diff --git a/.gitignore b/.gitignore index cbf8d7996a..4976fd9119 100644 --- a/.gitignore +++ b/.gitignore @@ -4,9 +4,11 @@ *.so *.so.[0-9] *.so.[0-9].[0-9] +*.so.[0-9].[0-9][0-9] *.sl *.sl.[0-9] *.sl.[0-9].[0-9] +*.sl.[0-9].[0-9][0-9] *.dylib *.dll *.exp diff --git a/COPYRIGHT b/COPYRIGHT index 01b6e3601e..c320eccac0 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,7 +1,7 @@ PostgreSQL Database Management System (formerly known as Postgres, then as Postgres95) -Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group Portions Copyright (c) 1994, The Regents of the University of California diff --git a/GNUmakefile.in b/GNUmakefile.in index 15fba9fce0..dc76a5d11d 100644 --- a/GNUmakefile.in +++ b/GNUmakefile.in @@ -39,9 +39,9 @@ install-world: # build src/ before contrib/ install-world-contrib-recurse: install-world-src-recurse -$(call recurse,installdirs uninstall coverage init-po update-po,doc src config) +$(call recurse,installdirs uninstall init-po update-po,doc src config) -$(call recurse,distprep,doc src config contrib) +$(call recurse,distprep coverage,doc src config contrib) # clean, distclean, etc should apply to contrib too, even though # it's not built by default diff --git a/config/c-compiler.m4 b/config/c-compiler.m4 index a7f6773ae1..7d901e1f1a 100644 --- a/config/c-compiler.m4 +++ b/config/c-compiler.m4 @@ -71,8 +71,10 @@ int does_int64_work() return 0; return 1; } + +int main() { - exit(! does_int64_work()); + return (! does_int64_work()); }])], [Ac_cachevar=yes], [Ac_cachevar=no], diff --git a/config/c-library.m4 b/config/c-library.m4 index 50d068d3fb..4ff8dae141 100644 --- a/config/c-library.m4 +++ b/config/c-library.m4 @@ -42,7 +42,8 @@ if test "$ac_cv_member_struct_tm_tm_zone" = yes; then fi AC_CACHE_CHECK(for tzname, ac_cv_var_tzname, [AC_LINK_IFELSE([AC_LANG_PROGRAM( -[[#include +[[#include +#include #ifndef tzname /* For SGI. */ extern char *tzname[]; /* RS6000 and others reject char **tzname. */ #endif @@ -184,6 +185,7 @@ AC_DEFUN([PGAC_FUNC_SNPRINTF_LONG_LONG_INT_MODIFIER], AC_CACHE_VAL(pgac_cv_snprintf_long_long_int_modifier, [for pgac_modifier in 'll' 'q' 'I64'; do AC_RUN_IFELSE([AC_LANG_SOURCE([[#include +#include typedef long long int ac_int64; #define INT64_FORMAT "%${pgac_modifier}d" @@ -204,8 +206,10 @@ int does_int64_snprintf_work() return 0; /* either multiply or snprintf is busted */ return 1; } + +int main() { - exit(! does_int64_snprintf_work()); + return (! does_int64_snprintf_work()); }]])], [pgac_cv_snprintf_long_long_int_modifier=$pgac_modifier; break], [], @@ -292,8 +296,8 @@ AC_MSG_RESULT([$pgac_cv_snprintf_size_t_support]) # PGAC_TYPE_LOCALE_T # ------------------ -# Check for the locale_t type and find the right header file. Mac OS -# X needs xlocale.h; standard is locale.h, but glibc also has an +# Check for the locale_t type and find the right header file. macOS +# needs xlocale.h; standard is locale.h, but glibc also has an # xlocale.h file that we should not use. # AC_DEFUN([PGAC_TYPE_LOCALE_T], diff --git a/config/python.m4 b/config/python.m4 index b95c8ed3b3..b605212bea 100644 --- a/config/python.m4 +++ b/config/python.m4 @@ -58,36 +58,101 @@ AC_SUBST(python_includespec)[]dnl # PGAC_CHECK_PYTHON_EMBED_SETUP # ----------------------------- # -# Note: selecting libpython from python_configdir works in all Python -# releases, but it generally finds a non-shared library, which means -# that we are binding the python interpreter right into libplpython.so. -# In Python 2.3 and up there should be a shared library available in -# the main library location. +# Set python_libdir to the path of the directory containing the Python shared +# library. Set python_libspec to the -L/-l linker switches needed to link it. +# Set python_additional_libs to contain any additional linker switches needed +# for subsidiary libraries. +# +# In modern, well-configured Python installations, LIBDIR gives the correct +# directory name and LDLIBRARY is the file name of the shlib. But in older +# installations LDLIBRARY is frequently a useless path fragment, and it's also +# possible that the shlib is in a standard library directory such as /usr/lib +# so that LIBDIR is irrelevant. Also, some packagers put the .so symlink for +# the shlib in ${python_configdir} even though Python itself never does. +# We must also check that what we found is a shared library not a plain +# library, which we do by checking its extension. (We used to rely on +# Py_ENABLE_SHARED, but that only tells us that a shlib exists, not that +# we found it.) AC_DEFUN([PGAC_CHECK_PYTHON_EMBED_SETUP], [AC_REQUIRE([_PGAC_CHECK_PYTHON_DIRS]) AC_MSG_CHECKING([how to link an embedded Python application]) python_libdir=`${PYTHON} -c "import distutils.sysconfig; print(' '.join(filter(None,distutils.sysconfig.get_config_vars('LIBDIR'))))"` python_ldlibrary=`${PYTHON} -c "import distutils.sysconfig; print(' '.join(filter(None,distutils.sysconfig.get_config_vars('LDLIBRARY'))))"` -python_so=`${PYTHON} -c "import distutils.sysconfig; print(' '.join(filter(None,distutils.sysconfig.get_config_vars('SO'))))"` -ldlibrary=`echo "${python_ldlibrary}" | sed "s/${python_so}$//"` -python_enable_shared=`${PYTHON} -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_vars().get('Py_ENABLE_SHARED',0))"` -if test x"${python_libdir}" != x"" -a x"${python_ldlibrary}" != x"" -a x"${python_ldlibrary}" != x"${ldlibrary}" +# If LDLIBRARY exists and has a shlib extension, use it verbatim. +ldlibrary=`echo "${python_ldlibrary}" | sed -e 's/\.so$//' -e 's/\.dll$//' -e 's/\.dylib$//' -e 's/\.sl$//'` +if test -e "${python_libdir}/${python_ldlibrary}" -a x"${python_ldlibrary}" != x"${ldlibrary}" then - # New way: use the official shared library ldlibrary=`echo "${ldlibrary}" | sed "s/^lib//"` - python_libspec="-L${python_libdir} -l${ldlibrary}" + found_shlib=1 else - # Old way: use libpython from python_configdir - python_libdir="${python_configdir}" - # LDVERSION was introduced in Python 3.2. + # Otherwise, guess the base name of the shlib. + # LDVERSION was added in Python 3.2, before that use VERSION, + # or failing that, $python_version from _PGAC_CHECK_PYTHON_DIRS. python_ldversion=`${PYTHON} -c "import distutils.sysconfig; print(' '.join(filter(None,distutils.sysconfig.get_config_vars('LDVERSION'))))"` - if test x"${python_ldversion}" = x""; then - python_ldversion=$python_version + if test x"${python_ldversion}" != x""; then + ldlibrary="python${python_ldversion}" + else + python_version_var=`${PYTHON} -c "import distutils.sysconfig; print(' '.join(filter(None,distutils.sysconfig.get_config_vars('VERSION'))))"` + if test x"${python_version_var}" != x""; then + ldlibrary="python${python_version_var}" + else + ldlibrary="python${python_version}" + fi + fi + # Search for a likely-looking file. + found_shlib=0 + for d in "${python_libdir}" "${python_configdir}" /usr/lib64 /usr/lib + do + # We don't know the platform DLSUFFIX here, so check 'em all. + for e in .so .dll .dylib .sl; do + if test -e "$d/lib${ldlibrary}$e"; then + python_libdir="$d" + found_shlib=1 + break 2 + fi + done + done + # Some platforms (OpenBSD) require us to accept a bare versioned shlib + # (".so.n.n") as well. However, check this only after failing to find + # ".so" anywhere, because yet other platforms (Debian) put the .so + # symlink in a different directory from the underlying versioned shlib. + if test "$found_shlib" != 1; then + for d in "${python_libdir}" "${python_configdir}" /usr/lib64 /usr/lib + do + for f in "$d/lib${ldlibrary}.so."* ; do + if test -e "$f"; then + python_libdir="$d" + found_shlib=1 + break 2 + fi + done + done fi - python_libspec="-L${python_libdir} -lpython${python_ldversion}" + # As usual, Windows has its own ideas. Possible default library + # locations include c:/Windows/System32 and (for Cygwin) /usr/bin, + # and the "lib" prefix might not be there. + if test "$found_shlib" != 1 -a \( "$PORTNAME" = win32 -o "$PORTNAME" = cygwin \); then + for d in "${python_libdir}" "${python_configdir}" c:/Windows/System32 /usr/bin + do + for f in "$d/lib${ldlibrary}.dll" "$d/${ldlibrary}.dll" ; do + if test -e "$f"; then + python_libdir="$d" + found_shlib=1 + break 2 + fi + done + done + fi +fi +if test "$found_shlib" != 1; then + AC_MSG_ERROR([could not find shared library for Python +You might have to rebuild your Python installation. Refer to the +documentation for details. Use --without-python to disable building +PL/Python.]) fi +python_libspec="-L${python_libdir} -l${ldlibrary}" python_additional_libs=`${PYTHON} -c "import distutils.sysconfig; print(' '.join(filter(None,distutils.sysconfig.get_config_vars('LIBS','LIBC','LIBM','BASEMODLIBS'))))"` diff --git a/configure b/configure index 7244c755a7..9a83f19821 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for PostgreSQL 9.6beta4. +# Generated by GNU Autoconf 2.69 for PostgreSQL 10devel. # # Report bugs to . # @@ -11,7 +11,7 @@ # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. # -# Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Copyright (c) 1996-2017, PostgreSQL Global Development Group ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## @@ -582,8 +582,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='PostgreSQL' PACKAGE_TARNAME='postgresql' -PACKAGE_VERSION='9.6beta4' -PACKAGE_STRING='PostgreSQL 9.6beta4' +PACKAGE_VERSION='10devel' +PACKAGE_STRING='PostgreSQL 10devel' PACKAGE_BUGREPORT='pgsql-bugs@postgresql.org' PACKAGE_URL='' @@ -694,7 +694,6 @@ STRIP_SHARED_LIB STRIP_STATIC_LIB STRIP RANLIB -ld_R_works with_gnu_ld LD LDFLAGS_SL @@ -740,6 +739,7 @@ GENHTML LCOV GCOV enable_debug +enable_strong_random enable_rpath default_port WANTED_LANGUAGES @@ -807,6 +807,7 @@ with_pgport enable_rpath enable_spinlocks enable_atomics +enable_strong_random enable_debug enable_profiling enable_coverage @@ -1398,7 +1399,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures PostgreSQL 9.6beta4 to adapt to many kinds of systems. +\`configure' configures PostgreSQL 10devel to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1463,7 +1464,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of PostgreSQL 9.6beta4:";; + short | recursive ) echo "Configuration of PostgreSQL 10devel:";; esac cat <<\_ACEOF @@ -1479,6 +1480,7 @@ Optional Features: executables --disable-spinlocks do not use spinlocks --disable-atomics do not use atomic operations + --disable-strong-random do not use a strong random number source --enable-debug build with debugging symbols (-g) --enable-profiling build with profiling enabled --enable-coverage build with coverage testing instrumentation @@ -1615,14 +1617,14 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -PostgreSQL configure 9.6beta4 +PostgreSQL configure 10devel generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. -Copyright (c) 1996-2016, PostgreSQL Global Development Group +Copyright (c) 1996-2017, PostgreSQL Global Development Group _ACEOF exit fi @@ -2326,7 +2328,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by PostgreSQL $as_me 9.6beta4, which was +It was created by PostgreSQL $as_me 10devel, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2711,7 +2713,7 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. configure_args=$ac_configure_args -PG_MAJORVERSION=`expr "$PACKAGE_VERSION" : '\([0-9][0-9]*\.[0-9][0-9]*\)'` +PG_MAJORVERSION=`expr "$PACKAGE_VERSION" : '\([0-9][0-9]*\)'` cat >>confdefs.h <<_ACEOF @@ -2867,9 +2869,7 @@ dragonfly*) template=netbsd ;; mingw*) template=win32 ;; netbsd*) template=netbsd ;; openbsd*) template=openbsd ;; - sco*) template=sco ;; solaris*) template=solaris ;; - sysv5*) template=unixware ;; esac if test x"$template" = x"" ; then @@ -3195,6 +3195,34 @@ fi +# +# Random number generation +# + + +# Check whether --enable-strong-random was given. +if test "${enable_strong_random+set}" = set; then : + enableval=$enable_strong_random; + case $enableval in + yes) + : + ;; + no) + : + ;; + *) + as_fn_error $? "no argument expected for --enable-strong-random option" "$LINENO" 5 + ;; + esac + +else + enable_strong_random=yes + +fi + + + + # # --enable-debug adds -g to compiler flags # @@ -6382,40 +6410,6 @@ with_gnu_ld=$ac_cv_prog_gnu_ld -case $host_os in sysv5*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ld -R works" >&5 -$as_echo_n "checking whether ld -R works... " >&6; } -if ${pgac_cv_prog_ld_R+:} false; then : - $as_echo_n "(cached) " >&6 -else - - pgac_save_LDFLAGS=$LDFLAGS; LDFLAGS="$LDFLAGS -Wl,-R/usr/lib" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - pgac_cv_prog_ld_R=yes -else - pgac_cv_prog_ld_R=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$pgac_save_LDFLAGS - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_prog_ld_R" >&5 -$as_echo "$pgac_cv_prog_ld_R" >&6; } - ld_R_works=$pgac_cv_prog_ld_R - -esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 @@ -7622,25 +7616,80 @@ $as_echo_n "checking how to link an embedded Python application... " >&6; } python_libdir=`${PYTHON} -c "import distutils.sysconfig; print(' '.join(filter(None,distutils.sysconfig.get_config_vars('LIBDIR'))))"` python_ldlibrary=`${PYTHON} -c "import distutils.sysconfig; print(' '.join(filter(None,distutils.sysconfig.get_config_vars('LDLIBRARY'))))"` -python_so=`${PYTHON} -c "import distutils.sysconfig; print(' '.join(filter(None,distutils.sysconfig.get_config_vars('SO'))))"` -ldlibrary=`echo "${python_ldlibrary}" | sed "s/${python_so}$//"` -python_enable_shared=`${PYTHON} -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_vars().get('Py_ENABLE_SHARED',0))"` -if test x"${python_libdir}" != x"" -a x"${python_ldlibrary}" != x"" -a x"${python_ldlibrary}" != x"${ldlibrary}" +# If LDLIBRARY exists and has a shlib extension, use it verbatim. +ldlibrary=`echo "${python_ldlibrary}" | sed -e 's/\.so$//' -e 's/\.dll$//' -e 's/\.dylib$//' -e 's/\.sl$//'` +if test -e "${python_libdir}/${python_ldlibrary}" -a x"${python_ldlibrary}" != x"${ldlibrary}" then - # New way: use the official shared library ldlibrary=`echo "${ldlibrary}" | sed "s/^lib//"` - python_libspec="-L${python_libdir} -l${ldlibrary}" + found_shlib=1 else - # Old way: use libpython from python_configdir - python_libdir="${python_configdir}" - # LDVERSION was introduced in Python 3.2. + # Otherwise, guess the base name of the shlib. + # LDVERSION was added in Python 3.2, before that use VERSION, + # or failing that, $python_version from _PGAC_CHECK_PYTHON_DIRS. python_ldversion=`${PYTHON} -c "import distutils.sysconfig; print(' '.join(filter(None,distutils.sysconfig.get_config_vars('LDVERSION'))))"` - if test x"${python_ldversion}" = x""; then - python_ldversion=$python_version + if test x"${python_ldversion}" != x""; then + ldlibrary="python${python_ldversion}" + else + python_version_var=`${PYTHON} -c "import distutils.sysconfig; print(' '.join(filter(None,distutils.sysconfig.get_config_vars('VERSION'))))"` + if test x"${python_version_var}" != x""; then + ldlibrary="python${python_version_var}" + else + ldlibrary="python${python_version}" + fi + fi + # Search for a likely-looking file. + found_shlib=0 + for d in "${python_libdir}" "${python_configdir}" /usr/lib64 /usr/lib + do + # We don't know the platform DLSUFFIX here, so check 'em all. + for e in .so .dll .dylib .sl; do + if test -e "$d/lib${ldlibrary}$e"; then + python_libdir="$d" + found_shlib=1 + break 2 + fi + done + done + # Some platforms (OpenBSD) require us to accept a bare versioned shlib + # (".so.n.n") as well. However, check this only after failing to find + # ".so" anywhere, because yet other platforms (Debian) put the .so + # symlink in a different directory from the underlying versioned shlib. + if test "$found_shlib" != 1; then + for d in "${python_libdir}" "${python_configdir}" /usr/lib64 /usr/lib + do + for f in "$d/lib${ldlibrary}.so."* ; do + if test -e "$f"; then + python_libdir="$d" + found_shlib=1 + break 2 + fi + done + done fi - python_libspec="-L${python_libdir} -lpython${python_ldversion}" + # As usual, Windows has its own ideas. Possible default library + # locations include c:/Windows/System32 and (for Cygwin) /usr/bin, + # and the "lib" prefix might not be there. + if test "$found_shlib" != 1 -a \( "$PORTNAME" = win32 -o "$PORTNAME" = cygwin \); then + for d in "${python_libdir}" "${python_configdir}" c:/Windows/System32 /usr/bin + do + for f in "$d/lib${ldlibrary}.dll" "$d/${ldlibrary}.dll" ; do + if test -e "$f"; then + python_libdir="$d" + found_shlib=1 + break 2 + fi + done + done + fi +fi +if test "$found_shlib" != 1; then + as_fn_error $? "could not find shared library for Python +You might have to rebuild your Python installation. Refer to the +documentation for details. Use --without-python to disable building +PL/Python." "$LINENO" 5 fi +python_libspec="-L${python_libdir} -l${ldlibrary}" python_additional_libs=`${PYTHON} -c "import distutils.sysconfig; print(' '.join(filter(None,distutils.sysconfig.get_config_vars('LIBS','LIBC','LIBM','BASEMODLIBS'))))"` @@ -7649,40 +7698,6 @@ $as_echo "${python_libspec} ${python_additional_libs}" >&6; } - - # We need libpython as a shared library. With Python >=2.5, we - # check the Py_ENABLE_SHARED setting. On Debian, the setting is not - # correct before the jessie release (http://bugs.debian.org/695979). - # We also want to support older Python versions. So as a fallback - # we see if there is a file that is named like a shared library. - - if test "$python_enable_shared" != 1; then - if test "$PORTNAME" = darwin; then - # OS X does supply a .dylib even though Py_ENABLE_SHARED does - # not get set. The file detection logic below doesn't succeed - # on older OS X versions, so make it explicit. - python_enable_shared=1 - elif test "$PORTNAME" = win32; then - # Windows also needs an explicit override. - python_enable_shared=1 - else - # We don't know the platform shared library extension here yet, - # so we try some candidates. - for dlsuffix in .so .sl; do - if ls "$python_libdir"/libpython*${dlsuffix}* >/dev/null 2>&1; then - python_enable_shared=1 - break - fi - done - fi - fi - - if test "$python_enable_shared" != 1; then - as_fn_error $? "cannot build PL/Python because libpython is not a shared library -You might have to rebuild your Python installation. Refer to the -documentation for details. Use --without-python to disable building -PL/Python." "$LINENO" 5 - fi fi if test "$cross_compiling" = yes && test -z "$with_system_tzdata"; then @@ -9040,6 +9055,62 @@ if test "$ac_res" != no; then : fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 +$as_echo_n "checking for library containing clock_gettime... " >&6; } +if ${ac_cv_search_clock_gettime+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char clock_gettime (); +int +main () +{ +return clock_gettime (); + ; + return 0; +} +_ACEOF +for ac_lib in '' rt posix4; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_clock_gettime=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_clock_gettime+:} false; then : + break +fi +done +if ${ac_cv_search_clock_gettime+:} false; then : + +else + ac_cv_search_clock_gettime=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 +$as_echo "$ac_cv_search_clock_gettime" >&6; } +ac_res=$ac_cv_search_clock_gettime +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + # Solaris: { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing fdatasync" >&5 $as_echo_n "checking for library containing fdatasync... " >&6; } @@ -9538,9 +9609,9 @@ else as_fn_error $? "library 'crypto' is required for OpenSSL" "$LINENO" 5 fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_library_init in -lssl" >&5 -$as_echo_n "checking for SSL_library_init in -lssl... " >&6; } -if ${ac_cv_lib_ssl_SSL_library_init+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_new in -lssl" >&5 +$as_echo_n "checking for SSL_new in -lssl... " >&6; } +if ${ac_cv_lib_ssl_SSL_new+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -9554,27 +9625,27 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char SSL_library_init (); +char SSL_new (); int main () { -return SSL_library_init (); +return SSL_new (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_ssl_SSL_library_init=yes + ac_cv_lib_ssl_SSL_new=yes else - ac_cv_lib_ssl_SSL_library_init=no + ac_cv_lib_ssl_SSL_new=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_library_init" >&5 -$as_echo "$ac_cv_lib_ssl_SSL_library_init" >&6; } -if test "x$ac_cv_lib_ssl_SSL_library_init" = xyes; then : +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_new" >&5 +$as_echo "$ac_cv_lib_ssl_SSL_new" >&6; } +if test "x$ac_cv_lib_ssl_SSL_new" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSSL 1 _ACEOF @@ -9644,9 +9715,9 @@ else as_fn_error $? "library 'eay32' or 'crypto' is required for OpenSSL" "$LINENO" 5 fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing SSL_library_init" >&5 -$as_echo_n "checking for library containing SSL_library_init... " >&6; } -if ${ac_cv_search_SSL_library_init+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing SSL_new" >&5 +$as_echo_n "checking for library containing SSL_new... " >&6; } +if ${ac_cv_search_SSL_new+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -9659,11 +9730,11 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char SSL_library_init (); +char SSL_new (); int main () { -return SSL_library_init (); +return SSL_new (); ; return 0; } @@ -9676,25 +9747,25 @@ for ac_lib in '' ssleay32 ssl; do LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_SSL_library_init=$ac_res + ac_cv_search_SSL_new=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if ${ac_cv_search_SSL_library_init+:} false; then : + if ${ac_cv_search_SSL_new+:} false; then : break fi done -if ${ac_cv_search_SSL_library_init+:} false; then : +if ${ac_cv_search_SSL_new+:} false; then : else - ac_cv_search_SSL_library_init=no + ac_cv_search_SSL_new=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_SSL_library_init" >&5 -$as_echo "$ac_cv_search_SSL_library_init" >&6; } -ac_res=$ac_cv_search_SSL_library_init +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_SSL_new" >&5 +$as_echo "$ac_cv_search_SSL_new" >&6; } +ac_res=$ac_cv_search_SSL_new if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" @@ -9711,6 +9782,37 @@ if test "x$ac_cv_func_SSL_get_current_compression" = xyes; then : #define HAVE_SSL_GET_CURRENT_COMPRESSION 1 _ACEOF +fi +done + + # Functions introduced in OpenSSL 1.1.0. We used to check for + # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL + # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it + # doesn't have these OpenSSL 1.1.0 functions. So check for individual + # functions. + for ac_func in OPENSSL_init_ssl BIO_get_data BIO_meth_new ASN1_STRING_get0_data RAND_OpenSSL +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + # OpenSSL versions before 1.1.0 required setting callback functions, for + # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock() + # function was removed. + for ac_func in CRYPTO_lock +do : + ac_fn_c_check_func "$LINENO" "CRYPTO_lock" "ac_cv_func_CRYPTO_lock" +if test "x$ac_cv_func_CRYPTO_lock" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_CRYPTO_LOCK 1 +_ACEOF + fi done @@ -10089,7 +10191,7 @@ else fi elif test "$with_uuid" = e2fs ; then - # On OS X, the UUID functions are in libc + # On macOS, the UUID functions are in libc ac_fn_c_check_func "$LINENO" "uuid_generate" "ac_cv_func_uuid_generate" if test "x$ac_cv_func_uuid_generate" = xyes; then : UUID_LIBS="" @@ -11538,6 +11640,7 @@ if ${ac_cv_var_tzname+:} false; then : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ +#include #include #ifndef tzname /* For SGI. */ extern char *tzname[]; /* RS6000 and others reject char **tzname. */ @@ -12473,7 +12576,7 @@ fi LIBS_including_readline="$LIBS" LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'` -for ac_func in cbrt dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll pstat pthread_is_threaded_np readlink setproctitle setsid shm_open symlink sync_file_range towlower utime utimes wcstombs wcstombs_l +for ac_func in cbrt clock_gettime dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll pstat pthread_is_threaded_np readlink setproctitle setsid shm_open symlink sync_file_range towlower utime utimes wcstombs wcstombs_l do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" @@ -12641,7 +12744,7 @@ cat >>confdefs.h <<_ACEOF #define HAVE_DECL_STRLCPY $ac_have_decl _ACEOF -# This is probably only present on Darwin, but may as well check always +# This is probably only present on macOS, but may as well check always ac_fn_c_check_decl "$LINENO" "F_FULLFSYNC" "ac_cv_have_decl_F_FULLFSYNC" "#include " if test "x$ac_cv_have_decl_F_FULLFSYNC" = xyes; then : @@ -13563,8 +13666,10 @@ int does_int64_work() return 0; return 1; } + +int main() { - exit(! does_int64_work()); + return (! does_int64_work()); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : @@ -13645,8 +13750,10 @@ int does_int64_work() return 0; return 1; } + +int main() { - exit(! does_int64_work()); + return (! does_int64_work()); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : @@ -13719,6 +13826,7 @@ else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include +#include typedef long long int ac_int64; #define INT64_FORMAT "%${pgac_modifier}d" @@ -13739,8 +13847,10 @@ int does_int64_snprintf_work() return 0; /* either multiply or snprintf is busted */ return 1; } + +int main() { - exit(! does_int64_snprintf_work()); + return (! does_int64_snprintf_work()); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : @@ -14795,24 +14905,149 @@ fi # Select semaphore implementation type. if test "$PORTNAME" != "win32"; then + if test x"$PREFERRED_SEMAPHORES" = x"NAMED_POSIX" ; then + # Need sem_open for this + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing sem_open" >&5 +$as_echo_n "checking for library containing sem_open... " >&6; } +if ${ac_cv_search_sem_open+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char sem_open (); +int +main () +{ +return sem_open (); + ; + return 0; +} +_ACEOF +for ac_lib in '' rt pthread; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_sem_open=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_sem_open+:} false; then : + break +fi +done +if ${ac_cv_search_sem_open+:} false; then : + +else + ac_cv_search_sem_open=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_sem_open" >&5 +$as_echo "$ac_cv_search_sem_open" >&6; } +ac_res=$ac_cv_search_sem_open +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + USE_NAMED_POSIX_SEMAPHORES=1 +fi + + fi + if test x"$PREFERRED_SEMAPHORES" = x"UNNAMED_POSIX" ; then + # Need sem_init for this + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing sem_init" >&5 +$as_echo_n "checking for library containing sem_init... " >&6; } +if ${ac_cv_search_sem_init+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char sem_init (); +int +main () +{ +return sem_init (); + ; + return 0; +} +_ACEOF +for ac_lib in '' rt pthread; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_sem_init=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_sem_init+:} false; then : + break +fi +done +if ${ac_cv_search_sem_init+:} false; then : + +else + ac_cv_search_sem_init=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_sem_init" >&5 +$as_echo "$ac_cv_search_sem_init" >&6; } +ac_res=$ac_cv_search_sem_init +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + USE_UNNAMED_POSIX_SEMAPHORES=1 +fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking which semaphore API to use" >&5 +$as_echo_n "checking which semaphore API to use... " >&6; } if test x"$USE_NAMED_POSIX_SEMAPHORES" = x"1" ; then $as_echo "#define USE_NAMED_POSIX_SEMAPHORES 1" >>confdefs.h SEMA_IMPLEMENTATION="src/backend/port/posix_sema.c" + sematype="named POSIX" else if test x"$USE_UNNAMED_POSIX_SEMAPHORES" = x"1" ; then $as_echo "#define USE_UNNAMED_POSIX_SEMAPHORES 1" >>confdefs.h SEMA_IMPLEMENTATION="src/backend/port/posix_sema.c" + sematype="unnamed POSIX" else $as_echo "#define USE_SYSV_SEMAPHORES 1" >>confdefs.h SEMA_IMPLEMENTATION="src/backend/port/sysv_sema.c" + sematype="System V" fi fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $sematype" >&5 +$as_echo "$sematype" >&6; } else $as_echo "#define USE_WIN32_SEMAPHORES 1" >>confdefs.h @@ -14834,6 +15069,84 @@ $as_echo "#define USE_WIN32_SHARED_MEMORY 1" >>confdefs.h SHMEM_IMPLEMENTATION="src/backend/port/win32_shmem.c" fi +# Select random number source +# +# You can override this logic by setting the appropriate USE_*RANDOM flag to 1 +# in the template or configure command line. + +# If not selected manually, try to select a source automatically. +if test "$enable_strong_random" = "yes" && test x"$USE_OPENSSL_RANDOM" = x"" && test x"$USE_WIN32_RANDOM" = x"" && test x"$USE_DEV_URANDOM" = x"" ; then + if test x"$with_openssl" = x"yes" ; then + USE_OPENSSL_RANDOM=1 + elif test "$PORTNAME" = "win32" ; then + USE_WIN32_RANDOM=1 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /dev/urandom" >&5 +$as_echo_n "checking for /dev/urandom... " >&6; } +if ${ac_cv_file__dev_urandom+:} false; then : + $as_echo_n "(cached) " >&6 +else + test "$cross_compiling" = yes && + as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 +if test -r "/dev/urandom"; then + ac_cv_file__dev_urandom=yes +else + ac_cv_file__dev_urandom=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__dev_urandom" >&5 +$as_echo "$ac_cv_file__dev_urandom" >&6; } +if test "x$ac_cv_file__dev_urandom" = xyes; then : + +fi + + + if test x"$ac_cv_file__dev_urandom" = x"yes" ; then + USE_DEV_URANDOM=1 + fi + fi +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which random number source to use" >&5 +$as_echo_n "checking which random number source to use... " >&6; } +if test "$enable_strong_random" = yes ; then + if test x"$USE_OPENSSL_RANDOM" = x"1" ; then + +$as_echo "#define USE_OPENSSL_RANDOM 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: OpenSSL" >&5 +$as_echo "OpenSSL" >&6; } + elif test x"$USE_WIN32_RANDOM" = x"1" ; then + +$as_echo "#define USE_WIN32_RANDOM 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: Windows native" >&5 +$as_echo "Windows native" >&6; } + elif test x"$USE_DEV_URANDOM" = x"1" ; then + +$as_echo "#define USE_DEV_URANDOM 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: /dev/urandom" >&5 +$as_echo "/dev/urandom" >&6; } + else + as_fn_error $? " +no source of strong random numbers was found +PostgreSQL can use OpenSSL or /dev/urandom as a source of random numbers, +for authentication protocols. You can use --disable-strong-random to use a +built-in pseudo random number generator, but that may be insecure." "$LINENO" 5 + fi + +$as_echo "#define HAVE_STRONG_RANDOM 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: weak builtin PRNG" >&5 +$as_echo "weak builtin PRNG" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: +*** Not using a strong random number source may be insecure." >&5 +$as_echo "$as_me: WARNING: +*** Not using a strong random number source may be insecure." >&2;} +fi + # If not set in template file, set bytes to use libc memset() if test x"$MEMSET_LOOP_LIMIT" = x"" ; then MEMSET_LOOP_LIMIT=1024 @@ -16433,7 +16746,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by PostgreSQL $as_me 9.6beta4, which was +This file was extended by PostgreSQL $as_me 10devel, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -16503,7 +16816,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -PostgreSQL config.status 9.6beta4 +PostgreSQL config.status 10devel configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.in b/configure.in index 598fbd8f64..52e4e78471 100644 --- a/configure.in +++ b/configure.in @@ -17,19 +17,19 @@ dnl Read the Autoconf manual for details. dnl m4_pattern_forbid(^PGAC_)dnl to catch undefined macros -AC_INIT([PostgreSQL], [9.6beta4], [pgsql-bugs@postgresql.org]) +AC_INIT([PostgreSQL], [10devel], [pgsql-bugs@postgresql.org]) m4_if(m4_defn([m4_PACKAGE_VERSION]), [2.69], [], [m4_fatal([Autoconf version 2.69 is required. Untested combinations of 'autoconf' and PostgreSQL versions are not recommended. You can remove the check from 'configure.in' but it is then your responsibility whether the result works or not.])]) -AC_COPYRIGHT([Copyright (c) 1996-2016, PostgreSQL Global Development Group]) +AC_COPYRIGHT([Copyright (c) 1996-2017, PostgreSQL Global Development Group]) AC_CONFIG_SRCDIR([src/backend/access/common/heaptuple.c]) AC_CONFIG_AUX_DIR(config) AC_PREFIX_DEFAULT(/usr/local/pgsql) AC_SUBST(configure_args, [$ac_configure_args]) -[PG_MAJORVERSION=`expr "$PACKAGE_VERSION" : '\([0-9][0-9]*\.[0-9][0-9]*\)'`] +[PG_MAJORVERSION=`expr "$PACKAGE_VERSION" : '\([0-9][0-9]*\)'`] AC_SUBST(PG_MAJORVERSION) AC_DEFINE_UNQUOTED(PG_MAJORVERSION, "$PG_MAJORVERSION", [PostgreSQL major version as a string]) @@ -69,9 +69,7 @@ dragonfly*) template=netbsd ;; mingw*) template=win32 ;; netbsd*) template=netbsd ;; openbsd*) template=openbsd ;; - sco*) template=sco ;; solaris*) template=solaris ;; - sysv5*) template=unixware ;; esac if test x"$template" = x"" ; then @@ -195,6 +193,13 @@ PGAC_ARG_BOOL(enable, spinlocks, yes, PGAC_ARG_BOOL(enable, atomics, yes, [do not use atomic operations]) +# +# Random number generation +# +PGAC_ARG_BOOL(enable, strong-random, yes, + [do not use a strong random number source]) +AC_SUBST(enable_strong_random) + # # --enable-debug adds -g to compiler flags # @@ -871,18 +876,6 @@ AC_ARG_VAR(LDFLAGS_SL, [extra linker flags for linking shared libraries only]) PGAC_PROG_LD AC_SUBST(LD) AC_SUBST(with_gnu_ld) -case $host_os in sysv5*) - AC_CACHE_CHECK([whether ld -R works], [pgac_cv_prog_ld_R], - [ - pgac_save_LDFLAGS=$LDFLAGS; LDFLAGS="$LDFLAGS -Wl,-R/usr/lib" - AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], - [pgac_cv_prog_ld_R=yes], - [pgac_cv_prog_ld_R=no]) - LDFLAGS=$pgac_save_LDFLAGS - ]) - ld_R_works=$pgac_cv_prog_ld_R - AC_SUBST(ld_R_works) -esac AC_PROG_RANLIB PGAC_CHECK_STRIP AC_CHECK_TOOL(AR, ar, ar) @@ -934,40 +927,6 @@ fi if test "$with_python" = yes; then PGAC_PATH_PYTHON PGAC_CHECK_PYTHON_EMBED_SETUP - - # We need libpython as a shared library. With Python >=2.5, we - # check the Py_ENABLE_SHARED setting. On Debian, the setting is not - # correct before the jessie release (http://bugs.debian.org/695979). - # We also want to support older Python versions. So as a fallback - # we see if there is a file that is named like a shared library. - - if test "$python_enable_shared" != 1; then - if test "$PORTNAME" = darwin; then - # OS X does supply a .dylib even though Py_ENABLE_SHARED does - # not get set. The file detection logic below doesn't succeed - # on older OS X versions, so make it explicit. - python_enable_shared=1 - elif test "$PORTNAME" = win32; then - # Windows also needs an explicit override. - python_enable_shared=1 - else - # We don't know the platform shared library extension here yet, - # so we try some candidates. - for dlsuffix in .so .sl; do - if ls "$python_libdir"/libpython*${dlsuffix}* >/dev/null 2>&1; then - python_enable_shared=1 - break - fi - done - fi - fi - - if test "$python_enable_shared" != 1; then - AC_MSG_ERROR([cannot build PL/Python because libpython is not a shared library -You might have to rebuild your Python installation. Refer to the -documentation for details. Use --without-python to disable building -PL/Python.]) - fi fi if test "$cross_compiling" = yes && test -z "$with_system_tzdata"; then @@ -1057,6 +1016,7 @@ AC_SEARCH_LIBS(getopt_long, [getopt gnugetopt]) AC_SEARCH_LIBS(crypt, crypt) AC_SEARCH_LIBS(shm_open, rt) AC_SEARCH_LIBS(shm_unlink, rt) +AC_SEARCH_LIBS(clock_gettime, [rt posix4]) # Solaris: AC_SEARCH_LIBS(fdatasync, [rt posix4]) # Required for thread_test.c on Solaris @@ -1112,12 +1072,22 @@ if test "$with_openssl" = yes ; then dnl Order matters! if test "$PORTNAME" != "win32"; then AC_CHECK_LIB(crypto, CRYPTO_new_ex_data, [], [AC_MSG_ERROR([library 'crypto' is required for OpenSSL])]) - AC_CHECK_LIB(ssl, SSL_library_init, [], [AC_MSG_ERROR([library 'ssl' is required for OpenSSL])]) + AC_CHECK_LIB(ssl, SSL_new, [], [AC_MSG_ERROR([library 'ssl' is required for OpenSSL])]) else AC_SEARCH_LIBS(CRYPTO_new_ex_data, eay32 crypto, [], [AC_MSG_ERROR([library 'eay32' or 'crypto' is required for OpenSSL])]) - AC_SEARCH_LIBS(SSL_library_init, ssleay32 ssl, [], [AC_MSG_ERROR([library 'ssleay32' or 'ssl' is required for OpenSSL])]) + AC_SEARCH_LIBS(SSL_new, ssleay32 ssl, [], [AC_MSG_ERROR([library 'ssleay32' or 'ssl' is required for OpenSSL])]) fi AC_CHECK_FUNCS([SSL_get_current_compression]) + # Functions introduced in OpenSSL 1.1.0. We used to check for + # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL + # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it + # doesn't have these OpenSSL 1.1.0 functions. So check for individual + # functions. + AC_CHECK_FUNCS([OPENSSL_init_ssl BIO_get_data BIO_meth_new ASN1_STRING_get0_data RAND_OpenSSL]) + # OpenSSL versions before 1.1.0 required setting callback functions, for + # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock() + # function was removed. + AC_CHECK_FUNCS([CRYPTO_lock]) fi if test "$with_pam" = yes ; then @@ -1172,7 +1142,7 @@ if test "$with_uuid" = bsd ; then [UUID_LIBS=""], [AC_MSG_ERROR([BSD UUID functions are not present])]) elif test "$with_uuid" = e2fs ; then - # On OS X, the UUID functions are in libc + # On macOS, the UUID functions are in libc AC_CHECK_FUNC(uuid_generate, [UUID_LIBS=""], [AC_CHECK_LIB(uuid, uuid_generate, @@ -1415,8 +1385,8 @@ esac if test "$PORTNAME" != "win32"; then AC_SYS_LARGEFILE dnl Autoconf 2.69's AC_SYS_LARGEFILE believes it's a good idea to #define - dnl _DARWIN_USE_64_BIT_INODE, but it isn't: on OS X 10.5 that activates a - dnl bug that causes readdir() to sometimes return EINVAL. On later OS X + dnl _DARWIN_USE_64_BIT_INODE, but it isn't: on macOS 10.5 that activates a + dnl bug that causes readdir() to sometimes return EINVAL. On later macOS dnl versions where the feature actually works, it's on by default anyway. AH_VERBATIM([_DARWIN_USE_64_BIT_INODE],[]) fi @@ -1446,7 +1416,7 @@ PGAC_FUNC_WCSTOMBS_L LIBS_including_readline="$LIBS" LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'` -AC_CHECK_FUNCS([cbrt dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll pstat pthread_is_threaded_np readlink setproctitle setsid shm_open symlink sync_file_range towlower utime utimes wcstombs wcstombs_l]) +AC_CHECK_FUNCS([cbrt clock_gettime dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll pstat pthread_is_threaded_np readlink setproctitle setsid shm_open symlink sync_file_range towlower utime utimes wcstombs wcstombs_l]) AC_REPLACE_FUNCS(fseeko) case $host_os in @@ -1469,7 +1439,7 @@ fi AC_CHECK_DECLS(fdatasync, [], [], [#include ]) AC_CHECK_DECLS([strlcat, strlcpy]) -# This is probably only present on Darwin, but may as well check always +# This is probably only present on macOS, but may as well check always AC_CHECK_DECLS(F_FULLFSYNC, [], [], [#include ]) HAVE_IPV6=no @@ -1963,18 +1933,31 @@ AC_SUBST(PG_CRC32C_OBJS) # Select semaphore implementation type. if test "$PORTNAME" != "win32"; then + if test x"$PREFERRED_SEMAPHORES" = x"NAMED_POSIX" ; then + # Need sem_open for this + AC_SEARCH_LIBS(sem_open, [rt pthread], [USE_NAMED_POSIX_SEMAPHORES=1]) + fi + if test x"$PREFERRED_SEMAPHORES" = x"UNNAMED_POSIX" ; then + # Need sem_init for this + AC_SEARCH_LIBS(sem_init, [rt pthread], [USE_UNNAMED_POSIX_SEMAPHORES=1]) + fi + AC_MSG_CHECKING([which semaphore API to use]) if test x"$USE_NAMED_POSIX_SEMAPHORES" = x"1" ; then AC_DEFINE(USE_NAMED_POSIX_SEMAPHORES, 1, [Define to select named POSIX semaphores.]) SEMA_IMPLEMENTATION="src/backend/port/posix_sema.c" + sematype="named POSIX" else if test x"$USE_UNNAMED_POSIX_SEMAPHORES" = x"1" ; then AC_DEFINE(USE_UNNAMED_POSIX_SEMAPHORES, 1, [Define to select unnamed POSIX semaphores.]) SEMA_IMPLEMENTATION="src/backend/port/posix_sema.c" + sematype="unnamed POSIX" else AC_DEFINE(USE_SYSV_SEMAPHORES, 1, [Define to select SysV-style semaphores.]) SEMA_IMPLEMENTATION="src/backend/port/sysv_sema.c" + sematype="System V" fi fi + AC_MSG_RESULT([$sematype]) else AC_DEFINE(USE_WIN32_SEMAPHORES, 1, [Define to select Win32-style semaphores.]) SEMA_IMPLEMENTATION="src/backend/port/win32_sema.c" @@ -1990,6 +1973,51 @@ else SHMEM_IMPLEMENTATION="src/backend/port/win32_shmem.c" fi +# Select random number source +# +# You can override this logic by setting the appropriate USE_*RANDOM flag to 1 +# in the template or configure command line. + +# If not selected manually, try to select a source automatically. +if test "$enable_strong_random" = "yes" && test x"$USE_OPENSSL_RANDOM" = x"" && test x"$USE_WIN32_RANDOM" = x"" && test x"$USE_DEV_URANDOM" = x"" ; then + if test x"$with_openssl" = x"yes" ; then + USE_OPENSSL_RANDOM=1 + elif test "$PORTNAME" = "win32" ; then + USE_WIN32_RANDOM=1 + else + AC_CHECK_FILE([/dev/urandom], [], []) + + if test x"$ac_cv_file__dev_urandom" = x"yes" ; then + USE_DEV_URANDOM=1 + fi + fi +fi + +AC_MSG_CHECKING([which random number source to use]) +if test "$enable_strong_random" = yes ; then + if test x"$USE_OPENSSL_RANDOM" = x"1" ; then + AC_DEFINE(USE_OPENSSL_RANDOM, 1, [Define to use OpenSSL for random number generation]) + AC_MSG_RESULT([OpenSSL]) + elif test x"$USE_WIN32_RANDOM" = x"1" ; then + AC_DEFINE(USE_WIN32_RANDOM, 1, [Define to use native Windows API for random number generation]) + AC_MSG_RESULT([Windows native]) + elif test x"$USE_DEV_URANDOM" = x"1" ; then + AC_DEFINE(USE_DEV_URANDOM, 1, [Define to use /dev/urandom for random number generation]) + AC_MSG_RESULT([/dev/urandom]) + else + AC_MSG_ERROR([ +no source of strong random numbers was found +PostgreSQL can use OpenSSL or /dev/urandom as a source of random numbers, +for authentication protocols. You can use --disable-strong-random to use a +built-in pseudo random number generator, but that may be insecure.]) + fi + AC_DEFINE(HAVE_STRONG_RANDOM, 1, [Define to use have a strong random number source]) +else + AC_MSG_RESULT([weak builtin PRNG]) + AC_MSG_WARN([ +*** Not using a strong random number source may be insecure.]) +fi + # If not set in template file, set bytes to use libc memset() if test x"$MEMSET_LOOP_LIMIT" = x"" ; then MEMSET_LOOP_LIMIT=1024 diff --git a/contrib/Makefile b/contrib/Makefile index 25263c0be9..0fb41b5bd5 100644 --- a/contrib/Makefile +++ b/contrib/Makefile @@ -38,6 +38,8 @@ SUBDIRS = \ pgcrypto \ pgrowlocks \ pgstattuple \ + pg_execplan \ + pg_repeater \ pg_visibility \ postgres_fdw \ seg \ diff --git a/contrib/adminpack/adminpack.c b/contrib/adminpack/adminpack.c index ea781a0a5a..c7ff9055ef 100644 --- a/contrib/adminpack/adminpack.c +++ b/contrib/adminpack/adminpack.c @@ -3,7 +3,7 @@ * adminpack.c * * - * Copyright (c) 2002-2016, PostgreSQL Global Development Group + * Copyright (c) 2002-2017, PostgreSQL Global Development Group * * Author: Andreas Pflug * diff --git a/contrib/auth_delay/auth_delay.c b/contrib/auth_delay/auth_delay.c index 86f3aa0b7b..326ca79d73 100644 --- a/contrib/auth_delay/auth_delay.c +++ b/contrib/auth_delay/auth_delay.c @@ -2,7 +2,7 @@ * * auth_delay.c * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/auth_delay/auth_delay.c diff --git a/contrib/auto_explain/auto_explain.c b/contrib/auto_explain/auto_explain.c index 4ccd2aa849..34b9f1543e 100644 --- a/contrib/auto_explain/auto_explain.c +++ b/contrib/auto_explain/auto_explain.c @@ -3,7 +3,7 @@ * auto_explain.c * * - * Copyright (c) 2008-2016, PostgreSQL Global Development Group + * Copyright (c) 2008-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/auto_explain/auto_explain.c diff --git a/contrib/bloom/blcost.c b/contrib/bloom/blcost.c index 989789850e..98a2228edf 100644 --- a/contrib/bloom/blcost.c +++ b/contrib/bloom/blcost.c @@ -3,7 +3,7 @@ * blcost.c * Cost estimate function for bloom indexes. * - * Copyright (c) 2016, PostgreSQL Global Development Group + * Copyright (c) 2016-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/bloom/blcost.c diff --git a/contrib/bloom/blinsert.c b/contrib/bloom/blinsert.c index 78eec5c67e..29bc5cea79 100644 --- a/contrib/bloom/blinsert.c +++ b/contrib/bloom/blinsert.c @@ -3,7 +3,7 @@ * blinsert.c * Bloom index build and insert functions. * - * Copyright (c) 2016, PostgreSQL Global Development Group + * Copyright (c) 2016-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/bloom/blinsert.c @@ -130,9 +130,7 @@ blbuild(Relation heap, Relation index, IndexInfo *indexInfo) initBloomState(&buildstate.blstate, index); buildstate.tmpCtx = AllocSetContextCreate(CurrentMemoryContext, "Bloom build temporary context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); initCachedPage(&buildstate); /* Do the heap scan */ @@ -166,13 +164,18 @@ blbuildempty(Relation index) metapage = (Page) palloc(BLCKSZ); BloomFillMetapage(index, metapage); - /* Write the page. If archiving/streaming, XLOG it. */ + /* + * Write the page and log it. It might seem that an immediate sync + * would be sufficient to guarantee that the file exists on disk, but + * recovery itself might remove it while replaying, for example, an + * XLOG_DBASE_CREATE or XLOG_TBLSPC_CREATE record. Therefore, we + * need this even when wal_level=minimal. + */ PageSetChecksumInplace(metapage, BLOOM_METAPAGE_BLKNO); smgrwrite(index->rd_smgr, INIT_FORKNUM, BLOOM_METAPAGE_BLKNO, (char *) metapage, true); - if (XLogIsNeeded()) - log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM, - BLOOM_METAPAGE_BLKNO, metapage, false); + log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM, + BLOOM_METAPAGE_BLKNO, metapage, false); /* * An immediate sync is required even if we xlog'd the page, because the @@ -204,9 +207,7 @@ blinsert(Relation index, Datum *values, bool *isnull, insertCtx = AllocSetContextCreate(CurrentMemoryContext, "Bloom insert temporary context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldCtx = MemoryContextSwitchTo(insertCtx); diff --git a/contrib/bloom/bloom.h b/contrib/bloom/bloom.h index bc451a00db..a75a235a4f 100644 --- a/contrib/bloom/bloom.h +++ b/contrib/bloom/bloom.h @@ -3,7 +3,7 @@ * bloom.h * Header for bloom index. * - * Copyright (c) 2016, PostgreSQL Global Development Group + * Copyright (c) 2016-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/bloom/bloom.h @@ -174,7 +174,6 @@ typedef BloomScanOpaqueData *BloomScanOpaque; /* blutils.c */ extern void _PG_init(void); -extern Datum blhandler(PG_FUNCTION_ARGS); extern void initBloomState(BloomState *state, Relation index); extern void BloomFillMetapage(Relation index, Page metaPage); extern void BloomInitMetapage(Relation index); diff --git a/contrib/bloom/blscan.c b/contrib/bloom/blscan.c index 316a906734..b8fa2d0a71 100644 --- a/contrib/bloom/blscan.c +++ b/contrib/bloom/blscan.c @@ -3,7 +3,7 @@ * blscan.c * Bloom index scan functions. * - * Copyright (c) 2016, PostgreSQL Global Development Group + * Copyright (c) 2016-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/bloom/blscan.c diff --git a/contrib/bloom/blutils.c b/contrib/bloom/blutils.c index debf4f46eb..06077afed6 100644 --- a/contrib/bloom/blutils.c +++ b/contrib/bloom/blutils.c @@ -3,7 +3,7 @@ * blutils.c * Bloom index utilities. * - * Portions Copyright (c) 2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2016-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1990-1993, Regents of the University of California * * IDENTIFICATION @@ -75,7 +75,7 @@ _PG_init(void) bl_relopt_tab[i + 1].optname = MemoryContextStrdup(TopMemoryContext, buf); bl_relopt_tab[i + 1].opttype = RELOPT_TYPE_INT; - bl_relopt_tab[i + 1].offset = offsetof(BloomOptions, bitSize[i]); + bl_relopt_tab[i + 1].offset = offsetof(BloomOptions, bitSize[0]) + sizeof(int) * i; } } diff --git a/contrib/bloom/blvacuum.c b/contrib/bloom/blvacuum.c index 482242f1c2..807da9254e 100644 --- a/contrib/bloom/blvacuum.c +++ b/contrib/bloom/blvacuum.c @@ -3,7 +3,7 @@ * blvacuum.c * Bloom VACUUM functions. * - * Copyright (c) 2016, PostgreSQL Global Development Group + * Copyright (c) 2016-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/bloom/blvacuum.c diff --git a/contrib/bloom/blvalidate.c b/contrib/bloom/blvalidate.c index 12e7c7dbda..cb75d23199 100644 --- a/contrib/bloom/blvalidate.c +++ b/contrib/bloom/blvalidate.c @@ -3,7 +3,7 @@ * blvalidate.c * Opclass validator for bloom. * - * Copyright (c) 2016, PostgreSQL Global Development Group + * Copyright (c) 2016-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/bloom/blvalidate.c @@ -21,6 +21,7 @@ #include "catalog/pg_type.h" #include "utils/builtins.h" #include "utils/lsyscache.h" +#include "utils/regproc.h" #include "utils/syscache.h" #include "bloom.h" diff --git a/contrib/btree_gin/expected/install_btree_gin.out b/contrib/btree_gin/expected/install_btree_gin.out index 0fae4c5bfe..631a0df722 100644 --- a/contrib/btree_gin/expected/install_btree_gin.out +++ b/contrib/btree_gin/expected/install_btree_gin.out @@ -1 +1,9 @@ CREATE EXTENSION btree_gin; +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + amname | opcname +--------+--------- +(0 rows) + diff --git a/contrib/btree_gin/sql/install_btree_gin.sql b/contrib/btree_gin/sql/install_btree_gin.sql index 0fae4c5bfe..746e77654f 100644 --- a/contrib/btree_gin/sql/install_btree_gin.sql +++ b/contrib/btree_gin/sql/install_btree_gin.sql @@ -1 +1,6 @@ CREATE EXTENSION btree_gin; + +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); diff --git a/contrib/btree_gist/Makefile b/contrib/btree_gist/Makefile index 5134f72611..d36f51795d 100644 --- a/contrib/btree_gist/Makefile +++ b/contrib/btree_gist/Makefile @@ -6,16 +6,16 @@ OBJS = btree_gist.o btree_utils_num.o btree_utils_var.o btree_int2.o \ btree_int4.o btree_int8.o btree_float4.o btree_float8.o btree_cash.o \ btree_oid.o btree_ts.o btree_time.o btree_date.o btree_interval.o \ btree_macaddr.o btree_inet.o btree_text.o btree_bytea.o btree_bit.o \ - btree_numeric.o $(WIN32RES) + btree_numeric.o btree_uuid.o $(WIN32RES) EXTENSION = btree_gist -DATA = btree_gist--1.2.sql btree_gist--1.1--1.2.sql btree_gist--1.0--1.1.sql \ - btree_gist--unpackaged--1.0.sql +DATA = btree_gist--unpackaged--1.0.sql btree_gist--1.0--1.1.sql \ + btree_gist--1.1--1.2.sql btree_gist--1.2.sql btree_gist--1.2--1.3.sql PGFILEDESC = "btree_gist - B-tree equivalent GiST operator classes" REGRESS = init int2 int4 int8 float4 float8 cash oid timestamp timestamptz \ time timetz date interval macaddr inet cidr text varchar char bytea \ - bit varbit numeric not_equal + bit varbit numeric uuid not_equal SHLIB_LINK += $(filter -lm, $(LIBS)) diff --git a/contrib/btree_gist/btree_bit.c b/contrib/btree_gist/btree_bit.c index af210439f0..f34fa87f9d 100644 --- a/contrib/btree_gist/btree_bit.c +++ b/contrib/btree_gist/btree_bit.c @@ -5,6 +5,7 @@ #include "btree_gist.h" #include "btree_utils_var.h" +#include "utils/builtins.h" #include "utils/bytea.h" #include "utils/varbit.h" diff --git a/contrib/btree_gist/btree_bytea.c b/contrib/btree_gist/btree_bytea.c index dfc25a45c6..df6c960ce5 100644 --- a/contrib/btree_gist/btree_bytea.c +++ b/contrib/btree_gist/btree_bytea.c @@ -5,6 +5,7 @@ #include "btree_gist.h" #include "btree_utils_var.h" +#include "utils/builtins.h" #include "utils/bytea.h" diff --git a/contrib/btree_gist/btree_date.c b/contrib/btree_gist/btree_date.c index bb516a9500..56031d4a76 100644 --- a/contrib/btree_gist/btree_date.c +++ b/contrib/btree_gist/btree_date.c @@ -5,6 +5,7 @@ #include "btree_gist.h" #include "btree_utils_num.h" +#include "utils/builtins.h" #include "utils/date.h" typedef struct diff --git a/contrib/btree_gist/btree_gist--1.2--1.3.sql b/contrib/btree_gist/btree_gist--1.2--1.3.sql new file mode 100644 index 0000000000..726561e87b --- /dev/null +++ b/contrib/btree_gist/btree_gist--1.2--1.3.sql @@ -0,0 +1,65 @@ +/* contrib/btree_gist/btree_gist--1.2--1.3.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION btree_gist UPDATE TO '1.3'" to load this file. \quit + +-- Add support for indexing UUID columns + +-- define the GiST support methods +CREATE FUNCTION gbt_uuid_consistent(internal,uuid,int2,oid,internal) +RETURNS bool +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION gbt_uuid_fetch(internal) +RETURNS internal +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION gbt_uuid_compress(internal) +RETURNS internal +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION gbt_uuid_penalty(internal,internal,internal) +RETURNS internal +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION gbt_uuid_picksplit(internal, internal) +RETURNS internal +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION gbt_uuid_union(internal, internal) +RETURNS gbtreekey32 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION gbt_uuid_same(gbtreekey32, gbtreekey32, internal) +RETURNS internal +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +-- Create the operator class +CREATE OPERATOR CLASS gist_uuid_ops +DEFAULT FOR TYPE uuid USING gist +AS + OPERATOR 1 < , + OPERATOR 2 <= , + OPERATOR 3 = , + OPERATOR 4 >= , + OPERATOR 5 > , + FUNCTION 1 gbt_uuid_consistent (internal, uuid, int2, oid, internal), + FUNCTION 2 gbt_uuid_union (internal, internal), + FUNCTION 3 gbt_uuid_compress (internal), + FUNCTION 4 gbt_decompress (internal), + FUNCTION 5 gbt_uuid_penalty (internal, internal, internal), + FUNCTION 6 gbt_uuid_picksplit (internal, internal), + FUNCTION 7 gbt_uuid_same (gbtreekey32, gbtreekey32, internal), + STORAGE gbtreekey32; + +-- These are "loose" in the opfamily for consistency with the rest of btree_gist +ALTER OPERATOR FAMILY gist_uuid_ops USING gist ADD + OPERATOR 6 <> (uuid, uuid) , + FUNCTION 9 (uuid, uuid) gbt_uuid_fetch (internal) ; diff --git a/contrib/btree_gist/btree_gist.control b/contrib/btree_gist/btree_gist.control index 74d0e92591..ddbf83dc32 100644 --- a/contrib/btree_gist/btree_gist.control +++ b/contrib/btree_gist/btree_gist.control @@ -1,5 +1,5 @@ # btree_gist extension comment = 'support for indexing common datatypes in GiST' -default_version = '1.2' +default_version = '1.3' module_pathname = '$libdir/btree_gist' relocatable = true diff --git a/contrib/btree_gist/btree_gist.h b/contrib/btree_gist/btree_gist.h index dcffbb5178..9b3e22c469 100644 --- a/contrib/btree_gist/btree_gist.h +++ b/contrib/btree_gist/btree_gist.h @@ -31,17 +31,8 @@ enum gbtree_type gbt_t_bpchar, gbt_t_bytea, gbt_t_bit, - gbt_t_inet + gbt_t_inet, + gbt_t_uuid }; - - -/* - * Generic btree functions - */ - -Datum gbtreekey_in(PG_FUNCTION_ARGS); - -Datum gbtreekey_out(PG_FUNCTION_ARGS); - #endif diff --git a/contrib/btree_gist/btree_interval.c b/contrib/btree_gist/btree_interval.c index acccb8b42e..e5cd0a281d 100644 --- a/contrib/btree_gist/btree_interval.c +++ b/contrib/btree_gist/btree_interval.c @@ -5,6 +5,7 @@ #include "btree_gist.h" #include "btree_utils_num.h" +#include "utils/builtins.h" #include "utils/timestamp.h" typedef struct diff --git a/contrib/btree_gist/btree_time.c b/contrib/btree_gist/btree_time.c index 41d9959214..27f30bc112 100644 --- a/contrib/btree_gist/btree_time.c +++ b/contrib/btree_gist/btree_time.c @@ -5,6 +5,7 @@ #include "btree_gist.h" #include "btree_utils_num.h" +#include "utils/builtins.h" #include "utils/date.h" #include "utils/timestamp.h" diff --git a/contrib/btree_gist/btree_uuid.c b/contrib/btree_gist/btree_uuid.c new file mode 100644 index 0000000000..44cef64cac --- /dev/null +++ b/contrib/btree_gist/btree_uuid.c @@ -0,0 +1,238 @@ +/* + * contrib/btree_gist/btree_uuid.c + */ +#include "postgres.h" + +#include "btree_gist.h" +#include "btree_utils_num.h" +#include "port/pg_bswap.h" +#include "utils/uuid.h" + +typedef struct +{ + pg_uuid_t lower, + upper; +} uuidKEY; + + +/* + * UUID ops + */ +PG_FUNCTION_INFO_V1(gbt_uuid_compress); +PG_FUNCTION_INFO_V1(gbt_uuid_fetch); +PG_FUNCTION_INFO_V1(gbt_uuid_union); +PG_FUNCTION_INFO_V1(gbt_uuid_picksplit); +PG_FUNCTION_INFO_V1(gbt_uuid_consistent); +PG_FUNCTION_INFO_V1(gbt_uuid_penalty); +PG_FUNCTION_INFO_V1(gbt_uuid_same); + + +static int +uuid_internal_cmp(const pg_uuid_t *arg1, const pg_uuid_t *arg2) +{ + return memcmp(arg1->data, arg2->data, UUID_LEN); +} + +static bool +gbt_uuidgt(const void *a, const void *b) +{ + return uuid_internal_cmp((const pg_uuid_t *) a, (const pg_uuid_t *) b) > 0; +} + +static bool +gbt_uuidge(const void *a, const void *b) +{ + return uuid_internal_cmp((const pg_uuid_t *) a, (const pg_uuid_t *) b) >= 0; +} + +static bool +gbt_uuideq(const void *a, const void *b) +{ + return uuid_internal_cmp((const pg_uuid_t *) a, (const pg_uuid_t *) b) == 0; +} + +static bool +gbt_uuidle(const void *a, const void *b) +{ + return uuid_internal_cmp((const pg_uuid_t *) a, (const pg_uuid_t *) b) <= 0; +} + +static bool +gbt_uuidlt(const void *a, const void *b) +{ + return uuid_internal_cmp((const pg_uuid_t *) a, (const pg_uuid_t *) b) < 0; +} + +static int +gbt_uuidkey_cmp(const void *a, const void *b) +{ + uuidKEY *ia = (uuidKEY *) (((const Nsrt *) a)->t); + uuidKEY *ib = (uuidKEY *) (((const Nsrt *) b)->t); + int res; + + res = uuid_internal_cmp(&ia->lower, &ib->lower); + if (res == 0) + res = uuid_internal_cmp(&ia->upper, &ib->upper); + return res; +} + + +static const gbtree_ninfo tinfo = +{ + gbt_t_uuid, + UUID_LEN, + 32, /* sizeof(gbtreekey32) */ + gbt_uuidgt, + gbt_uuidge, + gbt_uuideq, + gbt_uuidle, + gbt_uuidlt, + gbt_uuidkey_cmp, + NULL +}; + + +/************************************************** + * uuid ops + **************************************************/ + + +Datum +gbt_uuid_compress(PG_FUNCTION_ARGS) +{ + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + GISTENTRY *retval; + + if (entry->leafkey) + { + char *r = (char *) palloc(2 * UUID_LEN); + pg_uuid_t *key = DatumGetUUIDP(entry->key); + + retval = palloc(sizeof(GISTENTRY)); + + memcpy((void *) r, (void *) key, UUID_LEN); + memcpy((void *) (r + UUID_LEN), (void *) key, UUID_LEN); + gistentryinit(*retval, PointerGetDatum(r), + entry->rel, entry->page, + entry->offset, FALSE); + } + else + retval = entry; + + PG_RETURN_POINTER(retval); +} + +Datum +gbt_uuid_fetch(PG_FUNCTION_ARGS) +{ + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + + PG_RETURN_POINTER(gbt_num_fetch(entry, &tinfo)); +} + +Datum +gbt_uuid_consistent(PG_FUNCTION_ARGS) +{ + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + pg_uuid_t *query = PG_GETARG_UUID_P(1); + StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); + + /* Oid subtype = PG_GETARG_OID(3); */ + bool *recheck = (bool *) PG_GETARG_POINTER(4); + uuidKEY *kkk = (uuidKEY *) DatumGetPointer(entry->key); + GBT_NUMKEY_R key; + + /* All cases served by this function are exact */ + *recheck = false; + + key.lower = (GBT_NUMKEY *) &kkk->lower; + key.upper = (GBT_NUMKEY *) &kkk->upper; + + PG_RETURN_BOOL( + gbt_num_consistent(&key, (void *) query, &strategy, + GIST_LEAF(entry), &tinfo) + ); +} + +Datum +gbt_uuid_union(PG_FUNCTION_ARGS) +{ + GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); + void *out = palloc(sizeof(uuidKEY)); + + *(int *) PG_GETARG_POINTER(1) = sizeof(uuidKEY); + PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo)); +} + +/* + * Convert a uuid to a "double" value for estimating sizes of ranges. + */ +static double +uuid_2_double(const pg_uuid_t *u) +{ + uint64 uu[2]; + const double two64 = 18446744073709551616.0; /* 2^64 */ + + /* Source data may not be suitably aligned, so copy */ + memcpy(uu, u->data, UUID_LEN); + + /* + * uuid values should be considered as big-endian numbers, since that + * corresponds to how memcmp will compare them. On a little-endian + * machine, byte-swap each half so we can use native uint64 arithmetic. + */ +#ifndef WORDS_BIGENDIAN + uu[0] = BSWAP64(uu[0]); + uu[1] = BSWAP64(uu[1]); +#endif + + /* + * 2^128 is about 3.4e38, which in theory could exceed the range of + * "double" (POSIX only requires 1e37). To avoid any risk of overflow, + * put the decimal point between the two halves rather than treating the + * uuid value as a 128-bit integer. + */ + return (double) uu[0] + (double) uu[1] / two64; +} + +Datum +gbt_uuid_penalty(PG_FUNCTION_ARGS) +{ + uuidKEY *origentry = (uuidKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key); + uuidKEY *newentry = (uuidKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key); + float *result = (float *) PG_GETARG_POINTER(2); + double olower, + oupper, + nlower, + nupper; + + olower = uuid_2_double(&origentry->lower); + oupper = uuid_2_double(&origentry->upper); + nlower = uuid_2_double(&newentry->lower); + nupper = uuid_2_double(&newentry->upper); + + penalty_num(result, olower, oupper, nlower, nupper); + + PG_RETURN_POINTER(result); +} + +Datum +gbt_uuid_picksplit(PG_FUNCTION_ARGS) +{ + PG_RETURN_POINTER(gbt_num_picksplit( + (GistEntryVector *) PG_GETARG_POINTER(0), + (GIST_SPLITVEC *) PG_GETARG_POINTER(1), + &tinfo + )); +} + +Datum +gbt_uuid_same(PG_FUNCTION_ARGS) +{ + uuidKEY *b1 = (uuidKEY *) PG_GETARG_POINTER(0); + uuidKEY *b2 = (uuidKEY *) PG_GETARG_POINTER(1); + bool *result = (bool *) PG_GETARG_POINTER(2); + + *result = gbt_num_same((void *) b1, (void *) b2, &tinfo); + PG_RETURN_POINTER(result); +} diff --git a/contrib/btree_gist/data/uuid.data b/contrib/btree_gist/data/uuid.data new file mode 100644 index 0000000000..df118d3670 --- /dev/null +++ b/contrib/btree_gist/data/uuid.data @@ -0,0 +1,703 @@ +5ad32d7e-b463-4363-a65f-52475d9fab27 +7787b66e-cf0e-48c2-b989-1e44e8a00891 +75ec8a55-afcf-442d-9e1d-f9d67a15caf9 +6f36f2e9-5e58-4961-9e8d-9c3ca1cfcd44 +78f6d184-f74e-4a38-81ce-a821e301e9ac +1aa4bf49-dd76-40df-a86c-393fd202b710 +98559f1d-00b3-417e-bc57-9053545a260d +ac24b4d7-1a8f-4abc-a02e-b3294497d18e +a425d99f-ee91-419a-8cd1-6908b8c89679 +815f3632-4d1b-42e3-8dbf-68a20e7fbea5 +ae212041-e64a-4ff1-b8c9-b922fc3f2087 +8e580963-0584-4391-9f1e-3e607d435bd8 +9348cf2f-fe8b-4f05-829e-e2f732482bcc +807b3ff5-0dac-46e1-ba10-07753ec4c7f5 +93325505-83f0-41f4-a060-0d6e1a166815 +cabeaad4-0096-4bc8-8d29-29623d3658c9 +8edda4dd-07fc-4457-b9c0-a28a97cdf9ee +4b7b09ae-d11d-4d54-aad2-c7dcbce92e04 +3ba8ace3-be63-4a11-b057-8ede07d49089 +70dfc341-127f-4d54-a8d4-8159eb119a8f +\N +f4910786-02d1-4874-9be7-c2cd5774fa1e +61a8407e-91f4-41f4-8050-32c8659839ac +d23c6778-d021-426b-8435-e7ee7172a456 +\N +77b3bb98-f8a6-4dc1-b2db-174da47ef88d +4ed9962e-9f7b-4bd2-b791-62c87e7e0f32 +\N +bf30fce0-2497-4594-94e2-5dabb58fa3d6 +289dcd8c-8046-4748-b1e7-3afc51e3791b +622aa432-d5e9-4d02-8a3f-09813dcc00cf +f95c69c4-7d22-41c2-89c1-6bcc6835d478 +2b4ed1c1-38e2-495c-8fba-f2060b983f8a +05905429-70b8-408b-a9b1-b8f00522ec7a +8b1dcbd2-10ca-4a37-a080-a1c846519370 +a6225a20-25c9-4afe-bc33-e6f600eb57a3 +b0121e3f-157c-4c8f-acf3-78dfc752bcb5 +\N +\N +11f510fb-ae06-4542-b936-cb5713908e10 +\N +26293032-dbd0-4914-be29-c060c5adf98b +d3d0b0ce-b60c-4864-9557-ba4a9cca8b1f +16c70611-bbfd-4a46-95fd-3c9e12ff4641 +27dc15a1-5518-4310-bb31-52da9f148afc +a86c2830-282a-4a74-8b5a-e5b562325d82 +8afadc39-3a85-490e-a31e-18d5e787a639 +1159af7d-4d72-4651-a013-9de9f3f03002 +5835b0b1-6a50-44c2-ab41-81fa34a29411 +\N +e031ab87-ccb2-496c-9eba-9966415f82d7 +\N +67b1194b-b700-440e-aa35-93f118707632 +a9a88b6a-c2f0-4de6-ab99-b34853aae425 +c9e3aeda-2001-4ab9-aaf1-57b33d841960 +6bbc3fae-1495-4178-8445-04960dd97c56 +bd7e52f5-4362-4447-9f7c-da14ed54266b +145fd346-4057-4e91-aa82-594d7a16ebce +\N +029d9c72-77e1-4951-b185-30574d00862d +d9233d92-3491-4985-a6bb-763f177535a5 +abe1ffca-8325-4041-8acd-b08904f76cb0 +0c8afca8-f720-4c4b-aab4-e061011db5ca +4f636f73-71e8-4b14-b4c5-25233d115421 +f05a62f1-f495-4ea1-9e20-433c67d2c94e +a21ee4b2-e9bd-4510-9b74-0bac543fc378 +a41bf7a6-92c2-48f1-80ef-0c3d4e002b5f +ed6b5777-b1b4-4e85-ab12-ce1f8054ced1 +04b9cc30-6d01-4f5d-9254-81eb78fbb4af +a89561d0-88e2-43d0-9548-35be00b1f028 +c77ad187-1ed9-4b25-a474-35bf8481cf25 +cc4cf4a1-aa64-4916-ae50-5fa7bb5c3b3b +\N +70337711-dd30-4454-bd6c-0e8f77ba34a0 +1ed02b49-aace-4c5b-a1cf-bc20e2edf03c +84b0f797-baa6-448f-ba29-0234e64ac30b +40556603-648c-4359-9c4c-5e76f21efd1f +af21ec76-27d6-47d8-9ede-1b08049410d3 +0f889e8a-e3b5-46bb-b222-e91cf32623ff +3f5403c1-16b1-4a36-bf4b-77333226e8e4 +5c5ebc3f-aced-4036-9b4a-59e19bd9c74c +8acec555-d518-422b-b416-19a2c5cbf825 +ab1effba-c614-4af2-9c9a-df8f6566f427 +4ae0722c-1c55-4ef1-a9aa-ddd9c43f3dd0 +77e2f0bf-cff2-4128-92da-c6d4bc656267 +2e643fa5-23db-4073-8dac-6f714f823af0 +d6624eac-e776-4e18-9d3c-d6c265a8c378 +\N +623353ca-0675-4a05-94cf-7bb62e49aece +2d29a192-0272-49fa-99ea-9b30e81f0b47 +54cf75a7-6ece-4e20-8f24-036f3daa2fa1 +8964987c-bacd-4474-83a7-2ea51ac7ff3a +87f3e366-6f70-4304-8789-e03f94adcadb +603c2f61-c91c-4f7b-9de4-ad43ea68b00a +fd036a77-ee2a-4c33-a985-709d8667c1a2 +be90eb3d-c147-447b-8ff1-2a62aba6ef3c +448ec399-4249-4daf-85f8-23ad8cc7fbdf +9788716f-1852-4b37-a2c4-f4f65d4eeef6 +bed0413b-64f7-4cf3-b2bd-765b10a31ba8 +6add9145-07d8-4d1d-bad0-57c2a914b90b +\N +caf27337-384f-4f51-92ce-76bd5dbf7317 +0f73ab51-4dc6-4cbf-b74f-faced034c866 +0b8c972d-f1e4-4150-bd9e-baee71af1ca9 +0567dd6d-0386-4002-849b-591d1512cc1e +4c783517-29df-4efa-8f40-12150943e6ab +1be634a9-77cc-4e17-8b24-817067dd2235 +ab233cca-286f-4977-ab03-0c9870b17934 +88d77def-4019-4b0d-8de5-47f3b84b4c1f +036f53a5-5270-4844-bedb-251512538a33 +\N +\N +afca4ef6-56ac-4bbe-8c44-f54858b55ab7 +8613d2fe-d9b6-4491-a70d-8de3ad41b4df +f084c252-43db-4735-bb47-eb45741cedf8 +d35f523d-4c8b-43a7-8839-2c5567ed4934 +40677618-afed-45cd-9299-ff715494d56f +7a5aa5c4-884f-460f-a9f4-a0033eb82de2 +26007d37-61cc-4386-a85e-08e56de23a2c +3753e811-da3f-4a23-92ce-1ae502c99195 +2dfb1eb2-56bf-4b0f-b2f8-3ec2dc2b0191 +551d2a52-f84a-42e4-aa2b-84f7000a3926 +\N +\N +b9cd6a67-e12b-4a0b-b935-92e267ea776f +fd4ec635-a1e5-4fcb-89a3-57bf8aa408b8 +6599e40d-a602-4a54-a24b-a694432992a2 +\N +55e65ca2-4136-4a4b-ba78-02ecb8053cf3 +c5b2bc4d-acf9-4b11-ae9a-02ecb8053cf3 +34bb5f60-3e47-445a-acbd-a5889334f4d5 +743008b5-0779-4d50-8662-1c5988335c33 +71317e40-193f-4a7f-a94a-a188847b0249 +23f14966-adfc-4460-84fa-14190d33d55f +d1bd4bba-8a17-4e8f-93d9-ed09f4719ea4 +b5964792-f607-4cbe-9759-3e459a90fe5e +c49c96e9-77ec-4b75-a3d3-00f9fa8c9ac2 +842f694a-426c-45c7-a7a9-5d750adbdacb +c48446ee-c9f6-4038-9ca2-e32f8706c36f +fd0ab627-022b-4fa5-bb9d-0ada8088c9e6 +b27dd1a0-7938-4e42-a9e7-93672a7d85a1 +\N +5ae9add1-28d5-4fd4-bf1d-f5a3ebabc31e +55e65ca2-4136-4a4b-ba78-cd3fe4678203 +25706dc9-61d1-4c67-be11-22f953132d48 +723f5921-c592-40a8-955c-7f46995b8173 +69c29563-77e3-43e6-93e4-d6ed321a294e +8d6b7ea4-d062-4fb9-a20a-d718abd9e331 +b1e945bc-2a8e-4d1c-b9e7-322b95d31b86 +4ef84213-0b39-4d86-80bb-14d2376f77cf +fd3daf86-96e0-42b7-b83a-c2781aa28e4d +ad6c141d-e257-410b-8596-77153d37b428 +40dd6844-7b56-4f39-a7cb-c00ae3870108 +883559f7-e3af-4f44-aff3-a4bd906e5f86 +98c04f9a-d3b7-4d21-9f89-43ef124d48fa +\N +55e65ca2-4136-4a4b-ba78-698a09529f02 +ee145a4b-6016-4914-b947-698a09529f02 +931473e1-2cb2-4951-9ab0-039396dc2ccb +0df573b5-3ef9-40ef-9b05-208e649965d1 +b13a6d18-33c9-4aa0-b167-88542cd5d8ba +73cbd742-37db-4497-9a30-e10279e9cb10 +63a68ba8-e223-4db7-b56f-459d25d3f873 +aa2e9b1e-e09c-4848-983e-aa4adf34938b +2d58bb19-ac14-42fe-b427-59798b8d9fcb +5d3b3f34-ce9a-4ee6-9400-c7bf7576ffa8 +41945dd7-9fb0-47af-8ee9-10e5a530da3e +\N +c3a9b409-4e0c-4426-8a3d-a87236d189bd +84da10fe-818d-4a3b-85fc-d4c169ca92bc +12a7071d-902d-4438-9c40-c2cd875b51f7 +2e7e60fb-ba46-4005-b6b5-e3630b699254 +9782a6b8-d676-45a8-8991-1c44e60764cc +6760f7e2-6b5a-4ce7-a66a-9014068fc8eb +\N +\N +2dab7131-2ba8-4def-9b28-00c0b1ed929a +9d3df737-16fd-481a-bde6-12a08a01e2f5 +d8390c84-1e90-4759-bd72-2629ca4c51f4 +0c1d5e42-5070-4e51-8076-8e8c15148f99 +9374026b-0ec3-4c44-b656-36520d322eec +\N +\N +ad0aa9a0-122c-4025-b889-70778af8e6e4 +948d0dea-5d30-45da-8867-09d2e1fbedb9 +d295f644-5f4a-4808-b966-b14e73d9fa2a +2de79a17-f91b-4310-ad74-dfa0729ff94d +\N +23eda39b-4f4f-4355-aeba-72771f922d20 +bccc111d-6f15-42c4-95c2-2c3d3329e83c +c4f864e2-f81a-4b65-bd7f-cac745bd7f32 +10447976-1ef1-4599-85fe-d837074c6ea0 +8eecc1f2-77b2-4058-811c-11efb47eb662 +98ad70bc-39b0-4b33-a104-241c6970c4c3 +15c04e8c-69d9-44b7-a177-d08c5b181045 +c6de918d-6536-47b3-b80f-80d049cfe550 +548321e5-cde7-4d74-9bb3-929244806e13 +7e046db3-d1dc-46b3-81e2-fc867ee83298 +5dd5cc44-4ad1-4658-9b4f-509c35a4976e +1aecf136-7583-4d31-980f-7fa5c4610e50 +ddb79c27-a80d-483a-9a52-c61ae2f4f93f +e7aa3080-4d09-43ae-8a2b-5b539ffef909 +aeba0aac-6b8d-4d8e-a5b8-a37359c457c6 +64b5c8e8-118b-414f-9da3-73286249243c +8b72b6d2-d3bb-4e74-a79f-577ff8767777 +dccd9254-24b4-4269-bf07-cfbbd349df54 +51cb6ab8-06c7-4280-9e0f-b2b9dcf026a3 +1f3d16eb-895f-48dd-a9e2-18eda41dacea +3ecc08b6-2b67-442c-92ef-b74af4cb4f42 +b55c7f4a-3d05-43b9-846a-23b86a73d202 +4f54dfd8-39fd-4178-bafa-97b34f131552 +d6874b48-96c0-459f-8dd1-7f7dcbc44b22 +93a213c8-6e28-4eb7-8a94-e1b18e8bebd6 +0743014a-e4a0-4eb9-a9ab-23b0d0d96782 +a7ffb6c6-4e3d-4d08-9cbc-297d8b1bc29e +45e788c4-4054-4d80-886a-e4f006936b7d +c51c64be-f130-40c1-95b9-adb39ef25385 +3af1d3cb-df6b-4d26-910d-a314a57f8550 +\N +477c1cd3-e9c9-4252-bc7c-4db57368ffc6 +b49ecde1-7413-4d6e-80c1-5df680d25617 +1f127009-eb85-4e7d-bfb1-1d804d86609b +\N +25e6a224-70a3-44dc-8faf-50feecee3480 +79094fc2-36d9-4521-bf36-0f6e0850fb6d +cb9b1ab9-96e3-4ac5-aa51-8c3c47437893 +c09d4ab8-5f03-496f-ad31-4b9e7348b9da +d5ab17e1-7017-4fbf-a30e-73a97a85a852 +\N +8c937920-7219-43fe-8436-97aca339a5e5 +b8d001a3-036c-4f15-846d-32e229d66985 +bf2cae32-9096-4ae4-b0c7-efdafdd16e0d +d916d001-fc9b-4e05-985c-b172b873c217 +\N +\N +e2c40a42-ef79-4754-a089-e254345896c3 +953fb2d0-d53a-4cc9-ad48-547263b85399 +8e2b1b14-1c56-48b9-a2b6-7868b42e6efc +\N +\N +76b7f2cb-00e9-4936-bcd0-ebf1db9c6fec +e24d88fb-6219-44c7-9f70-d34e0b274cdc +fda48ed2-113d-4403-b2dc-57f7afe25842 +9aa44ba6-6c48-418d-8689-eab1112b3fbb +42936d25-09a3-4af5-ab98-8c1216c5eca9 +\N +a9ddecb1-b762-4cda-a785-cce77c51c67a +f733a811-b83c-4a29-a59c-786825ea2070 +95e94fe5-eea0-4656-bc34-15724a4785a2 +521c55e4-3a5c-4064-b42f-0e8023af9c94 +a3379a9d-4b32-4956-a814-57b46db4bdc2 +0e46cef6-49ed-4a54-a6be-debcb7546583 +\N +1b1f4424-5c05-4ee6-8eb6-1deb677c743f +\N +caaf024d-ef32-42e5-8875-6fe563e7e18a +\N +98e9ce77-8677-44aa-8703-4633dd089225 +66037e2f-634f-4096-8823-9ded5cb533bb +\N +f6726b9f-8a0b-498e-8479-3ffa7af0cd62 +\N +4fd27a3c-2dd1-4f3d-9f48-a50407e9d1a3 +75737e5a-a509-4239-a627-99e430a4c3d1 +6a8bd5d4-7545-4dc8-86c3-003321cfd437 +73e26e64-baa7-4a9b-8833-8bd822c47146 +\N +d6de86fd-3fae-4de2-9082-e86e53b6ad7c +1143e251-091a-408f-b7b2-c12d05b42c2c +4cc745fe-4667-4041-b941-4a3a23f9c727 +ae7b16f4-9ba8-4dc0-aae7-f78258d4993b +38c5d6b2-ae34-4054-aa07-9a689afb23e1 +3421dcd4-553b-4ba6-b661-5cbf687b982a +\N +75ab9d18-5ba5-479c-b3cc-bcf3c41618b8 +c5a768bc-7765-4973-bd8b-a9528279a0a7 +e7b98405-47e6-404d-ab16-bb76fcca2b1d +\N +6b764c11-a1f1-4ae2-ab87-88bdf7597cbe +\N +e439cb96-6502-4207-a0c8-2fa6bf583bd2 +\N +0d3089c0-3e26-4425-b48a-3e8f18c8b5a2 +1a625bc4-f83b-4735-bf01-a9f748080fa5 +1d1f382c-c702-4c59-84f1-4b4e2f01d1ca +8d3b094e-112e-4535-87b3-04272426a956 +616f4879-2a33-4a5f-a776-08462d27ee1b +e2c83f19-3163-487c-8fc1-7fc00d40ca75 +dbf94f48-5f01-46dd-a13d-def8f9dbb6e0 +8c37b9f1-9766-4a5f-a222-eded294dad76 +\N +4cb9a4a8-e4bf-4757-9d68-36a3e24d7b6f +071ba528-c84a-45fc-8ac5-2368e6c640ae +ad34c9ca-0a4b-4c23-b64c-ccffa1f4dcd8 +4915fbe9-84b6-4bec-b6b4-50ff0cc49e9f +622ef77b-e22d-4ca2-850b-298abb39d870 +3e1803c7-8109-43f2-a742-b4ae6e56be55 +\N +0de0b43f-3e59-4060-a43d-baee17dd2c57 +\N +1a8e57f0-e65b-4e55-b46a-207825e00287 +\N +\N +1877c37c-3567-46e6-9afe-222ac3ccf36f +8f4bab7d-9454-4081-b1af-8e4956ab940f +c1d23aab-ce09-4afc-a95c-b9b0f7b9c16a +04761b0d-40ce-4cb2-a7e0-b1f6d582be26 +a29059f5-d4bc-446f-b903-6f09ec57a410 +4f9fcf12-54ff-442e-a7e3-6aabf45fa474 +facf76d4-e82b-44a3-9d7c-50a84395a2dc +\N +84484041-8e47-4349-91d6-418e9b584750 +44b949a1-502e-4309-af86-90bdfb04a085 +c5da9f0a-cca7-4b5b-82c2-1108e10989df +98e487b8-9527-4fcd-a20a-812c909f1342 +e950bf7c-280d-4774-8891-6cf6da8c8ab4 +d5a28af5-f357-4de9-a8e3-3518a8ca5556 +ae450238-e659-4253-90ee-afd66a676515 +294509e2-b4e1-42a3-8982-b7dca385e4c9 +9546a087-6cac-47d6-b55f-3828df9aec99 +4a715abf-18d1-4ffc-9ea3-fd3f069502d9 +e0e07aef-ce8b-4499-befa-430724707d66 +4df8c6d6-278e-4ba4-af45-7240805ce0a0 +1637abb1-1d05-4055-98fa-296fe8f8bbf2 +e3850663-b73e-4f0a-8107-0775825783ef +7b2dbbbf-2c82-49dd-9383-0edd1aee6d89 +2b99818e-2c53-4ab2-8f78-29bdbaa208b2 +22787985-d2c1-4af4-8b90-7bc441123952 +153166fb-923e-41d4-8413-edad8959a8d5 +732fab66-3055-49f8-807e-463fae914988 +1c39ccc7-2b24-4760-93d3-3e687ed04e1c +33f3d119-ff2a-4341-8145-b69f67e11192 +0370cd89-a0c1-4d8c-85fe-3df1eddc734b +d5a5e95c-e99c-48f6-9ebb-765651b893f9 +3e73a023-7b53-4323-a1f3-511809d322dc +44d2a25c-933c-4345-8d19-cc52daaa9f11 +fc25f498-455d-4a13-9ca4-9ed2b843da17 +f9737152-aa7c-47a3-b96f-d0560ccea84f +\N +c1140446-9885-4a23-a709-593c0ba3818d +050474c6-e6f5-417f-bcb8-2cc288cc412c +9f07cb2f-aec4-4108-a07a-ea51366043f2 +4d9cf071-119b-497d-88de-0d05d21bac34 +7f5de1dd-3848-4ad8-a0e6-fb4039eec4f8 +f97c4e03-e8ce-443f-846b-82485c8bf04d +2354e08c-8415-4b24-8cc2-b7b7616b6588 +b0a5e7da-9382-4a9f-b64c-0c4e5c3755ca +c4812583-5689-4384-8044-e200f796afee +890b609b-ac04-4bf3-9070-492a5db11e1c +b0789be3-59ad-44e5-b1c6-394df496ae1f +512ee0f6-380b-4758-ae20-b10d578473a9 +ad84303a-90e0-44dd-a7a2-b6015e748067 +986947bf-e924-4fb8-bdec-bd91f1b9d634 +fa576306-7eb6-411d-aa92-9e67678530ee +\N +3d66ae17-f27e-45f0-8b95-d47821b1d09c +e8f40639-2c3e-4802-96e1-b8ccf15762f1 +482c9541-9fa9-444f-8155-ceb86056f2f7 +f8dbf3c1-c67f-4a71-8bb1-b754d2fc4d9d +4764906b-3b71-4ccf-80d2-fb985af7728a +628312b0-5f3d-4856-a3b0-6e7f60dd19ee +37b5c576-d2c0-40b5-91cf-712b41dea919 +e7eefe4c-e647-40ba-bde1-bf4aa780b0ab +\N +4089198b-e1f1-4cf5-aa74-1e32aef1f034 +\N +5133a3c7-b9cd-4659-ad99-0453b433f237 +7d6c0ec0-0c7c-4a98-9d75-74a937b7ecba +74faeb7e-e0ac-4505-b2c5-bad6a39c6abb +ad895aff-3527-423b-bc82-607d9586f5fc +19a14c87-ab30-4747-8dc4-7599b4015960 +44955907-c727-4cab-aec3-464332e444fa +\N +b5d4dc6b-b65b-4a36-8f16-cf9760631718 +\N +49b4a368-b530-49ec-b8ed-7664c2dda4cc +e70020b6-eeac-425b-a3ce-9f5ad642f371 +448473ab-2a0f-4200-b7a7-b7583002779e +\N +\N +8a8b74f9-f49a-4f77-b6ab-2011df5645ca +\N +67ae0fa2-08c6-4566-92c4-adae5be3c3cc +1453d200-133e-4df3-9723-eb43bd21d896 +a7f3072e-e567-4e23-9bd0-70aba0554281 +f9caa2e9-6d43-4559-a9e7-6e5d7e7b2769 +b6a0b42b-70a3-42e0-b623-9dee8e2d3b85 +\N +05f2c97f-4c81-43a2-9c7b-8a1cf8de2474 +9287055b-ef1d-4b7f-bc28-fd637adaf530 +e0ed08d4-2521-46b1-983a-03c3cf915e42 +285a1259-f929-4e37-b25b-62af93fb1ea1 +d76631da-ace1-472c-a23d-7d4f2702f771 +80f89372-02be-4ad0-a1e5-9a2490769427 +\N +3c1043f7-f77f-4788-abc7-5615804ccd69 +a3942f4f-27f4-44bf-bf28-6ae854d4d346 +3b741249-a9bd-452b-bd08-9ae337134f13 +5aea4b8f-7dbb-4b7a-ad1b-cee1d93a5393 +cae01e8c-e75d-4c3d-8d90-ee3ebdb011d0 +13aeefb0-dbba-4cee-b108-931f23e286b1 +\N +40aee193-6c24-4a13-a004-9f4dec1ab2cf +2b731fff-597d-4a6e-888c-2ec72fe0dbef +4581b196-149e-492e-9053-5040207dcc19 +68d07598-261e-40bc-a2f5-e8f72cc86104 +94c1ecf0-2bdc-4d0f-962f-226a9617b8cb +2fcfe646-edc5-4397-8032-c4b4cd88afce +2ed39277-375a-4e9a-846d-660fe531bed2 +1244efdd-5d49-403a-9649-2550abae81f2 +281b757c-a039-4668-adf1-ff020ecf17ae +10f75609-865a-4b80-b5b2-39c67aa70c33 +8fb26a73-0535-4603-961e-217353617786 +98a14b8f-9a24-4c1d-b823-26d07b3d0e30 +200890d3-e23d-42dd-85f2-e9e4961495e6 +0faebfcf-6202-4799-b302-40c258d546c3 +714a3c57-cfdf-4db4-81f7-8bc0b9119f51 +c4f0d33b-3b8d-46b7-af89-2f5cce9d495a +\N +0a00b315-9668-493d-ab38-48d20cb5756f +a0a20648-1759-4330-94a3-e39746fdb30a +02890263-b147-4323-b59b-d533ea9d436e +ed12380e-14ff-4ec2-a47d-1b57dcd9cd68 +6d23b5ae-ca06-4aa7-a282-d96315c3ba83 +dac7a9bc-97e3-46e5-a543-ee4071ae9f0a +65995243-a887-407f-b5de-f6b25b07e3a5 +4831f146-46fe-4d57-9569-80852b0f655b +46037b99-bc54-4266-94cb-384c062346e4 +10661769-8d53-476e-9be4-440258481fdd +5ddd5380-3f03-4a76-b682-b65e1ff1a431 +5e1fe5a5-14fd-46e9-afd2-54908de1582b +62c070e4-7647-4c21-a4dd-cd8203ee6b20 +\N +efd4c5c8-629d-41be-8982-e3b8352f96e2 +16a2c85a-f455-45bc-8a29-38f7f664fc7c +0360c257-6ea8-4d6e-834f-43f37a7d8f4e +e2562225-53fe-457e-b538-c089d3946aec +ddbaebbe-8294-4f8d-8452-4a46d1b43c53 +dca63b45-648f-4b4c-a36a-c53f3e0abe28 +04e91983-21f7-408b-b4eb-aa6d9359f37a +905c498a-4b99-49af-89cd-fd1d022193e7 +413d7f85-6bdd-4d50-8859-afd317c841c4 +412ca3ee-90e5-46ae-adf3-80aa6ceee633 +1a8020e7-8671-46e4-b2d3-705e206723bf +9414f47f-088c-4fb1-98f2-bc020b0d550b +8f48e9ef-ae2c-4d0a-acc6-8d4b18622df5 +614cbf04-fb3b-4678-834b-da05f70bd529 +0c96ce68-9135-4199-a351-05f9dfc641e2 +f3dfa1a0-c156-435e-9f2c-662c345b92db +\N +d7c6b8cc-2d67-41c6-bae0-3ab23f8ad65c +b8ae6503-dbed-4455-85ce-6b985b4338ff +3ba1530c-911b-463d-aa61-5d81850b5fcb +\N +0f71da52-80da-4bc5-88f7-013603f8ef06 +f59318ec-1851-4beb-b02e-6e9ca7f2391a +8b712321-af06-4af2-8654-1e174851ae59 +\N +\N +c30e01ed-17eb-495d-8381-dc87cd280002 +10537620-20b9-4706-a1fb-ec470349e4d8 +bc669e4a-bef3-4635-a3c6-47e70a307e70 +5d965491-8d0d-4f7b-bab4-b615dd97dbcd +fa76b0d2-1c46-4855-9381-3ec02b21b475 +311c71c5-e5e2-4224-aa57-fc79adb0d037 +82f18b3d-dd3c-402c-a54b-afe92a8b4582 +8a39cdbf-39c5-41a9-a4cb-c334cccc0414 +396ed0f3-8c28-40a8-a5d0-b41d2448c618 +4dc37b03-f161-4436-bb41-3e114f78bb96 +1de1ff4c-5b47-40d2-a002-ff331900c4ec +7b248f50-920b-45f3-b20b-19d75590ef3d +\N +eba46805-9b82-4ebd-84d2-5aa6cb3d8a48 +2fef1c4c-d97c-423f-923d-cbac15961fc5 +7ae4af7a-3759-4ecb-9d3f-ed5e124ab08c +f812e63b-20a4-4f58-90be-e6c7357d89fd +cd91b9fe-5daa-4087-94a7-459c54d24d39 +54f4f7a3-c581-4bff-9bc1-82d8aaec2d3c +\N +d900a862-a0b2-4776-b418-af075881c53d +593143fa-99b6-464b-b563-33e201668db0 +1d8ffc5d-1011-41d5-b3bc-18e0fe5b7375 +93773b54-be94-4b99-9bcc-e181f1b09978 +\N +7fe6a809-a67e-46ef-b686-4a982a6f6fc1 +00c65908-2e09-4974-8c61-37ec926e74fc +d6f2cc12-6d93-4159-b247-70db9120217b +29806fd9-24bb-4e50-a228-8ad6c17559ab +bd093e48-01be-4a09-a8f0-33a2bfcf23a7 +13d3db20-68e0-4cb2-8530-90648e6a756c +b5bb9551-bb70-4589-a12c-15350d85232b +6736895a-671b-435c-85b7-133c65b09cc8 +a609184a-9035-4b75-b10e-838465bace14 +98c084a0-9c30-4dc0-b8a2-2b818f650034 +122afe72-60e5-497a-92f7-c8139339f999 +6b2b6d77-f49c-4b37-a57f-c8ab6f8deff3 +6e133f18-5a70-4717-a750-1c2ee9ab459a +\N +\N +96e2dc30-cc7e-4c9e-bbbc-e4af1ce9b5f6 +0a430277-f67d-44df-88e6-3ae2e78b8a1e +15445ff0-2087-4fa6-857e-baba197a3ec9 +5a8aba7a-1feb-4acc-b57d-2520233ec15f +a17ef384-5204-4240-a493-7db5dc28a6b2 +bfa0fd7d-7d18-4c57-a066-c94be05d0730 +4de53a8d-d76e-446e-9b68-48618314f2c4 +21cb20a2-36ab-4756-8925-cf8bade61148 +a2376936-9836-4397-a3eb-e779e498ab2d +f4b3d211-79bb-4256-a460-26dac56d9755 +4c4be10f-5141-429a-9ea6-24eb1fbd5330 +a45bb987-b935-44ae-a410-c82b1f895eb5 +b341e29a-e069-4ba2-b2ba-279b53c1fcda +68a4e4f8-9d7b-48f0-8614-e2a2072c859e +dc20e7f1-b79d-4135-b90c-cd87a265169a +1c5bfa73-8814-4f5d-9718-a12417814c41 +3000c028-3656-4455-b095-0b9f5ab1dc9e +\N +3d13811e-7b7a-4779-ab87-5257a1c702d1 +a9ea4067-e53c-484c-87ae-bdb218fbec40 +9c3925cc-4dba-4dd4-8000-c646f45db751 +f2e7334b-9840-4e9c-aff4-d7ac58ecbd91 +889d6968-a515-4458-a353-4a3d8d7528bd +dc02f6d6-fec3-4c2f-ace2-6a124a61f079 +9f48ed94-313c-4607-9c23-d3a1b20eaca4 +\N +\N +2428f056-4dc2-4db1-a110-20bb54a3037a +3cc8dd23-fd3a-4855-8ffa-23d1efa4fdbc +bd3e2f1d-5869-42ff-b1c5-3f65ae2d1974 +\N +\N +8330c73d-0dc5-4caa-be02-10e136137804 +f202e559-6ab2-4b72-a6e3-1bf16cfe8bf5 +54e42957-25fa-46c7-a939-eaaa4b54a5b4 +\N +7c3b2d81-44ca-49d1-8b08-c33f691c4f3c +\N +5083bb0b-7fa7-4ee1-8e51-ce20ee53a16c +ffdd64de-2c27-4858-8baf-b179f0fa690c +6e4632ce-f908-4c13-a15a-ac5cdca38c76 +e428a015-0cca-4b09-bb5c-ee4bffbd2de7 +\N +\N +d7a270ce-7ac4-49bf-a531-e56960f56850 +80b82b49-3984-4b6f-8690-7578f992d987 +824d6c6a-273d-4bfe-8ca6-197c8477d6c1 +\N +\N +5dddc93c-c4c9-44fc-8916-a826089245a4 +21357386-e17f-457e-93b4-77295904e67f +f9598cd5-3c4c-457c-b6d8-11049bbc94b1 +05f7fbbb-1660-42da-a154-de4aa6cce4df +a3b6aeef-e8b5-4692-944f-eb5edfd6a0b5 +cb8f1dea-fefa-470f-9a9c-1e169df844ec +\N +4b12759f-10e0-478c-b2d4-7c71be9f837e +3688c161-bc5a-40a4-a9a9-6854b623a139 +\N +a6a6ac8a-b805-4f15-bc8e-71c3679221e2 +ddcdad12-0919-4b8b-acc8-e775aaf6b6a1 +0dcce500-a4d6-4d34-916b-686cc04ceaa9 +2190bba9-e7e6-413a-85e3-40735e791c1b +3f06e070-1530-47a7-8898-a94d82ea59b8 +bfb7ef50-9a5c-4341-a65d-c7b9ccb76d39 +70972a38-8f23-478c-abfd-9dbdca17dd01 +3c6ba50f-9197-4f0b-bf46-ca51aef246d1 +fb4598bf-ffa0-470e-b8eb-2d704fc08bd5 +fb2bd46e-6f43-4b2a-a122-dd6539ccc03c +49f8d0a6-b7b0-444b-90dd-1cb5d08e95e5 +\N +e8b02af9-8671-49d3-a1bf-86e222fe4ecc +\N +26c6af97-9ffc-43bd-a926-da45469c3c52 +773ec08a-9d02-4a8f-87e9-f4460d703952 +286f3446-6e5c-4b91-bb47-d6106346369f +\N +2e1c1f21-8cdb-4a33-96b2-85b3eec11e41 +d7b3ebc0-62a0-419a-a710-f9950d012f92 +3edde810-79fd-4f1f-aa10-4aa472d9384a +a13013f8-e1cf-4902-9c95-8177d8a220a9 +b7c226d3-d115-4bf8-b03c-e7f14eee2169 +91a75836-a7a6-488b-806a-e8f948c8eb46 +b30da379-97b3-4a94-b6a2-2064767d2e52 +befec357-cf20-4712-9805-34910608e2fd +ca95130e-1c44-4733-a872-c0ce24d1b3c1 +\N +f5001512-9140-43c9-a4c8-54e26f71f1cf +a3f2283e-50dd-40b9-83f3-b50dca485209 +3f7ac41e-bc09-4b74-8665-bdde3ebe47a7 +761e1883-d06e-4360-9df5-5c5caeef905c +98cffbaf-dc52-4674-ade0-f930a70b64b2 +370e189c-b821-41ae-b748-a60b6d7660eb +12563667-28cd-478d-b53c-442f7bf12c67 +\N +29fe6754-ba91-49b4-bfb7-12b3dc03081c +87aa5cc1-3332-4bf3-a669-5bb61e56a7ee +\N +8bcd3587-03fd-44a0-aab8-b8aca2bc9eb9 +9ae7c0f8-6038-48af-b01f-0c5bccac6c8f +\N +3e98dbdb-b10f-4f6d-a87a-c8f1f2b1e22a +cd53b5ef-38fa-4d68-a8ff-4eb07f4162b5 +514644a8-fe52-4bab-8bb8-4cb8c7ef7acc +\N +b01b6978-46f9-46ec-844d-1322be2cfcb2 +04675ff9-2d55-413d-a3d0-4ac0ff1d3a54 +a7ee0137-c56a-472c-b4cb-dc41f1177ef0 +bc41bfcd-e5f0-423d-82f7-ffb7da97b5dd +55824064-db88-4077-ad90-945d878e88ba +a30050dd-1a17-4659-b3a6-c4c182ff0184 +82ffa955-b664-4503-9b1c-095404dbff48 +91d67d53-ec53-4dae-95ca-da25c1cfae7d +da144505-c151-42a4-b8d5-19ff810ae6ea +cfa1ddf5-6149-4896-940e-5dc57e4ec766 +c3a56789-f97f-4d5a-b70a-7d24da43bc5f +4547a150-68f8-4984-b7b4-67ee92315b6a +6b6d5e01-b18d-4afd-8b6e-8c3af536efe4 +bf723c93-f506-4990-9e97-b65476044b30 +c3ec8969-1f70-4b19-977b-237ede99a6a5 +78f11bd7-7a10-42ae-9475-eb16ca80f1e0 +cb3bf2fe-2d6c-47e7-b1e7-ce3254d2f800 +3842e996-3d91-4cab-8cce-da007a08328b +4c55e078-603b-4d4e-9c77-c747960f6aff +16d9f806-448d-48a1-9473-4d30df05aab8 +4611148b-cf71-40e6-829f-95ae0f2c8094 +9f3bcfbc-24ea-4105-8cb8-37a0924ff5e2 +4fac2eaa-2bd1-4d9c-bd80-a7ae083efcf9 +dc5546ca-99fc-4c1d-9559-b2ed9cd3d2aa +29721775-9930-4f6c-af20-bb5b5f8d0d73 +f39a6eac-e7d5-4124-9a65-9508bfc53920 +\N +7bc9960c-cf4f-4cca-a752-b28c5805ae01 +0e1c03e3-2cca-4bc8-b160-d6c2e888c182 +b12bb0d6-45d3-4608-9992-be9804a09448 +31bc67c6-1293-47c0-9732-5094e0b996bc +a262ce01-cdf9-47f4-8f48-e94d4b9d73ce +bc7150a9-0593-444c-b7b7-cc142348f1b4 +2f1e9e36-7e1b-49a5-a83e-b330267b5051 +f919c11a-b74f-4543-9798-da31133f90b5 +8672777e-a462-4042-9604-4392bbbd3308 +37b53421-3c74-40f5-9884-b83033e9f596 +1f843010-c79a-4bd4-a0a5-0251e0389722 +c51ecb09-45b4-40ff-9934-877c168c5038 +131335ce-a059-49c4-81ae-c9d98211ff9c +f467b40d-0c6e-40b9-9959-2f7f466f18e2 +44076ea8-1103-4086-9e7d-8bfb9a65893d +79ca8799-36a4-4982-9cd7-bf93fca45d74 +82569d43-65a3-44d7-8836-2db6de03e6f7 +cb5380e0-b075-48e6-8a9a-eee854444d34 +db88f31c-ce62-43f3-9781-8a8404e6ba39 +78f33ab0-a744-4bf1-82a7-c0b319492607 +2e4b580e-7d69-42c8-9f1d-7f232a3ae74c +427b3d53-2792-47d3-9d45-087b30568413 +40518971-9590-45fb-9219-242ab3053547 +fe49087f-d8c1-4769-b814-fd8bc1611b5c +27f8a8ab-671e-4eb2-88b4-2ad41814df1c +39ebe842-6c44-4fb1-a629-3f86323ca5ea +4a341b56-3523-4163-8563-83b9db172673 +513dd3a8-7354-47e7-9eef-d2a9e59a0e18 +b8e38294-7be9-4c39-b80f-bf2c9acfe69f +e1fa23c2-b0b6-47b3-82c9-eef6e930af08 +1b86903e-c395-42c7-b9ad-1a71a1fb52d1 +632161a2-474e-450c-9b70-0f09f512bcba +73f00c2b-ea38-46bb-aae3-4cf205572baf +013839fd-03de-4fe5-a08c-466670de6cbd +5d951cfe-d988-4b69-bce8-37d66598cbc3 +4da7e8f1-edaf-404a-bd1b-e8dd3a838fe2 +1f2c1809-8b85-48e8-ada4-1fdb418fea0e +\N +1bde5bbb-5d63-4d00-b227-1a706315eaa1 +f7ebf8f8-609f-4ce9-b93c-54759305926e +\N +7c2dd991-9377-4001-8486-7f3c3a6bae9c +9fe1e97c-718b-4cf2-b270-4e0b664aaf27 +2141a8f5-da01-47cc-8104-6dd28874d8ac +304096e8-b118-41e0-8174-32dc8e1fc45d +9d5fac3d-e6f2-4341-9e59-9a155bef7b17 +b42cebe1-f01f-4409-bfc2-150aa9f13159 +91adc8a2-266c-4196-99ff-1de1c361c3ef +54d26aee-0309-4af7-9b12-bbb24eb3e4e1 +bd449351-c50a-43b2-9742-1bcb838d4d04 +9fe70798-e3bd-448a-b461-e462702a9aca +\N +c8ef8969-1332-481b-909a-340ff3fd4473 +64c68c64-f815-4bd7-b0aa-ba68bb15f611 +9f271158-ff4e-41a6-a883-913f2b36ae68 +\N +b1082d66-0065-41ac-9bc5-dcea0bbec070 +\N +3ac2d674-2e12-4db1-b998-2470cba43b11 +\N +3061f573-96e9-4307-a683-df8ab30531a5 +01ce8c0e-7672-4023-be71-5dfae5ffa7d2 +06a9e327-29ea-4913-b6b9-90781484eff4 +9735f9eb-89b3-4f42-bfb5-e2bb208b640a +21ef890c-1c8c-4890-8c6d-851eebe68f40 +c35686c4-cfcc-48ff-b6d9-7c8da68dceb1 +3f08e734-1f52-42b5-ba89-738582a7f5b4 +12975217-8a58-4a95-9ede-4ceb0a487a67 +97e186f8-28a7-4340-b781-cd13168daf99 +2336ce4b-3d57-46f4-b460-cdeb89c81fcd +e824b114-66e0-441f-aa94-27feb7a3f672 +b8bf5230-0174-4f16-9470-dd476b9675d6 diff --git a/contrib/btree_gist/expected/init.out b/contrib/btree_gist/expected/init.out index afe0534682..ce4559d8b0 100644 --- a/contrib/btree_gist/expected/init.out +++ b/contrib/btree_gist/expected/init.out @@ -1 +1,9 @@ CREATE EXTENSION btree_gist; +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + amname | opcname +--------+--------- +(0 rows) + diff --git a/contrib/btree_gist/expected/uuid.out b/contrib/btree_gist/expected/uuid.out new file mode 100644 index 0000000000..a34b024603 --- /dev/null +++ b/contrib/btree_gist/expected/uuid.out @@ -0,0 +1,66 @@ +-- uuid check +CREATE TABLE uuidtmp (a uuid); +\copy uuidtmp from 'data/uuid.data' +SET enable_seqscan=on; +SELECT count(*) FROM uuidtmp WHERE a < '55e65ca2-4136-4a4b-ba78-cd3fe4678203'; + count +------- + 227 +(1 row) + +SELECT count(*) FROM uuidtmp WHERE a <= '55e65ca2-4136-4a4b-ba78-cd3fe4678203'; + count +------- + 228 +(1 row) + +SELECT count(*) FROM uuidtmp WHERE a = '55e65ca2-4136-4a4b-ba78-cd3fe4678203'; + count +------- + 1 +(1 row) + +SELECT count(*) FROM uuidtmp WHERE a >= '55e65ca2-4136-4a4b-ba78-cd3fe4678203'; + count +------- + 376 +(1 row) + +SELECT count(*) FROM uuidtmp WHERE a > '55e65ca2-4136-4a4b-ba78-cd3fe4678203'; + count +------- + 375 +(1 row) + +CREATE INDEX uuididx ON uuidtmp USING gist ( a ); +SET enable_seqscan=off; +SELECT count(*) FROM uuidtmp WHERE a < '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid; + count +------- + 227 +(1 row) + +SELECT count(*) FROM uuidtmp WHERE a <= '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid; + count +------- + 228 +(1 row) + +SELECT count(*) FROM uuidtmp WHERE a = '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid; + count +------- + 1 +(1 row) + +SELECT count(*) FROM uuidtmp WHERE a >= '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid; + count +------- + 376 +(1 row) + +SELECT count(*) FROM uuidtmp WHERE a > '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid; + count +------- + 375 +(1 row) + diff --git a/contrib/btree_gist/sql/init.sql b/contrib/btree_gist/sql/init.sql index afe0534682..a6d2cffc67 100644 --- a/contrib/btree_gist/sql/init.sql +++ b/contrib/btree_gist/sql/init.sql @@ -1 +1,6 @@ CREATE EXTENSION btree_gist; + +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); diff --git a/contrib/btree_gist/sql/uuid.sql b/contrib/btree_gist/sql/uuid.sql new file mode 100644 index 0000000000..3f7ad764e2 --- /dev/null +++ b/contrib/btree_gist/sql/uuid.sql @@ -0,0 +1,31 @@ +-- uuid check + +CREATE TABLE uuidtmp (a uuid); + +\copy uuidtmp from 'data/uuid.data' + +SET enable_seqscan=on; + +SELECT count(*) FROM uuidtmp WHERE a < '55e65ca2-4136-4a4b-ba78-cd3fe4678203'; + +SELECT count(*) FROM uuidtmp WHERE a <= '55e65ca2-4136-4a4b-ba78-cd3fe4678203'; + +SELECT count(*) FROM uuidtmp WHERE a = '55e65ca2-4136-4a4b-ba78-cd3fe4678203'; + +SELECT count(*) FROM uuidtmp WHERE a >= '55e65ca2-4136-4a4b-ba78-cd3fe4678203'; + +SELECT count(*) FROM uuidtmp WHERE a > '55e65ca2-4136-4a4b-ba78-cd3fe4678203'; + +CREATE INDEX uuididx ON uuidtmp USING gist ( a ); + +SET enable_seqscan=off; + +SELECT count(*) FROM uuidtmp WHERE a < '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid; + +SELECT count(*) FROM uuidtmp WHERE a <= '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid; + +SELECT count(*) FROM uuidtmp WHERE a = '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid; + +SELECT count(*) FROM uuidtmp WHERE a >= '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid; + +SELECT count(*) FROM uuidtmp WHERE a > '55e65ca2-4136-4a4b-ba78-cd3fe4678203'::uuid; diff --git a/contrib/chkpass/chkpass.c b/contrib/chkpass/chkpass.c index 9425c089b5..3803ccff9a 100644 --- a/contrib/chkpass/chkpass.c +++ b/contrib/chkpass/chkpass.c @@ -17,6 +17,7 @@ #endif #include "fmgr.h" +#include "utils/backend_random.h" #include "utils/builtins.h" PG_MODULE_MAGIC; @@ -77,8 +78,12 @@ chkpass_in(PG_FUNCTION_ARGS) result = (chkpass *) palloc0(sizeof(chkpass)); - mysalt[0] = salt_chars[random() & 0x3f]; - mysalt[1] = salt_chars[random() & 0x3f]; + if (!pg_backend_random(mysalt, 2)) + ereport(ERROR, + (errmsg("could not generate random salt"))); + + mysalt[0] = salt_chars[mysalt[0] & 0x3f]; + mysalt[1] = salt_chars[mysalt[1] & 0x3f]; mysalt[2] = 0; /* technically the terminator is not necessary * but I like to play safe */ diff --git a/contrib/citext/Makefile b/contrib/citext/Makefile index e39d3eee61..563cd22dcc 100644 --- a/contrib/citext/Makefile +++ b/contrib/citext/Makefile @@ -3,7 +3,8 @@ MODULES = citext EXTENSION = citext -DATA = citext--1.3.sql citext--1.2--1.3.sql citext--1.1--1.2.sql \ +DATA = citext--1.4.sql citext--1.3--1.4.sql \ + citext--1.2--1.3.sql citext--1.1--1.2.sql \ citext--1.0--1.1.sql citext--unpackaged--1.0.sql PGFILEDESC = "citext - case-insensitive character string data type" diff --git a/contrib/citext/citext--1.3--1.4.sql b/contrib/citext/citext--1.3--1.4.sql new file mode 100644 index 0000000000..7b36651186 --- /dev/null +++ b/contrib/citext/citext--1.3--1.4.sql @@ -0,0 +1,12 @@ +/* contrib/citext/citext--1.3--1.4.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION citext UPDATE TO '1.4'" to load this file. \quit + +CREATE FUNCTION regexp_match( citext, citext ) RETURNS TEXT[] AS $$ + SELECT pg_catalog.regexp_match( $1::pg_catalog.text, $2::pg_catalog.text, 'i' ); +$$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION regexp_match( citext, citext, text ) RETURNS TEXT[] AS $$ + SELECT pg_catalog.regexp_match( $1::pg_catalog.text, $2::pg_catalog.text, CASE WHEN pg_catalog.strpos($3, 'c') = 0 THEN $3 || 'i' ELSE $3 END ); +$$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; diff --git a/contrib/citext/citext--1.3.sql b/contrib/citext/citext--1.4.sql similarity index 96% rename from contrib/citext/citext--1.3.sql rename to contrib/citext/citext--1.4.sql index c2d0c0ce9b..7b06198935 100644 --- a/contrib/citext/citext--1.3.sql +++ b/contrib/citext/citext--1.4.sql @@ -1,4 +1,4 @@ -/* contrib/citext/citext--1.2.sql */ +/* contrib/citext/citext--1.4.sql */ -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION citext" to load this file. \quit @@ -444,6 +444,14 @@ CREATE OPERATOR !~~* ( -- XXX TODO Ideally these would be implemented in C. -- +CREATE FUNCTION regexp_match( citext, citext ) RETURNS TEXT[] AS $$ + SELECT pg_catalog.regexp_match( $1::pg_catalog.text, $2::pg_catalog.text, 'i' ); +$$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION regexp_match( citext, citext, text ) RETURNS TEXT[] AS $$ + SELECT pg_catalog.regexp_match( $1::pg_catalog.text, $2::pg_catalog.text, CASE WHEN pg_catalog.strpos($3, 'c') = 0 THEN $3 || 'i' ELSE $3 END ); +$$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; + CREATE FUNCTION regexp_matches( citext, citext ) RETURNS SETOF TEXT[] AS $$ SELECT pg_catalog.regexp_matches( $1::pg_catalog.text, $2::pg_catalog.text, 'i' ); $$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE ROWS 1; diff --git a/contrib/citext/citext.c b/contrib/citext/citext.c index 1174b70aa7..04f604b15f 100644 --- a/contrib/citext/citext.c +++ b/contrib/citext/citext.c @@ -7,6 +7,7 @@ #include "catalog/pg_collation.h" #include "utils/builtins.h" #include "utils/formatting.h" +#include "utils/varlena.h" #ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; diff --git a/contrib/citext/citext.control b/contrib/citext/citext.control index 5f080df3ee..17fce4e887 100644 --- a/contrib/citext/citext.control +++ b/contrib/citext/citext.control @@ -1,5 +1,5 @@ # citext extension comment = 'data type for case-insensitive character strings' -default_version = '1.3' +default_version = '1.4' module_pathname = '$libdir/citext' relocatable = true diff --git a/contrib/citext/expected/citext.out b/contrib/citext/expected/citext.out index 6541b24b5f..bc5d92eb91 100644 --- a/contrib/citext/expected/citext.out +++ b/contrib/citext/expected/citext.out @@ -2,6 +2,14 @@ -- Test citext datatype -- CREATE EXTENSION citext; +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + amname | opcname +--------+--------- +(0 rows) + -- Test the operators and indexing functions -- Test = and <>. SELECT 'a'::citext = 'a'::citext AS t; @@ -1770,6 +1778,60 @@ SELECT quote_literal( name ) = quote_literal( name::text ) AS t FROM srt; t (4 rows) +SELECT regexp_match('foobarbequebaz'::citext, '(bar)(beque)') = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)') = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext) = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext, '') = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)', '') = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz', '(BAR)(BEQUE)'::citext, '') = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext, ''::citext) = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +-- c forces case-sensitive +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext, 'c'::citext) = ARRAY[ 'bar', 'beque' ] AS "no result"; + no result +----------- + +(1 row) + +-- g is not allowed +SELECT regexp_match('foobarbequebazmorebarbequetoo'::citext, '(BAR)(BEQUE)'::citext, 'g') AS "error"; +ERROR: regexp_match does not support the global option +HINT: Use the regexp_matches function instead. +CONTEXT: SQL function "regexp_match" statement 1 SELECT regexp_matches('foobarbequebaz'::citext, '(bar)(beque)') = ARRAY[ 'bar', 'beque' ] AS t; t --- diff --git a/contrib/citext/expected/citext_1.out b/contrib/citext/expected/citext_1.out index 462d42a3bd..3d02d06b9c 100644 --- a/contrib/citext/expected/citext_1.out +++ b/contrib/citext/expected/citext_1.out @@ -2,6 +2,14 @@ -- Test citext datatype -- CREATE EXTENSION citext; +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + amname | opcname +--------+--------- +(0 rows) + -- Test the operators and indexing functions -- Test = and <>. SELECT 'a'::citext = 'a'::citext AS t; @@ -1770,6 +1778,60 @@ SELECT quote_literal( name ) = quote_literal( name::text ) AS t FROM srt; t (4 rows) +SELECT regexp_match('foobarbequebaz'::citext, '(bar)(beque)') = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)') = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext) = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext, '') = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)', '') = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz', '(BAR)(BEQUE)'::citext, '') = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext, ''::citext) = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +-- c forces case-sensitive +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext, 'c'::citext) = ARRAY[ 'bar', 'beque' ] AS "no result"; + no result +----------- + +(1 row) + +-- g is not allowed +SELECT regexp_match('foobarbequebazmorebarbequetoo'::citext, '(BAR)(BEQUE)'::citext, 'g') AS "error"; +ERROR: regexp_match does not support the global option +HINT: Use the regexp_matches function instead. +CONTEXT: SQL function "regexp_match" statement 1 SELECT regexp_matches('foobarbequebaz'::citext, '(bar)(beque)') = ARRAY[ 'bar', 'beque' ] AS t; t --- diff --git a/contrib/citext/sql/citext.sql b/contrib/citext/sql/citext.sql index 2df1b4aaf0..f70f9ebae9 100644 --- a/contrib/citext/sql/citext.sql +++ b/contrib/citext/sql/citext.sql @@ -4,6 +4,11 @@ CREATE EXTENSION citext; +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + -- Test the operators and indexing functions -- Test = and <>. @@ -592,6 +597,18 @@ SELECT md5( name ) = md5( name::text ) AS t FROM srt; SELECT quote_ident( name ) = quote_ident( name::text ) AS t FROM srt; SELECT quote_literal( name ) = quote_literal( name::text ) AS t FROM srt; +SELECT regexp_match('foobarbequebaz'::citext, '(bar)(beque)') = ARRAY[ 'bar', 'beque' ] AS t; +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)') = ARRAY[ 'bar', 'beque' ] AS t; +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext) = ARRAY[ 'bar', 'beque' ] AS t; +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext, '') = ARRAY[ 'bar', 'beque' ] AS t; +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)', '') = ARRAY[ 'bar', 'beque' ] AS t; +SELECT regexp_match('foobarbequebaz', '(BAR)(BEQUE)'::citext, '') = ARRAY[ 'bar', 'beque' ] AS t; +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext, ''::citext) = ARRAY[ 'bar', 'beque' ] AS t; +-- c forces case-sensitive +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext, 'c'::citext) = ARRAY[ 'bar', 'beque' ] AS "no result"; +-- g is not allowed +SELECT regexp_match('foobarbequebazmorebarbequetoo'::citext, '(BAR)(BEQUE)'::citext, 'g') AS "error"; + SELECT regexp_matches('foobarbequebaz'::citext, '(bar)(beque)') = ARRAY[ 'bar', 'beque' ] AS t; SELECT regexp_matches('foobarbequebaz'::citext, '(BAR)(BEQUE)') = ARRAY[ 'bar', 'beque' ] AS t; SELECT regexp_matches('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext) = ARRAY[ 'bar', 'beque' ] AS t; diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c index 3feddef8f3..2bb2ed029d 100644 --- a/contrib/cube/cube.c +++ b/contrib/cube/cube.c @@ -122,7 +122,7 @@ cube_in(PG_FUNCTION_ARGS) cube_scanner_init(str); if (cube_yyparse(&result) != 0) - cube_yyerror(&result, "bogus input"); + cube_yyerror(&result, "cube parser failed"); cube_scanner_finish(); @@ -254,12 +254,9 @@ cube_subset(PG_FUNCTION_ARGS) for (i = 0; i < dim; i++) { if ((dx[i] <= 0) || (dx[i] > DIM(c))) - { - pfree(result); ereport(ERROR, (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), errmsg("Index out of bounds"))); - } result->x[i] = c->x[dx[i] - 1]; if (!IS_POINT(c)) result->x[i + dim] = c->x[dx[i] + DIM(c) - 1]; @@ -276,27 +273,15 @@ cube_out(PG_FUNCTION_ARGS) StringInfoData buf; int dim = DIM(cube); int i; - int ndig; initStringInfo(&buf); - /* - * Get the number of digits to display. - */ - ndig = DBL_DIG + extra_float_digits; - if (ndig < 1) - ndig = 1; - - /* - * while printing the first (LL) corner, check if it is equal to the - * second one - */ appendStringInfoChar(&buf, '('); for (i = 0; i < dim; i++) { if (i > 0) appendStringInfoString(&buf, ", "); - appendStringInfo(&buf, "%.*g", ndig, LL_COORD(cube, i)); + appendStringInfoString(&buf, float8out_internal(LL_COORD(cube, i))); } appendStringInfoChar(&buf, ')'); @@ -307,7 +292,7 @@ cube_out(PG_FUNCTION_ARGS) { if (i > 0) appendStringInfoString(&buf, ", "); - appendStringInfo(&buf, "%.*g", ndig, UR_COORD(cube, i)); + appendStringInfoString(&buf, float8out_internal(UR_COORD(cube, i))); } appendStringInfoChar(&buf, ')'); } @@ -370,9 +355,6 @@ g_cube_union(PG_FUNCTION_ARGS) NDBOX *tmp; int i; - /* - * fprintf(stderr, "union\n"); - */ tmp = DatumGetNDBOX(entryvec->vector[0].key); /* @@ -441,9 +423,6 @@ g_cube_penalty(PG_FUNCTION_ARGS) rt_cube_size(DatumGetNDBOX(origentry->key), &tmp2); *result = (float) (tmp1 - tmp2); - /* - * fprintf(stderr, "penalty\n"); fprintf(stderr, "\t%g\n", *result); - */ PG_RETURN_FLOAT8(*result); } @@ -484,9 +463,6 @@ g_cube_picksplit(PG_FUNCTION_ARGS) *right; OffsetNumber maxoff; - /* - * fprintf(stderr, "picksplit\n"); - */ maxoff = entryvec->n - 2; nbytes = (maxoff + 2) * sizeof(OffsetNumber); v->spl_left = (OffsetNumber *) palloc(nbytes); @@ -617,9 +593,6 @@ g_cube_same(PG_FUNCTION_ARGS) else *result = FALSE; - /* - * fprintf(stderr, "same: %s\n", (*result ? "TRUE" : "FALSE" )); - */ PG_RETURN_NDBOX(result); } @@ -633,9 +606,6 @@ g_cube_leaf_consistent(NDBOX *key, { bool retval; - /* - * fprintf(stderr, "leaf_consistent, %d\n", strategy); - */ switch (strategy) { case RTOverlapStrategyNumber: @@ -665,9 +635,6 @@ g_cube_internal_consistent(NDBOX *key, { bool retval; - /* - * fprintf(stderr, "internal_consistent, %d\n", strategy); - */ switch (strategy) { case RTOverlapStrategyNumber: @@ -865,12 +832,8 @@ cube_size(PG_FUNCTION_ARGS) { NDBOX *a = PG_GETARG_NDBOX(0); double result; - int i; - - result = 1.0; - for (i = 0; i < DIM(a); i++) - result = result * Abs((LL_COORD(a, i) - UR_COORD(a, i))); + rt_cube_size(a, &result); PG_FREE_IF_COPY(a, 0); PG_RETURN_FLOAT8(result); } @@ -878,17 +841,26 @@ cube_size(PG_FUNCTION_ARGS) void rt_cube_size(NDBOX *a, double *size) { + double result; int i; if (a == (NDBOX *) NULL) - *size = 0.0; + { + /* special case for GiST */ + result = 0.0; + } + else if (IS_POINT(a) || DIM(a) == 0) + { + /* necessarily has zero size */ + result = 0.0; + } else { - *size = 1.0; + result = 1.0; for (i = 0; i < DIM(a); i++) - *size = (*size) * Abs(UR_COORD(a, i) - LL_COORD(a, i)); + result *= Abs(UR_COORD(a, i) - LL_COORD(a, i)); } - return; + *size = result; } /* make up a metric in which one box will be 'lower' than the other @@ -1155,10 +1127,6 @@ cube_overlap_v0(NDBOX *a, NDBOX *b) { int i; - /* - * This *very bad* error was found in the source: if ( (a==NULL) || - * (b=NULL) ) return(FALSE); - */ if ((a == NULL) || (b == NULL)) return (FALSE); @@ -1370,7 +1338,9 @@ g_cube_distance(PG_FUNCTION_ARGS) { int coord = PG_GETARG_INT32(1); - if (IS_POINT(cube)) + if (DIM(cube) == 0) + retval = 0.0; + else if (IS_POINT(cube)) retval = cube->x[(coord - 1) % DIM(cube)]; else retval = Min(cube->x[(coord - 1) % DIM(cube)], diff --git a/contrib/cube/cubedata.h b/contrib/cube/cubedata.h index 7eaac39640..af02464178 100644 --- a/contrib/cube/cubedata.h +++ b/contrib/cube/cubedata.h @@ -1,5 +1,9 @@ /* contrib/cube/cubedata.h */ +/* + * This limit is pretty arbitrary, but don't make it so large that you + * risk overflow in sizing calculations. + */ #define CUBE_MAX_DIM (100) typedef struct NDBOX @@ -29,6 +33,7 @@ typedef struct NDBOX double x[FLEXIBLE_ARRAY_MEMBER]; } NDBOX; +/* NDBOX access macros */ #define POINT_BIT 0x80000000 #define DIM_MASK 0x7fffffff @@ -43,10 +48,12 @@ typedef struct NDBOX #define POINT_SIZE(_dim) (offsetof(NDBOX, x) + sizeof(double)*(_dim)) #define CUBE_SIZE(_dim) (offsetof(NDBOX, x) + sizeof(double)*(_dim)*2) +/* fmgr interface macros */ #define DatumGetNDBOX(x) ((NDBOX *) PG_DETOAST_DATUM(x)) #define PG_GETARG_NDBOX(x) DatumGetNDBOX(PG_GETARG_DATUM(x)) #define PG_RETURN_NDBOX(x) PG_RETURN_POINTER(x) +/* GiST operator strategy numbers */ #define CubeKNNDistanceCoord 15 /* ~> */ #define CubeKNNDistanceTaxicab 16 /* <#> */ #define CubeKNNDistanceEuclid 17 /* <-> */ diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y index 33606c741c..1b65fa967c 100644 --- a/contrib/cube/cubeparse.y +++ b/contrib/cube/cubeparse.y @@ -4,12 +4,13 @@ /* NdBox = [(lowerleft),(upperright)] */ /* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */ -#define YYSTYPE char * -#define YYDEBUG 1 - #include "postgres.h" #include "cubedata.h" +#include "utils/builtins.h" + +/* All grammar constructs return strings */ +#define YYSTYPE char * /* * Bison doesn't allocate anything that needs to live across parser calls, @@ -25,9 +26,9 @@ static char *scanbuf; static int scanbuflen; -static int delim_count(char *s, char delim); -static NDBOX * write_box(unsigned int dim, char *str1, char *str2); -static NDBOX * write_point_as_box(char *s, int dim); +static int item_count(const char *s, char delim); +static NDBOX *write_box(int dim, char *str1, char *str2); +static NDBOX *write_point_as_box(int dim, char *str); %} @@ -46,47 +47,48 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET { int dim; - dim = delim_count($2, ',') + 1; - if ((delim_count($4, ',') + 1) != dim) + dim = item_count($2, ','); + if (item_count($4, ',') != dim) { ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("bad cube representation"), + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), errdetail("Different point dimensions in (%s) and (%s).", $2, $4))); YYABORT; } - if (dim > CUBE_MAX_DIM) { + if (dim > CUBE_MAX_DIM) + { ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("bad cube representation"), + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), errdetail("A cube cannot have more than %d dimensions.", CUBE_MAX_DIM))); YYABORT; } *result = write_box( dim, $2, $4 ); - } | paren_list COMMA paren_list { int dim; - dim = delim_count($1, ',') + 1; - - if ( (delim_count($3, ',') + 1) != dim ) { + dim = item_count($1, ','); + if (item_count($3, ',') != dim) + { ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("bad cube representation"), + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), errdetail("Different point dimensions in (%s) and (%s).", $1, $3))); YYABORT; } - if (dim > CUBE_MAX_DIM) { + if (dim > CUBE_MAX_DIM) + { ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("bad cube representation"), + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), errdetail("A cube cannot have more than %d dimensions.", CUBE_MAX_DIM))); YYABORT; @@ -99,33 +101,36 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET { int dim; - dim = delim_count($1, ',') + 1; - if (dim > CUBE_MAX_DIM) { + dim = item_count($1, ','); + if (dim > CUBE_MAX_DIM) + { ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("bad cube representation"), + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), errdetail("A cube cannot have more than %d dimensions.", CUBE_MAX_DIM))); YYABORT; } - *result = write_point_as_box($1, dim); + *result = write_point_as_box(dim, $1); } | list { int dim; - dim = delim_count($1, ',') + 1; - if (dim > CUBE_MAX_DIM) { + dim = item_count($1, ','); + if (dim > CUBE_MAX_DIM) + { ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("bad cube representation"), + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), errdetail("A cube cannot have more than %d dimensions.", CUBE_MAX_DIM))); YYABORT; } - *result = write_point_as_box($1, dim); + + *result = write_point_as_box(dim, $1); } ; @@ -133,6 +138,10 @@ paren_list: O_PAREN list C_PAREN { $$ = $2; } + | O_PAREN C_PAREN + { + $$ = pstrdup(""); + } ; list: CUBEFLOAT @@ -151,24 +160,30 @@ list: CUBEFLOAT %% +/* This assumes the string has been normalized by productions above */ static int -delim_count(char *s, char delim) +item_count(const char *s, char delim) { - int ndelim = 0; + int nitems = 0; - while ((s = strchr(s, delim)) != NULL) + if (s[0] != '\0') { - ndelim++; - s++; + nitems++; + while ((s = strchr(s, delim)) != NULL) + { + nitems++; + s++; + } } - return (ndelim); + return nitems; } static NDBOX * -write_box(unsigned int dim, char *str1, char *str2) +write_box(int dim, char *str1, char *str2) { NDBOX *bp; char *s; + char *endptr; int i; int size = CUBE_SIZE(dim); bool point = true; @@ -178,50 +193,58 @@ write_box(unsigned int dim, char *str1, char *str2) SET_DIM(bp, dim); s = str1; - bp->x[i=0] = strtod(s, NULL); + i = 0; + if (dim > 0) + bp->x[i++] = float8in_internal(s, &endptr, "cube", str1); while ((s = strchr(s, ',')) != NULL) { - s++; i++; - bp->x[i] = strtod(s, NULL); + s++; + bp->x[i++] = float8in_internal(s, &endptr, "cube", str1); } + Assert(i == dim); s = str2; - bp->x[i=dim] = strtod(s, NULL); - if (bp->x[dim] != bp->x[0]) - point = false; + if (dim > 0) + { + bp->x[i] = float8in_internal(s, &endptr, "cube", str2); + /* code this way to do right thing with NaN */ + point &= (bp->x[i] == bp->x[0]); + i++; + } while ((s = strchr(s, ',')) != NULL) { - s++; i++; - bp->x[i] = strtod(s, NULL); - if (bp->x[i] != bp->x[i-dim]) - point = false; + s++; + bp->x[i] = float8in_internal(s, &endptr, "cube", str2); + point &= (bp->x[i] == bp->x[i - dim]); + i++; } + Assert(i == dim * 2); if (point) { /* * The value turned out to be a point, ie. all the upper-right * coordinates were equal to the lower-left coordinates. Resize the - * the cube we constructed. Note: we don't bother to repalloc() it - * smaller, it's unlikely that the tiny amount of memory free'd that - * way would be useful. + * cube we constructed. Note: we don't bother to repalloc() it + * smaller, as it's unlikely that the tiny amount of memory freed + * that way would be useful, and the output is always short-lived. */ size = POINT_SIZE(dim); SET_VARSIZE(bp, size); SET_POINT_BIT(bp); } - return(bp); + return bp; } static NDBOX * -write_point_as_box(char *str, int dim) +write_point_as_box(int dim, char *str) { NDBOX *bp; int i, size; - double x; - char *s = str; + char *s; + char *endptr; size = POINT_SIZE(dim); bp = palloc0(size); @@ -229,17 +252,18 @@ write_point_as_box(char *str, int dim) SET_DIM(bp, dim); SET_POINT_BIT(bp); + s = str; i = 0; - x = strtod(s, NULL); - bp->x[0] = x; + if (dim > 0) + bp->x[i++] = float8in_internal(s, &endptr, "cube", str); while ((s = strchr(s, ',')) != NULL) { - s++; i++; - x = strtod(s, NULL); - bp->x[i] = x; + s++; + bp->x[i++] = float8in_internal(s, &endptr, "cube", str); } + Assert(i == dim); - return(bp); + return bp; } #include "cubescan.c" diff --git a/contrib/cube/cubescan.l b/contrib/cube/cubescan.l index 4408e28387..dada917820 100644 --- a/contrib/cube/cubescan.l +++ b/contrib/cube/cubescan.l @@ -38,36 +38,41 @@ n [0-9]+ integer [+-]?{n} real [+-]?({n}\.{n}?|\.{n}) float ({integer}|{real})([eE]{integer})? +infinity [+-]?[iI][nN][fF]([iI][nN][iI][tT][yY])? +NaN [nN][aA][nN] %% {float} yylval = yytext; return CUBEFLOAT; +{infinity} yylval = yytext; return CUBEFLOAT; +{NaN} yylval = yytext; return CUBEFLOAT; \[ yylval = "("; return O_BRACKET; \] yylval = ")"; return C_BRACKET; \( yylval = "("; return O_PAREN; \) yylval = ")"; return C_PAREN; -\, yylval = ")"; return COMMA; +\, yylval = ","; return COMMA; [ \t\n\r\f]+ /* discard spaces */ . return yytext[0]; /* alert parser of the garbage */ %% +/* result is not used, but Bison expects this signature */ void yyerror(NDBOX **result, const char *message) { if (*yytext == YY_END_OF_BUFFER_CHAR) { ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("bad cube representation"), + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), /* translator: %s is typically "syntax error" */ errdetail("%s at end of input", message))); } else { ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("bad cube representation"), + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), /* translator: first %s is typically "syntax error" */ errdetail("%s at or near \"%s\"", message, yytext))); } diff --git a/contrib/cube/expected/cube.out b/contrib/cube/expected/cube.out index e9e2c0f15b..ada54b2885 100644 --- a/contrib/cube/expected/cube.out +++ b/contrib/cube/expected/cube.out @@ -2,6 +2,14 @@ -- Test cube datatype -- CREATE EXTENSION cube; +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + amname | opcname +--------+--------- +(0 rows) + -- -- testing the input and output functions -- @@ -126,16 +134,34 @@ SELECT '-1.0e-7'::cube AS cube; (-1e-07) (1 row) -SELECT '1e-700'::cube AS cube; - cube ------- - (0) +SELECT '1e-300'::cube AS cube; + cube +---------- + (1e-300) (1 row) -SELECT '-1e-700'::cube AS cube; - cube ------- - (0) +SELECT '-1e-300'::cube AS cube; + cube +----------- + (-1e-300) +(1 row) + +SELECT 'infinity'::cube AS cube; + cube +------------ + (Infinity) +(1 row) + +SELECT '-infinity'::cube AS cube; + cube +------------- + (-Infinity) +(1 row) + +SELECT 'NaN'::cube AS cube; + cube +------- + (NaN) (1 row) SELECT '1234567890123456'::cube AS cube; @@ -175,6 +201,12 @@ SELECT '-.1234567890123456'::cube AS cube; (1 row) -- simple lists (points) +SELECT '()'::cube AS cube; + cube +------ + () +(1 row) + SELECT '1,2'::cube AS cube; cube -------- @@ -200,6 +232,12 @@ SELECT '(1,2,3,4,5)'::cube AS cube; (1 row) -- double lists (cubes) +SELECT '(),()'::cube AS cube; + cube +------ + () +(1 row) + SELECT '(0),(0)'::cube AS cube; cube ------ @@ -250,146 +288,145 @@ SELECT '[(0,0,0,0),(1,0,0,0)]'::cube AS cube; -- invalid input: parse errors SELECT ''::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT ''::cube AS cube; ^ DETAIL: syntax error at end of input SELECT 'ABC'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT 'ABC'::cube AS cube; ^ DETAIL: syntax error at or near "A" -SELECT '()'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '()'::cube AS cube; - ^ -DETAIL: syntax error at or near ")" SELECT '[]'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '[]'::cube AS cube; ^ DETAIL: syntax error at or near "]" SELECT '[()]'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '[()]'::cube AS cube; ^ -DETAIL: syntax error at or near ")" +DETAIL: syntax error at or near "]" SELECT '[(1)]'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '[(1)]'::cube AS cube; ^ DETAIL: syntax error at or near "]" SELECT '[(1),]'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '[(1),]'::cube AS cube; ^ DETAIL: syntax error at or near "]" SELECT '[(1),2]'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '[(1),2]'::cube AS cube; ^ DETAIL: syntax error at or near "2" SELECT '[(1),(2),(3)]'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '[(1),(2),(3)]'::cube AS cube; ^ DETAIL: syntax error at or near "," SELECT '1,'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '1,'::cube AS cube; ^ DETAIL: syntax error at end of input SELECT '1,2,'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '1,2,'::cube AS cube; ^ DETAIL: syntax error at end of input SELECT '1,,2'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '1,,2'::cube AS cube; ^ DETAIL: syntax error at or near "," SELECT '(1,)'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '(1,)'::cube AS cube; ^ DETAIL: syntax error at or near ")" SELECT '(1,2,)'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '(1,2,)'::cube AS cube; ^ DETAIL: syntax error at or near ")" SELECT '(1,,2)'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '(1,,2)'::cube AS cube; ^ DETAIL: syntax error at or near "," -- invalid input: semantic errors and trailing garbage SELECT '[(1),(2)],'::cube AS cube; -- 0 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '[(1),(2)],'::cube AS cube; ^ DETAIL: syntax error at or near "," SELECT '[(1,2,3),(2,3)]'::cube AS cube; -- 1 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '[(1,2,3),(2,3)]'::cube AS cube; ^ DETAIL: Different point dimensions in (1,2,3) and (2,3). SELECT '[(1,2),(1,2,3)]'::cube AS cube; -- 1 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '[(1,2),(1,2,3)]'::cube AS cube; ^ DETAIL: Different point dimensions in (1,2) and (1,2,3). SELECT '(1),(2),'::cube AS cube; -- 2 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '(1),(2),'::cube AS cube; ^ DETAIL: syntax error at or near "," SELECT '(1,2,3),(2,3)'::cube AS cube; -- 3 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '(1,2,3),(2,3)'::cube AS cube; ^ DETAIL: Different point dimensions in (1,2,3) and (2,3). SELECT '(1,2),(1,2,3)'::cube AS cube; -- 3 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '(1,2),(1,2,3)'::cube AS cube; ^ DETAIL: Different point dimensions in (1,2) and (1,2,3). SELECT '(1,2,3)ab'::cube AS cube; -- 4 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '(1,2,3)ab'::cube AS cube; ^ DETAIL: syntax error at or near "a" SELECT '(1,2,3)a'::cube AS cube; -- 5 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '(1,2,3)a'::cube AS cube; ^ DETAIL: syntax error at or near "a" SELECT '(1,2)('::cube AS cube; -- 5 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '(1,2)('::cube AS cube; ^ DETAIL: syntax error at or near "(" SELECT '1,2ab'::cube AS cube; -- 6 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '1,2ab'::cube AS cube; ^ DETAIL: syntax error at or near "a" SELECT '1 e7'::cube AS cube; -- 6 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '1 e7'::cube AS cube; ^ DETAIL: syntax error at or near "e" SELECT '1,2a'::cube AS cube; -- 7 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '1,2a'::cube AS cube; ^ DETAIL: syntax error at or near "a" SELECT '1..2'::cube AS cube; -- 7 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '1..2'::cube AS cube; ^ DETAIL: syntax error at or near ".2" +SELECT '-1e-700'::cube AS cube; -- out of range +ERROR: "-1e-700" is out of range for type double precision +LINE 1: SELECT '-1e-700'::cube AS cube; + ^ -- -- Testing building cubes from float8 values -- @@ -556,12 +593,12 @@ SELECT cube(cube(1,2), 42, 24); -- cube_c_f8_f8 -- Testing limit of CUBE_MAX_DIM dimensions check in cube_in. -- select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)'::cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0... ^ DETAIL: A cube cannot have more than 100 dimensions. select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)'::cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0... ^ DETAIL: A cube cannot have more than 100 dimensions. diff --git a/contrib/cube/expected/cube_1.out b/contrib/cube/expected/cube_1.out deleted file mode 100644 index c40fabcd46..0000000000 --- a/contrib/cube/expected/cube_1.out +++ /dev/null @@ -1,1710 +0,0 @@ --- --- Test cube datatype --- -CREATE EXTENSION cube; --- --- testing the input and output functions --- --- Any number (a one-dimensional point) -SELECT '1'::cube AS cube; - cube ------- - (1) -(1 row) - -SELECT '-1'::cube AS cube; - cube ------- - (-1) -(1 row) - -SELECT '1.'::cube AS cube; - cube ------- - (1) -(1 row) - -SELECT '-1.'::cube AS cube; - cube ------- - (-1) -(1 row) - -SELECT '.1'::cube AS cube; - cube -------- - (0.1) -(1 row) - -SELECT '-.1'::cube AS cube; - cube --------- - (-0.1) -(1 row) - -SELECT '1.0'::cube AS cube; - cube ------- - (1) -(1 row) - -SELECT '-1.0'::cube AS cube; - cube ------- - (-1) -(1 row) - -SELECT '1e27'::cube AS cube; - cube ---------- - (1e+27) -(1 row) - -SELECT '-1e27'::cube AS cube; - cube ----------- - (-1e+27) -(1 row) - -SELECT '1.0e27'::cube AS cube; - cube ---------- - (1e+27) -(1 row) - -SELECT '-1.0e27'::cube AS cube; - cube ----------- - (-1e+27) -(1 row) - -SELECT '1e+27'::cube AS cube; - cube ---------- - (1e+27) -(1 row) - -SELECT '-1e+27'::cube AS cube; - cube ----------- - (-1e+27) -(1 row) - -SELECT '1.0e+27'::cube AS cube; - cube ---------- - (1e+27) -(1 row) - -SELECT '-1.0e+27'::cube AS cube; - cube ----------- - (-1e+27) -(1 row) - -SELECT '1e-7'::cube AS cube; - cube ---------- - (1e-07) -(1 row) - -SELECT '-1e-7'::cube AS cube; - cube ----------- - (-1e-07) -(1 row) - -SELECT '1.0e-7'::cube AS cube; - cube ---------- - (1e-07) -(1 row) - -SELECT '-1.0e-7'::cube AS cube; - cube ----------- - (-1e-07) -(1 row) - -SELECT '1e-700'::cube AS cube; - cube ------- - (0) -(1 row) - -SELECT '-1e-700'::cube AS cube; - cube ------- - (-0) -(1 row) - -SELECT '1234567890123456'::cube AS cube; - cube ------------------------- - (1.23456789012346e+15) -(1 row) - -SELECT '+1234567890123456'::cube AS cube; - cube ------------------------- - (1.23456789012346e+15) -(1 row) - -SELECT '-1234567890123456'::cube AS cube; - cube -------------------------- - (-1.23456789012346e+15) -(1 row) - -SELECT '.1234567890123456'::cube AS cube; - cube ---------------------- - (0.123456789012346) -(1 row) - -SELECT '+.1234567890123456'::cube AS cube; - cube ---------------------- - (0.123456789012346) -(1 row) - -SELECT '-.1234567890123456'::cube AS cube; - cube ----------------------- - (-0.123456789012346) -(1 row) - --- simple lists (points) -SELECT '1,2'::cube AS cube; - cube --------- - (1, 2) -(1 row) - -SELECT '(1,2)'::cube AS cube; - cube --------- - (1, 2) -(1 row) - -SELECT '1,2,3,4,5'::cube AS cube; - cube ------------------ - (1, 2, 3, 4, 5) -(1 row) - -SELECT '(1,2,3,4,5)'::cube AS cube; - cube ------------------ - (1, 2, 3, 4, 5) -(1 row) - --- double lists (cubes) -SELECT '(0),(0)'::cube AS cube; - cube ------- - (0) -(1 row) - -SELECT '(0),(1)'::cube AS cube; - cube ---------- - (0),(1) -(1 row) - -SELECT '[(0),(0)]'::cube AS cube; - cube ------- - (0) -(1 row) - -SELECT '[(0),(1)]'::cube AS cube; - cube ---------- - (0),(1) -(1 row) - -SELECT '(0,0,0,0),(0,0,0,0)'::cube AS cube; - cube --------------- - (0, 0, 0, 0) -(1 row) - -SELECT '(0,0,0,0),(1,0,0,0)'::cube AS cube; - cube ---------------------------- - (0, 0, 0, 0),(1, 0, 0, 0) -(1 row) - -SELECT '[(0,0,0,0),(0,0,0,0)]'::cube AS cube; - cube --------------- - (0, 0, 0, 0) -(1 row) - -SELECT '[(0,0,0,0),(1,0,0,0)]'::cube AS cube; - cube ---------------------------- - (0, 0, 0, 0),(1, 0, 0, 0) -(1 row) - --- invalid input: parse errors -SELECT ''::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT ''::cube AS cube; - ^ -DETAIL: syntax error at end of input -SELECT 'ABC'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT 'ABC'::cube AS cube; - ^ -DETAIL: syntax error at or near "A" -SELECT '()'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '()'::cube AS cube; - ^ -DETAIL: syntax error at or near ")" -SELECT '[]'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '[]'::cube AS cube; - ^ -DETAIL: syntax error at or near "]" -SELECT '[()]'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '[()]'::cube AS cube; - ^ -DETAIL: syntax error at or near ")" -SELECT '[(1)]'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '[(1)]'::cube AS cube; - ^ -DETAIL: syntax error at or near "]" -SELECT '[(1),]'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '[(1),]'::cube AS cube; - ^ -DETAIL: syntax error at or near "]" -SELECT '[(1),2]'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '[(1),2]'::cube AS cube; - ^ -DETAIL: syntax error at or near "2" -SELECT '[(1),(2),(3)]'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '[(1),(2),(3)]'::cube AS cube; - ^ -DETAIL: syntax error at or near "," -SELECT '1,'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '1,'::cube AS cube; - ^ -DETAIL: syntax error at end of input -SELECT '1,2,'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '1,2,'::cube AS cube; - ^ -DETAIL: syntax error at end of input -SELECT '1,,2'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '1,,2'::cube AS cube; - ^ -DETAIL: syntax error at or near "," -SELECT '(1,)'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '(1,)'::cube AS cube; - ^ -DETAIL: syntax error at or near ")" -SELECT '(1,2,)'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '(1,2,)'::cube AS cube; - ^ -DETAIL: syntax error at or near ")" -SELECT '(1,,2)'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '(1,,2)'::cube AS cube; - ^ -DETAIL: syntax error at or near "," --- invalid input: semantic errors and trailing garbage -SELECT '[(1),(2)],'::cube AS cube; -- 0 -ERROR: bad cube representation -LINE 1: SELECT '[(1),(2)],'::cube AS cube; - ^ -DETAIL: syntax error at or near "," -SELECT '[(1,2,3),(2,3)]'::cube AS cube; -- 1 -ERROR: bad cube representation -LINE 1: SELECT '[(1,2,3),(2,3)]'::cube AS cube; - ^ -DETAIL: Different point dimensions in (1,2,3) and (2,3). -SELECT '[(1,2),(1,2,3)]'::cube AS cube; -- 1 -ERROR: bad cube representation -LINE 1: SELECT '[(1,2),(1,2,3)]'::cube AS cube; - ^ -DETAIL: Different point dimensions in (1,2) and (1,2,3). -SELECT '(1),(2),'::cube AS cube; -- 2 -ERROR: bad cube representation -LINE 1: SELECT '(1),(2),'::cube AS cube; - ^ -DETAIL: syntax error at or near "," -SELECT '(1,2,3),(2,3)'::cube AS cube; -- 3 -ERROR: bad cube representation -LINE 1: SELECT '(1,2,3),(2,3)'::cube AS cube; - ^ -DETAIL: Different point dimensions in (1,2,3) and (2,3). -SELECT '(1,2),(1,2,3)'::cube AS cube; -- 3 -ERROR: bad cube representation -LINE 1: SELECT '(1,2),(1,2,3)'::cube AS cube; - ^ -DETAIL: Different point dimensions in (1,2) and (1,2,3). -SELECT '(1,2,3)ab'::cube AS cube; -- 4 -ERROR: bad cube representation -LINE 1: SELECT '(1,2,3)ab'::cube AS cube; - ^ -DETAIL: syntax error at or near "a" -SELECT '(1,2,3)a'::cube AS cube; -- 5 -ERROR: bad cube representation -LINE 1: SELECT '(1,2,3)a'::cube AS cube; - ^ -DETAIL: syntax error at or near "a" -SELECT '(1,2)('::cube AS cube; -- 5 -ERROR: bad cube representation -LINE 1: SELECT '(1,2)('::cube AS cube; - ^ -DETAIL: syntax error at or near "(" -SELECT '1,2ab'::cube AS cube; -- 6 -ERROR: bad cube representation -LINE 1: SELECT '1,2ab'::cube AS cube; - ^ -DETAIL: syntax error at or near "a" -SELECT '1 e7'::cube AS cube; -- 6 -ERROR: bad cube representation -LINE 1: SELECT '1 e7'::cube AS cube; - ^ -DETAIL: syntax error at or near "e" -SELECT '1,2a'::cube AS cube; -- 7 -ERROR: bad cube representation -LINE 1: SELECT '1,2a'::cube AS cube; - ^ -DETAIL: syntax error at or near "a" -SELECT '1..2'::cube AS cube; -- 7 -ERROR: bad cube representation -LINE 1: SELECT '1..2'::cube AS cube; - ^ -DETAIL: syntax error at or near ".2" --- --- Testing building cubes from float8 values --- -SELECT cube(0::float8); - cube ------- - (0) -(1 row) - -SELECT cube(1::float8); - cube ------- - (1) -(1 row) - -SELECT cube(1,2); - cube ---------- - (1),(2) -(1 row) - -SELECT cube(cube(1,2),3); - cube ---------------- - (1, 3),(2, 3) -(1 row) - -SELECT cube(cube(1,2),3,4); - cube ---------------- - (1, 3),(2, 4) -(1 row) - -SELECT cube(cube(cube(1,2),3,4),5); - cube ---------------------- - (1, 3, 5),(2, 4, 5) -(1 row) - -SELECT cube(cube(cube(1,2),3,4),5,6); - cube ---------------------- - (1, 3, 5),(2, 4, 6) -(1 row) - --- --- Test that the text -> cube cast was installed. --- -SELECT '(0)'::text::cube; - cube ------- - (0) -(1 row) - --- --- Test the float[] -> cube cast --- -SELECT cube('{0,1,2}'::float[], '{3,4,5}'::float[]); - cube ---------------------- - (0, 1, 2),(3, 4, 5) -(1 row) - -SELECT cube('{0,1,2}'::float[], '{3}'::float[]); -ERROR: UR and LL arrays must be of same length -SELECT cube(NULL::float[], '{3}'::float[]); - cube ------- - -(1 row) - -SELECT cube('{0,1,2}'::float[]); - cube ------------ - (0, 1, 2) -(1 row) - -SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[3,2,1,1]); - cube_subset ---------------------------- - (5, 3, 1, 1),(8, 7, 6, 6) -(1 row) - -SELECT cube_subset(cube('(1,3,5),(1,3,5)'), ARRAY[3,2,1,1]); - cube_subset --------------- - (5, 3, 1, 1) -(1 row) - -SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[4,0]); -ERROR: Index out of bounds -SELECT cube_subset(cube('(6,7,8),(6,7,8)'), ARRAY[4,0]); -ERROR: Index out of bounds --- --- Test point processing --- -SELECT cube('(1,2),(1,2)'); -- cube_in - cube --------- - (1, 2) -(1 row) - -SELECT cube('{0,1,2}'::float[], '{0,1,2}'::float[]); -- cube_a_f8_f8 - cube ------------ - (0, 1, 2) -(1 row) - -SELECT cube('{5,6,7,8}'::float[]); -- cube_a_f8 - cube --------------- - (5, 6, 7, 8) -(1 row) - -SELECT cube(1.37); -- cube_f8 - cube --------- - (1.37) -(1 row) - -SELECT cube(1.37, 1.37); -- cube_f8_f8 - cube --------- - (1.37) -(1 row) - -SELECT cube(cube(1,1), 42); -- cube_c_f8 - cube ---------- - (1, 42) -(1 row) - -SELECT cube(cube(1,2), 42); -- cube_c_f8 - cube ------------------ - (1, 42),(2, 42) -(1 row) - -SELECT cube(cube(1,1), 42, 42); -- cube_c_f8_f8 - cube ---------- - (1, 42) -(1 row) - -SELECT cube(cube(1,1), 42, 24); -- cube_c_f8_f8 - cube ------------------ - (1, 42),(1, 24) -(1 row) - -SELECT cube(cube(1,2), 42, 42); -- cube_c_f8_f8 - cube ------------------ - (1, 42),(2, 42) -(1 row) - -SELECT cube(cube(1,2), 42, 24); -- cube_c_f8_f8 - cube ------------------ - (1, 42),(2, 24) -(1 row) - --- --- Testing limit of CUBE_MAX_DIM dimensions check in cube_in. --- -select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)'::cube; -ERROR: bad cube representation -LINE 1: select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0... - ^ -DETAIL: A cube cannot have more than 100 dimensions. -select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)'::cube; -ERROR: bad cube representation -LINE 1: select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0... - ^ -DETAIL: A cube cannot have more than 100 dimensions. --- --- testing the operators --- --- equality/inequality: --- -SELECT '24, 33.20'::cube = '24, 33.20'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '24, 33.20'::cube != '24, 33.20'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '24, 33.20'::cube = '24, 33.21'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '24, 33.20'::cube != '24, 33.21'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(2,0),(3,1)'::cube = '(2,0,0,0,0),(3,1,0,0,0)'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '(2,0),(3,1)'::cube = '(2,0,0,0,0),(3,1,0,0,1)'::cube AS bool; - bool ------- - f -(1 row) - --- "lower than" / "greater than" --- (these operators are not useful for anything but ordering) --- -SELECT '1'::cube > '2'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '1'::cube < '2'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '1,1'::cube > '1,2'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '1,1'::cube < '1,2'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(2,0),(3,1)'::cube > '(2,0,0,0,0),(3,1,0,0,1)'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '(2,0),(3,1)'::cube < '(2,0,0,0,0),(3,1,0,0,1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(2,0),(3,1)'::cube > '(2,0,0,0,1),(3,1,0,0,0)'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '(2,0),(3,1)'::cube < '(2,0,0,0,1),(3,1,0,0,0)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(2,0),(3,1)'::cube > '(2,0,0,0,0),(3,1,0,0,0)'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '(2,0),(3,1)'::cube < '(2,0,0,0,0),(3,1,0,0,0)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(2,0,0,0,0),(3,1,0,0,1)'::cube > '(2,0),(3,1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(2,0,0,0,0),(3,1,0,0,1)'::cube < '(2,0),(3,1)'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '(2,0,0,0,1),(3,1,0,0,0)'::cube > '(2,0),(3,1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(2,0,0,0,1),(3,1,0,0,0)'::cube < '(2,0),(3,1)'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '(2,0,0,0,0),(3,1,0,0,0)'::cube > '(2,0),(3,1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(2,0,0,0,0),(3,1,0,0,0)'::cube < '(2,0),(3,1)'::cube AS bool; - bool ------- - f -(1 row) - --- "overlap" --- -SELECT '1'::cube && '1'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '1'::cube && '2'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '0'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '1'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '1,1,1'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '[(1,1,1),(2,2,2)]'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '[(1,1),(2,2)]'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '[(2,1,1),(2,2,2)]'::cube AS bool; - bool ------- - f -(1 row) - --- "contained in" (the left operand is the cube entirely enclosed by --- the right operand): --- -SELECT '0'::cube <@ '0'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '0,0,0'::cube <@ '0,0,0'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '0,0'::cube <@ '0,0,1'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '0,0,0'::cube <@ '0,0,1'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '1,0,0'::cube <@ '0,0,1'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '(1,0,0),(0,0,1)'::cube <@ '(1,0,0),(0,0,1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(1,0,0),(0,0,1)'::cube <@ '(-1,-1,-1),(1,1,1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(1,0,0),(0,0,1)'::cube <@ '(-1,-1,-1,-1),(1,1,1,1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '0'::cube <@ '(-1),(1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '1'::cube <@ '(-1),(1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '-1'::cube <@ '(-1),(1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(-1),(1)'::cube <@ '(-1),(1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(-1),(1)'::cube <@ '(-1,-1),(1,1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(-2),(1)'::cube <@ '(-1),(1)'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '(-2),(1)'::cube <@ '(-1,-1),(1,1)'::cube AS bool; - bool ------- - f -(1 row) - --- "contains" (the left operand is the cube that entirely encloses the --- right operand) --- -SELECT '0'::cube @> '0'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '0,0,0'::cube @> '0,0,0'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '0,0,1'::cube @> '0,0'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '0,0,1'::cube @> '0,0,0'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '0,0,1'::cube @> '1,0,0'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '(1,0,0),(0,0,1)'::cube @> '(1,0,0),(0,0,1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(-1,-1,-1),(1,1,1)'::cube @> '(1,0,0),(0,0,1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(-1,-1,-1,-1),(1,1,1,1)'::cube @> '(1,0,0),(0,0,1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(-1),(1)'::cube @> '0'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(-1),(1)'::cube @> '1'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(-1),(1)'::cube @> '-1'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(-1),(1)'::cube @> '(-1),(1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(-1,-1),(1,1)'::cube @> '(-1),(1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(-1),(1)'::cube @> '(-2),(1)'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '(-1,-1),(1,1)'::cube @> '(-2),(1)'::cube AS bool; - bool ------- - f -(1 row) - --- Test of distance function --- -SELECT cube_distance('(0)'::cube,'(2,2,2,2)'::cube); - cube_distance ---------------- - 4 -(1 row) - -SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube); - cube_distance ---------------- - 0.5 -(1 row) - -SELECT cube_distance('(2,3,4)'::cube,'(2,3,4)'::cube); - cube_distance ---------------- - 0 -(1 row) - -SELECT cube_distance('(42,42,42,42)'::cube,'(137,137,137,137)'::cube); - cube_distance ---------------- - 190 -(1 row) - -SELECT cube_distance('(42,42,42)'::cube,'(137,137)'::cube); - cube_distance ------------------- - 140.762210837994 -(1 row) - --- Test of cube function (text to cube) --- -SELECT cube('(1,1.2)'::text); - cube ----------- - (1, 1.2) -(1 row) - -SELECT cube(NULL); - cube ------- - -(1 row) - --- Test of cube_dim function (dimensions stored in cube) --- -SELECT cube_dim('(0)'::cube); - cube_dim ----------- - 1 -(1 row) - -SELECT cube_dim('(0,0)'::cube); - cube_dim ----------- - 2 -(1 row) - -SELECT cube_dim('(0,0,0)'::cube); - cube_dim ----------- - 3 -(1 row) - -SELECT cube_dim('(42,42,42),(42,42,42)'::cube); - cube_dim ----------- - 3 -(1 row) - -SELECT cube_dim('(4,8,15,16,23),(4,8,15,16,23)'::cube); - cube_dim ----------- - 5 -(1 row) - --- Test of cube_ll_coord function (retrieves LL coodinate values) --- -SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 1); - cube_ll_coord ---------------- - -1 -(1 row) - -SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 2); - cube_ll_coord ---------------- - -2 -(1 row) - -SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 3); - cube_ll_coord ---------------- - 0 -(1 row) - -SELECT cube_ll_coord('(1,2),(1,2)'::cube, 1); - cube_ll_coord ---------------- - 1 -(1 row) - -SELECT cube_ll_coord('(1,2),(1,2)'::cube, 2); - cube_ll_coord ---------------- - 2 -(1 row) - -SELECT cube_ll_coord('(1,2),(1,2)'::cube, 3); - cube_ll_coord ---------------- - 0 -(1 row) - -SELECT cube_ll_coord('(42,137)'::cube, 1); - cube_ll_coord ---------------- - 42 -(1 row) - -SELECT cube_ll_coord('(42,137)'::cube, 2); - cube_ll_coord ---------------- - 137 -(1 row) - -SELECT cube_ll_coord('(42,137)'::cube, 3); - cube_ll_coord ---------------- - 0 -(1 row) - --- Test of cube_ur_coord function (retrieves UR coodinate values) --- -SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 1); - cube_ur_coord ---------------- - 2 -(1 row) - -SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 2); - cube_ur_coord ---------------- - 1 -(1 row) - -SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 3); - cube_ur_coord ---------------- - 0 -(1 row) - -SELECT cube_ur_coord('(1,2),(1,2)'::cube, 1); - cube_ur_coord ---------------- - 1 -(1 row) - -SELECT cube_ur_coord('(1,2),(1,2)'::cube, 2); - cube_ur_coord ---------------- - 2 -(1 row) - -SELECT cube_ur_coord('(1,2),(1,2)'::cube, 3); - cube_ur_coord ---------------- - 0 -(1 row) - -SELECT cube_ur_coord('(42,137)'::cube, 1); - cube_ur_coord ---------------- - 42 -(1 row) - -SELECT cube_ur_coord('(42,137)'::cube, 2); - cube_ur_coord ---------------- - 137 -(1 row) - -SELECT cube_ur_coord('(42,137)'::cube, 3); - cube_ur_coord ---------------- - 0 -(1 row) - --- Test of cube_is_point --- -SELECT cube_is_point('(0)'::cube); - cube_is_point ---------------- - t -(1 row) - -SELECT cube_is_point('(0,1,2)'::cube); - cube_is_point ---------------- - t -(1 row) - -SELECT cube_is_point('(0,1,2),(0,1,2)'::cube); - cube_is_point ---------------- - t -(1 row) - -SELECT cube_is_point('(0,1,2),(-1,1,2)'::cube); - cube_is_point ---------------- - f -(1 row) - -SELECT cube_is_point('(0,1,2),(0,-1,2)'::cube); - cube_is_point ---------------- - f -(1 row) - -SELECT cube_is_point('(0,1,2),(0,1,-2)'::cube); - cube_is_point ---------------- - f -(1 row) - --- Test of cube_enlarge (enlarging and shrinking cubes) --- -SELECT cube_enlarge('(0)'::cube, 0, 0); - cube_enlarge --------------- - (0) -(1 row) - -SELECT cube_enlarge('(0)'::cube, 0, 1); - cube_enlarge --------------- - (0) -(1 row) - -SELECT cube_enlarge('(0)'::cube, 0, 2); - cube_enlarge --------------- - (0) -(1 row) - -SELECT cube_enlarge('(2),(-2)'::cube, 0, 4); - cube_enlarge --------------- - (-2),(2) -(1 row) - -SELECT cube_enlarge('(0)'::cube, 1, 0); - cube_enlarge --------------- - (-1),(1) -(1 row) - -SELECT cube_enlarge('(0)'::cube, 1, 1); - cube_enlarge --------------- - (-1),(1) -(1 row) - -SELECT cube_enlarge('(0)'::cube, 1, 2); - cube_enlarge ------------------ - (-1, -1),(1, 1) -(1 row) - -SELECT cube_enlarge('(2),(-2)'::cube, 1, 4); - cube_enlarge -------------------------------- - (-3, -1, -1, -1),(3, 1, 1, 1) -(1 row) - -SELECT cube_enlarge('(0)'::cube, -1, 0); - cube_enlarge --------------- - (0) -(1 row) - -SELECT cube_enlarge('(0)'::cube, -1, 1); - cube_enlarge --------------- - (0) -(1 row) - -SELECT cube_enlarge('(0)'::cube, -1, 2); - cube_enlarge --------------- - (0) -(1 row) - -SELECT cube_enlarge('(2),(-2)'::cube, -1, 4); - cube_enlarge --------------- - (-1),(1) -(1 row) - -SELECT cube_enlarge('(0,0,0)'::cube, 1, 0); - cube_enlarge ------------------------- - (-1, -1, -1),(1, 1, 1) -(1 row) - -SELECT cube_enlarge('(0,0,0)'::cube, 1, 2); - cube_enlarge ------------------------- - (-1, -1, -1),(1, 1, 1) -(1 row) - -SELECT cube_enlarge('(2,-2),(-3,7)'::cube, 1, 2); - cube_enlarge ------------------ - (-4, -3),(3, 8) -(1 row) - -SELECT cube_enlarge('(2,-2),(-3,7)'::cube, 3, 2); - cube_enlarge ------------------- - (-6, -5),(5, 10) -(1 row) - -SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -1, 2); - cube_enlarge ------------------ - (-2, -1),(1, 6) -(1 row) - -SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -3, 2); - cube_enlarge ---------------------- - (-0.5, 1),(-0.5, 4) -(1 row) - -SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -23, 5); - cube_enlarge --------------- - (42, 0, 0) -(1 row) - -SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -24, 5); - cube_enlarge --------------- - (42, 0, 0) -(1 row) - --- Test of cube_union (MBR for two cubes) --- -SELECT cube_union('(1,2),(3,4)'::cube, '(5,6,7),(8,9,10)'::cube); - cube_union ----------------------- - (1, 2, 0),(8, 9, 10) -(1 row) - -SELECT cube_union('(1,2)'::cube, '(4,2,0,0)'::cube); - cube_union ---------------------------- - (1, 2, 0, 0),(4, 2, 0, 0) -(1 row) - -SELECT cube_union('(1,2),(1,2)'::cube, '(4,2),(4,2)'::cube); - cube_union ---------------- - (1, 2),(4, 2) -(1 row) - -SELECT cube_union('(1,2),(1,2)'::cube, '(1,2),(1,2)'::cube); - cube_union ------------- - (1, 2) -(1 row) - -SELECT cube_union('(1,2),(1,2)'::cube, '(1,2,0),(1,2,0)'::cube); - cube_union ------------- - (1, 2, 0) -(1 row) - --- Test of cube_inter --- -SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (16,15)'::cube); -- intersects - cube_inter ------------------ - (3, 4),(10, 11) -(1 row) - -SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (6,5)'::cube); -- includes - cube_inter ---------------- - (3, 4),(6, 5) -(1 row) - -SELECT cube_inter('(1,2),(10,11)'::cube, '(13,14), (16,15)'::cube); -- no intersection - cube_inter -------------------- - (13, 14),(10, 11) -(1 row) - -SELECT cube_inter('(1,2),(10,11)'::cube, '(3,14), (16,15)'::cube); -- no intersection, but one dimension intersects - cube_inter ------------------- - (3, 14),(10, 11) -(1 row) - -SELECT cube_inter('(1,2),(10,11)'::cube, '(10,11), (16,15)'::cube); -- point intersection - cube_inter ------------- - (10, 11) -(1 row) - -SELECT cube_inter('(1,2,3)'::cube, '(1,2,3)'::cube); -- point args - cube_inter ------------- - (1, 2, 3) -(1 row) - -SELECT cube_inter('(1,2,3)'::cube, '(5,6,3)'::cube); -- point args - cube_inter ---------------------- - (5, 6, 3),(1, 2, 3) -(1 row) - --- Test of cube_size --- -SELECT cube_size('(4,8),(15,16)'::cube); - cube_size ------------ - 88 -(1 row) - -SELECT cube_size('(42,137)'::cube); - cube_size ------------ - 0 -(1 row) - --- Test of distances --- -SELECT cube_distance('(1,1)'::cube, '(4,5)'::cube); - cube_distance ---------------- - 5 -(1 row) - -SELECT '(1,1)'::cube <-> '(4,5)'::cube as d_e; - d_e ------ - 5 -(1 row) - -SELECT distance_chebyshev('(1,1)'::cube, '(4,5)'::cube); - distance_chebyshev --------------------- - 4 -(1 row) - -SELECT '(1,1)'::cube <=> '(4,5)'::cube as d_c; - d_c ------ - 4 -(1 row) - -SELECT distance_taxicab('(1,1)'::cube, '(4,5)'::cube); - distance_taxicab ------------------- - 7 -(1 row) - -SELECT '(1,1)'::cube <#> '(4,5)'::cube as d_t; - d_t ------ - 7 -(1 row) - --- zero for overlapping -SELECT cube_distance('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube); - cube_distance ---------------- - 0 -(1 row) - -SELECT distance_chebyshev('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube); - distance_chebyshev --------------------- - 0 -(1 row) - -SELECT distance_taxicab('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube); - distance_taxicab ------------------- - 0 -(1 row) - --- coordinate access -SELECT cube(array[10,20,30], array[40,50,60])->1; - ?column? ----------- - 10 -(1 row) - -SELECT cube(array[40,50,60], array[10,20,30])->1; - ?column? ----------- - 40 -(1 row) - -SELECT cube(array[10,20,30], array[40,50,60])->6; - ?column? ----------- - 60 -(1 row) - -SELECT cube(array[10,20,30], array[40,50,60])->0; -ERROR: cube index 0 is out of bounds -SELECT cube(array[10,20,30], array[40,50,60])->7; -ERROR: cube index 7 is out of bounds -SELECT cube(array[10,20,30], array[40,50,60])->-1; -ERROR: cube index -1 is out of bounds -SELECT cube(array[10,20,30], array[40,50,60])->-6; -ERROR: cube index -6 is out of bounds -SELECT cube(array[10,20,30])->3; - ?column? ----------- - 30 -(1 row) - -SELECT cube(array[10,20,30])->6; - ?column? ----------- - 30 -(1 row) - -SELECT cube(array[10,20,30])->-6; -ERROR: cube index -6 is out of bounds --- "normalized" coordinate access -SELECT cube(array[10,20,30], array[40,50,60])~>1; - ?column? ----------- - 10 -(1 row) - -SELECT cube(array[40,50,60], array[10,20,30])~>1; - ?column? ----------- - 10 -(1 row) - -SELECT cube(array[10,20,30], array[40,50,60])~>2; - ?column? ----------- - 20 -(1 row) - -SELECT cube(array[40,50,60], array[10,20,30])~>2; - ?column? ----------- - 20 -(1 row) - -SELECT cube(array[10,20,30], array[40,50,60])~>3; - ?column? ----------- - 30 -(1 row) - -SELECT cube(array[40,50,60], array[10,20,30])~>3; - ?column? ----------- - 30 -(1 row) - -SELECT cube(array[40,50,60], array[10,20,30])~>0; -ERROR: cube index 0 is out of bounds -SELECT cube(array[40,50,60], array[10,20,30])~>4; - ?column? ----------- - 40 -(1 row) - -SELECT cube(array[40,50,60], array[10,20,30])~>(-1); -ERROR: cube index -1 is out of bounds --- Load some example data and build the index --- -CREATE TABLE test_cube (c cube); -\copy test_cube from 'data/test_cube.data' -CREATE INDEX test_cube_ix ON test_cube USING gist (c); -SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' ORDER BY c; - c --------------------------- - (337, 455),(240, 359) - (759, 187),(662, 163) - (1444, 403),(1346, 344) - (1594, 1043),(1517, 971) - (2424, 160),(2424, 81) -(5 rows) - --- Test sorting -SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' GROUP BY c ORDER BY c; - c --------------------------- - (337, 455),(240, 359) - (759, 187),(662, 163) - (1444, 403),(1346, 344) - (1594, 1043),(1517, 971) - (2424, 160),(2424, 81) -(5 rows) - --- kNN with index -SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5; - c | dist --------------------------+------------------ - (337, 455),(240, 359) | 0 - (759, 187),(662, 163) | 162 - (948, 1201),(907, 1156) | 772.000647668122 - (1444, 403),(1346, 344) | 846 - (369, 1457),(278, 1409) | 909 -(5 rows) - -SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5; - c | dist --------------------------+------ - (337, 455),(240, 359) | 0 - (759, 187),(662, 163) | 162 - (948, 1201),(907, 1156) | 656 - (1444, 403),(1346, 344) | 846 - (369, 1457),(278, 1409) | 909 -(5 rows) - -SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5; - c | dist --------------------------+------ - (337, 455),(240, 359) | 0 - (759, 187),(662, 163) | 162 - (1444, 403),(1346, 344) | 846 - (369, 1457),(278, 1409) | 909 - (948, 1201),(907, 1156) | 1063 -(5 rows) - --- kNN-based sorting -SELECT * FROM test_cube ORDER BY c~>1 LIMIT 15; -- ascending by 1st coordinate of lower left corner - c ---------------------------- - (54, 38679),(3, 38602) - (83, 10271),(15, 10265) - (122, 46832),(64, 46762) - (167, 17214),(92, 17184) - (161, 24465),(107, 24374) - (162, 26040),(120, 25963) - (154, 4019),(138, 3990) - (259, 1850),(175, 1820) - (207, 40886),(179, 40879) - (288, 49588),(204, 49571) - (270, 32616),(226, 32607) - (318, 31489),(235, 31404) - (337, 455),(240, 359) - (270, 29508),(264, 29440) - (369, 1457),(278, 1409) -(15 rows) - -SELECT * FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by 2nd coordinate or upper right corner - c ---------------------------- - (30333, 50),(30273, 6) - (43301, 75),(43227, 43) - (19650, 142),(19630, 51) - (2424, 160),(2424, 81) - (3449, 171),(3354, 108) - (18037, 155),(17941, 109) - (28511, 208),(28479, 114) - (19946, 217),(19941, 118) - (16906, 191),(16816, 139) - (759, 187),(662, 163) - (22684, 266),(22656, 181) - (24423, 255),(24360, 213) - (45989, 249),(45910, 222) - (11399, 377),(11360, 294) - (12162, 389),(12103, 309) -(15 rows) - -SELECT * FROM test_cube ORDER BY c~>1 DESC LIMIT 15; -- descending by 1st coordinate of lower left corner - c -------------------------------- - (50027, 49230),(49951, 49214) - (49980, 35004),(49937, 34963) - (49985, 6436),(49927, 6338) - (49999, 27218),(49908, 27176) - (49954, 1340),(49905, 1294) - (49944, 25163),(49902, 25153) - (49981, 34876),(49898, 34786) - (49957, 43390),(49897, 43384) - (49853, 18504),(49848, 18503) - (49902, 41752),(49818, 41746) - (49907, 30225),(49810, 30158) - (49843, 5175),(49808, 5145) - (49887, 24274),(49805, 24184) - (49847, 7128),(49798, 7067) - (49820, 7990),(49771, 7967) -(15 rows) - -SELECT * FROM test_cube ORDER BY c~>4 DESC LIMIT 15; -- descending by 2nd coordinate or upper right corner - c -------------------------------- - (36311, 50073),(36258, 49987) - (30746, 50040),(30727, 49992) - (2168, 50012),(2108, 49914) - (21551, 49983),(21492, 49885) - (17954, 49975),(17865, 49915) - (3531, 49962),(3463, 49934) - (19128, 49932),(19112, 49849) - (31287, 49923),(31236, 49913) - (43925, 49912),(43888, 49878) - (29261, 49910),(29247, 49818) - (14913, 49873),(14849, 49836) - (20007, 49858),(19921, 49778) - (38266, 49852),(38233, 49844) - (37595, 49849),(37581, 49834) - (46151, 49848),(46058, 49830) -(15 rows) - --- same thing for index with points -CREATE TABLE test_point(c cube); -INSERT INTO test_point(SELECT cube(array[c->1,c->2,c->3,c->4]) FROM test_cube); -CREATE INDEX ON test_point USING gist(c); -SELECT * FROM test_point ORDER BY c~>1, c~>2 LIMIT 15; -- ascending by 1st then by 2nd coordinate - c --------------------------- - (54, 38679, 3, 38602) - (83, 10271, 15, 10265) - (122, 46832, 64, 46762) - (154, 4019, 138, 3990) - (161, 24465, 107, 24374) - (162, 26040, 120, 25963) - (167, 17214, 92, 17184) - (207, 40886, 179, 40879) - (259, 1850, 175, 1820) - (270, 29508, 264, 29440) - (270, 32616, 226, 32607) - (288, 49588, 204, 49571) - (318, 31489, 235, 31404) - (326, 18837, 285, 18817) - (337, 455, 240, 359) -(15 rows) - -SELECT * FROM test_point ORDER BY c~>4 DESC LIMIT 15; -- descending by 1st coordinate - c ------------------------------- - (30746, 50040, 30727, 49992) - (36311, 50073, 36258, 49987) - (3531, 49962, 3463, 49934) - (17954, 49975, 17865, 49915) - (2168, 50012, 2108, 49914) - (31287, 49923, 31236, 49913) - (21551, 49983, 21492, 49885) - (43925, 49912, 43888, 49878) - (19128, 49932, 19112, 49849) - (38266, 49852, 38233, 49844) - (14913, 49873, 14849, 49836) - (37595, 49849, 37581, 49834) - (46151, 49848, 46058, 49830) - (29261, 49910, 29247, 49818) - (19233, 49824, 19185, 49794) -(15 rows) - diff --git a/contrib/cube/expected/cube_2.out b/contrib/cube/expected/cube_2.out index fef749c698..c58614ef05 100644 --- a/contrib/cube/expected/cube_2.out +++ b/contrib/cube/expected/cube_2.out @@ -2,6 +2,14 @@ -- Test cube datatype -- CREATE EXTENSION cube; +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + amname | opcname +--------+--------- +(0 rows) + -- -- testing the input and output functions -- @@ -126,16 +134,34 @@ SELECT '-1.0e-7'::cube AS cube; (-1e-007) (1 row) -SELECT '1e-700'::cube AS cube; - cube ------- - (0) +SELECT '1e-300'::cube AS cube; + cube +---------- + (1e-300) (1 row) -SELECT '-1e-700'::cube AS cube; - cube ------- - (0) +SELECT '-1e-300'::cube AS cube; + cube +----------- + (-1e-300) +(1 row) + +SELECT 'infinity'::cube AS cube; + cube +------------ + (Infinity) +(1 row) + +SELECT '-infinity'::cube AS cube; + cube +------------- + (-Infinity) +(1 row) + +SELECT 'NaN'::cube AS cube; + cube +------- + (NaN) (1 row) SELECT '1234567890123456'::cube AS cube; @@ -175,6 +201,12 @@ SELECT '-.1234567890123456'::cube AS cube; (1 row) -- simple lists (points) +SELECT '()'::cube AS cube; + cube +------ + () +(1 row) + SELECT '1,2'::cube AS cube; cube -------- @@ -200,6 +232,12 @@ SELECT '(1,2,3,4,5)'::cube AS cube; (1 row) -- double lists (cubes) +SELECT '(),()'::cube AS cube; + cube +------ + () +(1 row) + SELECT '(0),(0)'::cube AS cube; cube ------ @@ -250,146 +288,145 @@ SELECT '[(0,0,0,0),(1,0,0,0)]'::cube AS cube; -- invalid input: parse errors SELECT ''::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT ''::cube AS cube; ^ DETAIL: syntax error at end of input SELECT 'ABC'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT 'ABC'::cube AS cube; ^ DETAIL: syntax error at or near "A" -SELECT '()'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '()'::cube AS cube; - ^ -DETAIL: syntax error at or near ")" SELECT '[]'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '[]'::cube AS cube; ^ DETAIL: syntax error at or near "]" SELECT '[()]'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '[()]'::cube AS cube; ^ -DETAIL: syntax error at or near ")" +DETAIL: syntax error at or near "]" SELECT '[(1)]'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '[(1)]'::cube AS cube; ^ DETAIL: syntax error at or near "]" SELECT '[(1),]'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '[(1),]'::cube AS cube; ^ DETAIL: syntax error at or near "]" SELECT '[(1),2]'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '[(1),2]'::cube AS cube; ^ DETAIL: syntax error at or near "2" SELECT '[(1),(2),(3)]'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '[(1),(2),(3)]'::cube AS cube; ^ DETAIL: syntax error at or near "," SELECT '1,'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '1,'::cube AS cube; ^ DETAIL: syntax error at end of input SELECT '1,2,'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '1,2,'::cube AS cube; ^ DETAIL: syntax error at end of input SELECT '1,,2'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '1,,2'::cube AS cube; ^ DETAIL: syntax error at or near "," SELECT '(1,)'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '(1,)'::cube AS cube; ^ DETAIL: syntax error at or near ")" SELECT '(1,2,)'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '(1,2,)'::cube AS cube; ^ DETAIL: syntax error at or near ")" SELECT '(1,,2)'::cube AS cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '(1,,2)'::cube AS cube; ^ DETAIL: syntax error at or near "," -- invalid input: semantic errors and trailing garbage SELECT '[(1),(2)],'::cube AS cube; -- 0 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '[(1),(2)],'::cube AS cube; ^ DETAIL: syntax error at or near "," SELECT '[(1,2,3),(2,3)]'::cube AS cube; -- 1 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '[(1,2,3),(2,3)]'::cube AS cube; ^ DETAIL: Different point dimensions in (1,2,3) and (2,3). SELECT '[(1,2),(1,2,3)]'::cube AS cube; -- 1 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '[(1,2),(1,2,3)]'::cube AS cube; ^ DETAIL: Different point dimensions in (1,2) and (1,2,3). SELECT '(1),(2),'::cube AS cube; -- 2 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '(1),(2),'::cube AS cube; ^ DETAIL: syntax error at or near "," SELECT '(1,2,3),(2,3)'::cube AS cube; -- 3 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '(1,2,3),(2,3)'::cube AS cube; ^ DETAIL: Different point dimensions in (1,2,3) and (2,3). SELECT '(1,2),(1,2,3)'::cube AS cube; -- 3 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '(1,2),(1,2,3)'::cube AS cube; ^ DETAIL: Different point dimensions in (1,2) and (1,2,3). SELECT '(1,2,3)ab'::cube AS cube; -- 4 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '(1,2,3)ab'::cube AS cube; ^ DETAIL: syntax error at or near "a" SELECT '(1,2,3)a'::cube AS cube; -- 5 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '(1,2,3)a'::cube AS cube; ^ DETAIL: syntax error at or near "a" SELECT '(1,2)('::cube AS cube; -- 5 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '(1,2)('::cube AS cube; ^ DETAIL: syntax error at or near "(" SELECT '1,2ab'::cube AS cube; -- 6 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '1,2ab'::cube AS cube; ^ DETAIL: syntax error at or near "a" SELECT '1 e7'::cube AS cube; -- 6 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '1 e7'::cube AS cube; ^ DETAIL: syntax error at or near "e" SELECT '1,2a'::cube AS cube; -- 7 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '1,2a'::cube AS cube; ^ DETAIL: syntax error at or near "a" SELECT '1..2'::cube AS cube; -- 7 -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: SELECT '1..2'::cube AS cube; ^ DETAIL: syntax error at or near ".2" +SELECT '-1e-700'::cube AS cube; -- out of range +ERROR: "-1e-700" is out of range for type double precision +LINE 1: SELECT '-1e-700'::cube AS cube; + ^ -- -- Testing building cubes from float8 values -- @@ -556,12 +593,12 @@ SELECT cube(cube(1,2), 42, 24); -- cube_c_f8_f8 -- Testing limit of CUBE_MAX_DIM dimensions check in cube_in. -- select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)'::cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0... ^ DETAIL: A cube cannot have more than 100 dimensions. select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)'::cube; -ERROR: bad cube representation +ERROR: invalid input syntax for cube LINE 1: select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0... ^ DETAIL: A cube cannot have more than 100 dimensions. diff --git a/contrib/cube/expected/cube_3.out b/contrib/cube/expected/cube_3.out deleted file mode 100644 index 31d2d1a64e..0000000000 --- a/contrib/cube/expected/cube_3.out +++ /dev/null @@ -1,1710 +0,0 @@ --- --- Test cube datatype --- -CREATE EXTENSION cube; --- --- testing the input and output functions --- --- Any number (a one-dimensional point) -SELECT '1'::cube AS cube; - cube ------- - (1) -(1 row) - -SELECT '-1'::cube AS cube; - cube ------- - (-1) -(1 row) - -SELECT '1.'::cube AS cube; - cube ------- - (1) -(1 row) - -SELECT '-1.'::cube AS cube; - cube ------- - (-1) -(1 row) - -SELECT '.1'::cube AS cube; - cube -------- - (0.1) -(1 row) - -SELECT '-.1'::cube AS cube; - cube --------- - (-0.1) -(1 row) - -SELECT '1.0'::cube AS cube; - cube ------- - (1) -(1 row) - -SELECT '-1.0'::cube AS cube; - cube ------- - (-1) -(1 row) - -SELECT '1e27'::cube AS cube; - cube ----------- - (1e+027) -(1 row) - -SELECT '-1e27'::cube AS cube; - cube ------------ - (-1e+027) -(1 row) - -SELECT '1.0e27'::cube AS cube; - cube ----------- - (1e+027) -(1 row) - -SELECT '-1.0e27'::cube AS cube; - cube ------------ - (-1e+027) -(1 row) - -SELECT '1e+27'::cube AS cube; - cube ----------- - (1e+027) -(1 row) - -SELECT '-1e+27'::cube AS cube; - cube ------------ - (-1e+027) -(1 row) - -SELECT '1.0e+27'::cube AS cube; - cube ----------- - (1e+027) -(1 row) - -SELECT '-1.0e+27'::cube AS cube; - cube ------------ - (-1e+027) -(1 row) - -SELECT '1e-7'::cube AS cube; - cube ----------- - (1e-007) -(1 row) - -SELECT '-1e-7'::cube AS cube; - cube ------------ - (-1e-007) -(1 row) - -SELECT '1.0e-7'::cube AS cube; - cube ----------- - (1e-007) -(1 row) - -SELECT '-1.0e-7'::cube AS cube; - cube ------------ - (-1e-007) -(1 row) - -SELECT '1e-700'::cube AS cube; - cube ------- - (0) -(1 row) - -SELECT '-1e-700'::cube AS cube; - cube ------- - (-0) -(1 row) - -SELECT '1234567890123456'::cube AS cube; - cube -------------------------- - (1.23456789012346e+015) -(1 row) - -SELECT '+1234567890123456'::cube AS cube; - cube -------------------------- - (1.23456789012346e+015) -(1 row) - -SELECT '-1234567890123456'::cube AS cube; - cube --------------------------- - (-1.23456789012346e+015) -(1 row) - -SELECT '.1234567890123456'::cube AS cube; - cube ---------------------- - (0.123456789012346) -(1 row) - -SELECT '+.1234567890123456'::cube AS cube; - cube ---------------------- - (0.123456789012346) -(1 row) - -SELECT '-.1234567890123456'::cube AS cube; - cube ----------------------- - (-0.123456789012346) -(1 row) - --- simple lists (points) -SELECT '1,2'::cube AS cube; - cube --------- - (1, 2) -(1 row) - -SELECT '(1,2)'::cube AS cube; - cube --------- - (1, 2) -(1 row) - -SELECT '1,2,3,4,5'::cube AS cube; - cube ------------------ - (1, 2, 3, 4, 5) -(1 row) - -SELECT '(1,2,3,4,5)'::cube AS cube; - cube ------------------ - (1, 2, 3, 4, 5) -(1 row) - --- double lists (cubes) -SELECT '(0),(0)'::cube AS cube; - cube ------- - (0) -(1 row) - -SELECT '(0),(1)'::cube AS cube; - cube ---------- - (0),(1) -(1 row) - -SELECT '[(0),(0)]'::cube AS cube; - cube ------- - (0) -(1 row) - -SELECT '[(0),(1)]'::cube AS cube; - cube ---------- - (0),(1) -(1 row) - -SELECT '(0,0,0,0),(0,0,0,0)'::cube AS cube; - cube --------------- - (0, 0, 0, 0) -(1 row) - -SELECT '(0,0,0,0),(1,0,0,0)'::cube AS cube; - cube ---------------------------- - (0, 0, 0, 0),(1, 0, 0, 0) -(1 row) - -SELECT '[(0,0,0,0),(0,0,0,0)]'::cube AS cube; - cube --------------- - (0, 0, 0, 0) -(1 row) - -SELECT '[(0,0,0,0),(1,0,0,0)]'::cube AS cube; - cube ---------------------------- - (0, 0, 0, 0),(1, 0, 0, 0) -(1 row) - --- invalid input: parse errors -SELECT ''::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT ''::cube AS cube; - ^ -DETAIL: syntax error at end of input -SELECT 'ABC'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT 'ABC'::cube AS cube; - ^ -DETAIL: syntax error at or near "A" -SELECT '()'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '()'::cube AS cube; - ^ -DETAIL: syntax error at or near ")" -SELECT '[]'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '[]'::cube AS cube; - ^ -DETAIL: syntax error at or near "]" -SELECT '[()]'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '[()]'::cube AS cube; - ^ -DETAIL: syntax error at or near ")" -SELECT '[(1)]'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '[(1)]'::cube AS cube; - ^ -DETAIL: syntax error at or near "]" -SELECT '[(1),]'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '[(1),]'::cube AS cube; - ^ -DETAIL: syntax error at or near "]" -SELECT '[(1),2]'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '[(1),2]'::cube AS cube; - ^ -DETAIL: syntax error at or near "2" -SELECT '[(1),(2),(3)]'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '[(1),(2),(3)]'::cube AS cube; - ^ -DETAIL: syntax error at or near "," -SELECT '1,'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '1,'::cube AS cube; - ^ -DETAIL: syntax error at end of input -SELECT '1,2,'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '1,2,'::cube AS cube; - ^ -DETAIL: syntax error at end of input -SELECT '1,,2'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '1,,2'::cube AS cube; - ^ -DETAIL: syntax error at or near "," -SELECT '(1,)'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '(1,)'::cube AS cube; - ^ -DETAIL: syntax error at or near ")" -SELECT '(1,2,)'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '(1,2,)'::cube AS cube; - ^ -DETAIL: syntax error at or near ")" -SELECT '(1,,2)'::cube AS cube; -ERROR: bad cube representation -LINE 1: SELECT '(1,,2)'::cube AS cube; - ^ -DETAIL: syntax error at or near "," --- invalid input: semantic errors and trailing garbage -SELECT '[(1),(2)],'::cube AS cube; -- 0 -ERROR: bad cube representation -LINE 1: SELECT '[(1),(2)],'::cube AS cube; - ^ -DETAIL: syntax error at or near "," -SELECT '[(1,2,3),(2,3)]'::cube AS cube; -- 1 -ERROR: bad cube representation -LINE 1: SELECT '[(1,2,3),(2,3)]'::cube AS cube; - ^ -DETAIL: Different point dimensions in (1,2,3) and (2,3). -SELECT '[(1,2),(1,2,3)]'::cube AS cube; -- 1 -ERROR: bad cube representation -LINE 1: SELECT '[(1,2),(1,2,3)]'::cube AS cube; - ^ -DETAIL: Different point dimensions in (1,2) and (1,2,3). -SELECT '(1),(2),'::cube AS cube; -- 2 -ERROR: bad cube representation -LINE 1: SELECT '(1),(2),'::cube AS cube; - ^ -DETAIL: syntax error at or near "," -SELECT '(1,2,3),(2,3)'::cube AS cube; -- 3 -ERROR: bad cube representation -LINE 1: SELECT '(1,2,3),(2,3)'::cube AS cube; - ^ -DETAIL: Different point dimensions in (1,2,3) and (2,3). -SELECT '(1,2),(1,2,3)'::cube AS cube; -- 3 -ERROR: bad cube representation -LINE 1: SELECT '(1,2),(1,2,3)'::cube AS cube; - ^ -DETAIL: Different point dimensions in (1,2) and (1,2,3). -SELECT '(1,2,3)ab'::cube AS cube; -- 4 -ERROR: bad cube representation -LINE 1: SELECT '(1,2,3)ab'::cube AS cube; - ^ -DETAIL: syntax error at or near "a" -SELECT '(1,2,3)a'::cube AS cube; -- 5 -ERROR: bad cube representation -LINE 1: SELECT '(1,2,3)a'::cube AS cube; - ^ -DETAIL: syntax error at or near "a" -SELECT '(1,2)('::cube AS cube; -- 5 -ERROR: bad cube representation -LINE 1: SELECT '(1,2)('::cube AS cube; - ^ -DETAIL: syntax error at or near "(" -SELECT '1,2ab'::cube AS cube; -- 6 -ERROR: bad cube representation -LINE 1: SELECT '1,2ab'::cube AS cube; - ^ -DETAIL: syntax error at or near "a" -SELECT '1 e7'::cube AS cube; -- 6 -ERROR: bad cube representation -LINE 1: SELECT '1 e7'::cube AS cube; - ^ -DETAIL: syntax error at or near "e" -SELECT '1,2a'::cube AS cube; -- 7 -ERROR: bad cube representation -LINE 1: SELECT '1,2a'::cube AS cube; - ^ -DETAIL: syntax error at or near "a" -SELECT '1..2'::cube AS cube; -- 7 -ERROR: bad cube representation -LINE 1: SELECT '1..2'::cube AS cube; - ^ -DETAIL: syntax error at or near ".2" --- --- Testing building cubes from float8 values --- -SELECT cube(0::float8); - cube ------- - (0) -(1 row) - -SELECT cube(1::float8); - cube ------- - (1) -(1 row) - -SELECT cube(1,2); - cube ---------- - (1),(2) -(1 row) - -SELECT cube(cube(1,2),3); - cube ---------------- - (1, 3),(2, 3) -(1 row) - -SELECT cube(cube(1,2),3,4); - cube ---------------- - (1, 3),(2, 4) -(1 row) - -SELECT cube(cube(cube(1,2),3,4),5); - cube ---------------------- - (1, 3, 5),(2, 4, 5) -(1 row) - -SELECT cube(cube(cube(1,2),3,4),5,6); - cube ---------------------- - (1, 3, 5),(2, 4, 6) -(1 row) - --- --- Test that the text -> cube cast was installed. --- -SELECT '(0)'::text::cube; - cube ------- - (0) -(1 row) - --- --- Test the float[] -> cube cast --- -SELECT cube('{0,1,2}'::float[], '{3,4,5}'::float[]); - cube ---------------------- - (0, 1, 2),(3, 4, 5) -(1 row) - -SELECT cube('{0,1,2}'::float[], '{3}'::float[]); -ERROR: UR and LL arrays must be of same length -SELECT cube(NULL::float[], '{3}'::float[]); - cube ------- - -(1 row) - -SELECT cube('{0,1,2}'::float[]); - cube ------------ - (0, 1, 2) -(1 row) - -SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[3,2,1,1]); - cube_subset ---------------------------- - (5, 3, 1, 1),(8, 7, 6, 6) -(1 row) - -SELECT cube_subset(cube('(1,3,5),(1,3,5)'), ARRAY[3,2,1,1]); - cube_subset --------------- - (5, 3, 1, 1) -(1 row) - -SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[4,0]); -ERROR: Index out of bounds -SELECT cube_subset(cube('(6,7,8),(6,7,8)'), ARRAY[4,0]); -ERROR: Index out of bounds --- --- Test point processing --- -SELECT cube('(1,2),(1,2)'); -- cube_in - cube --------- - (1, 2) -(1 row) - -SELECT cube('{0,1,2}'::float[], '{0,1,2}'::float[]); -- cube_a_f8_f8 - cube ------------ - (0, 1, 2) -(1 row) - -SELECT cube('{5,6,7,8}'::float[]); -- cube_a_f8 - cube --------------- - (5, 6, 7, 8) -(1 row) - -SELECT cube(1.37); -- cube_f8 - cube --------- - (1.37) -(1 row) - -SELECT cube(1.37, 1.37); -- cube_f8_f8 - cube --------- - (1.37) -(1 row) - -SELECT cube(cube(1,1), 42); -- cube_c_f8 - cube ---------- - (1, 42) -(1 row) - -SELECT cube(cube(1,2), 42); -- cube_c_f8 - cube ------------------ - (1, 42),(2, 42) -(1 row) - -SELECT cube(cube(1,1), 42, 42); -- cube_c_f8_f8 - cube ---------- - (1, 42) -(1 row) - -SELECT cube(cube(1,1), 42, 24); -- cube_c_f8_f8 - cube ------------------ - (1, 42),(1, 24) -(1 row) - -SELECT cube(cube(1,2), 42, 42); -- cube_c_f8_f8 - cube ------------------ - (1, 42),(2, 42) -(1 row) - -SELECT cube(cube(1,2), 42, 24); -- cube_c_f8_f8 - cube ------------------ - (1, 42),(2, 24) -(1 row) - --- --- Testing limit of CUBE_MAX_DIM dimensions check in cube_in. --- -select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)'::cube; -ERROR: bad cube representation -LINE 1: select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0... - ^ -DETAIL: A cube cannot have more than 100 dimensions. -select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)'::cube; -ERROR: bad cube representation -LINE 1: select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0... - ^ -DETAIL: A cube cannot have more than 100 dimensions. --- --- testing the operators --- --- equality/inequality: --- -SELECT '24, 33.20'::cube = '24, 33.20'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '24, 33.20'::cube != '24, 33.20'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '24, 33.20'::cube = '24, 33.21'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '24, 33.20'::cube != '24, 33.21'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(2,0),(3,1)'::cube = '(2,0,0,0,0),(3,1,0,0,0)'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '(2,0),(3,1)'::cube = '(2,0,0,0,0),(3,1,0,0,1)'::cube AS bool; - bool ------- - f -(1 row) - --- "lower than" / "greater than" --- (these operators are not useful for anything but ordering) --- -SELECT '1'::cube > '2'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '1'::cube < '2'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '1,1'::cube > '1,2'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '1,1'::cube < '1,2'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(2,0),(3,1)'::cube > '(2,0,0,0,0),(3,1,0,0,1)'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '(2,0),(3,1)'::cube < '(2,0,0,0,0),(3,1,0,0,1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(2,0),(3,1)'::cube > '(2,0,0,0,1),(3,1,0,0,0)'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '(2,0),(3,1)'::cube < '(2,0,0,0,1),(3,1,0,0,0)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(2,0),(3,1)'::cube > '(2,0,0,0,0),(3,1,0,0,0)'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '(2,0),(3,1)'::cube < '(2,0,0,0,0),(3,1,0,0,0)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(2,0,0,0,0),(3,1,0,0,1)'::cube > '(2,0),(3,1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(2,0,0,0,0),(3,1,0,0,1)'::cube < '(2,0),(3,1)'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '(2,0,0,0,1),(3,1,0,0,0)'::cube > '(2,0),(3,1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(2,0,0,0,1),(3,1,0,0,0)'::cube < '(2,0),(3,1)'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '(2,0,0,0,0),(3,1,0,0,0)'::cube > '(2,0),(3,1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(2,0,0,0,0),(3,1,0,0,0)'::cube < '(2,0),(3,1)'::cube AS bool; - bool ------- - f -(1 row) - --- "overlap" --- -SELECT '1'::cube && '1'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '1'::cube && '2'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '0'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '1'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '1,1,1'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '[(1,1,1),(2,2,2)]'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '[(1,1),(2,2)]'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '[(2,1,1),(2,2,2)]'::cube AS bool; - bool ------- - f -(1 row) - --- "contained in" (the left operand is the cube entirely enclosed by --- the right operand): --- -SELECT '0'::cube <@ '0'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '0,0,0'::cube <@ '0,0,0'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '0,0'::cube <@ '0,0,1'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '0,0,0'::cube <@ '0,0,1'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '1,0,0'::cube <@ '0,0,1'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '(1,0,0),(0,0,1)'::cube <@ '(1,0,0),(0,0,1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(1,0,0),(0,0,1)'::cube <@ '(-1,-1,-1),(1,1,1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(1,0,0),(0,0,1)'::cube <@ '(-1,-1,-1,-1),(1,1,1,1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '0'::cube <@ '(-1),(1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '1'::cube <@ '(-1),(1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '-1'::cube <@ '(-1),(1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(-1),(1)'::cube <@ '(-1),(1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(-1),(1)'::cube <@ '(-1,-1),(1,1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(-2),(1)'::cube <@ '(-1),(1)'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '(-2),(1)'::cube <@ '(-1,-1),(1,1)'::cube AS bool; - bool ------- - f -(1 row) - --- "contains" (the left operand is the cube that entirely encloses the --- right operand) --- -SELECT '0'::cube @> '0'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '0,0,0'::cube @> '0,0,0'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '0,0,1'::cube @> '0,0'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '0,0,1'::cube @> '0,0,0'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '0,0,1'::cube @> '1,0,0'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '(1,0,0),(0,0,1)'::cube @> '(1,0,0),(0,0,1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(-1,-1,-1),(1,1,1)'::cube @> '(1,0,0),(0,0,1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(-1,-1,-1,-1),(1,1,1,1)'::cube @> '(1,0,0),(0,0,1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(-1),(1)'::cube @> '0'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(-1),(1)'::cube @> '1'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(-1),(1)'::cube @> '-1'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(-1),(1)'::cube @> '(-1),(1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(-1,-1),(1,1)'::cube @> '(-1),(1)'::cube AS bool; - bool ------- - t -(1 row) - -SELECT '(-1),(1)'::cube @> '(-2),(1)'::cube AS bool; - bool ------- - f -(1 row) - -SELECT '(-1,-1),(1,1)'::cube @> '(-2),(1)'::cube AS bool; - bool ------- - f -(1 row) - --- Test of distance function --- -SELECT cube_distance('(0)'::cube,'(2,2,2,2)'::cube); - cube_distance ---------------- - 4 -(1 row) - -SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube); - cube_distance ---------------- - 0.5 -(1 row) - -SELECT cube_distance('(2,3,4)'::cube,'(2,3,4)'::cube); - cube_distance ---------------- - 0 -(1 row) - -SELECT cube_distance('(42,42,42,42)'::cube,'(137,137,137,137)'::cube); - cube_distance ---------------- - 190 -(1 row) - -SELECT cube_distance('(42,42,42)'::cube,'(137,137)'::cube); - cube_distance ------------------- - 140.762210837994 -(1 row) - --- Test of cube function (text to cube) --- -SELECT cube('(1,1.2)'::text); - cube ----------- - (1, 1.2) -(1 row) - -SELECT cube(NULL); - cube ------- - -(1 row) - --- Test of cube_dim function (dimensions stored in cube) --- -SELECT cube_dim('(0)'::cube); - cube_dim ----------- - 1 -(1 row) - -SELECT cube_dim('(0,0)'::cube); - cube_dim ----------- - 2 -(1 row) - -SELECT cube_dim('(0,0,0)'::cube); - cube_dim ----------- - 3 -(1 row) - -SELECT cube_dim('(42,42,42),(42,42,42)'::cube); - cube_dim ----------- - 3 -(1 row) - -SELECT cube_dim('(4,8,15,16,23),(4,8,15,16,23)'::cube); - cube_dim ----------- - 5 -(1 row) - --- Test of cube_ll_coord function (retrieves LL coodinate values) --- -SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 1); - cube_ll_coord ---------------- - -1 -(1 row) - -SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 2); - cube_ll_coord ---------------- - -2 -(1 row) - -SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 3); - cube_ll_coord ---------------- - 0 -(1 row) - -SELECT cube_ll_coord('(1,2),(1,2)'::cube, 1); - cube_ll_coord ---------------- - 1 -(1 row) - -SELECT cube_ll_coord('(1,2),(1,2)'::cube, 2); - cube_ll_coord ---------------- - 2 -(1 row) - -SELECT cube_ll_coord('(1,2),(1,2)'::cube, 3); - cube_ll_coord ---------------- - 0 -(1 row) - -SELECT cube_ll_coord('(42,137)'::cube, 1); - cube_ll_coord ---------------- - 42 -(1 row) - -SELECT cube_ll_coord('(42,137)'::cube, 2); - cube_ll_coord ---------------- - 137 -(1 row) - -SELECT cube_ll_coord('(42,137)'::cube, 3); - cube_ll_coord ---------------- - 0 -(1 row) - --- Test of cube_ur_coord function (retrieves UR coodinate values) --- -SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 1); - cube_ur_coord ---------------- - 2 -(1 row) - -SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 2); - cube_ur_coord ---------------- - 1 -(1 row) - -SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 3); - cube_ur_coord ---------------- - 0 -(1 row) - -SELECT cube_ur_coord('(1,2),(1,2)'::cube, 1); - cube_ur_coord ---------------- - 1 -(1 row) - -SELECT cube_ur_coord('(1,2),(1,2)'::cube, 2); - cube_ur_coord ---------------- - 2 -(1 row) - -SELECT cube_ur_coord('(1,2),(1,2)'::cube, 3); - cube_ur_coord ---------------- - 0 -(1 row) - -SELECT cube_ur_coord('(42,137)'::cube, 1); - cube_ur_coord ---------------- - 42 -(1 row) - -SELECT cube_ur_coord('(42,137)'::cube, 2); - cube_ur_coord ---------------- - 137 -(1 row) - -SELECT cube_ur_coord('(42,137)'::cube, 3); - cube_ur_coord ---------------- - 0 -(1 row) - --- Test of cube_is_point --- -SELECT cube_is_point('(0)'::cube); - cube_is_point ---------------- - t -(1 row) - -SELECT cube_is_point('(0,1,2)'::cube); - cube_is_point ---------------- - t -(1 row) - -SELECT cube_is_point('(0,1,2),(0,1,2)'::cube); - cube_is_point ---------------- - t -(1 row) - -SELECT cube_is_point('(0,1,2),(-1,1,2)'::cube); - cube_is_point ---------------- - f -(1 row) - -SELECT cube_is_point('(0,1,2),(0,-1,2)'::cube); - cube_is_point ---------------- - f -(1 row) - -SELECT cube_is_point('(0,1,2),(0,1,-2)'::cube); - cube_is_point ---------------- - f -(1 row) - --- Test of cube_enlarge (enlarging and shrinking cubes) --- -SELECT cube_enlarge('(0)'::cube, 0, 0); - cube_enlarge --------------- - (0) -(1 row) - -SELECT cube_enlarge('(0)'::cube, 0, 1); - cube_enlarge --------------- - (0) -(1 row) - -SELECT cube_enlarge('(0)'::cube, 0, 2); - cube_enlarge --------------- - (0) -(1 row) - -SELECT cube_enlarge('(2),(-2)'::cube, 0, 4); - cube_enlarge --------------- - (-2),(2) -(1 row) - -SELECT cube_enlarge('(0)'::cube, 1, 0); - cube_enlarge --------------- - (-1),(1) -(1 row) - -SELECT cube_enlarge('(0)'::cube, 1, 1); - cube_enlarge --------------- - (-1),(1) -(1 row) - -SELECT cube_enlarge('(0)'::cube, 1, 2); - cube_enlarge ------------------ - (-1, -1),(1, 1) -(1 row) - -SELECT cube_enlarge('(2),(-2)'::cube, 1, 4); - cube_enlarge -------------------------------- - (-3, -1, -1, -1),(3, 1, 1, 1) -(1 row) - -SELECT cube_enlarge('(0)'::cube, -1, 0); - cube_enlarge --------------- - (0) -(1 row) - -SELECT cube_enlarge('(0)'::cube, -1, 1); - cube_enlarge --------------- - (0) -(1 row) - -SELECT cube_enlarge('(0)'::cube, -1, 2); - cube_enlarge --------------- - (0) -(1 row) - -SELECT cube_enlarge('(2),(-2)'::cube, -1, 4); - cube_enlarge --------------- - (-1),(1) -(1 row) - -SELECT cube_enlarge('(0,0,0)'::cube, 1, 0); - cube_enlarge ------------------------- - (-1, -1, -1),(1, 1, 1) -(1 row) - -SELECT cube_enlarge('(0,0,0)'::cube, 1, 2); - cube_enlarge ------------------------- - (-1, -1, -1),(1, 1, 1) -(1 row) - -SELECT cube_enlarge('(2,-2),(-3,7)'::cube, 1, 2); - cube_enlarge ------------------ - (-4, -3),(3, 8) -(1 row) - -SELECT cube_enlarge('(2,-2),(-3,7)'::cube, 3, 2); - cube_enlarge ------------------- - (-6, -5),(5, 10) -(1 row) - -SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -1, 2); - cube_enlarge ------------------ - (-2, -1),(1, 6) -(1 row) - -SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -3, 2); - cube_enlarge ---------------------- - (-0.5, 1),(-0.5, 4) -(1 row) - -SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -23, 5); - cube_enlarge --------------- - (42, 0, 0) -(1 row) - -SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -24, 5); - cube_enlarge --------------- - (42, 0, 0) -(1 row) - --- Test of cube_union (MBR for two cubes) --- -SELECT cube_union('(1,2),(3,4)'::cube, '(5,6,7),(8,9,10)'::cube); - cube_union ----------------------- - (1, 2, 0),(8, 9, 10) -(1 row) - -SELECT cube_union('(1,2)'::cube, '(4,2,0,0)'::cube); - cube_union ---------------------------- - (1, 2, 0, 0),(4, 2, 0, 0) -(1 row) - -SELECT cube_union('(1,2),(1,2)'::cube, '(4,2),(4,2)'::cube); - cube_union ---------------- - (1, 2),(4, 2) -(1 row) - -SELECT cube_union('(1,2),(1,2)'::cube, '(1,2),(1,2)'::cube); - cube_union ------------- - (1, 2) -(1 row) - -SELECT cube_union('(1,2),(1,2)'::cube, '(1,2,0),(1,2,0)'::cube); - cube_union ------------- - (1, 2, 0) -(1 row) - --- Test of cube_inter --- -SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (16,15)'::cube); -- intersects - cube_inter ------------------ - (3, 4),(10, 11) -(1 row) - -SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (6,5)'::cube); -- includes - cube_inter ---------------- - (3, 4),(6, 5) -(1 row) - -SELECT cube_inter('(1,2),(10,11)'::cube, '(13,14), (16,15)'::cube); -- no intersection - cube_inter -------------------- - (13, 14),(10, 11) -(1 row) - -SELECT cube_inter('(1,2),(10,11)'::cube, '(3,14), (16,15)'::cube); -- no intersection, but one dimension intersects - cube_inter ------------------- - (3, 14),(10, 11) -(1 row) - -SELECT cube_inter('(1,2),(10,11)'::cube, '(10,11), (16,15)'::cube); -- point intersection - cube_inter ------------- - (10, 11) -(1 row) - -SELECT cube_inter('(1,2,3)'::cube, '(1,2,3)'::cube); -- point args - cube_inter ------------- - (1, 2, 3) -(1 row) - -SELECT cube_inter('(1,2,3)'::cube, '(5,6,3)'::cube); -- point args - cube_inter ---------------------- - (5, 6, 3),(1, 2, 3) -(1 row) - --- Test of cube_size --- -SELECT cube_size('(4,8),(15,16)'::cube); - cube_size ------------ - 88 -(1 row) - -SELECT cube_size('(42,137)'::cube); - cube_size ------------ - 0 -(1 row) - --- Test of distances --- -SELECT cube_distance('(1,1)'::cube, '(4,5)'::cube); - cube_distance ---------------- - 5 -(1 row) - -SELECT '(1,1)'::cube <-> '(4,5)'::cube as d_e; - d_e ------ - 5 -(1 row) - -SELECT distance_chebyshev('(1,1)'::cube, '(4,5)'::cube); - distance_chebyshev --------------------- - 4 -(1 row) - -SELECT '(1,1)'::cube <=> '(4,5)'::cube as d_c; - d_c ------ - 4 -(1 row) - -SELECT distance_taxicab('(1,1)'::cube, '(4,5)'::cube); - distance_taxicab ------------------- - 7 -(1 row) - -SELECT '(1,1)'::cube <#> '(4,5)'::cube as d_t; - d_t ------ - 7 -(1 row) - --- zero for overlapping -SELECT cube_distance('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube); - cube_distance ---------------- - 0 -(1 row) - -SELECT distance_chebyshev('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube); - distance_chebyshev --------------------- - 0 -(1 row) - -SELECT distance_taxicab('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube); - distance_taxicab ------------------- - 0 -(1 row) - --- coordinate access -SELECT cube(array[10,20,30], array[40,50,60])->1; - ?column? ----------- - 10 -(1 row) - -SELECT cube(array[40,50,60], array[10,20,30])->1; - ?column? ----------- - 40 -(1 row) - -SELECT cube(array[10,20,30], array[40,50,60])->6; - ?column? ----------- - 60 -(1 row) - -SELECT cube(array[10,20,30], array[40,50,60])->0; -ERROR: cube index 0 is out of bounds -SELECT cube(array[10,20,30], array[40,50,60])->7; -ERROR: cube index 7 is out of bounds -SELECT cube(array[10,20,30], array[40,50,60])->-1; -ERROR: cube index -1 is out of bounds -SELECT cube(array[10,20,30], array[40,50,60])->-6; -ERROR: cube index -6 is out of bounds -SELECT cube(array[10,20,30])->3; - ?column? ----------- - 30 -(1 row) - -SELECT cube(array[10,20,30])->6; - ?column? ----------- - 30 -(1 row) - -SELECT cube(array[10,20,30])->-6; -ERROR: cube index -6 is out of bounds --- "normalized" coordinate access -SELECT cube(array[10,20,30], array[40,50,60])~>1; - ?column? ----------- - 10 -(1 row) - -SELECT cube(array[40,50,60], array[10,20,30])~>1; - ?column? ----------- - 10 -(1 row) - -SELECT cube(array[10,20,30], array[40,50,60])~>2; - ?column? ----------- - 20 -(1 row) - -SELECT cube(array[40,50,60], array[10,20,30])~>2; - ?column? ----------- - 20 -(1 row) - -SELECT cube(array[10,20,30], array[40,50,60])~>3; - ?column? ----------- - 30 -(1 row) - -SELECT cube(array[40,50,60], array[10,20,30])~>3; - ?column? ----------- - 30 -(1 row) - -SELECT cube(array[40,50,60], array[10,20,30])~>0; -ERROR: cube index 0 is out of bounds -SELECT cube(array[40,50,60], array[10,20,30])~>4; - ?column? ----------- - 40 -(1 row) - -SELECT cube(array[40,50,60], array[10,20,30])~>(-1); -ERROR: cube index -1 is out of bounds --- Load some example data and build the index --- -CREATE TABLE test_cube (c cube); -\copy test_cube from 'data/test_cube.data' -CREATE INDEX test_cube_ix ON test_cube USING gist (c); -SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' ORDER BY c; - c --------------------------- - (337, 455),(240, 359) - (759, 187),(662, 163) - (1444, 403),(1346, 344) - (1594, 1043),(1517, 971) - (2424, 160),(2424, 81) -(5 rows) - --- Test sorting -SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' GROUP BY c ORDER BY c; - c --------------------------- - (337, 455),(240, 359) - (759, 187),(662, 163) - (1444, 403),(1346, 344) - (1594, 1043),(1517, 971) - (2424, 160),(2424, 81) -(5 rows) - --- kNN with index -SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5; - c | dist --------------------------+------------------ - (337, 455),(240, 359) | 0 - (759, 187),(662, 163) | 162 - (948, 1201),(907, 1156) | 772.000647668122 - (1444, 403),(1346, 344) | 846 - (369, 1457),(278, 1409) | 909 -(5 rows) - -SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5; - c | dist --------------------------+------ - (337, 455),(240, 359) | 0 - (759, 187),(662, 163) | 162 - (948, 1201),(907, 1156) | 656 - (1444, 403),(1346, 344) | 846 - (369, 1457),(278, 1409) | 909 -(5 rows) - -SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5; - c | dist --------------------------+------ - (337, 455),(240, 359) | 0 - (759, 187),(662, 163) | 162 - (1444, 403),(1346, 344) | 846 - (369, 1457),(278, 1409) | 909 - (948, 1201),(907, 1156) | 1063 -(5 rows) - --- kNN-based sorting -SELECT * FROM test_cube ORDER BY c~>1 LIMIT 15; -- ascending by 1st coordinate of lower left corner - c ---------------------------- - (54, 38679),(3, 38602) - (83, 10271),(15, 10265) - (122, 46832),(64, 46762) - (167, 17214),(92, 17184) - (161, 24465),(107, 24374) - (162, 26040),(120, 25963) - (154, 4019),(138, 3990) - (259, 1850),(175, 1820) - (207, 40886),(179, 40879) - (288, 49588),(204, 49571) - (270, 32616),(226, 32607) - (318, 31489),(235, 31404) - (337, 455),(240, 359) - (270, 29508),(264, 29440) - (369, 1457),(278, 1409) -(15 rows) - -SELECT * FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by 2nd coordinate or upper right corner - c ---------------------------- - (30333, 50),(30273, 6) - (43301, 75),(43227, 43) - (19650, 142),(19630, 51) - (2424, 160),(2424, 81) - (3449, 171),(3354, 108) - (18037, 155),(17941, 109) - (28511, 208),(28479, 114) - (19946, 217),(19941, 118) - (16906, 191),(16816, 139) - (759, 187),(662, 163) - (22684, 266),(22656, 181) - (24423, 255),(24360, 213) - (45989, 249),(45910, 222) - (11399, 377),(11360, 294) - (12162, 389),(12103, 309) -(15 rows) - -SELECT * FROM test_cube ORDER BY c~>1 DESC LIMIT 15; -- descending by 1st coordinate of lower left corner - c -------------------------------- - (50027, 49230),(49951, 49214) - (49980, 35004),(49937, 34963) - (49985, 6436),(49927, 6338) - (49999, 27218),(49908, 27176) - (49954, 1340),(49905, 1294) - (49944, 25163),(49902, 25153) - (49981, 34876),(49898, 34786) - (49957, 43390),(49897, 43384) - (49853, 18504),(49848, 18503) - (49902, 41752),(49818, 41746) - (49907, 30225),(49810, 30158) - (49843, 5175),(49808, 5145) - (49887, 24274),(49805, 24184) - (49847, 7128),(49798, 7067) - (49820, 7990),(49771, 7967) -(15 rows) - -SELECT * FROM test_cube ORDER BY c~>4 DESC LIMIT 15; -- descending by 2nd coordinate or upper right corner - c -------------------------------- - (36311, 50073),(36258, 49987) - (30746, 50040),(30727, 49992) - (2168, 50012),(2108, 49914) - (21551, 49983),(21492, 49885) - (17954, 49975),(17865, 49915) - (3531, 49962),(3463, 49934) - (19128, 49932),(19112, 49849) - (31287, 49923),(31236, 49913) - (43925, 49912),(43888, 49878) - (29261, 49910),(29247, 49818) - (14913, 49873),(14849, 49836) - (20007, 49858),(19921, 49778) - (38266, 49852),(38233, 49844) - (37595, 49849),(37581, 49834) - (46151, 49848),(46058, 49830) -(15 rows) - --- same thing for index with points -CREATE TABLE test_point(c cube); -INSERT INTO test_point(SELECT cube(array[c->1,c->2,c->3,c->4]) FROM test_cube); -CREATE INDEX ON test_point USING gist(c); -SELECT * FROM test_point ORDER BY c~>1, c~>2 LIMIT 15; -- ascending by 1st then by 2nd coordinate - c --------------------------- - (54, 38679, 3, 38602) - (83, 10271, 15, 10265) - (122, 46832, 64, 46762) - (154, 4019, 138, 3990) - (161, 24465, 107, 24374) - (162, 26040, 120, 25963) - (167, 17214, 92, 17184) - (207, 40886, 179, 40879) - (259, 1850, 175, 1820) - (270, 29508, 264, 29440) - (270, 32616, 226, 32607) - (288, 49588, 204, 49571) - (318, 31489, 235, 31404) - (326, 18837, 285, 18817) - (337, 455, 240, 359) -(15 rows) - -SELECT * FROM test_point ORDER BY c~>4 DESC LIMIT 15; -- descending by 1st coordinate - c ------------------------------- - (30746, 50040, 30727, 49992) - (36311, 50073, 36258, 49987) - (3531, 49962, 3463, 49934) - (17954, 49975, 17865, 49915) - (2168, 50012, 2108, 49914) - (31287, 49923, 31236, 49913) - (21551, 49983, 21492, 49885) - (43925, 49912, 43888, 49878) - (19128, 49932, 19112, 49849) - (38266, 49852, 38233, 49844) - (14913, 49873, 14849, 49836) - (37595, 49849, 37581, 49834) - (46151, 49848, 46058, 49830) - (29261, 49910, 29247, 49818) - (19233, 49824, 19185, 49794) -(15 rows) - diff --git a/contrib/cube/sql/cube.sql b/contrib/cube/sql/cube.sql index e225fb7da1..a61fba1ea8 100644 --- a/contrib/cube/sql/cube.sql +++ b/contrib/cube/sql/cube.sql @@ -4,6 +4,11 @@ CREATE EXTENSION cube; +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + -- -- testing the input and output functions -- @@ -29,8 +34,11 @@ SELECT '1e-7'::cube AS cube; SELECT '-1e-7'::cube AS cube; SELECT '1.0e-7'::cube AS cube; SELECT '-1.0e-7'::cube AS cube; -SELECT '1e-700'::cube AS cube; -SELECT '-1e-700'::cube AS cube; +SELECT '1e-300'::cube AS cube; +SELECT '-1e-300'::cube AS cube; +SELECT 'infinity'::cube AS cube; +SELECT '-infinity'::cube AS cube; +SELECT 'NaN'::cube AS cube; SELECT '1234567890123456'::cube AS cube; SELECT '+1234567890123456'::cube AS cube; SELECT '-1234567890123456'::cube AS cube; @@ -39,12 +47,14 @@ SELECT '+.1234567890123456'::cube AS cube; SELECT '-.1234567890123456'::cube AS cube; -- simple lists (points) +SELECT '()'::cube AS cube; SELECT '1,2'::cube AS cube; SELECT '(1,2)'::cube AS cube; SELECT '1,2,3,4,5'::cube AS cube; SELECT '(1,2,3,4,5)'::cube AS cube; -- double lists (cubes) +SELECT '(),()'::cube AS cube; SELECT '(0),(0)'::cube AS cube; SELECT '(0),(1)'::cube AS cube; SELECT '[(0),(0)]'::cube AS cube; @@ -57,7 +67,6 @@ SELECT '[(0,0,0,0),(1,0,0,0)]'::cube AS cube; -- invalid input: parse errors SELECT ''::cube AS cube; SELECT 'ABC'::cube AS cube; -SELECT '()'::cube AS cube; SELECT '[]'::cube AS cube; SELECT '[()]'::cube AS cube; SELECT '[(1)]'::cube AS cube; @@ -85,6 +94,7 @@ SELECT '1,2ab'::cube AS cube; -- 6 SELECT '1 e7'::cube AS cube; -- 6 SELECT '1,2a'::cube AS cube; -- 7 SELECT '1..2'::cube AS cube; -- 7 +SELECT '-1e-700'::cube AS cube; -- out of range -- -- Testing building cubes from float8 values diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c index 9c8e308358..ac43c458cb 100644 --- a/contrib/dblink/dblink.c +++ b/contrib/dblink/dblink.c @@ -9,7 +9,7 @@ * Shridhar Daithankar * * contrib/dblink/dblink.c - * Copyright (c) 2001-2016, PostgreSQL Global Development Group + * Copyright (c) 2001-2017, PostgreSQL Global Development Group * ALL RIGHTS RESERVED; * * Permission to use, copy, modify, and distribute this software and its @@ -40,6 +40,7 @@ #include "access/reloptions.h" #include "catalog/indexing.h" #include "catalog/namespace.h" +#include "catalog/pg_foreign_data_wrapper.h" #include "catalog/pg_foreign_server.h" #include "catalog/pg_type.h" #include "catalog/pg_user_mapping.h" @@ -58,6 +59,7 @@ #include "utils/memutils.h" #include "utils/rel.h" #include "utils/tqual.h" +#include "utils/varlena.h" #include "dblink.h" @@ -112,7 +114,8 @@ static Relation get_rel_from_relname(text *relname_text, LOCKMODE lockmode, AclM static char *generate_relation_name(Relation rel); static void dblink_connstr_check(const char *connstr); static void dblink_security_check(PGconn *conn, remoteConn *rconn); -static void dblink_res_error(const char *conname, PGresult *res, const char *dblink_context_msg, bool fail); +static void dblink_res_error(PGconn *conn, const char *conname, PGresult *res, + const char *dblink_context_msg, bool fail); static char *get_connect_string(const char *servername); static char *escape_param_str(const char *from); static void validate_pkattnums(Relation rel, @@ -427,7 +430,7 @@ dblink_open(PG_FUNCTION_ARGS) res = PQexec(conn, buf.data); if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { - dblink_res_error(conname, res, "could not open cursor", fail); + dblink_res_error(conn, conname, res, "could not open cursor", fail); PG_RETURN_TEXT_P(cstring_to_text("ERROR")); } @@ -496,7 +499,7 @@ dblink_close(PG_FUNCTION_ARGS) res = PQexec(conn, buf.data); if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { - dblink_res_error(conname, res, "could not close cursor", fail); + dblink_res_error(conn, conname, res, "could not close cursor", fail); PG_RETURN_TEXT_P(cstring_to_text("ERROR")); } @@ -599,7 +602,8 @@ dblink_fetch(PG_FUNCTION_ARGS) (PQresultStatus(res) != PGRES_COMMAND_OK && PQresultStatus(res) != PGRES_TUPLES_OK)) { - dblink_res_error(conname, res, "could not fetch from cursor", fail); + dblink_res_error(conn, conname, res, + "could not fetch from cursor", fail); return (Datum) 0; } else if (PQresultStatus(res) == PGRES_COMMAND_OK) @@ -750,8 +754,8 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async) if (PQresultStatus(res) != PGRES_COMMAND_OK && PQresultStatus(res) != PGRES_TUPLES_OK) { - dblink_res_error(conname, res, "could not execute query", - fail); + dblink_res_error(conn, conname, res, + "could not execute query", fail); /* if fail isn't set, we'll return an empty query result */ } else @@ -980,9 +984,7 @@ materializeQueryResult(FunctionCallInfo fcinfo, /* Create short-lived memory context for data conversions */ sinfo.tmpcontext = AllocSetContextCreate(CurrentMemoryContext, "dblink temporary context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* execute query, collecting any tuples into the tuplestore */ res = storeQueryResult(&sinfo, conn, sql); @@ -998,7 +1000,8 @@ materializeQueryResult(FunctionCallInfo fcinfo, PGresult *res1 = res; res = NULL; - dblink_res_error(conname, res1, "could not execute query", fail); + dblink_res_error(conn, conname, res1, + "could not execute query", fail); /* if fail isn't set, we'll return an empty query result */ } else if (PQresultStatus(res) == PGRES_COMMAND_OK) @@ -1433,7 +1436,8 @@ dblink_exec(PG_FUNCTION_ARGS) (PQresultStatus(res) != PGRES_COMMAND_OK && PQresultStatus(res) != PGRES_TUPLES_OK)) { - dblink_res_error(conname, res, "could not execute command", fail); + dblink_res_error(conn, conname, res, + "could not execute command", fail); /* * and save a copy of the command status string to return as our @@ -2664,7 +2668,8 @@ dblink_connstr_check(const char *connstr) } static void -dblink_res_error(const char *conname, PGresult *res, const char *dblink_context_msg, bool fail) +dblink_res_error(PGconn *conn, const char *conname, PGresult *res, + const char *dblink_context_msg, bool fail) { int level; char *pg_diag_sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE); @@ -2698,6 +2703,14 @@ dblink_res_error(const char *conname, PGresult *res, const char *dblink_context_ xpstrdup(message_hint, pg_diag_message_hint); xpstrdup(message_context, pg_diag_context); + /* + * If we don't get a message from the PGresult, try the PGconn. This + * is needed because for connection-level failures, PQexec may just + * return NULL, not a PGresult at all. + */ + if (message_primary == NULL) + message_primary = PQerrorMessage(conn); + if (res) PQclear(res); @@ -2707,7 +2720,7 @@ dblink_res_error(const char *conname, PGresult *res, const char *dblink_context_ ereport(level, (errcode(sqlstate), message_primary ? errmsg_internal("%s", message_primary) : - errmsg("unknown error"), + errmsg("could not obtain message string for remote error"), message_detail ? errdetail_internal("%s", message_detail) : 0, message_hint ? errhint("%s", message_hint) : 0, message_context ? errcontext("%s", message_context) : 0, @@ -2729,6 +2742,25 @@ get_connect_string(const char *servername) AclResult aclresult; char *srvname; + static const PQconninfoOption *options = NULL; + + /* + * Get list of valid libpq options. + * + * To avoid unnecessary work, we get the list once and use it throughout + * the lifetime of this backend process. We don't need to care about + * memory context issues, because PQconndefaults allocates with malloc. + */ + if (!options) + { + options = PQconndefaults(); + if (!options) /* assume reason for failure is OOM */ + ereport(ERROR, + (errcode(ERRCODE_FDW_OUT_OF_MEMORY), + errmsg("out of memory"), + errdetail("could not get libpq's default connection options"))); + } + /* first gather the server connstr options */ srvname = pstrdup(servername); truncate_identifier(srvname, strlen(srvname), false); @@ -2752,16 +2784,18 @@ get_connect_string(const char *servername) { DefElem *def = lfirst(cell); - appendStringInfo(buf, "%s='%s' ", def->defname, - escape_param_str(strVal(def->arg))); + if (is_valid_dblink_option(options, def->defname, ForeignDataWrapperRelationId)) + appendStringInfo(buf, "%s='%s' ", def->defname, + escape_param_str(strVal(def->arg))); } foreach(cell, foreign_server->options) { DefElem *def = lfirst(cell); - appendStringInfo(buf, "%s='%s' ", def->defname, - escape_param_str(strVal(def->arg))); + if (is_valid_dblink_option(options, def->defname, ForeignServerRelationId)) + appendStringInfo(buf, "%s='%s' ", def->defname, + escape_param_str(strVal(def->arg))); } foreach(cell, user_mapping->options) @@ -2769,8 +2803,9 @@ get_connect_string(const char *servername) DefElem *def = lfirst(cell); - appendStringInfo(buf, "%s='%s' ", def->defname, - escape_param_str(strVal(def->arg))); + if (is_valid_dblink_option(options, def->defname, UserMappingRelationId)) + appendStringInfo(buf, "%s='%s' ", def->defname, + escape_param_str(strVal(def->arg))); } return buf->data; diff --git a/contrib/dblink/dblink.h b/contrib/dblink/dblink.h index 1b94912152..c96dbe28a8 100644 --- a/contrib/dblink/dblink.h +++ b/contrib/dblink/dblink.h @@ -9,7 +9,7 @@ * Shridhar Daithankar * * contrib/dblink/dblink.h - * Copyright (c) 2001-2016, PostgreSQL Global Development Group + * Copyright (c) 2001-2017, PostgreSQL Global Development Group * ALL RIGHTS RESERVED; * * Permission to use, copy, modify, and distribute this software and its @@ -36,28 +36,4 @@ #include "fmgr.h" -/* - * External declarations - */ -extern Datum dblink_connect(PG_FUNCTION_ARGS); -extern Datum dblink_disconnect(PG_FUNCTION_ARGS); -extern Datum dblink_open(PG_FUNCTION_ARGS); -extern Datum dblink_close(PG_FUNCTION_ARGS); -extern Datum dblink_fetch(PG_FUNCTION_ARGS); -extern Datum dblink_record(PG_FUNCTION_ARGS); -extern Datum dblink_send_query(PG_FUNCTION_ARGS); -extern Datum dblink_get_result(PG_FUNCTION_ARGS); -extern Datum dblink_get_connections(PG_FUNCTION_ARGS); -extern Datum dblink_is_busy(PG_FUNCTION_ARGS); -extern Datum dblink_cancel_query(PG_FUNCTION_ARGS); -extern Datum dblink_error_message(PG_FUNCTION_ARGS); -extern Datum dblink_exec(PG_FUNCTION_ARGS); -extern Datum dblink_get_pkey(PG_FUNCTION_ARGS); -extern Datum dblink_build_sql_insert(PG_FUNCTION_ARGS); -extern Datum dblink_build_sql_delete(PG_FUNCTION_ARGS); -extern Datum dblink_build_sql_update(PG_FUNCTION_ARGS); -extern Datum dblink_current_query(PG_FUNCTION_ARGS); -extern Datum dblink_get_notify(PG_FUNCTION_ARGS); -extern Datum dblink_fdw_validator(PG_FUNCTION_ARGS); - #endif /* DBLINK_H */ diff --git a/contrib/dict_int/dict_int.c b/contrib/dict_int/dict_int.c index 935dbd4c82..55427c4bc7 100644 --- a/contrib/dict_int/dict_int.c +++ b/contrib/dict_int/dict_int.c @@ -3,7 +3,7 @@ * dict_int.c * Text search dictionary for integers * - * Copyright (c) 2007-2016, PostgreSQL Global Development Group + * Copyright (c) 2007-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/dict_int/dict_int.c diff --git a/contrib/dict_xsyn/dict_xsyn.c b/contrib/dict_xsyn/dict_xsyn.c index 63b0383ccc..fcf541ee0f 100644 --- a/contrib/dict_xsyn/dict_xsyn.c +++ b/contrib/dict_xsyn/dict_xsyn.c @@ -3,7 +3,7 @@ * dict_xsyn.c * Extended synonym dictionary * - * Copyright (c) 2007-2016, PostgreSQL Global Development Group + * Copyright (c) 2007-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/dict_xsyn/dict_xsyn.c diff --git a/contrib/earthdistance/expected/earthdistance.out b/contrib/earthdistance/expected/earthdistance.out index e9daa8488e..89022491cb 100644 --- a/contrib/earthdistance/expected/earthdistance.out +++ b/contrib/earthdistance/expected/earthdistance.out @@ -1049,10 +1049,10 @@ HINT: Use DROP ... CASCADE to drop the dependent objects too. drop extension cube cascade; NOTICE: drop cascades to table foo column f1 \d foo - Table "public.foo" - Column | Type | Modifiers ---------+---------+----------- - f2 | integer | + Table "public.foo" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + f2 | integer | | | -- list what's installed \dT public.* diff --git a/contrib/file_fdw/file_fdw.c b/contrib/file_fdw/file_fdw.c index c0491318c0..735b79484c 100644 --- a/contrib/file_fdw/file_fdw.c +++ b/contrib/file_fdw/file_fdw.c @@ -1,9 +1,9 @@ /*------------------------------------------------------------------------- * * file_fdw.c - * foreign-data wrapper for server-side flat files. + * foreign-data wrapper for server-side flat files (or programs). * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/file_fdw/file_fdw.c @@ -57,8 +57,9 @@ struct FileFdwOption * fileGetOptions(), which currently doesn't bother to look at user mappings. */ static const struct FileFdwOption valid_options[] = { - /* File options */ + /* Data source options */ {"filename", ForeignTableRelationId}, + {"program", ForeignTableRelationId}, /* Format options */ /* oids option is not supported */ @@ -85,10 +86,12 @@ static const struct FileFdwOption valid_options[] = { */ typedef struct FileFdwPlanState { - char *filename; /* file to read */ - List *options; /* merged COPY options, excluding filename */ + char *filename; /* file or program to read from */ + bool is_program; /* true if filename represents an OS command */ + List *options; /* merged COPY options, excluding filename and + * is_program */ BlockNumber pages; /* estimate of file's physical size */ - double ntuples; /* estimate of number of rows in file */ + double ntuples; /* estimate of number of data rows */ } FileFdwPlanState; /* @@ -96,9 +99,11 @@ typedef struct FileFdwPlanState */ typedef struct FileFdwExecutionState { - char *filename; /* file to read */ - List *options; /* merged COPY options, excluding filename */ - CopyState cstate; /* state of reading file */ + char *filename; /* file or program to read from */ + bool is_program; /* true if filename represents an OS command */ + List *options; /* merged COPY options, excluding filename and + * is_program */ + CopyState cstate; /* COPY execution state */ } FileFdwExecutionState; /* @@ -139,7 +144,9 @@ static bool fileIsForeignScanParallelSafe(PlannerInfo *root, RelOptInfo *rel, */ static bool is_valid_option(const char *option, Oid context); static void fileGetOptions(Oid foreigntableid, - char **filename, List **other_options); + char **filename, + bool *is_program, + List **other_options); static List *get_file_fdw_attribute_options(Oid relid); static bool check_selective_binary_conversion(RelOptInfo *baserel, Oid foreigntableid, @@ -196,16 +203,16 @@ file_fdw_validator(PG_FUNCTION_ARGS) /* * Only superusers are allowed to set options of a file_fdw foreign table. - * This is because the filename is one of those options, and we don't want - * non-superusers to be able to determine which file gets read. + * This is because we don't want non-superusers to be able to control + * which file gets read or which program gets executed. * * Putting this sort of permissions check in a validator is a bit of a * crock, but there doesn't seem to be any other place that can enforce * the check more cleanly. * - * Note that the valid_options[] array disallows setting filename at any - * options level other than foreign table --- otherwise there'd still be a - * security hole. + * Note that the valid_options[] array disallows setting filename and + * program at any options level other than foreign table --- otherwise + * there'd still be a security hole. */ if (catalog == ForeignTableRelationId && !superuser()) ereport(ERROR, @@ -247,11 +254,11 @@ file_fdw_validator(PG_FUNCTION_ARGS) } /* - * Separate out filename and column-specific options, since + * Separate out filename, program, and column-specific options, since * ProcessCopyOptions won't accept them. */ - - if (strcmp(def->defname, "filename") == 0) + if (strcmp(def->defname, "filename") == 0 || + strcmp(def->defname, "program") == 0) { if (filename) ereport(ERROR, @@ -293,15 +300,16 @@ file_fdw_validator(PG_FUNCTION_ARGS) /* * Now apply the core COPY code's validation logic for more checks. */ - ProcessCopyOptions(NULL, true, other_options); + ProcessCopyOptions(NULL, NULL, true, other_options); /* - * Filename option is required for file_fdw foreign tables. + * Either filename or program option is required for file_fdw foreign + * tables. */ if (catalog == ForeignTableRelationId && filename == NULL) ereport(ERROR, (errcode(ERRCODE_FDW_DYNAMIC_PARAMETER_VALUE_NEEDED), - errmsg("filename is required for file_fdw foreign tables"))); + errmsg("either filename or program is required for file_fdw foreign tables"))); PG_RETURN_VOID(); } @@ -326,12 +334,12 @@ is_valid_option(const char *option, Oid context) /* * Fetch the options for a file_fdw foreign table. * - * We have to separate out "filename" from the other options because - * it must not appear in the options list passed to the core COPY code. + * We have to separate out filename/program from the other options because + * those must not appear in the options list passed to the core COPY code. */ static void fileGetOptions(Oid foreigntableid, - char **filename, List **other_options) + char **filename, bool *is_program, List **other_options) { ForeignTable *table; ForeignServer *server; @@ -359,9 +367,11 @@ fileGetOptions(Oid foreigntableid, options = list_concat(options, get_file_fdw_attribute_options(foreigntableid)); /* - * Separate out the filename. + * Separate out the filename or program option (we assume there is only + * one). */ *filename = NULL; + *is_program = false; prev = NULL; foreach(lc, options) { @@ -373,15 +383,22 @@ fileGetOptions(Oid foreigntableid, options = list_delete_cell(options, lc, prev); break; } + else if (strcmp(def->defname, "program") == 0) + { + *filename = defGetString(def); + *is_program = true; + options = list_delete_cell(options, lc, prev); + break; + } prev = lc; } /* - * The validator should have checked that a filename was included in the - * options, but check again, just in case. + * The validator should have checked that filename or program was included + * in the options, but check again, just in case. */ if (*filename == NULL) - elog(ERROR, "filename is required for file_fdw foreign tables"); + elog(ERROR, "either filename or program is required for file_fdw foreign tables"); *other_options = options; } @@ -455,10 +472,10 @@ get_file_fdw_attribute_options(Oid relid) * force_null options set */ if (fnncolumns != NIL) - options = lappend(options, makeDefElem("force_not_null", (Node *) fnncolumns)); + options = lappend(options, makeDefElem("force_not_null", (Node *) fnncolumns, -1)); if (fncolumns != NIL) - options = lappend(options, makeDefElem("force_null", (Node *) fncolumns)); + options = lappend(options, makeDefElem("force_null", (Node *) fncolumns, -1)); return options; } @@ -475,12 +492,15 @@ fileGetForeignRelSize(PlannerInfo *root, FileFdwPlanState *fdw_private; /* - * Fetch options. We only need filename at this point, but we might as - * well get everything and not need to re-fetch it later in planning. + * Fetch options. We only need filename (or program) at this point, but + * we might as well get everything and not need to re-fetch it later in + * planning. */ fdw_private = (FileFdwPlanState *) palloc(sizeof(FileFdwPlanState)); fileGetOptions(foreigntableid, - &fdw_private->filename, &fdw_private->options); + &fdw_private->filename, + &fdw_private->is_program, + &fdw_private->options); baserel->fdw_private = (void *) fdw_private; /* Estimate relation size */ @@ -511,7 +531,7 @@ fileGetForeignPaths(PlannerInfo *root, foreigntableid, &columns)) coptions = list_make1(makeDefElem("convert_selectively", - (Node *) columns)); + (Node *) columns, -1)); /* Estimate costs */ estimate_costs(root, baserel, fdw_private, @@ -583,20 +603,25 @@ static void fileExplainForeignScan(ForeignScanState *node, ExplainState *es) { char *filename; + bool is_program; List *options; - /* Fetch options --- we only need filename at this point */ + /* Fetch options --- we only need filename and is_program at this point */ fileGetOptions(RelationGetRelid(node->ss.ss_currentRelation), - &filename, &options); + &filename, &is_program, &options); - ExplainPropertyText("Foreign File", filename, es); + if (is_program) + ExplainPropertyText("Foreign Program", filename, es); + else + ExplainPropertyText("Foreign File", filename, es); /* Suppress file size if we're not showing cost details */ if (es->costs) { struct stat stat_buf; - if (stat(filename, &stat_buf) == 0) + if (!is_program && + stat(filename, &stat_buf) == 0) ExplainPropertyLong("Foreign File Size", (long) stat_buf.st_size, es); } @@ -611,6 +636,7 @@ fileBeginForeignScan(ForeignScanState *node, int eflags) { ForeignScan *plan = (ForeignScan *) node->ss.ps.plan; char *filename; + bool is_program; List *options; CopyState cstate; FileFdwExecutionState *festate; @@ -623,7 +649,7 @@ fileBeginForeignScan(ForeignScanState *node, int eflags) /* Fetch options of foreign table */ fileGetOptions(RelationGetRelid(node->ss.ss_currentRelation), - &filename, &options); + &filename, &is_program, &options); /* Add any options from the plan (currently only convert_selectively) */ options = list_concat(options, plan->fdw_private); @@ -632,9 +658,10 @@ fileBeginForeignScan(ForeignScanState *node, int eflags) * Create CopyState from FDW options. We always acquire all columns, so * as to match the expected ScanTupleSlot signature. */ - cstate = BeginCopyFrom(node->ss.ss_currentRelation, + cstate = BeginCopyFrom(NULL, + node->ss.ss_currentRelation, filename, - false, + is_program, NIL, options); @@ -644,6 +671,7 @@ fileBeginForeignScan(ForeignScanState *node, int eflags) */ festate = (FileFdwExecutionState *) palloc(sizeof(FileFdwExecutionState)); festate->filename = filename; + festate->is_program = is_program; festate->options = options; festate->cstate = cstate; @@ -705,9 +733,10 @@ fileReScanForeignScan(ForeignScanState *node) EndCopyFrom(festate->cstate); - festate->cstate = BeginCopyFrom(node->ss.ss_currentRelation, + festate->cstate = BeginCopyFrom(NULL, + node->ss.ss_currentRelation, festate->filename, - false, + festate->is_program, NIL, festate->options); } @@ -736,11 +765,22 @@ fileAnalyzeForeignTable(Relation relation, BlockNumber *totalpages) { char *filename; + bool is_program; List *options; struct stat stat_buf; /* Fetch options of foreign table */ - fileGetOptions(RelationGetRelid(relation), &filename, &options); + fileGetOptions(RelationGetRelid(relation), &filename, &is_program, &options); + + /* + * If this is a program instead of a file, just return false to skip + * analyzing the table. We could run the program and collect stats on + * whatever it currently returns, but it seems likely that in such cases + * the output would be too volatile for the stats to be useful. Maybe + * there should be an option to enable doing this? + */ + if (is_program) + return false; /* * Get size of the file. (XXX if we fail here, would it be better to just @@ -767,8 +807,8 @@ fileAnalyzeForeignTable(Relation relation, /* * fileIsForeignScanParallelSafe - * Reading a file in a parallel worker should work just the same as - * reading it in the leader, so mark scans safe. + * Reading a file, or external program, in a parallel worker should work + * just the same as reading it in the leader, so mark scans safe. */ static bool fileIsForeignScanParallelSafe(PlannerInfo *root, RelOptInfo *rel, @@ -914,9 +954,10 @@ estimate_size(PlannerInfo *root, RelOptInfo *baserel, /* * Get size of the file. It might not be there at plan time, though, in - * which case we have to use a default estimate. + * which case we have to use a default estimate. We also have to fall + * back to the default if using a program as the input. */ - if (stat(fdw_private->filename, &stat_buf) < 0) + if (fdw_private->is_program || stat(fdw_private->filename, &stat_buf) < 0) stat_buf.st_size = 10 * BLCKSZ; /* @@ -998,6 +1039,11 @@ estimate_costs(PlannerInfo *root, RelOptInfo *baserel, * that I/O costs are equivalent to a regular table file of the same size. * However, we take per-tuple CPU costs as 10x of a seqscan, to account * for the cost of parsing records. + * + * In the case of a program source, this calculation is even more divorced + * from reality, but we have no good alternative; and it's not clear that + * the numbers we produce here matter much anyway, since there's only one + * access path for the rel. */ run_cost += seq_page_cost * pages; @@ -1034,6 +1080,7 @@ file_acquire_sample_rows(Relation onerel, int elevel, bool *nulls; bool found; char *filename; + bool is_program; List *options; CopyState cstate; ErrorContextCallback errcallback; @@ -1048,12 +1095,12 @@ file_acquire_sample_rows(Relation onerel, int elevel, nulls = (bool *) palloc(tupDesc->natts * sizeof(bool)); /* Fetch options of foreign table */ - fileGetOptions(RelationGetRelid(onerel), &filename, &options); + fileGetOptions(RelationGetRelid(onerel), &filename, &is_program, &options); /* * Create CopyState from FDW options. */ - cstate = BeginCopyFrom(onerel, filename, false, NIL, options); + cstate = BeginCopyFrom(NULL, onerel, filename, is_program, NIL, options); /* * Use per-tuple memory context to prevent leak of memory used to read @@ -1061,9 +1108,7 @@ file_acquire_sample_rows(Relation onerel, int elevel, */ tupcontext = AllocSetContextCreate(CurrentMemoryContext, "file_fdw temporary context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* Prepare for sampling rows */ reservoir_init_selection_state(&rstate, targrows); diff --git a/contrib/file_fdw/output/file_fdw.source b/contrib/file_fdw/output/file_fdw.source index 6fa54409b9..01e2690a82 100644 --- a/contrib/file_fdw/output/file_fdw.source +++ b/contrib/file_fdw/output/file_fdw.source @@ -76,7 +76,7 @@ CREATE FOREIGN TABLE tbl () SERVER file_server OPTIONS (format 'csv', null ' '); -- ERROR ERROR: COPY null representation cannot use newline or carriage return CREATE FOREIGN TABLE tbl () SERVER file_server; -- ERROR -ERROR: filename is required for file_fdw foreign tables +ERROR: either filename or program is required for file_fdw foreign tables CREATE FOREIGN TABLE agg_text ( a int2 CHECK (a >= 0), b float4 @@ -132,7 +132,7 @@ ERROR: invalid option "force_not_null" HINT: There are no valid options in this context. CREATE FOREIGN TABLE tbl () SERVER file_server OPTIONS (force_not_null '*'); -- ERROR ERROR: invalid option "force_not_null" -HINT: Valid options in this context are: filename, format, header, delimiter, quote, escape, null, encoding +HINT: Valid options in this context are: filename, program, format, header, delimiter, quote, escape, null, encoding -- force_null is not allowed to be specified at any foreign object level: ALTER FOREIGN DATA WRAPPER file_fdw OPTIONS (ADD force_null '*'); -- ERROR ERROR: invalid option "force_null" @@ -145,7 +145,7 @@ ERROR: invalid option "force_null" HINT: There are no valid options in this context. CREATE FOREIGN TABLE tbl () SERVER file_server OPTIONS (force_null '*'); -- ERROR ERROR: invalid option "force_null" -HINT: Valid options in this context are: filename, format, header, delimiter, quote, escape, null, encoding +HINT: Valid options in this context are: filename, program, format, header, delimiter, quote, escape, null, encoding -- basic query tests SELECT * FROM agg_text WHERE b > 10.0 ORDER BY a; a | b diff --git a/contrib/fuzzystrmatch/fuzzystrmatch.c b/contrib/fuzzystrmatch/fuzzystrmatch.c index cbac1f2381..bd36fc57dc 100644 --- a/contrib/fuzzystrmatch/fuzzystrmatch.c +++ b/contrib/fuzzystrmatch/fuzzystrmatch.c @@ -6,7 +6,7 @@ * Joe Conway * * contrib/fuzzystrmatch/fuzzystrmatch.c - * Copyright (c) 2001-2016, PostgreSQL Global Development Group + * Copyright (c) 2001-2017, PostgreSQL Global Development Group * ALL RIGHTS RESERVED; * * metaphone() @@ -42,6 +42,7 @@ #include "mb/pg_wchar.h" #include "utils/builtins.h" +#include "utils/varlena.h" PG_MODULE_MAGIC; diff --git a/contrib/hstore/expected/hstore.out b/contrib/hstore/expected/hstore.out index 6773a2b72f..f0d421602d 100644 --- a/contrib/hstore/expected/hstore.out +++ b/contrib/hstore/expected/hstore.out @@ -1,4 +1,12 @@ CREATE EXTENSION hstore; +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + amname | opcname +--------+--------- +(0 rows) + set escape_string_warning=off; --hstore; select ''::hstore; diff --git a/contrib/hstore/sql/hstore.sql b/contrib/hstore/sql/hstore.sql index 48514789e6..d64b9f77c7 100644 --- a/contrib/hstore/sql/hstore.sql +++ b/contrib/hstore/sql/hstore.sql @@ -1,5 +1,10 @@ CREATE EXTENSION hstore; +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + set escape_string_warning=off; --hstore; diff --git a/contrib/hstore_plperl/Makefile b/contrib/hstore_plperl/Makefile index b3b8654bc8..41d34357f9 100644 --- a/contrib/hstore_plperl/Makefile +++ b/contrib/hstore_plperl/Makefile @@ -23,20 +23,20 @@ include $(top_builddir)/src/Makefile.global include $(top_srcdir)/contrib/contrib-global.mk endif -# In configurations that forbid undefined symbols in libraries, link with each -# dependency. This does preclude pgxs builds. +# We must link libperl explicitly ifeq ($(PORTNAME), aix) rpathdir = $(pkglibdir):$(perl_archlibexp)/CORE -SHLIB_LINK += ../hstore/libhstore.exp $(perl_embed_ldflags) -endif +SHLIB_LINK += $(perl_embed_ldflags) +else ifeq ($(PORTNAME), win32) # these settings are the same as for plperl override CPPFLAGS += -DPLPERL_HAVE_UID_GID -Wno-comment -SHLIB_LINK += ../hstore/libhstore.a $(sort $(wildcard ../../src/pl/plperl/libperl*.a)) +# ... see silliness in plperl Makefile ... +SHLIB_LINK += $(sort $(wildcard ../../src/pl/plperl/libperl*.a)) +else +rpathdir = $(perl_archlibexp)/CORE +SHLIB_LINK += $(perl_embed_ldflags) endif - -ifeq ($(PORTNAME), cygwin) -SHLIB_LINK += -L../hstore -l hstore $(perl_embed_ldflags) endif # As with plperl we need to make sure that the CORE directory is included diff --git a/contrib/hstore_plperl/expected/create_transform.out b/contrib/hstore_plperl/expected/create_transform.out index c588d33ab8..02dc62af0d 100644 --- a/contrib/hstore_plperl/expected/create_transform.out +++ b/contrib/hstore_plperl/expected/create_transform.out @@ -18,9 +18,9 @@ ERROR: type "foo" does not exist CREATE TRANSFORM FOR hstore LANGUAGE foo (FROM SQL WITH FUNCTION hstore_to_plperl(internal), TO SQL WITH FUNCTION plperl_to_hstore(internal)); -- fail ERROR: language "foo" does not exist CREATE TRANSFORM FOR hstore LANGUAGE plperl (FROM SQL WITH FUNCTION hstore_out(hstore), TO SQL WITH FUNCTION plperl_to_hstore(internal)); -- fail -ERROR: return data type of FROM SQL function must be "internal" +ERROR: return data type of FROM SQL function must be internal CREATE TRANSFORM FOR hstore LANGUAGE plperl (FROM SQL WITH FUNCTION internal_in(cstring), TO SQL WITH FUNCTION plperl_to_hstore(internal)); -- fail -ERROR: first argument of transform function must be type "internal" +ERROR: first argument of transform function must be type internal CREATE TRANSFORM FOR hstore LANGUAGE plperl (FROM SQL WITH FUNCTION hstore_to_plperl(internal), TO SQL WITH FUNCTION plperl_to_hstore(internal)); -- ok CREATE TRANSFORM FOR hstore LANGUAGE plperl (FROM SQL WITH FUNCTION hstore_to_plperl(internal), TO SQL WITH FUNCTION plperl_to_hstore(internal)); -- fail ERROR: transform for type hstore language "plperl" already exists diff --git a/contrib/hstore_plperl/hstore_plperl--1.0.sql b/contrib/hstore_plperl/hstore_plperl--1.0.sql index 9a64fcb18b..af743c8733 100644 --- a/contrib/hstore_plperl/hstore_plperl--1.0.sql +++ b/contrib/hstore_plperl/hstore_plperl--1.0.sql @@ -3,11 +3,6 @@ -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION hstore_plperl" to load this file. \quit --- make sure the prerequisite libraries are loaded -LOAD 'plperl'; -SELECT NULL::hstore; - - CREATE FUNCTION hstore_to_plperl(val internal) RETURNS internal LANGUAGE C STRICT IMMUTABLE AS 'MODULE_PATHNAME'; diff --git a/contrib/hstore_plperl/hstore_plperl.c b/contrib/hstore_plperl/hstore_plperl.c index d40a792730..480212f341 100644 --- a/contrib/hstore_plperl/hstore_plperl.c +++ b/contrib/hstore_plperl/hstore_plperl.c @@ -1,5 +1,7 @@ #include "postgres.h" + #undef _ + #include "fmgr.h" #include "plperl.h" #include "plperl_helpers.h" @@ -7,6 +9,58 @@ PG_MODULE_MAGIC; +extern void _PG_init(void); + +/* Linkage to functions in hstore module */ +typedef HStore *(*hstoreUpgrade_t) (Datum orig); +static hstoreUpgrade_t hstoreUpgrade_p; +typedef int (*hstoreUniquePairs_t) (Pairs *a, int32 l, int32 *buflen); +static hstoreUniquePairs_t hstoreUniquePairs_p; +typedef HStore *(*hstorePairs_t) (Pairs *pairs, int32 pcount, int32 buflen); +static hstorePairs_t hstorePairs_p; +typedef size_t (*hstoreCheckKeyLen_t) (size_t len); +static hstoreCheckKeyLen_t hstoreCheckKeyLen_p; +typedef size_t (*hstoreCheckValLen_t) (size_t len); +static hstoreCheckValLen_t hstoreCheckValLen_p; + + +/* + * Module initialize function: fetch function pointers for cross-module calls. + */ +void +_PG_init(void) +{ + /* Asserts verify that typedefs above match original declarations */ + AssertVariableIsOfType(&hstoreUpgrade, hstoreUpgrade_t); + hstoreUpgrade_p = (hstoreUpgrade_t) + load_external_function("$libdir/hstore", "hstoreUpgrade", + true, NULL); + AssertVariableIsOfType(&hstoreUniquePairs, hstoreUniquePairs_t); + hstoreUniquePairs_p = (hstoreUniquePairs_t) + load_external_function("$libdir/hstore", "hstoreUniquePairs", + true, NULL); + AssertVariableIsOfType(&hstorePairs, hstorePairs_t); + hstorePairs_p = (hstorePairs_t) + load_external_function("$libdir/hstore", "hstorePairs", + true, NULL); + AssertVariableIsOfType(&hstoreCheckKeyLen, hstoreCheckKeyLen_t); + hstoreCheckKeyLen_p = (hstoreCheckKeyLen_t) + load_external_function("$libdir/hstore", "hstoreCheckKeyLen", + true, NULL); + AssertVariableIsOfType(&hstoreCheckValLen, hstoreCheckValLen_t); + hstoreCheckValLen_p = (hstoreCheckValLen_t) + load_external_function("$libdir/hstore", "hstoreCheckValLen", + true, NULL); +} + + +/* These defines must be after the module init function */ +#define hstoreUpgrade hstoreUpgrade_p +#define hstoreUniquePairs hstoreUniquePairs_p +#define hstorePairs hstorePairs_p +#define hstoreCheckKeyLen hstoreCheckKeyLen_p +#define hstoreCheckValLen hstoreCheckValLen_p + PG_FUNCTION_INFO_V1(hstore_to_plperl); diff --git a/contrib/hstore_plperl/hstore_plperlu--1.0.sql b/contrib/hstore_plperl/hstore_plperlu--1.0.sql index f355284907..7c3bc86eba 100644 --- a/contrib/hstore_plperl/hstore_plperlu--1.0.sql +++ b/contrib/hstore_plperl/hstore_plperlu--1.0.sql @@ -3,11 +3,6 @@ -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION hstore_plperlu" to load this file. \quit --- make sure the prerequisite libraries are loaded -LOAD 'plperl'; -SELECT NULL::hstore; - - CREATE FUNCTION hstore_to_plperlu(val internal) RETURNS internal LANGUAGE C STRICT IMMUTABLE AS 'MODULE_PATHNAME', 'hstore_to_plperl'; diff --git a/contrib/hstore_plpython/Makefile b/contrib/hstore_plpython/Makefile index c4dad6f111..a55c9a162c 100644 --- a/contrib/hstore_plpython/Makefile +++ b/contrib/hstore_plpython/Makefile @@ -4,7 +4,7 @@ MODULE_big = hstore_plpython$(python_majorversion) OBJS = hstore_plpython.o $(WIN32RES) PGFILEDESC = "hstore_plpython - hstore transform for plpython" -PG_CPPFLAGS = -I$(top_srcdir)/src/pl/plpython $(python_includespec) -I$(top_srcdir)/contrib/hstore +PG_CPPFLAGS = -I$(top_srcdir)/src/pl/plpython $(python_includespec) -I$(top_srcdir)/contrib/hstore -DPLPYTHON_LIBNAME='"plpython$(python_majorversion)"' EXTENSION = hstore_plpythonu hstore_plpython2u hstore_plpython3u DATA = hstore_plpythonu--1.0.sql hstore_plpython2u--1.0.sql hstore_plpython3u--1.0.sql @@ -23,19 +23,18 @@ include $(top_builddir)/src/Makefile.global include $(top_srcdir)/contrib/contrib-global.mk endif -# In configurations that forbid undefined symbols in libraries, link with each -# dependency. This does preclude pgxs builds. +# We must link libpython explicitly ifeq ($(PORTNAME), aix) rpathdir = $(pkglibdir):$(python_libdir) -SHLIB_LINK += ../hstore/libhstore.exp $(python_libspec) $(python_additional_libs) $(sort $(wildcard ../../src/pl/plpython/libplpython*.exp)) -endif +SHLIB_LINK += $(python_libspec) $(python_additional_libs) +else ifeq ($(PORTNAME), win32) -SHLIB_LINK += ../hstore/libhstore.a $(sort $(wildcard ../../src/pl/plpython/libpython*.a)) $(sort $(wildcard ../../src/pl/plpython/libplpython*.a)) +# ... see silliness in plpython Makefile ... +SHLIB_LINK += $(sort $(wildcard ../../src/pl/plpython/libpython*.a)) +else +rpathdir = $(python_libdir) +SHLIB_LINK += $(python_libspec) endif - -ifeq ($(PORTNAME), cygwin) -SHLIB_LINK += -L../hstore -lhstore -L../../src/pl/plpython \ - -lplpython$(python_majorversion) $(python_libspec) endif REGRESS_OPTS += --load-extension=hstore diff --git a/contrib/hstore_plpython/hstore_plpython.c b/contrib/hstore_plpython/hstore_plpython.c index 6f2751a8df..b184324ebf 100644 --- a/contrib/hstore_plpython/hstore_plpython.c +++ b/contrib/hstore_plpython/hstore_plpython.c @@ -1,4 +1,5 @@ #include "postgres.h" + #include "fmgr.h" #include "plpython.h" #include "plpy_typeio.h" @@ -6,6 +7,78 @@ PG_MODULE_MAGIC; +extern void _PG_init(void); + +/* Linkage to functions in plpython module */ +typedef char *(*PLyObject_AsString_t) (PyObject *plrv); +static PLyObject_AsString_t PLyObject_AsString_p; +#if PY_MAJOR_VERSION >= 3 +typedef PyObject *(*PLyUnicode_FromStringAndSize_t) (const char *s, Py_ssize_t size); +static PLyUnicode_FromStringAndSize_t PLyUnicode_FromStringAndSize_p; +#endif + +/* Linkage to functions in hstore module */ +typedef HStore *(*hstoreUpgrade_t) (Datum orig); +static hstoreUpgrade_t hstoreUpgrade_p; +typedef int (*hstoreUniquePairs_t) (Pairs *a, int32 l, int32 *buflen); +static hstoreUniquePairs_t hstoreUniquePairs_p; +typedef HStore *(*hstorePairs_t) (Pairs *pairs, int32 pcount, int32 buflen); +static hstorePairs_t hstorePairs_p; +typedef size_t (*hstoreCheckKeyLen_t) (size_t len); +static hstoreCheckKeyLen_t hstoreCheckKeyLen_p; +typedef size_t (*hstoreCheckValLen_t) (size_t len); +static hstoreCheckValLen_t hstoreCheckValLen_p; + + +/* + * Module initialize function: fetch function pointers for cross-module calls. + */ +void +_PG_init(void) +{ + /* Asserts verify that typedefs above match original declarations */ + AssertVariableIsOfType(&PLyObject_AsString, PLyObject_AsString_t); + PLyObject_AsString_p = (PLyObject_AsString_t) + load_external_function("$libdir/" PLPYTHON_LIBNAME, "PLyObject_AsString", + true, NULL); +#if PY_MAJOR_VERSION >= 3 + AssertVariableIsOfType(&PLyUnicode_FromStringAndSize, PLyUnicode_FromStringAndSize_t); + PLyUnicode_FromStringAndSize_p = (PLyUnicode_FromStringAndSize_t) + load_external_function("$libdir/" PLPYTHON_LIBNAME, "PLyUnicode_FromStringAndSize", + true, NULL); +#endif + AssertVariableIsOfType(&hstoreUpgrade, hstoreUpgrade_t); + hstoreUpgrade_p = (hstoreUpgrade_t) + load_external_function("$libdir/hstore", "hstoreUpgrade", + true, NULL); + AssertVariableIsOfType(&hstoreUniquePairs, hstoreUniquePairs_t); + hstoreUniquePairs_p = (hstoreUniquePairs_t) + load_external_function("$libdir/hstore", "hstoreUniquePairs", + true, NULL); + AssertVariableIsOfType(&hstorePairs, hstorePairs_t); + hstorePairs_p = (hstorePairs_t) + load_external_function("$libdir/hstore", "hstorePairs", + true, NULL); + AssertVariableIsOfType(&hstoreCheckKeyLen, hstoreCheckKeyLen_t); + hstoreCheckKeyLen_p = (hstoreCheckKeyLen_t) + load_external_function("$libdir/hstore", "hstoreCheckKeyLen", + true, NULL); + AssertVariableIsOfType(&hstoreCheckValLen, hstoreCheckValLen_t); + hstoreCheckValLen_p = (hstoreCheckValLen_t) + load_external_function("$libdir/hstore", "hstoreCheckValLen", + true, NULL); +} + + +/* These defines must be after the module init function */ +#define PLyObject_AsString PLyObject_AsString_p +#define PLyUnicode_FromStringAndSize PLyUnicode_FromStringAndSize_p +#define hstoreUpgrade hstoreUpgrade_p +#define hstoreUniquePairs hstoreUniquePairs_p +#define hstorePairs hstorePairs_p +#define hstoreCheckKeyLen hstoreCheckKeyLen_p +#define hstoreCheckValLen hstoreCheckValLen_p + PG_FUNCTION_INFO_V1(hstore_to_plpython); diff --git a/contrib/hstore_plpython/hstore_plpython2u--1.0.sql b/contrib/hstore_plpython/hstore_plpython2u--1.0.sql index e3aea6399e..800765f3f0 100644 --- a/contrib/hstore_plpython/hstore_plpython2u--1.0.sql +++ b/contrib/hstore_plpython/hstore_plpython2u--1.0.sql @@ -3,11 +3,6 @@ -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION hstore_plpython2u" to load this file. \quit --- make sure the prerequisite libraries are loaded -LOAD 'plpython2'; -SELECT NULL::hstore; - - CREATE FUNCTION hstore_to_plpython2(val internal) RETURNS internal LANGUAGE C STRICT IMMUTABLE AS 'MODULE_PATHNAME', 'hstore_to_plpython'; diff --git a/contrib/hstore_plpython/hstore_plpython3u--1.0.sql b/contrib/hstore_plpython/hstore_plpython3u--1.0.sql index a964a49059..0b410ab183 100644 --- a/contrib/hstore_plpython/hstore_plpython3u--1.0.sql +++ b/contrib/hstore_plpython/hstore_plpython3u--1.0.sql @@ -3,11 +3,6 @@ -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION hstore_plpython3u" to load this file. \quit --- make sure the prerequisite libraries are loaded -LOAD 'plpython3'; -SELECT NULL::hstore; - - CREATE FUNCTION hstore_to_plpython3(val internal) RETURNS internal LANGUAGE C STRICT IMMUTABLE AS 'MODULE_PATHNAME', 'hstore_to_plpython'; diff --git a/contrib/hstore_plpython/hstore_plpythonu--1.0.sql b/contrib/hstore_plpython/hstore_plpythonu--1.0.sql index d79bdc96d9..52832912ab 100644 --- a/contrib/hstore_plpython/hstore_plpythonu--1.0.sql +++ b/contrib/hstore_plpython/hstore_plpythonu--1.0.sql @@ -3,11 +3,6 @@ -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION hstore_plpythonu" to load this file. \quit --- make sure the prerequisite libraries are loaded -LOAD 'plpython2'; -- change to plpython3 if that ever becomes the default -SELECT NULL::hstore; - - CREATE FUNCTION hstore_to_plpython(val internal) RETURNS internal LANGUAGE C STRICT IMMUTABLE AS 'MODULE_PATHNAME'; diff --git a/contrib/intarray/_int_selfuncs.c b/contrib/intarray/_int_selfuncs.c index 3dad7eeb7d..9b4a22fe34 100644 --- a/contrib/intarray/_int_selfuncs.c +++ b/contrib/intarray/_int_selfuncs.c @@ -3,7 +3,7 @@ * _int_selfuncs.c * Functions for selectivity estimation of intarray operators * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -19,6 +19,7 @@ #include "catalog/pg_operator.h" #include "catalog/pg_statistic.h" #include "catalog/pg_type.h" +#include "utils/builtins.h" #include "utils/selfuncs.h" #include "utils/syscache.h" #include "utils/lsyscache.h" @@ -32,14 +33,6 @@ PG_FUNCTION_INFO_V1(_int_contains_joinsel); PG_FUNCTION_INFO_V1(_int_contained_joinsel); PG_FUNCTION_INFO_V1(_int_matchsel); -Datum _int_overlap_sel(PG_FUNCTION_ARGS); -Datum _int_contains_sel(PG_FUNCTION_ARGS); -Datum _int_contained_sel(PG_FUNCTION_ARGS); -Datum _int_overlap_joinsel(PG_FUNCTION_ARGS); -Datum _int_contains_joinsel(PG_FUNCTION_ARGS); -Datum _int_contained_joinsel(PG_FUNCTION_ARGS); -Datum _int_matchsel(PG_FUNCTION_ARGS); - static Selectivity int_query_opr_selec(ITEM *item, Datum *values, float4 *freqs, int nmncelems, float4 minfreq); diff --git a/contrib/intarray/bench/bench.pl b/contrib/intarray/bench/bench.pl index 8746291114..395d61655f 100755 --- a/contrib/intarray/bench/bench.pl +++ b/contrib/intarray/bench/bench.pl @@ -92,7 +92,8 @@ if ($opt{e}) { - $dbi->do("explain $sql"); + my @plan = map { "$_->[0]\n" } @{$dbi->selectall_arrayref("explain $sql")}; + print @plan; } my $t0 = [gettimeofday]; diff --git a/contrib/intarray/expected/_int.out b/contrib/intarray/expected/_int.out index 962e5c6a4b..0a5dd463ac 100644 --- a/contrib/intarray/expected/_int.out +++ b/contrib/intarray/expected/_int.out @@ -1,4 +1,12 @@ CREATE EXTENSION intarray; +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + amname | opcname +--------+--------- +(0 rows) + SELECT intset(1234); intset -------- diff --git a/contrib/intarray/sql/_int.sql b/contrib/intarray/sql/_int.sql index f6fe2de55c..44e1a729b4 100644 --- a/contrib/intarray/sql/_int.sql +++ b/contrib/intarray/sql/_int.sql @@ -1,5 +1,10 @@ CREATE EXTENSION intarray; +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + SELECT intset(1234); SELECT icount('{1234234,234234}'); SELECT sort('{1234234,-30,234234}'); diff --git a/contrib/isn/expected/isn.out b/contrib/isn/expected/isn.out index 140bc86656..ef9d3a61e7 100644 --- a/contrib/isn/expected/isn.out +++ b/contrib/isn/expected/isn.out @@ -2,6 +2,50 @@ -- Test ISN extension -- CREATE EXTENSION isn; +-- Check whether any of our opclasses fail amvalidate +-- ... they will, because of missing cross-type operators +SELECT amname, opcname +FROM (SELECT amname, opcname, opc.oid + FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod + WHERE opc.oid >= 16384 + ORDER BY 1, 2 OFFSET 0) ss +WHERE NOT amvalidate(oid); +INFO: btree operator family "isn_ops" is missing cross-type operator(s) +INFO: btree operator family "isn_ops" is missing cross-type operator(s) +INFO: btree operator family "isn_ops" is missing cross-type operator(s) +INFO: btree operator family "isn_ops" is missing cross-type operator(s) +INFO: btree operator family "isn_ops" is missing cross-type operator(s) +INFO: btree operator family "isn_ops" is missing cross-type operator(s) +INFO: btree operator family "isn_ops" is missing cross-type operator(s) +INFO: btree operator family "isn_ops" is missing cross-type operator(s) +INFO: hash operator family "isn_ops" is missing cross-type operator(s) +INFO: hash operator family "isn_ops" is missing cross-type operator(s) +INFO: hash operator family "isn_ops" is missing cross-type operator(s) +INFO: hash operator family "isn_ops" is missing cross-type operator(s) +INFO: hash operator family "isn_ops" is missing cross-type operator(s) +INFO: hash operator family "isn_ops" is missing cross-type operator(s) +INFO: hash operator family "isn_ops" is missing cross-type operator(s) +INFO: hash operator family "isn_ops" is missing cross-type operator(s) + amname | opcname +--------+------------ + btree | ean13_ops + btree | isbn13_ops + btree | isbn_ops + btree | ismn13_ops + btree | ismn_ops + btree | issn13_ops + btree | issn_ops + btree | upc_ops + hash | ean13_ops + hash | isbn13_ops + hash | isbn_ops + hash | ismn13_ops + hash | ismn_ops + hash | issn13_ops + hash | issn_ops + hash | upc_ops +(16 rows) + -- -- test valid conversions -- diff --git a/contrib/isn/isn.c b/contrib/isn/isn.c index c622a4ef07..9e125b83d7 100644 --- a/contrib/isn/isn.c +++ b/contrib/isn/isn.c @@ -4,7 +4,7 @@ * PostgreSQL type definitions for ISNs (ISBN, ISMN, ISSN, EAN13, UPC) * * Author: German Mendez Bravo (Kronuz) - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/isn/isn.c diff --git a/contrib/isn/isn.h b/contrib/isn/isn.h index d8291c2b06..09dc7c6575 100644 --- a/contrib/isn/isn.h +++ b/contrib/isn/isn.h @@ -4,7 +4,7 @@ * PostgreSQL type definitions for ISNs (ISBN, ISMN, ISSN, EAN13, UPC) * * Author: German Mendez Bravo (Kronuz) - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/isn/isn.h @@ -30,25 +30,6 @@ typedef uint64 ean13; #define PG_GETARG_EAN13(n) PG_GETARG_INT64(n) #define PG_RETURN_EAN13(x) PG_RETURN_INT64(x) -extern Datum isn_out(PG_FUNCTION_ARGS); -extern Datum ean13_out(PG_FUNCTION_ARGS); -extern Datum ean13_in(PG_FUNCTION_ARGS); -extern Datum isbn_in(PG_FUNCTION_ARGS); -extern Datum ismn_in(PG_FUNCTION_ARGS); -extern Datum issn_in(PG_FUNCTION_ARGS); -extern Datum upc_in(PG_FUNCTION_ARGS); - -extern Datum isbn_cast_from_ean13(PG_FUNCTION_ARGS); -extern Datum ismn_cast_from_ean13(PG_FUNCTION_ARGS); -extern Datum issn_cast_from_ean13(PG_FUNCTION_ARGS); -extern Datum upc_cast_from_ean13(PG_FUNCTION_ARGS); - -extern Datum is_valid(PG_FUNCTION_ARGS); -extern Datum make_valid(PG_FUNCTION_ARGS); - -extern Datum accept_weak_input(PG_FUNCTION_ARGS); -extern Datum weak_input_status(PG_FUNCTION_ARGS); - extern void initialize(void); #endif /* ISN_H */ diff --git a/contrib/isn/sql/isn.sql b/contrib/isn/sql/isn.sql index 5ef6d8aa3b..71577d5590 100644 --- a/contrib/isn/sql/isn.sql +++ b/contrib/isn/sql/isn.sql @@ -4,6 +4,15 @@ CREATE EXTENSION isn; +-- Check whether any of our opclasses fail amvalidate +-- ... they will, because of missing cross-type operators +SELECT amname, opcname +FROM (SELECT amname, opcname, opc.oid + FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod + WHERE opc.oid >= 16384 + ORDER BY 1, 2 OFFSET 0) ss +WHERE NOT amvalidate(oid); + -- -- test valid conversions -- diff --git a/contrib/lo/lo.c b/contrib/lo/lo.c index 953659305f..050bd8a72a 100644 --- a/contrib/lo/lo.c +++ b/contrib/lo/lo.c @@ -9,7 +9,7 @@ #include "commands/trigger.h" #include "executor/spi.h" -#include "libpq/be-fsstubs.h" +#include "utils/builtins.h" #include "utils/rel.h" PG_MODULE_MAGIC; @@ -82,7 +82,7 @@ lo_manage(PG_FUNCTION_ARGS) char *newv = SPI_getvalue(newtuple, tupdesc, attnum); if (orig != NULL && (newv == NULL || strcmp(orig, newv) != 0)) - DirectFunctionCall1(lo_unlink, + DirectFunctionCall1(be_lo_unlink, ObjectIdGetDatum(atooid(orig))); if (newv) @@ -102,7 +102,7 @@ lo_manage(PG_FUNCTION_ARGS) if (orig != NULL) { - DirectFunctionCall1(lo_unlink, + DirectFunctionCall1(be_lo_unlink, ObjectIdGetDatum(atooid(orig))); pfree(orig); diff --git a/contrib/ltree/expected/ltree.out b/contrib/ltree/expected/ltree.out index da6e39a785..db52069c26 100644 --- a/contrib/ltree/expected/ltree.out +++ b/contrib/ltree/expected/ltree.out @@ -1,4 +1,12 @@ CREATE EXTENSION ltree; +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + amname | opcname +--------+--------- +(0 rows) + SELECT ''::ltree; ltree ------- diff --git a/contrib/ltree/sql/ltree.sql b/contrib/ltree/sql/ltree.sql index 46cfa41a41..b4f62e3feb 100644 --- a/contrib/ltree/sql/ltree.sql +++ b/contrib/ltree/sql/ltree.sql @@ -1,5 +1,10 @@ CREATE EXTENSION ltree; +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + SELECT ''::ltree; SELECT '1'::ltree; SELECT '1.2'::ltree; diff --git a/contrib/ltree_plpython/Makefile b/contrib/ltree_plpython/Makefile index 08186f19a1..c45b7c2b09 100644 --- a/contrib/ltree_plpython/Makefile +++ b/contrib/ltree_plpython/Makefile @@ -4,7 +4,7 @@ MODULE_big = ltree_plpython$(python_majorversion) OBJS = ltree_plpython.o $(WIN32RES) PGFILEDESC = "ltree_plpython - ltree transform for plpython" -PG_CPPFLAGS = -I$(top_srcdir)/src/pl/plpython $(python_includespec) -I$(top_srcdir)/contrib/ltree +PG_CPPFLAGS = -I$(top_srcdir)/src/pl/plpython $(python_includespec) -I$(top_srcdir)/contrib/ltree -DPLPYTHON_LIBNAME='"plpython$(python_majorversion)"' EXTENSION = ltree_plpythonu ltree_plpython2u ltree_plpython3u DATA = ltree_plpythonu--1.0.sql ltree_plpython2u--1.0.sql ltree_plpython3u--1.0.sql @@ -23,19 +23,18 @@ include $(top_builddir)/src/Makefile.global include $(top_srcdir)/contrib/contrib-global.mk endif -# In configurations that forbid undefined symbols in libraries, link with each -# dependency. This does preclude pgxs builds. +# We must link libpython explicitly ifeq ($(PORTNAME), aix) rpathdir = $(pkglibdir):$(python_libdir) -SHLIB_LINK += $(python_libspec) $(python_additional_libs) $(sort $(wildcard ../../src/pl/plpython/libplpython*.exp)) -endif +SHLIB_LINK += $(python_libspec) $(python_additional_libs) +else ifeq ($(PORTNAME), win32) -SHLIB_LINK += $(sort $(wildcard ../../src/pl/plpython/libpython*.a)) $(sort $(wildcard ../../src/pl/plpython/libplpython*.a)) +# ... see silliness in plpython Makefile ... +SHLIB_LINK += $(sort $(wildcard ../../src/pl/plpython/libpython*.a)) +else +rpathdir = $(python_libdir) +SHLIB_LINK += $(python_libspec) endif - -ifeq ($(PORTNAME), cygwin) -SHLIB_LINK += -L../ltree -lltree -L../../src/pl/plpython \ - -lplpython$(python_majorversion) $(python_libspec) endif REGRESS_OPTS += --load-extension=ltree diff --git a/contrib/ltree_plpython/ltree_plpython.c b/contrib/ltree_plpython/ltree_plpython.c index 26b7b3c275..bdd462a91b 100644 --- a/contrib/ltree_plpython/ltree_plpython.c +++ b/contrib/ltree_plpython/ltree_plpython.c @@ -1,10 +1,39 @@ #include "postgres.h" + #include "fmgr.h" #include "plpython.h" #include "ltree.h" PG_MODULE_MAGIC; +extern void _PG_init(void); + +/* Linkage to functions in plpython module */ +#if PY_MAJOR_VERSION >= 3 +typedef PyObject *(*PLyUnicode_FromStringAndSize_t) (const char *s, Py_ssize_t size); +static PLyUnicode_FromStringAndSize_t PLyUnicode_FromStringAndSize_p; +#endif + + +/* + * Module initialize function: fetch function pointers for cross-module calls. + */ +void +_PG_init(void) +{ + /* Asserts verify that typedefs above match original declarations */ +#if PY_MAJOR_VERSION >= 3 + AssertVariableIsOfType(&PLyUnicode_FromStringAndSize, PLyUnicode_FromStringAndSize_t); + PLyUnicode_FromStringAndSize_p = (PLyUnicode_FromStringAndSize_t) + load_external_function("$libdir/" PLPYTHON_LIBNAME, "PLyUnicode_FromStringAndSize", + true, NULL); +#endif +} + + +/* These defines must be after the module init function */ +#define PLyUnicode_FromStringAndSize PLyUnicode_FromStringAndSize_p + PG_FUNCTION_INFO_V1(ltree_to_plpython); diff --git a/contrib/ltree_plpython/ltree_plpython2u--1.0.sql b/contrib/ltree_plpython/ltree_plpython2u--1.0.sql index 62531371bf..5c4a703701 100644 --- a/contrib/ltree_plpython/ltree_plpython2u--1.0.sql +++ b/contrib/ltree_plpython/ltree_plpython2u--1.0.sql @@ -3,11 +3,6 @@ -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION ltree_plpython2u" to load this file. \quit --- make sure the prerequisite libraries are loaded -LOAD 'plpython2'; -SELECT NULL::ltree; - - CREATE FUNCTION ltree_to_plpython2(val internal) RETURNS internal LANGUAGE C STRICT IMMUTABLE AS 'MODULE_PATHNAME', 'ltree_to_plpython'; diff --git a/contrib/ltree_plpython/ltree_plpython3u--1.0.sql b/contrib/ltree_plpython/ltree_plpython3u--1.0.sql index 3f21d1b721..09ada3c7e8 100644 --- a/contrib/ltree_plpython/ltree_plpython3u--1.0.sql +++ b/contrib/ltree_plpython/ltree_plpython3u--1.0.sql @@ -3,11 +3,6 @@ -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION ltree_plpython3u" to load this file. \quit --- make sure the prerequisite libraries are loaded -LOAD 'plpython3'; -SELECT NULL::ltree; - - CREATE FUNCTION ltree_to_plpython3(val internal) RETURNS internal LANGUAGE C STRICT IMMUTABLE AS 'MODULE_PATHNAME', 'ltree_to_plpython'; diff --git a/contrib/ltree_plpython/ltree_plpythonu--1.0.sql b/contrib/ltree_plpython/ltree_plpythonu--1.0.sql index e8deadc62d..ee93edf28b 100644 --- a/contrib/ltree_plpython/ltree_plpythonu--1.0.sql +++ b/contrib/ltree_plpython/ltree_plpythonu--1.0.sql @@ -3,11 +3,6 @@ -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION ltree_plpythonu" to load this file. \quit --- make sure the prerequisite libraries are loaded -LOAD 'plpython2'; -- change to plpython3 if that ever becomes the default -SELECT NULL::ltree; - - CREATE FUNCTION ltree_to_plpython(val internal) RETURNS internal LANGUAGE C STRICT IMMUTABLE AS 'MODULE_PATHNAME'; diff --git a/contrib/oid2name/oid2name.c b/contrib/oid2name/oid2name.c index e5eeec21c1..5a2aa1dd0e 100644 --- a/contrib/oid2name/oid2name.c +++ b/contrib/oid2name/oid2name.c @@ -261,7 +261,8 @@ PGconn * sql_conn(struct options * my_opts) { PGconn *conn; - char *password = NULL; + bool have_password = false; + char password[100]; bool new_pass; /* @@ -282,7 +283,7 @@ sql_conn(struct options * my_opts) keywords[2] = "user"; values[2] = my_opts->username; keywords[3] = "password"; - values[3] = password; + values[3] = have_password ? password : NULL; keywords[4] = "dbname"; values[4] = my_opts->dbname; keywords[5] = "fallback_application_name"; @@ -302,17 +303,15 @@ sql_conn(struct options * my_opts) if (PQstatus(conn) == CONNECTION_BAD && PQconnectionNeedsPassword(conn) && - password == NULL) + !have_password) { PQfinish(conn); - password = simple_prompt("Password: ", 100, false); + simple_prompt("Password: ", password, sizeof(password), false); + have_password = true; new_pass = true; } } while (new_pass); - if (password) - free(password); - /* check to see that the backend connection was successfully made */ if (PQstatus(conn) == CONNECTION_BAD) { diff --git a/contrib/pageinspect/.gitignore b/contrib/pageinspect/.gitignore new file mode 100644 index 0000000000..5dcb3ff972 --- /dev/null +++ b/contrib/pageinspect/.gitignore @@ -0,0 +1,4 @@ +# Generated subdirectories +/log/ +/results/ +/tmp_check/ diff --git a/contrib/pageinspect/Makefile b/contrib/pageinspect/Makefile index a98237ecbd..87a28e98c2 100644 --- a/contrib/pageinspect/Makefile +++ b/contrib/pageinspect/Makefile @@ -11,6 +11,8 @@ DATA = pageinspect--1.5.sql pageinspect--1.4--1.5.sql \ pageinspect--unpackaged--1.0.sql PGFILEDESC = "pageinspect - functions to inspect contents of database pages" +REGRESS = page btree brin gin + ifdef USE_PGXS PG_CONFIG = pg_config PGXS := $(shell $(PG_CONFIG) --pgxs) diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c index aa6bd0bc97..7b877e3d0c 100644 --- a/contrib/pageinspect/brinfuncs.c +++ b/contrib/pageinspect/brinfuncs.c @@ -2,7 +2,7 @@ * brinfuncs.c * Functions to investigate BRIN indexes * - * Copyright (c) 2014-2016, PostgreSQL Global Development Group + * Copyright (c) 2014-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/pageinspect/brinfuncs.c diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c index 4983bbbbaf..3f09d5f0a4 100644 --- a/contrib/pageinspect/btreefuncs.c +++ b/contrib/pageinspect/btreefuncs.c @@ -34,6 +34,7 @@ #include "miscadmin.h" #include "utils/builtins.h" #include "utils/rel.h" +#include "utils/varlena.h" PG_FUNCTION_INFO_V1(bt_metap); diff --git a/contrib/pageinspect/expected/brin.out b/contrib/pageinspect/expected/brin.out new file mode 100644 index 0000000000..71eb190380 --- /dev/null +++ b/contrib/pageinspect/expected/brin.out @@ -0,0 +1,51 @@ +CREATE TABLE test1 (a int, b text); +INSERT INTO test1 VALUES (1, 'one'); +CREATE INDEX test1_a_idx ON test1 USING brin (a); +SELECT brin_page_type(get_raw_page('test1_a_idx', 0)); + brin_page_type +---------------- + meta +(1 row) + +SELECT brin_page_type(get_raw_page('test1_a_idx', 1)); + brin_page_type +---------------- + revmap +(1 row) + +SELECT brin_page_type(get_raw_page('test1_a_idx', 2)); + brin_page_type +---------------- + regular +(1 row) + +SELECT * FROM brin_metapage_info(get_raw_page('test1_a_idx', 0)); + magic | version | pagesperrange | lastrevmappage +------------+---------+---------------+---------------- + 0xA8109CFA | 1 | 128 | 1 +(1 row) + +SELECT * FROM brin_metapage_info(get_raw_page('test1_a_idx', 1)); +ERROR: page is not a BRIN page of type "metapage" +DETAIL: Expected special type 0000f091, got 0000f092. +SELECT * FROM brin_revmap_data(get_raw_page('test1_a_idx', 0)) LIMIT 5; +ERROR: page is not a BRIN page of type "revmap" +DETAIL: Expected special type 0000f092, got 0000f091. +SELECT * FROM brin_revmap_data(get_raw_page('test1_a_idx', 1)) LIMIT 5; + pages +------- + (2,1) + (0,0) + (0,0) + (0,0) + (0,0) +(5 rows) + +SELECT * FROM brin_page_items(get_raw_page('test1_a_idx', 2), 'test1_a_idx') + ORDER BY blknum, attnum LIMIT 5; + itemoffset | blknum | attnum | allnulls | hasnulls | placeholder | value +------------+--------+--------+----------+----------+-------------+---------- + 1 | 0 | 1 | f | f | f | {1 .. 1} +(1 row) + +DROP TABLE test1; diff --git a/contrib/pageinspect/expected/btree.out b/contrib/pageinspect/expected/btree.out new file mode 100644 index 0000000000..82a49e3d6c --- /dev/null +++ b/contrib/pageinspect/expected/btree.out @@ -0,0 +1,45 @@ +CREATE TABLE test1 (a int8, b text); +INSERT INTO test1 VALUES (72057594037927937, 'text'); +CREATE INDEX test1_a_idx ON test1 USING btree (a); +\x +SELECT * FROM bt_metap('test1_a_idx'); +-[ RECORD 1 ]----- +magic | 340322 +version | 2 +root | 1 +level | 0 +fastroot | 1 +fastlevel | 0 + +SELECT * FROM bt_page_stats('test1_a_idx', 0); +ERROR: block 0 is a meta page +SELECT * FROM bt_page_stats('test1_a_idx', 1); +-[ RECORD 1 ]-+----- +blkno | 1 +type | l +live_items | 1 +dead_items | 0 +avg_item_size | 16 +page_size | 8192 +free_size | 8128 +btpo_prev | 0 +btpo_next | 0 +btpo | 0 +btpo_flags | 3 + +SELECT * FROM bt_page_stats('test1_a_idx', 2); +ERROR: block number out of range +SELECT * FROM bt_page_items('test1_a_idx', 0); +ERROR: block 0 is a meta page +SELECT * FROM bt_page_items('test1_a_idx', 1); +-[ RECORD 1 ]----------------------- +itemoffset | 1 +ctid | (0,1) +itemlen | 16 +nulls | f +vars | f +data | 01 00 00 00 00 00 00 01 + +SELECT * FROM bt_page_items('test1_a_idx', 2); +ERROR: block number out of range +DROP TABLE test1; diff --git a/contrib/pageinspect/expected/gin.out b/contrib/pageinspect/expected/gin.out new file mode 100644 index 0000000000..82f63b23b1 --- /dev/null +++ b/contrib/pageinspect/expected/gin.out @@ -0,0 +1,37 @@ +CREATE TABLE test1 (x int, y int[]); +INSERT INTO test1 VALUES (1, ARRAY[11, 111]); +CREATE INDEX test1_y_idx ON test1 USING gin (y) WITH (fastupdate = off); +\x +SELECT * FROM gin_metapage_info(get_raw_page('test1_y_idx', 0)); +-[ RECORD 1 ]----+----------- +pending_head | 4294967295 +pending_tail | 4294967295 +tail_free_size | 0 +n_pending_pages | 0 +n_pending_tuples | 0 +n_total_pages | 2 +n_entry_pages | 1 +n_data_pages | 0 +n_entries | 2 +version | 2 + +SELECT * FROM gin_metapage_info(get_raw_page('test1_y_idx', 1)); +ERROR: input page is not a GIN metapage +DETAIL: Flags 0002, expected 0008 +SELECT * FROM gin_page_opaque_info(get_raw_page('test1_y_idx', 1)); +-[ RECORD 1 ]--------- +rightlink | 4294967295 +maxoff | 0 +flags | {leaf} + +SELECT * FROM gin_leafpage_items(get_raw_page('test1_y_idx', 1)); +ERROR: input page is not a compressed GIN data leaf page +DETAIL: Flags 0002, expected 0083 +INSERT INTO test1 SELECT x, ARRAY[1,10] FROM generate_series(2,10000) x; +SELECT COUNT(*) > 0 +FROM gin_leafpage_items(get_raw_page('test1_y_idx', + (pg_relation_size('test1_y_idx') / + current_setting('block_size')::bigint)::int - 1)); +-[ RECORD 1 ] +?column? | t + diff --git a/contrib/pageinspect/expected/page.out b/contrib/pageinspect/expected/page.out new file mode 100644 index 0000000000..13964cd878 --- /dev/null +++ b/contrib/pageinspect/expected/page.out @@ -0,0 +1,73 @@ +CREATE EXTENSION pageinspect; +CREATE TABLE test1 (a int, b int); +INSERT INTO test1 VALUES (16777217, 131584); +VACUUM test1; -- set up FSM +-- The page contents can vary, so just test that it can be read +-- successfully, but don't keep the output. +SELECT octet_length(get_raw_page('test1', 'main', 0)) AS main_0; + main_0 +-------- + 8192 +(1 row) + +SELECT octet_length(get_raw_page('test1', 'main', 1)) AS main_1; +ERROR: block number 1 is out of range for relation "test1" +SELECT octet_length(get_raw_page('test1', 'fsm', 0)) AS fsm_0; + fsm_0 +------- + 8192 +(1 row) + +SELECT octet_length(get_raw_page('test1', 'fsm', 1)) AS fsm_1; + fsm_1 +------- + 8192 +(1 row) + +SELECT octet_length(get_raw_page('test1', 'vm', 0)) AS vm_0; + vm_0 +------ + 8192 +(1 row) + +SELECT octet_length(get_raw_page('test1', 'vm', 1)) AS vm_1; +ERROR: block number 1 is out of range for relation "test1" +SELECT octet_length(get_raw_page('xxx', 'main', 0)); +ERROR: relation "xxx" does not exist +SELECT octet_length(get_raw_page('test1', 'xxx', 0)); +ERROR: invalid fork name +HINT: Valid fork names are "main", "fsm", "vm", and "init". +SELECT get_raw_page('test1', 0) = get_raw_page('test1', 'main', 0); + ?column? +---------- + t +(1 row) + +SELECT tuple_data_split('test1'::regclass, t_data, t_infomask, t_infomask2, t_bits) + FROM heap_page_items(get_raw_page('test1', 0)); + tuple_data_split +------------------------------- + {"\\x01000001","\\x00020200"} +(1 row) + +SELECT * FROM fsm_page_contents(get_raw_page('test1', 'fsm', 0)); + fsm_page_contents +------------------- + 0: 254 + + 1: 254 + + 3: 254 + + 7: 254 + + 15: 254 + + 31: 254 + + 63: 254 + + 127: 254 + + 255: 254 + + 511: 254 + + 1023: 254 + + 2047: 254 + + 4095: 254 + + fp_next_slot: 0 + + +(1 row) + +DROP TABLE test1; diff --git a/contrib/pageinspect/fsmfuncs.c b/contrib/pageinspect/fsmfuncs.c index c94f5f8445..654164616b 100644 --- a/contrib/pageinspect/fsmfuncs.c +++ b/contrib/pageinspect/fsmfuncs.c @@ -9,7 +9,7 @@ * there's hardly any use case for using these without superuser-rights * anyway. * - * Copyright (c) 2007-2016, PostgreSQL Global Development Group + * Copyright (c) 2007-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/pageinspect/fsmfuncs.c diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c index a2f119b02e..cea77d301e 100644 --- a/contrib/pageinspect/ginfuncs.c +++ b/contrib/pageinspect/ginfuncs.c @@ -2,7 +2,7 @@ * ginfuncs.c * Functions to investigate the content of GIN indexes * - * Copyright (c) 2014-2016, PostgreSQL Global Development Group + * Copyright (c) 2014-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/pageinspect/ginfuncs.c @@ -28,11 +28,31 @@ PG_FUNCTION_INFO_V1(gin_metapage_info); PG_FUNCTION_INFO_V1(gin_page_opaque_info); PG_FUNCTION_INFO_V1(gin_leafpage_items); + +static Page +get_page_from_raw(bytea *raw_page) +{ + int raw_page_size; + Page page; + + raw_page_size = VARSIZE(raw_page) - VARHDRSZ; + if (raw_page_size < BLCKSZ) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("input page too small (%d bytes)", raw_page_size))); + + /* make a copy so that the page is properly aligned for struct access */ + page = palloc(raw_page_size); + memcpy(page, VARDATA(raw_page), raw_page_size); + + return page; +} + + Datum gin_metapage_info(PG_FUNCTION_ARGS) { bytea *raw_page = PG_GETARG_BYTEA_P(0); - int raw_page_size; TupleDesc tupdesc; Page page; GinPageOpaque opaq; @@ -46,12 +66,7 @@ gin_metapage_info(PG_FUNCTION_ARGS) (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to use raw page functions")))); - raw_page_size = VARSIZE(raw_page) - VARHDRSZ; - if (raw_page_size < BLCKSZ) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("input page too small (%d bytes)", raw_page_size))); - page = VARDATA(raw_page); + page = get_page_from_raw(raw_page); opaq = (GinPageOpaque) PageGetSpecialPointer(page); if (opaq->flags != GIN_META) @@ -94,13 +109,12 @@ Datum gin_page_opaque_info(PG_FUNCTION_ARGS) { bytea *raw_page = PG_GETARG_BYTEA_P(0); - int raw_page_size; TupleDesc tupdesc; Page page; GinPageOpaque opaq; HeapTuple resultTuple; Datum values[3]; - bool nulls[10]; + bool nulls[3]; Datum flags[16]; int nflags = 0; uint16 flagbits; @@ -110,12 +124,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS) (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to use raw page functions")))); - raw_page_size = VARSIZE(raw_page) - VARHDRSZ; - if (raw_page_size < BLCKSZ) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("input page too small (%d bytes)", raw_page_size))); - page = VARDATA(raw_page); + page = get_page_from_raw(raw_page); opaq = (GinPageOpaque) PageGetSpecialPointer(page); @@ -152,9 +161,9 @@ gin_page_opaque_info(PG_FUNCTION_ARGS) memset(nulls, 0, sizeof(nulls)); values[0] = Int64GetDatum(opaq->rightlink); - values[1] = Int64GetDatum(opaq->maxoff); - values[2] = PointerGetDatum( - construct_array(flags, nflags, TEXTOID, -1, false, 'i')); + values[1] = Int32GetDatum(opaq->maxoff); + values[2] = PointerGetDatum(construct_array(flags, nflags, + TEXTOID, -1, false, 'i')); /* Build and return the result tuple. */ resultTuple = heap_form_tuple(tupdesc, values, nulls); @@ -173,7 +182,6 @@ Datum gin_leafpage_items(PG_FUNCTION_ARGS) { bytea *raw_page = PG_GETARG_BYTEA_P(0); - int raw_page_size; FuncCallContext *fctx; gin_leafpage_items_state *inter_call_data; @@ -182,8 +190,6 @@ gin_leafpage_items(PG_FUNCTION_ARGS) (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to use raw page functions")))); - raw_page_size = VARSIZE(raw_page) - VARHDRSZ; - if (SRF_IS_FIRSTCALL()) { TupleDesc tupdesc; @@ -191,11 +197,10 @@ gin_leafpage_items(PG_FUNCTION_ARGS) Page page; GinPageOpaque opaq; - if (raw_page_size < BLCKSZ) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("input page too small (%d bytes)", raw_page_size))); - page = VARDATA(raw_page); + fctx = SRF_FIRSTCALL_INIT(); + mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx); + + page = get_page_from_raw(raw_page); if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GinPageOpaqueData))) ereport(ERROR, @@ -214,9 +219,6 @@ gin_leafpage_items(PG_FUNCTION_ARGS) opaq->flags, (GIN_DATA | GIN_LEAF | GIN_COMPRESSED)))); - fctx = SRF_FIRSTCALL_INIT(); - mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx); - inter_call_data = palloc(sizeof(gin_leafpage_items_state)); /* Build a tuple descriptor for our result type */ diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c index 904eaef2da..748b1db093 100644 --- a/contrib/pageinspect/heapfuncs.c +++ b/contrib/pageinspect/heapfuncs.c @@ -15,7 +15,7 @@ * there's hardly any use case for using these without superuser-rights * anyway. * - * Copyright (c) 2007-2016, PostgreSQL Global Development Group + * Copyright (c) 2007-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/pageinspect/heapfuncs.c @@ -279,7 +279,7 @@ heap_page_items(PG_FUNCTION_ARGS) * * Split raw tuple data taken directly from a page into an array of bytea * elements. This routine does a lookup on NULL values and creates array - * elements accordindly. This is a reimplementation of nocachegetattr() + * elements accordingly. This is a reimplementation of nocachegetattr() * in heaptuple.c simplified for educational purposes. */ static Datum diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c index 71d0c8d2ca..a2ac078d40 100644 --- a/contrib/pageinspect/rawpage.c +++ b/contrib/pageinspect/rawpage.c @@ -5,7 +5,7 @@ * * Access-method specific inspection functions are in separate files. * - * Copyright (c) 2007-2016, PostgreSQL Global Development Group + * Copyright (c) 2007-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/pageinspect/rawpage.c @@ -25,6 +25,7 @@ #include "utils/builtins.h" #include "utils/pg_lsn.h" #include "utils/rel.h" +#include "utils/varlena.h" PG_MODULE_MAGIC; diff --git a/contrib/pageinspect/sql/brin.sql b/contrib/pageinspect/sql/brin.sql new file mode 100644 index 0000000000..735bc3b673 --- /dev/null +++ b/contrib/pageinspect/sql/brin.sql @@ -0,0 +1,18 @@ +CREATE TABLE test1 (a int, b text); +INSERT INTO test1 VALUES (1, 'one'); +CREATE INDEX test1_a_idx ON test1 USING brin (a); + +SELECT brin_page_type(get_raw_page('test1_a_idx', 0)); +SELECT brin_page_type(get_raw_page('test1_a_idx', 1)); +SELECT brin_page_type(get_raw_page('test1_a_idx', 2)); + +SELECT * FROM brin_metapage_info(get_raw_page('test1_a_idx', 0)); +SELECT * FROM brin_metapage_info(get_raw_page('test1_a_idx', 1)); + +SELECT * FROM brin_revmap_data(get_raw_page('test1_a_idx', 0)) LIMIT 5; +SELECT * FROM brin_revmap_data(get_raw_page('test1_a_idx', 1)) LIMIT 5; + +SELECT * FROM brin_page_items(get_raw_page('test1_a_idx', 2), 'test1_a_idx') + ORDER BY blknum, attnum LIMIT 5; + +DROP TABLE test1; diff --git a/contrib/pageinspect/sql/btree.sql b/contrib/pageinspect/sql/btree.sql new file mode 100644 index 0000000000..1eafc3249c --- /dev/null +++ b/contrib/pageinspect/sql/btree.sql @@ -0,0 +1,17 @@ +CREATE TABLE test1 (a int8, b text); +INSERT INTO test1 VALUES (72057594037927937, 'text'); +CREATE INDEX test1_a_idx ON test1 USING btree (a); + +\x + +SELECT * FROM bt_metap('test1_a_idx'); + +SELECT * FROM bt_page_stats('test1_a_idx', 0); +SELECT * FROM bt_page_stats('test1_a_idx', 1); +SELECT * FROM bt_page_stats('test1_a_idx', 2); + +SELECT * FROM bt_page_items('test1_a_idx', 0); +SELECT * FROM bt_page_items('test1_a_idx', 1); +SELECT * FROM bt_page_items('test1_a_idx', 2); + +DROP TABLE test1; diff --git a/contrib/pageinspect/sql/gin.sql b/contrib/pageinspect/sql/gin.sql new file mode 100644 index 0000000000..d516ed3cbd --- /dev/null +++ b/contrib/pageinspect/sql/gin.sql @@ -0,0 +1,19 @@ +CREATE TABLE test1 (x int, y int[]); +INSERT INTO test1 VALUES (1, ARRAY[11, 111]); +CREATE INDEX test1_y_idx ON test1 USING gin (y) WITH (fastupdate = off); + +\x + +SELECT * FROM gin_metapage_info(get_raw_page('test1_y_idx', 0)); +SELECT * FROM gin_metapage_info(get_raw_page('test1_y_idx', 1)); + +SELECT * FROM gin_page_opaque_info(get_raw_page('test1_y_idx', 1)); + +SELECT * FROM gin_leafpage_items(get_raw_page('test1_y_idx', 1)); + +INSERT INTO test1 SELECT x, ARRAY[1,10] FROM generate_series(2,10000) x; + +SELECT COUNT(*) > 0 +FROM gin_leafpage_items(get_raw_page('test1_y_idx', + (pg_relation_size('test1_y_idx') / + current_setting('block_size')::bigint)::int - 1)); diff --git a/contrib/pageinspect/sql/page.sql b/contrib/pageinspect/sql/page.sql new file mode 100644 index 0000000000..97eef9829a --- /dev/null +++ b/contrib/pageinspect/sql/page.sql @@ -0,0 +1,30 @@ +CREATE EXTENSION pageinspect; + +CREATE TABLE test1 (a int, b int); +INSERT INTO test1 VALUES (16777217, 131584); + +VACUUM test1; -- set up FSM + +-- The page contents can vary, so just test that it can be read +-- successfully, but don't keep the output. + +SELECT octet_length(get_raw_page('test1', 'main', 0)) AS main_0; +SELECT octet_length(get_raw_page('test1', 'main', 1)) AS main_1; + +SELECT octet_length(get_raw_page('test1', 'fsm', 0)) AS fsm_0; +SELECT octet_length(get_raw_page('test1', 'fsm', 1)) AS fsm_1; + +SELECT octet_length(get_raw_page('test1', 'vm', 0)) AS vm_0; +SELECT octet_length(get_raw_page('test1', 'vm', 1)) AS vm_1; + +SELECT octet_length(get_raw_page('xxx', 'main', 0)); +SELECT octet_length(get_raw_page('test1', 'xxx', 0)); + +SELECT get_raw_page('test1', 0) = get_raw_page('test1', 'main', 0); + +SELECT tuple_data_split('test1'::regclass, t_data, t_infomask, t_infomask2, t_bits) + FROM heap_page_items(get_raw_page('test1', 0)); + +SELECT * FROM fsm_page_contents(get_raw_page('test1', 'fsm', 0)); + +DROP TABLE test1; diff --git a/contrib/passwordcheck/passwordcheck.c b/contrib/passwordcheck/passwordcheck.c index b4c1ce005b..2399372017 100644 --- a/contrib/passwordcheck/passwordcheck.c +++ b/contrib/passwordcheck/passwordcheck.c @@ -3,7 +3,7 @@ * passwordcheck.c * * - * Copyright (c) 2009-2016, PostgreSQL Global Development Group + * Copyright (c) 2009-2017, PostgreSQL Global Development Group * * Author: Laurenz Albe * @@ -21,8 +21,8 @@ #endif #include "commands/user.h" +#include "common/md5.h" #include "fmgr.h" -#include "libpq/md5.h" PG_MODULE_MAGIC; diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c index 17b4b6fa6f..8bebf2384d 100644 --- a/contrib/pg_buffercache/pg_buffercache_pages.c +++ b/contrib/pg_buffercache/pg_buffercache_pages.c @@ -124,7 +124,9 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) fctx->tupdesc = BlessTupleDesc(tupledesc); /* Allocate NBuffers worth of BufferCachePagesRec records. */ - fctx->record = (BufferCachePagesRec *) palloc(sizeof(BufferCachePagesRec) * NBuffers); + fctx->record = (BufferCachePagesRec *) + MemoryContextAllocHuge(CurrentMemoryContext, + sizeof(BufferCachePagesRec) * NBuffers); /* Set max calls and remember the user function context. */ funcctx->max_calls = NBuffers; @@ -133,18 +135,13 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) /* Return to original context when allocating transient memory */ MemoryContextSwitchTo(oldcontext); - /* - * To get a consistent picture of the buffer state, we must lock all - * partitions of the buffer map. Needless to say, this is horrible - * for concurrency. Must grab locks in increasing order to avoid - * possible deadlocks. - */ - for (i = 0; i < NUM_BUFFER_PARTITIONS; i++) - LWLockAcquire(BufMappingPartitionLockByIndex(i), LW_SHARED); - /* * Scan through all the buffers, saving the relevant fields in the * fctx->record structure. + * + * We don't hold the partition locks, so we don't get a consistent + * snapshot across all buffers, but we do grab the buffer header + * locks, so the information of each buffer is self-consistent. */ for (i = 0; i < NBuffers; i++) { @@ -177,16 +174,6 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) UnlockBufHdr(bufHdr, buf_state); } - - /* - * And release locks. We do this in reverse order for two reasons: - * (1) Anyone else who needs more than one of the locks will be trying - * to lock them in increasing order; we don't want to release the - * other process until it can get all the locks it needs. (2) This - * avoids O(N^2) behavior inside LWLockRelease. - */ - for (i = NUM_BUFFER_PARTITIONS; --i >= 0;) - LWLockRelease(BufMappingPartitionLockByIndex(i)); } funcctx = SRF_PERCALL_SETUP(); diff --git a/contrib/pg_execplan/LICENSE b/contrib/pg_execplan/LICENSE new file mode 100644 index 0000000000..b7e6f0f56d --- /dev/null +++ b/contrib/pg_execplan/LICENSE @@ -0,0 +1,11 @@ +ExecPlan is released under the PostgreSQL License, a liberal Open Source license, similar to the BSD or MIT licenses. + +Copyright (c) 2018-2019, Postgres Professional +Portions Copyright (c) 1996-2018, 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 POSTGRES PROFESSIONAL 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 POSTGRES PROFESSIONAL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +POSTGRES PROFESSIONAL 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 POSTGRES PROFESSIONAL HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. diff --git a/contrib/pg_execplan/Makefile b/contrib/pg_execplan/Makefile new file mode 100644 index 0000000000..86226cb2c2 --- /dev/null +++ b/contrib/pg_execplan/Makefile @@ -0,0 +1,28 @@ +# contrib/pg_execplan/Makefile + +MODULE_big = pg_execplan +EXTENSION = pg_execplan +EXTVERSION = 0.1 +PGFILEDESC = "pg_execplan" +MODULES = pg_execplan +OBJS = pg_execplan.o $(WIN32RES) + +PG_CPPFLAGS = -I$(libpq_srcdir) +SHLIB_LINK_INTERNAL = $(libpq) + +DATA_built = $(EXTENSION)--$(EXTVERSION).sql + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +SHLIB_PREREQS = submake-libpq +subdir = contrib/pg_execplan +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif + +$(EXTENSION)--$(EXTVERSION).sql: init.sql + cat $^ > $@ diff --git a/contrib/pg_execplan/README.md b/contrib/pg_execplan/README.md new file mode 100644 index 0000000000..82220e2305 --- /dev/null +++ b/contrib/pg_execplan/README.md @@ -0,0 +1,15 @@ +# execplan +PostgreSQL patch & extension for raw query plan execution + +This project dedicated to query execution problem in DBMS for computing systems with cluster architecture. + +The DBMS may need to execute an identical query plan at each computing node. +Today PostgreSQL can process only SQL statements. But it is not guaranteed, that the planner at each node will construct same query plan, because different statistics, relation sizes e.t.c. + +This solution based on postgres-xl approach: plan tree is serialized by the nodeToString() routine. +During serialization we transform all database object identifiers (oid) in each node field to portable representation. +Further, the serialized plan transfer by new libpq routine called `PQsendPlan`. +In this project we use postgres_fdw connections for management of sessions and remote transactions. +Some `repeater` extension used for the demonstration of plan transfer machinery. +The `pg12_devel.patch` patch contains all core changes. +The `scripts` directory contains some simplistic demo tests. diff --git a/contrib/pg_execplan/init.sql b/contrib/pg_execplan/init.sql new file mode 100644 index 0000000000..066b9f1da3 --- /dev/null +++ b/contrib/pg_execplan/init.sql @@ -0,0 +1,21 @@ +\echo Use "CREATE EXTENSION pg_execplan" to load this file. \quit + +-- Store plan of a query into a text file. +-- query - query string which will be parsed and planned. +-- filename - path to the file on a disk. +CREATE OR REPLACE FUNCTION @extschema@.pg_store_query_plan( + filename TEXT, + query TEXT + ) +RETURNS VOID AS 'pg_execplan' +LANGUAGE C; + +CREATE OR REPLACE FUNCTION @extschema@.pg_exec_plan(query TEXT, + plan TEXT + ) +RETURNS BOOL AS 'pg_execplan' +LANGUAGE C; + +CREATE OR REPLACE FUNCTION @extschema@.pg_exec_stored_plan(filename TEXT) +RETURNS BOOL AS 'pg_execplan' +LANGUAGE C; diff --git a/contrib/pg_execplan/pg_execplan.c b/contrib/pg_execplan/pg_execplan.c new file mode 100644 index 0000000000..0c6133f32e --- /dev/null +++ b/contrib/pg_execplan/pg_execplan.c @@ -0,0 +1,238 @@ +/* + * pg_execplan.c + * + */ + +#include "postgres.h" + +#include "access/printtup.h" +#include "commands/extension.h" +#include "commands/prepare.h" +#include "executor/executor.h" +#include "nodes/nodes.h" +#include "nodes/plannodes.h" +#include "tcop/pquery.h" +#include "tcop/utility.h" +#include "utils/builtins.h" +#include "utils/memutils.h" +#include "utils/plancache.h" +#include "utils/snapmgr.h" + + +#define EXPLAN_DEBUG_LEVEL 0 + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(pg_store_query_plan); +PG_FUNCTION_INFO_V1(pg_exec_plan); +PG_FUNCTION_INFO_V1(pg_exec_stored_plan); + +void _PG_init(void); + +/* + * Module load/unload callback + */ +void +_PG_init(void) +{ + return; +} + +Datum +pg_store_query_plan(PG_FUNCTION_ARGS) +{ + char *query_string = TextDatumGetCString(PG_GETARG_DATUM(1)), + *filename = TextDatumGetCString(PG_GETARG_DATUM(0)), + *plan_string; + int nstmts; + FILE *fout; + MemoryContext oldcontext; + List *parsetree_list; + RawStmt *parsetree; + List *querytree_list, + *plantree_list; + QueryDesc *queryDesc; + size_t string_len; + + if (EXPLAN_DEBUG_LEVEL > 0) + elog(LOG, "Store into %s plan of the query %s.", filename, query_string); + + oldcontext = MemoryContextSwitchTo(MessageContext); + + parsetree_list = pg_parse_query(query_string); + nstmts = list_length(parsetree_list); + if (nstmts != 1) + elog(ERROR, "Query contains %d elements, but must contain only one.", nstmts); + + parsetree = (RawStmt *) linitial(parsetree_list); + querytree_list = pg_analyze_and_rewrite(parsetree, query_string, NULL, 0); + plantree_list = pg_plan_queries(querytree_list, CURSOR_OPT_PARALLEL_OK, NULL); + + queryDesc = CreateQueryDesc((PlannedStmt *) linitial(plantree_list), + query_string, + InvalidSnapshot, + InvalidSnapshot, + None_Receiver, + 0, + 0); + + if (EXPLAN_DEBUG_LEVEL > 0) + elog(INFO, "BEFORE writing %s ...", filename); + + fout = fopen(filename, "wb"); + Assert(fout != NULL); + string_len = strlen(query_string); + fwrite(&string_len, sizeof(size_t), 1, fout); + fwrite(query_string, sizeof(char), string_len, fout); + + set_portable_output(true); + plan_string = nodeToString(queryDesc->plannedstmt); + set_portable_output(false); + string_len = strlen(plan_string); + fwrite(&string_len, sizeof(size_t), 1, fout); + fwrite(plan_string, sizeof(char), string_len, fout); + + fclose(fout); + MemoryContextSwitchTo(oldcontext); + PG_RETURN_VOID(); +} + +static void +exec_plan(char *query_string, char *plan_string) +{ + PlannedStmt *pstmt; + ParamListInfo paramLI = NULL; + CachedPlanSource *psrc; + CachedPlan *cplan; + QueryDesc *queryDesc; + DestReceiver *receiver; + int eflags = 0; + + PG_TRY(); + { + set_portable_input(true); + pstmt = (PlannedStmt *) stringToNode(plan_string); + set_portable_input(false); + } + PG_CATCH(); + { + elog(INFO, "BAD PLAN: %s. Query: %s", plan_string, query_string); + PG_RE_THROW(); + } + PG_END_TRY(); + + if (EXPLAN_DEBUG_LEVEL > 0) + elog(INFO, "query: %s\n", query_string); + if (EXPLAN_DEBUG_LEVEL > 1) + elog(INFO, "\nplan: %s\n", plan_string); + + psrc = CreateCachedPlan(NULL, query_string, NULL); + CompleteCachedPlan(psrc, NIL, NULL, NULL, 0, NULL, NULL, + CURSOR_OPT_GENERIC_PLAN, false); + + SetRemoteSubplan(psrc, pstmt); + cplan = GetCachedPlan(psrc, paramLI, false); + + receiver = CreateDestReceiver(DestLog); + + PG_TRY(); + { + queryDesc = CreateQueryDesc(pstmt, + query_string, + GetActiveSnapshot(), + InvalidSnapshot, + receiver, + paramLI, + 0); + ExecutorStart(queryDesc, eflags); + PushActiveSnapshot(queryDesc->snapshot); + ExecutorRun(queryDesc, ForwardScanDirection, 0); + PopActiveSnapshot(); + ExecutorFinish(queryDesc); + ExecutorEnd(queryDesc); + FreeQueryDesc(queryDesc); + } + PG_CATCH(); + { + elog(INFO, "BAD QUERY: '%s'.", query_string); + ReleaseCachedPlan(cplan, false); + PG_RE_THROW(); + } + PG_END_TRY(); + + receiver->rDestroy(receiver); + ReleaseCachedPlan(cplan, false); + + if (EXPLAN_DEBUG_LEVEL > 0) + elog(INFO, "query execution finished.\n"); +} + +Datum +pg_exec_plan(PG_FUNCTION_ARGS) +{ + char *query_string = TextDatumGetCString(PG_GETARG_DATUM(0)); + char *plan_string = TextDatumGetCString(PG_GETARG_DATUM(1)); + + char *dec_query, + *dec_plan; + int dec_query_len, + dec_query_len1, + dec_plan_len, + dec_plan_len1; + + Assert(query_string != NULL); + Assert(plan_string != NULL); + + dec_query_len = b64_dec_len(query_string, strlen(query_string) + 1)+1; + dec_query = palloc0(dec_query_len + 1); + dec_query_len1 = b64_decode(query_string, strlen(query_string), dec_query); + Assert(dec_query_len > dec_query_len1); + + dec_plan_len = b64_dec_len(plan_string, strlen(plan_string) + 1); + dec_plan = palloc0(dec_plan_len + 1); + dec_plan_len1 = b64_decode(plan_string, strlen(plan_string), dec_plan); + Assert(dec_plan_len > dec_plan_len1); + + exec_plan(dec_query, dec_plan); + pfree(dec_query); + pfree(dec_plan); + PG_RETURN_BOOL(true); +} + +static void +LoadPlanFromFile(const char *filename, char **query_string, char **plan_string) +{ + FILE *fin; + size_t string_len; + int nelems; + + fin = fopen(filename, "rb"); + Assert(fin != NULL); + + nelems = fread(&string_len, sizeof(size_t), 1, fin); + Assert(nelems == 1); + *query_string = palloc0(string_len + 1); + nelems = fread(*query_string, sizeof(char), string_len, fin); + Assert(nelems == string_len); + + nelems = fread(&string_len, sizeof(size_t), 1, fin); + Assert(nelems == 1); + *plan_string = palloc0(string_len + 1); + nelems = fread(*plan_string, sizeof(char), string_len, fin); + Assert(nelems == string_len); + + fclose(fin); + +} + +Datum +pg_exec_stored_plan(PG_FUNCTION_ARGS) +{ + char *filename = TextDatumGetCString(PG_GETARG_DATUM(0)), + *query_string = NULL, + *plan_string = NULL; + + LoadPlanFromFile(filename, &query_string, &plan_string); + exec_plan(query_string, plan_string); + PG_RETURN_BOOL(true); +} diff --git a/contrib/pg_execplan/pg_execplan.control b/contrib/pg_execplan/pg_execplan.control new file mode 100644 index 0000000000..9eb84e1bcd --- /dev/null +++ b/contrib/pg_execplan/pg_execplan.control @@ -0,0 +1,5 @@ +# pg_execplan extension +comment = 'Execute raw query plan on remote node' +default_version = '0.1' +module_pathname = '$libdir/pg_execplan' +relocatable = false diff --git a/contrib/pg_execplan/tests/create_objects.sql b/contrib/pg_execplan/tests/create_objects.sql new file mode 100644 index 0000000000..dedf46c5cc --- /dev/null +++ b/contrib/pg_execplan/tests/create_objects.sql @@ -0,0 +1,70 @@ +CREATE SCHEMA tests; +SET search_path = 'tests'; + +CREATE TYPE int42; +-- Make dummy I/O routines using the existing internal support for int4, text +CREATE FUNCTION int42_in(cstring) + RETURNS int42 + AS 'int4in' + LANGUAGE internal STRICT IMMUTABLE; +CREATE FUNCTION int42_out(int42) + RETURNS cstring + AS 'int4out' + LANGUAGE internal STRICT IMMUTABLE; + +CREATE TYPE int42 ( + internallength = 4, + input = int42_in, + output = int42_out, + alignment = int4, + default = 42, + passedbyvalue +); + +-- RELOID, TYPEOID +CREATE TABLE tests.t1 (id int42); +CREATE TABLE t2 (id int, payload TEXT, par1 INT); + +CREATE FUNCTION select1(tid INT) RETURNS VOID AS $$ +BEGIN + INSERT INTO tests.t2 (id, payload, par1) VALUES (1, 'qwe', 2); +END; +$$ LANGUAGE plpgsql; + +-- COLLOID +CREATE COLLATION test1 (locale = 'en_US.utf8'); +CREATE TABLE ttest1 ( + id serial, + a text COLLATE test1, + b text COLLATE test1 +); +INSERT INTO ttest1 (a, b) VALUES ('one', 'one'); +INSERT INTO ttest1 (a, b) VALUES ('one', 'two'); + +-- OPEROID +CREATE OPERATOR public.### ( + leftarg = numeric, + rightarg = numeric, + procedure = numeric_add +); + +-- Different types and parameter types +CREATE TYPE bug_status AS ENUM ('new', 'open', 'closed'); + +CREATE TABLE public.bug ( + id serial, + description TEXT, + status bug_status +); + +INSERT INTO public.bug (description, status) VALUES ('abc', 'open'); +INSERT INTO public.bug (description, status) VALUES ('abc1', 'closed'); + +CREATE TABLE public.bug1 ( + id serial, + status bug_status +); +INSERT INTO public.bug1 (status) VALUES ('new'); +INSERT INTO public.bug1 (status) VALUES ('new'); +INSERT INTO public.bug1 (status) VALUES ('closed'); + diff --git a/contrib/pg_execplan/tests/regress b/contrib/pg_execplan/tests/regress new file mode 100755 index 0000000000..f986dca420 --- /dev/null +++ b/contrib/pg_execplan/tests/regress @@ -0,0 +1,63 @@ +#!/bin/bash + +# This script performs regress tests at a master and mirrored it into the slave. +U=regression +export LC_ALL=C +export LANGUAGE="en_US:en" + +# Paths +PGINSTALL=`pwd`/tmp_install/ +SCRIPTS=`pwd`/contrib/pg_execplan/tests +LD_LIBRARY_PATH=$PGINSTALL/lib +remoteSrvName=fdwremote +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH +export PATH=$PGINSTALL/bin:$PATH +export PGDATABASE=regression + +pkill -9 postgres || true +sleep 1 +rm -rf $PGINSTALL || true +rm -rf PGDATA_Master || true +rm -rf PGDATA_Slave || true +rm -rf master.log || true +rm -rf slave.log || true + +# Building project +make > /dev/null +make -C contrib > /dev/null +make install > /dev/null +make -C contrib install > /dev/null + +mkdir PGDATA_Master +mkdir PGDATA_Slave +initdb -D PGDATA_Master -E UTF8 --locale=C +initdb -D PGDATA_Slave -E UTF8 --locale=C +echo "shared_preload_libraries = 'postgres_fdw, pg_execplan, pg_repeater'" >> PGDATA_Master/postgresql.conf +echo "shared_preload_libraries = 'pg_execplan'" >> PGDATA_Slave/postgresql.conf +echo "repeater.fdwname = '$remoteSrvName'" >> PGDATA_Master/postgresql.conf + +pg_ctl -c -o "-p 5433" -D PGDATA_Slave -l slave.log start +pg_ctl -c -o "-p 5432" -D PGDATA_Master -l master.log start +createdb -p 5433 $U +createdb -p 5432 $U + +psql -p 5432 -c "CREATE EXTENSION postgres_fdw;" +psql -p 5432 -c "CREATE SERVER $remoteSrvName FOREIGN DATA WRAPPER postgres_fdw OPTIONS (port '5433', dbname 'regression', use_remote_estimate 'on');" +psql -p 5432 -c "CREATE USER MAPPING FOR PUBLIC SERVER $remoteSrvName;" + +# Prepare plan execution +psql -p 5432 -c "CREATE EXTENSION pg_execplan;" +psql -p 5433 -c "CREATE EXTENSION pg_execplan;" +psql -p 5432 -c "CREATE EXTENSION pg_repeater;" + +psql -p 5433 -c "CREATE TABLE t2 (id Serial, b INT, PRIMARY KEY(id));" +psql -p 5433 -c "DROP TABLE t2;" +#psql -p 5433 -c "SELECT pg_exec_plan('SELECT * FROM pg_class;','sdadad');" + +rm -rf `pwd`/src/test/regress/testtablespace +mkdir `pwd`/src/test/regress/testtablespace +rm -rf $PGINSTALL/lib/regress.so +cp `pwd`/src/test/regress/regress.so $PGINSTALL/lib +cp `pwd`/src/test/regress/regress.so $PGINSTALL/lib/postgresql/ +cd src/test/regress +./pg_regress --schedule=$SCRIPTS/serial_schedule --load-extension=postgres_fdw --load-extension=pg_execplan --load-extension=pg_repeater --dbname=regression --use-existing diff --git a/contrib/pg_execplan/tests/rpl.sh b/contrib/pg_execplan/tests/rpl.sh new file mode 100755 index 0000000000..4e2f882b99 --- /dev/null +++ b/contrib/pg_execplan/tests/rpl.sh @@ -0,0 +1,109 @@ +#!/bin/bash + +# This script to pass some plans between separate instances. +U=`whoami` +export LC_ALL=C +export LANGUAGE="en_US:en" + +# Paths +PGINSTALL=`pwd`/tmp_install/ +LD_LIBRARY_PATH=$PGINSTALL/lib +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH +export PATH=$PGINSTALL/bin:$PATH + +pkill -9 postgres || true +sleep 1 +rm -rf $PGINSTALL || true +rm -rf PGDATA_Master || true +rm -rf PGDATA_Slave || true +rm -rf master.log || true +rm -rf slave.log || true + +# Building project +make > /dev/null +make -C contrib > /dev/null +make install > /dev/null +make -C contrib install > /dev/null + +mkdir PGDATA_Master +mkdir PGDATA_Slave +initdb -D PGDATA_Master -E UTF8 --locale=C +initdb -D PGDATA_Slave -E UTF8 --locale=C +echo "shared_preload_libraries = 'postgres_fdw, pg_execplan'" >> PGDATA_Master/postgresql.conf +echo "shared_preload_libraries = 'postgres_fdw, pg_execplan'" >> PGDATA_Slave/postgresql.conf + +pg_ctl -w -D PGDATA_Master -o "-p 5432" -l master.log start +pg_ctl -w -D PGDATA_Slave -o "-p 5433" -l slave.log start +createdb $U -p 5432 +createdb $U -p 5433 + +psql -p 5432 -c "CREATE EXTENSION postgres_fdw;" +psql -p 5433 -c "CREATE EXTENSION postgres_fdw;" +psql -p 5432 -c "CREATE EXTENSION pg_execplan;" +psql -p 5433 -c "CREATE EXTENSION pg_execplan;" + +# shift oids +psql -p 5433 -c "CREATE TABLE t0 (id int);" +psql -p 5433 -c "DROP TABLE t0;" + +#create database objects for check of oid switching +psql -p 5432 -f contrib/pg_execplan/tests/create_objects.sql +psql -p 5433 -f contrib/pg_execplan/tests/create_objects.sql +psql -p 5433 -c "SELECT current_schemas(true);" + +# TEST ON RELOID and TYPEOID objects. +psql -p 5432 -c "SELECT pg_store_query_plan('../test.txt', 'SELECT * FROM tests.t1;');" +psql -p 5433 -c "SELECT pg_exec_stored_plan('../test.txt');" + +psql -p 5432 -c "SELECT pg_store_query_plan('../test.txt', 'SELECT tests.select1(42);');" +psql -p 5433 -c "SELECT pg_exec_stored_plan('../test.txt');" +psql -p 5432 -c "SELECT pg_exec_stored_plan('../test.txt');" + +psql -p 5432 -c "SELECT * FROM tests.t2;" +psql -p 5433 -c "SELECT * FROM tests.t2;" + +# COLLOID ---------------------------------------------------------------------- +# Check on different oids +psql -p 5432 -c "SELECT oid, * FROM pg_collation WHERE collname LIKE 'test%';" +psql -p 5433 -c "SELECT oid, * FROM pg_collation WHERE collname LIKE 'test%';" + +psql -p 5432 -c "SELECT pg_store_query_plan('../test.txt', 'SELECT max(id) FROM tests.ttest1 WHERE a < b COLLATE tests.test1');" +psql -p 5433 -c "SELECT pg_exec_stored_plan('../test.txt');" + +# OPEROID ---------------------------------------------------------------------- +# Check on different oids +psql -p 5432 -c "SELECT oid, oprname, oprnamespace FROM pg_operator WHERE oprname LIKE '###';" +psql -p 5433 -c "SELECT oid, oprname, oprnamespace FROM pg_operator WHERE oprname LIKE '###';" + +# Test +psql -p 5432 -c "SELECT pg_store_query_plan('../test.txt', 'SELECT id ### 1 FROM tests.ttest1;');" +psql -p 5433 -c "SELECT pg_exec_stored_plan('../test.txt');" + +#ENUMOID ----------------------------------------------------------------------- +psql -p 5432 -c "SELECT pg_store_query_plan('../test.txt', 'INSERT INTO bug (description, status) VALUES (''abc3'', ''new''::tests.bug_status);');" +psql -p 5433 -c "SELECT pg_exec_stored_plan('../test.txt');" + +echo "ENUMOID test" +psql -p 5432 -c "SELECT pg_store_query_plan('../test.txt', ' + SELECT A.description, B.id + FROM bug as A, bug1 AS B + WHERE A.status = B.status; + ');" +psql -p 5433 -c "SELECT pg_exec_stored_plan('../test.txt');" + +# Prepared operator +psql -p 5432 -c "PREPARE abc (TEXT, tests.bug_status) AS + INSERT INTO bug (description, status) + VALUES (\$1,\$2); + SELECT pg_store_query_plan('../test.txt', ' + EXECUTE abc(''test1'', ''closed'') + ');" + +psql -p 5433 -c "PREPARE abc (TEXT, tests.bug_status) AS + INSERT INTO bug (description, status) + VALUES (\$1,\$2); + SELECT pg_exec_stored_plan('../test.txt');" + +psql -p 5433 -c "SELECT * FROM bug;" +psql -p 5433 -c "SELECT * FROM bug1;" + diff --git a/contrib/pg_execplan/tests/serial_schedule b/contrib/pg_execplan/tests/serial_schedule new file mode 100644 index 0000000000..84ad1ac4a9 --- /dev/null +++ b/contrib/pg_execplan/tests/serial_schedule @@ -0,0 +1,172 @@ +# src/test/regress/serial_schedule +# This should probably be in an order similar to parallel_schedule. +test: boolean +test: char +test: name +test: varchar +test: text +test: int2 +test: int4 +test: int8 +test: oid +test: float4 +test: float8 +test: bit +test: numeric +test: txid +test: uuid +test: enum +test: money +test: rangetypes +test: pg_lsn +test: regproc +test: strings +test: numerology +test: point +test: lseg +test: line +test: box +test: path +test: polygon +test: circle +test: date +test: time +test: timetz +test: timestamp +test: timestamptz +test: interval +test: abstime +test: reltime +test: tinterval +test: inet +test: macaddr +test: tstypes +test: comments +test: geometry +test: horology +test: regex +test: oidjoins +test: type_sanity +test: opr_sanity +test: insert +test: insert_conflict +test: create_function_1 +test: create_type +test: create_table +test: create_function_2 +test: copy +test: copyselect +test: copydml +test: create_misc +test: create_operator +test: create_index +test: create_view +test: create_aggregate +test: create_function_3 +test: create_cast +test: constraints +test: triggers +test: inherit +test: create_table_like +test: typed_table +test: vacuum +test: drop_if_exists +test: updatable_views +test: rolenames +test: roleattributes +test: create_am +test: sanity_check +test: errors +test: select +test: select_into +test: select_distinct +test: select_distinct_on +test: select_implicit +test: select_having +test: subselect +test: union +test: case +test: join +test: aggregates +test: transactions +ignore: random +test: random +test: portals +test: arrays +test: btree_index +test: hash_index +test: update +test: delete +test: namespace +test: prepared_xacts +test: brin +test: gin +test: gist +test: spgist +test: privileges +test: init_privs +test: security_label +test: collate +test: matview +test: lock +test: replica_identity +test: rowsecurity +test: object_address +test: tablesample +test: groupingsets +test: drop_operator +test: alter_generic +test: alter_operator +test: misc +test: psql +test: async +test: dbsize +test: misc_functions +test: tsrf +test: rules +test: psql_crosstab +test: select_parallel +test: publication +test: subscription +test: amutils +test: select_views +test: portals_p2 +test: foreign_key +test: cluster +test: dependency +test: guc +test: bitmapops +test: combocid +test: tsearch +test: tsdicts +test: foreign_data +test: window +test: xmlmap +test: functional_deps +test: advisory_lock +test: json +test: jsonb +test: json_encoding +test: indirect_toast +test: equivclass +test: plancache +test: limit +test: plpgsql +test: copy2 +test: temp +test: domain +test: rangefuncs +test: prepare +test: without_oid +test: conversion +test: truncate +test: alter_table +test: sequence +test: polymorphism +test: rowtypes +test: returning +test: largeobject +test: with +test: xml +test: event_trigger +test: stats diff --git a/contrib/pg_prewarm/pg_prewarm.c b/contrib/pg_prewarm/pg_prewarm.c index c3a518cfc2..52ea004e7f 100644 --- a/contrib/pg_prewarm/pg_prewarm.c +++ b/contrib/pg_prewarm/pg_prewarm.c @@ -3,7 +3,7 @@ * pg_prewarm.c * prewarming utilities * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/pg_prewarm/pg_prewarm.c diff --git a/contrib/pg_repeater/.gitignore b/contrib/pg_repeater/.gitignore new file mode 100644 index 0000000000..c6127b38c1 --- /dev/null +++ b/contrib/pg_repeater/.gitignore @@ -0,0 +1,52 @@ +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf diff --git a/contrib/pg_repeater/LICENSE b/contrib/pg_repeater/LICENSE new file mode 100644 index 0000000000..183b813986 --- /dev/null +++ b/contrib/pg_repeater/LICENSE @@ -0,0 +1,11 @@ +pg_repeater is released under the PostgreSQL License, a liberal Open Source license, similar to the BSD or MIT licenses. + +Copyright (c) 2018-2019, Postgres Professional +Portions Copyright (c) 1996-2018, 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 POSTGRES PROFESSIONAL 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 POSTGRES PROFESSIONAL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +POSTGRES PROFESSIONAL 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 POSTGRES PROFESSIONAL HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. diff --git a/contrib/pg_repeater/Makefile b/contrib/pg_repeater/Makefile new file mode 100644 index 0000000000..a4d4f30016 --- /dev/null +++ b/contrib/pg_repeater/Makefile @@ -0,0 +1,32 @@ +# contrib/pg_repeater/Makefile + +MODULE_big = pg_repeater +EXTENSION = pg_repeater +EXTVERSION = 0.1 +PGFILEDESC = "pg_repeater" +MODULES = pg_repeater +OBJS = pg_repeater.o $(WIN32RES) + +fdw_srcdir = $(top_srcdir)/contrib/postgres_fdw/ +execplan_srcdir = $(top_srcdir)/contrib/pg_execplan/ + +PG_CPPFLAGS = -I$(libpq_srcdir) -I$(fdw_srcdir) -L$(fdw_srcdir) -I$(execplan_srcdir) -L$(execplan_srcdir) +SHLIB_LINK_INTERNAL = $(libpq) + +DATA_built = $(EXTENSION)--$(EXTVERSION).sql + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +EXTRA_INSTALL = contrib/postgres_fdw contrib/pg_execplan +SHLIB_PREREQS = submake-libpq +subdir = contrib/pg_repeater +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif + +$(EXTENSION)--$(EXTVERSION).sql: init.sql + cat $^ > $@ diff --git a/contrib/pg_repeater/README.md b/contrib/pg_repeater/README.md new file mode 100644 index 0000000000..109af3744c --- /dev/null +++ b/contrib/pg_repeater/README.md @@ -0,0 +1,20 @@ +# pg_repeater +PostgreSQL patch & extension for UTILITY queries and query plans execution at +remote instance. + +Plan is passed by postgres_fdw connection service. It executed by pg_exec_plan() +routine, introduced by pg_execplan extension. + +This project dedicated to query execution problem in DBMS for computing systems +with cluster architecture. + +The DBMS may need to execute an identical query plan at each computing node. +Today PostgreSQL can process only SQL statements. But it is not guaranteed, that +the planner at each node will construct same query plan, because different +statistics, relation sizes e.t.c. + +This solution based on postgres-xl approach: plan tree is serialized by the +nodeToString() routine. +During serialization we transform all database object identifiers (oid) at each +node field to portable representation. + diff --git a/contrib/pg_repeater/init.sql b/contrib/pg_repeater/init.sql new file mode 100644 index 0000000000..da3d2fc504 --- /dev/null +++ b/contrib/pg_repeater/init.sql @@ -0,0 +1 @@ +\echo Use "CREATE EXTENSION pg_repeater" to load this file. \quit diff --git a/contrib/pg_repeater/pg_repeater.c b/contrib/pg_repeater/pg_repeater.c new file mode 100644 index 0000000000..4fefc325d1 --- /dev/null +++ b/contrib/pg_repeater/pg_repeater.c @@ -0,0 +1,242 @@ +/*------------------------------------------------------------------------- + * + * repeater.c + * Simple demo for remote plan execution patch. + * + * Transfer query plan to a remote instance and wait for result. + * Remote instance parameters (host, port) defines by GUCs. + * + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2018-2019, Postgres Professional + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "access/parallel.h" +#include "access/xact.h" +#include "commands/extension.h" +#include "executor/executor.h" +#include "fmgr.h" +#include "foreign/foreign.h" +#include "libpq/libpq.h" +#include "libpq-fe.h" +#include "miscadmin.h" +#include "optimizer/planner.h" +#include "pgstat.h" +#include "postgres_fdw.h" +#include "storage/latch.h" +#include "tcop/utility.h" +#include "utils/builtins.h" +#include "utils/guc.h" +#include "utils/memutils.h" + + +PG_MODULE_MAGIC; + +void _PG_init(void); + +static ProcessUtility_hook_type next_ProcessUtility_hook = NULL; +static ExecutorStart_hook_type prev_ExecutorStart = NULL; +static ExecutorEnd_hook_type prev_ExecutorEnd = NULL; + +static void HOOK_Utility_injection(PlannedStmt *pstmt, const char *queryString, + ProcessUtilityContext context, ParamListInfo params, + DestReceiver *dest, char *completionTag); +static void HOOK_ExecStart_injection(QueryDesc *queryDesc, int eflags); +static void HOOK_ExecEnd_injection(QueryDesc *queryDesc); + +/* Remote instance parameters. */ +char *remote_server_fdwname; + +static bool ExtensionIsActivated = false; +static PGconn *conn = NULL; + +static Oid serverid = InvalidOid; +static UserMapping *user = NULL; + + +/* + * Module load/unload callback + */ +void +_PG_init(void) +{ + DefineCustomStringVariable("repeater.fdwname", + "Remote host fdw name", + NULL, + &remote_server_fdwname, + "remoteserv", + PGC_SIGHUP, + GUC_NOT_IN_SAMPLE, + NULL, + NULL, + NULL); + + /* ProcessUtility hook */ + next_ProcessUtility_hook = ProcessUtility_hook; + ProcessUtility_hook = HOOK_Utility_injection; + + prev_ExecutorStart = ExecutorStart_hook; + ExecutorStart_hook = HOOK_ExecStart_injection; + + prev_ExecutorEnd = ExecutorEnd_hook; + ExecutorEnd_hook = HOOK_ExecEnd_injection; +} + +static bool +ExtensionIsActive(void) +{ + if (ExtensionIsActivated) + return true; + + if ( + !IsTransactionState() || + !OidIsValid(get_extension_oid("pg_repeater", true)) + ) + return false; + + ExtensionIsActivated = true; + return ExtensionIsActivated; +} + +/* + * We need to send some DML queries for sync database schema to a plan execution + * at a remote instance. + */ +static void +HOOK_Utility_injection(PlannedStmt *pstmt, + const char *queryString, + ProcessUtilityContext context, + ParamListInfo params, + DestReceiver *dest, + char *completionTag) +{ + Node *parsetree = pstmt->utilityStmt; + + if (ExtensionIsActive() && + pstmt->canSetTag && + (context != PROCESS_UTILITY_SUBCOMMAND) + ) + { + if (!user) + { + MemoryContext oldCxt = MemoryContextSwitchTo(TopMemoryContext); + + serverid = get_foreign_server_oid(remote_server_fdwname, true); + Assert(OidIsValid(serverid)); + + user = GetUserMapping(GetUserId(), serverid); + MemoryContextSwitchTo(oldCxt); + } + switch (nodeTag(parsetree)) + { + case T_CopyStmt: + case T_CreateExtensionStmt: + case T_ExplainStmt: + case T_FetchStmt: + case T_VacuumStmt: + break; + default: + { + PGresult *res; + + if (nodeTag(parsetree) == T_TransactionStmt) + { + TransactionStmt *stmt = (TransactionStmt *) parsetree; + + if ( +/* (stmt->kind != TRANS_STMT_ROLLBACK_TO) && */ + (stmt->kind != TRANS_STMT_SAVEPOINT) + ) + break; + } + conn = GetConnection(user, true); + Assert(conn != NULL); + + res = PQexec(conn, queryString); + PQclear(res); + } + break; + } + } + + if (next_ProcessUtility_hook) + (*next_ProcessUtility_hook) (pstmt, queryString, context, params, + dest, completionTag); + else + standard_ProcessUtility(pstmt, queryString, + context, params, + dest, completionTag); +} + +static void +HOOK_ExecStart_injection(QueryDesc *queryDesc, int eflags) +{ + Node *parsetree = queryDesc->plannedstmt->utilityStmt; + + if (prev_ExecutorStart) + prev_ExecutorStart(queryDesc, eflags); + else + standard_ExecutorStart(queryDesc, eflags); + + /* + * This not fully correct sign for prevent passing each subquery to the + * remote instance. Only for demo. + */ + if (ExtensionIsActive() && + queryDesc->plannedstmt->canSetTag && + !IsParallelWorker() && + ((parsetree == NULL) || (nodeTag(parsetree) != T_CreatedbStmt)) && + !(eflags & EXEC_FLAG_EXPLAIN_ONLY)) + { + Oid serverid; + UserMapping *user; + char *query, + *query_container, + *plan, + *plan_container; + int qlen, + qlen1, + plen, + plen1; + PGresult *res; + + serverid = get_foreign_server_oid(remote_server_fdwname, true); + Assert(OidIsValid(serverid)); + + user = GetUserMapping(GetUserId(), serverid); + conn = GetConnection(user, true); + + set_portable_output(true); + plan = nodeToString(queryDesc->plannedstmt); + set_portable_output(false); + plen = b64_enc_len(plan, strlen(plan) + 1); + plan_container = (char *) palloc0(plen + 1); + plen1 = b64_encode(plan, strlen(plan), plan_container); + Assert(plen > plen1); + + qlen = b64_enc_len(queryDesc->sourceText, strlen(queryDesc->sourceText) + 1); + query_container = (char *) palloc0(qlen + 1); + qlen1 = b64_encode(queryDesc->sourceText, strlen(queryDesc->sourceText), query_container); + Assert(qlen > qlen1); + + query = palloc0(qlen + plen + 100); + sprintf(query, "SELECT public.pg_exec_plan('%s', '%s');", query_container, plan_container); + + res = PQexec(conn, query); + PQclear(res); + pfree(query); + pfree(query_container); + pfree(plan_container); + } +} + +static void +HOOK_ExecEnd_injection(QueryDesc *queryDesc) +{ + if (prev_ExecutorEnd) + prev_ExecutorEnd(queryDesc); + else + standard_ExecutorEnd(queryDesc); +} diff --git a/contrib/pg_repeater/pg_repeater.control b/contrib/pg_repeater/pg_repeater.control new file mode 100644 index 0000000000..369cad48af --- /dev/null +++ b/contrib/pg_repeater/pg_repeater.control @@ -0,0 +1,6 @@ +# pg_repeater extension +comment = 'Pass raw query plan to a remote node' +default_version = '0.1' +module_pathname = '$libdir/pg_repeater' +relocatable = false +requires = 'postgres_fdw, pg_execplan' diff --git a/contrib/pg_standby/pg_standby.c b/contrib/pg_standby/pg_standby.c index 5eac2b1e49..e4136f9149 100644 --- a/contrib/pg_standby/pg_standby.c +++ b/contrib/pg_standby/pg_standby.c @@ -632,7 +632,7 @@ main(int argc, char **argv) } break; case 't': /* Trigger file */ - triggerPath = strdup(optarg); + triggerPath = pg_strdup(optarg); break; case 'w': /* Max wait time */ maxwaittime = atoi(optarg); diff --git a/contrib/pg_stat_statements/.gitignore b/contrib/pg_stat_statements/.gitignore new file mode 100644 index 0000000000..5dcb3ff972 --- /dev/null +++ b/contrib/pg_stat_statements/.gitignore @@ -0,0 +1,4 @@ +# Generated subdirectories +/log/ +/results/ +/tmp_check/ diff --git a/contrib/pg_stat_statements/Makefile b/contrib/pg_stat_statements/Makefile index ddcdb10b92..298951a5f5 100644 --- a/contrib/pg_stat_statements/Makefile +++ b/contrib/pg_stat_statements/Makefile @@ -11,6 +11,12 @@ PGFILEDESC = "pg_stat_statements - execution statistics of SQL statements" LDFLAGS_SL += $(filter -lm, $(LIBS)) +REGRESS_OPTS = --temp-config $(top_srcdir)/contrib/pg_stat_statements/pg_stat_statements.conf +REGRESS = pg_stat_statements +# Disabled because these tests require "shared_preload_libraries=pg_stat_statements", +# which typical installcheck users do not have (e.g. buildfarm clients). +NO_INSTALLCHECK = 1 + ifdef USE_PGXS PG_CONFIG = pg_config PGXS := $(shell $(PG_CONFIG) --pgxs) diff --git a/contrib/pg_stat_statements/expected/pg_stat_statements.out b/contrib/pg_stat_statements/expected/pg_stat_statements.out new file mode 100644 index 0000000000..fd53f15d8b --- /dev/null +++ b/contrib/pg_stat_statements/expected/pg_stat_statements.out @@ -0,0 +1,359 @@ +CREATE EXTENSION pg_stat_statements; +-- +-- simple and compound statements +-- +SET pg_stat_statements.track_utility = FALSE; +SELECT pg_stat_statements_reset(); + pg_stat_statements_reset +-------------------------- + +(1 row) + +SELECT 1 AS "int"; + int +----- + 1 +(1 row) + +SELECT 'hello' + -- multiline + AS "text"; + text +------- + hello +(1 row) + +SELECT 'world' AS "text"; + text +------- + world +(1 row) + +-- transaction +BEGIN; +SELECT 1 AS "int"; + int +----- + 1 +(1 row) + +SELECT 'hello' AS "text"; + text +------- + hello +(1 row) + +COMMIT; +-- compound transaction +BEGIN \; +SELECT 2.0 AS "float" \; +SELECT 'world' AS "text" \; +COMMIT; +-- compound with empty statements and spurious leading spacing +\;\; SELECT 3 + 3 \;\;\; SELECT ' ' || ' !' \;\; SELECT 1 + 4 \;; + ?column? +---------- + 5 +(1 row) + +-- non ;-terminated statements +SELECT 1 + 1 + 1 AS "add" \gset +SELECT :add + 1 + 1 AS "add" \; +SELECT :add + 1 + 1 AS "add" \gset +-- set operator +SELECT 1 AS i UNION SELECT 2 ORDER BY i; + i +--- + 1 + 2 +(2 rows) + +-- cte +WITH t(f) AS ( + VALUES (1.0), (2.0) +) + SELECT f FROM t ORDER BY f; + f +----- + 1.0 + 2.0 +(2 rows) + +SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; + query | calls | rows +-----------------------------------------+-------+------ + SELECT ? +| 4 | 4 + +| | + AS "text" | | + SELECT ? + ? | 2 | 2 + SELECT ? + ? + ? AS "add" | 3 | 3 + SELECT ? AS "float" | 1 | 1 + SELECT ? AS "int" | 2 | 2 + SELECT ? AS i UNION SELECT ? ORDER BY i | 1 | 2 + SELECT ? || ? | 1 | 1 + SELECT pg_stat_statements_reset() | 1 | 1 + WITH t(f) AS ( +| 1 | 2 + VALUES (?), (?) +| | + ) +| | + SELECT f FROM t ORDER BY f | | +(9 rows) + +-- +-- CRUD: INSERT SELECT UPDATE DELETE on test table +-- +SELECT pg_stat_statements_reset(); + pg_stat_statements_reset +-------------------------- + +(1 row) + +-- utility "create table" should not be shown +CREATE TABLE test (a int, b char(20)); +INSERT INTO test VALUES(generate_series(1, 10), 'aaa'); +UPDATE test SET b = 'bbb' WHERE a > 7; +DELETE FROM test WHERE a > 9; +-- explicit transaction +BEGIN; +UPDATE test SET b = '111' WHERE a = 1 ; +COMMIT; +BEGIN \; +UPDATE test SET b = '222' WHERE a = 2 \; +COMMIT ; +UPDATE test SET b = '333' WHERE a = 3 \; +UPDATE test SET b = '444' WHERE a = 4 ; +BEGIN \; +UPDATE test SET b = '555' WHERE a = 5 \; +UPDATE test SET b = '666' WHERE a = 6 \; +COMMIT ; +-- SELECT with constants +SELECT * FROM test WHERE a > 5 ORDER BY a ; + a | b +---+---------------------- + 6 | 666 + 7 | aaa + 8 | bbb + 9 | bbb +(4 rows) + +SELECT * + FROM test + WHERE a > 9 + ORDER BY a ; + a | b +---+--- +(0 rows) + +-- SELECT without constants +SELECT * FROM test ORDER BY a; + a | b +---+---------------------- + 1 | 111 + 2 | 222 + 3 | 333 + 4 | 444 + 5 | 555 + 6 | 666 + 7 | aaa + 8 | bbb + 9 | bbb +(9 rows) + +SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; + query | calls | rows +---------------------------------------------------+-------+------ + DELETE FROM test WHERE a > ? | 1 | 1 + INSERT INTO test VALUES(generate_series(?, ?), ?) | 1 | 10 + SELECT * FROM test ORDER BY a | 1 | 9 + SELECT * FROM test WHERE a > ? ORDER BY a | 2 | 4 + SELECT pg_stat_statements_reset() | 1 | 1 + UPDATE test SET b = ? WHERE a = ? | 6 | 6 + UPDATE test SET b = ? WHERE a > ? | 1 | 3 +(7 rows) + +-- +-- pg_stat_statements.track = none +-- +SET pg_stat_statements.track = 'none'; +SELECT pg_stat_statements_reset(); + pg_stat_statements_reset +-------------------------- + +(1 row) + +SELECT 1 AS "one"; + one +----- + 1 +(1 row) + +SELECT 1 + 1 AS "two"; + two +----- + 2 +(1 row) + +SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; + query | calls | rows +-------+-------+------ +(0 rows) + +-- +-- pg_stat_statements.track = top +-- +SET pg_stat_statements.track = 'top'; +SELECT pg_stat_statements_reset(); + pg_stat_statements_reset +-------------------------- + +(1 row) + +DO LANGUAGE plpgsql $$ +BEGIN + -- this is a SELECT + PERFORM 'hello world'::TEXT; +END; +$$; +-- PL/pgSQL function +CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$ +DECLARE + r INTEGER; +BEGIN + SELECT (i + 1 + 1.0)::INTEGER INTO r; + RETURN r; +END; $$ LANGUAGE plpgsql; +SELECT PLUS_TWO(3); + plus_two +---------- + 5 +(1 row) + +SELECT PLUS_TWO(7); + plus_two +---------- + 9 +(1 row) + +-- SQL function --- use LIMIT to keep it from being inlined +CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS +$$ SELECT (i + 1.0)::INTEGER LIMIT 1 $$ LANGUAGE SQL; +SELECT PLUS_ONE(8); + plus_one +---------- + 9 +(1 row) + +SELECT PLUS_ONE(10); + plus_one +---------- + 11 +(1 row) + +SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; + query | calls | rows +-----------------------------------+-------+------ + SELECT ?::TEXT | 1 | 1 + SELECT PLUS_ONE(?) | 2 | 2 + SELECT PLUS_TWO(?) | 2 | 2 + SELECT pg_stat_statements_reset() | 1 | 1 +(4 rows) + +-- +-- pg_stat_statements.track = all +-- +SET pg_stat_statements.track = 'all'; +SELECT pg_stat_statements_reset(); + pg_stat_statements_reset +-------------------------- + +(1 row) + +-- we drop and recreate the functions to avoid any caching funnies +DROP FUNCTION PLUS_ONE(INTEGER); +DROP FUNCTION PLUS_TWO(INTEGER); +-- PL/pgSQL function +CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$ +DECLARE + r INTEGER; +BEGIN + SELECT (i + 1 + 1.0)::INTEGER INTO r; + RETURN r; +END; $$ LANGUAGE plpgsql; +SELECT PLUS_TWO(-1); + plus_two +---------- + 1 +(1 row) + +SELECT PLUS_TWO(2); + plus_two +---------- + 4 +(1 row) + +-- SQL function --- use LIMIT to keep it from being inlined +CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS +$$ SELECT (i + 1.0)::INTEGER LIMIT 1 $$ LANGUAGE SQL; +SELECT PLUS_ONE(3); + plus_one +---------- + 4 +(1 row) + +SELECT PLUS_ONE(1); + plus_one +---------- + 2 +(1 row) + +SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; + query | calls | rows +-----------------------------------+-------+------ + SELECT (i + ? + ?)::INTEGER | 2 | 2 + SELECT (i + ?)::INTEGER LIMIT ? | 2 | 2 + SELECT PLUS_ONE(?) | 2 | 2 + SELECT PLUS_TWO(?) | 2 | 2 + SELECT pg_stat_statements_reset() | 1 | 1 +(5 rows) + +-- +-- utility commands +-- +SET pg_stat_statements.track_utility = TRUE; +SELECT pg_stat_statements_reset(); + pg_stat_statements_reset +-------------------------- + +(1 row) + +SELECT 1; + ?column? +---------- + 1 +(1 row) + +CREATE INDEX test_b ON test(b); +DROP TABLE test \; +DROP TABLE IF EXISTS test \; +DROP FUNCTION PLUS_ONE(INTEGER); +NOTICE: table "test" does not exist, skipping +DROP TABLE IF EXISTS test \; +DROP TABLE IF EXISTS test \; +DROP FUNCTION IF EXISTS PLUS_ONE(INTEGER); +NOTICE: table "test" does not exist, skipping +NOTICE: table "test" does not exist, skipping +NOTICE: function plus_one(pg_catalog.int4) does not exist, skipping +DROP FUNCTION PLUS_TWO(INTEGER); +SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; + query | calls | rows +-------------------------------------------+-------+------ + CREATE INDEX test_b ON test(b) | 1 | 0 + DROP FUNCTION IF EXISTS PLUS_ONE(INTEGER) | 1 | 0 + DROP FUNCTION PLUS_ONE(INTEGER) | 1 | 0 + DROP FUNCTION PLUS_TWO(INTEGER) | 1 | 0 + DROP TABLE IF EXISTS test | 3 | 0 + DROP TABLE test | 1 | 0 + SELECT ? | 1 | 1 + SELECT pg_stat_statements_reset() | 1 | 1 +(8 rows) + +DROP EXTENSION pg_stat_statements; diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c index 3d9b8e45d9..6edc3d926b 100644 --- a/contrib/pg_stat_statements/pg_stat_statements.c +++ b/contrib/pg_stat_statements/pg_stat_statements.c @@ -48,7 +48,7 @@ * in the file to be read or written while holding only shared lock. * * - * Copyright (c) 2008-2016, PostgreSQL Global Development Group + * Copyright (c) 2008-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/pg_stat_statements/pg_stat_statements.c @@ -69,6 +69,7 @@ #include "parser/analyze.h" #include "parser/parsetree.h" #include "parser/scanner.h" +#include "parser/scansup.h" #include "pgstat.h" #include "storage/fd.h" #include "storage/ipc.h" @@ -292,13 +293,14 @@ static void pgss_ExecutorRun(QueryDesc *queryDesc, uint64 count); static void pgss_ExecutorFinish(QueryDesc *queryDesc); static void pgss_ExecutorEnd(QueryDesc *queryDesc); -static void pgss_ProcessUtility(Node *parsetree, const char *queryString, +static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag); static uint32 pgss_hash_fn(const void *key, Size keysize); static int pgss_match_fn(const void *key1, const void *key2, Size keysize); -static uint32 pgss_hash_string(const char *str); +static uint32 pgss_hash_string(const char *str, int len); static void pgss_store(const char *query, uint32 queryId, + int query_location, int query_len, double total_time, uint64 rows, const BufferUsage *bufusage, pgssJumbleState *jstate); @@ -324,8 +326,9 @@ static void JumbleRangeTable(pgssJumbleState *jstate, List *rtable); static void JumbleExpr(pgssJumbleState *jstate, Node *node); static void RecordConstLocation(pgssJumbleState *jstate, int location); static char *generate_normalized_query(pgssJumbleState *jstate, const char *query, - int *query_len_p, int encoding); -static void fill_in_constant_lengths(pgssJumbleState *jstate, const char *query); + int query_loc, int *query_len_p, int encoding); +static void fill_in_constant_lengths(pgssJumbleState *jstate, const char *query, + int query_loc); static int comp_location(const void *a, const void *b); @@ -822,6 +825,8 @@ pgss_post_parse_analyze(ParseState *pstate, Query *query) if (jstate.clocations_count > 0) pgss_store(pstate->p_sourcetext, query->queryId, + query->stmt_location, + query->stmt_len, 0, 0, NULL, @@ -926,6 +931,8 @@ pgss_ExecutorEnd(QueryDesc *queryDesc) pgss_store(queryDesc->sourceText, queryId, + queryDesc->plannedstmt->stmt_location, + queryDesc->plannedstmt->stmt_len, queryDesc->totaltime->total * 1000.0, /* convert to msec */ queryDesc->estate->es_processed, &queryDesc->totaltime->bufusage, @@ -942,10 +949,12 @@ pgss_ExecutorEnd(QueryDesc *queryDesc) * ProcessUtility hook */ static void -pgss_ProcessUtility(Node *parsetree, const char *queryString, +pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag) { + Node *parsetree = pstmt->utilityStmt; + /* * If it's an EXECUTE statement, we don't track it and don't increment the * nesting level. This allows the cycles to be charged to the underlying @@ -970,7 +979,6 @@ pgss_ProcessUtility(Node *parsetree, const char *queryString, uint64 rows; BufferUsage bufusage_start, bufusage; - uint32 queryId; bufusage_start = pgBufferUsage; INSTR_TIME_SET_CURRENT(start); @@ -979,11 +987,11 @@ pgss_ProcessUtility(Node *parsetree, const char *queryString, PG_TRY(); { if (prev_ProcessUtility) - prev_ProcessUtility(parsetree, queryString, + prev_ProcessUtility(pstmt, queryString, context, params, dest, completionTag); else - standard_ProcessUtility(parsetree, queryString, + standard_ProcessUtility(pstmt, queryString, context, params, dest, completionTag); nested_level--; @@ -1031,11 +1039,10 @@ pgss_ProcessUtility(Node *parsetree, const char *queryString, bufusage.blk_write_time = pgBufferUsage.blk_write_time; INSTR_TIME_SUBTRACT(bufusage.blk_write_time, bufusage_start.blk_write_time); - /* For utility statements, we just hash the query string directly */ - queryId = pgss_hash_string(queryString); - pgss_store(queryString, - queryId, + 0, /* signal that it's a utility stmt */ + pstmt->stmt_location, + pstmt->stmt_len, INSTR_TIME_GET_MILLISEC(duration), rows, &bufusage, @@ -1044,11 +1051,11 @@ pgss_ProcessUtility(Node *parsetree, const char *queryString, else { if (prev_ProcessUtility) - prev_ProcessUtility(parsetree, queryString, + prev_ProcessUtility(pstmt, queryString, context, params, dest, completionTag); else - standard_ProcessUtility(parsetree, queryString, + standard_ProcessUtility(pstmt, queryString, context, params, dest, completionTag); } @@ -1090,20 +1097,24 @@ pgss_match_fn(const void *key1, const void *key2, Size keysize) * utility statements. */ static uint32 -pgss_hash_string(const char *str) +pgss_hash_string(const char *str, int len) { - return hash_any((const unsigned char *) str, strlen(str)); + return hash_any((const unsigned char *) str, len); } /* * Store some statistics for a statement. * + * If queryId is 0 then this is a utility statement and we should compute + * a suitable queryId internally. + * * If jstate is not NULL then we're trying to create an entry for which * we have no statistics as yet; we just want to record the normalized * query string. total_time, rows, bufusage are ignored in this case. */ static void pgss_store(const char *query, uint32 queryId, + int query_location, int query_len, double total_time, uint64 rows, const BufferUsage *bufusage, pgssJumbleState *jstate) @@ -1112,7 +1123,6 @@ pgss_store(const char *query, uint32 queryId, pgssEntry *entry; char *norm_query = NULL; int encoding = GetDatabaseEncoding(); - int query_len; Assert(query != NULL); @@ -1120,7 +1130,43 @@ pgss_store(const char *query, uint32 queryId, if (!pgss || !pgss_hash) return; - query_len = strlen(query); + /* + * Confine our attention to the relevant part of the string, if the query + * is a portion of a multi-statement source string. + * + * First apply starting offset, unless it's -1 (unknown). + */ + if (query_location >= 0) + { + Assert(query_location <= strlen(query)); + query += query_location; + /* Length of 0 (or -1) means "rest of string" */ + if (query_len <= 0) + query_len = strlen(query); + else + Assert(query_len <= strlen(query)); + } + else + { + /* If query location is unknown, distrust query_len as well */ + query_location = 0; + query_len = strlen(query); + } + + /* + * Discard leading and trailing whitespace, too. Use scanner_isspace() + * not libc's isspace(), because we want to match the lexer's behavior. + */ + while (query_len > 0 && scanner_isspace(query[0])) + query++, query_location++, query_len--; + while (query_len > 0 && scanner_isspace(query[query_len - 1])) + query_len--; + + /* + * For utility statements, we just hash the query string to get an ID. + */ + if (queryId == 0) + queryId = pgss_hash_string(query, query_len); /* Set up key for hashtable search */ key.userid = GetUserId(); @@ -1151,6 +1197,7 @@ pgss_store(const char *query, uint32 queryId, { LWLockRelease(pgss->lock); norm_query = generate_normalized_query(jstate, query, + query_location, &query_len, encoding); LWLockAcquire(pgss->lock, LW_SHARED); @@ -1770,11 +1817,8 @@ entry_dealloc(void) } /* - * Given a null-terminated string, allocate a new entry in the external query - * text file and store the string there. - * - * Although we could compute the string length via strlen(), callers already - * have it handy, so we require them to pass it too. + * Given a query string (not necessarily null-terminated), allocate a new + * entry in the external query text file and store the string there. * * If successful, returns true, and stores the new entry's offset in the file * into *query_offset. Also, if gc_count isn't NULL, *gc_count is set to the @@ -1822,7 +1866,9 @@ qtext_store(const char *query, int query_len, if (lseek(fd, off, SEEK_SET) != off) goto error; - if (write(fd, query, query_len + 1) != query_len + 1) + if (write(fd, query, query_len) != query_len) + goto error; + if (write(fd, "\0", 1) != 1) goto error; CloseTransientFile(fd); @@ -2632,6 +2678,15 @@ JumbleExpr(pgssJumbleState *jstate, Node *node) JumbleExpr(jstate, (Node *) mmexpr->args); } break; + case T_SQLValueFunction: + { + SQLValueFunction *svf = (SQLValueFunction *) node; + + APP_JUMB(svf->op); + /* type is fully determined by op */ + APP_JUMB(svf->typmod); + } + break; case T_XmlExpr: { XmlExpr *xexpr = (XmlExpr *) node; @@ -2866,6 +2921,11 @@ RecordConstLocation(pgssJumbleState *jstate, int location) * just which "equivalent" query is used to create the hashtable entry. * We assume this is OK. * + * If query_loc > 0, then "query" has been advanced by that much compared to + * the original string start, so we need to translate the provided locations + * to compensate. (This lets us avoid re-scanning statements before the one + * of interest, so it's worth doing.) + * * *query_len_p contains the input string length, and is updated with * the result string length (which cannot be longer) on exit. * @@ -2873,7 +2933,7 @@ RecordConstLocation(pgssJumbleState *jstate, int location) */ static char * generate_normalized_query(pgssJumbleState *jstate, const char *query, - int *query_len_p, int encoding) + int query_loc, int *query_len_p, int encoding) { char *norm_query; int query_len = *query_len_p; @@ -2888,7 +2948,7 @@ generate_normalized_query(pgssJumbleState *jstate, const char *query, * Get constants' lengths (core system only gives us locations). Note * this also ensures the items are sorted by location. */ - fill_in_constant_lengths(jstate, query); + fill_in_constant_lengths(jstate, query, query_loc); /* Allocate result buffer */ norm_query = palloc(query_len + 1); @@ -2899,6 +2959,9 @@ generate_normalized_query(pgssJumbleState *jstate, const char *query, tok_len; /* Length (in bytes) of that tok */ off = jstate->clocations[i].location; + /* Adjust recorded location if we're dealing with partial string */ + off -= query_loc; + tok_len = jstate->clocations[i].length; if (tok_len < 0) @@ -2955,12 +3018,18 @@ generate_normalized_query(pgssJumbleState *jstate, const char *query, * marked as '-1', so that they are later ignored. (Actually, we assume the * lengths were initialized as -1 to start with, and don't change them here.) * + * If query_loc > 0, then "query" has been advanced by that much compared to + * the original string start, so we need to translate the provided locations + * to compensate. (This lets us avoid re-scanning statements before the one + * of interest, so it's worth doing.) + * * N.B. There is an assumption that a '-' character at a Const location begins * a negative numeric constant. This precludes there ever being another * reason for a constant to start with a '-'. */ static void -fill_in_constant_lengths(pgssJumbleState *jstate, const char *query) +fill_in_constant_lengths(pgssJumbleState *jstate, const char *query, + int query_loc) { pgssLocationLen *locs; core_yyscan_t yyscanner; @@ -2994,6 +3063,9 @@ fill_in_constant_lengths(pgssJumbleState *jstate, const char *query) int loc = locs[i].location; int tok; + /* Adjust recorded location if we're dealing with partial string */ + loc -= query_loc; + Assert(loc >= 0); if (loc <= last_loc) diff --git a/contrib/pg_stat_statements/pg_stat_statements.conf b/contrib/pg_stat_statements/pg_stat_statements.conf new file mode 100644 index 0000000000..13346e2807 --- /dev/null +++ b/contrib/pg_stat_statements/pg_stat_statements.conf @@ -0,0 +1 @@ +shared_preload_libraries = 'pg_stat_statements' diff --git a/contrib/pg_stat_statements/sql/pg_stat_statements.sql b/contrib/pg_stat_statements/sql/pg_stat_statements.sql new file mode 100644 index 0000000000..385c8a8d99 --- /dev/null +++ b/contrib/pg_stat_statements/sql/pg_stat_statements.sql @@ -0,0 +1,184 @@ +CREATE EXTENSION pg_stat_statements; + +-- +-- simple and compound statements +-- +SET pg_stat_statements.track_utility = FALSE; +SELECT pg_stat_statements_reset(); + +SELECT 1 AS "int"; + +SELECT 'hello' + -- multiline + AS "text"; + +SELECT 'world' AS "text"; + +-- transaction +BEGIN; +SELECT 1 AS "int"; +SELECT 'hello' AS "text"; +COMMIT; + +-- compound transaction +BEGIN \; +SELECT 2.0 AS "float" \; +SELECT 'world' AS "text" \; +COMMIT; + +-- compound with empty statements and spurious leading spacing +\;\; SELECT 3 + 3 \;\;\; SELECT ' ' || ' !' \;\; SELECT 1 + 4 \;; + +-- non ;-terminated statements +SELECT 1 + 1 + 1 AS "add" \gset +SELECT :add + 1 + 1 AS "add" \; +SELECT :add + 1 + 1 AS "add" \gset + +-- set operator +SELECT 1 AS i UNION SELECT 2 ORDER BY i; + +-- cte +WITH t(f) AS ( + VALUES (1.0), (2.0) +) + SELECT f FROM t ORDER BY f; + +SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; + +-- +-- CRUD: INSERT SELECT UPDATE DELETE on test table +-- +SELECT pg_stat_statements_reset(); + +-- utility "create table" should not be shown +CREATE TABLE test (a int, b char(20)); + +INSERT INTO test VALUES(generate_series(1, 10), 'aaa'); +UPDATE test SET b = 'bbb' WHERE a > 7; +DELETE FROM test WHERE a > 9; + +-- explicit transaction +BEGIN; +UPDATE test SET b = '111' WHERE a = 1 ; +COMMIT; + +BEGIN \; +UPDATE test SET b = '222' WHERE a = 2 \; +COMMIT ; + +UPDATE test SET b = '333' WHERE a = 3 \; +UPDATE test SET b = '444' WHERE a = 4 ; + +BEGIN \; +UPDATE test SET b = '555' WHERE a = 5 \; +UPDATE test SET b = '666' WHERE a = 6 \; +COMMIT ; + +-- SELECT with constants +SELECT * FROM test WHERE a > 5 ORDER BY a ; + +SELECT * + FROM test + WHERE a > 9 + ORDER BY a ; + +-- SELECT without constants +SELECT * FROM test ORDER BY a; + +SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; + +-- +-- pg_stat_statements.track = none +-- +SET pg_stat_statements.track = 'none'; +SELECT pg_stat_statements_reset(); + +SELECT 1 AS "one"; +SELECT 1 + 1 AS "two"; + +SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; + +-- +-- pg_stat_statements.track = top +-- +SET pg_stat_statements.track = 'top'; +SELECT pg_stat_statements_reset(); + +DO LANGUAGE plpgsql $$ +BEGIN + -- this is a SELECT + PERFORM 'hello world'::TEXT; +END; +$$; + +-- PL/pgSQL function +CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$ +DECLARE + r INTEGER; +BEGIN + SELECT (i + 1 + 1.0)::INTEGER INTO r; + RETURN r; +END; $$ LANGUAGE plpgsql; + +SELECT PLUS_TWO(3); +SELECT PLUS_TWO(7); + +-- SQL function --- use LIMIT to keep it from being inlined +CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS +$$ SELECT (i + 1.0)::INTEGER LIMIT 1 $$ LANGUAGE SQL; + +SELECT PLUS_ONE(8); +SELECT PLUS_ONE(10); + +SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; + +-- +-- pg_stat_statements.track = all +-- +SET pg_stat_statements.track = 'all'; +SELECT pg_stat_statements_reset(); + +-- we drop and recreate the functions to avoid any caching funnies +DROP FUNCTION PLUS_ONE(INTEGER); +DROP FUNCTION PLUS_TWO(INTEGER); + +-- PL/pgSQL function +CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$ +DECLARE + r INTEGER; +BEGIN + SELECT (i + 1 + 1.0)::INTEGER INTO r; + RETURN r; +END; $$ LANGUAGE plpgsql; + +SELECT PLUS_TWO(-1); +SELECT PLUS_TWO(2); + +-- SQL function --- use LIMIT to keep it from being inlined +CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS +$$ SELECT (i + 1.0)::INTEGER LIMIT 1 $$ LANGUAGE SQL; + +SELECT PLUS_ONE(3); +SELECT PLUS_ONE(1); + +SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; + +-- +-- utility commands +-- +SET pg_stat_statements.track_utility = TRUE; +SELECT pg_stat_statements_reset(); + +SELECT 1; +CREATE INDEX test_b ON test(b); +DROP TABLE test \; +DROP TABLE IF EXISTS test \; +DROP FUNCTION PLUS_ONE(INTEGER); +DROP TABLE IF EXISTS test \; +DROP TABLE IF EXISTS test \; +DROP FUNCTION IF EXISTS PLUS_ONE(INTEGER); +DROP FUNCTION PLUS_TWO(INTEGER); + +SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; + +DROP EXTENSION pg_stat_statements; diff --git a/contrib/pg_trgm/expected/pg_trgm.out b/contrib/pg_trgm/expected/pg_trgm.out index 9bc55f1d0d..f646cbf90a 100644 --- a/contrib/pg_trgm/expected/pg_trgm.out +++ b/contrib/pg_trgm/expected/pg_trgm.out @@ -1,4 +1,12 @@ CREATE EXTENSION pg_trgm; +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + amname | opcname +--------+--------- +(0 rows) + select show_trgm(''); show_trgm ----------- diff --git a/contrib/pg_trgm/sql/pg_trgm.sql b/contrib/pg_trgm/sql/pg_trgm.sql index 244946bb8d..34d0614edb 100644 --- a/contrib/pg_trgm/sql/pg_trgm.sql +++ b/contrib/pg_trgm/sql/pg_trgm.sql @@ -1,5 +1,10 @@ CREATE EXTENSION pg_trgm; +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + select show_trgm(''); select show_trgm('(*&^$@%@'); select show_trgm('a b c'); diff --git a/contrib/pg_trgm/trgm_regexp.c b/contrib/pg_trgm/trgm_regexp.c index 3f09a9c718..9b8ff1062d 100644 --- a/contrib/pg_trgm/trgm_regexp.c +++ b/contrib/pg_trgm/trgm_regexp.c @@ -181,7 +181,7 @@ * 7) Mark state 3 final because state 5 of source NFA is marked as final. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -529,9 +529,7 @@ createTrgmNFA(text *text_re, Oid collation, */ tmpcontext = AllocSetContextCreate(CurrentMemoryContext, "createTrgmNFA temporary context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldcontext = MemoryContextSwitchTo(tmpcontext); /* diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c index 7034066663..5580637870 100644 --- a/contrib/pg_visibility/pg_visibility.c +++ b/contrib/pg_visibility/pg_visibility.c @@ -3,6 +3,8 @@ * pg_visibility.c * display visibility map information and page-level visibility bits * + * Copyright (c) 2016-2017, PostgreSQL Global Development Group + * * contrib/pg_visibility/pg_visibility.c *------------------------------------------------------------------------- */ @@ -54,6 +56,10 @@ static bool tuple_all_visible(HeapTuple tup, TransactionId OldestXmin, /* * Visibility map information for a single block of a relation. + * + * Note: the VM code will silently return zeroes for pages past the end + * of the map, so we allow probes up to MaxBlockNumber regardless of the + * actual relation size. */ Datum pg_visibility_map(PG_FUNCTION_ARGS) @@ -122,13 +128,22 @@ pg_visibility(PG_FUNCTION_ARGS) values[0] = BoolGetDatum((mapbits & VISIBILITYMAP_ALL_VISIBLE) != 0); values[1] = BoolGetDatum((mapbits & VISIBILITYMAP_ALL_FROZEN) != 0); - buffer = ReadBuffer(rel, blkno); - LockBuffer(buffer, BUFFER_LOCK_SHARE); + /* Here we have to explicitly check rel size ... */ + if (blkno < RelationGetNumberOfBlocks(rel)) + { + buffer = ReadBuffer(rel, blkno); + LockBuffer(buffer, BUFFER_LOCK_SHARE); - page = BufferGetPage(buffer); - values[2] = BoolGetDatum(PageIsAllVisible(page)); + page = BufferGetPage(buffer); + values[2] = BoolGetDatum(PageIsAllVisible(page)); - UnlockReleaseBuffer(buffer); + UnlockReleaseBuffer(buffer); + } + else + { + /* As with the vismap, silently return 0 for pages past EOF */ + values[2] = BoolGetDatum(false); + } relation_close(rel, AccessShareLock); @@ -611,14 +626,13 @@ collect_corrupt_items(Oid relid, bool all_visible, bool all_frozen) /* Dead line pointers are neither all-visible nor frozen. */ if (ItemIdIsDead(itemid)) { - ItemPointerData tid; - - ItemPointerSet(&tid, blkno, offnum); - record_corrupt_item(items, &tid); + ItemPointerSet(&(tuple.t_self), blkno, offnum); + record_corrupt_item(items, &tuple.t_self); continue; } /* Initialize a HeapTupleData structure for checks below. */ + ItemPointerSet(&(tuple.t_self), blkno, offnum); tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid); tuple.t_len = ItemIdGetLength(itemid); tuple.t_tableOid = relid; @@ -649,12 +663,12 @@ collect_corrupt_items(Oid relid, bool all_visible, bool all_frozen) RecomputedOldestXmin = GetOldestXmin(NULL, true); if (!TransactionIdPrecedes(OldestXmin, RecomputedOldestXmin)) - record_corrupt_item(items, &tuple.t_data->t_ctid); + record_corrupt_item(items, &tuple.t_self); else { OldestXmin = RecomputedOldestXmin; if (!tuple_all_visible(&tuple, OldestXmin, buffer)) - record_corrupt_item(items, &tuple.t_data->t_ctid); + record_corrupt_item(items, &tuple.t_self); } } @@ -665,7 +679,7 @@ collect_corrupt_items(Oid relid, bool all_visible, bool all_frozen) if (check_frozen) { if (heap_tuple_needs_eventual_freeze(tuple.t_data)) - record_corrupt_item(items, &tuple.t_data->t_ctid); + record_corrupt_item(items, &tuple.t_self); } } diff --git a/contrib/pgcrypto/Makefile b/contrib/pgcrypto/Makefile index 805db7626b..f65d84d1f3 100644 --- a/contrib/pgcrypto/Makefile +++ b/contrib/pgcrypto/Makefile @@ -1,7 +1,7 @@ # contrib/pgcrypto/Makefile INT_SRCS = md5.c sha1.c sha2.c internal.c internal-sha2.c blf.c rijndael.c \ - fortuna.c random.c pgp-mpi-internal.c imath.c + pgp-mpi-internal.c imath.c INT_TESTS = sha2 OSSL_SRCS = openssl.c pgp-mpi-openssl.c diff --git a/contrib/pgcrypto/expected/pgp-compression_1.out b/contrib/pgcrypto/expected/pgp-compression_1.out new file mode 100644 index 0000000000..25d5c35bf7 --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-compression_1.out @@ -0,0 +1,42 @@ +-- +-- PGP compression support +-- +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- + +ww0ECQMCsci6AdHnELlh0kQB4jFcVwHMJg0Bulop7m3Mi36s15TAhBo0AnzIrRFrdLVCkKohsS6+ +DMcmR53SXfLoDJOv/M8uKj3QSq7oWNIp95pxfA== +=tbSn +-----END PGP MESSAGE----- +'), 'key', 'expect-compress-algo=1'); + pgp_sym_decrypt +----------------- + Secret message +(1 row) + +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret message', 'key', 'compress-algo=0'), + 'key', 'expect-compress-algo=0'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret message', 'key', 'compress-algo=1'), + 'key', 'expect-compress-algo=1'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret message', 'key', 'compress-algo=2'), + 'key', 'expect-compress-algo=2'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +-- level=0 should turn compression off +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret message', 'key', + 'compress-algo=2, compress-level=0'), + 'key', 'expect-compress-algo=0'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random diff --git a/contrib/pgcrypto/expected/pgp-decrypt_1.out b/contrib/pgcrypto/expected/pgp-decrypt_1.out new file mode 100644 index 0000000000..d9e1e386a2 --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-decrypt_1.out @@ -0,0 +1,424 @@ +-- +-- pgp_descrypt tests +-- +-- Checking ciphers +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.blowfish.sha1.mdc.s2k3.z0 + +jA0EBAMCfFNwxnvodX9g0jwB4n4s26/g5VmKzVab1bX1SmwY7gvgvlWdF3jKisvS +yA6Ce1QTMK3KdL2MPfamsTUSAML8huCJMwYQFfE= +=JcP+ +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCci97v0Q6Z0Zg0kQBsVf5Oe3iC+FBzUmuMV9KxmAyOMyjCc/5i8f1Eest +UTAsG35A1vYs02VARKzGz6xI2UHwFUirP+brPBg3Ee7muOx8pA== +=XtrP +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes192.sha1.mdc.s2k3.z0 + +jA0ECAMCI7YQpWqp3D1g0kQBCjB7GlX7+SQeXNleXeXQ78ZAPNliquGDq9u378zI +5FPTqAhIB2/2fjY8QEIs1ai00qphjX2NitxV/3Wn+6dufB4Q4g== +=rCZt +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes256.sha1.mdc.s2k3.z0 + +jA0ECQMC4f/5djqCC1Rg0kQBTHEPsD+Sw7biBsM2er3vKyGPAQkuTBGKC5ie7hT/ +lceMfQdbAg6oTFyJpk/wH18GzRDphCofg0X8uLgkAKMrpcmgog== +=fB6S +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +-- Checking MDC modes +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.nomdc.s2k3.z0 + +jA0EBwMCnv07rlXqWctgyS2Dm2JfOKCRL4sLSLJUC8RS2cH7cIhKSuLitOtyquB+ +u9YkgfJfsuRJmgQ9tmo= +=60ui +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCEeP3idNjQ1Bg0kQBf4G0wX+2QNzLh2YNwYkQgQkfYhn/hLXjV4nK9nsE +8Ex1Dsdt5UPvOz8W8VKQRS6loOfOe+yyXil8W3IYFwUpdDUi+Q== +=moGf +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +-- Checking hashes +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.md5.mdc.s2k3.z0 + +jA0EBwMClrXXtOXetohg0kQBn0Kl1ymevQZRHkdoYRHgzCwSQEiss7zYff2UNzgO +KyRrHf7zEBuZiZ2AG34jNVMOLToj1jJUg5zTSdecUzQVCykWTA== +=NyLk +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCApbdlrURoWJg0kQBzHM/E0o7djY82bNuspjxjAcPFrrtp0uvDdMQ4z2m +/PM8jhgI5vxFYfNQjLl8y3fHYIomk9YflN9K/Q13iq8A8sjeTw== +=FxbQ +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +-- Checking S2K modes +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k0.z0 + +jAQEBwAC0kQBKTaLAKE3xzps+QIZowqRNb2eAdzBw2LxEW2YD5PgNlbhJdGg+dvw +Ah9GXjGS1TVALzTImJbz1uHUZRfhJlFbc5yGQw== +=YvkV +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k1.z0 + +jAwEBwEC/QTByBLI3b/SRAHPxKzI6SZBo5lAEOD+EsvKQWO4adL9tDY+++Iqy1xK +4IaWXVKEj9R2Lr2xntWWMGZtcKtjD2lFFRXXd9dZp1ZThNDz +=dbXm +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCEq4Su3ZqNEJg0kQB4QG5jBTKF0i04xtH+avzmLhstBNRxvV3nsmB3cwl +z+9ZaA/XdSx5ZiFnMym8P6r8uY9rLjjNptvvRHlxIReF+p9MNg== +=VJKg +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes192.sha1.mdc.s2k0.z0 + +jAQECAAC0kQBBDnQWkgsx9YFaqDfWmpsiyAJ6y2xG/sBvap1dySYEMuZ+wJTXQ9E +Cr3i2M7TgVZ0M4jp4QL0adG1lpN5iK7aQeOwMw== +=cg+i +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes192.sha1.mdc.s2k1.z0 + +jAwECAECruOfyNDFiTnSRAEVoGXm4A9UZKkWljdzjEO/iaE7mIraltIpQMkiqCh9 +7h8uZ2u9uRBOv222fZodGvc6bvq/4R4hAa/6qSHtm8mdmvGt +=aHmC +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes192.sha1.mdc.s2k3.z0 + +jA0ECAMCjFn6SRi3SONg0kQBqtSHPaD0m7rXfDAhCWU/ypAsI93GuHGRyM99cvMv +q6eF6859ZVnli3BFSDSk3a4e/pXhglxmDYCfjAXkozKNYLo6yw== +=K0LS +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes256.sha1.mdc.s2k0.z0 + +jAQECQAC0kQB4L1eMbani07XF2ZYiXNK9LW3v8w41oUPl7dStmrJPQFwsdxmrDHu +rQr3WbdKdY9ufjOE5+mXI+EFkSPrF9rL9NCq6w== +=RGts +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes256.sha1.mdc.s2k1.z0 + +jAwECQECKHhrou7ZOIXSRAHWIVP+xjVQcjAVBTt+qh9SNzYe248xFTwozkwev3mO ++KVJW0qhk0An+Y2KF99/bYFl9cL5D3Tl43fC8fXGl3x3m7pR +=SUrU +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes256.sha1.mdc.s2k3.z0 + +jA0ECQMCjc8lwZu8Fz1g0kQBkEzjImi21liep5jj+3dAJ2aZFfUkohi8b3n9z+7+ +4+NRzL7cMW2RLAFnJbiqXDlRHMwleeuLN1up2WIxsxtYYuaBjA== +=XZrG +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +-- Checking longer passwords +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCx6dBiuqrYNRg0kQBEo63AvA1SCslxP7ayanLf1H0/hlk2nONVhTwVEWi +tTGup1mMz6Cfh1uDRErUuXpx9A0gdMu7zX0o5XjrL7WGDAZdSw== +=XKKG +-----END PGP MESSAGE----- +'), '0123456789abcdefghij'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCBDvYuS990iFg0kQBW31UK5OiCjWf5x6KJ8qNNT2HZWQCjCBZMU0XsOC6 +CMxFKadf144H/vpoV9GA0f22keQgCl0EsTE4V4lweVOPTKCMJg== +=gWDh +-----END PGP MESSAGE----- +'), '0123456789abcdefghij2jk4h5g2j54khg23h54g2kh54g2khj54g23hj54'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCqXbFafC+ofVg0kQBejyiPqH0QMERVGfmPOjtAxvyG5KDIJPYojTgVSDt +FwsDabdQUz5O7bgNSnxfmyw1OifGF+W2bIn/8W+0rDf8u3+O+Q== +=OxOF +-----END PGP MESSAGE----- +'), 'x'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +-- Checking various data +select encode(digest(pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCGJ+SpuOysINg0kQBJfSjzsW0x4OVcAyr17O7FBvMTwIGeGcJd99oTQU8 +Xtx3kDqnhUq9Z1fS3qPbi5iNP2A9NxOBxPWz2JzxhydANlgbxg== +=W/ik +-----END PGP MESSAGE----- +'), '0123456789abcdefghij'), 'sha1'), 'hex'); + encode +------------------------------------------ + 0225e3ede6f2587b076d021a189ff60aad67e066 +(1 row) + +-- expected: 0225e3ede6f2587b076d021a189ff60aad67e066 +select encode(digest(pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat2.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCvdpDvidNzMxg0jUBvj8eS2+1t/9/zgemxvhtc0fvdKGGbjH7dleaTJRB +SaV9L04ky1qECNDx3XjnoKLC+H7IOQ== +=Fxen +-----END PGP MESSAGE----- +'), '0123456789abcdefghij'), 'sha1'), 'hex'); + encode +------------------------------------------ + da39a3ee5e6b4b0d3255bfef95601890afd80709 +(1 row) + +-- expected: da39a3ee5e6b4b0d3255bfef95601890afd80709 +select encode(digest(pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat3.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCxQvxJZ3G/HRg0lgBeYmTa7/uDAjPyFwSX4CYBgpZWVn/JS8JzILrcWF8 +gFnkUKIE0PSaYFp+Yi1VlRfUtRQ/X/LYNGa7tWZS+4VQajz2Xtz4vUeAEiYFYPXk +73Hb8m1yRhQK +=ivrD +-----END PGP MESSAGE----- +'), '0123456789abcdefghij'), 'sha1'), 'hex'); + encode +------------------------------------------ + 5e5c135efc0dd00633efc6dfd6e731ea408a5b4c +(1 row) + +-- expected: 5e5c135efc0dd00633efc6dfd6e731ea408a5b4c +-- Checking CRLF +select encode(digest(pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: crlf mess + +ww0ECQMCt7VAtby6l4Bi0lgB5KMIZiiF/b3CfMfUyY0eDncsGXtkbu1X+l9brjpMP8eJnY79Amms +a3nsOzKTXUfS9VyaXo8IrncM6n7fdaXpwba/3tNsAhJG4lDv1k4g9v8Ix2dfv6Rs +=mBP9 +-----END PGP MESSAGE----- +'), 'key', 'convert-crlf=0'), 'sha1'), 'hex'); + encode +------------------------------------------ + 9353062be7720f1446d30b9e75573a4833886784 +(1 row) + +-- expected: 9353062be7720f1446d30b9e75573a4833886784 +select encode(digest(pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: crlf mess + +ww0ECQMCt7VAtby6l4Bi0lgB5KMIZiiF/b3CfMfUyY0eDncsGXtkbu1X+l9brjpMP8eJnY79Amms +a3nsOzKTXUfS9VyaXo8IrncM6n7fdaXpwba/3tNsAhJG4lDv1k4g9v8Ix2dfv6Rs +=mBP9 +-----END PGP MESSAGE----- +'), 'key', 'convert-crlf=1'), 'sha1'), 'hex'); + encode +------------------------------------------ + 7efefcab38467f7484d6fa43dc86cf5281bd78e2 +(1 row) + +-- expected: 7efefcab38467f7484d6fa43dc86cf5281bd78e2 +-- check BUG #11905, problem with messages 6 less than a power of 2. +select pgp_sym_decrypt(pgp_sym_encrypt(repeat('x',65530),'1'),'1') = repeat('x',65530); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +-- expected: true +-- Negative tests +-- Decryption with a certain incorrect key yields an apparent Literal Data +-- packet reporting its content to be binary data. Ciphertext source: +-- iterative pgp_sym_encrypt('secret', 'key') until the random prefix gave +-- rise to that property. +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- + +ww0EBwMCxf8PTrQBmJdl0jcB6y2joE7GSLKRv7trbNsF5Z8ou5NISLUg31llVH/S0B2wl4bvzZjV +VsxxqLSPzNLAeIspJk5G +=mSd/ +-----END PGP MESSAGE----- +'), 'wrong-key', 'debug=1'); +NOTICE: dbg: prefix_init: corrupt prefix +NOTICE: dbg: parse_literal_data: data type=b +NOTICE: dbg: mdcbuf_finish: bad MDC pkt hdr +ERROR: Wrong key or corrupt data +-- Routine text/binary mismatch. +select pgp_sym_decrypt(pgp_sym_encrypt_bytea('P', 'key'), 'key', 'debug=1'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +-- Decryption with a certain incorrect key yields an apparent BZip2-compressed +-- plaintext. Ciphertext source: iterative pgp_sym_encrypt('secret', 'key') +-- until the random prefix gave rise to that property. +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- + +ww0EBwMC9rK/dMkF5Zlt0jcBlzAQ1mQY2qYbKYbw8h3EZ5Jk0K2IiY92R82TRhWzBIF/8cmXDPtP +GXsd65oYJZp3Khz0qfyn +=Nmpq +-----END PGP MESSAGE----- +'), 'wrong-key', 'debug=1'); +NOTICE: dbg: prefix_init: corrupt prefix +NOTICE: dbg: parse_compressed_data: bzip2 unsupported +NOTICE: dbg: mdcbuf_finish: bad MDC pkt hdr +ERROR: Wrong key or corrupt data +-- Routine use of BZip2 compression. Ciphertext source: +-- echo x | gpg --homedir /nonexistent --personal-compress-preferences bzip2 \ +-- --personal-cipher-preferences aes --no-emit-version --batch \ +-- --symmetric --passphrase key --armor +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- + +jA0EBwMCRhFrAKNcLVJg0mMBLJG1cCASNk/x/3dt1zJ+2eo7jHfjgg3N6wpB3XIe +QCwkWJwlBG5pzbO5gu7xuPQN+TbPJ7aQ2sLx3bAHhtYb0i3vV9RO10Gw++yUyd4R +UCAAw2JRIISttRHMfDpDuZJpvYo= +=AZ9M +-----END PGP MESSAGE----- +'), 'key', 'debug=1'); +NOTICE: dbg: parse_compressed_data: bzip2 unsupported +ERROR: Unsupported compression algorithm diff --git a/contrib/pgcrypto/expected/pgp-encrypt-DISABLED.out b/contrib/pgcrypto/expected/pgp-encrypt-DISABLED.out deleted file mode 100644 index 4122300d97..0000000000 --- a/contrib/pgcrypto/expected/pgp-encrypt-DISABLED.out +++ /dev/null @@ -1 +0,0 @@ --- no random source diff --git a/contrib/pgcrypto/expected/pgp-encrypt_1.out b/contrib/pgcrypto/expected/pgp-encrypt_1.out new file mode 100644 index 0000000000..2291e662ec --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-encrypt_1.out @@ -0,0 +1,161 @@ +-- +-- PGP encrypt +-- +-- ensure consistent test output regardless of the default bytea format +SET bytea_output TO escape; +select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'), 'key'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +-- check whether the defaults are ok +select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'), + 'key', 'expect-cipher-algo=aes128, + expect-disable-mdc=0, + expect-sess-key=0, + expect-s2k-mode=3, + expect-s2k-digest-algo=sha1, + expect-compress-algo=0 + '); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +-- maybe the expect- stuff simply does not work +select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'), + 'key', 'expect-cipher-algo=bf, + expect-disable-mdc=1, + expect-sess-key=1, + expect-s2k-mode=0, + expect-s2k-digest-algo=md5, + expect-compress-algo=1 + '); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +-- bytea as text +select pgp_sym_decrypt(pgp_sym_encrypt_bytea('Binary', 'baz'), 'baz'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +-- text as bytea +select pgp_sym_decrypt_bytea(pgp_sym_encrypt('Text', 'baz'), 'baz'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +-- algorithm change +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=bf'), + 'key', 'expect-cipher-algo=bf'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes'), + 'key', 'expect-cipher-algo=aes128'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes192'), + 'key', 'expect-cipher-algo=aes192'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +-- s2k change +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 's2k-mode=0'), + 'key', 'expect-s2k-mode=0'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 's2k-mode=1'), + 'key', 'expect-s2k-mode=1'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 's2k-mode=3'), + 'key', 'expect-s2k-mode=3'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +-- s2k count change +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 's2k-count=1024'), + 'key', 'expect-s2k-count=1024'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +-- s2k_count rounds up +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 's2k-count=65000000'), + 'key', 'expect-s2k-count=65000000'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +-- s2k digest change +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=md5'), + 'key', 'expect-s2k-digest-algo=md5'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=sha1'), + 'key', 'expect-s2k-digest-algo=sha1'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +-- sess key +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'sess-key=0'), + 'key', 'expect-sess-key=0'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'sess-key=1'), + 'key', 'expect-sess-key=1'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'sess-key=1, cipher-algo=bf'), + 'key', 'expect-sess-key=1, expect-cipher-algo=bf'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'sess-key=1, cipher-algo=aes192'), + 'key', 'expect-sess-key=1, expect-cipher-algo=aes192'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'sess-key=1, cipher-algo=aes256'), + 'key', 'expect-sess-key=1, expect-cipher-algo=aes256'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +-- no mdc +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'disable-mdc=1'), + 'key', 'expect-disable-mdc=1'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +-- crlf +select encode(pgp_sym_decrypt_bytea( + pgp_sym_encrypt(E'1\n2\n3\r\n', 'key', 'convert-crlf=1'), + 'key'), 'hex'); +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +-- conversion should be lossless +select encode(digest(pgp_sym_decrypt( + pgp_sym_encrypt(E'\r\n0\n1\r\r\n\n2\r', 'key', 'convert-crlf=1'), + 'key', 'convert-crlf=1'), 'sha1'), 'hex') as result, + encode(digest(E'\r\n0\n1\r\r\n\n2\r', 'sha1'), 'hex') as expect; +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random diff --git a/contrib/pgcrypto/expected/pgp-pubkey-DISABLED.out b/contrib/pgcrypto/expected/pgp-pubkey-DISABLED.out deleted file mode 100644 index d35c0971ba..0000000000 --- a/contrib/pgcrypto/expected/pgp-pubkey-DISABLED.out +++ /dev/null @@ -1 +0,0 @@ --- no bignum support diff --git a/contrib/pgcrypto/expected/pgp-pubkey-encrypt_1.out b/contrib/pgcrypto/expected/pgp-pubkey-encrypt_1.out new file mode 100644 index 0000000000..3b1822ed91 --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-pubkey-encrypt_1.out @@ -0,0 +1,62 @@ +-- +-- PGP Public Key Encryption +-- +-- ensure consistent test output regardless of the default bytea format +SET bytea_output TO escape; +-- successful encrypt/decrypt +select pgp_pub_decrypt( + pgp_pub_encrypt('Secret msg', dearmor(pubkey)), + dearmor(seckey)) +from keytbl where keytbl.id=1; +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +select pgp_pub_decrypt( + pgp_pub_encrypt('Secret msg', dearmor(pubkey)), + dearmor(seckey)) +from keytbl where keytbl.id=2; +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +select pgp_pub_decrypt( + pgp_pub_encrypt('Secret msg', dearmor(pubkey)), + dearmor(seckey)) +from keytbl where keytbl.id=3; +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +select pgp_pub_decrypt( + pgp_pub_encrypt('Secret msg', dearmor(pubkey)), + dearmor(seckey)) +from keytbl where keytbl.id=6; +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +-- try with rsa-sign only +select pgp_pub_decrypt( + pgp_pub_encrypt('Secret msg', dearmor(pubkey)), + dearmor(seckey)) +from keytbl where keytbl.id=4; +ERROR: No encryption key found +-- try with secret key +select pgp_pub_decrypt( + pgp_pub_encrypt('Secret msg', dearmor(seckey)), + dearmor(seckey)) +from keytbl where keytbl.id=1; +ERROR: Refusing to encrypt with secret key +-- does text-to-bytea works +select pgp_pub_decrypt_bytea( + pgp_pub_encrypt('Secret msg', dearmor(pubkey)), + dearmor(seckey)) +from keytbl where keytbl.id=1; +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random +-- and bytea-to-text? +select pgp_pub_decrypt( + pgp_pub_encrypt_bytea('Secret msg', dearmor(pubkey)), + dearmor(seckey)) +from keytbl where keytbl.id=1; +ERROR: pg_random_bytes() is not supported by this build +DETAIL: This functionality requires a source of strong random numbers +HINT: You need to rebuild PostgreSQL using --enable-strong-random diff --git a/contrib/pgcrypto/fortuna.c b/contrib/pgcrypto/fortuna.c deleted file mode 100644 index 5028203479..0000000000 --- a/contrib/pgcrypto/fortuna.c +++ /dev/null @@ -1,463 +0,0 @@ -/* - * fortuna.c - * Fortuna-like PRNG. - * - * Copyright (c) 2005 Marko Kreen - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. - * - * contrib/pgcrypto/fortuna.c - */ - -#include "postgres.h" - -#include -#include - -#include "px.h" -#include "rijndael.h" -#include "sha2.h" -#include "fortuna.h" - - -/* - * Why Fortuna-like: There does not seem to be any definitive reference - * on Fortuna in the net. Instead this implementation is based on - * following references: - * - * http://en.wikipedia.org/wiki/Fortuna_(PRNG) - * - Wikipedia article - * http://jlcooke.ca/random/ - * - Jean-Luc Cooke Fortuna-based /dev/random driver for Linux. - */ - -/* - * There is some confusion about whether and how to carry forward - * the state of the pools. Seems like original Fortuna does not - * do it, resetting hash after each request. I guess expecting - * feeding to happen more often that requesting. This is absolutely - * unsuitable for pgcrypto, as nothing asynchronous happens here. - * - * J.L. Cooke fixed this by feeding previous hash to new re-initialized - * hash context. - * - * Fortuna predecessor Yarrow requires ability to query intermediate - * 'final result' from hash, without affecting it. - * - * This implementation uses the Yarrow method - asking intermediate - * results, but continuing with old state. - */ - - -/* - * Algorithm parameters - */ - -/* - * How many pools. - * - * Original Fortuna uses 32 pools, that means 32'th pool is - * used not earlier than in 13th year. This is a waste in - * pgcrypto, as we have very low-frequancy seeding. Here - * is preferable to have all entropy usable in reasonable time. - * - * With 23 pools, 23th pool is used after 9 days which seems - * more sane. - * - * In our case the minimal cycle time would be bit longer - * than the system-randomness feeding frequency. - */ -#define NUM_POOLS 23 - -/* in microseconds */ -#define RESEED_INTERVAL 100000 /* 0.1 sec */ - -/* for one big request, reseed after this many bytes */ -#define RESEED_BYTES (1024*1024) - -/* - * Skip reseed if pool 0 has less than this many - * bytes added since last reseed. - */ -#define POOL0_FILL (256/8) - -/* - * Algorithm constants - */ - -/* Both cipher key size and hash result size */ -#define BLOCK 32 - -/* cipher block size */ -#define CIPH_BLOCK 16 - -/* for internal wrappers */ -#define MD_CTX SHA256_CTX -#define CIPH_CTX rijndael_ctx - -struct fortuna_state -{ - uint8 counter[CIPH_BLOCK]; - uint8 result[CIPH_BLOCK]; - uint8 key[BLOCK]; - MD_CTX pool[NUM_POOLS]; - CIPH_CTX ciph; - unsigned reseed_count; - struct timeval last_reseed_time; - unsigned pool0_bytes; - unsigned rnd_pos; - int tricks_done; -}; -typedef struct fortuna_state FState; - - -/* - * Use our own wrappers here. - * - Need to get intermediate result from digest, without affecting it. - * - Need re-set key on a cipher context. - * - Algorithms are guaranteed to exist. - * - No memory allocations. - */ - -static void -ciph_init(CIPH_CTX * ctx, const uint8 *key, int klen) -{ - rijndael_set_key(ctx, (const uint32 *) key, klen, 1); -} - -static void -ciph_encrypt(CIPH_CTX * ctx, const uint8 *in, uint8 *out) -{ - rijndael_encrypt(ctx, (const uint32 *) in, (uint32 *) out); -} - -static void -md_init(MD_CTX * ctx) -{ - SHA256_Init(ctx); -} - -static void -md_update(MD_CTX * ctx, const uint8 *data, int len) -{ - SHA256_Update(ctx, data, len); -} - -static void -md_result(MD_CTX * ctx, uint8 *dst) -{ - SHA256_CTX tmp; - - memcpy(&tmp, ctx, sizeof(*ctx)); - SHA256_Final(dst, &tmp); - px_memset(&tmp, 0, sizeof(tmp)); -} - -/* - * initialize state - */ -static void -init_state(FState *st) -{ - int i; - - memset(st, 0, sizeof(*st)); - for (i = 0; i < NUM_POOLS; i++) - md_init(&st->pool[i]); -} - -/* - * Endianess does not matter. - * It just needs to change without repeating. - */ -static void -inc_counter(FState *st) -{ - uint32 *val = (uint32 *) st->counter; - - if (++val[0]) - return; - if (++val[1]) - return; - if (++val[2]) - return; - ++val[3]; -} - -/* - * This is called 'cipher in counter mode'. - */ -static void -encrypt_counter(FState *st, uint8 *dst) -{ - ciph_encrypt(&st->ciph, st->counter, dst); - inc_counter(st); -} - - -/* - * The time between reseed must be at least RESEED_INTERVAL - * microseconds. - */ -static int -enough_time_passed(FState *st) -{ - int ok; - struct timeval tv; - struct timeval *last = &st->last_reseed_time; - - gettimeofday(&tv, NULL); - - /* check how much time has passed */ - ok = 0; - if (tv.tv_sec > last->tv_sec + 1) - ok = 1; - else if (tv.tv_sec == last->tv_sec + 1) - { - if (1000000 + tv.tv_usec - last->tv_usec >= RESEED_INTERVAL) - ok = 1; - } - else if (tv.tv_usec - last->tv_usec >= RESEED_INTERVAL) - ok = 1; - - /* reseed will happen, update last_reseed_time */ - if (ok) - memcpy(last, &tv, sizeof(tv)); - - px_memset(&tv, 0, sizeof(tv)); - - return ok; -} - -/* - * generate new key from all the pools - */ -static void -reseed(FState *st) -{ - unsigned k; - unsigned n; - MD_CTX key_md; - uint8 buf[BLOCK]; - - /* set pool as empty */ - st->pool0_bytes = 0; - - /* - * Both #0 and #1 reseed would use only pool 0. Just skip #0 then. - */ - n = ++st->reseed_count; - - /* - * The goal: use k-th pool only 1/(2^k) of the time. - */ - md_init(&key_md); - for (k = 0; k < NUM_POOLS; k++) - { - md_result(&st->pool[k], buf); - md_update(&key_md, buf, BLOCK); - - if (n & 1 || !n) - break; - n >>= 1; - } - - /* add old key into mix too */ - md_update(&key_md, st->key, BLOCK); - - /* now we have new key */ - md_result(&key_md, st->key); - - /* use new key */ - ciph_init(&st->ciph, st->key, BLOCK); - - px_memset(&key_md, 0, sizeof(key_md)); - px_memset(buf, 0, BLOCK); -} - -/* - * Pick a random pool. This uses key bytes as random source. - */ -static unsigned -get_rand_pool(FState *st) -{ - unsigned rnd; - - /* - * This slightly prefers lower pools - that is OK. - */ - rnd = st->key[st->rnd_pos] % NUM_POOLS; - - st->rnd_pos++; - if (st->rnd_pos >= BLOCK) - st->rnd_pos = 0; - - return rnd; -} - -/* - * update pools - */ -static void -add_entropy(FState *st, const uint8 *data, unsigned len) -{ - unsigned pos; - uint8 hash[BLOCK]; - MD_CTX md; - - /* hash given data */ - md_init(&md); - md_update(&md, data, len); - md_result(&md, hash); - - /* - * Make sure the pool 0 is initialized, then update randomly. - */ - if (st->reseed_count == 0) - pos = 0; - else - pos = get_rand_pool(st); - md_update(&st->pool[pos], hash, BLOCK); - - if (pos == 0) - st->pool0_bytes += len; - - px_memset(hash, 0, BLOCK); - px_memset(&md, 0, sizeof(md)); -} - -/* - * Just take 2 next blocks as new key - */ -static void -rekey(FState *st) -{ - encrypt_counter(st, st->key); - encrypt_counter(st, st->key + CIPH_BLOCK); - ciph_init(&st->ciph, st->key, BLOCK); -} - -/* - * Hide public constants. (counter, pools > 0) - * - * This can also be viewed as spreading the startup - * entropy over all of the components. - */ -static void -startup_tricks(FState *st) -{ - int i; - uint8 buf[BLOCK]; - - /* Use next block as counter. */ - encrypt_counter(st, st->counter); - - /* Now shuffle pools, excluding #0 */ - for (i = 1; i < NUM_POOLS; i++) - { - encrypt_counter(st, buf); - encrypt_counter(st, buf + CIPH_BLOCK); - md_update(&st->pool[i], buf, BLOCK); - } - px_memset(buf, 0, BLOCK); - - /* Hide the key. */ - rekey(st); - - /* This can be done only once. */ - st->tricks_done = 1; -} - -static void -extract_data(FState *st, unsigned count, uint8 *dst) -{ - unsigned n; - unsigned block_nr = 0; - - /* Should we reseed? */ - if (st->pool0_bytes >= POOL0_FILL || st->reseed_count == 0) - if (enough_time_passed(st)) - reseed(st); - - /* Do some randomization on first call */ - if (!st->tricks_done) - startup_tricks(st); - - while (count > 0) - { - /* produce bytes */ - encrypt_counter(st, st->result); - - /* copy result */ - if (count > CIPH_BLOCK) - n = CIPH_BLOCK; - else - n = count; - memcpy(dst, st->result, n); - dst += n; - count -= n; - - /* must not give out too many bytes with one key */ - block_nr++; - if (block_nr > (RESEED_BYTES / CIPH_BLOCK)) - { - rekey(st); - block_nr = 0; - } - } - /* Set new key for next request. */ - rekey(st); -} - -/* - * public interface - */ - -static FState main_state; -static int init_done = 0; - -void -fortuna_add_entropy(const uint8 *data, unsigned len) -{ - if (!init_done) - { - init_state(&main_state); - init_done = 1; - } - if (!data || !len) - return; - add_entropy(&main_state, data, len); -} - -void -fortuna_get_bytes(unsigned len, uint8 *dst) -{ - if (!init_done) - { - init_state(&main_state); - init_done = 1; - } - if (!dst || !len) - return; - extract_data(&main_state, len, dst); -} diff --git a/contrib/pgcrypto/fortuna.h b/contrib/pgcrypto/fortuna.h deleted file mode 100644 index bf9f4768d1..0000000000 --- a/contrib/pgcrypto/fortuna.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * fortuna.c - * Fortuna PRNG. - * - * Copyright (c) 2005 Marko Kreen - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. - * - * contrib/pgcrypto/fortuna.h - */ - -#ifndef __FORTUNA_H -#define __FORTUNA_H - -void fortuna_get_bytes(unsigned len, uint8 *dst); -void fortuna_add_entropy(const uint8 *data, unsigned len); - -#endif diff --git a/contrib/pgcrypto/internal.c b/contrib/pgcrypto/internal.c index cb8ba2633d..2516092ba4 100644 --- a/contrib/pgcrypto/internal.c +++ b/contrib/pgcrypto/internal.c @@ -38,7 +38,6 @@ #include "sha1.h" #include "blf.h" #include "rijndael.h" -#include "fortuna.h" /* * System reseeds should be separated at least this much. @@ -615,74 +614,3 @@ px_find_cipher(const char *name, PX_Cipher **res) *res = c; return 0; } - -/* - * Randomness provider - */ - -/* - * Use always strong randomness. - */ -int -px_get_pseudo_random_bytes(uint8 *dst, unsigned count) -{ - return px_get_random_bytes(dst, count); -} - -static time_t seed_time = 0; -static time_t check_time = 0; - -static void -system_reseed(void) -{ - uint8 buf[1024]; - int n; - time_t t; - int skip = 1; - - t = time(NULL); - - if (seed_time == 0) - skip = 0; - else if ((t - seed_time) < SYSTEM_RESEED_MIN) - skip = 1; - else if ((t - seed_time) > SYSTEM_RESEED_MAX) - skip = 0; - else if (check_time == 0 || - (t - check_time) > SYSTEM_RESEED_CHECK_TIME) - { - check_time = t; - - /* roll dice */ - px_get_random_bytes(buf, 1); - skip = buf[0] >= SYSTEM_RESEED_CHANCE; - } - /* clear 1 byte */ - px_memset(buf, 0, sizeof(buf)); - - if (skip) - return; - - n = px_acquire_system_randomness(buf); - if (n > 0) - fortuna_add_entropy(buf, n); - - seed_time = t; - px_memset(buf, 0, sizeof(buf)); -} - -int -px_get_random_bytes(uint8 *dst, unsigned count) -{ - system_reseed(); - fortuna_get_bytes(count, dst); - return 0; -} - -int -px_add_entropy(const uint8 *data, unsigned count) -{ - system_reseed(); - fortuna_add_entropy(data, count); - return 0; -} diff --git a/contrib/pgcrypto/openssl.c b/contrib/pgcrypto/openssl.c index 976af70591..8063f34227 100644 --- a/contrib/pgcrypto/openssl.c +++ b/contrib/pgcrypto/openssl.c @@ -34,11 +34,11 @@ #include "px.h" #include -#include -#include -#include -#include #include +#include + +#include "utils/memutils.h" +#include "utils/resowner.h" /* * Max lengths we might want to handle. @@ -47,170 +47,76 @@ #define MAX_IV (128/8) /* - * Compatibility with OpenSSL 0.9.6 - * - * It needs AES and newer DES and digest API. - */ -#if OPENSSL_VERSION_NUMBER >= 0x00907000L - -/* - * Nothing needed for OpenSSL 0.9.7+ + * Hashes */ -#include -#else /* old OPENSSL */ - /* - * Emulate OpenSSL AES. + * To make sure we don't leak OpenSSL handles on abort, we keep OSSLDigest + * objects in a linked list, allocated in TopMemoryContext. We use the + * ResourceOwner mechanism to free them on abort. */ - -#include "rijndael.c" - -#define AES_ENCRYPT 1 -#define AES_DECRYPT 0 -#define AES_KEY rijndael_ctx - -static int -AES_set_encrypt_key(const uint8 *key, int kbits, AES_KEY *ctx) +typedef struct OSSLDigest { - aes_set_key(ctx, key, kbits, 1); - return 0; -} + const EVP_MD *algo; + EVP_MD_CTX *ctx; -static int -AES_set_decrypt_key(const uint8 *key, int kbits, AES_KEY *ctx) -{ - aes_set_key(ctx, key, kbits, 0); - return 0; -} + ResourceOwner owner; + struct OSSLDigest *next; + struct OSSLDigest *prev; +} OSSLDigest; -static void -AES_ecb_encrypt(const uint8 *src, uint8 *dst, AES_KEY *ctx, int enc) -{ - memcpy(dst, src, 16); - if (enc) - aes_ecb_encrypt(ctx, dst, 16); - else - aes_ecb_decrypt(ctx, dst, 16); -} +static OSSLDigest *open_digests = NULL; +static bool digest_resowner_callback_registered = false; static void -AES_cbc_encrypt(const uint8 *src, uint8 *dst, int len, AES_KEY *ctx, uint8 *iv, int enc) +free_openssl_digest(OSSLDigest *digest) { - memcpy(dst, src, len); - if (enc) - { - aes_cbc_encrypt(ctx, iv, dst, len); - memcpy(iv, dst + len - 16, 16); - } + EVP_MD_CTX_destroy(digest->ctx); + if (digest->prev) + digest->prev->next = digest->next; else - { - aes_cbc_decrypt(ctx, iv, dst, len); - memcpy(iv, src + len - 16, 16); - } + open_digests = digest->next; + if (digest->next) + digest->next->prev = digest->prev; + pfree(digest); } /* - * Emulate DES_* API - */ - -#define DES_key_schedule des_key_schedule -#define DES_cblock des_cblock -#define DES_set_key(k, ks) \ - des_set_key((k), *(ks)) -#define DES_ecb_encrypt(i, o, k, e) \ - des_ecb_encrypt((i), (o), *(k), (e)) -#define DES_ncbc_encrypt(i, o, l, k, iv, e) \ - des_ncbc_encrypt((i), (o), (l), *(k), (iv), (e)) -#define DES_ecb3_encrypt(i, o, k1, k2, k3, e) \ - des_ecb3_encrypt((des_cblock *)(i), (des_cblock *)(o), \ - *(k1), *(k2), *(k3), (e)) -#define DES_ede3_cbc_encrypt(i, o, l, k1, k2, k3, iv, e) \ - des_ede3_cbc_encrypt((i), (o), \ - (l), *(k1), *(k2), *(k3), (iv), (e)) - -/* - * Emulate newer digest API. + * Close any open OpenSSL handles on abort. */ - static void -EVP_MD_CTX_init(EVP_MD_CTX *ctx) +digest_free_callback(ResourceReleasePhase phase, + bool isCommit, + bool isTopLevel, + void *arg) { - memset(ctx, 0, sizeof(*ctx)); -} + OSSLDigest *curr; + OSSLDigest *next; -static int -EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx) -{ - px_memset(ctx, 0, sizeof(*ctx)); - return 1; -} + if (phase != RESOURCE_RELEASE_AFTER_LOCKS) + return; -static int -EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *md, void *engine) -{ - EVP_DigestInit(ctx, md); - return 1; -} - -static int -EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *res, unsigned int *len) -{ - EVP_DigestFinal(ctx, res, len); - return 1; -} -#endif /* old OpenSSL */ - -/* - * Provide SHA2 for older OpenSSL < 0.9.8 - */ -#if OPENSSL_VERSION_NUMBER < 0x00908000L - -#include "sha2.c" -#include "internal-sha2.c" - -typedef void (*init_f) (PX_MD *md); - -static int -compat_find_digest(const char *name, PX_MD **res) -{ - init_f init = NULL; - - if (pg_strcasecmp(name, "sha224") == 0) - init = init_sha224; - else if (pg_strcasecmp(name, "sha256") == 0) - init = init_sha256; - else if (pg_strcasecmp(name, "sha384") == 0) - init = init_sha384; - else if (pg_strcasecmp(name, "sha512") == 0) - init = init_sha512; - else - return PXE_NO_HASH; + next = open_digests; + while (next) + { + curr = next; + next = curr->next; - *res = px_alloc(sizeof(PX_MD)); - init(*res); - return 0; + if (curr->owner == CurrentResourceOwner) + { + if (isCommit) + elog(WARNING, "pgcrypto digest reference leak: digest %p still referenced", curr); + free_openssl_digest(curr); + } + } } -#else -#define compat_find_digest(name, res) (PXE_NO_HASH) -#endif - -/* - * Hashes - */ - -typedef struct OSSLDigest -{ - const EVP_MD *algo; - EVP_MD_CTX ctx; -} OSSLDigest; static unsigned digest_result_size(PX_MD *h) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; - return EVP_MD_CTX_size(&digest->ctx); + return EVP_MD_CTX_size(digest->ctx); } static unsigned @@ -218,7 +124,7 @@ digest_block_size(PX_MD *h) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; - return EVP_MD_CTX_block_size(&digest->ctx); + return EVP_MD_CTX_block_size(digest->ctx); } static void @@ -226,7 +132,7 @@ digest_reset(PX_MD *h) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; - EVP_DigestInit_ex(&digest->ctx, digest->algo, NULL); + EVP_DigestInit_ex(digest->ctx, digest->algo, NULL); } static void @@ -234,7 +140,7 @@ digest_update(PX_MD *h, const uint8 *data, unsigned dlen) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; - EVP_DigestUpdate(&digest->ctx, data, dlen); + EVP_DigestUpdate(digest->ctx, data, dlen); } static void @@ -242,7 +148,7 @@ digest_finish(PX_MD *h, uint8 *dst) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; - EVP_DigestFinal_ex(&digest->ctx, dst, NULL); + EVP_DigestFinal_ex(digest->ctx, dst, NULL); } static void @@ -250,9 +156,7 @@ digest_free(PX_MD *h) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; - EVP_MD_CTX_cleanup(&digest->ctx); - - px_free(digest); + free_openssl_digest(digest); px_free(h); } @@ -264,6 +168,7 @@ int px_find_digest(const char *name, PX_MD **res) { const EVP_MD *md; + EVP_MD_CTX *ctx; PX_MD *h; OSSLDigest *digest; @@ -273,17 +178,43 @@ px_find_digest(const char *name, PX_MD **res) OpenSSL_add_all_algorithms(); } + if (!digest_resowner_callback_registered) + { + RegisterResourceReleaseCallback(digest_free_callback, NULL); + digest_resowner_callback_registered = true; + } + md = EVP_get_digestbyname(name); if (md == NULL) - return compat_find_digest(name, res); + return PXE_NO_HASH; - digest = px_alloc(sizeof(*digest)); - digest->algo = md; + /* + * Create an OSSLDigest object, an OpenSSL MD object, and a PX_MD object. + * The order is crucial, to make sure we don't leak anything on + * out-of-memory or other error. + */ + digest = MemoryContextAlloc(TopMemoryContext, sizeof(*digest)); - EVP_MD_CTX_init(&digest->ctx); - if (EVP_DigestInit_ex(&digest->ctx, digest->algo, NULL) == 0) + ctx = EVP_MD_CTX_create(); + if (!ctx) + { + pfree(digest); return -1; + } + if (EVP_DigestInit_ex(ctx, md, NULL) == 0) + { + pfree(digest); + return -1; + } + + digest->algo = md; + digest->ctx = ctx; + digest->owner = CurrentResourceOwner; + digest->next = open_digests; + digest->prev = NULL; + open_digests = digest; + /* The PX_MD object is allocated in the current memory context. */ h = px_alloc(sizeof(*h)); h->result_size = digest_result_size; h->block_size = digest_block_size; @@ -300,60 +231,101 @@ px_find_digest(const char *name, PX_MD **res) /* * Ciphers * - * The problem with OpenSSL is that the EVP* family - * of functions does not allow enough flexibility - * and forces some of the parameters (keylen, - * padding) to SSL defaults. - * - * So need to manage ciphers ourselves. + * We use OpenSSL's EVP* family of functions for these. */ +/* + * prototype for the EVP functions that return an algorithm, e.g. + * EVP_aes_128_cbc(). + */ +typedef const EVP_CIPHER *(*ossl_EVP_cipher_func)(void); + +/* + * ossl_cipher contains the static information about each cipher. + */ struct ossl_cipher { int (*init) (PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv); - int (*encrypt) (PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res); - int (*decrypt) (PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res); - + ossl_EVP_cipher_func cipher_func; int block_size; int max_key_size; - int stream_cipher; }; -typedef struct +/* + * OSSLCipher contains the state for using a cipher. A separate OSSLCipher + * object is allocated in each px_find_cipher() call. + * + * To make sure we don't leak OpenSSL handles on abort, we keep OSSLCipher + * objects in a linked list, allocated in TopMemoryContext. We use the + * ResourceOwner mechanism to free them on abort. + */ +typedef struct OSSLCipher { - union - { - struct - { - BF_KEY key; - int num; - } bf; - struct - { - DES_key_schedule key_schedule; - } des; - struct - { - DES_key_schedule k1, - k2, - k3; - } des3; - CAST_KEY cast_key; - AES_KEY aes_key; - } u; + EVP_CIPHER_CTX *evp_ctx; + const EVP_CIPHER *evp_ciph; uint8 key[MAX_KEY]; uint8 iv[MAX_IV]; unsigned klen; unsigned init; const struct ossl_cipher *ciph; -} ossldata; -/* generic */ + ResourceOwner owner; + struct OSSLCipher *next; + struct OSSLCipher *prev; +} OSSLCipher; + +static OSSLCipher *open_ciphers = NULL; +static bool cipher_resowner_callback_registered = false; + +static void +free_openssl_cipher(OSSLCipher *od) +{ + EVP_CIPHER_CTX_free(od->evp_ctx); + if (od->prev) + od->prev->next = od->next; + else + open_ciphers = od->next; + if (od->next) + od->next->prev = od->prev; + pfree(od); +} + +/* + * Close any open OpenSSL cipher handles on abort. + */ +static void +cipher_free_callback(ResourceReleasePhase phase, + bool isCommit, + bool isTopLevel, + void *arg) +{ + OSSLCipher *curr; + OSSLCipher *next; + + if (phase != RESOURCE_RELEASE_AFTER_LOCKS) + return; + + next = open_ciphers; + while (next) + { + curr = next; + next = curr->next; + + if (curr->owner == CurrentResourceOwner) + { + if (isCommit) + elog(WARNING, "pgcrypto cipher reference leak: cipher %p still referenced", curr); + free_openssl_cipher(curr); + } + } +} + +/* Common routines for all algorithms */ static unsigned gen_ossl_block_size(PX_Cipher *c) { - ossldata *od = (ossldata *) c->ptr; + OSSLCipher *od = (OSSLCipher *) c->ptr; return od->ciph->block_size; } @@ -361,7 +333,7 @@ gen_ossl_block_size(PX_Cipher *c) static unsigned gen_ossl_key_size(PX_Cipher *c) { - ossldata *od = (ossldata *) c->ptr; + OSSLCipher *od = (OSSLCipher *) c->ptr; return od->ciph->max_key_size; } @@ -370,7 +342,7 @@ static unsigned gen_ossl_iv_size(PX_Cipher *c) { unsigned ivlen; - ossldata *od = (ossldata *) c->ptr; + OSSLCipher *od = (OSSLCipher *) c->ptr; ivlen = od->ciph->block_size; return ivlen; @@ -379,13 +351,60 @@ gen_ossl_iv_size(PX_Cipher *c) static void gen_ossl_free(PX_Cipher *c) { - ossldata *od = (ossldata *) c->ptr; + OSSLCipher *od = (OSSLCipher *) c->ptr; - px_memset(od, 0, sizeof(*od)); - px_free(od); + free_openssl_cipher(od); px_free(c); } +static int +gen_ossl_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, + uint8 *res) +{ + OSSLCipher *od = c->ptr; + int outlen; + + if (!od->init) + { + if (!EVP_DecryptInit_ex(od->evp_ctx, od->evp_ciph, NULL, NULL, NULL)) + return PXE_CIPHER_INIT; + if (!EVP_CIPHER_CTX_set_key_length(od->evp_ctx, od->klen)) + return PXE_CIPHER_INIT; + if (!EVP_DecryptInit_ex(od->evp_ctx, NULL, NULL, od->key, od->iv)) + return PXE_CIPHER_INIT; + od->init = true; + } + + if (!EVP_DecryptUpdate(od->evp_ctx, res, &outlen, data, dlen)) + return PXE_DECRYPT_FAILED; + + return 0; +} + +static int +gen_ossl_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, + uint8 *res) +{ + OSSLCipher *od = c->ptr; + int outlen; + + if (!od->init) + { + if (!EVP_EncryptInit_ex(od->evp_ctx, od->evp_ciph, NULL, NULL, NULL)) + return PXE_CIPHER_INIT; + if (!EVP_CIPHER_CTX_set_key_length(od->evp_ctx, od->klen)) + return PXE_CIPHER_INIT; + if (!EVP_EncryptInit_ex(od->evp_ctx, NULL, NULL, od->key, od->iv)) + return PXE_CIPHER_INIT; + od->init = true; + } + + if (!EVP_EncryptUpdate(od->evp_ctx, res, &outlen, data, dlen)) + return PXE_ERR_GENERIC; + + return 0; +} + /* Blowfish */ /* @@ -407,24 +426,40 @@ bf_check_supported_key_len(void) static const uint8 data[8] = {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}; static const uint8 res[8] = {0xc0, 0x45, 0x04, 0x01, 0x2e, 0x4e, 0x1f, 0x53}; - static uint8 out[8]; - - BF_KEY bf_key; + uint8 out[8]; + EVP_CIPHER_CTX *evp_ctx; + int outlen; + int status = 0; /* encrypt with 448bits key and verify output */ - BF_set_key(&bf_key, 56, key); - BF_ecb_encrypt(data, out, &bf_key, BF_ENCRYPT); + evp_ctx = EVP_CIPHER_CTX_new(); + if (!evp_ctx) + return 0; + if (!EVP_EncryptInit_ex(evp_ctx, EVP_bf_ecb(), NULL, NULL, NULL)) + goto leave; + if (!EVP_CIPHER_CTX_set_key_length(evp_ctx, 56)) + goto leave; + if (!EVP_EncryptInit_ex(evp_ctx, NULL, NULL, key, NULL)) + goto leave; + + if (!EVP_EncryptUpdate(evp_ctx, out, &outlen, data, 8)) + goto leave; if (memcmp(out, res, 8) != 0) - return 0; /* Output does not match -> strong cipher is + goto leave; /* Output does not match -> strong cipher is * not supported */ - return 1; + status = 1; + +leave: + EVP_CIPHER_CTX_free(evp_ctx); + return status; } static int bf_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) { - ossldata *od = c->ptr; + OSSLCipher *od = c->ptr; + unsigned bs = gen_ossl_block_size(c); static int bf_is_strong = -1; /* @@ -440,74 +475,13 @@ bf_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) return PXE_KEY_TOO_BIG; /* Key len is supported. We can use it. */ - BF_set_key(&od->u.bf.key, klen, key); + od->klen = klen; + memcpy(od->key, key, klen); + if (iv) - memcpy(od->iv, iv, BF_BLOCK); + memcpy(od->iv, iv, bs); else - memset(od->iv, 0, BF_BLOCK); - od->u.bf.num = 0; - return 0; -} - -static int -bf_ecb_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) -{ - unsigned bs = gen_ossl_block_size(c); - unsigned i; - ossldata *od = c->ptr; - - for (i = 0; i < dlen / bs; i++) - BF_ecb_encrypt(data + i * bs, res + i * bs, &od->u.bf.key, BF_ENCRYPT); - return 0; -} - -static int -bf_ecb_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) -{ - unsigned bs = gen_ossl_block_size(c), - i; - ossldata *od = c->ptr; - - for (i = 0; i < dlen / bs; i++) - BF_ecb_encrypt(data + i * bs, res + i * bs, &od->u.bf.key, BF_DECRYPT); - return 0; -} - -static int -bf_cbc_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) -{ - ossldata *od = c->ptr; - - BF_cbc_encrypt(data, res, dlen, &od->u.bf.key, od->iv, BF_ENCRYPT); - return 0; -} - -static int -bf_cbc_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) -{ - ossldata *od = c->ptr; - - BF_cbc_encrypt(data, res, dlen, &od->u.bf.key, od->iv, BF_DECRYPT); - return 0; -} - -static int -bf_cfb64_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) -{ - ossldata *od = c->ptr; - - BF_cfb64_encrypt(data, res, dlen, &od->u.bf.key, od->iv, - &od->u.bf.num, BF_ENCRYPT); - return 0; -} - -static int -bf_cfb64_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) -{ - ossldata *od = c->ptr; - - BF_cfb64_encrypt(data, res, dlen, &od->u.bf.key, od->iv, - &od->u.bf.num, BF_DECRYPT); + memset(od->iv, 0, bs); return 0; } @@ -516,70 +490,17 @@ bf_cfb64_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) static int ossl_des_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) { - ossldata *od = c->ptr; - DES_cblock xkey; + OSSLCipher *od = c->ptr; + unsigned bs = gen_ossl_block_size(c); - memset(&xkey, 0, sizeof(xkey)); - memcpy(&xkey, key, klen > 8 ? 8 : klen); - DES_set_key(&xkey, &od->u.des.key_schedule); - memset(&xkey, 0, sizeof(xkey)); + od->klen = 8; + memset(od->key, 0, 8); + memcpy(od->key, key, klen > 8 ? 8 : klen); if (iv) - memcpy(od->iv, iv, 8); + memcpy(od->iv, iv, bs); else - memset(od->iv, 0, 8); - return 0; -} - -static int -ossl_des_ecb_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) -{ - unsigned bs = gen_ossl_block_size(c); - unsigned i; - ossldata *od = c->ptr; - - for (i = 0; i < dlen / bs; i++) - DES_ecb_encrypt((DES_cblock *) (data + i * bs), - (DES_cblock *) (res + i * bs), - &od->u.des.key_schedule, 1); - return 0; -} - -static int -ossl_des_ecb_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) -{ - unsigned bs = gen_ossl_block_size(c); - unsigned i; - ossldata *od = c->ptr; - - for (i = 0; i < dlen / bs; i++) - DES_ecb_encrypt((DES_cblock *) (data + i * bs), - (DES_cblock *) (res + i * bs), - &od->u.des.key_schedule, 0); - return 0; -} - -static int -ossl_des_cbc_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) -{ - ossldata *od = c->ptr; - - DES_ncbc_encrypt(data, res, dlen, &od->u.des.key_schedule, - (DES_cblock *) od->iv, 1); - return 0; -} - -static int -ossl_des_cbc_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) -{ - ossldata *od = c->ptr; - - DES_ncbc_encrypt(data, res, dlen, &od->u.des.key_schedule, - (DES_cblock *) od->iv, 0); + memset(od->iv, 0, bs); return 0; } @@ -588,83 +509,17 @@ ossl_des_cbc_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, static int ossl_des3_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) { - ossldata *od = c->ptr; - DES_cblock xkey1, - xkey2, - xkey3; - - memset(&xkey1, 0, sizeof(xkey1)); - memset(&xkey2, 0, sizeof(xkey2)); - memset(&xkey3, 0, sizeof(xkey3)); - memcpy(&xkey1, key, klen > 8 ? 8 : klen); - if (klen > 8) - memcpy(&xkey2, key + 8, (klen - 8) > 8 ? 8 : (klen - 8)); - if (klen > 16) - memcpy(&xkey3, key + 16, (klen - 16) > 8 ? 8 : (klen - 16)); - - DES_set_key(&xkey1, &od->u.des3.k1); - DES_set_key(&xkey2, &od->u.des3.k2); - DES_set_key(&xkey3, &od->u.des3.k3); - memset(&xkey1, 0, sizeof(xkey1)); - memset(&xkey2, 0, sizeof(xkey2)); - memset(&xkey3, 0, sizeof(xkey3)); - - if (iv) - memcpy(od->iv, iv, 8); - else - memset(od->iv, 0, 8); - return 0; -} - -static int -ossl_des3_ecb_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) -{ + OSSLCipher *od = c->ptr; unsigned bs = gen_ossl_block_size(c); - unsigned i; - ossldata *od = c->ptr; - for (i = 0; i < dlen / bs; i++) - DES_ecb3_encrypt((void *) (data + i * bs), (void *) (res + i * bs), - &od->u.des3.k1, &od->u.des3.k2, &od->u.des3.k3, 1); - return 0; -} - -static int -ossl_des3_ecb_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) -{ - unsigned bs = gen_ossl_block_size(c); - unsigned i; - ossldata *od = c->ptr; - - for (i = 0; i < dlen / bs; i++) - DES_ecb3_encrypt((void *) (data + i * bs), (void *) (res + i * bs), - &od->u.des3.k1, &od->u.des3.k2, &od->u.des3.k3, 0); - return 0; -} - -static int -ossl_des3_cbc_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) -{ - ossldata *od = c->ptr; + od->klen = 24; + memset(od->key, 0, 24); + memcpy(od->key, key, klen > 24 ? 24 : klen); - DES_ede3_cbc_encrypt(data, res, dlen, - &od->u.des3.k1, &od->u.des3.k2, &od->u.des3.k3, - (DES_cblock *) od->iv, 1); - return 0; -} - -static int -ossl_des3_cbc_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) -{ - ossldata *od = c->ptr; - - DES_ede3_cbc_encrypt(data, res, dlen, - &od->u.des3.k1, &od->u.des3.k2, &od->u.des3.k3, - (DES_cblock *) od->iv, 0); + if (iv) + memcpy(od->iv, iv, bs); + else + memset(od->iv, 0, bs); return 0; } @@ -673,10 +528,12 @@ ossl_des3_cbc_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, static int ossl_cast_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) { - ossldata *od = c->ptr; + OSSLCipher *od = c->ptr; unsigned bs = gen_ossl_block_size(c); - CAST_set_key(&od->u.cast_key, klen, key); + od->klen = klen; + memcpy(od->key, key, klen); + if (iv) memcpy(od->iv, iv, bs); else @@ -684,54 +541,12 @@ ossl_cast_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) return 0; } -static int -ossl_cast_ecb_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) -{ - unsigned bs = gen_ossl_block_size(c); - ossldata *od = c->ptr; - const uint8 *end = data + dlen - bs; - - for (; data <= end; data += bs, res += bs) - CAST_ecb_encrypt(data, res, &od->u.cast_key, CAST_ENCRYPT); - return 0; -} - -static int -ossl_cast_ecb_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) -{ - unsigned bs = gen_ossl_block_size(c); - ossldata *od = c->ptr; - const uint8 *end = data + dlen - bs; - - for (; data <= end; data += bs, res += bs) - CAST_ecb_encrypt(data, res, &od->u.cast_key, CAST_DECRYPT); - return 0; -} - -static int -ossl_cast_cbc_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) -{ - ossldata *od = c->ptr; - - CAST_cbc_encrypt(data, res, dlen, &od->u.cast_key, od->iv, CAST_ENCRYPT); - return 0; -} - -static int -ossl_cast_cbc_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) -{ - ossldata *od = c->ptr; - - CAST_cbc_encrypt(data, res, dlen, &od->u.cast_key, od->iv, CAST_DECRYPT); - return 0; -} - /* AES */ static int ossl_aes_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) { - ossldata *od = c->ptr; + OSSLCipher *od = c->ptr; unsigned bs = gen_ossl_block_size(c); if (klen <= 128 / 8) @@ -749,96 +564,68 @@ ossl_aes_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) memcpy(od->iv, iv, bs); else memset(od->iv, 0, bs); + return 0; } static int -ossl_aes_key_init(ossldata *od, int type) +ossl_aes_ecb_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) { + OSSLCipher *od = c->ptr; int err; - /* - * Strong key support could be missing on some openssl installations. We - * must check return value from set key function. - */ - if (type == AES_ENCRYPT) - err = AES_set_encrypt_key(od->key, od->klen * 8, &od->u.aes_key); - else - err = AES_set_decrypt_key(od->key, od->klen * 8, &od->u.aes_key); + err = ossl_aes_init(c, key, klen, iv); + if (err) + return err; - if (err == 0) + switch (od->klen) { - od->init = 1; - return 0; + case 128 / 8: + od->evp_ciph = EVP_aes_128_ecb(); + break; + case 192 / 8: + od->evp_ciph = EVP_aes_192_ecb(); + break; + case 256 / 8: + od->evp_ciph = EVP_aes_256_ecb(); + break; + default: + /* shouldn't happen */ + err = PXE_CIPHER_INIT; + break; } - od->init = 0; - return PXE_KEY_TOO_BIG; -} - -static int -ossl_aes_ecb_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) -{ - unsigned bs = gen_ossl_block_size(c); - ossldata *od = c->ptr; - const uint8 *end = data + dlen - bs; - int err; - - if (!od->init) - if ((err = ossl_aes_key_init(od, AES_ENCRYPT)) != 0) - return err; - for (; data <= end; data += bs, res += bs) - AES_ecb_encrypt(data, res, &od->u.aes_key, AES_ENCRYPT); - return 0; -} - -static int -ossl_aes_ecb_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) -{ - unsigned bs = gen_ossl_block_size(c); - ossldata *od = c->ptr; - const uint8 *end = data + dlen - bs; - int err; - - if (!od->init) - if ((err = ossl_aes_key_init(od, AES_DECRYPT)) != 0) - return err; - - for (; data <= end; data += bs, res += bs) - AES_ecb_encrypt(data, res, &od->u.aes_key, AES_DECRYPT); - return 0; + return err; } static int -ossl_aes_cbc_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) +ossl_aes_cbc_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) { - ossldata *od = c->ptr; + OSSLCipher *od = c->ptr; int err; - if (!od->init) - if ((err = ossl_aes_key_init(od, AES_ENCRYPT)) != 0) - return err; - - AES_cbc_encrypt(data, res, dlen, &od->u.aes_key, od->iv, AES_ENCRYPT); - return 0; -} + err = ossl_aes_init(c, key, klen, iv); + if (err) + return err; -static int -ossl_aes_cbc_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) -{ - ossldata *od = c->ptr; - int err; - - if (!od->init) - if ((err = ossl_aes_key_init(od, AES_DECRYPT)) != 0) - return err; + switch (od->klen) + { + case 128 / 8: + od->evp_ciph = EVP_aes_128_cbc(); + break; + case 192 / 8: + od->evp_ciph = EVP_aes_192_cbc(); + break; + case 256 / 8: + od->evp_ciph = EVP_aes_256_cbc(); + break; + default: + /* shouldn't happen */ + err = PXE_CIPHER_INIT; + break; + } - AES_cbc_encrypt(data, res, dlen, &od->u.aes_key, od->iv, AES_DECRYPT); - return 0; + return err; } /* @@ -864,58 +651,69 @@ static PX_Alias ossl_aliases[] = { }; static const struct ossl_cipher ossl_bf_cbc = { - bf_init, bf_cbc_encrypt, bf_cbc_decrypt, - 64 / 8, 448 / 8, 0 + bf_init, + EVP_bf_cbc, + 64 / 8, 448 / 8 }; static const struct ossl_cipher ossl_bf_ecb = { - bf_init, bf_ecb_encrypt, bf_ecb_decrypt, - 64 / 8, 448 / 8, 0 + bf_init, + EVP_bf_ecb, + 64 / 8, 448 / 8 }; static const struct ossl_cipher ossl_bf_cfb = { - bf_init, bf_cfb64_encrypt, bf_cfb64_decrypt, - 64 / 8, 448 / 8, 1 + bf_init, + EVP_bf_cfb, + 64 / 8, 448 / 8 }; static const struct ossl_cipher ossl_des_ecb = { - ossl_des_init, ossl_des_ecb_encrypt, ossl_des_ecb_decrypt, - 64 / 8, 64 / 8, 0 + ossl_des_init, + EVP_des_ecb, + 64 / 8, 64 / 8 }; static const struct ossl_cipher ossl_des_cbc = { - ossl_des_init, ossl_des_cbc_encrypt, ossl_des_cbc_decrypt, - 64 / 8, 64 / 8, 0 + ossl_des_init, + EVP_des_cbc, + 64 / 8, 64 / 8 }; static const struct ossl_cipher ossl_des3_ecb = { - ossl_des3_init, ossl_des3_ecb_encrypt, ossl_des3_ecb_decrypt, - 64 / 8, 192 / 8, 0 + ossl_des3_init, + EVP_des_ede3_ecb, + 64 / 8, 192 / 8 }; static const struct ossl_cipher ossl_des3_cbc = { - ossl_des3_init, ossl_des3_cbc_encrypt, ossl_des3_cbc_decrypt, - 64 / 8, 192 / 8, 0 + ossl_des3_init, + EVP_des_ede3_cbc, + 64 / 8, 192 / 8 }; static const struct ossl_cipher ossl_cast_ecb = { - ossl_cast_init, ossl_cast_ecb_encrypt, ossl_cast_ecb_decrypt, - 64 / 8, 128 / 8, 0 + ossl_cast_init, + EVP_cast5_ecb, + 64 / 8, 128 / 8 }; static const struct ossl_cipher ossl_cast_cbc = { - ossl_cast_init, ossl_cast_cbc_encrypt, ossl_cast_cbc_decrypt, - 64 / 8, 128 / 8, 0 + ossl_cast_init, + EVP_cast5_cbc, + 64 / 8, 128 / 8 }; static const struct ossl_cipher ossl_aes_ecb = { - ossl_aes_init, ossl_aes_ecb_encrypt, ossl_aes_ecb_decrypt, - 128 / 8, 256 / 8, 0 + ossl_aes_ecb_init, + NULL, /* EVP_aes_XXX_ecb(), determined in init function */ + 128 / 8, 256 / 8 }; static const struct ossl_cipher ossl_aes_cbc = { - ossl_aes_init, ossl_aes_cbc_encrypt, ossl_aes_cbc_decrypt, - 128 / 8, 256 / 8, 0 + ossl_aes_cbc_init, + NULL, /* EVP_aes_XXX_cbc(), determined in init function */ + 128 / 8, 256 / 8 }; /* @@ -949,7 +747,8 @@ px_find_cipher(const char *name, PX_Cipher **res) { const struct ossl_cipher_lookup *i; PX_Cipher *c = NULL; - ossldata *od; + EVP_CIPHER_CTX *ctx; + OSSLCipher *od; name = px_resolve_alias(ossl_aliases, name); for (i = ossl_cipher_types; i->name; i++) @@ -958,75 +757,48 @@ px_find_cipher(const char *name, PX_Cipher **res) if (i->name == NULL) return PXE_NO_CIPHER; - od = px_alloc(sizeof(*od)); - memset(od, 0, sizeof(*od)); + if (!cipher_resowner_callback_registered) + { + RegisterResourceReleaseCallback(cipher_free_callback, NULL); + cipher_resowner_callback_registered = true; + } + + /* + * Create an OSSLCipher object, an EVP_CIPHER_CTX object and a PX_Cipher. + * The order is crucial, to make sure we don't leak anything on + * out-of-memory or other error. + */ + od = MemoryContextAllocZero(TopMemoryContext, sizeof(*od)); od->ciph = i->ciph; + /* Allocate an EVP_CIPHER_CTX object. */ + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) + { + pfree(od); + return PXE_CIPHER_INIT; + } + + od->evp_ctx = ctx; + od->owner = CurrentResourceOwner; + od->next = open_ciphers; + od->prev = NULL; + open_ciphers = od; + + if (i->ciph->cipher_func) + od->evp_ciph = i->ciph->cipher_func(); + + /* The PX_Cipher is allocated in current memory context */ c = px_alloc(sizeof(*c)); c->block_size = gen_ossl_block_size; c->key_size = gen_ossl_key_size; c->iv_size = gen_ossl_iv_size; c->free = gen_ossl_free; c->init = od->ciph->init; - c->encrypt = od->ciph->encrypt; - c->decrypt = od->ciph->decrypt; + c->encrypt = gen_ossl_encrypt; + c->decrypt = gen_ossl_decrypt; c->ptr = od; *res = c; return 0; } - - -static int openssl_random_init = 0; - -/* - * OpenSSL random should re-feeded occasionally. From /dev/urandom - * preferably. - */ -static void -init_openssl_rand(void) -{ - if (RAND_get_rand_method() == NULL) - RAND_set_rand_method(RAND_SSLeay()); - openssl_random_init = 1; -} - -int -px_get_random_bytes(uint8 *dst, unsigned count) -{ - int res; - - if (!openssl_random_init) - init_openssl_rand(); - - res = RAND_bytes(dst, count); - if (res == 1) - return count; - - return PXE_OSSL_RAND_ERROR; -} - -int -px_get_pseudo_random_bytes(uint8 *dst, unsigned count) -{ - int res; - - if (!openssl_random_init) - init_openssl_rand(); - - res = RAND_pseudo_bytes(dst, count); - if (res == 0 || res == 1) - return count; - - return PXE_OSSL_RAND_ERROR; -} - -int -px_add_entropy(const uint8 *data, unsigned count) -{ - /* - * estimate 0 bits - */ - RAND_add(data, count, 0); - return 0; -} diff --git a/contrib/pgcrypto/pgcrypto.c b/contrib/pgcrypto/pgcrypto.c index 2d446d8cc9..d815de3073 100644 --- a/contrib/pgcrypto/pgcrypto.c +++ b/contrib/pgcrypto/pgcrypto.c @@ -34,6 +34,7 @@ #include #include "parser/scansup.h" +#include "utils/backend_random.h" #include "utils/builtins.h" #include "utils/uuid.h" @@ -422,7 +423,7 @@ PG_FUNCTION_INFO_V1(pg_random_bytes); Datum pg_random_bytes(PG_FUNCTION_ARGS) { - int err; +#ifdef HAVE_STRONG_RANDOM int len = PG_GETARG_INT32(0); bytea *res; @@ -435,13 +436,13 @@ pg_random_bytes(PG_FUNCTION_ARGS) SET_VARSIZE(res, VARHDRSZ + len); /* generate result */ - err = px_get_random_bytes((uint8 *) VARDATA(res), len); - if (err < 0) - ereport(ERROR, - (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), - errmsg("Random generator error: %s", px_strerror(err)))); + if (!pg_strong_random(VARDATA(res), len)) + px_THROW_ERROR(PXE_NO_RANDOM); PG_RETURN_BYTEA_P(res); +#else + px_THROW_ERROR(PXE_NO_RANDOM); +#endif } /* SQL function: gen_random_uuid() returns uuid */ @@ -451,14 +452,14 @@ Datum pg_random_uuid(PG_FUNCTION_ARGS) { uint8 *buf = (uint8 *) palloc(UUID_LEN); - int err; - /* generate random bits */ - err = px_get_pseudo_random_bytes(buf, UUID_LEN); - if (err < 0) - ereport(ERROR, - (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), - errmsg("Random generator error: %s", px_strerror(err)))); + /* + * Generate random bits. pg_backend_random() will do here, we don't + * promis UUIDs to be cryptographically random, when built with + * --disable-strong-random. + */ + if (!pg_backend_random((char *) buf, UUID_LEN)) + px_THROW_ERROR(PXE_NO_RANDOM); /* * Set magic numbers for a "version 4" (pseudorandom) UUID, see diff --git a/contrib/pgcrypto/pgcrypto.h b/contrib/pgcrypto/pgcrypto.h index dfc7a10590..65a1ed3157 100644 --- a/contrib/pgcrypto/pgcrypto.h +++ b/contrib/pgcrypto/pgcrypto.h @@ -34,17 +34,4 @@ #include "fmgr.h" -/* exported functions */ -Datum pg_digest(PG_FUNCTION_ARGS); -Datum pg_hmac(PG_FUNCTION_ARGS); -Datum pg_gen_salt(PG_FUNCTION_ARGS); -Datum pg_gen_salt_rounds(PG_FUNCTION_ARGS); -Datum pg_crypt(PG_FUNCTION_ARGS); -Datum pg_encrypt(PG_FUNCTION_ARGS); -Datum pg_decrypt(PG_FUNCTION_ARGS); -Datum pg_encrypt_iv(PG_FUNCTION_ARGS); -Datum pg_decrypt_iv(PG_FUNCTION_ARGS); -Datum pg_random_bytes(PG_FUNCTION_ARGS); -Datum pg_random_uuid(PG_FUNCTION_ARGS); - #endif diff --git a/contrib/pgcrypto/pgp-encrypt.c b/contrib/pgcrypto/pgp-encrypt.c index c9148fd2fc..d510729e5b 100644 --- a/contrib/pgcrypto/pgp-encrypt.c +++ b/contrib/pgcrypto/pgp-encrypt.c @@ -37,6 +37,8 @@ #include "px.h" #include "pgp.h" +#include "utils/backend_random.h" + #define MDC_DIGEST_LEN 20 #define STREAM_ID 0xE0 @@ -217,6 +219,8 @@ encrypt_free(void *priv) { struct EncStat *st = priv; + if (st->ciph) + pgp_cfb_free(st->ciph); px_memset(st, 0, sizeof(*st)); px_free(st); } @@ -477,14 +481,14 @@ init_encdata_packet(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst) static int write_prefix(PGP_Context *ctx, PushFilter *dst) { +#ifdef HAVE_STRONG_RANDOM uint8 prefix[PGP_MAX_BLOCK + 2]; int res, bs; bs = pgp_get_cipher_block_size(ctx->cipher_algo); - res = px_get_random_bytes(prefix, bs); - if (res < 0) - return res; + if (!pg_backend_random((char *) prefix, bs)) + return PXE_NO_RANDOM; prefix[bs + 0] = prefix[bs - 2]; prefix[bs + 1] = prefix[bs - 1]; @@ -492,6 +496,9 @@ write_prefix(PGP_Context *ctx, PushFilter *dst) res = pushf_write(dst, prefix, bs + 2); px_memset(prefix, 0, bs + 2); return res < 0 ? res : 0; +#else + return PXE_NO_RANDOM; +#endif } /* @@ -578,14 +585,15 @@ init_s2k_key(PGP_Context *ctx) static int init_sess_key(PGP_Context *ctx) { - int res; - if (ctx->use_sess_key || ctx->pub_key) { +#ifdef HAVE_STRONG_RANDOM ctx->sess_key_len = pgp_get_cipher_key_size(ctx->cipher_algo); - res = px_get_random_bytes(ctx->sess_key, ctx->sess_key_len); - if (res < 0) - return res; + if (!pg_strong_random((char *) ctx->sess_key, ctx->sess_key_len)) + return PXE_NO_RANDOM; +#else + return PXE_NO_RANDOM; +#endif } else { diff --git a/contrib/pgcrypto/pgp-mpi-internal.c b/contrib/pgcrypto/pgp-mpi-internal.c index be95f2d092..cb70fcba6c 100644 --- a/contrib/pgcrypto/pgp-mpi-internal.c +++ b/contrib/pgcrypto/pgp-mpi-internal.c @@ -57,17 +57,16 @@ mp_clear_free(mpz_t *a) static int mp_px_rand(uint32 bits, mpz_t *res) { - int err; +#ifdef HAVE_STRONG_RANDOM unsigned bytes = (bits + 7) / 8; int last_bits = bits & 7; uint8 *buf; buf = px_alloc(bytes); - err = px_get_random_bytes(buf, bytes); - if (err < 0) + if (!pg_strong_random((char *) buf, bytes)) { px_free(buf); - return err; + return PXE_NO_RANDOM; } /* clear unnecessary bits and set last bit to one */ @@ -84,6 +83,9 @@ mp_px_rand(uint32 bits, mpz_t *res) px_free(buf); return 0; +#else + return PXE_NO_RANDOM; +#endif } static void diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c index 1f65b667ca..ce16db71d8 100644 --- a/contrib/pgcrypto/pgp-pgsql.c +++ b/contrib/pgcrypto/pgp-pgsql.c @@ -61,65 +61,6 @@ PG_FUNCTION_INFO_V1(pg_armor); PG_FUNCTION_INFO_V1(pg_dearmor); PG_FUNCTION_INFO_V1(pgp_armor_headers); -/* - * Mix a block of data into RNG. - */ -static void -add_block_entropy(PX_MD *md, text *data) -{ - uint8 sha1[20]; - - px_md_reset(md); - px_md_update(md, (uint8 *) VARDATA(data), VARSIZE(data) - VARHDRSZ); - px_md_finish(md, sha1); - - px_add_entropy(sha1, 20); - - px_memset(sha1, 0, 20); -} - -/* - * Mix user data into RNG. It is for user own interests to have - * RNG state shuffled. - */ -static void -add_entropy(text *data1, text *data2, text *data3) -{ - PX_MD *md; - uint8 rnd[3]; - - if (!data1 && !data2 && !data3) - return; - - if (px_get_random_bytes(rnd, 3) < 0) - return; - - if (px_find_digest("sha1", &md) < 0) - return; - - /* - * Try to make the feeding unpredictable. - * - * Prefer data over keys, as it's rather likely that key is same in - * several calls. - */ - - /* chance: 7/8 */ - if (data1 && rnd[0] >= 32) - add_block_entropy(md, data1); - - /* chance: 5/8 */ - if (data2 && rnd[1] >= 160) - add_block_entropy(md, data2); - - /* chance: 5/8 */ - if (data3 && rnd[2] >= 160) - add_block_entropy(md, data3); - - px_md_free(md); - px_memset(rnd, 0, sizeof(rnd)); -} - /* * returns src in case of no conversion or error */ @@ -432,11 +373,7 @@ init_work(PGP_Context **ctx_p, int is_text, VARSIZE(args) - VARHDRSZ, ex); if (err) - { - ereport(ERROR, - (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), - errmsg("%s", px_strerror(err)))); - } + px_THROW_ERROR(err); if (ex->debug) px_set_debug_handler(show_debug); @@ -459,11 +396,6 @@ encrypt_internal(int is_pubenc, int is_text, struct debug_expect ex; text *tmp_data = NULL; - /* - * Add data and key info RNG. - */ - add_entropy(data, key, NULL); - init_work(&ctx, is_text, args, &ex); if (is_text && pgp_get_unicode_mode(ctx)) @@ -516,9 +448,7 @@ encrypt_internal(int is_pubenc, int is_text, pgp_free(ctx); mbuf_free(src); mbuf_free(dst); - ereport(ERROR, - (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), - errmsg("%s", px_strerror(err)))); + px_THROW_ERROR(err); } /* res_len includes VARHDRSZ */ @@ -605,9 +535,7 @@ decrypt_internal(int is_pubenc, int need_text, text *data, { px_set_debug_handler(NULL); mbuf_free(dst); - ereport(ERROR, - (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), - errmsg("%s", px_strerror(err)))); + px_THROW_ERROR(err); } res_len = mbuf_steal_data(dst, &restmp); @@ -629,11 +557,6 @@ decrypt_internal(int is_pubenc, int need_text, text *data, } px_set_debug_handler(NULL); - /* - * add successful decryptions also into RNG - */ - add_entropy(res, key, keypsw); - return res; } @@ -985,9 +908,7 @@ pg_dearmor(PG_FUNCTION_ARGS) ret = pgp_armor_decode((uint8 *) VARDATA(data), data_len, &buf); if (ret < 0) - ereport(ERROR, - (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), - errmsg("%s", px_strerror(ret)))); + px_THROW_ERROR(ret); res = palloc(VARHDRSZ + buf.len); SET_VARSIZE(res, VARHDRSZ + buf.len); memcpy(VARDATA(res), buf.data, buf.len); @@ -1041,9 +962,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS) &state->nheaders, &state->keys, &state->values); if (res < 0) - ereport(ERROR, - (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), - errmsg("%s", px_strerror(res)))); + px_THROW_ERROR(res); MemoryContextSwitchTo(oldcontext); funcctx->user_fctx = state; @@ -1092,9 +1011,7 @@ pgp_key_id_w(PG_FUNCTION_ARGS) res_len = pgp_get_keyid(buf, VARDATA(res)); mbuf_free(buf); if (res_len < 0) - ereport(ERROR, - (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), - errmsg("%s", px_strerror(res_len)))); + px_THROW_ERROR(res_len); SET_VARSIZE(res, VARHDRSZ + res_len); PG_FREE_IF_COPY(data, 0); diff --git a/contrib/pgcrypto/pgp-pubenc.c b/contrib/pgcrypto/pgp-pubenc.c index 3b43bb61c0..4439876664 100644 --- a/contrib/pgcrypto/pgp-pubenc.c +++ b/contrib/pgcrypto/pgp-pubenc.c @@ -39,7 +39,7 @@ static int pad_eme_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p) { - int res; +#ifdef HAVE_STRONG_RANDOM uint8 *buf, *p; int pad_len = res_len - 2 - data_len; @@ -49,11 +49,11 @@ pad_eme_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p) buf = px_alloc(res_len); buf[0] = 0x02; - res = px_get_random_bytes(buf + 1, pad_len); - if (res < 0) + + if (!pg_strong_random((char *) buf + 1, pad_len)) { px_free(buf); - return res; + return PXE_NO_RANDOM; } /* pad must not contain zero bytes */ @@ -62,26 +62,26 @@ pad_eme_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p) { if (*p == 0) { - res = px_get_random_bytes(p, 1); - if (res < 0) + if (!pg_strong_random((char *) p, 1)) + { + px_memset(buf, 0, res_len); + px_free(buf); break; + } } if (*p != 0) p++; } - if (res < 0) - { - px_memset(buf, 0, res_len); - px_free(buf); - return res; - } - buf[pad_len + 1] = 0; memcpy(buf + pad_len + 2, data, data_len); *res_p = buf; return 0; + +#else + return PXE_NO_RANDOM; +#endif } static int diff --git a/contrib/pgcrypto/pgp-s2k.c b/contrib/pgcrypto/pgp-s2k.c index 9937d154f2..a0fd8969ef 100644 --- a/contrib/pgcrypto/pgp-s2k.c +++ b/contrib/pgcrypto/pgp-s2k.c @@ -34,6 +34,8 @@ #include "px.h" #include "pgp.h" +#include "utils/backend_random.h" + static int calc_s2k_simple(PGP_S2K *s2k, PX_MD *md, const uint8 *key, unsigned key_len) @@ -233,15 +235,14 @@ pgp_s2k_fill(PGP_S2K *s2k, int mode, int digest_algo, int count) case PGP_S2K_SIMPLE: break; case PGP_S2K_SALTED: - res = px_get_pseudo_random_bytes(s2k->salt, PGP_S2K_SALT); + if (!pg_backend_random((char *) s2k->salt, PGP_S2K_SALT)) + return PXE_NO_RANDOM; break; case PGP_S2K_ISALTED: - res = px_get_pseudo_random_bytes(s2k->salt, PGP_S2K_SALT); - if (res < 0) - break; - res = px_get_pseudo_random_bytes(&tmp, 1); - if (res < 0) - break; + if (!pg_backend_random((char *) s2k->salt, PGP_S2K_SALT)) + return PXE_NO_RANDOM; + if (!pg_backend_random((char *) &tmp, 1)) + return PXE_NO_RANDOM; s2k->iter = decide_s2k_iter(tmp, count); break; default: diff --git a/contrib/pgcrypto/px-crypt.c b/contrib/pgcrypto/px-crypt.c index e3246fc5b9..6c72c4ae83 100644 --- a/contrib/pgcrypto/px-crypt.c +++ b/contrib/pgcrypto/px-crypt.c @@ -34,6 +34,7 @@ #include "px.h" #include "px-crypt.h" +#include "utils/backend_random.h" static char * run_crypt_des(const char *psw, const char *salt, @@ -132,7 +133,6 @@ static struct generator gen_list[] = { int px_gen_salt(const char *salt_type, char *buf, int rounds) { - int res; struct generator *g; char *p; char rbuf[16]; @@ -153,9 +153,8 @@ px_gen_salt(const char *salt_type, char *buf, int rounds) return PXE_BAD_SALT_ROUNDS; } - res = px_get_pseudo_random_bytes((uint8 *) rbuf, g->input_len); - if (res < 0) - return res; + if (!pg_backend_random(rbuf, g->input_len)) + return PXE_NO_RANDOM; p = g->gen(rounds, rbuf, g->input_len, buf, PX_MAX_SALT_LEN); px_memset(rbuf, 0, sizeof(rbuf)); diff --git a/contrib/pgcrypto/px.c b/contrib/pgcrypto/px.c index 7e69da696f..a5c02f3612 100644 --- a/contrib/pgcrypto/px.c +++ b/contrib/pgcrypto/px.c @@ -51,7 +51,6 @@ static const struct error_desc px_err_list[] = { {PXE_CIPHER_INIT, "Cipher cannot be initialized ?"}, {PXE_HASH_UNUSABLE_FOR_HMAC, "This hash algorithm is unusable for HMAC"}, {PXE_DEV_READ_ERROR, "Error reading from random device"}, - {PXE_OSSL_RAND_ERROR, "OpenSSL PRNG error"}, {PXE_BUG, "pgcrypto bug"}, {PXE_ARGUMENT_ERROR, "Illegal argument to function"}, {PXE_UNKNOWN_SALT_ALGO, "Unknown salt algorithm"}, @@ -67,12 +66,8 @@ static const struct error_desc px_err_list[] = { {PXE_PGP_COMPRESSION_ERROR, "Compression error"}, {PXE_PGP_NOT_TEXT, "Not text data"}, {PXE_PGP_UNEXPECTED_PKT, "Unexpected packet in key data"}, - {PXE_PGP_NO_BIGNUM, - "public-key functions disabled - " - "pgcrypto needs OpenSSL for bignums"}, {PXE_PGP_MATH_FAILED, "Math operation failed"}, {PXE_PGP_SHORT_ELGAMAL_KEY, "Elgamal keys must be at least 1024 bits long"}, - {PXE_PGP_RSA_UNSUPPORTED, "pgcrypto does not support RSA keys"}, {PXE_PGP_UNKNOWN_PUBALGO, "Unknown public-key encryption algorithm"}, {PXE_PGP_WRONG_KEY, "Wrong key"}, {PXE_PGP_MULTIPLE_KEYS, @@ -90,6 +85,39 @@ static const struct error_desc px_err_list[] = { {0, NULL}, }; +/* + * Call ereport(ERROR, ...), with an error code and message corresponding to + * the PXE_* error code given as argument. + * + * This is similar to px_strerror(err), but for some errors, we fill in the + * error code and detail fields more appropriately. + */ +void +px_THROW_ERROR(int err) +{ + if (err == PXE_NO_RANDOM) + { +#ifdef HAVE_STRONG_RANDOM + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("could not generate a random number"))); +#else + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("pg_random_bytes() is not supported by this build"), + errdetail("This functionality requires a source of strong random numbers"), + errhint("You need to rebuild PostgreSQL using --enable-strong-random"))); +#endif + } + else + { + /* For other errors, use the message from the above list. */ + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), + errmsg("%s", px_strerror(err)))); + } +} + const char * px_strerror(int err) { diff --git a/contrib/pgcrypto/px.h b/contrib/pgcrypto/px.h index 0f6bbd7a8d..00fc6f0c01 100644 --- a/contrib/pgcrypto/px.h +++ b/contrib/pgcrypto/px.h @@ -71,7 +71,6 @@ void px_free(void *p); #define PXE_CIPHER_INIT -8 #define PXE_HASH_UNUSABLE_FOR_HMAC -9 #define PXE_DEV_READ_ERROR -10 -#define PXE_OSSL_RAND_ERROR -11 #define PXE_BUG -12 #define PXE_ARGUMENT_ERROR -13 #define PXE_UNKNOWN_SALT_ALGO -14 @@ -88,10 +87,10 @@ void px_free(void *p); #define PXE_PGP_COMPRESSION_ERROR -105 #define PXE_PGP_NOT_TEXT -106 #define PXE_PGP_UNEXPECTED_PKT -107 -#define PXE_PGP_NO_BIGNUM -108 +/* -108 is unused */ #define PXE_PGP_MATH_FAILED -109 #define PXE_PGP_SHORT_ELGAMAL_KEY -110 -#define PXE_PGP_RSA_UNSUPPORTED -111 +/* -111 is unused */ #define PXE_PGP_UNKNOWN_PUBALGO -112 #define PXE_PGP_WRONG_KEY -113 #define PXE_PGP_MULTIPLE_KEYS -114 @@ -189,12 +188,7 @@ int px_find_hmac(const char *name, PX_HMAC **res); int px_find_cipher(const char *name, PX_Cipher **res); int px_find_combo(const char *name, PX_Combo **res); -int px_get_random_bytes(uint8 *dst, unsigned count); -int px_get_pseudo_random_bytes(uint8 *dst, unsigned count); -int px_add_entropy(const uint8 *data, unsigned count); - -unsigned px_acquire_system_randomness(uint8 *dst); - +void px_THROW_ERROR(int err) pg_attribute_noreturn(); const char *px_strerror(int err); const char *px_resolve_alias(const PX_Alias *aliases, const char *name); diff --git a/contrib/pgcrypto/random.c b/contrib/pgcrypto/random.c deleted file mode 100644 index d72679e412..0000000000 --- a/contrib/pgcrypto/random.c +++ /dev/null @@ -1,247 +0,0 @@ -/* - * random.c - * Acquire randomness from system. For seeding RNG. - * - * Copyright (c) 2001 Marko Kreen - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. - * - * contrib/pgcrypto/random.c - */ - -#include "postgres.h" - -#include "px.h" -#include "utils/memdebug.h" - -/* how many bytes to ask from system random provider */ -#define RND_BYTES 32 - -/* - * Try to read from /dev/urandom or /dev/random on these OS'es. - * - * The list can be pretty liberal, as the device not existing - * is expected event. - */ -#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \ - || defined(__NetBSD__) || defined(__DragonFly__) \ - || defined(__darwin__) || defined(__SOLARIS__) \ - || defined(__hpux) || defined(__HPUX__) \ - || defined(__CYGWIN__) || defined(_AIX) - -#define TRY_DEV_RANDOM - -#include -#include - -static int -safe_read(int fd, void *buf, size_t count) -{ - int done = 0; - char *p = buf; - int res; - - while (count) - { - res = read(fd, p, count); - if (res <= 0) - { - if (errno == EINTR) - continue; - return PXE_DEV_READ_ERROR; - } - p += res; - done += res; - count -= res; - } - return done; -} - -static uint8 * -try_dev_random(uint8 *dst) -{ - int fd; - int res; - - fd = open("/dev/urandom", O_RDONLY, 0); - if (fd == -1) - { - fd = open("/dev/random", O_RDONLY, 0); - if (fd == -1) - return dst; - } - res = safe_read(fd, dst, RND_BYTES); - close(fd); - if (res > 0) - dst += res; - return dst; -} -#endif - -/* - * Try to find randomness on Windows - */ -#ifdef WIN32 - -#define TRY_WIN32_GENRAND -#define TRY_WIN32_PERFC - -#include -#include - -/* - * this function is from libtomcrypt - * - * try to use Microsoft crypto API - */ -static uint8 * -try_win32_genrand(uint8 *dst) -{ - int res; - HCRYPTPROV h = 0; - - res = CryptAcquireContext(&h, NULL, MS_DEF_PROV, PROV_RSA_FULL, - (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)); - if (!res) - res = CryptAcquireContext(&h, NULL, MS_DEF_PROV, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET); - if (!res) - return dst; - - res = CryptGenRandom(h, RND_BYTES, dst); - if (res == TRUE) - dst += RND_BYTES; - - CryptReleaseContext(h, 0); - return dst; -} - -static uint8 * -try_win32_perfc(uint8 *dst) -{ - int res; - LARGE_INTEGER time; - - res = QueryPerformanceCounter(&time); - if (!res) - return dst; - - memcpy(dst, &time, sizeof(time)); - return dst + sizeof(time); -} -#endif /* WIN32 */ - - -/* - * If we are not on Windows, then hopefully we are - * on a unix-like system. Use the usual suspects - * for randomness. - */ -#ifndef WIN32 - -#define TRY_UNIXSTD - -#include -#include -#include -#include - -/* - * Everything here is predictible, only needs some patience. - * - * But there is a chance that the system-specific functions - * did not work. So keep faith and try to slow the attacker down. - */ -static uint8 * -try_unix_std(uint8 *dst) -{ - pid_t pid; - int x; - PX_MD *md; - struct timeval tv; - int res; - - /* process id */ - pid = getpid(); - memcpy(dst, (uint8 *) &pid, sizeof(pid)); - dst += sizeof(pid); - - /* time */ - gettimeofday(&tv, NULL); - memcpy(dst, (uint8 *) &tv, sizeof(tv)); - dst += sizeof(tv); - - /* pointless, but should not hurt */ - x = random(); - memcpy(dst, (uint8 *) &x, sizeof(x)); - dst += sizeof(x); - - /* hash of uninitialized stack and heap allocations */ - res = px_find_digest("sha1", &md); - if (res >= 0) - { - uint8 *ptr; - uint8 stack[8192]; - int alloc = 32 * 1024; - - VALGRIND_MAKE_MEM_DEFINED(stack, sizeof(stack)); - px_md_update(md, stack, sizeof(stack)); - ptr = px_alloc(alloc); - VALGRIND_MAKE_MEM_DEFINED(ptr, alloc); - px_md_update(md, ptr, alloc); - px_free(ptr); - - px_md_finish(md, dst); - px_md_free(md); - - dst += 20; - } - - return dst; -} -#endif - -/* - * try to extract some randomness for initial seeding - * - * dst should have room for 1024 bytes. - */ -unsigned -px_acquire_system_randomness(uint8 *dst) -{ - uint8 *p = dst; - -#ifdef TRY_DEV_RANDOM - p = try_dev_random(p); -#endif -#ifdef TRY_WIN32_GENRAND - p = try_win32_genrand(p); -#endif -#ifdef TRY_WIN32_PERFC - p = try_win32_perfc(p); -#endif -#ifdef TRY_UNIXSTD - p = try_unix_std(p); -#endif - return p - dst; -} diff --git a/contrib/pgcrypto/sql/pgp-encrypt-DISABLED.sql b/contrib/pgcrypto/sql/pgp-encrypt-DISABLED.sql deleted file mode 100644 index 4122300d97..0000000000 --- a/contrib/pgcrypto/sql/pgp-encrypt-DISABLED.sql +++ /dev/null @@ -1 +0,0 @@ --- no random source diff --git a/contrib/pgcrypto/sql/pgp-pubkey-DISABLED.sql b/contrib/pgcrypto/sql/pgp-pubkey-DISABLED.sql deleted file mode 100644 index d35c0971ba..0000000000 --- a/contrib/pgcrypto/sql/pgp-pubkey-DISABLED.sql +++ /dev/null @@ -1 +0,0 @@ --- no bignum support diff --git a/contrib/pgrowlocks/pgrowlocks.c b/contrib/pgrowlocks/pgrowlocks.c index e20e7f83de..4d49610641 100644 --- a/contrib/pgrowlocks/pgrowlocks.c +++ b/contrib/pgrowlocks/pgrowlocks.c @@ -37,6 +37,7 @@ #include "utils/rel.h" #include "utils/snapmgr.h" #include "utils/tqual.h" +#include "utils/varlena.h" PG_MODULE_MAGIC; diff --git a/contrib/pgstattuple/Makefile b/contrib/pgstattuple/Makefile index e732680dea..294077d4c1 100644 --- a/contrib/pgstattuple/Makefile +++ b/contrib/pgstattuple/Makefile @@ -4,9 +4,10 @@ MODULE_big = pgstattuple OBJS = pgstattuple.o pgstatindex.o pgstatapprox.o $(WIN32RES) EXTENSION = pgstattuple -DATA = pgstattuple--1.4.sql pgstattuple--1.3--1.4.sql \ - pgstattuple--1.2--1.3.sql pgstattuple--1.1--1.2.sql \ - pgstattuple--1.0--1.1.sql pgstattuple--unpackaged--1.0.sql +DATA = pgstattuple--1.4.sql pgstattuple--1.4--1.5.sql \ + pgstattuple--1.3--1.4.sql pgstattuple--1.2--1.3.sql \ + pgstattuple--1.1--1.2.sql pgstattuple--1.0--1.1.sql \ + pgstattuple--unpackaged--1.0.sql PGFILEDESC = "pgstattuple - tuple-level statistics" REGRESS = pgstattuple diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c index a49ff543d2..8db1e20373 100644 --- a/contrib/pgstattuple/pgstatapprox.c +++ b/contrib/pgstattuple/pgstatapprox.c @@ -3,7 +3,7 @@ * pgstatapprox.c * Bloat estimation functions * - * Copyright (c) 2014-2016, PostgreSQL Global Development Group + * Copyright (c) 2014-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/pgstattuple/pgstatapprox.c @@ -29,6 +29,9 @@ #include "commands/vacuum.h" PG_FUNCTION_INFO_V1(pgstattuple_approx); +PG_FUNCTION_INFO_V1(pgstattuple_approx_v1_5); + +Datum pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo); typedef struct output_type { @@ -204,11 +207,42 @@ statapprox_heap(Relation rel, output_type *stat) /* * Returns estimated live/dead tuple statistics for the given relid. + * + * The superuser() check here must be kept as the library might be upgraded + * without the extension being upgraded, meaning that in pre-1.5 installations + * these functions could be called by any user. */ Datum pgstattuple_approx(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); + + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + (errmsg("must be superuser to use pgstattuple functions")))); + + PG_RETURN_DATUM(pgstattuple_approx_internal(relid, fcinfo)); +} + +/* + * As of pgstattuple version 1.5, we no longer need to check if the user + * is a superuser because we REVOKE EXECUTE on the SQL function from PUBLIC. + * Users can then grant access to it based on their policies. + * + * Otherwise identical to pgstattuple_approx (above). + */ +Datum +pgstattuple_approx_v1_5(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + + PG_RETURN_DATUM(pgstattuple_approx_internal(relid, fcinfo)); +} + +Datum +pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo) +{ Relation rel; output_type stat = {0}; TupleDesc tupdesc; @@ -217,11 +251,6 @@ pgstattuple_approx(PG_FUNCTION_ARGS) HeapTuple ret; int i = 0; - if (!superuser()) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - (errmsg("must be superuser to use pgstattuple functions")))); - if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c index 6084589e07..b40669250a 100644 --- a/contrib/pgstattuple/pgstatindex.c +++ b/contrib/pgstattuple/pgstatindex.c @@ -38,6 +38,7 @@ #include "storage/bufmgr.h" #include "utils/builtins.h" #include "utils/rel.h" +#include "utils/varlena.h" /* @@ -54,6 +55,14 @@ PG_FUNCTION_INFO_V1(pg_relpages); PG_FUNCTION_INFO_V1(pg_relpagesbyid); PG_FUNCTION_INFO_V1(pgstatginindex); +PG_FUNCTION_INFO_V1(pgstatindex_v1_5); +PG_FUNCTION_INFO_V1(pgstatindexbyid_v1_5); +PG_FUNCTION_INFO_V1(pg_relpages_v1_5); +PG_FUNCTION_INFO_V1(pg_relpagesbyid_v1_5); +PG_FUNCTION_INFO_V1(pgstatginindex_v1_5); + +Datum pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo); + #define IS_INDEX(r) ((r)->rd_rel->relkind == RELKIND_INDEX) #define IS_BTREE(r) ((r)->rd_rel->relam == BTREE_AM_OID) #define IS_GIN(r) ((r)->rd_rel->relam == GIN_AM_OID) @@ -99,6 +108,10 @@ static Datum pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo); * pgstatindex() * * Usage: SELECT * FROM pgstatindex('t1_pkey'); + * + * The superuser() check here must be kept as the library might be upgraded + * without the extension being upgraded, meaning that in pre-1.5 installations + * these functions could be called by any user. * ------------------------------------------------------ */ Datum @@ -119,6 +132,31 @@ pgstatindex(PG_FUNCTION_ARGS) PG_RETURN_DATUM(pgstatindex_impl(rel, fcinfo)); } +/* + * As of pgstattuple version 1.5, we no longer need to check if the user + * is a superuser because we REVOKE EXECUTE on the function from PUBLIC. + * Users can then grant access to it based on their policies. + * + * Otherwise identical to pgstatindex (above). + */ +Datum +pgstatindex_v1_5(PG_FUNCTION_ARGS) +{ + text *relname = PG_GETARG_TEXT_P(0); + Relation rel; + RangeVar *relrv; + + relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); + rel = relation_openrv(relrv, AccessShareLock); + + PG_RETURN_DATUM(pgstatindex_impl(rel, fcinfo)); +} + +/* + * The superuser() check here must be kept as the library might be upgraded + * without the extension being upgraded, meaning that in pre-1.5 installations + * these functions could be called by any user. + */ Datum pgstatindexbyid(PG_FUNCTION_ARGS) { @@ -135,6 +173,18 @@ pgstatindexbyid(PG_FUNCTION_ARGS) PG_RETURN_DATUM(pgstatindex_impl(rel, fcinfo)); } +/* No need for superuser checks in v1.5, see above */ +Datum +pgstatindexbyid_v1_5(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + Relation rel; + + rel = relation_open(relid, AccessShareLock); + + PG_RETURN_DATUM(pgstatindex_impl(rel, fcinfo)); +} + static Datum pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo) { @@ -292,6 +342,8 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo) * * Usage: SELECT pg_relpages('t1'); * SELECT pg_relpages('t1_pkey'); + * + * Must keep superuser() check, see above. * -------------------------------------------------------- */ Datum @@ -319,6 +371,28 @@ pg_relpages(PG_FUNCTION_ARGS) PG_RETURN_INT64(relpages); } +/* No need for superuser checks in v1.5, see above */ +Datum +pg_relpages_v1_5(PG_FUNCTION_ARGS) +{ + text *relname = PG_GETARG_TEXT_P(0); + int64 relpages; + Relation rel; + RangeVar *relrv; + + relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); + rel = relation_openrv(relrv, AccessShareLock); + + /* note: this will work OK on non-local temp tables */ + + relpages = RelationGetNumberOfBlocks(rel); + + relation_close(rel, AccessShareLock); + + PG_RETURN_INT64(relpages); +} + +/* Must keep superuser() check, see above. */ Datum pg_relpagesbyid(PG_FUNCTION_ARGS) { @@ -342,16 +416,58 @@ pg_relpagesbyid(PG_FUNCTION_ARGS) PG_RETURN_INT64(relpages); } +/* No need for superuser checks in v1.5, see above */ +Datum +pg_relpagesbyid_v1_5(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 relpages; + Relation rel; + + rel = relation_open(relid, AccessShareLock); + + /* note: this will work OK on non-local temp tables */ + + relpages = RelationGetNumberOfBlocks(rel); + + relation_close(rel, AccessShareLock); + + PG_RETURN_INT64(relpages); +} + /* ------------------------------------------------------ * pgstatginindex() * * Usage: SELECT * FROM pgstatginindex('ginindex'); + * + * Must keep superuser() check, see above. * ------------------------------------------------------ */ Datum pgstatginindex(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); + + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + (errmsg("must be superuser to use pgstattuple functions")))); + + PG_RETURN_DATUM(pgstatginindex_internal(relid, fcinfo)); +} + +/* No need for superuser checks in v1.5, see above */ +Datum +pgstatginindex_v1_5(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + + PG_RETURN_DATUM(pgstatginindex_internal(relid, fcinfo)); +} + +Datum +pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo) +{ Relation rel; Buffer buffer; Page page; @@ -363,11 +479,6 @@ pgstatginindex(PG_FUNCTION_ARGS) bool nulls[3] = {false, false, false}; Datum result; - if (!superuser()) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - (errmsg("must be superuser to use pgstattuple functions")))); - rel = relation_open(relid, AccessShareLock); if (!IS_INDEX(rel) || !IS_GIN(rel)) @@ -415,5 +526,5 @@ pgstatginindex(PG_FUNCTION_ARGS) tuple = heap_form_tuple(tupleDesc, values, nulls); result = HeapTupleGetDatum(tuple); - PG_RETURN_DATUM(result); + return (result); } diff --git a/contrib/pgstattuple/pgstattuple--1.4--1.5.sql b/contrib/pgstattuple/pgstattuple--1.4--1.5.sql new file mode 100644 index 0000000000..65d7f19c2a --- /dev/null +++ b/contrib/pgstattuple/pgstattuple--1.4--1.5.sql @@ -0,0 +1,111 @@ +/* contrib/pgstattuple/pgstattuple--1.4--1.5.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION pgstattuple UPDATE TO '1.5'" to load this file. \quit + +CREATE OR REPLACE FUNCTION pgstattuple(IN relname text, + OUT table_len BIGINT, -- physical table length in bytes + OUT tuple_count BIGINT, -- number of live tuples + OUT tuple_len BIGINT, -- total tuples length in bytes + OUT tuple_percent FLOAT8, -- live tuples in % + OUT dead_tuple_count BIGINT, -- number of dead tuples + OUT dead_tuple_len BIGINT, -- total dead tuples length in bytes + OUT dead_tuple_percent FLOAT8, -- dead tuples in % + OUT free_space BIGINT, -- free space in bytes + OUT free_percent FLOAT8) -- free space in % +AS 'MODULE_PATHNAME', 'pgstattuple_v1_5' +LANGUAGE C STRICT PARALLEL SAFE; + +REVOKE EXECUTE ON FUNCTION pgstattuple(text) FROM PUBLIC; + +CREATE OR REPLACE FUNCTION pgstatindex(IN relname text, + OUT version INT, + OUT tree_level INT, + OUT index_size BIGINT, + OUT root_block_no BIGINT, + OUT internal_pages BIGINT, + OUT leaf_pages BIGINT, + OUT empty_pages BIGINT, + OUT deleted_pages BIGINT, + OUT avg_leaf_density FLOAT8, + OUT leaf_fragmentation FLOAT8) +AS 'MODULE_PATHNAME', 'pgstatindex_v1_5' +LANGUAGE C STRICT PARALLEL SAFE; + +REVOKE EXECUTE ON FUNCTION pgstatindex(text) FROM PUBLIC; + +CREATE OR REPLACE FUNCTION pg_relpages(IN relname text) +RETURNS BIGINT +AS 'MODULE_PATHNAME', 'pg_relpages_v1_5' +LANGUAGE C STRICT PARALLEL SAFE; + +REVOKE EXECUTE ON FUNCTION pg_relpages(text) FROM PUBLIC; + +/* New stuff in 1.1 begins here */ + +CREATE OR REPLACE FUNCTION pgstatginindex(IN relname regclass, + OUT version INT4, + OUT pending_pages INT4, + OUT pending_tuples BIGINT) +AS 'MODULE_PATHNAME', 'pgstatginindex_v1_5' +LANGUAGE C STRICT PARALLEL SAFE; + +REVOKE EXECUTE ON FUNCTION pgstatginindex(regclass) FROM PUBLIC; + +/* New stuff in 1.2 begins here */ + +CREATE OR REPLACE FUNCTION pgstattuple(IN reloid regclass, + OUT table_len BIGINT, -- physical table length in bytes + OUT tuple_count BIGINT, -- number of live tuples + OUT tuple_len BIGINT, -- total tuples length in bytes + OUT tuple_percent FLOAT8, -- live tuples in % + OUT dead_tuple_count BIGINT, -- number of dead tuples + OUT dead_tuple_len BIGINT, -- total dead tuples length in bytes + OUT dead_tuple_percent FLOAT8, -- dead tuples in % + OUT free_space BIGINT, -- free space in bytes + OUT free_percent FLOAT8) -- free space in % +AS 'MODULE_PATHNAME', 'pgstattuplebyid_v1_5' +LANGUAGE C STRICT PARALLEL SAFE; + +REVOKE EXECUTE ON FUNCTION pgstattuple(regclass) FROM PUBLIC; + +CREATE OR REPLACE FUNCTION pgstatindex(IN relname regclass, + OUT version INT, + OUT tree_level INT, + OUT index_size BIGINT, + OUT root_block_no BIGINT, + OUT internal_pages BIGINT, + OUT leaf_pages BIGINT, + OUT empty_pages BIGINT, + OUT deleted_pages BIGINT, + OUT avg_leaf_density FLOAT8, + OUT leaf_fragmentation FLOAT8) +AS 'MODULE_PATHNAME', 'pgstatindexbyid_v1_5' +LANGUAGE C STRICT PARALLEL SAFE; + +REVOKE EXECUTE ON FUNCTION pgstatindex(regclass) FROM PUBLIC; + +CREATE OR REPLACE FUNCTION pg_relpages(IN relname regclass) +RETURNS BIGINT +AS 'MODULE_PATHNAME', 'pg_relpagesbyid_v1_5' +LANGUAGE C STRICT PARALLEL SAFE; + +REVOKE EXECUTE ON FUNCTION pg_relpages(regclass) FROM PUBLIC; + +/* New stuff in 1.3 begins here */ + +CREATE OR REPLACE FUNCTION pgstattuple_approx(IN reloid regclass, + OUT table_len BIGINT, -- physical table length in bytes + OUT scanned_percent FLOAT8, -- what percentage of the table's pages was scanned + OUT approx_tuple_count BIGINT, -- estimated number of live tuples + OUT approx_tuple_len BIGINT, -- estimated total length in bytes of live tuples + OUT approx_tuple_percent FLOAT8, -- live tuples in % (based on estimate) + OUT dead_tuple_count BIGINT, -- exact number of dead tuples + OUT dead_tuple_len BIGINT, -- exact total length in bytes of dead tuples + OUT dead_tuple_percent FLOAT8, -- dead tuples in % (based on estimate) + OUT approx_free_space BIGINT, -- estimated free space in bytes + OUT approx_free_percent FLOAT8) -- free space in % (based on estimate) +AS 'MODULE_PATHNAME', 'pgstattuple_approx_v1_5' +LANGUAGE C STRICT PARALLEL SAFE; + +REVOKE EXECUTE ON FUNCTION pgstattuple_approx(regclass) FROM PUBLIC; diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c index c1122b496a..06a1992bb1 100644 --- a/contrib/pgstattuple/pgstattuple.c +++ b/contrib/pgstattuple/pgstattuple.c @@ -36,11 +36,14 @@ #include "storage/lmgr.h" #include "utils/builtins.h" #include "utils/tqual.h" +#include "utils/varlena.h" PG_MODULE_MAGIC; PG_FUNCTION_INFO_V1(pgstattuple); +PG_FUNCTION_INFO_V1(pgstattuple_v1_5); PG_FUNCTION_INFO_V1(pgstattuplebyid); +PG_FUNCTION_INFO_V1(pgstattuplebyid_v1_5); /* * struct pgstattuple_type @@ -152,6 +155,10 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo) * * C FUNCTION definition * pgstattuple(text) returns pgstattuple_type + * + * The superuser() check here must be kept as the library might be upgraded + * without the extension being upgraded, meaning that in pre-1.5 installations + * these functions could be called by any user. * ---------- */ @@ -174,6 +181,28 @@ pgstattuple(PG_FUNCTION_ARGS) PG_RETURN_DATUM(pgstat_relation(rel, fcinfo)); } +/* + * As of pgstattuple version 1.5, we no longer need to check if the user + * is a superuser because we REVOKE EXECUTE on the function from PUBLIC. + * Users can then grant access to it based on their policies. + * + * Otherwise identical to pgstattuple (above). + */ +Datum +pgstattuple_v1_5(PG_FUNCTION_ARGS) +{ + text *relname = PG_GETARG_TEXT_P(0); + RangeVar *relrv; + Relation rel; + + /* open relation */ + relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); + rel = relation_openrv(relrv, AccessShareLock); + + PG_RETURN_DATUM(pgstat_relation(rel, fcinfo)); +} + +/* Must keep superuser() check, see above. */ Datum pgstattuplebyid(PG_FUNCTION_ARGS) { @@ -191,6 +220,19 @@ pgstattuplebyid(PG_FUNCTION_ARGS) PG_RETURN_DATUM(pgstat_relation(rel, fcinfo)); } +/* Remove superuser() check for 1.5 version, see above */ +Datum +pgstattuplebyid_v1_5(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + Relation rel; + + /* open relation */ + rel = relation_open(relid, AccessShareLock); + + PG_RETURN_DATUM(pgstat_relation(rel, fcinfo)); +} + /* * pgstat_relation */ @@ -400,7 +442,6 @@ pgstat_hash_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno, Buffer buf; Page page; - _hash_getlock(rel, blkno, HASH_SHARE); buf = _hash_getbuf_with_strategy(rel, blkno, HASH_READ, 0, bstrategy); page = BufferGetPage(buf); @@ -431,7 +472,6 @@ pgstat_hash_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno, } _hash_relbuf(rel, buf); - _hash_droplock(rel, blkno, HASH_SHARE); } /* diff --git a/contrib/pgstattuple/pgstattuple.control b/contrib/pgstattuple/pgstattuple.control index fa328fd664..6af40757b2 100644 --- a/contrib/pgstattuple/pgstattuple.control +++ b/contrib/pgstattuple/pgstattuple.control @@ -1,5 +1,5 @@ # pgstattuple extension comment = 'show tuple-level statistics' -default_version = '1.4' +default_version = '1.5' module_pathname = '$libdir/pgstattuple' relocatable = true diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c index 8ca1c1c898..be3d3a795d 100644 --- a/contrib/postgres_fdw/connection.c +++ b/contrib/postgres_fdw/connection.c @@ -3,7 +3,7 @@ * connection.c * Connection management functions for postgres_fdw * - * Portions Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/postgres_fdw/connection.c @@ -17,6 +17,7 @@ #include "access/xact.h" #include "mb/pg_wchar.h" #include "miscadmin.h" +#include "pgstat.h" #include "storage/latch.h" #include "utils/hsearch.h" #include "utils/memutils.h" @@ -317,7 +318,12 @@ configure_remote_session(PGconn *conn) int remoteversion = PQserverVersion(conn); /* Force the search path to contain only pg_catalog (see deparse.c) */ - do_sql_command(conn, "SET search_path = pg_catalog"); + + /* + * Temporarily switch off this option. Not all regression tests passes + * correctly without including 'public' value in default search path. + */ + /* do_sql_command(conn, "SET search_path = pg_catalog"); */ /* * Set remote timezone; this is basically just cosmetic, since all @@ -496,7 +502,7 @@ pgfdw_get_result(PGconn *conn, const char *query) wc = WaitLatchOrSocket(MyLatch, WL_LATCH_SET | WL_SOCKET_READABLE, PQsocket(conn), - -1L); + -1L, PG_WAIT_EXTENSION); ResetLatch(MyLatch); CHECK_FOR_INTERRUPTS(); @@ -567,7 +573,7 @@ pgfdw_report_error(int elevel, PGresult *res, PGconn *conn, ereport(elevel, (errcode(sqlstate), message_primary ? errmsg_internal("%s", message_primary) : - errmsg("unknown error"), + errmsg("could not obtain message string for remote error"), message_detail ? errdetail_internal("%s", message_detail) : 0, message_hint ? errhint("%s", message_hint) : 0, message_context ? errcontext("%s", message_context) : 0, diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c index 6476005f6d..6bdeda9824 100644 --- a/contrib/postgres_fdw/deparse.c +++ b/contrib/postgres_fdw/deparse.c @@ -24,7 +24,7 @@ * with collations that match the remote table's columns, which we can * consider to be user error. * - * Portions Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/postgres_fdw/deparse.c @@ -38,6 +38,7 @@ #include "access/heapam.h" #include "access/htup_details.h" #include "access/sysattr.h" +#include "catalog/pg_aggregate.h" #include "catalog/pg_collation.h" #include "catalog/pg_namespace.h" #include "catalog/pg_operator.h" @@ -56,6 +57,7 @@ #include "utils/lsyscache.h" #include "utils/rel.h" #include "utils/syscache.h" +#include "utils/typcache.h" /* @@ -65,6 +67,8 @@ typedef struct foreign_glob_cxt { PlannerInfo *root; /* global planner state */ RelOptInfo *foreignrel; /* the foreign relation we are planning for */ + Relids relids; /* relids of base relations in the underlying + * scan */ } foreign_glob_cxt; /* @@ -94,6 +98,9 @@ typedef struct deparse_expr_cxt { PlannerInfo *root; /* global planner state */ RelOptInfo *foreignrel; /* the foreign relation we are planning for */ + RelOptInfo *scanrel; /* the underlying scan relation. Same as + * foreignrel, when that represents a join or + * a base relation. */ StringInfo buf; /* output buffer to append to */ List **params_list; /* exprs that will become remote Params */ } deparse_expr_cxt; @@ -135,7 +142,7 @@ static void deparseColumnRef(StringInfo buf, int varno, int varattno, static void deparseRelation(StringInfo buf, Relation rel); static void deparseExpr(Expr *expr, deparse_expr_cxt *context); static void deparseVar(Var *node, deparse_expr_cxt *context); -static void deparseConst(Const *node, deparse_expr_cxt *context); +static void deparseConst(Const *node, deparse_expr_cxt *context, int showtype); static void deparseParam(Param *node, deparse_expr_cxt *context); static void deparseArrayRef(ArrayRef *node, deparse_expr_cxt *context); static void deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context); @@ -159,6 +166,14 @@ static void appendOrderByClause(List *pathkeys, deparse_expr_cxt *context); static void appendConditions(List *exprs, deparse_expr_cxt *context); static void deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *joinrel, bool use_alias, List **params_list); +static void deparseFromExpr(List *quals, deparse_expr_cxt *context); +static void deparseAggref(Aggref *node, deparse_expr_cxt *context); +static void appendGroupByClause(List *tlist, deparse_expr_cxt *context); +static void appendAggOrderBy(List *orderList, List *targetList, + deparse_expr_cxt *context); +static void appendFunctionName(Oid funcid, deparse_expr_cxt *context); +static Node *deparseSortGroupClause(Index ref, List *tlist, + deparse_expr_cxt *context); /* @@ -200,6 +215,7 @@ is_foreign_expr(PlannerInfo *root, { foreign_glob_cxt glob_cxt; foreign_loc_cxt loc_cxt; + PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) (baserel->fdw_private); /* * Check that the expression consists of nodes that are safe to execute @@ -207,6 +223,16 @@ is_foreign_expr(PlannerInfo *root, */ glob_cxt.root = root; glob_cxt.foreignrel = baserel; + + /* + * For an upper relation, use relids from its underneath scan relation, + * because the upperrel's own relids currently aren't set to anything + * meaningful by the core code. For other relation, use their own relids. + */ + if (baserel->reloptkind == RELOPT_UPPER_REL) + glob_cxt.relids = fpinfo->outerrel->relids; + else + glob_cxt.relids = baserel->relids; loc_cxt.collation = InvalidOid; loc_cxt.state = FDW_COLLATE_NONE; if (!foreign_expr_walker((Node *) expr, &glob_cxt, &loc_cxt)) @@ -281,19 +307,20 @@ foreign_expr_walker(Node *node, * Param's collation, ie it's not safe for it to have a * non-default collation. */ - if (bms_is_member(var->varno, glob_cxt->foreignrel->relids) && + if (bms_is_member(var->varno, glob_cxt->relids) && var->varlevelsup == 0) { /* Var belongs to foreign table */ /* - * System columns other than ctid should not be sent to - * the remote, since we don't make any effort to ensure - * that local and remote values match (tableoid, in + * System columns other than ctid and oid should not be + * sent to the remote, since we don't make any effort to + * ensure that local and remote values match (tableoid, in * particular, almost certainly doesn't match). */ if (var->varattno < 0 && - var->varattno != SelfItemPointerAttributeNumber) + var->varattno != SelfItemPointerAttributeNumber && + var->varattno != ObjectIdAttributeNumber) return false; /* Else check the collation */ @@ -630,6 +657,106 @@ foreign_expr_walker(Node *node, check_type = false; } break; + case T_Aggref: + { + Aggref *agg = (Aggref *) node; + ListCell *lc; + + /* Not safe to pushdown when not in grouping context */ + if (glob_cxt->foreignrel->reloptkind != RELOPT_UPPER_REL) + return false; + + /* Only non-split aggregates are pushable. */ + if (agg->aggsplit != AGGSPLIT_SIMPLE) + return false; + + /* As usual, it must be shippable. */ + if (!is_shippable(agg->aggfnoid, ProcedureRelationId, fpinfo)) + return false; + + /* + * Recurse to input args. aggdirectargs, aggorder and + * aggdistinct are all present in args, so no need to check + * their shippability explicitly. + */ + foreach(lc, agg->args) + { + Node *n = (Node *) lfirst(lc); + + /* If TargetEntry, extract the expression from it */ + if (IsA(n, TargetEntry)) + { + TargetEntry *tle = (TargetEntry *) n; + + n = (Node *) tle->expr; + } + + if (!foreign_expr_walker(n, glob_cxt, &inner_cxt)) + return false; + } + + /* + * For aggorder elements, check whether the sort operator, if + * specified, is shippable or not. + */ + if (agg->aggorder) + { + ListCell *lc; + + foreach(lc, agg->aggorder) + { + SortGroupClause *srt = (SortGroupClause *) lfirst(lc); + Oid sortcoltype; + TypeCacheEntry *typentry; + TargetEntry *tle; + + tle = get_sortgroupref_tle(srt->tleSortGroupRef, + agg->args); + sortcoltype = exprType((Node *) tle->expr); + typentry = lookup_type_cache(sortcoltype, + TYPECACHE_LT_OPR | TYPECACHE_GT_OPR); + /* Check shippability of non-default sort operator. */ + if (srt->sortop != typentry->lt_opr && + srt->sortop != typentry->gt_opr && + !is_shippable(srt->sortop, OperatorRelationId, + fpinfo)) + return false; + } + } + + /* Check aggregate filter */ + if (!foreign_expr_walker((Node *) agg->aggfilter, + glob_cxt, &inner_cxt)) + return false; + + /* + * If aggregate's input collation is not derived from a + * foreign Var, it can't be sent to remote. + */ + if (agg->inputcollid == InvalidOid) + /* OK, inputs are all noncollatable */ ; + else if (inner_cxt.state != FDW_COLLATE_SAFE || + agg->inputcollid != inner_cxt.collation) + return false; + + /* + * Detect whether node is introducing a collation not derived + * from a foreign Var. (If so, we just mark it unsafe for now + * rather than immediately returning false, since the parent + * node might not care.) + */ + collation = agg->aggcollid; + if (collation == InvalidOid) + state = FDW_COLLATE_NONE; + else if (inner_cxt.state == FDW_COLLATE_SAFE && + collation == inner_cxt.collation) + state = FDW_COLLATE_SAFE; + else if (collation == DEFAULT_COLLATION_OID) + state = FDW_COLLATE_NONE; + else + state = FDW_COLLATE_UNSAFE; + } + break; default: /* @@ -719,7 +846,9 @@ deparse_type_name(Oid type_oid, int32 typemod) * Build the targetlist for given relation to be deparsed as SELECT clause. * * The output targetlist contains the columns that need to be fetched from the - * foreign server for the given relation. + * foreign server for the given relation. If foreignrel is an upper relation, + * then the output targetlist can also contain expressions to be evaluated on + * foreign server. */ List * build_tlist_to_deparse(RelOptInfo *foreignrel) @@ -727,6 +856,13 @@ build_tlist_to_deparse(RelOptInfo *foreignrel) List *tlist = NIL; PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private; + /* + * For an upper relation, we have already built the target list while + * checking shippability, so just return that. + */ + if (foreignrel->reloptkind == RELOPT_UPPER_REL) + return fpinfo->grouped_tlist; + /* * We require columns specified in foreignrel->reltarget->exprs and those * required for evaluating the local conditions. @@ -748,7 +884,8 @@ build_tlist_to_deparse(RelOptInfo *foreignrel) * For a base relation fpinfo->attrs_used is used to construct SELECT clause, * hence the tlist is ignored for a base relation. * - * remote_conds is the list of conditions to be deparsed as WHERE clause. + * remote_conds is the list of conditions to be deparsed into the WHERE clause + * (or, in the case of upper relations, into the HAVING clause). * * If params_list is not NULL, it receives a list of Params and other-relation * Vars used in the clauses; these values must be transmitted to the remote @@ -767,28 +904,58 @@ deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *rel, List **retrieved_attrs, List **params_list) { deparse_expr_cxt context; + PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) rel->fdw_private; + List *quals; - /* We handle relations for foreign tables and joins between those */ + /* + * We handle relations for foreign tables, joins between those and upper + * relations. + */ Assert(rel->reloptkind == RELOPT_JOINREL || rel->reloptkind == RELOPT_BASEREL || - rel->reloptkind == RELOPT_OTHER_MEMBER_REL); + rel->reloptkind == RELOPT_OTHER_MEMBER_REL || + rel->reloptkind == RELOPT_UPPER_REL); - /* Fill portions of context common to join and base relation */ + /* Fill portions of context common to upper, join and base relation */ context.buf = buf; context.root = root; context.foreignrel = rel; + context.scanrel = (rel->reloptkind == RELOPT_UPPER_REL) ? + fpinfo->outerrel : rel; context.params_list = params_list; - /* Construct SELECT clause and FROM clause */ + /* Construct SELECT clause */ deparseSelectSql(tlist, retrieved_attrs, &context); /* - * Construct WHERE clause + * For upper relations, the WHERE clause is built from the remote + * conditions of the underlying scan relation; otherwise, we can use the + * supplied list of remote conditions directly. */ - if (remote_conds) + if (rel->reloptkind == RELOPT_UPPER_REL) { - appendStringInfo(buf, " WHERE "); - appendConditions(remote_conds, &context); + PgFdwRelationInfo *ofpinfo; + + ofpinfo = (PgFdwRelationInfo *) fpinfo->outerrel->fdw_private; + quals = ofpinfo->remote_conds; + } + else + quals = remote_conds; + + /* Construct FROM and WHERE clauses */ + deparseFromExpr(quals, &context); + + if (rel->reloptkind == RELOPT_UPPER_REL) + { + /* Append GROUP BY clause */ + appendGroupByClause(tlist, &context); + + /* Append HAVING clause */ + if (remote_conds) + { + appendStringInfo(buf, " HAVING "); + appendConditions(remote_conds, &context); + } } /* Add ORDER BY clause if we found any useful pathkeys */ @@ -802,7 +969,7 @@ deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *rel, /* * Construct a simple SELECT statement that retrieves desired columns * of the specified foreign table, and append it to "buf". The output - * contains just "SELECT ... FROM ....". + * contains just "SELECT ... ". * * We also create an integer List of the columns being retrieved, which is * returned to *retrieved_attrs. @@ -823,7 +990,8 @@ deparseSelectSql(List *tlist, List **retrieved_attrs, deparse_expr_cxt *context) */ appendStringInfoString(buf, "SELECT "); - if (foreignrel->reloptkind == RELOPT_JOINREL) + if (foreignrel->reloptkind == RELOPT_JOINREL || + foreignrel->reloptkind == RELOPT_UPPER_REL) { /* For a join relation use the input tlist */ deparseExplicitTargetList(tlist, retrieved_attrs, context); @@ -846,14 +1014,37 @@ deparseSelectSql(List *tlist, List **retrieved_attrs, deparse_expr_cxt *context) fpinfo->attrs_used, false, retrieved_attrs); heap_close(rel, NoLock); } +} - /* - * Construct FROM clause - */ +/* + * Construct a FROM clause and, if needed, a WHERE clause, and append those to + * "buf". + * + * quals is the list of clauses to be included in the WHERE clause. + */ +static void +deparseFromExpr(List *quals, deparse_expr_cxt *context) +{ + StringInfo buf = context->buf; + RelOptInfo *scanrel = context->scanrel; + + /* For upper relations, scanrel must be either a joinrel or a baserel */ + Assert(context->foreignrel->reloptkind != RELOPT_UPPER_REL || + scanrel->reloptkind == RELOPT_JOINREL || + scanrel->reloptkind == RELOPT_BASEREL); + + /* Construct FROM clause */ appendStringInfoString(buf, " FROM "); - deparseFromExprForRel(buf, root, foreignrel, - (foreignrel->reloptkind == RELOPT_JOINREL), + deparseFromExprForRel(buf, context->root, scanrel, + (bms_num_members(scanrel->relids) > 1), context->params_list); + + /* Construct WHERE clause */ + if (quals != NIL) + { + appendStringInfo(buf, " WHERE "); + appendConditions(quals, context); + } } /* @@ -913,8 +1104,8 @@ deparseTargetList(StringInfo buf, } /* - * Add ctid if needed. We currently don't support retrieving any other - * system columns. + * Add ctid and oid if needed. We currently don't support retrieving any + * other system columns. */ if (bms_is_member(SelfItemPointerAttributeNumber - FirstLowInvalidHeapAttributeNumber, attrs_used)) @@ -932,6 +1123,22 @@ deparseTargetList(StringInfo buf, *retrieved_attrs = lappend_int(*retrieved_attrs, SelfItemPointerAttributeNumber); } + if (bms_is_member(ObjectIdAttributeNumber - FirstLowInvalidHeapAttributeNumber, + attrs_used)) + { + if (!first) + appendStringInfoString(buf, ", "); + else if (is_returning) + appendStringInfoString(buf, " RETURNING "); + first = false; + + if (qualify_col) + ADD_REL_QUALIFIER(buf, rtindex); + appendStringInfoString(buf, "oid"); + + *retrieved_attrs = lappend_int(*retrieved_attrs, + ObjectIdAttributeNumber); + } /* Don't generate bad syntax if no undropped columns */ if (first && !is_returning) @@ -939,15 +1146,15 @@ deparseTargetList(StringInfo buf, } /* - * Deparse the appropriate locking clause (FOR SELECT or FOR SHARE) for a - * given relation (context->foreignrel). + * Deparse the appropriate locking clause (FOR UPDATE or FOR SHARE) for a + * given relation (context->scanrel). */ static void deparseLockingClause(deparse_expr_cxt *context) { StringInfo buf = context->buf; PlannerInfo *root = context->root; - RelOptInfo *rel = context->foreignrel; + RelOptInfo *rel = context->scanrel; int relid = -1; while ((relid = bms_next_member(rel->relids, relid)) >= 0) @@ -1007,7 +1214,7 @@ deparseLockingClause(deparse_expr_cxt *context) } /* Add the relation alias if we are here for a join relation */ - if (rel->reloptkind == RELOPT_JOINREL && + if (bms_num_members(rel->relids) > 1 && rc->strength != LCS_NONE) appendStringInfo(buf, " OF %s%d", REL_ALIAS_PREFIX, relid); } @@ -1019,7 +1226,7 @@ deparseLockingClause(deparse_expr_cxt *context) * Deparse conditions from the provided list and append them to buf. * * The conditions in the list are assumed to be ANDed. This function is used to - * deparse both WHERE clauses and JOIN .. ON clauses. + * deparse WHERE clauses, JOIN .. ON clauses and HAVING clauses. */ static void appendConditions(List *exprs, deparse_expr_cxt *context) @@ -1109,22 +1316,15 @@ deparseExplicitTargetList(List *tlist, List **retrieved_attrs, foreach(lc, tlist) { TargetEntry *tle = (TargetEntry *) lfirst(lc); - Var *var; /* Extract expression if TargetEntry node */ Assert(IsA(tle, TargetEntry)); - var = (Var *) tle->expr; - - /* We expect only Var nodes here */ - if (!IsA(var, Var)) - elog(ERROR, "non-Var not expected in target list"); if (i > 0) appendStringInfoString(buf, ", "); - deparseVar(var, context); + deparseExpr((Expr *) tle->expr, context); *retrieved_attrs = lappend_int(*retrieved_attrs, i + 1); - i++; } @@ -1163,7 +1363,7 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel, /* * For a join relation FROM clause entry is deparsed as * - * ((outer relation) (inner relation) ON (joinclauses) + * ((outer relation) (inner relation) ON (joinclauses)) */ appendStringInfo(buf, "(%s %s JOIN %s ON ", join_sql_o.data, get_jointype_name(fpinfo->jointype), join_sql_i.data); @@ -1175,6 +1375,7 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel, context.buf = buf; context.foreignrel = foreignrel; + context.scanrel = foreignrel; context.root = root; context.params_list = params_list; @@ -1343,6 +1544,7 @@ deparseDirectUpdateSql(StringInfo buf, PlannerInfo *root, /* Set up context struct for recursion */ context.root = root; context.foreignrel = baserel; + context.scanrel = baserel; context.buf = buf; context.params_list = params_list; @@ -1427,6 +1629,7 @@ deparseDirectDeleteSql(StringInfo buf, PlannerInfo *root, /* Set up context struct for recursion */ context.root = root; context.foreignrel = baserel; + context.scanrel = baserel; context.buf = buf; context.params_list = params_list; @@ -1574,13 +1777,19 @@ deparseColumnRef(StringInfo buf, int varno, int varattno, PlannerInfo *root, { RangeTblEntry *rte; + /* We support fetching the remote side's CTID and OID. */ if (varattno == SelfItemPointerAttributeNumber) { - /* We support fetching the remote side's CTID. */ if (qualify_col) ADD_REL_QUALIFIER(buf, varno); appendStringInfoString(buf, "ctid"); } + else if (varattno == ObjectIdAttributeNumber) + { + if (qualify_col) + ADD_REL_QUALIFIER(buf, varno); + appendStringInfoString(buf, "oid"); + } else if (varattno < 0) { /* @@ -1794,7 +2003,7 @@ deparseExpr(Expr *node, deparse_expr_cxt *context) deparseVar((Var *) node, context); break; case T_Const: - deparseConst((Const *) node, context); + deparseConst((Const *) node, context, 0); break; case T_Param: deparseParam((Param *) node, context); @@ -1826,6 +2035,9 @@ deparseExpr(Expr *node, deparse_expr_cxt *context) case T_ArrayExpr: deparseArrayExpr((ArrayExpr *) node, context); break; + case T_Aggref: + deparseAggref((Aggref *) node, context); + break; default: elog(ERROR, "unsupported expression type for deparse: %d", (int) nodeTag(node)); @@ -1844,10 +2056,12 @@ deparseExpr(Expr *node, deparse_expr_cxt *context) static void deparseVar(Var *node, deparse_expr_cxt *context) { - bool qualify_col = (context->foreignrel->reloptkind == RELOPT_JOINREL); + Relids relids = context->scanrel->relids; + + /* Qualify columns when multiple relations are involved. */ + bool qualify_col = (bms_num_members(relids) > 1); - if (bms_is_member(node->varno, context->foreignrel->relids) && - node->varlevelsup == 0) + if (bms_is_member(node->varno, relids) && node->varlevelsup == 0) deparseColumnRef(context->buf, node->varno, node->varattno, context->root, qualify_col); else @@ -1885,9 +2099,12 @@ deparseVar(Var *node, deparse_expr_cxt *context) * Deparse given constant value into context->buf. * * This function has to be kept in sync with ruleutils.c's get_const_expr. + * As for that function, showtype can be -1 to never show "::typename" decoration, + * or +1 to always show it, or 0 to show it only if the constant wouldn't be assumed + * to be the right type by default. */ static void -deparseConst(Const *node, deparse_expr_cxt *context) +deparseConst(Const *node, deparse_expr_cxt *context, int showtype) { StringInfo buf = context->buf; Oid typoutput; @@ -1899,9 +2116,10 @@ deparseConst(Const *node, deparse_expr_cxt *context) if (node->constisnull) { appendStringInfoString(buf, "NULL"); - appendStringInfo(buf, "::%s", - deparse_type_name(node->consttype, - node->consttypmod)); + if (showtype >= 0) + appendStringInfo(buf, "::%s", + deparse_type_name(node->consttype, + node->consttypmod)); return; } @@ -1951,9 +2169,14 @@ deparseConst(Const *node, deparse_expr_cxt *context) break; } + pfree(extval); + + if (showtype < 0) + return; + /* - * Append ::typename unless the constant will be implicitly typed as the - * right type when it is read in. + * For showtype == 0, append ::typename unless the constant will be + * implicitly typed as the right type when it is read in. * * XXX this code has to be kept in sync with the behavior of the parser, * especially make_const. @@ -1972,7 +2195,7 @@ deparseConst(Const *node, deparse_expr_cxt *context) needlabel = true; break; } - if (needlabel) + if (needlabel || showtype > 0) appendStringInfo(buf, "::%s", deparse_type_name(node->consttype, node->consttypmod)); @@ -2069,9 +2292,6 @@ static void deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context) { StringInfo buf = context->buf; - HeapTuple proctup; - Form_pg_proc procform; - const char *proname; bool use_variadic; bool first; ListCell *arg; @@ -2104,29 +2324,15 @@ deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context) return; } - /* - * Normal function: display as proname(args). - */ - proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(node->funcid)); - if (!HeapTupleIsValid(proctup)) - elog(ERROR, "cache lookup failed for function %u", node->funcid); - procform = (Form_pg_proc) GETSTRUCT(proctup); - /* Check if need to print VARIADIC (cf. ruleutils.c) */ use_variadic = node->funcvariadic; - /* Print schema name only if it's not pg_catalog */ - if (procform->pronamespace != PG_CATALOG_NAMESPACE) - { - const char *schemaname; - - schemaname = get_namespace_name(procform->pronamespace); - appendStringInfo(buf, "%s.", quote_identifier(schemaname)); - } + /* + * Normal function: display as proname(args). + */ + appendFunctionName(node->funcid, context); + appendStringInfoChar(buf, '('); - /* Deparse the function name ... */ - proname = NameStr(procform->proname); - appendStringInfo(buf, "%s(", quote_identifier(proname)); /* ... and all the arguments */ first = true; foreach(arg, node->args) @@ -2139,8 +2345,6 @@ deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context) first = false; } appendStringInfoChar(buf, ')'); - - ReleaseSysCache(proctup); } /* @@ -2396,6 +2600,152 @@ deparseArrayExpr(ArrayExpr *node, deparse_expr_cxt *context) deparse_type_name(node->array_typeid, -1)); } +/* + * Deparse an Aggref node. + */ +static void +deparseAggref(Aggref *node, deparse_expr_cxt *context) +{ + StringInfo buf = context->buf; + bool use_variadic; + + /* Only basic, non-split aggregation accepted. */ + Assert(node->aggsplit == AGGSPLIT_SIMPLE); + + /* Check if need to print VARIADIC (cf. ruleutils.c) */ + use_variadic = node->aggvariadic; + + /* Find aggregate name from aggfnoid which is a pg_proc entry */ + appendFunctionName(node->aggfnoid, context); + appendStringInfoChar(buf, '('); + + /* Add DISTINCT */ + appendStringInfo(buf, "%s", (node->aggdistinct != NIL) ? "DISTINCT " : ""); + + if (AGGKIND_IS_ORDERED_SET(node->aggkind)) + { + /* Add WITHIN GROUP (ORDER BY ..) */ + ListCell *arg; + bool first = true; + + Assert(!node->aggvariadic); + Assert(node->aggorder != NIL); + + foreach(arg, node->aggdirectargs) + { + if (!first) + appendStringInfoString(buf, ", "); + first = false; + + deparseExpr((Expr *) lfirst(arg), context); + } + + appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY "); + appendAggOrderBy(node->aggorder, node->args, context); + } + else + { + /* aggstar can be set only in zero-argument aggregates */ + if (node->aggstar) + appendStringInfoChar(buf, '*'); + else + { + ListCell *arg; + bool first = true; + + /* Add all the arguments */ + foreach(arg, node->args) + { + TargetEntry *tle = (TargetEntry *) lfirst(arg); + Node *n = (Node *) tle->expr; + + if (tle->resjunk) + continue; + + if (!first) + appendStringInfoString(buf, ", "); + first = false; + + /* Add VARIADIC */ + if (use_variadic && lnext(arg) == NULL) + appendStringInfoString(buf, "VARIADIC "); + + deparseExpr((Expr *) n, context); + } + } + + /* Add ORDER BY */ + if (node->aggorder != NIL) + { + appendStringInfoString(buf, " ORDER BY "); + appendAggOrderBy(node->aggorder, node->args, context); + } + } + + /* Add FILTER (WHERE ..) */ + if (node->aggfilter != NULL) + { + appendStringInfoString(buf, ") FILTER (WHERE "); + deparseExpr((Expr *) node->aggfilter, context); + } + + appendStringInfoChar(buf, ')'); +} + +/* + * Append ORDER BY within aggregate function. + */ +static void +appendAggOrderBy(List *orderList, List *targetList, deparse_expr_cxt *context) +{ + StringInfo buf = context->buf; + ListCell *lc; + bool first = true; + + foreach(lc, orderList) + { + SortGroupClause *srt = (SortGroupClause *) lfirst(lc); + Node *sortexpr; + Oid sortcoltype; + TypeCacheEntry *typentry; + + if (!first) + appendStringInfoString(buf, ", "); + first = false; + + sortexpr = deparseSortGroupClause(srt->tleSortGroupRef, targetList, + context); + sortcoltype = exprType(sortexpr); + /* See whether operator is default < or > for datatype */ + typentry = lookup_type_cache(sortcoltype, + TYPECACHE_LT_OPR | TYPECACHE_GT_OPR); + if (srt->sortop == typentry->lt_opr) + appendStringInfoString(buf, " ASC"); + else if (srt->sortop == typentry->gt_opr) + appendStringInfoString(buf, " DESC"); + else + { + HeapTuple opertup; + Form_pg_operator operform; + + appendStringInfoString(buf, " USING "); + + /* Append operator name. */ + opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(srt->sortop)); + if (!HeapTupleIsValid(opertup)) + elog(ERROR, "cache lookup failed for operator %u", srt->sortop); + operform = (Form_pg_operator) GETSTRUCT(opertup); + deparseOperatorName(buf, operform); + ReleaseSysCache(opertup); + } + + if (srt->nulls_first) + appendStringInfoString(buf, " NULLS FIRST"); + else + appendStringInfoString(buf, " NULLS LAST"); + } +} + /* * Print the representation of a parameter to be sent to the remote side. * @@ -2440,6 +2790,41 @@ printRemotePlaceholder(Oid paramtype, int32 paramtypmod, appendStringInfo(buf, "((SELECT null::%s)::%s)", ptypename, ptypename); } +/* + * Deparse GROUP BY clause. + */ +static void +appendGroupByClause(List *tlist, deparse_expr_cxt *context) +{ + StringInfo buf = context->buf; + Query *query = context->root->parse; + ListCell *lc; + bool first = true; + + /* Nothing to be done, if there's no GROUP BY clause in the query. */ + if (!query->groupClause) + return; + + appendStringInfo(buf, " GROUP BY "); + + /* + * Queries with grouping sets are not pushed down, so we don't expect + * grouping sets here. + */ + Assert(!query->groupingSets); + + foreach(lc, query->groupClause) + { + SortGroupClause *grp = (SortGroupClause *) lfirst(lc); + + if (!first) + appendStringInfoString(buf, ", "); + first = false; + + deparseSortGroupClause(grp->tleSortGroupRef, tlist, context); + } +} + /* * Deparse ORDER BY clause according to the given pathkeys for given base * relation. From given pathkeys expressions belonging entirely to the given @@ -2451,7 +2836,7 @@ appendOrderByClause(List *pathkeys, deparse_expr_cxt *context) ListCell *lcell; int nestlevel; char *delim = " "; - RelOptInfo *baserel = context->foreignrel; + RelOptInfo *baserel = context->scanrel; StringInfo buf = context->buf; /* Make sure any constants in the exprs are printed portably */ @@ -2482,3 +2867,74 @@ appendOrderByClause(List *pathkeys, deparse_expr_cxt *context) } reset_transmission_modes(nestlevel); } + +/* + * appendFunctionName + * Deparses function name from given function oid. + */ +static void +appendFunctionName(Oid funcid, deparse_expr_cxt *context) +{ + StringInfo buf = context->buf; + HeapTuple proctup; + Form_pg_proc procform; + const char *proname; + + proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); + if (!HeapTupleIsValid(proctup)) + elog(ERROR, "cache lookup failed for function %u", funcid); + procform = (Form_pg_proc) GETSTRUCT(proctup); + + /* Print schema name only if it's not pg_catalog */ + if (procform->pronamespace != PG_CATALOG_NAMESPACE) + { + const char *schemaname; + + schemaname = get_namespace_name(procform->pronamespace); + appendStringInfo(buf, "%s.", quote_identifier(schemaname)); + } + + /* Always print the function name */ + proname = NameStr(procform->proname); + appendStringInfo(buf, "%s", quote_identifier(proname)); + + ReleaseSysCache(proctup); +} + +/* + * Appends a sort or group clause. + * + * Like get_rule_sortgroupclause(), returns the expression tree, so caller + * need not find it again. + */ +static Node * +deparseSortGroupClause(Index ref, List *tlist, deparse_expr_cxt *context) +{ + StringInfo buf = context->buf; + TargetEntry *tle; + Expr *expr; + + tle = get_sortgroupref_tle(ref, tlist); + expr = tle->expr; + + if (expr && IsA(expr, Const)) + { + /* + * Force a typecast here so that we don't emit something like "GROUP + * BY 2", which will be misconstrued as a column position rather than + * a constant. + */ + deparseConst((Const *) expr, context, 1); + } + else if (!expr || IsA(expr, Var)) + deparseExpr(expr, context); + else + { + /* Always parenthesize the expression. */ + appendStringInfoString(buf, "("); + deparseExpr(expr, context); + appendStringInfoString(buf, ")"); + } + + return (Node *) expr; +} diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index d7747cc665..0045f3fef8 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -124,6 +124,13 @@ CREATE FOREIGN TABLE ft6 ( c2 int NOT NULL, c3 text ) SERVER loopback2 OPTIONS (schema_name 'S 1', table_name 'T 4'); +-- A table with oids. CREATE FOREIGN TABLE doesn't support the +-- WITH OIDS option, but ALTER does. +CREATE FOREIGN TABLE ft_pg_type ( + typname name, + typlen smallint +) SERVER loopback OPTIONS (schema_name 'pg_catalog', table_name 'pg_type'); +ALTER TABLE ft_pg_type SET WITH OIDS; -- =================================================================== -- tests for validator -- =================================================================== @@ -173,15 +180,16 @@ ALTER FOREIGN TABLE ft2 OPTIONS (schema_name 'S 1', table_name 'T 1'); ALTER FOREIGN TABLE ft1 ALTER COLUMN c1 OPTIONS (column_name 'C 1'); ALTER FOREIGN TABLE ft2 ALTER COLUMN c1 OPTIONS (column_name 'C 1'); \det+ - List of foreign tables - Schema | Table | Server | FDW Options | Description ---------+-------+-----------+---------------------------------------+------------- - public | ft1 | loopback | (schema_name 'S 1', table_name 'T 1') | - public | ft2 | loopback | (schema_name 'S 1', table_name 'T 1') | - public | ft4 | loopback | (schema_name 'S 1', table_name 'T 3') | - public | ft5 | loopback | (schema_name 'S 1', table_name 'T 4') | - public | ft6 | loopback2 | (schema_name 'S 1', table_name 'T 4') | -(5 rows) + List of foreign tables + Schema | Table | Server | FDW Options | Description +--------+------------+-----------+--------------------------------------------------+------------- + public | ft1 | loopback | (schema_name 'S 1', table_name 'T 1') | + public | ft2 | loopback | (schema_name 'S 1', table_name 'T 1') | + public | ft4 | loopback | (schema_name 'S 1', table_name 'T 3') | + public | ft5 | loopback | (schema_name 'S 1', table_name 'T 4') | + public | ft6 | loopback2 | (schema_name 'S 1', table_name 'T 4') | + public | ft_pg_type | loopback | (schema_name 'pg_catalog', table_name 'pg_type') | +(6 rows) -- Now we should be able to run ANALYZE. -- To exercise multiple code paths, we use local stats on ft1 @@ -853,14 +861,13 @@ CREATE OPERATOR === ( -- built-in operators and functions can be shipped for remote execution EXPLAIN (VERBOSE, COSTS OFF) SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = abs(t1.c2); - QUERY PLAN --------------------------------------------------------------------------- - Aggregate - Output: count(c3) - -> Foreign Scan on public.ft1 t1 - Output: c3 - Remote SQL: SELECT c3 FROM "S 1"."T 1" WHERE (("C 1" = abs(c2))) -(5 rows) + QUERY PLAN +--------------------------------------------------------------------------- + Foreign Scan + Output: (count(c3)) + Relations: Aggregate on (public.ft1 t1) + Remote SQL: SELECT count(c3) FROM "S 1"."T 1" WHERE (("C 1" = abs(c2))) +(4 rows) SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = abs(t1.c2); count @@ -870,14 +877,13 @@ SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = abs(t1.c2); EXPLAIN (VERBOSE, COSTS OFF) SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = t1.c2; - QUERY PLAN ---------------------------------------------------------------------- - Aggregate - Output: count(c3) - -> Foreign Scan on public.ft1 t1 - Output: c3 - Remote SQL: SELECT c3 FROM "S 1"."T 1" WHERE (("C 1" = c2)) -(5 rows) + QUERY PLAN +---------------------------------------------------------------------- + Foreign Scan + Output: (count(c3)) + Relations: Aggregate on (public.ft1 t1) + Remote SQL: SELECT count(c3) FROM "S 1"."T 1" WHERE (("C 1" = c2)) +(4 rows) SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = t1.c2; count @@ -929,14 +935,13 @@ ALTER SERVER loopback OPTIONS (ADD extensions 'postgres_fdw'); -- ... now they can be shipped EXPLAIN (VERBOSE, COSTS OFF) SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = postgres_fdw_abs(t1.c2); - QUERY PLAN ----------------------------------------------------------------------------------------------- - Aggregate - Output: count(c3) - -> Foreign Scan on public.ft1 t1 - Output: c3 - Remote SQL: SELECT c3 FROM "S 1"."T 1" WHERE (("C 1" = public.postgres_fdw_abs(c2))) -(5 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------- + Foreign Scan + Output: (count(c3)) + Relations: Aggregate on (public.ft1 t1) + Remote SQL: SELECT count(c3) FROM "S 1"."T 1" WHERE (("C 1" = public.postgres_fdw_abs(c2))) +(4 rows) SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = postgres_fdw_abs(t1.c2); count @@ -946,14 +951,13 @@ SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = postgres_fdw_abs(t1.c2); EXPLAIN (VERBOSE, COSTS OFF) SELECT count(c3) FROM ft1 t1 WHERE t1.c1 === t1.c2; - QUERY PLAN ----------------------------------------------------------------------------------------- - Aggregate - Output: count(c3) - -> Foreign Scan on public.ft1 t1 - Output: c3 - Remote SQL: SELECT c3 FROM "S 1"."T 1" WHERE (("C 1" OPERATOR(public.===) c2)) -(5 rows) + QUERY PLAN +----------------------------------------------------------------------------------------- + Foreign Scan + Output: (count(c3)) + Relations: Aggregate on (public.ft1 t1) + Remote SQL: SELECT count(c3) FROM "S 1"."T 1" WHERE (("C 1" OPERATOR(public.===) c2)) +(4 rows) SELECT count(c3) FROM ft1 t1 WHERE t1.c1 === t1.c2; count @@ -2274,6 +2278,1098 @@ ALTER VIEW v4 OWNER TO regress_view_owner; -- cleanup DROP OWNED BY regress_view_owner; DROP ROLE regress_view_owner; +-- =================================================================== +-- Aggregate and grouping queries +-- =================================================================== +-- Simple aggregates +explain (verbose, costs off) +select count(c6), sum(c1), avg(c1), min(c2), max(c1), stddev(c2), sum(c1) * (random() <= 1)::int as sum2 from ft1 where c2 < 5 group by c2 order by 1, 2; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------- + Result + Output: (count(c6)), (sum(c1)), (avg(c1)), (min(c2)), (max(c1)), (stddev(c2)), ((sum(c1)) * ((random() <= '1'::double precision))::integer), c2 + -> Sort + Output: (count(c6)), (sum(c1)), (avg(c1)), (min(c2)), (max(c1)), (stddev(c2)), c2 + Sort Key: (count(ft1.c6)), (sum(ft1.c1)) + -> Foreign Scan + Output: (count(c6)), (sum(c1)), (avg(c1)), (min(c2)), (max(c1)), (stddev(c2)), c2 + Relations: Aggregate on (public.ft1) + Remote SQL: SELECT count(c6), sum("C 1"), avg("C 1"), min(c2), max("C 1"), stddev(c2), c2 FROM "S 1"."T 1" WHERE ((c2 < 5)) GROUP BY c2 +(9 rows) + +select count(c6), sum(c1), avg(c1), min(c2), max(c1), stddev(c2), sum(c1) * (random() <= 1)::int as sum2 from ft1 where c2 < 5 group by c2 order by 1, 2; + count | sum | avg | min | max | stddev | sum2 +-------+-------+----------------------+-----+------+--------+------- + 100 | 49600 | 496.0000000000000000 | 1 | 991 | 0 | 49600 + 100 | 49700 | 497.0000000000000000 | 2 | 992 | 0 | 49700 + 100 | 49800 | 498.0000000000000000 | 3 | 993 | 0 | 49800 + 100 | 49900 | 499.0000000000000000 | 4 | 994 | 0 | 49900 + 100 | 50500 | 505.0000000000000000 | 0 | 1000 | 0 | 50500 +(5 rows) + +-- Aggregate is not pushed down as aggregation contains random() +explain (verbose, costs off) +select sum(c1 * (random() <= 1)::int) as sum, avg(c1) from ft1; + QUERY PLAN +------------------------------------------------------------------------------- + Aggregate + Output: sum((c1 * ((random() <= '1'::double precision))::integer)), avg(c1) + -> Foreign Scan on public.ft1 + Output: c1 + Remote SQL: SELECT "C 1" FROM "S 1"."T 1" +(5 rows) + +-- Aggregate over join query +explain (verbose, costs off) +select count(*), sum(t1.c1), avg(t2.c1) from ft1 t1 inner join ft1 t2 on (t1.c2 = t2.c2) where t1.c2 = 6; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan + Output: (count(*)), (sum(t1.c1)), (avg(t2.c1)) + Relations: Aggregate on ((public.ft1 t1) INNER JOIN (public.ft1 t2)) + Remote SQL: SELECT count(*), sum(r1."C 1"), avg(r2."C 1") FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r2.c2 = 6)) AND ((r1.c2 = 6)))) +(4 rows) + +select count(*), sum(t1.c1), avg(t2.c1) from ft1 t1 inner join ft1 t2 on (t1.c2 = t2.c2) where t1.c2 = 6; + count | sum | avg +-------+---------+---------------------- + 10000 | 5010000 | 501.0000000000000000 +(1 row) + +-- Not pushed down due to local conditions present in underneath input rel +explain (verbose, costs off) +select sum(t1.c1), count(t2.c1) from ft1 t1 inner join ft2 t2 on (t1.c1 = t2.c1) where ((t1.c1 * t2.c1)/(t1.c1 * t2.c1)) * random() <= 1; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: sum(t1.c1), count(t2.c1) + -> Foreign Scan + Output: t1.c1, t2.c1 + Filter: (((((t1.c1 * t2.c1) / (t1.c1 * t2.c1)))::double precision * random()) <= '1'::double precision) + Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2) + Remote SQL: SELECT r1."C 1", r2."C 1" FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) +(7 rows) + +-- GROUP BY clause having expressions +explain (verbose, costs off) +select c2/2, sum(c2) * (c2/2) from ft1 group by c2/2 order by c2/2; + QUERY PLAN +------------------------------------------------------------------------------------------------ + Sort + Output: ((c2 / 2)), ((sum(c2) * (c2 / 2))) + Sort Key: ((ft1.c2 / 2)) + -> Foreign Scan + Output: ((c2 / 2)), ((sum(c2) * (c2 / 2))) + Relations: Aggregate on (public.ft1) + Remote SQL: SELECT (c2 / 2), (sum(c2) * (c2 / 2)) FROM "S 1"."T 1" GROUP BY ((c2 / 2)) +(7 rows) + +select c2/2, sum(c2) * (c2/2) from ft1 group by c2/2 order by c2/2; + ?column? | ?column? +----------+---------- + 0 | 0 + 1 | 500 + 2 | 1800 + 3 | 3900 + 4 | 6800 +(5 rows) + +-- Aggregates in subquery are pushed down. +explain (verbose, costs off) +select count(x.a), sum(x.a) from (select c2 a, sum(c1) b from ft1 group by c2, sqrt(c1) order by 1, 2) x; + QUERY PLAN +---------------------------------------------------------------------------------------------------------- + Aggregate + Output: count(ft1.c2), sum(ft1.c2) + -> Sort + Output: ft1.c2, (sum(ft1.c1)), (sqrt((ft1.c1)::double precision)) + Sort Key: ft1.c2, (sum(ft1.c1)) + -> Foreign Scan + Output: ft1.c2, (sum(ft1.c1)), (sqrt((ft1.c1)::double precision)) + Relations: Aggregate on (public.ft1) + Remote SQL: SELECT c2, sum("C 1"), sqrt("C 1") FROM "S 1"."T 1" GROUP BY c2, (sqrt("C 1")) +(9 rows) + +select count(x.a), sum(x.a) from (select c2 a, sum(c1) b from ft1 group by c2, sqrt(c1) order by 1, 2) x; + count | sum +-------+------ + 1000 | 4500 +(1 row) + +-- Aggregate is still pushed down by taking unshippable expression out +explain (verbose, costs off) +select c2 * (random() <= 1)::int as sum1, sum(c1) * c2 as sum2 from ft1 group by c2 order by 1, 2; + QUERY PLAN +--------------------------------------------------------------------------------------------------- + Sort + Output: ((c2 * ((random() <= '1'::double precision))::integer)), ((sum(c1) * c2)), c2 + Sort Key: ((ft1.c2 * ((random() <= '1'::double precision))::integer)), ((sum(ft1.c1) * ft1.c2)) + -> Foreign Scan + Output: (c2 * ((random() <= '1'::double precision))::integer), ((sum(c1) * c2)), c2 + Relations: Aggregate on (public.ft1) + Remote SQL: SELECT (sum("C 1") * c2), c2 FROM "S 1"."T 1" GROUP BY c2 +(7 rows) + +select c2 * (random() <= 1)::int as sum1, sum(c1) * c2 as sum2 from ft1 group by c2 order by 1, 2; + sum1 | sum2 +------+-------- + 0 | 0 + 1 | 49600 + 2 | 99400 + 3 | 149400 + 4 | 199600 + 5 | 250000 + 6 | 300600 + 7 | 351400 + 8 | 402400 + 9 | 453600 +(10 rows) + +-- Aggregate with unshippable GROUP BY clause are not pushed +explain (verbose, costs off) +select c2 * (random() <= 1)::int as c2 from ft2 group by c2 * (random() <= 1)::int order by 1; + QUERY PLAN +------------------------------------------------------------------------------ + Sort + Output: ((c2 * ((random() <= '1'::double precision))::integer)) + Sort Key: ((ft2.c2 * ((random() <= '1'::double precision))::integer)) + -> HashAggregate + Output: ((c2 * ((random() <= '1'::double precision))::integer)) + Group Key: (ft2.c2 * ((random() <= '1'::double precision))::integer) + -> Foreign Scan on public.ft2 + Output: (c2 * ((random() <= '1'::double precision))::integer) + Remote SQL: SELECT c2 FROM "S 1"."T 1" +(9 rows) + +-- GROUP BY clause in various forms, cardinal, alias and constant expression +explain (verbose, costs off) +select count(c2) w, c2 x, 5 y, 7.0 z from ft1 group by 2, y, 9.0::int order by 2; + QUERY PLAN +---------------------------------------------------------------------------------------------------------- + Sort + Output: (count(c2)), c2, 5, 7.0, 9 + Sort Key: ft1.c2 + -> Foreign Scan + Output: (count(c2)), c2, 5, 7.0, 9 + Relations: Aggregate on (public.ft1) + Remote SQL: SELECT count(c2), c2, 5, 7.0, 9 FROM "S 1"."T 1" GROUP BY c2, 5::integer, 9::integer +(7 rows) + +select count(c2) w, c2 x, 5 y, 7.0 z from ft1 group by 2, y, 9.0::int order by 2; + w | x | y | z +-----+---+---+----- + 100 | 0 | 5 | 7.0 + 100 | 1 | 5 | 7.0 + 100 | 2 | 5 | 7.0 + 100 | 3 | 5 | 7.0 + 100 | 4 | 5 | 7.0 + 100 | 5 | 5 | 7.0 + 100 | 6 | 5 | 7.0 + 100 | 7 | 5 | 7.0 + 100 | 8 | 5 | 7.0 + 100 | 9 | 5 | 7.0 +(10 rows) + +-- Testing HAVING clause shippability +explain (verbose, costs off) +select c2, sum(c1) from ft2 group by c2 having avg(c1) < 500 and sum(c1) < 49800 order by c2; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------- + Sort + Output: c2, (sum(c1)) + Sort Key: ft2.c2 + -> Foreign Scan + Output: c2, (sum(c1)) + Relations: Aggregate on (public.ft2) + Remote SQL: SELECT c2, sum("C 1") FROM "S 1"."T 1" GROUP BY c2 HAVING ((avg("C 1") < 500::numeric)) AND ((sum("C 1") < 49800)) +(7 rows) + +select c2, sum(c1) from ft2 group by c2 having avg(c1) < 500 and sum(c1) < 49800 order by c2; + c2 | sum +----+------- + 1 | 49600 + 2 | 49700 +(2 rows) + +-- Unshippable HAVING clause will be evaluated locally, and other qual in HAVING clause is pushed down +explain (verbose, costs off) +select count(*) from (select c5, count(c1) from ft1 group by c5, sqrt(c2) having (avg(c1) / avg(c1)) * random() <= 1 and avg(c1) < 500) x; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: count(*) + -> Foreign Scan + Output: ft1.c5, NULL::bigint, (sqrt((ft1.c2)::double precision)) + Filter: (((((avg(ft1.c1)) / (avg(ft1.c1))))::double precision * random()) <= '1'::double precision) + Relations: Aggregate on (public.ft1) + Remote SQL: SELECT c5, NULL::bigint, sqrt(c2), avg("C 1") FROM "S 1"."T 1" GROUP BY c5, (sqrt(c2)) HAVING ((avg("C 1") < 500::numeric)) +(7 rows) + +select count(*) from (select c5, count(c1) from ft1 group by c5, sqrt(c2) having (avg(c1) / avg(c1)) * random() <= 1 and avg(c1) < 500) x; + count +------- + 49 +(1 row) + +-- Aggregate in HAVING clause is not pushable, and thus aggregation is not pushed down +explain (verbose, costs off) +select sum(c1) from ft1 group by c2 having avg(c1 * (random() <= 1)::int) > 100 order by 1; + QUERY PLAN +--------------------------------------------------------------------------------------------------- + Sort + Output: (sum(c1)), c2 + Sort Key: (sum(ft1.c1)) + -> HashAggregate + Output: sum(c1), c2 + Group Key: ft1.c2 + Filter: (avg((ft1.c1 * ((random() <= '1'::double precision))::integer)) > '100'::numeric) + -> Foreign Scan on public.ft1 + Output: c2, c1 + Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" +(10 rows) + +-- Testing ORDER BY, DISTINCT, FILTER, Ordered-sets and VARIADIC within aggregates +-- ORDER BY within aggregate, same column used to order +explain (verbose, costs off) +select array_agg(c1 order by c1) from ft1 where c1 < 100 group by c2 order by 1; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- + Sort + Output: (array_agg(c1 ORDER BY c1)), c2 + Sort Key: (array_agg(ft1.c1 ORDER BY ft1.c1)) + -> Foreign Scan + Output: (array_agg(c1 ORDER BY c1)), c2 + Relations: Aggregate on (public.ft1) + Remote SQL: SELECT array_agg("C 1" ORDER BY "C 1" ASC NULLS LAST), c2 FROM "S 1"."T 1" WHERE (("C 1" < 100)) GROUP BY c2 +(7 rows) + +select array_agg(c1 order by c1) from ft1 where c1 < 100 group by c2 order by 1; + array_agg +-------------------------------- + {1,11,21,31,41,51,61,71,81,91} + {2,12,22,32,42,52,62,72,82,92} + {3,13,23,33,43,53,63,73,83,93} + {4,14,24,34,44,54,64,74,84,94} + {5,15,25,35,45,55,65,75,85,95} + {6,16,26,36,46,56,66,76,86,96} + {7,17,27,37,47,57,67,77,87,97} + {8,18,28,38,48,58,68,78,88,98} + {9,19,29,39,49,59,69,79,89,99} + {10,20,30,40,50,60,70,80,90} +(10 rows) + +-- ORDER BY within aggregate, different column used to order also using DESC +explain (verbose, costs off) +select array_agg(c5 order by c1 desc) from ft2 where c2 = 6 and c1 < 50; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- + Foreign Scan + Output: (array_agg(c5 ORDER BY c1 DESC)) + Relations: Aggregate on (public.ft2) + Remote SQL: SELECT array_agg(c5 ORDER BY "C 1" DESC NULLS FIRST) FROM "S 1"."T 1" WHERE (("C 1" < 50)) AND ((c2 = 6)) +(4 rows) + +select array_agg(c5 order by c1 desc) from ft2 where c2 = 6 and c1 < 50; + array_agg +------------------------------------------------------------------------------------------------------------------------------------------ + {"Mon Feb 16 00:00:00 1970","Fri Feb 06 00:00:00 1970","Tue Jan 27 00:00:00 1970","Sat Jan 17 00:00:00 1970","Wed Jan 07 00:00:00 1970"} +(1 row) + +-- DISTINCT within aggregate +explain (verbose, costs off) +select array_agg(distinct (t1.c1)%5) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) where t1.c1 < 20 or (t1.c1 is null and t2.c1 < 5) group by (t2.c1)%3 order by 1; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Sort + Output: (array_agg(DISTINCT (t1.c1 % 5))), ((t2.c1 % 3)) + Sort Key: (array_agg(DISTINCT (t1.c1 % 5))) + -> Foreign Scan + Output: (array_agg(DISTINCT (t1.c1 % 5))), ((t2.c1 % 3)) + Relations: Aggregate on ((public.ft4 t1) FULL JOIN (public.ft5 t2)) + Remote SQL: SELECT array_agg(DISTINCT (r1.c1 % 5)), (r2.c1 % 3) FROM ("S 1"."T 3" r1 FULL JOIN "S 1"."T 4" r2 ON (((r1.c1 = r2.c1)))) WHERE (((r1.c1 < 20) OR ((r1.c1 IS NULL) AND (r2.c1 < 5)))) GROUP BY ((r2.c1 % 3)) +(7 rows) + +select array_agg(distinct (t1.c1)%5) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) where t1.c1 < 20 or (t1.c1 is null and t2.c1 < 5) group by (t2.c1)%3 order by 1; + array_agg +-------------- + {0,1,2,3,4} + {1,2,3,NULL} +(2 rows) + +-- DISTINCT combined with ORDER BY within aggregate +explain (verbose, costs off) +select array_agg(distinct (t1.c1)%5 order by (t1.c1)%5) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) where t1.c1 < 20 or (t1.c1 is null and t2.c1 < 5) group by (t2.c1)%3 order by 1; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + Sort + Output: (array_agg(DISTINCT (t1.c1 % 5) ORDER BY (t1.c1 % 5))), ((t2.c1 % 3)) + Sort Key: (array_agg(DISTINCT (t1.c1 % 5) ORDER BY (t1.c1 % 5))) + -> Foreign Scan + Output: (array_agg(DISTINCT (t1.c1 % 5) ORDER BY (t1.c1 % 5))), ((t2.c1 % 3)) + Relations: Aggregate on ((public.ft4 t1) FULL JOIN (public.ft5 t2)) + Remote SQL: SELECT array_agg(DISTINCT (r1.c1 % 5) ORDER BY ((r1.c1 % 5)) ASC NULLS LAST), (r2.c1 % 3) FROM ("S 1"."T 3" r1 FULL JOIN "S 1"."T 4" r2 ON (((r1.c1 = r2.c1)))) WHERE (((r1.c1 < 20) OR ((r1.c1 IS NULL) AND (r2.c1 < 5)))) GROUP BY ((r2.c1 % 3)) +(7 rows) + +select array_agg(distinct (t1.c1)%5 order by (t1.c1)%5) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) where t1.c1 < 20 or (t1.c1 is null and t2.c1 < 5) group by (t2.c1)%3 order by 1; + array_agg +-------------- + {0,1,2,3,4} + {1,2,3,NULL} +(2 rows) + +explain (verbose, costs off) +select array_agg(distinct (t1.c1)%5 order by (t1.c1)%5 desc nulls last) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) where t1.c1 < 20 or (t1.c1 is null and t2.c1 < 5) group by (t2.c1)%3 order by 1; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Sort + Output: (array_agg(DISTINCT (t1.c1 % 5) ORDER BY (t1.c1 % 5) DESC NULLS LAST)), ((t2.c1 % 3)) + Sort Key: (array_agg(DISTINCT (t1.c1 % 5) ORDER BY (t1.c1 % 5) DESC NULLS LAST)) + -> Foreign Scan + Output: (array_agg(DISTINCT (t1.c1 % 5) ORDER BY (t1.c1 % 5) DESC NULLS LAST)), ((t2.c1 % 3)) + Relations: Aggregate on ((public.ft4 t1) FULL JOIN (public.ft5 t2)) + Remote SQL: SELECT array_agg(DISTINCT (r1.c1 % 5) ORDER BY ((r1.c1 % 5)) DESC NULLS LAST), (r2.c1 % 3) FROM ("S 1"."T 3" r1 FULL JOIN "S 1"."T 4" r2 ON (((r1.c1 = r2.c1)))) WHERE (((r1.c1 < 20) OR ((r1.c1 IS NULL) AND (r2.c1 < 5)))) GROUP BY ((r2.c1 % 3)) +(7 rows) + +select array_agg(distinct (t1.c1)%5 order by (t1.c1)%5 desc nulls last) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) where t1.c1 < 20 or (t1.c1 is null and t2.c1 < 5) group by (t2.c1)%3 order by 1; + array_agg +-------------- + {3,2,1,NULL} + {4,3,2,1,0} +(2 rows) + +-- FILTER within aggregate +explain (verbose, costs off) +select sum(c1) filter (where c1 < 100 and c2 > 5) from ft1 group by c2 order by 1 nulls last; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- + Sort + Output: (sum(c1) FILTER (WHERE ((c1 < 100) AND (c2 > 5)))), c2 + Sort Key: (sum(ft1.c1) FILTER (WHERE ((ft1.c1 < 100) AND (ft1.c2 > 5)))) + -> Foreign Scan + Output: (sum(c1) FILTER (WHERE ((c1 < 100) AND (c2 > 5)))), c2 + Relations: Aggregate on (public.ft1) + Remote SQL: SELECT sum("C 1") FILTER (WHERE (("C 1" < 100) AND (c2 > 5))), c2 FROM "S 1"."T 1" GROUP BY c2 +(7 rows) + +select sum(c1) filter (where c1 < 100 and c2 > 5) from ft1 group by c2 order by 1 nulls last; + sum +----- + 510 + 520 + 530 + 540 + + + + + + +(10 rows) + +-- DISTINCT, ORDER BY and FILTER within aggregate +explain (verbose, costs off) +select sum(c1%3), sum(distinct c1%3 order by c1%3) filter (where c1%3 < 2), c2 from ft1 where c2 = 6 group by c2; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan + Output: (sum((c1 % 3))), (sum(DISTINCT (c1 % 3) ORDER BY (c1 % 3)) FILTER (WHERE ((c1 % 3) < 2))), c2 + Relations: Aggregate on (public.ft1) + Remote SQL: SELECT sum(("C 1" % 3)), sum(DISTINCT ("C 1" % 3) ORDER BY (("C 1" % 3)) ASC NULLS LAST) FILTER (WHERE (("C 1" % 3) < 2)), c2 FROM "S 1"."T 1" WHERE ((c2 = 6)) GROUP BY c2 +(4 rows) + +select sum(c1%3), sum(distinct c1%3 order by c1%3) filter (where c1%3 < 2), c2 from ft1 where c2 = 6 group by c2; + sum | sum | c2 +-----+-----+---- + 99 | 1 | 6 +(1 row) + +-- Outer query is aggregation query +explain (verbose, costs off) +select distinct (select count(*) filter (where t2.c2 = 6 and t2.c1 < 10) from ft1 t1 where t1.c1 = 6) from ft2 t2 order by 1; + QUERY PLAN +------------------------------------------------------------------------------------------------------- + Unique + Output: ((SubPlan 1)) + -> Sort + Output: ((SubPlan 1)) + Sort Key: ((SubPlan 1)) + -> Foreign Scan + Output: (SubPlan 1) + Relations: Aggregate on (public.ft2 t2) + Remote SQL: SELECT count(*) FILTER (WHERE ((c2 = 6) AND ("C 1" < 10))) FROM "S 1"."T 1" + SubPlan 1 + -> Foreign Scan on public.ft1 t1 + Output: (count(*) FILTER (WHERE ((t2.c2 = 6) AND (t2.c1 < 10)))) + Remote SQL: SELECT NULL FROM "S 1"."T 1" WHERE (("C 1" = 6)) +(13 rows) + +select distinct (select count(*) filter (where t2.c2 = 6 and t2.c1 < 10) from ft1 t1 where t1.c1 = 6) from ft2 t2 order by 1; + count +------- + 1 +(1 row) + +-- Inner query is aggregation query +explain (verbose, costs off) +select distinct (select count(t1.c1) filter (where t2.c2 = 6 and t2.c1 < 10) from ft1 t1 where t1.c1 = 6) from ft2 t2 order by 1; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------ + Unique + Output: ((SubPlan 1)) + -> Sort + Output: ((SubPlan 1)) + Sort Key: ((SubPlan 1)) + -> Foreign Scan on public.ft2 t2 + Output: (SubPlan 1) + Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" + SubPlan 1 + -> Foreign Scan + Output: (count(t1.c1) FILTER (WHERE ((t2.c2 = 6) AND (t2.c1 < 10)))) + Relations: Aggregate on (public.ft1 t1) + Remote SQL: SELECT count("C 1") FILTER (WHERE (($1::integer = 6) AND ($2::integer < 10))) FROM "S 1"."T 1" WHERE (("C 1" = 6)) +(13 rows) + +select distinct (select count(t1.c1) filter (where t2.c2 = 6 and t2.c1 < 10) from ft1 t1 where t1.c1 = 6) from ft2 t2 order by 1; + count +------- + 0 + 1 +(2 rows) + +-- Aggregate not pushed down as FILTER condition is not pushable +explain (verbose, costs off) +select sum(c1) filter (where (c1 / c1) * random() <= 1) from ft1 group by c2 order by 1; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ + Sort + Output: (sum(c1) FILTER (WHERE ((((c1 / c1))::double precision * random()) <= '1'::double precision))), c2 + Sort Key: (sum(ft1.c1) FILTER (WHERE ((((ft1.c1 / ft1.c1))::double precision * random()) <= '1'::double precision))) + -> HashAggregate + Output: sum(c1) FILTER (WHERE ((((c1 / c1))::double precision * random()) <= '1'::double precision)), c2 + Group Key: ft1.c2 + -> Foreign Scan on public.ft1 + Output: c2, c1 + Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" +(9 rows) + +explain (verbose, costs off) +select sum(c2) filter (where c2 in (select c2 from ft1 where c2 < 5)) from ft1; + QUERY PLAN +------------------------------------------------------------------- + Aggregate + Output: sum(ft1.c2) FILTER (WHERE (hashed SubPlan 1)) + -> Foreign Scan on public.ft1 + Output: ft1.c2 + Remote SQL: SELECT c2 FROM "S 1"."T 1" + SubPlan 1 + -> Foreign Scan on public.ft1 ft1_1 + Output: ft1_1.c2 + Remote SQL: SELECT c2 FROM "S 1"."T 1" WHERE ((c2 < 5)) +(9 rows) + +-- Ordered-sets within aggregate +explain (verbose, costs off) +select c2, rank('10'::varchar) within group (order by c6), percentile_cont(c2/10::numeric) within group (order by c1) from ft1 where c2 < 10 group by c2 having percentile_cont(c2/10::numeric) within group (order by c1) < 500 order by c2; + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Sort + Output: c2, (rank('10'::character varying) WITHIN GROUP (ORDER BY c6)), (percentile_cont((((c2)::numeric / '10'::numeric))::double precision) WITHIN GROUP (ORDER BY ((c1)::double precision))) + Sort Key: ft1.c2 + -> Foreign Scan + Output: c2, (rank('10'::character varying) WITHIN GROUP (ORDER BY c6)), (percentile_cont((((c2)::numeric / '10'::numeric))::double precision) WITHIN GROUP (ORDER BY ((c1)::double precision))) + Relations: Aggregate on (public.ft1) + Remote SQL: SELECT c2, rank('10'::character varying) WITHIN GROUP (ORDER BY c6 ASC NULLS LAST), percentile_cont((c2 / 10::numeric)) WITHIN GROUP (ORDER BY ("C 1") ASC NULLS LAST) FROM "S 1"."T 1" WHERE ((c2 < 10)) GROUP BY c2 HAVING ((percentile_cont((c2 / 10::numeric)) WITHIN GROUP (ORDER BY ("C 1") ASC NULLS LAST) < 500::double precision)) +(7 rows) + +select c2, rank('10'::varchar) within group (order by c6), percentile_cont(c2/10::numeric) within group (order by c1) from ft1 where c2 < 10 group by c2 having percentile_cont(c2/10::numeric) within group (order by c1) < 500 order by c2; + c2 | rank | percentile_cont +----+------+----------------- + 0 | 101 | 10 + 1 | 101 | 100 + 2 | 1 | 200 + 3 | 1 | 300 + 4 | 1 | 400 +(5 rows) + +-- Using multiple arguments within aggregates +explain (verbose, costs off) +select c1, rank(c1, c2) within group (order by c1, c2) from ft1 group by c1, c2 having c1 = 6 order by 1; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan + Output: c1, (rank(c1, c2) WITHIN GROUP (ORDER BY c1, c2)), c2 + Relations: Aggregate on (public.ft1) + Remote SQL: SELECT "C 1", rank("C 1", c2) WITHIN GROUP (ORDER BY "C 1" ASC NULLS LAST, c2 ASC NULLS LAST), c2 FROM "S 1"."T 1" WHERE (("C 1" = 6)) GROUP BY "C 1", c2 +(4 rows) + +select c1, rank(c1, c2) within group (order by c1, c2) from ft1 group by c1, c2 having c1 = 6 order by 1; + c1 | rank +----+------ + 6 | 1 +(1 row) + +-- User defined function for user defined aggregate, VARIADIC +create function least_accum(anyelement, variadic anyarray) +returns anyelement language sql as + 'select least($1, min($2[i])) from generate_subscripts($2,1) g(i)'; +create aggregate least_agg(variadic items anyarray) ( + stype = anyelement, sfunc = least_accum +); +-- Disable hash aggregation for plan stability. +set enable_hashagg to false; +-- Not pushed down due to user defined aggregate +explain (verbose, costs off) +select c2, least_agg(c1) from ft1 group by c2 order by c2; + QUERY PLAN +---------------------------------------------------------------------------------- + GroupAggregate + Output: c2, least_agg(VARIADIC ARRAY[c1]) + Group Key: ft1.c2 + -> Foreign Scan on public.ft1 + Output: c2, c1 + Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" ORDER BY c2 ASC NULLS LAST +(6 rows) + +-- Add function and aggregate into extension +alter extension postgres_fdw add function least_accum(anyelement, variadic anyarray); +alter extension postgres_fdw add aggregate least_agg(variadic items anyarray); +alter server loopback options (set extensions 'postgres_fdw'); +-- Now aggregate will be pushed. Aggregate will display VARIADIC argument. +explain (verbose, costs off) +select c2, least_agg(c1) from ft1 where c2 < 100 group by c2 order by c2; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ + Sort + Output: c2, (least_agg(VARIADIC ARRAY[c1])) + Sort Key: ft1.c2 + -> Foreign Scan + Output: c2, (least_agg(VARIADIC ARRAY[c1])) + Relations: Aggregate on (public.ft1) + Remote SQL: SELECT c2, public.least_agg(VARIADIC ARRAY["C 1"]) FROM "S 1"."T 1" WHERE ((c2 < 100)) GROUP BY c2 +(7 rows) + +select c2, least_agg(c1) from ft1 where c2 < 100 group by c2 order by c2; + c2 | least_agg +----+----------- + 0 | 10 + 1 | 1 + 2 | 2 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 +(10 rows) + +-- Remove function and aggregate from extension +alter extension postgres_fdw drop function least_accum(anyelement, variadic anyarray); +alter extension postgres_fdw drop aggregate least_agg(variadic items anyarray); +alter server loopback options (set extensions 'postgres_fdw'); +-- Not pushed down as we have dropped objects from extension. +explain (verbose, costs off) +select c2, least_agg(c1) from ft1 group by c2 order by c2; + QUERY PLAN +---------------------------------------------------------------------------------- + GroupAggregate + Output: c2, least_agg(VARIADIC ARRAY[c1]) + Group Key: ft1.c2 + -> Foreign Scan on public.ft1 + Output: c2, c1 + Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" ORDER BY c2 ASC NULLS LAST +(6 rows) + +-- Cleanup +reset enable_hashagg; +drop aggregate least_agg(variadic items anyarray); +drop function least_accum(anyelement, variadic anyarray); +-- Testing USING OPERATOR() in ORDER BY within aggregate. +-- For this, we need user defined operators along with operator family and +-- operator class. Create those and then add them in extension. Note that +-- user defined objects are considered unshippable unless they are part of +-- the extension. +create operator public.<^ ( + leftarg = int4, + rightarg = int4, + procedure = int4eq +); +create operator public.=^ ( + leftarg = int4, + rightarg = int4, + procedure = int4lt +); +create operator public.>^ ( + leftarg = int4, + rightarg = int4, + procedure = int4gt +); +create operator family my_op_family using btree; +create function my_op_cmp(a int, b int) returns int as + $$begin return btint4cmp(a, b); end $$ language plpgsql; +create operator class my_op_class for type int using btree family my_op_family as + operator 1 public.<^, + operator 3 public.=^, + operator 5 public.>^, + function 1 my_op_cmp(int, int); +-- This will not be pushed as user defined sort operator is not part of the +-- extension yet. +explain (verbose, costs off) +select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6 and c1 < 100 group by c2; + QUERY PLAN +-------------------------------------------------------------------------------------------- + GroupAggregate + Output: array_agg(c1 ORDER BY c1 USING <^ NULLS LAST), c2 + Group Key: ft2.c2 + -> Foreign Scan on public.ft2 + Output: c2, c1 + Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" WHERE (("C 1" < 100)) AND ((c2 = 6)) +(6 rows) + +-- Add into extension +alter extension postgres_fdw add operator class my_op_class using btree; +alter extension postgres_fdw add function my_op_cmp(a int, b int); +alter extension postgres_fdw add operator family my_op_family using btree; +alter extension postgres_fdw add operator public.<^(int, int); +alter extension postgres_fdw add operator public.=^(int, int); +alter extension postgres_fdw add operator public.>^(int, int); +alter server loopback options (set extensions 'postgres_fdw'); +-- Now this will be pushed as sort operator is part of the extension. +explain (verbose, costs off) +select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6 and c1 < 100 group by c2; + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan + Output: (array_agg(c1 ORDER BY c1 USING <^ NULLS LAST)), c2 + Relations: Aggregate on (public.ft2) + Remote SQL: SELECT array_agg("C 1" ORDER BY "C 1" USING OPERATOR(public.<^) NULLS LAST), c2 FROM "S 1"."T 1" WHERE (("C 1" < 100)) AND ((c2 = 6)) GROUP BY c2 +(4 rows) + +select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6 and c1 < 100 group by c2; + array_agg +-------------------------------- + {6,16,26,36,46,56,66,76,86,96} +(1 row) + +-- Remove from extension +alter extension postgres_fdw drop operator class my_op_class using btree; +alter extension postgres_fdw drop function my_op_cmp(a int, b int); +alter extension postgres_fdw drop operator family my_op_family using btree; +alter extension postgres_fdw drop operator public.<^(int, int); +alter extension postgres_fdw drop operator public.=^(int, int); +alter extension postgres_fdw drop operator public.>^(int, int); +alter server loopback options (set extensions 'postgres_fdw'); +-- This will not be pushed as sort operator is now removed from the extension. +explain (verbose, costs off) +select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6 and c1 < 100 group by c2; + QUERY PLAN +-------------------------------------------------------------------------------------------- + GroupAggregate + Output: array_agg(c1 ORDER BY c1 USING <^ NULLS LAST), c2 + Group Key: ft2.c2 + -> Foreign Scan on public.ft2 + Output: c2, c1 + Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" WHERE (("C 1" < 100)) AND ((c2 = 6)) +(6 rows) + +-- Cleanup +drop operator class my_op_class using btree; +drop function my_op_cmp(a int, b int); +drop operator family my_op_family using btree; +drop operator public.>^(int, int); +drop operator public.=^(int, int); +drop operator public.<^(int, int); +-- Input relation to aggregate push down hook is not safe to pushdown and thus +-- the aggregate cannot be pushed down to foreign server. +explain (verbose, costs off) +select count(t1.c3) from ft1 t1, ft1 t2 where t1.c1 = postgres_fdw_abs(t1.c2); + QUERY PLAN +---------------------------------------------------------------------------------------------------------- + Aggregate + Output: count(t1.c3) + -> Nested Loop + Output: t1.c3 + -> Foreign Scan on public.ft1 t2 + Remote SQL: SELECT NULL FROM "S 1"."T 1" + -> Materialize + Output: t1.c3 + -> Foreign Scan on public.ft1 t1 + Output: t1.c3 + Remote SQL: SELECT c3 FROM "S 1"."T 1" WHERE (("C 1" = public.postgres_fdw_abs(c2))) +(11 rows) + +-- Subquery in FROM clause having aggregate +explain (verbose, costs off) +select count(*), x.b from ft1, (select c2 a, sum(c1) b from ft1 group by c2) x where ft1.c2 = x.a group by x.b order by 1, 2; + QUERY PLAN +------------------------------------------------------------------------------------------------ + Sort + Output: (count(*)), x.b + Sort Key: (count(*)), x.b + -> HashAggregate + Output: count(*), x.b + Group Key: x.b + -> Hash Join + Output: x.b + Hash Cond: (ft1.c2 = x.a) + -> Foreign Scan on public.ft1 + Output: ft1.c2 + Remote SQL: SELECT c2 FROM "S 1"."T 1" + -> Hash + Output: x.b, x.a + -> Subquery Scan on x + Output: x.b, x.a + -> Foreign Scan + Output: ft1_1.c2, (sum(ft1_1.c1)) + Relations: Aggregate on (public.ft1) + Remote SQL: SELECT c2, sum("C 1") FROM "S 1"."T 1" GROUP BY c2 +(20 rows) + +select count(*), x.b from ft1, (select c2 a, sum(c1) b from ft1 group by c2) x where ft1.c2 = x.a group by x.b order by 1, 2; + count | b +-------+------- + 100 | 49600 + 100 | 49700 + 100 | 49800 + 100 | 49900 + 100 | 50000 + 100 | 50100 + 100 | 50200 + 100 | 50300 + 100 | 50400 + 100 | 50500 +(10 rows) + +-- FULL join with IS NULL check in HAVING +explain (verbose, costs off) +select avg(t1.c1), sum(t2.c1) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) group by t2.c1 having (avg(t1.c1) is null and sum(t2.c1) < 10) or sum(t2.c1) is null order by 1 nulls last, 2; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Sort + Output: (avg(t1.c1)), (sum(t2.c1)), t2.c1 + Sort Key: (avg(t1.c1)), (sum(t2.c1)) + -> Foreign Scan + Output: (avg(t1.c1)), (sum(t2.c1)), t2.c1 + Relations: Aggregate on ((public.ft4 t1) FULL JOIN (public.ft5 t2)) + Remote SQL: SELECT avg(r1.c1), sum(r2.c1), r2.c1 FROM ("S 1"."T 3" r1 FULL JOIN "S 1"."T 4" r2 ON (((r1.c1 = r2.c1)))) GROUP BY r2.c1 HAVING ((((avg(r1.c1) IS NULL) AND (sum(r2.c1) < 10)) OR (sum(r2.c1) IS NULL))) +(7 rows) + +select avg(t1.c1), sum(t2.c1) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) group by t2.c1 having (avg(t1.c1) is null and sum(t2.c1) < 10) or sum(t2.c1) is null order by 1 nulls last, 2; + avg | sum +---------------------+----- + 51.0000000000000000 | + | 3 + | 9 +(3 rows) + +-- ORDER BY expression is part of the target list but not pushed down to +-- foreign server. +explain (verbose, costs off) +select sum(c2) * (random() <= 1)::int as sum from ft1 order by 1; + QUERY PLAN +-------------------------------------------------------------------------------- + Sort + Output: (((sum(c2)) * ((random() <= '1'::double precision))::integer)) + Sort Key: (((sum(ft1.c2)) * ((random() <= '1'::double precision))::integer)) + -> Foreign Scan + Output: ((sum(c2)) * ((random() <= '1'::double precision))::integer) + Relations: Aggregate on (public.ft1) + Remote SQL: SELECT sum(c2) FROM "S 1"."T 1" +(7 rows) + +select sum(c2) * (random() <= 1)::int as sum from ft1 order by 1; + sum +------ + 4500 +(1 row) + +-- LATERAL join, with parameterization +set enable_hashagg to false; +explain (verbose, costs off) +select c2, sum from "S 1"."T 1" t1, lateral (select sum(t2.c1 + t1."C 1") sum from ft2 t2 group by t2.c1) qry where t1.c2 * 2 = qry.sum and t1.c2 < 10 order by 1; + QUERY PLAN +---------------------------------------------------------------------------------------------------------- + Sort + Output: t1.c2, qry.sum + Sort Key: t1.c2 + -> Nested Loop + Output: t1.c2, qry.sum + -> Seq Scan on "S 1"."T 1" t1 + Output: t1."C 1", t1.c2, t1.c3, t1.c4, t1.c5, t1.c6, t1.c7, t1.c8 + Filter: (t1.c2 < 10) + -> Subquery Scan on qry + Output: qry.sum, t2.c1 + Filter: ((t1.c2 * 2) = qry.sum) + -> Foreign Scan + Output: (sum((t2.c1 + t1."C 1"))), t2.c1 + Relations: Aggregate on (public.ft2 t2) + Remote SQL: SELECT sum(("C 1" + $1::integer)), "C 1" FROM "S 1"."T 1" GROUP BY "C 1" +(15 rows) + +select c2, sum from "S 1"."T 1" t1, lateral (select sum(t2.c1 + t1."C 1") sum from ft2 t2 group by t2.c1) qry where t1.c2 * 2 = qry.sum and t1.c2 < 10 order by 1; + c2 | sum +----+----- + 1 | 2 + 2 | 4 + 3 | 6 + 4 | 8 + 5 | 10 + 6 | 12 + 7 | 14 + 8 | 16 + 9 | 18 +(9 rows) + +reset enable_hashagg; +-- Check with placeHolderVars +explain (verbose, costs off) +select sum(q.a), count(q.b) from ft4 left join (select 13, avg(ft1.c1), sum(ft2.c1) from ft1 right join ft2 on (ft1.c1 = ft2.c1)) q(a, b, c) on (ft4.c1 <= q.b); + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: sum(q.a), count(q.b) + -> Nested Loop Left Join + Output: q.a, q.b + Join Filter: ((ft4.c1)::numeric <= q.b) + -> Foreign Scan on public.ft4 + Output: ft4.c1, ft4.c2, ft4.c3 + Remote SQL: SELECT c1 FROM "S 1"."T 3" + -> Materialize + Output: q.a, q.b + -> Subquery Scan on q + Output: q.a, q.b + -> Foreign Scan + Output: 13, (avg(ft1.c1)), NULL::bigint + Relations: Aggregate on ((public.ft2) LEFT JOIN (public.ft1)) + Remote SQL: SELECT 13, avg(r1."C 1"), NULL::bigint FROM ("S 1"."T 1" r2 LEFT JOIN "S 1"."T 1" r1 ON (((r1."C 1" = r2."C 1")))) +(16 rows) + +select sum(q.a), count(q.b) from ft4 left join (select 13, avg(ft1.c1), sum(ft2.c1) from ft1 right join ft2 on (ft1.c1 = ft2.c1)) q(a, b, c) on (ft4.c1 <= q.b); + sum | count +-----+------- + 650 | 50 +(1 row) + +-- Not supported cases +-- Grouping sets +explain (verbose, costs off) +select c2, sum(c1) from ft1 where c2 < 3 group by rollup(c2) order by 1 nulls last; + QUERY PLAN +--------------------------------------------------------------------------------------------------- + GroupAggregate + Output: c2, sum(c1) + Group Key: ft1.c2 + Group Key: () + -> Foreign Scan on public.ft1 + Output: c2, c1 + Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" WHERE ((c2 < 3)) ORDER BY c2 ASC NULLS LAST +(7 rows) + +select c2, sum(c1) from ft1 where c2 < 3 group by rollup(c2) order by 1 nulls last; + c2 | sum +----+-------- + 0 | 50500 + 1 | 49600 + 2 | 49700 + | 149800 +(4 rows) + +explain (verbose, costs off) +select c2, sum(c1) from ft1 where c2 < 3 group by cube(c2) order by 1 nulls last; + QUERY PLAN +--------------------------------------------------------------------------------------------------- + GroupAggregate + Output: c2, sum(c1) + Group Key: ft1.c2 + Group Key: () + -> Foreign Scan on public.ft1 + Output: c2, c1 + Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" WHERE ((c2 < 3)) ORDER BY c2 ASC NULLS LAST +(7 rows) + +select c2, sum(c1) from ft1 where c2 < 3 group by cube(c2) order by 1 nulls last; + c2 | sum +----+-------- + 0 | 50500 + 1 | 49600 + 2 | 49700 + | 149800 +(4 rows) + +explain (verbose, costs off) +select c2, c6, sum(c1) from ft1 where c2 < 3 group by grouping sets(c2, c6) order by 1 nulls last, 2 nulls last; + QUERY PLAN +------------------------------------------------------------------------------------------------------------- + Sort + Output: c2, c6, (sum(c1)) + Sort Key: ft1.c2, ft1.c6 + -> GroupAggregate + Output: c2, c6, sum(c1) + Group Key: ft1.c2 + Sort Key: ft1.c6 + Group Key: ft1.c6 + -> Foreign Scan on public.ft1 + Output: c2, c6, c1 + Remote SQL: SELECT "C 1", c2, c6 FROM "S 1"."T 1" WHERE ((c2 < 3)) ORDER BY c2 ASC NULLS LAST +(11 rows) + +select c2, c6, sum(c1) from ft1 where c2 < 3 group by grouping sets(c2, c6) order by 1 nulls last, 2 nulls last; + c2 | c6 | sum +----+----+------- + 0 | | 50500 + 1 | | 49600 + 2 | | 49700 + | 0 | 50500 + | 1 | 49600 + | 2 | 49700 +(6 rows) + +explain (verbose, costs off) +select c2, sum(c1), grouping(c2) from ft1 where c2 < 3 group by c2 order by 1 nulls last; + QUERY PLAN +------------------------------------------------------------------------------ + Sort + Output: c2, (sum(c1)), (GROUPING(c2)) + Sort Key: ft1.c2 + -> HashAggregate + Output: c2, sum(c1), GROUPING(c2) + Group Key: ft1.c2 + -> Foreign Scan on public.ft1 + Output: c2, c1 + Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" WHERE ((c2 < 3)) +(9 rows) + +select c2, sum(c1), grouping(c2) from ft1 where c2 < 3 group by c2 order by 1 nulls last; + c2 | sum | grouping +----+-------+---------- + 0 | 50500 | 0 + 1 | 49600 | 0 + 2 | 49700 | 0 +(3 rows) + +-- DISTINCT itself is not pushed down, whereas underneath aggregate is pushed +explain (verbose, costs off) +select distinct sum(c1)/1000 s from ft2 where c2 < 6 group by c2 order by 1; + QUERY PLAN +-------------------------------------------------------------------------------------------------------- + Unique + Output: ((sum(c1) / 1000)), c2 + -> Sort + Output: ((sum(c1) / 1000)), c2 + Sort Key: ((sum(ft2.c1) / 1000)) + -> Foreign Scan + Output: ((sum(c1) / 1000)), c2 + Relations: Aggregate on (public.ft2) + Remote SQL: SELECT (sum("C 1") / 1000), c2 FROM "S 1"."T 1" WHERE ((c2 < 6)) GROUP BY c2 +(9 rows) + +select distinct sum(c1)/1000 s from ft2 where c2 < 6 group by c2 order by 1; + s +---- + 49 + 50 +(2 rows) + +-- WindowAgg +explain (verbose, costs off) +select c2, sum(c2), count(c2) over (partition by c2%2) from ft2 where c2 < 10 group by c2 order by 1; + QUERY PLAN +------------------------------------------------------------------------------------------------------------- + Sort + Output: c2, (sum(c2)), (count(c2) OVER (?)), ((c2 % 2)) + Sort Key: ft2.c2 + -> WindowAgg + Output: c2, (sum(c2)), count(c2) OVER (?), ((c2 % 2)) + -> Sort + Output: c2, ((c2 % 2)), (sum(c2)) + Sort Key: ((ft2.c2 % 2)) + -> Foreign Scan + Output: c2, ((c2 % 2)), (sum(c2)) + Relations: Aggregate on (public.ft2) + Remote SQL: SELECT c2, (c2 % 2), sum(c2) FROM "S 1"."T 1" WHERE ((c2 < 10)) GROUP BY c2 +(12 rows) + +select c2, sum(c2), count(c2) over (partition by c2%2) from ft2 where c2 < 10 group by c2 order by 1; + c2 | sum | count +----+-----+------- + 0 | 0 | 5 + 1 | 100 | 5 + 2 | 200 | 5 + 3 | 300 | 5 + 4 | 400 | 5 + 5 | 500 | 5 + 6 | 600 | 5 + 7 | 700 | 5 + 8 | 800 | 5 + 9 | 900 | 5 +(10 rows) + +explain (verbose, costs off) +select c2, array_agg(c2) over (partition by c2%2 order by c2 desc) from ft1 where c2 < 10 group by c2 order by 1; + QUERY PLAN +---------------------------------------------------------------------------------------------------- + Sort + Output: c2, (array_agg(c2) OVER (?)), ((c2 % 2)) + Sort Key: ft1.c2 + -> WindowAgg + Output: c2, array_agg(c2) OVER (?), ((c2 % 2)) + -> Sort + Output: c2, ((c2 % 2)) + Sort Key: ((ft1.c2 % 2)), ft1.c2 DESC + -> Foreign Scan + Output: c2, ((c2 % 2)) + Relations: Aggregate on (public.ft1) + Remote SQL: SELECT c2, (c2 % 2) FROM "S 1"."T 1" WHERE ((c2 < 10)) GROUP BY c2 +(12 rows) + +select c2, array_agg(c2) over (partition by c2%2 order by c2 desc) from ft1 where c2 < 10 group by c2 order by 1; + c2 | array_agg +----+------------- + 0 | {8,6,4,2,0} + 1 | {9,7,5,3,1} + 2 | {8,6,4,2} + 3 | {9,7,5,3} + 4 | {8,6,4} + 5 | {9,7,5} + 6 | {8,6} + 7 | {9,7} + 8 | {8} + 9 | {9} +(10 rows) + +explain (verbose, costs off) +select c2, array_agg(c2) over (partition by c2%2 order by c2 range between current row and unbounded following) from ft1 where c2 < 10 group by c2 order by 1; + QUERY PLAN +---------------------------------------------------------------------------------------------------- + Sort + Output: c2, (array_agg(c2) OVER (?)), ((c2 % 2)) + Sort Key: ft1.c2 + -> WindowAgg + Output: c2, array_agg(c2) OVER (?), ((c2 % 2)) + -> Sort + Output: c2, ((c2 % 2)) + Sort Key: ((ft1.c2 % 2)), ft1.c2 + -> Foreign Scan + Output: c2, ((c2 % 2)) + Relations: Aggregate on (public.ft1) + Remote SQL: SELECT c2, (c2 % 2) FROM "S 1"."T 1" WHERE ((c2 < 10)) GROUP BY c2 +(12 rows) + +select c2, array_agg(c2) over (partition by c2%2 order by c2 range between current row and unbounded following) from ft1 where c2 < 10 group by c2 order by 1; + c2 | array_agg +----+------------- + 0 | {0,2,4,6,8} + 1 | {1,3,5,7,9} + 2 | {2,4,6,8} + 3 | {3,5,7,9} + 4 | {4,6,8} + 5 | {5,7,9} + 6 | {6,8} + 7 | {7,9} + 8 | {8} + 9 | {9} +(10 rows) + -- =================================================================== -- parameterized queries -- =================================================================== @@ -2479,13 +3575,100 @@ EXECUTE st5('foo', 1); 1 | 1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1 | 1 | foo (1 row) +-- altering FDW options requires replanning +PREPARE st6 AS SELECT * FROM ft1 t1 WHERE t1.c1 = t1.c2; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st6; + QUERY PLAN +---------------------------------------------------------------------------------------------- + Foreign Scan on public.ft1 t1 + Output: c1, c2, c3, c4, c5, c6, c7, c8 + Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = c2)) +(3 rows) + +PREPARE st7 AS INSERT INTO ft1 (c1,c2,c3) VALUES (1001,101,'foo'); +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st7; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Insert on public.ft1 + Remote SQL: INSERT INTO "S 1"."T 1"("C 1", c2, c3, c4, c5, c6, c7, c8) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) + -> Result + Output: NULL::integer, 1001, 101, 'foo'::text, NULL::timestamp with time zone, NULL::timestamp without time zone, NULL::character varying, 'ft1 '::character(10), NULL::user_enum +(4 rows) + +ALTER TABLE "S 1"."T 1" RENAME TO "T 0"; +ALTER FOREIGN TABLE ft1 OPTIONS (SET table_name 'T 0'); +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st6; + QUERY PLAN +---------------------------------------------------------------------------------------------- + Foreign Scan on public.ft1 t1 + Output: c1, c2, c3, c4, c5, c6, c7, c8 + Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 0" WHERE (("C 1" = c2)) +(3 rows) + +EXECUTE st6; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 +----+----+-------+------------------------------+--------------------------+----+------------+----- + 1 | 1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1 | 1 | foo + 2 | 2 | 00002 | Sat Jan 03 00:00:00 1970 PST | Sat Jan 03 00:00:00 1970 | 2 | 2 | foo + 3 | 3 | 00003 | Sun Jan 04 00:00:00 1970 PST | Sun Jan 04 00:00:00 1970 | 3 | 3 | foo + 4 | 4 | 00004 | Mon Jan 05 00:00:00 1970 PST | Mon Jan 05 00:00:00 1970 | 4 | 4 | foo + 5 | 5 | 00005 | Tue Jan 06 00:00:00 1970 PST | Tue Jan 06 00:00:00 1970 | 5 | 5 | foo + 6 | 6 | 00006 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6 | 6 | foo + 7 | 7 | 00007 | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7 | 7 | foo + 8 | 8 | 00008 | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8 | 8 | foo + 9 | 9 | 00009 | Sat Jan 10 00:00:00 1970 PST | Sat Jan 10 00:00:00 1970 | 9 | 9 | foo +(9 rows) + +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st7; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Insert on public.ft1 + Remote SQL: INSERT INTO "S 1"."T 0"("C 1", c2, c3, c4, c5, c6, c7, c8) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) + -> Result + Output: NULL::integer, 1001, 101, 'foo'::text, NULL::timestamp with time zone, NULL::timestamp without time zone, NULL::character varying, 'ft1 '::character(10), NULL::user_enum +(4 rows) + +ALTER TABLE "S 1"."T 0" RENAME TO "T 1"; +ALTER FOREIGN TABLE ft1 OPTIONS (SET table_name 'T 1'); +PREPARE st8 AS SELECT count(c3) FROM ft1 t1 WHERE t1.c1 === t1.c2; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st8; + QUERY PLAN +----------------------------------------------------------------------------------------- + Foreign Scan + Output: (count(c3)) + Relations: Aggregate on (public.ft1 t1) + Remote SQL: SELECT count(c3) FROM "S 1"."T 1" WHERE (("C 1" OPERATOR(public.===) c2)) +(4 rows) + +ALTER SERVER loopback OPTIONS (DROP extensions); +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st8; + QUERY PLAN +----------------------------------------------------------- + Aggregate + Output: count(c3) + -> Foreign Scan on public.ft1 t1 + Output: c3 + Filter: (t1.c1 === t1.c2) + Remote SQL: SELECT "C 1", c2, c3 FROM "S 1"."T 1" +(6 rows) + +EXECUTE st8; + count +------- + 9 +(1 row) + +ALTER SERVER loopback OPTIONS (ADD extensions 'postgres_fdw'); -- cleanup DEALLOCATE st1; DEALLOCATE st2; DEALLOCATE st3; DEALLOCATE st4; DEALLOCATE st5; --- System columns, except ctid, should not be sent to remote +DEALLOCATE st6; +DEALLOCATE st7; +DEALLOCATE st8; +-- System columns, except ctid and oid, should not be sent to remote EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE t1.tableoid = 'pg_class'::regclass LIMIT 1; QUERY PLAN @@ -2553,6 +3736,21 @@ SELECT ctid, * FROM ft1 t1 LIMIT 1; (0,1) | 1 | 1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1 | 1 | foo (1 row) +EXPLAIN (VERBOSE, COSTS OFF) +SELECT oid, * FROM ft_pg_type WHERE typname = 'int4'; + QUERY PLAN +---------------------------------------------------------------------------------------------------- + Foreign Scan on public.ft_pg_type + Output: oid, typname, typlen + Remote SQL: SELECT typname, typlen, oid FROM pg_catalog.pg_type WHERE ((typname = 'int4'::name)) +(3 rows) + +SELECT oid, * FROM ft_pg_type WHERE typname = 'int4'; + oid | typname | typlen +-----+---------+-------- + 23 | int4 | 4 +(1 row) + -- =================================================================== -- used in pl/pgsql function -- =================================================================== @@ -2585,6 +3783,9 @@ CONTEXT: column "c8" of foreign table "ft1" SELECT ft1.c1, ft2.c2, ft1 FROM ft1, ft2 WHERE ft1.c1 = ft2.c1 AND ft1.c1 = 1; -- ERROR ERROR: invalid input syntax for integer: "foo" CONTEXT: whole-row reference to foreign table "ft1" +SELECT sum(c2), array_agg(c8) FROM ft1 GROUP BY c8; -- ERROR +ERROR: invalid input syntax for integer: "foo" +CONTEXT: processing expression at position 2 in select list ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE user_enum; -- =================================================================== -- subtransaction @@ -4418,12 +5619,12 @@ SELECT * FROM ft1 ORDER BY c6 ASC NULLS FIRST, c1 OFFSET 15 LIMIT 10; -- Consistent check constraints provide consistent results ALTER FOREIGN TABLE ft1 ADD CONSTRAINT ft1_c2positive CHECK (c2 >= 0); EXPLAIN (VERBOSE, COSTS OFF) SELECT count(*) FROM ft1 WHERE c2 < 0; - QUERY PLAN -------------------------------------------------------------------- - Aggregate - Output: count(*) - -> Foreign Scan on public.ft1 - Remote SQL: SELECT NULL FROM "S 1"."T 1" WHERE ((c2 < 0)) + QUERY PLAN +----------------------------------------------------------------- + Foreign Scan + Output: (count(*)) + Relations: Aggregate on (public.ft1) + Remote SQL: SELECT count(*) FROM "S 1"."T 1" WHERE ((c2 < 0)) (4 rows) SELECT count(*) FROM ft1 WHERE c2 < 0; @@ -4462,12 +5663,12 @@ ALTER FOREIGN TABLE ft1 DROP CONSTRAINT ft1_c2positive; -- But inconsistent check constraints provide inconsistent results ALTER FOREIGN TABLE ft1 ADD CONSTRAINT ft1_c2negative CHECK (c2 < 0); EXPLAIN (VERBOSE, COSTS OFF) SELECT count(*) FROM ft1 WHERE c2 >= 0; - QUERY PLAN --------------------------------------------------------------------- - Aggregate - Output: count(*) - -> Foreign Scan on public.ft1 - Remote SQL: SELECT NULL FROM "S 1"."T 1" WHERE ((c2 >= 0)) + QUERY PLAN +------------------------------------------------------------------ + Foreign Scan + Output: (count(*)) + Relations: Aggregate on (public.ft1) + Remote SQL: SELECT count(*) FROM "S 1"."T 1" WHERE ((c2 >= 0)) (4 rows) SELECT count(*) FROM ft1 WHERE c2 >= 0; @@ -5593,43 +6794,43 @@ IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest1; (5 rows) \d import_dest1.* - Foreign table "import_dest1.t1" - Column | Type | Modifiers | FDW Options ---------+-------------------+-----------+-------------------- - c1 | integer | | (column_name 'c1') - c2 | character varying | not null | (column_name 'c2') + Foreign table "import_dest1.t1" + Column | Type | Collation | Nullable | Default | FDW Options +--------+-------------------+-----------+----------+---------+-------------------- + c1 | integer | | | | (column_name 'c1') + c2 | character varying | | not null | | (column_name 'c2') Server: loopback FDW Options: (schema_name 'import_source', table_name 't1') - Foreign table "import_dest1.t2" - Column | Type | Modifiers | FDW Options ---------+-------------------+---------------+-------------------- - c1 | integer | | (column_name 'c1') - c2 | character varying | | (column_name 'c2') - c3 | text | collate POSIX | (column_name 'c3') + Foreign table "import_dest1.t2" + Column | Type | Collation | Nullable | Default | FDW Options +--------+-------------------+-----------+----------+---------+-------------------- + c1 | integer | | | | (column_name 'c1') + c2 | character varying | | | | (column_name 'c2') + c3 | text | POSIX | | | (column_name 'c3') Server: loopback FDW Options: (schema_name 'import_source', table_name 't2') - Foreign table "import_dest1.t3" - Column | Type | Modifiers | FDW Options ---------+--------------------------+-----------+-------------------- - c1 | timestamp with time zone | | (column_name 'c1') - c2 | typ1 | | (column_name 'c2') + Foreign table "import_dest1.t3" + Column | Type | Collation | Nullable | Default | FDW Options +--------+--------------------------+-----------+----------+---------+-------------------- + c1 | timestamp with time zone | | | | (column_name 'c1') + c2 | typ1 | | | | (column_name 'c2') Server: loopback FDW Options: (schema_name 'import_source', table_name 't3') - Foreign table "import_dest1.x 4" - Column | Type | Modifiers | FDW Options ---------+-----------------------+-----------+--------------------- - c1 | double precision | | (column_name 'c1') - C 2 | text | | (column_name 'C 2') - c3 | character varying(42) | | (column_name 'c3') + Foreign table "import_dest1.x 4" + Column | Type | Collation | Nullable | Default | FDW Options +--------+-----------------------+-----------+----------+---------+--------------------- + c1 | double precision | | | | (column_name 'c1') + C 2 | text | | | | (column_name 'C 2') + c3 | character varying(42) | | | | (column_name 'c3') Server: loopback FDW Options: (schema_name 'import_source', table_name 'x 4') - Foreign table "import_dest1.x 5" - Column | Type | Modifiers | FDW Options ---------+------+-----------+------------- + Foreign table "import_dest1.x 5" + Column | Type | Collation | Nullable | Default | FDW Options +--------+------+-----------+----------+---------+------------- Server: loopback FDW Options: (schema_name 'import_source', table_name 'x 5') @@ -5649,43 +6850,43 @@ IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest2 (5 rows) \d import_dest2.* - Foreign table "import_dest2.t1" - Column | Type | Modifiers | FDW Options ---------+-------------------+-----------+-------------------- - c1 | integer | | (column_name 'c1') - c2 | character varying | not null | (column_name 'c2') + Foreign table "import_dest2.t1" + Column | Type | Collation | Nullable | Default | FDW Options +--------+-------------------+-----------+----------+---------+-------------------- + c1 | integer | | | | (column_name 'c1') + c2 | character varying | | not null | | (column_name 'c2') Server: loopback FDW Options: (schema_name 'import_source', table_name 't1') - Foreign table "import_dest2.t2" - Column | Type | Modifiers | FDW Options ---------+-------------------+---------------+-------------------- - c1 | integer | default 42 | (column_name 'c1') - c2 | character varying | | (column_name 'c2') - c3 | text | collate POSIX | (column_name 'c3') + Foreign table "import_dest2.t2" + Column | Type | Collation | Nullable | Default | FDW Options +--------+-------------------+-----------+----------+---------+-------------------- + c1 | integer | | | 42 | (column_name 'c1') + c2 | character varying | | | | (column_name 'c2') + c3 | text | POSIX | | | (column_name 'c3') Server: loopback FDW Options: (schema_name 'import_source', table_name 't2') - Foreign table "import_dest2.t3" - Column | Type | Modifiers | FDW Options ---------+--------------------------+---------------+-------------------- - c1 | timestamp with time zone | default now() | (column_name 'c1') - c2 | typ1 | | (column_name 'c2') + Foreign table "import_dest2.t3" + Column | Type | Collation | Nullable | Default | FDW Options +--------+--------------------------+-----------+----------+---------+-------------------- + c1 | timestamp with time zone | | | now() | (column_name 'c1') + c2 | typ1 | | | | (column_name 'c2') Server: loopback FDW Options: (schema_name 'import_source', table_name 't3') - Foreign table "import_dest2.x 4" - Column | Type | Modifiers | FDW Options ---------+-----------------------+-----------+--------------------- - c1 | double precision | | (column_name 'c1') - C 2 | text | | (column_name 'C 2') - c3 | character varying(42) | | (column_name 'c3') + Foreign table "import_dest2.x 4" + Column | Type | Collation | Nullable | Default | FDW Options +--------+-----------------------+-----------+----------+---------+--------------------- + c1 | double precision | | | | (column_name 'c1') + C 2 | text | | | | (column_name 'C 2') + c3 | character varying(42) | | | | (column_name 'c3') Server: loopback FDW Options: (schema_name 'import_source', table_name 'x 4') - Foreign table "import_dest2.x 5" - Column | Type | Modifiers | FDW Options ---------+------+-----------+------------- + Foreign table "import_dest2.x 5" + Column | Type | Collation | Nullable | Default | FDW Options +--------+------+-----------+----------+---------+------------- Server: loopback FDW Options: (schema_name 'import_source', table_name 'x 5') @@ -5704,43 +6905,43 @@ IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest3 (5 rows) \d import_dest3.* - Foreign table "import_dest3.t1" - Column | Type | Modifiers | FDW Options ---------+-------------------+-----------+-------------------- - c1 | integer | | (column_name 'c1') - c2 | character varying | | (column_name 'c2') + Foreign table "import_dest3.t1" + Column | Type | Collation | Nullable | Default | FDW Options +--------+-------------------+-----------+----------+---------+-------------------- + c1 | integer | | | | (column_name 'c1') + c2 | character varying | | | | (column_name 'c2') Server: loopback FDW Options: (schema_name 'import_source', table_name 't1') - Foreign table "import_dest3.t2" - Column | Type | Modifiers | FDW Options ---------+-------------------+-----------+-------------------- - c1 | integer | | (column_name 'c1') - c2 | character varying | | (column_name 'c2') - c3 | text | | (column_name 'c3') + Foreign table "import_dest3.t2" + Column | Type | Collation | Nullable | Default | FDW Options +--------+-------------------+-----------+----------+---------+-------------------- + c1 | integer | | | | (column_name 'c1') + c2 | character varying | | | | (column_name 'c2') + c3 | text | | | | (column_name 'c3') Server: loopback FDW Options: (schema_name 'import_source', table_name 't2') - Foreign table "import_dest3.t3" - Column | Type | Modifiers | FDW Options ---------+--------------------------+-----------+-------------------- - c1 | timestamp with time zone | | (column_name 'c1') - c2 | typ1 | | (column_name 'c2') + Foreign table "import_dest3.t3" + Column | Type | Collation | Nullable | Default | FDW Options +--------+--------------------------+-----------+----------+---------+-------------------- + c1 | timestamp with time zone | | | | (column_name 'c1') + c2 | typ1 | | | | (column_name 'c2') Server: loopback FDW Options: (schema_name 'import_source', table_name 't3') - Foreign table "import_dest3.x 4" - Column | Type | Modifiers | FDW Options ---------+-----------------------+-----------+--------------------- - c1 | double precision | | (column_name 'c1') - C 2 | text | | (column_name 'C 2') - c3 | character varying(42) | | (column_name 'c3') + Foreign table "import_dest3.x 4" + Column | Type | Collation | Nullable | Default | FDW Options +--------+-----------------------+-----------+----------+---------+--------------------- + c1 | double precision | | | | (column_name 'c1') + C 2 | text | | | | (column_name 'C 2') + c3 | character varying(42) | | | | (column_name 'c3') Server: loopback FDW Options: (schema_name 'import_source', table_name 'x 4') - Foreign table "import_dest3.x 5" - Column | Type | Modifiers | FDW Options ---------+------+-----------+------------- + Foreign table "import_dest3.x 5" + Column | Type | Collation | Nullable | Default | FDW Options +--------+------+-----------+----------+---------+------------- Server: loopback FDW Options: (schema_name 'import_source', table_name 'x 5') diff --git a/contrib/postgres_fdw/option.c b/contrib/postgres_fdw/option.c index 224aed948e..e24db569ea 100644 --- a/contrib/postgres_fdw/option.c +++ b/contrib/postgres_fdw/option.c @@ -3,7 +3,7 @@ * option.c * FDW option handling for postgres_fdw * - * Portions Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/postgres_fdw/option.c @@ -21,6 +21,7 @@ #include "commands/defrem.h" #include "commands/extension.h" #include "utils/builtins.h" +#include "utils/varlena.h" /* diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index 931bcfd37d..ce1f443d55 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -3,7 +3,7 @@ * postgres_fdw.c * Foreign-data wrapper for remote PostgreSQL servers * - * Portions Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/postgres_fdw/postgres_fdw.c @@ -25,6 +25,7 @@ #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" #include "optimizer/cost.h" +#include "optimizer/clauses.h" #include "optimizer/pathnode.h" #include "optimizer/paths.h" #include "optimizer/planmain.h" @@ -38,6 +39,7 @@ #include "utils/memutils.h" #include "utils/rel.h" #include "utils/sampling.h" +#include "utils/selfuncs.h" PG_MODULE_MAGIC; @@ -343,6 +345,10 @@ static void postgresGetForeignJoinPaths(PlannerInfo *root, JoinPathExtraData *extra); static bool postgresRecheckForeignScan(ForeignScanState *node, TupleTableSlot *slot); +static void postgresGetForeignUpperPaths(PlannerInfo *root, + UpperRelationKind stage, + RelOptInfo *input_rel, + RelOptInfo *output_rel); /* * Helper functions @@ -400,11 +406,15 @@ static void conversion_error_callback(void *arg); static bool foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, RelOptInfo *outerrel, RelOptInfo *innerrel, JoinPathExtraData *extra); +static bool foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel); static List *get_useful_pathkeys_for_relation(PlannerInfo *root, RelOptInfo *rel); static List *get_useful_ecs_for_relation(PlannerInfo *root, RelOptInfo *rel); static void add_paths_with_pathkeys_for_rel(PlannerInfo *root, RelOptInfo *rel, Path *epq_path); +static void add_foreign_grouping_paths(PlannerInfo *root, + RelOptInfo *input_rel, + RelOptInfo *grouped_rel); /* @@ -455,6 +465,9 @@ postgres_fdw_handler(PG_FUNCTION_ARGS) /* Support functions for join push-down */ routine->GetForeignJoinPaths = postgresGetForeignJoinPaths; + /* Support functions for upper relation push-down */ + routine->GetForeignUpperPaths = postgresGetForeignUpperPaths; + PG_RETURN_POINTER(routine); } @@ -484,7 +497,7 @@ postgresGetForeignRelSize(PlannerInfo *root, fpinfo = (PgFdwRelationInfo *) palloc0(sizeof(PgFdwRelationInfo)); baserel->fdw_private = (void *) fpinfo; - /* Base foreign tables need to be push down always. */ + /* Base foreign tables need to be pushed down always. */ fpinfo->pushdown_safe = true; /* Look up foreign-table catalog info. */ @@ -1120,7 +1133,7 @@ postgresGetForeignPlan(PlannerInfo *root, * rel->baserestrictinfo + parameterization clauses through * scan_clauses. For a join rel->baserestrictinfo is NIL and we are * not considering parameterization right now, so there should be no - * scan_clauses for a joinrel. + * scan_clauses for a joinrel and upper rel either. */ Assert(!scan_clauses); } @@ -1170,7 +1183,8 @@ postgresGetForeignPlan(PlannerInfo *root, local_exprs = lappend(local_exprs, rinfo->clause); } - if (foreignrel->reloptkind == RELOPT_JOINREL) + if (foreignrel->reloptkind == RELOPT_JOINREL || + foreignrel->reloptkind == RELOPT_UPPER_REL) { /* For a join relation, get the conditions from fdw_private structure */ remote_conds = fpinfo->remote_conds; @@ -1191,6 +1205,13 @@ postgresGetForeignPlan(PlannerInfo *root, { ListCell *lc; + /* + * Right now, we only consider grouping and aggregation beyond + * joins. Queries involving aggregates or grouping do not require + * EPQ mechanism, hence should not have an outer plan here. + */ + Assert(foreignrel->reloptkind != RELOPT_UPPER_REL); + outer_plan->targetlist = fdw_scan_tlist; foreach(lc, local_exprs) @@ -1228,7 +1249,8 @@ postgresGetForeignPlan(PlannerInfo *root, remote_conds, retrieved_attrs, makeInteger(fpinfo->fetch_size)); - if (foreignrel->reloptkind == RELOPT_JOINREL) + if (foreignrel->reloptkind == RELOPT_JOINREL || + foreignrel->reloptkind == RELOPT_UPPER_REL) fdw_private = lappend(fdw_private, makeString(fpinfo->relation_name->data)); @@ -1280,8 +1302,9 @@ postgresBeginForeignScan(ForeignScanState *node, int eflags) /* * Identify which user to do the remote access as. This should match what - * ExecCheckRTEPerms() does. In case of a join, use the lowest-numbered - * member RTE as a representative; we would get the same result from any. + * ExecCheckRTEPerms() does. In case of a join or aggregate, use the + * lowest-numbered member RTE as a representative; we would get the same + * result from any. */ if (fsplan->scan.scanrelid > 0) rtindex = fsplan->scan.scanrelid; @@ -1315,14 +1338,10 @@ postgresBeginForeignScan(ForeignScanState *node, int eflags) /* Create contexts for batches of tuples and per-tuple temp workspace. */ fsstate->batch_cxt = AllocSetContextCreate(estate->es_query_cxt, "postgres_fdw tuple data", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); fsstate->temp_cxt = AllocSetContextCreate(estate->es_query_cxt, "postgres_fdw temporary data", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MAXSIZE); + ALLOCSET_SMALL_SIZES); /* * Get info we'll need for converting data fetched from the foreign server @@ -1695,9 +1714,7 @@ postgresBeginForeignModify(ModifyTableState *mtstate, /* Create context for per-tuple temp workspace. */ fmstate->temp_cxt = AllocSetContextCreate(estate->es_query_cxt, "postgres_fdw temporary data", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MAXSIZE); + ALLOCSET_SMALL_SIZES); /* Prepare for input conversion of RETURNING results. */ if (fmstate->has_returning) @@ -2294,9 +2311,7 @@ postgresBeginDirectModify(ForeignScanState *node, int eflags) /* Create context for per-tuple temp workspace. */ dmstate->temp_cxt = AllocSetContextCreate(estate->es_query_cxt, "postgres_fdw temporary data", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MAXSIZE); + ALLOCSET_SMALL_SIZES); /* Prepare for input conversion of RETURNING results. */ if (dmstate->has_returning) @@ -2460,7 +2475,8 @@ postgresExplainDirectModify(ForeignScanState *node, ExplainState *es) /* * estimate_path_cost_size * Get cost and size estimates for a foreign scan on given foreign relation - * either a base relation or a join between foreign relations. + * either a base relation or a join between foreign relations or an upper + * relation containing foreign relations. * * param_join_conds are the parameterization clauses with outer relations. * pathkeys specify the expected sort order if any for given path being costed. @@ -2513,7 +2529,8 @@ estimate_path_cost_size(PlannerInfo *root, &remote_param_join_conds, &local_param_join_conds); /* Build the list of columns to be fetched from the foreign server. */ - if (foreignrel->reloptkind == RELOPT_JOINREL) + if (foreignrel->reloptkind == RELOPT_JOINREL || + foreignrel->reloptkind == RELOPT_UPPER_REL) fdw_scan_tlist = build_tlist_to_deparse(foreignrel); else fdw_scan_tlist = NIL; @@ -2594,25 +2611,7 @@ estimate_path_cost_size(PlannerInfo *root, startup_cost = fpinfo->rel_startup_cost; run_cost = fpinfo->rel_total_cost - fpinfo->rel_startup_cost; } - else if (foreignrel->reloptkind != RELOPT_JOINREL) - { - /* Clamp retrieved rows estimates to at most foreignrel->tuples. */ - retrieved_rows = Min(retrieved_rows, foreignrel->tuples); - - /* - * Cost as though this were a seqscan, which is pessimistic. We - * effectively imagine the local_conds are being evaluated - * remotely, too. - */ - startup_cost = 0; - run_cost = 0; - run_cost += seq_page_cost * foreignrel->pages; - - startup_cost += foreignrel->baserestrictcost.startup; - cpu_per_tuple = cpu_tuple_cost + foreignrel->baserestrictcost.per_tuple; - run_cost += cpu_per_tuple * foreignrel->tuples; - } - else + else if (foreignrel->reloptkind == RELOPT_JOINREL) { PgFdwRelationInfo *fpinfo_i; PgFdwRelationInfo *fpinfo_o; @@ -2637,7 +2636,9 @@ estimate_path_cost_size(PlannerInfo *root, * rows. */ - /* Calculate the cost of clauses pushed down the foreign server */ + /* + * Calculate the cost of clauses pushed down to the foreign server + */ cost_qual_eval(&remote_conds_cost, fpinfo->remote_conds, root); /* Calculate the cost of applying join clauses */ cost_qual_eval(&join_cost, fpinfo->joinclauses, root); @@ -2676,6 +2677,99 @@ estimate_path_cost_size(PlannerInfo *root, run_cost += nrows * remote_conds_cost.per_tuple; run_cost += fpinfo->local_conds_cost.per_tuple * retrieved_rows; } + else if (foreignrel->reloptkind == RELOPT_UPPER_REL) + { + PgFdwRelationInfo *ofpinfo; + PathTarget *ptarget = root->upper_targets[UPPERREL_GROUP_AGG]; + AggClauseCosts aggcosts; + double input_rows; + int numGroupCols; + double numGroups = 1; + + /* + * This cost model is mixture of costing done for sorted and + * hashed aggregates in cost_agg(). We are not sure which + * strategy will be considered at remote side, thus for + * simplicity, we put all startup related costs in startup_cost + * and all finalization and run cost are added in total_cost. + * + * Also, core does not care about costing HAVING expressions and + * adding that to the costs. So similarly, here too we are not + * considering remote and local conditions for costing. + */ + + ofpinfo = (PgFdwRelationInfo *) fpinfo->outerrel->fdw_private; + + /* Get rows and width from input rel */ + input_rows = ofpinfo->rows; + width = ofpinfo->width; + + /* Collect statistics about aggregates for estimating costs. */ + MemSet(&aggcosts, 0, sizeof(AggClauseCosts)); + if (root->parse->hasAggs) + { + get_agg_clause_costs(root, (Node *) fpinfo->grouped_tlist, + AGGSPLIT_SIMPLE, &aggcosts); + get_agg_clause_costs(root, (Node *) root->parse->havingQual, + AGGSPLIT_SIMPLE, &aggcosts); + } + + /* Get number of grouping columns and possible number of groups */ + numGroupCols = list_length(root->parse->groupClause); + numGroups = estimate_num_groups(root, + get_sortgrouplist_exprs(root->parse->groupClause, + fpinfo->grouped_tlist), + input_rows, NULL); + + /* + * Number of rows expected from foreign server will be same as + * that of number of groups. + */ + rows = retrieved_rows = numGroups; + + /*----- + * Startup cost includes: + * 1. Startup cost for underneath input * relation + * 2. Cost of performing aggregation, per cost_agg() + * 3. Startup cost for PathTarget eval + *----- + */ + startup_cost = ofpinfo->rel_startup_cost; + startup_cost += aggcosts.transCost.startup; + startup_cost += aggcosts.transCost.per_tuple * input_rows; + startup_cost += (cpu_operator_cost * numGroupCols) * input_rows; + startup_cost += ptarget->cost.startup; + + /*----- + * Run time cost includes: + * 1. Run time cost of underneath input relation + * 2. Run time cost of performing aggregation, per cost_agg() + * 3. PathTarget eval cost for each output row + *----- + */ + run_cost = ofpinfo->rel_total_cost - ofpinfo->rel_startup_cost; + run_cost += aggcosts.finalCost * numGroups; + run_cost += cpu_tuple_cost * numGroups; + run_cost += ptarget->cost.per_tuple * numGroups; + } + else + { + /* Clamp retrieved rows estimates to at most foreignrel->tuples. */ + retrieved_rows = Min(retrieved_rows, foreignrel->tuples); + + /* + * Cost as though this were a seqscan, which is pessimistic. We + * effectively imagine the local_conds are being evaluated + * remotely, too. + */ + startup_cost = 0; + run_cost = 0; + run_cost += seq_page_cost * foreignrel->pages; + + startup_cost += foreignrel->baserestrictcost.startup; + cpu_per_tuple = cpu_tuple_cost + foreignrel->baserestrictcost.per_tuple; + run_cost += cpu_per_tuple * foreignrel->tuples; + } /* * Without remote estimates, we have no real way to estimate the cost @@ -3350,7 +3444,7 @@ process_query_params(ExprContext *econtext, bool isNull; /* Evaluate the parameter expression */ - expr_value = ExecEvalExpr(expr_state, econtext, &isNull, NULL); + expr_value = ExecEvalExpr(expr_state, econtext, &isNull); /* * Get string representation of each parameter value by invoking @@ -3479,9 +3573,7 @@ postgresAcquireSampleRowsFunc(Relation relation, int elevel, astate.anl_cxt = CurrentMemoryContext; astate.temp_cxt = AllocSetContextCreate(CurrentMemoryContext, "postgres_fdw temporary data", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MAXSIZE); + ALLOCSET_SMALL_SIZES); /* * Get the connection to use. We do the remote access as the table's @@ -4064,7 +4156,7 @@ foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, * other remote clauses. For LEFT and RIGHT OUTER join, the clauses from * the outer side are added to remote_conds since those can be evaluated * after the join is evaluated. The clauses from inner side are added to - * the joinclauses, since they need to evaluated while constructing the + * the joinclauses, since they need to be evaluated while constructing the * join. * * For a FULL OUTER JOIN, the other clauses from either relation can not @@ -4339,7 +4431,7 @@ postgresGetForeignJoinPaths(PlannerInfo *root, NIL, /* no pathkeys */ NULL, /* no required_outer */ epq_path, - NULL); /* no fdw_private */ + NIL); /* no fdw_private */ /* Add generated path into joinrel by add_path(). */ add_path(joinrel, (Path *) joinpath); @@ -4350,6 +4442,318 @@ postgresGetForeignJoinPaths(PlannerInfo *root, /* XXX Consider parameterized paths for the join relation */ } +/* + * Assess whether the aggregation, grouping and having operations can be pushed + * down to the foreign server. As a side effect, save information we obtain in + * this function to PgFdwRelationInfo of the input relation. + */ +static bool +foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel) +{ + Query *query = root->parse; + PathTarget *grouping_target; + PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) grouped_rel->fdw_private; + PgFdwRelationInfo *ofpinfo; + List *aggvars; + ListCell *lc; + int i; + List *tlist = NIL; + + /* Grouping Sets are not pushable */ + if (query->groupingSets) + return false; + + /* Get the fpinfo of the underlying scan relation. */ + ofpinfo = (PgFdwRelationInfo *) fpinfo->outerrel->fdw_private; + + /* + * If underneath input relation has any local conditions, those conditions + * are required to be applied before performing aggregation. Hence the + * aggregate cannot be pushed down. + */ + if (ofpinfo->local_conds) + return false; + + /* + * The targetlist expected from this node and the targetlist pushed down + * to the foreign server may be different. The latter requires + * sortgrouprefs to be set to push down GROUP BY clause, but should not + * have those arising from ORDER BY clause. These sortgrouprefs may be + * different from those in the plan's targetlist. Use a copy of path + * target to record the new sortgrouprefs. + */ + grouping_target = copy_pathtarget(root->upper_targets[UPPERREL_GROUP_AGG]); + + /* + * Evaluate grouping targets and check whether they are safe to push down + * to the foreign side. All GROUP BY expressions will be part of the + * grouping target and thus there is no need to evaluate it separately. + * While doing so, add required expressions into target list which can + * then be used to pass to foreign server. + */ + i = 0; + foreach(lc, grouping_target->exprs) + { + Expr *expr = (Expr *) lfirst(lc); + Index sgref = get_pathtarget_sortgroupref(grouping_target, i); + ListCell *l; + + /* Check whether this expression is part of GROUP BY clause */ + if (sgref && get_sortgroupref_clause_noerr(sgref, query->groupClause)) + { + /* + * If any of the GROUP BY expression is not shippable we can not + * push down aggregation to the foreign server. + */ + if (!is_foreign_expr(root, grouped_rel, expr)) + return false; + + /* Pushable, add to tlist */ + tlist = add_to_flat_tlist(tlist, list_make1(expr)); + } + else + { + /* Check entire expression whether it is pushable or not */ + if (is_foreign_expr(root, grouped_rel, expr)) + { + /* Pushable, add to tlist */ + tlist = add_to_flat_tlist(tlist, list_make1(expr)); + } + else + { + /* + * If we have sortgroupref set, then it means that we have an + * ORDER BY entry pointing to this expression. Since we are + * not pushing ORDER BY with GROUP BY, clear it. + */ + if (sgref) + grouping_target->sortgrouprefs[i] = 0; + + /* Not matched exactly, pull the var with aggregates then */ + aggvars = pull_var_clause((Node *) expr, + PVC_INCLUDE_AGGREGATES); + + if (!is_foreign_expr(root, grouped_rel, (Expr *) aggvars)) + return false; + + /* + * Add aggregates, if any, into the targetlist. Plain var + * nodes should be either same as some GROUP BY expression or + * part of some GROUP BY expression. In later case, the query + * cannot refer plain var nodes without the surrounding + * expression. In both the cases, they are already part of + * the targetlist and thus no need to add them again. In fact + * adding pulled plain var nodes in SELECT clause will cause + * an error on the foreign server if they are not same as some + * GROUP BY expression. + */ + foreach(l, aggvars) + { + Expr *expr = (Expr *) lfirst(l); + + if (IsA(expr, Aggref)) + tlist = add_to_flat_tlist(tlist, list_make1(expr)); + } + } + } + + i++; + } + + /* + * Classify the pushable and non-pushable having clauses and save them in + * remote_conds and local_conds of the grouped rel's fpinfo. + */ + if (root->hasHavingQual && query->havingQual) + { + ListCell *lc; + + foreach(lc, (List *) query->havingQual) + { + Expr *expr = (Expr *) lfirst(lc); + + if (!is_foreign_expr(root, grouped_rel, expr)) + fpinfo->local_conds = lappend(fpinfo->local_conds, expr); + else + fpinfo->remote_conds = lappend(fpinfo->remote_conds, expr); + } + } + + /* + * If there are any local conditions, pull Vars and aggregates from it and + * check whether they are safe to pushdown or not. + */ + if (fpinfo->local_conds) + { + ListCell *lc; + List *aggvars = pull_var_clause((Node *) fpinfo->local_conds, + PVC_INCLUDE_AGGREGATES); + + foreach(lc, aggvars) + { + Expr *expr = (Expr *) lfirst(lc); + + /* + * If aggregates within local conditions are not safe to push + * down, then we cannot push down the query. Vars are already + * part of GROUP BY clause which are checked above, so no need to + * access them again here. + */ + if (IsA(expr, Aggref)) + { + if (!is_foreign_expr(root, grouped_rel, expr)) + return false; + + tlist = add_to_flat_tlist(tlist, aggvars); + } + } + } + + /* Transfer any sortgroupref data to the replacement tlist */ + apply_pathtarget_labeling_to_tlist(tlist, grouping_target); + + /* Store generated targetlist */ + fpinfo->grouped_tlist = tlist; + + /* Safe to pushdown */ + fpinfo->pushdown_safe = true; + + /* + * If user is willing to estimate cost for a scan using EXPLAIN, he + * intends to estimate scans on that relation more accurately. Then, it + * makes sense to estimate the cost of the grouping on that relation more + * accurately using EXPLAIN. + */ + fpinfo->use_remote_estimate = ofpinfo->use_remote_estimate; + + /* Copy startup and tuple cost as is from underneath input rel's fpinfo */ + fpinfo->fdw_startup_cost = ofpinfo->fdw_startup_cost; + fpinfo->fdw_tuple_cost = ofpinfo->fdw_tuple_cost; + + /* + * Set cached relation costs to some negative value, so that we can detect + * when they are set to some sensible costs, during one (usually the + * first) of the calls to estimate_path_cost_size(). + */ + fpinfo->rel_startup_cost = -1; + fpinfo->rel_total_cost = -1; + + /* Set fetch size same as that of underneath input rel's fpinfo */ + fpinfo->fetch_size = ofpinfo->fetch_size; + + /* + * Set the string describing this grouped relation to be used in EXPLAIN + * output of corresponding ForeignScan. + */ + fpinfo->relation_name = makeStringInfo(); + appendStringInfo(fpinfo->relation_name, "Aggregate on (%s)", + ofpinfo->relation_name->data); + + return true; +} + +/* + * postgresGetForeignUpperPaths + * Add paths for post-join operations like aggregation, grouping etc. if + * corresponding operations are safe to push down. + * + * Right now, we only support aggregate, grouping and having clause pushdown. + */ +static void +postgresGetForeignUpperPaths(PlannerInfo *root, UpperRelationKind stage, + RelOptInfo *input_rel, RelOptInfo *output_rel) +{ + PgFdwRelationInfo *fpinfo; + + /* + * If input rel is not safe to pushdown, then simply return as we cannot + * perform any post-join operations on the foreign server. + */ + if (!input_rel->fdw_private || + !((PgFdwRelationInfo *) input_rel->fdw_private)->pushdown_safe) + return; + + /* Ignore stages we don't support; and skip any duplicate calls. */ + if (stage != UPPERREL_GROUP_AGG || output_rel->fdw_private) + return; + + fpinfo = (PgFdwRelationInfo *) palloc0(sizeof(PgFdwRelationInfo)); + fpinfo->pushdown_safe = false; + output_rel->fdw_private = fpinfo; + + add_foreign_grouping_paths(root, input_rel, output_rel); +} + +/* + * add_foreign_grouping_paths + * Add foreign path for grouping and/or aggregation. + * + * Given input_rel represents the underlying scan. The paths are added to the + * given grouped_rel. + */ +static void +add_foreign_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel, + RelOptInfo *grouped_rel) +{ + Query *parse = root->parse; + PgFdwRelationInfo *ifpinfo = input_rel->fdw_private; + PgFdwRelationInfo *fpinfo = grouped_rel->fdw_private; + ForeignPath *grouppath; + PathTarget *grouping_target; + double rows; + int width; + Cost startup_cost; + Cost total_cost; + + /* Nothing to be done, if there is no grouping or aggregation required. */ + if (!parse->groupClause && !parse->groupingSets && !parse->hasAggs && + !root->hasHavingQual) + return; + + grouping_target = root->upper_targets[UPPERREL_GROUP_AGG]; + + /* save the input_rel as outerrel in fpinfo */ + fpinfo->outerrel = input_rel; + + /* + * Copy foreign table, foreign server, user mapping, shippable extensions + * etc. details from the input relation's fpinfo. + */ + fpinfo->table = ifpinfo->table; + fpinfo->server = ifpinfo->server; + fpinfo->user = ifpinfo->user; + fpinfo->shippable_extensions = ifpinfo->shippable_extensions; + + /* Assess if it is safe to push down aggregation and grouping. */ + if (!foreign_grouping_ok(root, grouped_rel)) + return; + + /* Estimate the cost of push down */ + estimate_path_cost_size(root, grouped_rel, NIL, NIL, &rows, + &width, &startup_cost, &total_cost); + + /* Now update this information in the fpinfo */ + fpinfo->rows = rows; + fpinfo->width = width; + fpinfo->startup_cost = startup_cost; + fpinfo->total_cost = total_cost; + + /* Create and add foreign path to the grouping relation. */ + grouppath = create_foreignscan_path(root, + grouped_rel, + grouping_target, + rows, + startup_cost, + total_cost, + NIL, /* no pathkeys */ + NULL, /* no required_outer */ + NULL, + NIL); /* no fdw_private */ + + /* Add generated path into grouped_rel by add_path(). */ + add_path(grouped_rel, (Path *) grouppath); +} + /* * Create a tuple from the specified row of the PGresult. * @@ -4372,6 +4776,7 @@ make_tuple_from_result_row(PGresult *res, Datum *values; bool *nulls; ItemPointer ctid = NULL; + Oid oid = InvalidOid; ConversionLocation errpos; ErrorContextCallback errcallback; MemoryContext oldcontext; @@ -4429,7 +4834,11 @@ make_tuple_from_result_row(PGresult *res, else valstr = PQgetvalue(res, row, j); - /* convert value to internal representation */ + /* + * convert value to internal representation + * + * Note: we ignore system columns other than ctid and oid in result + */ errpos.cur_attno = i; if (i > 0) { @@ -4444,7 +4853,7 @@ make_tuple_from_result_row(PGresult *res, } else if (i == SelfItemPointerAttributeNumber) { - /* ctid --- note we ignore any other system column in result */ + /* ctid */ if (valstr != NULL) { Datum datum; @@ -4453,6 +4862,17 @@ make_tuple_from_result_row(PGresult *res, ctid = (ItemPointer) DatumGetPointer(datum); } } + else if (i == ObjectIdAttributeNumber) + { + /* oid */ + if (valstr != NULL) + { + Datum datum; + + datum = DirectFunctionCall1(oidin, CStringGetDatum(valstr)); + oid = DatumGetObjectId(datum); + } + } errpos.cur_attno = 0; j++; @@ -4496,6 +4916,12 @@ make_tuple_from_result_row(PGresult *res, HeapTupleHeaderSetXmin(tuple->t_data, InvalidTransactionId); HeapTupleHeaderSetCmin(tuple->t_data, InvalidTransactionId); + /* + * If we have an OID to return, install it. + */ + if (OidIsValid(oid)) + HeapTupleSetOid(tuple, oid); + /* Clean up */ MemoryContextReset(temp_context); @@ -4523,6 +4949,8 @@ conversion_error_callback(void *arg) attname = NameStr(tupdesc->attrs[errpos->cur_attno - 1]->attname); else if (errpos->cur_attno == SelfItemPointerAttributeNumber) attname = "ctid"; + else if (errpos->cur_attno == ObjectIdAttributeNumber) + attname = "oid"; relname = RelationGetRelationName(errpos->rel); } @@ -4533,24 +4961,34 @@ conversion_error_callback(void *arg) ForeignScan *fsplan = (ForeignScan *) fsstate->ss.ps.plan; EState *estate = fsstate->ss.ps.state; TargetEntry *tle; - Var *var; - RangeTblEntry *rte; Assert(IsA(fsplan, ForeignScan)); tle = (TargetEntry *) list_nth(fsplan->fdw_scan_tlist, errpos->cur_attno - 1); Assert(IsA(tle, TargetEntry)); - var = (Var *) tle->expr; - Assert(IsA(var, Var)); - rte = rt_fetch(var->varno, estate->es_range_table); + /* + * Target list can have Vars and expressions. For Vars, we can get + * it's relation, however for expressions we can't. Thus for + * expressions, just show generic context message. + */ + if (IsA(tle->expr, Var)) + { + RangeTblEntry *rte; + Var *var = (Var *) tle->expr; + + rte = rt_fetch(var->varno, estate->es_range_table); - if (var->varattno == 0) - is_wholerow = true; - else - attname = get_relid_attribute_name(rte->relid, var->varattno); + if (var->varattno == 0) + is_wholerow = true; + else + attname = get_relid_attribute_name(rte->relid, var->varattno); - relname = get_rel_name(rte->relid); + relname = get_rel_name(rte->relid); + } + else + errcontext("processing expression at position %d in select list", + errpos->cur_attno); } if (relname) diff --git a/contrib/postgres_fdw/postgres_fdw.h b/contrib/postgres_fdw/postgres_fdw.h index 67126bc421..46cac55e98 100644 --- a/contrib/postgres_fdw/postgres_fdw.h +++ b/contrib/postgres_fdw/postgres_fdw.h @@ -3,7 +3,7 @@ * postgres_fdw.h * Foreign-data wrapper for remote PostgreSQL servers * - * Portions Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/postgres_fdw/postgres_fdw.h @@ -92,6 +92,9 @@ typedef struct PgFdwRelationInfo RelOptInfo *innerrel; JoinType jointype; List *joinclauses; + + /* Grouping information */ + List *grouped_tlist; } PgFdwRelationInfo; /* in postgres_fdw.c */ @@ -155,7 +158,7 @@ extern void deparseAnalyzeSql(StringInfo buf, Relation rel, List **retrieved_attrs); extern void deparseStringLiteral(StringInfo buf, const char *val); extern Expr *find_em_expr_for_rel(EquivalenceClass *ec, RelOptInfo *rel); -extern List *build_tlist_to_deparse(RelOptInfo *foreign_rel); +extern List *build_tlist_to_deparse(RelOptInfo *foreignrel); extern void deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel, List *tlist, List *remote_conds, List *pathkeys, diff --git a/contrib/postgres_fdw/shippable.c b/contrib/postgres_fdw/shippable.c index 92c952589e..2ac0873caa 100644 --- a/contrib/postgres_fdw/shippable.c +++ b/contrib/postgres_fdw/shippable.c @@ -13,7 +13,7 @@ * functions or functions using nonportable collations. Those considerations * need not be accounted for here. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/postgres_fdw/shippable.c diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql index 6f684a1b0c..919177649e 100644 --- a/contrib/postgres_fdw/sql/postgres_fdw.sql +++ b/contrib/postgres_fdw/sql/postgres_fdw.sql @@ -136,6 +136,14 @@ CREATE FOREIGN TABLE ft6 ( c3 text ) SERVER loopback2 OPTIONS (schema_name 'S 1', table_name 'T 4'); +-- A table with oids. CREATE FOREIGN TABLE doesn't support the +-- WITH OIDS option, but ALTER does. +CREATE FOREIGN TABLE ft_pg_type ( + typname name, + typlen smallint +) SERVER loopback OPTIONS (schema_name 'pg_catalog', table_name 'pg_type'); +ALTER TABLE ft_pg_type SET WITH OIDS; + -- =================================================================== -- tests for validator -- =================================================================== @@ -533,6 +541,309 @@ ALTER VIEW v4 OWNER TO regress_view_owner; DROP OWNED BY regress_view_owner; DROP ROLE regress_view_owner; + +-- =================================================================== +-- Aggregate and grouping queries +-- =================================================================== + +-- Simple aggregates +explain (verbose, costs off) +select count(c6), sum(c1), avg(c1), min(c2), max(c1), stddev(c2), sum(c1) * (random() <= 1)::int as sum2 from ft1 where c2 < 5 group by c2 order by 1, 2; +select count(c6), sum(c1), avg(c1), min(c2), max(c1), stddev(c2), sum(c1) * (random() <= 1)::int as sum2 from ft1 where c2 < 5 group by c2 order by 1, 2; + +-- Aggregate is not pushed down as aggregation contains random() +explain (verbose, costs off) +select sum(c1 * (random() <= 1)::int) as sum, avg(c1) from ft1; + +-- Aggregate over join query +explain (verbose, costs off) +select count(*), sum(t1.c1), avg(t2.c1) from ft1 t1 inner join ft1 t2 on (t1.c2 = t2.c2) where t1.c2 = 6; +select count(*), sum(t1.c1), avg(t2.c1) from ft1 t1 inner join ft1 t2 on (t1.c2 = t2.c2) where t1.c2 = 6; + +-- Not pushed down due to local conditions present in underneath input rel +explain (verbose, costs off) +select sum(t1.c1), count(t2.c1) from ft1 t1 inner join ft2 t2 on (t1.c1 = t2.c1) where ((t1.c1 * t2.c1)/(t1.c1 * t2.c1)) * random() <= 1; + +-- GROUP BY clause having expressions +explain (verbose, costs off) +select c2/2, sum(c2) * (c2/2) from ft1 group by c2/2 order by c2/2; +select c2/2, sum(c2) * (c2/2) from ft1 group by c2/2 order by c2/2; + +-- Aggregates in subquery are pushed down. +explain (verbose, costs off) +select count(x.a), sum(x.a) from (select c2 a, sum(c1) b from ft1 group by c2, sqrt(c1) order by 1, 2) x; +select count(x.a), sum(x.a) from (select c2 a, sum(c1) b from ft1 group by c2, sqrt(c1) order by 1, 2) x; + +-- Aggregate is still pushed down by taking unshippable expression out +explain (verbose, costs off) +select c2 * (random() <= 1)::int as sum1, sum(c1) * c2 as sum2 from ft1 group by c2 order by 1, 2; +select c2 * (random() <= 1)::int as sum1, sum(c1) * c2 as sum2 from ft1 group by c2 order by 1, 2; + +-- Aggregate with unshippable GROUP BY clause are not pushed +explain (verbose, costs off) +select c2 * (random() <= 1)::int as c2 from ft2 group by c2 * (random() <= 1)::int order by 1; + +-- GROUP BY clause in various forms, cardinal, alias and constant expression +explain (verbose, costs off) +select count(c2) w, c2 x, 5 y, 7.0 z from ft1 group by 2, y, 9.0::int order by 2; +select count(c2) w, c2 x, 5 y, 7.0 z from ft1 group by 2, y, 9.0::int order by 2; + +-- Testing HAVING clause shippability +explain (verbose, costs off) +select c2, sum(c1) from ft2 group by c2 having avg(c1) < 500 and sum(c1) < 49800 order by c2; +select c2, sum(c1) from ft2 group by c2 having avg(c1) < 500 and sum(c1) < 49800 order by c2; + +-- Unshippable HAVING clause will be evaluated locally, and other qual in HAVING clause is pushed down +explain (verbose, costs off) +select count(*) from (select c5, count(c1) from ft1 group by c5, sqrt(c2) having (avg(c1) / avg(c1)) * random() <= 1 and avg(c1) < 500) x; +select count(*) from (select c5, count(c1) from ft1 group by c5, sqrt(c2) having (avg(c1) / avg(c1)) * random() <= 1 and avg(c1) < 500) x; + +-- Aggregate in HAVING clause is not pushable, and thus aggregation is not pushed down +explain (verbose, costs off) +select sum(c1) from ft1 group by c2 having avg(c1 * (random() <= 1)::int) > 100 order by 1; + + +-- Testing ORDER BY, DISTINCT, FILTER, Ordered-sets and VARIADIC within aggregates + +-- ORDER BY within aggregate, same column used to order +explain (verbose, costs off) +select array_agg(c1 order by c1) from ft1 where c1 < 100 group by c2 order by 1; +select array_agg(c1 order by c1) from ft1 where c1 < 100 group by c2 order by 1; + +-- ORDER BY within aggregate, different column used to order also using DESC +explain (verbose, costs off) +select array_agg(c5 order by c1 desc) from ft2 where c2 = 6 and c1 < 50; +select array_agg(c5 order by c1 desc) from ft2 where c2 = 6 and c1 < 50; + +-- DISTINCT within aggregate +explain (verbose, costs off) +select array_agg(distinct (t1.c1)%5) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) where t1.c1 < 20 or (t1.c1 is null and t2.c1 < 5) group by (t2.c1)%3 order by 1; +select array_agg(distinct (t1.c1)%5) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) where t1.c1 < 20 or (t1.c1 is null and t2.c1 < 5) group by (t2.c1)%3 order by 1; + +-- DISTINCT combined with ORDER BY within aggregate +explain (verbose, costs off) +select array_agg(distinct (t1.c1)%5 order by (t1.c1)%5) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) where t1.c1 < 20 or (t1.c1 is null and t2.c1 < 5) group by (t2.c1)%3 order by 1; +select array_agg(distinct (t1.c1)%5 order by (t1.c1)%5) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) where t1.c1 < 20 or (t1.c1 is null and t2.c1 < 5) group by (t2.c1)%3 order by 1; + +explain (verbose, costs off) +select array_agg(distinct (t1.c1)%5 order by (t1.c1)%5 desc nulls last) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) where t1.c1 < 20 or (t1.c1 is null and t2.c1 < 5) group by (t2.c1)%3 order by 1; +select array_agg(distinct (t1.c1)%5 order by (t1.c1)%5 desc nulls last) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) where t1.c1 < 20 or (t1.c1 is null and t2.c1 < 5) group by (t2.c1)%3 order by 1; + +-- FILTER within aggregate +explain (verbose, costs off) +select sum(c1) filter (where c1 < 100 and c2 > 5) from ft1 group by c2 order by 1 nulls last; +select sum(c1) filter (where c1 < 100 and c2 > 5) from ft1 group by c2 order by 1 nulls last; + +-- DISTINCT, ORDER BY and FILTER within aggregate +explain (verbose, costs off) +select sum(c1%3), sum(distinct c1%3 order by c1%3) filter (where c1%3 < 2), c2 from ft1 where c2 = 6 group by c2; +select sum(c1%3), sum(distinct c1%3 order by c1%3) filter (where c1%3 < 2), c2 from ft1 where c2 = 6 group by c2; + +-- Outer query is aggregation query +explain (verbose, costs off) +select distinct (select count(*) filter (where t2.c2 = 6 and t2.c1 < 10) from ft1 t1 where t1.c1 = 6) from ft2 t2 order by 1; +select distinct (select count(*) filter (where t2.c2 = 6 and t2.c1 < 10) from ft1 t1 where t1.c1 = 6) from ft2 t2 order by 1; +-- Inner query is aggregation query +explain (verbose, costs off) +select distinct (select count(t1.c1) filter (where t2.c2 = 6 and t2.c1 < 10) from ft1 t1 where t1.c1 = 6) from ft2 t2 order by 1; +select distinct (select count(t1.c1) filter (where t2.c2 = 6 and t2.c1 < 10) from ft1 t1 where t1.c1 = 6) from ft2 t2 order by 1; + +-- Aggregate not pushed down as FILTER condition is not pushable +explain (verbose, costs off) +select sum(c1) filter (where (c1 / c1) * random() <= 1) from ft1 group by c2 order by 1; +explain (verbose, costs off) +select sum(c2) filter (where c2 in (select c2 from ft1 where c2 < 5)) from ft1; + +-- Ordered-sets within aggregate +explain (verbose, costs off) +select c2, rank('10'::varchar) within group (order by c6), percentile_cont(c2/10::numeric) within group (order by c1) from ft1 where c2 < 10 group by c2 having percentile_cont(c2/10::numeric) within group (order by c1) < 500 order by c2; +select c2, rank('10'::varchar) within group (order by c6), percentile_cont(c2/10::numeric) within group (order by c1) from ft1 where c2 < 10 group by c2 having percentile_cont(c2/10::numeric) within group (order by c1) < 500 order by c2; + +-- Using multiple arguments within aggregates +explain (verbose, costs off) +select c1, rank(c1, c2) within group (order by c1, c2) from ft1 group by c1, c2 having c1 = 6 order by 1; +select c1, rank(c1, c2) within group (order by c1, c2) from ft1 group by c1, c2 having c1 = 6 order by 1; + +-- User defined function for user defined aggregate, VARIADIC +create function least_accum(anyelement, variadic anyarray) +returns anyelement language sql as + 'select least($1, min($2[i])) from generate_subscripts($2,1) g(i)'; +create aggregate least_agg(variadic items anyarray) ( + stype = anyelement, sfunc = least_accum +); + +-- Disable hash aggregation for plan stability. +set enable_hashagg to false; + +-- Not pushed down due to user defined aggregate +explain (verbose, costs off) +select c2, least_agg(c1) from ft1 group by c2 order by c2; + +-- Add function and aggregate into extension +alter extension postgres_fdw add function least_accum(anyelement, variadic anyarray); +alter extension postgres_fdw add aggregate least_agg(variadic items anyarray); +alter server loopback options (set extensions 'postgres_fdw'); + +-- Now aggregate will be pushed. Aggregate will display VARIADIC argument. +explain (verbose, costs off) +select c2, least_agg(c1) from ft1 where c2 < 100 group by c2 order by c2; +select c2, least_agg(c1) from ft1 where c2 < 100 group by c2 order by c2; + +-- Remove function and aggregate from extension +alter extension postgres_fdw drop function least_accum(anyelement, variadic anyarray); +alter extension postgres_fdw drop aggregate least_agg(variadic items anyarray); +alter server loopback options (set extensions 'postgres_fdw'); + +-- Not pushed down as we have dropped objects from extension. +explain (verbose, costs off) +select c2, least_agg(c1) from ft1 group by c2 order by c2; + +-- Cleanup +reset enable_hashagg; +drop aggregate least_agg(variadic items anyarray); +drop function least_accum(anyelement, variadic anyarray); + + +-- Testing USING OPERATOR() in ORDER BY within aggregate. +-- For this, we need user defined operators along with operator family and +-- operator class. Create those and then add them in extension. Note that +-- user defined objects are considered unshippable unless they are part of +-- the extension. +create operator public.<^ ( + leftarg = int4, + rightarg = int4, + procedure = int4eq +); + +create operator public.=^ ( + leftarg = int4, + rightarg = int4, + procedure = int4lt +); + +create operator public.>^ ( + leftarg = int4, + rightarg = int4, + procedure = int4gt +); + +create operator family my_op_family using btree; + +create function my_op_cmp(a int, b int) returns int as + $$begin return btint4cmp(a, b); end $$ language plpgsql; + +create operator class my_op_class for type int using btree family my_op_family as + operator 1 public.<^, + operator 3 public.=^, + operator 5 public.>^, + function 1 my_op_cmp(int, int); + +-- This will not be pushed as user defined sort operator is not part of the +-- extension yet. +explain (verbose, costs off) +select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6 and c1 < 100 group by c2; + +-- Add into extension +alter extension postgres_fdw add operator class my_op_class using btree; +alter extension postgres_fdw add function my_op_cmp(a int, b int); +alter extension postgres_fdw add operator family my_op_family using btree; +alter extension postgres_fdw add operator public.<^(int, int); +alter extension postgres_fdw add operator public.=^(int, int); +alter extension postgres_fdw add operator public.>^(int, int); +alter server loopback options (set extensions 'postgres_fdw'); + +-- Now this will be pushed as sort operator is part of the extension. +explain (verbose, costs off) +select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6 and c1 < 100 group by c2; +select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6 and c1 < 100 group by c2; + +-- Remove from extension +alter extension postgres_fdw drop operator class my_op_class using btree; +alter extension postgres_fdw drop function my_op_cmp(a int, b int); +alter extension postgres_fdw drop operator family my_op_family using btree; +alter extension postgres_fdw drop operator public.<^(int, int); +alter extension postgres_fdw drop operator public.=^(int, int); +alter extension postgres_fdw drop operator public.>^(int, int); +alter server loopback options (set extensions 'postgres_fdw'); + +-- This will not be pushed as sort operator is now removed from the extension. +explain (verbose, costs off) +select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6 and c1 < 100 group by c2; + +-- Cleanup +drop operator class my_op_class using btree; +drop function my_op_cmp(a int, b int); +drop operator family my_op_family using btree; +drop operator public.>^(int, int); +drop operator public.=^(int, int); +drop operator public.<^(int, int); + +-- Input relation to aggregate push down hook is not safe to pushdown and thus +-- the aggregate cannot be pushed down to foreign server. +explain (verbose, costs off) +select count(t1.c3) from ft1 t1, ft1 t2 where t1.c1 = postgres_fdw_abs(t1.c2); + +-- Subquery in FROM clause having aggregate +explain (verbose, costs off) +select count(*), x.b from ft1, (select c2 a, sum(c1) b from ft1 group by c2) x where ft1.c2 = x.a group by x.b order by 1, 2; +select count(*), x.b from ft1, (select c2 a, sum(c1) b from ft1 group by c2) x where ft1.c2 = x.a group by x.b order by 1, 2; + +-- FULL join with IS NULL check in HAVING +explain (verbose, costs off) +select avg(t1.c1), sum(t2.c1) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) group by t2.c1 having (avg(t1.c1) is null and sum(t2.c1) < 10) or sum(t2.c1) is null order by 1 nulls last, 2; +select avg(t1.c1), sum(t2.c1) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) group by t2.c1 having (avg(t1.c1) is null and sum(t2.c1) < 10) or sum(t2.c1) is null order by 1 nulls last, 2; + +-- ORDER BY expression is part of the target list but not pushed down to +-- foreign server. +explain (verbose, costs off) +select sum(c2) * (random() <= 1)::int as sum from ft1 order by 1; +select sum(c2) * (random() <= 1)::int as sum from ft1 order by 1; + +-- LATERAL join, with parameterization +set enable_hashagg to false; +explain (verbose, costs off) +select c2, sum from "S 1"."T 1" t1, lateral (select sum(t2.c1 + t1."C 1") sum from ft2 t2 group by t2.c1) qry where t1.c2 * 2 = qry.sum and t1.c2 < 10 order by 1; +select c2, sum from "S 1"."T 1" t1, lateral (select sum(t2.c1 + t1."C 1") sum from ft2 t2 group by t2.c1) qry where t1.c2 * 2 = qry.sum and t1.c2 < 10 order by 1; +reset enable_hashagg; + +-- Check with placeHolderVars +explain (verbose, costs off) +select sum(q.a), count(q.b) from ft4 left join (select 13, avg(ft1.c1), sum(ft2.c1) from ft1 right join ft2 on (ft1.c1 = ft2.c1)) q(a, b, c) on (ft4.c1 <= q.b); +select sum(q.a), count(q.b) from ft4 left join (select 13, avg(ft1.c1), sum(ft2.c1) from ft1 right join ft2 on (ft1.c1 = ft2.c1)) q(a, b, c) on (ft4.c1 <= q.b); + + +-- Not supported cases +-- Grouping sets +explain (verbose, costs off) +select c2, sum(c1) from ft1 where c2 < 3 group by rollup(c2) order by 1 nulls last; +select c2, sum(c1) from ft1 where c2 < 3 group by rollup(c2) order by 1 nulls last; +explain (verbose, costs off) +select c2, sum(c1) from ft1 where c2 < 3 group by cube(c2) order by 1 nulls last; +select c2, sum(c1) from ft1 where c2 < 3 group by cube(c2) order by 1 nulls last; +explain (verbose, costs off) +select c2, c6, sum(c1) from ft1 where c2 < 3 group by grouping sets(c2, c6) order by 1 nulls last, 2 nulls last; +select c2, c6, sum(c1) from ft1 where c2 < 3 group by grouping sets(c2, c6) order by 1 nulls last, 2 nulls last; +explain (verbose, costs off) +select c2, sum(c1), grouping(c2) from ft1 where c2 < 3 group by c2 order by 1 nulls last; +select c2, sum(c1), grouping(c2) from ft1 where c2 < 3 group by c2 order by 1 nulls last; + +-- DISTINCT itself is not pushed down, whereas underneath aggregate is pushed +explain (verbose, costs off) +select distinct sum(c1)/1000 s from ft2 where c2 < 6 group by c2 order by 1; +select distinct sum(c1)/1000 s from ft2 where c2 < 6 group by c2 order by 1; + +-- WindowAgg +explain (verbose, costs off) +select c2, sum(c2), count(c2) over (partition by c2%2) from ft2 where c2 < 10 group by c2 order by 1; +select c2, sum(c2), count(c2) over (partition by c2%2) from ft2 where c2 < 10 group by c2 order by 1; +explain (verbose, costs off) +select c2, array_agg(c2) over (partition by c2%2 order by c2 desc) from ft1 where c2 < 10 group by c2 order by 1; +select c2, array_agg(c2) over (partition by c2%2 order by c2 desc) from ft1 where c2 < 10 group by c2 order by 1; +explain (verbose, costs off) +select c2, array_agg(c2) over (partition by c2%2 order by c2 range between current row and unbounded following) from ft1 where c2 < 10 group by c2 order by 1; +select c2, array_agg(c2) over (partition by c2%2 order by c2 range between current row and unbounded following) from ft1 where c2 < 10 group by c2 order by 1; + + -- =================================================================== -- parameterized queries -- =================================================================== @@ -570,14 +881,37 @@ EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st5('foo', 1); EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st5('foo', 1); EXECUTE st5('foo', 1); +-- altering FDW options requires replanning +PREPARE st6 AS SELECT * FROM ft1 t1 WHERE t1.c1 = t1.c2; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st6; +PREPARE st7 AS INSERT INTO ft1 (c1,c2,c3) VALUES (1001,101,'foo'); +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st7; +ALTER TABLE "S 1"."T 1" RENAME TO "T 0"; +ALTER FOREIGN TABLE ft1 OPTIONS (SET table_name 'T 0'); +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st6; +EXECUTE st6; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st7; +ALTER TABLE "S 1"."T 0" RENAME TO "T 1"; +ALTER FOREIGN TABLE ft1 OPTIONS (SET table_name 'T 1'); + +PREPARE st8 AS SELECT count(c3) FROM ft1 t1 WHERE t1.c1 === t1.c2; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st8; +ALTER SERVER loopback OPTIONS (DROP extensions); +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st8; +EXECUTE st8; +ALTER SERVER loopback OPTIONS (ADD extensions 'postgres_fdw'); + -- cleanup DEALLOCATE st1; DEALLOCATE st2; DEALLOCATE st3; DEALLOCATE st4; DEALLOCATE st5; +DEALLOCATE st6; +DEALLOCATE st7; +DEALLOCATE st8; --- System columns, except ctid, should not be sent to remote +-- System columns, except ctid and oid, should not be sent to remote EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE t1.tableoid = 'pg_class'::regclass LIMIT 1; SELECT * FROM ft1 t1 WHERE t1.tableoid = 'ft1'::regclass LIMIT 1; @@ -590,6 +924,9 @@ SELECT * FROM ft1 t1 WHERE t1.ctid = '(0,2)'; EXPLAIN (VERBOSE, COSTS OFF) SELECT ctid, * FROM ft1 t1 LIMIT 1; SELECT ctid, * FROM ft1 t1 LIMIT 1; +EXPLAIN (VERBOSE, COSTS OFF) +SELECT oid, * FROM ft_pg_type WHERE typname = 'int4'; +SELECT oid, * FROM ft_pg_type WHERE typname = 'int4'; -- =================================================================== -- used in pl/pgsql function @@ -613,6 +950,7 @@ ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE int; SELECT * FROM ft1 WHERE c1 = 1; -- ERROR SELECT ft1.c1, ft2.c2, ft1.c8 FROM ft1, ft2 WHERE ft1.c1 = ft2.c1 AND ft1.c1 = 1; -- ERROR SELECT ft1.c1, ft2.c2, ft1 FROM ft1, ft2 WHERE ft1.c1 = ft2.c1 AND ft1.c1 = 1; -- ERROR +SELECT sum(c2), array_agg(c8) FROM ft1 GROUP BY c8; -- ERROR ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE user_enum; -- =================================================================== diff --git a/contrib/seg/expected/seg.out b/contrib/seg/expected/seg.out index 1f82a4abb8..18010c4d5c 100644 --- a/contrib/seg/expected/seg.out +++ b/contrib/seg/expected/seg.out @@ -2,6 +2,14 @@ -- Test seg datatype -- CREATE EXTENSION seg; +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + amname | opcname +--------+--------- +(0 rows) + -- -- testing the input and output functions -- diff --git a/contrib/seg/expected/seg_1.out b/contrib/seg/expected/seg_1.out index 563c744b2d..566ce394ed 100644 --- a/contrib/seg/expected/seg_1.out +++ b/contrib/seg/expected/seg_1.out @@ -2,6 +2,14 @@ -- Test seg datatype -- CREATE EXTENSION seg; +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + amname | opcname +--------+--------- +(0 rows) + -- -- testing the input and output functions -- diff --git a/contrib/seg/seg-validate.pl b/contrib/seg/seg-validate.pl index cb3fb9a099..b8957ed984 100755 --- a/contrib/seg/seg-validate.pl +++ b/contrib/seg/seg-validate.pl @@ -1,20 +1,23 @@ #!/usr/bin/perl -$integer = '[+-]?[0-9]+'; -$real = '[+-]?[0-9]+\.[0-9]+'; - -$RANGE = '(\.\.)(\.)?'; -$PLUMIN = q(\'\+\-\'); -$FLOAT = "(($integer)|($real))([eE]($integer))?"; -$EXTENSION = '<|>|~'; - -$boundary = "($EXTENSION)?$FLOAT"; -$deviation = $FLOAT; - -$rule_1 = $boundary . $PLUMIN . $deviation; -$rule_2 = $boundary . $RANGE . $boundary; -$rule_3 = $boundary . $RANGE; -$rule_4 = $RANGE . $boundary; -$rule_5 = $boundary; + +use strict; + +my $integer = '[+-]?[0-9]+'; +my $real = '[+-]?[0-9]+\.[0-9]+'; + +my $RANGE = '(\.\.)(\.)?'; +my $PLUMIN = q(\'\+\-\'); +my $FLOAT = "(($integer)|($real))([eE]($integer))?"; +my $EXTENSION = '<|>|~'; + +my $boundary = "($EXTENSION)?$FLOAT"; +my $deviation = $FLOAT; + +my $rule_1 = $boundary . $PLUMIN . $deviation; +my $rule_2 = $boundary . $RANGE . $boundary; +my $rule_3 = $boundary . $RANGE; +my $rule_4 = $RANGE . $boundary; +my $rule_5 = $boundary; print "$rule_5\n"; diff --git a/contrib/seg/sort-segments.pl b/contrib/seg/sort-segments.pl index a465468d5b..04eafd92f2 100755 --- a/contrib/seg/sort-segments.pl +++ b/contrib/seg/sort-segments.pl @@ -2,6 +2,10 @@ # this script will sort any table with the segment data type in its last column +use strict; + +my @rows; + while (<>) { chomp; @@ -10,11 +14,11 @@ foreach ( sort { - @ar = split("\t", $a); - $valA = pop @ar; + my @ar = split("\t", $a); + my $valA = pop @ar; $valA =~ s/[~<> ]+//g; @ar = split("\t", $b); - $valB = pop @ar; + my $valB = pop @ar; $valB =~ s/[~<> ]+//g; $valA <=> $valB } @rows) diff --git a/contrib/seg/sql/seg.sql b/contrib/seg/sql/seg.sql index 7b7f138dbf..aa91931474 100644 --- a/contrib/seg/sql/seg.sql +++ b/contrib/seg/sql/seg.sql @@ -4,6 +4,11 @@ CREATE EXTENSION seg; +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + -- -- testing the input and output functions -- diff --git a/contrib/sepgsql/database.c b/contrib/sepgsql/database.c index 8fad1fc80c..69dd290a77 100644 --- a/contrib/sepgsql/database.c +++ b/contrib/sepgsql/database.c @@ -4,7 +4,7 @@ * * Routines corresponding to database objects * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * * ------------------------------------------------------------------------- */ diff --git a/contrib/sepgsql/dml.c b/contrib/sepgsql/dml.c index d1e9f53cda..bc170895f0 100644 --- a/contrib/sepgsql/dml.c +++ b/contrib/sepgsql/dml.c @@ -4,7 +4,7 @@ * * Routines to handle DML permission checks * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * * ------------------------------------------------------------------------- */ diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c index 38b1a49775..93cc8debaa 100644 --- a/contrib/sepgsql/hooks.c +++ b/contrib/sepgsql/hooks.c @@ -4,7 +4,7 @@ * * Entrypoints of the hooks in PostgreSQL, and dispatches the callbacks. * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * * ------------------------------------------------------------------------- */ @@ -297,13 +297,14 @@ sepgsql_exec_check_perms(List *rangeTabls, bool abort) * break whole of the things if nefarious user would use. */ static void -sepgsql_utility_command(Node *parsetree, +sepgsql_utility_command(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag) { + Node *parsetree = pstmt->utilityStmt; sepgsql_context_info_t saved_context_info = sepgsql_context_info; ListCell *cell; @@ -362,11 +363,11 @@ sepgsql_utility_command(Node *parsetree, } if (next_ProcessUtility_hook) - (*next_ProcessUtility_hook) (parsetree, queryString, + (*next_ProcessUtility_hook) (pstmt, queryString, context, params, dest, completionTag); else - standard_ProcessUtility(parsetree, queryString, + standard_ProcessUtility(pstmt, queryString, context, params, dest, completionTag); } diff --git a/contrib/sepgsql/label.c b/contrib/sepgsql/label.c index e12a0e8cb6..82deb93093 100644 --- a/contrib/sepgsql/label.c +++ b/contrib/sepgsql/label.c @@ -4,7 +4,7 @@ * * Routines to support SELinux labels (security context) * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * * ------------------------------------------------------------------------- */ diff --git a/contrib/sepgsql/launcher b/contrib/sepgsql/launcher index eb827a0e0a..0fc96ea0d4 100755 --- a/contrib/sepgsql/launcher +++ b/contrib/sepgsql/launcher @@ -2,7 +2,7 @@ # # A wrapper script to launch psql command in regression test # -# Copyright (c) 2010-2016, PostgreSQL Global Development Group +# Copyright (c) 2010-2017, PostgreSQL Global Development Group # # ------------------------------------------------------------------------- diff --git a/contrib/sepgsql/proc.c b/contrib/sepgsql/proc.c index 9cc21f05b5..4ccf4a5e60 100644 --- a/contrib/sepgsql/proc.c +++ b/contrib/sepgsql/proc.c @@ -4,7 +4,7 @@ * * Routines corresponding to procedure objects * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * * ------------------------------------------------------------------------- */ diff --git a/contrib/sepgsql/relation.c b/contrib/sepgsql/relation.c index 1f1ab04d39..ab98a9b4f2 100644 --- a/contrib/sepgsql/relation.c +++ b/contrib/sepgsql/relation.c @@ -4,7 +4,7 @@ * * Routines corresponding to relation/attribute objects * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * * ------------------------------------------------------------------------- */ diff --git a/contrib/sepgsql/schema.c b/contrib/sepgsql/schema.c index 5285fc5452..940384bf40 100644 --- a/contrib/sepgsql/schema.c +++ b/contrib/sepgsql/schema.c @@ -4,7 +4,7 @@ * * Routines corresponding to schema objects * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * * ------------------------------------------------------------------------- */ diff --git a/contrib/sepgsql/selinux.c b/contrib/sepgsql/selinux.c index b0b9fadede..3e2cfab819 100644 --- a/contrib/sepgsql/selinux.c +++ b/contrib/sepgsql/selinux.c @@ -5,7 +5,7 @@ * Interactions between userspace and selinux in kernelspace, * using libselinux api. * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * * ------------------------------------------------------------------------- */ diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h index c080716f8f..9d245c2780 100644 --- a/contrib/sepgsql/sepgsql.h +++ b/contrib/sepgsql/sepgsql.h @@ -4,7 +4,7 @@ * * Definitions corresponding to SE-PostgreSQL * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * * ------------------------------------------------------------------------- */ @@ -276,12 +276,6 @@ extern char *sepgsql_get_label(Oid relOid, Oid objOid, int32 subId); extern void sepgsql_object_relabel(const ObjectAddress *object, const char *seclabel); -extern Datum sepgsql_getcon(PG_FUNCTION_ARGS); -extern Datum sepgsql_setcon(PG_FUNCTION_ARGS); -extern Datum sepgsql_mcstrans_in(PG_FUNCTION_ARGS); -extern Datum sepgsql_mcstrans_out(PG_FUNCTION_ARGS); -extern Datum sepgsql_restorecon(PG_FUNCTION_ARGS); - /* * dml.c */ diff --git a/contrib/sepgsql/uavc.c b/contrib/sepgsql/uavc.c index 10fa9a0b0b..6fd58c7e42 100644 --- a/contrib/sepgsql/uavc.c +++ b/contrib/sepgsql/uavc.c @@ -6,7 +6,7 @@ * access control decisions recently used, and reduce number of kernel * invocations to avoid unnecessary performance hit. * - * Copyright (c) 2011-2016, PostgreSQL Global Development Group + * Copyright (c) 2011-2017, PostgreSQL Global Development Group * * ------------------------------------------------------------------------- */ @@ -498,13 +498,11 @@ sepgsql_avc_init(void) int rc; /* - * All the avc stuff shall be allocated on avc_mem_cxt + * All the avc stuff shall be allocated in avc_mem_cxt */ avc_mem_cxt = AllocSetContextCreate(TopMemoryContext, "userspace access vector cache", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); memset(avc_slots, 0, sizeof(avc_slots)); avc_num_caches = 0; avc_lru_hint = 0; diff --git a/contrib/spi/autoinc.c b/contrib/spi/autoinc.c index 41eae4fdc4..54f85a3709 100644 --- a/contrib/spi/autoinc.c +++ b/contrib/spi/autoinc.c @@ -3,6 +3,7 @@ */ #include "postgres.h" +#include "access/htup_details.h" #include "catalog/pg_type.h" #include "commands/sequence.h" #include "commands/trigger.h" @@ -23,6 +24,7 @@ autoinc(PG_FUNCTION_ARGS) int *chattrs; /* attnums of attributes to change */ int chnattrs = 0; /* # of above */ Datum *newvals; /* vals of above */ + bool *newnulls; /* null flags for above */ char **args; /* arguments */ char *relname; /* triggered relation name */ Relation rel; /* triggered relation */ @@ -64,6 +66,7 @@ autoinc(PG_FUNCTION_ARGS) chattrs = (int *) palloc(nargs / 2 * sizeof(int)); newvals = (Datum *) palloc(nargs / 2 * sizeof(Datum)); + newnulls = (bool *) palloc(nargs / 2 * sizeof(bool)); for (i = 0; i < nargs;) { @@ -71,7 +74,7 @@ autoinc(PG_FUNCTION_ARGS) int32 val; Datum seqname; - if (attnum < 0) + if (attnum <= 0) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("\"%s\" has no attribute \"%s\"", @@ -102,6 +105,7 @@ autoinc(PG_FUNCTION_ARGS) newvals[chnattrs] = DirectFunctionCall1(nextval, seqname); newvals[chnattrs] = Int32GetDatum((int32) DatumGetInt64(newvals[chnattrs])); } + newnulls[chnattrs] = false; pfree(DatumGetTextP(seqname)); chnattrs++; i++; @@ -109,16 +113,15 @@ autoinc(PG_FUNCTION_ARGS) if (chnattrs > 0) { - rettuple = SPI_modifytuple(rel, rettuple, chnattrs, chattrs, newvals, NULL); - if (rettuple == NULL) - /* internal error */ - elog(ERROR, "autoinc (%s): %d returned by SPI_modifytuple", - relname, SPI_result); + rettuple = heap_modify_tuple_by_cols(rettuple, tupdesc, + chnattrs, chattrs, + newvals, newnulls); } pfree(relname); pfree(chattrs); pfree(newvals); + pfree(newnulls); return PointerGetDatum(rettuple); } diff --git a/contrib/spi/insert_username.c b/contrib/spi/insert_username.c index 3812525c4c..a2e1747ff7 100644 --- a/contrib/spi/insert_username.c +++ b/contrib/spi/insert_username.c @@ -1,6 +1,4 @@ /* - * insert_username.c - * $Modified: Thu Oct 16 08:13:42 1997 by brook $ * contrib/spi/insert_username.c * * insert user name in response to a trigger @@ -8,6 +6,7 @@ */ #include "postgres.h" +#include "access/htup_details.h" #include "catalog/pg_type.h" #include "commands/trigger.h" #include "executor/spi.h" @@ -26,6 +25,7 @@ insert_username(PG_FUNCTION_ARGS) Trigger *trigger; /* to get trigger name */ int nargs; /* # of arguments */ Datum newval; /* new value of column */ + bool newnull; /* null flag */ char **args; /* arguments */ char *relname; /* triggered relation name */ Relation rel; /* triggered relation */ @@ -67,7 +67,7 @@ insert_username(PG_FUNCTION_ARGS) attnum = SPI_fnumber(tupdesc, args[0]); - if (attnum < 0) + if (attnum <= 0) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("\"%s\" has no attribute \"%s\"", relname, args[0]))); @@ -80,13 +80,11 @@ insert_username(PG_FUNCTION_ARGS) /* create fields containing name */ newval = CStringGetTextDatum(GetUserNameFromId(GetUserId(), false)); + newnull = false; /* construct new tuple */ - rettuple = SPI_modifytuple(rel, rettuple, 1, &attnum, &newval, NULL); - if (rettuple == NULL) - /* internal error */ - elog(ERROR, "insert_username (\"%s\"): %d returned by SPI_modifytuple", - relname, SPI_result); + rettuple = heap_modify_tuple_by_cols(rettuple, tupdesc, + 1, &attnum, &newval, &newnull); pfree(relname); diff --git a/contrib/spi/moddatetime.c b/contrib/spi/moddatetime.c index c6d33b7355..70476f77c2 100644 --- a/contrib/spi/moddatetime.c +++ b/contrib/spi/moddatetime.c @@ -15,11 +15,12 @@ OH, me, I'm Terry Mackintosh */ #include "postgres.h" +#include "access/htup_details.h" #include "catalog/pg_type.h" #include "executor/spi.h" #include "commands/trigger.h" +#include "utils/builtins.h" #include "utils/rel.h" -#include "utils/timestamp.h" PG_MODULE_MAGIC; @@ -34,6 +35,7 @@ moddatetime(PG_FUNCTION_ARGS) int attnum; /* positional number of field to change */ Oid atttypid; /* type OID of field to change */ Datum newdt; /* The current datetime. */ + bool newdtnull; /* null flag for it */ char **args; /* arguments */ char *relname; /* triggered relation name */ Relation rel; /* triggered relation */ @@ -84,9 +86,9 @@ moddatetime(PG_FUNCTION_ARGS) /* * This is where we check to see if the field we are supposed to update - * even exists. The above function must return -1 if name not found? + * even exists. */ - if (attnum < 0) + if (attnum <= 0) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("\"%s\" has no attribute \"%s\"", @@ -115,22 +117,13 @@ moddatetime(PG_FUNCTION_ARGS) args[0], relname))); newdt = (Datum) 0; /* keep compiler quiet */ } + newdtnull = false; -/* 1 is the number of items in the arrays attnum and newdt. - attnum is the positional number of the field to be updated. - newdt is the new datetime stamp. - NOTE that attnum and newdt are not arrays, but then a 1 element array - is not an array any more then they are. Thus, they can be considered a - one element array. -*/ - rettuple = SPI_modifytuple(rel, rettuple, 1, &attnum, &newdt, NULL); - - if (rettuple == NULL) - /* internal error */ - elog(ERROR, "moddatetime (%s): %d returned by SPI_modifytuple", - relname, SPI_result); + /* Replace the attnum'th column with newdt */ + rettuple = heap_modify_tuple_by_cols(rettuple, tupdesc, + 1, &attnum, &newdt, &newdtnull); -/* Clean up */ + /* Clean up */ pfree(relname); return PointerGetDatum(rettuple); diff --git a/contrib/spi/refint.c b/contrib/spi/refint.c index 01dd717522..78cfedf219 100644 --- a/contrib/spi/refint.c +++ b/contrib/spi/refint.c @@ -135,7 +135,7 @@ check_primary_key(PG_FUNCTION_ARGS) int fnumber = SPI_fnumber(tupdesc, args[i]); /* Bad guys may give us un-existing column in CREATE TRIGGER */ - if (fnumber < 0) + if (fnumber <= 0) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("there is no attribute \"%s\" in relation \"%s\"", @@ -362,7 +362,7 @@ check_foreign_key(PG_FUNCTION_ARGS) int fnumber = SPI_fnumber(tupdesc, args[i]); /* Bad guys may give us un-existing column in CREATE TRIGGER */ - if (fnumber < 0) + if (fnumber <= 0) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("there is no attribute \"%s\" in relation \"%s\"", @@ -469,6 +469,7 @@ check_foreign_key(PG_FUNCTION_ARGS) char *type; fn = SPI_fnumber(tupdesc, args_temp[k - 1]); + Assert(fn > 0); /* already checked above */ nv = SPI_getvalue(newtuple, tupdesc, fn); type = SPI_gettype(tupdesc, fn); diff --git a/contrib/spi/timetravel.c b/contrib/spi/timetravel.c index 5a345841c6..2733aa231e 100644 --- a/contrib/spi/timetravel.c +++ b/contrib/spi/timetravel.c @@ -11,6 +11,7 @@ #include +#include "access/htup_details.h" #include "catalog/pg_type.h" #include "commands/trigger.h" #include "executor/spi.h" @@ -157,7 +158,7 @@ timetravel(PG_FUNCTION_ARGS) for (i = 0; i < MinAttrNum; i++) { attnum[i] = SPI_fnumber(tupdesc, args[i]); - if (attnum[i] < 0) + if (attnum[i] <= 0) elog(ERROR, "timetravel (%s): there is no attribute %s", relname, args[i]); if (SPI_gettypeid(tupdesc, attnum[i]) != ABSTIMEOID) elog(ERROR, "timetravel (%s): attribute %s must be of abstime type", @@ -166,7 +167,7 @@ timetravel(PG_FUNCTION_ARGS) for (; i < argc; i++) { attnum[i] = SPI_fnumber(tupdesc, args[i]); - if (attnum[i] < 0) + if (attnum[i] <= 0) elog(ERROR, "timetravel (%s): there is no attribute %s", relname, args[i]); if (SPI_gettypeid(tupdesc, attnum[i]) != TEXTOID) elog(ERROR, "timetravel (%s): attribute %s must be of text type", @@ -183,13 +184,13 @@ timetravel(PG_FUNCTION_ARGS) int chnattrs = 0; int chattrs[MaxAttrNum]; Datum newvals[MaxAttrNum]; - char newnulls[MaxAttrNum]; + bool newnulls[MaxAttrNum]; oldtimeon = SPI_getbinval(trigtuple, tupdesc, attnum[a_time_on], &isnull); if (isnull) { newvals[chnattrs] = GetCurrentAbsoluteTime(); - newnulls[chnattrs] = ' '; + newnulls[chnattrs] = false; chattrs[chnattrs] = attnum[a_time_on]; chnattrs++; } @@ -201,7 +202,7 @@ timetravel(PG_FUNCTION_ARGS) (chnattrs > 0 && DatumGetInt32(newvals[a_time_on]) >= NOEND_ABSTIME)) elog(ERROR, "timetravel (%s): %s is infinity", relname, args[a_time_on]); newvals[chnattrs] = NOEND_ABSTIME; - newnulls[chnattrs] = ' '; + newnulls[chnattrs] = false; chattrs[chnattrs] = attnum[a_time_off]; chnattrs++; } @@ -220,21 +221,23 @@ timetravel(PG_FUNCTION_ARGS) { /* clear update_user value */ newvals[chnattrs] = nulltext; - newnulls[chnattrs] = 'n'; + newnulls[chnattrs] = true; chattrs[chnattrs] = attnum[a_upd_user]; chnattrs++; /* clear delete_user value */ newvals[chnattrs] = nulltext; - newnulls[chnattrs] = 'n'; + newnulls[chnattrs] = true; chattrs[chnattrs] = attnum[a_del_user]; chnattrs++; /* set insert_user value */ newvals[chnattrs] = newuser; - newnulls[chnattrs] = ' '; + newnulls[chnattrs] = false; chattrs[chnattrs] = attnum[a_ins_user]; chnattrs++; } - rettuple = SPI_modifytuple(rel, trigtuple, chnattrs, chattrs, newvals, newnulls); + rettuple = heap_modify_tuple_by_cols(trigtuple, tupdesc, + chnattrs, chattrs, + newvals, newnulls); return PointerGetDatum(rettuple); /* end of INSERT */ } @@ -395,13 +398,11 @@ timetravel(PG_FUNCTION_ARGS) chnattrs++; } - rettuple = SPI_modifytuple(rel, newtuple, chnattrs, chattrs, newvals, newnulls); - /* - * SPI_copytuple allocates tmptuple in upper executor context - have - * to free allocation using SPI_pfree + * Use SPI_modifytuple() here because we are inside SPI environment + * but rettuple must be allocated in caller's context. */ - /* SPI_pfree(tmptuple); */ + rettuple = SPI_modifytuple(rel, newtuple, chnattrs, chattrs, newvals, newnulls); } else /* DELETE case */ diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c index 82a4c1bd70..a4b0f9b6a1 100644 --- a/contrib/sslinfo/sslinfo.c +++ b/contrib/sslinfo/sslinfo.c @@ -402,8 +402,6 @@ ssl_extension_info(PG_FUNCTION_ARGS) MemoryContext oldcontext; SSLExtensionInfoContext *fctx; - STACK_OF(X509_EXTENSION) *ext_stack = NULL; - if (SRF_IS_FIRSTCALL()) { @@ -427,16 +425,10 @@ ssl_extension_info(PG_FUNCTION_ARGS) errmsg("function returning record called in context that cannot accept type record"))); fctx->tupdesc = BlessTupleDesc(tupdesc); - /* Get all extensions of certificate */ - if (cert && cert->cert_info) - ext_stack = cert->cert_info->extensions; - /* Set max_calls as a count of extensions in certificate */ max_calls = cert != NULL ? X509_get_ext_count(cert) : 0; - if (cert != NULL && - ext_stack != NULL && - max_calls > 0) + if (max_calls > 0) { /* got results, keep track of them */ funcctx->max_calls = max_calls; @@ -462,8 +454,6 @@ ssl_extension_info(PG_FUNCTION_ARGS) max_calls = funcctx->max_calls; fctx = funcctx->user_fctx; - ext_stack = cert->cert_info->extensions; - /* do while there are more left to send */ if (call_cntr < max_calls) { @@ -486,7 +476,7 @@ ssl_extension_info(PG_FUNCTION_ARGS) errmsg("could not create OpenSSL BIO structure"))); /* Get the extension from the certificate */ - ext = sk_X509_EXTENSION_value(ext_stack, call_cntr); + ext = X509_get_ext(cert, call_cntr); obj = X509_EXTENSION_get_object(ext); /* Get the extension name */ diff --git a/contrib/start-scripts/freebsd b/contrib/start-scripts/freebsd index 758574b427..c6ac8cd47a 100644 --- a/contrib/start-scripts/freebsd +++ b/contrib/start-scripts/freebsd @@ -28,8 +28,7 @@ PGLOG="$PGDATA/serverlog" PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin # What to use to start up the postmaster. (If you want the script to wait -# until the server has started, you could use "pg_ctl start -w" here. -# But without -w, pg_ctl adds no value.) +# until the server has started, you could use "pg_ctl start" here.) DAEMON="$prefix/bin/postmaster" # What to use to shut down the postmaster @@ -48,10 +47,10 @@ case $1 in echo -n ' postgresql' ;; stop) - su -l $PGUSER -c "$PGCTL stop -D '$PGDATA' -s -m fast" + su -l $PGUSER -c "$PGCTL stop -D '$PGDATA' -s" ;; restart) - su -l $PGUSER -c "$PGCTL stop -D '$PGDATA' -s -m fast -w" + su -l $PGUSER -c "$PGCTL stop -D '$PGDATA' -s" su -l $PGUSER -c "$DAEMON -D '$PGDATA' &" >>$PGLOG 2>&1 ;; status) diff --git a/contrib/start-scripts/linux b/contrib/start-scripts/linux index 763a8064ab..44a775b030 100644 --- a/contrib/start-scripts/linux +++ b/contrib/start-scripts/linux @@ -60,8 +60,7 @@ PGLOG="$PGDATA/serverlog" PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin # What to use to start up the postmaster. (If you want the script to wait -# until the server has started, you could use "pg_ctl start -w" here. -# But without -w, pg_ctl adds no value.) +# until the server has started, you could use "pg_ctl start" here.) DAEMON="$prefix/bin/postmaster" # What to use to shut down the postmaster @@ -97,21 +96,21 @@ case $1 in ;; stop) echo -n "Stopping PostgreSQL: " - su - $PGUSER -c "$PGCTL stop -D '$PGDATA' -s -m fast" + su - $PGUSER -c "$PGCTL stop -D '$PGDATA' -s" echo "ok" ;; restart) echo -n "Restarting PostgreSQL: " - su - $PGUSER -c "$PGCTL stop -D '$PGDATA' -s -m fast -w" + su - $PGUSER -c "$PGCTL stop -D '$PGDATA' -s" test -e "$PG_OOM_ADJUST_FILE" && echo "$PG_MASTER_OOM_SCORE_ADJ" > "$PG_OOM_ADJUST_FILE" su - $PGUSER -c "$DAEMON_ENV $DAEMON -D '$PGDATA' &" >>$PGLOG 2>&1 echo "ok" ;; reload) - echo -n "Reload PostgreSQL: " - su - $PGUSER -c "$PGCTL reload -D '$PGDATA' -s" - echo "ok" - ;; + echo -n "Reload PostgreSQL: " + su - $PGUSER -c "$PGCTL reload -D '$PGDATA' -s" + echo "ok" + ;; status) su - $PGUSER -c "$PGCTL status -D '$PGDATA'" ;; diff --git a/contrib/start-scripts/osx/PostgreSQL b/contrib/start-scripts/osx/PostgreSQL index 24872b0944..9735c8c57f 100755 --- a/contrib/start-scripts/osx/PostgreSQL +++ b/contrib/start-scripts/osx/PostgreSQL @@ -65,8 +65,7 @@ ROTATESEC="604800" PATH="$prefix/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin" # What to use to start up the postmaster. (If you want the script to wait -# until the server has started, you could use "pg_ctl start -w" here. -# But without -w, pg_ctl adds no value.) +# until the server has started, you could use "pg_ctl start" here.) DAEMON="$prefix/bin/postmaster" # What to use to shut down the postmaster @@ -90,15 +89,15 @@ StartService () { StopService () { ConsoleMessage "Stopping PostgreSQL database server" - sudo -u $PGUSER sh -c "$PGCTL stop -D '${PGDATA}' -s -m fast" + sudo -u $PGUSER sh -c "$PGCTL stop -D '${PGDATA}' -s" } RestartService () { if [ "${POSTGRESQL:=-NO-}" = "-YES-" ]; then ConsoleMessage "Restarting PostgreSQL database server" - # should match StopService: - sudo -u $PGUSER sh -c "$PGCTL stop -D '${PGDATA}' -s -m fast" - # should match StartService: + # should match StopService: + sudo -u $PGUSER sh -c "$PGCTL stop -D '${PGDATA}' -s" + # should match StartService: if [ "${ROTATELOGS}" = "1" ]; then sudo -u $PGUSER sh -c "${DAEMON} -D '${PGDATA}' &" 2>&1 | ${LOGUTIL} "${PGLOG}" ${ROTATESEC} & else diff --git a/contrib/tablefunc/tablefunc.c b/contrib/tablefunc/tablefunc.c index 787c02d08f..7434ca9373 100644 --- a/contrib/tablefunc/tablefunc.c +++ b/contrib/tablefunc/tablefunc.c @@ -10,7 +10,7 @@ * And contributors: * Nabil Sayegh * - * Copyright (c) 2002-2016, PostgreSQL Global Development Group + * Copyright (c) 2002-2017, PostgreSQL Global Development Group * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without a written agreement diff --git a/contrib/tablefunc/tablefunc.h b/contrib/tablefunc/tablefunc.h index 3477ed823f..87fa1e5dcb 100644 --- a/contrib/tablefunc/tablefunc.h +++ b/contrib/tablefunc/tablefunc.h @@ -10,7 +10,7 @@ * And contributors: * Nabil Sayegh * - * Copyright (c) 2002-2016, PostgreSQL Global Development Group + * Copyright (c) 2002-2017, PostgreSQL Global Development Group * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without a written agreement @@ -36,13 +36,4 @@ #include "fmgr.h" -/* - * External declarations - */ -extern Datum normal_rand(PG_FUNCTION_ARGS); -extern Datum crosstab(PG_FUNCTION_ARGS); -extern Datum crosstab_hash(PG_FUNCTION_ARGS); -extern Datum connectby_text(PG_FUNCTION_ARGS); -extern Datum connectby_text_serial(PG_FUNCTION_ARGS); - #endif /* TABLEFUNC_H */ diff --git a/contrib/tcn/tcn.c b/contrib/tcn/tcn.c index 7352b292b9..124110830f 100644 --- a/contrib/tcn/tcn.c +++ b/contrib/tcn/tcn.c @@ -3,7 +3,7 @@ * tcn.c * triggered change notification support for PostgreSQL * - * Portions Copyright (c) 2011-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2011-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/contrib/test_decoding/Makefile b/contrib/test_decoding/Makefile index 309cb0b39a..d2bc8b8350 100644 --- a/contrib/test_decoding/Makefile +++ b/contrib/test_decoding/Makefile @@ -38,7 +38,8 @@ submake-test_decoding: $(MAKE) -C $(top_builddir)/contrib/test_decoding REGRESSCHECKS=ddl xact rewrite toast permissions decoding_in_xact \ - decoding_into_rel binary prepared replorigin time messages + decoding_into_rel binary prepared replorigin time messages \ + spill slot regresscheck: | submake-regress submake-test_decoding temp-install $(MKDIR_P) regression_output diff --git a/contrib/test_decoding/expected/ddl.out b/contrib/test_decoding/expected/ddl.out index bd9b42f401..c104c4802d 100644 --- a/contrib/test_decoding/expected/ddl.out +++ b/contrib/test_decoding/expected/ddl.out @@ -274,9 +274,9 @@ INSERT INTO tr_etoomuch (id, data) SELECT g.i, -g.i FROM generate_series(8000, 12000) g(i) ON CONFLICT(id) DO UPDATE SET data = EXCLUDED.data; SELECT substring(data, 1, 29), count(*) -FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1') +FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1') WITH ORDINALITY GROUP BY 1 -ORDER BY min(location - '0/0'); +ORDER BY min(ordinality); substring | count -------------------------------+------- BEGIN | 1 @@ -416,12 +416,12 @@ CREATE TABLE replication_metadata ( WITH (user_catalog_table = true) ; \d+ replication_metadata - Table "public.replication_metadata" - Column | Type | Modifiers | Storage | Stats target | Description -----------+---------+-------------------------------------------------------------------+----------+--------------+------------- - id | integer | not null default nextval('replication_metadata_id_seq'::regclass) | plain | | - relation | name | not null | plain | | - options | text[] | | extended | | + Table "public.replication_metadata" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +----------+---------+-----------+----------+--------------------------------------------------+----------+--------------+------------- + id | integer | | not null | nextval('replication_metadata_id_seq'::regclass) | plain | | + relation | name | | not null | | plain | | + options | text[] | | | | extended | | Indexes: "replication_metadata_pkey" PRIMARY KEY, btree (id) Options: user_catalog_table=true @@ -430,12 +430,12 @@ INSERT INTO replication_metadata(relation, options) VALUES ('foo', ARRAY['a', 'b']); ALTER TABLE replication_metadata RESET (user_catalog_table); \d+ replication_metadata - Table "public.replication_metadata" - Column | Type | Modifiers | Storage | Stats target | Description -----------+---------+-------------------------------------------------------------------+----------+--------------+------------- - id | integer | not null default nextval('replication_metadata_id_seq'::regclass) | plain | | - relation | name | not null | plain | | - options | text[] | | extended | | + Table "public.replication_metadata" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +----------+---------+-----------+----------+--------------------------------------------------+----------+--------------+------------- + id | integer | | not null | nextval('replication_metadata_id_seq'::regclass) | plain | | + relation | name | | not null | | plain | | + options | text[] | | | | extended | | Indexes: "replication_metadata_pkey" PRIMARY KEY, btree (id) @@ -443,12 +443,12 @@ INSERT INTO replication_metadata(relation, options) VALUES ('bar', ARRAY['a', 'b']); ALTER TABLE replication_metadata SET (user_catalog_table = true); \d+ replication_metadata - Table "public.replication_metadata" - Column | Type | Modifiers | Storage | Stats target | Description -----------+---------+-------------------------------------------------------------------+----------+--------------+------------- - id | integer | not null default nextval('replication_metadata_id_seq'::regclass) | plain | | - relation | name | not null | plain | | - options | text[] | | extended | | + Table "public.replication_metadata" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +----------+---------+-----------+----------+--------------------------------------------------+----------+--------------+------------- + id | integer | | not null | nextval('replication_metadata_id_seq'::regclass) | plain | | + relation | name | | not null | | plain | | + options | text[] | | | | extended | | Indexes: "replication_metadata_pkey" PRIMARY KEY, btree (id) Options: user_catalog_table=true @@ -461,13 +461,13 @@ ALTER TABLE replication_metadata ALTER COLUMN rewritemeornot TYPE text; ERROR: cannot rewrite table "replication_metadata" used as a catalog table ALTER TABLE replication_metadata SET (user_catalog_table = false); \d+ replication_metadata - Table "public.replication_metadata" - Column | Type | Modifiers | Storage | Stats target | Description -----------------+---------+-------------------------------------------------------------------+----------+--------------+------------- - id | integer | not null default nextval('replication_metadata_id_seq'::regclass) | plain | | - relation | name | not null | plain | | - options | text[] | | extended | | - rewritemeornot | integer | | plain | | + Table "public.replication_metadata" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +----------------+---------+-----------+----------+--------------------------------------------------+----------+--------------+------------- + id | integer | | not null | nextval('replication_metadata_id_seq'::regclass) | plain | | + relation | name | | not null | | plain | | + options | text[] | | | | extended | | + rewritemeornot | integer | | | | plain | | Indexes: "replication_metadata_pkey" PRIMARY KEY, btree (id) Options: user_catalog_table=false @@ -702,7 +702,7 @@ SELECT pg_drop_replication_slot('regression_slot'); /* check that the slot is gone */ SELECT * FROM pg_replication_slots; - slot_name | plugin | slot_type | datoid | database | active | active_pid | xmin | catalog_xmin | restart_lsn | confirmed_flush_lsn ------------+--------+-----------+--------+----------+--------+------------+------+--------------+-------------+--------------------- + slot_name | plugin | slot_type | datoid | database | temporary | active | active_pid | xmin | catalog_xmin | restart_lsn | confirmed_flush_lsn +-----------+--------+-----------+--------+----------+-----------+--------+------------+------+--------------+-------------+--------------------- (0 rows) diff --git a/contrib/test_decoding/expected/slot.out b/contrib/test_decoding/expected/slot.out new file mode 100644 index 0000000000..6dee1436cc --- /dev/null +++ b/contrib/test_decoding/expected/slot.out @@ -0,0 +1,100 @@ +SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot_p', 'test_decoding'); + ?column? +---------- + init +(1 row) + +SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot_t', 'test_decoding', true); + ?column? +---------- + init +(1 row) + +SELECT pg_drop_replication_slot('regression_slot_p'); + pg_drop_replication_slot +-------------------------- + +(1 row) + +SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot_p', 'test_decoding', false); + ?column? +---------- + init +(1 row) + +SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot_t2', 'test_decoding', true); + ?column? +---------- + init +(1 row) + +-- here we want to start a new session and wait till old one is gone +select pg_backend_pid() as oldpid \gset +\c - +do 'declare c int = 0; +begin + while (select count(*) from pg_replication_slots where active_pid = ' + :'oldpid' + ') > 0 loop c := c + 1; perform pg_sleep(0.01); end loop; + raise log ''slot test looped % times'', c; +end'; +-- should fail because the temporary slots were dropped automatically +SELECT pg_drop_replication_slot('regression_slot_t'); +ERROR: replication slot "regression_slot_t" does not exist +SELECT pg_drop_replication_slot('regression_slot_t2'); +ERROR: replication slot "regression_slot_t2" does not exist +-- permanent slot has survived +SELECT pg_drop_replication_slot('regression_slot_p'); + pg_drop_replication_slot +-------------------------- + +(1 row) + +-- test switching between slots in a session +SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot1', 'test_decoding', true); + ?column? +---------- + init +(1 row) + +CREATE TABLE replication_example(id SERIAL PRIMARY KEY, somedata int, text varchar(120)); +BEGIN; +INSERT INTO replication_example(somedata, text) VALUES (1, 1); +INSERT INTO replication_example(somedata, text) VALUES (1, 2); +COMMIT; +SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot2', 'test_decoding', true); + ?column? +---------- + init +(1 row) + +INSERT INTO replication_example(somedata, text) VALUES (1, 3); +SELECT data FROM pg_logical_slot_get_changes('regression_slot1', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); + data +--------------------------------------------------------------------------------------------------------- + BEGIN + table public.replication_example: INSERT: id[integer]:1 somedata[integer]:1 text[character varying]:'1' + table public.replication_example: INSERT: id[integer]:2 somedata[integer]:1 text[character varying]:'2' + COMMIT + BEGIN + table public.replication_example: INSERT: id[integer]:3 somedata[integer]:1 text[character varying]:'3' + COMMIT +(7 rows) + +SELECT data FROM pg_logical_slot_get_changes('regression_slot2', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); + data +--------------------------------------------------------------------------------------------------------- + BEGIN + table public.replication_example: INSERT: id[integer]:3 somedata[integer]:1 text[character varying]:'3' + COMMIT +(3 rows) + +DROP TABLE replication_example; +-- error +SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot1', 'test_decoding', true); +ERROR: replication slot "regression_slot1" already exists +-- both should error as they should be dropped on error +SELECT pg_drop_replication_slot('regression_slot1'); +ERROR: replication slot "regression_slot1" does not exist +SELECT pg_drop_replication_slot('regression_slot2'); +ERROR: replication slot "regression_slot2" does not exist diff --git a/contrib/test_decoding/expected/spill.out b/contrib/test_decoding/expected/spill.out new file mode 100644 index 0000000000..10734bdb6a --- /dev/null +++ b/contrib/test_decoding/expected/spill.out @@ -0,0 +1,256 @@ +-- predictability +SET synchronous_commit = on; +SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding'); + ?column? +---------- + init +(1 row) + +CREATE TABLE spill_test(data text); +-- consume DDL +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); + data +------ +(0 rows) + +-- spilling main xact +BEGIN; +INSERT INTO spill_test SELECT 'serialize-topbig--1:'||g.i FROM generate_series(1, 5000) g(i); +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4], COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + regexp_split_to_array | count | array_agg | array_agg +-----------------------+-------+---------------------------------------------------------------------+------------------------------------------------------------------------ + 'serialize-topbig--1 | 5000 | table public.spill_test: INSERT: data[text]:'serialize-topbig--1:1' | table public.spill_test: INSERT: data[text]:'serialize-topbig--1:5000' +(1 row) + +-- spilling subxact, nothing in main +BEGIN; +SAVEPOINT s; +INSERT INTO spill_test SELECT 'serialize-subbig--1:'||g.i FROM generate_series(1, 5000) g(i); +RELEASE SAVEPOINT s; +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4], COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + regexp_split_to_array | count | array_agg | array_agg +-----------------------+-------+---------------------------------------------------------------------+------------------------------------------------------------------------ + 'serialize-subbig--1 | 5000 | table public.spill_test: INSERT: data[text]:'serialize-subbig--1:1' | table public.spill_test: INSERT: data[text]:'serialize-subbig--1:5000' +(1 row) + +-- spilling subxact, spilling main xact +BEGIN; +SAVEPOINT s; +INSERT INTO spill_test SELECT 'serialize-subbig-topbig--1:'||g.i FROM generate_series(1, 5000) g(i); +RELEASE SAVEPOINT s; +INSERT INTO spill_test SELECT 'serialize-subbig-topbig--2:'||g.i FROM generate_series(5001, 10000) g(i); +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4], COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + regexp_split_to_array | count | array_agg | array_agg +-----------------------------+-------+-------------------------------------------------------------------------------+-------------------------------------------------------------------------------- + 'serialize-subbig-topbig--1 | 5000 | table public.spill_test: INSERT: data[text]:'serialize-subbig-topbig--1:1' | table public.spill_test: INSERT: data[text]:'serialize-subbig-topbig--1:5000' + 'serialize-subbig-topbig--2 | 5000 | table public.spill_test: INSERT: data[text]:'serialize-subbig-topbig--2:5001' | table public.spill_test: INSERT: data[text]:'serialize-subbig-topbig--2:10000' +(2 rows) + +-- spilling subxact, non-spilling main xact +BEGIN; +SAVEPOINT s; +INSERT INTO spill_test SELECT 'serialize-subbig-topsmall--1:'||g.i FROM generate_series(1, 5000) g(i); +RELEASE SAVEPOINT s; +INSERT INTO spill_test SELECT 'serialize-subbig-topsmall--2:'||g.i FROM generate_series(5001, 5001) g(i); +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4], COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + regexp_split_to_array | count | array_agg | array_agg +-------------------------------+-------+---------------------------------------------------------------------------------+--------------------------------------------------------------------------------- + 'serialize-subbig-topsmall--1 | 5000 | table public.spill_test: INSERT: data[text]:'serialize-subbig-topsmall--1:1' | table public.spill_test: INSERT: data[text]:'serialize-subbig-topsmall--1:5000' + 'serialize-subbig-topsmall--2 | 1 | table public.spill_test: INSERT: data[text]:'serialize-subbig-topsmall--2:5001' | table public.spill_test: INSERT: data[text]:'serialize-subbig-topsmall--2:5001' +(2 rows) + +-- not-spilling subxact, spilling main xact +BEGIN; +SAVEPOINT s; +INSERT INTO spill_test SELECT 'serialize-subbig-topbig--1:'||g.i FROM generate_series(1, 5000) g(i); +RELEASE SAVEPOINT s; +INSERT INTO spill_test SELECT 'serialize-subbig-topbig--2:'||g.i FROM generate_series(5001, 10000) g(i); +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4], COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + regexp_split_to_array | count | array_agg | array_agg +-----------------------------+-------+-------------------------------------------------------------------------------+-------------------------------------------------------------------------------- + 'serialize-subbig-topbig--1 | 5000 | table public.spill_test: INSERT: data[text]:'serialize-subbig-topbig--1:1' | table public.spill_test: INSERT: data[text]:'serialize-subbig-topbig--1:5000' + 'serialize-subbig-topbig--2 | 5000 | table public.spill_test: INSERT: data[text]:'serialize-subbig-topbig--2:5001' | table public.spill_test: INSERT: data[text]:'serialize-subbig-topbig--2:10000' +(2 rows) + +-- spilling main xact, spilling subxact +BEGIN; +INSERT INTO spill_test SELECT 'serialize-topbig-subbig--1:'||g.i FROM generate_series(1, 5000) g(i); +SAVEPOINT s; +INSERT INTO spill_test SELECT 'serialize-topbig-subbig--2:'||g.i FROM generate_series(5001, 10000) g(i); +RELEASE SAVEPOINT s; +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4], COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + regexp_split_to_array | count | array_agg | array_agg +-----------------------------+-------+-------------------------------------------------------------------------------+-------------------------------------------------------------------------------- + 'serialize-topbig-subbig--1 | 5000 | table public.spill_test: INSERT: data[text]:'serialize-topbig-subbig--1:1' | table public.spill_test: INSERT: data[text]:'serialize-topbig-subbig--1:5000' + 'serialize-topbig-subbig--2 | 5000 | table public.spill_test: INSERT: data[text]:'serialize-topbig-subbig--2:5001' | table public.spill_test: INSERT: data[text]:'serialize-topbig-subbig--2:10000' +(2 rows) + +-- spilling main xact, not spilling subxact +BEGIN; +INSERT INTO spill_test SELECT 'serialize-topbig-subsmall--1:'||g.i FROM generate_series(1, 5000) g(i); +SAVEPOINT s; +INSERT INTO spill_test SELECT 'serialize-topbig-subsmall--2:'||g.i FROM generate_series(5001, 5001) g(i); +RELEASE SAVEPOINT s; +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4], COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + regexp_split_to_array | count | array_agg | array_agg +-------------------------------+-------+---------------------------------------------------------------------------------+--------------------------------------------------------------------------------- + 'serialize-topbig-subsmall--1 | 5000 | table public.spill_test: INSERT: data[text]:'serialize-topbig-subsmall--1:1' | table public.spill_test: INSERT: data[text]:'serialize-topbig-subsmall--1:5000' + 'serialize-topbig-subsmall--2 | 1 | table public.spill_test: INSERT: data[text]:'serialize-topbig-subsmall--2:5001' | table public.spill_test: INSERT: data[text]:'serialize-topbig-subsmall--2:5001' +(2 rows) + +-- spilling subxact, followed by another spilling subxact +BEGIN; +SAVEPOINT s1; +INSERT INTO spill_test SELECT 'serialize-subbig-subbig--1:'||g.i FROM generate_series(1, 5000) g(i); +RELEASE SAVEPOINT s1; +SAVEPOINT s2; +INSERT INTO spill_test SELECT 'serialize-subbig-subbig--2:'||g.i FROM generate_series(5001, 10000) g(i); +RELEASE SAVEPOINT s2; +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4], COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + regexp_split_to_array | count | array_agg | array_agg +-----------------------------+-------+-------------------------------------------------------------------------------+-------------------------------------------------------------------------------- + 'serialize-subbig-subbig--1 | 5000 | table public.spill_test: INSERT: data[text]:'serialize-subbig-subbig--1:1' | table public.spill_test: INSERT: data[text]:'serialize-subbig-subbig--1:5000' + 'serialize-subbig-subbig--2 | 5000 | table public.spill_test: INSERT: data[text]:'serialize-subbig-subbig--2:5001' | table public.spill_test: INSERT: data[text]:'serialize-subbig-subbig--2:10000' +(2 rows) + +-- spilling subxact, followed by not spilling subxact +BEGIN; +SAVEPOINT s1; +INSERT INTO spill_test SELECT 'serialize-subbig-subsmall--1:'||g.i FROM generate_series(1, 5000) g(i); +RELEASE SAVEPOINT s1; +SAVEPOINT s2; +INSERT INTO spill_test SELECT 'serialize-subbig-subsmall--2:'||g.i FROM generate_series(5001, 5001) g(i); +RELEASE SAVEPOINT s2; +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4], COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + regexp_split_to_array | count | array_agg | array_agg +-------------------------------+-------+---------------------------------------------------------------------------------+--------------------------------------------------------------------------------- + 'serialize-subbig-subsmall--1 | 5000 | table public.spill_test: INSERT: data[text]:'serialize-subbig-subsmall--1:1' | table public.spill_test: INSERT: data[text]:'serialize-subbig-subsmall--1:5000' + 'serialize-subbig-subsmall--2 | 1 | table public.spill_test: INSERT: data[text]:'serialize-subbig-subsmall--2:5001' | table public.spill_test: INSERT: data[text]:'serialize-subbig-subsmall--2:5001' +(2 rows) + +-- not spilling subxact, followed by spilling subxact +BEGIN; +SAVEPOINT s1; +INSERT INTO spill_test SELECT 'serialize-subsmall-subbig--1:'||g.i FROM generate_series(1, 1) g(i); +RELEASE SAVEPOINT s1; +SAVEPOINT s2; +INSERT INTO spill_test SELECT 'serialize-subsmall-subbig--2:'||g.i FROM generate_series(2, 5001) g(i); +RELEASE SAVEPOINT s2; +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4] COLLATE "C", COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + regexp_split_to_array | count | array_agg | array_agg +-------------------------------+-------+------------------------------------------------------------------------------+--------------------------------------------------------------------------------- + 'serialize-subsmall-subbig--1 | 1 | table public.spill_test: INSERT: data[text]:'serialize-subsmall-subbig--1:1' | table public.spill_test: INSERT: data[text]:'serialize-subsmall-subbig--1:1' + 'serialize-subsmall-subbig--2 | 5000 | table public.spill_test: INSERT: data[text]:'serialize-subsmall-subbig--2:2' | table public.spill_test: INSERT: data[text]:'serialize-subsmall-subbig--2:5001' +(2 rows) + +-- spilling subxact, containing another spilling subxact +BEGIN; +SAVEPOINT s1; +INSERT INTO spill_test SELECT 'serialize-nested-subbig-subbig--1:'||g.i FROM generate_series(1, 5000) g(i); +SAVEPOINT s2; +INSERT INTO spill_test SELECT 'serialize-nested-subbig-subbig--2:'||g.i FROM generate_series(5001, 10000) g(i); +RELEASE SAVEPOINT s2; +RELEASE SAVEPOINT s1; +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4] COLLATE "C", COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + regexp_split_to_array | count | array_agg | array_agg +------------------------------------+-------+--------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------- + 'serialize-nested-subbig-subbig--1 | 5000 | table public.spill_test: INSERT: data[text]:'serialize-nested-subbig-subbig--1:1' | table public.spill_test: INSERT: data[text]:'serialize-nested-subbig-subbig--1:5000' + 'serialize-nested-subbig-subbig--2 | 5000 | table public.spill_test: INSERT: data[text]:'serialize-nested-subbig-subbig--2:5001' | table public.spill_test: INSERT: data[text]:'serialize-nested-subbig-subbig--2:10000' +(2 rows) + +-- spilling subxact, containing a not spilling subxact +BEGIN; +SAVEPOINT s1; +INSERT INTO spill_test SELECT 'serialize-nested-subbig-subsmall--1:'||g.i FROM generate_series(1, 5000) g(i); +SAVEPOINT s2; +INSERT INTO spill_test SELECT 'serialize-nested-subbig-subsmall--2:'||g.i FROM generate_series(5001, 5001) g(i); +RELEASE SAVEPOINT s2; +RELEASE SAVEPOINT s1; +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4] COLLATE "C", COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + regexp_split_to_array | count | array_agg | array_agg +--------------------------------------+-------+----------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------- + 'serialize-nested-subbig-subsmall--1 | 5000 | table public.spill_test: INSERT: data[text]:'serialize-nested-subbig-subsmall--1:1' | table public.spill_test: INSERT: data[text]:'serialize-nested-subbig-subsmall--1:5000' + 'serialize-nested-subbig-subsmall--2 | 1 | table public.spill_test: INSERT: data[text]:'serialize-nested-subbig-subsmall--2:5001' | table public.spill_test: INSERT: data[text]:'serialize-nested-subbig-subsmall--2:5001' +(2 rows) + +-- not spilling subxact, containing a spilling subxact +BEGIN; +SAVEPOINT s1; +INSERT INTO spill_test SELECT 'serialize-nested-subsmall-subbig--1:'||g.i FROM generate_series(1, 1) g(i); +SAVEPOINT s2; +INSERT INTO spill_test SELECT 'serialize-nested-subsmall-subbig--2:'||g.i FROM generate_series(2, 5001) g(i); +RELEASE SAVEPOINT s2; +RELEASE SAVEPOINT s1; +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4] COLLATE "C", COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + regexp_split_to_array | count | array_agg | array_agg +--------------------------------------+-------+-------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------- + 'serialize-nested-subsmall-subbig--1 | 1 | table public.spill_test: INSERT: data[text]:'serialize-nested-subsmall-subbig--1:1' | table public.spill_test: INSERT: data[text]:'serialize-nested-subsmall-subbig--1:1' + 'serialize-nested-subsmall-subbig--2 | 5000 | table public.spill_test: INSERT: data[text]:'serialize-nested-subsmall-subbig--2:2' | table public.spill_test: INSERT: data[text]:'serialize-nested-subsmall-subbig--2:5001' +(2 rows) + +-- not spilling subxact, containing a spilling subxact that aborts and one that commits +BEGIN; +SAVEPOINT s1; +INSERT INTO spill_test SELECT 'serialize-nested-subbig-subbigabort--1:'||g.i FROM generate_series(1, 5000) g(i); +SAVEPOINT s2; +INSERT INTO spill_test SELECT 'serialize-nested-subbig-subbigabort--2:'||g.i FROM generate_series(5001, 10000) g(i); +ROLLBACK TO SAVEPOINT s2; +SAVEPOINT s3; +INSERT INTO spill_test SELECT 'serialize-nested-subbig-subbigabort-subbig-3:'||g.i FROM generate_series(5001, 10000) g(i); +RELEASE SAVEPOINT s1; +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4] COLLATE "C", COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + regexp_split_to_array | count | array_agg | array_agg +-----------------------------------------------+-------+-------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------- + 'serialize-nested-subbig-subbigabort--1 | 5000 | table public.spill_test: INSERT: data[text]:'serialize-nested-subbig-subbigabort--1:1' | table public.spill_test: INSERT: data[text]:'serialize-nested-subbig-subbigabort--1:5000' + 'serialize-nested-subbig-subbigabort-subbig-3 | 5000 | table public.spill_test: INSERT: data[text]:'serialize-nested-subbig-subbigabort-subbig-3:5001' | table public.spill_test: INSERT: data[text]:'serialize-nested-subbig-subbigabort-subbig-3:10000' +(2 rows) + +DROP TABLE spill_test; +SELECT pg_drop_replication_slot('regression_slot'); + pg_drop_replication_slot +-------------------------- + +(1 row) + diff --git a/contrib/test_decoding/sql/ddl.sql b/contrib/test_decoding/sql/ddl.sql index e99b2d37d9..89b8b8f780 100644 --- a/contrib/test_decoding/sql/ddl.sql +++ b/contrib/test_decoding/sql/ddl.sql @@ -146,9 +146,9 @@ SELECT g.i, -g.i FROM generate_series(8000, 12000) g(i) ON CONFLICT(id) DO UPDATE SET data = EXCLUDED.data; SELECT substring(data, 1, 29), count(*) -FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1') +FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1') WITH ORDINALITY GROUP BY 1 -ORDER BY min(location - '0/0'); +ORDER BY min(ordinality); /* * check whether we decode subtransactions correctly in relation with each diff --git a/contrib/test_decoding/sql/slot.sql b/contrib/test_decoding/sql/slot.sql new file mode 100644 index 0000000000..7ca83feac5 --- /dev/null +++ b/contrib/test_decoding/sql/slot.sql @@ -0,0 +1,50 @@ +SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot_p', 'test_decoding'); +SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot_t', 'test_decoding', true); + +SELECT pg_drop_replication_slot('regression_slot_p'); +SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot_p', 'test_decoding', false); + +SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot_t2', 'test_decoding', true); + +-- here we want to start a new session and wait till old one is gone +select pg_backend_pid() as oldpid \gset +\c - +do 'declare c int = 0; +begin + while (select count(*) from pg_replication_slots where active_pid = ' + :'oldpid' + ') > 0 loop c := c + 1; perform pg_sleep(0.01); end loop; + raise log ''slot test looped % times'', c; +end'; + +-- should fail because the temporary slots were dropped automatically +SELECT pg_drop_replication_slot('regression_slot_t'); +SELECT pg_drop_replication_slot('regression_slot_t2'); + +-- permanent slot has survived +SELECT pg_drop_replication_slot('regression_slot_p'); + +-- test switching between slots in a session +SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot1', 'test_decoding', true); + +CREATE TABLE replication_example(id SERIAL PRIMARY KEY, somedata int, text varchar(120)); +BEGIN; +INSERT INTO replication_example(somedata, text) VALUES (1, 1); +INSERT INTO replication_example(somedata, text) VALUES (1, 2); +COMMIT; + +SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot2', 'test_decoding', true); + +INSERT INTO replication_example(somedata, text) VALUES (1, 3); + +SELECT data FROM pg_logical_slot_get_changes('regression_slot1', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +SELECT data FROM pg_logical_slot_get_changes('regression_slot2', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); + +DROP TABLE replication_example; + +-- error +SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot1', 'test_decoding', true); + +-- both should error as they should be dropped on error +SELECT pg_drop_replication_slot('regression_slot1'); +SELECT pg_drop_replication_slot('regression_slot2'); diff --git a/contrib/test_decoding/sql/spill.sql b/contrib/test_decoding/sql/spill.sql new file mode 100644 index 0000000000..e638cacd3f --- /dev/null +++ b/contrib/test_decoding/sql/spill.sql @@ -0,0 +1,179 @@ +-- predictability +SET synchronous_commit = on; + +SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding'); + +CREATE TABLE spill_test(data text); + +-- consume DDL +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); + +-- spilling main xact +BEGIN; +INSERT INTO spill_test SELECT 'serialize-topbig--1:'||g.i FROM generate_series(1, 5000) g(i); +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4], COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + +-- spilling subxact, nothing in main +BEGIN; +SAVEPOINT s; +INSERT INTO spill_test SELECT 'serialize-subbig--1:'||g.i FROM generate_series(1, 5000) g(i); +RELEASE SAVEPOINT s; +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4], COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + +-- spilling subxact, spilling main xact +BEGIN; +SAVEPOINT s; +INSERT INTO spill_test SELECT 'serialize-subbig-topbig--1:'||g.i FROM generate_series(1, 5000) g(i); +RELEASE SAVEPOINT s; +INSERT INTO spill_test SELECT 'serialize-subbig-topbig--2:'||g.i FROM generate_series(5001, 10000) g(i); +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4], COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + +-- spilling subxact, non-spilling main xact +BEGIN; +SAVEPOINT s; +INSERT INTO spill_test SELECT 'serialize-subbig-topsmall--1:'||g.i FROM generate_series(1, 5000) g(i); +RELEASE SAVEPOINT s; +INSERT INTO spill_test SELECT 'serialize-subbig-topsmall--2:'||g.i FROM generate_series(5001, 5001) g(i); +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4], COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + +-- not-spilling subxact, spilling main xact +BEGIN; +SAVEPOINT s; +INSERT INTO spill_test SELECT 'serialize-subbig-topbig--1:'||g.i FROM generate_series(1, 5000) g(i); +RELEASE SAVEPOINT s; +INSERT INTO spill_test SELECT 'serialize-subbig-topbig--2:'||g.i FROM generate_series(5001, 10000) g(i); +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4], COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + +-- spilling main xact, spilling subxact +BEGIN; +INSERT INTO spill_test SELECT 'serialize-topbig-subbig--1:'||g.i FROM generate_series(1, 5000) g(i); +SAVEPOINT s; +INSERT INTO spill_test SELECT 'serialize-topbig-subbig--2:'||g.i FROM generate_series(5001, 10000) g(i); +RELEASE SAVEPOINT s; +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4], COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + +-- spilling main xact, not spilling subxact +BEGIN; +INSERT INTO spill_test SELECT 'serialize-topbig-subsmall--1:'||g.i FROM generate_series(1, 5000) g(i); +SAVEPOINT s; +INSERT INTO spill_test SELECT 'serialize-topbig-subsmall--2:'||g.i FROM generate_series(5001, 5001) g(i); +RELEASE SAVEPOINT s; +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4], COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + +-- spilling subxact, followed by another spilling subxact +BEGIN; +SAVEPOINT s1; +INSERT INTO spill_test SELECT 'serialize-subbig-subbig--1:'||g.i FROM generate_series(1, 5000) g(i); +RELEASE SAVEPOINT s1; +SAVEPOINT s2; +INSERT INTO spill_test SELECT 'serialize-subbig-subbig--2:'||g.i FROM generate_series(5001, 10000) g(i); +RELEASE SAVEPOINT s2; +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4], COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + +-- spilling subxact, followed by not spilling subxact +BEGIN; +SAVEPOINT s1; +INSERT INTO spill_test SELECT 'serialize-subbig-subsmall--1:'||g.i FROM generate_series(1, 5000) g(i); +RELEASE SAVEPOINT s1; +SAVEPOINT s2; +INSERT INTO spill_test SELECT 'serialize-subbig-subsmall--2:'||g.i FROM generate_series(5001, 5001) g(i); +RELEASE SAVEPOINT s2; +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4], COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + +-- not spilling subxact, followed by spilling subxact +BEGIN; +SAVEPOINT s1; +INSERT INTO spill_test SELECT 'serialize-subsmall-subbig--1:'||g.i FROM generate_series(1, 1) g(i); +RELEASE SAVEPOINT s1; +SAVEPOINT s2; +INSERT INTO spill_test SELECT 'serialize-subsmall-subbig--2:'||g.i FROM generate_series(2, 5001) g(i); +RELEASE SAVEPOINT s2; +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4] COLLATE "C", COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + +-- spilling subxact, containing another spilling subxact +BEGIN; +SAVEPOINT s1; +INSERT INTO spill_test SELECT 'serialize-nested-subbig-subbig--1:'||g.i FROM generate_series(1, 5000) g(i); +SAVEPOINT s2; +INSERT INTO spill_test SELECT 'serialize-nested-subbig-subbig--2:'||g.i FROM generate_series(5001, 10000) g(i); +RELEASE SAVEPOINT s2; +RELEASE SAVEPOINT s1; +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4] COLLATE "C", COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + +-- spilling subxact, containing a not spilling subxact +BEGIN; +SAVEPOINT s1; +INSERT INTO spill_test SELECT 'serialize-nested-subbig-subsmall--1:'||g.i FROM generate_series(1, 5000) g(i); +SAVEPOINT s2; +INSERT INTO spill_test SELECT 'serialize-nested-subbig-subsmall--2:'||g.i FROM generate_series(5001, 5001) g(i); +RELEASE SAVEPOINT s2; +RELEASE SAVEPOINT s1; +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4] COLLATE "C", COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + +-- not spilling subxact, containing a spilling subxact +BEGIN; +SAVEPOINT s1; +INSERT INTO spill_test SELECT 'serialize-nested-subsmall-subbig--1:'||g.i FROM generate_series(1, 1) g(i); +SAVEPOINT s2; +INSERT INTO spill_test SELECT 'serialize-nested-subsmall-subbig--2:'||g.i FROM generate_series(2, 5001) g(i); +RELEASE SAVEPOINT s2; +RELEASE SAVEPOINT s1; +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4] COLLATE "C", COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + +-- not spilling subxact, containing a spilling subxact that aborts and one that commits +BEGIN; +SAVEPOINT s1; +INSERT INTO spill_test SELECT 'serialize-nested-subbig-subbigabort--1:'||g.i FROM generate_series(1, 5000) g(i); +SAVEPOINT s2; +INSERT INTO spill_test SELECT 'serialize-nested-subbig-subbigabort--2:'||g.i FROM generate_series(5001, 10000) g(i); +ROLLBACK TO SAVEPOINT s2; +SAVEPOINT s3; +INSERT INTO spill_test SELECT 'serialize-nested-subbig-subbigabort-subbig-3:'||g.i FROM generate_series(5001, 10000) g(i); +RELEASE SAVEPOINT s1; +COMMIT; +SELECT (regexp_split_to_array(data, ':'))[4] COLLATE "C", COUNT(*), (array_agg(data))[1], (array_agg(data))[count(*)] +FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL) WHERE data ~ 'INSERT' +GROUP BY 1 ORDER BY 1; + +DROP TABLE spill_test; + +SELECT pg_drop_replication_slot('regression_slot'); diff --git a/contrib/test_decoding/test_decoding.c b/contrib/test_decoding/test_decoding.c index c3508f0e13..21cfd673c6 100644 --- a/contrib/test_decoding/test_decoding.c +++ b/contrib/test_decoding/test_decoding.c @@ -3,7 +3,7 @@ * test_decoding.c * example logical decoding output plugin * - * Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Copyright (c) 2012-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/test_decoding/test_decoding.c @@ -102,9 +102,7 @@ pg_decode_startup(LogicalDecodingContext *ctx, OutputPluginOptions *opt, data = palloc0(sizeof(TestDecodingData)); data->context = AllocSetContextCreate(ctx->context, "text conversion context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); data->include_xids = true; data->include_timestamp = false; data->skip_empty_xacts = false; diff --git a/contrib/tsearch2/expected/tsearch2.out b/contrib/tsearch2/expected/tsearch2.out index e84e4d27f2..eef85ef09d 100644 --- a/contrib/tsearch2/expected/tsearch2.out +++ b/contrib/tsearch2/expected/tsearch2.out @@ -1,4 +1,12 @@ CREATE EXTENSION tsearch2; +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + amname | opcname +--------+--------- +(0 rows) + --tsvector SELECT '1'::tsvector; tsvector diff --git a/contrib/tsearch2/sql/tsearch2.sql b/contrib/tsearch2/sql/tsearch2.sql index 53e3073af4..2c37c4a1dd 100644 --- a/contrib/tsearch2/sql/tsearch2.sql +++ b/contrib/tsearch2/sql/tsearch2.sql @@ -1,5 +1,10 @@ CREATE EXTENSION tsearch2; +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + --tsvector SELECT '1'::tsvector; SELECT '1 '::tsvector; diff --git a/contrib/tsearch2/tsearch2.c b/contrib/tsearch2/tsearch2.c index 3fc72cb995..16772a2b92 100644 --- a/contrib/tsearch2/tsearch2.c +++ b/contrib/tsearch2/tsearch2.c @@ -3,7 +3,7 @@ * tsearch2.c * Backwards-compatibility package for old contrib/tsearch2 API * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -19,6 +19,7 @@ #include "tsearch/ts_utils.h" #include "utils/builtins.h" #include "utils/guc.h" +#include "utils/regproc.h" #include "utils/syscache.h" PG_MODULE_MAGIC; diff --git a/contrib/tsm_system_rows/tsm_system_rows.c b/contrib/tsm_system_rows/tsm_system_rows.c index c5251ed652..544458ec91 100644 --- a/contrib/tsm_system_rows/tsm_system_rows.c +++ b/contrib/tsm_system_rows/tsm_system_rows.c @@ -17,7 +17,7 @@ * won't visit blocks added after the first scan, but that is fine since * such blocks shouldn't contain any visible tuples anyway. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/contrib/tsm_system_time/tsm_system_time.c b/contrib/tsm_system_time/tsm_system_time.c index cd681c042a..af8d025414 100644 --- a/contrib/tsm_system_time/tsm_system_time.c +++ b/contrib/tsm_system_time/tsm_system_time.c @@ -13,7 +13,7 @@ * However, we do what we can to reduce surprising behavior by selecting * the sampling pattern just once per query, much as in tsm_system_rows. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/contrib/unaccent/unaccent.c b/contrib/unaccent/unaccent.c index e243bc2607..542e7267be 100644 --- a/contrib/unaccent/unaccent.c +++ b/contrib/unaccent/unaccent.c @@ -3,7 +3,7 @@ * unaccent.c * Text search unaccent dictionary * - * Copyright (c) 2009-2016, PostgreSQL Global Development Group + * Copyright (c) 2009-2017, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/unaccent/unaccent.c @@ -20,6 +20,7 @@ #include "tsearch/ts_locale.h" #include "tsearch/ts_public.h" #include "utils/builtins.h" +#include "utils/regproc.h" PG_MODULE_MAGIC; diff --git a/contrib/uuid-ossp/uuid-ossp.c b/contrib/uuid-ossp/uuid-ossp.c index 3e12bc4e96..57bdf4d8d4 100644 --- a/contrib/uuid-ossp/uuid-ossp.c +++ b/contrib/uuid-ossp/uuid-ossp.c @@ -2,7 +2,7 @@ * * UUID generation functions using the BSD, E2FS or OSSP UUID library * - * Copyright (c) 2007-2016, PostgreSQL Global Development Group + * Copyright (c) 2007-2017, PostgreSQL Global Development Group * * Portions Copyright (c) 2009 Andrew Gierth * @@ -17,6 +17,10 @@ #include "utils/builtins.h" #include "utils/uuid.h" +/* for ntohl/htonl */ +#include +#include + /* * It's possible that there's more than one uuid.h header file present. * We expect configure to set the HAVE_ symbol for only the one we want. @@ -26,14 +30,14 @@ */ #define uuid_hash bsd_uuid_hash -#ifdef HAVE_UUID_H +#if defined(HAVE_UUID_H) #include -#endif -#ifdef HAVE_OSSP_UUID_H +#elif defined(HAVE_OSSP_UUID_H) #include -#endif -#ifdef HAVE_UUID_UUID_H +#elif defined(HAVE_UUID_UUID_H) #include +#else +#error "please use configure's --with-uuid switch to select a UUID library" #endif #undef uuid_hash diff --git a/contrib/vacuumlo/vacuumlo.c b/contrib/vacuumlo/vacuumlo.c index 769c805a84..d9dee2f7a0 100644 --- a/contrib/vacuumlo/vacuumlo.c +++ b/contrib/vacuumlo/vacuumlo.c @@ -3,7 +3,7 @@ * vacuumlo.c * This removes orphaned large objects from a database. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -65,13 +65,17 @@ vacuumlo(const char *database, const struct _param * param) long matched; long deleted; int i; - static char *password = NULL; bool new_pass; bool success = true; + static bool have_password = false; + static char password[100]; /* Note: password can be carried over from a previous call */ - if (param->pg_prompt == TRI_YES && password == NULL) - password = simple_prompt("Password: ", 100, false); + if (param->pg_prompt == TRI_YES && !have_password) + { + simple_prompt("Password: ", password, sizeof(password), false); + have_password = true; + } /* * Start the connection. Loop until we have a password if requested by @@ -91,7 +95,7 @@ vacuumlo(const char *database, const struct _param * param) keywords[2] = "user"; values[2] = param->pg_user; keywords[3] = "password"; - values[3] = password; + values[3] = have_password ? password : NULL; keywords[4] = "dbname"; values[4] = database; keywords[5] = "fallback_application_name"; @@ -110,11 +114,12 @@ vacuumlo(const char *database, const struct _param * param) if (PQstatus(conn) == CONNECTION_BAD && PQconnectionNeedsPassword(conn) && - password == NULL && + !have_password && param->pg_prompt != TRI_NO) { PQfinish(conn); - password = simple_prompt("Password: ", 100, false); + simple_prompt("Password: ", password, sizeof(password), false); + have_password = true; new_pass = true; } } while (new_pass); @@ -237,7 +242,7 @@ vacuumlo(const char *database, const struct _param * param) if (!schema || !table || !field) { - fprintf(stderr, "Out of memory\n"); + fprintf(stderr, "%s", PQerrorMessage(conn)); PQclear(res); PQfinish(conn); if (schema != NULL) @@ -514,7 +519,7 @@ main(int argc, char **argv) } break; case 'U': - param.pg_user = strdup(optarg); + param.pg_user = pg_strdup(optarg); break; case 'w': param.pg_prompt = TRI_NO; @@ -529,10 +534,10 @@ main(int argc, char **argv) fprintf(stderr, "%s: invalid port number: %s\n", progname, optarg); exit(1); } - param.pg_port = strdup(optarg); + param.pg_port = pg_strdup(optarg); break; case 'h': - param.pg_host = strdup(optarg); + param.pg_host = pg_strdup(optarg); break; } } diff --git a/doc/bug.template b/doc/bug.template index 5534772196..8e7401e1ce 100644 --- a/doc/bug.template +++ b/doc/bug.template @@ -27,7 +27,7 @@ System Configuration: Operating System (example: Linux 2.4.18) : - PostgreSQL version (example: PostgreSQL 9.6beta4): PostgreSQL 9.6beta4 + PostgreSQL version (example: PostgreSQL 10devel): PostgreSQL 10devel Compiler used (example: gcc 3.3.5) : diff --git a/doc/src/sgml/Makefile b/doc/src/sgml/Makefile index 24b895f3c3..fe7ca65cd4 100644 --- a/doc/src/sgml/Makefile +++ b/doc/src/sgml/Makefile @@ -106,9 +106,9 @@ draft: postgres.sgml $(ALMOSTALLSGML) stylesheet.dsl $(JADE.html.call) -V draft-mode $< cp $(srcdir)/stylesheet.css html/ -html: html-stamp +oldhtml: oldhtml-stamp -html-stamp: postgres.sgml $(ALLSGML) stylesheet.dsl +oldhtml-stamp: postgres.sgml $(ALLSGML) stylesheet.dsl $(MAKE) check-tabs $(MKDIR_P) html $(JADE.html.call) -i include-index $< @@ -258,9 +258,9 @@ ifeq ($(STYLE),website) XSLTPROC_HTML_FLAGS += --param website.stylesheet 1 endif -xslthtml: xslthtml-stamp +html: html-stamp -xslthtml-stamp: stylesheet.xsl postgres.xml +html-stamp: stylesheet.xsl postgres.xml $(XMLLINT) --noout --valid postgres.xml $(XSLTPROC) $(XSLTPROCFLAGS) $(XSLTPROC_HTML_FLAGS) $^ cp $(srcdir)/stylesheet.css html/ @@ -270,20 +270,16 @@ htmlhelp: stylesheet-hh.xsl postgres.xml $(XMLLINT) --noout --valid postgres.xml $(XSLTPROC) $(XSLTPROCFLAGS) $^ -%-A4.fo.tmp: stylesheet-fo.xsl %.xml +%-A4.fo: stylesheet-fo.xsl %.xml $(XMLLINT) --noout --valid $*.xml $(XSLTPROC) $(XSLTPROCFLAGS) --stringparam paper.type A4 -o $@ $^ -%-US.fo.tmp: stylesheet-fo.xsl %.xml +%-US.fo: stylesheet-fo.xsl %.xml $(XMLLINT) --noout --valid $*.xml $(XSLTPROC) $(XSLTPROCFLAGS) --stringparam paper.type USletter -o $@ $^ FOP = fop -# reformat FO output so that locations of errors are easier to find -%.fo: %.fo.tmp - $(XMLLINT) --format --output $@ $^ - .SECONDARY: postgres-A4.fo postgres-US.fo %-fop.pdf: %.fo @@ -326,11 +322,7 @@ check: postgres.sgml $(ALMOSTALLSGML) check-tabs ## Install ## -install: install-html - -ifneq ($(PORTNAME), sco) -install: install-man -endif +install: install-html install-man installdirs: $(MKDIR_P) '$(DESTDIR)$(htmldir)'/html $(addprefix '$(DESTDIR)$(mandir)'/man, 1 3 $(sqlmansectnum)) @@ -408,7 +400,7 @@ clean: # index rm -f HTML.index $(GENERATED_SGML) # XSLT - rm -f postgres.xml postgres.xmltmp htmlhelp.hhp toc.hhc index.hhk *.fo *.fo.tmp + rm -f postgres.xml postgres.xmltmp htmlhelp.hhp toc.hhc index.hhk *.fo # EPUB rm -f postgres.epub # Texinfo diff --git a/doc/src/sgml/acronyms.sgml b/doc/src/sgml/acronyms.sgml index 38f111ef9d..bf2273fa8a 100644 --- a/doc/src/sgml/acronyms.sgml +++ b/doc/src/sgml/acronyms.sgml @@ -380,6 +380,16 @@ + + LSN + + + Log Sequence Number, see pg_lsn + and WAL Internals. + + + + MSVC diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml index 0f09d82d65..d7df91090d 100644 --- a/doc/src/sgml/backup.sgml +++ b/doc/src/sgml/backup.sgml @@ -472,7 +472,7 @@ tar -cf backup.tar /usr/local/pgsql/data At all times, PostgreSQL maintains a - write ahead log (WAL) in the pg_xlog/ + write ahead log (WAL) in the pg_wal/ subdirectory of the cluster's data directory. The log records every change made to the database's data files. This log exists primarily for crash-safety purposes: if the system crashes, the @@ -616,7 +616,7 @@ archive_command = 'copy "%p" "C:\\server\\archivedir\\%f"' # Windows %p and %f parameters have been replaced, the actual command executed might look like this: -test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_xlog/00000001000000A900000065 /mnt/server/archivedir/00000001000000A900000065 +test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/00000001000000A900000065 /mnt/server/archivedir/00000001000000A900000065 A similar command will be generated for each new file to be archived. @@ -668,9 +668,9 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_xlog/ fills, nothing further can be archived until the tape is swapped. You should ensure that any error condition or request to a human operator is reported appropriately so that the situation can be - resolved reasonably quickly. The pg_xlog/ directory will + resolved reasonably quickly. The pg_wal/ directory will continue to fill with WAL segment files until the situation is resolved. - (If the file system containing pg_xlog/ fills up, + (If the file system containing pg_wal/ fills up, PostgreSQL will do a PANIC shutdown. No committed transactions will be lost, but the database will remain offline until you free some space.) @@ -682,7 +682,7 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_xlog/ operation continues even if the archiving process falls a little behind. If archiving falls significantly behind, this will increase the amount of data that would be lost in the event of a disaster. It will also mean that - the pg_xlog/ directory will contain large numbers of + the pg_wal/ directory will contain large numbers of not-yet-archived segment files, which could eventually exceed available disk space. You are advised to monitor the archiving process to ensure that it is working as you intend. @@ -743,7 +743,7 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_xlog/ configuration file reload. If you wish to temporarily stop archiving, one way to do it is to set archive_command to the empty string (''). - This will cause WAL files to accumulate in pg_xlog/ until a + This will cause WAL files to accumulate in pg_wal/ until a working archive_command is re-established. @@ -1062,10 +1062,10 @@ SELECT pg_stop_backup(); You should, however, omit from the backup the files within the - cluster's pg_xlog/ subdirectory. This + cluster's pg_wal/ subdirectory. This slight adjustment is worthwhile because it reduces the risk of mistakes when restoring. This is easy to arrange if - pg_xlog/ is a symbolic link pointing to someplace outside + pg_wal/ is a symbolic link pointing to someplace outside the cluster directory, which is a common setup anyway for performance reasons. You might also want to exclude postmaster.pid and postmaster.opts, which record information @@ -1089,6 +1089,22 @@ SELECT pg_stop_backup(); the new master comes on line. + + The contents of the directories pg_dynshmem/, + pg_notify/, pg_serial/, + pg_snapshots/, pg_stat_tmp/, + and pg_subtrans/ (but not the directories themselves) can be + omitted from the backup as they will be initialized on postmaster startup. + If is set and is under the data + directory then the contents of that directory can also be omitted. + + + + Any file or directory beginning with pgsql_tmp can be + omitted from the backup. These files are removed on postmaster start and + the directories will be recreated as needed. + + The backup label file includes the label string you gave to pg_start_backup, @@ -1133,7 +1149,7 @@ SELECT pg_stop_backup(); location in case you need them later. Note that this precaution will require that you have enough free space on your system to hold two copies of your existing database. If you do not have enough space, - you should at least save the contents of the cluster's pg_xlog + you should at least save the contents of the cluster's pg_wal subdirectory, as it might contain logs which were not archived before the system went down. @@ -1156,9 +1172,9 @@ SELECT pg_stop_backup(); - Remove any files present in pg_xlog/; these came from the + Remove any files present in pg_wal/; these came from the file system backup and are therefore probably obsolete rather than current. - If you didn't archive pg_xlog/ at all, then recreate + If you didn't archive pg_wal/ at all, then recreate it with proper permissions, being careful to ensure that you re-establish it as a symbolic link if you had it set up that way before. @@ -1167,7 +1183,7 @@ SELECT pg_stop_backup(); If you have unarchived WAL segment files that you saved in step 2, - copy them into pg_xlog/. (It is best to copy them, + copy them into pg_wal/. (It is best to copy them, not move them, so you still have the unmodified files if a problem occurs and you have to start over.) @@ -1249,9 +1265,9 @@ restore_command = 'cp /mnt/server/archivedir/%f %p' WAL segments that cannot be found in the archive will be sought in - pg_xlog/; this allows use of recent un-archived segments. + pg_wal/; this allows use of recent un-archived segments. However, segments that are available from the archive will be used in - preference to files in pg_xlog/. + preference to files in pg_wal/. @@ -1404,7 +1420,8 @@ restore_command = 'cp /mnt/server/archivedir/%f %p' If more flexibility in copying the backup files is needed, a lower level process can be used for standalone hot backups as well. - To prepare for low level standalone hot backups, set wal_level to + To prepare for low level standalone hot backups, make sure + wal_level is set to replica or higher, archive_mode to on, and set up an archive_command that performs archiving only when a switch file exists. For example: diff --git a/doc/src/sgml/btree-gist.sgml b/doc/src/sgml/btree-gist.sgml index e8a5622704..d08647ce05 100644 --- a/doc/src/sgml/btree-gist.sgml +++ b/doc/src/sgml/btree-gist.sgml @@ -16,7 +16,8 @@ time without time zone, date, interval, oid, money, char, varchar, text, bytea, bit, - varbit, macaddr, inet, and cidr. + varbit, macaddr, inet, cidr, + and uuid. @@ -99,8 +100,9 @@ INSERT 0 1 Teodor Sigaev (teodor@stack.net), - Oleg Bartunov (oleg@sai.msu.su), and - Janko Richter (jankorichter@yahoo.de). See + Oleg Bartunov (oleg@sai.msu.su), + Janko Richter (jankorichter@yahoo.de), and + Paul Jungwirth (pj@illuminatedcomputing.com). See for additional information. diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 4e09e06aed..524180e011 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -225,6 +225,11 @@ template data for procedural languages + + pg_partitioned_table + information about partition key of tables + + pg_policy row-security policies @@ -235,6 +240,16 @@ functions and procedures + + pg_publication + publications for logical replication + + + + pg_publication_rel + relation to publication mapping + + pg_range information about range types @@ -255,6 +270,11 @@ security labels on database objects + + pg_sequence + information about sequences + + pg_shdepend dependencies on shared objects @@ -275,6 +295,11 @@ planner statistics + + pg_subscription + logical replication subscriptions + + pg_tablespace tablespaces within this database cluster @@ -566,7 +591,7 @@ amhandler - oid + regproc pg_proc.oid OID of a handler function that is responsible for supplying information @@ -1541,7 +1566,8 @@ The catalog pg_class catalogs tables and most everything else that has columns or is otherwise similar to a table. This includes indexes (but see also - pg_index), sequences, views, materialized + pg_index), sequences (but see also + pg_sequence), views, materialized views, composite types, and TOAST tables; see relkind. Below, when we mean all of these kinds of objects we speak of relations. Not all @@ -1723,7 +1749,8 @@ char - r = ordinary table, i = index, + r = ordinary table, P = partitioned table, + i = index S = sequence, v = view, m = materialized view, c = composite type, t = TOAST table, @@ -1839,6 +1866,13 @@ + + relispartition + bool + + True if table is a partition + + relfrozenxid xid @@ -1885,6 +1919,16 @@ Access-method-specific options, as keyword=value strings + + + relpartbound + pg_node_tree + + + If table is a partition (see relispartition), + internal representation of the partition bound + + @@ -4689,6 +4733,110 @@ + + <structname>pg_partitioned_table</structname> + + + pg_partitioned_table + + + + The catalog pg_partitioned_table stores + information about how tables are partitioned. + + + + <structname>pg_partitioned_table</> Columns + + + + + Name + Type + References + Description + + + + + + + partrelid + oid + pg_class.oid + The OID of the pg_class entry for this partitioned table + + + + partstrat + char + + + Partitioning strategy; l = list partitioned table, + r = range partitioned table + + + + + partnatts + int2 + + The number of columns in partition key + + + + partattrs + int2vector + pg_attribute.attnum + + This is an array of partnatts values that + indicate which table columns are part of the partition key. For + example, a value of 1 3 would mean that the first + and the third table columns make up the partition key. A zero in this + array indicates that the corresponding partition key column is an + expression, rather than a simple column reference. + + + + + partclass + oidvector + pg_opclass.oid + + For each column in the partition key, this contains the OID of the + operator class to use. See + pg_opclass for details. + + + + + partcollation + oidvector + pg_opclass.oid + + For each column in the partition key, this contains the OID of the + the collation to use for partitioning. + + + + + partexprs + pg_node_tree + + + Expression trees (in nodeToString() + representation) for partition key columns that are not simple column + references. This is a list with one element for each zero + entry in partattrs. Null if all partition key columns + are simple references. + + + + + +
+
+ <structname>pg_policy</structname> @@ -4747,6 +4895,13 @@ or * for all
+ + polpermissive + boolean + + Is the policy permissive or restrictive? + + polroles oid[] @@ -5131,6 +5286,137 @@ + + <structname>pg_publication</structname> + + + pg_publication + + + + The catalog pg_publication contains all + publications created in the database. For more on publications see + . + + + + <structname>pg_publication</structname> Columns + + + + + Name + Type + References + Description + + + + + + oid + oid + + Row identifier (hidden attribute; must be explicitly selected) + + + + pubname + Name + + Name of the publication + + + + pubowner + oid + pg_authid.oid + Owner of the publication + + + + puballtables + bool + + If true, this publication automatically includes all tables + in the database, including any that will be created in the future. + + + + + pubinsert + bool + + If true, INSERT operations are replicated for + tables in the publication. + + + + pubupdate + bool + + If true, UPDATE operations are replicated for + tables in the publication. + + + + pubdelete + bool + + If true, DELETE operations are replicated for + tables in the publication. + + + +
+
+ + + <structname>pg_publication_rel</structname> + + + pg_publication_rel + + + + The catalog pg_publication_rel contains the + mapping between relations and publications in the database. This is a + many-to-many mapping. See also + for a more user-friendly view of this information. + + + + <structname>pg_publication_rel</structname> Columns + + + + + Name + Type + References + Description + + + + + + prpubid + oid + pg_publication.oid + Reference to publication + + + + prrelid + oid + pg_class.oid + Reference to relation + + + +
+
+ <structname>pg_range</structname> @@ -5453,6 +5739,86 @@ + + <structname>pg_sequence</structname> + + + pg_sequence + + + + The catalog pg_sequence contains information about + sequences. Some of the information about sequences, such as the name and + the schema, is in pg_class. + + + + <structname>pg_sequence</> Columns + + + + + Name + Type + References + Description + + + + + + seqrelid + oid + pg_class.oid + The OID of the pg_class entry for this sequence + + + + seqcycle + bool + + Whether the sequence cycles + + + + seqstart + int8 + + Start value of the sequence + + + + seqincrement + int8 + + Increment value of the sequence + + + + seqmax + int8 + + Maximum value of the sequence + + + + seqmin + int8 + + Minimum value of the sequence + + + + seqcache + int8 + + Cache size of the sequence + + + +
+
+ <structname>pg_shdepend</structname> @@ -5930,6 +6296,109 @@ + + <structname>pg_subscription</structname> + + + pg_subscription + + + + The catalog pg_subscription contains all existing + logical replication subscriptions. For more information about logical + replication see . + + + + Unlike most system catalogs, pg_subscription is + shared across all databases of a cluster: There is only one copy + of pg_subscription per cluster, not one per + database. + + + + Access to this catalog is restricted from normal users. Normal users can + use the view to get some information + about subscriptions. + + + + <structname>pg_subscription</structname> Columns + + + + + Name + Type + References + Description + + + + + + oid + oid + + Row identifier (hidden attribute; must be explicitly selected) + + + + subdbid + oid + pg_database.oid + OID of the database which the subscription resides in + + + + subname + name + + Name of the subscription + + + + subowner + oid + pg_authid.oid + Owner of the subscription + + + + subenabled + bool + + If true, the subscription is enabled and should be replicating. + + + + subconninfo + text + + Connection string to the upstream database + + + + subslotname + name + + Name of the replication slot in the upstream database. Also used + for local replication origin name. + + + + subpublications + text[] + + Array of subscribed publication names. These reference the + publications on the publisher server. For more on publications + see . + + + + +
+
<structname>pg_tablespace</structname> @@ -6231,6 +6700,22 @@ representation) for the trigger's WHEN condition, or null if none
+ + + tgoldtable + name + + REFERENCING clause name for OLD TABLE, + or null if none + + + + tgnewtable + name + + REFERENCING clause name for NEW TABLE, + or null if none + @@ -7353,6 +7838,11 @@ prepared transactions + + pg_publication_tables + publications and their associated tables + + pg_replication_origin_status information about replication origins, including replication progress @@ -7378,6 +7868,11 @@ security labels + + pg_sequences + sequences + + pg_settings parameter settings @@ -7596,6 +8091,11 @@ application.
+ + By default, the pg_config view can be read + only by superusers. + + <structname>pg_config</> Columns @@ -7771,8 +8271,8 @@ - The pg_file_settings view can be read only by - superusers. + By default, the pg_file_settings view can be read + only by superusers.
@@ -8411,6 +8911,12 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx pg_policy.polnameName of policy + + polpermissive + text + + Is the policy permissive or restrictive? + roles name[] @@ -8619,6 +9125,61 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx + + <structname>pg_publication_tables</structname> + + + pg_publication_tables + + + + The view pg_publication_tables provides + information about the mapping between publications and the tables they + contain. Unlike the underlying + catalog pg_publication_rel, this view expands + publications defined as FOR ALL TABLES, so for such + publications there will be a row for each eligible table. + + +
+ <structname>pg_publication_tables</structname> Columns + + + + + Name + Type + References + Description + + + + + + pubname + name + pg_publication.pubname + Name of publication + + + + schemaname + name + pg_namespace.nspname + Name of schema containing table + + + + tablename + name + pg_class.relname + Name of table + + + +
+ + <structname>pg_replication_origin_status</structname> @@ -8754,6 +9315,15 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx null. Only logical slots have an associated database. + + temporary + boolean + + True if this is temporary replication slot. Temporary slots are + not saved to disk and are automatically dropped on error or when + the session has finished. + + active boolean @@ -9114,6 +9684,98 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx + + <structname>pg_sequences</structname> + + + pg_sequences + + + + The view pg_sequences provides access to + useful information about each sequence in the database. + + + + <structname>pg_sequences</> Columns + + + + + Name + Type + References + Description + + + + + schemaname + name + pg_namespace.nspname + Name of schema containing sequence + + + sequencename + name + pg_class.relname + Name of sequence + + + sequenceowner + name + pg_authid.rolname + Name of sequence's owner + + + start_value + bigint + + Start value of the sequence + + + min_value + bigint + + Minimum value of the sequence + + + max_value + bigint + + Maximum value of the sequence + + + increment_by + bigint + + Increment value of the sequence + + + cycle + boolean + + Whether the sequence cycles + + + cache_size + bigint + + Cache size of the sequence + + + last_value + bigint + + The last sequence value written to disk. If caching is used, + this value can be greater than the last value handed out from the + sequence. Null if the sequence has not been read from yet. + + + +
+
+ <structname>pg_settings</structname> @@ -9811,6 +10473,13 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx + + While most timezone abbreviations represent fixed offsets from UTC, + there are some that have historically varied in value + (see for more information). + In such cases this view presents their current meaning. + + diff --git a/doc/src/sgml/charset.sgml b/doc/src/sgml/charset.sgml index f8c7ac3b16..2aba0fc528 100644 --- a/doc/src/sgml/charset.sgml +++ b/doc/src/sgml/charset.sgml @@ -496,7 +496,7 @@ SELECT * FROM test1 ORDER BY a || b COLLATE "fr_FR";
- + Managing Collations diff --git a/doc/src/sgml/citext.sgml b/doc/src/sgml/citext.sgml index 7fdf30252a..9b4c68f7d4 100644 --- a/doc/src/sgml/citext.sgml +++ b/doc/src/sgml/citext.sgml @@ -124,6 +124,11 @@ SELECT * FROM users WHERE nick = 'Larry'; + + + regexp_match() + + regexp_matches() diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml index ca262d9452..dda5891900 100644 --- a/doc/src/sgml/client-auth.sgml +++ b/doc/src/sgml/client-auth.sgml @@ -156,9 +156,11 @@ hostnossl database user To make use of this option the server must be built with SSL support. Furthermore, - SSL must be enabled at server start time + SSL must be enabled by setting the configuration parameter (see for more information). + Otherwise, the hostssl record is ignored except for + logging a warning that it cannot match any connections.
@@ -711,7 +713,7 @@ local db1,db2,@demodbs all md5 When using an external authentication system such as Ident or GSSAPI, the name of the operating system user that initiated the connection - might not be the same as the database user that is to be connect as. + might not be the same as the database user (role) that is to be used. In this case, a user name map can be applied to map the operating system user name to a database user. To use user name mapping, specify map=map-name @@ -1306,7 +1308,7 @@ omicron bryanh guest1 socket parameter, or similar mechanisms. Currently that includes Linux, most flavors of BSD including - OS X, + macOS, and Solaris. diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 02f917b375..fb5d6473ef 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -958,10 +958,10 @@ include_dir 'conf.d' Enables SSL connections. Please read - before using this. The default - is off. This parameter can only be set at server - start. SSL communication is only possible with - TCP/IP connections. + before using this. + This parameter can only be set in the postgresql.conf + file or on the server command line. + The default is off. @@ -975,11 +975,16 @@ include_dir 'conf.d' Specifies the name of the file containing the SSL server certificate - authority (CA). The default is empty, meaning no CA file is loaded, - and client certificate verification is not performed. (In previous - releases of PostgreSQL, the name of this file was hard-coded - as root.crt.) Relative paths are relative to the - data directory. This parameter can only be set at server start. + authority (CA). + Relative paths are relative to the data directory. + This parameter can only be set in the postgresql.conf + file or on the server command line. + The default is empty, meaning no CA file is loaded, + and client certificate verification is not performed. + + + In previous releases of PostgreSQL, the name of this file was + hard-coded as root.crt. @@ -993,9 +998,10 @@ include_dir 'conf.d' Specifies the name of the file containing the SSL server certificate. - The default is server.crt. Relative paths are - relative to the data directory. This parameter can only be set at - server start. + Relative paths are relative to the data directory. + This parameter can only be set in the postgresql.conf + file or on the server command line. + The default is server.crt. @@ -1009,11 +1015,15 @@ include_dir 'conf.d' Specifies the name of the file containing the SSL server certificate - revocation list (CRL). The default is empty, meaning no CRL file is - loaded. (In previous releases of PostgreSQL, the name of this file was - hard-coded as root.crl.) Relative paths are - relative to the data directory. This parameter can only be set at - server start. + revocation list (CRL). + Relative paths are relative to the data directory. + This parameter can only be set in the postgresql.conf + file or on the server command line. + The default is empty, meaning no CRL file is loaded. + + + In previous releases of PostgreSQL, the name of this file was + hard-coded as root.crl. @@ -1027,9 +1037,10 @@ include_dir 'conf.d' Specifies the name of the file containing the SSL server private key. - The default is server.key. Relative paths are - relative to the data directory. This parameter can only be set at - server start. + Relative paths are relative to the data directory. + This parameter can only be set in the postgresql.conf + file or on the server command line. + The default is server.key. @@ -1046,9 +1057,12 @@ include_dir 'conf.d' used on secure connections. See the ciphers manual page in the OpenSSL package for the syntax of this setting - and a list of supported values. The default value is - HIGH:MEDIUM:+3DES:!aNULL. It is usually reasonable, - unless you have specific security requirements. + and a list of supported values. + This parameter can only be set in the postgresql.conf + file or on the server command line. + The default value is HIGH:MEDIUM:+3DES:!aNULL. The + default is usually a reasonable choice unless you have specific + security requirements. @@ -1112,7 +1126,7 @@ include_dir 'conf.d' - ssl_prefer_server_ciphers (bool) + ssl_prefer_server_ciphers (boolean) ssl_prefer_server_ciphers configuration parameter @@ -1120,7 +1134,10 @@ include_dir 'conf.d' Specifies whether to use the server's SSL cipher preferences, rather - than the client's. The default is true. + than the client's. + This parameter can only be set in the postgresql.conf + file or on the server command line. + The default is true. @@ -1143,18 +1160,18 @@ include_dir 'conf.d' Specifies the name of the curve to use in ECDH key exchange. It needs to be supported by all clients that connect. - It does not need to be same curve as used by server's Elliptic - Curve key. The default is prime256v1. + It does not need to be the same curve used by the server's Elliptic + Curve key. + This parameter can only be set in the postgresql.conf + file or on the server command line. + The default is prime256v1. - OpenSSL names for most common curves: + OpenSSL names for the most common curves are: prime256v1 (NIST P-256), secp384r1 (NIST P-384), secp521r1 (NIST P-521). - - - The full list of available curves can be shown with the command openssl ecparam -list_curves. Not all of them are usable in TLS though. @@ -1163,21 +1180,22 @@ include_dir 'conf.d' - password_encryption (boolean) + password_encryption (enum) password_encryption configuration parameter - When a password is specified in or - - without writing either ENCRYPTED or - UNENCRYPTED, this parameter determines whether the - password is to be encrypted. The default is on - (encrypt the password). + When a password is specified in or + without writing either ENCRYPTED + or UNENCRYPTED, this parameter determines whether the + password is to be encrypted. The default value is md5, which + stores the password as an MD5 hash. Setting this to plain stores + it in plaintext. on and off are also accepted, as + aliases for md5 and plain, respectively. + @@ -1227,8 +1245,8 @@ include_dir 'conf.d' - If this is on, you should create users as username@dbname. - When username is passed by a connecting client, + If this is on, you should create users as username@dbname. + When username is passed by a connecting client, @ and the database name are appended to the user name and that database-specific user name is looked up by the server. Note that when you create users with names containing @@ -1298,7 +1316,7 @@ include_dir 'conf.d' If you have a dedicated database server with 1GB or more of RAM, a reasonable starting value for shared_buffers is 25% of the memory in your system. There are some workloads where even - large settings for shared_buffers are effective, but + larger settings for shared_buffers are effective, but because PostgreSQL also relies on the operating system cache, it is unlikely that an allocation of more than 40% of RAM to shared_buffers will work better than a @@ -1312,11 +1330,6 @@ include_dir 'conf.d' On systems with less than 1GB of RAM, a smaller percentage of RAM is appropriate, so as to leave adequate space for the operating system. - Also, on Windows, large values for shared_buffers - aren't as effective. You may find better results keeping the setting - relatively low and using the operating system cache more instead. The - useful range for shared_buffers on Windows systems - is generally from 64MB to 512MB. @@ -1902,10 +1915,10 @@ include_dir 'conf.d' , but smaller than the OS's page cache, where performance might degrade. This setting may have no effect on some platforms. The valid range is between - 0, which disables controlled writeback, and + 0, which disables forced writeback, and 2MB. The default is 512kB on Linux, - 0 elsewhere. (Non-default values of - BLCKSZ change the default and maximum.) + 0 elsewhere. (If BLCKSZ is not 8kB, + the default and maximum values scale proportionally to it.) This parameter can only be set in the postgresql.conf file or on the server command line. @@ -1991,6 +2004,12 @@ include_dir 'conf.d' same or higher value than on the master server. Otherwise, queries will not be allowed in the standby server. + + + When changing this value, consider also adjusting + and + . + @@ -2005,8 +2024,9 @@ include_dir 'conf.d' Sets the maximum number of workers that can be started by a single Gather node. Parallel workers are taken from the pool of processes established by - . Note that the requested - number of workers may not actually be available at run time. If this + , limited by + . Note that the requested + number of workers may not actually be available at runtime. If this occurs, the plan will run with fewer workers than expected, which may be inefficient. The default value is 2. Setting this value to 0 disables parallel query execution. @@ -2027,6 +2047,31 @@ include_dir 'conf.d' as much CPU time, memory, I/O bandwidth, and so forth as a query which uses no workers at all. + + + For more information on parallel query, see + . + + + + + + max_parallel_workers (integer) + + max_parallel_workers configuration parameter + + + + + Sets the maximum number of workers that the system can support for + parallel queries. The default value is 8. When increasing or + decreasing this value, consider also adjusting + . + Also, note that a setting for this value which is higher than + will have no effect, + since parallel workers are taken from the pool of worker processes + established by that setting. + @@ -2049,10 +2094,10 @@ include_dir 'conf.d' that are bigger than , but smaller than the OS's page cache, where performance might degrade. This setting may have no effect on some platforms. The valid range is - between 0, which disables controlled writeback, - and 2MB. The default is 0 (i.e. no - flush control). (Non-default values of BLCKSZ - change the maximum.) + between 0, which disables forced writeback, + and 2MB. The default is 0, i.e., no + forced writeback. (If BLCKSZ is not 8kB, + the maximum value scales proportionally to it.) @@ -2138,12 +2183,12 @@ include_dir 'conf.d' - wal_level determines how much information is written - to the WAL. The default value is minimal, which writes - only the information needed to recover from a crash or immediate - shutdown. replica adds logging required for WAL - archiving as well as information required to run - read-only queries on a standby server. Finally, + wal_level determines how much information is written to + the WAL. The default value is replica, which writes enough + data to support WAL archiving and replication, including running + read-only queries on a standby server. minimal removes all + logging except the information required to recover from a crash or + immediate shutdown. Finally, logical adds information necessary to support logical decoding. Each level includes the information logged at all lower levels. This parameter can only be set at server start. @@ -2512,10 +2557,11 @@ include_dir 'conf.d' Specifies how often the WAL writer flushes WAL. After flushing WAL it sleeps for wal_writer_delay milliseconds, unless woken up - by an asynchronously committing transaction. In case the last flush + by an asynchronously committing transaction. If the last flush happened less than wal_writer_delay milliseconds ago and less than wal_writer_flush_after bytes of WAL have been - produced since, WAL is only written to the OS, not flushed to disk. + produced since, then WAL is only written to the operating system, not + flushed to disk. The default value is 200 milliseconds (200ms). Note that on many systems, the effective resolution of sleep delays is 10 milliseconds; setting wal_writer_delay to a value that is @@ -2534,12 +2580,12 @@ include_dir 'conf.d' - Specifies how often the WAL writer flushes WAL. In case the last flush + Specifies how often the WAL writer flushes WAL. If the last flush happened less than wal_writer_delay milliseconds ago and less than wal_writer_flush_after bytes of WAL have been - produced since, WAL is only written to the OS, not flushed to disk. - If wal_writer_flush_after is set to 0 WAL is - flushed every time the WAL writer has written WAL. The default is + produced since, then WAL is only written to the operating system, not + flushed to disk. If wal_writer_flush_after is set + to 0 then WAL data is flushed immediately. The default is 1MB. This parameter can only be set in the postgresql.conf file or on the server command line. @@ -2614,7 +2660,7 @@ include_dir 'conf.d' Maximum time between automatic WAL checkpoints, in seconds. - The valid range is between 30 seconds and one hour. + The valid range is between 30 seconds and one day. The default is five minutes (5min). Increasing this parameter can increase the amount of time needed for crash recovery. @@ -2659,10 +2705,10 @@ include_dir 'conf.d' that are bigger than , but smaller than the OS's page cache, where performance might degrade. This setting may have no effect on some platforms. The valid range is - between 0, which disables controlled writeback, + between 0, which disables forced writeback, and 2MB. The default is 256kB on - Linux, 0 elsewhere. (Non-default values of - BLCKSZ change the default and maximum.) + Linux, 0 elsewhere. (If BLCKSZ is not + 8kB, the default and maximum values scale proportionally to it.) This parameter can only be set in the postgresql.conf file or on the server command line. @@ -2820,12 +2866,10 @@ include_dir 'conf.d' parameter is greater than zero, the server will switch to a new segment file whenever this many seconds have elapsed since the last segment file switch, and there has been any database activity, - including a single checkpoint. (Increasing - checkpoint_timeout will reduce unnecessary - checkpoints on an idle system.) - Note that archived files that are closed early - due to a forced switch are still the same length as completely full - files. Therefore, it is unwise to use a very short + including a single checkpoint (checkpoints are skipped if there is + no database activity). Note that archived files that are closed + early due to a forced switch are still the same length as completely + full files. Therefore, it is unwise to use a very short archive_timeout — it will bloat your archive storage. archive_timeout settings of a minute or so are usually reasonable. You should consider using streaming replication, @@ -2882,7 +2926,7 @@ include_dir 'conf.d' Specifies the maximum number of concurrent connections from standby servers or streaming base backup clients (i.e., the maximum number of simultaneously running WAL sender - processes). The default is zero, meaning replication is + processes). The default is 10. The value 0 means replication is disabled. WAL sender processes count towards the total number of connections, so the parameter cannot be set higher than . Abrupt streaming client @@ -2907,7 +2951,7 @@ include_dir 'conf.d' Specifies the maximum number of replication slots (see ) that the server - can support. The default is zero. This parameter can only be set at + can support. The default is 10. This parameter can only be set at server start. wal_level must be set to replica or higher to allow replication slots to @@ -2926,7 +2970,7 @@ include_dir 'conf.d' Specifies the minimum number of past log file segments kept in the - pg_xlog + pg_wal directory, in case a standby server needs to fetch them for streaming replication. Each segment is normally 16 megabytes. If a standby server connected to the sending server falls behind by more than @@ -2940,7 +2984,7 @@ include_dir 'conf.d' This sets only the minimum number of segments retained in - pg_xlog; the system might need to retain more segments + pg_wal; the system might need to retain more segments for WAL archival or to recover from a checkpoint. If wal_keep_segments is zero (the default), the system doesn't keep any extra segments for standby purposes, so the number @@ -2973,7 +3017,7 @@ include_dir 'conf.d' - track_commit_timestamp (bool) + track_commit_timestamp (boolean) track_commit_timestamp configuration parameter @@ -3022,41 +3066,71 @@ include_dir 'conf.d' transactions waiting for commit will be allowed to proceed after these standby servers confirm receipt of their data. The synchronous standbys will be those whose names appear - earlier in this list, and + in this list, and that are both currently connected and streaming data in real-time (as shown by a state of streaming in the pg_stat_replication view). - Other standby servers appearing later in this list represent potential - synchronous standbys. If any of the current synchronous - standbys disconnects for whatever reason, - it will be replaced immediately with the next-highest-priority standby. - Specifying more than one standby name can allow very high availability. + Specifying more than one standby names can allow very high availability. This parameter specifies a list of standby servers using either of the following syntaxes: -num_sync ( standby_name [, ...] ) +[FIRST] num_sync ( standby_name [, ...] ) +ANY num_sync ( standby_name [, ...] ) standby_name [, ...] where num_sync is the number of synchronous standbys that transactions need to wait for replies from, and standby_name - is the name of a standby server. For example, a setting of - 3 (s1, s2, s3, s4) makes transaction commits wait - until their WAL records are received by three higher-priority standbys - chosen from standby servers s1, s2, - s3 and s4. - - - The second syntax was used before PostgreSQL + is the name of a standby server. + FIRST and ANY specify the method to choose + synchronous standbys from the listed servers. + + + The keyword FIRST, coupled with + num_sync, specifies a + priority-based synchronous replication and makes transaction commits + wait until their WAL records are replicated to + num_sync synchronous + standbys chosen based on their priorities. For example, a setting of + FIRST 3 (s1, s2, s3, s4) will cause each commit to wait for + replies from three higher-priority standbys chosen from standby servers + s1, s2, s3 and s4. + The standbys whose names appear earlier in the list are given higher + priority and will be considered as synchronous. Other standby servers + appearing later in this list represent potential synchronous standbys. + If any of the current synchronous standbys disconnects for whatever + reason, it will be replaced immediately with the next-highest-priority + standby. The keyword FIRST is optional. + + + The keyword ANY, coupled with + num_sync, specifies a + quorum-based synchronous replication and makes transaction commits + wait until their WAL records are replicated to at least + num_sync listed standbys. + For example, a setting of ANY 3 (s1, s2, s3, s4) will cause + each commit to proceed as soon as at least any three standbys of + s1, s2, s3 and s4 + reply. + + + FIRST and ANY are case-insensitive. If these + keywords are used as the name of a standby server, + its standby_name must + be double-quoted. + + + The third syntax was used before PostgreSQL version 9.6 and is still supported. It's the same as the first syntax - with num_sync equal to 1. - For example, 1 (s1, s2) and - s1, s2 have the same meaning: either s1 - or s2 is chosen as a synchronous standby. + with FIRST and + num_sync equal to 1. + For example, FIRST 1 (s1, s2) and s1, s2 have + the same meaning: either s1 or s2 is chosen + as a synchronous standby. The name of a standby server for this purpose is the @@ -3316,7 +3390,7 @@ include_dir 'conf.d' Specify how long the standby server should wait when WAL data is not available from any sources (streaming replication, - local pg_xlog or WAL archive) before retrying to + local pg_wal or WAL archive) before retrying to retrieve WAL data. This parameter can only be set in the postgresql.conf file or on the server command line. The default value is 5 seconds. Units are milliseconds if not specified. @@ -3337,6 +3411,47 @@ include_dir 'conf.d' + + + Subscribers + + + These settings control the behavior of a logical replication subscriber. + Their values on the publisher are irrelevant. + + + + Note that wal_receiver_timeout and + wal_retrieve_retry_interval configuration parameters + affect the logical replication workers as well. + + + + + + max_logical_replication_workers (int) + + max_logical_replication_workers configuration parameter + + + + + Specifies maximum number of logical replication workers. This includes + both apply workers and table synchronization workers. + + + Logical replication workers are taken from the pool defined by + max_worker_processes. + + + The default value is 4. + + + + + + + @@ -4998,7 +5113,8 @@ local0.* /var/log/postgresql value will pad on the left. Padding can be useful to aid human readability in log files. This parameter can only be set in the postgresql.conf - file or on the server command line. The default is an empty string. + file or on the server command line. The default is + '%m [%p] ' which logs a time stamp and the process ID. @@ -5136,6 +5252,17 @@ FROM pg_stat_activity; include those escapes if you are logging to syslog. + + + + The %q escape is useful when including information that is + only available in session (backend) context like user or database + name. For example: + +log_line_prefix = '%m [%p] %q%u@%d/%a ' + + + @@ -5388,9 +5515,10 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv; Process Title - These settings control how the process title as seen - by ps is modified. See - for details. + These settings control how process titles of server processes are + modified. Process titles are typically viewed using programs like + ps or, on Windows, Process Explorer. + See for details. @@ -5403,18 +5531,14 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv; Sets the cluster name that appears in the process title for all - processes in this cluster. The name can be any string of less than - NAMEDATALEN characters (64 characters in a standard + server processes in this cluster. The name can be any string of less + than NAMEDATALEN characters (64 characters in a standard build). Only printable ASCII characters may be used in the cluster_name value. Other characters will be replaced with question marks (?). No name is shown if this parameter is set to the empty string '' (which is the default). This parameter can only be set at server start. - - The process title is typically viewed using programs like - ps or, on Windows, Process Explorer. - @@ -5427,9 +5551,10 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv; Enables updating of the process title every time a new SQL command - is received by the server. The process title is typically viewed - by the ps command, - or in Windows by using the Process Explorer. + is received by the server. + This setting defaults to on on most platforms, but it + defaults to off on Windows due to that platform's larger + overhead for updating the process title. Only superusers can change this setting. @@ -7324,36 +7449,6 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir' - - sql_inheritance (boolean) - - sql_inheritance configuration parameter - - inheritance - - - - This setting controls whether undecorated table references are - considered to include inheritance child tables. The default is - on, which means child tables are included (thus, - a * suffix is assumed by default). If turned - off, child tables are not included (thus, an - ONLY prefix is assumed). The SQL standard - requires child tables to be included, so the off setting - is not spec-compliant, but it is provided for compatibility with - PostgreSQL releases prior to 7.1. - See for more information. - - - - Turning sql_inheritance off is deprecated, because that - behavior has been found to be error-prone as well as contrary to SQL - standard. Discussions of inheritance behavior elsewhere in this - manual generally assume that it is on. - - - - standard_conforming_strings (boolean) stringsstandard conforming diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index 67d0c349e0..3bc6854be6 100644 --- a/doc/src/sgml/datatype.sgml +++ b/doc/src/sgml/datatype.sgml @@ -1651,13 +1651,14 @@ SELECT E'\\xDEADBEEF'; When timestamp values are stored as eight-byte integers (currently the default), microsecond precision is available over - the full range of values. When timestamp values are - stored as double precision floating-point numbers instead (a - deprecated compile-time option), the effective limit of precision - might be less than 6. timestamp values are stored as - seconds before or after midnight 2000-01-01. When - timestamp values are implemented using floating-point - numbers, microsecond precision is achieved for dates within a few + the full range of values. In this case, the internal representation + is the number of microseconds before or after midnight 2000-01-01. + When timestamp values are stored as double precision + floating-point numbers (a deprecated compile-time option), the + internal representation is the number of seconds before or after + midnight 2000-01-01. With this representation, the effective limit + of precision might be less than 6; in practice, + microsecond precision is achieved for dates within a few years of 2000-01-01, but the precision degrades for dates further away. Note that using floating-point datetimes allows a larger range of timestamp values to be represented than @@ -3959,15 +3960,7 @@ SELECT 'fat & rat & ! cat'::tsquery; tsquery ------------------------ 'fat' & 'rat' & !'cat' - -SELECT '(fat | rat) <-> cat'::tsquery; - tsquery ------------------------------------ - 'fat' <-> 'cat' | 'rat' <-> 'cat' - - The last example demonstrates that tsquery sometimes - rearranges nested operators into a logically equivalent formulation. diff --git a/doc/src/sgml/datetime.sgml b/doc/src/sgml/datetime.sgml index ffd0715128..ef9139f9e3 100644 --- a/doc/src/sgml/datetime.sgml +++ b/doc/src/sgml/datetime.sgml @@ -384,19 +384,38 @@ A zone_abbreviation is just the abbreviation - being defined. The offset is the equivalent - offset in seconds from UTC, positive being east from Greenwich and - negative being west. For example, -18000 would be five hours west - of Greenwich, or North American east coast standard time. D - indicates that the zone name represents local daylight-savings time rather - than standard time. Alternatively, a time_zone_name can - be given, in which case that time zone definition is consulted, and the - abbreviation's meaning in that zone is used. This alternative is - recommended only for abbreviations whose meaning has historically varied, - as looking up the meaning is noticeably more expensive than just using - a fixed integer value. + being defined. An offset is an integer giving + the equivalent offset in seconds from UTC, positive being east from + Greenwich and negative being west. For example, -18000 would be five + hours west of Greenwich, or North American east coast standard time. + D indicates that the zone name represents local + daylight-savings time rather than standard time. + + Alternatively, a time_zone_name can be given, referencing + a zone name defined in the IANA timezone database. The zone's definition + is consulted to see whether the abbreviation is or has been in use in + that zone, and if so, the appropriate meaning is used — that is, + the meaning that was currently in use at the timestamp whose value is + being determined, or the meaning in use immediately before that if it + wasn't current at that time, or the oldest meaning if it was used only + after that time. This behavior is essential for dealing with + abbreviations whose meaning has historically varied. It is also allowed + to define an abbreviation in terms of a zone name in which that + abbreviation does not appear; then using the abbreviation is just + equivalent to writing out the zone name. + + + + + Using a simple integer offset is preferred + when defining an abbreviation whose offset from UTC has never changed, + as such abbreviations are much cheaper to process than those that + require consulting a time zone definition. + + + The @INCLUDE syntax allows inclusion of another file in the .../share/timezonesets/ directory. Inclusion can be nested, diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml index a393813b38..d7117cbc8f 100644 --- a/doc/src/sgml/ddl.sgml +++ b/doc/src/sgml/ddl.sgml @@ -1599,9 +1599,11 @@ REVOKE ALL ON accounts FROM PUBLIC; When multiple policies apply to a given query, they are combined using - OR, so that a row is accessible if any policy allows - it. This is similar to the rule that a given role has the privileges - of all roles that they are a member of. + either OR (for permissive policies, which are the + default) or using AND (for restrictive policies). + This is similar to the rule that a given role has the privileges + of all roles that they are a member of. Permissive vs. restrictive + policies are discussed further below. @@ -1629,7 +1631,7 @@ CREATE POLICY account_managers ON accounts TO managers CREATE POLICY user_policy ON users - USING (user = current_user); + USING (user_name = current_user); @@ -1642,7 +1644,7 @@ CREATE POLICY user_policy ON users CREATE POLICY user_policy ON users USING (true) - WITH CHECK (user = current_user); + WITH CHECK (user_name = current_user); @@ -1662,7 +1664,7 @@ CREATE POLICY user_policy ON users -- Simple passwd-file based example CREATE TABLE passwd ( - username text UNIQUE NOT NULL, + user_name text UNIQUE NOT NULL, pwhash text, uid int PRIMARY KEY, gid int NOT NULL, @@ -1696,9 +1698,9 @@ CREATE POLICY all_view ON passwd FOR SELECT USING (true); -- Normal users can update their own records, but -- limit which shells a normal user is allowed to set CREATE POLICY user_mod ON passwd FOR UPDATE - USING (current_user = username) + USING (current_user = user_name) WITH CHECK ( - current_user = username AND + current_user = user_name AND shell IN ('/bin/bash','/bin/sh','/bin/dash','/bin/zsh','/bin/tcsh') ); @@ -1706,7 +1708,7 @@ CREATE POLICY user_mod ON passwd FOR UPDATE GRANT SELECT, INSERT, UPDATE, DELETE ON passwd TO admin; -- Users only get select access on public columns GRANT SELECT - (username, uid, gid, real_name, home_phone, extra_info, home_dir, shell) + (user_name, uid, gid, real_name, home_phone, extra_info, home_dir, shell) ON passwd TO public; -- Allow users to update certain columns GRANT UPDATE @@ -1725,11 +1727,11 @@ GRANT UPDATE postgres=> set role admin; SET postgres=> table passwd; - username | pwhash | uid | gid | real_name | home_phone | extra_info | home_dir | shell -----------+--------+-----+-----+-----------+--------------+------------+-------------+----------- - admin | xxx | 0 | 0 | Admin | 111-222-3333 | | /root | /bin/dash - bob | xxx | 1 | 1 | Bob | 123-456-7890 | | /home/bob | /bin/zsh - alice | xxx | 2 | 1 | Alice | 098-765-4321 | | /home/alice | /bin/zsh + user_name | pwhash | uid | gid | real_name | home_phone | extra_info | home_dir | shell +-----------+--------+-----+-----+-----------+--------------+------------+-------------+----------- + admin | xxx | 0 | 0 | Admin | 111-222-3333 | | /root | /bin/dash + bob | xxx | 1 | 1 | Bob | 123-456-7890 | | /home/bob | /bin/zsh + alice | xxx | 2 | 1 | Alice | 098-765-4321 | | /home/alice | /bin/zsh (3 rows) -- Test what Alice is able to do @@ -1737,30 +1739,80 @@ postgres=> set role alice; SET postgres=> table passwd; ERROR: permission denied for relation passwd -postgres=> select username,real_name,home_phone,extra_info,home_dir,shell from passwd; - username | real_name | home_phone | extra_info | home_dir | shell -----------+-----------+--------------+------------+-------------+----------- - admin | Admin | 111-222-3333 | | /root | /bin/dash - bob | Bob | 123-456-7890 | | /home/bob | /bin/zsh - alice | Alice | 098-765-4321 | | /home/alice | /bin/zsh +postgres=> select user_name,real_name,home_phone,extra_info,home_dir,shell from passwd; + user_name | real_name | home_phone | extra_info | home_dir | shell +-----------+-----------+--------------+------------+-------------+----------- + admin | Admin | 111-222-3333 | | /root | /bin/dash + bob | Bob | 123-456-7890 | | /home/bob | /bin/zsh + alice | Alice | 098-765-4321 | | /home/alice | /bin/zsh (3 rows) -postgres=> update passwd set username = 'joe'; +postgres=> update passwd set user_name = 'joe'; ERROR: permission denied for relation passwd -- Alice is allowed to change her own real_name, but no others postgres=> update passwd set real_name = 'Alice Doe'; UPDATE 1 -postgres=> update passwd set real_name = 'John Doe' where username = 'admin'; +postgres=> update passwd set real_name = 'John Doe' where user_name = 'admin'; UPDATE 0 postgres=> update passwd set shell = '/bin/xx'; ERROR: new row violates WITH CHECK OPTION for "passwd" postgres=> delete from passwd; ERROR: permission denied for relation passwd -postgres=> insert into passwd (username) values ('xxx'); +postgres=> insert into passwd (user_name) values ('xxx'); ERROR: permission denied for relation passwd -- Alice can change her own password; RLS silently prevents updating other rows postgres=> update passwd set pwhash = 'abc'; UPDATE 1 + + + + All of the policies constructed thus far have been permissive policies, + meaning that when multiple policies are applied they are combined using + the "OR" boolean operator. While permissive policies can be constructed + to only allow access to rows in the intended cases, it can be simpler to + combine permissive policies with restrictive policies (which the records + must pass and which are combined using the "AND" boolean operator). + Building on the example above, we add a restrictive policy to require + the administrator to be connected over a local unix socket to access the + records of the passwd table: + + + +CREATE POLICY admin_local_only ON passwd AS RESTRICTIVE TO admin + USING (pg_catalog.inet_client_addr() IS NULL); + + + + We can then see that an administrator connecting over a network will not + see any records, due to the restrictive policy: + + + +=> SELECT current_user; + current_user +-------------- + admin +(1 row) + +=> select inet_client_addr(); + inet_client_addr +------------------ + 127.0.0.1 +(1 row) + +=> SELECT current_user; + current_user +-------------- + admin +(1 row) + +=> TABLE passwd; + user_name | pwhash | uid | gid | real_name | home_phone | extra_info | home_dir | shell +-----------+--------+-----+-----+-----------+------------+------------+----------+------- +(0 rows) + +=> UPDATE passwd set pwhash = NULL; +UPDATE 0 @@ -2055,7 +2107,7 @@ DROP SCHEMA myschema CASCADE; (since this is one of the ways to restrict the activities of your users to well-defined namespaces). The syntax for that is: -CREATE SCHEMA schemaname AUTHORIZATION username; +CREATE SCHEMA schema_name AUTHORIZATION user_name; You can even omit the schema name, in which case the schema name will be the same as the user name. See username.tablename. + user_name.table_name. This is how PostgreSQL will effectively behave if you create a per-user schema for every user. @@ -2477,11 +2529,9 @@ SELECT name, altitude WHERE altitude > 500; - Writing * is not necessary, since this behavior is - the default (unless you have changed the setting of the - configuration option). - However writing * might be useful to emphasize that - additional tables will be searched. + Writing * is not necessary, since this behavior is always + the default. However, this syntax is still supported for + compatibility with older releases where the default could be changed. @@ -2559,7 +2609,8 @@ VALUES ('Albany', NULL, NULL, 'NY'); All check constraints and not-null constraints on a parent table are - automatically inherited by its children. Other types of constraints + automatically inherited by its children, unless explicitly specified + otherwise with NO INHERIT clauses. Other types of constraints (unique, primary key, and foreign key constraints) are not inherited. @@ -2570,10 +2621,12 @@ VALUES ('Albany', NULL, NULL, 'NY'); same column name appears in multiple parent tables, or in both a parent table and the child's definition, then these columns are merged so that there is only one such column in the child table. To be merged, - columns must have the same data types, else an error is raised. The - merged column will have copies of all the check constraints coming from - any one of the column definitions it came from, and will be marked not-null - if any of them are. + columns must have the same data types, else an error is raised. + Inheritable check constraints and not-null constraints are merged in a + similar fashion. Thus, for example, a merged column will be marked + not-null if any one of the column definitions it came from is marked + not-null. Check constraints are merged if they have the same name, + and the merge will fail if their conditions are different. @@ -2625,12 +2678,19 @@ VALUES ('Albany', NULL, NULL, 'NY'); - Note how table access permissions are handled. Querying a parent - table can automatically access data in child tables without further - access privilege checking. This preserves the appearance that the - data is (also) in the parent table. Accessing the child tables - directly is, however, not automatically allowed and would require - further privileges to be granted. + Inherited queries perform access permission checks on the parent table + only. Thus, for example, granting UPDATE permission on + the cities table implies permission to update rows in + the capitals table as well, when they are + accessed through cities. This preserves the appearance + that the data is (also) in the parent table. But + the capitals table could not be updated directly + without an additional grant. In a similar way, the parent table's row + security policies (see ) are applied to + rows coming from child tables during an inherited query. A child table's + policies, if any, are applied only when it is the table explicitly named + in the query; and in that case, any policies attached to its parent(s) are + ignored. diff --git a/doc/src/sgml/dfunc.sgml b/doc/src/sgml/dfunc.sgml index 5a368f6df0..6a4b7d6e97 100644 --- a/doc/src/sgml/dfunc.sgml +++ b/doc/src/sgml/dfunc.sgml @@ -127,8 +127,8 @@ cc -shared -o foo.so foo.o - OS X - OS Xshared library + macOS + macOSshared library @@ -200,32 +200,6 @@ cc -G -o foo.so foo.o gcc -fpic -c foo.c gcc -G -o foo.so foo.o - - - - - - - - UnixWare - UnixWareshared library - - - - The compiler flag to create PIC is with the SCO compiler and - with GCC. To link shared libraries, - the compiler option is with the SCO compiler - and with - GCC. - -cc -K PIC -c foo.c -cc -G -o foo.so foo.o - - or - -gcc -fpic -c foo.c -gcc -shared -o foo.so foo.o diff --git a/doc/src/sgml/dml.sgml b/doc/src/sgml/dml.sgml index cd36a73811..0c65578b59 100644 --- a/doc/src/sgml/dml.sgml +++ b/doc/src/sgml/dml.sgml @@ -102,6 +102,18 @@ INSERT INTO products (product_no, name, price) VALUES + + It is also possible to insert the result of a query (which might be no + rows, one row, or many rows): + +INSERT INTO products (product_no, name, price) + SELECT product_no, name, price FROM new_products + WHERE release_date = 'today'; + + This provides the full power of the SQL query mechanism () for computing the rows to be inserted. + + When inserting a lot of data at the same time, considering using @@ -252,4 +264,91 @@ DELETE FROM products; then all rows in the table will be deleted! Caveat programmer. + + + Returning Data From Modified Rows + + + RETURNING + + + + INSERT + RETURNING + + + + UPDATE + RETURNING + + + + DELETE + RETURNING + + + + Sometimes it is useful to obtain data from modified rows while they are + being manipulated. The INSERT, UPDATE, + and DELETE commands all have an + optional RETURNING clause that supports this. Use + of RETURNING avoids performing an extra database query to + collect the data, and is especially valuable when it would otherwise be + difficult to identify the modified rows reliably. + + + + The allowed contents of a RETURNING clause are the same as + a SELECT command's output list + (see ). It can contain column + names of the command's target table, or value expressions using those + columns. A common shorthand is RETURNING *, which selects + all columns of the target table in order. + + + + In an INSERT, the data available to RETURNING is + the row as it was inserted. This is not so useful in trivial inserts, + since it would just repeat the data provided by the client. But it can + be very handy when relying on computed default values. For example, + when using a serial + column to provide unique identifiers, RETURNING can return + the ID assigned to a new row: + +CREATE TABLE users (firstname text, lastname text, id serial primary key); + +INSERT INTO users (firstname, lastname) VALUES ('Joe', 'Cool') RETURNING id; + + The RETURNING clause is also very useful + with INSERT ... SELECT. + + + + In an UPDATE, the data available to RETURNING is + the new content of the modified row. For example: + +UPDATE products SET price = price * 1.10 + WHERE price <= 99.99 + RETURNING name, price AS new_price; + + + + + In a DELETE, the data available to RETURNING is + the content of the deleted row. For example: + +DELETE FROM products + WHERE obsoletion_date = 'today' + RETURNING *; + + + + + If there are triggers () on the target table, + the data available to RETURNING is the row as modified by + the triggers. Thus, inspecting columns computed by triggers is another + common use-case for RETURNING. + + + diff --git a/doc/src/sgml/docguide.sgml b/doc/src/sgml/docguide.sgml index 6f896b565f..48828aff37 100644 --- a/doc/src/sgml/docguide.sgml +++ b/doc/src/sgml/docguide.sgml @@ -275,7 +275,7 @@ apt-get install docbook docbook-dsssl docbook-xsl libxml2-utils openjade1.3 open - OS X + macOS If you use MacPorts, the following will get you set up: diff --git a/doc/src/sgml/ecpg.sgml b/doc/src/sgml/ecpg.sgml index a30e25cfa0..b8021cbe5b 100644 --- a/doc/src/sgml/ecpg.sgml +++ b/doc/src/sgml/ecpg.sgml @@ -517,7 +517,7 @@ EXEC SQL COMMIT; - SET AUTOCOMMIT TO OFF + EXEC SQL SET AUTOCOMMIT TO OFF Disable autocommit mode. This is the default. diff --git a/doc/src/sgml/extend.sgml b/doc/src/sgml/extend.sgml index f050ff1f66..c4f211bc02 100644 --- a/doc/src/sgml/extend.sgml +++ b/doc/src/sgml/extend.sgml @@ -335,11 +335,13 @@ by pg_dump. Such a change is usually only sensible if you concurrently make the same change in the extension's script file. (But there are special provisions for tables containing configuration - data; see below.) + data; see .) + In production situations, it's generally better to create an extension + update script to perform changes to extension member objects. - The extension script may set privileges on objects which are part of the + The extension script may set privileges on objects that are part of the extension via GRANT and REVOKE statements. The final set of privileges for each object (if any are set) will be stored in the @@ -388,6 +390,15 @@ schema(s) its member objects are within. + + If an extension's script creates any temporary objects (such as temp + tables), those objects are treated as extension members for the + remainder of the current session, but are automatically dropped at + session end, as any temporary object would be. This is an exception + to the rule that extension member objects cannot be dropped without + dropping the whole extension. + + Extension Files @@ -453,9 +464,11 @@ comment (string) - A comment (any string) about the extension. Alternatively, - the comment can be set by means of the - command in the script file. + A comment (any string) about the extension. The comment is applied + when initially creating an extension, but not during extension updates + (since that might override user-added comments). Alternatively, + the extension's comment can be set by writing + a command in the script file. @@ -518,7 +531,7 @@ its contained objects into a different schema after initial creation of the extension. The default is false, i.e. the extension is not relocatable. - See below for more information. + See for more information. @@ -529,7 +542,10 @@ This parameter can only be set for non-relocatable extensions. It forces the extension to be loaded into exactly the named schema - and not any other. See below for more information. + and not any other. + The schema parameter is consulted only when + initially creating an extension, not during extension updates. + See for more information. @@ -562,7 +578,8 @@ comments) by the extension mechanism. This provision is commonly used to throw an error if the script file is fed to psql rather than being loaded via CREATE EXTENSION (see example - script below). Without that, users might accidentally load the + script in ). + Without that, users might accidentally load the extension's contents as loose objects rather than as an extension, a state of affairs that's a bit tedious to recover from. @@ -580,7 +597,7 @@ - + Extension Relocatability @@ -678,7 +695,7 @@ SET LOCAL search_path TO @extschema@; - + Extension Configuration Tables @@ -762,7 +779,7 @@ SELECT pg_catalog.pg_extension_config_dump('my_config', 'WHERE NOT standard_entr out but the dump will not be able to be restored directly and user intervention will be required. - + Sequences associated with serial or bigserial columns need to be directly marked to dump their state. Marking their parent @@ -795,7 +812,8 @@ SELECT pg_catalog.pg_extension_config_dump('my_config', 'WHERE NOT standard_entr environment that CREATE EXTENSION provides for installation scripts: in particular, search_path is set up in the same way, and any new objects created by the script are automatically added - to the extension. + to the extension. Also, if the script chooses to drop extension member + objects, they are automatically dissociated from the extension. @@ -878,6 +896,47 @@ SELECT * FROM pg_extension_update_paths('extension_name'); + Installing Extensions using Update Scripts + + + An extension that has been around for awhile will probably exist in + several versions, for which the author will need to write update scripts. + For example, if you have released a foo extension in + versions 1.0, 1.1, and 1.2, there + should be update scripts foo--1.0--1.1.sql + and foo--1.1--1.2.sql. + Before PostgreSQL 10, it was necessary to also create + new script files foo--1.1.sql and foo--1.2.sql + that directly build the newer extension versions, or else the newer + versions could not be installed directly, only by + installing 1.0 and then updating. That was tedious and + duplicative, but now it's unnecessary, because CREATE + EXTENSION can follow update chains automatically. + For example, if only the script + files foo--1.0.sql, foo--1.0--1.1.sql, + and foo--1.1--1.2.sql are available then a request to + install version 1.2 is honored by running those three + scripts in sequence. The processing is the same as if you'd first + installed 1.0 and then updated to 1.2. + (As with ALTER EXTENSION UPDATE, if multiple pathways are + available then the shortest is preferred.) Arranging an extension's + script files in this style can reduce the amount of maintenance effort + needed to produce small updates. + + + + If you use secondary (version-specific) control files with an extension + maintained in this style, keep in mind that each version needs a control + file even if it has no stand-alone installation script, as that control + file will determine how the implicit update to that version is performed. + For example, if foo--1.0.control specifies requires + = 'bar' but foo's other control files do not, the + extension's dependency on bar will be dropped when updating + from 1.0 to another version. + + + + Extension Example @@ -1144,6 +1203,15 @@ include $(PGXS) + + NO_INSTALLCHECK + + + don't define an installcheck target, useful e.g. if tests require special configuration, or don't use pg_regress + + + + EXTRA_CLEAN diff --git a/doc/src/sgml/file-fdw.sgml b/doc/src/sgml/file-fdw.sgml index d3b39aa120..309a303e03 100644 --- a/doc/src/sgml/file-fdw.sgml +++ b/doc/src/sgml/file-fdw.sgml @@ -10,10 +10,11 @@ The file_fdw module provides the foreign-data wrapper file_fdw, which can be used to access data - files in the server's file system. Data files must be in a format + files in the server's file system, or to execute programs on the server + and read their output. The data file or program output must be in a format that can be read by COPY FROM; see for details. - Access to such data files is currently read-only. + Access to data files is currently read-only. @@ -27,7 +28,22 @@ - Specifies the file to be read. Required. Must be an absolute path name. + Specifies the file to be read. Must be an absolute path name. + Either filename or program must be + specified, but not both. + + + + + + program + + + + Specifies the command to be executed. The standard output of this + command will be read as though COPY FROM PROGRAM were used. + Either program or filename must be + specified, but not both. @@ -37,7 +53,7 @@ - Specifies the file's format, + Specifies the data format, the same as COPY's FORMAT option. @@ -48,7 +64,7 @@ - Specifies whether the file has a header line, + Specifies whether the data has a header line, the same as COPY's HEADER option. @@ -59,7 +75,7 @@ - Specifies the file's delimiter character, + Specifies the data delimiter character, the same as COPY's DELIMITER option. @@ -70,7 +86,7 @@ - Specifies the file's quote character, + Specifies the data quote character, the same as COPY's QUOTE option. @@ -81,7 +97,7 @@ - Specifies the file's escape character, + Specifies the data escape character, the same as COPY's ESCAPE option. @@ -92,7 +108,7 @@ - Specifies the file's null string, + Specifies the data null string, the same as COPY's NULL option. @@ -103,7 +119,7 @@ - Specifies the file's encoding, + Specifies the data encoding, the same as COPY's ENCODING option. @@ -112,11 +128,11 @@ - Note that while COPY allows options such as OIDS and HEADER - to be specified without a corresponding value, the foreign data wrapper + Note that while COPY allows options such as HEADER + to be specified without a corresponding value, the foreign table option syntax requires a value to be present in all cases. To activate - COPY options normally supplied without a value, you can - instead pass the value TRUE. + COPY options typically written without a value, you can pass + the value TRUE, since all such options are Booleans. @@ -133,7 +149,7 @@ This is a Boolean option. If true, it specifies that values of the column should not be matched against the null string (that is, the - file-level null option). This has the same effect + table-level null option). This has the same effect as listing the column in COPY's FORCE_NOT_NULL option. @@ -171,14 +187,24 @@ Changing table-level options requires superuser privileges, for security - reasons: only a superuser should be able to determine which file is read. - In principle non-superusers could be allowed to change the other options, - but that's not supported at present. + reasons: only a superuser should be able to control which file is read + or which program is run. In principle non-superusers could be allowed to + change the other options, but that's not supported at present. + + + + When specifying the program option, keep in mind that the option + string is executed by the shell. If you need to pass any arguments to the + command that come from an untrusted source, you must be careful to strip or + escape any characters that might have special meaning to the shell. + For security reasons, it is best to use a fixed command string, or at least + avoid passing any user input in it. For a foreign table using file_fdw, EXPLAIN shows - the name of the file to be read. Unless COSTS OFF is + the name of the file to be read or program to be run. + For a file, unless COSTS OFF is specified, the file size (in bytes) is shown as well. @@ -186,7 +212,7 @@ Create a Foreign Table for PostgreSQL CSV Logs - One of the obvious uses for the file_fdw is to make + One of the obvious uses for file_fdw is to make the PostgreSQL activity log available as a table for querying. To do this, first you must be logging to a CSV file, which here we will call pglog.csv. First, install file_fdw diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml index 43837114ba..2624c627dc 100644 --- a/doc/src/sgml/filelist.sgml +++ b/doc/src/sgml/filelist.sgml @@ -24,6 +24,7 @@ + @@ -49,6 +50,7 @@ + diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 426e562b03..b214218791 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -1534,11 +1534,12 @@ text - Remove the longest string containing only the + Remove the longest string containing only characters from characters (a space by default) from the - start/end/both ends of the string + start, end, or both ends (both is the default) + of string - trim(both 'x' from 'xTomxx') + trim(both 'xyz' from 'yxTomxx') Tom @@ -1547,14 +1548,14 @@ trim(leading | trailing | both from string - , characters + , characters ) text - Non-standard version of trim() + Non-standard syntax for trim() - trim(both from 'xTomxx', 'x') + trim(both from 'yxTomxx', 'xyz') Tom @@ -1626,7 +1627,7 @@ in characters (a space by default) from the start and end of string - btrim('xyxtrimyyx', 'xy') + btrim('xyxtrimyyx', 'xyz') trim @@ -1895,8 +1896,8 @@ characters (a space by default) from the start of string - ltrim('zzzytrim', 'xyz') - trim + ltrim('zzzytest', 'xyz') + test @@ -2036,6 +2037,23 @@ '42.5' + + + + regexp_match + + regexp_match(string text, pattern text [, flags text]) + + text[] + + Return captured substring(s) resulting from the first match of a POSIX + regular expression to the string. See + for more information. + + regexp_match('foobarbequebaz', '(bar)(beque)') + {bar,beque} + + @@ -2045,12 +2063,12 @@ setof text[] - Return all captured substrings resulting from matching a POSIX regular - expression against the string. See + Return captured substring(s) resulting from matching a POSIX regular + expression to the string. See for more information. - regexp_matches('foobarbequebaz', '(bar)(beque)') - {bar,beque} + regexp_matches('foobarbequebaz', 'ba.', 'g') + {bar}{baz} (2 rows) @@ -2201,8 +2219,8 @@ characters (a space by default) from the end of string - rtrim('trimxxxx', 'x') - trim + rtrim('testxxzx', 'xyz') + test @@ -3467,11 +3485,11 @@ SELECT format('Testing %3$s, %2$s, %s', 'one', 'two', 'three'); bytea - Remove the longest string containing only the bytes in + Remove the longest string containing only bytes appearing in bytes from the start and end of string - trim(E'\\000'::bytea from E'\\000Tom\\000'::bytea) + trim(E'\\000\\001'::bytea from E'\\000Tom\\001'::bytea) Tom @@ -3510,11 +3528,11 @@ SELECT format('Testing %3$s, %2$s, %s', 'one', 'two', 'three'); bytea - Remove the longest string consisting only of bytes - in bytes from the start and end of + Remove the longest string containing only bytes appearing in + bytes from the start and end of string - btrim(E'\\000trim\\000'::bytea, E'\\000'::bytea) + btrim(E'\\000trim\\001'::bytea, E'\\000\\001'::bytea) trim @@ -4112,6 +4130,9 @@ substring('foobar' from '#"o_b#"%' for '#') NULL regexp_replace + + regexp_match + regexp_matches @@ -4272,64 +4293,106 @@ regexp_replace('foobarbaz', 'b(..)', E'X\\1Y', 'g') - The regexp_matches function returns a text array of - all of the captured substrings resulting from matching a POSIX - regular expression pattern. It has the syntax - regexp_matches(string, pattern - , flags ). - The function can return no rows, one row, or multiple rows (see - the g flag below). If the pattern - does not match, the function returns no rows. If the pattern - contains no parenthesized subexpressions, then each row - returned is a single-element text array containing the substring - matching the whole pattern. If the pattern contains parenthesized - subexpressions, the function returns a text array whose - n'th element is the substring matching the - n'th parenthesized subexpression of the pattern - (not counting non-capturing parentheses; see below for - details). - The flags parameter is an optional text - string containing zero or more single-letter flags that change the - function's behavior. Flag g causes the function to find - each match in the string, not only the first one, and return a row for - each such match. Supported flags (though - not g) - are described in . + The regexp_match function returns a text array of + captured substring(s) resulting from the first match of a POSIX + regular expression pattern to a string. It has the syntax + regexp_match(string, + pattern , flags ). + If there is no match, the result is NULL. + If a match is found, and the pattern contains no + parenthesized subexpressions, then the result is a single-element text + array containing the substring matching the whole pattern. + If a match is found, and the pattern contains + parenthesized subexpressions, then the result is a text array + whose n'th element is the substring matching + the n'th parenthesized subexpression of + the pattern (not counting non-capturing + parentheses; see below for details). + The flags parameter is an optional text string + containing zero or more single-letter flags that change the function's + behavior. Supported flags are described + in . Some examples: -SELECT regexp_matches('foobarbequebaz', '(bar)(beque)'); - regexp_matches ----------------- +SELECT regexp_match('foobarbequebaz', 'bar.*que'); + regexp_match +-------------- + {barbeque} +(1 row) + +SELECT regexp_match('foobarbequebaz', '(bar)(beque)'); + regexp_match +-------------- {bar,beque} (1 row) + + In the common case where you just want the whole matching substring + or NULL for no match, write something like + +SELECT (regexp_match('foobarbequebaz', 'bar.*que'))[1]; + regexp_match +-------------- + barbeque +(1 row) + + + + + The regexp_matches function returns a set of text arrays + of captured substring(s) resulting from matching a POSIX regular + expression pattern to a string. It has the same syntax as + regexp_match. + This function returns no rows if there is no match, one row if there is + a match and the g flag is not given, or N + rows if there are N matches and the g flag + is given. Each returned row is a text array containing the whole + matched substring or the substrings matching parenthesized + subexpressions of the pattern, just as described above + for regexp_match. + regexp_matches accepts all the flags shown + in , plus + the g flag which commands it to return all matches, not + just the first one. + + + + Some examples: + + SELECT regexp_matches('foo', 'not there'); + regexp_matches +---------------- +(0 rows) SELECT regexp_matches('foobarbequebazilbarfbonk', '(b[^b]+)(b[^b]+)', 'g'); - regexp_matches + regexp_matches ---------------- {bar,beque} {bazil,barf} (2 rows) - -SELECT regexp_matches('foobarbequebaz', 'barbeque'); - regexp_matches ----------------- - {barbeque} -(1 row) - - It is possible to force regexp_matches() to always - return one row by using a sub-select; this is particularly useful - in a SELECT target list when you want all rows - returned, even non-matching ones: + + + In most cases regexp_matches() should be used with + the g flag, since if you only want the first match, it's + easier and more efficient to use regexp_match(). + However, regexp_match() only exists + in PostgreSQL version 10 and up. When working in older + versions, a common trick is to place a regexp_matches() + call in a sub-select, for example: SELECT col1, (SELECT regexp_matches(col2, '(bar)(beque)')) FROM tab; - + This produces a text array if there's a match, or NULL if + not, the same as regexp_match() would do. Without the + sub-select, this query would produce no output at all for table rows + without a match, which is typically not the desired behavior. + + The regexp_split_to_table function splits a string using a POSIX @@ -4408,6 +4471,7 @@ SELECT foo FROM regexp_split_to_table('the quick brown fox', E'\\s*') AS foo; zero-length matches that occur at the start or end of the string or immediately after a previous match. This is contrary to the strict definition of regexp matching that is implemented by + regexp_match and regexp_matches, but is usually the most convenient behavior in practice. Other software systems such as Perl use similar definitions. @@ -5482,7 +5546,7 @@ SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})'); into the digits and the parts before and after them. We might try to do that like this: -SELECT regexp_matches('abc01234xyz', '(.*)(\d+)(.*)'); +SELECT regexp_match('abc01234xyz', '(.*)(\d+)(.*)'); Result: {abc0123,4,xyz} That didn't work: the first .* is greedy so @@ -5490,14 +5554,14 @@ SELECT regexp_matches('abc01234xyz', '(.*)(\d+)(.*)'); match at the last possible place, the last digit. We might try to fix that by making it non-greedy: -SELECT regexp_matches('abc01234xyz', '(.*?)(\d+)(.*)'); +SELECT regexp_match('abc01234xyz', '(.*?)(\d+)(.*)'); Result: {abc,0,""} That didn't work either, because now the RE as a whole is non-greedy and so it ends the overall match as soon as possible. We can get what we want by forcing the RE as a whole to be greedy: -SELECT regexp_matches('abc01234xyz', '(?:(.*?)(\d+)(.*)){1,1}'); +SELECT regexp_match('abc01234xyz', '(?:(.*?)(\d+)(.*)){1,1}'); Result: {abc,01234,xyz} Controlling the RE's overall greediness separately from its components' @@ -5769,6 +5833,17 @@ SELECT regexp_matches('abc01234xyz', '(?:(.*?)(\d+)(.*)){1,1}'); + + + to_timestamp and to_date + exist to handle input formats that cannot be converted by + simple casting. For most standard date/time formats, simply casting the + source string to the required data type works, and is much easier. + Similarly, to_number is unnecessary for standard numeric + representations. + + + In a to_char output template string, there are certain patterns that are recognized and replaced with appropriately-formatted @@ -5975,7 +6050,7 @@ SELECT regexp_matches('abc01234xyz', '(?:(.*?)(\d+)(.*)){1,1}'); Q - quarter (ignored by to_date and to_timestamp) + quarter RM @@ -6093,20 +6168,6 @@ SELECT regexp_matches('abc01234xyz', '(?:(.*?)(\d+)(.*)){1,1}'); - - - to_timestamp and to_date - exist to handle input formats that cannot be converted by - simple casting. These functions interpret input liberally, - with minimal error checking. While they produce valid output, - the conversion can yield unexpected results. For example, - input to these functions is not restricted by normal ranges, - thus to_date('20096040','YYYYMMDD') returns - 2014-01-17 rather than causing an error. - Casting does not have this behavior. - - - Ordinary text is allowed in to_char @@ -6132,7 +6193,8 @@ SELECT regexp_matches('abc01234xyz', '(?:(.*?)(\d+)(.*)){1,1}'); - If the year format specification is less than four digits, e.g. + In to_timestamp and to_date, + if the year format specification is less than four digits, e.g. YYY, and the supplied year is less than four digits, the year will be adjusted to be nearest to the year 2020, e.g. 95 becomes 1995. @@ -6141,8 +6203,9 @@ SELECT regexp_matches('abc01234xyz', '(?:(.*?)(\d+)(.*)){1,1}'); - The YYYY conversion from string to timestamp or - date has a restriction when processing years with more than 4 digits. You must + In to_timestamp and to_date, + the YYYY conversion has a restriction when + processing years with more than 4 digits. You must use some non-digit character or template after YYYY, otherwise the year is always interpreted as 4 digits. For example (with the year 20000): @@ -6156,12 +6219,12 @@ SELECT regexp_matches('abc01234xyz', '(?:(.*?)(\d+)(.*)){1,1}'); - In conversions from string to timestamp or - date, the CC (century) field is ignored + In to_timestamp and to_date, + the CC (century) field is accepted but ignored if there is a YYY, YYYY or Y,YYY field. If CC is used with - YY or Y then the year is computed - as the year in the specified century. If the century is + YY or Y then the result is + computed as that year in the specified century. If the century is specified but the year is not, the first year of the century is assumed. @@ -6169,9 +6232,19 @@ SELECT regexp_matches('abc01234xyz', '(?:(.*?)(\d+)(.*)){1,1}'); - An ISO 8601 week-numbering date (as distinct from a Gregorian date) - can be specified to to_timestamp and - to_date in one of two ways: + In to_timestamp and to_date, + weekday names or numbers (DAY, D, + and related field types) are accepted but are ignored for purposes of + computing the result. The same is true for quarter + (Q) fields. + + + + + + In to_timestamp and to_date, + an ISO 8601 week-numbering date (as distinct from a Gregorian date) + can be specified in one of two ways: @@ -6213,23 +6286,24 @@ SELECT regexp_matches('abc01234xyz', '(?:(.*?)(\d+)(.*)){1,1}'); - In a conversion from string to timestamp, millisecond + In to_timestamp, millisecond (MS) or microsecond (US) - values are used as the + fields are used as the seconds digits after the decimal point. For example - to_timestamp('12:3', 'SS:MS') is not 3 milliseconds, - but 300, because the conversion counts it as 12 + 0.3 seconds. - This means for the format SS:MS, the input values - 12:3, 12:30, and 12:300 specify the - same number of milliseconds. To get three milliseconds, one must use - 12:003, which the conversion counts as + to_timestamp('12.3', 'SS.MS') is not 3 milliseconds, + but 300, because the conversion treats it as 12 + 0.3 seconds. + So, for the format SS.MS, the input values + 12.3, 12.30, + and 12.300 specify the + same number of milliseconds. To get three milliseconds, one must write + 12.003, which the conversion treats as 12 + 0.003 = 12.003 seconds. Here is a more complex example: - to_timestamp('15:12:02.020.001230', 'HH:MI:SS.MS.US') + to_timestamp('15:12:02.020.001230', 'HH24:MI:SS.MS.US') is 15 hours, 12 minutes, and 2 seconds + 20 milliseconds + 1230 microseconds = 2.021230 seconds. @@ -6247,9 +6321,10 @@ SELECT regexp_matches('abc01234xyz', '(?:(.*?)(\d+)(.*)){1,1}'); to_char(interval) formats HH and - HH12 as shown on a 12-hour clock, i.e. zero hours - and 36 hours output as 12, while HH24 - outputs the full hour value, which can exceed 23 for intervals. + HH12 as shown on a 12-hour clock, for example zero hours + and 36 hours both output as 12, while HH24 + outputs the full hour value, which can exceed 23 in + an interval value. @@ -8302,12 +8377,12 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple # Point or box of intersection - '((1,-1),(-1,1))' # '((1,1),(-1,-1))' + box '((1,-1),(-1,1))' # box '((1,1),(-2,-2))' # Number of points in path or polygon - # '((1,0),(0,1),(-1,0))' + # path '((1,0),(0,1),(-1,0))' @-@ @@ -9460,7 +9535,7 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple ts_filter(vector tsvector, weights "char"[]) tsvector - Select only elements with given weights from vector + select only elements with given weights from vector ts_filter('fat:2,4 cat:3b rat:5A'::tsvector, '{a,b}') 'cat':3B 'rat':5A @@ -10768,6 +10843,14 @@ table2-mapping on their key value. '{"a": "b"}'::jsonb - 'a' + + - + text[] + Delete multiple key/value pairs or string + elements from left operand. Key/value pairs are matched based + on their key value. + '{"a": "b", "c": "d"}'::jsonb - '{a,c}'::text[] + - integer @@ -13699,9 +13782,6 @@ SELECT xmlagg(x) FROM (SELECT x FROM test ORDER BY y DESC) AS tab; percentile continuous - - median - percentile_cont(fraction) WITHIN GROUP (ORDER BY sort_expression) @@ -13737,7 +13817,7 @@ SELECT xmlagg(x) FROM (SELECT x FROM test ORDER BY y DESC) AS tab; No multiple continuous percentile: returns an array of results matching - the shape of the fractions parameter, with each + the shape of the fractions parameter, with each non-null element replaced by the value corresponding to that percentile @@ -13782,7 +13862,7 @@ SELECT xmlagg(x) FROM (SELECT x FROM test ORDER BY y DESC) AS tab; No multiple discrete percentile: returns an array of results matching the - shape of the fractions parameter, with each non-null + shape of the fractions parameter, with each non-null element replaced by the input value corresponding to that percentile @@ -15253,7 +15333,7 @@ SELECT * FROM pg_ls_dir('.') WITH ORDINALITY AS t(ls,n); pg_snapshots | 13 pg_multixact | 14 PG_VERSION | 15 - pg_xlog | 16 + pg_wal | 16 pg_hba.conf | 17 pg_stat_tmp | 18 pg_subtrans | 19 @@ -15834,6 +15914,21 @@ SET search_path TO schema , schema, .. boolean does current user have privilege for tablespace + + has_type_privilege(user, + type, + privilege) + + boolean + does user have privilege for type + + + has_type_privilege(type, + privilege) + + boolean + does current user have privilege for type + pg_has_role(user, role, @@ -15892,6 +15987,9 @@ SET search_path TO schema , schema, .. has_tablespace_privilege + + has_type_privilege + pg_has_role @@ -16046,6 +16144,18 @@ SELECT has_function_privilege('joeuser', 'myfunc(int, text)', 'execute'); CREATE. + + has_type_privilege checks whether a user + can access a type in a particular way. + Its argument possibilities + are analogous to has_table_privilege. + When specifying a type by a text string rather than by OID, + the allowed input is the same as for the regtype data type + (see ). + The desired access privilege type must evaluate to + USAGE. + + pg_has_role checks whether a user can access a role in a particular way. @@ -16787,7 +16897,7 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); pg_options_to_table returns the set of storage option name/value pairs - (option_name/option_value) when passed + (option_name/option_value) when passed pg_class.reloptions or pg_attribute.attoptions. @@ -17056,6 +17166,10 @@ SELECT collation for ('foo' COLLATE "de_DE"); txid_current + + txid_current_if_assigned + + txid_current_snapshot @@ -17096,6 +17210,11 @@ SELECT collation for ('foo' COLLATE "de_DE"); bigint get current transaction ID, assigning a new one if the current transaction does not have one + + txid_current_if_assigned() + bigint + same as txid_current() but returns null instead of assigning an xid if none is already assigned + txid_current_snapshot() txid_snapshot @@ -18351,7 +18470,7 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); pg_create_physical_replication_slot - pg_create_physical_replication_slot(slot_name name , immediately_reserve boolean ) + pg_create_physical_replication_slot(slot_name name , immediately_reserve boolean, temporary boolean) (slot_name name, xlog_position pg_lsn) @@ -18364,7 +18483,11 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); the LSN is reserved on first connection from a streaming replication client. Streaming changes from a physical slot is only possible with the streaming-replication protocol — - see . This function corresponds + see . The optional third + parameter, temporary, when set to true, specifies that + the slot should not be permanently stored to disk and is only meant + for use by current session. Temporary slots are also + released upon any error. This function corresponds to the replication protocol command CREATE_REPLICATION_SLOT ... PHYSICAL. @@ -18391,7 +18514,7 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); pg_create_logical_replication_slot - pg_create_logical_replication_slot(slot_name name, plugin name) + pg_create_logical_replication_slot(slot_name name, plugin name , temporary boolean) (slot_name name, xlog_position pg_lsn) @@ -18399,7 +18522,11 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); Creates a new logical (decoding) replication slot named slot_name using the output plugin - plugin. A call to this function has the same + plugin. The optional third + parameter, temporary, when set to true, specifies that + the slot should not be permanently stored to disk and is only meant + for use by current session. Temporary slots are also + released upon any error. A call to this function has the same effect as the replication protocol command CREATE_REPLICATION_SLOT ... LOGICAL. @@ -18508,7 +18635,7 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); pg_replication_origin_drop(node_name text) - void + void Delete a previously created replication origin, including any @@ -18540,7 +18667,7 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); pg_replication_origin_session_setup(node_name text) - void + void Mark the current session as replaying from the given @@ -18558,7 +18685,7 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); pg_replication_origin_session_reset() - void + void Cancel the effects @@ -18607,7 +18734,7 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); pg_replication_origin_xact_setup(origin_lsn pg_lsn, origin_timestamp timestamptz) - void + void Mark the current transaction as replaying a transaction that has @@ -18626,7 +18753,7 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); pg_replication_origin_xact_reset() - void + void Cancel the effects of @@ -18635,14 +18762,14 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); - + pg_replication_origin_advance pg_replication_origin_advance(node_name text, pos pg_lsn) - void + void Set replication progress for the given node to the given @@ -19071,6 +19198,46 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); in the database's default tablespace, the tablespace can be specified as 0. + + lists functions used to manage + collations. + + + + Collation Management Functions + + + Name Return Type Description + + + + + + pg_import_system_collations + pg_import_system_collations(if_not_exists boolean, schema regnamespace) + + void + Import operating system collations + + + +
+ + + pg_import_system_collations populates the system + catalog pg_collation with collations based on all the + locales it finds on the operating system. This is + what initdb uses; + see for more details. If additional + locales are installed into the operating system later on, this function + can be run again to add collations for the new locales. In that case, the + parameter if_not_exists should be set to true to + skip over existing collations. The schema + parameter would typically be pg_catalog, but that is + not a requirement. (Collation objects based on locales that are no longer + present on the operating system are never removed by this function.) + +
@@ -19102,7 +19269,7 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); - brin_summarize_new_values(index_oid regclass) + brin_summarize_new_values(index regclass) integer summarize page ranges not already summarized @@ -19119,8 +19286,8 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); - brin_summarize_new_values receives a BRIN index OID as - argument and inspects the index to find page ranges in the base table + brin_summarize_new_values accepts the OID or name of a + BRIN index and inspects the index to find page ranges in the base table that are not currently summarized by the index; for any such range it creates a new summary index tuple by scanning the table pages. It returns the number of new page range summaries that were inserted @@ -19129,12 +19296,12 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); gin_clean_pending_list accepts the OID or name of - a GIN index and cleans up the pending list of the specified GIN index + a GIN index and cleans up the pending list of the specified index by moving entries in it to the main GIN data structure in bulk. - It returns the number of pages cleaned up from the pending list. - Note that if the argument is a GIN index built with fastupdate - option disabled, the cleanup does not happen and the return value is 0 - because the index doesn't have a pending list. + It returns the number of pages removed from the pending list. + Note that if the argument is a GIN index built with + the fastupdate option disabled, no cleanup happens and the + return value is 0, because the index doesn't have a pending list. Please see and for details of the pending list and fastupdate option. diff --git a/doc/src/sgml/generate-errcodes-table.pl b/doc/src/sgml/generate-errcodes-table.pl index 2195e0f453..66be811adb 100644 --- a/doc/src/sgml/generate-errcodes-table.pl +++ b/doc/src/sgml/generate-errcodes-table.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl # # Generate the errcodes-table.sgml file from errcodes.txt -# Copyright (c) 2000-2016, PostgreSQL Global Development Group +# Copyright (c) 2000-2017, PostgreSQL Global Development Group use warnings; use strict; diff --git a/doc/src/sgml/gin.sgml b/doc/src/sgml/gin.sgml index 05d92eb975..7c2321ec3c 100644 --- a/doc/src/sgml/gin.sgml +++ b/doc/src/sgml/gin.sgml @@ -85,298 +85,8 @@ - _abstime_ops - abstime[] - - && - <@ - = - @> - - - - _bit_ops - bit[] - - && - <@ - = - @> - - - - _bool_ops - boolean[] - - && - <@ - = - @> - - - - _bpchar_ops - character[] - - && - <@ - = - @> - - - - _bytea_ops - bytea[] - - && - <@ - = - @> - - - - _char_ops - "char"[] - - && - <@ - = - @> - - - - _cidr_ops - cidr[] - - && - <@ - = - @> - - - - _date_ops - date[] - - && - <@ - = - @> - - - - _float4_ops - float4[] - - && - <@ - = - @> - - - - _float8_ops - float8[] - - && - <@ - = - @> - - - - _inet_ops - inet[] - - && - <@ - = - @> - - - - _int2_ops - smallint[] - - && - <@ - = - @> - - - - _int4_ops - integer[] - - && - <@ - = - @> - - - - _int8_ops - bigint[] - - && - <@ - = - @> - - - - _interval_ops - interval[] - - && - <@ - = - @> - - - - _macaddr_ops - macaddr[] - - && - <@ - = - @> - - - - _money_ops - money[] - - && - <@ - = - @> - - - - _name_ops - name[] - - && - <@ - = - @> - - - - _numeric_ops - numeric[] - - && - <@ - = - @> - - - - _oid_ops - oid[] - - && - <@ - = - @> - - - - _oidvector_ops - oidvector[] - - && - <@ - = - @> - - - - _reltime_ops - reltime[] - - && - <@ - = - @> - - - - _text_ops - text[] - - && - <@ - = - @> - - - - _time_ops - time[] - - && - <@ - = - @> - - - - _timestamp_ops - timestamp[] - - && - <@ - = - @> - - - - _timestamptz_ops - timestamp with time zone[] - - && - <@ - = - @> - - - - _timetz_ops - time with time zone[] - - && - <@ - = - @> - - - - _tinterval_ops - tinterval[] - - && - <@ - = - @> - - - - _varbit_ops - bit varying[] - - && - <@ - = - @> - - - - _varchar_ops - character varying[] + array_ops + anyarray && <@ @@ -441,22 +151,10 @@ - There are three methods that an operator class for + There are two methods that an operator class for GIN must provide: - - - int compare(Datum a, Datum b) - - - Compares two keys (not indexed items!) and returns an integer less than - zero, zero, or greater than zero, indicating whether the first key is - less than, equal to, or greater than the second. Null keys are never - passed to this function. - - - - + Datum *extractValue(Datum itemValue, int32 *nkeys, bool **nullFlags) @@ -645,7 +343,38 @@ + + + + In addition, GIN must have a way to sort the key values stored in the index. + The operator class can define the sort ordering by specifying a comparison + method: + + + int compare(Datum a, Datum b) + + + Compares two keys (not indexed items!) and returns an integer less than + zero, zero, or greater than zero, indicating whether the first key is + less than, equal to, or greater than the second. Null keys are never + passed to this function. + + + + + + Alternatively, if the operator class does not provide a compare + method, GIN will look up the default btree operator class for the index + key data type, and use its comparison function. It is recommended to + specify the comparison function in a GIN operator class that is meant for + just one data type, as looking up the btree operator class costs a few + cycles. However, polymorphic GIN operator classes (such + as array_ops) typically cannot specify a single comparison + function. + + + Optionally, an operator class for GIN can supply the following method: @@ -900,11 +629,9 @@ Examples - The PostgreSQL source distribution includes - GIN operator classes for tsvector and - for one-dimensional arrays of all internal types. Prefix searching in - tsvector is implemented using the GIN partial match - feature. + The core PostgreSQL distribution + includes the GIN operator classes previously shown in + . The following contrib modules also contain GIN operator classes: diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml index 06f49dba5d..a1a9532088 100644 --- a/doc/src/sgml/high-availability.sgml +++ b/doc/src/sgml/high-availability.sgml @@ -594,24 +594,24 @@ protocol to make nodes agree on a serializable transactional order. (see ) or directly from the master over a TCP connection (streaming replication). The standby server will also attempt to restore any WAL found in the standby cluster's - pg_xlog directory. That typically happens after a server + pg_wal directory. That typically happens after a server restart, when the standby replays again WAL that was streamed from the master before the restart, but you can also manually copy files to - pg_xlog at any time to have them replayed. + pg_wal at any time to have them replayed. At startup, the standby begins by restoring all WAL available in the archive location, calling restore_command. Once it reaches the end of WAL available there and restore_command - fails, it tries to restore any WAL available in the pg_xlog directory. + fails, it tries to restore any WAL available in the pg_wal directory. If that fails, and streaming replication has been configured, the standby tries to connect to the primary server and start streaming WAL - from the last valid record found in archive or pg_xlog. If that fails + from the last valid record found in archive or pg_wal. If that fails or streaming replication is not configured, or if the connection is later disconnected, the standby goes back to step 1 and tries to restore the file from the archive again. This loop of retries from the - archive, pg_xlog, and via streaming replication goes on until the server + archive, pg_wal, and via streaming replication goes on until the server is stopped or failover is triggered by a trigger file. @@ -619,7 +619,7 @@ protocol to make nodes agree on a serializable transactional order. Standby mode is exited and the server switches to normal operation when pg_ctl promote is run or a trigger file is found (trigger_file). Before failover, - any WAL immediately available in the archive or in pg_xlog will be + any WAL immediately available in the archive or in pg_wal will be restored, but no attempt is made to connect to the master. @@ -895,7 +895,7 @@ primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass' However, these methods often result in retaining more WAL segments than required, whereas replication slots retain only the number of segments known to be needed. An advantage of these methods is that they bound - the space requirement for pg_xlog; there is currently no way + the space requirement for pg_wal; there is currently no way to do this using replication slots. @@ -1138,19 +1138,25 @@ primary_slot_name = 'node_a_slot' as synchronous confirm receipt of their data. The number of synchronous standbys that transactions must wait for replies from is specified in synchronous_standby_names. This parameter also specifies - a list of standby names, which determines the priority of each standby - for being chosen as a synchronous standby. The standbys whose names - appear earlier in the list are given higher priority and will be considered - as synchronous. Other standby servers appearing later in this list - represent potential synchronous standbys. If any of the current - synchronous standbys disconnects for whatever reason, it will be replaced - immediately with the next-highest-priority standby. + a list of standby names and the method (FIRST and + ANY) to choose synchronous standbys from the listed ones. - An example of synchronous_standby_names for multiple - synchronous standbys is: + The method FIRST specifies a priority-based synchronous + replication and makes transaction commits wait until their WAL records are + replicated to the requested number of synchronous standbys chosen based on + their priorities. The standbys whose names appear earlier in the list are + given higher priority and will be considered as synchronous. Other standby + servers appearing later in this list represent potential synchronous + standbys. If any of the current synchronous standbys disconnects for + whatever reason, it will be replaced immediately with the + next-highest-priority standby. + + + An example of synchronous_standby_names for + a priority-based multiple synchronous standbys is: -synchronous_standby_names = '2 (s1, s2, s3)' +synchronous_standby_names = 'FIRST 2 (s1, s2, s3)' In this example, if four standby servers s1, s2, s3 and s4 are running, the two standbys @@ -1161,6 +1167,28 @@ synchronous_standby_names = '2 (s1, s2, s3)' s2 fails. s4 is an asynchronous standby since its name is not in the list. + + The method ANY specifies a quorum-based synchronous + replication and makes transaction commits wait until their WAL records + are replicated to at least the requested number of + synchronous standbys in the list. + + + An example of synchronous_standby_names for + a quorum-based multiple synchronous standbys is: + + synchronous_standby_names = 'ANY 2 (s1, s2, s3)' + + In this example, if four standby servers s1, s2, + s3 and s4 are running, transaction commits will + wait for replies from at least any two standbys of s1, + s2 and s3. s4 is an asynchronous + standby since its name is not in the list. + + + The synchronous states of standby servers can be viewed using + the pg_stat_replication view. + @@ -1235,6 +1263,8 @@ synchronous_standby_names = '2 (s1, s2, s3)' will increase according to the length of time the standby has been down. The standby is only able to become a synchronous standby once it has reached streaming state. + This state can be viewed using + the pg_stat_replication view. diff --git a/doc/src/sgml/indexam.sgml b/doc/src/sgml/indexam.sgml index b59cd0363a..40f201b11b 100644 --- a/doc/src/sgml/indexam.sgml +++ b/doc/src/sgml/indexam.sgml @@ -51,16 +51,9 @@ pg_am system catalog. The pg_am entry specifies a name and a handler function for the access - method. There is not currently any special support - for creating or deleting pg_am entries; - anyone able to write a new access method is expected to be competent - to insert an appropriate row for themselves. - - - - Index access methods can be defined and dropped using + method. These entries can be created and deleted using the and - SQL commands respectively. + SQL commands. diff --git a/doc/src/sgml/indices.sgml b/doc/src/sgml/indices.sgml index 46f8e55ca9..271c135519 100644 --- a/doc/src/sgml/indices.sgml +++ b/doc/src/sgml/indices.sgml @@ -315,9 +315,8 @@ SELECT * FROM places ORDER BY location <-> point '(101,456)' LIMIT 10; operators with which a GIN index can be used vary depending on the indexing strategy. As an example, the standard distribution of - PostgreSQL includes GIN operator classes - for one-dimensional arrays, which support indexed - queries using these operators: + PostgreSQL includes a GIN operator class + for arrays, which supports indexed queries using these operators: <@ diff --git a/doc/src/sgml/install-windows.sgml b/doc/src/sgml/install-windows.sgml index 8cd189c8e1..ecec0a60c7 100644 --- a/doc/src/sgml/install-windows.sgml +++ b/doc/src/sgml/install-windows.sgml @@ -51,7 +51,7 @@ MinGW-w64. These tools can also be used to cross-compile for 32 bit and 64 bit Windows targets on other hosts, such as Linux and - Darwin. + macOS. Cygwin is not recommended for running a production server, and it should only be used for running on older versions of Windows where @@ -145,6 +145,14 @@ $ENV{PATH}=$ENV{PATH} . ';c:\some\where\bison\bin'; + + To pass additional command line arguments to the Visual Studio build + command (msbuild or vcbuild): + +$ENV{MSBFLAGS}="/m"; + + + Requirements @@ -161,7 +169,7 @@ $ENV{PATH}=$ENV{PATH} . ';c:\some\where\bison\bin'; Microsoft Windows SDK it is recommended that you upgrade to the latest version (currently version 7.1), available for download from - . + . You must always include the diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml index a9968756e6..4431ed75a9 100644 --- a/doc/src/sgml/installation.sgml +++ b/doc/src/sgml/installation.sgml @@ -252,10 +252,17 @@ su - postgres - You need Kerberos, OpenSSL, - OpenLDAP, and/or - PAM, if you want to support authentication or - encryption using those services. + You need OpenSSL, if you want to support + encrypted client connections. The minimum required version is + 0.9.8. + + + + + + You need Kerberos, OpenLDAP, + and/or PAM, if you want to support authentication + using those services. @@ -867,7 +874,7 @@ su - postgres Build with Bonjour support. This requires Bonjour support - in your operating system. Recommended on OS X. + in your operating system. Recommended on macOS. @@ -893,7 +900,7 @@ su - postgres @@ -1089,6 +1096,25 @@ su - postgres + + + + + Allow the build to succeed even if PostgreSQL + has no support for strong random numbers on the platform. + A source of random numbers is needed for some authentication + protocols, as well as some routines in the + + ]]> + module. --disable-strong-random disables functionality that + requires cryptographically strong random numbers, and substitutes + a weak pseudo-random-number-generator for the generation of + authentication salt values and query cancel keys. It may make + authentication less secure. + + + + @@ -1422,7 +1448,7 @@ su - postgres PERL - Full path to the Perl interpreter. This will be used to + Full path name of the Perl interpreter. This will be used to determine the dependencies for building PL/Perl. @@ -1432,7 +1458,7 @@ su - postgres PYTHON - Full path to the Python interpreter. This will be used to + Full path name of the Python interpreter. This will be used to determine the dependencies for building PL/Python. Also, whether Python 2 or 3 is specified here (or otherwise implicitly chosen) determines which variant of the PL/Python @@ -1449,7 +1475,7 @@ su - postgres TCLSH - Full path to the Tcl interpreter. This will be used to + Full path name of the Tcl interpreter. This will be used to determine the dependencies for building PL/Tcl, and it will be substituted into Tcl scripts. @@ -1503,7 +1529,7 @@ su - postgres will take a few minutes depending on your hardware. The last line displayed should be: -All of PostgreSQL is successfully made. Ready to install. +All of PostgreSQL successfully made. Ready to install. @@ -1516,7 +1542,7 @@ All of PostgreSQL is successfully made. Ready to install. The last line displayed should be: -PostgreSQL, contrib and HTML documentation successfully made. Ready to install. +PostgreSQL, contrib, and documentation successfully made. Ready to install. @@ -1993,8 +2019,8 @@ kill `cat /usr/local/pgsql/data/postmaster.pid` In general, PostgreSQL can be expected to work on these CPU architectures: x86, x86_64, IA64, PowerPC, - PowerPC 64, S/390, S/390x, Sparc, Sparc 64, ARM, MIPS, MIPSEL, M68K, - and PA-RISC. Code support exists for M32R and VAX, but these + PowerPC 64, S/390, S/390x, Sparc, Sparc 64, ARM, MIPS, MIPSEL, + and PA-RISC. Code support exists for M68K, M32R, and VAX, but these architectures are not known to have been tested recently. It is often possible to build on an unsupported CPU type by configuring with , but performance will be poor. @@ -2003,11 +2029,11 @@ kill `cat /usr/local/pgsql/data/postmaster.pid` PostgreSQL can be expected to work on these operating systems: Linux (all recent distributions), Windows (Win2000 SP4 and later), - FreeBSD, OpenBSD, NetBSD, OS X, AIX, HP/UX, Solaris, - and UnixWare. Other Unix-like systems may also work but are not currently + FreeBSD, OpenBSD, NetBSD, macOS, AIX, HP/UX, and Solaris. + Other Unix-like systems may also work but are not currently being tested. In most cases, all CPU architectures supported by a given operating system will work. Look in - the below to see if + below to see if there is information specific to your operating system, particularly if using an older system. @@ -2632,160 +2658,6 @@ PHSS_30849 s700_800 u2comp/be/plugin library Patch
- - SCO OpenServer and SCO UnixWare - - - SCO - installation on - - - - UnixWare - installation on - - - - PostgreSQL can be built on SCO UnixWare 7 and SCO OpenServer 5. - On OpenServer, you can use either the OpenServer Development Kit - or the Universal Development Kit. However, some tweaking may be - needed, as described below. - - - - Skunkware - - - You should locate your copy of the SCO Skunkware CD. The - Skunkware CD is included with UnixWare 7 and current versions of - OpenServer 5. Skunkware includes ready-to-install versions of - many popular programs that are available on the Internet. For - example, gzip, gunzip, GNU Make, Flex, and Bison are all - included. For UnixWare 7.1, this CD is now labeled "Open License - Software Supplement". If you do not have this CD, the software - on it is available - from . - - - - Skunkware has different versions for UnixWare and OpenServer. - Make sure you install the correct version for your operating - system, except as noted below. - - - - On UnixWare 7.1.3 and beyond, the GCC compiler is included on the - UDK CD as is GNU Make. - - - - - GNU Make - - - You need to use the GNU Make program, which is on the Skunkware - CD. By default, it installs - as /usr/local/bin/make. - - - - As of UnixWare 7.1.3 and above, the GNU Make program is the - OSTK portion of the UDK CD, and is - in /usr/gnu/bin/gmake. - - - - - Readline - - - The Readline library is on the Skunkware CD. But it is not - included on the UnixWare 7.1 Skunkware CD. If you have the - UnixWare 7.0.0 or 7.0.1 Skunkware CDs, you can install it from - there. Otherwise, - try . - - - - By default, Readline installs into /usr/local/lib and - /usr/local/include. However, the - PostgreSQL configure program will not find it - there without help. If you installed Readline, then use the - following options to configure: - -./configure --with-libraries=/usr/local/lib --with-includes=/usr/local/include - - - - - - Using the UDK on OpenServer - - - If you are using the new Universal Development Kit (UDK) compiler - on OpenServer, you need to specify the locations of the UDK - libraries: - -./configure --with-libraries=/udk/usr/lib --with-includes=/udk/usr/include - - Putting these together with the Readline options from above: - -./configure --with-libraries="/udk/usr/lib /usr/local/lib" --with-includes="/udk/usr/include /usr/local/include" - - - - - - Reading the PostgreSQL Man Pages - - - By default, the PostgreSQL man pages are installed into - /usr/local/pgsql/share/man. By default, UnixWare - does not look there for man pages. To be able to read them you - need to modify the - MANPATH variable - in /etc/default/man, for example: - -MANPATH=/usr/lib/scohelp/%L/man:/usr/dt/man:/usr/man:/usr/share/man:scohelp:/usr/local/man:/usr/local/pgsql/share/man - - - - - On OpenServer, some extra research needs to be invested to make - the man pages usable, because the man system is a bit different - from other platforms. Currently, PostgreSQL will not install - them at all. - - - - - C99 Issues with the 7.1.1b Feature Supplement - - - For compilers earlier than the one released with OpenUNIX 8.0.0 - (UnixWare 7.1.2), including the 7.1.1b Feature Supplement, you - may need to specify - in CFLAGS or the CC - environment variable. The indication of this is an error in - compiling tuplesort.c referencing inline - functions. Apparently there was a change in the 7.1.2(8.0.0) - compiler and beyond. - - - - - Threading on UnixWare - - - For threading, youmust use - on all libpq-using programs. libpq - uses pthread_* calls, which are only - available with the - - - - Solaris @@ -2826,30 +2698,6 @@ MANPATH=/usr/lib/scohelp/%L/man:/usr/dt/man:/usr/man:/usr/share/man:scohelp:/usr - - Problems with OpenSSL - - - When you build PostgreSQL with OpenSSL support you might get - compilation errors in the following files: - - src/backend/libpq/crypt.c - src/backend/libpq/password.c - src/interfaces/libpq/fe-auth.c - src/interfaces/libpq/fe-connect.c - - - This is because of a namespace conflict between the standard - /usr/include/crypt.h header and the header - files provided by OpenSSL. - - - - Upgrading your OpenSSL installation to version 0.9.6a fixes this - problem. Solaris 9 and above has a newer version of OpenSSL. - - - configure Complains About a Failed Test Program diff --git a/doc/src/sgml/legal.sgml b/doc/src/sgml/legal.sgml index 84bc7beb5a..67ef88b2ff 100644 --- a/doc/src/sgml/legal.sgml +++ b/doc/src/sgml/legal.sgml @@ -1,9 +1,9 @@ -2016 +2017 - 1996-2016 + 1996-2017 The PostgreSQL Global Development Group @@ -11,7 +11,7 @@ Legal Notice - PostgreSQL is Copyright © 1996-2016 + PostgreSQL is Copyright © 1996-2017 by the PostgreSQL Global Development Group. diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index f22e3da047..2620eec033 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -756,8 +756,10 @@ PGPing PQping(const char *conninfo); Several libpq functions parse a user-specified string to obtain connection parameters. There are two accepted formats for these strings: plain keyword = value strings - and RFC - 3986 URIs. + and URIs. URIs generally follow + RFC + 3986, except that multi-host connection strings are allowed + as further described below. @@ -792,7 +794,7 @@ host=localhost port=5432 dbname=mydb connect_timeout=10 The general form for a connection URI is: -postgresql://[user[:password]@][netloc][:port][/dbname][?param1=value1&...] +postgresql://[user[:password]@][netloc][:port][,...][/dbname][?param1=value1&...] @@ -809,6 +811,7 @@ postgresql://localhost/mydb postgresql://user@localhost postgresql://user:secret@localhost postgresql://other@localhost/otherdb?connect_timeout=10&application_name=myapp +postgresql://host1:123,host2:456/somedb?target_session_attrs=any&application_name=myapp Components of the hierarchical part of the URI can also be given as parameters. For example: @@ -856,6 +859,15 @@ postgresql:///dbname?host=/var/lib/postgresql postgresql://%2Fvar%2Flib%2Fpostgresql/dbname + + + It is possible to specify multiple host components, each with an optional + port component, in a single URI. A URI of the form + postgresql://host1:port1,host2:port2,host3:port3/ + is equivalent to a connection string of the form + host=host1,host2,host3 port=port1,port2,port3. Each + host will be tried in turn until a connection is successfully established. + @@ -870,12 +882,13 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname host - Name of host to connect to.host name - If this begins with a slash, it specifies Unix-domain + Comma-separated list of host names.host name + If a host name begins with a slash, it specifies Unix-domain communication rather than TCP/IP communication; the value is the - name of the directory in which the socket file is stored. The - default behavior when host is not specified - is to connect to a Unix-domain + name of the directory in which the socket file is stored. If + multiple host names are specified, each will be tried in turn in + the order given. The default behavior when host is + not specified is to connect to a Unix-domain socketUnix domain socket in /tmp (or whatever socket directory was specified when PostgreSQL was built). On machines without @@ -950,6 +963,9 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname Port number to connect to at the server host, or socket file name extension for Unix-domain connections.port + If the host parameter included multiple, comma-separated + hosts, this parameter may specify a list of ports of equal length, + or it may specify a single port number to be used for all hosts. @@ -993,6 +1009,10 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname Maximum wait for connection, in seconds (write as a decimal integer string). Zero or not specified means wait indefinitely. It is not recommended to use a timeout of less than 2 seconds. + This timeout applies separately to each connection attempt. + For example, if you specify two hosts and both of them are unreachable, + and connect_timeout is 5, the total time spent waiting for a + connection might be up to 10 seconds. @@ -1238,8 +1258,7 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname If set to 1 (default), data sent over SSL connections will be - compressed (this requires OpenSSL version - 0.9.8 or later). + compressed. If set to 0, compression will be disabled (this requires OpenSSL 1.0.0 or later). This parameter is ignored if a connection without SSL is made, @@ -1367,6 +1386,23 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname + + + target_session_attrs + + + If this parameter is set to read-write, only a + connection in which read-write transactions are accepted by default + is considered acceptable. The query + show transaction_read_only will be sent upon any + successful connection; if it returns on, the connection + will be closed. If multiple hosts were specified in the connection + string, any remaining servers will be tried just as if the connection + attempt had failed. The default value of this parameter, + any, regards all connections as acceptable. + + +
@@ -1395,7 +1431,11 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname The following functions return parameter values established at connection. - These values are fixed for the life of the PGconn object. + These values are fixed for the life of the connection. If a multi-host + connection string is used, the values of PQhost, + PQport, and PQpass can change if a new connection + is established using the same PGconn object. Other values + are fixed for the lifetime of the PGconn object. @@ -2767,6 +2807,22 @@ char *PQresultErrorField(const PGresult *res, int fieldcode); + + PG_DIAG_SEVERITY_NONLOCALIZED + + + The severity; the field contents are ERROR, + FATAL, or PANIC (in an error message), + or WARNING, NOTICE, DEBUG, + INFO, or LOG (in a notice message). + This is identical to the PG_DIAG_SEVERITY field except + that the contents are never localized. This is present only in + reports generated by PostgreSQL versions 9.6 + and later. + + + + PG_DIAG_SQLSTATE @@ -7030,6 +7086,16 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough) linkend="libpq-connect-client-encoding"> connection parameter. + + + + + PGTARGETSESSIONATTRS + + PGTARGETSESSIONATTRS behaves the same as the connection parameter. + + diff --git a/doc/src/sgml/lobj.sgml b/doc/src/sgml/lobj.sgml index 8726f0c701..7757e1e441 100644 --- a/doc/src/sgml/lobj.sgml +++ b/doc/src/sgml/lobj.sgml @@ -670,7 +670,7 @@ SELECT lo_export(image.raster, '/tmp/motd') FROM image * testlo.c * test using large objects with libpq * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/doc/src/sgml/logical-replication.sgml b/doc/src/sgml/logical-replication.sgml new file mode 100644 index 0000000000..9312c0c9a0 --- /dev/null +++ b/doc/src/sgml/logical-replication.sgml @@ -0,0 +1,396 @@ + + + + Logical Replication + + + Logical replication is a method of replicating data objects and their + changes, based upon their replication identity (usually a primary key). We + use the term logical in contrast to physical replication, which uses exact + block addresses and byte-by-byte replication. PostgreSQL supports both + mechanisms concurrently, see . Logical + replication allows fine-grained control over both data replication and + security. + + + + Logical replication uses a publish + and subscribe model with one or + more subscribers subscribing to one or more + publications on a publisher + node. Subscribers pull data from the publications they subscribe to and may + subsequently re-publish data to allow cascading replication or more complex + configurations. + + + + Logical replication sends the changes on the publisher to the subscriber as + they occur in real-time. The subscriber applies the data in the same order + as the publisher so that transactional consistency is guaranteed for + publications within a single subscription. This method of data replication + is sometimes referred to as transactional replication. + + + + The typical use-cases for logical replication are: + + + + + Sending incremental changes in a single database or a subset of a + database to subscribers as they occur. + + + + + + Firing triggers for individual changes as they are incoming to + subscriber. + + + + + + Consolidating multiple databases into a single one (for example for + analytical purposes). + + + + + + Replicating between different major versions of PostgreSQL. + + + + + + Giving access to replicated data to different groups of users. + + + + + + Sharing a subset of the database between multiple databases. + + + + + + + The subscriber database behaves in the same way as any other PostgreSQL + instance and can be used as a publisher for other databases by defining its + own publications. When the subscriber is treated as read-only by + application, there will be no conflicts from a single subscription. On the + other hand, if there are other writes done either by application or other + subscribers to the same set of tables conflicts can arise. + + + + Publication + + + A publication object can be defined on any physical + replication master. The node where a publication is defined is referred to + as publisher. A publication is a set of changes + generated from a group of tables, and might also be described as a change + set or replication set. Each publication exists in only one database. + + + + Publications are different from schemas and do not affect how the table is + accessed. Each table can be added to multiple publications if needed. + Publications may currently only contain tables. Objects must be added + explicitly, except when a publication is created for ALL + TABLES. + + + + Publications can choose to limit the changes they produce to show + any combination of INSERT, UPDATE, and + DELETE in a similar way to the way triggers are fired by + particular event types. If a table without a REPLICA + IDENTITY is added to a publication that + replicates UPDATE or DELETE + operations then subsequent UPDATE + or DELETE operations will fail on the publisher. + + + + Every publication can have multiple subscribers. + + + + A publication is created using the + command and may be later altered or dropped using corresponding commands. + + + + The individual tables can be added and removed dynamically using + . Both the ADD + TABLE and DROP TABLE operations are + transactional; so the table will start or stop replicating at the correct + snapshot once the transaction has committed. + + + + + Subscription + + + A subscription is the downstream side of logical + replication. The node where a subscription is defined is referred to as + the subscriber. Subscription defines the connection + to another database and set of publications (one or more) to which it wants + to be subscribed. + + + + The subscriber database behaves in the same way as any other PostgreSQL + instance and can be used as a publisher for other databases by defining its + own publications. + + + + A subscriber node may have multiple subscriptions if desired. It is + possible to define multiple subscriptions between a single + publisher-subscriber pair, in which case extra care must be taken to ensure + that the subscribed publication objects don't overlap. + + + + Each subscription will receive changes via one replication slot (see + ). + + + + Subscriptions are not dumped by pg_dump by default but + can be requested using the command-line + option . + + + + The subscription is added using and + can be stopped/resumed at any time using the + command and removed using + . + + + + When a subscription is dropped and recreated, the synchronization + information is lost. This means that the data has to be resynchronized + afterwards. + + + + The schema definitions are not replicated and the published tables must + exist on the subsriber for replication to work. Only regular tables may be + the target of replication. For example, you can't replicate to a view. + + + + The tables are matched between the publisher and the subscriber using the + fully qualified table name. Replication to differently-named tables on the + subscriber is not supported. + + + + Columns of a table are also matched by name. A different order of columns + in the target table is allowed, but the column types have to match. + + + + + Conflicts + + + The logical replication behaves similarly to normal DML operations in that + the data will be updated even if it was changed locally on the subscriber + node. If the incoming data violates any constraints the replication will + stop. This is referred to as a conflict. When + replicating UPDATE or DELETE + operations, missing data will not produce a conflict and such operations + will simply be skipped. + + + + A conflict will produce an error and will stop the replication; it must be + resolved manually by the user. Details about the conflict can be found in + the subscriber's server log. + + + + The resolution can be done either by changing data on the subscriber so + that it does not conflict with the incoming change or by skipping the + transaction that conflicts with the existing data. The transaction can be + skipped by calling the + pg_replication_origin_advance() function with + a node_name corresponding to the subscription name. + The current position of origins can be seen in the + + pg_replication_origin_status system view. + + + + + Architecture + + + Logical replication starts by copying a snapshot of the data on the + publisher database. Once that is done, changes on the publisher are sent + to the subscriber as they occur in real time. The subscriber applies data + in the order in which commits were made on the publisher so that + transactional consistency is guaranteed for the publications within any + single subscription. + + + + Logical replication is built with an architecture similar to physical + streaming replication (see ). It is + implemented by walsender and the apply + processes. The walsender starts logical decoding (described + in ) of the WAL and loads the standard + logical decoding plugin (pgoutput). The plugin transforms the changes read + from WAL to the logical replication protocol + (see ) and filters the data + according to the publication specification. The data is then continuously + transferred using the streaming replication protocol to the apply worker, + which maps the data to local tables and applies the individual changes as + they are received in exact transactional order. + + + + The apply process on the subscriber database always runs with + session_replication_role set + to replica, which produces the usual effects on triggers + and constraints. + + + + + Monitoring + + + Because logical replication is based on similar architecture as + physical streaming replication + the monitoring on a publication node is very similar to monitoring of + physical replication master + (see ). + + + + The monitoring information about subscription is visible in + pg_stat_subscription. + This view contains one row for every subscription worker. A subscription + can have zero or more active subscription workers depending on its state. + + + + Normally, there is a single apply process running for an enabled + subscription. A disabled subscription or a crashed subscription will have + zero rows in this view. + + + + + Security + + + Logical replication connections occur in the same way as physical streaming + replication. It requires access to be specifically given using + pg_hba.conf. The role used for the replication + connection must have the REPLICATION attribute. This + gives a role access to both logical and physical replication. + + + + To create a publication, the user must have the CREATE + privilege in the database. + + + + To create a subscription, the user must be a superuser. + + + + The subscription apply process will run in the local database with the + privileges of a superuser. + + + + Privileges are only checked once at the start of a replication connection. + They are not re-checked as each change record is read from the publisher, + nor are they re-checked for each change when applied. + + + + + Configuration Settings + + + Logical replication requires several configuration options to be set. + + + + On the publisher side, wal_level must be set to + logical, and max_replication_slots + has to be set to at least the number of subscriptions expected to connect. + And max_wal_senders should be set to at least the same + as max_replication_slots plus the number of physical replicas + that are connected at the same time. + + + + The subscriber also requires the max_replication_slots + to be set. In this case it should be set to at least the number of + subscriptions that will be added to the subscriber. + max_logical_replication_workers has to be set to at + least the number of subscriptions. Additionally the + max_worker_processes may need to be adjusted to + accommodate for replication workers, at least + (max_logical_replication_workers + + 1). Note that some extensions and parallel queries + also take worker slots from max_worker_processes. + + + + + Quick Setup + + + First set the configuration options in postgresql.conf: + +wal_level = logical + + The other required settings have default values that are sufficient for a + basic setup. + + + + pg_hba.conf needs to be adjusted to allow replication + (the values here depend on your actual network configuration and user you + want to use for connecting): + +host replication repuser 0.0.0.0/0 md5 + + + + + Then on the publisher database: + +CREATE PUBLICATION mypub FOR TABLE users, departments; + + + + + And on the subscriber database: + +CREATE SUBSCRIPTION mysub CONNECTION 'dbname=foo host=bar user=repuser' PUBLICATION mypub; + + + + + The above will start the replication process of changes to + users and departments tables. + + + diff --git a/doc/src/sgml/logicaldecoding.sgml b/doc/src/sgml/logicaldecoding.sgml index c42082002e..484915d042 100644 --- a/doc/src/sgml/logicaldecoding.sgml +++ b/doc/src/sgml/logicaldecoding.sgml @@ -12,7 +12,6 @@ Changes are sent out in streams identified by logical replication slots. - Each stream outputs each change exactly once. @@ -204,8 +203,7 @@ $ pg_recvlogical -d postgres --slot test --drop-slot In the context of logical replication, a slot represents a stream of changes that can be replayed to a client in the order they were made on the origin server. Each slot streams a sequence of changes from a single - database, sending each change exactly once (except when peeking forward - in the stream). + database. @@ -221,6 +219,20 @@ $ pg_recvlogical -d postgres --slot test --drop-slot independently of the connection using them and are crash-safe. + + A logical slot will emit each change just once in normal operation. + The current position of each slot is persisted only at checkpoint, so in + the case of a crash the slot may return to an earlier LSN, which will + then cause recent changes to be resent when the server restarts. + Logical decoding clients are responsible for avoiding ill effects from + handling the same message more than once. Clients may wish to record + the last LSN they saw when decoding and skip over any repeated data or + (when using the replication protocol) request that decoding start from + that LSN rather than letting the server determine the start point. + The Replication Progress Tracking feature is designed for this purpose, + refer to replication origins. + + Multiple independent slots may exist for a single database. Each slot has its own state, allowing different consumers to receive changes from diff --git a/doc/src/sgml/maintenance.sgml b/doc/src/sgml/maintenance.sgml index 2713883019..f87f3e00de 100644 --- a/doc/src/sgml/maintenance.sgml +++ b/doc/src/sgml/maintenance.sgml @@ -389,7 +389,8 @@ - PostgreSQL's MVCC transaction semantics + PostgreSQL's + MVCC transaction semantics depend on being able to compare transaction ID (XID) numbers: a row version with an insertion XID greater than the current transaction's XID is in the future and should not be visible @@ -407,13 +408,10 @@ The reason that periodic vacuuming solves the problem is that VACUUM will mark rows as frozen, indicating that - they were inserted by a transaction which committed sufficiently far in - the past that the effects of the inserting transaction is certain to be - visible, from an MVCC perspective, to all current and future transactions. - PostgreSQL reserves a special XID, - FrozenTransactionId, which does not follow the normal XID - comparison rules and is always considered older - than every normal XID. Normal XIDs are + they were inserted by a transaction that committed sufficiently far in + the past that the effects of the inserting transaction are certain to be + visible to all current and future transactions. + Normal XIDs are compared using modulo-232 arithmetic. This means that for every normal XID, there are two billion XIDs that are older and two billion that are newer; another @@ -423,16 +421,40 @@ the next two billion transactions, no matter which normal XID we are talking about. If the row version still exists after more than two billion transactions, it will suddenly appear to be in the future. To - prevent this, frozen row versions are treated as if the inserting XID were + prevent this, PostgreSQL reserves a special XID, + FrozenTransactionId, which does not follow the normal XID + comparison rules and is always considered older + than every normal XID. + Frozen row versions are treated as if the inserting XID were FrozenTransactionId, so that they will appear to be in the past to all normal transactions regardless of wraparound issues, and so such row versions will be valid until deleted, no matter how long that is. + + + In PostgreSQL versions before 9.4, freezing was + implemented by actually replacing a row's insertion XID + with FrozenTransactionId, which was visible in the + row's xmin system column. Newer versions just set a flag + bit, preserving the row's original xmin for possible + forensic use. However, rows with xmin equal + to FrozenTransactionId (2) may still be found + in databases pg_upgrade'd from pre-9.4 versions. + + + Also, system catalogs may contain rows with xmin equal + to BootstrapTransactionId (1), indicating that they were + inserted during the first phase of initdb. + Like FrozenTransactionId, this special XID is treated as + older than every normal XID. + + + - controls how old an XID value has to be before its row version will be + controls how old an XID value has to be before rows bearing that XID will be frozen. Increasing this setting may avoid unnecessary work if the rows that would otherwise be frozen will soon be modified again, but decreasing this setting increases @@ -442,10 +464,10 @@ VACUUM uses the visibility map - to determine which pages of a relation must be scanned. Normally, it - will skips pages that don't have any dead row versions even if those pages + to determine which pages of a table must be scanned. Normally, it + will skip pages that don't have any dead row versions even if those pages might still have row versions with old XID values. Therefore, normal - scans won't succeed in freezing every row version in the table. + VACUUMs won't always freeze every old row version in the table. Periodically, VACUUM will perform an aggressive vacuum, skipping only those pages which contain neither dead rows nor any unfrozen XID or MXID values. diff --git a/doc/src/sgml/mk_feature_tables.pl b/doc/src/sgml/mk_feature_tables.pl index 45dea798cd..93dab2132e 100644 --- a/doc/src/sgml/mk_feature_tables.pl +++ b/doc/src/sgml/mk_feature_tables.pl @@ -2,6 +2,8 @@ # doc/src/sgml/mk_feature_tables.pl +use strict; + my $yesno = $ARGV[0]; open PACK, $ARGV[1] or die; diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index 077642878e..01fad3870f 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -308,6 +308,14 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser + + pg_stat_subscriptionpg_stat_subscription + At least one row per subscription, showing information about + the subscription workers. + See for details. + + + pg_stat_sslpg_stat_ssl One row per connection (regular and replication), showing information about @@ -646,18 +654,11 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser - LWLockNamed: The backend is waiting for a specific named - lightweight lock. Each such lock protects a particular data - structure in shared memory. wait_event will contain - the name of the lightweight lock. - - - - - LWLockTranche: The backend is waiting for one of a - group of related lightweight locks. All locks in the group perform - a similar function; wait_event will identify the general - purpose of locks in that group. + LWLock: The backend is waiting for a lightweight lock. + Each such lock protects a particular data structure in shared memory. + wait_event will contain a name identifying the purpose + of the lightweight lock. (Some locks have specific names; others + are part of a group of locks each with a similar purpose.) @@ -679,6 +680,42 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser buffer in question. + + + Activity: The server process is idle. This is used by + system processes waiting for activity in their main processing loop. + wait_event will identify the specific wait point. + + + + + Extension: The server process is waiting for activity + in an extension module. This category is useful for modules to + track custom waiting points. + + + + + Client: The server process is waiting for some activity + on a socket from user applications, and that the server expects + something to happen that is independent from its internal processes. + wait_event will identify the specific wait point. + + + + + IPC: The server process is waiting for some activity + from another process in the server. wait_event will + identify the specific wait point. + + + + + Timeout: The server process is waiting for a timeout + to expire. wait_event will identify the specific wait + point. + + @@ -749,7 +786,9 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser Text of this backend's most recent query. If state is active this field shows the currently executing query. In all other states, it shows the last query - that was executed. + that was executed. By default the query text is truncated at 1024 + characters; this value can be changed via the parameter + . @@ -787,7 +826,7 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser - LWLockNamed + LWLock ShmemIndexLock Waiting to find or allocate space in shared memory. @@ -973,7 +1012,6 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser Waiting to read or update old snapshot control information. - LWLockTranche clog Waiting for I/O on a clog (transaction status) buffer. @@ -1039,6 +1077,10 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser predicate_lock_manager Waiting to add or examine predicate lock information. + + parallel_query_dsa + Waiting for parallel query dynamic shared memory allocation lock. + Lock relation @@ -1085,6 +1127,139 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser BufferPin Waiting to acquire a pin on a buffer. + + Activity + ArchiverMain + Waiting in main loop of the archiver process. + + + AutoVacuumMain + Waiting in main loop of autovacuum launcher process. + + + BgWriterHibernate + Waiting in background writer process, hibernating. + + + BgWriterMain + Waiting in main loop of background writer process background worker. + + + CheckpointerMain + Waiting in main loop of checkpointer process. + + + PgStatMain + Waiting in main loop of the statistics collector process. + + + RecoveryWalAll + Waiting for WAL from any kind of source (local, archive or stream) at recovery. + + + RecoveryWalStream + Waiting for WAL from a stream at recovery. + + + SysLoggerMain + Waiting in main loop of syslogger process. + + + WalReceiverMain + Waiting in main loop of WAL receiver process. + + + WalSenderMain + Waiting in main loop of WAL sender process. + + + WalWriterMain + Waiting in main loop of WAL writer process. + + + Client + ClientRead + Waiting to read data from the client. + + + ClientWrite + Waiting to write data from the client. + + + SSLOpenServer + Waiting for SSL while attempting connection. + + + WalReceiverWaitStart + Waiting for startup process to send initial data for streaming replication. + + + WalSenderWaitForWAL + Waiting for WAL to be flushed in WAL sender process. + + + WalSenderWriteData + Waiting for any activity when processing replies from WAL receiver in WAL sender process. + + + Extension + Extension + Waiting in an extension. + + + IPC + BgWorkerShutdown + Waiting for background worker to shut down. + + + BgWorkerStartup + Waiting for background worker to start up. + + + ExecuteGather + Waiting for activity from child process when executing Gather node. + + + MessageQueueInternal + Waiting for other process to be attached in shared message queue. + + + MessageQueuePutMessage + Waiting to write a protoocol message to a shared message queue. + + + MessageQueueReceive + Waiting to receive bytes from a shared message queue. + + + MessageQueueSend + Waiting to send bytes to a shared message queue. + + + ParallelFinish + Waiting for parallel workers to finish computing. + + + SafeSnapshot + Waiting for a snapshot for a READ ONLY DEFERRABLE transaction. + + + SyncRep + Waiting for confirmation from remote server during synchronous replication. + + + Timeout + BaseBackupThrottle + Waiting during base backup when throttling activity. + + + PgSleep + Waiting in process that called pg_sleep. + + + RecoveryApplyDelay + Waiting to apply WAL at recovery because it is delayed. + @@ -1108,7 +1283,7 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i pid | wait_event_type | wait_event ------+-----------------+--------------- 2540 | Lock | relation - 6644 | LWLockNamed | ProcArrayLock + 6644 | LWLock | ProcArrayLock (2 rows) @@ -1186,7 +1361,33 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i state text - Current WAL sender state + Current WAL sender state. + Possible values are: + + + + startup: This WAL sender is starting up. + + + + + catchup: This WAL sender's connected standby is + catching up with the primary. + + + + + streaming: This WAL sender is streaming changes + after its connected standby server has caught up with the primary. + + + + + backup: This WAL sender is sending a backup. + + + + sent_location @@ -1215,12 +1416,40 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i sync_priority integer Priority of this standby server for being chosen as the - synchronous standby + synchronous standby in a priority-based synchronous replication. + This has no effect in a quorum-based synchronous replication. sync_state text - Synchronous state of this standby server + Synchronous state of this standby server. + Possible values are: + + + + async: This standby server is asynchronous. + + + + + potential: This standby server is now asynchronous, + but can potentially become synchronous if one of current + synchronous ones fails. + + + + + sync: This standby server is synchronous. + + + + + quorum: This standby server is considered as a candidate + for quorum standbys. + + + + @@ -1324,6 +1553,72 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i connected server. + + <structname>pg_stat_subscription</structname> View + + + + Column + Type + Description + + + + + + subid + oid + OID of the subscription + + + subname + text + Name of the subscription + + + pid + integer + Process ID of the subscription worker process + + + received_lsn + pg_lsn + Last transaction log position received, the initial value of + this field being 0 + + + last_msg_send_time + timestamp with time zone + Send time of last message received from origin WAL sender + + + last_msg_receipt_time + timestamp with time zone + Receipt time of last message received from origin WAL sender + + + + latest_end_lsn + pg_lsn + Last transaction log position reported to origin WAL sender + + + + latest_end_time + timestamp with time zone + Time of last transaction log position reported to origin WAL + sender + + + +
+ + + The pg_stat_subscription view will contain one + row per subscription for main worker (with null PID if the worker is + not running). + + <structname>pg_stat_ssl</structname> View @@ -2739,7 +3034,7 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid, Currently, the DTrace utility is supported, which, at the time of this writing, is available - on Solaris, OS X, FreeBSD, NetBSD, and Oracle Linux. The + on Solaris, macOS, FreeBSD, NetBSD, and Oracle Linux. The SystemTap project for Linux provides a DTrace equivalent and can also be used. Supporting other dynamic tracing utilities is theoretically possible by changing the definitions for @@ -3129,55 +3424,49 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid, lwlock-acquire - (char *, int, LWLockMode) + (char *, LWLockMode) Probe that fires when an LWLock has been acquired. arg0 is the LWLock's tranche. - arg1 is the LWLock's offset within its tranche. - arg2 is the requested lock mode, either exclusive or shared. + arg1 is the requested lock mode, either exclusive or shared. lwlock-release - (char *, int) + (char *) Probe that fires when an LWLock has been released (but note that any released waiters have not yet been awakened). - arg0 is the LWLock's tranche. - arg1 is the LWLock's offset within its tranche. + arg0 is the LWLock's tranche. lwlock-wait-start - (char *, int, LWLockMode) + (char *, LWLockMode) Probe that fires when an LWLock was not immediately available and a server process has begun to wait for the lock to become available. arg0 is the LWLock's tranche. - arg1 is the LWLock's offset within its tranche. - arg2 is the requested lock mode, either exclusive or shared. + arg1 is the requested lock mode, either exclusive or shared. lwlock-wait-done - (char *, int, LWLockMode) + (char *, LWLockMode) Probe that fires when a server process has been released from its wait for an LWLock (it does not actually have the lock yet). arg0 is the LWLock's tranche. - arg1 is the LWLock's offset within its tranche. - arg2 is the requested lock mode, either exclusive or shared. + arg1 is the requested lock mode, either exclusive or shared. lwlock-condacquire - (char *, int, LWLockMode) + (char *, LWLockMode) Probe that fires when an LWLock was successfully acquired when the caller specified no waiting. arg0 is the LWLock's tranche. - arg1 is the LWLock's offset within its tranche. - arg2 is the requested lock mode, either exclusive or shared. + arg1 is the requested lock mode, either exclusive or shared. lwlock-condacquire-fail - (char *, int, LWLockMode) + (char *, LWLockMode) Probe that fires when an LWLock was not successfully acquired when the caller specified no waiting. arg0 is the LWLock's tranche. - arg1 is the LWLock's offset within its tranche. - arg2 is the requested lock mode, either exclusive or shared. + arg1 is the requested lock mode, either exclusive or shared. lock-wait-start diff --git a/doc/src/sgml/pageinspect.sgml b/doc/src/sgml/pageinspect.sgml index 5d187ede3a..d12dbac32d 100644 --- a/doc/src/sgml/pageinspect.sgml +++ b/doc/src/sgml/pageinspect.sgml @@ -14,7 +14,7 @@ - Functions + General Functions @@ -160,7 +160,36 @@ test=# SELECT * FROM heap_page_item_attrs(get_raw_page('pg_class', 0), 'pg_class - + + + + fsm_page_contents(page bytea) returns text + + fsm_page_contents + + + + + + fsm_page_contents shows the internal node structure + of a FSM page. The output is a multiline string, with one line per + node in the binary tree within the page. Only those nodes that are not + zero are printed. The so-called "next" pointer, which points to the + next slot to be returned from the page, is also printed. + + + See src/backend/storage/freespace/README for more + information on the structure of an FSM page. + + + + + + + + B-tree Functions + + bt_metap(relname text) returns record @@ -261,7 +290,13 @@ test=# SELECT * FROM bt_page_items('pg_cast_oid_index', 1); + + + + BRIN Functions + + brin_page_type(page bytea) returns text @@ -321,7 +356,7 @@ test=# SELECT * FROM brin_metapage_info(get_raw_page('brinidx', 0)); identifiers in a BRIN index range map page. For example: -test=# SELECT * FROM brin_revmap_data(get_raw_page('brinidx', 2)) limit 5; +test=# SELECT * FROM brin_revmap_data(get_raw_page('brinidx', 2)) LIMIT 5; pages --------- (6,137) @@ -365,7 +400,13 @@ test=# SELECT * FROM brin_page_items(get_raw_page('brinidx', 5), + + + + + GIN Functions + gin_metapage_info(page bytea) returns record @@ -433,7 +474,7 @@ test=# SELECT * FROM gin_page_opaque_info(get_raw_page('gin_index', 2)); gin_leafpage_items returns information about the data stored in a GIN leaf page. For example: -test=# SELECT first_tid, nbytes, tids[0:5] as some_tids +test=# SELECT first_tid, nbytes, tids[0:5] AS some_tids FROM gin_leafpage_items(get_raw_page('gin_test_idx', 2)); first_tid | nbytes | some_tids -----------+--------+---------------------------------------------------------- @@ -449,29 +490,6 @@ test=# SELECT first_tid, nbytes, tids[0:5] as some_tids - - - - fsm_page_contents(page bytea) returns text - - fsm_page_contents - - - - - - fsm_page_contents shows the internal node structure - of a FSM page. The output is a multiline string, with one line per - node in the binary tree within the page. Only those nodes that are not - zero are printed. The so-called "next" pointer, which points to the - next slot to be returned from the page, is also printed. - - - See src/backend/storage/freespace/README for more - information on the structure of an FSM page. - - - diff --git a/doc/src/sgml/parallel.sgml b/doc/src/sgml/parallel.sgml new file mode 100644 index 0000000000..5d4bb211c1 --- /dev/null +++ b/doc/src/sgml/parallel.sgml @@ -0,0 +1,490 @@ + + + + Parallel Query + + + parallel query + + + + PostgreSQL can devise query plans which can leverage + multiple CPUs in order to answer queries faster. This feature is known + as parallel query. Many queries cannot benefit from parallel query, either + due to limitations of the current implementation or because there is no + imaginable query plan which is any faster than the serial query plan. + However, for queries that can benefit, the speedup from parallel query + is often very significant. Many queries can run more than twice as fast + when using parallel query, and some queries can run four times faster or + even more. Queries that touch a large amount of data but return only a + few rows to the user will typically benefit most. This chapter explains + some details of how parallel query works and in which situations it can be + used so that users who wish to make use of it can understand what to expect. + + + + How Parallel Query Works + + + When the optimizer determines that parallel query is the fastest execution + strategy for a particular query, it will create a query plan which includes + a Gather node. Here is a simple example: + + +EXPLAIN SELECT * FROM pgbench_accounts WHERE filler LIKE '%x%'; + QUERY PLAN +------------------------------------------------------------------------------------- + Gather (cost=1000.00..217018.43 rows=1 width=97) + Workers Planned: 2 + -> Parallel Seq Scan on pgbench_accounts (cost=0.00..216018.33 rows=1 width=97) + Filter: (filler ~~ '%x%'::text) +(4 rows) + + + + + In all cases, the Gather node will have exactly one + child plan, which is the portion of the plan that will be executed in + parallel. If the Gather node is at the very top of the plan + tree, then the entire query will execute in parallel. If it is somewhere + else in the plan tree, then only the portion of the plan below it will run + in parallel. In the example above, the query accesses only one table, so + there is only one plan node other than the Gather node itself; + since that plan node is a child of the Gather node, it will + run in parallel. + + + + Using EXPLAIN, you can see the number of + workers chosen by the planner. When the Gather node is reached + during query execution, the process which is implementing the user's + session will request a number of background + worker processes equal to the number + of workers chosen by the planner. The total number of background + workers that can exist at any one time is limited by both + and + , so it is possible for a + parallel query to run with fewer workers than planned, or even with + no workers at all. The optimal plan may depend on the number of workers + that are available, so this can result in poor query performance. If this + occurrence is frequent, considering increasing + max_worker_processes and max_parallel_workers + so that more workers can be run simultaneously or alternatively reducing + so that the planner + requests fewer workers. + + + + Every background worker process which is successfully started for a given + parallel query will execute the portion of the plan below + the Gather node. The leader will also execute that portion + of the plan, but it has an additional responsibility: it must also read + all of the tuples generated by the workers. When the parallel portion of + the plan generates only a small number of tuples, the leader will often + behave very much like an additional worker, speeding up query execution. + Conversely, when the parallel portion of the plan generates a large number + of tuples, the leader may be almost entirely occupied with reading the + tuples generated by the workers and performing any further processing + steps which are required by plan nodes above the level of the + Gather node. In such cases, the leader will do very + little of the work of executing the parallel portion of the plan. + + + + + When Can Parallel Query Be Used? + + + There are several settings which can cause the query planner not to + generate a parallel query plan under any circumstances. In order for + any parallel query plans whatsoever to be generated, the following + settings must be configured as indicated. + + + + + + must be set to a + value which is greater than zero. This is a special case of the more + general principle that no more workers should be used than the number + configured via max_parallel_workers_per_gather. + + + + + + must be set to a + value other than none. Parallel query requires dynamic + shared memory in order to pass data between cooperating processes. + + + + + + In addition, the system must not be running in single-user mode. Since + the entire database system is running in single process in this situation, + no background workers will be available. + + + + Even when it is in general possible for parallel query plans to be + generated, the planner will not generate them for a given query + if any of the following are true: + + + + + + The query writes any data or locks any database rows. If a query + contains a data-modifying operation either at the top level or within + a CTE, no parallel plans for that query will be generated. This is a + limitation of the current implementation which could be lifted in a + future release. + + + + + + The query might be suspended during execution. In any situation in + which the system thinks that partial or incremental execution might + occur, no parallel plan is generated. For example, a cursor created + using DECLARE CURSOR will never use + a parallel plan. Similarly, a PL/pgsql loop of the form + FOR x IN query LOOP .. END LOOP will never use a + parallel plan, because the parallel query system is unable to verify + that the code in the loop is safe to execute while parallel query is + active. + + + + + + The query uses any function marked PARALLEL UNSAFE. + Most system-defined functions are PARALLEL SAFE, + but user-defined functions are marked PARALLEL + UNSAFE by default. See the discussion of + . + + + + + + The query is running inside of another query that is already parallel. + For example, if a function called by a parallel query issues an SQL + query itself, that query will never use a parallel plan. This is a + limitation of the current implementation, but it may not be desirable + to remove this limitation, since it could result in a single query + using a very large number of processes. + + + + + + The transaction isolation level is serializable. This is + a limitation of the current implementation. + + + + + + Even when parallel query plan is generated for a particular query, there + are several circumstances under which it will be impossible to execute + that plan in parallel at execution time. If this occurs, the leader + will execute the portion of the plan below the Gather + node entirely by itself, almost as if the Gather node were + not present. This will happen if any of the following conditions are met: + + + + + + No background workers can be obtained because of the limitation that + the total number of background workers cannot exceed + . + + + + + + No background workers can be obtained because of the limitation that + the total number of background workers launched for purposes of + parallel query cannot exceed . + + + + + + The client sends an Execute message with a non-zero fetch count. + See the discussion of the + extended query protocol. + Since libpq currently provides no way to + send such a message, this can only occur when using a client that + does not rely on libpq. If this is a frequent + occurrence, it may be a good idea to set + in sessions + where it is likely, so as to avoid generating query plans that may + be suboptimal when run serially. + + + + + + A prepared statement is executed using a CREATE TABLE .. AS + EXECUTE .. statement. This construct converts what otherwise + would have been a read-only operation into a read-write operation, + making it ineligible for parallel query. + + + + + + The transaction isolation level is serializable. This situation + does not normally arise, because parallel query plans are not + generated when the transaction isolation level is serializable. + However, it can happen if the transaction isolation level is changed to + serializable after the plan is generated and before it is executed. + + + + + + + Parallel Plans + + + Because each worker executes the parallel portion of the plan to + completion, it is not possible to simply take an ordinary query plan + and run it using multiple workers. Each worker would produce a full + copy of the output result set, so the query would not run any faster + than normal but would produce incorrect results. Instead, the parallel + portion of the plan must be what is known internally to the query + optimizer as a partial plan; that is, it must be constructed + so that each process which executes the plan will generate only a + subset of the output rows in such a way that each required output row + is guaranteed to be generated by exactly one of the cooperating processes. + + + + Parallel Scans + + + Currently, the only type of scan which has been modified to work with + parallel query is a sequential scan. Therefore, the driving table in + a parallel plan will always be scanned using a + Parallel Seq Scan. The relation's blocks will be divided + among the cooperating processes. Blocks are handed out one at a + time, so that access to the relation remains sequential. Each process + will visit every tuple on the page assigned to it before requesting a new + page. + + + + + Parallel Joins + + + The driving table may be joined to one or more other tables using nested + loops or hash joins. The outer side of the join may be any kind of + non-parallel plan that is otherwise supported by the planner provided that + it is safe to run within a parallel worker. For example, it may be an + index scan which looks up a value based on a column taken from the inner + table. Each worker will execute the outer side of the plan in full, which + is why merge joins are not supported here. The outer side of a merge join + will often involve sorting the entire inner table; even if it involves an + index, it is unlikely to be productive to have multiple processes each + conduct a full index scan of the inner table. + + + + + Parallel Aggregation + + It is not possible to perform the aggregation portion of a query entirely + in parallel. For example, if a query involves selecting + COUNT(*), each worker could compute a total, but those totals + would need to combined in order to produce a final answer. If the query + involved a GROUP BY clause, a separate total would need to + be computed for each group. Even though aggregation can't be done entirely + in parallel, queries involving aggregation are often excellent candidates + for parallel query, because they typically read many rows but return only + a few rows to the client. Queries that return many rows to the client + are often limited by the speed at which the client can read the data, + in which case parallel query cannot help very much. + + + + PostgreSQL supports parallel aggregation by aggregating + twice. First, each process participating in the parallel portion of the + query performs an aggregation step, producing a partial result for each + group of which that process is aware. This is reflected in the plan as + a PartialAggregate node. Second, the partial results are + transferred to the leader via the Gather node. Finally, the + leader re-aggregates the results across all workers in order to produce + the final result. This is reflected in the plan as a + FinalizeAggregate node. + + + + Parallel aggregation is not supported in all situations. Each aggregate + must be safe for parallelism and must + have a combine function. If the aggregate has a transition state of type + internal, it must have serialization and deserialization + functions. See for more details. + Parallel aggregation is not supported for ordered set aggregates or when + the query involves GROUPING SETS. It can only be used when + all joins involved in the query are also part of the parallel portion + of the plan. + + + + + + Parallel Plan Tips + + + If a query that is expected to do so does not produce a parallel plan, + you can try reducing or + . Of course, this plan may turn + out to be slower than the serial plan which the planner preferred, but + this will not always be the case. If you don't get a parallel + plan even with very small values of these settings (e.g. after setting + them both to zero), there may be some reason why the query planner is + unable to generate a parallel plan for your query. See + and + for information on why this may be + the case. + + + + When executing a parallel plan, you can use EXPLAIN (ANALYZE, + VERBOSE) to display per-worker statistics for each plan node. + This may be useful in determining whether the work is being evenly + distributed between all plan nodes and more generally in understanding the + performance characteristics of the plan. + + + + + + + Parallel Safety + + + The planner classifies operations involved in a query as either + parallel safe, parallel restricted, + or parallel unsafe. A parallel safe operation is one which + does not conflict with the use of parallel query. A parallel restricted + operation is one which cannot be performed in a parallel worker, but which + can be performed in the leader while parallel query is in use. Therefore, + parallel restricted operations can never occur below a Gather + node, but can occur elsewhere in a plan which contains a + Gather node. A parallel unsafe operation is one which cannot + be performed while parallel query is in use, not even in the leader. + When a query contains anything which is parallel unsafe, parallel query + is completely disabled for that query. + + + + The following operations are always parallel restricted. + + + + + + Scans of common table expressions (CTEs). + + + + + + Scans of temporary tables. + + + + + + Scans of foreign tables, unless the foreign data wrapper has + an IsForeignScanParallelSafe API which indicates otherwise. + + + + + + Access to an InitPlan or SubPlan. + + + + + + Parallel Labeling for Functions and Aggregates + + + The planner cannot automatically determine whether a user-defined + function or aggregate is parallel safe, parallel restricted, or parallel + unsafe, because this would require predicting every operation which the + function could possibly perform. In general, this is equivalent to the + Halting Problem and therefore impossible. Even for simple functions + where it conceivably be done, we do not try, since this would be expensive + and error-prone. Instead, all user-defined functions are assumed to + be parallel unsafe unless otherwise marked. When using + or + , markings can be set by specifying + PARALLEL SAFE, PARALLEL RESTRICTED, or + PARALLEL UNSAFE as appropriate. When using + , the + PARALLEL option can be specified with SAFE, + RESTRICTED, or UNSAFE as the corresponding value. + + + + Functions and aggregates must be marked PARALLEL UNSAFE if + they write to the database, access sequences, change the transaction state + even temporarily (e.g. a PL/pgsql function which establishes an + EXCEPTION block to catch errors), or make persistent changes to + settings. Similarly, functions must be marked PARALLEL + RESTRICTED if they access temporary tables, client connection state, + cursors, prepared statements, or miscellaneous backend-local state which + the system cannot synchronize across workers. For example, + setseed and random are parallel restricted for + this last reason. + + + + In general, if a function is labeled as being safe when it is restricted or + unsafe, or if it is labeled as being restricted when it is in fact unsafe, + it may throw errors or produce wrong answers when used in a parallel query. + C-language functions could in theory exhibit totally undefined behavior if + mislabeled, since there is no way for the system to protect itself against + arbitrary C code, but in most likely cases the result will be no worse than + for any other function. If in doubt, it is probably best to label functions + as UNSAFE. + + + + If a function executed within a parallel worker acquires locks which are + not held by the leader, for example by querying a table not referenced in + the query, those locks will be released at worker exit, not end of + transaction. If you write a function which does this, and this behavior + difference is important to you, mark such functions as + PARALLEL RESTRICTED + to ensure that they execute only in the leader. + + + + Note that the query planner does not consider deferring the evaluation of + parallel-restricted functions or aggregates involved in the query in + order to obtain a superior plan. So, for example, if a WHERE + clause applied to a particular table is parallel restricted, the query + planner will not consider placing the scan of that table below a + Gather node. In some cases, it would be + possible (and perhaps even efficient) to include the scan of that table in + the parallel portion of the query and defer the evaluation of the + WHERE clause so that it happens above the Gather + node. However, the planner does not do this. + + + + + + + diff --git a/doc/src/sgml/perform.sgml b/doc/src/sgml/perform.sgml index 7bcbfa7611..8d30fd1384 100644 --- a/doc/src/sgml/perform.sgml +++ b/doc/src/sgml/perform.sgml @@ -1612,7 +1612,7 @@ SELECT * FROM x, y, a, b, c WHERE something AND somethingelse; Increase and ; this reduces the frequency of checkpoints, but increases the storage requirements of - /pg_xlog. + /pg_wal. diff --git a/doc/src/sgml/pgcrypto.sgml b/doc/src/sgml/pgcrypto.sgml index c4cefde4f7..bf514aacf3 100644 --- a/doc/src/sgml/pgcrypto.sgml +++ b/doc/src/sgml/pgcrypto.sgml @@ -1184,12 +1184,12 @@ gen_random_uuid() returns uuid SHA224/256/384/512 yes - yes (Note 1) + yes Other digest algorithms no - yes (Note 2) + yes (Note 1) Blowfish @@ -1199,7 +1199,7 @@ gen_random_uuid() returns uuid AES yes - yes (Note 3) + yes DES/3DES/CAST5 @@ -1230,12 +1230,6 @@ gen_random_uuid() returns uuid - - - SHA2 algorithms were added to OpenSSL in version 0.9.8. For - older versions, pgcrypto will use built-in code. - - Any digest algorithm OpenSSL supports is automatically picked up. @@ -1243,12 +1237,6 @@ gen_random_uuid() returns uuid explicitly. - - - AES is included in OpenSSL since version 0.9.7. For - older versions, pgcrypto will use built-in code. - - diff --git a/doc/src/sgml/pgstandby.sgml b/doc/src/sgml/pgstandby.sgml index fb3f32eaaa..80c6f60062 100644 --- a/doc/src/sgml/pgstandby.sgml +++ b/doc/src/sgml/pgstandby.sgml @@ -363,7 +363,7 @@ recovery_end_command = 'del C:\pgsql.trigger.5442' The copy command on Windows sets the final file size before the file is completely copied, which would ordinarily confuse pg_standby. Therefore - pg_standby waits sleeptime + pg_standby waits sleeptime seconds once it sees the proper file size. GNUWin32's cp sets the file size only after the file copy is complete. diff --git a/doc/src/sgml/pgstattuple.sgml b/doc/src/sgml/pgstattuple.sgml index 61340bedbc..d2fa524d6e 100644 --- a/doc/src/sgml/pgstattuple.sgml +++ b/doc/src/sgml/pgstattuple.sgml @@ -12,6 +12,14 @@ obtain tuple-level statistics. + + As these functions return detailed page-level information, only the superuser + has EXECUTE privileges on them upon installation. After the functions have + been installed, users may issue GRANT commands to change + the privileges on the functions to allow non-superusers to execute them. See + the description of the command for specifics. + + Functions @@ -109,6 +117,16 @@ free_percent | 1.95
+ + + The table_len will always be greater than the sum + of the tuple_len, dead_tuple_len + and free_space. The difference is accounted for by + fixed page overhead, the per-page table of pointers to tuples, and + padding to ensure that tuples are correctly aligned. + + + pgstattuple acquires only a read lock on the relation. So the results do not reflect an instantaneous snapshot; diff --git a/doc/src/sgml/pgtrgm.sgml b/doc/src/sgml/pgtrgm.sgml index d362b03cf3..775a7b8be7 100644 --- a/doc/src/sgml/pgtrgm.sgml +++ b/doc/src/sgml/pgtrgm.sgml @@ -104,7 +104,7 @@ the second string a most similar word not a most similar substring. The range of the result is zero (indicating that the two strings are completely dissimilar) to one (indicating that the first string is - identical to one of the word of the second string). + identical to one of the words of the second string). diff --git a/doc/src/sgml/pgvisibility.sgml b/doc/src/sgml/pgvisibility.sgml index d764eff9a0..fd486696fc 100644 --- a/doc/src/sgml/pgvisibility.sgml +++ b/doc/src/sgml/pgvisibility.sgml @@ -9,31 +9,33 @@ The pg_visibility module provides a means for examining the - visibility map (VM) and page-level visibility information. It also - provides functions to check the integrity of the visibility map and to + visibility map (VM) and page-level visibility information of a table. + It also provides functions to check the integrity of a visibility map and to force it to be rebuilt. Three different bits are used to store information about page-level visibility. The all-visible bit in the visibility map indicates that every - tuple on a given page of a relation is visible to every current transaction. - The all-frozen bit in the visibility map indicates that every tuple on the - page is frozen; that is, no future vacuum will need to modify the page - until such time as a tuple is inserted, updated, deleted, or locked on - that page. The page-level PD_ALL_VISIBLE bit has the + tuple in the corresponding page of the relation is visible to every current + and future transaction. The all-frozen bit in the visibility map indicates + that every tuple in the page is frozen; that is, no future vacuum will need + to modify the page until such time as a tuple is inserted, updated, deleted, + or locked on that page. + The page header's PD_ALL_VISIBLE bit has the same meaning as the all-visible bit in the visibility map, but is stored - within the data page itself rather than a separate data structure. These - will normally agree, but the page-level bit can sometimes be set while the - visibility map bit is clear after a crash recovery; or they can disagree - because of a change which occurs after pg_visibility examines - the visibility map and before it examines the data page. Any event which - causes data corruption can also cause these bits to disagree. + within the data page itself rather than in a separate data structure. + These two bits will normally agree, but the page's all-visible bit can + sometimes be set while the visibility map bit is clear after a crash + recovery. The reported values can also disagree because of a change that + occurs after pg_visibility examines the visibility map and + before it examines the data page. Any event that causes data corruption + can also cause these bits to disagree. - Functions which display information about PD_ALL_VISIBLE - are much more costly than those which only consult the visibility map, + Functions that display information about PD_ALL_VISIBLE bits + are much more costly than those that only consult the visibility map, because they must read the relation's data blocks rather than only the (much smaller) visibility map. Functions that check the relation's data blocks are similarly expensive. @@ -44,7 +46,7 @@ - pg_visibility_map(regclass, blkno bigint, all_visible OUT boolean, all_frozen OUT boolean) returns record + pg_visibility_map(relation regclass, blkno bigint, all_visible OUT boolean, all_frozen OUT boolean) returns record Returns the all-visible and all-frozen bits in the visibility map for @@ -54,40 +56,40 @@ - pg_visibility(regclass, blkno bigint, all_visible OUT boolean, all_frozen OUT boolean, pd_all_visible OUT boolean) returns record + pg_visibility(relation regclass, blkno bigint, all_visible OUT boolean, all_frozen OUT boolean, pd_all_visible OUT boolean) returns record Returns the all-visible and all-frozen bits in the visibility map for the given block of the given relation, plus the - PD_ALL_VISIBLE bit for that block. + PD_ALL_VISIBLE bit of that block. - pg_visibility_map(regclass, blkno OUT bigint, all_visible OUT boolean, all_frozen OUT boolean) returns setof record + pg_visibility_map(relation regclass, blkno OUT bigint, all_visible OUT boolean, all_frozen OUT boolean) returns setof record Returns the all-visible and all-frozen bits in the visibility map for - each block the given relation. + each block of the given relation. - pg_visibility(regclass, blkno OUT bigint, all_visible OUT boolean, all_frozen OUT boolean, pd_all_visible OUT boolean) returns setof record + pg_visibility(relation regclass, blkno OUT bigint, all_visible OUT boolean, all_frozen OUT boolean, pd_all_visible OUT boolean) returns setof record Returns the all-visible and all-frozen bits in the visibility map for - each block the given relation, plus the PD_ALL_VISIBLE - bit for each block. + each block of the given relation, plus the PD_ALL_VISIBLE + bit of each block. - pg_visibility_map_summary(regclass, all_visible OUT bigint, all_frozen OUT bigint) returns record + pg_visibility_map_summary(relation regclass, all_visible OUT bigint, all_frozen OUT bigint) returns record @@ -96,50 +98,49 @@ - + - pg_check_frozen(regclass, t_ctid OUT tid) returns setof tid + pg_check_frozen(relation regclass, t_ctid OUT tid) returns setof tid - Returns the TIDs of non-frozen tuples present in pages marked all-frozen + Returns the TIDs of non-frozen tuples stored in pages marked all-frozen in the visibility map. If this function returns a non-empty set of - TIDs, the database is corrupt. + TIDs, the visibility map is corrupt. - - - pg_check_visible(regclass, t_ctid OUT tid) returns setof tid + + + pg_check_visible(relation regclass, t_ctid OUT tid) returns setof tid - Returns the TIDs of tuples which are not all-visible despite the fact - that the pages which contain them are marked as all-visible in the - visibility map. If this function returns a non-empty set of TIDs, the - database is corrupt. + Returns the TIDs of non-all-visible tuples stored in pages marked + all-visible in the visibility map. If this function returns a non-empty + set of TIDs, the visibility map is corrupt. - pg_truncate_visibility_map(regclass) returns void + pg_truncate_visibility_map(relation regclass) returns void - Truncates the visibility map for the given relation. This function - is only expected to be useful if you suspect that the visibility map - for the indicated relation is corrupt and wish to rebuild it. The first - VACUUM executed on the given relation after this function - is executed will scan every page in the relation and rebuild the - visibility map. + Truncates the visibility map for the given relation. This function is + useful if you believe that the visibility map for the relation is + corrupt and wish to force rebuilding it. The first VACUUM + executed on the given relation after this function is executed will scan + every page in the relation and rebuild the visibility map. (Until that + is done, queries will treat the visibility map as containing all zeroes.) - By default, these functions are not publicly executable. + By default, these functions are executable only by superusers. diff --git a/doc/src/sgml/plpython.sgml b/doc/src/sgml/plpython.sgml index 905e757ab6..46397781be 100644 --- a/doc/src/sgml/plpython.sgml +++ b/doc/src/sgml/plpython.sgml @@ -451,13 +451,13 @@ $$ LANGUAGE plpythonu; SQL array values are passed into PL/Python as a Python list. To return an SQL array value out of a PL/Python function, return a - Python sequence, for example a list or tuple: + Python list: CREATE FUNCTION return_arr() RETURNS int[] AS $$ -return (1, 2, 3, 4, 5) +return [1, 2, 3, 4, 5] $$ LANGUAGE plpythonu; SELECT return_arr(); @@ -467,6 +467,34 @@ SELECT return_arr(); (1 row) + Multidimensional arrays are passed into PL/Python as nested Python lists. + A 2-dimensional array is a list of lists, for example. When returning + a multi-dimensional SQL array out of a PL/Python function, the inner + lists at each level must all be of the same size. For example: + + +CREATE FUNCTION test_type_conversion_array_int4(x int4[]) RETURNS int4[] AS $$ +plpy.info(x, type(x)) +return x +$$ LANGUAGE plpythonu; + +SELECT * FROM test_type_conversion_array_int4(ARRAY[[1,2,3],[4,5,6]]); +INFO: ([[1, 2, 3], [4, 5, 6]], <type 'list'>) + test_type_conversion_array_int4 +--------------------------------- + {{1,2,3},{4,5,6}} +(1 row) + + + Other Python sequences, like tuples, are also accepted for + backwards-compatibility with PostgreSQL versions 9.6 and below, when + multi-dimensional arrays were not supported. However, they are always + treated as one-dimensional arrays, because they are ambiguous with + composite types. For the same reason, when a composite type is used in a + multi-dimensional array, it must be represented by a tuple, rather than a + list. + + Note that in Python, strings are sequences, which can have undesirable effects that might be familiar to Python programmers: @@ -541,14 +569,19 @@ CREATE TYPE named_value AS ( CREATE FUNCTION make_pair (name text, value integer) RETURNS named_value AS $$ - return [ name, value ] - # or alternatively, as tuple: return ( name, value ) + return ( name, value ) + # or alternatively, as tuple: return [ name, value ] $$ LANGUAGE plpythonu; To return a SQL null for any column, insert None at the corresponding position. + + When an array of composite types is returned, it cannot be returned as a list, + because it is ambiguous whether the Python list represents a composite type, + or another array dimension. + @@ -696,19 +729,6 @@ AS $$ $$ LANGUAGE plpythonu; - - - Due to Python - bug #1483133, - some debug versions of Python 2.4 - (configured and compiled with option --with-pydebug) - are known to crash the PostgreSQL server - when using an iterator to return a set result. - Unpatched versions of Fedora 4 contain this bug. - It does not happen in production versions of Python or on patched - versions of Fedora 4. - - diff --git a/doc/src/sgml/pltcl.sgml b/doc/src/sgml/pltcl.sgml index 805cc89dc9..8afaf4ad36 100644 --- a/doc/src/sgml/pltcl.sgml +++ b/doc/src/sgml/pltcl.sgml @@ -94,11 +94,11 @@ $$ LANGUAGE pltcl; The body of the function is simply a piece of Tcl script. - When the function is called, the argument values are passed as - variables $1 ... $n to the - Tcl script. The result is returned - from the Tcl code in the usual way, with a return - statement. + When the function is called, the argument values are passed to the + Tcl script as variables named 1 + ... n. The result is + returned from the Tcl code in the usual way, with + a return statement. @@ -173,17 +173,57 @@ $$ LANGUAGE pltcl; - There is currently no support for returning a composite-type - result value, nor for returning sets. + PL/Tcl functions can return composite-type results, too. To do this, + the Tcl code must return a list of column name/value pairs matching + the expected result type. Any column names omitted from the list + are returned as nulls, and an error is raised if there are unexpected + column names. Here is an example: + + +CREATE FUNCTION square_cube(in int, out squared int, out cubed int) AS $$ + return [list squared [expr {$1 * $1}] cubed [expr {$1 * $1 * $1}]] +$$ LANGUAGE pltcl; + + + + The result list can be made from an array representation of the + desired tuple with the array get Tcl command. For example: + + +CREATE FUNCTION raise_pay(employee, delta int) RETURNS employee AS $$ + set 1(salary) [expr {$1(salary) + $2}] + return [array get 1] +$$ LANGUAGE pltcl; + + + + - PL/Tcl does not currently have full support for - domain types: it treats a domain the same as the underlying scalar - type. This means that constraints associated with the domain will - not be enforced. This is not an issue for function arguments, but - it is a hazard if you declare a PL/Tcl function - as returning a domain type. + PL/Tcl functions can return sets. To do this, the Tcl code should + call return_next once per row to be returned, + passing either the appropriate value when returning a scalar type, + or a list of column name/value pairs when returning a composite type. + Here is an example returning a scalar type: + + +CREATE FUNCTION sequence(int, int) RETURNS SETOF int AS $$ + for {set i $1} {$i < $2} {incr i} { + return_next $i + } +$$ LANGUAGE pltcl; + + + and here is one returning a composite type: + + +CREATE FUNCTION table_of_squares(int, int) RETURNS TABLE (x int, x2 int) AS $$ + for {set i $1} {$i < $2} {incr i} { + return_next [list x $i x2 [expr {$i * $i}]] + } +$$ LANGUAGE pltcl; + @@ -195,10 +235,9 @@ $$ LANGUAGE pltcl; The argument values supplied to a PL/Tcl function's code are simply the input arguments converted to text form (just as if they had been displayed by a SELECT statement). Conversely, the - return - command will accept any string that is acceptable input format for - the function's declared return type. So, within the PL/Tcl function, - all values are just text strings. + return and return_next commands will accept + any string that is acceptable input format for the function's declared + result type, or for the specified column of a composite result type. @@ -296,20 +335,22 @@ $$ LANGUAGE pltcl; If the command is a SELECT statement, the values of the result columns are placed into Tcl variables named after the columns. If the -array option is given, the column values are - instead stored into the named associative array, with the - column names used as array indexes. + instead stored into elements of the named associative array, with the + column names used as array indexes. In addition, the current row + number within the result (counting from zero) is stored into the array + element named .tupno, unless that name is + in use as a column name in the result.
If the command is a SELECT statement and no loop-body script is given, then only the first row of results are stored into - Tcl variables; remaining rows, if any, are ignored. No storing occurs - if the - query returns no rows. (This case can be detected by checking the - result of spi_exec.) For example: + Tcl variables or array elements; remaining rows, if any, are ignored. + No storing occurs if the query returns no rows. (This case can be + detected by checking the result of spi_exec.) + For example: spi_exec "SELECT count(*) AS cnt FROM pg_proc" - will set the Tcl variable $cnt to the number of rows in the pg_proc system catalog. @@ -317,15 +358,15 @@ spi_exec "SELECT count(*) AS cnt FROM pg_proc" If the optional loop-body argument is given, it is a piece of Tcl script that is executed once for each row in the query result. (loop-body is ignored if the given - command is not a SELECT.) The values of the current row's columns - are stored into Tcl variables before each iteration. For example: - + command is not a SELECT.) + The values of the current row's columns + are stored into Tcl variables or array elements before each iteration. + For example: spi_exec -array C "SELECT * FROM pg_class" { elog DEBUG "have table $C(relname)" } - will print a log message for every row of pg_class. This feature works similarly to other Tcl looping constructs; in particular continue and break work in the @@ -667,21 +708,35 @@ SELECT 'doesn''t' AS ret The return value from a trigger procedure can be one of the strings - OK or SKIP, or a list as returned by the - array get Tcl command. If the return value is OK, - the operation (INSERT/UPDATE/DELETE) that fired the trigger will proceed + OK or SKIP, or a list of column name/value pairs. + If the return value is OK, + the operation (INSERT/UPDATE/DELETE) + that fired the trigger will proceed normally. SKIP tells the trigger manager to silently suppress the operation for this row. If a list is returned, it tells PL/Tcl to - return a modified row to the trigger manager. This is only meaningful + return a modified row to the trigger manager; the contents of the + modified row are specified by the column names and values in the list. + Any columns not mentioned in the list are set to null. + Returning a modified row is only meaningful for row-level BEFORE INSERT or UPDATE - triggers for which the modified row will be inserted instead of the one + triggers, for which the modified row will be inserted instead of the one given in $NEW; or for row-level INSTEAD OF INSERT or UPDATE triggers where the returned row - is used to support INSERT RETURNING and - UPDATE RETURNING commands. The return value is ignored for - other types of triggers. + is used as the source data for INSERT RETURNING or + UPDATE RETURNING clauses. + In row-level BEFORE DELETE or INSTEAD + OF DELETE triggers, returning a modified row has the same + effect as returning OK, that is the operation proceeds. + The trigger return value is ignored for all other types of triggers. + + + The result list can be made from an array representation of the + modified tuple with the array get Tcl command. + + + Here's a little example trigger procedure that forces an integer value in a table to keep track of the number of updates that are performed on the diff --git a/doc/src/sgml/postgres.sgml b/doc/src/sgml/postgres.sgml index 0346d367e5..4e169d1b18 100644 --- a/doc/src/sgml/postgres.sgml +++ b/doc/src/sgml/postgres.sgml @@ -106,6 +106,7 @@ &textsearch; &mvcc; &perform; + ∥ @@ -159,6 +160,7 @@ &monitoring; &diskusage; &wal; + &logical-replication; ®ress; diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml index 9c96d8fc44..5f89db5857 100644 --- a/doc/src/sgml/protocol.sgml +++ b/doc/src/sgml/protocol.sgml @@ -1434,7 +1434,7 @@ The commands accepted in walsender mode are: - CREATE_REPLICATION_SLOT slot_name { PHYSICAL [ RESERVE_WAL ] | LOGICAL output_plugin } + CREATE_REPLICATION_SLOT slot_name [ TEMPORARY ] { PHYSICAL [ RESERVE_WAL ] | LOGICAL output_plugin } CREATE_REPLICATION_SLOT @@ -1464,6 +1464,17 @@ The commands accepted in walsender mode are: + + TEMPORARY + + + Specify that this replication slot is a temporary one. Temporary + slots are not saved to disk and are automatically dropped on error + or when the session has finished. + + + + RESERVE_WAL @@ -1947,7 +1958,7 @@ The commands accepted in walsender mode are: Include the necessary WAL segments in the backup. This will include all the files between start and stop backup in the - pg_xlog directory of the base directory tar + pg_wal directory of the base directory tar file. @@ -2069,26 +2080,33 @@ The commands accepted in walsender mode are: - various temporary files created during the operation of the PostgreSQL server + Various temporary files and directories created during the operation + of the PostgreSQL server, such as any file or directory beginning + with pgsql_tmp. - pg_xlog, including subdirectories. If the backup is run - with WAL files included, a synthesized version of pg_xlog will be + pg_wal, including subdirectories. If the backup is run + with WAL files included, a synthesized version of pg_wal will be included, but it will only contain the files necessary for the backup to work, not the rest of the contents. - pg_replslot is copied as an empty directory. + pg_dynshmem, pg_notify, + pg_replslot, pg_serial, + pg_snapshots, pg_stat_tmp, and + pg_subtrans are copied as empty directories (even if + they are symbolic links). Files other than regular files and directories, such as symbolic - links and special device files, are skipped. (Symbolic links + links (other than for the directories listed above) and special + device files, are skipped. (Symbolic links in pg_tblspc are maintained.) @@ -2104,6 +2122,119 @@ The commands accepted in walsender mode are: + + Logical Streaming Replication Protocol + + + This section describes the logical replication protocol, which is the message + flow started by the START_REPLICATION + SLOT slot_name + LOGICAL replication command. + + + + The logical streaming replication protocol builds on the primitives of + the physical streaming replication protocol. + + + + Logical Streaming Replication Parameters + + + The logical replication START_REPLICATION command + accepts following parameters: + + + + + proto_version + + + + Protocol version. Currently only version 1 is + supported. + + + + + + + publication_names + + + + Comma separated list of publication names for which to subscribe + (receive changes). The individual publication names are treated + as standard objects names and can be quoted the same as needed. + + + + + + + + + + Logical Replication Protocol Messages + + + The individual protocol messages are discussed in the following + subsections. Individual messages are describer in + section. + + + + All top-level protocol messages begin with a message type byte. + While represented in code as a character, this is a signed byte with no + associated encoding. + + + + Since the streaming replication protocol supplies a message length there + is no need for top-level protocol messages to embed a length in their + header. + + + + + + Logical Replication Protocol Message Flow + + + With the exception of the START_REPLICATION command and + the replay progress messages, all information flows only from the backend + to the frontend. + + + + The logical replication protocol sends individual transactions one by one. + This means that all messages between a pair of Begin and Commit messages + belong to the same transaction. + + + + Every sent transaction contains zero or more DML messages (Insert, + Update, Delete). In case of a cascaded setup it can also contain Origin + messages. The origin message indicated that the transaction originated on + different replication node. Since a replication node in the scope of logical + replication protocol can be pretty much anything, the only identifier + is the origin name. It's downstream's responsibility to handle this as + needed (if needed). The Origin message is always sent before any DML + messages in the transaction. + + + + Every DML message contains an arbitrary relation ID, which can be mapped to + an ID in the Relation messages. The Relation messages describe the schema of the + given relation. The Relation message is sent for a given relation either + because it is the first time we send a DML message for given relation in the + current session or because the relation definition has changed since the + last Relation message was sent for it. The protocol assumes that the client + is capable of caching the metadata for as many relations as needed. + + + + Message Data Types @@ -4882,6 +5013,25 @@ message. + + +V + + + + Severity: the field contents are + ERROR, FATAL, or + PANIC (in an error message), or + WARNING, NOTICE, DEBUG, + INFO, or LOG (in a notice message). + This is identical to the S field except + that the contents are never localized. This is present only in + messages generated by PostgreSQL versions 9.6 + and later. + + + + C @@ -5112,6 +5262,614 @@ not line breaks. + +Logical Replication Message Formats + + +This section describes the detailed format of each logical replication message. +These messages are returned either by the replication slot SQL interface or are +sent by a walsender. In case of a walsender they are encapsulated inside the replication +protocol WAL messages as described in +and generally obey same message flow as physical replication. + + + + + + +Begin + + + + + + + + Byte1('B') + + + + Identifies the message as a begin message. + + + + + + Int64 + + + + The final LSN of the transaction. + + + + + + Int64 + + + + Commit timestamp of the transaction. The value is in number + of microseconds since PostgreSQL epoch (2000-01-01). + + + + + + Int32 + + + + Xid of the transaction. + + + + + + + + + + + +Commit + + + + + + + + Byte1('C') + + + + Identifies the message as a commit message. + + + + + + Int64 + + + + The LSN of the commit. + + + + + + Int64 + + + + The end LSN of the transaction. + + + + + + Int64 + + + + Commit timestamp of the transaction. The value is in number + of microseconds since PostgreSQL epoch (2000-01-01). + + + + + + + + + + + +Origin + + + + + + + + Byte1('O') + + + + Identifies the message as an origin message. + + + + + + Int64 + + + + The LSN of the commit on the origin server. + + + + + + String + + + + Name of the origin. + + + + + + + + + Note that there can be multiple Origin messages inside a single transaction. + + + + + + + +Relation + + + + + + + + Byte1('R') + + + + Identifies the message as a relation message. + + + + + + Int32 + + + + ID of the relation. + + + + + + String + + + + Namespace (empty string for pg_catalog). + + + + + + String + + + + Relation name. + + + + + + + Int8 + + + + Replica identity setting for the relation (same as + relreplident in pg_class). + + + + + + + Int16 + + + + Number of columns. + + + + + Next, the following message part appears for each column: + + + + Int8 + + + + Flags for the column. Currently can be either 0 for no flags + or 1 which marks the column as part of the key. + + + + + + String + + + + Name of the column. + + + + + + + + + + + +Insert + + + + + + + + Byte1('I') + + + + Identifies the message as an insert message. + + + + + + Int32 + + + + ID of the relation corresponding to the ID in the relation + message. + + + + + + Byte1('N') + + + + Identifies the following TupleData message as a new tuple. + + + + + + + TupleData + + + + TupleData message part representing the contents of new tuple. + + + + + + + + + + + +Update + + + + + + + + Byte1('U') + + + + Identifies the message as an update message. + + + + + + Int32 + + + + ID of the relation corresponding to the ID in the relation + message. + + + + + + + Byte1('K') + + + + Identifies the following TupleData submessage as a key. + This field is optional and is only present if + the update changed data in any of the column(s) that are + part of the REPLICA IDENTITY index. + + + + + + + Byte1('O') + + + + Identifies the following TupleData submessage as an old tuple. + This field is optional and is only present if table in which + the update happened has REPLICA IDENTITY set to FULL. + + + + + + + TupleData + + + + TupleData message part representing the contents of the old tuple + or primary key. Only present if the previous 'O' or 'K' part + is present. + + + + + + + Byte1('N') + + + + Identifies the following TupleData message as a new tuple. + + + + + + + TupleData + + + + TupleData message part representing the contents of a new tuple. + + + + + + + + + The Update message may contain either a 'K' message part or an 'O' message part + or neither of them, but never both of them. + + + + + + + +Delete + + + + + + + + Byte1('D') + + + + Identifies the message as a delete message. + + + + + + Int32 + + + + ID of the relation corresponding to the ID in the relation + message. + + + + + + + Byte1('K') + + + + Identifies the following TupleData submessage as a key. + This field is present if the table in which the delete has + happened uses an index as REPLICA IDENTITY. + + + + + + + Byte1('O') + + + + Identifies the following TupleData message as a old tuple. + This field is is present if the table in which the delete has + happened has REPLICA IDENTITY set to FULL. + + + + + + + TupleData + + + + TupleData message part representing the contents of the old tuple + or primary key, depending on the previous field. + + + + + + + + The Delete message may contain either a 'K' message part or an 'O' message part, + but never both of them. + + + + + + + + + +Following message parts that are shared by above messages. + + + + + + + +TupleData + + + + + + + + Int16 + + + + Number of columns. + + + + + Next, one of the following submessages appears for each column: + + + + Byte1('n') + + + + Idenfifies the data as NULL value. + + + + + Or + + + + Byte1('u') + + + + Idenfifies unchanged TOASTed value (the actual value is not + sent). + + + + + Or + + + + Byte1('t') + + + + Idenfifies the data as text formatted value. + + + + + + Int32 + + + + Length of the column value. + + + + + + String + + + + The text value. + + + + + + + + + + + + + Summary of Changes since Protocol 2.0 diff --git a/doc/src/sgml/queries.sgml b/doc/src/sgml/queries.sgml index 718262f1aa..ef623d59bd 100644 --- a/doc/src/sgml/queries.sgml +++ b/doc/src/sgml/queries.sgml @@ -145,11 +145,9 @@ FROM table_reference , table_r Instead of writing ONLY before the table name, you can write * after the table name to explicitly specify that descendant - tables are included. Writing * is not necessary since that - behavior is the default (unless you have changed the setting of the configuration option). However writing - * might be useful to emphasize that additional tables will be - searched. + tables are included. There is no real reason to use this syntax any more, + because searching descendant tables is now always the default behavior. + However, it is supported for compatibility with older releases. @@ -1457,7 +1455,8 @@ SELECT tbl1.a, tbl2.a, tbl1.b FROM ... SELECT tbl1.*, tbl2.a FROM ... - (See also .) + See for more about + the table_name.* notation. @@ -2262,7 +2261,8 @@ SELECT * FROM moved_rows; Data-modifying statements in WITH usually have - RETURNING clauses, as seen in the example above. + RETURNING clauses (see ), + as shown in the example above. It is the output of the RETURNING clause, not the target table of the data-modifying statement, that forms the temporary table that can be referred to by the rest of the query. If a diff --git a/doc/src/sgml/recovery-config.sgml b/doc/src/sgml/recovery-config.sgml index 26af221745..8c24ae2174 100644 --- a/doc/src/sgml/recovery-config.sgml +++ b/doc/src/sgml/recovery-config.sgml @@ -157,9 +157,10 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows By default, recovery will recover to the end of the WAL log. The following parameters can be used to specify an earlier stopping point. At most one of recovery_target, - recovery_target_name, recovery_target_time, or - recovery_target_xid can be used; if more than one of these - is specified in the configuration file, the last entry will be used. + recovery_target_lsn, recovery_target_name, + recovery_target_time, or recovery_target_xid + can be used; if more than one of these is specified in the configuration + file, the last entry will be used. @@ -232,6 +233,23 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows + + + recovery_target_lsn (pg_lsn) + + recovery_target_lsn recovery parameter + + + + + This parameter specifies the LSN of the transaction log location up + to which recovery will proceed. The precise stopping point is also + influenced by . This + parameter is parsed using the system data type + pg_lsn. + + + @@ -469,10 +487,17 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows This parameter is intended for use with streaming replication deployments; however, if the parameter is specified it will be honored in all cases. - Synchronous replication is not affected by this setting because there is - not yet any setting to request synchronous apply of transaction commits. + hot_standby_feedback will be delayed by use of this feature which could lead to bloat on the master; use both together with care. + + + + Synchronous replication is affected by this setting when synchronous_commit + is set to remote_apply; every COMMIT + will need to wait to be applied. + + diff --git a/doc/src/sgml/ref/allfiles.sgml b/doc/src/sgml/ref/allfiles.sgml index 77667bdebd..0d09f81ccc 100644 --- a/doc/src/sgml/ref/allfiles.sgml +++ b/doc/src/sgml/ref/allfiles.sgml @@ -26,11 +26,13 @@ Complete list of usable sgml source files in this directory. + + @@ -72,11 +74,13 @@ Complete list of usable sgml source files in this directory. + + @@ -116,11 +120,13 @@ Complete list of usable sgml source files in this directory. + + diff --git a/doc/src/sgml/ref/alter_extension.sgml b/doc/src/sgml/ref/alter_extension.sgml index 7141ee352e..de6d6dca16 100644 --- a/doc/src/sgml/ref/alter_extension.sgml +++ b/doc/src/sgml/ref/alter_extension.sgml @@ -30,6 +30,7 @@ ALTER EXTENSION name DROP where member_object is: + ACCESS METHOD object_name | AGGREGATE aggregate_name ( aggregate_signature ) | CAST (source_type AS target_type) | COLLATION object_name | diff --git a/doc/src/sgml/ref/alter_materialized_view.sgml b/doc/src/sgml/ref/alter_materialized_view.sgml index b5c44bfabf..b88f5ac00f 100644 --- a/doc/src/sgml/ref/alter_materialized_view.sgml +++ b/doc/src/sgml/ref/alter_materialized_view.sgml @@ -45,7 +45,6 @@ ALTER MATERIALIZED VIEW ALL IN TABLESPACE namestorage_parameter = value [, ... ] ) RESET ( storage_parameter [, ... ] ) OWNER TO { new_owner | CURRENT_USER | SESSION_USER } - SET TABLESPACE new_tablespace diff --git a/doc/src/sgml/ref/alter_policy.sgml b/doc/src/sgml/ref/alter_policy.sgml index a9b1541322..df347d180e 100644 --- a/doc/src/sgml/ref/alter_policy.sgml +++ b/doc/src/sgml/ref/alter_policy.sgml @@ -35,7 +35,12 @@ ALTER POLICY name ON ALTER POLICY changes the definition of an existing - row-level security policy. + row-level security policy. Note that ALTER POLICY + only allows the set of roles to which the policy applies and the + USING and WITH CHECK expressions to + be modified. To change other properties of a policy, such as the command + to which it applies or whether it is permissive or restrictive, the policy + must be dropped and recreated. diff --git a/doc/src/sgml/ref/alter_publication.sgml b/doc/src/sgml/ref/alter_publication.sgml new file mode 100644 index 0000000000..47d83b80be --- /dev/null +++ b/doc/src/sgml/ref/alter_publication.sgml @@ -0,0 +1,139 @@ + + + + + ALTER PUBLICATION + + + + ALTER PUBLICATION + 7 + SQL - Language Statements + + + + ALTER PUBLICATION + change the definition of a publication + + + + +ALTER PUBLICATION name WITH ( option [, ... ] ) + +where option can be: + + PUBLISH INSERT | NOPUBLISH INSERT + | PUBLISH UPDATE | NOPUBLISH UPDATE + | PUBLISH DELETE | NOPUBLISH DELETE + +ALTER PUBLICATION name OWNER TO { new_owner | CURRENT_USER | SESSION_USER } +ALTER PUBLICATION name ADD TABLE table_name [, ...] +ALTER PUBLICATION name SET TABLE table_name [, ...] +ALTER PUBLICATION name DROP TABLE table_name [, ...] + + + + + Description + + + The first variant of this command listed in the synopsis can change + all of the publication properties specified in + . Properties not mentioned in the + command retain their previous settings. Database superusers can change any + of these settings for any role. + + + + To alter the owner, you must also be a direct or indirect member of the + new owning role. The new owner has to be a superuser + + + + The other variants of this command deal with the table membership of the + publication. The SET TABLE clause will replace the + list of tables in the publication with the specified one. + The ADD TABLE and + DROP TABLE will add and remove one or more tables from + the publication. + + + + + Parameters + + + + name + + + The name of an existing publication whose definition is to be altered. + + + + + + PUBLISH INSERT + NOPUBLISH INSERT + PUBLISH UPDATE + NOPUBLISH UPDATE + PUBLISH DELETE + NOPUBLISH DELETE + + + These clauses alter properties originally set by + . See there for more information. + + + + + + table_name + + + Name of an existing table. + + + + + + + + Examples + + + Change the publication to not publish inserts: + +ALTER PUBLICATION noinsert WITH (NOPUBLISH INSERT); + + + + + Add some tables to the publication: + +ALTER PUBLICATION mypublication ADD TABLE users, departments; + + + + + + Compatibility + + + ALTER PUBLICATION is a PostgreSQL + extension. + + + + + See Also + + + + + + + diff --git a/doc/src/sgml/ref/alter_subscription.sgml b/doc/src/sgml/ref/alter_subscription.sgml new file mode 100644 index 0000000000..032ecbb885 --- /dev/null +++ b/doc/src/sgml/ref/alter_subscription.sgml @@ -0,0 +1,139 @@ + + + + + ALTER SUBSCRIPTION + + + + ALTER SUBSCRIPTION + 7 + SQL - Language Statements + + + + ALTER SUBSCRIPTION + change the definition of a subscription + + + + +ALTER SUBSCRIPTION name WITH ( option [, ... ] ) ] + +where option can be: + + SLOT NAME = slot_name + +ALTER SUBSCRIPTION name OWNER TO { new_owner | CURRENT_USER | SESSION_USER } +ALTER SUBSCRIPTION name CONNECTION 'conninfo' +ALTER SUBSCRIPTION name SET PUBLICATION publication_name [, ...] +ALTER SUBSCRIPTION name ENABLE +ALTER SUBSCRIPTION name DISABLE + + + + + Description + + + ALTER SUBSCRIPTION can change most of the subscription + properties that can be specified + in . + + + + To alter the owner, you must also be a direct or indirect member of the + new owning role. The new owner has to be a superuser + + + + + Parameters + + + + name + + + The name of a subscription whose properties are to be altered. + + + + + + CONNECTION 'conninfo' + SET PUBLICATION publication_name + SLOT NAME = slot_name + + + These clauses alter properties originally set by + . See there for more + information. + + + + + + ENABLE + + + Enables the previously disabled subscription, starting the logical + replication worker at the end of transaction. + + + + + + DISABLE + + + Disables the running subscription, stopping the logical replication + worker at the end of transaction. + + + + + + + + Examples + + + Change the publication subscribed by a subscription to + insert_only: + +ALTER SUBSCRIPTION mysub SET PUBLICATION insert_only; + + + + + Disable (stop) the subscription: + +ALTER SUBSCRIPTION mysub DISABLE; + + + + + + Compatibility + + + ALTER SUBSCRIPTION is a PostgreSQL + extension. + + + + + See Also + + + + + + + + + diff --git a/doc/src/sgml/ref/alter_table.sgml b/doc/src/sgml/ref/alter_table.sgml index 6f51cbc896..da431f8369 100644 --- a/doc/src/sgml/ref/alter_table.sgml +++ b/doc/src/sgml/ref/alter_table.sgml @@ -33,6 +33,10 @@ ALTER TABLE [ IF EXISTS ] name SET SCHEMA new_schema ALTER TABLE ALL IN TABLESPACE name [ OWNED BY role_name [, ... ] ] SET TABLESPACE new_tablespace [ NOWAIT ] +ALTER TABLE [ IF EXISTS ] name + ATTACH PARTITION partition_name FOR VALUES partition_bound_spec +ALTER TABLE [ IF EXISTS ] name + DETACH PARTITION partition_name where action is one of: @@ -166,6 +170,12 @@ ALTER TABLE ALL IN TABLESPACE name values or to reject null values. You can only use SET NOT NULL when the column contains no null values. + + + If this table is a partition, one cannot perform DROP NOT NULL + on a column if it is marked NOT NULL in the parent + table. + @@ -704,14 +714,64 @@ ALTER TABLE ALL IN TABLESPACE name + + ATTACH PARTITION partition_name FOR VALUES partition_bound_spec + + + This form attaches an existing table (which might itself be partitioned) + as a partition of the target table using the same syntax for + partition_bound_spec as + . The partition bound specification + must correspond to the partitioning strategy and partition key of the + target table. The table to be attached must have all the same columns + as the target table and no more; moreover, the column types must also + match. Also, it must have all the NOT NULL and + CHECK constraints of the target table. Currently + UNIQUE, PRIMARY KEY, and + FOREIGN KEY constraints are not considered. + If any of the CHECK constraints of the table being + attached is marked NO INHERIT, the command will fail; + such a constraint must be recreated without the NO INHERIT + clause. + + + + A full table scan is performed on the table being attached to check that + no existing row in the table violates the partition constraint. It is + possible to avoid this scan by adding a valid CHECK + constraint to the table that would allow only the rows satisfying the + desired partition constraint before running this command. It will be + determined using such a constraint that the table need not be scanned + to validate the partition constraint. This does not work, however, if + any of the partition keys is an expression and the partition does not + accept NULL values. If attaching a list partition + that will not accept NULL values, also add + NOT NULL constraint to the partition key column, + unless it's an expression. + + + + + + DETACH PARTITION partition_name + + + This form detaches specified partition of the target table. The detached + partition continues to exist as a standalone table, but no longer has any + ties to the table from which it was detached. + + + + - All the actions except RENAME, - SET TABLESPACE and SET SCHEMA - can be combined into - a list of multiple alterations to apply in parallel. For example, it + All the forms of ALTER TABLE that act on a single table, except + RENAME, SET SCHEMA, + ATTACH PARTITION, and + DETACH PARTITION can be combined into + a list of multiple alterations to be applied together. For example, it is possible to add several columns and/or alter the type of several columns in a single command. This is particularly useful with large tables, since only one pass over the table need be made. @@ -721,8 +781,9 @@ ALTER TABLE ALL IN TABLESPACE name You must own the table to use ALTER TABLE. To change the schema or tablespace of a table, you must also have CREATE privilege on the new schema or tablespace. - To add the table as a new child of a parent table, you must own the - parent table as well. + To add the table as a new child of a parent table, you must own the parent + table as well. Also, to attach a table as a new partition of the table, + you must own the table being attached. To alter the owner, you must also be a direct or indirect member of the new owning role, and that role must have CREATE privilege on the table's schema. (These restrictions enforce that altering the owner @@ -938,6 +999,25 @@ ALTER TABLE ALL IN TABLESPACE name + + partition_name + + + The name of the table to attach as a new partition or to detach from this table. + + + + + + partition_bound_spec + + + The partition bound specification for a new partition. Refer to + for more details on the syntax of the same. + + + + @@ -977,6 +1057,11 @@ ALTER TABLE ALL IN TABLESPACE name but does not require a table rewrite. + + Similarly, when attaching a new partition it may be scanned to verify that + existing rows meet the partition constraint. + + The main reason for providing the option to specify multiple changes in a single ALTER TABLE is that multiple table scans or @@ -1028,11 +1113,15 @@ ALTER TABLE ALL IN TABLESPACE name If a table has any descendant tables, it is not permitted to add, - rename, or change the type of a column, or rename an inherited constraint - in the parent table without doing - the same to the descendants. That is, ALTER TABLE ONLY - will be rejected. This ensures that the descendants always have - columns matching the parent. + rename, or change the type of a column in the parent table without doing + same to the descendants. This ensures that the descendants always have + columns matching the parent. Similarly, a constraint cannot be renamed + in the parent without also renaming it in all descendants, so that + constraints also match between the parent and its descendants. + Also, because selecting from the parent also selects from its descendants, + a constraint on the parent cannot be marked valid unless it is also marked + valid for those descendants. In all of these cases, ALTER TABLE + ONLY will be rejected. @@ -1043,6 +1132,9 @@ ALTER TABLE ALL IN TABLESPACE name COLUMN (i.e., ALTER TABLE ONLY ... DROP COLUMN) never removes any descendant columns, but instead marks them as independently defined rather than inherited. + A nonrecursive DROP COLUMN command will fail for a + partitioned table, because all partitions of a table must have the same + columns as the partitioning root. @@ -1229,6 +1321,27 @@ ALTER TABLE distributors DROP CONSTRAINT distributors_pkey, ADD CONSTRAINT distributors_pkey PRIMARY KEY USING INDEX dist_id_temp_idx; + + Attach a partition to range partitioned table: + +ALTER TABLE measurement + ATTACH PARTITION measurement_y2016m07 FOR VALUES FROM ('2016-07-01') TO ('2016-08-01'); + + + + Attach a partition to list partitioned table: + +ALTER TABLE cities + ATTACH PARTITION cities_ab FOR VALUES IN ('a', 'b'); + + + + Detach a partition from partitioned table: + +ALTER TABLE cities + DETACH PARTITION measurement_y2015m12; + + diff --git a/doc/src/sgml/ref/alter_tablespace.sgml b/doc/src/sgml/ref/alter_tablespace.sgml index d9b2a133b1..2f41105001 100644 --- a/doc/src/sgml/ref/alter_tablespace.sgml +++ b/doc/src/sgml/ref/alter_tablespace.sgml @@ -83,14 +83,15 @@ ALTER TABLESPACE name RESET ( , - ). This may be useful if one - tablespace is located on a disk which is faster or slower than the + available parameters are seq_page_cost, + random_page_cost and effective_io_concurrency. + Setting either value for a particular tablespace will override the + planner's usual estimate of the cost of reading pages from tables in + that tablespace, as established by the configuration parameters of the + same name (see , + , + ). This may be useful if + one tablespace is located on a disk which is faster or slower than the remainder of the I/O subsystem. diff --git a/doc/src/sgml/ref/alter_type.sgml b/doc/src/sgml/ref/alter_type.sgml index 9789881a5c..fdb4f3367d 100644 --- a/doc/src/sgml/ref/alter_type.sgml +++ b/doc/src/sgml/ref/alter_type.sgml @@ -28,7 +28,8 @@ ALTER TYPE name OWNER TO { name RENAME ATTRIBUTE attribute_name TO new_attribute_name [ CASCADE | RESTRICT ] ALTER TYPE name RENAME TO new_name ALTER TYPE name SET SCHEMA new_schema -ALTER TYPE name ADD VALUE [ IF NOT EXISTS ] new_enum_value [ { BEFORE | AFTER } existing_enum_value ] +ALTER TYPE name ADD VALUE [ IF NOT EXISTS ] new_enum_value [ { BEFORE | AFTER } neighbor_enum_value ] +ALTER TYPE name RENAME VALUE existing_enum_value TO new_enum_value where action is one of: @@ -124,21 +125,13 @@ ALTER TYPE name ADD VALUE [ IF NOT - CASCADE + RENAME VALUE - Automatically propagate the operation to typed tables of the - type being altered, and their descendants. - - - - - - RESTRICT - - - Refuse the operation if the type being altered is the type of a - typed table. This is the default. + This form renames a value of an enum type. + The value's place in the enum's ordering is not affected. + An error will occur if the specified value is not present or the new + name is already present. @@ -241,14 +234,15 @@ ALTER TYPE name ADD VALUE [ IF NOT new_enum_value - The new value to be added to an enum type's list of values. + The new value to be added to an enum type's list of values, + or the new name to be given to an existing value. Like all enum literals, it needs to be quoted. - existing_enum_value + neighbor_enum_value The existing enum value that the new value should be added immediately @@ -258,6 +252,36 @@ ALTER TYPE name ADD VALUE [ IF NOT + + existing_enum_value + + + The existing enum value that should be renamed. + Like all enum literals, it needs to be quoted. + + + + + + CASCADE + + + Automatically propagate the operation to typed tables of the + type being altered, and their descendants. + + + + + + RESTRICT + + + Refuse the operation if the type being altered is the type of a + typed table. This is the default. + + + + @@ -266,8 +290,12 @@ ALTER TYPE name ADD VALUE [ IF NOT Notes - ALTER TYPE ... ADD VALUE (the form that adds a new value to an - enum type) cannot be executed inside a transaction block. + If ALTER TYPE ... ADD VALUE (the form that adds a new value to + an enum type) is executed inside a transaction block, the new value cannot + be used until after the transaction has been committed, except in the case + that the enum type itself was created earlier in the same transaction. + Likewise, when a pre-existing enum value is renamed, the transaction must + be committed before the renamed value can be used. @@ -321,7 +349,15 @@ ALTER TYPE compfoo ADD ATTRIBUTE f3 int; To add a new value to an enum type in a particular sort position: ALTER TYPE colors ADD VALUE 'orange' AFTER 'red'; - + + + + + To rename an enum value: + +ALTER TYPE colors RENAME VALUE 'purple' TO 'mauve'; + + diff --git a/doc/src/sgml/ref/alter_user_mapping.sgml b/doc/src/sgml/ref/alter_user_mapping.sgml index 3a908130d8..3be54afee5 100644 --- a/doc/src/sgml/ref/alter_user_mapping.sgml +++ b/doc/src/sgml/ref/alter_user_mapping.sgml @@ -89,9 +89,9 @@ ALTER USER MAPPING FOR { user_name Examples - Change the password for user mapping bob, server foo: + Change the password for user mapping bob, server foo: -ALTER USER MAPPING FOR bob SERVER foo OPTIONS (user 'bob', password 'public'); +ALTER USER MAPPING FOR bob SERVER foo OPTIONS (SET password 'public'); diff --git a/doc/src/sgml/ref/clusterdb.sgml b/doc/src/sgml/ref/clusterdb.sgml index c13d74853e..67582fd6e6 100644 --- a/doc/src/sgml/ref/clusterdb.sgml +++ b/doc/src/sgml/ref/clusterdb.sgml @@ -316,7 +316,7 @@ PostgreSQL documentation foo in a database named xyzzy: -$ clusterdb --table foo xyzzy +$ clusterdb --table=foo xyzzy diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml index 07e2f45196..7ff62f2a82 100644 --- a/doc/src/sgml/ref/copy.sgml +++ b/doc/src/sgml/ref/copy.sgml @@ -395,9 +395,15 @@ COPY count Notes - COPY can only be used with plain tables, not + COPY TO can only be used with plain tables, not with views. However, you can write COPY (SELECT * FROM - viewname) TO .... + viewname) TO ... + to copy the current contents of a view. + + + + COPY FROM can be used with plain tables and with views + that have INSTEAD OF INSERT triggers. @@ -418,6 +424,15 @@ COPY count to have column privileges on the column(s) listed in the command. + + If row-level security is enabled for the table, the relevant + SELECT policies will apply to COPY + table TO statements. + Currently, COPY FROM is not supported for tables + with row-level security. Use equivalent INSERT + statements instead. + + Files named in a COPY command are read or written directly by the server, not by the client application. Therefore, diff --git a/doc/src/sgml/ref/create_access_method.sgml b/doc/src/sgml/ref/create_access_method.sgml index 3c091f8021..0a30e6ea3c 100644 --- a/doc/src/sgml/ref/create_access_method.sgml +++ b/doc/src/sgml/ref/create_access_method.sgml @@ -57,29 +57,28 @@ CREATE ACCESS METHOD name - access_method_type + access_method_type - This clause specifies type of access method to define. + This clause specifies the type of access method to define. Only INDEX is supported at present. - HANDLER handler_function + handler_function - handler_function is the - name of a previously registered function that will be called to - retrieve the struct which contains required parameters and functions - of access method to the core. The handler function must take single - argument of type internal, and its return type depends on the - type of access method; for INDEX access methods, it - must be index_am_handler. - - - See for index access methods API. + handler_function is the + name (possibly schema-qualified) of a previously registered function + that represents the access method. The handler function must be + declared to take a single argument of type internal, + and its return type depends on the type of access method; + for INDEX access methods, it must + be index_am_handler. The C-level API that the handler + function must implement varies depending on the type of access method. + The index access method API is described in . @@ -90,7 +89,7 @@ CREATE ACCESS METHOD name Examples - Create an access method heptree with + Create an index access method heptree with handler function heptree_handler: CREATE ACCESS METHOD heptree TYPE INDEX HANDLER heptree_handler; diff --git a/doc/src/sgml/ref/create_extension.sgml b/doc/src/sgml/ref/create_extension.sgml index 007d8c9330..14e910115a 100644 --- a/doc/src/sgml/ref/create_extension.sgml +++ b/doc/src/sgml/ref/create_extension.sgml @@ -95,35 +95,21 @@ CREATE EXTENSION [ IF NOT EXISTS ] extension_name If not specified, and the extension's control file does not specify a schema either, the current default object creation schema is used. + - If the extension specifies schema in its control file, - the schema cannot be overridden with SCHEMA clause. - The SCHEMA clause in this case works as follows: - - - - If schema_name matches - the schema in control file, it will be used normally as there is no - conflict. - - - - - If the CASCADE clause is given, the - schema_name will only - be used for the missing required extensions which do not specify - schema in their control files. - - - - - If schema_name is not - the same as the one in extension's control file and the - CASCADE clause is not given, error will be thrown. - - - + If the extension specifies a schema parameter in its + control file, then that schema cannot be overridden with + a SCHEMA clause. Normally, an error will be raised if + a SCHEMA clause is given and it conflicts with the + extension's schema parameter. However, if + the CASCADE clause is also given, + then schema_name is + ignored when it conflicts. The + given schema_name will be + used for installation of any needed extensions that do not + specify schema in their control files. + Remember that the extension itself is not considered to be within any schema: extensions have unqualified names that must be unique @@ -147,7 +133,8 @@ CREATE EXTENSION [ IF NOT EXISTS ] extension_name old_version - FROM old_version + + FROM old_version must be specified when, and only when, you are attempting to install an extension that replaces an old style module that is just a collection of objects not packaged into an extension. This option @@ -174,10 +161,13 @@ CREATE EXTENSION [ IF NOT EXISTS ] extension_name CASCADE - Try to install extension including the required dependencies - recursively. The SCHEMA option will be propagated - to the required extensions. Other options are not recursively - applied when using this clause. + Automatically install any extensions that this extension depends on + that are not already installed. Their dependencies are likewise + automatically installed, recursively. The SCHEMA clause, + if given, applies to all extensions that get installed this way. + Other options of the statement are not applied to + automatically-installed extensions; in particular, their default + versions are always selected. diff --git a/doc/src/sgml/ref/create_foreign_table.sgml b/doc/src/sgml/ref/create_foreign_table.sgml index 413b033cb5..5d0dcf567b 100644 --- a/doc/src/sgml/ref/create_foreign_table.sgml +++ b/doc/src/sgml/ref/create_foreign_table.sgml @@ -27,6 +27,15 @@ CREATE FOREIGN TABLE [ IF NOT EXISTS ] table_name SERVER server_name [ OPTIONS ( option 'value' [, ... ] ) ] +CREATE FOREIGN TABLE [ IF NOT EXISTS ] table_name + PARTITION OF parent_table [ ( + { column_name WITH OPTIONS [ column_constraint [ ... ] ] + | table_constraint } + [, ... ] +) ] partition_bound_spec + SERVER server_name +[ OPTIONS ( option 'value' [, ... ] ) ] + where column_constraint is: [ CONSTRAINT constraint_name ] @@ -67,6 +76,12 @@ CHECK ( expression ) [ NO INHERIT ] name as any existing data type in the same schema. + + If PARTITION OF clause is specified then the table is + created as a partition of parent_table with specified + bounds. + + To be able to create a foreign table, you must have USAGE privilege on the foreign server, as well as USAGE @@ -314,6 +329,17 @@ CREATE FOREIGN TABLE films ( SERVER film_server; + + Create foreign table measurement_y2016m07, which will be + accessed through the server server_07, as a partition + of the range partitioned table measurement: + + +CREATE FOREIGN TABLE measurement_y2016m07 + PARTITION OF measurement FOR VALUES FROM ('2016-07-01') TO ('2016-08-01') + SERVER server_07; + + diff --git a/doc/src/sgml/ref/create_index.sgml b/doc/src/sgml/ref/create_index.sgml index e9f47c4414..fcb7a60ce3 100644 --- a/doc/src/sgml/ref/create_index.sgml +++ b/doc/src/sgml/ref/create_index.sgml @@ -459,9 +459,9 @@ CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] postgres=# \d tab Table "public.tab" - Column | Type | Modifiers ---------+---------+----------- - col | integer | + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + col | integer | | | Indexes: "idx" btree (col) INVALID diff --git a/doc/src/sgml/ref/create_opclass.sgml b/doc/src/sgml/ref/create_opclass.sgml index 7b9d55d38d..829d8f2fff 100644 --- a/doc/src/sgml/ref/create_opclass.sgml +++ b/doc/src/sgml/ref/create_opclass.sgml @@ -235,6 +235,11 @@ CREATE OPERATOR CLASS name [ DEFAUL (currently GiST, GIN and BRIN) allow it to be different. The STORAGE clause must be omitted unless the index method allows a different type to be used. + If the column data_type is specified + as anyarray, the storage_type + can be declared as anyelement to indicate that the index + entries are members of the element type belonging to the actual array + type that each particular index is created for. diff --git a/doc/src/sgml/ref/create_policy.sgml b/doc/src/sgml/ref/create_policy.sgml index 89d27879b1..f0486effaf 100644 --- a/doc/src/sgml/ref/create_policy.sgml +++ b/doc/src/sgml/ref/create_policy.sgml @@ -22,6 +22,7 @@ PostgreSQL documentation CREATE POLICY name ON table_name + [ AS { PERMISSIVE | RESTRICTIVE } ] [ FOR { ALL | SELECT | INSERT | UPDATE | DELETE } ] [ TO { role_name | PUBLIC | CURRENT_USER | SESSION_USER } [, ...] ] [ USING ( using_expression ) ] @@ -119,6 +120,33 @@ CREATE POLICY name ON + + PERMISSIVE + + + Specify that the policy is to be created as a permissive policy. + All permissive policies which are applicable to a given query will + be combined together using the boolean "OR" operator. By creating + permissive policies, administrators can add to the set of records + which can be accessed. Policies are PERMISSIVE by default. + + + + + + RESTRICTIVE + + + Specify that the policy is to be created as a restrictive policy. + All restrictive policies which are applicable to a given query will + be combined together using the boolean "AND" operator. By creating + restrictive policies, administrators can reduce the set of records + which can be accessed as all restrictive policies must be passed for + each record. + + + + command @@ -390,6 +418,16 @@ CREATE POLICY name ON + + Note that there needs to be at least one permissive policy to grant + access to records before restrictive policies can be usefully used to + reduce that access. If only restrictive policies exist, then no records + will be accessible. When a mix of permissive and restrictive policies + are present, a record is only accessible if at least one of the + permissive policies passes, in addition to all the restrictive + policies. + + Generally, the system will enforce filter conditions imposed using security policies prior to qualifications that appear in user queries, diff --git a/doc/src/sgml/ref/create_publication.sgml b/doc/src/sgml/ref/create_publication.sgml new file mode 100644 index 0000000000..995f2bcf3c --- /dev/null +++ b/doc/src/sgml/ref/create_publication.sgml @@ -0,0 +1,206 @@ + + + + + CREATE PUBLICATION + + + + CREATE PUBLICATION + 7 + SQL - Language Statements + + + + CREATE PUBLICATION + define a new publication + + + + +CREATE PUBLICATION name + [ FOR TABLE table_name [, ...] + | FOR ALL TABLES ] + [ WITH ( option [, ... ] ) ] + +where option can be: + + PUBLISH INSERT | NOPUBLISH INSERT + | PUBLISH UPDATE | NOPUBLISH UPDATE + | PUBLISH DELETE | NOPUBLISH DELETE + + + + + Description + + + CREATE PUBLICATION adds a new publication + into the current database. The publication name must be distinct from + the name of any existing publication in the current database. + + + + A publication is essentially a group of tables whose data changes are + intended to be replicated through logical replication. See + for details about how + publications fit into the logical replication setup. + + + + + Parameters + + + + name + + + The name of the new publication. + + + + + + FOR TABLE + + + Specifies a list of tables to add to the publication. + + + + + + FOR ALL TABLES + + + Marks the publication as one that replicates changes for all tables in + the database, including tables created in the future. + + + + + + PUBLISH INSERT + NOPUBLISH INSERT + + + These clauses determine whether the new publication will send + the INSERT operations to the subscribers. + PUBLISH INSERT is the default. + + + + + + PUBLISH UPDATE + NOPUBLISH UPDATE + + + These clauses determine whether the new publication will send + the UPDATE operations to the subscribers. + PUBLISH UPDATE is the default. + + + + + + PUBLISH DELETE + NOPUBLISH DELETE + + + These clauses determine whether the new publication will send + the DELETE operations to the subscribers. + PUBLISH DELETE is the default. + + + + + + + + + Notes + + + If neither FOR TABLE nor FOR ALL + TABLES is specified, then the publication starts out with an + empty set of tables. That is useful if tables are to be added later. + + + + The creation of a publication does not start replication. It only defines + a grouping and filtering logic for future subscribers. + + + + To create a publication, the invoking user must have the + CREATE privilege for the current database. + (Of course, superusers bypass this check.) + + + + To add a table to a publication, the invoking user must have + SELECT privilege on given table. The + FOR ALL TABLES clause requires superuser. + + + + The tables added to a publication that publishes UPDATE + and/or DELETE operations must have + REPLICA IDENTITY defined. Otherwise those operations will be + disallowed on those tables. + + + + For an INSERT ... ON CONFLICT command, the publication will + publish the operation that actually results from the command. So depending + of the outcome, it may be published as either INSERT or + UPDATE, or it may not be published at all. + + + + TRUNCATE and other DDL operations + are not published. + + + + + Examples + + + Create a simple publication that just publishes all DML for tables in it: + +CREATE PUBLICATION mypublication; + + + + + Create an insert-only publication: + +CREATE PUBLICATION insert_only WITH (NOPUBLISH UPDATE, NOPUBLISH DELETE); + + + + + + Compatibility + + + CREATE PUBLICATION is a PostgreSQL + extension. + + + + + See Also + + + + + + + diff --git a/doc/src/sgml/ref/create_role.sgml b/doc/src/sgml/ref/create_role.sgml index 38cd4c8369..a3b8ed9ab4 100644 --- a/doc/src/sgml/ref/create_role.sgml +++ b/doc/src/sgml/ref/create_role.sgml @@ -235,12 +235,6 @@ CREATE ROLE name [ [ WITH ] - - - Note that older clients might lack support for the MD5 - authentication mechanism that is needed to work with passwords - that are stored encrypted. - diff --git a/doc/src/sgml/ref/create_sequence.sgml b/doc/src/sgml/ref/create_sequence.sgml index c9591462ee..62ae379226 100644 --- a/doc/src/sgml/ref/create_sequence.sgml +++ b/doc/src/sgml/ref/create_sequence.sgml @@ -349,7 +349,7 @@ END; - The standard's AS <data type> expression is not + The standard's AS data_type expression is not supported. diff --git a/doc/src/sgml/ref/create_subscription.sgml b/doc/src/sgml/ref/create_subscription.sgml new file mode 100644 index 0000000000..40d08b3440 --- /dev/null +++ b/doc/src/sgml/ref/create_subscription.sgml @@ -0,0 +1,176 @@ + + + + + CREATE SUBSCRIPTION + + + + CREATE SUBSCRIPTION + 7 + SQL - Language Statements + + + + CREATE SUBSCRIPTION + define a new subscription + + + + +CREATE SUBSCRIPTION subscription_name CONNECTION 'conninfo' PUBLICATION { publication_name [, ...] } [ WITH ( option [, ... ] ) ] + +where option can be: + + | ENABLED | DISABLED + | CREATE SLOT | NOCREATE SLOT + | SLOT NAME = slot_name + + + + + Description + + + CREATE SUBSCRIPTION adds a new subscription for a + current database. The subscription name must be distinct from the name of + any existing subscription in the database. + + + + The subscription represents a replication connection to the publisher. As + such this command does not only add definitions in the local catalogs but + also creates a replication slot on the publisher. + + + + A logical replication worker will be started to replicate data for the new + subscription at the commit of the transaction where this command is run. + + + + Additional info about subscriptions and logical replication as a whole + can is available at and + . + + + + + + Parameters + + + + subscription_name + + + The name of the new subscription. + + + + + + CONNECTION 'conninfo' + + + The connection string to the publisher. + + + + + + PUBLICATION publication_name + + + Name(s) of the publications on the publisher to subscribe to. + + + + + + ENABLED + DISABLED + + + Specifies whether the subscription should be actively replicating or + if it should be just setup but not started yet. Note that the + replication slot as described above is created in either case. + ENABLED is the default. + + + + + + CREATE SLOT + NOCREATE SLOT + + + Specifies whether the command should create the replication slot on the + publisher. CREATE SLOT is the default. + + + + + + SLOT NAME = slot_name + + + Name of the replication slot to use. The default behavior is to use + subscription_name for slot name. + + + + + + + + Examples + + + Create a subscription to a remote server that replicates tables in + the publications mypubclication and + insert_only and starts replicating immediately on + commit: + +CREATE SUBSCRIPTION mysub + CONNECTION 'host=192.168.1.50 port=5432 user=foo dbname=foodb password=foopass' + PUBLICATION mypublication, insert_only; + + + + + Create a subscription to a remote server that replicates tables in + the insert_only publication and does not start replicating + until enabled at a later time. + +CREATE SUBSCRIPTION mysub + CONNECTION 'host=192.168.1.50 port=5432 user=foo dbname=foodb password=foopass' + PUBLICATION insert_only + WITH (DISABLED); + + + + + + Compatibility + + + CREATE SUBSCRIPTION is a PostgreSQL + extension. + + + + + See Also + + + + + + + + + diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml index bf2ad64d66..58f8bf6d6a 100644 --- a/doc/src/sgml/ref/create_table.sgml +++ b/doc/src/sgml/ref/create_table.sgml @@ -28,6 +28,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI [, ... ] ] ) [ INHERITS ( parent_table [, ... ] ) ] +[ PARTITION BY { RANGE | LIST } ( { column_name | ( expression ) } [ COLLATE collation ] [ opclass ] [, ... ] ) ] [ WITH ( storage_parameter [= value] [, ... ] ) | WITH OIDS | WITHOUT OIDS ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] [ TABLESPACE tablespace_name ] @@ -38,6 +39,18 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI | table_constraint } [, ... ] ) ] +[ PARTITION BY { RANGE | LIST } ( { column_name | ( expression ) } [ COLLATE collation ] [ opclass ] [, ... ] ) ] +[ WITH ( storage_parameter [= value] [, ... ] ) | WITH OIDS | WITHOUT OIDS ] +[ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] +[ TABLESPACE tablespace_name ] + +CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXISTS ] table_name + PARTITION OF parent_table [ ( + { column_name [ column_constraint [ ... ] ] + | table_constraint } + [, ... ] +) ] FOR VALUES partition_bound_spec +[ PARTITION BY { RANGE | LIST } ( { column_name | ( expression ) } [ COLLATE collation ] [ opclass ] [, ... ] ) ] [ WITH ( storage_parameter [= value] [, ... ] ) | WITH OIDS | WITHOUT OIDS ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] [ TABLESPACE tablespace_name ] @@ -70,6 +83,11 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI { INCLUDING | EXCLUDING } { DEFAULTS | CONSTRAINTS | INDEXES | STORAGE | COMMENTS | ALL } +and partition_bound_spec is: + +{ IN ( expression [, ...] ) | + FROM ( { expression | UNBOUNDED } [, ...] ) TO ( { expression | UNBOUNDED } [, ...] ) } + index_parameters in UNIQUE, PRIMARY KEY, and EXCLUDE constraints are: [ WITH ( storage_parameter [= value] [, ... ] ) ] @@ -229,6 +247,52 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI + + PARTITION OF parent_table FOR VALUES partition_bound_spec + + + Creates the table as partition of the specified + parent table. + + + + The partition bound specification must correspond to the partitioning + method and partition key of the parent table, and must not overlap with + any existing partition of that parent. + + + + A partition cannot have columns other than those inherited from the + parent. That includes the oid column, which can be + specified using the WITH (OIDS) clause. + Defaults and constraints can optionally be specified for each of the + inherited columns. One can also specify table constraints in addition + to those inherited from the parent. If a check constraint with the name + matching one of the parent's constraint is specified, it is merged with + the latter, provided the specified condition is same. + + + + Rows inserted into a partitioned table will be automatically routed to + the correct partition. If no suitable partition exists, an error will + occur. Also, if updating a row in a given partition causes it to move + to another partition due to the new partition key, an error will occur. + + + + A partition must have the same column names and types as the table of + which it is a partition. Therefore, modifications to the column names + or types of the partitioned table will automatically propagate to all + children, as will operations such as TRUNCATE which normally affect a + table and all of its inheritance children. It is also possible to + TRUNCATE a partition individually, just as for an inheritance child. + Note that dropping a partition with DROP TABLE + requires taking an ACCESS EXCLUSIVE lock on the + parent table. + + + + column_name @@ -313,6 +377,46 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI + + PARTITION BY { RANGE | LIST } ( { column_name | ( expression ) } [ opclass ] [, ...] ) + + + The optional PARTITION BY clause specifies a strategy + of partitioning the table. The table thus created is called a + partitioned table. The parenthesized list of + columns or expressions forms the partition key + for the table. When using range partitioning, the partition key can + include multiple columns or expressions, but for list partitioning, the + partition key must consist of a single column or expression. If no + btree operator class is specified when creating a partitioned table, + the default btree operator class for the datatype will be used. If + there is none, an error will be reported. + + + + A partitioned table is divided into sub-tables (called partitions), + which are created using separate CREATE TABLE commands. + The partitioned table is itself empty. A data row inserted into the + table is routed to a partition based on the value of columns or + expressions in the partition key. If no existing partition matches + the values in the new row, an error will be reported. + + + + Partitioned tables do not support UNIQUE, + PRIMARY KEY, EXCLUDE, or + FOREIGN KEY constraints; however, you can define + these constraints on individual partitions. + + + + When using range partitioning, a NOT NULL constraint + is added to each non-expression column in the partition key. + + + + + LIKE source_table [ like_option ... ] @@ -1368,6 +1472,57 @@ CREATE TABLE employees OF employee_type ( PRIMARY KEY (name), salary WITH OPTIONS DEFAULT 1000 ); + + + + Create a range partitioned table: + +CREATE TABLE measurement ( + logdate date not null, + peaktemp int, + unitsales int +) PARTITION BY RANGE (logdate); + + + + Create a list partitioned table: + +CREATE TABLE cities ( + city_id bigserial not null, + name text not null, + population bigint, +) PARTITION BY LIST (left(lower(name), 1)); + + + + Create partition of a range partitioned table: + +CREATE TABLE measurement_y2016m07 + PARTITION OF measurement ( + unitsales DEFAULT 0 +) FOR VALUES FROM ('2016-07-01') TO ('2016-08-01'); + + + + Create partition of a list partitioned table: + +CREATE TABLE cities_ab + PARTITION OF cities ( + CONSTRAINT city_id_nonzero CHECK (city_id != 0) +) FOR VALUES IN ('a', 'b'); + + + + Create partition of a list partitioned table that is itself further + partitioned and then add a partition to it: + +CREATE TABLE cities_ab + PARTITION OF cities ( + CONSTRAINT city_id_nonzero CHECK (city_id != 0) +) FOR VALUES IN ('a', 'b') PARTITION BY RANGE (population); + +CREATE TABLE cities_ab_10000_to_100000 + PARTITION OF cities_ab FOR VALUES FROM (10000) TO (100000); diff --git a/doc/src/sgml/ref/create_trigger.sgml b/doc/src/sgml/ref/create_trigger.sgml index 4bde815012..8590e226e3 100644 --- a/doc/src/sgml/ref/create_trigger.sgml +++ b/doc/src/sgml/ref/create_trigger.sgml @@ -25,6 +25,7 @@ CREATE [ CONSTRAINT ] TRIGGER name ON table_name [ FROM referenced_table_name ] [ NOT DEFERRABLE | [ DEFERRABLE ] [ INITIALLY IMMEDIATE | INITIALLY DEFERRED ] ] + [ REFERENCING { { OLD | NEW } TABLE [ AS ] transition_relation_name } [ ... ] ] [ FOR [ EACH ] { ROW | STATEMENT } ] [ WHEN ( condition ) ] EXECUTE PROCEDURE function_name ( arguments ) @@ -177,6 +178,15 @@ CREATE [ CONSTRAINT ] TRIGGER name when the constraints they implement are violated. + + The REFERENCING option is only allowed for an AFTER + trigger which is not a constraint trigger. OLD TABLE may only + be specified once, and only on a trigger which can fire on + UPDATE or DELETE. NEW TABLE may only + be specified once, and only on a trigger which can fire on + UPDATE or INSERT. + + SELECT does not modify any rows so you cannot create SELECT triggers. Rules and views are more @@ -281,6 +291,40 @@ UPDATE OF column_name1 [, column_name2 + + REFERENCING + + + This immediately preceeds the declaration of one or two relations which + can be used to read the before and/or after images of all rows directly + affected by the triggering statement. An AFTER EACH ROW + trigger is allowed to use both these transition relation names and the + row names (OLD and NEW) which reference each + individual row for which the trigger fires. + + + + + + OLD TABLE + NEW TABLE + + + This specifies whether the named relation contains the before or after + images for rows affected by the statement which fired the trigger. + + + + + + transition_relation_name + + + The (unqualified) name to be used within the trigger for this relation. + + + + FOR EACH ROW FOR EACH STATEMENT @@ -474,6 +518,30 @@ CREATE TRIGGER view_insert FOR EACH ROW EXECUTE PROCEDURE view_insert_row(); + + Execute the function check_transfer_balances_to_zero for each + statement to confirm that the transfer rows offset to a net of + zero: + + +CREATE TRIGGER transfer_insert + AFTER INSERT ON transfer + FOR EACH STATEMENT + REFERENCING NEW TABLE AS inserted + EXECUTE PROCEDURE check_transfer_balances_to_zero(); + + + Execute the function check_matching_pairs for each row to + confirm that changes are made to matching pairs at the same time (by the + same statement): + + +CREATE TRIGGER paired_items_update + AFTER UPDATE ON paired_items + FOR EACH ROW + REFERENCING NEW TABLE AS newtab OLD TABLE AS oldtab + EXECUTE PROCEDURE check_matching_pairs(); + @@ -502,24 +570,14 @@ CREATE TRIGGER view_insert - SQL allows you to define aliases for the old - and new rows or tables for use in the definition - of the triggered action (e.g., CREATE TRIGGER ... ON - tablename REFERENCING OLD ROW AS somename NEW ROW AS othername - ...). Since PostgreSQL - allows trigger procedures to be written in any number of - user-defined languages, access to the data is handled in a - language-specific way. - - - - - - PostgreSQL does not allow the old and new - tables to be referenced in statement-level triggers, i.e., the tables - that contain all the old and/or new rows, which are referred to by the - OLD TABLE and NEW TABLE clauses in - the SQL standard. + While transition tables for AFTER triggers are specified + using the REFERENCING clause in the standard way, the row + variables used in FOR EACH ROW triggers may not be + specified in REFERENCING clause. They are available in a + manner which is dependent on the language in which the trigger function + is written. Some languages effectively behave as though there is a + REFERENCING clause containing OLD ROW AS OLD NEW + ROW AS NEW. diff --git a/doc/src/sgml/ref/create_view.sgml b/doc/src/sgml/ref/create_view.sgml index ede1698051..8641e1925e 100644 --- a/doc/src/sgml/ref/create_view.sgml +++ b/doc/src/sgml/ref/create_view.sgml @@ -87,13 +87,13 @@ CREATE [ OR REPLACE ] [ TEMP | TEMPORARY ] [ RECURSIVE ] VIEW Creates a recursive view. The syntax -CREATE RECURSIVE VIEW name (columns) AS SELECT ...; +CREATE RECURSIVE VIEW [ schema . ] view_name (column_names) AS SELECT ...; is equivalent to -CREATE VIEW name AS WITH RECURSIVE name (columns) AS (SELECT ...) SELECT columns FROM name; +CREATE VIEW [ schema . ] view_name AS WITH RECURSIVE view_name (column_names) AS (SELECT ...) SELECT column_names FROM view_name; - A view column list must be specified for a recursive view. + A view column name list must be specified for a recursive view. @@ -462,11 +462,16 @@ CREATE VIEW comedies AS Create a recursive view consisting of the numbers from 1 to 100: -CREATE RECURSIVE VIEW nums_1_100 (n) AS +CREATE RECURSIVE VIEW public.nums_1_100 (n) AS VALUES (1) UNION ALL SELECT n+1 FROM nums_1_100 WHERE n < 100; - + + Notice that although the recursive view's name is schema-qualified in this + CREATE, its internal self-reference is not schema-qualified. + This is because the implicitly-created CTE's name cannot be + schema-qualified. + diff --git a/doc/src/sgml/ref/drop_publication.sgml b/doc/src/sgml/ref/drop_publication.sgml new file mode 100644 index 0000000000..1a1be579ad --- /dev/null +++ b/doc/src/sgml/ref/drop_publication.sgml @@ -0,0 +1,107 @@ + + + + + DROP PUBLICATION + + + + DROP PUBLICATION + 7 + SQL - Language Statements + + + + DROP PUBLICATION + remove a publication + + + + +DROP PUBLICATION [ IF EXISTS ] name [, ...] [ CASCADE | RESTRICT ] + + + + + Description + + + DROP PUBLICATION removes an existing publication from + the database. + + + + A publication can only be dropped by its owner or a superuser. + + + + + Parameters + + + + IF EXISTS + + + Do not throw an error if the extension does not exist. A notice is issued + in this case. + + + + + + name + + + The name of an existing publication. + + + + + + CASCADE + RESTRICT + + + + These key words do not have any effect, since there are no dependencies + on publications. + + + + + + + + Examples + + + Drop a publication: + +DROP PUBLICATION mypublication; + + + + + + + Compatibility + + + DROP PUBLICATION is a PostgreSQL + extension. + + + + + See Also + + + + + + + diff --git a/doc/src/sgml/ref/drop_subscription.sgml b/doc/src/sgml/ref/drop_subscription.sgml new file mode 100644 index 0000000000..9f2fb93275 --- /dev/null +++ b/doc/src/sgml/ref/drop_subscription.sgml @@ -0,0 +1,110 @@ + + + + + DROP SUBSCRIPTION + + + + DROP SUBSCRIPTION + 7 + SQL - Language Statements + + + + DROP SUBSCRIPTION + remove a subscription + + + + +DROP SUBSCRIPTION [ IF EXISTS ] name [ DROP SLOT | NODROP SLOT ] + + + + + Description + + + DROP SUBSCRIPTION removes a subscription from the + database cluster. + + + + A subscription can only be dropped by a superuser. + + + + The replication worker associated with the subscription will not stop until + after the transaction that issued this command has committed. + + + + + Parameters + + + + name + + + The name of a subscription to be dropped. + + + + + + DROP SLOT + NODROP SLOT + + + Specifies whether to drop the replication slot on the publisher. The + default is + DROP SLOT. + + + + If the publisher is not reachable when the subscription is to be + dropped, then it is useful to specify NODROP SLOT. + But the replication slot on the publisher will then have to be removed + manually. + + + + + + + + + Examples + + + Drop a subscription: + +DROP SUBSCRIPTION mysub; + + + + + + + Compatibility + + + DROP SUBSCRIPTION is a PostgreSQL + extension. + + + + + See Also + + + + + + + diff --git a/doc/src/sgml/ref/ecpg-ref.sgml b/doc/src/sgml/ref/ecpg-ref.sgml index 029bd4a4d2..8bfb47c4d7 100644 --- a/doc/src/sgml/ref/ecpg-ref.sgml +++ b/doc/src/sgml/ref/ecpg-ref.sgml @@ -42,11 +42,9 @@ PostgreSQL documentation ecpg will convert each input file given on the command line to the corresponding C output file. Input files - preferably have the extension .pgc, in which - case the extension will be replaced by .c to - determine the output file name. If the extension of the input file - is not .pgc, then the output file name is - computed by appending .c to the full file name. + preferably have the extension .pgc. + The extension will be replaced by .c to + determine the output file name. The output file name can also be overridden using the option. diff --git a/doc/src/sgml/ref/initdb.sgml b/doc/src/sgml/ref/initdb.sgml index 4e339ecce8..31f081ae7a 100644 --- a/doc/src/sgml/ref/initdb.sgml +++ b/doc/src/sgml/ref/initdb.sgml @@ -235,7 +235,7 @@ PostgreSQL documentation - + By default, initdb will wait for all files to be @@ -355,7 +355,7 @@ PostgreSQL documentation - + By default, when initdb diff --git a/doc/src/sgml/ref/insert.sgml b/doc/src/sgml/ref/insert.sgml index 06f416039b..9339826818 100644 --- a/doc/src/sgml/ref/insert.sgml +++ b/doc/src/sgml/ref/insert.sgml @@ -527,6 +527,17 @@ INSERT oid count + + Notes + + + If the specified table is a partitioned table, each row is routed to + the appropriate partition and inserted into it. If the specified table + is a partition, an error will occur if one of the input rows violates + the partition constraint. + + + Examples diff --git a/doc/src/sgml/ref/pg_basebackup.sgml b/doc/src/sgml/ref/pg_basebackup.sgml index 03615da480..5c2db2581c 100644 --- a/doc/src/sgml/ref/pg_basebackup.sgml +++ b/doc/src/sgml/ref/pg_basebackup.sgml @@ -56,7 +56,7 @@ PostgreSQL documentation and pg_hba.conf must explicitly permit the replication connection. The server must also be configured with set high enough to leave at least - one session available for the backup. + one session available for the backup and one for WAL streaming (if used). @@ -85,10 +85,8 @@ PostgreSQL documentation - There is no guarantee that all WAL files required for the backup are archived - at the end of backup. If you are planning to use the backup for an archive - recovery and want to ensure that all required files are available at that moment, - you need to include them into the backup by using -x option. + If you are using -X none, there is no guarantee that all + WAL files required for the backup are archived at the end of backup. @@ -180,7 +178,8 @@ PostgreSQL documentation target directory, the tar contents will be written to standard output, suitable for piping to for example gzip. This is only possible if - the cluster has no additional tablespaces. + the cluster has no additional tablespaces and transaction + log streaming is not used. @@ -241,6 +240,31 @@ PostgreSQL documentation the server does not remove any necessary WAL data in the time between the end of the base backup and the start of streaming replication. + + If this option is not specified and the server supports temporary + replication slots (version 10 and later), then a temporary replication + slot is automatically used for WAL streaming. + + + + + + + + + This option prevents the creation of a temporary replication slot + during the backup even if it's supported by the server. + + + Temporary replication slots are created by default if no slot name + is given with the option when using log streaming. + + + The main purpose of this option is to allow taking a base backup when + the server is out of free replication slots. Using replication slots + is almost always preferred, because it prevents needed WAL from being + removed by the server during the backup. + @@ -283,17 +307,6 @@ PostgreSQL documentation - - - - - - Using this option is equivalent of using -X with - method fetch. - - - - @@ -301,16 +314,26 @@ PostgreSQL documentation Includes the required transaction log files (WAL files) in the backup. This will include all transaction logs generated during - the backup. If this option is specified, it is possible to start - a postmaster directly in the extracted directory without the need - to consult the log archive, thus making this a completely standalone - backup. + the backup. Unless the method none is specified, + it is possible to start a postmaster directly in the extracted + directory without the need to consult the log archive, thus + making this a completely standalone backup. The following methods for collecting the transaction logs are supported: + + n + none + + + Don't include transaction log in the backup. + + + + f fetch @@ -323,6 +346,10 @@ PostgreSQL documentation If the log has been rotated when it's time to transfer it, the backup will fail and be unusable. + + The transaction log files will be written to + the base.tar file. + @@ -339,6 +366,14 @@ PostgreSQL documentation client can keep up with transaction log received, using this mode requires no extra transaction logs to be saved on the master. + + The transaction log files are written to a separate file + named pg_wal.tar (if the server is a version + earlier than 10, the file will be named pg_xlog.tar). + + + This value is the default. + @@ -353,7 +388,8 @@ PostgreSQL documentation Enables gzip compression of tar file output, with the default compression level. Compression is only available when using - the tar format. + the tar format, and the suffix .gz will + automatically be added to all tar filenames. @@ -366,7 +402,8 @@ PostgreSQL documentation Enables gzip compression of tar file output, and specifies the compression level (0 through 9, 0 being no compression and 9 being best compression). Compression is only available when using the tar - format. + format, and the suffix .gz will + automatically be added to all tar filenames. @@ -398,6 +435,24 @@ PostgreSQL documentation + + + + + + By default, when pg_basebackup aborts with an + error, it removes any directories it might have created before + discovering that it cannot finish the job (for example, data directory + and transaction log directory). This option inhibits tidying-up and is + thus useful for debugging. + + + + Note that tablespace directories are not cleaned up either way. + + + + @@ -420,6 +475,21 @@ PostgreSQL documentation + + + + + + By default, pg_basebackup will wait for all files + to be written safely to disk. This option causes + pg_basebackup to return without waiting, which is + faster, but means that a subsequent operating system crash can leave + the base backup corrupt. Generally, this option is useful for testing + but should not be used when creating a production installation. + + + + @@ -592,10 +662,12 @@ PostgreSQL documentation The backup will include all files in the data directory and tablespaces, including the configuration files and any additional files placed in the - directory by third parties. But only regular files and directories are - copied. Symbolic links (other than those used for tablespaces) and special - device files are skipped. (See for - the precise details.) + directory by third parties, except certain temporary files managed by + PostgreSQL. But only regular files and directories are copied, except that + symbolic links used for tablespaces are preserved. Symbolic links pointing + to certain directories known to PostgreSQL are copied as empty directories. + Other symbolic links and special device files are skipped. + See for the precise details. @@ -652,7 +724,7 @@ PostgreSQL documentation To create a backup of a single-tablespace local database and compress this with bzip2: -$ pg_basebackup -D - -Ft | bzip2 > backup.tar.bz2 +$ pg_basebackup -D - -Ft -X fetch | bzip2 > backup.tar.bz2 (This command will fail if there are multiple tablespaces in the database.) diff --git a/doc/src/sgml/ref/pg_ctl-ref.sgml b/doc/src/sgml/ref/pg_ctl-ref.sgml index 6ceb7816dc..176dfaf98a 100644 --- a/doc/src/sgml/ref/pg_ctl-ref.sgml +++ b/doc/src/sgml/ref/pg_ctl-ref.sgml @@ -31,7 +31,7 @@ PostgreSQL documentation pg_ctl - + seconds datadir @@ -60,7 +60,7 @@ PostgreSQL documentation pg_ctl - + seconds datadir @@ -91,6 +91,8 @@ PostgreSQL documentation pg_ctl + + seconds datadir @@ -115,7 +117,7 @@ PostgreSQL documentation - + seconds options @@ -261,7 +263,7 @@ PostgreSQL documentation - + Specifies the file system location of the database configuration files. If @@ -273,7 +275,7 @@ PostgreSQL documentation - + Append the server log output to @@ -286,7 +288,7 @@ PostgreSQL documentation - + Specifies the shutdown mode. mode @@ -299,6 +301,7 @@ PostgreSQL documentation + Specifies options to be passed directly to the @@ -314,6 +317,7 @@ PostgreSQL documentation + Specifies options to be passed directly to the @@ -361,8 +365,8 @@ PostgreSQL documentation - The maximum number of seconds to wait when waiting for startup or - shutdown to complete. Defaults to the value of the + The maximum number of seconds to wait when waiting for an operation + to complete (see option ). Defaults to the value of the PGCTLTIMEOUT environment variable or, if not set, to 60 seconds. @@ -381,10 +385,16 @@ PostgreSQL documentation + - Wait for the startup or shutdown to complete. - Waiting is the default option for shutdowns, but not startups. + Wait for an operation to complete. This is supported for the + modes start, stop, + restart, promote, + and register, and is the default for those modes. + + + When waiting for startup, pg_ctl repeatedly attempts to connect to the server. When waiting for shutdown, pg_ctl waits for @@ -398,10 +408,23 @@ PostgreSQL documentation + - Do not wait for startup or shutdown to complete. This is the - default for start and restart modes. + Do not wait for an operation to complete. This is the opposite of the + option . + + + + If waiting is disabled, the requested action is triggered, but there + is no feedback about its success. In that case, the server log file + or an external monitoring system would have to be used to check the + progress and success of the operation. + + + + In prior releases of PostgreSQL, this was the default except for + the stop mode. @@ -572,7 +595,7 @@ PostgreSQL documentation To start the server, waiting until the server is accepting connections: -$ pg_ctl -w start +$ pg_ctl start @@ -594,7 +617,7 @@ PostgreSQL documentation The option allows control over how the server shuts down: -$ pg_ctl stop -m fast +$ pg_ctl stop -m smart @@ -616,7 +639,7 @@ PostgreSQL documentation To restart the server, waiting for it to shut down and restart: -$ pg_ctl -w restart +$ pg_ctl restart diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml index be1b684082..a1e03c481d 100644 --- a/doc/src/sgml/ref/pg_dump.sgml +++ b/doc/src/sgml/ref/pg_dump.sgml @@ -138,8 +138,27 @@ PostgreSQL documentation Include large objects in the dump. This is the default behavior except when + + + + + + + + + Exclude large objects in the dump. + + + + When both @@ -699,6 +718,11 @@ PostgreSQL documentation to dump the parts of the contents of the table that they have access to. + + Note that if you use this option currently, you probably also want + the dump be in INSERT format, as the + COPY FROM during restore does not support row security. + @@ -731,6 +755,15 @@ PostgreSQL documentation + + + + + Include logical replication subscriptions in the dump. + + + + @@ -758,10 +791,21 @@ PostgreSQL documentation the dump. Instead fail if unable to lock a table within the specified timeout. The timeout may be specified in any of the formats accepted by SET - statement_timeout. (Allowed values vary depending on the server + statement_timeout. (Allowed formats vary depending on the server version you are dumping from, but an integer number of milliseconds - is accepted by all versions since 7.3. This option is ignored when - dumping from a pre-7.3 server.) + is accepted by all versions.) + + + + + + + + + When dumping logical replication subscriptions, + generate CREATE SUBSCRIPTION commands that do not + create the remote replication slot. That way, the dump can be + restored without requiring network access to the remote servers. @@ -1172,7 +1216,7 @@ CREATE DATABASE foo WITH TEMPLATE template0; PostgreSQL server versions newer than pg_dump's version. pg_dump can also dump from PostgreSQL servers older than its own version. - (Currently, servers back to version 7.0 are supported.) + (Currently, servers back to version 8.0 are supported.) However, pg_dump cannot dump from PostgreSQL servers newer than its own major version; it will refuse to even try, rather than risk making an invalid dump. diff --git a/doc/src/sgml/ref/pg_receivexlog.sgml b/doc/src/sgml/ref/pg_receivexlog.sgml index bfa055b58b..8c1ea9a2e2 100644 --- a/doc/src/sgml/ref/pg_receivexlog.sgml +++ b/doc/src/sgml/ref/pg_receivexlog.sgml @@ -180,6 +180,19 @@ PostgreSQL documentation + + + + + + + Enables gzip compression of transaction logs, and specifies the + compression level (0 through 9, 0 being no compression and 9 being best + compression). The suffix .gz will + automatically be added to all filenames. + + + diff --git a/doc/src/sgml/ref/pg_recvlogical.sgml b/doc/src/sgml/ref/pg_recvlogical.sgml index b35881f2b9..d066ce8701 100644 --- a/doc/src/sgml/ref/pg_recvlogical.sgml +++ b/doc/src/sgml/ref/pg_recvlogical.sgml @@ -38,6 +38,14 @@ PostgreSQL documentation constraints as , plus those for logical replication (see ). + + + pg_recvlogical has no equivalent to the logical decoding + SQL interface's peek and get modes. It sends replay confirmations for + data lazily as it receives it and on clean exit. To examine pending data on + a slot without consuming it, use + pg_logical_slot_peek_changes. + @@ -154,6 +162,32 @@ PostgreSQL documentation + + + + + + In mode, automatically stop replication + and exit with normal exit status 0 when receiving reaches the + specified LSN. If specified when not in + mode, an error is raised. + + + + If there's a record with LSN exactly equal to lsn, + the record will be output. + + + + The option is not aware of transaction + boundaries and may truncate output partway through a transaction. + Any partially output transaction will not be consumed and will be + replayed again when the slot is next read from. Individual messages + are never truncated. + + + + diff --git a/doc/src/sgml/ref/pg_resetxlog.sgml b/doc/src/sgml/ref/pg_resetxlog.sgml index fd9d0be6f4..c949c5e849 100644 --- a/doc/src/sgml/ref/pg_resetxlog.sgml +++ b/doc/src/sgml/ref/pg_resetxlog.sgml @@ -173,22 +173,22 @@ PostgreSQL documentation The WAL starting address should be larger than any WAL segment file name currently existing in - the directory pg_xlog under the data directory. + the directory pg_wal under the data directory. These names are also in hexadecimal and have three parts. The first part is the timeline ID and should usually be kept the same. For example, if 00000001000000320000004A is the - largest entry in pg_xlog, use -l 00000001000000320000004B or higher. + largest entry in pg_wal, use -l 00000001000000320000004B or higher. pg_resetxlog itself looks at the files in - pg_xlog and chooses a default diff --git a/doc/src/sgml/ref/pg_restore.sgml b/doc/src/sgml/ref/pg_restore.sgml index c9069193af..44f0515066 100644 --- a/doc/src/sgml/ref/pg_restore.sgml +++ b/doc/src/sgml/ref/pg_restore.sgml @@ -302,7 +302,7 @@ - + @@ -314,6 +314,22 @@ + + + + + + Do not restore objects that are in the named schema. Multiple schemas + to be excluded may be specified with multiple + + + When both + + + @@ -527,7 +543,7 @@ Note that this option currently also requires the dump be in INSERT - format, as COPY TO does not support row security. + format, as COPY FROM does not support row security. diff --git a/doc/src/sgml/ref/pg_rewind.sgml b/doc/src/sgml/ref/pg_rewind.sgml index 42ebfbfdef..371c4a475f 100644 --- a/doc/src/sgml/ref/pg_rewind.sgml +++ b/doc/src/sgml/ref/pg_rewind.sgml @@ -61,14 +61,14 @@ PostgreSQL documentation pg_rewind examines the timeline histories of the source and target clusters to determine the point where they diverged, and - expects to find WAL in the target cluster's pg_xlog directory + expects to find WAL in the target cluster's pg_wal directory reaching all the way back to the point of divergence. The point of divergence can be found either on the target timeline, the source timeline, or their common ancestor. In the typical failover scenario where the target cluster was shut down soon after the divergence, this is not a problem, but if the target cluster ran for a long time after the divergence, the old WAL files might no longer be present. In that case, they can be manually - copied from the WAL archive to the pg_xlog directory, or + copied from the WAL archive to the pg_wal directory, or fetched on startup by configuring recovery.conf. The use of pg_rewind is not limited to failover, e.g. a standby server can be promoted, run some write transactions, and then rewinded diff --git a/doc/src/sgml/ref/pg_xlogdump.sgml b/doc/src/sgml/ref/pg_xlogdump.sgml index 296f1acc24..078b08e2e6 100644 --- a/doc/src/sgml/ref/pg_xlogdump.sgml +++ b/doc/src/sgml/ref/pg_xlogdump.sgml @@ -117,9 +117,12 @@ PostgreSQL documentation - Directory in which to find log segment files. The default is to search - for them in the pg_xlog subdirectory of the current - directory. + Specifies a directory to search for log segment files or a + directory with a pg_wal subdirectory that + contains such files. The default is to search in the current + directory, the pg_wal subdirectory of the + current directory, and the pg_wal subdirectory + of PGDATA. @@ -153,7 +156,7 @@ PostgreSQL documentation Timeline from which to read log records. The default is to use the - value in startseg, if that is specified; otherwise, the + value in startseg, if that is specified; otherwise, the default is 1. diff --git a/doc/src/sgml/ref/pgarchivecleanup.sgml b/doc/src/sgml/ref/pgarchivecleanup.sgml index 60a7fc4e6b..abe01bef4f 100644 --- a/doc/src/sgml/ref/pgarchivecleanup.sgml +++ b/doc/src/sgml/ref/pgarchivecleanup.sgml @@ -122,7 +122,7 @@ pg_archivecleanup: removing file "archive/00000001000000370000000E" extension - When using the program as a standalone utility, provide an extension + Provide an extension that will be stripped from all file names before deciding if they should be deleted. This is typically useful for cleaning up archives that have been compressed during storage, and therefore have had an diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml index f58da351f9..1eee8dc574 100644 --- a/doc/src/sgml/ref/pgbench.sgml +++ b/doc/src/sgml/ref/pgbench.sgml @@ -355,7 +355,7 @@ pgbench options dbname - Write the time taken by each transaction to a log file. + Write information about each transaction to a log file. See below for details. @@ -433,7 +433,7 @@ pgbench options dbname sec - Show progress report every sec seconds. The report + Show progress report every sec seconds. The report includes the time since the beginning of the run, the tps since the last report, and the transaction latency average and standard deviation since the last report. Under throttling ( + + + + + Set the filename prefix for the transaction log files created by + + + + @@ -803,7 +809,8 @@ pgbench options dbname Script file meta commands begin with a backslash (\) and - extend to the end of the line. + normally extend to the end of the line, although they can be continued + to additional lines by writing backslash-return. Arguments to a meta command are separated by white space. These meta commands are supported: @@ -832,7 +839,8 @@ pgbench options dbname Examples: \set ntellers 10 * :scale -\set aid (1021 * random(1, 100000 * :scale)) % (100000 * :scale) + 1 +\set aid (1021 * random(1, 100000 * :scale)) % \ + (100000 * :scale) + 1 @@ -1118,16 +1126,20 @@ END; Per-Transaction Logging - With the , - pgbench writes the time taken by each transaction + With the option), + pgbench writes information about each transaction to a log file. The log file will be named - pgbench_log.nnn, where - nnn is the PID of the pgbench process. - If the @@ -1136,18 +1148,22 @@ END; The format of the log is: -client_id transaction_no time script_no time_epoch time_us schedule_lag +client_id transaction_no time script_no time_epoch time_us schedule_lag - where time is the total elapsed transaction time in microseconds, + where + client_id indicates which client session ran the transaction, + transaction_no counts how many transactions have been + run by that session, + time is the total elapsed transaction time in microseconds, script_no identifies which script file was used (useful when multiple scripts were specified with diff --git a/doc/src/sgml/ref/select.sgml b/doc/src/sgml/ref/select.sgml index e0098eb8d3..211e4c320c 100644 --- a/doc/src/sgml/ref/select.sgml +++ b/doc/src/sgml/ref/select.sgml @@ -391,7 +391,7 @@ TABLE [ ONLY ] table_name [ * ] not been changed meanwhile. But different seed values will usually produce different samples. If REPEATABLE is not given then a new random - seed is selected for each query. + sample is selected for each query, based upon a system-generated seed. Note that some add-on sampling methods do not accept REPEATABLE, and will always produce new samples on each use. diff --git a/doc/src/sgml/ref/set_role.sgml b/doc/src/sgml/ref/set_role.sgml index aff3792199..a97ceabcff 100644 --- a/doc/src/sgml/ref/set_role.sgml +++ b/doc/src/sgml/ref/set_role.sgml @@ -127,7 +127,7 @@ SELECT SESSION_USER, CURRENT_USER; PostgreSQL - allows identifier syntax ("rolename"), while + allows identifier syntax ("rolename"), while the SQL standard requires the role name to be written as a string literal. SQL does not allow this command during a transaction; PostgreSQL does not make this diff --git a/doc/src/sgml/ref/set_session_auth.sgml b/doc/src/sgml/ref/set_session_auth.sgml index 4ac2128950..96d279aaf9 100644 --- a/doc/src/sgml/ref/set_session_auth.sgml +++ b/doc/src/sgml/ref/set_session_auth.sgml @@ -101,7 +101,7 @@ SELECT SESSION_USER, CURRENT_USER; The SQL standard allows some other expressions to appear in place of the literal user_name, but these options are not important in practice. PostgreSQL - allows identifier syntax ("username"), which SQL + allows identifier syntax ("username"), which SQL does not. SQL does not allow this command during a transaction; PostgreSQL does not make this restriction because there is no reason to. diff --git a/doc/src/sgml/ref/update.sgml b/doc/src/sgml/ref/update.sgml index c50434f85f..8a1619fb68 100644 --- a/doc/src/sgml/ref/update.sgml +++ b/doc/src/sgml/ref/update.sgml @@ -24,7 +24,7 @@ PostgreSQL documentation [ WITH [ RECURSIVE ] with_query [, ...] ] UPDATE [ ONLY ] table_name [ * ] [ [ AS ] alias ] SET { column_name = { expression | DEFAULT } | - ( column_name [, ...] ) = ( { expression | DEFAULT } [, ...] ) | + ( column_name [, ...] ) = [ ROW ] ( { expression | DEFAULT } [, ...] ) | ( column_name [, ...] ) = ( sub-SELECT ) } [, ...] [ FROM from_list ] @@ -279,6 +279,14 @@ UPDATE count sub-selects is safer, though often harder to read and slower than using a join. + + + In the case of a partitioned table, updating a row might cause it to no + longer satisfy the partition constraint. Since there is no provision to + move the row to the partition appropriate to the new value of its + partitioning key, an error will occur in this case. This can also happen + when updating a partition directly. + @@ -420,12 +428,12 @@ UPDATE films SET kind = 'Dramatic' WHERE CURRENT OF c_films; According to the standard, the source value for a parenthesized sub-list of - column names can be any row-valued expression yielding the correct number - of columns. PostgreSQL only allows the source - value to be a parenthesized list of expressions (a row constructor) or a - sub-SELECT. An individual column's updated value can be - specified as DEFAULT in the row-constructor case, but not - inside a sub-SELECT. + target column names can be any row-valued expression yielding the correct + number of columns. PostgreSQL only allows the + source value to be a row + constructor or a sub-SELECT. An individual column's + updated value can be specified as DEFAULT in the + row-constructor case, but not inside a sub-SELECT. diff --git a/doc/src/sgml/ref/vacuum.sgml b/doc/src/sgml/ref/vacuum.sgml index dee1c5bad3..f18180a2fa 100644 --- a/doc/src/sgml/ref/vacuum.sgml +++ b/doc/src/sgml/ref/vacuum.sgml @@ -253,27 +253,27 @@ INFO: vacuuming "public.onek" INFO: index "onek_unique1" now contains 1000 tuples in 14 pages DETAIL: 3000 index tuples were removed. 0 index pages have been deleted, 0 are currently reusable. -CPU 0.01s/0.08u sec elapsed 0.18 sec. +CPU: user: 0.08 s, system: 0.01 s, elapsed: 0.18 s. INFO: index "onek_unique2" now contains 1000 tuples in 16 pages DETAIL: 3000 index tuples were removed. 0 index pages have been deleted, 0 are currently reusable. -CPU 0.00s/0.07u sec elapsed 0.23 sec. +CPU: user: 0.07 s, system: 0.00 s, elapsed: 0.23 s. INFO: index "onek_hundred" now contains 1000 tuples in 13 pages DETAIL: 3000 index tuples were removed. 0 index pages have been deleted, 0 are currently reusable. -CPU 0.01s/0.08u sec elapsed 0.17 sec. +CPU: user: 0.08 s, system: 0.01 s, elapsed: 0.17 s. INFO: index "onek_stringu1" now contains 1000 tuples in 48 pages DETAIL: 3000 index tuples were removed. 0 index pages have been deleted, 0 are currently reusable. -CPU 0.01s/0.09u sec elapsed 0.59 sec. +CPU: user: 0.09 s, system: 0.01 s, elapsed: 0.59 s. INFO: "onek": removed 3000 tuples in 108 pages -DETAIL: CPU 0.01s/0.06u sec elapsed 0.07 sec. +DETAIL: CPU: user: 0.06 s, system: 0.01 s, elapsed: 0.07 s. INFO: "onek": found 3000 removable, 1000 nonremovable tuples in 143 pages DETAIL: 0 dead tuples cannot be removed yet. There were 0 unused item pointers. Skipped 0 pages due to buffer pins. 0 pages are entirely empty. -CPU 0.07s/0.39u sec elapsed 1.56 sec. +CPU: user: 0.39 s, system: 0.07 s, elapsed: 1.56 s. INFO: analyzing "public.onek" INFO: "onek": 36 pages, 1000 rows sampled, 1000 estimated total rows VACUUM diff --git a/doc/src/sgml/ref/vacuumdb.sgml b/doc/src/sgml/ref/vacuumdb.sgml index 92b8984b7a..4f6fa0d708 100644 --- a/doc/src/sgml/ref/vacuumdb.sgml +++ b/doc/src/sgml/ref/vacuumdb.sgml @@ -430,7 +430,7 @@ PostgreSQL documentation xyzzy, and analyze a single column bar of the table for the optimizer: -$ vacuumdb --analyze --verbose --table 'foo(bar)' xyzzy +$ vacuumdb --analyze --verbose --table='foo(bar)' xyzzy diff --git a/doc/src/sgml/reference.sgml b/doc/src/sgml/reference.sgml index 8acdff1393..34007d3508 100644 --- a/doc/src/sgml/reference.sgml +++ b/doc/src/sgml/reference.sgml @@ -54,11 +54,13 @@ &alterOperatorClass; &alterOperatorFamily; &alterPolicy; + &alterPublication; &alterRole; &alterRule; &alterSchema; &alterSequence; &alterServer; + &alterSubscription; &alterSystem; &alterTable; &alterTableSpace; @@ -100,11 +102,13 @@ &createOperatorClass; &createOperatorFamily; &createPolicy; + &createPublication; &createRole; &createRule; &createSchema; &createSequence; &createServer; + &createSubscription; &createTable; &createTableAs; &createTableSpace; @@ -144,11 +148,13 @@ &dropOperatorFamily; &dropOwned; &dropPolicy; + &dropPublication; &dropRole; &dropRule; &dropSchema; &dropSequence; &dropServer; + &dropSubscription; &dropTable; &dropTableSpace; &dropTSConfig; diff --git a/doc/src/sgml/release-7.4.sgml b/doc/src/sgml/release-7.4.sgml index 5a4c52d4c2..e42be5b89d 100644 --- a/doc/src/sgml/release-7.4.sgml +++ b/doc/src/sgml/release-7.4.sgml @@ -268,7 +268,7 @@ - This behavior has been observed on BSD-derived kernels including OS X. + This behavior has been observed on BSD-derived kernels including macOS. It resulted in an entirely-misleading startup failure complaining that the shared memory request size was too large. @@ -2437,7 +2437,7 @@ aggregate plan Pretty-print UNION queries correctly Make psql handle \r\n newlines properly in COPY IN pg_dump handled ACLs with grant options incorrectly -Fix thread support for OS X and Solaris +Fix thread support for macOS and Solaris Updated JDBC driver (build 215) with various fixes ECPG fixes Translation updates (various contributors) @@ -2627,7 +2627,7 @@ memory error during COPY IN TABLE AS from tables without OIDs Fix problems with alter_table regression test during parallel testing -Fix problems with hitting open file limit, especially on OS X (Tom) +Fix problems with hitting open file limit, especially on macOS (Tom) Partial fix for Turkish-locale issues initdb will succeed now in Turkish locale, but there are still some inconveniences associated with the i/I problem. @@ -3256,7 +3256,7 @@ DROP SCHEMA information_schema CASCADE; - Enable PAM for Mac OS X (Aaron Hillegass) + Enable PAM for macOS (Aaron Hillegass) Make B-tree indexes fully WAL-safe (Tom) @@ -3539,9 +3539,9 @@ DROP SCHEMA information_schema CASCADE; - Add Mac OS X Rendezvous server support (Chris Campbell) + Add macOS Rendezvous server support (Chris Campbell) - This allows Mac OS X hosts to query the network for available + This allows macOS hosts to query the network for available PostgreSQL servers. @@ -4561,7 +4561,7 @@ DROP SCHEMA information_schema CASCADE; Fix locking code for s390x CPU (64-bit) (Tom) Allow OpenBSD to use local ident credentials (William Ahern) Make query plan trees read-only to executor (Tom) - Add Darwin startup scripts (David Wheeler) + Add macOS startup scripts (David Wheeler) Allow libpq to compile with Borland C++ compiler (Lester Godwin, Karl Waclawek) Use our own version of getopt_long() if needed (Peter) Convert administration scripts to C (Peter) diff --git a/doc/src/sgml/release-8.0.sgml b/doc/src/sgml/release-8.0.sgml index 299c34e0f0..becd5090cc 100644 --- a/doc/src/sgml/release-8.0.sgml +++ b/doc/src/sgml/release-8.0.sgml @@ -345,7 +345,7 @@ - This behavior has been observed on BSD-derived kernels including OS X. + This behavior has been observed on BSD-derived kernels including macOS. It resulted in an entirely-misleading startup failure complaining that the shared memory request size was too large. @@ -1715,7 +1715,7 @@ While this could theoretically happen anywhere, no standard build of - Perl did things this way ... until Mac OS X 10.5. + Perl did things this way ... until macOS 10.5. @@ -2449,7 +2449,7 @@ Win32 to match the backend (Andrew) (Bruce) Fix pgxs -L library path -specification for Win32, Cygwin, OS X, AIX (Bruce) +specification for Win32, Cygwin, macOS, AIX (Bruce) Check that SID is enabled while checking for Win32 admin privileges (Magnus) @@ -5224,7 +5224,7 @@ typedefs (Michael) - Improvements to the Mac OS X startup scripts (Ray A.) + Improvements to the macOS startup scripts (Ray A.) @@ -5328,7 +5328,7 @@ typedefs (Michael) - Make libpq and ECPG build as proper shared libraries on OS X (Tom) + Make libpq and ECPG build as proper shared libraries on macOS (Tom) diff --git a/doc/src/sgml/release-8.1.sgml b/doc/src/sgml/release-8.1.sgml index 0cb5587e9b..05b07ade99 100644 --- a/doc/src/sgml/release-8.1.sgml +++ b/doc/src/sgml/release-8.1.sgml @@ -572,7 +572,7 @@ - This behavior has been observed on BSD-derived kernels including OS X. + This behavior has been observed on BSD-derived kernels including macOS. It resulted in an entirely-misleading startup failure complaining that the shared memory request size was too large. @@ -2188,7 +2188,7 @@ While this could theoretically happen anywhere, no standard build of - Perl did things this way ... until Mac OS X 10.5. + Perl did things this way ... until macOS 10.5. @@ -2730,7 +2730,7 @@ - Fix for Darwin (OS X) compilation (Tom) + Fix for macOS (Darwin) compilation (Tom) @@ -3104,7 +3104,7 @@ Win32 to match the backend (Andrew) (Bruce) Fix pgxs -L library path -specification for Win32, Cygwin, OS X, AIX (Bruce) +specification for Win32, Cygwin, macOS, AIX (Bruce) Check that SID is enabled while checking for Win32 admin privileges (Magnus) @@ -5225,7 +5225,7 @@ SELECT CURRENT_TIMESTAMP AT TIME ZONE 'Europe/London'; Add support for fsync_writethrough on - Darwin (Chris Campbell) + macOS (Chris Campbell) diff --git a/doc/src/sgml/release-8.2.sgml b/doc/src/sgml/release-8.2.sgml index 7f6a74bac9..2d21728cf7 100644 --- a/doc/src/sgml/release-8.2.sgml +++ b/doc/src/sgml/release-8.2.sgml @@ -1487,7 +1487,7 @@ - This behavior has been observed on BSD-derived kernels including OS X. + This behavior has been observed on BSD-derived kernels including macOS. It resulted in an entirely-misleading startup failure complaining that the shared memory request size was too large. @@ -3765,7 +3765,7 @@ While this could theoretically happen anywhere, no standard build of - Perl did things this way ... until Mac OS X 10.5. + Perl did things this way ... until macOS 10.5. diff --git a/doc/src/sgml/release-8.3.sgml b/doc/src/sgml/release-8.3.sgml index b56edb0102..b1b5d4875c 100644 --- a/doc/src/sgml/release-8.3.sgml +++ b/doc/src/sgml/release-8.3.sgml @@ -3075,7 +3075,7 @@ - This behavior has been observed on BSD-derived kernels including OS X. + This behavior has been observed on BSD-derived kernels including macOS. It resulted in an entirely-misleading startup failure complaining that the shared memory request size was too large. @@ -8396,7 +8396,7 @@ current_date < 2017-11-17 Use SYSV semaphores rather than POSIX on Darwin - >= 6.0, i.e., OS X 10.2 and up (Chris Marcellino) + >= 6.0, i.e., macOS 10.2 and up (Chris Marcellino) diff --git a/doc/src/sgml/release-8.4.sgml b/doc/src/sgml/release-8.4.sgml index 8b16c9e9d3..0d0478855e 100644 --- a/doc/src/sgml/release-8.4.sgml +++ b/doc/src/sgml/release-8.4.sgml @@ -240,7 +240,7 @@ - Fix linking of libpython on OS X (Tom Lane) + Fix linking of libpython on macOS (Tom Lane) @@ -5334,7 +5334,7 @@ - This behavior has been observed on BSD-derived kernels including OS X. + This behavior has been observed on BSD-derived kernels including macOS. It resulted in an entirely-misleading startup failure complaining that the shared memory request size was too large. @@ -9764,7 +9764,7 @@ WITH w AS (SELECT * FROM foo) SELECT * FROM w, bar ... FOR UPDATE - Enable DTrace support on Mac OS X + Enable DTrace support on macOS Leopard and other non-Solaris platforms (Robert Lor) diff --git a/doc/src/sgml/release-9.0.sgml b/doc/src/sgml/release-9.0.sgml index 61dce9fd78..2238b53745 100644 --- a/doc/src/sgml/release-9.0.sgml +++ b/doc/src/sgml/release-9.0.sgml @@ -1541,7 +1541,7 @@ - Warn if OS X's setlocale() starts an unwanted extra + Warn if macOS's setlocale() starts an unwanted extra thread inside the postmaster (Noah Misch) @@ -2093,7 +2093,7 @@ - Fix linking of libpython on OS X (Tom Lane) + Fix linking of libpython on macOS (Tom Lane) @@ -5895,7 +5895,7 @@ - Fix incorrect quoting of log file name in Mac OS X start script + Fix incorrect quoting of log file name in macOS start script (Sidar Lopez) @@ -10745,7 +10745,7 @@ if TG_OP = 'INSERT' and NEW.col1 = ... then - Bonjour support now requires OS X 10.3 or later. + Bonjour support now requires macOS 10.3 or later. The older API has been deprecated by Apple. diff --git a/doc/src/sgml/release-9.1.sgml b/doc/src/sgml/release-9.1.sgml index a66ca0d5b3..edacfbf355 100644 --- a/doc/src/sgml/release-9.1.sgml +++ b/doc/src/sgml/release-9.1.sgml @@ -1,6 +1,216 @@ + + Release 9.1.24 + + + Release Date + 2016-10-27 + + + + This release contains a variety of fixes from 9.1.23. + For information about new features in the 9.1 major release, see + . + + + + This is expected to be the last PostgreSQL release + in the 9.1.X series. Users are encouraged to update to a newer + release branch soon. + + + + Migration to Version 9.1.24 + + + A dump/restore is not required for those running 9.1.X. + + + + However, if you are upgrading from a version earlier than 9.1.16, + see . + + + + + + Changes + + + + + + Fix EvalPlanQual rechecks involving CTE scans (Tom Lane) + + + + The recheck would always see the CTE as returning no rows, typically + leading to failure to update rows that were recently updated. + + + + + + Fix improper repetition of previous results from hashed aggregation in + a subquery (Andrew Gierth) + + + + The test to see if we can reuse a previously-computed hash table of + the aggregate state values neglected the possibility of an outer query + reference appearing in an aggregate argument expression. A change in + the value of such a reference should lead to recalculating the hash + table, but did not. + + + + + + Fix timeout length when VACUUM is waiting for exclusive + table lock so that it can truncate the table (Simon Riggs) + + + + The timeout was meant to be 50 milliseconds, but it was actually only + 50 microseconds, causing VACUUM to give up on truncation + much more easily than intended. Set it to the intended value. + + + + + + Remove artificial restrictions on the values accepted + by numeric_in() and numeric_recv() + (Tom Lane) + + + + We allow numeric values up to the limit of the storage format (more + than 1e100000), so it seems fairly pointless + that numeric_in() rejected scientific-notation exponents + above 1000. Likewise, it was silly for numeric_recv() to + reject more than 1000 digits in an input value. + + + + + + Avoid very-low-probability data corruption due to testing tuple + visibility without holding buffer lock (Thomas Munro, Peter Geoghegan, + Tom Lane) + + + + + + Fix file descriptor leakage when truncating a temporary relation of + more than 1GB (Andres Freund) + + + + + + Disallow starting a standalone backend with standby_mode + turned on (Michael Paquier) + + + + This can't do anything useful, since there will be no WAL receiver + process to fetch more WAL data; and it could result in misbehavior + in code that wasn't designed with this situation in mind. + + + + + + Don't try to share SSL contexts across multiple connections + in libpq (Heikki Linnakangas) + + + + This led to assorted corner-case bugs, particularly when trying to use + different SSL parameters for different connections. + + + + + + Avoid corner-case memory leak in libpq (Tom Lane) + + + + The reported problem involved leaking an error report + during PQreset(), but there might be related cases. + + + + + + Make ecpg's + + + + + Fix contrib/intarray/bench/bench.pl to print the results + of the EXPLAIN it does when given the + + + + + Prevent failure of obsolete dynamic time zone abbreviations (Tom Lane) + + + + If a dynamic time zone abbreviation does not match any entry in the + referenced time zone, treat it as equivalent to the time zone name. + This avoids unexpected failures when IANA removes abbreviations from + their time zone database, as they did in tzdata + release 2016f and seem likely to do again in the future. The + consequences were not limited to not recognizing the individual + abbreviation; any mismatch caused + the pg_timezone_abbrevs view to fail altogether. + + + + + + Update time zone data files to tzdata release 2016h + for DST law changes in Palestine and Turkey, plus historical + corrections for Turkey and some regions of Russia. + Switch to numeric abbreviations for some time zones in Antarctica, + the former Soviet Union, and Sri Lanka. + + + + The IANA time zone database previously provided textual abbreviations + for all time zones, sometimes making up abbreviations that have little + or no currency among the local population. They are in process of + reversing that policy in favor of using numeric UTC offsets in zones + where there is no evidence of real-world use of an English + abbreviation. At least for the time being, PostgreSQL + will continue to accept such removed abbreviations for timestamp input. + But they will not be shown in the pg_timezone_names + view nor used for output. + + + + In this update, AMT is no longer shown as being in use to + mean Armenia Time. Therefore, we have changed the Default + abbreviation set to interpret it as Amazon Time, thus UTC-4 not UTC+4. + + + + + + + + Release 9.1.23 @@ -599,7 +809,7 @@ Branch: REL9_1_STABLE [354b3a3ac] 2016-06-19 14:01:17 -0400 This dodges a portability problem on FreeBSD-derived platforms - (including OS X). + (including macOS). @@ -2937,7 +3147,7 @@ Branch: REL9_0_STABLE [9d6af7367] 2015-08-15 11:02:34 -0400 - Warn if OS X's setlocale() starts an unwanted extra + Warn if macOS's setlocale() starts an unwanted extra thread inside the postmaster (Noah Misch) @@ -3574,7 +3784,7 @@ Branch: REL9_0_STABLE [9d6af7367] 2015-08-15 11:02:34 -0400 - Fix linking of libpython on OS X (Tom Lane) + Fix linking of libpython on macOS (Tom Lane) @@ -8443,7 +8653,7 @@ Branch: REL9_0_STABLE [9d6af7367] 2015-08-15 11:02:34 -0400 - Fix incorrect quoting of log file name in Mac OS X start script + Fix incorrect quoting of log file name in macOS start script (Sidar Lopez) diff --git a/doc/src/sgml/release-9.2.sgml b/doc/src/sgml/release-9.2.sgml index c801f98c3f..49430389d9 100644 --- a/doc/src/sgml/release-9.2.sgml +++ b/doc/src/sgml/release-9.2.sgml @@ -1,6 +1,272 @@ + + Release 9.2.19 + + + Release Date + 2016-10-27 + + + + This release contains a variety of fixes from 9.2.18. + For information about new features in the 9.2 major release, see + . + + + + Migration to Version 9.2.19 + + + A dump/restore is not required for those running 9.2.X. + + + + However, if you are upgrading from a version earlier than 9.2.11, + see . + + + + + + Changes + + + + + + Fix EvalPlanQual rechecks involving CTE scans (Tom Lane) + + + + The recheck would always see the CTE as returning no rows, typically + leading to failure to update rows that were recently updated. + + + + + + Fix improper repetition of previous results from hashed aggregation in + a subquery (Andrew Gierth) + + + + The test to see if we can reuse a previously-computed hash table of + the aggregate state values neglected the possibility of an outer query + reference appearing in an aggregate argument expression. A change in + the value of such a reference should lead to recalculating the hash + table, but did not. + + + + + + Fix EXPLAIN to emit valid XML when + is on (Markus Winand) + + + + Previously the XML output-format option produced syntactically invalid + tags such as <I/O-Read-Time>. That is now + rendered as <I-O-Read-Time>. + + + + + + Suppress printing of zeroes for unmeasured times + in EXPLAIN (Maksim Milyutin) + + + + Certain option combinations resulted in printing zero values for times + that actually aren't ever measured in that combination. Our general + policy in EXPLAIN is not to print such fields at all, so + do that consistently in all cases. + + + + + + Fix timeout length when VACUUM is waiting for exclusive + table lock so that it can truncate the table (Simon Riggs) + + + + The timeout was meant to be 50 milliseconds, but it was actually only + 50 microseconds, causing VACUUM to give up on truncation + much more easily than intended. Set it to the intended value. + + + + + + Fix bugs in merging inherited CHECK constraints while + creating or altering a table (Tom Lane, Amit Langote) + + + + Allow identical CHECK constraints to be added to a parent + and child table in either order. Prevent merging of a valid + constraint from the parent table with a NOT VALID + constraint on the child. Likewise, prevent merging of a NO + INHERIT child constraint with an inherited constraint. + + + + + + Remove artificial restrictions on the values accepted + by numeric_in() and numeric_recv() + (Tom Lane) + + + + We allow numeric values up to the limit of the storage format (more + than 1e100000), so it seems fairly pointless + that numeric_in() rejected scientific-notation exponents + above 1000. Likewise, it was silly for numeric_recv() to + reject more than 1000 digits in an input value. + + + + + + Avoid very-low-probability data corruption due to testing tuple + visibility without holding buffer lock (Thomas Munro, Peter Geoghegan, + Tom Lane) + + + + + + Fix file descriptor leakage when truncating a temporary relation of + more than 1GB (Andres Freund) + + + + + + Disallow starting a standalone backend with standby_mode + turned on (Michael Paquier) + + + + This can't do anything useful, since there will be no WAL receiver + process to fetch more WAL data; and it could result in misbehavior + in code that wasn't designed with this situation in mind. + + + + + + Don't try to share SSL contexts across multiple connections + in libpq (Heikki Linnakangas) + + + + This led to assorted corner-case bugs, particularly when trying to use + different SSL parameters for different connections. + + + + + + Avoid corner-case memory leak in libpq (Tom Lane) + + + + The reported problem involved leaking an error report + during PQreset(), but there might be related cases. + + + + + + Make ecpg's + + + + + In pg_dump, never dump range constructor functions + (Tom Lane) + + + + This oversight led to pg_upgrade failures with + extensions containing range types, due to duplicate creation of the + constructor functions. + + + + + + Fix contrib/intarray/bench/bench.pl to print the results + of the EXPLAIN it does when given the + + + + + Update Windows time zone mapping to recognize some time zone names + added in recent Windows versions (Michael Paquier) + + + + + + Prevent failure of obsolete dynamic time zone abbreviations (Tom Lane) + + + + If a dynamic time zone abbreviation does not match any entry in the + referenced time zone, treat it as equivalent to the time zone name. + This avoids unexpected failures when IANA removes abbreviations from + their time zone database, as they did in tzdata + release 2016f and seem likely to do again in the future. The + consequences were not limited to not recognizing the individual + abbreviation; any mismatch caused + the pg_timezone_abbrevs view to fail altogether. + + + + + + Update time zone data files to tzdata release 2016h + for DST law changes in Palestine and Turkey, plus historical + corrections for Turkey and some regions of Russia. + Switch to numeric abbreviations for some time zones in Antarctica, + the former Soviet Union, and Sri Lanka. + + + + The IANA time zone database previously provided textual abbreviations + for all time zones, sometimes making up abbreviations that have little + or no currency among the local population. They are in process of + reversing that policy in favor of using numeric UTC offsets in zones + where there is no evidence of real-world use of an English + abbreviation. At least for the time being, PostgreSQL + will continue to accept such removed abbreviations for timestamp input. + But they will not be shown in the pg_timezone_names + view nor used for output. + + + + In this update, AMT is no longer shown as being in use to + mean Armenia Time. Therefore, we have changed the Default + abbreviation set to interpret it as Amazon Time, thus UTC-4 not UTC+4. + + + + + + + + Release 9.2.18 @@ -629,7 +895,7 @@ This dodges a portability problem on FreeBSD-derived platforms - (including OS X). + (including macOS). @@ -3190,7 +3456,7 @@ Branch: REL9_2_STABLE [6b700301c] 2015-02-17 16:03:00 +0100 - Warn if OS X's setlocale() starts an unwanted extra + Warn if macOS's setlocale() starts an unwanted extra thread inside the postmaster (Noah Misch) @@ -3899,7 +4165,7 @@ Branch: REL9_2_STABLE [6b700301c] 2015-02-17 16:03:00 +0100 - Fix linking of libpython on OS X (Tom Lane) + Fix linking of libpython on macOS (Tom Lane) diff --git a/doc/src/sgml/release-9.3.sgml b/doc/src/sgml/release-9.3.sgml index c75f1109e1..81205a40c7 100644 --- a/doc/src/sgml/release-9.3.sgml +++ b/doc/src/sgml/release-9.3.sgml @@ -1,6 +1,335 @@ + + Release 9.3.15 + + + Release Date + 2016-10-27 + + + + This release contains a variety of fixes from 9.3.14. + For information about new features in the 9.3 major release, see + . + + + + Migration to Version 9.3.15 + + + A dump/restore is not required for those running 9.3.X. + + + + However, if your installation has been affected by the bug described in + the first changelog entry below, then after updating you may need + to take action to repair corrupted free space maps. + + + + Also, if you are upgrading from a version earlier than 9.3.9, + see . + + + + + + Changes + + + + + + Fix WAL-logging of truncation of relation free space maps and + visibility maps (Pavan Deolasee, Heikki Linnakangas) + + + + It was possible for these files to not be correctly restored during + crash recovery, or to be written incorrectly on a standby server. + Bogus entries in a free space map could lead to attempts to access + pages that have been truncated away from the relation itself, typically + producing errors like could not read block XXX: + read only 0 of 8192 bytes. Checksum failures in the + visibility map are also possible, if checksumming is enabled. + + + + Procedures for determining whether there is a problem and repairing it + if so are discussed at + . + + + + + + Fix SELECT FOR UPDATE/SHARE to correctly lock tuples that + have been updated by a subsequently-aborted transaction + (Álvaro Herrera) + + + + In 9.5 and later, the SELECT would sometimes fail to + return such tuples at all. A failure has not been proven to occur in + earlier releases, but might be possible with concurrent updates. + + + + + + Fix EvalPlanQual rechecks involving CTE scans (Tom Lane) + + + + The recheck would always see the CTE as returning no rows, typically + leading to failure to update rows that were recently updated. + + + + + + Fix improper repetition of previous results from hashed aggregation in + a subquery (Andrew Gierth) + + + + The test to see if we can reuse a previously-computed hash table of + the aggregate state values neglected the possibility of an outer query + reference appearing in an aggregate argument expression. A change in + the value of such a reference should lead to recalculating the hash + table, but did not. + + + + + + Fix EXPLAIN to emit valid XML when + is on (Markus Winand) + + + + Previously the XML output-format option produced syntactically invalid + tags such as <I/O-Read-Time>. That is now + rendered as <I-O-Read-Time>. + + + + + + Suppress printing of zeroes for unmeasured times + in EXPLAIN (Maksim Milyutin) + + + + Certain option combinations resulted in printing zero values for times + that actually aren't ever measured in that combination. Our general + policy in EXPLAIN is not to print such fields at all, so + do that consistently in all cases. + + + + + + Fix timeout length when VACUUM is waiting for exclusive + table lock so that it can truncate the table (Simon Riggs) + + + + The timeout was meant to be 50 milliseconds, but it was actually only + 50 microseconds, causing VACUUM to give up on truncation + much more easily than intended. Set it to the intended value. + + + + + + Fix bugs in merging inherited CHECK constraints while + creating or altering a table (Tom Lane, Amit Langote) + + + + Allow identical CHECK constraints to be added to a parent + and child table in either order. Prevent merging of a valid + constraint from the parent table with a NOT VALID + constraint on the child. Likewise, prevent merging of a NO + INHERIT child constraint with an inherited constraint. + + + + + + Remove artificial restrictions on the values accepted + by numeric_in() and numeric_recv() + (Tom Lane) + + + + We allow numeric values up to the limit of the storage format (more + than 1e100000), so it seems fairly pointless + that numeric_in() rejected scientific-notation exponents + above 1000. Likewise, it was silly for numeric_recv() to + reject more than 1000 digits in an input value. + + + + + + Avoid very-low-probability data corruption due to testing tuple + visibility without holding buffer lock (Thomas Munro, Peter Geoghegan, + Tom Lane) + + + + + + Fix file descriptor leakage when truncating a temporary relation of + more than 1GB (Andres Freund) + + + + + + Disallow starting a standalone backend with standby_mode + turned on (Michael Paquier) + + + + This can't do anything useful, since there will be no WAL receiver + process to fetch more WAL data; and it could result in misbehavior + in code that wasn't designed with this situation in mind. + + + + + + Don't try to share SSL contexts across multiple connections + in libpq (Heikki Linnakangas) + + + + This led to assorted corner-case bugs, particularly when trying to use + different SSL parameters for different connections. + + + + + + Avoid corner-case memory leak in libpq (Tom Lane) + + + + The reported problem involved leaking an error report + during PQreset(), but there might be related cases. + + + + + + Make ecpg's + + + + + In pg_dump, never dump range constructor functions + (Tom Lane) + + + + This oversight led to pg_upgrade failures with + extensions containing range types, due to duplicate creation of the + constructor functions. + + + + + + In pg_xlogdump, retry opening new WAL segments when + using + + + This allows for a possible delay in the server's creation of the next + segment. + + + + + + Fix pg_xlogdump to cope with a WAL file that begins + with a continuation record spanning more than one page (Pavan + Deolasee) + + + + + + Fix contrib/intarray/bench/bench.pl to print the results + of the EXPLAIN it does when given the + + + + + Update Windows time zone mapping to recognize some time zone names + added in recent Windows versions (Michael Paquier) + + + + + + Prevent failure of obsolete dynamic time zone abbreviations (Tom Lane) + + + + If a dynamic time zone abbreviation does not match any entry in the + referenced time zone, treat it as equivalent to the time zone name. + This avoids unexpected failures when IANA removes abbreviations from + their time zone database, as they did in tzdata + release 2016f and seem likely to do again in the future. The + consequences were not limited to not recognizing the individual + abbreviation; any mismatch caused + the pg_timezone_abbrevs view to fail altogether. + + + + + + Update time zone data files to tzdata release 2016h + for DST law changes in Palestine and Turkey, plus historical + corrections for Turkey and some regions of Russia. + Switch to numeric abbreviations for some time zones in Antarctica, + the former Soviet Union, and Sri Lanka. + + + + The IANA time zone database previously provided textual abbreviations + for all time zones, sometimes making up abbreviations that have little + or no currency among the local population. They are in process of + reversing that policy in favor of using numeric UTC offsets in zones + where there is no evidence of real-world use of an English + abbreviation. At least for the time being, PostgreSQL + will continue to accept such removed abbreviations for timestamp input. + But they will not be shown in the pg_timezone_names + view nor used for output. + + + + In this update, AMT is no longer shown as being in use to + mean Armenia Time. Therefore, we have changed the Default + abbreviation set to interpret it as Amazon Time, thus UTC-4 not UTC+4. + + + + + + + + Release 9.3.14 @@ -812,7 +1141,7 @@ Branch: REL9_2_STABLE [37f30b251] 2016-04-18 13:19:52 -0400 This dodges a portability problem on FreeBSD-derived platforms - (including OS X). + (including macOS). @@ -3021,7 +3350,7 @@ Branch: REL9_0_STABLE [4dddf8552] 2015-05-21 20:41:55 -0400 - Silence some build warnings on OS X (Tom Lane) + Silence some build warnings on macOS (Tom Lane) @@ -4092,7 +4421,7 @@ Branch: REL9_0_STABLE [2e4946169] 2015-01-07 22:46:20 -0500 - Warn if OS X's setlocale() starts an unwanted extra + Warn if macOS's setlocale() starts an unwanted extra thread inside the postmaster (Noah Misch) @@ -5743,7 +6072,7 @@ Branch: REL8_4_STABLE [ae41bb4be] 2014-05-30 18:18:32 -0400 - Fix linking of libpython on OS X (Tom Lane) + Fix linking of libpython on macOS (Tom Lane) @@ -10710,7 +11039,7 @@ ALTER EXTENSION hstore UPDATE; Add instructions for setting - up the documentation tool chain on Mac OS X + up the documentation tool chain on macOS (Peter Eisentraut) diff --git a/doc/src/sgml/release-9.4.sgml b/doc/src/sgml/release-9.4.sgml index 443c772846..94b028a065 100644 --- a/doc/src/sgml/release-9.4.sgml +++ b/doc/src/sgml/release-9.4.sgml @@ -1,6 +1,472 @@ + + Release 9.4.10 + + + Release Date + 2016-10-27 + + + + This release contains a variety of fixes from 9.4.9. + For information about new features in the 9.4 major release, see + . + + + + Migration to Version 9.4.10 + + + A dump/restore is not required for those running 9.4.X. + + + + However, if your installation has been affected by the bug described in + the first changelog entry below, then after updating you may need + to take action to repair corrupted free space maps. + + + + Also, if you are upgrading from a version earlier than 9.4.6, + see . + + + + + Changes + + + + + + Fix WAL-logging of truncation of relation free space maps and + visibility maps (Pavan Deolasee, Heikki Linnakangas) + + + + It was possible for these files to not be correctly restored during + crash recovery, or to be written incorrectly on a standby server. + Bogus entries in a free space map could lead to attempts to access + pages that have been truncated away from the relation itself, typically + producing errors like could not read block XXX: + read only 0 of 8192 bytes. Checksum failures in the + visibility map are also possible, if checksumming is enabled. + + + + Procedures for determining whether there is a problem and repairing it + if so are discussed at + . + + + + + + Fix incorrect creation of GIN index WAL records on big-endian machines + (Tom Lane) + + + + The typical symptom was unexpected GIN leaf action errors + during WAL replay. + + + + + + Fix SELECT FOR UPDATE/SHARE to correctly lock tuples that + have been updated by a subsequently-aborted transaction + (Álvaro Herrera) + + + + In 9.5 and later, the SELECT would sometimes fail to + return such tuples at all. A failure has not been proven to occur in + earlier releases, but might be possible with concurrent updates. + + + + + + Fix EvalPlanQual rechecks involving CTE scans (Tom Lane) + + + + The recheck would always see the CTE as returning no rows, typically + leading to failure to update rows that were recently updated. + + + + + + Fix improper repetition of previous results from hashed aggregation in + a subquery (Andrew Gierth) + + + + The test to see if we can reuse a previously-computed hash table of + the aggregate state values neglected the possibility of an outer query + reference appearing in an aggregate argument expression. A change in + the value of such a reference should lead to recalculating the hash + table, but did not. + + + + + + Fix query-lifespan memory leak in a bulk UPDATE on a table + with a PRIMARY KEY or REPLICA IDENTITY index + (Tom Lane) + + + + + + Fix EXPLAIN to emit valid XML when + is on (Markus Winand) + + + + Previously the XML output-format option produced syntactically invalid + tags such as <I/O-Read-Time>. That is now + rendered as <I-O-Read-Time>. + + + + + + Suppress printing of zeroes for unmeasured times + in EXPLAIN (Maksim Milyutin) + + + + Certain option combinations resulted in printing zero values for times + that actually aren't ever measured in that combination. Our general + policy in EXPLAIN is not to print such fields at all, so + do that consistently in all cases. + + + + + + Fix timeout length when VACUUM is waiting for exclusive + table lock so that it can truncate the table (Simon Riggs) + + + + The timeout was meant to be 50 milliseconds, but it was actually only + 50 microseconds, causing VACUUM to give up on truncation + much more easily than intended. Set it to the intended value. + + + + + + Fix bugs in merging inherited CHECK constraints while + creating or altering a table (Tom Lane, Amit Langote) + + + + Allow identical CHECK constraints to be added to a parent + and child table in either order. Prevent merging of a valid + constraint from the parent table with a NOT VALID + constraint on the child. Likewise, prevent merging of a NO + INHERIT child constraint with an inherited constraint. + + + + + + Remove artificial restrictions on the values accepted + by numeric_in() and numeric_recv() + (Tom Lane) + + + + We allow numeric values up to the limit of the storage format (more + than 1e100000), so it seems fairly pointless + that numeric_in() rejected scientific-notation exponents + above 1000. Likewise, it was silly for numeric_recv() to + reject more than 1000 digits in an input value. + + + + + + Avoid very-low-probability data corruption due to testing tuple + visibility without holding buffer lock (Thomas Munro, Peter Geoghegan, + Tom Lane) + + + + + + Fix logical WAL decoding to work properly when a subtransaction's WAL + output is large enough to spill to disk (Andres Freund) + + + + + + + Fix buffer overread in logical WAL decoding (Tom Lane) + + + + Logical decoding of a tuple update record read 23 bytes too many, + which was usually harmless but with very bad luck could result in a + crash. + + + + + + Fix file descriptor leakage when truncating a temporary relation of + more than 1GB (Andres Freund) + + + + + + Disallow starting a standalone backend with standby_mode + turned on (Michael Paquier) + + + + This can't do anything useful, since there will be no WAL receiver + process to fetch more WAL data; and it could result in misbehavior + in code that wasn't designed with this situation in mind. + + + + + + Properly initialize replication slot state when recycling a + previously-used slot (Michael Paquier) + + + + This failure to reset all of the fields of the slot could + prevent VACUUM from removing dead tuples. + + + + + + Round shared-memory allocation request to a multiple of the actual + huge page size when attempting to use huge pages on Linux (Tom Lane) + + + + This avoids possible failures during munmap() on systems + with atypical default huge page sizes. Except in crash-recovery + cases, there were no ill effects other than a log message. + + + + + + Use a more random value for the dynamic shared memory control + segment's ID (Robert Haas, Tom Lane) + + + + Previously, the same value would be chosen every time, because it was + derived from random() but srandom() had not + yet been called. While relatively harmless, this was not the intended + behavior. + + + + + + On Windows, retry creation of the dynamic shared memory control + segment after an access-denied error (Kyotaro Horiguchi, Amit Kapila) + + + + Windows sometimes returns ERROR_ACCESS_DENIED rather + than ERROR_ALREADY_EXISTS when there is an existing + segment. This led to postmaster startup failure due to believing that + the former was an unrecoverable error. + + + + + + Don't try to share SSL contexts across multiple connections + in libpq (Heikki Linnakangas) + + + + This led to assorted corner-case bugs, particularly when trying to use + different SSL parameters for different connections. + + + + + + Avoid corner-case memory leak in libpq (Tom Lane) + + + + The reported problem involved leaking an error report + during PQreset(), but there might be related cases. + + + + + + Make ecpg's + + + + + Fix pgbench's calculation of average latency + (Fabien Coelho) + + + + The calculation was incorrect when there were \sleep + commands in the script, or when the test duration was specified in + number of transactions rather than total time. + + + + + + In pg_dump, never dump range constructor functions + (Tom Lane) + + + + This oversight led to pg_upgrade failures with + extensions containing range types, due to duplicate creation of the + constructor functions. + + + + + + In pg_xlogdump, retry opening new WAL segments when + using + + + This allows for a possible delay in the server's creation of the next + segment. + + + + + + Fix pg_xlogdump to cope with a WAL file that begins + with a continuation record spanning more than one page (Pavan + Deolasee) + + + + + + Fix contrib/pg_buffercache to work + when shared_buffers exceeds 256GB (KaiGai Kohei) + + + + + + Fix contrib/intarray/bench/bench.pl to print the results + of the EXPLAIN it does when given the + + + + + Install TAP test infrastructure so that it's available for extension + testing (Craig Ringer) + + + + When PostgreSQL has been configured + with + + + + + In MSVC builds, include pg_recvlogical in a + client-only installation (MauMau) + + + + + + Update Windows time zone mapping to recognize some time zone names + added in recent Windows versions (Michael Paquier) + + + + + + Prevent failure of obsolete dynamic time zone abbreviations (Tom Lane) + + + + If a dynamic time zone abbreviation does not match any entry in the + referenced time zone, treat it as equivalent to the time zone name. + This avoids unexpected failures when IANA removes abbreviations from + their time zone database, as they did in tzdata + release 2016f and seem likely to do again in the future. The + consequences were not limited to not recognizing the individual + abbreviation; any mismatch caused + the pg_timezone_abbrevs view to fail altogether. + + + + + + Update time zone data files to tzdata release 2016h + for DST law changes in Palestine and Turkey, plus historical + corrections for Turkey and some regions of Russia. + Switch to numeric abbreviations for some time zones in Antarctica, + the former Soviet Union, and Sri Lanka. + + + + The IANA time zone database previously provided textual abbreviations + for all time zones, sometimes making up abbreviations that have little + or no currency among the local population. They are in process of + reversing that policy in favor of using numeric UTC offsets in zones + where there is no evidence of real-world use of an English + abbreviation. At least for the time being, PostgreSQL + will continue to accept such removed abbreviations for timestamp input. + But they will not be shown in the pg_timezone_names + view nor used for output. + + + + In this update, AMT is no longer shown as being in use to + mean Armenia Time. Therefore, we have changed the Default + abbreviation set to interpret it as Amazon Time, thus UTC-4 not UTC+4. + + + + + + + + Release 9.4.9 @@ -929,7 +1395,7 @@ Branch: REL9_1_STABLE [de887cc8a] 2016-05-25 19:39:49 -0400 This dodges a portability problem on FreeBSD-derived platforms - (including OS X). + (including macOS). @@ -5254,7 +5720,7 @@ Branch: REL9_3_STABLE [6347bdb31] 2015-04-05 13:01:55 -0400 - Silence some build warnings on OS X (Tom Lane) + Silence some build warnings on macOS (Tom Lane) @@ -5813,7 +6279,7 @@ Branch: REL9_0_STABLE [2e4946169] 2015-01-07 22:46:20 -0500 - Warn if OS X's setlocale() starts an unwanted extra + Warn if macOS's setlocale() starts an unwanted extra thread inside the postmaster (Noah Misch) diff --git a/doc/src/sgml/release-9.5.sgml b/doc/src/sgml/release-9.5.sgml index fa3537de10..abc0337026 100644 --- a/doc/src/sgml/release-9.5.sgml +++ b/doc/src/sgml/release-9.5.sgml @@ -1,6 +1,830 @@ + + Release 9.5.5 + + + Release Date + 2016-10-27 + + + + This release contains a variety of fixes from 9.5.4. + For information about new features in the 9.5 major release, see + . + + + + Migration to Version 9.5.5 + + + A dump/restore is not required for those running 9.5.X. + + + + However, if your installation has been affected by the bug described in + the first changelog entry below, then after updating you may need + to take action to repair corrupted free space maps. + + + + Also, if you are upgrading from a version earlier than 9.5.2, + see . + + + + + Changes + + + + + + Fix WAL-logging of truncation of relation free space maps and + visibility maps (Pavan Deolasee, Heikki Linnakangas) + + + + It was possible for these files to not be correctly restored during + crash recovery, or to be written incorrectly on a standby server. + Bogus entries in a free space map could lead to attempts to access + pages that have been truncated away from the relation itself, typically + producing errors like could not read block XXX: + read only 0 of 8192 bytes. Checksum failures in the + visibility map are also possible, if checksumming is enabled. + + + + Procedures for determining whether there is a problem and repairing it + if so are discussed at + . + + + + + + + Fix incorrect creation of GIN index WAL records on big-endian machines + (Tom Lane) + + + + The typical symptom was unexpected GIN leaf action errors + during WAL replay. + + + + + + + Fix SELECT FOR UPDATE/SHARE to correctly lock tuples that + have been updated by a subsequently-aborted transaction + (Álvaro Herrera) + + + + In 9.5 and later, the SELECT would sometimes fail to + return such tuples at all. A failure has not been proven to occur in + earlier releases, but might be possible with concurrent updates. + + + + + + + Fix EvalPlanQual rechecks involving CTE scans (Tom Lane) + + + + The recheck would always see the CTE as returning no rows, typically + leading to failure to update rows that were recently updated. + + + + + + + Fix deletion of speculatively inserted TOAST tuples when backing out + of INSERT ... ON CONFLICT (Oskari Saarenmaa) + + + + In the race condition where two transactions try to insert conflicting + tuples at about the same time, the loser would fail with + an attempted to delete invisible tuple error if its + insertion included any TOAST'ed fields. + + + + + + Don't throw serialization errors for self-conflicting insertions + in INSERT ... ON CONFLICT (Thomas Munro, Peter Geoghegan) + + + + + + + Fix improper repetition of previous results from hashed aggregation in + a subquery (Andrew Gierth) + + + + The test to see if we can reuse a previously-computed hash table of + the aggregate state values neglected the possibility of an outer query + reference appearing in an aggregate argument expression. A change in + the value of such a reference should lead to recalculating the hash + table, but did not. + + + + + + + Fix query-lifespan memory leak in a bulk UPDATE on a table + with a PRIMARY KEY or REPLICA IDENTITY index + (Tom Lane) + + + + + + Fix COPY with a column name list from a table that has + row-level security enabled (Adam Brightwell) + + + + + + Fix EXPLAIN to emit valid XML when + is on (Markus Winand) + + + + Previously the XML output-format option produced syntactically invalid + tags such as <I/O-Read-Time>. That is now + rendered as <I-O-Read-Time>. + + + + + + + Suppress printing of zeroes for unmeasured times + in EXPLAIN (Maksim Milyutin) + + + + Certain option combinations resulted in printing zero values for times + that actually aren't ever measured in that combination. Our general + policy in EXPLAIN is not to print such fields at all, so + do that consistently in all cases. + + + + + + Fix statistics update for TRUNCATE in a prepared + transaction (Stas Kelvich) + + + + + + + Fix timeout length when VACUUM is waiting for exclusive + table lock so that it can truncate the table (Simon Riggs) + + + + The timeout was meant to be 50 milliseconds, but it was actually only + 50 microseconds, causing VACUUM to give up on truncation + much more easily than intended. Set it to the intended value. + + + + + + Fix bugs in merging inherited CHECK constraints while + creating or altering a table (Tom Lane, Amit Langote) + + + + Allow identical CHECK constraints to be added to a parent + and child table in either order. Prevent merging of a valid + constraint from the parent table with a NOT VALID + constraint on the child. Likewise, prevent merging of a NO + INHERIT child constraint with an inherited constraint. + + + + + + Show a sensible value + in pg_settings.unit + for min_wal_size and max_wal_size (Tom Lane) + + + + + + + Remove artificial restrictions on the values accepted + by numeric_in() and numeric_recv() + (Tom Lane) + + + + We allow numeric values up to the limit of the storage format (more + than 1e100000), so it seems fairly pointless + that numeric_in() rejected scientific-notation exponents + above 1000. Likewise, it was silly for numeric_recv() to + reject more than 1000 digits in an input value. + + + + + + Avoid very-low-probability data corruption due to testing tuple + visibility without holding buffer lock (Thomas Munro, Peter Geoghegan, + Tom Lane) + + + + + + Preserve commit timestamps across server restart + (Julien Rouhaud, Craig Ringer) + + + + With turned on, old + commit timestamps became inaccessible after a clean server restart. + + + + + + Fix logical WAL decoding to work properly when a subtransaction's WAL + output is large enough to spill to disk (Andres Freund) + + + + + + + Fix possible sorting error when aborting use of abbreviated keys + (Peter Geoghegan) + + + + In the worst case, this could result in a corrupt btree index, which + would need to be rebuilt using REINDEX. However, the + situation is believed to be rare. + + + + + + + Fix file descriptor leakage when truncating a temporary relation of + more than 1GB (Andres Freund) + + + + + + + Disallow starting a standalone backend with standby_mode + turned on (Michael Paquier) + + + + This can't do anything useful, since there will be no WAL receiver + process to fetch more WAL data; and it could result in misbehavior + in code that wasn't designed with this situation in mind. + + + + + + + Properly initialize replication slot state when recycling a + previously-used slot (Michael Paquier) + + + + This failure to reset all of the fields of the slot could + prevent VACUUM from removing dead tuples. + + + + + + Round shared-memory allocation request to a multiple of the actual + huge page size when attempting to use huge pages on Linux (Tom Lane) + + + + This avoids possible failures during munmap() on systems + with atypical default huge page sizes. Except in crash-recovery + cases, there were no ill effects other than a log message. + + + + + + + Use a more random value for the dynamic shared memory control + segment's ID (Robert Haas, Tom Lane) + + + + Previously, the same value would be chosen every time, because it was + derived from random() but srandom() had not + yet been called. While relatively harmless, this was not the intended + behavior. + + + + + + + On Windows, retry creation of the dynamic shared memory control + segment after an access-denied error (Kyotaro Horiguchi, Amit Kapila) + + + + Windows sometimes returns ERROR_ACCESS_DENIED rather + than ERROR_ALREADY_EXISTS when there is an existing + segment. This led to postmaster startup failure due to believing that + the former was an unrecoverable error. + + + + + + + Fix PL/pgSQL to not misbehave with parameters and + local variables of type int2vector or oidvector + (Tom Lane) + + + + + + Don't try to share SSL contexts across multiple connections + in libpq (Heikki Linnakangas) + + + + This led to assorted corner-case bugs, particularly when trying to use + different SSL parameters for different connections. + + + + + + Avoid corner-case memory leak in libpq (Tom Lane) + + + + The reported problem involved leaking an error report + during PQreset(), but there might be related cases. + + + + + + + Make ecpg's + + + + + + Fix pgbench's calculation of average latency + (Fabien Coelho) + + + + The calculation was incorrect when there were \sleep + commands in the script, or when the test duration was specified in + number of transactions rather than total time. + + + + + + In pg_upgrade, check library loadability in name order + (Tom Lane) + + + + This is a workaround to deal with cross-extension dependencies from + language transform modules to their base language and data type + modules. + + + + + + + In pg_dump, never dump range constructor functions + (Tom Lane) + + + + This oversight led to pg_upgrade failures with + extensions containing range types, due to duplicate creation of the + constructor functions. + + + + + + + In pg_dump with + + + + + + Make pg_receivexlog work correctly + with + + + + + Disallow specifying both + + + + + Make pg_rewind turn off synchronous_commit + in its session on the source server (Michael Banck, Michael Paquier) + + + + This allows pg_rewind to work even when the source + server is using synchronous replication that is not working for some + reason. + + + + + + In pg_xlogdump, retry opening new WAL segments when + using + + + This allows for a possible delay in the server's creation of the next + segment. + + + + + + + Fix pg_xlogdump to cope with a WAL file that begins + with a continuation record spanning more than one page (Pavan + Deolasee) + + + + + + + Fix contrib/pg_buffercache to work + when shared_buffers exceeds 256GB (KaiGai Kohei) + + + + + + + Fix contrib/intarray/bench/bench.pl to print the results + of the EXPLAIN it does when given the + + + + + + Support OpenSSL 1.1.0 (Heikki Linnakangas) + + + + + + + Install TAP test infrastructure so that it's available for extension + testing (Craig Ringer) + + + + When PostgreSQL has been configured + with + + + + + + In MSVC builds, include pg_recvlogical in a + client-only installation (MauMau) + + + + + + + Update Windows time zone mapping to recognize some time zone names + added in recent Windows versions (Michael Paquier) + + + + + + + Prevent failure of obsolete dynamic time zone abbreviations (Tom Lane) + + + + If a dynamic time zone abbreviation does not match any entry in the + referenced time zone, treat it as equivalent to the time zone name. + This avoids unexpected failures when IANA removes abbreviations from + their time zone database, as they did in tzdata + release 2016f and seem likely to do again in the future. The + consequences were not limited to not recognizing the individual + abbreviation; any mismatch caused + the pg_timezone_abbrevs view to fail altogether. + + + + + + Update time zone data files to tzdata release 2016h + for DST law changes in Palestine and Turkey, plus historical + corrections for Turkey and some regions of Russia. + Switch to numeric abbreviations for some time zones in Antarctica, + the former Soviet Union, and Sri Lanka. + + + + The IANA time zone database previously provided textual abbreviations + for all time zones, sometimes making up abbreviations that have little + or no currency among the local population. They are in process of + reversing that policy in favor of using numeric UTC offsets in zones + where there is no evidence of real-world use of an English + abbreviation. At least for the time being, PostgreSQL + will continue to accept such removed abbreviations for timestamp input. + But they will not be shown in the pg_timezone_names + view nor used for output. + + + + In this update, AMT is no longer shown as being in use to + mean Armenia Time. Therefore, we have changed the Default + abbreviation set to interpret it as Amazon Time, thus UTC-4 not UTC+4. + + + + + + + + Release 9.5.4 @@ -2023,7 +2847,7 @@ Branch: REL9_1_STABLE [e56acbe2a] 2016-02-10 19:30:12 -0500 This dodges a portability problem on FreeBSD-derived platforms - (including OS X). + (including macOS). diff --git a/doc/src/sgml/release-9.6.sgml b/doc/src/sgml/release-9.6.sgml index cc886fa2bb..1ee136ab96 100644 --- a/doc/src/sgml/release-9.6.sgml +++ b/doc/src/sgml/release-9.6.sgml @@ -1,13 +1,607 @@ + + Release 9.6.1 + + + Release Date + 2016-10-27 + + + + This release contains a variety of fixes from 9.6.0. + For information about new features in the 9.6 major release, see + . + + + + Migration to Version 9.6.1 + + + A dump/restore is not required for those running 9.6.X. + + + + However, if your installation has been affected by the bugs described in + the first two changelog entries below, then after updating you may need + to take action to repair corrupted free space maps and/or visibility + maps. + + + + + Changes + + + + + + + Fix WAL-logging of truncation of relation free space maps and + visibility maps (Pavan Deolasee, Heikki Linnakangas) + + + + It was possible for these files to not be correctly restored during + crash recovery, or to be written incorrectly on a standby server. + Bogus entries in a free space map could lead to attempts to access + pages that have been truncated away from the relation itself, typically + producing errors like could not read block XXX: + read only 0 of 8192 bytes. Checksum failures in the + visibility map are also possible, if checksumming is enabled. + + + + Procedures for determining whether there is a problem and repairing it + if so are discussed at + . + + + + + + + Fix possible data corruption when pg_upgrade rewrites + a relation visibility map into 9.6 format (Tom Lane) + + + + On big-endian machines, bytes of the new visibility map were written + in the wrong order, leading to a completely incorrect map. On + Windows, the old map was read using text mode, leading to incorrect + results if the map happened to contain consecutive bytes that matched + a carriage return/line feed sequence. The latter error would almost + always lead to a pg_upgrade failure due to the map + file appearing to be the wrong length. + + + + If you are using a big-endian machine (many non-Intel architectures + are big-endian) and have used pg_upgrade to upgrade + from a pre-9.6 release, you should assume that all visibility maps are + incorrect and need to be regenerated. It is sufficient to truncate + each relation's visibility map + with contrib/pg_visibility's + pg_truncate_visibility_map() function. + For more information see + . + + + + + + + Don't throw serialization errors for self-conflicting insertions + in INSERT ... ON CONFLICT (Thomas Munro, Peter Geoghegan) + + + + + + + Fix use-after-free hazard in execution of aggregate functions + using DISTINCT (Peter Geoghegan) + + + + This could lead to a crash or incorrect query results. + + + + + + + Fix incorrect handling of polymorphic aggregates used as window + functions (Tom Lane) + + + + The aggregate's transition function was told that its first argument + and result were of the aggregate's output type, rather than the + state type. This led to errors or crashes with + polymorphic transition functions. + + + + + + + Fix COPY with a column name list from a table that has + row-level security enabled (Adam Brightwell) + + + + + + + Fix EXPLAIN to emit valid XML when + is on (Markus Winand) + + + + Previously the XML output-format option produced syntactically invalid + tags such as <I/O-Read-Time>. That is now + rendered as <I-O-Read-Time>. + + + + + + + Fix statistics update for TRUNCATE in a prepared + transaction (Stas Kelvich) + + + + + + + Fix bugs in merging inherited CHECK constraints while + creating or altering a table (Tom Lane, Amit Langote) + + + + Allow identical CHECK constraints to be added to a parent + and child table in either order. Prevent merging of a valid + constraint from the parent table with a NOT VALID + constraint on the child. Likewise, prevent merging of a NO + INHERIT child constraint with an inherited constraint. + + + + + + + Show a sensible value + in pg_settings.unit + for min_wal_size and max_wal_size (Tom Lane) + + + + + + + Fix replacement of array elements in jsonb_set() + (Tom Lane) + + + + If the target is an existing JSON array element, it got deleted + instead of being replaced with a new value. + + + + + + + Avoid very-low-probability data corruption due to testing tuple + visibility without holding buffer lock (Thomas Munro, Peter Geoghegan, + Tom Lane) + + + + + + + Preserve commit timestamps across server restart + (Julien Rouhaud, Craig Ringer) + + + + With turned on, old + commit timestamps became inaccessible after a clean server restart. + + + + + + + Fix logical WAL decoding to work properly when a subtransaction's WAL + output is large enough to spill to disk (Andres Freund) + + + + + + + Fix dangling-pointer problem in logical WAL decoding (Stas Kelvich) + + + + + + + Round shared-memory allocation request to a multiple of the actual + huge page size when attempting to use huge pages on Linux (Tom Lane) + + + + This avoids possible failures during munmap() on systems + with atypical default huge page sizes. Except in crash-recovery + cases, there were no ill effects other than a log message. + + + + + + + Don't try to share SSL contexts across multiple connections + in libpq (Heikki Linnakangas) + + + + This led to assorted corner-case bugs, particularly when trying to use + different SSL parameters for different connections. + + + + + + + Avoid corner-case memory leak in libpq (Tom Lane) + + + + The reported problem involved leaking an error report + during PQreset(), but there might be related cases. + + + + + + + In pg_upgrade, check library loadability in name order + (Tom Lane) + + + + This is a workaround to deal with cross-extension dependencies from + language transform modules to their base language and data type + modules. + + + + + + + Fix pg_upgrade to work correctly for extensions + containing index access methods (Tom Lane) + + + + To allow this, the server has been extended to support ALTER + EXTENSION ADD/DROP ACCESS METHOD. That functionality should have + been included in the original patch to support dynamic creation of + access methods, but it was overlooked. + + + + + + + Improve error reporting in pg_upgrade's file + copying/linking/rewriting steps (Tom Lane, Álvaro Herrera) + + + + + + + Fix pg_dump to work against pre-7.4 servers + (Amit Langote, Tom Lane) + + + + + + + Disallow specifying both + + + + + + Make pg_rewind turn off synchronous_commit + in its session on the source server (Michael Banck, Michael Paquier) + + + + This allows pg_rewind to work even when the source + server is using synchronous replication that is not working for some + reason. + + + + + + + In pg_xlogdump, retry opening new WAL segments when + using + + + This allows for a possible delay in the server's creation of the next + segment. + + + + + + + Fix contrib/pg_visibility to report the correct TID for + a corrupt tuple that has been the subject of a rolled-back update + (Tom Lane) + + + + + + + Fix makefile dependencies so that parallel make + of PL/Python by itself will succeed reliably + (Pavel Raiskup) + + + + + + + Update time zone data files to tzdata release 2016h + for DST law changes in Palestine and Turkey, plus historical + corrections for Turkey and some regions of Russia. + Switch to numeric abbreviations for some time zones in Antarctica, + the former Soviet Union, and Sri Lanka. + + + + The IANA time zone database previously provided textual abbreviations + for all time zones, sometimes making up abbreviations that have little + or no currency among the local population. They are in process of + reversing that policy in favor of using numeric UTC offsets in zones + where there is no evidence of real-world use of an English + abbreviation. At least for the time being, PostgreSQL + will continue to accept such removed abbreviations for timestamp input. + But they will not be shown in the pg_timezone_names + view nor used for output. + + + + In this update, AMT is no longer shown as being in use to + mean Armenia Time. Therefore, we have changed the Default + abbreviation set to interpret it as Amazon Time, thus UTC-4 not UTC+4. + + + + + + + + Release 9.6 Release Date - 2016-??-?? - Current as of 2016-08-08 (commit 34927b292) + 2016-09-29 @@ -23,40 +617,40 @@ - Parallel sequential scans, joins and aggregates + Parallel execution of sequential scans, joins and aggregates - Eliminate repetitive scanning of old data by autovacuum + Avoid scanning pages unnecessarily during vacuum freeze operations - Synchronous replication now allows multiple standby servers, for + Synchronous replication now allows multiple standby servers for increased reliability - Allow full-text search for phrases (multiple adjacent words) + Full-text search can now search for phrases (multiple adjacent words) - Support foreign/remote joins, sorts, and UPDATEs in - postgres_fdw + postgres_fdw now supports remote joins, sorts, + UPDATEs, and DELETEs Substantial performance improvements, especially in the area of - scalability on multi-CPU-socket servers + scalability on multi-CPU-socket servers @@ -87,25 +681,6 @@ - - Change the column name in the - information_schema.routines - view from result_cast_character_set_name - to result_cast_char_set_name (Clément - Prévost) - - - - The SQL:2011 standard specifies the longer name, but that appears - to be a mistake, because adjacent column names use the shorter - style, as do other information_schema views. - - - - - @@ -117,7 +692,7 @@ Historically a process has only been shown as waiting if it was - waiting for a heavy weight lock. Now waits for light weight locks + waiting for a heavyweight lock. Now waits for lightweight locks and buffer pins are also shown in pg_stat_activity. Also, the type of lock being waited for is now visible. These changes replace the waiting column with @@ -149,18 +724,18 @@ Make extract() behave - more reasonably with infinite inputs (Vitaly Burovoy) + more reasonably with infinite inputs (Vitaly Burovoy) Historically the extract() function just returned zero given an infinite timestamp, regardless of the given - unit name. Make it return infinity + field name. Make it return infinity or -infinity as appropriate when the requested field is one that is monotonically increasing (e.g, year, epoch), or NULL when it is not (e.g., day, hour). Also, - throw the expected error for bad unit names. + throw the expected error for bad field names. @@ -186,8 +761,8 @@ This commit is also listed under libpq and psql 2016-03-29 [61d66c44f] Fix support of digits in email/hostnames. --> - Fix text search parser to allow leading digits in email - and host tokens (Artur Zakirov) + Fix the default text search parser to allow leading digits + in email and host tokens (Artur Zakirov) @@ -205,18 +780,18 @@ This commit is also listed under libpq and psql 2016-03-16 [9a206d063] Improve script generating unaccent rules --> - Extend contrib/unaccent's standard - unaccent.rules file to handle all diacritics - known to Unicode, and expand ligatures correctly (Thomas Munro, + Extend contrib/unaccent's + standard unaccent.rules file to handle all diacritics + known to Unicode, and to expand ligatures correctly (Thomas Munro, Léonard Benedetti) - The previous version omitted some less-common letters with - diacritic marks. It now also expands ligatures into separate - letters. Installations that use this rules file may wish to - rebuild tsvector columns and indexes that depend on - the result. + The previous version neglected to convert some less-common letters + with diacritic marks. Also, ligatures are now expanded into + separate letters. Installations that use this rules file may wish + to rebuild tsvector columns and indexes that depend on the + result. @@ -258,17 +833,38 @@ This commit is also listed under libpq and psql + + Change a column name in the + information_schema.routines + view from result_cast_character_set_name + to result_cast_char_set_name (Clément + Prévost) + + + + The SQL:2011 standard specifies the longer name, but that appears + to be a mistake, because adjacent column names use the shorter + style, as do other information_schema views. + + + + + - Support multiple and - command-line options (Pavel Stehule, Catalin Iacob) + psql's option no longer implies + + (Pavel Stehule, Catalin Iacob) - To allow this with sane behavior, one backwards incompatibility - had to be introduced: no longer implies - . + Write (or its + abbreviation ) explicitly to obtain the old + behavior. Scripts so modified will still work with old + versions of psql. @@ -277,7 +873,7 @@ This commit is also listed under libpq and psql 2015-07-02 [5671aaca8] Improve pg_restore's -t switch to match all types of rel --> - Improve pg_restore's switch to + Improve pg_restore's option to match all types of relations, not only plain tables (Craig Ringer) @@ -287,7 +883,7 @@ This commit is also listed under libpq and psql 2016-02-12 [59a884e98] Change delimiter used for display of NextXID --> - Change the display format of NextXID in + Change the display format used for NextXID in pg_controldata and related places (Joe Conway, Bruce Momjian) @@ -301,6 +897,26 @@ This commit is also listed under libpq and psql + + + + Update extension functions to be marked parallel-safe where + appropriate (Andreas Karlsson) + + + + Many of the standard extensions have been updated to allow their + functions to be executed within parallel query worker processes. + These changes will not take effect in + databases pg_upgrade'd from prior versions unless + you apply ALTER EXTENSION UPDATE to each such extension + (in each database of a cluster). + + + @@ -348,6 +964,8 @@ This commit is also listed under libpq and psql 2016-04-27 [59eb55127] Fix EXPLAIN VERBOSE output for parallel aggregate. 2016-06-09 [c9ce4a1c6] Eliminate "parallel degree" terminology. 2016-06-16 [75be66464] Invent min_parallel_relation_size GUC to replace a hard- +2016-08-16 [f85b1a841] Disable parallel query by default. +2016-09-15 [72ce78162] Make min_parallel_relation_size's default value platform --> Parallel queries (Robert Haas, Amit Kapila, David Rowley, @@ -365,9 +983,11 @@ This commit is also listed under libpq and psql - Use of parallel query execution can be controlled - through the new configuration parameters , + Parallel query execution is not (yet) enabled by default. + To allow it, set the new configuration + parameter to a + value larger than zero. Additional control over use of parallelism + is available through other new configuration parameters , , , and - Provide infrastructure for marking the parallel-safe status of - functions (Robert Haas, Amit Kapila) + Provide infrastructure for marking the parallel-safety status of + functions (Robert Haas, Amit Kapila) @@ -401,7 +1021,7 @@ This commit is also listed under libpq and psql Allow GIN index builds to make effective use of - settings larger than 1GB (Robert Abraham, Teodor Sigaev) + settings larger than 1 GB (Robert Abraham, Teodor Sigaev) @@ -429,8 +1049,12 @@ This commit is also listed under libpq and psql Add gin_clean_pending_list() function to allow manual invocation of pending-list cleanup for a - GIN index, separately from vacuuming or analyzing the parent table - (Jeff Janes) + GIN index (Jeff Janes) + + + + Formerly, such cleanup happened only as a byproduct of vacuuming or + analyzing the parent table. @@ -467,222 +1091,186 @@ This commit is also listed under libpq and psql - General Performance + Sorting - Avoid re-vacuuming pages containing only frozen tuples (Masahiko - Sawada, Robert Haas, Andres Freund) - - - - Formerly, anti-wraparound vacuum had to visit every page of - a table, even pages where there was nothing to do. Now, pages - containing only already-frozen tuples are identified in the table's - visibility map, and can be skipped by vacuum even when doing - transaction wraparound prevention. This should greatly reduce the - cost of maintaining large tables containing mostly-unchanged data. + Improve sorting performance by using quicksort, not replacement + selection sort, when performing external sort steps (Peter + Geoghegan) - If necessary, vacuum can be forced to process all-frozen - pages using the new DISABLE_PAGE_SKIPPING option. - Normally, this should never be needed but it might help in - recovering from visibility-map corruption. + The new approach makes better use of the CPU cache + for typical cache sizes and data volumes. Where necessary, + the behavior can be adjusted via the new configuration parameter + . - Avoid useless heap-truncation attempts during VACUUM - (Jeff Janes, Tom Lane) - - - - This change avoids taking an exclusive table lock in some cases - where no truncation is possible. The main benefit comes from - avoiding unnecessary query cancellations on standby servers. + Speed up text sorts where the same string occurs multiple times + (Peter Geoghegan) - Reduce interlocking on standby servers during the replay of btree - index vacuuming operations (Simon Riggs) + Speed up sorting of uuid, bytea, and + char(n) fields by using abbreviated keys + (Peter Geoghegan) - This change avoids substantial replication delays that sometimes - occurre while replaying such operations. + Support for abbreviated keys has also been + added to the non-default operator classes text_pattern_ops, + varchar_pattern_ops, and + bpchar_pattern_ops. Processing of ordered-set + aggregates can also now exploit abbreviated keys. - Avoid computing GROUP BY columns if they are - functionally dependent on other columns (David Rowley) - - - - If a GROUP BY clause includes all columns of a - non-deferred primary key, as well as other columns of the same - table, those other columns are redundant and can be dropped - from the grouping. This saves computation in many common cases. + Speed up CREATE INDEX CONCURRENTLY by treating + TIDs as 64-bit integers during sorting (Peter + Geoghegan) + + + + + + Locking + + + - When appropriate, postpone evaluation of SELECT - output expressions until after an ORDER BY sort - (Konstantin Knizhnik) - - - - This change ensures that volatile or expensive functions in the - output list are executed in the order suggested by ORDER - BY, and that they are not evaluated more times than required - when there is a LIMIT clause. Previously, these - properties held if the ordering was performed by an index scan or - pre-merge-join sort, but not if it was performed by a top-level - sort. + Reduce contention for the ProcArrayLock (Amit Kapila, + Robert Haas) - Where feasible, trigger kernel writeback after a configurable - number of writes, to prevent accumulation of dirty data in kernel - disk buffers (Fabien Coelho, Andres Freund) + Improve performance by moving buffer content locks into the buffer + descriptors (Andres Freund, Simon Riggs) + + + - PostgreSQL writes data to the kernel's disk cache, - from where it will be flushed to physical storage in due time. - Many operating systems are not smart about managing this and allow - large amounts of dirty data to accumulate before deciding to flush - it all at once, leading to long delays for new I/O requests. - This change attempts to alleviate this problem by explicitly - requesting data flushes after a configurable interval. + Replace shared-buffer header spinlocks with atomic operations to + improve scalability (Alexander Korotkov, Andres Freund) + + + - On Linux, sync_file_range() is used for this purpose, - and the feature is on by default on Linux because that function has few - downsides. This sync capability is also available on other platforms - that have msync() or posix_fadvise(), - but those interfaces have some undesirable side-effects so the - feature is disabled by default on non-Linux platforms. + Use atomic operations, rather than a spinlock, to protect an + LWLock's wait queue (Andres Freund) + + + - The new configuration parameters , , , and control this behavior. + Partition the shared hash table freelist to reduce contention on + multi-CPU-socket servers (Aleksander Alekseev) - Perform checkpoint writes in sorted order (Fabien Coelho, - Andres Freund) + Reduce interlocking on standby servers during the replay of btree + index vacuuming operations (Simon Riggs) - Previously, checkpoints wrote out dirty pages in whatever order - they happen to appear in shared buffers, which usually is nearly - random. That performs poorly, especially on rotating media. - This change causes checkpoint-driven writes to be done in order - by file and block number, and to be balanced across tablespaces. + This change avoids substantial replication delays that sometimes + occurred while replaying such operations. + + + + + + Optimizer Statistics + + + - Allow old MVCC snapshots to be invalidated after a - configurable timeout (Kevin Grittner) + Improve ANALYZE's estimates for columns with many nulls + (Tomas Vondra, Alex Shulgin) - Normally, deleted tuples cannot be physically removed by - vacuuming until the last transaction that could see - them is gone. A transaction that stays open for a long - time can thus cause considerable table bloat because - space cannot be recycled. This feature allows setting - a time-based limit, via the new configuration parameter - , on how long an - MVCC snapshot is guaranteed to be valid. After that, - dead tuples are candidates for removal. A transaction using an - outdated snapshot will get an error if it attempts to read a page - that potentially could have contained such data. + Previously ANALYZE tended to underestimate the number + of non-NULL distinct values in a column with many + NULLs, and was also inaccurate in computing the + most-common values. - Allow use of an index-only - scan on a partial index when the index's WHERE - clause references columns which are not indexed (Tomas Vondra, - Kyotaro Horiguchi) - - - - For example, CREATE INDEX tidx_partial ON t(b) WHERE a - > 0 could not previously be used for an index-only scan by a - query that only referenced a in its WHERE - clause because a is not an indexed value like - b is. + Improve planner's estimate of the number of distinct values in + a query result (Tomas Vondra) - @@ -701,7 +1289,7 @@ This commit is also listed under libpq and psql (a,b) REFERENCES r (x,y), then a WHERE condition such as t.a = r.x AND t.b = r.y cannot select more than one r row per t row. - The planner formerly considered AND conditions + The planner formerly considered these AND conditions to be independent and would often drastically misestimate selectivity as a result. Now it compares the WHERE conditions to applicable foreign key constraints and produces @@ -709,267 +1297,321 @@ This commit is also listed under libpq and psql + + + + + + <command>VACUUM</> + + + - Improve aggregate-function performance by sharing calculations - across multiple aggregates if they have the same arguments and - transition functions (David Rowley) + Avoid re-vacuuming pages containing only frozen tuples (Masahiko + Sawada, Robert Haas, Andres Freund) - For example, SELECT AVG(x), SUM(x) FROM x can use a - single per-row compuation for both aggregates. + Formerly, anti-wraparound vacuum had to visit every page of + a table, even pages where there was nothing to do. Now, pages + containing only already-frozen tuples are identified in the table's + visibility map, and can be skipped by vacuum even when doing + transaction wraparound prevention. This should greatly reduce the + cost of maintaining large tables containing mostly-unchanging data. - - - - Speed up visibility tests for recently-created tuples by checking - our transaction snapshot, not pg_clog, to decide - if the source transaction should be considered committed (Jeff - Janes, Tom Lane) + If necessary, vacuum can be forced to process all-frozen + pages using the new DISABLE_PAGE_SKIPPING option. + Normally this should never be needed, but it might help in + recovering from visibility-map corruption. - Allow tuple hint bits to be set sooner than before (Andres Freund) + Avoid useless heap-truncation attempts during VACUUM + (Jeff Janes, Tom Lane) + + + + This change avoids taking an exclusive table lock in some cases + where no truncation is possible. The main benefit comes from + avoiding unnecessary query cancellations on standby servers. + + + + + + General Performance + + + - Improve performance of short-lived prepared transactions (Stas - Kelvich, Simon Riggs, Pavan Deolasee) + Allow old MVCC snapshots to be invalidated after a + configurable timeout (Kevin Grittner) - Two-phase commit information is now written only to WAL - during PREPARE TRANSACTION, and read from - WAL during COMMIT PREPARED. A separate - state file is created only if the pending transaction does not - get committed or aborted by the time of the next checkpoint. + Normally, deleted tuples cannot be physically removed by + vacuuming until the last transaction that could see + them is gone. A transaction that stays open for a long + time can thus cause considerable table bloat because + space cannot be recycled. This feature allows setting + a time-based limit, via the new configuration parameter + , on how long an + MVCC snapshot is guaranteed to be valid. After that, + dead tuples are candidates for removal. A transaction using an + outdated snapshot will get an error if it attempts to read a page + that potentially could have contained such data. - Improve performance of memory context destruction (Jan Wieck) + Ignore GROUP BY columns that are + functionally dependent on other columns (David Rowley) - - - - Improve performance of resource owners with many tracked objects - (Aleksander Alekseev) + If a GROUP BY clause includes all columns of a + non-deferred primary key, as well as other columns of the same + table, those other columns are redundant and can be dropped + from the grouping. This saves computation in many common cases. - Improve speed of the output functions for timestamp, - time, and date data types (David Rowley, - Andres Freund) + Allow use of an index-only + scan on a partial index when the index's WHERE + clause references columns that are not indexed (Tomas Vondra, + Kyotaro Horiguchi) - - - - Avoid some unnecessary cancellations of hot-standby queries - during replay of actions that take AccessExclusive - locks (Jeff Janes) + For example, an index defined by CREATE INDEX tidx_partial + ON t(b) WHERE a > 0 can now be used for an index-only scan by + a query that specifies WHERE a > 0 and does not + otherwise use a. Previously this was disallowed + because a is not listed as an index column. + - Improve ANALYZE's estimates for columns with many nulls - (Tomas Vondra, Alex Shulgin) + Perform checkpoint writes in sorted order (Fabien Coelho, + Andres Freund) - Previously ANALYZE tended to underestimate the number - of non-NULL distinct values in a column with many - NULLs, and was also inaccurate in computing the - most-common values. + Previously, checkpoints wrote out dirty pages in whatever order + they happen to appear in shared buffers, which usually is nearly + random. That performs poorly, especially on rotating media. + This change causes checkpoint-driven writes to be done in order + by file and block number, and to be balanced across tablespaces. - Improve planner's estimate of the number of distinct values in - a query result (Tomas Vondra) + Where feasible, trigger kernel writeback after a configurable + number of writes, to prevent accumulation of dirty data in kernel + disk buffers (Fabien Coelho, Andres Freund) - - - - Extend relations multiple blocks at a time when there is contention - for the relation's extension lock (Dilip Kumar) + PostgreSQL writes data to the kernel's disk cache, + from where it will be flushed to physical storage in due time. + Many operating systems are not smart about managing this and allow + large amounts of dirty data to accumulate before deciding to flush + it all at once, causing long delays for new I/O requests until the + flushing finishes. + This change attempts to alleviate this problem by explicitly + requesting data flushes after a configurable interval. - This improves scalability by decreasing contention. + On Linux, sync_file_range() is used for this purpose, + and the feature is on by default on Linux because that function has + few downsides. This flushing capability is also available on other + platforms if they have msync() + or posix_fadvise(), but those interfaces have some + undesirable side-effects so the feature is disabled by default on + non-Linux platforms. + + + + The new configuration parameters , , , and control this behavior. - Improve sorting performance by using quicksort, not replacement - selection sort, when performing external sort steps (Peter - Geoghegan) + Improve aggregate-function performance by sharing calculations + across multiple aggregates if they have the same arguments and + transition functions (David Rowley) - The new approach makes better use of the CPU cache - for typical cache sizes and data volumes. Where necessary, - the behavior can be adjusted via the new configuration parameter - . + For example, SELECT AVG(x), VARIANCE(x) FROM tab can use + a single per-row computation for both aggregates. - Speed up text sorts where the same string occurs multiple times - (Peter Geoghegan) + Speed up visibility tests for recently-created tuples by checking + the current transaction's snapshot, not pg_clog, to + decide if the source transaction should be considered committed + (Jeff Janes, Tom Lane) - Speed up sorting of uuid, bytea, and - char(n) fields by using abbreviated keys - (Peter Geoghegan) - - - - Support for abbreviated keys has also been - added to the non-default operator classes text_pattern_ops, - varchar_pattern_ops, and - bpchar_pattern_ops. Processing of ordered-set - aggregates can also now exploit abbreviated keys. + Allow tuple hint bits to be set sooner than before (Andres Freund) - Speed up CREATE INDEX CONCURRENTLY by treating - TIDs as 64-bit integers during sorting (Peter - Geoghegan) + Improve performance of short-lived prepared transactions (Stas + Kelvich, Simon Riggs, Pavan Deolasee) + + + + Two-phase commit information is now written only to WAL + during PREPARE TRANSACTION, and will be read back from + WAL during COMMIT PREPARED if that happens + soon thereafter. A separate state file is created only if the + pending transaction does not get committed or aborted by the time + of the next checkpoint. - Increase the number of clog buffers for better scalability (Amit - Kapila, Andres Freund) + Improve performance of memory context destruction (Jan Wieck) - Reduce contention for the ProcArrayLock (Amit Kapila, - Robert Haas) + Improve performance of resource owners with many tracked objects + (Aleksander Alekseev) - Improve performance by moving buffer content locks into the buffer - descriptors (Andres Freund, Simon Riggs) + Improve speed of the output functions for timestamp, + time, and date data types (David Rowley, + Andres Freund) - Replace shared-buffer header spinlocks with atomic operations to - improve scalability (Alexander Korotkov, Andres Freund) + Avoid some unnecessary cancellations of hot-standby queries + during replay of actions that take AccessExclusive + locks (Jeff Janes) - Use atomic operations, rather than a spinlock, to protect an - LWLock's wait queue (Andres Freund) + Extend relations multiple blocks at a time when there is contention + for the relation's extension lock (Dilip Kumar) + + + + This improves scalability by decreasing contention. - Partition the shared hash table freelist to reduce contention on - multi-CPU-socket servers (Aleksander Alekseev) + Increase the number of clog buffers for better scalability (Amit + Kapila, Andres Freund) @@ -994,6 +1636,22 @@ This commit is also listed under libpq and psql + + + + Disable by default on + Windows (Takayuki Tsunakawa) + + + + The overhead of updating the process title is much larger on Windows + than most other platforms, and it is also less useful to do it since + most Windows users do not have tools that can display process titles. + + + @@ -1017,6 +1675,21 @@ This commit is also listed under libpq and psql + + Add pg_control_system(), + pg_control_checkpoint(), + pg_control_recovery(), and + pg_control_init() functions to expose fields of + pg_control to SQL (Joe Conway, Michael + Paquier) + + + + + @@ -1026,7 +1699,7 @@ This commit is also listed under libpq and psql This view exposes the same information available from - the the pg_config comand-line utility, + the pg_config comand-line utility, namely assorted compile-time configuration information for PostgreSQL. @@ -1072,9 +1745,9 @@ This commit is also listed under libpq and psql This function returns an array of the process IDs of any sessions that are blocking the session with the given process ID. Historically users have obtained such information using a self-join - on the pg_locks view. However, it is unreasonably + on the pg_locks view. However, it is unreasonably tedious to do it that way with any modicum of correctness, and - the addition of parallel queries has made the approach entirely + the addition of parallel queries has made the old approach entirely impractical, since locks might be held or awaited by child worker processes rather than the session's main process. @@ -1082,21 +1755,6 @@ This commit is also listed under libpq and psql - - Add pg_control_system(), - pg_control_checkpoint(), - pg_control_recovery(), and - pg_control_init() functions to expose fields of - pg_control to SQL (Joe Conway, Michael - Paquier) - - - - - @@ -1126,7 +1784,7 @@ This commit is also listed under libpq and psql - The memory usage dump output to the postmaster log during an + The memory usage dump that is output to the postmaster log during an out-of-memory failure now summarizes statistics when there are a large number of memory contexts, rather than possibly generating a very large report. There is also a grand total @@ -1148,7 +1806,8 @@ This commit is also listed under libpq and psql 2016-04-08 [34c33a1f0] Add BSD authentication method. --> - Add an bsd authentication method to allow the use of + Add a BSD authentication + method to allow use of the BSD Authentication service for PostgreSQL client authentication (Marisa Emerson) @@ -1164,9 +1823,10 @@ This commit is also listed under libpq and psql 2016-04-08 [2f1d2b7a7] Set PAM_RHOST item for PAM authentication --> - When using PAM authentication, provide the client - IP address or host name to PAM modules via the - PAM_RHOST item (Grzegorz Sampolski) + When using PAM + authentication, provide the client IP address or host name + to PAM modules via the PAM_RHOST item + (Grzegorz Sampolski) @@ -1175,8 +1835,8 @@ This commit is also listed under libpq and psql 2016-01-07 [5e0b5dcab] Provide more detail in postmaster log for password authe --> - Provide detail in the postmaster log during more password - authentication failures (Tom Lane) + Provide detail in the postmaster log for more types of password + authentication failure (Tom Lane) @@ -1190,8 +1850,8 @@ This commit is also listed under libpq and psql 2015-09-06 [643beffe8] Support RADIUS passwords up to 128 characters --> - Support RADIUS passwords up to 128 characters long - (Marko Tiikkaja) + Support RADIUS passwords + up to 128 characters long (Marko Tiikkaja) @@ -1200,7 +1860,8 @@ This commit is also listed under libpq and psql 2016-04-08 [35e2e357c] Add authentication parameters compat_realm and upn_usena --> - Add new SSPI authentication parameters + Add new SSPI + authentication parameters compat_realm and upn_username to control whether NetBIOS or Kerberos realm names and user names are used during SSPI @@ -1219,46 +1880,39 @@ This commit is also listed under libpq and psql - Add configure option - This allows the use of systemd service units of - type notify, which greatly simplifies the management - of PostgreSQL under systemd. + This behavior is controlled by the new configuration parameter + . It can + be useful to prevent forgotten transactions from holding locks + or preventing vacuum cleanup for too long. - Allow effective_io_concurrency to be set per-tablespace - to support cases where different tablespaces have different I/O - characteristics (Julien Rouhaud) + Raise the maximum allowed value + of to 24 hours (Simon Riggs) - Allow sessions to be terminated automatically if they are in - idle-in-transaction state for too long (Vik Fearing) - - - - This behavior is controlled by the new configuration parameter - . It can - be useful to prevent forgotten transactions from holding locks - or preventing vacuum cleanup for too long. + Allow effective_io_concurrency to be set per-tablespace + to support cases where different tablespaces have different I/O + characteristics (Julien Rouhaud) @@ -1268,9 +1922,9 @@ This commit is also listed under libpq and psql 2015-09-07 [b1e1862a1] Coordinate log_line_prefix options 'm' and 'n' to share --> - Add log_line_prefix option %n to print - the current time as a Unix epoch, with milliseconds (Tomas Vondra, - Jeff Davis) + Add option %n to + print the current time in Unix epoch form, with milliseconds (Tomas + Vondra, Jeff Davis) @@ -1299,9 +1953,26 @@ This commit is also listed under libpq and psql Making a distinction between these settings is no longer useful, - and is part of a planned future simplification of replication - setup. The old names are still accepted but are converted - internally. + and merging them is a step towards a planned future simplification + of replication setup. The old names are still accepted but are + converted to replica internally. + + + + + + + Add configure option + + + This allows the use of systemd service units of + type notify, which greatly simplifies the management + of PostgreSQL under systemd. @@ -1311,7 +1982,7 @@ This commit is also listed under libpq and psql --> Allow the server's SSL key file to have group read - access if owned by root (Christoph Berg) + access if it is owned by root (Christoph Berg) @@ -1352,8 +2023,8 @@ This commit is also listed under libpq and psql but that is unsafe and inefficient. It also prevents a new postmaster from being started until the last old backend has exited. Backends will detect postmaster death when waiting for - client I/O, so the exit will not be instantaneous, but it in most - cases should happen no later than the end of the current query. + client I/O, so the exit will not be instantaneous, but it should + happen no later than the end of the current query. @@ -1486,7 +2157,8 @@ XXX this is pending backpatch, may need to remove --> Add a option to - pg_basebackup (Peter Eisentraut) + pg_basebackup + (Peter Eisentraut) @@ -1551,7 +2223,29 @@ XXX this is pending backpatch, may need to remove Previously, such cases failed if the same target column was mentioned more than once, e.g., INSERT INTO tab (x[1], - x[2]) VALUES .... + x[2]) VALUES (...). + + + + + + + When appropriate, postpone evaluation of SELECT + output expressions until after an ORDER BY sort + (Konstantin Knizhnik) + + + + This change ensures that volatile or expensive functions in the + output list are executed in the order suggested by ORDER + BY, and that they are not evaluated more times than required + when there is a LIMIT clause. Previously, these + properties held if the ordering was performed by an index scan or + pre-merge-join sort, but not if it was performed by a top-level + sort. @@ -1608,8 +2302,8 @@ XXX this is pending backpatch, may need to remove Previously, the foreign join pushdown infrastructure left the question of security entirely up to individual foreign data - wrappers, but it would be too easy for an FDW to - inadvertently open up subtle security hole. So, make it the core + wrappers, but that made it too easy for an FDW to + inadvertently create subtle security holes. So, make it the core code's job to determine which role ID will access each table, and do not attempt join pushdown unless the role is the same for all relevant relations. @@ -1652,7 +2346,7 @@ XXX this is pending backpatch, may need to remove This command allows a database object to be marked as depending - on an extension, so that it will be automatically dropped if + on an extension, so that it will be dropped automatically if the extension is dropped (without needing CASCADE). However, the object is not part of the extension, and thus will be dumped separately by pg_dump. @@ -1710,9 +2404,9 @@ XXX this is pending backpatch, may need to remove 2016-03-23 [473b93287] Support CREATE ACCESS METHOD --> - Introduce CREATE ACCESS METHOD to allow extensions - to create index access methods (Alexander Korotkov, Petr - Jelínek) + Introduce CREATE + ACCESS METHOD to allow extensions to create index access + methods (Alexander Korotkov, Petr Jelínek) @@ -1722,8 +2416,8 @@ XXX this is pending backpatch, may need to remove --> Add a CASCADE option to CREATE - EXTENSION to automatically create extensions it depends - on (Petr Jelínek) + EXTENSION to automatically create any extensions the + requested one depends on (Petr Jelínek) @@ -1748,7 +2442,7 @@ XXX this is pending backpatch, may need to remove - This is possible because the table has no existing rows. This matches + This is safe because the table has no existing rows. This matches the longstanding behavior of FOREIGN KEY constraints. @@ -1825,7 +2519,7 @@ XXX this is pending backpatch, may need to remove Formerly, many security-sensitive functions contained hard-wired checks that would throw an error if they were called by a - non-superuser role. This forced the use of superuser roles for + non-superuser. This forced the use of superuser roles for some relatively pedestrian tasks. The hard-wired error checks are now gone in favor of making initdb revoke the default public EXECUTE privilege on these functions. @@ -1844,6 +2538,11 @@ XXX this is pending backpatch, may need to remove that can be used to grant access to what were previously superuser-only functions (Stephen Frost) + + + Currently the only such role is pg_signal_backend, + but more are expected to be added in future. + @@ -1857,6 +2556,30 @@ XXX this is pending backpatch, may need to remove + + Improve full-text search to support + searching for phrases, that is, lexemes appearing adjacent to each + other in a specific order, or with a specified distance between + them (Teodor Sigaev, Oleg Bartunov, Dmitry Ivanov) + + + + A phrase-search query can be specified in tsquery + input using the new operators <-> and + <N>. The former means + that the lexemes before and after it must appear adjacent to + each other in that order. The latter means they must be exactly + N lexemes apart. + + + + + @@ -1917,38 +2640,15 @@ XXX this is pending backpatch, may need to remove - - Improve full-text search to support searching for phrases, that - is, lexemes appearing adjacent to each other in a specific order, - or with a specified distance between them (Teodor Sigaev, Oleg - Bartunov, Dmitry Ivanov) - - - - A phrase-search query can be specified in tsquery - input using the new operators <-> and - <N>. The former means - that the lexemes before and after it must appear adjacent to - each other in that order. The latter means they must be exactly - N lexemes apart. - - - - - - Upgrade the ispell dictionary to handle modern - Hunspell files and support more languages - (Artur Zakirov) + Upgrade + the ispell + dictionary type to handle modern Hunspell files and + support more languages (Artur Zakirov) @@ -1957,7 +2657,9 @@ XXX this is pending backpatch, may need to remove 2015-10-30 [12c9a0400] Implement lookbehind constraints in our regular-expressi --> - Implement look-behind constraints in regular expressions (Tom Lane) + Implement look-behind constraints + in regular expressions + (Tom Lane) @@ -1989,7 +2691,7 @@ XXX this is pending backpatch, may need to remove 2015-11-07 [c5e86ea93] Add "xid <> xid" and "xid <> int4" operators. --> - Add transaction id operators xid <> + Add transaction ID operators xid <> xid and xid <> int4, for consistency with the corresponding equality operators (Michael Paquier) @@ -2035,8 +2737,10 @@ XXX this is pending backpatch, may need to remove 2016-01-05 [abb173392] Add scale(numeric) --> - Add a scale(numeric) function to extract the display - scale of a numeric value (Marko Tiikkaja) + Add a scale(numeric) + function to extract the display scale of a numeric value + (Marko Tiikkaja) @@ -2054,7 +2758,7 @@ XXX this is pending backpatch, may need to remove measures its argument in degrees, whereas sin() measures in radians. These functions go to some lengths to deliver exact results for values where an exact result can be - expected, e.g. sind(30) = 0.5. + expected, for instance sind(30) = 0.5. @@ -2070,9 +2774,9 @@ XXX this is pending backpatch, may need to remove The POSIX standard says that these functions should - return NaN for NaN input, and should throw an error for - out-of-range inputs including infinity. Previously our - behavior varied across platforms. + return NaN for NaN input, and should throw + an error for out-of-range inputs including infinity. + Previously our behavior varied across platforms. @@ -2081,9 +2785,10 @@ XXX this is pending backpatch, may need to remove 2016-03-29 [e511d878f] Allow to_timestamp(float8) to convert float infinity to --> - Make to_timestamp(float8) convert float - infinity to timestamp infinity (Vitaly - Burovoy) + Make to_timestamp(float8) + convert float infinity to + timestamp infinity (Vitaly Burovoy) @@ -2115,11 +2820,12 @@ XXX this is pending backpatch, may need to remove 2015-09-17 [9acb9007d] Fix oversight in tsearch type check --> - Allow ts_stat_sql() and - tsvector_update_trigger() to operate on values that - are of types binary-compatible with the expected argument type, - not just that argument type; for example allow citext - where text is expected (Teodor Sigaev) + Allow ts_stat() + and tsvector_update_trigger() + to operate on values that are of types binary-compatible with the + expected argument type, not just exactly that type; for example + allow citext where text is expected (Teodor + Sigaev) @@ -2161,8 +2867,9 @@ XXX this is pending backpatch, may need to remove In to_number(), - interpret V as dividing by 10 to the power of the - number of digits following V (Bruce Momjian) + interpret a V format code as dividing by 10 to the + power of the number of digits following V (Bruce + Momjian) @@ -2176,8 +2883,10 @@ XXX this is pending backpatch, may need to remove 2016-01-05 [ea0d494da] Make the to_reg*() functions accept text not cstring. --> - Make the to_reg*() functions accept type text - not cstring (Petr Korobeinikov) + Make the to_reg*() + functions accept type text not cstring + (Petr Korobeinikov) @@ -2234,7 +2943,7 @@ XXX this is pending backpatch, may need to remove This allows avoiding an error for an unrecognized parameter - name, and instead return a NULL. + name, instead returning a NULL. @@ -2293,7 +3002,7 @@ XXX this is pending backpatch, may need to remove In PL/pgSQL, detect mismatched CONTINUE and EXIT statements while - compiling PL/pgSQL functions, rather than at execution time + compiling a function, rather than at execution time (Jim Nasby) @@ -2395,6 +3104,23 @@ XXX this is pending backpatch, may need to remove + + Add a nonlocalized version of + the severity field in + error and notice messages (Tom Lane) + + + + This change allows client code to determine severity of an error or + notice without having to worry about localized variants of the + severity strings. + + + + + @@ -2424,6 +3150,8 @@ This commit is also listed under psql and PL/pgSQL + This is done with the new function PQresultVerboseErrorMessage(). This supports psql's new \errverbose feature, and may be useful for other clients as well. @@ -2470,8 +3198,10 @@ This commit is also listed under psql and PL/pgSQL 2015-09-14 [d02426029] Check existency of table/schema for -t/-n option (pg_dum --> - Add a @@ -2505,10 +3235,26 @@ This commit is also listed under psql and PL/pgSQL + + Allow pg_dump to dump non-extension-owned objects + that are within an extension-owned schema + (Martín Marqués) + + + + Previously such objects were ignored because they were mistakenly + assumed to belong to the extension owning their schema. + + + + + - In pg_dump, include the table name in object + In pg_dump output, include the table name in object tags for object types that are only uniquely named per-table (for example, triggers) (Peter Eisentraut) @@ -2523,6 +3269,22 @@ This commit is also listed under psql and PL/pgSQL + + Support multiple and + command-line options (Pavel Stehule, Catalin Iacob) + + + + The specified operations are carried out in the order in which the + options are given, and then psql terminates. + + + + + @@ -2608,7 +3370,7 @@ This commit is also listed under psql and PL/pgSQL 2016-06-15 [9901d8ac2] Use strftime("%c") to format timestamps in psql's \watch --> - Improve the headers output of the \watch command + Improve the headers output by the \watch command (Michael Paquier, Tom Lane) @@ -2719,8 +3481,9 @@ This commit is also listed under libpq and PL/pgSQL This change allows SQL commands in scripts to span multiple lines. Existing custom scripts will need to be modified to add a semicolon - at the end of each line if missing. (Doing so does not break - the script for use with older versions of pgbench.) + at the end of each line that does not have one already. (Doing so + does not break the script for use with older versions + of pgbench.) @@ -2777,6 +3540,7 @@ This commit is also listed under libpq and PL/pgSQL Allow changing the selection probabilities (weights) for scripts @@ -2876,6 +3640,7 @@ This commit is also listed under libpq and PL/pgSQL Speed up initdb by using just one @@ -2889,8 +3654,9 @@ This commit is also listed under libpq and PL/pgSQL 2015-12-01 [e50cda784] Use pg_rewind when target timeline was switched --> - Improve pg_rewind so that it can work when the - target timeline changes (Alexander Korotkov) + Improve pg_rewind + so that it can work when the target timeline changes (Alexander + Korotkov) @@ -2921,6 +3687,25 @@ This commit is also listed under libpq and PL/pgSQL + + Add macros to make AllocSetContextCreate() calls simpler + and safer (Tom Lane) + + + + Writing out the individual sizing parameters for a memory context + is now deprecated in favor of using one of the new + macros ALLOCSET_DEFAULT_SIZES, + ALLOCSET_SMALL_SIZES, + or ALLOCSET_START_SMALL_SIZES. + Existing code continues to work, however. + + + + + @@ -3002,19 +3787,25 @@ This commit is also listed under libpq and PL/pgSQL - Restructure index access method API to hide most of - it at the C level (Alexander Korotkov) + Restructure index access + method API to hide most of it at + the C level (Alexander Korotkov, Andrew Gierth) This change modernizes the index AM API to look more like the designs we have adopted for foreign data wrappers and tablesample handlers. This simplifies the C code - and should make it more feasible to define index access methods in + and makes it much more practical to define index access methods in installable extensions. A consequence is that most of the columns of the pg_am system catalog have disappeared. + New inspection + functions have been added to allow SQL queries to determine + index AM properties that used to be discoverable + from pg_am. @@ -3023,9 +3814,11 @@ This commit is also listed under libpq and PL/pgSQL 2016-04-06 [6c268df12] Add new catalog called pg_init_privs --> - Add pg_init_privs system catalog to hold original - privileges of initdb-created and extension-created - objects (Stephen Frost) + Add pg_init_privs + system catalog to hold original privileges + of initdb-created and extension-created objects + (Stephen Frost) @@ -3220,7 +4013,7 @@ This commit is also listed under libpq and PL/pgSQL This is somewhat like the reconstructed value, but it - could be any arbitrary chunk of data, it need not be of the same + could be any arbitrary chunk of data, not necessarily of the same data type as the indexed column. @@ -3257,6 +4050,16 @@ This commit is also listed under libpq and PL/pgSQL + + + + Support OpenSSL 1.1.0 (Andreas Karlsson, Heikki Linnakangas) + + + @@ -3272,9 +4075,10 @@ This commit is also listed under libpq and PL/pgSQL 2016-03-13 [7a8d87483] Rename auto_explain.sample_ratio to sample_rate --> - Add configuration parameter auto_explain.sample_rate - to allow contrib/auto_explain to capture just a - configurable fraction of all queries (Craig Ringer, Julien Rouhaud) + Add configuration parameter auto_explain.sample_rate to + allow contrib/auto_explain + to capture just a configurable fraction of all queries (Craig + Ringer, Julien Rouhaud) @@ -3288,9 +4092,9 @@ This commit is also listed under libpq and PL/pgSQL 2016-04-01 [9ee014fc8] Bloom index contrib module --> - Add contrib/bloom module that implements an index - access method based on Bloom filtering (Teodor Sigaev, Alexander - Korotkov) + Add contrib/bloom module that + implements an index access method based on Bloom filtering (Teodor + Sigaev, Alexander Korotkov) @@ -3306,9 +4110,9 @@ This commit is also listed under libpq and PL/pgSQL 2015-12-28 [81ee726d8] Code and docs review for cube kNN support. --> - In contrib/cube, introduce distance operators for - cubes, and support kNN-style searches in GiST indexes on cube - columns (Stas Kelvich) + In contrib/cube, introduce + distance operators for cubes, and support kNN-style searches in + GiST indexes on cube columns (Stas Kelvich) @@ -3339,8 +4143,9 @@ This commit is also listed under libpq and PL/pgSQL --> Add selectivity estimation functions for - contrib/intarray operators to improve plans for - queries using those operators (Yury Zhuravlev, Alexander Korotkov) + contrib/intarray operators + to improve plans for queries using those operators (Yury Zhuravlev, + Alexander Korotkov) @@ -3375,7 +4180,8 @@ This commit is also listed under libpq and PL/pgSQL --> Add support for word similarity to - contrib/pg_trgm (Alexander Korotkov, Artur Zakirov) + contrib/pg_trgm + (Alexander Korotkov, Artur Zakirov) @@ -3391,9 +4197,8 @@ This commit is also listed under libpq and PL/pgSQL --> Add configuration parameter - pg_trgm.similarity_threshold for contrib/pg_trgm's similarity - threshold (Artur Zakirov) + pg_trgm.similarity_threshold for + contrib/pg_trgm's similarity threshold (Artur Zakirov) @@ -3430,8 +4235,9 @@ This commit is also listed under libpq and PL/pgSQL 2016-06-17 [71d05a2c7] pg_visibility: Add pg_truncate_visibility_map function. --> - Add contrib/pg_visibility module to allow examining - table visibility maps (Robert Haas) + Add contrib/pg_visibility module + to allow examining table visibility maps (Robert Haas) @@ -3450,7 +4256,7 @@ This commit is also listed under libpq and PL/pgSQL - <filename>postgres_fdw</> + <link linkend="postgres-fdw"><filename>postgres_fdw</></> @@ -3502,7 +4308,7 @@ This commit is also listed under libpq and PL/pgSQL - Formerly, this involved sending a SELECT FOR UPDATE + Formerly, remote updates involved sending a SELECT FOR UPDATE command and then updating or deleting the selected rows one-by-one. While that is still necessary if the operation requires any local processing, it can now be done remotely if all elements of the diff --git a/doc/src/sgml/release-old.sgml b/doc/src/sgml/release-old.sgml index ec8e43f6ea..cd9b3db35a 100644 --- a/doc/src/sgml/release-old.sgml +++ b/doc/src/sgml/release-old.sgml @@ -3299,7 +3299,7 @@ New BeOS port (David Reid, Cyril Velter) Add proofreader's changes to docs (Addison-Wesley, Bruce) New Alpha spinlock code (Adriaan Joubert, Compaq) UnixWare port overhaul (Peter E) -New Darwin/Mac OS X port (Peter Bierman, Bruce Hartzler) +New macOS (Darwin) port (Peter Bierman, Bruce Hartzler) New FreeBSD Alpha port (Alfred) Overhaul shared memory segments (Tom) Add IBM S/390 support (Neale Ferguson) diff --git a/doc/src/sgml/rowtypes.sgml b/doc/src/sgml/rowtypes.sgml index 605dc71dab..9d6768e006 100644 --- a/doc/src/sgml/rowtypes.sgml +++ b/doc/src/sgml/rowtypes.sgml @@ -19,7 +19,7 @@ column of a table can be declared to be of a composite type. - + Declaration of Composite Types @@ -90,7 +90,7 @@ CREATE TABLE inventory_item ( - Composite Value Input + Constructing Composite Values composite type @@ -101,8 +101,9 @@ CREATE TABLE inventory_item ( To write a composite value as a literal constant, enclose the field values within parentheses and separate them by commas. You can put double quotes around any field value, and must do so if it contains commas or - parentheses. (More details appear below.) Thus, the general format of a - composite constant is the following: + parentheses. (More details appear below.) Thus, the general format of + a composite constant is the following: '( val1 , val2 , ... )' @@ -129,7 +130,8 @@ CREATE TABLE inventory_item ( the generic type constants discussed in . The constant is initially treated as a string and passed to the composite-type input conversion - routine. An explicit type specification might be necessary.) + routine. An explicit type specification might be necessary to tell + which type to convert the constant to.) @@ -143,7 +145,7 @@ ROW('fuzzy dice', 42, 1.99) ROW('', 42, NULL) The ROW keyword is actually optional as long as you have more than one - field in the expression, so these can simplify to: + field in the expression, so these can be simplified to: ('fuzzy dice', 42, 1.99) ('', 42, NULL) @@ -153,7 +155,7 @@ ROW('', 42, NULL) - + Accessing Composite Types @@ -198,6 +200,11 @@ SELECT (my_func(...)).field FROM ... Without the extra parentheses, this will generate a syntax error. + + + The special field name * means all fields, as + further explained in . + @@ -243,6 +250,199 @@ INSERT INTO mytab (complex_col.r, complex_col.i) VALUES(1.1, 2.2); + + Using Composite Types in Queries + + + There are various special syntax rules and behaviors associated with + composite types in queries. These rules provide useful shortcuts, + but can be confusing if you don't know the logic behind them. + + + + In PostgreSQL, a reference to a table name (or alias) + in a query is effectively a reference to the composite value of the + table's current row. For example, if we had a table + inventory_item as shown + above, we could write: + +SELECT c FROM inventory_item c; + + This query produces a single composite-valued column, so we might get + output like: + + c +------------------------ + ("fuzzy dice",42,1.99) +(1 row) + + Note however that simple names are matched to column names before table + names, so this example works only because there is no column + named c in the query's tables. + + + + The ordinary qualified-column-name + syntax table_name.column_name + can be understood as applying field + selection to the composite value of the table's current row. + (For efficiency reasons, it's not actually implemented that way.) + + + + When we write + +SELECT c.* FROM inventory_item c; + + then, according to the SQL standard, we should get the contents of the + table expanded into separate columns: + + name | supplier_id | price +------------+-------------+------- + fuzzy dice | 42 | 1.99 +(1 row) + + as if the query were + +SELECT c.name, c.supplier_id, c.price FROM inventory_item c; + + PostgreSQL will apply this expansion behavior to + any composite-valued expression, although as shown above, you need to write parentheses + around the value that .* is applied to whenever it's not a + simple table name. For example, if myfunc() is a function + returning a composite type with columns a, + b, and c, then these two queries have the + same result: + +SELECT (myfunc(x)).* FROM some_table; +SELECT (myfunc(x)).a, (myfunc(x)).b, (myfunc(x)).c FROM some_table; + + + + + + PostgreSQL handles column expansion by + actually transforming the first form into the second. So, in this + example, myfunc() would get invoked three times per row + with either syntax. If it's an expensive function you may wish to + avoid that, which you can do with a query like: + +SELECT (m).* FROM (SELECT myfunc(x) AS m FROM some_table OFFSET 0) ss; + + The OFFSET 0 clause keeps the optimizer + from flattening the sub-select to arrive at the form with + multiple calls of myfunc(). + + + + + The composite_value.* syntax results in + column expansion of this kind when it appears at the top level of + a SELECT output + list, a RETURNING + list in INSERT/UPDATE/DELETE, + a VALUES clause, or + a row constructor. + In all other contexts (including when nested inside one of those + constructs), attaching .* to a composite value does not + change the value, since it means all columns and so the + same composite value is produced again. For example, + if somefunc() accepts a composite-valued argument, + these queries are the same: + + +SELECT somefunc(c.*) FROM inventory_item c; +SELECT somefunc(c) FROM inventory_item c; + + + In both cases, the current row of inventory_item is + passed to the function as a single composite-valued argument. + Even though .* does nothing in such cases, using it is good + style, since it makes clear that a composite value is intended. In + particular, the parser will consider c in c.* to + refer to a table name or alias, not to a column name, so that there is + no ambiguity; whereas without .*, it is not clear + whether c means a table name or a column name, and in fact + the column-name interpretation will be preferred if there is a column + named c. + + + + Another example demonstrating these concepts is that all these queries + mean the same thing: + +SELECT * FROM inventory_item c ORDER BY c; +SELECT * FROM inventory_item c ORDER BY c.*; +SELECT * FROM inventory_item c ORDER BY ROW(c.*); + + All of these ORDER BY clauses specify the row's composite + value, resulting in sorting the rows according to the rules described + in . However, + if inventory_item contained a column + named c, the first case would be different from the + others, as it would mean to sort by that column only. Given the column + names previously shown, these queries are also equivalent to those above: + +SELECT * FROM inventory_item c ORDER BY ROW(c.name, c.supplier_id, c.price); +SELECT * FROM inventory_item c ORDER BY (c.name, c.supplier_id, c.price); + + (The last case uses a row constructor with the key word ROW + omitted.) + + + + Another special syntactical behavior associated with composite values is + that we can use functional notation for extracting a field + of a composite value. The simple way to explain this is that + the notations field(table) + and table.field + are interchangeable. For example, these queries are equivalent: + + +SELECT c.name FROM inventory_item c WHERE c.price > 1000; +SELECT name(c) FROM inventory_item c WHERE price(c) > 1000; + + + Moreover, if we have a function that accepts a single argument of a + composite type, we can call it with either notation. These queries are + all equivalent: + + +SELECT somefunc(c) FROM inventory_item c; +SELECT somefunc(c.*) FROM inventory_item c; +SELECT c.somefunc FROM inventory_item c; + + + + + This equivalence between functional notation and field notation + makes it possible to use functions on composite types to implement + computed fields. + + computed field + + + field + computed + + An application using the last query above wouldn't need to be directly + aware that somefunc isn't a real column of the table. + + + + + Because of this behavior, it's unwise to give a function that takes a + single composite-type argument the same name as any of the fields of + that composite type. If there is ambiguity, the field-name + interpretation will be preferred, so that such a function could not be + called without tricks. One way to force the function interpretation is + to schema-qualify the function name, that is, write + schema.func(compositevalue). + + + + Composite Type Input and Output Syntax diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml index 8ba95e1b84..130c386462 100644 --- a/doc/src/sgml/runtime.sgml +++ b/doc/src/sgml/runtime.sgml @@ -184,7 +184,7 @@ postgres$ initdb -D /usr/local/pgsql/data - Non-C and and non-POSIX locales rely on the + Non-C and non-POSIX locales rely on the operating system's collation library for character set ordering. This controls the ordering of keys stored in indexes. For this reason, a cluster cannot switch to an incompatible collation library version, @@ -605,27 +605,47 @@ psql: could not connect to server: No such file or directory - Shared memory and semaphores are collectively referred to as - System V - IPC (together with message queues, which are not - relevant for PostgreSQL). Except on - Windows, where PostgreSQL - provides its own replacement implementation of these facilities, these - facilities are required in order to run - PostgreSQL. + PostgreSQL requires the operating system to provide + inter-process communication (IPC) features, specifically + shared memory and semaphores. Unix-derived systems typically provide + System V IPC, + POSIX IPC, or both. + Windows has its own implementation of + these features and is not discussed here. The complete lack of these facilities is usually manifested by an - Illegal system call error upon server start. In - that case there is no alternative but to reconfigure your + Illegal system call error upon server + start. In that case there is no alternative but to reconfigure your kernel. PostgreSQL won't work without them. This situation is rare, however, among modern operating systems. - When PostgreSQL exceeds one of the various hard - IPC limits, the server will refuse to start and + Upon starting the server, PostgreSQL normally allocates + a very small amount of System V shared memory, as well as a much larger + amount of POSIX (mmap) shared memory. + In addition a significant number of semaphores, which can be either + System V or POSIX style, are created at server startup. Currently, + POSIX semaphores are used on Linux and FreeBSD systems while other + platforms use System V semaphores. + + + + + Prior to PostgreSQL 9.3, only System V shared memory + was used, so the amount of System V shared memory required to start the + server was much larger. If you are running an older version of the + server, please consult the documentation for your server version. + + + + + System V IPC features are typically constrained by + system-wide allocation limits. + When PostgreSQL exceeds one of these limits, + the server will refuse to start and should leave an instructive error message describing the problem and what to do about it. (See also .) The relevant kernel @@ -634,15 +654,6 @@ psql: could not connect to server: No such file or directory them, however, vary. Suggestions for some platforms are given below. - - - Prior to PostgreSQL 9.3, the amount of System V shared - memory required to start the server was much larger. If you are running - an older version of the server, please consult the documentation for - your server version. - - - <systemitem class="osname">System V</> <acronym>IPC</> Parameters @@ -651,7 +662,7 @@ psql: could not connect to server: No such file or directory Name Description - Reasonable values + Values needed to run one PostgreSQL instance @@ -659,7 +670,7 @@ psql: could not connect to server: No such file or directory SHMMAX Maximum size of shared memory segment (bytes) - at least 1kB (more if running many copies of the server) + at least 1kB, but the default is usually much higher @@ -671,7 +682,9 @@ psql: could not connect to server: No such file or directory SHMALL Total amount of shared memory available (bytes or pages) - if bytes, same as SHMMAX; if pages, ceil(SHMMAX/PAGE_SIZE) + same as SHMMAX if bytes, + or ceil(SHMMAX/PAGE_SIZE) if pages, + plus room for other applications @@ -689,7 +702,7 @@ psql: could not connect to server: No such file or directory SEMMNI Maximum number of semaphore identifiers (i.e., sets) - at least ceil((max_connections + autovacuum_max_workers + max_worker_processes + 5) / 16) + at least ceil((max_connections + autovacuum_max_workers + max_worker_processes + 5) / 16) plus room for other applications @@ -725,9 +738,8 @@ psql: could not connect to server: No such file or directory (typically 48 bytes, on 64-bit platforms) for each copy of the server. On most modern operating systems, this amount can easily be allocated. However, if you are running many copies of the server, or if other - applications are also using System V shared memory, it may be necessary - to increase SHMMAX, the maximum size in bytes of a shared - memory segment, or SHMALL, the total amount of System V shared + applications are also using System V shared memory, it may be necessary to + increase SHMALL, which is the total amount of System V shared memory system-wide. Note that SHMALL is measured in pages rather than bytes on many systems. @@ -742,6 +754,7 @@ psql: could not connect to server: No such file or directory + When using System V semaphores, PostgreSQL uses one semaphore per allowed connection (), allowed autovacuum worker process () and allowed background @@ -779,15 +792,19 @@ psql: could not connect to server: No such file or directory - The SEMMSL parameter, which determines how many - semaphores can be in a set, must be at least 17 for + Various other settings related to semaphore undo, such as + SEMMNU and SEMUME, do not affect PostgreSQL. - Various other settings related to semaphore undo, such as - SEMMNU and SEMUME, do not affect - PostgreSQL. + When using POSIX semaphores, the number of semaphores needed is the + same as for System V, that is one semaphore per allowed connection + (), allowed autovacuum worker process + () and allowed background + process (). + On the platforms where this option is preferred, there is no specific + kernel limit on the number of POSIX semaphores. @@ -1006,12 +1023,12 @@ option SEMMAP=256 - OS X - OS XIPC configuration + macOS + macOSIPC configuration - The recommended method for configuring shared memory in OS X + The recommended method for configuring shared memory in macOS is to create a file named /etc/sysctl.conf, containing variable assignments such as: @@ -1021,13 +1038,13 @@ kern.sysv.shmmni=32 kern.sysv.shmseg=8 kern.sysv.shmall=1024 - Note that in some OS X versions, + Note that in some macOS versions, all five shared-memory parameters must be set in /etc/sysctl.conf, else the values will be ignored. - Beware that recent releases of OS X ignore attempts to set + Beware that recent releases of macOS ignore attempts to set SHMMAX to a value that isn't an exact multiple of 4096. @@ -1036,7 +1053,7 @@ kern.sysv.shmall=1024 - In older OS X versions, you will need to reboot to have changes in the + In older macOS versions, you will need to reboot to have changes in the shared memory parameters take effect. As of 10.5 it is possible to change all but SHMMNI on the fly, using sysctl. But it's still best to set up your preferred @@ -1045,7 +1062,7 @@ kern.sysv.shmall=1024 - The file /etc/sysctl.conf is only honored in OS X + The file /etc/sysctl.conf is only honored in macOS 10.3.9 and later. If you are running a previous 10.3.x release, you must edit the file /etc/rc and change the values in the following commands: @@ -1057,46 +1074,18 @@ sysctl -w kern.sysv.shmseg sysctl -w kern.sysv.shmall Note that - /etc/rc is usually overwritten by OS X system updates, + /etc/rc is usually overwritten by macOS system updates, so you should expect to have to redo these edits after each update. - In OS X 10.2 and earlier, instead edit these commands in the file + In macOS 10.2 and earlier, instead edit these commands in the file /System/Library/StartupItems/SystemTuning/SystemTuning. - - SCO OpenServer - SCO OpenServerIPC configuration - - - - In the default configuration, only 512 kB of shared memory per - segment is allowed. To increase the setting, first change to the - directory /etc/conf/cf.d. To display the current value of - SHMMAX, run: - -./configure -y SHMMAX - - To set a new value for SHMMAX, run: - -./configure SHMMAX=value - - where value is the new value you want to use - (in bytes). After setting SHMMAX, rebuild the kernel: - -./link_unix - - and reboot. - - - - - Solaris 2.6 to 2.9 (Solaris 6 to Solaris 9) @@ -1172,36 +1161,6 @@ project.max-msg-ids=(priv,4096,deny) - - - UnixWare - UnixWareIPC configuration - - - - On UnixWare 7, the maximum size for shared - memory segments is 512 kB in the default configuration. - To display the current value of SHMMAX, run: - -/etc/conf/bin/idtune -g SHMMAX - - which displays the current, default, minimum, and maximum - values. To set a new value for SHMMAX, - run: - -/etc/conf/bin/idtune SHMMAX value - - where value is the new value you want to use - (in bytes). After setting SHMMAX, rebuild the - kernel: - -/etc/conf/bin/idbuild -B - - and reboot. - - - - @@ -1422,53 +1381,67 @@ export PG_OOM_ADJUST_VALUE=0 - Linux huge pages + Linux Huge Pages Using huge pages reduces overhead when using large contiguous chunks of - memory, like PostgreSQL does. To enable this + memory, as PostgreSQL does, particularly when + using large values of . To use this feature in PostgreSQL you need a kernel with CONFIG_HUGETLBFS=y and - CONFIG_HUGETLB_PAGE=y. You also have to tune the system - setting vm.nr_hugepages. To estimate the number of - necessary huge pages start PostgreSQL without - huge pages enabled and check the VmPeak value from the - proc file system: + CONFIG_HUGETLB_PAGE=y. You will also have to adjust + the kernel setting vm.nr_hugepages. To estimate the + number of huge pages needed, start PostgreSQL + without huge pages enabled and check the + postmaster's VmPeak value, as well as the system's + huge page size, using the /proc file system. This might + look like: -$ head -1 /path/to/data/directory/postmaster.pid +$ head -1 $PGDATA/postmaster.pid 4170 $ grep ^VmPeak /proc/4170/status VmPeak: 6490428 kB +$ grep ^Hugepagesize /proc/meminfo +Hugepagesize: 2048 kB - 6490428 / 2048 - (PAGE_SIZE is 2MB in this case) are - roughly 3169.154 huge pages, so you will need at - least 3170 huge pages: + 6490428 / 2048 gives approximately + 3169.154, so in this example we need at + least 3170 huge pages, which we can set with: $ sysctl -w vm.nr_hugepages=3170 + A larger setting would be appropriate if other programs on the machine + also need huge pages. Don't forget to add this setting + to /etc/sysctl.conf so that it will be reapplied + after reboots. + + + Sometimes the kernel is not able to allocate the desired number of huge - pages, so it might be necessary to repeat that command or to reboot. Don't - forget to add an entry to /etc/sysctl.conf to persist - this setting through reboots. + pages immediately, so it might be necessary to repeat the command or to + reboot. (Immediately after a reboot, most of the machine's memory + should be available to convert into huge pages.) To verify the huge + page allocation situation, use: + +$ grep Huge /proc/meminfo + - It is also necessary to give the database server operating system + It may also be necessary to give the database server's operating system user permission to use huge pages by setting - vm.hugetlb_shm_group via sysctl, and - permission to lock memory with ulimit -l. + vm.hugetlb_shm_group via sysctl, and/or + give permission to lock memory with ulimit -l. The default behavior for huge pages in PostgreSQL is to use them when possible and - to fallback to normal pages when failing. To enforce the use of huge - pages, you can set - huge_pages - to on. Note that in this case - PostgreSQL will fail to start if not enough huge - pages are available. + to fall back to normal pages when failing. To enforce the use of huge + pages, you can set + to on in postgresql.conf. + Note that with this setting PostgreSQL will fail to + start if not enough huge pages are available. @@ -1601,17 +1574,26 @@ $ kill -INT `head -1 /usr/local/pgsql/data/postmaster.pid` - PostgreSQL major versions are represented by the - first two digit groups of the version number, e.g., 8.4. - PostgreSQL minor versions are represented by the - third group of version digits, e.g., 8.4.2 is the second minor - release of 8.4. Minor releases never change the internal storage - format and are always compatible with earlier and later minor - releases of the same major version number, e.g., 8.4.2 is compatible - with 8.4, 8.4.1 and 8.4.6. To update between compatible versions, - you simply replace the executables while the server is down and - restart the server. The data directory remains unchanged — - minor upgrades are that simple. + Current PostgreSQL version numbers consist of a + major and a minor version number. For example, in the version number 10.1, + the 10 is the major version number and the 1 is the minor version number, + meaning this would be the first minor release of the major release 10. For + releases before PostgreSQL version 10.0, version + numbers consist of three numbers, for example, 9.5.3. In those cases, the + major version consists of the first two digit groups of the version number, + e.g., 9.5, and the minor version is the third number, e.g., 3, meaning this + would be the third minor release of the major release 9.5. + + + + Minor releases never change the internal storage format and are always + compatible with earlier and later minor releases of the same major version + number. For example, version 10.1 is compatible with version 10.0 and + version 10.6. Similarly, for example, 9.5.3 is compatible with 9.5.0, + 9.5.1, and 9.5.6. To update between compatible versions, you simply + replace the executables while the server is down and restart the server. + The data directory remains unchanged — minor upgrades are that + simple. @@ -1913,7 +1895,7 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433 - The simplest way to prevent spoofing for local + One way to prevent spoofing of local connections is to use a Unix domain socket directory () that has write permission only for a trusted local user. This prevents a malicious user from creating @@ -1925,6 +1907,13 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433 /tmp cleanup script to prevent removal of the symbolic link. + + Another option for local connections is for clients to use + requirepeer + to specify the required owner of the server process connected to + the socket. + + To prevent spoofing on TCP connections, the best solution is to use SSL certificates and make sure that clients check the server's certificate. @@ -2173,6 +2162,10 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433 If the private key is protected with a passphrase, the server will prompt for the passphrase and will not start until it has been entered. + Using a passphrase also disables the ability to change the server's SSL + configuration without a server restart. + Furthermore, passphrase-protected private keys cannot be used at all + on Windows. @@ -2296,11 +2289,20 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
- The files server.key, server.crt, - root.crt, and root.crl - (or their configured alternative names) - are only examined during server start; so you must restart - the server for changes in them to take effect. + The server reads these files at server start and whenever the server + configuration is reloaded. On Windows + systems, they are also re-read whenever a new backend process is spawned + for a new client connection. + + + + If an error in these files is detected at server start, the server will + refuse to start. But if an error is detected during a configuration + reload, the files are ignored and the old SSL configuration continues to + be used. On Windows systems, if an error in + these files is detected at backend start, that backend will be unable to + establish an SSL connection. In all these cases, the error condition is + reported in the server log. @@ -2317,8 +2319,8 @@ openssl req -new -text -out server.req you enter the local host name as Common Name; the challenge password can be left blank. The program will generate a key that is passphrase protected; it will not accept a passphrase that is less - than four characters long. To remove the passphrase (as you must if - you want automatic start-up of the server), run the commands: + than four characters long. To remove the passphrase again (as you must + if you want automatic start-up of the server), next run the commands: openssl rsa -in privkey.pem -out server.key rm privkey.pem diff --git a/doc/src/sgml/sources.sgml b/doc/src/sgml/sources.sgml index d132ee4a2e..877fcedbb3 100644 --- a/doc/src/sgml/sources.sgml +++ b/doc/src/sgml/sources.sgml @@ -898,7 +898,7 @@ BETTER: unrecognized node type: 42 expressions of various types need to be passed to the macro.
- When the definition an inline function references symbols + When the definition of an inline function references symbols (i.e. variables, functions) that are only available as part of the backend, the function may not be visible when included from frontend code. diff --git a/doc/src/sgml/spgist.sgml b/doc/src/sgml/spgist.sgml index f40c790612..cd4a8d07c4 100644 --- a/doc/src/sgml/spgist.sgml +++ b/doc/src/sgml/spgist.sgml @@ -114,7 +114,7 @@ box_ops - box + box << &< @@ -145,6 +145,23 @@ ~>~ + + inet_ops + inet, cidr + + && + >> + >>= + > + >= + <> + << + <<= + < + <= + = + + @@ -183,11 +200,14 @@ Inner tuples are more complex, since they are branching points in the search tree. Each inner tuple contains a set of one or more nodes, which represent groups of similar leaf values. - A node contains a downlink that leads to either another, lower-level inner - tuple, or a short list of leaf tuples that all lie on the same index page. - Each node has a label that describes it; for example, + A node contains a downlink that leads either to another, lower-level inner + tuple, or to a short list of leaf tuples that all lie on the same index page. + Each node normally has a label that describes it; for example, in a radix tree the node label could be the next character of the string - value. Optionally, an inner tuple can have a prefix value + value. (Alternatively, an operator class can omit the node labels, if it + works with a fixed set of nodes for all inner tuples; + see .) + Optionally, an inner tuple can have a prefix value that describes all its members. In a radix tree this could be the common prefix of the represented strings. The prefix value is not necessarily really a prefix, but can be any data needed by the operator class; @@ -202,7 +222,8 @@ tuple, so the SP-GiST core provides the possibility for operator classes to manage level counting while descending the tree. There is also support for incrementally reconstructing the represented - value when that is needed. + value when that is needed, and for passing down additional data (called + traverse values) during a tree descent. @@ -343,10 +364,13 @@ typedef struct spgChooseOut } addNode; struct /* results for spgSplitTuple */ { - /* Info to form new inner tuple with one node */ + /* Info to form new upper-level inner tuple with one child tuple */ bool prefixHasPrefix; /* tuple should have a prefix? */ Datum prefixPrefixDatum; /* if so, its value */ - Datum nodeLabel; /* node's label */ + int prefixNNodes; /* number of nodes */ + Datum *prefixNodeLabels; /* their labels (or NULL for + * no labels) */ + int childNodeN; /* which node gets child tuple */ /* Info to form new lower-level inner tuple with all old nodes */ bool postfixHasPrefix; /* tuple should have a prefix? */ @@ -416,29 +440,33 @@ typedef struct spgChooseOut set resultType to spgSplitTuple. This action moves all the existing nodes into a new lower-level inner tuple, and replaces the existing inner tuple with a tuple - having a single node that links to the new lower-level inner tuple. + having a single downlink pointing to the new lower-level inner tuple. Set prefixHasPrefix to indicate whether the new upper tuple should have a prefix, and if so set prefixPrefixDatum to the prefix value. This new prefix value must be sufficiently less restrictive than the original - to accept the new value to be indexed, and it should be no longer - than the original prefix. - Set nodeLabel to the label to be used for the - node that will point to the new lower-level inner tuple. + to accept the new value to be indexed. + Set prefixNNodes to the number of nodes needed in the + new tuple, and set prefixNodeLabels to a palloc'd array + holding their labels, or to NULL if node labels are not required. + Note that the total size of the new upper tuple must be no more + than the total size of the tuple it is replacing; this constrains + the lengths of the new prefix and new labels. + Set childNodeN to the index (from zero) of the node + that will downlink to the new lower-level inner tuple. Set postfixHasPrefix to indicate whether the new lower-level inner tuple should have a prefix, and if so set postfixPrefixDatum to the prefix value. The - combination of these two prefixes and the additional label must - have the same meaning as the original prefix, because there is - no opportunity to alter the node labels that are moved to the new - lower-level tuple, nor to change any child index entries. + combination of these two prefixes and the downlink node's label + (if any) must have the same meaning as the original prefix, because + there is no opportunity to alter the node labels that are moved to + the new lower-level tuple, nor to change any child index entries. After the node has been split, the choose function will be called again with the replacement inner tuple. - That call will usually result in an spgAddNode result, - since presumably the node label added in the split step will not - match the new value; so after that, there will be a third call - that finally returns spgMatchNode and allows the - insertion to descend to the leaf level. + That call may return an spgAddNode result, if no suitable + node was created by the spgSplitTuple action. Eventually + choose must return spgMatchNode to + allow the insertion to descend to the next level.
@@ -492,9 +520,8 @@ typedef struct spgPickSplitOut prefixDatum to the prefix value. Set nNodes to indicate the number of nodes that the new inner tuple will contain, and - set nodeLabels to an array of their label values. - (If the nodes do not require labels, set nodeLabels - to NULL; see for details.) + set nodeLabels to an array of their label values, + or to NULL if node labels are not required. Set mapTuplesToNodes to an array that gives the index (from zero) of the node that each leaf tuple should be assigned to. Set leafTupleDatums to an array of the values to @@ -561,7 +588,7 @@ typedef struct spgInnerConsistentIn Datum reconstructedValue; /* value reconstructed at parent */ void *traversalValue; /* opclass-specific traverse value */ - MemoryContext traversalMemoryContext; + MemoryContext traversalMemoryContext; /* put new traverse values here */ int level; /* current level (counting from zero) */ bool returnData; /* original data must be returned? */ @@ -580,7 +607,6 @@ typedef struct spgInnerConsistentOut int *levelAdds; /* increment level by this much for each */ Datum *reconstructedValues; /* associated reconstructed values */ void **traversalValues; /* opclass-specific traverse values */ - } spgInnerConsistentOut; @@ -599,6 +625,11 @@ typedef struct spgInnerConsistentOut parent tuple; it is (Datum) 0 at the root level or if the inner_consistent function did not provide a value at the parent level. + traversalValue is a pointer to any traverse data + passed down from the previous call of inner_consistent + on the parent index tuple, or NULL at the root level. + traversalMemoryContext is the memory context in which + to store output traverse values (see below). level is the current inner tuple's level, starting at zero for the root level. returnData is true if reconstructed data is @@ -615,9 +646,6 @@ typedef struct spgInnerConsistentOut inner tuple, and nodeLabels is an array of their label values, or NULL if the nodes do not have labels. - traversalValue is a pointer to data that - inner_consistent gets when called on child nodes from an - outer call of inner_consistent on parent nodes. @@ -633,17 +661,20 @@ typedef struct spgInnerConsistentOut reconstructedValues to an array of the values reconstructed for each child node to be visited; otherwise, leave reconstructedValues as NULL. + If it is desired to pass down additional out-of-band information + (traverse values) to lower levels of the tree search, + set traversalValues to an array of the appropriate + traverse values, one for each child node to be visited; otherwise, + leave traversalValues as NULL. Note that the inner_consistent function is responsible for palloc'ing the - nodeNumbers, levelAdds and - reconstructedValues arrays. - Sometimes accumulating some information is needed, while - descending from parent to child node was happened. In this case - traversalValues array keeps pointers to - specific data you need to accumulate for every child node. - Memory for traversalValues should be allocated in - the default context, but each element of it should be allocated in - traversalMemoryContext. + nodeNumbers, levelAdds, + reconstructedValues, and + traversalValues arrays in the current memory context. + However, any output traverse values pointed to by + the traversalValues array should be allocated + in traversalMemoryContext. + Each traverse value must be a single palloc'd chunk. @@ -670,8 +701,8 @@ typedef struct spgLeafConsistentIn ScanKey scankeys; /* array of operators and comparison values */ int nkeys; /* length of array */ - void *traversalValue; /* opclass-specific traverse value */ Datum reconstructedValue; /* value reconstructed at parent */ + void *traversalValue; /* opclass-specific traverse value */ int level; /* current level (counting from zero) */ bool returnData; /* original data must be returned? */ @@ -700,6 +731,9 @@ typedef struct spgLeafConsistentOut parent tuple; it is (Datum) 0 at the root level or if the inner_consistent function did not provide a value at the parent level. + traversalValue is a pointer to any traverse data + passed down from the previous call of inner_consistent + on the parent index tuple, or NULL at the root level. level is the current leaf tuple's level, starting at zero for the root level. returnData is true if reconstructed data is @@ -797,7 +831,10 @@ typedef struct spgLeafConsistentOut point. In such a case the code typically works with the nodes by number, and there is no need for explicit node labels. To suppress node labels (and thereby save some space), the picksplit - function can return NULL for the nodeLabels array. + function can return NULL for the nodeLabels array, + and likewise the choose function can return NULL for + the prefixNodeLabels array during + a spgSplitTuple action. This will in turn result in nodeLabels being NULL during subsequent calls to choose and inner_consistent. In principle, node labels could be used for some inner tuples and omitted @@ -807,10 +844,7 @@ typedef struct spgLeafConsistentOut When working with an inner tuple having unlabeled nodes, it is an error for choose to return spgAddNode, since the set - of nodes is supposed to be fixed in such cases. Also, there is no - provision for generating an unlabeled node in spgSplitTuple - actions, since it is expected that an spgAddNode action will - be needed as well. + of nodes is supposed to be fixed in such cases. @@ -859,11 +893,10 @@ typedef struct spgLeafConsistentOut The PostgreSQL source distribution includes - several examples of index operator classes for - SP-GiST. The core system currently provides radix - trees over text columns and two types of trees over points: quad-tree and - k-d tree. Look into src/backend/access/spgist/ to see the - code. + several examples of index operator classes for SP-GiST, + as described in . Look + into src/backend/access/spgist/ + and src/backend/utils/adt/ to see the code. diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml index 9ae7126ae7..836ce0822f 100644 --- a/doc/src/sgml/spi.sgml +++ b/doc/src/sgml/spi.sgml @@ -90,21 +90,6 @@ int SPI_connect(void) function if you want to execute commands through SPI. Some utility SPI functions can be called from unconnected procedures. - - - If your procedure is already connected, - SPI_connect will return the error code - SPI_ERROR_CONNECT. This could happen if - a procedure that has called SPI_connect - directly calls another procedure that calls - SPI_connect. While recursive calls to the - SPI manager are permitted when an SQL command - called through SPI invokes another function that uses - SPI, directly nested calls to - SPI_connect and - SPI_finish are forbidden. - (But see SPI_push and SPI_pop.) - @@ -164,13 +149,6 @@ int SPI_finish(void) abort the transaction via elog(ERROR). In that case SPI will clean itself up automatically. - - - If SPI_finish is called without having a valid - connection, it will return SPI_ERROR_UNCONNECTED. - There is no fundamental problem with this; it means that the SPI - manager has nothing to do. - @@ -200,86 +178,6 @@ int SPI_finish(void) - - SPI_push - - - SPI_push - 3 - - - - SPI_push - push SPI stack to allow recursive SPI usage - - - - -void SPI_push(void) - - - - - Description - - - SPI_push should be called before executing another - procedure that might itself wish to use SPI. - After SPI_push, SPI is no longer in a - connected state, and SPI function calls will be rejected unless - a fresh SPI_connect is done. This ensures a clean - separation between your procedure's SPI state and that of another procedure - you call. After the other procedure returns, call - SPI_pop to restore access to your own SPI state. - - - - Note that SPI_execute and related functions - automatically do the equivalent of SPI_push before - passing control back to the SQL execution engine, so it is not necessary - for you to worry about this when using those functions. - Only when you are directly calling arbitrary code that might contain - SPI_connect calls do you need to issue - SPI_push and SPI_pop. - - - - - - - - - SPI_pop - - - SPI_pop - 3 - - - - SPI_pop - pop SPI stack to return from recursive SPI usage - - - - -void SPI_pop(void) - - - - - Description - - - SPI_pop pops the previous environment from the - SPI call stack. See SPI_push. - - - - - - - SPI_execute @@ -2891,7 +2789,7 @@ int SPI_fnumber(TupleDesc rowdesc, const char * Return Value - Column number (count starts at 1), or + Column number (count starts at 1 for user-defined columns), or SPI_ERROR_NOATTRIBUTE if the named column was not found. @@ -3361,17 +3259,8 @@ char * SPI_getnspname(Relation rel) upper executor context, that is, the memory context that was current when SPI_connect was called, which is precisely the right context for a value returned from your - procedure. - - - - If SPI_palloc is called while the procedure is - not connected to SPI, then it acts the same as a normal - palloc. Before a procedure connects to the - SPI manager, the current memory context is the upper executor - context, so all allocations made by the procedure via - palloc or by SPI utility functions are made in - this context. + procedure. Several of the other utility procedures described in + this section also return objects created in the upper executor context. @@ -3379,24 +3268,14 @@ char * SPI_getnspname(Relation rel) context of the procedure, which is created by SPI_connect, is made the current context. All allocations made by palloc, - repalloc, or SPI utility functions (except for - SPI_copytuple, - SPI_returntuple, - SPI_modifytuple, and - SPI_palloc) are made in this context. When a + repalloc, or SPI utility functions (except as + described in this section) are made in this context. When a procedure disconnects from the SPI manager (via SPI_finish) the current context is restored to the upper executor context, and all allocations made in the procedure memory context are freed and cannot be used any more. - - All functions described in this section can be used by both - connected and unconnected procedures. In an unconnected procedure, - they act the same as the underlying ordinary server functions - (palloc, etc.). - - @@ -3425,6 +3304,11 @@ void * SPI_palloc(Size size) SPI_palloc allocates memory in the upper executor context. + + + This function can only be used while connected to SPI. + Otherwise, it throws an error. + @@ -3604,6 +3488,12 @@ HeapTuple SPI_copytuple(HeapTuple row) row from a trigger. In a function declared to return a composite type, use SPI_returntuple instead. + + + This function can only be used while connected to SPI. + Otherwise, it returns NULL and sets SPI_result to + SPI_ERROR_UNCONNECTED. + @@ -3625,8 +3515,8 @@ HeapTuple SPI_copytuple(HeapTuple row) Return Value - the copied row; NULL only if - tuple is NULL + the copied row, or NULL on error + (see SPI_result for an error indication) @@ -3662,6 +3552,12 @@ HeapTupleHeader SPI_returntuple(HeapTuple row, TupleDesc before returning. + + This function can only be used while connected to SPI. + Otherwise, it returns NULL and sets SPI_result to + SPI_ERROR_UNCONNECTED. + + Note that this should be used for functions that are declared to return composite types. It is not used for triggers; use @@ -3698,10 +3594,9 @@ HeapTupleHeader SPI_returntuple(HeapTuple row, TupleDesc Return Value - HeapTupleHeader pointing to copied row; - NULL only if - row or rowdesc is - NULL + HeapTupleHeader pointing to copied row, + or NULL on error + (see SPI_result for an error indication) @@ -3735,6 +3630,13 @@ HeapTuple SPI_modifytuple(Relation rel, HeapTuple SPI_modifytuple creates a new row by substituting new values for selected columns, copying the original row's columns at other positions. The input row is not modified. + The new row is returned in the upper executor context. + + + + This function can only be used while connected to SPI. + Otherwise, it returns NULL and sets SPI_result to + SPI_ERROR_UNCONNECTED. @@ -3820,8 +3722,8 @@ HeapTuple SPI_modifytuple(Relation rel, HeapTuple new row with modifications, allocated in the upper executor - context; NULL only if row - is NULL + context, or NULL on error + (see SPI_result for an error indication) @@ -3844,11 +3746,20 @@ HeapTuple SPI_modifytuple(Relation rel, HeapTuple if colnum contains an invalid column number (less - than or equal to 0 or greater than the number of column in + than or equal to 0 or greater than the number of columns in row) + + + SPI_ERROR_UNCONNECTED + + + if SPI is not active + + + diff --git a/doc/src/sgml/storage.sgml b/doc/src/sgml/storage.sgml index 1b812bd0a9..5c52824dfc 100644 --- a/doc/src/sgml/storage.sgml +++ b/doc/src/sgml/storage.sgml @@ -141,7 +141,7 @@ Item - pg_xlog + pg_wal Subdirectory containing WAL (Write Ahead Log) files @@ -474,7 +474,7 @@ for storing TOAST-able columns on disk: Each TOAST-able data type specifies a default strategy for columns of that data type, but the strategy for a given table column can be altered -with ALTER TABLE SET STORAGE. +with ALTER TABLE ... SET STORAGE. diff --git a/doc/src/sgml/stylesheet-common.xsl b/doc/src/sgml/stylesheet-common.xsl index de3637624a..c23d38f128 100644 --- a/doc/src/sgml/stylesheet-common.xsl +++ b/doc/src/sgml/stylesheet-common.xsl @@ -7,11 +7,10 @@ all output formats (HTML, HTML Help, XSL-FO, etc.). --> + - - - ?? + ? + + ? diff --git a/doc/src/sgml/stylesheet-speedup-common.xsl b/doc/src/sgml/stylesheet-speedup-common.xsl new file mode 100644 index 0000000000..e3fb582a1c --- /dev/null +++ b/doc/src/sgml/stylesheet-speedup-common.xsl @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +en + + diff --git a/doc/src/sgml/stylesheet-speedup-xhtml.xsl b/doc/src/sgml/stylesheet-speedup-xhtml.xsl new file mode 100644 index 0000000000..da0f2b5a97 --- /dev/null +++ b/doc/src/sgml/stylesheet-speedup-xhtml.xsl @@ -0,0 +1,345 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Error: If you change $chunk.section.depth, then you must update the performance-optimized chunk-all-sections-template. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/src/sgml/stylesheet.css b/doc/src/sgml/stylesheet.css index 60dcc76209..f845876d07 100644 --- a/doc/src/sgml/stylesheet.css +++ b/doc/src/sgml/stylesheet.css @@ -2,18 +2,18 @@ /* color scheme similar to www.postgresql.org */ -BODY { +body { color: #000000; background: #FFFFFF; font-family: verdana, sans-serif; } -A:link { color:#0066A2; } -A:visited { color:#004E66; } -A:active { color:#0066A2; } -A:hover { color:#000000; } +a:link { color:#0066A2; } +a:visited { color:#004E66; } +a:active { color:#0066A2; } +a:hover { color:#000000; } -H1 { +h1 { font-size: 1.4em; font-weight: bold; margin-top: 0em; @@ -21,34 +21,34 @@ H1 { color: #EC5800; } -H2 { +h2 { font-size: 1.2em; margin: 1.2em 0em 1.2em 0em; font-weight: bold; - color: #666; + color: #EC5800; } -H3 { +h3 { font-size: 1.1em; margin: 1.2em 0em 1.2em 0em; font-weight: bold; color: #666; } -H4 { +h4 { font-size: 0.95em; margin: 1.2em 0em 1.2em 0em; font-weight: normal; color: #666; } -H5 { +h5 { font-size: 0.9em; margin: 1.2em 0em 1.2em 0em; font-weight: normal; } -H6 { +h6 { font-size: 0.85em; margin: 1.2em 0em 1.2em 0em; font-weight: normal; @@ -56,13 +56,13 @@ H6 { /* center some titles */ -.BOOK .TITLE, .BOOK .CORPAUTHOR, .BOOK .COPYRIGHT { +.book .title, .book .corpauthor, .book .copyright { text-align: center; } /* decoration for formal examples */ -DIV.EXAMPLE { +div.example { padding-left: 15px; border-style: solid; border-width: 0px; @@ -71,28 +71,16 @@ DIV.EXAMPLE { margin: 0.5ex; } -/* less dense spacing of TOC */ - -.BOOK .TOC DL DT { - padding-top: 1.5ex; - padding-bottom: 1.5ex; -} - -.BOOK .TOC DL DL DT { - padding-top: 0ex; - padding-bottom: 0ex; -} - /* miscellaneous */ -PRE.LITERALLAYOUT, .SCREEN, .SYNOPSIS, .PROGRAMLISTING { +pre.literallayout, .screen, .synopsis, .programlisting { margin-left: 4ex; } -.COMMENT { color: red; } +.comment { color: red; } -VAR { font-family: monospace; font-style: italic; } +var { font-family: monospace; font-style: italic; } /* Konqueror's standard style for ACRONYM is italic. */ -ACRONYM { font-style: inherit; } +acronym { font-style: inherit; } -.OPTION { white-space: nowrap; } +.option { white-space: nowrap; } diff --git a/doc/src/sgml/stylesheet.xsl b/doc/src/sgml/stylesheet.xsl index 7967b361dd..42e8cce368 100644 --- a/doc/src/sgml/stylesheet.xsl +++ b/doc/src/sgml/stylesheet.xsl @@ -1,4 +1,8 @@ + +%common.entities; +]> + @@ -58,4 +63,325 @@ section toc set toc,title + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + +
+

+ + + +

+
+ + + + + + + +
+
+
+ + + + + +
+

+ + + +

+
+ + + + + + + +
+
+
+
+
+ + + + + + + + +
+
+ + + + + + + + + +
+ + + + + + +

+ +

+
+
+ + + + + + + +
+
+
+
+ + + + + + + + + + + + | + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/src/sgml/syntax.sgml b/doc/src/sgml/syntax.sgml index 36df6c6b1b..4ea667bd52 100644 --- a/doc/src/sgml/syntax.sgml +++ b/doc/src/sgml/syntax.sgml @@ -1449,12 +1449,13 @@ $1.somecolumn
- In a select list (see ), you - can ask for all fields of a composite value by + You can ask for all fields of a composite value by writing .*: (compositecol).* + This notation behaves differently depending on context; + see for details. @@ -1531,7 +1532,7 @@ sqrt(2) interchangeable. This behavior is not SQL-standard but is provided in PostgreSQL because it allows use of functions to emulate computed fields. For more information see - . + .
@@ -1693,11 +1694,21 @@ SELECT string_agg(a ORDER BY a, ',') FROM table; -- incorrect case, write just () not (*). (PostgreSQL will actually accept either spelling, but only the first way conforms to the SQL standard.) + + + + + median + + + median + percentile + An example of an ordered-set aggregate call is: -SELECT percentile_disc(0.5) WITHIN GROUP (ORDER BY income) FROM households; - percentile_disc +SELECT percentile_cont(0.5) WITHIN GROUP (ORDER BY income) FROM households; + percentile_cont ----------------- 50489 @@ -2291,7 +2302,8 @@ SELECT ROW(1,2.5,'this is a test'); rowvalue.*, which will be expanded to a list of the elements of the row value, just as occurs when the .* syntax is used at the top level - of a SELECT list. For example, if table t has + of a SELECT list (see ). + For example, if table t has columns f1 and f2, these are the same: SELECT ROW(t.*, 42) FROM t; @@ -2302,9 +2314,9 @@ SELECT ROW(t.f1, t.f2, 42) FROM t; Before PostgreSQL 8.2, the - .* syntax was not expanded, so that writing - ROW(t.*, 42) created a two-field row whose first field - was another row value. The new behavior is usually more useful. + .* syntax was not expanded in row constructors, so + that writing ROW(t.*, 42) created a two-field row whose first + field was another row value. The new behavior is usually more useful. If you need the old behavior of nested row values, write the inner row value without .*, for instance ROW(t, 42). diff --git a/doc/src/sgml/textsearch.sgml b/doc/src/sgml/textsearch.sgml index be5974a4ff..67e4901c92 100644 --- a/doc/src/sgml/textsearch.sgml +++ b/doc/src/sgml/textsearch.sgml @@ -264,7 +264,7 @@ SELECT 'fat & cow'::tsquery @@ 'a fat cat sat on a mat and ate a fat rat'::t text, any more than a tsvector is. A tsquery contains search terms, which must be already-normalized lexemes, and may combine multiple terms using AND, OR, NOT, and FOLLOWED BY operators. - (For details see .) There are + (For syntax details see .) There are functions to_tsquery, plainto_tsquery, and phraseto_tsquery that are helpful in converting user-written text into a proper @@ -323,6 +323,8 @@ text @@ text at least one of its arguments must appear, while the ! (NOT) operator specifies that its argument must not appear in order to have a match. + For example, the query fat & ! rat matches documents that + contain fat but not rat. @@ -377,6 +379,28 @@ SELECT phraseto_tsquery('the cats ate the rats'); then &, then <->, and ! most tightly. + + + It's worth noticing that the AND/OR/NOT operators mean something subtly + different when they are within the arguments of a FOLLOWED BY operator + than when they are not, because within FOLLOWED BY the exact position of + the match is significant. For example, normally !x matches + only documents that do not contain x anywhere. + But !x <-> y matches y if it is not + immediately after an x; an occurrence of x + elsewhere in the document does not prevent a match. Another example is + that x & y normally only requires that x + and y both appear somewhere in the document, but + (x & y) <-> z requires x + and y to match at the same place, immediately before + a z. Thus this query behaves differently from + x <-> z & y <-> z, which will match a + document containing two separate sequences x z and + y z. (This specific query is useless as written, + since x and y could not match at the same place; + but with more complex situations such as prefix-match patterns, a query + of this form could be useful.) + @@ -1290,19 +1314,7 @@ query.', ts_headline uses the original document, not a tsvector summary, so it can be slow and should be used with - care. A typical mistake is to call ts_headline for - every matching document when only ten documents are - to be shown. SQL subqueries can help; here is an - example: - - -SELECT id, ts_headline(body, q), rank -FROM (SELECT id, body, q, ts_rank_cd(ti, q) AS rank - FROM apod, to_tsquery('stars') q - WHERE ti @@ q - ORDER BY rank DESC - LIMIT 10) AS foo; - + care. @@ -3622,10 +3634,10 @@ SELECT plainto_tsquery('supernovae stars'); - The optional parameter PATTERN can be the name of + The optional parameter PATTERN can be the name of a text search object, optionally schema-qualified. If - PATTERN is omitted then information about all - visible objects will be displayed. PATTERN can be a + PATTERN is omitted then information about all + visible objects will be displayed. PATTERN can be a regular expression and can provide separate patterns for the schema and object names. The following examples illustrate this: diff --git a/doc/src/sgml/uuid-ossp.sgml b/doc/src/sgml/uuid-ossp.sgml index e275febe4e..227d4a839c 100644 --- a/doc/src/sgml/uuid-ossp.sgml +++ b/doc/src/sgml/uuid-ossp.sgml @@ -169,7 +169,7 @@ SELECT uuid_generate_v3(uuid_ns_url(), 'http://www.postgresql.org'); platforms. uuid-ossp can now be built without the OSSP library on some platforms. On FreeBSD, NetBSD, and some other BSD-derived platforms, suitable UUID creation functions are included in the - core libc library. On Linux, OS X, and some other + core libc library. On Linux, macOS, and some other platforms, suitable functions are provided in the libuuid library, which originally came from the e2fsprogs project (though on modern Linux it is considered part diff --git a/doc/src/sgml/wal.sgml b/doc/src/sgml/wal.sgml index 503ea8a2a7..346aa769a8 100644 --- a/doc/src/sgml/wal.sgml +++ b/doc/src/sgml/wal.sgml @@ -115,7 +115,7 @@ - On OS X, write caching can be prevented by + On macOS, write caching can be prevented by setting wal_sync_method to fsync_writethrough. @@ -557,7 +557,7 @@ - The number of WAL segment files in pg_xlog directory depends on + The number of WAL segment files in pg_wal directory depends on min_wal_size, max_wal_size and the amount of WAL generated in previous checkpoint cycles. When old log segment files are no longer needed, they are removed or recycled (that is, @@ -582,7 +582,7 @@ kept at all times. Also, if WAL archiving is used, old segments can not be removed or recycled until they are archived. If WAL archiving cannot keep up with the pace that WAL is generated, or if archive_command - fails repeatedly, old WAL files will accumulate in pg_xlog + fails repeatedly, old WAL files will accumulate in pg_wal until the situation is resolved. A slow or failed standby server that uses a replication slot will have the same effect (see ). @@ -594,7 +594,7 @@ which are similar to checkpoints in normal operation: the server forces all its state to disk, updates the pg_control file to indicate that the already-processed WAL data need not be scanned again, - and then recycles any old log segment files in the pg_xlog + and then recycles any old log segment files in the pg_wal directory. Restartpoints can't be performed more frequently than checkpoints in the master because restartpoints can only be performed at checkpoint records. @@ -724,6 +724,10 @@ WAL Internals + + LSN + + WAL is automatically enabled; no action is required from the administrator except ensuring that the @@ -732,9 +736,21 @@ linkend="wal-configuration">). + + WAL records are appended to the WAL + logs as each new record is written. The insert position is described by + a Log Sequence Number (LSN) that is a byte offset into + the logs, increasing monotonically with each new record. + LSN values are returned as the datatype + pg_lsn. Values can be + compared to calculate the volume of WAL data that + separates them, so they are used to measure the progress of replication + and recovery. + + WAL logs are stored in the directory - pg_xlog under the data directory, as a set of + pg_wal under the data directory, as a set of segment files, normally each 16 MB in size (but the size can be changed by altering the + + The second argument of AggCheckCallContext can be used to + retrieve the memory context in which aggregate state values are being kept. + This is useful for transition functions that wish to use expanded + objects (see ) as their state values. + On first call, the transition function should return an expanded object + whose memory context is a child of the aggregate state context, and then + keep returning the same expanded object on subsequent calls. See + array_append() for an example. (array_append() + is not the transition function of any built-in aggregate, but it is written + to behave efficiently when used as transition function of a custom + aggregate.) + + Another support routine available to aggregate functions written in C is AggGetAggref, which returns the Aggref diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml index d8d2e9e490..255bfddad7 100644 --- a/doc/src/sgml/xfunc.sgml +++ b/doc/src/sgml/xfunc.sgml @@ -204,8 +204,8 @@ SELECT clean_emp(); If an argument is of a composite type, then the dot notation, - e.g., argname.fieldname or - $1.fieldname, can be used to access attributes of the + e.g., argname.fieldname or + $1.fieldname, can be used to access attributes of the argument. Again, you might need to qualify the argument's name with the function name to make the form with an argument name unambiguous. @@ -394,8 +394,8 @@ SELECT name, double_salary(emp.*) AS dream Notice the use of the syntax $1.salary to select one field of the argument row value. Also notice - how the calling SELECT command uses * - to select + how the calling SELECT command + uses table_name.* to select the entire current row of a table as a composite value. The table row can alternatively be referenced using just the table name, like this: @@ -405,6 +405,8 @@ SELECT name, double_salary(emp) AS dream WHERE emp.cubicle ~= point '(2,1)'; but this usage is deprecated since it's easy to get confused. + (See for details about these + two notations for the composite value of a table row.) @@ -479,7 +481,8 @@ $$ LANGUAGE SQL; - We could call this function directly in either of two ways: + We could call this function directly either by using it in + a value expression: SELECT new_emp(); @@ -487,7 +490,11 @@ SELECT new_emp(); new_emp -------------------------- (None,1000.0,25,"(2,2)") + + + or by calling it as a table function: + SELECT * FROM new_emp(); name | salary | age | cubicle @@ -524,11 +531,7 @@ LINE 1: SELECT new_emp().name; - Another option is to use - functional notation for extracting an attribute. The simple way - to explain this is that we can use the - notations attribute(table) and table.attribute - interchangeably. + Another option is to use functional notation for extracting an attribute: SELECT name(new_emp()); @@ -538,50 +541,10 @@ SELECT name(new_emp()); None - --- This is the same as: --- SELECT emp.name AS youngster FROM emp WHERE emp.age < 30; - -SELECT name(emp) AS youngster FROM emp WHERE age(emp) < 30; - - youngster ------------ - Sam - Andy - + As explained in , the field notation and + functional notation are equivalent. - - - The equivalence between functional notation and attribute notation - makes it possible to use functions on composite types to emulate - computed fields. - - computed field - - - field - computed - - For example, using the previous definition - for double_salary(emp), we can write - - -SELECT emp.name, emp.double_salary FROM emp; - - - An application using this wouldn't need to be directly aware that - double_salary isn't a real column of the table. - (You can also emulate computed fields with views.) - - - - Because of this behavior, it's unwise to give a function that takes - a single composite-type argument the same name as any of the fields of - that composite type. - - - Another way to use a function returning a composite type is to pass the result to another function that accepts the correct row type as input: @@ -598,12 +561,6 @@ SELECT getname(new_emp()); (1 row) - - - Still another way to use a function that returns a composite type is to - call it as a table function, as described in . - @@ -1005,12 +962,11 @@ SELECT name, child FROM nodes, LATERAL listchildren(name) AS child; - Currently, functions returning sets can also be called in the select list + Functions returning sets can also be called in the select list of a query. For each row that the query - generates by itself, the function returning set is invoked, and an output - row is generated for each element of the function's result set. Note, - however, that this capability is deprecated and might be removed in future - releases. The previous example could also be done with queries like + generates by itself, the set-returning function is invoked, and an output + row is generated for each element of the function's result set. + The previous example could also be done with queries like these: @@ -1041,6 +997,65 @@ SELECT name, listchildren(name) FROM nodes; the LATERAL syntax. + + If there is more than one set-returning function in the query's select + list, the behavior is similar to what you get from putting the functions + into a single LATERAL ROWS FROM( ... ) FROM-clause + item. For each row from the underlying query, there is an output row + using the first result from each function, then an output row using the + second result, and so on. If some of the set-returning functions + produce fewer outputs than others, null values are substituted for the + missing data, so that the total number of rows emitted for one + underlying row is the same as for the set-returning function that + produced the most outputs. Thus the set-returning functions + run in lockstep until they are all exhausted, and then + execution continues with the next underlying row. + + + + Set-returning functions can be nested in a select list, although that is + not allowed in FROM-clause items. In such cases, each level + of nesting is treated separately, as though it were + a separate LATERAL ROWS FROM( ... ) item. For example, in + +SELECT srf1(srf2(x), srf3(y)), srf4(srf5(z)) FROM tab; + + the set-returning functions srf2, srf3, + and srf5 would be run in lockstep for each row + of tab, and then srf1 and srf4 + would be applied in lockstep to each row produced by the lower + functions. + + + + This behavior also means that set-returning functions will be evaluated + even when it might appear that they should be skipped because of a + conditional-evaluation construct, such as CASE + or COALESCE. For example, consider + +SELECT x, CASE WHEN x > 0 THEN generate_series(1, 5) ELSE 0 END FROM tab; + + It might seem that this should produce five repetitions of input + rows that have x > 0, and a single repetition of those + that do not; but actually it will produce five repetitions of every + input row. This is because generate_series() is run first, + and then the CASE expression is applied to its result rows. + The behavior is thus comparable to + +SELECT x, CASE WHEN x > 0 THEN g ELSE 0 END + FROM tab, LATERAL generate_series(1,5) AS g; + + It would be exactly the same, except that in this specific example, + the planner could choose to put g on the outside of the + nestloop join, since g has no actual lateral dependency + on tab. That would result in a different output row + order. Set-returning functions in the select list are always evaluated + as though they are on the inside of a nestloop join with the rest of + the FROM clause, so that the function(s) are run to + completion before the next row from the FROM clause is + considered. + + If a function's last command is INSERT, UPDATE, @@ -1055,14 +1070,19 @@ SELECT name, listchildren(name) FROM nodes; - The key problem with using set-returning functions in the select list, - rather than the FROM clause, is that putting more than one - set-returning function in the same select list does not behave very - sensibly. (What you actually get if you do so is a number of output - rows equal to the least common multiple of the numbers of rows produced - by each set-returning function.) The LATERAL syntax - produces less surprising results when calling multiple set-returning - functions, and should usually be used instead. + Before PostgreSQL 10, putting more than one + set-returning function in the same select list did not behave very + sensibly unless they always produced equal numbers of rows. Otherwise, + what you got was a number of output rows equal to the least common + multiple of the numbers of rows produced by the set-returning + functions. Also, nested set-returning functions did not work as + described above; instead, a set-returning function could have at most + one set-returning argument, and each nest of set-returning functions + was run independently. The behavior for conditional execution + (set-returning functions inside CASE etc) was different too. + Use of the LATERAL syntax is recommended when writing + queries that need to work in older PostgreSQL versions, + because that will give consistent results across different versions. @@ -1305,12 +1325,15 @@ CREATE FUNCTION test(smallint, double precision) RETURNS ... A function that takes a single argument of a composite type should generally not have the same name as any attribute (field) of that type. - Recall that attribute(table) is considered equivalent - to table.attribute. In the case that there is an + Recall that attribute(table) + is considered equivalent + to table.attribute. + In the case that there is an ambiguity between a function on a composite type and an attribute of the composite type, the attribute will always be used. It is possible to override that choice by schema-qualifying the function name - (that is, schema.func(table)) but it's better to + (that is, schema.func(table) + ) but it's better to avoid the problem by not choosing conflicting names. @@ -2818,7 +2841,7 @@ HeapTuple heap_form_tuple(TupleDesc tupdesc, Datum *values, bool *isnull) HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values) to build a HeapTuple given user data - in C string form. values is an array of C strings, + in C string form. values is an array of C strings, one for each attribute of the return row. Each C string should be in the form expected by the input function of the attribute data type. In order to return a null value for one of the attributes, @@ -2866,7 +2889,7 @@ HeapTupleGetDatum(HeapTuple tuple) is used to hold a pointer to FuncCallContext across calls. -typedef struct +typedef struct FuncCallContext { /* * Number of times we've been called before @@ -2874,7 +2897,7 @@ typedef struct * call_cntr is initialized to 0 for you by SRF_FIRSTCALL_INIT(), and * incremented for you every time SRF_RETURN_NEXT() is called. */ - uint32 call_cntr; + uint64 call_cntr; /* * OPTIONAL maximum number of calls @@ -2883,7 +2906,7 @@ typedef struct * If not set, you must provide alternative means to know when the * function is done. */ - uint32 max_calls; + uint64 max_calls; /* * OPTIONAL pointer to result slot diff --git a/doc/src/sgml/xindex.sgml b/doc/src/sgml/xindex.sgml index f0b711e2ce..333a36c456 100644 --- a/doc/src/sgml/xindex.sgml +++ b/doc/src/sgml/xindex.sgml @@ -288,7 +288,7 @@ have a fixed set of strategies either. Instead the support routines of each operator class interpret the strategy numbers according to the operator class's definition. As an example, the strategy numbers used by - the built-in operator classes for arrays are shown in + the built-in operator class for arrays are shown in . diff --git a/doc/src/sgml/xml2.sgml b/doc/src/sgml/xml2.sgml index a40172c36d..9bbc9e75d7 100644 --- a/doc/src/sgml/xml2.sgml +++ b/doc/src/sgml/xml2.sgml @@ -53,7 +53,7 @@ - xml_is_well_formed(document) + xml_valid(document) @@ -62,10 +62,10 @@ This parses the document text in its parameter and returns true if the - document is well-formed XML. (Note: before PostgreSQL 8.2, this - function was called xml_valid(). That is the wrong name - since validity and well-formedness have different meanings in XML. - The old name is still available, but is deprecated.) + document is well-formed XML. (Note: this is an alias for the standard + PostgreSQL function xml_is_well_formed(). The + name xml_valid() is technically incorrect since validity + and well-formedness have different meanings in XML.) diff --git a/src/Makefile b/src/Makefile index b526be7985..b490c07138 100644 --- a/src/Makefile +++ b/src/Makefile @@ -22,11 +22,13 @@ SUBDIRS = \ include \ interfaces \ backend/replication/libpqwalreceiver \ + backend/replication/pgoutput \ fe_utils \ bin \ pl \ makefiles \ - test/regress + test/regress \ + test/perl # There are too many interdependencies between the subdirectories, so # don't attempt parallel make here. diff --git a/src/Makefile.global.in b/src/Makefile.global.in index c211a2d2e7..59bd7996d1 100644 --- a/src/Makefile.global.in +++ b/src/Makefile.global.in @@ -197,6 +197,7 @@ enable_dtrace = @enable_dtrace@ enable_coverage = @enable_coverage@ enable_tap_tests = @enable_tap_tests@ enable_thread_safety = @enable_thread_safety@ +enable_strong_random = @enable_strong_random@ python_includespec = @python_includespec@ python_libdir = @python_libdir@ @@ -265,7 +266,6 @@ UUID_LIBS = @UUID_LIBS@ UUID_EXTRA_OBJS = @UUID_EXTRA_OBJS@ LD = @LD@ with_gnu_ld = @with_gnu_ld@ -ld_R_works = @ld_R_works@ # We want -L for libpgport.a and libpgcommon.a to be first in LDFLAGS. We # also need LDFLAGS to be a "recursively expanded" variable, else adjustments @@ -332,7 +332,9 @@ endif endif PROVE = @PROVE@ -PG_PROVE_FLAGS = -I $(top_srcdir)/src/test/perl/ +# There are common routines in src/test/perl, and some test suites have +# extra perl modules in their own directory. +PG_PROVE_FLAGS = -I $(top_srcdir)/src/test/perl/ -I $(srcdir) PROVE_FLAGS = --verbose # prepend to path if already set, else just set it @@ -342,7 +344,7 @@ endef # platform-specific environment variable to set shared library path define ld_library_path_var -$(if $(filter $(PORTNAME),darwin),DYLD_LIBRARY_PATH,$(if $(filter $(PORTNAME),aix),LIBPATH,LD_LIBRARY_PATH)) +$(if $(filter $(PORTNAME),darwin),DYLD_LIBRARY_PATH,$(if $(filter $(PORTNAME),aix),LIBPATH,$(if $(filter $(PORTNAME),hpux),SHLIB_PATH,LD_LIBRARY_PATH))) endef define with_temp_install @@ -353,12 +355,12 @@ ifeq ($(enable_tap_tests),yes) define prove_installcheck rm -rf $(CURDIR)/tmp_check/log -cd $(srcdir) && TESTDIR='$(CURDIR)' PATH="$(bindir):$$PATH" PGPORT='6$(DEF_PGPORT)' top_builddir='$(CURDIR)/$(top_builddir)' PG_REGRESS='$(CURDIR)/$(top_builddir)/src/test/regress/pg_regress' $(PROVE) $(PG_PROVE_FLAGS) $(PROVE_FLAGS) t/*.pl +cd $(srcdir) && TESTDIR='$(CURDIR)' PATH="$(bindir):$$PATH" PGPORT='6$(DEF_PGPORT)' top_builddir='$(CURDIR)/$(top_builddir)' PG_REGRESS='$(CURDIR)/$(top_builddir)/src/test/regress/pg_regress' $(PROVE) $(PG_PROVE_FLAGS) $(PROVE_FLAGS) $(if $(PROVE_TESTS),$(PROVE_TESTS),t/*.pl) endef define prove_check rm -rf $(CURDIR)/tmp_check/log -cd $(srcdir) && TESTDIR='$(CURDIR)' $(with_temp_install) PGPORT='6$(DEF_PGPORT)' PG_REGRESS='$(CURDIR)/$(top_builddir)/src/test/regress/pg_regress' $(PROVE) $(PG_PROVE_FLAGS) $(PROVE_FLAGS) t/*.pl +cd $(srcdir) && TESTDIR='$(CURDIR)' $(with_temp_install) PGPORT='6$(DEF_PGPORT)' PG_REGRESS='$(CURDIR)/$(top_builddir)/src/test/regress/pg_regress' $(PROVE) $(PG_PROVE_FLAGS) $(PROVE_FLAGS) $(if $(PROVE_TESTS),$(PROVE_TESTS),t/*.pl) endef else diff --git a/src/Makefile.shlib b/src/Makefile.shlib index 924d21f443..c293a34d1a 100644 --- a/src/Makefile.shlib +++ b/src/Makefile.shlib @@ -47,9 +47,8 @@ # clean-lib delete the static and shared libraries from the build dir # maintainer-clean-lib delete .def files built for win32 # -# Since `all-lib' is the first rule in this file you probably want to -# have the `all' target before including this file. In the most simple -# case it would look like this: +# Typically you would add `all-lib' to the `all' target so that `make all' +# builds the libraries. In the most simple case it would look like this: # # all: all-lib # @@ -128,7 +127,7 @@ ifeq ($(PORTNAME), darwin) else # loadable module DLSUFFIX = .so - LINK.shared = $(COMPILER) -bundle -multiply_defined suppress -Wl,-undefined,dynamic_lookup + LINK.shared = $(COMPILER) -bundle -multiply_defined suppress endif BUILD.exports = $(AWK) '/^[^\#]/ {printf "_%s\n",$$1}' $< >$@ exports_file = $(SHLIB_EXPORTS:%.txt=%.list) @@ -194,7 +193,7 @@ ifeq ($(PORTNAME), hpux) # can't use the CC-syntax rpath pattern here, so instead: rpath = ifeq ($(enable_rpath), yes) - LINK.shared += +b '$(rpathdir)' + LINK.shared += +s +b '$(rpathdir)' endif # On HPUX platforms, gcc is usually configured to search for libraries # in /usr/local/lib, but ld won't do so. Add an explicit -L switch so @@ -237,30 +236,6 @@ ifeq ($(PORTNAME), solaris) endif endif -ifeq ($(PORTNAME), sco) - ifeq ($(GCC), yes) - LINK.shared = $(CC) -shared - else - LINK.shared = $(CC) -G - endif - LINK.shared += -Wl,-z,text - ifdef soname - LINK.shared += -Wl,-h,$(soname) - endif -endif - -ifeq ($(PORTNAME), unixware) - ifeq ($(GCC), yes) - LINK.shared = $(CC) -shared - else - LINK.shared = $(CC) -G - endif - LINK.shared += -Wl,-z,text - ifdef soname - LINK.shared += -Wl,-h,$(soname) - endif -endif - ifeq ($(PORTNAME), cygwin) LINK.shared = $(CC) -shared ifdef SO_MAJOR_VERSION @@ -323,7 +298,7 @@ endif endif # shlib_major # Where possible, restrict the symbols exported by the library to just the -# official list, so as to avoid unintentional ABI changes. On recent Darwin +# official list, so as to avoid unintentional ABI changes. On recent macOS # this also quiets multiply-defined-symbol warnings in programs that use # libpgport along with libpq. ifneq (,$(SHLIB_EXPORTS)) diff --git a/src/backend/Makefile b/src/backend/Makefile index 3b08defe2b..82975f514a 100644 --- a/src/backend/Makefile +++ b/src/backend/Makefile @@ -2,7 +2,7 @@ # # Makefile for the postgres backend # -# Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/backend/Makefile @@ -26,8 +26,8 @@ include $(srcdir)/common.mk # As of 1/2010: # The probes.o file is necessary for dtrace support on Solaris, and on recent # versions of systemtap. (Older systemtap releases just produce an empty -# file, but that's okay.) However, OS X's dtrace doesn't use it and doesn't -# even recognize the -G option. So, build probes.o except on Darwin. +# file, but that's okay.) However, macOS's dtrace doesn't use it and doesn't +# even recognize the -G option. So, build probes.o except on macOS. # This might need adjustment as other platforms add dtrace support. ifneq ($(PORTNAME), darwin) ifeq ($(enable_dtrace), yes) @@ -139,8 +139,8 @@ storage/lmgr/lwlocknames.h: storage/lmgr/generate-lwlocknames.pl storage/lmgr/lw utils/errcodes.h: utils/generate-errcodes.pl utils/errcodes.txt $(MAKE) -C utils errcodes.h -utils/fmgroids.h: utils/Gen_fmgrtab.pl catalog/Catalog.pm $(top_srcdir)/src/include/catalog/pg_proc.h - $(MAKE) -C utils fmgroids.h +utils/fmgroids.h utils/fmgrprotos.h: utils/Gen_fmgrtab.pl catalog/Catalog.pm $(top_srcdir)/src/include/catalog/pg_proc.h + $(MAKE) -C utils $(notdir $@) utils/probes.h: utils/probes.d $(MAKE) -C utils probes.h @@ -166,7 +166,7 @@ submake-schemapg: .PHONY: generated-headers -generated-headers: $(top_builddir)/src/include/parser/gram.h $(top_builddir)/src/include/catalog/schemapg.h $(top_builddir)/src/include/storage/lwlocknames.h $(top_builddir)/src/include/utils/errcodes.h $(top_builddir)/src/include/utils/fmgroids.h $(top_builddir)/src/include/utils/probes.h +generated-headers: $(top_builddir)/src/include/parser/gram.h $(top_builddir)/src/include/catalog/schemapg.h $(top_builddir)/src/include/storage/lwlocknames.h $(top_builddir)/src/include/utils/errcodes.h $(top_builddir)/src/include/utils/fmgroids.h $(top_builddir)/src/include/utils/fmgrprotos.h $(top_builddir)/src/include/utils/probes.h $(top_builddir)/src/include/parser/gram.h: parser/gram.h prereqdir=`cd '$(dir $<)' >/dev/null && pwd` && \ @@ -193,6 +193,11 @@ $(top_builddir)/src/include/utils/fmgroids.h: utils/fmgroids.h cd '$(dir $@)' && rm -f $(notdir $@) && \ $(LN_S) "$$prereqdir/$(notdir $<)" . +$(top_builddir)/src/include/utils/fmgrprotos.h: utils/fmgrprotos.h + prereqdir=`cd '$(dir $<)' >/dev/null && pwd` && \ + cd '$(dir $@)' && rm -f $(notdir $@) && \ + $(LN_S) "$$prereqdir/$(notdir $<)" . + $(top_builddir)/src/include/utils/probes.h: utils/probes.h cd '$(dir $@)' && rm -f $(notdir $@) && \ $(LN_S) "../../../$(subdir)/utils/probes.h" . @@ -211,7 +216,7 @@ distprep: $(MAKE) -C catalog schemapg.h postgres.bki postgres.description postgres.shdescription $(MAKE) -C replication repl_gram.c repl_scanner.c syncrep_gram.c syncrep_scanner.c $(MAKE) -C storage/lmgr lwlocknames.h - $(MAKE) -C utils fmgrtab.c fmgroids.h errcodes.h + $(MAKE) -C utils fmgrtab.c fmgroids.h fmgrprotos.h errcodes.h $(MAKE) -C utils/misc guc-file.c $(MAKE) -C utils/sort qsort_tuple.c @@ -291,7 +296,7 @@ endif $(MAKE) -C tsearch uninstall-data rm -f '$(DESTDIR)$(datadir)/pg_hba.conf.sample' \ '$(DESTDIR)$(datadir)/pg_ident.conf.sample' \ - '$(DESTDIR)$(datadir)/postgresql.conf.sample' \ + '$(DESTDIR)$(datadir)/postgresql.conf.sample' \ '$(DESTDIR)$(datadir)/recovery.conf.sample' @@ -303,6 +308,7 @@ clean: $(top_builddir)/src/include/catalog/schemapg.h \ $(top_builddir)/src/include/storage/lwlocknames.h \ $(top_builddir)/src/include/utils/fmgroids.h \ + $(top_builddir)/src/include/utils/fmgrprotos.h \ $(top_builddir)/src/include/utils/probes.h ifeq ($(PORTNAME), cygwin) rm -f postgres.dll libpostgres.a @@ -331,6 +337,7 @@ maintainer-clean: distclean storage/lmgr/lwlocknames.c \ storage/lmgr/lwlocknames.h \ utils/fmgroids.h \ + utils/fmgrprotos.h \ utils/fmgrtab.c \ utils/errcodes.h \ utils/misc/guc-file.c \ diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index b194d33cc5..d60ddd242c 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -4,7 +4,7 @@ * * See src/backend/access/brin/README for details. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -28,6 +28,7 @@ #include "pgstat.h" #include "storage/bufmgr.h" #include "storage/freespace.h" +#include "utils/builtins.h" #include "utils/index_selfuncs.h" #include "utils/memutils.h" #include "utils/rel.h" @@ -165,9 +166,7 @@ brininsert(Relation idxRel, Datum *values, bool *nulls, bdesc = brin_build_desc(idxRel); tupcxt = AllocSetContextCreate(CurrentMemoryContext, "brininsert cxt", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldcxt = MemoryContextSwitchTo(tupcxt); } @@ -347,9 +346,7 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) */ perRangeCxt = AllocSetContextCreate(CurrentMemoryContext, "bringetbitmap cxt", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldcxt = MemoryContextSwitchTo(perRangeCxt); /* @@ -856,9 +853,7 @@ brin_build_desc(Relation rel) cxt = AllocSetContextCreate(CurrentMemoryContext, "brin desc cxt", - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_MAXSIZE); + ALLOCSET_SMALL_SIZES); oldcxt = MemoryContextSwitchTo(cxt); tupdesc = RelationGetDescr(rel); @@ -1169,9 +1164,7 @@ union_tuples(BrinDesc *bdesc, BrinMemTuple *a, BrinTuple *b) /* Use our own memory context to avoid retail pfree */ cxt = AllocSetContextCreate(CurrentMemoryContext, "brin union", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldcxt = MemoryContextSwitchTo(cxt); db = brin_deform_tuple(bdesc, b); MemoryContextSwitchTo(oldcxt); diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 0ae7a72996..bc16dd7981 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -16,7 +16,7 @@ * writing is the INET type, where IPv6 values cannot be merged with IPv4 * values. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -30,6 +30,7 @@ #include "access/skey.h" #include "catalog/pg_amop.h" #include "catalog/pg_type.h" +#include "utils/builtins.h" #include "utils/datum.h" #include "utils/lsyscache.h" #include "utils/rel.h" @@ -76,10 +77,6 @@ typedef struct InclusionOpaque FmgrInfo strategy_procinfos[RTMaxStrategyNumber]; } InclusionOpaque; -Datum brin_inclusion_opcinfo(PG_FUNCTION_ARGS); -Datum brin_inclusion_add_value(PG_FUNCTION_ARGS); -Datum brin_inclusion_consistent(PG_FUNCTION_ARGS); -Datum brin_inclusion_union(PG_FUNCTION_ARGS); static FmgrInfo *inclusion_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum); static FmgrInfo *inclusion_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno, @@ -431,7 +428,7 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) * It is straightforward to support the equality strategies with * the contains operator. Generally, inequality strategies do not * make much sense for the types which will be used with the - * inclusion BRIN family of opclasses, but is is possible to + * inclusion BRIN family of opclasses, but is possible to * implement them with logical negation of the left-of and * right-of operators. * diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index b7c76e6eda..8f7a0c75b8 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -2,7 +2,7 @@ * brin_minmax.c * Implementation of Min/Max opclass for BRIN * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -16,6 +16,7 @@ #include "access/stratnum.h" #include "catalog/pg_type.h" #include "catalog/pg_amop.h" +#include "utils/builtins.h" #include "utils/datum.h" #include "utils/lsyscache.h" #include "utils/rel.h" @@ -28,10 +29,6 @@ typedef struct MinmaxOpaque FmgrInfo strategy_procinfos[BTMaxStrategyNumber]; } MinmaxOpaque; -Datum brin_minmax_opcinfo(PG_FUNCTION_ARGS); -Datum brin_minmax_add_value(PG_FUNCTION_ARGS); -Datum brin_minmax_consistent(PG_FUNCTION_ARGS); -Datum brin_minmax_union(PG_FUNCTION_ARGS); static FmgrInfo *minmax_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno, Oid subtype, uint16 strategynum); diff --git a/src/backend/access/brin/brin_pageops.c b/src/backend/access/brin/brin_pageops.c index 6ebfedd6a9..da94efc61c 100644 --- a/src/backend/access/brin/brin_pageops.c +++ b/src/backend/access/brin/brin_pageops.c @@ -2,7 +2,7 @@ * brin_pageops.c * Page-handling routines for BRIN indexes * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -178,10 +178,8 @@ brin_doupdate(Relation idxrel, BlockNumber pagesPerRange, } START_CRIT_SECTION(); - PageIndexDeleteNoCompact(oldpage, &oldoff, 1); - if (PageAddItemExtended(oldpage, (Item) newtup, newsz, oldoff, - PAI_OVERWRITE | PAI_ALLOW_FAR_OFFSET) == InvalidOffsetNumber) - elog(ERROR, "failed to add BRIN tuple"); + if (!PageIndexTupleOverwrite(oldpage, oldoff, (Item) newtup, newsz)) + elog(ERROR, "failed to replace BRIN tuple"); MarkBufferDirty(oldbuf); /* XLOG stuff */ @@ -247,7 +245,7 @@ brin_doupdate(Relation idxrel, BlockNumber pagesPerRange, if (extended) brin_page_init(BufferGetPage(newbuf), BRIN_PAGETYPE_REGULAR); - PageIndexDeleteNoCompact(oldpage, &oldoff, 1); + PageIndexTupleDeleteNoCompact(oldpage, oldoff); newoff = PageAddItem(newpage, (Item) newtup, newsz, InvalidOffsetNumber, false, false); if (newoff == InvalidOffsetNumber) @@ -289,7 +287,7 @@ brin_doupdate(Relation idxrel, BlockNumber pagesPerRange, XLogRegisterBufData(0, (char *) newtup, newsz); /* revmap page */ - XLogRegisterBuffer(1, revmapbuf, REGBUF_STANDARD); + XLogRegisterBuffer(1, revmapbuf, 0); /* old page */ XLogRegisterBuffer(2, oldbuf, REGBUF_STANDARD); diff --git a/src/backend/access/brin/brin_revmap.c b/src/backend/access/brin/brin_revmap.c index 853181b3fa..0de6999c2b 100644 --- a/src/backend/access/brin/brin_revmap.c +++ b/src/backend/access/brin/brin_revmap.c @@ -12,7 +12,7 @@ * the metapage. When the revmap needs to be expanded, all tuples on the * regular BRIN page at that block (if any) are moved out of the way. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/brin/brin_tuple.c b/src/backend/access/brin/brin_tuple.c index 64b8264959..ec5fc5660f 100644 --- a/src/backend/access/brin/brin_tuple.c +++ b/src/backend/access/brin/brin_tuple.c @@ -23,7 +23,7 @@ * Note the size of the null bitmask may not be the same as that of the * datum array. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -367,9 +367,7 @@ brin_new_memtuple(BrinDesc *brdesc) dtup->bt_context = AllocSetContextCreate(CurrentMemoryContext, "brin dtuple", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); return dtup; } diff --git a/src/backend/access/brin/brin_validate.c b/src/backend/access/brin/brin_validate.c index 1f1011e0ac..dc23e00e89 100644 --- a/src/backend/access/brin/brin_validate.c +++ b/src/backend/access/brin/brin_validate.c @@ -3,7 +3,7 @@ * brin_validate.c * Opclass validator for BRIN. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -23,6 +23,7 @@ #include "catalog/pg_type.h" #include "utils/builtins.h" #include "utils/syscache.h" +#include "utils/regproc.h" /* diff --git a/src/backend/access/brin/brin_xlog.c b/src/backend/access/brin/brin_xlog.c index 27ba0a97f8..b698c9b58c 100644 --- a/src/backend/access/brin/brin_xlog.c +++ b/src/backend/access/brin/brin_xlog.c @@ -2,7 +2,7 @@ * brin_xlog.c * XLog replay routines for BRIN indexes * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -148,10 +148,8 @@ brin_xlog_update(XLogReaderState *record) page = (Page) BufferGetPage(buffer); offnum = xlrec->oldOffnum; - if (PageGetMaxOffsetNumber(page) + 1 < offnum) - elog(PANIC, "brin_xlog_update: invalid max offset number"); - PageIndexDeleteNoCompact(page, &offnum, 1); + PageIndexTupleDeleteNoCompact(page, offnum); PageSetLSN(page, lsn); MarkBufferDirty(buffer); @@ -189,14 +187,9 @@ brin_xlog_samepage_update(XLogReaderState *record) page = (Page) BufferGetPage(buffer); offnum = xlrec->offnum; - if (PageGetMaxOffsetNumber(page) + 1 < offnum) - elog(PANIC, "brin_xlog_samepage_update: invalid max offset number"); - PageIndexDeleteNoCompact(page, &offnum, 1); - offnum = PageAddItemExtended(page, (Item) brintuple, tuplen, offnum, - PAI_OVERWRITE | PAI_ALLOW_FAR_OFFSET); - if (offnum == InvalidOffsetNumber) - elog(PANIC, "brin_xlog_samepage_update: failed to add tuple"); + if (!PageIndexTupleOverwrite(page, offnum, (Item) brintuple, tuplen)) + elog(PANIC, "brin_xlog_samepage_update: failed to replace tuple"); PageSetLSN(page, lsn); MarkBufferDirty(buffer); diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c index 6d0f3f3767..7e5f63d2cb 100644 --- a/src/backend/access/common/heaptuple.c +++ b/src/backend/access/common/heaptuple.c @@ -45,7 +45,7 @@ * and we'd like to still refer to them via C struct offsets. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -741,7 +741,9 @@ heap_form_tuple(TupleDesc tupleDescriptor, * Allocate and zero the space needed. Note that the tuple body and * HeapTupleData management structure are allocated in one chunk. */ - tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len); + tuple = MemoryContextAllocExtended(CurrentMemoryContext, + HEAPTUPLESIZE + len, + MCXT_ALLOC_HUGE | MCXT_ALLOC_ZERO); tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE); /* @@ -846,6 +848,72 @@ heap_modify_tuple(HeapTuple tuple, return newTuple; } +/* + * heap_modify_tuple_by_cols + * form a new tuple from an old tuple and a set of replacement values. + * + * This is like heap_modify_tuple, except that instead of specifying which + * column(s) to replace by a boolean map, an array of target column numbers + * is used. This is often more convenient when a fixed number of columns + * are to be replaced. The replCols, replValues, and replIsnull arrays must + * be of length nCols. Target column numbers are indexed from 1. + * + * The result is allocated in the current memory context. + */ +HeapTuple +heap_modify_tuple_by_cols(HeapTuple tuple, + TupleDesc tupleDesc, + int nCols, + int *replCols, + Datum *replValues, + bool *replIsnull) +{ + int numberOfAttributes = tupleDesc->natts; + Datum *values; + bool *isnull; + HeapTuple newTuple; + int i; + + /* + * allocate and fill values and isnull arrays from the tuple, then replace + * selected columns from the input arrays. + */ + values = (Datum *) palloc(numberOfAttributes * sizeof(Datum)); + isnull = (bool *) palloc(numberOfAttributes * sizeof(bool)); + + heap_deform_tuple(tuple, tupleDesc, values, isnull); + + for (i = 0; i < nCols; i++) + { + int attnum = replCols[i]; + + if (attnum <= 0 || attnum > numberOfAttributes) + elog(ERROR, "invalid column number %d", attnum); + values[attnum - 1] = replValues[i]; + isnull[attnum - 1] = replIsnull[i]; + } + + /* + * create a new tuple from the values and isnull arrays + */ + newTuple = heap_form_tuple(tupleDesc, values, isnull); + + pfree(values); + pfree(isnull); + + /* + * copy the identification info of the old tuple: t_ctid, t_self, and OID + * (if any) + */ + newTuple->t_data->t_ctid = tuple->t_data->t_ctid; + newTuple->t_self = tuple->t_self; + newTuple->t_tableOid = tuple->t_tableOid; + if (tupleDesc->tdhasoid) + HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple)); + + return newTuple; +} + /* * heap_deform_tuple * Given a tuple, extract data into values/isnull arrays; this is diff --git a/src/backend/access/common/indextuple.c b/src/backend/access/common/indextuple.c index 274a6c2e70..2846ec8b34 100644 --- a/src/backend/access/common/indextuple.c +++ b/src/backend/access/common/indextuple.c @@ -4,7 +4,7 @@ * This file contains index tuple accessor and mutator routines, * as well as various tuple utilities. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c index d9664aa6c6..b481348a91 100644 --- a/src/backend/access/common/printtup.c +++ b/src/backend/access/common/printtup.c @@ -5,7 +5,7 @@ * clients and standalone backends are supported here). * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -135,9 +135,7 @@ printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo) */ myState->tmpcontext = AllocSetContextCreate(CurrentMemoryContext, "printtup", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3) { @@ -231,9 +229,7 @@ SendRowDescriptionMessage(TupleDesc typeinfo, List *targetlist, int16 *formats) atttypid = getBaseTypeAndTypmod(atttypid, &atttypmod); pq_sendint(&buf, (int) atttypid, sizeof(atttypid)); pq_sendint(&buf, attrs[i]->attlen, sizeof(attrs[i]->attlen)); - /* typmod appears in protocol 2.0 and up */ - if (proto >= 2) - pq_sendint(&buf, atttypmod, sizeof(atttypmod)); + pq_sendint(&buf, atttypmod, sizeof(atttypmod)); /* format info appears in protocol 3.0 and up */ if (proto >= 3) { @@ -561,6 +557,50 @@ debugtup(TupleTableSlot *slot, DestReceiver *self) return true; } +void +logStartup(DestReceiver *self, int operation, TupleDesc typeinfo) +{ + int natts = typeinfo->natts; + Form_pg_attribute *attinfo = typeinfo->attrs; + int i; + + /* + * show the return type of the tuples + */ + printf("\t---- Result Attributes ----\n"); + for (i = 0; i < natts; ++i) + printf("%s\t|\t", NameStr(attinfo[i]->attname)); + printf("\n"); +} + +bool +logtup(TupleTableSlot *slot, DestReceiver *self) +{ + TupleDesc typeinfo = slot->tts_tupleDescriptor; + int natts = typeinfo->natts; + int i; + Datum attr; + char *value; + bool isnull; + Oid typoutput; + bool typisvarlena; + + for (i = 0; i < natts; ++i) + { + attr = slot_getattr(slot, i + 1, &isnull); + if (isnull) + continue; + getTypeOutputInfo(typeinfo->attrs[i]->atttypid, + &typoutput, &typisvarlena); + + value = OidOutputFunctionCall(typoutput, attr); + printf("%s\t|\t", value); + } + printf("\n"); + + return true; +} + /* ---------------- * printtup_internal_20 --- print a binary tuple in protocol 2.0 * diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index ba1f3aafed..816483ef8b 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -3,7 +3,7 @@ * reloptions.c * Core support for relation options (pg_class.reloptions) * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -888,7 +888,7 @@ untransformRelOptions(Datum options) *p++ = '\0'; val = (Node *) makeString(pstrdup(p)); } - result = lappend(result, makeDefElem(pstrdup(s), val)); + result = lappend(result, makeDefElem(pstrdup(s), val, -1)); } return result; @@ -930,6 +930,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, case RELKIND_RELATION: case RELKIND_TOASTVALUE: case RELKIND_MATVIEW: + case RELKIND_PARTITIONED_TABLE: options = heap_reloptions(classForm->relkind, datum, false); break; case RELKIND_VIEW: @@ -1381,6 +1382,7 @@ heap_reloptions(char relkind, Datum reloptions, bool validate) return (bytea *) rdopts; case RELKIND_RELATION: case RELKIND_MATVIEW: + case RELKIND_PARTITIONED_TABLE: return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP); default: /* other relkinds are not supported */ diff --git a/src/backend/access/common/scankey.c b/src/backend/access/common/scankey.c index 35391c2c60..13edca1f94 100644 --- a/src/backend/access/common/scankey.c +++ b/src/backend/access/common/scankey.c @@ -3,7 +3,7 @@ * scankey.c * scan key support code * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/common/tupconvert.c b/src/backend/access/common/tupconvert.c index 4787d4ca98..b17ceafa6e 100644 --- a/src/backend/access/common/tupconvert.c +++ b/src/backend/access/common/tupconvert.c @@ -9,7 +9,7 @@ * executor's "junkfilter" routines, but these functions work on bare * HeapTuples rather than TupleTableSlots. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -206,55 +206,12 @@ convert_tuples_by_name(TupleDesc indesc, { TupleConversionMap *map; AttrNumber *attrMap; - int n; + int n = outdesc->natts; int i; bool same; /* Verify compatibility and prepare attribute-number map */ - n = outdesc->natts; - attrMap = (AttrNumber *) palloc0(n * sizeof(AttrNumber)); - for (i = 0; i < n; i++) - { - Form_pg_attribute att = outdesc->attrs[i]; - char *attname; - Oid atttypid; - int32 atttypmod; - int j; - - if (att->attisdropped) - continue; /* attrMap[i] is already 0 */ - attname = NameStr(att->attname); - atttypid = att->atttypid; - atttypmod = att->atttypmod; - for (j = 0; j < indesc->natts; j++) - { - att = indesc->attrs[j]; - if (att->attisdropped) - continue; - if (strcmp(attname, NameStr(att->attname)) == 0) - { - /* Found it, check type */ - if (atttypid != att->atttypid || atttypmod != att->atttypmod) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg_internal("%s", _(msg)), - errdetail("Attribute \"%s\" of type %s does not match corresponding attribute of type %s.", - attname, - format_type_be(outdesc->tdtypeid), - format_type_be(indesc->tdtypeid)))); - attrMap[i] = (AttrNumber) (j + 1); - break; - } - } - if (attrMap[i] == 0) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg_internal("%s", _(msg)), - errdetail("Attribute \"%s\" of type %s does not exist in type %s.", - attname, - format_type_be(outdesc->tdtypeid), - format_type_be(indesc->tdtypeid)))); - } + attrMap = convert_tuples_by_name_map(indesc, outdesc, msg); /* * Check to see if the map is one-to-one and the tuple types are the same. @@ -312,6 +269,69 @@ convert_tuples_by_name(TupleDesc indesc, return map; } +/* + * Return a palloc'd bare attribute map for tuple conversion, matching input + * and output columns by name. (Dropped columns are ignored in both input and + * output.) This is normally a subroutine for convert_tuples_by_name, but can + * be used standalone. + */ +AttrNumber * +convert_tuples_by_name_map(TupleDesc indesc, + TupleDesc outdesc, + const char *msg) +{ + AttrNumber *attrMap; + int n; + int i; + + n = outdesc->natts; + attrMap = (AttrNumber *) palloc0(n * sizeof(AttrNumber)); + for (i = 0; i < n; i++) + { + Form_pg_attribute att = outdesc->attrs[i]; + char *attname; + Oid atttypid; + int32 atttypmod; + int j; + + if (att->attisdropped) + continue; /* attrMap[i] is already 0 */ + attname = NameStr(att->attname); + atttypid = att->atttypid; + atttypmod = att->atttypmod; + for (j = 0; j < indesc->natts; j++) + { + att = indesc->attrs[j]; + if (att->attisdropped) + continue; + if (strcmp(attname, NameStr(att->attname)) == 0) + { + /* Found it, check type */ + if (atttypid != att->atttypid || atttypmod != att->atttypmod) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg_internal("%s", _(msg)), + errdetail("Attribute \"%s\" of type %s does not match corresponding attribute of type %s.", + attname, + format_type_be(outdesc->tdtypeid), + format_type_be(indesc->tdtypeid)))); + attrMap[i] = (AttrNumber) (j + 1); + break; + } + } + if (attrMap[i] == 0) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg_internal("%s", _(msg)), + errdetail("Attribute \"%s\" of type %s does not exist in type %s.", + attname, + format_type_be(outdesc->tdtypeid), + format_type_be(indesc->tdtypeid)))); + } + + return attrMap; +} + /* * Perform conversion of a tuple according to the map. */ diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c index b56d0e336f..54a32c0223 100644 --- a/src/backend/access/common/tupdesc.c +++ b/src/backend/access/common/tupdesc.c @@ -3,7 +3,7 @@ * tupdesc.c * POSTGRES tuple descriptor support code * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/gin/ginarrayproc.c b/src/backend/access/gin/ginarrayproc.c index aaf72a3f9e..cc7435e030 100644 --- a/src/backend/access/gin/ginarrayproc.c +++ b/src/backend/access/gin/ginarrayproc.c @@ -4,7 +4,7 @@ * support functions for GIN's indexing of any array * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gin/ginbtree.c b/src/backend/access/gin/ginbtree.c index fa383719e6..e5e83b9331 100644 --- a/src/backend/access/gin/ginbtree.c +++ b/src/backend/access/gin/ginbtree.c @@ -4,7 +4,7 @@ * page utilities routines for the postgres inverted index access method. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -348,9 +348,7 @@ ginPlaceToPage(GinBtree btree, GinBtreeStack *stack, */ tmpCxt = AllocSetContextCreate(CurrentMemoryContext, "ginPlaceToPage temporary context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldCxt = MemoryContextSwitchTo(tmpCxt); if (GinPageIsData(page)) diff --git a/src/backend/access/gin/ginbulk.c b/src/backend/access/gin/ginbulk.c index d6422ea91e..f07c76b90b 100644 --- a/src/backend/access/gin/ginbulk.c +++ b/src/backend/access/gin/ginbulk.c @@ -4,7 +4,7 @@ * routines for fast build of inverted index * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -255,7 +255,7 @@ qsortCompareItemPointers(const void *a, const void *b) void ginBeginBAScan(BuildAccumulator *accum) { - rb_begin_iterate(accum->tree, LeftRightWalk); + rb_begin_iterate(accum->tree, LeftRightWalk, &accum->tree_walk); } /* @@ -271,7 +271,7 @@ ginGetBAEntry(BuildAccumulator *accum, GinEntryAccumulator *entry; ItemPointerData *list; - entry = (GinEntryAccumulator *) rb_iterate(accum->tree); + entry = (GinEntryAccumulator *) rb_iterate(&accum->tree_walk); if (entry == NULL) return NULL; /* no more entries */ diff --git a/src/backend/access/gin/gindatapage.c b/src/backend/access/gin/gindatapage.c index 97c8bf78e7..3ede711351 100644 --- a/src/backend/access/gin/gindatapage.c +++ b/src/backend/access/gin/gindatapage.c @@ -4,7 +4,7 @@ * routines for handling GIN posting tree pages. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -86,7 +86,7 @@ typedef struct char action; ItemPointerData *modifieditems; - int nmodifieditems; + uint16 nmodifieditems; /* * The following fields represent the items in this segment. If 'items' is diff --git a/src/backend/access/gin/ginentrypage.c b/src/backend/access/gin/ginentrypage.c index 8c0bfe9fde..446be55f69 100644 --- a/src/backend/access/gin/ginentrypage.c +++ b/src/backend/access/gin/ginentrypage.c @@ -4,7 +4,7 @@ * routines for handling GIN entry tree pages. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gin/ginfast.c b/src/backend/access/gin/ginfast.c index 59a63f28d0..85031e2921 100644 --- a/src/backend/access/gin/ginfast.c +++ b/src/backend/access/gin/ginfast.c @@ -7,7 +7,7 @@ * transfer pending entries into the regular index structure. This * wins because bulk insertion is much more efficient than retail. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -30,6 +30,7 @@ #include "postmaster/autovacuum.h" #include "storage/indexfsm.h" #include "storage/lmgr.h" +#include "utils/builtins.h" /* GUC parameter */ int gin_pending_list_limit = 0; @@ -808,9 +809,7 @@ ginInsertCleanup(GinState *ginstate, bool full_clean, */ opCtx = AllocSetContextCreate(CurrentMemoryContext, "GIN insert cleanup temporary context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldCtx = MemoryContextSwitchTo(opCtx); diff --git a/src/backend/access/gin/ginget.c b/src/backend/access/gin/ginget.c index 9ed9fd2dc5..60f005ce2b 100644 --- a/src/backend/access/gin/ginget.c +++ b/src/backend/access/gin/ginget.c @@ -4,7 +4,7 @@ * fetch tuples from a GIN scan. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c index 9f784bf48d..03a7235a0a 100644 --- a/src/backend/access/gin/gininsert.c +++ b/src/backend/access/gin/gininsert.c @@ -4,7 +4,7 @@ * insert routines for the postgres inverted index access method. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -372,9 +372,7 @@ ginbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ buildstate.tmpCtx = AllocSetContextCreate(CurrentMemoryContext, "Gin build temporary context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* * create a temporary memory context that is used for calling @@ -382,9 +380,7 @@ ginbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ buildstate.funcCtx = AllocSetContextCreate(CurrentMemoryContext, "Gin build temporary context for user-defined function", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); buildstate.accum.ginstate = &buildstate.ginstate; ginInitBA(&buildstate.accum); @@ -495,9 +491,7 @@ gininsert(Relation index, Datum *values, bool *isnull, insertCtx = AllocSetContextCreate(CurrentMemoryContext, "Gin insert temporary context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldCtx = MemoryContextSwitchTo(insertCtx); diff --git a/src/backend/access/gin/ginlogic.c b/src/backend/access/gin/ginlogic.c index d3e84eee97..a940a9374a 100644 --- a/src/backend/access/gin/ginlogic.c +++ b/src/backend/access/gin/ginlogic.c @@ -24,7 +24,7 @@ * is used for.) * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gin/ginpostinglist.c b/src/backend/access/gin/ginpostinglist.c index 54d5f6f630..598069d06f 100644 --- a/src/backend/access/gin/ginpostinglist.c +++ b/src/backend/access/gin/ginpostinglist.c @@ -4,7 +4,7 @@ * routines for dealing with posting lists. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gin/ginscan.c b/src/backend/access/gin/ginscan.c index c449c1cbc0..c3ce0479c5 100644 --- a/src/backend/access/gin/ginscan.c +++ b/src/backend/access/gin/ginscan.c @@ -4,7 +4,7 @@ * routines to manage scans of inverted index relations * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -38,14 +38,10 @@ ginbeginscan(Relation rel, int nkeys, int norderbys) so->nkeys = 0; so->tempCtx = AllocSetContextCreate(CurrentMemoryContext, "Gin scan temporary context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); so->keyCtx = AllocSetContextCreate(CurrentMemoryContext, "Gin scan key context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); initGinState(&so->ginstate, scan->indexRelation); scan->opaque = so; diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c index d9146488c4..3909638906 100644 --- a/src/backend/access/gin/ginutil.c +++ b/src/backend/access/gin/ginutil.c @@ -4,7 +4,7 @@ * Utility routines for the Postgres inverted index access method. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -22,7 +22,9 @@ #include "miscadmin.h" #include "storage/indexfsm.h" #include "storage/lmgr.h" +#include "utils/builtins.h" #include "utils/index_selfuncs.h" +#include "utils/typcache.h" /* @@ -105,9 +107,33 @@ initGinState(GinState *state, Relation index) origTupdesc->attrs[i]->attcollation); } - fmgr_info_copy(&(state->compareFn[i]), - index_getprocinfo(index, i + 1, GIN_COMPARE_PROC), - CurrentMemoryContext); + /* + * If the compare proc isn't specified in the opclass definition, look + * up the index key type's default btree comparator. + */ + if (index_getprocid(index, i + 1, GIN_COMPARE_PROC) != InvalidOid) + { + fmgr_info_copy(&(state->compareFn[i]), + index_getprocinfo(index, i + 1, GIN_COMPARE_PROC), + CurrentMemoryContext); + } + else + { + TypeCacheEntry *typentry; + + typentry = lookup_type_cache(origTupdesc->attrs[i]->atttypid, + TYPECACHE_CMP_PROC_FINFO); + if (!OidIsValid(typentry->cmp_proc_finfo.fn_oid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("could not identify a comparison function for type %s", + format_type_be(origTupdesc->attrs[i]->atttypid)))); + fmgr_info_copy(&(state->compareFn[i]), + &(typentry->cmp_proc_finfo), + CurrentMemoryContext); + } + + /* Opclass must always provide extract procs */ fmgr_info_copy(&(state->extractValueFn[i]), index_getprocinfo(index, i + 1, GIN_EXTRACTVALUE_PROC), CurrentMemoryContext); diff --git a/src/backend/access/gin/ginvacuum.c b/src/backend/access/gin/ginvacuum.c index c258478f23..ddd168bcc6 100644 --- a/src/backend/access/gin/ginvacuum.c +++ b/src/backend/access/gin/ginvacuum.c @@ -4,7 +4,7 @@ * delete & vacuum routines for the postgres GIN * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -526,9 +526,7 @@ ginbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, gvs.tmpCxt = AllocSetContextCreate(CurrentMemoryContext, "Gin vacuum temporary context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); gvs.index = index; gvs.callback = callback; gvs.callback_state = callback_state; diff --git a/src/backend/access/gin/ginvalidate.c b/src/backend/access/gin/ginvalidate.c index 032508387d..0d2847456e 100644 --- a/src/backend/access/gin/ginvalidate.c +++ b/src/backend/access/gin/ginvalidate.c @@ -3,7 +3,7 @@ * ginvalidate.c * Opclass validator for GIN. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -24,6 +24,7 @@ #include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/syscache.h" +#include "utils/regproc.h" /* @@ -237,7 +238,7 @@ ginvalidate(Oid opclassoid) if (opclassgroup && (opclassgroup->functionset & (((uint64) 1) << i)) != 0) continue; /* got it */ - if (i == GIN_COMPARE_PARTIAL_PROC) + if (i == GIN_COMPARE_PROC || i == GIN_COMPARE_PARTIAL_PROC) continue; /* optional method */ if (i == GIN_CONSISTENT_PROC || i == GIN_TRICONSISTENT_PROC) continue; /* don't need both, see check below loop */ diff --git a/src/backend/access/gin/ginxlog.c b/src/backend/access/gin/ginxlog.c index b4d310f337..8468fe825c 100644 --- a/src/backend/access/gin/ginxlog.c +++ b/src/backend/access/gin/ginxlog.c @@ -4,7 +4,7 @@ * WAL replay logic for inverted index. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -749,13 +749,12 @@ gin_xlog_startup(void) { opCtx = AllocSetContextCreate(CurrentMemoryContext, "GIN recovery temporary context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); } void gin_xlog_cleanup(void) { MemoryContextDelete(opCtx); + opCtx = NULL; } diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index 9a417ca2f4..597056ae44 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -4,7 +4,7 @@ * interface routines for the postgres GiST index access method. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -18,6 +18,7 @@ #include "access/gistscan.h" #include "catalog/pg_collation.h" #include "miscadmin.h" +#include "utils/builtins.h" #include "utils/index_selfuncs.h" #include "utils/memutils.h" #include "utils/rel.h" @@ -105,9 +106,7 @@ createTempGistContext(void) { return AllocSetContextCreate(CurrentMemoryContext, "GiST temporary context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); } /* @@ -495,18 +494,36 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate, else { /* - * Enough space. We also get here if ntuples==0. + * Enough space. We always get here if ntup==0. */ START_CRIT_SECTION(); /* - * While we delete only one tuple at once we could mix calls - * PageIndexTupleDelete() here and PageIndexMultiDelete() in - * gistRedoPageUpdateRecord() + * Delete old tuple if any, then insert new tuple(s) if any. If + * possible, use the fast path of PageIndexTupleOverwrite. */ if (OffsetNumberIsValid(oldoffnum)) - PageIndexTupleDelete(page, oldoffnum); - gistfillbuffer(page, itup, ntup, InvalidOffsetNumber); + { + if (ntup == 1) + { + /* One-for-one replacement, so use PageIndexTupleOverwrite */ + if (!PageIndexTupleOverwrite(page, oldoffnum, (Item) *itup, + IndexTupleSize(*itup))) + elog(ERROR, "failed to add item to index page in \"%s\"", + RelationGetRelationName(rel)); + } + else + { + /* Delete old, then append new tuple(s) to page */ + PageIndexTupleDelete(page, oldoffnum); + gistfillbuffer(page, itup, ntup, InvalidOffsetNumber); + } + } + else + { + /* Just append new tuples at the end of the page */ + gistfillbuffer(page, itup, ntup, InvalidOffsetNumber); + } MarkBufferDirty(buffer); @@ -1411,9 +1428,7 @@ initGISTstate(Relation index) /* Create the memory context that will hold the GISTSTATE */ scanCxt = AllocSetContextCreate(CurrentMemoryContext, "GiST scan context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldCxt = MemoryContextSwitchTo(scanCxt); /* Create and fill in the GISTSTATE */ diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 4e43a6932a..b65926f97a 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -4,7 +4,7 @@ * build algorithm for GiST indexes implementation. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gist/gistbuildbuffers.c b/src/backend/access/gist/gistbuildbuffers.c index 8e3fcfbdc1..ca4c32b3fe 100644 --- a/src/backend/access/gist/gistbuildbuffers.c +++ b/src/backend/access/gist/gistbuildbuffers.c @@ -4,7 +4,7 @@ * node buffer management functions for GiST buffering build algorithm. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c index 5ba7d0a793..eea366b1ad 100644 --- a/src/backend/access/gist/gistget.c +++ b/src/backend/access/gist/gistget.c @@ -4,7 +4,7 @@ * fetch tuples from a GiST scan. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c index d47211afc0..ffb1d772ad 100644 --- a/src/backend/access/gist/gistproc.c +++ b/src/backend/access/gist/gistproc.c @@ -7,7 +7,7 @@ * This gives R-tree behavior, with Guttman's poly-time split algorithm. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gist/gistscan.c b/src/backend/access/gist/gistscan.c index 6f07cd8d46..33b388906a 100644 --- a/src/backend/access/gist/gistscan.c +++ b/src/backend/access/gist/gistscan.c @@ -4,7 +4,7 @@ * routines to manage scans on GiST index relations * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -125,7 +125,7 @@ gistrescan(IndexScanDesc scan, ScanKey key, int nkeys, * which is created on the second call and reset on later calls. Thus, in * the common case where a scan is only rescan'd once, we just put the * queue in scanCxt and don't pay the overhead of making a second memory - * context. If we do rescan more than once, the first RBTree is just left + * context. If we do rescan more than once, the first queue is just left * for dead until end of scan; this small wastage seems worth the savings * in the common case. */ @@ -140,9 +140,7 @@ gistrescan(IndexScanDesc scan, ScanKey key, int nkeys, /* second time through */ so->queueCxt = AllocSetContextCreate(so->giststate->scanCxt, "GiST queue context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); first_time = false; } else @@ -180,12 +178,10 @@ gistrescan(IndexScanDesc scan, ScanKey key, int nkeys, so->pageDataCxt = AllocSetContextCreate(so->giststate->scanCxt, "GiST page data context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); } - /* create new, empty RBTree for search queue */ + /* create new, empty pairing heap for search queue */ oldCxt = MemoryContextSwitchTo(so->queueCxt); so->queue = pairingheap_allocate(pairingheap_GISTSearchItem_cmp, scan); MemoryContextSwitchTo(oldCxt); diff --git a/src/backend/access/gist/gistsplit.c b/src/backend/access/gist/gistsplit.c index d394969a57..cffc5ddc75 100644 --- a/src/backend/access/gist/gistsplit.c +++ b/src/backend/access/gist/gistsplit.c @@ -15,7 +15,7 @@ * gistSplitByKey() is the entry point to this file. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c index 26d4a64694..f92baedffd 100644 --- a/src/backend/access/gist/gistutil.c +++ b/src/backend/access/gist/gistutil.c @@ -4,7 +4,7 @@ * utilities routines for the postgres GiST index access method. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -852,7 +852,7 @@ gistproperty(Oid index_oid, int attno, bool *res, bool *isnull) { HeapTuple tuple; - Form_pg_index rd_index; + Form_pg_index rd_index PG_USED_FOR_ASSERTS_ONLY; Form_pg_opclass rd_opclass; Datum datum; bool disnull; diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c index 53e5cea580..77d9d12f0b 100644 --- a/src/backend/access/gist/gistvacuum.c +++ b/src/backend/access/gist/gistvacuum.c @@ -4,7 +4,7 @@ * vacuuming routines for the postgres GiST index access method. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gist/gistvalidate.c b/src/backend/access/gist/gistvalidate.c index ffd7fd631b..585c92be26 100644 --- a/src/backend/access/gist/gistvalidate.c +++ b/src/backend/access/gist/gistvalidate.c @@ -3,7 +3,7 @@ * gistvalidate.c * Opclass validator for GiST. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -23,6 +23,7 @@ #include "catalog/pg_type.h" #include "utils/builtins.h" #include "utils/lsyscache.h" +#include "utils/regproc.h" #include "utils/syscache.h" diff --git a/src/backend/access/gist/gistxlog.c b/src/backend/access/gist/gistxlog.c index 01c7ef7ea6..88b97a4e48 100644 --- a/src/backend/access/gist/gistxlog.c +++ b/src/backend/access/gist/gistxlog.c @@ -4,7 +4,7 @@ * WAL replay logic for GiST. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -80,9 +80,31 @@ gistRedoPageUpdateRecord(XLogReaderState *record) page = (Page) BufferGetPage(buffer); - /* Delete old tuples */ - if (xldata->ntodelete > 0) + if (xldata->ntodelete == 1 && xldata->ntoinsert == 1) { + /* + * When replacing one tuple with one other tuple, we must use + * PageIndexTupleOverwrite for consistency with gistplacetopage. + */ + OffsetNumber offnum = *((OffsetNumber *) data); + IndexTuple itup; + Size itupsize; + + data += sizeof(OffsetNumber); + itup = (IndexTuple) data; + itupsize = IndexTupleSize(itup); + if (!PageIndexTupleOverwrite(page, offnum, (Item) itup, itupsize)) + elog(ERROR, "failed to add item to GiST index page, size %d bytes", + (int) itupsize); + data += itupsize; + /* should be nothing left after consuming 1 tuple */ + Assert(data - begin == datalen); + /* update insertion count for assert check below */ + ninserted++; + } + else if (xldata->ntodelete > 0) + { + /* Otherwise, delete old tuples if any */ OffsetNumber *todelete = (OffsetNumber *) data; data += sizeof(OffsetNumber) * xldata->ntodelete; @@ -92,7 +114,7 @@ gistRedoPageUpdateRecord(XLogReaderState *record) GistMarkTuplesDeleted(page); } - /* add tuples */ + /* Add new tuples if any */ if (data - begin < datalen) { OffsetNumber off = (PageIsEmpty(page)) ? FirstOffsetNumber : @@ -115,6 +137,7 @@ gistRedoPageUpdateRecord(XLogReaderState *record) } } + /* Check that XLOG record contained expected number of tuples */ Assert(ninserted == xldata->ntoinsert); PageSetLSN(page, lsn); diff --git a/src/backend/access/hash/Makefile b/src/backend/access/hash/Makefile index 5d3bd94d3e..e2e7e91493 100644 --- a/src/backend/access/hash/Makefile +++ b/src/backend/access/hash/Makefile @@ -12,7 +12,7 @@ subdir = src/backend/access/hash top_builddir = ../../../.. include $(top_builddir)/src/Makefile.global -OBJS = hash.o hashfunc.o hashinsert.o hashovfl.o hashpage.o hashscan.o \ - hashsearch.o hashsort.o hashutil.o hashvalidate.o +OBJS = hash.o hashfunc.o hashinsert.o hashovfl.o hashpage.o hashsearch.o \ + hashsort.o hashutil.o hashvalidate.o include $(top_srcdir)/src/backend/common.mk diff --git a/src/backend/access/hash/README b/src/backend/access/hash/README index 0a7da89285..01ea115f4d 100644 --- a/src/backend/access/hash/README +++ b/src/backend/access/hash/README @@ -126,53 +126,54 @@ the initially created buckets. Lock Definitions ---------------- -We use both lmgr locks ("heavyweight" locks) and buffer context locks -(LWLocks) to control access to a hash index. lmgr locks are needed for -long-term locking since there is a (small) risk of deadlock, which we must -be able to detect. Buffer context locks are used for short-term access -control to individual pages of the index. - -LockPage(rel, page), where page is the page number of a hash bucket page, -represents the right to split or compact an individual bucket. A process -splitting a bucket must exclusive-lock both old and new halves of the -bucket until it is done. A process doing VACUUM must exclusive-lock the -bucket it is currently purging tuples from. Processes doing scans or -insertions must share-lock the bucket they are scanning or inserting into. -(It is okay to allow concurrent scans and insertions.) - -The lmgr lock IDs corresponding to overflow pages are currently unused. -These are available for possible future refinements. LockPage(rel, 0) -is also currently undefined (it was previously used to represent the right -to modify the hash-code-to-bucket mapping, but it is no longer needed for -that purpose). - -Note that these lock definitions are conceptually distinct from any sort -of lock on the pages whose numbers they share. A process must also obtain -read or write buffer lock on the metapage or bucket page before accessing -said page. - -Processes performing hash index scans must hold share lock on the bucket -they are scanning throughout the scan. This seems to be essential, since -there is no reasonable way for a scan to cope with its bucket being split -underneath it. This creates a possibility of deadlock external to the -hash index code, since a process holding one of these locks could block -waiting for an unrelated lock held by another process. If that process -then does something that requires exclusive lock on the bucket, we have -deadlock. Therefore the bucket locks must be lmgr locks so that deadlock -can be detected and recovered from. - -Processes must obtain read (share) buffer context lock on any hash index -page while reading it, and write (exclusive) lock while modifying it. -To prevent deadlock we enforce these coding rules: no buffer lock may be -held long term (across index AM calls), nor may any buffer lock be held -while waiting for an lmgr lock, nor may more than one buffer lock -be held at a time by any one process. (The third restriction is probably -stronger than necessary, but it makes the proof of no deadlock obvious.) +Concurrency control for hash indexes is provided using buffer content +locks, buffer pins, and cleanup locks. Here as elsewhere in PostgreSQL, +cleanup lock means that we hold an exclusive lock on the buffer and have +observed at some point after acquiring the lock that we hold the only pin +on that buffer. For hash indexes, a cleanup lock on a primary bucket page +represents the right to perform an arbitrary reorganization of the entire +bucket. Therefore, scans retain a pin on the primary bucket page for the +bucket they are currently scanning. Splitting a bucket requires a cleanup +lock on both the old and new primary bucket pages. VACUUM therefore takes +a cleanup lock on every bucket page in order to remove tuples. It can also +remove tuples copied to a new bucket by any previous split operation, because +the cleanup lock taken on the primary bucket page guarantees that no scans +which started prior to the most recent split can still be in progress. After +cleaning each page individually, it attempts to take a cleanup lock on the +primary bucket page in order to "squeeze" the bucket down to the minimum +possible number of pages. + +To avoid deadlocks, we must be consistent about the lock order in which we +lock the buckets for operations that requires locks on two different buckets. +We choose to always lock the lower-numbered bucket first. The metapage is +only ever locked after all bucket locks have been taken. Pseudocode Algorithms --------------------- +Various flags that are used in hash index operations are described as below: + +The bucket-being-split and bucket-being-populated flags indicate that split +the operation is in progress for a bucket. During split operation, a +bucket-being-split flag is set on the old bucket and bucket-being-populated +flag is set on new bucket. These flags are cleared once the split operation +is finished. + +The split-cleanup flag indicates that a bucket which has been recently split +still contains tuples that were also copied to the new bucket; it essentially +marks the split as incomplete. Once we're certain that no scans which +started before the new bucket was fully populated are still in progress, we +can remove the copies from the old bucket and clear the flag. We insist that +this flag must be clear before splitting a bucket; thus, a bucket can't be +split again until the previous split is totally complete. + +The moved-by-split flag on a tuple indicates that tuple is moved from old to +new bucket. Concurrent scans can skip such tuples till the split operation +is finished. Once the tuple is marked as moved-by-split, it will remain so +forever but that does no harm. We have intentionally not cleared it as that +can generate an additional I/O which is not necessary. + The operations we need to support are: readers scanning the index for entries of a particular hash code (which by definition are all in the same bucket); insertion of a new tuple into the correct bucket; enlarging the @@ -193,38 +194,48 @@ The reader algorithm is: release meta page buffer content lock if (correct bucket page is already locked) break - release any existing bucket page lock (if a concurrent split happened) - take heavyweight bucket lock + release any existing bucket page buffer content lock (if a concurrent + split happened) + take the buffer content lock on bucket page in shared mode retake meta page buffer content lock in shared mode --- then, per read request: release pin on metapage - read current page of bucket and take shared buffer content lock - step to next page if necessary (no chaining of locks) + if the target bucket is still being populated by a split: + release the buffer content lock on current bucket page + pin and acquire the buffer content lock on old bucket in shared mode + release the buffer content lock on old bucket, but not pin + retake the buffer content lock on new bucket + arrange to scan the old bucket normally and the new bucket for + tuples which are not moved-by-split +-- then, per read request: + reacquire content lock on current page + step to next page if necessary (no chaining of content locks, but keep + the pin on the primary bucket throughout the scan; we also maintain + a pin on the page currently being scanned) get tuple - release buffer content lock and pin on current page + release content lock -- at scan shutdown: - release bucket share-lock - -We can't hold the metapage lock while acquiring a lock on the target bucket, -because that might result in an undetected deadlock (lwlocks do not participate -in deadlock detection). Instead, we relock the metapage after acquiring the -bucket page lock and check whether the bucket has been split. If not, we're -done. If so, we release our previously-acquired lock and repeat the process -using the new bucket number. Holding the bucket sharelock for -the remainder of the scan prevents the reader's current-tuple pointer from -being invalidated by splits or compactions. Notice that the reader's lock -does not prevent other buckets from being split or compacted. + release all pins still held + +Holding the buffer pin on the primary bucket page for the whole scan prevents +the reader's current-tuple pointer from being invalidated by splits or +compactions. (Of course, other buckets can still be split or compacted.) To keep concurrency reasonably good, we require readers to cope with concurrent insertions, which means that they have to be able to re-find -their current scan position after re-acquiring the page sharelock. Since -deletion is not possible while a reader holds the bucket sharelock, and -we assume that heap tuple TIDs are unique, this can be implemented by +their current scan position after re-acquiring the buffer content lock on +page. Since deletion is not possible while a reader holds the pin on bucket, +and we assume that heap tuple TIDs are unique, this can be implemented by searching for the same heap tuple TID previously returned. Insertion does not move index entries across pages, so the previously-returned index entry should always be on the same page, at the same or higher offset number, as it was before. +To allow for scans during a bucket split, if at the start of the scan, the +bucket is marked as bucket-being-populated, it scan all the tuples in that +bucket except for those that are marked as moved-by-split. Once it finishes +the scan of all the tuples in the current bucket, it scans the old bucket from +which this bucket is formed by split. + The insertion algorithm is rather similar: pin meta page and take buffer content lock in shared mode @@ -233,18 +244,29 @@ The insertion algorithm is rather similar: release meta page buffer content lock if (correct bucket page is already locked) break - release any existing bucket page lock (if a concurrent split happened) - take heavyweight bucket lock in shared mode + release any existing bucket page buffer content lock (if a concurrent + split happened) + take the buffer content lock on bucket page in exclusive mode retake meta page buffer content lock in shared mode --- (so far same as reader) release pin on metapage - pin current page of bucket and take exclusive buffer content lock - if full, release, read/exclusive-lock next page; repeat as needed +-- (so far same as reader, except for acquisition of buffer content lock in + exclusive mode on primary bucket page) + if the bucket-being-split flag is set for a bucket and pin count on it is + one, then finish the split + release the buffer content lock on current bucket + get the "new" bucket which was being populated by the split + scan the new bucket and form the hash table of TIDs + conditionally get the cleanup lock on old and new buckets + if we get the lock on both the buckets + finish the split using algorithm mentioned below for split + release the pin on old bucket and restart the insert from beginning. + if current page is full, release lock but not pin, read/exclusive-lock + next page; repeat as needed >> see below if no space in any page of bucket insert tuple at appropriate place in page mark current page dirty and release buffer content lock and pin - release heavyweight share-lock - pin meta page and take buffer content lock in shared mode + if the current page is not a bucket page, release the pin on bucket page + pin meta page and take buffer content lock in exclusive mode increment tuple count, decide if split needed mark meta page dirty and release buffer content lock and pin done if no split needed, else enter Split algorithm below @@ -256,11 +278,13 @@ bucket that is being actively scanned, because readers can cope with this as explained above. We only need the short-term buffer locks to ensure that readers do not see a partially-updated page. -It is clearly impossible for readers and inserters to deadlock, and in -fact this algorithm allows them a very high degree of concurrency. -(The exclusive metapage lock taken to update the tuple count is stronger -than necessary, since readers do not care about the tuple count, but the -lock is held for such a short time that this is probably not an issue.) +To avoid deadlock between readers and inserters, whenever there is a need +to lock multiple buckets, we always take in the order suggested in Lock +Definitions above. This algorithm allows them a very high degree of +concurrency. (The exclusive metapage lock taken to update the tuple count +is stronger than necessary, since readers do not care about the tuple count, +but the lock is held for such a short time that this is probably not an +issue.) When an inserter cannot find space in any existing page of a bucket, it must obtain an overflow page and add that page to the bucket's chain. @@ -271,46 +295,45 @@ index is overfull (has a higher-than-wanted ratio of tuples to buckets). The algorithm attempts, but does not necessarily succeed, to split one existing bucket in two, thereby lowering the fill ratio: - pin meta page and take buffer content lock in exclusive mode - check split still needed - if split not needed anymore, drop buffer content lock and pin and exit - decide which bucket to split - Attempt to X-lock old bucket number (definitely could fail) - Attempt to X-lock new bucket number (shouldn't fail, but...) - if above fail, drop locks and pin and exit - update meta page to reflect new number of buckets - mark meta page dirty and release buffer content lock and pin - -- now, accesses to all other buckets can proceed. - Perform actual split of bucket, moving tuples as needed - >> see below about acquiring needed extra space - Release X-locks of old and new buckets - -Note the metapage lock is not held while the actual tuple rearrangement is -performed, so accesses to other buckets can proceed in parallel; in fact, -it's possible for multiple bucket splits to proceed in parallel. - -Split's attempt to X-lock the old bucket number could fail if another -process holds S-lock on it. We do not want to wait if that happens, first -because we don't want to wait while holding the metapage exclusive-lock, -and second because it could very easily result in deadlock. (The other -process might be out of the hash AM altogether, and could do something -that blocks on another lock this process holds; so even if the hash -algorithm itself is deadlock-free, a user-induced deadlock could occur.) -So, this is a conditional LockAcquire operation, and if it fails we just -abandon the attempt to split. This is all right since the index is -overfull but perfectly functional. Every subsequent inserter will try to -split, and eventually one will succeed. If multiple inserters failed to -split, the index might still be overfull, but eventually, the index will + pin meta page and take buffer content lock in exclusive mode + check split still needed + if split not needed anymore, drop buffer content lock and pin and exit + decide which bucket to split + try to take a cleanup lock on that bucket; if fail, give up + if that bucket is still being split or has split-cleanup work: + try to finish the split and the cleanup work + if that succeeds, start over; if it fails, give up + mark the old and new buckets indicating split is in progress + copy the tuples that belongs to new bucket from old bucket, marking + them as moved-by-split + release lock but not pin for primary bucket page of old bucket, + read/shared-lock next page; repeat as needed + clear the bucket-being-split and bucket-being-populated flags + mark the old bucket indicating split-cleanup + +The split operation's attempt to acquire cleanup-lock on the old bucket number +could fail if another process holds any lock or pin on it. We do not want to +wait if that happens, because we don't want to wait while holding the metapage +exclusive-lock. So, this is a conditional LWLockAcquire operation, and if +it fails we just abandon the attempt to split. This is all right since the +index is overfull but perfectly functional. Every subsequent inserter will +try to split, and eventually one will succeed. If multiple inserters failed +to split, the index might still be overfull, but eventually, the index will not be overfull and split attempts will stop. (We could make a successful splitter loop to see if the index is still overfull, but it seems better to distribute the split overhead across successive insertions.) -A problem is that if a split fails partway through (eg due to insufficient -disk space) the index is left corrupt. The probability of that could be -made quite low if we grab a free page or two before we update the meta -page, but the only real solution is to treat a split as a WAL-loggable, -must-complete action. I'm not planning to teach hash about WAL in this -go-round. +If a split fails partway through (e.g. due to insufficient disk space or an +interrupt), the index will not be corrupted. Instead, we'll retry the split +every time a tuple is inserted into the old bucket prior to inserting the new +tuple; eventually, we should succeed. The fact that a split is left +unfinished doesn't prevent subsequent buckets from being split, but we won't +try to split the bucket again until the prior split is finished. In other +words, a bucket can be in the middle of being split for some time, but it can't +be in the middle of two splits at the same time. + +Although we can survive a failure to split a bucket, a crash is likely to +corrupt the index, since hash indexes are not yet WAL-logged. The fourth operation is garbage collection (bulk deletion): @@ -319,9 +342,17 @@ The fourth operation is garbage collection (bulk deletion): fetch current max bucket number release meta page buffer content lock and pin while next bucket <= max bucket do - Acquire X lock on target bucket - Scan and remove tuples, compact free space as needed - Release X lock + acquire cleanup lock on primary bucket page + loop: + scan and remove tuples + if this is the last bucket page, break out of loop + pin and x-lock next page + release prior lock and pin (except keep pin on primary bucket page) + if the page we have locked is not the primary bucket page: + release lock and take exclusive lock on primary bucket page + if there are no other pins on the primary bucket page: + squeeze the bucket to remove free space + release the pin on primary bucket page next bucket ++ end loop pin metapage and take buffer content lock in exclusive mode @@ -330,20 +361,24 @@ The fourth operation is garbage collection (bulk deletion): else update metapage tuple count mark meta page dirty and release buffer content lock and pin -Note that this is designed to allow concurrent splits. If a split occurs, -tuples relocated into the new bucket will be visited twice by the scan, -but that does no harm. (We must however be careful about the statistics +Note that this is designed to allow concurrent splits and scans. If a split +occurs, tuples relocated into the new bucket will be visited twice by the +scan, but that does no harm. As we release the lock on bucket page during +cleanup scan of a bucket, it will allow concurrent scan to start on a bucket +and ensures that scan will always be behind cleanup. It is must to keep scans +behind cleanup, else vacuum could decrease the TIDs that are required to +complete the scan. Now, as the scan that returns multiple tuples from the +same bucket page always expect next valid TID to be greater than or equal to +the current TID, it might miss the tuples. This holds true for backward scans +as well (backward scans first traverse each bucket starting from first bucket +to last overflow page in the chain). We must be careful about the statistics reported by the VACUUM operation. What we can do is count the number of -tuples scanned, and believe this in preference to the stored tuple count -if the stored tuple count and number of buckets did *not* change at any -time during the scan. This provides a way of correcting the stored tuple -count if it gets out of sync for some reason. But if a split or insertion -does occur concurrently, the scan count is untrustworthy; instead, -subtract the number of tuples deleted from the stored tuple count and -use that.) - -The exclusive lock request could deadlock in some strange scenarios, but -we can just error out without any great harm being done. +tuples scanned, and believe this in preference to the stored tuple count if +the stored tuple count and number of buckets did *not* change at any time +during the scan. This provides a way of correcting the stored tuple count if +it gets out of sync for some reason. But if a split or insertion does occur +concurrently, the scan count is untrustworthy; instead, subtract the number of +tuples deleted from the stored tuple count and use that. Free Space Management @@ -417,13 +452,11 @@ free page; there can be no other process holding lock on it. Bucket splitting uses a similar algorithm if it has to extend the new bucket, but it need not worry about concurrent extension since it has -exclusive lock on the new bucket. +buffer content lock in exclusive mode on the new bucket. -Freeing an overflow page is done by garbage collection and by bucket -splitting (the old bucket may contain no-longer-needed overflow pages). -In both cases, the process holds exclusive lock on the containing bucket, -so need not worry about other accessors of pages in the bucket. The -algorithm is: +Freeing an overflow page requires the process to hold buffer content lock in +exclusive mode on the containing bucket, so need not worry about other +accessors of pages in the bucket. The algorithm is: delink overflow page from bucket chain (this requires read/update/write/release of fore and aft siblings) @@ -454,14 +487,6 @@ locks. Since they need no lmgr locks, deadlock is not possible. Other Notes ----------- -All the shenanigans with locking prevent a split occurring while *another* -process is stopped in a given bucket. They do not ensure that one of -our *own* backend's scans is not stopped in the bucket, because lmgr -doesn't consider a process's own locks to conflict. So the Split -algorithm must check for that case separately before deciding it can go -ahead with the split. VACUUM does not have this problem since nothing -else can be happening within the vacuuming backend. - -Should we instead try to fix the state of any conflicting local scan? -Seems mighty ugly --- got to move the held bucket S-lock as well as lots -of other messiness. For now, just punt and don't split. +Clean up locks prevent a split from occurring while *another* process is stopped +in a given bucket. It also ensures that one of our *own* backend's scans is not +stopped in the bucket. diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c index 07496f8156..a64a9b9696 100644 --- a/src/backend/access/hash/hash.c +++ b/src/backend/access/hash/hash.c @@ -3,7 +3,7 @@ * hash.c * Implementation of Margo Seltzer's Hashing package for postgres. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -19,11 +19,13 @@ #include "postgres.h" #include "access/hash.h" +#include "access/hash_xlog.h" #include "access/relscan.h" #include "catalog/index.h" #include "commands/vacuum.h" #include "miscadmin.h" #include "optimizer/plancat.h" +#include "utils/builtins.h" #include "utils/index_selfuncs.h" #include "utils/rel.h" @@ -273,7 +275,7 @@ hashgettuple(IndexScanDesc scan, ScanDirection dir) * Reacquire the read lock here. */ if (BufferIsValid(so->hashso_curbuf)) - _hash_chgbufaccess(rel, so->hashso_curbuf, HASH_NOLOCK, HASH_READ); + LockBuffer(so->hashso_curbuf, BUFFER_LOCK_SHARE); /* * If we've already initialized this scan, we can just advance it in the @@ -286,10 +288,10 @@ hashgettuple(IndexScanDesc scan, ScanDirection dir) /* * An insertion into the current index page could have happened while * we didn't have read lock on it. Re-find our position by looking - * for the TID we previously returned. (Because we hold share lock on - * the bucket, no deletions or splits could have occurred; therefore - * we can expect that the TID still exists in the current index page, - * at an offset >= where we were.) + * for the TID we previously returned. (Because we hold a pin on the + * primary bucket page, no deletions or splits could have occurred; + * therefore we can expect that the TID still exists in the current + * index page, at an offset >= where we were.) */ OffsetNumber maxoffnum; @@ -353,7 +355,7 @@ hashgettuple(IndexScanDesc scan, ScanDirection dir) /* Release read lock on current buffer, but keep it pinned */ if (BufferIsValid(so->hashso_curbuf)) - _hash_chgbufaccess(rel, so->hashso_curbuf, HASH_READ, HASH_NOLOCK); + LockBuffer(so->hashso_curbuf, BUFFER_LOCK_UNLOCK); /* Return current heap TID on success */ scan->xs_ctup.t_self = so->hashso_heappos; @@ -423,17 +425,17 @@ hashbeginscan(Relation rel, int nkeys, int norderbys) scan = RelationGetIndexScan(rel, nkeys, norderbys); so = (HashScanOpaque) palloc(sizeof(HashScanOpaqueData)); - so->hashso_bucket_valid = false; - so->hashso_bucket_blkno = 0; so->hashso_curbuf = InvalidBuffer; + so->hashso_bucket_buf = InvalidBuffer; + so->hashso_split_bucket_buf = InvalidBuffer; /* set position invalid (this will cause _hash_first call) */ ItemPointerSetInvalid(&(so->hashso_curpos)); ItemPointerSetInvalid(&(so->hashso_heappos)); - scan->opaque = so; + so->hashso_buc_populated = false; + so->hashso_buc_split = false; - /* register scan in case we change pages it's using */ - _hash_regscan(scan); + scan->opaque = so; return scan; } @@ -448,15 +450,7 @@ hashrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, HashScanOpaque so = (HashScanOpaque) scan->opaque; Relation rel = scan->indexRelation; - /* release any pin we still hold */ - if (BufferIsValid(so->hashso_curbuf)) - _hash_dropbuf(rel, so->hashso_curbuf); - so->hashso_curbuf = InvalidBuffer; - - /* release lock on bucket, too */ - if (so->hashso_bucket_blkno) - _hash_droplock(rel, so->hashso_bucket_blkno, HASH_SHARE); - so->hashso_bucket_blkno = 0; + _hash_dropscanbuf(rel, so); /* set position invalid (this will cause _hash_first call) */ ItemPointerSetInvalid(&(so->hashso_curpos)); @@ -468,8 +462,10 @@ hashrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, memmove(scan->keyData, scankey, scan->numberOfKeys * sizeof(ScanKeyData)); - so->hashso_bucket_valid = false; } + + so->hashso_buc_populated = false; + so->hashso_buc_split = false; } /* @@ -481,18 +477,7 @@ hashendscan(IndexScanDesc scan) HashScanOpaque so = (HashScanOpaque) scan->opaque; Relation rel = scan->indexRelation; - /* don't need scan registered anymore */ - _hash_dropscan(scan); - - /* release any pin we still hold */ - if (BufferIsValid(so->hashso_curbuf)) - _hash_dropbuf(rel, so->hashso_curbuf); - so->hashso_curbuf = InvalidBuffer; - - /* release lock on bucket, too */ - if (so->hashso_bucket_blkno) - _hash_droplock(rel, so->hashso_bucket_blkno, HASH_SHARE); - so->hashso_bucket_blkno = 0; + _hash_dropscanbuf(rel, so); pfree(so); scan->opaque = NULL; @@ -503,6 +488,9 @@ hashendscan(IndexScanDesc scan) * The set of target tuples is specified via a callback routine that tells * whether any given heap tuple (identified by ItemPointer) is being deleted. * + * This function also deletes the tuples that are moved by split to other + * bucket. + * * Result: a palloc'd struct containing statistical info for VACUUM displays. */ IndexBulkDeleteResult * @@ -536,7 +524,8 @@ hashbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, orig_maxbucket = metap->hashm_maxbucket; orig_ntuples = metap->hashm_ntuples; memcpy(&local_metapage, metap, sizeof(local_metapage)); - _hash_relbuf(rel, metabuf); + /* release the lock, but keep pin */ + LockBuffer(metabuf, BUFFER_LOCK_UNLOCK); /* Scan the buckets that we know exist */ cur_bucket = 0; @@ -547,90 +536,69 @@ hashbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, { BlockNumber bucket_blkno; BlockNumber blkno; - bool bucket_dirty = false; + Buffer bucket_buf; + Buffer buf; + HashPageOpaque bucket_opaque; + Page page; + bool split_cleanup = false; /* Get address of bucket's start page */ bucket_blkno = BUCKET_TO_BLKNO(&local_metapage, cur_bucket); - /* Exclusive-lock the bucket so we can shrink it */ - _hash_getlock(rel, bucket_blkno, HASH_EXCLUSIVE); + blkno = bucket_blkno; - /* Shouldn't have any active scans locally, either */ - if (_hash_has_active_scan(rel, cur_bucket)) - elog(ERROR, "hash index has active scan during VACUUM"); + /* + * We need to acquire a cleanup lock on the primary bucket page to out + * wait concurrent scans before deleting the dead tuples. + */ + buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, info->strategy); + LockBufferForCleanup(buf); + _hash_checkpage(rel, buf, LH_BUCKET_PAGE); - /* Scan each page in bucket */ - blkno = bucket_blkno; - while (BlockNumberIsValid(blkno)) - { - Buffer buf; - Page page; - HashPageOpaque opaque; - OffsetNumber offno; - OffsetNumber maxoffno; - OffsetNumber deletable[MaxOffsetNumber]; - int ndeletable = 0; - - vacuum_delay_point(); - - buf = _hash_getbuf_with_strategy(rel, blkno, HASH_WRITE, - LH_BUCKET_PAGE | LH_OVERFLOW_PAGE, - info->strategy); - page = BufferGetPage(buf); - opaque = (HashPageOpaque) PageGetSpecialPointer(page); - Assert(opaque->hasho_bucket == cur_bucket); - - /* Scan each tuple in page */ - maxoffno = PageGetMaxOffsetNumber(page); - for (offno = FirstOffsetNumber; - offno <= maxoffno; - offno = OffsetNumberNext(offno)) - { - IndexTuple itup; - ItemPointer htup; + page = BufferGetPage(buf); + bucket_opaque = (HashPageOpaque) PageGetSpecialPointer(page); - itup = (IndexTuple) PageGetItem(page, - PageGetItemId(page, offno)); - htup = &(itup->t_tid); - if (callback(htup, callback_state)) - { - /* mark the item for deletion */ - deletable[ndeletable++] = offno; - tuples_removed += 1; - } - else - num_index_tuples += 1; - } + /* + * If the bucket contains tuples that are moved by split, then we need + * to delete such tuples. We can't delete such tuples if the split + * operation on bucket is not finished as those are needed by scans. + */ + if (!H_BUCKET_BEING_SPLIT(bucket_opaque) && + H_NEEDS_SPLIT_CLEANUP(bucket_opaque)) + { + split_cleanup = true; /* - * Apply deletions and write page if needed, advance to next page. + * This bucket might have been split since we last held a lock on + * the metapage. If so, hashm_maxbucket, hashm_highmask and + * hashm_lowmask might be old enough to cause us to fail to remove + * tuples left behind by the most recent split. To prevent that, + * now that the primary page of the target bucket has been locked + * (and thus can't be further split), update our cached metapage + * data. */ - blkno = opaque->hasho_nextblkno; - - if (ndeletable > 0) - { - PageIndexMultiDelete(page, deletable, ndeletable); - _hash_wrtbuf(rel, buf); - bucket_dirty = true; - } - else - _hash_relbuf(rel, buf); + LockBuffer(metabuf, BUFFER_LOCK_SHARE); + memcpy(&local_metapage, metap, sizeof(local_metapage)); + LockBuffer(metabuf, BUFFER_LOCK_UNLOCK); } - /* If we deleted anything, try to compact free space */ - if (bucket_dirty) - _hash_squeezebucket(rel, cur_bucket, bucket_blkno, - info->strategy); + bucket_buf = buf; + + hashbucketcleanup(rel, cur_bucket, bucket_buf, blkno, info->strategy, + local_metapage.hashm_maxbucket, + local_metapage.hashm_highmask, + local_metapage.hashm_lowmask, &tuples_removed, + &num_index_tuples, split_cleanup, + callback, callback_state); - /* Release bucket lock */ - _hash_droplock(rel, bucket_blkno, HASH_EXCLUSIVE); + _hash_dropbuf(rel, bucket_buf); /* Advance to next bucket */ cur_bucket++; } /* Write-lock metapage and check for split since we started */ - metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_WRITE, LH_META_PAGE); + LockBuffer(metabuf, BUFFER_LOCK_EXCLUSIVE); metap = HashPageGetMeta(BufferGetPage(metabuf)); if (cur_maxbucket != metap->hashm_maxbucket) @@ -638,7 +606,7 @@ hashbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, /* There's been a split, so process the additional bucket(s) */ cur_maxbucket = metap->hashm_maxbucket; memcpy(&local_metapage, metap, sizeof(local_metapage)); - _hash_relbuf(rel, metabuf); + LockBuffer(metabuf, BUFFER_LOCK_UNLOCK); goto loop_top; } @@ -668,7 +636,8 @@ hashbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, num_index_tuples = metap->hashm_ntuples; } - _hash_wrtbuf(rel, metabuf); + MarkBufferDirty(metabuf); + _hash_relbuf(rel, metabuf); /* return statistics */ if (stats == NULL) @@ -704,6 +673,202 @@ hashvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) return stats; } +/* + * Helper function to perform deletion of index entries from a bucket. + * + * This function expects that the caller has acquired a cleanup lock on the + * primary bucket page, and will return with a write lock again held on the + * primary bucket page. The lock won't necessarily be held continuously, + * though, because we'll release it when visiting overflow pages. + * + * It would be very bad if this function cleaned a page while some other + * backend was in the midst of scanning it, because hashgettuple assumes + * that the next valid TID will be greater than or equal to the current + * valid TID. There can't be any concurrent scans in progress when we first + * enter this function because of the cleanup lock we hold on the primary + * bucket page, but as soon as we release that lock, there might be. We + * handle that by conspiring to prevent those scans from passing our cleanup + * scan. To do that, we lock the next page in the bucket chain before + * releasing the lock on the previous page. (This type of lock chaining is + * not ideal, so we might want to look for a better solution at some point.) + * + * We need to retain a pin on the primary bucket to ensure that no concurrent + * split can start. + */ +void +hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf, + BlockNumber bucket_blkno, BufferAccessStrategy bstrategy, + uint32 maxbucket, uint32 highmask, uint32 lowmask, + double *tuples_removed, double *num_index_tuples, + bool split_cleanup, + IndexBulkDeleteCallback callback, void *callback_state) +{ + BlockNumber blkno; + Buffer buf; + Bucket new_bucket PG_USED_FOR_ASSERTS_ONLY = InvalidBucket; + bool bucket_dirty = false; + + blkno = bucket_blkno; + buf = bucket_buf; + + if (split_cleanup) + new_bucket = _hash_get_newbucket_from_oldbucket(rel, cur_bucket, + lowmask, maxbucket); + + /* Scan each page in bucket */ + for (;;) + { + HashPageOpaque opaque; + OffsetNumber offno; + OffsetNumber maxoffno; + Buffer next_buf; + Page page; + OffsetNumber deletable[MaxOffsetNumber]; + int ndeletable = 0; + bool retain_pin = false; + + vacuum_delay_point(); + + page = BufferGetPage(buf); + opaque = (HashPageOpaque) PageGetSpecialPointer(page); + + /* Scan each tuple in page */ + maxoffno = PageGetMaxOffsetNumber(page); + for (offno = FirstOffsetNumber; + offno <= maxoffno; + offno = OffsetNumberNext(offno)) + { + ItemPointer htup; + IndexTuple itup; + Bucket bucket; + bool kill_tuple = false; + + itup = (IndexTuple) PageGetItem(page, + PageGetItemId(page, offno)); + htup = &(itup->t_tid); + + /* + * To remove the dead tuples, we strictly want to rely on results + * of callback function. refer btvacuumpage for detailed reason. + */ + if (callback && callback(htup, callback_state)) + { + kill_tuple = true; + if (tuples_removed) + *tuples_removed += 1; + } + else if (split_cleanup) + { + /* delete the tuples that are moved by split. */ + bucket = _hash_hashkey2bucket(_hash_get_indextuple_hashkey(itup), + maxbucket, + highmask, + lowmask); + /* mark the item for deletion */ + if (bucket != cur_bucket) + { + /* + * We expect tuples to either belong to curent bucket or + * new_bucket. This is ensured because we don't allow + * further splits from bucket that contains garbage. See + * comments in _hash_expandtable. + */ + Assert(bucket == new_bucket); + kill_tuple = true; + } + } + + if (kill_tuple) + { + /* mark the item for deletion */ + deletable[ndeletable++] = offno; + } + else + { + /* we're keeping it, so count it */ + if (num_index_tuples) + *num_index_tuples += 1; + } + } + + /* retain the pin on primary bucket page till end of bucket scan */ + if (blkno == bucket_blkno) + retain_pin = true; + else + retain_pin = false; + + blkno = opaque->hasho_nextblkno; + + /* + * Apply deletions, advance to next page and write page if needed. + */ + if (ndeletable > 0) + { + PageIndexMultiDelete(page, deletable, ndeletable); + bucket_dirty = true; + MarkBufferDirty(buf); + } + + /* bail out if there are no more pages to scan. */ + if (!BlockNumberIsValid(blkno)) + break; + + next_buf = _hash_getbuf_with_strategy(rel, blkno, HASH_WRITE, + LH_OVERFLOW_PAGE, + bstrategy); + + /* + * release the lock on previous page after acquiring the lock on next + * page + */ + if (retain_pin) + LockBuffer(buf, BUFFER_LOCK_UNLOCK); + else + _hash_relbuf(rel, buf); + + buf = next_buf; + } + + /* + * lock the bucket page to clear the garbage flag and squeeze the bucket. + * if the current buffer is same as bucket buffer, then we already have + * lock on bucket page. + */ + if (buf != bucket_buf) + { + _hash_relbuf(rel, buf); + LockBuffer(bucket_buf, BUFFER_LOCK_EXCLUSIVE); + } + + /* + * Clear the garbage flag from bucket after deleting the tuples that are + * moved by split. We purposefully clear the flag before squeeze bucket, + * so that after restart, vacuum shouldn't again try to delete the moved + * by split tuples. + */ + if (split_cleanup) + { + HashPageOpaque bucket_opaque; + Page page; + + page = BufferGetPage(bucket_buf); + bucket_opaque = (HashPageOpaque) PageGetSpecialPointer(page); + + bucket_opaque->hasho_flag &= ~LH_BUCKET_NEEDS_SPLIT_CLEANUP; + MarkBufferDirty(bucket_buf); + } + + /* + * If we have deleted anything, try to compact free space. For squeezing + * the bucket, we must have a cleanup lock, else it can impact the + * ordering of tuples for a scan that has started before it. + */ + if (bucket_dirty && IsBufferCleanupOK(bucket_buf)) + _hash_squeezebucket(rel, cur_bucket, bucket_blkno, bucket_buf, + bstrategy); + else + LockBuffer(bucket_buf, BUFFER_LOCK_UNLOCK); +} void hash_redo(XLogReaderState *record) diff --git a/src/backend/access/hash/hashfunc.c b/src/backend/access/hash/hashfunc.c index 614f4ff2f5..289d766419 100644 --- a/src/backend/access/hash/hashfunc.c +++ b/src/backend/access/hash/hashfunc.c @@ -3,7 +3,7 @@ * hashfunc.c * Support functions for hash access method. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -27,7 +27,17 @@ #include "postgres.h" #include "access/hash.h" +#include "utils/builtins.h" +/* + * Datatype-specific hash functions. + * + * These support both hash indexes and hash joins. + * + * NOTE: some of these are also used by catcache operations, without + * any direct connection to hash indexes. Also, the common hash_any + * routine is also used by dynahash tables. + */ /* Note: this is used for both "char" and boolean datatypes */ Datum @@ -130,23 +140,12 @@ hashoidvector(PG_FUNCTION_ARGS) return hash_any((unsigned char *) key->values, key->dim1 * sizeof(Oid)); } -Datum -hashint2vector(PG_FUNCTION_ARGS) -{ - int2vector *key = (int2vector *) PG_GETARG_POINTER(0); - - return hash_any((unsigned char *) key->values, key->dim1 * sizeof(int16)); -} - Datum hashname(PG_FUNCTION_ARGS) { char *key = NameStr(*PG_GETARG_NAME(0)); - int keylen = strlen(key); - - Assert(keylen < NAMEDATALEN); /* else it's not truncated correctly */ - return hash_any((unsigned char *) key, keylen); + return hash_any((unsigned char *) key, strlen(key)); } Datum diff --git a/src/backend/access/hash/hashinsert.c b/src/backend/access/hash/hashinsert.c index acd2e64763..39c70d3a80 100644 --- a/src/backend/access/hash/hashinsert.c +++ b/src/backend/access/hash/hashinsert.c @@ -3,7 +3,7 @@ * hashinsert.c * Item insertion in hash tables for Postgres. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -28,18 +28,23 @@ void _hash_doinsert(Relation rel, IndexTuple itup) { - Buffer buf; + Buffer buf = InvalidBuffer; + Buffer bucket_buf; Buffer metabuf; HashMetaPage metap; BlockNumber blkno; - BlockNumber oldblkno = InvalidBlockNumber; - bool retry = false; + BlockNumber oldblkno; + bool retry; + Page metapage; Page page; HashPageOpaque pageopaque; Size itemsz; bool do_expand; uint32 hashkey; Bucket bucket; + uint32 maxbucket; + uint32 highmask; + uint32 lowmask; /* * Get the hash key for the item (it's stored in the index tuple itself). @@ -51,9 +56,11 @@ _hash_doinsert(Relation rel, IndexTuple itup) itemsz = MAXALIGN(itemsz); /* be safe, PageAddItem will do this but we * need to be consistent */ +restart_insert: /* Read the metapage */ metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ, LH_META_PAGE); - metap = HashPageGetMeta(BufferGetPage(metabuf)); + metapage = BufferGetPage(metabuf); + metap = HashPageGetMeta(metapage); /* * Check whether the item can fit on a hash page at all. (Eventually, we @@ -62,13 +69,16 @@ _hash_doinsert(Relation rel, IndexTuple itup) * * XXX this is useless code if we are only storing hash keys. */ - if (itemsz > HashMaxItemSize((Page) metap)) + if (itemsz > HashMaxItemSize(metapage)) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("index row size %zu exceeds hash maximum %zu", - itemsz, HashMaxItemSize((Page) metap)), + itemsz, HashMaxItemSize(metapage)), errhint("Values larger than a buffer page cannot be indexed."))); + oldblkno = InvalidBlockNumber; + retry = false; + /* * Loop until we get a lock on the correct target bucket. */ @@ -84,37 +94,72 @@ _hash_doinsert(Relation rel, IndexTuple itup) blkno = BUCKET_TO_BLKNO(metap, bucket); + /* + * Copy bucket mapping info now; refer the comment in + * _hash_expandtable where we copy this information before calling + * _hash_splitbucket to see why this is okay. + */ + maxbucket = metap->hashm_maxbucket; + highmask = metap->hashm_highmask; + lowmask = metap->hashm_lowmask; + /* Release metapage lock, but keep pin. */ - _hash_chgbufaccess(rel, metabuf, HASH_READ, HASH_NOLOCK); + LockBuffer(metabuf, BUFFER_LOCK_UNLOCK); /* - * If the previous iteration of this loop locked what is still the - * correct target bucket, we are done. Otherwise, drop any old lock - * and lock what now appears to be the correct bucket. + * If the previous iteration of this loop locked the primary page of + * what is still the correct target bucket, we are done. Otherwise, + * drop any old lock before acquiring the new one. */ if (retry) { if (oldblkno == blkno) break; - _hash_droplock(rel, oldblkno, HASH_SHARE); + _hash_relbuf(rel, buf); } - _hash_getlock(rel, blkno, HASH_SHARE); + + /* Fetch and lock the primary bucket page for the target bucket */ + buf = _hash_getbuf(rel, blkno, HASH_WRITE, LH_BUCKET_PAGE); /* * Reacquire metapage lock and check that no bucket split has taken * place while we were awaiting the bucket lock. */ - _hash_chgbufaccess(rel, metabuf, HASH_NOLOCK, HASH_READ); + LockBuffer(metabuf, BUFFER_LOCK_SHARE); oldblkno = blkno; retry = true; } - /* Fetch the primary bucket page for the bucket */ - buf = _hash_getbuf(rel, blkno, HASH_WRITE, LH_BUCKET_PAGE); + /* remember the primary bucket buffer to release the pin on it at end. */ + bucket_buf = buf; + page = BufferGetPage(buf); pageopaque = (HashPageOpaque) PageGetSpecialPointer(page); Assert(pageopaque->hasho_bucket == bucket); + /* + * If this bucket is in the process of being split, try to finish the + * split before inserting, because that might create room for the + * insertion to proceed without allocating an additional overflow page. + * It's only interesting to finish the split if we're trying to insert + * into the bucket from which we're removing tuples (the "old" bucket), + * not if we're trying to insert into the bucket into which tuples are + * being moved (the "new" bucket). + */ + if (H_BUCKET_BEING_SPLIT(pageopaque) && IsBufferCleanupOK(buf)) + { + /* release the lock on bucket buffer, before completing the split. */ + LockBuffer(buf, BUFFER_LOCK_UNLOCK); + + _hash_finish_split(rel, metabuf, buf, pageopaque->hasho_bucket, + maxbucket, highmask, lowmask); + + /* release the pin on old and meta buffer. retry for insert. */ + _hash_dropbuf(rel, buf); + _hash_dropbuf(rel, metabuf); + goto restart_insert; + } + /* Do the insertion */ while (PageGetFreeSpace(page) < itemsz) { @@ -127,9 +172,15 @@ _hash_doinsert(Relation rel, IndexTuple itup) { /* * ovfl page exists; go get it. if it doesn't have room, we'll - * find out next pass through the loop test above. + * find out next pass through the loop test above. we always + * release both the lock and pin if this is an overflow page, but + * only the lock if this is the primary bucket page, since the pin + * on the primary bucket must be retained throughout the scan. */ - _hash_relbuf(rel, buf); + if (buf != bucket_buf) + _hash_relbuf(rel, buf); + else + LockBuffer(buf, BUFFER_LOCK_UNLOCK); buf = _hash_getbuf(rel, nextblkno, HASH_WRITE, LH_OVERFLOW_PAGE); page = BufferGetPage(buf); } @@ -141,10 +192,10 @@ _hash_doinsert(Relation rel, IndexTuple itup) */ /* release our write lock without modifying buffer */ - _hash_chgbufaccess(rel, buf, HASH_READ, HASH_NOLOCK); + LockBuffer(buf, BUFFER_LOCK_UNLOCK); /* chain to a new overflow page */ - buf = _hash_addovflpage(rel, metabuf, buf); + buf = _hash_addovflpage(rel, metabuf, buf, (buf == bucket_buf) ? true : false); page = BufferGetPage(buf); /* should fit now, given test above */ @@ -158,17 +209,21 @@ _hash_doinsert(Relation rel, IndexTuple itup) /* found page with enough space, so add the item here */ (void) _hash_pgaddtup(rel, buf, itemsz, itup); - /* write and release the modified page */ - _hash_wrtbuf(rel, buf); - - /* We can drop the bucket lock now */ - _hash_droplock(rel, blkno, HASH_SHARE); + /* + * dirty and release the modified page. if the page we modified was an + * overflow page, we also need to separately drop the pin we retained on + * the primary bucket page. + */ + MarkBufferDirty(buf); + _hash_relbuf(rel, buf); + if (buf != bucket_buf) + _hash_dropbuf(rel, bucket_buf); /* * Write-lock the metapage so we can increment the tuple count. After * incrementing it, check to see if it's time for a split. */ - _hash_chgbufaccess(rel, metabuf, HASH_NOLOCK, HASH_WRITE); + LockBuffer(metabuf, BUFFER_LOCK_EXCLUSIVE); metap->hashm_ntuples += 1; @@ -177,7 +232,8 @@ _hash_doinsert(Relation rel, IndexTuple itup) (double) metap->hashm_ffactor * (metap->hashm_maxbucket + 1); /* Write out the metapage and drop lock, but keep pin */ - _hash_chgbufaccess(rel, metabuf, HASH_WRITE, HASH_NOLOCK); + MarkBufferDirty(metabuf); + LockBuffer(metabuf, BUFFER_LOCK_UNLOCK); /* Attempt to split if a split is needed */ if (do_expand) diff --git a/src/backend/access/hash/hashovfl.c b/src/backend/access/hash/hashovfl.c index db3e268a76..e8928efc1a 100644 --- a/src/backend/access/hash/hashovfl.c +++ b/src/backend/access/hash/hashovfl.c @@ -3,7 +3,7 @@ * hashovfl.c * Overflow page management code for the Postgres hash access method * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -82,23 +82,20 @@ blkno_to_bitno(HashMetaPage metap, BlockNumber ovflblkno) * * On entry, the caller must hold a pin but no lock on 'buf'. The pin is * dropped before exiting (we assume the caller is not interested in 'buf' - * anymore). The returned overflow page will be pinned and write-locked; - * it is guaranteed to be empty. + * anymore) if not asked to retain. The pin will be retained only for the + * primary bucket. The returned overflow page will be pinned and + * write-locked; it is guaranteed to be empty. * * The caller must hold a pin, but no lock, on the metapage buffer. * That buffer is returned in the same state. * - * The caller must hold at least share lock on the bucket, to ensure that - * no one else tries to compact the bucket meanwhile. This guarantees that - * 'buf' won't stop being part of the bucket while it's unlocked. - * * NB: since this could be executed concurrently by multiple processes, * one should not assume that the returned overflow page will be the * immediate successor of the originally passed 'buf'. Additional overflow * pages might have been added to the bucket chain in between. */ Buffer -_hash_addovflpage(Relation rel, Buffer metabuf, Buffer buf) +_hash_addovflpage(Relation rel, Buffer metabuf, Buffer buf, bool retain_pin) { Buffer ovflbuf; Page page; @@ -113,7 +110,7 @@ _hash_addovflpage(Relation rel, Buffer metabuf, Buffer buf) * Write-lock the tail page. It is okay to hold two buffer locks here * since there cannot be anyone else contending for access to ovflbuf. */ - _hash_chgbufaccess(rel, buf, HASH_NOLOCK, HASH_WRITE); + LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); /* probably redundant... */ _hash_checkpage(rel, buf, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE); @@ -131,7 +128,16 @@ _hash_addovflpage(Relation rel, Buffer metabuf, Buffer buf) break; /* we assume we do not need to write the unmodified page */ - _hash_relbuf(rel, buf); + if (retain_pin) + { + /* pin will be retained only for the primary bucket page */ + Assert(pageopaque->hasho_flag & LH_BUCKET_PAGE); + LockBuffer(buf, BUFFER_LOCK_UNLOCK); + } + else + _hash_relbuf(rel, buf); + + retain_pin = false; buf = _hash_getbuf(rel, nextblkno, HASH_WRITE, LH_OVERFLOW_PAGE); } @@ -149,7 +155,15 @@ _hash_addovflpage(Relation rel, Buffer metabuf, Buffer buf) /* logically chain overflow page to previous page */ pageopaque->hasho_nextblkno = BufferGetBlockNumber(ovflbuf); - _hash_wrtbuf(rel, buf); + MarkBufferDirty(buf); + if (retain_pin) + { + /* pin will be retained only for the primary bucket page */ + Assert(pageopaque->hasho_flag & LH_BUCKET_PAGE); + LockBuffer(buf, BUFFER_LOCK_UNLOCK); + } + else + _hash_relbuf(rel, buf); return ovflbuf; } @@ -183,7 +197,7 @@ _hash_getovflpage(Relation rel, Buffer metabuf) j; /* Get exclusive lock on the meta page */ - _hash_chgbufaccess(rel, metabuf, HASH_NOLOCK, HASH_WRITE); + LockBuffer(metabuf, BUFFER_LOCK_EXCLUSIVE); _hash_checkpage(rel, metabuf, LH_META_PAGE); metap = HashPageGetMeta(BufferGetPage(metabuf)); @@ -221,7 +235,7 @@ _hash_getovflpage(Relation rel, Buffer metabuf) last_inpage = BMPGSZ_BIT(metap) - 1; /* Release exclusive lock on metapage while reading bitmap page */ - _hash_chgbufaccess(rel, metabuf, HASH_READ, HASH_NOLOCK); + LockBuffer(metabuf, BUFFER_LOCK_UNLOCK); mapbuf = _hash_getbuf(rel, mapblkno, HASH_WRITE, LH_BITMAP_PAGE); mappage = BufferGetPage(mapbuf); @@ -240,7 +254,7 @@ _hash_getovflpage(Relation rel, Buffer metabuf) bit = 0; /* Reacquire exclusive lock on the meta page */ - _hash_chgbufaccess(rel, metabuf, HASH_NOLOCK, HASH_WRITE); + LockBuffer(metabuf, BUFFER_LOCK_EXCLUSIVE); } /* @@ -291,7 +305,8 @@ _hash_getovflpage(Relation rel, Buffer metabuf) metap->hashm_firstfree = bit + 1; /* Write updated metapage and release lock, but not pin */ - _hash_chgbufaccess(rel, metabuf, HASH_WRITE, HASH_NOLOCK); + MarkBufferDirty(metabuf); + LockBuffer(metabuf, BUFFER_LOCK_UNLOCK); return newbuf; @@ -301,10 +316,11 @@ _hash_getovflpage(Relation rel, Buffer metabuf) /* mark page "in use" in the bitmap */ SETBIT(freep, bit); - _hash_wrtbuf(rel, mapbuf); + MarkBufferDirty(mapbuf); + _hash_relbuf(rel, mapbuf); /* Reacquire exclusive lock on the meta page */ - _hash_chgbufaccess(rel, metabuf, HASH_NOLOCK, HASH_WRITE); + LockBuffer(metabuf, BUFFER_LOCK_EXCLUSIVE); /* convert bit to absolute bit number */ bit += (i << BMPG_SHIFT(metap)); @@ -321,12 +337,13 @@ _hash_getovflpage(Relation rel, Buffer metabuf) metap->hashm_firstfree = bit + 1; /* Write updated metapage and release lock, but not pin */ - _hash_chgbufaccess(rel, metabuf, HASH_WRITE, HASH_NOLOCK); + MarkBufferDirty(metabuf); + LockBuffer(metabuf, BUFFER_LOCK_UNLOCK); } else { /* We didn't change the metapage, so no need to write */ - _hash_chgbufaccess(rel, metabuf, HASH_READ, HASH_NOLOCK); + LockBuffer(metabuf, BUFFER_LOCK_UNLOCK); } /* Fetch, init, and return the recycled page */ @@ -369,21 +386,24 @@ _hash_firstfreebit(uint32 map) * Returns the block number of the page that followed the given page * in the bucket, or InvalidBlockNumber if no following page. * - * NB: caller must not hold lock on metapage, nor on either page that's - * adjacent in the bucket chain. The caller had better hold exclusive lock - * on the bucket, too. + * NB: caller must not hold lock on metapage, nor on page, that's next to + * ovflbuf in the bucket chain. We don't acquire the lock on page that's + * prior to ovflbuf in chain if it is same as wbuf because the caller already + * has a lock on same. */ BlockNumber -_hash_freeovflpage(Relation rel, Buffer ovflbuf, +_hash_freeovflpage(Relation rel, Buffer ovflbuf, Buffer wbuf, BufferAccessStrategy bstrategy) { HashMetaPage metap; Buffer metabuf; Buffer mapbuf; + Buffer prevbuf = InvalidBuffer; BlockNumber ovflblkno; BlockNumber prevblkno; BlockNumber blkno; BlockNumber nextblkno; + BlockNumber writeblkno; HashPageOpaque ovflopaque; Page ovflpage; Page mappage; @@ -400,6 +420,7 @@ _hash_freeovflpage(Relation rel, Buffer ovflbuf, ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage); nextblkno = ovflopaque->hasho_nextblkno; prevblkno = ovflopaque->hasho_prevblkno; + writeblkno = BufferGetBlockNumber(wbuf); bucket = ovflopaque->hasho_bucket; /* @@ -408,27 +429,38 @@ _hash_freeovflpage(Relation rel, Buffer ovflbuf, * in _hash_pageinit() when the page is reused.) */ MemSet(ovflpage, 0, BufferGetPageSize(ovflbuf)); - _hash_wrtbuf(rel, ovflbuf); + MarkBufferDirty(ovflbuf); + _hash_relbuf(rel, ovflbuf); /* * Fix up the bucket chain. this is a doubly-linked list, so we must fix * up the bucket chain members behind and ahead of the overflow page being - * deleted. No concurrency issues since we hold exclusive lock on the - * entire bucket. + * deleted. Concurrency issues are avoided by using lock chaining as + * described atop hashbucketcleanup. */ if (BlockNumberIsValid(prevblkno)) { - Buffer prevbuf = _hash_getbuf_with_strategy(rel, - prevblkno, - HASH_WRITE, + Page prevpage; + HashPageOpaque prevopaque; + + if (prevblkno == writeblkno) + prevbuf = wbuf; + else + prevbuf = _hash_getbuf_with_strategy(rel, + prevblkno, + HASH_WRITE, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE, - bstrategy); - Page prevpage = BufferGetPage(prevbuf); - HashPageOpaque prevopaque = (HashPageOpaque) PageGetSpecialPointer(prevpage); + bstrategy); + + prevpage = BufferGetPage(prevbuf); + prevopaque = (HashPageOpaque) PageGetSpecialPointer(prevpage); Assert(prevopaque->hasho_bucket == bucket); prevopaque->hasho_nextblkno = nextblkno; - _hash_wrtbuf(rel, prevbuf); + + MarkBufferDirty(prevbuf); + if (prevblkno != writeblkno) + _hash_relbuf(rel, prevbuf); } if (BlockNumberIsValid(nextblkno)) { @@ -442,7 +474,8 @@ _hash_freeovflpage(Relation rel, Buffer ovflbuf, Assert(nextopaque->hasho_bucket == bucket); nextopaque->hasho_prevblkno = prevblkno; - _hash_wrtbuf(rel, nextbuf); + MarkBufferDirty(nextbuf); + _hash_relbuf(rel, nextbuf); } /* Note: bstrategy is intentionally not used for metapage and bitmap */ @@ -462,7 +495,7 @@ _hash_freeovflpage(Relation rel, Buffer ovflbuf, blkno = metap->hashm_mapp[bitmappage]; /* Release metapage lock while we access the bitmap page */ - _hash_chgbufaccess(rel, metabuf, HASH_READ, HASH_NOLOCK); + LockBuffer(metabuf, BUFFER_LOCK_UNLOCK); /* Clear the bitmap bit to indicate that this overflow page is free */ mapbuf = _hash_getbuf(rel, blkno, HASH_WRITE, LH_BITMAP_PAGE); @@ -470,22 +503,19 @@ _hash_freeovflpage(Relation rel, Buffer ovflbuf, freep = HashPageGetBitmap(mappage); Assert(ISSET(freep, bitmapbit)); CLRBIT(freep, bitmapbit); - _hash_wrtbuf(rel, mapbuf); + MarkBufferDirty(mapbuf); + _hash_relbuf(rel, mapbuf); /* Get write-lock on metapage to update firstfree */ - _hash_chgbufaccess(rel, metabuf, HASH_NOLOCK, HASH_WRITE); + LockBuffer(metabuf, BUFFER_LOCK_EXCLUSIVE); /* if this is now the first free page, update hashm_firstfree */ if (ovflbitno < metap->hashm_firstfree) { metap->hashm_firstfree = ovflbitno; - _hash_wrtbuf(rel, metabuf); - } - else - { - /* no need to change metapage */ - _hash_relbuf(rel, metabuf); + MarkBufferDirty(metabuf); } + _hash_relbuf(rel, metabuf); return nextblkno; } @@ -535,8 +565,9 @@ _hash_initbitmap(Relation rel, HashMetaPage metap, BlockNumber blkno, freep = HashPageGetBitmap(pg); MemSet(freep, 0xFF, BMPGSZ_BYTE(metap)); - /* write out the new bitmap page (releasing write lock and pin) */ - _hash_wrtbuf(rel, buf); + /* dirty the new bitmap page, and release write lock and pin */ + MarkBufferDirty(buf); + _hash_relbuf(rel, buf); /* add the new bitmap page to the metapage's list of bitmaps */ /* metapage already has a write lock */ @@ -570,8 +601,15 @@ _hash_initbitmap(Relation rel, HashMetaPage metap, BlockNumber blkno, * required that to be true on entry as well, but it's a lot easier for * callers to leave empty overflow pages and let this guy clean it up. * - * Caller must hold exclusive lock on the target bucket. This allows - * us to safely lock multiple pages in the bucket. + * Caller must acquire cleanup lock on the primary page of the target + * bucket to exclude any scans that are in progress, which could easily + * be confused into returning the same tuple more than once or some tuples + * not at all by the rearrangement we are performing here. To prevent + * any concurrent scan to cross the squeeze scan we use lock chaining + * similar to hasbucketcleanup. Refer comments atop hashbucketcleanup. + * + * We need to retain a pin on the primary bucket to ensure that no concurrent + * split can start. * * Since this function is invoked in VACUUM, we provide an access strategy * parameter that controls fetches of the bucket pages. @@ -580,6 +618,7 @@ void _hash_squeezebucket(Relation rel, Bucket bucket, BlockNumber bucket_blkno, + Buffer bucket_buf, BufferAccessStrategy bstrategy) { BlockNumber wblkno; @@ -593,23 +632,20 @@ _hash_squeezebucket(Relation rel, bool wbuf_dirty; /* - * start squeezing into the base bucket page. + * start squeezing into the primary bucket page. */ wblkno = bucket_blkno; - wbuf = _hash_getbuf_with_strategy(rel, - wblkno, - HASH_WRITE, - LH_BUCKET_PAGE, - bstrategy); + wbuf = bucket_buf; wpage = BufferGetPage(wbuf); wopaque = (HashPageOpaque) PageGetSpecialPointer(wpage); /* - * if there aren't any overflow pages, there's nothing to squeeze. + * if there aren't any overflow pages, there's nothing to squeeze. caller + * is responsible for releasing the pin on primary bucket page. */ if (!BlockNumberIsValid(wopaque->hasho_nextblkno)) { - _hash_relbuf(rel, wbuf); + LockBuffer(wbuf, BUFFER_LOCK_UNLOCK); return; } @@ -646,6 +682,7 @@ _hash_squeezebucket(Relation rel, OffsetNumber maxroffnum; OffsetNumber deletable[MaxOffsetNumber]; int ndeletable = 0; + bool retain_pin = false; /* Scan each tuple in "read" page */ maxroffnum = PageGetMaxOffsetNumber(rpage); @@ -656,6 +693,10 @@ _hash_squeezebucket(Relation rel, IndexTuple itup; Size itemsz; + /* skip dead tuples */ + if (ItemIdIsDead(PageGetItemId(rpage, roffnum))) + continue; + itup = (IndexTuple) PageGetItem(rpage, PageGetItemId(rpage, roffnum)); itemsz = IndexTupleDSize(*itup); @@ -667,13 +708,32 @@ _hash_squeezebucket(Relation rel, */ while (PageGetFreeSpace(wpage) < itemsz) { + Buffer next_wbuf = InvalidBuffer; + Assert(!PageIsEmpty(wpage)); + if (wblkno == bucket_blkno) + retain_pin = true; + wblkno = wopaque->hasho_nextblkno; Assert(BlockNumberIsValid(wblkno)); + /* don't need to move to next page if we reached the read page */ + if (wblkno != rblkno) + next_wbuf = _hash_getbuf_with_strategy(rel, + wblkno, + HASH_WRITE, + LH_OVERFLOW_PAGE, + bstrategy); + + /* + * release the lock on previous page after acquiring the lock + * on next page + */ if (wbuf_dirty) - _hash_wrtbuf(rel, wbuf); + MarkBufferDirty(wbuf); + if (retain_pin) + LockBuffer(wbuf, BUFFER_LOCK_UNLOCK); else _hash_relbuf(rel, wbuf); @@ -684,22 +744,18 @@ _hash_squeezebucket(Relation rel, { /* Delete tuples we already moved off read page */ PageIndexMultiDelete(rpage, deletable, ndeletable); - _hash_wrtbuf(rel, rbuf); + MarkBufferDirty(rbuf); } - else - _hash_relbuf(rel, rbuf); + _hash_relbuf(rel, rbuf); return; } - wbuf = _hash_getbuf_with_strategy(rel, - wblkno, - HASH_WRITE, - LH_OVERFLOW_PAGE, - bstrategy); + wbuf = next_wbuf; wpage = BufferGetPage(wbuf); wopaque = (HashPageOpaque) PageGetSpecialPointer(wpage); Assert(wopaque->hasho_bucket == bucket); wbuf_dirty = false; + retain_pin = false; } /* @@ -724,29 +780,28 @@ _hash_squeezebucket(Relation rel, * Tricky point here: if our read and write pages are adjacent in the * bucket chain, our write lock on wbuf will conflict with * _hash_freeovflpage's attempt to update the sibling links of the - * removed page. However, in that case we are done anyway, so we can - * simply drop the write lock before calling _hash_freeovflpage. + * removed page. In that case, we don't need to lock it again. */ rblkno = ropaque->hasho_prevblkno; Assert(BlockNumberIsValid(rblkno)); + /* free this overflow page (releases rbuf) */ + _hash_freeovflpage(rel, rbuf, wbuf, bstrategy); + + if (wbuf_dirty) + MarkBufferDirty(wbuf); + /* are we freeing the page adjacent to wbuf? */ if (rblkno == wblkno) { - /* yes, so release wbuf lock first */ - if (wbuf_dirty) - _hash_wrtbuf(rel, wbuf); + /* retain the pin on primary bucket page till end of bucket scan */ + if (wblkno == bucket_blkno) + LockBuffer(wbuf, BUFFER_LOCK_UNLOCK); else _hash_relbuf(rel, wbuf); - /* free this overflow page (releases rbuf) */ - _hash_freeovflpage(rel, rbuf, bstrategy); - /* done */ return; } - /* free this overflow page, then get the previous one */ - _hash_freeovflpage(rel, rbuf, bstrategy); - rbuf = _hash_getbuf_with_strategy(rel, rblkno, HASH_WRITE, diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c index 178463fcb6..9430794207 100644 --- a/src/backend/access/hash/hashpage.c +++ b/src/backend/access/hash/hashpage.c @@ -3,7 +3,7 @@ * hashpage.c * Hash table page management code for the Postgres hash access method * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -38,10 +38,14 @@ static bool _hash_alloc_buckets(Relation rel, BlockNumber firstblock, uint32 nblocks); static void _hash_splitbucket(Relation rel, Buffer metabuf, Bucket obucket, Bucket nbucket, - BlockNumber start_oblkno, + Buffer obuf, Buffer nbuf, uint32 maxbucket, uint32 highmask, uint32 lowmask); +static void _hash_splitbucket_guts(Relation rel, Buffer metabuf, + Bucket obucket, Bucket nbucket, Buffer obuf, + Buffer nbuf, HTAB *htab, uint32 maxbucket, + uint32 highmask, uint32 lowmask); /* @@ -54,46 +58,6 @@ static void _hash_splitbucket(Relation rel, Buffer metabuf, #define USELOCKING(rel) (!RELATION_IS_LOCAL(rel)) -/* - * _hash_getlock() -- Acquire an lmgr lock. - * - * 'whichlock' should the block number of a bucket's primary bucket page to - * acquire the per-bucket lock. (See README for details of the use of these - * locks.) - * - * 'access' must be HASH_SHARE or HASH_EXCLUSIVE. - */ -void -_hash_getlock(Relation rel, BlockNumber whichlock, int access) -{ - if (USELOCKING(rel)) - LockPage(rel, whichlock, access); -} - -/* - * _hash_try_getlock() -- Acquire an lmgr lock, but only if it's free. - * - * Same as above except we return FALSE without blocking if lock isn't free. - */ -bool -_hash_try_getlock(Relation rel, BlockNumber whichlock, int access) -{ - if (USELOCKING(rel)) - return ConditionalLockPage(rel, whichlock, access); - else - return true; -} - -/* - * _hash_droplock() -- Release an lmgr lock. - */ -void -_hash_droplock(Relation rel, BlockNumber whichlock, int access) -{ - if (USELOCKING(rel)) - UnlockPage(rel, whichlock, access); -} - /* * _hash_getbuf() -- Get a buffer by block number for read or write. * @@ -131,6 +95,35 @@ _hash_getbuf(Relation rel, BlockNumber blkno, int access, int flags) return buf; } +/* + * _hash_getbuf_with_condlock_cleanup() -- Try to get a buffer for cleanup. + * + * We read the page and try to acquire a cleanup lock. If we get it, + * we return the buffer; otherwise, we return InvalidBuffer. + */ +Buffer +_hash_getbuf_with_condlock_cleanup(Relation rel, BlockNumber blkno, int flags) +{ + Buffer buf; + + if (blkno == P_NEW) + elog(ERROR, "hash AM does not use P_NEW"); + + buf = ReadBuffer(rel, blkno); + + if (!ConditionalLockBufferForCleanup(buf)) + { + ReleaseBuffer(buf); + return InvalidBuffer; + } + + /* ref count and lock type are correct */ + + _hash_checkpage(rel, buf, flags); + + return buf; +} + /* * _hash_getinitbuf() -- Get and initialize a buffer by block number. * @@ -266,48 +259,34 @@ _hash_dropbuf(Relation rel, Buffer buf) } /* - * _hash_wrtbuf() -- write a hash page to disk. - * - * This routine releases the lock held on the buffer and our refcount - * for it. It is an error to call _hash_wrtbuf() without a write lock - * and a pin on the buffer. - * - * NOTE: this routine should go away when/if hash indexes are WAL-ified. - * The correct sequence of operations is to mark the buffer dirty, then - * write the WAL record, then release the lock and pin; so marking dirty - * can't be combined with releasing. - */ -void -_hash_wrtbuf(Relation rel, Buffer buf) -{ - MarkBufferDirty(buf); - UnlockReleaseBuffer(buf); -} - -/* - * _hash_chgbufaccess() -- Change the lock type on a buffer, without - * dropping our pin on it. - * - * from_access and to_access may be HASH_READ, HASH_WRITE, or HASH_NOLOCK, - * the last indicating that no buffer-level lock is held or wanted. + * _hash_dropscanbuf() -- release buffers used in scan. * - * When from_access == HASH_WRITE, we assume the buffer is dirty and tell - * bufmgr it must be written out. If the caller wants to release a write - * lock on a page that's not been modified, it's okay to pass from_access - * as HASH_READ (a bit ugly, but handy in some places). + * This routine unpins the buffers used during scan on which we + * hold no lock. */ void -_hash_chgbufaccess(Relation rel, - Buffer buf, - int from_access, - int to_access) +_hash_dropscanbuf(Relation rel, HashScanOpaque so) { - if (from_access == HASH_WRITE) - MarkBufferDirty(buf); - if (from_access != HASH_NOLOCK) - LockBuffer(buf, BUFFER_LOCK_UNLOCK); - if (to_access != HASH_NOLOCK) - LockBuffer(buf, to_access); + /* release pin we hold on primary bucket page */ + if (BufferIsValid(so->hashso_bucket_buf) && + so->hashso_bucket_buf != so->hashso_curbuf) + _hash_dropbuf(rel, so->hashso_bucket_buf); + so->hashso_bucket_buf = InvalidBuffer; + + /* release pin we hold on primary bucket page of bucket being split */ + if (BufferIsValid(so->hashso_split_bucket_buf) && + so->hashso_split_bucket_buf != so->hashso_curbuf) + _hash_dropbuf(rel, so->hashso_split_bucket_buf); + so->hashso_split_bucket_buf = InvalidBuffer; + + /* release any pin we still hold */ + if (BufferIsValid(so->hashso_curbuf)) + _hash_dropbuf(rel, so->hashso_curbuf); + so->hashso_curbuf = InvalidBuffer; + + /* reset split scan */ + so->hashso_buc_populated = false; + so->hashso_buc_split = false; } @@ -441,7 +420,8 @@ _hash_metapinit(Relation rel, double num_tuples, ForkNumber forkNum) * won't accomplish anything. It's a bad idea to hold buffer locks for * long intervals in any case, since that can block the bgwriter. */ - _hash_chgbufaccess(rel, metabuf, HASH_WRITE, HASH_NOLOCK); + MarkBufferDirty(metabuf); + LockBuffer(metabuf, BUFFER_LOCK_UNLOCK); /* * Initialize the first N buckets @@ -459,11 +439,12 @@ _hash_metapinit(Relation rel, double num_tuples, ForkNumber forkNum) pageopaque->hasho_bucket = i; pageopaque->hasho_flag = LH_BUCKET_PAGE; pageopaque->hasho_page_id = HASHO_PAGE_ID; - _hash_wrtbuf(rel, buf); + MarkBufferDirty(buf); + _hash_relbuf(rel, buf); } /* Now reacquire buffer lock on metapage */ - _hash_chgbufaccess(rel, metabuf, HASH_NOLOCK, HASH_WRITE); + LockBuffer(metabuf, BUFFER_LOCK_EXCLUSIVE); /* * Initialize first bitmap page @@ -471,7 +452,8 @@ _hash_metapinit(Relation rel, double num_tuples, ForkNumber forkNum) _hash_initbitmap(rel, metap, num_buckets + 1, forkNum); /* all done */ - _hash_wrtbuf(rel, metabuf); + MarkBufferDirty(metabuf); + _hash_relbuf(rel, metabuf); return num_buckets; } @@ -489,9 +471,11 @@ _hash_pageinit(Page page, Size size) /* * Attempt to expand the hash table by creating one new bucket. * - * This will silently do nothing if it cannot get the needed locks. + * This will silently do nothing if we don't get cleanup lock on old or + * new bucket. * - * The caller should hold no locks on the hash index. + * Complete the pending splits and remove the tuples from old bucket, + * if there are any left over from the previous split. * * The caller must hold a pin, but no lock, on the metapage buffer. * The buffer is returned in the same state. @@ -506,15 +490,20 @@ _hash_expandtable(Relation rel, Buffer metabuf) BlockNumber start_oblkno; BlockNumber start_nblkno; Buffer buf_nblkno; + Buffer buf_oblkno; + Page opage; + HashPageOpaque oopaque; uint32 maxbucket; uint32 highmask; uint32 lowmask; +restart_expand: + /* * Write-lock the meta page. It used to be necessary to acquire a * heavyweight lock to begin a split, but that is no longer required. */ - _hash_chgbufaccess(rel, metabuf, HASH_NOLOCK, HASH_WRITE); + LockBuffer(metabuf, BUFFER_LOCK_EXCLUSIVE); _hash_checkpage(rel, metabuf, LH_META_PAGE); metap = HashPageGetMeta(BufferGetPage(metabuf)); @@ -548,11 +537,16 @@ _hash_expandtable(Relation rel, Buffer metabuf) goto fail; /* - * Determine which bucket is to be split, and attempt to lock the old - * bucket. If we can't get the lock, give up. + * Determine which bucket is to be split, and attempt to take cleanup lock + * on the old bucket. If we can't get the lock, give up. + * + * The cleanup lock protects us not only against other backends, but + * against our own backend as well. * - * The lock protects us against other backends, but not against our own - * backend. Must check for active scans separately. + * The cleanup lock is mainly to protect the split from concurrent + * inserts. See src/backend/access/hash/README, Lock Definitions for + * further details. Due to this locking restriction, if there is any + * pending scan, the split will give up which is not good, but harmless. */ new_bucket = metap->hashm_maxbucket + 1; @@ -560,14 +554,86 @@ _hash_expandtable(Relation rel, Buffer metabuf) start_oblkno = BUCKET_TO_BLKNO(metap, old_bucket); - if (_hash_has_active_scan(rel, old_bucket)) + buf_oblkno = _hash_getbuf_with_condlock_cleanup(rel, start_oblkno, LH_BUCKET_PAGE); + if (!buf_oblkno) goto fail; - if (!_hash_try_getlock(rel, start_oblkno, HASH_EXCLUSIVE)) - goto fail; + opage = BufferGetPage(buf_oblkno); + oopaque = (HashPageOpaque) PageGetSpecialPointer(opage); + + /* + * We want to finish the split from a bucket as there is no apparent + * benefit by not doing so and it will make the code complicated to finish + * the split that involves multiple buckets considering the case where new + * split also fails. We don't need to consider the new bucket for + * completing the split here as it is not possible that a re-split of new + * bucket starts when there is still a pending split from old bucket. + */ + if (H_BUCKET_BEING_SPLIT(oopaque)) + { + /* + * Copy bucket mapping info now; refer the comment in code below where + * we copy this information before calling _hash_splitbucket to see + * why this is okay. + */ + maxbucket = metap->hashm_maxbucket; + highmask = metap->hashm_highmask; + lowmask = metap->hashm_lowmask; + + /* + * Release the lock on metapage and old_bucket, before completing the + * split. + */ + LockBuffer(metabuf, BUFFER_LOCK_UNLOCK); + LockBuffer(buf_oblkno, BUFFER_LOCK_UNLOCK); + + _hash_finish_split(rel, metabuf, buf_oblkno, old_bucket, maxbucket, + highmask, lowmask); + + /* release the pin on old buffer and retry for expand. */ + _hash_dropbuf(rel, buf_oblkno); + + goto restart_expand; + } /* - * Likewise lock the new bucket (should never fail). + * Clean the tuples remained from the previous split. This operation + * requires cleanup lock and we already have one on the old bucket, so + * let's do it. We also don't want to allow further splits from the bucket + * till the garbage of previous split is cleaned. This has two + * advantages; first, it helps in avoiding the bloat due to garbage and + * second is, during cleanup of bucket, we are always sure that the + * garbage tuples belong to most recently split bucket. On the contrary, + * if we allow cleanup of bucket after meta page is updated to indicate + * the new split and before the actual split, the cleanup operation won't + * be able to decide whether the tuple has been moved to the newly created + * bucket and ended up deleting such tuples. + */ + if (H_NEEDS_SPLIT_CLEANUP(oopaque)) + { + /* + * Copy bucket mapping info now; refer to the comment in code below + * where we copy this information before calling _hash_splitbucket + * to see why this is okay. + */ + maxbucket = metap->hashm_maxbucket; + highmask = metap->hashm_highmask; + lowmask = metap->hashm_lowmask; + + /* Release the metapage lock. */ + LockBuffer(metabuf, BUFFER_LOCK_UNLOCK); + + hashbucketcleanup(rel, old_bucket, buf_oblkno, start_oblkno, NULL, + maxbucket, highmask, lowmask, NULL, NULL, true, + NULL, NULL); + + _hash_dropbuf(rel, buf_oblkno); + + goto restart_expand; + } + + /* + * There shouldn't be any active scan on new bucket. * * Note: it is safe to compute the new bucket's blkno here, even though we * may still need to update the BUCKET_TO_BLKNO mapping. This is because @@ -576,12 +642,6 @@ _hash_expandtable(Relation rel, Buffer metabuf) */ start_nblkno = BUCKET_TO_BLKNO(metap, new_bucket); - if (_hash_has_active_scan(rel, new_bucket)) - elog(ERROR, "scan in progress on supposedly new bucket"); - - if (!_hash_try_getlock(rel, start_nblkno, HASH_EXCLUSIVE)) - elog(ERROR, "could not get lock on supposedly new bucket"); - /* * If the split point is increasing (hashm_maxbucket's log base 2 * increases), we need to allocate a new batch of bucket pages. @@ -600,8 +660,7 @@ _hash_expandtable(Relation rel, Buffer metabuf) if (!_hash_alloc_buckets(rel, start_nblkno, new_bucket)) { /* can't split due to BlockNumber overflow */ - _hash_droplock(rel, start_oblkno, HASH_EXCLUSIVE); - _hash_droplock(rel, start_nblkno, HASH_EXCLUSIVE); + _hash_relbuf(rel, buf_oblkno); goto fail; } } @@ -609,9 +668,18 @@ _hash_expandtable(Relation rel, Buffer metabuf) /* * Physically allocate the new bucket's primary page. We want to do this * before changing the metapage's mapping info, in case we can't get the - * disk space. + * disk space. Ideally, we don't need to check for cleanup lock on new + * bucket as no other backend could find this bucket unless meta page is + * updated. However, it is good to be consistent with old bucket locking. */ buf_nblkno = _hash_getnewbuf(rel, start_nblkno, MAIN_FORKNUM); + if (!IsBufferCleanupOK(buf_nblkno)) + { + _hash_relbuf(rel, buf_oblkno); + _hash_relbuf(rel, buf_nblkno); + goto fail; + } + /* * Okay to proceed with split. Update the metapage bucket mapping info. @@ -660,25 +728,22 @@ _hash_expandtable(Relation rel, Buffer metabuf) lowmask = metap->hashm_lowmask; /* Write out the metapage and drop lock, but keep pin */ - _hash_chgbufaccess(rel, metabuf, HASH_WRITE, HASH_NOLOCK); + MarkBufferDirty(metabuf); + LockBuffer(metabuf, BUFFER_LOCK_UNLOCK); /* Relocate records to the new bucket */ _hash_splitbucket(rel, metabuf, old_bucket, new_bucket, - start_oblkno, buf_nblkno, + buf_oblkno, buf_nblkno, maxbucket, highmask, lowmask); - /* Release bucket locks, allowing others to access them */ - _hash_droplock(rel, start_oblkno, HASH_EXCLUSIVE); - _hash_droplock(rel, start_nblkno, HASH_EXCLUSIVE); - return; /* Here if decide not to split or fail to acquire old bucket lock */ fail: /* We didn't write the metapage, so just drop lock */ - _hash_chgbufaccess(rel, metabuf, HASH_READ, HASH_NOLOCK); + LockBuffer(metabuf, BUFFER_LOCK_UNLOCK); } @@ -738,13 +803,17 @@ _hash_alloc_buckets(Relation rel, BlockNumber firstblock, uint32 nblocks) * belong in the new bucket, and compress out any free space in the old * bucket. * - * The caller must hold exclusive locks on both buckets to ensure that + * The caller must hold cleanup locks on both buckets to ensure that * no one else is trying to access them (see README). * * The caller must hold a pin, but no lock, on the metapage buffer. * The buffer is returned in the same state. (The metapage is only * touched if it becomes necessary to add or remove overflow pages.) * + * Split needs to retain pin on primary bucket pages of both old and new + * buckets till end of operation. This is to prevent vacuum from starting + * while a split is in progress. + * * In addition, the caller must have created the new bucket's base page, * which is passed in buffer nbuf, pinned and write-locked. That lock and * pin are released here. (The API is set up this way because we must do @@ -756,37 +825,86 @@ _hash_splitbucket(Relation rel, Buffer metabuf, Bucket obucket, Bucket nbucket, - BlockNumber start_oblkno, + Buffer obuf, Buffer nbuf, uint32 maxbucket, uint32 highmask, uint32 lowmask) { - Buffer obuf; Page opage; Page npage; HashPageOpaque oopaque; HashPageOpaque nopaque; - /* - * It should be okay to simultaneously write-lock pages from each bucket, - * since no one else can be trying to acquire buffer lock on pages of - * either bucket. - */ - obuf = _hash_getbuf(rel, start_oblkno, HASH_WRITE, LH_BUCKET_PAGE); opage = BufferGetPage(obuf); oopaque = (HashPageOpaque) PageGetSpecialPointer(opage); + /* + * Mark the old bucket to indicate that split is in progress. At + * operation end, we clear split-in-progress flag. + */ + oopaque->hasho_flag |= LH_BUCKET_BEING_SPLIT; + npage = BufferGetPage(nbuf); - /* initialize the new bucket's primary page */ + /* + * initialize the new bucket's primary page and mark it to indicate that + * split is in progress. + */ nopaque = (HashPageOpaque) PageGetSpecialPointer(npage); nopaque->hasho_prevblkno = InvalidBlockNumber; nopaque->hasho_nextblkno = InvalidBlockNumber; nopaque->hasho_bucket = nbucket; - nopaque->hasho_flag = LH_BUCKET_PAGE; + nopaque->hasho_flag = LH_BUCKET_PAGE | LH_BUCKET_BEING_POPULATED; nopaque->hasho_page_id = HASHO_PAGE_ID; + _hash_splitbucket_guts(rel, metabuf, obucket, + nbucket, obuf, nbuf, NULL, + maxbucket, highmask, lowmask); + + /* all done, now release the locks and pins on primary buckets. */ + _hash_relbuf(rel, obuf); + _hash_relbuf(rel, nbuf); +} + +/* + * _hash_splitbucket_guts -- Helper function to perform the split operation + * + * This routine is used to partition the tuples between old and new bucket and + * to finish incomplete split operations. To finish the previously + * interrupted split operation, caller needs to fill htab. If htab is set, then + * we skip the movement of tuples that exists in htab, otherwise NULL value of + * htab indicates movement of all the tuples that belong to new bucket. + * + * Caller needs to lock and unlock the old and new primary buckets. + */ +static void +_hash_splitbucket_guts(Relation rel, + Buffer metabuf, + Bucket obucket, + Bucket nbucket, + Buffer obuf, + Buffer nbuf, + HTAB *htab, + uint32 maxbucket, + uint32 highmask, + uint32 lowmask) +{ + Buffer bucket_obuf; + Buffer bucket_nbuf; + Page opage; + Page npage; + HashPageOpaque oopaque; + HashPageOpaque nopaque; + + bucket_obuf = obuf; + opage = BufferGetPage(obuf); + oopaque = (HashPageOpaque) PageGetSpecialPointer(opage); + + bucket_nbuf = nbuf; + npage = BufferGetPage(nbuf); + nopaque = (HashPageOpaque) PageGetSpecialPointer(npage); + /* * Partition the tuples in the old bucket between the old bucket and the * new bucket, advancing along the old bucket's overflow bucket chain and @@ -798,8 +916,6 @@ _hash_splitbucket(Relation rel, BlockNumber oblkno; OffsetNumber ooffnum; OffsetNumber omaxoffnum; - OffsetNumber deletable[MaxOffsetNumber]; - int ndeletable = 0; /* Scan each tuple in old page */ omaxoffnum = PageGetMaxOffsetNumber(opage); @@ -810,39 +926,63 @@ _hash_splitbucket(Relation rel, IndexTuple itup; Size itemsz; Bucket bucket; + bool found = false; + + /* skip dead tuples */ + if (ItemIdIsDead(PageGetItemId(opage, ooffnum))) + continue; /* - * Fetch the item's hash key (conveniently stored in the item) and - * determine which bucket it now belongs in. + * Before inserting a tuple, probe the hash table containing TIDs + * of tuples belonging to new bucket, if we find a match, then + * skip that tuple, else fetch the item's hash key (conveniently + * stored in the item) and determine which bucket it now belongs + * in. */ itup = (IndexTuple) PageGetItem(opage, PageGetItemId(opage, ooffnum)); + + if (htab) + (void) hash_search(htab, &itup->t_tid, HASH_FIND, &found); + + if (found) + continue; + bucket = _hash_hashkey2bucket(_hash_get_indextuple_hashkey(itup), maxbucket, highmask, lowmask); if (bucket == nbucket) { + IndexTuple new_itup; + + /* + * make a copy of index tuple as we have to scribble on it. + */ + new_itup = CopyIndexTuple(itup); + + /* + * mark the index tuple as moved by split, such tuples are + * skipped by scan if there is split in progress for a bucket. + */ + new_itup->t_info |= INDEX_MOVED_BY_SPLIT_MASK; + /* * insert the tuple into the new bucket. if it doesn't fit on * the current page in the new bucket, we must allocate a new * overflow page and place the tuple on that page instead. - * - * XXX we have a problem here if we fail to get space for a - * new overflow page: we'll error out leaving the bucket split - * only partially complete, meaning the index is corrupt, - * since searches may fail to find entries they should find. */ - itemsz = IndexTupleDSize(*itup); + itemsz = IndexTupleDSize(*new_itup); itemsz = MAXALIGN(itemsz); if (PageGetFreeSpace(npage) < itemsz) { /* write out nbuf and drop lock, but keep pin */ - _hash_chgbufaccess(rel, nbuf, HASH_WRITE, HASH_NOLOCK); + MarkBufferDirty(nbuf); + LockBuffer(nbuf, BUFFER_LOCK_UNLOCK); /* chain to a new overflow page */ - nbuf = _hash_addovflpage(rel, metabuf, nbuf); + nbuf = _hash_addovflpage(rel, metabuf, nbuf, (nbuf == bucket_nbuf) ? true : false); npage = BufferGetPage(nbuf); - /* we don't need nopaque within the loop */ + nopaque = (HashPageOpaque) PageGetSpecialPointer(npage); } /* @@ -852,12 +992,10 @@ _hash_splitbucket(Relation rel, * Possible future improvement: accumulate all the items for * the new page and qsort them before insertion. */ - (void) _hash_pgaddtup(rel, nbuf, itemsz, itup); + (void) _hash_pgaddtup(rel, nbuf, itemsz, new_itup); - /* - * Mark tuple for deletion from old page. - */ - deletable[ndeletable++] = ooffnum; + /* be tidy */ + pfree(new_itup); } else { @@ -870,15 +1008,9 @@ _hash_splitbucket(Relation rel, oblkno = oopaque->hasho_nextblkno; - /* - * Done scanning this old page. If we moved any tuples, delete them - * from the old page. - */ - if (ndeletable > 0) - { - PageIndexMultiDelete(opage, deletable, ndeletable); - _hash_wrtbuf(rel, obuf); - } + /* retain the pin on the old primary bucket */ + if (obuf == bucket_obuf) + LockBuffer(obuf, BUFFER_LOCK_UNLOCK); else _hash_relbuf(rel, obuf); @@ -887,18 +1019,175 @@ _hash_splitbucket(Relation rel, break; /* Else, advance to next old page */ - obuf = _hash_getbuf(rel, oblkno, HASH_WRITE, LH_OVERFLOW_PAGE); + obuf = _hash_getbuf(rel, oblkno, HASH_READ, LH_OVERFLOW_PAGE); opage = BufferGetPage(obuf); oopaque = (HashPageOpaque) PageGetSpecialPointer(opage); } /* * We're at the end of the old bucket chain, so we're done partitioning - * the tuples. Before quitting, call _hash_squeezebucket to ensure the - * tuples remaining in the old bucket (including the overflow pages) are - * packed as tightly as possible. The new bucket is already tight. + * the tuples. Mark the old and new buckets to indicate split is + * finished. + * + * To avoid deadlocks due to locking order of buckets, first lock the old + * bucket and then the new bucket. */ - _hash_wrtbuf(rel, nbuf); + if (nbuf == bucket_nbuf) + { + MarkBufferDirty(bucket_nbuf); + LockBuffer(bucket_nbuf, BUFFER_LOCK_UNLOCK); + } + else + { + MarkBufferDirty(nbuf); + _hash_relbuf(rel, nbuf); + } + + LockBuffer(bucket_obuf, BUFFER_LOCK_EXCLUSIVE); + opage = BufferGetPage(bucket_obuf); + oopaque = (HashPageOpaque) PageGetSpecialPointer(opage); + + LockBuffer(bucket_nbuf, BUFFER_LOCK_EXCLUSIVE); + npage = BufferGetPage(bucket_nbuf); + nopaque = (HashPageOpaque) PageGetSpecialPointer(npage); + + oopaque->hasho_flag &= ~LH_BUCKET_BEING_SPLIT; + nopaque->hasho_flag &= ~LH_BUCKET_BEING_POPULATED; + + /* + * After the split is finished, mark the old bucket to indicate that it + * contains deletable tuples. Vacuum will clear split-cleanup flag after + * deleting such tuples. + */ + oopaque->hasho_flag |= LH_BUCKET_NEEDS_SPLIT_CLEANUP; + + /* + * now write the buffers, here we don't release the locks as caller is + * responsible to release locks. + */ + MarkBufferDirty(bucket_obuf); + MarkBufferDirty(bucket_nbuf); +} + +/* + * _hash_finish_split() -- Finish the previously interrupted split operation + * + * To complete the split operation, we form the hash table of TIDs in new + * bucket which is then used by split operation to skip tuples that are + * already moved before the split operation was previously interrupted. + * + * The caller must hold a pin, but no lock, on the metapage and old bucket's + * primay page buffer. The buffers are returned in the same state. (The + * metapage is only touched if it becomes necessary to add or remove overflow + * pages.) + */ +void +_hash_finish_split(Relation rel, Buffer metabuf, Buffer obuf, Bucket obucket, + uint32 maxbucket, uint32 highmask, uint32 lowmask) +{ + HASHCTL hash_ctl; + HTAB *tidhtab; + Buffer bucket_nbuf = InvalidBuffer; + Buffer nbuf; + Page npage; + BlockNumber nblkno; + BlockNumber bucket_nblkno; + HashPageOpaque npageopaque; + Bucket nbucket; + bool found; + + /* Initialize hash tables used to track TIDs */ + memset(&hash_ctl, 0, sizeof(hash_ctl)); + hash_ctl.keysize = sizeof(ItemPointerData); + hash_ctl.entrysize = sizeof(ItemPointerData); + hash_ctl.hcxt = CurrentMemoryContext; + + tidhtab = + hash_create("bucket ctids", + 256, /* arbitrary initial size */ + &hash_ctl, + HASH_ELEM | HASH_BLOBS | HASH_CONTEXT); + + bucket_nblkno = nblkno = _hash_get_newblock_from_oldbucket(rel, obucket); + + /* + * Scan the new bucket and build hash table of TIDs + */ + for (;;) + { + OffsetNumber noffnum; + OffsetNumber nmaxoffnum; + + nbuf = _hash_getbuf(rel, nblkno, HASH_READ, + LH_BUCKET_PAGE | LH_OVERFLOW_PAGE); + + /* remember the primary bucket buffer to acquire cleanup lock on it. */ + if (nblkno == bucket_nblkno) + bucket_nbuf = nbuf; + + npage = BufferGetPage(nbuf); + npageopaque = (HashPageOpaque) PageGetSpecialPointer(npage); + + /* Scan each tuple in new page */ + nmaxoffnum = PageGetMaxOffsetNumber(npage); + for (noffnum = FirstOffsetNumber; + noffnum <= nmaxoffnum; + noffnum = OffsetNumberNext(noffnum)) + { + IndexTuple itup; + + /* Fetch the item's TID and insert it in hash table. */ + itup = (IndexTuple) PageGetItem(npage, + PageGetItemId(npage, noffnum)); + + (void) hash_search(tidhtab, &itup->t_tid, HASH_ENTER, &found); + + Assert(!found); + } + + nblkno = npageopaque->hasho_nextblkno; + + /* + * release our write lock without modifying buffer and ensure to + * retain the pin on primary bucket. + */ + if (nbuf == bucket_nbuf) + LockBuffer(nbuf, BUFFER_LOCK_UNLOCK); + else + _hash_relbuf(rel, nbuf); + + /* Exit loop if no more overflow pages in new bucket */ + if (!BlockNumberIsValid(nblkno)) + break; + } + + /* + * Conditionally get the cleanup lock on old and new buckets to perform + * the split operation. If we don't get the cleanup locks, silently give + * up and next insertion on old bucket will try again to complete the + * split. + */ + if (!ConditionalLockBufferForCleanup(obuf)) + { + hash_destroy(tidhtab); + return; + } + if (!ConditionalLockBufferForCleanup(bucket_nbuf)) + { + LockBuffer(obuf, BUFFER_LOCK_UNLOCK); + hash_destroy(tidhtab); + return; + } + + npage = BufferGetPage(bucket_nbuf); + npageopaque = (HashPageOpaque) PageGetSpecialPointer(npage); + nbucket = npageopaque->hasho_bucket; + + _hash_splitbucket_guts(rel, metabuf, obucket, + nbucket, obuf, bucket_nbuf, tidhtab, + maxbucket, highmask, lowmask); - _hash_squeezebucket(rel, obucket, start_oblkno, NULL); + _hash_relbuf(rel, bucket_nbuf); + LockBuffer(obuf, BUFFER_LOCK_UNLOCK); + hash_destroy(tidhtab); } diff --git a/src/backend/access/hash/hashscan.c b/src/backend/access/hash/hashscan.c deleted file mode 100644 index fe97ef201a..0000000000 --- a/src/backend/access/hash/hashscan.c +++ /dev/null @@ -1,153 +0,0 @@ -/*------------------------------------------------------------------------- - * - * hashscan.c - * manage scans on hash tables - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * src/backend/access/hash/hashscan.c - * - *------------------------------------------------------------------------- - */ - -#include "postgres.h" - -#include "access/hash.h" -#include "access/relscan.h" -#include "utils/memutils.h" -#include "utils/rel.h" -#include "utils/resowner.h" - - -/* - * We track all of a backend's active scans on hash indexes using a list - * of HashScanListData structs, which are allocated in TopMemoryContext. - * It's okay to use a long-lived context because we rely on the ResourceOwner - * mechanism to clean up unused entries after transaction or subtransaction - * abort. We can't safely keep the entries in the executor's per-query - * context, because that might be already freed before we get a chance to - * clean up the list. (XXX seems like there should be a better way to - * manage this...) - */ -typedef struct HashScanListData -{ - IndexScanDesc hashsl_scan; - ResourceOwner hashsl_owner; - struct HashScanListData *hashsl_next; -} HashScanListData; - -typedef HashScanListData *HashScanList; - -static HashScanList HashScans = NULL; - - -/* - * ReleaseResources_hash() --- clean up hash subsystem resources. - * - * This is here because it needs to touch this module's static var HashScans. - */ -void -ReleaseResources_hash(void) -{ - HashScanList l; - HashScanList prev; - HashScanList next; - - /* - * Release all HashScanList items belonging to the current ResourceOwner. - * Note that we do not release the underlying IndexScanDesc; that's in - * executor memory and will go away on its own (in fact quite possibly has - * gone away already, so we mustn't try to touch it here). - * - * Note: this should be a no-op during normal query shutdown. However, in - * an abort situation ExecutorEnd is not called and so there may be open - * index scans to clean up. - */ - prev = NULL; - - for (l = HashScans; l != NULL; l = next) - { - next = l->hashsl_next; - if (l->hashsl_owner == CurrentResourceOwner) - { - if (prev == NULL) - HashScans = next; - else - prev->hashsl_next = next; - - pfree(l); - /* prev does not change */ - } - else - prev = l; - } -} - -/* - * _hash_regscan() -- register a new scan. - */ -void -_hash_regscan(IndexScanDesc scan) -{ - HashScanList new_el; - - new_el = (HashScanList) MemoryContextAlloc(TopMemoryContext, - sizeof(HashScanListData)); - new_el->hashsl_scan = scan; - new_el->hashsl_owner = CurrentResourceOwner; - new_el->hashsl_next = HashScans; - HashScans = new_el; -} - -/* - * _hash_dropscan() -- drop a scan from the scan list - */ -void -_hash_dropscan(IndexScanDesc scan) -{ - HashScanList chk, - last; - - last = NULL; - for (chk = HashScans; - chk != NULL && chk->hashsl_scan != scan; - chk = chk->hashsl_next) - last = chk; - - if (chk == NULL) - elog(ERROR, "hash scan list trashed; cannot find 0x%p", (void *) scan); - - if (last == NULL) - HashScans = chk->hashsl_next; - else - last->hashsl_next = chk->hashsl_next; - - pfree(chk); -} - -/* - * Is there an active scan in this bucket? - */ -bool -_hash_has_active_scan(Relation rel, Bucket bucket) -{ - Oid relid = RelationGetRelid(rel); - HashScanList l; - - for (l = HashScans; l != NULL; l = l->hashsl_next) - { - if (relid == l->hashsl_scan->indexRelation->rd_id) - { - HashScanOpaque so = (HashScanOpaque) l->hashsl_scan->opaque; - - if (so->hashso_bucket_valid && - so->hashso_bucket == bucket) - return true; - } - } - - return false; -} diff --git a/src/backend/access/hash/hashsearch.c b/src/backend/access/hash/hashsearch.c index 48255584e1..a59ad6ff70 100644 --- a/src/backend/access/hash/hashsearch.c +++ b/src/backend/access/hash/hashsearch.c @@ -3,7 +3,7 @@ * hashsearch.c * search code for postgres hash tables * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -63,38 +63,94 @@ _hash_next(IndexScanDesc scan, ScanDirection dir) } /* - * Advance to next page in a bucket, if any. + * Advance to next page in a bucket, if any. If we are scanning the bucket + * being populated during split operation then this function advances to the + * bucket being split after the last bucket page of bucket being populated. */ static void -_hash_readnext(Relation rel, +_hash_readnext(IndexScanDesc scan, Buffer *bufp, Page *pagep, HashPageOpaque *opaquep) { BlockNumber blkno; + Relation rel = scan->indexRelation; + HashScanOpaque so = (HashScanOpaque) scan->opaque; + bool block_found = false; blkno = (*opaquep)->hasho_nextblkno; - _hash_relbuf(rel, *bufp); + + /* + * Retain the pin on primary bucket page till the end of scan. Refer the + * comments in _hash_first to know the reason of retaining pin. + */ + if (*bufp == so->hashso_bucket_buf || *bufp == so->hashso_split_bucket_buf) + LockBuffer(*bufp, BUFFER_LOCK_UNLOCK); + else + _hash_relbuf(rel, *bufp); + *bufp = InvalidBuffer; /* check for interrupts while we're not holding any buffer lock */ CHECK_FOR_INTERRUPTS(); if (BlockNumberIsValid(blkno)) { *bufp = _hash_getbuf(rel, blkno, HASH_READ, LH_OVERFLOW_PAGE); + block_found = true; + } + else if (so->hashso_buc_populated && !so->hashso_buc_split) + { + /* + * end of bucket, scan bucket being split if there was a split in + * progress at the start of scan. + */ + *bufp = so->hashso_split_bucket_buf; + + /* + * buffer for bucket being split must be valid as we acquire the pin + * on it before the start of scan and retain it till end of scan. + */ + Assert(BufferIsValid(*bufp)); + + LockBuffer(*bufp, BUFFER_LOCK_SHARE); + + /* + * setting hashso_buc_split to true indicates that we are scanning + * bucket being split. + */ + so->hashso_buc_split = true; + + block_found = true; + } + + if (block_found) + { *pagep = BufferGetPage(*bufp); *opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep); } } /* - * Advance to previous page in a bucket, if any. + * Advance to previous page in a bucket, if any. If the current scan has + * started during split operation then this function advances to bucket + * being populated after the first bucket page of bucket being split. */ static void -_hash_readprev(Relation rel, +_hash_readprev(IndexScanDesc scan, Buffer *bufp, Page *pagep, HashPageOpaque *opaquep) { BlockNumber blkno; + Relation rel = scan->indexRelation; + HashScanOpaque so = (HashScanOpaque) scan->opaque; blkno = (*opaquep)->hasho_prevblkno; - _hash_relbuf(rel, *bufp); + + /* + * Retain the pin on primary bucket page till the end of scan. Refer the + * comments in _hash_first to know the reason of retaining pin. + */ + if (*bufp == so->hashso_bucket_buf || *bufp == so->hashso_split_bucket_buf) + LockBuffer(*bufp, BUFFER_LOCK_UNLOCK); + else + _hash_relbuf(rel, *bufp); + *bufp = InvalidBuffer; /* check for interrupts while we're not holding any buffer lock */ CHECK_FOR_INTERRUPTS(); @@ -104,6 +160,41 @@ _hash_readprev(Relation rel, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE); *pagep = BufferGetPage(*bufp); *opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep); + + /* + * We always maintain the pin on bucket page for whole scan operation, + * so releasing the additional pin we have acquired here. + */ + if (*bufp == so->hashso_bucket_buf || *bufp == so->hashso_split_bucket_buf) + _hash_dropbuf(rel, *bufp); + } + else if (so->hashso_buc_populated && so->hashso_buc_split) + { + /* + * end of bucket, scan bucket being populated if there was a split in + * progress at the start of scan. + */ + *bufp = so->hashso_bucket_buf; + + /* + * buffer for bucket being populated must be valid as we acquire the + * pin on it before the start of scan and retain it till end of scan. + */ + Assert(BufferIsValid(*bufp)); + + LockBuffer(*bufp, BUFFER_LOCK_SHARE); + *pagep = BufferGetPage(*bufp); + *opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep); + + /* move to the end of bucket chain */ + while (BlockNumberIsValid((*opaquep)->hasho_nextblkno)) + _hash_readnext(scan, bufp, pagep, opaquep); + + /* + * setting hashso_buc_split to false indicates that we are scanning + * bucket being populated. + */ + so->hashso_buc_split = false; } } @@ -207,7 +298,7 @@ _hash_first(IndexScanDesc scan, ScanDirection dir) blkno = BUCKET_TO_BLKNO(metap, bucket); /* Release metapage lock, but keep pin. */ - _hash_chgbufaccess(rel, metabuf, HASH_READ, HASH_NOLOCK); + LockBuffer(metabuf, BUFFER_LOCK_UNLOCK); /* * If the previous iteration of this loop locked what is still the @@ -218,15 +309,17 @@ _hash_first(IndexScanDesc scan, ScanDirection dir) { if (oldblkno == blkno) break; - _hash_droplock(rel, oldblkno, HASH_SHARE); + _hash_relbuf(rel, buf); } - _hash_getlock(rel, blkno, HASH_SHARE); + + /* Fetch the primary bucket page for the bucket */ + buf = _hash_getbuf(rel, blkno, HASH_READ, LH_BUCKET_PAGE); /* * Reacquire metapage lock and check that no bucket split has taken * place while we were awaiting the bucket lock. */ - _hash_chgbufaccess(rel, metabuf, HASH_NOLOCK, HASH_READ); + LockBuffer(metabuf, BUFFER_LOCK_SHARE); oldblkno = blkno; retry = true; } @@ -234,22 +327,74 @@ _hash_first(IndexScanDesc scan, ScanDirection dir) /* done with the metapage */ _hash_dropbuf(rel, metabuf); - /* Update scan opaque state to show we have lock on the bucket */ - so->hashso_bucket = bucket; - so->hashso_bucket_valid = true; - so->hashso_bucket_blkno = blkno; - - /* Fetch the primary bucket page for the bucket */ - buf = _hash_getbuf(rel, blkno, HASH_READ, LH_BUCKET_PAGE); page = BufferGetPage(buf); opaque = (HashPageOpaque) PageGetSpecialPointer(page); Assert(opaque->hasho_bucket == bucket); + so->hashso_bucket_buf = buf; + + /* + * If a bucket split is in progress, then while scanning the bucket being + * populated, we need to skip tuples that were copied from bucket being + * split. We also need to maintain a pin on the bucket being split to + * ensure that split-cleanup work done by vacuum doesn't remove tuples + * from it till this scan is done. We need to maintain a pin on the + * bucket being populated to ensure that vacuum doesn't squeeze that + * bucket till this scan is complete; otherwise, the ordering of tuples + * can't be maintained during forward and backward scans. Here, we have + * to be cautious about locking order: first, acquire the lock on bucket + * being split; then, release the lock on it but not the pin; then, + * acquire a lock on bucket being populated and again re-verify whether + * the bucket split is still in progress. Acquiring the lock on bucket + * being split first ensures that the vacuum waits for this scan to + * finish. + */ + if (H_BUCKET_BEING_POPULATED(opaque)) + { + BlockNumber old_blkno; + Buffer old_buf; + + old_blkno = _hash_get_oldblock_from_newbucket(rel, bucket); + + /* + * release the lock on new bucket and re-acquire it after acquiring + * the lock on old bucket. + */ + LockBuffer(buf, BUFFER_LOCK_UNLOCK); + + old_buf = _hash_getbuf(rel, old_blkno, HASH_READ, LH_BUCKET_PAGE); + + /* + * remember the split bucket buffer so as to use it later for + * scanning. + */ + so->hashso_split_bucket_buf = old_buf; + LockBuffer(old_buf, BUFFER_LOCK_UNLOCK); + + LockBuffer(buf, BUFFER_LOCK_SHARE); + page = BufferGetPage(buf); + opaque = (HashPageOpaque) PageGetSpecialPointer(page); + Assert(opaque->hasho_bucket == bucket); + + if (H_BUCKET_BEING_POPULATED(opaque)) + so->hashso_buc_populated = true; + else + { + _hash_dropbuf(rel, so->hashso_split_bucket_buf); + so->hashso_split_bucket_buf = InvalidBuffer; + } + } + /* If a backwards scan is requested, move to the end of the chain */ if (ScanDirectionIsBackward(dir)) { - while (BlockNumberIsValid(opaque->hasho_nextblkno)) - _hash_readnext(rel, &buf, &page, &opaque); + /* + * Backward scans that start during split needs to start from end of + * bucket being split. + */ + while (BlockNumberIsValid(opaque->hasho_nextblkno) || + (so->hashso_buc_populated && !so->hashso_buc_split)) + _hash_readnext(scan, &buf, &page, &opaque); } /* Now find the first tuple satisfying the qualification */ @@ -273,6 +418,12 @@ _hash_first(IndexScanDesc scan, ScanDirection dir) * false. Else, return true and set the hashso_curpos for the * scan to the right thing. * + * Here we need to ensure that if the scan has started during split, then + * skip the tuples that are moved by split while scanning bucket being + * populated and then scan the bucket being split to cover all such + * tuples. This is done to ensure that we don't miss tuples in the scans + * that are started during split. + * * 'bufP' points to the current buffer, which is pinned and read-locked. * On success exit, we have pin and read-lock on whichever page * contains the right item; on failure, we have released all buffers. @@ -338,6 +489,19 @@ _hash_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir) { Assert(offnum >= FirstOffsetNumber); itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum)); + + /* + * skip the tuples that are moved by split operation + * for the scan that has started when split was in + * progress + */ + if (so->hashso_buc_populated && !so->hashso_buc_split && + (itup->t_info & INDEX_MOVED_BY_SPLIT_MASK)) + { + offnum = OffsetNumberNext(offnum); /* move forward */ + continue; + } + if (so->hashso_sk_hash == _hash_get_indextuple_hashkey(itup)) break; /* yes, so exit for-loop */ } @@ -345,7 +509,7 @@ _hash_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir) /* * ran off the end of this page, try the next */ - _hash_readnext(rel, &buf, &page, &opaque); + _hash_readnext(scan, &buf, &page, &opaque); if (BufferIsValid(buf)) { maxoff = PageGetMaxOffsetNumber(page); @@ -353,7 +517,6 @@ _hash_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir) } else { - /* end of bucket */ itup = NULL; break; /* exit for-loop */ } @@ -379,6 +542,19 @@ _hash_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir) { Assert(offnum <= maxoff); itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum)); + + /* + * skip the tuples that are moved by split operation + * for the scan that has started when split was in + * progress + */ + if (so->hashso_buc_populated && !so->hashso_buc_split && + (itup->t_info & INDEX_MOVED_BY_SPLIT_MASK)) + { + offnum = OffsetNumberPrev(offnum); /* move back */ + continue; + } + if (so->hashso_sk_hash == _hash_get_indextuple_hashkey(itup)) break; /* yes, so exit for-loop */ } @@ -386,7 +562,7 @@ _hash_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir) /* * ran off the end of this page, try the next */ - _hash_readprev(rel, &buf, &page, &opaque); + _hash_readprev(scan, &buf, &page, &opaque); if (BufferIsValid(buf)) { maxoff = PageGetMaxOffsetNumber(page); @@ -394,7 +570,6 @@ _hash_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir) } else { - /* end of bucket */ itup = NULL; break; /* exit for-loop */ } @@ -410,9 +585,16 @@ _hash_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir) if (itup == NULL) { - /* we ran off the end of the bucket without finding a match */ + /* + * We ran off the end of the bucket without finding a match. + * Release the pin on bucket buffers. Normally, such pins are + * released at end of scan, however scrolling cursors can + * reacquire the bucket lock and pin in the same scan multiple + * times. + */ *bufP = so->hashso_curbuf = InvalidBuffer; ItemPointerSetInvalid(current); + _hash_dropscanbuf(rel, so); return false; } diff --git a/src/backend/access/hash/hashsort.c b/src/backend/access/hash/hashsort.c index 8938ab5b24..ea8f109a57 100644 --- a/src/backend/access/hash/hashsort.c +++ b/src/backend/access/hash/hashsort.c @@ -14,7 +14,7 @@ * plenty of locality of access. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -104,15 +104,13 @@ void _h_indexbuild(HSpool *hspool) { IndexTuple itup; - bool should_free; #ifdef USE_ASSERT_CHECKING uint32 hashkey = 0; #endif tuplesort_performsort(hspool->sortstate); - while ((itup = tuplesort_getindextuple(hspool->sortstate, - true, &should_free)) != NULL) + while ((itup = tuplesort_getindextuple(hspool->sortstate, true)) != NULL) { /* * Technically, it isn't critical that hash keys be found in sorted @@ -129,7 +127,5 @@ _h_indexbuild(HSpool *hspool) #endif _hash_doinsert(hspool->index, itup); - if (should_free) - pfree(itup); } } diff --git a/src/backend/access/hash/hashutil.c b/src/backend/access/hash/hashutil.c index 822862db7a..c705531f04 100644 --- a/src/backend/access/hash/hashutil.c +++ b/src/backend/access/hash/hashutil.c @@ -3,7 +3,7 @@ * hashutil.c * Utility code for Postgres hash implementation. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -20,6 +20,8 @@ #include "utils/lsyscache.h" #include "utils/rel.h" +#define CALC_NEW_BUCKET(old_bucket, lowmask) \ + old_bucket | (lowmask + 1) /* * _hash_checkqual -- does the index tuple satisfy the scan conditions? @@ -352,3 +354,95 @@ _hash_binsearch_last(Page page, uint32 hash_value) return lower; } + +/* + * _hash_get_oldblock_from_newbucket() -- get the block number of a bucket + * from which current (new) bucket is being split. + */ +BlockNumber +_hash_get_oldblock_from_newbucket(Relation rel, Bucket new_bucket) +{ + Bucket old_bucket; + uint32 mask; + Buffer metabuf; + HashMetaPage metap; + BlockNumber blkno; + + /* + * To get the old bucket from the current bucket, we need a mask to modulo + * into lower half of table. This mask is stored in meta page as + * hashm_lowmask, but here we can't rely on the same, because we need a + * value of lowmask that was prevalent at the time when bucket split was + * started. Masking the most significant bit of new bucket would give us + * old bucket. + */ + mask = (((uint32) 1) << (fls(new_bucket) - 1)) - 1; + old_bucket = new_bucket & mask; + + metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ, LH_META_PAGE); + metap = HashPageGetMeta(BufferGetPage(metabuf)); + + blkno = BUCKET_TO_BLKNO(metap, old_bucket); + + _hash_relbuf(rel, metabuf); + + return blkno; +} + +/* + * _hash_get_newblock_from_oldbucket() -- get the block number of a bucket + * that will be generated after split from old bucket. + * + * This is used to find the new bucket from old bucket based on current table + * half. It is mainly required to finish the incomplete splits where we are + * sure that not more than one bucket could have split in progress from old + * bucket. + */ +BlockNumber +_hash_get_newblock_from_oldbucket(Relation rel, Bucket old_bucket) +{ + Bucket new_bucket; + Buffer metabuf; + HashMetaPage metap; + BlockNumber blkno; + + metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ, LH_META_PAGE); + metap = HashPageGetMeta(BufferGetPage(metabuf)); + + new_bucket = _hash_get_newbucket_from_oldbucket(rel, old_bucket, + metap->hashm_lowmask, + metap->hashm_maxbucket); + blkno = BUCKET_TO_BLKNO(metap, new_bucket); + + _hash_relbuf(rel, metabuf); + + return blkno; +} + +/* + * _hash_get_newbucket_from_oldbucket() -- get the new bucket that will be + * generated after split from current (old) bucket. + * + * This is used to find the new bucket from old bucket. New bucket can be + * obtained by OR'ing old bucket with most significant bit of current table + * half (lowmask passed in this function can be used to identify msb of + * current table half). There could be multiple buckets that could have + * been split from current bucket. We need the first such bucket that exists. + * Caller must ensure that no more than one split has happened from old + * bucket. + */ +Bucket +_hash_get_newbucket_from_oldbucket(Relation rel, Bucket old_bucket, + uint32 lowmask, uint32 maxbucket) +{ + Bucket new_bucket; + + new_bucket = CALC_NEW_BUCKET(old_bucket, lowmask); + if (new_bucket > maxbucket) + { + lowmask = lowmask >> 1; + new_bucket = CALC_NEW_BUCKET(old_bucket, lowmask); + } + + return new_bucket; +} diff --git a/src/backend/access/hash/hashvalidate.c b/src/backend/access/hash/hashvalidate.c index d8c5ed4d98..f914c015bd 100644 --- a/src/backend/access/hash/hashvalidate.c +++ b/src/backend/access/hash/hashvalidate.c @@ -3,7 +3,7 @@ * hashvalidate.c * Opclass validator for hash. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -25,6 +25,7 @@ #include "parser/parse_coerce.h" #include "utils/builtins.h" #include "utils/fmgroids.h" +#include "utils/regproc.h" #include "utils/syscache.h" diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 24bd9be5e1..1ce42ea970 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -3,7 +3,7 @@ * heapam.c * heap access method code * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -2507,7 +2507,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid, heaptup->t_len - SizeofHeapTupleHeader); /* filtering by origin on a row level is much more efficient */ - XLogIncludeOrigin(); + XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN); recptr = XLogInsert(RM_HEAP_ID, info); @@ -2846,7 +2846,7 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples, XLogRegisterBufData(0, tupledata, totaldatalen); /* filtering by origin on a row level is much more efficient */ - XLogIncludeOrigin(); + XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN); recptr = XLogInsert(RM_HEAP2_ID, info); @@ -3308,7 +3308,7 @@ heap_delete(Relation relation, ItemPointer tid, } /* filtering by origin on a row level is much more efficient */ - XLogIncludeOrigin(); + XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN); recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_DELETE); @@ -3335,7 +3335,7 @@ heap_delete(Relation relation, ItemPointer tid, Assert(!HeapTupleHasExternal(&tp)); } else if (HeapTupleHasExternal(&tp)) - toast_delete(relation, &tp); + toast_delete(relation, &tp, false); /* * Mark tuple for invalidation from system caches at next command @@ -3802,6 +3802,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup, ReleaseBuffer(vmbuffer); bms_free(hot_attrs); bms_free(key_attrs); + bms_free(id_attrs); return result; } @@ -4268,6 +4269,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup, bms_free(hot_attrs); bms_free(key_attrs); + bms_free(id_attrs); return HeapTupleMayBeUpdated; } @@ -5720,6 +5722,17 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid, goto out_locked; } + /* + * Also check Xmin: if this tuple was created by an aborted + * (sub)transaction, then we already locked the last live one in the + * chain, thus we're done, so return success. + */ + if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(mytup.t_data))) + { + UnlockReleaseBuffer(buf); + return HeapTupleMayBeUpdated; + } + old_infomask = mytup.t_data->t_infomask; old_infomask2 = mytup.t_data->t_infomask2; xmax = HeapTupleHeaderGetRawXmax(mytup.t_data); @@ -6022,7 +6035,7 @@ heap_finish_speculative(Relation relation, HeapTuple tuple) XLogBeginInsert(); /* We want the same filtering on this as on a plain insert */ - XLogIncludeOrigin(); + XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN); XLogRegisterData((char *) &xlrec, SizeOfHeapConfirm); XLogRegisterBuffer(0, buffer, REGBUF_STANDARD); @@ -6057,7 +6070,8 @@ heap_finish_speculative(Relation relation, HeapTuple tuple) * could deadlock with each other, which would not be acceptable. * * This is somewhat redundant with heap_delete, but we prefer to have a - * dedicated routine with stripped down requirements. + * dedicated routine with stripped down requirements. Note that this is also + * used to delete the TOAST tuples created during speculative insertion. * * This routine does not affect logical decoding as it only looks at * confirmation records. @@ -6101,7 +6115,7 @@ heap_abort_speculative(Relation relation, HeapTuple tuple) */ if (tp.t_data->t_choice.t_heap.t_xmin != xid) elog(ERROR, "attempted to kill a tuple inserted by another transaction"); - if (!HeapTupleHeaderIsSpeculative(tp.t_data)) + if (!(IsToastRelation(relation) || HeapTupleHeaderIsSpeculative(tp.t_data))) elog(ERROR, "attempted to kill a non-speculative tuple"); Assert(!HeapTupleHeaderIsHeapOnly(tp.t_data)); @@ -6171,7 +6185,10 @@ heap_abort_speculative(Relation relation, HeapTuple tuple) LockBuffer(buffer, BUFFER_LOCK_UNLOCK); if (HeapTupleHasExternal(&tp)) - toast_delete(relation, &tp); + { + Assert(!IsToastRelation(relation)); + toast_delete(relation, &tp, true); + } /* * Never need to mark tuple for invalidation, since catalogs don't support @@ -7686,7 +7703,7 @@ log_heap_update(Relation reln, Buffer oldbuf, } /* filtering by origin on a row level is much more efficient */ - XLogIncludeOrigin(); + XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN); recptr = XLogInsert(RM_HEAP_ID, info); diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c index c90fb71965..6529fe3d6b 100644 --- a/src/backend/access/heap/hio.c +++ b/src/backend/access/heap/hio.c @@ -3,7 +3,7 @@ * hio.c * POSTGRES heap access method input/output code. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c index 6ff92516ed..d69a266c36 100644 --- a/src/backend/access/heap/pruneheap.c +++ b/src/backend/access/heap/pruneheap.c @@ -3,7 +3,7 @@ * pruneheap.c * heap page pruning and HOT-chain management code * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c index f9ce9861e2..90ab6f2421 100644 --- a/src/backend/access/heap/rewriteheap.c +++ b/src/backend/access/heap/rewriteheap.c @@ -92,7 +92,7 @@ * heap's TOAST table will go through the normal bufmgr. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994-5, Regents of the University of California * * IDENTIFICATION @@ -258,9 +258,7 @@ begin_heap_rewrite(Relation old_heap, Relation new_heap, TransactionId oldest_xm */ rw_cxt = AllocSetContextCreate(CurrentMemoryContext, "Table rewrite", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); old_cxt = MemoryContextSwitchTo(rw_cxt); /* Create and fill in the state struct */ diff --git a/src/backend/access/heap/syncscan.c b/src/backend/access/heap/syncscan.c index a0f500edc8..20640cbbaf 100644 --- a/src/backend/access/heap/syncscan.c +++ b/src/backend/access/heap/syncscan.c @@ -36,7 +36,7 @@ * ss_report_location - update current scan location * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -48,6 +48,8 @@ #include "access/heapam.h" #include "miscadmin.h" +#include "storage/lwlock.h" +#include "storage/shmem.h" #include "utils/rel.h" diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c index bbb2649371..496648c42f 100644 --- a/src/backend/access/heap/tuptoaster.c +++ b/src/backend/access/heap/tuptoaster.c @@ -4,7 +4,7 @@ * Support routines for external and compressed storage of * variable size attributes. * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -67,7 +67,7 @@ typedef struct toast_compress_header #define TOAST_COMPRESS_SET_RAWSIZE(ptr, len) \ (((toast_compress_header *) (ptr))->rawsize = (len)) -static void toast_delete_datum(Relation rel, Datum value); +static void toast_delete_datum(Relation rel, Datum value, bool is_speculative); static Datum toast_save_datum(Relation rel, Datum value, struct varlena * oldexternal, int options); static bool toastrel_valueid_exists(Relation toastrel, Oid valueid); @@ -461,7 +461,7 @@ toast_datum_size(Datum value) * ---------- */ void -toast_delete(Relation rel, HeapTuple oldtup) +toast_delete(Relation rel, HeapTuple oldtup, bool is_speculative) { TupleDesc tupleDesc; Form_pg_attribute *att; @@ -508,7 +508,7 @@ toast_delete(Relation rel, HeapTuple oldtup) if (toast_isnull[i]) continue; else if (VARATT_IS_EXTERNAL_ONDISK(PointerGetDatum(value))) - toast_delete_datum(rel, value); + toast_delete_datum(rel, value, is_speculative); } } } @@ -1064,7 +1064,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, if (need_delold) for (i = 0; i < numAttrs; i++) if (toast_delold[i]) - toast_delete_datum(rel, toast_oldvalues[i]); + toast_delete_datum(rel, toast_oldvalues[i], false); return result_tuple; } @@ -1656,7 +1656,7 @@ toast_save_datum(Relation rel, Datum value, * ---------- */ static void -toast_delete_datum(Relation rel, Datum value) +toast_delete_datum(Relation rel, Datum value, bool is_speculative) { struct varlena *attr = (struct varlena *) DatumGetPointer(value); struct varatt_external toast_pointer; @@ -1707,7 +1707,10 @@ toast_delete_datum(Relation rel, Datum value) /* * Have a chunk, delete it */ - simple_heap_delete(toastrel, &toasttup->t_self); + if (is_speculative) + heap_abort_speculative(toastrel, toasttup); + else + simple_heap_delete(toastrel, &toasttup->t_self); } /* diff --git a/src/backend/access/heap/visibilitymap.c b/src/backend/access/heap/visibilitymap.c index 3ad4a9f587..e5616ce051 100644 --- a/src/backend/access/heap/visibilitymap.c +++ b/src/backend/access/heap/visibilitymap.c @@ -3,7 +3,7 @@ * visibilitymap.c * bitmap for tracking visibility of heap tuples * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -508,6 +508,9 @@ visibilitymap_truncate(Relation rel, BlockNumber nheapblocks) LockBuffer(mapBuffer, BUFFER_LOCK_EXCLUSIVE); + /* NO EREPORT(ERROR) from here till changes are logged */ + START_CRIT_SECTION(); + /* Clear out the unwanted bytes. */ MemSet(&map[truncByte + 1], 0, MAPSIZE - (truncByte + 1)); @@ -523,7 +526,20 @@ visibilitymap_truncate(Relation rel, BlockNumber nheapblocks) */ map[truncByte] &= (1 << truncOffset) - 1; + /* + * Truncation of a relation is WAL-logged at a higher-level, and we + * will be called at WAL replay. But if checksums are enabled, we need + * to still write a WAL record to protect against a torn page, if the + * page is flushed to disk before the truncation WAL record. We cannot + * use MarkBufferDirtyHint here, because that will not dirty the page + * during recovery. + */ MarkBufferDirty(mapBuffer); + if (!InRecovery && RelationNeedsWAL(rel) && XLogHintBitIsNeeded()) + log_newpage_buffer(mapBuffer, false); + + END_CRIT_SECTION(); + UnlockReleaseBuffer(mapBuffer); } else diff --git a/src/backend/access/index/amapi.c b/src/backend/access/index/amapi.c index 28f6cde896..7b597a072f 100644 --- a/src/backend/access/index/amapi.c +++ b/src/backend/access/index/amapi.c @@ -3,7 +3,7 @@ * amapi.c * Support routines for API for Postgres index access methods. * - * Copyright (c) 2015-2016, PostgreSQL Global Development Group + * Copyright (c) 2015-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -17,6 +17,7 @@ #include "access/htup_details.h" #include "catalog/pg_am.h" #include "catalog/pg_opclass.h" +#include "utils/builtins.h" #include "utils/syscache.h" diff --git a/src/backend/access/index/amvalidate.c b/src/backend/access/index/amvalidate.c index 1a3c5f16b9..80865e9ff9 100644 --- a/src/backend/access/index/amvalidate.c +++ b/src/backend/access/index/amvalidate.c @@ -3,7 +3,7 @@ * amvalidate.c * Support routines for index access methods' amvalidate functions. * - * Copyright (c) 2016, PostgreSQL Global Development Group + * Copyright (c) 2016-2017, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c index 65c941d812..c4a393f34e 100644 --- a/src/backend/access/index/genam.c +++ b/src/backend/access/index/genam.c @@ -3,7 +3,7 @@ * genam.c * general index access method routines * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c index 54b71cb2f7..4822af95a3 100644 --- a/src/backend/access/index/indexam.c +++ b/src/backend/access/index/indexam.c @@ -3,7 +3,7 @@ * indexam.c * general index access method routines * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/nbtree/README b/src/backend/access/nbtree/README index 067d15c803..a3f11da8d5 100644 --- a/src/backend/access/nbtree/README +++ b/src/backend/access/nbtree/README @@ -521,11 +521,12 @@ because it allows running applications to continue while the standby changes state into a normally running server. The interlocking required to avoid returning incorrect results from -MVCC scans is not required on standby nodes. That is because +non-MVCC scans is not required on standby nodes. That is because HeapTupleSatisfiesUpdate(), HeapTupleSatisfiesSelf(), HeapTupleSatisfiesDirty() and HeapTupleSatisfiesVacuum() are only ever used during write transactions, which cannot exist on the standby. -This leaves HeapTupleSatisfiesMVCC() and HeapTupleSatisfiesToast(). +MVCC scans are already protected by definition, so HeapTupleSatisfiesMVCC() +is not a problem. That leaves concern only for HeapTupleSatisfiesToast(). HeapTupleSatisfiesToast() doesn't use MVCC semantics, though that's because it doesn't need to - if the main heap row is visible then the toast rows will also be visible. So as long as we follow a toast diff --git a/src/backend/access/nbtree/nbtcompare.c b/src/backend/access/nbtree/nbtcompare.c index 0d60da61cc..4b131efb87 100644 --- a/src/backend/access/nbtree/nbtcompare.c +++ b/src/backend/access/nbtree/nbtcompare.c @@ -3,7 +3,7 @@ * nbtcompare.c * Comparison functions for btree access method. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c index ef69290b6c..883d70da11 100644 --- a/src/backend/access/nbtree/nbtinsert.c +++ b/src/backend/access/nbtree/nbtinsert.c @@ -3,7 +3,7 @@ * nbtinsert.c * Item insertion in Lehman and Yao btrees for Postgres. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c index 2001dc14fb..da74f79b40 100644 --- a/src/backend/access/nbtree/nbtpage.c +++ b/src/backend/access/nbtree/nbtpage.c @@ -4,7 +4,7 @@ * BTree-specific page management code for the Postgres btree access * method. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index 4668c5ee59..1bb1acfea6 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -8,7 +8,7 @@ * This file contains only the public interface routines. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -28,6 +28,7 @@ #include "storage/lmgr.h" #include "storage/smgr.h" #include "tcop/tcopprot.h" /* pgrminclude ignore */ +#include "utils/builtins.h" #include "utils/index_selfuncs.h" #include "utils/memutils.h" @@ -242,13 +243,18 @@ btbuildempty(Relation index) metapage = (Page) palloc(BLCKSZ); _bt_initmetapage(metapage, P_NONE, 0); - /* Write the page. If archiving/streaming, XLOG it. */ + /* + * Write the page and log it. It might seem that an immediate sync + * would be sufficient to guarantee that the file exists on disk, but + * recovery itself might remove it while replaying, for example, an + * XLOG_DBASE_CREATE or XLOG_TBLSPC_CREATE record. Therefore, we + * need this even when wal_level=minimal. + */ PageSetChecksumInplace(metapage, BTREE_METAPAGE); smgrwrite(index->rd_smgr, INIT_FORKNUM, BTREE_METAPAGE, (char *) metapage, true); - if (XLogIsNeeded()) - log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM, - BTREE_METAPAGE, metapage, false); + log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM, + BTREE_METAPAGE, metapage, false); /* * An immediate sync is required even if we xlog'd the page, because the @@ -763,9 +769,7 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, /* Create a temporary memory context to run _bt_pagedel in */ vstate.pagedelcontext = AllocSetContextCreate(CurrentMemoryContext, "_bt_pagedel", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* * The outer loop iterates over all index pages except the metapage, in diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c index ee46023c5a..4fba75aaf6 100644 --- a/src/backend/access/nbtree/nbtsearch.c +++ b/src/backend/access/nbtree/nbtsearch.c @@ -4,7 +4,7 @@ * Search code for postgres btrees. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c index 99a014e8f4..3d041c47c0 100644 --- a/src/backend/access/nbtree/nbtsort.c +++ b/src/backend/access/nbtree/nbtsort.c @@ -55,7 +55,7 @@ * This code isn't concerned about the FSM at all. The caller is responsible * for initializing that. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -680,9 +680,7 @@ _bt_load(BTWriteState *wstate, BTSpool *btspool, BTSpool *btspool2) bool merge = (btspool2 != NULL); IndexTuple itup, itup2 = NULL; - bool should_free, - should_free2, - load1; + bool load1; TupleDesc tupdes = RelationGetDescr(wstate->index); int i, keysz = RelationGetNumberOfAttributes(wstate->index); @@ -697,10 +695,8 @@ _bt_load(BTWriteState *wstate, BTSpool *btspool, BTSpool *btspool2) */ /* the preparation of merge */ - itup = tuplesort_getindextuple(btspool->sortstate, - true, &should_free); - itup2 = tuplesort_getindextuple(btspool2->sortstate, - true, &should_free2); + itup = tuplesort_getindextuple(btspool->sortstate, true); + itup2 = tuplesort_getindextuple(btspool2->sortstate, true); indexScanKey = _bt_mkscankey_nodata(wstate->index); /* Prepare SortSupport data for each column */ @@ -775,18 +771,12 @@ _bt_load(BTWriteState *wstate, BTSpool *btspool, BTSpool *btspool2) if (load1) { _bt_buildadd(wstate, state, itup); - if (should_free) - pfree(itup); - itup = tuplesort_getindextuple(btspool->sortstate, - true, &should_free); + itup = tuplesort_getindextuple(btspool->sortstate, true); } else { _bt_buildadd(wstate, state, itup2); - if (should_free2) - pfree(itup2); - itup2 = tuplesort_getindextuple(btspool2->sortstate, - true, &should_free2); + itup2 = tuplesort_getindextuple(btspool2->sortstate, true); } } pfree(sortKeys); @@ -795,15 +785,13 @@ _bt_load(BTWriteState *wstate, BTSpool *btspool, BTSpool *btspool2) { /* merge is unnecessary */ while ((itup = tuplesort_getindextuple(btspool->sortstate, - true, &should_free)) != NULL) + true)) != NULL) { /* When we see first tuple, create first index page */ if (state == NULL) state = _bt_pagestate(wstate, 0); _bt_buildadd(wstate, state, itup); - if (should_free) - pfree(itup); } } diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index 5d335c7f97..da0f330c96 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -3,7 +3,7 @@ * nbtutils.c * Utility code for Postgres btree implementation. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -232,10 +232,8 @@ _bt_preprocess_array_keys(IndexScanDesc scan) */ if (so->arrayContext == NULL) so->arrayContext = AllocSetContextCreate(CurrentMemoryContext, - "BTree Array Context", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MAXSIZE); + "BTree array context", + ALLOCSET_SMALL_SIZES); else MemoryContextReset(so->arrayContext); diff --git a/src/backend/access/nbtree/nbtvalidate.c b/src/backend/access/nbtree/nbtvalidate.c index 7d0bdabc1d..88e33f54cd 100644 --- a/src/backend/access/nbtree/nbtvalidate.c +++ b/src/backend/access/nbtree/nbtvalidate.c @@ -3,7 +3,7 @@ * nbtvalidate.c * Opclass validator for btree. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -22,6 +22,7 @@ #include "catalog/pg_opfamily.h" #include "catalog/pg_type.h" #include "utils/builtins.h" +#include "utils/regproc.h" #include "utils/syscache.h" diff --git a/src/backend/access/nbtree/nbtxlog.c b/src/backend/access/nbtree/nbtxlog.c index c536e22432..efad745c57 100644 --- a/src/backend/access/nbtree/nbtxlog.c +++ b/src/backend/access/nbtree/nbtxlog.c @@ -4,7 +4,7 @@ * WAL replay logic for btrees. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/rmgrdesc/brindesc.c b/src/backend/access/rmgrdesc/brindesc.c index 433526f5ec..b58cb5bde9 100644 --- a/src/backend/access/rmgrdesc/brindesc.c +++ b/src/backend/access/rmgrdesc/brindesc.c @@ -3,7 +3,7 @@ * brindesc.c * rmgr descriptor routines for BRIN indexes * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/clogdesc.c b/src/backend/access/rmgrdesc/clogdesc.c index 41ea254710..352de48dbe 100644 --- a/src/backend/access/rmgrdesc/clogdesc.c +++ b/src/backend/access/rmgrdesc/clogdesc.c @@ -3,7 +3,7 @@ * clogdesc.c * rmgr descriptor routines for access/transam/clog.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/committsdesc.c b/src/backend/access/rmgrdesc/committsdesc.c index 527e5dc724..3e670bd543 100644 --- a/src/backend/access/rmgrdesc/committsdesc.c +++ b/src/backend/access/rmgrdesc/committsdesc.c @@ -3,7 +3,7 @@ * committsdesc.c * rmgr descriptor routines for access/transam/commit_ts.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -33,10 +33,10 @@ commit_ts_desc(StringInfo buf, XLogReaderState *record) } else if (info == COMMIT_TS_TRUNCATE) { - int pageno; + xl_commit_ts_truncate *trunc = (xl_commit_ts_truncate *) rec; - memcpy(&pageno, rec, sizeof(int)); - appendStringInfo(buf, "%d", pageno); + appendStringInfo(buf, "pageno %d, oldestXid %u", + trunc->pageno, trunc->oldestXid); } else if (info == COMMIT_TS_SETTS) { diff --git a/src/backend/access/rmgrdesc/dbasedesc.c b/src/backend/access/rmgrdesc/dbasedesc.c index 83720ce765..768242cfd5 100644 --- a/src/backend/access/rmgrdesc/dbasedesc.c +++ b/src/backend/access/rmgrdesc/dbasedesc.c @@ -3,7 +3,7 @@ * dbasedesc.c * rmgr descriptor routines for commands/dbcommands.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/genericdesc.c b/src/backend/access/rmgrdesc/genericdesc.c index 22f81570a5..c4705428f1 100644 --- a/src/backend/access/rmgrdesc/genericdesc.c +++ b/src/backend/access/rmgrdesc/genericdesc.c @@ -4,7 +4,7 @@ * rmgr descriptor routines for access/transam/generic_xlog.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/rmgrdesc/genericdesc.c diff --git a/src/backend/access/rmgrdesc/gindesc.c b/src/backend/access/rmgrdesc/gindesc.c index db832a5f78..9e488b359a 100644 --- a/src/backend/access/rmgrdesc/gindesc.c +++ b/src/backend/access/rmgrdesc/gindesc.c @@ -3,7 +3,7 @@ * gindesc.c * rmgr descriptor routines for access/transam/gin/ginxlog.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -87,13 +87,13 @@ gin_desc(StringInfo buf, XLogReaderState *record) case XLOG_GIN_INSERT: { ginxlogInsert *xlrec = (ginxlogInsert *) rec; - char *payload = rec + sizeof(ginxlogInsert); appendStringInfo(buf, "isdata: %c isleaf: %c", (xlrec->flags & GIN_INSERT_ISDATA) ? 'T' : 'F', (xlrec->flags & GIN_INSERT_ISLEAF) ? 'T' : 'F'); if (!(xlrec->flags & GIN_INSERT_ISLEAF)) { + char *payload = rec + sizeof(ginxlogInsert); BlockNumber leftChildBlkno; BlockNumber rightChildBlkno; @@ -104,27 +104,27 @@ gin_desc(StringInfo buf, XLogReaderState *record) appendStringInfo(buf, " children: %u/%u", leftChildBlkno, rightChildBlkno); } - if (!(xlrec->flags & GIN_INSERT_ISDATA)) - appendStringInfo(buf, " isdelete: %c", - (((ginxlogInsertEntry *) payload)->isDelete) ? 'T' : 'F'); - else if (xlrec->flags & GIN_INSERT_ISLEAF) - { - ginxlogRecompressDataLeaf *insertData = - (ginxlogRecompressDataLeaf *) payload; - - if (XLogRecHasBlockImage(record, 0)) - appendStringInfoString(buf, " (full page image)"); - else - desc_recompress_leaf(buf, insertData); - } + if (XLogRecHasBlockImage(record, 0)) + appendStringInfoString(buf, " (full page image)"); else { - ginxlogInsertDataInternal *insertData = (ginxlogInsertDataInternal *) payload; + char *payload = XLogRecGetBlockData(record, 0, NULL); - appendStringInfo(buf, " pitem: %u-%u/%u", - PostingItemGetBlockNumber(&insertData->newitem), - ItemPointerGetBlockNumber(&insertData->newitem.key), - ItemPointerGetOffsetNumber(&insertData->newitem.key)); + if (!(xlrec->flags & GIN_INSERT_ISDATA)) + appendStringInfo(buf, " isdelete: %c", + (((ginxlogInsertEntry *) payload)->isDelete) ? 'T' : 'F'); + else if (xlrec->flags & GIN_INSERT_ISLEAF) + desc_recompress_leaf(buf, (ginxlogRecompressDataLeaf *) payload); + else + { + ginxlogInsertDataInternal *insertData = + (ginxlogInsertDataInternal *) payload; + + appendStringInfo(buf, " pitem: %u-%u/%u", + PostingItemGetBlockNumber(&insertData->newitem), + ItemPointerGetBlockNumber(&insertData->newitem.key), + ItemPointerGetOffsetNumber(&insertData->newitem.key)); + } } } break; @@ -144,12 +144,15 @@ gin_desc(StringInfo buf, XLogReaderState *record) break; case XLOG_GIN_VACUUM_DATA_LEAF_PAGE: { - ginxlogVacuumDataLeafPage *xlrec = (ginxlogVacuumDataLeafPage *) rec; - if (XLogRecHasBlockImage(record, 0)) appendStringInfoString(buf, " (full page image)"); else + { + ginxlogVacuumDataLeafPage *xlrec = + (ginxlogVacuumDataLeafPage *) XLogRecGetBlockData(record, 0, NULL); + desc_recompress_leaf(buf, &xlrec->data); + } } break; case XLOG_GIN_DELETE_PAGE: diff --git a/src/backend/access/rmgrdesc/gistdesc.c b/src/backend/access/rmgrdesc/gistdesc.c index 90bb88109f..bf34578bf7 100644 --- a/src/backend/access/rmgrdesc/gistdesc.c +++ b/src/backend/access/rmgrdesc/gistdesc.c @@ -3,7 +3,7 @@ * gistdesc.c * rmgr descriptor routines for access/gist/gistxlog.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/hashdesc.c b/src/backend/access/rmgrdesc/hashdesc.c index d37c9b1aae..7eac8191ca 100644 --- a/src/backend/access/rmgrdesc/hashdesc.c +++ b/src/backend/access/rmgrdesc/hashdesc.c @@ -3,7 +3,7 @@ * hashdesc.c * rmgr descriptor routines for access/hash/hash.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -14,7 +14,7 @@ */ #include "postgres.h" -#include "access/hash.h" +#include "access/hash_xlog.h" void hash_desc(StringInfo buf, XLogReaderState *record) diff --git a/src/backend/access/rmgrdesc/heapdesc.c b/src/backend/access/rmgrdesc/heapdesc.c index 7c763b6b0e..44d2d6333f 100644 --- a/src/backend/access/rmgrdesc/heapdesc.c +++ b/src/backend/access/rmgrdesc/heapdesc.c @@ -3,7 +3,7 @@ * heapdesc.c * rmgr descriptor routines for access/heap/heapam.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/logicalmsgdesc.c b/src/backend/access/rmgrdesc/logicalmsgdesc.c index 525826efd3..8287751e48 100644 --- a/src/backend/access/rmgrdesc/logicalmsgdesc.c +++ b/src/backend/access/rmgrdesc/logicalmsgdesc.c @@ -3,7 +3,7 @@ * logicalmsgdesc.c * rmgr descriptor routines for replication/logical/message.c * - * Portions Copyright (c) 2015-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2015-2017, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/access/rmgrdesc/mxactdesc.c b/src/backend/access/rmgrdesc/mxactdesc.c index 27c1fb0fc0..9c17447744 100644 --- a/src/backend/access/rmgrdesc/mxactdesc.c +++ b/src/backend/access/rmgrdesc/mxactdesc.c @@ -3,7 +3,7 @@ * mxactdesc.c * rmgr descriptor routines for access/transam/multixact.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/nbtdesc.c b/src/backend/access/rmgrdesc/nbtdesc.c index 7631cb5c73..96ec936a88 100644 --- a/src/backend/access/rmgrdesc/nbtdesc.c +++ b/src/backend/access/rmgrdesc/nbtdesc.c @@ -3,7 +3,7 @@ * nbtdesc.c * rmgr descriptor routines for access/nbtree/nbtxlog.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/relmapdesc.c b/src/backend/access/rmgrdesc/relmapdesc.c index 097a709fb2..4cbdf37c70 100644 --- a/src/backend/access/rmgrdesc/relmapdesc.c +++ b/src/backend/access/rmgrdesc/relmapdesc.c @@ -3,7 +3,7 @@ * relmapdesc.c * rmgr descriptor routines for utils/cache/relmapper.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/replorigindesc.c b/src/backend/access/rmgrdesc/replorigindesc.c index ce8ba10c14..c43f850f8e 100644 --- a/src/backend/access/rmgrdesc/replorigindesc.c +++ b/src/backend/access/rmgrdesc/replorigindesc.c @@ -3,7 +3,7 @@ * replorigindesc.c * rmgr descriptor routines for replication/logical/origin.c * - * Portions Copyright (c) 2015-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2015-2017, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/access/rmgrdesc/seqdesc.c b/src/backend/access/rmgrdesc/seqdesc.c index 5855715735..2209f7284e 100644 --- a/src/backend/access/rmgrdesc/seqdesc.c +++ b/src/backend/access/rmgrdesc/seqdesc.c @@ -3,7 +3,7 @@ * seqdesc.c * rmgr descriptor routines for commands/sequence.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/smgrdesc.c b/src/backend/access/rmgrdesc/smgrdesc.c index 242d79a136..b8174373dd 100644 --- a/src/backend/access/rmgrdesc/smgrdesc.c +++ b/src/backend/access/rmgrdesc/smgrdesc.c @@ -3,7 +3,7 @@ * smgrdesc.c * rmgr descriptor routines for catalog/storage.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/spgdesc.c b/src/backend/access/rmgrdesc/spgdesc.c index 8be47f9526..1a229d94f3 100644 --- a/src/backend/access/rmgrdesc/spgdesc.c +++ b/src/backend/access/rmgrdesc/spgdesc.c @@ -3,7 +3,7 @@ * spgdesc.c * rmgr descriptor routines for access/spgist/spgxlog.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/standbydesc.c b/src/backend/access/rmgrdesc/standbydesc.c index 13797a3d2f..278546a728 100644 --- a/src/backend/access/rmgrdesc/standbydesc.c +++ b/src/backend/access/rmgrdesc/standbydesc.c @@ -3,7 +3,7 @@ * standbydesc.c * rmgr descriptor routines for storage/ipc/standby.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -121,13 +121,11 @@ standby_desc_invalidations(StringInfo buf, else if (msg->id == SHAREDINVALSMGR_ID) appendStringInfoString(buf, " smgr"); /* not expected, but print something anyway */ - else if (msg->id == SHAREDINVALRELMAP_ID) - appendStringInfoString(buf, " relmap"); else if (msg->id == SHAREDINVALRELMAP_ID) appendStringInfo(buf, " relmap db %u", msg->rm.dbId); else if (msg->id == SHAREDINVALSNAPSHOT_ID) appendStringInfo(buf, " snapshot %u", msg->sn.relId); else - appendStringInfo(buf, " unknown id %d", msg->id); + appendStringInfo(buf, " unrecognized id %d", msg->id); } } diff --git a/src/backend/access/rmgrdesc/tblspcdesc.c b/src/backend/access/rmgrdesc/tblspcdesc.c index 15440271a3..47c42328f3 100644 --- a/src/backend/access/rmgrdesc/tblspcdesc.c +++ b/src/backend/access/rmgrdesc/tblspcdesc.c @@ -3,7 +3,7 @@ * tblspcdesc.c * rmgr descriptor routines for commands/tablespace.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/xactdesc.c b/src/backend/access/rmgrdesc/xactdesc.c index 91d27d0654..c91ca03db1 100644 --- a/src/backend/access/rmgrdesc/xactdesc.c +++ b/src/backend/access/rmgrdesc/xactdesc.c @@ -3,7 +3,7 @@ * xactdesc.c * rmgr descriptor routines for access/transam/xact.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c index 62ed1dc04b..5f07eb1499 100644 --- a/src/backend/access/rmgrdesc/xlogdesc.c +++ b/src/backend/access/rmgrdesc/xlogdesc.c @@ -3,7 +3,7 @@ * xlogdesc.c * rmgr descriptor routines for access/transam/xlog.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/spgist/spgdoinsert.c b/src/backend/access/spgist/spgdoinsert.c index f090ca528b..748e568a62 100644 --- a/src/backend/access/spgist/spgdoinsert.c +++ b/src/backend/access/spgist/spgdoinsert.c @@ -4,7 +4,7 @@ * implementation of insert algorithm * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -1705,17 +1705,40 @@ spgSplitNodeAction(Relation index, SpGistState *state, /* Should not be applied to nulls */ Assert(!SpGistPageStoresNulls(current->page)); + /* Check opclass gave us sane values */ + if (out->result.splitTuple.prefixNNodes <= 0 || + out->result.splitTuple.prefixNNodes > SGITMAXNNODES) + elog(ERROR, "invalid number of prefix nodes: %d", + out->result.splitTuple.prefixNNodes); + if (out->result.splitTuple.childNodeN < 0 || + out->result.splitTuple.childNodeN >= + out->result.splitTuple.prefixNNodes) + elog(ERROR, "invalid child node number: %d", + out->result.splitTuple.childNodeN); + /* - * Construct new prefix tuple, containing a single node with the specified - * label. (We'll update the node's downlink to point to the new postfix - * tuple, below.) + * Construct new prefix tuple with requested number of nodes. We'll fill + * in the childNodeN'th node's downlink below. */ - node = spgFormNodeTuple(state, out->result.splitTuple.nodeLabel, false); + nodes = (SpGistNodeTuple *) palloc(sizeof(SpGistNodeTuple) * + out->result.splitTuple.prefixNNodes); + + for (i = 0; i < out->result.splitTuple.prefixNNodes; i++) + { + Datum label = (Datum) 0; + bool labelisnull; + + labelisnull = (out->result.splitTuple.prefixNodeLabels == NULL); + if (!labelisnull) + label = out->result.splitTuple.prefixNodeLabels[i]; + nodes[i] = spgFormNodeTuple(state, label, labelisnull); + } prefixTuple = spgFormInnerTuple(state, out->result.splitTuple.prefixHasPrefix, out->result.splitTuple.prefixPrefixDatum, - 1, &node); + out->result.splitTuple.prefixNNodes, + nodes); /* it must fit in the space that innerTuple now occupies */ if (prefixTuple->size > innerTuple->size) @@ -1807,10 +1830,12 @@ spgSplitNodeAction(Relation index, SpGistState *state, * the postfix tuple first.) We have to update the local copy of the * prefixTuple too, because that's what will be written to WAL. */ - spgUpdateNodeLink(prefixTuple, 0, postfixBlkno, postfixOffset); + spgUpdateNodeLink(prefixTuple, out->result.splitTuple.childNodeN, + postfixBlkno, postfixOffset); prefixTuple = (SpGistInnerTuple) PageGetItem(current->page, PageGetItemId(current->page, current->offnum)); - spgUpdateNodeLink(prefixTuple, 0, postfixBlkno, postfixOffset); + spgUpdateNodeLink(prefixTuple, out->result.splitTuple.childNodeN, + postfixBlkno, postfixOffset); MarkBufferDirty(current->buffer); diff --git a/src/backend/access/spgist/spginsert.c b/src/backend/access/spgist/spginsert.c index 44fd644e42..b42f4b7139 100644 --- a/src/backend/access/spgist/spginsert.c +++ b/src/backend/access/spgist/spginsert.c @@ -5,7 +5,7 @@ * * All the actual insertion logic is in spgdoinsert.c. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -134,9 +134,7 @@ spgbuild(Relation heap, Relation index, IndexInfo *indexInfo) buildstate.tmpCtx = AllocSetContextCreate(CurrentMemoryContext, "SP-GiST build temporary context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); reltuples = IndexBuildHeapScan(heap, index, indexInfo, true, spgistBuildCallback, (void *) &buildstate); @@ -163,13 +161,18 @@ spgbuildempty(Relation index) page = (Page) palloc(BLCKSZ); SpGistInitMetapage(page); - /* Write the page. If archiving/streaming, XLOG it. */ + /* + * Write the page and log it unconditionally. This is important + * particularly for indexes created on tablespaces and databases + * whose creation happened after the last redo pointer as recovery + * removes any of their existing content when the corresponding + * create records are replayed. + */ PageSetChecksumInplace(page, SPGIST_METAPAGE_BLKNO); smgrwrite(index->rd_smgr, INIT_FORKNUM, SPGIST_METAPAGE_BLKNO, (char *) page, true); - if (XLogIsNeeded()) - log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM, - SPGIST_METAPAGE_BLKNO, page, false); + log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM, + SPGIST_METAPAGE_BLKNO, page, false); /* Likewise for the root page. */ SpGistInitPage(page, SPGIST_LEAF); @@ -177,9 +180,8 @@ spgbuildempty(Relation index) PageSetChecksumInplace(page, SPGIST_ROOT_BLKNO); smgrwrite(index->rd_smgr, INIT_FORKNUM, SPGIST_ROOT_BLKNO, (char *) page, true); - if (XLogIsNeeded()) - log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM, - SPGIST_ROOT_BLKNO, page, true); + log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM, + SPGIST_ROOT_BLKNO, page, true); /* Likewise for the null-tuples root page. */ SpGistInitPage(page, SPGIST_LEAF | SPGIST_NULLS); @@ -187,9 +189,8 @@ spgbuildempty(Relation index) PageSetChecksumInplace(page, SPGIST_NULL_BLKNO); smgrwrite(index->rd_smgr, INIT_FORKNUM, SPGIST_NULL_BLKNO, (char *) page, true); - if (XLogIsNeeded()) - log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM, - SPGIST_NULL_BLKNO, page, true); + log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM, + SPGIST_NULL_BLKNO, page, true); /* * An immediate sync is required even if we xlog'd the pages, because the @@ -213,9 +214,7 @@ spginsert(Relation index, Datum *values, bool *isnull, insertCtx = AllocSetContextCreate(CurrentMemoryContext, "SP-GiST insert temporary context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldCtx = MemoryContextSwitchTo(insertCtx); initSpGistState(&spgstate, index); diff --git a/src/backend/access/spgist/spgkdtreeproc.c b/src/backend/access/spgist/spgkdtreeproc.c index 1ab93350e1..9a2649bf2a 100644 --- a/src/backend/access/spgist/spgkdtreeproc.c +++ b/src/backend/access/spgist/spgkdtreeproc.c @@ -4,7 +4,7 @@ * implementation of k-d tree over points for SP-GiST * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/spgist/spgquadtreeproc.c b/src/backend/access/spgist/spgquadtreeproc.c index 40ab760b0f..6ad73f448d 100644 --- a/src/backend/access/spgist/spgquadtreeproc.c +++ b/src/backend/access/spgist/spgquadtreeproc.c @@ -4,7 +4,7 @@ * implementation of quad tree over points for SP-GiST * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/spgist/spgscan.c b/src/backend/access/spgist/spgscan.c index 6f9e223f43..139d998600 100644 --- a/src/backend/access/spgist/spgscan.c +++ b/src/backend/access/spgist/spgscan.c @@ -4,7 +4,7 @@ * routines for scanning SP-GiST indexes * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -193,9 +193,7 @@ spgbeginscan(Relation rel, int keysz, int orderbysz) initSpGistState(&so->state, scan->indexRelation); so->tempCxt = AllocSetContextCreate(CurrentMemoryContext, "SP-GiST search temporary context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* Set up indexTupDesc and xs_itupdesc in case it's an index-only scan */ so->indexTupDesc = scan->xs_itupdesc = RelationGetDescr(rel); diff --git a/src/backend/access/spgist/spgtextproc.c b/src/backend/access/spgist/spgtextproc.c index e0d8f30ef1..86788549a5 100644 --- a/src/backend/access/spgist/spgtextproc.c +++ b/src/backend/access/spgist/spgtextproc.c @@ -29,7 +29,7 @@ * No new entries ever get pushed into a -2-labeled child, either. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -45,6 +45,7 @@ #include "utils/builtins.h" #include "utils/datum.h" #include "utils/pg_locale.h" +#include "utils/varlena.h" /* @@ -212,9 +213,14 @@ spg_text_choose(PG_FUNCTION_ARGS) out->result.splitTuple.prefixPrefixDatum = formTextDatum(prefixStr, commonLen); } - out->result.splitTuple.nodeLabel = + out->result.splitTuple.prefixNNodes = 1; + out->result.splitTuple.prefixNodeLabels = + (Datum *) palloc(sizeof(Datum)); + out->result.splitTuple.prefixNodeLabels[0] = Int16GetDatum(*(unsigned char *) (prefixStr + commonLen)); + out->result.splitTuple.childNodeN = 0; + if (prefixSize - commonLen == 1) { out->result.splitTuple.postfixHasPrefix = false; @@ -280,7 +286,10 @@ spg_text_choose(PG_FUNCTION_ARGS) out->resultType = spgSplitTuple; out->result.splitTuple.prefixHasPrefix = in->hasPrefix; out->result.splitTuple.prefixPrefixDatum = in->prefixDatum; - out->result.splitTuple.nodeLabel = Int16GetDatum(-2); + out->result.splitTuple.prefixNNodes = 1; + out->result.splitTuple.prefixNodeLabels = (Datum *) palloc(sizeof(Datum)); + out->result.splitTuple.prefixNodeLabels[0] = Int16GetDatum(-2); + out->result.splitTuple.childNodeN = 0; out->result.splitTuple.postfixHasPrefix = false; } else diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c index d570ae5992..ca4b0bdbe4 100644 --- a/src/backend/access/spgist/spgutils.c +++ b/src/backend/access/spgist/spgutils.c @@ -4,7 +4,7 @@ * various support functions for SP-GiST * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -22,6 +22,7 @@ #include "storage/bufmgr.h" #include "storage/indexfsm.h" #include "storage/lmgr.h" +#include "utils/builtins.h" #include "utils/index_selfuncs.h" #include "utils/lsyscache.h" diff --git a/src/backend/access/spgist/spgvacuum.c b/src/backend/access/spgist/spgvacuum.c index 15b867f24c..cc6b000a62 100644 --- a/src/backend/access/spgist/spgvacuum.c +++ b/src/backend/access/spgist/spgvacuum.c @@ -4,7 +4,7 @@ * vacuum for SP-GiST * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/spgist/spgvalidate.c b/src/backend/access/spgist/spgvalidate.c index 6297111a7c..1bc5bce72e 100644 --- a/src/backend/access/spgist/spgvalidate.c +++ b/src/backend/access/spgist/spgvalidate.c @@ -3,7 +3,7 @@ * spgvalidate.c * Opclass validator for SP-GiST. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -22,6 +22,7 @@ #include "catalog/pg_opfamily.h" #include "catalog/pg_type.h" #include "utils/builtins.h" +#include "utils/regproc.h" #include "utils/syscache.h" diff --git a/src/backend/access/spgist/spgxlog.c b/src/backend/access/spgist/spgxlog.c index 01a4e0f252..3dc6a5ab88 100644 --- a/src/backend/access/spgist/spgxlog.c +++ b/src/backend/access/spgist/spgxlog.c @@ -4,7 +4,7 @@ * WAL replay logic for SP-GiST * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -1014,9 +1014,7 @@ spg_xlog_startup(void) { opCtx = AllocSetContextCreate(CurrentMemoryContext, "SP-GiST temporary context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); } void diff --git a/src/backend/access/tablesample/bernoulli.c b/src/backend/access/tablesample/bernoulli.c index bc45fd1bed..5f6d478159 100644 --- a/src/backend/access/tablesample/bernoulli.c +++ b/src/backend/access/tablesample/bernoulli.c @@ -13,7 +13,7 @@ * cutoff value computed from the selection probability by BeginSampleScan. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/tablesample/system.c b/src/backend/access/tablesample/system.c index 65f8c58d67..e270cbc4a0 100644 --- a/src/backend/access/tablesample/system.c +++ b/src/backend/access/tablesample/system.c @@ -13,7 +13,7 @@ * cutoff value computed from the selection probability by BeginSampleScan. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/tablesample/tablesample.c b/src/backend/access/tablesample/tablesample.c index d96aa5b2a3..10d2bc91b3 100644 --- a/src/backend/access/tablesample/tablesample.c +++ b/src/backend/access/tablesample/tablesample.c @@ -3,7 +3,7 @@ * tablesample.c * Support functions for TABLESAMPLE feature * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c index 263447679b..1a43819736 100644 --- a/src/backend/access/transam/clog.c +++ b/src/backend/access/transam/clog.c @@ -23,7 +23,7 @@ * for aborts (whether sync or async), since the post-crash assumption would * be that such transactions failed anyway. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/clog.c diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c index e330105217..18a5f5602c 100644 --- a/src/backend/access/transam/commit_ts.c +++ b/src/backend/access/transam/commit_ts.c @@ -15,7 +15,7 @@ * re-perform the status update on redo; so we need make no additional XLOG * entry here. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/commit_ts.c @@ -32,6 +32,7 @@ #include "funcapi.h" #include "miscadmin.h" #include "pg_trace.h" +#include "storage/shmem.h" #include "utils/builtins.h" #include "utils/snapmgr.h" #include "utils/timestamp.h" @@ -112,7 +113,7 @@ static bool CommitTsPagePrecedes(int page1, int page2); static void ActivateCommitTs(void); static void DeactivateCommitTs(void); static void WriteZeroPageXlogRec(int pageno); -static void WriteTruncateXlogRec(int pageno); +static void WriteTruncateXlogRec(int pageno, TransactionId oldestXid); static void WriteSetTimestampXlogRec(TransactionId mainxid, int nsubxids, TransactionId *subxids, TimestampTz timestamp, RepOriginId nodeid); @@ -288,11 +289,18 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts, TransactionId oldestCommitTsXid; TransactionId newestCommitTsXid; - /* error if the given Xid doesn't normally commit */ - if (!TransactionIdIsNormal(xid)) + if (!TransactionIdIsValid(xid)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("cannot retrieve commit timestamp for transaction %u", xid))); + else if (!TransactionIdIsNormal(xid)) + { + /* frozen and bootstrap xids are always committed far in the past */ + *ts = 0; + if (nodeid) + *nodeid = 0; + return false; + } LWLockAcquire(CommitTsLock, LW_SHARED); @@ -816,7 +824,7 @@ TruncateCommitTs(TransactionId oldestXact) return; /* nothing to remove */ /* Write XLOG record */ - WriteTruncateXlogRec(cutoffPage); + WriteTruncateXlogRec(cutoffPage, oldestXact); /* Now we can remove the old CommitTs segment(s) */ SimpleLruTruncate(CommitTsCtl, cutoffPage); @@ -843,6 +851,8 @@ SetCommitTsLimit(TransactionId oldestXact, TransactionId newestXact) else { Assert(ShmemVariableCache->newestCommitTsXid == InvalidTransactionId); + ShmemVariableCache->oldestCommitTsXid = oldestXact; + ShmemVariableCache->newestCommitTsXid = newestXact; } LWLockRelease(CommitTsLock); } @@ -900,10 +910,15 @@ WriteZeroPageXlogRec(int pageno) * Write a TRUNCATE xlog record */ static void -WriteTruncateXlogRec(int pageno) +WriteTruncateXlogRec(int pageno, TransactionId oldestXid) { + xl_commit_ts_truncate xlrec; + + xlrec.pageno = pageno; + xlrec.oldestXid = oldestXid; + XLogBeginInsert(); - XLogRegisterData((char *) (&pageno), sizeof(int)); + XLogRegisterData((char *) (&xlrec), SizeOfCommitTsTruncate); (void) XLogInsert(RM_COMMIT_TS_ID, COMMIT_TS_TRUNCATE); } @@ -957,17 +972,17 @@ commit_ts_redo(XLogReaderState *record) } else if (info == COMMIT_TS_TRUNCATE) { - int pageno; + xl_commit_ts_truncate *trunc = (xl_commit_ts_truncate *) XLogRecGetData(record); - memcpy(&pageno, XLogRecGetData(record), sizeof(int)); + AdvanceOldestCommitTsXid(trunc->oldestXid); /* * During XLOG replay, latest_page_number isn't set up yet; insert a * suitable value to bypass the sanity test in SimpleLruTruncate. */ - CommitTsCtl->shared->latest_page_number = pageno; + CommitTsCtl->shared->latest_page_number = trunc->pageno; - SimpleLruTruncate(CommitTsCtl, pageno); + SimpleLruTruncate(CommitTsCtl, trunc->pageno); } else if (info == COMMIT_TS_SETTS) { diff --git a/src/backend/access/transam/generic_xlog.c b/src/backend/access/transam/generic_xlog.c index 1926d98de0..eddec9bc54 100644 --- a/src/backend/access/transam/generic_xlog.c +++ b/src/backend/access/transam/generic_xlog.c @@ -4,7 +4,7 @@ * Implementation of generic xlog records. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/generic_xlog.c diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c index c2e4fa377d..59d1252ddc 100644 --- a/src/backend/access/transam/multixact.c +++ b/src/backend/access/transam/multixact.c @@ -59,7 +59,7 @@ * counter does not fall within the wraparound horizon considering the global * minimum value. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/multixact.c @@ -1570,10 +1570,8 @@ mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members) /* The cache only lives as long as the current transaction */ debug_elog2(DEBUG2, "CachePut: initializing memory context"); MXactContext = AllocSetContextCreate(TopTransactionContext, - "MultiXact Cache Context", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MAXSIZE); + "MultiXact cache context", + ALLOCSET_SMALL_SIZES); } entry = (mXactCacheEnt *) @@ -2802,7 +2800,7 @@ ReadMultiXactCounts(uint32 *multixacts, MultiXactOffset *members) * more aggressive in clamping this value. That not only causes autovacuum * to ramp up, but also makes any manual vacuums the user issues more * aggressive. This happens because vacuum_set_xid_limits() clamps the - * freeze table and and the minimum freeze age based on the effective + * freeze table and the minimum freeze age based on the effective * autovacuum_multixact_freeze_max_age this function returns. In the worst * case, we'll claim the freeze_max_age to zero, and every vacuum of any * table will try to freeze every multixact. diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c index a47eba647b..3e0ee87e20 100644 --- a/src/backend/access/transam/parallel.c +++ b/src/backend/access/transam/parallel.c @@ -3,7 +3,7 @@ * parallel.c * Infrastructure for launching parallel workers * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -24,6 +24,7 @@ #include "libpq/pqmq.h" #include "miscadmin.h" #include "optimizer/planmain.h" +#include "pgstat.h" #include "storage/ipc.h" #include "storage/sinval.h" #include "storage/spin.h" @@ -108,7 +109,6 @@ static dlist_head pcxt_list = DLIST_STATIC_INIT(pcxt_list); /* Private functions. */ static void HandleParallelMessage(ParallelContext *pcxt, int i, StringInfo msg); -static void ParallelErrorContext(void *arg); static void ParallelExtensionTrampoline(dsm_segment *seg, shm_toc *toc); static void ParallelWorkerMain(Datum main_arg); static void WaitForParallelWorkersToExit(ParallelContext *pcxt); @@ -454,7 +454,8 @@ LaunchParallelWorkers(ParallelContext *pcxt) snprintf(worker.bgw_name, BGW_MAXLEN, "parallel worker for PID %d", MyProcPid); worker.bgw_flags = - BGWORKER_SHMEM_ACCESS | BGWORKER_BACKEND_DATABASE_CONNECTION; + BGWORKER_SHMEM_ACCESS | BGWORKER_BACKEND_DATABASE_CONNECTION + | BGWORKER_CLASS_PARALLEL; worker.bgw_start_time = BgWorkerStart_ConsistentState; worker.bgw_restart_time = BGW_NEVER_RESTART; worker.bgw_main = ParallelWorkerMain; @@ -541,7 +542,8 @@ WaitForParallelWorkersToFinish(ParallelContext *pcxt) if (!anyone_alive) break; - WaitLatch(&MyProc->procLatch, WL_LATCH_SET, -1); + WaitLatch(&MyProc->procLatch, WL_LATCH_SET, -1, + WAIT_EVENT_PARALLEL_FINISH); ResetLatch(&MyProc->procLatch); } @@ -703,6 +705,9 @@ void HandleParallelMessages(void) { dlist_iter iter; + MemoryContext oldcontext; + + static MemoryContext hpm_context = NULL; /* * This is invoked from ProcessInterrupts(), and since some of the @@ -713,6 +718,21 @@ HandleParallelMessages(void) */ HOLD_INTERRUPTS(); + /* + * Moreover, CurrentMemoryContext might be pointing almost anywhere. We + * don't want to risk leaking data into long-lived contexts, so let's do + * our work here in a private context that we can reset on each use. + */ + if (hpm_context == NULL) /* first time through? */ + hpm_context = AllocSetContextCreate(TopMemoryContext, + "HandleParallelMessages", + ALLOCSET_DEFAULT_SIZES); + else + MemoryContextReset(hpm_context); + + oldcontext = MemoryContextSwitchTo(hpm_context); + + /* OK to process messages. Reset the flag saying there are more to do. */ ParallelMessagePending = false; dlist_foreach(iter, &pcxt_list) @@ -759,6 +779,11 @@ HandleParallelMessages(void) } } + MemoryContextSwitchTo(oldcontext); + + /* Might as well clear the context on our way out */ + MemoryContextReset(hpm_context); + RESUME_INTERRUPTS(); } @@ -788,30 +813,43 @@ HandleParallelMessage(ParallelContext *pcxt, int i, StringInfo msg) case 'N': /* NoticeResponse */ { ErrorData edata; - ErrorContextCallback errctx; ErrorContextCallback *save_error_context_stack; - /* - * Rethrow the error using the error context callbacks that - * were in effect when the context was created, not the - * current ones. - */ - save_error_context_stack = error_context_stack; - errctx.callback = ParallelErrorContext; - errctx.arg = NULL; - errctx.previous = pcxt->error_context_stack; - error_context_stack = &errctx; - /* Parse ErrorResponse or NoticeResponse. */ pq_parse_errornotice(msg, &edata); /* Death of a worker isn't enough justification for suicide. */ edata.elevel = Min(edata.elevel, ERROR); - /* Rethrow error or notice. */ + /* + * If desired, add a context line to show that this is a + * message propagated from a parallel worker. Otherwise, it + * can sometimes be confusing to understand what actually + * happened. (We don't do this in FORCE_PARALLEL_REGRESS mode + * because it causes test-result instability depending on + * whether a parallel worker is actually used or not.) + */ + if (force_parallel_mode != FORCE_PARALLEL_REGRESS) + { + if (edata.context) + edata.context = psprintf("%s\n%s", edata.context, + _("parallel worker")); + else + edata.context = pstrdup(_("parallel worker")); + } + + /* + * Context beyond that should use the error context callbacks + * that were in effect when the ParallelContext was created, + * not the current ones. + */ + save_error_context_stack = error_context_stack; + error_context_stack = pcxt->error_context_stack; + + /* Rethrow error or print notice. */ ThrowErrorData(&edata); - /* Restore previous context. */ + /* Not an error, so restore previous context stack. */ error_context_stack = save_error_context_stack; break; @@ -925,10 +963,8 @@ ParallelWorkerMain(Datum main_arg) Assert(CurrentResourceOwner == NULL); CurrentResourceOwner = ResourceOwnerCreate(NULL, "parallel toplevel"); CurrentMemoryContext = AllocSetContextCreate(TopMemoryContext, - "parallel worker", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + "Parallel worker", + ALLOCSET_DEFAULT_SIZES); /* * Now that we have a resource owner, we can attach to the dynamic shared @@ -1112,18 +1148,6 @@ ParallelExtensionTrampoline(dsm_segment *seg, shm_toc *toc) entrypt(seg, toc); } -/* - * Give the user a hint that this is a message propagated from a parallel - * worker. Otherwise, it can sometimes be confusing to understand what - * actually happened. - */ -static void -ParallelErrorContext(void *arg) -{ - if (force_parallel_mode != FORCE_PARALLEL_REGRESS) - errcontext("parallel worker"); -} - /* * Update shared memory with the ending location of the last WAL record we * wrote, if it's greater than the value already stored there. diff --git a/src/backend/access/transam/recovery.conf.sample b/src/backend/access/transam/recovery.conf.sample index b777400d03..7a16751541 100644 --- a/src/backend/access/transam/recovery.conf.sample +++ b/src/backend/access/transam/recovery.conf.sample @@ -67,8 +67,8 @@ # must set a recovery target. # # You may set a recovery target either by transactionId, by name, -# or by timestamp. Recovery may either include or exclude the -# transaction(s) with the recovery target value (ie, stop either +# by timestamp or by WAL position (LSN). Recovery may either include or +# exclude the transaction(s) with the recovery target value (ie, stop either # just after or just before the given target, respectively). # # @@ -78,6 +78,8 @@ # #recovery_target_xid = '' # +#recovery_target_lsn = '' # e.g. '0/70006B8' +# #recovery_target_inclusive = true # # diff --git a/src/backend/access/transam/rmgr.c b/src/backend/access/transam/rmgr.c index 31c5fd165c..9bb136218d 100644 --- a/src/backend/access/transam/rmgr.c +++ b/src/backend/access/transam/rmgr.c @@ -12,7 +12,7 @@ #include "access/gin.h" #include "access/gist_private.h" #include "access/generic_xlog.h" -#include "access/hash.h" +#include "access/hash_xlog.h" #include "access/heapam_xlog.h" #include "access/brin_xlog.h" #include "access/multixact.h" diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c index bbae5847f2..a66ef5c639 100644 --- a/src/backend/access/transam/slru.c +++ b/src/backend/access/transam/slru.c @@ -38,7 +38,7 @@ * by re-setting the page's page_dirty flag. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/slru.c @@ -216,9 +216,6 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, Assert(strlen(name) + 1 < SLRU_MAX_NAME_LENGTH); strlcpy(shared->lwlock_tranche_name, name, SLRU_MAX_NAME_LENGTH); shared->lwlock_tranche_id = tranche_id; - shared->lwlock_tranche.name = shared->lwlock_tranche_name; - shared->lwlock_tranche.array_base = shared->buffer_locks; - shared->lwlock_tranche.array_stride = sizeof(LWLockPadded); ptr += BUFFERALIGN(offset); for (slotno = 0; slotno < nslots; slotno++) @@ -237,7 +234,8 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, Assert(found); /* Register SLRU tranche in the main tranches array */ - LWLockRegisterTranche(shared->lwlock_tranche_id, &shared->lwlock_tranche); + LWLockRegisterTranche(shared->lwlock_tranche_id, + shared->lwlock_tranche_name); /* * Initialize the unshared control struct, including directory path. We diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c index 908fe2d533..a66fc0f2ad 100644 --- a/src/backend/access/transam/subtrans.c +++ b/src/backend/access/transam/subtrans.c @@ -19,7 +19,7 @@ * data across crashes. During database startup, we simply force the * currently-active page of SUBTRANS to zeroes. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/subtrans.c diff --git a/src/backend/access/transam/timeline.c b/src/backend/access/transam/timeline.c index bd91573708..c8240b112d 100644 --- a/src/backend/access/transam/timeline.c +++ b/src/backend/access/transam/timeline.c @@ -21,7 +21,7 @@ * The fields are separated by tabs. Lines beginning with # are comments, and * are ignored. Empty lines are also ignored. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/timeline.c @@ -43,7 +43,7 @@ /* * Copies all timeline history files with id's between 'begin' and 'end' - * from archive to pg_xlog. + * from archive to pg_wal. */ void restoreTimeLineHistoryFiles(TimeLineID begin, TimeLineID end) @@ -191,7 +191,7 @@ readTimeLineHistory(TimeLineID targetTLI) result = lcons(entry, result); /* - * If the history file was fetched from archive, save it in pg_xlog for + * If the history file was fetched from archive, save it in pg_wal for * future reference. */ if (fromArchive) diff --git a/src/backend/access/transam/transam.c b/src/backend/access/transam/transam.c index 1eba49a94b..c2b4318bd3 100644 --- a/src/backend/access/transam/transam.c +++ b/src/backend/access/transam/transam.c @@ -3,7 +3,7 @@ * transam.c * postgres transaction log interface routines * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c index 9f55adcaf5..5b72c1dcf5 100644 --- a/src/backend/access/transam/twophase.c +++ b/src/backend/access/transam/twophase.c @@ -3,7 +3,7 @@ * twophase.c * Two-phase commit support functions. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -1758,8 +1758,9 @@ PrescanPreparedTransactions(TransactionId **xids_p, int *nxids_p) * need to hold a lock while examining it. We still acquire the * lock to modify it, though. */ - subxids = (TransactionId *) - (buf + MAXALIGN(sizeof(TwoPhaseFileHeader))); + subxids = (TransactionId *) (buf + + MAXALIGN(sizeof(TwoPhaseFileHeader)) + + MAXALIGN(hdr->gidlen)); for (i = 0; i < hdr->nsubxacts; i++) { TransactionId subxid = subxids[i]; @@ -1877,8 +1878,9 @@ StandbyRecoverPreparedTransactions(bool overwriteOK) * Examine subtransaction XIDs ... they should all follow main * XID. */ - subxids = (TransactionId *) - (buf + MAXALIGN(sizeof(TwoPhaseFileHeader))); + subxids = (TransactionId *) (buf + + MAXALIGN(sizeof(TwoPhaseFileHeader)) + + MAXALIGN(hdr->gidlen)); for (i = 0; i < hdr->nsubxacts; i++) { TransactionId subxid = subxids[i]; @@ -1886,6 +1888,8 @@ StandbyRecoverPreparedTransactions(bool overwriteOK) Assert(TransactionIdFollows(subxid, xid)); SubTransSetParent(xid, subxid, overwriteOK); } + + pfree(buf); } } FreeDir(cldir); diff --git a/src/backend/access/transam/twophase_rmgr.c b/src/backend/access/transam/twophase_rmgr.c index 9f56e61e54..cdcc382f34 100644 --- a/src/backend/access/transam/twophase_rmgr.c +++ b/src/backend/access/transam/twophase_rmgr.c @@ -3,7 +3,7 @@ * twophase_rmgr.c * Two-phase-commit resource managers tables * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c index 2f7e645ace..fc084c5bdb 100644 --- a/src/backend/access/transam/varsup.c +++ b/src/backend/access/transam/varsup.c @@ -3,7 +3,7 @@ * varsup.c * postgres OID & XID variables support routines * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/access/transam/varsup.c diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 23f36ead7e..f6f136da3a 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -5,7 +5,7 @@ * * See src/backend/access/transam/README for more information. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -42,9 +42,11 @@ #include "miscadmin.h" #include "pgstat.h" #include "replication/logical.h" +#include "replication/logicallauncher.h" #include "replication/origin.h" #include "replication/syncrep.h" #include "replication/walsender.h" +#include "storage/condition_variable.h" #include "storage/fd.h" #include "storage/lmgr.h" #include "storage/predicate.h" @@ -327,7 +329,7 @@ static void AtSubStart_Memory(void); static void AtSubStart_ResourceOwner(void); static void ShowTransactionState(const char *str); -static void ShowTransactionStateRec(TransactionState state); +static void ShowTransactionStateRec(const char *str, TransactionState state); static const char *BlockStateAsString(TBlockState blockState); static const char *TransStateAsString(TransState state); @@ -1018,9 +1020,7 @@ AtStart_Memory(void) TopTransactionContext = AllocSetContextCreate(TopMemoryContext, "TopTransactionContext", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* * In a top-level transaction, CurTransactionContext is the same as @@ -1078,9 +1078,7 @@ AtSubStart_Memory(void) */ CurTransactionContext = AllocSetContextCreate(CurTransactionContext, "CurTransactionContext", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); s->curTransactionContext = CurTransactionContext; /* Make the CurTransactionContext active. */ @@ -2138,6 +2136,7 @@ CommitTransaction(void) AtEOXact_HashTables(true); AtEOXact_PgStat(true); AtEOXact_Snapshot(true); + AtCommit_ApplyLauncher(); pgstat_report_xact_timestamp(0); CurrentResourceOwner = NULL; @@ -2476,6 +2475,9 @@ AbortTransaction(void) /* Reset WAL record construction state */ XLogResetInsertion(); + /* Cancel condition variable sleep */ + ConditionVariableCancelSleep(); + /* * Also clean up any open wait for lock, since the lock manager will choke * if we try to wait for another lock before doing this. @@ -4948,11 +4950,8 @@ static void ShowTransactionState(const char *str) { /* skip work if message will definitely not be printed */ - if (log_min_messages <= DEBUG3 || client_min_messages <= DEBUG3) - { - elog(DEBUG3, "%s", str); - ShowTransactionStateRec(CurrentTransactionState); - } + if (log_min_messages <= DEBUG5 || client_min_messages <= DEBUG5) + ShowTransactionStateRec(str, CurrentTransactionState); } /* @@ -4960,7 +4959,7 @@ ShowTransactionState(const char *str) * Recursive subroutine for ShowTransactionState */ static void -ShowTransactionStateRec(TransactionState s) +ShowTransactionStateRec(const char *str, TransactionState s) { StringInfoData buf; @@ -4970,17 +4969,18 @@ ShowTransactionStateRec(TransactionState s) { int i; - appendStringInfo(&buf, "%u", s->childXids[0]); + appendStringInfo(&buf, ", children: %u", s->childXids[0]); for (i = 1; i < s->nChildXids; i++) appendStringInfo(&buf, " %u", s->childXids[i]); } if (s->parent) - ShowTransactionStateRec(s->parent); + ShowTransactionStateRec(str, s->parent); /* use ereport to suppress computation if msg will not be printed */ - ereport(DEBUG3, - (errmsg_internal("name: %s; blockState: %13s; state: %7s, xid/subid/cid: %u/%u/%u%s, nestlvl: %d, children: %s", + ereport(DEBUG5, + (errmsg_internal("%s(%d) name: %s; blockState: %s; state: %s, xid/subid/cid: %u/%u/%u%s%s", + str, s->nestingLevel, PointerIsValid(s->name) ? s->name : "unnamed", BlockStateAsString(s->blockState), TransStateAsString(s->state), @@ -4988,7 +4988,7 @@ ShowTransactionStateRec(TransactionState s) (unsigned int) s->subTransactionId, (unsigned int) currentCommandId, currentCommandIdUsed ? " (used)" : "", - s->nestingLevel, buf.data))); + buf.data))); pfree(buf.data); } @@ -5236,7 +5236,7 @@ XactLogCommitRecord(TimestampTz commit_time, XLogRegisterData((char *) (&xl_origin), sizeof(xl_xact_origin)); /* we allow filtering by xacts */ - XLogIncludeOrigin(); + XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN); return XLogInsert(RM_XACT_ID, info); } diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f13f9c1fa5..2f5d603066 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -4,7 +4,7 @@ * PostgreSQL transaction log manager * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/xlog.c @@ -41,6 +41,7 @@ #include "commands/tablespace.h" #include "miscadmin.h" #include "pgstat.h" +#include "port/atomics.h" #include "postmaster/bgwriter.h" #include "postmaster/walwriter.h" #include "postmaster/startup.h" @@ -51,7 +52,6 @@ #include "replication/snapbuild.h" #include "replication/walreceiver.h" #include "replication/walsender.h" -#include "storage/barrier.h" #include "storage/bufmgr.h" #include "storage/fd.h" #include "storage/ipc.h" @@ -67,6 +67,7 @@ #include "utils/builtins.h" #include "utils/guc.h" #include "utils/memutils.h" +#include "utils/pg_lsn.h" #include "utils/ps_status.h" #include "utils/relmapper.h" #include "utils/snapmgr.h" @@ -234,9 +235,9 @@ static int LocalXLogInsertAllowed = -1; * valid in the startup process. * * When ArchiveRecoveryRequested is true, but InArchiveRecovery is false, we're - * currently performing crash recovery using only XLOG files in pg_xlog, but + * currently performing crash recovery using only XLOG files in pg_wal, but * will switch to using offline XLOG archives as soon as we reach the end of - * WAL in pg_xlog. + * WAL in pg_wal. */ bool ArchiveRecoveryRequested = false; bool InArchiveRecovery = false; @@ -254,6 +255,7 @@ static RecoveryTargetAction recoveryTargetAction = RECOVERY_TARGET_ACTION_PAUSE; static TransactionId recoveryTargetXid; static TimestampTz recoveryTargetTime; static char *recoveryTargetName; +static XLogRecPtr recoveryTargetLSN; static int recovery_min_apply_delay = 0; static TimestampTz recoveryDelayUntilTime; @@ -275,6 +277,7 @@ static bool fast_promote = false; */ static TransactionId recoveryStopXid; static TimestampTz recoveryStopTime; +static XLogRecPtr recoveryStopLSN; static char recoveryStopName[MAXFNAMELEN]; static bool recoveryStopAfter; @@ -439,11 +442,21 @@ typedef struct XLogwrtResult * the WAL record is just copied to the page and the lock is released. But * to avoid the deadlock-scenario explained above, the indicator is always * updated before sleeping while holding an insertion lock. + * + * lastImportantAt contains the LSN of the last important WAL record inserted + * using a given lock. This value is used to detect if there has been + * important WAL activity since the last time some action, like a checkpoint, + * was performed - allowing to not repeat the action if not. The LSN is + * updated for all insertions, unless the XLOG_MARK_UNIMPORTANT flag was + * set. lastImportantAt is never cleared, only overwritten by the LSN of newer + * records. Tracking the WAL activity directly in WALInsertLock has the + * advantage of not needing any additional locks to update the value. */ typedef struct { LWLock lock; XLogRecPtr insertingAt; + XLogRecPtr lastImportantAt; } WALInsertLock; /* @@ -459,6 +472,29 @@ typedef union WALInsertLockPadded char pad[PG_CACHE_LINE_SIZE]; } WALInsertLockPadded; +/* + * State of an exclusive backup, necessary to control concurrent activities + * across sessions when working on exclusive backups. + * + * EXCLUSIVE_BACKUP_NONE means that there is no exclusive backup actually + * running, to be more precise pg_start_backup() is not being executed for + * an exclusive backup and there is no exclusive backup in progress. + * EXCLUSIVE_BACKUP_STARTING means that pg_start_backup() is starting an + * exclusive backup. + * EXCLUSIVE_BACKUP_IN_PROGRESS means that pg_start_backup() has finished + * running and an exclusive backup is in progress. pg_stop_backup() is + * needed to finish it. + * EXCLUSIVE_BACKUP_STOPPING means that pg_stop_backup() is stopping an + * exclusive backup. + */ +typedef enum ExclusiveBackupState +{ + EXCLUSIVE_BACKUP_NONE = 0, + EXCLUSIVE_BACKUP_STARTING, + EXCLUSIVE_BACKUP_IN_PROGRESS, + EXCLUSIVE_BACKUP_STOPPING +} ExclusiveBackupState; + /* * Shared state data for WAL insertion. */ @@ -500,13 +536,15 @@ typedef struct XLogCtlInsert bool fullPageWrites; /* - * exclusiveBackup is true if a backup started with pg_start_backup() is - * in progress, and nonExclusiveBackups is a counter indicating the number - * of streaming base backups currently in progress. forcePageWrites is set - * to true when either of these is non-zero. lastBackupStart is the latest - * checkpoint redo location used as a starting point for an online backup. + * exclusiveBackupState indicates the state of an exclusive backup + * (see comments of ExclusiveBackupState for more details). + * nonExclusiveBackups is a counter indicating the number of streaming + * base backups currently in progress. forcePageWrites is set to true + * when either of these is non-zero. lastBackupStart is the latest + * checkpoint redo location used as a starting point for an online + * backup. */ - bool exclusiveBackup; + ExclusiveBackupState exclusiveBackupState; int nonExclusiveBackups; XLogRecPtr lastBackupStart; @@ -514,7 +552,6 @@ typedef struct XLogCtlInsert * WAL insertion locks. */ WALInsertLockPadded *WALInsertLocks; - LWLockTranche WALInsertLockTranche; } XLogCtlInsert; /* @@ -539,8 +576,9 @@ typedef struct XLogCtlData XLogRecPtr unloggedLSN; slock_t ulsn_lck; - /* Time of last xlog segment switch. Protected by WALWriteLock. */ + /* Time and LSN of last xlog segment switch. Protected by WALWriteLock. */ pg_time_t lastSegSwitchTime; + XLogRecPtr lastSegSwitchLSN; /* * Protected by info_lck and WALWriteLock (you must hold either lock to @@ -612,11 +650,14 @@ typedef struct XLogCtlData /* * During recovery, we keep a copy of the latest checkpoint record here. - * Used by the background writer when it wants to create a restartpoint. + * lastCheckPointRecPtr points to start of checkpoint record and + * lastCheckPointEndPtr points to end+1 of checkpoint record. Used by the + * checkpointer when it wants to create a restartpoint. * * Protected by info_lck. */ XLogRecPtr lastCheckPointRecPtr; + XLogRecPtr lastCheckPointEndPtr; CheckPoint lastCheckPoint; /* @@ -697,12 +738,12 @@ typedef enum { XLOG_FROM_ANY = 0, /* request to read WAL from any source */ XLOG_FROM_ARCHIVE, /* restored using restore_command */ - XLOG_FROM_PG_XLOG, /* existing file in pg_xlog */ + XLOG_FROM_PG_WAL, /* existing file in pg_wal */ XLOG_FROM_STREAM /* streamed from master */ } XLogSource; /* human-readable names for XLogSources, for debugging output */ -static const char *xlogSourceNames[] = {"any", "archive", "pg_xlog", "stream"}; +static const char *xlogSourceNames[] = {"any", "archive", "pg_wal", "stream"}; /* * openLogFile is -1 or a kernel FD for an open log file segment. @@ -842,6 +883,7 @@ static void xlog_outrec(StringInfo buf, XLogReaderState *record); #endif static void xlog_outdesc(StringInfo buf, XLogReaderState *record); static void pg_start_backup_callback(int code, Datum arg); +static void pg_stop_backup_callback(int code, Datum arg); static bool read_backup_label(XLogRecPtr *checkPointLoc, bool *backupEndRequired, bool *backupFromStandby); static bool read_tablespace_map(List **tablespaces); @@ -879,6 +921,9 @@ static void WALInsertLockUpdateInsertingAt(XLogRecPtr insertingAt); * which pages need a full-page image, and retry. If fpw_lsn is invalid, the * record is always inserted. * + * 'flags' gives more in-depth control on the record being inserted. See + * XLogSetRecordFlags() for details. + * * The first XLogRecData in the chain must be for the record header, and its * data must be MAXALIGNed. XLogInsertRecord fills in the xl_prev and * xl_crc fields in the header, the rest of the header must already be filled @@ -891,14 +936,17 @@ static void WALInsertLockUpdateInsertingAt(XLogRecPtr insertingAt); * WAL rule "write the log before the data".) */ XLogRecPtr -XLogInsertRecord(XLogRecData *rdata, XLogRecPtr fpw_lsn) +XLogInsertRecord(XLogRecData *rdata, + XLogRecPtr fpw_lsn, + uint8 flags) { XLogCtlInsert *Insert = &XLogCtl->Insert; pg_crc32c rdata_crc; bool inserted; XLogRecord *rechdr = (XLogRecord *) rdata->data; + uint8 info = rechdr->xl_info & ~XLR_INFO_MASK; bool isLogSwitch = (rechdr->xl_rmid == RM_XLOG_ID && - rechdr->xl_info == XLOG_SWITCH); + info == XLOG_SWITCH); XLogRecPtr StartPos; XLogRecPtr EndPos; @@ -1007,6 +1055,18 @@ XLogInsertRecord(XLogRecData *rdata, XLogRecPtr fpw_lsn) */ CopyXLogRecordToWAL(rechdr->xl_tot_len, isLogSwitch, rdata, StartPos, EndPos); + + /* + * Unless record is flagged as not important, update LSN of last + * important record in the current slot. When holding all locks, just + * update the first one. + */ + if ((flags & XLOG_MARK_UNIMPORTANT) == 0) + { + int lockno = holdingAllLocks ? 0 : MyLockNo; + + WALInsertLocks[lockno].l.lastImportantAt = StartPos; + } } else { @@ -2326,6 +2386,7 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible) XLogArchiveNotifySeg(openLogSegNo); XLogCtl->lastSegSwitchTime = (pg_time_t) time(NULL); + XLogCtl->lastSegSwitchLSN = LogwrtResult.Flush; /* * Request a checkpoint if we've consumed too much xlog since @@ -2752,7 +2813,7 @@ XLogFlush(XLogRecPtr record) * This routine is invoked periodically by the background walwriter process. * * Returns TRUE if there was any work to do, even if we skipped flushing due - * to wal_writer_delay/wal_flush_after. + * to wal_writer_delay/wal_writer_flush_after. */ bool XLogBackgroundFlush(void) @@ -3342,7 +3403,7 @@ XLogFileOpen(XLogSegNo segno) * Open a logfile segment for reading (during recovery). * * If source == XLOG_FROM_ARCHIVE, the segment is retrieved from archive. - * Otherwise, it's assumed to be already available in pg_xlog. + * Otherwise, it's assumed to be already available in pg_wal. */ static int XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli, @@ -3371,7 +3432,7 @@ XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli, return -1; break; - case XLOG_FROM_PG_XLOG: + case XLOG_FROM_PG_WAL: case XLOG_FROM_STREAM: XLogFilePath(path, tli, segno); restoredFromArchive = false; @@ -3390,7 +3451,7 @@ XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli, KeepFileRestoredFromArchive(path, xlogfname); /* - * Set path to point at the new file in pg_xlog. + * Set path to point at the new file in pg_wal. */ snprintf(path, MAXPGPATH, XLOGDIR "/%s", xlogfname); } @@ -3478,10 +3539,10 @@ XLogFileReadAnyTLI(XLogSegNo segno, int emode, int source) } } - if (source == XLOG_FROM_ANY || source == XLOG_FROM_PG_XLOG) + if (source == XLOG_FROM_ANY || source == XLOG_FROM_PG_WAL) { fd = XLogFileRead(segno, emode, tli, - XLOG_FROM_PG_XLOG, true); + XLOG_FROM_PG_WAL, true); if (fd != -1) { if (!expectedTLEs) @@ -3690,10 +3751,10 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr PriorRedoPtr, XLogRecPtr endptr) * * This is called during recovery, whenever we switch to follow a new * timeline, and at the end of recovery when we create a new timeline. We - * wouldn't otherwise care about extra WAL files lying in pg_xlog, but they + * wouldn't otherwise care about extra WAL files lying in pg_wal, but they * might be leftover pre-allocated or recycled WAL segments on the old timeline * that we haven't used yet, and contain garbage. If we just leave them in - * pg_xlog, they will eventually be archived, and we can't let that happen. + * pg_wal, they will eventually be archived, and we can't let that happen. * Files that belong to our timeline history are valid, because we have * successfully replayed them, but from others we can't be sure. * @@ -3850,15 +3911,15 @@ RemoveXlogFile(const char *segname, XLogRecPtr PriorRedoPtr, XLogRecPtr endptr) } /* - * Verify whether pg_xlog and pg_xlog/archive_status exist. + * Verify whether pg_wal and pg_wal/archive_status exist. * If the latter does not exist, recreate it. * * It is not the goal of this function to verify the contents of these * directories, but to help in cases where someone has performed a cluster - * copy for PITR purposes but omitted pg_xlog from the copy. + * copy for PITR purposes but omitted pg_wal from the copy. * - * We could also recreate pg_xlog if it doesn't exist, but a deliberate - * policy decision was made not to. It is fairly common for pg_xlog to be + * We could also recreate pg_wal if it doesn't exist, but a deliberate + * policy decision was made not to. It is fairly common for pg_wal to be * a symlink, and if that was the DBA's intent then automatically making a * plain directory would result in degraded performance with no notice. */ @@ -3868,7 +3929,7 @@ ValidateXLOGDirectoryStructure(void) char path[MAXPGPATH]; struct stat stat_buf; - /* Check for pg_xlog; if it doesn't exist, error out */ + /* Check for pg_wal; if it doesn't exist, error out */ if (stat(XLOGDIR, &stat_buf) != 0 || !S_ISDIR(stat_buf.st_mode)) ereport(FATAL, @@ -4024,11 +4085,11 @@ ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int emode, * If archive recovery was requested, but we were still doing * crash recovery, switch to archive recovery and retry using the * offline archive. We have now replayed all the valid WAL in - * pg_xlog, so we are presumably now consistent. + * pg_wal, so we are presumably now consistent. * * We require that there's at least some valid WAL present in - * pg_xlog, however (!fetch_ckpt). We could recover using the WAL - * from the archive, even if pg_xlog is completely empty, but we'd + * pg_wal, however (!fetch_ckpt). We could recover using the WAL + * from the archive, even if pg_wal is completely empty, but we'd * have no idea how far we'd have to replay to reach consistency. * So err on the safe side and give up. */ @@ -4036,7 +4097,7 @@ ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int emode, !fetching_ckpt) { ereport(DEBUG1, - (errmsg_internal("reached end of WAL in pg_xlog, entering archive recovery"))); + (errmsg_internal("reached end of WAL in pg_wal, entering archive recovery"))); InArchiveRecovery = true; if (StandbyModeRequested) StandbyMode = true; @@ -4153,7 +4214,7 @@ rescanLatestTimeLine(void) /* * As in StartupXLOG(), try to ensure we have all the history files - * between the old target and new target in pg_xlog. + * between the old target and new target in pg_wal. */ restoreTimeLineHistoryFiles(oldtarget + 1, newtarget); @@ -4663,9 +4724,7 @@ XLOGShmemInit(void) { walDebugCxt = AllocSetContextCreate(TopMemoryContext, "WAL Debug", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); MemoryContextAllowInCriticalSection(walDebugCxt, true); } #endif @@ -4683,7 +4742,7 @@ XLOGShmemInit(void) /* Initialize local copy of WALInsertLocks and register the tranche */ WALInsertLocks = XLogCtl->Insert.WALInsertLocks; LWLockRegisterTranche(LWTRANCHE_WAL_INSERT, - &XLogCtl->Insert.WALInsertLockTranche); + "wal_insert"); return; } memset(XLogCtl, 0, sizeof(XLogCtlData)); @@ -4706,15 +4765,12 @@ XLOGShmemInit(void) (WALInsertLockPadded *) allocptr; allocptr += sizeof(WALInsertLockPadded) * NUM_XLOGINSERT_LOCKS; - XLogCtl->Insert.WALInsertLockTranche.name = "wal_insert"; - XLogCtl->Insert.WALInsertLockTranche.array_base = WALInsertLocks; - XLogCtl->Insert.WALInsertLockTranche.array_stride = sizeof(WALInsertLockPadded); - - LWLockRegisterTranche(LWTRANCHE_WAL_INSERT, &XLogCtl->Insert.WALInsertLockTranche); + LWLockRegisterTranche(LWTRANCHE_WAL_INSERT, "wal_insert"); for (i = 0; i < NUM_XLOGINSERT_LOCKS; i++) { LWLockInitialize(&WALInsertLocks[i].l.lock, LWTRANCHE_WAL_INSERT); WALInsertLocks[i].l.insertingAt = InvalidXLogRecPtr; + WALInsertLocks[i].l.lastImportantAt = InvalidXLogRecPtr; } /* @@ -5024,7 +5080,8 @@ readRecoveryCommandFile(void) rtli = (TimeLineID) strtoul(item->value, NULL, 0); if (errno == EINVAL || errno == ERANGE) ereport(FATAL, - (errmsg("recovery_target_timeline is not a valid number: \"%s\"", + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("recovery_target_timeline is not a valid number: \"%s\"", item->value))); } if (rtli) @@ -5040,7 +5097,8 @@ readRecoveryCommandFile(void) recoveryTargetXid = (TransactionId) strtoul(item->value, NULL, 0); if (errno == EINVAL || errno == ERANGE) ereport(FATAL, - (errmsg("recovery_target_xid is not a valid number: \"%s\"", + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("recovery_target_xid is not a valid number: \"%s\"", item->value))); ereport(DEBUG2, (errmsg_internal("recovery_target_xid = %u", @@ -5078,6 +5136,23 @@ readRecoveryCommandFile(void) (errmsg_internal("recovery_target_name = '%s'", recoveryTargetName))); } + else if (strcmp(item->name, "recovery_target_lsn") == 0) + { + recoveryTarget = RECOVERY_TARGET_LSN; + + /* + * Convert the LSN string given by the user to XLogRecPtr form. + */ + recoveryTargetLSN = + DatumGetLSN(DirectFunctionCall3(pg_lsn_in, + CStringGetDatum(item->value), + ObjectIdGetDatum(InvalidOid), + Int32GetDatum(-1))); + ereport(DEBUG2, + (errmsg_internal("recovery_target_lsn = '%X/%X'", + (uint32) (recoveryTargetLSN >> 32), + (uint32) recoveryTargetLSN))); + } else if (strcmp(item->name, "recovery_target") == 0) { if (strcmp(item->value, "immediate") == 0) @@ -5155,7 +5230,8 @@ readRecoveryCommandFile(void) } else ereport(FATAL, - (errmsg("unrecognized recovery parameter \"%s\"", + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unrecognized recovery parameter \"%s\"", item->name))); } @@ -5168,13 +5244,14 @@ readRecoveryCommandFile(void) ereport(WARNING, (errmsg("recovery command file \"%s\" specified neither primary_conninfo nor restore_command", RECOVERY_COMMAND_FILE), - errhint("The database server will regularly poll the pg_xlog subdirectory to check for files placed there."))); + errhint("The database server will regularly poll the pg_wal subdirectory to check for files placed there."))); } else { if (recoveryRestoreCommand == NULL) ereport(FATAL, - (errmsg("recovery command file \"%s\" must specify restore_command when standby mode is not enabled", + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("recovery command file \"%s\" must specify restore_command when standby mode is not enabled", RECOVERY_COMMAND_FILE))); } @@ -5188,6 +5265,15 @@ readRecoveryCommandFile(void) !EnableHotStandby) recoveryTargetAction = RECOVERY_TARGET_ACTION_SHUTDOWN; + /* + * We don't support standby_mode in standalone backends; that requires + * other processes such as the WAL receiver to be alive. + */ + if (StandbyModeRequested && !IsUnderPostmaster) + ereport(FATAL, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("standby mode is not supported by single-user servers"))); + /* Enable fetching from archive recovery area */ ArchiveRecoveryRequested = true; @@ -5204,7 +5290,8 @@ readRecoveryCommandFile(void) /* Timeline 1 does not have a history file, all else should */ if (rtli != 1 && !existsTimeLineHistory(rtli)) ereport(FATAL, - (errmsg("recovery target timeline %u does not exist", + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("recovery target timeline %u does not exist", rtli))); recoveryTargetTLI = rtli; recoveryTargetIsLatest = false; @@ -5388,11 +5475,29 @@ recoveryStopsBefore(XLogReaderState *record) recoveryStopAfter = false; recoveryStopXid = InvalidTransactionId; + recoveryStopLSN = InvalidXLogRecPtr; recoveryStopTime = 0; recoveryStopName[0] = '\0'; return true; } + /* Check if target LSN has been reached */ + if (recoveryTarget == RECOVERY_TARGET_LSN && + !recoveryTargetInclusive && + record->ReadRecPtr >= recoveryTargetLSN) + { + recoveryStopAfter = false; + recoveryStopXid = InvalidTransactionId; + recoveryStopLSN = record->ReadRecPtr; + recoveryStopTime = 0; + recoveryStopName[0] = '\0'; + ereport(LOG, + (errmsg("recovery stopping before WAL position (LSN) \"%X/%X\"", + (uint32) (recoveryStopLSN >> 32), + (uint32) recoveryStopLSN))); + return true; + } + /* Otherwise we only consider stopping before COMMIT or ABORT records. */ if (XLogRecGetRmid(record) != RM_XACT_ID) return false; @@ -5467,6 +5572,7 @@ recoveryStopsBefore(XLogReaderState *record) recoveryStopAfter = false; recoveryStopXid = recordXid; recoveryStopTime = recordXtime; + recoveryStopLSN = InvalidXLogRecPtr; recoveryStopName[0] = '\0'; if (isCommit) @@ -5520,6 +5626,7 @@ recoveryStopsAfter(XLogReaderState *record) { recoveryStopAfter = true; recoveryStopXid = InvalidTransactionId; + recoveryStopLSN = InvalidXLogRecPtr; (void) getRecordTimestamp(record, &recoveryStopTime); strlcpy(recoveryStopName, recordRestorePointData->rp_name, MAXFNAMELEN); @@ -5531,6 +5638,23 @@ recoveryStopsAfter(XLogReaderState *record) } } + /* Check if the target LSN has been reached */ + if (recoveryTarget == RECOVERY_TARGET_LSN && + recoveryTargetInclusive && + record->ReadRecPtr >= recoveryTargetLSN) + { + recoveryStopAfter = true; + recoveryStopXid = InvalidTransactionId; + recoveryStopLSN = record->ReadRecPtr; + recoveryStopTime = 0; + recoveryStopName[0] = '\0'; + ereport(LOG, + (errmsg("recovery stopping after WAL position (LSN) \"%X/%X\"", + (uint32) (recoveryStopLSN >> 32), + (uint32) recoveryStopLSN))); + return true; + } + if (rmid != RM_XACT_ID) return false; @@ -5586,6 +5710,7 @@ recoveryStopsAfter(XLogReaderState *record) recoveryStopAfter = true; recoveryStopXid = recordXid; recoveryStopTime = recordXtime; + recoveryStopLSN = InvalidXLogRecPtr; recoveryStopName[0] = '\0'; if (xact_info == XLOG_XACT_COMMIT || @@ -5617,6 +5742,7 @@ recoveryStopsAfter(XLogReaderState *record) recoveryStopAfter = true; recoveryStopXid = InvalidTransactionId; recoveryStopTime = 0; + recoveryStopLSN = InvalidXLogRecPtr; recoveryStopName[0] = '\0'; return true; } @@ -5756,7 +5882,8 @@ recoveryApplyDelay(XLogReaderState *record) WaitLatch(&XLogCtl->recoveryWakeupLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - secs * 1000L + microsecs / 1000); + secs * 1000L + microsecs / 1000, + WAIT_EVENT_RECOVERY_APPLY_DELAY); } return true; } @@ -5984,7 +6111,7 @@ StartupXLOG(void) #endif /* - * Verify that pg_xlog and pg_xlog/archive_status exist. In cases where + * Verify that pg_wal and pg_wal/archive_status exist. In cases where * someone has performed a copy for PITR, these directories may have been * excluded and need to be re-created. */ @@ -6043,6 +6170,11 @@ StartupXLOG(void) ereport(LOG, (errmsg("starting point-in-time recovery to \"%s\"", recoveryTargetName))); + else if (recoveryTarget == RECOVERY_TARGET_LSN) + ereport(LOG, + (errmsg("starting point-in-time recovery to WAL position (LSN) \"%X/%X\"", + (uint32) (recoveryTargetLSN >> 32), + (uint32) recoveryTargetLSN))); else if (recoveryTarget == RECOVERY_TARGET_IMMEDIATE) ereport(LOG, (errmsg("starting point-in-time recovery to earliest consistent point"))); @@ -6090,7 +6222,7 @@ StartupXLOG(void) if (record != NULL) { memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint)); - wasShutdown = (record->xl_info == XLOG_CHECKPOINT_SHUTDOWN); + wasShutdown = ((record->xl_info & ~XLR_INFO_MASK) == XLOG_CHECKPOINT_SHUTDOWN); ereport(DEBUG1, (errmsg("checkpoint record is at %X/%X", (uint32) (checkPointLoc >> 32), (uint32) checkPointLoc))); @@ -6192,7 +6324,7 @@ StartupXLOG(void) * and put it into archive recovery by creating a recovery.conf file. * * Our strategy in that case is to perform crash recovery first, - * replaying all the WAL present in pg_xlog, and only enter archive + * replaying all the WAL present in pg_wal, and only enter archive * recovery after that. * * But usually we already know how far we need to replay the WAL (up @@ -6248,7 +6380,7 @@ StartupXLOG(void) (errmsg("could not locate a valid checkpoint record"))); } memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint)); - wasShutdown = (record->xl_info == XLOG_CHECKPOINT_SHUTDOWN); + wasShutdown = ((record->xl_info & ~XLR_INFO_MASK) == XLOG_CHECKPOINT_SHUTDOWN); } /* @@ -6396,7 +6528,7 @@ StartupXLOG(void) /* * Copy any missing timeline history files between 'now' and the recovery - * target timeline from archive to pg_xlog. While we don't need those + * target timeline from archive to pg_wal. While we don't need those * files ourselves - the history file of the recovery target timeline * covers all the previous timelines in the history too - a cascading * standby server might be interested in them. Or, if you archive the WAL @@ -7017,7 +7149,7 @@ StartupXLOG(void) /* * We are now done reading the xlog from stream. Turn off streaming * recovery to force fetching the files (which would be required at end of - * recovery, e.g., timeline history file) from archive or pg_xlog. + * recovery, e.g., timeline history file) from archive or pg_wal. */ StandbyMode = false; @@ -7112,6 +7244,12 @@ StartupXLOG(void) "%s %s\n", recoveryStopAfter ? "after" : "before", timestamptz_to_str(recoveryStopTime)); + else if (recoveryTarget == RECOVERY_TARGET_LSN) + snprintf(reason, sizeof(reason), + "%s LSN %X/%X\n", + recoveryStopAfter ? "after" : "before", + (uint32 ) (recoveryStopLSN >> 32), + (uint32) recoveryStopLSN); else if (recoveryTarget == RECOVERY_TARGET_NAME) snprintf(reason, sizeof(reason), "at restore point \"%s\"", @@ -7299,7 +7437,7 @@ StartupXLOG(void) * As a compromise, we rename the last segment with the .partial * suffix, and archive it. Archive recovery will never try to read * .partial segments, so they will normally go unused. But in the odd - * PITR case, the administrator can copy them manually to the pg_xlog + * PITR case, the administrator can copy them manually to the pg_wal * directory (removing the suffix). They can be useful in debugging, * too. * @@ -7349,14 +7487,9 @@ StartupXLOG(void) */ InRecovery = false; - LWLockAcquire(ControlFileLock, LW_EXCLUSIVE); - ControlFile->state = DB_IN_PRODUCTION; - ControlFile->time = (pg_time_t) time(NULL); - UpdateControlFile(); - LWLockRelease(ControlFileLock); - - /* start the archive_timeout timer running */ + /* start the archive_timeout timer and LSN running */ XLogCtl->lastSegSwitchTime = (pg_time_t) time(NULL); + XLogCtl->lastSegSwitchLSN = EndOfLog; /* also initialize latestCompletedXid, to nextXid - 1 */ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); @@ -7412,15 +7545,32 @@ StartupXLOG(void) CompleteCommitTsInitialization(); /* - * All done. Allow backends to write WAL. (Although the bool flag is - * probably atomic in itself, we use the info_lck here to ensure that - * there are no race conditions concerning visibility of other recent - * updates to shared memory.) + * All done with end-of-recovery actions. + * + * Now allow backends to write WAL and update the control file status in + * consequence. The boolean flag allowing backends to write WAL is + * updated while holding ControlFileLock to prevent other backends to look + * at an inconsistent state of the control file in shared memory. There + * is still a small window during which backends can write WAL and the + * control file is still referring to a system not in DB_IN_PRODUCTION + * state while looking at the on-disk control file. + * + * Also, although the boolean flag to allow WAL is probably atomic in + * itself, we use the info_lck here to ensure that there are no race + * conditions concerning visibility of other recent updates to shared + * memory. */ + LWLockAcquire(ControlFileLock, LW_EXCLUSIVE); + ControlFile->state = DB_IN_PRODUCTION; + ControlFile->time = (pg_time_t) time(NULL); + SpinLockAcquire(&XLogCtl->info_lck); XLogCtl->SharedRecoveryInProgress = false; SpinLockRelease(&XLogCtl->info_lck); + UpdateControlFile(); + LWLockRelease(ControlFileLock); + /* * If there were cascading standby servers connected to us, nudge any wal * sender processes to notice that we've been promoted. @@ -7688,6 +7838,7 @@ ReadCheckpointRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int whichChkpt, bool report) { XLogRecord *record; + uint8 info; if (!XRecOffIsValid(RecPtr)) { @@ -7755,8 +7906,9 @@ ReadCheckpointRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, } return NULL; } - if (record->xl_info != XLOG_CHECKPOINT_SHUTDOWN && - record->xl_info != XLOG_CHECKPOINT_ONLINE) + info = record->xl_info & ~XLR_INFO_MASK; + if (info != XLOG_CHECKPOINT_SHUTDOWN && + info != XLOG_CHECKPOINT_ONLINE) { switch (whichChkpt) { @@ -7899,16 +8051,51 @@ GetFlushRecPtr(void) } /* - * Get the time of the last xlog segment switch + * GetLastImportantRecPtr -- Returns the LSN of the last important record + * inserted. All records not explicitly marked as unimportant are considered + * important. + * + * The LSN is determined by computing the maximum of + * WALInsertLocks[i].lastImportantAt. + */ +XLogRecPtr +GetLastImportantRecPtr(void) +{ + XLogRecPtr res = InvalidXLogRecPtr; + int i; + + for (i = 0; i < NUM_XLOGINSERT_LOCKS; i++) + { + XLogRecPtr last_important; + + /* + * Need to take a lock to prevent torn reads of the LSN, which are + * possible on some of the supported platforms. WAL insert locks only + * support exclusive mode, so we have to use that. + */ + LWLockAcquire(&WALInsertLocks[i].l.lock, LW_EXCLUSIVE); + last_important = WALInsertLocks[i].l.lastImportantAt; + LWLockRelease(&WALInsertLocks[i].l.lock); + + if (res < last_important) + res = last_important; + } + + return res; +} + +/* + * Get the time and LSN of the last xlog segment switch */ pg_time_t -GetLastSegSwitchTime(void) +GetLastSegSwitchData(XLogRecPtr *lastSwitchLSN) { pg_time_t result; /* Need WALWriteLock, but shared lock is sufficient */ LWLockAcquire(WALWriteLock, LW_SHARED); result = XLogCtl->lastSegSwitchTime; + *lastSwitchLSN = XLogCtl->lastSegSwitchLSN; LWLockRelease(WALWriteLock); return result; @@ -7970,7 +8157,7 @@ ShutdownXLOG(int code, Datum arg) * record will go to the next XLOG file and won't be archived (yet). */ if (XLogArchivingActive() && XLogArchiveCommandSet()) - RequestXLogSwitch(); + RequestXLogSwitch(false); CreateCheckPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_IMMEDIATE); } @@ -8158,7 +8345,7 @@ CreateCheckPoint(int flags) uint32 freespace; XLogRecPtr PriorRedoPtr; XLogRecPtr curInsert; - XLogRecPtr prevPtr; + XLogRecPtr last_important_lsn; VirtualTransactionId *vxids; int nvxids; @@ -8238,39 +8425,34 @@ CreateCheckPoint(int flags) else checkPoint.oldestActiveXid = InvalidTransactionId; + /* + * Get location of last important record before acquiring insert locks (as + * GetLastImportantRecPtr() also locks WAL locks). + */ + last_important_lsn = GetLastImportantRecPtr(); + /* * We must block concurrent insertions while examining insert state to * determine the checkpoint REDO pointer. */ WALInsertLockAcquireExclusive(); curInsert = XLogBytePosToRecPtr(Insert->CurrBytePos); - prevPtr = XLogBytePosToRecPtr(Insert->PrevBytePos); /* - * If this isn't a shutdown or forced checkpoint, and we have not inserted - * any XLOG records since the start of the last checkpoint, skip the - * checkpoint. The idea here is to avoid inserting duplicate checkpoints - * when the system is idle. That wastes log space, and more importantly it - * exposes us to possible loss of both current and previous checkpoint - * records if the machine crashes just as we're writing the update. - * (Perhaps it'd make even more sense to checkpoint only when the previous - * checkpoint record is in a different xlog page?) - * - * If the previous checkpoint crossed a WAL segment, however, we create - * the checkpoint anyway, to have the latest checkpoint fully contained in - * the new segment. This is for a little bit of extra robustness: it's - * better if you don't need to keep two WAL segments around to recover the - * checkpoint. + * If this isn't a shutdown or forced checkpoint, and if there has been no + * WAL activity requiring a checkpoint, skip it. The idea here is to + * avoid inserting duplicate checkpoints when the system is idle. */ if ((flags & (CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_END_OF_RECOVERY | CHECKPOINT_FORCE)) == 0) { - if (prevPtr == ControlFile->checkPointCopy.redo && - prevPtr / XLOG_SEG_SIZE == curInsert / XLOG_SEG_SIZE) + if (last_important_lsn == ControlFile->checkPoint) { WALInsertLockRelease(); LWLockRelease(CheckpointLock); END_CRIT_SECTION(); + ereport(DEBUG1, + (errmsg("checkpoint skipped due to an idle system"))); return; } } @@ -8679,6 +8861,7 @@ RecoveryRestartPoint(const CheckPoint *checkPoint) */ SpinLockAcquire(&XLogCtl->info_lck); XLogCtl->lastCheckPointRecPtr = ReadRecPtr; + XLogCtl->lastCheckPointEndPtr = EndRecPtr; XLogCtl->lastCheckPoint = *checkPoint; SpinLockRelease(&XLogCtl->info_lck); } @@ -8698,6 +8881,7 @@ bool CreateRestartPoint(int flags) { XLogRecPtr lastCheckPointRecPtr; + XLogRecPtr lastCheckPointEndPtr; CheckPoint lastCheckPoint; XLogRecPtr PriorRedoPtr; TimestampTz xtime; @@ -8711,6 +8895,7 @@ CreateRestartPoint(int flags) /* Get a local copy of the last safe checkpoint record. */ SpinLockAcquire(&XLogCtl->info_lck); lastCheckPointRecPtr = XLogCtl->lastCheckPointRecPtr; + lastCheckPointEndPtr = XLogCtl->lastCheckPointEndPtr; lastCheckPoint = XLogCtl->lastCheckPoint; SpinLockRelease(&XLogCtl->info_lck); @@ -8814,6 +8999,27 @@ CreateRestartPoint(int flags) ControlFile->checkPoint = lastCheckPointRecPtr; ControlFile->checkPointCopy = lastCheckPoint; ControlFile->time = (pg_time_t) time(NULL); + + /* + * Ensure minRecoveryPoint is past the checkpoint record. Normally, + * this will have happened already while writing out dirty buffers, + * but not necessarily - e.g. because no buffers were dirtied. We do + * this because a non-exclusive base backup uses minRecoveryPoint to + * determine which WAL files must be included in the backup, and the + * file (or files) containing the checkpoint record must be included, + * at a minimum. Note that for an ordinary restart of recovery there's + * no value in having the minimum recovery point any earlier than this + * anyway, because redo will begin just after the checkpoint record. + */ + if (ControlFile->minRecoveryPoint < lastCheckPointEndPtr) + { + ControlFile->minRecoveryPoint = lastCheckPointEndPtr; + ControlFile->minRecoveryPointTLI = lastCheckPoint.ThisTimeLineID; + + /* update local copy */ + minRecoveryPoint = ControlFile->minRecoveryPoint; + minRecoveryPointTLI = ControlFile->minRecoveryPointTLI; + } if (flags & CHECKPOINT_IS_SHUTDOWN) ControlFile->state = DB_SHUTDOWNED_IN_RECOVERY; UpdateControlFile(); @@ -9003,12 +9209,15 @@ XLogPutNextOid(Oid nextOid) * write a switch record because we are already at segment start. */ XLogRecPtr -RequestXLogSwitch(void) +RequestXLogSwitch(bool mark_unimportant) { XLogRecPtr RecPtr; /* XLOG SWITCH has no data */ XLogBeginInsert(); + + if (mark_unimportant) + XLogSetRecordFlags(XLOG_MARK_UNIMPORTANT); RecPtr = XLogInsert(RM_XLOG_ID, XLOG_SWITCH); return RecPtr; @@ -9833,7 +10042,12 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p, WALInsertLockAcquireExclusive(); if (exclusive) { - if (XLogCtl->Insert.exclusiveBackup) + /* + * At first, mark that we're now starting an exclusive backup, + * to ensure that there are no other sessions currently running + * pg_start_backup() or pg_stop_backup(). + */ + if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_NONE) { WALInsertLockRelease(); ereport(ERROR, @@ -9841,7 +10055,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p, errmsg("a backup is already in progress"), errhint("Run pg_stop_backup() and try again."))); } - XLogCtl->Insert.exclusiveBackup = true; + XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STARTING; } else XLogCtl->Insert.nonExclusiveBackups++; @@ -9864,7 +10078,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p, * first WAL segment containing the startup checkpoint has pages in * the beginning with the old timeline ID. That can cause trouble at * recovery: we won't have a history file covering the old timeline if - * pg_xlog directory was not included in the base backup and the WAL + * pg_wal directory was not included in the base backup and the WAL * archive was cleared too before starting the backup. * * This also ensures that we have emitted a WAL page header that has @@ -9878,7 +10092,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p, * recovery case described above. */ if (!backup_started_in_recovery) - RequestXLogSwitch(); + RequestXLogSwitch(false); do { @@ -10096,7 +10310,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p, { /* * Check for existing backup label --- implies a backup is already - * running. (XXX given that we checked exclusiveBackup above, + * running. (XXX given that we checked exclusiveBackupState above, * maybe it would be OK to just unlink any such label file?) */ if (stat(BACKUP_LABEL_FILE, &stat_buf) != 0) @@ -10177,6 +10391,16 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p, } PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive)); + /* + * Mark that start phase has correctly finished for an exclusive backup. + */ + if (exclusive) + { + WALInsertLockAcquireExclusive(); + XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS; + WALInsertLockRelease(); + } + /* * We're done. As a convenience, return the starting WAL location. */ @@ -10195,8 +10419,8 @@ pg_start_backup_callback(int code, Datum arg) WALInsertLockAcquireExclusive(); if (exclusive) { - Assert(XLogCtl->Insert.exclusiveBackup); - XLogCtl->Insert.exclusiveBackup = false; + Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STARTING); + XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE; } else { @@ -10204,7 +10428,7 @@ pg_start_backup_callback(int code, Datum arg) XLogCtl->Insert.nonExclusiveBackups--; } - if (!XLogCtl->Insert.exclusiveBackup && + if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE && XLogCtl->Insert.nonExclusiveBackups == 0) { XLogCtl->Insert.forcePageWrites = false; @@ -10212,10 +10436,28 @@ pg_start_backup_callback(int code, Datum arg) WALInsertLockRelease(); } +/* + * Error cleanup callback for pg_stop_backup + */ +static void +pg_stop_backup_callback(int code, Datum arg) +{ + bool exclusive = DatumGetBool(arg); + + /* Update backup status on failure */ + WALInsertLockAcquireExclusive(); + if (exclusive) + { + Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STOPPING); + XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS; + } + WALInsertLockRelease(); +} + /* * do_pg_stop_backup is the workhorse of the user-visible pg_stop_backup() * function. - + * * If labelfile is NULL, this stops an exclusive backup. Otherwise this stops * the non-exclusive backup specified by 'labelfile'. * @@ -10274,20 +10516,91 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p) errmsg("WAL level not sufficient for making an online backup"), errhint("wal_level must be set to \"replica\" or \"logical\" at server start."))); - /* - * OK to update backup counters and forcePageWrites - */ - WALInsertLockAcquireExclusive(); if (exclusive) { - if (!XLogCtl->Insert.exclusiveBackup) + /* + * At first, mark that we're now stopping an exclusive backup, + * to ensure that there are no other sessions currently running + * pg_start_backup() or pg_stop_backup(). + */ + WALInsertLockAcquireExclusive(); + if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_IN_PROGRESS) { WALInsertLockRelease(); ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("exclusive backup not in progress"))); } - XLogCtl->Insert.exclusiveBackup = false; + XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STOPPING; + WALInsertLockRelease(); + + /* + * Remove backup_label. In case of failure, the state for an exclusive + * backup is switched back to in-progress. + */ + PG_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive)); + { + /* + * Read the existing label file into memory. + */ + struct stat statbuf; + int r; + + if (stat(BACKUP_LABEL_FILE, &statbuf)) + { + /* should not happen per the upper checks */ + if (errno != ENOENT) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not stat file \"%s\": %m", + BACKUP_LABEL_FILE))); + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("a backup is not in progress"))); + } + + lfp = AllocateFile(BACKUP_LABEL_FILE, "r"); + if (!lfp) + { + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not read file \"%s\": %m", + BACKUP_LABEL_FILE))); + } + labelfile = palloc(statbuf.st_size + 1); + r = fread(labelfile, statbuf.st_size, 1, lfp); + labelfile[statbuf.st_size] = '\0'; + + /* + * Close and remove the backup label file + */ + if (r != 1 || ferror(lfp) || FreeFile(lfp)) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not read file \"%s\": %m", + BACKUP_LABEL_FILE))); + if (unlink(BACKUP_LABEL_FILE) != 0) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not remove file \"%s\": %m", + BACKUP_LABEL_FILE))); + + /* + * Remove tablespace_map file if present, it is created only if there + * are tablespaces. + */ + unlink(TABLESPACE_MAP); + } + PG_END_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive)); + } + + /* + * OK to update backup counters and forcePageWrites + */ + WALInsertLockAcquireExclusive(); + if (exclusive) + { + XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE; } else { @@ -10301,66 +10614,13 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p) XLogCtl->Insert.nonExclusiveBackups--; } - if (!XLogCtl->Insert.exclusiveBackup && + if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE && XLogCtl->Insert.nonExclusiveBackups == 0) { XLogCtl->Insert.forcePageWrites = false; } WALInsertLockRelease(); - if (exclusive) - { - /* - * Read the existing label file into memory. - */ - struct stat statbuf; - int r; - - if (stat(BACKUP_LABEL_FILE, &statbuf)) - { - if (errno != ENOENT) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not stat file \"%s\": %m", - BACKUP_LABEL_FILE))); - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("a backup is not in progress"))); - } - - lfp = AllocateFile(BACKUP_LABEL_FILE, "r"); - if (!lfp) - { - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not read file \"%s\": %m", - BACKUP_LABEL_FILE))); - } - labelfile = palloc(statbuf.st_size + 1); - r = fread(labelfile, statbuf.st_size, 1, lfp); - labelfile[statbuf.st_size] = '\0'; - - /* - * Close and remove the backup label file - */ - if (r != 1 || ferror(lfp) || FreeFile(lfp)) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not read file \"%s\": %m", - BACKUP_LABEL_FILE))); - if (unlink(BACKUP_LABEL_FILE) != 0) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not remove file \"%s\": %m", - BACKUP_LABEL_FILE))); - - /* - * Remove tablespace_map file if present, it is created only if there - * are tablespaces. - */ - unlink(TABLESPACE_MAP); - } - /* * Read and parse the START WAL LOCATION line (this code is pretty crude, * but we are not expecting any variability in the file format). @@ -10463,7 +10723,7 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p) * Force a switch to a new xlog segment file, so that the backup is valid * as soon as archiver moves out the current segment file. */ - RequestXLogSwitch(); + RequestXLogSwitch(false); XLByteToPrevSeg(stoppoint, _logSegNo); XLogFileName(stopxlogfilename, ThisTimeLineID, _logSegNo); @@ -10511,7 +10771,7 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p) * archived before returning. If archiving isn't enabled, the required WAL * needs to be transported via streaming replication (hopefully with * wal_keep_segments set high enough), or some more exotic mechanism like - * polling and copying files from pg_xlog with script. We have no + * polling and copying files from pg_wal with script. We have no * knowledge of those mechanisms, so it's up to the user to ensure that he * gets all the required WAL. * @@ -10597,7 +10857,7 @@ do_pg_abort_backup(void) Assert(XLogCtl->Insert.nonExclusiveBackups > 0); XLogCtl->Insert.nonExclusiveBackups--; - if (!XLogCtl->Insert.exclusiveBackup && + if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE && XLogCtl->Insert.nonExclusiveBackups == 0) { XLogCtl->Insert.forcePageWrites = false; @@ -11101,9 +11361,9 @@ XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen, * Open the WAL segment containing WAL position 'RecPtr'. * * The segment can be fetched via restore_command, or via walreceiver having - * streamed the record, or it can already be present in pg_xlog. Checking - * pg_xlog is mainly for crash recovery, but it will be polled in standby mode - * too, in case someone copies a new segment directly to pg_xlog. That is not + * streamed the record, or it can already be present in pg_wal. Checking + * pg_wal is mainly for crash recovery, but it will be polled in standby mode + * too, in case someone copies a new segment directly to pg_wal. That is not * documented or recommended, though. * * If 'fetching_ckpt' is true, we're fetching a checkpoint record, and should @@ -11133,8 +11393,8 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, /*------- * Standby mode is implemented by a state machine: * - * 1. Read from either archive or pg_xlog (XLOG_FROM_ARCHIVE), or just - * pg_xlog (XLOG_FROM_XLOG) + * 1. Read from either archive or pg_wal (XLOG_FROM_ARCHIVE), or just + * pg_wal (XLOG_FROM_PG_WAL) * 2. Check trigger file * 3. Read from primary server via walreceiver (XLOG_FROM_STREAM) * 4. Rescan timelines @@ -11150,7 +11410,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, *------- */ if (!InArchiveRecovery) - currentSource = XLOG_FROM_PG_XLOG; + currentSource = XLOG_FROM_PG_WAL; else if (currentSource == 0) currentSource = XLOG_FROM_ARCHIVE; @@ -11169,13 +11429,13 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, switch (currentSource) { case XLOG_FROM_ARCHIVE: - case XLOG_FROM_PG_XLOG: + case XLOG_FROM_PG_WAL: /* * Check to see if the trigger file exists. Note that we * do this only after failure, so when you create the * trigger file, we still finish replaying as much as we - * can from archive and pg_xlog before failover. + * can from archive and pg_wal before failover. */ if (StandbyMode && CheckForStandbyTrigger()) { @@ -11185,7 +11445,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, /* * Not in standby mode, and we've now tried the archive - * and pg_xlog. + * and pg_wal. */ if (!StandbyMode) return false; @@ -11245,7 +11505,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, * little chance that the problem will just go away, but * PANIC is not good for availability either, especially * in hot standby mode. So, we treat that the same as - * disconnection, and retry from archive/pg_xlog again. + * disconnection, and retry from archive/pg_wal again. * The WAL in the archive should be identical to what was * streamed, so it's unlikely that it helps, but one can * hope... @@ -11294,7 +11554,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, WaitLatch(&XLogCtl->recoveryWakeupLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - wait_time); + wait_time, WAIT_EVENT_RECOVERY_WAL_STREAM); ResetLatch(&XLogCtl->recoveryWakeupLatch); now = GetCurrentTimestamp(); } @@ -11306,11 +11566,11 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, elog(ERROR, "unexpected WAL source %d", currentSource); } } - else if (currentSource == XLOG_FROM_PG_XLOG) + else if (currentSource == XLOG_FROM_PG_WAL) { /* - * We just successfully read a file in pg_xlog. We prefer files in - * the archive over ones in pg_xlog, so try the next file again + * We just successfully read a file in pg_wal. We prefer files in + * the archive over ones in pg_wal, so try the next file again * from the archive first. */ if (InArchiveRecovery) @@ -11331,7 +11591,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, switch (currentSource) { case XLOG_FROM_ARCHIVE: - case XLOG_FROM_PG_XLOG: + case XLOG_FROM_PG_WAL: /* Close any old file we might have open. */ if (readFile >= 0) { @@ -11344,7 +11604,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, /* * Try to restore the file from archive, or read an existing - * file from pg_xlog. + * file from pg_wal. */ readFile = XLogFileReadAnyTLI(readSegNo, DEBUG2, currentSource == XLOG_FROM_ARCHIVE ? XLOG_FROM_ANY : @@ -11353,7 +11613,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, return true; /* success! */ /* - * Nope, not found in archive or pg_xlog. + * Nope, not found in archive or pg_wal. */ lastSourceFailed = true; break; @@ -11409,7 +11669,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, * not open already. Also read the timeline history * file if we haven't initialized timeline history * yet; it should be streamed over and present in - * pg_xlog by now. Use XLOG_FROM_STREAM so that + * pg_wal by now. Use XLOG_FROM_STREAM so that * source info is set correctly and XLogReceiptTime * isn't changed. */ @@ -11441,10 +11701,10 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, /* * Note that we don't "return false" immediately here. * After being triggered, we still want to replay all - * the WAL that was already streamed. It's in pg_xlog + * the WAL that was already streamed. It's in pg_wal * now, so we just treat this as a failure, and the * state machine will move on to replay the streamed - * WAL from pg_xlog, and then recheck the trigger and + * WAL from pg_wal, and then recheck the trigger and * exit replay. */ lastSourceFailed = true; @@ -11457,7 +11717,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, */ WaitLatch(&XLogCtl->recoveryWakeupLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - 5000L); + 5000L, WAIT_EVENT_RECOVERY_WAL_ALL); ResetLatch(&XLogCtl->recoveryWakeupLatch); break; } @@ -11484,7 +11744,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, * or legitimate end-of-WAL situation. Generally, we use it as-is, but if * we're retrying the exact same record that we've tried previously, only * complain the first time to keep the noise down. However, we only do when - * reading from pg_xlog, because we don't expect any invalid records in archive + * reading from pg_wal, because we don't expect any invalid records in archive * or in records streamed from master. Files in the archive should be complete, * and we should never hit the end of WAL because we stop and wait for more WAL * to arrive before replaying it. @@ -11499,7 +11759,7 @@ emode_for_corrupt_record(int emode, XLogRecPtr RecPtr) { static XLogRecPtr lastComplaint = 0; - if (readSource == XLOG_FROM_PG_XLOG && emode == LOG) + if (readSource == XLOG_FROM_PG_WAL && emode == LOG) { if (RecPtr == lastComplaint) emode = DEBUG1; diff --git a/src/backend/access/transam/xlogarchive.c b/src/backend/access/transam/xlogarchive.c index d153a44ea9..7e91e8f81a 100644 --- a/src/backend/access/transam/xlogarchive.c +++ b/src/backend/access/transam/xlogarchive.c @@ -4,7 +4,7 @@ * Functions for archiving WAL files and restoring from the archive. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/xlogarchive.c @@ -421,7 +421,7 @@ ExecuteRecoveryCommand(char *command, char *commandName, bool failOnSignal) /* * A file was restored from the archive under a temporary filename (path), * and now we want to keep it. Rename it under the permanent filename in - * in pg_xlog (xlogfname), replacing any existing file with the same name. + * in pg_wal (xlogfname), replacing any existing file with the same name. */ void KeepFileRestoredFromArchive(char *path, char *xlogfname) diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c index 33383b4dcc..63e6552ce7 100644 --- a/src/backend/access/transam/xlogfuncs.c +++ b/src/backend/access/transam/xlogfuncs.c @@ -7,7 +7,7 @@ * This file contains WAL control and information functions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/xlogfuncs.c @@ -18,7 +18,6 @@ #include "access/htup_details.h" #include "access/xlog.h" -#include "access/xlog_fn.h" #include "access/xlog_internal.h" #include "access/xlogutils.h" #include "catalog/catalog.h" @@ -128,7 +127,7 @@ pg_start_backup(PG_FUNCTION_ARGS) * pg_stop_backup: finish taking an on-line backup dump * * We write an end-of-backup WAL record, and remove the backup label file - * created by pg_start_backup, creating a backup history file in pg_xlog + * created by pg_start_backup, creating a backup history file in pg_wal * instead (whence it will immediately be archived). The backup history file * contains the same info found in the label file, plus the backup-end time * and WAL location. Before 9.0, the backup-end time was read from the backup @@ -293,7 +292,7 @@ pg_switch_xlog(PG_FUNCTION_ARGS) errmsg("recovery is in progress"), errhint("WAL control functions cannot be executed during recovery."))); - switchpoint = RequestXLogSwitch(); + switchpoint = RequestXLogSwitch(false); /* * As a convenience, return the WAL location of the switch record diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c index c37003a24c..a5aa58d845 100644 --- a/src/backend/access/transam/xloginsert.c +++ b/src/backend/access/transam/xloginsert.c @@ -9,7 +9,7 @@ * of XLogRecData structs by a call to XLogRecordAssemble(). See * access/transam/README for details. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/xloginsert.c @@ -73,8 +73,8 @@ static XLogRecData *mainrdata_head; static XLogRecData *mainrdata_last = (XLogRecData *) &mainrdata_head; static uint32 mainrdata_len; /* total # of bytes in chain */ -/* Should the in-progress insertion log the origin? */ -static bool include_origin = false; +/* flags for the in-progress insertion */ +static uint8 curinsert_flags = 0; /* * These are used to hold the record header while constructing a record. @@ -201,7 +201,7 @@ XLogResetInsertion(void) max_registered_block_id = 0; mainrdata_len = 0; mainrdata_last = (XLogRecData *) &mainrdata_head; - include_origin = false; + curinsert_flags = 0; begininsert_called = false; } @@ -384,13 +384,20 @@ XLogRegisterBufData(uint8 block_id, char *data, int len) } /* - * Should this record include the replication origin if one is set up? + * Set insert status flags for the upcoming WAL record. + * + * The flags that can be used here are: + * - XLOG_INCLUDE_ORIGIN, to determine if the replication origin should be + * included in the record. + * - XLOG_MARK_UNIMPORTANT, to signal that the record is not important for + * durability, which allows to avoid triggering WAL archiving and other + * background activity. */ void -XLogIncludeOrigin(void) +XLogSetRecordFlags(uint8 flags) { Assert(begininsert_called); - include_origin = true; + curinsert_flags = flags; } /* @@ -450,7 +457,7 @@ XLogInsert(RmgrId rmid, uint8 info) rdt = XLogRecordAssemble(rmid, info, RedoRecPtr, doPageWrites, &fpw_lsn); - EndPos = XLogInsertRecord(rdt, fpw_lsn); + EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags); } while (EndPos == InvalidXLogRecPtr); XLogResetInsertion(); @@ -701,7 +708,8 @@ XLogRecordAssemble(RmgrId rmid, uint8 info, } /* followed by the record's origin, if any */ - if (include_origin && replorigin_session_origin != InvalidRepOriginId) + if ((curinsert_flags & XLOG_INCLUDE_ORIGIN) && + replorigin_session_origin != InvalidRepOriginId) { *(scratch++) = XLR_BLOCK_ID_ORIGIN; memcpy(scratch, &replorigin_session_origin, sizeof(replorigin_session_origin)); @@ -997,9 +1005,7 @@ InitXLogInsert(void) { xloginsert_cxt = AllocSetContextCreate(TopMemoryContext, "WAL record construction", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); } if (registered_buffers == NULL) diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c index dcf747c633..b528745fe8 100644 --- a/src/backend/access/transam/xlogreader.c +++ b/src/backend/access/transam/xlogreader.c @@ -3,7 +3,7 @@ * xlogreader.c * Generic XLog reading facility * - * Portions Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2013-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/access/transam/xlogreader.c @@ -462,7 +462,8 @@ XLogReadRecord(XLogReaderState *state, XLogRecPtr RecPtr, char **errormsg) /* * Special processing if it's an XLOG SWITCH record */ - if (record->xl_rmid == RM_XLOG_ID && record->xl_info == XLOG_SWITCH) + if (record->xl_rmid == RM_XLOG_ID && + (record->xl_info & ~XLR_INFO_MASK) == XLOG_SWITCH) { /* Pretend it extends to end of segment */ state->EndRecPtr += XLogSegSize - 1; @@ -866,46 +867,83 @@ XLogRecPtr XLogFindNextRecord(XLogReaderState *state, XLogRecPtr RecPtr) { XLogReaderState saved_state = *state; - XLogRecPtr targetPagePtr; XLogRecPtr tmpRecPtr; - int targetRecOff; XLogRecPtr found = InvalidXLogRecPtr; - uint32 pageHeaderSize; XLogPageHeader header; - int readLen; char *errormsg; Assert(!XLogRecPtrIsInvalid(RecPtr)); - targetRecOff = RecPtr % XLOG_BLCKSZ; + /* + * skip over potential continuation data, keeping in mind that it may span + * multiple pages + */ + tmpRecPtr = RecPtr; + while (true) + { + XLogRecPtr targetPagePtr; + int targetRecOff; + uint32 pageHeaderSize; + int readLen; - /* scroll back to page boundary */ - targetPagePtr = RecPtr - targetRecOff; + /* + * Compute targetRecOff. It should typically be equal or greater than + * short page-header since a valid record can't start anywhere before + * that, except when caller has explicitly specified the offset that + * falls somewhere there or when we are skipping multi-page + * continuation record. It doesn't matter though because + * ReadPageInternal() is prepared to handle that and will read at least + * short page-header worth of data + */ + targetRecOff = tmpRecPtr % XLOG_BLCKSZ; - /* Read the page containing the record */ - readLen = ReadPageInternal(state, targetPagePtr, targetRecOff); - if (readLen < 0) - goto err; + /* scroll back to page boundary */ + targetPagePtr = tmpRecPtr - targetRecOff; - header = (XLogPageHeader) state->readBuf; + /* Read the page containing the record */ + readLen = ReadPageInternal(state, targetPagePtr, targetRecOff); + if (readLen < 0) + goto err; - pageHeaderSize = XLogPageHeaderSize(header); + header = (XLogPageHeader) state->readBuf; - /* make sure we have enough data for the page header */ - readLen = ReadPageInternal(state, targetPagePtr, pageHeaderSize); - if (readLen < 0) - goto err; + pageHeaderSize = XLogPageHeaderSize(header); - /* skip over potential continuation data */ - if (header->xlp_info & XLP_FIRST_IS_CONTRECORD) - { - /* record headers are MAXALIGN'ed */ - tmpRecPtr = targetPagePtr + pageHeaderSize - + MAXALIGN(header->xlp_rem_len); - } - else - { - tmpRecPtr = targetPagePtr + pageHeaderSize; + /* make sure we have enough data for the page header */ + readLen = ReadPageInternal(state, targetPagePtr, pageHeaderSize); + if (readLen < 0) + goto err; + + /* skip over potential continuation data */ + if (header->xlp_info & XLP_FIRST_IS_CONTRECORD) + { + /* + * If the length of the remaining continuation data is more than + * what can fit in this page, the continuation record crosses over + * this page. Read the next page and try again. xlp_rem_len in the + * next page header will contain the remaining length of the + * continuation data + * + * Note that record headers are MAXALIGN'ed + */ + if (MAXALIGN(header->xlp_rem_len) > (XLOG_BLCKSZ - pageHeaderSize)) + tmpRecPtr = targetPagePtr + XLOG_BLCKSZ; + else + { + /* + * The previous continuation record ends in this page. Set + * tmpRecPtr to point to the first valid record + */ + tmpRecPtr = targetPagePtr + pageHeaderSize + + MAXALIGN(header->xlp_rem_len); + break; + } + } + else + { + tmpRecPtr = targetPagePtr + pageHeaderSize; + break; + } } /* diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c index 51a8e8ddb2..0de2419e54 100644 --- a/src/backend/access/transam/xlogutils.c +++ b/src/backend/access/transam/xlogutils.c @@ -8,7 +8,7 @@ * None of this code is used during normal system operation. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/xlogutils.c diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y index 41d2fd4a5f..33d9f0b3c6 100644 --- a/src/backend/bootstrap/bootparse.y +++ b/src/backend/bootstrap/bootparse.y @@ -4,7 +4,7 @@ * bootparse.y * yacc grammar for the "bootstrap" mode (BKI file format) * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -105,11 +105,11 @@ static int num_columns_read = 0; %type boot_index_params %type boot_index_param -%type boot_const boot_ident +%type boot_ident %type optbootstrap optsharedrelation optwithoutoids boot_column_nullness %type oidspec optoideq optrowtypeoid -%token CONST_P ID +%token ID %token OPEN XCLOSE XCREATE INSERT_TUPLE %token XDECLARE INDEX ON USING XBUILD INDICES UNIQUE XTOAST %token COMMA EQUALS LPAREN RPAREN @@ -464,16 +464,10 @@ boot_column_val_list: boot_column_val: boot_ident { InsertOneValue($1, num_columns_read++); } - | boot_const - { InsertOneValue($1, num_columns_read++); } | NULLVAL { InsertOneNull(num_columns_read++); } ; -boot_const : - CONST_P { $$ = yylval.str; } - ; - boot_ident : ID { $$ = yylval.str; } ; diff --git a/src/backend/bootstrap/bootscanner.l b/src/backend/bootstrap/bootscanner.l index 0e1413bff9..6467882fa3 100644 --- a/src/backend/bootstrap/bootscanner.l +++ b/src/backend/bootstrap/bootscanner.l @@ -4,7 +4,7 @@ * bootscanner.l * a lexical scanner for the bootstrap parser * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -66,7 +66,6 @@ static int yyline = 1; /* line number for error reporting */ D [0-9] oct \\{D}{D}{D} -Exp [Ee][-+]?{D}+ id ([A-Za-z0-9_]|{oct}|\-)+ sid \"([^\"])*\" arrayid [A-Za-z0-9_]+\[{D}*\] @@ -127,13 +126,6 @@ insert { return(INSERT_TUPLE); } return(ID); } -(-)?{D}+"."{D}*({Exp})? | -(-)?{D}*"."{D}+({Exp})? | -(-)?{D}+{Exp} { - yylval.str = pstrdup(yytext); - return(CONST_P); - } - . { elog(ERROR, "syntax error at line %d: unexpected character \"%s\"", yyline, yytext); } diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index e518e178bb..6511c6064b 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -4,7 +4,7 @@ * routines to support running postgres in 'bootstrap' mode * bootstrap mode is used to create the initial template database * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -33,6 +33,7 @@ #include "replication/walreceiver.h" #include "storage/bufmgr.h" #include "storage/bufpage.h" +#include "storage/condition_variable.h" #include "storage/ipc.h" #include "storage/proc.h" #include "tcop/tcopprot.h" @@ -47,7 +48,8 @@ uint32 bootstrap_data_checksum_version = 0; /* No checksum */ -#define ALLOC(t, c) ((t *) calloc((unsigned)(c), sizeof(t))) +#define ALLOC(t, c) \ + ((t *) MemoryContextAllocZero(TopMemoryContext, (unsigned)(c) * sizeof(t))) static void CheckerModeMain(void); static void BootstrapModeMain(void); @@ -227,7 +229,7 @@ AuxiliaryProcessMain(int argc, char *argv[]) SetConfigOption("shared_buffers", optarg, PGC_POSTMASTER, PGC_S_ARGV); break; case 'D': - userDoption = strdup(optarg); + userDoption = pstrdup(optarg); break; case 'd': { @@ -535,6 +537,7 @@ static void ShutdownAuxiliaryProcess(int code, Datum arg) { LWLockReleaseAll(); + ConditionVariableCancelSleep(); pgstat_report_wait_end(); } @@ -1002,13 +1005,8 @@ boot_get_type_io_data(Oid typid, static Form_pg_attribute AllocateAttribute(void) { - Form_pg_attribute attribute = (Form_pg_attribute) malloc(ATTRIBUTE_FIXED_PART_SIZE); - - if (!PointerIsValid(attribute)) - elog(FATAL, "out of memory"); - MemSet(attribute, 0, ATTRIBUTE_FIXED_PART_SIZE); - - return attribute; + return (Form_pg_attribute) + MemoryContextAllocZero(TopMemoryContext, ATTRIBUTE_FIXED_PART_SIZE); } /* @@ -1069,9 +1067,7 @@ index_register(Oid heap, if (nogc == NULL) nogc = AllocSetContextCreate(NULL, "BootstrapNoGC", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldcxt = MemoryContextSwitchTo(nogc); diff --git a/src/backend/catalog/Catalog.pm b/src/backend/catalog/Catalog.pm index f411b970e5..e1f3c3a5ee 100644 --- a/src/backend/catalog/Catalog.pm +++ b/src/backend/catalog/Catalog.pm @@ -4,7 +4,7 @@ # Perl module that extracts info from catalog headers into Perl # data structures # -# Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/backend/catalog/Catalog.pm diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index 1ce7610049..31368585d2 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -11,11 +11,12 @@ top_builddir = ../../.. include $(top_builddir)/src/Makefile.global OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \ - objectaccess.o objectaddress.o pg_aggregate.o pg_collation.o \ + objectaccess.o objectaddress.o partition.o pg_aggregate.o pg_collation.o \ pg_constraint.o pg_conversion.o \ pg_depend.o pg_enum.o pg_inherits.o pg_largeobject.o pg_namespace.o \ - pg_operator.o pg_proc.o pg_range.o pg_db_role_setting.o pg_shdepend.o \ - pg_type.o storage.o toasting.o + pg_operator.o pg_proc.o pg_publication.o pg_range.o \ + pg_db_role_setting.o pg_shdepend.o pg_subscription.o pg_type.o \ + storage.o toasting.o BKIFILES = postgres.bki postgres.description postgres.shdescription @@ -41,7 +42,8 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\ pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \ pg_foreign_table.h pg_policy.h pg_replication_origin.h \ pg_default_acl.h pg_init_privs.h pg_seclabel.h pg_shseclabel.h \ - pg_collation.h pg_range.h pg_transform.h \ + pg_collation.h pg_partitioned_table.h pg_range.h pg_transform.h \ + pg_sequence.h pg_publication.h pg_publication_rel.h pg_subscription.h \ toasting.h indexing.h \ ) diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index a585c3ad19..a96bf692df 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -3,7 +3,7 @@ * aclchk.c * Routines to check access control permissions. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -45,6 +45,7 @@ #include "catalog/pg_operator.h" #include "catalog/pg_opfamily.h" #include "catalog/pg_proc.h" +#include "catalog/pg_subscription.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_type.h" #include "catalog/pg_ts_config.h" @@ -423,7 +424,7 @@ ExecuteGrantStmt(GrantStmt *stmt) grantee_uid = ACL_ID_PUBLIC; break; default: - grantee_uid = get_rolespec_oid((Node *) grantee, false); + grantee_uid = get_rolespec_oid(grantee, false); break; } istmt.grantees = lappend_oid(istmt.grantees, grantee_uid); @@ -768,6 +769,8 @@ objectsInSchemaToOids(GrantObjectType objtype, List *nspnames) objects = list_concat(objects, objs); objs = getRelationsInNamespace(namespaceId, RELKIND_FOREIGN_TABLE); objects = list_concat(objects, objs); + objs = getRelationsInNamespace(namespaceId, RELKIND_PARTITIONED_TABLE); + objects = list_concat(objects, objs); break; case ACL_OBJECT_SEQUENCE: objs = getRelationsInNamespace(namespaceId, RELKIND_SEQUENCE); @@ -849,7 +852,7 @@ getRelationsInNamespace(Oid namespaceId, char relkind) * ALTER DEFAULT PRIVILEGES statement */ void -ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt) +ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *stmt) { GrantStmt *action = stmt->action; InternalDefaultACL iacls; @@ -871,7 +874,8 @@ ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt) if (dnspnames) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); dnspnames = defel; } else if (strcmp(defel->defname, "roles") == 0) @@ -879,7 +883,8 @@ ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt) if (drolespecs) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); drolespecs = defel; } else @@ -918,7 +923,7 @@ ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt) grantee_uid = ACL_ID_PUBLIC; break; default: - grantee_uid = get_rolespec_oid((Node *) grantee, false); + grantee_uid = get_rolespec_oid(grantee, false); break; } iacls.grantees = lappend_oid(iacls.grantees, grantee_uid); @@ -1008,7 +1013,7 @@ ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt) { RoleSpec *rolespec = lfirst(rolecell); - iacls.roleid = get_rolespec_oid((Node *) rolespec, false); + iacls.roleid = get_rolespec_oid(rolespec, false); /* * We insist that calling user be a member of each target role. If @@ -1815,7 +1820,8 @@ ExecGrant_Relation(InternalGrant *istmt) */ ereport(ERROR, (errcode(ERRCODE_INVALID_GRANT_OPERATION), - errmsg("invalid privilege type USAGE for table"))); + errmsg("invalid privilege type %s for table", + "USAGE"))); } } } @@ -3385,6 +3391,10 @@ static const char *const not_owner_msg[MAX_ACL_KIND] = gettext_noop("must be owner of event trigger %s"), /* ACL_KIND_EXTENSION */ gettext_noop("must be owner of extension %s"), + /* ACL_KIND_PUBLICATION */ + gettext_noop("must be owner of publication %s"), + /* ACL_KIND_SUBSCRIPTION */ + gettext_noop("must be owner of subscription %s"), }; @@ -5066,6 +5076,58 @@ pg_extension_ownercheck(Oid ext_oid, Oid roleid) return has_privs_of_role(roleid, ownerId); } +/* + * Ownership check for an publication (specified by OID). + */ +bool +pg_publication_ownercheck(Oid pub_oid, Oid roleid) +{ + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pub_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("publication with OID %u does not exist", pub_oid))); + + ownerId = ((Form_pg_publication) GETSTRUCT(tuple))->pubowner; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, ownerId); +} + +/* + * Ownership check for an subscription (specified by OID). + */ +bool +pg_subscription_ownercheck(Oid sub_oid, Oid roleid) +{ + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(SUBSCRIPTIONOID, ObjectIdGetDatum(sub_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("subscription with OID %u does not exist", sub_oid))); + + ownerId = ((Form_pg_subscription) GETSTRUCT(tuple))->subowner; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, ownerId); +} + /* * Check whether specified role has CREATEROLE privilege (or is a superuser) * diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c index 1baaa0bb89..11ee536726 100644 --- a/src/backend/catalog/catalog.c +++ b/src/backend/catalog/catalog.c @@ -5,7 +5,7 @@ * bits of hard-wired knowledge * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -36,6 +36,7 @@ #include "catalog/pg_shdepend.h" #include "catalog/pg_shdescription.h" #include "catalog/pg_shseclabel.h" +#include "catalog/pg_subscription.h" #include "catalog/pg_tablespace.h" #include "catalog/toasting.h" #include "miscadmin.h" @@ -227,7 +228,8 @@ IsSharedRelation(Oid relationId) relationId == SharedSecLabelRelationId || relationId == TableSpaceRelationId || relationId == DbRoleSettingRelationId || - relationId == ReplicationOriginRelationId) + relationId == ReplicationOriginRelationId || + relationId == SubscriptionRelationId) return true; /* These are their indexes (see indexing.h) */ if (relationId == AuthIdRolnameIndexId || @@ -245,7 +247,9 @@ IsSharedRelation(Oid relationId) relationId == TablespaceNameIndexId || relationId == DbRoleSettingDatidRolidIndexId || relationId == ReplicationOriginIdentIndex || - relationId == ReplicationOriginNameIndex) + relationId == ReplicationOriginNameIndex || + relationId == SubscriptionObjectIndexId || + relationId == SubscriptionNameIndexId) return true; /* These are their toast tables and toast indexes (see toasting.h) */ if (relationId == PgShdescriptionToastTable || diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 04d7840290..1c43af6eff 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -4,7 +4,7 @@ * Routines to support inter-object dependencies. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -48,7 +48,10 @@ #include "catalog/pg_opfamily.h" #include "catalog/pg_policy.h" #include "catalog/pg_proc.h" +#include "catalog/pg_publication.h" +#include "catalog/pg_publication_rel.h" #include "catalog/pg_rewrite.h" +#include "catalog/pg_subscription.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_transform.h" #include "catalog/pg_trigger.h" @@ -64,8 +67,10 @@ #include "commands/extension.h" #include "commands/policy.h" #include "commands/proclang.h" +#include "commands/publicationcmds.h" #include "commands/schemacmds.h" #include "commands/seclabel.h" +#include "commands/sequence.h" #include "commands/trigger.h" #include "commands/typecmds.h" #include "nodes/nodeFuncs.h" @@ -163,11 +168,15 @@ static const Oid object_classes[] = { ExtensionRelationId, /* OCLASS_EXTENSION */ EventTriggerRelationId, /* OCLASS_EVENT_TRIGGER */ PolicyRelationId, /* OCLASS_POLICY */ + PublicationRelationId, /* OCLASS_PUBLICATION */ + PublicationRelRelationId, /* OCLASS_PUBLICATION_REL */ + SubscriptionRelationId, /* OCLASS_SUBSCRIPTION */ TransformRelationId /* OCLASS_TRANSFORM */ }; static void findDependentObjects(const ObjectAddress *object, + int objflags, int flags, ObjectAddressStack *stack, ObjectAddresses *targetObjects, @@ -175,7 +184,7 @@ static void findDependentObjects(const ObjectAddress *object, Relation *depRel); static void reportDependentObjects(const ObjectAddresses *targetObjects, DropBehavior behavior, - int msglevel, + int flags, const ObjectAddress *origObject); static void deleteOneObject(const ObjectAddress *object, Relation *depRel, int32 flags); @@ -237,11 +246,17 @@ deleteObjectsInList(ObjectAddresses *targetObjects, Relation *depRel, } /* - * Delete all the objects in the proper order. + * Delete all the objects in the proper order, except that if told to, we + * should skip the original object(s). */ for (i = 0; i < targetObjects->numrefs; i++) { ObjectAddress *thisobj = targetObjects->refs + i; + ObjectAddressExtra *thisextra = targetObjects->extras + i; + + if ((flags & PERFORM_DELETION_SKIP_ORIGINAL) && + (thisextra->flags & DEPFLAG_ORIGINAL)) + continue; deleteOneObject(thisobj, depRel, flags); } @@ -255,16 +270,32 @@ deleteObjectsInList(ObjectAddresses *targetObjects, Relation *depRel, * according to the dependency type. * * This is the outer control routine for all forms of DROP that drop objects - * that can participate in dependencies. Note that the next two routines - * are variants on the same theme; if you change anything here you'll likely - * need to fix them too. + * that can participate in dependencies. Note that performMultipleDeletions + * is a variant on the same theme; if you change anything here you'll likely + * need to fix that too. + * + * Bits in the flags argument can include: + * + * PERFORM_DELETION_INTERNAL: indicates that the drop operation is not the + * direct result of a user-initiated action. For example, when a temporary + * schema is cleaned out so that a new backend can use it, or when a column + * default is dropped as an intermediate step while adding a new one, that's + * an internal operation. On the other hand, when we drop something because + * the user issued a DROP statement against it, that's not internal. Currently + * this suppresses calling event triggers and making some permissions checks. + * + * PERFORM_DELETION_CONCURRENTLY: perform the drop concurrently. This does + * not currently work for anything except dropping indexes; don't set it for + * other object types or you may get strange results. * - * flags should include PERFORM_DELETION_INTERNAL when the drop operation is - * not the direct result of a user-initiated action. For example, when a - * temporary schema is cleaned out so that a new backend can use it, or when - * a column default is dropped as an intermediate step while adding a new one, - * that's an internal operation. On the other hand, when we drop something - * because the user issued a DROP statement against it, that's not internal. + * PERFORM_DELETION_QUIETLY: reduce message level from NOTICE to DEBUG2. + * + * PERFORM_DELETION_SKIP_ORIGINAL: do not delete the specified object(s), + * but only what depends on it/them. + * + * PERFORM_DELETION_SKIP_EXTENSIONS: do not delete extensions, even when + * deleting objects that are part of an extension. This should generally + * be used only when dropping temporary objects. */ void performDeletion(const ObjectAddress *object, @@ -293,6 +324,7 @@ performDeletion(const ObjectAddress *object, findDependentObjects(object, DEPFLAG_ORIGINAL, + flags, NULL, /* empty stack */ targetObjects, NULL, /* no pendingObjects */ @@ -303,7 +335,7 @@ performDeletion(const ObjectAddress *object, */ reportDependentObjects(targetObjects, behavior, - NOTICE, + flags, object); /* do the deed */ @@ -364,6 +396,7 @@ performMultipleDeletions(const ObjectAddresses *objects, findDependentObjects(thisobj, DEPFLAG_ORIGINAL, + flags, NULL, /* empty stack */ targetObjects, objects, @@ -378,7 +411,7 @@ performMultipleDeletions(const ObjectAddresses *objects, */ reportDependentObjects(targetObjects, behavior, - NOTICE, + flags, (objects->numrefs == 1 ? objects->refs : NULL)); /* do the deed */ @@ -390,88 +423,6 @@ performMultipleDeletions(const ObjectAddresses *objects, heap_close(depRel, RowExclusiveLock); } -/* - * deleteWhatDependsOn: attempt to drop everything that depends on the - * specified object, though not the object itself. Behavior is always - * CASCADE. - * - * This is currently used only to clean out the contents of a schema - * (namespace): the passed object is a namespace. We normally want this - * to be done silently, so there's an option to suppress NOTICE messages. - * - * Note we don't fire object drop event triggers here; it would be wrong to do - * so for the current only use of this function, but if more callers are added - * this might need to be reconsidered. - */ -void -deleteWhatDependsOn(const ObjectAddress *object, - bool showNotices) -{ - Relation depRel; - ObjectAddresses *targetObjects; - int i; - - /* - * We save some cycles by opening pg_depend just once and passing the - * Relation pointer down to all the recursive deletion steps. - */ - depRel = heap_open(DependRelationId, RowExclusiveLock); - - /* - * Acquire deletion lock on the target object. (Ideally the caller has - * done this already, but many places are sloppy about it.) - */ - AcquireDeletionLock(object, 0); - - /* - * Construct a list of objects to delete (ie, the given object plus - * everything directly or indirectly dependent on it). - */ - targetObjects = new_object_addresses(); - - findDependentObjects(object, - DEPFLAG_ORIGINAL, - NULL, /* empty stack */ - targetObjects, - NULL, /* no pendingObjects */ - &depRel); - - /* - * Check if deletion is allowed, and report about cascaded deletes. - */ - reportDependentObjects(targetObjects, - DROP_CASCADE, - showNotices ? NOTICE : DEBUG2, - object); - - /* - * Delete all the objects in the proper order, except we skip the original - * object. - */ - for (i = 0; i < targetObjects->numrefs; i++) - { - ObjectAddress *thisobj = targetObjects->refs + i; - ObjectAddressExtra *thisextra = targetObjects->extras + i; - - if (thisextra->flags & DEPFLAG_ORIGINAL) - continue; - - /* - * Since this function is currently only used to clean out temporary - * schemas, we pass PERFORM_DELETION_INTERNAL here, indicating that - * the operation is an automatic system operation rather than a user - * action. If, in the future, this function is used for other - * purposes, we might need to revisit this. - */ - deleteOneObject(thisobj, &depRel, PERFORM_DELETION_INTERNAL); - } - - /* And clean up */ - free_object_addresses(targetObjects); - - heap_close(depRel, RowExclusiveLock); -} - /* * findDependentObjects - find all objects that depend on 'object' * @@ -492,16 +443,22 @@ deleteWhatDependsOn(const ObjectAddress *object, * its sub-objects too. * * object: the object to add to targetObjects and find dependencies on - * flags: flags to be ORed into the object's targetObjects entry + * objflags: flags to be ORed into the object's targetObjects entry + * flags: PERFORM_DELETION_xxx flags for the deletion operation as a whole * stack: list of objects being visited in current recursion; topmost item * is the object that we recursed from (NULL for external callers) * targetObjects: list of objects that are scheduled to be deleted * pendingObjects: list of other objects slated for destruction, but * not necessarily in targetObjects yet (can be NULL if none) * *depRel: already opened pg_depend relation + * + * Note: objflags describes the reason for visiting this particular object + * at this time, and is not passed down when recursing. The flags argument + * is passed down, since it describes what we're doing overall. */ static void findDependentObjects(const ObjectAddress *object, + int objflags, int flags, ObjectAddressStack *stack, ObjectAddresses *targetObjects, @@ -518,8 +475,8 @@ findDependentObjects(const ObjectAddress *object, /* * If the target object is already being visited in an outer recursion - * level, just report the current flags back to that level and exit. This - * is needed to avoid infinite recursion in the face of circular + * level, just report the current objflags back to that level and exit. + * This is needed to avoid infinite recursion in the face of circular * dependencies. * * The stack check alone would result in dependency loops being broken at @@ -532,19 +489,19 @@ findDependentObjects(const ObjectAddress *object, * auto dependency, too, if we had to. However there are no known cases * where that would be necessary. */ - if (stack_address_present_add_flags(object, flags, stack)) + if (stack_address_present_add_flags(object, objflags, stack)) return; /* * It's also possible that the target object has already been completely * processed and put into targetObjects. If so, again we just add the - * specified flags to its entry and return. + * specified objflags to its entry and return. * * (Note: in these early-exit cases we could release the caller-taken * lock, since the object is presumably now locked multiple times; but it * seems not worth the cycles.) */ - if (object_address_present_add_flags(object, flags, targetObjects)) + if (object_address_present_add_flags(object, objflags, targetObjects)) return; /* @@ -594,29 +551,52 @@ findDependentObjects(const ObjectAddress *object, case DEPENDENCY_AUTO_EXTENSION: /* no problem */ break; - case DEPENDENCY_INTERNAL: + case DEPENDENCY_EXTENSION: + /* + * If told to, ignore EXTENSION dependencies altogether. This + * flag is normally used to prevent dropping extensions during + * temporary-object cleanup, even if a temp object was created + * during an extension script. + */ + if (flags & PERFORM_DELETION_SKIP_EXTENSIONS) + break; + + /* + * If the other object is the extension currently being + * created/altered, ignore this dependency and continue with + * the deletion. This allows dropping of an extension's + * objects within the extension's scripts, as well as corner + * cases such as dropping a transient object created within + * such a script. + */ + if (creating_extension && + otherObject.classId == ExtensionRelationId && + otherObject.objectId == CurrentExtensionObject) + break; + + /* Otherwise, treat this like an internal dependency */ + /* FALL THRU */ + + case DEPENDENCY_INTERNAL: + /* * This object is part of the internal implementation of * another object, or is part of the extension that is the * other object. We have three cases: * - * 1. At the outermost recursion level, we normally disallow - * the DROP. (We just ereport here, rather than proceeding, - * since no other dependencies are likely to be interesting.) - * However, there are exceptions. + * 1. At the outermost recursion level, disallow the DROP. (We + * just ereport here, rather than proceeding, since no other + * dependencies are likely to be interesting.) However, if + * the owning object is listed in pendingObjects, just release + * the caller's lock and return; we'll eventually complete the + * DROP when we reach that entry in the pending list. */ if (stack == NULL) { char *otherObjDesc; - /* - * Exception 1a: if the owning object is listed in - * pendingObjects, just release the caller's lock and - * return. We'll eventually complete the DROP when we - * reach that entry in the pending list. - */ if (pendingObjects && object_address_present(&otherObject, pendingObjects)) { @@ -625,21 +605,6 @@ findDependentObjects(const ObjectAddress *object, ReleaseDeletionLock(object); return; } - - /* - * Exception 1b: if the owning object is the extension - * currently being created/altered, it's okay to continue - * with the deletion. This allows dropping of an - * extension's objects within the extension's scripts, as - * well as corner cases such as dropping a transient - * object created within such a script. - */ - if (creating_extension && - otherObject.classId == ExtensionRelationId && - otherObject.objectId == CurrentExtensionObject) - break; - - /* No exception applies, so throw the error */ otherObjDesc = getObjectDescription(&otherObject); ereport(ERROR, (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), @@ -700,6 +665,7 @@ findDependentObjects(const ObjectAddress *object, */ findDependentObjects(&otherObject, DEPFLAG_REVERSE, + flags, stack, targetObjects, pendingObjects, @@ -730,7 +696,7 @@ findDependentObjects(const ObjectAddress *object, * they have to be deleted before the current object. */ mystack.object = object; /* set up a new stack level */ - mystack.flags = flags; + mystack.flags = objflags; mystack.next = stack; ScanKeyInit(&key[0], @@ -784,7 +750,7 @@ findDependentObjects(const ObjectAddress *object, continue; } - /* Recurse, passing flags indicating the dependency type */ + /* Recurse, passing objflags indicating the dependency type */ switch (foundDep->deptype) { case DEPENDENCY_NORMAL: @@ -821,6 +787,7 @@ findDependentObjects(const ObjectAddress *object, findDependentObjects(&otherObject, subflags, + flags, &mystack, targetObjects, pendingObjects, @@ -851,16 +818,17 @@ findDependentObjects(const ObjectAddress *object, * * targetObjects: list of objects that are scheduled to be deleted * behavior: RESTRICT or CASCADE - * msglevel: elog level for non-error report messages + * flags: other flags for the deletion operation * origObject: base object of deletion, or NULL if not available * (the latter case occurs in DROP OWNED) */ static void reportDependentObjects(const ObjectAddresses *targetObjects, DropBehavior behavior, - int msglevel, + int flags, const ObjectAddress *origObject) { + int msglevel = (flags & PERFORM_DELETION_QUIETLY) ? DEBUG2 : NOTICE; bool ok = true; StringInfoData clientdetail; StringInfoData logdetail; @@ -1141,8 +1109,7 @@ doDeletion(const ObjectAddress *object, int flags) if (relKind == RELKIND_INDEX) { - bool concurrent = ((flags & PERFORM_DELETION_CONCURRENTLY) - == PERFORM_DELETION_CONCURRENTLY); + bool concurrent = ((flags & PERFORM_DELETION_CONCURRENTLY) != 0); Assert(object->objectSubId == 0); index_drop(object->objectId, concurrent); @@ -1155,6 +1122,11 @@ doDeletion(const ObjectAddress *object, int flags) else heap_drop_with_catalog(object->objectId); } + + /* for a sequence, in addition to dropping the heap, also + * delete pg_sequence tuple */ + if (relKind == RELKIND_SEQUENCE) + DeleteSequenceTuple(object->objectId); break; } @@ -1279,6 +1251,14 @@ doDeletion(const ObjectAddress *object, int flags) RemovePolicyById(object->objectId); break; + case OCLASS_PUBLICATION: + RemovePublicationById(object->objectId); + break; + + case OCLASS_PUBLICATION_REL: + RemovePublicationRelById(object->objectId); + break; + case OCLASS_TRANSFORM: DropTransformById(object->objectId); break; @@ -1393,7 +1373,8 @@ void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, - DependencyType self_behavior) + DependencyType self_behavior, + bool ignore_self) { find_expr_references_context context; RangeTblEntry rte; @@ -1448,9 +1429,10 @@ recordDependencyOnSingleRelExpr(const ObjectAddress *depender, context.addrs->numrefs = outrefs; /* Record the self-dependencies */ - recordMultipleDependencies(depender, - self_addrs->refs, self_addrs->numrefs, - self_behavior); + if (!ignore_self) + recordMultipleDependencies(depender, + self_addrs->refs, self_addrs->numrefs, + self_behavior); free_object_addresses(self_addrs); } @@ -1631,7 +1613,8 @@ find_expr_references_walker(Node *node, case REGROLEOID: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("constant of the type \"regrole\" cannot be used here"))); + errmsg("constant of the type %s cannot be used here", + "regrole"))); break; } } @@ -2436,6 +2419,15 @@ getObjectClass(const ObjectAddress *object) case PolicyRelationId: return OCLASS_POLICY; + case PublicationRelationId: + return OCLASS_PUBLICATION; + + case PublicationRelRelationId: + return OCLASS_PUBLICATION_REL; + + case SubscriptionRelationId: + return OCLASS_SUBSCRIPTION; + case TransformRelationId: return OCLASS_TRANSFORM; } diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl index 54a14e5dc3..079516ca2f 100644 --- a/src/backend/catalog/genbki.pl +++ b/src/backend/catalog/genbki.pl @@ -7,7 +7,7 @@ # header files. The .bki files are used to initialize the postgres # template database. # -# Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/backend/catalog/genbki.pl @@ -43,8 +43,8 @@ elsif ($arg =~ /^--set-version=(.*)$/) { $major_version = $1; - die "Version must be in format nn.nn.\n" - if !($major_version =~ /^\d+\.\d+$/); + die "Invalid version string.\n" + if !($major_version =~ /^\d+$/); } else { @@ -294,7 +294,7 @@ * schemapg.h * Schema_pg_xxx macros for use by relcache.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index e997b574ca..bfc54a8b9f 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -3,7 +3,7 @@ * heap.c * code to create and destroy POSTGRES heap relations * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -41,6 +41,7 @@ #include "catalog/heap.h" #include "catalog/index.h" #include "catalog/objectaccess.h" +#include "catalog/partition.h" #include "catalog/pg_attrdef.h" #include "catalog/pg_collation.h" #include "catalog/pg_constraint.h" @@ -48,6 +49,8 @@ #include "catalog/pg_foreign_table.h" #include "catalog/pg_inherits.h" #include "catalog/pg_namespace.h" +#include "catalog/pg_opclass.h" +#include "catalog/pg_partitioned_table.h" #include "catalog/pg_statistic.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_type.h" @@ -105,6 +108,7 @@ static void StoreConstraints(Relation rel, List *cooked_constraints, bool is_internal); static bool MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr, bool allow_merge, bool is_local, + bool is_initially_valid, bool is_no_inherit); static void SetRelationNumChecks(Relation rel, int numchecks); static Node *cookConstraint(ParseState *pstate, @@ -494,7 +498,7 @@ CheckAttributeType(const char *attname, */ ereport(WARNING, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), - errmsg("column \"%s\" has type \"unknown\"", attname), + errmsg("column \"%s\" has type %s", attname, "unknown"), errdetail("Proceeding with relation creation anyway."))); } else if (att_typtype == TYPTYPE_PSEUDO) @@ -807,6 +811,7 @@ InsertPgClassTuple(Relation pg_class_desc, values[Anum_pg_class_relhassubclass - 1] = BoolGetDatum(rd_rel->relhassubclass); values[Anum_pg_class_relispopulated - 1] = BoolGetDatum(rd_rel->relispopulated); values[Anum_pg_class_relreplident - 1] = CharGetDatum(rd_rel->relreplident); + values[Anum_pg_class_relispartition - 1] = BoolGetDatum(rd_rel->relispartition); values[Anum_pg_class_relfrozenxid - 1] = TransactionIdGetDatum(rd_rel->relfrozenxid); values[Anum_pg_class_relminmxid - 1] = MultiXactIdGetDatum(rd_rel->relminmxid); if (relacl != (Datum) 0) @@ -818,6 +823,9 @@ InsertPgClassTuple(Relation pg_class_desc, else nulls[Anum_pg_class_reloptions - 1] = true; + /* relpartbound is set by updating this tuple, if necessary */ + nulls[Anum_pg_class_relpartbound - 1] = true; + tup = heap_form_tuple(RelationGetDescr(pg_class_desc), values, nulls); /* @@ -923,6 +931,9 @@ AddNewRelationTuple(Relation pg_class_desc, new_rel_reltup->reltype = new_type_oid; new_rel_reltup->reloftype = reloftype; + /* relispartition is always set by updating this tuple later */ + new_rel_reltup->relispartition = false; + new_rel_desc->rd_att->tdtypeid = new_type_oid; /* Now build and insert the tuple */ @@ -1103,7 +1114,8 @@ heap_create_with_catalog(const char *relname, if (IsBinaryUpgrade && (relkind == RELKIND_RELATION || relkind == RELKIND_SEQUENCE || relkind == RELKIND_VIEW || relkind == RELKIND_MATVIEW || - relkind == RELKIND_COMPOSITE_TYPE || relkind == RELKIND_FOREIGN_TABLE)) + relkind == RELKIND_COMPOSITE_TYPE || relkind == RELKIND_FOREIGN_TABLE || + relkind == RELKIND_PARTITIONED_TABLE)) { if (!OidIsValid(binary_upgrade_next_heap_pg_class_oid)) ereport(ERROR, @@ -1137,6 +1149,7 @@ heap_create_with_catalog(const char *relname, case RELKIND_VIEW: case RELKIND_MATVIEW: case RELKIND_FOREIGN_TABLE: + case RELKIND_PARTITIONED_TABLE: relacl = get_user_default_acl(ACL_OBJECT_RELATION, ownerid, relnamespace); break; @@ -1181,7 +1194,8 @@ heap_create_with_catalog(const char *relname, relkind == RELKIND_VIEW || relkind == RELKIND_MATVIEW || relkind == RELKIND_FOREIGN_TABLE || - relkind == RELKIND_COMPOSITE_TYPE)) + relkind == RELKIND_COMPOSITE_TYPE || + relkind == RELKIND_PARTITIONED_TABLE)) new_array_oid = AssignTypeArrayOid(); /* @@ -1284,10 +1298,6 @@ heap_create_with_catalog(const char *relname, * should they have any ACL entries. The same applies for extension * dependencies. * - * If it's a temp table, we do not make it an extension member; this - * prevents the unintuitive result that deletion of the temp table at - * session end would make the whole extension go away. - * * Also, skip this in bootstrap mode, since we don't make dependencies * while bootstrapping. */ @@ -1308,8 +1318,7 @@ heap_create_with_catalog(const char *relname, recordDependencyOnOwner(RelationRelationId, relid, ownerid); - if (relpersistence != RELPERSISTENCE_TEMP) - recordDependencyOnCurrentExtension(&myself, false); + recordDependencyOnCurrentExtension(&myself, false); if (reloftypeid) { @@ -1353,7 +1362,9 @@ heap_create_with_catalog(const char *relname, if (relpersistence == RELPERSISTENCE_UNLOGGED) { Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW || - relkind == RELKIND_TOASTVALUE); + relkind == RELKIND_TOASTVALUE || + relkind == RELKIND_PARTITIONED_TABLE); + heap_create_init_fork(new_rel_desc); } @@ -1369,18 +1380,19 @@ heap_create_with_catalog(const char *relname, /* * Set up an init fork for an unlogged table so that it can be correctly - * reinitialized on restart. Since we're going to do an immediate sync, we - * only need to xlog this if archiving or streaming is enabled. And the - * immediate sync is required, because otherwise there's no guarantee that - * this will hit the disk before the next checkpoint moves the redo pointer. + * reinitialized on restart. An immediate sync is required even if the + * page has been logged, because the write did not go through + * shared_buffers and therefore a concurrent checkpoint may have moved + * the redo pointer past our xlog record. Recovery may as well remove it + * while replaying, for example, XLOG_DBASE_CREATE or XLOG_TBLSPC_CREATE + * record. Therefore, logging is necessary even if wal_level=minimal. */ void heap_create_init_fork(Relation rel) { RelationOpenSmgr(rel); smgrcreate(rel->rd_smgr, INIT_FORKNUM, false); - if (XLogIsNeeded()) - log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM); + log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM); smgrimmedsync(rel->rd_smgr, INIT_FORKNUM); } @@ -1758,12 +1770,29 @@ void heap_drop_with_catalog(Oid relid) { Relation rel; + Oid parentOid; + Relation parent = NULL; /* * Open and lock the relation. */ rel = relation_open(relid, AccessExclusiveLock); + /* + * If the relation is a partition, we must grab exclusive lock on its + * parent because we need to update its partition descriptor. We must + * take a table lock strong enough to prevent all queries on the parent + * from proceeding until we commit and send out a shared-cache-inval + * notice that will make them update their partition descriptor. + * Sometimes, doing this is cycles spent uselessly, especially if the + * parent will be dropped as part of the same command anyway. + */ + if (rel->rd_rel->relispartition) + { + parentOid = get_partition_parent(relid); + parent = heap_open(parentOid, AccessExclusiveLock); + } + /* * There can no longer be anyone *else* touching the relation, but we * might still have open queries or cursors, or pending trigger events, in @@ -1799,6 +1828,12 @@ heap_drop_with_catalog(Oid relid) heap_close(rel, RowExclusiveLock); } + /* + * If a partitioned table, delete the pg_partitioned_table tuple. + */ + if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + RemovePartitionKeyByRelId(relid); + /* * Schedule unlinking of the relation's physical files at commit. */ @@ -1849,6 +1884,16 @@ heap_drop_with_catalog(Oid relid) * delete relation tuple */ DeleteRelationTuple(relid); + + if (parent) + { + /* + * Invalidate the parent's relcache so that the partition is no longer + * included in its partition descriptor. + */ + CacheInvalidateRelcache(parent); + heap_close(parent, NoLock); /* keep the lock */ + } } @@ -2031,6 +2076,17 @@ StoreRelCheck(Relation rel, char *ccname, Node *expr, else attNos = NULL; + /* + * Partitioned tables do not contain any rows themselves, so a NO INHERIT + * constraint makes no sense. + */ + if (is_no_inherit && + rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("cannot add NO INHERIT constraint to partitioned table \"%s\"", + RelationGetRelationName(rel)))); + /* * Create the Check Constraint */ @@ -2301,6 +2357,7 @@ AddRelationNewConstraints(Relation rel, */ if (MergeWithExistingConstraint(rel, ccname, expr, allow_merge, is_local, + cdef->initially_valid, cdef->is_no_inherit)) continue; } @@ -2389,6 +2446,7 @@ AddRelationNewConstraints(Relation rel, static bool MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr, bool allow_merge, bool is_local, + bool is_initially_valid, bool is_no_inherit) { bool found; @@ -2436,35 +2494,84 @@ MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr, if (equal(expr, stringToNode(TextDatumGetCString(val)))) found = true; } + + /* + * If the existing constraint is purely inherited (no local + * definition) then interpret addition of a local constraint as a + * legal merge. This allows ALTER ADD CONSTRAINT on parent and + * child tables to be given in either order with same end state. + * However if the relation is a partition, all inherited + * constraints are always non-local, including those that were + * merged. + */ + if (is_local && !con->conislocal && !rel->rd_rel->relispartition) + allow_merge = true; + if (!found || !allow_merge) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("constraint \"%s\" for relation \"%s\" already exists", ccname, RelationGetRelationName(rel)))); - tup = heap_copytuple(tup); - con = (Form_pg_constraint) GETSTRUCT(tup); - - /* If the constraint is "no inherit" then cannot merge */ + /* If the child constraint is "no inherit" then cannot merge */ if (con->connoinherit) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("constraint \"%s\" conflicts with non-inherited constraint on relation \"%s\"", ccname, RelationGetRelationName(rel)))); - if (is_local) - con->conislocal = true; + /* + * Must not change an existing inherited constraint to "no + * inherit" status. That's because inherited constraints should + * be able to propagate to lower-level children. + */ + if (con->coninhcount > 0 && is_no_inherit) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("constraint \"%s\" conflicts with inherited constraint on relation \"%s\"", + ccname, RelationGetRelationName(rel)))); + + /* + * If the child constraint is "not valid" then cannot merge with a + * valid parent constraint + */ + if (is_initially_valid && !con->convalidated) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("constraint \"%s\" conflicts with NOT VALID constraint on relation \"%s\"", + ccname, RelationGetRelationName(rel)))); + + /* OK to update the tuple */ + ereport(NOTICE, + (errmsg("merging constraint \"%s\" with inherited definition", + ccname))); + + tup = heap_copytuple(tup); + con = (Form_pg_constraint) GETSTRUCT(tup); + + /* + * In case of partitions, an inherited constraint must be + * inherited only once since it cannot have multiple parents and + * it is never considered local. + */ + if (rel->rd_rel->relispartition) + { + con->coninhcount = 1; + con->conislocal = false; + } else - con->coninhcount++; + { + if (is_local) + con->conislocal = true; + else + con->coninhcount++; + } + if (is_no_inherit) { Assert(is_local); con->connoinherit = true; } - /* OK to update the tuple */ - ereport(NOTICE, - (errmsg("merging constraint \"%s\" with inherited definition", - ccname))); simple_heap_update(conDesc, &tup->t_self, tup); CatalogUpdateIndexes(conDesc, tup); break; @@ -2560,14 +2667,9 @@ cookDefault(ParseState *pstate, /* * transformExpr() should have already rejected subqueries, aggregates, - * and window functions, based on the EXPR_KIND_ for a default expression. - * - * It can't return a set either. + * window functions, and SRFs, based on the EXPR_KIND_ for a default + * expression. */ - if (expression_returns_set(expr)) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("default expression must not return a set"))); /* * Coerce the expression to the correct type and typmod, if given. This @@ -2988,3 +3090,196 @@ insert_ordered_unique_oid(List *list, Oid datum) lappend_cell_oid(list, prev, datum); return list; } + +/* + * StorePartitionKey + * Store information about the partition key rel into the catalog + */ +void +StorePartitionKey(Relation rel, + char strategy, + int16 partnatts, + AttrNumber *partattrs, + List *partexprs, + Oid *partopclass, + Oid *partcollation) +{ + int i; + int2vector *partattrs_vec; + oidvector *partopclass_vec; + oidvector *partcollation_vec; + Datum partexprDatum; + Relation pg_partitioned_table; + HeapTuple tuple; + Datum values[Natts_pg_partitioned_table]; + bool nulls[Natts_pg_partitioned_table]; + ObjectAddress myself; + ObjectAddress referenced; + + Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE); + + tuple = SearchSysCache1(PARTRELID, + ObjectIdGetDatum(RelationGetRelid(rel))); + + /* Copy the partition attribute numbers, opclass OIDs into arrays */ + partattrs_vec = buildint2vector(partattrs, partnatts); + partopclass_vec = buildoidvector(partopclass, partnatts); + partcollation_vec = buildoidvector(partcollation, partnatts); + + /* Convert the expressions (if any) to a text datum */ + if (partexprs) + { + char *exprString; + + exprString = nodeToString(partexprs); + partexprDatum = CStringGetTextDatum(exprString); + pfree(exprString); + } + else + partexprDatum = (Datum) 0; + + pg_partitioned_table = heap_open(PartitionedRelationId, RowExclusiveLock); + + MemSet(nulls, false, sizeof(nulls)); + + /* Only this can ever be NULL */ + if (!partexprDatum) + nulls[Anum_pg_partitioned_table_partexprs - 1] = true; + + values[Anum_pg_partitioned_table_partrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel)); + values[Anum_pg_partitioned_table_partstrat - 1] = CharGetDatum(strategy); + values[Anum_pg_partitioned_table_partnatts - 1] = Int16GetDatum(partnatts); + values[Anum_pg_partitioned_table_partattrs - 1] = PointerGetDatum(partattrs_vec); + values[Anum_pg_partitioned_table_partclass - 1] = PointerGetDatum(partopclass_vec); + values[Anum_pg_partitioned_table_partcollation - 1] = PointerGetDatum(partcollation_vec); + values[Anum_pg_partitioned_table_partexprs - 1] = partexprDatum; + + tuple = heap_form_tuple(RelationGetDescr(pg_partitioned_table), values, nulls); + + simple_heap_insert(pg_partitioned_table, tuple); + + /* Update the indexes on pg_partitioned_table */ + CatalogUpdateIndexes(pg_partitioned_table, tuple); + heap_close(pg_partitioned_table, RowExclusiveLock); + + /* Mark this relation as dependent on a few things as follows */ + myself.classId = RelationRelationId; + myself.objectId = RelationGetRelid(rel);; + myself.objectSubId = 0; + + /* Operator class and collation per key column */ + for (i = 0; i < partnatts; i++) + { + referenced.classId = OperatorClassRelationId; + referenced.objectId = partopclass[i]; + referenced.objectSubId = 0; + + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + referenced.classId = CollationRelationId; + referenced.objectId = partcollation[i]; + referenced.objectSubId = 0; + + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* + * Anything mentioned in the expressions. We must ignore the column + * references, which will depend on the table itself; there is no + * separate partition key object. + */ + if (partexprs) + recordDependencyOnSingleRelExpr(&myself, + (Node *) partexprs, + RelationGetRelid(rel), + DEPENDENCY_NORMAL, + DEPENDENCY_AUTO, true); + + /* + * We must invalidate the relcache so that the next + * CommandCounterIncrement() will cause the same to be rebuilt using the + * information in just created catalog entry. + */ + CacheInvalidateRelcache(rel); +} + +/* + * RemovePartitionKeyByRelId + * Remove pg_partitioned_table entry for a relation + */ +void +RemovePartitionKeyByRelId(Oid relid) +{ + Relation rel; + HeapTuple tuple; + + rel = heap_open(PartitionedRelationId, RowExclusiveLock); + + tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for partition key of relation %u", + relid); + + simple_heap_delete(rel, &tuple->t_self); + + ReleaseSysCache(tuple); + heap_close(rel, RowExclusiveLock); +} + +/* + * StorePartitionBound + * Update pg_class tuple of rel to store the partition bound and set + * relispartition to true + * + * Also, invalidate the parent's relcache, so that the next rebuild will load + * the new partition's info into its partition descriptor. + */ +void +StorePartitionBound(Relation rel, Relation parent, Node *bound) +{ + Relation classRel; + HeapTuple tuple, + newtuple; + Datum new_val[Natts_pg_class]; + bool new_null[Natts_pg_class], + new_repl[Natts_pg_class]; + + /* Update pg_class tuple */ + classRel = heap_open(RelationRelationId, RowExclusiveLock); + tuple = SearchSysCacheCopy1(RELOID, + ObjectIdGetDatum(RelationGetRelid(rel))); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation %u", + RelationGetRelid(rel)); + +#ifdef USE_ASSERT_CHECKING + { + Form_pg_class classForm; + bool isnull; + + classForm = (Form_pg_class) GETSTRUCT(tuple); + Assert(!classForm->relispartition); + (void) SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relpartbound, + &isnull); + Assert(isnull); + } +#endif + + /* Fill in relpartbound value */ + memset(new_val, 0, sizeof(new_val)); + memset(new_null, false, sizeof(new_null)); + memset(new_repl, false, sizeof(new_repl)); + new_val[Anum_pg_class_relpartbound - 1] = CStringGetTextDatum(nodeToString(bound)); + new_null[Anum_pg_class_relpartbound - 1] = false; + new_repl[Anum_pg_class_relpartbound - 1] = true; + newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel), + new_val, new_null, new_repl); + /* Also set the flag */ + ((Form_pg_class) GETSTRUCT(newtuple))->relispartition = true; + simple_heap_update(classRel, &newtuple->t_self, newtuple); + CatalogUpdateIndexes(classRel, newtuple); + heap_freetuple(newtuple); + heap_close(classRel, RowExclusiveLock); + + CacheInvalidateRelcache(parent); +} diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index b0b43cf02d..26cbc0e06a 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -3,7 +3,7 @@ * index.c * code to create and destroy POSTGRES index relations * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -437,11 +437,28 @@ ConstructTupleDescriptor(Relation heapRelation, keyType = opclassTup->opckeytype; else keyType = amroutine->amkeytype; + + /* + * If keytype is specified as ANYELEMENT, and opcintype is ANYARRAY, + * then the attribute type must be an array (else it'd not have + * matched this opclass); use its element type. + */ + if (keyType == ANYELEMENTOID && opclassTup->opcintype == ANYARRAYOID) + { + keyType = get_base_element_type(to->atttypid); + if (!OidIsValid(keyType)) + elog(ERROR, "could not get element type of array type %u", + to->atttypid); + } + ReleaseSysCache(tuple); + /* + * If a key type different from the heap value is specified, update + * the type-related fields in the index tupdesc. + */ if (OidIsValid(keyType) && keyType != to->atttypid) { - /* index value and heap value have different types */ tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(keyType)); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for type %u", keyType); @@ -1026,7 +1043,7 @@ index_create(Relation heapRelation, (Node *) indexInfo->ii_Expressions, heapRelationId, DEPENDENCY_NORMAL, - DEPENDENCY_AUTO); + DEPENDENCY_AUTO, false); } /* Store dependencies on anything mentioned in predicate */ @@ -1036,7 +1053,7 @@ index_create(Relation heapRelation, (Node *) indexInfo->ii_Predicate, heapRelationId, DEPENDENCY_NORMAL, - DEPENDENCY_AUTO); + DEPENDENCY_AUTO, false); } } else @@ -1788,8 +1805,7 @@ FormIndexDatum(IndexInfo *indexInfo, elog(ERROR, "wrong number of index expressions"); iDatum = ExecEvalExprSwitchContext((ExprState *) lfirst(indexpr_item), GetPerTupleExprContext(estate), - &isNull, - NULL); + &isNull); indexpr_item = lnext(indexpr_item); } values[i] = iDatum; diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c index b9fe10237b..1915ca3779 100644 --- a/src/backend/catalog/indexing.c +++ b/src/backend/catalog/indexing.c @@ -4,7 +4,7 @@ * This file contains routines to support indexes defined on system * catalogs. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql index 18be08fead..62ee2b4e0e 100644 --- a/src/backend/catalog/information_schema.sql +++ b/src/backend/catalog/information_schema.sql @@ -2,7 +2,7 @@ * SQL Information Schema * as defined in ISO/IEC 9075-11:2011 * - * Copyright (c) 2003-2016, PostgreSQL Global Development Group + * Copyright (c) 2003-2017, PostgreSQL Global Development Group * * src/backend/catalog/information_schema.sql * @@ -453,7 +453,7 @@ CREATE VIEW check_constraints AS AND a.attnum > 0 AND NOT a.attisdropped AND a.attnotnull - AND r.relkind = 'r' + AND r.relkind IN ('r', 'P') AND pg_has_role(r.relowner, 'USAGE'); GRANT SELECT ON check_constraints TO PUBLIC; @@ -525,7 +525,7 @@ CREATE VIEW column_domain_usage AS AND a.attrelid = c.oid AND a.atttypid = t.oid AND t.typtype = 'd' - AND c.relkind IN ('r', 'v', 'f') + AND c.relkind IN ('r', 'v', 'f', 'P') AND a.attnum > 0 AND NOT a.attisdropped AND pg_has_role(t.typowner, 'USAGE'); @@ -564,7 +564,7 @@ CREATE VIEW column_privileges AS pr_c.relowner FROM (SELECT oid, relname, relnamespace, relowner, (aclexplode(coalesce(relacl, acldefault('r', relowner)))).* FROM pg_class - WHERE relkind IN ('r', 'v', 'f') + WHERE relkind IN ('r', 'v', 'f', 'P') ) pr_c (oid, relname, relnamespace, relowner, grantor, grantee, prtype, grantable), pg_attribute a WHERE a.attrelid = pr_c.oid @@ -586,7 +586,7 @@ CREATE VIEW column_privileges AS ) pr_a (attrelid, attname, grantor, grantee, prtype, grantable), pg_class c WHERE pr_a.attrelid = c.oid - AND relkind IN ('r', 'v', 'f') + AND relkind IN ('r', 'v', 'f', 'P') ) x, pg_namespace nc, pg_authid u_grantor, @@ -629,7 +629,7 @@ CREATE VIEW column_udt_usage AS WHERE a.attrelid = c.oid AND a.atttypid = t.oid AND nc.oid = c.relnamespace - AND a.attnum > 0 AND NOT a.attisdropped AND c.relkind in ('r', 'v', 'f') + AND a.attnum > 0 AND NOT a.attisdropped AND c.relkind in ('r', 'v', 'f', 'P') AND pg_has_role(coalesce(bt.typowner, t.typowner), 'USAGE'); GRANT SELECT ON column_udt_usage TO PUBLIC; @@ -738,7 +738,7 @@ CREATE VIEW columns AS CAST('NEVER' AS character_data) AS is_generated, CAST(null AS character_data) AS generation_expression, - CAST(CASE WHEN c.relkind = 'r' OR + CAST(CASE WHEN c.relkind IN ('r', 'P') OR (c.relkind IN ('v', 'f') AND pg_column_is_updatable(c.oid, a.attnum, false)) THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_updatable @@ -753,7 +753,7 @@ CREATE VIEW columns AS WHERE (NOT pg_is_other_temp_schema(nc.oid)) - AND a.attnum > 0 AND NOT a.attisdropped AND c.relkind in ('r', 'v', 'f') + AND a.attnum > 0 AND NOT a.attisdropped AND c.relkind in ('r', 'v', 'f', 'P') AND (pg_has_role(c.relowner, 'USAGE') OR has_column_privilege(c.oid, a.attnum, @@ -789,7 +789,7 @@ CREATE VIEW constraint_column_usage AS AND d.objid = c.oid AND c.connamespace = nc.oid AND c.contype = 'c' - AND r.relkind = 'r' + AND r.relkind IN ('r', 'P') AND NOT a.attisdropped UNION ALL @@ -805,7 +805,7 @@ CREATE VIEW constraint_column_usage AS ELSE r.oid = c.conrelid AND a.attnum = ANY (c.conkey) END) AND NOT a.attisdropped AND c.contype IN ('p', 'u', 'f') - AND r.relkind = 'r' + AND r.relkind IN ('r', 'P') ) AS x (tblschema, tblname, tblowner, colname, cstrschema, cstrname) @@ -841,7 +841,7 @@ CREATE VIEW constraint_table_usage AS WHERE c.connamespace = nc.oid AND r.relnamespace = nr.oid AND ( (c.contype = 'f' AND c.confrelid = r.oid) OR (c.contype IN ('p', 'u') AND c.conrelid = r.oid) ) - AND r.relkind = 'r' + AND r.relkind IN ('r', 'P') AND pg_has_role(r.relowner, 'USAGE'); GRANT SELECT ON constraint_table_usage TO PUBLIC; @@ -1058,7 +1058,7 @@ CREATE VIEW key_column_usage AS AND r.oid = c.conrelid AND nc.oid = c.connamespace AND c.contype IN ('p', 'u', 'f') - AND r.relkind = 'r' + AND r.relkind IN ('r', 'P') AND (NOT pg_is_other_temp_schema(nr.oid)) ) AS ss WHERE ss.roid = a.attrelid AND a.attnum = (ss.x).x @@ -1535,15 +1535,16 @@ CREATE VIEW sequences AS CAST(64 AS cardinal_number) AS numeric_precision, CAST(2 AS cardinal_number) AS numeric_precision_radix, CAST(0 AS cardinal_number) AS numeric_scale, - CAST(p.start_value AS character_data) AS start_value, - CAST(p.minimum_value AS character_data) AS minimum_value, - CAST(p.maximum_value AS character_data) AS maximum_value, - CAST(p.increment AS character_data) AS increment, - CAST(CASE WHEN p.cycle_option THEN 'YES' ELSE 'NO' END AS yes_or_no) AS cycle_option - FROM pg_namespace nc, pg_class c, LATERAL pg_sequence_parameters(c.oid) p + CAST(s.seqstart AS character_data) AS start_value, + CAST(s.seqmin AS character_data) AS minimum_value, + CAST(s.seqmax AS character_data) AS maximum_value, + CAST(s.seqincrement AS character_data) AS increment, + CAST(CASE WHEN s.seqcycle THEN 'YES' ELSE 'NO' END AS yes_or_no) AS cycle_option + FROM pg_namespace nc, pg_class c, pg_sequence s WHERE c.relnamespace = nc.oid AND c.relkind = 'S' AND (NOT pg_is_other_temp_schema(nc.oid)) + AND c.oid = s.seqrelid AND (pg_has_role(c.relowner, 'USAGE') OR has_sequence_privilege(c.oid, 'SELECT, UPDATE, USAGE') ); @@ -1773,7 +1774,7 @@ CREATE VIEW table_constraints AS WHERE nc.oid = c.connamespace AND nr.oid = r.relnamespace AND c.conrelid = r.oid AND c.contype NOT IN ('t', 'x') -- ignore nonstandard constraints - AND r.relkind = 'r' + AND r.relkind IN ('r', 'P') AND (NOT pg_is_other_temp_schema(nr.oid)) AND (pg_has_role(r.relowner, 'USAGE') -- SELECT privilege omitted, per SQL standard @@ -1803,7 +1804,7 @@ CREATE VIEW table_constraints AS AND a.attnotnull AND a.attnum > 0 AND NOT a.attisdropped - AND r.relkind = 'r' + AND r.relkind IN ('r', 'P') AND (NOT pg_is_other_temp_schema(nr.oid)) AND (pg_has_role(r.relowner, 'USAGE') -- SELECT privilege omitted, per SQL standard @@ -1853,7 +1854,7 @@ CREATE VIEW table_privileges AS ) AS grantee (oid, rolname) WHERE c.relnamespace = nc.oid - AND c.relkind IN ('r', 'v') + AND c.relkind IN ('r', 'v', 'P') AND c.grantee = grantee.oid AND c.grantor = u_grantor.oid AND c.prtype IN ('INSERT', 'SELECT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER') @@ -1897,7 +1898,7 @@ CREATE VIEW tables AS CAST( CASE WHEN nc.oid = pg_my_temp_schema() THEN 'LOCAL TEMPORARY' - WHEN c.relkind = 'r' THEN 'BASE TABLE' + WHEN c.relkind IN ('r', 'P') THEN 'BASE TABLE' WHEN c.relkind = 'v' THEN 'VIEW' WHEN c.relkind = 'f' THEN 'FOREIGN TABLE' ELSE null END @@ -1910,7 +1911,7 @@ CREATE VIEW tables AS CAST(nt.nspname AS sql_identifier) AS user_defined_type_schema, CAST(t.typname AS sql_identifier) AS user_defined_type_name, - CAST(CASE WHEN c.relkind = 'r' OR + CAST(CASE WHEN c.relkind IN ('r', 'P') OR (c.relkind IN ('v', 'f') AND -- 1 << CMD_INSERT pg_relation_is_updatable(c.oid, false) & 8 = 8) @@ -1922,7 +1923,7 @@ CREATE VIEW tables AS FROM pg_namespace nc JOIN pg_class c ON (nc.oid = c.relnamespace) LEFT JOIN (pg_type t JOIN pg_namespace nt ON (t.typnamespace = nt.oid)) ON (c.reloftype = t.oid) - WHERE c.relkind IN ('r', 'v', 'f') + WHERE c.relkind IN ('r', 'v', 'f', 'P') AND (NOT pg_is_other_temp_schema(nc.oid)) AND (pg_has_role(c.relowner, 'USAGE') OR has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER') @@ -2068,7 +2069,7 @@ CREATE VIEW triggers AS -- XXX strange hacks follow CAST( CASE WHEN pg_has_role(c.relowner, 'USAGE') - THEN (SELECT m[1] FROM regexp_matches(pg_get_triggerdef(t.oid), E'.{35,} WHEN \\((.+)\\) EXECUTE PROCEDURE') AS rm(m) LIMIT 1) + THEN (regexp_match(pg_get_triggerdef(t.oid), E'.{35,} WHEN \\((.+)\\) EXECUTE PROCEDURE'))[1] ELSE null END AS character_data) AS action_condition, CAST( @@ -2441,7 +2442,7 @@ CREATE VIEW view_column_usage AS AND dt.refclassid = 'pg_catalog.pg_class'::regclass AND dt.refobjid = t.oid AND t.relnamespace = nt.oid - AND t.relkind IN ('r', 'v', 'f') + AND t.relkind IN ('r', 'v', 'f', 'P') AND t.oid = a.attrelid AND dt.refobjsubid = a.attnum AND pg_has_role(t.relowner, 'USAGE'); @@ -2519,7 +2520,7 @@ CREATE VIEW view_table_usage AS AND dt.refclassid = 'pg_catalog.pg_class'::regclass AND dt.refobjid = t.oid AND t.relnamespace = nt.oid - AND t.relkind IN ('r', 'v', 'f') + AND t.relkind IN ('r', 'v', 'f', 'P') AND pg_has_role(t.relowner, 'USAGE'); GRANT SELECT ON view_table_usage TO PUBLIC; @@ -2672,7 +2673,7 @@ CREATE VIEW element_types AS a.attnum, a.atttypid, a.attcollation FROM pg_class c, pg_attribute a WHERE c.oid = a.attrelid - AND c.relkind IN ('r', 'v', 'f', 'c') + AND c.relkind IN ('r', 'v', 'f', 'c', 'P') AND attnum > 0 AND NOT attisdropped UNION ALL diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index 8fd4c3136b..a38da3047f 100644 --- a/src/backend/catalog/namespace.c +++ b/src/backend/catalog/namespace.c @@ -9,7 +9,7 @@ * and implementing search-path-controlled searches. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -56,6 +56,7 @@ #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/syscache.h" +#include "utils/varlena.h" /* @@ -198,22 +199,6 @@ static void NamespaceCallback(Datum arg, int cacheid, uint32 hashvalue); static bool MatchNamedCall(HeapTuple proctup, int nargs, List *argnames, int **argnumbers); -/* These don't really need to appear in any header file */ -Datum pg_table_is_visible(PG_FUNCTION_ARGS); -Datum pg_type_is_visible(PG_FUNCTION_ARGS); -Datum pg_function_is_visible(PG_FUNCTION_ARGS); -Datum pg_operator_is_visible(PG_FUNCTION_ARGS); -Datum pg_opclass_is_visible(PG_FUNCTION_ARGS); -Datum pg_opfamily_is_visible(PG_FUNCTION_ARGS); -Datum pg_collation_is_visible(PG_FUNCTION_ARGS); -Datum pg_conversion_is_visible(PG_FUNCTION_ARGS); -Datum pg_ts_parser_is_visible(PG_FUNCTION_ARGS); -Datum pg_ts_dict_is_visible(PG_FUNCTION_ARGS); -Datum pg_ts_template_is_visible(PG_FUNCTION_ARGS); -Datum pg_ts_config_is_visible(PG_FUNCTION_ARGS); -Datum pg_my_temp_schema(PG_FUNCTION_ARGS); -Datum pg_is_other_temp_schema(PG_FUNCTION_ARGS); - /* * RangeVarGetRelid @@ -3872,14 +3857,19 @@ RemoveTempRelations(Oid tempNamespaceId) /* * We want to get rid of everything in the target namespace, but not the * namespace itself (deleting it only to recreate it later would be a - * waste of cycles). We do this by finding everything that has a - * dependency on the namespace. + * waste of cycles). Hence, specify SKIP_ORIGINAL. It's also an INTERNAL + * deletion, and we want to not drop any extensions that might happen to + * own temp objects. */ object.classId = NamespaceRelationId; object.objectId = tempNamespaceId; object.objectSubId = 0; - deleteWhatDependsOn(&object, false); + performDeletion(&object, DROP_CASCADE, + PERFORM_DELETION_INTERNAL | + PERFORM_DELETION_QUIETLY | + PERFORM_DELETION_SKIP_ORIGINAL | + PERFORM_DELETION_SKIP_EXTENSIONS); } /* diff --git a/src/backend/catalog/objectaccess.c b/src/backend/catalog/objectaccess.c index 23103d0cb6..9d5eb7b9da 100644 --- a/src/backend/catalog/objectaccess.c +++ b/src/backend/catalog/objectaccess.c @@ -3,7 +3,7 @@ * objectaccess.c * functions for object_access_hook on various events * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * ------------------------------------------------------------------------- diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index 8068b82eab..d1529c3197 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -3,7 +3,7 @@ * objectaddress.c * functions for working with ObjectAddresses * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -45,7 +45,10 @@ #include "catalog/pg_operator.h" #include "catalog/pg_proc.h" #include "catalog/pg_policy.h" +#include "catalog/pg_publication.h" +#include "catalog/pg_publication_rel.h" #include "catalog/pg_rewrite.h" +#include "catalog/pg_subscription.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_transform.h" #include "catalog/pg_trigger.h" @@ -78,6 +81,7 @@ #include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/memutils.h" +#include "utils/regproc.h" #include "utils/syscache.h" #include "utils/tqual.h" @@ -450,6 +454,30 @@ static const ObjectPropertyType ObjectProperty[] = Anum_pg_type_typacl, ACL_KIND_TYPE, true + }, + { + PublicationRelationId, + PublicationObjectIndexId, + PUBLICATIONOID, + PUBLICATIONNAME, + Anum_pg_publication_pubname, + InvalidAttrNumber, + Anum_pg_publication_pubowner, + InvalidAttrNumber, + -1, + true + }, + { + SubscriptionRelationId, + SubscriptionObjectIndexId, + SUBSCRIPTIONOID, + SUBSCRIPTIONNAME, + Anum_pg_subscription_subname, + InvalidAttrNumber, + Anum_pg_subscription_subowner, + InvalidAttrNumber, + -1, + true } }; @@ -653,6 +681,18 @@ static const struct object_type_map { "policy", OBJECT_POLICY }, + /* OCLASS_PUBLICATION */ + { + "publication", OBJECT_PUBLICATION + }, + /* OCLASS_PUBLICATION_REL */ + { + "publication relation", OBJECT_PUBLICATION_REL + }, + /* OCLASS_SUBSCRIPTION */ + { + "subscription", OBJECT_SUBSCRIPTION + }, /* OCLASS_TRANSFORM */ { "transform", OBJECT_TRANSFORM @@ -688,6 +728,9 @@ static ObjectAddress get_object_address_opf_member(ObjectType objtype, static ObjectAddress get_object_address_usermapping(List *objname, List *objargs, bool missing_ok); +static ObjectAddress get_object_address_publication_rel(List *objname, + List *objargs, Relation *relation, + bool missing_ok); static ObjectAddress get_object_address_defacl(List *objname, List *objargs, bool missing_ok); static const ObjectPropertyType *get_object_property_data(Oid class_id); @@ -812,6 +855,8 @@ get_object_address(ObjectType objtype, List *objname, List *objargs, case OBJECT_FOREIGN_SERVER: case OBJECT_EVENT_TRIGGER: case OBJECT_ACCESS_METHOD: + case OBJECT_PUBLICATION: + case OBJECT_SUBSCRIPTION: address = get_object_address_unqualified(objtype, objname, missing_ok); break; @@ -926,6 +971,11 @@ get_object_address(ObjectType objtype, List *objname, List *objargs, address = get_object_address_usermapping(objname, objargs, missing_ok); break; + case OBJECT_PUBLICATION_REL: + address = get_object_address_publication_rel(objname, objargs, + &relation, + missing_ok); + break; case OBJECT_DEFACL: address = get_object_address_defacl(objname, objargs, missing_ok); @@ -1091,6 +1141,12 @@ get_object_address_unqualified(ObjectType objtype, case OBJECT_EVENT_TRIGGER: msg = gettext_noop("event trigger name cannot be qualified"); break; + case OBJECT_PUBLICATION: + msg = gettext_noop("publication name cannot be qualified"); + break; + case OBJECT_SUBSCRIPTION: + msg = gettext_noop("subscription name cannot be qualified"); + break; default: elog(ERROR, "unrecognized objtype: %d", (int) objtype); msg = NULL; /* placate compiler */ @@ -1156,6 +1212,16 @@ get_object_address_unqualified(ObjectType objtype, address.objectId = get_event_trigger_oid(name, missing_ok); address.objectSubId = 0; break; + case OBJECT_PUBLICATION: + address.classId = PublicationRelationId; + address.objectId = get_publication_oid(name, missing_ok); + address.objectSubId = 0; + break; + case OBJECT_SUBSCRIPTION: + address.classId = SubscriptionRelationId; + address.objectId = get_subscription_oid(name, missing_ok); + address.objectSubId = 0; + break; default: elog(ERROR, "unrecognized objtype: %d", (int) objtype); /* placate compiler, which doesn't know elog won't return */ @@ -1204,7 +1270,8 @@ get_relation_by_qualified_name(ObjectType objtype, List *objname, RelationGetRelationName(relation)))); break; case OBJECT_TABLE: - if (relation->rd_rel->relkind != RELKIND_RELATION) + if (relation->rd_rel->relkind != RELKIND_RELATION && + relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table", @@ -1742,6 +1809,51 @@ get_object_address_usermapping(List *objname, List *objargs, bool missing_ok) return address; } +/* + * Find the ObjectAddress for a publication relation. The objname parameter + * is the relation name; objargs contains the publication name. + */ +static ObjectAddress +get_object_address_publication_rel(List *objname, List *objargs, + Relation *relation, bool missing_ok) +{ + ObjectAddress address; + char *pubname; + Publication *pub; + + ObjectAddressSet(address, PublicationRelRelationId, InvalidOid); + + *relation = relation_openrv_extended(makeRangeVarFromNameList(objname), + AccessShareLock, missing_ok); + if (!relation) + return address; + + /* fetch publication name from input list */ + pubname = strVal(linitial(objargs)); + + /* Now look up the pg_publication tuple */ + pub = GetPublicationByName(pubname, missing_ok); + if (!pub) + return address; + + /* Find the publication relation mapping in syscache. */ + address.objectId = + GetSysCacheOid2(PUBLICATIONRELMAP, + ObjectIdGetDatum(RelationGetRelid(*relation)), + ObjectIdGetDatum(pub->oid)); + if (!OidIsValid(address.objectId)) + { + if (!missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("publication relation \"%s\" in publication \"%s\" does not exist", + RelationGetRelationName(*relation), pubname))); + return address; + } + + return address; +} + /* * Find the ObjectAddress for a default ACL. */ @@ -2001,6 +2113,7 @@ pg_get_object_address(PG_FUNCTION_ARGS) case OBJECT_DOMCONSTRAINT: case OBJECT_CAST: case OBJECT_USER_MAPPING: + case OBJECT_PUBLICATION_REL: case OBJECT_DEFACL: case OBJECT_TRANSFORM: if (list_length(args) != 1) @@ -2182,6 +2295,16 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, format_type_be(targettypeid)))); } break; + case OBJECT_PUBLICATION: + if (!pg_publication_ownercheck(address.objectId, roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PUBLICATION, + NameListToString(objname)); + break; + case OBJECT_SUBSCRIPTION: + if (!pg_subscription_ownercheck(address.objectId, roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_SUBSCRIPTION, + NameListToString(objname)); + break; case OBJECT_TRANSFORM: { TypeName *typename = (TypeName *) linitial(objname); @@ -2290,23 +2413,18 @@ get_object_namespace(const ObjectAddress *address) int read_objtype_from_string(const char *objtype) { - ObjectType type; int i; for (i = 0; i < lengthof(ObjectTypeMap); i++) { if (strcmp(ObjectTypeMap[i].tm_name, objtype) == 0) - { - type = ObjectTypeMap[i].tm_type; - break; - } + return ObjectTypeMap[i].tm_type; } - if (i >= lengthof(ObjectTypeMap)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("unrecognized object type \"%s\"", objtype))); + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unrecognized object type \"%s\"", objtype))); - return type; + return -1; /* keep compiler quiet */ } /* @@ -3195,6 +3313,41 @@ getObjectDescription(const ObjectAddress *object) break; } + case OCLASS_PUBLICATION: + { + appendStringInfo(&buffer, _("publication %s"), + get_publication_name(object->objectId)); + break; + } + + case OCLASS_PUBLICATION_REL: + { + HeapTuple tup; + char *pubname; + Form_pg_publication_rel prform; + + tup = SearchSysCache1(PUBLICATIONREL, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for publication table %u", + object->objectId); + + prform = (Form_pg_publication_rel) GETSTRUCT(tup); + pubname = get_publication_name(prform->prpubid); + + appendStringInfo(&buffer, _("publication table %s in publication %s"), + get_rel_name(prform->prrelid), pubname); + ReleaseSysCache(tup); + break; + } + + case OCLASS_SUBSCRIPTION: + { + appendStringInfo(&buffer, _("subscription %s"), + get_subscription_name(object->objectId)); + break; + } + default: appendStringInfo(&buffer, "unrecognized object %u %u %d", object->classId, @@ -3249,6 +3402,7 @@ getRelationDescription(StringInfo buffer, Oid relid) switch (relForm->relkind) { case RELKIND_RELATION: + case RELKIND_PARTITIONED_TABLE: appendStringInfo(buffer, _("table %s"), relname); break; @@ -3680,6 +3834,18 @@ getObjectTypeDescription(const ObjectAddress *object) appendStringInfoString(&buffer, "access method"); break; + case OCLASS_PUBLICATION: + appendStringInfoString(&buffer, "publication"); + break; + + case OCLASS_PUBLICATION_REL: + appendStringInfoString(&buffer, "publication table"); + break; + + case OCLASS_SUBSCRIPTION: + appendStringInfoString(&buffer, "subscription"); + break; + default: appendStringInfo(&buffer, "unrecognized %u", object->classId); break; @@ -3706,6 +3872,7 @@ getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId) switch (relForm->relkind) { case RELKIND_RELATION: + case RELKIND_PARTITIONED_TABLE: appendStringInfoString(buffer, "table"); break; case RELKIND_INDEX: @@ -4650,6 +4817,58 @@ getObjectIdentityParts(const ObjectAddress *object, } break; + case OCLASS_PUBLICATION: + { + char *pubname; + + pubname = get_publication_name(object->objectId); + appendStringInfoString(&buffer, + quote_identifier(pubname)); + if (objname) + *objname = list_make1(pubname); + break; + } + + case OCLASS_PUBLICATION_REL: + { + HeapTuple tup; + char *pubname; + Form_pg_publication_rel prform; + + tup = SearchSysCache1(PUBLICATIONREL, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for publication table %u", + object->objectId); + + prform = (Form_pg_publication_rel) GETSTRUCT(tup); + pubname = get_publication_name(prform->prpubid); + + appendStringInfo(&buffer, _("publication table %s in publication %s"), + get_rel_name(prform->prrelid), pubname); + + if (objname) + { + getRelationIdentity(&buffer, prform->prrelid, objname); + *objargs = list_make1(pubname); + } + + ReleaseSysCache(tup); + break; + } + + case OCLASS_SUBSCRIPTION: + { + char *subname; + + subname = get_subscription_name(object->objectId); + appendStringInfoString(&buffer, + quote_identifier(subname)); + if (objname) + *objname = list_make1(subname); + break; + } + default: appendStringInfo(&buffer, "unrecognized object %u %u %d", object->classId, @@ -4747,9 +4966,7 @@ strlist_to_textarray(List *list) memcxt = AllocSetContextCreate(CurrentMemoryContext, "strlist to array", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldcxt = MemoryContextSwitchTo(memcxt); datums = palloc(sizeof(text *) * list_length(list)); diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c new file mode 100644 index 0000000000..ad95b1bc55 --- /dev/null +++ b/src/backend/catalog/partition.c @@ -0,0 +1,2031 @@ +/*------------------------------------------------------------------------- + * + * partition.c + * Partitioning related data structures and functions. + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/partition.c + * + *------------------------------------------------------------------------- +*/ + +#include "postgres.h" + +#include "access/heapam.h" +#include "access/htup_details.h" +#include "access/nbtree.h" +#include "access/sysattr.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" +#include "catalog/objectaddress.h" +#include "catalog/partition.h" +#include "catalog/pg_collation.h" +#include "catalog/pg_inherits.h" +#include "catalog/pg_inherits_fn.h" +#include "catalog/pg_opclass.h" +#include "catalog/pg_type.h" +#include "executor/executor.h" +#include "miscadmin.h" +#include "nodes/makefuncs.h" +#include "nodes/nodeFuncs.h" +#include "nodes/parsenodes.h" +#include "optimizer/clauses.h" +#include "optimizer/planmain.h" +#include "optimizer/var.h" +#include "rewrite/rewriteManip.h" +#include "storage/lmgr.h" +#include "utils/array.h" +#include "utils/builtins.h" +#include "utils/datum.h" +#include "utils/memutils.h" +#include "utils/fmgroids.h" +#include "utils/inval.h" +#include "utils/lsyscache.h" +#include "utils/rel.h" +#include "utils/ruleutils.h" +#include "utils/syscache.h" + +/* + * Information about bounds of a partitioned relation + * + * A list partition datum that is known to be NULL is never put into the + * datums array. Instead, it is tracked using has_null and null_index fields. + * + * In the case of range partitioning, ndatums will typically be far less than + * 2 * nparts, because a partition's upper bound and the next partition's lower + * bound are the same in most common cases, and we only store one of them. + * + * In the case of list partitioning, the indexes array stores one entry for + * every datum, which is the index of the partition that accepts a given datum. + * In case of range partitioning, it stores one entry per distinct range + * datum, which is the index of the partition for which a given datum + * is an upper bound. + */ + +/* Ternary value to represent what's contained in a range bound datum */ +typedef enum RangeDatumContent +{ + RANGE_DATUM_FINITE = 0, /* actual datum stored elsewhere */ + RANGE_DATUM_NEG_INF, /* negative infinity */ + RANGE_DATUM_POS_INF /* positive infinity */ +} RangeDatumContent; + +typedef struct PartitionBoundInfoData +{ + char strategy; /* list or range bounds? */ + int ndatums; /* Length of the datums following array */ + Datum **datums; /* Array of datum-tuples with key->partnatts + * datums each */ + RangeDatumContent **content;/* what's contained in each range bound datum? + * (see the above enum); NULL for list + * partitioned tables */ + int *indexes; /* Partition indexes; one entry per member of + * the datums array (plus one if range + * partitioned table) */ + bool has_null; /* Is there a null-accepting partition? false + * for range partitioned tables */ + int null_index; /* Index of the null-accepting partition; -1 + * for range partitioned tables */ +} PartitionBoundInfoData; + +/* + * When qsort'ing partition bounds after reading from the catalog, each bound + * is represented with one of the following structs. + */ + +/* One value coming from some (index'th) list partition */ +typedef struct PartitionListValue +{ + int index; + Datum value; +} PartitionListValue; + +/* One bound of a range partition */ +typedef struct PartitionRangeBound +{ + int index; + Datum *datums; /* range bound datums */ + RangeDatumContent *content; /* what's contained in each datum? */ + bool lower; /* this is the lower (vs upper) bound */ +} PartitionRangeBound; + +static int32 qsort_partition_list_value_cmp(const void *a, const void *b, + void *arg); +static int32 qsort_partition_rbound_cmp(const void *a, const void *b, + void *arg); + +static List *get_qual_for_list(PartitionKey key, PartitionBoundSpec *spec); +static List *get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec); +static Oid get_partition_operator(PartitionKey key, int col, + StrategyNumber strategy, bool *need_relabel); +static List *generate_partition_qual(Relation rel); + +static PartitionRangeBound *make_one_range_bound(PartitionKey key, int index, + List *datums, bool lower); +static int32 partition_rbound_cmp(PartitionKey key, + Datum *datums1, RangeDatumContent *content1, bool lower1, + PartitionRangeBound *b2); +static int32 partition_rbound_datum_cmp(PartitionKey key, + Datum *rb_datums, RangeDatumContent *rb_content, + Datum *tuple_datums); + +static int32 partition_bound_cmp(PartitionKey key, + PartitionBoundInfo boundinfo, + int offset, void *probe, bool probe_is_bound); +static int partition_bound_bsearch(PartitionKey key, + PartitionBoundInfo boundinfo, + void *probe, bool probe_is_bound, bool *is_equal); + +/* Support get_partition_for_tuple() */ +static void FormPartitionKeyDatum(PartitionDispatch pd, + TupleTableSlot *slot, + EState *estate, + Datum *values, + bool *isnull); + +/* + * RelationBuildPartitionDesc + * Form rel's partition descriptor + * + * Not flushed from the cache by RelationClearRelation() unless changed because + * of addition or removal of partition. + */ +void +RelationBuildPartitionDesc(Relation rel) +{ + List *inhoids, + *partoids; + Oid *oids = NULL; + List *boundspecs = NIL; + ListCell *cell; + int i, + nparts; + PartitionKey key = RelationGetPartitionKey(rel); + PartitionDesc result; + MemoryContext oldcxt; + + int ndatums = 0; + + /* List partitioning specific */ + PartitionListValue **all_values = NULL; + bool found_null = false; + int null_index = -1; + + /* Range partitioning specific */ + PartitionRangeBound **rbounds = NULL; + + /* + * The following could happen in situations where rel has a pg_class entry + * but not the pg_partitioned_table entry yet. + */ + if (key == NULL) + return; + + /* Get partition oids from pg_inherits */ + inhoids = find_inheritance_children(RelationGetRelid(rel), NoLock); + + /* Collect bound spec nodes in a list */ + i = 0; + partoids = NIL; + foreach(cell, inhoids) + { + Oid inhrelid = lfirst_oid(cell); + HeapTuple tuple; + Datum datum; + bool isnull; + Node *boundspec; + + tuple = SearchSysCache1(RELOID, inhrelid); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation %u", inhrelid); + + /* + * It is possible that the pg_class tuple of a partition has not been + * updated yet to set its relpartbound field. The only case where + * this happens is when we open the parent relation to check using its + * partition descriptor that a new partition's bound does not overlap + * some existing partition. + */ + if (!((Form_pg_class) GETSTRUCT(tuple))->relispartition) + { + ReleaseSysCache(tuple); + continue; + } + + datum = SysCacheGetAttr(RELOID, tuple, + Anum_pg_class_relpartbound, + &isnull); + Assert(!isnull); + boundspec = (Node *) stringToNode(TextDatumGetCString(datum)); + boundspecs = lappend(boundspecs, boundspec); + partoids = lappend_oid(partoids, inhrelid); + ReleaseSysCache(tuple); + } + + nparts = list_length(partoids); + + if (nparts > 0) + { + oids = (Oid *) palloc(nparts * sizeof(Oid)); + i = 0; + foreach(cell, partoids) + oids[i++] = lfirst_oid(cell); + + /* Convert from node to the internal representation */ + if (key->strategy == PARTITION_STRATEGY_LIST) + { + List *non_null_values = NIL; + + /* + * Create a unified list of non-null values across all partitions. + */ + i = 0; + found_null = false; + null_index = -1; + foreach(cell, boundspecs) + { + ListCell *c; + PartitionBoundSpec *spec = lfirst(cell); + + if (spec->strategy != PARTITION_STRATEGY_LIST) + elog(ERROR, "invalid strategy in partition bound spec"); + + foreach(c, spec->listdatums) + { + Const *val = lfirst(c); + PartitionListValue *list_value = NULL; + + if (!val->constisnull) + { + list_value = (PartitionListValue *) + palloc0(sizeof(PartitionListValue)); + list_value->index = i; + list_value->value = val->constvalue; + } + else + { + /* + * Never put a null into the values array, flag + * instead for the code further down below where we + * construct the actual relcache struct. + */ + if (found_null) + elog(ERROR, "found null more than once"); + found_null = true; + null_index = i; + } + + if (list_value) + non_null_values = lappend(non_null_values, + list_value); + } + + i++; + } + + ndatums = list_length(non_null_values); + + /* + * Collect all list values in one array. Alongside the value, we + * also save the index of partition the value comes from. + */ + all_values = (PartitionListValue **) palloc(ndatums * + sizeof(PartitionListValue *)); + i = 0; + foreach(cell, non_null_values) + { + PartitionListValue *src = lfirst(cell); + + all_values[i] = (PartitionListValue *) + palloc(sizeof(PartitionListValue)); + all_values[i]->value = src->value; + all_values[i]->index = src->index; + i++; + } + + qsort_arg(all_values, ndatums, sizeof(PartitionListValue *), + qsort_partition_list_value_cmp, (void *) key); + } + else if (key->strategy == PARTITION_STRATEGY_RANGE) + { + int j, + k; + PartitionRangeBound **all_bounds, + *prev; + bool *distinct_indexes; + + all_bounds = (PartitionRangeBound **) palloc0(2 * nparts * + sizeof(PartitionRangeBound *)); + distinct_indexes = (bool *) palloc(2 * nparts * sizeof(bool)); + + /* + * Create a unified list of range bounds across all the + * partitions. + */ + i = j = 0; + foreach(cell, boundspecs) + { + PartitionBoundSpec *spec = lfirst(cell); + PartitionRangeBound *lower, + *upper; + + if (spec->strategy != PARTITION_STRATEGY_RANGE) + elog(ERROR, "invalid strategy in partition bound spec"); + + lower = make_one_range_bound(key, i, spec->lowerdatums, + true); + upper = make_one_range_bound(key, i, spec->upperdatums, + false); + all_bounds[j] = lower; + all_bounds[j + 1] = upper; + j += 2; + i++; + } + Assert(j == 2 * nparts); + + /* Sort all the bounds in ascending order */ + qsort_arg(all_bounds, 2 * nparts, + sizeof(PartitionRangeBound *), + qsort_partition_rbound_cmp, + (void *) key); + + /* + * Count the number of distinct bounds to allocate an array of + * that size. + */ + ndatums = 0; + prev = NULL; + for (i = 0; i < 2 * nparts; i++) + { + PartitionRangeBound *cur = all_bounds[i]; + bool is_distinct = false; + int j; + + /* Is current bound is distinct from the previous? */ + for (j = 0; j < key->partnatts; j++) + { + Datum cmpval; + + if (prev == NULL) + { + is_distinct = true; + break; + } + + /* + * If either of them has infinite element, we can't equate + * them. Even when both are infinite, they'd have + * opposite signs, because only one of cur and prev is a + * lower bound). + */ + if (cur->content[j] != RANGE_DATUM_FINITE || + prev->content[j] != RANGE_DATUM_FINITE) + { + is_distinct = true; + break; + } + cmpval = FunctionCall2Coll(&key->partsupfunc[j], + key->partcollation[j], + cur->datums[j], + prev->datums[j]); + if (DatumGetInt32(cmpval) != 0) + { + is_distinct = true; + break; + } + } + + /* + * Count the current bound if it is distinct from the previous + * one. Also, store if the index i contains a distinct bound + * that we'd like put in the relcache array. + */ + if (is_distinct) + { + distinct_indexes[i] = true; + ndatums++; + } + else + distinct_indexes[i] = false; + + prev = cur; + } + + /* + * Finally save them in an array from where they will be copied + * into the relcache. + */ + rbounds = (PartitionRangeBound **) palloc(ndatums * + sizeof(PartitionRangeBound *)); + k = 0; + for (i = 0; i < 2 * nparts; i++) + { + if (distinct_indexes[i]) + rbounds[k++] = all_bounds[i]; + } + Assert(k == ndatums); + } + else + elog(ERROR, "unexpected partition strategy: %d", + (int) key->strategy); + } + + /* Now build the actual relcache partition descriptor */ + rel->rd_pdcxt = AllocSetContextCreate(CacheMemoryContext, + RelationGetRelationName(rel), + ALLOCSET_DEFAULT_SIZES); + oldcxt = MemoryContextSwitchTo(rel->rd_pdcxt); + + result = (PartitionDescData *) palloc0(sizeof(PartitionDescData)); + result->nparts = nparts; + if (nparts > 0) + { + PartitionBoundInfo boundinfo; + int *mapping; + int next_index = 0; + + result->oids = (Oid *) palloc0(nparts * sizeof(Oid)); + + boundinfo = (PartitionBoundInfoData *) + palloc0(sizeof(PartitionBoundInfoData)); + boundinfo->strategy = key->strategy; + boundinfo->ndatums = ndatums; + boundinfo->datums = (Datum **) palloc0(ndatums * sizeof(Datum *)); + + /* Initialize mapping array with invalid values */ + mapping = (int *) palloc(sizeof(int) * nparts); + for (i = 0; i < nparts; i++) + mapping[i] = -1; + + switch (key->strategy) + { + case PARTITION_STRATEGY_LIST: + { + boundinfo->has_null = found_null; + boundinfo->indexes = (int *) palloc(ndatums * sizeof(int)); + + /* + * Copy values. Indexes of individual values are mapped + * to canonical values so that they match for any two list + * partitioned tables with same number of partitions and + * same lists per partition. One way to canonicalize is + * to assign the index in all_values[] of the smallest + * value of each partition, as the index of all of the + * partition's values. + */ + for (i = 0; i < ndatums; i++) + { + boundinfo->datums[i] = (Datum *) palloc(sizeof(Datum)); + boundinfo->datums[i][0] = datumCopy(all_values[i]->value, + key->parttypbyval[0], + key->parttyplen[0]); + + /* If the old index has no mapping, assign one */ + if (mapping[all_values[i]->index] == -1) + mapping[all_values[i]->index] = next_index++; + + boundinfo->indexes[i] = mapping[all_values[i]->index]; + } + + /* + * If null-accepting partition has no mapped index yet, + * assign one. This could happen if such partition + * accepts only null and hence not covered in the above + * loop which only handled non-null values. + */ + if (found_null) + { + Assert(null_index >= 0); + if (mapping[null_index] == -1) + mapping[null_index] = next_index++; + } + + /* All partition must now have a valid mapping */ + Assert(next_index == nparts); + + if (found_null) + boundinfo->null_index = mapping[null_index]; + else + boundinfo->null_index = -1; + break; + } + + case PARTITION_STRATEGY_RANGE: + { + boundinfo->content = (RangeDatumContent **) palloc(ndatums * + sizeof(RangeDatumContent *)); + boundinfo->indexes = (int *) palloc((ndatums + 1) * + sizeof(int)); + + for (i = 0; i < ndatums; i++) + { + int j; + + boundinfo->datums[i] = (Datum *) palloc(key->partnatts * + sizeof(Datum)); + boundinfo->content[i] = (RangeDatumContent *) + palloc(key->partnatts * + sizeof(RangeDatumContent)); + for (j = 0; j < key->partnatts; j++) + { + if (rbounds[i]->content[j] == RANGE_DATUM_FINITE) + boundinfo->datums[i][j] = + datumCopy(rbounds[i]->datums[j], + key->parttypbyval[j], + key->parttyplen[j]); + /* Remember, we are storing the tri-state value. */ + boundinfo->content[i][j] = rbounds[i]->content[j]; + } + + /* + * There is no mapping for invalid indexes. + * + * Any lower bounds in the rbounds array have invalid + * indexes assigned, because the values between the + * previous bound (if there is one) and this (lower) + * bound are not part of the range of any existing + * partition. + */ + if (rbounds[i]->lower) + boundinfo->indexes[i] = -1; + else + { + int orig_index = rbounds[i]->index; + + /* If the old index is has no mapping, assign one */ + if (mapping[orig_index] == -1) + mapping[orig_index] = next_index++; + + boundinfo->indexes[i] = mapping[orig_index]; + } + } + boundinfo->indexes[i] = -1; + break; + } + + default: + elog(ERROR, "unexpected partition strategy: %d", + (int) key->strategy); + } + + result->boundinfo = boundinfo; + + /* + * Now assign OIDs from the original array into mapped indexes of the + * result array. Order of OIDs in the former is defined by the + * catalog scan that retrived them, whereas that in the latter is + * defined by canonicalized representation of the list values or the + * range bounds. + */ + for (i = 0; i < nparts; i++) + result->oids[mapping[i]] = oids[i]; + pfree(mapping); + } + + MemoryContextSwitchTo(oldcxt); + rel->rd_partdesc = result; +} + +/* + * Are two partition bound collections logically equal? + * + * Used in the keep logic of relcache.c (ie, in RelationClearRelation()). + * This is also useful when b1 and b2 are bound collections of two separate + * relations, respectively, because PartitionBoundInfo is a canonical + * representation of partition bounds. + */ +bool +partition_bounds_equal(PartitionKey key, + PartitionBoundInfo b1, PartitionBoundInfo b2) +{ + int i; + + if (b1->strategy != b2->strategy) + return false; + + if (b1->ndatums != b2->ndatums) + return false; + + if (b1->has_null != b2->has_null) + return false; + + if (b1->null_index != b2->null_index) + return false; + + for (i = 0; i < b1->ndatums; i++) + { + int j; + + for (j = 0; j < key->partnatts; j++) + { + int32 cmpval; + + /* For range partitions, the bounds might not be finite. */ + if (b1->content != NULL) + { + /* + * A finite bound always differs from an infinite bound, and + * different kinds of infinities differ from each other. + */ + if (b1->content[i][j] != b2->content[i][j]) + return false; + + /* Non-finite bounds are equal without further examination. */ + if (b1->content[i][j] != RANGE_DATUM_FINITE) + continue; + } + + /* Compare the actual values */ + cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[j], + key->partcollation[j], + b1->datums[i][j], + b2->datums[i][j])); + if (cmpval != 0) + return false; + } + + if (b1->indexes[i] != b2->indexes[i]) + return false; + } + + /* There are ndatums+1 indexes in case of range partitions */ + if (key->strategy == PARTITION_STRATEGY_RANGE && + b1->indexes[i] != b2->indexes[i]) + return false; + + return true; +} + +/* + * check_new_partition_bound + * + * Checks if the new partition's bound overlaps any of the existing partitions + * of parent. Also performs additional checks as necessary per strategy. + */ +void +check_new_partition_bound(char *relname, Relation parent, Node *bound) +{ + PartitionBoundSpec *spec = (PartitionBoundSpec *) bound; + PartitionKey key = RelationGetPartitionKey(parent); + PartitionDesc partdesc = RelationGetPartitionDesc(parent); + ParseState *pstate = make_parsestate(NULL); + int with = -1; + bool overlap = false; + + switch (key->strategy) + { + case PARTITION_STRATEGY_LIST: + { + Assert(spec->strategy == PARTITION_STRATEGY_LIST); + + if (partdesc->nparts > 0) + { + PartitionBoundInfo boundinfo = partdesc->boundinfo; + ListCell *cell; + + Assert(boundinfo && + boundinfo->strategy == PARTITION_STRATEGY_LIST && + (boundinfo->ndatums > 0 || boundinfo->has_null)); + + foreach(cell, spec->listdatums) + { + Const *val = lfirst(cell); + + if (!val->constisnull) + { + int offset; + bool equal; + + offset = partition_bound_bsearch(key, boundinfo, + &val->constvalue, + true, &equal); + if (offset >= 0 && equal) + { + overlap = true; + with = boundinfo->indexes[offset]; + break; + } + } + else if (boundinfo->has_null) + { + overlap = true; + with = boundinfo->null_index; + break; + } + } + } + + break; + } + + case PARTITION_STRATEGY_RANGE: + { + PartitionRangeBound *lower, + *upper; + + Assert(spec->strategy == PARTITION_STRATEGY_RANGE); + lower = make_one_range_bound(key, -1, spec->lowerdatums, true); + upper = make_one_range_bound(key, -1, spec->upperdatums, false); + + /* + * First check if the resulting range would be empty with + * specified lower and upper bounds + */ + if (partition_rbound_cmp(key, lower->datums, lower->content, true, + upper) >= 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("cannot create range partition with empty range"), + parser_errposition(pstate, spec->location))); + + if (partdesc->nparts > 0) + { + PartitionBoundInfo boundinfo = partdesc->boundinfo; + int off1, + off2; + bool equal = false; + + Assert(boundinfo && boundinfo->ndatums > 0 && + boundinfo->strategy == PARTITION_STRATEGY_RANGE); + + /* + * Firstly, find the greatest range bound that is less + * than or equal to the new lower bound. + */ + off1 = partition_bound_bsearch(key, boundinfo, lower, true, + &equal); + + /* + * off1 == -1 means that all existing bounds are greater + * than the new lower bound. In that case and the case + * where no partition is defined between the bounds at + * off1 and off1 + 1, we have a "gap" in the range that + * could be occupied by the new partition. We confirm if + * so by checking whether the new upper bound is confined + * within the gap. + */ + if (!equal && boundinfo->indexes[off1 + 1] < 0) + { + off2 = partition_bound_bsearch(key, boundinfo, upper, + true, &equal); + + /* + * If the new upper bound is returned to be equal to + * the bound at off2, the latter must be the upper + * bound of some partition with which the new + * partition clearly overlaps. + * + * Also, if bound at off2 is not same as the one + * returned for the new lower bound (IOW, off1 != + * off2), then the new partition overlaps at least one + * partition. + */ + if (equal || off1 != off2) + { + overlap = true; + + /* + * The bound at off2 could be the lower bound of + * the partition with which the new partition + * overlaps. In that case, use the upper bound + * (that is, the bound at off2 + 1) to get the + * index of that partition. + */ + if (boundinfo->indexes[off2] < 0) + with = boundinfo->indexes[off2 + 1]; + else + with = boundinfo->indexes[off2]; + } + } + else + { + /* + * Equal has been set to true and there is no "gap" + * between the bound at off1 and that at off1 + 1, so + * the new partition will overlap some partition. In + * the former case, the new lower bound is found to be + * equal to the bound at off1, which could only ever + * be true if the latter is the lower bound of some + * partition. It's clear in such a case that the new + * partition overlaps that partition, whose index we + * get using its upper bound (that is, using the bound + * at off1 + 1). + */ + overlap = true; + with = boundinfo->indexes[off1 + 1]; + } + } + + break; + } + + default: + elog(ERROR, "unexpected partition strategy: %d", + (int) key->strategy); + } + + if (overlap) + { + Assert(with >= 0); + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("partition \"%s\" would overlap partition \"%s\"", + relname, get_rel_name(partdesc->oids[with])), + parser_errposition(pstate, spec->location))); + } +} + +/* + * get_partition_parent + * + * Returns inheritance parent of a partition by scanning pg_inherits + * + * Note: Because this function assumes that the relation whose OID is passed + * as an argument will have precisely one parent, it should only be called + * when it is known that the relation is a partition. + */ +Oid +get_partition_parent(Oid relid) +{ + Form_pg_inherits form; + Relation catalogRelation; + SysScanDesc scan; + ScanKeyData key[2]; + HeapTuple tuple; + Oid result; + + catalogRelation = heap_open(InheritsRelationId, AccessShareLock); + + ScanKeyInit(&key[0], + Anum_pg_inherits_inhrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(relid)); + ScanKeyInit(&key[1], + Anum_pg_inherits_inhseqno, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(1)); + + scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, true, + NULL, 2, key); + + tuple = systable_getnext(scan); + Assert(HeapTupleIsValid(tuple)); + + form = (Form_pg_inherits) GETSTRUCT(tuple); + result = form->inhparent; + + systable_endscan(scan); + heap_close(catalogRelation, AccessShareLock); + + return result; +} + +/* + * get_qual_from_partbound + * Given a parser node for partition bound, return the list of executable + * expressions as partition constraint + */ +List * +get_qual_from_partbound(Relation rel, Relation parent, Node *bound) +{ + PartitionBoundSpec *spec = (PartitionBoundSpec *) bound; + PartitionKey key = RelationGetPartitionKey(parent); + List *my_qual = NIL; + + Assert(key != NULL); + + switch (key->strategy) + { + case PARTITION_STRATEGY_LIST: + Assert(spec->strategy == PARTITION_STRATEGY_LIST); + my_qual = get_qual_for_list(key, spec); + break; + + case PARTITION_STRATEGY_RANGE: + Assert(spec->strategy == PARTITION_STRATEGY_RANGE); + my_qual = get_qual_for_range(key, spec); + break; + + default: + elog(ERROR, "unexpected partition strategy: %d", + (int) key->strategy); + } + + return my_qual; +} + +/* + * map_partition_varattnos - maps varattno of any Vars in expr from the + * parent attno to partition attno. + * + * We must allow for a case where physical attnos of a partition can be + * different from the parent's. + */ +List * +map_partition_varattnos(List *expr, int target_varno, + Relation partrel, Relation parent) +{ + AttrNumber *part_attnos; + bool found_whole_row; + + if (expr == NIL) + return NIL; + + part_attnos = convert_tuples_by_name_map(RelationGetDescr(partrel), + RelationGetDescr(parent), + gettext_noop("could not convert row type")); + expr = (List *) map_variable_attnos((Node *) expr, + target_varno, 0, + part_attnos, + RelationGetDescr(parent)->natts, + &found_whole_row); + /* There can never be a whole-row reference here */ + if (found_whole_row) + elog(ERROR, "unexpected whole-row reference found in partition key"); + + return expr; +} + +/* + * RelationGetPartitionQual + * + * Returns a list of partition quals + */ +List * +RelationGetPartitionQual(Relation rel) +{ + /* Quick exit */ + if (!rel->rd_rel->relispartition) + return NIL; + + return generate_partition_qual(rel); +} + +/* + * Append OIDs of rel's partitions to the list 'partoids' and for each OID, + * append pointer rel to the list 'parents'. + */ +#define APPEND_REL_PARTITION_OIDS(rel, partoids, parents) \ + do\ + {\ + int i;\ + for (i = 0; i < (rel)->rd_partdesc->nparts; i++)\ + {\ + (partoids) = lappend_oid((partoids), (rel)->rd_partdesc->oids[i]);\ + (parents) = lappend((parents), (rel));\ + }\ + } while(0) + +/* + * RelationGetPartitionDispatchInfo + * Returns information necessary to route tuples down a partition tree + * + * All the partitions will be locked with lockmode, unless it is NoLock. + * A list of the OIDs of all the leaf partition of rel is returned in + * *leaf_part_oids. + */ +PartitionDispatch * +RelationGetPartitionDispatchInfo(Relation rel, int lockmode, + int *num_parted, List **leaf_part_oids) +{ + PartitionDispatchData **pd; + List *all_parts = NIL, + *all_parents = NIL, + *parted_rels, + *parted_rel_parents; + ListCell *lc1, + *lc2; + int i, + k, + offset; + + /* + * Lock partitions and make a list of the partitioned ones to prepare + * their PartitionDispatch objects below. + * + * Cannot use find_all_inheritors() here, because then the order of OIDs + * in parted_rels list would be unknown, which does not help, because we + * we assign indexes within individual PartitionDispatch in an order that + * is predetermined (determined by the order of OIDs in individual + * partition descriptors). + */ + *num_parted = 1; + parted_rels = list_make1(rel); + /* Root partitioned table has no parent, so NULL for parent */ + parted_rel_parents = list_make1(NULL); + APPEND_REL_PARTITION_OIDS(rel, all_parts, all_parents); + forboth(lc1, all_parts, lc2, all_parents) + { + Relation partrel = heap_open(lfirst_oid(lc1), lockmode); + Relation parent = lfirst(lc2); + PartitionDesc partdesc = RelationGetPartitionDesc(partrel); + + /* + * If this partition is a partitioned table, add its children to the + * end of the list, so that they are processed as well. + */ + if (partdesc) + { + (*num_parted)++; + parted_rels = lappend(parted_rels, partrel); + parted_rel_parents = lappend(parted_rel_parents, parent); + APPEND_REL_PARTITION_OIDS(partrel, all_parts, all_parents); + } + else + heap_close(partrel, NoLock); + + /* + * We keep the partitioned ones open until we're done using the + * information being collected here (for example, see + * ExecEndModifyTable). + */ + } + + /* + * We want to create two arrays - one for leaf partitions and another for + * partitioned tables (including the root table and internal partitions). + * While we only create the latter here, leaf partition array of suitable + * objects (such as, ResultRelInfo) is created by the caller using the + * list of OIDs we return. Indexes into these arrays get assigned in a + * breadth-first manner, whereby partitions of any given level are placed + * consecutively in the respective arrays. + */ + pd = (PartitionDispatchData **) palloc(*num_parted * + sizeof(PartitionDispatchData *)); + *leaf_part_oids = NIL; + i = k = offset = 0; + forboth(lc1, parted_rels, lc2, parted_rel_parents) + { + Relation partrel = lfirst(lc1); + Relation parent = lfirst(lc2); + PartitionKey partkey = RelationGetPartitionKey(partrel); + TupleDesc tupdesc = RelationGetDescr(partrel); + PartitionDesc partdesc = RelationGetPartitionDesc(partrel); + int j, + m; + + pd[i] = (PartitionDispatch) palloc(sizeof(PartitionDispatchData)); + pd[i]->reldesc = partrel; + pd[i]->key = partkey; + pd[i]->keystate = NIL; + pd[i]->partdesc = partdesc; + if (parent != NULL) + { + /* + * For every partitioned table other than root, we must store + * a tuple table slot initialized with its tuple descriptor and + * a tuple conversion map to convert a tuple from its parent's + * rowtype to its own. That is to make sure that we are looking + * at the correct row using the correct tuple descriptor when + * computing its partition key for tuple routing. + */ + pd[i]->tupslot = MakeSingleTupleTableSlot(tupdesc); + pd[i]->tupmap = convert_tuples_by_name(RelationGetDescr(parent), + tupdesc, + gettext_noop("could not convert row type")); + } + else + { + /* Not required for the root partitioned table */ + pd[i]->tupslot = NULL; + pd[i]->tupmap = NULL; + } + pd[i]->indexes = (int *) palloc(partdesc->nparts * sizeof(int)); + + /* + * Indexes corresponding to the internal partitions are multiplied by + * -1 to distinguish them from those of leaf partitions. Encountering + * an index >= 0 means we found a leaf partition, which is immediately + * returned as the partition we are looking for. A negative index + * means we found a partitioned table, whose PartitionDispatch object + * is located at the above index multiplied back by -1. Using the + * PartitionDispatch object, search is continued further down the + * partition tree. + */ + m = 0; + for (j = 0; j < partdesc->nparts; j++) + { + Oid partrelid = partdesc->oids[j]; + + if (get_rel_relkind(partrelid) != RELKIND_PARTITIONED_TABLE) + { + *leaf_part_oids = lappend_oid(*leaf_part_oids, partrelid); + pd[i]->indexes[j] = k++; + } + else + { + /* + * offset denotes the number of partitioned tables of upper + * levels including those of the current level. Any partition + * of this table must belong to the next level and hence will + * be placed after the last partitioned table of this level. + */ + pd[i]->indexes[j] = -(1 + offset + m); + m++; + } + } + i++; + + /* + * This counts the number of partitioned tables at upper levels + * including those of the current level. + */ + offset += m; + } + + return pd; +} + +/* Module-local functions */ + +/* + * get_qual_for_list + * + * Returns a list of expressions to use as a list partition's constraint. + */ +static List * +get_qual_for_list(PartitionKey key, PartitionBoundSpec *spec) +{ + List *result; + ArrayExpr *arr; + ScalarArrayOpExpr *opexpr; + ListCell *cell, + *prev, + *next; + Node *keyCol; + Oid operoid; + bool need_relabel, + list_has_null = false; + NullTest *nulltest1 = NULL, + *nulltest2 = NULL; + + /* Left operand is either a simple Var or arbitrary expression */ + if (key->partattrs[0] != 0) + keyCol = (Node *) makeVar(1, + key->partattrs[0], + key->parttypid[0], + key->parttypmod[0], + key->parttypcoll[0], + 0); + else + keyCol = (Node *) copyObject(linitial(key->partexprs)); + + /* + * We must remove any NULL value in the list; we handle it separately + * below. + */ + prev = NULL; + for (cell = list_head(spec->listdatums); cell; cell = next) + { + Const *val = (Const *) lfirst(cell); + + next = lnext(cell); + + if (val->constisnull) + { + list_has_null = true; + spec->listdatums = list_delete_cell(spec->listdatums, + cell, prev); + } + else + prev = cell; + } + + if (!list_has_null) + { + /* + * Gin up a col IS NOT NULL test that will be AND'd with other + * expressions + */ + nulltest1 = makeNode(NullTest); + nulltest1->arg = (Expr *) keyCol; + nulltest1->nulltesttype = IS_NOT_NULL; + nulltest1->argisrow = false; + nulltest1->location = -1; + } + else + { + /* + * Gin up a col IS NULL test that will be OR'd with other expressions + */ + nulltest2 = makeNode(NullTest); + nulltest2->arg = (Expr *) keyCol; + nulltest2->nulltesttype = IS_NULL; + nulltest2->argisrow = false; + nulltest2->location = -1; + } + + /* Right operand is an ArrayExpr containing this partition's values */ + arr = makeNode(ArrayExpr); + arr->array_typeid = !type_is_array(key->parttypid[0]) + ? get_array_type(key->parttypid[0]) + : key->parttypid[0]; + arr->array_collid = key->parttypcoll[0]; + arr->element_typeid = key->parttypid[0]; + arr->elements = spec->listdatums; + arr->multidims = false; + arr->location = -1; + + /* Get the correct btree equality operator */ + operoid = get_partition_operator(key, 0, BTEqualStrategyNumber, + &need_relabel); + if (need_relabel || key->partcollation[0] != key->parttypcoll[0]) + keyCol = (Node *) makeRelabelType((Expr *) keyCol, + key->partopcintype[0], + -1, + key->partcollation[0], + COERCE_EXPLICIT_CAST); + + /* Build leftop = ANY (rightop) */ + opexpr = makeNode(ScalarArrayOpExpr); + opexpr->opno = operoid; + opexpr->opfuncid = get_opcode(operoid); + opexpr->useOr = true; + opexpr->inputcollid = key->partcollation[0]; + opexpr->args = list_make2(keyCol, arr); + opexpr->location = -1; + + if (nulltest1) + result = list_make2(nulltest1, opexpr); + else if (nulltest2) + { + Expr *or; + + or = makeBoolExpr(OR_EXPR, list_make2(nulltest2, opexpr), -1); + result = list_make1(or); + } + else + result = list_make1(opexpr); + + return result; +} + +/* + * get_qual_for_range + * + * Get a list of OpExpr's to use as a range partition's constraint. + */ +static List * +get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec) +{ + List *result = NIL; + ListCell *cell1, + *cell2, + *partexprs_item; + int i; + + /* + * Iterate over columns of the key, emitting an OpExpr for each using the + * corresponding lower and upper datums as constant operands. + */ + i = 0; + partexprs_item = list_head(key->partexprs); + forboth(cell1, spec->lowerdatums, cell2, spec->upperdatums) + { + PartitionRangeDatum *ldatum = lfirst(cell1), + *udatum = lfirst(cell2); + Node *keyCol; + Const *lower_val = NULL, + *upper_val = NULL; + EState *estate; + MemoryContext oldcxt; + Expr *test_expr; + ExprState *test_exprstate; + Datum test_result; + bool isNull; + bool need_relabel = false; + Oid operoid; + NullTest *nulltest; + + /* Left operand */ + if (key->partattrs[i] != 0) + { + keyCol = (Node *) makeVar(1, + key->partattrs[i], + key->parttypid[i], + key->parttypmod[i], + key->parttypcoll[i], + 0); + } + else + { + keyCol = (Node *) copyObject(lfirst(partexprs_item)); + partexprs_item = lnext(partexprs_item); + } + + /* + * Emit a IS NOT NULL expression for non-Var keys, because whereas + * simple attributes are covered by NOT NULL constraints, expression + * keys are still nullable which is not acceptable in case of range + * partitioning. + */ + if (!IsA(keyCol, Var)) + { + nulltest = makeNode(NullTest); + nulltest->arg = (Expr *) keyCol; + nulltest->nulltesttype = IS_NOT_NULL; + nulltest->argisrow = false; + nulltest->location = -1; + result = lappend(result, nulltest); + } + + /* + * Stop at this column if either of lower or upper datum is infinite, + * but do emit an OpExpr for the non-infinite datum. + */ + if (!ldatum->infinite) + lower_val = (Const *) ldatum->value; + if (!udatum->infinite) + upper_val = (Const *) udatum->value; + + /* + * If lower_val and upper_val are both finite and happen to be equal, + * emit only (keyCol = lower_val) for this column, because all rows in + * this partition could only ever contain this value (ie, lower_val) + * in the current partitioning column. We must consider further + * columns because the above condition does not fully constrain the + * rows of this partition. + */ + if (lower_val && upper_val) + { + /* Get the correct btree equality operator for the test */ + operoid = get_partition_operator(key, i, BTEqualStrategyNumber, + &need_relabel); + + /* Create the test expression */ + estate = CreateExecutorState(); + oldcxt = MemoryContextSwitchTo(estate->es_query_cxt); + test_expr = make_opclause(operoid, + BOOLOID, + false, + (Expr *) lower_val, + (Expr *) upper_val, + InvalidOid, + key->partcollation[i]); + fix_opfuncids((Node *) test_expr); + test_exprstate = ExecInitExpr(test_expr, NULL); + test_result = ExecEvalExprSwitchContext(test_exprstate, + GetPerTupleExprContext(estate), + &isNull); + MemoryContextSwitchTo(oldcxt); + FreeExecutorState(estate); + + if (DatumGetBool(test_result)) + { + /* This can never be, but it's better to make sure */ + if (i == key->partnatts - 1) + elog(ERROR, "invalid range bound specification"); + + if (need_relabel || key->partcollation[i] != key->parttypcoll[i]) + keyCol = (Node *) makeRelabelType((Expr *) keyCol, + key->partopcintype[i], + -1, + key->partcollation[i], + COERCE_EXPLICIT_CAST); + result = lappend(result, + make_opclause(operoid, + BOOLOID, + false, + (Expr *) keyCol, + (Expr *) lower_val, + InvalidOid, + key->partcollation[i])); + + /* Go over to consider the next column. */ + i++; + continue; + } + } + + /* + * We can say here that lower_val != upper_val. Emit expressions + * (keyCol >= lower_val) and (keyCol < upper_val), then stop. + */ + if (lower_val) + { + operoid = get_partition_operator(key, i, + BTGreaterEqualStrategyNumber, + &need_relabel); + + if (need_relabel || key->partcollation[i] != key->parttypcoll[i]) + keyCol = (Node *) makeRelabelType((Expr *) keyCol, + key->partopcintype[i], + -1, + key->partcollation[i], + COERCE_EXPLICIT_CAST); + result = lappend(result, + make_opclause(operoid, + BOOLOID, + false, + (Expr *) keyCol, + (Expr *) lower_val, + InvalidOid, + key->partcollation[i])); + } + + if (upper_val) + { + operoid = get_partition_operator(key, i, + BTLessStrategyNumber, + &need_relabel); + + if (need_relabel || key->partcollation[i] != key->parttypcoll[i]) + keyCol = (Node *) makeRelabelType((Expr *) keyCol, + key->partopcintype[i], + -1, + key->partcollation[i], + COERCE_EXPLICIT_CAST); + + result = lappend(result, + make_opclause(operoid, + BOOLOID, + false, + (Expr *) keyCol, + (Expr *) upper_val, + InvalidOid, + key->partcollation[i])); + } + + /* + * We can stop at this column, because we would not have checked the + * next column when routing a given row into this partition. + */ + break; + } + + return result; +} + +/* + * get_partition_operator + * + * Return oid of the operator of given strategy for a given partition key + * column. + */ +static Oid +get_partition_operator(PartitionKey key, int col, StrategyNumber strategy, + bool *need_relabel) +{ + Oid operoid; + + /* + * First check if there exists an operator of the given strategy, with + * this column's type as both its lefttype and righttype, in the + * partitioning operator family specified for the column. + */ + operoid = get_opfamily_member(key->partopfamily[col], + key->parttypid[col], + key->parttypid[col], + strategy); + + /* + * If one doesn't exist, we must resort to using an operator in the same + * opreator family but with the operator class declared input type. It is + * OK to do so, because the column's type is known to be binary-coercible + * with the operator class input type (otherwise, the operator class in + * question would not have been accepted as the partitioning operator + * class). We must however inform the caller to wrap the non-Const + * expression with a RelabelType node to denote the implicit coercion. It + * ensures that the resulting expression structurally matches similarly + * processed expressions within the optimizer. + */ + if (!OidIsValid(operoid)) + { + operoid = get_opfamily_member(key->partopfamily[col], + key->partopcintype[col], + key->partopcintype[col], + strategy); + *need_relabel = true; + } + else + *need_relabel = false; + + if (!OidIsValid(operoid)) + elog(ERROR, "could not find operator for partitioning"); + + return operoid; +} + +/* + * generate_partition_qual + * + * Generate partition predicate from rel's partition bound expression + * + * Result expression tree is stored CacheMemoryContext to ensure it survives + * as long as the relcache entry. But we should be running in a less long-lived + * working context. To avoid leaking cache memory if this routine fails partway + * through, we build in working memory and then copy the completed structure + * into cache memory. + */ +static List * +generate_partition_qual(Relation rel) +{ + HeapTuple tuple; + MemoryContext oldcxt; + Datum boundDatum; + bool isnull; + Node *bound; + List *my_qual = NIL, + *result = NIL; + Relation parent; + + /* Guard against stack overflow due to overly deep partition tree */ + check_stack_depth(); + + /* Quick copy */ + if (rel->rd_partcheck != NIL) + return copyObject(rel->rd_partcheck); + + /* Grab at least an AccessShareLock on the parent table */ + parent = heap_open(get_partition_parent(RelationGetRelid(rel)), + AccessShareLock); + + /* Get pg_class.relpartbound */ + tuple = SearchSysCache1(RELOID, RelationGetRelid(rel)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation %u", + RelationGetRelid(rel)); + + boundDatum = SysCacheGetAttr(RELOID, tuple, + Anum_pg_class_relpartbound, + &isnull); + if (isnull) /* should not happen */ + elog(ERROR, "relation \"%s\" has relpartbound = null", + RelationGetRelationName(rel)); + bound = stringToNode(TextDatumGetCString(boundDatum)); + ReleaseSysCache(tuple); + + my_qual = get_qual_from_partbound(rel, parent, bound); + + /* Add the parent's quals to the list (if any) */ + if (parent->rd_rel->relispartition) + result = list_concat(generate_partition_qual(parent), my_qual); + else + result = my_qual; + + /* + * Change Vars to have partition's attnos instead of the parent's. + * We do this after we concatenate the parent's quals, because + * we want every Var in it to bear this relation's attnos. + * It's safe to assume varno = 1 here. + */ + result = map_partition_varattnos(result, 1, rel, parent); + + /* Save a copy in the relcache */ + oldcxt = MemoryContextSwitchTo(CacheMemoryContext); + rel->rd_partcheck = copyObject(result); + MemoryContextSwitchTo(oldcxt); + + /* Keep the parent locked until commit */ + heap_close(parent, NoLock); + + return result; +} + +/* ---------------- + * FormPartitionKeyDatum + * Construct values[] and isnull[] arrays for the partition key + * of a tuple. + * + * pd Partition dispatch object of the partitioned table + * slot Heap tuple from which to extract partition key + * estate executor state for evaluating any partition key + * expressions (must be non-NULL) + * values Array of partition key Datums (output area) + * isnull Array of is-null indicators (output area) + * + * the ecxt_scantuple slot of estate's per-tuple expr context must point to + * the heap tuple passed in. + * ---------------- + */ +static void +FormPartitionKeyDatum(PartitionDispatch pd, + TupleTableSlot *slot, + EState *estate, + Datum *values, + bool *isnull) +{ + ListCell *partexpr_item; + int i; + + if (pd->key->partexprs != NIL && pd->keystate == NIL) + { + /* Check caller has set up context correctly */ + Assert(estate != NULL && + GetPerTupleExprContext(estate)->ecxt_scantuple == slot); + + /* First time through, set up expression evaluation state */ + pd->keystate = (List *) ExecPrepareExpr((Expr *) pd->key->partexprs, + estate); + } + + partexpr_item = list_head(pd->keystate); + for (i = 0; i < pd->key->partnatts; i++) + { + AttrNumber keycol = pd->key->partattrs[i]; + Datum datum; + bool isNull; + + if (keycol != 0) + { + /* Plain column; get the value directly from the heap tuple */ + datum = slot_getattr(slot, keycol, &isNull); + } + else + { + /* Expression; need to evaluate it */ + if (partexpr_item == NULL) + elog(ERROR, "wrong number of partition key expressions"); + datum = ExecEvalExprSwitchContext((ExprState *) lfirst(partexpr_item), + GetPerTupleExprContext(estate), + &isNull); + partexpr_item = lnext(partexpr_item); + } + values[i] = datum; + isnull[i] = isNull; + } + + if (partexpr_item != NULL) + elog(ERROR, "wrong number of partition key expressions"); +} + +/* + * get_partition_for_tuple + * Finds a leaf partition for tuple contained in *slot + * + * Returned value is the sequence number of the leaf partition thus found, + * or -1 if no leaf partition is found for the tuple. *failed_at is set + * to the OID of the partitioned table whose partition was not found in + * the latter case. + */ +int +get_partition_for_tuple(PartitionDispatch *pd, + TupleTableSlot *slot, + EState *estate, + Oid *failed_at) +{ + PartitionDispatch parent; + Datum values[PARTITION_MAX_KEYS]; + bool isnull[PARTITION_MAX_KEYS]; + int cur_offset, + cur_index; + int i; + + /* start with the root partitioned table */ + parent = pd[0]; + while (true) + { + PartitionKey key = parent->key; + PartitionDesc partdesc = parent->partdesc; + TupleTableSlot *myslot = parent->tupslot; + TupleConversionMap *map = parent->tupmap; + + /* Quick exit */ + if (partdesc->nparts == 0) + { + *failed_at = RelationGetRelid(parent->reldesc); + return -1; + } + + if (myslot != NULL) + { + HeapTuple tuple = ExecFetchSlotTuple(slot); + + ExecClearTuple(myslot); + Assert(map != NULL); + tuple = do_convert_tuple(tuple, map); + ExecStoreTuple(tuple, myslot, InvalidBuffer, true); + slot = myslot; + } + + /* Extract partition key from tuple */ + FormPartitionKeyDatum(parent, slot, estate, values, isnull); + + if (key->strategy == PARTITION_STRATEGY_RANGE) + { + /* Disallow nulls in the range partition key of the tuple */ + for (i = 0; i < key->partnatts; i++) + if (isnull[i]) + ereport(ERROR, + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("range partition key of row contains null"))); + } + + if (partdesc->boundinfo->has_null && isnull[0]) + /* Tuple maps to the null-accepting list partition */ + cur_index = partdesc->boundinfo->null_index; + else + { + /* Else bsearch in partdesc->boundinfo */ + bool equal = false; + + cur_offset = partition_bound_bsearch(key, partdesc->boundinfo, + values, false, &equal); + switch (key->strategy) + { + case PARTITION_STRATEGY_LIST: + if (cur_offset >= 0 && equal) + cur_index = partdesc->boundinfo->indexes[cur_offset]; + else + cur_index = -1; + break; + + case PARTITION_STRATEGY_RANGE: + + /* + * Offset returned is such that the bound at offset is + * found to be less or equal with the tuple. So, the bound + * at offset+1 would be the upper bound. + */ + cur_index = partdesc->boundinfo->indexes[cur_offset + 1]; + break; + + default: + elog(ERROR, "unexpected partition strategy: %d", + (int) key->strategy); + } + } + + /* + * cur_index < 0 means we failed to find a partition of this parent. + * cur_index >= 0 means we either found the leaf partition, or the + * next parent to find a partition of. + */ + if (cur_index < 0) + { + *failed_at = RelationGetRelid(parent->reldesc); + return -1; + } + else if (parent->indexes[cur_index] < 0) + parent = pd[-parent->indexes[cur_index]]; + else + break; + } + + return parent->indexes[cur_index]; +} + +/* + * qsort_partition_list_value_cmp + * + * Compare two list partition bound datums + */ +static int32 +qsort_partition_list_value_cmp(const void *a, const void *b, void *arg) +{ + Datum val1 = (*(const PartitionListValue **) a)->value, + val2 = (*(const PartitionListValue **) b)->value; + PartitionKey key = (PartitionKey) arg; + + return DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[0], + key->partcollation[0], + val1, val2)); +} + +/* + * make_one_range_bound + * + * Return a PartitionRangeBound given a list of PartitionRangeDatum elements + * and a flag telling whether the bound is lower or not. Made into a function + * because there are multiple sites that want to use this facility. + */ +static PartitionRangeBound * +make_one_range_bound(PartitionKey key, int index, List *datums, bool lower) +{ + PartitionRangeBound *bound; + ListCell *cell; + int i; + + bound = (PartitionRangeBound *) palloc0(sizeof(PartitionRangeBound)); + bound->index = index; + bound->datums = (Datum *) palloc0(key->partnatts * sizeof(Datum)); + bound->content = (RangeDatumContent *) palloc0(key->partnatts * + sizeof(RangeDatumContent)); + bound->lower = lower; + + i = 0; + foreach(cell, datums) + { + PartitionRangeDatum *datum = lfirst(cell); + + /* What's contained in this range datum? */ + bound->content[i] = !datum->infinite + ? RANGE_DATUM_FINITE + : (lower ? RANGE_DATUM_NEG_INF + : RANGE_DATUM_POS_INF); + + if (bound->content[i] == RANGE_DATUM_FINITE) + { + Const *val = (Const *) datum->value; + + if (val->constisnull) + elog(ERROR, "invalid range bound datum"); + bound->datums[i] = val->constvalue; + } + + i++; + } + + return bound; +} + +/* Used when sorting range bounds across all range partitions */ +static int32 +qsort_partition_rbound_cmp(const void *a, const void *b, void *arg) +{ + PartitionRangeBound *b1 = (*(PartitionRangeBound *const *) a); + PartitionRangeBound *b2 = (*(PartitionRangeBound *const *) b); + PartitionKey key = (PartitionKey) arg; + + return partition_rbound_cmp(key, b1->datums, b1->content, b1->lower, b2); +} + +/* + * partition_rbound_cmp + * + * Return for two range bounds whether the 1st one (specified in datum1, + * content1, and lower1) is <=, =, >= the bound specified in *b2 + */ +static int32 +partition_rbound_cmp(PartitionKey key, + Datum *datums1, RangeDatumContent *content1, bool lower1, + PartitionRangeBound *b2) +{ + int32 cmpval = 0; /* placate compiler */ + int i; + Datum *datums2 = b2->datums; + RangeDatumContent *content2 = b2->content; + bool lower2 = b2->lower; + + for (i = 0; i < key->partnatts; i++) + { + /* + * First, handle cases involving infinity, which don't require + * invoking the comparison proc. + */ + if (content1[i] != RANGE_DATUM_FINITE && + content2[i] != RANGE_DATUM_FINITE) + + /* + * Both are infinity, so they are equal unless one is negative + * infinity and other positive (or vice versa) + */ + return content1[i] == content2[i] ? 0 + : (content1[i] < content2[i] ? -1 : 1); + else if (content1[i] != RANGE_DATUM_FINITE) + return content1[i] == RANGE_DATUM_NEG_INF ? -1 : 1; + else if (content2[i] != RANGE_DATUM_FINITE) + return content2[i] == RANGE_DATUM_NEG_INF ? 1 : -1; + + cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[i], + key->partcollation[i], + datums1[i], + datums2[i])); + if (cmpval != 0) + break; + } + + /* + * If the comparison is anything other than equal, we're done. If they + * compare equal though, we still have to consider whether the boundaries + * are inclusive or exclusive. Exclusive one is considered smaller of the + * two. + */ + if (cmpval == 0 && lower1 != lower2) + cmpval = lower1 ? 1 : -1; + + return cmpval; +} + +/* + * partition_rbound_datum_cmp + * + * Return whether range bound (specified in rb_datums, rb_content, and + * rb_lower) <=, =, >= partition key of tuple (tuple_datums) + */ +static int32 +partition_rbound_datum_cmp(PartitionKey key, + Datum *rb_datums, RangeDatumContent *rb_content, + Datum *tuple_datums) +{ + int i; + int32 cmpval = -1; + + for (i = 0; i < key->partnatts; i++) + { + if (rb_content[i] != RANGE_DATUM_FINITE) + return rb_content[i] == RANGE_DATUM_NEG_INF ? -1 : 1; + + cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[i], + key->partcollation[i], + rb_datums[i], + tuple_datums[i])); + if (cmpval != 0) + break; + } + + return cmpval; +} + +/* + * partition_bound_cmp + * + * Return whether the bound at offset in boundinfo is <=, =, >= the argument + * specified in *probe. + */ +static int32 +partition_bound_cmp(PartitionKey key, PartitionBoundInfo boundinfo, + int offset, void *probe, bool probe_is_bound) +{ + Datum *bound_datums = boundinfo->datums[offset]; + int32 cmpval = -1; + + switch (key->strategy) + { + case PARTITION_STRATEGY_LIST: + cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[0], + key->partcollation[0], + bound_datums[0], + *(Datum *) probe)); + break; + + case PARTITION_STRATEGY_RANGE: + { + RangeDatumContent *content = boundinfo->content[offset]; + + if (probe_is_bound) + { + /* + * We need to pass whether the existing bound is a lower + * bound, so that two equal-valued lower and upper bounds + * are not regarded equal. + */ + bool lower = boundinfo->indexes[offset] < 0; + + cmpval = partition_rbound_cmp(key, + bound_datums, content, lower, + (PartitionRangeBound *) probe); + } + else + cmpval = partition_rbound_datum_cmp(key, + bound_datums, content, + (Datum *) probe); + break; + } + + default: + elog(ERROR, "unexpected partition strategy: %d", + (int) key->strategy); + } + + return cmpval; +} + +/* + * Binary search on a collection of partition bounds. Returns greatest + * bound in array boundinfo->datums which is less than or equal to *probe + * If all bounds in the array are greater than *probe, -1 is returned. + * + * *probe could either be a partition bound or a Datum array representing + * the partition key of a tuple being routed; probe_is_bound tells which. + * We pass that down to the comparison function so that it can interpret the + * contents of *probe accordingly. + * + * *is_equal is set to whether the bound at the returned index is equal with + * *probe. + */ +static int +partition_bound_bsearch(PartitionKey key, PartitionBoundInfo boundinfo, + void *probe, bool probe_is_bound, bool *is_equal) +{ + int lo, + hi, + mid; + + lo = -1; + hi = boundinfo->ndatums - 1; + while (lo < hi) + { + int32 cmpval; + + mid = (lo + hi + 1) / 2; + cmpval = partition_bound_cmp(key, boundinfo, mid, probe, + probe_is_bound); + if (cmpval <= 0) + { + lo = mid; + *is_equal = (cmpval == 0); + + if (*is_equal) + break; + } + else + hi = mid - 1; + } + + return lo; +} diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c index 959d3845df..3a4e22f0d6 100644 --- a/src/backend/catalog/pg_aggregate.c +++ b/src/backend/catalog/pg_aggregate.c @@ -3,7 +3,7 @@ * pg_aggregate.c * routines to support manipulation of the pg_aggregate relation * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/pg_collation.c b/src/backend/catalog/pg_collation.c index f37cf37c4a..694c0f67f5 100644 --- a/src/backend/catalog/pg_collation.c +++ b/src/backend/catalog/pg_collation.c @@ -3,7 +3,7 @@ * pg_collation.c * routines to support manipulation of the pg_collation relation * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -41,7 +41,8 @@ Oid CollationCreate(const char *collname, Oid collnamespace, Oid collowner, int32 collencoding, - const char *collcollate, const char *collctype) + const char *collcollate, const char *collctype, + bool if_not_exists) { Relation rel; TupleDesc tupDesc; @@ -72,10 +73,21 @@ CollationCreate(const char *collname, Oid collnamespace, PointerGetDatum(collname), Int32GetDatum(collencoding), ObjectIdGetDatum(collnamespace))) - ereport(ERROR, + { + if (if_not_exists) + { + ereport(NOTICE, (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("collation \"%s\" for encoding \"%s\" already exists", + errmsg("collation \"%s\" for encoding \"%s\" already exists, skipping", collname, pg_encoding_to_char(collencoding)))); + return InvalidOid; + } + else + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("collation \"%s\" for encoding \"%s\" already exists", + collname, pg_encoding_to_char(collencoding)))); + } /* * Also forbid matching an any-encoding entry. This test of course is not @@ -86,10 +98,21 @@ CollationCreate(const char *collname, Oid collnamespace, PointerGetDatum(collname), Int32GetDatum(-1), ObjectIdGetDatum(collnamespace))) - ereport(ERROR, + { + if (if_not_exists) + { + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("collation \"%s\" already exists, skipping", + collname))); + return InvalidOid; + } + else + ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("collation \"%s\" already exists", collname))); + } /* open pg_collation */ rel = heap_open(CollationRelationId, RowExclusiveLock); diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c index 8fabe6899f..b5a0ce95c1 100644 --- a/src/backend/catalog/pg_constraint.c +++ b/src/backend/catalog/pg_constraint.c @@ -3,7 +3,7 @@ * pg_constraint.c * routines to support manipulation of the pg_constraint relation * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -368,7 +368,7 @@ CreateConstraintEntry(const char *constraintName, */ recordDependencyOnSingleRelExpr(&conobject, conExpr, relId, DEPENDENCY_NORMAL, - DEPENDENCY_NORMAL); + DEPENDENCY_NORMAL, false); } /* Post creation hook for new constraint */ diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c index e2feb1709c..adaf7b8ee6 100644 --- a/src/backend/catalog/pg_conversion.c +++ b/src/backend/catalog/pg_conversion.c @@ -3,7 +3,7 @@ * pg_conversion.c * routines to support manipulation of the pg_conversion relation * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/pg_db_role_setting.c b/src/backend/catalog/pg_db_role_setting.c index 9414ede961..117cc8d1eb 100644 --- a/src/backend/catalog/pg_db_role_setting.c +++ b/src/backend/catalog/pg_db_role_setting.c @@ -2,7 +2,7 @@ * pg_db_role_setting.c * Routines to support manipulation of the pg_db_role_setting relation * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c index 7a0713e6cc..b71fa1b981 100644 --- a/src/backend/catalog/pg_depend.c +++ b/src/backend/catalog/pg_depend.c @@ -3,7 +3,7 @@ * pg_depend.c * routines to support manipulation of the pg_depend relation * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/pg_enum.c b/src/backend/catalog/pg_enum.c index af89daa712..089a9a0a65 100644 --- a/src/backend/catalog/pg_enum.c +++ b/src/backend/catalog/pg_enum.c @@ -3,7 +3,7 @@ * pg_enum.c * routines to support manipulation of the pg_enum relation * - * Copyright (c) 2006-2016, PostgreSQL Global Development Group + * Copyright (c) 2006-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -24,6 +24,7 @@ #include "catalog/pg_type.h" #include "storage/lmgr.h" #include "miscadmin.h" +#include "nodes/value.h" #include "utils/builtins.h" #include "utils/catcache.h" #include "utils/fmgroids.h" @@ -315,21 +316,21 @@ AddEnumLabel(Oid enumTypeOid, newelemorder = nbr_en->enumsortorder + 1; else { - other_nbr_en = (Form_pg_enum) GETSTRUCT(existing[other_nbr_index]); - newelemorder = (nbr_en->enumsortorder + - other_nbr_en->enumsortorder) / 2; - /* - * On some machines, newelemorder may be in a register that's - * wider than float4. We need to force it to be rounded to float4 - * precision before making the following comparisons, or we'll get - * wrong results. (Such behavior violates the C standard, but - * fixing the compilers is out of our reach.) + * The midpoint value computed here has to be rounded to float4 + * precision, else our equality comparisons against the adjacent + * values are meaningless. The most portable way of forcing that + * to happen with non-C-standard-compliant compilers is to store + * it into a volatile variable. */ - newelemorder = DatumGetFloat4(Float4GetDatum(newelemorder)); + volatile float4 midpoint; + + other_nbr_en = (Form_pg_enum) GETSTRUCT(existing[other_nbr_index]); + midpoint = (nbr_en->enumsortorder + + other_nbr_en->enumsortorder) / 2; - if (newelemorder == nbr_en->enumsortorder || - newelemorder == other_nbr_en->enumsortorder) + if (midpoint == nbr_en->enumsortorder || + midpoint == other_nbr_en->enumsortorder) { RenumberEnumType(pg_enum, existing, nelems); /* Clean up and start over */ @@ -337,6 +338,8 @@ AddEnumLabel(Oid enumTypeOid, ReleaseCatCacheList(list); goto restart; } + + newelemorder = midpoint; } } @@ -463,6 +466,91 @@ AddEnumLabel(Oid enumTypeOid, } +/* + * RenameEnumLabel + * Rename a label in an enum set. + */ +void +RenameEnumLabel(Oid enumTypeOid, + const char *oldVal, + const char *newVal) +{ + Relation pg_enum; + HeapTuple enum_tup; + Form_pg_enum en; + CatCList *list; + int nelems; + HeapTuple old_tup; + bool found_new; + int i; + + /* check length of new label is ok */ + if (strlen(newVal) > (NAMEDATALEN - 1)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("invalid enum label \"%s\"", newVal), + errdetail("Labels must be %d characters or less.", + NAMEDATALEN - 1))); + + /* + * Acquire a lock on the enum type, which we won't release until commit. + * This ensures that two backends aren't concurrently modifying the same + * enum type. Since we are not changing the type's sort order, this is + * probably not really necessary, but there seems no reason not to take + * the lock to be sure. + */ + LockDatabaseObject(TypeRelationId, enumTypeOid, 0, ExclusiveLock); + + pg_enum = heap_open(EnumRelationId, RowExclusiveLock); + + /* Get the list of existing members of the enum */ + list = SearchSysCacheList1(ENUMTYPOIDNAME, + ObjectIdGetDatum(enumTypeOid)); + nelems = list->n_members; + + /* + * Locate the element to rename and check if the new label is already in + * use. (The unique index on pg_enum would catch that anyway, but we + * prefer a friendlier error message.) + */ + old_tup = NULL; + found_new = false; + for (i = 0; i < nelems; i++) + { + enum_tup = &(list->members[i]->tuple); + en = (Form_pg_enum) GETSTRUCT(enum_tup); + if (strcmp(NameStr(en->enumlabel), oldVal) == 0) + old_tup = enum_tup; + if (strcmp(NameStr(en->enumlabel), newVal) == 0) + found_new = true; + } + if (!old_tup) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("\"%s\" is not an existing enum label", + oldVal))); + if (found_new) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("enum label \"%s\" already exists", + newVal))); + + /* OK, make a writable copy of old tuple */ + enum_tup = heap_copytuple(old_tup); + en = (Form_pg_enum) GETSTRUCT(enum_tup); + + ReleaseCatCacheList(list); + + /* Update the pg_enum entry */ + namestrcpy(&en->enumlabel, newVal); + simple_heap_update(pg_enum, &enum_tup->t_self, enum_tup); + CatalogUpdateIndexes(pg_enum, enum_tup); + heap_freetuple(enum_tup); + + heap_close(pg_enum, RowExclusiveLock); +} + + /* * RenumberEnumType * Renumber existing enum elements to have sort positions 1..n. diff --git a/src/backend/catalog/pg_inherits.c b/src/backend/catalog/pg_inherits.c index 00f2ae0bbb..82662a1f7e 100644 --- a/src/backend/catalog/pg_inherits.c +++ b/src/backend/catalog/pg_inherits.c @@ -8,7 +8,7 @@ * Perhaps someday that code should be moved here, but it'd have to be * disentangled from other stuff such as pg_depend updates. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/pg_largeobject.c b/src/backend/catalog/pg_largeobject.c index d08b94e28f..24edf6a6b6 100644 --- a/src/backend/catalog/pg_largeobject.c +++ b/src/backend/catalog/pg_largeobject.c @@ -3,7 +3,7 @@ * pg_largeobject.c * routines to support manipulation of the pg_largeobject relation * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/pg_namespace.c b/src/backend/catalog/pg_namespace.c index e5eed79237..f048ad4207 100644 --- a/src/backend/catalog/pg_namespace.c +++ b/src/backend/catalog/pg_namespace.c @@ -3,7 +3,7 @@ * pg_namespace.c * routines to support manipulation of the pg_namespace relation * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c index 5b5cd3fc01..556f9fef13 100644 --- a/src/backend/catalog/pg_operator.c +++ b/src/backend/catalog/pg_operator.c @@ -3,7 +3,7 @@ * pg_operator.c * routines to support manipulation of the pg_operator relation * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index c1d1505e64..7ae192a407 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -3,7 +3,7 @@ * pg_proc.c * routines to support manipulation of the pg_proc relation * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -37,14 +37,11 @@ #include "utils/acl.h" #include "utils/builtins.h" #include "utils/lsyscache.h" +#include "utils/regproc.h" #include "utils/rel.h" #include "utils/syscache.h" -Datum fmgr_internal_validator(PG_FUNCTION_ARGS); -Datum fmgr_c_validator(PG_FUNCTION_ARGS); -Datum fmgr_sql_validator(PG_FUNCTION_ARGS); - typedef struct { char *proname; @@ -934,7 +931,7 @@ fmgr_sql_validator(PG_FUNCTION_ARGS) querytree_list = NIL; foreach(lc, raw_parsetree_list) { - Node *parsetree = (Node *) lfirst(lc); + RawStmt *parsetree = (RawStmt *) lfirst(lc); List *querytree_sublist; querytree_sublist = pg_analyze_and_rewrite_params(parsetree, diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c new file mode 100644 index 0000000000..576b7faa04 --- /dev/null +++ b/src/backend/catalog/pg_publication.c @@ -0,0 +1,457 @@ +/*------------------------------------------------------------------------- + * + * pg_publication.c + * publication C API manipulation + * + * Copyright (c) 2016, PostgreSQL Global Development Group + * + * IDENTIFICATION + * pg_publication.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "funcapi.h" +#include "miscadmin.h" + +#include "access/genam.h" +#include "access/hash.h" +#include "access/heapam.h" +#include "access/htup_details.h" +#include "access/xact.h" + +#include "catalog/catalog.h" +#include "catalog/dependency.h" +#include "catalog/index.h" +#include "catalog/indexing.h" +#include "catalog/namespace.h" +#include "catalog/objectaccess.h" +#include "catalog/objectaddress.h" +#include "catalog/pg_type.h" +#include "catalog/pg_publication.h" +#include "catalog/pg_publication_rel.h" + +#include "utils/array.h" +#include "utils/builtins.h" +#include "utils/catcache.h" +#include "utils/fmgroids.h" +#include "utils/inval.h" +#include "utils/lsyscache.h" +#include "utils/rel.h" +#include "utils/syscache.h" + +/* + * Check if relation can be in given publication and throws appropriate + * error if not. + */ +static void +check_publication_add_relation(Relation targetrel) +{ + /* Must be table */ + if (RelationGetForm(targetrel)->relkind != RELKIND_RELATION) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("\"%s\" is not a table", + RelationGetRelationName(targetrel)), + errdetail("Only tables can be added to publications."))); + + /* Can't be system table */ + if (IsCatalogRelation(targetrel)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("\"%s\" is a system table", + RelationGetRelationName(targetrel)), + errdetail("System tables cannot be added to publications."))); + + /* UNLOGGED and TEMP relations cannot be part of publication. */ + if (!RelationNeedsWAL(targetrel)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("table \"%s\" cannot be replicated", + RelationGetRelationName(targetrel)), + errdetail("Temporary and unlogged relations cannot be replicated."))); +} + +/* + * Returns if relation represented by oid and Form_pg_class entry + * is publishable. + * + * Does same checks as the above, but does not need relation to be opened + * and also does not throw errors. + */ +static bool +is_publishable_class(Oid relid, Form_pg_class reltuple) +{ + return reltuple->relkind == RELKIND_RELATION && + !IsCatalogClass(relid, reltuple) && + reltuple->relpersistence == RELPERSISTENCE_PERMANENT && + /* + * Also exclude any tables created as part of initdb. This mainly + * affects the preinstalled information_schema. + * Note that IsCatalogClass() only checks for these inside pg_catalog + * and toast schemas. + */ + relid >= FirstNormalObjectId; +} + +/* + * Insert new publication / relation mapping. + */ +ObjectAddress +publication_add_relation(Oid pubid, Relation targetrel, + bool if_not_exists) +{ + Relation rel; + HeapTuple tup; + Datum values[Natts_pg_publication_rel]; + bool nulls[Natts_pg_publication_rel]; + Oid relid = RelationGetRelid(targetrel); + Oid prrelid; + Publication *pub = GetPublication(pubid); + ObjectAddress myself, + referenced; + + rel = heap_open(PublicationRelRelationId, RowExclusiveLock); + + /* + * Check for duplicates. Note that this does not really prevent + * duplicates, it's here just to provide nicer error message in common + * case. The real protection is the unique key on the catalog. + */ + if (SearchSysCacheExists2(PUBLICATIONRELMAP, ObjectIdGetDatum(relid), + ObjectIdGetDatum(pubid))) + { + heap_close(rel, RowExclusiveLock); + + if (if_not_exists) + return InvalidObjectAddress; + + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("relation \"%s\" is already member of publication \"%s\"", + RelationGetRelationName(targetrel), pub->name))); + } + + check_publication_add_relation(targetrel); + + /* Form a tuple. */ + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(nulls)); + + values[Anum_pg_publication_rel_prpubid - 1] = + ObjectIdGetDatum(pubid); + values[Anum_pg_publication_rel_prrelid - 1] = + ObjectIdGetDatum(relid); + + tup = heap_form_tuple(RelationGetDescr(rel), values, nulls); + + /* Insert tuple into catalog. */ + prrelid = simple_heap_insert(rel, tup); + CatalogUpdateIndexes(rel, tup); + heap_freetuple(tup); + + ObjectAddressSet(myself, PublicationRelRelationId, prrelid); + + /* Add dependency on the publication */ + ObjectAddressSet(referenced, PublicationRelationId, pubid); + recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); + + /* Add dependency on the relation */ + ObjectAddressSet(referenced, RelationRelationId, relid); + recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); + + /* Close the table. */ + heap_close(rel, RowExclusiveLock); + + /* Invalidate relcache so that publication info is rebuilt. */ + CacheInvalidateRelcache(targetrel); + + return myself; +} + + +/* + * Gets list of publication oids for a relation oid. + */ +List * +GetRelationPublications(Oid relid) +{ + List *result = NIL; + CatCList *pubrellist; + int i; + + /* Find all publications associated with the relation. */ + pubrellist = SearchSysCacheList1(PUBLICATIONRELMAP, + ObjectIdGetDatum(relid)); + for (i = 0; i < pubrellist->n_members; i++) + { + HeapTuple tup = &pubrellist->members[i]->tuple; + Oid pubid = ((Form_pg_publication_rel) GETSTRUCT(tup))->prpubid; + + result = lappend_oid(result, pubid); + } + + ReleaseSysCacheList(pubrellist); + + return result; +} + +/* + * Gets list of relation oids for a publication. + * + * This should only be used for normal publications, the FOR ALL TABLES + * should use GetAllTablesPublicationRelations(). + */ +List * +GetPublicationRelations(Oid pubid) +{ + List *result; + Relation pubrelsrel; + ScanKeyData scankey; + SysScanDesc scan; + HeapTuple tup; + + /* Find all publications associated with the relation. */ + pubrelsrel = heap_open(PublicationRelRelationId, AccessShareLock); + + ScanKeyInit(&scankey, + Anum_pg_publication_rel_prpubid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(pubid)); + + scan = systable_beginscan(pubrelsrel, PublicationRelMapIndexId, true, + NULL, 1, &scankey); + + result = NIL; + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_publication_rel pubrel; + + pubrel = (Form_pg_publication_rel) GETSTRUCT(tup); + + result = lappend_oid(result, pubrel->prrelid); + } + + systable_endscan(scan); + heap_close(pubrelsrel, AccessShareLock); + + return result; +} + +/* + * Gets list of publication oids for publications marked as FOR ALL TABLES. + */ +List * +GetAllTablesPublications(void) +{ + List *result; + Relation rel; + ScanKeyData scankey; + SysScanDesc scan; + HeapTuple tup; + + /* Find all publications that are marked as for all tables. */ + rel = heap_open(PublicationRelationId, AccessShareLock); + + ScanKeyInit(&scankey, + Anum_pg_publication_puballtables, + BTEqualStrategyNumber, F_BOOLEQ, + BoolGetDatum(true)); + + scan = systable_beginscan(rel, InvalidOid, false, + NULL, 1, &scankey); + + result = NIL; + while (HeapTupleIsValid(tup = systable_getnext(scan))) + result = lappend_oid(result, HeapTupleGetOid(tup)); + + systable_endscan(scan); + heap_close(rel, AccessShareLock); + + return result; +} + +/* + * Gets list of all relation published by FOR ALL TABLES publication(s). + */ +List * +GetAllTablesPublicationRelations(void) +{ + Relation classRel; + ScanKeyData key[1]; + HeapScanDesc scan; + HeapTuple tuple; + List *result = NIL; + + classRel = heap_open(RelationRelationId, AccessShareLock); + + ScanKeyInit(&key[0], + Anum_pg_class_relkind, + BTEqualStrategyNumber, F_CHAREQ, + CharGetDatum(RELKIND_RELATION)); + + scan = heap_beginscan_catalog(classRel, 1, key); + + while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) + { + Oid relid = HeapTupleGetOid(tuple); + Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple); + + if (is_publishable_class(relid, relForm)) + result = lappend_oid(result, relid); + } + + heap_endscan(scan); + heap_close(classRel, AccessShareLock); + + return result; +} + +/* + * Get publication using oid + * + * The Publication struct and it's data are palloced here. + */ +Publication * +GetPublication(Oid pubid) +{ + HeapTuple tup; + Publication *pub; + Form_pg_publication pubform; + + tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid)); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for publication %u", pubid); + + pubform = (Form_pg_publication) GETSTRUCT(tup); + + pub = (Publication *) palloc(sizeof(Publication)); + pub->oid = pubid; + pub->name = pstrdup(NameStr(pubform->pubname)); + pub->alltables = pubform->puballtables; + pub->pubactions.pubinsert = pubform->pubinsert; + pub->pubactions.pubupdate = pubform->pubupdate; + pub->pubactions.pubdelete = pubform->pubdelete; + + ReleaseSysCache(tup); + + return pub; +} + + +/* + * Get Publication using name. + */ +Publication * +GetPublicationByName(const char *pubname, bool missing_ok) +{ + Oid oid; + + oid = GetSysCacheOid1(PUBLICATIONNAME, CStringGetDatum(pubname)); + if (!OidIsValid(oid)) + { + if (missing_ok) + return NULL; + + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("publication \"%s\" does not exist", pubname))); + } + + return GetPublication(oid); +} + +/* + * get_publication_oid - given a publication name, look up the OID + * + * If missing_ok is false, throw an error if name not found. If true, just + * return InvalidOid. + */ +Oid +get_publication_oid(const char *pubname, bool missing_ok) +{ + Oid oid; + + oid = GetSysCacheOid1(PUBLICATIONNAME, CStringGetDatum(pubname)); + if (!OidIsValid(oid) && !missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("publication \"%s\" does not exist", pubname))); + return oid; +} + +/* + * get_publication_name - given a publication Oid, look up the name + */ +char * +get_publication_name(Oid pubid) +{ + HeapTuple tup; + char *pubname; + Form_pg_publication pubform; + + tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid)); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for publication %u", pubid); + + pubform = (Form_pg_publication) GETSTRUCT(tup); + pubname = pstrdup(NameStr(pubform->pubname)); + + ReleaseSysCache(tup); + + return pubname; +} + +/* + * Returns Oids of tables in a publication. + */ +Datum +pg_get_publication_tables(PG_FUNCTION_ARGS) +{ + FuncCallContext *funcctx; + char *pubname = text_to_cstring(PG_GETARG_TEXT_PP(0)); + Publication *publication; + List *tables; + ListCell **lcp; + + /* stuff done only on the first call of the function */ + if (SRF_IS_FIRSTCALL()) + { + MemoryContext oldcontext; + + /* create a function context for cross-call persistence */ + funcctx = SRF_FIRSTCALL_INIT(); + + /* switch to memory context appropriate for multiple function calls */ + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + publication = GetPublicationByName(pubname, false); + if (publication->alltables) + tables = GetAllTablesPublicationRelations(); + else + tables = GetPublicationRelations(publication->oid); + lcp = (ListCell **) palloc(sizeof(ListCell *)); + *lcp = list_head(tables); + funcctx->user_fctx = (void *) lcp; + + MemoryContextSwitchTo(oldcontext); + } + + /* stuff done on every call of the function */ + funcctx = SRF_PERCALL_SETUP(); + lcp = (ListCell **) funcctx->user_fctx; + + while (*lcp != NULL) + { + Oid relid = lfirst_oid(*lcp); + + *lcp = lnext(*lcp); + SRF_RETURN_NEXT(funcctx, ObjectIdGetDatum(relid)); + } + + SRF_RETURN_DONE(funcctx); +} diff --git a/src/backend/catalog/pg_range.c b/src/backend/catalog/pg_range.c index 84e7733e74..d3a4c264b3 100644 --- a/src/backend/catalog/pg_range.c +++ b/src/backend/catalog/pg_range.c @@ -3,7 +3,7 @@ * pg_range.c * routines to support manipulation of the pg_range relation * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c index 65ecc45d49..60ed957655 100644 --- a/src/backend/catalog/pg_shdepend.c +++ b/src/backend/catalog/pg_shdepend.c @@ -3,7 +3,7 @@ * pg_shdepend.c * routines to support manipulation of the pg_shdepend relation * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -39,6 +39,7 @@ #include "catalog/pg_opfamily.h" #include "catalog/pg_proc.h" #include "catalog/pg_shdepend.h" +#include "catalog/pg_subscription.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_ts_config.h" #include "catalog/pg_ts_dict.h" @@ -53,7 +54,9 @@ #include "commands/extension.h" #include "commands/policy.h" #include "commands/proclang.h" +#include "commands/publicationcmds.h" #include "commands/schemacmds.h" +#include "commands/subscriptioncmds.h" #include "commands/tablecmds.h" #include "commands/typecmds.h" #include "storage/lmgr.h" @@ -1406,6 +1409,14 @@ shdepReassignOwned(List *roleids, Oid newrole) AlterEventTriggerOwner_oid(sdepForm->objid, newrole); break; + case PublicationRelationId: + AlterPublicationOwner_oid(sdepForm->objid, newrole); + break; + + case SubscriptionRelationId: + AlterSubscriptionOwner_oid(sdepForm->objid, newrole); + break; + /* Generic alter owner cases */ case CollationRelationId: case ConversionRelationId: diff --git a/src/backend/catalog/pg_subscription.c b/src/backend/catalog/pg_subscription.c new file mode 100644 index 0000000000..c358ef6c9a --- /dev/null +++ b/src/backend/catalog/pg_subscription.c @@ -0,0 +1,207 @@ +/*------------------------------------------------------------------------- + * + * pg_subscription.c + * replication subscriptions + * + * Copyright (c) 2016, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/backend/catalog/pg_subscription.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "miscadmin.h" + +#include "access/genam.h" +#include "access/heapam.h" +#include "access/htup_details.h" + +#include "catalog/pg_type.h" +#include "catalog/pg_subscription.h" + +#include "nodes/makefuncs.h" + +#include "utils/array.h" +#include "utils/builtins.h" +#include "utils/fmgroids.h" +#include "utils/syscache.h" + + +static List *textarray_to_stringlist(ArrayType *textarray); + +/* + * Fetch the subscription from the syscache. + */ +Subscription * +GetSubscription(Oid subid, bool missing_ok) +{ + HeapTuple tup; + Subscription *sub; + Form_pg_subscription subform; + Datum datum; + bool isnull; + + tup = SearchSysCache1(SUBSCRIPTIONOID, ObjectIdGetDatum(subid)); + + if (!HeapTupleIsValid(tup)) + { + if (missing_ok) + return NULL; + + elog(ERROR, "cache lookup failed for subscription %u", subid); + } + + subform = (Form_pg_subscription) GETSTRUCT(tup); + + sub = (Subscription *) palloc(sizeof(Subscription)); + sub->oid = subid; + sub->dbid = subform->subdbid; + sub->name = pstrdup(NameStr(subform->subname)); + sub->owner = subform->subowner; + sub->enabled = subform->subenabled; + + /* Get conninfo */ + datum = SysCacheGetAttr(SUBSCRIPTIONOID, + tup, + Anum_pg_subscription_subconninfo, + &isnull); + Assert(!isnull); + sub->conninfo = pstrdup(TextDatumGetCString(datum)); + + /* Get slotname */ + datum = SysCacheGetAttr(SUBSCRIPTIONOID, + tup, + Anum_pg_subscription_subslotname, + &isnull); + Assert(!isnull); + sub->slotname = pstrdup(NameStr(*DatumGetName(datum))); + + /* Get publications */ + datum = SysCacheGetAttr(SUBSCRIPTIONOID, + tup, + Anum_pg_subscription_subpublications, + &isnull); + Assert(!isnull); + sub->publications = textarray_to_stringlist(DatumGetArrayTypeP(datum)); + + ReleaseSysCache(tup); + + return sub; +} + +/* + * Return number of subscriptions defined in given database. + * Used by dropdb() to check if database can indeed be dropped. + */ +int +CountDBSubscriptions(Oid dbid) +{ + int nsubs = 0; + Relation rel; + ScanKeyData scankey; + SysScanDesc scan; + HeapTuple tup; + + rel = heap_open(SubscriptionRelationId, RowExclusiveLock); + + ScanKeyInit(&scankey, + Anum_pg_subscription_subdbid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(dbid)); + + scan = systable_beginscan(rel, InvalidOid, false, + NULL, 1, &scankey); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + nsubs++; + + systable_endscan(scan); + + heap_close(rel, NoLock); + + return nsubs; +} + +/* + * Free memory allocated by subscription struct. + */ +void +FreeSubscription(Subscription *sub) +{ + pfree(sub->name); + pfree(sub->conninfo); + pfree(sub->slotname); + list_free_deep(sub->publications); + pfree(sub); +} + +/* + * get_subscription_oid - given a subscription name, look up the OID + * + * If missing_ok is false, throw an error if name not found. If true, just + * return InvalidOid. + */ +Oid +get_subscription_oid(const char *subname, bool missing_ok) +{ + Oid oid; + + oid = GetSysCacheOid2(SUBSCRIPTIONNAME, MyDatabaseId, + CStringGetDatum(subname)); + if (!OidIsValid(oid) && !missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("subscription \"%s\" does not exist", subname))); + return oid; +} + +/* + * get_subscription_name - given a subscription OID, look up the name + */ +char * +get_subscription_name(Oid subid) +{ + HeapTuple tup; + char *subname; + Form_pg_subscription subform; + + tup = SearchSysCache1(SUBSCRIPTIONOID, ObjectIdGetDatum(subid)); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for subscription %u", subid); + + subform = (Form_pg_subscription) GETSTRUCT(tup); + subname = pstrdup(NameStr(subform->subname)); + + ReleaseSysCache(tup); + + return subname; +} + +/* + * Convert text array to list of strings. + * + * Note: the resulting list of strings is pallocated here. + */ +static List * +textarray_to_stringlist(ArrayType *textarray) +{ + Datum *elems; + int nelems, i; + List *res = NIL; + + deconstruct_array(textarray, + TEXTOID, -1, false, 'i', + &elems, NULL, &nelems); + + if (nelems == 0) + return NIL; + + for (i = 0; i < nelems; i++) + res = lappend(res, makeString(pstrdup(TextDatumGetCString(elems[i])))); + + return res; +} diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index 4b2d281f2c..6d9a3247a9 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -3,7 +3,7 @@ * pg_type.c * routines to support manipulation of the pg_type relation * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c index 0d8311c403..f677916d03 100644 --- a/src/backend/catalog/storage.c +++ b/src/backend/catalog/storage.c @@ -3,7 +3,7 @@ * storage.c * code to create and destroy physical storage for relations * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 4fc5d5a065..4dfedf89b6 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1,7 +1,7 @@ /* * PostgreSQL System Views * - * Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Copyright (c) 1996-2017, PostgreSQL Global Development Group * * src/backend/catalog/system_views.sql * @@ -75,6 +75,12 @@ CREATE VIEW pg_policies AS N.nspname AS schemaname, C.relname AS tablename, pol.polname AS policyname, + CASE + WHEN pol.polpermissive THEN + 'PERMISSIVE' + ELSE + 'RESTRICTIVE' + END AS permissive, CASE WHEN pol.polroles = '{0}' THEN string_to_array('public', '') @@ -130,7 +136,7 @@ CREATE VIEW pg_tables AS C.relrowsecurity AS rowsecurity FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) LEFT JOIN pg_tablespace T ON (T.oid = C.reltablespace) - WHERE C.relkind = 'r'; + WHERE C.relkind IN ('r', 'P'); CREATE VIEW pg_matviews AS SELECT @@ -158,6 +164,23 @@ CREATE VIEW pg_indexes AS LEFT JOIN pg_tablespace T ON (T.oid = I.reltablespace) WHERE C.relkind IN ('r', 'm') AND I.relkind = 'i'; +CREATE OR REPLACE VIEW pg_sequences AS + SELECT + N.nspname AS schemaname, + C.relname AS sequencename, + pg_get_userbyid(C.relowner) AS sequenceowner, + S.seqstart AS start_value, + S.seqmin AS min_value, + S.seqmax AS max_value, + S.seqincrement AS increment_by, + S.seqcycle AS cycle, + S.seqcache AS cache_size, + pg_sequence_last_value(C.oid) AS last_value + FROM pg_sequence S JOIN pg_class C ON (C.oid = S.seqrelid) + LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) + WHERE NOT pg_is_other_temp_schema(N.oid) + AND relkind = 'S'; + CREATE VIEW pg_stats WITH (security_barrier) AS SELECT nspname AS schemaname, @@ -225,6 +248,15 @@ CREATE VIEW pg_stats WITH (security_barrier) AS REVOKE ALL on pg_statistic FROM public; +CREATE VIEW pg_publication_tables AS + SELECT + P.pubname AS pubname, + N.nspname AS schemaname, + C.relname AS tablename + FROM pg_publication P, pg_class C + JOIN pg_namespace N ON (N.oid = C.relnamespace) + WHERE C.oid IN (SELECT relid FROM pg_get_publication_tables(P.pubname)); + CREATE VIEW pg_locks AS SELECT * FROM pg_lock_status() AS L; @@ -257,7 +289,7 @@ CREATE VIEW pg_prepared_statements AS CREATE VIEW pg_seclabels AS SELECT l.objoid, l.classoid, l.objsubid, - CASE WHEN rel.relkind = 'r' THEN 'table'::text + CASE WHEN rel.relkind IN ('r', 'P') THEN 'table'::text WHEN rel.relkind = 'v' THEN 'view'::text WHEN rel.relkind = 'm' THEN 'materialized view'::text WHEN rel.relkind = 'S' THEN 'sequence'::text @@ -642,9 +674,9 @@ CREATE VIEW pg_stat_activity AS S.backend_xid, s.backend_xmin, S.query - FROM pg_database D, pg_stat_get_activity(NULL) AS S, pg_authid U - WHERE S.datid = D.oid AND - S.usesysid = U.oid; + FROM pg_stat_get_activity(NULL) AS S + LEFT JOIN pg_database AS D ON (S.datid = D.oid) + LEFT JOIN pg_authid AS U ON (S.usesysid = U.oid); CREATE VIEW pg_stat_replication AS SELECT @@ -664,10 +696,9 @@ CREATE VIEW pg_stat_replication AS W.replay_location, W.sync_priority, W.sync_state - FROM pg_stat_get_activity(NULL) AS S, pg_authid U, - pg_stat_get_wal_senders() AS W - WHERE S.usesysid = U.oid AND - S.pid = W.pid; + FROM pg_stat_get_activity(NULL) AS S + JOIN pg_stat_get_wal_senders() AS W ON (S.pid = W.pid) + LEFT JOIN pg_authid AS U ON (S.usesysid = U.oid); CREATE VIEW pg_stat_wal_receiver AS SELECT @@ -686,6 +717,20 @@ CREATE VIEW pg_stat_wal_receiver AS FROM pg_stat_get_wal_receiver() s WHERE s.pid IS NOT NULL; +CREATE VIEW pg_stat_subscription AS + SELECT + su.oid AS subid, + su.subname, + st.pid, + st.received_lsn, + st.last_msg_send_time, + st.last_msg_receipt_time, + st.latest_end_lsn, + st.latest_end_time + FROM pg_subscription su + LEFT JOIN pg_stat_get_subscription(NULL) st + ON (st.subid = su.oid); + CREATE VIEW pg_stat_ssl AS SELECT S.pid, @@ -704,6 +749,7 @@ CREATE VIEW pg_replication_slots AS L.slot_type, L.datoid, D.datname AS database, + L.temporary, L.active, L.active_pid, L.xmin, @@ -813,7 +859,7 @@ CREATE VIEW pg_stat_progress_vacuum AS S.param4 AS heap_blks_vacuumed, S.param5 AS index_vacuum_count, S.param6 AS max_dead_tuples, S.param7 AS num_dead_tuples FROM pg_stat_get_progress_info('VACUUM') AS S - JOIN pg_database D ON S.datid = D.oid; + LEFT JOIN pg_database D ON S.datid = D.oid; CREATE VIEW pg_user_mappings AS SELECT @@ -832,18 +878,19 @@ CREATE VIEW pg_user_mappings AS NULL END AS umoptions FROM pg_user_mapping U - LEFT JOIN pg_authid A ON (A.oid = U.umuser) JOIN - pg_foreign_server S ON (U.umserver = S.oid); + JOIN pg_foreign_server S ON (U.umserver = S.oid) + LEFT JOIN pg_authid A ON (A.oid = U.umuser); REVOKE ALL on pg_user_mapping FROM public; - CREATE VIEW pg_replication_origin_status AS SELECT * FROM pg_show_replication_origin_status(); REVOKE ALL ON pg_replication_origin_status FROM public; +REVOKE ALL ON pg_subscription FROM public; + -- -- We have a few function definitions in here, too. -- At some point there might be enough to justify breaking them out into @@ -970,12 +1017,22 @@ AS 'pg_logical_slot_peek_binary_changes'; CREATE OR REPLACE FUNCTION pg_create_physical_replication_slot( IN slot_name name, IN immediately_reserve boolean DEFAULT false, + IN temporary boolean DEFAULT false, OUT slot_name name, OUT xlog_position pg_lsn) RETURNS RECORD LANGUAGE INTERNAL STRICT VOLATILE AS 'pg_create_physical_replication_slot'; +CREATE OR REPLACE FUNCTION pg_create_logical_replication_slot( + IN slot_name name, IN plugin name, + IN temporary boolean DEFAULT false, + OUT slot_name text, OUT xlog_position pg_lsn) +RETURNS RECORD +LANGUAGE INTERNAL +STRICT VOLATILE +AS 'pg_create_logical_replication_slot'; + CREATE OR REPLACE FUNCTION make_interval(years int4 DEFAULT 0, months int4 DEFAULT 0, weeks int4 DEFAULT 0, days int4 DEFAULT 0, hours int4 DEFAULT 0, mins int4 DEFAULT 0, diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c index 564e10e3a2..ee4a182e35 100644 --- a/src/backend/catalog/toasting.c +++ b/src/backend/catalog/toasting.c @@ -4,7 +4,7 @@ * This file contains routines to support creation of toast tables * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile index 6b3742c0a0..e0fab38cbe 100644 --- a/src/backend/commands/Makefile +++ b/src/backend/commands/Makefile @@ -17,9 +17,9 @@ OBJS = amcmds.o aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o \ dbcommands.o define.o discard.o dropcmds.o \ event_trigger.o explain.o extension.o foreigncmds.o functioncmds.o \ indexcmds.o lockcmds.o matview.o operatorcmds.o opclasscmds.o \ - policy.o portalcmds.o prepare.o proclang.o \ - schemacmds.o seclabel.o sequence.o tablecmds.o tablespace.o trigger.o \ - tsearchcmds.o typecmds.o user.o vacuum.o vacuumlazy.o \ - variable.o view.o + policy.o portalcmds.o prepare.o proclang.o publicationcmds.o \ + schemacmds.o seclabel.o sequence.o subscriptioncmds.o tablecmds.o \ + tablespace.o trigger.o tsearchcmds.o typecmds.o user.o vacuum.o \ + vacuumlazy.o variable.o view.o include $(top_srcdir)/src/backend/common.mk diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c index d34c82c5ba..02ea254cd4 100644 --- a/src/backend/commands/aggregatecmds.c +++ b/src/backend/commands/aggregatecmds.c @@ -4,7 +4,7 @@ * * Routines for aggregate-manipulation commands * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -22,7 +22,6 @@ */ #include "postgres.h" -#include "access/heapam.h" #include "access/htup_details.h" #include "catalog/dependency.h" #include "catalog/indexing.h" @@ -52,8 +51,7 @@ * "parameters" is a list of DefElem representing the agg's definition clauses. */ ObjectAddress -DefineAggregate(List *name, List *args, bool oldstyle, List *parameters, - const char *queryString) +DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List *parameters) { char *aggName; Oid aggNamespace; @@ -287,10 +285,10 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters, errmsg("basetype is redundant with aggregate input type specification"))); numArgs = list_length(args); - interpret_function_parameter_list(args, + interpret_function_parameter_list(pstate, + args, InvalidOid, true, /* is an aggregate */ - queryString, ¶meterTypes, &allParameterTypes, ¶meterModes, diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index 1301bcb5e8..768fcc82dd 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -3,7 +3,7 @@ * alter.c * Drivers for generic alter commands * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -45,7 +45,9 @@ #include "commands/extension.h" #include "commands/policy.h" #include "commands/proclang.h" +#include "commands/publicationcmds.h" #include "commands/schemacmds.h" +#include "commands/subscriptioncmds.h" #include "commands/tablecmds.h" #include "commands/tablespace.h" #include "commands/trigger.h" @@ -757,7 +759,6 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt) case OBJECT_TYPE: case OBJECT_DOMAIN: /* same as TYPE */ return AlterTypeOwner(stmt->object, newowner, stmt->objectType); - break; case OBJECT_FDW: return AlterForeignDataWrapperOwner(strVal(linitial(stmt->object)), @@ -771,6 +772,14 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt) return AlterEventTriggerOwner(strVal(linitial(stmt->object)), newowner); + case OBJECT_PUBLICATION: + return AlterPublicationOwner(strVal(linitial(stmt->object)), + newowner); + + case OBJECT_SUBSCRIPTION: + return AlterSubscriptionOwner(strVal(linitial(stmt->object)), + newowner); + /* Generic cases */ case OBJECT_AGGREGATE: case OBJECT_COLLATION: diff --git a/src/backend/commands/amcmds.c b/src/backend/commands/amcmds.c index 9ac930ea8b..29061b888a 100644 --- a/src/backend/commands/amcmds.c +++ b/src/backend/commands/amcmds.c @@ -3,7 +3,7 @@ * amcmds.c * Routines for SQL commands that manipulate access methods. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index 9ac71220a2..e3e1a53072 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -3,7 +3,7 @@ * analyze.c * the Postgres statistics generator * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -201,7 +201,8 @@ analyze_rel(Oid relid, RangeVar *relation, int options, * locked the relation. */ if (onerel->rd_rel->relkind == RELKIND_RELATION || - onerel->rd_rel->relkind == RELKIND_MATVIEW) + onerel->rd_rel->relkind == RELKIND_MATVIEW || + onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) { /* Regular table, so we'll use the regular row acquisition function */ acquirefunc = acquire_sample_rows; @@ -332,9 +333,7 @@ do_analyze_rel(Relation onerel, int options, VacuumParams *params, */ anl_context = AllocSetContextCreate(CurrentMemoryContext, "Analyze", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); caller_context = MemoryContextSwitchTo(anl_context); /* @@ -504,9 +503,7 @@ do_analyze_rel(Relation onerel, int options, VacuumParams *params, col_context = AllocSetContextCreate(anl_context, "Analyze Column", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); old_context = MemoryContextSwitchTo(col_context); for (i = 0; i < attr_cnt; i++) @@ -688,9 +685,7 @@ compute_index_stats(Relation onerel, double totalrows, ind_context = AllocSetContextCreate(anl_context, "Analyze Index", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); old_context = MemoryContextSwitchTo(ind_context); for (ind = 0; ind < nindexes; ind++) @@ -1323,7 +1318,8 @@ acquire_inherited_sample_rows(Relation onerel, int elevel, /* Check table type (MATVIEW can't happen, but might as well allow) */ if (childrel->rd_rel->relkind == RELKIND_RELATION || - childrel->rd_rel->relkind == RELKIND_MATVIEW) + childrel->rd_rel->relkind == RELKIND_MATVIEW || + childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) { /* Regular table, so use the regular row acquisition function */ acquirefunc = acquire_sample_rows; diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c index 716f1c3318..6d0ce7a358 100644 --- a/src/backend/commands/async.c +++ b/src/backend/commands/async.c @@ -3,7 +3,7 @@ * async.c * Asynchronous notification: NOTIFY, LISTEN, UNLISTEN * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index 43bbd90591..f9309fcf47 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -6,7 +6,7 @@ * There is hardly anything left of Paul Brown's original implementation... * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994-5, Regents of the University of California * * @@ -204,9 +204,7 @@ cluster(ClusterStmt *stmt, bool isTopLevel) */ cluster_context = AllocSetContextCreate(PortalContext, "Cluster", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* * Build the list of relations to cluster. Note that this lives in @@ -1059,11 +1057,10 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose, for (;;) { HeapTuple tuple; - bool shouldfree; CHECK_FOR_INTERRUPTS(); - tuple = tuplesort_getheaptuple(tuplesort, true, &shouldfree); + tuple = tuplesort_getheaptuple(tuplesort, true); if (tuple == NULL) break; @@ -1071,9 +1068,6 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose, oldTupDesc, newTupDesc, values, isnull, NewHeap->rd_rel->relhasoids, rwstate); - - if (shouldfree) - heap_freetuple(tuple); } tuplesort_end(tuplesort); diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c index e4ebb654a6..71b21bf0d2 100644 --- a/src/backend/commands/collationcmds.c +++ b/src/backend/commands/collationcmds.c @@ -3,7 +3,7 @@ * collationcmds.c * collation-related commands support code * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -14,7 +14,6 @@ */ #include "postgres.h" -#include "access/heapam.h" #include "access/htup_details.h" #include "access/xact.h" #include "catalog/dependency.h" @@ -38,7 +37,7 @@ * CREATE COLLATION */ ObjectAddress -DefineCollation(List *names, List *parameters) +DefineCollation(ParseState *pstate, List *names, List *parameters) { char *collName; Oid collNamespace; @@ -78,7 +77,8 @@ DefineCollation(List *names, List *parameters) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("collation attribute \"%s\" not recognized", - defel->defname))); + defel->defname), + parser_errposition(pstate, defel->location))); break; } @@ -136,7 +136,11 @@ DefineCollation(List *names, List *parameters) GetUserId(), GetDatabaseEncoding(), collcollate, - collctype); + collctype, + false); + + if (!OidIsValid(newoid)) + return InvalidObjectAddress; ObjectAddressSet(address, CollationRelationId, newoid); @@ -177,3 +181,167 @@ IsThereCollationInNamespace(const char *collname, Oid nspOid) errmsg("collation \"%s\" already exists in schema \"%s\"", collname, get_namespace_name(nspOid)))); } + + +/* + * "Normalize" a locale name, stripping off encoding tags such as + * ".utf8" (e.g., "en_US.utf8" -> "en_US", but "br_FR.iso885915@euro" + * -> "br_FR@euro"). Return true if a new, different name was + * generated. + */ +pg_attribute_unused() +static bool +normalize_locale_name(char *new, const char *old) +{ + char *n = new; + const char *o = old; + bool changed = false; + + while (*o) + { + if (*o == '.') + { + /* skip over encoding tag such as ".utf8" or ".UTF-8" */ + o++; + while ((*o >= 'A' && *o <= 'Z') + || (*o >= 'a' && *o <= 'z') + || (*o >= '0' && *o <= '9') + || (*o == '-')) + o++; + changed = true; + } + else + *n++ = *o++; + } + *n = '\0'; + + return changed; +} + + +Datum +pg_import_system_collations(PG_FUNCTION_ARGS) +{ +#if defined(HAVE_LOCALE_T) && !defined(WIN32) + bool if_not_exists = PG_GETARG_BOOL(0); + Oid nspid = PG_GETARG_OID(1); + + FILE *locale_a_handle; + char localebuf[NAMEDATALEN]; /* we assume ASCII so this is fine */ + int count = 0; + List *aliaslist = NIL; + List *localelist = NIL; + List *enclist = NIL; + ListCell *lca, + *lcl, + *lce; +#endif + + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + (errmsg("must be superuser to import system collations")))); + +#if defined(HAVE_LOCALE_T) && !defined(WIN32) + locale_a_handle = OpenPipeStream("locale -a", "r"); + if (locale_a_handle == NULL) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not execute command \"%s\": %m", + "locale -a"))); + + while (fgets(localebuf, sizeof(localebuf), locale_a_handle)) + { + int i; + size_t len; + int enc; + bool skip; + char alias[NAMEDATALEN]; + + len = strlen(localebuf); + + if (len == 0 || localebuf[len - 1] != '\n') + { + elog(DEBUG1, "locale name too long, skipped: \"%s\"", localebuf); + continue; + } + localebuf[len - 1] = '\0'; + + /* + * Some systems have locale names that don't consist entirely of ASCII + * letters (such as "bokmål" or "français"). This is + * pretty silly, since we need the locale itself to interpret the + * non-ASCII characters. We can't do much with those, so we filter + * them out. + */ + skip = false; + for (i = 0; i < len; i++) + { + if (IS_HIGHBIT_SET(localebuf[i])) + { + skip = true; + break; + } + } + if (skip) + { + elog(DEBUG1, "locale name has non-ASCII characters, skipped: \"%s\"", localebuf); + continue; + } + + enc = pg_get_encoding_from_locale(localebuf, false); + if (enc < 0) + { + /* error message printed by pg_get_encoding_from_locale() */ + continue; + } + if (!PG_VALID_BE_ENCODING(enc)) + continue; /* ignore locales for client-only encodings */ + if (enc == PG_SQL_ASCII) + continue; /* C/POSIX are already in the catalog */ + + count++; + + CollationCreate(localebuf, nspid, GetUserId(), enc, + localebuf, localebuf, if_not_exists); + + CommandCounterIncrement(); + + /* + * Generate aliases such as "en_US" in addition to "en_US.utf8" for + * ease of use. Note that collation names are unique per encoding + * only, so this doesn't clash with "en_US" for LATIN1, say. + * + * However, it might conflict with a name we'll see later in the + * "locale -a" output. So save up the aliases and try to add them + * after we've read all the output. + */ + if (normalize_locale_name(alias, localebuf)) + { + aliaslist = lappend(aliaslist, pstrdup(alias)); + localelist = lappend(localelist, pstrdup(localebuf)); + enclist = lappend_int(enclist, enc); + } + } + + ClosePipeStream(locale_a_handle); + + /* Now try to add any aliases we created */ + forthree(lca, aliaslist, lcl, localelist, lce, enclist) + { + char *alias = (char *) lfirst(lca); + char *locale = (char *) lfirst(lcl); + int enc = lfirst_int(lce); + + CollationCreate(alias, nspid, GetUserId(), enc, + locale, locale, true); + CommandCounterIncrement(); + } + + if (count == 0) + ereport(ERROR, + (errmsg("no usable system locales were found"))); +#endif /* not HAVE_LOCALE_T && not WIN32 */ + + PG_RETURN_VOID(); +} diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c index a0d3f8d01d..ada0b0356a 100644 --- a/src/backend/commands/comment.c +++ b/src/backend/commands/comment.c @@ -4,7 +4,7 @@ * * PostgreSQL object comments utility code. * - * Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/commands/comment.c diff --git a/src/backend/commands/constraint.c b/src/backend/commands/constraint.c index 26f9114f55..77cf8ceee7 100644 --- a/src/backend/commands/constraint.c +++ b/src/backend/commands/constraint.c @@ -3,7 +3,7 @@ * constraint.c * PostgreSQL CONSTRAINT support code. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/commands/conversioncmds.c b/src/backend/commands/conversioncmds.c index 175d4ab685..9861d3df22 100644 --- a/src/backend/commands/conversioncmds.c +++ b/src/backend/commands/conversioncmds.c @@ -3,7 +3,7 @@ * conversioncmds.c * conversion creation command support code * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -14,7 +14,6 @@ */ #include "postgres.h" -#include "access/heapam.h" #include "access/htup_details.h" #include "catalog/dependency.h" #include "catalog/indexing.h" diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index f45b3304ae..c05e14e26f 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -3,7 +3,7 @@ * copy.c * Implements the COPY utility command * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -162,6 +162,14 @@ typedef struct CopyStateData bool volatile_defexprs; /* is any of defexprs volatile? */ List *range_table; + PartitionDispatch *partition_dispatch_info; + int num_dispatch; /* Number of entries in the above array */ + int num_partitions; /* Number of members in the following + * arrays */ + ResultRelInfo *partitions; /* Per partition result relation */ + TupleConversionMap **partition_tupconv_maps; + TupleTableSlot *partition_tuple_slot; + /* * These variables are used to reduce overhead in textual COPY FROM. * @@ -279,13 +287,13 @@ static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0"; /* non-export function prototypes */ -static CopyState BeginCopy(bool is_from, Relation rel, Node *raw_query, - const char *queryString, const Oid queryRelId, List *attnamelist, +static CopyState BeginCopy(ParseState *pstate, bool is_from, Relation rel, + RawStmt *raw_query, Oid queryRelId, List *attnamelist, List *options); static void EndCopy(CopyState cstate); static void ClosePipeToProgram(CopyState cstate); -static CopyState BeginCopyTo(Relation rel, Node *query, const char *queryString, - const Oid queryRelId, const char *filename, bool is_program, +static CopyState BeginCopyTo(ParseState *pstate, Relation rel, RawStmt *query, + Oid queryRelId, const char *filename, bool is_program, List *attnamelist, List *options); static void EndCopyTo(CopyState cstate); static uint64 DoCopyTo(CopyState cstate); @@ -353,7 +361,7 @@ SendCopyBegin(CopyState cstate) pq_endmessage(&buf); cstate->copy_dest = COPY_NEW_FE; } - else if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2) + else { /* old way */ if (cstate->binary) @@ -365,18 +373,6 @@ SendCopyBegin(CopyState cstate) pq_startcopyout(); cstate->copy_dest = COPY_OLD_FE; } - else - { - /* very old way */ - if (cstate->binary) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("COPY BINARY is not supported to stdout or from stdin"))); - pq_putemptymessage('B'); - /* grottiness needed for old COPY OUT protocol */ - pq_startcopyout(); - cstate->copy_dest = COPY_OLD_FE; - } } static void @@ -397,9 +393,9 @@ ReceiveCopyBegin(CopyState cstate) pq_sendint(&buf, format, 2); /* per-column formats */ pq_endmessage(&buf); cstate->copy_dest = COPY_NEW_FE; - cstate->fe_msgbuf = makeStringInfo(); + cstate->fe_msgbuf = makeLongStringInfo(); } - else if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2) + else { /* old way */ if (cstate->binary) @@ -411,18 +407,6 @@ ReceiveCopyBegin(CopyState cstate) pq_startmsgread(); cstate->copy_dest = COPY_OLD_FE; } - else - { - /* very old way */ - if (cstate->binary) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("COPY BINARY is not supported to stdout or from stdin"))); - pq_putemptymessage('D'); - /* any error in old protocol will make us lose sync */ - pq_startmsgread(); - cstate->copy_dest = COPY_OLD_FE; - } /* We *must* flush here to ensure FE knows it can send. */ pq_flush(); } @@ -786,15 +770,17 @@ CopyLoadRawBuf(CopyState cstate) * Do not allow the copy if user doesn't have proper permission to access * the table or the specifically requested columns. */ -Oid -DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed) +void +DoCopy(ParseState *pstate, const CopyStmt *stmt, + int stmt_location, int stmt_len, + uint64 *processed) { CopyState cstate; bool is_from = stmt->is_from; bool pipe = (stmt->filename == NULL); Relation rel; Oid relid; - Node *query = NULL; + RawStmt *query = NULL; List *range_table = NIL; /* Disallow COPY to/from file or program except to superusers. */ @@ -871,6 +857,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed) ColumnRef *cr; ResTarget *target; RangeVar *from; + List *targetList = NIL; if (is_from) ereport(ERROR, @@ -878,21 +865,59 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed) errmsg("COPY FROM not supported with row-level security"), errhint("Use INSERT statements instead."))); - /* Build target list */ - cr = makeNode(ColumnRef); - + /* + * Build target list + * + * If no columns are specified in the attribute list of the COPY + * command, then the target list is 'all' columns. Therefore, '*' + * should be used as the target list for the resulting SELECT + * statement. + * + * In the case that columns are specified in the attribute list, + * create a ColumnRef and ResTarget for each column and add them + * to the target list for the resulting SELECT statement. + */ if (!stmt->attlist) + { + cr = makeNode(ColumnRef); cr->fields = list_make1(makeNode(A_Star)); - else - cr->fields = stmt->attlist; + cr->location = -1; - cr->location = 1; + target = makeNode(ResTarget); + target->name = NULL; + target->indirection = NIL; + target->val = (Node *) cr; + target->location = -1; + + targetList = list_make1(target); + } + else + { + ListCell *lc; - target = makeNode(ResTarget); - target->name = NULL; - target->indirection = NIL; - target->val = (Node *) cr; - target->location = 1; + foreach(lc, stmt->attlist) + { + /* + * Build the ColumnRef for each column. The ColumnRef + * 'fields' property is a String 'Value' node (see + * nodes/value.h) that corresponds to the column name + * respectively. + */ + cr = makeNode(ColumnRef); + cr->fields = list_make1(lfirst(lc)); + cr->location = -1; + + /* Build the ResTarget and add the ColumnRef to it. */ + target = makeNode(ResTarget); + target->name = NULL; + target->indirection = NIL; + target->val = (Node *) cr; + target->location = -1; + + /* Add each column to the SELECT statement's target list */ + targetList = lappend(targetList, target); + } + } /* * Build RangeVar for from clause, fully qualified based on the @@ -903,10 +928,13 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed) /* Build query */ select = makeNode(SelectStmt); - select->targetList = list_make1(target); + select->targetList = targetList; select->fromClause = list_make1(from); - query = (Node *) select; + query = makeNode(RawStmt); + query->stmt = (Node *) select; + query->stmt_location = stmt_location; + query->stmt_len = stmt_len; /* * Close the relation for now, but keep the lock on it to prevent @@ -922,7 +950,11 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed) { Assert(stmt->query); - query = stmt->query; + query = makeNode(RawStmt); + query->stmt = stmt->query; + query->stmt_location = stmt_location; + query->stmt_len = stmt_len; + relid = InvalidOid; rel = NULL; } @@ -936,7 +968,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed) PreventCommandIfReadOnly("COPY FROM"); PreventCommandIfParallelMode("COPY FROM"); - cstate = BeginCopyFrom(rel, stmt->filename, stmt->is_program, + cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program, stmt->attlist, stmt->options); cstate->range_table = range_table; *processed = CopyFrom(cstate); /* copy from file to database */ @@ -944,7 +976,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed) } else { - cstate = BeginCopyTo(rel, query, queryString, relid, + cstate = BeginCopyTo(pstate, rel, query, relid, stmt->filename, stmt->is_program, stmt->attlist, stmt->options); *processed = DoCopyTo(cstate); /* copy from database to file */ @@ -958,8 +990,6 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed) */ if (rel != NULL) heap_close(rel, (is_from ? NoLock : AccessShareLock)); - - return relid; } /* @@ -980,7 +1010,8 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed) * self-consistency of the options list. */ void -ProcessCopyOptions(CopyState cstate, +ProcessCopyOptions(ParseState *pstate, + CopyState cstate, bool is_from, List *options) { @@ -1005,7 +1036,8 @@ ProcessCopyOptions(CopyState cstate, if (format_specified) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); format_specified = true; if (strcmp(fmt, "text") == 0) /* default format */ ; @@ -1016,14 +1048,16 @@ ProcessCopyOptions(CopyState cstate, else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("COPY format \"%s\" not recognized", fmt))); + errmsg("COPY format \"%s\" not recognized", fmt), + parser_errposition(pstate, defel->location))); } else if (strcmp(defel->defname, "oids") == 0) { if (cstate->oids) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); cstate->oids = defGetBoolean(defel); } else if (strcmp(defel->defname, "freeze") == 0) @@ -1031,7 +1065,8 @@ ProcessCopyOptions(CopyState cstate, if (cstate->freeze) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); cstate->freeze = defGetBoolean(defel); } else if (strcmp(defel->defname, "delimiter") == 0) @@ -1039,7 +1074,8 @@ ProcessCopyOptions(CopyState cstate, if (cstate->delim) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); cstate->delim = defGetString(defel); } else if (strcmp(defel->defname, "null") == 0) @@ -1047,7 +1083,8 @@ ProcessCopyOptions(CopyState cstate, if (cstate->null_print) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); cstate->null_print = defGetString(defel); } else if (strcmp(defel->defname, "header") == 0) @@ -1055,7 +1092,8 @@ ProcessCopyOptions(CopyState cstate, if (cstate->header_line) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); cstate->header_line = defGetBoolean(defel); } else if (strcmp(defel->defname, "quote") == 0) @@ -1063,7 +1101,8 @@ ProcessCopyOptions(CopyState cstate, if (cstate->quote) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); cstate->quote = defGetString(defel); } else if (strcmp(defel->defname, "escape") == 0) @@ -1071,7 +1110,8 @@ ProcessCopyOptions(CopyState cstate, if (cstate->escape) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); cstate->escape = defGetString(defel); } else if (strcmp(defel->defname, "force_quote") == 0) @@ -1079,7 +1119,8 @@ ProcessCopyOptions(CopyState cstate, if (cstate->force_quote || cstate->force_quote_all) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); if (defel->arg && IsA(defel->arg, A_Star)) cstate->force_quote_all = true; else if (defel->arg && IsA(defel->arg, List)) @@ -1088,21 +1129,24 @@ ProcessCopyOptions(CopyState cstate, ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("argument to option \"%s\" must be a list of column names", - defel->defname))); + defel->defname), + parser_errposition(pstate, defel->location))); } else if (strcmp(defel->defname, "force_not_null") == 0) { if (cstate->force_notnull) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); if (defel->arg && IsA(defel->arg, List)) cstate->force_notnull = (List *) defel->arg; else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("argument to option \"%s\" must be a list of column names", - defel->defname))); + defel->defname), + parser_errposition(pstate, defel->location))); } else if (strcmp(defel->defname, "force_null") == 0) { @@ -1116,7 +1160,8 @@ ProcessCopyOptions(CopyState cstate, ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("argument to option \"%s\" must be a list of column names", - defel->defname))); + defel->defname), + parser_errposition(pstate, defel->location))); } else if (strcmp(defel->defname, "convert_selectively") == 0) { @@ -1128,7 +1173,8 @@ ProcessCopyOptions(CopyState cstate, if (cstate->convert_selectively) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); cstate->convert_selectively = true; if (defel->arg == NULL || IsA(defel->arg, List)) cstate->convert_select = (List *) defel->arg; @@ -1136,26 +1182,30 @@ ProcessCopyOptions(CopyState cstate, ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("argument to option \"%s\" must be a list of column names", - defel->defname))); + defel->defname), + parser_errposition(pstate, defel->location))); } else if (strcmp(defel->defname, "encoding") == 0) { if (cstate->file_encoding >= 0) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); cstate->file_encoding = pg_char_to_encoding(defGetString(defel)); if (cstate->file_encoding < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("argument to option \"%s\" must be a valid encoding name", - defel->defname))); + defel->defname), + parser_errposition(pstate, defel->location))); } else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("option \"%s\" not recognized", - defel->defname))); + defel->defname), + parser_errposition(pstate, defel->location))); } /* @@ -1318,11 +1368,11 @@ ProcessCopyOptions(CopyState cstate, * NULL values as . */ static CopyState -BeginCopy(bool is_from, +BeginCopy(ParseState *pstate, + bool is_from, Relation rel, - Node *raw_query, - const char *queryString, - const Oid queryRelId, + RawStmt *raw_query, + Oid queryRelId, List *attnamelist, List *options) { @@ -1340,14 +1390,12 @@ BeginCopy(bool is_from, */ cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext, "COPY", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldcontext = MemoryContextSwitchTo(cstate->copycontext); /* Extract options from the statement node tree */ - ProcessCopyOptions(cstate, is_from, options); + ProcessCopyOptions(pstate, cstate, is_from, options); /* Process the source/target relation or query */ if (rel) @@ -1364,6 +1412,30 @@ BeginCopy(bool is_from, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("table \"%s\" does not have OIDs", RelationGetRelationName(cstate->rel)))); + + /* Initialize state for CopyFrom tuple routing. */ + if (is_from && rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + { + PartitionDispatch *partition_dispatch_info; + ResultRelInfo *partitions; + TupleConversionMap **partition_tupconv_maps; + TupleTableSlot *partition_tuple_slot; + int num_parted, + num_partitions; + + ExecSetupPartitionTupleRouting(rel, + &partition_dispatch_info, + &partitions, + &partition_tupconv_maps, + &partition_tuple_slot, + &num_parted, &num_partitions); + cstate->partition_dispatch_info = partition_dispatch_info; + cstate->num_dispatch = num_parted; + cstate->partitions = partitions; + cstate->num_partitions = num_partitions; + cstate->partition_tupconv_maps = partition_tupconv_maps; + cstate->partition_tuple_slot = partition_tuple_slot; + } } else { @@ -1391,8 +1463,8 @@ BeginCopy(bool is_from, * function and is executed repeatedly. (See also the same hack in * DECLARE CURSOR and PREPARE.) XXX FIXME someday. */ - rewritten = pg_analyze_and_rewrite((Node *) copyObject(raw_query), - queryString, NULL, 0); + rewritten = pg_analyze_and_rewrite((RawStmt *) copyObject(raw_query), + pstate->p_sourcetext, NULL, 0); /* check that we got back something we can work with */ if (rewritten == NIL) @@ -1492,7 +1564,7 @@ BeginCopy(bool is_from, ((DR_copy *) dest)->cstate = cstate; /* Create a QueryDesc requesting no output */ - cstate->queryDesc = CreateQueryDesc(plan, queryString, + cstate->queryDesc = CreateQueryDesc(plan, pstate->p_sourcetext, GetActiveSnapshot(), InvalidSnapshot, dest, NULL, 0); @@ -1680,10 +1752,10 @@ EndCopy(CopyState cstate) * Setup CopyState to read tuples from a table or a query for COPY TO. */ static CopyState -BeginCopyTo(Relation rel, - Node *query, - const char *queryString, - const Oid queryRelId, +BeginCopyTo(ParseState *pstate, + Relation rel, + RawStmt *query, + Oid queryRelId, const char *filename, bool is_program, List *attnamelist, @@ -1718,6 +1790,12 @@ BeginCopyTo(Relation rel, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot copy from sequence \"%s\"", RelationGetRelationName(rel)))); + else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot copy from partitioned table \"%s\"", + RelationGetRelationName(rel)), + errhint("Try the COPY (SELECT ...) TO variant."))); else ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), @@ -1725,7 +1803,7 @@ BeginCopyTo(Relation rel, RelationGetRelationName(rel)))); } - cstate = BeginCopy(false, rel, query, queryString, queryRelId, attnamelist, + cstate = BeginCopy(pstate, false, rel, query, queryRelId, attnamelist, options); oldcontext = MemoryContextSwitchTo(cstate->copycontext); @@ -1767,10 +1845,18 @@ BeginCopyTo(Relation rel, cstate->copy_file = AllocateFile(cstate->filename, PG_BINARY_W); umask(oumask); if (cstate->copy_file == NULL) + { + /* copy errno because ereport subfunctions might change it */ + int save_errno = errno; + ereport(ERROR, (errcode_for_file_access(), errmsg("could not open file \"%s\" for writing: %m", - cstate->filename))); + cstate->filename), + (save_errno == ENOENT || save_errno == EACCES) ? + errhint("COPY TO instructs the PostgreSQL server process to write a file. " + "You may want a client-side facility such as psql's \\copy.") : 0)); + } if (fstat(fileno(cstate->copy_file), &st)) ereport(ERROR, @@ -1866,7 +1952,7 @@ CopyTo(CopyState cstate) cstate->null_print_client = cstate->null_print; /* default */ /* We use fe_msgbuf as a per-row buffer regardless of copy_dest */ - cstate->fe_msgbuf = makeStringInfo(); + cstate->fe_msgbuf = makeLongStringInfo(); /* Get info about the columns we need to process. */ cstate->out_functions = (FmgrInfo *) palloc(num_phys_attrs * sizeof(FmgrInfo)); @@ -1895,9 +1981,7 @@ CopyTo(CopyState cstate) */ cstate->rowcontext = AllocSetContextCreate(CurrentMemoryContext, "COPY TO", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); if (cstate->binary) { @@ -2210,6 +2294,7 @@ CopyFrom(CopyState cstate) Datum *values; bool *nulls; ResultRelInfo *resultRelInfo; + ResultRelInfo *saved_resultRelInfo = NULL; EState *estate = CreateExecutorState(); /* for ExecConstraints() */ ExprContext *econtext; TupleTableSlot *myslot; @@ -2230,13 +2315,22 @@ CopyFrom(CopyState cstate) Assert(cstate->rel); - if (cstate->rel->rd_rel->relkind != RELKIND_RELATION) + /* + * The target must be a plain relation or have an INSTEAD OF INSERT row + * trigger. (Currently, such triggers are only allowed on views, so we + * only hint about them in the view case.) + */ + if (cstate->rel->rd_rel->relkind != RELKIND_RELATION && + cstate->rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE && + !(cstate->rel->trigdesc && + cstate->rel->trigdesc->trig_insert_instead_row)) { if (cstate->rel->rd_rel->relkind == RELKIND_VIEW) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot copy to view \"%s\"", - RelationGetRelationName(cstate->rel)))); + RelationGetRelationName(cstate->rel)), + errhint("To enable copying to a view, provide an INSTEAD OF INSERT trigger."))); else if (cstate->rel->rd_rel->relkind == RELKIND_MATVIEW) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), @@ -2338,6 +2432,7 @@ CopyFrom(CopyState cstate) InitResultRelInfo(resultRelInfo, cstate->rel, 1, /* dummy rangetable index */ + NULL, 0); ExecOpenIndices(resultRelInfo, false); @@ -2360,11 +2455,13 @@ CopyFrom(CopyState cstate) * BEFORE/INSTEAD OF triggers, or we need to evaluate volatile default * expressions. Such triggers or expressions might query the table we're * inserting to, and act differently if the tuples that have already been - * processed and prepared for insertion are not there. + * processed and prepared for insertion are not there. We also can't do + * it if the table is partitioned. */ if ((resultRelInfo->ri_TrigDesc != NULL && (resultRelInfo->ri_TrigDesc->trig_insert_before_row || resultRelInfo->ri_TrigDesc->trig_insert_instead_row)) || + cstate->partition_dispatch_info != NULL || cstate->volatile_defexprs) { useHeapMultiInsert = false; @@ -2400,7 +2497,8 @@ CopyFrom(CopyState cstate) for (;;) { - TupleTableSlot *slot; + TupleTableSlot *slot, + *oldslot; bool skip_tuple; Oid loaded_oid = InvalidOid; @@ -2441,6 +2539,71 @@ CopyFrom(CopyState cstate) slot = myslot; ExecStoreTuple(tuple, slot, InvalidBuffer, false); + /* Determine the partition to heap_insert the tuple into */ + oldslot = slot; + if (cstate->partition_dispatch_info) + { + int leaf_part_index; + TupleConversionMap *map; + + /* + * Away we go ... If we end up not finding a partition after all, + * ExecFindPartition() does not return and errors out instead. + * Otherwise, the returned value is to be used as an index into + * arrays mt_partitions[] and mt_partition_tupconv_maps[] that + * will get us the ResultRelInfo and TupleConversionMap for the + * partition, respectively. + */ + leaf_part_index = ExecFindPartition(resultRelInfo, + cstate->partition_dispatch_info, + slot, + estate); + Assert(leaf_part_index >= 0 && + leaf_part_index < cstate->num_partitions); + + /* + * Save the old ResultRelInfo and switch to the one corresponding + * to the selected partition. + */ + saved_resultRelInfo = resultRelInfo; + resultRelInfo = cstate->partitions + leaf_part_index; + + /* We do not yet have a way to insert into a foreign partition */ + if (resultRelInfo->ri_FdwRoutine) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot route inserted tuples to a foreign table"))); + + /* + * For ExecInsertIndexTuples() to work on the partition's indexes + */ + estate->es_result_relation_info = resultRelInfo; + + /* + * We might need to convert from the parent rowtype to the + * partition rowtype. + */ + map = cstate->partition_tupconv_maps[leaf_part_index]; + if (map) + { + Relation partrel = resultRelInfo->ri_RelationDesc; + + tuple = do_convert_tuple(tuple, map); + + /* + * We must use the partition's tuple descriptor from this + * point on. Use a dedicated slot from this point on until + * we're finished dealing with the partition. + */ + slot = cstate->partition_tuple_slot; + Assert(slot != NULL); + ExecSetSlotDescriptor(slot, RelationGetDescr(partrel)); + ExecStoreTuple(tuple, slot, InvalidBuffer, true); + } + + tuple->t_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc); + } + skip_tuple = false; /* BEFORE ROW INSERT Triggers */ @@ -2457,52 +2620,66 @@ CopyFrom(CopyState cstate) if (!skip_tuple) { - /* Check the constraints of the tuple */ - if (cstate->rel->rd_att->constr) - ExecConstraints(resultRelInfo, slot, estate); - - if (useHeapMultiInsert) + if (resultRelInfo->ri_TrigDesc && + resultRelInfo->ri_TrigDesc->trig_insert_instead_row) { - /* Add this tuple to the tuple buffer */ - if (nBufferedTuples == 0) - firstBufferedLineNo = cstate->cur_lineno; - bufferedTuples[nBufferedTuples++] = tuple; - bufferedTuplesSize += tuple->t_len; - - /* - * If the buffer filled up, flush it. Also flush if the total - * size of all the tuples in the buffer becomes large, to - * avoid using large amounts of memory for the buffers when - * the tuples are exceptionally wide. - */ - if (nBufferedTuples == MAX_BUFFERED_TUPLES || - bufferedTuplesSize > 65535) - { - CopyFromInsertBatch(cstate, estate, mycid, hi_options, - resultRelInfo, myslot, bistate, - nBufferedTuples, bufferedTuples, - firstBufferedLineNo); - nBufferedTuples = 0; - bufferedTuplesSize = 0; - } + /* Pass the data to the INSTEAD ROW INSERT trigger */ + ExecIRInsertTriggers(estate, resultRelInfo, slot); } else { - List *recheckIndexes = NIL; + /* Check the constraints of the tuple */ + if (cstate->rel->rd_att->constr || + resultRelInfo->ri_PartitionCheck) + ExecConstraints(resultRelInfo, slot, oldslot, estate); - /* OK, store the tuple and create index entries for it */ - heap_insert(cstate->rel, tuple, mycid, hi_options, bistate); + if (useHeapMultiInsert) + { + /* Add this tuple to the tuple buffer */ + if (nBufferedTuples == 0) + firstBufferedLineNo = cstate->cur_lineno; + bufferedTuples[nBufferedTuples++] = tuple; + bufferedTuplesSize += tuple->t_len; + + /* + * If the buffer filled up, flush it. Also flush if the + * total size of all the tuples in the buffer becomes + * large, to avoid using large amounts of memory for the + * buffer when the tuples are exceptionally wide. + */ + if (nBufferedTuples == MAX_BUFFERED_TUPLES || + bufferedTuplesSize > 65535) + { + CopyFromInsertBatch(cstate, estate, mycid, hi_options, + resultRelInfo, myslot, bistate, + nBufferedTuples, bufferedTuples, + firstBufferedLineNo); + nBufferedTuples = 0; + bufferedTuplesSize = 0; + } + } + else + { + List *recheckIndexes = NIL; + + /* OK, store the tuple and create index entries for it */ + heap_insert(resultRelInfo->ri_RelationDesc, tuple, mycid, + hi_options, bistate); - if (resultRelInfo->ri_NumIndices > 0) - recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self), - estate, false, NULL, - NIL); + if (resultRelInfo->ri_NumIndices > 0) + recheckIndexes = ExecInsertIndexTuples(slot, + &(tuple->t_self), + estate, + false, + NULL, + NIL); - /* AFTER ROW INSERT Triggers */ - ExecARInsertTriggers(estate, resultRelInfo, tuple, - recheckIndexes); + /* AFTER ROW INSERT Triggers */ + ExecARInsertTriggers(estate, resultRelInfo, tuple, + recheckIndexes); - list_free(recheckIndexes); + list_free(recheckIndexes); + } } /* @@ -2511,6 +2688,12 @@ CopyFrom(CopyState cstate) * tuples inserted by an INSERT command. */ processed++; + + if (saved_resultRelInfo) + { + resultRelInfo = saved_resultRelInfo; + estate->es_result_relation_info = resultRelInfo; + } } } @@ -2548,6 +2731,36 @@ CopyFrom(CopyState cstate) ExecCloseIndices(resultRelInfo); + /* Close all the partitioned tables, leaf partitions, and their indices */ + if (cstate->partition_dispatch_info) + { + int i; + + /* + * Remember cstate->partition_dispatch_info[0] corresponds to the root + * partitioned table, which we must not try to close, because it is + * the main target table of COPY that will be closed eventually by + * DoCopy(). Also, tupslot is NULL for the root partitioned table. + */ + for (i = 1; i < cstate->num_dispatch; i++) + { + PartitionDispatch pd = cstate->partition_dispatch_info[i]; + + heap_close(pd->reldesc, NoLock); + ExecDropSingleTupleTableSlot(pd->tupslot); + } + for (i = 0; i < cstate->num_partitions; i++) + { + ResultRelInfo *resultRelInfo = cstate->partitions + i; + + ExecCloseIndices(resultRelInfo); + heap_close(resultRelInfo->ri_RelationDesc, NoLock); + } + + /* Release the standalone partition tuple descriptor */ + ExecDropSingleTupleTableSlot(cstate->partition_tuple_slot); + } + FreeExecutorState(estate); /* @@ -2649,7 +2862,8 @@ CopyFromInsertBatch(CopyState cstate, EState *estate, CommandId mycid, * Returns a CopyState, to be passed to NextCopyFrom and related functions. */ CopyState -BeginCopyFrom(Relation rel, +BeginCopyFrom(ParseState *pstate, + Relation rel, const char *filename, bool is_program, List *attnamelist, @@ -2670,7 +2884,7 @@ BeginCopyFrom(Relation rel, MemoryContext oldcontext; bool volatile_defexprs; - cstate = BeginCopy(true, rel, NULL, NULL, InvalidOid, attnamelist, options); + cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options); oldcontext = MemoryContextSwitchTo(cstate->copycontext); /* Initialize state variables */ @@ -2682,8 +2896,8 @@ BeginCopyFrom(Relation rel, cstate->cur_attval = NULL; /* Set up variables to avoid per-attribute overhead. */ - initStringInfo(&cstate->attribute_buf); - initStringInfo(&cstate->line_buf); + initLongStringInfo(&cstate->attribute_buf); + initLongStringInfo(&cstate->line_buf); cstate->line_buf_converted = false; cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1); cstate->raw_buf_index = cstate->raw_buf_len = 0; @@ -2793,10 +3007,18 @@ BeginCopyFrom(Relation rel, cstate->copy_file = AllocateFile(cstate->filename, PG_BINARY_R); if (cstate->copy_file == NULL) + { + /* copy errno because ereport subfunctions might change it */ + int save_errno = errno; + ereport(ERROR, (errcode_for_file_access(), errmsg("could not open file \"%s\" for reading: %m", - cstate->filename))); + cstate->filename), + (save_errno == ENOENT || save_errno == EACCES) ? + errhint("COPY FROM instructs the PostgreSQL server process to read a file. " + "You may want a client-side facility such as psql's \\copy.") : 0)); + } if (fstat(fileno(cstate->copy_file), &st)) ereport(ERROR, @@ -3172,7 +3394,7 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext, Assert(CurrentMemoryContext == econtext->ecxt_per_tuple_memory); values[defmap[i]] = ExecEvalExpr(defexprs[i], econtext, - &nulls[defmap[i]], NULL); + &nulls[defmap[i]]); } return true; diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c index 5b4f6affcc..cee3b4d50b 100644 --- a/src/backend/commands/createas.c +++ b/src/backend/commands/createas.c @@ -13,7 +13,7 @@ * we must return a tuples-processed count in the completionTag. (We no * longer do that for CTAS ... WITH NO DATA, however.) * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -112,7 +112,7 @@ create_ctas_internal(List *attrList, IntoClause *into) * Create the relation. (This will error out if there's an existing view, * so we don't need more code to complain if "replace" is false.) */ - intoRelationAddr = DefineRelation(create, relkind, InvalidOid, NULL); + intoRelationAddr = DefineRelation(create, relkind, InvalidOid, NULL, NULL); /* * If necessary, create a TOAST table for the target table. Note that @@ -326,7 +326,7 @@ ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString, query = (Query *) linitial(rewritten); Assert(query->commandType == CMD_SELECT); - /* plan the query */ + /* plan the query --- note we disallow parallelism */ plan = pg_plan_query(query, 0, params); /* diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index c1c0223770..6ad8fd77b1 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -8,7 +8,7 @@ * stepping on each others' toes. Formerly we used table-level locks * on pg_database, but that's too coarse-grained. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -37,6 +37,7 @@ #include "catalog/pg_authid.h" #include "catalog/pg_database.h" #include "catalog/pg_db_role_setting.h" +#include "catalog/pg_subscription.h" #include "catalog/pg_tablespace.h" #include "commands/comment.h" #include "commands/dbcommands.h" @@ -96,7 +97,7 @@ static int errdetail_busy_db(int notherbackends, int npreparedxacts); * CREATE DATABASE */ Oid -createdb(const CreatedbStmt *stmt) +createdb(ParseState *pstate, const CreatedbStmt *stmt) { HeapScanDesc scan; Relation rel; @@ -152,7 +153,8 @@ createdb(const CreatedbStmt *stmt) if (dtablespacename) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); dtablespacename = defel; } else if (strcmp(defel->defname, "owner") == 0) @@ -160,7 +162,8 @@ createdb(const CreatedbStmt *stmt) if (downer) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); downer = defel; } else if (strcmp(defel->defname, "template") == 0) @@ -168,7 +171,8 @@ createdb(const CreatedbStmt *stmt) if (dtemplate) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); dtemplate = defel; } else if (strcmp(defel->defname, "encoding") == 0) @@ -176,7 +180,8 @@ createdb(const CreatedbStmt *stmt) if (dencoding) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); dencoding = defel; } else if (strcmp(defel->defname, "lc_collate") == 0) @@ -184,7 +189,8 @@ createdb(const CreatedbStmt *stmt) if (dcollate) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); dcollate = defel; } else if (strcmp(defel->defname, "lc_ctype") == 0) @@ -192,7 +198,8 @@ createdb(const CreatedbStmt *stmt) if (dctype) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); dctype = defel; } else if (strcmp(defel->defname, "is_template") == 0) @@ -200,7 +207,8 @@ createdb(const CreatedbStmt *stmt) if (distemplate) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); distemplate = defel; } else if (strcmp(defel->defname, "allow_connections") == 0) @@ -208,7 +216,8 @@ createdb(const CreatedbStmt *stmt) if (dallowconnections) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); dallowconnections = defel; } else if (strcmp(defel->defname, "connection_limit") == 0) @@ -216,7 +225,8 @@ createdb(const CreatedbStmt *stmt) if (dconnlimit) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); dconnlimit = defel; } else if (strcmp(defel->defname, "location") == 0) @@ -224,12 +234,14 @@ createdb(const CreatedbStmt *stmt) ereport(WARNING, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("LOCATION is not supported anymore"), - errhint("Consider using tablespaces instead."))); + errhint("Consider using tablespaces instead."), + parser_errposition(pstate, defel->location))); } else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("option \"%s\" not recognized", defel->defname))); + errmsg("option \"%s\" not recognized", defel->defname), + parser_errposition(pstate, defel->location))); } if (downer && downer->arg) @@ -249,7 +261,8 @@ createdb(const CreatedbStmt *stmt) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("%d is not a valid encoding code", - encoding))); + encoding), + parser_errposition(pstate, dencoding->location))); } else { @@ -259,7 +272,8 @@ createdb(const CreatedbStmt *stmt) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("%s is not a valid encoding name", - encoding_name))); + encoding_name), + parser_errposition(pstate, dencoding->location))); } } if (dcollate && dcollate->arg) @@ -777,6 +791,7 @@ dropdb(const char *dbname, bool missing_ok) int npreparedxacts; int nslots, nslots_active; + int nsubscriptions; /* * Look up the target database's OID, and get exclusive lock on it. We @@ -861,6 +876,21 @@ dropdb(const char *dbname, bool missing_ok) dbname), errdetail_busy_db(notherbackends, npreparedxacts))); + /* + * Check if there are subscriptions defined in the target database. + * + * We can't drop them automatically because they might be holding + * resources in other databases/instances. + */ + if ((nsubscriptions = CountDBSubscriptions(db_id)) > 0) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_IN_USE), + errmsg("database \"%s\" is being used by logical replication subscription", + dbname), + errdetail_plural("There is %d subscription.", + "There are %d subscriptions.", + nsubscriptions, nsubscriptions))); + /* * Remove the database's tuple from pg_database. */ @@ -1247,7 +1277,7 @@ movedb(const char *dbname, const char *tblspcname) ScanKeyInit(&scankey, Anum_pg_database_datname, BTEqualStrategyNumber, F_NAMEEQ, - NameGetDatum(dbname)); + CStringGetDatum(dbname)); sysscan = systable_beginscan(pgdbrel, DatabaseNameIndexId, true, NULL, 1, &scankey); oldtuple = systable_getnext(sysscan); @@ -1364,7 +1394,7 @@ movedb_failure_callback(int code, Datum arg) * ALTER DATABASE name ... */ Oid -AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel) +AlterDatabase(ParseState *pstate, AlterDatabaseStmt *stmt, bool isTopLevel) { Relation rel; Oid dboid; @@ -1394,7 +1424,8 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel) if (distemplate) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); distemplate = defel; } else if (strcmp(defel->defname, "allow_connections") == 0) @@ -1402,7 +1433,8 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel) if (dallowconnections) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); dallowconnections = defel; } else if (strcmp(defel->defname, "connection_limit") == 0) @@ -1410,7 +1442,8 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel) if (dconnlimit) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); dconnlimit = defel; } else if (strcmp(defel->defname, "tablespace") == 0) @@ -1418,13 +1451,15 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel) if (dtablespace) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); dtablespace = defel; } else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("option \"%s\" not recognized", defel->defname))); + errmsg("option \"%s\" not recognized", defel->defname), + parser_errposition(pstate, defel->location))); } if (dtablespace) @@ -1438,7 +1473,8 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("option \"%s\" cannot be specified with other options", - dtablespace->defname))); + dtablespace->defname), + parser_errposition(pstate, dtablespace->location))); /* this case isn't allowed within a transaction block */ PreventTransactionChain(isTopLevel, "ALTER DATABASE SET TABLESPACE"); movedb(stmt->dbname, defGetString(dtablespace)); @@ -1467,7 +1503,7 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel) ScanKeyInit(&scankey, Anum_pg_database_datname, BTEqualStrategyNumber, F_NAMEEQ, - NameGetDatum(stmt->dbname)); + CStringGetDatum(stmt->dbname)); scan = systable_beginscan(rel, DatabaseNameIndexId, true, NULL, 1, &scankey); tuple = systable_getnext(scan); @@ -1584,7 +1620,7 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId) ScanKeyInit(&scankey, Anum_pg_database_datname, BTEqualStrategyNumber, F_NAMEEQ, - NameGetDatum(dbname)); + CStringGetDatum(dbname)); scan = systable_beginscan(rel, DatabaseNameIndexId, true, NULL, 1, &scankey); tuple = systable_getnext(scan); @@ -1724,7 +1760,7 @@ get_db_info(const char *name, LOCKMODE lockmode, ScanKeyInit(&scanKey, Anum_pg_database_datname, BTEqualStrategyNumber, F_NAMEEQ, - NameGetDatum(name)); + CStringGetDatum(name)); scan = systable_beginscan(relation, DatabaseNameIndexId, true, NULL, 1, &scanKey); diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c index ece803ec4b..8da924517b 100644 --- a/src/backend/commands/define.c +++ b/src/backend/commands/define.c @@ -4,7 +4,7 @@ * Support routines for various kinds of object creation. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -40,7 +40,7 @@ #include "nodes/makefuncs.h" #include "parser/parse_type.h" #include "parser/scansup.h" -#include "utils/int8.h" +#include "utils/builtins.h" /* * Extract a string value (otherwise uninterpreted) from a DefElem. @@ -321,10 +321,29 @@ defGetTypeLength(DefElem *def) } /* - * Create a DefElem setting "oids" to the specified value. + * Extract a list of string values (otherwise uninterpreted) from a DefElem. */ -DefElem * -defWithOids(bool value) +List * +defGetStringList(DefElem *def) { - return makeDefElem("oids", (Node *) makeInteger(value)); + ListCell *cell; + + if (def->arg == NULL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("%s requires a parameter", + def->defname))); + if (nodeTag(def->arg) != T_List) + elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg)); + + foreach(cell, (List *)def->arg) + { + Node *str = (Node *) lfirst(cell); + + if (!IsA(str, String)) + elog(ERROR, "unexpected node type in name list: %d", + (int) nodeTag(str)); + } + + return (List *) def->arg; } diff --git a/src/backend/commands/discard.c b/src/backend/commands/discard.c index 5b8bd67579..f0dcd87fb8 100644 --- a/src/backend/commands/discard.c +++ b/src/backend/commands/discard.c @@ -3,7 +3,7 @@ * discard.c * The implementation of the DISCARD command * - * Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c index 61ff8f2190..8cfbcf43f7 100644 --- a/src/backend/commands/dropcmds.c +++ b/src/backend/commands/dropcmds.c @@ -3,7 +3,7 @@ * dropcmds.c * handle various "DROP" operations * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -441,6 +441,10 @@ does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs) } } break; + case OBJECT_PUBLICATION: + msg = gettext_noop("publication \"%s\" does not exist, skipping"); + name = NameListToString(objname); + break; default: elog(ERROR, "unrecognized object type: %d", (int) objtype); break; diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index 50c89b827b..8125537361 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -3,7 +3,7 @@ * event_trigger.c * PostgreSQL EVENT TRIGGER support code. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -106,11 +106,13 @@ static event_trigger_support_data event_trigger_support[] = { {"OPERATOR CLASS", true}, {"OPERATOR FAMILY", true}, {"POLICY", true}, + {"PUBLICATION", true}, {"ROLE", false}, {"RULE", true}, {"SCHEMA", true}, {"SEQUENCE", true}, {"SERVER", true}, + {"SUBSCRIPTION", true}, {"TABLE", true}, {"TABLESPACE", false}, {"TRANSFORM", true}, @@ -742,7 +744,7 @@ EventTriggerCommonSetup(Node *parsetree, /* * Filter list of event triggers by command tag, and copy them into our - * memory context. Once we start running the command trigers, or indeed + * memory context. Once we start running the command triggers, or indeed * once we do anything at all that touches the catalogs, an invalidation * might leave cachelist pointing at garbage, so we must do this before we * can do much else. @@ -1018,9 +1020,7 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata) */ context = AllocSetContextCreate(CurrentMemoryContext, "event trigger context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldcontext = MemoryContextSwitchTo(context); /* Call each event trigger. */ @@ -1105,9 +1105,12 @@ EventTriggerSupportsObjectType(ObjectType obtype) case OBJECT_OPERATOR: case OBJECT_OPFAMILY: case OBJECT_POLICY: + case OBJECT_PUBLICATION: + case OBJECT_PUBLICATION_REL: case OBJECT_RULE: case OBJECT_SCHEMA: case OBJECT_SEQUENCE: + case OBJECT_SUBSCRIPTION: case OBJECT_TABCONSTRAINT: case OBJECT_TABLE: case OBJECT_TRANSFORM: @@ -1170,6 +1173,9 @@ EventTriggerSupportsObjectClass(ObjectClass objclass) case OCLASS_EXTENSION: case OCLASS_POLICY: case OCLASS_AM: + case OCLASS_PUBLICATION: + case OCLASS_PUBLICATION_REL: + case OCLASS_SUBSCRIPTION: return true; } @@ -1226,9 +1232,7 @@ EventTriggerBeginCompleteQuery(void) cxt = AllocSetContextCreate(TopMemoryContext, "event trigger state", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); state = MemoryContextAlloc(cxt, sizeof(EventTriggerQueryState)); state->cxt = cxt; slist_init(&(state->SQLDropList)); diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 82ba58ef71..f9fb27658f 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -3,7 +3,7 @@ * explain.c * Explain query execution plans * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994-5, Regents of the University of California * * IDENTIFICATION @@ -53,7 +53,8 @@ explain_get_index_name_hook_type explain_get_index_name_hook = NULL; #define X_CLOSE_IMMEDIATE 2 #define X_NOWHITESPACE 4 -static void ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es, +static void ExplainOneQuery(Query *query, int cursorOptions, + IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params); static void report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es); @@ -140,7 +141,7 @@ static void escape_yaml(StringInfo buf, const char *str); * execute an EXPLAIN command */ void -ExplainQuery(ExplainStmt *stmt, const char *queryString, +ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString, ParamListInfo params, DestReceiver *dest) { ExplainState *es = NewExplainState(); @@ -183,13 +184,15 @@ ExplainQuery(ExplainStmt *stmt, const char *queryString, ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unrecognized value for EXPLAIN option \"%s\": \"%s\"", - opt->defname, p))); + opt->defname, p), + parser_errposition(pstate, opt->location))); } else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("unrecognized EXPLAIN option \"%s\"", - opt->defname))); + opt->defname), + parser_errposition(pstate, opt->location))); } if (es->buffers && !es->analyze) @@ -243,7 +246,8 @@ ExplainQuery(ExplainStmt *stmt, const char *queryString, /* Explain every plan */ foreach(l, rewritten) { - ExplainOneQuery((Query *) lfirst(l), NULL, es, + ExplainOneQuery((Query *) lfirst(l), + CURSOR_OPT_PARALLEL_OK, NULL, es, queryString, params); /* Separate plans with an appropriate separator */ @@ -327,7 +331,8 @@ ExplainResultDesc(ExplainStmt *stmt) * "into" is NULL unless we are explaining the contents of a CreateTableAsStmt. */ static void -ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es, +ExplainOneQuery(Query *query, int cursorOptions, + IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params) { /* planner will not cope with utility statements */ @@ -339,7 +344,8 @@ ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es, /* if an advisor plugin is present, let it manage things */ if (ExplainOneQuery_hook) - (*ExplainOneQuery_hook) (query, into, es, queryString, params); + (*ExplainOneQuery_hook) (query, cursorOptions, into, es, + queryString, params); else { PlannedStmt *plan; @@ -349,7 +355,7 @@ ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es, INSTR_TIME_SET_CURRENT(planstart); /* plan the query */ - plan = pg_plan_query(query, into ? 0 : CURSOR_OPT_PARALLEL_OK, params); + plan = pg_plan_query(query, cursorOptions, params); INSTR_TIME_SET_CURRENT(planduration); INSTR_TIME_SUBTRACT(planduration, planstart); @@ -383,6 +389,8 @@ ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, * We have to rewrite the contained SELECT and then pass it back to * ExplainOneQuery. It's probably not really necessary to copy the * contained parsetree another time, but let's be safe. + * + * Like ExecCreateTableAs, disallow parallelism in the plan. */ CreateTableAsStmt *ctas = (CreateTableAsStmt *) utilityStmt; List *rewritten; @@ -390,7 +398,28 @@ ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, Assert(IsA(ctas->query, Query)); rewritten = QueryRewrite((Query *) copyObject(ctas->query)); Assert(list_length(rewritten) == 1); - ExplainOneQuery((Query *) linitial(rewritten), ctas->into, es, + ExplainOneQuery((Query *) linitial(rewritten), + 0, ctas->into, es, + queryString, params); + } + else if (IsA(utilityStmt, DeclareCursorStmt)) + { + /* + * Likewise for DECLARE CURSOR. + * + * Notice that if you say EXPLAIN ANALYZE DECLARE CURSOR then we'll + * actually run the query. This is different from pre-8.3 behavior + * but seems more useful than not running the query. No cursor will + * be created, however. + */ + DeclareCursorStmt *dcs = (DeclareCursorStmt *) utilityStmt; + List *rewritten; + + Assert(IsA(dcs->query, Query)); + rewritten = QueryRewrite((Query *) copyObject(dcs->query)); + Assert(list_length(rewritten) == 1); + ExplainOneQuery((Query *) linitial(rewritten), + dcs->options, NULL, es, queryString, params); } else if (IsA(utilityStmt, ExecuteStmt)) @@ -421,11 +450,6 @@ ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, * "into" is NULL unless we are explaining the contents of a CreateTableAsStmt, * in which case executing the query should result in creating that table. * - * Since we ignore any DeclareCursorStmt that might be attached to the query, - * if you say EXPLAIN ANALYZE DECLARE CURSOR then we'll actually run the - * query. This is different from pre-8.3 behavior but seems more useful than - * not running the query. No cursor will be created, however. - * * This is exported because it's called back from prepare.c in the * EXPLAIN EXECUTE case, and because an index advisor plugin would need * to call it. @@ -442,6 +466,8 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, int eflags; int instrument_option = 0; + Assert(plannedstmt->commandType != CMD_UTILITY); + if (es->analyze && es->timing) instrument_option |= INSTRUMENT_TIMER; else if (es->analyze) @@ -826,6 +852,9 @@ ExplainNode(PlanState *planstate, List *ancestors, case T_Result: pname = sname = "Result"; break; + case T_ProjectSet: + pname = sname = "ProjectSet"; + break; case T_ModifyTable: sname = "ModifyTable"; switch (((ModifyTable *) plan)->operation) @@ -3310,13 +3339,15 @@ ExplainSeparatePlans(ExplainState *es) * Optionally, OR in X_NOWHITESPACE to suppress the whitespace we'd normally * add. * - * XML tag names can't contain white space, so we replace any spaces in - * "tagname" with dashes. + * XML restricts tag names more than our other output formats, eg they can't + * contain white space or slashes. Replace invalid characters with dashes, + * so that for example "I/O Read Time" becomes "I-O-Read-Time". */ static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es) { const char *s; + const char *valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_."; if ((flags & X_NOWHITESPACE) == 0) appendStringInfoSpaces(es->str, 2 * es->indent); @@ -3324,7 +3355,7 @@ ExplainXMLTag(const char *tagname, int flags, ExplainState *es) if ((flags & X_CLOSING) != 0) appendStringInfoCharMacro(es->str, '/'); for (s = tagname; *s; s++) - appendStringInfoCharMacro(es->str, (*s == ' ') ? '-' : *s); + appendStringInfoChar(es->str, strchr(valid, *s) ? *s : '-'); if ((flags & X_CLOSE_IMMEDIATE) != 0) appendStringInfoString(es->str, " /"); appendStringInfoCharMacro(es->str, '>'); diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index 518fefcf09..554fdc46b4 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -12,7 +12,7 @@ * postgresql.conf and recovery.conf. An extension also has an installation * script file, containing SQL commands to create the extension's objects. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -59,6 +59,7 @@ #include "utils/rel.h" #include "utils/snapmgr.h" #include "utils/tqual.h" +#include "utils/varlena.h" /* Globally visible state variables */ @@ -100,14 +101,25 @@ typedef struct ExtensionVersionInfo static List *find_update_path(List *evi_list, ExtensionVersionInfo *evi_start, ExtensionVersionInfo *evi_target, + bool reject_indirect, bool reinitialize); +static Oid get_required_extension(char *reqExtensionName, + char *extensionName, + char *origSchemaName, + bool cascade, + List *parents, + bool is_create); static void get_available_versions_for_extension(ExtensionControlFile *pcontrol, Tuplestorestate *tupstore, TupleDesc tupdesc); +static Datum convert_requires_to_datum(List *requires); static void ApplyExtensionUpdates(Oid extensionOid, ExtensionControlFile *pcontrol, const char *initialVersion, - List *updateVersions); + List *updateVersions, + char *origSchemaName, + bool cascade, + bool is_create); static char *read_whole_file(const char *filename, int *length); @@ -701,7 +713,7 @@ execute_sql_string(const char *sql, const char *filename) */ foreach(lc1, raw_parsetree_list) { - Node *parsetree = (Node *) lfirst(lc1); + RawStmt *parsetree = (RawStmt *) lfirst(lc1); List *stmt_list; ListCell *lc2; @@ -713,23 +725,17 @@ execute_sql_string(const char *sql, const char *filename) foreach(lc2, stmt_list) { - Node *stmt = (Node *) lfirst(lc2); - - if (IsA(stmt, TransactionStmt)) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("transaction control statements are not allowed within an extension script"))); + PlannedStmt *stmt = (PlannedStmt *) lfirst(lc2); CommandCounterIncrement(); PushActiveSnapshot(GetTransactionSnapshot()); - if (IsA(stmt, PlannedStmt) && - ((PlannedStmt *) stmt)->utilityStmt == NULL) + if (stmt->utilityStmt == NULL) { QueryDesc *qdesc; - qdesc = CreateQueryDesc((PlannedStmt *) stmt, + qdesc = CreateQueryDesc(stmt, sql, GetActiveSnapshot(), NULL, dest, NULL, 0); @@ -743,6 +749,11 @@ execute_sql_string(const char *sql, const char *filename) } else { + if (IsA(stmt->utilityStmt, TransactionStmt)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("transaction control statements are not allowed within an extension script"))); + ProcessUtility(stmt, sql, PROCESS_UTILITY_QUERY, @@ -1071,7 +1082,7 @@ identify_update_path(ExtensionControlFile *control, evi_target = get_ext_ver_info(newVersion, &evi_list); /* Find shortest path */ - result = find_update_path(evi_list, evi_start, evi_target, false); + result = find_update_path(evi_list, evi_start, evi_target, false, false); if (result == NIL) ereport(ERROR, @@ -1086,9 +1097,13 @@ identify_update_path(ExtensionControlFile *control, * Apply Dijkstra's algorithm to find the shortest path from evi_start to * evi_target. * + * If reject_indirect is true, ignore paths that go through installable + * versions. This saves work when the caller will consider starting from + * all installable versions anyway. + * * If reinitialize is false, assume the ExtensionVersionInfo list has not * been used for this before, and the initialization done by get_ext_ver_info - * is still good. + * is still good. Otherwise, reinitialize all transient fields used here. * * Result is a List of names of versions to transition through (the initial * version is *not* included). Returns NIL if no such path. @@ -1097,6 +1112,7 @@ static List * find_update_path(List *evi_list, ExtensionVersionInfo *evi_start, ExtensionVersionInfo *evi_target, + bool reject_indirect, bool reinitialize) { List *result; @@ -1105,6 +1121,8 @@ find_update_path(List *evi_list, /* Caller error if start == target */ Assert(evi_start != evi_target); + /* Caller error if reject_indirect and target is installable */ + Assert(!(reject_indirect && evi_target->installable)); if (reinitialize) { @@ -1131,6 +1149,9 @@ find_update_path(List *evi_list, ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc); int newdist; + /* if reject_indirect, treat installable versions as unreachable */ + if (reject_indirect && evi2->installable) + continue; newdist = evi->distance + 1; if (newdist < evi2->distance) { @@ -1166,26 +1187,86 @@ find_update_path(List *evi_list, return result; } +/* + * Given a target version that is not directly installable, find the + * best installation sequence starting from a directly-installable version. + * + * evi_list: previously-collected version update graph + * evi_target: member of that list that we want to reach + * + * Returns the best starting-point version, or NULL if there is none. + * On success, *best_path is set to the path from the start point. + * + * If there's more than one possible start point, prefer shorter update paths, + * and break any ties arbitrarily on the basis of strcmp'ing the starting + * versions' names. + */ +static ExtensionVersionInfo * +find_install_path(List *evi_list, ExtensionVersionInfo *evi_target, + List **best_path) +{ + ExtensionVersionInfo *evi_start = NULL; + ListCell *lc; + + *best_path = NIL; + + /* + * We don't expect to be called for an installable target, but if we are, + * the answer is easy: just start from there, with an empty update path. + */ + if (evi_target->installable) + return evi_target; + + /* Consider all installable versions as start points */ + foreach(lc, evi_list) + { + ExtensionVersionInfo *evi1 = (ExtensionVersionInfo *) lfirst(lc); + List *path; + + if (!evi1->installable) + continue; + + /* + * Find shortest path from evi1 to evi_target; but no need to consider + * paths going through other installable versions. + */ + path = find_update_path(evi_list, evi1, evi_target, true, true); + if (path == NIL) + continue; + + /* Remember best path */ + if (evi_start == NULL || + list_length(path) < list_length(*best_path) || + (list_length(path) == list_length(*best_path) && + strcmp(evi_start->name, evi1->name) < 0)) + { + evi_start = evi1; + *best_path = path; + } + } + + return evi_start; +} + /* * CREATE EXTENSION worker * - * When CASCADE is specified CreateExtensionInternal() recurses if required - * extensions need to be installed. To sanely handle cyclic dependencies - * cascade_parent contains the dependency chain leading to the current - * invocation; thus allowing to error out if there's a cyclic dependency. + * When CASCADE is specified, CreateExtensionInternal() recurses if required + * extensions need to be installed. To sanely handle cyclic dependencies, + * the "parents" list contains a list of names of extensions already being + * installed, allowing us to error out if we recurse to one of those. */ static ObjectAddress -CreateExtensionInternal(CreateExtensionStmt *stmt, List *parents) +CreateExtensionInternal(char *extensionName, + char *schemaName, + char *versionName, + char *oldVersionName, + bool cascade, + List *parents, + bool is_create) { - DefElem *d_schema = NULL; - DefElem *d_new_version = NULL; - DefElem *d_old_version = NULL; - DefElem *d_cascade = NULL; - char *schemaName = NULL; + char *origSchemaName = schemaName; Oid schemaOid = InvalidOid; - char *versionName; - char *oldVersionName; - bool cascade = false; Oid extowner = GetUserId(); ExtensionControlFile *pcontrol; ExtensionControlFile *control; @@ -1193,83 +1274,43 @@ CreateExtensionInternal(CreateExtensionStmt *stmt, List *parents) List *requiredExtensions; List *requiredSchemas; Oid extensionOid; - ListCell *lc; ObjectAddress address; + ListCell *lc; /* * Read the primary control file. Note we assume that it does not contain * any non-ASCII data, so there is no need to worry about encoding at this * point. */ - pcontrol = read_extension_control_file(stmt->extname); - - /* - * Read the statement option list - */ - foreach(lc, stmt->options) - { - DefElem *defel = (DefElem *) lfirst(lc); - - if (strcmp(defel->defname, "schema") == 0) - { - if (d_schema) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); - d_schema = defel; - } - else if (strcmp(defel->defname, "new_version") == 0) - { - if (d_new_version) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); - d_new_version = defel; - } - else if (strcmp(defel->defname, "old_version") == 0) - { - if (d_old_version) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); - d_old_version = defel; - } - else if (strcmp(defel->defname, "cascade") == 0) - { - if (d_cascade) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); - d_cascade = defel; - cascade = defGetBoolean(d_cascade); - } - else - elog(ERROR, "unrecognized option: %s", defel->defname); - } + pcontrol = read_extension_control_file(extensionName); /* * Determine the version to install */ - if (d_new_version && d_new_version->arg) - versionName = strVal(d_new_version->arg); - else if (pcontrol->default_version) - versionName = pcontrol->default_version; - else + if (versionName == NULL) { - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("version to install must be specified"))); - versionName = NULL; /* keep compiler quiet */ + if (pcontrol->default_version) + versionName = pcontrol->default_version; + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("version to install must be specified"))); } check_valid_version_name(versionName); /* - * Determine the (unpackaged) version to update from, if any, and then - * figure out what sequence of update scripts we need to apply. + * Figure out which script(s) we need to run to install the desired + * version of the extension. If we do not have a script that directly + * does what is needed, we try to find a sequence of update scripts that + * will get us there. */ - if (d_old_version && d_old_version->arg) + if (oldVersionName) { - oldVersionName = strVal(d_old_version->arg); + /* + * "FROM old_version" was specified, indicating that we're trying to + * update from some unpackaged version of the extension. Locate a + * series of update scripts that will do it. + */ check_valid_version_name(oldVersionName); if (strcmp(oldVersionName, versionName) == 0) @@ -1304,8 +1345,48 @@ CreateExtensionInternal(CreateExtensionStmt *stmt, List *parents) } else { + /* + * No FROM, so we're installing from scratch. If there is an install + * script for the desired version, we only need to run that one. + */ + char *filename; + struct stat fst; + oldVersionName = NULL; - updateVersions = NIL; + + filename = get_extension_script_filename(pcontrol, NULL, versionName); + if (stat(filename, &fst) == 0) + { + /* Easy, no extra scripts */ + updateVersions = NIL; + } + else + { + /* Look for best way to install this version */ + List *evi_list; + ExtensionVersionInfo *evi_start; + ExtensionVersionInfo *evi_target; + + /* Extract the version update graph from the script directory */ + evi_list = get_ext_ver_list(pcontrol); + + /* Identify the target version */ + evi_target = get_ext_ver_info(versionName, &evi_list); + + /* Identify best path to reach target */ + evi_start = find_install_path(evi_list, evi_target, + &updateVersions); + + /* Fail if no path ... */ + if (evi_start == NULL) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("extension \"%s\" has no installation script nor update path for version \"%s\"", + pcontrol->name, versionName))); + + /* Otherwise, install best starting point and then upgrade */ + versionName = evi_start->name; + } } /* @@ -1316,13 +1397,8 @@ CreateExtensionInternal(CreateExtensionStmt *stmt, List *parents) /* * Determine the target schema to install the extension into */ - if (d_schema && d_schema->arg) + if (schemaName) { - /* - * User given schema, CREATE EXTENSION ... WITH SCHEMA ... - */ - schemaName = strVal(d_schema->arg); - /* If the user is giving us the schema name, it must exist already. */ schemaOid = get_namespace_oid(schemaName, false); } @@ -1358,7 +1434,8 @@ CreateExtensionInternal(CreateExtensionStmt *stmt, List *parents) csstmt->authrole = NULL; /* will be created by current user */ csstmt->schemaElts = NIL; csstmt->if_not_exists = false; - CreateSchemaCommand(csstmt, NULL); + CreateSchemaCommand(csstmt, "(generated CREATE SCHEMA command)", + -1, -1); /* * CreateSchemaCommand includes CommandCounterIncrement, so new @@ -1370,7 +1447,7 @@ CreateExtensionInternal(CreateExtensionStmt *stmt, List *parents) else if (!OidIsValid(schemaOid)) { /* - * Neither user nor author of the extension specified schema, use the + * Neither user nor author of the extension specified schema; use the * current default creation namespace, which is the first explicit * entry in the search_path. */ @@ -1400,8 +1477,8 @@ CreateExtensionInternal(CreateExtensionStmt *stmt, List *parents) */ /* - * Look up the prerequisite extensions, and build lists of their OIDs and - * the OIDs of their target schemas. + * Look up the prerequisite extensions, install them if necessary, and + * build lists of their OIDs and the OIDs of their target schemas. */ requiredExtensions = NIL; requiredSchemas = NIL; @@ -1411,65 +1488,12 @@ CreateExtensionInternal(CreateExtensionStmt *stmt, List *parents) Oid reqext; Oid reqschema; - reqext = get_extension_oid(curreq, true); - if (!OidIsValid(reqext)) - { - if (cascade) - { - CreateExtensionStmt *ces; - ListCell *lc; - ObjectAddress addr; - List *cascade_parents; - - /* Check extension name validity before trying to cascade */ - check_valid_extension_name(curreq); - - /* Check for cyclic dependency between extensions. */ - foreach(lc, parents) - { - char *pname = (char *) lfirst(lc); - - if (strcmp(pname, curreq) == 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_RECURSION), - errmsg("cyclic dependency detected between extensions \"%s\" and \"%s\"", - curreq, stmt->extname))); - } - - ereport(NOTICE, - (errmsg("installing required extension \"%s\"", - curreq))); - - /* Create and execute new CREATE EXTENSION statement. */ - ces = makeNode(CreateExtensionStmt); - ces->extname = curreq; - - /* Propagate the CASCADE option */ - ces->options = list_make1(d_cascade); - - /* Propagate the SCHEMA option if given. */ - if (d_schema && d_schema->arg) - ces->options = lappend(ces->options, d_schema); - - /* - * Pass the current list of parents + the current extension to - * the "child" CreateExtensionInternal(). - */ - cascade_parents = - lappend(list_copy(parents), stmt->extname); - - /* Create the required extension. */ - addr = CreateExtensionInternal(ces, cascade_parents); - reqext = addr.objectId; - } - else - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("required extension \"%s\" is not installed", - curreq), - errhint("Use CREATE EXTENSION ... CASCADE to install required extensions too."))); - } - + reqext = get_required_extension(curreq, + extensionName, + origSchemaName, + cascade, + parents, + is_create); reqschema = get_extension_schema(reqext); requiredExtensions = lappend_oid(requiredExtensions, reqext); requiredSchemas = lappend_oid(requiredSchemas, reqschema); @@ -1505,17 +1529,100 @@ CreateExtensionInternal(CreateExtensionStmt *stmt, List *parents) * though a series of ALTER EXTENSION UPDATE commands were given */ ApplyExtensionUpdates(extensionOid, pcontrol, - versionName, updateVersions); + versionName, updateVersions, + origSchemaName, cascade, is_create); return address; } +/* + * Get the OID of an extension listed in "requires", possibly creating it. + */ +static Oid +get_required_extension(char *reqExtensionName, + char *extensionName, + char *origSchemaName, + bool cascade, + List *parents, + bool is_create) +{ + Oid reqExtensionOid; + + reqExtensionOid = get_extension_oid(reqExtensionName, true); + if (!OidIsValid(reqExtensionOid)) + { + if (cascade) + { + /* Must install it. */ + ObjectAddress addr; + List *cascade_parents; + ListCell *lc; + + /* Check extension name validity before trying to cascade. */ + check_valid_extension_name(reqExtensionName); + + /* Check for cyclic dependency between extensions. */ + foreach(lc, parents) + { + char *pname = (char *) lfirst(lc); + + if (strcmp(pname, reqExtensionName) == 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_RECURSION), + errmsg("cyclic dependency detected between extensions \"%s\" and \"%s\"", + reqExtensionName, extensionName))); + } + + ereport(NOTICE, + (errmsg("installing required extension \"%s\"", + reqExtensionName))); + + /* Add current extension to list of parents to pass down. */ + cascade_parents = lappend(list_copy(parents), extensionName); + + /* + * Create the required extension. We propagate the SCHEMA option + * if any, and CASCADE, but no other options. + */ + addr = CreateExtensionInternal(reqExtensionName, + origSchemaName, + NULL, + NULL, + cascade, + cascade_parents, + is_create); + + /* Get its newly-assigned OID. */ + reqExtensionOid = addr.objectId; + } + else + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("required extension \"%s\" is not installed", + reqExtensionName), + is_create ? + errhint("Use CREATE EXTENSION ... CASCADE to install required extensions too.") : 0)); + } + + return reqExtensionOid; +} + /* * CREATE EXTENSION */ ObjectAddress -CreateExtension(CreateExtensionStmt *stmt) +CreateExtension(ParseState *pstate, CreateExtensionStmt *stmt) { + DefElem *d_schema = NULL; + DefElem *d_new_version = NULL; + DefElem *d_old_version = NULL; + DefElem *d_cascade = NULL; + char *schemaName = NULL; + char *versionName = NULL; + char *oldVersionName = NULL; + bool cascade = false; + ListCell *lc; + /* Check extension name validity before any filesystem access */ check_valid_extension_name(stmt->extname); @@ -1551,9 +1658,63 @@ CreateExtension(CreateExtensionStmt *stmt) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("nested CREATE EXTENSION is not supported"))); + /* Deconstruct the statement option list */ + foreach(lc, stmt->options) + { + DefElem *defel = (DefElem *) lfirst(lc); + + if (strcmp(defel->defname, "schema") == 0) + { + if (d_schema) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); + d_schema = defel; + schemaName = defGetString(d_schema); + } + else if (strcmp(defel->defname, "new_version") == 0) + { + if (d_new_version) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); + d_new_version = defel; + versionName = defGetString(d_new_version); + } + else if (strcmp(defel->defname, "old_version") == 0) + { + if (d_old_version) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); + d_old_version = defel; + oldVersionName = defGetString(d_old_version); + } + else if (strcmp(defel->defname, "cascade") == 0) + { + if (d_cascade) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); + d_cascade = defel; + cascade = defGetBoolean(d_cascade); + } + else + elog(ERROR, "unrecognized option: %s", defel->defname); + } - /* Finally create the extension. */ - return CreateExtensionInternal(stmt, NIL); + /* Call CreateExtensionInternal to do the real work. */ + return CreateExtensionInternal(stmt->extname, + schemaName, + versionName, + oldVersionName, + cascade, + NIL, + true); } /* @@ -1910,43 +2071,28 @@ get_available_versions_for_extension(ExtensionControlFile *pcontrol, Tuplestorestate *tupstore, TupleDesc tupdesc) { - int extnamelen = strlen(pcontrol->name); - char *location; - DIR *dir; - struct dirent *de; + List *evi_list; + ListCell *lc; - location = get_extension_script_directory(pcontrol); - dir = AllocateDir(location); - /* Note this will fail if script directory doesn't exist */ - while ((de = ReadDir(dir, location)) != NULL) + /* Extract the version update graph from the script directory */ + evi_list = get_ext_ver_list(pcontrol); + + /* For each installable version ... */ + foreach(lc, evi_list) { + ExtensionVersionInfo *evi = (ExtensionVersionInfo *) lfirst(lc); ExtensionControlFile *control; - char *vername; Datum values[7]; bool nulls[7]; + ListCell *lc2; - /* must be a .sql file ... */ - if (!is_extension_script_filename(de->d_name)) - continue; - - /* ... matching extension name followed by separator */ - if (strncmp(de->d_name, pcontrol->name, extnamelen) != 0 || - de->d_name[extnamelen] != '-' || - de->d_name[extnamelen + 1] != '-') - continue; - - /* extract version name from 'extname--something.sql' filename */ - vername = pstrdup(de->d_name + extnamelen + 2); - *strrchr(vername, '.') = '\0'; - - /* ignore it if it's an update script */ - if (strstr(vername, "--")) + if (!evi->installable) continue; /* * Fetch parameters for specific version (pcontrol is not changed) */ - control = read_extension_aux_control_file(pcontrol, vername); + control = read_extension_aux_control_file(pcontrol, evi->name); memset(values, 0, sizeof(values)); memset(nulls, 0, sizeof(nulls)); @@ -1955,7 +2101,7 @@ get_available_versions_for_extension(ExtensionControlFile *pcontrol, values[0] = DirectFunctionCall1(namein, CStringGetDatum(control->name)); /* version */ - values[1] = CStringGetTextDatum(vername); + values[1] = CStringGetTextDatum(evi->name); /* superuser */ values[2] = BoolGetDatum(control->superuser); /* relocatable */ @@ -1970,27 +2116,7 @@ get_available_versions_for_extension(ExtensionControlFile *pcontrol, if (control->requires == NIL) nulls[5] = true; else - { - Datum *datums; - int ndatums; - ArrayType *a; - ListCell *lc; - - ndatums = list_length(control->requires); - datums = (Datum *) palloc(ndatums * sizeof(Datum)); - ndatums = 0; - foreach(lc, control->requires) - { - char *curreq = (char *) lfirst(lc); - - datums[ndatums++] = - DirectFunctionCall1(namein, CStringGetDatum(curreq)); - } - a = construct_array(datums, ndatums, - NAMEOID, - NAMEDATALEN, false, 'c'); - values[5] = PointerGetDatum(a); - } + values[5] = convert_requires_to_datum(control->requires); /* comment */ if (control->comment == NULL) nulls[6] = true; @@ -1998,9 +2124,75 @@ get_available_versions_for_extension(ExtensionControlFile *pcontrol, values[6] = CStringGetTextDatum(control->comment); tuplestore_putvalues(tupstore, tupdesc, values, nulls); + + /* + * Find all non-directly-installable versions that would be installed + * starting from this version, and report them, inheriting the + * parameters that aren't changed in updates from this version. + */ + foreach(lc2, evi_list) + { + ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc2); + List *best_path; + + if (evi2->installable) + continue; + if (find_install_path(evi_list, evi2, &best_path) == evi) + { + /* + * Fetch parameters for this version (pcontrol is not changed) + */ + control = read_extension_aux_control_file(pcontrol, evi2->name); + + /* name stays the same */ + /* version */ + values[1] = CStringGetTextDatum(evi2->name); + /* superuser */ + values[2] = BoolGetDatum(control->superuser); + /* relocatable */ + values[3] = BoolGetDatum(control->relocatable); + /* schema stays the same */ + /* requires */ + if (control->requires == NIL) + nulls[5] = true; + else + { + values[5] = convert_requires_to_datum(control->requires); + nulls[5] = false; + } + /* comment stays the same */ + + tuplestore_putvalues(tupstore, tupdesc, values, nulls); + } + } } +} - FreeDir(dir); +/* + * Convert a list of extension names to a name[] Datum + */ +static Datum +convert_requires_to_datum(List *requires) +{ + Datum *datums; + int ndatums; + ArrayType *a; + ListCell *lc; + + ndatums = list_length(requires); + datums = (Datum *) palloc(ndatums * sizeof(Datum)); + ndatums = 0; + foreach(lc, requires) + { + char *curreq = (char *) lfirst(lc); + + datums[ndatums++] = + DirectFunctionCall1(namein, CStringGetDatum(curreq)); + } + a = construct_array(datums, ndatums, + NAMEOID, + NAMEDATALEN, false, 'c'); + return PointerGetDatum(a); } /* @@ -2072,7 +2264,7 @@ pg_extension_update_paths(PG_FUNCTION_ARGS) continue; /* Find shortest path from evi1 to evi2 */ - path = find_update_path(evi_list, evi1, evi2, true); + path = find_update_path(evi_list, evi1, evi2, false, true); /* Emit result row */ memset(values, 0, sizeof(values)); @@ -2671,7 +2863,7 @@ AlterExtensionNamespace(List *names, const char *newschema, Oid *oldschema) * Execute ALTER EXTENSION UPDATE */ ObjectAddress -ExecAlterExtensionStmt(AlterExtensionStmt *stmt) +ExecAlterExtensionStmt(ParseState *pstate, AlterExtensionStmt *stmt) { DefElem *d_new_version = NULL; char *versionName; @@ -2757,7 +2949,8 @@ ExecAlterExtensionStmt(AlterExtensionStmt *stmt) if (d_new_version) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); d_new_version = defel; } else @@ -2803,7 +2996,8 @@ ExecAlterExtensionStmt(AlterExtensionStmt *stmt) * time */ ApplyExtensionUpdates(extensionOid, control, - oldVersionName, updateVersions); + oldVersionName, updateVersions, + NULL, false, false); ObjectAddressSet(address, ExtensionRelationId, extensionOid); @@ -2822,7 +3016,10 @@ static void ApplyExtensionUpdates(Oid extensionOid, ExtensionControlFile *pcontrol, const char *initialVersion, - List *updateVersions) + List *updateVersions, + char *origSchemaName, + bool cascade, + bool is_create) { const char *oldVersionName = initialVersion; ListCell *lcv; @@ -2901,8 +3098,9 @@ ApplyExtensionUpdates(Oid extensionOid, heap_close(extRel, RowExclusiveLock); /* - * Look up the prerequisite extensions for this version, and build - * lists of their OIDs and the OIDs of their target schemas. + * Look up the prerequisite extensions for this version, install them + * if necessary, and build lists of their OIDs and the OIDs of their + * target schemas. */ requiredExtensions = NIL; requiredSchemas = NIL; @@ -2912,16 +3110,12 @@ ApplyExtensionUpdates(Oid extensionOid, Oid reqext; Oid reqschema; - /* - * We intentionally don't use get_extension_oid's default error - * message here, because it would be confusing in this context. - */ - reqext = get_extension_oid(curreq, true); - if (!OidIsValid(reqext)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("required extension \"%s\" is not installed", - curreq))); + reqext = get_required_extension(curreq, + control->name, + origSchemaName, + cascade, + NIL, + is_create); reqschema = get_extension_schema(reqext); requiredExtensions = lappend_oid(requiredExtensions, reqext); requiredSchemas = lappend_oid(requiredSchemas, reqschema); diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c index eb531afd49..476a023ec5 100644 --- a/src/backend/commands/foreigncmds.c +++ b/src/backend/commands/foreigncmds.c @@ -3,7 +3,7 @@ * foreigncmds.c * foreign-data wrapper/server creation/manipulation commands * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -1572,7 +1572,9 @@ ImportForeignSchema(ImportForeignSchemaStmt *stmt) */ foreach(lc2, raw_parsetree_list) { - CreateForeignTableStmt *cstmt = lfirst(lc2); + RawStmt *rs = (RawStmt *) lfirst(lc2); + CreateForeignTableStmt *cstmt = (CreateForeignTableStmt *) rs->stmt; + PlannedStmt *pstmt; /* * Because we only allow CreateForeignTableStmt, we can skip parse @@ -1593,8 +1595,16 @@ ImportForeignSchema(ImportForeignSchemaStmt *stmt) /* Ensure creation schema is the one given in IMPORT statement */ cstmt->base.relation->schemaname = pstrdup(stmt->local_schema); + /* No planning needed, just make a wrapper PlannedStmt */ + pstmt = makeNode(PlannedStmt); + pstmt->commandType = CMD_UTILITY; + pstmt->canSetTag = false; + pstmt->utilityStmt = (Node *) cstmt; + pstmt->stmt_location = rs->stmt_location; + pstmt->stmt_len = rs->stmt_len; + /* Execute statement */ - ProcessUtility((Node *) cstmt, + ProcessUtility(pstmt, cmd, PROCESS_UTILITY_SUBCOMMAND, NULL, None_Receiver, NULL); diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index 748c8f75d4..22aecb24f9 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -5,7 +5,7 @@ * Routines for CREATE and DROP FUNCTION commands and CREATE and DROP * CAST commands. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -167,7 +167,6 @@ compute_return_type(TypeName *returnType, Oid languageOid, * parameters: list of FunctionParameter structs * languageOid: OID of function language (InvalidOid if it's CREATE AGGREGATE) * is_aggregate: needed only to determine error handling - * queryString: likewise, needed only for error handling * * Results are stored into output parameters. parameterTypes must always * be created, but the other arrays are set to NULL if not needed. @@ -177,10 +176,10 @@ compute_return_type(TypeName *returnType, Oid languageOid, * else it is set to the OID of the implied result type. */ void -interpret_function_parameter_list(List *parameters, +interpret_function_parameter_list(ParseState *pstate, + List *parameters, Oid languageOid, bool is_aggregate, - const char *queryString, oidvector **parameterTypes, ArrayType **allParameterTypes, ArrayType **parameterModes, @@ -201,7 +200,6 @@ interpret_function_parameter_list(List *parameters, bool have_defaults = false; ListCell *x; int i; - ParseState *pstate; *variadicArgType = InvalidOid; /* default result */ *requiredResultType = InvalidOid; /* default result */ @@ -212,10 +210,6 @@ interpret_function_parameter_list(List *parameters, paramNames = (Datum *) palloc0(parameterCount * sizeof(Datum)); *parameterDefaults = NIL; - /* may need a pstate for parse analysis of default exprs */ - pstate = make_parsestate(NULL); - pstate->p_sourcetext = queryString; - /* Scan the list and extract data into work arrays */ i = 0; foreach(x, parameters) @@ -413,8 +407,6 @@ interpret_function_parameter_list(List *parameters, i++; } - free_parsestate(pstate); - /* Now construct the proper outputs as needed */ *parameterTypes = buildoidvector(inTypes, inCount); @@ -458,7 +450,8 @@ interpret_function_parameter_list(List *parameters, * SET parameters though --- if you're redundant, the last one wins.) */ static bool -compute_common_attribute(DefElem *defel, +compute_common_attribute(ParseState *pstate, + DefElem *defel, DefElem **volatility_item, DefElem **strict_item, DefElem **security_item, @@ -530,7 +523,8 @@ compute_common_attribute(DefElem *defel, duplicate_error: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); return false; /* keep compiler quiet */ } @@ -609,7 +603,8 @@ update_proconfig_value(ArrayType *a, List *set_items) * attributes. */ static void -compute_attributes_sql_style(List *options, +compute_attributes_sql_style(ParseState *pstate, + List *options, List **as, char **language, Node **transform, @@ -646,7 +641,8 @@ compute_attributes_sql_style(List *options, if (as_item) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); as_item = defel; } else if (strcmp(defel->defname, "language") == 0) @@ -654,7 +650,8 @@ compute_attributes_sql_style(List *options, if (language_item) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); language_item = defel; } else if (strcmp(defel->defname, "transform") == 0) @@ -662,7 +659,8 @@ compute_attributes_sql_style(List *options, if (transform_item) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); transform_item = defel; } else if (strcmp(defel->defname, "window") == 0) @@ -670,10 +668,12 @@ compute_attributes_sql_style(List *options, if (windowfunc_item) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); windowfunc_item = defel; } - else if (compute_common_attribute(defel, + else if (compute_common_attribute(pstate, + defel, &volatility_item, &strict_item, &security_item, @@ -763,7 +763,7 @@ compute_attributes_sql_style(List *options, *------------ */ static void -compute_attributes_with_style(List *parameters, bool *isStrict_p, char *volatility_p) +compute_attributes_with_style(ParseState *pstate, List *parameters, bool *isStrict_p, char *volatility_p) { ListCell *pl; @@ -783,7 +783,8 @@ compute_attributes_with_style(List *parameters, bool *isStrict_p, char *volatili ereport(WARNING, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("unrecognized function attribute \"%s\" ignored", - param->defname))); + param->defname), + parser_errposition(pstate, param->location))); } } @@ -858,7 +859,7 @@ interpret_AS_clause(Oid languageOid, const char *languageName, * Execute a CREATE FUNCTION utility statement. */ ObjectAddress -CreateFunction(CreateFunctionStmt *stmt, const char *queryString) +CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt) { char *probin_str; char *prosrc_str; @@ -915,7 +916,8 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString) parallel = PROPARALLEL_UNSAFE; /* override attributes from explicit list */ - compute_attributes_sql_style(stmt->options, + compute_attributes_sql_style(pstate, + stmt->options, &as_clause, &language, &transformDefElem, &isWindowFunc, &volatility, &isStrict, &security, &isLeakProof, @@ -987,10 +989,10 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString) * Convert remaining parameters of CREATE to form wanted by * ProcedureCreate. */ - interpret_function_parameter_list(stmt->parameters, + interpret_function_parameter_list(pstate, + stmt->parameters, languageOid, false, /* not an aggregate */ - queryString, ¶meterTypes, &allParameterTypes, ¶meterModes, @@ -1045,7 +1047,7 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString) trftypes = NULL; } - compute_attributes_with_style(stmt->withClause, &isStrict, &volatility); + compute_attributes_with_style(pstate, stmt->withClause, &isStrict, &volatility); interpret_AS_clause(languageOid, language, funcname, as_clause, &prosrc_str, &probin_str); @@ -1163,7 +1165,7 @@ RemoveFunctionById(Oid funcOid) * ALTER framework). */ ObjectAddress -AlterFunction(AlterFunctionStmt *stmt) +AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt) { HeapTuple tup; Oid funcOid; @@ -1208,7 +1210,8 @@ AlterFunction(AlterFunctionStmt *stmt) { DefElem *defel = (DefElem *) lfirst(l); - if (compute_common_attribute(defel, + if (compute_common_attribute(pstate, + defel, &volatility_item, &strict_item, &security_def_item, @@ -1479,11 +1482,13 @@ CreateCast(CreateCastStmt *stmt) if (nargs > 1 && procstruct->proargtypes.values[1] != INT4OID) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("second argument of cast function must be type integer"))); + errmsg("second argument of cast function must be type %s", + "integer"))); if (nargs > 2 && procstruct->proargtypes.values[2] != BOOLOID) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("third argument of cast function must be type boolean"))); + errmsg("third argument of cast function must be type %s", + "boolean"))); if (!IsBinaryCoercible(procstruct->prorettype, targettypeid)) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), @@ -1773,7 +1778,8 @@ check_transform_function(Form_pg_proc procstruct) if (procstruct->proargtypes.values[0] != INTERNALOID) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("first argument of transform function must be type \"internal\""))); + errmsg("first argument of transform function must be type %s", + "internal"))); } @@ -1856,7 +1862,8 @@ CreateTransform(CreateTransformStmt *stmt) if (procstruct->prorettype != INTERNALOID) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("return data type of FROM SQL function must be \"internal\""))); + errmsg("return data type of FROM SQL function must be %s", + "internal"))); check_transform_function(procstruct); ReleaseSysCache(tuple); } diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index d14d540b26..ed6136c153 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -3,7 +3,7 @@ * indexcmds.c * POSTGRES define and remove index code. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -51,6 +51,7 @@ #include "utils/inval.h" #include "utils/lsyscache.h" #include "utils/memutils.h" +#include "utils/regproc.h" #include "utils/snapmgr.h" #include "utils/syscache.h" #include "utils/tqual.h" @@ -69,8 +70,6 @@ static void ComputeIndexAttrs(IndexInfo *indexInfo, char *accessMethodName, Oid accessMethodId, bool amcanorder, bool isconstraint); -static Oid GetIndexOpClass(List *opclass, Oid attrType, - char *accessMethodName, Oid accessMethodId); static char *ChooseIndexName(const char *tabname, Oid namespaceId, List *colnames, List *exclusionOpNames, bool primary, bool isconstraint); @@ -383,6 +382,11 @@ DefineIndex(Oid relationId, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot create index on foreign table \"%s\"", RelationGetRelationName(rel)))); + else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot create index on partitioned table \"%s\"", + RelationGetRelationName(rel)))); else ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), @@ -1145,10 +1149,10 @@ ComputeIndexAttrs(IndexInfo *indexInfo, /* * Identify the opclass to use. */ - classOidP[attn] = GetIndexOpClass(attribute->opclass, - atttype, - accessMethodName, - accessMethodId); + classOidP[attn] = ResolveOpClass(attribute->opclass, + atttype, + accessMethodName, + accessMethodId); /* * Identify the exclusion operator, if any. @@ -1255,10 +1259,13 @@ ComputeIndexAttrs(IndexInfo *indexInfo, /* * Resolve possibly-defaulted operator class specification + * + * Note: This is used to resolve operator class specification in index and + * partition key definitions. */ -static Oid -GetIndexOpClass(List *opclass, Oid attrType, - char *accessMethodName, Oid accessMethodId) +Oid +ResolveOpClass(List *opclass, Oid attrType, + char *accessMethodName, Oid accessMethodId) { char *schemaname; char *opcname; @@ -1903,9 +1910,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind, */ private_context = AllocSetContextCreate(PortalContext, "ReindexMultipleTables", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_SMALL_SIZES); /* * Define the search keys to find the objects to reindex. For a schema, we diff --git a/src/backend/commands/lockcmds.c b/src/backend/commands/lockcmds.c index 175d1f3f2e..9fe9e022b0 100644 --- a/src/backend/commands/lockcmds.c +++ b/src/backend/commands/lockcmds.c @@ -3,7 +3,7 @@ * lockcmds.c * LOCK command support code * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -14,7 +14,6 @@ */ #include "postgres.h" -#include "access/heapam.h" #include "catalog/namespace.h" #include "catalog/pg_inherits_fn.h" #include "commands/lockcmds.h" @@ -55,7 +54,7 @@ LockTableCommand(LockStmt *lockstmt) foreach(p, lockstmt->relations) { RangeVar *rv = (RangeVar *) lfirst(p); - bool recurse = interpretInhOption(rv->inhOpt); + bool recurse = rv->inh; Oid reloid; reloid = RangeVarGetRelidExtended(rv, lockstmt->mode, false, @@ -88,7 +87,7 @@ RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid, * check */ /* Currently, we only allow plain tables to be locked */ - if (relkind != RELKIND_RELATION) + if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table", diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c index 6cddcbd02c..6b5a9b6fe8 100644 --- a/src/backend/commands/matview.c +++ b/src/backend/commands/matview.c @@ -3,7 +3,7 @@ * matview.c * materialized view support * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c index f4dfdb9642..c28be08bc9 100644 --- a/src/backend/commands/opclasscmds.c +++ b/src/backend/commands/opclasscmds.c @@ -4,7 +4,7 @@ * * Routines for opclass (and opfamily) manipulation commands * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -1589,6 +1589,58 @@ RemoveOpFamilyById(Oid opfamilyOid) heap_close(rel, RowExclusiveLock); } +Oid +get_family_oid(const char *opfname, const char *nspname, const char *ammth) +{ + Oid nspoid, + amoid, + opfoid = InvalidOid; + HeapTuple htup = NULL; + + nspoid = LookupNamespaceNoError(nspname); + amoid = get_am_oid(ammth, false); + + if (OidIsValid(nspoid) && OidIsValid(amoid)) + htup = SearchSysCache3(OPFAMILYAMNAMENSP, + ObjectIdGetDatum(amoid), + PointerGetDatum(opfname), + ObjectIdGetDatum(nspoid)); + + if (HeapTupleIsValid(htup)) + { + opfoid = HeapTupleGetOid(htup); + ReleaseSysCache(htup); + } + + return opfoid; +} + +char * +get_opfamily_name(Oid opfamilyOid, char **nspname, char **opfmethod) +{ + HeapTuple tup; + char *opfname; + Oid nspoid, + mthoid; + + Assert(nspname != NULL); + + + tup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamilyOid)); + if (!HeapTupleIsValid(tup)) /* should not happen */ + elog(ERROR, "cache lookup failed for opfamily %u", opfamilyOid); + + opfname = pstrdup(NameStr(((Form_pg_opfamily) GETSTRUCT(tup))->opfname)); + nspoid = ((Form_pg_opfamily) GETSTRUCT(tup))->opfnamespace; + *nspname = get_namespace_name(nspoid); + + mthoid = ((Form_pg_opfamily) GETSTRUCT(tup))->opfmethod; + *opfmethod = get_am_name(mthoid); + + ReleaseSysCache(tup); + return opfname; +} + void RemoveOpClassById(Oid opclassOid) { diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c index 67d08d862b..a273376e21 100644 --- a/src/backend/commands/operatorcmds.c +++ b/src/backend/commands/operatorcmds.c @@ -4,7 +4,7 @@ * * Routines for operator manipulation commands * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c index bc2e4af82a..5d9d3a6a05 100644 --- a/src/backend/commands/policy.c +++ b/src/backend/commands/policy.c @@ -3,7 +3,7 @@ * policy.c * Commands for manipulating policies. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/commands/policy.c @@ -88,7 +88,7 @@ RangeVarCallbackForPolicy(const RangeVar *rv, Oid relid, Oid oldrelid, rv->relname))); /* Relation type MUST be a table. */ - if (relkind != RELKIND_RELATION) + if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table", rv->relname))); @@ -177,7 +177,7 @@ policy_role_list_to_array(List *roles, int *num_roles) } else role_oids[i++] = - ObjectIdGetDatum(get_rolespec_oid((Node *) spec, false)); + ObjectIdGetDatum(get_rolespec_oid(spec, false)); } return role_oids; @@ -201,9 +201,7 @@ RelationBuildRowSecurity(Relation relation) */ rscxt = AllocSetContextCreate(CacheMemoryContext, "row security descriptor", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MAXSIZE); + ALLOCSET_SMALL_SIZES); /* * Since rscxt lives under CacheMemoryContext, it is long-lived. Use a @@ -237,6 +235,7 @@ RelationBuildRowSecurity(Relation relation) { Datum value_datum; char cmd_value; + bool permissive_value; Datum roles_datum; char *qual_value; Expr *qual_expr; @@ -259,6 +258,12 @@ RelationBuildRowSecurity(Relation relation) Assert(!isnull); cmd_value = DatumGetChar(value_datum); + /* Get policy permissive or restrictive */ + value_datum = heap_getattr(tuple, Anum_pg_policy_polpermissive, + RelationGetDescr(catalog), &isnull); + Assert(!isnull); + permissive_value = DatumGetBool(value_datum); + /* Get policy name */ value_datum = heap_getattr(tuple, Anum_pg_policy_polname, RelationGetDescr(catalog), &isnull); @@ -300,6 +305,7 @@ RelationBuildRowSecurity(Relation relation) policy = palloc0(sizeof(RowSecurityPolicy)); policy->policy_name = pstrdup(policy_name_value); policy->polcmd = cmd_value; + policy->permissive = permissive_value; policy->roles = DatumGetArrayTypePCopy(roles_datum); policy->qual = copyObject(qual_expr); policy->with_check_qual = copyObject(with_check_qual); @@ -378,7 +384,8 @@ RemovePolicyById(Oid policy_id) relid = ((Form_pg_policy) GETSTRUCT(tuple))->polrelid; rel = heap_open(relid, AccessExclusiveLock); - if (rel->rd_rel->relkind != RELKIND_RELATION) + if (rel->rd_rel->relkind != RELKIND_RELATION && + rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table", @@ -798,6 +805,7 @@ CreatePolicy(CreatePolicyStmt *stmt) values[Anum_pg_policy_polname - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->policy_name)); values[Anum_pg_policy_polcmd - 1] = CharGetDatum(polcmd); + values[Anum_pg_policy_polpermissive - 1] = BoolGetDatum(stmt->permissive); values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids); /* Add qual if present. */ diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c index e52830f7ec..1d3e39299b 100644 --- a/src/backend/commands/portalcmds.c +++ b/src/backend/commands/portalcmds.c @@ -9,7 +9,7 @@ * storage management for portals (but doesn't run any queries in them). * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -27,7 +27,9 @@ #include "commands/portalcmds.h" #include "executor/executor.h" #include "executor/tstoreReceiver.h" +#include "rewrite/rewriteHandler.h" #include "tcop/pquery.h" +#include "tcop/tcopprot.h" #include "utils/memutils.h" #include "utils/snapmgr.h" @@ -35,21 +37,18 @@ /* * PerformCursorOpen * Execute SQL DECLARE CURSOR command. - * - * The query has already been through parse analysis, rewriting, and planning. - * When it gets here, it looks like a SELECT PlannedStmt, except that the - * utilityStmt field is set. */ void -PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params, +PerformCursorOpen(DeclareCursorStmt *cstmt, ParamListInfo params, const char *queryString, bool isTopLevel) { - DeclareCursorStmt *cstmt = (DeclareCursorStmt *) stmt->utilityStmt; + Query *query = (Query *) cstmt->query; + List *rewritten; + PlannedStmt *plan; Portal portal; MemoryContext oldContext; - if (cstmt == NULL || !IsA(cstmt, DeclareCursorStmt)) - elog(ERROR, "PerformCursorOpen called for non-cursor query"); + Assert(IsA(query, Query)); /* else parse analysis wasn't done */ /* * Disallow empty-string cursor name (conflicts with protocol-level @@ -68,6 +67,32 @@ PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params, if (!(cstmt->options & CURSOR_OPT_HOLD)) RequireTransactionChain(isTopLevel, "DECLARE CURSOR"); + /* + * Parse analysis was done already, but we still have to run the rule + * rewriter. We do not do AcquireRewriteLocks: we assume the query either + * came straight from the parser, or suitable locks were acquired by + * plancache.c. + * + * Because the rewriter and planner tend to scribble on the input, we make + * a preliminary copy of the source querytree. This prevents problems in + * the case that the DECLARE CURSOR is in a portal or plpgsql function and + * is executed repeatedly. (See also the same hack in EXPLAIN and + * PREPARE.) XXX FIXME someday. + */ + rewritten = QueryRewrite((Query *) copyObject(query)); + + /* SELECT should never rewrite to more or less than one query */ + if (list_length(rewritten) != 1) + elog(ERROR, "non-SELECT statement in DECLARE CURSOR"); + + query = (Query *) linitial(rewritten); + + if (query->commandType != CMD_SELECT) + elog(ERROR, "non-SELECT statement in DECLARE CURSOR"); + + /* Plan the query, applying the specified options */ + plan = pg_plan_query(query, cstmt->options, params); + /* * Create a portal and copy the plan and queryString into its memory. */ @@ -75,8 +100,7 @@ PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params, oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal)); - stmt = copyObject(stmt); - stmt->utilityStmt = NULL; /* make it look like plain SELECT */ + plan = copyObject(plan); queryString = pstrdup(queryString); @@ -84,7 +108,7 @@ PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params, NULL, queryString, "SELECT", /* cursor's query is always a SELECT */ - list_make1(stmt), + list_make1(plan), NULL); /*---------- @@ -111,8 +135,8 @@ PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params, portal->cursorOptions = cstmt->options; if (!(portal->cursorOptions & (CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL))) { - if (stmt->rowMarks == NIL && - ExecSupportsBackwardScan(stmt->planTree)) + if (plan->rowMarks == NIL && + ExecSupportsBackwardScan(plan->planTree)) portal->cursorOptions |= CURSOR_OPT_SCROLL; else portal->cursorOptions |= CURSOR_OPT_NO_SCROLL; diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index cec37ce040..7d7e3daf1e 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -7,7 +7,7 @@ * accessed via the extended FE/BE query protocol. * * - * Copyright (c) 2002-2016, PostgreSQL Global Development Group + * Copyright (c) 2002-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/commands/prepare.c @@ -52,8 +52,10 @@ static Datum build_regtype_array(Oid *param_types, int num_params); * Implements the 'PREPARE' utility statement. */ void -PrepareQuery(PrepareStmt *stmt, const char *queryString) +PrepareQuery(PrepareStmt *stmt, const char *queryString, + int stmt_location, int stmt_len) { + RawStmt *rawstmt; CachedPlanSource *plansource; Oid *argtypes = NULL; int nargs; @@ -70,11 +72,23 @@ PrepareQuery(PrepareStmt *stmt, const char *queryString) (errcode(ERRCODE_INVALID_PSTATEMENT_DEFINITION), errmsg("invalid statement name: must not be empty"))); + /* + * Need to wrap the contained statement in a RawStmt node to pass it to + * parse analysis. + * + * Because parse analysis scribbles on the raw querytree, we must make a + * copy to ensure we don't modify the passed-in tree. FIXME someday. + */ + rawstmt = makeNode(RawStmt); + rawstmt->stmt = (Node *) copyObject(stmt->query); + rawstmt->stmt_location = stmt_location; + rawstmt->stmt_len = stmt_len; + /* * Create the CachedPlanSource before we do parse analysis, since it needs * to see the unmodified raw parse tree. */ - plansource = CreateCachedPlan(stmt->query, queryString, + plansource = CreateCachedPlan(rawstmt, queryString, CreateCommandTag(stmt->query)); /* Transform list of TypeNames to array of type OIDs */ @@ -108,12 +122,8 @@ PrepareQuery(PrepareStmt *stmt, const char *queryString) * Analyze the statement using these parameter types (any parameters * passed in from above us will not be visible to it), allowing * information about unknown parameters to be deduced from context. - * - * Because parse analysis scribbles on the raw querytree, we must make a - * copy to ensure we don't modify the passed-in tree. FIXME someday. */ - query = parse_analyze_varparams((Node *) copyObject(stmt->query), - queryString, + query = parse_analyze_varparams(rawstmt, queryString, &argtypes, &nargs); /* @@ -159,7 +169,7 @@ PrepareQuery(PrepareStmt *stmt, const char *queryString) nargs, NULL, NULL, - 0, /* default cursor options */ + CURSOR_OPT_PARALLEL_OK, /* allow parallel mode */ true); /* fixed result */ /* @@ -256,9 +266,8 @@ ExecuteQuery(ExecuteStmt *stmt, IntoClause *intoClause, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("prepared statement is not a SELECT"))); pstmt = (PlannedStmt *) linitial(plan_list); - if (!IsA(pstmt, PlannedStmt) || - pstmt->commandType != CMD_SELECT || - pstmt->utilityStmt != NULL) + Assert(IsA(pstmt, PlannedStmt)); + if (pstmt->commandType != CMD_SELECT) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("prepared statement is not a SELECT"))); @@ -404,8 +413,7 @@ EvaluateParams(PreparedStatement *pstmt, List *params, prm->pflags = PARAM_FLAG_CONST; prm->value = ExecEvalExprSwitchContext(n, GetPerTupleExprContext(estate), - &prm->isnull, - NULL); + &prm->isnull); i++; } @@ -664,10 +672,11 @@ ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into, ExplainState *es, { PlannedStmt *pstmt = (PlannedStmt *) lfirst(p); - if (IsA(pstmt, PlannedStmt)) + Assert(IsA(pstmt, PlannedStmt)); + if (pstmt->commandType != CMD_UTILITY) ExplainOnePlan(pstmt, into, es, query_string, paramLI, NULL); else - ExplainOneUtility((Node *) pstmt, into, es, query_string, paramLI); + ExplainOneUtility(pstmt->utilityStmt, into, es, query_string, paramLI); /* No need for CommandCounterIncrement, as ExplainOnePlan did it */ diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c index 761d08f604..b684f413c0 100644 --- a/src/backend/commands/proclang.c +++ b/src/backend/commands/proclang.c @@ -3,7 +3,7 @@ * proclang.c * PostgreSQL PROCEDURAL LANGUAGE support code. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -278,8 +278,9 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) { ereport(WARNING, (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("changing return type of function %s from \"opaque\" to \"language_handler\"", - NameListToString(stmt->plhandler)))); + errmsg("changing return type of function %s from %s to %s", + NameListToString(stmt->plhandler), + "opaque", "language_handler"))); SetFunctionReturnType(handlerOid, LANGUAGE_HANDLEROID); } else @@ -463,7 +464,7 @@ find_language_template(const char *languageName) ScanKeyInit(&key, Anum_pg_pltemplate_tmplname, BTEqualStrategyNumber, F_NAMEEQ, - NameGetDatum(languageName)); + CStringGetDatum(languageName)); scan = systable_beginscan(rel, PLTemplateNameIndexId, true, NULL, 1, &key); diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c new file mode 100644 index 0000000000..63dcc10bd3 --- /dev/null +++ b/src/backend/commands/publicationcmds.c @@ -0,0 +1,756 @@ +/*------------------------------------------------------------------------- + * + * publicationcmds.c + * publication manipulation + * + * Copyright (c) 2016, PostgreSQL Global Development Group + * + * IDENTIFICATION + * publicationcmds.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "funcapi.h" +#include "miscadmin.h" + +#include "access/genam.h" +#include "access/hash.h" +#include "access/heapam.h" +#include "access/htup_details.h" +#include "access/xact.h" + +#include "catalog/catalog.h" +#include "catalog/indexing.h" +#include "catalog/namespace.h" +#include "catalog/objectaccess.h" +#include "catalog/objectaddress.h" +#include "catalog/pg_inherits_fn.h" +#include "catalog/pg_type.h" +#include "catalog/pg_publication.h" +#include "catalog/pg_publication_rel.h" + +#include "commands/dbcommands.h" +#include "commands/defrem.h" +#include "commands/event_trigger.h" +#include "commands/publicationcmds.h" + +#include "utils/array.h" +#include "utils/builtins.h" +#include "utils/catcache.h" +#include "utils/fmgroids.h" +#include "utils/inval.h" +#include "utils/lsyscache.h" +#include "utils/rel.h" +#include "utils/syscache.h" + +/* Same as MAXNUMMESSAGES in sinvaladt.c */ +#define MAX_RELCACHE_INVAL_MSGS 4096 + +static List *OpenTableList(List *tables); +static void CloseTableList(List *rels); +static void PublicationAddTables(Oid pubid, List *rels, bool if_not_exists, + AlterPublicationStmt *stmt); +static void PublicationDropTables(Oid pubid, List *rels, bool missing_ok); + +static void +parse_publication_options(List *options, + bool *publish_insert_given, + bool *publish_insert, + bool *publish_update_given, + bool *publish_update, + bool *publish_delete_given, + bool *publish_delete) +{ + ListCell *lc; + + *publish_insert_given = false; + *publish_update_given = false; + *publish_delete_given = false; + + /* Defaults are true */ + *publish_insert = true; + *publish_update = true; + *publish_delete = true; + + /* Parse options */ + foreach (lc, options) + { + DefElem *defel = (DefElem *) lfirst(lc); + + if (strcmp(defel->defname, "publish insert") == 0) + { + if (*publish_insert_given) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + + *publish_insert_given = true; + *publish_insert = defGetBoolean(defel); + } + else if (strcmp(defel->defname, "nopublish insert") == 0) + { + if (*publish_insert_given) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + + *publish_insert_given = true; + *publish_insert = !defGetBoolean(defel); + } + else if (strcmp(defel->defname, "publish update") == 0) + { + if (*publish_update_given) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + + *publish_update_given = true; + *publish_update = defGetBoolean(defel); + } + else if (strcmp(defel->defname, "nopublish update") == 0) + { + if (*publish_update_given) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + + *publish_update_given = true; + *publish_update = !defGetBoolean(defel); + } + else if (strcmp(defel->defname, "publish delete") == 0) + { + if (*publish_delete_given) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + + *publish_delete_given = true; + *publish_delete = defGetBoolean(defel); + } + else if (strcmp(defel->defname, "nopublish delete") == 0) + { + if (*publish_delete_given) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + + *publish_delete_given = true; + *publish_delete = !defGetBoolean(defel); + } + else + elog(ERROR, "unrecognized option: %s", defel->defname); + } +} + +/* + * Create new publication. + */ +ObjectAddress +CreatePublication(CreatePublicationStmt *stmt) +{ + Relation rel; + ObjectAddress myself; + Oid puboid; + bool nulls[Natts_pg_publication]; + Datum values[Natts_pg_publication]; + HeapTuple tup; + bool publish_insert_given; + bool publish_update_given; + bool publish_delete_given; + bool publish_insert; + bool publish_update; + bool publish_delete; + AclResult aclresult; + + /* must have CREATE privilege on database */ + aclresult = pg_database_aclcheck(MyDatabaseId, GetUserId(), ACL_CREATE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, ACL_KIND_DATABASE, + get_database_name(MyDatabaseId)); + + /* FOR ALL TABLES requires superuser */ + if (stmt->for_all_tables && !superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + (errmsg("must be superuser to create FOR ALL TABLES publication")))); + + rel = heap_open(PublicationRelationId, RowExclusiveLock); + + /* Check if name is used */ + puboid = GetSysCacheOid1(PUBLICATIONNAME, CStringGetDatum(stmt->pubname)); + if (OidIsValid(puboid)) + { + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("publication \"%s\" already exists", + stmt->pubname))); + } + + /* Form a tuple. */ + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(nulls)); + + values[Anum_pg_publication_pubname - 1] = + DirectFunctionCall1(namein, CStringGetDatum(stmt->pubname)); + values[Anum_pg_publication_pubowner - 1] = ObjectIdGetDatum(GetUserId()); + + parse_publication_options(stmt->options, + &publish_insert_given, &publish_insert, + &publish_update_given, &publish_update, + &publish_delete_given, &publish_delete); + + values[Anum_pg_publication_puballtables - 1] = + BoolGetDatum(stmt->for_all_tables); + values[Anum_pg_publication_pubinsert - 1] = + BoolGetDatum(publish_insert); + values[Anum_pg_publication_pubupdate - 1] = + BoolGetDatum(publish_update); + values[Anum_pg_publication_pubdelete - 1] = + BoolGetDatum(publish_delete); + + tup = heap_form_tuple(RelationGetDescr(rel), values, nulls); + + /* Insert tuple into catalog. */ + puboid = simple_heap_insert(rel, tup); + CatalogUpdateIndexes(rel, tup); + heap_freetuple(tup); + + recordDependencyOnOwner(PublicationRelationId, puboid, GetUserId()); + + ObjectAddressSet(myself, PublicationRelationId, puboid); + + /* Make the changes visible. */ + CommandCounterIncrement(); + + if (stmt->tables) + { + List *rels; + + Assert(list_length(stmt->tables) > 0); + + rels = OpenTableList(stmt->tables); + PublicationAddTables(puboid, rels, true, NULL); + CloseTableList(rels); + } + + heap_close(rel, RowExclusiveLock); + + InvokeObjectPostCreateHook(PublicationRelationId, puboid, 0); + + return myself; +} + +/* + * Change options of a publication. + */ +static void +AlterPublicationOptions(AlterPublicationStmt *stmt, Relation rel, + HeapTuple tup) +{ + bool nulls[Natts_pg_publication]; + bool replaces[Natts_pg_publication]; + Datum values[Natts_pg_publication]; + bool publish_insert_given; + bool publish_update_given; + bool publish_delete_given; + bool publish_insert; + bool publish_update; + bool publish_delete; + ObjectAddress obj; + + parse_publication_options(stmt->options, + &publish_insert_given, &publish_insert, + &publish_update_given, &publish_update, + &publish_delete_given, &publish_delete); + + /* Everything ok, form a new tuple. */ + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(nulls)); + memset(replaces, false, sizeof(replaces)); + + if (publish_insert_given) + { + values[Anum_pg_publication_pubinsert - 1] = + BoolGetDatum(publish_insert); + replaces[Anum_pg_publication_pubinsert - 1] = true; + } + if (publish_update_given) + { + values[Anum_pg_publication_pubupdate - 1] = + BoolGetDatum(publish_update); + replaces[Anum_pg_publication_pubupdate - 1] = true; + } + if (publish_delete_given) + { + values[Anum_pg_publication_pubdelete - 1] = + BoolGetDatum(publish_delete); + replaces[Anum_pg_publication_pubdelete - 1] = true; + } + + tup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls, + replaces); + + /* Update the catalog. */ + simple_heap_update(rel, &tup->t_self, tup); + CatalogUpdateIndexes(rel, tup); + + CommandCounterIncrement(); + + /* Invalidate the relcache. */ + if (((Form_pg_publication) GETSTRUCT(tup))->puballtables) + { + CacheInvalidateRelcacheAll(); + } + else + { + List *relids = GetPublicationRelations(HeapTupleGetOid(tup)); + + /* + * We don't want to send too many individual messages, at some point + * it's cheaper to just reset whole relcache. + */ + if (list_length(relids) < MAX_RELCACHE_INVAL_MSGS) + { + ListCell *lc; + + foreach (lc, relids) + { + Oid relid = lfirst_oid(lc); + + CacheInvalidateRelcacheByRelid(relid); + } + } + else + CacheInvalidateRelcacheAll(); + } + + ObjectAddressSet(obj, PublicationRelationId, HeapTupleGetOid(tup)); + EventTriggerCollectSimpleCommand(obj, InvalidObjectAddress, + (Node *) stmt); + + InvokeObjectPostAlterHook(PublicationRelationId, HeapTupleGetOid(tup), 0); +} + +/* + * Add or remove table to/from publication. + */ +static void +AlterPublicationTables(AlterPublicationStmt *stmt, Relation rel, + HeapTuple tup) +{ + Oid pubid = HeapTupleGetOid(tup); + List *rels = NIL; + Form_pg_publication pubform = (Form_pg_publication) GETSTRUCT(tup); + + /* Check that user is allowed to manipulate the publication tables. */ + if (pubform->puballtables) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("publication \"%s\" is defined as FOR ALL TABLES", + NameStr(pubform->pubname)), + errdetail("Tables cannot be added to or dropped from FOR ALL TABLES publications."))); + + Assert(list_length(stmt->tables) > 0); + + rels = OpenTableList(stmt->tables); + + if (stmt->tableAction == DEFELEM_ADD) + PublicationAddTables(pubid, rels, false, stmt); + else if (stmt->tableAction == DEFELEM_DROP) + PublicationDropTables(pubid, rels, false); + else /* DEFELEM_SET */ + { + List *oldrelids = GetPublicationRelations(pubid); + List *delrels = NIL; + ListCell *oldlc; + + /* Calculate which relations to drop. */ + foreach(oldlc, oldrelids) + { + Oid oldrelid = lfirst_oid(oldlc); + ListCell *newlc; + bool found = false; + + foreach(newlc, rels) + { + Relation newrel = (Relation) lfirst(newlc); + + if (RelationGetRelid(newrel) == oldrelid) + { + found = true; + break; + } + } + + if (!found) + { + Relation oldrel = heap_open(oldrelid, + ShareUpdateExclusiveLock); + delrels = lappend(delrels, oldrel); + } + } + + /* And drop them. */ + PublicationDropTables(pubid, delrels, true); + + /* + * Don't bother calculating the difference for adding, we'll catch + * and skip existing ones when doing catalog update. + */ + PublicationAddTables(pubid, rels, true, stmt); + + CloseTableList(delrels); + } + + CloseTableList(rels); +} + +/* + * Alter the existing publication. + * + * This is dispatcher function for AlterPublicationOptions and + * AlterPublicationTables. + */ +void +AlterPublication(AlterPublicationStmt *stmt) +{ + Relation rel; + HeapTuple tup; + + rel = heap_open(PublicationRelationId, RowExclusiveLock); + + tup = SearchSysCacheCopy1(PUBLICATIONNAME, + CStringGetDatum(stmt->pubname)); + + if (!HeapTupleIsValid(tup)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("publication \"%s\" does not exist", + stmt->pubname))); + + /* must be owner */ + if (!pg_publication_ownercheck(HeapTupleGetOid(tup), GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PUBLICATION, + stmt->pubname); + + if (stmt->options) + AlterPublicationOptions(stmt, rel, tup); + else + AlterPublicationTables(stmt, rel, tup); + + /* Cleanup. */ + heap_freetuple(tup); + heap_close(rel, RowExclusiveLock); +} + +/* + * Drop publication by OID + */ +void +RemovePublicationById(Oid pubid) +{ + Relation rel; + HeapTuple tup; + + rel = heap_open(PublicationRelationId, RowExclusiveLock); + + tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid)); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for publication %u", pubid); + + simple_heap_delete(rel, &tup->t_self); + + ReleaseSysCache(tup); + + heap_close(rel, RowExclusiveLock); +} + +/* + * Remove relation from publication by mapping OID. + */ +void +RemovePublicationRelById(Oid proid) +{ + Relation rel; + HeapTuple tup; + Form_pg_publication_rel pubrel; + + rel = heap_open(PublicationRelRelationId, RowExclusiveLock); + + tup = SearchSysCache1(PUBLICATIONREL, ObjectIdGetDatum(proid)); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for publication table %u", + proid); + + + pubrel = (Form_pg_publication_rel) GETSTRUCT(tup); + + /* Invalidate relcache so that publication info is rebuilt. */ + CacheInvalidateRelcacheByRelid(pubrel->prrelid); + + simple_heap_delete(rel, &tup->t_self); + + ReleaseSysCache(tup); + + heap_close(rel, RowExclusiveLock); +} + +/* + * Open relations based om provided by RangeVar list. + * The returned tables are locked in ShareUpdateExclusiveLock mode. + */ +static List * +OpenTableList(List *tables) +{ + List *relids = NIL; + List *rels = NIL; + ListCell *lc; + + /* + * Open, share-lock, and check all the explicitly-specified relations + */ + foreach(lc, tables) + { + RangeVar *rv = lfirst(lc); + Relation rel; + bool recurse = rv->inh; + Oid myrelid; + + CHECK_FOR_INTERRUPTS(); + + rel = heap_openrv(rv, ShareUpdateExclusiveLock); + myrelid = RelationGetRelid(rel); + /* + * filter out duplicates when user specifies "foo, foo" + * Note that this algrithm is know to not be very effective (O(N^2)) + * but given that it only works on list of tables given to us by user + * it's deemed acceptable. + */ + if (list_member_oid(relids, myrelid)) + { + heap_close(rel, ShareUpdateExclusiveLock); + continue; + } + rels = lappend(rels, rel); + relids = lappend_oid(relids, myrelid); + + if (recurse) + { + ListCell *child; + List *children; + + children = find_all_inheritors(myrelid, ShareUpdateExclusiveLock, + NULL); + + foreach(child, children) + { + Oid childrelid = lfirst_oid(child); + + if (list_member_oid(relids, childrelid)) + continue; + + /* + * Skip duplicates if user specified both parent and child + * tables. + */ + if (list_member_oid(relids, childrelid)) + { + heap_close(rel, ShareUpdateExclusiveLock); + continue; + } + + /* find_all_inheritors already got lock */ + rel = heap_open(childrelid, NoLock); + rels = lappend(rels, rel); + relids = lappend_oid(relids, childrelid); + } + } + } + + list_free(relids); + + return rels; +} + +/* + * Close all relations in the list. + */ +static void +CloseTableList(List *rels) +{ + ListCell *lc; + + foreach(lc, rels) + { + Relation rel = (Relation) lfirst(lc); + + heap_close(rel, NoLock); + } +} + +/* + * Add listed tables to the publication. + */ +static void +PublicationAddTables(Oid pubid, List *rels, bool if_not_exists, + AlterPublicationStmt *stmt) +{ + ListCell *lc; + + Assert(!stmt || !stmt->for_all_tables); + + foreach(lc, rels) + { + Relation rel = (Relation) lfirst(lc); + ObjectAddress obj; + + /* Must be owner of the table or superuser. */ + if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + RelationGetRelationName(rel)); + + obj = publication_add_relation(pubid, rel, if_not_exists); + if (stmt) + { + EventTriggerCollectSimpleCommand(obj, InvalidObjectAddress, + (Node *) stmt); + + InvokeObjectPostCreateHook(PublicationRelRelationId, + obj.objectId, 0); + } + } +} + +/* + * Remove listed tables from the publication. + */ +static void +PublicationDropTables(Oid pubid, List *rels, bool missing_ok) +{ + ObjectAddress obj; + ListCell *lc; + Oid prid; + + foreach(lc, rels) + { + Relation rel = (Relation) lfirst(lc); + Oid relid = RelationGetRelid(rel); + + prid = GetSysCacheOid2(PUBLICATIONRELMAP, ObjectIdGetDatum(relid), + ObjectIdGetDatum(pubid)); + if (!OidIsValid(prid)) + { + if (missing_ok) + continue; + + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("relation \"%s\" is not part of the publication", + RelationGetRelationName(rel)))); + } + + ObjectAddressSet(obj, PublicationRelRelationId, prid); + performDeletion(&obj, DROP_CASCADE, 0); + } +} + +/* + * Internal workhorse for changing a publication owner + */ + static void +AlterPublicationOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) +{ + Form_pg_publication form; + + form = (Form_pg_publication) GETSTRUCT(tup); + + if (form->pubowner == newOwnerId) + return; + + if (!pg_publication_ownercheck(HeapTupleGetOid(tup), GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PUBLICATION, + NameStr(form->pubname)); + + /* New owner must be a superuser */ + if (!superuser_arg(newOwnerId)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied to change owner of publication \"%s\"", + NameStr(form->pubname)), + errhint("The owner of a publication must be a superuser."))); + + form->pubowner = newOwnerId; + simple_heap_update(rel, &tup->t_self, tup); + CatalogUpdateIndexes(rel, tup); + + /* Update owner dependency reference */ + changeDependencyOnOwner(PublicationRelationId, + HeapTupleGetOid(tup), + newOwnerId); + + InvokeObjectPostAlterHook(PublicationRelationId, + HeapTupleGetOid(tup), 0); +} + +/* + * Change publication owner -- by name + */ +ObjectAddress +AlterPublicationOwner(const char *name, Oid newOwnerId) +{ + Oid subid; + HeapTuple tup; + Relation rel; + ObjectAddress address; + + rel = heap_open(PublicationRelationId, RowExclusiveLock); + + tup = SearchSysCacheCopy1(PUBLICATIONNAME, CStringGetDatum(name)); + + if (!HeapTupleIsValid(tup)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("publication \"%s\" does not exist", name))); + + subid = HeapTupleGetOid(tup); + + AlterPublicationOwner_internal(rel, tup, newOwnerId); + + ObjectAddressSet(address, PublicationRelationId, subid); + + heap_freetuple(tup); + + heap_close(rel, RowExclusiveLock); + + return address; +} + +/* + * Change publication owner -- by OID + */ +void +AlterPublicationOwner_oid(Oid subid, Oid newOwnerId) +{ + HeapTuple tup; + Relation rel; + + rel = heap_open(PublicationRelationId, RowExclusiveLock); + + tup = SearchSysCacheCopy1(PUBLICATIONOID, ObjectIdGetDatum(subid)); + + if (!HeapTupleIsValid(tup)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("publication with OID %u does not exist", subid))); + + AlterPublicationOwner_internal(rel, tup, newOwnerId); + + heap_freetuple(tup); + + heap_close(rel, RowExclusiveLock); +} diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c index a60ceb8eba..c3b37b2625 100644 --- a/src/backend/commands/schemacmds.c +++ b/src/backend/commands/schemacmds.c @@ -3,7 +3,7 @@ * schemacmds.c * schema creation/manipulation commands * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -40,9 +40,16 @@ static void AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerI /* * CREATE SCHEMA + * + * Note: caller should pass in location information for the whole + * CREATE SCHEMA statement, which in turn we pass down as the location + * of the component commands. This comports with our general plan of + * reporting location/len for the whole command even when executing + * a subquery. */ Oid -CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString) +CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString, + int stmt_location, int stmt_len) { const char *schemaName = stmt->schemaname; Oid namespaceId; @@ -172,14 +179,24 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString) foreach(parsetree_item, parsetree_list) { Node *stmt = (Node *) lfirst(parsetree_item); + PlannedStmt *wrapper; + + /* need to make a wrapper PlannedStmt */ + wrapper = makeNode(PlannedStmt); + wrapper->commandType = CMD_UTILITY; + wrapper->canSetTag = false; + wrapper->utilityStmt = stmt; + wrapper->stmt_location = stmt_location; + wrapper->stmt_len = stmt_len; /* do this step */ - ProcessUtility(stmt, + ProcessUtility(wrapper, queryString, PROCESS_UTILITY_SUBCOMMAND, NULL, None_Receiver, NULL); + /* make sure later steps can see the object created here */ CommandCounterIncrement(); } diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c index 5bd7e124c1..324f2e7bd9 100644 --- a/src/backend/commands/seclabel.c +++ b/src/backend/commands/seclabel.c @@ -3,7 +3,7 @@ * seclabel.c * routines to support security label feature. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * ------------------------------------------------------------------------- @@ -110,7 +110,8 @@ ExecSecLabelStmt(SecLabelStmt *stmt) relation->rd_rel->relkind != RELKIND_VIEW && relation->rd_rel->relkind != RELKIND_MATVIEW && relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE && - relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE) + relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE && + relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table", diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index c98f981111..36f1249ee5 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -3,7 +3,7 @@ * sequence.c * PostgreSQL sequences support code. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -22,8 +22,10 @@ #include "access/xloginsert.h" #include "access/xlogutils.h" #include "catalog/dependency.h" +#include "catalog/indexing.h" #include "catalog/namespace.h" #include "catalog/objectaccess.h" +#include "catalog/pg_sequence.h" #include "catalog/pg_type.h" #include "commands/defrem.h" #include "commands/sequence.h" @@ -39,6 +41,7 @@ #include "utils/lsyscache.h" #include "utils/resowner.h" #include "utils/syscache.h" +#include "utils/varlena.h" /* @@ -74,7 +77,7 @@ typedef struct SeqTableData int64 cached; /* last value already cached for nextval */ /* if last != cached, we have not used up all the cached values */ int64 increment; /* copy of sequence's increment field */ - /* note that increment is zero until we first do read_seq_tuple() */ + /* note that increment is zero until we first do nextval_internal() */ } SeqTableData; typedef SeqTableData *SeqTable; @@ -92,10 +95,11 @@ static int64 nextval_internal(Oid relid); static Relation open_share_lock(SeqTable seq); static void create_seq_hashtable(void); static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel); -static Form_pg_sequence read_seq_tuple(SeqTable elm, Relation rel, - Buffer *buf, HeapTuple seqtuple); -static void init_params(List *options, bool isInit, - Form_pg_sequence new, List **owned_by); +static Form_pg_sequence_data read_seq_tuple(Relation rel, + Buffer *buf, HeapTuple seqdatatuple); +static void init_params(ParseState *pstate, List *options, bool isInit, + Form_pg_sequence seqform, + Form_pg_sequence_data seqdataform, List **owned_by); static void do_setval(Oid relid, int64 next, bool iscalled); static void process_owned_by(Relation seqrel, List *owned_by); @@ -105,9 +109,10 @@ static void process_owned_by(Relation seqrel, List *owned_by); * Creates a new sequence relation */ ObjectAddress -DefineSequence(CreateSeqStmt *seq) +DefineSequence(ParseState *pstate, CreateSeqStmt *seq) { - FormData_pg_sequence new; + FormData_pg_sequence seqform; + FormData_pg_sequence_data seqdataform; List *owned_by; CreateStmt *stmt = makeNode(CreateStmt); Oid seqoid; @@ -117,8 +122,9 @@ DefineSequence(CreateSeqStmt *seq) TupleDesc tupDesc; Datum value[SEQ_COL_LASTCOL]; bool null[SEQ_COL_LASTCOL]; + Datum pgs_values[Natts_pg_sequence]; + bool pgs_nulls[Natts_pg_sequence]; int i; - NameData name; /* Unlogged sequences are not implemented -- not clear if useful. */ if (seq->sequence->relpersistence == RELPERSISTENCE_UNLOGGED) @@ -145,7 +151,7 @@ DefineSequence(CreateSeqStmt *seq) } /* Check and set all option values */ - init_params(seq->options, true, &new, &owned_by); + init_params(pstate, seq->options, true, &seqform, &seqdataform, &owned_by); /* * Create relation (and fill value[] and null[] for the tuple) @@ -171,52 +177,16 @@ DefineSequence(CreateSeqStmt *seq) switch (i) { - case SEQ_COL_NAME: - coldef->typeName = makeTypeNameFromOid(NAMEOID, -1); - coldef->colname = "sequence_name"; - namestrcpy(&name, seq->sequence->relname); - value[i - 1] = NameGetDatum(&name); - break; case SEQ_COL_LASTVAL: coldef->typeName = makeTypeNameFromOid(INT8OID, -1); coldef->colname = "last_value"; - value[i - 1] = Int64GetDatumFast(new.last_value); - break; - case SEQ_COL_STARTVAL: - coldef->typeName = makeTypeNameFromOid(INT8OID, -1); - coldef->colname = "start_value"; - value[i - 1] = Int64GetDatumFast(new.start_value); - break; - case SEQ_COL_INCBY: - coldef->typeName = makeTypeNameFromOid(INT8OID, -1); - coldef->colname = "increment_by"; - value[i - 1] = Int64GetDatumFast(new.increment_by); - break; - case SEQ_COL_MAXVALUE: - coldef->typeName = makeTypeNameFromOid(INT8OID, -1); - coldef->colname = "max_value"; - value[i - 1] = Int64GetDatumFast(new.max_value); - break; - case SEQ_COL_MINVALUE: - coldef->typeName = makeTypeNameFromOid(INT8OID, -1); - coldef->colname = "min_value"; - value[i - 1] = Int64GetDatumFast(new.min_value); - break; - case SEQ_COL_CACHE: - coldef->typeName = makeTypeNameFromOid(INT8OID, -1); - coldef->colname = "cache_value"; - value[i - 1] = Int64GetDatumFast(new.cache_value); + value[i - 1] = Int64GetDatumFast(seqdataform.last_value); break; case SEQ_COL_LOG: coldef->typeName = makeTypeNameFromOid(INT8OID, -1); coldef->colname = "log_cnt"; value[i - 1] = Int64GetDatum((int64) 0); break; - case SEQ_COL_CYCLE: - coldef->typeName = makeTypeNameFromOid(BOOLOID, -1); - coldef->colname = "is_cycled"; - value[i - 1] = BoolGetDatum(new.is_cycled); - break; case SEQ_COL_CALLED: coldef->typeName = makeTypeNameFromOid(BOOLOID, -1); coldef->colname = "is_called"; @@ -234,7 +204,7 @@ DefineSequence(CreateSeqStmt *seq) stmt->tablespacename = NULL; stmt->if_not_exists = seq->if_not_exists; - address = DefineRelation(stmt, RELKIND_SEQUENCE, seq->ownerId, NULL); + address = DefineRelation(stmt, RELKIND_SEQUENCE, seq->ownerId, NULL, NULL); seqoid = address.objectId; Assert(seqoid != InvalidOid); @@ -251,6 +221,27 @@ DefineSequence(CreateSeqStmt *seq) heap_close(rel, NoLock); + /* fill in pg_sequence */ + rel = heap_open(SequenceRelationId, RowExclusiveLock); + tupDesc = RelationGetDescr(rel); + + memset(pgs_nulls, 0, sizeof(pgs_nulls)); + + pgs_values[Anum_pg_sequence_seqrelid - 1] = ObjectIdGetDatum(seqoid); + pgs_values[Anum_pg_sequence_seqcycle - 1] = BoolGetDatum(seqform.seqcycle); + pgs_values[Anum_pg_sequence_seqstart - 1] = Int64GetDatumFast(seqform.seqstart); + pgs_values[Anum_pg_sequence_seqincrement - 1] = Int64GetDatumFast(seqform.seqincrement); + pgs_values[Anum_pg_sequence_seqmax - 1] = Int64GetDatumFast(seqform.seqmax); + pgs_values[Anum_pg_sequence_seqmin - 1] = Int64GetDatumFast(seqform.seqmin); + pgs_values[Anum_pg_sequence_seqcache - 1] = Int64GetDatumFast(seqform.seqcache); + + tuple = heap_form_tuple(tupDesc, pgs_values, pgs_nulls); + simple_heap_insert(rel, tuple); + CatalogUpdateIndexes(rel, tuple); + + heap_freetuple(tuple); + heap_close(rel, RowExclusiveLock); + return address; } @@ -271,10 +262,13 @@ ResetSequence(Oid seq_relid) { Relation seq_rel; SeqTable elm; - Form_pg_sequence seq; + Form_pg_sequence_data seq; Buffer buf; - HeapTupleData seqtuple; + HeapTupleData seqdatatuple; HeapTuple tuple; + HeapTuple pgstuple; + Form_pg_sequence pgsform; + int64 startv; /* * Read the old sequence. This does a bit more work than really @@ -282,12 +276,19 @@ ResetSequence(Oid seq_relid) * indeed a sequence. */ init_sequence(seq_relid, &elm, &seq_rel); - (void) read_seq_tuple(elm, seq_rel, &buf, &seqtuple); + (void) read_seq_tuple(seq_rel, &buf, &seqdatatuple); + + pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(seq_relid)); + if (!HeapTupleIsValid(pgstuple)) + elog(ERROR, "cache lookup failed for sequence %u", seq_relid); + pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple); + startv = pgsform->seqstart; + ReleaseSysCache(pgstuple); /* * Copy the existing sequence tuple. */ - tuple = heap_copytuple(&seqtuple); + tuple = heap_copytuple(&seqdatatuple); /* Now we're done with the old page */ UnlockReleaseBuffer(buf); @@ -296,8 +297,8 @@ ResetSequence(Oid seq_relid) * Modify the copied tuple to execute the restart (compare the RESTART * action in AlterSequence) */ - seq = (Form_pg_sequence) GETSTRUCT(tuple); - seq->last_value = seq->start_value; + seq = (Form_pg_sequence_data) GETSTRUCT(tuple); + seq->last_value = startv; seq->is_called = false; seq->log_cnt = 0; @@ -404,17 +405,20 @@ fill_seq_with_data(Relation rel, HeapTuple tuple) * Modify the definition of a sequence relation */ ObjectAddress -AlterSequence(AlterSeqStmt *stmt) +AlterSequence(ParseState *pstate, AlterSeqStmt *stmt) { Oid relid; SeqTable elm; Relation seqrel; Buffer buf; - HeapTupleData seqtuple; - Form_pg_sequence seq; - FormData_pg_sequence new; + HeapTupleData seqdatatuple; + Form_pg_sequence seqform; + Form_pg_sequence_data seqdata; + FormData_pg_sequence_data newseqdata; List *owned_by; ObjectAddress address; + Relation rel; + HeapTuple tuple; /* Open and lock sequence. */ relid = RangeVarGetRelid(stmt->sequence, AccessShareLock, stmt->missing_ok); @@ -434,13 +438,22 @@ AlterSequence(AlterSeqStmt *stmt) stmt->sequence->relname); /* lock page' buffer and read tuple into new sequence structure */ - seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple); + seqdata = read_seq_tuple(seqrel, &buf, &seqdatatuple); /* Copy old values of options into workspace */ - memcpy(&new, seq, sizeof(FormData_pg_sequence)); + memcpy(&newseqdata, seqdata, sizeof(FormData_pg_sequence_data)); + + rel = heap_open(SequenceRelationId, RowExclusiveLock); + tuple = SearchSysCacheCopy1(SEQRELID, + ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for sequence %u", + relid); + + seqform = (Form_pg_sequence) GETSTRUCT(tuple); /* Check and set new values */ - init_params(stmt->options, false, &new, &owned_by); + init_params(pstate, stmt->options, false, seqform, &newseqdata, &owned_by); /* Clear local cache so that we don't think we have cached numbers */ /* Note that we do not change the currval() state */ @@ -453,7 +466,7 @@ AlterSequence(AlterSeqStmt *stmt) /* Now okay to update the on-disk tuple */ START_CRIT_SECTION(); - memcpy(seq, &new, sizeof(FormData_pg_sequence)); + memcpy(seqdata, &newseqdata, sizeof(FormData_pg_sequence_data)); MarkBufferDirty(buf); @@ -470,7 +483,7 @@ AlterSequence(AlterSeqStmt *stmt) xlrec.node = seqrel->rd_node; XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec)); - XLogRegisterData((char *) seqtuple.t_data, seqtuple.t_len); + XLogRegisterData((char *) seqdatatuple.t_data, seqdatatuple.t_len); recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG); @@ -491,9 +504,30 @@ AlterSequence(AlterSeqStmt *stmt) relation_close(seqrel, NoLock); + simple_heap_update(rel, &tuple->t_self, tuple); + CatalogUpdateIndexes(rel, tuple); + heap_close(rel, RowExclusiveLock); + return address; } +void +DeleteSequenceTuple(Oid relid) +{ + Relation rel; + HeapTuple tuple; + + rel = heap_open(SequenceRelationId, RowExclusiveLock); + + tuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for sequence %u", relid); + + simple_heap_delete(rel, &tuple->t_self); + + ReleaseSysCache(tuple); + heap_close(rel, RowExclusiveLock); +} /* * Note: nextval with a text argument is no longer exported as a pg_proc @@ -537,8 +571,10 @@ nextval_internal(Oid relid) Relation seqrel; Buffer buf; Page page; - HeapTupleData seqtuple; - Form_pg_sequence seq; + HeapTuple pgstuple; + Form_pg_sequence pgsform; + HeapTupleData seqdatatuple; + Form_pg_sequence_data seq; int64 incby, maxv, minv, @@ -549,6 +585,7 @@ nextval_internal(Oid relid) int64 result, next, rescnt = 0; + bool cycle; bool logit = false; /* open and AccessShareLock sequence */ @@ -582,15 +619,24 @@ nextval_internal(Oid relid) return elm->last; } + pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(pgstuple)) + elog(ERROR, "cache lookup failed for sequence %u", relid); + pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple); + cycle = pgsform->seqcycle; + incby = pgsform->seqincrement; + maxv = pgsform->seqmax; + minv = pgsform->seqmin; + cache = pgsform->seqcache; + ReleaseSysCache(pgstuple); + /* lock page' buffer and read tuple */ - seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple); + seq = read_seq_tuple(seqrel, &buf, &seqdatatuple); page = BufferGetPage(buf); + elm->increment = incby; last = next = result = seq->last_value; - incby = seq->increment_by; - maxv = seq->max_value; - minv = seq->min_value; - fetch = cache = seq->cache_value; + fetch = cache; log = seq->log_cnt; if (!seq->is_called) @@ -641,7 +687,7 @@ nextval_internal(Oid relid) { if (rescnt > 0) break; /* stop fetching */ - if (!seq->is_cycled) + if (!cycle) { char buf[100]; @@ -664,7 +710,7 @@ nextval_internal(Oid relid) { if (rescnt > 0) break; /* stop fetching */ - if (!seq->is_cycled) + if (!cycle) { char buf[100]; @@ -747,7 +793,7 @@ nextval_internal(Oid relid) xlrec.node = seqrel->rd_node; XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec)); - XLogRegisterData((char *) seqtuple.t_data, seqtuple.t_len); + XLogRegisterData((char *) seqdatatuple.t_data, seqdatatuple.t_len); recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG); @@ -853,8 +899,12 @@ do_setval(Oid relid, int64 next, bool iscalled) SeqTable elm; Relation seqrel; Buffer buf; - HeapTupleData seqtuple; - Form_pg_sequence seq; + HeapTupleData seqdatatuple; + Form_pg_sequence_data seq; + HeapTuple pgstuple; + Form_pg_sequence pgsform; + int64 maxv, + minv; /* open and AccessShareLock sequence */ init_sequence(relid, &elm, &seqrel); @@ -865,6 +915,14 @@ do_setval(Oid relid, int64 next, bool iscalled) errmsg("permission denied for sequence %s", RelationGetRelationName(seqrel)))); + pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(pgstuple)) + elog(ERROR, "cache lookup failed for sequence %u", relid); + pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple); + maxv = pgsform->seqmax; + minv = pgsform->seqmin; + ReleaseSysCache(pgstuple); + /* read-only transactions may only modify temp sequences */ if (!seqrel->rd_islocaltemp) PreventCommandIfReadOnly("setval()"); @@ -877,17 +935,17 @@ do_setval(Oid relid, int64 next, bool iscalled) PreventCommandIfParallelMode("setval()"); /* lock page' buffer and read tuple */ - seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple); + seq = read_seq_tuple(seqrel, &buf, &seqdatatuple); - if ((next < seq->min_value) || (next > seq->max_value)) + if ((next < minv) || (next > maxv)) { char bufv[100], bufm[100], bufx[100]; snprintf(bufv, sizeof(bufv), INT64_FORMAT, next); - snprintf(bufm, sizeof(bufm), INT64_FORMAT, seq->min_value); - snprintf(bufx, sizeof(bufx), INT64_FORMAT, seq->max_value); + snprintf(bufm, sizeof(bufm), INT64_FORMAT, minv); + snprintf(bufx, sizeof(bufx), INT64_FORMAT, maxv); ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("setval: value %s is out of bounds for sequence \"%s\" (%s..%s)", @@ -930,7 +988,7 @@ do_setval(Oid relid, int64 next, bool iscalled) xlrec.node = seqrel->rd_node; XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec)); - XLogRegisterData((char *) seqtuple.t_data, seqtuple.t_len); + XLogRegisterData((char *) seqdatatuple.t_data, seqdatatuple.t_len); recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG); @@ -1064,7 +1122,7 @@ init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel) elm->filenode = InvalidOid; elm->lxid = InvalidLocalTransactionId; elm->last_valid = false; - elm->last = elm->cached = elm->increment = 0; + elm->last = elm->cached = 0; } /* @@ -1099,18 +1157,18 @@ init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel) * Given an opened sequence relation, lock the page buffer and find the tuple * * *buf receives the reference to the pinned-and-ex-locked buffer - * *seqtuple receives the reference to the sequence tuple proper + * *seqdatatuple receives the reference to the sequence tuple proper * (this arg should point to a local variable of type HeapTupleData) * * Function's return value points to the data payload of the tuple */ -static Form_pg_sequence -read_seq_tuple(SeqTable elm, Relation rel, Buffer *buf, HeapTuple seqtuple) +static Form_pg_sequence_data +read_seq_tuple(Relation rel, Buffer *buf, HeapTuple seqdatatuple) { Page page; ItemId lp; sequence_magic *sm; - Form_pg_sequence seq; + Form_pg_sequence_data seq; *buf = ReadBuffer(rel, 0); LockBuffer(*buf, BUFFER_LOCK_EXCLUSIVE); @@ -1125,9 +1183,9 @@ read_seq_tuple(SeqTable elm, Relation rel, Buffer *buf, HeapTuple seqtuple) lp = PageGetItemId(page, FirstOffsetNumber); Assert(ItemIdIsNormal(lp)); - /* Note we currently only bother to set these two fields of *seqtuple */ - seqtuple->t_data = (HeapTupleHeader) PageGetItem(page, lp); - seqtuple->t_len = ItemIdGetLength(lp); + /* Note we currently only bother to set these two fields of *seqdatatuple */ + seqdatatuple->t_data = (HeapTupleHeader) PageGetItem(page, lp); + seqdatatuple->t_len = ItemIdGetLength(lp); /* * Previous releases of Postgres neglected to prevent SELECT FOR UPDATE on @@ -1137,19 +1195,16 @@ read_seq_tuple(SeqTable elm, Relation rel, Buffer *buf, HeapTuple seqtuple) * bit update, ie, don't bother to WAL-log it, since we can certainly do * this again if the update gets lost. */ - Assert(!(seqtuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI)); - if (HeapTupleHeaderGetRawXmax(seqtuple->t_data) != InvalidTransactionId) + Assert(!(seqdatatuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI)); + if (HeapTupleHeaderGetRawXmax(seqdatatuple->t_data) != InvalidTransactionId) { - HeapTupleHeaderSetXmax(seqtuple->t_data, InvalidTransactionId); - seqtuple->t_data->t_infomask &= ~HEAP_XMAX_COMMITTED; - seqtuple->t_data->t_infomask |= HEAP_XMAX_INVALID; + HeapTupleHeaderSetXmax(seqdatatuple->t_data, InvalidTransactionId); + seqdatatuple->t_data->t_infomask &= ~HEAP_XMAX_COMMITTED; + seqdatatuple->t_data->t_infomask |= HEAP_XMAX_INVALID; MarkBufferDirtyHint(*buf, true); } - seq = (Form_pg_sequence) GETSTRUCT(seqtuple); - - /* this is a handy place to update our copy of the increment */ - elm->increment = seq->increment_by; + seq = (Form_pg_sequence_data) GETSTRUCT(seqdatatuple); return seq; } @@ -1163,8 +1218,9 @@ read_seq_tuple(SeqTable elm, Relation rel, Buffer *buf, HeapTuple seqtuple) * otherwise, do not change existing options that aren't explicitly overridden. */ static void -init_params(List *options, bool isInit, - Form_pg_sequence new, List **owned_by) +init_params(ParseState *pstate, List *options, bool isInit, + Form_pg_sequence seqform, + Form_pg_sequence_data seqdataform, List **owned_by) { DefElem *start_value = NULL; DefElem *restart_value = NULL; @@ -1186,7 +1242,8 @@ init_params(List *options, bool isInit, if (increment_by) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); increment_by = defel; } else if (strcmp(defel->defname, "start") == 0) @@ -1194,7 +1251,8 @@ init_params(List *options, bool isInit, if (start_value) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); start_value = defel; } else if (strcmp(defel->defname, "restart") == 0) @@ -1202,7 +1260,8 @@ init_params(List *options, bool isInit, if (restart_value) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); restart_value = defel; } else if (strcmp(defel->defname, "maxvalue") == 0) @@ -1210,7 +1269,8 @@ init_params(List *options, bool isInit, if (max_value) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); max_value = defel; } else if (strcmp(defel->defname, "minvalue") == 0) @@ -1218,7 +1278,8 @@ init_params(List *options, bool isInit, if (min_value) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); min_value = defel; } else if (strcmp(defel->defname, "cache") == 0) @@ -1226,7 +1287,8 @@ init_params(List *options, bool isInit, if (cache_value) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); cache_value = defel; } else if (strcmp(defel->defname, "cycle") == 0) @@ -1234,7 +1296,8 @@ init_params(List *options, bool isInit, if (is_cycled) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); is_cycled = defel; } else if (strcmp(defel->defname, "owned_by") == 0) @@ -1242,7 +1305,8 @@ init_params(List *options, bool isInit, if (*owned_by) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); *owned_by = defGetQualifiedName(defel); } else @@ -1255,69 +1319,69 @@ init_params(List *options, bool isInit, * would affect future nextval allocations. */ if (isInit) - new->log_cnt = 0; + seqdataform->log_cnt = 0; /* INCREMENT BY */ if (increment_by != NULL) { - new->increment_by = defGetInt64(increment_by); - if (new->increment_by == 0) + seqform->seqincrement = defGetInt64(increment_by); + if (seqform->seqincrement == 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("INCREMENT must not be zero"))); - new->log_cnt = 0; + seqdataform->log_cnt = 0; } else if (isInit) - new->increment_by = 1; + seqform->seqincrement = 1; /* CYCLE */ if (is_cycled != NULL) { - new->is_cycled = intVal(is_cycled->arg); - Assert(BoolIsValid(new->is_cycled)); - new->log_cnt = 0; + seqform->seqcycle = intVal(is_cycled->arg); + Assert(BoolIsValid(seqform->seqcycle)); + seqdataform->log_cnt = 0; } else if (isInit) - new->is_cycled = false; + seqform->seqcycle = false; /* MAXVALUE (null arg means NO MAXVALUE) */ if (max_value != NULL && max_value->arg) { - new->max_value = defGetInt64(max_value); - new->log_cnt = 0; + seqform->seqmax = defGetInt64(max_value); + seqdataform->log_cnt = 0; } else if (isInit || max_value != NULL) { - if (new->increment_by > 0) - new->max_value = SEQ_MAXVALUE; /* ascending seq */ + if (seqform->seqincrement > 0) + seqform->seqmax = SEQ_MAXVALUE; /* ascending seq */ else - new->max_value = -1; /* descending seq */ - new->log_cnt = 0; + seqform->seqmax = -1; /* descending seq */ + seqdataform->log_cnt = 0; } /* MINVALUE (null arg means NO MINVALUE) */ if (min_value != NULL && min_value->arg) { - new->min_value = defGetInt64(min_value); - new->log_cnt = 0; + seqform->seqmin = defGetInt64(min_value); + seqdataform->log_cnt = 0; } else if (isInit || min_value != NULL) { - if (new->increment_by > 0) - new->min_value = 1; /* ascending seq */ + if (seqform->seqincrement > 0) + seqform->seqmin = 1; /* ascending seq */ else - new->min_value = SEQ_MINVALUE; /* descending seq */ - new->log_cnt = 0; + seqform->seqmin = SEQ_MINVALUE; /* descending seq */ + seqdataform->log_cnt = 0; } /* crosscheck min/max */ - if (new->min_value >= new->max_value) + if (seqform->seqmin >= seqform->seqmax) { char bufm[100], bufx[100]; - snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value); - snprintf(bufx, sizeof(bufx), INT64_FORMAT, new->max_value); + snprintf(bufm, sizeof(bufm), INT64_FORMAT, seqform->seqmin); + snprintf(bufx, sizeof(bufx), INT64_FORMAT, seqform->seqmax); ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("MINVALUE (%s) must be less than MAXVALUE (%s)", @@ -1326,35 +1390,35 @@ init_params(List *options, bool isInit, /* START WITH */ if (start_value != NULL) - new->start_value = defGetInt64(start_value); + seqform->seqstart = defGetInt64(start_value); else if (isInit) { - if (new->increment_by > 0) - new->start_value = new->min_value; /* ascending seq */ + if (seqform->seqincrement > 0) + seqform->seqstart = seqform->seqmin; /* ascending seq */ else - new->start_value = new->max_value; /* descending seq */ + seqform->seqstart = seqform->seqmax; /* descending seq */ } /* crosscheck START */ - if (new->start_value < new->min_value) + if (seqform->seqstart < seqform->seqmin) { char bufs[100], bufm[100]; - snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->start_value); - snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value); + snprintf(bufs, sizeof(bufs), INT64_FORMAT, seqform->seqstart); + snprintf(bufm, sizeof(bufm), INT64_FORMAT, seqform->seqmin); ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("START value (%s) cannot be less than MINVALUE (%s)", bufs, bufm))); } - if (new->start_value > new->max_value) + if (seqform->seqstart > seqform->seqmax) { char bufs[100], bufm[100]; - snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->start_value); - snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->max_value); + snprintf(bufs, sizeof(bufs), INT64_FORMAT, seqform->seqstart); + snprintf(bufm, sizeof(bufm), INT64_FORMAT, seqform->seqmax); ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("START value (%s) cannot be greater than MAXVALUE (%s)", @@ -1365,38 +1429,38 @@ init_params(List *options, bool isInit, if (restart_value != NULL) { if (restart_value->arg != NULL) - new->last_value = defGetInt64(restart_value); + seqdataform->last_value = defGetInt64(restart_value); else - new->last_value = new->start_value; - new->is_called = false; - new->log_cnt = 0; + seqdataform->last_value = seqform->seqstart; + seqdataform->is_called = false; + seqdataform->log_cnt = 0; } else if (isInit) { - new->last_value = new->start_value; - new->is_called = false; + seqdataform->last_value = seqform->seqstart; + seqdataform->is_called = false; } /* crosscheck RESTART (or current value, if changing MIN/MAX) */ - if (new->last_value < new->min_value) + if (seqdataform->last_value < seqform->seqmin) { char bufs[100], bufm[100]; - snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->last_value); - snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value); + snprintf(bufs, sizeof(bufs), INT64_FORMAT, seqdataform->last_value); + snprintf(bufm, sizeof(bufm), INT64_FORMAT, seqform->seqmin); ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("RESTART value (%s) cannot be less than MINVALUE (%s)", bufs, bufm))); } - if (new->last_value > new->max_value) + if (seqdataform->last_value > seqform->seqmax) { char bufs[100], bufm[100]; - snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->last_value); - snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->max_value); + snprintf(bufs, sizeof(bufs), INT64_FORMAT, seqdataform->last_value); + snprintf(bufm, sizeof(bufm), INT64_FORMAT, seqform->seqmax); ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("RESTART value (%s) cannot be greater than MAXVALUE (%s)", @@ -1406,21 +1470,21 @@ init_params(List *options, bool isInit, /* CACHE */ if (cache_value != NULL) { - new->cache_value = defGetInt64(cache_value); - if (new->cache_value <= 0) + seqform->seqcache = defGetInt64(cache_value); + if (seqform->seqcache <= 0) { char buf[100]; - snprintf(buf, sizeof(buf), INT64_FORMAT, new->cache_value); + snprintf(buf, sizeof(buf), INT64_FORMAT, seqform->seqcache); ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("CACHE (%s) must be greater than zero", buf))); } - new->log_cnt = 0; + seqdataform->log_cnt = 0; } else if (isInit) - new->cache_value = 1; + seqform->seqcache = 1; } /* @@ -1467,7 +1531,8 @@ process_owned_by(Relation seqrel, List *owned_by) /* Must be a regular or foreign table */ if (!(tablerel->rd_rel->relkind == RELKIND_RELATION || - tablerel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)) + tablerel->rd_rel->relkind == RELKIND_FOREIGN_TABLE || + tablerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("referenced relation \"%s\" is not a table or foreign table", @@ -1519,31 +1584,25 @@ process_owned_by(Relation seqrel, List *owned_by) /* - * Return sequence parameters, for use by information schema + * Return sequence parameters (formerly for use by information schema) */ Datum pg_sequence_parameters(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); TupleDesc tupdesc; - Datum values[5]; - bool isnull[5]; - SeqTable elm; - Relation seqrel; - Buffer buf; - HeapTupleData seqtuple; - Form_pg_sequence seq; - - /* open and AccessShareLock sequence */ - init_sequence(relid, &elm, &seqrel); + Datum values[6]; + bool isnull[6]; + HeapTuple pgstuple; + Form_pg_sequence pgsform; if (pg_class_aclcheck(relid, GetUserId(), ACL_SELECT | ACL_UPDATE | ACL_USAGE) != ACLCHECK_OK) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied for sequence %s", - RelationGetRelationName(seqrel)))); + get_rel_name(relid)))); - tupdesc = CreateTemplateTupleDesc(5, false); + tupdesc = CreateTemplateTupleDesc(6, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "start_value", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "minimum_value", @@ -1554,23 +1613,68 @@ pg_sequence_parameters(PG_FUNCTION_ARGS) INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 5, "cycle_option", BOOLOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 6, "cache_size", + INT8OID, -1, 0); BlessTupleDesc(tupdesc); memset(isnull, 0, sizeof(isnull)); - seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple); + pgstuple = SearchSysCache1(SEQRELID, relid); + if (!HeapTupleIsValid(pgstuple)) + elog(ERROR, "cache lookup failed for sequence %u", relid); + pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple); + + values[0] = Int64GetDatum(pgsform->seqstart); + values[1] = Int64GetDatum(pgsform->seqmin); + values[2] = Int64GetDatum(pgsform->seqmax); + values[3] = Int64GetDatum(pgsform->seqincrement); + values[4] = BoolGetDatum(pgsform->seqcycle); + values[5] = Int64GetDatum(pgsform->seqcache); + + ReleaseSysCache(pgstuple); - values[0] = Int64GetDatum(seq->start_value); - values[1] = Int64GetDatum(seq->min_value); - values[2] = Int64GetDatum(seq->max_value); - values[3] = Int64GetDatum(seq->increment_by); - values[4] = BoolGetDatum(seq->is_cycled); + return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull)); +} + +/* + * Return the last value from the sequence + * + * Note: This has a completely different meaning than lastval(). + */ +Datum +pg_sequence_last_value(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + SeqTable elm; + Relation seqrel; + Buffer buf; + HeapTupleData seqtuple; + Form_pg_sequence_data seq; + bool is_called; + int64 result; + + /* open and AccessShareLock sequence */ + init_sequence(relid, &elm, &seqrel); + + if (pg_class_aclcheck(relid, GetUserId(), ACL_SELECT | ACL_USAGE) != ACLCHECK_OK) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied for sequence %s", + RelationGetRelationName(seqrel)))); + + seq = read_seq_tuple(seqrel, &buf, &seqtuple); + + is_called = seq->is_called; + result = seq->last_value; UnlockReleaseBuffer(buf); relation_close(seqrel, NoLock); - return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull)); + if (is_called) + PG_RETURN_INT64(result); + else + PG_RETURN_NULL(); } diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c new file mode 100644 index 0000000000..2b6d322559 --- /dev/null +++ b/src/backend/commands/subscriptioncmds.c @@ -0,0 +1,649 @@ +/*------------------------------------------------------------------------- + * + * subscriptioncmds.c + * subscription catalog manipulation functions + * + * Copyright (c) 2015, PostgreSQL Global Development Group + * + * IDENTIFICATION + * subscriptioncmds.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "miscadmin.h" + +#include "access/heapam.h" +#include "access/htup_details.h" + +#include "catalog/indexing.h" +#include "catalog/objectaccess.h" +#include "catalog/objectaddress.h" +#include "catalog/pg_type.h" +#include "catalog/pg_subscription.h" + +#include "commands/defrem.h" +#include "commands/event_trigger.h" +#include "commands/subscriptioncmds.h" + +#include "replication/logicallauncher.h" +#include "replication/origin.h" +#include "replication/walreceiver.h" +#include "replication/worker_internal.h" + +#include "storage/lmgr.h" + +#include "utils/builtins.h" +#include "utils/memutils.h" +#include "utils/syscache.h" + +/* + * Common option parsing function for CREATE and ALTER SUBSCRIPTION commands. + * + * Since not all options can be specified in both commands, this function + * will report an error on options if the target output pointer is NULL to + * accomodate that. + */ +static void +parse_subscription_options(List *options, char **conninfo, + List **publications, bool *enabled_given, + bool *enabled, bool *create_slot, char **slot_name) +{ + ListCell *lc; + bool create_slot_given = false; + + if (conninfo) + *conninfo = NULL; + if (publications) + *publications = NIL; + if (enabled) + { + *enabled_given = false; + *enabled = true; + } + if (create_slot) + *create_slot = true; + if (slot_name) + *slot_name = NULL; + + /* Parse options */ + foreach (lc, options) + { + DefElem *defel = (DefElem *) lfirst(lc); + + if (strcmp(defel->defname, "conninfo") == 0 && conninfo) + { + if (*conninfo) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + + *conninfo = defGetString(defel); + } + else if (strcmp(defel->defname, "publication") == 0 && publications) + { + if (*publications) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + + *publications = defGetStringList(defel); + } + else if (strcmp(defel->defname, "enabled") == 0 && enabled) + { + if (*enabled_given) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + + *enabled_given = true; + *enabled = defGetBoolean(defel); + } + else if (strcmp(defel->defname, "disabled") == 0 && enabled) + { + if (*enabled_given) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + + *enabled_given = true; + *enabled = !defGetBoolean(defel); + } + else if (strcmp(defel->defname, "create slot") == 0 && create_slot) + { + if (create_slot_given) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + + create_slot_given = true; + *create_slot = defGetBoolean(defel); + } + else if (strcmp(defel->defname, "nocreate slot") == 0 && create_slot) + { + if (create_slot_given) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + + create_slot_given = true; + *create_slot = !defGetBoolean(defel); + } + else if (strcmp(defel->defname, "slot name") == 0 && slot_name) + { + if (*slot_name) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + + *slot_name = defGetString(defel); + } + else + elog(ERROR, "unrecognized option: %s", defel->defname); + } +} + +/* + * Auxiliary function to return a text array out of a list of String nodes. + */ +static Datum +publicationListToArray(List *publist) +{ + ArrayType *arr; + Datum *datums; + int j = 0; + ListCell *cell; + MemoryContext memcxt; + MemoryContext oldcxt; + + /* Create memory context for temporary allocations. */ + memcxt = AllocSetContextCreate(CurrentMemoryContext, + "publicationListToArray to array", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + oldcxt = MemoryContextSwitchTo(memcxt); + + datums = palloc(sizeof(text *) * list_length(publist)); + foreach(cell, publist) + { + char *name = strVal(lfirst(cell)); + ListCell *pcell; + + /* Check for duplicates. */ + foreach(pcell, publist) + { + char *pname = strVal(lfirst(cell)); + + if (name == pname) + break; + + if (strcmp(name, pname) == 0) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("publication name \"%s\" used more than once", + pname))); + } + + datums[j++] = CStringGetTextDatum(name); + } + + MemoryContextSwitchTo(oldcxt); + + arr = construct_array(datums, list_length(publist), + TEXTOID, -1, false, 'i'); + MemoryContextDelete(memcxt); + + return PointerGetDatum(arr); +} + +/* + * Create new subscription. + */ +ObjectAddress +CreateSubscription(CreateSubscriptionStmt *stmt) +{ + Relation rel; + ObjectAddress myself; + Oid subid; + bool nulls[Natts_pg_subscription]; + Datum values[Natts_pg_subscription]; + Oid owner = GetUserId(); + HeapTuple tup; + bool enabled_given; + bool enabled; + char *conninfo; + char *slotname; + char originname[NAMEDATALEN]; + bool create_slot; + List *publications; + + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + (errmsg("must be superuser to create subscriptions")))); + + rel = heap_open(SubscriptionRelationId, RowExclusiveLock); + + /* Check if name is used */ + subid = GetSysCacheOid2(SUBSCRIPTIONNAME, MyDatabaseId, + CStringGetDatum(stmt->subname)); + if (OidIsValid(subid)) + { + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("subscription \"%s\" already exists", + stmt->subname))); + } + + /* + * Parse and check options. + * Connection and publication should not be specified here. + */ + parse_subscription_options(stmt->options, NULL, NULL, + &enabled_given, &enabled, + &create_slot, &slotname); + if (slotname == NULL) + slotname = stmt->subname; + + conninfo = stmt->conninfo; + publications = stmt->publication; + + /* Load the library providing us libpq calls. */ + load_file("libpqwalreceiver", false); + + /* Check the connection info string. */ + walrcv_check_conninfo(conninfo); + + /* Everything ok, form a new tuple. */ + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(nulls)); + + values[Anum_pg_subscription_subdbid - 1] = ObjectIdGetDatum(MyDatabaseId); + values[Anum_pg_subscription_subname - 1] = + DirectFunctionCall1(namein, CStringGetDatum(stmt->subname)); + values[Anum_pg_subscription_subowner - 1] = ObjectIdGetDatum(owner); + values[Anum_pg_subscription_subenabled - 1] = BoolGetDatum(enabled); + values[Anum_pg_subscription_subconninfo - 1] = + CStringGetTextDatum(conninfo); + values[Anum_pg_subscription_subslotname - 1] = + DirectFunctionCall1(namein, CStringGetDatum(slotname)); + values[Anum_pg_subscription_subpublications - 1] = + publicationListToArray(publications); + + tup = heap_form_tuple(RelationGetDescr(rel), values, nulls); + + /* Insert tuple into catalog. */ + subid = simple_heap_insert(rel, tup); + CatalogUpdateIndexes(rel, tup); + heap_freetuple(tup); + + recordDependencyOnOwner(SubscriptionRelationId, subid, owner); + + snprintf(originname, sizeof(originname), "pg_%u", subid); + replorigin_create(originname); + + /* + * If requested, create the replication slot on remote side for our + * newly created subscription. + */ + if (create_slot) + { + XLogRecPtr lsn; + char *err; + WalReceiverConn *wrconn; + + /* Try to connect to the publisher. */ + wrconn = walrcv_connect(conninfo, true, stmt->subname, &err); + if (!wrconn) + ereport(ERROR, + (errmsg("could not connect to the publisher: %s", err))); + + walrcv_create_slot(wrconn, slotname, false, &lsn); + ereport(NOTICE, + (errmsg("created replication slot \"%s\" on publisher", + slotname))); + + /* And we are done with the remote side. */ + walrcv_disconnect(wrconn); + } + + heap_close(rel, RowExclusiveLock); + + ApplyLauncherWakeupAtCommit(); + + ObjectAddressSet(myself, SubscriptionRelationId, subid); + + InvokeObjectPostCreateHook(SubscriptionRelationId, subid, 0); + + return myself; +} + +/* + * Alter the existing subscription. + */ +ObjectAddress +AlterSubscription(AlterSubscriptionStmt *stmt) +{ + Relation rel; + ObjectAddress myself; + bool nulls[Natts_pg_subscription]; + bool replaces[Natts_pg_subscription]; + Datum values[Natts_pg_subscription]; + HeapTuple tup; + Oid subid; + bool enabled_given; + bool enabled; + char *conninfo; + char *slot_name; + List *publications; + + rel = heap_open(SubscriptionRelationId, RowExclusiveLock); + + /* Fetch the existing tuple. */ + tup = SearchSysCacheCopy2(SUBSCRIPTIONNAME, MyDatabaseId, + CStringGetDatum(stmt->subname)); + + if (!HeapTupleIsValid(tup)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("subscription \"%s\" does not exist", + stmt->subname))); + + /* must be owner */ + if (!pg_subscription_ownercheck(HeapTupleGetOid(tup), GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_SUBSCRIPTION, + stmt->subname); + + subid = HeapTupleGetOid(tup); + + /* Parse options. */ + parse_subscription_options(stmt->options, &conninfo, &publications, + &enabled_given, &enabled, + NULL, &slot_name); + + /* Form a new tuple. */ + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(nulls)); + memset(replaces, false, sizeof(replaces)); + + if (enabled_given) + { + values[Anum_pg_subscription_subenabled - 1] = BoolGetDatum(enabled); + replaces[Anum_pg_subscription_subenabled - 1] = true; + } + if (conninfo) + { + values[Anum_pg_subscription_subconninfo - 1] = + CStringGetTextDatum(conninfo); + replaces[Anum_pg_subscription_subconninfo - 1] = true; + } + if (slot_name) + { + values[Anum_pg_subscription_subslotname - 1] = + DirectFunctionCall1(namein, CStringGetDatum(slot_name)); + replaces[Anum_pg_subscription_subslotname - 1] = true; + } + if (publications != NIL) + { + values[Anum_pg_subscription_subpublications - 1] = + publicationListToArray(publications); + replaces[Anum_pg_subscription_subpublications - 1] = true; + } + + tup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls, + replaces); + + /* Update the catalog. */ + simple_heap_update(rel, &tup->t_self, tup); + CatalogUpdateIndexes(rel, tup); + + ObjectAddressSet(myself, SubscriptionRelationId, subid); + + /* Cleanup. */ + heap_freetuple(tup); + heap_close(rel, RowExclusiveLock); + + InvokeObjectPostAlterHook(SubscriptionRelationId, subid, 0); + + return myself; +} + +/* + * Drop a subscription + */ +void +DropSubscription(DropSubscriptionStmt *stmt) +{ + Relation rel; + ObjectAddress myself; + HeapTuple tup; + Oid subid; + Datum datum; + bool isnull; + char *subname; + char *conninfo; + char *slotname; + char originname[NAMEDATALEN]; + char *err = NULL; + RepOriginId originid; + WalReceiverConn *wrconn = NULL; + StringInfoData cmd; + + rel = heap_open(SubscriptionRelationId, RowExclusiveLock); + + tup = SearchSysCache2(SUBSCRIPTIONNAME, MyDatabaseId, + CStringGetDatum(stmt->subname)); + + if (!HeapTupleIsValid(tup)) + { + heap_close(rel, NoLock); + + if (!stmt->missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("subscription \"%s\" does not exist", + stmt->subname))); + else + ereport(NOTICE, + (errmsg("subscription \"%s\" does not exist, skipping", + stmt->subname))); + + return; + } + + subid = HeapTupleGetOid(tup); + + /* must be owner */ + if (!pg_subscription_ownercheck(subid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_SUBSCRIPTION, + stmt->subname); + + /* DROP hook for the subscription being removed */ + InvokeObjectDropHook(SubscriptionRelationId, subid, 0); + + /* + * Lock the subscription so noboby else can do anything with it + * (including the replication workers). + */ + LockSharedObject(SubscriptionRelationId, subid, 0, AccessExclusiveLock); + + /* Get subname */ + datum = SysCacheGetAttr(SUBSCRIPTIONOID, tup, + Anum_pg_subscription_subname, &isnull); + Assert(!isnull); + subname = pstrdup(NameStr(*DatumGetName(datum))); + + /* Get conninfo */ + datum = SysCacheGetAttr(SUBSCRIPTIONOID, tup, + Anum_pg_subscription_subconninfo, &isnull); + Assert(!isnull); + conninfo = pstrdup(TextDatumGetCString(datum)); + + /* Get slotname */ + datum = SysCacheGetAttr(SUBSCRIPTIONOID, tup, + Anum_pg_subscription_subslotname, &isnull); + Assert(!isnull); + slotname = pstrdup(NameStr(*DatumGetName(datum))); + + ObjectAddressSet(myself, SubscriptionRelationId, subid); + EventTriggerSQLDropAddObject(&myself, true, true); + + /* Remove the tuple from catalog. */ + simple_heap_delete(rel, &tup->t_self); + + ReleaseSysCache(tup); + + /* Clean up dependencies */ + deleteSharedDependencyRecordsFor(SubscriptionRelationId, subid, 0); + + /* Protect against launcher restarting the worker. */ + LWLockAcquire(LogicalRepLauncherLock, LW_EXCLUSIVE); + + /* Kill the apply worker so that the slot becomes accessible. */ + logicalrep_worker_stop(subid); + + /* Remove the origin tracking if exists. */ + snprintf(originname, sizeof(originname), "pg_%u", subid); + originid = replorigin_by_name(originname, true); + if (originid != InvalidRepOriginId) + replorigin_drop(originid); + + /* If the user asked to not drop the slot, we are done mow.*/ + if (!stmt->drop_slot) + { + heap_close(rel, NoLock); + return; + } + + /* + * Otherwise drop the replication slot at the publisher node using + * the replication connection. + */ + load_file("libpqwalreceiver", false); + + initStringInfo(&cmd); + appendStringInfo(&cmd, "DROP_REPLICATION_SLOT \"%s\"", slotname); + + wrconn = walrcv_connect(conninfo, true, subname, &err); + if (wrconn == NULL) + ereport(ERROR, + (errmsg("could not connect to publisher when attempting to " + "drop the replication slot \"%s\"", slotname), + errdetail("The error was: %s", err))); + + if (!walrcv_command(wrconn, cmd.data, &err)) + ereport(ERROR, + (errmsg("could not drop the replication slot \"%s\" on publisher", + slotname), + errdetail("The error was: %s", err))); + else + ereport(NOTICE, + (errmsg("dropped replication slot \"%s\" on publisher", + slotname))); + + walrcv_disconnect(wrconn); + + pfree(cmd.data); + + heap_close(rel, NoLock); +} + +/* + * Internal workhorse for changing a subscription owner + */ +static void +AlterSubscriptionOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) +{ + Form_pg_subscription form; + + form = (Form_pg_subscription) GETSTRUCT(tup); + + if (form->subowner == newOwnerId) + return; + + if (!pg_subscription_ownercheck(HeapTupleGetOid(tup), GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_SUBSCRIPTION, + NameStr(form->subname)); + + /* New owner must be a superuser */ + if (!superuser_arg(newOwnerId)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied to change owner of subscription \"%s\"", + NameStr(form->subname)), + errhint("The owner of an subscription must be a superuser."))); + + form->subowner = newOwnerId; + simple_heap_update(rel, &tup->t_self, tup); + CatalogUpdateIndexes(rel, tup); + + /* Update owner dependency reference */ + changeDependencyOnOwner(SubscriptionRelationId, + HeapTupleGetOid(tup), + newOwnerId); + + InvokeObjectPostAlterHook(SubscriptionRelationId, + HeapTupleGetOid(tup), 0); +} + +/* + * Change subscription owner -- by name + */ +ObjectAddress +AlterSubscriptionOwner(const char *name, Oid newOwnerId) +{ + Oid subid; + HeapTuple tup; + Relation rel; + ObjectAddress address; + + rel = heap_open(SubscriptionRelationId, RowExclusiveLock); + + tup = SearchSysCacheCopy2(SUBSCRIPTIONNAME, MyDatabaseId, + CStringGetDatum(name)); + + if (!HeapTupleIsValid(tup)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("subscription \"%s\" does not exist", name))); + + subid = HeapTupleGetOid(tup); + + AlterSubscriptionOwner_internal(rel, tup, newOwnerId); + + ObjectAddressSet(address, SubscriptionRelationId, subid); + + heap_freetuple(tup); + + heap_close(rel, RowExclusiveLock); + + return address; +} + +/* + * Change subscription owner -- by OID + */ +void +AlterSubscriptionOwner_oid(Oid subid, Oid newOwnerId) +{ + HeapTuple tup; + Relation rel; + + rel = heap_open(SubscriptionRelationId, RowExclusiveLock); + + tup = SearchSysCacheCopy1(SUBSCRIPTIONOID, ObjectIdGetDatum(subid)); + + if (!HeapTupleIsValid(tup)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("subscription with OID %u does not exist", subid))); + + AlterSubscriptionOwner_internal(rel, tup, newOwnerId); + + heap_freetuple(tup); + + heap_close(rel, RowExclusiveLock); +} diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 86e98148c1..c4b0011bdd 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -3,7 +3,7 @@ * tablecmds.c * Commands for creating and altering table structures and settings * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -20,6 +20,7 @@ #include "access/reloptions.h" #include "access/relscan.h" #include "access/sysattr.h" +#include "access/tupconvert.h" #include "access/xact.h" #include "access/xlog.h" #include "catalog/catalog.h" @@ -29,6 +30,7 @@ #include "catalog/indexing.h" #include "catalog/namespace.h" #include "catalog/objectaccess.h" +#include "catalog/partition.h" #include "catalog/pg_am.h" #include "catalog/pg_collation.h" #include "catalog/pg_constraint.h" @@ -65,6 +67,9 @@ #include "nodes/parsenodes.h" #include "optimizer/clauses.h" #include "optimizer/planner.h" +#include "optimizer/predtest.h" +#include "optimizer/prep.h" +#include "optimizer/var.h" #include "parser/parse_clause.h" #include "parser/parse_coerce.h" #include "parser/parse_collate.h" @@ -162,6 +167,7 @@ typedef struct AlteredTableInfo Oid newTableSpace; /* new tablespace; 0 means no change */ bool chgPersistence; /* T if SET LOGGED/UNLOGGED is used */ char newrelpersistence; /* if above is true */ + List *partition_constraint; /* for attach partition validation */ /* Objects to rebuild after completing ALTER TYPE operations */ List *changedConstraintOids; /* OIDs of constraints to rebuild */ List *changedConstraintDefs; /* string definitions of same */ @@ -252,6 +258,12 @@ static const struct dropmsgstrings dropmsgstringarray[] = { gettext_noop("foreign table \"%s\" does not exist, skipping"), gettext_noop("\"%s\" is not a foreign table"), gettext_noop("Use DROP FOREIGN TABLE to remove a foreign table.")}, + {RELKIND_PARTITIONED_TABLE, + ERRCODE_UNDEFINED_TABLE, + gettext_noop("table \"%s\" does not exist"), + gettext_noop("table \"%s\" does not exist, skipping"), + gettext_noop("\"%s\" is not a table"), + gettext_noop("Use DROP TABLE to remove a table.")}, {'\0', 0, NULL, NULL, NULL, NULL} }; @@ -272,7 +284,8 @@ struct DropRelationCallbackState static void truncate_check_rel(Relation rel); static List *MergeAttributes(List *schema, List *supers, char relpersistence, - List **supOids, List **supconstr, int *supOidCount); + bool is_partition, List **supOids, List **supconstr, + int *supOidCount); static bool MergeCheckConstraint(List *constraints, char *name, Node *expr); static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel); static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel); @@ -339,7 +352,9 @@ static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid); static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid); static void ATPrepAddOids(List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd, LOCKMODE lockmode); +static void ATPrepDropNotNull(Relation rel, bool recurse, bool recursing); static ObjectAddress ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode); +static void ATPrepSetNotNull(Relation rel, bool recurse, bool recursing); static ObjectAddress ATExecSetNotNull(AlteredTableInfo *tab, Relation rel, const char *colName, LOCKMODE lockmode); static ObjectAddress ATExecColumnDefault(Relation rel, const char *colName, @@ -433,6 +448,15 @@ static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg); static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg); +static bool is_partition_attr(Relation rel, AttrNumber attnum, bool *used_in_expr); +static PartitionSpec *transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy); +static void ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs, + List **partexprs, Oid *partopclass, Oid *partcollation); +static void CreateInheritance(Relation child_rel, Relation parent_rel); +static void RemoveInheritance(Relation child_rel, Relation parent_rel); +static ObjectAddress ATExecAttachPartition(List **wqueue, Relation rel, + PartitionCmd *cmd); +static ObjectAddress ATExecDetachPartition(Relation rel, RangeVar *name); /* ---------------------------------------------------------------- @@ -455,7 +479,7 @@ static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, */ ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, - ObjectAddress *typaddress) + ObjectAddress *typaddress, const char *queryString) { char relname[NAMEDATALEN]; Oid namespaceId; @@ -492,6 +516,14 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("ON COMMIT can only be used on temporary tables"))); + if (stmt->partspec != NULL) + { + if (relkind != RELKIND_RELATION) + elog(ERROR, "unexpected relkind: %d", (int) relkind); + + relkind = RELKIND_PARTITIONED_TABLE; + } + /* * Look up the namespace in which we are supposed to create the relation, * check we have permission to create there, lock it against concurrent @@ -578,6 +610,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, */ schema = MergeAttributes(schema, stmt->inhRelations, stmt->relation->relpersistence, + stmt->partbound != NULL, &inheritOids, &old_constraints, &parentOidCount); /* @@ -588,17 +621,33 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, descriptor = BuildDescForRelation(schema); /* - * Notice that we allow OIDs here only for plain tables, even though some - * other relkinds can support them. This is necessary because the - * default_with_oids GUC must apply only to plain tables and not any other - * relkind; doing otherwise would break existing pg_dump files. We could - * allow explicit "WITH OIDS" while not allowing default_with_oids to - * affect other relkinds, but it would complicate interpretOidsOption(). + * Notice that we allow OIDs here only for plain tables and partitioned + * tables, even though some other relkinds can support them. This is + * necessary because the default_with_oids GUC must apply only to plain + * tables and not any other relkind; doing otherwise would break existing + * pg_dump files. We could allow explicit "WITH OIDS" while not allowing + * default_with_oids to affect other relkinds, but it would complicate + * interpretOidsOption(). */ localHasOids = interpretOidsOption(stmt->options, - (relkind == RELKIND_RELATION)); + (relkind == RELKIND_RELATION || + relkind == RELKIND_PARTITIONED_TABLE)); descriptor->tdhasoid = (localHasOids || parentOidCount > 0); + if (stmt->partbound) + { + /* If the parent has OIDs, partitions must have them too. */ + if (parentOidCount > 0 && !localHasOids) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot create table without OIDs as partition of table with OIDs"))); + /* If the parent doesn't, partitions must not have them. */ + if (parentOidCount == 0 && localHasOids) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot create table with OIDs as partition of table without OIDs"))); + } + /* * Find columns with default values and prepare for insertion of the * defaults. Pre-cooked (that is, inherited) defaults go into a list of @@ -697,6 +746,111 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, */ rel = relation_open(relationId, AccessExclusiveLock); + /* Process and store partition bound, if any. */ + if (stmt->partbound) + { + Node *bound; + ParseState *pstate; + Oid parentId = linitial_oid(inheritOids); + Relation parent; + + /* Already have strong enough lock on the parent */ + parent = heap_open(parentId, NoLock); + + /* + * We are going to try to validate the partition bound specification + * against the partition key of parentRel, so it better have one. + */ + if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("\"%s\" is not partitioned", + RelationGetRelationName(parent)))); + + /* Tranform the bound values */ + pstate = make_parsestate(NULL); + pstate->p_sourcetext = queryString; + bound = transformPartitionBound(pstate, parent, stmt->partbound); + + /* + * Check first that the new partition's bound is valid and does not + * overlap with any of existing partitions of the parent - note that + * it does not return on error. + */ + check_new_partition_bound(relname, parent, bound); + + /* Update the pg_class entry. */ + StorePartitionBound(rel, parent, bound); + + heap_close(parent, NoLock); + + /* + * The code that follows may also update the pg_class tuple to update + * relnumchecks, so bump up the command counter to avoid the "already + * updated by self" error. + */ + CommandCounterIncrement(); + } + + /* + * Process the partitioning specification (if any) and store the partition + * key information into the catalog. + */ + if (stmt->partspec) + { + char strategy; + int partnatts, + i; + AttrNumber partattrs[PARTITION_MAX_KEYS]; + Oid partopclass[PARTITION_MAX_KEYS]; + Oid partcollation[PARTITION_MAX_KEYS]; + List *partexprs = NIL; + List *cmds = NIL; + + /* + * We need to transform the raw parsetrees corresponding to partition + * expressions into executable expression trees. Like column defaults + * and CHECK constraints, we could not have done the transformation + * earlier. + */ + stmt->partspec = transformPartitionSpec(rel, stmt->partspec, + &strategy); + ComputePartitionAttrs(rel, stmt->partspec->partParams, + partattrs, &partexprs, partopclass, + partcollation); + + partnatts = list_length(stmt->partspec->partParams); + StorePartitionKey(rel, strategy, partnatts, partattrs, partexprs, + partopclass, partcollation); + + /* Force key columns to be NOT NULL when using range partitioning */ + if (strategy == PARTITION_STRATEGY_RANGE) + { + for (i = 0; i < partnatts; i++) + { + AttrNumber partattno = partattrs[i]; + Form_pg_attribute attform = descriptor->attrs[partattno - 1]; + + if (partattno != 0 && !attform->attnotnull) + { + /* Add a subcommand to make this one NOT NULL */ + AlterTableCmd *cmd = makeNode(AlterTableCmd); + + cmd->subtype = AT_SetNotNull; + cmd->name = pstrdup(NameStr(attform->attname)); + cmds = lappend(cmds, cmd); + } + } + + /* + * Although, there cannot be any partitions yet, we still need to + * pass true for recurse; ATPrepSetNotNull() complains if we don't + */ + if (cmds != NIL) + AlterTableInternal(RelationGetRelid(rel), cmds, true); + } + } + /* * Now add any newly specified column default values and CHECK constraints * to the new relation. These are passed to us in the form of raw @@ -927,6 +1081,7 @@ RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid, HeapTuple tuple; struct DropRelationCallbackState *state; char relkind; + char expected_relkind; Form_pg_class classform; LOCKMODE heap_lockmode; @@ -955,7 +1110,19 @@ RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid, return; /* concurrently dropped, so nothing to do */ classform = (Form_pg_class) GETSTRUCT(tuple); - if (classform->relkind != relkind) + /* + * Both RELKIND_RELATION and RELKIND_PARTITIONED_TABLE are OBJECT_TABLE, + * but RemoveRelations() can only pass one relkind for a given relation. + * It chooses RELKIND_RELATION for both regular and partitioned tables. + * That means we must be careful before giving the wrong type error when + * the relation is RELKIND_PARTITIONED_TABLE. + */ + if (classform->relkind == RELKIND_PARTITIONED_TABLE) + expected_relkind = RELKIND_RELATION; + else + expected_relkind = classform->relkind; + + if (relkind != expected_relkind) DropErrorMsgWrongType(rel->relname, classform->relkind, relkind); /* Allow DROP to either table owner or schema owner */ @@ -1018,7 +1185,7 @@ ExecuteTruncate(TruncateStmt *stmt) { RangeVar *rv = lfirst(cell); Relation rel; - bool recurse = interpretInhOption(rv->inhOpt); + bool recurse = rv->inh; Oid myrelid; rel = heap_openrv(rv, AccessExclusiveLock); @@ -1054,6 +1221,10 @@ ExecuteTruncate(TruncateStmt *stmt) relids = lappend_oid(relids, childrelid); } } + else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("must truncate child tables too"))); } /* @@ -1153,6 +1324,7 @@ ExecuteTruncate(TruncateStmt *stmt) InitResultRelInfo(resultRelInfo, rel, 0, /* dummy rangetable index */ + NULL, 0); resultRelInfo++; } @@ -1293,7 +1465,8 @@ truncate_check_rel(Relation rel) AclResult aclresult; /* Only allow truncate on regular tables */ - if (rel->rd_rel->relkind != RELKIND_RELATION) + if (rel->rd_rel->relkind != RELKIND_RELATION && + rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table", @@ -1359,6 +1532,7 @@ storage_name(char c) * of ColumnDef's.) It is destructively changed. * 'supers' is a list of names (as RangeVar nodes) of parent relations. * 'relpersistence' is a persistence type of the table. + * 'is_partition' tells if the table is a partition * * Output arguments: * 'supOids' receives a list of the OIDs of the parent relations. @@ -1410,7 +1584,8 @@ storage_name(char c) */ static List * MergeAttributes(List *schema, List *supers, char relpersistence, - List **supOids, List **supconstr, int *supOidCount) + bool is_partition, List **supOids, List **supconstr, + int *supOidCount) { ListCell *entry; List *inhSchema = NIL; @@ -1420,6 +1595,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence, bool have_bogus_defaults = false; int child_attno; static Node bogus_marker = {0}; /* marks conflicting defaults */ + List *saved_schema = NIL; /* * Check for and reject tables with too many columns. We perform this @@ -1429,8 +1605,8 @@ MergeAttributes(List *schema, List *supers, char relpersistence, * execute if the user attempts to create a table with hundreds of * thousands of columns. * - * Note that we also need to check that any we do not exceed this figure - * after including columns from inherited relations. + * Note that we also need to check that we do not exceed this figure after + * including columns from inherited relations. */ if (list_length(schema) > MaxHeapAttributeNumber) ereport(ERROR, @@ -1438,6 +1614,17 @@ MergeAttributes(List *schema, List *supers, char relpersistence, errmsg("tables can have at most %d columns", MaxHeapAttributeNumber))); + /* + * In case of a partition, there are no new column definitions, only dummy + * ColumnDefs created for column constraints. We merge them with the + * constraints inherited from the parent. + */ + if (is_partition) + { + saved_schema = schema; + schema = NIL; + } + /* * Check for duplicate names in the explicit list of attributes. * @@ -1518,11 +1705,35 @@ MergeAttributes(List *schema, List *supers, char relpersistence, * on the parent table, which might otherwise be attempting to clear * the parent's relhassubclass field, if its previous children were * recently dropped. + * + * If the child table is a partition, then we instead grab an + * exclusive lock on the parent because its partition descriptor will + * be changed by addition of the new partition. + */ + if (!is_partition) + relation = heap_openrv(parent, ShareUpdateExclusiveLock); + else + relation = heap_openrv(parent, AccessExclusiveLock); + + /* + * We do not allow partitioned tables and partitions to participate in + * regular inheritance. */ - relation = heap_openrv(parent, ShareUpdateExclusiveLock); + if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && + !is_partition) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot inherit from partitioned table \"%s\"", + parent->relname))); + if (relation->rd_rel->relispartition && !is_partition) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot inherit from partition \"%s\"", + parent->relname))); if (relation->rd_rel->relkind != RELKIND_RELATION && - relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE) + relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE && + relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("inherited relation \"%s\" is not a table or foreign table", @@ -1532,7 +1743,9 @@ MergeAttributes(List *schema, List *supers, char relpersistence, relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("cannot inherit from temporary relation \"%s\"", + errmsg(!is_partition + ? "cannot inherit from temporary relation \"%s\"" + : "cannot create a permanent relation as partition of temporary relation \"%s\"", parent->relname))); /* If existing rel is temp, it must belong to this session */ @@ -1540,7 +1753,9 @@ MergeAttributes(List *schema, List *supers, char relpersistence, !relation->rd_islocaltemp) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("cannot inherit from temporary relation of another session"))); + errmsg(!is_partition + ? "cannot inherit from temporary relation of another session" + : "cannot create as partition of temporary relation of another session"))); /* * We should have an UNDER permission flag for this, but for now, @@ -1777,9 +1992,9 @@ MergeAttributes(List *schema, List *supers, char relpersistence, pfree(newattno); /* - * Close the parent rel, but keep our ShareUpdateExclusiveLock on it - * until xact commit. That will prevent someone else from deleting or - * ALTERing the parent before the child is committed. + * Close the parent rel, but keep our lock on it until xact commit. + * That will prevent someone else from deleting or ALTERing the parent + * before the child is committed. */ heap_close(relation, NoLock); } @@ -1787,7 +2002,8 @@ MergeAttributes(List *schema, List *supers, char relpersistence, /* * If we had no inherited attributes, the result schema is just the * explicitly declared columns. Otherwise, we need to merge the declared - * columns into the inherited schema list. + * columns into the inherited schema list. Although, we never have any + * explicitly declared columns if the table is a partition. */ if (inhSchema != NIL) { @@ -1815,6 +2031,12 @@ MergeAttributes(List *schema, List *supers, char relpersistence, Oid defcollid, newcollid; + /* + * Partitions have only one parent and have no column + * definitions of their own, so conflict should never occur. + */ + Assert(!is_partition); + /* * Yes, try to merge the two column definitions. They must * have the same type, typmod, and collation. @@ -1896,6 +2118,56 @@ MergeAttributes(List *schema, List *supers, char relpersistence, MaxHeapAttributeNumber))); } + /* + * Now that we have the column definition list for a partition, we can + * check whether the columns referenced in the column constraint specs + * actually exist. Also, we merge the constraints into the corresponding + * column definitions. + */ + if (is_partition && list_length(saved_schema) > 0) + { + schema = list_concat(schema, saved_schema); + + foreach(entry, schema) + { + ColumnDef *coldef = lfirst(entry); + ListCell *rest = lnext(entry); + ListCell *prev = entry; + + /* + * Partition column option that does not belong to a column from + * the parent. This works because the columns from the parent + * come first in the list (see above). + */ + if (coldef->typeName == NULL) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" does not exist", + coldef->colname))); + while (rest != NULL) + { + ColumnDef *restdef = lfirst(rest); + ListCell *next = lnext(rest); /* need to save it in case we + * delete it */ + + if (strcmp(coldef->colname, restdef->colname) == 0) + { + /* + * merge the column options into the column from the + * parent + */ + coldef->is_not_null = restdef->is_not_null; + coldef->raw_default = restdef->raw_default; + coldef->cooked_default = restdef->cooked_default; + coldef->constraints = restdef->constraints; + list_delete_cell(schema, rest, prev); + } + prev = rest; + rest = next; + } + } + } + /* * If we found any conflicting parent default values, check to make sure * they were overridden by the child. @@ -2166,7 +2438,8 @@ renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing) relkind != RELKIND_MATVIEW && relkind != RELKIND_COMPOSITE_TYPE && relkind != RELKIND_INDEX && - relkind != RELKIND_FOREIGN_TABLE) + relkind != RELKIND_FOREIGN_TABLE && + relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table, view, materialized view, composite type, index, or foreign table", @@ -2383,7 +2656,7 @@ renameatt(RenameStmt *stmt) renameatt_internal(relid, stmt->subname, /* old att name */ stmt->newname, /* new att name */ - interpretInhOption(stmt->relation->inhOpt), /* recursive? */ + stmt->relation->inh, /* recursive? */ false, /* recursing? */ 0, /* expected inhcount */ stmt->behavior); @@ -2535,7 +2808,8 @@ RenameConstraint(RenameStmt *stmt) rename_constraint_internal(relid, typid, stmt->subname, stmt->newname, - stmt->relation ? interpretInhOption(stmt->relation->inhOpt) : false, /* recursive? */ + (stmt->relation && + stmt->relation->inh), /* recursive? */ false, /* recursing? */ 0 /* expected inhcount */ ); @@ -2777,9 +3051,7 @@ AlterTable(Oid relid, LOCKMODE lockmode, AlterTableStmt *stmt) CheckTableNotInUse(rel, "ALTER TABLE"); - ATController(stmt, - rel, stmt->cmds, interpretInhOption(stmt->relation->inhOpt), - lockmode); + ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode); } /* @@ -3057,6 +3329,11 @@ AlterTableGetLockLevel(List *cmds) cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def); break; + case AT_AttachPartition: + case AT_DetachPartition: + cmd_lockmode = AccessExclusiveLock; + break; + default: /* oops */ elog(ERROR, "unrecognized alter table type: %d", (int) cmd->subtype); @@ -3168,12 +3445,14 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, break; case AT_DropNotNull: /* ALTER COLUMN DROP NOT NULL */ ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE); + ATPrepDropNotNull(rel, recurse, recursing); ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode); /* No command-specific prep needed */ pass = AT_PASS_DROP; break; case AT_SetNotNull: /* ALTER COLUMN SET NOT NULL */ ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE); + ATPrepSetNotNull(rel, recurse, recursing); ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode); /* No command-specific prep needed */ pass = AT_PASS_ADD_CONSTR; @@ -3374,6 +3653,12 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, /* No command-specific prep needed */ pass = AT_PASS_MISC; break; + case AT_AttachPartition: + case AT_DetachPartition: + ATSimplePermissions(rel, ATT_TABLE); + /* No command-specific prep needed */ + pass = AT_PASS_MISC; + break; default: /* oops */ elog(ERROR, "unrecognized alter table type: %d", (int) cmd->subtype); @@ -3444,7 +3729,14 @@ ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode) { AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab); - if (tab->relkind == RELKIND_RELATION || + /* + * If the table is source table of ATTACH PARTITION command, we did + * not modify anything about it that will change its toasting + * requirement, so no need to check. + */ + if (((tab->relkind == RELKIND_RELATION || + tab->relkind == RELKIND_PARTITIONED_TABLE) && + tab->partition_constraint == NIL) || tab->relkind == RELKIND_MATVIEW) AlterTableCreateToastTable(tab->relid, (Datum) 0, lockmode); } @@ -3693,6 +3985,12 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, case AT_GenericOptions: ATExecGenericOptions(rel, (List *) cmd->def); break; + case AT_AttachPartition: + ATExecAttachPartition(wqueue, rel, (PartitionCmd *) cmd->def); + break; + case AT_DetachPartition: + ATExecDetachPartition(rel, ((PartitionCmd *) cmd->def)->name); + break; default: /* oops */ elog(ERROR, "unrecognized alter table type: %d", (int) cmd->subtype); @@ -3878,7 +4176,8 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode) * Test the current data within the table against new constraints * generated by ALTER TABLE commands, but don't rebuild data. */ - if (tab->constraints != NIL || tab->new_notnull) + if (tab->constraints != NIL || tab->new_notnull || + tab->partition_constraint != NIL) ATRewriteTable(tab, InvalidOid, lockmode); /* @@ -3958,6 +4257,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode) CommandId mycid; BulkInsertState bistate; int hi_options; + List *partqualstate = NIL; /* * Open the relation(s). We have surely already locked the existing @@ -4022,6 +4322,15 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode) } } + /* Build expression execution states for partition check quals */ + if (tab->partition_constraint) + { + needscan = true; + partqualstate = (List *) + ExecPrepareExpr((Expr *) tab->partition_constraint, + estate); + } + foreach(l, tab->newvals) { NewColumnValue *ex = lfirst(l); @@ -4151,8 +4460,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode) values[ex->attnum - 1] = ExecEvalExpr(ex->exprstate, econtext, - &isnull[ex->attnum - 1], - NULL); + &isnull[ex->attnum - 1]); } /* @@ -4211,6 +4519,11 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode) } } + if (partqualstate && !ExecQual(partqualstate, econtext, true)) + ereport(ERROR, + (errcode(ERRCODE_CHECK_VIOLATION), + errmsg("partition constraint is violated by some row"))); + /* Write the tuple out to the new relation */ if (newrel) heap_insert(newrel, tuple, mycid, hi_options, bistate); @@ -4291,6 +4604,7 @@ ATSimplePermissions(Relation rel, int allowed_targets) switch (rel->rd_rel->relkind) { case RELKIND_RELATION: + case RELKIND_PARTITIONED_TABLE: actual_target = ATT_TABLE; break; case RELKIND_VIEW: @@ -4407,7 +4721,8 @@ ATSimpleRecursion(List **wqueue, Relation rel, */ if (recurse && (rel->rd_rel->relkind == RELKIND_RELATION || - rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)) + rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE || + rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)) { Oid relid = RelationGetRelid(rel); ListCell *child; @@ -4527,7 +4842,8 @@ find_composite_type_dependencies(Oid typeOid, Relation origRelation, att = rel->rd_att->attrs[pg_depend->objsubid - 1]; if (rel->rd_rel->relkind == RELKIND_RELATION || - rel->rd_rel->relkind == RELKIND_MATVIEW) + rel->rd_rel->relkind == RELKIND_MATVIEW || + rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) { if (origTypeName) ereport(ERROR, @@ -4728,6 +5044,11 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, if (recursing) ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE); + if (rel->rd_rel->relispartition && !recursing) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot add column to a partition"))); + attrdesc = heap_open(AttributeRelationId, RowExclusiveLock); /* @@ -5174,6 +5495,20 @@ ATPrepAddOids(List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd, LOC * Return the address of the modified column. If the column was already * nullable, InvalidObjectAddress is returned. */ + +static void +ATPrepDropNotNull(Relation rel, bool recurse, bool recursing) +{ + /* + * If the parent is a partitioned table, like check constraints, NOT NULL + * constraints must be dropped from child tables. + */ + if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && + !recurse && !recursing) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("constraint must be dropped from child tables too"))); +} static ObjectAddress ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode) { @@ -5249,6 +5584,45 @@ ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode) list_free(indexoidlist); + /* If rel is partition, shouldn't drop NOT NULL if parent has the same */ + if (rel->rd_rel->relispartition) + { + Oid parentId = get_partition_parent(RelationGetRelid(rel)); + Relation parent = heap_open(parentId, AccessShareLock); + TupleDesc tupDesc = RelationGetDescr(parent); + AttrNumber parent_attnum; + + parent_attnum = get_attnum(parentId, colName); + if (tupDesc->attrs[parent_attnum - 1]->attnotnull) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("column \"%s\" is marked NOT NULL in parent table", + colName))); + heap_close(parent, AccessShareLock); + } + + /* + * If the table is a range partitioned table, check that the column is not + * in the partition key. + */ + if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + { + PartitionKey key = RelationGetPartitionKey(rel); + int partnatts = get_partition_natts(key), + i; + + for (i = 0; i < partnatts; i++) + { + AttrNumber partattnum = get_partition_col_attnum(key, i); + + if (partattnum == attnum) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("column \"%s\" is in range partition key", + colName))); + } + } + /* * Okay, actually perform the catalog change ... if needed */ @@ -5281,6 +5655,21 @@ ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode) * Return the address of the modified column. If the column was already NOT * NULL, InvalidObjectAddress is returned. */ + +static void +ATPrepSetNotNull(Relation rel, bool recurse, bool recursing) +{ + /* + * If the parent is a partitioned table, like check constraints, NOT NULL + * constraints must be added to the child tables. + */ + if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && + !recurse && !recursing) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("constraint must be added to child tables too"))); +} + static ObjectAddress ATExecSetNotNull(AlteredTableInfo *tab, Relation rel, const char *colName, LOCKMODE lockmode) @@ -5419,7 +5808,8 @@ ATPrepSetStatistics(Relation rel, const char *colName, Node *newValue, LOCKMODE if (rel->rd_rel->relkind != RELKIND_RELATION && rel->rd_rel->relkind != RELKIND_MATVIEW && rel->rd_rel->relkind != RELKIND_INDEX && - rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE) + rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE && + rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table, materialized view, index, or foreign table", @@ -5691,6 +6081,68 @@ ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing, cmd->subtype = AT_DropColumnRecurse; } +/* + * Checks if attnum is a partition attribute for rel + * + * Sets *used_in_expr if attnum is found to be referenced in some partition + * key expression. It's possible for a column to be both used directly and + * as part of an expression; if that happens, *used_in_expr may end up as + * either true or false. That's OK for current uses of this function, because + * *used_in_expr is only used to tailor the error message text. + */ +static bool +is_partition_attr(Relation rel, AttrNumber attnum, bool *used_in_expr) +{ + PartitionKey key; + int partnatts; + List *partexprs; + ListCell *partexprs_item; + int i; + + if (rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) + return false; + + key = RelationGetPartitionKey(rel); + partnatts = get_partition_natts(key); + partexprs = get_partition_exprs(key); + + partexprs_item = list_head(partexprs); + for (i = 0; i < partnatts; i++) + { + AttrNumber partattno = get_partition_col_attnum(key, i); + + if (partattno != 0) + { + if (attnum == partattno) + { + if (used_in_expr) + *used_in_expr = false; + return true; + } + } + else + { + /* Arbitrary expression */ + Node *expr = (Node *) lfirst(partexprs_item); + Bitmapset *expr_attrs = NULL; + + /* Find all attributes referenced */ + pull_varattnos(expr, 1, &expr_attrs); + partexprs_item = lnext(partexprs_item); + + if (bms_is_member(attnum - FirstLowInvalidHeapAttributeNumber, + expr_attrs)) + { + if (used_in_expr) + *used_in_expr = true; + return true; + } + } + } + + return false; +} + /* * Return value is the address of the dropped column. */ @@ -5705,6 +6157,7 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName, AttrNumber attnum; List *children; ObjectAddress object; + bool is_expr; /* At top level, permission check was done in ATPrepCmd, else do it */ if (recursing) @@ -5749,6 +6202,19 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName, errmsg("cannot drop inherited column \"%s\"", colName))); + /* Don't drop columns used in the partition key */ + if (is_partition_attr(rel, attnum, &is_expr)) + { + if (!is_expr) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("cannot drop column named in partition key"))); + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("cannot drop column referenced in partition key expression"))); + } + ReleaseSysCache(tuple); /* @@ -5763,6 +6229,15 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName, Relation attr_rel; ListCell *child; + /* + * In case of a partitioned table, the column must be dropped from the + * partitions as well. + */ + if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && !recurse) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("column must be dropped from child tables too"))); + attr_rel = heap_open(AttributeRelationId, RowExclusiveLock); foreach(child, children) { @@ -6267,6 +6742,12 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel, * Validity checks (permission checks wait till we have the column * numbers) */ + if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot reference partitioned table \"%s\"", + RelationGetRelationName(pkrel)))); + if (pkrel->rd_rel->relkind != RELKIND_RELATION) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), @@ -6740,16 +7221,34 @@ ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd, while (HeapTupleIsValid(tgtuple = systable_getnext(tgscan))) { + Form_pg_trigger tgform = (Form_pg_trigger) GETSTRUCT(tgtuple); Form_pg_trigger copy_tg; + /* + * Remember OIDs of other relation(s) involved in FK constraint. + * (Note: it's likely that we could skip forcing a relcache inval + * for other rels that don't have a trigger whose properties + * change, but let's be conservative.) + */ + if (tgform->tgrelid != RelationGetRelid(rel)) + otherrelids = list_append_unique_oid(otherrelids, + tgform->tgrelid); + + /* + * Update deferrability of RI_FKey_noaction_del, + * RI_FKey_noaction_upd, RI_FKey_check_ins and RI_FKey_check_upd + * triggers, but not others; see createForeignKeyTriggers and + * CreateFKCheckTrigger. + */ + if (tgform->tgfoid != F_RI_FKEY_NOACTION_DEL && + tgform->tgfoid != F_RI_FKEY_NOACTION_UPD && + tgform->tgfoid != F_RI_FKEY_CHECK_INS && + tgform->tgfoid != F_RI_FKEY_CHECK_UPD) + continue; + copyTuple = heap_copytuple(tgtuple); copy_tg = (Form_pg_trigger) GETSTRUCT(copyTuple); - /* Remember OIDs of other relation(s) involved in FK constraint */ - if (copy_tg->tgrelid != RelationGetRelid(rel)) - otherrelids = list_append_unique_oid(otherrelids, - copy_tg->tgrelid); - copy_tg->tgdeferrable = cmdcon->deferrable; copy_tg->tginitdeferred = cmdcon->initdeferred; simple_heap_update(tgrel, ©Tuple->t_self, copyTuple); @@ -6908,7 +7407,8 @@ ATExecValidateConstraint(Relation rel, char *constrName, bool recurse, /* * If we are told not to recurse, there had better not be any - * child tables; else the addition would put them out of step. + * child tables, because we can't mark the constraint on the + * parent valid unless it is valid for all child tables. */ if (!recurse) ereport(ERROR, @@ -7411,7 +7911,7 @@ validateForeignKeyConstraint(char *conname, trig.tgconstraint = constraintOid; trig.tgdeferrable = FALSE; trig.tginitdeferred = FALSE; - /* we needn't fill in tgargs or tgqual */ + /* we needn't fill in remaining fields */ /* * See if we can do it with a single LEFT JOIN query. A FALSE result @@ -7495,6 +7995,7 @@ CreateFKCheckTrigger(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, } fk_trigger->columns = NIL; + fk_trigger->transitionRels = NIL; fk_trigger->whenClause = NULL; fk_trigger->isconstraint = true; fk_trigger->deferrable = fkconstraint->deferrable; @@ -7511,6 +8012,9 @@ CreateFKCheckTrigger(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, /* * Create the triggers that implement an FK constraint. + * + * NB: if you change any trigger properties here, see also + * ATExecAlterConstraint. */ static void createForeignKeyTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, @@ -7535,6 +8039,7 @@ createForeignKeyTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, fk_trigger->timing = TRIGGER_TYPE_AFTER; fk_trigger->events = TRIGGER_TYPE_DELETE; fk_trigger->columns = NIL; + fk_trigger->transitionRels = NIL; fk_trigger->whenClause = NULL; fk_trigger->isconstraint = true; fk_trigger->constrrel = NULL; @@ -7589,6 +8094,7 @@ createForeignKeyTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, fk_trigger->timing = TRIGGER_TYPE_AFTER; fk_trigger->events = TRIGGER_TYPE_UPDATE; fk_trigger->columns = NIL; + fk_trigger->transitionRels = NIL; fk_trigger->whenClause = NULL; fk_trigger->isconstraint = true; fk_trigger->constrrel = NULL; @@ -7697,6 +8203,24 @@ ATExecDropConstraint(Relation rel, const char *constrName, is_no_inherit_constraint = con->connoinherit; + /* + * If it's a foreign-key constraint, we'd better lock the referenced + * table and check that that's not in use, just as we've already done + * for the constrained table (else we might, eg, be dropping a trigger + * that has unfired events). But we can/must skip that in the + * self-referential case. + */ + if (con->contype == CONSTRAINT_FOREIGN && + con->confrelid != RelationGetRelid(rel)) + { + Relation frel; + + /* Must match lock taken by RemoveTriggerById: */ + frel = heap_open(con->confrelid, AccessExclusiveLock); + CheckTableNotInUse(frel, "ALTER TABLE"); + heap_close(frel, NoLock); + } + /* * Perform the actual constraint deletion */ @@ -7733,6 +8257,16 @@ ATExecDropConstraint(Relation rel, const char *constrName, } } + /* + * In case of a partitioned table, the constraint must be dropped from the + * partitions too. There is no such thing as NO INHERIT constraints in + * case of partitioned tables. + */ + if (!recurse && rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("constraint must be dropped from child tables too"))); + /* * Propagate to children as appropriate. Unlike most other ALTER * routines, we have to do this one level of recursion at a time; we can't @@ -7861,6 +8395,7 @@ ATPrepAlterColumnType(List **wqueue, NewColumnValue *newval; ParseState *pstate = make_parsestate(NULL); AclResult aclresult; + bool is_expr; if (rel->rd_rel->reloftype && !recursing) ereport(ERROR, @@ -7891,6 +8426,19 @@ ATPrepAlterColumnType(List **wqueue, errmsg("cannot alter inherited column \"%s\"", colName))); + /* Don't alter columns used in the partition key */ + if (is_partition_attr(rel, attnum, &is_expr)) + { + if (!is_expr) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("cannot alter type of column named in partition key"))); + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("cannot alter type of column referenced in partition key expression"))); + } + /* Look up the target type */ typenameTypeIdAndMod(NULL, typeName, &targettype, &targettypmod); @@ -7906,7 +8454,8 @@ ATPrepAlterColumnType(List **wqueue, list_make1_oid(rel->rd_rel->reltype), false); - if (tab->relkind == RELKIND_RELATION) + if (tab->relkind == RELKIND_RELATION || + tab->relkind == RELKIND_PARTITIONED_TABLE) { /* * Set up an expression to transform the old data value to the new @@ -7990,25 +8539,82 @@ ATPrepAlterColumnType(List **wqueue, ReleaseSysCache(tuple); /* - * The recursion case is handled by ATSimpleRecursion. However, if we are - * told not to recurse, there had better not be any child tables; else the - * alter would put them out of step. + * Recurse manually by queueing a new command for each child, if + * necessary. We cannot apply ATSimpleRecursion here because we need to + * remap attribute numbers in the USING expression, if any. + * + * If we are told not to recurse, there had better not be any child + * tables; else the alter would put them out of step. */ if (recurse) - ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode); - else if (!recursing && - find_inheritance_children(RelationGetRelid(rel), NoLock) != NIL) - ereport(ERROR, - (errcode(ERRCODE_INVALID_TABLE_DEFINITION), - errmsg("type of inherited column \"%s\" must be changed in child tables too", - colName))); + { + Oid relid = RelationGetRelid(rel); + ListCell *child; + List *children; - if (tab->relkind == RELKIND_COMPOSITE_TYPE) - ATTypedTableRecursion(wqueue, rel, cmd, lockmode); -} + children = find_all_inheritors(relid, lockmode, NULL); -/* - * When the data type of a column is changed, a rewrite might not be required + /* + * find_all_inheritors does the recursive search of the inheritance + * hierarchy, so all we have to do is process all of the relids in the + * list that it returns. + */ + foreach(child, children) + { + Oid childrelid = lfirst_oid(child); + Relation childrel; + + if (childrelid == relid) + continue; + + /* find_all_inheritors already got lock */ + childrel = relation_open(childrelid, NoLock); + CheckTableNotInUse(childrel, "ALTER TABLE"); + + /* + * Remap the attribute numbers. If no USING expression was + * specified, there is no need for this step. + */ + if (def->cooked_default) + { + AttrNumber *attmap; + bool found_whole_row; + + /* create a copy to scribble on */ + cmd = copyObject(cmd); + + attmap = convert_tuples_by_name_map(RelationGetDescr(childrel), + RelationGetDescr(rel), + gettext_noop("could not convert row type")); + ((ColumnDef *) cmd->def)->cooked_default = + map_variable_attnos(def->cooked_default, + 1, 0, + attmap, RelationGetDescr(rel)->natts, + &found_whole_row); + if (found_whole_row) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot convert whole-row table reference"), + errdetail("USING expression contains a whole-row table reference."))); + pfree(attmap); + } + ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode); + relation_close(childrel, NoLock); + } + } + else if (!recursing && + find_inheritance_children(RelationGetRelid(rel), NoLock) != NIL) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("type of inherited column \"%s\" must be changed in child tables too", + colName))); + + if (tab->relkind == RELKIND_COMPOSITE_TYPE) + ATTypedTableRecursion(wqueue, rel, cmd, lockmode); +} + +/* + * When the data type of a column is changed, a rewrite might not be required * if the new type is sufficiently identical to the old one, and the USING * clause isn't trying to insert some other value. It's safe to skip the * rewrite if the old type is binary coercible to the new type, or if the @@ -8677,7 +9283,8 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd, querytree_list = NIL; foreach(list_item, raw_parsetree_list) { - Node *stmt = (Node *) lfirst(list_item); + RawStmt *rs = (RawStmt *) lfirst(list_item); + Node *stmt = rs->stmt; if (IsA(stmt, IndexStmt)) querytree_list = lappend(querytree_list, @@ -8936,6 +9543,7 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock case RELKIND_VIEW: case RELKIND_MATVIEW: case RELKIND_FOREIGN_TABLE: + case RELKIND_PARTITIONED_TABLE: /* ok to change owner */ break; case RELKIND_INDEX: @@ -9397,6 +10005,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, case RELKIND_RELATION: case RELKIND_TOASTVALUE: case RELKIND_MATVIEW: + case RELKIND_PARTITIONED_TABLE: (void) heap_reloptions(rel->rd_rel->relkind, newOptions, true); break; case RELKIND_VIEW: @@ -9817,7 +10426,8 @@ AlterTableMoveAll(AlterTableMoveAllStmt *stmt) /* Only move the object type requested */ if ((stmt->objtype == OBJECT_TABLE && - relForm->relkind != RELKIND_RELATION) || + relForm->relkind != RELKIND_RELATION && + relForm->relkind != RELKIND_PARTITIONED_TABLE) || (stmt->objtype == OBJECT_INDEX && relForm->relkind != RELKIND_INDEX) || (stmt->objtype == OBJECT_MATVIEW && @@ -10016,6 +10626,16 @@ ATPrepAddInherit(Relation child_rel) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot change inheritance of typed table"))); + + if (child_rel->rd_rel->relispartition) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot change inheritance of a partition"))); + + if (child_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot change inheritance of partitioned table"))); } /* @@ -10024,12 +10644,7 @@ ATPrepAddInherit(Relation child_rel) static ObjectAddress ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode) { - Relation parent_rel, - catalogRelation; - SysScanDesc scan; - ScanKeyData key; - HeapTuple inheritsTuple; - int32 inhseqno; + Relation parent_rel; List *children; ObjectAddress address; @@ -10067,37 +10682,18 @@ ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode) (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot inherit to temporary relation of another session"))); - /* - * Check for duplicates in the list of parents, and determine the highest - * inhseqno already present; we'll use the next one for the new parent. - * (Note: get RowExclusiveLock because we will write pg_inherits below.) - * - * Note: we do not reject the case where the child already inherits from - * the parent indirectly; CREATE TABLE doesn't reject comparable cases. - */ - catalogRelation = heap_open(InheritsRelationId, RowExclusiveLock); - ScanKeyInit(&key, - Anum_pg_inherits_inhrelid, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(RelationGetRelid(child_rel))); - scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, - true, NULL, 1, &key); - - /* inhseqno sequences start at 1 */ - inhseqno = 0; - while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan))) - { - Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inheritsTuple); + /* Prevent partitioned tables from becoming inheritance parents */ + if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot inherit from partitioned table \"%s\"", + parent->relname))); - if (inh->inhparent == RelationGetRelid(parent_rel)) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_TABLE), - errmsg("relation \"%s\" would be inherited from more than once", - RelationGetRelationName(parent_rel)))); - if (inh->inhseqno > inhseqno) - inhseqno = inh->inhseqno; - } - systable_endscan(scan); + /* Likewise for partitions */ + if (parent_rel->rd_rel->relispartition) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot inherit from a partition"))); /* * Prevent circularity by seeing if proposed parent inherits from child. @@ -10132,6 +10728,70 @@ ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode) RelationGetRelationName(child_rel), RelationGetRelationName(parent_rel)))); + /* OK to create inheritance */ + CreateInheritance(child_rel, parent_rel); + + ObjectAddressSet(address, RelationRelationId, + RelationGetRelid(parent_rel)); + + /* keep our lock on the parent relation until commit */ + heap_close(parent_rel, NoLock); + + return address; +} + +/* + * CreateInheritance + * Catalog manipulation portion of creating inheritance between a child + * table and a parent table. + * + * Common to ATExecAddInherit() and ATExecAttachPartition(). + */ +static void +CreateInheritance(Relation child_rel, Relation parent_rel) +{ + Relation catalogRelation; + SysScanDesc scan; + ScanKeyData key; + HeapTuple inheritsTuple; + int32 inhseqno; + + /* Note: get RowExclusiveLock because we will write pg_inherits below. */ + catalogRelation = heap_open(InheritsRelationId, RowExclusiveLock); + + /* + * Check for duplicates in the list of parents, and determine the highest + * inhseqno already present; we'll use the next one for the new parent. + * Also, if proposed child is a partition, it cannot already be + * inheriting. + * + * Note: we do not reject the case where the child already inherits from + * the parent indirectly; CREATE TABLE doesn't reject comparable cases. + */ + ScanKeyInit(&key, + Anum_pg_inherits_inhrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationGetRelid(child_rel))); + scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, + true, NULL, 1, &key); + + /* inhseqno sequences start at 1 */ + inhseqno = 0; + while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan))) + { + Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inheritsTuple); + + if (inh->inhparent == RelationGetRelid(parent_rel)) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_TABLE), + errmsg("relation \"%s\" would be inherited from more than once", + RelationGetRelationName(parent_rel)))); + + if (inh->inhseqno > inhseqno) + inhseqno = inh->inhseqno; + } + systable_endscan(scan); + /* Match up the columns and bump attinhcount as needed */ MergeAttributesIntoExisting(child_rel, parent_rel); @@ -10146,16 +10806,8 @@ ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode) inhseqno + 1, catalogRelation); - ObjectAddressSet(address, RelationRelationId, - RelationGetRelid(parent_rel)); - /* Now we're done with pg_inherits */ heap_close(catalogRelation, RowExclusiveLock); - - /* keep our lock on the parent relation until commit */ - heap_close(parent_rel, NoLock); - - return address; } /* @@ -10206,7 +10858,7 @@ constraints_equivalent(HeapTuple a, HeapTuple b, TupleDesc tupleDesc) * Check columns in child table match up with columns in parent, and increment * their attinhcount. * - * Called by ATExecAddInherit + * Called by CreateInheritance * * Currently all parent columns must be found in child. Missing columns are an * error. One day we might consider creating new columns like CREATE TABLE @@ -10224,12 +10876,17 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel) int parent_natts; TupleDesc tupleDesc; HeapTuple tuple; + bool child_is_partition = false; attrrel = heap_open(AttributeRelationId, RowExclusiveLock); tupleDesc = RelationGetDescr(parent_rel); parent_natts = tupleDesc->natts; + /* If parent_rel is a partitioned table, child_rel must be a partition */ + if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + child_is_partition = true; + for (parent_attno = 1; parent_attno <= parent_natts; parent_attno++) { Form_pg_attribute attribute = tupleDesc->attrs[parent_attno - 1]; @@ -10277,6 +10934,18 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel) * later on, this change will just roll back.) */ childatt->attinhcount++; + + /* + * In case of partitions, we must enforce that value of attislocal + * is same in all partitions. (Note: there are only inherited + * attributes in partitions) + */ + if (child_is_partition) + { + Assert(childatt->attinhcount == 1); + childatt->attislocal = false; + } + simple_heap_update(attrrel, &tuple->t_self, tuple); CatalogUpdateIndexes(attrrel, tuple); heap_freetuple(tuple); @@ -10290,6 +10959,46 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel) } } + /* + * If the parent has an OID column, so must the child, and we'd better + * update the child's attinhcount and attislocal the same as for normal + * columns. We needn't check data type or not-nullness though. + */ + if (tupleDesc->tdhasoid) + { + /* + * Here we match by column number not name; the match *must* be the + * system column, not some random column named "oid". + */ + tuple = SearchSysCacheCopy2(ATTNUM, + ObjectIdGetDatum(RelationGetRelid(child_rel)), + Int16GetDatum(ObjectIdAttributeNumber)); + if (HeapTupleIsValid(tuple)) + { + Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple); + + /* See comments above; these changes should be the same */ + childatt->attinhcount++; + + if (child_is_partition) + { + Assert(childatt->attinhcount == 1); + childatt->attislocal = false; + } + + simple_heap_update(attrrel, &tuple->t_self, tuple); + CatalogUpdateIndexes(attrrel, tuple); + heap_freetuple(tuple); + } + else + { + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("child table is missing column \"%s\"", + "oid"))); + } + } + heap_close(attrrel, RowExclusiveLock); } @@ -10299,7 +11008,7 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel) * * Constraints that are marked ONLY in the parent are ignored. * - * Called by ATExecAddInherit + * Called by CreateInheritance * * Currently all constraints in parent must be present in the child. One day we * may consider adding new constraints like CREATE TABLE does. @@ -10318,10 +11027,15 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel) SysScanDesc parent_scan; ScanKeyData parent_key; HeapTuple parent_tuple; + bool child_is_partition = false; catalog_relation = heap_open(ConstraintRelationId, RowExclusiveLock); tuple_desc = RelationGetDescr(catalog_relation); + /* If parent_rel is a partitioned table, child_rel must be a partition */ + if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + child_is_partition = true; + /* Outer loop scans through the parent's constraint definitions */ ScanKeyInit(&parent_key, Anum_pg_constraint_conrelid, @@ -10372,7 +11086,7 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel) RelationGetRelationName(child_rel), NameStr(parent_con->conname)))); - /* If the constraint is "no inherit" then cannot merge */ + /* If the child constraint is "no inherit" then cannot merge */ if (child_con->connoinherit) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), @@ -10380,6 +11094,17 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel) NameStr(child_con->conname), RelationGetRelationName(child_rel)))); + /* + * If the child constraint is "not valid" then cannot merge with a + * valid parent constraint + */ + if (parent_con->convalidated && !child_con->convalidated) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("constraint \"%s\" conflicts with NOT VALID constraint on child table \"%s\"", + NameStr(child_con->conname), + RelationGetRelationName(child_rel)))); + /* * OK, bump the child constraint's inheritance count. (If we fail * later on, this change will just roll back.) @@ -10387,6 +11112,18 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel) child_copy = heap_copytuple(child_tuple); child_con = (Form_pg_constraint) GETSTRUCT(child_copy); child_con->coninhcount++; + + /* + * In case of partitions, an inherited constraint must be + * inherited only once since it cannot have multiple parents and + * it is never considered local. + */ + if (child_is_partition) + { + Assert(child_con->coninhcount == 1); + child_con->conislocal = false; + } + simple_heap_update(catalog_relation, &child_copy->t_self, child_copy); CatalogUpdateIndexes(catalog_relation, child_copy); heap_freetuple(child_copy); @@ -10411,6 +11148,46 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel) /* * ALTER TABLE NO INHERIT * + * Return value is the address of the relation that is no longer parent. + */ +static ObjectAddress +ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode) +{ + ObjectAddress address; + Relation parent_rel; + + if (rel->rd_rel->relispartition) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot change inheritance of a partition"))); + + /* + * AccessShareLock on the parent is probably enough, seeing that DROP + * TABLE doesn't lock parent tables at all. We need some lock since we'll + * be inspecting the parent's schema. + */ + parent_rel = heap_openrv(parent, AccessShareLock); + + /* + * We don't bother to check ownership of the parent table --- ownership of + * the child is presumed enough rights. + */ + + /* Off to RemoveInheritance() where most of the work happens */ + RemoveInheritance(rel, parent_rel); + + /* keep our lock on the parent relation until commit */ + heap_close(parent_rel, NoLock); + + ObjectAddressSet(address, RelationRelationId, + RelationGetRelid(parent_rel)); + + return address; +} + +/* + * RemoveInheritance + * * Drop a parent from the child's parents. This just adjusts the attinhcount * and attislocal of the columns and removes the pg_inherit and pg_depend * entries. @@ -10424,13 +11201,11 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel) * coninhcount and conislocal for inherited constraints are adjusted in * exactly the same way. * - * Return value is the address of the relation that is no longer parent. + * Common to ATExecDropInherit() and ATExecDetachPartition(). */ -static ObjectAddress -ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode) +static void +RemoveInheritance(Relation child_rel, Relation parent_rel) { - Relation parent_rel; - Oid parent_oid; Relation catalogRelation; SysScanDesc scan; ScanKeyData key[3]; @@ -10439,19 +11214,11 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode) constraintTuple; List *connames; bool found = false; - ObjectAddress address; - - /* - * AccessShareLock on the parent is probably enough, seeing that DROP - * TABLE doesn't lock parent tables at all. We need some lock since we'll - * be inspecting the parent's schema. - */ - parent_rel = heap_openrv(parent, AccessShareLock); + bool child_is_partition = false; - /* - * We don't bother to check ownership of the parent table --- ownership of - * the child is presumed enough rights. - */ + /* If parent_rel is a partitioned table, child_rel must be a partition */ + if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + child_is_partition = true; /* * Find and destroy the pg_inherits entry linking the two, or error out if @@ -10461,7 +11228,7 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode) ScanKeyInit(&key[0], Anum_pg_inherits_inhrelid, BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(RelationGetRelid(rel))); + ObjectIdGetDatum(RelationGetRelid(child_rel))); scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, true, NULL, 1, key); @@ -10482,11 +11249,20 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode) heap_close(catalogRelation, RowExclusiveLock); if (!found) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_TABLE), + { + if (child_is_partition) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("relation \"%s\" is not a partition of relation \"%s\"", + RelationGetRelationName(child_rel), + RelationGetRelationName(parent_rel)))); + else + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_TABLE), errmsg("relation \"%s\" is not a parent of relation \"%s\"", RelationGetRelationName(parent_rel), - RelationGetRelationName(rel)))); + RelationGetRelationName(child_rel)))); + } /* * Search through child columns looking for ones matching parent rel @@ -10495,7 +11271,7 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode) ScanKeyInit(&key[0], Anum_pg_attribute_attrelid, BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(RelationGetRelid(rel))); + ObjectIdGetDatum(RelationGetRelid(child_rel))); scan = systable_beginscan(catalogRelation, AttributeRelidNumIndexId, true, NULL, 1, key); while (HeapTupleIsValid(attributeTuple = systable_getnext(scan))) @@ -10557,7 +11333,7 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode) ScanKeyInit(&key[0], Anum_pg_constraint_conrelid, BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(RelationGetRelid(rel))); + ObjectIdGetDatum(RelationGetRelid(child_rel))); scan = systable_beginscan(catalogRelation, ConstraintRelidIndexId, true, NULL, 1, key); @@ -10588,7 +11364,7 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode) if (copy_con->coninhcount <= 0) /* shouldn't happen */ elog(ERROR, "relation %u has non-inherited constraint \"%s\"", - RelationGetRelid(rel), NameStr(copy_con->conname)); + RelationGetRelid(child_rel), NameStr(copy_con->conname)); copy_con->coninhcount--; if (copy_con->coninhcount == 0) @@ -10600,12 +11376,10 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode) } } - parent_oid = RelationGetRelid(parent_rel); - systable_endscan(scan); heap_close(catalogRelation, RowExclusiveLock); - drop_parent_dependency(RelationGetRelid(rel), + drop_parent_dependency(RelationGetRelid(child_rel), RelationRelationId, RelationGetRelid(parent_rel)); @@ -10615,15 +11389,8 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode) * auxiliary_id argument. */ InvokeObjectPostAlterHookArg(InheritsRelationId, - RelationGetRelid(rel), 0, + RelationGetRelid(child_rel), 0, RelationGetRelid(parent_rel), false); - - /* keep our lock on the parent relation until commit */ - heap_close(parent_rel, NoLock); - - ObjectAddressSet(address, RelationRelationId, parent_oid); - - return address; } /* @@ -11230,6 +11997,12 @@ ATExecGenericOptions(Relation rel, List *options) simple_heap_update(ftrel, &tuple->t_self, tuple); CatalogUpdateIndexes(ftrel, tuple); + /* + * Invalidate relcache so that all sessions will refresh any cached plans + * that might depend on the old options. + */ + CacheInvalidateRelcache(rel); + InvokeObjectPostAlterHook(ForeignTableRelationId, RelationGetRelid(rel), 0); @@ -11282,6 +12055,18 @@ ATPrepChangePersistence(Relation rel, bool toLogged) break; } + /* + * Check that the table is not part any publication when changing to + * UNLOGGED as UNLOGGED tables can't be published. + */ + if (!toLogged && + list_length(GetRelationPublications(RelationGetRelid(rel))) > 0) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("cannot change table \"%s\" to unlogged because it is part of a publication", + RelationGetRelationName(rel)), + errdetail("Unlogged relations cannot be replicated."))); + /* * Check existing foreign key constraints to preserve the invariant that * permanent tables cannot reference unlogged ones. Self-referencing @@ -11445,7 +12230,8 @@ AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, /* Fix other dependent stuff */ if (rel->rd_rel->relkind == RELKIND_RELATION || - rel->rd_rel->relkind == RELKIND_MATVIEW) + rel->rd_rel->relkind == RELKIND_MATVIEW || + rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) { AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved); AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid, @@ -11894,7 +12680,7 @@ RangeVarCallbackOwnsTable(const RangeVar *relation, if (!relkind) return; if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE && - relkind != RELKIND_MATVIEW) + relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table or materialized view", relation->relname))); @@ -12051,7 +12837,8 @@ RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, relkind != RELKIND_VIEW && relkind != RELKIND_MATVIEW && relkind != RELKIND_SEQUENCE && - relkind != RELKIND_FOREIGN_TABLE) + relkind != RELKIND_FOREIGN_TABLE && + relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table, view, materialized view, sequence, or foreign table", @@ -12059,3 +12846,701 @@ RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, ReleaseSysCache(tuple); } + +/* + * Transform any expressions present in the partition key + */ +static PartitionSpec * +transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy) +{ + PartitionSpec *newspec; + ParseState *pstate; + RangeTblEntry *rte; + ListCell *l; + + newspec = makeNode(PartitionSpec); + + newspec->strategy = partspec->strategy; + newspec->location = partspec->location; + newspec->partParams = NIL; + + /* Parse partitioning strategy name */ + if (!pg_strcasecmp(partspec->strategy, "list")) + *strategy = PARTITION_STRATEGY_LIST; + else if (!pg_strcasecmp(partspec->strategy, "range")) + *strategy = PARTITION_STRATEGY_RANGE; + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unrecognized partitioning strategy \"%s\"", + partspec->strategy))); + + /* + * Create a dummy ParseState and insert the target relation as its sole + * rangetable entry. We need a ParseState for transformExpr. + */ + pstate = make_parsestate(NULL); + rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true); + addRTEtoQuery(pstate, rte, true, true, true); + + /* take care of any partition expressions */ + foreach(l, partspec->partParams) + { + ListCell *lc; + PartitionElem *pelem = (PartitionElem *) lfirst(l); + + /* Check for PARTITION BY ... (foo, foo) */ + foreach(lc, newspec->partParams) + { + PartitionElem *pparam = (PartitionElem *) lfirst(lc); + + if (pelem->name && pparam->name && + !strcmp(pelem->name, pparam->name)) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_COLUMN), + errmsg("column \"%s\" appears more than once in partition key", + pelem->name), + parser_errposition(pstate, pelem->location))); + } + + if (pelem->expr) + { + /* Now do parse transformation of the expression */ + pelem->expr = transformExpr(pstate, pelem->expr, + EXPR_KIND_PARTITION_EXPRESSION); + + /* we have to fix its collations too */ + assign_expr_collations(pstate, pelem->expr); + } + + newspec->partParams = lappend(newspec->partParams, pelem); + } + + return newspec; +} + +/* + * Compute per-partition-column information from a list of PartitionElem's + */ +static void +ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs, + List **partexprs, Oid *partopclass, Oid *partcollation) +{ + int attn; + ListCell *lc; + + attn = 0; + foreach(lc, partParams) + { + PartitionElem *pelem = (PartitionElem *) lfirst(lc); + Oid atttype; + Oid attcollation; + + if (pelem->name != NULL) + { + /* Simple attribute reference */ + HeapTuple atttuple; + Form_pg_attribute attform; + + atttuple = SearchSysCacheAttName(RelationGetRelid(rel), pelem->name); + if (!HeapTupleIsValid(atttuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" named in partition key does not exist", + pelem->name))); + attform = (Form_pg_attribute) GETSTRUCT(atttuple); + + if (attform->attnum <= 0) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("cannot use system column \"%s\" in partition key", + pelem->name))); + + partattrs[attn] = attform->attnum; + atttype = attform->atttypid; + attcollation = attform->attcollation; + ReleaseSysCache(atttuple); + + /* Note that whole-row references can't happen here; see below */ + } + else + { + /* Expression */ + Node *expr = pelem->expr; + + Assert(expr != NULL); + atttype = exprType(expr); + attcollation = exprCollation(expr); + + /* + * Strip any top-level COLLATE clause. This ensures that we treat + * "x COLLATE y" and "(x COLLATE y)" alike. + */ + while (IsA(expr, CollateExpr)) + expr = (Node *) ((CollateExpr *) expr)->arg; + + if (IsA(expr, Var) && + ((Var *) expr)->varattno != InvalidAttrNumber) + { + /* + * User wrote "(column)" or "(column COLLATE something)". + * Treat it like simple attribute anyway. + */ + partattrs[attn] = ((Var *) expr)->varattno; + } + else + { + Bitmapset *expr_attrs = NULL; + + partattrs[attn] = 0; /* marks the column as expression */ + *partexprs = lappend(*partexprs, expr); + + /* + * Note that expression_planner does not change the passed in + * expression destructively and we have already saved the + * expression to be stored into the catalog above. + */ + expr = (Node *) expression_planner((Expr *) expr); + + /* + * Partition expression cannot contain mutable functions, + * because a given row must always map to the same partition + * as long as there is no change in the partition boundary + * structure. + */ + if (contain_mutable_functions(expr)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("functions in partition key expression must be marked IMMUTABLE"))); + + /* + * While it is not exactly *wrong* for an expression to be a + * constant value, it seems better to prevent such input. + */ + if (IsA(expr, Const)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("cannot use constant expression as partition key"))); + + /* + * transformPartitionSpec() should have already rejected + * subqueries, aggregates, window functions, and SRFs, based + * on the EXPR_KIND_ for partition expressions. + */ + + /* Cannot have expressions containing whole-row references */ + pull_varattnos(expr, 1, &expr_attrs); + if (bms_is_member(0 - FirstLowInvalidHeapAttributeNumber, + expr_attrs)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("partition key expressions cannot contain whole-row references"))); + } + } + + /* + * Apply collation override if any + */ + if (pelem->collation) + attcollation = get_collation_oid(pelem->collation, false); + + /* + * Check we have a collation iff it's a collatable type. The only + * expected failures here are (1) COLLATE applied to a noncollatable + * type, or (2) partition expression had an unresolved collation. But + * we might as well code this to be a complete consistency check. + */ + if (type_is_collatable(atttype)) + { + if (!OidIsValid(attcollation)) + ereport(ERROR, + (errcode(ERRCODE_INDETERMINATE_COLLATION), + errmsg("could not determine which collation to use for partition expression"), + errhint("Use the COLLATE clause to set the collation explicitly."))); + } + else + { + if (OidIsValid(attcollation)) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("collations are not supported by type %s", + format_type_be(atttype)))); + } + + partcollation[attn] = attcollation; + + /* + * Identify a btree opclass to use. Currently, we use only btree + * operators, which seems enough for list and range partitioning. + */ + if (!pelem->opclass) + { + partopclass[attn] = GetDefaultOpClass(atttype, BTREE_AM_OID); + + if (!OidIsValid(partopclass[attn])) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("data type %s has no default btree operator class", + format_type_be(atttype)), + errhint("You must specify a btree operator class or define a default btree operator class for the data type."))); + } + else + partopclass[attn] = ResolveOpClass(pelem->opclass, + atttype, + "btree", + BTREE_AM_OID); + + attn++; + } +} + +/* + * ALTER TABLE ATTACH PARTITION FOR VALUES + * + * Return the address of the newly attached partition. + */ +static ObjectAddress +ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd) +{ + PartitionKey key = RelationGetPartitionKey(rel); + Relation attachRel, + catalog; + List *childrels; + TupleConstr *attachRel_constr; + List *partConstraint, + *existConstraint; + SysScanDesc scan; + ScanKeyData skey; + AttrNumber attno; + int natts; + TupleDesc tupleDesc; + bool skip_validate = false; + ObjectAddress address; + + attachRel = heap_openrv(cmd->name, AccessExclusiveLock); + + /* + * Must be owner of both parent and source table -- parent was checked by + * ATSimplePermissions call in ATPrepCmd + */ + ATSimplePermissions(attachRel, ATT_TABLE | ATT_FOREIGN_TABLE); + + /* A partition can only have one parent */ + if (attachRel->rd_rel->relispartition) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is already a partition", + RelationGetRelationName(attachRel)))); + + if (OidIsValid(attachRel->rd_rel->reloftype)) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot attach a typed table as partition"))); + + /* + * Table being attached should not already be part of inheritance; either + * as a child table... + */ + catalog = heap_open(InheritsRelationId, AccessShareLock); + ScanKeyInit(&skey, + Anum_pg_inherits_inhrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationGetRelid(attachRel))); + scan = systable_beginscan(catalog, InheritsRelidSeqnoIndexId, true, + NULL, 1, &skey); + if (HeapTupleIsValid(systable_getnext(scan))) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot attach inheritance child as partition"))); + systable_endscan(scan); + + /* ...or as a parent table (except the case when it is partitioned) */ + ScanKeyInit(&skey, + Anum_pg_inherits_inhparent, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationGetRelid(attachRel))); + scan = systable_beginscan(catalog, InheritsParentIndexId, true, NULL, + 1, &skey); + if (HeapTupleIsValid(systable_getnext(scan)) && + attachRel->rd_rel->relkind == RELKIND_RELATION) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot attach inheritance parent as partition"))); + systable_endscan(scan); + heap_close(catalog, AccessShareLock); + + /* + * Prevent circularity by seeing if rel is a partition of attachRel. (In + * particular, this disallows making a rel a partition of itself.) + */ + childrels = find_all_inheritors(RelationGetRelid(attachRel), + AccessShareLock, NULL); + if (list_member_oid(childrels, RelationGetRelid(rel))) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_TABLE), + errmsg("circular inheritance not allowed"), + errdetail("\"%s\" is already a child of \"%s\".", + RelationGetRelationName(rel), + RelationGetRelationName(attachRel)))); + + /* Temp parent cannot have a partition that is itself not a temp */ + if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP && + attachRel->rd_rel->relpersistence != RELPERSISTENCE_TEMP) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot attach a permanent relation as partition of temporary relation \"%s\"", + RelationGetRelationName(rel)))); + + /* If the parent is temp, it must belong to this session */ + if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP && + !rel->rd_islocaltemp) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot attach as partition of temporary relation of another session"))); + + /* Ditto for the partition */ + if (attachRel->rd_rel->relpersistence == RELPERSISTENCE_TEMP && + !attachRel->rd_islocaltemp) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot attach temporary relation of another session as partition"))); + + /* If parent has OIDs then child must have OIDs */ + if (rel->rd_rel->relhasoids && !attachRel->rd_rel->relhasoids) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot attach table \"%s\" without OIDs as partition of" + " table \"%s\" with OIDs", RelationGetRelationName(attachRel), + RelationGetRelationName(rel)))); + + /* OTOH, if parent doesn't have them, do not allow in attachRel either */ + if (attachRel->rd_rel->relhasoids && !rel->rd_rel->relhasoids) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot attach table \"%s\" with OIDs as partition of table" + " \"%s\" without OIDs", RelationGetRelationName(attachRel), + RelationGetRelationName(rel)))); + + /* Check if there are any columns in attachRel that aren't in the parent */ + tupleDesc = RelationGetDescr(attachRel); + natts = tupleDesc->natts; + for (attno = 1; attno <= natts; attno++) + { + Form_pg_attribute attribute = tupleDesc->attrs[attno - 1]; + char *attributeName = NameStr(attribute->attname); + + /* Ignore dropped */ + if (attribute->attisdropped) + continue; + + /* Try to find the column in parent (matching on column name) */ + if (!SearchSysCacheExists2(ATTNAME, + ObjectIdGetDatum(RelationGetRelid(rel)), + CStringGetDatum(attributeName))) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("table \"%s\" contains column \"%s\" not found in parent \"%s\"", + RelationGetRelationName(attachRel), attributeName, + RelationGetRelationName(rel)), + errdetail("New partition should contain only the columns present in parent."))); + } + + /* OK to create inheritance. Rest of the checks performed there */ + CreateInheritance(attachRel, rel); + + /* + * Check that the new partition's bound is valid and does not overlap any + * of existing partitions of the parent - note that it does not return on + * error. + */ + check_new_partition_bound(RelationGetRelationName(attachRel), rel, + cmd->bound); + + /* Update the pg_class entry. */ + StorePartitionBound(attachRel, rel, cmd->bound); + + /* + * Generate partition constraint from the partition bound specification. + * If the parent itself is a partition, make sure to include its + * constraint as well. + */ + partConstraint = list_concat(get_qual_from_partbound(attachRel, rel, + cmd->bound), + RelationGetPartitionQual(rel)); + partConstraint = (List *) eval_const_expressions(NULL, + (Node *) partConstraint); + partConstraint = (List *) canonicalize_qual((Expr *) partConstraint); + partConstraint = list_make1(make_ands_explicit(partConstraint)); + + /* + * Check if we can do away with having to scan the table being attached to + * validate the partition constraint, by *proving* that the existing + * constraints of the table *imply* the partition predicate. We include + * the table's check constraints and NOT NULL constraints in the list of + * clauses passed to predicate_implied_by(). + * + * There is a case in which we cannot rely on just the result of the + * proof. + */ + attachRel_constr = tupleDesc->constr; + existConstraint = NIL; + if (attachRel_constr != NULL) + { + int num_check = attachRel_constr->num_check; + int i; + Bitmapset *not_null_attrs = NULL; + List *part_constr; + ListCell *lc; + bool partition_accepts_null = true; + int partnatts; + + if (attachRel_constr->has_not_null) + { + int natts = attachRel->rd_att->natts; + + for (i = 1; i <= natts; i++) + { + Form_pg_attribute att = attachRel->rd_att->attrs[i - 1]; + + if (att->attnotnull && !att->attisdropped) + { + NullTest *ntest = makeNode(NullTest); + + ntest->arg = (Expr *) makeVar(1, + i, + att->atttypid, + att->atttypmod, + att->attcollation, + 0); + ntest->nulltesttype = IS_NOT_NULL; + + /* + * argisrow=false is correct even for a composite column, + * because attnotnull does not represent a SQL-spec IS NOT + * NULL test in such a case, just IS DISTINCT FROM NULL. + */ + ntest->argisrow = false; + ntest->location = -1; + existConstraint = lappend(existConstraint, ntest); + not_null_attrs = bms_add_member(not_null_attrs, i); + } + } + } + + for (i = 0; i < num_check; i++) + { + Node *cexpr; + + /* + * If this constraint hasn't been fully validated yet, we must + * ignore it here. + */ + if (!attachRel_constr->check[i].ccvalid) + continue; + + cexpr = stringToNode(attachRel_constr->check[i].ccbin); + + /* + * Run each expression through const-simplification and + * canonicalization. It is necessary, because we will be + * comparing it to similarly-processed qual clauses, and may fail + * to detect valid matches without this. + */ + cexpr = eval_const_expressions(NULL, cexpr); + cexpr = (Node *) canonicalize_qual((Expr *) cexpr); + + existConstraint = list_concat(existConstraint, + make_ands_implicit((Expr *) cexpr)); + } + + existConstraint = list_make1(make_ands_explicit(existConstraint)); + + /* And away we go ... */ + if (predicate_implied_by(partConstraint, existConstraint)) + skip_validate = true; + + /* + * We choose to err on the safer side, i.e., give up on skipping the + * validation scan, if the partition key column doesn't have the NOT + * NULL constraint and the table is to become a list partition that + * does not accept nulls. In this case, the partition predicate + * (partConstraint) does include an 'key IS NOT NULL' expression, + * however, because of the way predicate_implied_by_simple_clause() is + * designed to handle IS NOT NULL predicates in the absence of a IS + * NOT NULL clause, we cannot rely on just the above proof. + * + * That is not an issue in case of a range partition, because if there + * were no NOT NULL constraint defined on the key columns, an error + * would be thrown before we get here anyway. That is not true, + * however, if any of the partition keys is an expression, which is + * handled below. + */ + part_constr = linitial(partConstraint); + part_constr = make_ands_implicit((Expr *) part_constr); + + /* + * part_constr contains an IS NOT NULL expression, if this is a list + * partition that does not accept nulls (in fact, also if this is a + * range partition and some partition key is an expression, but we + * never skip validation in that case anyway; see below) + */ + foreach(lc, part_constr) + { + Node *expr = lfirst(lc); + + if (IsA(expr, NullTest) && + ((NullTest *) expr)->nulltesttype == IS_NOT_NULL) + { + partition_accepts_null = false; + break; + } + } + + partnatts = get_partition_natts(key); + for (i = 0; i < partnatts; i++) + { + AttrNumber partattno; + + partattno = get_partition_col_attnum(key, i); + + /* If partition key is an expression, must not skip validation */ + if (!partition_accepts_null && + (partattno == 0 || + !bms_is_member(partattno, not_null_attrs))) + skip_validate = false; + } + } + + /* It's safe to skip the validation scan after all */ + if (skip_validate) + ereport(INFO, + (errmsg("partition constraint for table \"%s\" is implied by existing constraints", + RelationGetRelationName(attachRel)))); + + /* + * Set up to have the table to be scanned to validate the partition + * constraint (see partConstraint above). If it's a partitioned table, we + * instead schdule its leaf partitions to be scanned instead. + */ + if (!skip_validate) + { + List *all_parts; + ListCell *lc; + + /* Take an exclusive lock on the partitions to be checked */ + if (attachRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + all_parts = find_all_inheritors(RelationGetRelid(attachRel), + AccessExclusiveLock, NULL); + else + all_parts = list_make1_oid(RelationGetRelid(attachRel)); + + foreach(lc, all_parts) + { + AlteredTableInfo *tab; + Oid part_relid = lfirst_oid(lc); + Relation part_rel; + Expr *constr; + List *my_constr; + + /* Lock already taken */ + if (part_relid != RelationGetRelid(attachRel)) + part_rel = heap_open(part_relid, NoLock); + else + part_rel = attachRel; + + /* + * Skip if it's a partitioned table. Only RELKIND_RELATION + * relations (ie, leaf partitions) need to be scanned. + */ + if (part_rel != attachRel && + part_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + { + heap_close(part_rel, NoLock); + continue; + } + + /* Grab a work queue entry */ + tab = ATGetQueueEntry(wqueue, part_rel); + + constr = linitial(partConstraint); + my_constr = make_ands_implicit((Expr *) constr); + tab->partition_constraint = map_partition_varattnos(my_constr, + 1, + part_rel, + rel); + /* keep our lock until commit */ + if (part_rel != attachRel) + heap_close(part_rel, NoLock); + } + } + + ObjectAddressSet(address, RelationRelationId, RelationGetRelid(attachRel)); + + /* keep our lock until commit */ + heap_close(attachRel, NoLock); + + return address; +} + +/* + * ALTER TABLE DETACH PARTITION + * + * Return the address of the relation that is no longer a partition of rel. + */ +static ObjectAddress +ATExecDetachPartition(Relation rel, RangeVar *name) +{ + Relation partRel, + classRel; + HeapTuple tuple, + newtuple; + Datum new_val[Natts_pg_class]; + bool isnull, + new_null[Natts_pg_class], + new_repl[Natts_pg_class]; + ObjectAddress address; + + partRel = heap_openrv(name, AccessShareLock); + + /* All inheritance related checks are performed within the function */ + RemoveInheritance(partRel, rel); + + /* Update pg_class tuple */ + classRel = heap_open(RelationRelationId, RowExclusiveLock); + tuple = SearchSysCacheCopy1(RELOID, + ObjectIdGetDatum(RelationGetRelid(partRel))); + Assert(((Form_pg_class) GETSTRUCT(tuple))->relispartition); + + (void) SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relpartbound, + &isnull); + Assert(!isnull); + + /* Clear relpartbound and reset relispartition */ + memset(new_val, 0, sizeof(new_val)); + memset(new_null, false, sizeof(new_null)); + memset(new_repl, false, sizeof(new_repl)); + new_val[Anum_pg_class_relpartbound - 1] = (Datum) 0; + new_null[Anum_pg_class_relpartbound - 1] = true; + new_repl[Anum_pg_class_relpartbound - 1] = true; + newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel), + new_val, new_null, new_repl); + + ((Form_pg_class) GETSTRUCT(newtuple))->relispartition = false; + simple_heap_update(classRel, &newtuple->t_self, newtuple); + CatalogUpdateIndexes(classRel, newtuple); + heap_freetuple(newtuple); + heap_close(classRel, RowExclusiveLock); + + /* + * Invalidate the parent's relcache so that the partition is no longer + * included in its partition descriptor. + */ + CacheInvalidateRelcache(rel); + + ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel)); + + /* keep our lock until commit */ + heap_close(partRel, NoLock); + + return address; +} diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index 7902d433d5..651e1b303a 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -35,7 +35,7 @@ * and munge the system catalogs of the new database. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -82,6 +82,7 @@ #include "utils/memutils.h" #include "utils/rel.h" #include "utils/tqual.h" +#include "utils/varlena.h" /* GUC variables */ diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 99a659a102..3fc3a21cee 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -3,7 +3,7 @@ * trigger.c * PostgreSQL TRIGGERs support code. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -164,6 +164,8 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString, Oid constrrelid = InvalidOid; ObjectAddress myself, referenced; + char *oldtablename = NULL; + char *newtablename = NULL; if (OidIsValid(relOid)) rel = heap_open(relOid, ShareRowExclusiveLock); @@ -174,7 +176,8 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString, * Triggers must be on tables or views, and there are additional * relation-type-specific restrictions. */ - if (rel->rd_rel->relkind == RELKIND_RELATION) + if (rel->rd_rel->relkind == RELKIND_RELATION || + rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) { /* Tables can't have INSTEAD OF triggers */ if (stmt->timing != TRIGGER_TYPE_BEFORE && @@ -184,6 +187,13 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString, errmsg("\"%s\" is a table", RelationGetRelationName(rel)), errdetail("Tables cannot have INSTEAD OF triggers."))); + /* Disallow ROW triggers on partitioned tables */ + if (stmt->row && rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is a partitioned table", + RelationGetRelationName(rel)), + errdetail("Partitioned tables cannot have ROW triggers."))); } else if (rel->rd_rel->relkind == RELKIND_VIEW) { @@ -309,6 +319,87 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString, errmsg("INSTEAD OF triggers cannot have column lists"))); } + /* + * We don't yet support naming ROW transition variables, but the parser + * recognizes the syntax so we can give a nicer message here. + * + * Per standard, REFERENCING TABLE names are only allowed on AFTER + * triggers. Per standard, REFERENCING ROW names are not allowed with FOR + * EACH STATEMENT. Per standard, each OLD/NEW, ROW/TABLE permutation is + * only allowed once. Per standard, OLD may not be specified when + * creating a trigger only for INSERT, and NEW may not be specified when + * creating a trigger only for DELETE. + * + * Notice that the standard allows an AFTER ... FOR EACH ROW trigger to + * reference both ROW and TABLE transition data. + */ + if (stmt->transitionRels != NIL) + { + List *varList = stmt->transitionRels; + ListCell *lc; + + foreach(lc, varList) + { + TriggerTransition *tt = (TriggerTransition *) lfirst(lc); + + Assert(IsA(tt, TriggerTransition)); + + if (!(tt->isTable)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("ROW variable naming in the REFERENCING clause is not supported"), + errhint("Use OLD TABLE or NEW TABLE for naming transition tables."))); + + /* + * Because of the above test, we omit further ROW-related testing + * below. If we later allow naming OLD and NEW ROW variables, + * adjustments will be needed below. + */ + + if (stmt->timing != TRIGGER_TYPE_AFTER) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("transition table name can only be specified for an AFTER trigger"))); + + if (tt->isNew) + { + if (!(TRIGGER_FOR_INSERT(tgtype) || + TRIGGER_FOR_UPDATE(tgtype))) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("NEW TABLE can only be specified for an INSERT or UPDATE trigger"))); + + if (newtablename != NULL) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("NEW TABLE cannot be specified multiple times"))); + + newtablename = tt->name; + } + else + { + if (!(TRIGGER_FOR_DELETE(tgtype) || + TRIGGER_FOR_UPDATE(tgtype))) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("OLD TABLE can only be specified for a DELETE or UPDATE trigger"))); + + if (oldtablename != NULL) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("OLD TABLE cannot be specified multiple times"))); + + oldtablename = tt->name; + } + } + + if (newtablename != NULL && oldtablename != NULL && + strcmp(newtablename, oldtablename) == 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("OLD TABLE name and NEW TABLE name cannot be the same"))); + } + /* * Parse the WHEN clause, if any */ @@ -431,8 +522,9 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString, if (funcrettype == OPAQUEOID) { ereport(WARNING, - (errmsg("changing return type of function %s from \"opaque\" to \"trigger\"", - NameListToString(stmt->funcname)))); + (errmsg("changing return type of function %s from %s to %s", + NameListToString(stmt->funcname), + "opaque", "trigger"))); SetFunctionReturnType(funcoid, TRIGGEROID); } else @@ -664,6 +756,17 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString, else nulls[Anum_pg_trigger_tgqual - 1] = true; + if (oldtablename) + values[Anum_pg_trigger_tgoldtable - 1] = DirectFunctionCall1(namein, + CStringGetDatum(oldtablename)); + else + nulls[Anum_pg_trigger_tgoldtable - 1] = true; + if (newtablename) + values[Anum_pg_trigger_tgnewtable - 1] = DirectFunctionCall1(namein, + CStringGetDatum(newtablename)); + else + nulls[Anum_pg_trigger_tgnewtable - 1] = true; + tuple = heap_form_tuple(tgrel->rd_att, values, nulls); /* force tuple to have the desired OID */ @@ -682,6 +785,10 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString, pfree(DatumGetPointer(values[Anum_pg_trigger_tgname - 1])); pfree(DatumGetPointer(values[Anum_pg_trigger_tgargs - 1])); pfree(DatumGetPointer(values[Anum_pg_trigger_tgattr - 1])); + if (oldtablename) + pfree(DatumGetPointer(values[Anum_pg_trigger_tgoldtable - 1])); + if (newtablename) + pfree(DatumGetPointer(values[Anum_pg_trigger_tgnewtable - 1])); /* * Update relation's pg_class entry. Crucial side-effect: other backends @@ -972,6 +1079,7 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid) AlterTableStmt *atstmt = makeNode(AlterTableStmt); AlterTableCmd *atcmd = makeNode(AlterTableCmd); Constraint *fkcon = makeNode(Constraint); + PlannedStmt *wrapper = makeNode(PlannedStmt); ereport(NOTICE, (errmsg("converting trigger group into constraint \"%s\" %s", @@ -1061,8 +1169,15 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid) fkcon->skip_validation = false; fkcon->initially_valid = true; + /* finally, wrap it in a dummy PlannedStmt */ + wrapper->commandType = CMD_UTILITY; + wrapper->canSetTag = false; + wrapper->utilityStmt = (Node *) atstmt; + wrapper->stmt_location = -1; + wrapper->stmt_len = -1; + /* ... and execute it */ - ProcessUtility((Node *) atstmt, + ProcessUtility(wrapper, "(generated ALTER TABLE ADD FOREIGN KEY command)", PROCESS_UTILITY_SUBCOMMAND, NULL, None_Receiver, NULL); @@ -1113,7 +1228,8 @@ RemoveTriggerById(Oid trigOid) if (rel->rd_rel->relkind != RELKIND_RELATION && rel->rd_rel->relkind != RELKIND_VIEW && - rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE) + rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE && + rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table, view, or foreign table", @@ -1218,7 +1334,8 @@ RangeVarCallbackForRenameTrigger(const RangeVar *rv, Oid relid, Oid oldrelid, /* only tables and views can have triggers */ if (form->relkind != RELKIND_RELATION && form->relkind != RELKIND_VIEW && - form->relkind != RELKIND_FOREIGN_TABLE) + form->relkind != RELKIND_FOREIGN_TABLE && + form->relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table, view, or foreign table", @@ -1584,6 +1701,23 @@ RelationBuildTriggers(Relation relation) } else build->tgargs = NULL; + + datum = fastgetattr(htup, Anum_pg_trigger_tgoldtable, + tgrel->rd_att, &isnull); + if (!isnull) + build->tgoldtable = + DatumGetCString(DirectFunctionCall1(nameout, datum)); + else + build->tgoldtable = NULL; + + datum = fastgetattr(htup, Anum_pg_trigger_tgnewtable, + tgrel->rd_att, &isnull); + if (!isnull) + build->tgnewtable = + DatumGetCString(DirectFunctionCall1(nameout, datum)); + else + build->tgnewtable = NULL; + datum = fastgetattr(htup, Anum_pg_trigger_tgqual, tgrel->rd_att, &isnull); if (!isnull) @@ -1680,6 +1814,19 @@ SetTriggerFlags(TriggerDesc *trigdesc, Trigger *trigger) trigdesc->trig_truncate_after_statement |= TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT, TRIGGER_TYPE_AFTER, TRIGGER_TYPE_TRUNCATE); + + trigdesc->trig_insert_new_table |= + (TRIGGER_FOR_INSERT(tgtype) && + TRIGGER_USES_TRANSITION_TABLE(trigger->tgnewtable)); + trigdesc->trig_update_old_table |= + (TRIGGER_FOR_UPDATE(tgtype) && + TRIGGER_USES_TRANSITION_TABLE(trigger->tgoldtable)); + trigdesc->trig_update_new_table |= + (TRIGGER_FOR_UPDATE(tgtype) && + TRIGGER_USES_TRANSITION_TABLE(trigger->tgnewtable)); + trigdesc->trig_delete_old_table |= + (TRIGGER_FOR_DELETE(tgtype) && + TRIGGER_USES_TRANSITION_TABLE(trigger->tgoldtable)); } /* @@ -1729,6 +1876,10 @@ CopyTriggerDesc(TriggerDesc *trigdesc) } if (trigger->tgqual) trigger->tgqual = pstrdup(trigger->tgqual); + if (trigger->tgoldtable) + trigger->tgoldtable = pstrdup(trigger->tgoldtable); + if (trigger->tgnewtable) + trigger->tgnewtable = pstrdup(trigger->tgnewtable); trigger++; } @@ -1761,6 +1912,10 @@ FreeTriggerDesc(TriggerDesc *trigdesc) } if (trigger->tgqual) pfree(trigger->tgqual); + if (trigger->tgoldtable) + pfree(trigger->tgoldtable); + if (trigger->tgnewtable) + pfree(trigger->tgnewtable); trigger++; } pfree(trigdesc->triggers); @@ -1839,6 +1994,18 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2) return false; else if (strcmp(trig1->tgqual, trig2->tgqual) != 0) return false; + if (trig1->tgoldtable == NULL && trig2->tgoldtable == NULL) + /* ok */ ; + else if (trig1->tgoldtable == NULL || trig2->tgoldtable == NULL) + return false; + else if (strcmp(trig1->tgoldtable, trig2->tgoldtable) != 0) + return false; + if (trig1->tgnewtable == NULL && trig2->tgnewtable == NULL) + /* ok */ ; + else if (trig1->tgnewtable == NULL || trig2->tgnewtable == NULL) + return false; + else if (strcmp(trig1->tgnewtable, trig2->tgnewtable) != 0) + return false; } } else if (trigdesc2 != NULL) @@ -1870,6 +2037,18 @@ ExecCallTriggerFunc(TriggerData *trigdata, Datum result; MemoryContext oldContext; + /* + * Protect against code paths that may fail to initialize transition table + * info. + */ + Assert(((TRIGGER_FIRED_BY_INSERT(trigdata->tg_event) || + TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event) || + TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)) && + TRIGGER_FIRED_AFTER(trigdata->tg_event) && + !(trigdata->tg_event & AFTER_TRIGGER_DEFERRABLE) && + !(trigdata->tg_event & AFTER_TRIGGER_INITDEFERRED)) || + (trigdata->tg_oldtable == NULL && trigdata->tg_newtable == NULL)); + finfo += tgindx; /* @@ -1960,6 +2139,8 @@ ExecBSInsertTriggers(EState *estate, ResultRelInfo *relinfo) LocTriggerData.tg_relation = relinfo->ri_RelationDesc; LocTriggerData.tg_trigtuple = NULL; LocTriggerData.tg_newtuple = NULL; + LocTriggerData.tg_oldtable = NULL; + LocTriggerData.tg_newtable = NULL; LocTriggerData.tg_trigtuplebuf = InvalidBuffer; LocTriggerData.tg_newtuplebuf = InvalidBuffer; for (i = 0; i < trigdesc->numtriggers; i++) @@ -2017,6 +2198,8 @@ ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo, TRIGGER_EVENT_BEFORE; LocTriggerData.tg_relation = relinfo->ri_RelationDesc; LocTriggerData.tg_newtuple = NULL; + LocTriggerData.tg_oldtable = NULL; + LocTriggerData.tg_newtable = NULL; LocTriggerData.tg_newtuplebuf = InvalidBuffer; for (i = 0; i < trigdesc->numtriggers; i++) { @@ -2070,7 +2253,8 @@ ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo, { TriggerDesc *trigdesc = relinfo->ri_TrigDesc; - if (trigdesc && trigdesc->trig_insert_after_row) + if (trigdesc && + (trigdesc->trig_insert_after_row || trigdesc->trig_insert_new_table)) AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_INSERT, true, NULL, trigtuple, recheckIndexes, NULL); } @@ -2092,6 +2276,8 @@ ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo, TRIGGER_EVENT_INSTEAD; LocTriggerData.tg_relation = relinfo->ri_RelationDesc; LocTriggerData.tg_newtuple = NULL; + LocTriggerData.tg_oldtable = NULL; + LocTriggerData.tg_newtable = NULL; LocTriggerData.tg_newtuplebuf = InvalidBuffer; for (i = 0; i < trigdesc->numtriggers; i++) { @@ -2159,6 +2345,8 @@ ExecBSDeleteTriggers(EState *estate, ResultRelInfo *relinfo) LocTriggerData.tg_relation = relinfo->ri_RelationDesc; LocTriggerData.tg_trigtuple = NULL; LocTriggerData.tg_newtuple = NULL; + LocTriggerData.tg_oldtable = NULL; + LocTriggerData.tg_newtable = NULL; LocTriggerData.tg_trigtuplebuf = InvalidBuffer; LocTriggerData.tg_newtuplebuf = InvalidBuffer; for (i = 0; i < trigdesc->numtriggers; i++) @@ -2230,6 +2418,8 @@ ExecBRDeleteTriggers(EState *estate, EPQState *epqstate, TRIGGER_EVENT_BEFORE; LocTriggerData.tg_relation = relinfo->ri_RelationDesc; LocTriggerData.tg_newtuple = NULL; + LocTriggerData.tg_oldtable = NULL; + LocTriggerData.tg_newtable = NULL; LocTriggerData.tg_newtuplebuf = InvalidBuffer; for (i = 0; i < trigdesc->numtriggers; i++) { @@ -2273,7 +2463,8 @@ ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo, { TriggerDesc *trigdesc = relinfo->ri_TrigDesc; - if (trigdesc && trigdesc->trig_delete_after_row) + if (trigdesc && + (trigdesc->trig_delete_after_row || trigdesc->trig_delete_old_table)) { HeapTuple trigtuple; @@ -2310,6 +2501,8 @@ ExecIRDeleteTriggers(EState *estate, ResultRelInfo *relinfo, TRIGGER_EVENT_INSTEAD; LocTriggerData.tg_relation = relinfo->ri_RelationDesc; LocTriggerData.tg_newtuple = NULL; + LocTriggerData.tg_oldtable = NULL; + LocTriggerData.tg_newtable = NULL; LocTriggerData.tg_newtuplebuf = InvalidBuffer; for (i = 0; i < trigdesc->numtriggers; i++) { @@ -2363,6 +2556,8 @@ ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo) LocTriggerData.tg_relation = relinfo->ri_RelationDesc; LocTriggerData.tg_trigtuple = NULL; LocTriggerData.tg_newtuple = NULL; + LocTriggerData.tg_oldtable = NULL; + LocTriggerData.tg_newtable = NULL; LocTriggerData.tg_trigtuplebuf = InvalidBuffer; LocTriggerData.tg_newtuplebuf = InvalidBuffer; for (i = 0; i < trigdesc->numtriggers; i++) @@ -2464,6 +2659,8 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate, TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE; LocTriggerData.tg_relation = relinfo->ri_RelationDesc; + LocTriggerData.tg_oldtable = NULL; + LocTriggerData.tg_newtable = NULL; updatedCols = GetUpdatedColumns(relinfo, estate); for (i = 0; i < trigdesc->numtriggers; i++) { @@ -2528,7 +2725,8 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo, { TriggerDesc *trigdesc = relinfo->ri_TrigDesc; - if (trigdesc && trigdesc->trig_update_after_row) + if (trigdesc && (trigdesc->trig_update_after_row || + trigdesc->trig_update_old_table || trigdesc->trig_update_new_table)) { HeapTuple trigtuple; @@ -2567,6 +2765,8 @@ ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo, TRIGGER_EVENT_ROW | TRIGGER_EVENT_INSTEAD; LocTriggerData.tg_relation = relinfo->ri_RelationDesc; + LocTriggerData.tg_oldtable = NULL; + LocTriggerData.tg_newtable = NULL; for (i = 0; i < trigdesc->numtriggers; i++) { Trigger *trigger = &trigdesc->triggers[i]; @@ -2635,6 +2835,8 @@ ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo) LocTriggerData.tg_relation = relinfo->ri_RelationDesc; LocTriggerData.tg_trigtuple = NULL; LocTriggerData.tg_newtuple = NULL; + LocTriggerData.tg_oldtable = NULL; + LocTriggerData.tg_newtable = NULL; LocTriggerData.tg_trigtuplebuf = InvalidBuffer; LocTriggerData.tg_newtuplebuf = InvalidBuffer; for (i = 0; i < trigdesc->numtriggers; i++) @@ -3163,8 +3365,11 @@ typedef struct AfterTriggerEventList * fdw_tuplestores[query_depth] is a tuplestore containing the foreign tuples * needed for the current query. * - * maxquerydepth is just the allocated length of query_stack and - * fdw_tuplestores. + * old_tuplestores[query_depth] and new_tuplestores[query_depth] hold the + * transition relations for the current query. + * + * maxquerydepth is just the allocated length of query_stack and the + * tuplestores. * * state_stack is a stack of pointers to saved copies of the SET CONSTRAINTS * state data; each subtransaction level that modifies that state first @@ -3193,7 +3398,9 @@ typedef struct AfterTriggersData AfterTriggerEventList events; /* deferred-event list */ int query_depth; /* current query list index */ AfterTriggerEventList *query_stack; /* events pending from each query */ - Tuplestorestate **fdw_tuplestores; /* foreign tuples from each query */ + Tuplestorestate **fdw_tuplestores; /* foreign tuples for one row from each query */ + Tuplestorestate **old_tuplestores; /* all old tuples from each query */ + Tuplestorestate **new_tuplestores; /* all new tuples from each query */ int maxquerydepth; /* allocated len of above array */ MemoryContext event_cxt; /* memory context for events, if any */ @@ -3222,14 +3429,16 @@ static SetConstraintState SetConstraintStateAddItem(SetConstraintState state, /* - * Gets the current query fdw tuplestore and initializes it if necessary + * Gets a current query transition tuplestore and initializes it if necessary. + * This can be holding a single transition row tuple (in the case of an FDW) + * or a transition table (for an AFTER trigger). */ static Tuplestorestate * -GetCurrentFDWTuplestore(void) +GetTriggerTransitionTuplestore(Tuplestorestate **tss) { Tuplestorestate *ret; - ret = afterTriggers.fdw_tuplestores[afterTriggers.query_depth]; + ret = tss[afterTriggers.query_depth]; if (ret == NULL) { MemoryContext oldcxt; @@ -3256,7 +3465,7 @@ GetCurrentFDWTuplestore(void) CurrentResourceOwner = saveResourceOwner; MemoryContextSwitchTo(oldcxt); - afterTriggers.fdw_tuplestores[afterTriggers.query_depth] = ret; + tss[afterTriggers.query_depth] = ret; } return ret; @@ -3339,9 +3548,7 @@ afterTriggerAddEvent(AfterTriggerEventList *events, afterTriggers.event_cxt = AllocSetContextCreate(TopTransactionContext, "AfterTriggerEvents", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* * Chunk size starts at 1KB and is allowed to increase up to 1MB. @@ -3556,7 +3763,9 @@ AfterTriggerExecute(AfterTriggerEvent event, { case AFTER_TRIGGER_FDW_FETCH: { - Tuplestorestate *fdw_tuplestore = GetCurrentFDWTuplestore(); + Tuplestorestate *fdw_tuplestore = + GetTriggerTransitionTuplestore + (afterTriggers.fdw_tuplestores); if (!tuplestore_gettupleslot(fdw_tuplestore, true, false, trig_tuple_slot1)) @@ -3625,6 +3834,20 @@ AfterTriggerExecute(AfterTriggerEvent event, } } + /* + * Set up the tuplestore information. + */ + if (LocTriggerData.tg_trigger->tgoldtable) + LocTriggerData.tg_oldtable = + GetTriggerTransitionTuplestore(afterTriggers.old_tuplestores); + else + LocTriggerData.tg_oldtable = NULL; + if (LocTriggerData.tg_trigger->tgnewtable) + LocTriggerData.tg_newtable = + GetTriggerTransitionTuplestore(afterTriggers.new_tuplestores); + else + LocTriggerData.tg_newtable = NULL; + /* * Setup the remaining trigger information */ @@ -3780,9 +4003,7 @@ afterTriggerInvokeEvents(AfterTriggerEventList *events, per_tuple_context = AllocSetContextCreate(CurrentMemoryContext, "AfterTriggerTupleContext", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); for_each_chunk(chunk, *events) { @@ -3916,6 +4137,8 @@ AfterTriggerBeginXact(void) Assert(afterTriggers.state == NULL); Assert(afterTriggers.query_stack == NULL); Assert(afterTriggers.fdw_tuplestores == NULL); + Assert(afterTriggers.old_tuplestores == NULL); + Assert(afterTriggers.new_tuplestores == NULL); Assert(afterTriggers.maxquerydepth == 0); Assert(afterTriggers.event_cxt == NULL); Assert(afterTriggers.events.head == NULL); @@ -3960,6 +4183,8 @@ AfterTriggerEndQuery(EState *estate) { AfterTriggerEventList *events; Tuplestorestate *fdw_tuplestore; + Tuplestorestate *old_tuplestore; + Tuplestorestate *new_tuplestore; /* Must be inside a query, too */ Assert(afterTriggers.query_depth >= 0); @@ -4018,6 +4243,18 @@ AfterTriggerEndQuery(EState *estate) tuplestore_end(fdw_tuplestore); afterTriggers.fdw_tuplestores[afterTriggers.query_depth] = NULL; } + old_tuplestore = afterTriggers.old_tuplestores[afterTriggers.query_depth]; + if (old_tuplestore) + { + tuplestore_end(old_tuplestore); + afterTriggers.old_tuplestores[afterTriggers.query_depth] = NULL; + } + new_tuplestore = afterTriggers.new_tuplestores[afterTriggers.query_depth]; + if (new_tuplestore) + { + tuplestore_end(new_tuplestore); + afterTriggers.new_tuplestores[afterTriggers.query_depth] = NULL; + } afterTriggerFreeEventList(&afterTriggers.query_stack[afterTriggers.query_depth]); afterTriggers.query_depth--; @@ -4131,6 +4368,8 @@ AfterTriggerEndXact(bool isCommit) */ afterTriggers.query_stack = NULL; afterTriggers.fdw_tuplestores = NULL; + afterTriggers.old_tuplestores = NULL; + afterTriggers.new_tuplestores = NULL; afterTriggers.maxquerydepth = 0; afterTriggers.state = NULL; @@ -4263,6 +4502,18 @@ AfterTriggerEndSubXact(bool isCommit) tuplestore_end(ts); afterTriggers.fdw_tuplestores[afterTriggers.query_depth] = NULL; } + ts = afterTriggers.old_tuplestores[afterTriggers.query_depth]; + if (ts) + { + tuplestore_end(ts); + afterTriggers.old_tuplestores[afterTriggers.query_depth] = NULL; + } + ts = afterTriggers.new_tuplestores[afterTriggers.query_depth]; + if (ts) + { + tuplestore_end(ts); + afterTriggers.new_tuplestores[afterTriggers.query_depth] = NULL; + } afterTriggerFreeEventList(&afterTriggers.query_stack[afterTriggers.query_depth]); } @@ -4342,6 +4593,12 @@ AfterTriggerEnlargeQueryState(void) afterTriggers.fdw_tuplestores = (Tuplestorestate **) MemoryContextAllocZero(TopTransactionContext, new_alloc * sizeof(Tuplestorestate *)); + afterTriggers.old_tuplestores = (Tuplestorestate **) + MemoryContextAllocZero(TopTransactionContext, + new_alloc * sizeof(Tuplestorestate *)); + afterTriggers.new_tuplestores = (Tuplestorestate **) + MemoryContextAllocZero(TopTransactionContext, + new_alloc * sizeof(Tuplestorestate *)); afterTriggers.maxquerydepth = new_alloc; } else @@ -4357,9 +4614,19 @@ AfterTriggerEnlargeQueryState(void) afterTriggers.fdw_tuplestores = (Tuplestorestate **) repalloc(afterTriggers.fdw_tuplestores, new_alloc * sizeof(Tuplestorestate *)); + afterTriggers.old_tuplestores = (Tuplestorestate **) + repalloc(afterTriggers.old_tuplestores, + new_alloc * sizeof(Tuplestorestate *)); + afterTriggers.new_tuplestores = (Tuplestorestate **) + repalloc(afterTriggers.new_tuplestores, + new_alloc * sizeof(Tuplestorestate *)); /* Clear newly-allocated slots for subsequent lazy initialization. */ memset(afterTriggers.fdw_tuplestores + old_alloc, 0, (new_alloc - old_alloc) * sizeof(Tuplestorestate *)); + memset(afterTriggers.old_tuplestores + old_alloc, + 0, (new_alloc - old_alloc) * sizeof(Tuplestorestate *)); + memset(afterTriggers.new_tuplestores + old_alloc, + 0, (new_alloc - old_alloc) * sizeof(Tuplestorestate *)); afterTriggers.maxquerydepth = new_alloc; } @@ -4804,7 +5071,14 @@ AfterTriggerPendingOnRel(Oid relid) * * NOTE: this is called whenever there are any triggers associated with * the event (even if they are disabled). This function decides which - * triggers actually need to be queued. + * triggers actually need to be queued. It is also called after each row, + * even if there are no triggers for that event, if there are any AFTER + * STATEMENT triggers for the statement which use transition tables, so that + * the transition tuplestores can be built. + * + * Transition tuplestores are built now, rather than when events are pulled + * off of the queue because AFTER ROW triggers are allowed to select from the + * transition tables for the statement. * ---------- */ static void @@ -4835,6 +5109,46 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, if (afterTriggers.query_depth >= afterTriggers.maxquerydepth) AfterTriggerEnlargeQueryState(); + /* + * If the relation has AFTER ... FOR EACH ROW triggers, capture rows into + * transition tuplestores for this depth. + */ + if (row_trigger) + { + if ((event == TRIGGER_EVENT_DELETE && + trigdesc->trig_delete_old_table) || + (event == TRIGGER_EVENT_UPDATE && + trigdesc->trig_update_old_table)) + { + Tuplestorestate *old_tuplestore; + + Assert(oldtup != NULL); + old_tuplestore = + GetTriggerTransitionTuplestore + (afterTriggers.old_tuplestores); + tuplestore_puttuple(old_tuplestore, oldtup); + } + if ((event == TRIGGER_EVENT_INSERT && + trigdesc->trig_insert_new_table) || + (event == TRIGGER_EVENT_UPDATE && + trigdesc->trig_update_new_table)) + { + Tuplestorestate *new_tuplestore; + + Assert(newtup != NULL); + new_tuplestore = + GetTriggerTransitionTuplestore + (afterTriggers.new_tuplestores); + tuplestore_puttuple(new_tuplestore, newtup); + } + + /* If transition tables are the only reason we're here, return. */ + if ((event == TRIGGER_EVENT_DELETE && !trigdesc->trig_delete_after_row) || + (event == TRIGGER_EVENT_INSERT && !trigdesc->trig_insert_after_row) || + (event == TRIGGER_EVENT_UPDATE && !trigdesc->trig_update_after_row)) + return; + } + /* * Validate the event code and collect the associated tuple CTIDs. * @@ -4932,7 +5246,9 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, { if (fdw_tuplestore == NULL) { - fdw_tuplestore = GetCurrentFDWTuplestore(); + fdw_tuplestore = + GetTriggerTransitionTuplestore + (afterTriggers.fdw_tuplestores); new_event.ate_flags = AFTER_TRIGGER_FDW_FETCH; } else diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c index 69c038c52b..479a160815 100644 --- a/src/backend/commands/tsearchcmds.c +++ b/src/backend/commands/tsearchcmds.c @@ -4,7 +4,7 @@ * * Routines for tsearch manipulation commands * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -1215,10 +1215,10 @@ AlterTSConfiguration(AlterTSConfigurationStmt *stmt) /* Update dependencies */ makeConfigurationDependencies(tup, true, relMap); - InvokeObjectPostAlterHook(TSConfigMapRelationId, + InvokeObjectPostAlterHook(TSConfigRelationId, HeapTupleGetOid(tup), 0); - ObjectAddressSet(address, TSConfigMapRelationId, cfgId); + ObjectAddressSet(address, TSConfigRelationId, cfgId); heap_close(relMap, RowExclusiveLock); @@ -1700,7 +1700,7 @@ deserialize_deflist(Datum txt) *wsptr++ = '\0'; result = lappend(result, makeDefElem(pstrdup(workspace), - (Node *) makeString(pstrdup(startvalue)))); + (Node *) makeString(pstrdup(startvalue)), -1)); state = CS_WAITKEY; } } @@ -1732,7 +1732,7 @@ deserialize_deflist(Datum txt) *wsptr++ = '\0'; result = lappend(result, makeDefElem(pstrdup(workspace), - (Node *) makeString(pstrdup(startvalue)))); + (Node *) makeString(pstrdup(startvalue)), -1)); state = CS_WAITKEY; } } @@ -1747,7 +1747,7 @@ deserialize_deflist(Datum txt) *wsptr++ = '\0'; result = lappend(result, makeDefElem(pstrdup(workspace), - (Node *) makeString(pstrdup(startvalue)))); + (Node *) makeString(pstrdup(startvalue)), -1)); state = CS_WAITKEY; } else @@ -1766,7 +1766,7 @@ deserialize_deflist(Datum txt) *wsptr++ = '\0'; result = lappend(result, makeDefElem(pstrdup(workspace), - (Node *) makeString(pstrdup(startvalue)))); + (Node *) makeString(pstrdup(startvalue)), -1)); } else if (state != CS_WAITKEY) ereport(ERROR, diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index ce04211067..4c33d55484 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -3,7 +3,7 @@ * typecmds.c * Routines for SQL commands that manipulate types (and domains). * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -104,6 +104,8 @@ static char *domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, char *domainName, ObjectAddress *constrAddr); +static Node *replace_domain_constraint_value(ParseState *pstate, + ColumnRef *cref); /* @@ -111,7 +113,7 @@ static char *domainAddConstraint(Oid domainOid, Oid domainNamespace, * Registers a new base type. */ ObjectAddress -DefineType(List *names, List *parameters) +DefineType(ParseState *pstate, List *names, List *parameters) { char *typeName; Oid typeNamespace; @@ -286,13 +288,15 @@ DefineType(List *names, List *parameters) ereport(WARNING, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("type attribute \"%s\" not recognized", - defel->defname))); + defel->defname), + parser_errposition(pstate, defel->location))); continue; } if (*defelp != NULL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); *defelp = defel; } @@ -1221,7 +1225,7 @@ DefineEnum(CreateEnumStmt *stmt) * Adds a new label to an existing enum. */ ObjectAddress -AlterEnum(AlterEnumStmt *stmt, bool isTopLevel) +AlterEnum(AlterEnumStmt *stmt) { Oid enum_type_oid; TypeName *typename; @@ -1236,39 +1240,28 @@ AlterEnum(AlterEnumStmt *stmt, bool isTopLevel) if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", enum_type_oid); - /* - * Ordinarily we disallow adding values within transaction blocks, because - * we can't cope with enum OID values getting into indexes and then having - * their defining pg_enum entries go away. However, it's okay if the enum - * type was created in the current transaction, since then there can be no - * such indexes that wouldn't themselves go away on rollback. (We support - * this case because pg_dump --binary-upgrade needs it.) We test this by - * seeing if the pg_type row has xmin == current XID and is not - * HEAP_UPDATED. If it is HEAP_UPDATED, we can't be sure whether the type - * was created or only modified in this xact. So we are disallowing some - * cases that could theoretically be safe; but fortunately pg_dump only - * needs the simplest case. - */ - if (HeapTupleHeaderGetXmin(tup->t_data) == GetCurrentTransactionId() && - !(tup->t_data->t_infomask & HEAP_UPDATED)) - /* safe to do inside transaction block */ ; - else - PreventTransactionChain(isTopLevel, "ALTER TYPE ... ADD"); - /* Check it's an enum and check user has permission to ALTER the enum */ checkEnumOwner(tup); - /* Add the new label */ - AddEnumLabel(enum_type_oid, stmt->newVal, - stmt->newValNeighbor, stmt->newValIsAfter, - stmt->skipIfExists); + ReleaseSysCache(tup); + + if (stmt->oldVal) + { + /* Rename an existing label */ + RenameEnumLabel(enum_type_oid, stmt->oldVal, stmt->newVal); + } + else + { + /* Add a new label */ + AddEnumLabel(enum_type_oid, stmt->newVal, + stmt->newValNeighbor, stmt->newValIsAfter, + stmt->skipIfNewValExists); + } InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0); ObjectAddressSet(address, TypeRelationId, enum_type_oid); - ReleaseSysCache(tup); - return address; } @@ -2116,7 +2109,8 @@ DefineCompositeType(RangeVar *typevar, List *coldeflist) /* * Finally create the relation. This also creates the type. */ - DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address); + DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address, + NULL); return address; } @@ -2741,7 +2735,7 @@ validateDomainConstraint(Oid domainoid, char *ccbin) conResult = ExecEvalExprSwitchContext(exprstate, econtext, - &isNull, NULL); + &isNull); if (!isNull && !DatumGetBool(conResult)) { @@ -3030,7 +3024,8 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, domVal->collation = get_typcollation(baseTypeOid); domVal->location = -1; /* will be set when/if used */ - pstate->p_value_substitute = (Node *) domVal; + pstate->p_pre_columnref_hook = replace_domain_constraint_value; + pstate->p_ref_hook_state = (void *) domVal; expr = transformExpr(pstate, constr->raw_expr, EXPR_KIND_DOMAIN_CHECK); @@ -3107,6 +3102,35 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, return ccbin; } +/* Parser pre_columnref_hook for domain CHECK constraint parsing */ +static Node * +replace_domain_constraint_value(ParseState *pstate, ColumnRef *cref) +{ + /* + * Check for a reference to "value", and if that's what it is, replace + * with a CoerceToDomainValue as prepared for us by domainAddConstraint. + * (We handle VALUE as a name, not a keyword, to avoid breaking a lot of + * applications that have used VALUE as a column name in the past.) + */ + if (list_length(cref->fields) == 1) + { + Node *field1 = (Node *) linitial(cref->fields); + char *colname; + + Assert(IsA(field1, String)); + colname = strVal(field1); + if (strcmp(colname, "value") == 0) + { + CoerceToDomainValue *domVal = copyObject(pstate->p_ref_hook_state); + + /* Propagate location knowledge, if any */ + domVal->location = cref->location; + return (Node *) domVal; + } + } + return NULL; +} + /* * Execute ALTER TYPE RENAME @@ -3512,7 +3536,7 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, /* check for duplicate name (more friendly than unique-index failure) */ if (SearchSysCacheExists2(TYPENAMENSP, - CStringGetDatum(NameStr(typform->typname)), + NameGetDatum(&typform->typname), ObjectIdGetDatum(nspOid))) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index b6ea95061d..f6b5741434 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -3,7 +3,7 @@ * user.c * Commands for manipulating roles (formerly called users). * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/commands/user.c @@ -29,7 +29,7 @@ #include "commands/dbcommands.h" #include "commands/seclabel.h" #include "commands/user.h" -#include "libpq/md5.h" +#include "common/md5.h" #include "miscadmin.h" #include "storage/lmgr.h" #include "utils/acl.h" @@ -44,7 +44,7 @@ Oid binary_upgrade_next_pg_authid_oid = InvalidOid; /* GUC parameter */ -extern bool Password_encryption; +int Password_encryption = PASSWORD_TYPE_MD5; /* Hook to check passwords in CreateRole() and AlterRole() */ check_password_hook_type check_password_hook = NULL; @@ -69,7 +69,7 @@ have_createrole_privilege(void) * CREATE ROLE */ Oid -CreateRole(CreateRoleStmt *stmt) +CreateRole(ParseState *pstate, CreateRoleStmt *stmt) { Relation pg_authid_rel; TupleDesc pg_authid_dsc; @@ -80,7 +80,7 @@ CreateRole(CreateRoleStmt *stmt) ListCell *item; ListCell *option; char *password = NULL; /* user password */ - bool encrypt_password = Password_encryption; /* encrypt password? */ + int password_type = Password_encryption; char encrypted_password[MD5_PASSWD_LEN + 1]; bool issuper = false; /* Make the user a superuser? */ bool inherit = true; /* Auto inherit privileges? */ @@ -136,12 +136,13 @@ CreateRole(CreateRoleStmt *stmt) if (dpassword) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); dpassword = defel; if (strcmp(defel->defname, "encryptedPassword") == 0) - encrypt_password = true; + password_type = PASSWORD_TYPE_MD5; else if (strcmp(defel->defname, "unencryptedPassword") == 0) - encrypt_password = false; + password_type = PASSWORD_TYPE_PLAINTEXT; } else if (strcmp(defel->defname, "sysid") == 0) { @@ -153,7 +154,8 @@ CreateRole(CreateRoleStmt *stmt) if (dissuper) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); dissuper = defel; } else if (strcmp(defel->defname, "inherit") == 0) @@ -161,7 +163,8 @@ CreateRole(CreateRoleStmt *stmt) if (dinherit) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); dinherit = defel; } else if (strcmp(defel->defname, "createrole") == 0) @@ -169,7 +172,8 @@ CreateRole(CreateRoleStmt *stmt) if (dcreaterole) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); dcreaterole = defel; } else if (strcmp(defel->defname, "createdb") == 0) @@ -177,7 +181,8 @@ CreateRole(CreateRoleStmt *stmt) if (dcreatedb) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); dcreatedb = defel; } else if (strcmp(defel->defname, "canlogin") == 0) @@ -185,7 +190,8 @@ CreateRole(CreateRoleStmt *stmt) if (dcanlogin) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); dcanlogin = defel; } else if (strcmp(defel->defname, "isreplication") == 0) @@ -193,7 +199,8 @@ CreateRole(CreateRoleStmt *stmt) if (disreplication) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); disreplication = defel; } else if (strcmp(defel->defname, "connectionlimit") == 0) @@ -201,7 +208,8 @@ CreateRole(CreateRoleStmt *stmt) if (dconnlimit) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); dconnlimit = defel; } else if (strcmp(defel->defname, "addroleto") == 0) @@ -209,7 +217,8 @@ CreateRole(CreateRoleStmt *stmt) if (daddroleto) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); daddroleto = defel; } else if (strcmp(defel->defname, "rolemembers") == 0) @@ -217,7 +226,8 @@ CreateRole(CreateRoleStmt *stmt) if (drolemembers) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); drolemembers = defel; } else if (strcmp(defel->defname, "adminmembers") == 0) @@ -225,7 +235,8 @@ CreateRole(CreateRoleStmt *stmt) if (dadminmembers) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); dadminmembers = defel; } else if (strcmp(defel->defname, "validUntil") == 0) @@ -233,7 +244,8 @@ CreateRole(CreateRoleStmt *stmt) if (dvalidUntil) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); dvalidUntil = defel; } else if (strcmp(defel->defname, "bypassrls") == 0) @@ -241,7 +253,8 @@ CreateRole(CreateRoleStmt *stmt) if (dbypassRLS) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); dbypassRLS = defel; } else @@ -380,7 +393,7 @@ CreateRole(CreateRoleStmt *stmt) if (password) { - if (!encrypt_password || isMD5(password)) + if (password_type == PASSWORD_TYPE_PLAINTEXT || isMD5(password)) new_record[Anum_pg_authid_rolpassword - 1] = CStringGetTextDatum(password); else @@ -436,7 +449,7 @@ CreateRole(CreateRoleStmt *stmt) foreach(item, addroleto) { RoleSpec *oldrole = lfirst(item); - HeapTuple oldroletup = get_rolespec_tuple((Node *) oldrole); + HeapTuple oldroletup = get_rolespec_tuple(oldrole); Oid oldroleid = HeapTupleGetOid(oldroletup); char *oldrolename = NameStr(((Form_pg_authid) GETSTRUCT(oldroletup))->rolname); @@ -492,7 +505,7 @@ AlterRole(AlterRoleStmt *stmt) ListCell *option; char *rolename = NULL; char *password = NULL; /* user password */ - bool encrypt_password = Password_encryption; /* encrypt password? */ + int password_type = Password_encryption; char encrypted_password[MD5_PASSWD_LEN + 1]; int issuper = -1; /* Make the user a superuser? */ int inherit = -1; /* Auto inherit privileges? */ @@ -537,9 +550,9 @@ AlterRole(AlterRoleStmt *stmt) errmsg("conflicting or redundant options"))); dpassword = defel; if (strcmp(defel->defname, "encryptedPassword") == 0) - encrypt_password = true; + password_type = PASSWORD_TYPE_MD5; else if (strcmp(defel->defname, "unencryptedPassword") == 0) - encrypt_password = false; + password_type = PASSWORD_TYPE_PLAINTEXT; } else if (strcmp(defel->defname, "superuser") == 0) { @@ -791,7 +804,7 @@ AlterRole(AlterRoleStmt *stmt) /* password */ if (password) { - if (!encrypt_password || isMD5(password)) + if (password_type == PASSWORD_TYPE_PLAINTEXT || isMD5(password)) new_record[Anum_pg_authid_rolpassword - 1] = CStringGetTextDatum(password); else @@ -1117,6 +1130,41 @@ DropRole(DropRoleStmt *stmt) heap_close(pg_authid_rel, NoLock); } +char * +get_rolename(Oid roleid) +{ + HeapTuple tuple; + char *rolename; + + tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid)); + + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("role with oid\"%d\" does not exist", roleid))); + + rolename = strdup(NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname)); + ReleaseSysCache(tuple); + return rolename; +} + +Oid +get_roleid(const char *rolename) +{ + HeapTuple tuple; + Oid roleid; + + tuple = SearchSysCache1(AUTHNAME, CStringGetDatum(rolename)); + + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("role \"%s\" does not exist", rolename))); + + roleid = HeapTupleGetOid(tuple); + ReleaseSysCache(tuple); + return roleid; +} /* * Rename role */ @@ -1383,9 +1431,11 @@ roleSpecsToIds(List *memberNames) foreach(l, memberNames) { - Node *rolespec = (Node *) lfirst(l); + RoleSpec *rolespec = (RoleSpec *) lfirst(l); Oid roleid; + Assert(IsA(rolespec, RoleSpec)); + roleid = get_rolespec_oid(rolespec, false); result = lappend_oid(result, roleid); } @@ -1480,7 +1530,7 @@ AddRoleMems(const char *rolename, Oid roleid, ereport(ERROR, (errcode(ERRCODE_INVALID_GRANT_OPERATION), (errmsg("role \"%s\" is a member of role \"%s\"", - rolename, get_rolespec_name((Node *) memberRole))))); + rolename, get_rolespec_name(memberRole))))); /* * Check if entry for this role/member already exists; if so, give @@ -1495,7 +1545,7 @@ AddRoleMems(const char *rolename, Oid roleid, { ereport(NOTICE, (errmsg("role \"%s\" is already a member of role \"%s\"", - get_rolespec_name((Node *) memberRole), rolename))); + get_rolespec_name(memberRole), rolename))); ReleaseSysCache(authmem_tuple); continue; } @@ -1606,7 +1656,7 @@ DelRoleMems(const char *rolename, Oid roleid, { ereport(WARNING, (errmsg("role \"%s\" is not a member of role \"%s\"", - get_rolespec_name((Node *) memberRole), rolename))); + get_rolespec_name(memberRole), rolename))); continue; } diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 0563e63474..812fb4a48f 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -9,7 +9,7 @@ * in cluster.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -209,9 +209,7 @@ vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params, */ vac_context = AllocSetContextCreate(PortalContext, "Vacuum", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* * If caller didn't give us a buffer strategy object, make one in the @@ -1154,6 +1152,15 @@ vac_truncate_clog(TransactionId frozenXID, if (bogus) return; + /* + * Advance the oldest value for commit timestamps before truncating, so + * that if a user requests a timestamp for a transaction we're truncating + * away right after this point, they get NULL instead of an ugly "file not + * found" error from slru.c. This doesn't matter for xact/multixact + * because they are not subject to arbitrary lookups from users. + */ + AdvanceOldestCommitTsXid(frozenXID); + /* * Truncate CLOG, multixact and CommitTs to the oldest computed value. */ @@ -1169,7 +1176,6 @@ vac_truncate_clog(TransactionId frozenXID, */ SetTransactionIdLimit(frozenXID, oldestxid_datoid); SetMultiXactIdLimit(minMulti, minmulti_datoid); - AdvanceOldestCommitTsXid(frozenXID); } @@ -1316,7 +1322,8 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params) */ if (onerel->rd_rel->relkind != RELKIND_RELATION && onerel->rd_rel->relkind != RELKIND_MATVIEW && - onerel->rd_rel->relkind != RELKIND_TOASTVALUE) + onerel->rd_rel->relkind != RELKIND_TOASTVALUE && + onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) { ereport(WARNING, (errmsg("skipping \"%s\" --- cannot vacuum non-tables or special system tables", diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c index 231e92d8e4..a2999b3bf7 100644 --- a/src/backend/commands/vacuumlazy.c +++ b/src/backend/commands/vacuumlazy.c @@ -24,7 +24,7 @@ * the TID array, just enough to hold as many heap tuples as fit on one page. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -1747,7 +1747,7 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats) return; } - pg_usleep(VACUUM_TRUNCATE_LOCK_WAIT_INTERVAL); + pg_usleep(VACUUM_TRUNCATE_LOCK_WAIT_INTERVAL * 1000L); } /* diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index defafa54b2..15dbaf3fd2 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -4,7 +4,7 @@ * Routines for handling specialized SET variables. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -30,6 +30,7 @@ #include "utils/syscache.h" #include "utils/snapmgr.h" #include "utils/timestamp.h" +#include "utils/varlena.h" #include "mb/pg_wchar.h" /* diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c index 085bf32320..1f008b0756 100644 --- a/src/backend/commands/view.c +++ b/src/backend/commands/view.c @@ -3,7 +3,7 @@ * view.c * use rewrite rules to construct views * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -59,15 +59,13 @@ validateWithCheckOption(char *value) /*--------------------------------------------------------------------- * DefineVirtualRelation * - * Create the "view" relation. `DefineRelation' does all the work, - * we just provide the correct arguments ... at least when we're - * creating a view. If we're updating an existing view, we have to - * work harder. + * Create a view relation and use the rules system to store the query + * for the view. *--------------------------------------------------------------------- */ static ObjectAddress DefineVirtualRelation(RangeVar *relation, List *tlist, bool replace, - List *options) + List *options, Query *viewParse) { Oid viewOid; LOCKMODE lockmode; @@ -161,19 +159,14 @@ DefineVirtualRelation(RangeVar *relation, List *tlist, bool replace, descriptor = BuildDescForRelation(attrList); checkViewTupleDesc(descriptor, rel->rd_att); - /* - * The new options list replaces the existing options list, even if - * it's empty. - */ - atcmd = makeNode(AlterTableCmd); - atcmd->subtype = AT_ReplaceRelOptions; - atcmd->def = (Node *) options; - atcmds = lappend(atcmds, atcmd); - /* * If new attributes have been added, we must add pg_attribute entries * for them. It is convenient (although overkill) to use the ALTER * TABLE ADD COLUMN infrastructure for this. + * + * Note that we must do this before updating the query for the view, + * since the rules system requires that the correct view columns be in + * place when defining the new rules. */ if (list_length(attrList) > rel->rd_att->natts) { @@ -192,9 +185,38 @@ DefineVirtualRelation(RangeVar *relation, List *tlist, bool replace, atcmd->def = (Node *) lfirst(c); atcmds = lappend(atcmds, atcmd); } + + AlterTableInternal(viewOid, atcmds, true); + + /* Make the new view columns visible */ + CommandCounterIncrement(); } - /* OK, let's do it. */ + /* + * Update the query for the view. + * + * Note that we must do this before updating the view options, because + * the new options may not be compatible with the old view query (for + * example if we attempt to add the WITH CHECK OPTION, we require that + * the new view be automatically updatable, but the old view may not + * have been). + */ + StoreViewQuery(viewOid, viewParse, replace); + + /* Make the new view query visible */ + CommandCounterIncrement(); + + /* + * Finally update the view options. + * + * The new options list replaces the existing options list, even if + * it's empty. + */ + atcmd = makeNode(AlterTableCmd); + atcmd->subtype = AT_ReplaceRelOptions; + atcmd->def = (Node *) options; + atcmds = list_make1(atcmd); + AlterTableInternal(viewOid, atcmds, true); ObjectAddressSet(address, RelationRelationId, viewOid); @@ -211,7 +233,7 @@ DefineVirtualRelation(RangeVar *relation, List *tlist, bool replace, ObjectAddress address; /* - * now set the parameters for keys/inheritance etc. All of these are + * Set the parameters for keys/inheritance etc. All of these are * uninteresting for views... */ createStmt->relation = relation; @@ -224,12 +246,20 @@ DefineVirtualRelation(RangeVar *relation, List *tlist, bool replace, createStmt->if_not_exists = false; /* - * finally create the relation (this will error out if there's an - * existing view, so we don't need more code to complain if "replace" - * is false). + * Create the relation (this will error out if there's an existing + * view, so we don't need more code to complain if "replace" is + * false). */ - address = DefineRelation(createStmt, RELKIND_VIEW, InvalidOid, NULL); + address = DefineRelation(createStmt, RELKIND_VIEW, InvalidOid, NULL, + NULL); Assert(address.objectId != InvalidOid); + + /* Make the new view relation visible */ + CommandCounterIncrement(); + + /* Store the query for the view */ + StoreViewQuery(address.objectId, viewParse, replace); + return address; } } @@ -384,8 +414,10 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse) * Execute a CREATE VIEW command. */ ObjectAddress -DefineView(ViewStmt *stmt, const char *queryString) +DefineView(ViewStmt *stmt, const char *queryString, + int stmt_location, int stmt_len) { + RawStmt *rawstmt; Query *viewParse; RangeVar *view; ListCell *cell; @@ -399,8 +431,12 @@ DefineView(ViewStmt *stmt, const char *queryString) * Since parse analysis scribbles on its input, copy the raw parse tree; * this ensures we don't corrupt a prepared statement, for example. */ - viewParse = parse_analyze((Node *) copyObject(stmt->query), - queryString, NULL, 0); + rawstmt = makeNode(RawStmt); + rawstmt->stmt = (Node *) copyObject(stmt->query); + rawstmt->stmt_location = stmt_location; + rawstmt->stmt_len = stmt_len; + + viewParse = parse_analyze(rawstmt, queryString, NULL, 0); /* * The grammar should ensure that the result is a single SELECT Query. @@ -413,8 +449,7 @@ DefineView(ViewStmt *stmt, const char *queryString) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("views must not contain SELECT INTO"))); - if (viewParse->commandType != CMD_SELECT || - viewParse->utilityStmt != NULL) + if (viewParse->commandType != CMD_SELECT) elog(ERROR, "unexpected parse analysis result"); /* @@ -434,11 +469,11 @@ DefineView(ViewStmt *stmt, const char *queryString) if (stmt->withCheckOption == LOCAL_CHECK_OPTION) stmt->options = lappend(stmt->options, makeDefElem("check_option", - (Node *) makeString("local"))); + (Node *) makeString("local"), -1)); else if (stmt->withCheckOption == CASCADED_CHECK_OPTION) stmt->options = lappend(stmt->options, makeDefElem("check_option", - (Node *) makeString("cascaded"))); + (Node *) makeString("cascaded"), -1)); /* * Check that the view is auto-updatable if WITH CHECK OPTION was @@ -529,16 +564,7 @@ DefineView(ViewStmt *stmt, const char *queryString) * aborted. */ address = DefineVirtualRelation(view, viewParse->targetList, - stmt->replace, stmt->options); - - /* - * The relation we have just created is not visible to any other commands - * running with the same transaction & command id. So, increment the - * command id counter (but do NOT pfree any memory!!!!) - */ - CommandCounterIncrement(); - - StoreViewQuery(address.objectId, viewParse, stmt->replace); + stmt->replace, stmt->options, viewParse); return address; } diff --git a/src/backend/executor/Makefile b/src/backend/executor/Makefile index 51edd4c5e7..2a2b7eb9bd 100644 --- a/src/backend/executor/Makefile +++ b/src/backend/executor/Makefile @@ -14,14 +14,15 @@ include $(top_builddir)/src/Makefile.global OBJS = execAmi.o execCurrent.o execGrouping.o execIndexing.o execJunk.o \ execMain.o execParallel.o execProcnode.o execQual.o \ - execScan.o execTuples.o \ + execReplication.o execScan.o execTuples.o \ execUtils.o functions.o instrument.o nodeAppend.o nodeAgg.o \ nodeBitmapAnd.o nodeBitmapOr.o \ - nodeBitmapHeapscan.o nodeBitmapIndexscan.o nodeCustom.o nodeGather.o \ + nodeBitmapHeapscan.o nodeBitmapIndexscan.o \ + nodeCustom.o nodeFunctionscan.o nodeGather.o \ nodeHash.o nodeHashjoin.o nodeIndexscan.o nodeIndexonlyscan.o \ nodeLimit.o nodeLockRows.o \ nodeMaterial.o nodeMergeAppend.o nodeMergejoin.o nodeModifyTable.o \ - nodeNestloop.o nodeFunctionscan.o nodeRecursiveunion.o nodeResult.o \ + nodeNestloop.o nodeProjectSet.o nodeRecursiveunion.o nodeResult.o \ nodeSamplescan.o nodeSeqscan.o nodeSetOp.o nodeSort.o nodeUnique.o \ nodeValuesscan.o nodeCtescan.o nodeWorktablescan.o \ nodeGroup.o nodeSubplan.o nodeSubqueryscan.o nodeTidscan.o \ diff --git a/src/backend/executor/README b/src/backend/executor/README index 8afa1e3e4a..f1d1e4c76c 100644 --- a/src/backend/executor/README +++ b/src/backend/executor/README @@ -195,8 +195,7 @@ the entire row value in the join output row. We disallow set-returning functions in the targetlist of SELECT FOR UPDATE, so as to ensure that at most one tuple can be returned for any particular set of scan tuples. Otherwise we'd get duplicates due to the original -query returning the same set of scan tuples multiple times. (Note: there -is no explicit prohibition on SRFs in UPDATE, but the net effect will be -that only the first result row of an SRF counts, because all subsequent -rows will result in attempts to re-update an already updated target row. -This is historical behavior and seems not worth changing.) +query returning the same set of scan tuples multiple times. Likewise, +SRFs are disallowed in an UPDATE's targetlist. There, they would have the +effect of the same row being updated multiple times, which is not very +useful --- and updates after the first would have no effect anyway. diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c index 2587ef7046..1ca4bcb117 100644 --- a/src/backend/executor/execAmi.c +++ b/src/backend/executor/execAmi.c @@ -3,7 +3,7 @@ * execAmi.c * miscellaneous executor access method routines * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/executor/execAmi.c @@ -39,6 +39,7 @@ #include "executor/nodeMergejoin.h" #include "executor/nodeModifyTable.h" #include "executor/nodeNestloop.h" +#include "executor/nodeProjectSet.h" #include "executor/nodeRecursiveunion.h" #include "executor/nodeResult.h" #include "executor/nodeSamplescan.h" @@ -58,7 +59,6 @@ #include "utils/syscache.h" -static bool TargetListSupportsBackwardScan(List *targetlist); static bool IndexSupportsBackwardScan(Oid indexid); @@ -119,7 +119,7 @@ ExecReScan(PlanState *node) UpdateChangedParamSet(node->righttree, node->chgParam); } - /* Shut down any SRFs in the plan node's targetlist */ + /* Call expression callbacks */ if (node->ps_ExprContext) ReScanExprContext(node->ps_ExprContext); @@ -130,6 +130,10 @@ ExecReScan(PlanState *node) ExecReScanResult((ResultState *) node); break; + case T_ProjectSetState: + ExecReScanProjectSet((ProjectSetState *) node); + break; + case T_ModifyTableState: ExecReScanModifyTable((ModifyTableState *) node); break; @@ -455,8 +459,7 @@ ExecSupportsBackwardScan(Plan *node) { case T_Result: if (outerPlan(node) != NULL) - return ExecSupportsBackwardScan(outerPlan(node)) && - TargetListSupportsBackwardScan(node->targetlist); + return ExecSupportsBackwardScan(outerPlan(node)); else return false; @@ -473,13 +476,6 @@ ExecSupportsBackwardScan(Plan *node) return true; } - case T_SeqScan: - case T_TidScan: - case T_FunctionScan: - case T_ValuesScan: - case T_CteScan: - return TargetListSupportsBackwardScan(node->targetlist); - case T_SampleScan: /* Simplify life for tablesample methods by disallowing this */ return false; @@ -488,35 +484,34 @@ ExecSupportsBackwardScan(Plan *node) return false; case T_IndexScan: - return IndexSupportsBackwardScan(((IndexScan *) node)->indexid) && - TargetListSupportsBackwardScan(node->targetlist); + return IndexSupportsBackwardScan(((IndexScan *) node)->indexid); case T_IndexOnlyScan: - return IndexSupportsBackwardScan(((IndexOnlyScan *) node)->indexid) && - TargetListSupportsBackwardScan(node->targetlist); + return IndexSupportsBackwardScan(((IndexOnlyScan *) node)->indexid); case T_SubqueryScan: - return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan) && - TargetListSupportsBackwardScan(node->targetlist); + return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan); case T_CustomScan: { uint32 flags = ((CustomScan *) node)->flags; - if ((flags & CUSTOMPATH_SUPPORT_BACKWARD_SCAN) && - TargetListSupportsBackwardScan(node->targetlist)) + if (flags & CUSTOMPATH_SUPPORT_BACKWARD_SCAN) return true; } return false; + case T_SeqScan: + case T_TidScan: + case T_FunctionScan: + case T_ValuesScan: + case T_CteScan: case T_Material: case T_Sort: - /* these don't evaluate tlist */ return true; case T_LockRows: case T_Limit: - /* these don't evaluate tlist */ return ExecSupportsBackwardScan(outerPlan(node)); default: @@ -524,18 +519,6 @@ ExecSupportsBackwardScan(Plan *node) } } -/* - * If the tlist contains set-returning functions, we can't support backward - * scan, because the TupFromTlist code is direction-ignorant. - */ -static bool -TargetListSupportsBackwardScan(List *targetlist) -{ - if (expression_returns_set((Node *) targetlist)) - return false; - return true; -} - /* * An IndexScan or IndexOnlyScan node supports backward scan only if the * index's AM does. diff --git a/src/backend/executor/execCurrent.c b/src/backend/executor/execCurrent.c index 2e4e485a06..3af4a90b51 100644 --- a/src/backend/executor/execCurrent.c +++ b/src/backend/executor/execCurrent.c @@ -3,7 +3,7 @@ * execCurrent.c * executor support for WHERE CURRENT OF cursor * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/executor/execCurrent.c diff --git a/src/backend/executor/execGrouping.c b/src/backend/executor/execGrouping.c index 808275a094..47c9656e1b 100644 --- a/src/backend/executor/execGrouping.c +++ b/src/backend/executor/execGrouping.c @@ -7,7 +7,7 @@ * collation-sensitive, so the code in this file has no support for passing * collation settings through from callers. That may have to change someday. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -18,17 +18,32 @@ */ #include "postgres.h" +#include "access/hash.h" +#include "access/parallel.h" #include "executor/executor.h" #include "miscadmin.h" #include "utils/lsyscache.h" #include "utils/memutils.h" +static uint32 TupleHashTableHash(struct tuplehash_hash *tb, const MinimalTuple tuple); +static int TupleHashTableMatch(struct tuplehash_hash *tb, const MinimalTuple tuple1, const MinimalTuple tuple2); -static TupleHashTable CurTupleHashTable = NULL; - -static uint32 TupleHashTableHash(const void *key, Size keysize); -static int TupleHashTableMatch(const void *key1, const void *key2, - Size keysize); +/* + * Define parameters for tuple hash table code generation. The interface is + * *also* declared in execnodes.h (to generate the types, which are externally + * visible). + */ +#define SH_PREFIX tuplehash +#define SH_ELEMENT_TYPE TupleHashEntryData +#define SH_KEY_TYPE MinimalTuple +#define SH_KEY firstTuple +#define SH_HASH_KEY(tb, key) TupleHashTableHash(tb, key) +#define SH_EQUAL(tb, a, b) TupleHashTableMatch(tb, a, b) == 0 +#define SH_SCOPE extern +#define SH_STORE_HASH +#define SH_GET_HASH(tb, a) a->hash +#define SH_DEFINE +#include "lib/simplehash.h" /***************************************************************************** @@ -260,7 +275,7 @@ execTuplesHashPrepare(int numCols, * eqfunctions: equality comparison functions to use * hashfunctions: datatype-specific hashing functions to use * nbuckets: initial estimate of hashtable size - * entrysize: size of each entry (at least sizeof(TupleHashEntryData)) + * additionalsize: size of data stored in ->additional * tablecxt: memory context in which to store table and table entries * tempcxt: short-lived context for evaluation hash and comparison functions * @@ -275,20 +290,20 @@ TupleHashTable BuildTupleHashTable(int numCols, AttrNumber *keyColIdx, FmgrInfo *eqfunctions, FmgrInfo *hashfunctions, - long nbuckets, Size entrysize, - MemoryContext tablecxt, MemoryContext tempcxt) + long nbuckets, Size additionalsize, + MemoryContext tablecxt, MemoryContext tempcxt, + bool use_variable_hash_iv) { TupleHashTable hashtable; - HASHCTL hash_ctl; + Size entrysize = sizeof(TupleHashEntryData) + additionalsize; Assert(nbuckets > 0); - Assert(entrysize >= sizeof(TupleHashEntryData)); /* Limit initial table size request to not more than work_mem */ nbuckets = Min(nbuckets, (long) ((work_mem * 1024L) / entrysize)); - hashtable = (TupleHashTable) MemoryContextAlloc(tablecxt, - sizeof(TupleHashTableData)); + hashtable = (TupleHashTable) + MemoryContextAlloc(tablecxt, sizeof(TupleHashTableData)); hashtable->numCols = numCols; hashtable->keyColIdx = keyColIdx; @@ -302,15 +317,21 @@ BuildTupleHashTable(int numCols, AttrNumber *keyColIdx, hashtable->in_hash_funcs = NULL; hashtable->cur_eq_funcs = NULL; - MemSet(&hash_ctl, 0, sizeof(hash_ctl)); - hash_ctl.keysize = sizeof(TupleHashEntryData); - hash_ctl.entrysize = entrysize; - hash_ctl.hash = TupleHashTableHash; - hash_ctl.match = TupleHashTableMatch; - hash_ctl.hcxt = tablecxt; - hashtable->hashtab = hash_create("TupleHashTable", nbuckets, - &hash_ctl, - HASH_ELEM | HASH_FUNCTION | HASH_COMPARE | HASH_CONTEXT); + /* + * If parallelism is in use, even if the master backend is performing the + * scan itself, we don't want to create the hashtable exactly the same way + * in all workers. As hashtables are iterated over in keyspace-order, + * doing so in all processes in the same way is likely to lead to + * "unbalanced" hashtables when the table size initially is + * underestimated. + */ + if (use_variable_hash_iv) + hashtable->hash_iv = hash_uint32(ParallelWorkerNumber); + else + hashtable->hash_iv = 0; + + hashtable->hashtab = tuplehash_create(tablecxt, nbuckets); + hashtable->hashtab->private_data = hashtable; return hashtable; } @@ -324,18 +345,17 @@ BuildTupleHashTable(int numCols, AttrNumber *keyColIdx, * * If isnew isn't NULL, then a new entry is created if no existing entry * matches. On return, *isnew is true if the entry is newly created, - * false if it existed already. Any extra space in a new entry has been - * zeroed. + * false if it existed already. ->additional_data in the new entry has + * been zeroed. */ TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew) { - TupleHashEntry entry; + TupleHashEntryData *entry; MemoryContext oldContext; - TupleHashTable saveCurHT; - TupleHashEntryData dummy; bool found; + MinimalTuple key; /* If first time through, clone the input slot to make table slot */ if (hashtable->tableslot == NULL) @@ -356,28 +376,17 @@ LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, /* Need to run the hash functions in short-lived context */ oldContext = MemoryContextSwitchTo(hashtable->tempcxt); - /* - * Set up data needed by hash and match functions - * - * We save and restore CurTupleHashTable just in case someone manages to - * invoke this code re-entrantly. - */ + /* set up data needed by hash and match functions */ hashtable->inputslot = slot; hashtable->in_hash_funcs = hashtable->tab_hash_funcs; hashtable->cur_eq_funcs = hashtable->tab_eq_funcs; - saveCurHT = CurTupleHashTable; - CurTupleHashTable = hashtable; - - /* Search the hash table */ - dummy.firstTuple = NULL; /* flag to reference inputslot */ - entry = (TupleHashEntry) hash_search(hashtable->hashtab, - &dummy, - isnew ? HASH_ENTER : HASH_FIND, - &found); + key = NULL; /* flag to reference inputslot */ if (isnew) { + entry = tuplehash_insert(hashtable->hashtab, key, &found); + if (found) { /* found pre-existing entry */ @@ -385,24 +394,19 @@ LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, } else { - /* - * created new entry - * - * Zero any caller-requested space in the entry. (This zaps the - * "key data" dynahash.c copied into the new entry, but we don't - * care since we're about to overwrite it anyway.) - */ - MemSet(entry, 0, hashtable->entrysize); - - /* Copy the first tuple into the table context */ + /* created new entry */ + *isnew = true; + /* zero caller data */ + entry->additional = NULL; MemoryContextSwitchTo(hashtable->tablecxt); + /* Copy the first tuple into the table context */ entry->firstTuple = ExecCopySlotMinimalTuple(slot); - - *isnew = true; } } - - CurTupleHashTable = saveCurHT; + else + { + entry = tuplehash_lookup(hashtable->hashtab, key); + } MemoryContextSwitchTo(oldContext); @@ -425,34 +429,19 @@ FindTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, { TupleHashEntry entry; MemoryContext oldContext; - TupleHashTable saveCurHT; - TupleHashEntryData dummy; + MinimalTuple key; /* Need to run the hash functions in short-lived context */ oldContext = MemoryContextSwitchTo(hashtable->tempcxt); - /* - * Set up data needed by hash and match functions - * - * We save and restore CurTupleHashTable just in case someone manages to - * invoke this code re-entrantly. - */ + /* Set up data needed by hash and match functions */ hashtable->inputslot = slot; hashtable->in_hash_funcs = hashfunctions; hashtable->cur_eq_funcs = eqfunctions; - saveCurHT = CurTupleHashTable; - CurTupleHashTable = hashtable; - /* Search the hash table */ - dummy.firstTuple = NULL; /* flag to reference inputslot */ - entry = (TupleHashEntry) hash_search(hashtable->hashtab, - &dummy, - HASH_FIND, - NULL); - - CurTupleHashTable = saveCurHT; - + key = NULL; /* flag to reference inputslot */ + entry = tuplehash_lookup(hashtable->hashtab, key); MemoryContextSwitchTo(oldContext); return entry; @@ -468,22 +457,18 @@ FindTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, * This convention avoids the need to materialize virtual input tuples unless * they actually need to get copied into the table. * - * CurTupleHashTable must be set before calling this, since dynahash.c - * doesn't provide any API that would let us get at the hashtable otherwise. - * * Also, the caller must select an appropriate memory context for running * the hash functions. (dynahash.c doesn't change CurrentMemoryContext.) */ static uint32 -TupleHashTableHash(const void *key, Size keysize) +TupleHashTableHash(struct tuplehash_hash *tb, const MinimalTuple tuple) { - MinimalTuple tuple = ((const TupleHashEntryData *) key)->firstTuple; - TupleTableSlot *slot; - TupleHashTable hashtable = CurTupleHashTable; + TupleHashTable hashtable = (TupleHashTable) tb->private_data; int numCols = hashtable->numCols; AttrNumber *keyColIdx = hashtable->keyColIdx; + uint32 hashkey = hashtable->hash_iv; + TupleTableSlot *slot; FmgrInfo *hashfunctions; - uint32 hashkey = 0; int i; if (tuple == NULL) @@ -494,8 +479,12 @@ TupleHashTableHash(const void *key, Size keysize) } else { - /* Process a tuple already stored in the table */ - /* (this case never actually occurs in current dynahash.c code) */ + /* + * Process a tuple already stored in the table. + * + * (this case never actually occurs due to the way simplehash.h is + * used, as the hash-value is stored in the entries) + */ slot = hashtable->tableslot; ExecStoreMinimalTuple(tuple, slot, false); hashfunctions = hashtable->tab_hash_funcs; @@ -530,29 +519,21 @@ TupleHashTableHash(const void *key, Size keysize) * * As above, the passed pointers are pointers to TupleHashEntryData. * - * CurTupleHashTable must be set before calling this, since dynahash.c - * doesn't provide any API that would let us get at the hashtable otherwise. - * * Also, the caller must select an appropriate memory context for running * the compare functions. (dynahash.c doesn't change CurrentMemoryContext.) */ static int -TupleHashTableMatch(const void *key1, const void *key2, Size keysize) +TupleHashTableMatch(struct tuplehash_hash *tb, const MinimalTuple tuple1, const MinimalTuple tuple2) { - MinimalTuple tuple1 = ((const TupleHashEntryData *) key1)->firstTuple; - -#ifdef USE_ASSERT_CHECKING - MinimalTuple tuple2 = ((const TupleHashEntryData *) key2)->firstTuple; -#endif TupleTableSlot *slot1; TupleTableSlot *slot2; - TupleHashTable hashtable = CurTupleHashTable; + TupleHashTable hashtable = (TupleHashTable) tb->private_data; /* - * We assume that dynahash.c will only ever call us with the first + * We assume that simplehash.h will only ever call us with the first * argument being an actual table entry, and the second argument being * LookupTupleHashEntry's dummy TupleHashEntryData. The other direction - * could be supported too, but is not currently used by dynahash.c. + * could be supported too, but is not currently required. */ Assert(tuple1 != NULL); slot1 = hashtable->tableslot; diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c index 0e2d834ed1..8d119f6a19 100644 --- a/src/backend/executor/execIndexing.c +++ b/src/backend/executor/execIndexing.c @@ -2,7 +2,7 @@ * * execIndexing.c * routines for inserting index tuples and enforcing unique and - * exclusive constraints. + * exclusion constraints. * * ExecInsertIndexTuples() is the main entry point. It's called after * inserting a tuple to the heap, and it inserts corresponding index tuples @@ -95,7 +95,7 @@ * with the higher XID backs out. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/execJunk.c b/src/backend/executor/execJunk.c index 74a10048a2..a422327c88 100644 --- a/src/backend/executor/execJunk.c +++ b/src/backend/executor/execJunk.c @@ -3,7 +3,7 @@ * execJunk.c * Junk attribute support stuff.... * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 32bb3f9205..0bc146ca47 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -26,7 +26,7 @@ * before ExecutorEnd. This can be omitted only in case of EXPLAIN, * which should also omit ExecutorRun. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -42,6 +42,8 @@ #include "access/transam.h" #include "access/xact.h" #include "catalog/namespace.h" +#include "catalog/partition.h" +#include "catalog/pg_publication.h" #include "commands/matview.h" #include "commands/trigger.h" #include "executor/execdebug.h" @@ -50,6 +52,7 @@ #include "miscadmin.h" #include "optimizer/clauses.h" #include "parser/parsetree.h" +#include "rewrite/rewriteManip.h" #include "storage/bufmgr.h" #include "storage/lmgr.h" #include "tcop/utility.h" @@ -822,9 +825,11 @@ InitPlan(QueryDesc *queryDesc, int eflags) resultRelationOid = getrelid(resultRelationIndex, rangeTable); resultRelation = heap_open(resultRelationOid, RowExclusiveLock); + InitResultRelInfo(resultRelInfo, resultRelation, resultRelationIndex, + NULL, estate->es_instrument); resultRelInfo++; } @@ -1019,7 +1024,8 @@ CheckValidResultRel(Relation resultRel, CmdType operation) switch (resultRel->rd_rel->relkind) { case RELKIND_RELATION: - /* OK */ + case RELKIND_PARTITIONED_TABLE: + CheckCmdReplicaIdentity(resultRel, operation); break; case RELKIND_SEQUENCE: ereport(ERROR, @@ -1152,6 +1158,7 @@ CheckValidRowMarkRel(Relation rel, RowMarkType markType) switch (rel->rd_rel->relkind) { case RELKIND_RELATION: + case RELKIND_PARTITIONED_TABLE: /* OK */ break; case RELKIND_SEQUENCE: @@ -1212,8 +1219,11 @@ void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, + Relation partition_root, int instrument_options) { + List *partition_check = NIL; + MemSet(resultRelInfo, 0, sizeof(ResultRelInfo)); resultRelInfo->type = T_ResultRelInfo; resultRelInfo->ri_RangeTableIndex = resultRelationIndex; @@ -1249,6 +1259,39 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo, resultRelInfo->ri_ConstraintExprs = NULL; resultRelInfo->ri_junkFilter = NULL; resultRelInfo->ri_projectReturning = NULL; + + /* + * If partition_root has been specified, that means we are builiding the + * ResultRelationInfo for one of its leaf partitions. In that case, we + * need *not* initialize the leaf partition's constraint, but rather the + * the partition_root's (if any). We must do that explicitly like this, + * because implicit partition constraints are not inherited like user- + * defined constraints and would fail to be enforced by ExecConstraints() + * after a tuple is routed to a leaf partition. + */ + if (partition_root) + { + /* + * Root table itself may or may not be a partition; partition_check + * would be NIL in the latter case. + */ + partition_check = RelationGetPartitionQual(partition_root); + + /* + * This is not our own partition constraint, but rather an ancestor's. + * So any Vars in it bear the ancestor's attribute numbers. We must + * switch them to our own. (dummy varno = 1) + */ + if (partition_check != NIL) + partition_check = map_partition_varattnos(partition_check, 1, + resultRelationDesc, + partition_root); + } + else + partition_check = RelationGetPartitionQual(resultRelationDesc); + + resultRelInfo->ri_PartitionCheck = partition_check; + resultRelInfo->ri_PartitionRoot = partition_root; } /* @@ -1311,6 +1354,7 @@ ExecGetTriggerResultRel(EState *estate, Oid relid) InitResultRelInfo(rInfo, rel, 0, /* dummy rangetable index */ + NULL, estate->es_instrument); estate->es_trig_target_relations = lappend(estate->es_trig_target_relations, rInfo); @@ -1541,9 +1585,11 @@ ExecutePlan(EState *estate, /* * If a tuple count was supplied, we must force the plan to run without - * parallelism, because we might exit early. + * parallelism, because we might exit early. Also disable parallelism + * when writing into a relation, because no database changes are allowed + * in parallel mode. */ - if (numberTuples) + if (numberTuples || dest->mydest == DestIntoRel) use_parallel_mode = false; /* @@ -1690,9 +1736,61 @@ ExecRelCheck(ResultRelInfo *resultRelInfo, return NULL; } +/* + * ExecPartitionCheck --- check that tuple meets the partition constraint. + * + * Note: This is called *iff* resultRelInfo is the main target table. + */ +static bool +ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, + EState *estate) +{ + ExprContext *econtext; + + /* + * If first time through, build expression state tree for the partition + * check expression. Keep it in the per-query memory context so they'll + * survive throughout the query. + */ + if (resultRelInfo->ri_PartitionCheckExpr == NULL) + { + List *qual = resultRelInfo->ri_PartitionCheck; + + resultRelInfo->ri_PartitionCheckExpr = (List *) + ExecPrepareExpr((Expr *) qual, estate); + } + + /* + * We will use the EState's per-tuple context for evaluating constraint + * expressions (creating it if it's not already there). + */ + econtext = GetPerTupleExprContext(estate); + + /* Arrange for econtext's scan tuple to be the tuple under test */ + econtext->ecxt_scantuple = slot; + + /* + * As in case of the catalogued constraints, we treat a NULL result as + * success here, not a failure. + */ + return ExecQual(resultRelInfo->ri_PartitionCheckExpr, econtext, true); +} + +/* + * ExecConstraints - check constraints of the tuple in 'slot' + * + * This checks the traditional NOT NULL and check constraints, as well as + * the partition constraint, if any. + * + * Note: 'slot' contains the tuple to check the constraints of, which may + * have been converted from the original input tuple after tuple routing, + * while 'orig_slot' contains the original tuple to be shown in the message, + * if an error occurs. + */ void ExecConstraints(ResultRelInfo *resultRelInfo, - TupleTableSlot *slot, EState *estate) + TupleTableSlot *slot, TupleTableSlot *orig_slot, + EState *estate) { Relation rel = resultRelInfo->ri_RelationDesc; TupleDesc tupdesc = RelationGetDescr(rel); @@ -1701,9 +1799,9 @@ ExecConstraints(ResultRelInfo *resultRelInfo, Bitmapset *insertedCols; Bitmapset *updatedCols; - Assert(constr); + Assert(constr || resultRelInfo->ri_PartitionCheck); - if (constr->has_not_null) + if (constr && constr->has_not_null) { int natts = tupdesc->natts; int attrChk; @@ -1714,12 +1812,24 @@ ExecConstraints(ResultRelInfo *resultRelInfo, slot_attisnull(slot, attrChk)) { char *val_desc; + Relation orig_rel = rel; + TupleDesc orig_tupdesc = tupdesc; + + /* + * choose the correct relation to build val_desc from the + * tuple contained in orig_slot + */ + if (resultRelInfo->ri_PartitionRoot) + { + rel = resultRelInfo->ri_PartitionRoot; + tupdesc = RelationGetDescr(rel); + } insertedCols = GetInsertedColumns(resultRelInfo, estate); updatedCols = GetUpdatedColumns(resultRelInfo, estate); modifiedCols = bms_union(insertedCols, updatedCols); val_desc = ExecBuildSlotValueDescription(RelationGetRelid(rel), - slot, + orig_slot, tupdesc, modifiedCols, 64); @@ -1727,37 +1837,73 @@ ExecConstraints(ResultRelInfo *resultRelInfo, ereport(ERROR, (errcode(ERRCODE_NOT_NULL_VIOLATION), errmsg("null value in column \"%s\" violates not-null constraint", - NameStr(tupdesc->attrs[attrChk - 1]->attname)), + NameStr(orig_tupdesc->attrs[attrChk - 1]->attname)), val_desc ? errdetail("Failing row contains %s.", val_desc) : 0, - errtablecol(rel, attrChk))); + errtablecol(orig_rel, attrChk))); } } } - if (constr->num_check > 0) + if (constr && constr->num_check > 0) { const char *failed; if ((failed = ExecRelCheck(resultRelInfo, slot, estate)) != NULL) { char *val_desc; + Relation orig_rel = rel; + + /* See the comment above. */ + if (resultRelInfo->ri_PartitionRoot) + { + rel = resultRelInfo->ri_PartitionRoot; + tupdesc = RelationGetDescr(rel); + } insertedCols = GetInsertedColumns(resultRelInfo, estate); updatedCols = GetUpdatedColumns(resultRelInfo, estate); modifiedCols = bms_union(insertedCols, updatedCols); val_desc = ExecBuildSlotValueDescription(RelationGetRelid(rel), - slot, + orig_slot, tupdesc, modifiedCols, 64); ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION), errmsg("new row for relation \"%s\" violates check constraint \"%s\"", - RelationGetRelationName(rel), failed), + RelationGetRelationName(orig_rel), failed), val_desc ? errdetail("Failing row contains %s.", val_desc) : 0, - errtableconstraint(rel, failed))); + errtableconstraint(orig_rel, failed))); } } + + if (resultRelInfo->ri_PartitionCheck && + !ExecPartitionCheck(resultRelInfo, slot, estate)) + { + char *val_desc; + Relation orig_rel = rel; + + /* See the comment above. */ + if (resultRelInfo->ri_PartitionRoot) + { + rel = resultRelInfo->ri_PartitionRoot; + tupdesc = RelationGetDescr(rel); + } + + insertedCols = GetInsertedColumns(resultRelInfo, estate); + updatedCols = GetUpdatedColumns(resultRelInfo, estate); + modifiedCols = bms_union(insertedCols, updatedCols); + val_desc = ExecBuildSlotValueDescription(RelationGetRelid(rel), + orig_slot, + tupdesc, + modifiedCols, + 64); + ereport(ERROR, + (errcode(ERRCODE_CHECK_VIOLATION), + errmsg("new row for relation \"%s\" violates partition constraint", + RelationGetRelationName(orig_rel)), + val_desc ? errdetail("Failing row contains %s.", val_desc) : 0)); + } } /* @@ -2925,3 +3071,155 @@ EvalPlanQualEnd(EPQState *epqstate) epqstate->planstate = NULL; epqstate->origslot = NULL; } + +/* + * ExecSetupPartitionTupleRouting - set up information needed during + * tuple routing for partitioned tables + * + * Output arguments: + * 'pd' receives an array of PartitionDispatch objects with one entry for + * every partitioned table in the partition tree + * 'partitions' receives an array of ResultRelInfo objects with one entry for + * every leaf partition in the partition tree + * 'tup_conv_maps' receives an array of TupleConversionMap objects with one + * entry for every leaf partition (required to convert input tuple based + * on the root table's rowtype to a leaf partition's rowtype after tuple + * routing is done + * 'partition_tuple_slot' receives a standalone TupleTableSlot to be used + * to manipulate any given leaf partition's rowtype after that partition + * is chosen by tuple-routing. + * 'num_parted' receives the number of partitioned tables in the partition + * tree (= the number of entries in the 'pd' output array) + * 'num_partitions' receives the number of leaf partitions in the partition + * tree (= the number of entries in the 'partitions' and 'tup_conv_maps' + * output arrays + * + * Note that all the relations in the partition tree are locked using the + * RowExclusiveLock mode upon return from this function. + */ +void +ExecSetupPartitionTupleRouting(Relation rel, + PartitionDispatch **pd, + ResultRelInfo **partitions, + TupleConversionMap ***tup_conv_maps, + TupleTableSlot **partition_tuple_slot, + int *num_parted, int *num_partitions) +{ + TupleDesc tupDesc = RelationGetDescr(rel); + List *leaf_parts; + ListCell *cell; + int i; + ResultRelInfo *leaf_part_rri; + + /* Get the tuple-routing information and lock partitions */ + *pd = RelationGetPartitionDispatchInfo(rel, RowExclusiveLock, num_parted, + &leaf_parts); + *num_partitions = list_length(leaf_parts); + *partitions = (ResultRelInfo *) palloc(*num_partitions * + sizeof(ResultRelInfo)); + *tup_conv_maps = (TupleConversionMap **) palloc0(*num_partitions * + sizeof(TupleConversionMap *)); + + /* + * Initialize an empty slot that will be used to manipulate tuples of any + * given partition's rowtype. It is attached to the caller-specified node + * (such as ModifyTableState) and released when the node finishes + * processing. + */ + *partition_tuple_slot = MakeTupleTableSlot(); + + leaf_part_rri = *partitions; + i = 0; + foreach(cell, leaf_parts) + { + Relation partrel; + TupleDesc part_tupdesc; + + /* + * We locked all the partitions above including the leaf partitions. + * Note that each of the relations in *partitions are eventually + * closed by the caller. + */ + partrel = heap_open(lfirst_oid(cell), NoLock); + part_tupdesc = RelationGetDescr(partrel); + + /* + * Verify result relation is a valid target for the current operation. + */ + CheckValidResultRel(partrel, CMD_INSERT); + + /* + * Save a tuple conversion map to convert a tuple routed to this + * partition from the parent's type to the partition's. + */ + (*tup_conv_maps)[i] = convert_tuples_by_name(tupDesc, part_tupdesc, + gettext_noop("could not convert row type")); + + InitResultRelInfo(leaf_part_rri, + partrel, + 1, /* dummy */ + rel, + 0); + + /* + * Open partition indices (remember we do not support ON CONFLICT in + * case of partitioned tables, so we do not need support information + * for speculative insertion) + */ + if (leaf_part_rri->ri_RelationDesc->rd_rel->relhasindex && + leaf_part_rri->ri_IndexRelationDescs == NULL) + ExecOpenIndices(leaf_part_rri, false); + + leaf_part_rri++; + i++; + } +} + +/* + * ExecFindPartition -- Find a leaf partition in the partition tree rooted + * at parent, for the heap tuple contained in *slot + * + * estate must be non-NULL; we'll need it to compute any expressions in the + * partition key(s) + * + * If no leaf partition is found, this routine errors out with the appropriate + * error message, else it returns the leaf partition sequence number returned + * by get_partition_for_tuple() unchanged. + */ +int +ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd, + TupleTableSlot *slot, EState *estate) +{ + int result; + Oid failed_at; + ExprContext *econtext = GetPerTupleExprContext(estate); + + econtext->ecxt_scantuple = slot; + result = get_partition_for_tuple(pd, slot, estate, &failed_at); + if (result < 0) + { + Relation rel = resultRelInfo->ri_RelationDesc; + char *val_desc; + Bitmapset *insertedCols, + *updatedCols, + *modifiedCols; + TupleDesc tupDesc = RelationGetDescr(rel); + + insertedCols = GetInsertedColumns(resultRelInfo, estate); + updatedCols = GetUpdatedColumns(resultRelInfo, estate); + modifiedCols = bms_union(insertedCols, updatedCols); + val_desc = ExecBuildSlotValueDescription(RelationGetRelid(rel), + slot, + tupDesc, + modifiedCols, + 64); + Assert(OidIsValid(failed_at)); + ereport(ERROR, + (errcode(ERRCODE_CHECK_VIOLATION), + errmsg("no partition of relation \"%s\" found for row", + get_rel_name(failed_at)), + val_desc ? errdetail("Failing row contains %s.", val_desc) : 0)); + } + + return result; +} diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c index 380d743f6c..e01fe6da96 100644 --- a/src/backend/executor/execParallel.c +++ b/src/backend/executor/execParallel.c @@ -3,7 +3,7 @@ * execParallel.c * Support routines for parallel execution. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * This file contains routines that are intended to support setting up, @@ -34,6 +34,7 @@ #include "optimizer/planner.h" #include "storage/spin.h" #include "tcop/tcopprot.h" +#include "utils/dsa.h" #include "utils/memutils.h" #include "utils/snapmgr.h" @@ -47,6 +48,7 @@ #define PARALLEL_KEY_BUFFER_USAGE UINT64CONST(0xE000000000000003) #define PARALLEL_KEY_TUPLE_QUEUE UINT64CONST(0xE000000000000004) #define PARALLEL_KEY_INSTRUMENTATION UINT64CONST(0xE000000000000005) +#define PARALLEL_KEY_DSA UINT64CONST(0xE000000000000006) #define PARALLEL_TUPLE_QUEUE_SIZE 65536 @@ -154,13 +156,15 @@ ExecSerializePlan(Plan *plan, EState *estate) pstmt->planTree = plan; pstmt->rtable = estate->es_range_table; pstmt->resultRelations = NIL; - pstmt->utilityStmt = NULL; pstmt->subplans = NIL; pstmt->rewindPlanIDs = NULL; pstmt->rowMarks = NIL; pstmt->relationOids = NIL; pstmt->invalItems = NIL; /* workers can't replan anyway... */ pstmt->nParamExec = estate->es_plannedstmt->nParamExec; + pstmt->utilityStmt = NULL; + pstmt->stmt_location = -1; + pstmt->stmt_len = -1; /* Return serialized copy of our dummy PlannedStmt. */ return nodeToString(pstmt); @@ -345,6 +349,7 @@ ExecInitParallelPlan(PlanState *planstate, EState *estate, int nworkers) int param_len; int instrumentation_len = 0; int instrument_offset = 0; + Size dsa_minsize = dsa_minimum_size(); /* Allocate object for return value. */ pei = palloc0(sizeof(ParallelExecutorInfo)); @@ -413,6 +418,10 @@ ExecInitParallelPlan(PlanState *planstate, EState *estate, int nworkers) shm_toc_estimate_keys(&pcxt->estimator, 1); } + /* Estimate space for DSA area. */ + shm_toc_estimate_chunk(&pcxt->estimator, dsa_minsize); + shm_toc_estimate_keys(&pcxt->estimator, 1); + /* Everyone's had a chance to ask for space, so now create the DSM. */ InitializeParallelDSM(pcxt); @@ -466,6 +475,28 @@ ExecInitParallelPlan(PlanState *planstate, EState *estate, int nworkers) pei->instrumentation = instrumentation; } + /* + * Create a DSA area that can be used by the leader and all workers. + * (However, if we failed to create a DSM and are using private memory + * instead, then skip this.) + */ + if (pcxt->seg != NULL) + { + char *area_space; + + area_space = shm_toc_allocate(pcxt->toc, dsa_minsize); + shm_toc_insert(pcxt->toc, PARALLEL_KEY_DSA, area_space); + pei->area = dsa_create_in_place(area_space, dsa_minsize, + LWTRANCHE_PARALLEL_QUERY_DSA, + pcxt->seg); + } + + /* + * Make the area available to executor nodes running in the leader. See + * also ParallelQueryMain which makes it available to workers. + */ + estate->es_query_dsa = pei->area; + /* * Give parallel-aware nodes a chance to initialize their shared data. * This also initializes the elements of instrumentation->ps_instrument, @@ -488,7 +519,7 @@ ExecInitParallelPlan(PlanState *planstate, EState *estate, int nworkers) } /* - * Copy instrumentation information about this node and its descendents from + * Copy instrumentation information about this node and its descendants from * dynamic shared memory. */ static bool @@ -500,6 +531,7 @@ ExecParallelRetrieveInstrumentation(PlanState *planstate, int n; int ibytes; int plan_node_id = planstate->plan->plan_node_id; + MemoryContext oldcontext; /* Find the instumentation for this node. */ for (i = 0; i < instrumentation->num_plan_nodes; ++i) @@ -514,10 +546,19 @@ ExecParallelRetrieveInstrumentation(PlanState *planstate, for (n = 0; n < instrumentation->num_workers; ++n) InstrAggNode(planstate->instrument, &instrument[n]); - /* Also store the per-worker detail. */ + /* + * Also store the per-worker detail. + * + * Worker instrumentation should be allocated in the same context as + * the regular instrumentation information, which is the per-query + * context. Switch into per-query memory context. + */ + oldcontext = MemoryContextSwitchTo(planstate->state->es_query_cxt); ibytes = mul_size(instrumentation->num_workers, sizeof(Instrumentation)); planstate->worker_instrument = palloc(ibytes + offsetof(WorkerInstrumentation, instrument)); + MemoryContextSwitchTo(oldcontext); + planstate->worker_instrument->num_workers = instrumentation->num_workers; memcpy(&planstate->worker_instrument->instrument, instrument, ibytes); @@ -553,7 +594,7 @@ ExecParallelFinish(ParallelExecutorInfo *pei) } /* - * Clean up whatever ParallelExecutreInfo resources still exist after + * Clean up whatever ParallelExecutorInfo resources still exist after * ExecParallelFinish. We separate these routines because someone might * want to examine the contents of the DSM after ExecParallelFinish and * before calling this routine. @@ -561,6 +602,11 @@ ExecParallelFinish(ParallelExecutorInfo *pei) void ExecParallelCleanup(ParallelExecutorInfo *pei) { + if (pei->area != NULL) + { + dsa_detach(pei->area); + pei->area = NULL; + } if (pei->pcxt != NULL) { DestroyParallelContext(pei->pcxt); @@ -621,7 +667,7 @@ ExecParallelGetQueryDesc(shm_toc *toc, DestReceiver *receiver, } /* - * Copy instrumentation information from this node and its descendents into + * Copy instrumentation information from this node and its descendants into * dynamic shared memory, so that the parallel leader can retrieve it. */ static bool @@ -661,7 +707,7 @@ ExecParallelReportInstrumentation(PlanState *planstate, } /* - * Initialize the PlanState and its descendents with the information + * Initialize the PlanState and its descendants with the information * retrieved from shared memory. This has to be done once the PlanState * is allocated and initialized by executor; that is, after ExecutorStart(). */ @@ -698,10 +744,11 @@ ExecParallelInitializeWorker(PlanState *planstate, shm_toc *toc) /* * Main entrypoint for parallel query worker processes. * - * We reach this function from ParallelMain, so the setup necessary to create - * a sensible parallel environment has already been done; ParallelMain worries - * about stuff like the transaction state, combo CID mappings, and GUC values, - * so we don't need to deal with any of that here. + * We reach this function from ParallelWorkerMain, so the setup necessary to + * create a sensible parallel environment has already been done; + * ParallelWorkerMain worries about stuff like the transaction state, combo + * CID mappings, and GUC values, so we don't need to deal with any of that + * here. * * Our job is to deal with concerns specific to the executor. The parallel * group leader will have stored a serialized PlannedStmt, and it's our job @@ -718,6 +765,8 @@ ParallelQueryMain(dsm_segment *seg, shm_toc *toc) QueryDesc *queryDesc; SharedExecutorInstrumentation *instrumentation; int instrument_options = 0; + void *area_space; + dsa_area *area; /* Set up DestReceiver, SharedExecutorInstrumentation, and QueryDesc. */ receiver = ExecParallelGetReceiver(seg, toc); @@ -729,10 +778,21 @@ ParallelQueryMain(dsm_segment *seg, shm_toc *toc) /* Prepare to track buffer usage during query execution. */ InstrStartParallelQuery(); - /* Start up the executor, have it run the plan, and then shut it down. */ + /* Attach to the dynamic shared memory area. */ + area_space = shm_toc_lookup(toc, PARALLEL_KEY_DSA); + area = dsa_attach_in_place(area_space, seg); + + /* Start up the executor */ ExecutorStart(queryDesc, 0); + + /* Special executor initialization steps for parallel workers */ + queryDesc->planstate->state->es_query_dsa = area; ExecParallelInitializeWorker(queryDesc->planstate, toc); + + /* Run the plan */ ExecutorRun(queryDesc, ForwardScanDirection, 0L); + + /* Shut down the executor */ ExecutorFinish(queryDesc); /* Report buffer usage during parallel execution. */ @@ -748,6 +808,7 @@ ParallelQueryMain(dsm_segment *seg, shm_toc *toc) ExecutorEnd(queryDesc); /* Cleanup. */ + dsa_detach(area); FreeQueryDesc(queryDesc); (*receiver->rDestroy) (receiver); } diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c index 554244ff71..0dd95c6d17 100644 --- a/src/backend/executor/execProcnode.c +++ b/src/backend/executor/execProcnode.c @@ -7,7 +7,7 @@ * ExecProcNode, or ExecEndNode on its subnodes and do the appropriate * processing. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -88,6 +88,7 @@ #include "executor/nodeCustom.h" #include "executor/nodeForeignscan.h" #include "executor/nodeFunctionscan.h" +#include "executor/nodeGather.h" #include "executor/nodeGroup.h" #include "executor/nodeHash.h" #include "executor/nodeHashjoin.h" @@ -100,7 +101,7 @@ #include "executor/nodeMergejoin.h" #include "executor/nodeModifyTable.h" #include "executor/nodeNestloop.h" -#include "executor/nodeGather.h" +#include "executor/nodeProjectSet.h" #include "executor/nodeRecursiveunion.h" #include "executor/nodeResult.h" #include "executor/nodeSamplescan.h" @@ -155,6 +156,11 @@ ExecInitNode(Plan *node, EState *estate, int eflags) estate, eflags); break; + case T_ProjectSet: + result = (PlanState *) ExecInitProjectSet((ProjectSet *) node, + estate, eflags); + break; + case T_ModifyTable: result = (PlanState *) ExecInitModifyTable((ModifyTable *) node, estate, eflags); @@ -392,6 +398,10 @@ ExecProcNode(PlanState *node) result = ExecResult((ResultState *) node); break; + case T_ProjectSetState: + result = ExecProjectSet((ProjectSetState *) node); + break; + case T_ModifyTableState: result = ExecModifyTable((ModifyTableState *) node); break; @@ -634,6 +644,10 @@ ExecEndNode(PlanState *node) ExecEndResult((ResultState *) node); break; + case T_ProjectSetState: + ExecEndProjectSet((ProjectSetState *) node); + break; + case T_ModifyTableState: ExecEndModifyTable((ModifyTableState *) node); break; diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index cbb76d1f1c..19dd0b264b 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -3,7 +3,7 @@ * execQual.c * Routines to evaluate qualification and targetlist expressions * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -29,9 +29,9 @@ * instead of doing needless copying. -cim 5/31/91 * * During expression evaluation, we check_stack_depth only in - * ExecMakeFunctionResult (and substitute routines) rather than at every - * single node. This is a compromise that trades off precision of the - * stack limit setting to gain speed. + * ExecMakeFunctionResultSet/ExecMakeFunctionResultNoSets rather than at + * every single node. This is a compromise that trades off precision of + * the stack limit setting to gain speed. */ #include "postgres.h" @@ -53,8 +53,10 @@ #include "pgstat.h" #include "utils/acl.h" #include "utils/builtins.h" +#include "utils/date.h" #include "utils/lsyscache.h" #include "utils/memutils.h" +#include "utils/timestamp.h" #include "utils/typcache.h" #include "utils/xml.h" @@ -62,128 +64,127 @@ /* static function decls */ static Datum ExecEvalArrayRef(ArrayRefExprState *astate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static bool isAssignmentIndirectionExpr(ExprState *exprstate); static Datum ExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalWindowFunc(WindowFuncExprState *wfunc, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalScalarVar(ExprState *exprstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalScalarVarFast(ExprState *exprstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalWholeRowFast(WholeRowVarExprState *wrvstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalWholeRowSlow(WholeRowVarExprState *wrvstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalConst(ExprState *exprstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalParamExec(ExprState *exprstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalParamExtern(ExprState *exprstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static void init_fcache(Oid foid, Oid input_collation, FuncExprState *fcache, - MemoryContext fcacheCxt, bool needDescForSets); + MemoryContext fcacheCxt, bool allowSRF, bool needDescForSRF); static void ShutdownFuncExpr(Datum arg); static TupleDesc get_cached_rowtype(Oid type_id, int32 typmod, TupleDesc *cache_field, ExprContext *econtext); static void ShutdownTupleDescRef(Datum arg); -static ExprDoneCond ExecEvalFuncArgs(FunctionCallInfo fcinfo, +static void ExecEvalFuncArgs(FunctionCallInfo fcinfo, List *argList, ExprContext *econtext); static void ExecPrepareTuplestoreResult(FuncExprState *fcache, ExprContext *econtext, Tuplestorestate *resultStore, TupleDesc resultDesc); static void tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc); -static Datum ExecMakeFunctionResult(FuncExprState *fcache, - ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone); static Datum ExecMakeFunctionResultNoSets(FuncExprState *fcache, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalFunc(FuncExprState *fcache, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalOper(FuncExprState *fcache, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalDistinct(FuncExprState *fcache, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalNot(BoolExprState *notclause, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalCaseTestExpr(ExprState *exprstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalArray(ArrayExprState *astate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalRow(RowExprState *rstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalRowCompare(RowCompareExprState *rstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalCoalesce(CoalesceExprState *coalesceExpr, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); +static Datum ExecEvalSQLValueFunction(ExprState *svfExpr, + ExprContext *econtext, + bool *isNull); static Datum ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalNullIf(FuncExprState *nullIfExpr, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalNullTest(NullTestState *nstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalBooleanTest(GenericExprState *bstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalCoerceToDomainValue(ExprState *exprstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalFieldSelect(FieldSelectState *fstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalFieldStore(FieldStoreState *fstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalRelabelType(GenericExprState *exprstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalCoerceViaIO(CoerceViaIOState *iostate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalCurrentOfExpr(ExprState *exprstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static Datum ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); /* ---------------------------------------------------------------- @@ -194,8 +195,7 @@ static Datum ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate, * Each of the following routines having the signature * Datum ExecEvalFoo(ExprState *expression, * ExprContext *econtext, - * bool *isNull, - * ExprDoneCond *isDone); + * bool *isNull); * is responsible for evaluating one type or subtype of ExprState node. * They are normally called via the ExecEvalExpr macro, which makes use of * the function pointer set up when the ExprState node was built by @@ -219,22 +219,6 @@ static Datum ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate, * return value: Datum value of result * *isNull: set to TRUE if result is NULL (actual return value is * meaningless if so); set to FALSE if non-null result - * *isDone: set to indicator of set-result status - * - * A caller that can only accept a singleton (non-set) result should pass - * NULL for isDone; if the expression computes a set result then an error - * will be reported via ereport. If the caller does pass an isDone pointer - * then *isDone is set to one of these three states: - * ExprSingleResult singleton result (not a set) - * ExprMultipleResult return value is one element of a set - * ExprEndResult there are no more elements in the set - * When ExprMultipleResult is returned, the caller should invoke - * ExecEvalExpr() repeatedly until ExprEndResult is returned. ExprEndResult - * is returned after the last real set element. For convenience isNull will - * always be set TRUE when ExprEndResult is returned, but this should not be - * taken as indicating a NULL element of the set. Note that these return - * conventions allow us to distinguish among a singleton NULL, a NULL element - * of a set, and an empty set. * * The caller should already have switched into the temporary memory * context econtext->ecxt_per_tuple_memory. The convenience entry point @@ -259,8 +243,7 @@ static Datum ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate, static Datum ExecEvalArrayRef(ArrayRefExprState *astate, ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) + bool *isNull) { ArrayRef *arrayRef = (ArrayRef *) astate->xprstate.expr; Datum array_source; @@ -277,8 +260,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate, array_source = ExecEvalExpr(astate->refexpr, econtext, - isNull, - isDone); + isNull); /* * If refexpr yields NULL, and it's a fetch, then result is NULL. In the @@ -286,8 +268,6 @@ ExecEvalArrayRef(ArrayRefExprState *astate, */ if (*isNull) { - if (isDone && *isDone == ExprEndResult) - return (Datum) NULL; /* end of set result */ if (!isAssignment) return (Datum) NULL; } @@ -313,8 +293,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate, upper.indx[i++] = DatumGetInt32(ExecEvalExpr(eltstate, econtext, - &eisnull, - NULL)); + &eisnull)); /* If any index expr yields NULL, result is NULL or error */ if (eisnull) { @@ -349,8 +328,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate, lower.indx[j++] = DatumGetInt32(ExecEvalExpr(eltstate, econtext, - &eisnull, - NULL)); + &eisnull)); /* If any index expr yields NULL, result is NULL or error */ if (eisnull) { @@ -437,8 +415,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate, */ sourceData = ExecEvalExpr(astate->refassgnexpr, econtext, - &eisnull, - NULL); + &eisnull); econtext->caseValue_datum = save_datum; econtext->caseValue_isNull = save_isNull; @@ -541,11 +518,8 @@ isAssignmentIndirectionExpr(ExprState *exprstate) */ static Datum ExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { - if (isDone) - *isDone = ExprSingleResult; - if (econtext->ecxt_aggvalues == NULL) /* safety check */ elog(ERROR, "no aggregates in this expression context"); @@ -562,11 +536,8 @@ ExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext, */ static Datum ExecEvalWindowFunc(WindowFuncExprState *wfunc, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { - if (isDone) - *isDone = ExprSingleResult; - if (econtext->ecxt_aggvalues == NULL) /* safety check */ elog(ERROR, "no window functions in this expression context"); @@ -587,15 +558,12 @@ ExecEvalWindowFunc(WindowFuncExprState *wfunc, ExprContext *econtext, */ static Datum ExecEvalScalarVar(ExprState *exprstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { Var *variable = (Var *) exprstate->expr; TupleTableSlot *slot; AttrNumber attnum; - if (isDone) - *isDone = ExprSingleResult; - /* Get the input slot and attribute number we want */ switch (variable->varno) { @@ -676,15 +644,12 @@ ExecEvalScalarVar(ExprState *exprstate, ExprContext *econtext, */ static Datum ExecEvalScalarVarFast(ExprState *exprstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { Var *variable = (Var *) exprstate->expr; TupleTableSlot *slot; AttrNumber attnum; - if (isDone) - *isDone = ExprSingleResult; - /* Get the input slot and attribute number we want */ switch (variable->varno) { @@ -724,7 +689,7 @@ ExecEvalScalarVarFast(ExprState *exprstate, ExprContext *econtext, */ static Datum ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { Var *variable = (Var *) wrvstate->xprstate.expr; TupleTableSlot *slot; @@ -732,9 +697,6 @@ ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, ExprContext *econtext, MemoryContext oldcontext; bool needslow = false; - if (isDone) - *isDone = ExprSingleResult; - /* This was checked by ExecInitExpr */ Assert(variable->varattno == InvalidAttrNumber); @@ -940,7 +902,7 @@ ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, ExprContext *econtext, /* Fetch the value */ return (*wrvstate->xprstate.evalfunc) ((ExprState *) wrvstate, econtext, - isNull, isDone); + isNull); } /* ---------------------------------------------------------------- @@ -951,14 +913,12 @@ ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, ExprContext *econtext, */ static Datum ExecEvalWholeRowFast(WholeRowVarExprState *wrvstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { Var *variable = (Var *) wrvstate->xprstate.expr; TupleTableSlot *slot; HeapTupleHeader dtuple; - if (isDone) - *isDone = ExprSingleResult; *isNull = false; /* Get the input slot we want */ @@ -1007,7 +967,7 @@ ExecEvalWholeRowFast(WholeRowVarExprState *wrvstate, ExprContext *econtext, */ static Datum ExecEvalWholeRowSlow(WholeRowVarExprState *wrvstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { Var *variable = (Var *) wrvstate->xprstate.expr; TupleTableSlot *slot; @@ -1017,8 +977,6 @@ ExecEvalWholeRowSlow(WholeRowVarExprState *wrvstate, ExprContext *econtext, HeapTupleHeader dtuple; int i; - if (isDone) - *isDone = ExprSingleResult; *isNull = false; /* Get the input slot we want */ @@ -1096,13 +1054,10 @@ ExecEvalWholeRowSlow(WholeRowVarExprState *wrvstate, ExprContext *econtext, */ static Datum ExecEvalConst(ExprState *exprstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { Const *con = (Const *) exprstate->expr; - if (isDone) - *isDone = ExprSingleResult; - *isNull = con->constisnull; return con->constvalue; } @@ -1115,15 +1070,12 @@ ExecEvalConst(ExprState *exprstate, ExprContext *econtext, */ static Datum ExecEvalParamExec(ExprState *exprstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { Param *expression = (Param *) exprstate->expr; int thisParamId = expression->paramid; ParamExecData *prm; - if (isDone) - *isDone = ExprSingleResult; - /* * PARAM_EXEC params (internal executor parameters) are stored in the * ecxt_param_exec_vals array, and can be accessed by array index. @@ -1148,15 +1100,12 @@ ExecEvalParamExec(ExprState *exprstate, ExprContext *econtext, */ static Datum ExecEvalParamExtern(ExprState *exprstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { Param *expression = (Param *) exprstate->expr; int thisParamId = expression->paramid; ParamListInfo paramInfo = econtext->ecxt_param_list_info; - if (isDone) - *isDone = ExprSingleResult; - /* * PARAM_EXTERN parameters must be sought in ecxt_param_list_info. */ @@ -1322,7 +1271,7 @@ GetAttributeByName(HeapTupleHeader tuple, const char *attname, bool *isNull) */ static void init_fcache(Oid foid, Oid input_collation, FuncExprState *fcache, - MemoryContext fcacheCxt, bool needDescForSets) + MemoryContext fcacheCxt, bool allowSRF, bool needDescForSRF) { AclResult aclresult; @@ -1355,8 +1304,17 @@ init_fcache(Oid foid, Oid input_collation, FuncExprState *fcache, list_length(fcache->args), input_collation, NULL, NULL); + /* If function returns set, check if that's allowed by caller */ + if (fcache->func.fn_retset && !allowSRF) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("set-valued function called in context that cannot accept a set"))); + + /* Otherwise, ExecInitExpr should have marked the fcache correctly */ + Assert(fcache->func.fn_retset == fcache->funcReturnsSet); + /* If function returns set, prepare expected tuple descriptor */ - if (fcache->func.fn_retset && needDescForSets) + if (fcache->func.fn_retset && needDescForSRF) { TypeFuncClass functypclass; Oid funcrettype; @@ -1411,7 +1369,6 @@ init_fcache(Oid foid, Oid input_collation, FuncExprState *fcache, /* Initialize additional state */ fcache->funcResultStore = NULL; fcache->funcResultSlot = NULL; - fcache->setArgsValid = false; fcache->shutdown_reg = false; } @@ -1498,53 +1455,32 @@ ShutdownTupleDescRef(Datum arg) /* * Evaluate arguments for a function. */ -static ExprDoneCond +static void ExecEvalFuncArgs(FunctionCallInfo fcinfo, List *argList, ExprContext *econtext) { - ExprDoneCond argIsDone; int i; ListCell *arg; - argIsDone = ExprSingleResult; /* default assumption */ - i = 0; foreach(arg, argList) { ExprState *argstate = (ExprState *) lfirst(arg); - ExprDoneCond thisArgIsDone; fcinfo->arg[i] = ExecEvalExpr(argstate, econtext, - &fcinfo->argnull[i], - &thisArgIsDone); - - if (thisArgIsDone != ExprSingleResult) - { - /* - * We allow only one argument to have a set value; we'd need much - * more complexity to keep track of multiple set arguments (cf. - * ExecTargetList) and it doesn't seem worth it. - */ - if (argIsDone != ExprSingleResult) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("functions and operators can take at most one set argument"))); - argIsDone = thisArgIsDone; - } + &fcinfo->argnull[i]); i++; } Assert(i == fcinfo->nargs); - - return argIsDone; } /* * ExecPrepareTuplestoreResult * - * Subroutine for ExecMakeFunctionResult: prepare to extract rows from a + * Subroutine for ExecMakeFunctionResultSet: prepare to extract rows from a * tuplestore function result. We must set up a funcResultSlot (unless * already done in a previous call cycle) and verify that the function * returned the expected tuple descriptor. @@ -1668,27 +1604,24 @@ tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc) } /* - * ExecMakeFunctionResult - * - * Evaluate the arguments to a function and then the function itself. - * init_fcache is presumed already run on the FuncExprState. + * ExecMakeFunctionResultSet * - * This function handles the most general case, wherein the function or - * one of its arguments can return a set. + * Evaluate the arguments to a set-returning function and then call the + * function itself. The argument expressions may not contain set-returning + * functions (the planner is supposed to have separated evaluation for those). */ -static Datum -ExecMakeFunctionResult(FuncExprState *fcache, - ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) +Datum +ExecMakeFunctionResultSet(FuncExprState *fcache, + ExprContext *econtext, + bool *isNull, + ExprDoneCond *isDone) { List *arguments; Datum result; FunctionCallInfo fcinfo; PgStat_FunctionCallUsage fcusage; - ReturnSetInfo rsinfo; /* for functions returning sets */ - ExprDoneCond argDone; - bool hasSetArg; + ReturnSetInfo rsinfo; + bool callit; int i; restart: @@ -1696,6 +1629,34 @@ ExecMakeFunctionResult(FuncExprState *fcache, /* Guard against stack overflow due to overly complex expressions */ check_stack_depth(); + /* + * Initialize function cache if first time through. The expression node + * could be either a FuncExpr or an OpExpr. + */ + if (fcache->func.fn_oid == InvalidOid) + { + if (IsA(fcache->xprstate.expr, FuncExpr)) + { + FuncExpr *func = (FuncExpr *) fcache->xprstate.expr; + + init_fcache(func->funcid, func->inputcollid, fcache, + econtext->ecxt_per_query_memory, true, true); + } + else if (IsA(fcache->xprstate.expr, OpExpr)) + { + OpExpr *op = (OpExpr *) fcache->xprstate.expr; + + init_fcache(op->opfuncid, op->inputcollid, fcache, + econtext->ecxt_per_query_memory, true, true); + } + else + elog(ERROR, "unrecognized node type: %d", + (int) nodeTag(fcache->xprstate.expr)); + + /* shouldn't get here otherwise */ + Assert(fcache->func.fn_retset); + } + /* * If a previous call of the function returned a set result in the form of * a tuplestore, continue reading rows from the tuplestore until it's @@ -1703,7 +1664,6 @@ ExecMakeFunctionResult(FuncExprState *fcache, */ if (fcache->funcResultStore) { - Assert(isDone); /* it was provided before ... */ if (tuplestore_gettupleslot(fcache->funcResultStore, true, false, fcache->funcResultSlot)) { @@ -1723,15 +1683,9 @@ ExecMakeFunctionResult(FuncExprState *fcache, /* Exhausted the tuplestore, so clean up */ tuplestore_end(fcache->funcResultStore); fcache->funcResultStore = NULL; - /* We are done unless there was a set-valued argument */ - if (!fcache->setHasSetArg) - { - *isDone = ExprEndResult; - *isNull = true; - return (Datum) 0; - } - /* If there was, continue evaluating the argument values */ - Assert(!fcache->setArgsValid); + *isDone = ExprEndResult; + *isNull = true; + return (Datum) 0; } /* @@ -1743,26 +1697,9 @@ ExecMakeFunctionResult(FuncExprState *fcache, fcinfo = &fcache->fcinfo_data; arguments = fcache->args; if (!fcache->setArgsValid) - { - argDone = ExecEvalFuncArgs(fcinfo, arguments, econtext); - if (argDone == ExprEndResult) - { - /* input is an empty set, so return an empty set. */ - *isNull = true; - if (isDone) - *isDone = ExprEndResult; - else - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("set-valued function called in context that cannot accept a set"))); - return (Datum) 0; - } - hasSetArg = (argDone != ExprSingleResult); - } + ExecEvalFuncArgs(fcinfo, arguments, econtext); else { - /* Re-use callinfo from previous evaluation */ - hasSetArg = fcache->setHasSetArg; /* Reset flag (we may set it again below) */ fcache->setArgsValid = false; } @@ -1770,213 +1707,105 @@ ExecMakeFunctionResult(FuncExprState *fcache, /* * Now call the function, passing the evaluated parameter values. */ - if (fcache->func.fn_retset || hasSetArg) - { - /* - * We need to return a set result. Complain if caller not ready to - * accept one. - */ - if (isDone == NULL) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("set-valued function called in context that cannot accept a set"))); - /* - * Prepare a resultinfo node for communication. If the function - * doesn't itself return set, we don't pass the resultinfo to the - * function, but we need to fill it in anyway for internal use. - */ - if (fcache->func.fn_retset) - fcinfo->resultinfo = (Node *) &rsinfo; - rsinfo.type = T_ReturnSetInfo; - rsinfo.econtext = econtext; - rsinfo.expectedDesc = fcache->funcResultDesc; - rsinfo.allowedModes = (int) (SFRM_ValuePerCall | SFRM_Materialize); - /* note we do not set SFRM_Materialize_Random or _Preferred */ - rsinfo.returnMode = SFRM_ValuePerCall; - /* isDone is filled below */ - rsinfo.setResult = NULL; - rsinfo.setDesc = NULL; + /* Prepare a resultinfo node for communication. */ + fcinfo->resultinfo = (Node *) &rsinfo; + rsinfo.type = T_ReturnSetInfo; + rsinfo.econtext = econtext; + rsinfo.expectedDesc = fcache->funcResultDesc; + rsinfo.allowedModes = (int) (SFRM_ValuePerCall | SFRM_Materialize); + /* note we do not set SFRM_Materialize_Random or _Preferred */ + rsinfo.returnMode = SFRM_ValuePerCall; + /* isDone is filled below */ + rsinfo.setResult = NULL; + rsinfo.setDesc = NULL; - /* - * This loop handles the situation where we have both a set argument - * and a set-valued function. Once we have exhausted the function's - * value(s) for a particular argument value, we have to get the next - * argument value and start the function over again. We might have to - * do it more than once, if the function produces an empty result set - * for a particular input value. - */ - for (;;) + /* + * If function is strict, and there are any NULL arguments, skip calling + * the function. + */ + callit = true; + if (fcache->func.fn_strict) + { + for (i = 0; i < fcinfo->nargs; i++) { - /* - * If function is strict, and there are any NULL arguments, skip - * calling the function (at least for this set of args). - */ - bool callit = true; - - if (fcache->func.fn_strict) - { - for (i = 0; i < fcinfo->nargs; i++) - { - if (fcinfo->argnull[i]) - { - callit = false; - break; - } - } - } - - if (callit) - { - pgstat_init_function_usage(fcinfo, &fcusage); - - fcinfo->isnull = false; - rsinfo.isDone = ExprSingleResult; - result = FunctionCallInvoke(fcinfo); - *isNull = fcinfo->isnull; - *isDone = rsinfo.isDone; - - pgstat_end_function_usage(&fcusage, - rsinfo.isDone != ExprMultipleResult); - } - else if (fcache->func.fn_retset) - { - /* for a strict SRF, result for NULL is an empty set */ - result = (Datum) 0; - *isNull = true; - *isDone = ExprEndResult; - } - else - { - /* for a strict non-SRF, result for NULL is a NULL */ - result = (Datum) 0; - *isNull = true; - *isDone = ExprSingleResult; - } - - /* Which protocol does function want to use? */ - if (rsinfo.returnMode == SFRM_ValuePerCall) - { - if (*isDone != ExprEndResult) - { - /* - * Got a result from current argument. If function itself - * returns set, save the current argument values to re-use - * on the next call. - */ - if (fcache->func.fn_retset && - *isDone == ExprMultipleResult) - { - fcache->setHasSetArg = hasSetArg; - fcache->setArgsValid = true; - /* Register cleanup callback if we didn't already */ - if (!fcache->shutdown_reg) - { - RegisterExprContextCallback(econtext, - ShutdownFuncExpr, - PointerGetDatum(fcache)); - fcache->shutdown_reg = true; - } - } - - /* - * Make sure we say we are returning a set, even if the - * function itself doesn't return sets. - */ - if (hasSetArg) - *isDone = ExprMultipleResult; - break; - } - } - else if (rsinfo.returnMode == SFRM_Materialize) + if (fcinfo->argnull[i]) { - /* check we're on the same page as the function author */ - if (rsinfo.isDone != ExprSingleResult) - ereport(ERROR, - (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED), - errmsg("table-function protocol for materialize mode was not followed"))); - if (rsinfo.setResult != NULL) - { - /* prepare to return values from the tuplestore */ - ExecPrepareTuplestoreResult(fcache, econtext, - rsinfo.setResult, - rsinfo.setDesc); - /* remember whether we had set arguments */ - fcache->setHasSetArg = hasSetArg; - /* loop back to top to start returning from tuplestore */ - goto restart; - } - /* if setResult was left null, treat it as empty set */ - *isDone = ExprEndResult; - *isNull = true; - result = (Datum) 0; + callit = false; + break; } - else - ereport(ERROR, - (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED), - errmsg("unrecognized table-function returnMode: %d", - (int) rsinfo.returnMode))); - - /* Else, done with this argument */ - if (!hasSetArg) - break; /* input not a set, so done */ + } + } - /* Re-eval args to get the next element of the input set */ - argDone = ExecEvalFuncArgs(fcinfo, arguments, econtext); + if (callit) + { + pgstat_init_function_usage(fcinfo, &fcusage); - if (argDone != ExprMultipleResult) - { - /* End of argument set, so we're done. */ - *isNull = true; - *isDone = ExprEndResult; - result = (Datum) 0; - break; - } + fcinfo->isnull = false; + rsinfo.isDone = ExprSingleResult; + result = FunctionCallInvoke(fcinfo); + *isNull = fcinfo->isnull; + *isDone = rsinfo.isDone; - /* - * If we reach here, loop around to run the function on the new - * argument. - */ - } + pgstat_end_function_usage(&fcusage, + rsinfo.isDone != ExprMultipleResult); } else { - /* - * Non-set case: much easier. - * - * In common cases, this code path is unreachable because we'd have - * selected ExecMakeFunctionResultNoSets instead. However, it's - * possible to get here if an argument sometimes produces set results - * and sometimes scalar results. For example, a CASE expression might - * call a set-returning function in only some of its arms. - */ - if (isDone) - *isDone = ExprSingleResult; + /* for a strict SRF, result for NULL is an empty set */ + result = (Datum) 0; + *isNull = true; + *isDone = ExprEndResult; + } - /* - * If function is strict, and there are any NULL arguments, skip - * calling the function and return NULL. - */ - if (fcache->func.fn_strict) + /* Which protocol does function want to use? */ + if (rsinfo.returnMode == SFRM_ValuePerCall) + { + if (*isDone != ExprEndResult) { - for (i = 0; i < fcinfo->nargs; i++) + /* + * Save the current argument values to re-use on the next call. + */ + if (*isDone == ExprMultipleResult) { - if (fcinfo->argnull[i]) + fcache->setArgsValid = true; + /* Register cleanup callback if we didn't already */ + if (!fcache->shutdown_reg) { - *isNull = true; - return (Datum) 0; + RegisterExprContextCallback(econtext, + ShutdownFuncExpr, + PointerGetDatum(fcache)); + fcache->shutdown_reg = true; } } } - - pgstat_init_function_usage(fcinfo, &fcusage); - - fcinfo->isnull = false; - result = FunctionCallInvoke(fcinfo); - *isNull = fcinfo->isnull; - - pgstat_end_function_usage(&fcusage, true); } + else if (rsinfo.returnMode == SFRM_Materialize) + { + /* check we're on the same page as the function author */ + if (rsinfo.isDone != ExprSingleResult) + ereport(ERROR, + (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED), + errmsg("table-function protocol for materialize mode was not followed"))); + if (rsinfo.setResult != NULL) + { + /* prepare to return values from the tuplestore */ + ExecPrepareTuplestoreResult(fcache, econtext, + rsinfo.setResult, + rsinfo.setDesc); + /* loop back to top to start returning from tuplestore */ + goto restart; + } + /* if setResult was left null, treat it as empty set */ + *isDone = ExprEndResult; + *isNull = true; + result = (Datum) 0; + } + else + ereport(ERROR, + (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED), + errmsg("unrecognized table-function returnMode: %d", + (int) rsinfo.returnMode))); return result; } @@ -1984,14 +1813,13 @@ ExecMakeFunctionResult(FuncExprState *fcache, /* * ExecMakeFunctionResultNoSets * - * Simplified version of ExecMakeFunctionResult that can only handle - * non-set cases. Hand-tuned for speed. + * Evaluate a function or operator node with a non-set-returning function. + * Assumes init_fcache() already done. Hand-tuned for speed. */ static Datum ExecMakeFunctionResultNoSets(FuncExprState *fcache, ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) + bool *isNull) { ListCell *arg; Datum result; @@ -2002,9 +1830,6 @@ ExecMakeFunctionResultNoSets(FuncExprState *fcache, /* Guard against stack overflow due to overly complex expressions */ check_stack_depth(); - if (isDone) - *isDone = ExprSingleResult; - /* inlined, simplified version of ExecEvalFuncArgs */ fcinfo = &fcache->fcinfo_data; i = 0; @@ -2014,8 +1839,7 @@ ExecMakeFunctionResultNoSets(FuncExprState *fcache, fcinfo->arg[i] = ExecEvalExpr(argstate, econtext, - &fcinfo->argnull[i], - NULL); + &fcinfo->argnull[i]); i++; } @@ -2112,10 +1936,9 @@ ExecMakeTableFunctionResult(ExprState *funcexpr, IsA(funcexpr->expr, FuncExpr)) { FuncExprState *fcache = (FuncExprState *) funcexpr; - ExprDoneCond argDone; /* - * This path is similar to ExecMakeFunctionResult. + * This path is similar to ExecMakeFunctionResultSet. */ direct_function_call = true; @@ -2127,7 +1950,7 @@ ExecMakeTableFunctionResult(ExprState *funcexpr, FuncExpr *func = (FuncExpr *) fcache->xprstate.expr; init_fcache(func->funcid, func->inputcollid, fcache, - econtext->ecxt_per_query_memory, false); + econtext->ecxt_per_query_memory, true, false); } returnsSet = fcache->func.fn_retset; InitFunctionCallInfoData(fcinfo, &(fcache->func), @@ -2147,15 +1970,9 @@ ExecMakeTableFunctionResult(ExprState *funcexpr, */ MemoryContextReset(argContext); oldcontext = MemoryContextSwitchTo(argContext); - argDone = ExecEvalFuncArgs(&fcinfo, fcache->args, econtext); + ExecEvalFuncArgs(&fcinfo, fcache->args, econtext); MemoryContextSwitchTo(oldcontext); - /* We don't allow sets in the arguments of the table function */ - if (argDone != ExprSingleResult) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("set-valued function called in context that cannot accept a set"))); - /* * If function is strict, and there are any NULL arguments, skip * calling the function and act like it returned NULL (or an empty @@ -2215,8 +2032,8 @@ ExecMakeTableFunctionResult(ExprState *funcexpr, } else { - result = ExecEvalExpr(funcexpr, econtext, - &fcinfo.isnull, &rsinfo.isDone); + result = ExecEvalExpr(funcexpr, econtext, &fcinfo.isnull); + rsinfo.isDone = ExprSingleResult; } /* Which protocol does function want to use? */ @@ -2410,32 +2227,18 @@ ExecMakeTableFunctionResult(ExprState *funcexpr, static Datum ExecEvalFunc(FuncExprState *fcache, ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) + bool *isNull) { /* This is called only the first time through */ FuncExpr *func = (FuncExpr *) fcache->xprstate.expr; /* Initialize function lookup info */ init_fcache(func->funcid, func->inputcollid, fcache, - econtext->ecxt_per_query_memory, true); + econtext->ecxt_per_query_memory, false, false); - /* - * We need to invoke ExecMakeFunctionResult if either the function itself - * or any of its input expressions can return a set. Otherwise, invoke - * ExecMakeFunctionResultNoSets. In either case, change the evalfunc - * pointer to go directly there on subsequent uses. - */ - if (fcache->func.fn_retset || expression_returns_set((Node *) func->args)) - { - fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResult; - return ExecMakeFunctionResult(fcache, econtext, isNull, isDone); - } - else - { - fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResultNoSets; - return ExecMakeFunctionResultNoSets(fcache, econtext, isNull, isDone); - } + /* Change the evalfunc pointer to save a few cycles in additional calls */ + fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResultNoSets; + return ExecMakeFunctionResultNoSets(fcache, econtext, isNull); } /* ---------------------------------------------------------------- @@ -2445,32 +2248,18 @@ ExecEvalFunc(FuncExprState *fcache, static Datum ExecEvalOper(FuncExprState *fcache, ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) + bool *isNull) { /* This is called only the first time through */ OpExpr *op = (OpExpr *) fcache->xprstate.expr; /* Initialize function lookup info */ init_fcache(op->opfuncid, op->inputcollid, fcache, - econtext->ecxt_per_query_memory, true); + econtext->ecxt_per_query_memory, false, false); - /* - * We need to invoke ExecMakeFunctionResult if either the function itself - * or any of its input expressions can return a set. Otherwise, invoke - * ExecMakeFunctionResultNoSets. In either case, change the evalfunc - * pointer to go directly there on subsequent uses. - */ - if (fcache->func.fn_retset || expression_returns_set((Node *) op->args)) - { - fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResult; - return ExecMakeFunctionResult(fcache, econtext, isNull, isDone); - } - else - { - fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResultNoSets; - return ExecMakeFunctionResultNoSets(fcache, econtext, isNull, isDone); - } + /* Change the evalfunc pointer to save a few cycles in additional calls */ + fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResultNoSets; + return ExecMakeFunctionResultNoSets(fcache, econtext, isNull); } /* ---------------------------------------------------------------- @@ -2487,17 +2276,13 @@ ExecEvalOper(FuncExprState *fcache, static Datum ExecEvalDistinct(FuncExprState *fcache, ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) + bool *isNull) { Datum result; FunctionCallInfo fcinfo; - ExprDoneCond argDone; - /* Set default values for result flags: non-null, not a set result */ + /* Set non-null as default */ *isNull = false; - if (isDone) - *isDone = ExprSingleResult; /* * Initialize function cache if first time through @@ -2507,19 +2292,14 @@ ExecEvalDistinct(FuncExprState *fcache, DistinctExpr *op = (DistinctExpr *) fcache->xprstate.expr; init_fcache(op->opfuncid, op->inputcollid, fcache, - econtext->ecxt_per_query_memory, true); - Assert(!fcache->func.fn_retset); + econtext->ecxt_per_query_memory, false, false); } /* * Evaluate arguments */ fcinfo = &fcache->fcinfo_data; - argDone = ExecEvalFuncArgs(fcinfo, fcache->args, econtext); - if (argDone != ExprSingleResult) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("IS DISTINCT FROM does not support set arguments"))); + ExecEvalFuncArgs(fcinfo, fcache->args, econtext); Assert(fcinfo->nargs == 2); if (fcinfo->argnull[0] && fcinfo->argnull[1]) @@ -2555,7 +2335,7 @@ ExecEvalDistinct(FuncExprState *fcache, static Datum ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) sstate->fxprstate.xprstate.expr; bool useOr = opexpr->useOr; @@ -2564,7 +2344,6 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate, Datum result; bool resultnull; FunctionCallInfo fcinfo; - ExprDoneCond argDone; int i; int16 typlen; bool typbyval; @@ -2573,10 +2352,8 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate, bits8 *bitmap; int bitmask; - /* Set default values for result flags: non-null, not a set result */ + /* Set non-null as default */ *isNull = false; - if (isDone) - *isDone = ExprSingleResult; /* * Initialize function cache if first time through @@ -2584,19 +2361,14 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate, if (sstate->fxprstate.func.fn_oid == InvalidOid) { init_fcache(opexpr->opfuncid, opexpr->inputcollid, &sstate->fxprstate, - econtext->ecxt_per_query_memory, true); - Assert(!sstate->fxprstate.func.fn_retset); + econtext->ecxt_per_query_memory, false, false); } /* * Evaluate arguments */ fcinfo = &sstate->fxprstate.fcinfo_data; - argDone = ExecEvalFuncArgs(fcinfo, sstate->fxprstate.args, econtext); - if (argDone != ExprSingleResult) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("op ANY/ALL (array) does not support set arguments"))); + ExecEvalFuncArgs(fcinfo, sstate->fxprstate.args, econtext); Assert(fcinfo->nargs == 2); /* @@ -2742,15 +2514,12 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate, */ static Datum ExecEvalNot(BoolExprState *notclause, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { ExprState *clause = linitial(notclause->args); Datum expr_value; - if (isDone) - *isDone = ExprSingleResult; - - expr_value = ExecEvalExpr(clause, econtext, isNull, NULL); + expr_value = ExecEvalExpr(clause, econtext, isNull); /* * if the expression evaluates to null, then we just cascade the null back @@ -2772,15 +2541,12 @@ ExecEvalNot(BoolExprState *notclause, ExprContext *econtext, */ static Datum ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { List *clauses = orExpr->args; ListCell *clause; bool AnyNull; - if (isDone) - *isDone = ExprSingleResult; - AnyNull = false; /* @@ -2801,7 +2567,7 @@ ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext, ExprState *clausestate = (ExprState *) lfirst(clause); Datum clause_value; - clause_value = ExecEvalExpr(clausestate, econtext, isNull, NULL); + clause_value = ExecEvalExpr(clausestate, econtext, isNull); /* * if we have a non-null true result, then return it. @@ -2823,15 +2589,12 @@ ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext, */ static Datum ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { List *clauses = andExpr->args; ListCell *clause; bool AnyNull; - if (isDone) - *isDone = ExprSingleResult; - AnyNull = false; /* @@ -2848,7 +2611,7 @@ ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext, ExprState *clausestate = (ExprState *) lfirst(clause); Datum clause_value; - clause_value = ExecEvalExpr(clausestate, econtext, isNull, NULL); + clause_value = ExecEvalExpr(clausestate, econtext, isNull); /* * if we have a non-null false result, then return it. @@ -2874,7 +2637,7 @@ ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext, static Datum ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) cstate->xprstate.expr; HeapTuple result; @@ -2882,7 +2645,7 @@ ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate, HeapTupleHeader tuple; HeapTupleData tmptup; - tupDatum = ExecEvalExpr(cstate->arg, econtext, isNull, isDone); + tupDatum = ExecEvalExpr(cstate->arg, econtext, isNull); /* this test covers the isDone exception too: */ if (*isNull) @@ -2958,16 +2721,13 @@ ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate, */ static Datum ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { List *clauses = caseExpr->args; ListCell *clause; Datum save_datum; bool save_isNull; - if (isDone) - *isDone = ExprSingleResult; - /* * If there's a test expression, we have to evaluate it and save the value * where the CaseTestExpr placeholders can find it. We must save and @@ -2987,12 +2747,17 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, if (caseExpr->arg) { + Datum arg_value; bool arg_isNull; - econtext->caseValue_datum = ExecEvalExpr(caseExpr->arg, - econtext, - &arg_isNull, - NULL); + arg_value = ExecEvalExpr(caseExpr->arg, + econtext, + &arg_isNull); + /* Since caseValue_datum may be read multiple times, force to R/O */ + econtext->caseValue_datum = + MakeExpandedObjectReadOnly(arg_value, + arg_isNull, + caseExpr->argtyplen); econtext->caseValue_isNull = arg_isNull; } @@ -3009,8 +2774,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, clause_value = ExecEvalExpr(wclause->expr, econtext, - &clause_isNull, - NULL); + &clause_isNull); /* * if we have a true test, then we return the result, since the case @@ -3023,8 +2787,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, econtext->caseValue_isNull = save_isNull; return ExecEvalExpr(wclause->result, econtext, - isNull, - isDone); + isNull); } } @@ -3035,8 +2798,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, { return ExecEvalExpr(caseExpr->defresult, econtext, - isNull, - isDone); + isNull); } *isNull = true; @@ -3051,10 +2813,8 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, static Datum ExecEvalCaseTestExpr(ExprState *exprstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { - if (isDone) - *isDone = ExprSingleResult; *isNull = econtext->caseValue_isNull; return econtext->caseValue_datum; } @@ -3071,17 +2831,13 @@ ExecEvalCaseTestExpr(ExprState *exprstate, static Datum ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate, ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) + bool *isNull) { int result = 0; int attnum = 0; Bitmapset *grouped_cols = gstate->aggstate->grouped_cols; ListCell *lc; - if (isDone) - *isDone = ExprSingleResult; - *isNull = false; foreach(lc, (gstate->clauses)) @@ -3103,7 +2859,7 @@ ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate, */ static Datum ExecEvalArray(ArrayExprState *astate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { ArrayExpr *arrayExpr = (ArrayExpr *) astate->xprstate.expr; ArrayType *result; @@ -3113,10 +2869,8 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext, int dims[MAXDIM]; int lbs[MAXDIM]; - /* Set default values for result flags: non-null, not a set result */ + /* Set non-null as default */ *isNull = false; - if (isDone) - *isDone = ExprSingleResult; if (!arrayExpr->multidims) { @@ -3141,7 +2895,7 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext, { ExprState *e = (ExprState *) lfirst(element); - dvalues[i] = ExecEvalExpr(e, econtext, &dnulls[i], NULL); + dvalues[i] = ExecEvalExpr(e, econtext, &dnulls[i]); i++; } @@ -3191,7 +2945,7 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext, ArrayType *array; int this_ndims; - arraydatum = ExecEvalExpr(e, econtext, &eisnull, NULL); + arraydatum = ExecEvalExpr(e, econtext, &eisnull); /* temporarily ignore null subarrays */ if (eisnull) { @@ -3330,7 +3084,7 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext, static Datum ExecEvalRow(RowExprState *rstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { HeapTuple tuple; Datum *values; @@ -3339,10 +3093,8 @@ ExecEvalRow(RowExprState *rstate, ListCell *arg; int i; - /* Set default values for result flags: non-null, not a set result */ + /* Set non-null as default */ *isNull = false; - if (isDone) - *isDone = ExprSingleResult; /* Allocate workspace */ natts = rstate->tupdesc->natts; @@ -3358,7 +3110,7 @@ ExecEvalRow(RowExprState *rstate, { ExprState *e = (ExprState *) lfirst(arg); - values[i] = ExecEvalExpr(e, econtext, &isnull[i], NULL); + values[i] = ExecEvalExpr(e, econtext, &isnull[i]); i++; } @@ -3377,7 +3129,7 @@ ExecEvalRow(RowExprState *rstate, static Datum ExecEvalRowCompare(RowCompareExprState *rstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { bool result; RowCompareType rctype = ((RowCompareExpr *) rstate->xprstate.expr)->rctype; @@ -3386,8 +3138,6 @@ ExecEvalRowCompare(RowCompareExprState *rstate, ListCell *r; int i; - if (isDone) - *isDone = ExprSingleResult; *isNull = true; /* until we get a result */ i = 0; @@ -3401,9 +3151,9 @@ ExecEvalRowCompare(RowCompareExprState *rstate, rstate->collations[i], NULL, NULL); locfcinfo.arg[0] = ExecEvalExpr(le, econtext, - &locfcinfo.argnull[0], NULL); + &locfcinfo.argnull[0]); locfcinfo.arg[1] = ExecEvalExpr(re, econtext, - &locfcinfo.argnull[1], NULL); + &locfcinfo.argnull[1]); if (rstate->funcs[i].fn_strict && (locfcinfo.argnull[0] || locfcinfo.argnull[1])) return (Datum) 0; /* force NULL result */ @@ -3447,20 +3197,17 @@ ExecEvalRowCompare(RowCompareExprState *rstate, */ static Datum ExecEvalCoalesce(CoalesceExprState *coalesceExpr, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { ListCell *arg; - if (isDone) - *isDone = ExprSingleResult; - /* Simply loop through until something NOT NULL is found */ foreach(arg, coalesceExpr->args) { ExprState *e = (ExprState *) lfirst(arg); Datum value; - value = ExecEvalExpr(e, econtext, isNull, NULL); + value = ExecEvalExpr(e, econtext, isNull); if (!*isNull) return value; } @@ -3476,7 +3223,7 @@ ExecEvalCoalesce(CoalesceExprState *coalesceExpr, ExprContext *econtext, */ static Datum ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { Datum result = (Datum) 0; MinMaxExpr *minmax = (MinMaxExpr *) minmaxExpr->xprstate.expr; @@ -3485,8 +3232,6 @@ ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext, FunctionCallInfoData locfcinfo; ListCell *arg; - if (isDone) - *isDone = ExprSingleResult; *isNull = true; /* until we get a result */ InitFunctionCallInfoData(locfcinfo, &minmaxExpr->cfunc, 2, @@ -3501,7 +3246,7 @@ ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext, bool valueIsNull; int32 cmpresult; - value = ExecEvalExpr(e, econtext, &valueIsNull, NULL); + value = ExecEvalExpr(e, econtext, &valueIsNull); if (valueIsNull) continue; /* ignore NULL inputs */ @@ -3530,13 +3275,80 @@ ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext, return result; } +/* ---------------------------------------------------------------- + * ExecEvalSQLValueFunction + * ---------------------------------------------------------------- + */ +static Datum +ExecEvalSQLValueFunction(ExprState *svfExpr, + ExprContext *econtext, + bool *isNull) +{ + Datum result = (Datum) 0; + SQLValueFunction *svf = (SQLValueFunction *) svfExpr->expr; + FunctionCallInfoData fcinfo; + + *isNull = false; + + /* + * Note: current_schema() can return NULL. current_user() etc currently + * cannot, but might as well code those cases the same way for safety. + */ + switch (svf->op) + { + case SVFOP_CURRENT_DATE: + result = DateADTGetDatum(GetSQLCurrentDate()); + break; + case SVFOP_CURRENT_TIME: + case SVFOP_CURRENT_TIME_N: + result = TimeTzADTPGetDatum(GetSQLCurrentTime(svf->typmod)); + break; + case SVFOP_CURRENT_TIMESTAMP: + case SVFOP_CURRENT_TIMESTAMP_N: + result = TimestampTzGetDatum(GetSQLCurrentTimestamp(svf->typmod)); + break; + case SVFOP_LOCALTIME: + case SVFOP_LOCALTIME_N: + result = TimeADTGetDatum(GetSQLLocalTime(svf->typmod)); + break; + case SVFOP_LOCALTIMESTAMP: + case SVFOP_LOCALTIMESTAMP_N: + result = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod)); + break; + case SVFOP_CURRENT_ROLE: + case SVFOP_CURRENT_USER: + case SVFOP_USER: + InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL); + result = current_user(&fcinfo); + *isNull = fcinfo.isnull; + break; + case SVFOP_SESSION_USER: + InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL); + result = session_user(&fcinfo); + *isNull = fcinfo.isnull; + break; + case SVFOP_CURRENT_CATALOG: + InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL); + result = current_database(&fcinfo); + *isNull = fcinfo.isnull; + break; + case SVFOP_CURRENT_SCHEMA: + InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL); + result = current_schema(&fcinfo); + *isNull = fcinfo.isnull; + break; + } + + return result; +} + /* ---------------------------------------------------------------- * ExecEvalXml * ---------------------------------------------------------------- */ static Datum ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { XmlExpr *xexpr = (XmlExpr *) xmlExpr->xprstate.expr; Datum value; @@ -3544,8 +3356,6 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, ListCell *arg; ListCell *narg; - if (isDone) - *isDone = ExprSingleResult; *isNull = true; /* until we get a result */ switch (xexpr->op) @@ -3558,7 +3368,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, { ExprState *e = (ExprState *) lfirst(arg); - value = ExecEvalExpr(e, econtext, &isnull, NULL); + value = ExecEvalExpr(e, econtext, &isnull); if (!isnull) values = lappend(values, DatumGetPointer(value)); } @@ -3583,7 +3393,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, ExprState *e = (ExprState *) lfirst(arg); char *argname = strVal(lfirst(narg)); - value = ExecEvalExpr(e, econtext, &isnull, NULL); + value = ExecEvalExpr(e, econtext, &isnull); if (!isnull) { appendStringInfo(&buf, "<%s>%s", @@ -3626,13 +3436,13 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, Assert(list_length(xmlExpr->args) == 2); e = (ExprState *) linitial(xmlExpr->args); - value = ExecEvalExpr(e, econtext, &isnull, NULL); + value = ExecEvalExpr(e, econtext, &isnull); if (isnull) return (Datum) 0; data = DatumGetTextP(value); e = (ExprState *) lsecond(xmlExpr->args); - value = ExecEvalExpr(e, econtext, &isnull, NULL); + value = ExecEvalExpr(e, econtext, &isnull); if (isnull) /* probably can't happen */ return (Datum) 0; preserve_whitespace = DatumGetBool(value); @@ -3656,7 +3466,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, if (xmlExpr->args) { e = (ExprState *) linitial(xmlExpr->args); - value = ExecEvalExpr(e, econtext, &isnull, NULL); + value = ExecEvalExpr(e, econtext, &isnull); if (isnull) arg = NULL; else @@ -3683,20 +3493,20 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, Assert(list_length(xmlExpr->args) == 3); e = (ExprState *) linitial(xmlExpr->args); - value = ExecEvalExpr(e, econtext, &isnull, NULL); + value = ExecEvalExpr(e, econtext, &isnull); if (isnull) return (Datum) 0; data = DatumGetXmlP(value); e = (ExprState *) lsecond(xmlExpr->args); - value = ExecEvalExpr(e, econtext, &isnull, NULL); + value = ExecEvalExpr(e, econtext, &isnull); if (isnull) version = NULL; else version = DatumGetTextP(value); e = (ExprState *) lthird(xmlExpr->args); - value = ExecEvalExpr(e, econtext, &isnull, NULL); + value = ExecEvalExpr(e, econtext, &isnull); standalone = DatumGetInt32(value); *isNull = false; @@ -3715,7 +3525,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, Assert(list_length(xmlExpr->args) == 1); e = (ExprState *) linitial(xmlExpr->args); - value = ExecEvalExpr(e, econtext, &isnull, NULL); + value = ExecEvalExpr(e, econtext, &isnull); if (isnull) return (Datum) 0; @@ -3733,7 +3543,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, Assert(list_length(xmlExpr->args) == 1); e = (ExprState *) linitial(xmlExpr->args); - value = ExecEvalExpr(e, econtext, &isnull, NULL); + value = ExecEvalExpr(e, econtext, &isnull); if (isnull) return (Datum) 0; else @@ -3760,14 +3570,10 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, static Datum ExecEvalNullIf(FuncExprState *nullIfExpr, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { Datum result; FunctionCallInfo fcinfo; - ExprDoneCond argDone; - - if (isDone) - *isDone = ExprSingleResult; /* * Initialize function cache if first time through @@ -3777,19 +3583,14 @@ ExecEvalNullIf(FuncExprState *nullIfExpr, NullIfExpr *op = (NullIfExpr *) nullIfExpr->xprstate.expr; init_fcache(op->opfuncid, op->inputcollid, nullIfExpr, - econtext->ecxt_per_query_memory, true); - Assert(!nullIfExpr->func.fn_retset); + econtext->ecxt_per_query_memory, false, false); } /* * Evaluate arguments */ fcinfo = &nullIfExpr->fcinfo_data; - argDone = ExecEvalFuncArgs(fcinfo, nullIfExpr->args, econtext); - if (argDone != ExprSingleResult) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("NULLIF does not support set arguments"))); + ExecEvalFuncArgs(fcinfo, nullIfExpr->args, econtext); Assert(fcinfo->nargs == 2); /* if either argument is NULL they can't be equal */ @@ -3819,16 +3620,12 @@ ExecEvalNullIf(FuncExprState *nullIfExpr, static Datum ExecEvalNullTest(NullTestState *nstate, ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) + bool *isNull) { NullTest *ntest = (NullTest *) nstate->xprstate.expr; Datum result; - result = ExecEvalExpr(nstate->arg, econtext, isNull, isDone); - - if (isDone && *isDone == ExprEndResult) - return result; /* nothing to check */ + result = ExecEvalExpr(nstate->arg, econtext, isNull); if (ntest->argisrow && !(*isNull)) { @@ -3928,16 +3725,12 @@ ExecEvalNullTest(NullTestState *nstate, static Datum ExecEvalBooleanTest(GenericExprState *bstate, ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) + bool *isNull) { BooleanTest *btest = (BooleanTest *) bstate->xprstate.expr; Datum result; - result = ExecEvalExpr(bstate->arg, econtext, isNull, isDone); - - if (isDone && *isDone == ExprEndResult) - return result; /* nothing to check */ + result = ExecEvalExpr(bstate->arg, econtext, isNull); switch (btest->booltesttype) { @@ -4013,16 +3806,13 @@ ExecEvalBooleanTest(GenericExprState *bstate, */ static Datum ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { CoerceToDomain *ctest = (CoerceToDomain *) cstate->xprstate.expr; Datum result; ListCell *l; - result = ExecEvalExpr(cstate->arg, econtext, isNull, isDone); - - if (isDone && *isDone == ExprEndResult) - return result; /* nothing to check */ + result = ExecEvalExpr(cstate->arg, econtext, isNull); /* Make sure we have up-to-date constraints */ UpdateDomainConstraintRef(cstate->constraint_ref); @@ -4053,15 +3843,22 @@ ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext, * nodes. We must save and restore prior setting of * econtext's domainValue fields, in case this node is * itself within a check expression for another domain. + * + * Also, if we are working with a read-write expanded + * datum, be sure that what we pass to CHECK expressions + * is a read-only pointer; else called functions might + * modify or even delete the expanded object. */ save_datum = econtext->domainValue_datum; save_isNull = econtext->domainValue_isNull; - econtext->domainValue_datum = result; + econtext->domainValue_datum = + MakeExpandedObjectReadOnly(result, *isNull, + cstate->constraint_ref->tcache->typlen); econtext->domainValue_isNull = *isNull; - conResult = ExecEvalExpr(con->check_expr, - econtext, &conIsNull, NULL); + conResult = ExecEvalExpr(con->check_expr, econtext, + &conIsNull); if (!conIsNull && !DatumGetBool(conResult)) @@ -4096,10 +3893,8 @@ ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext, static Datum ExecEvalCoerceToDomainValue(ExprState *exprstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { - if (isDone) - *isDone = ExprSingleResult; *isNull = econtext->domainValue_isNull; return econtext->domainValue_datum; } @@ -4113,8 +3908,7 @@ ExecEvalCoerceToDomainValue(ExprState *exprstate, static Datum ExecEvalFieldSelect(FieldSelectState *fstate, ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) + bool *isNull) { FieldSelect *fselect = (FieldSelect *) fstate->xprstate.expr; AttrNumber fieldnum = fselect->fieldnum; @@ -4127,9 +3921,8 @@ ExecEvalFieldSelect(FieldSelectState *fstate, Form_pg_attribute attr; HeapTupleData tmptup; - tupDatum = ExecEvalExpr(fstate->arg, econtext, isNull, isDone); + tupDatum = ExecEvalExpr(fstate->arg, econtext, isNull); - /* this test covers the isDone exception too: */ if (*isNull) return tupDatum; @@ -4192,8 +3985,7 @@ ExecEvalFieldSelect(FieldSelectState *fstate, static Datum ExecEvalFieldStore(FieldStoreState *fstate, ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) + bool *isNull) { FieldStore *fstore = (FieldStore *) fstate->xprstate.expr; HeapTuple tuple; @@ -4206,10 +3998,7 @@ ExecEvalFieldStore(FieldStoreState *fstate, ListCell *l1, *l2; - tupDatum = ExecEvalExpr(fstate->arg, econtext, isNull, isDone); - - if (isDone && *isDone == ExprEndResult) - return tupDatum; + tupDatum = ExecEvalExpr(fstate->arg, econtext, isNull); /* Lookup tupdesc if first time through or after rescan */ tupDesc = get_cached_rowtype(fstore->resulttype, -1, @@ -4269,8 +4058,7 @@ ExecEvalFieldStore(FieldStoreState *fstate, values[fieldnum - 1] = ExecEvalExpr(newval, econtext, - &isnull[fieldnum - 1], - NULL); + &isnull[fieldnum - 1]); } econtext->caseValue_datum = save_datum; @@ -4293,9 +4081,9 @@ ExecEvalFieldStore(FieldStoreState *fstate, static Datum ExecEvalRelabelType(GenericExprState *exprstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { - return ExecEvalExpr(exprstate->arg, econtext, isNull, isDone); + return ExecEvalExpr(exprstate->arg, econtext, isNull); } /* ---------------------------------------------------------------- @@ -4307,16 +4095,13 @@ ExecEvalRelabelType(GenericExprState *exprstate, static Datum ExecEvalCoerceViaIO(CoerceViaIOState *iostate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { Datum result; Datum inputval; char *string; - inputval = ExecEvalExpr(iostate->arg, econtext, isNull, isDone); - - if (isDone && *isDone == ExprEndResult) - return inputval; /* nothing to do */ + inputval = ExecEvalExpr(iostate->arg, econtext, isNull); if (*isNull) string = NULL; /* output functions are not called on nulls */ @@ -4341,16 +4126,14 @@ ExecEvalCoerceViaIO(CoerceViaIOState *iostate, static Datum ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) astate->xprstate.expr; Datum result; FunctionCallInfoData locfcinfo; - result = ExecEvalExpr(astate->arg, econtext, isNull, isDone); + result = ExecEvalExpr(astate->arg, econtext, isNull); - if (isDone && *isDone == ExprEndResult) - return result; /* nothing to do */ if (*isNull) return result; /* nothing to do */ @@ -4418,7 +4201,7 @@ ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate, */ static Datum ExecEvalCurrentOfExpr(ExprState *exprstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) + bool *isNull) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -4435,14 +4218,13 @@ ExecEvalCurrentOfExpr(ExprState *exprstate, ExprContext *econtext, Datum ExecEvalExprSwitchContext(ExprState *expression, ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) + bool *isNull) { Datum retDatum; MemoryContext oldContext; oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); - retDatum = ExecEvalExpr(expression, econtext, isNull, isDone); + retDatum = ExecEvalExpr(expression, econtext, isNull); MemoryContextSwitchTo(oldContext); return retDatum; } @@ -4507,16 +4289,16 @@ ExecInitExpr(Expr *node, PlanState *parent) } else { - state = (ExprState *) makeNode(ExprState); + state = makeNode(ExprState); state->evalfunc = ExecEvalScalarVar; } break; case T_Const: - state = (ExprState *) makeNode(ExprState); + state = makeNode(ExprState); state->evalfunc = ExecEvalConst; break; case T_Param: - state = (ExprState *) makeNode(ExprState); + state = makeNode(ExprState); switch (((Param *) node)->paramkind) { case PARAM_EXEC: @@ -4532,11 +4314,11 @@ ExecInitExpr(Expr *node, PlanState *parent) } break; case T_CoerceToDomainValue: - state = (ExprState *) makeNode(ExprState); + state = makeNode(ExprState); state->evalfunc = ExecEvalCoerceToDomainValue; break; case T_CaseTestExpr: - state = (ExprState *) makeNode(ExprState); + state = makeNode(ExprState); state->evalfunc = ExecEvalCaseTestExpr; break; case T_Aggref: @@ -4652,6 +4434,7 @@ ExecInitExpr(Expr *node, PlanState *parent) fstate->args = (List *) ExecInitExpr((Expr *) funcexpr->args, parent); fstate->func.fn_oid = InvalidOid; /* not initialized */ + fstate->funcReturnsSet = funcexpr->funcretset; state = (ExprState *) fstate; } break; @@ -4664,6 +4447,7 @@ ExecInitExpr(Expr *node, PlanState *parent) fstate->args = (List *) ExecInitExpr((Expr *) opexpr->args, parent); fstate->func.fn_oid = InvalidOid; /* not initialized */ + fstate->funcReturnsSet = opexpr->opretset; state = (ExprState *) fstate; } break; @@ -4676,6 +4460,7 @@ ExecInitExpr(Expr *node, PlanState *parent) fstate->args = (List *) ExecInitExpr((Expr *) distinctexpr->args, parent); fstate->func.fn_oid = InvalidOid; /* not initialized */ + fstate->funcReturnsSet = false; /* not supported */ state = (ExprState *) fstate; } break; @@ -4688,6 +4473,7 @@ ExecInitExpr(Expr *node, PlanState *parent) fstate->args = (List *) ExecInitExpr((Expr *) nullifexpr->args, parent); fstate->func.fn_oid = InvalidOid; /* not initialized */ + fstate->funcReturnsSet = false; /* not supported */ state = (ExprState *) fstate; } break; @@ -4700,6 +4486,7 @@ ExecInitExpr(Expr *node, PlanState *parent) sstate->fxprstate.args = (List *) ExecInitExpr((Expr *) opexpr->args, parent); sstate->fxprstate.func.fn_oid = InvalidOid; /* not initialized */ + sstate->fxprstate.funcReturnsSet = false; /* not supported */ sstate->element_type = InvalidOid; /* ditto */ state = (ExprState *) sstate; } @@ -4865,6 +4652,8 @@ ExecInitExpr(Expr *node, PlanState *parent) } cstate->args = outlist; cstate->defresult = ExecInitExpr(caseexpr->defresult, parent); + if (caseexpr->arg) + cstate->argtyplen = get_typlen(exprType((Node *) caseexpr->arg)); state = (ExprState *) cstate; } break; @@ -5086,6 +4875,10 @@ ExecInitExpr(Expr *node, PlanState *parent) state = (ExprState *) mstate; } break; + case T_SQLValueFunction: + state = makeNode(ExprState); + state->evalfunc = ExecEvalSQLValueFunction; + break; case T_XmlExpr: { XmlExpr *xexpr = (XmlExpr *) node; @@ -5157,7 +4950,7 @@ ExecInitExpr(Expr *node, PlanState *parent) } break; case T_CurrentOfExpr: - state = (ExprState *) makeNode(ExprState); + state = makeNode(ExprState); state->evalfunc = ExecEvalCurrentOfExpr; break; case T_TargetEntry: @@ -5298,7 +5091,7 @@ ExecQual(List *qual, ExprContext *econtext, bool resultForNull) Datum expr_value; bool isNull; - expr_value = ExecEvalExpr(clause, econtext, &isNull, NULL); + expr_value = ExecEvalExpr(clause, econtext, &isNull); if (isNull) { @@ -5356,17 +5149,11 @@ ExecCleanTargetListLength(List *targetlist) /* * ExecTargetList * Evaluates a targetlist with respect to the given - * expression context. Returns TRUE if we were able to create - * a result, FALSE if we have exhausted a set-valued expression. + * expression context. * - * Results are stored into the passed values and isnull arrays. - * The caller must provide an itemIsDone array that persists across calls. + * tupdesc must describe the rowtype of the expected result. * - * As with ExecEvalExpr, the caller should pass isDone = NULL if not - * prepared to deal with sets of result tuples. Otherwise, a return - * of *isDone = ExprMultipleResult signifies a set element, and a return - * of *isDone = ExprEndResult signifies end of the set of tuple. - * We assume that *isDone has been initialized to ExprSingleResult by caller. + * Results are stored into the passed values and isnull arrays. * * Since fields of the result tuple might be multiply referenced in higher * plan nodes, we have to force any read/write expanded values to read-only @@ -5375,19 +5162,16 @@ ExecCleanTargetListLength(List *targetlist) * actually-multiply-referenced Vars and insert an expression node that * would do that only where really required. */ -static bool +static void ExecTargetList(List *targetlist, TupleDesc tupdesc, ExprContext *econtext, Datum *values, - bool *isnull, - ExprDoneCond *itemIsDone, - ExprDoneCond *isDone) + bool *isnull) { Form_pg_attribute *att = tupdesc->attrs; MemoryContext oldContext; ListCell *tl; - bool haveDoneSets; /* * Run in short-lived per-tuple context while computing expressions. @@ -5397,8 +5181,6 @@ ExecTargetList(List *targetlist, /* * evaluate all the expressions in the target list */ - haveDoneSets = false; /* any exhausted set exprs in tlist? */ - foreach(tl, targetlist) { GenericExprState *gstate = (GenericExprState *) lfirst(tl); @@ -5407,117 +5189,14 @@ ExecTargetList(List *targetlist, values[resind] = ExecEvalExpr(gstate->arg, econtext, - &isnull[resind], - &itemIsDone[resind]); + &isnull[resind]); values[resind] = MakeExpandedObjectReadOnly(values[resind], isnull[resind], att[resind]->attlen); - - if (itemIsDone[resind] != ExprSingleResult) - { - /* We have a set-valued expression in the tlist */ - if (isDone == NULL) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("set-valued function called in context that cannot accept a set"))); - if (itemIsDone[resind] == ExprMultipleResult) - { - /* we have undone sets in the tlist, set flag */ - *isDone = ExprMultipleResult; - } - else - { - /* we have done sets in the tlist, set flag for that */ - haveDoneSets = true; - } - } - } - - if (haveDoneSets) - { - /* - * note: can't get here unless we verified isDone != NULL - */ - if (*isDone == ExprSingleResult) - { - /* - * all sets are done, so report that tlist expansion is complete. - */ - *isDone = ExprEndResult; - MemoryContextSwitchTo(oldContext); - return false; - } - else - { - /* - * We have some done and some undone sets. Restart the done ones - * so that we can deliver a tuple (if possible). - */ - foreach(tl, targetlist) - { - GenericExprState *gstate = (GenericExprState *) lfirst(tl); - TargetEntry *tle = (TargetEntry *) gstate->xprstate.expr; - AttrNumber resind = tle->resno - 1; - - if (itemIsDone[resind] == ExprEndResult) - { - values[resind] = ExecEvalExpr(gstate->arg, - econtext, - &isnull[resind], - &itemIsDone[resind]); - - values[resind] = MakeExpandedObjectReadOnly(values[resind], - isnull[resind], - att[resind]->attlen); - - if (itemIsDone[resind] == ExprEndResult) - { - /* - * Oh dear, this item is returning an empty set. Guess - * we can't make a tuple after all. - */ - *isDone = ExprEndResult; - break; - } - } - } - - /* - * If we cannot make a tuple because some sets are empty, we still - * have to cycle the nonempty sets to completion, else resources - * will not be released from subplans etc. - * - * XXX is that still necessary? - */ - if (*isDone == ExprEndResult) - { - foreach(tl, targetlist) - { - GenericExprState *gstate = (GenericExprState *) lfirst(tl); - TargetEntry *tle = (TargetEntry *) gstate->xprstate.expr; - AttrNumber resind = tle->resno - 1; - - while (itemIsDone[resind] == ExprMultipleResult) - { - values[resind] = ExecEvalExpr(gstate->arg, - econtext, - &isnull[resind], - &itemIsDone[resind]); - /* no need for MakeExpandedObjectReadOnly */ - } - } - - MemoryContextSwitchTo(oldContext); - return false; - } - } } - /* Report success */ MemoryContextSwitchTo(oldContext); - - return true; } /* @@ -5534,7 +5213,7 @@ ExecTargetList(List *targetlist, * result slot. */ TupleTableSlot * -ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone) +ExecProject(ProjectionInfo *projInfo) { TupleTableSlot *slot; ExprContext *econtext; @@ -5551,14 +5230,9 @@ ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone) slot = projInfo->pi_slot; econtext = projInfo->pi_exprContext; - /* Assume single result row until proven otherwise */ - if (isDone) - *isDone = ExprSingleResult; - /* * Clear any former contents of the result slot. This makes it safe for - * us to use the slot's Datum/isnull arrays as workspace. (Also, we can - * return the slot as-is if we decide no rows can be projected.) + * us to use the slot's Datum/isnull arrays as workspace. */ ExecClearTuple(slot); @@ -5622,26 +5296,19 @@ ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone) } /* - * If there are any generic expressions, evaluate them. It's possible - * that there are set-returning functions in such expressions; if so and - * we have reached the end of the set, we return the result slot, which we - * already marked empty. + * If there are any generic expressions, evaluate them. */ if (projInfo->pi_targetlist) { - if (!ExecTargetList(projInfo->pi_targetlist, - slot->tts_tupleDescriptor, - econtext, - slot->tts_values, - slot->tts_isnull, - projInfo->pi_itemIsDone, - isDone)) - return slot; /* no more result rows, return empty slot */ + ExecTargetList(projInfo->pi_targetlist, + slot->tts_tupleDescriptor, + econtext, + slot->tts_values, + slot->tts_isnull); } /* - * Successfully formed a result row. Mark the result slot as containing a - * valid virtual tuple. + * Mark the result slot as containing a valid virtual tuple. */ return ExecStoreVirtualTuple(slot); } diff --git a/src/backend/executor/execReplication.c b/src/backend/executor/execReplication.c new file mode 100644 index 0000000000..a18ae512db --- /dev/null +++ b/src/backend/executor/execReplication.c @@ -0,0 +1,553 @@ +/*------------------------------------------------------------------------- + * + * execReplication.c + * miscellaneous executor routines for logical replication + * + * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/executor/execReplication.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "access/relscan.h" +#include "access/transam.h" +#include "access/xact.h" +#include "commands/trigger.h" +#include "executor/executor.h" +#include "nodes/nodeFuncs.h" +#include "parser/parse_relation.h" +#include "parser/parsetree.h" +#include "storage/bufmgr.h" +#include "storage/lmgr.h" +#include "utils/datum.h" +#include "utils/lsyscache.h" +#include "utils/memutils.h" +#include "utils/rel.h" +#include "utils/snapmgr.h" +#include "utils/syscache.h" +#include "utils/tqual.h" + + +/* + * Setup a ScanKey for a search in the relation 'rel' for a tuple 'key' that + * is setup to match 'rel' (*NOT* idxrel!). + * + * Returns whether any column contains NULLs. + * + * This is not generic routine, it expects the idxrel to be replication + * identity of a rel and meet all limitations associated with that. + */ +static bool +build_replindex_scan_key(ScanKey skey, Relation rel, Relation idxrel, + TupleTableSlot *searchslot) +{ + int attoff; + bool isnull; + Datum indclassDatum; + oidvector *opclass; + int2vector *indkey = &idxrel->rd_index->indkey; + bool hasnulls = false; + + Assert(RelationGetReplicaIndex(rel) == RelationGetRelid(idxrel)); + + indclassDatum = SysCacheGetAttr(INDEXRELID, idxrel->rd_indextuple, + Anum_pg_index_indclass, &isnull); + Assert(!isnull); + opclass = (oidvector *) DatumGetPointer(indclassDatum); + + /* Build scankey for every attribute in the index. */ + for (attoff = 0; attoff < RelationGetNumberOfAttributes(idxrel); attoff++) + { + Oid operator; + Oid opfamily; + RegProcedure regop; + int pkattno = attoff + 1; + int mainattno = indkey->values[attoff]; + Oid optype = get_opclass_input_type(opclass->values[attoff]); + + /* + * Load the operator info. We need this to get the equality operator + * function for the scan key. + */ + opfamily = get_opclass_family(opclass->values[attoff]); + + operator = get_opfamily_member(opfamily, optype, + optype, + BTEqualStrategyNumber); + + if (!OidIsValid(operator)) + elog(ERROR, "could not find member %d(%u,%u) of opfamily %u", + BTEqualStrategyNumber, optype, optype, opfamily); + + regop = get_opcode(operator); + + /* Initialize the scankey. */ + ScanKeyInit(&skey[attoff], + pkattno, + BTEqualStrategyNumber, + regop, + searchslot->tts_values[mainattno - 1]); + + /* Check for null value. */ + if (searchslot->tts_isnull[mainattno - 1]) + { + hasnulls = true; + skey[attoff].sk_flags |= SK_ISNULL; + } + } + + return hasnulls; +} + +/* + * Search the relation 'rel' for tuple using the index. + * + * If a matching tuple is found, lock it with lockmode, fill the slot with its + * contents, and return true. Return false otherwise. + */ +bool +RelationFindReplTupleByIndex(Relation rel, Oid idxoid, + LockTupleMode lockmode, + TupleTableSlot *searchslot, + TupleTableSlot *outslot) +{ + HeapTuple scantuple; + ScanKeyData skey[INDEX_MAX_KEYS]; + IndexScanDesc scan; + SnapshotData snap; + TransactionId xwait; + Relation idxrel; + bool found; + + /* Open the index.*/ + idxrel = index_open(idxoid, RowExclusiveLock); + + /* Start an index scan. */ + InitDirtySnapshot(snap); + scan = index_beginscan(rel, idxrel, &snap, + RelationGetNumberOfAttributes(idxrel), + 0); + + /* Build scan key. */ + build_replindex_scan_key(skey, rel, idxrel, searchslot); + +retry: + found = false; + + index_rescan(scan, skey, RelationGetNumberOfAttributes(idxrel), NULL, 0); + + /* Try to find the tuple */ + if ((scantuple = index_getnext(scan, ForwardScanDirection)) != NULL) + { + found = true; + ExecStoreTuple(scantuple, outslot, InvalidBuffer, false); + ExecMaterializeSlot(outslot); + + xwait = TransactionIdIsValid(snap.xmin) ? + snap.xmin : snap.xmax; + + /* + * If the tuple is locked, wait for locking transaction to finish + * and retry. + */ + if (TransactionIdIsValid(xwait)) + { + XactLockTableWait(xwait, NULL, NULL, XLTW_None); + goto retry; + } + } + + /* Found tuple, try to lock it in the lockmode. */ + if (found) + { + Buffer buf; + HeapUpdateFailureData hufd; + HTSU_Result res; + HeapTupleData locktup; + + ItemPointerCopy(&outslot->tts_tuple->t_self, &locktup.t_self); + + PushActiveSnapshot(GetLatestSnapshot()); + + res = heap_lock_tuple(rel, &locktup, GetCurrentCommandId(false), + lockmode, + false /* wait */, + false /* don't follow updates */, + &buf, &hufd); + /* the tuple slot already has the buffer pinned */ + ReleaseBuffer(buf); + + PopActiveSnapshot(); + + switch (res) + { + case HeapTupleMayBeUpdated: + break; + case HeapTupleUpdated: + /* XXX: Improve handling here */ + ereport(LOG, + (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), + errmsg("concurrent update, retrying"))); + goto retry; + case HeapTupleInvisible: + elog(ERROR, "attempted to lock invisible tuple"); + default: + elog(ERROR, "unexpected heap_lock_tuple status: %u", res); + break; + } + } + + index_endscan(scan); + + /* Don't release lock until commit. */ + index_close(idxrel, NoLock); + + return found; +} + +/* + * Compare the tuple and slot and check if they have equal values. + * + * We use binary datum comparison which might return false negatives but + * that's the best we can do here as there may be multiple notions of + * equality for the data types and table columns don't specify which one + * to use. + */ +static bool +tuple_equals_slot(TupleDesc desc, HeapTuple tup, TupleTableSlot *slot) +{ + Datum values[MaxTupleAttributeNumber]; + bool isnull[MaxTupleAttributeNumber]; + int attrnum; + Form_pg_attribute att; + + heap_deform_tuple(tup, desc, values, isnull); + + /* Check equality of the attributes. */ + for (attrnum = 0; attrnum < desc->natts; attrnum++) + { + /* + * If one value is NULL and other is not, then they are certainly not + * equal + */ + if (isnull[attrnum] != slot->tts_isnull[attrnum]) + return false; + + /* + * If both are NULL, they can be considered equal. + */ + if (isnull[attrnum]) + continue; + + att = desc->attrs[attrnum]; + if (!datumIsEqual(values[attrnum], slot->tts_values[attrnum], + att->attbyval, att->attlen)) + return false; + } + + return true; +} + +/* + * Search the relation 'rel' for tuple using the sequential scan. + * + * If a matching tuple is found, lock it with lockmode, fill the slot with its + * contents, and return true. Return false otherwise. + * + * Note that this stops on the first matching tuple. + * + * This can obviously be quite slow on tables that have more than few rows. + */ +bool +RelationFindReplTupleSeq(Relation rel, LockTupleMode lockmode, + TupleTableSlot *searchslot, TupleTableSlot *outslot) +{ + HeapTuple scantuple; + HeapScanDesc scan; + SnapshotData snap; + TransactionId xwait; + bool found; + TupleDesc desc = RelationGetDescr(rel); + + Assert(equalTupleDescs(desc, outslot->tts_tupleDescriptor)); + + /* Start an index scan. */ + InitDirtySnapshot(snap); + scan = heap_beginscan(rel, &snap, 0, NULL); + +retry: + found = false; + + heap_rescan(scan, NULL); + + /* Try to find the tuple */ + while ((scantuple = heap_getnext(scan, ForwardScanDirection)) != NULL) + { + if (!tuple_equals_slot(desc, scantuple, searchslot)) + continue; + + found = true; + ExecStoreTuple(scantuple, outslot, InvalidBuffer, false); + ExecMaterializeSlot(outslot); + + xwait = TransactionIdIsValid(snap.xmin) ? + snap.xmin : snap.xmax; + + /* + * If the tuple is locked, wait for locking transaction to finish + * and retry. + */ + if (TransactionIdIsValid(xwait)) + { + XactLockTableWait(xwait, NULL, NULL, XLTW_None); + goto retry; + } + } + + /* Found tuple, try to lock it in the lockmode. */ + if (found) + { + Buffer buf; + HeapUpdateFailureData hufd; + HTSU_Result res; + HeapTupleData locktup; + + ItemPointerCopy(&outslot->tts_tuple->t_self, &locktup.t_self); + + PushActiveSnapshot(GetLatestSnapshot()); + + res = heap_lock_tuple(rel, &locktup, GetCurrentCommandId(false), + lockmode, + false /* wait */, + false /* don't follow updates */, + &buf, &hufd); + /* the tuple slot already has the buffer pinned */ + ReleaseBuffer(buf); + + PopActiveSnapshot(); + + switch (res) + { + case HeapTupleMayBeUpdated: + break; + case HeapTupleUpdated: + /* XXX: Improve handling here */ + ereport(LOG, + (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), + errmsg("concurrent update, retrying"))); + goto retry; + case HeapTupleInvisible: + elog(ERROR, "attempted to lock invisible tuple"); + default: + elog(ERROR, "unexpected heap_lock_tuple status: %u", res); + break; + } + } + + heap_endscan(scan); + + return found; +} + +/* + * Insert tuple represented in the slot to the relation, update the indexes, + * and execute any constraints and per-row triggers. + * + * Caller is responsible for opening the indexes. + */ +void +ExecSimpleRelationInsert(EState *estate, TupleTableSlot *slot) +{ + bool skip_tuple = false; + HeapTuple tuple; + ResultRelInfo *resultRelInfo = estate->es_result_relation_info; + Relation rel = resultRelInfo->ri_RelationDesc; + + /* For now we support only tables. */ + Assert(rel->rd_rel->relkind == RELKIND_RELATION); + + CheckCmdReplicaIdentity(rel, CMD_INSERT); + + /* BEFORE ROW INSERT Triggers */ + if (resultRelInfo->ri_TrigDesc && + resultRelInfo->ri_TrigDesc->trig_insert_before_row) + { + slot = ExecBRInsertTriggers(estate, resultRelInfo, slot); + + if (slot == NULL) /* "do nothing" */ + skip_tuple = true; + } + + if (!skip_tuple) + { + List *recheckIndexes = NIL; + + /* Check the constraints of the tuple */ + if (rel->rd_att->constr) + ExecConstraints(resultRelInfo, slot, slot, estate); + + /* Store the slot into tuple that we can insett. */ + tuple = ExecMaterializeSlot(slot); + + /* OK, store the tuple and create index entries for it */ + simple_heap_insert(rel, tuple); + + if (resultRelInfo->ri_NumIndices > 0) + recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self), + estate, false, NULL, + NIL); + + /* AFTER ROW INSERT Triggers */ + ExecARInsertTriggers(estate, resultRelInfo, tuple, + recheckIndexes); + + list_free(recheckIndexes); + } +} + +/* + * Find the searchslot tuple and update it with data in the slot, + * update the indexes, and execute any constraints and per-row triggers. + * + * Caller is responsible for opening the indexes. + */ +void +ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate, + TupleTableSlot *searchslot, TupleTableSlot *slot) +{ + bool skip_tuple = false; + HeapTuple tuple; + ResultRelInfo *resultRelInfo = estate->es_result_relation_info; + Relation rel = resultRelInfo->ri_RelationDesc; + + /* For now we support only tables. */ + Assert(rel->rd_rel->relkind == RELKIND_RELATION); + + CheckCmdReplicaIdentity(rel, CMD_UPDATE); + + /* BEFORE ROW INSERT Triggers */ + if (resultRelInfo->ri_TrigDesc && + resultRelInfo->ri_TrigDesc->trig_update_before_row) + { + slot = ExecBRUpdateTriggers(estate, epqstate, resultRelInfo, + &searchslot->tts_tuple->t_self, + NULL, slot); + + if (slot == NULL) /* "do nothing" */ + skip_tuple = true; + } + + if (!skip_tuple) + { + List *recheckIndexes = NIL; + + /* Check the constraints of the tuple */ + if (rel->rd_att->constr) + ExecConstraints(resultRelInfo, slot, slot, estate); + + /* Store the slot into tuple that we can write. */ + tuple = ExecMaterializeSlot(slot); + + /* OK, update the tuple and index entries for it */ + simple_heap_update(rel, &searchslot->tts_tuple->t_self, + slot->tts_tuple); + + if (resultRelInfo->ri_NumIndices > 0 && + !HeapTupleIsHeapOnly(slot->tts_tuple)) + recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self), + estate, false, NULL, + NIL); + + /* AFTER ROW UPDATE Triggers */ + ExecARUpdateTriggers(estate, resultRelInfo, + &searchslot->tts_tuple->t_self, + NULL, tuple, recheckIndexes); + + list_free(recheckIndexes); + } +} + +/* + * Find the searchslot tuple and delete it, and execute any constraints + * and per-row triggers. + * + * Caller is responsible for opening the indexes. + */ +void +ExecSimpleRelationDelete(EState *estate, EPQState *epqstate, + TupleTableSlot *searchslot) +{ + bool skip_tuple = false; + ResultRelInfo *resultRelInfo = estate->es_result_relation_info; + Relation rel = resultRelInfo->ri_RelationDesc; + + /* For now we support only tables. */ + Assert(rel->rd_rel->relkind == RELKIND_RELATION); + + CheckCmdReplicaIdentity(rel, CMD_DELETE); + + /* BEFORE ROW INSERT Triggers */ + if (resultRelInfo->ri_TrigDesc && + resultRelInfo->ri_TrigDesc->trig_update_before_row) + { + skip_tuple = !ExecBRDeleteTriggers(estate, epqstate, resultRelInfo, + &searchslot->tts_tuple->t_self, + NULL); + } + + if (!skip_tuple) + { + List *recheckIndexes = NIL; + + /* OK, delete the tuple */ + simple_heap_delete(rel, &searchslot->tts_tuple->t_self); + + /* AFTER ROW DELETE Triggers */ + ExecARDeleteTriggers(estate, resultRelInfo, + &searchslot->tts_tuple->t_self, NULL); + + list_free(recheckIndexes); + } +} + +/* + * Check if command can be executed with current replica identity. + */ +void +CheckCmdReplicaIdentity(Relation rel, CmdType cmd) +{ + PublicationActions *pubactions; + + /* We only need to do checks for UPDATE and DELETE. */ + if (cmd != CMD_UPDATE && cmd != CMD_DELETE) + return; + + /* If relation has replica identity we are always good. */ + if (rel->rd_rel->relreplident == REPLICA_IDENTITY_FULL || + OidIsValid(RelationGetReplicaIndex(rel))) + return; + + /* + * This is either UPDATE OR DELETE and there is no replica identity. + * + * Check if the table publishes UPDATES or DELETES. + */ + pubactions = GetRelationPublicationActions(rel); + if (cmd == CMD_UPDATE && pubactions->pubupdate) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("cannot update table \"%s\" because it does not have replica identity and publishes updates", + RelationGetRelationName(rel)), + errhint("To enable updating the table, set REPLICA IDENTITY using ALTER TABLE."))); + else if (cmd == CMD_DELETE && pubactions->pubdelete) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("cannot delete from table \"%s\" because it does not have replica identity and publishes deletes", + RelationGetRelationName(rel)), + errhint("To enable deleting from the table, set REPLICA IDENTITY using ALTER TABLE."))); +} diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c index fb0013dc53..65196795d7 100644 --- a/src/backend/executor/execScan.c +++ b/src/backend/executor/execScan.c @@ -7,7 +7,7 @@ * stuff - checking the qualification and projecting the tuple * appropriately. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -125,8 +125,6 @@ ExecScan(ScanState *node, ExprContext *econtext; List *qual; ProjectionInfo *projInfo; - ExprDoneCond isDone; - TupleTableSlot *resultSlot; /* * Fetch data from node @@ -145,25 +143,9 @@ ExecScan(ScanState *node, return ExecScanFetch(node, accessMtd, recheckMtd); } - /* - * Check to see if we're still projecting out tuples from a previous scan - * tuple (because there is a function-returning-set in the projection - * expressions). If so, try to project another one. - */ - if (node->ps.ps_TupFromTlist) - { - Assert(projInfo); /* can't get here if not projecting */ - resultSlot = ExecProject(projInfo, &isDone); - if (isDone == ExprMultipleResult) - return resultSlot; - /* Done with that source tuple... */ - node->ps.ps_TupFromTlist = false; - } - /* * Reset per-tuple memory context to free any expression evaluation - * storage allocated in the previous tuple cycle. Note this can't happen - * until we're done projecting out tuples from a scan tuple. + * storage allocated in the previous tuple cycle. */ ResetExprContext(econtext); @@ -214,15 +196,9 @@ ExecScan(ScanState *node, { /* * Form a projection tuple, store it in the result tuple slot - * and return it --- unless we find we can project no tuples - * from this scan tuple, in which case continue scan. + * and return it. */ - resultSlot = ExecProject(projInfo, &isDone); - if (isDone != ExprEndResult) - { - node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult); - return resultSlot; - } + return ExecProject(projInfo); } else { @@ -352,9 +328,6 @@ ExecScanReScan(ScanState *node) { EState *estate = node->ps.state; - /* Stop projecting any tuples from SRFs in the targetlist */ - node->ps.ps_TupFromTlist = false; - /* Rescan EvalPlanQual tuple if we're inside an EvalPlanQual recheck */ if (estate->es_epqScanDone != NULL) { diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index 533050dc85..cbb2bcb568 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -12,7 +12,7 @@ * This information is needed by routines manipulating tuples * (getattribute, formtuple, etc.). * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index e937cf8e7e..e49feff6c0 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -3,7 +3,7 @@ * execUtils.c * miscellaneous executor utility routines * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -80,9 +80,7 @@ CreateExecutorState(void) */ qcontext = AllocSetContextCreate(CurrentMemoryContext, "ExecutorState", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* * Make the EState node within the per-query context. This way, we don't @@ -229,9 +227,7 @@ CreateExprContext(EState *estate) econtext->ecxt_per_tuple_memory = AllocSetContextCreate(estate->es_query_cxt, "ExprContext", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); econtext->ecxt_param_exec_vals = estate->es_param_exec_vals; econtext->ecxt_param_list_info = estate->es_param_list_info; @@ -300,9 +296,7 @@ CreateStandaloneExprContext(void) econtext->ecxt_per_tuple_memory = AllocSetContextCreate(CurrentMemoryContext, "ExprContext", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); econtext->ecxt_param_exec_vals = NULL; econtext->ecxt_param_list_info = NULL; @@ -592,12 +586,6 @@ ExecBuildProjectionInfo(List *targetList, projInfo->pi_numSimpleVars = numSimpleVars; projInfo->pi_directMap = directMap; - if (exprlist == NIL) - projInfo->pi_itemIsDone = NULL; /* not needed */ - else - projInfo->pi_itemIsDone = (ExprDoneCond *) - palloc(len * sizeof(ExprDoneCond)); - return projInfo; } diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index e02fba5232..e4a1da4dbb 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -3,7 +3,7 @@ * functions.c * Execution of SQL-language functions * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -66,7 +66,7 @@ typedef struct execution_state ExecStatus status; bool setsResult; /* true if this query produces func's result */ bool lazyEval; /* true if should fetch one row at a time */ - Node *stmt; /* PlannedStmt or utility statement */ + PlannedStmt *stmt; /* plan for this query */ QueryDesc *qd; /* null unless status == RUN */ } execution_state; @@ -487,36 +487,56 @@ init_execution_state(List *queryTree_list, foreach(lc2, qtlist) { Query *queryTree = (Query *) lfirst(lc2); - Node *stmt; + PlannedStmt *stmt; execution_state *newes; Assert(IsA(queryTree, Query)); /* Plan the query if needed */ if (queryTree->commandType == CMD_UTILITY) - stmt = queryTree->utilityStmt; + { + /* Utility commands require no planning. */ + stmt = makeNode(PlannedStmt); + stmt->commandType = CMD_UTILITY; + stmt->canSetTag = queryTree->canSetTag; + stmt->utilityStmt = queryTree->utilityStmt; + stmt->stmt_location = queryTree->stmt_location; + stmt->stmt_len = queryTree->stmt_len; + } else - stmt = (Node *) pg_plan_query(queryTree, + stmt = pg_plan_query(queryTree, fcache->readonly_func ? CURSOR_OPT_PARALLEL_OK : 0, - NULL); + NULL); - /* Precheck all commands for validity in a function */ - if (IsA(stmt, TransactionStmt)) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - /* translator: %s is a SQL statement name */ - errmsg("%s is not allowed in a SQL function", - CreateCommandTag(stmt)))); + /* + * Precheck all commands for validity in a function. This should + * generally match the restrictions spi.c applies. + */ + if (stmt->commandType == CMD_UTILITY) + { + if (IsA(stmt->utilityStmt, CopyStmt) && + ((CopyStmt *) stmt->utilityStmt)->filename == NULL) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot COPY to/from client in a SQL function"))); + + if (IsA(stmt->utilityStmt, TransactionStmt)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + /* translator: %s is a SQL statement name */ + errmsg("%s is not allowed in a SQL function", + CreateCommandTag(stmt->utilityStmt)))); + } if (fcache->readonly_func && !CommandIsReadOnly(stmt)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), /* translator: %s is a SQL statement name */ errmsg("%s is not allowed in a non-volatile function", - CreateCommandTag(stmt)))); + CreateCommandTag((Node *) stmt)))); if (IsInParallelMode() && !CommandIsReadOnly(stmt)) - PreventCommandIfParallelMode(CreateCommandTag(stmt)); + PreventCommandIfParallelMode(CreateCommandTag((Node *) stmt)); /* OK, build the execution_state for this query */ newes = (execution_state *) palloc(sizeof(execution_state)); @@ -560,15 +580,9 @@ init_execution_state(List *queryTree_list, { lasttages->setsResult = true; if (lazyEvalOK && - IsA(lasttages->stmt, PlannedStmt)) - { - PlannedStmt *ps = (PlannedStmt *) lasttages->stmt; - - if (ps->commandType == CMD_SELECT && - ps->utilityStmt == NULL && - !ps->hasModifyingCTE) - fcache->lazyEval = lasttages->lazyEval = true; - } + lasttages->stmt->commandType == CMD_SELECT && + !lasttages->stmt->hasModifyingCTE) + fcache->lazyEval = lasttages->lazyEval = true; } return eslist; @@ -600,9 +614,7 @@ init_sql_fcache(FmgrInfo *finfo, Oid collation, bool lazyEvalOK) */ fcontext = AllocSetContextCreate(finfo->fn_mcxt, "SQL function data", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldcontext = MemoryContextSwitchTo(fcontext); @@ -697,7 +709,7 @@ init_sql_fcache(FmgrInfo *finfo, Oid collation, bool lazyEvalOK) flat_query_list = NIL; foreach(lc, raw_parsetree_list) { - Node *parsetree = (Node *) lfirst(lc); + RawStmt *parsetree = (RawStmt *) lfirst(lc); List *queryTree_sublist; queryTree_sublist = pg_analyze_and_rewrite_params(parsetree, @@ -794,22 +806,15 @@ postquel_start(execution_state *es, SQLFunctionCachePtr fcache) else dest = None_Receiver; - if (IsA(es->stmt, PlannedStmt)) - es->qd = CreateQueryDesc((PlannedStmt *) es->stmt, - fcache->src, - GetActiveSnapshot(), - InvalidSnapshot, - dest, - fcache->paramLI, 0); - else - es->qd = CreateUtilityQueryDesc(es->stmt, - fcache->src, - GetActiveSnapshot(), - dest, - fcache->paramLI); + es->qd = CreateQueryDesc(es->stmt, + fcache->src, + GetActiveSnapshot(), + InvalidSnapshot, + dest, + fcache->paramLI, 0); /* Utility commands don't need Executor. */ - if (es->qd->utilitystmt == NULL) + if (es->qd->operation != CMD_UTILITY) { /* * In lazyEval mode, do not let the executor set up an AfterTrigger @@ -837,12 +842,9 @@ postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache) { bool result; - if (es->qd->utilitystmt) + if (es->qd->operation == CMD_UTILITY) { - /* ProcessUtility needs the PlannedStmt for DECLARE CURSOR */ - ProcessUtility((es->qd->plannedstmt ? - (Node *) es->qd->plannedstmt : - es->qd->utilitystmt), + ProcessUtility(es->qd->plannedstmt, fcache->src, PROCESS_UTILITY_QUERY, es->qd->params, @@ -875,7 +877,7 @@ postquel_end(execution_state *es) es->status = F_EXEC_DONE; /* Utility commands don't need Executor. */ - if (es->qd->utilitystmt == NULL) + if (es->qd->operation != CMD_UTILITY) { ExecutorFinish(es->qd); ExecutorEnd(es->qd); @@ -1569,8 +1571,7 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList, * entities. */ if (parse && - parse->commandType == CMD_SELECT && - parse->utilityStmt == NULL) + parse->commandType == CMD_SELECT) { tlist_ptr = &parse->targetList; tlist = parse->targetList; diff --git a/src/backend/executor/instrument.c b/src/backend/executor/instrument.c index 2614bf451f..6ec96ec371 100644 --- a/src/backend/executor/instrument.c +++ b/src/backend/executor/instrument.c @@ -4,7 +4,7 @@ * functions for instrumentation of plan execution * * - * Copyright (c) 2001-2016, PostgreSQL Global Development Group + * Copyright (c) 2001-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/executor/instrument.c diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 1ec2515090..e4992134bd 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -91,10 +91,13 @@ * transition value or a previous function result, and in either case its * value need not be preserved. See int8inc() for an example. Notice that * advance_transition_function() is coded to avoid a data copy step when - * the previous transition value pointer is returned. Also, some - * transition functions want to store working state in addition to the - * nominal transition value; they can use the memory context returned by - * AggCheckCallContext() to do that. + * the previous transition value pointer is returned. It is also possible + * to avoid repeated data copying when the transition value is an expanded + * object: to do that, the transition function must take care to return + * an expanded object that is in a child context of the memory context + * returned by AggCheckCallContext(). Also, some transition functions want + * to store working state in addition to the nominal transition value; they + * can use the memory context returned by AggCheckCallContext() to do that. * * Note: AggCheckCallContext() is available as of PostgreSQL 9.0. The * AggState is available as context in earlier releases (back to 8.1), @@ -138,7 +141,7 @@ * * TODO: AGG_HASHED doesn't support multiple grouping sets yet. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -157,6 +160,7 @@ #include "executor/executor.h" #include "executor/nodeAgg.h" #include "miscadmin.h" +#include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" #include "optimizer/clauses.h" #include "optimizer/tlist.h" @@ -210,6 +214,9 @@ typedef struct AggStatePerTransData */ int numInputs; + /* offset of input columns in AggState->evalslot */ + int inputoff; + /* * Number of aggregated input columns to pass to the transfn. This * includes the ORDER BY columns for ordered-set aggs, but not for plain @@ -231,7 +238,6 @@ typedef struct AggStatePerTransData /* ExprStates of the FILTER and argument expressions. */ ExprState *aggfilter; /* state of FILTER expression, if any */ - List *args; /* states of aggregated-argument expressions */ List *aggdirectargs; /* states of direct-argument expressions */ /* @@ -288,19 +294,19 @@ typedef struct AggStatePerTransData transtypeByVal; /* - * Stuff for evaluation of inputs. We used to just use ExecEvalExpr, but - * with the addition of ORDER BY we now need at least a slot for passing - * data to the sort object, which requires a tupledesc, so we might as - * well go whole hog and use ExecProject too. + * Stuff for evaluation of aggregate inputs in cases where the aggregate + * requires sorted input. The arguments themselves will be evaluated via + * AggState->evalslot/evalproj for all aggregates at once, but we only + * want to sort the relevant columns for individual aggregates. */ - TupleDesc evaldesc; /* descriptor of input tuples */ - ProjectionInfo *evalproj; /* projection machinery */ + TupleDesc sortdesc; /* descriptor of input tuples */ /* * Slots for holding the evaluated input arguments. These are set up - * during ExecInitAgg() and then used for each input row. + * during ExecInitAgg() and then used for each input row requiring + * procesessing besides what's done in AggState->evalproj. */ - TupleTableSlot *evalslot; /* current input tuple */ + TupleTableSlot *sortslot; /* current input tuple */ TupleTableSlot *uniqslot; /* used for multi-column DISTINCT */ /* @@ -434,20 +440,6 @@ typedef struct AggStatePerPhaseData Sort *sortnode; /* Sort node for input ordering for phase */ } AggStatePerPhaseData; -/* - * To implement hashed aggregation, we need a hashtable that stores a - * representative tuple and an array of AggStatePerGroup structs for each - * distinct set of GROUP BY column values. We compute the hash key from - * the GROUP BY columns. - */ -typedef struct AggHashEntryData *AggHashEntry; - -typedef struct AggHashEntryData -{ - TupleHashEntryData shared; /* common header for hash table entries */ - /* per-aggregate transition status array */ - AggStatePerGroupData pergroup[FLEXIBLE_ARRAY_MEMBER]; -} AggHashEntryData; static void initialize_phase(AggState *aggstate, int newphase); static TupleTableSlot *fetch_input_tuple(AggState *aggstate); @@ -487,7 +479,7 @@ static TupleTableSlot *project_aggregates(AggState *aggstate); static Bitmapset *find_unaggregated_cols(AggState *aggstate); static bool find_unaggregated_cols_walker(Node *node, Bitmapset **colnos); static void build_hash_table(AggState *aggstate); -static AggHashEntry lookup_hash_entry(AggState *aggstate, +static TupleHashEntryData *lookup_hash_entry(AggState *aggstate, TupleTableSlot *inputslot); static TupleTableSlot *agg_retrieve_direct(AggState *aggstate); static void agg_fill_hash_table(AggState *aggstate); @@ -632,14 +624,14 @@ initialize_aggregate(AggState *aggstate, AggStatePerTrans pertrans, */ if (pertrans->numInputs == 1) pertrans->sortstates[aggstate->current_set] = - tuplesort_begin_datum(pertrans->evaldesc->attrs[0]->atttypid, + tuplesort_begin_datum(pertrans->sortdesc->attrs[0]->atttypid, pertrans->sortOperators[0], pertrans->sortCollations[0], pertrans->sortNullsFirst[0], work_mem, false); else pertrans->sortstates[aggstate->current_set] = - tuplesort_begin_heap(pertrans->evaldesc, + tuplesort_begin_heap(pertrans->sortdesc, pertrans->numSortCols, pertrans->sortColIdx, pertrans->sortOperators, @@ -805,8 +797,10 @@ advance_transition_function(AggState *aggstate, /* * If pass-by-ref datatype, must copy the new value into aggcontext and - * pfree the prior transValue. But if transfn returned a pointer to its - * first input, we don't need to do anything. + * free the prior transValue. But if transfn returned a pointer to its + * first input, we don't need to do anything. Also, if transfn returned a + * pointer to a R/W expanded object that is already a child of the + * aggcontext, assume we can adopt that value without copying it. */ if (!pertrans->transtypeByVal && DatumGetPointer(newVal) != DatumGetPointer(pergroupstate->transValue)) @@ -814,12 +808,25 @@ advance_transition_function(AggState *aggstate, if (!fcinfo->isnull) { MemoryContextSwitchTo(aggstate->aggcontexts[aggstate->current_set]->ecxt_per_tuple_memory); - newVal = datumCopy(newVal, - pertrans->transtypeByVal, - pertrans->transtypeLen); + if (DatumIsReadWriteExpandedObject(newVal, + false, + pertrans->transtypeLen) && + MemoryContextGetParent(DatumGetEOHP(newVal)->eoh_context) == CurrentMemoryContext) + /* do nothing */ ; + else + newVal = datumCopy(newVal, + pertrans->transtypeByVal, + pertrans->transtypeLen); } if (!pergroupstate->transValueIsNull) - pfree(DatumGetPointer(pergroupstate->transValue)); + { + if (DatumIsReadWriteExpandedObject(pergroupstate->transValue, + false, + pertrans->transtypeLen)) + DeleteExpandedObject(pergroupstate->transValue); + else + pfree(DatumGetPointer(pergroupstate->transValue)); + } } pergroupstate->transValue = newVal; @@ -843,6 +850,11 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup) int setno = 0; int numGroupingSets = Max(aggstate->phase->numsets, 1); int numTrans = aggstate->numtrans; + TupleTableSlot *slot = aggstate->evalslot; + + /* compute input for all aggregates */ + if (aggstate->evalproj) + aggstate->evalslot = ExecProject(aggstate->evalproj); for (transno = 0; transno < numTrans; transno++) { @@ -850,7 +862,7 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup) ExprState *filter = pertrans->aggfilter; int numTransInputs = pertrans->numTransInputs; int i; - TupleTableSlot *slot; + int inputoff = pertrans->inputoff; /* Skip anything FILTERed out */ if (filter) @@ -859,18 +871,15 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup) bool isnull; res = ExecEvalExprSwitchContext(filter, aggstate->tmpcontext, - &isnull, NULL); + &isnull); if (isnull || !DatumGetBool(res)) continue; } - /* Evaluate the current input expressions for this aggregate */ - slot = ExecProject(pertrans->evalproj, NULL); - if (pertrans->numSortCols > 0) { /* DISTINCT and/or ORDER BY case */ - Assert(slot->tts_nvalid == pertrans->numInputs); + Assert(slot->tts_nvalid >= (pertrans->numInputs + inputoff)); /* * If the transfn is strict, we want to check for nullity before @@ -883,7 +892,7 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup) { for (i = 0; i < numTransInputs; i++) { - if (slot->tts_isnull[i]) + if (slot->tts_isnull[i + inputoff]) break; } if (i < numTransInputs) @@ -895,10 +904,25 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup) /* OK, put the tuple into the tuplesort object */ if (pertrans->numInputs == 1) tuplesort_putdatum(pertrans->sortstates[setno], - slot->tts_values[0], - slot->tts_isnull[0]); + slot->tts_values[inputoff], + slot->tts_isnull[inputoff]); else - tuplesort_puttupleslot(pertrans->sortstates[setno], slot); + { + /* + * Copy slot contents, starting from inputoff, into sort + * slot. + */ + ExecClearTuple(pertrans->sortslot); + memcpy(pertrans->sortslot->tts_values, + &slot->tts_values[inputoff], + pertrans->numInputs * sizeof(Datum)); + memcpy(pertrans->sortslot->tts_isnull, + &slot->tts_isnull[inputoff], + pertrans->numInputs * sizeof(bool)); + pertrans->sortslot->tts_nvalid = pertrans->numInputs; + ExecStoreVirtualTuple(pertrans->sortslot); + tuplesort_puttupleslot(pertrans->sortstates[setno], pertrans->sortslot); + } } } else @@ -908,11 +932,12 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup) /* Load values into fcinfo */ /* Start from 1, since the 0th arg will be the transition value */ - Assert(slot->tts_nvalid >= numTransInputs); + Assert(slot->tts_nvalid >= (numTransInputs + inputoff)); + for (i = 0; i < numTransInputs; i++) { - fcinfo->arg[i + 1] = slot->tts_values[i]; - fcinfo->argnull[i + 1] = slot->tts_isnull[i]; + fcinfo->arg[i + 1] = slot->tts_values[i + inputoff]; + fcinfo->argnull[i + 1] = slot->tts_isnull[i + inputoff]; } for (setno = 0; setno < numGroupingSets; setno++) @@ -939,20 +964,22 @@ combine_aggregates(AggState *aggstate, AggStatePerGroup pergroup) { int transno; int numTrans = aggstate->numtrans; + TupleTableSlot *slot; /* combine not supported with grouping sets */ Assert(aggstate->phase->numsets == 0); + /* compute input for all aggregates */ + slot = ExecProject(aggstate->evalproj); + for (transno = 0; transno < numTrans; transno++) { AggStatePerTrans pertrans = &aggstate->pertrans[transno]; AggStatePerGroup pergroupstate = &pergroup[transno]; - TupleTableSlot *slot; FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo; + int inputoff = pertrans->inputoff; - /* Evaluate the current input expressions for this aggregate */ - slot = ExecProject(pertrans->evalproj, NULL); - Assert(slot->tts_nvalid >= 1); + Assert(slot->tts_nvalid > inputoff); /* * deserialfn_oid will be set if we must deserialize the input state @@ -961,18 +988,18 @@ combine_aggregates(AggState *aggstate, AggStatePerGroup pergroup) if (OidIsValid(pertrans->deserialfn_oid)) { /* Don't call a strict deserialization function with NULL input */ - if (pertrans->deserialfn.fn_strict && slot->tts_isnull[0]) + if (pertrans->deserialfn.fn_strict && slot->tts_isnull[inputoff]) { - fcinfo->arg[1] = slot->tts_values[0]; - fcinfo->argnull[1] = slot->tts_isnull[0]; + fcinfo->arg[1] = slot->tts_values[inputoff]; + fcinfo->argnull[1] = slot->tts_isnull[inputoff]; } else { FunctionCallInfo dsinfo = &pertrans->deserialfn_fcinfo; MemoryContext oldContext; - dsinfo->arg[0] = slot->tts_values[0]; - dsinfo->argnull[0] = slot->tts_isnull[0]; + dsinfo->arg[0] = slot->tts_values[inputoff]; + dsinfo->argnull[0] = slot->tts_isnull[inputoff]; /* Dummy second argument for type-safety reasons */ dsinfo->arg[1] = PointerGetDatum(NULL); dsinfo->argnull[1] = false; @@ -991,8 +1018,8 @@ combine_aggregates(AggState *aggstate, AggStatePerGroup pergroup) } else { - fcinfo->arg[1] = slot->tts_values[0]; - fcinfo->argnull[1] = slot->tts_isnull[0]; + fcinfo->arg[1] = slot->tts_values[inputoff]; + fcinfo->argnull[1] = slot->tts_isnull[inputoff]; } advance_combine_function(aggstate, pertrans, pergroupstate); @@ -1067,8 +1094,11 @@ advance_combine_function(AggState *aggstate, /* * If pass-by-ref datatype, must copy the new value into aggcontext and - * pfree the prior transValue. But if the combine function returned a - * pointer to its first input, we don't need to do anything. + * free the prior transValue. But if the combine function returned a + * pointer to its first input, we don't need to do anything. Also, if the + * combine function returned a pointer to a R/W expanded object that is + * already a child of the aggcontext, assume we can adopt that value + * without copying it. */ if (!pertrans->transtypeByVal && DatumGetPointer(newVal) != DatumGetPointer(pergroupstate->transValue)) @@ -1076,12 +1106,25 @@ advance_combine_function(AggState *aggstate, if (!fcinfo->isnull) { MemoryContextSwitchTo(aggstate->aggcontexts[aggstate->current_set]->ecxt_per_tuple_memory); - newVal = datumCopy(newVal, - pertrans->transtypeByVal, - pertrans->transtypeLen); + if (DatumIsReadWriteExpandedObject(newVal, + false, + pertrans->transtypeLen) && + MemoryContextGetParent(DatumGetEOHP(newVal)->eoh_context) == CurrentMemoryContext) + /* do nothing */ ; + else + newVal = datumCopy(newVal, + pertrans->transtypeByVal, + pertrans->transtypeLen); } if (!pergroupstate->transValueIsNull) - pfree(DatumGetPointer(pergroupstate->transValue)); + { + if (DatumIsReadWriteExpandedObject(pergroupstate->transValue, + false, + pertrans->transtypeLen)) + DeleteExpandedObject(pergroupstate->transValue); + else + pfree(DatumGetPointer(pergroupstate->transValue)); + } } pergroupstate->transValue = newVal; @@ -1213,7 +1256,7 @@ process_ordered_aggregate_multi(AggState *aggstate, { MemoryContext workcontext = aggstate->tmpcontext->ecxt_per_tuple_memory; FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo; - TupleTableSlot *slot1 = pertrans->evalslot; + TupleTableSlot *slot1 = pertrans->sortslot; TupleTableSlot *slot2 = pertrans->uniqslot; int numTransInputs = pertrans->numTransInputs; int numDistinctCols = pertrans->numDistinctCols; @@ -1325,8 +1368,7 @@ finalize_aggregate(AggState *aggstate, fcinfo.arg[i] = ExecEvalExpr(expr, aggstate->ss.ps.ps_ExprContext, - &fcinfo.argnull[i], - NULL); + &fcinfo.argnull[i]); anynull |= fcinfo.argnull[i]; i++; } @@ -1347,7 +1389,9 @@ finalize_aggregate(AggState *aggstate, (void *) aggstate, NULL); /* Fill in the transition state value */ - fcinfo.arg[0] = pergroupstate->transValue; + fcinfo.arg[0] = MakeExpandedObjectReadOnly(pergroupstate->transValue, + pergroupstate->transValueIsNull, + pertrans->transtypeLen); fcinfo.argnull[0] = pergroupstate->transValueIsNull; anynull |= pergroupstate->transValueIsNull; @@ -1374,6 +1418,7 @@ finalize_aggregate(AggState *aggstate, } else { + /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */ *resultVal = pergroupstate->transValue; *resultIsNull = pergroupstate->transValueIsNull; } @@ -1424,7 +1469,9 @@ finalize_partialaggregate(AggState *aggstate, { FunctionCallInfo fcinfo = &pertrans->serialfn_fcinfo; - fcinfo->arg[0] = pergroupstate->transValue; + fcinfo->arg[0] = MakeExpandedObjectReadOnly(pergroupstate->transValue, + pergroupstate->transValueIsNull, + pertrans->transtypeLen); fcinfo->argnull[0] = pergroupstate->transValueIsNull; *resultVal = FunctionCallInvoke(fcinfo); @@ -1433,6 +1480,7 @@ finalize_partialaggregate(AggState *aggstate, } else { + /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */ *resultVal = pergroupstate->transValue; *resultIsNull = pergroupstate->transValueIsNull; } @@ -1525,16 +1573,19 @@ finalize_aggregates(AggState *aggstate, Datum *aggvalues = econtext->ecxt_aggvalues; bool *aggnulls = econtext->ecxt_aggnulls; int aggno; + int transno; Assert(currentSet == 0 || ((Agg *) aggstate->ss.ps.plan)->aggstrategy != AGG_HASHED); aggstate->current_set = currentSet; - for (aggno = 0; aggno < aggstate->numaggs; aggno++) + /* + * If there were any DISTINCT and/or ORDER BY aggregates, sort their + * inputs and run the transition functions. + */ + for (transno = 0; transno < aggstate->numtrans; transno++) { - AggStatePerAgg peragg = &peraggs[aggno]; - int transno = peragg->transno; AggStatePerTrans pertrans = &aggstate->pertrans[transno]; AggStatePerGroup pergroupstate; @@ -1553,6 +1604,18 @@ finalize_aggregates(AggState *aggstate, pertrans, pergroupstate); } + } + + /* + * Run the final functions. + */ + for (aggno = 0; aggno < aggstate->numaggs; aggno++) + { + AggStatePerAgg peragg = &peraggs[aggno]; + int transno = peragg->transno; + AggStatePerGroup pergroupstate; + + pergroupstate = &pergroup[transno + (currentSet * (aggstate->numtrans))]; if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit)) finalize_partialaggregate(aggstate, peragg, pergroupstate, @@ -1566,7 +1629,7 @@ finalize_aggregates(AggState *aggstate, /* * Project the result of a group (whose aggs have already been calculated by * finalize_aggregates). Returns the result slot, or NULL if no row is - * projected (suppressed by qual or by an empty SRF). + * projected (suppressed by qual). */ static TupleTableSlot * project_aggregates(AggState *aggstate) @@ -1579,20 +1642,10 @@ project_aggregates(AggState *aggstate) if (ExecQual(aggstate->ss.ps.qual, econtext, false)) { /* - * Form and return or store a projection tuple using the aggregate - * results and the representative input tuple. + * Form and return projection tuple using the aggregate results and + * the representative input tuple. */ - ExprDoneCond isDone; - TupleTableSlot *result; - - result = ExecProject(aggstate->ss.ps.ps_ProjInfo, &isDone); - - if (isDone != ExprEndResult) - { - aggstate->ss.ps.ps_TupFromTlist = - (isDone == ExprMultipleResult); - return result; - } + return ExecProject(aggstate->ss.ps.ps_ProjInfo); } else InstrCountFiltered1(aggstate, 1); @@ -1646,6 +1699,12 @@ find_unaggregated_cols_walker(Node *node, Bitmapset **colnos) /* * Initialize the hash table to empty. * + * To implement hashed aggregation, we need a hashtable that stores a + * representative tuple and an array of AggStatePerGroup structs for each + * distinct set of GROUP BY column values. We compute the hash key from the + * GROUP BY columns. The per-group data is allocated in lookup_hash_entry(), + * for each entry. + * * The hash table always lives in the aggcontext memory context. */ static void @@ -1653,48 +1712,43 @@ build_hash_table(AggState *aggstate) { Agg *node = (Agg *) aggstate->ss.ps.plan; MemoryContext tmpmem = aggstate->tmpcontext->ecxt_per_tuple_memory; - Size entrysize; + Size additionalsize; Assert(node->aggstrategy == AGG_HASHED); Assert(node->numGroups > 0); - entrysize = offsetof(AggHashEntryData, pergroup) + - aggstate->numaggs * sizeof(AggStatePerGroupData); + additionalsize = aggstate->numaggs * sizeof(AggStatePerGroupData); aggstate->hashtable = BuildTupleHashTable(node->numCols, - node->grpColIdx, + aggstate->hashGrpColIdxHash, aggstate->phase->eqfunctions, aggstate->hashfunctions, node->numGroups, - entrysize, + additionalsize, aggstate->aggcontexts[0]->ecxt_per_tuple_memory, - tmpmem); + tmpmem, + DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit)); } /* - * Create a list of the tuple columns that actually need to be stored in - * hashtable entries. The incoming tuples from the child plan node will - * contain grouping columns, other columns referenced in our targetlist and - * qual, columns used to compute the aggregate functions, and perhaps just - * junk columns we don't use at all. Only columns of the first two types - * need to be stored in the hashtable, and getting rid of the others can - * make the table entries significantly smaller. To avoid messing up Var - * numbering, we keep the same tuple descriptor for hashtable entries as the - * incoming tuples have, but set unwanted columns to NULL in the tuples that - * go into the table. - * - * To eliminate duplicates, we build a bitmapset of the needed columns, then - * convert it to an integer list (cheaper to scan at runtime). The list is - * in decreasing order so that the first entry is the largest; - * lookup_hash_entry depends on this to use slot_getsomeattrs correctly. - * Note that the list is preserved over ExecReScanAgg, so we allocate it in - * the per-query context (unlike the hash table itself). - * - * Note: at present, searching the tlist/qual is not really necessary since - * the parser should disallow any unaggregated references to ungrouped - * columns. However, the search will be needed when we add support for - * SQL99 semantics that allow use of "functionally dependent" columns that - * haven't been explicitly grouped by. + * Compute columns that actually need to be stored in hashtable entries. The + * incoming tuples from the child plan node will contain grouping columns, + * other columns referenced in our targetlist and qual, columns used to + * compute the aggregate functions, and perhaps just junk columns we don't use + * at all. Only columns of the first two types need to be stored in the + * hashtable, and getting rid of the others can make the table entries + * significantly smaller. The hashtable only contains the relevant columns, + * and is packed/unpacked in lookup_hash_entry() / agg_retrieve_hash_table() + * into the format of the normal input descriptor. + * + * Additional columns, in addition to the columns grouped by, come from two + * sources: Firstly functionally dependent columns that we don't need to group + * by themselves, and secondly ctids for row-marks. + * + * To eliminate duplicates, we build a bitmapset of the needed columns, and + * then build an array of the columns included in the hashtable. Note that + * the array is preserved over ExecReScanAgg, so we allocate it in the + * per-query context (unlike the hash table itself). */ static List * find_hash_columns(AggState *aggstate) @@ -1702,8 +1756,13 @@ find_hash_columns(AggState *aggstate) Agg *node = (Agg *) aggstate->ss.ps.plan; Bitmapset *colnos; List *collist; + TupleDesc hashDesc; + List *outerTlist = outerPlanState(aggstate)->plan->targetlist; + List *hashTlist = NIL; int i; + aggstate->largestGrpColIdx = 0; + /* Find Vars that will be needed in tlist and qual */ colnos = find_unaggregated_cols(aggstate); /* Add in all the grouping columns */ @@ -1711,8 +1770,49 @@ find_hash_columns(AggState *aggstate) colnos = bms_add_member(colnos, node->grpColIdx[i]); /* Convert to list, using lcons so largest element ends up first */ collist = NIL; + + aggstate->hashGrpColIdxInput = + palloc(bms_num_members(colnos) * sizeof(AttrNumber)); + aggstate->hashGrpColIdxHash = + palloc(node->numCols * sizeof(AttrNumber)); + + /* + * First build mapping for columns directly hashed. These are the first, + * because they'll be accessed when computing hash values and comparing + * tuples for exact matches. We also build simple mapping for + * execGrouping, so it knows where to find the to-be-hashed / compared + * columns in the input. + */ + for (i = 0; i < node->numCols; i++) + { + aggstate->hashGrpColIdxInput[i] = node->grpColIdx[i]; + aggstate->hashGrpColIdxHash[i] = i + 1; + aggstate->numhashGrpCols++; + /* delete already mapped columns */ + bms_del_member(colnos, node->grpColIdx[i]); + } + + /* and add the remaining columns */ while ((i = bms_first_member(colnos)) >= 0) - collist = lcons_int(i, collist); + { + aggstate->hashGrpColIdxInput[aggstate->numhashGrpCols] = i; + aggstate->numhashGrpCols++; + } + + /* and build a tuple descriptor for the hashtable */ + for (i = 0; i < aggstate->numhashGrpCols; i++) + { + int varNumber = aggstate->hashGrpColIdxInput[i] - 1; + + hashTlist = lappend(hashTlist, list_nth(outerTlist, varNumber)); + aggstate->largestGrpColIdx = + Max(varNumber + 1, aggstate->largestGrpColIdx); + } + + hashDesc = ExecTypeFromTL(hashTlist, false); + ExecSetSlotDescriptor(aggstate->hashslot, hashDesc); + + list_free(hashTlist); bms_free(colnos); return collist; @@ -1723,6 +1823,8 @@ find_hash_columns(AggState *aggstate) * * Note that the estimate does not include space for pass-by-reference * transition data values, nor for the representative tuple of each group. + * Nor does this account of the target fill-factor and growth policy of the + * hash table. */ Size hash_agg_entry_size(int numAggs) @@ -1730,11 +1832,10 @@ hash_agg_entry_size(int numAggs) Size entrysize; /* This must match build_hash_table */ - entrysize = offsetof(AggHashEntryData, pergroup) + + entrysize = sizeof(TupleHashEntryData) + numAggs * sizeof(AggStatePerGroupData); entrysize = MAXALIGN(entrysize); - /* Account for hashtable overhead (assuming fill factor = 1) */ - entrysize += 3 * sizeof(void *); + return entrysize; } @@ -1744,41 +1845,38 @@ hash_agg_entry_size(int numAggs) * * When called, CurrentMemoryContext should be the per-query context. */ -static AggHashEntry +static TupleHashEntryData * lookup_hash_entry(AggState *aggstate, TupleTableSlot *inputslot) { TupleTableSlot *hashslot = aggstate->hashslot; - ListCell *l; - AggHashEntry entry; + TupleHashEntryData *entry; bool isnew; - - /* if first time through, initialize hashslot by cloning input slot */ - if (hashslot->tts_tupleDescriptor == NULL) - { - ExecSetSlotDescriptor(hashslot, inputslot->tts_tupleDescriptor); - /* Make sure all unused columns are NULLs */ - ExecStoreAllNullTuple(hashslot); - } + int i; /* transfer just the needed columns into hashslot */ - slot_getsomeattrs(inputslot, linitial_int(aggstate->hash_needed)); - foreach(l, aggstate->hash_needed) + slot_getsomeattrs(inputslot, aggstate->largestGrpColIdx); + ExecClearTuple(hashslot); + + for (i = 0; i < aggstate->numhashGrpCols; i++) { - int varNumber = lfirst_int(l) - 1; + int varNumber = aggstate->hashGrpColIdxInput[i] - 1; - hashslot->tts_values[varNumber] = inputslot->tts_values[varNumber]; - hashslot->tts_isnull[varNumber] = inputslot->tts_isnull[varNumber]; + hashslot->tts_values[i] = inputslot->tts_values[varNumber]; + hashslot->tts_isnull[i] = inputslot->tts_isnull[varNumber]; } + ExecStoreVirtualTuple(hashslot); /* find or create the hashtable entry using the filtered tuple */ - entry = (AggHashEntry) LookupTupleHashEntry(aggstate->hashtable, - hashslot, - &isnew); + entry = LookupTupleHashEntry(aggstate->hashtable, hashslot, &isnew); if (isnew) { + entry->additional = (AggStatePerGroup) + MemoryContextAlloc(aggstate->hashtable->tablecxt, + sizeof(AggStatePerGroupData) * aggstate->numtrans); /* initialize aggregates for new tuple group */ - initialize_aggregates(aggstate, entry->pergroup, 0); + initialize_aggregates(aggstate, (AggStatePerGroup) entry->additional, + 0); } return entry; @@ -1802,27 +1900,6 @@ ExecAgg(AggState *node) { TupleTableSlot *result; - /* - * Check to see if we're still projecting out tuples from a previous agg - * tuple (because there is a function-returning-set in the projection - * expressions). If so, try to project another one. - */ - if (node->ss.ps.ps_TupFromTlist) - { - ExprDoneCond isDone; - - result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone); - if (isDone == ExprMultipleResult) - return result; - /* Done with that source tuple... */ - node->ss.ps.ps_TupFromTlist = false; - } - - /* - * (We must do the ps_TupFromTlist check first, because in some cases - * agg_done gets set before we emit the final aggregate tuple, and we have - * to finish running SRFs for it.) - */ if (!node->agg_done) { /* Dispatch based on strategy */ @@ -2176,7 +2253,7 @@ static void agg_fill_hash_table(AggState *aggstate) { ExprContext *tmpcontext; - AggHashEntry entry; + TupleHashEntryData *entry; TupleTableSlot *outerslot; /* @@ -2203,9 +2280,9 @@ agg_fill_hash_table(AggState *aggstate) /* Advance the aggregates */ if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit)) - combine_aggregates(aggstate, entry->pergroup); + combine_aggregates(aggstate, (AggStatePerGroup) entry->additional); else - advance_aggregates(aggstate, entry->pergroup); + advance_aggregates(aggstate, (AggStatePerGroup) entry->additional); /* Reset per-input-tuple context after each tuple */ ResetExprContext(tmpcontext); @@ -2225,9 +2302,10 @@ agg_retrieve_hash_table(AggState *aggstate) ExprContext *econtext; AggStatePerAgg peragg; AggStatePerGroup pergroup; - AggHashEntry entry; + TupleHashEntryData *entry; TupleTableSlot *firstSlot; TupleTableSlot *result; + TupleTableSlot *hashslot; /* * get state info from node @@ -2236,6 +2314,8 @@ agg_retrieve_hash_table(AggState *aggstate) econtext = aggstate->ss.ps.ps_ExprContext; peragg = aggstate->peragg; firstSlot = aggstate->ss.ss_ScanTupleSlot; + hashslot = aggstate->hashslot; + /* * We loop retrieving groups until we find one satisfying @@ -2243,10 +2323,12 @@ agg_retrieve_hash_table(AggState *aggstate) */ while (!aggstate->agg_done) { + int i; + /* * Find the next entry in the hash table */ - entry = (AggHashEntry) ScanTupleHashTable(&aggstate->hashiter); + entry = ScanTupleHashTable(aggstate->hashtable, &aggstate->hashiter); if (entry == NULL) { /* No more entries in hashtable, so done */ @@ -2264,14 +2346,26 @@ agg_retrieve_hash_table(AggState *aggstate) ResetExprContext(econtext); /* - * Store the copied first input tuple in the tuple table slot reserved - * for it, so that it can be used in ExecProject. + * Transform representative tuple back into one with the right + * columns. */ - ExecStoreMinimalTuple(entry->shared.firstTuple, - firstSlot, - false); + ExecStoreMinimalTuple(entry->firstTuple, hashslot, false); + slot_getallattrs(hashslot); + + ExecClearTuple(firstSlot); + memset(firstSlot->tts_isnull, true, + firstSlot->tts_tupleDescriptor->natts * sizeof(bool)); + + for (i = 0; i < aggstate->numhashGrpCols; i++) + { + int varNumber = aggstate->hashGrpColIdxInput[i] - 1; - pergroup = entry->pergroup; + firstSlot->tts_values[varNumber] = hashslot->tts_values[i]; + firstSlot->tts_isnull[varNumber] = hashslot->tts_isnull[i]; + } + ExecStoreVirtualTuple(firstSlot); + + pergroup = (AggStatePerGroup) entry->additional; finalize_aggregates(aggstate, peragg, pergroup, 0); @@ -2309,10 +2403,12 @@ ExecInitAgg(Agg *node, EState *estate, int eflags) transno, aggno; int phase; + List *combined_inputeval; ListCell *l; Bitmapset *all_grouped_cols = NULL; int numGroupingSets = 1; int numPhases; + int column_offset; int i = 0; int j = 0; @@ -2443,8 +2539,6 @@ ExecInitAgg(Agg *node, EState *estate, int eflags) ExecAssignResultTypeFromTL(&aggstate->ss.ps); ExecAssignProjectionInfo(&aggstate->ss.ps, NULL); - aggstate->ss.ps.ps_TupFromTlist = false; - /* * get the count of aggregates in targetlist and quals */ @@ -2544,16 +2638,6 @@ ExecInitAgg(Agg *node, EState *estate, int eflags) while ((i = bms_next_member(all_grouped_cols, i)) >= 0) aggstate->all_grouped_cols = lcons_int(i, aggstate->all_grouped_cols); - /* - * Hashing can only appear in the initial phase. - */ - - if (node->aggstrategy == AGG_HASHED) - execTuplesHashPrepare(node->numCols, - node->grpOperators, - &aggstate->phases[0].eqfunctions, - &aggstate->hashfunctions); - /* * Initialize current phase-dependent values to initial phase */ @@ -2575,12 +2659,21 @@ ExecInitAgg(Agg *node, EState *estate, int eflags) aggstate->peragg = peraggs; aggstate->pertrans = pertransstates; + + /* + * Hashing can only appear in the initial phase. + */ if (node->aggstrategy == AGG_HASHED) { + find_hash_columns(aggstate); + + execTuplesHashPrepare(node->numCols, + node->grpOperators, + &aggstate->phases[0].eqfunctions, + &aggstate->hashfunctions); + build_hash_table(aggstate); aggstate->table_filled = false; - /* Compute the columns we actually need to hash on */ - aggstate->hash_needed = find_hash_columns(aggstate); } else { @@ -2894,6 +2987,53 @@ ExecInitAgg(Agg *node, EState *estate, int eflags) aggstate->numaggs = aggno + 1; aggstate->numtrans = transno + 1; + /* + * Build a single projection computing the aggregate arguments for all + * aggregates at once, that's considerably faster than doing it separately + * for each. + * + * First create a targetlist combining the targetlist of all the + * transitions. + */ + combined_inputeval = NIL; + column_offset = 0; + for (transno = 0; transno < aggstate->numtrans; transno++) + { + AggStatePerTrans pertrans = &pertransstates[transno]; + ListCell *arg; + + pertrans->inputoff = column_offset; + + /* + * Adjust resno in a copied target entries, to point into the combined + * slot. + */ + foreach(arg, pertrans->aggref->args) + { + TargetEntry *source_tle = (TargetEntry *) lfirst(arg); + TargetEntry *tle; + + Assert(IsA(source_tle, TargetEntry)); + tle = flatCopyTargetEntry(source_tle); + tle->resno += column_offset; + + combined_inputeval = lappend(combined_inputeval, tle); + } + + column_offset += list_length(pertrans->aggref->args); + } + + /* and then create a projection for that targetlist */ + aggstate->evaldesc = ExecTypeFromTL(combined_inputeval, false); + aggstate->evalslot = ExecInitExtraTupleSlot(estate); + combined_inputeval = (List *) ExecInitExpr((Expr *) combined_inputeval, + (PlanState *) aggstate); + aggstate->evalproj = ExecBuildProjectionInfo(combined_inputeval, + aggstate->tmpcontext, + aggstate->evalslot, + NULL); + ExecSetSlotDescriptor(aggstate->evalslot, aggstate->evaldesc); + return aggstate; } @@ -3064,24 +3204,12 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans, } - /* - * Get a tupledesc corresponding to the aggregated inputs (including sort - * expressions) of the agg. - */ - pertrans->evaldesc = ExecTypeFromTL(aggref->args, false); - - /* Create slot we're going to do argument evaluation in */ - pertrans->evalslot = ExecInitExtraTupleSlot(estate); - ExecSetSlotDescriptor(pertrans->evalslot, pertrans->evaldesc); - /* Initialize the input and FILTER expressions */ naggs = aggstate->numaggs; pertrans->aggfilter = ExecInitExpr(aggref->aggfilter, (PlanState *) aggstate); pertrans->aggdirectargs = (List *) ExecInitExpr((Expr *) aggref->aggdirectargs, (PlanState *) aggstate); - pertrans->args = (List *) ExecInitExpr((Expr *) aggref->args, - (PlanState *) aggstate); /* * Complain if the aggregate's arguments contain any aggregates; nested @@ -3093,12 +3221,6 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans, (errcode(ERRCODE_GROUPING_ERROR), errmsg("aggregate function calls cannot be nested"))); - /* Set up projection info for evaluation */ - pertrans->evalproj = ExecBuildProjectionInfo(pertrans->args, - aggstate->tmpcontext, - pertrans->evalslot, - NULL); - /* * If we're doing either DISTINCT or ORDER BY for a plain agg, then we * have a list of SortGroupClause nodes; fish out the data in them and @@ -3131,6 +3253,14 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans, if (numSortCols > 0) { + /* + * Get a tupledesc and slot corresponding to the aggregated inputs + * (including sort expressions) of the agg. + */ + pertrans->sortdesc = ExecTypeFromTL(aggref->args, false); + pertrans->sortslot = ExecInitExtraTupleSlot(estate); + ExecSetSlotDescriptor(pertrans->sortslot, pertrans->sortdesc); + /* * We don't implement DISTINCT or ORDER BY aggs in the HASHED case * (yet) @@ -3149,7 +3279,7 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans, /* we will need an extra slot to store prior values */ pertrans->uniqslot = ExecInitExtraTupleSlot(estate); ExecSetSlotDescriptor(pertrans->uniqslot, - pertrans->evaldesc); + pertrans->sortdesc); } /* Extract the sort information for use later */ @@ -3411,8 +3541,6 @@ ExecReScanAgg(AggState *node) node->agg_done = false; - node->ss.ps.ps_TupFromTlist = false; - if (aggnode->aggstrategy == AGG_HASHED) { /* @@ -3425,11 +3553,13 @@ ExecReScanAgg(AggState *node) return; /* - * If we do have the hash table and the subplan does not have any - * parameter changes, then we can just rescan the existing hash table; - * no need to build it again. + * If we do have the hash table, and the subplan does not have any + * parameter changes, and none of our own parameter changes affect + * input expressions of the aggregated functions, then we can just + * rescan the existing hash table; no need to build it again. */ - if (outerPlan->chgParam == NULL) + if (outerPlan->chgParam == NULL && + !bms_overlap(node->ss.ps.chgParam, aggnode->aggParams)) { ResetTupleHashIterator(node->hashtable, &node->hashiter); return; diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c index a26bd6354c..6986caee6b 100644 --- a/src/backend/executor/nodeAppend.c +++ b/src/backend/executor/nodeAppend.c @@ -3,7 +3,7 @@ * nodeAppend.c * routines to handle append nodes. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeBitmapAnd.c b/src/backend/executor/nodeBitmapAnd.c index c39d790f82..e4eb028ff9 100644 --- a/src/backend/executor/nodeBitmapAnd.c +++ b/src/backend/executor/nodeBitmapAnd.c @@ -3,7 +3,7 @@ * nodeBitmapAnd.c * routines to handle BitmapAnd nodes. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c index 449aacb6e7..f18827de0b 100644 --- a/src/backend/executor/nodeBitmapHeapscan.c +++ b/src/backend/executor/nodeBitmapHeapscan.c @@ -16,7 +16,7 @@ * required index qual conditions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -575,8 +575,6 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &scanstate->ss.ps); - scanstate->ss.ps.ps_TupFromTlist = false; - /* * initialize child expressions */ diff --git a/src/backend/executor/nodeBitmapIndexscan.c b/src/backend/executor/nodeBitmapIndexscan.c index a364098e59..4274e9abcb 100644 --- a/src/backend/executor/nodeBitmapIndexscan.c +++ b/src/backend/executor/nodeBitmapIndexscan.c @@ -3,7 +3,7 @@ * nodeBitmapIndexscan.c * Routines to support bitmapped index scans of relations * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeBitmapOr.c b/src/backend/executor/nodeBitmapOr.c index 7e928eb618..3c6155b7c3 100644 --- a/src/backend/executor/nodeBitmapOr.c +++ b/src/backend/executor/nodeBitmapOr.c @@ -3,7 +3,7 @@ * nodeBitmapOr.c * routines to handle BitmapOr nodes. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeCtescan.c b/src/backend/executor/nodeCtescan.c index 3c2f684a06..610797b36b 100644 --- a/src/backend/executor/nodeCtescan.c +++ b/src/backend/executor/nodeCtescan.c @@ -3,7 +3,7 @@ * nodeCtescan.c * routines to handle CteScan nodes. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -224,9 +224,13 @@ ExecInitCteScan(CteScan *node, EState *estate, int eflags) { /* Not the leader */ Assert(IsA(scanstate->leader, CteScanState)); + /* Create my own read pointer, and ensure it is at start */ scanstate->readptr = tuplestore_alloc_read_pointer(scanstate->leader->cte_table, scanstate->eflags); + tuplestore_select_read_pointer(scanstate->leader->cte_table, + scanstate->readptr); + tuplestore_rescan(scanstate->leader->cte_table); } /* @@ -265,8 +269,6 @@ ExecInitCteScan(CteScan *node, EState *estate, int eflags) ExecAssignResultTypeFromTL(&scanstate->ss.ps); ExecAssignScanProjectionInfo(&scanstate->ss); - scanstate->ss.ps.ps_TupFromTlist = false; - return scanstate; } diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c index 322abca282..a27430242a 100644 --- a/src/backend/executor/nodeCustom.c +++ b/src/backend/executor/nodeCustom.c @@ -3,7 +3,7 @@ * nodeCustom.c * Routines to handle execution of custom scan node * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * ------------------------------------------------------------------------ @@ -48,8 +48,6 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags) /* create expression context for node */ ExecAssignExprContext(estate, &css->ss.ps); - css->ss.ps.ps_TupFromTlist = false; - /* initialize child expressions */ css->ss.ps.targetlist = (List *) ExecInitExpr((Expr *) cscan->scan.plan.targetlist, diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c index d886aaf64d..86a77e356c 100644 --- a/src/backend/executor/nodeForeignscan.c +++ b/src/backend/executor/nodeForeignscan.c @@ -3,7 +3,7 @@ * nodeForeignscan.c * Routines to support scans of foreign tables * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -152,8 +152,6 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &scanstate->ss.ps); - scanstate->ss.ps.ps_TupFromTlist = false; - /* * initialize child expressions */ diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c index a03f6e73fd..972022784d 100644 --- a/src/backend/executor/nodeFunctionscan.c +++ b/src/backend/executor/nodeFunctionscan.c @@ -3,7 +3,7 @@ * nodeFunctionscan.c * Support routines for scanning RangeFunctions (functions in rangetable). * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -331,8 +331,6 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &scanstate->ss.ps); - scanstate->ss.ps.ps_TupFromTlist = false; - /* * tuple table initialization */ @@ -508,9 +506,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags) */ scanstate->argcontext = AllocSetContextCreate(CurrentMemoryContext, "Table function arguments", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); return scanstate; } diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c index 438d1b24fc..a1a3561d48 100644 --- a/src/backend/executor/nodeGather.c +++ b/src/backend/executor/nodeGather.c @@ -3,7 +3,7 @@ * nodeGather.c * Support routines for scanning a plan via multiple workers. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * A Gather executor launches parallel workers to run multiple copies of a @@ -38,6 +38,7 @@ #include "executor/nodeSubplan.h" #include "executor/tqueue.h" #include "miscadmin.h" +#include "pgstat.h" #include "utils/memutils.h" #include "utils/rel.h" @@ -99,8 +100,6 @@ ExecInitGather(Gather *node, EState *estate, int eflags) outerNode = outerPlan(node); outerPlanState(gatherstate) = ExecInitNode(outerNode, estate, eflags); - gatherstate->ps.ps_TupFromTlist = false; - /* * Initialize result tuple type and projection info. */ @@ -131,15 +130,13 @@ ExecGather(GatherState *node) TupleTableSlot *fslot = node->funnel_slot; int i; TupleTableSlot *slot; - TupleTableSlot *resultSlot; - ExprDoneCond isDone; ExprContext *econtext; /* * Initialize the parallel context and workers on first execution. We do * this on first execution rather than during node initialization, as it - * needs to allocate large dynamic segment, so it is better to do if it is - * really needed. + * needs to allocate a large dynamic segment, so it is better to do it + * only if it is really needed. */ if (!node->initialized) { @@ -172,6 +169,7 @@ ExecGather(GatherState *node) if (pcxt->nworkers_launched > 0) { node->nreaders = 0; + node->nextreader = 0; node->reader = palloc(pcxt->nworkers_launched * sizeof(TupleQueueReader *)); @@ -197,58 +195,29 @@ ExecGather(GatherState *node) node->initialized = true; } - /* - * Check to see if we're still projecting out tuples from a previous scan - * tuple (because there is a function-returning-set in the projection - * expressions). If so, try to project another one. - */ - if (node->ps.ps_TupFromTlist) - { - resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone); - if (isDone == ExprMultipleResult) - return resultSlot; - /* Done with that source tuple... */ - node->ps.ps_TupFromTlist = false; - } - /* * Reset per-tuple memory context to free any expression evaluation - * storage allocated in the previous tuple cycle. Note we can't do this - * until we're done projecting. This will also clear any previous tuple - * returned by a TupleQueueReader; to make sure we don't leave a dangling - * pointer around, clear the working slot first. + * storage allocated in the previous tuple cycle. This will also clear + * any previous tuple returned by a TupleQueueReader; to make sure we + * don't leave a dangling pointer around, clear the working slot first. */ - ExecClearTuple(node->funnel_slot); + ExecClearTuple(fslot); econtext = node->ps.ps_ExprContext; ResetExprContext(econtext); - /* Get and return the next tuple, projecting if necessary. */ - for (;;) - { - /* - * Get next tuple, either from one of our workers, or by running the - * plan ourselves. - */ - slot = gather_getnext(node); - if (TupIsNull(slot)) - return NULL; - - /* - * form the result tuple using ExecProject(), and return it --- unless - * the projection produces an empty set, in which case we must loop - * back around for another tuple - */ - econtext->ecxt_outertuple = slot; - resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone); - - if (isDone != ExprEndResult) - { - node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult); - return resultSlot; - } - } + /* + * Get next tuple, either from one of our workers, or by running the plan + * ourselves. + */ + slot = gather_getnext(node); + if (TupIsNull(slot)) + return NULL; - return slot; + /* + * Form the result tuple using ExecProject(), and return it. + */ + econtext->ecxt_outertuple = slot; + return ExecProject(node->ps.ps_ProjInfo); } /* ---------------------------------------------------------------- @@ -334,6 +303,7 @@ gather_readnext(GatherState *gatherstate) CHECK_FOR_INTERRUPTS(); /* Attempt to read a tuple, but don't block if none is available. */ + Assert(gatherstate->nextreader < gatherstate->nreaders); reader = gatherstate->reader[gatherstate->nextreader]; tup = TupleQueueReaderNext(reader, true, &readerdone); @@ -387,7 +357,7 @@ gather_readnext(GatherState *gatherstate) return NULL; /* Nothing to do except wait for developments. */ - WaitLatch(MyLatch, WL_LATCH_SET, 0); + WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_EXECUTE_GATHER); ResetLatch(MyLatch); nvisited = 0; } diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c index dcf5175d9b..66c095bc72 100644 --- a/src/backend/executor/nodeGroup.c +++ b/src/backend/executor/nodeGroup.c @@ -3,7 +3,7 @@ * nodeGroup.c * Routines to handle group nodes (used for queries with GROUP BY clause). * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -49,23 +49,6 @@ ExecGroup(GroupState *node) numCols = ((Group *) node->ss.ps.plan)->numCols; grpColIdx = ((Group *) node->ss.ps.plan)->grpColIdx; - /* - * Check to see if we're still projecting out tuples from a previous group - * tuple (because there is a function-returning-set in the projection - * expressions). If so, try to project another one. - */ - if (node->ss.ps.ps_TupFromTlist) - { - TupleTableSlot *result; - ExprDoneCond isDone; - - result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone); - if (isDone == ExprMultipleResult) - return result; - /* Done with that source tuple... */ - node->ss.ps.ps_TupFromTlist = false; - } - /* * The ScanTupleSlot holds the (copied) first tuple of each group. */ @@ -107,16 +90,7 @@ ExecGroup(GroupState *node) /* * Form and return a projection tuple using the first input tuple. */ - TupleTableSlot *result; - ExprDoneCond isDone; - - result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone); - - if (isDone != ExprEndResult) - { - node->ss.ps.ps_TupFromTlist = (isDone == ExprMultipleResult); - return result; - } + return ExecProject(node->ss.ps.ps_ProjInfo); } else InstrCountFiltered1(node, 1); @@ -170,16 +144,7 @@ ExecGroup(GroupState *node) /* * Form and return a projection tuple using the first input tuple. */ - TupleTableSlot *result; - ExprDoneCond isDone; - - result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone); - - if (isDone != ExprEndResult) - { - node->ss.ps.ps_TupFromTlist = (isDone == ExprMultipleResult); - return result; - } + return ExecProject(node->ss.ps.ps_ProjInfo); } else InstrCountFiltered1(node, 1); @@ -246,8 +211,6 @@ ExecInitGroup(Group *node, EState *estate, int eflags) ExecAssignResultTypeFromTL(&grpstate->ss.ps); ExecAssignProjectionInfo(&grpstate->ss.ps, NULL); - grpstate->ss.ps.ps_TupFromTlist = false; - /* * Precompute fmgr lookup data for inner loop */ @@ -283,7 +246,6 @@ ExecReScanGroup(GroupState *node) PlanState *outerPlan = outerPlanState(node); node->grp_done = FALSE; - node->ss.ps.ps_TupFromTlist = false; /* must clear first tuple */ ExecClearTuple(node->ss.ss_ScanTupleSlot); diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index 9ed09a7b0c..af5934d2bc 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -3,7 +3,7 @@ * nodeHash.c * Routines to hash relations for hashjoin * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -344,15 +344,11 @@ ExecHashTableCreate(Hash *node, List *hashOperators, bool keepNulls) */ hashtable->hashCxt = AllocSetContextCreate(CurrentMemoryContext, "HashTableContext", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); hashtable->batchCxt = AllocSetContextCreate(hashtable->hashCxt, "HashBatchContext", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* Allocate data that will live for the life of the hashjoin */ @@ -963,7 +959,7 @@ ExecHashGetHashValue(HashJoinTable hashtable, /* * Get the join attribute value of the tuple */ - keyval = ExecEvalExpr(keyexpr, econtext, &isNull, NULL); + keyval = ExecEvalExpr(keyexpr, econtext, &isNull); /* * If the attribute is NULL, and the join operator is strict, then diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c index 369e666f88..6e576ad0b3 100644 --- a/src/backend/executor/nodeHashjoin.c +++ b/src/backend/executor/nodeHashjoin.c @@ -3,7 +3,7 @@ * nodeHashjoin.c * Routines to handle hash join nodes * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -66,7 +66,6 @@ ExecHashJoin(HashJoinState *node) List *joinqual; List *otherqual; ExprContext *econtext; - ExprDoneCond isDone; HashJoinTable hashtable; TupleTableSlot *outerTupleSlot; uint32 hashvalue; @@ -82,26 +81,9 @@ ExecHashJoin(HashJoinState *node) hashtable = node->hj_HashTable; econtext = node->js.ps.ps_ExprContext; - /* - * Check to see if we're still projecting out tuples from a previous join - * tuple (because there is a function-returning-set in the projection - * expressions). If so, try to project another one. - */ - if (node->js.ps.ps_TupFromTlist) - { - TupleTableSlot *result; - - result = ExecProject(node->js.ps.ps_ProjInfo, &isDone); - if (isDone == ExprMultipleResult) - return result; - /* Done with that source tuple... */ - node->js.ps.ps_TupFromTlist = false; - } - /* * Reset per-tuple memory context to free any expression evaluation - * storage allocated in the previous tuple cycle. Note this can't happen - * until we're done projecting out tuples from a join tuple. + * storage allocated in the previous tuple cycle. */ ResetExprContext(econtext); @@ -314,18 +296,7 @@ ExecHashJoin(HashJoinState *node) if (otherqual == NIL || ExecQual(otherqual, econtext, false)) - { - TupleTableSlot *result; - - result = ExecProject(node->js.ps.ps_ProjInfo, &isDone); - - if (isDone != ExprEndResult) - { - node->js.ps.ps_TupFromTlist = - (isDone == ExprMultipleResult); - return result; - } - } + return ExecProject(node->js.ps.ps_ProjInfo); else InstrCountFiltered2(node, 1); } @@ -353,18 +324,7 @@ ExecHashJoin(HashJoinState *node) if (otherqual == NIL || ExecQual(otherqual, econtext, false)) - { - TupleTableSlot *result; - - result = ExecProject(node->js.ps.ps_ProjInfo, &isDone); - - if (isDone != ExprEndResult) - { - node->js.ps.ps_TupFromTlist = - (isDone == ExprMultipleResult); - return result; - } - } + return ExecProject(node->js.ps.ps_ProjInfo); else InstrCountFiltered2(node, 1); } @@ -392,18 +352,7 @@ ExecHashJoin(HashJoinState *node) if (otherqual == NIL || ExecQual(otherqual, econtext, false)) - { - TupleTableSlot *result; - - result = ExecProject(node->js.ps.ps_ProjInfo, &isDone); - - if (isDone != ExprEndResult) - { - node->js.ps.ps_TupFromTlist = - (isDone == ExprMultipleResult); - return result; - } - } + return ExecProject(node->js.ps.ps_ProjInfo); else InstrCountFiltered2(node, 1); break; @@ -586,7 +535,6 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags) /* child Hash node needs to evaluate inner hash keys, too */ ((HashState *) innerPlanState(hjstate))->hashkeys = rclauses; - hjstate->js.ps.ps_TupFromTlist = false; hjstate->hj_JoinState = HJ_BUILD_HASHTABLE; hjstate->hj_MatchedOuter = false; hjstate->hj_OuterNotEmpty = false; @@ -1000,7 +948,6 @@ ExecReScanHashJoin(HashJoinState *node) node->hj_CurSkewBucketNo = INVALID_SKEW_BUCKET_NO; node->hj_CurTuple = NULL; - node->js.ps.ps_TupFromTlist = false; node->hj_MatchedOuter = false; node->hj_FirstOuterTupleSlot = NULL; diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c index 4f6f91c8db..d5b19b7c11 100644 --- a/src/backend/executor/nodeIndexonlyscan.c +++ b/src/backend/executor/nodeIndexonlyscan.c @@ -3,7 +3,7 @@ * nodeIndexonlyscan.c * Routines to support index-only scans * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -412,8 +412,6 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &indexstate->ss.ps); - indexstate->ss.ps.ps_TupFromTlist = false; - /* * initialize child expressions * diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index 3143bd94ec..5734550d2c 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -3,7 +3,7 @@ * nodeIndexscan.c * Routines to support indexed scans of relations * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -336,8 +336,7 @@ EvalOrderByExpressions(IndexScanState *node, ExprContext *econtext) node->iss_OrderByValues[i] = ExecEvalExpr(orderby, econtext, - &node->iss_OrderByNulls[i], - NULL); + &node->iss_OrderByNulls[i]); i++; } @@ -590,8 +589,7 @@ ExecIndexEvalRuntimeKeys(ExprContext *econtext, */ scanvalue = ExecEvalExpr(key_expr, econtext, - &isNull, - NULL); + &isNull); if (isNull) { scan_key->sk_argument = scanvalue; @@ -648,8 +646,7 @@ ExecIndexEvalArrayKeys(ExprContext *econtext, */ arraydatum = ExecEvalExpr(array_expr, econtext, - &isNull, - NULL); + &isNull); if (isNull) { result = false; @@ -837,8 +834,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &indexstate->ss.ps); - indexstate->ss.ps.ps_TupFromTlist = false; - /* * initialize child expressions * diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c index faf32e1aee..aaec132218 100644 --- a/src/backend/executor/nodeLimit.c +++ b/src/backend/executor/nodeLimit.c @@ -3,7 +3,7 @@ * nodeLimit.c * Routines to handle limiting of query results where appropriate * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -239,8 +239,7 @@ recompute_limits(LimitState *node) { val = ExecEvalExprSwitchContext(node->limitOffset, econtext, - &isNull, - NULL); + &isNull); /* Interpret NULL offset as no offset */ if (isNull) node->offset = 0; @@ -263,8 +262,7 @@ recompute_limits(LimitState *node) { val = ExecEvalExprSwitchContext(node->limitCount, econtext, - &isNull, - NULL); + &isNull); /* Interpret NULL count as no count (LIMIT ALL) */ if (isNull) { @@ -346,18 +344,11 @@ pass_down_bound(LimitState *node, PlanState *child_node) else if (IsA(child_node, ResultState)) { /* - * An extra consideration here is that if the Result is projecting a - * targetlist that contains any SRFs, we can't assume that every input - * tuple generates an output tuple, so a Sort underneath might need to - * return more than N tuples to satisfy LIMIT N. So we cannot use - * bounded sort. - * * If Result supported qual checking, we'd have to punt on seeing a - * qual, too. Note that having a resconstantqual is not a - * showstopper: if that fails we're not getting any rows at all. + * qual. Note that having a resconstantqual is not a showstopper: if + * that fails we're not getting any rows at all. */ - if (outerPlanState(child_node) && - !expression_returns_set((Node *) child_node->plan->targetlist)) + if (outerPlanState(child_node)) pass_down_bound(node, outerPlanState(child_node)); } } diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c index 4ebcaffe69..f1bf6fdf9f 100644 --- a/src/backend/executor/nodeLockRows.c +++ b/src/backend/executor/nodeLockRows.c @@ -3,7 +3,7 @@ * nodeLockRows.c * Routines to handle FOR UPDATE/FOR SHARE row locking * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c index 9ab03f3f15..aa5d2529f4 100644 --- a/src/backend/executor/nodeMaterial.c +++ b/src/backend/executor/nodeMaterial.c @@ -3,7 +3,7 @@ * nodeMaterial.c * Routines to handle materialization nodes. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c index e271927077..7a20bf07a4 100644 --- a/src/backend/executor/nodeMergeAppend.c +++ b/src/backend/executor/nodeMergeAppend.c @@ -3,7 +3,7 @@ * nodeMergeAppend.c * routines to handle MergeAppend nodes. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c index 6db09b836a..105e2dcedb 100644 --- a/src/backend/executor/nodeMergejoin.c +++ b/src/backend/executor/nodeMergejoin.c @@ -3,7 +3,7 @@ * nodeMergejoin.c * routines supporting merge joins * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -313,7 +313,7 @@ MJEvalOuterValues(MergeJoinState *mergestate) MergeJoinClause clause = &mergestate->mj_Clauses[i]; clause->ldatum = ExecEvalExpr(clause->lexpr, econtext, - &clause->lisnull, NULL); + &clause->lisnull); if (clause->lisnull) { /* match is impossible; can we end the join early? */ @@ -360,7 +360,7 @@ MJEvalInnerValues(MergeJoinState *mergestate, TupleTableSlot *innerslot) MergeJoinClause clause = &mergestate->mj_Clauses[i]; clause->rdatum = ExecEvalExpr(clause->rexpr, econtext, - &clause->risnull, NULL); + &clause->risnull); if (clause->risnull) { /* match is impossible; can we end the join early? */ @@ -465,19 +465,9 @@ MJFillOuter(MergeJoinState *node) * qualification succeeded. now form the desired projection tuple and * return the slot containing it. */ - TupleTableSlot *result; - ExprDoneCond isDone; - MJ_printf("ExecMergeJoin: returning outer fill tuple\n"); - result = ExecProject(node->js.ps.ps_ProjInfo, &isDone); - - if (isDone != ExprEndResult) - { - node->js.ps.ps_TupFromTlist = - (isDone == ExprMultipleResult); - return result; - } + return ExecProject(node->js.ps.ps_ProjInfo); } else InstrCountFiltered2(node, 1); @@ -506,19 +496,9 @@ MJFillInner(MergeJoinState *node) * qualification succeeded. now form the desired projection tuple and * return the slot containing it. */ - TupleTableSlot *result; - ExprDoneCond isDone; - MJ_printf("ExecMergeJoin: returning inner fill tuple\n"); - result = ExecProject(node->js.ps.ps_ProjInfo, &isDone); - - if (isDone != ExprEndResult) - { - node->js.ps.ps_TupFromTlist = - (isDone == ExprMultipleResult); - return result; - } + return ExecProject(node->js.ps.ps_ProjInfo); } else InstrCountFiltered2(node, 1); @@ -641,27 +621,9 @@ ExecMergeJoin(MergeJoinState *node) doFillOuter = node->mj_FillOuter; doFillInner = node->mj_FillInner; - /* - * Check to see if we're still projecting out tuples from a previous join - * tuple (because there is a function-returning-set in the projection - * expressions). If so, try to project another one. - */ - if (node->js.ps.ps_TupFromTlist) - { - TupleTableSlot *result; - ExprDoneCond isDone; - - result = ExecProject(node->js.ps.ps_ProjInfo, &isDone); - if (isDone == ExprMultipleResult) - return result; - /* Done with that source tuple... */ - node->js.ps.ps_TupFromTlist = false; - } - /* * Reset per-tuple memory context to free any expression evaluation - * storage allocated in the previous tuple cycle. Note this can't happen - * until we're done projecting out tuples from a join tuple. + * storage allocated in the previous tuple cycle. */ ResetExprContext(econtext); @@ -856,20 +818,9 @@ ExecMergeJoin(MergeJoinState *node) * qualification succeeded. now form the desired * projection tuple and return the slot containing it. */ - TupleTableSlot *result; - ExprDoneCond isDone; - MJ_printf("ExecMergeJoin: returning tuple\n"); - result = ExecProject(node->js.ps.ps_ProjInfo, - &isDone); - - if (isDone != ExprEndResult) - { - node->js.ps.ps_TupFromTlist = - (isDone == ExprMultipleResult); - return result; - } + return ExecProject(node->js.ps.ps_ProjInfo); } else InstrCountFiltered2(node, 1); @@ -1629,7 +1580,6 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags) * initialize join state */ mergestate->mj_JoinState = EXEC_MJ_INITIALIZE_OUTER; - mergestate->js.ps.ps_TupFromTlist = false; mergestate->mj_MatchedOuter = false; mergestate->mj_MatchedInner = false; mergestate->mj_OuterTupleSlot = NULL; @@ -1684,7 +1634,6 @@ ExecReScanMergeJoin(MergeJoinState *node) ExecClearTuple(node->mj_MarkedTupleSlot); node->mj_JoinState = EXEC_MJ_INITIALIZE_OUTER; - node->js.ps.ps_TupFromTlist = false; node->mj_MatchedOuter = false; node->mj_MatchedInner = false; node->mj_OuterTupleSlot = NULL; diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index af7b26c0ef..2ac7407318 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -3,7 +3,7 @@ * nodeModifyTable.c * routines to handle ModifyTable nodes. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -175,7 +175,7 @@ ExecProcessReturning(ResultRelInfo *resultRelInfo, econtext->ecxt_outertuple = planSlot; /* Compute the RETURNING expressions */ - return ExecProject(projectReturning, NULL); + return ExecProject(projectReturning); } /* @@ -194,10 +194,25 @@ ExecCheckHeapTupleVisible(EState *estate, if (!IsolationUsesXactSnapshot()) return; + /* + * We need buffer pin and lock to call HeapTupleSatisfiesVisibility. + * Caller should be holding pin, but not lock. + */ + LockBuffer(buffer, BUFFER_LOCK_SHARE); if (!HeapTupleSatisfiesVisibility(tuple, estate->es_snapshot, buffer)) - ereport(ERROR, - (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), + { + /* + * We should not raise a serialization failure if the conflict is + * against a tuple inserted by our own transaction, even if it's not + * visible to our snapshot. (This would happen, for example, if + * conflicting keys are proposed for insertion in a single command.) + */ + if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple->t_data))) + ereport(ERROR, + (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), errmsg("could not serialize access due to concurrent update"))); + } + LockBuffer(buffer, BUFFER_LOCK_UNLOCK); } /* @@ -243,9 +258,12 @@ ExecInsert(ModifyTableState *mtstate, { HeapTuple tuple; ResultRelInfo *resultRelInfo; + ResultRelInfo *saved_resultRelInfo = NULL; Relation resultRelationDesc; Oid newId; List *recheckIndexes = NIL; + TupleTableSlot *oldslot = slot, + *result = NULL; /* * get the heap tuple out of the tuple table slot, making sure we have a @@ -257,6 +275,67 @@ ExecInsert(ModifyTableState *mtstate, * get information on the (current) result relation */ resultRelInfo = estate->es_result_relation_info; + + /* Determine the partition to heap_insert the tuple into */ + if (mtstate->mt_partition_dispatch_info) + { + int leaf_part_index; + TupleConversionMap *map; + + /* + * Away we go ... If we end up not finding a partition after all, + * ExecFindPartition() does not return and errors out instead. + * Otherwise, the returned value is to be used as an index into + * arrays mt_partitions[] and mt_partition_tupconv_maps[] that + * will get us the ResultRelInfo and TupleConversionMap for the + * partition, respectively. + */ + leaf_part_index = ExecFindPartition(resultRelInfo, + mtstate->mt_partition_dispatch_info, + slot, + estate); + Assert(leaf_part_index >= 0 && + leaf_part_index < mtstate->mt_num_partitions); + + /* + * Save the old ResultRelInfo and switch to the one corresponding to + * the selected partition. + */ + saved_resultRelInfo = resultRelInfo; + resultRelInfo = mtstate->mt_partitions + leaf_part_index; + + /* We do not yet have a way to insert into a foreign partition */ + if (resultRelInfo->ri_FdwRoutine) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot route inserted tuples to a foreign table"))); + + /* For ExecInsertIndexTuples() to work on the partition's indexes */ + estate->es_result_relation_info = resultRelInfo; + + /* + * We might need to convert from the parent rowtype to the partition + * rowtype. + */ + map = mtstate->mt_partition_tupconv_maps[leaf_part_index]; + if (map) + { + Relation partrel = resultRelInfo->ri_RelationDesc; + + tuple = do_convert_tuple(tuple, map); + + /* + * We must use the partition's tuple descriptor from this + * point on, until we're finished dealing with the partition. + * Use the dedicated slot for that. + */ + slot = mtstate->mt_partition_tuple_slot; + Assert(slot != NULL); + ExecSetSlotDescriptor(slot, RelationGetDescr(partrel)); + ExecStoreTuple(tuple, slot, InvalidBuffer, true); + } + } + resultRelationDesc = resultRelInfo->ri_RelationDesc; /* @@ -354,8 +433,8 @@ ExecInsert(ModifyTableState *mtstate, /* * Check the constraints of the tuple */ - if (resultRelationDesc->rd_att->constr) - ExecConstraints(resultRelInfo, slot, estate); + if (resultRelationDesc->rd_att->constr || resultRelInfo->ri_PartitionCheck) + ExecConstraints(resultRelInfo, slot, oldslot, estate); if (onconflict != ONCONFLICT_NONE && resultRelInfo->ri_NumIndices > 0) { @@ -513,9 +592,12 @@ ExecInsert(ModifyTableState *mtstate, /* Process RETURNING if present */ if (resultRelInfo->ri_projectReturning) - return ExecProcessReturning(resultRelInfo, slot, planSlot); + result = ExecProcessReturning(resultRelInfo, slot, planSlot); - return NULL; + if (saved_resultRelInfo) + estate->es_result_relation_info = saved_resultRelInfo; + + return result; } /* ---------------------------------------------------------------- @@ -905,10 +987,12 @@ lreplace:; resultRelInfo, slot, estate); /* - * Check the constraints of the tuple + * Check the constraints of the tuple. Note that we pass the same + * slot for the orig_slot argument, because unlike ExecInsert(), no + * tuple-routing is performed here, hence the slot remains unchanged. */ - if (resultRelationDesc->rd_att->constr) - ExecConstraints(resultRelInfo, slot, estate); + if (resultRelationDesc->rd_att->constr || resultRelInfo->ri_PartitionCheck) + ExecConstraints(resultRelInfo, slot, slot, estate); /* * replace the heap tuple @@ -1216,7 +1300,7 @@ ExecOnConflictUpdate(ModifyTableState *mtstate, } /* Project the new tuple version */ - ExecProject(resultRelInfo->ri_onConflictSetProj, NULL); + ExecProject(resultRelInfo->ri_onConflictSetProj); /* * Note that it is possible that the target tuple has been modified in @@ -1550,6 +1634,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) Plan *subplan; ListCell *l; int i; + Relation rel; /* check for unsupported flags */ Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); @@ -1640,6 +1725,32 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) estate->es_result_relation_info = saved_resultRelInfo; + /* Build state for INSERT tuple routing */ + rel = mtstate->resultRelInfo->ri_RelationDesc; + if (operation == CMD_INSERT && + rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + { + PartitionDispatch *partition_dispatch_info; + ResultRelInfo *partitions; + TupleConversionMap **partition_tupconv_maps; + TupleTableSlot *partition_tuple_slot; + int num_parted, + num_partitions; + + ExecSetupPartitionTupleRouting(rel, + &partition_dispatch_info, + &partitions, + &partition_tupconv_maps, + &partition_tuple_slot, + &num_parted, &num_partitions); + mtstate->mt_partition_dispatch_info = partition_dispatch_info; + mtstate->mt_num_dispatch = num_parted; + mtstate->mt_partitions = partitions; + mtstate->mt_num_partitions = num_partitions; + mtstate->mt_partition_tupconv_maps = partition_tupconv_maps; + mtstate->mt_partition_tuple_slot = partition_tuple_slot; + } + /* * Initialize any WITH CHECK OPTION constraints if needed. */ @@ -1673,6 +1784,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) { TupleTableSlot *slot; ExprContext *econtext; + List *returningList; /* * Initialize result tuple slot and assign its rowtype using the first @@ -1705,6 +1817,32 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) resultRelInfo->ri_RelationDesc->rd_att); resultRelInfo++; } + + /* + * Build a projection for each leaf partition rel. Note that we + * didn't build the returningList for each partition within the + * planner, but simple translation of the varattnos for each + * partition will suffice. This only occurs for the INSERT case; + * UPDATE/DELETE are handled above. + */ + resultRelInfo = mtstate->mt_partitions; + returningList = linitial(node->returningLists); + for (i = 0; i < mtstate->mt_num_partitions; i++) + { + Relation partrel = resultRelInfo->ri_RelationDesc; + List *rlist, + *rliststate; + + /* varno = node->nominalRelation */ + rlist = map_partition_varattnos(returningList, + node->nominalRelation, + partrel, rel); + rliststate = (List *) ExecInitExpr((Expr *) rlist, &mtstate->ps); + resultRelInfo->ri_projectReturning = + ExecBuildProjectionInfo(rliststate, econtext, slot, + resultRelInfo->ri_RelationDesc->rd_att); + resultRelInfo++; + } } else { @@ -1871,7 +2009,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind; if (relkind == RELKIND_RELATION || - relkind == RELKIND_MATVIEW) + relkind == RELKIND_MATVIEW || + relkind == RELKIND_PARTITIONED_TABLE) { j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid"); if (!AttributeNumberIsValid(j->jf_junkAttNo)) @@ -1956,6 +2095,32 @@ ExecEndModifyTable(ModifyTableState *node) resultRelInfo); } + /* Close all the partitioned tables, leaf partitions, and their indices + * + * Remember node->mt_partition_dispatch_info[0] corresponds to the root + * partitioned table, which we must not try to close, because it is the + * main target table of the query that will be closed by ExecEndPlan(). + * Also, tupslot is NULL for the root partitioned table. + */ + for (i = 1; i < node->mt_num_dispatch; i++) + { + PartitionDispatch pd = node->mt_partition_dispatch_info[i]; + + heap_close(pd->reldesc, NoLock); + ExecDropSingleTupleTableSlot(pd->tupslot); + } + for (i = 0; i < node->mt_num_partitions; i++) + { + ResultRelInfo *resultRelInfo = node->mt_partitions + i; + + ExecCloseIndices(resultRelInfo); + heap_close(resultRelInfo->ri_RelationDesc, NoLock); + } + + /* Release the standalone partition tuple descriptor, if any */ + if (node->mt_partition_tuple_slot) + ExecDropSingleTupleTableSlot(node->mt_partition_tuple_slot); + /* * Free the exprcontext */ diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c index 555fa09679..cac7ba1b9b 100644 --- a/src/backend/executor/nodeNestloop.c +++ b/src/backend/executor/nodeNestloop.c @@ -3,7 +3,7 @@ * nodeNestloop.c * routines to support nest-loop joins * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -81,27 +81,9 @@ ExecNestLoop(NestLoopState *node) innerPlan = innerPlanState(node); econtext = node->js.ps.ps_ExprContext; - /* - * Check to see if we're still projecting out tuples from a previous join - * tuple (because there is a function-returning-set in the projection - * expressions). If so, try to project another one. - */ - if (node->js.ps.ps_TupFromTlist) - { - TupleTableSlot *result; - ExprDoneCond isDone; - - result = ExecProject(node->js.ps.ps_ProjInfo, &isDone); - if (isDone == ExprMultipleResult) - return result; - /* Done with that source tuple... */ - node->js.ps.ps_TupFromTlist = false; - } - /* * Reset per-tuple memory context to free any expression evaluation - * storage allocated in the previous tuple cycle. Note this can't happen - * until we're done projecting out tuples from a join tuple. + * storage allocated in the previous tuple cycle. */ ResetExprContext(econtext); @@ -201,19 +183,9 @@ ExecNestLoop(NestLoopState *node) * the slot containing the result tuple using * ExecProject(). */ - TupleTableSlot *result; - ExprDoneCond isDone; - ENL1_printf("qualification succeeded, projecting tuple"); - result = ExecProject(node->js.ps.ps_ProjInfo, &isDone); - - if (isDone != ExprEndResult) - { - node->js.ps.ps_TupFromTlist = - (isDone == ExprMultipleResult); - return result; - } + return ExecProject(node->js.ps.ps_ProjInfo); } else InstrCountFiltered2(node, 1); @@ -259,19 +231,9 @@ ExecNestLoop(NestLoopState *node) * qualification was satisfied so we project and return the * slot containing the result tuple using ExecProject(). */ - TupleTableSlot *result; - ExprDoneCond isDone; - ENL1_printf("qualification succeeded, projecting tuple"); - result = ExecProject(node->js.ps.ps_ProjInfo, &isDone); - - if (isDone != ExprEndResult) - { - node->js.ps.ps_TupFromTlist = - (isDone == ExprMultipleResult); - return result; - } + return ExecProject(node->js.ps.ps_ProjInfo); } else InstrCountFiltered2(node, 1); @@ -377,7 +339,6 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags) /* * finally, wipe the current outer tuple clean. */ - nlstate->js.ps.ps_TupFromTlist = false; nlstate->nl_NeedNewOuter = true; nlstate->nl_MatchedOuter = false; @@ -441,7 +402,6 @@ ExecReScanNestLoop(NestLoopState *node) * outer Vars are used as run-time keys... */ - node->js.ps.ps_TupFromTlist = false; node->nl_NeedNewOuter = true; node->nl_MatchedOuter = false; } diff --git a/src/backend/executor/nodeProjectSet.c b/src/backend/executor/nodeProjectSet.c new file mode 100644 index 0000000000..eae0f1dad9 --- /dev/null +++ b/src/backend/executor/nodeProjectSet.c @@ -0,0 +1,300 @@ +/*------------------------------------------------------------------------- + * + * nodeProjectSet.c + * support for evaluating targetlists containing set-returning functions + * + * DESCRIPTION + * + * ProjectSet nodes are inserted by the planner to evaluate set-returning + * functions in the targetlist. It's guaranteed that all set-returning + * functions are directly at the top level of the targetlist, i.e. they + * can't be inside more-complex expressions. If that'd otherwise be + * the case, the planner adds additional ProjectSet nodes. + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/executor/nodeProjectSet.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "executor/executor.h" +#include "executor/nodeProjectSet.h" +#include "utils/memutils.h" + + +static TupleTableSlot *ExecProjectSRF(ProjectSetState *node, bool continuing); + + +/* ---------------------------------------------------------------- + * ExecProjectSet(node) + * + * Return tuples after evaluating the targetlist (which contains set + * returning functions). + * ---------------------------------------------------------------- + */ +TupleTableSlot * +ExecProjectSet(ProjectSetState *node) +{ + TupleTableSlot *outerTupleSlot; + TupleTableSlot *resultSlot; + PlanState *outerPlan; + ExprContext *econtext; + + econtext = node->ps.ps_ExprContext; + + /* + * Check to see if we're still projecting out tuples from a previous scan + * tuple (because there is a function-returning-set in the projection + * expressions). If so, try to project another one. + */ + if (node->pending_srf_tuples) + { + resultSlot = ExecProjectSRF(node, true); + + if (resultSlot != NULL) + return resultSlot; + } + + /* + * Reset per-tuple memory context to free any expression evaluation + * storage allocated in the previous tuple cycle. Note this can't happen + * until we're done projecting out tuples from a scan tuple. + */ + ResetExprContext(econtext); + + /* + * Get another input tuple and project SRFs from it. + */ + for (;;) + { + /* + * Retrieve tuples from the outer plan until there are no more. + */ + outerPlan = outerPlanState(node); + outerTupleSlot = ExecProcNode(outerPlan); + + if (TupIsNull(outerTupleSlot)) + return NULL; + + /* + * Prepare to compute projection expressions, which will expect to + * access the input tuples as varno OUTER. + */ + econtext->ecxt_outertuple = outerTupleSlot; + + /* Evaluate the expressions */ + resultSlot = ExecProjectSRF(node, false); + + /* + * Return the tuple unless the projection produced no rows (due to an + * empty set), in which case we must loop back to see if there are + * more outerPlan tuples. + */ + if (resultSlot) + return resultSlot; + } + + return NULL; +} + +/* ---------------------------------------------------------------- + * ExecProjectSRF + * + * Project a targetlist containing one or more set-returning functions. + * + * 'continuing' indicates whether to continue projecting rows for the + * same input tuple; or whether a new input tuple is being projected. + * + * Returns NULL if no output tuple has been produced. + * + * ---------------------------------------------------------------- + */ +static TupleTableSlot * +ExecProjectSRF(ProjectSetState *node, bool continuing) +{ + TupleTableSlot *resultSlot = node->ps.ps_ResultTupleSlot; + ExprContext *econtext = node->ps.ps_ExprContext; + bool hassrf PG_USED_FOR_ASSERTS_ONLY = false; + bool hasresult; + int argno; + ListCell *lc; + + ExecClearTuple(resultSlot); + + /* + * Assume no further tuples are produced unless an ExprMultipleResult is + * encountered from a set returning function. + */ + node->pending_srf_tuples = false; + + hasresult = false; + argno = 0; + foreach(lc, node->ps.targetlist) + { + GenericExprState *gstate = (GenericExprState *) lfirst(lc); + ExprDoneCond *isdone = &node->elemdone[argno]; + Datum *result = &resultSlot->tts_values[argno]; + bool *isnull = &resultSlot->tts_isnull[argno]; + + if (continuing && *isdone == ExprEndResult) + { + /* + * If we're continuing to project output rows from a source tuple, + * return NULLs once the SRF has been exhausted. + */ + *result = (Datum) 0; + *isnull = true; + hassrf = true; + } + else if (IsA(gstate->arg, FuncExprState) && + ((FuncExprState *) gstate->arg)->funcReturnsSet) + { + /* + * Evaluate SRF - possibly continuing previously started output. + */ + *result = ExecMakeFunctionResultSet((FuncExprState *) gstate->arg, + econtext, isnull, isdone); + + if (*isdone != ExprEndResult) + hasresult = true; + if (*isdone == ExprMultipleResult) + node->pending_srf_tuples = true; + hassrf = true; + } + else + { + /* Non-SRF tlist expression, just evaluate normally. */ + *result = ExecEvalExpr(gstate->arg, econtext, isnull); + *isdone = ExprSingleResult; + } + + argno++; + } + + /* ProjectSet should not be used if there's no SRFs */ + Assert(hassrf); + + /* + * If all the SRFs returned EndResult, we consider that as no row being + * produced. + */ + if (hasresult) + { + ExecStoreVirtualTuple(resultSlot); + return resultSlot; + } + + return NULL; +} + +/* ---------------------------------------------------------------- + * ExecInitProjectSet + * + * Creates the run-time state information for the ProjectSet node + * produced by the planner and initializes outer relations + * (child nodes). + * ---------------------------------------------------------------- + */ +ProjectSetState * +ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags) +{ + ProjectSetState *state; + + /* check for unsupported flags */ + Assert(!(eflags & (EXEC_FLAG_MARK | EXEC_FLAG_BACKWARD))); + + /* + * create state structure + */ + state = makeNode(ProjectSetState); + state->ps.plan = (Plan *) node; + state->ps.state = estate; + + state->pending_srf_tuples = false; + + /* + * Miscellaneous initialization + * + * create expression context for node + */ + ExecAssignExprContext(estate, &state->ps); + + /* + * tuple table initialization + */ + ExecInitResultTupleSlot(estate, &state->ps); + + /* + * initialize child expressions + */ + state->ps.targetlist = (List *) + ExecInitExpr((Expr *) node->plan.targetlist, + (PlanState *) state); + Assert(node->plan.qual == NIL); + + /* + * initialize child nodes + */ + outerPlanState(state) = ExecInitNode(outerPlan(node), estate, eflags); + + /* + * we don't use inner plan + */ + Assert(innerPlan(node) == NULL); + + /* + * initialize tuple type and projection info + */ + ExecAssignResultTypeFromTL(&state->ps); + + /* Create workspace for per-SRF is-done state */ + state->nelems = list_length(node->plan.targetlist); + state->elemdone = (ExprDoneCond *) + palloc(sizeof(ExprDoneCond) * state->nelems); + + return state; +} + +/* ---------------------------------------------------------------- + * ExecEndProjectSet + * + * frees up storage allocated through C routines + * ---------------------------------------------------------------- + */ +void +ExecEndProjectSet(ProjectSetState *node) +{ + /* + * Free the exprcontext + */ + ExecFreeExprContext(&node->ps); + + /* + * clean out the tuple table + */ + ExecClearTuple(node->ps.ps_ResultTupleSlot); + + /* + * shut down subplans + */ + ExecEndNode(outerPlanState(node)); +} + +void +ExecReScanProjectSet(ProjectSetState *node) +{ + /* Forget any incompletely-evaluated SRFs */ + node->pending_srf_tuples = false; + + /* + * If chgParam of subnode is not null then plan will be re-scanned by + * first ExecProcNode. + */ + if (node->ps.lefttree->chgParam == NULL) + ExecReScan(node->ps.lefttree); +} diff --git a/src/backend/executor/nodeRecursiveunion.c b/src/backend/executor/nodeRecursiveunion.c index e76405a56e..fc1c00d68f 100644 --- a/src/backend/executor/nodeRecursiveunion.c +++ b/src/backend/executor/nodeRecursiveunion.c @@ -3,7 +3,11 @@ * nodeRecursiveunion.c * routines to handle RecursiveUnion nodes. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * To implement UNION (without ALL), we need a hashtable that stores tuples + * already seen. The hash key is computed from the grouping columns. + * + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -20,17 +24,6 @@ #include "utils/memutils.h" -/* - * To implement UNION (without ALL), we need a hashtable that stores tuples - * already seen. The hash key is computed from the grouping columns. - */ -typedef struct RUHashEntryData *RUHashEntry; - -typedef struct RUHashEntryData -{ - TupleHashEntryData shared; /* common header for hash table entries */ -} RUHashEntryData; - /* * Initialize the hash table to empty. @@ -48,9 +41,10 @@ build_hash_table(RecursiveUnionState *rustate) rustate->eqfunctions, rustate->hashfunctions, node->numGroups, - sizeof(RUHashEntryData), + 0, rustate->tableContext, - rustate->tempContext); + rustate->tempContext, + false); } @@ -200,15 +194,11 @@ ExecInitRecursiveUnion(RecursiveUnion *node, EState *estate, int eflags) rustate->tempContext = AllocSetContextCreate(CurrentMemoryContext, "RecursiveUnion", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); rustate->tableContext = AllocSetContextCreate(CurrentMemoryContext, "RecursiveUnion hash table", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); } /* diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c index 4007b765bf..b5b50b21e9 100644 --- a/src/backend/executor/nodeResult.c +++ b/src/backend/executor/nodeResult.c @@ -34,7 +34,7 @@ * plan normally and pass back the results. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -67,10 +67,8 @@ TupleTableSlot * ExecResult(ResultState *node) { TupleTableSlot *outerTupleSlot; - TupleTableSlot *resultSlot; PlanState *outerPlan; ExprContext *econtext; - ExprDoneCond isDone; econtext = node->ps.ps_ExprContext; @@ -91,24 +89,9 @@ ExecResult(ResultState *node) } } - /* - * Check to see if we're still projecting out tuples from a previous scan - * tuple (because there is a function-returning-set in the projection - * expressions). If so, try to project another one. - */ - if (node->ps.ps_TupFromTlist) - { - resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone); - if (isDone == ExprMultipleResult) - return resultSlot; - /* Done with that source tuple... */ - node->ps.ps_TupFromTlist = false; - } - /* * Reset per-tuple memory context to free any expression evaluation - * storage allocated in the previous tuple cycle. Note this can't happen - * until we're done projecting out tuples from a scan tuple. + * storage allocated in the previous tuple cycle. */ ResetExprContext(econtext); @@ -147,18 +130,8 @@ ExecResult(ResultState *node) node->rs_done = true; } - /* - * form the result tuple using ExecProject(), and return it --- unless - * the projection produces an empty set, in which case we must loop - * back to see if there are more outerPlan tuples. - */ - resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone); - - if (isDone != ExprEndResult) - { - node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult); - return resultSlot; - } + /* form the result tuple using ExecProject(), and return it */ + return ExecProject(node->ps.ps_ProjInfo); } return NULL; @@ -228,8 +201,6 @@ ExecInitResult(Result *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &resstate->ps); - resstate->ps.ps_TupFromTlist = false; - /* * tuple table initialization */ @@ -295,7 +266,6 @@ void ExecReScanResult(ResultState *node) { node->rs_done = false; - node->ps.ps_TupFromTlist = false; node->rs_checkqual = (node->resconstantqual == NULL) ? false : true; /* diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c index 9ce7c02aff..d38265e810 100644 --- a/src/backend/executor/nodeSamplescan.c +++ b/src/backend/executor/nodeSamplescan.c @@ -3,7 +3,7 @@ * nodeSamplescan.c * Support routines for sample scans of relations (table sampling). * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -22,6 +22,7 @@ #include "miscadmin.h" #include "pgstat.h" #include "storage/predicate.h" +#include "utils/builtins.h" #include "utils/rel.h" #include "utils/tqual.h" @@ -188,8 +189,6 @@ ExecInitSampleScan(SampleScan *node, EState *estate, int eflags) */ InitScanRelation(scanstate, estate, eflags); - scanstate->ss.ps.ps_TupFromTlist = false; - /* * Initialize result tuple type and projection info. */ @@ -299,8 +298,7 @@ tablesample_init(SampleScanState *scanstate) params[i] = ExecEvalExprSwitchContext(argstate, econtext, - &isnull, - NULL); + &isnull); if (isnull) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLESAMPLE_ARGUMENT), @@ -312,8 +310,7 @@ tablesample_init(SampleScanState *scanstate) { datum = ExecEvalExprSwitchContext(scanstate->repeatable, econtext, - &isnull, - NULL); + &isnull); if (isnull) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLESAMPLE_REPEAT), diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c index 00bf3a58b1..e61895de0a 100644 --- a/src/backend/executor/nodeSeqscan.c +++ b/src/backend/executor/nodeSeqscan.c @@ -3,7 +3,7 @@ * nodeSeqscan.c * Support routines for sequential scans of relations. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -206,8 +206,6 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags) */ InitScanRelation(scanstate, estate, eflags); - scanstate->ss.ps.ps_TupFromTlist = false; - /* * Initialize result tuple type and projection info. */ diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c index 2d81d46927..85b3f67b33 100644 --- a/src/backend/executor/nodeSetOp.c +++ b/src/backend/executor/nodeSetOp.c @@ -32,7 +32,7 @@ * input group. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -66,19 +66,6 @@ typedef struct SetOpStatePerGroupData long numRight; /* number of right-input dups in group */ } SetOpStatePerGroupData; -/* - * To implement hashed mode, we need a hashtable that stores a - * representative tuple and the duplicate counts for each distinct set - * of grouping columns. We compute the hash key from the grouping columns. - */ -typedef struct SetOpHashEntryData *SetOpHashEntry; - -typedef struct SetOpHashEntryData -{ - TupleHashEntryData shared; /* common header for hash table entries */ - SetOpStatePerGroupData pergroup; -} SetOpHashEntryData; - static TupleTableSlot *setop_retrieve_direct(SetOpState *setopstate); static void setop_fill_hash_table(SetOpState *setopstate); @@ -141,9 +128,10 @@ build_hash_table(SetOpState *setopstate) setopstate->eqfunctions, setopstate->hashfunctions, node->numGroups, - sizeof(SetOpHashEntryData), + 0, setopstate->tableContext, - setopstate->tempContext); + setopstate->tempContext, + false); } /* @@ -238,7 +226,7 @@ setop_retrieve_direct(SetOpState *setopstate) * get state info from node */ outerPlan = outerPlanState(setopstate); - pergroup = setopstate->pergroup; + pergroup = (SetOpStatePerGroup) setopstate->pergroup; resultTupleSlot = setopstate->ps.ps_ResultTupleSlot; /* @@ -367,7 +355,7 @@ setop_fill_hash_table(SetOpState *setopstate) { TupleTableSlot *outerslot; int flag; - SetOpHashEntry entry; + TupleHashEntryData *entry; bool isnew; outerslot = ExecProcNode(outerPlan); @@ -383,15 +371,20 @@ setop_fill_hash_table(SetOpState *setopstate) Assert(in_first_rel); /* Find or build hashtable entry for this tuple's group */ - entry = (SetOpHashEntry) - LookupTupleHashEntry(setopstate->hashtable, outerslot, &isnew); + entry = LookupTupleHashEntry(setopstate->hashtable, outerslot, + &isnew); /* If new tuple group, initialize counts */ if (isnew) - initialize_counts(&entry->pergroup); + { + entry->additional = (SetOpStatePerGroup) + MemoryContextAlloc(setopstate->hashtable->tablecxt, + sizeof(SetOpStatePerGroupData)); + initialize_counts((SetOpStatePerGroup) entry->additional); + } /* Advance the counts */ - advance_counts(&entry->pergroup, flag); + advance_counts((SetOpStatePerGroup) entry->additional, flag); } else { @@ -399,12 +392,12 @@ setop_fill_hash_table(SetOpState *setopstate) in_first_rel = false; /* For tuples not seen previously, do not make hashtable entry */ - entry = (SetOpHashEntry) - LookupTupleHashEntry(setopstate->hashtable, outerslot, NULL); + entry = LookupTupleHashEntry(setopstate->hashtable, outerslot, + NULL); /* Advance the counts if entry is already present */ if (entry) - advance_counts(&entry->pergroup, flag); + advance_counts((SetOpStatePerGroup) entry->additional, flag); } /* Must reset temp context after each hashtable lookup */ @@ -422,7 +415,7 @@ setop_fill_hash_table(SetOpState *setopstate) static TupleTableSlot * setop_retrieve_hash_table(SetOpState *setopstate) { - SetOpHashEntry entry; + TupleHashEntryData *entry; TupleTableSlot *resultTupleSlot; /* @@ -438,7 +431,7 @@ setop_retrieve_hash_table(SetOpState *setopstate) /* * Find the next entry in the hash table */ - entry = (SetOpHashEntry) ScanTupleHashTable(&setopstate->hashiter); + entry = ScanTupleHashTable(setopstate->hashtable, &setopstate->hashiter); if (entry == NULL) { /* No more entries in hashtable, so done */ @@ -450,12 +443,12 @@ setop_retrieve_hash_table(SetOpState *setopstate) * See if we should emit any copies of this tuple, and if so return * the first copy. */ - set_output_count(setopstate, &entry->pergroup); + set_output_count(setopstate, (SetOpStatePerGroup) entry->additional); if (setopstate->numOutput > 0) { setopstate->numOutput--; - return ExecStoreMinimalTuple(entry->shared.firstTuple, + return ExecStoreMinimalTuple(entry->firstTuple, resultTupleSlot, false); } @@ -507,9 +500,7 @@ ExecInitSetOp(SetOp *node, EState *estate, int eflags) setopstate->tempContext = AllocSetContextCreate(CurrentMemoryContext, "SetOp", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* * If hashing, we also need a longer-lived context to store the hash @@ -520,9 +511,7 @@ ExecInitSetOp(SetOp *node, EState *estate, int eflags) setopstate->tableContext = AllocSetContextCreate(CurrentMemoryContext, "SetOp hash table", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* * Tuple table initialization diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c index a34dcc5135..591a31aa6a 100644 --- a/src/backend/executor/nodeSort.c +++ b/src/backend/executor/nodeSort.c @@ -3,7 +3,7 @@ * nodeSort.c * Routines to handle sorting of relations. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c index e503494edd..f8a2cd446a 100644 --- a/src/backend/executor/nodeSubplan.c +++ b/src/backend/executor/nodeSubplan.c @@ -11,7 +11,7 @@ * subplans, which are re-evaluated every time their result is required. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -41,12 +41,10 @@ static Datum ExecSubPlan(SubPlanState *node, ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone); + bool *isNull); static Datum ExecAlternativeSubPlan(AlternativeSubPlanState *node, ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone); + bool *isNull); static Datum ExecHashSubPlan(SubPlanState *node, ExprContext *econtext, bool *isNull); @@ -69,15 +67,12 @@ static bool slotNoNulls(TupleTableSlot *slot); static Datum ExecSubPlan(SubPlanState *node, ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) + bool *isNull) { SubPlan *subplan = (SubPlan *) node->xprstate.expr; - /* Set default values for result flags: non-null, not a set result */ + /* Set non-null as default */ *isNull = false; - if (isDone) - *isDone = ExprSingleResult; /* Sanity checks */ if (subplan->subLinkType == CTE_SUBLINK) @@ -128,7 +123,7 @@ ExecHashSubPlan(SubPlanState *node, * have to set the econtext to use (hack alert!). */ node->projLeft->pi_exprContext = econtext; - slot = ExecProject(node->projLeft, NULL); + slot = ExecProject(node->projLeft); /* * Note: because we are typically called in a per-tuple context, we have @@ -285,8 +280,7 @@ ExecScanSubPlan(SubPlanState *node, prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar), econtext, - &(prm->isnull), - NULL); + &(prm->isnull)); planstate->chgParam = bms_add_member(planstate->chgParam, paramid); } @@ -403,7 +397,7 @@ ExecScanSubPlan(SubPlanState *node, } rowresult = ExecEvalExprSwitchContext(node->testexpr, econtext, - &rownull, NULL); + &rownull); if (subLinkType == ANY_SUBLINK) { @@ -508,9 +502,10 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext) node->tab_eq_funcs, node->tab_hash_funcs, nbuckets, - sizeof(TupleHashEntryData), + 0, node->hashtablecxt, - node->hashtempcxt); + node->hashtempcxt, + false); if (!subplan->unknownEqFalse) { @@ -527,9 +522,10 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext) node->tab_eq_funcs, node->tab_hash_funcs, nbuckets, - sizeof(TupleHashEntryData), + 0, node->hashtablecxt, - node->hashtempcxt); + node->hashtempcxt, + false); } /* @@ -570,7 +566,7 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext) &(prmdata->isnull)); col++; } - slot = ExecProject(node->projRight, NULL); + slot = ExecProject(node->projRight); /* * If result contains any nulls, store separately or not at all. @@ -626,7 +622,7 @@ findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot, TupleHashEntry entry; InitTupleHashIterator(hashtable, &hashiter); - while ((entry = ScanTupleHashTable(&hashiter)) != NULL) + while ((entry = ScanTupleHashTable(hashtable, &hashiter)) != NULL) { ExecStoreMinimalTuple(entry->firstTuple, hashtable->tableslot, false); if (!execTuplesUnequal(slot, hashtable->tableslot, @@ -776,16 +772,12 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent) sstate->hashtablecxt = AllocSetContextCreate(CurrentMemoryContext, "Subplan HashTable Context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* and a small one for the hash tables to use as temp storage */ sstate->hashtempcxt = AllocSetContextCreate(CurrentMemoryContext, "Subplan HashTable Temp Context", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MAXSIZE); + ALLOCSET_SMALL_SIZES); /* and a short-lived exprcontext for function evaluation */ sstate->innerecontext = CreateExprContext(estate); /* Silly little array of column numbers 1..n */ @@ -987,8 +979,7 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext) prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar), econtext, - &(prm->isnull), - NULL); + &(prm->isnull)); planstate->chgParam = bms_add_member(planstate->chgParam, paramid); } @@ -1224,8 +1215,7 @@ ExecInitAlternativeSubPlan(AlternativeSubPlan *asplan, PlanState *parent) static Datum ExecAlternativeSubPlan(AlternativeSubPlanState *node, ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) + bool *isNull) { /* Just pass control to the active subplan */ SubPlanState *activesp = (SubPlanState *) list_nth(node->subplans, @@ -1233,8 +1223,5 @@ ExecAlternativeSubPlan(AlternativeSubPlanState *node, Assert(IsA(activesp, SubPlanState)); - return ExecSubPlan(activesp, - econtext, - isNull, - isDone); + return ExecSubPlan(activesp, econtext, isNull); } diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c index 9bafc62677..230a96f9d2 100644 --- a/src/backend/executor/nodeSubqueryscan.c +++ b/src/backend/executor/nodeSubqueryscan.c @@ -7,7 +7,7 @@ * we need two sets of code. Ought to look at trying to unify the cases. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -138,8 +138,6 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags) */ subquerystate->subplan = ExecInitNode(node->subplan, estate, eflags); - subquerystate->ss.ps.ps_TupFromTlist = false; - /* * Initialize scan tuple type (needed by ExecAssignScanProjectionInfo) */ diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c index 2604103352..13ed886577 100644 --- a/src/backend/executor/nodeTidscan.c +++ b/src/backend/executor/nodeTidscan.c @@ -3,7 +3,7 @@ * nodeTidscan.c * Routines to support direct tid scans of relations * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -104,8 +104,7 @@ TidListCreate(TidScanState *tidstate) itemptr = (ItemPointer) DatumGetPointer(ExecEvalExprSwitchContext(exstate, econtext, - &isNull, - NULL)); + &isNull)); if (!isNull && ItemPointerIsValid(itemptr) && ItemPointerGetBlockNumber(itemptr) < nblocks) @@ -133,13 +132,12 @@ TidListCreate(TidScanState *tidstate) exstate = (ExprState *) lsecond(saexstate->fxprstate.args); arraydatum = ExecEvalExprSwitchContext(exstate, econtext, - &isNull, - NULL); + &isNull); if (isNull) continue; itemarray = DatumGetArrayTypeP(arraydatum); deconstruct_array(itemarray, - TIDOID, SizeOfIptrData, false, 's', + TIDOID, sizeof(ItemPointerData), false, 's', &ipdatums, &ipnulls, &ndatums); if (numTids + ndatums > numAllocTids) { @@ -469,8 +467,6 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags) */ ExecAssignExprContext(estate, &tidstate->ss.ps); - tidstate->ss.ps.ps_TupFromTlist = false; - /* * initialize child expressions */ diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c index 4caae34b97..28cc1e90f8 100644 --- a/src/backend/executor/nodeUnique.c +++ b/src/backend/executor/nodeUnique.c @@ -11,7 +11,7 @@ * (It's debatable whether the savings justifies carrying two plan node * types, though.) * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -133,9 +133,7 @@ ExecInitUnique(Unique *node, EState *estate, int eflags) uniquestate->tempContext = AllocSetContextCreate(CurrentMemoryContext, "Unique", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* * Tuple table initialization diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c index 9c03f8ae16..9883a8b130 100644 --- a/src/backend/executor/nodeValuesscan.c +++ b/src/backend/executor/nodeValuesscan.c @@ -4,7 +4,7 @@ * Support routines for scanning Values lists * ("VALUES (...), (...), ..." in rangetable). * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -140,8 +140,7 @@ ValuesNext(ValuesScanState *node) values[resind] = ExecEvalExpr(estate, econtext, - &isnull[resind], - NULL); + &isnull[resind]); /* * We must force any R/W expanded datums to read-only state, in @@ -272,8 +271,6 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags) scanstate->exprlists[i++] = (List *) lfirst(vtl); } - scanstate->ss.ps.ps_TupFromTlist = false; - /* * Initialize result tuple type and projection info. */ diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index d4c88a1f0e..6ac6b83cdd 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -23,7 +23,7 @@ * aggregate function over all rows in the current row's window frame. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -256,7 +256,7 @@ advance_windowaggregate(WindowAggState *winstate, if (filter) { bool isnull; - Datum res = ExecEvalExpr(filter, econtext, &isnull, NULL); + Datum res = ExecEvalExpr(filter, econtext, &isnull); if (isnull || !DatumGetBool(res)) { @@ -272,7 +272,7 @@ advance_windowaggregate(WindowAggState *winstate, ExprState *argstate = (ExprState *) lfirst(arg); fcinfo->arg[i] = ExecEvalExpr(argstate, econtext, - &fcinfo->argnull[i], NULL); + &fcinfo->argnull[i]); i++; } @@ -362,8 +362,10 @@ advance_windowaggregate(WindowAggState *winstate, /* * If pass-by-ref datatype, must copy the new value into aggcontext and - * pfree the prior transValue. But if transfn returned a pointer to its - * first input, we don't need to do anything. + * free the prior transValue. But if transfn returned a pointer to its + * first input, we don't need to do anything. Also, if transfn returned a + * pointer to a R/W expanded object that is already a child of the + * aggcontext, assume we can adopt that value without copying it. */ if (!peraggstate->transtypeByVal && DatumGetPointer(newVal) != DatumGetPointer(peraggstate->transValue)) @@ -371,12 +373,25 @@ advance_windowaggregate(WindowAggState *winstate, if (!fcinfo->isnull) { MemoryContextSwitchTo(peraggstate->aggcontext); - newVal = datumCopy(newVal, - peraggstate->transtypeByVal, - peraggstate->transtypeLen); + if (DatumIsReadWriteExpandedObject(newVal, + false, + peraggstate->transtypeLen) && + MemoryContextGetParent(DatumGetEOHP(newVal)->eoh_context) == CurrentMemoryContext) + /* do nothing */ ; + else + newVal = datumCopy(newVal, + peraggstate->transtypeByVal, + peraggstate->transtypeLen); } if (!peraggstate->transValueIsNull) - pfree(DatumGetPointer(peraggstate->transValue)); + { + if (DatumIsReadWriteExpandedObject(peraggstate->transValue, + false, + peraggstate->transtypeLen)) + DeleteExpandedObject(peraggstate->transValue); + else + pfree(DatumGetPointer(peraggstate->transValue)); + } } MemoryContextSwitchTo(oldContext); @@ -418,7 +433,7 @@ advance_windowaggregate_base(WindowAggState *winstate, if (filter) { bool isnull; - Datum res = ExecEvalExpr(filter, econtext, &isnull, NULL); + Datum res = ExecEvalExpr(filter, econtext, &isnull); if (isnull || !DatumGetBool(res)) { @@ -434,7 +449,7 @@ advance_windowaggregate_base(WindowAggState *winstate, ExprState *argstate = (ExprState *) lfirst(arg); fcinfo->arg[i] = ExecEvalExpr(argstate, econtext, - &fcinfo->argnull[i], NULL); + &fcinfo->argnull[i]); i++; } @@ -513,8 +528,10 @@ advance_windowaggregate_base(WindowAggState *winstate, /* * If pass-by-ref datatype, must copy the new value into aggcontext and - * pfree the prior transValue. But if invtransfn returned a pointer to - * its first input, we don't need to do anything. + * free the prior transValue. But if invtransfn returned a pointer to its + * first input, we don't need to do anything. Also, if invtransfn + * returned a pointer to a R/W expanded object that is already a child of + * the aggcontext, assume we can adopt that value without copying it. * * Note: the checks for null values here will never fire, but it seems * best to have this stanza look just like advance_windowaggregate. @@ -525,12 +542,25 @@ advance_windowaggregate_base(WindowAggState *winstate, if (!fcinfo->isnull) { MemoryContextSwitchTo(peraggstate->aggcontext); - newVal = datumCopy(newVal, - peraggstate->transtypeByVal, - peraggstate->transtypeLen); + if (DatumIsReadWriteExpandedObject(newVal, + false, + peraggstate->transtypeLen) && + MemoryContextGetParent(DatumGetEOHP(newVal)->eoh_context) == CurrentMemoryContext) + /* do nothing */ ; + else + newVal = datumCopy(newVal, + peraggstate->transtypeByVal, + peraggstate->transtypeLen); } if (!peraggstate->transValueIsNull) - pfree(DatumGetPointer(peraggstate->transValue)); + { + if (DatumIsReadWriteExpandedObject(peraggstate->transValue, + false, + peraggstate->transtypeLen)) + DeleteExpandedObject(peraggstate->transValue); + else + pfree(DatumGetPointer(peraggstate->transValue)); + } } MemoryContextSwitchTo(oldContext); @@ -568,7 +598,9 @@ finalize_windowaggregate(WindowAggState *winstate, numFinalArgs, perfuncstate->winCollation, (void *) winstate, NULL); - fcinfo.arg[0] = peraggstate->transValue; + fcinfo.arg[0] = MakeExpandedObjectReadOnly(peraggstate->transValue, + peraggstate->transValueIsNull, + peraggstate->transtypeLen); fcinfo.argnull[0] = peraggstate->transValueIsNull; anynull = peraggstate->transValueIsNull; @@ -596,6 +628,7 @@ finalize_windowaggregate(WindowAggState *winstate, } else { + /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */ *result = peraggstate->transValue; *isnull = peraggstate->transValueIsNull; } @@ -1551,15 +1584,12 @@ update_frametailpos(WindowObject winobj, TupleTableSlot *slot) * ExecWindowAgg receives tuples from its outer subplan and * stores them into a tuplestore, then processes window functions. * This node doesn't reduce nor qualify any row so the number of - * returned rows is exactly the same as its outer subplan's result - * (ignoring the case of SRFs in the targetlist, that is). + * returned rows is exactly the same as its outer subplan's result. * ----------------- */ TupleTableSlot * ExecWindowAgg(WindowAggState *winstate) { - TupleTableSlot *result; - ExprDoneCond isDone; ExprContext *econtext; int i; int numfuncs; @@ -1567,23 +1597,6 @@ ExecWindowAgg(WindowAggState *winstate) if (winstate->all_done) return NULL; - /* - * Check to see if we're still projecting out tuples from a previous - * output tuple (because there is a function-returning-set in the - * projection expressions). If so, try to project another one. - */ - if (winstate->ss.ps.ps_TupFromTlist) - { - TupleTableSlot *result; - ExprDoneCond isDone; - - result = ExecProject(winstate->ss.ps.ps_ProjInfo, &isDone); - if (isDone == ExprMultipleResult) - return result; - /* Done with that source tuple... */ - winstate->ss.ps.ps_TupFromTlist = false; - } - /* * Compute frame offset values, if any, during first call. */ @@ -1601,8 +1614,7 @@ ExecWindowAgg(WindowAggState *winstate) Assert(winstate->startOffset != NULL); value = ExecEvalExprSwitchContext(winstate->startOffset, econtext, - &isnull, - NULL); + &isnull); if (isnull) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), @@ -1627,8 +1639,7 @@ ExecWindowAgg(WindowAggState *winstate) Assert(winstate->endOffset != NULL); value = ExecEvalExprSwitchContext(winstate->endOffset, econtext, - &isnull, - NULL); + &isnull); if (isnull) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), @@ -1651,7 +1662,6 @@ ExecWindowAgg(WindowAggState *winstate) winstate->all_first = false; } -restart: if (winstate->buffer == NULL) { /* Initialize for first partition and set current row = 0 */ @@ -1743,17 +1753,8 @@ ExecWindowAgg(WindowAggState *winstate) * evaluated with respect to that row. */ econtext->ecxt_outertuple = winstate->ss.ss_ScanTupleSlot; - result = ExecProject(winstate->ss.ps.ps_ProjInfo, &isDone); - if (isDone == ExprEndResult) - { - /* SRF in tlist returned no rows, so advance to next input tuple */ - goto restart; - } - - winstate->ss.ps.ps_TupFromTlist = - (isDone == ExprMultipleResult); - return result; + return ExecProject(winstate->ss.ps.ps_ProjInfo); } /* ----------------- @@ -1801,10 +1802,8 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags) /* Create long-lived context for storage of partition-local memory etc */ winstate->partcontext = AllocSetContextCreate(CurrentMemoryContext, - "WindowAgg_Partition", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + "WindowAgg Partition", + ALLOCSET_DEFAULT_SIZES); /* * Create mid-lived context for aggregate trans values etc. @@ -1814,10 +1813,8 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags) */ winstate->aggcontext = AllocSetContextCreate(CurrentMemoryContext, - "WindowAgg_Aggregates", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + "WindowAgg Aggregates", + ALLOCSET_DEFAULT_SIZES); /* * tuple table initialization @@ -1867,8 +1864,6 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags) ExecAssignResultTypeFromTL(&winstate->ss.ps); ExecAssignProjectionInfo(&winstate->ss.ps, NULL); - winstate->ss.ps.ps_TupFromTlist = false; - /* Set up data for comparing tuples */ if (node->partNumCols > 0) winstate->partEqfunctions = execTuplesMatchPrepare(node->partNumCols, @@ -2061,8 +2056,6 @@ ExecReScanWindowAgg(WindowAggState *node) ExprContext *econtext = node->ss.ps.ps_ExprContext; node->all_done = false; - - node->ss.ps.ps_TupFromTlist = false; node->all_first = true; /* release tuplestore et al */ @@ -2222,7 +2215,7 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc, numArguments, 0, /* no ordered-set window functions yet */ false, /* no variadic window functions yet */ - wfunc->wintype, + aggtranstype, wfunc->inputcollid, transfn_oid, invtransfn_oid, @@ -2321,10 +2314,8 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc, if (OidIsValid(invtransfn_oid)) peraggstate->aggcontext = AllocSetContextCreate(CurrentMemoryContext, - "WindowAgg_AggregatePrivate", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + "WindowAgg Per Aggregate", + ALLOCSET_DEFAULT_SIZES); else peraggstate->aggcontext = winstate->aggcontext; @@ -2685,7 +2676,7 @@ WinGetFuncArgInPartition(WindowObject winobj, int argno, } econtext->ecxt_outertuple = slot; return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno), - econtext, isnull, NULL); + econtext, isnull); } } @@ -2784,7 +2775,7 @@ WinGetFuncArgInFrame(WindowObject winobj, int argno, } econtext->ecxt_outertuple = slot; return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno), - econtext, isnull, NULL); + econtext, isnull); } } @@ -2814,5 +2805,5 @@ WinGetFuncArgCurrent(WindowObject winobj, int argno, bool *isnull) econtext->ecxt_outertuple = winstate->ss.ss_ScanTupleSlot; return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno), - econtext, isnull, NULL); + econtext, isnull); } diff --git a/src/backend/executor/nodeWorktablescan.c b/src/backend/executor/nodeWorktablescan.c index cfed6e6329..bdba9e0bfc 100644 --- a/src/backend/executor/nodeWorktablescan.c +++ b/src/backend/executor/nodeWorktablescan.c @@ -3,7 +3,7 @@ * nodeWorktablescan.c * routines to handle WorkTableScan nodes. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -174,8 +174,6 @@ ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags) */ ExecAssignResultTypeFromTL(&scanstate->ss.ps); - scanstate->ss.ps.ps_TupFromTlist = false; - return scanstate; } diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 38de18006d..7bd37283b7 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -3,7 +3,7 @@ * spi.c * Server Programming Interface * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -44,8 +44,7 @@ int SPI_result; static _SPI_connection *_SPI_stack = NULL; static _SPI_connection *_SPI_current = NULL; static int _SPI_stack_depth = 0; /* allocated size of _SPI_stack */ -static int _SPI_connected = -1; -static int _SPI_curid = -1; +static int _SPI_connected = -1; /* current stack index */ static Portal SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, ParamListInfo paramLI, bool read_only); @@ -86,13 +85,7 @@ SPI_connect(void) { int newdepth; - /* - * When procedure called by Executor _SPI_curid expected to be equal to - * _SPI_connected - */ - if (_SPI_curid != _SPI_connected) - return SPI_ERROR_CONNECT; - + /* Enlarge stack if necessary */ if (_SPI_stack == NULL) { if (_SPI_connected != -1 || _SPI_stack_depth != 0) @@ -117,9 +110,7 @@ SPI_connect(void) } } - /* - * We're entering procedure where _SPI_curid == _SPI_connected - 1 - */ + /* Enter new stack level */ _SPI_connected++; Assert(_SPI_connected >= 0 && _SPI_connected < _SPI_stack_depth); @@ -142,14 +133,10 @@ SPI_connect(void) */ _SPI_current->procCxt = AllocSetContextCreate(TopTransactionContext, "SPI Proc", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); _SPI_current->execCxt = AllocSetContextCreate(TopTransactionContext, "SPI Exec", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* ... and switch to procedure's context */ _SPI_current->savedcxt = MemoryContextSwitchTo(_SPI_current->procCxt); @@ -182,14 +169,9 @@ SPI_finish(void) SPI_lastoid = InvalidOid; SPI_tuptable = NULL; - /* - * After _SPI_begin_call _SPI_connected == _SPI_curid. Now we are closing - * connection to SPI and returning to upper Executor and so _SPI_connected - * must be equal to _SPI_curid. - */ + /* Exit stack level */ _SPI_connected--; - _SPI_curid--; - if (_SPI_connected == -1) + if (_SPI_connected < 0) _SPI_current = NULL; else _SPI_current = &(_SPI_stack[_SPI_connected]); @@ -216,7 +198,7 @@ AtEOXact_SPI(bool isCommit) _SPI_current = _SPI_stack = NULL; _SPI_stack_depth = 0; - _SPI_connected = _SPI_curid = -1; + _SPI_connected = -1; SPI_processed = 0; SPI_lastoid = InvalidOid; SPI_tuptable = NULL; @@ -262,8 +244,7 @@ AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid) * be already gone. */ _SPI_connected--; - _SPI_curid = _SPI_connected; - if (_SPI_connected == -1) + if (_SPI_connected < 0) _SPI_current = NULL; else _SPI_current = &(_SPI_stack[_SPI_connected]); @@ -317,53 +298,6 @@ AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid) } -/* Pushes SPI stack to allow recursive SPI calls */ -void -SPI_push(void) -{ - _SPI_curid++; -} - -/* Pops SPI stack to allow recursive SPI calls */ -void -SPI_pop(void) -{ - _SPI_curid--; -} - -/* Conditional push: push only if we're inside a SPI procedure */ -bool -SPI_push_conditional(void) -{ - bool pushed = (_SPI_curid != _SPI_connected); - - if (pushed) - { - _SPI_curid++; - /* We should now be in a state where SPI_connect would succeed */ - Assert(_SPI_curid == _SPI_connected); - } - return pushed; -} - -/* Conditional pop: pop only if SPI_push_conditional pushed */ -void -SPI_pop_conditional(bool pushed) -{ - /* We should be in a state where SPI_connect would succeed */ - Assert(_SPI_curid == _SPI_connected); - if (pushed) - _SPI_curid--; -} - -/* Restore state of SPI stack after aborting a subtransaction */ -void -SPI_restore_connection(void) -{ - Assert(_SPI_connected >= 0); - _SPI_curid = _SPI_connected - 1; -} - /* Parse, plan, and execute a query string */ int SPI_execute(const char *src, bool read_only, long tcount) @@ -695,7 +629,7 @@ SPI_freeplan(SPIPlanPtr plan) HeapTuple SPI_copytuple(HeapTuple tuple) { - MemoryContext oldcxt = NULL; + MemoryContext oldcxt; HeapTuple ctuple; if (tuple == NULL) @@ -704,17 +638,17 @@ SPI_copytuple(HeapTuple tuple) return NULL; } - if (_SPI_curid + 1 == _SPI_connected) /* connected */ + if (_SPI_current == NULL) { - if (_SPI_current != &(_SPI_stack[_SPI_curid + 1])) - elog(ERROR, "SPI stack corrupted"); - oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt); + SPI_result = SPI_ERROR_UNCONNECTED; + return NULL; } + oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt); + ctuple = heap_copytuple(tuple); - if (oldcxt) - MemoryContextSwitchTo(oldcxt); + MemoryContextSwitchTo(oldcxt); return ctuple; } @@ -722,7 +656,7 @@ SPI_copytuple(HeapTuple tuple) HeapTupleHeader SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc) { - MemoryContext oldcxt = NULL; + MemoryContext oldcxt; HeapTupleHeader dtup; if (tuple == NULL || tupdesc == NULL) @@ -731,22 +665,22 @@ SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc) return NULL; } + if (_SPI_current == NULL) + { + SPI_result = SPI_ERROR_UNCONNECTED; + return NULL; + } + /* For RECORD results, make sure a typmod has been assigned */ if (tupdesc->tdtypeid == RECORDOID && tupdesc->tdtypmod < 0) assign_record_type_typmod(tupdesc); - if (_SPI_curid + 1 == _SPI_connected) /* connected */ - { - if (_SPI_current != &(_SPI_stack[_SPI_curid + 1])) - elog(ERROR, "SPI stack corrupted"); - oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt); - } + oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt); dtup = DatumGetHeapTupleHeader(heap_copy_tuple_as_datum(tuple, tupdesc)); - if (oldcxt) - MemoryContextSwitchTo(oldcxt); + MemoryContextSwitchTo(oldcxt); return dtup; } @@ -755,7 +689,7 @@ HeapTuple SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum, Datum *Values, const char *Nulls) { - MemoryContext oldcxt = NULL; + MemoryContext oldcxt; HeapTuple mtuple; int numberOfAttributes; Datum *v; @@ -768,13 +702,16 @@ SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum, return NULL; } - if (_SPI_curid + 1 == _SPI_connected) /* connected */ + if (_SPI_current == NULL) { - if (_SPI_current != &(_SPI_stack[_SPI_curid + 1])) - elog(ERROR, "SPI stack corrupted"); - oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt); + SPI_result = SPI_ERROR_UNCONNECTED; + return NULL; } + + oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt); + SPI_result = 0; + numberOfAttributes = rel->rd_att->natts; v = (Datum *) palloc(numberOfAttributes * sizeof(Datum)); n = (bool *) palloc(numberOfAttributes * sizeof(bool)); @@ -814,8 +751,7 @@ SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum, pfree(v); pfree(n); - if (oldcxt) - MemoryContextSwitchTo(oldcxt); + MemoryContextSwitchTo(oldcxt); return mtuple; } @@ -828,7 +764,8 @@ SPI_fnumber(TupleDesc tupdesc, const char *fname) for (res = 0; res < tupdesc->natts; res++) { - if (namestrcmp(&tupdesc->attrs[res]->attname, fname) == 0) + if (namestrcmp(&tupdesc->attrs[res]->attname, fname) == 0 && + !tupdesc->attrs[res]->attisdropped) return res + 1; } @@ -983,22 +920,10 @@ SPI_getnspname(Relation rel) void * SPI_palloc(Size size) { - MemoryContext oldcxt = NULL; - void *pointer; - - if (_SPI_curid + 1 == _SPI_connected) /* connected */ - { - if (_SPI_current != &(_SPI_stack[_SPI_curid + 1])) - elog(ERROR, "SPI stack corrupted"); - oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt); - } + if (_SPI_current == NULL) + elog(ERROR, "SPI_palloc called while not connected to SPI"); - pointer = palloc(size); - - if (oldcxt) - MemoryContextSwitchTo(oldcxt); - - return pointer; + return MemoryContextAlloc(_SPI_current->savedcxt, size); } void * @@ -1018,20 +943,17 @@ SPI_pfree(void *pointer) Datum SPI_datumTransfer(Datum value, bool typByVal, int typLen) { - MemoryContext oldcxt = NULL; + MemoryContext oldcxt; Datum result; - if (_SPI_curid + 1 == _SPI_connected) /* connected */ - { - if (_SPI_current != &(_SPI_stack[_SPI_curid + 1])) - elog(ERROR, "SPI stack corrupted"); - oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt); - } + if (_SPI_current == NULL) + elog(ERROR, "SPI_datumTransfer called while not connected to SPI"); + + oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt); result = datumTransfer(value, typByVal, typLen); - if (oldcxt) - MemoryContextSwitchTo(oldcxt); + MemoryContextSwitchTo(oldcxt); return result; } @@ -1053,17 +975,12 @@ SPI_freetuptable(SPITupleTable *tuptable) return; /* - * Since this function might be called during error recovery, it seems - * best not to insist that the caller be actively connected. We just - * search the topmost SPI context, connected or not. + * Search only the topmost SPI context for a matching tuple table. */ - if (_SPI_connected >= 0) + if (_SPI_current != NULL) { slist_mutable_iter siter; - if (_SPI_current != &(_SPI_stack[_SPI_connected])) - elog(ERROR, "SPI stack corrupted"); - /* find tuptable in active list, then remove it */ slist_foreach_modify(siter, &_SPI_current->tuptables) { @@ -1171,13 +1088,9 @@ SPI_cursor_open_with_args(const char *name, /* We needn't copy the plan; SPI_cursor_open_internal will do so */ - /* Adjust stack so that SPI_cursor_open_internal doesn't complain */ - _SPI_curid--; - result = SPI_cursor_open_internal(name, &plan, paramLI, read_only); /* And clean up */ - _SPI_curid++; _SPI_end_call(true); return result; @@ -1319,7 +1232,7 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, if (!(portal->cursorOptions & (CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL))) { if (list_length(stmt_list) == 1 && - IsA((Node *) linitial(stmt_list), PlannedStmt) && + ((PlannedStmt *) linitial(stmt_list))->commandType != CMD_UTILITY && ((PlannedStmt *) linitial(stmt_list))->rowMarks == NIL && ExecSupportsBackwardScan(((PlannedStmt *) linitial(stmt_list))->planTree)) portal->cursorOptions |= CURSOR_OPT_SCROLL; @@ -1335,7 +1248,7 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, if (portal->cursorOptions & CURSOR_OPT_SCROLL) { if (list_length(stmt_list) == 1 && - IsA((Node *) linitial(stmt_list), PlannedStmt) && + ((PlannedStmt *) linitial(stmt_list))->commandType != CMD_UTILITY && ((PlannedStmt *) linitial(stmt_list))->rowMarks != NIL) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -1357,7 +1270,7 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, foreach(lc, stmt_list) { - Node *pstmt = (Node *) lfirst(lc); + PlannedStmt *pstmt = (PlannedStmt *) lfirst(lc); if (!CommandIsReadOnly(pstmt)) { @@ -1366,9 +1279,9 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), /* translator: %s is a SQL statement name */ errmsg("%s is not allowed in a non-volatile function", - CreateCommandTag(pstmt)))); + CreateCommandTag((Node *) pstmt)))); else - PreventCommandIfParallelMode(CreateCommandTag(pstmt)); + PreventCommandIfParallelMode(CreateCommandTag((Node *) pstmt)); } } } @@ -1726,14 +1639,8 @@ spi_dest_startup(DestReceiver *self, int operation, TupleDesc typeinfo) MemoryContext oldcxt; MemoryContext tuptabcxt; - /* - * When called by Executor _SPI_curid expected to be equal to - * _SPI_connected - */ - if (_SPI_curid != _SPI_connected || _SPI_connected < 0) - elog(ERROR, "improper call to spi_dest_startup"); - if (_SPI_current != &(_SPI_stack[_SPI_curid])) - elog(ERROR, "SPI stack corrupted"); + if (_SPI_current == NULL) + elog(ERROR, "spi_dest_startup called while not connected to SPI"); if (_SPI_current->tuptable != NULL) elog(ERROR, "improper call to spi_dest_startup"); @@ -1744,9 +1651,7 @@ spi_dest_startup(DestReceiver *self, int operation, TupleDesc typeinfo) tuptabcxt = AllocSetContextCreate(CurrentMemoryContext, "SPI TupTable", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); MemoryContextSwitchTo(tuptabcxt); _SPI_current->tuptable = tuptable = (SPITupleTable *) @@ -1780,14 +1685,8 @@ spi_printtup(TupleTableSlot *slot, DestReceiver *self) SPITupleTable *tuptable; MemoryContext oldcxt; - /* - * When called by Executor _SPI_curid expected to be equal to - * _SPI_connected - */ - if (_SPI_curid != _SPI_connected || _SPI_connected < 0) - elog(ERROR, "improper call to spi_printtup"); - if (_SPI_current != &(_SPI_stack[_SPI_curid])) - elog(ERROR, "SPI stack corrupted"); + if (_SPI_current == NULL) + elog(ERROR, "spi_printtup called while not connected to SPI"); tuptable = _SPI_current->tuptable; if (tuptable == NULL) @@ -1858,7 +1757,7 @@ _SPI_prepare_plan(const char *src, SPIPlanPtr plan) foreach(list_item, raw_parsetree_list) { - Node *parsetree = (Node *) lfirst(list_item); + RawStmt *parsetree = (RawStmt *) lfirst(list_item); List *stmt_list; CachedPlanSource *plansource; @@ -1868,7 +1767,7 @@ _SPI_prepare_plan(const char *src, SPIPlanPtr plan) */ plansource = CreateCachedPlan(parsetree, src, - CreateCommandTag(parsetree)); + CreateCommandTag(parsetree->stmt)); /* * Parameter datatypes are driven by parserSetup hook if provided, @@ -1960,12 +1859,12 @@ _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan) foreach(list_item, raw_parsetree_list) { - Node *parsetree = (Node *) lfirst(list_item); + RawStmt *parsetree = (RawStmt *) lfirst(list_item); CachedPlanSource *plansource; plansource = CreateOneShotCachedPlan(parsetree, src, - CreateCommandTag(parsetree)); + CreateCommandTag(parsetree->stmt)); plancache_list = lappend(plancache_list, plansource); } @@ -2060,7 +1959,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, */ if (plan->oneshot) { - Node *parsetree = plansource->raw_parse_tree; + RawStmt *parsetree = plansource->raw_parse_tree; const char *src = plansource->query_string; List *stmt_list; @@ -2119,26 +2018,19 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, foreach(lc2, stmt_list) { - Node *stmt = (Node *) lfirst(lc2); - bool canSetTag; + PlannedStmt *stmt = (PlannedStmt *) lfirst(lc2); + bool canSetTag = stmt->canSetTag; DestReceiver *dest; _SPI_current->processed = 0; _SPI_current->lastoid = InvalidOid; _SPI_current->tuptable = NULL; - if (IsA(stmt, PlannedStmt)) - { - canSetTag = ((PlannedStmt *) stmt)->canSetTag; - } - else + if (stmt->utilityStmt) { - /* utilities are canSetTag if only thing in list */ - canSetTag = (list_length(stmt_list) == 1); - - if (IsA(stmt, CopyStmt)) + if (IsA(stmt->utilityStmt, CopyStmt)) { - CopyStmt *cstmt = (CopyStmt *) stmt; + CopyStmt *cstmt = (CopyStmt *) stmt->utilityStmt; if (cstmt->filename == NULL) { @@ -2146,7 +2038,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, goto fail; } } - else if (IsA(stmt, TransactionStmt)) + else if (IsA(stmt->utilityStmt, TransactionStmt)) { my_res = SPI_ERROR_TRANSACTION; goto fail; @@ -2158,10 +2050,10 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), /* translator: %s is a SQL statement name */ errmsg("%s is not allowed in a non-volatile function", - CreateCommandTag(stmt)))); + CreateCommandTag((Node *) stmt)))); if (IsInParallelMode() && !CommandIsReadOnly(stmt)) - PreventCommandIfParallelMode(CreateCommandTag(stmt)); + PreventCommandIfParallelMode(CreateCommandTag((Node *) stmt)); /* * If not read-only mode, advance the command counter before each @@ -2175,8 +2067,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, dest = CreateDestReceiver(canSetTag ? DestSPI : DestNone); - if (IsA(stmt, PlannedStmt) && - ((PlannedStmt *) stmt)->utilityStmt == NULL) + if (stmt->utilityStmt == NULL) { QueryDesc *qdesc; Snapshot snap; @@ -2186,7 +2077,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, else snap = InvalidSnapshot; - qdesc = CreateQueryDesc((PlannedStmt *) stmt, + qdesc = CreateQueryDesc(stmt, plansource->query_string, snap, crosscheck_snapshot, dest, @@ -2217,9 +2108,9 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, * Some utility statements return a row count, even though the * tuples are not returned to the caller. */ - if (IsA(stmt, CreateTableAsStmt)) + if (IsA(stmt->utilityStmt, CreateTableAsStmt)) { - CreateTableAsStmt *ctastmt = (CreateTableAsStmt *) stmt; + CreateTableAsStmt *ctastmt = (CreateTableAsStmt *) stmt->utilityStmt; if (strncmp(completionTag, "SELECT ", 7) == 0) _SPI_current->processed = @@ -2242,7 +2133,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, if (ctastmt->is_select_into) res = SPI_OK_SELINTO; } - else if (IsA(stmt, CopyStmt)) + else if (IsA(stmt->utilityStmt, CopyStmt)) { Assert(strncmp(completionTag, "COPY ", 5) == 0); _SPI_current->processed = pg_strtouint64(completionTag + 5, @@ -2371,7 +2262,6 @@ _SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, uint64 tcount) switch (operation) { case CMD_SELECT: - Assert(queryDesc->plannedstmt->utilityStmt == NULL); if (queryDesc->dest->mydest != DestSPI) { /* Don't return SPI_OK_SELECT if we're discarding result */ @@ -2539,11 +2429,8 @@ _SPI_procmem(void) static int _SPI_begin_call(bool execmem) { - if (_SPI_curid + 1 != _SPI_connected) + if (_SPI_current == NULL) return SPI_ERROR_UNCONNECTED; - _SPI_curid++; - if (_SPI_current != &(_SPI_stack[_SPI_curid])) - elog(ERROR, "SPI stack corrupted"); if (execmem) /* switch to the Executor memory context */ _SPI_execmem(); @@ -2559,11 +2446,6 @@ _SPI_begin_call(bool execmem) static int _SPI_end_call(bool procmem) { - /* - * We're returning to procedure where _SPI_curid == _SPI_connected - 1 - */ - _SPI_curid--; - if (procmem) /* switch to the procedure memory context */ { _SPI_procmem(); @@ -2615,14 +2497,11 @@ _SPI_make_plan_non_temp(SPIPlanPtr plan) /* * Create a memory context for the plan, underneath the procedure context. - * We don't expect the plan to be very large, so use smaller-than-default - * alloc parameters. + * We don't expect the plan to be very large. */ plancxt = AllocSetContextCreate(parentcxt, "SPI Plan", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MAXSIZE); + ALLOCSET_SMALL_SIZES); oldcxt = MemoryContextSwitchTo(plancxt); /* Copy the SPI_plan struct and subsidiary data into the new context */ @@ -2689,9 +2568,7 @@ _SPI_save_plan(SPIPlanPtr plan) */ plancxt = AllocSetContextCreate(CurrentMemoryContext, "SPI Plan", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MAXSIZE); + ALLOCSET_SMALL_SIZES); oldcxt = MemoryContextSwitchTo(plancxt); /* Copy the SPI plan into its own context */ diff --git a/src/backend/executor/tqueue.c b/src/backend/executor/tqueue.c index 58d0eeaf0b..8d7e711b3b 100644 --- a/src/backend/executor/tqueue.c +++ b/src/backend/executor/tqueue.c @@ -23,7 +23,7 @@ * and rewrites the typmods sent by the remote side to the corresponding * local record typmods. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -281,9 +281,7 @@ tqueueReceiveSlot(TupleTableSlot *slot, DestReceiver *self) tqueue->tmpcontext = AllocSetContextCreate(tqueue->mycontext, "tqueue sender temp context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldcontext = MemoryContextSwitchTo(tqueue->tmpcontext); } diff --git a/src/backend/executor/tstoreReceiver.c b/src/backend/executor/tstoreReceiver.c index 8f1e1b3f50..1e641c9837 100644 --- a/src/backend/executor/tstoreReceiver.c +++ b/src/backend/executor/tstoreReceiver.c @@ -9,7 +9,7 @@ * data even if the underlying table is dropped. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c index 242d6d2696..fdb4f71253 100644 --- a/src/backend/foreign/foreign.c +++ b/src/backend/foreign/foreign.c @@ -3,7 +3,7 @@ * foreign.c * support for foreign-data wrappers, servers and user mappings. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/foreign/foreign.c @@ -28,10 +28,6 @@ #include "utils/syscache.h" -extern Datum pg_options_to_table(PG_FUNCTION_ARGS); -extern Datum postgresql_fdw_validator(PG_FUNCTION_ARGS); - - /* * GetForeignDataWrapper - look up the foreign-data wrapper by OID. */ diff --git a/src/backend/lib/binaryheap.c b/src/backend/lib/binaryheap.c index d3cd4ad963..9f99e77db0 100644 --- a/src/backend/lib/binaryheap.c +++ b/src/backend/lib/binaryheap.c @@ -3,7 +3,7 @@ * binaryheap.c * A simple binary heap implementation * - * Portions Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/lib/binaryheap.c diff --git a/src/backend/lib/bipartite_match.c b/src/backend/lib/bipartite_match.c index 381627ec3d..4564a463d5 100644 --- a/src/backend/lib/bipartite_match.c +++ b/src/backend/lib/bipartite_match.c @@ -7,7 +7,7 @@ * * http://en.wikipedia.org/w/index.php?title=Hopcroft%E2%80%93Karp_algorithm&oldid=593898016 * - * Copyright (c) 2015-2016, PostgreSQL Global Development Group + * Copyright (c) 2015-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/lib/bipartite_match.c diff --git a/src/backend/lib/hyperloglog.c b/src/backend/lib/hyperloglog.c index 6d246ce77b..df7a67e7dc 100644 --- a/src/backend/lib/hyperloglog.c +++ b/src/backend/lib/hyperloglog.c @@ -3,7 +3,7 @@ * hyperloglog.c * HyperLogLog cardinality estimator * - * Portions Copyright (c) 2014-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2014-2017, PostgreSQL Global Development Group * * Based on Hideaki Ohno's C++ implementation. This is probably not ideally * suited to estimating the cardinality of very large sets; in particular, we diff --git a/src/backend/lib/ilist.c b/src/backend/lib/ilist.c index fb995e30d6..720cecb0e7 100644 --- a/src/backend/lib/ilist.c +++ b/src/backend/lib/ilist.c @@ -3,7 +3,7 @@ * ilist.c * support for integrated/inline doubly- and singly- linked lists * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/lib/pairingheap.c b/src/backend/lib/pairingheap.c index 3cf83fce0c..7c6bd837c6 100644 --- a/src/backend/lib/pairingheap.c +++ b/src/backend/lib/pairingheap.c @@ -14,7 +14,7 @@ * The pairing heap: a new form of self-adjusting heap. * Algorithmica 1, 1 (January 1986), pages 111-129. DOI: 10.1007/BF01840439 * - * Portions Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/lib/pairingheap.c diff --git a/src/backend/lib/rbtree.c b/src/backend/lib/rbtree.c index 4fa8a1dd58..b08e48b344 100644 --- a/src/backend/lib/rbtree.c +++ b/src/backend/lib/rbtree.c @@ -17,7 +17,7 @@ * longest path from root to leaf is only about twice as long as the shortest, * so lookups are guaranteed to run in O(lg n) time. * - * Copyright (c) 2009-2016, PostgreSQL Global Development Group + * Copyright (c) 2009-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/lib/rbtree.c @@ -29,17 +29,6 @@ #include "lib/rbtree.h" -/* - * Values of RBNode.iteratorState - * - * Note that iteratorState has an undefined value except in nodes that are - * currently being visited by an active iteration. - */ -#define InitialState (0) -#define FirstStepDone (1) -#define SecondStepDone (2) -#define ThirdStepDone (3) - /* * Colors of nodes (values of RBNode.color) */ @@ -53,10 +42,6 @@ struct RBTree { RBNode *root; /* root node, or RBNIL if tree is empty */ - /* Iteration state */ - RBNode *cur; /* current iteration node */ - RBNode *(*iterate) (RBTree *rb); - /* Remaining fields are constant after rb_create */ Size node_size; /* actual size of tree nodes */ @@ -75,8 +60,19 @@ struct RBTree */ #define RBNIL (&sentinel) -static RBNode sentinel = {InitialState, RBBLACK, RBNIL, RBNIL, NULL}; +static RBNode sentinel = {RBBLACK, RBNIL, RBNIL, NULL}; +/* + * Values used in the RBTreeIterator.next_state field, with an + * InvertedWalk iterator. + */ +typedef enum InvertedWalkNextStep +{ + NextStepBegin, + NextStepUp, + NextStepLeft, + NextStepRight +} InvertedWalkNextStep; /* * rb_create: create an empty RBTree @@ -123,8 +119,6 @@ rb_create(Size node_size, Assert(node_size > sizeof(RBNode)); tree->root = RBNIL; - tree->cur = RBNIL; - tree->iterate = NULL; tree->node_size = node_size; tree->comparator = comparator; tree->combiner = combiner; @@ -437,7 +431,6 @@ rb_insert(RBTree *rb, const RBNode *data, bool *isNew) x = rb->allocfunc (rb->arg); - x->iteratorState = InitialState; x->color = RBRED; x->left = RBNIL; @@ -653,171 +646,196 @@ rb_delete(RBTree *rb, RBNode *node) * Traverse * **********************************************************************/ -/* - * The iterator routines were originally coded in tail-recursion style, - * which is nice to look at, but is trouble if your compiler isn't smart - * enough to optimize it. Now we just use looping. - */ -#define descend(next_node) \ - do { \ - (next_node)->iteratorState = InitialState; \ - node = rb->cur = (next_node); \ - goto restart; \ - } while (0) +static RBNode * +rb_left_right_iterator(RBTreeIterator *iter) +{ + if (iter->last_visited == NULL) + { + iter->last_visited = iter->rb->root; + while (iter->last_visited->left != RBNIL) + iter->last_visited = iter->last_visited->left; -#define ascend(next_node) \ - do { \ - node = rb->cur = (next_node); \ - goto restart; \ - } while (0) + return iter->last_visited; + } + if (iter->last_visited->right != RBNIL) + { + iter->last_visited = iter->last_visited->right; + while (iter->last_visited->left != RBNIL) + iter->last_visited = iter->last_visited->left; -static RBNode * -rb_left_right_iterator(RBTree *rb) -{ - RBNode *node = rb->cur; + return iter->last_visited; + } -restart: - switch (node->iteratorState) + for (;;) { - case InitialState: - if (node->left != RBNIL) - { - node->iteratorState = FirstStepDone; - descend(node->left); - } - /* FALL THROUGH */ - case FirstStepDone: - node->iteratorState = SecondStepDone; - return node; - case SecondStepDone: - if (node->right != RBNIL) - { - node->iteratorState = ThirdStepDone; - descend(node->right); - } - /* FALL THROUGH */ - case ThirdStepDone: - if (node->parent) - ascend(node->parent); + RBNode *came_from = iter->last_visited; + + iter->last_visited = iter->last_visited->parent; + if (iter->last_visited == NULL) + { + iter->is_over = true; break; - default: - elog(ERROR, "unrecognized rbtree node state: %d", - node->iteratorState); + } + + if (iter->last_visited->left == came_from) + break; /* came from left sub-tree, return current + * node */ + + /* else - came from right sub-tree, continue to move up */ } - return NULL; + return iter->last_visited; } static RBNode * -rb_right_left_iterator(RBTree *rb) +rb_right_left_iterator(RBTreeIterator *iter) { - RBNode *node = rb->cur; + if (iter->last_visited == NULL) + { + iter->last_visited = iter->rb->root; + while (iter->last_visited->right != RBNIL) + iter->last_visited = iter->last_visited->right; -restart: - switch (node->iteratorState) + return iter->last_visited; + } + + if (iter->last_visited->left != RBNIL) { - case InitialState: - if (node->right != RBNIL) - { - node->iteratorState = FirstStepDone; - descend(node->right); - } - /* FALL THROUGH */ - case FirstStepDone: - node->iteratorState = SecondStepDone; - return node; - case SecondStepDone: - if (node->left != RBNIL) - { - node->iteratorState = ThirdStepDone; - descend(node->left); - } - /* FALL THROUGH */ - case ThirdStepDone: - if (node->parent) - ascend(node->parent); + iter->last_visited = iter->last_visited->left; + while (iter->last_visited->right != RBNIL) + iter->last_visited = iter->last_visited->right; + + return iter->last_visited; + } + + for (;;) + { + RBNode *came_from = iter->last_visited; + + iter->last_visited = iter->last_visited->parent; + if (iter->last_visited == NULL) + { + iter->is_over = true; break; - default: - elog(ERROR, "unrecognized rbtree node state: %d", - node->iteratorState); + } + + if (iter->last_visited->right == came_from) + break; /* came from right sub-tree, return current + * node */ + + /* else - came from left sub-tree, continue to move up */ } - return NULL; + return iter->last_visited; } static RBNode * -rb_direct_iterator(RBTree *rb) +rb_direct_iterator(RBTreeIterator *iter) { - RBNode *node = rb->cur; + if (iter->last_visited == NULL) + { + iter->last_visited = iter->rb->root; + return iter->last_visited; + } -restart: - switch (node->iteratorState) + if (iter->last_visited->left != RBNIL) { - case InitialState: - node->iteratorState = FirstStepDone; - return node; - case FirstStepDone: - if (node->left != RBNIL) + iter->last_visited = iter->last_visited->left; + return iter->last_visited; + } + + do + { + if (iter->last_visited->right != RBNIL) + { + iter->last_visited = iter->last_visited->right; + break; + } + + /* go up and one step right */ + for (;;) + { + RBNode *came_from = iter->last_visited; + + iter->last_visited = iter->last_visited->parent; + if (iter->last_visited == NULL) { - node->iteratorState = SecondStepDone; - descend(node->left); + iter->is_over = true; + break; } - /* FALL THROUGH */ - case SecondStepDone: - if (node->right != RBNIL) + + if ((iter->last_visited->right != came_from) && (iter->last_visited->right != RBNIL)) { - node->iteratorState = ThirdStepDone; - descend(node->right); + iter->last_visited = iter->last_visited->right; + return iter->last_visited; } - /* FALL THROUGH */ - case ThirdStepDone: - if (node->parent) - ascend(node->parent); - break; - default: - elog(ERROR, "unrecognized rbtree node state: %d", - node->iteratorState); + } } + while (iter->last_visited != NULL); - return NULL; + return iter->last_visited; } static RBNode * -rb_inverted_iterator(RBTree *rb) +rb_inverted_iterator(RBTreeIterator *iter) { - RBNode *node = rb->cur; + RBNode *came_from; + RBNode *current; -restart: - switch (node->iteratorState) + current = iter->last_visited; + +loop: + switch ((InvertedWalkNextStep) iter->next_step) { - case InitialState: - if (node->left != RBNIL) + /* First call, begin from root */ + case NextStepBegin: + current = iter->rb->root; + iter->next_step = NextStepLeft; + goto loop; + + case NextStepLeft: + while (current->left != RBNIL) + current = current->left; + + iter->next_step = NextStepRight; + goto loop; + + case NextStepRight: + if (current->right != RBNIL) + { + current = current->right; + iter->next_step = NextStepLeft; + goto loop; + } + else /* not moved - return current, then go up */ + iter->next_step = NextStepUp; + break; + + case NextStepUp: + came_from = current; + current = current->parent; + if (current == NULL) { - node->iteratorState = FirstStepDone; - descend(node->left); + iter->is_over = true; + break; /* end of iteration */ } - /* FALL THROUGH */ - case FirstStepDone: - if (node->right != RBNIL) + else if (came_from == current->right) { - node->iteratorState = SecondStepDone; - descend(node->right); + /* return current, then continue to go up */ + break; + } + else + { + /* otherwise we came from the left */ + Assert(came_from == current->left); + iter->next_step = NextStepRight; + goto loop; } - /* FALL THROUGH */ - case SecondStepDone: - node->iteratorState = ThirdStepDone; - return node; - case ThirdStepDone: - if (node->parent) - ascend(node->parent); - break; - default: - elog(ERROR, "unrecognized rbtree node state: %d", - node->iteratorState); } - return NULL; + iter->last_visited = current; + return current; } /* @@ -827,33 +845,34 @@ rb_inverted_iterator(RBTree *rb) * returns NULL or the traversal stops being of interest. * * If the tree is changed during traversal, results of further calls to - * rb_iterate are unspecified. + * rb_iterate are unspecified. Multiple concurrent iterators on the same + * tree are allowed. * - * Note: this used to return a separately palloc'd iterator control struct, - * but that's a bit pointless since the data structure is incapable of - * supporting multiple concurrent traversals. Now we just keep the state - * in RBTree. + * The iterator state is stored in the 'iter' struct. The caller should + * treat it as opaque struct. */ void -rb_begin_iterate(RBTree *rb, RBOrderControl ctrl) +rb_begin_iterate(RBTree *rb, RBOrderControl ctrl, RBTreeIterator *iter) { - rb->cur = rb->root; - if (rb->cur != RBNIL) - rb->cur->iteratorState = InitialState; + /* Common initialization for all traversal orders */ + iter->rb = rb; + iter->last_visited = NULL; + iter->is_over = (rb->root == RBNIL); switch (ctrl) { case LeftRightWalk: /* visit left, then self, then right */ - rb->iterate = rb_left_right_iterator; + iter->iterate = rb_left_right_iterator; break; case RightLeftWalk: /* visit right, then self, then left */ - rb->iterate = rb_right_left_iterator; + iter->iterate = rb_right_left_iterator; break; case DirectWalk: /* visit self, then left, then right */ - rb->iterate = rb_direct_iterator; + iter->iterate = rb_direct_iterator; break; case InvertedWalk: /* visit left, then right, then self */ - rb->iterate = rb_inverted_iterator; + iter->iterate = rb_inverted_iterator; + iter->next_step = NextStepBegin; break; default: elog(ERROR, "unrecognized rbtree iteration order: %d", ctrl); @@ -864,10 +883,10 @@ rb_begin_iterate(RBTree *rb, RBOrderControl ctrl) * rb_iterate: return the next node in traversal order, or NULL if no more */ RBNode * -rb_iterate(RBTree *rb) +rb_iterate(RBTreeIterator *iter) { - if (rb->cur == RBNIL) + if (iter->is_over) return NULL; - return rb->iterate(rb); + return iter->iterate(iter); } diff --git a/src/backend/lib/stringinfo.c b/src/backend/lib/stringinfo.c index 7382e08077..3eee49beb6 100644 --- a/src/backend/lib/stringinfo.c +++ b/src/backend/lib/stringinfo.c @@ -4,9 +4,10 @@ * * StringInfo 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 palloc(). + * or arbitrary binary data. All storage is allocated with palloc() and + * friends. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/lib/stringinfo.c @@ -36,11 +37,29 @@ makeStringInfo(void) return res; } +/* + * makeLongStringInfo + * + * Same as makeStringInfo, for larger strings. + */ +StringInfo +makeLongStringInfo(void) +{ + StringInfo res; + + res = (StringInfo) palloc(sizeof(StringInfoData)); + + initLongStringInfo(res); + + return res; +} + + /* * initStringInfo * * Initialize a StringInfoData struct (with previously undefined contents) - * to describe an empty string. + * to describe an empty string; don't enable long strings yet. */ void initStringInfo(StringInfo str) @@ -49,9 +68,22 @@ initStringInfo(StringInfo str) str->data = (char *) palloc(size); str->maxlen = size; + str->long_ok = false; resetStringInfo(str); } +/* + * initLongStringInfo + * + * Same as initStringInfo, plus enable long strings. + */ +void +initLongStringInfo(StringInfo str) +{ + initStringInfo(str); + str->long_ok = true; +} + /* * resetStringInfo * @@ -142,7 +174,7 @@ appendStringInfoVA(StringInfo str, const char *fmt, va_list args) /* * 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.) + * than either MaxAllocSize or half an int's width.) */ return (int) nprinted; } @@ -244,7 +276,17 @@ appendBinaryStringInfo(StringInfo str, const char *data, int datalen) void enlargeStringInfo(StringInfo str, int needed) { - int newlen; + Size newlen; + Size limit; + + /* + * Determine the upper size limit. Because of overflow concerns outside + * of this module, we limit ourselves to 4-byte signed integer range, + * even for "long_ok" strings. + */ + limit = str->long_ok ? + (((Size) 1) << (sizeof(int32) * 8 - 1)) - 1 : + MaxAllocSize; /* * Guard against out-of-range "needed" values. Without this, we can get @@ -252,7 +294,7 @@ enlargeStringInfo(StringInfo str, int needed) */ if (needed < 0) /* should not happen */ elog(ERROR, "invalid string enlargement request size: %d", needed); - if (((Size) needed) >= (MaxAllocSize - (Size) str->len)) + if (((Size) needed) >= (limit - (Size) str->len)) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("out of memory"), @@ -261,7 +303,7 @@ enlargeStringInfo(StringInfo str, int needed) needed += str->len + 1; /* total space required now */ - /* Because of the above test, we now have needed <= MaxAllocSize */ + /* Because of the above test, we now have needed <= limit */ if (needed <= str->maxlen) return; /* got enough space already */ @@ -271,19 +313,20 @@ enlargeStringInfo(StringInfo str, int needed) * 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 * (Size) str->maxlen; + while ((Size) 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. + * Clamp to the limit in case we went past it. (We used to depend on + * limit <= INT32_MAX/2, to avoid overflow in the loop above; we no longer + * depend on that, but if "needed" and str->maxlen ever become wider, we + * will need similar caution here.) We will still have newlen >= needed. */ - if (newlen > (int) MaxAllocSize) - newlen = (int) MaxAllocSize; + if (newlen > limit) + newlen = limit; - str->data = (char *) repalloc(str->data, newlen); + str->data = (char *) repalloc_huge(str->data, newlen); str->maxlen = newlen; } diff --git a/src/backend/libpq/Makefile b/src/backend/libpq/Makefile index 09410c4bb1..1bdd8adde2 100644 --- a/src/backend/libpq/Makefile +++ b/src/backend/libpq/Makefile @@ -14,7 +14,7 @@ include $(top_builddir)/src/Makefile.global # be-fsstubs is here for historical reasons, probably belongs elsewhere -OBJS = be-fsstubs.o be-secure.o auth.o crypt.o hba.o ip.o md5.o pqcomm.o \ +OBJS = be-fsstubs.o be-secure.o auth.o crypt.o hba.o ifaddr.o pqcomm.o \ pqformat.o pqmq.o pqsignal.o ifeq ($(with_openssl),yes) diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 7d8fc3e54d..824e40837b 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -3,7 +3,7 @@ * auth.c * Routines to handle network authentication * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -20,28 +20,45 @@ #include #include #include +#ifdef HAVE_SYS_SELECT_H +#include +#endif +#include "common/ip.h" +#include "common/md5.h" #include "libpq/auth.h" #include "libpq/crypt.h" -#include "libpq/ip.h" #include "libpq/libpq.h" #include "libpq/pqformat.h" -#include "libpq/md5.h" #include "miscadmin.h" #include "replication/walsender.h" #include "storage/ipc.h" +#include "utils/backend_random.h" /*---------------------------------------------------------------- * Global authentication functions *---------------------------------------------------------------- */ -static void sendAuthRequest(Port *port, AuthRequest areq); +static void sendAuthRequest(Port *port, AuthRequest areq, char *extradata, + int extralen); static void auth_failed(Port *port, int status, char *logdetail); static char *recv_password_packet(Port *port); -static int recv_and_check_password_packet(Port *port, char **logdetail); +/*---------------------------------------------------------------- + * MD5 authentication + *---------------------------------------------------------------- + */ +static int CheckMD5Auth(Port *port, char **logdetail); + +/*---------------------------------------------------------------- + * Plaintext password authentication + *---------------------------------------------------------------- + */ + +static int CheckPasswordAuth(Port *port, char **logdetail); + /*---------------------------------------------------------------- * Ident authentication *---------------------------------------------------------------- @@ -177,9 +194,6 @@ static int pg_SSPI_make_upn(char *accountname, * RADIUS Authentication *---------------------------------------------------------------- */ -#ifdef USE_OPENSSL -#include -#endif static int CheckRADIUSAuth(Port *port); @@ -334,28 +348,22 @@ ClientAuthentication(Port *port) */ if (port->hba->clientcert) { + /* If we haven't loaded a root certificate store, fail */ + if (!secure_loaded_verify_locations()) + ereport(FATAL, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("client certificates can only be checked if a root certificate store is available"))); + /* - * When we parse pg_hba.conf, we have already made sure that we have - * been able to load a certificate store. Thus, if a certificate is - * present on the client, it has been verified against our root + * If we loaded a root certificate store, and if a certificate is + * present on the client, then it has been verified against our root * certificate store, and the connection would have been aborted * already if it didn't verify ok. */ -#ifdef USE_SSL if (!port->peer_cert_valid) - { ereport(FATAL, (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), errmsg("connection requires a valid client certificate"))); - } -#else - - /* - * hba.c makes sure hba->clientcert can't be set unless OpenSSL is - * present. - */ - Assert(false); -#endif } /* @@ -498,7 +506,7 @@ ClientAuthentication(Port *port) case uaGSS: #ifdef ENABLE_GSS - sendAuthRequest(port, AUTH_REQ_GSS); + sendAuthRequest(port, AUTH_REQ_GSS, NULL, 0); status = pg_GSS_recvauth(port); #else Assert(false); @@ -507,7 +515,7 @@ ClientAuthentication(Port *port) case uaSSPI: #ifdef ENABLE_SSPI - sendAuthRequest(port, AUTH_REQ_SSPI); + sendAuthRequest(port, AUTH_REQ_SSPI, NULL, 0); status = pg_SSPI_recvauth(port); #else Assert(false); @@ -527,17 +535,11 @@ ClientAuthentication(Port *port) break; case uaMD5: - if (Db_user_namespace) - ereport(FATAL, - (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), - errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled"))); - sendAuthRequest(port, AUTH_REQ_MD5); - status = recv_and_check_password_packet(port, &logdetail); + status = CheckMD5Auth(port, &logdetail); break; case uaPassword: - sendAuthRequest(port, AUTH_REQ_PASSWORD); - status = recv_and_check_password_packet(port, &logdetail); + status = CheckPasswordAuth(port, &logdetail); break; case uaPAM: @@ -583,7 +585,7 @@ ClientAuthentication(Port *port) (*ClientAuthentication_hook) (port, status); if (status == STATUS_OK) - sendAuthRequest(port, AUTH_REQ_OK); + sendAuthRequest(port, AUTH_REQ_OK, NULL, 0); else auth_failed(port, status, logdetail); } @@ -593,7 +595,7 @@ ClientAuthentication(Port *port) * Send an authentication request packet to the frontend. */ static void -sendAuthRequest(Port *port, AuthRequest areq) +sendAuthRequest(Port *port, AuthRequest areq, char *extradata, int extralen) { StringInfoData buf; @@ -601,28 +603,8 @@ sendAuthRequest(Port *port, AuthRequest areq) pq_beginmessage(&buf, 'R'); pq_sendint(&buf, (int32) areq, sizeof(int32)); - - /* Add the salt for encrypted passwords. */ - if (areq == AUTH_REQ_MD5) - pq_sendbytes(&buf, port->md5Salt, 4); - -#if defined(ENABLE_GSS) || defined(ENABLE_SSPI) - - /* - * Add the authentication data for the next step of the GSSAPI or SSPI - * negotiation. - */ - else if (areq == AUTH_REQ_GSS_CONT) - { - if (port->gss->outbuf.length > 0) - { - elog(DEBUG4, "sending GSS token of length %u", - (unsigned int) port->gss->outbuf.length); - - pq_sendbytes(&buf, port->gss->outbuf.value, port->gss->outbuf.length); - } - } -#endif + if (extralen > 0) + pq_sendbytes(&buf, extradata, extralen); pq_endmessage(&buf); @@ -711,24 +693,70 @@ recv_password_packet(Port *port) *---------------------------------------------------------------- */ -/* - * Called when we have sent an authorization request for a password. - * Get the response and check it. - * On error, optionally store a detail string at *logdetail. - */ static int -recv_and_check_password_packet(Port *port, char **logdetail) +CheckMD5Auth(Port *port, char **logdetail) { + char md5Salt[4]; /* Password salt */ char *passwd; + char *shadow_pass; int result; + if (Db_user_namespace) + ereport(FATAL, + (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), + errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled"))); + + /* include the salt to use for computing the response */ + if (!pg_backend_random(md5Salt, 4)) + { + ereport(LOG, + (errmsg("could not generate random MD5 salt"))); + return STATUS_ERROR; + } + + sendAuthRequest(port, AUTH_REQ_MD5, md5Salt, 4); + passwd = recv_password_packet(port); + if (passwd == NULL) + return STATUS_EOF; /* client wouldn't send password */ + + result = get_role_password(port->user_name, &shadow_pass, logdetail); + if (result == STATUS_OK) + result = md5_crypt_verify(port->user_name, shadow_pass, passwd, + md5Salt, 4, logdetail); + if (shadow_pass) + pfree(shadow_pass); + pfree(passwd); + + return result; +} + +/*---------------------------------------------------------------- + * Plaintext password authentication + *---------------------------------------------------------------- + */ + +static int +CheckPasswordAuth(Port *port, char **logdetail) +{ + char *passwd; + int result; + char *shadow_pass; + + sendAuthRequest(port, AUTH_REQ_PASSWORD, NULL, 0); + + passwd = recv_password_packet(port); if (passwd == NULL) return STATUS_EOF; /* client wouldn't send password */ - result = md5_crypt_verify(port, port->user_name, passwd, logdetail); + result = get_role_password(port->user_name, &shadow_pass, logdetail); + if (result == STATUS_OK) + result = plain_crypt_verify(port->user_name, shadow_pass, passwd, + logdetail); + if (shadow_pass) + pfree(shadow_pass); pfree(passwd); return result; @@ -934,7 +962,8 @@ pg_GSS_recvauth(Port *port) elog(DEBUG4, "sending GSS response token of length %u", (unsigned int) port->gss->outbuf.length); - sendAuthRequest(port, AUTH_REQ_GSS_CONT); + sendAuthRequest(port, AUTH_REQ_GSS_CONT, + port->gss->outbuf.value, port->gss->outbuf.length); gss_release_buffer(&lmin_s, &port->gss->outbuf); } @@ -1179,7 +1208,8 @@ pg_SSPI_recvauth(Port *port) port->gss->outbuf.length = outbuf.pBuffers[0].cbBuffer; port->gss->outbuf.value = outbuf.pBuffers[0].pvBuffer; - sendAuthRequest(port, AUTH_REQ_GSS_CONT); + sendAuthRequest(port, AUTH_REQ_GSS_CONT, + port->gss->outbuf.value, port->gss->outbuf.length); FreeContextBuffer(outbuf.pBuffers[0].pvBuffer); } @@ -1807,7 +1837,7 @@ pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg, * let's go ask the client to send a password, which we * then stuff into PAM. */ - sendAuthRequest(pam_port_cludge, AUTH_REQ_PASSWORD); + sendAuthRequest(pam_port_cludge, AUTH_REQ_PASSWORD, NULL, 0); passwd = recv_password_packet(pam_port_cludge); if (passwd == NULL) { @@ -2137,7 +2167,7 @@ CheckLDAPAuth(Port *port) if (port->hba->ldapport == 0) port->hba->ldapport = LDAP_PORT; - sendAuthRequest(port, AUTH_REQ_PASSWORD); + sendAuthRequest(port, AUTH_REQ_PASSWORD, NULL, 0); passwd = recv_password_packet(port); if (passwd == NULL) @@ -2497,7 +2527,7 @@ CheckRADIUSAuth(Port *port) identifier = port->hba->radiusidentifier; /* Send regular password request to client, and get the response */ - sendAuthRequest(port, AUTH_REQ_PASSWORD); + sendAuthRequest(port, AUTH_REQ_PASSWORD, NULL, 0); passwd = recv_password_packet(port); if (passwd == NULL) @@ -2521,18 +2551,12 @@ CheckRADIUSAuth(Port *port) /* Construct RADIUS packet */ packet->code = RADIUS_ACCESS_REQUEST; packet->length = RADIUS_HEADER_LENGTH; -#ifdef USE_OPENSSL - if (RAND_bytes(packet->vector, RADIUS_VECTOR_LENGTH) != 1) + if (!pg_backend_random((char *) packet->vector, RADIUS_VECTOR_LENGTH)) { ereport(LOG, (errmsg("could not generate random encryption vector"))); return STATUS_ERROR; } -#else - for (i = 0; i < RADIUS_VECTOR_LENGTH; i++) - /* Use a lower strengh random number of OpenSSL is not available */ - packet->vector[i] = random() % 255; -#endif packet->id = packet->vector[0]; radius_add_attribute(packet, RADIUS_SERVICE_TYPE, (unsigned char *) &service, sizeof(service)); radius_add_attribute(packet, RADIUS_USER_NAME, (unsigned char *) port->user_name, strlen(port->user_name)); diff --git a/src/backend/libpq/be-fsstubs.c b/src/backend/libpq/be-fsstubs.c index b64ef8b5c4..f537affdd9 100644 --- a/src/backend/libpq/be-fsstubs.c +++ b/src/backend/libpq/be-fsstubs.c @@ -3,7 +3,7 @@ * be-fsstubs.c * Builtin functions for open/close/read/write operations on large objects * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -79,9 +79,7 @@ static MemoryContext fscxt = NULL; if (fscxt == NULL) \ fscxt = AllocSetContextCreate(TopMemoryContext, \ "Filesystem", \ - ALLOCSET_DEFAULT_MINSIZE, \ - ALLOCSET_DEFAULT_INITSIZE, \ - ALLOCSET_DEFAULT_MAXSIZE); \ + ALLOCSET_DEFAULT_SIZES); \ } while (0) @@ -95,7 +93,7 @@ static Oid lo_import_internal(text *filename, Oid lobjOid); *****************************************************************************/ Datum -lo_open(PG_FUNCTION_ARGS) +be_lo_open(PG_FUNCTION_ARGS) { Oid lobjId = PG_GETARG_OID(0); int32 mode = PG_GETARG_INT32(1); @@ -124,7 +122,7 @@ lo_open(PG_FUNCTION_ARGS) } Datum -lo_close(PG_FUNCTION_ARGS) +be_lo_close(PG_FUNCTION_ARGS) { int32 fd = PG_GETARG_INT32(0); @@ -226,7 +224,7 @@ lo_write(int fd, const char *buf, int len) } Datum -lo_lseek(PG_FUNCTION_ARGS) +be_lo_lseek(PG_FUNCTION_ARGS) { int32 fd = PG_GETARG_INT32(0); int32 offset = PG_GETARG_INT32(1); @@ -251,7 +249,7 @@ lo_lseek(PG_FUNCTION_ARGS) } Datum -lo_lseek64(PG_FUNCTION_ARGS) +be_lo_lseek64(PG_FUNCTION_ARGS) { int32 fd = PG_GETARG_INT32(0); int64 offset = PG_GETARG_INT64(1); @@ -269,7 +267,7 @@ lo_lseek64(PG_FUNCTION_ARGS) } Datum -lo_creat(PG_FUNCTION_ARGS) +be_lo_creat(PG_FUNCTION_ARGS) { Oid lobjId; @@ -285,7 +283,7 @@ lo_creat(PG_FUNCTION_ARGS) } Datum -lo_create(PG_FUNCTION_ARGS) +be_lo_create(PG_FUNCTION_ARGS) { Oid lobjId = PG_GETARG_OID(0); @@ -301,7 +299,7 @@ lo_create(PG_FUNCTION_ARGS) } Datum -lo_tell(PG_FUNCTION_ARGS) +be_lo_tell(PG_FUNCTION_ARGS) { int32 fd = PG_GETARG_INT32(0); int64 offset; @@ -324,7 +322,7 @@ lo_tell(PG_FUNCTION_ARGS) } Datum -lo_tell64(PG_FUNCTION_ARGS) +be_lo_tell64(PG_FUNCTION_ARGS) { int32 fd = PG_GETARG_INT32(0); int64 offset; @@ -340,7 +338,7 @@ lo_tell64(PG_FUNCTION_ARGS) } Datum -lo_unlink(PG_FUNCTION_ARGS) +be_lo_unlink(PG_FUNCTION_ARGS) { Oid lobjId = PG_GETARG_OID(0); @@ -380,7 +378,7 @@ lo_unlink(PG_FUNCTION_ARGS) *****************************************************************************/ Datum -loread(PG_FUNCTION_ARGS) +be_loread(PG_FUNCTION_ARGS) { int32 fd = PG_GETARG_INT32(0); int32 len = PG_GETARG_INT32(1); @@ -398,7 +396,7 @@ loread(PG_FUNCTION_ARGS) } Datum -lowrite(PG_FUNCTION_ARGS) +be_lowrite(PG_FUNCTION_ARGS) { int32 fd = PG_GETARG_INT32(0); bytea *wbuf = PG_GETARG_BYTEA_P(1); @@ -419,7 +417,7 @@ lowrite(PG_FUNCTION_ARGS) * imports a file as an (inversion) large object. */ Datum -lo_import(PG_FUNCTION_ARGS) +be_lo_import(PG_FUNCTION_ARGS) { text *filename = PG_GETARG_TEXT_PP(0); @@ -431,7 +429,7 @@ lo_import(PG_FUNCTION_ARGS) * imports a file as an (inversion) large object specifying oid. */ Datum -lo_import_with_oid(PG_FUNCTION_ARGS) +be_lo_import_with_oid(PG_FUNCTION_ARGS) { text *filename = PG_GETARG_TEXT_PP(0); Oid oid = PG_GETARG_OID(1); @@ -504,7 +502,7 @@ lo_import_internal(text *filename, Oid lobjOid) * exports an (inversion) large object. */ Datum -lo_export(PG_FUNCTION_ARGS) +be_lo_export(PG_FUNCTION_ARGS) { Oid lobjId = PG_GETARG_OID(0); text *filename = PG_GETARG_TEXT_PP(1); @@ -608,7 +606,7 @@ lo_truncate_internal(int32 fd, int64 len) } Datum -lo_truncate(PG_FUNCTION_ARGS) +be_lo_truncate(PG_FUNCTION_ARGS) { int32 fd = PG_GETARG_INT32(0); int32 len = PG_GETARG_INT32(1); @@ -618,7 +616,7 @@ lo_truncate(PG_FUNCTION_ARGS) } Datum -lo_truncate64(PG_FUNCTION_ARGS) +be_lo_truncate64(PG_FUNCTION_ARGS) { int32 fd = PG_GETARG_INT32(0); int64 len = PG_GETARG_INT64(1); @@ -830,7 +828,7 @@ lo_get_fragment_internal(Oid loOid, int64 offset, int32 nbytes) * Read entire LO */ Datum -lo_get(PG_FUNCTION_ARGS) +be_lo_get(PG_FUNCTION_ARGS) { Oid loOid = PG_GETARG_OID(0); bytea *result; @@ -844,7 +842,7 @@ lo_get(PG_FUNCTION_ARGS) * Read range within LO */ Datum -lo_get_fragment(PG_FUNCTION_ARGS) +be_lo_get_fragment(PG_FUNCTION_ARGS) { Oid loOid = PG_GETARG_OID(0); int64 offset = PG_GETARG_INT64(1); @@ -865,7 +863,7 @@ lo_get_fragment(PG_FUNCTION_ARGS) * Create LO with initial contents given by a bytea argument */ Datum -lo_from_bytea(PG_FUNCTION_ARGS) +be_lo_from_bytea(PG_FUNCTION_ARGS) { Oid loOid = PG_GETARG_OID(0); bytea *str = PG_GETARG_BYTEA_PP(1); @@ -887,7 +885,7 @@ lo_from_bytea(PG_FUNCTION_ARGS) * Update range within LO */ Datum -lo_put(PG_FUNCTION_ARGS) +be_lo_put(PG_FUNCTION_ARGS) { Oid loOid = PG_GETARG_OID(0); int64 offset = PG_GETARG_INT64(1); diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c index f6adb155c6..44c84a7869 100644 --- a/src/backend/libpq/be-secure-openssl.c +++ b/src/backend/libpq/be-secure-openssl.c @@ -4,7 +4,7 @@ * functions for OpenSSL support in the backend. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -53,15 +53,14 @@ #include #include -#if SSLEAY_VERSION_NUMBER >= 0x0907000L #include -#endif -#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_ECDH) +#ifndef OPENSSL_NO_ECDH #include #endif #include "libpq/libpq.h" #include "miscadmin.h" +#include "pgstat.h" #include "storage/latch.h" #include "tcop/tcopprot.h" #include "utils/memutils.h" @@ -74,15 +73,19 @@ static int my_SSL_set_fd(Port *port, int fd); static DH *load_dh_file(int keylength); static DH *load_dh_buffer(const char *, size_t); +static DH *generate_dh_parameters(int prime_len, int generator); static DH *tmp_dh_cb(SSL *s, int is_export, int keylength); +static int ssl_passwd_cb(char *buf, int size, int rwflag, void *userdata); static int verify_cb(int, X509_STORE_CTX *); static void info_cb(const SSL *ssl, int type, int args); -static void initialize_ecdh(void); +static bool initialize_ecdh(SSL_CTX *context, bool isServerStart); static const char *SSLerrmessage(unsigned long ecode); static char *X509_NAME_to_cstring(X509_NAME *name); static SSL_CTX *SSL_context = NULL; +static bool SSL_initialized = false; +static bool ssl_passwd_cb_called = false; /* ------------------------------------------------------------ */ /* Hardcoded values */ @@ -156,136 +159,200 @@ KWbuHn491xNO25CQWMtem80uKw+pTnisBRF/454n1Jnhub144YRBoN8CAQI=\n\ /* * Initialize global SSL context. + * + * If isServerStart is true, report any errors as FATAL (so we don't return). + * Otherwise, log errors at LOG level and return -1 to indicate trouble, + * preserving the old SSL state if any. Returns 0 if OK. */ -void -be_tls_init(void) +int +be_tls_init(bool isServerStart) { - struct stat buf; - STACK_OF(X509_NAME) *root_cert_list = NULL; + SSL_CTX *context; + struct stat buf; - if (!SSL_context) + /* This stuff need be done only once. */ + if (!SSL_initialized) { -#if SSLEAY_VERSION_NUMBER >= 0x0907000L +#ifdef HAVE_OPENSSL_INIT_SSL + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL); +#else OPENSSL_config(NULL); -#endif SSL_library_init(); SSL_load_error_strings(); +#endif + SSL_initialized = true; + } - /* - * We use SSLv23_method() because it can negotiate use of the highest - * mutually supported protocol version, while alternatives like - * TLSv1_2_method() permit only one specific version. Note that we - * don't actually allow SSL v2 or v3, only TLS protocols (see below). - */ - SSL_context = SSL_CTX_new(SSLv23_method()); - if (!SSL_context) - ereport(FATAL, - (errmsg("could not create SSL context: %s", - SSLerrmessage(ERR_get_error())))); + /* + * We use SSLv23_method() because it can negotiate use of the highest + * mutually supported protocol version, while alternatives like + * TLSv1_2_method() permit only one specific version. Note that we don't + * actually allow SSL v2 or v3, only TLS protocols (see below). + */ + context = SSL_CTX_new(SSLv23_method()); + if (!context) + { + ereport(isServerStart ? FATAL : LOG, + (errmsg("could not create SSL context: %s", + SSLerrmessage(ERR_get_error())))); + goto error; + } - /* - * 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); + /* + * Disable OpenSSL's moving-write-buffer sanity check, because it causes + * unnecessary failures in nonblocking send cases. + */ + SSL_CTX_set_mode(context, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - /* - * Load and verify server's certificate and private key - */ - if (SSL_CTX_use_certificate_chain_file(SSL_context, - ssl_cert_file) != 1) - ereport(FATAL, - (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("could not load server certificate file \"%s\": %s", - ssl_cert_file, SSLerrmessage(ERR_get_error())))); + /* + * If reloading, override OpenSSL's default handling of + * passphrase-protected files, because we don't want to prompt for a + * passphrase in an already-running server. (Not that the default + * handling is very desirable during server start either, but some people + * insist we need to keep it.) + */ + if (!isServerStart) + SSL_CTX_set_default_passwd_cb(context, ssl_passwd_cb); - if (stat(ssl_key_file, &buf) != 0) - ereport(FATAL, - (errcode_for_file_access(), - errmsg("could not access private key file \"%s\": %m", - ssl_key_file))); + /* + * Load and verify server's certificate and private key + */ + if (SSL_CTX_use_certificate_chain_file(context, ssl_cert_file) != 1) + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("could not load server certificate file \"%s\": %s", + ssl_cert_file, SSLerrmessage(ERR_get_error())))); + goto error; + } - if (!S_ISREG(buf.st_mode)) - ereport(FATAL, - (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("private key file \"%s\" is not a regular file", - ssl_key_file))); + if (stat(ssl_key_file, &buf) != 0) + { + ereport(isServerStart ? FATAL : LOG, + (errcode_for_file_access(), + errmsg("could not access private key file \"%s\": %m", + ssl_key_file))); + goto error; + } - /* - * Refuse to load files owned by users other than us or root. - * - * XXX surely we can check this on Windows somehow, too. - */ + if (!S_ISREG(buf.st_mode)) + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("private key file \"%s\" is not a regular file", + ssl_key_file))); + goto error; + } + + /* + * Refuse to load key files owned by users other than us or root. + * + * XXX surely we can check this on Windows somehow, too. + */ #if !defined(WIN32) && !defined(__CYGWIN__) - if (buf.st_uid != geteuid() && buf.st_uid != 0) - ereport(FATAL, - (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("private key file \"%s\" must be owned by the database user or root", - ssl_key_file))); + if (buf.st_uid != geteuid() && buf.st_uid != 0) + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("private key file \"%s\" must be owned by the database user or root", + ssl_key_file))); + goto error; + } #endif - /* - * Require no public access to key file. If the file is owned by us, - * require mode 0600 or less. If owned by root, require 0640 or less - * to allow read access through our gid, or a supplementary gid that - * allows to read system-wide certificates. - * - * XXX temporarily suppress check when on Windows, because there may - * not be proper support for Unix-y file permissions. Need to think - * of a reasonable check to apply on Windows. (See also the data - * directory permission check in postmaster.c) - */ + /* + * Require no public access to key file. If the file is owned by us, + * require mode 0600 or less. If owned by root, require 0640 or less to + * allow read access through our gid, or a supplementary gid that allows + * to read system-wide certificates. + * + * XXX temporarily suppress check when on Windows, because there may not + * be proper support for Unix-y file permissions. Need to think of a + * reasonable check to apply on Windows. (See also the data directory + * permission check in postmaster.c) + */ #if !defined(WIN32) && !defined(__CYGWIN__) - if ((buf.st_uid == geteuid() && buf.st_mode & (S_IRWXG | S_IRWXO)) || - (buf.st_uid == 0 && buf.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO))) - ereport(FATAL, - (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("private key file \"%s\" has group or world access", - ssl_key_file), - errdetail("File must have permissions u=rw (0600) or less if owned by the database user, or permissions u=rw,g=r (0640) or less if owned by root."))); + if ((buf.st_uid == geteuid() && buf.st_mode & (S_IRWXG | S_IRWXO)) || + (buf.st_uid == 0 && buf.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO))) + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("private key file \"%s\" has group or world access", + ssl_key_file), + errdetail("File must have permissions u=rw (0600) or less if owned by the database user, or permissions u=rw,g=r (0640) or less if owned by root."))); + goto error; + } #endif - if (SSL_CTX_use_PrivateKey_file(SSL_context, - ssl_key_file, - SSL_FILETYPE_PEM) != 1) - ereport(FATAL, - (errmsg("could not load private key file \"%s\": %s", + /* + * OK, try to load the private key file. + */ + ssl_passwd_cb_called = false; + + if (SSL_CTX_use_PrivateKey_file(context, + ssl_key_file, + SSL_FILETYPE_PEM) != 1) + { + if (ssl_passwd_cb_called) + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("private key file \"%s\" cannot be reloaded because it requires a passphrase", + ssl_key_file))); + else + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("could not load private key file \"%s\": %s", ssl_key_file, SSLerrmessage(ERR_get_error())))); + goto error; + } - if (SSL_CTX_check_private_key(SSL_context) != 1) - ereport(FATAL, - (errmsg("check of private key failed: %s", - SSLerrmessage(ERR_get_error())))); + if (SSL_CTX_check_private_key(context) != 1) + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("check of private key failed: %s", + SSLerrmessage(ERR_get_error())))); + goto error; } /* set up ephemeral DH keys, and disallow SSL v2/v3 while at it */ - SSL_CTX_set_tmp_dh_callback(SSL_context, tmp_dh_cb); - SSL_CTX_set_options(SSL_context, + SSL_CTX_set_tmp_dh_callback(context, tmp_dh_cb); + SSL_CTX_set_options(context, SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); /* set up ephemeral ECDH keys */ - initialize_ecdh(); + if (!initialize_ecdh(context, isServerStart)) + goto error; /* set up the allowed cipher list */ - if (SSL_CTX_set_cipher_list(SSL_context, SSLCipherSuites) != 1) - elog(FATAL, "could not set the cipher list (no valid ciphers available)"); + if (SSL_CTX_set_cipher_list(context, SSLCipherSuites) != 1) + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("could not set the cipher list (no valid ciphers available)"))); + goto error; + } /* Let server choose order */ if (SSLPreferServerCiphers) - SSL_CTX_set_options(SSL_context, SSL_OP_CIPHER_SERVER_PREFERENCE); + SSL_CTX_set_options(context, SSL_OP_CIPHER_SERVER_PREFERENCE); /* * Load CA store, so we can verify client certificates if needed. */ if (ssl_ca_file[0]) { - if (SSL_CTX_load_verify_locations(SSL_context, ssl_ca_file, NULL) != 1 || + if (SSL_CTX_load_verify_locations(context, ssl_ca_file, NULL) != 1 || (root_cert_list = SSL_load_client_CA_file(ssl_ca_file)) == NULL) - ereport(FATAL, - (errmsg("could not load root certificate file \"%s\": %s", + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("could not load root certificate file \"%s\": %s", ssl_ca_file, SSLerrmessage(ERR_get_error())))); + goto error; + } } /*---------- @@ -295,7 +362,7 @@ be_tls_init(void) */ if (ssl_crl_file[0]) { - X509_STORE *cvstore = SSL_CTX_get_cert_store(SSL_context); + X509_STORE *cvstore = SSL_CTX_get_cert_store(context); if (cvstore) { @@ -308,15 +375,20 @@ be_tls_init(void) X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); #else ereport(LOG, - (errmsg("SSL certificate revocation list file \"%s\" ignored", - ssl_crl_file), - errdetail("SSL library does not support certificate revocation lists."))); + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("SSL certificate revocation list file \"%s\" ignored", + ssl_crl_file), + errdetail("SSL library does not support certificate revocation lists."))); #endif } else - ereport(FATAL, - (errmsg("could not load SSL certificate revocation list file \"%s\": %s", + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("could not load SSL certificate revocation list file \"%s\": %s", ssl_crl_file, SSLerrmessage(ERR_get_error())))); + goto error; + } } } @@ -327,21 +399,53 @@ be_tls_init(void) * presented. We might fail such connections later, depending on what * we find in pg_hba.conf. */ - SSL_CTX_set_verify(SSL_context, + SSL_CTX_set_verify(context, (SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE), verify_cb); - /* Set flag to remember CA store is successfully loaded */ - ssl_loaded_verify_locations = true; - /* * Tell OpenSSL to send the list of root certs we trust to clients in * CertificateRequests. This lets a client with a keystore select the * appropriate client certificate to send to us. */ - SSL_CTX_set_client_CA_list(SSL_context, root_cert_list); + SSL_CTX_set_client_CA_list(context, root_cert_list); } + + /* + * Success! Replace any existing SSL_context. + */ + if (SSL_context) + SSL_CTX_free(SSL_context); + + SSL_context = context; + + /* + * Set flag to remember whether CA store has been loaded into SSL_context. + */ + if (ssl_ca_file[0]) + ssl_loaded_verify_locations = true; + else + ssl_loaded_verify_locations = false; + + return 0; + +error: + if (context) + SSL_CTX_free(context); + return -1; +} + +/* + * Destroy global SSL context, if any. + */ +void +be_tls_destroy(void) +{ + if (SSL_context) + SSL_CTX_free(SSL_context); + SSL_context = NULL; + ssl_loaded_verify_locations = false; } /* @@ -358,6 +462,14 @@ be_tls_open_server(Port *port) Assert(!port->ssl); Assert(!port->peer); + if (!SSL_context) + { + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("could not initialize SSL connection: SSL context not set up"))); + return -1; + } + if (!(port->ssl = SSL_new(SSL_context))) { ereport(COMMERROR, @@ -418,7 +530,8 @@ be_tls_open_server(Port *port) else waitfor = WL_SOCKET_WRITEABLE; - WaitLatchOrSocket(MyLatch, waitfor, port->sock, 0); + WaitLatchOrSocket(MyLatch, waitfor, port->sock, 0, + WAIT_EVENT_SSL_OPEN_SERVER); goto aloop; case SSL_ERROR_SYSCALL: if (r < 0) @@ -451,8 +564,6 @@ be_tls_open_server(Port *port) return -1; } - port->count = 0; - /* Get client certificate, if available. */ port->peer = SSL_get_peer_certificate(port->ssl); @@ -553,7 +664,7 @@ be_tls_read(Port *port, void *ptr, size_t len, int *waitfor) switch (err) { case SSL_ERROR_NONE: - port->count += n; + /* a-ok */ break; case SSL_ERROR_WANT_READ: *waitfor = WL_SOCKET_READABLE; @@ -613,7 +724,7 @@ be_tls_write(Port *port, void *ptr, size_t len, int *waitfor) switch (err) { case SSL_ERROR_NONE: - port->count += n; + /* a-ok */ break; case SSL_ERROR_WANT_READ: *waitfor = WL_SOCKET_READABLE; @@ -673,8 +784,12 @@ be_tls_write(Port *port, void *ptr, size_t len, int *waitfor) * to retry; do we need to adopt their logic for that? */ -static bool my_bio_initialized = false; -static BIO_METHOD my_bio_methods; +#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 = NULL; static int my_sock_read(BIO *h, char *buf, int size) @@ -683,7 +798,7 @@ my_sock_read(BIO *h, char *buf, int size) if (buf != NULL) { - res = secure_raw_read(((Port *) h->ptr), buf, size); + res = secure_raw_read(((Port *) BIO_get_data(h)), buf, size); BIO_clear_retry_flags(h); if (res <= 0) { @@ -703,7 +818,7 @@ my_sock_write(BIO *h, const char *buf, int size) { int res = 0; - res = secure_raw_write(((Port *) h->ptr), buf, size); + res = secure_raw_write(((Port *) BIO_get_data(h)), buf, size); BIO_clear_retry_flags(h); if (res <= 0) { @@ -720,14 +835,41 @@ my_sock_write(BIO *h, const char *buf, int size) static BIO_METHOD * my_BIO_s_socket(void) { - if (!my_bio_initialized) + if (!my_bio_methods) { - memcpy(&my_bio_methods, BIO_s_socket(), sizeof(BIO_METHOD)); - my_bio_methods.bread = my_sock_read; - my_bio_methods.bwrite = my_sock_write; - my_bio_initialized = true; + 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_methods = BIO_meth_new(my_bio_index, "PostgreSQL backend socket"); + if (!my_bio_methods) + return NULL; + 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; + return my_bio_methods; } /* This should exactly match openssl's SSL_set_fd except for using my BIO */ @@ -735,17 +877,23 @@ static int my_SSL_set_fd(Port *port, int fd) { int ret = 0; - BIO *bio = NULL; + BIO *bio; + BIO_METHOD *bio_method; - bio = BIO_new(my_BIO_s_socket()); + 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; } - /* Use 'ptr' to store pointer to PGconn */ - bio->ptr = port; + BIO_set_data(bio, port); BIO_set_fd(bio, fd, BIO_NOCLOSE); SSL_set_bio(port->ssl, bio, bio); @@ -839,6 +987,27 @@ load_dh_buffer(const char *buffer, size_t len) return dh; } +/* + * Generate DH parameters. + * + * Last resort if we can't load precomputed nor hardcoded + * parameters. + */ +static DH * +generate_dh_parameters(int prime_len, int generator) +{ + DH *dh; + + if ((dh = DH_new()) == NULL) + return NULL; + + if (DH_generate_parameters_ex(dh, prime_len, generator, NULL)) + return dh; + + DH_free(dh); + return NULL; +} + /* * Generate an ephemeral DH key. Because this can take a long * time to compute, we can use precomputed parameters of the @@ -908,12 +1077,32 @@ tmp_dh_cb(SSL *s, int is_export, int keylength) ereport(DEBUG2, (errmsg_internal("DH: generating parameters (%d bits)", keylength))); - r = DH_generate_parameters(keylength, DH_GENERATOR_2, NULL, NULL); + r = generate_dh_parameters(keylength, DH_GENERATOR_2); } return r; } +/* + * Passphrase collection callback + * + * If OpenSSL is told to use a passphrase-protected server key, by default + * it will issue a prompt on /dev/tty and try to read a key from there. + * That's no good during a postmaster SIGHUP cycle, not to mention SSL context + * reload in an EXEC_BACKEND postmaster child. So override it with this dummy + * function that just returns an empty passphrase, guaranteeing failure. + */ +static int +ssl_passwd_cb(char *buf, int size, int rwflag, void *userdata) +{ + /* Set flag to change the error message we'll report */ + ssl_passwd_cb_called = true; + /* And return empty string */ + Assert(size > 0); + buf[0] = '\0'; + return 0; +} + /* * Certificate verification callback * @@ -975,27 +1164,37 @@ info_cb(const SSL *ssl, int type, int args) } } -static void -initialize_ecdh(void) +static bool +initialize_ecdh(SSL_CTX *context, bool isServerStart) { -#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_ECDH) +#ifndef OPENSSL_NO_ECDH EC_KEY *ecdh; int nid; nid = OBJ_sn2nid(SSLECDHCurve); if (!nid) - ereport(FATAL, - (errmsg("ECDH: unrecognized curve name: %s", SSLECDHCurve))); + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("ECDH: unrecognized curve name: %s", SSLECDHCurve))); + return false; + } ecdh = EC_KEY_new_by_curve_name(nid); if (!ecdh) - ereport(FATAL, - (errmsg("ECDH: could not create key"))); + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("ECDH: could not create key"))); + return false; + } - SSL_CTX_set_options(SSL_context, SSL_OP_SINGLE_ECDH_USE); - SSL_CTX_set_tmp_ecdh(SSL_context, ecdh); + SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE); + SSL_CTX_set_tmp_ecdh(context, ecdh); EC_KEY_free(ecdh); #endif + + return true; } /* diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c index cdd07d577b..785dadb6c2 100644 --- a/src/backend/libpq/be-secure.c +++ b/src/backend/libpq/be-secure.c @@ -6,7 +6,7 @@ * message integrity and endpoint authentication. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -33,6 +33,7 @@ #include "libpq/libpq.h" #include "miscadmin.h" +#include "pgstat.h" #include "tcop/tcopprot.h" #include "utils/memutils.h" #include "storage/ipc.h" @@ -62,16 +63,31 @@ bool SSLPreferServerCiphers; /* ------------------------------------------------------------ */ /* - * Initialize global context + * Initialize global context. + * + * If isServerStart is true, report any errors as FATAL (so we don't return). + * Otherwise, log errors at LOG level and return -1 to indicate trouble, + * preserving the old SSL state if any. Returns 0 if OK. */ int -secure_initialize(void) +secure_initialize(bool isServerStart) { #ifdef USE_SSL - be_tls_init(); + return be_tls_init(isServerStart); +#else + return 0; #endif +} - return 0; +/* + * Destroy global context, if any. + */ +void +secure_destroy(void) +{ +#ifdef USE_SSL + be_tls_destroy(); +#endif } /* @@ -146,7 +162,8 @@ secure_read(Port *port, void *ptr, size_t len) ModifyWaitEvent(FeBeWaitSet, 0, waitfor, NULL); - WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1); + WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1, + WAIT_EVENT_CLIENT_READ); /* * If the postmaster has died, it's not safe to continue running, @@ -247,7 +264,8 @@ secure_write(Port *port, void *ptr, size_t len) ModifyWaitEvent(FeBeWaitSet, 0, waitfor, NULL); - WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1); + WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1, + WAIT_EVENT_CLIENT_WRITE); /* See comments in secure_read. */ if (event.events & WL_POSTMASTER_DEATH) diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c index d79f5a2496..e1c10137d9 100644 --- a/src/backend/libpq/crypt.c +++ b/src/backend/libpq/crypt.c @@ -6,7 +6,7 @@ * * Original coding by Todd A. Brandys * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/libpq/crypt.c @@ -21,8 +21,8 @@ #endif #include "catalog/pg_authid.h" +#include "common/md5.h" #include "libpq/crypt.h" -#include "libpq/md5.h" #include "miscadmin.h" #include "utils/builtins.h" #include "utils/syscache.h" @@ -30,23 +30,28 @@ /* - * Check given password for given user, and return STATUS_OK or STATUS_ERROR. - * In the error case, optionally store a palloc'd string at *logdetail - * that will be sent to the postmaster log (but not the client). + * Fetch stored password for a user, for authentication. + * + * Returns STATUS_OK on success. On error, returns STATUS_ERROR, and stores + * a palloc'd string describing the reason, for the postmaster log, in + * *logdetail. The error reason should *not* be sent to the client, to avoid + * giving away user information! + * + * If the password is expired, it is still returned in *shadow_pass, but the + * return code is STATUS_ERROR. On other errors, *shadow_pass is set to + * NULL. */ int -md5_crypt_verify(const Port *port, const char *role, char *client_pass, - char **logdetail) +get_role_password(const char *role, char **shadow_pass, char **logdetail) { int retval = STATUS_ERROR; - char *shadow_pass, - *crypt_pwd; TimestampTz vuntil = 0; - char *crypt_client_pass = client_pass; HeapTuple roleTup; Datum datum; bool isnull; + *shadow_pass = NULL; + /* Get role info from pg_authid */ roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(role)); if (!HeapTupleIsValid(roleTup)) @@ -65,7 +70,7 @@ md5_crypt_verify(const Port *port, const char *role, char *client_pass, role); return STATUS_ERROR; /* user has no password */ } - shadow_pass = TextDatumGetCString(datum); + *shadow_pass = TextDatumGetCString(datum); datum = SysCacheGetAttr(AUTHNAME, roleTup, Anum_pg_authid_rolvaliduntil, &isnull); @@ -74,103 +79,151 @@ md5_crypt_verify(const Port *port, const char *role, char *client_pass, ReleaseSysCache(roleTup); - if (*shadow_pass == '\0') + if (**shadow_pass == '\0') { *logdetail = psprintf(_("User \"%s\" has an empty password."), role); + pfree(*shadow_pass); + *shadow_pass = NULL; return STATUS_ERROR; /* empty password */ } /* - * Compare with the encrypted or plain password depending on the - * authentication method being used for this connection. (We do not - * bother setting logdetail for pg_md5_encrypt failure: the only possible - * error is out-of-memory, which is unlikely, and if it did happen adding - * a psprintf call would only make things worse.) + * Password OK, now check to be sure we are not past rolvaliduntil */ - switch (port->hba->auth_method) + if (isnull) + retval = STATUS_OK; + else if (vuntil < GetCurrentTimestamp()) { - case uaMD5: - crypt_pwd = palloc(MD5_PASSWD_LEN + 1); - if (isMD5(shadow_pass)) - { - /* stored password already encrypted, only do salt */ - if (!pg_md5_encrypt(shadow_pass + strlen("md5"), - port->md5Salt, - sizeof(port->md5Salt), crypt_pwd)) - { - pfree(crypt_pwd); - return STATUS_ERROR; - } - } - else - { - /* stored password is plain, double-encrypt */ - char *crypt_pwd2 = palloc(MD5_PASSWD_LEN + 1); - - if (!pg_md5_encrypt(shadow_pass, - port->user_name, - strlen(port->user_name), - crypt_pwd2)) - { - pfree(crypt_pwd); - pfree(crypt_pwd2); - return STATUS_ERROR; - } - if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"), - port->md5Salt, - sizeof(port->md5Salt), - crypt_pwd)) - { - pfree(crypt_pwd); - pfree(crypt_pwd2); - return STATUS_ERROR; - } - pfree(crypt_pwd2); - } - break; - default: - if (isMD5(shadow_pass)) - { - /* Encrypt user-supplied password to match stored MD5 */ - crypt_client_pass = palloc(MD5_PASSWD_LEN + 1); - if (!pg_md5_encrypt(client_pass, - port->user_name, - strlen(port->user_name), - crypt_client_pass)) - { - pfree(crypt_client_pass); - return STATUS_ERROR; - } - } - crypt_pwd = shadow_pass; - break; + *logdetail = psprintf(_("User \"%s\" has an expired password."), + role); + retval = STATUS_ERROR; } + else + retval = STATUS_OK; + + return retval; +} - if (strcmp(crypt_client_pass, crypt_pwd) == 0) +/* + * Check MD5 authentication response, and return STATUS_OK or STATUS_ERROR. + * + * 'shadow_pass' is the user's correct password or password hash, as stored + * in pg_authid.rolpassword. + * 'client_pass' is the response given by the remote user to the MD5 challenge. + * 'md5_salt' is the salt used in the MD5 authentication challenge. + * + * In the error case, optionally store a palloc'd string at *logdetail + * that will be sent to the postmaster log (but not the client). + */ +int +md5_crypt_verify(const char *role, const char *shadow_pass, + const char *client_pass, + const char *md5_salt, int md5_salt_len, + char **logdetail) +{ + int retval; + char crypt_pwd[MD5_PASSWD_LEN + 1]; + char crypt_pwd2[MD5_PASSWD_LEN + 1]; + + Assert(md5_salt_len > 0); + + /* + * Compute the correct answer for the MD5 challenge. + * + * We do not bother setting logdetail for any pg_md5_encrypt failure + * below: the only possible error is out-of-memory, which is unlikely, and + * if it did happen adding a psprintf call would only make things worse. + */ + if (isMD5(shadow_pass)) { - /* - * Password OK, now check to be sure we are not past rolvaliduntil - */ - if (isnull) - retval = STATUS_OK; - else if (vuntil < GetCurrentTimestamp()) + /* stored password already encrypted, only do salt */ + if (!pg_md5_encrypt(shadow_pass + strlen("md5"), + md5_salt, md5_salt_len, + crypt_pwd)) { - *logdetail = psprintf(_("User \"%s\" has an expired password."), - role); - retval = STATUS_ERROR; + return STATUS_ERROR; } - else - retval = STATUS_OK; } else + { + /* stored password is plain, double-encrypt */ + if (!pg_md5_encrypt(shadow_pass, + role, + strlen(role), + crypt_pwd2)) + { + return STATUS_ERROR; + } + if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"), + md5_salt, md5_salt_len, + crypt_pwd)) + { + return STATUS_ERROR; + } + } + + if (strcmp(client_pass, crypt_pwd) == 0) + retval = STATUS_OK; + else + { *logdetail = psprintf(_("Password does not match for user \"%s\"."), role); + retval = STATUS_ERROR; + } + + return retval; +} + +/* + * Check given password for given user, and return STATUS_OK or STATUS_ERROR. + * + * 'shadow_pass' is the user's correct password or password hash, as stored + * in pg_authid.rolpassword. + * 'client_pass' is the password given by the remote user. + * + * In the error case, optionally store a palloc'd string at *logdetail + * that will be sent to the postmaster log (but not the client). + */ +int +plain_crypt_verify(const char *role, const char *shadow_pass, + const char *client_pass, + char **logdetail) +{ + int retval; + char crypt_client_pass[MD5_PASSWD_LEN + 1]; - if (port->hba->auth_method == uaMD5) - pfree(crypt_pwd); - if (crypt_client_pass != client_pass) - pfree(crypt_client_pass); + /* + * Client sent password in plaintext. If we have an MD5 hash stored, hash + * the password the client sent, and compare the hashes. Otherwise + * compare the plaintext passwords directly. + */ + if (isMD5(shadow_pass)) + { + if (!pg_md5_encrypt(client_pass, + role, + strlen(role), + crypt_client_pass)) + { + /* + * We do not bother setting logdetail for pg_md5_encrypt failure: + * the only possible error is out-of-memory, which is unlikely, + * and if it did happen adding a psprintf call would only make + * things worse. + */ + return STATUS_ERROR; + } + client_pass = crypt_client_pass; + } + + if (strcmp(client_pass, shadow_pass) == 0) + retval = STATUS_OK; + else + { + *logdetail = psprintf(_("Password does not match for user \"%s\"."), + role); + retval = STATUS_ERROR; + } return retval; } diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c index 1b4bbce42d..07f046fd8b 100644 --- a/src/backend/libpq/hba.c +++ b/src/backend/libpq/hba.c @@ -5,7 +5,7 @@ * wherein you authenticate a user by seeing what IP address the system * says he comes from and choosing authentication method based on it). * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -26,7 +26,8 @@ #include #include "catalog/pg_collation.h" -#include "libpq/ip.h" +#include "common/ip.h" +#include "libpq/ifaddr.h" #include "libpq/libpq.h" #include "postmaster/postmaster.h" #include "regex/regex.h" @@ -387,10 +388,8 @@ tokenize_file(const char *filename, FILE *file, MemoryContext oldcxt; linecxt = AllocSetContextCreate(CurrentMemoryContext, - "tokenize file cxt", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + "tokenize_file", + ALLOCSET_SMALL_SIZES); oldcxt = MemoryContextSwitchTo(linecxt); *lines = *line_nums = NIL; @@ -871,28 +870,23 @@ parse_hba_line(List *line, int line_num, char *raw_line) if (token->string[4] == 's') /* "hostssl" */ { - /* SSL support must be actually active, else complain */ + parsedline->conntype = ctHostSSL; + /* Log a warning if SSL support is not active */ #ifdef USE_SSL - if (EnableSSL) - parsedline->conntype = ctHostSSL; - else - { + if (!EnableSSL) ereport(LOG, (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("hostssl requires SSL to be turned on"), + errmsg("hostssl record cannot match because SSL is disabled"), errhint("Set ssl = on in postgresql.conf."), errcontext("line %d of configuration file \"%s\"", line_num, HbaFileName))); - return NULL; - } #else ereport(LOG, (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("hostssl is not supported by this build"), + errmsg("hostssl record cannot match because SSL is not supported by this build"), errhint("Compile with --with-openssl to use SSL connections."), errcontext("line %d of configuration file \"%s\"", line_num, HbaFileName))); - return NULL; #endif } else if (token->string[4] == 'n') /* "hostnossl" */ @@ -1418,10 +1412,6 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num) } else if (strcmp(name, "clientcert") == 0) { - /* - * Since we require ctHostSSL, this really can never happen on - * non-SSL-enabled builds, so don't bother checking for USE_SSL. - */ if (hbaline->conntype != ctHostSSL) { ereport(LOG, @@ -1433,16 +1423,6 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num) } if (strcmp(val, "1") == 0) { - if (!secure_loaded_verify_locations()) - { - ereport(LOG, - (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("client certificates can only be checked if a root certificate store is available"), - errhint("Make sure the configuration parameter \"%s\" is set.", "ssl_ca_file"), - errcontext("line %d of configuration file \"%s\"", - line_num, HbaFileName))); - return false; - } hbaline->clientcert = true; } else @@ -1817,9 +1797,7 @@ load_hba(void) Assert(PostmasterContext); hbacxt = AllocSetContextCreate(PostmasterContext, "hba parser context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_SMALL_SIZES); oldcxt = MemoryContextSwitchTo(hbacxt); forthree(line, hba_lines, line_num, hba_line_nums, raw_line, hba_raw_lines) { @@ -2195,9 +2173,7 @@ load_ident(void) Assert(PostmasterContext); ident_context = AllocSetContextCreate(PostmasterContext, "ident parser context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_SMALL_SIZES); oldcxt = MemoryContextSwitchTo(ident_context); forboth(line_cell, ident_lines, num_cell, ident_line_nums) { diff --git a/src/backend/libpq/ip.c b/src/backend/libpq/ifaddr.c similarity index 72% rename from src/backend/libpq/ip.c rename to src/backend/libpq/ifaddr.c index 9591ed2862..7692881c8b 100644 --- a/src/backend/libpq/ip.c +++ b/src/backend/libpq/ifaddr.c @@ -1,14 +1,14 @@ /*------------------------------------------------------------------------- * - * ip.c - * IPv6-aware network access. + * ifaddr.c + * IP netmask calculations, and enumerating network interfaces. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * src/backend/libpq/ip.c + * src/backend/libpq/ifaddr.c * * This file and the IPV6 implementation were initially provided by * Nigel Kukard , Linux Based Systems Design @@ -17,8 +17,7 @@ *------------------------------------------------------------------------- */ -/* This is intended to be used in both frontend and backend, so use c.h */ -#include "c.h" +#include "postgres.h" #include #include @@ -32,8 +31,7 @@ #include #include -#include "libpq/ip.h" - +#include "libpq/ifaddr.h" static int range_sockaddr_AF_INET(const struct sockaddr_in * addr, const struct sockaddr_in * netaddr, @@ -45,226 +43,6 @@ static int range_sockaddr_AF_INET6(const struct sockaddr_in6 * addr, const struct sockaddr_in6 * netmask); #endif -#ifdef HAVE_UNIX_SOCKETS -static int getaddrinfo_unix(const char *path, - const struct addrinfo * hintsp, - struct addrinfo ** result); - -static int getnameinfo_unix(const struct sockaddr_un * sa, int salen, - char *node, int nodelen, - char *service, int servicelen, - int flags); -#endif - - -/* - * pg_getaddrinfo_all - get address info for Unix, IPv4 and IPv6 sockets - */ -int -pg_getaddrinfo_all(const char *hostname, const char *servname, - const struct addrinfo * hintp, struct addrinfo ** result) -{ - int rc; - - /* not all versions of getaddrinfo() zero *result on failure */ - *result = NULL; - -#ifdef HAVE_UNIX_SOCKETS - if (hintp->ai_family == AF_UNIX) - return getaddrinfo_unix(servname, hintp, result); -#endif - - /* NULL has special meaning to getaddrinfo(). */ - rc = getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname, - servname, hintp, result); - - return rc; -} - - -/* - * pg_freeaddrinfo_all - free addrinfo structures for IPv4, IPv6, or Unix - * - * Note: the ai_family field of the original hint structure must be passed - * so that we can tell whether the addrinfo struct was built by the system's - * getaddrinfo() routine or our own getaddrinfo_unix() routine. Some versions - * of getaddrinfo() might be willing to return AF_UNIX addresses, so it's - * not safe to look at ai_family in the addrinfo itself. - */ -void -pg_freeaddrinfo_all(int hint_ai_family, struct addrinfo * ai) -{ -#ifdef HAVE_UNIX_SOCKETS - if (hint_ai_family == AF_UNIX) - { - /* struct was built by getaddrinfo_unix (see pg_getaddrinfo_all) */ - while (ai != NULL) - { - struct addrinfo *p = ai; - - ai = ai->ai_next; - free(p->ai_addr); - free(p); - } - } - else -#endif /* HAVE_UNIX_SOCKETS */ - { - /* struct was built by getaddrinfo() */ - if (ai != NULL) - freeaddrinfo(ai); - } -} - - -/* - * pg_getnameinfo_all - get name info for Unix, IPv4 and IPv6 sockets - * - * The API of this routine differs from the standard getnameinfo() definition - * in two ways: first, the addr parameter is declared as sockaddr_storage - * rather than struct sockaddr, and second, the node and service fields are - * guaranteed to be filled with something even on failure return. - */ -int -pg_getnameinfo_all(const struct sockaddr_storage * addr, int salen, - char *node, int nodelen, - char *service, int servicelen, - int flags) -{ - int rc; - -#ifdef HAVE_UNIX_SOCKETS - if (addr && addr->ss_family == AF_UNIX) - rc = getnameinfo_unix((const struct sockaddr_un *) addr, salen, - node, nodelen, - service, servicelen, - flags); - else -#endif - rc = getnameinfo((const struct sockaddr *) addr, salen, - node, nodelen, - service, servicelen, - flags); - - if (rc != 0) - { - if (node) - strlcpy(node, "???", nodelen); - if (service) - strlcpy(service, "???", servicelen); - } - - return rc; -} - - -#if defined(HAVE_UNIX_SOCKETS) - -/* ------- - * getaddrinfo_unix - get unix socket info using IPv6-compatible API - * - * Bugs: only one addrinfo is set even though hintsp is NULL or - * ai_socktype is 0 - * AI_CANONNAME is not supported. - * ------- - */ -static int -getaddrinfo_unix(const char *path, const struct addrinfo * hintsp, - struct addrinfo ** result) -{ - struct addrinfo hints; - struct addrinfo *aip; - struct sockaddr_un *unp; - - *result = NULL; - - MemSet(&hints, 0, sizeof(hints)); - - if (strlen(path) >= sizeof(unp->sun_path)) - return EAI_FAIL; - - if (hintsp == NULL) - { - hints.ai_family = AF_UNIX; - hints.ai_socktype = SOCK_STREAM; - } - else - memcpy(&hints, hintsp, sizeof(hints)); - - if (hints.ai_socktype == 0) - hints.ai_socktype = SOCK_STREAM; - - if (hints.ai_family != AF_UNIX) - { - /* shouldn't have been called */ - return EAI_FAIL; - } - - aip = calloc(1, sizeof(struct addrinfo)); - if (aip == NULL) - return EAI_MEMORY; - - unp = calloc(1, sizeof(struct sockaddr_un)); - if (unp == NULL) - { - free(aip); - return EAI_MEMORY; - } - - aip->ai_family = AF_UNIX; - aip->ai_socktype = hints.ai_socktype; - aip->ai_protocol = hints.ai_protocol; - aip->ai_next = NULL; - aip->ai_canonname = NULL; - *result = aip; - - unp->sun_family = AF_UNIX; - aip->ai_addr = (struct sockaddr *) unp; - aip->ai_addrlen = sizeof(struct sockaddr_un); - - strcpy(unp->sun_path, path); - -#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN - unp->sun_len = sizeof(struct sockaddr_un); -#endif - - return 0; -} - -/* - * Convert an address to a hostname. - */ -static int -getnameinfo_unix(const struct sockaddr_un * sa, int salen, - char *node, int nodelen, - char *service, int servicelen, - int flags) -{ - int ret = -1; - - /* Invalid arguments. */ - if (sa == NULL || sa->sun_family != AF_UNIX || - (node == NULL && service == NULL)) - return EAI_FAIL; - - if (node) - { - ret = snprintf(node, nodelen, "%s", "[local]"); - if (ret == -1 || ret > nodelen) - return EAI_MEMORY; - } - - if (service) - { - ret = snprintf(service, servicelen, "%s", sa->sun_path); - if (ret == -1 || ret > servicelen) - return EAI_MEMORY; - } - - return 0; -} -#endif /* HAVE_UNIX_SOCKETS */ - /* * pg_range_sockaddr - is addr within the subnet specified by netaddr/netmask ? diff --git a/src/backend/libpq/pg_hba.conf.sample b/src/backend/libpq/pg_hba.conf.sample index 86a89edf9a..e0fbfcb026 100644 --- a/src/backend/libpq/pg_hba.conf.sample +++ b/src/backend/libpq/pg_hba.conf.sample @@ -59,11 +59,11 @@ # its special character, and just match a database or username with # that name. # -# This file is read on server startup and when the postmaster receives -# a SIGHUP signal. If you edit the file on a running system, you have -# to SIGHUP the postmaster for the changes to take effect. You can -# use "pg_ctl reload" to do that. - +# This file is read on server startup and when the server receives a +# SIGHUP signal. If you edit the file on a running system, you have to +# SIGHUP the server for the changes to take effect, run "pg_ctl reload", +# or execute "SELECT pg_reload_conf()". +# # Put your actual configuration here # ---------------------------------- # diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index ba42753c06..7939b1f544 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -27,7 +27,7 @@ * the backend's "backend/libpq" is quite separate from "interfaces/libpq". * All that remains is similarities of names to trap the unwary... * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/libpq/pqcomm.c @@ -89,7 +89,7 @@ #include #endif -#include "libpq/ip.h" +#include "common/ip.h" #include "libpq/libpq.h" #include "miscadmin.h" #include "storage/ipc.h" @@ -145,7 +145,6 @@ static void socket_startcopyout(void); static void socket_endcopyout(bool errorAbort); static int internal_putbytes(const char *s, size_t len); static int internal_flush(void); -static void socket_set_nonblocking(bool nonblocking); #ifdef HAVE_UNIX_SOCKETS static int Lock_AF_UNIX(char *unixSocketDir, char *unixSocketPath); @@ -684,16 +683,6 @@ StreamConnection(pgsocket server_fd, Port *port) return STATUS_ERROR; } -#ifdef SCO_ACCEPT_BUG - - /* - * UnixWare 7+ and OpenServer 5.0.4 are known to have this bug, but it - * shouldn't hurt to catch it for all versions of those platforms. - */ - if (port->raddr.addr.ss_family == 0) - port->raddr.addr.ss_family = AF_UNIX; -#endif - /* fill in the server (local) address */ port->laddr.salen = sizeof(port->laddr.addr); if (getsockname(port->sock, diff --git a/src/backend/libpq/pqformat.c b/src/backend/libpq/pqformat.c index b5d9d64e54..c8cf67c041 100644 --- a/src/backend/libpq/pqformat.c +++ b/src/backend/libpq/pqformat.c @@ -21,7 +21,7 @@ * are different. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/libpq/pqformat.c diff --git a/src/backend/libpq/pqmq.c b/src/backend/libpq/pqmq.c index 921242fbc4..96939327c3 100644 --- a/src/backend/libpq/pqmq.c +++ b/src/backend/libpq/pqmq.c @@ -3,7 +3,7 @@ * pqmq.c * Use the frontend/backend protocol for communication over a shm_mq * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/libpq/pqmq.c @@ -17,6 +17,7 @@ #include "libpq/pqformat.h" #include "libpq/pqmq.h" #include "miscadmin.h" +#include "pgstat.h" #include "tcop/tcopprot.h" #include "utils/builtins.h" @@ -171,7 +172,8 @@ mq_putmessage(char msgtype, const char *s, size_t len) if (result != SHM_MQ_WOULD_BLOCK) break; - WaitLatch(&MyProc->procLatch, WL_LATCH_SET, 0); + WaitLatch(&MyProc->procLatch, WL_LATCH_SET, 0, + WAIT_EVENT_MQ_PUT_MESSAGE); ResetLatch(&MyProc->procLatch); CHECK_FOR_INTERRUPTS(); } @@ -237,10 +239,26 @@ pq_parse_errornotice(StringInfo msg, ErrorData *edata) switch (code) { case PG_DIAG_SEVERITY: + /* ignore, trusting we'll get a nonlocalized version */ + break; + case PG_DIAG_SEVERITY_NONLOCALIZED: if (strcmp(value, "DEBUG") == 0) - edata->elevel = DEBUG1; /* or some other DEBUG level */ + { + /* + * We can't reconstruct the exact DEBUG level, but + * presumably it was >= client_min_messages, so select + * DEBUG1 to ensure we'll pass it on to the client. + */ + edata->elevel = DEBUG1; + } else if (strcmp(value, "LOG") == 0) - edata->elevel = LOG; /* can't be COMMERROR */ + { + /* + * It can't be LOG_SERVER_ONLY, or the worker wouldn't + * have sent it to us; so LOG is the correct value. + */ + edata->elevel = LOG; + } else if (strcmp(value, "INFO") == 0) edata->elevel = INFO; else if (strcmp(value, "NOTICE") == 0) @@ -254,11 +272,11 @@ pq_parse_errornotice(StringInfo msg, ErrorData *edata) else if (strcmp(value, "PANIC") == 0) edata->elevel = PANIC; else - elog(ERROR, "unknown error severity"); + elog(ERROR, "unrecognized error severity: \"%s\"", value); break; case PG_DIAG_SQLSTATE: if (strlen(value) != 5) - elog(ERROR, "malformed sql state"); + elog(ERROR, "invalid SQLSTATE: \"%s\"", value); edata->sqlerrcode = MAKE_SQLSTATE(value[0], value[1], value[2], value[3], value[4]); break; @@ -308,7 +326,7 @@ pq_parse_errornotice(StringInfo msg, ErrorData *edata) edata->funcname = pstrdup(value); break; default: - elog(ERROR, "unknown error field: %d", (int) code); + elog(ERROR, "unrecognized error field code: %d", (int) code); break; } } diff --git a/src/backend/libpq/pqsignal.c b/src/backend/libpq/pqsignal.c index b5c1855557..476e883a68 100644 --- a/src/backend/libpq/pqsignal.c +++ b/src/backend/libpq/pqsignal.c @@ -3,7 +3,7 @@ * pqsignal.c * Backend signal(2) support (see also src/port/pqsignal.c) * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/main/main.c b/src/backend/main/main.c index c018c90524..8846865ba3 100644 --- a/src/backend/main/main.c +++ b/src/backend/main/main.c @@ -9,7 +9,7 @@ * proper FooMain() routine for the incarnation. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -33,8 +33,8 @@ #include "bootstrap/bootstrap.h" #include "common/username.h" +#include "port/atomics.h" #include "postmaster/postmaster.h" -#include "storage/barrier.h" #include "storage/s_lock.h" #include "storage/spin.h" #include "tcop/tcopprot.h" diff --git a/src/backend/nodes/bitmapset.c b/src/backend/nodes/bitmapset.c index f281cc5471..252af5c870 100644 --- a/src/backend/nodes/bitmapset.c +++ b/src/backend/nodes/bitmapset.c @@ -11,7 +11,7 @@ * bms_is_empty() in preference to testing for NULL.) * * - * Copyright (c) 2003-2016, PostgreSQL Global Development Group + * Copyright (c) 2003-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/nodes/bitmapset.c diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 3244c76ddc..30d733e57a 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -11,7 +11,7 @@ * be handled easily in a simple depth-first traversal. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -90,13 +90,15 @@ _copyPlannedStmt(const PlannedStmt *from) COPY_NODE_FIELD(planTree); COPY_NODE_FIELD(rtable); COPY_NODE_FIELD(resultRelations); - COPY_NODE_FIELD(utilityStmt); COPY_NODE_FIELD(subplans); COPY_BITMAPSET_FIELD(rewindPlanIDs); COPY_NODE_FIELD(rowMarks); COPY_NODE_FIELD(relationOids); COPY_NODE_FIELD(invalItems); COPY_SCALAR_FIELD(nParamExec); + COPY_NODE_FIELD(utilityStmt); + COPY_LOCATION_FIELD(stmt_location); + COPY_LOCATION_FIELD(stmt_len); return newnode; } @@ -163,6 +165,22 @@ _copyResult(const Result *from) return newnode; } +/* + * _copyProjectSet + */ +static ProjectSet * +_copyProjectSet(const ProjectSet *from) +{ + ProjectSet *newnode = makeNode(ProjectSet); + + /* + * copy node superclass fields + */ + CopyPlanFields((const Plan *) from, (Plan *) newnode); + + return newnode; +} + /* * _copyModifyTable */ @@ -877,6 +895,7 @@ _copyAgg(const Agg *from) COPY_POINTER_FIELD(grpOperators, from->numCols * sizeof(Oid)); } COPY_SCALAR_FIELD(numGroups); + COPY_BITMAPSET_FIELD(aggParams); COPY_NODE_FIELD(groupingSets); COPY_NODE_FIELD(chain); @@ -1111,7 +1130,7 @@ _copyRangeVar(const RangeVar *from) COPY_STRING_FIELD(catalogname); COPY_STRING_FIELD(schemaname); COPY_STRING_FIELD(relname); - COPY_SCALAR_FIELD(inhOpt); + COPY_SCALAR_FIELD(inh); COPY_SCALAR_FIELD(relpersistence); COPY_NODE_FIELD(alias); COPY_LOCATION_FIELD(location); @@ -1752,6 +1771,22 @@ _copyMinMaxExpr(const MinMaxExpr *from) return newnode; } +/* + * _copySQLValueFunction + */ +static SQLValueFunction * +_copySQLValueFunction(const SQLValueFunction *from) +{ + SQLValueFunction *newnode = makeNode(SQLValueFunction); + + COPY_SCALAR_FIELD(op); + COPY_SCALAR_FIELD(type); + COPY_SCALAR_FIELD(typmod); + COPY_LOCATION_FIELD(location); + + return newnode; +} + /* * _copyXmlExpr */ @@ -2008,6 +2043,8 @@ _copyRestrictInfo(const RestrictInfo *from) COPY_SCALAR_FIELD(outerjoin_delayed); COPY_SCALAR_FIELD(can_join); COPY_SCALAR_FIELD(pseudoconstant); + COPY_SCALAR_FIELD(leakproof); + COPY_SCALAR_FIELD(security_level); COPY_BITMAPSET_FIELD(clause_relids); COPY_BITMAPSET_FIELD(required_relids); COPY_BITMAPSET_FIELD(outer_relids); @@ -2132,13 +2169,12 @@ _copyRangeTblEntry(const RangeTblEntry *from) COPY_NODE_FIELD(functions); COPY_SCALAR_FIELD(funcordinality); COPY_NODE_FIELD(values_lists); - COPY_NODE_FIELD(values_collations); COPY_STRING_FIELD(ctename); COPY_SCALAR_FIELD(ctelevelsup); COPY_SCALAR_FIELD(self_reference); - COPY_NODE_FIELD(ctecoltypes); - COPY_NODE_FIELD(ctecoltypmods); - COPY_NODE_FIELD(ctecolcollations); + COPY_NODE_FIELD(coltypes); + COPY_NODE_FIELD(coltypmods); + COPY_NODE_FIELD(colcollations); COPY_NODE_FIELD(alias); COPY_NODE_FIELD(eref); COPY_SCALAR_FIELD(lateral); @@ -2659,6 +2695,7 @@ _copyDefElem(const DefElem *from) COPY_STRING_FIELD(defname); COPY_NODE_FIELD(arg); COPY_SCALAR_FIELD(defaction); + COPY_LOCATION_FIELD(location); return newnode; } @@ -2700,6 +2737,18 @@ _copyRoleSpec(const RoleSpec *from) return newnode; } +static TriggerTransition * +_copyTriggerTransition(const TriggerTransition *from) +{ + TriggerTransition *newnode = makeNode(TriggerTransition); + + COPY_STRING_FIELD(name); + COPY_SCALAR_FIELD(isNew); + COPY_SCALAR_FIELD(isTable); + + return newnode; +} + static Query * _copyQuery(const Query *from) { @@ -2713,6 +2762,7 @@ _copyQuery(const Query *from) COPY_SCALAR_FIELD(resultRelation); COPY_SCALAR_FIELD(hasAggs); COPY_SCALAR_FIELD(hasWindowFuncs); + COPY_SCALAR_FIELD(hasTargetSRFs); COPY_SCALAR_FIELD(hasSubLinks); COPY_SCALAR_FIELD(hasDistinctOn); COPY_SCALAR_FIELD(hasRecursive); @@ -2737,6 +2787,20 @@ _copyQuery(const Query *from) COPY_NODE_FIELD(setOperations); COPY_NODE_FIELD(constraintDeps); COPY_NODE_FIELD(withCheckOptions); + COPY_LOCATION_FIELD(stmt_location); + COPY_LOCATION_FIELD(stmt_len); + + return newnode; +} + +static RawStmt * +_copyRawStmt(const RawStmt *from) +{ + RawStmt *newnode = makeNode(RawStmt); + + COPY_NODE_FIELD(stmt); + COPY_LOCATION_FIELD(stmt_location); + COPY_LOCATION_FIELD(stmt_len); return newnode; } @@ -2999,6 +3063,8 @@ CopyCreateStmtFields(const CreateStmt *from, CreateStmt *newnode) COPY_NODE_FIELD(relation); COPY_NODE_FIELD(tableElts); COPY_NODE_FIELD(inhRelations); + COPY_NODE_FIELD(partspec); + COPY_NODE_FIELD(partbound); COPY_NODE_FIELD(ofTypename); COPY_NODE_FIELD(constraints); COPY_NODE_FIELD(options); @@ -3357,10 +3423,11 @@ _copyAlterEnumStmt(const AlterEnumStmt *from) AlterEnumStmt *newnode = makeNode(AlterEnumStmt); COPY_NODE_FIELD(typeName); + COPY_STRING_FIELD(oldVal); COPY_STRING_FIELD(newVal); COPY_STRING_FIELD(newValNeighbor); COPY_SCALAR_FIELD(newValIsAfter); - COPY_SCALAR_FIELD(skipIfExists); + COPY_SCALAR_FIELD(skipIfNewValExists); return newnode; } @@ -3873,6 +3940,7 @@ _copyCreateTrigStmt(const CreateTrigStmt *from) COPY_NODE_FIELD(columns); COPY_NODE_FIELD(whenClause); COPY_SCALAR_FIELD(isconstraint); + COPY_NODE_FIELD(transitionRels); COPY_SCALAR_FIELD(deferrable); COPY_SCALAR_FIELD(initdeferred); COPY_NODE_FIELD(constrrel); @@ -4133,6 +4201,7 @@ _copyCreatePolicyStmt(const CreatePolicyStmt *from) COPY_STRING_FIELD(policy_name); COPY_NODE_FIELD(table); COPY_STRING_FIELD(cmd_name); + COPY_SCALAR_FIELD(permissive); COPY_NODE_FIELD(roles); COPY_NODE_FIELD(qual); COPY_NODE_FIELD(with_check); @@ -4154,6 +4223,132 @@ _copyAlterPolicyStmt(const AlterPolicyStmt *from) return newnode; } +static PartitionSpec * +_copyPartitionSpec(const PartitionSpec *from) +{ + PartitionSpec *newnode = makeNode(PartitionSpec); + + COPY_STRING_FIELD(strategy); + COPY_NODE_FIELD(partParams); + COPY_LOCATION_FIELD(location); + + return newnode; +} + +static PartitionElem * +_copyPartitionElem(const PartitionElem *from) +{ + PartitionElem *newnode = makeNode(PartitionElem); + + COPY_STRING_FIELD(name); + COPY_NODE_FIELD(expr); + COPY_NODE_FIELD(collation); + COPY_NODE_FIELD(opclass); + COPY_LOCATION_FIELD(location); + + return newnode; +} + +static PartitionBoundSpec * +_copyPartitionBoundSpec(const PartitionBoundSpec *from) +{ + PartitionBoundSpec *newnode = makeNode(PartitionBoundSpec); + + COPY_SCALAR_FIELD(strategy); + COPY_NODE_FIELD(listdatums); + COPY_NODE_FIELD(lowerdatums); + COPY_NODE_FIELD(upperdatums); + COPY_LOCATION_FIELD(location); + + return newnode; +} + +static PartitionRangeDatum * +_copyPartitionRangeDatum(const PartitionRangeDatum *from) +{ + PartitionRangeDatum *newnode = makeNode(PartitionRangeDatum); + + COPY_SCALAR_FIELD(infinite); + COPY_NODE_FIELD(value); + COPY_LOCATION_FIELD(location); + + return newnode; +} + +static PartitionCmd * +_copyPartitionCmd(const PartitionCmd *from) +{ + PartitionCmd *newnode = makeNode(PartitionCmd); + + COPY_NODE_FIELD(name); + COPY_NODE_FIELD(bound); + + return newnode; +} + +static CreatePublicationStmt * +_copyCreatePublicationStmt(const CreatePublicationStmt *from) +{ + CreatePublicationStmt *newnode = makeNode(CreatePublicationStmt); + + COPY_STRING_FIELD(pubname); + COPY_NODE_FIELD(options); + COPY_NODE_FIELD(tables); + COPY_SCALAR_FIELD(for_all_tables); + + return newnode; +} + +static AlterPublicationStmt * +_copyAlterPublicationStmt(const AlterPublicationStmt *from) +{ + AlterPublicationStmt *newnode = makeNode(AlterPublicationStmt); + + COPY_STRING_FIELD(pubname); + COPY_NODE_FIELD(options); + COPY_NODE_FIELD(tables); + COPY_SCALAR_FIELD(for_all_tables); + COPY_SCALAR_FIELD(tableAction); + + return newnode; +} + +static CreateSubscriptionStmt * +_copyCreateSubscriptionStmt(const CreateSubscriptionStmt *from) +{ + CreateSubscriptionStmt *newnode = makeNode(CreateSubscriptionStmt); + + COPY_STRING_FIELD(subname); + COPY_STRING_FIELD(conninfo); + COPY_NODE_FIELD(publication); + COPY_NODE_FIELD(options); + + return newnode; +} + +static AlterSubscriptionStmt * +_copyAlterSubscriptionStmt(const AlterSubscriptionStmt *from) +{ + AlterSubscriptionStmt *newnode = makeNode(AlterSubscriptionStmt); + + COPY_STRING_FIELD(subname); + COPY_NODE_FIELD(options); + + return newnode; +} + +static DropSubscriptionStmt * +_copyDropSubscriptionStmt(const DropSubscriptionStmt *from) +{ + DropSubscriptionStmt *newnode = makeNode(DropSubscriptionStmt); + + COPY_STRING_FIELD(subname); + COPY_SCALAR_FIELD(drop_slot); + COPY_SCALAR_FIELD(missing_ok); + + return newnode; +} + /* **************************************************************** * pg_list.h copy functions * **************************************************************** @@ -4299,6 +4494,9 @@ copyObject(const void *from) case T_Result: retval = _copyResult(from); break; + case T_ProjectSet: + retval = _copyProjectSet(from); + break; case T_ModifyTable: retval = _copyModifyTable(from); break; @@ -4525,6 +4723,9 @@ copyObject(const void *from) case T_MinMaxExpr: retval = _copyMinMaxExpr(from); break; + case T_SQLValueFunction: + retval = _copySQLValueFunction(from); + break; case T_XmlExpr: retval = _copyXmlExpr(from); break; @@ -4627,6 +4828,9 @@ copyObject(const void *from) case T_Query: retval = _copyQuery(from); break; + case T_RawStmt: + retval = _copyRawStmt(from); + break; case T_InsertStmt: retval = _copyInsertStmt(from); break; @@ -4945,6 +5149,21 @@ copyObject(const void *from) case T_AlterPolicyStmt: retval = _copyAlterPolicyStmt(from); break; + case T_CreatePublicationStmt: + retval = _copyCreatePublicationStmt(from); + break; + case T_AlterPublicationStmt: + retval = _copyAlterPublicationStmt(from); + break; + case T_CreateSubscriptionStmt: + retval = _copyCreateSubscriptionStmt(from); + break; + case T_AlterSubscriptionStmt: + retval = _copyAlterSubscriptionStmt(from); + break; + case T_DropSubscriptionStmt: + retval = _copyDropSubscriptionStmt(from); + break; case T_A_Expr: retval = _copyAExpr(from); break; @@ -5065,6 +5284,24 @@ copyObject(const void *from) case T_RoleSpec: retval = _copyRoleSpec(from); break; + case T_TriggerTransition: + retval = _copyTriggerTransition(from); + break; + case T_PartitionSpec: + retval = _copyPartitionSpec(from); + break; + case T_PartitionElem: + retval = _copyPartitionElem(from); + break; + case T_PartitionBoundSpec: + retval = _copyPartitionBoundSpec(from); + break; + case T_PartitionRangeDatum: + retval = _copyPartitionRangeDatum(from); + break; + case T_PartitionCmd: + retval = _copyPartitionCmd(from); + break; /* * MISCELLANEOUS NODES diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 1eb679926a..55c73b7292 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -18,7 +18,7 @@ * "x" to be considered equal() to another reference to "x" in the query. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -108,7 +108,7 @@ _equalRangeVar(const RangeVar *a, const RangeVar *b) COMPARE_STRING_FIELD(catalogname); COMPARE_STRING_FIELD(schemaname); COMPARE_STRING_FIELD(relname); - COMPARE_SCALAR_FIELD(inhOpt); + COMPARE_SCALAR_FIELD(inh); COMPARE_SCALAR_FIELD(relpersistence); COMPARE_NODE_FIELD(alias); COMPARE_LOCATION_FIELD(location); @@ -619,6 +619,17 @@ _equalMinMaxExpr(const MinMaxExpr *a, const MinMaxExpr *b) return true; } +static bool +_equalSQLValueFunction(const SQLValueFunction *a, const SQLValueFunction *b) +{ + COMPARE_SCALAR_FIELD(op); + COMPARE_SCALAR_FIELD(type); + COMPARE_SCALAR_FIELD(typmod); + COMPARE_LOCATION_FIELD(location); + + return true; +} + static bool _equalXmlExpr(const XmlExpr *a, const XmlExpr *b) { @@ -794,6 +805,7 @@ _equalRestrictInfo(const RestrictInfo *a, const RestrictInfo *b) COMPARE_NODE_FIELD(clause); COMPARE_SCALAR_FIELD(is_pushed_down); COMPARE_SCALAR_FIELD(outerjoin_delayed); + COMPARE_SCALAR_FIELD(security_level); COMPARE_BITMAPSET_FIELD(required_relids); COMPARE_BITMAPSET_FIELD(outer_relids); COMPARE_BITMAPSET_FIELD(nullable_relids); @@ -910,6 +922,7 @@ _equalQuery(const Query *a, const Query *b) COMPARE_SCALAR_FIELD(resultRelation); COMPARE_SCALAR_FIELD(hasAggs); COMPARE_SCALAR_FIELD(hasWindowFuncs); + COMPARE_SCALAR_FIELD(hasTargetSRFs); COMPARE_SCALAR_FIELD(hasSubLinks); COMPARE_SCALAR_FIELD(hasDistinctOn); COMPARE_SCALAR_FIELD(hasRecursive); @@ -934,6 +947,18 @@ _equalQuery(const Query *a, const Query *b) COMPARE_NODE_FIELD(setOperations); COMPARE_NODE_FIELD(constraintDeps); COMPARE_NODE_FIELD(withCheckOptions); + COMPARE_LOCATION_FIELD(stmt_location); + COMPARE_LOCATION_FIELD(stmt_len); + + return true; +} + +static bool +_equalRawStmt(const RawStmt *a, const RawStmt *b) +{ + COMPARE_NODE_FIELD(stmt); + COMPARE_LOCATION_FIELD(stmt_location); + COMPARE_LOCATION_FIELD(stmt_len); return true; } @@ -1156,6 +1181,8 @@ _equalCreateStmt(const CreateStmt *a, const CreateStmt *b) COMPARE_NODE_FIELD(relation); COMPARE_NODE_FIELD(tableElts); COMPARE_NODE_FIELD(inhRelations); + COMPARE_NODE_FIELD(partspec); + COMPARE_NODE_FIELD(partbound); COMPARE_NODE_FIELD(ofTypename); COMPARE_NODE_FIELD(constraints); COMPARE_NODE_FIELD(options); @@ -1454,10 +1481,11 @@ static bool _equalAlterEnumStmt(const AlterEnumStmt *a, const AlterEnumStmt *b) { COMPARE_NODE_FIELD(typeName); + COMPARE_STRING_FIELD(oldVal); COMPARE_STRING_FIELD(newVal); COMPARE_STRING_FIELD(newValNeighbor); COMPARE_SCALAR_FIELD(newValIsAfter); - COMPARE_SCALAR_FIELD(skipIfExists); + COMPARE_SCALAR_FIELD(skipIfNewValExists); return true; } @@ -1892,6 +1920,7 @@ _equalCreateTrigStmt(const CreateTrigStmt *a, const CreateTrigStmt *b) COMPARE_NODE_FIELD(columns); COMPARE_NODE_FIELD(whenClause); COMPARE_SCALAR_FIELD(isconstraint); + COMPARE_NODE_FIELD(transitionRels); COMPARE_SCALAR_FIELD(deferrable); COMPARE_SCALAR_FIELD(initdeferred); COMPARE_NODE_FIELD(constrrel); @@ -2105,12 +2134,71 @@ _equalAlterTSConfigurationStmt(const AlterTSConfigurationStmt *a, return true; } +static bool +_equalCreatePublicationStmt(const CreatePublicationStmt *a, + const CreatePublicationStmt *b) +{ + COMPARE_STRING_FIELD(pubname); + COMPARE_NODE_FIELD(options); + COMPARE_NODE_FIELD(tables); + COMPARE_SCALAR_FIELD(for_all_tables); + + return true; +} + +static bool +_equalAlterPublicationStmt(const AlterPublicationStmt *a, + const AlterPublicationStmt *b) +{ + COMPARE_STRING_FIELD(pubname); + COMPARE_NODE_FIELD(options); + COMPARE_NODE_FIELD(tables); + COMPARE_SCALAR_FIELD(for_all_tables); + COMPARE_SCALAR_FIELD(tableAction); + + return true; +} + +static bool +_equalCreateSubscriptionStmt(const CreateSubscriptionStmt *a, + const CreateSubscriptionStmt *b) +{ + COMPARE_STRING_FIELD(subname); + COMPARE_STRING_FIELD(conninfo); + COMPARE_NODE_FIELD(publication); + COMPARE_NODE_FIELD(options); + + return true; +} + +static bool +_equalAlterSubscriptionStmt(const AlterSubscriptionStmt *a, + const AlterSubscriptionStmt *b) +{ + COMPARE_STRING_FIELD(subname); + COMPARE_NODE_FIELD(options); + + return true; +} + +static bool +_equalDropSubscriptionStmt(const DropSubscriptionStmt *a, + const DropSubscriptionStmt *b) +{ + COMPARE_STRING_FIELD(subname); + COMPARE_SCALAR_FIELD(drop_slot); + COMPARE_SCALAR_FIELD(missing_ok); + + return true; +} + static bool _equalCreatePolicyStmt(const CreatePolicyStmt *a, const CreatePolicyStmt *b) { COMPARE_STRING_FIELD(policy_name); COMPARE_NODE_FIELD(table); COMPARE_STRING_FIELD(cmd_name); + COMPARE_SCALAR_FIELD(permissive); COMPARE_NODE_FIELD(roles); COMPARE_NODE_FIELD(qual); COMPARE_NODE_FIELD(with_check); @@ -2413,6 +2501,7 @@ _equalDefElem(const DefElem *a, const DefElem *b) COMPARE_STRING_FIELD(defname); COMPARE_NODE_FIELD(arg); COMPARE_SCALAR_FIELD(defaction); + COMPARE_LOCATION_FIELD(location); return true; } @@ -2423,6 +2512,7 @@ _equalLockingClause(const LockingClause *a, const LockingClause *b) COMPARE_NODE_FIELD(lockedRels); COMPARE_SCALAR_FIELD(strength); COMPARE_SCALAR_FIELD(waitPolicy); + COMPARE_LOCATION_FIELD(location); return true; } @@ -2441,13 +2531,12 @@ _equalRangeTblEntry(const RangeTblEntry *a, const RangeTblEntry *b) COMPARE_NODE_FIELD(functions); COMPARE_SCALAR_FIELD(funcordinality); COMPARE_NODE_FIELD(values_lists); - COMPARE_NODE_FIELD(values_collations); COMPARE_STRING_FIELD(ctename); COMPARE_SCALAR_FIELD(ctelevelsup); COMPARE_SCALAR_FIELD(self_reference); - COMPARE_NODE_FIELD(ctecoltypes); - COMPARE_NODE_FIELD(ctecoltypmods); - COMPARE_NODE_FIELD(ctecolcollations); + COMPARE_NODE_FIELD(coltypes); + COMPARE_NODE_FIELD(coltypmods); + COMPARE_NODE_FIELD(colcollations); COMPARE_NODE_FIELD(alias); COMPARE_NODE_FIELD(eref); COMPARE_SCALAR_FIELD(lateral); @@ -2619,6 +2708,69 @@ _equalRoleSpec(const RoleSpec *a, const RoleSpec *b) return true; } +static bool +_equalTriggerTransition(const TriggerTransition *a, const TriggerTransition *b) +{ + COMPARE_STRING_FIELD(name); + COMPARE_SCALAR_FIELD(isNew); + COMPARE_SCALAR_FIELD(isTable); + + return true; +} + +static bool +_equalPartitionSpec(const PartitionSpec *a, const PartitionSpec *b) +{ + COMPARE_STRING_FIELD(strategy); + COMPARE_NODE_FIELD(partParams); + COMPARE_LOCATION_FIELD(location); + + return true; +} + +static bool +_equalPartitionElem(const PartitionElem *a, const PartitionElem *b) +{ + COMPARE_STRING_FIELD(name); + COMPARE_NODE_FIELD(expr); + COMPARE_NODE_FIELD(collation); + COMPARE_NODE_FIELD(opclass); + COMPARE_LOCATION_FIELD(location); + + return true; +} + +static bool +_equalPartitionBoundSpec(const PartitionBoundSpec *a, const PartitionBoundSpec *b) +{ + COMPARE_SCALAR_FIELD(strategy); + COMPARE_NODE_FIELD(listdatums); + COMPARE_NODE_FIELD(lowerdatums); + COMPARE_NODE_FIELD(upperdatums); + COMPARE_LOCATION_FIELD(location); + + return true; +} + +static bool +_equalPartitionRangeDatum(const PartitionRangeDatum *a, const PartitionRangeDatum *b) +{ + COMPARE_SCALAR_FIELD(infinite); + COMPARE_NODE_FIELD(value); + COMPARE_LOCATION_FIELD(location); + + return true; +} + +static bool +_equalPartitionCmd(const PartitionCmd *a, const PartitionCmd *b) +{ + COMPARE_NODE_FIELD(name); + COMPARE_NODE_FIELD(bound); + + return true; +} + /* * Stuff from pg_list.h */ @@ -2842,6 +2994,9 @@ equal(const void *a, const void *b) case T_MinMaxExpr: retval = _equalMinMaxExpr(a, b); break; + case T_SQLValueFunction: + retval = _equalSQLValueFunction(a, b); + break; case T_XmlExpr: retval = _equalXmlExpr(a, b); break; @@ -2931,6 +3086,9 @@ equal(const void *a, const void *b) case T_Query: retval = _equalQuery(a, b); break; + case T_RawStmt: + retval = _equalRawStmt(a, b); + break; case T_InsertStmt: retval = _equalInsertStmt(a, b); break; @@ -3249,6 +3407,21 @@ equal(const void *a, const void *b) case T_AlterPolicyStmt: retval = _equalAlterPolicyStmt(a, b); break; + case T_CreatePublicationStmt: + retval = _equalCreatePublicationStmt(a, b); + break; + case T_AlterPublicationStmt: + retval = _equalAlterPublicationStmt(a, b); + break; + case T_CreateSubscriptionStmt: + retval = _equalCreateSubscriptionStmt(a, b); + break; + case T_AlterSubscriptionStmt: + retval = _equalAlterSubscriptionStmt(a, b); + break; + case T_DropSubscriptionStmt: + retval = _equalDropSubscriptionStmt(a, b); + break; case T_A_Expr: retval = _equalAExpr(a, b); break; @@ -3369,6 +3542,24 @@ equal(const void *a, const void *b) case T_RoleSpec: retval = _equalRoleSpec(a, b); break; + case T_TriggerTransition: + retval = _equalTriggerTransition(a, b); + break; + case T_PartitionSpec: + retval = _equalPartitionSpec(a, b); + break; + case T_PartitionElem: + retval = _equalPartitionElem(a, b); + break; + case T_PartitionBoundSpec: + retval = _equalPartitionBoundSpec(a, b); + break; + case T_PartitionRangeDatum: + retval = _equalPartitionRangeDatum(a, b); + break; + case T_PartitionCmd: + retval = _equalPartitionCmd(a, b); + break; default: elog(ERROR, "unrecognized node type: %d", diff --git a/src/backend/nodes/extensible.c b/src/backend/nodes/extensible.c index a4f1c99016..01cd3c84fb 100644 --- a/src/backend/nodes/extensible.c +++ b/src/backend/nodes/extensible.c @@ -10,7 +10,7 @@ * and GetExtensibleNodeMethods to get information about a previously * registered type of extensible node. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/nodes/list.c b/src/backend/nodes/list.c index 085b68cd1f..f09aa248d8 100644 --- a/src/backend/nodes/list.c +++ b/src/backend/nodes/list.c @@ -4,7 +4,7 @@ * implementation for PostgreSQL generic linked list package * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c index d72a85ee1b..7586cce56a 100644 --- a/src/backend/nodes/makefuncs.c +++ b/src/backend/nodes/makefuncs.c @@ -4,7 +4,7 @@ * creator functions for primitive nodes. The functions here are for * the most frequently created nodes. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -423,7 +423,7 @@ makeRangeVar(char *schemaname, char *relname, int location) r->catalogname = NULL; r->schemaname = schemaname; r->relname = relname; - r->inhOpt = INH_DEFAULT; + r->inh = true; r->relpersistence = RELPERSISTENCE_PERMANENT; r->alias = NULL; r->location = location; @@ -540,7 +540,7 @@ makeFuncExpr(Oid funcid, Oid rettype, List *args, * and no special action. */ DefElem * -makeDefElem(char *name, Node *arg) +makeDefElem(char *name, Node *arg, int location) { DefElem *res = makeNode(DefElem); @@ -548,6 +548,7 @@ makeDefElem(char *name, Node *arg) res->defname = name; res->arg = arg; res->defaction = DEFELEM_UNSPEC; + res->location = location; return res; } @@ -558,7 +559,7 @@ makeDefElem(char *name, Node *arg) */ DefElem * makeDefElemExtended(char *nameSpace, char *name, Node *arg, - DefElemAction defaction) + DefElemAction defaction, int location) { DefElem *res = makeNode(DefElem); @@ -566,6 +567,7 @@ makeDefElemExtended(char *nameSpace, char *name, Node *arg, res->defname = name; res->arg = arg; res->defaction = defaction; + res->location = location; return res; } diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index cd39167351..c2f03b73f4 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -3,7 +3,7 @@ * nodeFuncs.c * Various general-purpose manipulations of Node trees * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -218,6 +218,9 @@ exprType(const Node *expr) case T_MinMaxExpr: type = ((const MinMaxExpr *) expr)->minmaxtype; break; + case T_SQLValueFunction: + type = ((const SQLValueFunction *) expr)->type; + break; case T_XmlExpr: if (((const XmlExpr *) expr)->op == IS_DOCUMENT) type = BOOLOID; @@ -479,6 +482,8 @@ exprTypmod(const Node *expr) return typmod; } break; + case T_SQLValueFunction: + return ((const SQLValueFunction *) expr)->typmod; case T_CoerceToDomain: return ((const CoerceToDomain *) expr)->resulttypmod; case T_CoerceToDomainValue: @@ -718,6 +723,8 @@ expression_returns_set_walker(Node *node, void *context) return false; if (IsA(node, MinMaxExpr)) return false; + if (IsA(node, SQLValueFunction)) + return false; if (IsA(node, XmlExpr)) return false; @@ -883,6 +890,9 @@ exprCollation(const Node *expr) case T_MinMaxExpr: coll = ((const MinMaxExpr *) expr)->minmaxcollid; break; + case T_SQLValueFunction: + coll = InvalidOid; /* all cases return non-collatable types */ + break; case T_XmlExpr: /* @@ -1091,6 +1101,9 @@ exprSetCollation(Node *expr, Oid collation) case T_MinMaxExpr: ((MinMaxExpr *) expr)->minmaxcollid = collation; break; + case T_SQLValueFunction: + Assert(!OidIsValid(collation)); /* no collatable results */ + break; case T_XmlExpr: Assert((((XmlExpr *) expr)->op == IS_XMLSERIALIZE) ? (collation == DEFAULT_COLLATION_OID) : @@ -1364,6 +1377,10 @@ exprLocation(const Node *expr) /* GREATEST/LEAST keyword should always be the first thing */ loc = ((const MinMaxExpr *) expr)->location; break; + case T_SQLValueFunction: + /* function keyword should always be the first thing */ + loc = ((const SQLValueFunction *) expr)->location; + break; case T_XmlExpr: { const XmlExpr *xexpr = (const XmlExpr *) expr; @@ -1535,6 +1552,12 @@ exprLocation(const Node *expr) /* just use nested expr's location */ loc = exprLocation((Node *) ((const InferenceElem *) expr)->expr); break; + case T_PartitionBoundSpec: + loc = ((const PartitionBoundSpec *) expr)->location; + break; + case T_PartitionRangeDatum: + loc = ((const PartitionRangeDatum *) expr)->location; + break; default: /* for any other node type it's just unknown... */ loc = -1; @@ -1633,9 +1656,10 @@ set_sa_opfuncid(ScalarArrayOpExpr *opexpr) * for themselves, in case additional checks should be made, or because they * have special rules about which parts of the tree need to be visited. * - * Note: we ignore MinMaxExpr, XmlExpr, and CoerceToDomain nodes, because they - * do not contain SQL function OIDs. However, they can invoke SQL-visible - * functions, so callers should take thought about how to treat them. + * Note: we ignore MinMaxExpr, SQLValueFunction, XmlExpr, and CoerceToDomain + * nodes, because they do not contain SQL function OIDs. However, they can + * invoke SQL-visible functions, so callers should take thought about how to + * treat them. */ bool check_functions_in_node(Node *node, check_function_callback checker, @@ -1859,6 +1883,7 @@ expression_tree_walker(Node *node, case T_CaseTestExpr: case T_SetToDefault: case T_CurrentOfExpr: + case T_SQLValueFunction: case T_RangeTblRef: case T_SortGroupClause: /* primitive node types with no expression subnodes */ @@ -2433,6 +2458,7 @@ expression_tree_mutator(Node *node, case T_CaseTestExpr: case T_SetToDefault: case T_CurrentOfExpr: + case T_SQLValueFunction: case T_RangeTblRef: case T_SortGroupClause: return (Node *) copyObject(node); @@ -3197,6 +3223,7 @@ raw_expression_tree_walker(Node *node, { case T_SetToDefault: case T_CurrentOfExpr: + case T_SQLValueFunction: case T_Integer: case T_Float: case T_String: diff --git a/src/backend/nodes/nodes.c b/src/backend/nodes/nodes.c index aea3880858..d3345aae6d 100644 --- a/src/backend/nodes/nodes.c +++ b/src/backend/nodes/nodes.c @@ -4,7 +4,7 @@ * support code for nodes (now that we have removed the home-brew * inheritance system, our support code for nodes is much simpler) * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index acaf4ea5eb..dcdfa38671 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -3,7 +3,7 @@ * outfuncs.c * Output functions for Postgres tree nodes. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -25,13 +25,185 @@ #include +#include "catalog/pg_type.h" +#include "commands/dbcommands.h" +#include "commands/defrem.h" +#include "commands/user.h" #include "lib/stringinfo.h" +#include "miscadmin.h" #include "nodes/extensible.h" #include "nodes/plannodes.h" #include "nodes/relation.h" #include "utils/datum.h" +#include "utils/lsyscache.h" #include "utils/rel.h" +#include "utils/syscache.h" +#define NSP_NAME(nspoid) (get_namespace_name(nspoid)) +#define OID_TYPES_NUM (12) + +static const Oid oid_types[OID_TYPES_NUM] = {RELOID, TYPEOID, PROCOID, COLLOID, +OPEROID, AUTHOID, LANGOID, AMOID, NAMESPACEOID, DATABASEOID, RULEOID, OPFAMILYOID}; +static void _printDatum(StringInfo str, Datum value, Oid typid); +static bool portable_output = false; +void +set_portable_output(bool value) +{ + portable_output = value; +} + +static void +write_oid_field(StringInfo str, Oid oid) +{ + int i; + char *rulename; + Oid ev_class = InvalidOid; + + if (!portable_output) + { + appendStringInfo(str, " %u", oid); + return; + } + + appendStringInfo(str, " ("); + + if (!OidIsValid(oid)) + { + /* Special case for invalid oid fields. For example, checkAsUser. */ + appendStringInfo(str, "0 %u)", oid); + return; + } + + for (i = 0; i < OID_TYPES_NUM; i++) + if (oid_types[i] != RULEOID) + { + if (SearchSysCacheExists1(oid_types[i], oid)) + break; + } + else if ((rulename = get_rule_name(oid, &ev_class)) != NULL) + break; + + if (i == OID_TYPES_NUM) + { + elog(LOG, "Unexpected oid type %d!", oid); + appendStringInfo(str, "0 %u)", oid); + return; + } + + switch (oid_types[i]) + { + case RELOID: + appendStringInfo(str, "%u %s %s", RELOID, + get_namespace_name((get_rel_namespace((oid)))), + get_rel_name((oid))); + break; + + case TYPEOID: + appendStringInfo(str, "%u %s %s", TYPEOID, + get_namespace_name(get_typ_namespace(oid)), + get_typ_name(oid)); + + break; + + case PROCOID: + { + Oid *argtypes; + int i, + nargs; + + get_func_signature(oid, &argtypes, &nargs); + appendStringInfo(str, "%u %s %s %d", PROCOID, + NSP_NAME(get_func_namespace(oid)), + get_func_name(oid), + nargs); + + for (i = 0; i < nargs; i++) + { + appendStringInfoChar(str, ' '); + outToken(str, NSP_NAME(get_typ_namespace(argtypes[i]))); + appendStringInfoChar(str, ' '); + outToken(str, get_typ_name(argtypes[i])); + } + } + break; + case COLLOID: + appendStringInfo(str, "%u ", COLLOID); + outToken(str, NSP_NAME(get_collation_namespace(oid))); + appendStringInfoChar(str, ' '); + outToken(str, get_collation_name(oid)); + appendStringInfo(str, " %d", get_collation_encoding(oid)); + break; + + case OPEROID: + { + Oid oprleft, + oprright; + + appendStringInfo(str, "%u ", OPEROID); + outToken(str, NSP_NAME(get_opnamespace(oid))); + appendStringInfoChar(str, ' '); + outToken(str, get_opname(oid)); + appendStringInfoChar(str, ' '); + op_input_types(oid, &oprleft, &oprright); + outToken(str, OidIsValid(oprleft) ? + NSP_NAME(get_typ_namespace(oprleft)) : NULL); + appendStringInfoChar(str, ' '); + outToken(str, OidIsValid(oprleft) ? get_typ_name(oprleft) : NULL); + appendStringInfoChar(str, ' '); + outToken(str, OidIsValid(oprright) ? + NSP_NAME(get_typ_namespace(oprright)) : NULL); + appendStringInfoChar(str, ' '); + outToken(str, OidIsValid(oprright) ? get_typ_name(oprright) : NULL); + } + break; + + case AUTHOID: + appendStringInfo(str, "%u %s", AUTHOID, get_rolename(oid)); + break; + + case LANGOID: + appendStringInfo(str, "%u %s", LANGOID, get_language_name(oid, false)); + break; + + case AMOID: + appendStringInfo(str, "%u %s", AMOID, get_am_name(oid)); + break; + + case NAMESPACEOID: + appendStringInfo(str, "%u %s", NAMESPACEOID, get_namespace_name_or_temp(oid)); + break; + + case DATABASEOID: + appendStringInfo(str, "%u %s", DATABASEOID, get_database_name(oid)); + break; + + case RULEOID: + Assert(rulename != NULL); + appendStringInfo(str, "%u %s %s %s", RULEOID, rulename, + NSP_NAME(get_rel_namespace(ev_class)), + get_rel_name(ev_class)); + break; + + case OPFAMILYOID: + { + char *opfname = NULL, + *nspname = NULL, + *amname = NULL; + + opfname = get_opfamily_name(oid, &nspname, &amname); + Assert(opfname && nspname && amname); + + appendStringInfo(str, "%u %s %s %s", OPFAMILYOID, opfname, + nspname, amname); + } + break; + + default: + Assert(0); + break; + } + appendStringInfo(str, ")"); +} /* * Macros to simplify output of different kinds of fields. Use these @@ -54,7 +226,10 @@ /* Write an OID field (don't hard-wire assumption that OID is same as uint) */ #define WRITE_OID_FIELD(fldname) \ - appendStringInfo(str, " :" CppAsString(fldname) " %u", node->fldname) +do { \ + appendStringInfo(str, " :%s", CppAsString(fldname)); \ + write_oid_field(str, node->fldname); \ +} while (0) /* Write a long-integer field */ #define WRITE_LONG_FIELD(fldname) \ @@ -81,7 +256,7 @@ /* Write a character-string (possibly NULL) field */ #define WRITE_STRING_FIELD(fldname) \ (appendStringInfo(str, " :" CppAsString(fldname) " "), \ - _outToken(str, node->fldname)) + outToken(str, node->fldname)) /* Write a parse location field (actually same as INT case) */ #define WRITE_LOCATION_FIELD(fldname) \ @@ -95,21 +270,21 @@ /* Write a bitmapset field */ #define WRITE_BITMAPSET_FIELD(fldname) \ (appendStringInfo(str, " :" CppAsString(fldname) " "), \ - _outBitmapset(str, node->fldname)) + outBitmapset(str, node->fldname)) #define booltostr(x) ((x) ? "true" : "false") /* - * _outToken + * outToken * Convert an ordinary string (eg, an identifier) into a form that * will be decoded back to a plain token by read.c's functions. * * If a null or empty string is given, it is encoded as "<>". */ -static void -_outToken(StringInfo str, const char *s) +void +outToken(StringInfo str, const char *s) { if (s == NULL || *s == '\0') { @@ -140,13 +315,6 @@ _outToken(StringInfo str, const char *s) } } -/* for use by extensions which define extensible nodes */ -void -outToken(StringInfo str, const char *s) -{ - _outToken(str, s); -} - static void _outList(StringInfo str, const List *node) { @@ -185,13 +353,13 @@ _outList(StringInfo str, const List *node) } /* - * _outBitmapset - + * outBitmapset - * converts a bitmap set of integers * * Note: the output format is "(b int int ...)", similar to an integer List. */ -static void -_outBitmapset(StringInfo str, const Bitmapset *bms) +void +outBitmapset(StringInfo str, const Bitmapset *bms) { int x; @@ -203,13 +371,6 @@ _outBitmapset(StringInfo str, const Bitmapset *bms) appendStringInfoChar(str, ')'); } -/* for use by extensions which define extensible nodes */ -void -outBitmapset(StringInfo str, const Bitmapset *bms) -{ - _outBitmapset(str, bms); -} - /* * Print the value of a Datum given its type. */ @@ -266,13 +427,15 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node) WRITE_NODE_FIELD(planTree); WRITE_NODE_FIELD(rtable); WRITE_NODE_FIELD(resultRelations); - WRITE_NODE_FIELD(utilityStmt); WRITE_NODE_FIELD(subplans); WRITE_BITMAPSET_FIELD(rewindPlanIDs); WRITE_NODE_FIELD(rowMarks); WRITE_NODE_FIELD(relationOids); WRITE_NODE_FIELD(invalItems); WRITE_INT_FIELD(nParamExec); + WRITE_NODE_FIELD(utilityStmt); + WRITE_LOCATION_FIELD(stmt_location); + WRITE_LOCATION_FIELD(stmt_len); } /* @@ -338,6 +501,14 @@ _outResult(StringInfo str, const Result *node) WRITE_NODE_FIELD(resconstantqual); } +static void +_outProjectSet(StringInfo str, const ProjectSet *node) +{ + WRITE_NODE_TYPE("PROJECTSET"); + + _outPlanInfo(str, (const Plan *) node); +} + static void _outModifyTable(StringInfo str, const ModifyTable *node) { @@ -632,7 +803,7 @@ _outCustomScan(StringInfo str, const CustomScan *node) WRITE_BITMAPSET_FIELD(custom_relids); /* CustomName is a key to lookup CustomScanMethods */ appendStringInfoString(str, " :methods "); - _outToken(str, node->methods->CustomName); + outToken(str, node->methods->CustomName); } static void @@ -716,6 +887,7 @@ _outAgg(StringInfo str, const Agg *node) appendStringInfo(str, " %u", node->grpOperators[i]); WRITE_LONG_FIELD(numGroups); + WRITE_BITMAPSET_FIELD(aggParams); WRITE_NODE_FIELD(groupingSets); WRITE_NODE_FIELD(chain); } @@ -952,7 +1124,7 @@ _outRangeVar(StringInfo str, const RangeVar *node) */ WRITE_STRING_FIELD(schemaname); WRITE_STRING_FIELD(relname); - WRITE_ENUM_FIELD(inhOpt, InhOption); + WRITE_BOOL_FIELD(inh); WRITE_CHAR_FIELD(relpersistence); WRITE_NODE_FIELD(alias); WRITE_LOCATION_FIELD(location); @@ -1004,6 +1176,8 @@ _outConst(StringInfo str, const Const *node) appendStringInfoString(str, " :constvalue "); if (node->constisnull) appendStringInfoString(str, "<>"); + else if (portable_output) + _printDatum(str, node->constvalue, node->consttype); else outDatum(str, node->constvalue, node->constlen, node->constbyval); } @@ -1195,7 +1369,7 @@ _outBoolExpr(StringInfo str, const BoolExpr *node) break; } appendStringInfoString(str, " :boolop "); - _outToken(str, opstr); + outToken(str, opstr); WRITE_NODE_FIELD(args); WRITE_LOCATION_FIELD(location); @@ -1423,6 +1597,17 @@ _outMinMaxExpr(StringInfo str, const MinMaxExpr *node) WRITE_LOCATION_FIELD(location); } +static void +_outSQLValueFunction(StringInfo str, const SQLValueFunction *node) +{ + WRITE_NODE_TYPE("SQLVALUEFUNCTION"); + + WRITE_ENUM_FIELD(op, SQLValueFunctionOp); + WRITE_OID_FIELD(type); + WRITE_INT_FIELD(typmod); + WRITE_LOCATION_FIELD(location); +} + static void _outXmlExpr(StringInfo str, const XmlExpr *node) { @@ -1597,14 +1782,14 @@ _outPathInfo(StringInfo str, const Path *node) { WRITE_ENUM_FIELD(pathtype, NodeTag); appendStringInfoString(str, " :parent_relids "); - _outBitmapset(str, node->parent->relids); + outBitmapset(str, node->parent->relids); if (node->pathtarget != node->parent->reltarget) WRITE_NODE_FIELD(pathtarget); appendStringInfoString(str, " :required_outer "); if (node->param_info) - _outBitmapset(str, node->param_info->ppi_req_outer); + outBitmapset(str, node->param_info->ppi_req_outer); else - _outBitmapset(str, NULL); + outBitmapset(str, NULL); WRITE_BOOL_FIELD(parallel_aware); WRITE_BOOL_FIELD(parallel_safe); WRITE_INT_FIELD(parallel_workers); @@ -1728,7 +1913,7 @@ _outCustomPath(StringInfo str, const CustomPath *node) WRITE_NODE_FIELD(custom_paths); WRITE_NODE_FIELD(custom_private); appendStringInfoString(str, " :methods "); - _outToken(str, node->methods->CustomName); + outToken(str, node->methods->CustomName); } static void @@ -1753,7 +1938,7 @@ _outMergeAppendPath(StringInfo str, const MergeAppendPath *node) } static void -_outResultPath(StringInfo str, const ResultPath *node) +_outResultPath(StringInfo str, const ResultPath * node) { WRITE_NODE_TYPE("RESULTPATH"); @@ -1807,6 +1992,16 @@ _outProjectionPath(StringInfo str, const ProjectionPath *node) WRITE_BOOL_FIELD(dummypp); } +static void +_outProjectSetPath(StringInfo str, const ProjectSetPath *node) +{ + WRITE_NODE_TYPE("PROJECTSETPATH"); + + _outPathInfo(str, (const Path *) node); + + WRITE_NODE_FIELD(subpath); +} + static void _outSortPath(StringInfo str, const SortPath *node) { @@ -2018,6 +2213,7 @@ _outPlannerGlobal(StringInfo str, const PlannerGlobal *node) WRITE_BOOL_FIELD(dependsOnRole); WRITE_BOOL_FIELD(parallelModeOK); WRITE_BOOL_FIELD(parallelModeNeeded); + WRITE_CHAR_FIELD(maxParallelHazard); } static void @@ -2058,6 +2254,7 @@ _outPlannerInfo(StringInfo str, const PlannerInfo *node) WRITE_FLOAT_FIELD(total_table_pages, "%.0f"); WRITE_FLOAT_FIELD(tuple_fraction, "%.4f"); WRITE_FLOAT_FIELD(limit_tuples, "%.0f"); + WRITE_UINT_FIELD(qual_security_level); WRITE_BOOL_FIELD(hasInheritedTarget); WRITE_BOOL_FIELD(hasJoinRTEs); WRITE_BOOL_FIELD(hasLateralRTEs); @@ -2111,6 +2308,7 @@ _outRelOptInfo(StringInfo str, const RelOptInfo *node) WRITE_BOOL_FIELD(useridiscurrent); /* we don't try to print fdwroutine or fdw_private */ WRITE_NODE_FIELD(baserestrictinfo); + WRITE_UINT_FIELD(baserestrict_min_security); WRITE_NODE_FIELD(joininfo); WRITE_BOOL_FIELD(has_eclass_joins); } @@ -2194,6 +2392,8 @@ _outEquivalenceClass(StringInfo str, const EquivalenceClass *node) WRITE_BOOL_FIELD(ec_below_outer_join); WRITE_BOOL_FIELD(ec_broken); WRITE_UINT_FIELD(ec_sortref); + WRITE_UINT_FIELD(ec_min_security); + WRITE_UINT_FIELD(ec_max_security); } static void @@ -2260,6 +2460,8 @@ _outRestrictInfo(StringInfo str, const RestrictInfo *node) WRITE_BOOL_FIELD(outerjoin_delayed); WRITE_BOOL_FIELD(can_join); WRITE_BOOL_FIELD(pseudoconstant); + WRITE_BOOL_FIELD(leakproof); + WRITE_UINT_FIELD(security_level); WRITE_BITMAPSET_FIELD(clause_relids); WRITE_BITMAPSET_FIELD(required_relids); WRITE_BITMAPSET_FIELD(outer_relids); @@ -2393,6 +2595,8 @@ _outCreateStmtInfo(StringInfo str, const CreateStmt *node) WRITE_NODE_FIELD(relation); WRITE_NODE_FIELD(tableElts); WRITE_NODE_FIELD(inhRelations); + WRITE_NODE_FIELD(partspec); + WRITE_NODE_FIELD(partbound); WRITE_NODE_FIELD(ofTypename); WRITE_NODE_FIELD(constraints); WRITE_NODE_FIELD(options); @@ -2529,6 +2733,7 @@ _outDefElem(StringInfo str, const DefElem *node) WRITE_STRING_FIELD(defname); WRITE_NODE_FIELD(arg); WRITE_ENUM_FIELD(defaction, DefElemAction); + WRITE_LOCATION_FIELD(location); } static void @@ -2561,6 +2766,16 @@ _outXmlSerialize(StringInfo str, const XmlSerialize *node) WRITE_LOCATION_FIELD(location); } +static void +_outTriggerTransition(StringInfo str, const TriggerTransition *node) +{ + WRITE_NODE_TYPE("TRIGGERTRANSITION"); + + WRITE_STRING_FIELD(name); + WRITE_BOOL_FIELD(isNew); + WRITE_BOOL_FIELD(isTable); +} + static void _outColumnDef(StringInfo str, const ColumnDef *node) { @@ -2669,6 +2884,7 @@ _outQuery(StringInfo str, const Query *node) WRITE_INT_FIELD(resultRelation); WRITE_BOOL_FIELD(hasAggs); WRITE_BOOL_FIELD(hasWindowFuncs); + WRITE_BOOL_FIELD(hasTargetSRFs); WRITE_BOOL_FIELD(hasSubLinks); WRITE_BOOL_FIELD(hasDistinctOn); WRITE_BOOL_FIELD(hasRecursive); @@ -2692,6 +2908,9 @@ _outQuery(StringInfo str, const Query *node) WRITE_NODE_FIELD(rowMarks); WRITE_NODE_FIELD(setOperations); WRITE_NODE_FIELD(constraintDeps); + /* withCheckOptions intentionally omitted, see comment in parsenodes.h */ + WRITE_LOCATION_FIELD(stmt_location); + WRITE_LOCATION_FIELD(stmt_len); } static void @@ -2828,15 +3047,17 @@ _outRangeTblEntry(StringInfo str, const RangeTblEntry *node) break; case RTE_VALUES: WRITE_NODE_FIELD(values_lists); - WRITE_NODE_FIELD(values_collations); + WRITE_NODE_FIELD(coltypes); + WRITE_NODE_FIELD(coltypmods); + WRITE_NODE_FIELD(colcollations); break; case RTE_CTE: WRITE_STRING_FIELD(ctename); WRITE_UINT_FIELD(ctelevelsup); WRITE_BOOL_FIELD(self_reference); - WRITE_NODE_FIELD(ctecoltypes); - WRITE_NODE_FIELD(ctecoltypmods); - WRITE_NODE_FIELD(ctecolcollations); + WRITE_NODE_FIELD(coltypes); + WRITE_NODE_FIELD(coltypmods); + WRITE_NODE_FIELD(colcollations); break; default: elog(ERROR, "unrecognized RTE kind: %d", (int) node->rtekind); @@ -2979,12 +3200,12 @@ _outValue(StringInfo str, const Value *value) case T_String: /* - * We use _outToken to provide escaping of the string's content, + * We use outToken to provide escaping of the string's content, * but we don't want it to do anything with an empty string. */ appendStringInfoChar(str, '"'); if (value->val.str[0] != '\0') - _outToken(str, value->val.str); + outToken(str, value->val.str); appendStringInfoChar(str, '"'); break; case T_BitString: @@ -3266,6 +3487,47 @@ _outForeignKeyCacheInfo(StringInfo str, const ForeignKeyCacheInfo *node) appendStringInfo(str, " %u", node->conpfeqop[i]); } +static void +_outPartitionSpec(StringInfo str, const PartitionSpec *node) +{ + WRITE_NODE_TYPE("PARTITIONBY"); + + WRITE_STRING_FIELD(strategy); + WRITE_NODE_FIELD(partParams); + WRITE_LOCATION_FIELD(location); +} + +static void +_outPartitionElem(StringInfo str, const PartitionElem *node) +{ + WRITE_NODE_TYPE("PARTITIONELEM"); + + WRITE_STRING_FIELD(name); + WRITE_NODE_FIELD(expr); + WRITE_NODE_FIELD(collation); + WRITE_NODE_FIELD(opclass); + WRITE_LOCATION_FIELD(location); +} + +static void +_outPartitionBoundSpec(StringInfo str, const PartitionBoundSpec *node) +{ + WRITE_NODE_TYPE("PARTITIONBOUND"); + + WRITE_CHAR_FIELD(strategy); + WRITE_NODE_FIELD(listdatums); + WRITE_NODE_FIELD(lowerdatums); + WRITE_NODE_FIELD(upperdatums); +} + +static void +_outPartitionRangeDatum(StringInfo str, const PartitionRangeDatum *node) +{ + WRITE_NODE_TYPE("PARTRANGEDATUM"); + + WRITE_BOOL_FIELD(infinite); + WRITE_NODE_FIELD(value); +} /* * outNode - @@ -3300,6 +3562,9 @@ outNode(StringInfo str, const void *obj) case T_Result: _outResult(str, obj); break; + case T_ProjectSet: + _outProjectSet(str, obj); + break; case T_ModifyTable: _outModifyTable(str, obj); break; @@ -3522,6 +3787,9 @@ outNode(StringInfo str, const void *obj) case T_MinMaxExpr: _outMinMaxExpr(str, obj); break; + case T_SQLValueFunction: + _outSQLValueFunction(str, obj); + break; case T_XmlExpr: _outXmlExpr(str, obj); break; @@ -3609,6 +3877,9 @@ outNode(StringInfo str, const void *obj) case T_ProjectionPath: _outProjectionPath(str, obj); break; + case T_ProjectSetPath: + _outProjectSetPath(str, obj); + break; case T_SortPath: _outSortPath(str, obj); break; @@ -3848,6 +4119,21 @@ outNode(StringInfo str, const void *obj) case T_ForeignKeyCacheInfo: _outForeignKeyCacheInfo(str, obj); break; + case T_TriggerTransition: + _outTriggerTransition(str, obj); + break; + case T_PartitionSpec: + _outPartitionSpec(str, obj); + break; + case T_PartitionElem: + _outPartitionElem(str, obj); + break; + case T_PartitionBoundSpec: + _outPartitionBoundSpec(str, obj); + break; + case T_PartitionRangeDatum: + _outPartitionRangeDatum(str, obj); + break; default: @@ -3877,3 +4163,66 @@ nodeToString(const void *obj) outNode(&str, obj); return str.data; } + +/* + * bmsToString - + * returns the ascii representation of the Bitmapset as a palloc'd string + */ +char * +bmsToString(const Bitmapset *bms) +{ + StringInfoData str; + + /* see stringinfo.h for an explanation of this maneuver */ + initStringInfo(&str); + outBitmapset(&str, bms); + return str.data; +} + +/* + * Output value in text format + */ +static void +_printDatum(StringInfo str, Datum value, Oid typid) +{ + Oid typOutput; + bool typIsVarlena; + FmgrInfo finfo; + Datum tmpval; + char *textvalue; + int saveDateStyle; + + /* Get output function for the type */ + getTypeOutputInfo(typid, &typOutput, &typIsVarlena); + fmgr_info(typOutput, &finfo); + + /* Detoast value if needed */ + if (typIsVarlena) + tmpval = PointerGetDatum(PG_DETOAST_DATUM(value)); + else + tmpval = value; + + /* + * It was found that if configuration setting for date style is + * "postgres,ymd" the output dates have format DD-MM-YYYY and they can not + * be parsed correctly by receiving party. So force ISO format YYYY-MM-DD + * in internal cluster communications, these values are always parsed + * correctly. + */ + saveDateStyle = DateStyle; + DateStyle = USE_ISO_DATES; + + if (typid == OIDOID) + { + /* Const type is "OID". Need to parse. */ + Oid oid = DatumGetObjectId(value); + + write_oid_field(str, oid); + } + else + { + textvalue = DatumGetCString(FunctionCall1(&finfo, tmpval)); + outToken(str, textvalue); + } + DateStyle = saveDateStyle; +} diff --git a/src/backend/nodes/params.c b/src/backend/nodes/params.c index f2e26b80c4..0fb08b94db 100644 --- a/src/backend/nodes/params.c +++ b/src/backend/nodes/params.c @@ -4,7 +4,7 @@ * Support for finding the values associated with Param nodes. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c index a1f29416ab..926f226f34 100644 --- a/src/backend/nodes/print.c +++ b/src/backend/nodes/print.c @@ -3,7 +3,7 @@ * print.c * various print routines (used mostly for debugging) * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/nodes/read.c b/src/backend/nodes/read.c index c1ab494d77..b56f28e15f 100644 --- a/src/backend/nodes/read.c +++ b/src/backend/nodes/read.c @@ -4,7 +4,7 @@ * routines to convert a string (legal ascii representation of node) back * to nodes * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 94954dcc72..8df116bbc0 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -3,7 +3,7 @@ * readfuncs.c * Reader functions for Postgres tree nodes. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -34,6 +34,28 @@ #include "nodes/plannodes.h" #include "nodes/readfuncs.h" +/* Portable-related dependencies */ +#include "catalog/namespace.h" +#include "catalog/pg_type.h" +#include "commands/dbcommands.h" +#include "commands/defrem.h" +#include "commands/proclang.h" +#include "commands/user.h" +#include "rewrite/rewriteSupport.h" +#include "utils/builtins.h" +#include "utils/lsyscache.h" +#include "utils/syscache.h" + +#define NSP_OID(nspname) LookupNamespaceNoError(nspname) +static Oid read_oid_field(char **token, int *length); +static Datum scanDatum(Oid typid, int typmod); + +static bool portable_input = false; +void +set_portable_input(bool value) +{ + portable_input = value; +} /* * Macros to simplify reading of different kinds of fields. Use these @@ -79,8 +101,7 @@ /* Read an OID field (don't hard-wire assumption that OID is same as uint) */ #define READ_OID_FIELD(fldname) \ token = pg_strtok(&length); /* skip :fldname */ \ - token = pg_strtok(&length); /* get field value */ \ - local_node->fldname = atooid(token) + local_node->fldname = read_oid_field(&token, &length); /* Read a char field (ie, one ascii character) */ #define READ_CHAR_FIELD(fldname) \ @@ -117,7 +138,7 @@ token = pg_strtok(&length); /* skip :fldname */ \ token = pg_strtok(&length); /* get field value */ \ (void) token; /* in case not used elsewhere */ \ - local_node->fldname = -1 /* set field to "unknown" */ + local_node->fldname = atoi(token) /* set field to "unknown" */ /* Read a Node field */ #define READ_NODE_FIELD(fldname) \ @@ -238,6 +259,7 @@ _readQuery(void) READ_INT_FIELD(resultRelation); READ_BOOL_FIELD(hasAggs); READ_BOOL_FIELD(hasWindowFuncs); + READ_BOOL_FIELD(hasTargetSRFs); READ_BOOL_FIELD(hasSubLinks); READ_BOOL_FIELD(hasDistinctOn); READ_BOOL_FIELD(hasRecursive); @@ -261,6 +283,9 @@ _readQuery(void) READ_NODE_FIELD(rowMarks); READ_NODE_FIELD(setOperations); READ_NODE_FIELD(constraintDeps); + /* withCheckOptions intentionally omitted, see comment in parsenodes.h */ + READ_LOCATION_FIELD(stmt_location); + READ_LOCATION_FIELD(stmt_len); READ_DONE(); } @@ -448,7 +473,7 @@ _readRangeVar(void) READ_STRING_FIELD(schemaname); READ_STRING_FIELD(relname); - READ_ENUM_FIELD(inhOpt, InhOption); + READ_BOOL_FIELD(inh); READ_CHAR_FIELD(relpersistence); READ_NODE_FIELD(alias); READ_LOCATION_FIELD(location); @@ -512,6 +537,9 @@ _readConst(void) token = pg_strtok(&length); /* skip :constvalue */ if (local_node->constisnull) token = pg_strtok(&length); /* skip "<>" */ + else if (portable_input) + local_node->constvalue = scanDatum(local_node->consttype, + local_node->consttypmod); else local_node->constvalue = readDatum(local_node->constbyval); @@ -1041,6 +1069,22 @@ _readMinMaxExpr(void) READ_DONE(); } +/* + * _readSQLValueFunction + */ +static SQLValueFunction * +_readSQLValueFunction(void) +{ + READ_LOCALS(SQLValueFunction); + + READ_ENUM_FIELD(op, SQLValueFunctionOp); + READ_OID_FIELD(type); + READ_INT_FIELD(typmod); + READ_LOCATION_FIELD(location); + + READ_DONE(); +} + /* * _readXmlExpr */ @@ -1297,15 +1341,17 @@ _readRangeTblEntry(void) break; case RTE_VALUES: READ_NODE_FIELD(values_lists); - READ_NODE_FIELD(values_collations); + READ_NODE_FIELD(coltypes); + READ_NODE_FIELD(coltypmods); + READ_NODE_FIELD(colcollations); break; case RTE_CTE: READ_STRING_FIELD(ctename); READ_UINT_FIELD(ctelevelsup); READ_BOOL_FIELD(self_reference); - READ_NODE_FIELD(ctecoltypes); - READ_NODE_FIELD(ctecoltypmods); - READ_NODE_FIELD(ctecolcollations); + READ_NODE_FIELD(coltypes); + READ_NODE_FIELD(coltypmods); + READ_NODE_FIELD(colcollations); break; default: elog(ERROR, "unrecognized RTE kind: %d", @@ -1372,6 +1418,7 @@ _readDefElem(void) READ_STRING_FIELD(defname); READ_NODE_FIELD(arg); READ_ENUM_FIELD(defaction, DefElemAction); + READ_LOCATION_FIELD(location); READ_DONE(); } @@ -1395,13 +1442,15 @@ _readPlannedStmt(void) READ_NODE_FIELD(planTree); READ_NODE_FIELD(rtable); READ_NODE_FIELD(resultRelations); - READ_NODE_FIELD(utilityStmt); READ_NODE_FIELD(subplans); READ_BITMAPSET_FIELD(rewindPlanIDs); READ_NODE_FIELD(rowMarks); READ_NODE_FIELD(relationOids); READ_NODE_FIELD(invalItems); READ_INT_FIELD(nParamExec); + READ_NODE_FIELD(utilityStmt); + READ_LOCATION_FIELD(stmt_location); + READ_LOCATION_FIELD(stmt_len); READ_DONE(); } @@ -1458,6 +1507,19 @@ _readResult(void) READ_DONE(); } +/* + * _readProjectSet + */ +static ProjectSet * +_readProjectSet(void) +{ + READ_LOCALS_NO_FIELDS(ProjectSet); + + ReadCommonPlan(&local_node->plan); + + READ_DONE(); +} + /* * _readModifyTable */ @@ -1991,6 +2053,7 @@ _readAgg(void) READ_ATTRNUMBER_ARRAY(grpColIdx, local_node->numCols); READ_OID_ARRAY(grpOperators, local_node->numCols); READ_LONG_FIELD(numGroups); + READ_BITMAPSET_FIELD(aggParams); READ_NODE_FIELD(groupingSets); READ_NODE_FIELD(chain); @@ -2246,6 +2309,36 @@ _readExtensibleNode(void) READ_DONE(); } +/* + * _readPartitionBoundSpec + */ +static PartitionBoundSpec * +_readPartitionBoundSpec(void) +{ + READ_LOCALS(PartitionBoundSpec); + + READ_CHAR_FIELD(strategy); + READ_NODE_FIELD(listdatums); + READ_NODE_FIELD(lowerdatums); + READ_NODE_FIELD(upperdatums); + + READ_DONE(); +} + +/* + * _readPartitionRangeDatum + */ +static PartitionRangeDatum * +_readPartitionRangeDatum(void) +{ + READ_LOCALS(PartitionRangeDatum); + + READ_BOOL_FIELD(infinite); + READ_NODE_FIELD(value); + + READ_DONE(); +} + /* * parseNodeString * @@ -2348,6 +2441,8 @@ parseNodeString(void) return_value = _readCoalesceExpr(); else if (MATCH("MINMAX", 6)) return_value = _readMinMaxExpr(); + else if (MATCH("SQLVALUEFUNCTION", 16)) + return_value = _readSQLValueFunction(); else if (MATCH("XMLEXPR", 7)) return_value = _readXmlExpr(); else if (MATCH("NULLTEST", 8)) @@ -2392,6 +2487,8 @@ parseNodeString(void) return_value = _readPlan(); else if (MATCH("RESULT", 6)) return_value = _readResult(); + else if (MATCH("PROJECTSET", 10)) + return_value = _readProjectSet(); else if (MATCH("MODIFYTABLE", 11)) return_value = _readModifyTable(); else if (MATCH("APPEND", 6)) @@ -2476,6 +2573,10 @@ parseNodeString(void) return_value = _readAlternativeSubPlan(); else if (MATCH("EXTENSIBLENODE", 14)) return_value = _readExtensibleNode(); + else if (MATCH("PARTITIONBOUND", 14)) + return_value = _readPartitionBoundSpec(); + else if (MATCH("PARTRANGEDATUM", 14)) + return_value = _readPartitionRangeDatum(); else { elog(ERROR, "badly formatted node string \"%.32s\"...", token); @@ -2642,3 +2743,315 @@ readBoolCols(int numCols) return bool_vals; } + +#define atooid(x) ((Oid) strtoul((x), NULL, 10)) + +static Oid +read_oid_field(char **token, int *length) +{ + Oid oid_type, + oid; + + if (!portable_input) + { + *token = pg_strtok(length); + return atooid(*token); + } + + *token = pg_strtok(length); + Assert((*token)[0] == '('); + *token = pg_strtok(length); + oid_type = atooid(*token); + + /* + * It is undefined oid type + */ + if (!OidIsValid(oid_type)) + { + Oid oid; + + *token = pg_strtok(length); + oid = atooid(*token); + *token = pg_strtok(length); + Assert((*token)[0] == ')'); + return oid; + } + + switch (oid_type) + { + case RELOID: + { + char *relname, + *nspname; + Oid rel_nsp_oid; + + *token = pg_strtok(length); /* Switch to namespace name */ + nspname = nullable_string(*token, *length); + rel_nsp_oid = LookupNamespaceNoError(nspname); + *token = pg_strtok(length); /* Switch to relname */ + relname = nullable_string(*token, *length); + oid = get_relname_relid(relname, rel_nsp_oid); + break; + } + case TYPEOID: + { + char *nspname; /* namespace name */ + char *typname; /* data type name */ + + *token = pg_strtok(length); /* get nspname */ + nspname = nullable_string(*token, *length); + *token = pg_strtok(length); /* get typname */ + typname = nullable_string(*token, *length); + if (typname) + { + oid = get_typname_typid(typname, LookupNamespaceNoError((nspname))); + if (!OidIsValid((oid))) + elog(WARNING, "could not find OID for type %s.%s", + nspname, typname); + } + else + oid = InvalidOid; + } + break; + + case PROCOID: + { + char *nspname; /* namespace name */ + char *funcname; /* function name */ + int nargs; /* number of arguments */ + Oid *argtypes; /* argument types */ + + *token = pg_strtok(length); /* get nspname */ + nspname = nullable_string(*token, *length); + *token = pg_strtok(length); /* get funcname */ + funcname = nullable_string(*token, *length); + *token = pg_strtok(length); /* get nargs */ + nargs = atoi(*token); + + if (funcname) + { + int i; + + argtypes = palloc(nargs * sizeof(Oid)); + for (i = 0; i < nargs; i++) + { + char *typnspname; /* argument type namespace */ + char *typname; /* argument type name */ + + *token = pg_strtok(length); /* get type nspname */ + typnspname = nullable_string(*token, *length); + *token = pg_strtok(length); /* get type name */ + typname = nullable_string(*token, *length); + argtypes[i] = get_typname_typid(typname, + NSP_OID(typnspname)); + } + oid = get_funcid(funcname, buildoidvector(argtypes, nargs), NSP_OID(nspname)); + } + else + oid = InvalidOid; + } + break; + + case COLLOID: + { + char *nspname; /* namespace name */ + char *collname; /* collation name */ + int collencoding; /* collation encoding */ + + *token = pg_strtok(length); /* get nspname */ + nspname = nullable_string(*token, *length); + *token = pg_strtok(length); /* get collname */ + collname = nullable_string(*token, *length); + *token = pg_strtok(length); /* get collencoding */ + collencoding = atoi(*token); + if (collname) + oid = get_collid(collname, collencoding, NSP_OID(nspname)); + else + oid = InvalidOid; + } + break; + + case OPEROID: + { + char *nspname; /* namespace name */ + char *oprname; /* operator name */ + char *leftnspname; /* left type namespace */ + char *leftname; /* left type name */ + Oid oprleft; /* left type */ + char *rightnspname; /* right type namespace */ + char *rightname; /* right type name */ + Oid oprright; /* right type */ + + *token = pg_strtok(length); /* get nspname */ + nspname = nullable_string(*token, *length); + *token = pg_strtok(length); /* get operator name */ + oprname = nullable_string(*token, *length); + *token = pg_strtok(length); /* left type namespace */ + leftnspname = nullable_string(*token, *length); + *token = pg_strtok(length); /* left type name */ + leftname = nullable_string(*token, *length); + *token = pg_strtok(length); /* right type namespace */ + rightnspname = nullable_string(*token, *length); + *token = pg_strtok(length); /* right type name */ + rightname = nullable_string(*token, *length); + if (oprname) + { + if (leftname) + oprleft = get_typname_typid(leftname, NSP_OID(leftnspname)); + else + oprleft = InvalidOid; + if (rightname) + oprright = get_typname_typid(rightname, NSP_OID(rightnspname)); + else + oprright = InvalidOid; + oid = get_operid(oprname, oprleft, oprright, NSP_OID(nspname)); + } + else + oid = InvalidOid; + } + break; + + case AUTHOID: + { + char *rolename; + + *token = pg_strtok(length); /* get nspname */ + rolename = nullable_string(*token, *length); + oid = get_roleid(rolename); + } + break; + + case LANGOID: + { + char *langname; + + *token = pg_strtok(length); /* get nspname */ + langname = nullable_string(*token, *length); + oid = get_language_oid(langname, false); + } + break; + + case AMOID: + { + char *amname; + + *token = pg_strtok(length); /* get nspname */ + amname = nullable_string(*token, *length); + oid = get_am_oid(amname, false); + } + break; + + case NAMESPACEOID: + { + char *nspname; + + *token = pg_strtok(length); /* get nspname */ + nspname = nullable_string(*token, *length); + oid = LookupNamespaceNoError(nspname); + } + break; + + case DATABASEOID: + { + char *dbname; + + *token = pg_strtok(length); /* get nspname */ + dbname = nullable_string(*token, *length); + oid = get_database_oid(dbname, false); + } + break; + + case RULEOID: + { + char *rulename, + *relname, + *nspname; + Oid nspoid, + reloid; + + *token = pg_strtok(length); /* get name of the rule */ + rulename = nullable_string(*token, *length); + + *token = pg_strtok(length); + nspname = nullable_string(*token, *length); + nspoid = LookupNamespaceNoError(nspname); + *token = pg_strtok(length); + relname = nullable_string(*token, *length); + reloid = get_relname_relid(relname, nspoid); + + oid = get_rewrite_oid(reloid, rulename, false); + } + break; + + case OPFAMILYOID: + { + char *opfname = NULL, + *nspname = NULL, + *amname = NULL; + + *token = pg_strtok(length); + opfname = nullable_string(*token, *length); + *token = pg_strtok(length); + nspname = nullable_string(*token, *length); + *token = pg_strtok(length); + amname = nullable_string(*token, *length); + oid = get_family_oid(opfname, nspname, amname); + } + break; + + default: + Assert(0); + break; + } + *token = pg_strtok(length); + Assert((*token)[0] == ')'); + return oid; +} + +/* + * scanDatum + * + * Recreate Datum from the text format understandable by the input function + * of the specified data type. + */ +static Datum +scanDatum(Oid typid, int typmod) +{ + Oid typInput; + Oid typioparam; + FmgrInfo finfo; + FunctionCallInfoData fcinfo; + char *value; + Datum res; + + READ_TEMP_LOCALS(); + + if (typid == OIDOID) + return read_oid_field(&token, &length); + + /* Get input function for the type */ + getTypeInputInfo(typid, &typInput, &typioparam); + fmgr_info(typInput, &finfo); + + /* Read the value */ + token = pg_strtok(&length); + value = nullable_string(token, length); + + /* The value can not be NULL, so we actually received empty string */ + if (value == NULL) + value = ""; + + /* Invoke input function */ + InitFunctionCallInfoData(fcinfo, &finfo, 3, InvalidOid, NULL, NULL); + + fcinfo.arg[0] = CStringGetDatum(value); + fcinfo.arg[1] = ObjectIdGetDatum(typioparam); + fcinfo.arg[2] = Int32GetDatum(typmod); + fcinfo.argnull[0] = false; + fcinfo.argnull[1] = false; + fcinfo.argnull[2] = false; + + res = FunctionCallInvoke(&fcinfo); + + return res; +} diff --git a/src/backend/nodes/tidbitmap.c b/src/backend/nodes/tidbitmap.c index dfeb7d5c63..7b31948fd2 100644 --- a/src/backend/nodes/tidbitmap.c +++ b/src/backend/nodes/tidbitmap.c @@ -29,7 +29,7 @@ * and a non-lossy page. * * - * Copyright (c) 2003-2016, PostgreSQL Global Development Group + * Copyright (c) 2003-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/nodes/tidbitmap.c @@ -43,7 +43,6 @@ #include "access/htup_details.h" #include "nodes/bitmapset.h" #include "nodes/tidbitmap.h" -#include "utils/hsearch.h" /* * The maximum number of tuples per page is not large (typically 256 with @@ -61,12 +60,12 @@ * for that page in the page table. * * We actually store both exact pages and lossy chunks in the same hash - * table, using identical data structures. (This is because dynahash.c's - * memory management doesn't allow space to be transferred easily from one - * hashtable to another.) Therefore it's best if PAGES_PER_CHUNK is the - * same as MAX_TUPLES_PER_PAGE, or at least not too different. But we - * also want PAGES_PER_CHUNK to be a power of 2 to avoid expensive integer - * remainder operations. So, define it like this: + * table, using identical data structures. (This is because the memory + * management for hashtables doesn't easily/efficiently allow space to be + * transferred easily from one hashtable to another.) Therefore it's best + * if PAGES_PER_CHUNK is the same as MAX_TUPLES_PER_PAGE, or at least not + * too different. But we also want PAGES_PER_CHUNK to be a power of 2 to + * avoid expensive integer remainder operations. So, define it like this: */ #define PAGES_PER_CHUNK (BLCKSZ / 32) @@ -97,21 +96,22 @@ typedef struct PagetableEntry { BlockNumber blockno; /* page number (hashtable key) */ + char status; /* hash entry status */ bool ischunk; /* T = lossy storage, F = exact */ bool recheck; /* should the tuples be rechecked? */ bitmapword words[Max(WORDS_PER_PAGE, WORDS_PER_CHUNK)]; } PagetableEntry; /* - * dynahash.c is optimized for relatively large, long-lived hash tables. - * This is not ideal for TIDBitMap, particularly when we are using a bitmap - * scan on the inside of a nestloop join: a bitmap may well live only long - * enough to accumulate one entry in such cases. We therefore avoid creating - * an actual hashtable until we need two pagetable entries. When just one - * pagetable entry is needed, we store it in a fixed field of TIDBitMap. - * (NOTE: we don't get rid of the hashtable if the bitmap later shrinks down - * to zero or one page again. So, status can be TBM_HASH even when nentries - * is zero or one.) + * We want to avoid the overhead of creating the hashtable, which is + * comparatively large, when not necessary. Particularly when we are using a + * bitmap scan on the inside of a nestloop join: a bitmap may well live only + * long enough to accumulate one entry in such cases. We therefore avoid + * creating an actual hashtable until we need two pagetable entries. When + * just one pagetable entry is needed, we store it in a fixed field of + * TIDBitMap. (NOTE: we don't get rid of the hashtable if the bitmap later + * shrinks down to zero or one page again. So, status can be TBM_HASH even + * when nentries is zero or one.) */ typedef enum { @@ -128,12 +128,13 @@ struct TIDBitmap NodeTag type; /* to make it a valid Node */ MemoryContext mcxt; /* memory context containing me */ TBMStatus status; /* see codes above */ - HTAB *pagetable; /* hash table of PagetableEntry's */ + struct pagetable_hash *pagetable; /* hash table of PagetableEntry's */ int nentries; /* number of entries in pagetable */ int maxentries; /* limit on same to meet maxbytes */ int npages; /* number of exact entries in pagetable */ int nchunks; /* number of lossy entries in pagetable */ bool iterating; /* tbm_begin_iterate called? */ + uint32 lossify_start; /* offset to start lossifying hashtable at */ PagetableEntry entry1; /* used when status == TBM_ONE_PAGE */ /* these are valid when iterating is true: */ PagetableEntry **spages; /* sorted exact-page list, or NULL */ @@ -168,6 +169,35 @@ static void tbm_mark_page_lossy(TIDBitmap *tbm, BlockNumber pageno); static void tbm_lossify(TIDBitmap *tbm); static int tbm_comparator(const void *left, const void *right); +/* + * Simple inline murmur hash implementation for the exact width required, for + * performance. + */ +static inline uint32 +hash_blockno(BlockNumber b) +{ + uint32 h = b; + + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + return h; +} + +/* define hashtable mapping block numbers to PagetableEntry's */ +#define SH_PREFIX pagetable +#define SH_ELEMENT_TYPE PagetableEntry +#define SH_KEY_TYPE BlockNumber +#define SH_KEY blockno +#define SH_HASH_KEY(tb, key) hash_blockno(key) +#define SH_EQUAL(tb, a, b) a == b +#define SH_SCOPE static inline +#define SH_DEFINE +#define SH_DECLARE +#include "lib/simplehash.h" + /* * tbm_create - create an initially-empty bitmap @@ -190,17 +220,16 @@ tbm_create(long maxbytes) /* * Estimate number of hashtable entries we can have within maxbytes. This - * estimates the hash overhead at MAXALIGN(sizeof(HASHELEMENT)) plus a - * pointer per hash entry, which is crude but good enough for our purpose. - * Also count an extra Pointer per entry for the arrays created during - * iteration readout. + * estimates the hash cost as sizeof(PagetableEntry), which is good enough + * for our purpose. Also count an extra Pointer per entry for the arrays + * created during iteration readout. */ nbuckets = maxbytes / - (MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(sizeof(PagetableEntry)) - + sizeof(Pointer) + sizeof(Pointer)); + (sizeof(PagetableEntry) + sizeof(Pointer) + sizeof(Pointer)); nbuckets = Min(nbuckets, INT_MAX - 1); /* safety limit */ nbuckets = Max(nbuckets, 16); /* sanity limit */ tbm->maxentries = (int) nbuckets; + tbm->lossify_start = 0; return tbm; } @@ -212,32 +241,25 @@ tbm_create(long maxbytes) static void tbm_create_pagetable(TIDBitmap *tbm) { - HASHCTL hash_ctl; - Assert(tbm->status != TBM_HASH); Assert(tbm->pagetable == NULL); - /* Create the hashtable proper */ - MemSet(&hash_ctl, 0, sizeof(hash_ctl)); - hash_ctl.keysize = sizeof(BlockNumber); - hash_ctl.entrysize = sizeof(PagetableEntry); - hash_ctl.hcxt = tbm->mcxt; - tbm->pagetable = hash_create("TIDBitmap", - 128, /* start small and extend */ - &hash_ctl, - HASH_ELEM | HASH_BLOBS | HASH_CONTEXT); + tbm->pagetable = pagetable_create(tbm->mcxt, 128); /* If entry1 is valid, push it into the hashtable */ if (tbm->status == TBM_ONE_PAGE) { PagetableEntry *page; bool found; + char oldstatus; - page = (PagetableEntry *) hash_search(tbm->pagetable, - (void *) &tbm->entry1.blockno, - HASH_ENTER, &found); + page = pagetable_insert(tbm->pagetable, + tbm->entry1.blockno, + &found); Assert(!found); + oldstatus = page->status; memcpy(page, &tbm->entry1, sizeof(PagetableEntry)); + page->status = oldstatus; } tbm->status = TBM_HASH; @@ -250,7 +272,7 @@ void tbm_free(TIDBitmap *tbm) { if (tbm->pagetable) - hash_destroy(tbm->pagetable); + pagetable_destroy(tbm->pagetable); if (tbm->spages) pfree(tbm->spages); if (tbm->schunks) @@ -357,12 +379,12 @@ tbm_union(TIDBitmap *a, const TIDBitmap *b) tbm_union_page(a, &b->entry1); else { - HASH_SEQ_STATUS status; + pagetable_iterator i; PagetableEntry *bpage; Assert(b->status == TBM_HASH); - hash_seq_init(&status, b->pagetable); - while ((bpage = (PagetableEntry *) hash_seq_search(&status)) != NULL) + pagetable_start_iterate(b->pagetable, &i); + while ((bpage = pagetable_iterate(b->pagetable, &i)) != NULL) tbm_union_page(a, bpage); } } @@ -449,12 +471,12 @@ tbm_intersect(TIDBitmap *a, const TIDBitmap *b) } else { - HASH_SEQ_STATUS status; + pagetable_iterator i; PagetableEntry *apage; Assert(a->status == TBM_HASH); - hash_seq_init(&status, a->pagetable); - while ((apage = (PagetableEntry *) hash_seq_search(&status)) != NULL) + pagetable_start_iterate(a->pagetable, &i); + while ((apage = pagetable_iterate(a->pagetable, &i)) != NULL) { if (tbm_intersect_page(a, apage, b)) { @@ -464,9 +486,7 @@ tbm_intersect(TIDBitmap *a, const TIDBitmap *b) else a->npages--; a->nentries--; - if (hash_search(a->pagetable, - (void *) &apage->blockno, - HASH_REMOVE, NULL) == NULL) + if (!pagetable_delete(a->pagetable, apage->blockno)) elog(ERROR, "hash table corrupted"); } } @@ -606,7 +626,7 @@ tbm_begin_iterate(TIDBitmap *tbm) */ if (tbm->status == TBM_HASH && !tbm->iterating) { - HASH_SEQ_STATUS status; + pagetable_iterator i; PagetableEntry *page; int npages; int nchunks; @@ -620,9 +640,9 @@ tbm_begin_iterate(TIDBitmap *tbm) MemoryContextAlloc(tbm->mcxt, tbm->nchunks * sizeof(PagetableEntry *)); - hash_seq_init(&status, tbm->pagetable); npages = nchunks = 0; - while ((page = (PagetableEntry *) hash_seq_search(&status)) != NULL) + pagetable_start_iterate(tbm->pagetable, &i); + while ((page = pagetable_iterate(tbm->pagetable, &i)) != NULL) { if (page->ischunk) tbm->schunks[nchunks++] = page; @@ -791,9 +811,7 @@ tbm_find_pageentry(const TIDBitmap *tbm, BlockNumber pageno) return page; } - page = (PagetableEntry *) hash_search(tbm->pagetable, - (void *) &pageno, - HASH_FIND, NULL); + page = pagetable_lookup(tbm->pagetable, pageno); if (page == NULL) return NULL; if (page->ischunk) @@ -834,15 +852,16 @@ tbm_get_pageentry(TIDBitmap *tbm, BlockNumber pageno) } /* Look up or create an entry */ - page = (PagetableEntry *) hash_search(tbm->pagetable, - (void *) &pageno, - HASH_ENTER, &found); + page = pagetable_insert(tbm->pagetable, pageno, &found); } /* Initialize it if not present before */ if (!found) { + char oldstatus = page->status; + MemSet(page, 0, sizeof(PagetableEntry)); + page->status = oldstatus; page->blockno = pageno; /* must count it too */ tbm->nentries++; @@ -869,9 +888,9 @@ tbm_page_is_lossy(const TIDBitmap *tbm, BlockNumber pageno) bitno = pageno % PAGES_PER_CHUNK; chunk_pageno = pageno - bitno; - page = (PagetableEntry *) hash_search(tbm->pagetable, - (void *) &chunk_pageno, - HASH_FIND, NULL); + + page = pagetable_lookup(tbm->pagetable, chunk_pageno); + if (page != NULL && page->ischunk) { int wordnum = WORDNUM(bitno); @@ -912,9 +931,7 @@ tbm_mark_page_lossy(TIDBitmap *tbm, BlockNumber pageno) */ if (bitno != 0) { - if (hash_search(tbm->pagetable, - (void *) &pageno, - HASH_REMOVE, NULL) != NULL) + if (pagetable_delete(tbm->pagetable, pageno)) { /* It was present, so adjust counts */ tbm->nentries--; @@ -923,14 +940,15 @@ tbm_mark_page_lossy(TIDBitmap *tbm, BlockNumber pageno) } /* Look up or create entry for chunk-header page */ - page = (PagetableEntry *) hash_search(tbm->pagetable, - (void *) &chunk_pageno, - HASH_ENTER, &found); + page = pagetable_insert(tbm->pagetable, chunk_pageno, &found); /* Initialize it if not present before */ if (!found) { + char oldstatus = page->status; + MemSet(page, 0, sizeof(PagetableEntry)); + page->status = oldstatus; page->blockno = chunk_pageno; page->ischunk = true; /* must count it too */ @@ -939,8 +957,11 @@ tbm_mark_page_lossy(TIDBitmap *tbm, BlockNumber pageno) } else if (!page->ischunk) { + char oldstatus = page->status; + /* chunk header page was formerly non-lossy, make it lossy */ MemSet(page, 0, sizeof(PagetableEntry)); + page->status = oldstatus; page->blockno = chunk_pageno; page->ischunk = true; /* we assume it had some tuple bit(s) set, so mark it lossy */ @@ -962,7 +983,7 @@ tbm_mark_page_lossy(TIDBitmap *tbm, BlockNumber pageno) static void tbm_lossify(TIDBitmap *tbm) { - HASH_SEQ_STATUS status; + pagetable_iterator i; PagetableEntry *page; /* @@ -977,8 +998,8 @@ tbm_lossify(TIDBitmap *tbm) Assert(!tbm->iterating); Assert(tbm->status == TBM_HASH); - hash_seq_init(&status, tbm->pagetable); - while ((page = (PagetableEntry *) hash_seq_search(&status)) != NULL) + pagetable_start_iterate_at(tbm->pagetable, &i, tbm->lossify_start); + while ((page = pagetable_iterate(tbm->pagetable, &i)) != NULL) { if (page->ischunk) continue; /* already a chunk header */ @@ -995,15 +1016,19 @@ tbm_lossify(TIDBitmap *tbm) if (tbm->nentries <= tbm->maxentries / 2) { - /* we have done enough */ - hash_seq_term(&status); + /* + * We have made enough room. Remember where to start lossifying + * next round, so we evenly iterate over the hashtable. + */ + tbm->lossify_start = i.cur; break; } /* * Note: tbm_mark_page_lossy may have inserted a lossy chunk into the - * hashtable. We can continue the same seq_search scan since we do - * not care whether we visit lossy chunks or not. + * hashtable and may have deleted the non-lossy chunk. We can + * continue the same hash table scan, since failure to visit one + * element or visiting the newly inserted element, isn't fatal. */ } diff --git a/src/backend/nodes/value.c b/src/backend/nodes/value.c index a5ed5bc7c2..5d2f96c103 100644 --- a/src/backend/nodes/value.c +++ b/src/backend/nodes/value.c @@ -4,7 +4,7 @@ * implementation of Value nodes * * - * Copyright (c) 2003-2016, PostgreSQL Global Development Group + * Copyright (c) 2003-2017, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/optimizer/README b/src/backend/optimizer/README index 775bcc3b73..7ae2b74b2c 100644 --- a/src/backend/optimizer/README +++ b/src/backend/optimizer/README @@ -375,6 +375,7 @@ RelOptInfo - a relation or joined relations UniquePath - remove duplicate rows (either by hashing or sorting) GatherPath - collect the results of parallel workers ProjectionPath - a Result plan node with child (used for projection) + ProjectSetPath - a ProjectSet plan node applied to some sub-path SortPath - a Sort plan node applied to some sub-path GroupPath - a Group plan node applied to some sub-path UpperUniquePath - a Unique plan node applied to some sub-path @@ -877,6 +878,108 @@ lateral reference. (Perhaps now that that stuff works, we could relax the pullup restriction?) +Security-level constraints on qual clauses +------------------------------------------ + +To support row-level security and security-barrier views efficiently, +we mark qual clauses (RestrictInfo nodes) with a "security_level" field. +The basic concept is that a qual with a lower security_level must be +evaluated before one with a higher security_level. This ensures that +"leaky" quals that might expose sensitive data are not evaluated until +after the security barrier quals that are supposed to filter out +security-sensitive rows. However, many qual conditions are "leakproof", +that is we trust the functions they use to not expose data. To avoid +unnecessarily inefficient plans, a leakproof qual is not delayed by +security-level considerations, even if it has a higher syntactic +security_level than another qual. + +In a query that contains no use of RLS or security-barrier views, all +quals will have security_level zero, so that none of these restrictions +kick in; we don't even need to check leakproofness of qual conditions. + +If there are security-barrier quals, they get security_level zero (and +possibly higher, if there are multiple layers of barriers). Regular quals +coming from the query text get a security_level one more than the highest +level used for barrier quals. + +When new qual clauses are generated by EquivalenceClass processing, +they must be assigned a security_level. This is trickier than it seems. +One's first instinct is that it would be safe to use the largest level +found among the source quals for the EquivalenceClass, but that isn't +safe at all, because it allows unwanted delays of security-barrier quals. +Consider a barrier qual "t.x = t.y" plus a query qual "t.x = constant", +and suppose there is another query qual "leaky_function(t.z)" that +we mustn't evaluate before the barrier qual has been checked. +We will have an EC {t.x, t.y, constant} which will lead us to replace +the EC quals with "t.x = constant AND t.y = constant". (We do not want +to give up that behavior, either, since the latter condition could allow +use of an index on t.y, which we would never discover from the original +quals.) If these generated quals are assigned the same security_level as +the query quals, then it's possible for the leaky_function qual to be +evaluated first, allowing leaky_function to see data from rows that +possibly don't pass the barrier condition. + +Instead, our handling of security levels with ECs works like this: +* Quals are not accepted as source clauses for ECs in the first place +unless they are leakproof or have security_level zero. +* EC-derived quals are assigned the minimum (not maximum) security_level +found among the EC's source clauses. +* If the maximum security_level found among the EC's source clauses is +above zero, then the equality operators selected for derived quals must +be leakproof. When no such operator can be found, the EC is treated as +"broken" and we fall back to emitting its source clauses without any +additional derived quals. + +These rules together ensure that an untrusted qual clause (one with +security_level above zero) cannot cause an EC to generate a leaky derived +clause. This makes it safe to use the minimum not maximum security_level +for derived clauses. The rules could result in poor plans due to not +being able to generate derived clauses at all, but the risk of that is +small in practice because most btree equality operators are leakproof. +Also, by making exceptions for level-zero quals, we ensure that there is +no plan degradation when no barrier quals are present. + +Once we have security levels assigned to all clauses, enforcement +of barrier-qual ordering restrictions boils down to two rules: + +* Table scan plan nodes must not select quals for early execution +(for example, use them as index qualifiers in an indexscan) unless +they are leakproof or have security_level no higher than any other +qual that is due to be executed at the same plan node. (Use the +utility function restriction_is_securely_promotable() to check +whether it's okay to select a qual for early execution.) + +* Normal execution of a list of quals must execute them in an order +that satisfies the same security rule, ie higher security_levels must +be evaluated later unless leakproof. (This is handled in a single place +by order_qual_clauses() in createplan.c.) + +order_qual_clauses() uses a heuristic to decide exactly what to do with +leakproof clauses. Normally it sorts clauses by security_level then cost, +being careful that the sort is stable so that we don't reorder clauses +without a clear reason. But this could result in a very expensive qual +being done before a cheaper one that is of higher security_level. +If the cheaper qual is leaky we have no choice, but if it is leakproof +we could put it first. We choose to sort leakproof quals as if they +have security_level zero, but only when their cost is less than 10X +cpu_operator_cost; that restriction alleviates the opposite problem of +doing expensive quals first just because they're leakproof. + +Additional rules will be needed to support safe handling of join quals +when there is a mix of security levels among join quals; for example, it +will be necessary to prevent leaky higher-security-level quals from being +evaluated at a lower join level than other quals of lower security level. +Currently there is no need to consider that since security-prioritized +quals can only be single-table restriction quals coming from RLS policies +or security-barrier views, and security-barrier view subqueries are never +flattened into the parent query. Hence enforcement of security-prioritized +quals only happens at the table scan level. With extra rules for safe +handling of security levels among join quals, it should be possible to let +security-barrier views be flattened into the parent query, allowing more +flexibility of planning while still preserving required ordering of qual +evaluation. But that will come later. + + Post scan/join planning ----------------------- diff --git a/src/backend/optimizer/geqo/geqo_copy.c b/src/backend/optimizer/geqo/geqo_copy.c index 475d221dd2..8fd20c5986 100644 --- a/src/backend/optimizer/geqo/geqo_copy.c +++ b/src/backend/optimizer/geqo/geqo_copy.c @@ -2,7 +2,7 @@ * * geqo_copy.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/optimizer/geqo/geqo_copy.c diff --git a/src/backend/optimizer/geqo/geqo_eval.c b/src/backend/optimizer/geqo/geqo_eval.c index 88acebc1f2..b5cab0c351 100644 --- a/src/backend/optimizer/geqo/geqo_eval.c +++ b/src/backend/optimizer/geqo/geqo_eval.c @@ -3,7 +3,7 @@ * geqo_eval.c * Routines to evaluate query trees * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/optimizer/geqo/geqo_eval.c @@ -74,9 +74,7 @@ geqo_eval(PlannerInfo *root, Gene *tour, int num_gene) */ mycontext = AllocSetContextCreate(CurrentMemoryContext, "GEQO", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldcxt = MemoryContextSwitchTo(mycontext); /* diff --git a/src/backend/optimizer/geqo/geqo_main.c b/src/backend/optimizer/geqo/geqo_main.c index 73fc38b907..52bd428187 100644 --- a/src/backend/optimizer/geqo/geqo_main.c +++ b/src/backend/optimizer/geqo/geqo_main.c @@ -4,7 +4,7 @@ * solution to the query optimization problem * by means of a Genetic Algorithm (GA) * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/optimizer/geqo/geqo_main.c diff --git a/src/backend/optimizer/geqo/geqo_misc.c b/src/backend/optimizer/geqo/geqo_misc.c index b1d99cc0b1..503a19f6d6 100644 --- a/src/backend/optimizer/geqo/geqo_misc.c +++ b/src/backend/optimizer/geqo/geqo_misc.c @@ -3,7 +3,7 @@ * geqo_misc.c * misc. printout and debug stuff * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/optimizer/geqo/geqo_misc.c diff --git a/src/backend/optimizer/geqo/geqo_pool.c b/src/backend/optimizer/geqo/geqo_pool.c index 727c356032..0f7a26c9a1 100644 --- a/src/backend/optimizer/geqo/geqo_pool.c +++ b/src/backend/optimizer/geqo/geqo_pool.c @@ -3,7 +3,7 @@ * geqo_pool.c * Genetic Algorithm (GA) pool stuff * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/optimizer/geqo/geqo_pool.c diff --git a/src/backend/optimizer/geqo/geqo_random.c b/src/backend/optimizer/geqo/geqo_random.c index 2368b8fa96..6f3500649c 100644 --- a/src/backend/optimizer/geqo/geqo_random.c +++ b/src/backend/optimizer/geqo/geqo_random.c @@ -3,7 +3,7 @@ * geqo_random.c * random number generator * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/optimizer/geqo/geqo_random.c diff --git a/src/backend/optimizer/geqo/geqo_selection.c b/src/backend/optimizer/geqo/geqo_selection.c index 991b2e36f9..4d0f6b0881 100644 --- a/src/backend/optimizer/geqo/geqo_selection.c +++ b/src/backend/optimizer/geqo/geqo_selection.c @@ -3,7 +3,7 @@ * geqo_selection.c * linear selection scheme for the genetic query optimizer * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/optimizer/geqo/geqo_selection.c diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 88d833a2e8..5c189874ef 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -3,7 +3,7 @@ * allpaths.c * Routines to find possible search paths for processing a query * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -78,7 +78,6 @@ static void set_plain_rel_size(PlannerInfo *root, RelOptInfo *rel, static void create_plain_partial_paths(PlannerInfo *root, RelOptInfo *rel); static void set_rel_consider_parallel(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte); -static bool function_rte_parallel_ok(RangeTblEntry *rte); static void set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte); static void set_tablesample_rel_size(PlannerInfo *root, RelOptInfo *rel, @@ -127,6 +126,7 @@ static void subquery_push_qual(Query *subquery, static void recurse_push_qual(Node *setOp, Query *topquery, RangeTblEntry *rte, Index rti, Node *qual); static void remove_unused_subquery_outputs(Query *subquery, RelOptInfo *rel); +static int compute_parallel_worker(RelOptInfo *rel, BlockNumber pages); /* @@ -538,12 +538,11 @@ set_rel_consider_parallel(PlannerInfo *root, RelOptInfo *rel, */ if (rte->tablesample != NULL) { - Oid proparallel = func_parallel(rte->tablesample->tsmhandler); + char proparallel = func_parallel(rte->tablesample->tsmhandler); if (proparallel != PROPARALLEL_SAFE) return; - if (has_parallel_hazard((Node *) rte->tablesample->args, - false)) + if (!is_parallel_safe(root, (Node *) rte->tablesample->args)) return; } @@ -596,16 +595,14 @@ set_rel_consider_parallel(PlannerInfo *root, RelOptInfo *rel, case RTE_FUNCTION: /* Check for parallel-restricted functions. */ - if (!function_rte_parallel_ok(rte)) + if (!is_parallel_safe(root, (Node *) rte->functions)) return; break; case RTE_VALUES: - - /* - * The data for a VALUES clause is stored in the plan tree itself, - * so scanning it in a worker is fine. - */ + /* Check for parallel-restricted functions. */ + if (!is_parallel_safe(root, (Node *) rte->values_lists)) + return; break; case RTE_CTE: @@ -629,40 +626,20 @@ set_rel_consider_parallel(PlannerInfo *root, RelOptInfo *rel, * outer join clauses work correctly. It would likely break equivalence * classes, too. */ - if (has_parallel_hazard((Node *) rel->baserestrictinfo, false)) + if (!is_parallel_safe(root, (Node *) rel->baserestrictinfo)) return; /* * Likewise, if the relation's outputs are not parallel-safe, give up. * (Usually, they're just Vars, but sometimes they're not.) */ - if (has_parallel_hazard((Node *) rel->reltarget->exprs, false)) + if (!is_parallel_safe(root, (Node *) rel->reltarget->exprs)) return; /* We have a winner. */ rel->consider_parallel = true; } -/* - * Check whether a function RTE is scanning something parallel-restricted. - */ -static bool -function_rte_parallel_ok(RangeTblEntry *rte) -{ - ListCell *lc; - - foreach(lc, rte->functions) - { - RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc); - - Assert(IsA(rtfunc, RangeTblFunction)); - if (has_parallel_hazard(rtfunc->funcexpr, false)) - return false; - } - - return true; -} - /* * set_plain_rel_pathlist * Build access paths for a plain relation (no subquery, no inheritance) @@ -702,49 +679,7 @@ create_plain_partial_paths(PlannerInfo *root, RelOptInfo *rel) { int parallel_workers; - /* - * If the user has set the parallel_workers reloption, use that; otherwise - * select a default number of workers. - */ - if (rel->rel_parallel_workers != -1) - parallel_workers = rel->rel_parallel_workers; - else - { - int parallel_threshold; - - /* - * If this relation is too small to be worth a parallel scan, just - * return without doing anything ... unless it's an inheritance child. - * In that case, we want to generate a parallel path here anyway. It - * might not be worthwhile just for this relation, but when combined - * with all of its inheritance siblings it may well pay off. - */ - if (rel->pages < (BlockNumber) min_parallel_relation_size && - rel->reloptkind == RELOPT_BASEREL) - return; - - /* - * Select the number of workers based on the log of the size of the - * relation. This probably needs to be a good deal more - * sophisticated, but we need something here for now. Note that the - * upper limit of the min_parallel_relation_size GUC is chosen to - * prevent overflow here. - */ - parallel_workers = 1; - parallel_threshold = Max(min_parallel_relation_size, 1); - while (rel->pages >= (BlockNumber) (parallel_threshold * 3)) - { - parallel_workers++; - parallel_threshold *= 3; - if (parallel_threshold > INT_MAX / 3) - break; /* avoid overflow */ - } - } - - /* - * In no case use more than max_parallel_workers_per_gather workers. - */ - parallel_workers = Min(parallel_workers, max_parallel_workers_per_gather); + parallel_workers = compute_parallel_worker(rel, rel->pages); /* If any limit was set to zero, the user doesn't want a parallel scan. */ if (parallel_workers <= 0) @@ -920,9 +855,11 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *childRTE; RelOptInfo *childrel; List *childquals; - Node *childqual; + Index cq_min_security; + bool have_const_false_cq; ListCell *parentvars; ListCell *childvars; + ListCell *lc; /* append_rel_list contains all append rels; ignore others */ if (appinfo->parent_relid != parentRTindex) @@ -945,34 +882,120 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel, * constraint exclusion; so do that first and then check to see if we * can disregard this child. * - * As of 8.4, the child rel's targetlist might contain non-Var - * expressions, which means that substitution into the quals could - * produce opportunities for const-simplification, and perhaps even - * pseudoconstant quals. To deal with this, we strip the RestrictInfo - * nodes, do the substitution, do const-simplification, and then - * reconstitute the RestrictInfo layer. + * The child rel's targetlist might contain non-Var expressions, which + * means that substitution into the quals could produce opportunities + * for const-simplification, and perhaps even pseudoconstant quals. + * Therefore, transform each RestrictInfo separately to see if it + * reduces to a constant or pseudoconstant. (We must process them + * separately to keep track of the security level of each qual.) */ - childquals = get_all_actual_clauses(rel->baserestrictinfo); - childquals = (List *) adjust_appendrel_attrs(root, - (Node *) childquals, - appinfo); - childqual = eval_const_expressions(root, (Node *) - make_ands_explicit(childquals)); - if (childqual && IsA(childqual, Const) && - (((Const *) childqual)->constisnull || - !DatumGetBool(((Const *) childqual)->constvalue))) + childquals = NIL; + cq_min_security = UINT_MAX; + have_const_false_cq = false; + foreach(lc, rel->baserestrictinfo) + { + RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc); + Node *childqual; + ListCell *lc2; + + Assert(IsA(rinfo, RestrictInfo)); + childqual = adjust_appendrel_attrs(root, + (Node *) rinfo->clause, + appinfo); + childqual = eval_const_expressions(root, childqual); + /* check for flat-out constant */ + if (childqual && IsA(childqual, Const)) + { + if (((Const *) childqual)->constisnull || + !DatumGetBool(((Const *) childqual)->constvalue)) + { + /* Restriction reduces to constant FALSE or NULL */ + have_const_false_cq = true; + break; + } + /* Restriction reduces to constant TRUE, so drop it */ + continue; + } + /* might have gotten an AND clause, if so flatten it */ + foreach(lc2, make_ands_implicit((Expr *) childqual)) + { + Node *onecq = (Node *) lfirst(lc2); + bool pseudoconstant; + + /* check for pseudoconstant (no Vars or volatile functions) */ + pseudoconstant = + !contain_vars_of_level(onecq, 0) && + !contain_volatile_functions(onecq); + if (pseudoconstant) + { + /* tell createplan.c to check for gating quals */ + root->hasPseudoConstantQuals = true; + } + /* reconstitute RestrictInfo with appropriate properties */ + childquals = lappend(childquals, + make_restrictinfo((Expr *) onecq, + rinfo->is_pushed_down, + rinfo->outerjoin_delayed, + pseudoconstant, + rinfo->security_level, + NULL, NULL, NULL)); + /* track minimum security level among child quals */ + cq_min_security = Min(cq_min_security, rinfo->security_level); + } + } + + /* + * In addition to the quals inherited from the parent, we might have + * securityQuals associated with this particular child node. + * (Currently this can only happen in appendrels originating from + * UNION ALL; inheritance child tables don't have their own + * securityQuals, see expand_inherited_rtentry().) Pull any such + * securityQuals up into the baserestrictinfo for the child. This is + * similar to process_security_barrier_quals() for the parent rel, + * except that we can't make any general deductions from such quals, + * since they don't hold for the whole appendrel. + */ + if (childRTE->securityQuals) + { + Index security_level = 0; + + foreach(lc, childRTE->securityQuals) + { + List *qualset = (List *) lfirst(lc); + ListCell *lc2; + + foreach(lc2, qualset) + { + Expr *qual = (Expr *) lfirst(lc2); + + /* not likely that we'd see constants here, so no check */ + childquals = lappend(childquals, + make_restrictinfo(qual, + true, false, false, + security_level, + NULL, NULL, NULL)); + cq_min_security = Min(cq_min_security, security_level); + } + security_level++; + } + Assert(security_level <= root->qual_security_level); + } + + /* + * OK, we've got all the baserestrictinfo quals for this child. + */ + childrel->baserestrictinfo = childquals; + childrel->baserestrict_min_security = cq_min_security; + + if (have_const_false_cq) { /* - * Restriction reduces to constant FALSE or constant NULL after + * Some restriction clause reduced to constant FALSE or NULL after * substitution, so this child need not be scanned. */ set_dummy_rel_pathlist(childrel); continue; } - childquals = make_ands_implicit((Expr *) childqual); - childquals = make_restrictinfos_from_actual_clauses(root, - childquals); - childrel->baserestrictinfo = childquals; if (relation_excluded_by_constraints(root, childrel, childRTE)) { @@ -1736,6 +1759,7 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel, } } rel->baserestrictinfo = upperrestrictlist; + /* We don't bother recomputing baserestrict_min_security */ } pfree(safetyInfo.unsafeColumns); @@ -2278,6 +2302,12 @@ standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels) * thereby changing the partition contents and thus the window functions' * results for rows that remain. * + * 5. If the subquery contains any set-returning functions in its targetlist, + * we cannot push volatile quals into it. That would push them below the SRFs + * and thereby change the number of times they are evaluated. Also, a + * volatile qual could succeed for some SRF output rows and fail for others, + * a behavior that cannot occur if it's evaluated before SRF expansion. + * * In addition, we make several checks on the subquery's output columns to see * if it is safe to reference them in pushed-down quals. If output column k * is found to be unsafe to reference, we set safetyInfo->unsafeColumns[k] @@ -2322,8 +2352,10 @@ subquery_is_pushdown_safe(Query *subquery, Query *topquery, if (subquery->limitOffset != NULL || subquery->limitCount != NULL) return false; - /* Check points 3 and 4 */ - if (subquery->distinctClause || subquery->hasWindowFuncs) + /* Check points 3, 4, and 5 */ + if (subquery->distinctClause || + subquery->hasWindowFuncs || + subquery->hasTargetSRFs) safetyInfo->unsafeVolatile = true; /* @@ -2446,7 +2478,8 @@ check_output_expressions(Query *subquery, pushdown_safety_info *safetyInfo) continue; /* Functions returning sets are unsafe (point 1) */ - if (expression_returns_set((Node *) tle->expr)) + if (subquery->hasTargetSRFs && + expression_returns_set((Node *) tle->expr)) { safetyInfo->unsafeColumns[tle->resno] = true; continue; @@ -2655,46 +2688,6 @@ subquery_push_qual(Query *subquery, RangeTblEntry *rte, Index rti, Node *qual) recurse_push_qual(subquery->setOperations, subquery, rte, rti, qual); } - else if (IsA(qual, CurrentOfExpr)) - { - /* - * This is possible when a WHERE CURRENT OF expression is applied to a - * table with row-level security. In that case, the subquery should - * contain precisely one rtable entry for the table, and we can safely - * push the expression down into the subquery. This will cause a TID - * scan subquery plan to be generated allowing the target relation to - * be updated. - * - * Someday we might also be able to use a WHERE CURRENT OF expression - * on a view, but currently the rewriter prevents that, so we should - * never see any other case here, but generate sane error messages in - * case it does somehow happen. - */ - if (subquery->rtable == NIL) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("WHERE CURRENT OF is not supported on a view with no underlying relation"))); - - if (list_length(subquery->rtable) > 1) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("WHERE CURRENT OF is not supported on a view with more than one underlying relation"))); - - if (subquery->hasAggs || subquery->groupClause || subquery->groupingSets || subquery->havingQual) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("WHERE CURRENT OF is not supported on a view with grouping or aggregation"))); - - /* - * Adjust the CURRENT OF expression to refer to the underlying table - * in the subquery, and attach it to the subquery's WHERE clause. - */ - qual = copyObject(qual); - ((CurrentOfExpr *) qual)->cvarno = 1; - - subquery->jointree->quals = - make_and_qual(subquery->jointree->quals, qual); - } else { /* @@ -2723,7 +2716,7 @@ subquery_push_qual(Query *subquery, RangeTblEntry *rte, Index rti, Node *qual) make_and_qual(subquery->jointree->quals, qual); /* - * We need not change the subquery's hasAggs or hasSublinks flags, + * We need not change the subquery's hasAggs or hasSubLinks flags, * since we can't be pushing down any aggregates that weren't there * before, and we don't push down subselects at all. */ @@ -2859,7 +2852,8 @@ remove_unused_subquery_outputs(Query *subquery, RelOptInfo *rel) * If it contains a set-returning function, we can't remove it since * that could change the number of rows returned by the subquery. */ - if (expression_returns_set(texpr)) + if (subquery->hasTargetSRFs && + expression_returns_set(texpr)) continue; /* @@ -2880,6 +2874,64 @@ remove_unused_subquery_outputs(Query *subquery, RelOptInfo *rel) } } +/* + * Compute the number of parallel workers that should be used to scan a + * relation. "pages" is the number of pages from the relation that we + * expect to scan. + */ +static int +compute_parallel_worker(RelOptInfo *rel, BlockNumber pages) +{ + int parallel_workers; + + /* + * If the user has set the parallel_workers reloption, use that; otherwise + * select a default number of workers. + */ + if (rel->rel_parallel_workers != -1) + parallel_workers = rel->rel_parallel_workers; + else + { + int parallel_threshold; + + /* + * If this relation is too small to be worth a parallel scan, just + * return without doing anything ... unless it's an inheritance child. + * In that case, we want to generate a parallel path here anyway. It + * might not be worthwhile just for this relation, but when combined + * with all of its inheritance siblings it may well pay off. + */ + if (pages < (BlockNumber) min_parallel_relation_size && + rel->reloptkind == RELOPT_BASEREL) + return 0; + + /* + * Select the number of workers based on the log of the size of the + * relation. This probably needs to be a good deal more + * sophisticated, but we need something here for now. Note that the + * upper limit of the min_parallel_relation_size GUC is chosen to + * prevent overflow here. + */ + parallel_workers = 1; + parallel_threshold = Max(min_parallel_relation_size, 1); + while (pages >= (BlockNumber) (parallel_threshold * 3)) + { + parallel_workers++; + parallel_threshold *= 3; + if (parallel_threshold > INT_MAX / 3) + break; /* avoid overflow */ + } + } + + /* + * In no case use more than max_parallel_workers_per_gather workers. + */ + parallel_workers = Min(parallel_workers, max_parallel_workers_per_gather); + + return parallel_workers; +} + + /***************************************************************************** * DEBUG SUPPORT *****************************************************************************/ @@ -3006,6 +3058,10 @@ print_path(PlannerInfo *root, Path *path, int indent) ptype = "Projection"; subpath = ((ProjectionPath *) path)->subpath; break; + case T_ProjectSetPath: + ptype = "ProjectSet"; + subpath = ((ProjectSetPath *) path)->subpath; + break; case T_SortPath: ptype = "Sort"; subpath = ((SortPath *) path)->subpath; diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c index 02660c2ba5..af2934a721 100644 --- a/src/backend/optimizer/path/clausesel.c +++ b/src/backend/optimizer/path/clausesel.c @@ -3,7 +3,7 @@ * clausesel.c * Routines to compute clause selectivities * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 2a49639f12..458f139d7c 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -60,7 +60,7 @@ * values. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -161,6 +161,7 @@ static Selectivity get_foreign_key_join_selectivity(PlannerInfo *root, static void set_rel_width(PlannerInfo *root, RelOptInfo *rel); static double relation_byte_size(double tuples, int width); static double page_size(double tuples, int width); +static double get_parallel_divisor(Path *path); /* @@ -238,32 +239,7 @@ cost_seqscan(Path *path, PlannerInfo *root, /* Adjust costing for parallelism, if used. */ if (path->parallel_workers > 0) { - double parallel_divisor = path->parallel_workers; - double leader_contribution; - - /* - * Early experience with parallel query suggests that when there is - * only one worker, the leader often makes a very substantial - * contribution to executing the parallel portion of the plan, but as - * more workers are added, it does less and less, because it's busy - * reading tuples from the workers and doing whatever non-parallel - * post-processing is needed. By the time we reach 4 workers, the - * leader no longer makes a meaningful contribution. Thus, for now, - * estimate that the leader spends 30% of its time servicing each - * worker, and the remainder executing the parallel plan. - */ - leader_contribution = 1.0 - (0.3 * path->parallel_workers); - if (leader_contribution > 0) - parallel_divisor += leader_contribution; - - /* - * In the case of a parallel plan, the row count needs to represent - * the number of tuples processed per worker. Otherwise, higher-level - * plan nodes that appear below the gather will be costed incorrectly, - * because they'll anticipate receiving more rows than any given copy - * will actually get. - */ - path->rows = clamp_row_est(path->rows / parallel_divisor); + double parallel_divisor = get_parallel_divisor(path); /* The CPU cost is divided among all the workers. */ cpu_run_cost /= parallel_divisor; @@ -274,6 +250,12 @@ cost_seqscan(Path *path, PlannerInfo *root, * prefetching. For now, we assume that the disk run cost can't be * amortized at all. */ + + /* + * In the case of a parallel plan, the row count needs to represent + * the number of tuples processed per worker. + */ + path->rows = clamp_row_est(path->rows / parallel_divisor); } path->startup_cost = startup_cost; @@ -1577,8 +1559,7 @@ cost_sort(Path *path, PlannerInfo *root, * at any given instant holds the next tuple from each stream. If there * are N streams, we need about N*log2(N) tuple comparisons to construct * the heap at startup, and then for each output tuple, about log2(N) - * comparisons to delete the top heap entry and another log2(N) comparisons - * to insert its successor from the same stream. + * comparisons to replace the top entry. * * (The effective value of N will drop once some of the input streams are * exhausted, but it seems unlikely to be worth trying to account for that.) @@ -1619,7 +1600,7 @@ cost_merge_append(Path *path, PlannerInfo *root, startup_cost += comparison_cost * N * logN; /* Per-tuple heap maintenance cost */ - run_cost += tuples * comparison_cost * 2.0 * logN; + run_cost += tuples * comparison_cost * logN; /* * Also charge a small amount (arbitrarily set equal to operator cost) per @@ -2014,6 +1995,10 @@ final_cost_nestloop(PlannerInfo *root, NestPath *path, else path->path.rows = path->path.parent->rows; + /* For partial paths, scale row estimate. */ + if (path->path.parallel_workers > 0) + path->path.rows /= get_parallel_divisor(&path->path); + /* * We could include disable_cost in the preliminary estimate, but that * would amount to optimizing for the case where the join method is @@ -2432,6 +2417,10 @@ final_cost_mergejoin(PlannerInfo *root, MergePath *path, else path->jpath.path.rows = path->jpath.path.parent->rows; + /* For partial paths, scale row estimate. */ + if (path->jpath.path.parallel_workers > 0) + path->jpath.path.rows /= get_parallel_divisor(&path->jpath.path); + /* * We could include disable_cost in the preliminary estimate, but that * would amount to optimizing for the case where the join method is @@ -2811,6 +2800,10 @@ final_cost_hashjoin(PlannerInfo *root, HashPath *path, else path->jpath.path.rows = path->jpath.path.parent->rows; + /* For partial paths, scale row estimate. */ + if (path->jpath.path.parallel_workers > 0) + path->jpath.path.rows /= get_parallel_divisor(&path->jpath.path); + /* * We could include disable_cost in the preliminary estimate, but that * would amount to optimizing for the case where the join method is @@ -4086,6 +4079,7 @@ get_foreign_key_join_selectivity(PlannerInfo *root, { ForeignKeyOptInfo *fkinfo = (ForeignKeyOptInfo *) lfirst(lc); bool ref_is_outer; + bool use_smallest_selectivity = false; List *removedlist; ListCell *cell; ListCell *prev; @@ -4206,9 +4200,9 @@ get_foreign_key_join_selectivity(PlannerInfo *root, * be double-counting the null fraction, and (2) it's not very clear * how to combine null fractions for multiple referencing columns. * - * In the first branch of the logic below, null derating is done - * implicitly by relying on clause_selectivity(); in the other two - * paths, we do nothing for now about correcting for nulls. + * In the use_smallest_selectivity code below, null derating is done + * implicitly by relying on clause_selectivity(); in the other cases, + * we do nothing for now about correcting for nulls. * * XXX another point here is that if either side of an FK constraint * is an inheritance parent, we estimate as though the constraint @@ -4231,28 +4225,41 @@ get_foreign_key_join_selectivity(PlannerInfo *root, * the smallest per-column selectivity, instead. (This should * correspond to the FK column with the most nulls.) */ - Selectivity thisfksel = 1.0; - - foreach(cell, removedlist) - { - RestrictInfo *rinfo = (RestrictInfo *) lfirst(cell); - Selectivity csel; - - csel = clause_selectivity(root, (Node *) rinfo, - 0, jointype, sjinfo); - thisfksel = Min(thisfksel, csel); - } - fkselec *= thisfksel; + use_smallest_selectivity = true; } else if (jointype == JOIN_SEMI || jointype == JOIN_ANTI) { /* * For JOIN_SEMI and JOIN_ANTI, the selectivity is defined as the - * fraction of LHS rows that have matches. If the referenced - * table is on the inner side, that means the selectivity is 1.0 - * (modulo nulls, which we're ignoring for now). We already - * covered the other case, so no work here. + * fraction of LHS rows that have matches. The referenced table + * is on the inner side (we already handled the other case above), + * so the FK implies that every LHS row has a match *in the + * referenced table*. But any restriction or join clauses below + * here will reduce the number of matches. */ + if (bms_membership(inner_relids) == BMS_SINGLETON) + { + /* + * When the inner side of the semi/anti join is just the + * referenced table, we may take the FK selectivity as equal + * to the selectivity of the table's restriction clauses. + */ + RelOptInfo *ref_rel = find_base_rel(root, fkinfo->ref_relid); + double ref_tuples = Max(ref_rel->tuples, 1.0); + + fkselec *= ref_rel->rows / ref_tuples; + } + else + { + /* + * When the inner side of the semi/anti join is itself a join, + * it's hard to guess what fraction of the referenced table + * will get through the join. But we still don't want to + * multiply per-column estimates together. Take the smallest + * per-column selectivity, instead. + */ + use_smallest_selectivity = true; + } } else { @@ -4266,6 +4273,26 @@ get_foreign_key_join_selectivity(PlannerInfo *root, fkselec *= 1.0 / ref_tuples; } + + /* + * Common code for cases where we should use the smallest selectivity + * that would be computed for any one of the FK's clauses. + */ + if (use_smallest_selectivity) + { + Selectivity thisfksel = 1.0; + + foreach(cell, removedlist) + { + RestrictInfo *rinfo = (RestrictInfo *) lfirst(cell); + Selectivity csel; + + csel = clause_selectivity(root, (Node *) rinfo, + 0, jointype, sjinfo); + thisfksel = Min(thisfksel, csel); + } + fkselec *= thisfksel; + } } *restrictlist = worklist; @@ -4765,3 +4792,31 @@ page_size(double tuples, int width) { return ceil(relation_byte_size(tuples, width) / BLCKSZ); } + +/* + * Estimate the fraction of the work that each worker will do given the + * number of workers budgeted for the path. + */ +static double +get_parallel_divisor(Path *path) +{ + double parallel_divisor = path->parallel_workers; + double leader_contribution; + + /* + * Early experience with parallel query suggests that when there is only + * one worker, the leader often makes a very substantial contribution to + * executing the parallel portion of the plan, but as more workers are + * added, it does less and less, because it's busy reading tuples from the + * workers and doing whatever non-parallel post-processing is needed. By + * the time we reach 4 workers, the leader no longer makes a meaningful + * contribution. Thus, for now, estimate that the leader spends 30% of + * its time servicing each worker, and the remainder executing the + * parallel plan. + */ + leader_contribution = 1.0 - (0.3 * path->parallel_workers); + if (leader_contribution > 0) + parallel_divisor += leader_contribution; + + return parallel_divisor; +} diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index 0e50ad5f34..a329dd1e10 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -6,7 +6,7 @@ * See src/backend/optimizer/README for discussion of EquivalenceClasses. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -16,6 +16,8 @@ */ #include "postgres.h" +#include + #include "access/stratnum.h" #include "catalog/pg_type.h" #include "nodes/makefuncs.h" @@ -78,9 +80,16 @@ static bool reconsider_full_join_clause(PlannerInfo *root, * care to mark an EquivalenceClass if it came from any such clauses. Also, * we have to check that both sides are either pseudo-constants or strict * functions of Vars, else they might not both go to NULL above the outer - * join. (This is the reason why we need a failure return. It's more + * join. (This is the main reason why we need a failure return. It's more * convenient to check this case here than at the call sites...) * + * We also reject proposed equivalence clauses if they contain leaky functions + * and have security_level above zero. The EC evaluation rules require us to + * apply certain tests at certain joining levels, and we can't tolerate + * delaying any test on security_level grounds. By rejecting candidate clauses + * that might require security delays, we ensure it's safe to apply an EC + * clause as soon as it's supposed to be applied. + * * On success return, we have also initialized the clause's left_ec/right_ec * fields to point to the EquivalenceClass representing it. This saves lookup * effort later. @@ -120,6 +129,10 @@ process_equivalence(PlannerInfo *root, RestrictInfo *restrictinfo, Assert(restrictinfo->left_ec == NULL); Assert(restrictinfo->right_ec == NULL); + /* Reject if it is potentially postponable by security considerations */ + if (restrictinfo->security_level > 0 && !restrictinfo->leakproof) + return false; + /* Extract info from given clause */ Assert(is_opclause(clause)); opno = ((OpExpr *) clause)->opno; @@ -275,6 +288,10 @@ process_equivalence(PlannerInfo *root, RestrictInfo *restrictinfo, { ec1->ec_sources = lappend(ec1->ec_sources, restrictinfo); ec1->ec_below_outer_join |= below_outer_join; + ec1->ec_min_security = Min(ec1->ec_min_security, + restrictinfo->security_level); + ec1->ec_max_security = Max(ec1->ec_max_security, + restrictinfo->security_level); /* mark the RI as associated with this eclass */ restrictinfo->left_ec = ec1; restrictinfo->right_ec = ec1; @@ -306,6 +323,10 @@ process_equivalence(PlannerInfo *root, RestrictInfo *restrictinfo, ec1->ec_has_const |= ec2->ec_has_const; /* can't need to set has_volatile */ ec1->ec_below_outer_join |= ec2->ec_below_outer_join; + ec1->ec_min_security = Min(ec1->ec_min_security, + ec2->ec_min_security); + ec1->ec_max_security = Max(ec1->ec_max_security, + ec2->ec_max_security); ec2->ec_merged = ec1; root->eq_classes = list_delete_ptr(root->eq_classes, ec2); /* just to avoid debugging confusion w/ dangling pointers: */ @@ -315,6 +336,10 @@ process_equivalence(PlannerInfo *root, RestrictInfo *restrictinfo, ec2->ec_relids = NULL; ec1->ec_sources = lappend(ec1->ec_sources, restrictinfo); ec1->ec_below_outer_join |= below_outer_join; + ec1->ec_min_security = Min(ec1->ec_min_security, + restrictinfo->security_level); + ec1->ec_max_security = Max(ec1->ec_max_security, + restrictinfo->security_level); /* mark the RI as associated with this eclass */ restrictinfo->left_ec = ec1; restrictinfo->right_ec = ec1; @@ -329,6 +354,10 @@ process_equivalence(PlannerInfo *root, RestrictInfo *restrictinfo, false, item2_type); ec1->ec_sources = lappend(ec1->ec_sources, restrictinfo); ec1->ec_below_outer_join |= below_outer_join; + ec1->ec_min_security = Min(ec1->ec_min_security, + restrictinfo->security_level); + ec1->ec_max_security = Max(ec1->ec_max_security, + restrictinfo->security_level); /* mark the RI as associated with this eclass */ restrictinfo->left_ec = ec1; restrictinfo->right_ec = ec1; @@ -343,6 +372,10 @@ process_equivalence(PlannerInfo *root, RestrictInfo *restrictinfo, false, item1_type); ec2->ec_sources = lappend(ec2->ec_sources, restrictinfo); ec2->ec_below_outer_join |= below_outer_join; + ec2->ec_min_security = Min(ec2->ec_min_security, + restrictinfo->security_level); + ec2->ec_max_security = Max(ec2->ec_max_security, + restrictinfo->security_level); /* mark the RI as associated with this eclass */ restrictinfo->left_ec = ec2; restrictinfo->right_ec = ec2; @@ -366,6 +399,8 @@ process_equivalence(PlannerInfo *root, RestrictInfo *restrictinfo, ec->ec_below_outer_join = below_outer_join; ec->ec_broken = false; ec->ec_sortref = 0; + ec->ec_min_security = restrictinfo->security_level; + ec->ec_max_security = restrictinfo->security_level; ec->ec_merged = NULL; em1 = add_eq_member(ec, item1, item1_relids, item1_nullable_relids, false, item1_type); @@ -639,6 +674,8 @@ get_eclass_for_sort_expr(PlannerInfo *root, newec->ec_below_outer_join = false; newec->ec_broken = false; newec->ec_sortref = sortref; + newec->ec_min_security = UINT_MAX; + newec->ec_max_security = 0; newec->ec_merged = NULL; if (newec->ec_has_volatile && sortref == 0) /* should not happen */ @@ -834,6 +871,7 @@ generate_base_implied_equalities_const(PlannerInfo *root, bms_copy(ec->ec_relids), bms_union(cur_em->em_nullable_relids, const_em->em_nullable_relids), + ec->ec_min_security, ec->ec_below_outer_join, cur_em->em_is_const); } @@ -890,6 +928,7 @@ generate_base_implied_equalities_no_const(PlannerInfo *root, bms_copy(ec->ec_relids), bms_union(prev_em->em_nullable_relids, cur_em->em_nullable_relids), + ec->ec_min_security, ec->ec_below_outer_join, false); } @@ -1313,7 +1352,13 @@ select_equality_operator(EquivalenceClass *ec, Oid lefttype, Oid righttype) opno = get_opfamily_member(opfamily, lefttype, righttype, BTEqualStrategyNumber); - if (OidIsValid(opno)) + if (!OidIsValid(opno)) + continue; + /* If no barrier quals in query, don't worry about leaky operators */ + if (ec->ec_max_security == 0) + return opno; + /* Otherwise, insist that selected operators be leakproof */ + if (get_func_leakproof(get_opcode(opno))) return opno; } return InvalidOid; @@ -1380,7 +1425,8 @@ create_join_clause(PlannerInfo *root, bms_union(leftem->em_relids, rightem->em_relids), bms_union(leftem->em_nullable_relids, - rightem->em_nullable_relids)); + rightem->em_nullable_relids), + ec->ec_min_security); /* Mark the clause as redundant, or not */ rinfo->parent_ec = parent_ec; @@ -1691,7 +1737,8 @@ reconsider_outer_join_clause(PlannerInfo *root, RestrictInfo *rinfo, innervar, cur_em->em_expr, bms_copy(inner_relids), - bms_copy(inner_nullable_relids)); + bms_copy(inner_nullable_relids), + cur_ec->ec_min_security); if (process_equivalence(root, newrinfo, true)) match = true; } @@ -1833,7 +1880,8 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo) leftvar, cur_em->em_expr, bms_copy(left_relids), - bms_copy(left_nullable_relids)); + bms_copy(left_nullable_relids), + cur_ec->ec_min_security); if (process_equivalence(root, newrinfo, true)) matchleft = true; } @@ -1847,7 +1895,8 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo) rightvar, cur_em->em_expr, bms_copy(right_relids), - bms_copy(right_nullable_relids)); + bms_copy(right_nullable_relids), + cur_ec->ec_min_security); if (process_equivalence(root, newrinfo, true)) matchright = true; } diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 2952bfb7c2..5283468988 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -4,7 +4,7 @@ * Routines to determine which indexes are usable for scanning a * given relation, and create Paths accordingly. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -2143,6 +2143,23 @@ match_clause_to_index(IndexOptInfo *index, { int indexcol; + /* + * Never match pseudoconstants to indexes. (Normally a match could not + * happen anyway, since a pseudoconstant clause couldn't contain a Var, + * but what if someone builds an expression index on a constant? It's not + * totally unreasonable to do so with a partial index, either.) + */ + if (rinfo->pseudoconstant) + return; + + /* + * If clause can't be used as an indexqual because it must wait till after + * some lower-security-level restriction clause, reject it. + */ + if (!restriction_is_securely_promotable(rinfo, index->rel)) + return; + + /* OK, check each index column for a match */ for (indexcol = 0; indexcol < index->ncolumns; indexcol++) { if (match_clause_to_indexcol(index, @@ -2237,15 +2254,6 @@ match_clause_to_indexcol(IndexOptInfo *index, Oid expr_coll; bool plain_op; - /* - * Never match pseudoconstants to indexes. (Normally this could not - * happen anyway, since a pseudoconstant clause couldn't contain a Var, - * but what if someone builds an expression index on a constant? It's not - * totally unreasonable to do so with a partial index, either.) - */ - if (rinfo->pseudoconstant) - return false; - /* First check for boolean-index cases. */ if (IsBooleanOpfamily(opfamily)) { @@ -3025,6 +3033,52 @@ relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel, return false; } +/* + * indexcol_is_bool_constant_for_query + * + * If an index column is constrained to have a constant value by the query's + * WHERE conditions, then it's irrelevant for sort-order considerations. + * Usually that means we have a restriction clause WHERE indexcol = constant, + * which gets turned into an EquivalenceClass containing a constant, which + * is recognized as redundant by build_index_pathkeys(). But if the index + * column is a boolean variable (or expression), then we are not going to + * see WHERE indexcol = constant, because expression preprocessing will have + * simplified that to "WHERE indexcol" or "WHERE NOT indexcol". So we are not + * going to have a matching EquivalenceClass (unless the query also contains + * "ORDER BY indexcol"). To allow such cases to work the same as they would + * for non-boolean values, this function is provided to detect whether the + * specified index column matches a boolean restriction clause. + */ +bool +indexcol_is_bool_constant_for_query(IndexOptInfo *index, int indexcol) +{ + ListCell *lc; + + /* If the index isn't boolean, we can't possibly get a match */ + if (!IsBooleanOpfamily(index->opfamily[indexcol])) + return false; + + /* Check each restriction clause for the index's rel */ + foreach(lc, index->rel->baserestrictinfo) + { + RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc); + + /* + * As in match_clause_to_indexcol, never match pseudoconstants to + * indexes. (It might be semantically okay to do so here, but the + * odds of getting a match are negligible, so don't waste the cycles.) + */ + if (rinfo->pseudoconstant) + continue; + + /* See if we can match the clause's expression to the index column */ + if (match_boolean_index_clause((Node *) rinfo->clause, indexcol, index)) + return true; + } + + return false; +} + /**************************************************************************** * ---- ROUTINES TO CHECK OPERANDS ---- diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index cc7384f7e5..7c30ec6fb9 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -3,7 +3,7 @@ * joinpath.c * Routines to find all possible paths for processing a set of joins * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -50,6 +50,15 @@ static List *select_mergejoin_clauses(PlannerInfo *root, List *restrictlist, JoinType jointype, bool *mergejoin_allowed); +static void generate_mergejoin_paths(PlannerInfo *root, + RelOptInfo *joinrel, + RelOptInfo *innerrel, + Path *outerpath, + JoinType jointype, + JoinPathExtraData *extra, + bool useallclauses, + Path *inner_cheapest_total, + List *merge_pathkeys); /* @@ -131,7 +140,7 @@ add_paths_to_joinrel(PlannerInfo *root, */ foreach(lc, root->join_info_list) { - SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc); + SpecialJoinInfo *sjinfo2 = (SpecialJoinInfo *) lfirst(lc); /* * SJ is relevant to this join if we have some part of its RHS @@ -140,19 +149,19 @@ add_paths_to_joinrel(PlannerInfo *root, * join has already been proven legal.) If the SJ is relevant, it * presents constraints for joining to anything not in its RHS. */ - if (bms_overlap(joinrel->relids, sjinfo->min_righthand) && - !bms_overlap(joinrel->relids, sjinfo->min_lefthand)) + if (bms_overlap(joinrel->relids, sjinfo2->min_righthand) && + !bms_overlap(joinrel->relids, sjinfo2->min_lefthand)) extra.param_source_rels = bms_join(extra.param_source_rels, bms_difference(root->all_baserels, - sjinfo->min_righthand)); + sjinfo2->min_righthand)); /* full joins constrain both sides symmetrically */ - if (sjinfo->jointype == JOIN_FULL && - bms_overlap(joinrel->relids, sjinfo->min_lefthand) && - !bms_overlap(joinrel->relids, sjinfo->min_righthand)) + if (sjinfo2->jointype == JOIN_FULL && + bms_overlap(joinrel->relids, sjinfo2->min_lefthand) && + !bms_overlap(joinrel->relids, sjinfo2->min_righthand)) extra.param_source_rels = bms_join(extra.param_source_rels, bms_difference(root->all_baserels, - sjinfo->min_lefthand)); + sjinfo2->min_lefthand)); } /* @@ -776,6 +785,241 @@ sort_inner_and_outer(PlannerInfo *root, } } +/* + * generate_mergejoin_paths + * Creates possible mergejoin paths for input outerpath. + * + * We generate mergejoins if mergejoin clauses are available. We have + * two ways to generate the inner path for a mergejoin: sort the cheapest + * inner path, or use an inner path that is already suitably ordered for the + * merge. If we have several mergeclauses, it could be that there is no inner + * path (or only a very expensive one) for the full list of mergeclauses, but + * better paths exist if we truncate the mergeclause list (thereby discarding + * some sort key requirements). So, we consider truncations of the + * mergeclause list as well as the full list. (Ideally we'd consider all + * subsets of the mergeclause list, but that seems way too expensive.) + */ +static void +generate_mergejoin_paths(PlannerInfo *root, + RelOptInfo *joinrel, + RelOptInfo *innerrel, + Path *outerpath, + JoinType jointype, + JoinPathExtraData *extra, + bool useallclauses, + Path *inner_cheapest_total, + List *merge_pathkeys) +{ + List *mergeclauses; + List *innersortkeys; + List *trialsortkeys; + Path *cheapest_startup_inner; + Path *cheapest_total_inner; + JoinType save_jointype = jointype; + int num_sortkeys; + int sortkeycnt; + + if (jointype == JOIN_UNIQUE_OUTER || jointype == JOIN_UNIQUE_INNER) + jointype = JOIN_INNER; + + /* Look for useful mergeclauses (if any) */ + mergeclauses = find_mergeclauses_for_pathkeys(root, + outerpath->pathkeys, + true, + extra->mergeclause_list); + + /* + * Done with this outer path if no chance for a mergejoin. + * + * Special corner case: for "x FULL JOIN y ON true", there will be no join + * clauses at all. Ordinarily we'd generate a clauseless nestloop path, + * but since mergejoin is our only join type that supports FULL JOIN + * without any join clauses, it's necessary to generate a clauseless + * mergejoin path instead. + */ + if (mergeclauses == NIL) + { + if (jointype == JOIN_FULL) + /* okay to try for mergejoin */ ; + else + return; + } + if (useallclauses && + list_length(mergeclauses) != list_length(extra->mergeclause_list)) + return; + + /* Compute the required ordering of the inner path */ + innersortkeys = make_inner_pathkeys_for_merge(root, + mergeclauses, + outerpath->pathkeys); + + /* + * Generate a mergejoin on the basis of sorting the cheapest inner. Since + * a sort will be needed, only cheapest total cost matters. (But + * try_mergejoin_path will do the right thing if inner_cheapest_total is + * already correctly sorted.) + */ + try_mergejoin_path(root, + joinrel, + outerpath, + inner_cheapest_total, + merge_pathkeys, + mergeclauses, + NIL, + innersortkeys, + jointype, + extra); + + /* Can't do anything else if inner path needs to be unique'd */ + if (save_jointype == JOIN_UNIQUE_INNER) + return; + + /* + * Look for presorted inner paths that satisfy the innersortkey list --- + * or any truncation thereof, if we are allowed to build a mergejoin using + * a subset of the merge clauses. Here, we consider both cheap startup + * cost and cheap total cost. + * + * Currently we do not consider parameterized inner paths here. This + * interacts with decisions elsewhere that also discriminate against + * mergejoins with parameterized inputs; see comments in + * src/backend/optimizer/README. + * + * As we shorten the sortkey list, we should consider only paths that are + * strictly cheaper than (in particular, not the same as) any path found + * in an earlier iteration. Otherwise we'd be intentionally using fewer + * merge keys than a given path allows (treating the rest as plain + * joinquals), which is unlikely to be a good idea. Also, eliminating + * paths here on the basis of compare_path_costs is a lot cheaper than + * building the mergejoin path only to throw it away. + * + * If inner_cheapest_total is well enough sorted to have not required a + * sort in the path made above, we shouldn't make a duplicate path with + * it, either. We handle that case with the same logic that handles the + * previous consideration, by initializing the variables that track + * cheapest-so-far properly. Note that we do NOT reject + * inner_cheapest_total if we find it matches some shorter set of + * pathkeys. That case corresponds to using fewer mergekeys to avoid + * sorting inner_cheapest_total, whereas we did sort it above, so the + * plans being considered are different. + */ + if (pathkeys_contained_in(innersortkeys, + inner_cheapest_total->pathkeys)) + { + /* inner_cheapest_total didn't require a sort */ + cheapest_startup_inner = inner_cheapest_total; + cheapest_total_inner = inner_cheapest_total; + } + else + { + /* it did require a sort, at least for the full set of keys */ + cheapest_startup_inner = NULL; + cheapest_total_inner = NULL; + } + num_sortkeys = list_length(innersortkeys); + if (num_sortkeys > 1 && !useallclauses) + trialsortkeys = list_copy(innersortkeys); /* need modifiable copy */ + else + trialsortkeys = innersortkeys; /* won't really truncate */ + + for (sortkeycnt = num_sortkeys; sortkeycnt > 0; sortkeycnt--) + { + Path *innerpath; + List *newclauses = NIL; + + /* + * Look for an inner path ordered well enough for the first + * 'sortkeycnt' innersortkeys. NB: trialsortkeys list is modified + * destructively, which is why we made a copy... + */ + trialsortkeys = list_truncate(trialsortkeys, sortkeycnt); + innerpath = get_cheapest_path_for_pathkeys(innerrel->pathlist, + trialsortkeys, + NULL, + TOTAL_COST); + if (innerpath != NULL && + (cheapest_total_inner == NULL || + compare_path_costs(innerpath, cheapest_total_inner, + TOTAL_COST) < 0)) + { + /* Found a cheap (or even-cheaper) sorted path */ + /* Select the right mergeclauses, if we didn't already */ + if (sortkeycnt < num_sortkeys) + { + newclauses = + find_mergeclauses_for_pathkeys(root, + trialsortkeys, + false, + mergeclauses); + Assert(newclauses != NIL); + } + else + newclauses = mergeclauses; + try_mergejoin_path(root, + joinrel, + outerpath, + innerpath, + merge_pathkeys, + newclauses, + NIL, + NIL, + jointype, + extra); + cheapest_total_inner = innerpath; + } + /* Same on the basis of cheapest startup cost ... */ + innerpath = get_cheapest_path_for_pathkeys(innerrel->pathlist, + trialsortkeys, + NULL, + STARTUP_COST); + if (innerpath != NULL && + (cheapest_startup_inner == NULL || + compare_path_costs(innerpath, cheapest_startup_inner, + STARTUP_COST) < 0)) + { + /* Found a cheap (or even-cheaper) sorted path */ + if (innerpath != cheapest_total_inner) + { + /* + * Avoid rebuilding clause list if we already made one; saves + * memory in big join trees... + */ + if (newclauses == NIL) + { + if (sortkeycnt < num_sortkeys) + { + newclauses = + find_mergeclauses_for_pathkeys(root, + trialsortkeys, + false, + mergeclauses); + Assert(newclauses != NIL); + } + else + newclauses = mergeclauses; + } + try_mergejoin_path(root, + joinrel, + outerpath, + innerpath, + merge_pathkeys, + newclauses, + NIL, + NIL, + jointype, + extra); + } + cheapest_startup_inner = innerpath; + } + + /* + * Don't consider truncated sortkeys if we need all clauses. + */ + if (useallclauses) + break; + } +} + /* * match_unsorted_outer * Creates possible join paths for processing a single join relation @@ -790,15 +1034,8 @@ sort_inner_and_outer(PlannerInfo *root, * cheapest-total inner-indexscan path (if any), and one on the * cheapest-startup inner-indexscan path (if different). * - * We also consider mergejoins if mergejoin clauses are available. We have - * two ways to generate the inner path for a mergejoin: sort the cheapest - * inner path, or use an inner path that is already suitably ordered for the - * merge. If we have several mergeclauses, it could be that there is no inner - * path (or only a very expensive one) for the full list of mergeclauses, but - * better paths exist if we truncate the mergeclause list (thereby discarding - * some sort key requirements). So, we consider truncations of the - * mergeclause list as well as the full list. (Ideally we'd consider all - * subsets of the mergeclause list, but that seems way too expensive.) + * We also consider mergejoins if mergejoin clauses are available. See + * detailed comments in generate_mergejoin_paths. * * 'joinrel' is the join relation * 'outerrel' is the outer join relation @@ -894,13 +1131,6 @@ match_unsorted_outer(PlannerInfo *root, { Path *outerpath = (Path *) lfirst(lc1); List *merge_pathkeys; - List *mergeclauses; - List *innersortkeys; - List *trialsortkeys; - Path *cheapest_startup_inner; - Path *cheapest_total_inner; - int num_sortkeys; - int sortkeycnt; /* * We cannot use an outer path that is parameterized by the inner rel. @@ -986,201 +1216,10 @@ match_unsorted_outer(PlannerInfo *root, if (inner_cheapest_total == NULL) continue; - /* Look for useful mergeclauses (if any) */ - mergeclauses = find_mergeclauses_for_pathkeys(root, - outerpath->pathkeys, - true, - extra->mergeclause_list); - - /* - * Done with this outer path if no chance for a mergejoin. - * - * Special corner case: for "x FULL JOIN y ON true", there will be no - * join clauses at all. Ordinarily we'd generate a clauseless - * nestloop path, but since mergejoin is our only join type that - * supports FULL JOIN without any join clauses, it's necessary to - * generate a clauseless mergejoin path instead. - */ - if (mergeclauses == NIL) - { - if (jointype == JOIN_FULL) - /* okay to try for mergejoin */ ; - else - continue; - } - if (useallclauses && list_length(mergeclauses) != list_length(extra->mergeclause_list)) - continue; - - /* Compute the required ordering of the inner path */ - innersortkeys = make_inner_pathkeys_for_merge(root, - mergeclauses, - outerpath->pathkeys); - - /* - * Generate a mergejoin on the basis of sorting the cheapest inner. - * Since a sort will be needed, only cheapest total cost matters. (But - * try_mergejoin_path will do the right thing if inner_cheapest_total - * is already correctly sorted.) - */ - try_mergejoin_path(root, - joinrel, - outerpath, - inner_cheapest_total, - merge_pathkeys, - mergeclauses, - NIL, - innersortkeys, - jointype, - extra); - - /* Can't do anything else if inner path needs to be unique'd */ - if (save_jointype == JOIN_UNIQUE_INNER) - continue; - - /* - * Look for presorted inner paths that satisfy the innersortkey list - * --- or any truncation thereof, if we are allowed to build a - * mergejoin using a subset of the merge clauses. Here, we consider - * both cheap startup cost and cheap total cost. - * - * Currently we do not consider parameterized inner paths here. This - * interacts with decisions elsewhere that also discriminate against - * mergejoins with parameterized inputs; see comments in - * src/backend/optimizer/README. - * - * As we shorten the sortkey list, we should consider only paths that - * are strictly cheaper than (in particular, not the same as) any path - * found in an earlier iteration. Otherwise we'd be intentionally - * using fewer merge keys than a given path allows (treating the rest - * as plain joinquals), which is unlikely to be a good idea. Also, - * eliminating paths here on the basis of compare_path_costs is a lot - * cheaper than building the mergejoin path only to throw it away. - * - * If inner_cheapest_total is well enough sorted to have not required - * a sort in the path made above, we shouldn't make a duplicate path - * with it, either. We handle that case with the same logic that - * handles the previous consideration, by initializing the variables - * that track cheapest-so-far properly. Note that we do NOT reject - * inner_cheapest_total if we find it matches some shorter set of - * pathkeys. That case corresponds to using fewer mergekeys to avoid - * sorting inner_cheapest_total, whereas we did sort it above, so the - * plans being considered are different. - */ - if (pathkeys_contained_in(innersortkeys, - inner_cheapest_total->pathkeys)) - { - /* inner_cheapest_total didn't require a sort */ - cheapest_startup_inner = inner_cheapest_total; - cheapest_total_inner = inner_cheapest_total; - } - else - { - /* it did require a sort, at least for the full set of keys */ - cheapest_startup_inner = NULL; - cheapest_total_inner = NULL; - } - num_sortkeys = list_length(innersortkeys); - if (num_sortkeys > 1 && !useallclauses) - trialsortkeys = list_copy(innersortkeys); /* need modifiable copy */ - else - trialsortkeys = innersortkeys; /* won't really truncate */ - - for (sortkeycnt = num_sortkeys; sortkeycnt > 0; sortkeycnt--) - { - Path *innerpath; - List *newclauses = NIL; - - /* - * Look for an inner path ordered well enough for the first - * 'sortkeycnt' innersortkeys. NB: trialsortkeys list is modified - * destructively, which is why we made a copy... - */ - trialsortkeys = list_truncate(trialsortkeys, sortkeycnt); - innerpath = get_cheapest_path_for_pathkeys(innerrel->pathlist, - trialsortkeys, - NULL, - TOTAL_COST); - if (innerpath != NULL && - (cheapest_total_inner == NULL || - compare_path_costs(innerpath, cheapest_total_inner, - TOTAL_COST) < 0)) - { - /* Found a cheap (or even-cheaper) sorted path */ - /* Select the right mergeclauses, if we didn't already */ - if (sortkeycnt < num_sortkeys) - { - newclauses = - find_mergeclauses_for_pathkeys(root, - trialsortkeys, - false, - mergeclauses); - Assert(newclauses != NIL); - } - else - newclauses = mergeclauses; - try_mergejoin_path(root, - joinrel, - outerpath, - innerpath, - merge_pathkeys, - newclauses, - NIL, - NIL, - jointype, - extra); - cheapest_total_inner = innerpath; - } - /* Same on the basis of cheapest startup cost ... */ - innerpath = get_cheapest_path_for_pathkeys(innerrel->pathlist, - trialsortkeys, - NULL, - STARTUP_COST); - if (innerpath != NULL && - (cheapest_startup_inner == NULL || - compare_path_costs(innerpath, cheapest_startup_inner, - STARTUP_COST) < 0)) - { - /* Found a cheap (or even-cheaper) sorted path */ - if (innerpath != cheapest_total_inner) - { - /* - * Avoid rebuilding clause list if we already made one; - * saves memory in big join trees... - */ - if (newclauses == NIL) - { - if (sortkeycnt < num_sortkeys) - { - newclauses = - find_mergeclauses_for_pathkeys(root, - trialsortkeys, - false, - mergeclauses); - Assert(newclauses != NIL); - } - else - newclauses = mergeclauses; - } - try_mergejoin_path(root, - joinrel, - outerpath, - innerpath, - merge_pathkeys, - newclauses, - NIL, - NIL, - jointype, - extra); - } - cheapest_startup_inner = innerpath; - } - - /* - * Don't consider truncated sortkeys if we need all clauses. - */ - if (useallclauses) - break; - } + /* Generate merge join paths */ + generate_mergejoin_paths(root, joinrel, innerrel, outerpath, + save_jointype, extra, useallclauses, + inner_cheapest_total, merge_pathkeys); } /* @@ -1217,8 +1256,12 @@ consider_parallel_nestloop(PlannerInfo *root, JoinType jointype, JoinPathExtraData *extra) { + JoinType save_jointype = jointype; ListCell *lc1; + if (jointype == JOIN_UNIQUE_INNER) + jointype = JOIN_INNER; + foreach(lc1, outerrel->partial_pathlist) { Path *outerpath = (Path *) lfirst(lc1); @@ -1244,18 +1287,19 @@ consider_parallel_nestloop(PlannerInfo *root, continue; /* - * Like match_unsorted_outer, we only consider a single nestloop - * path when the jointype is JOIN_UNIQUE_INNER. But we have to - * scan cheapest_parameterized_paths to find the one we want to - * consider, because cheapest_total_path might not be - * parallel-safe. + * If we're doing JOIN_UNIQUE_INNER, we can only use the inner's + * cheapest_total_path, and we have to unique-ify it. (We might + * be able to relax this to allow other safe, unparameterized + * inner paths, but right now create_unique_path is not on board + * with that.) */ - if (jointype == JOIN_UNIQUE_INNER) + if (save_jointype == JOIN_UNIQUE_INNER) { - if (!bms_is_empty(PATH_REQ_OUTER(innerpath))) + if (innerpath != innerrel->cheapest_total_path) continue; innerpath = (Path *) create_unique_path(root, innerrel, - innerpath, extra->sjinfo); + innerpath, + extra->sjinfo); Assert(innerpath); } @@ -1284,6 +1328,7 @@ hash_inner_and_outer(PlannerInfo *root, JoinType jointype, JoinPathExtraData *extra) { + JoinType save_jointype = jointype; bool isouterjoin = IS_OUTER_JOIN(jointype); List *hashclauses; ListCell *l; @@ -1450,9 +1495,9 @@ hash_inner_and_outer(PlannerInfo *root, * extended rows. Also, the resulting path must not be parameterized. */ if (joinrel->consider_parallel && - jointype != JOIN_UNIQUE_OUTER && - jointype != JOIN_FULL && - jointype != JOIN_RIGHT && + save_jointype != JOIN_UNIQUE_OUTER && + save_jointype != JOIN_FULL && + save_jointype != JOIN_RIGHT && outerrel->partial_pathlist != NIL && bms_is_empty(joinrel->lateral_relids)) { @@ -1466,11 +1511,12 @@ hash_inner_and_outer(PlannerInfo *root, * Normally, given that the joinrel is parallel-safe, the cheapest * total inner path will also be parallel-safe, but if not, we'll * have to search cheapest_parameterized_paths for the cheapest - * unparameterized inner path. + * safe, unparameterized inner path. If doing JOIN_UNIQUE_INNER, + * we can't use any alternative inner path. */ if (cheapest_total_inner->parallel_safe) cheapest_safe_inner = cheapest_total_inner; - else + else if (save_jointype != JOIN_UNIQUE_INNER) { ListCell *lc; diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c index 01d4fea78c..6f3c20b33f 100644 --- a/src/backend/optimizer/path/joinrels.c +++ b/src/backend/optimizer/path/joinrels.c @@ -3,7 +3,7 @@ * joinrels.c * Routines to determine which relations should be joined * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c index 4436ac111d..1065b31ad1 100644 --- a/src/backend/optimizer/path/pathkeys.c +++ b/src/backend/optimizer/path/pathkeys.c @@ -7,7 +7,7 @@ * the nature and use of path keys. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -480,17 +480,30 @@ build_index_pathkeys(PlannerInfo *root, index->rel->relids, false); - /* - * If the sort key isn't already present in any EquivalenceClass, then - * it's not an interesting sort order for this query. So we can stop - * now --- lower-order sort keys aren't useful either. - */ - if (!cpathkey) - break; - - /* Add to list unless redundant */ - if (!pathkey_is_redundant(cpathkey, retval)) - retval = lappend(retval, cpathkey); + if (cpathkey) + { + /* + * We found the sort key in an EquivalenceClass, so it's relevant + * for this query. Add it to list, unless it's redundant. + */ + if (!pathkey_is_redundant(cpathkey, retval)) + retval = lappend(retval, cpathkey); + } + else + { + /* + * Boolean index keys might be redundant even if they do not + * appear in an EquivalenceClass, because of our special treatment + * of boolean equality conditions --- see the comment for + * indexcol_is_bool_constant_for_query(). If that applies, we can + * continue to examine lower-order index columns. Otherwise, the + * sort key is not an interesting sort order for this query, so we + * should stop considering index columns; any lower-order sort + * keys won't be useful either. + */ + if (!indexcol_is_bool_constant_for_query(index, i)) + break; + } i++; } diff --git a/src/backend/optimizer/path/tidpath.c b/src/backend/optimizer/path/tidpath.c index 530e1347e0..a2fe661075 100644 --- a/src/backend/optimizer/path/tidpath.c +++ b/src/backend/optimizer/path/tidpath.c @@ -25,7 +25,7 @@ * for that. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -43,12 +43,13 @@ #include "optimizer/clauses.h" #include "optimizer/pathnode.h" #include "optimizer/paths.h" +#include "optimizer/restrictinfo.h" static bool IsTidEqualClause(OpExpr *node, int varno); static bool IsTidEqualAnyClause(ScalarArrayOpExpr *node, int varno); static List *TidQualFromExpr(Node *expr, int varno); -static List *TidQualFromRestrictinfo(List *restrictinfo, int varno); +static List *TidQualFromBaseRestrictinfo(RelOptInfo *rel); /* @@ -216,24 +217,26 @@ TidQualFromExpr(Node *expr, int varno) } /* - * Extract a set of CTID conditions from the given restrictinfo list - * - * This is essentially identical to the AND case of TidQualFromExpr, - * except for the format of the input. + * Extract a set of CTID conditions from the rel's baserestrictinfo list */ static List * -TidQualFromRestrictinfo(List *restrictinfo, int varno) +TidQualFromBaseRestrictinfo(RelOptInfo *rel) { List *rlst = NIL; ListCell *l; - foreach(l, restrictinfo) + foreach(l, rel->baserestrictinfo) { RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); - if (!IsA(rinfo, RestrictInfo)) - continue; /* probably should never happen */ - rlst = TidQualFromExpr((Node *) rinfo->clause, varno); + /* + * If clause must wait till after some lower-security-level + * restriction clause, reject it. + */ + if (!restriction_is_securely_promotable(rinfo, rel)) + continue; + + rlst = TidQualFromExpr((Node *) rinfo->clause, rel->relid); if (rlst) break; } @@ -259,7 +262,7 @@ create_tidscan_paths(PlannerInfo *root, RelOptInfo *rel) */ required_outer = rel->lateral_relids; - tidquals = TidQualFromRestrictinfo(rel->baserestrictinfo, rel->relid); + tidquals = TidQualFromBaseRestrictinfo(rel); if (tidquals) add_path(rel, (Path *) create_tidscan_path(root, rel, tidquals, diff --git a/src/backend/optimizer/plan/analyzejoins.c b/src/backend/optimizer/plan/analyzejoins.c index e28a8dc533..438baf1e61 100644 --- a/src/backend/optimizer/plan/analyzejoins.c +++ b/src/backend/optimizer/plan/analyzejoins.c @@ -11,7 +11,7 @@ * is that we have to work harder to clean up after ourselves when we modify * the query, since the derived data structures have to be updated too. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -650,6 +650,11 @@ rel_is_distinct_for(PlannerInfo *root, RelOptInfo *rel, List *clause_list) bool query_supports_distinctness(Query *query) { + /* we don't cope with SRFs, see comment below */ + if (query->hasTargetSRFs) + return false; + + /* check for features we can prove distinctness with */ if (query->distinctClause != NIL || query->groupClause != NIL || query->groupingSets != NIL || @@ -695,7 +700,7 @@ query_is_distinct_for(Query *query, List *colnos, List *opids) * specified columns, since those must be evaluated before de-duplication; * but it doesn't presently seem worth the complication to check that.) */ - if (expression_returns_set((Node *) query->targetList)) + if (query->hasTargetSRFs) return false; /* diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 54d601fc47..fae1f67b9c 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -5,7 +5,7 @@ * Planning is complete, we just need to convert the selected * Path into a Plan. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -81,6 +81,7 @@ static Plan *create_join_plan(PlannerInfo *root, JoinPath *best_path); static Plan *create_append_plan(PlannerInfo *root, AppendPath *best_path); static Plan *create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path); static Result *create_result_plan(PlannerInfo *root, ResultPath *best_path); +static ProjectSet *create_project_set_plan(PlannerInfo *root, ProjectSetPath *best_path); static Material *create_material_plan(PlannerInfo *root, MaterialPath *best_path, int flags); static Plan *create_unique_plan(PlannerInfo *root, UniquePath *best_path, @@ -264,6 +265,7 @@ static SetOp *make_setop(SetOpCmd cmd, SetOpStrategy strategy, Plan *lefttree, long numGroups); static LockRows *make_lockrows(Plan *lefttree, List *rowMarks, int epqParam); static Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan); +static ProjectSet *make_project_set(List *tlist, Plan *subplan); static ModifyTable *make_modifytable(PlannerInfo *root, CmdType operation, bool canSetTag, Index nominalRelation, @@ -392,6 +394,10 @@ create_plan_recurse(PlannerInfo *root, Path *best_path, int flags) (ResultPath *) best_path); } break; + case T_ProjectSet: + plan = (Plan *) create_project_set_plan(root, + (ProjectSetPath *) best_path); + break; case T_Material: plan = (Plan *) create_material_plan(root, (MaterialPath *) best_path, @@ -1141,6 +1147,31 @@ create_result_plan(PlannerInfo *root, ResultPath *best_path) return plan; } +/* + * create_project_set_plan + * Create a ProjectSet plan for 'best_path'. + * + * Returns a Plan node. + */ +static ProjectSet * +create_project_set_plan(PlannerInfo *root, ProjectSetPath *best_path) +{ + ProjectSet *plan; + Plan *subplan; + List *tlist; + + /* Since we intend to project, we don't need to constrain child tlist */ + subplan = create_plan_recurse(root, best_path->subpath, 0); + + tlist = build_path_tlist(root, &best_path->path); + + plan = make_project_set(tlist, subplan); + + copy_generic_path_info(&plan->plan, (Path *) best_path); + + return plan; +} + /* * create_material_plan * Create a Material plan for 'best_path' and (recursively) plans @@ -3243,8 +3274,15 @@ create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path, /* Copy foreign server OID; likewise, no need to make FDW do this */ scan_plan->fs_server = rel->serverid; - /* Likewise, copy the relids that are represented by this foreign scan */ - scan_plan->fs_relids = best_path->path.parent->relids; + /* + * Likewise, copy the relids that are represented by this foreign scan. An + * upper rel doesn't have relids set, but it covers all the base relations + * participating in the underlying scan, so use root's all_baserels. + */ + if (rel->reloptkind == RELOPT_UPPER_REL) + scan_plan->fs_relids = root->all_baserels; + else + scan_plan->fs_relids = best_path->path.parent->relids; /* * If this is a foreign join, and to make it valid to push down we had to @@ -4493,21 +4531,32 @@ get_switched_clauses(List *clauses, Relids outerrelids) * plan node, sort the list into the order we want to check the quals * in at runtime. * + * When security barrier quals are used in the query, we may have quals with + * different security levels in the list. Quals of lower security_level + * must go before quals of higher security_level, except that we can grant + * exceptions to move up quals that are leakproof. When security level + * doesn't force the decision, we prefer to order clauses by estimated + * execution cost, cheapest first. + * * Ideally the order should be driven by a combination of execution cost and * selectivity, but it's not immediately clear how to account for both, * and given the uncertainty of the estimates the reliability of the decisions - * would be doubtful anyway. So we just order by estimated per-tuple cost, - * being careful not to change the order when (as is often the case) the - * estimates are identical. + * would be doubtful anyway. So we just order by security level then + * estimated per-tuple cost, being careful not to change the order when + * (as is often the case) the estimates are identical. * * Although this will work on either bare clauses or RestrictInfos, it's * much faster to apply it to RestrictInfos, since it can re-use cost - * information that is cached in RestrictInfos. + * information that is cached in RestrictInfos. XXX in the bare-clause + * case, we are also not able to apply security considerations. That is + * all right for the moment, because the bare-clause case doesn't occur + * anywhere that barrier quals could be present, but it would be better to + * get rid of it. * * Note: some callers pass lists that contain entries that will later be * removed; this is the easiest way to let this routine see RestrictInfos - * instead of bare clauses. It's OK because we only sort by cost, but - * a cost/selectivity combination would likely do the wrong thing. + * instead of bare clauses. This is another reason why trying to consider + * selectivity in the ordering would likely do the wrong thing. */ static List * order_qual_clauses(PlannerInfo *root, List *clauses) @@ -4516,6 +4565,7 @@ order_qual_clauses(PlannerInfo *root, List *clauses) { Node *clause; Cost cost; + Index security_level; } QualItem; int nitems = list_length(clauses); QualItem *items; @@ -4541,6 +4591,27 @@ order_qual_clauses(PlannerInfo *root, List *clauses) cost_qual_eval_node(&qcost, clause, root); items[i].clause = clause; items[i].cost = qcost.per_tuple; + if (IsA(clause, RestrictInfo)) + { + RestrictInfo *rinfo = (RestrictInfo *) clause; + + /* + * If a clause is leakproof, it doesn't have to be constrained by + * its nominal security level. If it's also reasonably cheap + * (here defined as 10X cpu_operator_cost), pretend it has + * security_level 0, which will allow it to go in front of + * more-expensive quals of lower security levels. Of course, that + * will also force it to go in front of cheaper quals of its own + * security level, which is not so great, but we can alleviate + * that risk by applying the cost limit cutoff. + */ + if (rinfo->leakproof && items[i].cost < 10 * cpu_operator_cost) + items[i].security_level = 0; + else + items[i].security_level = rinfo->security_level; + } + else + items[i].security_level = 0; i++; } @@ -4557,9 +4628,13 @@ order_qual_clauses(PlannerInfo *root, List *clauses) /* insert newitem into the already-sorted subarray */ for (j = i; j > 0; j--) { - if (newitem.cost >= items[j - 1].cost) + QualItem *olditem = &items[j - 1]; + + if (newitem.security_level > olditem->security_level || + (newitem.security_level == olditem->security_level && + newitem.cost >= olditem->cost)) break; - items[j] = items[j - 1]; + items[j] = *olditem; } items[j] = newitem; } @@ -5664,6 +5739,7 @@ make_agg(List *tlist, List *qual, node->grpColIdx = grpColIdx; node->grpOperators = grpOperators; node->numGroups = numGroups; + node->aggParams = NULL; /* SS_finalize_plan() will fill this */ node->groupingSets = groupingSets; node->chain = chain; @@ -6018,6 +6094,25 @@ make_result(List *tlist, return node; } +/* + * make_project_set + * Build a ProjectSet plan node + */ +static ProjectSet * +make_project_set(List *tlist, + Plan *subplan) +{ + ProjectSet *node = makeNode(ProjectSet); + Plan *plan = &node->plan; + + plan->targetlist = tlist; + plan->qual = NIL; + plan->lefttree = subplan; + plan->righttree = NULL; + + return node; +} + /* * make_modifytable * Build a ModifyTable plan node @@ -6184,6 +6279,15 @@ is_projection_capable_path(Path *path) * projection to its dummy path. */ return IS_DUMMY_PATH(path); + case T_ProjectSet: + + /* + * Although ProjectSet certainly projects, say "no" because we + * don't want the planner to randomly replace its tlist with + * something else; the SRFs have to stay at top level. This might + * get relaxed later. + */ + return false; default: break; } @@ -6212,6 +6316,15 @@ is_projection_capable_plan(Plan *plan) case T_MergeAppend: case T_RecursiveUnion: return false; + case T_ProjectSet: + + /* + * Although ProjectSet certainly projects, say "no" because we + * don't want the planner to randomly replace its tlist with + * something else; the SRFs have to stay at top level. This might + * get relaxed later. + */ + return false; default: break; } diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index 84ce6b3125..c170e9614f 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -3,7 +3,7 @@ * initsplan.c * Target list, qualification, joininfo initialization routines * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -51,6 +51,9 @@ static List *deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join, Relids *qualscope, Relids *inner_join_rels, List **postponed_qual_list); +static void process_security_barrier_quals(PlannerInfo *root, + int rti, Relids qualscope, + bool below_outer_join); static SpecialJoinInfo *make_outerjoininfo(PlannerInfo *root, Relids left_rels, Relids right_rels, Relids inner_join_rels, @@ -60,6 +63,7 @@ static void distribute_qual_to_rels(PlannerInfo *root, Node *clause, bool is_deduced, bool below_outer_join, JoinType jointype, + Index security_level, Relids qualscope, Relids ojscope, Relids outerjoin_nonnullable, @@ -745,8 +749,14 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join, { int varno = ((RangeTblRef *) jtnode)->rtindex; - /* No quals to deal with, just return correct result */ + /* qualscope is just the one RTE */ *qualscope = bms_make_singleton(varno); + /* Deal with any securityQuals attached to the RTE */ + if (root->qual_security_level > 0) + process_security_barrier_quals(root, + varno, + *qualscope, + below_outer_join); /* A single baserel does not create an inner join */ *inner_join_rels = NULL; joinlist = list_make1(jtnode); @@ -810,6 +820,7 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join, if (bms_is_subset(pq->relids, *qualscope)) distribute_qual_to_rels(root, pq->qual, false, below_outer_join, JOIN_INNER, + root->qual_security_level, *qualscope, NULL, NULL, NULL, NULL); else @@ -825,6 +836,7 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join, distribute_qual_to_rels(root, qual, false, below_outer_join, JOIN_INNER, + root->qual_security_level, *qualscope, NULL, NULL, NULL, postponed_qual_list); } @@ -1002,6 +1014,7 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join, distribute_qual_to_rels(root, qual, false, below_outer_join, j->jointype, + root->qual_security_level, *qualscope, ojscope, nonnullable_rels, NULL, postponed_qual_list); @@ -1058,6 +1071,67 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join, return joinlist; } +/* + * process_security_barrier_quals + * Transfer security-barrier quals into relation's baserestrictinfo list. + * + * The rewriter put any relevant security-barrier conditions into the RTE's + * securityQuals field, but it's now time to copy them into the rel's + * baserestrictinfo. + * + * In inheritance cases, we only consider quals attached to the parent rel + * here; they will be valid for all children too, so it's okay to consider + * them for purposes like equivalence class creation. Quals attached to + * individual child rels will be dealt with during path creation. + */ +static void +process_security_barrier_quals(PlannerInfo *root, + int rti, Relids qualscope, + bool below_outer_join) +{ + RangeTblEntry *rte = root->simple_rte_array[rti]; + Index security_level = 0; + ListCell *lc; + + /* + * Each element of the securityQuals list has been preprocessed into an + * implicitly-ANDed list of clauses. All the clauses in a given sublist + * should get the same security level, but successive sublists get higher + * levels. + */ + foreach(lc, rte->securityQuals) + { + List *qualset = (List *) lfirst(lc); + ListCell *lc2; + + foreach(lc2, qualset) + { + Node *qual = (Node *) lfirst(lc2); + + /* + * We cheat to the extent of passing ojscope = qualscope rather + * than its more logical value of NULL. The only effect this has + * is to force a Var-free qual to be evaluated at the rel rather + * than being pushed up to top of tree, which we don't want. + */ + distribute_qual_to_rels(root, qual, + false, + below_outer_join, + JOIN_INNER, + security_level, + qualscope, + qualscope, + NULL, + NULL, + NULL); + } + security_level++; + } + + /* Assert that qual_security_level is higher than anything we just used */ + Assert(security_level <= root->qual_security_level); +} + /* * make_outerjoininfo * Build a SpecialJoinInfo for the current outer join @@ -1516,6 +1590,7 @@ compute_semijoin_info(SpecialJoinInfo *sjinfo, List *clause) * 'below_outer_join': TRUE if the qual is from a JOIN/ON that is below the * nullable side of a higher-level outer join * 'jointype': type of join the qual is from (JOIN_INNER for a WHERE clause) + * 'security_level': security_level to assign to the qual * 'qualscope': set of baserels the qual's syntactic scope covers * 'ojscope': NULL if not an outer-join qual, else the minimum set of baserels * needed to form this join @@ -1545,6 +1620,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, bool is_deduced, bool below_outer_join, JoinType jointype, + Index security_level, Relids qualscope, Relids ojscope, Relids outerjoin_nonnullable, @@ -1794,6 +1870,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, is_pushed_down, outerjoin_delayed, pseudoconstant, + security_level, relids, outerjoin_nonnullable, nullable_relids); @@ -2142,6 +2219,9 @@ distribute_restrictinfo_to_rels(PlannerInfo *root, /* Add clause to rel's restriction list */ rel->baserestrictinfo = lappend(rel->baserestrictinfo, restrictinfo); + /* Update security level info */ + rel->baserestrict_min_security = Min(rel->baserestrict_min_security, + restrictinfo->security_level); break; case BMS_MULTIPLE: @@ -2189,6 +2269,8 @@ distribute_restrictinfo_to_rels(PlannerInfo *root, * caller because this function is used after deconstruct_jointree, so we * don't have knowledge of where the clause items came from.) * + * "security_level" is the security level to assign to the new restrictinfo. + * * "both_const" indicates whether both items are known pseudo-constant; * in this case it is worth applying eval_const_expressions() in case we * can produce constant TRUE or constant FALSE. (Otherwise it's not, @@ -2209,6 +2291,7 @@ process_implied_equality(PlannerInfo *root, Expr *item2, Relids qualscope, Relids nullable_relids, + Index security_level, bool below_outer_join, bool both_const) { @@ -2247,6 +2330,7 @@ process_implied_equality(PlannerInfo *root, */ distribute_qual_to_rels(root, (Node *) clause, true, below_outer_join, JOIN_INNER, + security_level, qualscope, NULL, NULL, nullable_relids, NULL); } @@ -2270,7 +2354,8 @@ build_implied_join_equality(Oid opno, Expr *item1, Expr *item2, Relids qualscope, - Relids nullable_relids) + Relids nullable_relids, + Index security_level) { RestrictInfo *restrictinfo; Expr *clause; @@ -2294,6 +2379,7 @@ build_implied_join_equality(Oid opno, true, /* is_pushed_down */ false, /* outerjoin_delayed */ false, /* pseudoconstant */ + security_level, /* security_level */ qualscope, /* required_relids */ NULL, /* outer_relids */ nullable_relids); /* nullable_relids */ diff --git a/src/backend/optimizer/plan/planagg.c b/src/backend/optimizer/plan/planagg.c index 805aae7ee7..c3fbf3cdf8 100644 --- a/src/backend/optimizer/plan/planagg.c +++ b/src/backend/optimizer/plan/planagg.c @@ -17,7 +17,7 @@ * scan all the rows anyway. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -103,6 +103,14 @@ preprocess_minmax_aggregates(PlannerInfo *root, List *tlist) parse->hasWindowFuncs) return; + /* + * Reject if query contains any CTEs; there's no way to build an indexscan + * on one so we couldn't succeed here. (If the CTEs are unreferenced, + * that's not true, but it doesn't seem worth expending cycles to check.) + */ + if (parse->cteList) + return; + /* * We also restrict the query to reference exactly one table, since join * conditions can't be handled reasonably. (We could perhaps handle a @@ -360,7 +368,6 @@ build_minmax_path(PlannerInfo *root, MinMaxAggInfo *mminfo, subroot->plan_params = NIL; subroot->outer_params = NULL; subroot->init_plans = NIL; - subroot->cte_plan_ids = NIL; subroot->parse = parse = (Query *) copyObject(root->parse); IncrementVarSublevelsUp((Node *) parse, 1, 1); diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c index 27234ffa22..e8807591a0 100644 --- a/src/backend/optimizer/plan/planmain.c +++ b/src/backend/optimizer/plan/planmain.c @@ -9,7 +9,7 @@ * shorn of features like subselects, inheritance, aggregates, grouping, * and so on. (Those are the things planner.c deals with.) * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -71,14 +71,13 @@ query_planner(PlannerInfo *root, List *tlist, /* * If query allows parallelism in general, check whether the quals are - * parallel-restricted. There's currently no real benefit to setting - * this flag correctly because we can't yet reference subplans from - * parallel workers. But that might change someday, so set this - * correctly anyway. + * parallel-restricted. (We need not check final_rel->reltarget + * because it's empty at this point. Anything parallel-restricted in + * the query tlist will be dealt with later.) */ if (root->glob->parallelModeOK) final_rel->consider_parallel = - !has_parallel_hazard(parse->jointree->quals, false); + is_parallel_safe(root, parse->jointree->quals); /* The only path for it is a trivial Result path */ add_path(final_rel, (Path *) diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index b265628325..4b5902fc3e 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -3,7 +3,7 @@ * planner.c * The query optimizer external interface. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -23,6 +23,7 @@ #include "access/sysattr.h" #include "access/xact.h" #include "catalog/pg_constraint_fn.h" +#include "catalog/pg_proc.h" #include "catalog/pg_type.h" #include "executor/executor.h" #include "executor/nodeAgg.h" @@ -152,6 +153,8 @@ static List *make_pathkeys_for_window(PlannerInfo *root, WindowClause *wc, static PathTarget *make_sort_input_target(PlannerInfo *root, PathTarget *final_target, bool *have_postponed_srfs); +static void adjust_paths_for_srfs(PlannerInfo *root, RelOptInfo *rel, + List *targets, List *targets_contain_srfs); /***************************************************************************** @@ -192,11 +195,6 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) ListCell *lp, *lr; - /* Cursor options may come from caller or from DECLARE CURSOR stmt */ - if (parse->utilityStmt && - IsA(parse->utilityStmt, DeclareCursorStmt)) - cursorOptions |= ((DeclareCursorStmt *) parse->utilityStmt)->options; - /* * Set up global state for this planner invocation. This data is needed * across all levels of sub-Query that might exist in the given command, @@ -241,12 +239,25 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) * time and execution time, so don't generate a parallel plan if we're in * serializable mode. */ - glob->parallelModeOK = (cursorOptions & CURSOR_OPT_PARALLEL_OK) != 0 && - IsUnderPostmaster && dynamic_shared_memory_type != DSM_IMPL_NONE && - parse->commandType == CMD_SELECT && !parse->hasModifyingCTE && - parse->utilityStmt == NULL && max_parallel_workers_per_gather > 0 && - !IsParallelWorker() && !IsolationIsSerializable() && - !has_parallel_hazard((Node *) parse, true); + if ((cursorOptions & CURSOR_OPT_PARALLEL_OK) != 0 && + IsUnderPostmaster && + dynamic_shared_memory_type != DSM_IMPL_NONE && + parse->commandType == CMD_SELECT && + !parse->hasModifyingCTE && + max_parallel_workers_per_gather > 0 && + !IsParallelWorker() && + !IsolationIsSerializable()) + { + /* all the cheap tests pass, so scan the query tree */ + glob->maxParallelHazard = max_parallel_hazard(parse); + glob->parallelModeOK = (glob->maxParallelHazard != PROPARALLEL_UNSAFE); + } + else + { + /* skip the query tree scan, just assume it's unsafe */ + glob->maxParallelHazard = PROPARALLEL_UNSAFE; + glob->parallelModeOK = false; + } /* * glob->parallelModeNeeded should tell us whether it's necessary to @@ -326,12 +337,9 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) * Optionally add a Gather node for testing purposes, provided this is * actually a safe thing to do. (Note: we assume adding a Material node * above did not change the parallel safety of the plan, so we can still - * rely on best_path->parallel_safe. However, that flag doesn't account - * for initPlans, which render the plan parallel-unsafe.) + * rely on best_path->parallel_safe.) */ - if (force_parallel_mode != FORCE_PARALLEL_OFF && - best_path->parallel_safe && - top_plan->initPlan == NIL) + if (force_parallel_mode != FORCE_PARALLEL_OFF && best_path->parallel_safe) { Gather *gather = makeNode(Gather); @@ -409,13 +417,16 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) result->planTree = top_plan; result->rtable = glob->finalrtable; result->resultRelations = glob->resultRelations; - result->utilityStmt = parse->utilityStmt; result->subplans = glob->subplans; result->rewindPlanIDs = glob->rewindPlanIDs; result->rowMarks = glob->finalrowmarks; result->relationOids = glob->relationOids; result->invalItems = glob->invalItems; result->nParamExec = glob->nParamExec; + /* utilityStmt should be null, but we might as well copy it */ + result->utilityStmt = parse->utilityStmt; + result->stmt_location = parse->stmt_location; + result->stmt_len = parse->stmt_len; return result; } @@ -481,6 +492,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse, root->processed_tlist = NIL; root->grouping_map = NULL; root->minmax_aggs = NIL; + root->qual_security_level = 0; root->hasInheritedTarget = false; root->hasRecursion = hasRecursion; if (hasRecursion) @@ -589,6 +601,10 @@ subquery_planner(PlannerGlobal *glob, Query *parse, preprocess_expression(root, (Node *) parse->targetList, EXPRKIND_TARGET); + /* Constant-folding might have removed all set-returning functions */ + if (parse->hasTargetSRFs) + parse->hasTargetSRFs = expression_returns_set((Node *) parse->targetList); + newWithCheckOptions = NIL; foreach(l, parse->withCheckOptions) { @@ -656,6 +672,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse, { RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); int kind; + ListCell *lcsq; if (rte->rtekind == RTE_RELATION) { @@ -691,6 +708,19 @@ subquery_planner(PlannerGlobal *glob, Query *parse, rte->values_lists = (List *) preprocess_expression(root, (Node *) rte->values_lists, kind); } + + /* + * Process each element of the securityQuals list as if it were a + * separate qual expression (as indeed it is). We need to do it this + * way to get proper canonicalization of AND/OR structure. Note that + * this converts each element into an implicit-AND sublist. + */ + foreach(lcsq, rte->securityQuals) + { + lfirst(lcsq) = preprocess_expression(root, + (Node *) lfirst(lcsq), + EXPRKIND_QUAL); + } } /* @@ -782,10 +812,10 @@ subquery_planner(PlannerGlobal *glob, Query *parse, SS_identify_outer_params(root); /* - * If any initPlans were created in this query level, increment the - * surviving Paths' costs to account for them. They won't actually get - * attached to the plan tree till create_plan() runs, but we want to be - * sure their costs are included now. + * If any initPlans were created in this query level, adjust the surviving + * Paths' costs and parallel-safety flags to account for them. The + * initPlans won't actually get attached to the plan tree till + * create_plan() runs, but we must include their effects now. */ final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL); SS_charge_for_initplans(root, final_rel); @@ -965,7 +995,6 @@ inheritance_planner(PlannerInfo *root) { Query *parse = root->parse; int parentRTindex = parse->resultRelation; - Bitmapset *resultRTindexes; Bitmapset *subqueryRTindexes; Bitmapset *modifiableARIindexes; int nominalRelation = -1; @@ -999,26 +1028,7 @@ inheritance_planner(PlannerInfo *root) * at least O(N^3) work expended here; and (2) would greatly complicate * management of the rowMarks list. * - * Note that any RTEs with security barrier quals will be turned into - * subqueries during planning, and so we must create copies of them too, - * except where they are target relations, which will each only be used in - * a single plan. - * - * To begin with, we'll need a bitmapset of the target relation relids. - */ - resultRTindexes = bms_make_singleton(parentRTindex); - foreach(lc, root->append_rel_list) - { - AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc); - - if (appinfo->parent_relid == parentRTindex) - resultRTindexes = bms_add_member(resultRTindexes, - appinfo->child_relid); - } - - /* - * Now, generate a bitmapset of the relids of the subquery RTEs, including - * security-barrier RTEs that will become subqueries, as just explained. + * To begin with, generate a bitmapset of the relids of the subquery RTEs. */ subqueryRTindexes = NULL; rti = 1; @@ -1026,9 +1036,7 @@ inheritance_planner(PlannerInfo *root) { RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc); - if (rte->rtekind == RTE_SUBQUERY || - (rte->securityQuals != NIL && - !bms_is_member(rti, resultRTindexes))) + if (rte->rtekind == RTE_SUBQUERY) subqueryRTindexes = bms_add_member(subqueryRTindexes, rti); rti++; } @@ -1066,6 +1074,8 @@ inheritance_planner(PlannerInfo *root) { AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc); PlannerInfo *subroot; + RangeTblEntry *parent_rte; + RangeTblEntry *child_rte; RelOptInfo *sub_final_rel; Path *subpath; @@ -1091,6 +1101,15 @@ inheritance_planner(PlannerInfo *root) (Node *) parse, appinfo); + /* + * If there are securityQuals attached to the parent, move them to the + * child rel (they've already been transformed properly for that). + */ + parent_rte = rt_fetch(parentRTindex, subroot->parse->rtable); + child_rte = rt_fetch(appinfo->child_relid, subroot->parse->rtable); + child_rte->securityQuals = parent_rte->securityQuals; + parent_rte->securityQuals = NIL; + /* * The rowMarks list might contain references to subquery RTEs, so * make a copy that we can apply ChangeVarNodes to. (Fortunately, the @@ -1138,11 +1157,11 @@ inheritance_planner(PlannerInfo *root) /* * If this isn't the first child Query, generate duplicates of all - * subquery (or subquery-to-be) RTEs, and adjust Var numbering to - * reference the duplicates. To simplify the loop logic, we scan the - * original rtable not the copy just made by adjust_appendrel_attrs; - * that should be OK since subquery RTEs couldn't contain any - * references to the target rel. + * subquery RTEs, and adjust Var numbering to reference the + * duplicates. To simplify the loop logic, we scan the original rtable + * not the copy just made by adjust_appendrel_attrs; that should be OK + * since subquery RTEs couldn't contain any references to the target + * rel. */ if (final_rtable != NIL && subqueryRTindexes != NULL) { @@ -1159,9 +1178,9 @@ inheritance_planner(PlannerInfo *root) /* * The RTE can't contain any references to its own RT - * index, except in the security barrier quals, so we can - * save a few cycles by applying ChangeVarNodes before we - * append the RTE to the rangetable. + * index, except in its securityQuals, so we can save a + * few cycles by applying ChangeVarNodes to the rest of + * the rangetable before we append the RTE to it. */ newrti = list_length(subroot->parse->rtable) + 1; ChangeVarNodes((Node *) subroot->parse, rti, newrti, 0); @@ -1199,12 +1218,6 @@ inheritance_planner(PlannerInfo *root) /* Generate Path(s) for accessing this result relation */ grouping_planner(subroot, true, 0.0 /* retrieve all tuples */ ); - /* - * Planning may have modified the query result relation (if there were - * security barrier quals on the result RTE). - */ - appinfo->child_relid = subroot->parse->resultRelation; - /* * We'll use the first child relation (even if it's excluded) as the * nominal target relation of the ModifyTable node. Because of the @@ -1243,41 +1256,9 @@ inheritance_planner(PlannerInfo *root) if (final_rtable == NIL) final_rtable = subroot->parse->rtable; else - { - List *tmp_rtable = NIL; - ListCell *cell1, - *cell2; - - /* - * Check to see if any of the original RTEs were turned into - * subqueries during planning. Currently, this should only ever - * happen due to securityQuals being involved which push a - * relation down under a subquery, to ensure that the security - * barrier quals are evaluated first. - * - * When this happens, we want to use the new subqueries in the - * final rtable. - */ - forboth(cell1, final_rtable, cell2, subroot->parse->rtable) - { - RangeTblEntry *rte1 = (RangeTblEntry *) lfirst(cell1); - RangeTblEntry *rte2 = (RangeTblEntry *) lfirst(cell2); - - if (rte1->rtekind == RTE_RELATION && - rte2->rtekind == RTE_SUBQUERY) - { - /* Should only be when there are securityQuals today */ - Assert(rte1->securityQuals != NIL); - tmp_rtable = lappend(tmp_rtable, rte2); - } - else - tmp_rtable = lappend(tmp_rtable, rte1); - } - - final_rtable = list_concat(tmp_rtable, + final_rtable = list_concat(final_rtable, list_copy_tail(subroot->parse->rtable, list_length(final_rtable))); - } /* * We need to collect all the RelOptInfos from all child plans into @@ -1421,8 +1402,9 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, int64 count_est = 0; double limit_tuples = -1.0; bool have_postponed_srfs = false; - double tlist_rows; PathTarget *final_target; + List *final_targets; + List *final_targets_contain_srfs; RelOptInfo *current_rel; RelOptInfo *final_rel; ListCell *lc; @@ -1485,6 +1467,10 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, /* Also extract the PathTarget form of the setop result tlist */ final_target = current_rel->cheapest_total_path->pathtarget; + /* The setop result tlist couldn't contain any SRFs */ + Assert(!parse->hasTargetSRFs); + final_targets = final_targets_contain_srfs = NIL; + /* * Can't handle FOR [KEY] UPDATE/SHARE here (parser should have * checked already, but let's make sure). @@ -1510,8 +1496,14 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, { /* No set operations, do regular planning */ PathTarget *sort_input_target; + List *sort_input_targets; + List *sort_input_targets_contain_srfs; PathTarget *grouping_target; + List *grouping_targets; + List *grouping_targets_contain_srfs; PathTarget *scanjoin_target; + List *scanjoin_targets; + List *scanjoin_targets_contain_srfs; bool have_grouping; AggClauseCosts agg_costs; WindowFuncLists *wflists = NULL; @@ -1621,12 +1613,6 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, parse->resultRelation, parse->rtable); - /* - * Expand any rangetable entries that have security barrier quals. - * This may add new security barrier subquery RTEs to the rangetable. - */ - expand_security_quals(root, tlist); - /* * We are now done hacking up the query's targetlist. Most of the * remaining planning work will be done with the PathTarget @@ -1687,16 +1673,14 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, * Figure out whether there's a hard limit on the number of rows that * query_planner's result subplan needs to return. Even if we know a * hard limit overall, it doesn't apply if the query has any - * grouping/aggregation operations. (XXX it also doesn't apply if the - * tlist contains any SRFs; but checking for that here seems more - * costly than it's worth, since root->limit_tuples is only used for - * cost estimates, and only in a small number of cases.) + * grouping/aggregation operations, or SRFs in the tlist. */ if (parse->groupClause || parse->groupingSets || parse->distinctClause || parse->hasAggs || parse->hasWindowFuncs || + parse->hasTargetSRFs || root->hasHavingQual) root->limit_tuples = -1.0; else @@ -1764,8 +1748,50 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, scanjoin_target = grouping_target; /* - * Forcibly apply scan/join target to all the Paths for the scan/join - * rel. + * If there are any SRFs in the targetlist, we must separate each of + * these PathTargets into SRF-computing and SRF-free targets. Replace + * each of the named targets with a SRF-free version, and remember the + * list of additional projection steps we need to add afterwards. + */ + if (parse->hasTargetSRFs) + { + /* final_target doesn't recompute any SRFs in sort_input_target */ + split_pathtarget_at_srfs(root, final_target, sort_input_target, + &final_targets, + &final_targets_contain_srfs); + final_target = (PathTarget *) linitial(final_targets); + Assert(!linitial_int(final_targets_contain_srfs)); + /* likewise for sort_input_target vs. grouping_target */ + split_pathtarget_at_srfs(root, sort_input_target, grouping_target, + &sort_input_targets, + &sort_input_targets_contain_srfs); + sort_input_target = (PathTarget *) linitial(sort_input_targets); + Assert(!linitial_int(sort_input_targets_contain_srfs)); + /* likewise for grouping_target vs. scanjoin_target */ + split_pathtarget_at_srfs(root, grouping_target, scanjoin_target, + &grouping_targets, + &grouping_targets_contain_srfs); + grouping_target = (PathTarget *) linitial(grouping_targets); + Assert(!linitial_int(grouping_targets_contain_srfs)); + /* scanjoin_target will not have any SRFs precomputed for it */ + split_pathtarget_at_srfs(root, scanjoin_target, NULL, + &scanjoin_targets, + &scanjoin_targets_contain_srfs); + scanjoin_target = (PathTarget *) linitial(scanjoin_targets); + Assert(!linitial_int(scanjoin_targets_contain_srfs)); + } + else + { + /* initialize lists, just to keep compiler quiet */ + final_targets = final_targets_contain_srfs = NIL; + sort_input_targets = sort_input_targets_contain_srfs = NIL; + grouping_targets = grouping_targets_contain_srfs = NIL; + scanjoin_targets = scanjoin_targets_contain_srfs = NIL; + } + + /* + * Forcibly apply SRF-free scan/join target to all the Paths for the + * scan/join rel. * * In principle we should re-run set_cheapest() here to identify the * cheapest path, but it seems unlikely that adding the same tlist @@ -1802,7 +1828,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, * computed by partial paths. */ if (current_rel->partial_pathlist && - !has_parallel_hazard((Node *) scanjoin_target->exprs, false)) + is_parallel_safe(root, (Node *) scanjoin_target->exprs)) { /* Apply the scan/join target to each partial path */ foreach(lc, current_rel->partial_pathlist) @@ -1836,6 +1862,12 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, current_rel->partial_pathlist = NIL; } + /* Now fix things up if scan/join target contains SRFs */ + if (parse->hasTargetSRFs) + adjust_paths_for_srfs(root, current_rel, + scanjoin_targets, + scanjoin_targets_contain_srfs); + /* * Save the various upper-rel PathTargets we just computed into * root->upper_targets[]. The core code doesn't use this, but it @@ -1860,6 +1892,11 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, &agg_costs, rollup_lists, rollup_groupclauses); + /* Fix things up if grouping_target contains SRFs */ + if (parse->hasTargetSRFs) + adjust_paths_for_srfs(root, current_rel, + grouping_targets, + grouping_targets_contain_srfs); } /* @@ -1875,6 +1912,11 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, tlist, wflists, activeWindows); + /* Fix things up if sort_input_target contains SRFs */ + if (parse->hasTargetSRFs) + adjust_paths_for_srfs(root, current_rel, + sort_input_targets, + sort_input_targets_contain_srfs); } /* @@ -1903,36 +1945,11 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, final_target, have_postponed_srfs ? -1.0 : limit_tuples); - } - - /* - * If there are set-returning functions in the tlist, scale up the output - * rowcounts of all surviving Paths to account for that. Note that if any - * SRFs appear in sorting or grouping columns, we'll have underestimated - * the numbers of rows passing through earlier steps; but that's such a - * weird usage that it doesn't seem worth greatly complicating matters to - * account for it. - */ - tlist_rows = tlist_returns_set_rows(tlist); - if (tlist_rows > 1) - { - foreach(lc, current_rel->pathlist) - { - Path *path = (Path *) lfirst(lc); - - /* - * We assume that execution costs of the tlist as such were - * already accounted for. However, it still seems appropriate to - * charge something more for the executor's general costs of - * processing the added tuples. The cost is probably less than - * cpu_tuple_cost, though, so we arbitrarily use half of that. - */ - path->total_cost += path->rows * (tlist_rows - 1) * - cpu_tuple_cost / 2; - - path->rows *= tlist_rows; - } - /* No need to run set_cheapest; we're keeping all paths anyway. */ + /* Fix things up if final_target contains SRFs */ + if (parse->hasTargetSRFs) + adjust_paths_for_srfs(root, current_rel, + final_targets, + final_targets_contain_srfs); } /* @@ -1948,8 +1965,8 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, * query. */ if (current_rel->consider_parallel && - !has_parallel_hazard(parse->limitOffset, false) && - !has_parallel_hazard(parse->limitCount, false)) + is_parallel_safe(root, parse->limitOffset) && + is_parallel_safe(root, parse->limitCount)) final_rel->consider_parallel = true; /* @@ -2282,17 +2299,8 @@ select_rowmark_type(RangeTblEntry *rte, LockClauseStrength strength) /* * We don't need a tuple lock, only the ability to re-fetch - * the row. Regular tables support ROW_MARK_REFERENCE, but if - * this RTE has security barrier quals, it will be turned into - * a subquery during planning, so use ROW_MARK_COPY. - * - * This is only necessary for LCS_NONE, since real tuple locks - * on an RTE with security barrier quals are supported by - * pushing the lock down into the subquery --- see - * expand_security_qual. + * the row. */ - if (rte->securityQuals != NIL) - return ROW_MARK_COPY; return ROW_MARK_REFERENCE; break; case LCS_FORKEYSHARE: @@ -3271,6 +3279,12 @@ estimate_hashagg_tablesize(Path *path, const AggClauseCosts *agg_costs, /* plus the per-hash-entry overhead */ hashentrysize += hash_agg_entry_size(agg_costs->numAggs); + /* + * Note that this disregards the effect of fill-factor and growth policy + * of the hash-table. That's probably ok, given default the default + * fill-factor is relatively high. It'd be hard to meaningfully factor in + * "double-in-size" growth policies here. + */ return hashentrysize * dNumGroups; } @@ -3326,8 +3340,8 @@ create_grouping_paths(PlannerInfo *root, * target list and HAVING quals are parallel-safe. */ if (input_rel->consider_parallel && - !has_parallel_hazard((Node *) target->exprs, false) && - !has_parallel_hazard((Node *) parse->havingQual, false)) + is_parallel_safe(root, (Node *) target->exprs) && + is_parallel_safe(root, (Node *) parse->havingQual)) grouped_rel->consider_parallel = true; /* @@ -3714,11 +3728,11 @@ create_grouping_paths(PlannerInfo *root, &total_groups); /* - * Gather is always unsorted, so we'll need to sort, unless - * there's no GROUP BY clause, in which case there will only be a - * single group. + * Since Gather's output is always unsorted, we'll need to sort, + * unless there's no GROUP BY clause or a degenerate (constant) + * one, in which case there will only be a single group. */ - if (parse->groupClause) + if (root->group_pathkeys) path = (Path *) create_sort_path(root, grouped_rel, path, @@ -3881,8 +3895,8 @@ create_window_paths(PlannerInfo *root, * target list and active windows for non-parallel-safe constructs. */ if (input_rel->consider_parallel && - !has_parallel_hazard((Node *) output_target->exprs, false) && - !has_parallel_hazard((Node *) activeWindows, false)) + is_parallel_safe(root, (Node *) output_target->exprs) && + is_parallel_safe(root, (Node *) activeWindows)) window_rel->consider_parallel = true; /* @@ -4272,7 +4286,7 @@ create_ordered_paths(PlannerInfo *root, * target list is parallel-safe. */ if (input_rel->consider_parallel && - !has_parallel_hazard((Node *) target->exprs, false)) + is_parallel_safe(root, (Node *) target->exprs)) ordered_rel->consider_parallel = true; /* @@ -4980,7 +4994,8 @@ make_sort_input_target(PlannerInfo *root, * Check for SRF or volatile functions. Check the SRF case first * because we must know whether we have any postponed SRFs. */ - if (expression_returns_set((Node *) expr)) + if (parse->hasTargetSRFs && + expression_returns_set((Node *) expr)) { /* We'll decide below whether these are postponable */ col_is_srf[i] = true; @@ -5019,6 +5034,7 @@ make_sort_input_target(PlannerInfo *root, { /* For sortgroupref cols, just check if any contain SRFs */ if (!have_srf_sortcols && + parse->hasTargetSRFs && expression_returns_set((Node *) expr)) have_srf_sortcols = true; } @@ -5127,6 +5143,109 @@ get_cheapest_fractional_path(RelOptInfo *rel, double tuple_fraction) return best_path; } +/* + * adjust_paths_for_srfs + * Fix up the Paths of the given upperrel to handle tSRFs properly. + * + * The executor can only handle set-returning functions that appear at the + * top level of the targetlist of a ProjectSet plan node. If we have any SRFs + * that are not at top level, we need to split up the evaluation into multiple + * plan levels in which each level satisfies this constraint. This function + * modifies each Path of an upperrel that (might) compute any SRFs in its + * output tlist to insert appropriate projection steps. + * + * The given targets and targets_contain_srfs lists are from + * split_pathtarget_at_srfs(). We assume the existing Paths emit the first + * target in targets. + */ +static void +adjust_paths_for_srfs(PlannerInfo *root, RelOptInfo *rel, + List *targets, List *targets_contain_srfs) +{ + ListCell *lc; + + Assert(list_length(targets) == list_length(targets_contain_srfs)); + Assert(!linitial_int(targets_contain_srfs)); + + /* If no SRFs appear at this plan level, nothing to do */ + if (list_length(targets) == 1) + return; + + /* + * Stack SRF-evaluation nodes atop each path for the rel. + * + * In principle we should re-run set_cheapest() here to identify the + * cheapest path, but it seems unlikely that adding the same tlist eval + * costs to all the paths would change that, so we don't bother. Instead, + * just assume that the cheapest-startup and cheapest-total paths remain + * so. (There should be no parameterized paths anymore, so we needn't + * worry about updating cheapest_parameterized_paths.) + */ + foreach(lc, rel->pathlist) + { + Path *subpath = (Path *) lfirst(lc); + Path *newpath = subpath; + ListCell *lc1, + *lc2; + + Assert(subpath->param_info == NULL); + forboth(lc1, targets, lc2, targets_contain_srfs) + { + PathTarget *thistarget = (PathTarget *) lfirst(lc1); + bool contains_srfs = (bool) lfirst_int(lc2); + + /* If this level doesn't contain SRFs, do regular projection */ + if (contains_srfs) + newpath = (Path *) create_set_projection_path(root, + rel, + newpath, + thistarget); + else + newpath = (Path *) apply_projection_to_path(root, + rel, + newpath, + thistarget); + } + lfirst(lc) = newpath; + if (subpath == rel->cheapest_startup_path) + rel->cheapest_startup_path = newpath; + if (subpath == rel->cheapest_total_path) + rel->cheapest_total_path = newpath; + } + + /* Likewise for partial paths, if any */ + foreach(lc, rel->partial_pathlist) + { + Path *subpath = (Path *) lfirst(lc); + Path *newpath = subpath; + ListCell *lc1, + *lc2; + + Assert(subpath->param_info == NULL); + forboth(lc1, targets, lc2, targets_contain_srfs) + { + PathTarget *thistarget = (PathTarget *) lfirst(lc1); + bool contains_srfs = (bool) lfirst_int(lc2); + + /* If this level doesn't contain SRFs, do regular projection */ + if (contains_srfs) + newpath = (Path *) create_set_projection_path(root, + rel, + newpath, + thistarget); + else + { + /* avoid apply_projection_to_path, in case of multiple refs */ + newpath = (Path *) create_projection_path(root, + rel, + newpath, + thistarget); + } + } + lfirst(lc) = newpath; + } +} + /* * expression_planner * Perform planner's transformations on a standalone expression. diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index d10a98396c..be267b9da7 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -4,7 +4,7 @@ * Post-processing of a completed plan tree: fix references to subplan * vars, compute regproc values for operators, etc * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -396,10 +396,9 @@ add_rte_to_flat_rtable(PlannerGlobal *glob, RangeTblEntry *rte) newrte->joinaliasvars = NIL; newrte->functions = NIL; newrte->values_lists = NIL; - newrte->values_collations = NIL; - newrte->ctecoltypes = NIL; - newrte->ctecoltypmods = NIL; - newrte->ctecolcollations = NIL; + newrte->coltypes = NIL; + newrte->coltypmods = NIL; + newrte->colcollations = NIL; newrte->securityQuals = NIL; glob->finalrtable = lappend(glob->finalrtable, newrte); @@ -734,6 +733,9 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) fix_scan_expr(root, splan->resconstantqual, rtoffset); } break; + case T_ProjectSet: + set_upper_references(root, plan, rtoffset); + break; case T_ModifyTable: { ModifyTable *splan = (ModifyTable *) plan; @@ -1823,6 +1825,19 @@ set_dummy_tlist_references(Plan *plan, int rtoffset) Var *oldvar = (Var *) tle->expr; Var *newvar; + /* + * As in search_indexed_tlist_for_non_var(), we prefer to keep Consts + * as Consts, not Vars referencing Consts. Here, there's no speed + * advantage to be had, but it makes EXPLAIN output look cleaner, and + * again it avoids confusing the executor. + */ + if (IsA(oldvar, Const)) + { + /* just reuse the existing TLE node */ + output_targetlist = lappend(output_targetlist, tle); + continue; + } + newvar = makeVar(OUTER_VAR, tle->resno, exprType((Node *) oldvar), @@ -2010,6 +2025,16 @@ search_indexed_tlist_for_non_var(Node *node, { TargetEntry *tle; + /* + * If it's a simple Const, replacing it with a Var is silly, even if there + * happens to be an identical Const below; a Var is more expensive to + * execute than a Const. What's more, replacing it could confuse some + * places in the executor that expect to see simple Consts for, eg, + * dropped columns. + */ + if (IsA(node, Const)) + return NULL; + tle = tlist_member(node, itlist->tlist); if (tle) { diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index a46cc10820..9fc748973e 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -3,7 +3,7 @@ * subselect.c * Planning routines for subselects and parameters. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -82,6 +82,7 @@ static Bitmapset *finalize_plan(PlannerInfo *root, Bitmapset *valid_params, Bitmapset *scan_params); static bool finalize_primnode(Node *node, finalize_primnode_context *context); +static bool finalize_agg_primnode(Node *node, finalize_primnode_context *context); /* @@ -1561,7 +1562,7 @@ simplify_EXISTS_query(PlannerInfo *root, Query *query) { /* * We don't try to simplify at all if the query uses set operations, - * aggregates, grouping sets, modifying CTEs, HAVING, OFFSET, or FOR + * aggregates, grouping sets, SRFs, modifying CTEs, HAVING, OFFSET, or FOR * UPDATE/SHARE; none of these seem likely in normal usage and their * possible effects are complex. (Note: we could ignore an "OFFSET 0" * clause, but that traditionally is used as an optimization fence, so we @@ -1572,6 +1573,7 @@ simplify_EXISTS_query(PlannerInfo *root, Query *query) query->hasAggs || query->groupingSets || query->hasWindowFuncs || + query->hasTargetSRFs || query->hasModifyingCTE || query->havingQual || query->limitOffset || @@ -1612,13 +1614,6 @@ simplify_EXISTS_query(PlannerInfo *root, Query *query) query->limitCount = NULL; } - /* - * Mustn't throw away the targetlist if it contains set-returning - * functions; those could affect whether zero rows are returned! - */ - if (expression_returns_set((Node *) query->targetList)) - return false; - /* * Otherwise, we can throw away the targetlist, as well as any GROUP, * WINDOW, DISTINCT, and ORDER BY clauses; none of those clauses will @@ -2133,11 +2128,13 @@ SS_identify_outer_params(PlannerInfo *root) } /* - * SS_charge_for_initplans - account for cost of initplans in Path costs + * SS_charge_for_initplans - account for initplans in Path costs & parallelism * * If any initPlans have been created in the current query level, they will * get attached to the Plan tree created from whichever Path we select from - * the given rel; so increment all the rel's Paths' costs to account for them. + * the given rel. Increment all that rel's Paths' costs to account for them, + * and make sure the paths get marked as parallel-unsafe, since we can't + * currently transmit initPlans to parallel workers. * * This is separate from SS_attach_initplans because we might conditionally * create more initPlans during create_plan(), depending on which Path we @@ -2169,7 +2166,7 @@ SS_charge_for_initplans(PlannerInfo *root, RelOptInfo *final_rel) } /* - * Now adjust the costs. + * Now adjust the costs and parallel_safe flags. */ foreach(lc, final_rel->pathlist) { @@ -2177,6 +2174,7 @@ SS_charge_for_initplans(PlannerInfo *root, RelOptInfo *final_rel) path->startup_cost += initplan_cost; path->total_cost += initplan_cost; + path->parallel_safe = false; } /* We needn't do set_cheapest() here, caller will do it */ @@ -2652,6 +2650,29 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params, locally_added_param); break; + case T_Agg: + { + Agg *agg = (Agg *) plan; + + /* + * AGG_HASHED plans need to know which Params are referenced + * in aggregate calls. Do a separate scan to identify them. + */ + if (agg->aggstrategy == AGG_HASHED) + { + finalize_primnode_context aggcontext; + + aggcontext.root = root; + aggcontext.paramids = NULL; + finalize_agg_primnode((Node *) agg->plan.targetlist, + &aggcontext); + finalize_agg_primnode((Node *) agg->plan.qual, + &aggcontext); + agg->aggParams = aggcontext.paramids; + } + } + break; + case T_WindowAgg: finalize_primnode(((WindowAgg *) plan)->startOffset, &context); @@ -2659,14 +2680,15 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params, &context); break; + case T_ProjectSet: case T_Hash: - case T_Agg: case T_Material: case T_Sort: case T_Unique: case T_Gather: case T_SetOp: case T_Group: + /* no node-type-specific fields need fixing */ break; default: @@ -2811,6 +2833,29 @@ finalize_primnode(Node *node, finalize_primnode_context *context) (void *) context); } +/* + * finalize_agg_primnode: find all Aggref nodes in the given expression tree, + * and add IDs of all PARAM_EXEC params appearing within their aggregated + * arguments to the result set. + */ +static bool +finalize_agg_primnode(Node *node, finalize_primnode_context *context) +{ + if (node == NULL) + return false; + if (IsA(node, Aggref)) + { + Aggref *agg = (Aggref *) node; + + /* we should not consider the direct arguments, if any */ + finalize_primnode((Node *) agg->args, context); + finalize_primnode((Node *) agg->aggfilter, context); + return false; /* there can't be any Aggrefs below here */ + } + return expression_tree_walker(node, finalize_agg_primnode, + (void *) context); +} + /* * SS_make_initplan_output_param - make a Param for an initPlan's output * diff --git a/src/backend/optimizer/prep/Makefile b/src/backend/optimizer/prep/Makefile index 5195d9b0ba..86301bfbd3 100644 --- a/src/backend/optimizer/prep/Makefile +++ b/src/backend/optimizer/prep/Makefile @@ -12,6 +12,6 @@ subdir = src/backend/optimizer/prep top_builddir = ../../../.. include $(top_builddir)/src/Makefile.global -OBJS = prepjointree.o prepqual.o prepsecurity.o preptlist.o prepunion.o +OBJS = prepjointree.o prepqual.o preptlist.o prepunion.o include $(top_srcdir)/src/backend/common.mk diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index a334f15773..6911177b68 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -12,7 +12,7 @@ * reduce_outer_joins * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -913,6 +913,7 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, subroot->processed_tlist = NIL; subroot->grouping_map = NULL; subroot->minmax_aggs = NIL; + subroot->qual_security_level = 0; subroot->hasInheritedTarget = false; subroot->hasRecursion = false; subroot->wt_param_id = -1; @@ -1187,9 +1188,12 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, */ parse->hasSubLinks |= subquery->hasSubLinks; + /* If subquery had any RLS conditions, now main query does too */ + parse->hasRowSecurity |= subquery->hasRowSecurity; + /* - * subquery won't be pulled up if it hasAggs or hasWindowFuncs, so no work - * needed on those flags + * subquery won't be pulled up if it hasAggs, hasWindowFuncs, or + * hasTargetSRFs, so no work needed on those flags */ /* @@ -1406,8 +1410,7 @@ is_simple_subquery(Query *subquery, RangeTblEntry *rte, * Let's just make sure it's a valid subselect ... */ if (!IsA(subquery, Query) || - subquery->commandType != CMD_SELECT || - subquery->utilityStmt != NULL) + subquery->commandType != CMD_SELECT) elog(ERROR, "subquery is bogus"); /* @@ -1419,8 +1422,8 @@ is_simple_subquery(Query *subquery, RangeTblEntry *rte, return false; /* - * Can't pull up a subquery involving grouping, aggregation, sorting, - * limiting, or WITH. (XXX WITH could possibly be allowed later) + * Can't pull up a subquery involving grouping, aggregation, SRFs, + * sorting, limiting, or WITH. (XXX WITH could possibly be allowed later) * * We also don't pull up a subquery that has explicit FOR UPDATE/SHARE * clauses, because pullup would cause the locking to occur semantically @@ -1430,6 +1433,7 @@ is_simple_subquery(Query *subquery, RangeTblEntry *rte, */ if (subquery->hasAggs || subquery->hasWindowFuncs || + subquery->hasTargetSRFs || subquery->groupClause || subquery->groupingSets || subquery->havingQual || @@ -1542,15 +1546,6 @@ is_simple_subquery(Query *subquery, RangeTblEntry *rte, } } - /* - * Don't pull up a subquery that has any set-returning functions in its - * targetlist. Otherwise we might well wind up inserting set-returning - * functions into places where they mustn't go, such as quals of higher - * queries. This also ensures deletion of an empty jointree is valid. - */ - if (expression_returns_set((Node *) subquery->targetList)) - return false; - /* * Don't pull up a subquery that has any volatile functions in its * targetlist. Otherwise we might introduce multiple evaluations of these @@ -1749,8 +1744,7 @@ is_simple_union_all(Query *subquery) /* Let's just make sure it's a valid subselect ... */ if (!IsA(subquery, Query) || - subquery->commandType != CMD_SELECT || - subquery->utilityStmt != NULL) + subquery->commandType != CMD_SELECT) elog(ERROR, "subquery is bogus"); /* Is it a set-operation query at all? */ diff --git a/src/backend/optimizer/prep/prepqual.c b/src/backend/optimizer/prep/prepqual.c index 0cc8856732..f75b3274ad 100644 --- a/src/backend/optimizer/prep/prepqual.c +++ b/src/backend/optimizer/prep/prepqual.c @@ -19,7 +19,7 @@ * tree after local transformations that might introduce nested AND/ORs. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/prep/prepsecurity.c b/src/backend/optimizer/prep/prepsecurity.c deleted file mode 100644 index 01eddf0fbf..0000000000 --- a/src/backend/optimizer/prep/prepsecurity.c +++ /dev/null @@ -1,486 +0,0 @@ -/*------------------------------------------------------------------------- - * - * prepsecurity.c - * Routines for preprocessing security barrier quals. - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * src/backend/optimizer/prep/prepsecurity.c - * - *------------------------------------------------------------------------- - */ -#include "postgres.h" - -#include "access/heapam.h" -#include "access/sysattr.h" -#include "catalog/heap.h" -#include "nodes/makefuncs.h" -#include "nodes/nodeFuncs.h" -#include "optimizer/prep.h" -#include "parser/analyze.h" -#include "parser/parsetree.h" -#include "rewrite/rewriteManip.h" -#include "utils/rel.h" - - -typedef struct -{ - int rt_index; /* Index of security barrier RTE */ - int sublevels_up; /* Current nesting depth */ - Relation rel; /* RTE relation at rt_index */ - List *targetlist; /* Targetlist for new subquery RTE */ - List *colnames; /* Column names in subquery RTE */ - List *vars_processed; /* List of Vars already processed */ -} security_barrier_replace_vars_context; - -static void expand_security_qual(PlannerInfo *root, List *tlist, int rt_index, - RangeTblEntry *rte, Node *qual, bool targetRelation); - -static void security_barrier_replace_vars(Node *node, - security_barrier_replace_vars_context *context); - -static bool security_barrier_replace_vars_walker(Node *node, - security_barrier_replace_vars_context *context); - - -/* - * expand_security_quals - - * expands any security barrier quals on RTEs in the query rtable, turning - * them into security barrier subqueries. - * - * Any given RTE may have multiple security barrier quals in a list, from which - * we create a set of nested subqueries to isolate each security barrier from - * the others, providing protection against malicious user-defined security - * barriers. The first security barrier qual in the list will be used in the - * innermost subquery. - * - * In practice, the only RTEs that will have security barrier quals are those - * that refer to tables with row-level security, or which are the target - * relation of an update to an auto-updatable security barrier view. RTEs - * that read from a security barrier view will have already been expanded by - * the rewriter. - */ -void -expand_security_quals(PlannerInfo *root, List *tlist) -{ - Query *parse = root->parse; - int rt_index; - ListCell *cell; - - /* - * Process each RTE in the rtable list. - * - * We only ever modify entries in place and append to the rtable, so it is - * safe to use a foreach loop here. - */ - rt_index = 0; - foreach(cell, parse->rtable) - { - bool targetRelation = false; - RangeTblEntry *rte = (RangeTblEntry *) lfirst(cell); - - rt_index++; - - if (rte->securityQuals == NIL) - continue; - - /* - * Ignore any RTEs that aren't used in the query (such RTEs may be - * present for permissions checks). - */ - if (rt_index != parse->resultRelation && - !rangeTableEntry_used((Node *) parse, rt_index, 0)) - continue; - - /* - * If this RTE is the target then we need to make a copy of it before - * expanding it. The unexpanded copy will become the new target, and - * the original RTE will be expanded to become the source of rows to - * update/delete. - */ - if (rt_index == parse->resultRelation) - { - RangeTblEntry *newrte = copyObject(rte); - - /* - * We need to let expand_security_qual know if this is the target - * relation, as it has additional work to do in that case. - * - * Capture that information here as we're about to replace - * parse->resultRelation. - */ - targetRelation = true; - - parse->rtable = lappend(parse->rtable, newrte); - parse->resultRelation = list_length(parse->rtable); - - /* - * Wipe out any copied security barrier quals on the new target to - * prevent infinite recursion. - */ - newrte->securityQuals = NIL; - - /* - * There's no need to do permissions checks twice, so wipe out the - * permissions info for the original RTE (we prefer to keep the - * bits set on the result RTE). - */ - rte->requiredPerms = 0; - rte->checkAsUser = InvalidOid; - rte->selectedCols = NULL; - rte->insertedCols = NULL; - rte->updatedCols = NULL; - - /* - * For the most part, Vars referencing the original relation - * should remain as they are, meaning that they pull OLD values - * from the expanded RTE. But in the RETURNING list and in any - * WITH CHECK OPTION quals, we want such Vars to represent NEW - * values, so change them to reference the new RTE. - */ - ChangeVarNodes((Node *) parse->returningList, rt_index, - parse->resultRelation, 0); - - ChangeVarNodes((Node *) parse->withCheckOptions, rt_index, - parse->resultRelation, 0); - } - - /* - * Process each security barrier qual in turn, starting with the - * innermost one (the first in the list) and working outwards. - * - * We remove each qual from the list before processing it, so that its - * variables aren't modified by expand_security_qual. Also we don't - * necessarily want the attributes referred to by the qual to be - * exposed by the newly built subquery. - */ - while (rte->securityQuals != NIL) - { - Node *qual = (Node *) linitial(rte->securityQuals); - - rte->securityQuals = list_delete_first(rte->securityQuals); - - ChangeVarNodes(qual, rt_index, 1, 0); - expand_security_qual(root, tlist, rt_index, rte, qual, - targetRelation); - } - } -} - - -/* - * expand_security_qual - - * expand the specified security barrier qual on a query RTE, turning the - * RTE into a security barrier subquery. - */ -static void -expand_security_qual(PlannerInfo *root, List *tlist, int rt_index, - RangeTblEntry *rte, Node *qual, bool targetRelation) -{ - Query *parse = root->parse; - Oid relid = rte->relid; - Query *subquery; - RangeTblEntry *subrte; - RangeTblRef *subrtr; - PlanRowMark *rc; - security_barrier_replace_vars_context context; - ListCell *cell; - - /* - * There should only be 2 possible cases: - * - * 1. A relation RTE, which we turn into a subquery RTE containing all - * referenced columns. - * - * 2. A subquery RTE (either from a prior call to this function or from an - * expanded view). In this case we build a new subquery on top of it to - * isolate this security barrier qual from any other quals. - */ - switch (rte->rtekind) - { - case RTE_RELATION: - - /* - * Turn the relation RTE into a security barrier subquery RTE, - * moving all permissions checks down into the subquery. - */ - subquery = makeNode(Query); - subquery->commandType = CMD_SELECT; - subquery->querySource = QSRC_INSTEAD_RULE; - - subrte = copyObject(rte); - subrte->inFromCl = true; - subrte->securityQuals = NIL; - subquery->rtable = list_make1(subrte); - - subrtr = makeNode(RangeTblRef); - subrtr->rtindex = 1; - subquery->jointree = makeFromExpr(list_make1(subrtr), qual); - subquery->hasSubLinks = checkExprHasSubLink(qual); - - rte->rtekind = RTE_SUBQUERY; - rte->relid = InvalidOid; - rte->subquery = subquery; - rte->security_barrier = true; - rte->inh = false; /* must not be set for a subquery */ - - /* the permissions checks have now been moved down */ - rte->requiredPerms = 0; - rte->checkAsUser = InvalidOid; - rte->selectedCols = NULL; - rte->insertedCols = NULL; - rte->updatedCols = NULL; - - /* - * Now deal with any PlanRowMark on this RTE by requesting a lock - * of the same strength on the RTE copied down to the subquery. - * - * Note that we can only push down user-defined quals if they are - * only using leakproof (and therefore trusted) functions and - * operators. As a result, we may end up locking more rows than - * strictly necessary (and, in the worst case, we could end up - * locking all rows which pass the securityQuals). This is - * currently documented behavior, but it'd be nice to come up with - * a better solution some day. - */ - rc = get_plan_rowmark(root->rowMarks, rt_index); - if (rc != NULL) - { - if (rc->strength != LCS_NONE) - applyLockingClause(subquery, 1, rc->strength, - rc->waitPolicy, false); - root->rowMarks = list_delete_ptr(root->rowMarks, rc); - } - - /* - * When we are replacing the target relation with a subquery, we - * need to make sure to add a locking clause explicitly to the - * generated subquery since there won't be any row marks against - * the target relation itself. - */ - if (targetRelation) - applyLockingClause(subquery, 1, LCS_FORUPDATE, - LockWaitBlock, false); - - /* - * Replace any variables in the outer query that refer to the - * original relation RTE with references to columns that we will - * expose in the new subquery, building the subquery's targetlist - * as we go. Also replace any references in the translated_vars - * lists of any appendrels. - */ - context.rt_index = rt_index; - context.sublevels_up = 0; - context.rel = heap_open(relid, NoLock); - context.targetlist = NIL; - context.colnames = NIL; - context.vars_processed = NIL; - - security_barrier_replace_vars((Node *) parse, &context); - security_barrier_replace_vars((Node *) tlist, &context); - security_barrier_replace_vars((Node *) root->append_rel_list, - &context); - - heap_close(context.rel, NoLock); - - /* Now we know what columns the subquery needs to expose */ - rte->subquery->targetList = context.targetlist; - rte->eref = makeAlias(rte->eref->aliasname, context.colnames); - - break; - - case RTE_SUBQUERY: - - /* - * Build a new subquery that includes all the same columns as the - * original subquery. - */ - subquery = makeNode(Query); - subquery->commandType = CMD_SELECT; - subquery->querySource = QSRC_INSTEAD_RULE; - subquery->targetList = NIL; - - foreach(cell, rte->subquery->targetList) - { - TargetEntry *tle; - Var *var; - - tle = (TargetEntry *) lfirst(cell); - var = makeVarFromTargetEntry(1, tle); - - tle = makeTargetEntry((Expr *) var, - list_length(subquery->targetList) + 1, - pstrdup(tle->resname), - tle->resjunk); - subquery->targetList = lappend(subquery->targetList, tle); - } - - subrte = makeNode(RangeTblEntry); - subrte->rtekind = RTE_SUBQUERY; - subrte->subquery = rte->subquery; - subrte->security_barrier = rte->security_barrier; - subrte->eref = copyObject(rte->eref); - subrte->inFromCl = true; - subquery->rtable = list_make1(subrte); - - subrtr = makeNode(RangeTblRef); - subrtr->rtindex = 1; - subquery->jointree = makeFromExpr(list_make1(subrtr), qual); - subquery->hasSubLinks = checkExprHasSubLink(qual); - - rte->subquery = subquery; - rte->security_barrier = true; - - break; - - default: - elog(ERROR, "invalid range table entry for security barrier qual"); - } -} - - -/* - * security_barrier_replace_vars - - * Apply security barrier variable replacement to an expression tree. - * - * This also builds/updates a targetlist with entries for each replacement - * variable that needs to be exposed by the security barrier subquery RTE. - * - * NOTE: although this has the form of a walker, we cheat and modify the - * nodes in-place. The given expression tree should have been copied - * earlier to ensure that no unwanted side-effects occur! - */ -static void -security_barrier_replace_vars(Node *node, - security_barrier_replace_vars_context *context) -{ - /* - * Must be prepared to start with a Query or a bare expression tree; if - * it's a Query, go straight to query_tree_walker to make sure that - * sublevels_up doesn't get incremented prematurely. - */ - if (node && IsA(node, Query)) - query_tree_walker((Query *) node, - security_barrier_replace_vars_walker, - (void *) context, 0); - else - security_barrier_replace_vars_walker(node, context); -} - -static bool -security_barrier_replace_vars_walker(Node *node, - security_barrier_replace_vars_context *context) -{ - if (node == NULL) - return false; - - if (IsA(node, Var)) - { - Var *var = (Var *) node; - - /* - * Note that the same Var may be present in different lists, so we - * need to take care not to process it multiple times. - */ - if (var->varno == context->rt_index && - var->varlevelsup == context->sublevels_up && - !list_member_ptr(context->vars_processed, var)) - { - /* - * Found a matching variable. Make sure that it is in the subquery - * targetlist and map its attno accordingly. - */ - AttrNumber attno; - ListCell *l; - TargetEntry *tle; - char *attname; - Var *newvar; - - /* Search for the base attribute in the subquery targetlist */ - attno = InvalidAttrNumber; - foreach(l, context->targetlist) - { - tle = (TargetEntry *) lfirst(l); - attno++; - - Assert(IsA(tle->expr, Var)); - if (((Var *) tle->expr)->varattno == var->varattno && - ((Var *) tle->expr)->varcollid == var->varcollid) - { - /* Map the variable onto this subquery targetlist entry */ - var->varattno = var->varoattno = attno; - /* Mark this var as having been processed */ - context->vars_processed = lappend(context->vars_processed, var); - return false; - } - } - - /* Not in the subquery targetlist, so add it. Get its name. */ - if (var->varattno < 0) - { - Form_pg_attribute att_tup; - - att_tup = SystemAttributeDefinition(var->varattno, - context->rel->rd_rel->relhasoids); - attname = NameStr(att_tup->attname); - } - else if (var->varattno == InvalidAttrNumber) - { - attname = "wholerow"; - } - else if (var->varattno <= context->rel->rd_att->natts) - { - Form_pg_attribute att_tup; - - att_tup = context->rel->rd_att->attrs[var->varattno - 1]; - attname = NameStr(att_tup->attname); - } - else - { - elog(ERROR, "invalid attribute number %d in security_barrier_replace_vars", var->varattno); - } - - /* New variable for subquery targetlist */ - newvar = copyObject(var); - newvar->varno = newvar->varnoold = 1; - newvar->varlevelsup = 0; - - attno = list_length(context->targetlist) + 1; - tle = makeTargetEntry((Expr *) newvar, - attno, - pstrdup(attname), - false); - - context->targetlist = lappend(context->targetlist, tle); - - context->colnames = lappend(context->colnames, - makeString(pstrdup(attname))); - - /* Update the outer query's variable */ - var->varattno = var->varoattno = attno; - - /* Remember this Var so that we don't process it again */ - context->vars_processed = lappend(context->vars_processed, var); - } - return false; - } - - if (IsA(node, Query)) - { - /* Recurse into subselects */ - bool result; - - context->sublevels_up++; - result = query_tree_walker((Query *) node, - security_barrier_replace_vars_walker, - (void *) context, 0); - context->sublevels_up--; - return result; - } - - return expression_tree_walker(node, security_barrier_replace_vars_walker, - (void *) context); -} diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c index 1c8d1052c5..824af3f54c 100644 --- a/src/backend/optimizer/prep/preptlist.c +++ b/src/backend/optimizer/prep/preptlist.c @@ -27,7 +27,7 @@ * that because it's faster in typical non-inherited cases. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index b7147832e0..06e843dff0 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -17,7 +17,7 @@ * append relations, and thenceforth share code with the UNION ALL case. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -56,7 +56,6 @@ typedef struct { PlannerInfo *root; AppendRelInfo *appinfo; - int sublevels_up; } adjust_appendrel_attrs_context; static Path *recurse_set_operations(Node *setOp, PlannerInfo *root, @@ -1467,12 +1466,19 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti) * We copy most fields of the parent's RTE, but replace relation OID * and relkind, and set inh = false. Also, set requiredPerms to zero * since all required permissions checks are done on the original RTE. + * Likewise, set the child's securityQuals to empty, because we only + * want to apply the parent's RLS conditions regardless of what RLS + * properties individual children may have. (This is an intentional + * choice to make inherited RLS work like regular permissions checks.) + * The parent securityQuals will be propagated to children along with + * other base restriction clauses, so we don't need to do it here. */ childrte = copyObject(rte); childrte->relid = childOID; childrte->relkind = newrelation->rd_rel->relkind; childrte->inh = false; childrte->requiredPerms = 0; + childrte->securityQuals = NIL; parse->rtable = lappend(parse->rtable, childrte); childRTindex = list_length(parse->rtable); @@ -1541,7 +1547,8 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti) /* * If all the children were temp tables, pretend it's a non-inheritance * situation. The duplicate RTE we added for the parent table is - * harmless, so we don't bother to get rid of it. + * harmless, so we don't bother to get rid of it; ditto for the useless + * PlanRowMark node. */ if (list_length(appinfos) < 2) { @@ -1717,9 +1724,8 @@ translate_col_privs(const Bitmapset *parent_privs, * child rel instead. We also update rtindexes appearing outside Vars, * such as resultRelation and jointree relids. * - * Note: this is applied after conversion of sublinks to subplans in the - * query jointree, but there may still be sublinks in the security barrier - * quals of RTEs, so we do need to cope with recursion into sub-queries. + * Note: this is only applied after conversion of sublinks to subplans, + * so we don't need to cope with recursion into sub-queries. * * Note: this is not hugely different from what pullup_replace_vars() does; * maybe we should try to fold the two routines together. @@ -1732,12 +1738,9 @@ adjust_appendrel_attrs(PlannerInfo *root, Node *node, AppendRelInfo *appinfo) context.root = root; context.appinfo = appinfo; - context.sublevels_up = 0; /* - * Must be prepared to start with a Query or a bare expression tree; if - * it's a Query, go straight to query_tree_walker to make sure that - * sublevels_up doesn't get incremented prematurely. + * Must be prepared to start with a Query or a bare expression tree. */ if (node && IsA(node, Query)) { @@ -1776,7 +1779,7 @@ adjust_appendrel_attrs_mutator(Node *node, { Var *var = (Var *) copyObject(node); - if (var->varlevelsup == context->sublevels_up && + if (var->varlevelsup == 0 && var->varno == appinfo->parent_relid) { var->varno = appinfo->child_relid; @@ -1793,7 +1796,6 @@ adjust_appendrel_attrs_mutator(Node *node, if (newnode == NULL) elog(ERROR, "attribute %d of relation \"%s\" does not exist", var->varattno, get_rel_name(appinfo->parent_reloid)); - ((Var *) newnode)->varlevelsup += context->sublevels_up; return newnode; } else if (var->varattno == 0) @@ -1836,17 +1838,10 @@ adjust_appendrel_attrs_mutator(Node *node, RowExpr *rowexpr; List *fields; RangeTblEntry *rte; - ListCell *lc; rte = rt_fetch(appinfo->parent_relid, context->root->parse->rtable); fields = (List *) copyObject(appinfo->translated_vars); - foreach(lc, fields) - { - Var *field = (Var *) lfirst(lc); - - field->varlevelsup += context->sublevels_up; - } rowexpr = makeNode(RowExpr); rowexpr->args = fields; rowexpr->row_typeid = var->vartype; @@ -1865,8 +1860,7 @@ adjust_appendrel_attrs_mutator(Node *node, { CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node); - if (context->sublevels_up == 0 && - cexpr->cvarno == appinfo->parent_relid) + if (cexpr->cvarno == appinfo->parent_relid) cexpr->cvarno = appinfo->child_relid; return (Node *) cexpr; } @@ -1874,8 +1868,7 @@ adjust_appendrel_attrs_mutator(Node *node, { RangeTblRef *rtr = (RangeTblRef *) copyObject(node); - if (context->sublevels_up == 0 && - rtr->rtindex == appinfo->parent_relid) + if (rtr->rtindex == appinfo->parent_relid) rtr->rtindex = appinfo->child_relid; return (Node *) rtr; } @@ -1888,8 +1881,7 @@ adjust_appendrel_attrs_mutator(Node *node, adjust_appendrel_attrs_mutator, (void *) context); /* now fix JoinExpr's rtindex (probably never happens) */ - if (context->sublevels_up == 0 && - j->rtindex == appinfo->parent_relid) + if (j->rtindex == appinfo->parent_relid) j->rtindex = appinfo->child_relid; return (Node *) j; } @@ -1902,7 +1894,7 @@ adjust_appendrel_attrs_mutator(Node *node, adjust_appendrel_attrs_mutator, (void *) context); /* now fix PlaceHolderVar's relid sets */ - if (phv->phlevelsup == context->sublevels_up) + if (phv->phlevelsup == 0) phv->phrels = adjust_relid_set(phv->phrels, appinfo->parent_relid, appinfo->child_relid); @@ -1973,29 +1965,12 @@ adjust_appendrel_attrs_mutator(Node *node, return (Node *) newinfo; } - if (IsA(node, Query)) - { - /* - * Recurse into sublink subqueries. This should only be possible in - * security barrier quals of top-level RTEs. All other sublinks should - * have already been converted to subplans during expression - * preprocessing, but this doesn't happen for security barrier quals, - * since they are destined to become quals of a subquery RTE, which - * will be recursively planned, and so should not be preprocessed at - * this stage. - * - * We don't explicitly Assert() for securityQuals here simply because - * it's not trivial to do so. - */ - Query *newnode; - - context->sublevels_up++; - newnode = query_tree_mutator((Query *) node, - adjust_appendrel_attrs_mutator, - (void *) context, 0); - context->sublevels_up--; - return (Node *) newnode; - } + /* + * NOTE: we do not need to recurse into sublinks, because they should + * already have been converted to subplans before we see them. + */ + Assert(!IsA(node, SubLink)); + Assert(!IsA(node, Query)); return expression_tree_mutator(node, adjust_appendrel_attrs_mutator, (void *) context); diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 4e23898ff9..d589dc2544 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -3,7 +3,7 @@ * clauses.c * routines to manipulate qualification clauses * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -91,20 +91,20 @@ typedef struct typedef struct { - bool allow_restricted; -} has_parallel_hazard_arg; + char max_hazard; /* worst proparallel hazard found so far */ + char max_interesting; /* worst proparallel hazard of interest */ +} max_parallel_hazard_context; static bool contain_agg_clause_walker(Node *node, void *context); static bool get_agg_clause_costs_walker(Node *node, get_agg_clause_costs_context *context); static bool find_window_functions_walker(Node *node, WindowFuncLists *lists); -static bool expression_returns_set_rows_walker(Node *node, double *count); static bool contain_subplans_walker(Node *node, void *context); static bool contain_mutable_functions_walker(Node *node, void *context); static bool contain_volatile_functions_walker(Node *node, void *context); static bool contain_volatile_functions_not_nextval_walker(Node *node, void *context); -static bool has_parallel_hazard_walker(Node *node, - has_parallel_hazard_arg *context); +static bool max_parallel_hazard_walker(Node *node, + max_parallel_hazard_context *context); static bool contain_nonstrict_functions_walker(Node *node, void *context); static bool contain_context_dependent_node(Node *clause); static bool contain_context_dependent_node_walker(Node *node, int *flags); @@ -646,6 +646,16 @@ get_agg_clause_costs_walker(Node *node, get_agg_clause_costs_context *context) /* Use average width if aggregate definition gave one */ if (aggtransspace > 0) avgwidth = aggtransspace; + else if (aggtransfn == F_ARRAY_APPEND) + { + /* + * If the transition function is array_append(), it'll use an + * expanded array as transvalue, which will occupy at least + * ALLOCSET_SMALL_INITSIZE and possibly more. Use that as the + * estimate for lack of a better idea. + */ + avgwidth = ALLOCSET_SMALL_INITSIZE; + } else { /* @@ -779,114 +789,37 @@ find_window_functions_walker(Node *node, WindowFuncLists *lists) /* * expression_returns_set_rows * Estimate the number of rows returned by a set-returning expression. - * The result is 1 if there are no set-returning functions. + * The result is 1 if it's not a set-returning expression. * - * We use the product of the rowcount estimates of all the functions in - * the given tree (this corresponds to the behavior of ExecMakeFunctionResult - * for nested set-returning functions). + * We should only examine the top-level function or operator; it used to be + * appropriate to recurse, but not anymore. (Even if there are more SRFs in + * the function's inputs, their multipliers are accounted for separately.) * * Note: keep this in sync with expression_returns_set() in nodes/nodeFuncs.c. */ double expression_returns_set_rows(Node *clause) { - double result = 1; - - (void) expression_returns_set_rows_walker(clause, &result); - return clamp_row_est(result); -} - -static bool -expression_returns_set_rows_walker(Node *node, double *count) -{ - if (node == NULL) - return false; - if (IsA(node, FuncExpr)) + if (clause == NULL) + return 1.0; + if (IsA(clause, FuncExpr)) { - FuncExpr *expr = (FuncExpr *) node; + FuncExpr *expr = (FuncExpr *) clause; if (expr->funcretset) - *count *= get_func_rows(expr->funcid); + return clamp_row_est(get_func_rows(expr->funcid)); } - if (IsA(node, OpExpr)) + if (IsA(clause, OpExpr)) { - OpExpr *expr = (OpExpr *) node; + OpExpr *expr = (OpExpr *) clause; if (expr->opretset) { set_opfuncid(expr); - *count *= get_func_rows(expr->opfuncid); + return clamp_row_est(get_func_rows(expr->opfuncid)); } } - - /* Avoid recursion for some cases that can't return a set */ - if (IsA(node, Aggref)) - return false; - if (IsA(node, WindowFunc)) - return false; - if (IsA(node, DistinctExpr)) - return false; - if (IsA(node, NullIfExpr)) - return false; - if (IsA(node, ScalarArrayOpExpr)) - return false; - if (IsA(node, BoolExpr)) - return false; - if (IsA(node, SubLink)) - return false; - if (IsA(node, SubPlan)) - return false; - if (IsA(node, AlternativeSubPlan)) - return false; - if (IsA(node, ArrayExpr)) - return false; - if (IsA(node, RowExpr)) - return false; - if (IsA(node, RowCompareExpr)) - return false; - if (IsA(node, CoalesceExpr)) - return false; - if (IsA(node, MinMaxExpr)) - return false; - if (IsA(node, XmlExpr)) - return false; - - return expression_tree_walker(node, expression_returns_set_rows_walker, - (void *) count); -} - -/* - * tlist_returns_set_rows - * Estimate the number of rows returned by a set-returning targetlist. - * The result is 1 if there are no set-returning functions. - * - * Here, the result is the largest rowcount estimate of any of the tlist's - * expressions, not the product as you would get from naively applying - * expression_returns_set_rows() to the whole tlist. The behavior actually - * implemented by ExecTargetList produces a number of rows equal to the least - * common multiple of the expression rowcounts, so that the product would be - * a worst-case estimate that is typically not realistic. Taking the max as - * we do here is a best-case estimate that might not be realistic either, - * but it's probably closer for typical usages. We don't try to compute the - * actual LCM because we're working with very approximate estimates, so their - * LCM would be unduly noisy. - */ -double -tlist_returns_set_rows(List *tlist) -{ - double result = 1; - ListCell *lc; - - foreach(lc, tlist) - { - TargetEntry *tle = (TargetEntry *) lfirst(lc); - double colresult; - - colresult = expression_returns_set_rows((Node *) tle->expr); - if (result < colresult) - result = colresult; - } - return result; + return 1.0; } @@ -962,6 +895,12 @@ contain_mutable_functions_walker(Node *node, void *context) context)) return true; + if (IsA(node, SQLValueFunction)) + { + /* all variants of SQLValueFunction are stable */ + return true; + } + /* * It should be safe to treat MinMaxExpr as immutable, because it will * depend on a non-cross-type btree comparison function, and those should @@ -1031,7 +970,8 @@ contain_volatile_functions_walker(Node *node, void *context) /* * See notes in contain_mutable_functions_walker about why we treat - * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable. + * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while + * SQLValueFunction is stable. Hence, none of them are of interest here. */ /* Recurse to check arguments */ @@ -1076,7 +1016,8 @@ contain_volatile_functions_not_nextval_walker(Node *node, void *context) /* * See notes in contain_mutable_functions_walker about why we treat - * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable. + * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while + * SQLValueFunction is stable. Hence, none of them are of interest here. */ /* Recurse to check arguments */ @@ -1092,46 +1033,104 @@ contain_volatile_functions_not_nextval_walker(Node *node, void *context) context); } + /***************************************************************************** * Check queries for parallel unsafe and/or restricted constructs *****************************************************************************/ /* - * Check whether a node tree contains parallel hazards. This is used both on - * the entire query tree, to see whether the query can be parallelized at all - * (with allow_restricted = true), and also to evaluate whether a particular - * expression is safe to run within a parallel worker (with allow_restricted = - * false). We could separate these concerns into two different functions, but - * there's enough overlap that it doesn't seem worthwhile. + * max_parallel_hazard + * Find the worst parallel-hazard level in the given query + * + * Returns the worst function hazard property (the earliest in this list: + * PROPARALLEL_UNSAFE, PROPARALLEL_RESTRICTED, PROPARALLEL_SAFE) that can + * be found in the given parsetree. We use this to find out whether the query + * can be parallelized at all. The caller will also save the result in + * PlannerGlobal so as to short-circuit checks of portions of the querytree + * later, in the common case where everything is SAFE. + */ +char +max_parallel_hazard(Query *parse) +{ + max_parallel_hazard_context context; + + context.max_hazard = PROPARALLEL_SAFE; + context.max_interesting = PROPARALLEL_UNSAFE; + (void) max_parallel_hazard_walker((Node *) parse, &context); + return context.max_hazard; +} + +/* + * is_parallel_safe + * Detect whether the given expr contains only parallel-safe functions + * + * root->glob->maxParallelHazard must previously have been set to the + * result of max_parallel_hazard() on the whole query. */ bool -has_parallel_hazard(Node *node, bool allow_restricted) +is_parallel_safe(PlannerInfo *root, Node *node) { - has_parallel_hazard_arg context; + max_parallel_hazard_context context; - context.allow_restricted = allow_restricted; - return has_parallel_hazard_walker(node, &context); + /* + * Even if the original querytree contained nothing unsafe, we need to + * search the expression if we have generated any PARAM_EXEC Params while + * planning, because those are parallel-restricted and there might be one + * in this expression. But otherwise we don't need to look. + */ + if (root->glob->maxParallelHazard == PROPARALLEL_SAFE && + root->glob->nParamExec == 0) + return true; + /* Else use max_parallel_hazard's search logic, but stop on RESTRICTED */ + context.max_hazard = PROPARALLEL_SAFE; + context.max_interesting = PROPARALLEL_RESTRICTED; + return !max_parallel_hazard_walker(node, &context); } +/* core logic for all parallel-hazard checks */ static bool -has_parallel_hazard_checker(Oid func_id, void *context) +max_parallel_hazard_test(char proparallel, max_parallel_hazard_context *context) { - char proparallel = func_parallel(func_id); + switch (proparallel) + { + case PROPARALLEL_SAFE: + /* nothing to see here, move along */ + break; + case PROPARALLEL_RESTRICTED: + /* increase max_hazard to RESTRICTED */ + Assert(context->max_hazard != PROPARALLEL_UNSAFE); + context->max_hazard = proparallel; + /* done if we are not expecting any unsafe functions */ + if (context->max_interesting == proparallel) + return true; + break; + case PROPARALLEL_UNSAFE: + context->max_hazard = proparallel; + /* we're always done at the first unsafe construct */ + return true; + default: + elog(ERROR, "unrecognized proparallel value \"%c\"", proparallel); + break; + } + return false; +} - if (((has_parallel_hazard_arg *) context)->allow_restricted) - return (proparallel == PROPARALLEL_UNSAFE); - else - return (proparallel != PROPARALLEL_SAFE); +/* check_functions_in_node callback */ +static bool +max_parallel_hazard_checker(Oid func_id, void *context) +{ + return max_parallel_hazard_test(func_parallel(func_id), + (max_parallel_hazard_context *) context); } static bool -has_parallel_hazard_walker(Node *node, has_parallel_hazard_arg *context) +max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context) { if (node == NULL) return false; /* Check for hazardous functions in node itself */ - if (check_functions_in_node(node, has_parallel_hazard_checker, + if (check_functions_in_node(node, max_parallel_hazard_checker, context)) return true; @@ -1143,11 +1142,12 @@ has_parallel_hazard_walker(Node *node, has_parallel_hazard_arg *context) * (Note: in principle that's wrong because a domain constraint could * contain a parallel-unsafe function; but useful constraints probably * never would have such, and assuming they do would cripple use of - * parallel query in the presence of domain types.) + * parallel query in the presence of domain types.) SQLValueFunction + * should be safe in all cases. */ if (IsA(node, CoerceToDomain)) { - if (!context->allow_restricted) + if (max_parallel_hazard_test(PROPARALLEL_RESTRICTED, context)) return true; } @@ -1158,7 +1158,7 @@ has_parallel_hazard_walker(Node *node, has_parallel_hazard_arg *context) { RestrictInfo *rinfo = (RestrictInfo *) node; - return has_parallel_hazard_walker((Node *) rinfo->clause, context); + return max_parallel_hazard_walker((Node *) rinfo->clause, context); } /* @@ -1167,13 +1167,13 @@ has_parallel_hazard_walker(Node *node, has_parallel_hazard_arg *context) * not worry about examining their contents; if they are unsafe, we would * have found that out while examining the whole tree before reduction of * sublinks to subplans. (Really we should not see SubLink during a - * not-allow_restricted scan, but if we do, return true.) + * max_interesting == restricted scan, but if we do, return true.) */ else if (IsA(node, SubLink) || IsA(node, SubPlan) || IsA(node, AlternativeSubPlan)) { - if (!context->allow_restricted) + if (max_parallel_hazard_test(PROPARALLEL_RESTRICTED, context)) return true; } @@ -1183,7 +1183,7 @@ has_parallel_hazard_walker(Node *node, has_parallel_hazard_arg *context) */ else if (IsA(node, Param)) { - if (!context->allow_restricted) + if (max_parallel_hazard_test(PROPARALLEL_RESTRICTED, context)) return true; } @@ -1198,20 +1198,24 @@ has_parallel_hazard_walker(Node *node, has_parallel_hazard_arg *context) /* SELECT FOR UPDATE/SHARE must be treated as unsafe */ if (query->rowMarks != NULL) + { + context->max_hazard = PROPARALLEL_UNSAFE; return true; + } /* Recurse into subselects */ return query_tree_walker(query, - has_parallel_hazard_walker, + max_parallel_hazard_walker, context, 0); } /* Recurse to check arguments */ return expression_tree_walker(node, - has_parallel_hazard_walker, + max_parallel_hazard_walker, context); } + /***************************************************************************** * Check clauses for nonstrict functions *****************************************************************************/ @@ -1418,10 +1422,8 @@ contain_context_dependent_node_walker(Node *node, int *flags) * * Returns true if the clause contains any non-leakproof functions that are * passed Var nodes of the current query level, and which might therefore leak - * data. Qualifiers from outside a security_barrier view that might leak data - * in this way should not be pushed down into the view in case the contents of - * tuples intended to be filtered out by the view are revealed by the leaky - * functions. + * data. Such clauses must be applied after any lower-level security barrier + * clauses. */ bool contain_leaked_vars(Node *clause) @@ -1458,6 +1460,7 @@ contain_leaked_vars_walker(Node *node, void *context) case T_CaseTestExpr: case T_RowExpr: case T_MinMaxExpr: + case T_SQLValueFunction: case T_NullTest: case T_BooleanTest: case T_List: @@ -1515,10 +1518,10 @@ contain_leaked_vars_walker(Node *node, void *context) case T_CurrentOfExpr: /* - * WHERE CURRENT OF doesn't contain function calls. Moreover, it - * is important that this can be pushed down into a - * security_barrier view, since the planner must always generate a - * TID scan when CURRENT OF is present -- c.f. cost_tidscan. + * WHERE CURRENT OF doesn't contain leaky function calls. + * Moreover, it is essential that this is considered non-leaky, + * since the planner must always generate a TID scan when CURRENT + * OF is present -- c.f. cost_tidscan. */ return false; @@ -3263,6 +3266,23 @@ eval_const_expressions_mutator(Node *node, newcoalesce->location = coalesceexpr->location; return (Node *) newcoalesce; } + case T_SQLValueFunction: + { + /* + * All variants of SQLValueFunction are stable, so if we are + * estimating the expression's value, we should evaluate the + * current function value. Otherwise just copy. + */ + SQLValueFunction *svf = (SQLValueFunction *) node; + + if (context->estimate) + return (Node *) evaluate_expr((Expr *) svf, + svf->type, + svf->typmod, + InvalidOid); + else + return copyObject((Node *) svf); + } case T_FieldSelect: { /* @@ -4311,9 +4331,7 @@ inline_function(Oid funcid, Oid result_type, Oid result_collid, */ mycxt = AllocSetContextCreate(CurrentMemoryContext, "inline_function", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldcxt = MemoryContextSwitchTo(mycxt); /* Fetch the function body */ @@ -4381,9 +4399,9 @@ inline_function(Oid funcid, Oid result_type, Oid result_collid, */ if (!IsA(querytree, Query) || querytree->commandType != CMD_SELECT || - querytree->utilityStmt || querytree->hasAggs || querytree->hasWindowFuncs || + querytree->hasTargetSRFs || querytree->hasSubLinks || querytree->cteList || querytree->rtable || @@ -4424,17 +4442,13 @@ inline_function(Oid funcid, Oid result_type, Oid result_collid, Assert(!modifyTargetList); /* - * Additional validity checks on the expression. It mustn't return a set, - * and it mustn't be more volatile than the surrounding function (this is - * to avoid breaking hacks that involve pretending a function is immutable - * when it really ain't). If the surrounding function is declared strict, - * then the expression must contain only strict constructs and must use - * all of the function parameters (this is overkill, but an exact analysis - * is hard). + * Additional validity checks on the expression. It mustn't be more + * volatile than the surrounding function (this is to avoid breaking hacks + * that involve pretending a function is immutable when it really ain't). + * If the surrounding function is declared strict, then the expression + * must contain only strict constructs and must use all of the function + * parameters (this is overkill, but an exact analysis is hard). */ - if (expression_returns_set(newexpr)) - goto fail; - if (funcform->provolatile == PROVOLATILE_IMMUTABLE && contain_mutable_functions(newexpr)) goto fail; @@ -4671,7 +4685,7 @@ evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod, */ const_val = ExecEvalExprSwitchContext(exprstate, GetPerTupleExprContext(estate), - &const_is_null, NULL); + &const_is_null); /* Get info needed about result datatype */ get_typlenbyval(result_type, &resultTypLen, &resultTypByVal); @@ -4829,9 +4843,7 @@ inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte) */ mycxt = AllocSetContextCreate(CurrentMemoryContext, "inline_set_returning_function", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldcxt = MemoryContextSwitchTo(mycxt); /* @@ -4913,8 +4925,7 @@ inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte) * The single command must be a plain SELECT. */ if (!IsA(querytree, Query) || - querytree->commandType != CMD_SELECT || - querytree->utilityStmt) + querytree->commandType != CMD_SELECT) goto fail; /* diff --git a/src/backend/optimizer/util/joininfo.c b/src/backend/optimizer/util/joininfo.c index 97d5fba391..6d84477f86 100644 --- a/src/backend/optimizer/util/joininfo.c +++ b/src/backend/optimizer/util/joininfo.c @@ -3,7 +3,7 @@ * joininfo.c * joininfo list manipulation routines * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/util/orclauses.c b/src/backend/optimizer/util/orclauses.c index 13570f006e..c965bb678d 100644 --- a/src/backend/optimizer/util/orclauses.c +++ b/src/backend/optimizer/util/orclauses.c @@ -3,7 +3,7 @@ * orclauses.c * Routines to extract restriction OR clauses from join OR clauses * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -270,6 +270,7 @@ consider_new_or_clause(PlannerInfo *root, RelOptInfo *rel, true, false, false, + join_or_rinfo->security_level, NULL, NULL, NULL); @@ -296,6 +297,8 @@ consider_new_or_clause(PlannerInfo *root, RelOptInfo *rel, * OK, add it to the rel's restriction-clause list. */ rel->baserestrictinfo = lappend(rel->baserestrictinfo, or_rinfo); + rel->baserestrict_min_security = Min(rel->baserestrict_min_security, + or_rinfo->security_level); /* * Adjust the original join OR clause's cached selectivity to compensate diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index ce7ad545a9..f440875ceb 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -3,7 +3,7 @@ * pathnode.c * Routines to manipulate pathlists and create path nodes * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -1333,7 +1333,7 @@ create_merge_append_path(PlannerInfo *root, cost_merge_append(&pathnode->path, root, pathkeys, list_length(subpaths), input_startup_cost, input_total_cost, - rel->tuples); + pathnode->path.rows); return pathnode; } @@ -2178,7 +2178,7 @@ create_projection_path(PlannerInfo *root, pathnode->path.parallel_aware = false; pathnode->path.parallel_safe = rel->consider_parallel && subpath->parallel_safe && - !has_parallel_hazard((Node *) target->exprs, false); + is_parallel_safe(root, (Node *) target->exprs); pathnode->path.parallel_workers = subpath->parallel_workers; /* Projection does not change the sort order */ pathnode->path.pathkeys = subpath->pathkeys; @@ -2285,7 +2285,7 @@ apply_projection_to_path(PlannerInfo *root, * target expressions, then we can't. */ if (IsA(path, GatherPath) && - !has_parallel_hazard((Node *) target->exprs, false)) + is_parallel_safe(root, (Node *) target->exprs)) { GatherPath *gpath = (GatherPath *) path; @@ -2306,7 +2306,7 @@ apply_projection_to_path(PlannerInfo *root, target); } else if (path->parallel_safe && - has_parallel_hazard((Node *) target->exprs, false)) + !is_parallel_safe(root, (Node *) target->exprs)) { /* * We're inserting a parallel-restricted target list into a path @@ -2319,6 +2319,72 @@ apply_projection_to_path(PlannerInfo *root, return path; } +/* + * create_set_projection_path + * Creates a pathnode that represents performing a projection that + * includes set-returning functions. + * + * 'rel' is the parent relation associated with the result + * 'subpath' is the path representing the source of data + * 'target' is the PathTarget to be computed + */ +ProjectSetPath * +create_set_projection_path(PlannerInfo *root, + RelOptInfo *rel, + Path *subpath, + PathTarget *target) +{ + ProjectSetPath *pathnode = makeNode(ProjectSetPath); + double tlist_rows; + ListCell *lc; + + pathnode->path.pathtype = T_ProjectSet; + pathnode->path.parent = rel; + pathnode->path.pathtarget = target; + /* For now, assume we are above any joins, so no parameterization */ + pathnode->path.param_info = NULL; + pathnode->path.parallel_aware = false; + pathnode->path.parallel_safe = rel->consider_parallel && + subpath->parallel_safe && + is_parallel_safe(root, (Node *) target->exprs); + pathnode->path.parallel_workers = subpath->parallel_workers; + /* Projection does not change the sort order XXX? */ + pathnode->path.pathkeys = subpath->pathkeys; + + pathnode->subpath = subpath; + + /* + * Estimate number of rows produced by SRFs for each row of input; if + * there's more than one in this node, use the maximum. + */ + tlist_rows = 1; + foreach(lc, target->exprs) + { + Node *node = (Node *) lfirst(lc); + double itemrows; + + itemrows = expression_returns_set_rows(node); + if (tlist_rows < itemrows) + tlist_rows = itemrows; + } + + /* + * In addition to the cost of evaluating the tlist, charge cpu_tuple_cost + * per input row, and half of cpu_tuple_cost for each added output row. + * This is slightly bizarre maybe, but it's what 9.6 did; we may revisit + * this estimate later. + */ + pathnode->path.rows = subpath->rows * tlist_rows; + pathnode->path.startup_cost = subpath->startup_cost + + target->cost.startup; + pathnode->path.total_cost = subpath->total_cost + + target->cost.startup + + (cpu_tuple_cost + target->cost.per_tuple) * subpath->rows + + (pathnode->path.rows - subpath->rows) * cpu_tuple_cost / 2; + + return pathnode; +} + /* * create_sort_path * Creates a pathnode that represents performing an explicit sort. diff --git a/src/backend/optimizer/util/placeholder.c b/src/backend/optimizer/util/placeholder.c index b210914b85..698a387ac2 100644 --- a/src/backend/optimizer/util/placeholder.c +++ b/src/backend/optimizer/util/placeholder.c @@ -4,7 +4,7 @@ * PlaceHolderVar and PlaceHolderInfo manipulation routines * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 5d18206b91..7836e6b3f8 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -4,7 +4,7 @@ * routines for accessing the system catalogs * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -27,6 +27,7 @@ #include "catalog/catalog.h" #include "catalog/dependency.h" #include "catalog/heap.h" +#include "catalog/partition.h" #include "catalog/pg_am.h" #include "foreign/fdwapi.h" #include "miscadmin.h" @@ -53,7 +54,7 @@ get_relation_info_hook_type get_relation_info_hook = NULL; static void get_relation_foreign_keys(PlannerInfo *root, RelOptInfo *rel, - Relation relation); + Relation relation, bool inhparent); static bool infer_collation_opclass_match(InferenceElem *elem, Relation idxRel, List *idxExprs); static int32 get_rel_data_width(Relation rel, int32 *attr_widths); @@ -78,6 +79,7 @@ static List *build_index_tlist(PlannerInfo *root, IndexOptInfo *index, * fdwroutine if it's a foreign table, the FDW function pointers * pages number of pages * tuples number of tuples + * rel_parallel_workers user-defined number of parallel workers * * Also, add information about the relation's foreign keys to root->fkey_list. * @@ -408,7 +410,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, } /* Collect info about relation's foreign keys, if relevant */ - get_relation_foreign_keys(root, rel, relation); + get_relation_foreign_keys(root, rel, relation, inhparent); heap_close(relation, NoLock); @@ -433,7 +435,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, */ static void get_relation_foreign_keys(PlannerInfo *root, RelOptInfo *rel, - Relation relation) + Relation relation, bool inhparent) { List *rtable = root->parse->rtable; List *cachedfkeys; @@ -448,6 +450,15 @@ get_relation_foreign_keys(PlannerInfo *root, RelOptInfo *rel, list_length(rtable) < 2) return; + /* + * If it's the parent of an inheritance tree, ignore its FKs. We could + * make useful FK-based deductions if we found that all members of the + * inheritance tree have equivalent FK constraints, but detecting that + * would require code that hasn't been written. + */ + if (inhparent) + return; + /* * Extract data about relation's FKs from the relcache. Note that this * list belongs to the relcache and might disappear in a cache flush, so @@ -488,6 +499,9 @@ get_relation_foreign_keys(PlannerInfo *root, RelOptInfo *rel, if (rte->rtekind != RTE_RELATION || rte->relid != cachedfk->confrelid) continue; + /* Ignore if it's an inheritance parent; doesn't really match */ + if (rte->inh) + continue; /* Ignore self-referential FKs; we only care about joins */ if (rti == rel->relid) continue; @@ -1127,6 +1141,7 @@ get_relation_constraints(PlannerInfo *root, Index varno = rel->relid; Relation relation; TupleConstr *constr; + List *pcqual; /* * We assume the relation has already been safely locked. @@ -1212,6 +1227,24 @@ get_relation_constraints(PlannerInfo *root, } } + /* Append partition predicates, if any */ + pcqual = RelationGetPartitionQual(relation); + if (pcqual) + { + /* + * Run each expression through const-simplification and + * canonicalization similar to check constraints. + */ + pcqual = (List *) eval_const_expressions(root, (Node *) pcqual); + pcqual = (List *) canonicalize_qual((Expr *) pcqual); + + /* Fix Vars to have the desired varno */ + if (varno != 1) + ChangeVarNodes((Node *) pcqual, 1, varno, 0); + + result = list_concat(result, pcqual); + } + heap_close(relation, NoLock); return result; diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c index 2c2efb1576..c4a04cfa95 100644 --- a/src/backend/optimizer/util/predtest.c +++ b/src/backend/optimizer/util/predtest.c @@ -4,7 +4,7 @@ * Routines to attempt to prove logical implications between predicate * expressions. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -1596,7 +1596,7 @@ operator_predicate_proof(Expr *predicate, Node *clause, bool refute_it) /* And execute it. */ test_result = ExecEvalExprSwitchContext(test_exprstate, GetPerTupleExprContext(estate), - &isNull, NULL); + &isNull); /* Get back to outer memory context */ MemoryContextSwitchTo(oldcontext); diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 806600ed10..adc1db94f4 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -3,7 +3,7 @@ * relnode.c * Relation-node lookup/construction routines * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -14,6 +14,8 @@ */ #include "postgres.h" +#include + #include "miscadmin.h" #include "optimizer/clauses.h" #include "optimizer/cost.h" @@ -126,7 +128,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind) rel->allvisfrac = 0; rel->subroot = NULL; rel->subplan_params = NIL; - rel->rel_parallel_workers = -1; /* set up in GetRelationInfo */ + rel->rel_parallel_workers = -1; /* set up in get_relation_info */ rel->serverid = InvalidOid; rel->userid = rte->checkAsUser; rel->useridiscurrent = false; @@ -135,6 +137,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind) rel->baserestrictinfo = NIL; rel->baserestrictcost.startup = 0; rel->baserestrictcost.per_tuple = 0; + rel->baserestrict_min_security = UINT_MAX; rel->joininfo = NIL; rel->has_eclass_joins = false; @@ -172,6 +175,16 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind) /* Save the finished struct in the query's simple_rel_array */ root->simple_rel_array[relid] = rel; + /* + * This is a convenient spot at which to note whether rels participating + * in the query have any securityQuals attached. If so, increase + * root->qual_security_level to ensure it's larger than the maximum + * security level needed for securityQuals. + */ + if (rte->securityQuals) + root->qual_security_level = Max(root->qual_security_level, + list_length(rte->securityQuals)); + /* * If this rel is an appendrel parent, recurse to build "other rel" * RelOptInfos for its children. They are "other rels" because they are @@ -407,6 +420,7 @@ build_join_rel(PlannerInfo *root, joinrel->baserestrictinfo = NIL; joinrel->baserestrictcost.startup = 0; joinrel->baserestrictcost.per_tuple = 0; + joinrel->baserestrict_min_security = UINT_MAX; joinrel->joininfo = NIL; joinrel->has_eclass_joins = false; @@ -513,8 +527,8 @@ build_join_rel(PlannerInfo *root, * here. */ if (inner_rel->consider_parallel && outer_rel->consider_parallel && - !has_parallel_hazard((Node *) restrictlist, false) && - !has_parallel_hazard((Node *) joinrel->reltarget->exprs, false)) + is_parallel_safe(root, (Node *) restrictlist) && + is_parallel_safe(root, (Node *) joinrel->reltarget->exprs)) joinrel->consider_parallel = true; /* diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c index 7fc81e7aa3..8f10520f81 100644 --- a/src/backend/optimizer/util/restrictinfo.c +++ b/src/backend/optimizer/util/restrictinfo.c @@ -3,7 +3,7 @@ * restrictinfo.c * RestrictInfo node manipulation routines. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -24,6 +24,7 @@ static RestrictInfo *make_restrictinfo_internal(Expr *clause, bool is_pushed_down, bool outerjoin_delayed, bool pseudoconstant, + Index security_level, Relids required_relids, Relids outer_relids, Relids nullable_relids); @@ -31,6 +32,7 @@ static Expr *make_sub_restrictinfos(Expr *clause, bool is_pushed_down, bool outerjoin_delayed, bool pseudoconstant, + Index security_level, Relids required_relids, Relids outer_relids, Relids nullable_relids); @@ -43,7 +45,7 @@ static Expr *make_sub_restrictinfos(Expr *clause, * * The is_pushed_down, outerjoin_delayed, and pseudoconstant flags for the * RestrictInfo must be supplied by the caller, as well as the correct values - * for outer_relids and nullable_relids. + * for security_level, outer_relids, and nullable_relids. * required_relids can be NULL, in which case it defaults to the actual clause * contents (i.e., clause_relids). * @@ -56,6 +58,7 @@ make_restrictinfo(Expr *clause, bool is_pushed_down, bool outerjoin_delayed, bool pseudoconstant, + Index security_level, Relids required_relids, Relids outer_relids, Relids nullable_relids) @@ -69,6 +72,7 @@ make_restrictinfo(Expr *clause, is_pushed_down, outerjoin_delayed, pseudoconstant, + security_level, required_relids, outer_relids, nullable_relids); @@ -81,64 +85,12 @@ make_restrictinfo(Expr *clause, is_pushed_down, outerjoin_delayed, pseudoconstant, + security_level, required_relids, outer_relids, nullable_relids); } -/* - * make_restrictinfos_from_actual_clauses - * - * Given a list of implicitly-ANDed restriction clauses, produce a list - * of RestrictInfo nodes. This is used to reconstitute the RestrictInfo - * representation after doing transformations of a list of clauses. - * - * We assume that the clauses are relation-level restrictions and therefore - * we don't have to worry about is_pushed_down, outerjoin_delayed, - * outer_relids, and nullable_relids (these can be assumed true, false, - * NULL, and NULL, respectively). - * We do take care to recognize pseudoconstant clauses properly. - */ -List * -make_restrictinfos_from_actual_clauses(PlannerInfo *root, - List *clause_list) -{ - List *result = NIL; - ListCell *l; - - foreach(l, clause_list) - { - Expr *clause = (Expr *) lfirst(l); - bool pseudoconstant; - RestrictInfo *rinfo; - - /* - * It's pseudoconstant if it contains no Vars and no volatile - * functions. We probably can't see any sublinks here, so - * contain_var_clause() would likely be enough, but for safety use - * contain_vars_of_level() instead. - */ - pseudoconstant = - !contain_vars_of_level((Node *) clause, 0) && - !contain_volatile_functions((Node *) clause); - if (pseudoconstant) - { - /* tell createplan.c to check for gating quals */ - root->hasPseudoConstantQuals = true; - } - - rinfo = make_restrictinfo(clause, - true, - false, - pseudoconstant, - NULL, - NULL, - NULL); - result = lappend(result, rinfo); - } - return result; -} - /* * make_restrictinfo_internal * @@ -150,6 +102,7 @@ make_restrictinfo_internal(Expr *clause, bool is_pushed_down, bool outerjoin_delayed, bool pseudoconstant, + Index security_level, Relids required_relids, Relids outer_relids, Relids nullable_relids) @@ -162,9 +115,20 @@ make_restrictinfo_internal(Expr *clause, restrictinfo->outerjoin_delayed = outerjoin_delayed; restrictinfo->pseudoconstant = pseudoconstant; restrictinfo->can_join = false; /* may get set below */ + restrictinfo->security_level = security_level; restrictinfo->outer_relids = outer_relids; restrictinfo->nullable_relids = nullable_relids; + /* + * If it's potentially delayable by lower-level security quals, figure out + * whether it's leakproof. We can skip testing this for level-zero quals, + * since they would never get delayed on security grounds anyway. + */ + if (security_level > 0) + restrictinfo->leakproof = !contain_leaked_vars((Node *) clause); + else + restrictinfo->leakproof = false; /* really, "don't know" */ + /* * If it's a binary opclause, set up left/right relids info. In any case * set up the total clause relids info. @@ -250,7 +214,7 @@ make_restrictinfo_internal(Expr *clause, * * The same is_pushed_down, outerjoin_delayed, and pseudoconstant flag * values can be applied to all RestrictInfo nodes in the result. Likewise - * for outer_relids and nullable_relids. + * for security_level, outer_relids, and nullable_relids. * * The given required_relids are attached to our top-level output, * but any OR-clause constituents are allowed to default to just the @@ -261,6 +225,7 @@ make_sub_restrictinfos(Expr *clause, bool is_pushed_down, bool outerjoin_delayed, bool pseudoconstant, + Index security_level, Relids required_relids, Relids outer_relids, Relids nullable_relids) @@ -276,6 +241,7 @@ make_sub_restrictinfos(Expr *clause, is_pushed_down, outerjoin_delayed, pseudoconstant, + security_level, NULL, outer_relids, nullable_relids)); @@ -284,6 +250,7 @@ make_sub_restrictinfos(Expr *clause, is_pushed_down, outerjoin_delayed, pseudoconstant, + security_level, required_relids, outer_relids, nullable_relids); @@ -299,6 +266,7 @@ make_sub_restrictinfos(Expr *clause, is_pushed_down, outerjoin_delayed, pseudoconstant, + security_level, required_relids, outer_relids, nullable_relids)); @@ -310,6 +278,7 @@ make_sub_restrictinfos(Expr *clause, is_pushed_down, outerjoin_delayed, pseudoconstant, + security_level, required_relids, outer_relids, nullable_relids); @@ -330,42 +299,36 @@ restriction_is_or_clause(RestrictInfo *restrictinfo) } /* - * get_actual_clauses + * restriction_is_securely_promotable * - * Returns a list containing the bare clauses from 'restrictinfo_list'. - * - * This is only to be used in cases where none of the RestrictInfos can - * be pseudoconstant clauses (for instance, it's OK on indexqual lists). + * Returns true if it's okay to evaluate this clause "early", that is before + * other restriction clauses attached to the specified relation. */ -List * -get_actual_clauses(List *restrictinfo_list) +bool +restriction_is_securely_promotable(RestrictInfo *restrictinfo, + RelOptInfo *rel) { - List *result = NIL; - ListCell *l; - - foreach(l, restrictinfo_list) - { - RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); - - Assert(IsA(rinfo, RestrictInfo)); - - Assert(!rinfo->pseudoconstant); - - result = lappend(result, rinfo->clause); - } - return result; + /* + * It's okay if there are no baserestrictinfo clauses for the rel that + * would need to go before this one, *or* if this one is leakproof. + */ + if (restrictinfo->security_level <= rel->baserestrict_min_security || + restrictinfo->leakproof) + return true; + else + return false; } /* - * get_all_actual_clauses + * get_actual_clauses * * Returns a list containing the bare clauses from 'restrictinfo_list'. * - * This loses the distinction between regular and pseudoconstant clauses, - * so be careful what you use it for. + * This is only to be used in cases where none of the RestrictInfos can + * be pseudoconstant clauses (for instance, it's OK on indexqual lists). */ List * -get_all_actual_clauses(List *restrictinfo_list) +get_actual_clauses(List *restrictinfo_list) { List *result = NIL; ListCell *l; @@ -376,6 +339,8 @@ get_all_actual_clauses(List *restrictinfo_list) Assert(IsA(rinfo, RestrictInfo)); + Assert(!rinfo->pseudoconstant); + result = lappend(result, rinfo->clause); } return result; diff --git a/src/backend/optimizer/util/tlist.c b/src/backend/optimizer/util/tlist.c index 68096b309c..cca5db88e2 100644 --- a/src/backend/optimizer/util/tlist.c +++ b/src/backend/optimizer/util/tlist.c @@ -3,7 +3,7 @@ * tlist.c * Target list manipulation routines * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -16,9 +16,20 @@ #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" +#include "optimizer/cost.h" #include "optimizer/tlist.h" +typedef struct +{ + List *nextlevel_tlist; + bool nextlevel_contains_srfs; +} split_pathtarget_context; + +static bool split_pathtarget_walker(Node *node, + split_pathtarget_context *context); + + /***************************************************************************** * Target list creation and searching utilities *****************************************************************************/ @@ -759,3 +770,191 @@ apply_pathtarget_labeling_to_tlist(List *tlist, PathTarget *target) i++; } } + +/* + * split_pathtarget_at_srfs + * Split given PathTarget into multiple levels to position SRFs safely + * + * The executor can only handle set-returning functions that appear at the + * top level of the targetlist of a ProjectSet plan node. If we have any SRFs + * that are not at top level, we need to split up the evaluation into multiple + * plan levels in which each level satisfies this constraint. This function + * creates appropriate PathTarget(s) for each level. + * + * As an example, consider the tlist expression + * x + srf1(srf2(y + z)) + * This expression should appear as-is in the top PathTarget, but below that + * we must have a PathTarget containing + * x, srf1(srf2(y + z)) + * and below that, another PathTarget containing + * x, srf2(y + z) + * and below that, another PathTarget containing + * x, y, z + * When these tlists are processed by setrefs.c, subexpressions that match + * output expressions of the next lower tlist will be replaced by Vars, + * so that what the executor gets are tlists looking like + * Var1 + Var2 + * Var1, srf1(Var2) + * Var1, srf2(Var2 + Var3) + * x, y, z + * which satisfy the desired property. + * + * In some cases, a SRF has already been evaluated in some previous plan level + * and we shouldn't expand it again (that is, what we see in the target is + * already meant as a reference to a lower subexpression). So, don't expand + * any tlist expressions that appear in input_target, if that's not NULL. + * In principle we might need to consider matching subexpressions to + * input_target, but for now it's not necessary because only ORDER BY and + * GROUP BY expressions are at issue and those will look the same at both + * plan levels. + * + * The outputs of this function are two parallel lists, one a list of + * PathTargets and the other an integer list of bool flags indicating + * whether the corresponding PathTarget contains any top-level SRFs. + * The lists are given in the order they'd need to be evaluated in, with + * the "lowest" PathTarget first. So the last list entry is always the + * originally given PathTarget, and any entries before it indicate evaluation + * levels that must be inserted below it. The first list entry must not + * contain any SRFs, since it will typically be attached to a plan node + * that cannot evaluate SRFs. + * + * Note: using a list for the flags may seem like overkill, since there + * are only a few possible patterns for which levels contain SRFs. + * But this representation decouples callers from that knowledge. + */ +void +split_pathtarget_at_srfs(PlannerInfo *root, + PathTarget *target, PathTarget *input_target, + List **targets, List **targets_contain_srfs) +{ + /* Initialize output lists to empty; we prepend to them within loop */ + *targets = *targets_contain_srfs = NIL; + + /* Loop to consider each level of PathTarget we need */ + for (;;) + { + bool target_contains_srfs = false; + split_pathtarget_context context; + ListCell *lc; + + context.nextlevel_tlist = NIL; + context.nextlevel_contains_srfs = false; + + /* + * Scan the PathTarget looking for SRFs. Top-level SRFs are handled + * in this loop, ones lower down are found by split_pathtarget_walker. + */ + foreach(lc, target->exprs) + { + Node *node = (Node *) lfirst(lc); + + /* + * A tlist item that is just a reference to an expression already + * computed in input_target need not be evaluated here, so just + * make sure it's included in the next PathTarget. + */ + if (input_target && list_member(input_target->exprs, node)) + { + context.nextlevel_tlist = lappend(context.nextlevel_tlist, node); + continue; + } + + /* Else, we need to compute this expression. */ + if (IsA(node, FuncExpr) && + ((FuncExpr *) node)->funcretset) + { + /* Top-level SRF: it can be evaluated here */ + target_contains_srfs = true; + /* Recursively examine SRF's inputs */ + split_pathtarget_walker((Node *) ((FuncExpr *) node)->args, + &context); + } + else if (IsA(node, OpExpr) && + ((OpExpr *) node)->opretset) + { + /* Same as above, but for set-returning operator */ + target_contains_srfs = true; + split_pathtarget_walker((Node *) ((OpExpr *) node)->args, + &context); + } + else + { + /* Not a top-level SRF, so recursively examine expression */ + split_pathtarget_walker(node, &context); + } + } + + /* + * Prepend current target and associated flag to output lists. + */ + *targets = lcons(target, *targets); + *targets_contain_srfs = lcons_int(target_contains_srfs, + *targets_contain_srfs); + + /* + * Done if we found no SRFs anywhere in this target; the tentative + * tlist we built for the next level can be discarded. + */ + if (!target_contains_srfs && !context.nextlevel_contains_srfs) + break; + + /* + * Else build the next PathTarget down, and loop back to process it. + * Copy the subexpressions to make sure PathTargets don't share + * substructure (might be unnecessary, but be safe); and drop any + * duplicate entries in the sub-targetlist. + */ + target = create_empty_pathtarget(); + add_new_columns_to_pathtarget(target, + (List *) copyObject(context.nextlevel_tlist)); + set_pathtarget_cost_width(root, target); + } +} + +/* Recursively examine expressions for split_pathtarget_at_srfs */ +static bool +split_pathtarget_walker(Node *node, split_pathtarget_context *context) +{ + if (node == NULL) + return false; + if (IsA(node, Var) || + IsA(node, PlaceHolderVar) || + IsA(node, Aggref) || + IsA(node, GroupingFunc) || + IsA(node, WindowFunc)) + { + /* + * Pass these items down to the child plan level for evaluation. + * + * We assume that these constructs cannot contain any SRFs (if one + * does, there will be an executor failure from a misplaced SRF). + */ + context->nextlevel_tlist = lappend(context->nextlevel_tlist, node); + + /* Having done that, we need not examine their sub-structure */ + return false; + } + else if ((IsA(node, FuncExpr) && + ((FuncExpr *) node)->funcretset) || + (IsA(node, OpExpr) && + ((OpExpr *) node)->opretset)) + { + /* + * Pass SRFs down to the child plan level for evaluation, and mark + * that it contains SRFs. (We are not at top level of our own tlist, + * else this would have been picked up by split_pathtarget_at_srfs.) + */ + context->nextlevel_tlist = lappend(context->nextlevel_tlist, node); + context->nextlevel_contains_srfs = true; + + /* Inputs to the SRF need not be considered here, so we're done */ + return false; + } + + /* + * Otherwise, the node is evaluatable within the current PathTarget, so + * recurse to examine its inputs. + */ + return expression_tree_walker(node, split_pathtarget_walker, + (void *) context); +} diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index 292e1f4aac..cf326ae003 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -9,7 +9,7 @@ * contains variables. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index eac86cce3e..a02a77a03a 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -14,7 +14,7 @@ * contain optimizable statements, which we should transform. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/parser/analyze.c @@ -48,6 +48,7 @@ /* Hook for plugins to get control at end of parse analysis */ post_parse_analyze_hook_type post_parse_analyze_hook = NULL; +static Query *transformOptionalSelectInto(ParseState *pstate, Node *parseTree); static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt); static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt); static List *transformInsertRow(ParseState *pstate, List *exprlist, @@ -92,7 +93,7 @@ static bool test_raw_expression_coverage(Node *node, void *context); * a dummy CMD_UTILITY Query node. */ Query * -parse_analyze(Node *parseTree, const char *sourceText, +parse_analyze(RawStmt *parseTree, const char *sourceText, Oid *paramTypes, int numParams) { ParseState *pstate = make_parsestate(NULL); @@ -123,7 +124,7 @@ parse_analyze(Node *parseTree, const char *sourceText, * be modified or enlarged (via repalloc). */ Query * -parse_analyze_varparams(Node *parseTree, const char *sourceText, +parse_analyze_varparams(RawStmt *parseTree, const char *sourceText, Oid **paramTypes, int *numParams) { ParseState *pstate = make_parsestate(NULL); @@ -174,14 +175,35 @@ parse_sub_analyze(Node *parseTree, ParseState *parentParseState, * transformTopLevelStmt - * transform a Parse tree into a Query tree. * + * This function is just responsible for transferring statement location data + * from the RawStmt into the finished Query. + */ +Query * +transformTopLevelStmt(ParseState *pstate, RawStmt *parseTree) +{ + Query *result; + + /* We're at top level, so allow SELECT INTO */ + result = transformOptionalSelectInto(pstate, parseTree->stmt); + + result->stmt_location = parseTree->stmt_location; + result->stmt_len = parseTree->stmt_len; + + return result; +} + +/* + * transformOptionalSelectInto - + * If SELECT has INTO, convert it to CREATE TABLE AS. + * * The only thing we do here that we don't do in transformStmt() is to * convert SELECT ... INTO into CREATE TABLE AS. Since utility statements * aren't allowed within larger statements, this is only allowed at the top * of the parse tree, and so we only try it before entering the recursive * transformStmt() processing. */ -Query * -transformTopLevelStmt(ParseState *pstate, Node *parseTree) +static Query * +transformOptionalSelectInto(ParseState *pstate, Node *parseTree) { if (IsA(parseTree, SelectStmt)) { @@ -318,11 +340,11 @@ transformStmt(ParseState *pstate, Node *parseTree) * Classification here should match transformStmt(). */ bool -analyze_requires_snapshot(Node *parseTree) +analyze_requires_snapshot(RawStmt *parseTree) { bool result; - switch (nodeTag(parseTree)) + switch (nodeTag(parseTree->stmt)) { /* * Optimizable statements @@ -338,10 +360,6 @@ analyze_requires_snapshot(Node *parseTree) * Special cases */ case T_DeclareCursorStmt: - /* yes, because it's analyzed just like SELECT */ - result = true; - break; - case T_ExplainStmt: case T_CreateTableAsStmt: /* yes, because we must analyze the contained statement */ @@ -380,7 +398,7 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt) /* set up range table with just the result rel */ qry->resultRelation = setTargetTable(pstate, stmt->relation, - interpretInhOption(stmt->relation->inhOpt), + stmt->relation->inh, true, ACL_DELETE); @@ -417,6 +435,7 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt) qry->hasSubLinks = pstate->p_hasSubLinks; qry->hasWindowFuncs = pstate->p_hasWindowFuncs; + qry->hasTargetSRFs = pstate->p_hasTargetSRFs; qry->hasAggs = pstate->p_hasAggs; if (pstate->p_hasAggs) parseCheckAggregates(pstate, qry); @@ -562,8 +581,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt) /* The grammar should have produced a SELECT */ if (!IsA(selectQuery, Query) || - selectQuery->commandType != CMD_SELECT || - selectQuery->utilityStmt != NULL) + selectQuery->commandType != CMD_SELECT) elog(ERROR, "unexpected non-SELECT command in INSERT ... SELECT"); /* @@ -632,10 +650,11 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt) * RTE. */ List *exprsLists = NIL; - List *collations = NIL; + List *coltypes = NIL; + List *coltypmods = NIL; + List *colcollations = NIL; int sublist_length = -1; bool lateral = false; - int i; Assert(selectStmt->intoClause == NULL); @@ -643,8 +662,12 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt) { List *sublist = (List *) lfirst(lc); - /* Do basic expression transformation (same as a ROW() expr) */ - sublist = transformExpressionList(pstate, sublist, EXPR_KIND_VALUES); + /* + * Do basic expression transformation (same as a ROW() expr, but + * allow SetToDefault at top level) + */ + sublist = transformExpressionList(pstate, sublist, + EXPR_KIND_VALUES, true); /* * All the sublists must be the same length, *after* @@ -698,11 +721,20 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt) } /* - * Although we don't really need collation info, let's just make sure - * we provide a correctly-sized list in the VALUES RTE. + * Construct column type/typmod/collation lists for the VALUES RTE. + * Every expression in each column has been coerced to the type/typmod + * of the corresponding target column or subfield, so it's sufficient + * to look at the exprType/exprTypmod of the first row. We don't care + * about the collation labeling, so just fill in InvalidOid for that. */ - for (i = 0; i < sublist_length; i++) - collations = lappend_oid(collations, InvalidOid); + foreach(lc, (List *) linitial(exprsLists)) + { + Node *val = (Node *) lfirst(lc); + + coltypes = lappend_oid(coltypes, exprType(val)); + coltypmods = lappend_int(coltypmods, exprTypmod(val)); + colcollations = lappend_oid(colcollations, InvalidOid); + } /* * Ordinarily there can't be any current-level Vars in the expression @@ -717,7 +749,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt) /* * Generate the VALUES RTE */ - rte = addRangeTableEntryForValues(pstate, exprsLists, collations, + rte = addRangeTableEntryForValues(pstate, exprsLists, + coltypes, coltypmods, colcollations, NULL, lateral, true); rtr = makeNode(RangeTblRef); /* assume new rte is at end */ @@ -751,10 +784,14 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt) Assert(list_length(valuesLists) == 1); Assert(selectStmt->intoClause == NULL); - /* Do basic expression transformation (same as a ROW() expr) */ + /* + * Do basic expression transformation (same as a ROW() expr, but allow + * SetToDefault at top level) + */ exprList = transformExpressionList(pstate, (List *) linitial(valuesLists), - EXPR_KIND_VALUES); + EXPR_KIND_VALUES_SINGLE, + true); /* Prepare row for assignment to target table */ exprList = transformInsertRow(pstate, exprList, @@ -797,8 +834,16 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt) /* Process ON CONFLICT, if any. */ if (stmt->onConflictClause) + { + /* Bail out if target relation is partitioned table */ + if (pstate->p_target_rangetblentry->relkind == RELKIND_PARTITIONED_TABLE) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("ON CONFLICT clause is not supported with partitioned tables"))); + qry->onConflict = transformOnConflictClause(pstate, stmt->onConflictClause); + } /* * If we have a RETURNING clause, we need to add the target relation to @@ -819,6 +864,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt) qry->rtable = pstate->p_rtable; qry->jointree = makeFromExpr(pstate->p_joinlist, NULL); + qry->hasTargetSRFs = pstate->p_hasTargetSRFs; qry->hasSubLinks = pstate->p_hasSubLinks; assign_query_collations(pstate, qry); @@ -938,7 +984,7 @@ transformInsertRow(ParseState *pstate, List *exprlist, } /* - * transformSelectStmt - + * transformOnConflictClause - * transforms an OnConflictClause in an INSERT */ static OnConflictExpr * @@ -986,11 +1032,10 @@ transformOnConflictClause(ParseState *pstate, exclRelIndex = list_length(pstate->p_rtable); /* - * Build a targetlist for the EXCLUDED pseudo relation. Have to be - * careful to use resnos that correspond to attnos of the underlying - * relation. + * Build a targetlist representing the columns of the EXCLUDED pseudo + * relation. Have to be careful to use resnos that correspond to + * attnos of the underlying relation. */ - Assert(pstate->p_next_resno == 1); for (attno = 0; attno < targetrel->rd_rel->relnatts; attno++) { Form_pg_attribute attr = targetrel->rd_att->attrs[attno]; @@ -1011,14 +1056,11 @@ transformOnConflictClause(ParseState *pstate, attr->atttypid, attr->atttypmod, attr->attcollation, 0); - var->location = -1; - - name = NameStr(attr->attname); + name = pstrdup(NameStr(attr->attname)); } - Assert(pstate->p_next_resno == attno + 1); te = makeTargetEntry((Expr *) var, - pstate->p_next_resno++, + attno + 1, name, false); @@ -1027,15 +1069,16 @@ transformOnConflictClause(ParseState *pstate, } /* - * Additionally add a whole row tlist entry for EXCLUDED. That's - * really only needed for ruleutils' benefit, which expects to find - * corresponding entries in child tlists. Alternatively we could do - * this only when required, but that doesn't seem worth the trouble. + * Add a whole-row-Var entry to support references to "EXCLUDED.*". + * Like the other entries in exclRelTlist, its resno must match the + * Var's varattno, else the wrong things happen while resolving + * references in setrefs.c. This is against normal conventions for + * targetlists, but it's okay since we don't use this as a real tlist. */ var = makeVar(exclRelIndex, InvalidAttrNumber, - RelationGetRelid(targetrel), + targetrel->rd_rel->reltype, -1, InvalidOid, 0); - te = makeTargetEntry((Expr *) var, 0, NULL, true); + te = makeTargetEntry((Expr *) var, InvalidAttrNumber, NULL, true); exclRelTlist = lappend(exclRelTlist, te); /* @@ -1231,6 +1274,7 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt) qry->hasSubLinks = pstate->p_hasSubLinks; qry->hasWindowFuncs = pstate->p_hasWindowFuncs; + qry->hasTargetSRFs = pstate->p_hasTargetSRFs; qry->hasAggs = pstate->p_hasAggs; if (pstate->p_hasAggs || qry->groupClause || qry->groupingSets || qry->havingQual) parseCheckAggregates(pstate, qry); @@ -1258,7 +1302,9 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt) { Query *qry = makeNode(Query); List *exprsLists; - List *collations; + List *coltypes = NIL; + List *coltypmods = NIL; + List *colcollations = NIL; List **colexprs = NULL; int sublist_length = -1; bool lateral = false; @@ -1290,9 +1336,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt) } /* - * For each row of VALUES, transform the raw expressions. This is also a - * handy place to reject DEFAULT nodes, which the grammar allows for - * simplicity. + * For each row of VALUES, transform the raw expressions. * * Note that the intermediate representation we build is column-organized * not row-organized. That simplifies the type and collation processing @@ -1302,8 +1346,12 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt) { List *sublist = (List *) lfirst(lc); - /* Do basic expression transformation (same as a ROW() expr) */ - sublist = transformExpressionList(pstate, sublist, EXPR_KIND_VALUES); + /* + * Do basic expression transformation (same as a ROW() expr, but here + * we disallow SetToDefault) + */ + sublist = transformExpressionList(pstate, sublist, + EXPR_KIND_VALUES, false); /* * All the sublists must be the same length, *after* transformation @@ -1326,17 +1374,12 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt) exprLocation((Node *) sublist)))); } - /* Check for DEFAULT and build per-column expression lists */ + /* Build per-column expression lists */ i = 0; foreach(lc2, sublist) { Node *col = (Node *) lfirst(lc2); - if (IsA(col, SetToDefault)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("DEFAULT can only appear in a VALUES list within INSERT"), - parser_errposition(pstate, exprLocation(col)))); colexprs[i] = lappend(colexprs[i], col); i++; } @@ -1347,8 +1390,8 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt) /* * Now resolve the common types of the columns, and coerce everything to - * those types. Then identify the common collation, if any, of each - * column. + * those types. Then identify the common typmod and common collation, if + * any, of each column. * * We must do collation processing now because (1) assign_query_collations * doesn't process rangetable entries, and (2) we need to label the VALUES @@ -1359,11 +1402,12 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt) * * Note we modify the per-column expression lists in-place. */ - collations = NIL; for (i = 0; i < sublist_length; i++) { Oid coltype; + int32 coltypmod = -1; Oid colcoll; + bool first = true; coltype = select_common_type(pstate, colexprs[i], "VALUES", NULL); @@ -1373,11 +1417,24 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt) col = coerce_to_common_type(pstate, col, coltype, "VALUES"); lfirst(lc) = (void *) col; + if (first) + { + coltypmod = exprTypmod(col); + first = false; + } + else + { + /* As soon as we see a non-matching typmod, fall back to -1 */ + if (coltypmod >= 0 && coltypmod != exprTypmod(col)) + coltypmod = -1; + } } colcoll = select_common_collation(pstate, colexprs[i], true); - collations = lappend_oid(collations, colcoll); + coltypes = lappend_oid(coltypes, coltype); + coltypmods = lappend_int(coltypmods, coltypmod); + colcollations = lappend_oid(colcollations, colcoll); } /* @@ -1419,7 +1476,8 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt) /* * Generate the VALUES RTE */ - rte = addRangeTableEntryForValues(pstate, exprsLists, collations, + rte = addRangeTableEntryForValues(pstate, exprsLists, + coltypes, coltypmods, colcollations, NULL, lateral, true); addRTEtoQuery(pstate, rte, true, true, true); @@ -1691,6 +1749,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt) qry->hasSubLinks = pstate->p_hasSubLinks; qry->hasWindowFuncs = pstate->p_hasWindowFuncs; + qry->hasTargetSRFs = pstate->p_hasTargetSRFs; qry->hasAggs = pstate->p_hasAggs; if (pstate->p_hasAggs || qry->groupClause || qry->groupingSets || qry->havingQual) parseCheckAggregates(pstate, qry); @@ -2135,7 +2194,7 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt) } qry->resultRelation = setTargetTable(pstate, stmt->relation, - interpretInhOption(stmt->relation->inhOpt), + stmt->relation->inh, true, ACL_UPDATE); @@ -2170,6 +2229,7 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt) qry->rtable = pstate->p_rtable; qry->jointree = makeFromExpr(pstate->p_joinlist, qual); + qry->hasTargetSRFs = pstate->p_hasTargetSRFs; qry->hasSubLinks = pstate->p_hasSubLinks; assign_query_collations(pstate, qry); @@ -2301,17 +2361,17 @@ transformReturningList(ParseState *pstate, List *returningList) * transformDeclareCursorStmt - * transform a DECLARE CURSOR Statement * - * DECLARE CURSOR is a hybrid case: it's an optimizable statement (in fact not - * significantly different from a SELECT) as far as parsing/rewriting/planning - * are concerned, but it's not passed to the executor and so in that sense is - * a utility statement. We transform it into a Query exactly as if it were - * a SELECT, then stick the original DeclareCursorStmt into the utilityStmt - * field to carry the cursor name and options. + * DECLARE CURSOR is like other utility statements in that we emit it as a + * CMD_UTILITY Query node; however, we must first transform the contained + * query. We used to postpone that until execution, but it's really necessary + * to do it during the normal parse analysis phase to ensure that side effects + * of parser hooks happen at the expected time. */ static Query * transformDeclareCursorStmt(ParseState *pstate, DeclareCursorStmt *stmt) { Query *result; + Query *query; /* * Don't allow both SCROLL and NO SCROLL to be specified @@ -2322,12 +2382,13 @@ transformDeclareCursorStmt(ParseState *pstate, DeclareCursorStmt *stmt) (errcode(ERRCODE_INVALID_CURSOR_DEFINITION), errmsg("cannot specify both SCROLL and NO SCROLL"))); - result = transformStmt(pstate, stmt->query); + /* Transform contained query, not allowing SELECT INTO */ + query = transformStmt(pstate, stmt->query); + stmt->query = (Node *) query; /* Grammar should not have allowed anything but SELECT */ - if (!IsA(result, Query) || - result->commandType != CMD_SELECT || - result->utilityStmt != NULL) + if (!IsA(query, Query) || + query->commandType != CMD_SELECT) elog(ERROR, "unexpected non-SELECT command in DECLARE CURSOR"); /* @@ -2335,47 +2396,47 @@ transformDeclareCursorStmt(ParseState *pstate, DeclareCursorStmt *stmt) * allowed, but the semantics of when the updates occur might be * surprising.) */ - if (result->hasModifyingCTE) + if (query->hasModifyingCTE) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("DECLARE CURSOR must not contain data-modifying statements in WITH"))); /* FOR UPDATE and WITH HOLD are not compatible */ - if (result->rowMarks != NIL && (stmt->options & CURSOR_OPT_HOLD)) + if (query->rowMarks != NIL && (stmt->options & CURSOR_OPT_HOLD)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), /*------ translator: %s is a SQL row locking clause such as FOR UPDATE */ errmsg("DECLARE CURSOR WITH HOLD ... %s is not supported", LCS_asString(((RowMarkClause *) - linitial(result->rowMarks))->strength)), + linitial(query->rowMarks))->strength)), errdetail("Holdable cursors must be READ ONLY."))); /* FOR UPDATE and SCROLL are not compatible */ - if (result->rowMarks != NIL && (stmt->options & CURSOR_OPT_SCROLL)) + if (query->rowMarks != NIL && (stmt->options & CURSOR_OPT_SCROLL)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), /*------ translator: %s is a SQL row locking clause such as FOR UPDATE */ errmsg("DECLARE SCROLL CURSOR ... %s is not supported", LCS_asString(((RowMarkClause *) - linitial(result->rowMarks))->strength)), + linitial(query->rowMarks))->strength)), errdetail("Scrollable cursors must be READ ONLY."))); /* FOR UPDATE and INSENSITIVE are not compatible */ - if (result->rowMarks != NIL && (stmt->options & CURSOR_OPT_INSENSITIVE)) + if (query->rowMarks != NIL && (stmt->options & CURSOR_OPT_INSENSITIVE)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), /*------ translator: %s is a SQL row locking clause such as FOR UPDATE */ errmsg("DECLARE INSENSITIVE CURSOR ... %s is not supported", LCS_asString(((RowMarkClause *) - linitial(result->rowMarks))->strength)), + linitial(query->rowMarks))->strength)), errdetail("Insensitive cursors must be READ ONLY."))); - /* We won't need the raw querytree any more */ - stmt->query = NULL; - + /* represent the command as a utility Query */ + result = makeNode(Query); + result->commandType = CMD_UTILITY; result->utilityStmt = (Node *) stmt; return result; @@ -2398,7 +2459,7 @@ transformExplainStmt(ParseState *pstate, ExplainStmt *stmt) Query *result; /* transform contained query, allowing SELECT INTO */ - stmt->query = (Node *) transformTopLevelStmt(pstate, stmt->query); + stmt->query = (Node *) transformOptionalSelectInto(pstate, stmt->query); /* represent the command as a utility Query */ result = makeNode(Query); @@ -2414,7 +2475,7 @@ transformExplainStmt(ParseState *pstate, ExplainStmt *stmt) * transform a CREATE TABLE AS, SELECT ... INTO, or CREATE MATERIALIZED VIEW * Statement * - * As with EXPLAIN, transform the contained statement now. + * As with DECLARE CURSOR and EXPLAIN, transform the contained statement now. */ static Query * transformCreateTableAsStmt(ParseState *pstate, CreateTableAsStmt *stmt) @@ -2422,7 +2483,7 @@ transformCreateTableAsStmt(ParseState *pstate, CreateTableAsStmt *stmt) Query *result; Query *query; - /* transform contained query */ + /* transform contained query, not allowing SELECT INTO */ query = transformStmt(pstate, stmt->query); stmt->query = (Node *) query; @@ -2565,7 +2626,7 @@ CheckSelectLocking(Query *qry, LockClauseStrength strength) translator: %s is a SQL row locking clause such as FOR UPDATE */ errmsg("%s is not allowed with window functions", LCS_asString(strength)))); - if (expression_returns_set((Node *) qry->targetList)) + if (qry->hasTargetSRFs) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), /*------ diff --git a/src/backend/parser/check_keywords.pl b/src/backend/parser/check_keywords.pl index 568ef696fd..45862ce940 100644 --- a/src/backend/parser/check_keywords.pl +++ b/src/backend/parser/check_keywords.pl @@ -4,7 +4,7 @@ # Usage: check_keywords.pl gram.y kwlist.h # src/backend/parser/check_keywords.pl -# Copyright (c) 2009-2016, PostgreSQL Global Development Group +# Copyright (c) 2009-2017, PostgreSQL Global Development Group use warnings; use strict; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 6a0f7b393c..a8e35feccc 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -6,7 +6,7 @@ * gram.y * POSTGRESQL BISON rules/actions * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -28,12 +28,11 @@ * current transaction and are just parsing commands to find the next * ROLLBACK or COMMIT. If you make use of SET variables, then you * will do the wrong thing in multi-query strings like this: - * SET SQL_inheritance TO off; SELECT * FROM foo; + * SET constraint_exclusion TO off; SELECT * FROM foo; * because the entire string is parsed by gram.y before the SET gets * executed. Anything that depends on the database or changeable state * should be handled during parse analysis so that it happens at the - * right time not the wrong time. The handling of SQL_inheritance is - * a good example. + * right time not the wrong time. * * WARNINGS * If you use a list, make sure the datum is a node so that the printing @@ -81,7 +80,8 @@ /* * The above macro assigns -1 (unknown) as the parse location of any - * nonterminal that was reduced from an empty rule. This is problematic + * nonterminal that was reduced from an empty rule, or whose leftmost + * component was reduced from an empty rule. This is problematic * for nonterminals defined like * OptFooList: / * EMPTY * / { ... } | OptFooList Foo { ... } ; * because we'll set -1 as the location during the first reduction and then @@ -92,6 +92,12 @@ * (Although we have many nonterminals that follow this pattern, we only * bother with fixing @$ like this when the nonterminal's parse location * is actually referenced in some rule.) + * + * A cleaner answer would be to make YYLLOC_DEFAULT scan all the Rhs + * locations until it's found one that's not -1. Then we'd get a correct + * location for any nonterminal that isn't entirely empty. But this way + * would add overhead to every rule reduction, and so far there's not been + * a compelling reason to pay that overhead. */ /* @@ -134,6 +140,8 @@ typedef struct ImportQual static void base_yyerror(YYLTYPE *yylloc, core_yyscan_t yyscanner, const char *msg); +static RawStmt *makeRawStmt(Node *stmt, int stmt_location); +static void updateRawStmtEnd(RawStmt *rs, int end_location); static Node *makeColumnRef(char *colname, List *indirection, int location, core_yyscan_t yyscanner); static Node *makeTypeCast(Node *arg, TypeName *typename, int location); @@ -145,7 +153,7 @@ static Node *makeBitStringConst(char *str, int location); static Node *makeNullAConst(int location); static Node *makeAConst(Value *v, int location); static Node *makeBoolAConst(bool state, int location); -static Node *makeRoleSpec(RoleSpecType type, int location); +static RoleSpec *makeRoleSpec(RoleSpecType type, int location); static void check_qualified_name(List *names, core_yyscan_t yyscanner); static List *check_func_name(List *names, core_yyscan_t yyscanner); static List *check_indirection(List *indirection, core_yyscan_t yyscanner); @@ -165,6 +173,8 @@ static Node *makeAndExpr(Node *lexpr, Node *rexpr, int location); static Node *makeOrExpr(Node *lexpr, Node *rexpr, int location); static Node *makeNotExpr(Node *expr, int location); static Node *makeAArrayExpr(List *elements, int location); +static Node *makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod, + int location); static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, int location); static List *mergeTableFuncParameters(List *func_args, List *columns); @@ -227,6 +237,10 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); struct ImportQual *importqual; InsertStmt *istmt; VariableSetStmt *vsetstmt; + PartitionElem *partelem; + PartitionSpec *partspec; + PartitionRangeDatum *partrange_datum; + RoleSpec *rolespec; } %type stmt schema_stmt @@ -266,6 +280,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); DropOwnedStmt ReassignOwnedStmt AlterTSConfigurationStmt AlterTSDictionaryStmt CreateMatViewStmt RefreshMatViewStmt CreateAmStmt + CreatePublicationStmt AlterPublicationStmt + CreateSubscriptionStmt AlterSubscriptionStmt DropSubscriptionStmt %type select_no_parens select_with_parens select_clause simple_select values_clause @@ -274,7 +290,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type add_drop opt_asc_desc opt_nulls_order %type alter_table_cmd alter_type_cmd opt_collate_clause - replica_identity + replica_identity partition_cmd %type alter_table_cmds alter_type_cmds %type opt_drop_behavior @@ -308,6 +324,9 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type TriggerEvents TriggerOneEvent %type TriggerFuncArg %type TriggerWhen +%type TransitionRelName +%type TransitionRowOrTable TransitionOldOrNew +%type TriggerTransition %type event_trigger_when_list event_trigger_value_list %type event_trigger_when_item @@ -317,6 +336,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); database_name access_method_clause access_method attr_name name cursor_name file_name index_name opt_index_name cluster_index_specification + def_key %type func_name handler_name qual_Op qual_all_Op subquery_Op opt_class opt_inline_handler opt_validator validator_clause @@ -327,16 +347,17 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type all_Op MathOp %type row_security_cmd RowSecurityDefaultForCmd +%type RowSecurityDefaultPermissive %type RowSecurityOptionalWithCheck RowSecurityOptionalExpr %type RowSecurityDefaultToRole RowSecurityOptionalToRole %type iso_level opt_encoding -%type grantee +%type grantee %type grantee_list %type privilege %type privileges privilege_list %type privilege_target -%type function_with_argtypes +%type function_with_argtypes aggregate_with_argtypes %type function_with_argtypes_list %type defacl_privilege_target %type DefACLOption @@ -360,8 +381,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); qualified_name_list any_name any_name_list type_name_list any_operator expr_list attrs target_list opt_target_list insert_column_list set_target_list - set_clause_list set_clause multiple_set_clause - ctext_expr_list ctext_row def_list operator_def_list indirection opt_indirection + set_clause_list set_clause + def_list operator_def_list indirection opt_indirection reloption_list group_clause TriggerFuncArgs select_limit opt_select_limit opclass_item_list opclass_drop_list opclass_purpose opt_opfamily transaction_mode_list_or_empty @@ -372,10 +393,14 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); create_generic_options alter_generic_options relation_expr_list dostmt_opt_list transform_element_list transform_type_list + TriggerTransitions TriggerReferencing + publication_name_list %type group_by_list %type group_by_item empty_grouping_set rollup_clause cube_clause %type grouping_sets_clause +%type opt_publication_for_tables publication_for_tables +%type publication_name_item %type opt_fdw_options fdw_options %type fdw_option @@ -388,7 +413,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type arg_class %type func_return func_type -%type opt_trusted opt_restart_seqs +%type opt_trusted opt_restart_seqs opt_drop_slot %type OptTemp %type OptNoLog %type OnCommitOption @@ -448,7 +473,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type case_expr case_arg when_clause case_default %type when_clause_list %type sub_type -%type ctext_expr %type NumericOnly %type NumericOnly_list %type alias_clause opt_alias_clause @@ -460,7 +484,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type relation_expr %type relation_expr_opt_alias %type tablesample_clause opt_repeatable_clause -%type target_el single_set_clause set_target insert_column_item +%type target_el set_target insert_column_item %type generic_option_name %type generic_option_arg @@ -498,7 +522,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type NonReservedWord NonReservedWord_or_Sconst %type createdb_opt_name %type var_value zone_value -%type auth_ident RoleSpec opt_granted_by +%type auth_ident RoleSpec opt_granted_by %type unreserved_keyword type_func_name_keyword %type col_name_keyword reserved_keyword @@ -514,7 +538,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type constraints_set_list %type constraints_set_mode %type OptTableSpace OptConsTableSpace -%type OptTableSpaceOwner +%type OptTableSpaceOwner %type opt_check_option %type opt_provider security_label @@ -539,6 +563,17 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); opt_frame_clause frame_extent frame_bound %type opt_existing_window_name %type opt_if_not_exists +%type PartitionSpec OptPartitionSpec +%type part_strategy +%type part_elem +%type part_params +%type OptPartitionElementList PartitionElementList +%type PartitionElement +%type ForValues +%type partbound_datum +%type partbound_datum_list +%type PartitionRangeDatum +%type range_datum_list /* * Non-keyword token types. These are hard-wired into the "flex" lexer. @@ -564,7 +599,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); /* ordinary key words in alphabetical order */ %token ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC - ASSERTION ASSIGNMENT ASYMMETRIC AT ATTRIBUTE AUTHORIZATION + ASSERTION ASSIGNMENT ASYMMETRIC AT ATTACH ATTRIBUTE AUTHORIZATION BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT BOOLEAN_P BOTH BY @@ -580,7 +615,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); DATA_P DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DEPENDS DESC - DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP + DETACH DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P + DOUBLE_P DROP EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EVENT EXCEPT EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN @@ -608,29 +644,29 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); MAPPING MATCH MATERIALIZED MAXVALUE METHOD MINUTE_P MINVALUE MODE MONTH_P MOVE - NAME_P NAMES NATIONAL NATURAL NCHAR NEXT NO NONE + NAME_P NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NONE NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NULLS_P NUMERIC - OBJECT_P OF OFF OFFSET OIDS ON ONLY OPERATOR OPTION OPTIONS OR + OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OPTIONS OR ORDER ORDINALITY OUT_P OUTER_P OVER OVERLAPS OVERLAY OWNED OWNER PARALLEL PARSER PARTIAL PARTITION PASSING PASSWORD PLACING PLANS POLICY POSITION PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY - PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROGRAM + PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROGRAM PUBLICATION QUOTE - RANGE READ REAL REASSIGN RECHECK RECURSIVE REF REFERENCES REFRESH REINDEX - RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA + RANGE READ REAL REASSIGN RECHECK RECURSIVE REF REFERENCES REFERENCING + REFRESH REINDEX RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA RESET RESTART RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP ROW ROWS RULE SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE SEQUENCES SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHOW - SIMILAR SIMPLE SKIP SMALLINT SNAPSHOT SOME SQL_P STABLE STANDALONE_P START - STATEMENT STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P SUBSTRING - SYMMETRIC SYSID SYSTEM_P + SIMILAR SIMPLE SKIP SLOT SMALLINT SNAPSHOT SOME SQL_P STABLE STANDALONE_P + START STATEMENT STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P + SUBSCRIPTION SUBSTRING SYMMETRIC SYSID SYSTEM_P TABLE TABLES TABLESAMPLE TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN TIME TIMESTAMP TO TRAILING TRANSACTION TRANSFORM TREAT TRIGGER TRIM TRUE_P @@ -737,18 +773,32 @@ stmtblock: stmtmulti } ; -/* the thrashing around here is to discard "empty" statements... */ +/* + * At top level, we wrap each stmt with a RawStmt node carrying start location + * and length of the stmt's text. Notice that the start loc/len are driven + * entirely from semicolon locations (@2). It would seem natural to use + * @1 or @3 to get the true start location of a stmt, but that doesn't work + * for statements that can start with empty nonterminals (opt_with_clause is + * the main offender here); as noted in the comments for YYLLOC_DEFAULT, + * we'd get -1 for the location in such cases. + * We also take care to discard empty statements entirely. + */ stmtmulti: stmtmulti ';' stmt { + if ($1 != NIL) + { + /* update length of previous stmt */ + updateRawStmtEnd((RawStmt *) llast($1), @2); + } if ($3 != NULL) - $$ = lappend($1, $3); + $$ = lappend($1, makeRawStmt($3, @2 + 1)); else $$ = $1; } | stmt { if ($1 != NULL) - $$ = list_make1($1); + $$ = list_make1(makeRawStmt($1, 0)); else $$ = NIL; } @@ -778,8 +828,10 @@ stmt : | AlterTableStmt | AlterTblSpcStmt | AlterCompositeTypeStmt + | AlterPublicationStmt | AlterRoleSetStmt | AlterRoleStmt + | AlterSubscriptionStmt | AlterTSConfigurationStmt | AlterTSDictionaryStmt | AlterUserMappingStmt @@ -807,12 +859,14 @@ stmt : | CreateMatViewStmt | CreateOpClassStmt | CreateOpFamilyStmt + | CreatePublicationStmt | AlterOpFamilyStmt | CreatePolicyStmt | CreatePLangStmt | CreateSchemaStmt | CreateSeqStmt | CreateStmt + | CreateSubscriptionStmt | CreateTableSpaceStmt | CreateTransformStmt | CreateTrigStmt @@ -839,6 +893,7 @@ stmt : | DropPLangStmt | DropRuleStmt | DropStmt + | DropSubscriptionStmt | DropTableSpaceStmt | DropTransformStmt | DropTrigStmt @@ -926,38 +981,38 @@ AlterOptRoleElem: PASSWORD Sconst { $$ = makeDefElem("password", - (Node *)makeString($2)); + (Node *)makeString($2), @1); } | PASSWORD NULL_P { - $$ = makeDefElem("password", NULL); + $$ = makeDefElem("password", NULL, @1); } | ENCRYPTED PASSWORD Sconst { $$ = makeDefElem("encryptedPassword", - (Node *)makeString($3)); + (Node *)makeString($3), @1); } | UNENCRYPTED PASSWORD Sconst { $$ = makeDefElem("unencryptedPassword", - (Node *)makeString($3)); + (Node *)makeString($3), @1); } | INHERIT { - $$ = makeDefElem("inherit", (Node *)makeInteger(TRUE)); + $$ = makeDefElem("inherit", (Node *)makeInteger(TRUE), @1); } | CONNECTION LIMIT SignedIconst { - $$ = makeDefElem("connectionlimit", (Node *)makeInteger($3)); + $$ = makeDefElem("connectionlimit", (Node *)makeInteger($3), @1); } | VALID UNTIL Sconst { - $$ = makeDefElem("validUntil", (Node *)makeString($3)); + $$ = makeDefElem("validUntil", (Node *)makeString($3), @1); } /* Supported but not documented for roles, for use by ALTER GROUP. */ | USER role_list { - $$ = makeDefElem("rolemembers", (Node *)$2); + $$ = makeDefElem("rolemembers", (Node *)$2, @1); } | IDENT { @@ -967,36 +1022,36 @@ AlterOptRoleElem: * size of the main parser. */ if (strcmp($1, "superuser") == 0) - $$ = makeDefElem("superuser", (Node *)makeInteger(TRUE)); + $$ = makeDefElem("superuser", (Node *)makeInteger(TRUE), @1); else if (strcmp($1, "nosuperuser") == 0) - $$ = makeDefElem("superuser", (Node *)makeInteger(FALSE)); + $$ = makeDefElem("superuser", (Node *)makeInteger(FALSE), @1); else if (strcmp($1, "createrole") == 0) - $$ = makeDefElem("createrole", (Node *)makeInteger(TRUE)); + $$ = makeDefElem("createrole", (Node *)makeInteger(TRUE), @1); else if (strcmp($1, "nocreaterole") == 0) - $$ = makeDefElem("createrole", (Node *)makeInteger(FALSE)); + $$ = makeDefElem("createrole", (Node *)makeInteger(FALSE), @1); else if (strcmp($1, "replication") == 0) - $$ = makeDefElem("isreplication", (Node *)makeInteger(TRUE)); + $$ = makeDefElem("isreplication", (Node *)makeInteger(TRUE), @1); else if (strcmp($1, "noreplication") == 0) - $$ = makeDefElem("isreplication", (Node *)makeInteger(FALSE)); + $$ = makeDefElem("isreplication", (Node *)makeInteger(FALSE), @1); else if (strcmp($1, "createdb") == 0) - $$ = makeDefElem("createdb", (Node *)makeInteger(TRUE)); + $$ = makeDefElem("createdb", (Node *)makeInteger(TRUE), @1); else if (strcmp($1, "nocreatedb") == 0) - $$ = makeDefElem("createdb", (Node *)makeInteger(FALSE)); + $$ = makeDefElem("createdb", (Node *)makeInteger(FALSE), @1); else if (strcmp($1, "login") == 0) - $$ = makeDefElem("canlogin", (Node *)makeInteger(TRUE)); + $$ = makeDefElem("canlogin", (Node *)makeInteger(TRUE), @1); else if (strcmp($1, "nologin") == 0) - $$ = makeDefElem("canlogin", (Node *)makeInteger(FALSE)); + $$ = makeDefElem("canlogin", (Node *)makeInteger(FALSE), @1); else if (strcmp($1, "bypassrls") == 0) - $$ = makeDefElem("bypassrls", (Node *)makeInteger(TRUE)); + $$ = makeDefElem("bypassrls", (Node *)makeInteger(TRUE), @1); else if (strcmp($1, "nobypassrls") == 0) - $$ = makeDefElem("bypassrls", (Node *)makeInteger(FALSE)); + $$ = makeDefElem("bypassrls", (Node *)makeInteger(FALSE), @1); else if (strcmp($1, "noinherit") == 0) { /* * Note that INHERIT is a keyword, so it's handled by main parser, but * NOINHERIT is handled here. */ - $$ = makeDefElem("inherit", (Node *)makeInteger(FALSE)); + $$ = makeDefElem("inherit", (Node *)makeInteger(FALSE), @1); } else ereport(ERROR, @@ -1011,23 +1066,23 @@ CreateOptRoleElem: /* The following are not supported by ALTER ROLE/USER/GROUP */ | SYSID Iconst { - $$ = makeDefElem("sysid", (Node *)makeInteger($2)); + $$ = makeDefElem("sysid", (Node *)makeInteger($2), @1); } | ADMIN role_list { - $$ = makeDefElem("adminmembers", (Node *)$2); + $$ = makeDefElem("adminmembers", (Node *)$2, @1); } | ROLE role_list { - $$ = makeDefElem("rolemembers", (Node *)$2); + $$ = makeDefElem("rolemembers", (Node *)$2, @1); } | IN_P ROLE role_list { - $$ = makeDefElem("addroleto", (Node *)$3); + $$ = makeDefElem("addroleto", (Node *)$3, @1); } | IN_P GROUP_P role_list { - $$ = makeDefElem("addroleto", (Node *)$3); + $$ = makeDefElem("addroleto", (Node *)$3, @1); } ; @@ -1204,7 +1259,7 @@ AlterGroupStmt: n->role = $3; n->action = $4; n->options = list_make1(makeDefElem("rolemembers", - (Node *)$6)); + (Node *)$6, @6)); $$ = (Node *)n; } ; @@ -1781,6 +1836,24 @@ AlterTableStmt: n->missing_ok = true; $$ = (Node *)n; } + | ALTER TABLE relation_expr partition_cmd + { + AlterTableStmt *n = makeNode(AlterTableStmt); + n->relation = $3; + n->cmds = list_make1($4); + n->relkind = OBJECT_TABLE; + n->missing_ok = false; + $$ = (Node *)n; + } + | ALTER TABLE IF_P EXISTS relation_expr partition_cmd + { + AlterTableStmt *n = makeNode(AlterTableStmt); + n->relation = $5; + n->cmds = list_make1($6); + n->relkind = OBJECT_TABLE; + n->missing_ok = true; + $$ = (Node *)n; + } | ALTER TABLE ALL IN_P TABLESPACE name SET TABLESPACE name opt_nowait { AlterTableMoveAllStmt *n = @@ -1926,6 +1999,34 @@ alter_table_cmds: | alter_table_cmds ',' alter_table_cmd { $$ = lappend($1, $3); } ; +partition_cmd: + /* ALTER TABLE ATTACH PARTITION FOR VALUES */ + ATTACH PARTITION qualified_name ForValues + { + AlterTableCmd *n = makeNode(AlterTableCmd); + PartitionCmd *cmd = makeNode(PartitionCmd); + + n->subtype = AT_AttachPartition; + cmd->name = $3; + cmd->bound = (Node *) $4; + n->def = (Node *) cmd; + + $$ = (Node *) n; + } + /* ALTER TABLE DETACH PARTITION */ + | DETACH PARTITION qualified_name + { + AlterTableCmd *n = makeNode(AlterTableCmd); + PartitionCmd *cmd = makeNode(PartitionCmd); + + n->subtype = AT_DetachPartition; + cmd->name = $3; + n->def = (Node *) cmd; + + $$ = (Node *) n; + } + ; + alter_table_cmd: /* ALTER TABLE ADD */ ADD_P columnDef @@ -2444,23 +2545,90 @@ reloption_list: reloption_elem: ColLabel '=' def_arg { - $$ = makeDefElem($1, (Node *) $3); + $$ = makeDefElem($1, (Node *) $3, @1); } | ColLabel { - $$ = makeDefElem($1, NULL); + $$ = makeDefElem($1, NULL, @1); } | ColLabel '.' ColLabel '=' def_arg { $$ = makeDefElemExtended($1, $3, (Node *) $5, - DEFELEM_UNSPEC); + DEFELEM_UNSPEC, @1); } | ColLabel '.' ColLabel { - $$ = makeDefElemExtended($1, $3, NULL, DEFELEM_UNSPEC); + $$ = makeDefElemExtended($1, $3, NULL, DEFELEM_UNSPEC, @1); + } + ; + +ForValues: + /* a LIST partition */ + FOR VALUES IN_P '(' partbound_datum_list ')' + { + PartitionBoundSpec *n = makeNode(PartitionBoundSpec); + + n->strategy = PARTITION_STRATEGY_LIST; + n->listdatums = $5; + n->location = @3; + + $$ = (Node *) n; + } + + /* a RANGE partition */ + | FOR VALUES FROM '(' range_datum_list ')' TO '(' range_datum_list ')' + { + PartitionBoundSpec *n = makeNode(PartitionBoundSpec); + + n->strategy = PARTITION_STRATEGY_RANGE; + n->lowerdatums = $5; + n->upperdatums = $9; + n->location = @3; + + $$ = (Node *) n; } ; +partbound_datum: + Sconst { $$ = makeStringConst($1, @1); } + | NumericOnly { $$ = makeAConst($1, @1); } + | NULL_P { $$ = makeNullAConst(@1); } + ; + +partbound_datum_list: + partbound_datum { $$ = list_make1($1); } + | partbound_datum_list ',' partbound_datum + { $$ = lappend($1, $3); } + ; + +range_datum_list: + PartitionRangeDatum { $$ = list_make1($1); } + | range_datum_list ',' PartitionRangeDatum + { $$ = lappend($1, $3); } + ; + +PartitionRangeDatum: + UNBOUNDED + { + PartitionRangeDatum *n = makeNode(PartitionRangeDatum); + + n->infinite = true; + n->value = NULL; + n->location = @1; + + $$ = n; + } + | partbound_datum + { + PartitionRangeDatum *n = makeNode(PartitionRangeDatum); + + n->infinite = false; + n->value = $1; + n->location = @1; + + $$ = n; + } + ; /***************************************************************************** * @@ -2667,59 +2835,59 @@ copy_opt_list: copy_opt_item: BINARY { - $$ = makeDefElem("format", (Node *)makeString("binary")); + $$ = makeDefElem("format", (Node *)makeString("binary"), @1); } | OIDS { - $$ = makeDefElem("oids", (Node *)makeInteger(TRUE)); + $$ = makeDefElem("oids", (Node *)makeInteger(TRUE), @1); } | FREEZE { - $$ = makeDefElem("freeze", (Node *)makeInteger(TRUE)); + $$ = makeDefElem("freeze", (Node *)makeInteger(TRUE), @1); } | DELIMITER opt_as Sconst { - $$ = makeDefElem("delimiter", (Node *)makeString($3)); + $$ = makeDefElem("delimiter", (Node *)makeString($3), @1); } | NULL_P opt_as Sconst { - $$ = makeDefElem("null", (Node *)makeString($3)); + $$ = makeDefElem("null", (Node *)makeString($3), @1); } | CSV { - $$ = makeDefElem("format", (Node *)makeString("csv")); + $$ = makeDefElem("format", (Node *)makeString("csv"), @1); } | HEADER_P { - $$ = makeDefElem("header", (Node *)makeInteger(TRUE)); + $$ = makeDefElem("header", (Node *)makeInteger(TRUE), @1); } | QUOTE opt_as Sconst { - $$ = makeDefElem("quote", (Node *)makeString($3)); + $$ = makeDefElem("quote", (Node *)makeString($3), @1); } | ESCAPE opt_as Sconst { - $$ = makeDefElem("escape", (Node *)makeString($3)); + $$ = makeDefElem("escape", (Node *)makeString($3), @1); } | FORCE QUOTE columnList { - $$ = makeDefElem("force_quote", (Node *)$3); + $$ = makeDefElem("force_quote", (Node *)$3, @1); } | FORCE QUOTE '*' { - $$ = makeDefElem("force_quote", (Node *)makeNode(A_Star)); + $$ = makeDefElem("force_quote", (Node *)makeNode(A_Star), @1); } | FORCE NOT NULL_P columnList { - $$ = makeDefElem("force_not_null", (Node *)$4); + $$ = makeDefElem("force_not_null", (Node *)$4, @1); } | FORCE NULL_P columnList { - $$ = makeDefElem("force_null", (Node *)$3); + $$ = makeDefElem("force_null", (Node *)$3, @1); } | ENCODING Sconst { - $$ = makeDefElem("encoding", (Node *)makeString($2)); + $$ = makeDefElem("encoding", (Node *)makeString($2), @1); } ; @@ -2728,7 +2896,7 @@ copy_opt_item: opt_binary: BINARY { - $$ = makeDefElem("format", (Node *)makeString("binary")); + $$ = makeDefElem("format", (Node *)makeString("binary"), @1); } | /*EMPTY*/ { $$ = NULL; } ; @@ -2736,7 +2904,7 @@ opt_binary: opt_oids: WITH OIDS { - $$ = makeDefElem("oids", (Node *)makeInteger(TRUE)); + $$ = makeDefElem("oids", (Node *)makeInteger(TRUE), @1); } | /*EMPTY*/ { $$ = NULL; } ; @@ -2744,7 +2912,7 @@ opt_oids: copy_delimiter: opt_using DELIMITERS Sconst { - $$ = makeDefElem("delimiter", (Node *)makeString($3)); + $$ = makeDefElem("delimiter", (Node *)makeString($3), @2); } | /*EMPTY*/ { $$ = NULL; } ; @@ -2769,7 +2937,7 @@ copy_generic_opt_list: copy_generic_opt_elem: ColLabel copy_generic_opt_arg { - $$ = makeDefElem($1, $2); + $$ = makeDefElem($1, $2, @1); } ; @@ -2806,69 +2974,113 @@ copy_generic_opt_arg_list_item: *****************************************************************************/ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' - OptInherit OptWith OnCommitOption OptTableSpace + OptInherit OptPartitionSpec OptWith OnCommitOption OptTableSpace { CreateStmt *n = makeNode(CreateStmt); $4->relpersistence = $2; n->relation = $4; n->tableElts = $6; n->inhRelations = $8; + n->partspec = $9; n->ofTypename = NULL; n->constraints = NIL; - n->options = $9; - n->oncommit = $10; - n->tablespacename = $11; + n->options = $10; + n->oncommit = $11; + n->tablespacename = $12; n->if_not_exists = false; $$ = (Node *)n; } | CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name '(' - OptTableElementList ')' OptInherit OptWith OnCommitOption - OptTableSpace + OptTableElementList ')' OptInherit OptPartitionSpec OptWith + OnCommitOption OptTableSpace { CreateStmt *n = makeNode(CreateStmt); $7->relpersistence = $2; n->relation = $7; n->tableElts = $9; n->inhRelations = $11; + n->partspec = $12; n->ofTypename = NULL; n->constraints = NIL; - n->options = $12; - n->oncommit = $13; - n->tablespacename = $14; + n->options = $13; + n->oncommit = $14; + n->tablespacename = $15; n->if_not_exists = true; $$ = (Node *)n; } | CREATE OptTemp TABLE qualified_name OF any_name - OptTypedTableElementList OptWith OnCommitOption OptTableSpace + OptTypedTableElementList OptPartitionSpec OptWith OnCommitOption + OptTableSpace { CreateStmt *n = makeNode(CreateStmt); $4->relpersistence = $2; n->relation = $4; n->tableElts = $7; n->inhRelations = NIL; + n->partspec = $8; n->ofTypename = makeTypeNameFromNameList($6); n->ofTypename->location = @6; n->constraints = NIL; - n->options = $8; - n->oncommit = $9; - n->tablespacename = $10; + n->options = $9; + n->oncommit = $10; + n->tablespacename = $11; n->if_not_exists = false; $$ = (Node *)n; } | CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name OF any_name - OptTypedTableElementList OptWith OnCommitOption OptTableSpace + OptTypedTableElementList OptPartitionSpec OptWith OnCommitOption + OptTableSpace { CreateStmt *n = makeNode(CreateStmt); $7->relpersistence = $2; n->relation = $7; n->tableElts = $10; n->inhRelations = NIL; + n->partspec = $11; n->ofTypename = makeTypeNameFromNameList($9); n->ofTypename->location = @9; n->constraints = NIL; + n->options = $12; + n->oncommit = $13; + n->tablespacename = $14; + n->if_not_exists = true; + $$ = (Node *)n; + } + | CREATE OptTemp TABLE qualified_name PARTITION OF qualified_name + OptPartitionElementList ForValues OptPartitionSpec OptWith + OnCommitOption OptTableSpace + { + CreateStmt *n = makeNode(CreateStmt); + $4->relpersistence = $2; + n->relation = $4; + n->tableElts = $8; + n->inhRelations = list_make1($7); + n->partbound = (Node *) $9; + n->partspec = $10; + n->ofTypename = NULL; + n->constraints = NIL; n->options = $11; n->oncommit = $12; n->tablespacename = $13; + n->if_not_exists = false; + $$ = (Node *)n; + } + | CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name PARTITION OF + qualified_name OptPartitionElementList ForValues OptPartitionSpec + OptWith OnCommitOption OptTableSpace + { + CreateStmt *n = makeNode(CreateStmt); + $7->relpersistence = $2; + n->relation = $7; + n->tableElts = $11; + n->inhRelations = list_make1($10); + n->partbound = (Node *) $12; + n->partspec = $13; + n->ofTypename = NULL; + n->constraints = NIL; + n->options = $14; + n->oncommit = $15; + n->tablespacename = $16; n->if_not_exists = true; $$ = (Node *)n; } @@ -2917,6 +3129,11 @@ OptTypedTableElementList: | /*EMPTY*/ { $$ = NIL; } ; +OptPartitionElementList: + '(' PartitionElementList ')' { $$ = $2; } + | /*EMPTY*/ { $$ = NIL; } + ; + TableElementList: TableElement { @@ -2939,6 +3156,17 @@ TypedTableElementList: } ; +PartitionElementList: + PartitionElement + { + $$ = list_make1($1); + } + | PartitionElementList ',' PartitionElement + { + $$ = lappend($1, $3); + } + ; + TableElement: columnDef { $$ = $1; } | TableLikeClause { $$ = $1; } @@ -2950,6 +3178,28 @@ TypedTableElement: | TableConstraint { $$ = $1; } ; +PartitionElement: + TableConstraint { $$ = $1; } + | ColId ColQualList + { + ColumnDef *n = makeNode(ColumnDef); + n->colname = $1; + n->typeName = NULL; + n->inhcount = 0; + n->is_local = true; + n->is_not_null = false; + n->is_from_type = false; + n->storage = 0; + n->raw_default = NULL; + n->cooked_default = NULL; + n->collOid = InvalidOid; + SplitColQualList($2, &n->constraints, &n->collClause, + yyscanner); + n->location = @1; + $$ = (Node *) n; + } + ; + columnDef: ColId Typename create_generic_options ColQualList { ColumnDef *n = makeNode(ColumnDef); @@ -3413,11 +3663,70 @@ OptInherit: INHERITS '(' qualified_name_list ')' { $$ = $3; } | /*EMPTY*/ { $$ = NIL; } ; +/* Optional partition key specification */ +OptPartitionSpec: PartitionSpec { $$ = $1; } + | /*EMPTY*/ { $$ = NULL; } + ; + +PartitionSpec: PARTITION BY part_strategy '(' part_params ')' + { + PartitionSpec *n = makeNode(PartitionSpec); + + n->strategy = $3; + n->partParams = $5; + n->location = @1; + + $$ = n; + } + ; + +part_strategy: IDENT { $$ = $1; } + | unreserved_keyword { $$ = pstrdup($1); } + ; + +part_params: part_elem { $$ = list_make1($1); } + | part_params ',' part_elem { $$ = lappend($1, $3); } + ; + +part_elem: ColId opt_collate opt_class + { + PartitionElem *n = makeNode(PartitionElem); + + n->name = $1; + n->expr = NULL; + n->collation = $2; + n->opclass = $3; + n->location = @1; + $$ = n; + } + | func_expr_windowless opt_collate opt_class + { + PartitionElem *n = makeNode(PartitionElem); + + n->name = NULL; + n->expr = $1; + n->collation = $2; + n->opclass = $3; + n->location = @1; + $$ = n; + } + | '(' a_expr ')' opt_collate opt_class + { + PartitionElem *n = makeNode(PartitionElem); + + n->name = NULL; + n->expr = $2; + n->collation = $4; + n->opclass = $5; + n->location = @1; + $$ = n; + } + ; /* WITH (options) is preferred, WITH OIDS and WITHOUT OIDS are legacy forms */ OptWith: WITH reloptions { $$ = $2; } - | WITH OIDS { $$ = list_make1(defWithOids(true)); } - | WITHOUT OIDS { $$ = list_make1(defWithOids(false)); } + | WITH OIDS { $$ = list_make1(makeDefElem("oids", (Node *) makeInteger(true), @1)); } + | WITHOUT OIDS { $$ = list_make1(makeDefElem("oids", (Node *) makeInteger(false), @1)); } | /*EMPTY*/ { $$ = NIL; } ; @@ -3634,51 +3943,51 @@ SeqOptList: SeqOptElem { $$ = list_make1($1); } SeqOptElem: CACHE NumericOnly { - $$ = makeDefElem("cache", (Node *)$2); + $$ = makeDefElem("cache", (Node *)$2, @1); } | CYCLE { - $$ = makeDefElem("cycle", (Node *)makeInteger(TRUE)); + $$ = makeDefElem("cycle", (Node *)makeInteger(TRUE), @1); } | NO CYCLE { - $$ = makeDefElem("cycle", (Node *)makeInteger(FALSE)); + $$ = makeDefElem("cycle", (Node *)makeInteger(FALSE), @1); } | INCREMENT opt_by NumericOnly { - $$ = makeDefElem("increment", (Node *)$3); + $$ = makeDefElem("increment", (Node *)$3, @1); } | MAXVALUE NumericOnly { - $$ = makeDefElem("maxvalue", (Node *)$2); + $$ = makeDefElem("maxvalue", (Node *)$2, @1); } | MINVALUE NumericOnly { - $$ = makeDefElem("minvalue", (Node *)$2); + $$ = makeDefElem("minvalue", (Node *)$2, @1); } | NO MAXVALUE { - $$ = makeDefElem("maxvalue", NULL); + $$ = makeDefElem("maxvalue", NULL, @1); } | NO MINVALUE { - $$ = makeDefElem("minvalue", NULL); + $$ = makeDefElem("minvalue", NULL, @1); } | OWNED BY any_name { - $$ = makeDefElem("owned_by", (Node *)$3); + $$ = makeDefElem("owned_by", (Node *)$3, @1); } | START opt_with NumericOnly { - $$ = makeDefElem("start", (Node *)$3); + $$ = makeDefElem("start", (Node *)$3, @1); } | RESTART { - $$ = makeDefElem("restart", NULL); + $$ = makeDefElem("restart", NULL, @1); } | RESTART opt_with NumericOnly { - $$ = makeDefElem("restart", (Node *)$3); + $$ = makeDefElem("restart", (Node *)$3, @1); } ; @@ -3877,19 +4186,19 @@ create_extension_opt_list: create_extension_opt_item: SCHEMA name { - $$ = makeDefElem("schema", (Node *)makeString($2)); + $$ = makeDefElem("schema", (Node *)makeString($2), @1); } | VERSION_P NonReservedWord_or_Sconst { - $$ = makeDefElem("new_version", (Node *)makeString($2)); + $$ = makeDefElem("new_version", (Node *)makeString($2), @1); } | FROM NonReservedWord_or_Sconst { - $$ = makeDefElem("old_version", (Node *)makeString($2)); + $$ = makeDefElem("old_version", (Node *)makeString($2), @1); } | CASCADE { - $$ = makeDefElem("cascade", (Node *)makeInteger(TRUE)); + $$ = makeDefElem("cascade", (Node *)makeInteger(TRUE), @1); } ; @@ -3918,7 +4227,7 @@ alter_extension_opt_list: alter_extension_opt_item: TO NonReservedWord_or_Sconst { - $$ = makeDefElem("new_version", (Node *)makeString($2)); + $$ = makeDefElem("new_version", (Node *)makeString($2), @1); } ; @@ -3929,14 +4238,23 @@ alter_extension_opt_item: *****************************************************************************/ AlterExtensionContentsStmt: - ALTER EXTENSION name add_drop AGGREGATE func_name aggr_args + ALTER EXTENSION name add_drop ACCESS METHOD name + { + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); + n->extname = $3; + n->action = $4; + n->objtype = OBJECT_ACCESS_METHOD; + n->objname = list_make1(makeString($7)); + $$ = (Node *)n; + } + | ALTER EXTENSION name add_drop AGGREGATE aggregate_with_argtypes { AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); n->extname = $3; n->action = $4; n->objtype = OBJECT_AGGREGATE; - n->objname = $6; - n->objargs = extractAggrArgTypes($7); + n->objname = $6->funcname; + n->objargs = $6->funcargs; $$ = (Node *)n; } | ALTER EXTENSION name add_drop CAST '(' Typename AS Typename ')' @@ -4179,10 +4497,10 @@ CreateFdwStmt: CREATE FOREIGN DATA_P WRAPPER name opt_fdw_options create_generic ; fdw_option: - HANDLER handler_name { $$ = makeDefElem("handler", (Node *)$2); } - | NO HANDLER { $$ = makeDefElem("handler", NULL); } - | VALIDATOR handler_name { $$ = makeDefElem("validator", (Node *)$2); } - | NO VALIDATOR { $$ = makeDefElem("validator", NULL); } + HANDLER handler_name { $$ = makeDefElem("handler", (Node *)$2, @1); } + | NO HANDLER { $$ = makeDefElem("handler", NULL, @1); } + | VALIDATOR handler_name { $$ = makeDefElem("validator", (Node *)$2, @1); } + | NO VALIDATOR { $$ = makeDefElem("validator", NULL, @1); } ; fdw_options: @@ -4301,14 +4619,14 @@ alter_generic_option_elem: } | DROP generic_option_name { - $$ = makeDefElemExtended(NULL, $2, NULL, DEFELEM_DROP); + $$ = makeDefElemExtended(NULL, $2, NULL, DEFELEM_DROP, @2); } ; generic_option_elem: generic_option_name generic_option_arg { - $$ = makeDefElem($1, $2); + $$ = makeDefElem($1, $2, @1); } ; @@ -4469,6 +4787,48 @@ CreateForeignTableStmt: n->options = $14; $$ = (Node *) n; } + | CREATE FOREIGN TABLE qualified_name + PARTITION OF qualified_name OptPartitionElementList ForValues + SERVER name create_generic_options + { + CreateForeignTableStmt *n = makeNode(CreateForeignTableStmt); + $4->relpersistence = RELPERSISTENCE_PERMANENT; + n->base.relation = $4; + n->base.inhRelations = list_make1($7); + n->base.tableElts = $8; + n->base.partbound = (Node *) $9; + n->base.ofTypename = NULL; + n->base.constraints = NIL; + n->base.options = NIL; + n->base.oncommit = ONCOMMIT_NOOP; + n->base.tablespacename = NULL; + n->base.if_not_exists = false; + /* FDW-specific data */ + n->servername = $11; + n->options = $12; + $$ = (Node *) n; + } + | CREATE FOREIGN TABLE IF_P NOT EXISTS qualified_name + PARTITION OF qualified_name OptPartitionElementList ForValues + SERVER name create_generic_options + { + CreateForeignTableStmt *n = makeNode(CreateForeignTableStmt); + $7->relpersistence = RELPERSISTENCE_PERMANENT; + n->base.relation = $7; + n->base.inhRelations = list_make1($10); + n->base.tableElts = $11; + n->base.partbound = (Node *) $12; + n->base.ofTypename = NULL; + n->base.constraints = NIL; + n->base.options = NIL; + n->base.oncommit = ONCOMMIT_NOOP; + n->base.tablespacename = NULL; + n->base.if_not_exists = true; + /* FDW-specific data */ + n->servername = $14; + n->options = $15; + $$ = (Node *) n; + } ; /***************************************************************************** @@ -4614,26 +4974,30 @@ AlterUserMappingStmt: ALTER USER MAPPING FOR auth_ident SERVER name alter_generi /***************************************************************************** * * QUERIES: - * CREATE POLICY name ON table [FOR cmd] [TO role, ...] - * [USING (qual)] [WITH CHECK (with_check)] + * CREATE POLICY name ON table + * [AS { PERMISSIVE | RESTRICTIVE } ] + * [FOR { SELECT | INSERT | UPDATE | DELETE } ] + * [TO role, ...] + * [USING (qual)] [WITH CHECK (with check qual)] * ALTER POLICY name ON table [TO role, ...] - * [USING (qual)] [WITH CHECK (with_check)] + * [USING (qual)] [WITH CHECK (with check qual)] * DROP POLICY name ON table * *****************************************************************************/ CreatePolicyStmt: - CREATE POLICY name ON qualified_name RowSecurityDefaultForCmd - RowSecurityDefaultToRole RowSecurityOptionalExpr - RowSecurityOptionalWithCheck + CREATE POLICY name ON qualified_name RowSecurityDefaultPermissive + RowSecurityDefaultForCmd RowSecurityDefaultToRole + RowSecurityOptionalExpr RowSecurityOptionalWithCheck { CreatePolicyStmt *n = makeNode(CreatePolicyStmt); n->policy_name = $3; n->table = $5; - n->cmd_name = $6; - n->roles = $7; - n->qual = $8; - n->with_check = $9; + n->permissive = $6; + n->cmd_name = $7; + n->roles = $8; + n->qual = $9; + n->with_check = $10; $$ = (Node *) n; } ; @@ -4697,6 +5061,24 @@ RowSecurityOptionalToRole: | /* EMPTY */ { $$ = NULL; } ; +RowSecurityDefaultPermissive: + AS IDENT + { + if (strcmp($2, "permissive") == 0) + $$ = true; + else if (strcmp($2, "restrictive") == 0) + $$ = false; + else + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("unrecognized row security option \"%s\"", $2), + errhint("Only PERMISSIVE or RESTRICTIVE policies are supported currently."), + parser_errposition(@2))); + + } + | /* EMPTY */ { $$ = true; } + ; + RowSecurityDefaultForCmd: FOR row_security_cmd { $$ = $2; } | /* EMPTY */ { $$ = "all"; } @@ -4737,19 +5119,20 @@ CreateAmStmt: CREATE ACCESS METHOD name TYPE_P INDEX HANDLER handler_name CreateTrigStmt: CREATE TRIGGER name TriggerActionTime TriggerEvents ON - qualified_name TriggerForSpec TriggerWhen + qualified_name TriggerReferencing TriggerForSpec TriggerWhen EXECUTE PROCEDURE func_name '(' TriggerFuncArgs ')' { CreateTrigStmt *n = makeNode(CreateTrigStmt); n->trigname = $3; n->relation = $7; - n->funcname = $12; - n->args = $14; - n->row = $8; + n->funcname = $13; + n->args = $15; + n->row = $9; n->timing = $4; n->events = intVal(linitial($5)); n->columns = (List *) lsecond($5); - n->whenClause = $9; + n->whenClause = $10; + n->transitionRels = $8; n->isconstraint = FALSE; n->deferrable = FALSE; n->initdeferred = FALSE; @@ -4771,6 +5154,7 @@ CreateTrigStmt: n->events = intVal(linitial($6)); n->columns = (List *) lsecond($6); n->whenClause = $14; + n->transitionRels = NIL; n->isconstraint = TRUE; processCASbits($10, @10, "TRIGGER", &n->deferrable, &n->initdeferred, NULL, @@ -4823,6 +5207,49 @@ TriggerOneEvent: { $$ = list_make2(makeInteger(TRIGGER_TYPE_TRUNCATE), NIL); } ; +TriggerReferencing: + REFERENCING TriggerTransitions { $$ = $2; } + | /*EMPTY*/ { $$ = NIL; } + ; + +TriggerTransitions: + TriggerTransition { $$ = list_make1($1); } + | TriggerTransitions TriggerTransition { $$ = lappend($1, $2); } + ; + +TriggerTransition: + TransitionOldOrNew TransitionRowOrTable opt_as TransitionRelName + { + TriggerTransition *n = makeNode(TriggerTransition); + n->name = $4; + n->isNew = $1; + n->isTable = $2; + $$ = (Node *)n; + } + ; + +TransitionOldOrNew: + NEW { $$ = TRUE; } + | OLD { $$ = FALSE; } + ; + +TransitionRowOrTable: + TABLE { $$ = TRUE; } + /* + * According to the standard, lack of a keyword here implies ROW. + * Support for that would require prohibiting ROW entirely here, + * reserving the keyword ROW, and/or requiring AS (instead of + * allowing it to be optional, as the standard specifies) as the + * next token. Requiring ROW seems cleanest and easiest to + * explain. + */ + | ROW { $$ = FALSE; } + ; + +TransitionRelName: + ColId { $$ = $1; } + ; + TriggerForSpec: FOR TriggerForOptEach TriggerForType { @@ -4980,7 +5407,7 @@ event_trigger_when_list: event_trigger_when_item: ColId IN_P '(' event_trigger_value_list ')' - { $$ = makeDefElem($1, (Node *) $4); } + { $$ = makeDefElem($1, (Node *) $4, @1); } ; event_trigger_value_list: @@ -5185,7 +5612,7 @@ DefineStmt: n->kind = OBJECT_COLLATION; n->args = NIL; n->defnames = $3; - n->definition = list_make1(makeDefElem("from", (Node *) $5)); + n->definition = list_make1(makeDefElem("from", (Node *) $5, @5)); $$ = (Node *)n; } ; @@ -5197,16 +5624,21 @@ def_list: def_elem { $$ = list_make1($1); } | def_list ',' def_elem { $$ = lappend($1, $3); } ; -def_elem: ColLabel '=' def_arg +def_elem: def_key '=' def_arg { - $$ = makeDefElem($1, (Node *) $3); + $$ = makeDefElem($1, (Node *) $3, @1); } - | ColLabel + | def_key { - $$ = makeDefElem($1, NULL); + $$ = makeDefElem($1, NULL, @1); } ; +def_key: + ColLabel { $$ = $1; } + | ColLabel ColLabel { $$ = psprintf("%s %s", $1, $2); } + ; + /* Note: any simple identifier will be returned as a type name! */ def_arg: func_type { $$ = (Node *)$1; } | reserved_keyword { $$ = (Node *)makeString(pstrdup($1)); } @@ -5229,7 +5661,7 @@ old_aggr_list: old_aggr_elem { $$ = list_make1($1); } */ old_aggr_elem: IDENT '=' def_arg { - $$ = makeDefElem($1, (Node *)$3); + $$ = makeDefElem($1, (Node *)$3, @1); } ; @@ -5255,30 +5687,44 @@ AlterEnumStmt: { AlterEnumStmt *n = makeNode(AlterEnumStmt); n->typeName = $3; + n->oldVal = NULL; n->newVal = $7; n->newValNeighbor = NULL; n->newValIsAfter = true; - n->skipIfExists = $6; + n->skipIfNewValExists = $6; $$ = (Node *) n; } | ALTER TYPE_P any_name ADD_P VALUE_P opt_if_not_exists Sconst BEFORE Sconst { AlterEnumStmt *n = makeNode(AlterEnumStmt); n->typeName = $3; + n->oldVal = NULL; n->newVal = $7; n->newValNeighbor = $9; n->newValIsAfter = false; - n->skipIfExists = $6; + n->skipIfNewValExists = $6; $$ = (Node *) n; } | ALTER TYPE_P any_name ADD_P VALUE_P opt_if_not_exists Sconst AFTER Sconst { AlterEnumStmt *n = makeNode(AlterEnumStmt); n->typeName = $3; + n->oldVal = NULL; n->newVal = $7; n->newValNeighbor = $9; n->newValIsAfter = true; - n->skipIfExists = $6; + n->skipIfNewValExists = $6; + $$ = (Node *) n; + } + | ALTER TYPE_P any_name RENAME VALUE_P Sconst TO Sconst + { + AlterEnumStmt *n = makeNode(AlterEnumStmt); + n->typeName = $3; + n->oldVal = $6; + n->newVal = $8; + n->newValNeighbor = NULL; + n->newValIsAfter = false; + n->skipIfNewValExists = false; $$ = (Node *) n; } ; @@ -5341,21 +5787,21 @@ opclass_item: n->order_family = $5; $$ = (Node *) n; } - | FUNCTION Iconst func_name func_args + | FUNCTION Iconst function_with_argtypes { CreateOpClassItem *n = makeNode(CreateOpClassItem); n->itemtype = OPCLASS_ITEM_FUNCTION; - n->name = $3; - n->args = extractArgTypes($4); + n->name = $3->funcname; + n->args = $3->funcargs; n->number = $2; $$ = (Node *) n; } - | FUNCTION Iconst '(' type_list ')' func_name func_args + | FUNCTION Iconst '(' type_list ')' function_with_argtypes { CreateOpClassItem *n = makeNode(CreateOpClassItem); n->itemtype = OPCLASS_ITEM_FUNCTION; - n->name = $6; - n->args = extractArgTypes($7); + n->name = $6->funcname; + n->args = $6->funcargs; n->number = $2; n->class_args = $4; $$ = (Node *) n; @@ -5643,6 +6089,7 @@ drop_type: TABLE { $$ = OBJECT_TABLE; } | TEXT_P SEARCH DICTIONARY { $$ = OBJECT_TSDICTIONARY; } | TEXT_P SEARCH TEMPLATE { $$ = OBJECT_TSTEMPLATE; } | TEXT_P SEARCH CONFIGURATION { $$ = OBJECT_TSCONFIGURATION; } + | PUBLICATION { $$ = OBJECT_PUBLICATION; } ; any_name_list: @@ -5746,22 +6193,22 @@ CommentStmt: n->comment = $6; $$ = (Node *) n; } - | COMMENT ON AGGREGATE func_name aggr_args IS comment_text + | COMMENT ON AGGREGATE aggregate_with_argtypes IS comment_text { CommentStmt *n = makeNode(CommentStmt); n->objtype = OBJECT_AGGREGATE; - n->objname = $4; - n->objargs = extractAggrArgTypes($5); - n->comment = $7; + n->objname = $4->funcname; + n->objargs = $4->funcargs; + n->comment = $6; $$ = (Node *) n; } - | COMMENT ON FUNCTION func_name func_args IS comment_text + | COMMENT ON FUNCTION function_with_argtypes IS comment_text { CommentStmt *n = makeNode(CommentStmt); n->objtype = OBJECT_FUNCTION; - n->objname = $4; - n->objargs = extractArgTypes($5); - n->comment = $7; + n->objname = $4->funcname; + n->objargs = $4->funcargs; + n->comment = $6; $$ = (Node *) n; } | COMMENT ON OPERATOR any_operator oper_argtypes IS comment_text @@ -5962,26 +6409,26 @@ SecLabelStmt: n->label = $8; $$ = (Node *) n; } - | SECURITY LABEL opt_provider ON AGGREGATE func_name aggr_args + | SECURITY LABEL opt_provider ON AGGREGATE aggregate_with_argtypes IS security_label { SecLabelStmt *n = makeNode(SecLabelStmt); n->provider = $3; n->objtype = OBJECT_AGGREGATE; - n->objname = $6; - n->objargs = extractAggrArgTypes($7); - n->label = $9; + n->objname = $6->funcname; + n->objargs = $6->funcargs; + n->label = $8; $$ = (Node *) n; } - | SECURITY LABEL opt_provider ON FUNCTION func_name func_args + | SECURITY LABEL opt_provider ON FUNCTION function_with_argtypes IS security_label { SecLabelStmt *n = makeNode(SecLabelStmt); n->provider = $3; n->objtype = OBJECT_FUNCTION; - n->objname = $6; - n->objargs = extractArgTypes($7); - n->label = $9; + n->objname = $6->funcname; + n->objargs = $6->funcargs; + n->label = $8; $$ = (Node *) n; } | SECURITY LABEL opt_provider ON LARGE_P OBJECT_P NumericOnly @@ -6460,22 +6907,6 @@ opt_grant_grant_option: | /*EMPTY*/ { $$ = FALSE; } ; -function_with_argtypes_list: - function_with_argtypes { $$ = list_make1($1); } - | function_with_argtypes_list ',' function_with_argtypes - { $$ = lappend($1, $3); } - ; - -function_with_argtypes: - func_name func_args - { - FuncWithArgs *n = makeNode(FuncWithArgs); - n->funcname = $1; - n->funcargs = extractArgTypes($2); - $$ = n; - } - ; - /***************************************************************************** * * GRANT and REVOKE ROLE statements @@ -6550,15 +6981,15 @@ DefACLOptionList: DefACLOption: IN_P SCHEMA name_list { - $$ = makeDefElem("schemas", (Node *)$3); + $$ = makeDefElem("schemas", (Node *)$3, @1); } | FOR ROLE role_list { - $$ = makeDefElem("roles", (Node *)$3); + $$ = makeDefElem("roles", (Node *)$3, @1); } | FOR USER role_list { - $$ = makeDefElem("roles", (Node *)$3); + $$ = makeDefElem("roles", (Node *)$3, @1); } ; @@ -6828,6 +7259,22 @@ func_args_list: | func_args_list ',' func_arg { $$ = lappend($1, $3); } ; +function_with_argtypes_list: + function_with_argtypes { $$ = list_make1($1); } + | function_with_argtypes_list ',' function_with_argtypes + { $$ = lappend($1, $3); } + ; + +function_with_argtypes: + func_name func_args + { + FuncWithArgs *n = makeNode(FuncWithArgs); + n->funcname = $1; + n->funcargs = extractArgTypes($2); + $$ = n; + } + ; + /* * func_args_with_defaults is separate because we only want to accept * defaults in CREATE FUNCTION, not in ALTER etc. @@ -7025,11 +7472,21 @@ aggr_args: '(' '*' ')' } ; -aggr_args_list: - aggr_arg { $$ = list_make1($1); } - | aggr_args_list ',' aggr_arg { $$ = lappend($1, $3); } - ; - +aggr_args_list: + aggr_arg { $$ = list_make1($1); } + | aggr_args_list ',' aggr_arg { $$ = lappend($1, $3); } + ; + +aggregate_with_argtypes: + func_name aggr_args + { + FuncWithArgs *n = makeNode(FuncWithArgs); + n->funcname = $1; + n->funcargs = extractAggrArgTypes($2); + $$ = n; + } + ; + createfunc_opt_list: /* Must be at least one to prevent conflict */ createfunc_opt_item { $$ = list_make1($1); } @@ -7042,87 +7499,87 @@ createfunc_opt_list: common_func_opt_item: CALLED ON NULL_P INPUT_P { - $$ = makeDefElem("strict", (Node *)makeInteger(FALSE)); + $$ = makeDefElem("strict", (Node *)makeInteger(FALSE), @1); } | RETURNS NULL_P ON NULL_P INPUT_P { - $$ = makeDefElem("strict", (Node *)makeInteger(TRUE)); + $$ = makeDefElem("strict", (Node *)makeInteger(TRUE), @1); } | STRICT_P { - $$ = makeDefElem("strict", (Node *)makeInteger(TRUE)); + $$ = makeDefElem("strict", (Node *)makeInteger(TRUE), @1); } | IMMUTABLE { - $$ = makeDefElem("volatility", (Node *)makeString("immutable")); + $$ = makeDefElem("volatility", (Node *)makeString("immutable"), @1); } | STABLE { - $$ = makeDefElem("volatility", (Node *)makeString("stable")); + $$ = makeDefElem("volatility", (Node *)makeString("stable"), @1); } | VOLATILE { - $$ = makeDefElem("volatility", (Node *)makeString("volatile")); + $$ = makeDefElem("volatility", (Node *)makeString("volatile"), @1); } | EXTERNAL SECURITY DEFINER { - $$ = makeDefElem("security", (Node *)makeInteger(TRUE)); + $$ = makeDefElem("security", (Node *)makeInteger(TRUE), @1); } | EXTERNAL SECURITY INVOKER { - $$ = makeDefElem("security", (Node *)makeInteger(FALSE)); + $$ = makeDefElem("security", (Node *)makeInteger(FALSE), @1); } | SECURITY DEFINER { - $$ = makeDefElem("security", (Node *)makeInteger(TRUE)); + $$ = makeDefElem("security", (Node *)makeInteger(TRUE), @1); } | SECURITY INVOKER { - $$ = makeDefElem("security", (Node *)makeInteger(FALSE)); + $$ = makeDefElem("security", (Node *)makeInteger(FALSE), @1); } | LEAKPROOF { - $$ = makeDefElem("leakproof", (Node *)makeInteger(TRUE)); + $$ = makeDefElem("leakproof", (Node *)makeInteger(TRUE), @1); } | NOT LEAKPROOF { - $$ = makeDefElem("leakproof", (Node *)makeInteger(FALSE)); + $$ = makeDefElem("leakproof", (Node *)makeInteger(FALSE), @1); } | COST NumericOnly { - $$ = makeDefElem("cost", (Node *)$2); + $$ = makeDefElem("cost", (Node *)$2, @1); } | ROWS NumericOnly { - $$ = makeDefElem("rows", (Node *)$2); + $$ = makeDefElem("rows", (Node *)$2, @1); } | FunctionSetResetClause { /* we abuse the normal content of a DefElem here */ - $$ = makeDefElem("set", (Node *)$1); + $$ = makeDefElem("set", (Node *)$1, @1); } | PARALLEL ColId { - $$ = makeDefElem("parallel", (Node *)makeString($2)); + $$ = makeDefElem("parallel", (Node *)makeString($2), @1); } ; createfunc_opt_item: AS func_as { - $$ = makeDefElem("as", (Node *)$2); + $$ = makeDefElem("as", (Node *)$2, @1); } | LANGUAGE NonReservedWord_or_Sconst { - $$ = makeDefElem("language", (Node *)makeString($2)); + $$ = makeDefElem("language", (Node *)makeString($2), @1); } | TRANSFORM transform_type_list { - $$ = makeDefElem("transform", (Node *)$2); + $$ = makeDefElem("transform", (Node *)$2, @1); } | WINDOW { - $$ = makeDefElem("window", (Node *)makeInteger(TRUE)); + $$ = makeDefElem("window", (Node *)makeInteger(TRUE), @1); } | common_func_opt_item { @@ -7211,24 +7668,24 @@ opt_restrict: *****************************************************************************/ RemoveFuncStmt: - DROP FUNCTION func_name func_args opt_drop_behavior + DROP FUNCTION function_with_argtypes opt_drop_behavior { DropStmt *n = makeNode(DropStmt); n->removeType = OBJECT_FUNCTION; - n->objects = list_make1($3); - n->arguments = list_make1(extractArgTypes($4)); - n->behavior = $5; + n->objects = list_make1($3->funcname); + n->arguments = list_make1($3->funcargs); + n->behavior = $4; n->missing_ok = false; n->concurrent = false; $$ = (Node *)n; } - | DROP FUNCTION IF_P EXISTS func_name func_args opt_drop_behavior + | DROP FUNCTION IF_P EXISTS function_with_argtypes opt_drop_behavior { DropStmt *n = makeNode(DropStmt); n->removeType = OBJECT_FUNCTION; - n->objects = list_make1($5); - n->arguments = list_make1(extractArgTypes($6)); - n->behavior = $7; + n->objects = list_make1($5->funcname); + n->arguments = list_make1($5->funcargs); + n->behavior = $6; n->missing_ok = true; n->concurrent = false; $$ = (Node *)n; @@ -7236,24 +7693,24 @@ RemoveFuncStmt: ; RemoveAggrStmt: - DROP AGGREGATE func_name aggr_args opt_drop_behavior + DROP AGGREGATE aggregate_with_argtypes opt_drop_behavior { DropStmt *n = makeNode(DropStmt); n->removeType = OBJECT_AGGREGATE; - n->objects = list_make1($3); - n->arguments = list_make1(extractAggrArgTypes($4)); - n->behavior = $5; + n->objects = list_make1($3->funcname); + n->arguments = list_make1($3->funcargs); + n->behavior = $4; n->missing_ok = false; n->concurrent = false; $$ = (Node *)n; } - | DROP AGGREGATE IF_P EXISTS func_name aggr_args opt_drop_behavior + | DROP AGGREGATE IF_P EXISTS aggregate_with_argtypes opt_drop_behavior { DropStmt *n = makeNode(DropStmt); n->removeType = OBJECT_AGGREGATE; - n->objects = list_make1($5); - n->arguments = list_make1(extractAggrArgTypes($6)); - n->behavior = $7; + n->objects = list_make1($5->funcname); + n->arguments = list_make1($5->funcargs); + n->behavior = $6; n->missing_ok = true; n->concurrent = false; $$ = (Node *)n; @@ -7334,11 +7791,11 @@ dostmt_opt_list: dostmt_opt_item: Sconst { - $$ = makeDefElem("as", (Node *)makeString($1)); + $$ = makeDefElem("as", (Node *)makeString($1), @1); } | LANGUAGE NonReservedWord_or_Sconst { - $$ = makeDefElem("language", (Node *)makeString($2)); + $$ = makeDefElem("language", (Node *)makeString($2), @1); } ; @@ -7552,13 +8009,13 @@ AlterTblSpcStmt: * *****************************************************************************/ -RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name +RenameStmt: ALTER AGGREGATE aggregate_with_argtypes RENAME TO name { RenameStmt *n = makeNode(RenameStmt); n->renameType = OBJECT_AGGREGATE; - n->object = $3; - n->objarg = extractAggrArgTypes($4); - n->newname = $7; + n->object = $3->funcname; + n->objarg = $3->funcargs; + n->newname = $6; n->missing_ok = false; $$ = (Node *)n; } @@ -8084,13 +8541,13 @@ AlterObjectDependsStmt: *****************************************************************************/ AlterObjectSchemaStmt: - ALTER AGGREGATE func_name aggr_args SET SCHEMA name + ALTER AGGREGATE aggregate_with_argtypes SET SCHEMA name { AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); n->objectType = OBJECT_AGGREGATE; - n->object = $3; - n->objarg = extractAggrArgTypes($4); - n->newschema = $7; + n->object = $3->funcname; + n->objarg = $3->funcargs; + n->newschema = $6; n->missing_ok = false; $$ = (Node *)n; } @@ -8327,9 +8784,9 @@ operator_def_list: operator_def_elem { $$ = list_make1($1); } ; operator_def_elem: ColLabel '=' NONE - { $$ = makeDefElem($1, NULL); } + { $$ = makeDefElem($1, NULL, @1); } | ColLabel '=' def_arg - { $$ = makeDefElem($1, (Node *) $3); } + { $$ = makeDefElem($1, (Node *) $3, @1); } ; /***************************************************************************** @@ -8338,13 +8795,13 @@ operator_def_elem: ColLabel '=' NONE * *****************************************************************************/ -AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleSpec +AlterOwnerStmt: ALTER AGGREGATE aggregate_with_argtypes OWNER TO RoleSpec { AlterOwnerStmt *n = makeNode(AlterOwnerStmt); n->objectType = OBJECT_AGGREGATE; - n->object = $3; - n->objarg = extractAggrArgTypes($4); - n->newowner = $7; + n->object = $3->funcname; + n->objarg = $3->funcargs; + n->newowner = $6; $$ = (Node *)n; } | ALTER COLLATION any_name OWNER TO RoleSpec @@ -8493,8 +8950,236 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleSpec n->newowner = $7; $$ = (Node *)n; } + | ALTER PUBLICATION name OWNER TO RoleSpec + { + AlterOwnerStmt *n = makeNode(AlterOwnerStmt); + n->objectType = OBJECT_PUBLICATION; + n->object = list_make1(makeString($3)); + n->newowner = $6; + $$ = (Node *)n; + } + | ALTER SUBSCRIPTION name OWNER TO RoleSpec + { + AlterOwnerStmt *n = makeNode(AlterOwnerStmt); + n->objectType = OBJECT_SUBSCRIPTION; + n->object = list_make1(makeString($3)); + n->newowner = $6; + $$ = (Node *)n; + } + ; + + +/***************************************************************************** + * + * CREATE PUBLICATION name [ FOR TABLE ] [ WITH options ] + * + *****************************************************************************/ + +CreatePublicationStmt: + CREATE PUBLICATION name opt_publication_for_tables opt_definition + { + CreatePublicationStmt *n = makeNode(CreatePublicationStmt); + n->pubname = $3; + n->options = $5; + if ($4 != NULL) + { + /* FOR TABLE */ + if (IsA($4, List)) + n->tables = (List *)$4; + /* FOR ALL TABLES */ + else + n->for_all_tables = TRUE; + } + $$ = (Node *)n; + } + ; + +opt_publication_for_tables: + publication_for_tables { $$ = $1; } + | /* EMPTY */ { $$ = NULL; } + ; + +publication_for_tables: + FOR TABLE relation_expr_list + { + $$ = (Node *) $3; + } + | FOR ALL TABLES + { + $$ = (Node *) makeInteger(TRUE); + } + ; + +/***************************************************************************** + * + * ALTER PUBLICATION name [ WITH ] options + * + * ALTER PUBLICATION name ADD TABLE table [, table2] + * + * ALTER PUBLICATION name DROP TABLE table [, table2] + * + * ALTER PUBLICATION name SET TABLE table [, table2] + * + *****************************************************************************/ + +AlterPublicationStmt: + ALTER PUBLICATION name WITH definition + { + AlterPublicationStmt *n = makeNode(AlterPublicationStmt); + n->pubname = $3; + n->options = $5; + $$ = (Node *)n; + } + | ALTER PUBLICATION name ADD_P TABLE relation_expr_list + { + AlterPublicationStmt *n = makeNode(AlterPublicationStmt); + n->pubname = $3; + n->tables = $6; + n->tableAction = DEFELEM_ADD; + $$ = (Node *)n; + } + | ALTER PUBLICATION name SET TABLE relation_expr_list + { + AlterPublicationStmt *n = makeNode(AlterPublicationStmt); + n->pubname = $3; + n->tables = $6; + n->tableAction = DEFELEM_SET; + $$ = (Node *)n; + } + | ALTER PUBLICATION name DROP TABLE relation_expr_list + { + AlterPublicationStmt *n = makeNode(AlterPublicationStmt); + n->pubname = $3; + n->tables = $6; + n->tableAction = DEFELEM_DROP; + $$ = (Node *)n; + } + ; + +/***************************************************************************** + * + * CREATE SUBSCRIPTION name ... + * + *****************************************************************************/ + +CreateSubscriptionStmt: + CREATE SUBSCRIPTION name CONNECTION Sconst PUBLICATION publication_name_list opt_definition + { + CreateSubscriptionStmt *n = + makeNode(CreateSubscriptionStmt); + n->subname = $3; + n->conninfo = $5; + n->publication = $7; + n->options = $8; + $$ = (Node *)n; + } + ; + +publication_name_list: + publication_name_item + { + $$ = list_make1($1); + } + | publication_name_list ',' publication_name_item + { + $$ = lappend($1, $3); + } + ; + +publication_name_item: + ColLabel { $$ = makeString($1); }; + +/***************************************************************************** + * + * ALTER SUBSCRIPTION name [ WITH ] options + * + *****************************************************************************/ + +AlterSubscriptionStmt: + ALTER SUBSCRIPTION name WITH definition + { + AlterSubscriptionStmt *n = + makeNode(AlterSubscriptionStmt); + n->subname = $3; + n->options = $5; + $$ = (Node *)n; + } + | ALTER SUBSCRIPTION name CONNECTION Sconst + { + AlterSubscriptionStmt *n = + makeNode(AlterSubscriptionStmt); + n->subname = $3; + n->options = list_make1(makeDefElem("conninfo", + (Node *)makeString($5), @1)); + $$ = (Node *)n; + } + | ALTER SUBSCRIPTION name SET PUBLICATION publication_name_list + { + AlterSubscriptionStmt *n = + makeNode(AlterSubscriptionStmt); + n->subname = $3; + n->options = list_make1(makeDefElem("publication", + (Node *)$6, @1)); + $$ = (Node *)n; + } + | ALTER SUBSCRIPTION name ENABLE_P + { + AlterSubscriptionStmt *n = + makeNode(AlterSubscriptionStmt); + n->subname = $3; + n->options = list_make1(makeDefElem("enabled", + (Node *)makeInteger(TRUE), @1)); + $$ = (Node *)n; + } + | ALTER SUBSCRIPTION name DISABLE_P + { + AlterSubscriptionStmt *n = + makeNode(AlterSubscriptionStmt); + n->subname = $3; + n->options = list_make1(makeDefElem("enabled", + (Node *)makeInteger(FALSE), @1)); + $$ = (Node *)n; + } ; + +/***************************************************************************** + * + * DROP SUBSCRIPTION [ IF EXISTS ] name + * + *****************************************************************************/ + +DropSubscriptionStmt: DROP SUBSCRIPTION name opt_drop_slot + { + DropSubscriptionStmt *n = makeNode(DropSubscriptionStmt); + n->subname = $3; + n->drop_slot = $4; + n->missing_ok = false; + $$ = (Node *) n; + } + | DROP SUBSCRIPTION IF_P EXISTS name opt_drop_slot + { + DropSubscriptionStmt *n = makeNode(DropSubscriptionStmt); + n->subname = $5; + n->drop_slot = $6; + n->missing_ok = true; + $$ = (Node *) n; + } ; +opt_drop_slot: + IDENT SLOT + { + if (strcmp($1, "drop") == 0) + $$ = TRUE; + else if (strcmp($1, "nodrop") == 0) + $$ = FALSE; + else + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("unrecognized option \"%s\"", $1), + parser_errposition(@1))); + } + | /*EMPTY*/ { $$ = TRUE; } + ; /***************************************************************************** * @@ -8695,7 +9380,7 @@ TransactionStmt: TransactionStmt *n = makeNode(TransactionStmt); n->kind = TRANS_STMT_SAVEPOINT; n->options = list_make1(makeDefElem("savepoint_name", - (Node *)makeString($2))); + (Node *)makeString($2), @1)); $$ = (Node *)n; } | RELEASE SAVEPOINT ColId @@ -8703,7 +9388,7 @@ TransactionStmt: TransactionStmt *n = makeNode(TransactionStmt); n->kind = TRANS_STMT_RELEASE; n->options = list_make1(makeDefElem("savepoint_name", - (Node *)makeString($3))); + (Node *)makeString($3), @1)); $$ = (Node *)n; } | RELEASE ColId @@ -8711,7 +9396,7 @@ TransactionStmt: TransactionStmt *n = makeNode(TransactionStmt); n->kind = TRANS_STMT_RELEASE; n->options = list_make1(makeDefElem("savepoint_name", - (Node *)makeString($2))); + (Node *)makeString($2), @1)); $$ = (Node *)n; } | ROLLBACK opt_transaction TO SAVEPOINT ColId @@ -8719,7 +9404,7 @@ TransactionStmt: TransactionStmt *n = makeNode(TransactionStmt); n->kind = TRANS_STMT_ROLLBACK_TO; n->options = list_make1(makeDefElem("savepoint_name", - (Node *)makeString($5))); + (Node *)makeString($5), @1)); $$ = (Node *)n; } | ROLLBACK opt_transaction TO ColId @@ -8727,7 +9412,7 @@ TransactionStmt: TransactionStmt *n = makeNode(TransactionStmt); n->kind = TRANS_STMT_ROLLBACK_TO; n->options = list_make1(makeDefElem("savepoint_name", - (Node *)makeString($4))); + (Node *)makeString($4), @1)); $$ = (Node *)n; } | PREPARE TRANSACTION Sconst @@ -8761,19 +9446,19 @@ opt_transaction: WORK {} transaction_mode_item: ISOLATION LEVEL iso_level { $$ = makeDefElem("transaction_isolation", - makeStringConst($3, @3)); } + makeStringConst($3, @3), @1); } | READ ONLY { $$ = makeDefElem("transaction_read_only", - makeIntConst(TRUE, @1)); } + makeIntConst(TRUE, @1), @1); } | READ WRITE { $$ = makeDefElem("transaction_read_only", - makeIntConst(FALSE, @1)); } + makeIntConst(FALSE, @1), @1); } | DEFERRABLE { $$ = makeDefElem("transaction_deferrable", - makeIntConst(TRUE, @1)); } + makeIntConst(TRUE, @1), @1); } | NOT DEFERRABLE { $$ = makeDefElem("transaction_deferrable", - makeIntConst(FALSE, @1)); } + makeIntConst(FALSE, @1), @1); } ; /* Syntax with commas is SQL-spec, without commas is Postgres historical */ @@ -8917,15 +9602,15 @@ createdb_opt_items: createdb_opt_item: createdb_opt_name opt_equal SignedIconst { - $$ = makeDefElem($1, (Node *)makeInteger($3)); + $$ = makeDefElem($1, (Node *)makeInteger($3), @1); } | createdb_opt_name opt_equal opt_boolean_or_string { - $$ = makeDefElem($1, (Node *)makeString($3)); + $$ = makeDefElem($1, (Node *)makeString($3), @1); } | createdb_opt_name opt_equal DEFAULT { - $$ = makeDefElem($1, NULL); + $$ = makeDefElem($1, NULL, @1); } ; @@ -8985,7 +9670,7 @@ AlterDatabaseStmt: AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt); n->dbname = $3; n->options = list_make1(makeDefElem("tablespace", - (Node *)makeString($6))); + (Node *)makeString($6), @6)); $$ = (Node *)n; } ; @@ -9449,17 +10134,17 @@ ExplainStmt: { ExplainStmt *n = makeNode(ExplainStmt); n->query = $4; - n->options = list_make1(makeDefElem("analyze", NULL)); + n->options = list_make1(makeDefElem("analyze", NULL, @2)); if ($3) n->options = lappend(n->options, - makeDefElem("verbose", NULL)); + makeDefElem("verbose", NULL, @3)); $$ = (Node *) n; } | EXPLAIN VERBOSE ExplainableStmt { ExplainStmt *n = makeNode(ExplainStmt); n->query = $3; - n->options = list_make1(makeDefElem("verbose", NULL)); + n->options = list_make1(makeDefElem("verbose", NULL, @2)); $$ = (Node *) n; } | EXPLAIN '(' explain_option_list ')' ExplainableStmt @@ -9497,7 +10182,7 @@ explain_option_list: explain_option_elem: explain_option_name explain_option_arg { - $$ = makeDefElem($1, $2); + $$ = makeDefElem($1, $2, @1); } ; @@ -9840,75 +10525,24 @@ set_clause_list: ; set_clause: - single_set_clause { $$ = list_make1($1); } - | multiple_set_clause { $$ = $1; } - ; - -single_set_clause: - set_target '=' ctext_expr - { - $$ = $1; - $$->val = (Node *) $3; - } - ; - -/* - * Ideally, we'd accept any row-valued a_expr as RHS of a multiple_set_clause. - * However, per SQL spec the row-constructor case must allow DEFAULT as a row - * member, and it's pretty unclear how to do that (unless perhaps we allow - * DEFAULT in any a_expr and let parse analysis sort it out later?). For the - * moment, the planner/executor only support a subquery as a multiassignment - * source anyhow, so we need only accept ctext_row and subqueries here. - */ -multiple_set_clause: - '(' set_target_list ')' '=' ctext_row + set_target '=' a_expr { - ListCell *col_cell; - ListCell *val_cell; - - /* - * Break the ctext_row apart, merge individual expressions - * into the destination ResTargets. This is semantically - * equivalent to, and much cheaper to process than, the - * general case. - */ - if (list_length($2) != list_length($5)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("number of columns does not match number of values"), - parser_errposition(@5))); - forboth(col_cell, $2, val_cell, $5) - { - ResTarget *res_col = (ResTarget *) lfirst(col_cell); - Node *res_val = (Node *) lfirst(val_cell); - - res_col->val = res_val; - } - - $$ = $2; + $1->val = (Node *) $3; + $$ = list_make1($1); } - | '(' set_target_list ')' '=' select_with_parens + | '(' set_target_list ')' '=' a_expr { - SubLink *sl = makeNode(SubLink); int ncolumns = list_length($2); int i = 1; ListCell *col_cell; - /* First, convert bare SelectStmt into a SubLink */ - sl->subLinkType = MULTIEXPR_SUBLINK; - sl->subLinkId = 0; /* will be assigned later */ - sl->testexpr = NULL; - sl->operName = NIL; - sl->subselect = $5; - sl->location = @5; - /* Create a MultiAssignRef source for each target */ foreach(col_cell, $2) { ResTarget *res_col = (ResTarget *) lfirst(col_cell); MultiAssignRef *r = makeNode(MultiAssignRef); - r->source = (Node *) sl; + r->source = (Node *) $5; r->colno = i; r->ncolumns = ncolumns; res_col->val = (Node *) r; @@ -10567,17 +11201,22 @@ locked_rels_list: ; +/* + * We should allow ROW '(' expr_list ')' too, but that seems to require + * making VALUES a fully reserved word, which will probably break more apps + * than allowing the noise-word is worth. + */ values_clause: - VALUES ctext_row + VALUES '(' expr_list ')' { SelectStmt *n = makeNode(SelectStmt); - n->valuesLists = list_make1($2); + n->valuesLists = list_make1($3); $$ = (Node *) n; } - | values_clause ',' ctext_row + | values_clause ',' '(' expr_list ')' { SelectStmt *n = (SelectStmt *) $1; - n->valuesLists = lappend(n->valuesLists, $3); + n->valuesLists = lappend(n->valuesLists, $4); $$ = (Node *) n; } ; @@ -10878,30 +11517,30 @@ join_qual: USING '(' name_list ')' { $$ = (Node *) $3; } relation_expr: qualified_name { - /* default inheritance */ + /* inheritance query, implicitly */ $$ = $1; - $$->inhOpt = INH_DEFAULT; + $$->inh = true; $$->alias = NULL; } | qualified_name '*' { - /* inheritance query */ + /* inheritance query, explicitly */ $$ = $1; - $$->inhOpt = INH_YES; + $$->inh = true; $$->alias = NULL; } | ONLY qualified_name { /* no inheritance */ $$ = $2; - $$->inhOpt = INH_NO; + $$->inh = false; $$->alias = NULL; } | ONLY '(' qualified_name ')' { /* no inheritance, SQL99-style syntax */ $$ = $3; - $$->inhOpt = INH_NO; + $$->inh = false; $$->alias = NULL; } ; @@ -11968,6 +12607,20 @@ a_expr: c_expr { $$ = $1; } list_make1($1), @2), @2); } + | DEFAULT + { + /* + * The SQL spec only allows DEFAULT in "contextually typed + * expressions", but for us, it's easier to allow it in + * any a_expr and then throw error during parse analysis + * if it's in an inappropriate context. This way also + * lets us say something smarter than "syntax error". + */ + SetToDefault *n = makeNode(SetToDefault); + /* parse analysis will fill in the rest */ + n->location = @1; + $$ = (Node *)n; + } ; /* @@ -12330,143 +12983,63 @@ func_expr_common_subexpr: } | CURRENT_DATE { - /* - * Translate as "'now'::text::date". - * - * We cannot use "'now'::date" because coerce_type() will - * immediately reduce that to a constant representing - * today's date. We need to delay the conversion until - * runtime, else the wrong things will happen when - * CURRENT_DATE is used in a column default value or rule. - * - * This could be simplified if we had a way to generate - * an expression tree representing runtime application - * of type-input conversion functions. (As of PG 7.3 - * that is actually possible, but not clear that we want - * to rely on it.) - * - * The token location is attached to the run-time - * typecast, not to the Const, for the convenience of - * pg_stat_statements (which doesn't want these constructs - * to appear to be replaceable constants). - */ - Node *n; - n = makeStringConstCast("now", -1, SystemTypeName("text")); - $$ = makeTypeCast(n, SystemTypeName("date"), @1); + $$ = makeSQLValueFunction(SVFOP_CURRENT_DATE, -1, @1); } | CURRENT_TIME { - /* - * Translate as "'now'::text::timetz". - * See comments for CURRENT_DATE. - */ - Node *n; - n = makeStringConstCast("now", -1, SystemTypeName("text")); - $$ = makeTypeCast(n, SystemTypeName("timetz"), @1); + $$ = makeSQLValueFunction(SVFOP_CURRENT_TIME, -1, @1); } | CURRENT_TIME '(' Iconst ')' { - /* - * Translate as "'now'::text::timetz(n)". - * See comments for CURRENT_DATE. - */ - Node *n; - TypeName *d; - n = makeStringConstCast("now", -1, SystemTypeName("text")); - d = SystemTypeName("timetz"); - d->typmods = list_make1(makeIntConst($3, @3)); - $$ = makeTypeCast(n, d, @1); + $$ = makeSQLValueFunction(SVFOP_CURRENT_TIME_N, $3, @1); } | CURRENT_TIMESTAMP { - /* - * Translate as "now()", since we have a function that - * does exactly what is needed. - */ - $$ = (Node *) makeFuncCall(SystemFuncName("now"), NIL, @1); + $$ = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP, -1, @1); } | CURRENT_TIMESTAMP '(' Iconst ')' { - /* - * Translate as "'now'::text::timestamptz(n)". - * See comments for CURRENT_DATE. - */ - Node *n; - TypeName *d; - n = makeStringConstCast("now", -1, SystemTypeName("text")); - d = SystemTypeName("timestamptz"); - d->typmods = list_make1(makeIntConst($3, @3)); - $$ = makeTypeCast(n, d, @1); + $$ = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP_N, $3, @1); } | LOCALTIME { - /* - * Translate as "'now'::text::time". - * See comments for CURRENT_DATE. - */ - Node *n; - n = makeStringConstCast("now", -1, SystemTypeName("text")); - $$ = makeTypeCast((Node *)n, SystemTypeName("time"), @1); + $$ = makeSQLValueFunction(SVFOP_LOCALTIME, -1, @1); } | LOCALTIME '(' Iconst ')' { - /* - * Translate as "'now'::text::time(n)". - * See comments for CURRENT_DATE. - */ - Node *n; - TypeName *d; - n = makeStringConstCast("now", -1, SystemTypeName("text")); - d = SystemTypeName("time"); - d->typmods = list_make1(makeIntConst($3, @3)); - $$ = makeTypeCast((Node *)n, d, @1); + $$ = makeSQLValueFunction(SVFOP_LOCALTIME_N, $3, @1); } | LOCALTIMESTAMP { - /* - * Translate as "'now'::text::timestamp". - * See comments for CURRENT_DATE. - */ - Node *n; - n = makeStringConstCast("now", -1, SystemTypeName("text")); - $$ = makeTypeCast(n, SystemTypeName("timestamp"), @1); + $$ = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP, -1, @1); } | LOCALTIMESTAMP '(' Iconst ')' { - /* - * Translate as "'now'::text::timestamp(n)". - * See comments for CURRENT_DATE. - */ - Node *n; - TypeName *d; - n = makeStringConstCast("now", -1, SystemTypeName("text")); - d = SystemTypeName("timestamp"); - d->typmods = list_make1(makeIntConst($3, @3)); - $$ = makeTypeCast(n, d, @1); + $$ = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP_N, $3, @1); } | CURRENT_ROLE { - $$ = (Node *) makeFuncCall(SystemFuncName("current_user"), NIL, @1); + $$ = makeSQLValueFunction(SVFOP_CURRENT_ROLE, -1, @1); } | CURRENT_USER { - $$ = (Node *) makeFuncCall(SystemFuncName("current_user"), NIL, @1); + $$ = makeSQLValueFunction(SVFOP_CURRENT_USER, -1, @1); } | SESSION_USER { - $$ = (Node *) makeFuncCall(SystemFuncName("session_user"), NIL, @1); + $$ = makeSQLValueFunction(SVFOP_SESSION_USER, -1, @1); } | USER { - $$ = (Node *) makeFuncCall(SystemFuncName("current_user"), NIL, @1); + $$ = makeSQLValueFunction(SVFOP_USER, -1, @1); } | CURRENT_CATALOG { - $$ = (Node *) makeFuncCall(SystemFuncName("current_database"), NIL, @1); + $$ = makeSQLValueFunction(SVFOP_CURRENT_CATALOG, -1, @1); } | CURRENT_SCHEMA { - $$ = (Node *) makeFuncCall(SystemFuncName("current_schema"), NIL, @1); + $$ = makeSQLValueFunction(SVFOP_CURRENT_SCHEMA, -1, @1); } | CAST '(' a_expr AS Typename ')' { $$ = makeTypeCast($3, $5, @1); } @@ -13303,36 +13876,6 @@ opt_asymmetric: ASYMMETRIC | /*EMPTY*/ ; -/* - * The SQL spec defines "contextually typed value expressions" and - * "contextually typed row value constructors", which for our purposes - * are the same as "a_expr" and "row" except that DEFAULT can appear at - * the top level. - */ - -ctext_expr: - a_expr { $$ = (Node *) $1; } - | DEFAULT - { - SetToDefault *n = makeNode(SetToDefault); - n->location = @1; - $$ = (Node *) n; - } - ; - -ctext_expr_list: - ctext_expr { $$ = list_make1($1); } - | ctext_expr_list ',' ctext_expr { $$ = lappend($1, $3); } - ; - -/* - * We should allow ROW '(' ctext_expr_list ')' too, but that seems to require - * making VALUES a fully reserved word, which will probably break more apps - * than allowing the noise-word is worth. - */ -ctext_row: '(' ctext_expr_list ')' { $$ = $2; } - ; - /***************************************************************************** * @@ -13644,10 +14187,10 @@ RoleSpec: NonReservedWord } else { - n = (RoleSpec *) makeRoleSpec(ROLESPEC_CSTRING, @1); + n = makeRoleSpec(ROLESPEC_CSTRING, @1); n->rolename = pstrdup($1); } - $$ = (Node *) n; + $$ = n; } | CURRENT_USER { @@ -13739,6 +14282,7 @@ unreserved_keyword: | ASSERTION | ASSIGNMENT | AT + | ATTACH | ATTRIBUTE | BACKWARD | BEFORE @@ -13785,6 +14329,7 @@ unreserved_keyword: | DELIMITER | DELIMITERS | DEPENDS + | DETACH | DICTIONARY | DISABLE_P | DISCARD @@ -13865,6 +14410,7 @@ unreserved_keyword: | MOVE | NAME_P | NAMES + | NEW | NEXT | NO | NOTHING @@ -13875,6 +14421,7 @@ unreserved_keyword: | OF | OFF | OIDS + | OLD | OPERATOR | OPTION | OPTIONS @@ -13899,6 +14446,7 @@ unreserved_keyword: | PROCEDURAL | PROCEDURE | PROGRAM + | PUBLICATION | QUOTE | RANGE | READ @@ -13906,6 +14454,7 @@ unreserved_keyword: | RECHECK | RECURSIVE | REF + | REFERENCING | REFRESH | REINDEX | RELATIVE_P @@ -13941,6 +14490,7 @@ unreserved_keyword: | SHOW | SIMPLE | SKIP + | SLOT | SNAPSHOT | SQL_P | STABLE @@ -13953,6 +14503,7 @@ unreserved_keyword: | STORAGE | STRICT_P | STRIP_P + | SUBSCRIPTION | SYSID | SYSTEM_P | TABLES @@ -14194,6 +14745,33 @@ base_yyerror(YYLTYPE *yylloc, core_yyscan_t yyscanner, const char *msg) parser_yyerror(msg); } +static RawStmt * +makeRawStmt(Node *stmt, int stmt_location) +{ + RawStmt *rs = makeNode(RawStmt); + + rs->stmt = stmt; + rs->stmt_location = stmt_location; + rs->stmt_len = 0; /* might get changed later */ + return rs; +} + +/* Adjust a RawStmt to reflect that it doesn't run to the end of the string */ +static void +updateRawStmtEnd(RawStmt *rs, int end_location) +{ + /* + * If we already set the length, don't change it. This is for situations + * like "select foo ;; select bar" where the same statement will be last + * in the string for more than one semicolon. + */ + if (rs->stmt_len > 0) + return; + + /* OK, update length of RawStmt */ + rs->stmt_len = end_location - rs->stmt_location; +} + static Node * makeColumnRef(char *colname, List *indirection, int location, core_yyscan_t yyscanner) @@ -14365,7 +14943,7 @@ makeBoolAConst(bool state, int location) /* makeRoleSpec * Create a RoleSpec with the given type */ -static Node * +static RoleSpec * makeRoleSpec(RoleSpecType type, int location) { RoleSpec *spec = makeNode(RoleSpec); @@ -14373,7 +14951,7 @@ makeRoleSpec(RoleSpecType type, int location) spec->roletype = type; spec->location = location; - return (Node *) spec; + return spec; } /* check_qualified_name --- check the result of qualified_name production @@ -14710,6 +15288,18 @@ makeAArrayExpr(List *elements, int location) return (Node *) n; } +static Node * +makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod, int location) +{ + SQLValueFunction *svf = makeNode(SQLValueFunction); + + svf->op = op; + /* svf->type will be filled during parse analysis */ + svf->typmod = typmod; + svf->location = location; + return (Node *) svf; +} + static Node * makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, int location) diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c index 481a4ddc48..7be7fe9689 100644 --- a/src/backend/parser/parse_agg.c +++ b/src/backend/parser/parse_agg.c @@ -3,7 +3,7 @@ * parse_agg.c * handle aggregates and window functions in parser * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -447,6 +447,7 @@ check_agglevels_and_constraints(ParseState *pstate, Node *expr) errkind = true; break; case EXPR_KIND_VALUES: + case EXPR_KIND_VALUES_SINGLE: errkind = true; break; case EXPR_KIND_CHECK_CONSTRAINT: @@ -501,6 +502,13 @@ check_agglevels_and_constraints(ParseState *pstate, Node *expr) err = _("grouping operations are not allowed in trigger WHEN conditions"); break; + case EXPR_KIND_PARTITION_EXPRESSION: + if (isAgg) + err = _("aggregate functions are not allowed in partition key expression"); + else + err = _("grouping operations are not allowed in partition key expression"); + + break; /* * There is intentionally no default: case here, so that the @@ -833,6 +841,7 @@ transformWindowFuncCall(ParseState *pstate, WindowFunc *wfunc, errkind = true; break; case EXPR_KIND_VALUES: + case EXPR_KIND_VALUES_SINGLE: errkind = true; break; case EXPR_KIND_CHECK_CONSTRAINT: @@ -858,6 +867,9 @@ transformWindowFuncCall(ParseState *pstate, WindowFunc *wfunc, case EXPR_KIND_TRIGGER_WHEN: err = _("window functions are not allowed in trigger WHEN conditions"); break; + case EXPR_KIND_PARTITION_EXPRESSION: + err = _("window functions are not allowed in partition key expression"); + break; /* * There is intentionally no default: case here, so that the diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 751de4bddb..624ab41371 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -3,7 +3,7 @@ * parse_clause.c * handle clauses in parser * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -228,30 +228,6 @@ setTargetTable(ParseState *pstate, RangeVar *relation, return rtindex; } -/* - * Simplify InhOption (yes/no/default) into boolean yes/no. - * - * The reason we do things this way is that we don't want to examine the - * SQL_inheritance option flag until parse_analyze() is run. Otherwise, - * we'd do the wrong thing with query strings that intermix SET commands - * with queries. - */ -bool -interpretInhOption(InhOption inhOpt) -{ - switch (inhOpt) - { - case INH_NO: - return false; - case INH_YES: - return true; - case INH_DEFAULT: - return SQL_inheritance; - } - elog(ERROR, "bogus InhOption value: %d", inhOpt); - return false; /* keep compiler quiet */ -} - /* * Given a relation-options list (of DefElems), return true iff the specified * table/result set should be created with OIDs. This needs to be done after @@ -436,8 +412,7 @@ transformTableEntry(ParseState *pstate, RangeVar *r) RangeTblEntry *rte; /* We need only build a range table entry */ - rte = addRangeTableEntry(pstate, r, r->alias, - interpretInhOption(r->inhOpt), true); + rte = addRangeTableEntry(pstate, r, r->alias, r->inh, true); return rte; } @@ -503,12 +478,11 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r) pstate->p_expr_kind = EXPR_KIND_NONE; /* - * Check that we got something reasonable. Many of these conditions are - * impossible given restrictions of the grammar, but check 'em anyway. + * Check that we got a SELECT. Anything else should be impossible given + * restrictions of the grammar, but check anyway. */ if (!IsA(query, Query) || - query->commandType != CMD_SELECT || - query->utilityStmt != NULL) + query->commandType != CMD_SELECT) elog(ERROR, "unexpected non-SELECT command in subquery in FROM"); /* diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index d277fd6200..2a2ac32157 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -3,7 +3,7 @@ * parse_coerce.c * handle type coercions/conversions for parser * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -1077,8 +1077,9 @@ coerce_to_boolean(ParseState *pstate, Node *node, ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), /* translator: first %s is name of a SQL construct, eg WHERE */ - errmsg("argument of %s must be type boolean, not type %s", - constructName, format_type_be(inputTypeId)), + errmsg("argument of %s must be type %s, not type %s", + constructName, "boolean", + format_type_be(inputTypeId)), parser_errposition(pstate, exprLocation(node)))); node = newnode; } @@ -1695,8 +1696,8 @@ enforce_generic_type_consistency(Oid *actual_arg_types, if (!OidIsValid(array_typelem)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("argument declared \"anyarray\" is not an array but type %s", - format_type_be(array_typeid)))); + errmsg("argument declared %s is not an array but type %s", + "anyarray", format_type_be(array_typeid)))); } if (!OidIsValid(elem_typeid)) @@ -1711,7 +1712,8 @@ enforce_generic_type_consistency(Oid *actual_arg_types, /* otherwise, they better match */ ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("argument declared \"anyarray\" is not consistent with argument declared \"anyelement\""), + errmsg("argument declared %s is not consistent with argument declared %s", + "anyarray", "anyelement"), errdetail("%s versus %s", format_type_be(array_typeid), format_type_be(elem_typeid)))); @@ -1732,8 +1734,9 @@ enforce_generic_type_consistency(Oid *actual_arg_types, if (!OidIsValid(range_typelem)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("argument declared \"anyrange\" is not a range type but type %s", - format_type_be(range_typeid)))); + errmsg("argument declared %s is not a range type but type %s", + "anyrange", + format_type_be(range_typeid)))); } if (!OidIsValid(elem_typeid)) @@ -1748,7 +1751,8 @@ enforce_generic_type_consistency(Oid *actual_arg_types, /* otherwise, they better match */ ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("argument declared \"anyrange\" is not consistent with argument declared \"anyelement\""), + errmsg("argument declared %s is not consistent with argument declared %s", + "anyrange", "anyelement"), errdetail("%s versus %s", format_type_be(range_typeid), format_type_be(elem_typeid)))); @@ -1768,7 +1772,8 @@ enforce_generic_type_consistency(Oid *actual_arg_types, /* Only way to get here is if all the generic args are UNKNOWN */ ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("could not determine polymorphic type because input has type \"unknown\""))); + errmsg("could not determine polymorphic type because input has type %s", + "unknown"))); } } @@ -1906,8 +1911,8 @@ resolve_generic_type(Oid declared_type, if (!OidIsValid(array_typelem)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("argument declared \"anyarray\" is not an array but type %s", - format_type_be(context_base_type)))); + errmsg("argument declared %s is not an array but type %s", + "anyarray", format_type_be(context_base_type)))); return context_base_type; } else if (context_declared_type == ANYELEMENTOID || @@ -1940,8 +1945,8 @@ resolve_generic_type(Oid declared_type, if (!OidIsValid(array_typelem)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("argument declared \"anyarray\" is not an array but type %s", - format_type_be(context_base_type)))); + errmsg("argument declared %s is not an array but type %s", + "anyarray", format_type_be(context_base_type)))); return array_typelem; } else if (context_declared_type == ANYRANGEOID) @@ -1953,8 +1958,8 @@ resolve_generic_type(Oid declared_type, if (!OidIsValid(range_typelem)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("argument declared \"anyrange\" is not a range type but type %s", - format_type_be(context_base_type)))); + errmsg("argument declared %s is not a range type but type %s", + "anyrange", format_type_be(context_base_type)))); return range_typelem; } else if (context_declared_type == ANYELEMENTOID || diff --git a/src/backend/parser/parse_collate.c b/src/backend/parser/parse_collate.c index a19e8dd075..832897f68d 100644 --- a/src/backend/parser/parse_collate.c +++ b/src/backend/parser/parse_collate.c @@ -29,7 +29,7 @@ * at runtime. If we knew exactly which functions require collation * information, we could throw those errors at parse time instead. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/parser/parse_cte.c b/src/backend/parser/parse_cte.c index 5e8bcd40d5..fc8c15b268 100644 --- a/src/backend/parser/parse_cte.c +++ b/src/backend/parser/parse_cte.c @@ -3,7 +3,7 @@ * parse_cte.c * handle CTEs (common table expressions) in parser * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index cead21283d..add3be6566 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -3,7 +3,7 @@ * parse_expr.c * handle expressions in parser * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -34,7 +34,9 @@ #include "parser/parse_type.h" #include "parser/parse_agg.h" #include "utils/builtins.h" +#include "utils/date.h" #include "utils/lsyscache.h" +#include "utils/timestamp.h" #include "utils/xml.h" @@ -104,9 +106,11 @@ static Node *transformCaseExpr(ParseState *pstate, CaseExpr *c); static Node *transformSubLink(ParseState *pstate, SubLink *sublink); static Node *transformArrayExpr(ParseState *pstate, A_ArrayExpr *a, Oid array_type, Oid element_type, int32 typmod); -static Node *transformRowExpr(ParseState *pstate, RowExpr *r); +static Node *transformRowExpr(ParseState *pstate, RowExpr *r, bool allowDefault); static Node *transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c); static Node *transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m); +static Node *transformSQLValueFunction(ParseState *pstate, + SQLValueFunction *svf); static Node *transformXmlExpr(ParseState *pstate, XmlExpr *x); static Node *transformXmlSerialize(ParseState *pstate, XmlSerialize *xs); static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b); @@ -295,7 +299,7 @@ transformExprRecurse(ParseState *pstate, Node *expr) break; case T_RowExpr: - result = transformRowExpr(pstate, (RowExpr *) expr); + result = transformRowExpr(pstate, (RowExpr *) expr, false); break; case T_CoalesceExpr: @@ -306,6 +310,11 @@ transformExprRecurse(ParseState *pstate, Node *expr) result = transformMinMaxExpr(pstate, (MinMaxExpr *) expr); break; + case T_SQLValueFunction: + result = transformSQLValueFunction(pstate, + (SQLValueFunction *) expr); + break; + case T_XmlExpr: result = transformXmlExpr(pstate, (XmlExpr *) expr); break; @@ -339,8 +348,20 @@ transformExprRecurse(ParseState *pstate, Node *expr) break; /* - * CaseTestExpr and SetToDefault don't require any processing; - * they are only injected into parse trees in fully-formed state. + * In all places where DEFAULT is legal, the caller should have + * processed it rather than passing it to transformExpr(). + */ + case T_SetToDefault: + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("DEFAULT is not allowed in this context"), + parser_errposition(pstate, + ((SetToDefault *) expr)->location))); + break; + + /* + * CaseTestExpr doesn't require any processing; it is only + * injected into parse trees in a fully-formed state. * * Ordinarily we should not see a Var here, but it is convenient * for transformJoinUsingClause() to create untransformed operator @@ -349,7 +370,6 @@ transformExprRecurse(ParseState *pstate, Node *expr) * references, which seems expensively pointless. So allow it. */ case T_CaseTestExpr: - case T_SetToDefault: case T_Var: { result = (Node *) expr; @@ -557,27 +577,6 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) /* * Not known as a column of any range-table entry. * - * Consider the possibility that it's VALUE in a domain - * check expression. (We handle VALUE as a name, not a - * keyword, to avoid breaking a lot of applications that - * have used VALUE as a column name in the past.) - */ - if (pstate->p_value_substitute != NULL && - strcmp(colname, "value") == 0) - { - node = (Node *) copyObject(pstate->p_value_substitute); - - /* - * Try to propagate location knowledge. This should - * be extended if p_value_substitute can ever take on - * other node types. - */ - if (IsA(node, CoerceToDomainValue)) - ((CoerceToDomainValue *) node)->location = cref->location; - break; - } - - /* * Try to find the name as a relation. Note that only * relations already entered into the rangetable will be * recognized. @@ -1477,9 +1476,9 @@ static Node * transformMultiAssignRef(ParseState *pstate, MultiAssignRef *maref) { SubLink *sublink; + RowExpr *rexpr; Query *qtree; TargetEntry *tle; - Param *param; /* We should only see this in first-stage processing of UPDATE tlists */ Assert(pstate->p_expr_kind == EXPR_KIND_UPDATE_SOURCE); @@ -1487,64 +1486,139 @@ transformMultiAssignRef(ParseState *pstate, MultiAssignRef *maref) /* We only need to transform the source if this is the first column */ if (maref->colno == 1) { - sublink = (SubLink *) transformExprRecurse(pstate, maref->source); - /* Currently, the grammar only allows a SubLink as source */ - Assert(IsA(sublink, SubLink)); - Assert(sublink->subLinkType == MULTIEXPR_SUBLINK); - qtree = (Query *) sublink->subselect; - Assert(IsA(qtree, Query)); - - /* Check subquery returns required number of columns */ - if (count_nonjunk_tlist_entries(qtree->targetList) != maref->ncolumns) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("number of columns does not match number of values"), - parser_errposition(pstate, sublink->location))); - /* - * Build a resjunk tlist item containing the MULTIEXPR SubLink, and - * add it to pstate->p_multiassign_exprs, whence it will later get - * appended to the completed targetlist. We needn't worry about - * selecting a resno for it; transformUpdateStmt will do that. + * For now, we only allow EXPR SubLinks and RowExprs as the source of + * an UPDATE multiassignment. This is sufficient to cover interesting + * cases; at worst, someone would have to write (SELECT * FROM expr) + * to expand a composite-returning expression of another form. */ - tle = makeTargetEntry((Expr *) sublink, 0, NULL, true); - pstate->p_multiassign_exprs = lappend(pstate->p_multiassign_exprs, tle); + if (IsA(maref->source, SubLink) && + ((SubLink *) maref->source)->subLinkType == EXPR_SUBLINK) + { + /* Relabel it as a MULTIEXPR_SUBLINK */ + sublink = (SubLink *) maref->source; + sublink->subLinkType = MULTIEXPR_SUBLINK; + /* And transform it */ + sublink = (SubLink *) transformExprRecurse(pstate, + (Node *) sublink); + + qtree = (Query *) sublink->subselect; + Assert(IsA(qtree, Query)); + + /* Check subquery returns required number of columns */ + if (count_nonjunk_tlist_entries(qtree->targetList) != maref->ncolumns) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("number of columns does not match number of values"), + parser_errposition(pstate, sublink->location))); - /* - * Assign a unique-within-this-targetlist ID to the MULTIEXPR SubLink. - * We can just use its position in the p_multiassign_exprs list. - */ - sublink->subLinkId = list_length(pstate->p_multiassign_exprs); + /* + * Build a resjunk tlist item containing the MULTIEXPR SubLink, + * and add it to pstate->p_multiassign_exprs, whence it will later + * get appended to the completed targetlist. We needn't worry + * about selecting a resno for it; transformUpdateStmt will do + * that. + */ + tle = makeTargetEntry((Expr *) sublink, 0, NULL, true); + pstate->p_multiassign_exprs = lappend(pstate->p_multiassign_exprs, + tle); + + /* + * Assign a unique-within-this-targetlist ID to the MULTIEXPR + * SubLink. We can just use its position in the + * p_multiassign_exprs list. + */ + sublink->subLinkId = list_length(pstate->p_multiassign_exprs); + } + else if (IsA(maref->source, RowExpr)) + { + /* Transform the RowExpr, allowing SetToDefault items */ + rexpr = (RowExpr *) transformRowExpr(pstate, + (RowExpr *) maref->source, + true); + + /* Check it returns required number of columns */ + if (list_length(rexpr->args) != maref->ncolumns) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("number of columns does not match number of values"), + parser_errposition(pstate, rexpr->location))); + + /* + * Temporarily append it to p_multiassign_exprs, so we can get it + * back when we come back here for additional columns. + */ + tle = makeTargetEntry((Expr *) rexpr, 0, NULL, true); + pstate->p_multiassign_exprs = lappend(pstate->p_multiassign_exprs, + tle); + } + else + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("source for a multiple-column UPDATE item must be a sub-SELECT or ROW() expression"), + parser_errposition(pstate, exprLocation(maref->source)))); } else { /* * Second or later column in a multiassignment. Re-fetch the - * transformed query, which we assume is still the last entry in - * p_multiassign_exprs. + * transformed SubLink or RowExpr, which we assume is still the last + * entry in p_multiassign_exprs. */ Assert(pstate->p_multiassign_exprs != NIL); tle = (TargetEntry *) llast(pstate->p_multiassign_exprs); + } + + /* + * Emit the appropriate output expression for the current column + */ + if (IsA(tle->expr, SubLink)) + { + Param *param; + sublink = (SubLink *) tle->expr; - Assert(IsA(sublink, SubLink)); Assert(sublink->subLinkType == MULTIEXPR_SUBLINK); qtree = (Query *) sublink->subselect; Assert(IsA(qtree, Query)); + + /* Build a Param representing the current subquery output column */ + tle = (TargetEntry *) list_nth(qtree->targetList, maref->colno - 1); + Assert(!tle->resjunk); + + param = makeNode(Param); + param->paramkind = PARAM_MULTIEXPR; + param->paramid = (sublink->subLinkId << 16) | maref->colno; + param->paramtype = exprType((Node *) tle->expr); + param->paramtypmod = exprTypmod((Node *) tle->expr); + param->paramcollid = exprCollation((Node *) tle->expr); + param->location = exprLocation((Node *) tle->expr); + + return (Node *) param; } - /* Build a Param representing the appropriate subquery output column */ - tle = (TargetEntry *) list_nth(qtree->targetList, maref->colno - 1); - Assert(!tle->resjunk); + if (IsA(tle->expr, RowExpr)) + { + Node *result; + + rexpr = (RowExpr *) tle->expr; - param = makeNode(Param); - param->paramkind = PARAM_MULTIEXPR; - param->paramid = (sublink->subLinkId << 16) | maref->colno; - param->paramtype = exprType((Node *) tle->expr); - param->paramtypmod = exprTypmod((Node *) tle->expr); - param->paramcollid = exprCollation((Node *) tle->expr); - param->location = exprLocation((Node *) tle->expr); + /* Just extract and return the next element of the RowExpr */ + result = (Node *) list_nth(rexpr->args, maref->colno - 1); + + /* + * If we're at the last column, delete the RowExpr from + * p_multiassign_exprs; we don't need it anymore, and don't want it in + * the finished UPDATE tlist. + */ + if (maref->colno == maref->ncolumns) + pstate->p_multiassign_exprs = + list_delete_ptr(pstate->p_multiassign_exprs, tle); + + return result; + } - return (Node *) param; + elog(ERROR, "unexpected expr type in multiassign list"); + return NULL; /* keep compiler quiet */ } static Node * @@ -1723,6 +1797,7 @@ transformSubLink(ParseState *pstate, SubLink *sublink) case EXPR_KIND_OFFSET: case EXPR_KIND_RETURNING: case EXPR_KIND_VALUES: + case EXPR_KIND_VALUES_SINGLE: /* okay */ break; case EXPR_KIND_CHECK_CONSTRAINT: @@ -1748,6 +1823,9 @@ transformSubLink(ParseState *pstate, SubLink *sublink) case EXPR_KIND_TRIGGER_WHEN: err = _("cannot use subquery in trigger WHEN condition"); break; + case EXPR_KIND_PARTITION_EXPRESSION: + err = _("cannot use subquery in partition key expression"); + break; /* * There is intentionally no default: case here, so that the @@ -1771,12 +1849,11 @@ transformSubLink(ParseState *pstate, SubLink *sublink) qtree = parse_sub_analyze(sublink->subselect, pstate, NULL, false); /* - * Check that we got something reasonable. Many of these conditions are - * impossible given restrictions of the grammar, but check 'em anyway. + * Check that we got a SELECT. Anything else should be impossible given + * restrictions of the grammar, but check anyway. */ if (!IsA(qtree, Query) || - qtree->commandType != CMD_SELECT || - qtree->utilityStmt != NULL) + qtree->commandType != CMD_SELECT) elog(ERROR, "unexpected non-SELECT command in SubLink"); sublink->subselect = (Node *) qtree; @@ -2072,7 +2149,7 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a, } static Node * -transformRowExpr(ParseState *pstate, RowExpr *r) +transformRowExpr(ParseState *pstate, RowExpr *r, bool allowDefault) { RowExpr *newr; char fname[16]; @@ -2082,7 +2159,8 @@ transformRowExpr(ParseState *pstate, RowExpr *r) newr = makeNode(RowExpr); /* Transform the field expressions */ - newr->args = transformExpressionList(pstate, r->args, pstate->p_expr_kind); + newr->args = transformExpressionList(pstate, r->args, + pstate->p_expr_kind, allowDefault); /* Barring later casting, we consider the type RECORD */ newr->row_typeid = RECORDOID; @@ -2178,6 +2256,59 @@ transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m) return (Node *) newm; } +static Node * +transformSQLValueFunction(ParseState *pstate, SQLValueFunction *svf) +{ + /* + * All we need to do is insert the correct result type and (where needed) + * validate the typmod, so we just modify the node in-place. + */ + switch (svf->op) + { + case SVFOP_CURRENT_DATE: + svf->type = DATEOID; + break; + case SVFOP_CURRENT_TIME: + svf->type = TIMETZOID; + break; + case SVFOP_CURRENT_TIME_N: + svf->type = TIMETZOID; + svf->typmod = anytime_typmod_check(true, svf->typmod); + break; + case SVFOP_CURRENT_TIMESTAMP: + svf->type = TIMESTAMPTZOID; + break; + case SVFOP_CURRENT_TIMESTAMP_N: + svf->type = TIMESTAMPTZOID; + svf->typmod = anytimestamp_typmod_check(true, svf->typmod); + break; + case SVFOP_LOCALTIME: + svf->type = TIMEOID; + break; + case SVFOP_LOCALTIME_N: + svf->type = TIMEOID; + svf->typmod = anytime_typmod_check(false, svf->typmod); + break; + case SVFOP_LOCALTIMESTAMP: + svf->type = TIMESTAMPOID; + break; + case SVFOP_LOCALTIMESTAMP_N: + svf->type = TIMESTAMPOID; + svf->typmod = anytimestamp_typmod_check(false, svf->typmod); + break; + case SVFOP_CURRENT_ROLE: + case SVFOP_CURRENT_USER: + case SVFOP_USER: + case SVFOP_SESSION_USER: + case SVFOP_CURRENT_CATALOG: + case SVFOP_CURRENT_SCHEMA: + svf->type = NAMEOID; + break; + } + + return (Node *) svf; +} + static Node * transformXmlExpr(ParseState *pstate, XmlExpr *x) { @@ -3280,6 +3411,7 @@ ParseExprKindName(ParseExprKind exprKind) case EXPR_KIND_RETURNING: return "RETURNING"; case EXPR_KIND_VALUES: + case EXPR_KIND_VALUES_SINGLE: return "VALUES"; case EXPR_KIND_CHECK_CONSTRAINT: case EXPR_KIND_DOMAIN_CHECK: @@ -3297,6 +3429,8 @@ ParseExprKindName(ParseExprKind exprKind) return "EXECUTE"; case EXPR_KIND_TRIGGER_WHEN: return "WHEN"; + case EXPR_KIND_PARTITION_EXPRESSION: + return "PARTITION BY"; /* * There is intentionally no default: case here, so that the diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 61af484fee..a52261f2e9 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -3,7 +3,7 @@ * parse_func.c * handle function calls in parser * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -25,6 +25,7 @@ #include "parser/parse_agg.h" #include "parser/parse_clause.h" #include "parser/parse_coerce.h" +#include "parser/parse_expr.h" #include "parser/parse_func.h" #include "parser/parse_relation.h" #include "parser/parse_target.h" @@ -625,6 +626,10 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, exprLocation((Node *) llast(fargs))))); } + /* if it returns a set, check that's OK */ + if (retset) + check_srf_call_placement(pstate, location); + /* build the appropriate output structure */ if (fdresult == FUNCDETAIL_NORMAL) { @@ -2040,3 +2045,154 @@ LookupAggNameTypeNames(List *aggname, List *argtypes, bool noError) return oid; } + + +/* + * check_srf_call_placement + * Verify that a set-returning function is called in a valid place, + * and throw a nice error if not. + * + * A side-effect is to set pstate->p_hasTargetSRFs true if appropriate. + */ +void +check_srf_call_placement(ParseState *pstate, int location) +{ + const char *err; + bool errkind; + + /* + * Check to see if the set-returning function is in an invalid place + * within the query. Basically, we don't allow SRFs anywhere except in + * the targetlist (which includes GROUP BY/ORDER BY expressions), VALUES, + * and functions in FROM. + * + * For brevity we support two schemes for reporting an error here: set + * "err" to a custom message, or set "errkind" true if the error context + * is sufficiently identified by what ParseExprKindName will return, *and* + * what it will return is just a SQL keyword. (Otherwise, use a custom + * message to avoid creating translation problems.) + */ + err = NULL; + errkind = false; + switch (pstate->p_expr_kind) + { + case EXPR_KIND_NONE: + Assert(false); /* can't happen */ + break; + case EXPR_KIND_OTHER: + /* Accept SRF here; caller must throw error if wanted */ + break; + case EXPR_KIND_JOIN_ON: + case EXPR_KIND_JOIN_USING: + err = _("set-returning functions are not allowed in JOIN conditions"); + break; + case EXPR_KIND_FROM_SUBSELECT: + /* can't get here, but just in case, throw an error */ + errkind = true; + break; + case EXPR_KIND_FROM_FUNCTION: + /* okay ... but we can't check nesting here */ + break; + case EXPR_KIND_WHERE: + errkind = true; + break; + case EXPR_KIND_POLICY: + err = _("set-returning functions are not allowed in policy expressions"); + break; + case EXPR_KIND_HAVING: + errkind = true; + break; + case EXPR_KIND_FILTER: + errkind = true; + break; + case EXPR_KIND_WINDOW_PARTITION: + case EXPR_KIND_WINDOW_ORDER: + /* okay, these are effectively GROUP BY/ORDER BY */ + pstate->p_hasTargetSRFs = true; + break; + case EXPR_KIND_WINDOW_FRAME_RANGE: + case EXPR_KIND_WINDOW_FRAME_ROWS: + err = _("set-returning functions are not allowed in window definitions"); + break; + case EXPR_KIND_SELECT_TARGET: + case EXPR_KIND_INSERT_TARGET: + /* okay */ + pstate->p_hasTargetSRFs = true; + break; + case EXPR_KIND_UPDATE_SOURCE: + case EXPR_KIND_UPDATE_TARGET: + /* disallowed because it would be ambiguous what to do */ + errkind = true; + break; + case EXPR_KIND_GROUP_BY: + case EXPR_KIND_ORDER_BY: + /* okay */ + pstate->p_hasTargetSRFs = true; + break; + case EXPR_KIND_DISTINCT_ON: + /* okay */ + pstate->p_hasTargetSRFs = true; + break; + case EXPR_KIND_LIMIT: + case EXPR_KIND_OFFSET: + errkind = true; + break; + case EXPR_KIND_RETURNING: + errkind = true; + break; + case EXPR_KIND_VALUES: + /* SRFs are presently not supported by nodeValuesscan.c */ + errkind = true; + break; + case EXPR_KIND_VALUES_SINGLE: + /* okay, since we process this like a SELECT tlist */ + pstate->p_hasTargetSRFs = true; + break; + case EXPR_KIND_CHECK_CONSTRAINT: + case EXPR_KIND_DOMAIN_CHECK: + err = _("set-returning functions are not allowed in check constraints"); + break; + case EXPR_KIND_COLUMN_DEFAULT: + case EXPR_KIND_FUNCTION_DEFAULT: + err = _("set-returning functions are not allowed in DEFAULT expressions"); + break; + case EXPR_KIND_INDEX_EXPRESSION: + err = _("set-returning functions are not allowed in index expressions"); + break; + case EXPR_KIND_INDEX_PREDICATE: + err = _("set-returning functions are not allowed in index predicates"); + break; + case EXPR_KIND_ALTER_COL_TRANSFORM: + err = _("set-returning functions are not allowed in transform expressions"); + break; + case EXPR_KIND_EXECUTE_PARAMETER: + err = _("set-returning functions are not allowed in EXECUTE parameters"); + break; + case EXPR_KIND_TRIGGER_WHEN: + err = _("set-returning functions are not allowed in trigger WHEN conditions"); + break; + case EXPR_KIND_PARTITION_EXPRESSION: + err = _("set-returning functions are not allowed in partition key expression"); + break; + + /* + * There is intentionally no default: case here, so that the + * compiler will warn if we add a new ParseExprKind without + * extending this switch. If we do see an unrecognized value at + * runtime, the behavior will be the same as for EXPR_KIND_OTHER, + * which is sane anyway. + */ + } + if (err) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg_internal("%s", err), + parser_errposition(pstate, location))); + if (errkind) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + /* translator: %s is name of a SQL construct, eg GROUP BY */ + errmsg("set-returning functions are not allowed in %s", + ParseExprKindName(pstate->p_expr_kind)), + parser_errposition(pstate, location))); +} diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c index 62d2f7105f..73e7d65c35 100644 --- a/src/backend/parser/parse_node.c +++ b/src/backend/parser/parse_node.c @@ -3,7 +3,7 @@ * parse_node.c * various routines that make nodes for querytrees * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c index e913d05a79..894e900073 100644 --- a/src/backend/parser/parse_oper.c +++ b/src/backend/parser/parse_oper.c @@ -3,7 +3,7 @@ * parse_oper.c * handle operator things for parser * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -839,6 +839,10 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree, result->args = args; result->location = location; + /* if it returns a set, check that's OK */ + if (result->opretset) + check_srf_call_placement(pstate, location); + ReleaseSysCache(tup); return (Expr *) result; diff --git a/src/backend/parser/parse_param.c b/src/backend/parser/parse_param.c index b402843680..2575e02325 100644 --- a/src/backend/parser/parse_param.c +++ b/src/backend/parser/parse_param.c @@ -12,7 +12,7 @@ * Note that other approaches to parameters are possible using the parser * hooks defined in ParseState. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index 1e3ecbc51e..e693c316e3 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -3,7 +3,7 @@ * parse_relation.c * parser support routines dealing with relations * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -31,6 +31,7 @@ #include "utils/lsyscache.h" #include "utils/rel.h" #include "utils/syscache.h" +#include "utils/varlena.h" #define MAX_FUZZY_DISTANCE 3 @@ -1635,7 +1636,9 @@ addRangeTableEntryForFunction(ParseState *pstate, RangeTblEntry * addRangeTableEntryForValues(ParseState *pstate, List *exprs, - List *collations, + List *coltypes, + List *coltypmods, + List *colcollations, Alias *alias, bool lateral, bool inFromCl) @@ -1652,7 +1655,9 @@ addRangeTableEntryForValues(ParseState *pstate, rte->relid = InvalidOid; rte->subquery = NULL; rte->values_lists = exprs; - rte->values_collations = collations; + rte->coltypes = coltypes; + rte->coltypmods = coltypmods; + rte->colcollations = colcollations; rte->alias = alias; eref = alias ? copyObject(alias) : makeAlias(refname, NIL); @@ -1822,9 +1827,9 @@ addRangeTableEntryForCTE(ParseState *pstate, parser_errposition(pstate, rv->location))); } - rte->ctecoltypes = cte->ctecoltypes; - rte->ctecoltypmods = cte->ctecoltypmods; - rte->ctecolcollations = cte->ctecolcollations; + rte->coltypes = cte->ctecoltypes; + rte->coltypmods = cte->ctecoltypmods; + rte->colcollations = cte->ctecolcollations; rte->alias = alias; if (alias) @@ -2153,46 +2158,6 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, } } break; - case RTE_VALUES: - { - /* Values RTE */ - ListCell *aliasp_item = list_head(rte->eref->colnames); - ListCell *lcv; - ListCell *lcc; - - varattno = 0; - forboth(lcv, (List *) linitial(rte->values_lists), - lcc, rte->values_collations) - { - Node *col = (Node *) lfirst(lcv); - Oid colcollation = lfirst_oid(lcc); - - varattno++; - if (colnames) - { - /* Assume there is one alias per column */ - char *label = strVal(lfirst(aliasp_item)); - - *colnames = lappend(*colnames, - makeString(pstrdup(label))); - aliasp_item = lnext(aliasp_item); - } - - if (colvars) - { - Var *varnode; - - varnode = makeVar(rtindex, varattno, - exprType(col), - exprTypmod(col), - colcollation, - sublevels_up); - varnode->location = location; - *colvars = lappend(*colvars, varnode); - } - } - } - break; case RTE_JOIN: { /* Join RTE */ @@ -2262,17 +2227,19 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, } } break; + case RTE_VALUES: case RTE_CTE: { + /* Values or CTE RTE */ ListCell *aliasp_item = list_head(rte->eref->colnames); ListCell *lct; ListCell *lcm; ListCell *lcc; varattno = 0; - forthree(lct, rte->ctecoltypes, - lcm, rte->ctecoltypmods, - lcc, rte->ctecolcollations) + forthree(lct, rte->coltypes, + lcm, rte->coltypmods, + lcc, rte->colcollations) { Oid coltype = lfirst_oid(lct); int32 coltypmod = lfirst_int(lcm); @@ -2285,7 +2252,8 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, /* Assume there is one alias per output column */ char *label = strVal(lfirst(aliasp_item)); - *colnames = lappend(*colnames, makeString(pstrdup(label))); + *colnames = lappend(*colnames, + makeString(pstrdup(label))); aliasp_item = lnext(aliasp_item); } @@ -2296,6 +2264,8 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, varnode = makeVar(rtindex, varattno, coltype, coltypmod, colcoll, sublevels_up); + varnode->location = location; + *colvars = lappend(*colvars, varnode); } } @@ -2654,22 +2624,6 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum, rte->eref->aliasname))); } break; - case RTE_VALUES: - { - /* Values RTE --- get type info from first sublist */ - /* collation is stored separately, though */ - List *collist = (List *) linitial(rte->values_lists); - Node *col; - - if (attnum < 1 || attnum > list_length(collist)) - elog(ERROR, "values list %s does not have attribute %d", - rte->eref->aliasname, attnum); - col = (Node *) list_nth(collist, attnum - 1); - *vartype = exprType(col); - *vartypmod = exprTypmod(col); - *varcollid = list_nth_oid(rte->values_collations, attnum - 1); - } - break; case RTE_JOIN: { /* @@ -2685,13 +2639,14 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum, *varcollid = exprCollation(aliasvar); } break; + case RTE_VALUES: case RTE_CTE: { - /* CTE RTE --- get type info from lists in the RTE */ - Assert(attnum > 0 && attnum <= list_length(rte->ctecoltypes)); - *vartype = list_nth_oid(rte->ctecoltypes, attnum - 1); - *vartypmod = list_nth_int(rte->ctecoltypmods, attnum - 1); - *varcollid = list_nth_oid(rte->ctecolcollations, attnum - 1); + /* VALUES or CTE RTE --- get type info from lists in the RTE */ + Assert(attnum > 0 && attnum <= list_length(rte->coltypes)); + *vartype = list_nth_oid(rte->coltypes, attnum - 1); + *vartypmod = list_nth_int(rte->coltypmods, attnum - 1); + *varcollid = list_nth_oid(rte->colcollations, attnum - 1); } break; default: diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index fc93063ed0..081a8dd468 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -3,7 +3,7 @@ * parse_target.c * handle target lists * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -91,7 +91,17 @@ transformTargetEntry(ParseState *pstate, { /* Transform the node if caller didn't do it already */ if (expr == NULL) - expr = transformExpr(pstate, node, exprKind); + { + /* + * If it's a SetToDefault node and we should allow that, pass it + * through unmodified. (transformExpr will throw the appropriate + * error if we're disallowing it.) + */ + if (exprKind == EXPR_KIND_UPDATE_SOURCE && IsA(node, SetToDefault)) + expr = node; + else + expr = transformExpr(pstate, node, exprKind); + } if (colname == NULL && !resjunk) { @@ -122,11 +132,15 @@ transformTargetList(ParseState *pstate, List *targetlist, ParseExprKind exprKind) { List *p_target = NIL; + bool expand_star; ListCell *o_target; /* Shouldn't have any leftover multiassign items at start */ Assert(pstate->p_multiassign_exprs == NIL); + /* Expand "something.*" in SELECT and RETURNING, but not UPDATE */ + expand_star = (exprKind != EXPR_KIND_UPDATE_SOURCE); + foreach(o_target, targetlist) { ResTarget *res = (ResTarget *) lfirst(o_target); @@ -136,35 +150,42 @@ transformTargetList(ParseState *pstate, List *targetlist, * "something", the star could appear as the last field in ColumnRef, * or as the last indirection item in A_Indirection. */ - if (IsA(res->val, ColumnRef)) + if (expand_star) { - ColumnRef *cref = (ColumnRef *) res->val; - - if (IsA(llast(cref->fields), A_Star)) + if (IsA(res->val, ColumnRef)) { - /* It is something.*, expand into multiple items */ - p_target = list_concat(p_target, - ExpandColumnRefStar(pstate, cref, - true)); - continue; - } - } - else if (IsA(res->val, A_Indirection)) - { - A_Indirection *ind = (A_Indirection *) res->val; + ColumnRef *cref = (ColumnRef *) res->val; - if (IsA(llast(ind->indirection), A_Star)) + if (IsA(llast(cref->fields), A_Star)) + { + /* It is something.*, expand into multiple items */ + p_target = list_concat(p_target, + ExpandColumnRefStar(pstate, + cref, + true)); + continue; + } + } + else if (IsA(res->val, A_Indirection)) { - /* It is something.*, expand into multiple items */ - p_target = list_concat(p_target, - ExpandIndirectionStar(pstate, ind, - true, exprKind)); - continue; + A_Indirection *ind = (A_Indirection *) res->val; + + if (IsA(llast(ind->indirection), A_Star)) + { + /* It is something.*, expand into multiple items */ + p_target = list_concat(p_target, + ExpandIndirectionStar(pstate, + ind, + true, + exprKind)); + continue; + } } } /* - * Not "something.*", so transform as a single expression + * Not "something.*", or we want to treat that as a plain whole-row + * variable, so transform as a single expression */ p_target = lappend(p_target, transformTargetEntry(pstate, @@ -199,10 +220,13 @@ transformTargetList(ParseState *pstate, List *targetlist, * the input list elements are bare expressions without ResTarget decoration, * and the output elements are likewise just expressions without TargetEntry * decoration. We use this for ROW() and VALUES() constructs. + * + * exprKind is not enough to tell us whether to allow SetToDefault, so + * an additional flag is needed for that. */ List * transformExpressionList(ParseState *pstate, List *exprlist, - ParseExprKind exprKind) + ParseExprKind exprKind, bool allowDefault) { List *result = NIL; ListCell *lc; @@ -244,10 +268,17 @@ transformExpressionList(ParseState *pstate, List *exprlist, } /* - * Not "something.*", so transform as a single expression + * Not "something.*", so transform as a single expression. If it's a + * SetToDefault node and we should allow that, pass it through + * unmodified. (transformExpr will throw the appropriate error if + * we're disallowing it.) */ - result = lappend(result, - transformExpr(pstate, e, exprKind)); + if (allowDefault && IsA(e, SetToDefault)) + /* do nothing */ ; + else + e = transformExpr(pstate, e, exprKind); + + result = lappend(result, e); } /* Shouldn't have any multiassign items here */ @@ -1761,6 +1792,49 @@ FigureColnameInternal(Node *node, char **name) return 2; } break; + case T_SQLValueFunction: + /* make these act like a function or variable */ + switch (((SQLValueFunction *) node)->op) + { + case SVFOP_CURRENT_DATE: + *name = "current_date"; + return 2; + case SVFOP_CURRENT_TIME: + case SVFOP_CURRENT_TIME_N: + *name = "current_time"; + return 2; + case SVFOP_CURRENT_TIMESTAMP: + case SVFOP_CURRENT_TIMESTAMP_N: + *name = "current_timestamp"; + return 2; + case SVFOP_LOCALTIME: + case SVFOP_LOCALTIME_N: + *name = "localtime"; + return 2; + case SVFOP_LOCALTIMESTAMP: + case SVFOP_LOCALTIMESTAMP_N: + *name = "localtimestamp"; + return 2; + case SVFOP_CURRENT_ROLE: + *name = "current_role"; + return 2; + case SVFOP_CURRENT_USER: + *name = "current_user"; + return 2; + case SVFOP_USER: + *name = "user"; + return 2; + case SVFOP_SESSION_USER: + *name = "session_user"; + return 2; + case SVFOP_CURRENT_CATALOG: + *name = "current_catalog"; + return 2; + case SVFOP_CURRENT_SCHEMA: + *name = "current_schema"; + return 2; + } + break; case T_XmlExpr: /* make SQL/XML functions act like a regular function */ switch (((XmlExpr *) node)->op) diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c index a8bb4721f3..6660929dec 100644 --- a/src/backend/parser/parse_type.c +++ b/src/backend/parser/parse_type.c @@ -3,7 +3,7 @@ * parse_type.c * handle type operations for parser * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -720,7 +720,7 @@ typeStringToTypeName(const char *str) */ if (list_length(raw_parsetree_list) != 1) goto fail; - stmt = (SelectStmt *) linitial(raw_parsetree_list); + stmt = (SelectStmt *) ((RawStmt *) linitial(raw_parsetree_list))->stmt; if (stmt == NULL || !IsA(stmt, SelectStmt) || stmt->distinctClause != NIL || diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index e98fad051e..0e4e7a8c80 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -16,7 +16,7 @@ * a quick copyObject() call before manipulating the query tree. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/parser/parse_utilcmd.c @@ -47,8 +47,10 @@ #include "miscadmin.h" #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" +#include "optimizer/planner.h" #include "parser/analyze.h" #include "parser/parse_clause.h" +#include "parser/parse_coerce.h" #include "parser/parse_collate.h" #include "parser/parse_expr.h" #include "parser/parse_relation.h" @@ -59,9 +61,9 @@ #include "rewrite/rewriteManip.h" #include "utils/acl.h" #include "utils/builtins.h" -#include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/rel.h" +#include "utils/ruleutils.h" #include "utils/syscache.h" #include "utils/typcache.h" @@ -87,6 +89,8 @@ typedef struct List *alist; /* "after list" of things to do after creating * the table */ IndexStmt *pkey; /* PRIMARY KEY index, if any */ + bool ispartitioned; /* true if table is partitioned */ + Node *partbound; /* transformed FOR VALUES */ } CreateStmtContext; /* State shared by transformCreateSchemaStmt and its subroutines */ @@ -129,6 +133,7 @@ static void transformConstraintAttrs(CreateStmtContext *cxt, List *constraintList); static void transformColumnType(CreateStmtContext *cxt, ColumnDef *column); static void setSchemaName(char *context_schema, char **stmt_schema_name); +static void transformAttachPartition(CreateStmtContext *cxt, PartitionCmd *cmd); /* @@ -229,6 +234,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString) cxt.blist = NIL; cxt.alist = NIL; cxt.pkey = NULL; + cxt.ispartitioned = stmt->partspec != NULL; /* * Notice that we allow OIDs here only for plain tables, even though @@ -247,12 +253,31 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString) if (stmt->ofTypename) transformOfType(&cxt, stmt->ofTypename); + if (stmt->partspec) + { + int partnatts = list_length(stmt->partspec->partParams); + + if (stmt->inhRelations && !stmt->partbound) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("cannot create partitioned table as inheritance child"))); + + if (partnatts > PARTITION_MAX_KEYS) + ereport(ERROR, + (errcode(ERRCODE_TOO_MANY_COLUMNS), + errmsg("cannot partition using more than %d columns", + PARTITION_MAX_KEYS))); + + if (!pg_strcasecmp(stmt->partspec->strategy, "list") && + partnatts > 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("cannot list partition using more than one column"))); + } + /* * Run through each primary element in the table creation clause. Separate - * column defs from constraints, and do preliminary analysis. We have to - * process column-defining clauses first because it can control the - * presence of columns which are referenced by columns referenced by - * constraints. + * column defs from constraints, and do preliminary analysis. */ foreach(elements, stmt->tableElts) { @@ -264,17 +289,13 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString) transformColumnDefinition(&cxt, (ColumnDef *) element); break; - case T_TableLikeClause: - if (!like_found) - { - cxt.hasoids = false; - like_found = true; - } - transformTableLikeClause(&cxt, (TableLikeClause *) element); + case T_Constraint: + transformTableConstraint(&cxt, (Constraint *) element); break; - case T_Constraint: - /* process later */ + case T_TableLikeClause: + like_found = true; + transformTableLikeClause(&cxt, (TableLikeClause *) element); break; default: @@ -284,26 +305,19 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString) } } - if (like_found) - { - /* - * To match INHERITS, the existence of any LIKE table with OIDs causes - * the new table to have oids. For the same reason, WITH/WITHOUT OIDs - * is also ignored with LIKE. We prepend because the first oid option - * list entry is honored. Our prepended WITHOUT OIDS clause will be - * overridden if an inherited table has oids. - */ + /* + * If we had any LIKE tables, they may require creation of an OID column + * even though the command's own WITH clause didn't ask for one (or, + * perhaps, even specifically rejected having one). Insert a WITH option + * to ensure that happens. We prepend to the list because the first oid + * option will be honored, and we want to override anything already there. + * (But note that DefineRelation will override this again to add an OID + * column if one appears in an inheritance parent table.) + */ + if (like_found && cxt.hasoids) stmt->options = lcons(makeDefElem("oids", - (Node *) makeInteger(cxt.hasoids)), stmt->options); - } - - foreach(elements, stmt->tableElts) - { - Node *element = lfirst(elements); - - if (nodeTag(element) == T_Constraint) - transformTableConstraint(&cxt, (Constraint *) element); - } + (Node *) makeInteger(true), -1), + stmt->options); /* * transformIndexConstraints wants cxt.alist to contain only index @@ -482,7 +496,7 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column) makeString(cxt->relation->relname), makeString(column->colname)); altseqstmt->options = list_make1(makeDefElem("owned_by", - (Node *) attnamelist)); + (Node *) attnamelist, -1)); cxt->alist = lappend(cxt->alist, altseqstmt); @@ -582,6 +596,12 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column) errmsg("primary key constraints are not supported on foreign tables"), parser_errposition(cxt->pstate, constraint->location))); + if (cxt->ispartitioned) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("primary key constraints are not supported on partitioned tables"), + parser_errposition(cxt->pstate, + constraint->location))); /* FALL THRU */ case CONSTR_UNIQUE: @@ -591,6 +611,12 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column) errmsg("unique constraints are not supported on foreign tables"), parser_errposition(cxt->pstate, constraint->location))); + if (cxt->ispartitioned) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("unique constraints are not supported on partitioned tables"), + parser_errposition(cxt->pstate, + constraint->location))); if (constraint->keys == NIL) constraint->keys = list_make1(makeString(column->colname)); cxt->ixconstraints = lappend(cxt->ixconstraints, constraint); @@ -608,6 +634,12 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column) errmsg("foreign key constraints are not supported on foreign tables"), parser_errposition(cxt->pstate, constraint->location))); + if (cxt->ispartitioned) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("foreign key constraints are not supported on partitioned tables"), + parser_errposition(cxt->pstate, + constraint->location))); /* * Fill in the current attribute's name and throw it into the @@ -673,6 +705,12 @@ transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint) errmsg("primary key constraints are not supported on foreign tables"), parser_errposition(cxt->pstate, constraint->location))); + if (cxt->ispartitioned) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("primary key constraints are not supported on partitioned tables"), + parser_errposition(cxt->pstate, + constraint->location))); cxt->ixconstraints = lappend(cxt->ixconstraints, constraint); break; @@ -683,6 +721,12 @@ transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint) errmsg("unique constraints are not supported on foreign tables"), parser_errposition(cxt->pstate, constraint->location))); + if (cxt->ispartitioned) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("unique constraints are not supported on partitioned tables"), + parser_errposition(cxt->pstate, + constraint->location))); cxt->ixconstraints = lappend(cxt->ixconstraints, constraint); break; @@ -693,6 +737,12 @@ transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint) errmsg("exclusion constraints are not supported on foreign tables"), parser_errposition(cxt->pstate, constraint->location))); + if (cxt->ispartitioned) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("exclusion constraints are not supported on partitioned tables"), + parser_errposition(cxt->pstate, + constraint->location))); cxt->ixconstraints = lappend(cxt->ixconstraints, constraint); break; @@ -707,6 +757,12 @@ transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint) errmsg("foreign key constraints are not supported on foreign tables"), parser_errposition(cxt->pstate, constraint->location))); + if (cxt->ispartitioned) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("foreign key constraints are not supported on partitioned tables"), + parser_errposition(cxt->pstate, + constraint->location))); cxt->fkconstraints = lappend(cxt->fkconstraints, constraint); break; @@ -762,7 +818,8 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla relation->rd_rel->relkind != RELKIND_VIEW && relation->rd_rel->relkind != RELKIND_MATVIEW && relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE && - relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE) + relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE && + relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table", @@ -902,7 +959,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla } /* We use oids if at least one LIKE'ed table has oids. */ - cxt->hasoids = cxt->hasoids || relation->rd_rel->relhasoids; + cxt->hasoids |= relation->rd_rel->relhasoids; /* * Copy CHECK constraints if requested, being careful to adjust attribute @@ -1853,7 +1910,8 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt) rel = heap_openrv(inh, AccessShareLock); /* check user requested inheritance from valid relkind */ if (rel->rd_rel->relkind != RELKIND_RELATION && - rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE) + rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE && + rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("inherited relation \"%s\" is not a table or foreign table", @@ -2105,17 +2163,11 @@ transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString) /* * transformExpr() should have already rejected subqueries, - * aggregates, and window functions, based on the EXPR_KIND_ for - * an index expression. + * aggregates, window functions, and SRFs, based on the EXPR_KIND_ + * for an index expression. * - * Also reject expressions returning sets; this is for consistency - * with what transformWhereClause() checks for the predicate. * DefineIndex() will make more checks. */ - if (expression_returns_set(ielem->expr)) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("index expression cannot return a set"))); } } @@ -2517,6 +2569,8 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt, cxt.blist = NIL; cxt.alist = NIL; cxt.pkey = NULL; + cxt.ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE); + cxt.partbound = NULL; /* * The only subtypes that currently require parse transformation handling @@ -2593,18 +2647,25 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt, def->cooked_default = transformExpr(pstate, def->raw_default, EXPR_KIND_ALTER_COL_TRANSFORM); - - /* it can't return a set */ - if (expression_returns_set(def->cooked_default)) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("transform expression must not return a set"))); } newcmds = lappend(newcmds, cmd); break; } + case AT_AttachPartition: + { + PartitionCmd *partcmd = (PartitionCmd *) cmd->def; + + transformAttachPartition(&cxt, partcmd); + + /* assign transformed values */ + partcmd->bound = cxt.partbound; + } + + newcmds = lappend(newcmds, cmd); + break; + default: newcmds = lappend(newcmds, cmd); break; @@ -2969,3 +3030,237 @@ setSchemaName(char *context_schema, char **stmt_schema_name) "different from the one being created (%s)", *stmt_schema_name, context_schema))); } + +/* + * transformAttachPartition + * Analyze ATTACH PARTITION ... FOR VALUES ... + */ +static void +transformAttachPartition(CreateStmtContext *cxt, PartitionCmd *cmd) +{ + Relation parentRel = cxt->rel; + + /* + * We are going to try to validate the partition bound specification + * against the partition key of rel, so it better have one. + */ + if (parentRel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("\"%s\" is not partitioned", + RelationGetRelationName(parentRel)))); + + /* tranform the values */ + Assert(RelationGetPartitionKey(parentRel) != NULL); + cxt->partbound = transformPartitionBound(cxt->pstate, parentRel, + cmd->bound); +} + +/* + * transformPartitionBound + * + * Transform partition bound specification + */ +Node * +transformPartitionBound(ParseState *pstate, Relation parent, Node *bound) +{ + PartitionBoundSpec *spec = (PartitionBoundSpec *) bound, + *result_spec; + PartitionKey key = RelationGetPartitionKey(parent); + char strategy = get_partition_strategy(key); + int partnatts = get_partition_natts(key); + List *partexprs = get_partition_exprs(key); + + result_spec = copyObject(spec); + + if (strategy == PARTITION_STRATEGY_LIST) + { + ListCell *cell; + char *colname; + + /* Get the only column's name in case we need to output an error */ + if (key->partattrs[0] != 0) + colname = get_relid_attribute_name(RelationGetRelid(parent), + key->partattrs[0]); + else + colname = deparse_expression((Node *) linitial(partexprs), + deparse_context_for(RelationGetRelationName(parent), + RelationGetRelid(parent)), + false, false); + + if (spec->strategy != PARTITION_STRATEGY_LIST) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("invalid bound specification for a list partition"), + parser_errposition(pstate, exprLocation(bound)))); + + result_spec->listdatums = NIL; + foreach(cell, spec->listdatums) + { + A_Const *con = (A_Const *) lfirst(cell); + Node *value; + ListCell *cell2; + bool duplicate; + + value = (Node *) make_const(pstate, &con->val, con->location); + value = coerce_to_target_type(pstate, + value, exprType(value), + get_partition_col_typid(key, 0), + get_partition_col_typmod(key, 0), + COERCION_ASSIGNMENT, + COERCE_IMPLICIT_CAST, + -1); + + if (value == NULL) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("specified value cannot be cast to type \"%s\" of column \"%s\"", + format_type_be(get_partition_col_typid(key, 0)), + colname), + parser_errposition(pstate, + exprLocation((Node *) con)))); + + /* Simplify the expression */ + value = (Node *) expression_planner((Expr *) value); + + /* Don't add to the result if the value is a duplicate */ + duplicate = false; + foreach(cell2, result_spec->listdatums) + { + Const *value2 = (Const *) lfirst(cell2); + + if (equal(value, value2)) + { + duplicate = true; + break; + } + } + if (duplicate) + continue; + + result_spec->listdatums = lappend(result_spec->listdatums, + value); + } + } + else if (strategy == PARTITION_STRATEGY_RANGE) + { + ListCell *cell1, + *cell2; + int i, + j; + char *colname; + + if (spec->strategy != PARTITION_STRATEGY_RANGE) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("invalid bound specification for a range partition"), + parser_errposition(pstate, exprLocation(bound)))); + + Assert(spec->lowerdatums != NIL && spec->upperdatums != NIL); + + if (list_length(spec->lowerdatums) != partnatts) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("FROM must specify exactly one value per partitioning column"))); + if (list_length(spec->upperdatums) != partnatts) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("TO must specify exactly one value per partitioning column"))); + + i = j = 0; + result_spec->lowerdatums = result_spec->upperdatums = NIL; + forboth(cell1, spec->lowerdatums, cell2, spec->upperdatums) + { + PartitionRangeDatum *ldatum, + *rdatum; + Node *value; + A_Const *lcon = NULL, + *rcon = NULL; + + ldatum = (PartitionRangeDatum *) lfirst(cell1); + rdatum = (PartitionRangeDatum *) lfirst(cell2); + /* Get the column's name in case we need to output an error */ + if (key->partattrs[i] != 0) + colname = get_relid_attribute_name(RelationGetRelid(parent), + key->partattrs[i]); + else + { + colname = deparse_expression((Node *) list_nth(partexprs, j), + deparse_context_for(RelationGetRelationName(parent), + RelationGetRelid(parent)), + false, false); + ++j; + } + + if (!ldatum->infinite) + lcon = (A_Const *) ldatum->value; + if (!rdatum->infinite) + rcon = (A_Const *) rdatum->value; + + if (lcon) + { + value = (Node *) make_const(pstate, &lcon->val, lcon->location); + if (((Const *) value)->constisnull) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("cannot specify NULL in range bound"))); + value = coerce_to_target_type(pstate, + value, exprType(value), + get_partition_col_typid(key, i), + get_partition_col_typmod(key, i), + COERCION_ASSIGNMENT, + COERCE_IMPLICIT_CAST, + -1); + if (value == NULL) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("specified value cannot be cast to type \"%s\" of column \"%s\"", + format_type_be(get_partition_col_typid(key, i)), + colname), + parser_errposition(pstate, exprLocation((Node *) ldatum)))); + + /* Simplify the expression */ + value = (Node *) expression_planner((Expr *) value); + ldatum->value = value; + } + + if (rcon) + { + value = (Node *) make_const(pstate, &rcon->val, rcon->location); + if (((Const *) value)->constisnull) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("cannot specify NULL in range bound"))); + value = coerce_to_target_type(pstate, + value, exprType(value), + get_partition_col_typid(key, i), + get_partition_col_typmod(key, i), + COERCION_ASSIGNMENT, + COERCE_IMPLICIT_CAST, + -1); + if (value == NULL) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("specified value cannot be cast to type \"%s\" of column \"%s\"", + format_type_be(get_partition_col_typid(key, i)), + colname), + parser_errposition(pstate, exprLocation((Node *) rdatum)))); + + /* Simplify the expression */ + value = (Node *) expression_planner((Expr *) value); + rdatum->value = value; + } + + result_spec->lowerdatums = lappend(result_spec->lowerdatums, + copyObject(ldatum)); + result_spec->upperdatums = lappend(result_spec->upperdatums, + copyObject(rdatum)); + + ++i; + } + } + else + elog(ERROR, "unexpected partition strategy: %d", (int) strategy); + + return (Node *) result_spec; +} diff --git a/src/backend/parser/parser.c b/src/backend/parser/parser.c index 61d24e11d3..245b4cda3b 100644 --- a/src/backend/parser/parser.c +++ b/src/backend/parser/parser.c @@ -10,7 +10,7 @@ * analyze.c and related files. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -29,7 +29,8 @@ * raw_parser * Given a query in string form, do lexical and grammatical analysis. * - * Returns a list of raw (un-analyzed) parse trees. + * Returns a list of raw (un-analyzed) parse trees. The immediate elements + * of the list are always RawStmt nodes. */ List * raw_parser(const char *str) diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l index 998349d742..634bfa512f 100644 --- a/src/backend/parser/scan.l +++ b/src/backend/parser/scan.l @@ -21,7 +21,7 @@ * Postgres 9.2, this check is made automatically by the Makefile.) * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -1435,6 +1435,13 @@ litbuf_udeescape(unsigned char escape, core_yyscan_t yyscanner) } } + /* unfinished surrogate pair? */ + if (pair_first) + { + ADVANCE_YYLLOC(in - litbuf + 3); /* 3 for U&" */ + yyerror("invalid Unicode surrogate pair"); + } + *out = '\0'; /* diff --git a/src/backend/parser/scansup.c b/src/backend/parser/scansup.c index 7aa5b76841..c3d2805803 100644 --- a/src/backend/parser/scansup.c +++ b/src/backend/parser/scansup.c @@ -4,7 +4,7 @@ * support routines for the lex/flex scanner, used by both the normal * backend as well as the bootstrap backend * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/port/Makefile b/src/backend/port/Makefile index 89549d0d2b..aba1e92fe1 100644 --- a/src/backend/port/Makefile +++ b/src/backend/port/Makefile @@ -23,9 +23,6 @@ include $(top_builddir)/src/Makefile.global OBJS = atomics.o dynloader.o pg_sema.o pg_shmem.o $(TAS) -ifeq ($(PORTNAME), darwin) -SUBDIRS += darwin -endif ifeq ($(PORTNAME), win32) SUBDIRS += win32 endif @@ -44,5 +41,4 @@ endif distclean clean: rm -f tas_cpp.s - $(MAKE) -C darwin clean $(MAKE) -C win32 clean diff --git a/src/backend/port/atomics.c b/src/backend/port/atomics.c index 42169a33cf..86b5308214 100644 --- a/src/backend/port/atomics.c +++ b/src/backend/port/atomics.c @@ -3,7 +3,7 @@ * atomics.c * Non-Inline parts of the atomics implementation * - * Portions Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2013-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -104,6 +104,19 @@ pg_atomic_init_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val_) ptr->value = val_; } +void +pg_atomic_write_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val) +{ + /* + * One might think that an unlocked write doesn't need to acquire the + * spinlock, but one would be wrong. Even an unlocked write has to cause a + * concurrent pg_atomic_compare_exchange_u32() (et al) to fail. + */ + SpinLockAcquire((slock_t *) &ptr->sema); + ptr->value = val; + SpinLockRelease((slock_t *) &ptr->sema); +} + bool pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 *expected, uint32 newval) diff --git a/src/backend/port/darwin/Makefile b/src/backend/port/darwin/Makefile deleted file mode 100644 index 9d463ffb87..0000000000 --- a/src/backend/port/darwin/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -#------------------------------------------------------------------------- -# -# Makefile-- -# Makefile for port/darwin -# -# IDENTIFICATION -# src/backend/port/darwin/Makefile -# -#------------------------------------------------------------------------- - -subdir = src/backend/port/darwin -top_builddir = ../../../.. -include $(top_builddir)/src/Makefile.global - -OBJS = system.o - -include $(top_srcdir)/src/backend/common.mk diff --git a/src/backend/port/darwin/README b/src/backend/port/darwin/README deleted file mode 100644 index 2d9df79683..0000000000 --- a/src/backend/port/darwin/README +++ /dev/null @@ -1,36 +0,0 @@ -src/backend/port/darwin/README - -Darwin -====== - -The file system.c included herein is taken directly from Apple's Darwin -open-source CVS archives, and is redistributed under the BSD copyright -notice it bears. (According to Apple's CVS logs, their version is -identical to the FreeBSD original.) It provides our own implementation of -the system(3) function, which ought by all rights to be identical to the -one provided in libc on Darwin machines. Nonetheless, this version works, -whereas the one that actually ships with Mac OS X 10.1 doesn't. The -shipped version appears to disconnect the calling process from any shared -memory segments it is attached to. (The symptom seen in PostgreSQL is -that a backend attempting to execute CREATE DATABASE core-dumps.) I would -love to know why there is a discrepancy between the published source and -the actual behavior --- tgl 7-Nov-2001. - -Appropriate bug reports have been filed with Apple --- see -Radar Bug#s 2767956, 2683531, 2805147. One hopes we can retire this -kluge in the not too distant future. - - -As of PostgreSQL 7.3 and Mac OS X 10.1, one should expect warnings -like these while linking the backend: - -/usr/bin/ld: warning unused multiple definitions of symbol _system -port/SUBSYS.o definition of _system in section (__TEXT,__text) -/usr/lib/libm.dylib(system.o) unused definition of _system - -These are due to overriding system() per the above-described hack. - - -The bug appears to be repaired in OS X 10.2.6 and later (possibly in -earlier 10.2.* as well, but no systems handy to check). We #ifdef out -the substitute system() definition on 10.3 and later. diff --git a/src/backend/port/darwin/system.c b/src/backend/port/darwin/system.c deleted file mode 100644 index 1cd5266929..0000000000 --- a/src/backend/port/darwin/system.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * src/backend/port/darwin/system.c - * - * only needed in OS X 10.1 and possibly early 10.2 releases */ -#include /* pgrminclude ignore */ -#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_2 || !defined(MAC_OS_X_VERSION_10_2) - -/* - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD: src/lib/libc/stdlib/system.c,v 1.6 2000/03/16 02:14:41 jasone Exp $ - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)system.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ - -#include -#include -#include -#include -#include - -int system(const char *command); - -int -system(const char *command) -{ - pid_t pid; - int pstat; - struct sigaction ign, - intact, - quitact; - sigset_t newsigblock, - oldsigblock; - - if (!command) /* just checking... */ - return (1); - - /* - * Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save existing - * signal dispositions. - */ - ign.sa_handler = SIG_IGN; - (void) sigemptyset(&ign.sa_mask); - ign.sa_flags = 0; - (void) sigaction(SIGINT, &ign, &intact); - (void) sigaction(SIGQUIT, &ign, &quitact); - (void) sigemptyset(&newsigblock); - (void) sigaddset(&newsigblock, SIGCHLD); - (void) sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock); - switch (pid = fork()) - { - case -1: /* error */ - break; - case 0: /* child */ - - /* - * Restore original signal dispositions and exec the command. - */ - (void) sigaction(SIGINT, &intact, NULL); - (void) sigaction(SIGQUIT, &quitact, NULL); - (void) sigprocmask(SIG_SETMASK, &oldsigblock, NULL); - execl(_PATH_BSHELL, "sh", "-c", command, (char *) NULL); - _exit(127); - default: /* parent */ - do - { - pid = wait4(pid, &pstat, 0, (struct rusage *) 0); - } while (pid == -1 && errno == EINTR); - break; - } - (void) sigaction(SIGINT, &intact, NULL); - (void) sigaction(SIGQUIT, &quitact, NULL); - (void) sigprocmask(SIG_SETMASK, &oldsigblock, NULL); - return (pid == -1 ? -1 : pstat); -} - -#endif /* OS X < 10.3 */ diff --git a/src/backend/port/dynloader/aix.h b/src/backend/port/dynloader/aix.h index 620fb92ac9..321597dae2 100644 --- a/src/backend/port/dynloader/aix.h +++ b/src/backend/port/dynloader/aix.h @@ -4,7 +4,7 @@ * prototypes for AIX-specific routines * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/port/dynloader/aix.h diff --git a/src/backend/port/dynloader/cygwin.h b/src/backend/port/dynloader/cygwin.h index cfa5f81070..bb3d7a322a 100644 --- a/src/backend/port/dynloader/cygwin.h +++ b/src/backend/port/dynloader/cygwin.h @@ -2,7 +2,7 @@ * * Dynamic loader declarations for Cygwin * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/port/dynloader/cygwin.h diff --git a/src/backend/port/dynloader/darwin.c b/src/backend/port/dynloader/darwin.c index ccd92c39d4..7b6b48d14a 100644 --- a/src/backend/port/dynloader/darwin.c +++ b/src/backend/port/dynloader/darwin.c @@ -1,5 +1,5 @@ /* - * Dynamic loading support for Darwin + * Dynamic loading support for macOS (Darwin) * * If dlopen() is available (Darwin 10.3 and later), we just use it. * Otherwise we emulate it with the older, now deprecated, NSLinkModule API. @@ -78,6 +78,9 @@ pg_dlsym(void *handle, char *funcname) NSSymbol symbol; char *symname = (char *) malloc(strlen(funcname) + 2); + if (!symname) + return NULL; + sprintf(symname, "_%s", funcname); if (NSIsSymbolNameDefined(symname)) { diff --git a/src/backend/port/dynloader/freebsd.c b/src/backend/port/dynloader/freebsd.c index 875a888251..e61b1c241a 100644 --- a/src/backend/port/dynloader/freebsd.c +++ b/src/backend/port/dynloader/freebsd.c @@ -1,5 +1,5 @@ /* - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * diff --git a/src/backend/port/dynloader/freebsd.h b/src/backend/port/dynloader/freebsd.h index b8963690aa..78dda69922 100644 --- a/src/backend/port/dynloader/freebsd.h +++ b/src/backend/port/dynloader/freebsd.h @@ -3,7 +3,7 @@ * freebsd.h * port-specific prototypes for FreeBSD * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/port/dynloader/freebsd.h diff --git a/src/backend/port/dynloader/hpux.c b/src/backend/port/dynloader/hpux.c index 60f05c39b1..c7f93d2d4a 100644 --- a/src/backend/port/dynloader/hpux.c +++ b/src/backend/port/dynloader/hpux.c @@ -3,7 +3,7 @@ * dynloader.c * dynamic loader for HP-UX using the shared library mechanism * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/port/dynloader/hpux.h b/src/backend/port/dynloader/hpux.h index d38a598523..0a17454f2b 100644 --- a/src/backend/port/dynloader/hpux.h +++ b/src/backend/port/dynloader/hpux.h @@ -3,7 +3,7 @@ * dynloader.h * dynamic loader for HP-UX using the shared library mechanism * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/port/dynloader/linux.c b/src/backend/port/dynloader/linux.c index 174b29ba1a..5d8a76af59 100644 --- a/src/backend/port/dynloader/linux.c +++ b/src/backend/port/dynloader/linux.c @@ -6,7 +6,7 @@ * * You need to install the dld library on your Linux system! * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/port/dynloader/linux.h b/src/backend/port/dynloader/linux.h index fac58d7e17..9d804ad955 100644 --- a/src/backend/port/dynloader/linux.h +++ b/src/backend/port/dynloader/linux.h @@ -4,7 +4,7 @@ * Port-specific prototypes for Linux * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/port/dynloader/linux.h diff --git a/src/backend/port/dynloader/netbsd.c b/src/backend/port/dynloader/netbsd.c index fcb228f58a..01a96013cb 100644 --- a/src/backend/port/dynloader/netbsd.c +++ b/src/backend/port/dynloader/netbsd.c @@ -1,5 +1,5 @@ /* - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * diff --git a/src/backend/port/dynloader/netbsd.h b/src/backend/port/dynloader/netbsd.h index 61df076edb..688b7fb793 100644 --- a/src/backend/port/dynloader/netbsd.h +++ b/src/backend/port/dynloader/netbsd.h @@ -4,7 +4,7 @@ * port-specific prototypes for NetBSD * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/port/dynloader/netbsd.h diff --git a/src/backend/port/dynloader/openbsd.c b/src/backend/port/dynloader/openbsd.c index 452be3a658..fcd336acbe 100644 --- a/src/backend/port/dynloader/openbsd.c +++ b/src/backend/port/dynloader/openbsd.c @@ -1,5 +1,5 @@ /* - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * diff --git a/src/backend/port/dynloader/openbsd.h b/src/backend/port/dynloader/openbsd.h index 7fce21b014..34d2724615 100644 --- a/src/backend/port/dynloader/openbsd.h +++ b/src/backend/port/dynloader/openbsd.h @@ -3,7 +3,7 @@ * openbsd.h * port-specific prototypes for OpenBSD * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/port/dynloader/openbsd.h diff --git a/src/backend/port/dynloader/sco.c b/src/backend/port/dynloader/sco.c deleted file mode 100644 index 1e24f494ac..0000000000 --- a/src/backend/port/dynloader/sco.c +++ /dev/null @@ -1,7 +0,0 @@ -/* - * src/backend/port/dynloader/sco.c - * - * Dummy file used for nothing at this point - * - * see sco.h - */ diff --git a/src/backend/port/dynloader/sco.h b/src/backend/port/dynloader/sco.h deleted file mode 100644 index 86f2383729..0000000000 --- a/src/backend/port/dynloader/sco.h +++ /dev/null @@ -1,46 +0,0 @@ -/*------------------------------------------------------------------------- - * - * sco.h - * port-specific prototypes for SCO 3.2v5.2 - * - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * src/backend/port/dynloader/sco.h - * - *------------------------------------------------------------------------- - */ -#ifndef PORT_PROTOS_H -#define PORT_PROTOS_H - -#include -#include "utils/dynamic_loader.h" /* pgrminclude ignore */ - -/* - * Dynamic Loader on SCO 3.2v5.0.2 - * - * this dynamic loader uses the system dynamic loading interface for shared - * libraries (ie. dlopen/dlsym/dlclose). The user must specify a shared - * library as the file to be dynamically loaded. - */ - -/* - * In some older systems, the RTLD_NOW flag isn't defined and the mode - * argument to dlopen must always be 1. The RTLD_GLOBAL flag is wanted - * if available, but it doesn't exist everywhere. - * If it doesn't exist, set it to 0 so it has no effect. - */ -#ifndef RTLD_NOW -#define RTLD_NOW 1 -#endif -#ifndef RTLD_GLOBAL -#define RTLD_GLOBAL 0 -#endif - -#define pg_dlopen(f) dlopen((f), RTLD_NOW | RTLD_GLOBAL) -#define pg_dlsym dlsym -#define pg_dlclose dlclose -#define pg_dlerror dlerror - -#endif /* PORT_PROTOS_H */ diff --git a/src/backend/port/dynloader/solaris.h b/src/backend/port/dynloader/solaris.h index 49fb87d683..f50ba524dc 100644 --- a/src/backend/port/dynloader/solaris.h +++ b/src/backend/port/dynloader/solaris.h @@ -4,7 +4,7 @@ * port-specific prototypes for Solaris * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/port/dynloader/solaris.h diff --git a/src/backend/port/dynloader/unixware.c b/src/backend/port/dynloader/unixware.c deleted file mode 100644 index afb36dfe99..0000000000 --- a/src/backend/port/dynloader/unixware.c +++ /dev/null @@ -1,7 +0,0 @@ -/* - * src/backend/port/dynloader/unixware.c - * - * Dummy file used for nothing at this point - * - * see unixware.h - */ diff --git a/src/backend/port/dynloader/unixware.h b/src/backend/port/dynloader/unixware.h deleted file mode 100644 index 130a9a25d5..0000000000 --- a/src/backend/port/dynloader/unixware.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * src/backend/port/dynloader/unixware.h - * - *------------------------------------------------------------------------- - * - * unixware.h - * port-specific prototypes for Intel x86/UNIXWARE 7 - * - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * unixware.h,v 1.2 1995/03/17 06:40:18 andrew Exp - * - *------------------------------------------------------------------------- - */ -#ifndef PORT_PROTOS_H -#define PORT_PROTOS_H - -#include -#include "utils/dynamic_loader.h" /* pgrminclude ignore */ - -/* - * Dynamic Loader on UnixWare. - * - * this dynamic loader uses the system dynamic loading interface for shared - * libraries (ie. dlopen/dlsym/dlclose). The user must specify a shared - * library as the file to be dynamically loaded. - */ - -/* - * In some older systems, the RTLD_NOW flag isn't defined and the mode - * argument to dlopen must always be 1. The RTLD_GLOBAL flag is wanted - * if available, but it doesn't exist everywhere. - * If it doesn't exist, set it to 0 so it has no effect. - */ -#ifndef RTLD_NOW -#define RTLD_NOW 1 -#endif -#ifndef RTLD_GLOBAL -#define RTLD_GLOBAL 0 -#endif - -#define pg_dlopen(f) dlopen((f), RTLD_NOW | RTLD_GLOBAL) -#define pg_dlsym dlsym -#define pg_dlclose dlclose -#define pg_dlerror dlerror - -#endif /* PORT_PROTOS_H */ diff --git a/src/backend/port/posix_sema.c b/src/backend/port/posix_sema.c index 2b4b11ce4e..6e9e03a571 100644 --- a/src/backend/port/posix_sema.c +++ b/src/backend/port/posix_sema.c @@ -6,8 +6,16 @@ * We prefer the unnamed style of POSIX semaphore (the kind made with * sem_init). We can cope with the kind made with sem_open, however. * + * In either implementation, typedef PGSemaphore is equivalent to "sem_t *". + * With unnamed semaphores, the sem_t structs live in an array in shared + * memory. With named semaphores, that's not true because we cannot persuade + * sem_open to do its allocation there. Therefore, the named-semaphore code + * *does not cope with EXEC_BACKEND*. The sem_t structs will just be in the + * postmaster's private memory, where they are successfully inherited by + * forked backends, but they could not be accessed by exec'd backends. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -18,28 +26,38 @@ #include "postgres.h" #include +#include #include #include #include "miscadmin.h" #include "storage/ipc.h" #include "storage/pg_sema.h" +#include "storage/shmem.h" -#ifdef USE_NAMED_POSIX_SEMAPHORES -/* PGSemaphore is pointer to pointer to sem_t */ -#define PG_SEM_REF(x) (*(x)) -#else -/* PGSemaphore is pointer to sem_t */ -#define PG_SEM_REF(x) (x) +/* see file header comment */ +#if defined(USE_NAMED_POSIX_SEMAPHORES) && defined(EXEC_BACKEND) +#error cannot use named POSIX semaphores with EXEC_BACKEND #endif +/* typedef PGSemaphore is equivalent to pointer to sem_t */ +typedef struct PGSemaphoreData +{ + sem_t pgsem; +} PGSemaphoreData; + +#define PG_SEM_REF(x) (&(x)->pgsem) #define IPCProtection (0600) /* access/modify by user only */ +#ifdef USE_NAMED_POSIX_SEMAPHORES static sem_t **mySemPointers; /* keep track of created semaphores */ +#else +static PGSemaphore sharedSemas; /* array of PGSemaphoreData in shared memory */ +#endif static int numSems; /* number of semas acquired so far */ -static int maxSems; /* allocated size of mySemaPointers array */ +static int maxSems; /* allocated size of above arrays */ static int nextSemKey; /* next name to try */ @@ -133,6 +151,21 @@ PosixSemaphoreKill(sem_t * sem) } +/* + * Report amount of shared memory needed for semaphores + */ +Size +PGSemaphoreShmemSize(int maxSemas) +{ +#ifdef USE_NAMED_POSIX_SEMAPHORES + /* No shared memory needed in this case */ + return 0; +#else + /* Need a PGSemaphoreData per semaphore */ + return mul_size(maxSemas, sizeof(PGSemaphoreData)); +#endif +} + /* * PGReserveSemaphores --- initialize semaphore support * @@ -147,15 +180,33 @@ PosixSemaphoreKill(sem_t * sem) * zero will be passed. * * In the Posix implementation, we acquire semaphores on-demand; the - * maxSemas parameter is just used to size the array that keeps track of - * acquired semas for subsequent releasing. + * maxSemas parameter is just used to size the arrays. For unnamed + * semaphores, there is an array of PGSemaphoreData structs in shared memory. + * For named semaphores, we keep a postmaster-local array of sem_t pointers, + * which we use for releasing the semphores when done. + * (This design minimizes the dependency of postmaster shutdown on the + * contents of shared memory, which a failed backend might have clobbered. + * We can't do much about the possibility of sem_destroy() crashing, but + * we don't have to expose the counters to other processes.) */ void PGReserveSemaphores(int maxSemas, int port) { +#ifdef USE_NAMED_POSIX_SEMAPHORES mySemPointers = (sem_t **) malloc(maxSemas * sizeof(sem_t *)); if (mySemPointers == NULL) elog(PANIC, "out of memory"); +#else + + /* + * We must use ShmemAllocUnlocked(), since the spinlock protecting + * ShmemAlloc() won't be ready yet. (This ordering is necessary when we + * are emulating spinlocks with semaphores.) + */ + sharedSemas = (PGSemaphore) + ShmemAllocUnlocked(PGSemaphoreShmemSize(maxSemas)); +#endif + numSems = 0; maxSems = maxSemas; nextSemKey = port * 1000; @@ -173,19 +224,27 @@ ReleaseSemaphores(int status, Datum arg) { int i; +#ifdef USE_NAMED_POSIX_SEMAPHORES for (i = 0; i < numSems; i++) PosixSemaphoreKill(mySemPointers[i]); free(mySemPointers); +#endif + +#ifdef USE_UNNAMED_POSIX_SEMAPHORES + for (i = 0; i < numSems; i++) + PosixSemaphoreKill(PG_SEM_REF(sharedSemas + i)); +#endif } /* * PGSemaphoreCreate * - * Initialize a PGSemaphore structure to represent a sema with count 1 + * Allocate a PGSemaphore structure with initial count 1 */ -void -PGSemaphoreCreate(PGSemaphore sema) +PGSemaphore +PGSemaphoreCreate(void) { + PGSemaphore sema; sem_t *newsem; /* Can't do this in a backend, because static state is postmaster's */ @@ -195,14 +254,19 @@ PGSemaphoreCreate(PGSemaphore sema) elog(PANIC, "too many semaphores created"); #ifdef USE_NAMED_POSIX_SEMAPHORES - *sema = newsem = PosixSemaphoreCreate(); + newsem = PosixSemaphoreCreate(); + /* Remember new sema for ReleaseSemaphores */ + mySemPointers[numSems] = newsem; + sema = (PGSemaphore) newsem; #else - PosixSemaphoreCreate(sema); - newsem = sema; + sema = &sharedSemas[numSems]; + newsem = PG_SEM_REF(sema); + PosixSemaphoreCreate(newsem); #endif - /* Remember new sema for ReleaseSemaphores */ - mySemPointers[numSems++] = newsem; + numSems++; + + return sema; } /* diff --git a/src/backend/port/sysv_sema.c b/src/backend/port/sysv_sema.c index f6f1516920..4fbcc5e2b4 100644 --- a/src/backend/port/sysv_sema.c +++ b/src/backend/port/sysv_sema.c @@ -4,7 +4,7 @@ * Implement PGSemaphores using SysV semaphore facilities * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -27,8 +27,15 @@ #include "miscadmin.h" #include "storage/ipc.h" #include "storage/pg_sema.h" +#include "storage/shmem.h" +typedef struct PGSemaphoreData +{ + int semId; /* semaphore set identifier */ + int semNum; /* semaphore number within set */ +} PGSemaphoreData; + #ifndef HAVE_UNION_SEMUN union semun { @@ -54,6 +61,9 @@ typedef int IpcSemaphoreId; /* semaphore ID returned by semget(2) */ #define PGSemaMagic 537 /* must be less than SEMVMX */ +static PGSemaphore sharedSemas; /* array of PGSemaphoreData in shared memory */ +static int numSharedSemas; /* number of PGSemaphoreDatas used so far */ +static int maxSharedSemas; /* allocated size of PGSemaphoreData array */ static IpcSemaphoreId *mySemaSets; /* IDs of sema sets acquired so far */ static int numSemaSets; /* number of sema sets acquired so far */ static int maxSemaSets; /* allocated size of mySemaSets array */ @@ -273,6 +283,15 @@ IpcSemaphoreCreate(int numSems) } +/* + * Report amount of shared memory needed for semaphores + */ +Size +PGSemaphoreShmemSize(int maxSemas) +{ + return mul_size(maxSemas, sizeof(PGSemaphoreData)); +} + /* * PGReserveSemaphores --- initialize semaphore support * @@ -287,12 +306,26 @@ IpcSemaphoreCreate(int numSems) * zero will be passed. * * In the SysV implementation, we acquire semaphore sets on-demand; the - * maxSemas parameter is just used to size the array that keeps track of - * acquired sets for subsequent releasing. + * maxSemas parameter is just used to size the arrays. There is an array + * of PGSemaphoreData structs in shared memory, and a postmaster-local array + * with one entry per SysV semaphore set, which we use for releasing the + * semaphore sets when done. (This design ensures that postmaster shutdown + * doesn't rely on the contents of shared memory, which a failed backend might + * have clobbered.) */ void PGReserveSemaphores(int maxSemas, int port) { + /* + * We must use ShmemAllocUnlocked(), since the spinlock protecting + * ShmemAlloc() won't be ready yet. (This ordering is necessary when we + * are emulating spinlocks with semaphores.) + */ + sharedSemas = (PGSemaphore) + ShmemAllocUnlocked(PGSemaphoreShmemSize(maxSemas)); + numSharedSemas = 0; + maxSharedSemas = maxSemas; + maxSemaSets = (maxSemas + SEMAS_PER_SET - 1) / SEMAS_PER_SET; mySemaSets = (IpcSemaphoreId *) malloc(maxSemaSets * sizeof(IpcSemaphoreId)); @@ -323,11 +356,13 @@ ReleaseSemaphores(int status, Datum arg) /* * PGSemaphoreCreate * - * Initialize a PGSemaphore structure to represent a sema with count 1 + * Allocate a PGSemaphore structure with initial count 1 */ -void -PGSemaphoreCreate(PGSemaphore sema) +PGSemaphore +PGSemaphoreCreate(void) { + PGSemaphore sema; + /* Can't do this in a backend, because static state is postmaster's */ Assert(!IsUnderPostmaster); @@ -340,11 +375,17 @@ PGSemaphoreCreate(PGSemaphore sema) numSemaSets++; nextSemaNumber = 0; } + /* Use the next shared PGSemaphoreData */ + if (numSharedSemas >= maxSharedSemas) + elog(PANIC, "too many semaphores created"); + sema = &sharedSemas[numSharedSemas++]; /* Assign the next free semaphore in the current set */ sema->semId = mySemaSets[numSemaSets - 1]; sema->semNum = nextSemaNumber++; /* Initialize it to count 1 */ IpcSemaphoreInitialize(sema->semId, sema->semNum, 1); + + return sema; } /* diff --git a/src/backend/port/sysv_shmem.c b/src/backend/port/sysv_shmem.c index 6c442b927a..77cd8f3cca 100644 --- a/src/backend/port/sysv_shmem.c +++ b/src/backend/port/sysv_shmem.c @@ -3,10 +3,13 @@ * sysv_shmem.c * Implement shared memory using SysV facilities * - * These routines represent a fairly thin layer on top of SysV shared - * memory functionality. + * These routines used to be a fairly thin layer on top of SysV shared + * memory functionality. With the addition of anonymous-shmem logic, + * they're a bit fatter now. We still require a SysV shmem block to + * exist, though, because mmap'd shmem provides no way to find out how + * many processes are attached, which we need for interlocking purposes. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -31,19 +34,50 @@ #include "miscadmin.h" #include "portability/mem.h" #include "storage/dsm.h" +#include "storage/fd.h" #include "storage/ipc.h" #include "storage/pg_shmem.h" #include "utils/guc.h" +/* + * As of PostgreSQL 9.3, we normally allocate only a very small amount of + * System V shared memory, and only for the purposes of providing an + * interlock to protect the data directory. The real shared memory block + * is allocated using mmap(). This works around the problem that many + * systems have very low limits on the amount of System V shared memory + * that can be allocated. Even a limit of a few megabytes will be enough + * to run many copies of PostgreSQL without needing to adjust system settings. + * + * We assume that no one will attempt to run PostgreSQL 9.3 or later on + * systems that are ancient enough that anonymous shared memory is not + * supported, such as pre-2.4 versions of Linux. If that turns out to be + * false, we might need to add compile and/or run-time tests here and do this + * only if the running kernel supports it. + * + * However, we must always disable this logic in the EXEC_BACKEND case, and + * fall back to the old method of allocating the entire segment using System V + * shared memory, because there's no way to attach an anonymous mmap'd segment + * to a process after exec(). Since EXEC_BACKEND is intended only for + * developer use, this shouldn't be a big problem. Because of this, we do + * not worry about supporting anonymous shmem in the EXEC_BACKEND cases below. + */ +#ifndef EXEC_BACKEND +#define USE_ANONYMOUS_SHMEM +#endif + + typedef key_t IpcMemoryKey; /* shared memory key passed to shmget(2) */ typedef int IpcMemoryId; /* shared memory ID returned by shmget(2) */ unsigned long UsedShmemSegID = 0; void *UsedShmemSegAddr = NULL; + +#ifdef USE_ANONYMOUS_SHMEM static Size AnonymousShmemSize; static void *AnonymousShmem = NULL; +#endif static void *InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size); static void IpcMemoryDetach(int status, Datum shmaddr); @@ -204,10 +238,6 @@ IpcMemoryDetach(int status, Datum shmaddr) /* Detach System V shared memory block. */ if (shmdt(DatumGetPointer(shmaddr)) < 0) elog(LOG, "shmdt(%p) failed: %m", DatumGetPointer(shmaddr)); - /* Release anonymous shared memory block, if any. */ - if (AnonymousShmem != NULL - && munmap(AnonymousShmem, AnonymousShmemSize) < 0) - elog(LOG, "munmap(%p) failed: %m", AnonymousShmem); } /****************************************************************************/ @@ -318,6 +348,82 @@ PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2) return true; } +#ifdef USE_ANONYMOUS_SHMEM + +#ifdef MAP_HUGETLB + +/* + * Identify the huge page size to use. + * + * Some Linux kernel versions have a bug causing mmap() to fail on requests + * that are not a multiple of the hugepage size. Versions without that bug + * instead silently round the request up to the next hugepage multiple --- + * and then munmap() fails when we give it a size different from that. + * So we have to round our request up to a multiple of the actual hugepage + * size to avoid trouble. + * + * Doing the round-up ourselves also lets us make use of the extra memory, + * rather than just wasting it. Currently, we just increase the available + * space recorded in the shmem header, which will make the extra usable for + * purposes such as additional locktable entries. Someday, for very large + * hugepage sizes, we might want to think about more invasive strategies, + * such as increasing shared_buffers to absorb the extra space. + * + * Returns the (real or assumed) page size into *hugepagesize, + * and the hugepage-related mmap flags to use into *mmap_flags. + * + * Currently *mmap_flags is always just MAP_HUGETLB. Someday, on systems + * that support it, we might OR in additional bits to specify a particular + * non-default huge page size. + */ +static void +GetHugePageSize(Size *hugepagesize, int *mmap_flags) +{ + /* + * If we fail to find out the system's default huge page size, assume it + * is 2MB. This will work fine when the actual size is less. If it's + * more, we might get mmap() or munmap() failures due to unaligned + * requests; but at this writing, there are no reports of any non-Linux + * systems being picky about that. + */ + *hugepagesize = 2 * 1024 * 1024; + *mmap_flags = MAP_HUGETLB; + + /* + * System-dependent code to find out the default huge page size. + * + * On Linux, read /proc/meminfo looking for a line like "Hugepagesize: + * nnnn kB". Ignore any failures, falling back to the preset default. + */ +#ifdef __linux__ + { + FILE *fp = AllocateFile("/proc/meminfo", "r"); + char buf[128]; + unsigned int sz; + char ch; + + if (fp) + { + while (fgets(buf, sizeof(buf), fp)) + { + if (sscanf(buf, "Hugepagesize: %u %c", &sz, &ch) == 2) + { + if (ch == 'k') + { + *hugepagesize = sz * (Size) 1024; + break; + } + /* We could accept other units besides kB, if needed */ + } + } + FreeFile(fp); + } + } +#endif /* __linux__ */ +} + +#endif /* MAP_HUGETLB */ + /* * Creates an anonymous mmap()ed shared memory segment. * @@ -325,7 +431,6 @@ PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2) * actual size of the allocation, if it ends up allocating a segment that is * larger than requested. */ -#ifndef EXEC_BACKEND static void * CreateAnonymousSegment(Size *size) { @@ -334,47 +439,35 @@ CreateAnonymousSegment(Size *size) int mmap_errno = 0; #ifndef MAP_HUGETLB - if (huge_pages == HUGE_PAGES_ON) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("huge TLB pages not supported on this platform"))); + /* PGSharedMemoryCreate should have dealt with this case */ + Assert(huge_pages != HUGE_PAGES_ON); #else if (huge_pages == HUGE_PAGES_ON || huge_pages == HUGE_PAGES_TRY) { /* * Round up the request size to a suitable large value. - * - * Some Linux kernel versions are known to have a bug, which causes - * mmap() with MAP_HUGETLB to fail if the request size is not a - * multiple of any supported huge page size. To work around that, we - * round up the request size to nearest 2MB. 2MB is the most common - * huge page page size on affected systems. - * - * Aside from that bug, even with a kernel that does the allocation - * correctly, rounding it up ourselves avoids wasting memory. Without - * it, if we for example make an allocation of 2MB + 1 bytes, the - * kernel might decide to use two 2MB huge pages for that, and waste 2 - * MB - 1 of memory. When we do the rounding ourselves, we can use - * that space for allocations. */ - int hugepagesize = 2 * 1024 * 1024; + Size hugepagesize; + int mmap_flags; + + GetHugePageSize(&hugepagesize, &mmap_flags); if (allocsize % hugepagesize != 0) allocsize += hugepagesize - (allocsize % hugepagesize); ptr = mmap(NULL, allocsize, PROT_READ | PROT_WRITE, - PG_MMAP_FLAGS | MAP_HUGETLB, -1, 0); + PG_MMAP_FLAGS | mmap_flags, -1, 0); mmap_errno = errno; if (huge_pages == HUGE_PAGES_TRY && ptr == MAP_FAILED) - elog(DEBUG1, "mmap with MAP_HUGETLB failed, huge pages disabled: %m"); + elog(DEBUG1, "mmap(%zu) with MAP_HUGETLB failed, huge pages disabled: %m", + allocsize); } #endif - if (huge_pages == HUGE_PAGES_OFF || - (huge_pages == HUGE_PAGES_TRY && ptr == MAP_FAILED)) + if (ptr == MAP_FAILED && huge_pages != HUGE_PAGES_ON) { /* - * use the original size, not the rounded up value, when falling back + * Use the original size, not the rounded-up value, when falling back * to non-huge pages. */ allocsize = *size; @@ -401,7 +494,25 @@ CreateAnonymousSegment(Size *size) *size = allocsize; return ptr; } -#endif + +/* + * AnonymousShmemDetach --- detach from an anonymous mmap'd block + * (called as an on_shmem_exit callback, hence funny argument list) + */ +static void +AnonymousShmemDetach(int status, Datum arg) +{ + /* Release anonymous shared memory block, if any. */ + if (AnonymousShmem != NULL) + { + if (munmap(AnonymousShmem, AnonymousShmemSize) < 0) + elog(LOG, "munmap(%p, %zu) failed: %m", + AnonymousShmem, AnonymousShmemSize); + AnonymousShmem = NULL; + } +} + +#endif /* USE_ANONYMOUS_SHMEM */ /* * PGSharedMemoryCreate @@ -432,7 +543,8 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port, struct stat statbuf; Size sysvsize; -#if defined(EXEC_BACKEND) || !defined(MAP_HUGETLB) + /* Complain if hugepages demanded but we can't possibly support them */ +#if !defined(USE_ANONYMOUS_SHMEM) || !defined(MAP_HUGETLB) if (huge_pages == HUGE_PAGES_ON) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -442,32 +554,13 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port, /* Room for a header? */ Assert(size > MAXALIGN(sizeof(PGShmemHeader))); - /* - * As of PostgreSQL 9.3, we normally allocate only a very small amount of - * System V shared memory, and only for the purposes of providing an - * interlock to protect the data directory. The real shared memory block - * is allocated using mmap(). This works around the problem that many - * systems have very low limits on the amount of System V shared memory - * that can be allocated. Even a limit of a few megabytes will be enough - * to run many copies of PostgreSQL without needing to adjust system - * settings. - * - * We assume that no one will attempt to run PostgreSQL 9.3 or later on - * systems that are ancient enough that anonymous shared memory is not - * supported, such as pre-2.4 versions of Linux. If that turns out to be - * false, we might need to add a run-time test here and do this only if - * the running kernel supports it. - * - * However, we disable this logic in the EXEC_BACKEND case, and fall back - * to the old method of allocating the entire segment using System V - * shared memory, because there's no way to attach an mmap'd segment to a - * process after exec(). Since EXEC_BACKEND is intended only for - * developer use, this shouldn't be a big problem. - */ -#ifndef EXEC_BACKEND +#ifdef USE_ANONYMOUS_SHMEM AnonymousShmem = CreateAnonymousSegment(&size); AnonymousShmemSize = size; + /* Register on-exit routine to unmap the anonymous segment */ + on_shmem_exit(AnonymousShmemDetach, (Datum) 0); + /* Now we need only allocate a minimal-sized SysV shmem block. */ sysvsize = sizeof(PGShmemHeader); #else @@ -572,10 +665,14 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port, * block. Otherwise, the System V shared memory block is only a shim, and * we must return a pointer to the real block. */ +#ifdef USE_ANONYMOUS_SHMEM if (AnonymousShmem == NULL) return hdr; memcpy(AnonymousShmem, hdr, sizeof(PGShmemHeader)); return (PGShmemHeader *) AnonymousShmem; +#else + return hdr; +#endif } #ifdef EXEC_BACKEND @@ -660,12 +757,12 @@ PGSharedMemoryNoReAttach(void) * * Detach from the shared memory segment, if still attached. This is not * intended to be called explicitly by the process that originally created the - * segment (it will have an on_shmem_exit callback registered to do that). + * segment (it will have on_shmem_exit callback(s) registered to do that). * Rather, this is for subprocesses that have inherited an attachment and want * to get rid of it. * * UsedShmemSegID and UsedShmemSegAddr are implicit parameters to this - * routine. + * routine, also AnonymousShmem and AnonymousShmemSize. */ void PGSharedMemoryDetach(void) @@ -682,10 +779,15 @@ PGSharedMemoryDetach(void) UsedShmemSegAddr = NULL; } - /* Release anonymous shared memory block, if any. */ - if (AnonymousShmem != NULL - && munmap(AnonymousShmem, AnonymousShmemSize) < 0) - elog(LOG, "munmap(%p) failed: %m", AnonymousShmem); +#ifdef USE_ANONYMOUS_SHMEM + if (AnonymousShmem != NULL) + { + if (munmap(AnonymousShmem, AnonymousShmemSize) < 0) + elog(LOG, "munmap(%p, %zu) failed: %m", + AnonymousShmem, AnonymousShmemSize); + AnonymousShmem = NULL; + } +#endif } diff --git a/src/backend/port/tas/sunstudio_sparc.s b/src/backend/port/tas/sunstudio_sparc.s index c3b91d1d6f..73ff315d1a 100644 --- a/src/backend/port/tas/sunstudio_sparc.s +++ b/src/backend/port/tas/sunstudio_sparc.s @@ -3,7 +3,7 @@ ! sunstudio_sparc.s ! compare and swap for Sun Studio on Sparc ! -! Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +! Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group ! Portions Copyright (c) 1994, Regents of the University of California ! ! IDENTIFICATION diff --git a/src/backend/port/tas/sunstudio_x86.s b/src/backend/port/tas/sunstudio_x86.s index 0d7ecc2f61..31934b01d4 100644 --- a/src/backend/port/tas/sunstudio_x86.s +++ b/src/backend/port/tas/sunstudio_x86.s @@ -3,7 +3,7 @@ / sunstudio_x86.s / compare and swap for Sun Studio on x86 / -/ Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +/ Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group / Portions Copyright (c) 1994, Regents of the University of California / / IDENTIFICATION diff --git a/src/backend/port/win32/crashdump.c b/src/backend/port/win32/crashdump.c index 92e23cbf4b..64969df73d 100644 --- a/src/backend/port/win32/crashdump.c +++ b/src/backend/port/win32/crashdump.c @@ -28,7 +28,7 @@ * be added, though at the cost of a greater chance of the crash dump failing. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/port/win32/crashdump.c diff --git a/src/backend/port/win32/mingwcompat.c b/src/backend/port/win32/mingwcompat.c index a18bd21815..7b525eab81 100644 --- a/src/backend/port/win32/mingwcompat.c +++ b/src/backend/port/win32/mingwcompat.c @@ -3,7 +3,7 @@ * mingwcompat.c * MinGW compatibility functions * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/port/win32/mingwcompat.c diff --git a/src/backend/port/win32/signal.c b/src/backend/port/win32/signal.c index 640ee9ec64..ebbd434b9a 100644 --- a/src/backend/port/win32/signal.c +++ b/src/backend/port/win32/signal.c @@ -3,7 +3,7 @@ * signal.c * Microsoft Windows Win32 Signal Emulation Functions * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/port/win32/signal.c diff --git a/src/backend/port/win32/socket.c b/src/backend/port/win32/socket.c index 5d8fb7fc91..a6f9070761 100644 --- a/src/backend/port/win32/socket.c +++ b/src/backend/port/win32/socket.c @@ -3,7 +3,7 @@ * socket.c * Microsoft Windows Win32 Socket Functions * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/port/win32/socket.c diff --git a/src/backend/port/win32/timer.c b/src/backend/port/win32/timer.c index a9a2d961b1..43097794f7 100644 --- a/src/backend/port/win32/timer.c +++ b/src/backend/port/win32/timer.c @@ -8,7 +8,7 @@ * - Does not support interval timer (value->it_interval) * - Only supports ITIMER_REAL * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/port/win32/timer.c diff --git a/src/backend/port/win32_sema.c b/src/backend/port/win32_sema.c index c688210e24..a798510bbc 100644 --- a/src/backend/port/win32_sema.c +++ b/src/backend/port/win32_sema.c @@ -3,7 +3,7 @@ * win32_sema.c * Microsoft Windows Win32 Semaphores Emulation * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/port/win32_sema.c @@ -23,6 +23,17 @@ static int maxSems; /* allocated size of mySemaSet array */ static void ReleaseSemaphores(int code, Datum arg); + +/* + * Report amount of shared memory needed for semaphores + */ +Size +PGSemaphoreShmemSize(int maxSemas) +{ + /* No shared memory needed on Windows */ + return 0; +} + /* * PGReserveSemaphores --- initialize semaphore support * @@ -62,10 +73,10 @@ ReleaseSemaphores(int code, Datum arg) /* * PGSemaphoreCreate * - * Initialize a PGSemaphore structure to represent a sema with count 1 + * Allocate a PGSemaphore structure with initial count 1 */ -void -PGSemaphoreCreate(PGSemaphore sema) +PGSemaphore +PGSemaphoreCreate(void) { HANDLE cur_handle; SECURITY_ATTRIBUTES sec_attrs; @@ -86,12 +97,14 @@ PGSemaphoreCreate(PGSemaphore sema) if (cur_handle) { /* Successfully done */ - *sema = cur_handle; mySemSet[numSems++] = cur_handle; } else ereport(PANIC, - (errmsg("could not create semaphore: error code %lu", GetLastError()))); + (errmsg("could not create semaphore: error code %lu", + GetLastError()))); + + return (PGSemaphore) cur_handle; } /* @@ -106,7 +119,8 @@ PGSemaphoreReset(PGSemaphore sema) * There's no direct API for this in Win32, so we have to ratchet the * semaphore down to 0 with repeated trylock's. */ - while (PGSemaphoreTryLock(sema)); + while (PGSemaphoreTryLock(sema)) + /* loop */ ; } /* @@ -127,7 +141,7 @@ PGSemaphoreLock(PGSemaphore sema) * pending signals are serviced. */ wh[0] = pgwin32_signal_event; - wh[1] = *sema; + wh[1] = sema; /* * As in other implementations of PGSemaphoreLock, we need to check for @@ -182,9 +196,10 @@ PGSemaphoreLock(PGSemaphore sema) void PGSemaphoreUnlock(PGSemaphore sema) { - if (!ReleaseSemaphore(*sema, 1, NULL)) + if (!ReleaseSemaphore(sema, 1, NULL)) ereport(FATAL, - (errmsg("could not unlock semaphore: error code %lu", GetLastError()))); + (errmsg("could not unlock semaphore: error code %lu", + GetLastError()))); } /* @@ -197,7 +212,7 @@ PGSemaphoreTryLock(PGSemaphore sema) { DWORD ret; - ret = WaitForSingleObject(*sema, 0); + ret = WaitForSingleObject(sema, 0); if (ret == WAIT_OBJECT_0) { @@ -213,7 +228,8 @@ PGSemaphoreTryLock(PGSemaphore sema) /* Otherwise we are in trouble */ ereport(FATAL, - (errmsg("could not try-lock semaphore: error code %lu", GetLastError()))); + (errmsg("could not try-lock semaphore: error code %lu", + GetLastError()))); /* keep compiler quiet */ return false; diff --git a/src/backend/port/win32_shmem.c b/src/backend/port/win32_shmem.c index 0ff2c7eb66..31489fcdb0 100644 --- a/src/backend/port/win32_shmem.c +++ b/src/backend/port/win32_shmem.c @@ -3,7 +3,7 @@ * win32_shmem.c * Implement shared memory using win32 facilities * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/port/win32_shmem.c diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 3768f50bcf..51821d3f55 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -50,7 +50,7 @@ * there is a window (caused by pgstat delay) on which a worker may choose a * table that was already vacuumed; this is a bug in the current design. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -87,6 +87,7 @@ #include "storage/bufmgr.h" #include "storage/ipc.h" #include "storage/latch.h" +#include "storage/lmgr.h" #include "storage/pmsignal.h" #include "storage/proc.h" #include "storage/procsignal.h" @@ -462,9 +463,7 @@ AutoVacLauncherMain(int argc, char *argv[]) */ AutovacMemCxt = AllocSetContextCreate(TopMemoryContext, "Autovacuum Launcher", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); MemoryContextSwitchTo(AutovacMemCxt); /* @@ -600,7 +599,8 @@ AutoVacLauncherMain(int argc, char *argv[]) */ rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L)); + (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L), + WAIT_EVENT_AUTOVACUUM_MAIN); ResetLatch(MyLatch); @@ -894,14 +894,10 @@ rebuild_database_list(Oid newdb) newcxt = AllocSetContextCreate(AutovacMemCxt, "AV dblist", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); tmpcxt = AllocSetContextCreate(newcxt, "tmp AV dblist", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldcxt = MemoryContextSwitchTo(tmpcxt); /* @@ -1111,9 +1107,7 @@ do_start_worker(void) */ tmpcxt = AllocSetContextCreate(CurrentMemoryContext, "Start worker tmp cxt", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldcxt = MemoryContextSwitchTo(tmpcxt); /* use fresh stats */ @@ -1894,6 +1888,7 @@ do_autovacuum(void) HeapScanDesc relScan; Form_pg_database dbForm; List *table_oids = NIL; + List *orphan_oids = NIL; HASHCTL ctl; HTAB *table_toast_map; ListCell *volatile cell; @@ -1903,6 +1898,8 @@ do_autovacuum(void) ScanKeyData key; TupleDesc pg_class_desc; int effective_multixact_freeze_max_age; + bool did_vacuum = false; + bool found_concurrent_worker = false; /* * StartTransactionCommand and CommitTransactionCommand will automatically @@ -1911,9 +1908,7 @@ do_autovacuum(void) */ AutovacMemCxt = AllocSetContextCreate(TopMemoryContext, "AV worker", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); MemoryContextSwitchTo(AutovacMemCxt); /* @@ -1995,7 +1990,7 @@ do_autovacuum(void) * TOAST tables. The reason for doing the second pass is that during it we * want to use the main relation's pg_class.reloptions entry if the TOAST * table does not have any, and we cannot obtain it unless we know - * beforehand what's the main table OID. + * beforehand what's the main table OID. * * We need to check TOAST tables separately because in cases with short, * wide tables there might be proportionally much more activity in the @@ -2023,16 +2018,6 @@ do_autovacuum(void) relid = HeapTupleGetOid(tuple); - /* Fetch reloptions and the pgstat entry for this table */ - relopts = extract_autovac_opts(tuple, pg_class_desc); - tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared, - shared, dbentry); - - /* Check if it needs vacuum or analyze */ - relation_needs_vacanalyze(relid, relopts, classForm, tabentry, - effective_multixact_freeze_max_age, - &dovacuum, &doanalyze, &wraparound); - /* * Check if it is a temp table (presumably, of some other backend's). * We cannot safely process other backends' temp tables. @@ -2044,69 +2029,60 @@ do_autovacuum(void) backendID = GetTempNamespaceBackendId(classForm->relnamespace); /* We just ignore it if the owning backend is still active */ - if (backendID == MyBackendId || BackendIdGetProc(backendID) == NULL) + if (backendID != InvalidBackendId && + (backendID == MyBackendId || + BackendIdGetProc(backendID) == NULL)) { /* - * We found an orphan temp table (which was probably left - * behind by a crashed backend). If it's so old as to need - * vacuum for wraparound, forcibly drop it. Otherwise just - * log a complaint. + * The table seems to be orphaned -- although it might be that + * the owning backend has already deleted it and exited; our + * pg_class scan snapshot is not necessarily up-to-date + * anymore, so we could be looking at a committed-dead entry. + * Remember it so we can try to delete it later. */ - if (wraparound) - { - ObjectAddress object; - - ereport(LOG, - (errmsg("autovacuum: dropping orphan temp table \"%s\".\"%s\" in database \"%s\"", - get_namespace_name(classForm->relnamespace), - NameStr(classForm->relname), - get_database_name(MyDatabaseId)))); - object.classId = RelationRelationId; - object.objectId = relid; - object.objectSubId = 0; - performDeletion(&object, DROP_CASCADE, PERFORM_DELETION_INTERNAL); - } - else - { - ereport(LOG, - (errmsg("autovacuum: found orphan temp table \"%s\".\"%s\" in database \"%s\"", - get_namespace_name(classForm->relnamespace), - NameStr(classForm->relname), - get_database_name(MyDatabaseId)))); - } + orphan_oids = lappend_oid(orphan_oids, relid); } + continue; } - else - { - /* relations that need work are added to table_oids */ - if (dovacuum || doanalyze) - table_oids = lappend_oid(table_oids, relid); - /* - * Remember the association for the second pass. Note: we must do - * this even if the table is going to be vacuumed, because we - * don't automatically vacuum toast tables along the parent table. - */ - if (OidIsValid(classForm->reltoastrelid)) - { - av_relation *hentry; - bool found; + /* Fetch reloptions and the pgstat entry for this table */ + relopts = extract_autovac_opts(tuple, pg_class_desc); + tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared, + shared, dbentry); - hentry = hash_search(table_toast_map, - &classForm->reltoastrelid, - HASH_ENTER, &found); + /* Check if it needs vacuum or analyze */ + relation_needs_vacanalyze(relid, relopts, classForm, tabentry, + effective_multixact_freeze_max_age, + &dovacuum, &doanalyze, &wraparound); - if (!found) + /* Relations that need work are added to table_oids */ + if (dovacuum || doanalyze) + table_oids = lappend_oid(table_oids, relid); + + /* + * Remember TOAST associations for the second pass. Note: we must do + * this whether or not the table is going to be vacuumed, because we + * don't automatically vacuum toast tables along the parent table. + */ + if (OidIsValid(classForm->reltoastrelid)) + { + av_relation *hentry; + bool found; + + hentry = hash_search(table_toast_map, + &classForm->reltoastrelid, + HASH_ENTER, &found); + + if (!found) + { + /* hash_search already filled in the key */ + hentry->ar_relid = relid; + hentry->ar_hasrelopts = false; + if (relopts != NULL) { - /* hash_search already filled in the key */ - hentry->ar_relid = relid; - hentry->ar_hasrelopts = false; - if (relopts != NULL) - { - hentry->ar_hasrelopts = true; - memcpy(&hentry->ar_reloptions, relopts, - sizeof(AutoVacOpts)); - } + hentry->ar_hasrelopts = true; + memcpy(&hentry->ar_reloptions, relopts, + sizeof(AutoVacOpts)); } } } @@ -2170,6 +2146,96 @@ do_autovacuum(void) heap_endscan(relScan); heap_close(classRel, AccessShareLock); + /* + * Recheck orphan temporary tables, and if they still seem orphaned, drop + * them. We'll eat a transaction per dropped table, which might seem + * excessive, but we should only need to do anything as a result of a + * previous backend crash, so this should not happen often enough to + * justify "optimizing". Using separate transactions ensures that we + * don't bloat the lock table if there are many temp tables to be dropped, + * and it ensures that we don't lose work if a deletion attempt fails. + */ + foreach(cell, orphan_oids) + { + Oid relid = lfirst_oid(cell); + Form_pg_class classForm; + int backendID; + ObjectAddress object; + + /* + * Check for user-requested abort. + */ + CHECK_FOR_INTERRUPTS(); + + /* + * Try to lock the table. If we can't get the lock immediately, + * somebody else is using (or dropping) the table, so it's not our + * concern anymore. Having the lock prevents race conditions below. + */ + if (!ConditionalLockRelationOid(relid, AccessExclusiveLock)) + continue; + + /* + * Re-fetch the pg_class tuple and re-check whether it still seems to + * be an orphaned temp table. If it's not there or no longer the same + * relation, ignore it. + */ + tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(tuple)) + { + /* be sure to drop useless lock so we don't bloat lock table */ + UnlockRelationOid(relid, AccessExclusiveLock); + continue; + } + classForm = (Form_pg_class) GETSTRUCT(tuple); + + /* + * Make all the same tests made in the loop above. In event of OID + * counter wraparound, the pg_class entry we have now might be + * completely unrelated to the one we saw before. + */ + if (!((classForm->relkind == RELKIND_RELATION || + classForm->relkind == RELKIND_MATVIEW) && + classForm->relpersistence == RELPERSISTENCE_TEMP)) + { + UnlockRelationOid(relid, AccessExclusiveLock); + continue; + } + backendID = GetTempNamespaceBackendId(classForm->relnamespace); + if (!(backendID != InvalidBackendId && + (backendID == MyBackendId || + BackendIdGetProc(backendID) == NULL))) + { + UnlockRelationOid(relid, AccessExclusiveLock); + continue; + } + + /* OK, let's delete it */ + ereport(LOG, + (errmsg("autovacuum: dropping orphan temp table \"%s.%s.%s\"", + get_database_name(MyDatabaseId), + get_namespace_name(classForm->relnamespace), + NameStr(classForm->relname)))); + + object.classId = RelationRelationId; + object.objectId = relid; + object.objectSubId = 0; + performDeletion(&object, DROP_CASCADE, + PERFORM_DELETION_INTERNAL | + PERFORM_DELETION_QUIETLY | + PERFORM_DELETION_SKIP_EXTENSIONS); + + /* + * To commit the deletion, end current transaction and start a new + * one. Note this also releases the lock we took. + */ + CommitTransactionCommand(); + StartTransactionCommand(); + + /* StartTransactionCommand changed current memory context */ + MemoryContextSwitchTo(AutovacMemCxt); + } + /* * Create a buffer access strategy object for VACUUM to use. We want to * use the same one across all the vacuum operations we perform, since the @@ -2183,9 +2249,7 @@ do_autovacuum(void) */ PortalContext = AllocSetContextCreate(AutovacMemCxt, "Autovacuum Portal", - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* * Perform operations on collected tables. @@ -2245,6 +2309,7 @@ do_autovacuum(void) if (worker->wi_tableoid == relid) { skipit = true; + found_concurrent_worker = true; break; } } @@ -2371,6 +2436,8 @@ do_autovacuum(void) } PG_END_TRY(); + did_vacuum = true; + /* the PGXACT flags are reset at the next end of transaction */ /* be tidy */ @@ -2408,8 +2475,25 @@ do_autovacuum(void) /* * Update pg_database.datfrozenxid, and truncate pg_clog if possible. We * only need to do this once, not after each table. + * + * Even if we didn't vacuum anything, it may still be important to do + * this, because one indirect effect of vac_update_datfrozenxid() is to + * update ShmemVariableCache->xidVacLimit. That might need to be done + * even if we haven't vacuumed anything, because relations with older + * relfrozenxid values or other databases with older datfrozenxid values + * might have been dropped, allowing xidVacLimit to advance. + * + * However, it's also important not to do this blindly in all cases, + * because when autovacuum=off this will restart the autovacuum launcher. + * If we're not careful, an infinite loop can result, where workers find + * no work to do and restart the launcher, which starts another worker in + * the same database that finds no work to do. To prevent that, we skip + * this if (1) we found no work to do and (2) we skipped at least one + * table due to concurrent autovacuum activity. In that case, the other + * worker has already done it, or will do so when it finishes. */ - vac_update_datfrozenxid(); + if (did_vacuum || !found_concurrent_worker) + vac_update_datfrozenxid(); /* Finally close out the last transaction. */ CommitTransactionCommand(); diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c index 699c934240..cd99b0b392 100644 --- a/src/backend/postmaster/bgworker.c +++ b/src/backend/postmaster/bgworker.c @@ -2,7 +2,7 @@ * bgworker.c * POSTGRES pluggable background workers implementation * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/postmaster/bgworker.c @@ -14,11 +14,13 @@ #include -#include "miscadmin.h" #include "libpq/pqsignal.h" +#include "miscadmin.h" +#include "pgstat.h" +#include "port/atomics.h" #include "postmaster/bgworker_internals.h" #include "postmaster/postmaster.h" -#include "storage/barrier.h" +#include "replication/logicallauncher.h" #include "storage/dsm.h" #include "storage/ipc.h" #include "storage/latch.h" @@ -79,9 +81,22 @@ typedef struct BackgroundWorkerSlot BackgroundWorker worker; } BackgroundWorkerSlot; +/* + * In order to limit the total number of parallel workers (according to + * max_parallel_workers GUC), we maintain the number of active parallel + * workers. Since the postmaster cannot take locks, two variables are used for + * this purpose: the number of registered parallel workers (modified by the + * backends, protected by BackgroundWorkerLock) and the number of terminated + * parallel workers (modified only by the postmaster, lockless). The active + * number of parallel workers is the number of registered workers minus the + * terminated ones. These counters can of course overflow, but it's not + * important here since the subtraction will still give the right number. + */ typedef struct BackgroundWorkerArray { int total_slots; + uint32 parallel_register_count; + uint32 parallel_terminate_count; BackgroundWorkerSlot slot[FLEXIBLE_ARRAY_MEMBER]; } BackgroundWorkerArray; @@ -93,6 +108,15 @@ struct BackgroundWorkerHandle static BackgroundWorkerArray *BackgroundWorkerData; +/* + * List of workers that are allowed to be started outside of + * shared_preload_libraries. + */ +static const bgworker_main_type InternalBGWorkers[] = { + ApplyLauncherMain, + NULL +}; + /* * Calculate shared memory needed. */ @@ -126,6 +150,8 @@ BackgroundWorkerShmemInit(void) int slotno = 0; BackgroundWorkerData->total_slots = max_worker_processes; + BackgroundWorkerData->parallel_register_count = 0; + BackgroundWorkerData->parallel_terminate_count = 0; /* * Copy contents of worker list into shared memory. Record the shared @@ -266,9 +292,12 @@ BackgroundWorkerStateChange(void) /* * We need a memory barrier here to make sure that the load of - * bgw_notify_pid completes before the store to in_use. + * bgw_notify_pid and the update of parallel_terminate_count + * complete before the store to in_use. */ notify_pid = slot->worker.bgw_notify_pid; + if ((slot->worker.bgw_flags & BGWORKER_CLASS_PARALLEL) != 0) + BackgroundWorkerData->parallel_terminate_count++; pg_memory_barrier(); slot->pid = 0; slot->in_use = false; @@ -369,6 +398,9 @@ ForgetBackgroundWorker(slist_mutable_iter *cur) Assert(rw->rw_shmem_slot < max_worker_processes); slot = &BackgroundWorkerData->slot[rw->rw_shmem_slot]; + if ((rw->rw_worker.bgw_flags & BGWORKER_CLASS_PARALLEL) != 0) + BackgroundWorkerData->parallel_terminate_count++; + slot->in_use = false; ereport(DEBUG1, @@ -601,7 +633,6 @@ StartBackgroundWorker(void) */ if ((worker->bgw_flags & BGWORKER_SHMEM_ACCESS) == 0) { - on_exit_reset(); dsm_detach_all(); PGSharedMemoryDetach(); } @@ -740,12 +771,23 @@ RegisterBackgroundWorker(BackgroundWorker *worker) { RegisteredBgWorker *rw; static int numworkers = 0; + bool internal = false; + int i; if (!IsUnderPostmaster) ereport(DEBUG1, (errmsg("registering background worker \"%s\"", worker->bgw_name))); - if (!process_shared_preload_libraries_in_progress) + for (i = 0; InternalBGWorkers[i]; i++) + { + if (worker->bgw_main == InternalBGWorkers[i]) + { + internal = true; + break; + } + } + + if (!process_shared_preload_libraries_in_progress && !internal) { if (!IsUnderPostmaster) ereport(LOG, @@ -824,6 +866,7 @@ RegisterDynamicBackgroundWorker(BackgroundWorker *worker, { int slotno; bool success = false; + bool parallel; uint64 generation = 0; /* @@ -840,8 +883,27 @@ RegisterDynamicBackgroundWorker(BackgroundWorker *worker, if (!SanityCheckBackgroundWorker(worker, ERROR)) return false; + parallel = (worker->bgw_flags & BGWORKER_CLASS_PARALLEL) != 0; + LWLockAcquire(BackgroundWorkerLock, LW_EXCLUSIVE); + /* + * If this is a parallel worker, check whether there are already too many + * parallel workers; if so, don't register another one. Our view of + * parallel_terminate_count may be slightly stale, but that doesn't really + * matter: we would have gotten the same result if we'd arrived here + * slightly earlier anyway. There's no help for it, either, since the + * postmaster must not take locks; a memory barrier wouldn't guarantee + * anything useful. + */ + if (parallel && (BackgroundWorkerData->parallel_register_count - + BackgroundWorkerData->parallel_terminate_count) >= + max_parallel_workers) + { + LWLockRelease(BackgroundWorkerLock); + return false; + } + /* * Look for an unused slot. If we find one, grab it. */ @@ -856,6 +918,8 @@ RegisterDynamicBackgroundWorker(BackgroundWorker *worker, slot->generation++; slot->terminate = false; generation = slot->generation; + if (parallel) + BackgroundWorkerData->parallel_register_count++; /* * Make sure postmaster doesn't see the slot as in use before it @@ -969,7 +1033,8 @@ WaitForBackgroundWorkerStartup(BackgroundWorkerHandle *handle, pid_t *pidp) break; rc = WaitLatch(MyLatch, - WL_LATCH_SET | WL_POSTMASTER_DEATH, 0); + WL_LATCH_SET | WL_POSTMASTER_DEATH, 0, + WAIT_EVENT_BGWORKER_STARTUP); if (rc & WL_POSTMASTER_DEATH) { @@ -1008,7 +1073,8 @@ WaitForBackgroundWorkerShutdown(BackgroundWorkerHandle *handle) break; rc = WaitLatch(&MyProc->procLatch, - WL_LATCH_SET | WL_POSTMASTER_DEATH, 0); + WL_LATCH_SET | WL_POSTMASTER_DEATH, 0, + WAIT_EVENT_BGWORKER_SHUTDOWN); if (rc & WL_POSTMASTER_DEATH) { diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c index 00f03d8acb..40819824ad 100644 --- a/src/backend/postmaster/bgwriter.c +++ b/src/backend/postmaster/bgwriter.c @@ -24,7 +24,7 @@ * should be killed by SIGQUIT and then a recovery cycle started. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -46,6 +46,7 @@ #include "postmaster/bgwriter.h" #include "storage/bufmgr.h" #include "storage/buf_internals.h" +#include "storage/condition_variable.h" #include "storage/fd.h" #include "storage/ipc.h" #include "storage/lwlock.h" @@ -160,9 +161,7 @@ BackgroundWriterMain(void) */ bgwriter_context = AllocSetContextCreate(TopMemoryContext, "Background Writer", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); MemoryContextSwitchTo(bgwriter_context); WritebackContextInit(&wb_context, &bgwriter_flush_after); @@ -189,6 +188,7 @@ BackgroundWriterMain(void) * about in bgwriter, but we do have LWLocks, buffers, and temp files. */ LWLockReleaseAll(); + ConditionVariableCancelSleep(); AbortBufferIO(); UnlockBuffers(); /* buffer pins are released here: */ @@ -310,7 +310,7 @@ BackgroundWriterMain(void) * check whether there has been any WAL inserted since the last time * we've logged a running xacts. * - * We do this logging in the bgwriter as its the only process that is + * We do this logging in the bgwriter as it is the only process that is * run regularly and returns to its mainloop all the time. E.g. * Checkpointer, when active, is barely ever in its mainloop and thus * makes it hard to log regularly. @@ -324,11 +324,11 @@ BackgroundWriterMain(void) LOG_SNAPSHOT_INTERVAL_MS); /* - * only log if enough time has passed and some xlog record has - * been inserted. + * Only log if enough time has passed and interesting records have + * been inserted since the last snapshot. */ if (now >= timeout && - last_snapshot_lsn != GetXLogInsertRecPtr()) + last_snapshot_lsn < GetLastImportantRecPtr()) { last_snapshot_lsn = LogStandbySnapshot(); last_snapshot_ts = now; @@ -347,7 +347,7 @@ BackgroundWriterMain(void) */ rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - BgWriterDelay /* ms */ ); + BgWriterDelay /* ms */, WAIT_EVENT_BGWRITER_MAIN); /* * If no latch event and BgBufferSync says nothing's happening, extend @@ -374,7 +374,8 @@ BackgroundWriterMain(void) /* Sleep ... */ rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - BgWriterDelay * HIBERNATE_FACTOR); + BgWriterDelay * HIBERNATE_FACTOR, + WAIT_EVENT_BGWRITER_HIBERNATE); /* Reset the notification request in case we timed out */ StrategyNotifyBgWriter(-1); } diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c index 8d4b3539b1..fe9041f748 100644 --- a/src/backend/postmaster/checkpointer.c +++ b/src/backend/postmaster/checkpointer.c @@ -26,7 +26,7 @@ * restart needs to be forced.) * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -49,6 +49,7 @@ #include "postmaster/bgwriter.h" #include "replication/syncrep.h" #include "storage/bufmgr.h" +#include "storage/condition_variable.h" #include "storage/fd.h" #include "storage/ipc.h" #include "storage/lwlock.h" @@ -245,9 +246,7 @@ CheckpointerMain(void) */ checkpointer_context = AllocSetContextCreate(TopMemoryContext, "Checkpointer", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); MemoryContextSwitchTo(checkpointer_context); /* @@ -273,6 +272,7 @@ CheckpointerMain(void) * files. */ LWLockReleaseAll(); + ConditionVariableCancelSleep(); pgstat_report_wait_end(); AbortBufferIO(); UnlockBuffers(); @@ -558,7 +558,8 @@ CheckpointerMain(void) rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - cur_timeout * 1000L /* convert to ms */ ); + cur_timeout * 1000L /* convert to ms */, + WAIT_EVENT_CHECKPOINTER_MAIN); /* * Emergency bailout if postmaster has died. This is to avoid the @@ -572,15 +573,21 @@ CheckpointerMain(void) /* * CheckArchiveTimeout -- check for archive_timeout and switch xlog files * - * This will switch to a new WAL file and force an archive file write - * if any activity is recorded in the current WAL file, including just - * a single checkpoint record. + * This will switch to a new WAL file and force an archive file write if + * meaningful activity is recorded in the current WAL file. This includes most + * writes, including just a single checkpoint record, but excludes WAL records + * that were inserted with the XLOG_MARK_UNIMPORTANT flag being set (like + * snapshots of running transactions). Such records, depending on + * configuration, occur on regular intervals and don't contain important + * information. This avoids generating archives with a few unimportant + * records. */ static void CheckArchiveTimeout(void) { pg_time_t now; pg_time_t last_time; + XLogRecPtr last_switch_lsn; if (XLogArchiveTimeout <= 0 || RecoveryInProgress()) return; @@ -595,26 +602,33 @@ CheckArchiveTimeout(void) * Update local state ... note that last_xlog_switch_time is the last time * a switch was performed *or requested*. */ - last_time = GetLastSegSwitchTime(); + last_time = GetLastSegSwitchData(&last_switch_lsn); last_xlog_switch_time = Max(last_xlog_switch_time, last_time); - /* Now we can do the real check */ + /* Now we can do the real checks */ if ((int) (now - last_xlog_switch_time) >= XLogArchiveTimeout) { - XLogRecPtr switchpoint; - - /* OK, it's time to switch */ - switchpoint = RequestXLogSwitch(); - /* - * If the returned pointer points exactly to a segment boundary, - * assume nothing happened. + * Switch segment only when "important" WAL has been logged since the + * last segment switch. */ - if ((switchpoint % XLogSegSize) != 0) - ereport(DEBUG1, - (errmsg("transaction log switch forced (archive_timeout=%d)", - XLogArchiveTimeout))); + if (GetLastImportantRecPtr() > last_switch_lsn) + { + XLogRecPtr switchpoint; + + /* mark switch as unimportant, avoids triggering checkpoints */ + switchpoint = RequestXLogSwitch(true); + + /* + * If the returned pointer points exactly to a segment boundary, + * assume nothing happened. + */ + if ((switchpoint % XLogSegSize) != 0) + ereport(DEBUG1, + (errmsg("transaction log switch forced (archive_timeout=%d)", + XLogArchiveTimeout))); + } /* * Update state in any case, so we don't retry constantly when the diff --git a/src/backend/postmaster/fork_process.c b/src/backend/postmaster/fork_process.c index c1958e8161..0bb15d8487 100644 --- a/src/backend/postmaster/fork_process.c +++ b/src/backend/postmaster/fork_process.c @@ -4,7 +4,7 @@ * EXEC_BACKEND case; it might be extended to do so, but it would be * considerably more complex. * - * Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/postmaster/fork_process.c diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c index 1aa6466d67..f3f58bd390 100644 --- a/src/backend/postmaster/pgarch.c +++ b/src/backend/postmaster/pgarch.c @@ -14,7 +14,7 @@ * * Initial author: Simon Riggs simon@2ndquadrant.com * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -390,7 +390,8 @@ pgarch_MainLoop(void) rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - timeout * 1000L); + timeout * 1000L, + WAIT_EVENT_ARCHIVER_MAIN); if (rc & WL_TIMEOUT) wakened = true; } diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 8fa9edbf72..7176cf1bbe 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -11,7 +11,7 @@ * - Add a pgstat config column to pg_database, so this * entire thing can be enabled/disabled on a per db basis. * - * Copyright (c) 2001-2016, PostgreSQL Global Development Group + * Copyright (c) 2001-2017, PostgreSQL Global Development Group * * src/backend/postmaster/pgstat.c * ---------- @@ -28,6 +28,9 @@ #include #include #include +#ifdef HAVE_SYS_SELECT_H +#include +#endif #include "pgstat.h" @@ -38,7 +41,7 @@ #include "access/xact.h" #include "catalog/pg_database.h" #include "catalog/pg_proc.h" -#include "libpq/ip.h" +#include "common/ip.h" #include "libpq/libpq.h" #include "libpq/pqsignal.h" #include "mb/pg_wchar.h" @@ -273,6 +276,11 @@ static PgStat_TableStatus *get_tabstat_entry(Oid rel_id, bool isshared); static void pgstat_setup_memcxt(void); +static const char *pgstat_get_wait_activity(WaitEventActivity w); +static const char *pgstat_get_wait_client(WaitEventClient w); +static const char *pgstat_get_wait_ipc(WaitEventIPC w); +static const char *pgstat_get_wait_timeout(WaitEventTimeout w); + static void pgstat_setheader(PgStat_MsgHdr *hdr, StatMsgType mtype); static void pgstat_send(void *msg, int len); @@ -2218,7 +2226,12 @@ pgstat_twophase_postcommit(TransactionId xid, uint16 info, pgstat_info->t_counts.t_tuples_updated += rec->tuples_updated; pgstat_info->t_counts.t_tuples_deleted += rec->tuples_deleted; pgstat_info->t_counts.t_truncated = rec->t_truncated; - + if (rec->t_truncated) + { + /* forget live/dead stats seen by backend thus far */ + pgstat_info->t_counts.t_delta_live_tuples = 0; + pgstat_info->t_counts.t_delta_dead_tuples = 0; + } pgstat_info->t_counts.t_delta_live_tuples += rec->tuples_inserted - rec->tuples_deleted; pgstat_info->t_counts.t_delta_dead_tuples += @@ -2398,7 +2411,7 @@ pgstat_fetch_stat_beentry(int beid) /* ---------- * pgstat_fetch_stat_local_beentry() - * - * Like pgstat_fetch_stat_beentry() but with locally computed addtions (like + * Like pgstat_fetch_stat_beentry() but with locally computed additions (like * xid and xmin values of the backend) * * NB: caller is responsible for a check if the user is permitted to see @@ -3128,30 +3141,41 @@ pgstat_read_current_status(void) const char * pgstat_get_wait_event_type(uint32 wait_event_info) { - uint8 classId; + uint32 classId; const char *event_type; /* report process as not waiting. */ if (wait_event_info == 0) return NULL; - wait_event_info = wait_event_info >> 24; - classId = wait_event_info & 0XFF; + classId = wait_event_info & 0xFF000000; switch (classId) { - case WAIT_LWLOCK_NAMED: - event_type = "LWLockNamed"; - break; - case WAIT_LWLOCK_TRANCHE: - event_type = "LWLockTranche"; + case PG_WAIT_LWLOCK: + event_type = "LWLock"; break; - case WAIT_LOCK: + case PG_WAIT_LOCK: event_type = "Lock"; break; - case WAIT_BUFFER_PIN: + case PG_WAIT_BUFFER_PIN: event_type = "BufferPin"; break; + case PG_WAIT_ACTIVITY: + event_type = "Activity"; + break; + case PG_WAIT_CLIENT: + event_type = "Client"; + break; + case PG_WAIT_EXTENSION: + event_type = "Extension"; + break; + case PG_WAIT_IPC: + event_type = "IPC"; + break; + case PG_WAIT_TIMEOUT: + event_type = "Timeout"; + break; default: event_type = "???"; break; @@ -3169,7 +3193,7 @@ pgstat_get_wait_event_type(uint32 wait_event_info) const char * pgstat_get_wait_event(uint32 wait_event_info) { - uint8 classId; + uint32 classId; uint16 eventId; const char *event_name; @@ -3177,22 +3201,51 @@ pgstat_get_wait_event(uint32 wait_event_info) if (wait_event_info == 0) return NULL; - eventId = wait_event_info & ((1 << 24) - 1); - wait_event_info = wait_event_info >> 24; - classId = wait_event_info & 0XFF; + classId = wait_event_info & 0xFF000000; + eventId = wait_event_info & 0x0000FFFF; switch (classId) { - case WAIT_LWLOCK_NAMED: - case WAIT_LWLOCK_TRANCHE: + case PG_WAIT_LWLOCK: event_name = GetLWLockIdentifier(classId, eventId); break; - case WAIT_LOCK: + case PG_WAIT_LOCK: event_name = GetLockNameFromTagType(eventId); break; - case WAIT_BUFFER_PIN: + case PG_WAIT_BUFFER_PIN: event_name = "BufferPin"; break; + case PG_WAIT_ACTIVITY: + { + WaitEventActivity w = (WaitEventActivity) wait_event_info; + + event_name = pgstat_get_wait_activity(w); + break; + } + case PG_WAIT_CLIENT: + { + WaitEventClient w = (WaitEventClient) wait_event_info; + + event_name = pgstat_get_wait_client(w); + break; + } + case PG_WAIT_EXTENSION: + event_name = "Extension"; + break; + case PG_WAIT_IPC: + { + WaitEventIPC w = (WaitEventIPC) wait_event_info; + + event_name = pgstat_get_wait_ipc(w); + break; + } + case PG_WAIT_TIMEOUT: + { + WaitEventTimeout w = (WaitEventTimeout) wait_event_info; + + event_name = pgstat_get_wait_timeout(w); + break; + } default: event_name = "unknown wait event"; break; @@ -3201,6 +3254,184 @@ pgstat_get_wait_event(uint32 wait_event_info) return event_name; } +/* ---------- + * pgstat_get_wait_activity() - + * + * Convert WaitEventActivity to string. + * ---------- + */ +static const char * +pgstat_get_wait_activity(WaitEventActivity w) +{ + const char *event_name = "unknown wait event"; + + switch (w) + { + case WAIT_EVENT_ARCHIVER_MAIN: + event_name = "ArchiverMain"; + break; + case WAIT_EVENT_AUTOVACUUM_MAIN: + event_name = "AutoVacuumMain"; + break; + case WAIT_EVENT_BGWRITER_HIBERNATE: + event_name = "BgWriterHibernate"; + break; + case WAIT_EVENT_BGWRITER_MAIN: + event_name = "BgWriterMain"; + break; + case WAIT_EVENT_CHECKPOINTER_MAIN: + event_name = "CheckpointerMain"; + break; + case WAIT_EVENT_PGSTAT_MAIN: + event_name = "PgStatMain"; + break; + case WAIT_EVENT_RECOVERY_WAL_ALL: + event_name = "RecoveryWalAll"; + break; + case WAIT_EVENT_RECOVERY_WAL_STREAM: + event_name = "RecoveryWalStream"; + break; + case WAIT_EVENT_SYSLOGGER_MAIN: + event_name = "SysLoggerMain"; + break; + case WAIT_EVENT_WAL_RECEIVER_MAIN: + event_name = "WalReceiverMain"; + break; + case WAIT_EVENT_WAL_SENDER_MAIN: + event_name = "WalSenderMain"; + break; + case WAIT_EVENT_WAL_WRITER_MAIN: + event_name = "WalWriterMain"; + break; + case WAIT_EVENT_LOGICAL_LAUNCHER_MAIN: + event_name = "LogicalLauncherMain"; + break; + case WAIT_EVENT_LOGICAL_APPLY_MAIN: + event_name = "LogicalApplyMain"; + break; + /* no default case, so that compiler will warn */ + } + + return event_name; +} + +/* ---------- + * pgstat_get_wait_client() - + * + * Convert WaitEventClient to string. + * ---------- + */ +static const char * +pgstat_get_wait_client(WaitEventClient w) +{ + const char *event_name = "unknown wait event"; + + switch (w) + { + case WAIT_EVENT_CLIENT_READ: + event_name = "ClientRead"; + break; + case WAIT_EVENT_CLIENT_WRITE: + event_name = "ClientWrite"; + break; + case WAIT_EVENT_SSL_OPEN_SERVER: + event_name = "SSLOpenServer"; + break; + case WAIT_EVENT_WAL_RECEIVER_WAIT_START: + event_name = "WalReceiverWaitStart"; + break; + case WAIT_EVENT_LIBPQWALRECEIVER_READ: + event_name = "LibPQWalReceiverRead"; + break; + case WAIT_EVENT_WAL_SENDER_WAIT_WAL: + event_name = "WalSenderWaitForWAL"; + break; + case WAIT_EVENT_WAL_SENDER_WRITE_DATA: + event_name = "WalSenderWriteData"; + break; + /* no default case, so that compiler will warn */ + } + + return event_name; +} + +/* ---------- + * pgstat_get_wait_ipc() - + * + * Convert WaitEventIPC to string. + * ---------- + */ +static const char * +pgstat_get_wait_ipc(WaitEventIPC w) +{ + const char *event_name = "unknown wait event"; + + switch (w) + { + case WAIT_EVENT_BGWORKER_SHUTDOWN: + event_name = "BgWorkerShutdown"; + break; + case WAIT_EVENT_BGWORKER_STARTUP: + event_name = "BgWorkerStartup"; + break; + case WAIT_EVENT_EXECUTE_GATHER: + event_name = "ExecuteGather"; + break; + case WAIT_EVENT_MQ_INTERNAL: + event_name = "MessageQueueInternal"; + break; + case WAIT_EVENT_MQ_PUT_MESSAGE: + event_name = "MessageQueuePutMessage"; + break; + case WAIT_EVENT_MQ_RECEIVE: + event_name = "MessageQueueReceive"; + break; + case WAIT_EVENT_MQ_SEND: + event_name = "MessageQueueSend"; + break; + case WAIT_EVENT_PARALLEL_FINISH: + event_name = "ParallelFinish"; + break; + case WAIT_EVENT_SAFE_SNAPSHOT: + event_name = "SafeSnapshot"; + break; + case WAIT_EVENT_SYNC_REP: + event_name = "SyncRep"; + break; + /* no default case, so that compiler will warn */ + } + + return event_name; +} + +/* ---------- + * pgstat_get_wait_timeout() - + * + * Convert WaitEventTimeout to string. + * ---------- + */ +static const char * +pgstat_get_wait_timeout(WaitEventTimeout w) +{ + const char *event_name = "unknown wait event"; + + switch (w) + { + case WAIT_EVENT_BASE_BACKUP_THROTTLE: + event_name = "BaseBackupThrottle"; + break; + case WAIT_EVENT_PG_SLEEP: + event_name = "PgSleep"; + break; + case WAIT_EVENT_RECOVERY_APPLY_DELAY: + event_name = "RecoveryApplyDelay"; + break; + /* no default case, so that compiler will warn */ + } + + return event_name; +} + /* ---------- * pgstat_get_backend_current_activity() - * @@ -3681,8 +3912,8 @@ PgstatCollectorMain(int argc, char *argv[]) #ifndef WIN32 wr = WaitLatchOrSocket(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_SOCKET_READABLE, - pgStatSock, - -1L); + pgStatSock, -1L, + WAIT_EVENT_PGSTAT_MAIN); #else /* @@ -3698,7 +3929,8 @@ PgstatCollectorMain(int argc, char *argv[]) wr = WaitLatchOrSocket(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_SOCKET_READABLE | WL_TIMEOUT, pgStatSock, - 2 * 1000L /* msec */ ); + 2 * 1000L /* msec */, + WAIT_EVENT_PGSTAT_MAIN); #endif /* @@ -4792,9 +5024,7 @@ pgstat_setup_memcxt(void) if (!pgStatLocalContext) pgStatLocalContext = AllocSetContextCreate(TopMemoryContext, "Statistics snapshot", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MAXSIZE); + ALLOCSET_SMALL_SIZES); } diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index f5c8e9d812..91ccbe78c0 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -32,7 +32,7 @@ * clients. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -99,9 +99,9 @@ #include "access/xlog.h" #include "bootstrap/bootstrap.h" #include "catalog/pg_control.h" +#include "common/ip.h" #include "lib/ilist.h" #include "libpq/auth.h" -#include "libpq/ip.h" #include "libpq/libpq.h" #include "libpq/pqsignal.h" #include "miscadmin.h" @@ -113,6 +113,7 @@ #include "postmaster/pgarch.h" #include "postmaster/postmaster.h" #include "postmaster/syslogger.h" +#include "replication/logicallauncher.h" #include "replication/walsender.h" #include "storage/fd.h" #include "storage/ipc.h" @@ -126,6 +127,7 @@ #include "utils/memutils.h" #include "utils/ps_status.h" #include "utils/timeout.h" +#include "utils/varlena.h" #ifdef EXEC_BACKEND #include "storage/spin.h" @@ -164,7 +166,7 @@ typedef struct bkend { pid_t pid; /* process id of backend */ - long cancel_key; /* cancel key for cancels for this backend */ + int32 cancel_key; /* cancel key for cancels for this backend */ int child_slot; /* PMChildSlot for this backend, if any */ /* @@ -358,13 +360,20 @@ static volatile bool avlauncher_needs_signal = false; static volatile bool StartWorkerNeeded = true; static volatile bool HaveCrashedWorker = false; +#ifndef HAVE_STRONG_RANDOM /* - * State for assigning random salts and cancel keys. + * State for assigning cancel keys. * Also, the global MyCancelKey passes the cancel key assigned to a given * backend from the postmaster to that backend (via fork). */ static unsigned int random_seed = 0; static struct timeval random_start_time; +#endif + +#ifdef USE_SSL +/* Set when and if SSL has been initialized properly */ +static bool LoadedSSL = false; +#endif #ifdef USE_BONJOUR static DNSServiceRef bonjour_sdref = NULL; @@ -403,8 +412,7 @@ static void processCancelRequest(Port *port, void *pkt); static int initMasks(fd_set *rmask); static void report_fork_failure_to_client(Port *port, int errnum); static CAC_state canAcceptConnections(void); -static long PostmasterRandom(void); -static void RandomSalt(char *md5Salt); +static bool RandomCancelKey(int32 *cancel_key); static void signal_child(pid_t pid, int signal); static bool SignalSomeChildren(int signal, int targets); static void TerminateChildren(int signal); @@ -471,7 +479,7 @@ typedef struct InheritableSocket portsocket; char DataDir[MAXPGPATH]; pgsocket ListenSocket[MAXLISTEN]; - long MyCancelKey; + int32 MyCancelKey; int MyPMChildSlot; #ifndef WIN32 unsigned long UsedShmemSegID; @@ -483,7 +491,7 @@ typedef struct VariableCache ShmemVariableCache; Backend *ShmemBackendArray; #ifndef HAVE_SPINLOCKS - PGSemaphore SpinlockSemaArray; + PGSemaphore *SpinlockSemaArray; #endif int NamedLWLockTrancheRequests; NamedLWLockTranche *NamedLWLockTrancheArray; @@ -575,6 +583,16 @@ PostmasterMain(int argc, char *argv[]) */ umask(S_IRWXG | S_IRWXO); + /* + * Initialize random(3) so we don't get the same values in every run. + * + * Note: the seed is pretty predictable from externally-visible facts such + * as postmaster start time, so avoid using random() for security-critical + * random values during postmaster startup. At the time of first + * connection, PostmasterRandom will select a hopefully-more-random seed. + */ + srandom((unsigned int) (MyProcPid ^ MyStartTime)); + /* * By default, palloc() requests in the postmaster will be allocated in * the PostmasterContext, which is space that can be recycled by backends. @@ -583,9 +601,7 @@ PostmasterMain(int argc, char *argv[]) */ PostmasterContext = AllocSetContextCreate(TopMemoryContext, "Postmaster", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); MemoryContextSwitchTo(PostmasterContext); /* Initialize paths to installation files */ @@ -921,9 +937,20 @@ PostmasterMain(int argc, char *argv[]) */ #ifdef USE_SSL if (EnableSSL) - secure_initialize(); + { + (void) secure_initialize(true); + LoadedSSL = true; + } #endif + /* + * Register the apply launcher. Since it registers a background worker, + * it needs to be called before InitializeMaxBackends(), and it's probably + * a good idea to call it before any modules had chance to take the + * background worker slots. + */ + ApplyLauncherRegister(); + /* * process any libraries that should be preloaded at postmaster start */ @@ -1265,7 +1292,7 @@ PostmasterMain(int argc, char *argv[]) #ifdef HAVE_PTHREAD_IS_THREADED_NP /* - * On Darwin, libintl replaces setlocale() with a version that calls + * On macOS, libintl replaces setlocale() with a version that calls * CFLocaleCopyCurrent() when its second argument is "" and every relevant * environment variable is unset or empty. CFLocaleCopyCurrent() makes * the process multithreaded. The postmaster calls sigprocmask() and @@ -1284,8 +1311,10 @@ PostmasterMain(int argc, char *argv[]) * Remember postmaster startup time */ PgStartTime = GetCurrentTimestamp(); - /* PostmasterRandom wants its own copy */ +#ifndef HAVE_STRONG_RANDOM + /* RandomCancelKey wants its own copy */ gettimeofday(&random_start_time, NULL); +#endif /* * We're ready to rock and roll... @@ -1745,7 +1774,8 @@ ServerLoop(void) } /* If we have lost the stats collector, try to start a new one */ - if (PgStatPID == 0 && pmState == PM_RUN) + if (PgStatPID == 0 && + (pmState == PM_RUN || pmState == PM_HOT_STANDBY)) PgStatPID = pgstat_start(); /* If we have lost the archiver, try to start a new one. */ @@ -1949,7 +1979,7 @@ ProcessStartupPacket(Port *port, bool SSLdone) #ifdef USE_SSL /* No SSL when disabled or on Unix sockets */ - if (!EnableSSL || IS_AF_UNIX(port->laddr.addr.ss_family)) + if (!LoadedSSL || IS_AF_UNIX(port->laddr.addr.ss_family)) SSLok = 'N'; else SSLok = 'S'; /* Support for SSL */ @@ -2204,7 +2234,7 @@ processCancelRequest(Port *port, void *pkt) { CancelRequestPacket *canc = (CancelRequestPacket *) pkt; int backendPID; - long cancelAuthCode; + int32 cancelAuthCode; Backend *bp; #ifndef EXEC_BACKEND @@ -2214,7 +2244,7 @@ processCancelRequest(Port *port, void *pkt) #endif backendPID = (int) ntohl(canc->backendPID); - cancelAuthCode = (long) ntohl(canc->cancelAuthCode); + cancelAuthCode = (int32) ntohl(canc->cancelAuthCode); /* * See if we have a matching backend. In the EXEC_BACKEND case, we can no @@ -2335,15 +2365,6 @@ ConnCreate(int serverFd) return NULL; } - /* - * Precompute password salt values to use for this connection. It's - * slightly annoying to do this long in advance of knowing whether we'll - * need 'em or not, but we must do the random() calls before we fork, not - * after. Else the postmaster's random sequence won't get advanced, and - * all backends would end up using the same salt... - */ - RandomSalt(port->md5Salt); - /* * Allocate GSSAPI specific state struct */ @@ -2495,12 +2516,29 @@ SIGHUP_handler(SIGNAL_ARGS) /* Reload authentication config files too */ if (!load_hba()) - ereport(WARNING, - (errmsg("pg_hba.conf not reloaded"))); + ereport(LOG, + (errmsg("pg_hba.conf was not reloaded"))); if (!load_ident()) - ereport(WARNING, - (errmsg("pg_ident.conf not reloaded"))); + ereport(LOG, + (errmsg("pg_ident.conf was not reloaded"))); + +#ifdef USE_SSL + /* Reload SSL configuration as well */ + if (EnableSSL) + { + if (secure_initialize(false) == 0) + LoadedSSL = true; + else + ereport(LOG, + (errmsg("SSL configuration was not reloaded"))); + } + else + { + secure_destroy(); + LoadedSSL = false; + } +#endif #ifdef EXEC_BACKEND /* Update the starting-point file for future children */ @@ -2955,7 +2993,7 @@ reaper(SIGNAL_ARGS) if (!EXIT_STATUS_0(exitstatus)) LogChildExit(LOG, _("statistics collector process"), pid, exitstatus); - if (pmState == PM_RUN) + if (pmState == PM_RUN || pmState == PM_HOT_STANDBY) PgStatPID = pgstat_start(); continue; } @@ -3896,7 +3934,15 @@ BackendStartup(Port *port) * backend will have its own copy in the forked-off process' value of * MyCancelKey, so that it can transmit the key to the frontend. */ - MyCancelKey = PostmasterRandom(); + if (!RandomCancelKey(&MyCancelKey)) + { + free(bn); + ereport(LOG, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("could not generate random cancel key"))); + return STATUS_ERROR; + } + bn->cancel_key = MyCancelKey; /* Pass down canAcceptConnections state */ @@ -4209,8 +4255,10 @@ BackendRun(Port *port) * generator state. We have to clobber the static random_seed *and* start * a new random sequence in the random() library function. */ +#ifndef HAVE_STRONG_RANDOM random_seed = 0; random_start_time.tv_usec = 0; +#endif /* slightly hacky way to convert timestamptz into integers */ TimestampDifference(0, port->SessionStartTime, &secs, &usecs); srandom((unsigned int) (MyProcPid ^ (usecs << 12) ^ secs)); @@ -4627,10 +4675,17 @@ SubPostmasterMain(int argc, char *argv[]) /* Setup essential subsystems (to ensure elog() behaves sanely) */ InitializeGUCOptions(); + /* Check we got appropriate args */ + if (argc < 3) + elog(FATAL, "invalid subpostmaster invocation"); + /* Read in the variables file */ memset(&port, 0, sizeof(Port)); read_backend_variables(argv[2], &port); + /* Close the postmaster's sockets (as soon as we know them) */ + ClosePostmasterPorts(strcmp(argv[1], "--forklog") == 0); + /* * Set reference point for stack-depth checking */ @@ -4648,15 +4703,21 @@ SubPostmasterMain(int argc, char *argv[]) errmsg("out of memory"))); #endif - /* Check we got appropriate args */ - if (argc < 3) - elog(FATAL, "invalid subpostmaster invocation"); - /* * If appropriate, physically re-attach to shared memory segment. We want * to do this before going any further to ensure that we can attach at the * same address the postmaster used. On the other hand, if we choose not * to re-attach, we may have other cleanup to do. + * + * If testing EXEC_BACKEND on Linux, you should run this as root before + * starting the postmaster: + * + * echo 0 >/proc/sys/kernel/randomize_va_space + * + * This prevents using randomized stack and code addresses that cause the + * child process's memory map to be different from the parent's, making it + * sometimes impossible to attach to shared memory at the desired address. + * Return the setting to its old value (usually '1' or '2') when finished. */ if (strcmp(argv[1], "--forkbackend") == 0 || strcmp(argv[1], "--forkavlauncher") == 0 || @@ -4702,20 +4763,27 @@ SubPostmasterMain(int argc, char *argv[]) { Assert(argc == 3); /* shouldn't be any more args */ - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - /* * Need to reinitialize the SSL library in the backend, since the * context structures contain function pointers and cannot be passed * through the parameter file. * + * If for some reason reload fails (maybe the user installed broken + * key files), soldier on without SSL; that's better than all + * connections becoming impossible. + * * XXX should we do this in all child processes? For the moment it's * enough to do it in backend children. */ #ifdef USE_SSL if (EnableSSL) - secure_initialize(); + { + if (secure_initialize(false) == 0) + LoadedSSL = true; + else + ereport(LOG, + (errmsg("SSL configuration could not be loaded in child process"))); + } #endif /* @@ -4735,17 +4803,7 @@ SubPostmasterMain(int argc, char *argv[]) /* Need a PGPROC to run CreateSharedMemoryAndSemaphores */ InitProcess(); - /* - * Attach process to shared data structures. If testing EXEC_BACKEND - * on Linux, you must run this as root before starting the postmaster: - * - * echo 0 >/proc/sys/kernel/randomize_va_space - * - * This prevents a randomized stack base address that causes child - * shared memory to be at a different address than the parent, making - * it impossible to attached to shared memory. Return the value to - * '1' when finished. - */ + /* Attach process to shared data structures */ CreateSharedMemoryAndSemaphores(false, 0); /* And run the backend */ @@ -4753,9 +4811,6 @@ SubPostmasterMain(int argc, char *argv[]) } if (strcmp(argv[1], "--forkboot") == 0) { - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - /* Restore basic shared memory pointers */ InitShmemAccess(UsedShmemSegAddr); @@ -4769,9 +4824,6 @@ SubPostmasterMain(int argc, char *argv[]) } if (strcmp(argv[1], "--forkavlauncher") == 0) { - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - /* Restore basic shared memory pointers */ InitShmemAccess(UsedShmemSegAddr); @@ -4785,9 +4837,6 @@ SubPostmasterMain(int argc, char *argv[]) } if (strcmp(argv[1], "--forkavworker") == 0) { - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - /* Restore basic shared memory pointers */ InitShmemAccess(UsedShmemSegAddr); @@ -4806,9 +4855,6 @@ SubPostmasterMain(int argc, char *argv[]) /* do this as early as possible; in particular, before InitProcess() */ IsBackgroundWorker = true; - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - /* Restore basic shared memory pointers */ InitShmemAccess(UsedShmemSegAddr); @@ -4826,27 +4872,18 @@ SubPostmasterMain(int argc, char *argv[]) } if (strcmp(argv[1], "--forkarch") == 0) { - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - /* Do not want to attach to shared memory */ PgArchiverMain(argc, argv); /* does not return */ } if (strcmp(argv[1], "--forkcol") == 0) { - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - /* Do not want to attach to shared memory */ PgstatCollectorMain(argc, argv); /* does not return */ } if (strcmp(argv[1], "--forklog") == 0) { - /* Close the postmaster's sockets */ - ClosePostmasterPorts(true); - /* Do not want to attach to shared memory */ SysLoggerMain(argc, argv); /* does not return */ @@ -5080,61 +5117,42 @@ StartupPacketTimeoutHandler(void) /* - * RandomSalt + * Generate a random cancel key. */ -static void -RandomSalt(char *md5Salt) +static bool +RandomCancelKey(int32 *cancel_key) { - long rand; - +#ifdef HAVE_STRONG_RANDOM + return pg_strong_random((char *) cancel_key, sizeof(int32)); +#else /* - * We use % 255, sacrificing one possible byte value, so as to ensure that - * all bits of the random() value participate in the result. While at it, - * add one to avoid generating any null bytes. + * If built with --disable-strong-random, use plain old erand48. + * + * We cannot use pg_backend_random() in postmaster, because it stores + * its state in shared memory. */ - rand = PostmasterRandom(); - md5Salt[0] = (rand % 255) + 1; - rand = PostmasterRandom(); - md5Salt[1] = (rand % 255) + 1; - rand = PostmasterRandom(); - md5Salt[2] = (rand % 255) + 1; - rand = PostmasterRandom(); - md5Salt[3] = (rand % 255) + 1; -} + static unsigned short seed[3]; -/* - * PostmasterRandom - */ -static long -PostmasterRandom(void) -{ /* * Select a random seed at the time of first receiving a request. */ if (random_seed == 0) { - do - { - struct timeval random_stop_time; + struct timeval random_stop_time; - gettimeofday(&random_stop_time, NULL); + gettimeofday(&random_stop_time, NULL); - /* - * We are not sure how much precision is in tv_usec, so we swap - * the high and low 16 bits of 'random_stop_time' and XOR them - * with 'random_start_time'. On the off chance that the result is - * 0, we loop until it isn't. - */ - random_seed = random_start_time.tv_usec ^ - ((random_stop_time.tv_usec << 16) | - ((random_stop_time.tv_usec >> 16) & 0xffff)); - } - while (random_seed == 0); + seed[0] = (unsigned short) random_start_time.tv_usec; + seed[1] = (unsigned short) (random_stop_time.tv_usec) ^ (random_start_time.tv_usec >> 16); + seed[2] = (unsigned short) (random_stop_time.tv_usec >> 16); - srandom(random_seed); + random_seed = 1; } - return random(); + *cancel_key = pg_jrand48(seed); + + return true; +#endif } /* @@ -5305,16 +5323,23 @@ StartAutovacuumWorker(void) */ if (canAcceptConnections() == CAC_OK) { + /* + * Compute the cancel key that will be assigned to this session. + * We probably don't need cancel keys for autovac workers, but + * we'd better have something random in the field to prevent + * unfriendly people from sending cancels to them. + */ + if (!RandomCancelKey(&MyCancelKey)) + { + ereport(LOG, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("could not generate random cancel key"))); + return; + } + bn = (Backend *) malloc(sizeof(Backend)); if (bn) { - /* - * Compute the cancel key that will be assigned to this session. - * We probably don't need cancel keys for autovac workers, but - * we'd better have something random in the field to prevent - * unfriendly people from sending cancels to them. - */ - MyCancelKey = PostmasterRandom(); bn->cancel_key = MyCancelKey; /* Autovac workers are not dead_end and need a child slot */ @@ -5602,8 +5627,25 @@ bgworker_should_start_now(BgWorkerStartTime start_time) static bool assign_backendlist_entry(RegisteredBgWorker *rw) { - Backend *bn = malloc(sizeof(Backend)); + Backend *bn; + + /* + * Compute the cancel key that will be assigned to this session. We + * probably don't need cancel keys for background workers, but we'd better + * have something random in the field to prevent unfriendly people from + * sending cancels to them. + */ + if (!RandomCancelKey(&MyCancelKey)) + { + ereport(LOG, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("could not generate random cancel key"))); + + rw->rw_crashed_at = GetCurrentTimestamp(); + return false; + } + bn = malloc(sizeof(Backend)); if (bn == NULL) { ereport(LOG, @@ -5620,15 +5662,7 @@ assign_backendlist_entry(RegisteredBgWorker *rw) return false; } - /* - * Compute the cancel key that will be assigned to this session. We - * probably don't need cancel keys for background workers, but we'd better - * have something random in the field to prevent unfriendly people from - * sending cancels to them. - */ - MyCancelKey = PostmasterRandom(); bn->cancel_key = MyCancelKey; - bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot(); bn->bkend_type = BACKEND_TYPE_BGWORKER; bn->dead_end = false; diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c index a7ae7e3bda..b172b5e5d7 100644 --- a/src/backend/postmaster/startup.c +++ b/src/backend/postmaster/startup.c @@ -9,7 +9,7 @@ * though.) * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c index e7e488a236..13a03014eb 100644 --- a/src/backend/postmaster/syslogger.c +++ b/src/backend/postmaster/syslogger.c @@ -13,7 +13,7 @@ * * Author: Andreas Pflug * - * Copyright (c) 2004-2016, PostgreSQL Global Development Group + * Copyright (c) 2004-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -35,6 +35,7 @@ #include "libpq/pqsignal.h" #include "miscadmin.h" #include "nodes/pg_list.h" +#include "pgstat.h" #include "pgtime.h" #include "postmaster/fork_process.h" #include "postmaster/postmaster.h" @@ -424,7 +425,8 @@ SysLoggerMain(int argc, char *argv[]) rc = WaitLatchOrSocket(MyLatch, WL_LATCH_SET | WL_SOCKET_READABLE | cur_flags, syslogPipe[0], - cur_timeout); + cur_timeout, + WAIT_EVENT_SYSLOGGER_MAIN); if (rc & WL_SOCKET_READABLE) { @@ -475,7 +477,8 @@ SysLoggerMain(int argc, char *argv[]) (void) WaitLatch(MyLatch, WL_LATCH_SET | cur_flags, - cur_timeout); + cur_timeout, + WAIT_EVENT_SYSLOGGER_MAIN); EnterCriticalSection(&sysloggerSection); #endif /* WIN32 */ diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c index 228190a836..a575d8f953 100644 --- a/src/backend/postmaster/walwriter.c +++ b/src/backend/postmaster/walwriter.c @@ -31,7 +31,7 @@ * should be killed by SIGQUIT and then a recovery cycle started. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -50,6 +50,7 @@ #include "pgstat.h" #include "postmaster/walwriter.h" #include "storage/bufmgr.h" +#include "storage/condition_variable.h" #include "storage/fd.h" #include "storage/ipc.h" #include "storage/lwlock.h" @@ -142,9 +143,7 @@ WalWriterMain(void) */ walwriter_context = AllocSetContextCreate(TopMemoryContext, "Wal Writer", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); MemoryContextSwitchTo(walwriter_context); /* @@ -169,6 +168,7 @@ WalWriterMain(void) * about in walwriter, but we do have LWLocks, and perhaps buffers? */ LWLockReleaseAll(); + ConditionVariableCancelSleep(); pgstat_report_wait_end(); AbortBufferIO(); UnlockBuffers(); @@ -292,7 +292,8 @@ WalWriterMain(void) rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - cur_timeout); + cur_timeout, + WAIT_EVENT_WAL_WRITER_MAIN); /* * Emergency bailout if postmaster has died. This is to avoid the diff --git a/src/backend/regex/README b/src/backend/regex/README index 6c9f48315e..f08aab69e3 100644 --- a/src/backend/regex/README +++ b/src/backend/regex/README @@ -27,13 +27,14 @@ and similarly additional source files rege_*.c that are #include'd in regexec. This was done to avoid exposing internal symbols globally; all functions not meant to be part of the library API are static. -(Actually the above is a lie in one respect: there is one more global -symbol, pg_set_regex_collation in regcomp. It is not meant to be part of -the API, but it has to be global because both regcomp and regexec call it. -It'd be better to get rid of that, as well as the static variables it -sets, in favor of keeping the needed locale state in the regex structs. -We have not done this yet for lack of a design for how to add -application-specific state to the structs.) +(Actually the above is a lie in one respect: there are two more global +symbols, pg_set_regex_collation and pg_reg_getcolor in regcomp. These are +not meant to be part of the API, but they have to be global because both +regcomp and regexec call them. It'd be better to get rid of +pg_set_regex_collation, as well as the static variables it sets, in favor of +keeping the needed locale state in the regex structs. We have not done this +yet for lack of a design for how to add application-specific state to the +structs.) What's where in src/backend/regex/: @@ -274,28 +275,65 @@ colors: an existing color has to be subdivided. The last two of these are handled with the "struct colordesc" array and -the "colorchain" links in NFA arc structs. The color map proper (that -is, the per-character lookup array) is handled as a multi-level tree, -with each tree level indexed by one byte of a character's value. The -code arranges to not have more than one copy of bottom-level tree pages -that are all-the-same-color. - -Unfortunately, this design does not seem terribly efficient for common -cases such as a tree in which all Unicode letters are colored the same, -because there aren't that many places where we get a whole page all the -same color, except at the end of the map. (It also strikes me that given -PG's current restrictions on the range of Unicode values, we could use a -3-level rather than 4-level tree; but there's not provision for that in -regguts.h at the moment.) - -A bigger problem is that it just doesn't seem very reasonable to have to -consider each Unicode letter separately at regex parse time for a regex -such as "\w"; more than likely, a huge percentage of those codes will -never be seen at runtime. We need to fix things so that locale-based -character classes are somehow processed "symbolically" without making a -full expansion of their contents at parse time. This would mean that we'd -have to be ready to call iswalpha() at runtime, but if that only happens -for high-code-value characters, it shouldn't be a big performance hit. +the "colorchain" links in NFA arc structs. + +Ideally, we'd do the first two operations using a simple linear array +storing the current color assignment for each character code. +Unfortunately, that's not terribly workable for large charsets such as +Unicode. Our solution is to divide the color map into two parts. A simple +linear array is used for character codes up to MAX_SIMPLE_CHR, which can be +chosen large enough to include all popular characters (so that the +significantly-slower code paths about to be described are seldom invoked). +Characters above that need be considered at compile time only if they +appear explicitly in the regex pattern. We store each such mentioned +character or character range as an entry in the "colormaprange" array in +the colormap. (Overlapping ranges are split into unique subranges, so that +each range in the finished list needs only a single color that describes +all its characters.) When mapping a character above MAX_SIMPLE_CHR to a +color at runtime, we search this list of ranges explicitly. + +That's still not quite enough, though, because of locale-dependent +character classes such as [[:alpha:]]. In Unicode locales these classes +may have thousands of entries that are above MAX_SIMPLE_CHR, and we +certainly don't want to be searching large colormaprange arrays at runtime. +Nor do we even want to spend the time to initialize cvec structures that +exhaustively describe all of those characters. Our solution is to compute +exact per-character colors at regex compile time only up to MAX_SIMPLE_CHR. +For characters above that, we apply the or lookup +functions at runtime for each locale-dependent character class used in the +regex pattern, constructing a bitmap that describes which classes the +runtime character belongs to. The per-character-range data structure +mentioned above actually holds, for each range, a separate color entry +for each possible combination of character class properties. That is, +the color map for characters above MAX_SIMPLE_CHR is really a 2-D array, +whose rows correspond to high characters or character ranges that are +explicitly mentioned in the regex pattern, and whose columns correspond +to sets of the locale-dependent character classes that are used in the +regex. + +As an example, given the pattern '\w\u1234[\U0001D100-\U0001D1FF]' +(and supposing that MAX_SIMPLE_CHR is less than 0x1234), we will need +a high color map with three rows. One row is for the single character +U+1234 (represented as a single-element range), one is for the range +U+1D100..U+1D1FF, and the other row represents all remaining high +characters. The color map has two columns, one for characters that +satisfy iswalnum() and one for those that don't. + +We build this color map in parallel with scanning the regex. Each time +we detect a new explicit high character (or range) or a locale-dependent +character class, we split existing entry(s) in the high color map so that +characters we need to be able to distinguish will have distinct entries +that can be given separate colors. Often, though, single entries in the +high color map will represent very large sets of characters. + +If there are both explicit high characters/ranges and locale-dependent +character classes, we may have entries in the high color map array that +have non-WHITE colors but don't actually represent any real characters. +(For example, in a row representing a singleton range, only one of the +columns could possibly be a live entry; it's the one matching the actual +locale properties for that single character.) We don't currently make +any effort to reclaim such colors. In principle it could be done, but +it's not clear that it's worth the trouble. Detailed semantics of an NFA diff --git a/src/backend/regex/regc_color.c b/src/backend/regex/regc_color.c index c495cee300..4b72894ad3 100644 --- a/src/backend/regex/regc_color.c +++ b/src/backend/regex/regc_color.c @@ -49,10 +49,6 @@ static void initcm(struct vars * v, struct colormap * cm) { - int i; - int j; - union tree *t; - union tree *nextt; struct colordesc *cd; cm->magic = CMMAGIC; @@ -64,24 +60,40 @@ initcm(struct vars * v, cm->free = 0; cd = cm->cd; /* cm->cd[WHITE] */ + cd->nschrs = MAX_SIMPLE_CHR - CHR_MIN + 1; + cd->nuchrs = 1; cd->sub = NOSUB; cd->arcs = NULL; cd->firstchr = CHR_MIN; - cd->nchrs = CHR_MAX - CHR_MIN + 1; cd->flags = 0; - /* upper levels of tree */ - for (t = &cm->tree[0], j = NBYTS - 1; j > 0; t = nextt, j--) + cm->locolormap = (color *) + MALLOC((MAX_SIMPLE_CHR - CHR_MIN + 1) * sizeof(color)); + if (cm->locolormap == NULL) { - nextt = t + 1; - for (i = BYTTAB - 1; i >= 0; i--) - t->tptr[i] = nextt; + CERR(REG_ESPACE); + cm->cmranges = NULL; /* prevent failure during freecm */ + cm->hicolormap = NULL; + return; } - /* bottom level is solid white */ - t = &cm->tree[NBYTS - 1]; - for (i = BYTTAB - 1; i >= 0; i--) - t->tcolor[i] = WHITE; - cd->block = t; + /* this memset relies on WHITE being zero: */ + memset(cm->locolormap, WHITE, + (MAX_SIMPLE_CHR - CHR_MIN + 1) * sizeof(color)); + + memset(cm->classbits, 0, sizeof(cm->classbits)); + cm->numcmranges = 0; + cm->cmranges = NULL; + cm->maxarrayrows = 4; /* arbitrary initial allocation */ + cm->hiarrayrows = 1; /* but we have only one row/col initially */ + cm->hiarraycols = 1; + cm->hicolormap = (color *) MALLOC(cm->maxarrayrows * sizeof(color)); + if (cm->hicolormap == NULL) + { + CERR(REG_ESPACE); + return; + } + /* initialize the "all other characters" row to WHITE */ + cm->hicolormap[0] = WHITE; } /* @@ -90,117 +102,67 @@ initcm(struct vars * v, static void freecm(struct colormap * cm) { - size_t i; - union tree *cb; - cm->magic = 0; - if (NBYTS > 1) - cmtreefree(cm, cm->tree, 0); - for (i = 1; i <= cm->max; i++) /* skip WHITE */ - if (!UNUSEDCOLOR(&cm->cd[i])) - { - cb = cm->cd[i].block; - if (cb != NULL) - FREE(cb); - } if (cm->cd != cm->cdspace) FREE(cm->cd); + if (cm->locolormap != NULL) + FREE(cm->locolormap); + if (cm->cmranges != NULL) + FREE(cm->cmranges); + if (cm->hicolormap != NULL) + FREE(cm->hicolormap); } /* - * cmtreefree - free a non-terminal part of a colormap tree + * pg_reg_getcolor - slow case of GETCOLOR() */ -static void -cmtreefree(struct colormap * cm, - union tree * tree, - int level) /* level number (top == 0) of this block */ +color +pg_reg_getcolor(struct colormap * cm, chr c) { - int i; - union tree *t; - union tree *fillt = &cm->tree[level + 1]; - union tree *cb; - - assert(level < NBYTS - 1); /* this level has pointers */ - for (i = BYTTAB - 1; i >= 0; i--) + int rownum, + colnum, + low, + high; + + /* Should not be used for chrs in the locolormap */ + assert(c > MAX_SIMPLE_CHR); + + /* + * Find which row it's in. The colormapranges are in order, so we can use + * binary search. + */ + rownum = 0; /* if no match, use array row zero */ + low = 0; + high = cm->numcmranges; + while (low < high) { - t = tree->tptr[i]; - assert(t != NULL); - if (t != fillt) + int middle = low + (high - low) / 2; + const colormaprange *cmr = &cm->cmranges[middle]; + + if (c < cmr->cmin) + high = middle; + else if (c > cmr->cmax) + low = middle + 1; + else { - if (level < NBYTS - 2) - { /* more pointer blocks below */ - cmtreefree(cm, t, level + 1); - FREE(t); - } - else - { /* color block below */ - cb = cm->cd[t->tcolor[0]].block; - if (t != cb) /* not a solid block */ - FREE(t); - } + rownum = cmr->rownum; /* found a match */ + break; } } -} -/* - * setcolor - set the color of a character in a colormap - */ -static color /* previous color */ -setcolor(struct colormap * cm, - chr c, - pcolor co) -{ - uchr uc = c; - int shift; - int level; - int b; - int bottom; - union tree *t; - union tree *newt; - union tree *fillt; - union tree *lastt; - union tree *cb; - color prev; - - assert(cm->magic == CMMAGIC); - if (CISERR() || co == COLORLESS) - return COLORLESS; - - t = cm->tree; - for (level = 0, shift = BYTBITS * (NBYTS - 1); shift > 0; - level++, shift -= BYTBITS) - { - b = (uc >> shift) & BYTMASK; - lastt = t; - t = lastt->tptr[b]; - assert(t != NULL); - fillt = &cm->tree[level + 1]; - bottom = (shift <= BYTBITS) ? 1 : 0; - cb = (bottom) ? cm->cd[t->tcolor[0]].block : fillt; - if (t == fillt || t == cb) - { /* must allocate a new block */ - newt = (union tree *) MALLOC((bottom) ? - sizeof(struct colors) : sizeof(struct ptrs)); - if (newt == NULL) - { - CERR(REG_ESPACE); - return COLORLESS; - } - if (bottom) - memcpy(VS(newt->tcolor), VS(t->tcolor), - BYTTAB * sizeof(color)); - else - memcpy(VS(newt->tptr), VS(t->tptr), - BYTTAB * sizeof(union tree *)); - t = newt; - lastt->tptr[b] = t; - } + /* + * Find which column it's in --- this is all locale-dependent. + */ + if (cm->hiarraycols > 1) + { + colnum = cclass_column_index(cm, c); + return cm->hicolormap[rownum * cm->hiarraycols + colnum]; + } + else + { + /* fast path if no relevant cclasses */ + return cm->hicolormap[rownum]; } - - b = uc & BYTMASK; - prev = t->tcolor[b]; - t->tcolor[b] = (color) co; - return prev; } /* @@ -216,7 +178,7 @@ maxcolor(struct colormap * cm) } /* - * newcolor - find a new color (must be subject of setcolor at once) + * newcolor - find a new color (must be assigned at once) * Beware: may relocate the colordescs. */ static color /* COLORLESS for error */ @@ -278,12 +240,12 @@ newcolor(struct colormap * cm) cd = &cm->cd[cm->max]; } - cd->nchrs = 0; + cd->nschrs = 0; + cd->nuchrs = 0; cd->sub = NOSUB; cd->arcs = NULL; cd->firstchr = CHR_MIN; /* in case never set otherwise */ cd->flags = 0; - cd->block = NULL; return (color) (cd - cm->cd); } @@ -293,7 +255,7 @@ newcolor(struct colormap * cm) */ static void freecolor(struct colormap * cm, - pcolor co) + color co) { struct colordesc *cd = &cm->cd[co]; color pco, @@ -305,13 +267,9 @@ freecolor(struct colormap * cm, assert(cd->arcs == NULL); assert(cd->sub == NOSUB); - assert(cd->nchrs == 0); + assert(cd->nschrs == 0); + assert(cd->nuchrs == 0); cd->flags = FREECOL; - if (cd->block != NULL) - { - FREE(cd->block); - cd->block = NULL; /* just paranoia */ - } if ((size_t) co == cm->max) { @@ -354,17 +312,25 @@ static color pseudocolor(struct colormap * cm) { color co; + struct colordesc *cd; co = newcolor(cm); if (CISERR()) return COLORLESS; - cm->cd[co].nchrs = 1; - cm->cd[co].flags = PSEUDO; + cd = &cm->cd[co]; + cd->nschrs = 0; + cd->nuchrs = 1; /* pretend it is in the upper map */ + cd->sub = NOSUB; + cd->arcs = NULL; + cd->firstchr = CHR_MIN; + cd->flags = PSEUDO; return co; } /* * subcolor - allocate a new subcolor (if necessary) to this chr + * + * This works only for chrs that map into the low color map. */ static color subcolor(struct colormap * cm, chr c) @@ -372,7 +338,9 @@ subcolor(struct colormap * cm, chr c) color co; /* current color of c */ color sco; /* new subcolor */ - co = GETCOLOR(cm, c); + assert(c <= MAX_SIMPLE_CHR); + + co = cm->locolormap[c - CHR_MIN]; sco = newsub(cm, co); if (CISERR()) return COLORLESS; @@ -380,11 +348,37 @@ subcolor(struct colormap * cm, chr c) if (co == sco) /* already in an open subcolor */ return co; /* rest is redundant */ - cm->cd[co].nchrs--; - if (cm->cd[sco].nchrs == 0) + cm->cd[co].nschrs--; + if (cm->cd[sco].nschrs == 0) cm->cd[sco].firstchr = c; - cm->cd[sco].nchrs++; - setcolor(cm, c, sco); + cm->cd[sco].nschrs++; + cm->locolormap[c - CHR_MIN] = sco; + return sco; +} + +/* + * subcolorhi - allocate a new subcolor (if necessary) to this colormap entry + * + * This is the same processing as subcolor(), but for entries in the high + * colormap, which do not necessarily correspond to exactly one chr code. + */ +static color +subcolorhi(struct colormap * cm, color *pco) +{ + color co; /* current color of entry */ + color sco; /* new subcolor */ + + co = *pco; + sco = newsub(cm, co); + if (CISERR()) + return COLORLESS; + assert(sco != COLORLESS); + + if (co == sco) /* already in an open subcolor */ + return co; /* rest is redundant */ + cm->cd[co].nuchrs--; + cm->cd[sco].nuchrs++; + *pco = sco; return sco; } @@ -393,14 +387,15 @@ subcolor(struct colormap * cm, chr c) */ static color newsub(struct colormap * cm, - pcolor co) + color co) { color sco; /* new subcolor */ sco = cm->cd[co].sub; if (sco == NOSUB) { /* color has no open subcolor */ - if (cm->cd[co].nchrs == 1) /* optimization */ + /* optimization: singly-referenced color need not be subcolored */ + if ((cm->cd[co].nschrs + cm->cd[co].nuchrs) == 1) return co; sco = newcolor(cm); /* must create subcolor */ if (sco == COLORLESS) @@ -417,136 +412,500 @@ newsub(struct colormap * cm, } /* - * subrange - allocate new subcolors to this range of chrs, fill in arcs + * newhicolorrow - get a new row in the hicolormap, cloning it from oldrow + * + * Returns array index of new row. Note the array might move. */ -static void -subrange(struct vars * v, - chr from, - chr to, - struct state * lp, - struct state * rp) +static int +newhicolorrow(struct colormap * cm, + int oldrow) { - uchr uf; + int newrow = cm->hiarrayrows; + color *newrowptr; int i; - assert(from <= to); + /* Assign a fresh array row index, enlarging storage if needed */ + if (newrow >= cm->maxarrayrows) + { + color *newarray; + + if (cm->maxarrayrows >= INT_MAX / (cm->hiarraycols * 2)) + { + CERR(REG_ESPACE); + return 0; + } + newarray = (color *) REALLOC(cm->hicolormap, + cm->maxarrayrows * 2 * + cm->hiarraycols * sizeof(color)); + if (newarray == NULL) + { + CERR(REG_ESPACE); + return 0; + } + cm->hicolormap = newarray; + cm->maxarrayrows *= 2; + } + cm->hiarrayrows++; + + /* Copy old row data */ + newrowptr = &cm->hicolormap[newrow * cm->hiarraycols]; + memcpy(newrowptr, + &cm->hicolormap[oldrow * cm->hiarraycols], + cm->hiarraycols * sizeof(color)); + + /* Increase color reference counts to reflect new colormap entries */ + for (i = 0; i < cm->hiarraycols; i++) + cm->cd[newrowptr[i]].nuchrs++; - /* first, align "from" on a tree-block boundary */ - uf = (uchr) from; - i = (int) (((uf + BYTTAB - 1) & (uchr) ~BYTMASK) - uf); - for (; from <= to && i > 0; i--, from++) - newarc(v->nfa, PLAIN, subcolor(v->cm, from), lp, rp); - if (from > to) /* didn't reach a boundary */ + return newrow; +} + +/* + * newhicolorcols - create a new set of columns in the high colormap + * + * Essentially, extends the 2-D array to the right with a copy of itself. + */ +static void +newhicolorcols(struct colormap * cm) +{ + color *newarray; + int r, + c; + + if (cm->hiarraycols >= INT_MAX / (cm->maxarrayrows * 2)) + { + CERR(REG_ESPACE); return; + } + newarray = (color *) REALLOC(cm->hicolormap, + cm->maxarrayrows * + cm->hiarraycols * 2 * sizeof(color)); + if (newarray == NULL) + { + CERR(REG_ESPACE); + return; + } + cm->hicolormap = newarray; - /* deal with whole blocks */ - for (; to - from >= BYTTAB; from += BYTTAB) - subblock(v, from, lp, rp); + /* Duplicate existing columns to the right, and increase ref counts */ + /* Must work backwards in the array because we realloc'd in place */ + for (r = cm->hiarrayrows - 1; r >= 0; r--) + { + color *oldrowptr = &newarray[r * cm->hiarraycols]; + color *newrowptr = &newarray[r * cm->hiarraycols * 2]; + color *newrowptr2 = newrowptr + cm->hiarraycols; + + for (c = 0; c < cm->hiarraycols; c++) + { + color co = oldrowptr[c]; - /* clean up any remaining partial table */ - for (; from <= to; from++) - newarc(v->nfa, PLAIN, subcolor(v->cm, from), lp, rp); + newrowptr[c] = newrowptr2[c] = co; + cm->cd[co].nuchrs++; + } + } + + cm->hiarraycols *= 2; } /* - * subblock - allocate new subcolors for one tree block of chrs, fill in arcs + * subcolorcvec - allocate new subcolors to cvec members, fill in arcs * - * Note: subcolors that are created during execution of this function - * will not be given a useful value of firstchr; it'll be left as CHR_MIN. - * For the current usage of firstchr in pg_regprefix, this does not matter - * because such subcolors won't occur in the common prefix of a regex. + * For each chr "c" represented by the cvec, do the equivalent of + * newarc(v->nfa, PLAIN, subcolor(v->cm, c), lp, rp); + * + * Note that in typical cases, many of the subcolors are the same. + * While newarc() would discard duplicate arc requests, we can save + * some cycles by not calling it repetitively to begin with. This is + * mechanized with the "lastsubcolor" state variable. */ static void -subblock(struct vars * v, - chr start, /* first of BYTTAB chrs */ - struct state * lp, - struct state * rp) +subcolorcvec(struct vars * v, + struct cvec * cv, + struct state * lp, + struct state * rp) { - uchr uc = start; struct colormap *cm = v->cm; - int shift; - int level; + color lastsubcolor = COLORLESS; + chr ch, + from, + to; + const chr *p; int i; - int b; - union tree *t; - union tree *cb; - union tree *fillt; - union tree *lastt; - int previ; - int ndone; - color co; - color sco; - assert((uc % BYTTAB) == 0); - - /* find its color block, making new pointer blocks as needed */ - t = cm->tree; - fillt = NULL; - for (level = 0, shift = BYTBITS * (NBYTS - 1); shift > 0; - level++, shift -= BYTBITS) - { - b = (uc >> shift) & BYTMASK; - lastt = t; - t = lastt->tptr[b]; - assert(t != NULL); - fillt = &cm->tree[level + 1]; - if (t == fillt && shift > BYTBITS) - { /* need new ptr block */ - t = (union tree *) MALLOC(sizeof(struct ptrs)); - if (t == NULL) + /* ordinary characters */ + for (p = cv->chrs, i = cv->nchrs; i > 0; p++, i--) + { + ch = *p; + subcoloronechr(v, ch, lp, rp, &lastsubcolor); + NOERR(); + } + + /* and the ranges */ + for (p = cv->ranges, i = cv->nranges; i > 0; p += 2, i--) + { + from = *p; + to = *(p + 1); + if (from <= MAX_SIMPLE_CHR) + { + /* deal with simple chars one at a time */ + chr lim = (to <= MAX_SIMPLE_CHR) ? to : MAX_SIMPLE_CHR; + + while (from <= lim) { - CERR(REG_ESPACE); - return; + color sco = subcolor(cm, from); + + NOERR(); + if (sco != lastsubcolor) + { + newarc(v->nfa, PLAIN, sco, lp, rp); + NOERR(); + lastsubcolor = sco; + } + from++; } - memcpy(VS(t->tptr), VS(fillt->tptr), - BYTTAB * sizeof(union tree *)); - lastt->tptr[b] = t; } + /* deal with any part of the range that's above MAX_SIMPLE_CHR */ + if (from < to) + subcoloronerange(v, from, to, lp, rp, &lastsubcolor); + else if (from == to) + subcoloronechr(v, from, lp, rp, &lastsubcolor); + NOERR(); } - /* special cases: fill block or solid block */ - co = t->tcolor[0]; - cb = cm->cd[co].block; - if (t == fillt || t == cb) + /* and deal with cclass if any */ + if (cv->cclasscode >= 0) { - /* either way, we want a subcolor solid block */ - sco = newsub(cm, co); - t = cm->cd[sco].block; - if (t == NULL) - { /* must set it up */ - t = (union tree *) MALLOC(sizeof(struct colors)); - if (t == NULL) + int classbit; + color *pco; + int r, + c; + + /* Enlarge array if we don't have a column bit assignment for cclass */ + if (cm->classbits[cv->cclasscode] == 0) + { + cm->classbits[cv->cclasscode] = cm->hiarraycols; + newhicolorcols(cm); + NOERR(); + } + /* Apply subcolorhi() and make arc for each entry in relevant cols */ + classbit = cm->classbits[cv->cclasscode]; + pco = cm->hicolormap; + for (r = 0; r < cm->hiarrayrows; r++) + { + for (c = 0; c < cm->hiarraycols; c++) { - CERR(REG_ESPACE); - return; + if (c & classbit) + { + color sco = subcolorhi(cm, pco); + + NOERR(); + /* add the arc if needed */ + if (sco != lastsubcolor) + { + newarc(v->nfa, PLAIN, sco, lp, rp); + NOERR(); + lastsubcolor = sco; + } + } + pco++; } - for (i = 0; i < BYTTAB; i++) - t->tcolor[i] = sco; - cm->cd[sco].block = t; } - /* find loop must have run at least once */ - lastt->tptr[b] = t; - newarc(v->nfa, PLAIN, sco, lp, rp); - cm->cd[co].nchrs -= BYTTAB; - cm->cd[sco].nchrs += BYTTAB; + } +} + +/* + * subcoloronechr - do subcolorcvec's work for a singleton chr + * + * We could just let subcoloronerange do this, but it's a bit more efficient + * if we exploit the single-chr case. Also, callers find it useful for this + * to be able to handle both low and high chr codes. + */ +static void +subcoloronechr(struct vars * v, + chr ch, + struct state * lp, + struct state * rp, + color *lastsubcolor) +{ + struct colormap *cm = v->cm; + colormaprange *newranges; + int numnewranges; + colormaprange *oldrange; + int oldrangen; + int newrow; + + /* Easy case for low chr codes */ + if (ch <= MAX_SIMPLE_CHR) + { + color sco = subcolor(cm, ch); + + NOERR(); + if (sco != *lastsubcolor) + { + newarc(v->nfa, PLAIN, sco, lp, rp); + *lastsubcolor = sco; + } + return; + } + + /* + * Potentially, we could need two more colormapranges than we have now, if + * the given chr is in the middle of some existing range. + */ + newranges = (colormaprange *) + MALLOC((cm->numcmranges + 2) * sizeof(colormaprange)); + if (newranges == NULL) + { + CERR(REG_ESPACE); return; } + numnewranges = 0; - /* general case, a mixed block to be altered */ - i = 0; - while (i < BYTTAB) + /* Ranges before target are unchanged */ + for (oldrange = cm->cmranges, oldrangen = 0; + oldrangen < cm->numcmranges; + oldrange++, oldrangen++) + { + if (oldrange->cmax >= ch) + break; + newranges[numnewranges++] = *oldrange; + } + + /* Match target chr against current range */ + if (oldrangen >= cm->numcmranges || oldrange->cmin > ch) + { + /* chr does not belong to any existing range, make a new one */ + newranges[numnewranges].cmin = ch; + newranges[numnewranges].cmax = ch; + /* row state should be cloned from the "all others" row */ + newranges[numnewranges].rownum = newrow = newhicolorrow(cm, 0); + numnewranges++; + } + else if (oldrange->cmin == oldrange->cmax) + { + /* we have an existing singleton range matching the chr */ + newranges[numnewranges++] = *oldrange; + newrow = oldrange->rownum; + /* we've now fully processed this old range */ + oldrange++, oldrangen++; + } + else { - co = t->tcolor[i]; - sco = newsub(cm, co); - newarc(v->nfa, PLAIN, sco, lp, rp); - previ = i; - do + /* chr is a subset of this existing range, must split it */ + if (ch > oldrange->cmin) + { + /* emit portion of old range before chr */ + newranges[numnewranges].cmin = oldrange->cmin; + newranges[numnewranges].cmax = ch - 1; + newranges[numnewranges].rownum = oldrange->rownum; + numnewranges++; + } + /* emit chr as singleton range, initially cloning from range */ + newranges[numnewranges].cmin = ch; + newranges[numnewranges].cmax = ch; + newranges[numnewranges].rownum = newrow = + newhicolorrow(cm, oldrange->rownum); + numnewranges++; + if (ch < oldrange->cmax) { - t->tcolor[i++] = sco; - } while (i < BYTTAB && t->tcolor[i] == co); - ndone = i - previ; - cm->cd[co].nchrs -= ndone; - cm->cd[sco].nchrs += ndone; + /* emit portion of old range after chr */ + newranges[numnewranges].cmin = ch + 1; + newranges[numnewranges].cmax = oldrange->cmax; + /* must clone the row if we are making two new ranges from old */ + newranges[numnewranges].rownum = + (ch > oldrange->cmin) ? newhicolorrow(cm, oldrange->rownum) : + oldrange->rownum; + numnewranges++; + } + /* we've now fully processed this old range */ + oldrange++, oldrangen++; + } + + /* Update colors in newrow and create arcs as needed */ + subcoloronerow(v, newrow, lp, rp, lastsubcolor); + + /* Ranges after target are unchanged */ + for (; oldrangen < cm->numcmranges; oldrange++, oldrangen++) + { + newranges[numnewranges++] = *oldrange; + } + + /* Assert our original space estimate was adequate */ + assert(numnewranges <= (cm->numcmranges + 2)); + + /* And finally, store back the updated list of ranges */ + if (cm->cmranges != NULL) + FREE(cm->cmranges); + cm->cmranges = newranges; + cm->numcmranges = numnewranges; +} + +/* + * subcoloronerange - do subcolorcvec's work for a high range + */ +static void +subcoloronerange(struct vars * v, + chr from, + chr to, + struct state * lp, + struct state * rp, + color *lastsubcolor) +{ + struct colormap *cm = v->cm; + colormaprange *newranges; + int numnewranges; + colormaprange *oldrange; + int oldrangen; + int newrow; + + /* Caller should take care of non-high-range cases */ + assert(from > MAX_SIMPLE_CHR); + assert(from < to); + + /* + * Potentially, if we have N non-adjacent ranges, we could need as many as + * 2N+1 result ranges (consider case where new range spans 'em all). + */ + newranges = (colormaprange *) + MALLOC((cm->numcmranges * 2 + 1) * sizeof(colormaprange)); + if (newranges == NULL) + { + CERR(REG_ESPACE); + return; + } + numnewranges = 0; + + /* Ranges before target are unchanged */ + for (oldrange = cm->cmranges, oldrangen = 0; + oldrangen < cm->numcmranges; + oldrange++, oldrangen++) + { + if (oldrange->cmax >= from) + break; + newranges[numnewranges++] = *oldrange; + } + + /* + * Deal with ranges that (partially) overlap the target. As we process + * each such range, increase "from" to remove the dealt-with characters + * from the target range. + */ + while (oldrangen < cm->numcmranges && oldrange->cmin <= to) + { + if (from < oldrange->cmin) + { + /* Handle portion of new range that corresponds to no old range */ + newranges[numnewranges].cmin = from; + newranges[numnewranges].cmax = oldrange->cmin - 1; + /* row state should be cloned from the "all others" row */ + newranges[numnewranges].rownum = newrow = newhicolorrow(cm, 0); + numnewranges++; + /* Update colors in newrow and create arcs as needed */ + subcoloronerow(v, newrow, lp, rp, lastsubcolor); + /* We've now fully processed the part of new range before old */ + from = oldrange->cmin; + } + + if (from <= oldrange->cmin && to >= oldrange->cmax) + { + /* old range is fully contained in new, process it in-place */ + newranges[numnewranges++] = *oldrange; + newrow = oldrange->rownum; + from = oldrange->cmax + 1; + } + else + { + /* some part of old range does not overlap new range */ + if (from > oldrange->cmin) + { + /* emit portion of old range before new range */ + newranges[numnewranges].cmin = oldrange->cmin; + newranges[numnewranges].cmax = from - 1; + newranges[numnewranges].rownum = oldrange->rownum; + numnewranges++; + } + /* emit common subrange, initially cloning from old range */ + newranges[numnewranges].cmin = from; + newranges[numnewranges].cmax = + (to < oldrange->cmax) ? to : oldrange->cmax; + newranges[numnewranges].rownum = newrow = + newhicolorrow(cm, oldrange->rownum); + numnewranges++; + if (to < oldrange->cmax) + { + /* emit portion of old range after new range */ + newranges[numnewranges].cmin = to + 1; + newranges[numnewranges].cmax = oldrange->cmax; + /* must clone the row if we are making two new ranges from old */ + newranges[numnewranges].rownum = + (from > oldrange->cmin) ? newhicolorrow(cm, oldrange->rownum) : + oldrange->rownum; + numnewranges++; + } + from = oldrange->cmax + 1; + } + /* Update colors in newrow and create arcs as needed */ + subcoloronerow(v, newrow, lp, rp, lastsubcolor); + /* we've now fully processed this old range */ + oldrange++, oldrangen++; + } + + if (from <= to) + { + /* Handle portion of new range that corresponds to no old range */ + newranges[numnewranges].cmin = from; + newranges[numnewranges].cmax = to; + /* row state should be cloned from the "all others" row */ + newranges[numnewranges].rownum = newrow = newhicolorrow(cm, 0); + numnewranges++; + /* Update colors in newrow and create arcs as needed */ + subcoloronerow(v, newrow, lp, rp, lastsubcolor); + } + + /* Ranges after target are unchanged */ + for (; oldrangen < cm->numcmranges; oldrange++, oldrangen++) + { + newranges[numnewranges++] = *oldrange; + } + + /* Assert our original space estimate was adequate */ + assert(numnewranges <= (cm->numcmranges * 2 + 1)); + + /* And finally, store back the updated list of ranges */ + if (cm->cmranges != NULL) + FREE(cm->cmranges); + cm->cmranges = newranges; + cm->numcmranges = numnewranges; +} + +/* + * subcoloronerow - do subcolorcvec's work for one new row in the high colormap + */ +static void +subcoloronerow(struct vars * v, + int rownum, + struct state * lp, + struct state * rp, + color *lastsubcolor) +{ + struct colormap *cm = v->cm; + color *pco; + int i; + + /* Apply subcolorhi() and make arc for each entry in row */ + pco = &cm->hicolormap[rownum * cm->hiarraycols]; + for (i = 0; i < cm->hiarraycols; pco++, i++) + { + color sco = subcolorhi(cm, pco); + + NOERR(); + /* make the arc if needed */ + if (sco != *lastsubcolor) + { + newarc(v->nfa, PLAIN, sco, lp, rp); + NOERR(); + *lastsubcolor = sco; + } } } @@ -575,12 +934,12 @@ okcolors(struct nfa * nfa, { /* is subcolor, let parent deal with it */ } - else if (cd->nchrs == 0) + else if (cd->nschrs == 0 && cd->nuchrs == 0) { /* parent empty, its arcs change color to subcolor */ cd->sub = NOSUB; scd = &cm->cd[sco]; - assert(scd->nchrs > 0); + assert(scd->nschrs > 0 || scd->nuchrs > 0); assert(scd->sub == sco); scd->sub = NOSUB; while ((a = cd->arcs) != NULL) @@ -597,7 +956,7 @@ okcolors(struct nfa * nfa, /* parent's arcs must gain parallel subcolor arcs */ cd->sub = NOSUB; scd = &cm->cd[sco]; - assert(scd->nchrs > 0); + assert(scd->nschrs > 0 || scd->nuchrs > 0); assert(scd->sub == sco); scd->sub = NOSUB; for (a = cd->arcs; a != NULL; a = a->colorchain) @@ -658,7 +1017,7 @@ static void rainbow(struct nfa * nfa, struct colormap * cm, int type, - pcolor but, /* COLORLESS if no exceptions */ + color but, /* COLORLESS if no exceptions */ struct state * from, struct state * to) { @@ -711,62 +1070,54 @@ dumpcolors(struct colormap * cm, struct colordesc *end; color co; chr c; - char *has; fprintf(f, "max %ld\n", (long) cm->max); - if (NBYTS > 1) - fillcheck(cm, cm->tree, 0, f); end = CDEND(cm); for (cd = cm->cd + 1, co = 1; cd < end; cd++, co++) /* skip 0 */ + { if (!UNUSEDCOLOR(cd)) { - assert(cd->nchrs > 0); - has = (cd->block != NULL) ? "#" : ""; + assert(cd->nschrs > 0 || cd->nuchrs > 0); if (cd->flags & PSEUDO) - fprintf(f, "#%2ld%s(ps): ", (long) co, has); + fprintf(f, "#%2ld(ps): ", (long) co); else - fprintf(f, "#%2ld%s(%2d): ", (long) co, - has, cd->nchrs); + fprintf(f, "#%2ld(%2d): ", (long) co, cd->nschrs + cd->nuchrs); /* * Unfortunately, it's hard to do this next bit more efficiently. - * - * Spencer's original coding has the loop iterating from CHR_MIN - * to CHR_MAX, but that's utterly unusable for 32-bit chr. For - * debugging purposes it seems fine to print only chr codes up to - * 1000 or so. */ - for (c = CHR_MIN; c < 1000; c++) + for (c = CHR_MIN; c <= MAX_SIMPLE_CHR; c++) if (GETCOLOR(cm, c) == co) dumpchr(c, f); fprintf(f, "\n"); } -} - -/* - * fillcheck - check proper filling of a tree - */ -static void -fillcheck(struct colormap * cm, - union tree * tree, - int level, /* level number (top == 0) of this block */ - FILE *f) -{ - int i; - union tree *t; - union tree *fillt = &cm->tree[level + 1]; - - assert(level < NBYTS - 1); /* this level has pointers */ - for (i = BYTTAB - 1; i >= 0; i--) + } + /* dump the high colormap if it contains anything interesting */ + if (cm->hiarrayrows > 1 || cm->hiarraycols > 1) { - t = tree->tptr[i]; - if (t == NULL) - fprintf(f, "NULL found in filled tree!\n"); - else if (t == fillt) + int r, + c; + const color *rowptr; + + fprintf(f, "other:\t"); + for (c = 0; c < cm->hiarraycols; c++) + { + fprintf(f, "\t%ld", (long) cm->hicolormap[c]); + } + fprintf(f, "\n"); + for (r = 0; r < cm->numcmranges; r++) { + dumpchr(cm->cmranges[r].cmin, f); + fprintf(f, ".."); + dumpchr(cm->cmranges[r].cmax, f); + fprintf(f, ":"); + rowptr = &cm->hicolormap[cm->cmranges[r].rownum * cm->hiarraycols]; + for (c = 0; c < cm->hiarraycols; c++) + { + fprintf(f, "\t%ld", (long) rowptr[c]); + } + fprintf(f, "\n"); } - else if (level < NBYTS - 2) /* more pointer blocks below */ - fillcheck(cm, t, level + 1, f); } } diff --git a/src/backend/regex/regc_cvec.c b/src/backend/regex/regc_cvec.c index 921a7d7f92..50b7a4574b 100644 --- a/src/backend/regex/regc_cvec.c +++ b/src/backend/regex/regc_cvec.c @@ -34,7 +34,8 @@ /* * Notes: - * Only (selected) functions in _this_ file should treat chr* as non-constant. + * Only (selected) functions in _this_ file should treat the chr arrays + * of a cvec as non-constant. */ /* @@ -67,6 +68,7 @@ clearcvec(struct cvec * cv) assert(cv != NULL); cv->nchrs = 0; cv->nranges = 0; + cv->cclasscode = -1; return cv; } @@ -78,7 +80,7 @@ addchr(struct cvec * cv, /* character vector */ chr c) /* character to add */ { assert(cv->nchrs < cv->chrspace); - cv->chrs[cv->nchrs++] = (chr) c; + cv->chrs[cv->nchrs++] = c; } /* @@ -90,8 +92,8 @@ addrange(struct cvec * cv, /* character vector */ chr to) /* last character of range */ { assert(cv->nranges < cv->rangespace); - cv->ranges[cv->nranges * 2] = (chr) from; - cv->ranges[cv->nranges * 2 + 1] = (chr) to; + cv->ranges[cv->nranges * 2] = from; + cv->ranges[cv->nranges * 2 + 1] = to; cv->nranges++; } diff --git a/src/backend/regex/regc_lex.c b/src/backend/regex/regc_lex.c index f62ec7dc81..cd34c8ae41 100644 --- a/src/backend/regex/regc_lex.c +++ b/src/backend/regex/regc_lex.c @@ -870,7 +870,7 @@ lexescape(struct vars * v) if (v->now == save || ((int) c > 0 && (int) c <= v->nsubexp)) { NOTE(REG_UBACKREF); - RETV(BACKREF, (chr) c); + RETV(BACKREF, c); } /* oops, doesn't look like it's a backref after all... */ v->now = save; @@ -986,10 +986,8 @@ lexdigits(struct vars * v, */ static int /* 1 normal, 0 failure */ brenext(struct vars * v, - chr pc) + chr c) { - chr c = (chr) pc; - switch (c) { case CHR('*'): @@ -1153,7 +1151,7 @@ chrnamed(struct vars * v, const chr *endp, /* just past end of name */ chr lastresort) /* what to return if name lookup fails */ { - celt c; + chr c; int errsave; int e; struct cvec *cv; @@ -1165,10 +1163,10 @@ chrnamed(struct vars * v, v->err = errsave; if (e != 0) - return (chr) lastresort; + return lastresort; cv = range(v, c, c, 0); if (cv->nchrs == 0) - return (chr) lastresort; + return lastresort; return cv->chrs[0]; } diff --git a/src/backend/regex/regc_locale.c b/src/backend/regex/regc_locale.c index 4fe62921e3..7cb3a40a0c 100644 --- a/src/backend/regex/regc_locale.c +++ b/src/backend/regex/regc_locale.c @@ -349,6 +349,19 @@ static const struct cname } }; +/* + * The following arrays define the valid character class names. + */ +static const char *const classNames[NUM_CCLASSES + 1] = { + "alnum", "alpha", "ascii", "blank", "cntrl", "digit", "graph", + "lower", "print", "punct", "space", "upper", "xdigit", NULL +}; + +enum classes +{ + CC_ALNUM, CC_ALPHA, CC_ASCII, CC_BLANK, CC_CNTRL, CC_DIGIT, CC_GRAPH, + CC_LOWER, CC_PRINT, CC_PUNCT, CC_SPACE, CC_UPPER, CC_XDIGIT +}; /* * We do not use the hard-wired Unicode classification tables that Tcl does. @@ -361,9 +374,9 @@ static const struct cname /* - * element - map collating-element name to celt + * element - map collating-element name to chr */ -static celt +static chr element(struct vars * v, /* context */ const chr *startp, /* points to start of name */ const chr *endp) /* points just past end of name */ @@ -401,13 +414,13 @@ element(struct vars * v, /* context */ */ static struct cvec * range(struct vars * v, /* context */ - celt a, /* range start */ - celt b, /* range end, might equal a */ + chr a, /* range start */ + chr b, /* range end, might equal a */ int cases) /* case-independent? */ { int nchrs; struct cvec *cv; - celt c, + chr c, cc; if (a != b && !before(a, b)) @@ -444,7 +457,7 @@ range(struct vars * v, /* context */ for (c = a; c <= b; c++) { - cc = pg_wc_tolower((chr) c); + cc = pg_wc_tolower(c); if (cc != c && (before(cc, a) || before(b, cc))) { @@ -455,7 +468,7 @@ range(struct vars * v, /* context */ } addchr(cv, cc); } - cc = pg_wc_toupper((chr) c); + cc = pg_wc_toupper(c); if (cc != c && (before(cc, a) || before(b, cc))) { @@ -477,10 +490,10 @@ range(struct vars * v, /* context */ } /* - * before - is celt x before celt y, for purposes of range legality? + * before - is chr x before chr y, for purposes of range legality? */ static int /* predicate */ -before(celt x, celt y) +before(chr x, chr y) { if (x < y) return 1; @@ -493,7 +506,7 @@ before(celt x, celt y) */ static struct cvec * eclass(struct vars * v, /* context */ - celt c, /* Collating element representing the + chr c, /* Collating element representing the * equivalence class. */ int cases) /* all cases? */ { @@ -503,12 +516,12 @@ eclass(struct vars * v, /* context */ if ((v->cflags & REG_FAKE) && c == 'x') { cv = getcvec(v, 4, 0); - addchr(cv, (chr) 'x'); - addchr(cv, (chr) 'y'); + addchr(cv, CHR('x')); + addchr(cv, CHR('y')); if (cases) { - addchr(cv, (chr) 'X'); - addchr(cv, (chr) 'Y'); + addchr(cv, CHR('X')); + addchr(cv, CHR('Y')); } return cv; } @@ -518,7 +531,7 @@ eclass(struct vars * v, /* context */ return allcases(v, c); cv = getcvec(v, 1, 0); assert(cv != NULL); - addchr(cv, (chr) c); + addchr(cv, c); return cv; } @@ -543,21 +556,6 @@ cclass(struct vars * v, /* context */ int i, index; - /* - * The following arrays define the valid character class names. - */ - - static const char *const classNames[] = { - "alnum", "alpha", "ascii", "blank", "cntrl", "digit", "graph", - "lower", "print", "punct", "space", "upper", "xdigit", NULL - }; - - enum classes - { - CC_ALNUM, CC_ALPHA, CC_ASCII, CC_BLANK, CC_CNTRL, CC_DIGIT, CC_GRAPH, - CC_LOWER, CC_PRINT, CC_PUNCT, CC_SPACE, CC_UPPER, CC_XDIGIT - }; - /* * Map the name to the corresponding enumerated value. */ @@ -593,18 +591,20 @@ cclass(struct vars * v, /* context */ * pg_ctype_get_cache so that we can cache the results. Other classes * have definitions that are hard-wired here, and for those we just * construct a transient cvec on the fly. + * + * NB: keep this code in sync with cclass_column_index(), below. */ switch ((enum classes) index) { case CC_PRINT: - cv = pg_ctype_get_cache(pg_wc_isprint); + cv = pg_ctype_get_cache(pg_wc_isprint, index); break; case CC_ALNUM: - cv = pg_ctype_get_cache(pg_wc_isalnum); + cv = pg_ctype_get_cache(pg_wc_isalnum, index); break; case CC_ALPHA: - cv = pg_ctype_get_cache(pg_wc_isalpha); + cv = pg_ctype_get_cache(pg_wc_isalpha, index); break; case CC_ASCII: /* hard-wired meaning */ @@ -625,10 +625,10 @@ cclass(struct vars * v, /* context */ addrange(cv, 0x7f, 0x9f); break; case CC_DIGIT: - cv = pg_ctype_get_cache(pg_wc_isdigit); + cv = pg_ctype_get_cache(pg_wc_isdigit, index); break; case CC_PUNCT: - cv = pg_ctype_get_cache(pg_wc_ispunct); + cv = pg_ctype_get_cache(pg_wc_ispunct, index); break; case CC_XDIGIT: @@ -646,16 +646,16 @@ cclass(struct vars * v, /* context */ } break; case CC_SPACE: - cv = pg_ctype_get_cache(pg_wc_isspace); + cv = pg_ctype_get_cache(pg_wc_isspace, index); break; case CC_LOWER: - cv = pg_ctype_get_cache(pg_wc_islower); + cv = pg_ctype_get_cache(pg_wc_islower, index); break; case CC_UPPER: - cv = pg_ctype_get_cache(pg_wc_isupper); + cv = pg_ctype_get_cache(pg_wc_isupper, index); break; case CC_GRAPH: - cv = pg_ctype_get_cache(pg_wc_isgraph); + cv = pg_ctype_get_cache(pg_wc_isgraph, index); break; } @@ -665,6 +665,47 @@ cclass(struct vars * v, /* context */ return cv; } +/* + * cclass_column_index - get appropriate high colormap column index for chr + */ +static int +cclass_column_index(struct colormap * cm, chr c) +{ + int colnum = 0; + + /* Shouldn't go through all these pushups for simple chrs */ + assert(c > MAX_SIMPLE_CHR); + + /* + * Note: we should not see requests to consider cclasses that are not + * treated as locale-specific by cclass(), above. + */ + if (cm->classbits[CC_PRINT] && pg_wc_isprint(c)) + colnum |= cm->classbits[CC_PRINT]; + if (cm->classbits[CC_ALNUM] && pg_wc_isalnum(c)) + colnum |= cm->classbits[CC_ALNUM]; + if (cm->classbits[CC_ALPHA] && pg_wc_isalpha(c)) + colnum |= cm->classbits[CC_ALPHA]; + assert(cm->classbits[CC_ASCII] == 0); + assert(cm->classbits[CC_BLANK] == 0); + assert(cm->classbits[CC_CNTRL] == 0); + if (cm->classbits[CC_DIGIT] && pg_wc_isdigit(c)) + colnum |= cm->classbits[CC_DIGIT]; + if (cm->classbits[CC_PUNCT] && pg_wc_ispunct(c)) + colnum |= cm->classbits[CC_PUNCT]; + assert(cm->classbits[CC_XDIGIT] == 0); + if (cm->classbits[CC_SPACE] && pg_wc_isspace(c)) + colnum |= cm->classbits[CC_SPACE]; + if (cm->classbits[CC_LOWER] && pg_wc_islower(c)) + colnum |= cm->classbits[CC_LOWER]; + if (cm->classbits[CC_UPPER] && pg_wc_isupper(c)) + colnum |= cm->classbits[CC_UPPER]; + if (cm->classbits[CC_GRAPH] && pg_wc_isgraph(c)) + colnum |= cm->classbits[CC_GRAPH]; + + return colnum; +} + /* * allcases - supply cvec for all case counterparts of a chr (including itself) * @@ -673,15 +714,14 @@ cclass(struct vars * v, /* context */ */ static struct cvec * allcases(struct vars * v, /* context */ - chr pc) /* character to get case equivs of */ + chr c) /* character to get case equivs of */ { struct cvec *cv; - chr c = (chr) pc; chr lc, uc; - lc = pg_wc_tolower((chr) c); - uc = pg_wc_toupper((chr) c); + lc = pg_wc_tolower(c); + uc = pg_wc_toupper(c); cv = getcvec(v, 2, 0); addchr(cv, lc); diff --git a/src/backend/regex/regc_nfa.c b/src/backend/regex/regc_nfa.c index cd9a3239bd..90dca5d9de 100644 --- a/src/backend/regex/regc_nfa.c +++ b/src/backend/regex/regc_nfa.c @@ -275,7 +275,7 @@ destroystate(struct nfa * nfa, static void newarc(struct nfa * nfa, int t, - pcolor co, + color co, struct state * from, struct state * to) { @@ -321,7 +321,7 @@ newarc(struct nfa * nfa, static void createarc(struct nfa * nfa, int t, - pcolor co, + color co, struct state * from, struct state * to) { @@ -334,7 +334,7 @@ createarc(struct nfa * nfa, assert(a != NULL); a->type = t; - a->co = (color) co; + a->co = co; a->to = to; a->from = from; @@ -553,7 +553,7 @@ hasnonemptyout(struct state * s) static struct arc * findarc(struct state * s, int type, - pcolor co) + color co) { struct arc *a; diff --git a/src/backend/regex/regc_pg_locale.c b/src/backend/regex/regc_pg_locale.c index 551ae7dc08..afa3a7d613 100644 --- a/src/backend/regex/regc_pg_locale.c +++ b/src/backend/regex/regc_pg_locale.c @@ -6,7 +6,7 @@ * * This file is #included by regcomp.c; it's not meant to compile standalone. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -736,7 +736,7 @@ store_match(pg_ctype_cache *pcc, pg_wchar chr1, int nchrs) * Note that the result must not be freed or modified by caller. */ static struct cvec * -pg_ctype_get_cache(pg_wc_probefunc probefunc) +pg_ctype_get_cache(pg_wc_probefunc probefunc, int cclasscode) { pg_ctype_cache *pcc; pg_wchar max_chr; @@ -770,31 +770,43 @@ pg_ctype_get_cache(pg_wc_probefunc probefunc) pcc->cv.ranges = (chr *) malloc(pcc->cv.rangespace * sizeof(chr) * 2); if (pcc->cv.chrs == NULL || pcc->cv.ranges == NULL) goto out_of_memory; + pcc->cv.cclasscode = cclasscode; /* - * Decide how many character codes we ought to look through. For C locale - * there's no need to go further than 127. Otherwise, if the encoding is - * UTF8 go up to 0x7FF, which is a pretty arbitrary cutoff but we cannot - * extend it as far as we'd like (say, 0xFFFF, the end of the Basic - * Multilingual Plane) without creating significant performance issues due - * to too many characters being fed through the colormap code. This will - * need redesign to fix reasonably, but at least for the moment we have - * all common European languages covered. Otherwise (not C, not UTF8) go - * up to 255. These limits are interrelated with restrictions discussed - * at the head of this file. + * Decide how many character codes we ought to look through. In general + * we don't go past MAX_SIMPLE_CHR; chr codes above that are handled at + * runtime using the "high colormap" mechanism. However, in C locale + * there's no need to go further than 127, and if we only have a 1-byte + * API there's no need to go further than that can handle. + * + * If it's not MAX_SIMPLE_CHR that's constraining the search, mark the + * output cvec as not having any locale-dependent behavior, since there + * will be no need to do any run-time locale checks. (The #if's here + * would always be true for production values of MAX_SIMPLE_CHR, but it's + * useful to allow it to be small for testing purposes.) */ switch (pg_regex_strategy) { case PG_REGEX_LOCALE_C: +#if MAX_SIMPLE_CHR >= 127 max_chr = (pg_wchar) 127; + pcc->cv.cclasscode = -1; +#else + max_chr = (pg_wchar) MAX_SIMPLE_CHR; +#endif break; case PG_REGEX_LOCALE_WIDE: case PG_REGEX_LOCALE_WIDE_L: - max_chr = (pg_wchar) 0x7FF; + max_chr = (pg_wchar) MAX_SIMPLE_CHR; break; case PG_REGEX_LOCALE_1BYTE: case PG_REGEX_LOCALE_1BYTE_L: +#if MAX_SIMPLE_CHR >= UCHAR_MAX max_chr = (pg_wchar) UCHAR_MAX; + pcc->cv.cclasscode = -1; +#else + max_chr = (pg_wchar) MAX_SIMPLE_CHR; +#endif break; default: max_chr = 0; /* can't get here, but keep compiler quiet */ diff --git a/src/backend/regex/regcomp.c b/src/backend/regex/regcomp.c index cc589b0930..ed95474b3f 100644 --- a/src/backend/regex/regcomp.c +++ b/src/backend/regex/regcomp.c @@ -55,7 +55,6 @@ static void cbracket(struct vars *, struct state *, struct state *); static void brackpart(struct vars *, struct state *, struct state *); static const chr *scanplain(struct vars *); static void onechr(struct vars *, chr, struct state *, struct state *); -static void dovec(struct vars *, struct cvec *, struct state *, struct state *); static void wordchrs(struct vars *); static void processlacon(struct vars *, struct state *, struct state *, int, struct state *, struct state *); @@ -96,25 +95,27 @@ static chr chrnamed(struct vars *, const chr *, const chr *, chr); /* === regc_color.c === */ static void initcm(struct vars *, struct colormap *); static void freecm(struct colormap *); -static void cmtreefree(struct colormap *, union tree *, int); -static color setcolor(struct colormap *, chr, pcolor); static color maxcolor(struct colormap *); static color newcolor(struct colormap *); -static void freecolor(struct colormap *, pcolor); +static void freecolor(struct colormap *, color); static color pseudocolor(struct colormap *); -static color subcolor(struct colormap *, chr c); -static color newsub(struct colormap *, pcolor); -static void subrange(struct vars *, chr, chr, struct state *, struct state *); -static void subblock(struct vars *, chr, struct state *, struct state *); +static color subcolor(struct colormap *, chr); +static color subcolorhi(struct colormap *, color *); +static color newsub(struct colormap *, color); +static int newhicolorrow(struct colormap *, int); +static void newhicolorcols(struct colormap *); +static void subcolorcvec(struct vars *, struct cvec *, struct state *, struct state *); +static void subcoloronechr(struct vars *, chr, struct state *, struct state *, color *); +static void subcoloronerange(struct vars *, chr, chr, struct state *, struct state *, color *); +static void subcoloronerow(struct vars *, int, struct state *, struct state *, color *); static void okcolors(struct nfa *, struct colormap *); static void colorchain(struct colormap *, struct arc *); static void uncolorchain(struct colormap *, struct arc *); -static void rainbow(struct nfa *, struct colormap *, int, pcolor, struct state *, struct state *); +static void rainbow(struct nfa *, struct colormap *, int, color, struct state *, struct state *); static void colorcomplement(struct nfa *, struct colormap *, int, struct state *, struct state *, struct state *); #ifdef REG_DEBUG static void dumpcolors(struct colormap *, FILE *); -static void fillcheck(struct colormap *, union tree *, int, FILE *); static void dumpchr(chr, FILE *); #endif /* === regc_nfa.c === */ @@ -125,13 +126,13 @@ static struct state *newfstate(struct nfa *, int flag); static void dropstate(struct nfa *, struct state *); static void freestate(struct nfa *, struct state *); static void destroystate(struct nfa *, struct state *); -static void newarc(struct nfa *, int, pcolor, struct state *, struct state *); -static void createarc(struct nfa *, int, pcolor, struct state *, struct state *); +static void newarc(struct nfa *, int, color, struct state *, struct state *); +static void createarc(struct nfa *, int, color, struct state *, struct state *); static struct arc *allocarc(struct nfa *, struct state *); static void freearc(struct nfa *, struct arc *); static void changearctarget(struct arc *, struct state *); static int hasnonemptyout(struct state *); -static struct arc *findarc(struct state *, int, pcolor); +static struct arc *findarc(struct state *, int, color); static void cparc(struct nfa *, struct arc *, struct state *, struct state *); static void sortins(struct nfa *, struct state *); static int sortins_cmp(const void *, const void *); @@ -210,11 +211,12 @@ static pg_wchar pg_wc_toupper(pg_wchar c); static pg_wchar pg_wc_tolower(pg_wchar c); /* === regc_locale.c === */ -static celt element(struct vars *, const chr *, const chr *); -static struct cvec *range(struct vars *, celt, celt, int); -static int before(celt, celt); -static struct cvec *eclass(struct vars *, celt, int); +static chr element(struct vars *, const chr *, const chr *); +static struct cvec *range(struct vars *, chr, chr, int); +static int before(chr, chr); +static struct cvec *eclass(struct vars *, chr, int); static struct cvec *cclass(struct vars *, const chr *, const chr *, int); +static int cclass_column_index(struct colormap *, chr); static struct cvec *allcases(struct vars *, chr); static int cmp(const chr *, const chr *, size_t); static int casecmp(const chr *, const chr *, size_t); @@ -1424,8 +1426,8 @@ brackpart(struct vars * v, struct state * lp, struct state * rp) { - celt startc; - celt endc; + chr startc; + chr endc; struct cvec *cv; const chr *startp; const chr *endp; @@ -1467,7 +1469,7 @@ brackpart(struct vars * v, NOERR(); cv = eclass(v, startc, (v->cflags & REG_ICASE)); NOERR(); - dovec(v, cv, lp, rp); + subcolorcvec(v, cv, lp, rp); return; break; case CCLASS: @@ -1477,7 +1479,7 @@ brackpart(struct vars * v, NOERR(); cv = cclass(v, startp, endp, (v->cflags & REG_ICASE)); NOERR(); - dovec(v, cv, lp, rp); + subcolorcvec(v, cv, lp, rp); return; break; default: @@ -1523,7 +1525,7 @@ brackpart(struct vars * v, NOTE(REG_UUNPORT); cv = range(v, startc, endc, (v->cflags & REG_ICASE)); NOERR(); - dovec(v, cv, lp, rp); + subcolorcvec(v, cv, lp, rp); } /* @@ -1565,46 +1567,14 @@ onechr(struct vars * v, { if (!(v->cflags & REG_ICASE)) { - newarc(v->nfa, PLAIN, subcolor(v->cm, c), lp, rp); + color lastsubcolor = COLORLESS; + + subcoloronechr(v, c, lp, rp, &lastsubcolor); return; } /* rats, need general case anyway... */ - dovec(v, allcases(v, c), lp, rp); -} - -/* - * dovec - fill in arcs for each element of a cvec - */ -static void -dovec(struct vars * v, - struct cvec * cv, - struct state * lp, - struct state * rp) -{ - chr ch, - from, - to; - const chr *p; - int i; - - /* ordinary characters */ - for (p = cv->chrs, i = cv->nchrs; i > 0; p++, i--) - { - ch = *p; - newarc(v->nfa, PLAIN, subcolor(v->cm, ch), lp, rp); - NOERR(); - } - - /* and the ranges */ - for (p = cv->ranges, i = cv->nranges; i > 0; p += 2, i--) - { - from = *p; - to = *(p + 1); - if (from <= to) - subrange(v, from, to, lp, rp); - NOERR(); - } + subcolorcvec(v, allcases(v, c), lp, rp); } /* diff --git a/src/backend/regex/rege_dfa.c b/src/backend/regex/rege_dfa.c index 7d90242ace..b98c9d3902 100644 --- a/src/backend/regex/rege_dfa.c +++ b/src/backend/regex/rege_dfa.c @@ -603,7 +603,7 @@ static struct sset * miss(struct vars * v, struct dfa * d, struct sset * css, - pcolor co, + color co, chr *cp, /* next chr */ chr *start) /* where the attempt got started */ { @@ -731,7 +731,7 @@ miss(struct vars * v, css->outs[co] = p; css->inchain[co] = p->ins; p->ins.ss = css; - p->ins.co = (color) co; + p->ins.co = co; } return p; } @@ -743,7 +743,7 @@ static int /* predicate: constraint satisfied? */ lacon(struct vars * v, struct cnfa * pcnfa, /* parent cnfa */ chr *cp, - pcolor co) /* "color" of the lookaround constraint */ + color co) /* "color" of the lookaround constraint */ { int n; struct subre *sub; diff --git a/src/backend/regex/regexec.c b/src/backend/regex/regexec.c index 82659a0f2f..5cbfd9b151 100644 --- a/src/backend/regex/regexec.c +++ b/src/backend/regex/regexec.c @@ -159,8 +159,8 @@ static struct dfa *newdfa(struct vars *, struct cnfa *, struct colormap *, struc static void freedfa(struct dfa *); static unsigned hash(unsigned *, int); static struct sset *initialize(struct vars *, struct dfa *, chr *); -static struct sset *miss(struct vars *, struct dfa *, struct sset *, pcolor, chr *, chr *); -static int lacon(struct vars *, struct cnfa *, chr *, pcolor); +static struct sset *miss(struct vars *, struct dfa *, struct sset *, color, chr *, chr *); +static int lacon(struct vars *, struct cnfa *, chr *, color); static struct sset *getvacant(struct vars *, struct dfa *, chr *, chr *); static struct sset *pickss(struct vars *, struct dfa *, chr *, chr *); diff --git a/src/backend/regex/regexport.c b/src/backend/regex/regexport.c index 93da82286f..3856ff873f 100644 --- a/src/backend/regex/regexport.c +++ b/src/backend/regex/regexport.c @@ -15,7 +15,7 @@ * allows the caller to decide how big is too big to bother with. * * - * Portions Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2013-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1998, 1999 Henry Spencer * * IDENTIFICATION @@ -28,10 +28,6 @@ #include "regex/regexport.h" -static void scancolormap(struct colormap * cm, int co, - union tree * t, int level, chr partial, - pg_wchar **chars, int *chars_len); - /* * Get total number of NFA states. @@ -187,10 +183,7 @@ pg_reg_colorisend(const regex_t *regex, int co) * * Note: we return -1 if the color number is invalid, or if it is a special * color (WHITE or a pseudocolor), or if the number of members is uncertain. - * The latter case cannot arise right now but is specified to allow for future - * improvements (see musings about run-time handling of higher character codes - * in regex/README). Callers should not try to extract the members if -1 is - * returned. + * Callers should not try to extract the members if -1 is returned. */ int pg_reg_getnumcharacters(const regex_t *regex, int co) @@ -205,7 +198,18 @@ pg_reg_getnumcharacters(const regex_t *regex, int co) if (cm->cd[co].flags & PSEUDO) /* also pseudocolors (BOS etc) */ return -1; - return cm->cd[co].nchrs; + /* + * If the color appears anywhere in the high colormap, treat its number of + * members as uncertain. In principle we could determine all the specific + * chrs corresponding to each such entry, but it would be expensive + * (particularly if character class tests are required) and it doesn't + * seem worth it. + */ + if (cm->cd[co].nuchrs != 0) + return -1; + + /* OK, return the known number of member chrs */ + return cm->cd[co].nschrs; } /* @@ -222,6 +226,7 @@ pg_reg_getcharacters(const regex_t *regex, int co, pg_wchar *chars, int chars_len) { struct colormap *cm; + chr c; assert(regex != NULL && regex->re_magic == REMAGIC); cm = &((struct guts *) regex->re_guts)->cmap; @@ -231,62 +236,17 @@ pg_reg_getcharacters(const regex_t *regex, int co, if (cm->cd[co].flags & PSEUDO) return; - /* Recursively search the colormap tree */ - scancolormap(cm, co, cm->tree, 0, 0, &chars, &chars_len); -} - -/* - * Recursively scan the colormap tree to find chrs belonging to color "co". - * See regex/README for info about the tree structure. - * - * t: tree block to scan - * level: level (from 0) of t - * partial: partial chr code for chrs within t - * chars, chars_len: output area - */ -static void -scancolormap(struct colormap * cm, int co, - union tree * t, int level, chr partial, - pg_wchar **chars, int *chars_len) -{ - int i; - - if (level < NBYTS - 1) - { - /* non-leaf node */ - for (i = 0; i < BYTTAB; i++) - { - /* - * We do not support search for chrs of color 0 (WHITE), so - * all-white subtrees need not be searched. These can be - * recognized because they are represented by the fill blocks in - * the colormap struct. This typically allows us to avoid - * scanning large regions of higher-numbered chrs. - */ - if (t->tptr[i] == &cm->tree[level + 1]) - continue; - - /* Recursively scan next level down */ - scancolormap(cm, co, - t->tptr[i], level + 1, - (partial | (chr) i) << BYTBITS, - chars, chars_len); - } - } - else + /* + * We need only examine the low character map; there should not be any + * matching entries in the high map. + */ + for (c = CHR_MIN; c <= MAX_SIMPLE_CHR; c++) { - /* leaf node */ - for (i = 0; i < BYTTAB; i++) + if (cm->locolormap[c - CHR_MIN] == co) { - if (t->tcolor[i] == co) - { - if (*chars_len > 0) - { - **chars = partial | (chr) i; - (*chars)++; - (*chars_len)--; - } - } + *chars++ = c; + if (--chars_len == 0) + break; } } } diff --git a/src/backend/regex/regprefix.c b/src/backend/regex/regprefix.c index 04b6449a20..cb74f2f311 100644 --- a/src/backend/regex/regprefix.c +++ b/src/backend/regex/regprefix.c @@ -4,7 +4,7 @@ * Extract a common prefix, if any, from a compiled regex. * * - * Portions Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1998, 1999 Henry Spencer * * IDENTIFICATION @@ -194,7 +194,10 @@ findprefix(struct cnfa * cnfa, if (thiscolor == COLORLESS) break; /* The color must be a singleton */ - if (cm->cd[thiscolor].nchrs != 1) + if (cm->cd[thiscolor].nschrs != 1) + break; + /* Must not have any high-color-map entries */ + if (cm->cd[thiscolor].nuchrs != 0) break; /* diff --git a/src/backend/replication/Makefile b/src/backend/replication/Makefile index c99717e0ae..da8bcf0471 100644 --- a/src/backend/replication/Makefile +++ b/src/backend/replication/Makefile @@ -26,7 +26,7 @@ repl_gram.o: repl_scanner.c # syncrep_scanner is complied as part of syncrep_gram syncrep_gram.o: syncrep_scanner.c -syncrep_scanner.c: FLEXFLAGS = -CF -p +syncrep_scanner.c: FLEXFLAGS = -CF -p -i syncrep_scanner.c: FLEX_NO_BACKUP=yes # repl_gram.c, repl_scanner.c, syncrep_gram.c and syncrep_scanner.c diff --git a/src/backend/replication/README b/src/backend/replication/README index ad4864dbbe..0cbb990613 100644 --- a/src/backend/replication/README +++ b/src/backend/replication/README @@ -54,7 +54,7 @@ and WalRcvData->slotname, and initializes the starting point in WalRcvData->receiveStart. As walreceiver receives WAL from the master server, and writes and flushes -it to disk (in pg_xlog), it updates WalRcvData->receivedUpto and signals +it to disk (in pg_wal), it updates WalRcvData->receivedUpto and signals the startup process to know how far WAL replay can advance. Walreceiver sends information about replication progress to the master server diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c index da9b7a6f0d..09ecc15365 100644 --- a/src/backend/replication/basebackup.c +++ b/src/backend/replication/basebackup.c @@ -3,7 +3,7 @@ * basebackup.c * code for taking a base backup and streaming it to a standby * - * Portions Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/basebackup.c @@ -30,6 +30,7 @@ #include "replication/basebackup.h" #include "replication/walsender.h" #include "replication/walsender_private.h" +#include "storage/dsm_impl.h" #include "storage/fd.h" #include "storage/ipc.h" #include "utils/builtins.h" @@ -55,8 +56,10 @@ static int64 sendDir(char *path, int basepathlen, bool sizeonly, static bool sendFile(char *readfilename, char *tarfilename, struct stat * statbuf, bool missing_ok); static void sendFileWithContent(const char *filename, const char *content); -static void _tarWriteHeader(const char *filename, const char *linktarget, - struct stat * statbuf); +static int64 _tarWriteHeader(const char *filename, const char *linktarget, + struct stat * statbuf, bool sizeonly); +static int64 _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf, + bool sizeonly); static void send_int8_string(StringInfoData *buf, int64 intval); static void SendBackupHeader(List *tablespaces); static void base_backup_cleanup(int code, Datum arg); @@ -94,6 +97,73 @@ static int64 elapsed_min_unit; /* The last check of the transfer rate. */ static int64 throttled_last; +/* + * The contents of these directories are removed or recreated during server + * start so they are not included in backups. The directories themselves are + * kept and included as empty to preserve access permissions. + */ +static const char *excludeDirContents[] = +{ + /* + * Skip temporary statistics files. PG_STAT_TMP_DIR must be skipped even + * when stats_temp_directory is set because PGSS_TEXT_FILE is always created + * there. + */ + PG_STAT_TMP_DIR, + + /* + * It is generally not useful to backup the contents of this directory even + * if the intention is to restore to another master. See backup.sgml for a + * more detailed description. + */ + "pg_replslot", + + /* Contents removed on startup, see dsm_cleanup_for_mmap(). */ + PG_DYNSHMEM_DIR, + + /* Contents removed on startup, see AsyncShmemInit(). */ + "pg_notify", + + /* + * Old contents are loaded for possible debugging but are not required for + * normal operation, see OldSerXidInit(). + */ + "pg_serial", + + /* Contents removed on startup, see DeleteAllExportedSnapshotFiles(). */ + "pg_snapshots", + + /* Contents zeroed on startup, see StartupSUBTRANS(). */ + "pg_subtrans", + + /* end of list */ + NULL +}; + +/* + * List of files excluded from backups. + */ +static const char *excludeFiles[] = +{ + /* Skip auto conf temporary file. */ + PG_AUTOCONF_FILENAME ".tmp", + + /* + * If there's a backup_label or tablespace_map file, it belongs to a + * backup started by the user with pg_start_backup(). It is *not* correct + * for this backup. Our backup_label/tablespace_map is injected into the + * tar separately. + */ + BACKUP_LABEL_FILE, + TABLESPACE_MAP, + + "postmaster.pid", + "postmaster.opts", + + /* end of list */ + NULL +}; + /* * Called when ERROR or FATAL happens in perform_base_backup() after * we have started the backup - make sure we end it! @@ -276,7 +346,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir) TimeLineID tli; /* - * I'd rather not worry about timelines here, so scan pg_xlog and + * I'd rather not worry about timelines here, so scan pg_wal and * include all WAL files in the range between 'startptr' and 'endptr', * regardless of the timeline the file is stamped with. If there are * some spurious WAL files belonging to timelines that don't belong in @@ -289,11 +359,11 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir) XLByteToPrevSeg(endptr, endsegno); XLogFileName(lastoff, ThisTimeLineID, endsegno); - dir = AllocateDir("pg_xlog"); + dir = AllocateDir("pg_wal"); if (!dir) ereport(ERROR, - (errmsg("could not open directory \"%s\": %m", "pg_xlog"))); - while ((de = ReadDir(dir, "pg_xlog")) != NULL) + (errmsg("could not open directory \"%s\": %m", "pg_wal"))); + while ((de = ReadDir(dir, "pg_wal")) != NULL) { /* Does it look like a WAL segment, and is it in the range? */ if (IsXLogFileName(de->d_name) && @@ -331,7 +401,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir) qsort(walFiles, nWalFiles, sizeof(char *), compareWalFileNames); /* - * There must be at least one xlog file in the pg_xlog directory, + * There must be at least one xlog file in the pg_wal directory, * since we are doing backup-including-xlog. */ if (nWalFiles < 1) @@ -415,7 +485,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir) } /* send the WAL file itself */ - _tarWriteHeader(pathbuf, NULL, &statbuf); + _tarWriteHeader(pathbuf, NULL, &statbuf, false); while ((cnt = fread(buf, 1, Min(sizeof(buf), XLogSegSize - len), fp)) > 0) { @@ -807,7 +877,7 @@ sendFileWithContent(const char *filename, const char *content) statbuf.st_mode = S_IRUSR | S_IWUSR; statbuf.st_size = len; - _tarWriteHeader(filename, NULL, &statbuf); + _tarWriteHeader(filename, NULL, &statbuf, false); /* Send the contents as a CopyData message */ pq_putmessage('d', content, len); @@ -858,9 +928,9 @@ sendTablespace(char *path, bool sizeonly) /* If the tablespace went away while scanning, it's no error. */ return 0; } - if (!sizeonly) - _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf); - size = 512; /* Size of the header just added */ + + size = _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf, + sizeonly); /* Send all the files in the tablespace version directory */ size += sendDir(pathbuf, strlen(path), sizeonly, NIL, true); @@ -893,6 +963,9 @@ sendDir(char *path, int basepathlen, bool sizeonly, List *tablespaces, dir = AllocateDir(path); while ((de = ReadDir(dir, path)) != NULL) { + int excludeIdx; + bool excludeFound; + /* Skip special stuff */ if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) continue; @@ -903,24 +976,6 @@ sendDir(char *path, int basepathlen, bool sizeonly, List *tablespaces, strlen(PG_TEMP_FILE_PREFIX)) == 0) continue; - /* skip auto conf temporary file */ - if (strncmp(de->d_name, - PG_AUTOCONF_FILENAME ".tmp", - sizeof(PG_AUTOCONF_FILENAME) + 4) == 0) - continue; - - /* - * If there's a backup_label or tablespace_map file, it belongs to a - * backup started by the user with pg_start_backup(). It is *not* - * correct for this backup, our backup_label/tablespace_map is - * injected into the tar separately. - */ - if (strcmp(de->d_name, BACKUP_LABEL_FILE) == 0) - continue; - - if (strcmp(de->d_name, TABLESPACE_MAP) == 0) - continue; - /* * Check if the postmaster has signaled us to exit, and abort with an * error in that case. The error handler further up will call @@ -938,13 +993,23 @@ sendDir(char *path, int basepathlen, bool sizeonly, List *tablespaces, "and should not be used. " "Try taking another online backup."))); - snprintf(pathbuf, MAXPGPATH, "%s/%s", path, de->d_name); + /* Scan for files that should be excluded */ + excludeFound = false; + for (excludeIdx = 0; excludeFiles[excludeIdx] != NULL; excludeIdx++) + { + if (strcmp(de->d_name, excludeFiles[excludeIdx]) == 0) + { + elog(DEBUG1, "file \"%s\" excluded from backup", de->d_name); + excludeFound = true; + break; + } + } - /* Skip postmaster.pid and postmaster.opts in the data directory */ - if (strcmp(pathbuf, "./postmaster.pid") == 0 || - strcmp(pathbuf, "./postmaster.opts") == 0) + if (excludeFound) continue; + snprintf(pathbuf, MAXPGPATH, "%s/%s", path, de->d_name); + /* Skip pg_control here to back up it last */ if (strcmp(pathbuf, "./global/pg_control") == 0) continue; @@ -957,65 +1022,55 @@ sendDir(char *path, int basepathlen, bool sizeonly, List *tablespaces, errmsg("could not stat file or directory \"%s\": %m", pathbuf))); - /* If the file went away while scanning, it's no error. */ + /* If the file went away while scanning, it's not an error. */ continue; } - /* - * Skip temporary statistics files. PG_STAT_TMP_DIR must be skipped - * even when stats_temp_directory is set because PGSS_TEXT_FILE is - * always created there. - */ - if ((statrelpath != NULL && strcmp(pathbuf, statrelpath) == 0) || - strncmp(de->d_name, PG_STAT_TMP_DIR, strlen(PG_STAT_TMP_DIR)) == 0) + /* Scan for directories whose contents should be excluded */ + excludeFound = false; + for (excludeIdx = 0; excludeDirContents[excludeIdx] != NULL; excludeIdx++) { - if (!sizeonly) - _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf); - size += 512; - continue; + if (strcmp(de->d_name, excludeDirContents[excludeIdx]) == 0) + { + elog(DEBUG1, "contents of directory \"%s\" excluded from backup", de->d_name); + size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly); + excludeFound = true; + break; + } } + if (excludeFound) + continue; + /* - * Skip pg_replslot, not useful to copy. But include it as an empty - * directory anyway, so we get permissions right. + * Exclude contents of directory specified by statrelpath if not set + * to the default (pg_stat_tmp) which is caught in the loop above. */ - if (strcmp(de->d_name, "pg_replslot") == 0) + if (statrelpath != NULL && strcmp(pathbuf, statrelpath) == 0) { - if (!sizeonly) - _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf); - size += 512; /* Size of the header just added */ + elog(DEBUG1, "contents of directory \"%s\" excluded from backup", statrelpath); + size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly); continue; } /* - * We can skip pg_xlog, the WAL segments need to be fetched from the + * We can skip pg_wal, the WAL segments need to be fetched from the * WAL archive anyway. But include it as an empty directory anyway, so * we get permissions right. */ - if (strcmp(pathbuf, "./pg_xlog") == 0) + if (strcmp(pathbuf, "./pg_wal") == 0) { - if (!sizeonly) - { - /* If pg_xlog is a symlink, write it as a directory anyway */ -#ifndef WIN32 - if (S_ISLNK(statbuf.st_mode)) -#else - if (pgwin32_is_junction(pathbuf)) -#endif - statbuf.st_mode = S_IFDIR | S_IRWXU; - _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf); - } - size += 512; /* Size of the header just added */ + /* If pg_wal is a symlink, write it as a directory anyway */ + size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly); /* * Also send archive_status directory (by hackishly reusing * statbuf from above ...). */ - if (!sizeonly) - _tarWriteHeader("./pg_xlog/archive_status", NULL, &statbuf); - size += 512; /* Size of the header just added */ + size += _tarWriteHeader("./pg_wal/archive_status", NULL, &statbuf, + sizeonly); - continue; /* don't recurse into pg_xlog */ + continue; /* don't recurse into pg_wal */ } /* Allow symbolic links in pg_tblspc only */ @@ -1044,9 +1099,8 @@ sendDir(char *path, int basepathlen, bool sizeonly, List *tablespaces, pathbuf))); linkpath[rllen] = '\0'; - if (!sizeonly) - _tarWriteHeader(pathbuf + basepathlen + 1, linkpath, &statbuf); - size += 512; /* Size of the header just added */ + size += _tarWriteHeader(pathbuf + basepathlen + 1, linkpath, + &statbuf, sizeonly); #else /* @@ -1069,9 +1123,8 @@ sendDir(char *path, int basepathlen, bool sizeonly, List *tablespaces, * Store a directory entry in the tar file so we can get the * permissions right. */ - if (!sizeonly) - _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf); - size += 512; /* Size of the header just added */ + size += _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf, + sizeonly); /* * Call ourselves recursively for a directory, unless it happens @@ -1162,7 +1215,7 @@ sendFile(char *readfilename, char *tarfilename, struct stat * statbuf, errmsg("could not open file \"%s\": %m", readfilename))); } - _tarWriteHeader(tarfilename, NULL, statbuf); + _tarWriteHeader(tarfilename, NULL, statbuf, false); while ((cnt = fread(buf, 1, Min(sizeof(buf), statbuf->st_size - len), fp)) > 0) { @@ -1215,36 +1268,61 @@ sendFile(char *readfilename, char *tarfilename, struct stat * statbuf, } -static void +static int64 _tarWriteHeader(const char *filename, const char *linktarget, - struct stat * statbuf) + struct stat * statbuf, bool sizeonly) { char h[512]; enum tarError rc; - rc = tarCreateHeader(h, filename, linktarget, statbuf->st_size, - statbuf->st_mode, statbuf->st_uid, statbuf->st_gid, - statbuf->st_mtime); - - switch (rc) + if (!sizeonly) { - case TAR_OK: - break; - case TAR_NAME_TOO_LONG: - ereport(ERROR, - (errmsg("file name too long for tar format: \"%s\"", - filename))); - break; - case TAR_SYMLINK_TOO_LONG: - ereport(ERROR, - (errmsg("symbolic link target too long for tar format: file name \"%s\", target \"%s\"", - filename, linktarget))); - break; - default: - elog(ERROR, "unrecognized tar error: %d", rc); + rc = tarCreateHeader(h, filename, linktarget, statbuf->st_size, + statbuf->st_mode, statbuf->st_uid, statbuf->st_gid, + statbuf->st_mtime); + + switch (rc) + { + case TAR_OK: + break; + case TAR_NAME_TOO_LONG: + ereport(ERROR, + (errmsg("file name too long for tar format: \"%s\"", + filename))); + break; + case TAR_SYMLINK_TOO_LONG: + ereport(ERROR, + (errmsg("symbolic link target too long for tar format: " + "file name \"%s\", target \"%s\"", + filename, linktarget))); + break; + default: + elog(ERROR, "unrecognized tar error: %d", rc); + } + + pq_putmessage('d', h, sizeof(h)); } - pq_putmessage('d', h, 512); + return sizeof(h); +} + +/* + * Write tar header for a directory. If the entry in statbuf is a link then + * write it as a directory anyway. + */ +static int64 +_tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf, + bool sizeonly) +{ + /* If symlink, write it as a directory anyway */ +#ifndef WIN32 + if (S_ISLNK(statbuf->st_mode)) +#else + if (pgwin32_is_junction(pathbuf)) +#endif + statbuf->st_mode = S_IFDIR | S_IRWXU; + + return _tarWriteHeader(pathbuf + basepathlen + 1, NULL, statbuf, sizeonly); } /* @@ -1286,31 +1364,22 @@ throttle(size_t increment) */ wait_result = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - (long) (sleep / 1000)); + (long) (sleep / 1000), + WAIT_EVENT_BASE_BACKUP_THROTTLE); if (wait_result & WL_LATCH_SET) CHECK_FOR_INTERRUPTS(); } - else - { - /* - * The actual transfer rate is below the limit. A negative value - * would distort the adjustment of throttled_last. - */ - wait_result = 0; - sleep = 0; - } /* - * Only a whole multiple of throttling_sample was processed. The rest will - * be done during the next call of this function. + * As we work with integers, only whole multiple of throttling_sample was + * processed. The rest will be done during the next call of this function. */ throttling_counter %= throttling_sample; - /* Once the (possible) sleep has ended, new period starts. */ - if (wait_result & WL_TIMEOUT) - throttled_last += elapsed + sleep; - else if (sleep > 0) - /* Sleep was necessary but might have been interrupted. */ - throttled_last = GetCurrentIntegerTimestamp(); + /* + * Time interval for the remaining amount and possible next increments + * starts now. + */ + throttled_last = GetCurrentIntegerTimestamp(); } diff --git a/src/backend/replication/libpqwalreceiver/Makefile b/src/backend/replication/libpqwalreceiver/Makefile index 6c95c1ce97..a7a5fe1ed2 100644 --- a/src/backend/replication/libpqwalreceiver/Makefile +++ b/src/backend/replication/libpqwalreceiver/Makefile @@ -15,7 +15,7 @@ include $(top_builddir)/src/Makefile.global override CPPFLAGS := -I$(srcdir) -I$(libpq_srcdir) $(CPPFLAGS) OBJS = libpqwalreceiver.o $(WIN32RES) -SHLIB_LINK = $(libpq) +SHLIB_LINK = $(libpq) $(filter -lintl, $(LIBS)) SHLIB_PREREQS = submake-libpq PGFILEDESC = "libpqwalreceiver - receive WAL during streaming replication" NAME = libpqwalreceiver diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c index f1c843e868..7df3698afb 100644 --- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c +++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c @@ -6,7 +6,7 @@ * loaded as a dynamic module to avoid linking the main server binary with * libpq. * - * Portions Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -23,77 +23,98 @@ #include "pqexpbuffer.h" #include "access/xlog.h" #include "miscadmin.h" +#include "pgstat.h" +#include "replication/logicalproto.h" #include "replication/walreceiver.h" +#include "storage/proc.h" #include "utils/builtins.h" - -#ifdef HAVE_POLL_H -#include -#endif -#ifdef HAVE_SYS_POLL_H -#include -#endif -#ifdef HAVE_SYS_SELECT_H -#include -#endif +#include "utils/pg_lsn.h" PG_MODULE_MAGIC; void _PG_init(void); -/* Current connection to the primary, if any */ -static PGconn *streamConn = NULL; - -/* Buffer for currently read records */ -static char *recvBuf = NULL; +struct WalReceiverConn +{ + /* Current connection to the primary, if any */ + PGconn *streamConn; + /* Used to remember if the connection is logical or physical */ + bool logical; + /* Buffer for currently read records */ + char *recvBuf; +}; /* Prototypes for interface functions */ -static void libpqrcv_connect(char *conninfo); -static char *libpqrcv_get_conninfo(void); -static void libpqrcv_identify_system(TimeLineID *primary_tli); -static void libpqrcv_readtimelinehistoryfile(TimeLineID tli, char **filename, char **content, int *len); -static bool libpqrcv_startstreaming(TimeLineID tli, XLogRecPtr startpoint, - char *slotname); -static void libpqrcv_endstreaming(TimeLineID *next_tli); -static int libpqrcv_receive(char **buffer, pgsocket *wait_fd); -static void libpqrcv_send(const char *buffer, int nbytes); -static void libpqrcv_disconnect(void); +static WalReceiverConn *libpqrcv_connect(const char *conninfo, + bool logical, const char *appname, + char **err); +static void libpqrcv_check_conninfo(const char *conninfo); +static char *libpqrcv_get_conninfo(WalReceiverConn *conn); +static char *libpqrcv_identify_system(WalReceiverConn *conn, + TimeLineID *primary_tli, + int *server_version); +static void libpqrcv_readtimelinehistoryfile(WalReceiverConn *conn, + TimeLineID tli, char **filename, + char **content, int *len); +static bool libpqrcv_startstreaming(WalReceiverConn *conn, + const WalRcvStreamOptions *options); +static void libpqrcv_endstreaming(WalReceiverConn *conn, + TimeLineID *next_tli); +static int libpqrcv_receive(WalReceiverConn *conn, char **buffer, + pgsocket *wait_fd); +static void libpqrcv_send(WalReceiverConn *conn, const char *buffer, + int nbytes); +static char *libpqrcv_create_slot(WalReceiverConn *conn, + const char *slotname, + bool temporary, + XLogRecPtr *lsn); +static bool libpqrcv_command(WalReceiverConn *conn, + const char *cmd, char **err); +static void libpqrcv_disconnect(WalReceiverConn *conn); + +static WalReceiverFunctionsType PQWalReceiverFunctions = { + libpqrcv_connect, + libpqrcv_check_conninfo, + libpqrcv_get_conninfo, + libpqrcv_identify_system, + libpqrcv_readtimelinehistoryfile, + libpqrcv_startstreaming, + libpqrcv_endstreaming, + libpqrcv_receive, + libpqrcv_send, + libpqrcv_create_slot, + libpqrcv_command, + libpqrcv_disconnect +}; /* Prototypes for private functions */ -static bool libpq_select(int timeout_ms); -static PGresult *libpqrcv_PQexec(const char *query); +static PGresult *libpqrcv_PQexec(PGconn *streamConn, const char *query); +static char *stringlist_to_identifierstr(PGconn *conn, List *strings); /* - * Module load callback + * Module initialization function */ void _PG_init(void) { - /* Tell walreceiver how to reach us */ - if (walrcv_connect != NULL || walrcv_identify_system != NULL || - walrcv_readtimelinehistoryfile != NULL || - walrcv_startstreaming != NULL || walrcv_endstreaming != NULL || - walrcv_receive != NULL || walrcv_send != NULL || - walrcv_disconnect != NULL) + if (WalReceiverFunctions != NULL) elog(ERROR, "libpqwalreceiver already loaded"); - walrcv_connect = libpqrcv_connect; - walrcv_get_conninfo = libpqrcv_get_conninfo; - walrcv_identify_system = libpqrcv_identify_system; - walrcv_readtimelinehistoryfile = libpqrcv_readtimelinehistoryfile; - walrcv_startstreaming = libpqrcv_startstreaming; - walrcv_endstreaming = libpqrcv_endstreaming; - walrcv_receive = libpqrcv_receive; - walrcv_send = libpqrcv_send; - walrcv_disconnect = libpqrcv_disconnect; + WalReceiverFunctions = &PQWalReceiverFunctions; } /* * Establish the connection to the primary server for XLOG streaming + * + * Returns NULL on error and fills the err with palloc'ed error message. */ -static void -libpqrcv_connect(char *conninfo) +static WalReceiverConn * +libpqrcv_connect(const char *conninfo, bool logical, const char *appname, + char **err) { + WalReceiverConn *conn; const char *keys[5]; const char *vals[5]; + int i = 0; /* * We use the expand_dbname parameter to process the connection string (or @@ -102,22 +123,49 @@ libpqrcv_connect(char *conninfo) * database name is ignored by the server in replication mode, but specify * "replication" for .pgpass lookup. */ - keys[0] = "dbname"; - vals[0] = conninfo; - keys[1] = "replication"; - vals[1] = "true"; - keys[2] = "dbname"; - vals[2] = "replication"; - keys[3] = "fallback_application_name"; - vals[3] = "walreceiver"; - keys[4] = NULL; - vals[4] = NULL; - - streamConn = PQconnectdbParams(keys, vals, /* expand_dbname = */ true); - if (PQstatus(streamConn) != CONNECTION_OK) + keys[i] = "dbname"; + vals[i] = conninfo; + keys[++i] = "replication"; + vals[i] = logical ? "database" : "true"; + if (!logical) + { + keys[++i] = "dbname"; + vals[i] = "replication"; + } + keys[++i] = "fallback_application_name"; + vals[i] = appname; + keys[++i] = NULL; + vals[i] = NULL; + + conn = palloc0(sizeof(WalReceiverConn)); + conn->streamConn = PQconnectdbParams(keys, vals, /* expand_dbname = */ true); + if (PQstatus(conn->streamConn) != CONNECTION_OK) + { + *err = pstrdup(PQerrorMessage(conn->streamConn)); + return NULL; + } + + conn->logical = logical; + + return conn; +} + +/* + * Validate connection info string (just try to parse it) + */ +static void +libpqrcv_check_conninfo(const char *conninfo) +{ + PQconninfoOption *opts = NULL; + char *err = NULL; + + opts = PQconninfoParse(conninfo, &err); + if (opts == NULL) ereport(ERROR, - (errmsg("could not connect to the primary server: %s", - PQerrorMessage(streamConn)))); + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("invalid connection string syntax: %s", err))); + + PQconninfoFree(opts); } /* @@ -125,17 +173,17 @@ libpqrcv_connect(char *conninfo) * are obfuscated. */ static char * -libpqrcv_get_conninfo(void) +libpqrcv_get_conninfo(WalReceiverConn *conn) { PQconninfoOption *conn_opts; PQconninfoOption *conn_opt; PQExpBufferData buf; char *retval; - Assert(streamConn != NULL); + Assert(conn->streamConn != NULL); initPQExpBuffer(&buf); - conn_opts = PQconninfo(streamConn); + conn_opts = PQconninfo(conn->streamConn); if (conn_opts == NULL) ereport(ERROR, @@ -173,25 +221,25 @@ libpqrcv_get_conninfo(void) * Check that primary's system identifier matches ours, and fetch the current * timeline ID of the primary. */ -static void -libpqrcv_identify_system(TimeLineID *primary_tli) +static char * +libpqrcv_identify_system(WalReceiverConn *conn, TimeLineID *primary_tli, + int *server_version) { PGresult *res; char *primary_sysid; - char standby_sysid[32]; /* * Get the system identifier and timeline ID as a DataRow message from the * primary server. */ - res = libpqrcv_PQexec("IDENTIFY_SYSTEM"); + res = libpqrcv_PQexec(conn->streamConn, "IDENTIFY_SYSTEM"); if (PQresultStatus(res) != PGRES_TUPLES_OK) { PQclear(res); ereport(ERROR, (errmsg("could not receive database system identifier and timeline ID from " "the primary server: %s", - PQerrorMessage(streamConn)))); + PQerrorMessage(conn->streamConn)))); } if (PQnfields(res) < 3 || PQntuples(res) != 1) { @@ -204,28 +252,17 @@ libpqrcv_identify_system(TimeLineID *primary_tli) errdetail("Could not identify system: got %d rows and %d fields, expected %d rows and %d or more fields.", ntuples, nfields, 3, 1))); } - primary_sysid = PQgetvalue(res, 0, 0); + primary_sysid = pstrdup(PQgetvalue(res, 0, 0)); *primary_tli = pg_atoi(PQgetvalue(res, 0, 1), 4, 0); - - /* - * Confirm that the system identifier of the primary is the same as ours. - */ - snprintf(standby_sysid, sizeof(standby_sysid), UINT64_FORMAT, - GetSystemIdentifier()); - if (strcmp(primary_sysid, standby_sysid) != 0) - { - primary_sysid = pstrdup(primary_sysid); - PQclear(res); - ereport(ERROR, - (errmsg("database system identifier differs between the primary and standby"), - errdetail("The primary's identifier is %s, the standby's identifier is %s.", - primary_sysid, standby_sysid))); - } PQclear(res); + + *server_version = PQserverVersion(conn->streamConn); + + return primary_sysid; } /* - * Start streaming WAL data from given startpoint and timeline. + * Start streaming WAL data from given streaming options. * * Returns true if we switched successfully to copy-both mode. False * means the server received the command and executed it successfully, but @@ -235,21 +272,57 @@ libpqrcv_identify_system(TimeLineID *primary_tli) * throws an ERROR. */ static bool -libpqrcv_startstreaming(TimeLineID tli, XLogRecPtr startpoint, char *slotname) +libpqrcv_startstreaming(WalReceiverConn *conn, + const WalRcvStreamOptions *options) { - char cmd[256]; + StringInfoData cmd; PGresult *res; - /* Start streaming from the point requested by startup process */ - if (slotname != NULL) - snprintf(cmd, sizeof(cmd), - "START_REPLICATION SLOT \"%s\" %X/%X TIMELINE %u", slotname, - (uint32) (startpoint >> 32), (uint32) startpoint, tli); + Assert(options->logical == conn->logical); + Assert(options->slotname || !options->logical); + + initStringInfo(&cmd); + + /* Build the command. */ + appendStringInfoString(&cmd, "START_REPLICATION"); + if (options->slotname != NULL) + appendStringInfo(&cmd, " SLOT \"%s\"", + options->slotname); + + if (options->logical) + appendStringInfo(&cmd, " LOGICAL"); + + appendStringInfo(&cmd, " %X/%X", + (uint32) (options->startpoint >> 32), + (uint32) options->startpoint); + + /* + * Additional options are different depending on if we are doing logical + * or physical replication. + */ + if (options->logical) + { + char *pubnames_str; + List *pubnames; + + appendStringInfoString(&cmd, " ("); + appendStringInfo(&cmd, "proto_version '%u'", + options->proto.logical.proto_version); + pubnames = options->proto.logical.publication_names; + pubnames_str = stringlist_to_identifierstr(conn->streamConn, pubnames); + appendStringInfo(&cmd, ", publication_names %s", + PQescapeLiteral(conn->streamConn, pubnames_str, + strlen(pubnames_str))); + appendStringInfoChar(&cmd, ')'); + pfree(pubnames_str); + } else - snprintf(cmd, sizeof(cmd), - "START_REPLICATION %X/%X TIMELINE %u", - (uint32) (startpoint >> 32), (uint32) startpoint, tli); - res = libpqrcv_PQexec(cmd); + appendStringInfo(&cmd, " TIMELINE %u", + options->proto.physical.startpointTLI); + + /* Start streaming. */ + res = libpqrcv_PQexec(conn->streamConn, cmd.data); + pfree(cmd.data); if (PQresultStatus(res) == PGRES_COMMAND_OK) { @@ -261,7 +334,7 @@ libpqrcv_startstreaming(TimeLineID tli, XLogRecPtr startpoint, char *slotname) PQclear(res); ereport(ERROR, (errmsg("could not start WAL streaming: %s", - PQerrorMessage(streamConn)))); + PQerrorMessage(conn->streamConn)))); } PQclear(res); return true; @@ -272,14 +345,17 @@ libpqrcv_startstreaming(TimeLineID tli, XLogRecPtr startpoint, char *slotname) * reported by the server, or 0 if it did not report it. */ static void -libpqrcv_endstreaming(TimeLineID *next_tli) +libpqrcv_endstreaming(WalReceiverConn *conn, TimeLineID *next_tli) { PGresult *res; - if (PQputCopyEnd(streamConn, NULL) <= 0 || PQflush(streamConn)) + if (PQputCopyEnd(conn->streamConn, NULL) <= 0 || + PQflush(conn->streamConn)) ereport(ERROR, (errmsg("could not send end-of-streaming message to primary: %s", - PQerrorMessage(streamConn)))); + PQerrorMessage(conn->streamConn)))); + + *next_tli = 0; /* * After COPY is finished, we should receive a result set indicating the @@ -291,7 +367,7 @@ libpqrcv_endstreaming(TimeLineID *next_tli) * called after receiving CopyDone from the backend - the walreceiver * never terminates replication on its own initiative. */ - res = PQgetResult(streamConn); + res = PQgetResult(conn->streamConn); if (PQresultStatus(res) == PGRES_TUPLES_OK) { /* @@ -305,47 +381,58 @@ libpqrcv_endstreaming(TimeLineID *next_tli) PQclear(res); /* the result set should be followed by CommandComplete */ - res = PQgetResult(streamConn); + res = PQgetResult(conn->streamConn); + } + else if (PQresultStatus(res) == PGRES_COPY_OUT) + { + PQclear(res); + + /* End the copy */ + PQendcopy(conn->streamConn); + + /* CommandComplete should follow */ + res = PQgetResult(conn->streamConn); } - else - *next_tli = 0; if (PQresultStatus(res) != PGRES_COMMAND_OK) ereport(ERROR, (errmsg("error reading result of streaming command: %s", - PQerrorMessage(streamConn)))); + PQerrorMessage(conn->streamConn)))); PQclear(res); /* Verify that there are no more results */ - res = PQgetResult(streamConn); + res = PQgetResult(conn->streamConn); if (res != NULL) ereport(ERROR, (errmsg("unexpected result after CommandComplete: %s", - PQerrorMessage(streamConn)))); + PQerrorMessage(conn->streamConn)))); } /* * Fetch the timeline history file for 'tli' from primary. */ static void -libpqrcv_readtimelinehistoryfile(TimeLineID tli, - char **filename, char **content, int *len) +libpqrcv_readtimelinehistoryfile(WalReceiverConn *conn, + TimeLineID tli, char **filename, + char **content, int *len) { PGresult *res; char cmd[64]; + Assert(!conn->logical); + /* * Request the primary to send over the history file for given timeline. */ snprintf(cmd, sizeof(cmd), "TIMELINE_HISTORY %u", tli); - res = libpqrcv_PQexec(cmd); + res = libpqrcv_PQexec(conn->streamConn, cmd); if (PQresultStatus(res) != PGRES_TUPLES_OK) { PQclear(res); ereport(ERROR, (errmsg("could not receive timeline history file from " "the primary server: %s", - PQerrorMessage(streamConn)))); + PQerrorMessage(conn->streamConn)))); } if (PQnfields(res) != 2 || PQntuples(res) != 1) { @@ -366,85 +453,21 @@ libpqrcv_readtimelinehistoryfile(TimeLineID tli, PQclear(res); } -/* - * Wait until we can read WAL stream, or timeout. - * - * Returns true if data has become available for reading, false if timed out - * or interrupted by signal. - * - * This is based on pqSocketCheck. - */ -static bool -libpq_select(int timeout_ms) -{ - int ret; - - Assert(streamConn != NULL); - if (PQsocket(streamConn) < 0) - ereport(ERROR, - (errcode_for_socket_access(), - errmsg("invalid socket: %s", PQerrorMessage(streamConn)))); - - /* We use poll(2) if available, otherwise select(2) */ - { -#ifdef HAVE_POLL - struct pollfd input_fd; - - input_fd.fd = PQsocket(streamConn); - input_fd.events = POLLIN | POLLERR; - input_fd.revents = 0; - - ret = poll(&input_fd, 1, timeout_ms); -#else /* !HAVE_POLL */ - - fd_set input_mask; - struct timeval timeout; - struct timeval *ptr_timeout; - - FD_ZERO(&input_mask); - FD_SET(PQsocket(streamConn), &input_mask); - - if (timeout_ms < 0) - ptr_timeout = NULL; - else - { - timeout.tv_sec = timeout_ms / 1000; - timeout.tv_usec = (timeout_ms % 1000) * 1000; - ptr_timeout = &timeout; - } - - ret = select(PQsocket(streamConn) + 1, &input_mask, - NULL, NULL, ptr_timeout); -#endif /* HAVE_POLL */ - } - - if (ret == 0 || (ret < 0 && errno == EINTR)) - return false; - if (ret < 0) - ereport(ERROR, - (errcode_for_socket_access(), - errmsg("select() failed: %m"))); - return true; -} - /* * Send a query and wait for the results by using the asynchronous libpq - * functions and the backend version of select(). + * functions and socket readiness events. * * We must not use the regular blocking libpq functions like PQexec() * since they are uninterruptible by signals on some platforms, such as * Windows. * - * We must also not use vanilla select() here since it cannot handle the - * signal emulation layer on Windows. - * * The function is modeled on PQexec() in libpq, but only implements * those parts that are in use in the walreceiver. * * Queries are always executed on the connection in streamConn. */ static PGresult * -libpqrcv_PQexec(const char *query) +libpqrcv_PQexec(PGconn *streamConn, const char *query) { PGresult *result = NULL; PGresult *lastResult = NULL; @@ -470,14 +493,31 @@ libpqrcv_PQexec(const char *query) */ while (PQisBusy(streamConn)) { + int rc; + /* * We don't need to break down the sleep into smaller increments, - * and check for interrupts after each nap, since we can just - * elog(FATAL) within SIGTERM signal handler if the signal arrives - * in the middle of establishment of replication connection. + * since we'll get interrupted by signals and can either handle + * interrupts here or elog(FATAL) within SIGTERM signal handler if + * the signal arrives in the middle of establishment of + * replication connection. */ - if (!libpq_select(-1)) - continue; /* interrupted */ + ResetLatch(&MyProc->procLatch); + rc = WaitLatchOrSocket(&MyProc->procLatch, + WL_POSTMASTER_DEATH | WL_SOCKET_READABLE | + WL_LATCH_SET, + PQsocket(streamConn), + 0, + WAIT_EVENT_LIBPQWALRECEIVER_READ); + if (rc & WL_POSTMASTER_DEATH) + exit(1); + + /* interrupted */ + if (rc & WL_LATCH_SET) + { + CHECK_FOR_INTERRUPTS(); + continue; + } if (PQconsumeInput(streamConn) == 0) return NULL; /* trouble */ } @@ -508,10 +548,12 @@ libpqrcv_PQexec(const char *query) * Disconnect connection to primary, if any. */ static void -libpqrcv_disconnect(void) +libpqrcv_disconnect(WalReceiverConn *conn) { - PQfinish(streamConn); - streamConn = NULL; + PQfinish(conn->streamConn); + if (conn->recvBuf != NULL) + PQfreemem(conn->recvBuf); + pfree(conn); } /* @@ -531,30 +573,31 @@ libpqrcv_disconnect(void) * ereports on error. */ static int -libpqrcv_receive(char **buffer, pgsocket *wait_fd) +libpqrcv_receive(WalReceiverConn *conn, char **buffer, + pgsocket *wait_fd) { int rawlen; - if (recvBuf != NULL) - PQfreemem(recvBuf); - recvBuf = NULL; + if (conn->recvBuf != NULL) + PQfreemem(conn->recvBuf); + conn->recvBuf = NULL; /* Try to receive a CopyData message */ - rawlen = PQgetCopyData(streamConn, &recvBuf, 1); + rawlen = PQgetCopyData(conn->streamConn, &conn->recvBuf, 1); if (rawlen == 0) { /* Try consuming some data. */ - if (PQconsumeInput(streamConn) == 0) + if (PQconsumeInput(conn->streamConn) == 0) ereport(ERROR, (errmsg("could not receive data from WAL stream: %s", - PQerrorMessage(streamConn)))); + PQerrorMessage(conn->streamConn)))); /* Now that we've consumed some input, try again */ - rawlen = PQgetCopyData(streamConn, &recvBuf, 1); + rawlen = PQgetCopyData(conn->streamConn, &conn->recvBuf, 1); if (rawlen == 0) { /* Tell caller to try again when our socket is ready. */ - *wait_fd = PQsocket(streamConn); + *wait_fd = PQsocket(conn->streamConn); return 0; } } @@ -562,7 +605,7 @@ libpqrcv_receive(char **buffer, pgsocket *wait_fd) { PGresult *res; - res = PQgetResult(streamConn); + res = PQgetResult(conn->streamConn); if (PQresultStatus(res) == PGRES_COMMAND_OK || PQresultStatus(res) == PGRES_COPY_IN) { @@ -574,16 +617,16 @@ libpqrcv_receive(char **buffer, pgsocket *wait_fd) PQclear(res); ereport(ERROR, (errmsg("could not receive data from WAL stream: %s", - PQerrorMessage(streamConn)))); + PQerrorMessage(conn->streamConn)))); } } if (rawlen < -1) ereport(ERROR, (errmsg("could not receive data from WAL stream: %s", - PQerrorMessage(streamConn)))); + PQerrorMessage(conn->streamConn)))); /* Return received messages to caller */ - *buffer = recvBuf; + *buffer = conn->recvBuf; return rawlen; } @@ -593,11 +636,115 @@ libpqrcv_receive(char **buffer, pgsocket *wait_fd) * ereports on error. */ static void -libpqrcv_send(const char *buffer, int nbytes) +libpqrcv_send(WalReceiverConn *conn, const char *buffer, int nbytes) { - if (PQputCopyData(streamConn, buffer, nbytes) <= 0 || - PQflush(streamConn)) + if (PQputCopyData(conn->streamConn, buffer, nbytes) <= 0 || + PQflush(conn->streamConn)) ereport(ERROR, (errmsg("could not send data to WAL stream: %s", - PQerrorMessage(streamConn)))); + PQerrorMessage(conn->streamConn)))); +} + +/* + * Create new replication slot. + * Returns the name of the exported snapshot for logical slot or NULL for + * physical slot. + */ +static char * +libpqrcv_create_slot(WalReceiverConn *conn, const char *slotname, + bool temporary, XLogRecPtr *lsn) +{ + PGresult *res; + StringInfoData cmd; + char *snapshot; + + initStringInfo(&cmd); + + appendStringInfo(&cmd, "CREATE_REPLICATION_SLOT \"%s\" ", slotname); + + if (temporary) + appendStringInfo(&cmd, "TEMPORARY "); + + if (conn->logical) + appendStringInfo(&cmd, "LOGICAL pgoutput"); + + res = libpqrcv_PQexec(conn->streamConn, cmd.data); + pfree(cmd.data); + + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + PQclear(res); + ereport(ERROR, + (errmsg("could not create replication slot \"%s\": %s", + slotname, PQerrorMessage(conn->streamConn)))); + } + + *lsn = DatumGetLSN(DirectFunctionCall1Coll(pg_lsn_in, InvalidOid, + CStringGetDatum(PQgetvalue(res, 0, 1)))); + if (!PQgetisnull(res, 0, 2)) + snapshot = pstrdup(PQgetvalue(res, 0, 2)); + else + snapshot = NULL; + + PQclear(res); + + return snapshot; +} + +/* + * Run command. + * + * Returns if the command has succeeded and fills the err with palloced + * error message if not. + */ +static bool +libpqrcv_command(WalReceiverConn *conn, const char *cmd, char **err) +{ + PGresult *res; + + res = libpqrcv_PQexec(conn->streamConn, cmd); + + if (PQresultStatus(res) != PGRES_COMMAND_OK) + { + PQclear(res); + *err = pstrdup(PQerrorMessage(conn->streamConn)); + return false; + } + + PQclear(res); + + return true; +} + +/* + * Given a List of strings, return it as single comma separated + * string, quoting identifiers as needed. + * + * This is essentially the reverse of SplitIdentifierString. + * + * The caller should free the result. + */ +static char * +stringlist_to_identifierstr(PGconn *conn, List *strings) +{ + ListCell *lc; + StringInfoData res; + bool first = true; + + initStringInfo(&res); + + foreach (lc, strings) + { + char *val = strVal(lfirst(lc)); + + if (first) + first = false; + else + appendStringInfoChar(&res, ','); + + appendStringInfoString(&res, + PQescapeIdentifier(conn, val, strlen(val))); + } + + return res.data; } diff --git a/src/backend/replication/logical/Makefile b/src/backend/replication/logical/Makefile index 1d7ca062d1..259befa4e6 100644 --- a/src/backend/replication/logical/Makefile +++ b/src/backend/replication/logical/Makefile @@ -14,7 +14,7 @@ include $(top_builddir)/src/Makefile.global override CPPFLAGS := -I$(srcdir) $(CPPFLAGS) -OBJS = decode.o logical.o logicalfuncs.o message.o origin.o reorderbuffer.o \ - snapbuild.o +OBJS = decode.o launcher.o logical.o logicalfuncs.o message.o origin.o \ + proto.o relation.o reorderbuffer.o snapbuild.o worker.o include $(top_srcdir)/src/backend/common.mk diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c index 46cd5ba1f2..5c13d26099 100644 --- a/src/backend/replication/logical/decode.c +++ b/src/backend/replication/logical/decode.c @@ -16,7 +16,7 @@ * contents of records in here except turning them into a more usable * format. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c new file mode 100644 index 0000000000..b5240dcede --- /dev/null +++ b/src/backend/replication/logical/launcher.c @@ -0,0 +1,759 @@ +/*------------------------------------------------------------------------- + * launcher.c + * PostgreSQL logical replication worker launcher process + * + * Copyright (c) 2012-2016, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/backend/replication/logical/launcher.c + * + * NOTES + * This module contains the logical replication worker launcher which + * uses the background worker infrastructure to start the logical + * replication workers for every enabled subscription. + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "funcapi.h" +#include "miscadmin.h" +#include "pgstat.h" + +#include "access/heapam.h" +#include "access/htup.h" +#include "access/htup_details.h" +#include "access/xact.h" + +#include "catalog/pg_subscription.h" + +#include "libpq/pqsignal.h" + +#include "postmaster/bgworker.h" +#include "postmaster/fork_process.h" +#include "postmaster/postmaster.h" + +#include "replication/logicallauncher.h" +#include "replication/logicalworker.h" +#include "replication/slot.h" +#include "replication/worker_internal.h" + +#include "storage/ipc.h" +#include "storage/proc.h" +#include "storage/procarray.h" +#include "storage/procsignal.h" + +#include "tcop/tcopprot.h" + +#include "utils/memutils.h" +#include "utils/pg_lsn.h" +#include "utils/ps_status.h" +#include "utils/timeout.h" +#include "utils/snapmgr.h" + +/* max sleep time between cycles (3min) */ +#define DEFAULT_NAPTIME_PER_CYCLE 180000L + +int max_logical_replication_workers = 4; +LogicalRepWorker *MyLogicalRepWorker = NULL; + +typedef struct LogicalRepCtxStruct +{ + /* Supervisor process. */ + pid_t launcher_pid; + + /* Background workers. */ + LogicalRepWorker workers[FLEXIBLE_ARRAY_MEMBER]; +} LogicalRepCtxStruct; + +LogicalRepCtxStruct *LogicalRepCtx; + +static void logicalrep_worker_onexit(int code, Datum arg); +static void logicalrep_worker_detach(void); + +bool got_SIGTERM = false; +static bool on_commit_laucher_wakeup = false; + +Datum pg_stat_get_subscription(PG_FUNCTION_ARGS); + + +/* + * Load the list of subscriptions. + * + * Only the fields interesting for worker start/stop functions are filled for + * each subscription. + */ +static List * +get_subscription_list(void) +{ + List *res = NIL; + Relation rel; + HeapScanDesc scan; + HeapTuple tup; + MemoryContext resultcxt; + + /* This is the context that we will allocate our output data in */ + resultcxt = CurrentMemoryContext; + + /* + * Start a transaction so we can access pg_database, and get a snapshot. + * We don't have a use for the snapshot itself, but we're interested in + * the secondary effect that it sets RecentGlobalXmin. (This is critical + * for anything that reads heap pages, because HOT may decide to prune + * them even if the process doesn't attempt to modify any tuples.) + */ + StartTransactionCommand(); + (void) GetTransactionSnapshot(); + + rel = heap_open(SubscriptionRelationId, AccessShareLock); + scan = heap_beginscan_catalog(rel, 0, NULL); + + while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection))) + { + Form_pg_subscription subform = (Form_pg_subscription) GETSTRUCT(tup); + Subscription *sub; + MemoryContext oldcxt; + + /* + * Allocate our results in the caller's context, not the + * transaction's. We do this inside the loop, and restore the original + * context at the end, so that leaky things like heap_getnext() are + * not called in a potentially long-lived context. + */ + oldcxt = MemoryContextSwitchTo(resultcxt); + + sub = (Subscription *) palloc(sizeof(Subscription)); + sub->oid = HeapTupleGetOid(tup); + sub->dbid = subform->subdbid; + sub->owner = subform->subowner; + sub->enabled = subform->subenabled; + sub->name = pstrdup(NameStr(subform->subname)); + + /* We don't fill fields we are not interested in. */ + sub->conninfo = NULL; + sub->slotname = NULL; + sub->publications = NIL; + + res = lappend(res, sub); + MemoryContextSwitchTo(oldcxt); + } + + heap_endscan(scan); + heap_close(rel, AccessShareLock); + + CommitTransactionCommand(); + + return res; +} + +/* + * Wait for a background worker to start up and attach to the shmem context. + * + * This is like WaitForBackgroundWorkerStartup(), except that we wait for + * attaching, not just start and we also just exit if postmaster died. + */ +static bool +WaitForReplicationWorkerAttach(LogicalRepWorker *worker, + BackgroundWorkerHandle *handle) +{ + BgwHandleStatus status; + int rc; + + for (;;) + { + pid_t pid; + + CHECK_FOR_INTERRUPTS(); + + status = GetBackgroundWorkerPid(handle, &pid); + + /* + * Worker started and attached to our shmem. This check is safe + * because only laucher ever starts the workers, so nobody can steal + * the worker slot. + */ + if (status == BGWH_STARTED && worker->proc) + return true; + /* Worker didn't start or died before attaching to our shmem. */ + if (status == BGWH_STOPPED) + return false; + + /* + * We need timeout because we generaly don't get notified via latch + * about the worker attach. + */ + rc = WaitLatch(MyLatch, + WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, + 1000L, WAIT_EVENT_BGWORKER_STARTUP); + + if (rc & WL_POSTMASTER_DEATH) + proc_exit(1); + + ResetLatch(MyLatch); + } + + return false; +} + +/* + * Walks the workers array and searches for one that matches given + * subscription id. + */ +LogicalRepWorker * +logicalrep_worker_find(Oid subid) +{ + int i; + LogicalRepWorker *res = NULL; + + Assert(LWLockHeldByMe(LogicalRepWorkerLock)); + /* Search for attached worker for a given subscription id. */ + for (i = 0; i < max_logical_replication_workers; i++) + { + LogicalRepWorker *w = &LogicalRepCtx->workers[i]; + if (w->subid == subid && w->proc && IsBackendPid(w->proc->pid)) + { + res = w; + break; + } + } + + return res; +} + +/* + * Start new apply background worker. + */ +void +logicalrep_worker_launch(Oid dbid, Oid subid, const char *subname, Oid userid) +{ + BackgroundWorker bgw; + BackgroundWorkerHandle *bgw_handle; + int slot; + LogicalRepWorker *worker = NULL; + + ereport(LOG, + (errmsg("starting logical replication worker for subscription \"%s\"", + subname))); + + /* Report this after the initial starting message for consistency. */ + if (max_replication_slots == 0) + ereport(ERROR, + (errcode(ERRCODE_CONFIGURATION_LIMIT_EXCEEDED), + errmsg("cannot start logical replication workers when max_replication_slots = 0"))); + + /* + * We need to do the modification of the shared memory under lock so that + * we have consistent view. + */ + LWLockAcquire(LogicalRepWorkerLock, LW_EXCLUSIVE); + + /* Find unused worker slot. */ + for (slot = 0; slot < max_logical_replication_workers; slot++) + { + if (!LogicalRepCtx->workers[slot].proc) + { + worker = &LogicalRepCtx->workers[slot]; + break; + } + } + + /* Bail if not found */ + if (worker == NULL) + { + ereport(WARNING, + (errcode(ERRCODE_CONFIGURATION_LIMIT_EXCEEDED), + errmsg("out of logical replication workers slots"), + errhint("You might need to increase max_logical_replication_workers."))); + return; + } + + /* Prepare the worker info. */ + memset(worker, 0, sizeof(LogicalRepWorker)); + worker->dbid = dbid; + worker->userid = userid; + worker->subid = subid; + + LWLockRelease(LogicalRepWorkerLock); + + /* Register the new dynamic worker. */ + bgw.bgw_flags = BGWORKER_SHMEM_ACCESS | + BGWORKER_BACKEND_DATABASE_CONNECTION; + bgw.bgw_start_time = BgWorkerStart_RecoveryFinished; + bgw.bgw_main = ApplyWorkerMain; + snprintf(bgw.bgw_name, BGW_MAXLEN, + "logical replication worker for subscription %u", subid); + + bgw.bgw_restart_time = BGW_NEVER_RESTART; + bgw.bgw_notify_pid = MyProcPid; + bgw.bgw_main_arg = slot; + + if (!RegisterDynamicBackgroundWorker(&bgw, &bgw_handle)) + { + ereport(WARNING, + (errcode(ERRCODE_CONFIGURATION_LIMIT_EXCEEDED), + errmsg("out of background workers slots"), + errhint("You might need to increase max_worker_processes."))); + return; + } + + /* Now wait until it attaches. */ + WaitForReplicationWorkerAttach(worker, bgw_handle); +} + +/* + * Stop the logical replication worker and wait until it detaches from the + * slot. + * + * The caller must hold LogicalRepLauncherLock to ensure that new workers are + * not being started during this function call. + */ +void +logicalrep_worker_stop(Oid subid) +{ + LogicalRepWorker *worker; + + Assert(LWLockHeldByMe(LogicalRepLauncherLock)); + + LWLockAcquire(LogicalRepWorkerLock, LW_SHARED); + + worker = logicalrep_worker_find(subid); + + /* No worker, nothing to do. */ + if (!worker) + { + LWLockRelease(LogicalRepWorkerLock); + return; + } + + /* + * If we found worker but it does not have proc set it is starting up, + * wait for it to finish and then kill it. + */ + while (worker && !worker->proc) + { + int rc; + + LWLockRelease(LogicalRepWorkerLock); + + CHECK_FOR_INTERRUPTS(); + + /* Wait for signal. */ + rc = WaitLatch(&MyProc->procLatch, + WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, + 1000L, WAIT_EVENT_BGWORKER_STARTUP); + + /* emergency bailout if postmaster has died */ + if (rc & WL_POSTMASTER_DEATH) + proc_exit(1); + + ResetLatch(&MyProc->procLatch); + + /* Check if the worker has started. */ + LWLockAcquire(LogicalRepWorkerLock, LW_SHARED); + worker = logicalrep_worker_find(subid); + if (!worker || worker->proc) + break; + } + + /* Now terminate the worker ... */ + kill(worker->proc->pid, SIGTERM); + LWLockRelease(LogicalRepWorkerLock); + + /* ... and wait for it to die. */ + for (;;) + { + int rc; + + LWLockAcquire(LogicalRepWorkerLock, LW_SHARED); + if (!worker->proc) + { + LWLockRelease(LogicalRepWorkerLock); + break; + } + LWLockRelease(LogicalRepWorkerLock); + + CHECK_FOR_INTERRUPTS(); + + /* Wait for more work. */ + rc = WaitLatch(&MyProc->procLatch, + WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, + 1000L, WAIT_EVENT_BGWORKER_SHUTDOWN); + + /* emergency bailout if postmaster has died */ + if (rc & WL_POSTMASTER_DEATH) + proc_exit(1); + + ResetLatch(&MyProc->procLatch); + } +} + +/* + * Attach to a slot. + */ +void +logicalrep_worker_attach(int slot) +{ + /* Block concurrent access. */ + LWLockAcquire(LogicalRepWorkerLock, LW_EXCLUSIVE); + + Assert(slot >= 0 && slot < max_logical_replication_workers); + MyLogicalRepWorker = &LogicalRepCtx->workers[slot]; + + if (MyLogicalRepWorker->proc) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("logical replication worker slot %d already used by " + "another worker", slot))); + + MyLogicalRepWorker->proc = MyProc; + before_shmem_exit(logicalrep_worker_onexit, (Datum) 0); + + LWLockRelease(LogicalRepWorkerLock); +} + +/* + * Detach the worker (cleans up the worker info). + */ +static void +logicalrep_worker_detach(void) +{ + /* Block concurrent access. */ + LWLockAcquire(LogicalRepWorkerLock, LW_EXCLUSIVE); + + MyLogicalRepWorker->dbid = InvalidOid; + MyLogicalRepWorker->userid = InvalidOid; + MyLogicalRepWorker->subid = InvalidOid; + MyLogicalRepWorker->proc = NULL; + + LWLockRelease(LogicalRepWorkerLock); +} + +/* + * Cleanup function. + * + * Called on logical replication worker exit. + */ +static void +logicalrep_worker_onexit(int code, Datum arg) +{ + logicalrep_worker_detach(); +} + +/* SIGTERM: set flag to exit at next convenient time */ +void +logicalrep_worker_sigterm(SIGNAL_ARGS) +{ + got_SIGTERM = true; + + /* Waken anything waiting on the process latch */ + SetLatch(MyLatch); +} + +/* + * ApplyLauncherShmemSize + * Compute space needed for replication launcher shared memory + */ +Size +ApplyLauncherShmemSize(void) +{ + Size size; + + /* + * Need the fixed struct and the array of LogicalRepWorker. + */ + size = sizeof(LogicalRepCtxStruct); + size = MAXALIGN(size); + size = add_size(size, mul_size(max_logical_replication_workers, + sizeof(LogicalRepWorker))); + return size; +} + +void +ApplyLauncherRegister(void) +{ + BackgroundWorker bgw; + + if (max_logical_replication_workers == 0) + return; + + bgw.bgw_flags = BGWORKER_SHMEM_ACCESS | + BGWORKER_BACKEND_DATABASE_CONNECTION; + bgw.bgw_start_time = BgWorkerStart_RecoveryFinished; + bgw.bgw_main = ApplyLauncherMain; + snprintf(bgw.bgw_name, BGW_MAXLEN, + "logical replication launcher"); + bgw.bgw_restart_time = 5; + bgw.bgw_notify_pid = 0; + bgw.bgw_main_arg = (Datum) 0; + + RegisterBackgroundWorker(&bgw); +} + +/* + * ApplyLauncherShmemInit + * Allocate and initialize replication launcher shared memory + */ +void +ApplyLauncherShmemInit(void) +{ + bool found; + + LogicalRepCtx = (LogicalRepCtxStruct *) + ShmemInitStruct("Logical Replication Launcher Data", + ApplyLauncherShmemSize(), + &found); + + if (!found) + memset(LogicalRepCtx, 0, ApplyLauncherShmemSize()); +} + +/* + * Wakeup the launcher on commit if requested. + */ +void +AtCommit_ApplyLauncher(void) +{ + if (on_commit_laucher_wakeup) + ApplyLauncherWakeup(); +} + +/* + * Request wakeup of the launcher on commit of the transaction. + * + * This is used to send launcher signal to stop sleeping and proccess the + * subscriptions when current transaction commits. Should be used when new + * tuple was added to the pg_subscription catalog. +*/ +void +ApplyLauncherWakeupAtCommit(void) +{ + if (!on_commit_laucher_wakeup) + on_commit_laucher_wakeup = true; +} + +void +ApplyLauncherWakeup(void) +{ + if (IsBackendPid(LogicalRepCtx->launcher_pid)) + kill(LogicalRepCtx->launcher_pid, SIGUSR1); +} + +/* + * Main loop for the apply launcher process. + */ +void +ApplyLauncherMain(Datum main_arg) +{ + ereport(LOG, + (errmsg("logical replication launcher started"))); + + /* Establish signal handlers. */ + pqsignal(SIGTERM, logicalrep_worker_sigterm); + BackgroundWorkerUnblockSignals(); + + /* Make it easy to identify our processes. */ + SetConfigOption("application_name", MyBgworkerEntry->bgw_name, + PGC_USERSET, PGC_S_SESSION); + + LogicalRepCtx->launcher_pid = MyProcPid; + + /* + * Establish connection to nailed catalogs (we only ever access + * pg_subscription). + */ + BackgroundWorkerInitializeConnection(NULL, NULL); + + /* Enter main loop */ + while (!got_SIGTERM) + { + int rc; + List *sublist; + ListCell *lc; + MemoryContext subctx; + MemoryContext oldctx; + TimestampTz now; + TimestampTz last_start_time = 0; + long wait_time = DEFAULT_NAPTIME_PER_CYCLE; + + now = GetCurrentTimestamp(); + + /* Limit the start retry to once a wal_retrieve_retry_interval */ + if (TimestampDifferenceExceeds(last_start_time, now, + wal_retrieve_retry_interval)) + { + /* Use temporary context for the database list and worker info. */ + subctx = AllocSetContextCreate(TopMemoryContext, + "Logical Replication Launcher sublist", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + oldctx = MemoryContextSwitchTo(subctx); + + /* Block any concurrent DROP SUBSCRIPTION. */ + LWLockAcquire(LogicalRepLauncherLock, LW_EXCLUSIVE); + + /* search for subscriptions to start or stop. */ + sublist = get_subscription_list(); + + /* Start the missing workers for enabled subscriptions. */ + foreach(lc, sublist) + { + Subscription *sub = (Subscription *) lfirst(lc); + LogicalRepWorker *w; + + LWLockAcquire(LogicalRepWorkerLock, LW_SHARED); + w = logicalrep_worker_find(sub->oid); + LWLockRelease(LogicalRepWorkerLock); + + if (sub->enabled && w == NULL) + { + logicalrep_worker_launch(sub->dbid, sub->oid, sub->name, sub->owner); + last_start_time = now; + wait_time = wal_retrieve_retry_interval; + /* Limit to one worker per mainloop cycle. */ + break; + } + } + + LWLockRelease(LogicalRepLauncherLock); + + /* Switch back to original memory context. */ + MemoryContextSwitchTo(oldctx); + /* Clean the temporary memory. */ + MemoryContextDelete(subctx); + } + else + { + /* + * The wait in previous cycle was interruped in less than + * wal_retrieve_retry_interval since last worker was started, + * this usually means crash of the worker, so we should retry + * in wal_retrieve_retry_interval again. + */ + wait_time = wal_retrieve_retry_interval; + } + + /* Wait for more work. */ + rc = WaitLatch(&MyProc->procLatch, + WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, + wait_time, + WAIT_EVENT_LOGICAL_LAUNCHER_MAIN); + + /* emergency bailout if postmaster has died */ + if (rc & WL_POSTMASTER_DEATH) + proc_exit(1); + + ResetLatch(&MyProc->procLatch); + } + + LogicalRepCtx->launcher_pid = 0; + + /* ... and if it returns, we're done */ + ereport(LOG, + (errmsg("logical replication launcher shutting down"))); + + proc_exit(0); +} + +/* + * Returns state of the subscriptions. + */ +Datum +pg_stat_get_subscription(PG_FUNCTION_ARGS) +{ +#define PG_STAT_GET_SUBSCRIPTION_COLS 7 + Oid subid = PG_ARGISNULL(0) ? InvalidOid : PG_GETARG_OID(0); + int i; + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + TupleDesc tupdesc; + Tuplestorestate *tupstore; + MemoryContext per_query_ctx; + MemoryContext oldcontext; + + /* check to see if caller supports us returning a tuplestore */ + if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("set-valued function called in context that cannot accept a set"))); + if (!(rsinfo->allowedModes & SFRM_Materialize)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("materialize mode required, but it is not " \ + "allowed in this context"))); + + /* Build a tuple descriptor for our result type */ + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + elog(ERROR, "return type must be a row type"); + + per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; + oldcontext = MemoryContextSwitchTo(per_query_ctx); + + tupstore = tuplestore_begin_heap(true, false, work_mem); + rsinfo->returnMode = SFRM_Materialize; + rsinfo->setResult = tupstore; + rsinfo->setDesc = tupdesc; + + MemoryContextSwitchTo(oldcontext); + + /* Make sure we get consistent view of the workers. */ + LWLockAcquire(LogicalRepWorkerLock, LW_SHARED); + + for (i = 0; i <= max_logical_replication_workers; i++) + { + /* for each row */ + Datum values[PG_STAT_GET_SUBSCRIPTION_COLS]; + bool nulls[PG_STAT_GET_SUBSCRIPTION_COLS]; + int worker_pid; + LogicalRepWorker worker; + + memcpy(&worker, &LogicalRepCtx->workers[i], + sizeof(LogicalRepWorker)); + if (!worker.proc || !IsBackendPid(worker.proc->pid)) + continue; + + if (OidIsValid(subid) && worker.subid != subid) + continue; + + worker_pid = worker.proc->pid; + + MemSet(values, 0, sizeof(values)); + MemSet(nulls, 0, sizeof(nulls)); + + values[0] = ObjectIdGetDatum(worker.subid); + values[1] = Int32GetDatum(worker_pid); + if (XLogRecPtrIsInvalid(worker.last_lsn)) + nulls[2] = true; + else + values[2] = LSNGetDatum(worker.last_lsn); + if (worker.last_send_time == 0) + nulls[3] = true; + else + values[3] = TimestampTzGetDatum(worker.last_send_time); + if (worker.last_recv_time == 0) + nulls[4] = true; + else + values[4] = TimestampTzGetDatum(worker.last_recv_time); + if (XLogRecPtrIsInvalid(worker.reply_lsn)) + nulls[5] = true; + else + values[5] = LSNGetDatum(worker.reply_lsn); + if (worker.reply_time == 0) + nulls[6] = true; + else + values[6] = TimestampTzGetDatum(worker.reply_time); + + tuplestore_putvalues(tupstore, tupdesc, values, nulls); + + /* If only a single subscription was requested, and we found it, break. */ + if (OidIsValid(subid)) + break; + } + + LWLockRelease(LogicalRepWorkerLock); + + /* clean up and return the tuplestore */ + tuplestore_donestoring(tupstore); + + return (Datum) 0; +} diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c index ecf9a03318..5529ac8fb4 100644 --- a/src/backend/replication/logical/logical.c +++ b/src/backend/replication/logical/logical.c @@ -2,7 +2,7 @@ * logical.c * PostgreSQL logical decoding coordination * - * Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Copyright (c) 2012-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/logical/logical.c @@ -127,10 +127,8 @@ StartupDecodingContext(List *output_plugin_options, slot = MyReplicationSlot; context = AllocSetContextCreate(CurrentMemoryContext, - "Logical Decoding Context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + "Logical decoding context", + ALLOCSET_DEFAULT_SIZES); old_context = MemoryContextSwitchTo(context); ctx = palloc0(sizeof(LogicalDecodingContext)); diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c index 4e4c8cdaeb..41c50005d7 100644 --- a/src/backend/replication/logical/logicalfuncs.c +++ b/src/backend/replication/logical/logicalfuncs.c @@ -6,7 +6,7 @@ * logical replication slots via SQL. * * - * Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Copyright (c) 2012-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/logicalfuncs.c @@ -37,6 +37,7 @@ #include "utils/inval.h" #include "utils/memutils.h" #include "utils/pg_lsn.h" +#include "utils/regproc.h" #include "utils/resowner.h" #include "utils/lsyscache.h" @@ -225,7 +226,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin char *name = TextDatumGetCString(datum_opts[i]); char *opt = TextDatumGetCString(datum_opts[i + 1]); - options = lappend(options, makeDefElem(name, (Node *) makeString(opt))); + options = lappend(options, makeDefElem(name, (Node *) makeString(opt), -1)); } } @@ -321,7 +322,22 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin * business..) */ if (ctx->reader->EndRecPtr != InvalidXLogRecPtr && confirm) + { LogicalConfirmReceivedLocation(ctx->reader->EndRecPtr); + /* + * If only the confirmed_flush_lsn has changed the slot won't get + * marked as dirty by the above. Callers on the walsender interface + * are expected to keep track of their own progress and don't need + * it written out. But SQL-interface users cannot specify their own + * start positions and it's harder for them to keep track of their + * progress, so we should make more of an effort to save it for them. + * + * Dirty the slot so it's written out at the next checkpoint. We'll + * still lose its position on crash, as documented, but it's better + * than always losing the position even on clean restart. + */ + ReplicationSlotMarkDirty(); + } /* free context, call shutdown callback */ FreeDecodingContext(ctx); diff --git a/src/backend/replication/logical/message.c b/src/backend/replication/logical/message.c index 8f9dc2f47c..0dc3a9b014 100644 --- a/src/backend/replication/logical/message.c +++ b/src/backend/replication/logical/message.c @@ -3,7 +3,7 @@ * message.c * Generic logical messages. * - * Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Copyright (c) 2013-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/logical/message.c @@ -73,7 +73,7 @@ LogLogicalMessage(const char *prefix, const char *message, size_t size, XLogRegisterData((char *) message, size); /* allow origin filtering */ - XLogIncludeOrigin(); + XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN); return XLogInsert(RM_LOGICALMSG_ID, XLOG_LOGICAL_MESSAGE); } diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c index cc2b513236..d7dda6a7b8 100644 --- a/src/backend/replication/logical/origin.c +++ b/src/backend/replication/logical/origin.c @@ -3,7 +3,7 @@ * origin.c * Logical replication progress tracking support. * - * Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Copyright (c) 2013-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/logical/origin.c @@ -143,7 +143,6 @@ typedef struct ReplicationStateOnDisk typedef struct ReplicationStateCtl { int tranche_id; - LWLockTranche tranche; ReplicationState states[FLEXIBLE_ARRAY_MEMBER]; } ReplicationStateCtl; @@ -474,11 +473,6 @@ ReplicationOriginShmemInit(void) int i; replication_states_ctl->tranche_id = LWTRANCHE_REPLICATION_ORIGIN; - replication_states_ctl->tranche.name = "replication_origin"; - replication_states_ctl->tranche.array_base = - &replication_states[0].lock; - replication_states_ctl->tranche.array_stride = - sizeof(ReplicationState); MemSet(replication_states, 0, ReplicationOriginShmemSize()); @@ -488,7 +482,7 @@ ReplicationOriginShmemInit(void) } LWLockRegisterTranche(replication_states_ctl->tranche_id, - &replication_states_ctl->tranche); + "replication_origin"); } /* --------------------------------------------------------------------------- diff --git a/src/backend/replication/logical/proto.c b/src/backend/replication/logical/proto.c new file mode 100644 index 0000000000..1f30de606a --- /dev/null +++ b/src/backend/replication/logical/proto.c @@ -0,0 +1,637 @@ +/*------------------------------------------------------------------------- + * + * proto.c + * logical replication protocol functions + * + * Copyright (c) 2015, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/backend/replication/logical/proto.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/sysattr.h" +#include "catalog/pg_namespace.h" +#include "catalog/pg_type.h" +#include "libpq/pqformat.h" +#include "replication/logicalproto.h" +#include "utils/builtins.h" +#include "utils/lsyscache.h" +#include "utils/syscache.h" + +/* + * Protocol message flags. + */ +#define LOGICALREP_IS_REPLICA_IDENTITY 1 + +static void logicalrep_write_attrs(StringInfo out, Relation rel); +static void logicalrep_write_tuple(StringInfo out, Relation rel, + HeapTuple tuple); + +static void logicalrep_read_attrs(StringInfo in, LogicalRepRelation *rel); +static void logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple); + +static void logicalrep_write_namespace(StringInfo out, Oid nspid); +static const char *logicalrep_read_namespace(StringInfo in); + +/* + * Write BEGIN to the output stream. + */ +void +logicalrep_write_begin(StringInfo out, ReorderBufferTXN *txn) +{ + pq_sendbyte(out, 'B'); /* BEGIN */ + + /* fixed fields */ + pq_sendint64(out, txn->final_lsn); + pq_sendint64(out, txn->commit_time); + pq_sendint(out, txn->xid, 4); +} + +/* + * Read transaction BEGIN from the stream. + */ +void +logicalrep_read_begin(StringInfo in, LogicalRepBeginData *begin_data) +{ + /* read fields */ + begin_data->final_lsn = pq_getmsgint64(in); + if (begin_data->final_lsn == InvalidXLogRecPtr) + elog(ERROR, "final_lsn not set in begin message"); + begin_data->committime = pq_getmsgint64(in); + begin_data->xid = pq_getmsgint(in, 4); +} + + +/* + * Write COMMIT to the output stream. + */ +void +logicalrep_write_commit(StringInfo out, ReorderBufferTXN *txn, + XLogRecPtr commit_lsn) +{ + uint8 flags = 0; + + pq_sendbyte(out, 'C'); /* sending COMMIT */ + + /* send the flags field (unused for now) */ + pq_sendbyte(out, flags); + + /* send fields */ + pq_sendint64(out, commit_lsn); + pq_sendint64(out, txn->end_lsn); + pq_sendint64(out, txn->commit_time); +} + +/* + * Read transaction COMMIT from the stream. + */ +void +logicalrep_read_commit(StringInfo in, LogicalRepCommitData *commit_data) +{ + /* read flags (unused for now) */ + uint8 flags = pq_getmsgbyte(in); + + if (flags != 0) + elog(ERROR, "unknown flags %u in commit message", flags); + + /* read fields */ + commit_data->commit_lsn = pq_getmsgint64(in); + commit_data->end_lsn = pq_getmsgint64(in); + commit_data->committime = pq_getmsgint64(in); +} + +/* + * Write ORIGIN to the output stream. + */ +void +logicalrep_write_origin(StringInfo out, const char *origin, + XLogRecPtr origin_lsn) +{ + pq_sendbyte(out, 'O'); /* ORIGIN */ + + /* fixed fields */ + pq_sendint64(out, origin_lsn); + + /* origin string */ + pq_sendstring(out, origin); +} + +/* + * Read ORIGIN from the output stream. + */ +char * +logicalrep_read_origin(StringInfo in, XLogRecPtr *origin_lsn) +{ + /* fixed fields */ + *origin_lsn = pq_getmsgint64(in); + + /* return origin */ + return pstrdup(pq_getmsgstring(in)); +} + +/* + * Write INSERT to the output stream. + */ +void +logicalrep_write_insert(StringInfo out, Relation rel, HeapTuple newtuple) +{ + pq_sendbyte(out, 'I'); /* action INSERT */ + + Assert(rel->rd_rel->relreplident == REPLICA_IDENTITY_DEFAULT || + rel->rd_rel->relreplident == REPLICA_IDENTITY_FULL || + rel->rd_rel->relreplident == REPLICA_IDENTITY_INDEX); + + /* use Oid as relation identifier */ + pq_sendint(out, RelationGetRelid(rel), 4); + + pq_sendbyte(out, 'N'); /* new tuple follows */ + logicalrep_write_tuple(out, rel, newtuple); +} + +/* + * Read INSERT from stream. + * + * Fills the new tuple. + */ +LogicalRepRelId +logicalrep_read_insert(StringInfo in, LogicalRepTupleData *newtup) +{ + char action; + LogicalRepRelId relid; + + /* read the relation id */ + relid = pq_getmsgint(in, 4); + + action = pq_getmsgbyte(in); + if (action != 'N') + elog(ERROR, "expected new tuple but got %d", + action); + + logicalrep_read_tuple(in, newtup); + + return relid; +} + +/* + * Write UPDATE to the output stream. + */ +void +logicalrep_write_update(StringInfo out, Relation rel, HeapTuple oldtuple, + HeapTuple newtuple) +{ + pq_sendbyte(out, 'U'); /* action UPDATE */ + + Assert(rel->rd_rel->relreplident == REPLICA_IDENTITY_DEFAULT || + rel->rd_rel->relreplident == REPLICA_IDENTITY_FULL || + rel->rd_rel->relreplident == REPLICA_IDENTITY_INDEX); + + /* use Oid as relation identifier */ + pq_sendint(out, RelationGetRelid(rel), 4); + + if (oldtuple != NULL) + { + if (rel->rd_rel->relreplident == REPLICA_IDENTITY_FULL) + pq_sendbyte(out, 'O'); /* old tuple follows */ + else + pq_sendbyte(out, 'K'); /* old key follows */ + logicalrep_write_tuple(out, rel, oldtuple); + } + + pq_sendbyte(out, 'N'); /* new tuple follows */ + logicalrep_write_tuple(out, rel, newtuple); +} + +/* + * Read UPDATE from stream. + */ +LogicalRepRelId +logicalrep_read_update(StringInfo in, bool *has_oldtuple, + LogicalRepTupleData *oldtup, + LogicalRepTupleData *newtup) +{ + char action; + LogicalRepRelId relid; + + /* read the relation id */ + relid = pq_getmsgint(in, 4); + + /* read and verify action */ + action = pq_getmsgbyte(in); + if (action != 'K' && action != 'O' && action != 'N') + elog(ERROR, "expected action 'N', 'O' or 'K', got %c", + action); + + /* check for old tuple */ + if (action == 'K' || action == 'O') + { + logicalrep_read_tuple(in, oldtup); + *has_oldtuple = true; + + action = pq_getmsgbyte(in); + } + else + *has_oldtuple = false; + + /* check for new tuple */ + if (action != 'N') + elog(ERROR, "expected action 'N', got %c", + action); + + logicalrep_read_tuple(in, newtup); + + return relid; +} + +/* + * Write DELETE to the output stream. + */ +void +logicalrep_write_delete(StringInfo out, Relation rel, HeapTuple oldtuple) +{ + Assert(rel->rd_rel->relreplident == REPLICA_IDENTITY_DEFAULT || + rel->rd_rel->relreplident == REPLICA_IDENTITY_FULL || + rel->rd_rel->relreplident == REPLICA_IDENTITY_INDEX); + + pq_sendbyte(out, 'D'); /* action DELETE */ + + /* use Oid as relation identifier */ + pq_sendint(out, RelationGetRelid(rel), 4); + + if (rel->rd_rel->relreplident == REPLICA_IDENTITY_FULL) + pq_sendbyte(out, 'O'); /* old tuple follows */ + else + pq_sendbyte(out, 'K'); /* old key follows */ + + logicalrep_write_tuple(out, rel, oldtuple); +} + +/* + * Read DELETE from stream. + * + * Fills the old tuple. + */ +LogicalRepRelId +logicalrep_read_delete(StringInfo in, LogicalRepTupleData *oldtup) +{ + char action; + LogicalRepRelId relid; + + /* read the relation id */ + relid = pq_getmsgint(in, 4); + + /* read and verify action */ + action = pq_getmsgbyte(in); + if (action != 'K' && action != 'O') + elog(ERROR, "expected action 'O' or 'K', got %c", action); + + logicalrep_read_tuple(in, oldtup); + + return relid; +} + +/* + * Write relation description to the output stream. + */ +void +logicalrep_write_rel(StringInfo out, Relation rel) +{ + char *relname; + + pq_sendbyte(out, 'R'); /* sending RELATION */ + + /* use Oid as relation identifier */ + pq_sendint(out, RelationGetRelid(rel), 4); + + /* send qualified relation name */ + logicalrep_write_namespace(out, RelationGetNamespace(rel)); + relname = RelationGetRelationName(rel); + pq_sendstring(out, relname); + + /* send replica identity */ + pq_sendbyte(out, rel->rd_rel->relreplident); + + /* send the attribute info */ + logicalrep_write_attrs(out, rel); +} + +/* + * Read the relation info from stream and return as LogicalRepRelation. + */ +LogicalRepRelation * +logicalrep_read_rel(StringInfo in) +{ + LogicalRepRelation *rel = palloc(sizeof(LogicalRepRelation)); + + rel->remoteid = pq_getmsgint(in, 4); + + /* Read relation name from stream */ + rel->nspname = pstrdup(logicalrep_read_namespace(in)); + rel->relname = pstrdup(pq_getmsgstring(in)); + + /* Read the replica identity. */ + rel->replident = pq_getmsgbyte(in); + + /* Get attribute description */ + logicalrep_read_attrs(in, rel); + + return rel; +} + +/* + * Write type info to the output stream. + * + * This function will always write base type info. + */ +void +logicalrep_write_typ(StringInfo out, Oid typoid) +{ + Oid basetypoid = getBaseType(typoid); + HeapTuple tup; + Form_pg_type typtup; + + pq_sendbyte(out, 'Y'); /* sending TYPE */ + + tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(basetypoid)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for type %u", basetypoid); + typtup = (Form_pg_type) GETSTRUCT(tup); + + /* use Oid as relation identifier */ + pq_sendint(out, typoid, 4); + + /* send qualified type name */ + logicalrep_write_namespace(out, typtup->typnamespace); + pq_sendstring(out, NameStr(typtup->typname)); + + ReleaseSysCache(tup); +} + +/* + * Read type info from the output stream. + */ +void +logicalrep_read_typ(StringInfo in, LogicalRepTyp *ltyp) +{ + ltyp->remoteid = pq_getmsgint(in, 4); + + /* Read tupe name from stream */ + ltyp->nspname = pstrdup(logicalrep_read_namespace(in)); + ltyp->typname = pstrdup(pq_getmsgstring(in)); +} + +/* + * Write a tuple to the outputstream, in the most efficient format possible. + */ +static void +logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple) +{ + TupleDesc desc; + Datum values[MaxTupleAttributeNumber]; + bool isnull[MaxTupleAttributeNumber]; + int i; + uint16 nliveatts = 0; + + desc = RelationGetDescr(rel); + + for (i = 0; i < desc->natts; i++) + { + if (desc->attrs[i]->attisdropped) + continue; + nliveatts++; + } + pq_sendint(out, nliveatts, 2); + + /* try to allocate enough memory from the get-go */ + enlargeStringInfo(out, tuple->t_len + + nliveatts * (1 + 4)); + + heap_deform_tuple(tuple, desc, values, isnull); + + /* Write the values */ + for (i = 0; i < desc->natts; i++) + { + HeapTuple typtup; + Form_pg_type typclass; + Form_pg_attribute att = desc->attrs[i]; + char *outputstr; + int len; + + /* skip dropped columns */ + if (att->attisdropped) + continue; + + if (isnull[i]) + { + pq_sendbyte(out, 'n'); /* null column */ + continue; + } + else if (att->attlen == -1 && VARATT_IS_EXTERNAL_ONDISK(values[i])) + { + pq_sendbyte(out, 'u'); /* unchanged toast column */ + continue; + } + + typtup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(att->atttypid)); + if (!HeapTupleIsValid(typtup)) + elog(ERROR, "cache lookup failed for type %u", att->atttypid); + typclass = (Form_pg_type) GETSTRUCT(typtup); + + pq_sendbyte(out, 't'); /* 'text' data follows */ + + outputstr = OidOutputFunctionCall(typclass->typoutput, values[i]); + len = strlen(outputstr) + 1; /* null terminated */ + pq_sendint(out, len, 4); /* length */ + appendBinaryStringInfo(out, outputstr, len); /* data */ + + pfree(outputstr); + + ReleaseSysCache(typtup); + } +} + +/* + * Read tuple in remote format from stream. + * + * The returned tuple points into the input stringinfo. + */ +static void +logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple) +{ + int i; + int natts; + + /* Get of attributes. */ + natts = pq_getmsgint(in, 2); + + memset(tuple->changed, 0, sizeof(tuple->changed)); + + /* Read the data */ + for (i = 0; i < natts; i++) + { + char kind; + int len; + + kind = pq_getmsgbyte(in); + + switch (kind) + { + case 'n': /* null */ + tuple->values[i] = NULL; + tuple->changed[i] = true; + break; + case 'u': /* unchanged column */ + tuple->values[i] = (char *) 0xdeadbeef; /* make bad usage more obvious */ + break; + case 't': /* text formatted value */ + { + tuple->changed[i] = true; + + len = pq_getmsgint(in, 4); /* read length */ + + /* and data */ + tuple->values[i] = (char *) pq_getmsgbytes(in, len); + } + break; + default: + elog(ERROR, "unknown data representation type '%c'", kind); + } + } +} + +/* + * Write relation attributes to the stream. + */ +static void +logicalrep_write_attrs(StringInfo out, Relation rel) +{ + TupleDesc desc; + int i; + uint16 nliveatts = 0; + Bitmapset *idattrs = NULL; + bool replidentfull; + + desc = RelationGetDescr(rel); + + /* send number of live attributes */ + for (i = 0; i < desc->natts; i++) + { + if (desc->attrs[i]->attisdropped) + continue; + nliveatts++; + } + pq_sendint(out, nliveatts, 2); + + /* fetch bitmap of REPLICATION IDENTITY attributes */ + replidentfull = (rel->rd_rel->relreplident == REPLICA_IDENTITY_FULL); + if (!replidentfull) + idattrs = RelationGetIndexAttrBitmap(rel, + INDEX_ATTR_BITMAP_IDENTITY_KEY); + + /* send the attributes */ + for (i = 0; i < desc->natts; i++) + { + Form_pg_attribute att = desc->attrs[i]; + uint8 flags = 0; + + if (att->attisdropped) + continue; + + /* REPLICA IDENTITY FULL means all colums are sent as part of key. */ + if (replidentfull || + bms_is_member(att->attnum - FirstLowInvalidHeapAttributeNumber, + idattrs)) + flags |= LOGICALREP_IS_REPLICA_IDENTITY; + + pq_sendbyte(out, flags); + + /* attribute name */ + pq_sendstring(out, NameStr(att->attname)); + + /* attribute type id */ + pq_sendint(out, (int) att->atttypid, sizeof(att->atttypid)); + + /* attribute mode */ + pq_sendint(out, att->atttypmod, sizeof(att->atttypmod)); + } + + bms_free(idattrs); +} + +/* + * Read relation attribute names from the stream. + */ +static void +logicalrep_read_attrs(StringInfo in, LogicalRepRelation *rel) +{ + int i; + int natts; + char **attnames; + Oid *atttyps; + Bitmapset *attkeys = NULL; + + natts = pq_getmsgint(in, 2); + attnames = palloc(natts * sizeof(char *)); + atttyps = palloc(natts * sizeof(Oid)); + + /* read the attributes */ + for (i = 0; i < natts; i++) + { + uint8 flags; + + /* Check for replica identity column */ + flags = pq_getmsgbyte(in); + if (flags & LOGICALREP_IS_REPLICA_IDENTITY) + attkeys = bms_add_member(attkeys, i); + + /* attribute name */ + attnames[i] = pstrdup(pq_getmsgstring(in)); + + /* attribute type id */ + atttyps[i] = (Oid) pq_getmsgint(in, 4); + + /* we ignore attribute mode for now */ + (void) pq_getmsgint(in, 4); + } + + rel->attnames = attnames; + rel->atttyps = atttyps; + rel->attkeys = attkeys; + rel->natts = natts; +} + +/* + * Write the namespace name or empty string for pg_catalog (to save space). + */ +static void +logicalrep_write_namespace(StringInfo out, Oid nspid) +{ + if (nspid == PG_CATALOG_NAMESPACE) + pq_sendbyte(out, '\0'); + else + { + char *nspname = get_namespace_name(nspid); + + if (nspname == NULL) + elog(ERROR, "cache lookup failed for namespace %u", + nspid); + + pq_sendstring(out, nspname); + } +} + +/* + * Read the namespace name while treating empty string as pg_catalog. + */ +static const char * +logicalrep_read_namespace(StringInfo in) +{ + const char *nspname = pq_getmsgstring(in); + + if (nspname[0] == '\0') + nspname = "pg_catalog"; + + return nspname; +} diff --git a/src/backend/replication/logical/relation.c b/src/backend/replication/logical/relation.c new file mode 100644 index 0000000000..383c6ebe76 --- /dev/null +++ b/src/backend/replication/logical/relation.c @@ -0,0 +1,489 @@ +/*------------------------------------------------------------------------- + * relation.c + * PostgreSQL logical replication + * + * Copyright (c) 2012-2016, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/backend/replication/logical/relation.c + * + * NOTES + * This file contains helper functions for logical replication relation + * mapping cache. + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "access/heapam.h" +#include "access/sysattr.h" +#include "catalog/namespace.h" +#include "nodes/makefuncs.h" +#include "replication/logicalrelation.h" +#include "replication/worker_internal.h" +#include "utils/builtins.h" +#include "utils/inval.h" +#include "utils/lsyscache.h" +#include "utils/memutils.h" +#include "utils/syscache.h" + +static MemoryContext LogicalRepRelMapContext = NULL; + +static HTAB *LogicalRepRelMap = NULL; +static HTAB *LogicalRepTypMap = NULL; + +static void logicalrep_typmap_invalidate_cb(Datum arg, int cacheid, + uint32 hashvalue); + +/* + * Relcache invalidation callback for our relation map cache. + */ +static void +logicalrep_relmap_invalidate_cb(Datum arg, Oid reloid) +{ + LogicalRepRelMapEntry *entry; + + /* Just to be sure. */ + if (LogicalRepRelMap == NULL) + return; + + if (reloid != InvalidOid) + { + HASH_SEQ_STATUS status; + + hash_seq_init(&status, LogicalRepRelMap); + + /* TODO, use inverse lookup hashtable? */ + while ((entry = (LogicalRepRelMapEntry *) hash_seq_search(&status)) != NULL) + { + if (entry->localreloid == reloid) + { + entry->localreloid = InvalidOid; + hash_seq_term(&status); + break; + } + } + } + else + { + /* invalidate all cache entries */ + HASH_SEQ_STATUS status; + + hash_seq_init(&status, LogicalRepRelMap); + + while ((entry = (LogicalRepRelMapEntry *) hash_seq_search(&status)) != NULL) + entry->localreloid = InvalidOid; + } +} + +/* + * Initialize the relation map cache. + */ +static void +logicalrep_relmap_init() +{ + HASHCTL ctl; + + if (!LogicalRepRelMapContext) + LogicalRepRelMapContext = + AllocSetContextCreate(CacheMemoryContext, + "LogicalRepRelMapContext", + ALLOCSET_DEFAULT_SIZES); + + /* Initialize the relation hash table. */ + MemSet(&ctl, 0, sizeof(ctl)); + ctl.keysize = sizeof(LogicalRepRelId); + ctl.entrysize = sizeof(LogicalRepRelMapEntry); + ctl.hcxt = LogicalRepRelMapContext; + + LogicalRepRelMap = hash_create("logicalrep relation map cache", 128, &ctl, + HASH_ELEM | HASH_BLOBS | HASH_CONTEXT); + + /* Initialize the type hash table. */ + MemSet(&ctl, 0, sizeof(ctl)); + ctl.keysize = sizeof(Oid); + ctl.entrysize = sizeof(LogicalRepTyp); + ctl.hcxt = LogicalRepRelMapContext; + + /* This will usually be small. */ + LogicalRepTypMap = hash_create("logicalrep type map cache", 2, &ctl, + HASH_ELEM | HASH_BLOBS |HASH_CONTEXT); + + /* Watch for invalidation events. */ + CacheRegisterRelcacheCallback(logicalrep_relmap_invalidate_cb, + (Datum) 0); + CacheRegisterSyscacheCallback(TYPEOID, logicalrep_typmap_invalidate_cb, + (Datum) 0); +} + +/* + * Free the entry of a relation map cache. + */ +static void +logicalrep_relmap_free_entry(LogicalRepRelMapEntry *entry) +{ + LogicalRepRelation *remoterel; + + remoterel = &entry->remoterel; + + pfree(remoterel->nspname); + pfree(remoterel->relname); + + if (remoterel->natts > 0) + { + int i; + + for (i = 0; i < remoterel->natts; i++) + pfree(remoterel->attnames[i]); + + pfree(remoterel->attnames); + pfree(remoterel->atttyps); + } + remoterel->attnames = NULL; + remoterel->atttyps = NULL; + + bms_free(remoterel->attkeys); + remoterel->attkeys = NULL; + + if (entry->attrmap) + pfree(entry->attrmap); + + entry->attrmap = NULL; + remoterel->natts = 0; + entry->localreloid = InvalidOid; + entry->localrel = NULL; +} + +/* + * Add new entry or update existing entry in the relation map cache. + * + * Called when new relation mapping is sent by the publisher to update + * our expected view of incoming data from said publisher. + */ +void +logicalrep_relmap_update(LogicalRepRelation *remoterel) +{ + MemoryContext oldctx; + LogicalRepRelMapEntry *entry; + bool found; + int i; + + if (LogicalRepRelMap == NULL) + logicalrep_relmap_init(); + + /* + * HASH_ENTER returns the existing entry if present or creates a new one. + */ + entry = hash_search(LogicalRepRelMap, (void *) &remoterel->remoteid, + HASH_ENTER, &found); + + if (found) + logicalrep_relmap_free_entry(entry); + + /* Make cached copy of the data */ + oldctx = MemoryContextSwitchTo(LogicalRepRelMapContext); + entry->remoterel.remoteid = remoterel->remoteid; + entry->remoterel.nspname = pstrdup(remoterel->nspname); + entry->remoterel.relname = pstrdup(remoterel->relname); + entry->remoterel.natts = remoterel->natts; + entry->remoterel.attnames = palloc(remoterel->natts * sizeof(char *)); + entry->remoterel.atttyps = palloc(remoterel->natts * sizeof(Oid)); + for (i = 0; i < remoterel->natts; i++) + { + entry->remoterel.attnames[i] = pstrdup(remoterel->attnames[i]); + entry->remoterel.atttyps[i] = remoterel->atttyps[i]; + } + entry->remoterel.replident = remoterel->replident; + entry->remoterel.attkeys = bms_copy(remoterel->attkeys); + entry->attrmap = NULL; + entry->localreloid = InvalidOid; + MemoryContextSwitchTo(oldctx); +} + +/* + * Find attribute index in TupleDesc struct by attribute name. + * + * Returns -1 if not found. + */ +static int +logicalrep_rel_att_by_name(LogicalRepRelation *remoterel, const char *attname) +{ + int i; + + for (i = 0; i < remoterel->natts; i++) + { + if (strcmp(remoterel->attnames[i], attname) == 0) + return i; + } + + return -1; +} + +/* + * Open the local relation associated with the remote one. + * + * Optionally rebuilds the Relcache mapping if it was invalidated + * by local DDL. + */ +LogicalRepRelMapEntry * +logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE lockmode) +{ + LogicalRepRelMapEntry *entry; + bool found; + + if (LogicalRepRelMap == NULL) + logicalrep_relmap_init(); + + /* Search for existing entry. */ + entry = hash_search(LogicalRepRelMap, (void *) &remoteid, + HASH_FIND, &found); + + if (!found) + elog(ERROR, "no relation map entry for remote relation ID %u", + remoteid); + + /* Need to update the local cache? */ + if (!OidIsValid(entry->localreloid)) + { + Oid relid; + int i; + int found; + Bitmapset *idkey; + TupleDesc desc; + LogicalRepRelation *remoterel; + MemoryContext oldctx; + remoterel = &entry->remoterel; + + /* Try to find and lock the relation by name. */ + relid = RangeVarGetRelid(makeRangeVar(remoterel->nspname, + remoterel->relname, -1), + lockmode, true); + if (!OidIsValid(relid)) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("logical replication target relation \"%s.%s\" does not exist", + remoterel->nspname, remoterel->relname))); + entry->localrel = heap_open(relid, NoLock); + + /* + * We currently only support writing to regular and partitioned + * tables. + */ + if (entry->localrel->rd_rel->relkind != RELKIND_RELATION) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("logical replication target relation \"%s.%s\" is not a table", + remoterel->nspname, remoterel->relname))); + + /* + * Build the mapping of local attribute numbers to remote attribute + * numbers and validate that we don't miss any replicated columns + * as that would result in potentially unwanted data loss. + */ + desc = RelationGetDescr(entry->localrel); + oldctx = MemoryContextSwitchTo(LogicalRepRelMapContext); + entry->attrmap = palloc(desc->natts * sizeof(int)); + MemoryContextSwitchTo(oldctx); + + found = 0; + for (i = 0; i < desc->natts; i++) + { + int attnum = logicalrep_rel_att_by_name(remoterel, + NameStr(desc->attrs[i]->attname)); + entry->attrmap[i] = attnum; + if (attnum >= 0) + found++; + } + + /* TODO, detail message with names of missing columns */ + if (found < remoterel->natts) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("logical replication target relation \"%s.%s\" is missing " + "some replicated columns", + remoterel->nspname, remoterel->relname))); + + /* + * Check that replica identity matches. We allow for stricter replica + * identity (fewer columns) on subscriber as that will not stop us + * from finding unique tuple. IE, if publisher has identity + * (id,timestamp) and subscriber just (id) this will not be a problem, + * but in the opposite scenario it will. + * + * Don't throw any error here just mark the relation entry as not + * updatable, as replica identity is only for updates and deletes + * but inserts can be replicated even without it. + */ + entry->updatable = true; + idkey = RelationGetIndexAttrBitmap(entry->localrel, + INDEX_ATTR_BITMAP_IDENTITY_KEY); + /* fallback to PK if no replica identity */ + if (idkey == NULL) + { + idkey = RelationGetIndexAttrBitmap(entry->localrel, + INDEX_ATTR_BITMAP_PRIMARY_KEY); + /* + * If no replica identity index and no PK, the published table + * must have replica identity FULL. + */ + if (idkey == NULL && remoterel->replident != REPLICA_IDENTITY_FULL) + entry->updatable = false; + } + + i = -1; + while ((i = bms_next_member(idkey, i)) >= 0) + { + int attnum = i + FirstLowInvalidHeapAttributeNumber; + + if (!AttrNumberIsForUserDefinedAttr(attnum)) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("logical replication target relation \"%s.%s\" uses " + "system columns in REPLICA IDENTITY index", + remoterel->nspname, remoterel->relname))); + + attnum = AttrNumberGetAttrOffset(attnum); + + if (!bms_is_member(entry->attrmap[attnum], remoterel->attkeys)) + { + entry->updatable = false; + break; + } + } + + entry->localreloid = relid; + } + else + entry->localrel = heap_open(entry->localreloid, lockmode); + + return entry; +} + +/* + * Close the previously opened logical relation. + */ +void +logicalrep_rel_close(LogicalRepRelMapEntry *rel, LOCKMODE lockmode) +{ + heap_close(rel->localrel, lockmode); + rel->localrel = NULL; +} + + +/* + * Type cache invalidation callback for our type map cache. + */ +static void +logicalrep_typmap_invalidate_cb(Datum arg, int cacheid, uint32 hashvalue) +{ + HASH_SEQ_STATUS status; + LogicalRepTyp *entry; + + /* Just to be sure. */ + if (LogicalRepTypMap == NULL) + return; + + /* invalidate all cache entries */ + hash_seq_init(&status, LogicalRepTypMap); + + while ((entry = (LogicalRepTyp *) hash_seq_search(&status)) != NULL) + entry->typoid = InvalidOid; +} + +/* + * Free the type map cache entry data. + */ +static void +logicalrep_typmap_free_entry(LogicalRepTyp *entry) +{ + pfree(entry->nspname); + pfree(entry->typname); + + entry->typoid = InvalidOid; +} + +/* + * Add new entry or update existing entry in the type map cache. + */ +void +logicalrep_typmap_update(LogicalRepTyp *remotetyp) +{ + MemoryContext oldctx; + LogicalRepTyp *entry; + bool found; + + if (LogicalRepTypMap == NULL) + logicalrep_relmap_init(); + + /* + * HASH_ENTER returns the existing entry if present or creates a new one. + */ + entry = hash_search(LogicalRepTypMap, (void *) &remotetyp->remoteid, + HASH_ENTER, &found); + + if (found) + logicalrep_typmap_free_entry(entry); + + /* Make cached copy of the data */ + entry->remoteid = remotetyp->remoteid; + oldctx = MemoryContextSwitchTo(LogicalRepRelMapContext); + entry->nspname = pstrdup(remotetyp->nspname); + entry->typname = pstrdup(remotetyp->typname); + MemoryContextSwitchTo(oldctx); + entry->typoid = InvalidOid; +} + +/* + * Fetch type info from the cache. + */ +Oid +logicalrep_typmap_getid(Oid remoteid) +{ + LogicalRepTyp *entry; + bool found; + Oid nspoid; + + /* Internal types are mapped directly. */ + if (remoteid < FirstNormalObjectId) + { + if (!get_typisdefined(remoteid)) + ereport(ERROR, + (errmsg("builtin type %u not found", remoteid), + errhint("This can be caused by having publisher with " + "higher major version than subscriber"))); + return remoteid; + } + + if (LogicalRepTypMap == NULL) + logicalrep_relmap_init(); + + /* Try finding the mapping. */ + entry = hash_search(LogicalRepTypMap, (void *) &remoteid, + HASH_FIND, &found); + + if (!found) + elog(ERROR, "no type map entry for remote type %u", + remoteid); + + /* Found and mapped, return the oid. */ + if (OidIsValid(entry->typoid)) + return entry->typoid; + + /* Otherwise, try to map to local type. */ + nspoid = LookupExplicitNamespace(entry->nspname, true); + if (OidIsValid(nspoid)) + entry->typoid = GetSysCacheOid2(TYPENAMENSP, + PointerGetDatum(entry->typname), + ObjectIdGetDatum(nspoid)); + else + entry->typoid = InvalidOid; + + if (!OidIsValid(entry->typoid)) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("data type \"%s.%s\" required for logical replication does not exist", + entry->nspname, entry->typname))); + + return entry->typoid; +} diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c index 9594b1c671..d805ef4fb7 100644 --- a/src/backend/replication/logical/reorderbuffer.c +++ b/src/backend/replication/logical/reorderbuffer.c @@ -4,7 +4,7 @@ * PostgreSQL logical replay/reorder buffer management * * - * Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Copyright (c) 2012-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -232,9 +232,7 @@ ReorderBufferAllocate(void) /* allocate memory in own context, to have better accountability */ new_ctx = AllocSetContextCreate(CurrentMemoryContext, "ReorderBuffer", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); buffer = (ReorderBuffer *) MemoryContextAlloc(new_ctx, sizeof(ReorderBuffer)); @@ -937,8 +935,12 @@ ReorderBufferIterTXNInit(ReorderBuffer *rb, ReorderBufferTXN *txn) ReorderBufferChange *cur_change; if (txn->nentries != txn->nentries_mem) + { + /* serialize remaining changes */ + ReorderBufferSerializeTXN(rb, txn); ReorderBufferRestoreChanges(rb, txn, &state->entries[off].fd, &state->entries[off].segno); + } cur_change = dlist_head_element(ReorderBufferChange, node, &txn->changes); @@ -962,10 +964,13 @@ ReorderBufferIterTXNInit(ReorderBuffer *rb, ReorderBufferTXN *txn) ReorderBufferChange *cur_change; if (cur_txn->nentries != cur_txn->nentries_mem) + { + /* serialize remaining changes */ + ReorderBufferSerializeTXN(rb, cur_txn); ReorderBufferRestoreChanges(rb, cur_txn, &state->entries[off].fd, &state->entries[off].segno); - + } cur_change = dlist_head_element(ReorderBufferChange, node, &cur_txn->changes); @@ -1160,17 +1165,15 @@ ReorderBufferCleanupTXN(ReorderBuffer *rb, ReorderBufferTXN *txn) txn->base_snapshot_lsn = InvalidXLogRecPtr; } - /* delete from list of known subxacts */ - if (txn->is_known_as_subxact) - { - /* NB: nsubxacts count of parent will be too high now */ - dlist_delete(&txn->node); - } - /* delete from LSN ordered list of toplevel TXNs */ - else - { - dlist_delete(&txn->node); - } + /* + * Remove TXN from its containing list. + * + * Note: if txn->is_known_as_subxact, we are deleting the TXN from its + * parent's list of known subxacts; this leaves the parent's nsubxacts + * count too high, but we don't care. Otherwise, we are deleting the TXN + * from the LSN-ordered list of toplevel TXNs. + */ + dlist_delete(&txn->node); /* now remove reference from buffer */ hash_search(rb->by_txn, @@ -1371,10 +1374,6 @@ ReorderBufferCommit(ReorderBuffer *rb, TransactionId xid, txn->origin_id = origin_id; txn->origin_lsn = origin_lsn; - /* serialize the last bunch of changes if we need start earlier anyway */ - if (txn->nentries_mem != txn->nentries) - ReorderBufferSerializeTXN(rb, txn); - /* * If this transaction didn't have any real changes in our database, it's * OK not to have a snapshot. Note that ReorderBufferCommitChild will have @@ -2254,6 +2253,9 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn, data = ((char *) rb->outbuf) + sizeof(ReorderBufferDiskChange); + /* might have been reallocated above */ + ondisk = (ReorderBufferDiskChange *) rb->outbuf; + /* write the prefix including the size */ memcpy(data, &prefix_size, sizeof(Size)); data += sizeof(Size); @@ -2317,7 +2319,10 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn, if (write(fd, rb->outbuf, ondisk->size) != ondisk->size) { + int save_errno = errno; + CloseTransientFile(fd); + errno = save_errno; ereport(ERROR, (errcode_for_file_access(), errmsg("could not write to data file for XID %u: %m", @@ -2547,7 +2552,7 @@ ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn, Assert(change->data.msg.prefix[prefix_size - 1] == '\0'); data += prefix_size; - /* read the messsage */ + /* read the message */ memcpy(&change->data.msg.message_size, data, sizeof(Size)); data += sizeof(Size); change->data.msg.message = MemoryContextAlloc(rb->context, @@ -3070,7 +3075,8 @@ ApplyLogicalMappingFile(HTAB *tuplecid_data, Oid relid, const char *fname) fd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0); if (fd < 0) ereport(ERROR, - (errmsg("could not open file \"%s\": %m", path))); + (errcode_for_file_access(), + errmsg("could not open file \"%s\": %m", path))); while (true) { diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c index b5fa3dbbc0..1e02aa9bd8 100644 --- a/src/backend/replication/logical/snapbuild.c +++ b/src/backend/replication/logical/snapbuild.c @@ -96,7 +96,7 @@ * is a convenient point to initialize replication from, which is why we * export a snapshot at that point, which *can* be used to read normal data. * - * Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Copyright (c) 2012-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/snapbuild.c @@ -289,9 +289,7 @@ AllocateSnapshotBuilder(ReorderBuffer *reorder, /* allocate memory in own context, to have better accountability */ context = AllocSetContextCreate(CurrentMemoryContext, "snapshot builder context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldcontext = MemoryContextSwitchTo(context); builder = palloc0(sizeof(SnapBuild)); diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c new file mode 100644 index 0000000000..7d86736444 --- /dev/null +++ b/src/backend/replication/logical/worker.c @@ -0,0 +1,1429 @@ +/*------------------------------------------------------------------------- + * worker.c + * PostgreSQL logical replication worker (apply) + * + * Copyright (c) 2012-2016, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/backend/replication/logical/worker.c + * + * NOTES + * This file contains the worker which applies logical changes as they come + * from remote logical replication stream. + * + * The main worker (apply) is started by logical replication worker + * launcher for every enabled subscription in a database. It uses + * walsender protocol to communicate with publisher. + * + * The apply worker may spawn additional workers (sync) for initial data + * synchronization of tables. + * + * This module includes server facing code and shares libpqwalreceiver + * module with walreceiver for providing the libpq specific functionality. + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "miscadmin.h" +#include "pgstat.h" +#include "funcapi.h" + +#include "access/xact.h" +#include "access/xlog_internal.h" + +#include "catalog/namespace.h" +#include "catalog/pg_subscription.h" + +#include "commands/trigger.h" + +#include "executor/executor.h" +#include "executor/nodeModifyTable.h" + +#include "libpq/pqformat.h" +#include "libpq/pqsignal.h" + +#include "mb/pg_wchar.h" + +#include "nodes/makefuncs.h" + +#include "optimizer/planner.h" + +#include "parser/parse_relation.h" + +#include "postmaster/bgworker.h" +#include "postmaster/postmaster.h" + +#include "replication/decode.h" +#include "replication/logical.h" +#include "replication/logicalproto.h" +#include "replication/logicalrelation.h" +#include "replication/logicalworker.h" +#include "replication/reorderbuffer.h" +#include "replication/origin.h" +#include "replication/snapbuild.h" +#include "replication/walreceiver.h" +#include "replication/worker_internal.h" + +#include "rewrite/rewriteHandler.h" + +#include "storage/bufmgr.h" +#include "storage/ipc.h" +#include "storage/lmgr.h" +#include "storage/proc.h" +#include "storage/procarray.h" + +#include "utils/builtins.h" +#include "utils/catcache.h" +#include "utils/datum.h" +#include "utils/fmgroids.h" +#include "utils/guc.h" +#include "utils/inval.h" +#include "utils/lsyscache.h" +#include "utils/memutils.h" +#include "utils/timeout.h" +#include "utils/tqual.h" +#include "utils/syscache.h" + +#define NAPTIME_PER_CYCLE 1000 /* max sleep time between cycles (1s) */ + +typedef struct FlushPosition +{ + dlist_node node; + XLogRecPtr local_end; + XLogRecPtr remote_end; +} FlushPosition; + +static dlist_head lsn_mapping = DLIST_STATIC_INIT(lsn_mapping); + +typedef struct SlotErrCallbackArg +{ + LogicalRepRelation *rel; + int attnum; +} SlotErrCallbackArg; + +static MemoryContext ApplyContext = NULL; +static MemoryContext ApplyCacheContext = NULL; + +WalReceiverConn *wrconn = NULL; + +Subscription *MySubscription = NULL; +bool MySubscriptionValid = false; + +bool in_remote_transaction = false; + +static void send_feedback(XLogRecPtr recvpos, bool force, bool requestReply); + +static void store_flush_position(XLogRecPtr remote_lsn); + +static void reread_subscription(void); + +/* + * Make sure that we started local transaction. + * + * Also switches to ApplyContext as necessary. + */ +static bool +ensure_transaction(void) +{ + if (IsTransactionState()) + { + if (CurrentMemoryContext != ApplyContext) + MemoryContextSwitchTo(ApplyContext); + return false; + } + + StartTransactionCommand(); + + if (!MySubscriptionValid) + reread_subscription(); + + MemoryContextSwitchTo(ApplyContext); + return true; +} + + +/* + * Executor state preparation for evaluation of constraint expressions, + * indexes and triggers. + * + * This is based on similar code in copy.c + */ +static EState * +create_estate_for_relation(LogicalRepRelMapEntry *rel) +{ + EState *estate; + ResultRelInfo *resultRelInfo; + RangeTblEntry *rte; + + estate = CreateExecutorState(); + + rte = makeNode(RangeTblEntry); + rte->rtekind = RTE_RELATION; + rte->relid = RelationGetRelid(rel->localrel); + rte->relkind = rel->localrel->rd_rel->relkind; + estate->es_range_table = list_make1(rte); + + resultRelInfo = makeNode(ResultRelInfo); + InitResultRelInfo(resultRelInfo, rel->localrel, 1, NULL, 0); + + estate->es_result_relations = resultRelInfo; + estate->es_num_result_relations = 1; + estate->es_result_relation_info = resultRelInfo; + + /* Triggers might need a slot */ + if (resultRelInfo->ri_TrigDesc) + estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate); + + return estate; +} + +/* + * Executes default values for columns for which we can't map to remote + * relation columns. + * + * This allows us to support tables which have more columns on the downstream + * than on the upstream. + */ +static void +slot_fill_defaults(LogicalRepRelMapEntry *rel, EState *estate, + TupleTableSlot *slot) +{ + TupleDesc desc = RelationGetDescr(rel->localrel); + int num_phys_attrs = desc->natts; + int i; + int attnum, + num_defaults = 0; + int *defmap; + ExprState **defexprs; + ExprContext *econtext; + + econtext = GetPerTupleExprContext(estate); + + /* We got all the data via replication, no need to evaluate anything. */ + if (num_phys_attrs == rel->remoterel.natts) + return; + + defmap = (int *) palloc(num_phys_attrs * sizeof(int)); + defexprs = (ExprState **) palloc(num_phys_attrs * sizeof(ExprState *)); + + for (attnum = 0; attnum < num_phys_attrs; attnum++) + { + Expr *defexpr; + + if (desc->attrs[attnum]->attisdropped) + continue; + + if (rel->attrmap[attnum] >= 0) + continue; + + defexpr = (Expr *) build_column_default(rel->localrel, attnum + 1); + + if (defexpr != NULL) + { + /* Run the expression through planner */ + defexpr = expression_planner(defexpr); + + /* Initialize executable expression in copycontext */ + defexprs[num_defaults] = ExecInitExpr(defexpr, NULL); + defmap[num_defaults] = attnum; + num_defaults++; + } + + } + + for (i = 0; i < num_defaults; i++) + slot->tts_values[defmap[i]] = + ExecEvalExpr(defexprs[i], econtext, &slot->tts_isnull[defmap[i]]); +} + +/* + * Error callback to give more context info about type conversion failure. + */ +static void +slot_store_error_callback(void *arg) +{ + SlotErrCallbackArg *errarg = (SlotErrCallbackArg *) arg; + Oid remotetypoid, + localtypoid; + + if (errarg->attnum < 0) + return; + + remotetypoid = errarg->rel->atttyps[errarg->attnum]; + localtypoid = logicalrep_typmap_getid(remotetypoid); + errcontext("processing remote data for replication target relation \"%s.%s\" column \"%s\", " + "remote type %s, local type %s", + errarg->rel->nspname, errarg->rel->relname, + errarg->rel->attnames[errarg->attnum], + format_type_be(remotetypoid), + format_type_be(localtypoid)); +} + +/* + * Store data in C string form into slot. + * This is similar to BuildTupleFromCStrings but TupleTableSlot fits our + * use better. + */ +static void +slot_store_cstrings(TupleTableSlot *slot, LogicalRepRelMapEntry *rel, + char **values) +{ + int natts = slot->tts_tupleDescriptor->natts; + int i; + SlotErrCallbackArg errarg; + ErrorContextCallback errcallback; + + ExecClearTuple(slot); + + /* Push callback + info on the error context stack */ + errarg.rel = &rel->remoterel; + errarg.attnum = -1; + errcallback.callback = slot_store_error_callback; + errcallback.arg = (void *) &errarg; + errcallback.previous = error_context_stack; + error_context_stack = &errcallback; + + /* Call the "in" function for each non-dropped attribute */ + for (i = 0; i < natts; i++) + { + Form_pg_attribute att = slot->tts_tupleDescriptor->attrs[i]; + int remoteattnum = rel->attrmap[i]; + + if (!att->attisdropped && remoteattnum >= 0 && + values[remoteattnum] != NULL) + { + Oid typinput; + Oid typioparam; + + errarg.attnum = remoteattnum; + + getTypeInputInfo(att->atttypid, &typinput, &typioparam); + slot->tts_values[i] = OidInputFunctionCall(typinput, + values[remoteattnum], + typioparam, + att->atttypmod); + slot->tts_isnull[i] = false; + } + else + { + /* + * We assign NULL to dropped attributes, NULL values, and missing + * values (missing values should be later filled using + * slot_fill_defaults). + */ + slot->tts_values[i] = (Datum) 0; + slot->tts_isnull[i] = true; + } + } + + /* Pop the error context stack */ + error_context_stack = errcallback.previous; + + ExecStoreVirtualTuple(slot); +} + +/* + * Modify slot with user data provided as C strigs. + * This is somewhat similar to heap_modify_tuple but also calls the type + * input fuction on the user data as the input is the text representation + * of the types. + */ +static void +slot_modify_cstrings(TupleTableSlot *slot, LogicalRepRelMapEntry *rel, + char **values, bool *replaces) +{ + int natts = slot->tts_tupleDescriptor->natts; + int i; + SlotErrCallbackArg errarg; + ErrorContextCallback errcallback; + + slot_getallattrs(slot); + ExecClearTuple(slot); + + /* Push callback + info on the error context stack */ + errarg.rel = &rel->remoterel; + errarg.attnum = -1; + errcallback.callback = slot_store_error_callback; + errcallback.arg = (void *) &errarg; + errcallback.previous = error_context_stack; + error_context_stack = &errcallback; + + /* Call the "in" function for each replaced attribute */ + for (i = 0; i < natts; i++) + { + Form_pg_attribute att = slot->tts_tupleDescriptor->attrs[i]; + int remoteattnum = rel->attrmap[i]; + + if (remoteattnum >= 0 && !replaces[remoteattnum]) + continue; + + if (remoteattnum >= 0 && values[remoteattnum] != NULL) + { + Oid typinput; + Oid typioparam; + + errarg.attnum = remoteattnum; + + getTypeInputInfo(att->atttypid, &typinput, &typioparam); + slot->tts_values[i] = OidInputFunctionCall(typinput, values[i], + typioparam, + att->atttypmod); + slot->tts_isnull[i] = false; + } + else + { + slot->tts_values[i] = (Datum) 0; + slot->tts_isnull[i] = true; + } + } + + /* Pop the error context stack */ + error_context_stack = errcallback.previous; + + ExecStoreVirtualTuple(slot); +} + +/* + * Handle BEGIN message. + */ +static void +apply_handle_begin(StringInfo s) +{ + LogicalRepBeginData begin_data; + + logicalrep_read_begin(s, &begin_data); + + replorigin_session_origin_timestamp = begin_data.committime; + replorigin_session_origin_lsn = begin_data.final_lsn; + + in_remote_transaction = true; + + pgstat_report_activity(STATE_RUNNING, NULL); +} + +/* + * Handle COMMIT message. + * + * TODO, support tracking of multiple origins + */ +static void +apply_handle_commit(StringInfo s) +{ + LogicalRepCommitData commit_data; + + logicalrep_read_commit(s, &commit_data); + + Assert(commit_data.commit_lsn == replorigin_session_origin_lsn); + Assert(commit_data.committime == replorigin_session_origin_timestamp); + + if (IsTransactionState()) + { + CommitTransactionCommand(); + + store_flush_position(commit_data.end_lsn); + } + + in_remote_transaction = false; + + pgstat_report_activity(STATE_IDLE, NULL); +} + +/* + * Handle ORIGIN message. + * + * TODO, support tracking of multiple origins + */ +static void +apply_handle_origin(StringInfo s) +{ + /* + * ORIGIN message can only come inside remote transaction and before + * any actual writes. + */ + if (!in_remote_transaction || IsTransactionState()) + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("ORIGIN message sent out of order"))); +} + +/* + * Handle RELATION message. + * + * Note we don't do validation against local schema here. The validation + * against local schema is postponed until first change for given relation + * comes as we only care about it when applying changes for it anyway and we + * do less locking this way. + */ +static void +apply_handle_relation(StringInfo s) +{ + LogicalRepRelation *rel; + + rel = logicalrep_read_rel(s); + logicalrep_relmap_update(rel); +} + +/* + * Handle TYPE message. + * + * Note we don't do local mapping here, that's done when the type is + * actually used. + */ +static void +apply_handle_type(StringInfo s) +{ + LogicalRepTyp typ; + + logicalrep_read_typ(s, &typ); + logicalrep_typmap_update(&typ); +} + +/* + * Get replica identity index or if it is not defined a primary key. + * + * If neither is defined, returns InvalidOid + */ +static Oid +GetRelationIdentityOrPK(Relation rel) +{ + Oid idxoid; + + idxoid = RelationGetReplicaIndex(rel); + + if (!OidIsValid(idxoid)) + idxoid = RelationGetPrimaryKeyIndex(rel); + + return idxoid; +} + +/* + * Handle INSERT message. + */ +static void +apply_handle_insert(StringInfo s) +{ + LogicalRepRelMapEntry *rel; + LogicalRepTupleData newtup; + LogicalRepRelId relid; + EState *estate; + TupleTableSlot *remoteslot; + MemoryContext oldctx; + + ensure_transaction(); + + relid = logicalrep_read_insert(s, &newtup); + rel = logicalrep_rel_open(relid, RowExclusiveLock); + + /* Initialize the executor state. */ + estate = create_estate_for_relation(rel); + remoteslot = ExecInitExtraTupleSlot(estate); + ExecSetSlotDescriptor(remoteslot, RelationGetDescr(rel->localrel)); + + /* Process and store remote tuple in the slot */ + oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); + slot_store_cstrings(remoteslot, rel, newtup.values); + slot_fill_defaults(rel, estate, remoteslot); + MemoryContextSwitchTo(oldctx); + + PushActiveSnapshot(GetTransactionSnapshot()); + ExecOpenIndices(estate->es_result_relation_info, false); + + /* Do the insert. */ + ExecSimpleRelationInsert(estate, remoteslot); + + /* Cleanup. */ + ExecCloseIndices(estate->es_result_relation_info); + PopActiveSnapshot(); + ExecResetTupleTable(estate->es_tupleTable, false); + FreeExecutorState(estate); + + logicalrep_rel_close(rel, NoLock); + + CommandCounterIncrement(); +} + +/* + * Check if the logical replication relation is updatable and throw + * appropriate error if it isn't. + */ +static void +check_relation_updatable(LogicalRepRelMapEntry *rel) +{ + /* Updatable, no error. */ + if (rel->updatable) + return; + + /* + * We are in error mode so it's fine this is somewhat slow. + * It's better to give user correct error. + */ + if (OidIsValid(GetRelationIdentityOrPK(rel->localrel))) + { + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("publisher does not send replica identity column " + "expected by the logical replication target relation \"%s.%s\"", + rel->remoterel.nspname, rel->remoterel.relname))); + } + + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("logical replication target relation \"%s.%s\" has " + "neither REPLICA IDENTIY index nor PRIMARY " + "KEY and published relation does not have " + "REPLICA IDENTITY FULL", + rel->remoterel.nspname, rel->remoterel.relname))); +} + +/* + * Handle UPDATE message. + * + * TODO: FDW support + */ +static void +apply_handle_update(StringInfo s) +{ + LogicalRepRelMapEntry *rel; + LogicalRepRelId relid; + Oid idxoid; + EState *estate; + EPQState epqstate; + LogicalRepTupleData oldtup; + LogicalRepTupleData newtup; + bool has_oldtup; + TupleTableSlot *localslot; + TupleTableSlot *remoteslot; + bool found; + MemoryContext oldctx; + + ensure_transaction(); + + relid = logicalrep_read_update(s, &has_oldtup, &oldtup, + &newtup); + rel = logicalrep_rel_open(relid, RowExclusiveLock); + + /* Check if we can do the update. */ + check_relation_updatable(rel); + + /* Initialize the executor state. */ + estate = create_estate_for_relation(rel); + remoteslot = ExecInitExtraTupleSlot(estate); + ExecSetSlotDescriptor(remoteslot, RelationGetDescr(rel->localrel)); + localslot = ExecInitExtraTupleSlot(estate); + ExecSetSlotDescriptor(localslot, RelationGetDescr(rel->localrel)); + EvalPlanQualInit(&epqstate, estate, NULL, NIL, -1); + + PushActiveSnapshot(GetTransactionSnapshot()); + ExecOpenIndices(estate->es_result_relation_info, false); + + /* Build the search tuple. */ + oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); + slot_store_cstrings(remoteslot, rel, + has_oldtup ? oldtup.values : newtup.values); + MemoryContextSwitchTo(oldctx); + + /* + * Try to find tuple using either replica identity index, primary key + * or if needed, sequential scan. + */ + idxoid = GetRelationIdentityOrPK(rel->localrel); + Assert(OidIsValid(idxoid) || + (rel->remoterel.replident == REPLICA_IDENTITY_FULL && has_oldtup)); + + if (OidIsValid(idxoid)) + found = RelationFindReplTupleByIndex(rel->localrel, idxoid, + LockTupleExclusive, + remoteslot, localslot); + else + found = RelationFindReplTupleSeq(rel->localrel, LockTupleExclusive, + remoteslot, localslot); + + ExecClearTuple(remoteslot); + + /* + * Tuple found. + * + * Note this will fail if there are other conflicting unique indexes. + */ + if (found) + { + /* Process and store remote tuple in the slot */ + oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); + ExecStoreTuple(localslot->tts_tuple, remoteslot, InvalidBuffer, false); + slot_modify_cstrings(remoteslot, rel, newtup.values, newtup.changed); + MemoryContextSwitchTo(oldctx); + + EvalPlanQualSetSlot(&epqstate, remoteslot); + + /* Do the actual update. */ + ExecSimpleRelationUpdate(estate, &epqstate, localslot, remoteslot); + } + else + { + /* + * The tuple to be updated could not be found. + * + * TODO what to do here, change the log level to LOG perhaps? + */ + elog(DEBUG1, + "logical replication did not find row for update " + "in replication target relation \"%s\"", + RelationGetRelationName(rel->localrel)); + } + + /* Cleanup. */ + ExecCloseIndices(estate->es_result_relation_info); + PopActiveSnapshot(); + EvalPlanQualEnd(&epqstate); + ExecResetTupleTable(estate->es_tupleTable, false); + FreeExecutorState(estate); + + logicalrep_rel_close(rel, NoLock); + + CommandCounterIncrement(); +} + +/* + * Handle DELETE message. + * + * TODO: FDW support + */ +static void +apply_handle_delete(StringInfo s) +{ + LogicalRepRelMapEntry *rel; + LogicalRepTupleData oldtup; + LogicalRepRelId relid; + Oid idxoid; + EState *estate; + EPQState epqstate; + TupleTableSlot *remoteslot; + TupleTableSlot *localslot; + bool found; + MemoryContext oldctx; + + ensure_transaction(); + + relid = logicalrep_read_delete(s, &oldtup); + rel = logicalrep_rel_open(relid, RowExclusiveLock); + + /* Check if we can do the delete. */ + check_relation_updatable(rel); + + /* Initialize the executor state. */ + estate = create_estate_for_relation(rel); + remoteslot = ExecInitExtraTupleSlot(estate); + ExecSetSlotDescriptor(remoteslot, RelationGetDescr(rel->localrel)); + localslot = ExecInitExtraTupleSlot(estate); + ExecSetSlotDescriptor(localslot, RelationGetDescr(rel->localrel)); + EvalPlanQualInit(&epqstate, estate, NULL, NIL, -1); + + PushActiveSnapshot(GetTransactionSnapshot()); + ExecOpenIndices(estate->es_result_relation_info, false); + + /* Find the tuple using the replica identity index. */ + oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); + slot_store_cstrings(remoteslot, rel, oldtup.values); + MemoryContextSwitchTo(oldctx); + + /* + * Try to find tuple using either replica identity index, primary key + * or if needed, sequential scan. + */ + idxoid = GetRelationIdentityOrPK(rel->localrel); + Assert(OidIsValid(idxoid) || + (rel->remoterel.replident == REPLICA_IDENTITY_FULL)); + + if (OidIsValid(idxoid)) + found = RelationFindReplTupleByIndex(rel->localrel, idxoid, + LockTupleExclusive, + remoteslot, localslot); + else + found = RelationFindReplTupleSeq(rel->localrel, LockTupleExclusive, + remoteslot, localslot); + /* If found delete it. */ + if (found) + { + EvalPlanQualSetSlot(&epqstate, localslot); + + /* Do the actual delete. */ + ExecSimpleRelationDelete(estate, &epqstate, localslot); + } + else + { + /* The tuple to be deleted could not be found.*/ + ereport(DEBUG1, + (errmsg("logical replication could not find row for delete " + "in replication target %s", + RelationGetRelationName(rel->localrel)))); + } + + /* Cleanup. */ + ExecCloseIndices(estate->es_result_relation_info); + PopActiveSnapshot(); + EvalPlanQualEnd(&epqstate); + ExecResetTupleTable(estate->es_tupleTable, false); + FreeExecutorState(estate); + + logicalrep_rel_close(rel, NoLock); + + CommandCounterIncrement(); +} + + +/* + * Logical replication protocol message dispatcher. + */ +static void +apply_dispatch(StringInfo s) +{ + char action = pq_getmsgbyte(s); + + switch (action) + { + /* BEGIN */ + case 'B': + apply_handle_begin(s); + break; + /* COMMIT */ + case 'C': + apply_handle_commit(s); + break; + /* INSERT */ + case 'I': + apply_handle_insert(s); + break; + /* UPDATE */ + case 'U': + apply_handle_update(s); + break; + /* DELETE */ + case 'D': + apply_handle_delete(s); + break; + /* RELATION */ + case 'R': + apply_handle_relation(s); + break; + /* TYPE */ + case 'Y': + apply_handle_type(s); + break; + /* ORIGIN */ + case 'O': + apply_handle_origin(s); + break; + default: + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("invalid logical replication message type %c", action))); + } +} + +/* + * Figure out which write/flush positions to report to the walsender process. + * + * We can't simply report back the last LSN the walsender sent us because the + * local transaction might not yet be flushed to disk locally. Instead we + * build a list that associates local with remote LSNs for every commit. When + * reporting back the flush position to the sender we iterate that list and + * check which entries on it are already locally flushed. Those we can report + * as having been flushed. + * + * The have_pending_txes is true if there are outstanding transactions that + * need to be flushed. + */ +static void +get_flush_position(XLogRecPtr *write, XLogRecPtr *flush, + bool *have_pending_txes) +{ + dlist_mutable_iter iter; + XLogRecPtr local_flush = GetFlushRecPtr(); + + *write = InvalidXLogRecPtr; + *flush = InvalidXLogRecPtr; + + dlist_foreach_modify(iter, &lsn_mapping) + { + FlushPosition *pos = + dlist_container(FlushPosition, node, iter.cur); + + *write = pos->remote_end; + + if (pos->local_end <= local_flush) + { + *flush = pos->remote_end; + dlist_delete(iter.cur); + pfree(pos); + } + else + { + /* + * Don't want to uselessly iterate over the rest of the list which + * could potentially be long. Instead get the last element and + * grab the write position from there. + */ + pos = dlist_tail_element(FlushPosition, node, + &lsn_mapping); + *write = pos->remote_end; + *have_pending_txes = true; + return; + } + } + + *have_pending_txes = !dlist_is_empty(&lsn_mapping); +} + +/* + * Store current remote/local lsn pair in the tracking list. + */ +static void +store_flush_position(XLogRecPtr remote_lsn) +{ + FlushPosition *flushpos; + + /* Need to do this in permanent context */ + MemoryContextSwitchTo(ApplyCacheContext); + + /* Track commit lsn */ + flushpos = (FlushPosition *) palloc(sizeof(FlushPosition)); + flushpos->local_end = XactLastCommitEnd; + flushpos->remote_end = remote_lsn; + + dlist_push_tail(&lsn_mapping, &flushpos->node); + MemoryContextSwitchTo(ApplyContext); +} + + +/* Update statistics of the worker. */ +static void +UpdateWorkerStats(XLogRecPtr last_lsn, TimestampTz send_time, bool reply) +{ + MyLogicalRepWorker->last_lsn = last_lsn; + MyLogicalRepWorker->last_send_time = send_time; + MyLogicalRepWorker->last_recv_time = GetCurrentTimestamp(); + if (reply) + { + MyLogicalRepWorker->reply_lsn = last_lsn; + MyLogicalRepWorker->reply_time = send_time; + } +} + +/* + * Apply main loop. + */ +static void +ApplyLoop(void) +{ + XLogRecPtr last_received = InvalidXLogRecPtr; + + /* Init the ApplyContext which we use for easier cleanup. */ + ApplyContext = AllocSetContextCreate(TopMemoryContext, + "ApplyContext", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + + /* mark as idle, before starting to loop */ + pgstat_report_activity(STATE_IDLE, NULL); + + while (!got_SIGTERM) + { + pgsocket fd = PGINVALID_SOCKET; + int rc; + int len; + char *buf = NULL; + bool endofstream = false; + TimestampTz last_recv_timestamp = GetCurrentTimestamp(); + bool ping_sent = false; + + MemoryContextSwitchTo(ApplyContext); + + len = walrcv_receive(wrconn, &buf, &fd); + + if (len != 0) + { + /* Process the data */ + for (;;) + { + CHECK_FOR_INTERRUPTS(); + + if (len == 0) + { + break; + } + else if (len < 0) + { + ereport(LOG, + (errmsg("data stream from publisher has ended"))); + endofstream = true; + break; + } + else + { + int c; + StringInfoData s; + + /* Reset timeout. */ + last_recv_timestamp = GetCurrentTimestamp(); + ping_sent = false; + + /* Ensure we are reading the data into our memory context. */ + MemoryContextSwitchTo(ApplyContext); + + s.data = buf; + s.len = len; + s.cursor = 0; + s.maxlen = -1; + + c = pq_getmsgbyte(&s); + + if (c == 'w') + { + XLogRecPtr start_lsn; + XLogRecPtr end_lsn; + TimestampTz send_time; + + start_lsn = pq_getmsgint64(&s); + end_lsn = pq_getmsgint64(&s); + send_time = + IntegerTimestampToTimestampTz(pq_getmsgint64(&s)); + + if (last_received < start_lsn) + last_received = start_lsn; + + if (last_received < end_lsn) + last_received = end_lsn; + + UpdateWorkerStats(last_received, send_time, false); + + apply_dispatch(&s); + } + else if (c == 'k') + { + XLogRecPtr endpos; + TimestampTz timestamp; + bool reply_requested; + + endpos = pq_getmsgint64(&s); + timestamp = + IntegerTimestampToTimestampTz(pq_getmsgint64(&s)); + reply_requested = pq_getmsgbyte(&s); + + send_feedback(endpos, reply_requested, false); + UpdateWorkerStats(last_received, timestamp, true); + } + /* other message types are purposefully ignored */ + } + + len = walrcv_receive(wrconn, &buf, &fd); + } + } + + if (!in_remote_transaction) + { + /* + * If we didn't get any transactions for a while there might be + * unconsumed invalidation messages in the queue, consume them now. + */ + StartTransactionCommand(); + /* Check for subscription change */ + if (!MySubscriptionValid) + reread_subscription(); + CommitTransactionCommand(); + } + + /* confirm all writes at once */ + send_feedback(last_received, false, false); + + /* Cleanup the memory. */ + MemoryContextResetAndDeleteChildren(ApplyContext); + MemoryContextSwitchTo(TopMemoryContext); + + /* Check if we need to exit the streaming loop. */ + if (endofstream) + break; + + /* + * Wait for more data or latch. + */ + rc = WaitLatchOrSocket(&MyProc->procLatch, + WL_SOCKET_READABLE | WL_LATCH_SET | + WL_TIMEOUT | WL_POSTMASTER_DEATH, + fd, NAPTIME_PER_CYCLE, + WAIT_EVENT_LOGICAL_APPLY_MAIN); + + /* Emergency bailout if postmaster has died */ + if (rc & WL_POSTMASTER_DEATH) + proc_exit(1); + + if (rc & WL_TIMEOUT) + { + /* + * We didn't receive anything new. If we haven't heard + * anything from the server for more than + * wal_receiver_timeout / 2, ping the server. Also, if + * it's been longer than wal_receiver_status_interval + * since the last update we sent, send a status update to + * the master anyway, to report any progress in applying + * WAL. + */ + bool requestReply = false; + + /* + * Check if time since last receive from standby has + * reached the configured limit. + */ + if (wal_receiver_timeout > 0) + { + TimestampTz now = GetCurrentTimestamp(); + TimestampTz timeout; + + timeout = + TimestampTzPlusMilliseconds(last_recv_timestamp, + wal_receiver_timeout); + + if (now >= timeout) + ereport(ERROR, + (errmsg("terminating logical replication worker due to timeout"))); + + /* + * We didn't receive anything new, for half of + * receiver replication timeout. Ping the server. + */ + if (!ping_sent) + { + timeout = TimestampTzPlusMilliseconds(last_recv_timestamp, + (wal_receiver_timeout / 2)); + if (now >= timeout) + { + requestReply = true; + ping_sent = true; + } + } + } + + send_feedback(last_received, requestReply, requestReply); + } + + ResetLatch(&MyProc->procLatch); + } +} + +/* + * Send a Standby Status Update message to server. + * + * 'recvpos' is the latest LSN we've received data to, force is set if we need + * to send a response to avoid timeouts. + */ +static void +send_feedback(XLogRecPtr recvpos, bool force, bool requestReply) +{ + static StringInfo reply_message = NULL; + static TimestampTz send_time = 0; + + static XLogRecPtr last_recvpos = InvalidXLogRecPtr; + static XLogRecPtr last_writepos = InvalidXLogRecPtr; + static XLogRecPtr last_flushpos = InvalidXLogRecPtr; + + XLogRecPtr writepos; + XLogRecPtr flushpos; + TimestampTz now; + bool have_pending_txes; + + /* + * If the user doesn't want status to be reported to the publisher, be + * sure to exit before doing anything at all. + */ + if (!force && wal_receiver_status_interval <= 0) + return; + + /* It's legal to not pass a recvpos */ + if (recvpos < last_recvpos) + recvpos = last_recvpos; + + get_flush_position(&writepos, &flushpos, &have_pending_txes); + + /* + * No outstanding transactions to flush, we can report the latest + * received position. This is important for synchronous replication. + */ + if (!have_pending_txes) + flushpos = writepos = recvpos; + + if (writepos < last_writepos) + writepos = last_writepos; + + if (flushpos < last_flushpos) + flushpos = last_flushpos; + + now = GetCurrentTimestamp(); + + /* if we've already reported everything we're good */ + if (!force && + writepos == last_writepos && + flushpos == last_flushpos && + !TimestampDifferenceExceeds(send_time, now, + wal_receiver_status_interval * 1000)) + return; + send_time = now; + + if (!reply_message) + { + MemoryContext oldctx = MemoryContextSwitchTo(ApplyCacheContext); + reply_message = makeStringInfo(); + MemoryContextSwitchTo(oldctx); + } + else + resetStringInfo(reply_message); + + pq_sendbyte(reply_message, 'r'); + pq_sendint64(reply_message, recvpos); /* write */ + pq_sendint64(reply_message, flushpos); /* flush */ + pq_sendint64(reply_message, writepos); /* apply */ + pq_sendint64(reply_message, now); /* sendTime */ + pq_sendbyte(reply_message, requestReply); /* replyRequested */ + + elog(DEBUG2, "sending feedback (force %d) to recv %X/%X, write %X/%X, flush %X/%X", + force, + (uint32) (recvpos >> 32), (uint32) recvpos, + (uint32) (writepos >> 32), (uint32) writepos, + (uint32) (flushpos >> 32), (uint32) flushpos + ); + + walrcv_send(wrconn, reply_message->data, reply_message->len); + + if (recvpos > last_recvpos) + last_recvpos = recvpos; + if (writepos > last_writepos) + last_writepos = writepos; + if (flushpos > last_flushpos) + last_flushpos = flushpos; +} + + +/* + * Reread subscription info and exit on change. + */ +static void +reread_subscription(void) +{ + MemoryContext oldctx; + Subscription *newsub; + + /* Ensure allocations in permanent context. */ + oldctx = MemoryContextSwitchTo(ApplyCacheContext); + + newsub = GetSubscription(MyLogicalRepWorker->subid, true); + + /* + * Exit if connection string was changed. The launcher will start + * new worker. + */ + if (strcmp(newsub->conninfo, MySubscription->conninfo) != 0) + { + ereport(LOG, + (errmsg("logical replication worker for subscription \"%s\" will " + "restart because the connection information was changed", + MySubscription->name))); + + walrcv_disconnect(wrconn); + proc_exit(0); + } + + /* + * Exit if publication list was changed. The launcher will start + * new worker. + */ + if (!equal(newsub->publications, MySubscription->publications)) + { + ereport(LOG, + (errmsg("logical replication worker for subscription \"%s\" will " + "restart because subscription's publications were changed", + MySubscription->name))); + + walrcv_disconnect(wrconn); + proc_exit(0); + } + + /* + * Exit if the subscription was removed. + * This normally should not happen as the worker gets killed + * during DROP SUBSCRIPTION. + */ + if (!newsub) + { + ereport(LOG, + (errmsg("logical replication worker for subscription \"%s\" will " + "stop because the subscription was removed", + MySubscription->name))); + + walrcv_disconnect(wrconn); + proc_exit(0); + } + + /* + * Exit if the subscription was disabled. + * This normally should not happen as the worker gets killed + * during ALTER SUBSCRIPTION ... DISABLE. + */ + if (!newsub->enabled) + { + ereport(LOG, + (errmsg("logical replication worker for subscription \"%s\" will " + "stop because the subscription was disabled", + MySubscription->name))); + + walrcv_disconnect(wrconn); + proc_exit(0); + } + + /* Check for other changes that should never happen too. */ + if (newsub->dbid != MySubscription->dbid || + strcmp(newsub->name, MySubscription->name) != 0 || + strcmp(newsub->slotname, MySubscription->slotname) != 0) + { + elog(ERROR, "subscription %u changed unexpectedly", + MyLogicalRepWorker->subid); + } + + /* Clean old subscription info and switch to new one. */ + FreeSubscription(MySubscription); + MySubscription = newsub; + + MemoryContextSwitchTo(oldctx); + + MySubscriptionValid = true; +} + +/* + * Callback from subscription syscache invalidation. + */ +static void +subscription_change_cb(Datum arg, int cacheid, uint32 hashvalue) +{ + MySubscriptionValid = false; +} + + +/* Logical Replication Apply worker entry point */ +void +ApplyWorkerMain(Datum main_arg) +{ + int worker_slot = DatumGetObjectId(main_arg); + MemoryContext oldctx; + char originname[NAMEDATALEN]; + RepOriginId originid; + XLogRecPtr origin_startpos; + char *err; + int server_version; + TimeLineID startpointTLI; + WalRcvStreamOptions options; + + /* Attach to slot */ + logicalrep_worker_attach(worker_slot); + + /* Setup signal handling */ + pqsignal(SIGTERM, logicalrep_worker_sigterm); + BackgroundWorkerUnblockSignals(); + + /* Initialise stats to a sanish value */ + MyLogicalRepWorker->last_send_time = MyLogicalRepWorker->last_recv_time = + MyLogicalRepWorker->reply_time = GetCurrentTimestamp(); + + /* Make it easy to identify our processes. */ + SetConfigOption("application_name", MyBgworkerEntry->bgw_name, + PGC_USERSET, PGC_S_SESSION); + + /* Load the libpq-specific functions */ + load_file("libpqwalreceiver", false); + + Assert(CurrentResourceOwner == NULL); + CurrentResourceOwner = ResourceOwnerCreate(NULL, + "logical replication apply"); + + /* Run as replica session replication role. */ + SetConfigOption("session_replication_role", "replica", + PGC_SUSET, PGC_S_OVERRIDE); + + /* Connect to our database. */ + BackgroundWorkerInitializeConnectionByOid(MyLogicalRepWorker->dbid, + MyLogicalRepWorker->userid); + + /* Load the subscription into persistent memory context. */ + CreateCacheMemoryContext(); + ApplyCacheContext = AllocSetContextCreate(CacheMemoryContext, + "ApplyCacheContext", + ALLOCSET_DEFAULT_SIZES); + StartTransactionCommand(); + oldctx = MemoryContextSwitchTo(ApplyCacheContext); + MySubscription = GetSubscription(MyLogicalRepWorker->subid, false); + MySubscriptionValid = true; + MemoryContextSwitchTo(oldctx); + + if (!MySubscription->enabled) + { + ereport(LOG, + (errmsg("logical replication worker for subscription \"%s\" will not " + "start because the subscription was disabled during startup", + MySubscription->name))); + + proc_exit(0); + } + + /* Keep us informed about subscription changes. */ + CacheRegisterSyscacheCallback(SUBSCRIPTIONOID, + subscription_change_cb, + (Datum) 0); + + ereport(LOG, + (errmsg("logical replication apply for subscription \"%s\" has started", + MySubscription->name))); + + /* Setup replication origin tracking. */ + snprintf(originname, sizeof(originname), "pg_%u", MySubscription->oid); + originid = replorigin_by_name(originname, true); + if (!OidIsValid(originid)) + originid = replorigin_create(originname); + replorigin_session_setup(originid); + replorigin_session_origin = originid; + origin_startpos = replorigin_session_get_progress(false); + + CommitTransactionCommand(); + + /* Connect to the origin and start the replication. */ + elog(DEBUG1, "connecting to publisher using connection string \"%s\"", + MySubscription->conninfo); + wrconn = walrcv_connect(MySubscription->conninfo, true, + MySubscription->name, &err); + if (wrconn == NULL) + ereport(ERROR, + (errmsg("could not connect to the publisher: %s", err))); + + /* + * We don't really use the output identify_system for anything + * but it does some initializations on the upstream so let's still + * call it. + */ + (void) walrcv_identify_system(wrconn, &startpointTLI, &server_version); + + /* Build logical replication streaming options. */ + options.logical = true; + options.startpoint = origin_startpos; + options.slotname = MySubscription->slotname; + options.proto.logical.proto_version = LOGICALREP_PROTO_VERSION_NUM; + options.proto.logical.publication_names = MySubscription->publications; + + /* Start streaming from the slot. */ + walrcv_startstreaming(wrconn, &options); + + /* Run the main loop. */ + ApplyLoop(); + + walrcv_disconnect(wrconn); + + /* We should only get here if we received SIGTERM */ + proc_exit(0); +} diff --git a/src/backend/replication/pgoutput/Makefile b/src/backend/replication/pgoutput/Makefile new file mode 100644 index 0000000000..cbe444bae3 --- /dev/null +++ b/src/backend/replication/pgoutput/Makefile @@ -0,0 +1,30 @@ +#------------------------------------------------------------------------- +# +# Makefile-- +# Makefile for src/backend/replication/pgoutput +# +# IDENTIFICATION +# src/backend/replication/pgoutput +# +#------------------------------------------------------------------------- + +subdir = src/backend/replication/pgoutput +top_builddir = ../../../.. +include $(top_builddir)/src/Makefile.global + +OBJS = pgoutput.o $(WIN32RES) +PGFILEDESC = "pgoutput - standard logical replication output plugin" +NAME = pgoutput + +all: all-shared-lib + +include $(top_srcdir)/src/Makefile.shlib + +install: all installdirs install-lib + +installdirs: installdirs-lib + +uninstall: uninstall-lib + +clean distclean maintainer-clean: clean-lib + rm -f $(OBJS) diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c new file mode 100644 index 0000000000..08c30af88a --- /dev/null +++ b/src/backend/replication/pgoutput/pgoutput.c @@ -0,0 +1,596 @@ +/*------------------------------------------------------------------------- + * + * pgoutput.c + * Logical Replication output plugin + * + * Copyright (c) 2012-2015, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/backend/replication/pgoutput/pgoutput.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "catalog/pg_publication.h" + +#include "replication/logical.h" +#include "replication/logicalproto.h" +#include "replication/origin.h" +#include "replication/pgoutput.h" + +#include "utils/inval.h" +#include "utils/int8.h" +#include "utils/memutils.h" +#include "utils/syscache.h" +#include "utils/varlena.h" + +PG_MODULE_MAGIC; + +extern void _PG_output_plugin_init(OutputPluginCallbacks *cb); + +static void pgoutput_startup(LogicalDecodingContext * ctx, + OutputPluginOptions *opt, bool is_init); +static void pgoutput_shutdown(LogicalDecodingContext * ctx); +static void pgoutput_begin_txn(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn); +static void pgoutput_commit_txn(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, XLogRecPtr commit_lsn); +static void pgoutput_change(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, Relation rel, + ReorderBufferChange *change); +static bool pgoutput_origin_filter(LogicalDecodingContext *ctx, + RepOriginId origin_id); + +static bool publications_valid; + +static List *LoadPublications(List *pubnames); +static void publication_invalidation_cb(Datum arg, int cacheid, + uint32 hashvalue); + +/* Entry in the map used to remember which relation schemas we sent. */ +typedef struct RelationSyncEntry +{ + Oid relid; /* relation oid */ + bool schema_sent; /* did we send the schema? */ + bool replicate_valid; + PublicationActions pubactions; +} RelationSyncEntry; + +/* Map used to remember which relation schemas we sent. */ +static HTAB *RelationSyncCache = NULL; + +static void init_rel_sync_cache(MemoryContext decoding_context); +static RelationSyncEntry *get_rel_sync_entry(PGOutputData *data, Oid relid); +static void rel_sync_cache_relation_cb(Datum arg, Oid relid); +static void rel_sync_cache_publication_cb(Datum arg, int cacheid, + uint32 hashvalue); + +/* + * Specify output plugin callbacks + */ +void +_PG_output_plugin_init(OutputPluginCallbacks *cb) +{ + AssertVariableIsOfType(&_PG_output_plugin_init, LogicalOutputPluginInit); + + cb->startup_cb = pgoutput_startup; + cb->begin_cb = pgoutput_begin_txn; + cb->change_cb = pgoutput_change; + cb->commit_cb = pgoutput_commit_txn; + cb->filter_by_origin_cb = pgoutput_origin_filter; + cb->shutdown_cb = pgoutput_shutdown; +} + +static void +parse_output_parameters(List *options, uint32 *protocol_version, + List **publication_names) +{ + ListCell *lc; + bool protocol_version_given = false; + bool publication_names_given = false; + + foreach(lc, options) + { + DefElem *defel = (DefElem *) lfirst(lc); + + Assert(defel->arg == NULL || IsA(defel->arg, String)); + + /* Check each param, whether or not we recognise it */ + if (strcmp(defel->defname, "proto_version") == 0) + { + int64 parsed; + + if (protocol_version_given) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + protocol_version_given = true; + + if (!scanint8(strVal(defel->arg), true, &parsed)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid proto_version"))); + + if (parsed > PG_UINT32_MAX || parsed < 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("proto_verson \"%s\" out of range", + strVal(defel->arg)))); + + *protocol_version = (uint32) parsed; + } + else if (strcmp(defel->defname, "publication_names") == 0) + { + if (publication_names_given) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + publication_names_given = true; + + if (!SplitIdentifierString(strVal(defel->arg), ',', + publication_names)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("invalid publication_names syntax"))); + } + else + elog(ERROR, "unrecognized pgoutput option: %s", defel->defname); + } +} + +/* + * Initialize this plugin + */ +static void +pgoutput_startup(LogicalDecodingContext * ctx, OutputPluginOptions *opt, + bool is_init) +{ + PGOutputData *data = palloc0(sizeof(PGOutputData)); + + /* Create our memory context for private allocations. */ + data->context = AllocSetContextCreate(ctx->context, + "logical replication output context", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + + ctx->output_plugin_private = data; + + /* This plugin uses binary protocol. */ + opt->output_type = OUTPUT_PLUGIN_BINARY_OUTPUT; + + /* + * This is replication start and not slot initialization. + * + * Parse and validate options passed by the client. + */ + if (!is_init) + { + /* Parse the params and ERROR if we see any we don't recognise */ + parse_output_parameters(ctx->output_plugin_options, + &data->protocol_version, + &data->publication_names); + + /* Check if we support requested protol */ + if (data->protocol_version != LOGICALREP_PROTO_VERSION_NUM) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("client sent proto_version=%d but we only support protocol %d or lower", + data->protocol_version, LOGICALREP_PROTO_VERSION_NUM))); + + if (data->protocol_version < LOGICALREP_PROTO_MIN_VERSION_NUM) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("client sent proto_version=%d but we only support protocol %d or higher", + data->protocol_version, LOGICALREP_PROTO_MIN_VERSION_NUM))); + + if (list_length(data->publication_names) < 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("publication_names parameter missing"))); + + /* Init publication state. */ + data->publications = NIL; + publications_valid = false; + CacheRegisterSyscacheCallback(PUBLICATIONOID, + publication_invalidation_cb, + (Datum) 0); + + /* Initialize relation schema cache. */ + init_rel_sync_cache(CacheMemoryContext); + } +} + +/* + * BEGIN callback + */ +static void +pgoutput_begin_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *txn) +{ + bool send_replication_origin = txn->origin_id != InvalidRepOriginId; + + OutputPluginPrepareWrite(ctx, !send_replication_origin); + logicalrep_write_begin(ctx->out, txn); + + if (send_replication_origin) + { + char *origin; + + /* Message boundary */ + OutputPluginWrite(ctx, false); + OutputPluginPrepareWrite(ctx, true); + + /* + * XXX: which behaviour we want here? + * + * Alternatives: + * - don't send origin message if origin name not found + * (that's what we do now) + * - throw error - that will break replication, not good + * - send some special "unknown" origin + */ + if (replorigin_by_oid(txn->origin_id, true, &origin)) + logicalrep_write_origin(ctx->out, origin, txn->origin_lsn); + } + + OutputPluginWrite(ctx, true); +} + +/* + * COMMIT callback + */ +static void +pgoutput_commit_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, + XLogRecPtr commit_lsn) +{ + OutputPluginPrepareWrite(ctx, true); + logicalrep_write_commit(ctx->out, txn, commit_lsn); + OutputPluginWrite(ctx, true); +} + +/* + * Sends the decoded DML over wire. + */ +static void +pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, + Relation relation, ReorderBufferChange *change) +{ + PGOutputData *data = (PGOutputData *) ctx->output_plugin_private; + MemoryContext old; + RelationSyncEntry *relentry; + + relentry = get_rel_sync_entry(data, RelationGetRelid(relation)); + + /* First check the table filter */ + switch (change->action) + { + case REORDER_BUFFER_CHANGE_INSERT: + if (!relentry->pubactions.pubinsert) + return; + break; + case REORDER_BUFFER_CHANGE_UPDATE: + if (!relentry->pubactions.pubupdate) + return; + break; + case REORDER_BUFFER_CHANGE_DELETE: + if (!relentry->pubactions.pubdelete) + return; + break; + default: + Assert(false); + } + + /* Avoid leaking memory by using and resetting our own context */ + old = MemoryContextSwitchTo(data->context); + + /* + * Write the relation schema if the current schema haven't been sent yet. + */ + if (!relentry->schema_sent) + { + TupleDesc desc; + int i; + + desc = RelationGetDescr(relation); + + /* + * Write out type info if needed. We do that only for user created + * types. + */ + for (i = 0; i < desc->natts; i++) + { + Form_pg_attribute att = desc->attrs[i]; + + if (att->attisdropped) + continue; + + if (att->atttypid < FirstNormalObjectId) + continue; + + OutputPluginPrepareWrite(ctx, false); + logicalrep_write_typ(ctx->out, att->atttypid); + OutputPluginWrite(ctx, false); + } + + OutputPluginPrepareWrite(ctx, false); + logicalrep_write_rel(ctx->out, relation); + OutputPluginWrite(ctx, false); + relentry->schema_sent = true; + } + + /* Send the data */ + switch (change->action) + { + case REORDER_BUFFER_CHANGE_INSERT: + OutputPluginPrepareWrite(ctx, true); + logicalrep_write_insert(ctx->out, relation, + &change->data.tp.newtuple->tuple); + OutputPluginWrite(ctx, true); + break; + case REORDER_BUFFER_CHANGE_UPDATE: + { + HeapTuple oldtuple = change->data.tp.oldtuple ? + &change->data.tp.oldtuple->tuple : NULL; + + OutputPluginPrepareWrite(ctx, true); + logicalrep_write_update(ctx->out, relation, oldtuple, + &change->data.tp.newtuple->tuple); + OutputPluginWrite(ctx, true); + break; + } + case REORDER_BUFFER_CHANGE_DELETE: + if (change->data.tp.oldtuple) + { + OutputPluginPrepareWrite(ctx, true); + logicalrep_write_delete(ctx->out, relation, + &change->data.tp.oldtuple->tuple); + OutputPluginWrite(ctx, true); + } + else + elog(DEBUG1, "didn't send DELETE change because of missing oldtuple"); + break; + default: + Assert(false); + } + + /* Cleanup */ + MemoryContextSwitchTo(old); + MemoryContextReset(data->context); +} + +/* + * Currently we always forward. + */ +static bool +pgoutput_origin_filter(LogicalDecodingContext *ctx, + RepOriginId origin_id) +{ + return false; +} + +/* + * Shutdown the output plugin. + * + * Note, we don't need to clean the data->context as it's child context + * of the ctx->context so it will be cleaned up by logical decoding machinery. + */ +static void +pgoutput_shutdown(LogicalDecodingContext * ctx) +{ + if (RelationSyncCache) + { + hash_destroy(RelationSyncCache); + RelationSyncCache = NULL; + } +} + +/* + * Load publications from the list of publication names. + */ +static List * +LoadPublications(List *pubnames) +{ + List *result = NIL; + ListCell *lc; + + foreach (lc, pubnames) + { + char *pubname = (char *) lfirst(lc); + Publication *pub = GetPublicationByName(pubname, false); + + result = lappend(result, pub); + } + + return result; +} + +/* + * Publication cache invalidation callback. + */ +static void +publication_invalidation_cb(Datum arg, int cacheid, uint32 hashvalue) +{ + publications_valid = false; + + /* + * Also invalidate per-relation cache so that next time the filtering + * info is checked it will be updated with the new publication + * settings. + */ + rel_sync_cache_publication_cb(arg, cacheid, hashvalue); +} + +/* + * Initialize the relation schema sync cache for a decoding session. + * + * The hash table is destoyed at the end of a decoding session. While + * relcache invalidations still exist and will still be invoked, they + * will just see the null hash table global and take no action. + */ +static void +init_rel_sync_cache(MemoryContext cachectx) +{ + HASHCTL ctl; + MemoryContext old_ctxt; + + if (RelationSyncCache != NULL) + return; + + /* Make a new hash table for the cache */ + MemSet(&ctl, 0, sizeof(ctl)); + ctl.keysize = sizeof(Oid); + ctl.entrysize = sizeof(RelationSyncEntry); + ctl.hcxt = cachectx; + + old_ctxt = MemoryContextSwitchTo(cachectx); + RelationSyncCache = hash_create("logical replication output relation cache", + 128, &ctl, + HASH_ELEM | HASH_CONTEXT | HASH_BLOBS); + (void) MemoryContextSwitchTo(old_ctxt); + + Assert(RelationSyncCache != NULL); + + CacheRegisterRelcacheCallback(rel_sync_cache_relation_cb, (Datum) 0); + CacheRegisterSyscacheCallback(PUBLICATIONRELMAP, + rel_sync_cache_publication_cb, + (Datum) 0); +} + +/* + * Find or create entry in the relation schema cache. + */ +static RelationSyncEntry * +get_rel_sync_entry(PGOutputData *data, Oid relid) +{ + RelationSyncEntry *entry; + bool found; + MemoryContext oldctx; + + Assert(RelationSyncCache != NULL); + + /* Find cached function info, creating if not found */ + oldctx = MemoryContextSwitchTo(CacheMemoryContext); + entry = (RelationSyncEntry *) hash_search(RelationSyncCache, + (void *) &relid, + HASH_ENTER, &found); + MemoryContextSwitchTo(oldctx); + Assert(entry != NULL); + + /* Not found means schema wasn't sent */ + if (!found || !entry->replicate_valid) + { + List *pubids = GetRelationPublications(relid); + ListCell *lc; + + /* Reload publications if needed before use. */ + if (!publications_valid) + { + oldctx = MemoryContextSwitchTo(CacheMemoryContext); + if (data->publications) + list_free_deep(data->publications); + + data->publications = LoadPublications(data->publication_names); + MemoryContextSwitchTo(oldctx); + publications_valid = true; + } + + /* + * Build publication cache. We can't use one provided by relcache + * as relcache considers all publications given relation is in, but + * here we only need to consider ones that the subscriber requested. + */ + entry->pubactions.pubinsert = entry->pubactions.pubupdate = + entry->pubactions.pubdelete = false; + + foreach(lc, data->publications) + { + Publication *pub = lfirst(lc); + + if (pub->alltables || list_member_oid(pubids, pub->oid)) + { + entry->pubactions.pubinsert |= pub->pubactions.pubinsert; + entry->pubactions.pubupdate |= pub->pubactions.pubupdate; + entry->pubactions.pubdelete |= pub->pubactions.pubdelete; + } + + if (entry->pubactions.pubinsert && entry->pubactions.pubupdate && + entry->pubactions.pubdelete) + break; + } + + list_free(pubids); + + entry->replicate_valid = true; + } + + if (!found) + entry->schema_sent = false; + + return entry; +} + +/* + * Relcache invalidation callback + */ +static void +rel_sync_cache_relation_cb(Datum arg, Oid relid) +{ + RelationSyncEntry *entry; + + /* + * We can get here if the plugin was used in SQL interface as the + * RelSchemaSyncCache is detroyed when the decoding finishes, but there + * is no way to unregister the relcache invalidation callback. + */ + if (RelationSyncCache == NULL) + return; + + /* + * Nobody keeps pointers to entries in this hash table around outside + * logical decoding callback calls - but invalidation events can come in + * *during* a callback if we access the relcache in the callback. Because + * of that we must mark the cache entry as invalid but not remove it from + * the hash while it could still be referenced, then prune it at a later + * safe point. + * + * Getting invalidations for relations that aren't in the table is + * entirely normal, since there's no way to unregister for an + * invalidation event. So we don't care if it's found or not. + */ + entry = (RelationSyncEntry *) hash_search(RelationSyncCache, &relid, + HASH_FIND, NULL); + + /* + * Reset schema sent status as the relation definition may have + * changed. + */ + if (entry != NULL) + entry->schema_sent = false; +} + +/* + * Publication relation map syscache invalidation callback + */ +static void +rel_sync_cache_publication_cb(Datum arg, int cacheid, uint32 hashvalue) +{ + HASH_SEQ_STATUS status; + RelationSyncEntry *entry; + + /* + * We can get here if the plugin was used in SQL interface as the + * RelSchemaSyncCache is detroyed when the decoding finishes, but there + * is no way to unregister the relcache invalidation callback. + */ + if (RelationSyncCache == NULL) + return; + + /* + * There is no way to find which entry in our cache the hash belongs to + * so mark the whole cache as invalid. + */ + hash_seq_init(&status, RelationSyncCache); + while ((entry = (RelationSyncEntry *) hash_seq_search(&status)) != NULL) + entry->replicate_valid = false; +} diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y index d93db88d42..d962c76819 100644 --- a/src/backend/replication/repl_gram.y +++ b/src/backend/replication/repl_gram.y @@ -3,7 +3,7 @@ * * repl_gram.y - Parser for the replication commands * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -77,6 +77,7 @@ Node *replication_parse_result; %token K_LOGICAL %token K_SLOT %token K_RESERVE_WAL +%token K_TEMPORARY %type command %type base_backup start_replication start_logical_replication @@ -89,7 +90,7 @@ Node *replication_parse_result; %type plugin_opt_elem %type plugin_opt_arg %type opt_slot -%type opt_reserve_wal +%type opt_reserve_wal opt_temporary %% @@ -130,8 +131,7 @@ identify_system: base_backup: K_BASE_BACKUP base_backup_opt_list { - BaseBackupCmd *cmd = - (BaseBackupCmd *) makeNode(BaseBackupCmd); + BaseBackupCmd *cmd = makeNode(BaseBackupCmd); cmd->options = $2; $$ = (Node *) cmd; } @@ -148,59 +148,61 @@ base_backup_opt: K_LABEL SCONST { $$ = makeDefElem("label", - (Node *)makeString($2)); + (Node *)makeString($2), -1); } | K_PROGRESS { $$ = makeDefElem("progress", - (Node *)makeInteger(TRUE)); + (Node *)makeInteger(TRUE), -1); } | K_FAST { $$ = makeDefElem("fast", - (Node *)makeInteger(TRUE)); + (Node *)makeInteger(TRUE), -1); } | K_WAL { $$ = makeDefElem("wal", - (Node *)makeInteger(TRUE)); + (Node *)makeInteger(TRUE), -1); } | K_NOWAIT { $$ = makeDefElem("nowait", - (Node *)makeInteger(TRUE)); + (Node *)makeInteger(TRUE), -1); } | K_MAX_RATE UCONST { $$ = makeDefElem("max_rate", - (Node *)makeInteger($2)); + (Node *)makeInteger($2), -1); } | K_TABLESPACE_MAP { $$ = makeDefElem("tablespace_map", - (Node *)makeInteger(TRUE)); + (Node *)makeInteger(TRUE), -1); } ; create_replication_slot: - /* CREATE_REPLICATION_SLOT slot PHYSICAL RESERVE_WAL */ - K_CREATE_REPLICATION_SLOT IDENT K_PHYSICAL opt_reserve_wal + /* CREATE_REPLICATION_SLOT slot TEMPORARY PHYSICAL RESERVE_WAL */ + K_CREATE_REPLICATION_SLOT IDENT opt_temporary K_PHYSICAL opt_reserve_wal { CreateReplicationSlotCmd *cmd; cmd = makeNode(CreateReplicationSlotCmd); cmd->kind = REPLICATION_KIND_PHYSICAL; cmd->slotname = $2; - cmd->reserve_wal = $4; + cmd->temporary = $3; + cmd->reserve_wal = $5; $$ = (Node *) cmd; } - /* CREATE_REPLICATION_SLOT slot LOGICAL plugin */ - | K_CREATE_REPLICATION_SLOT IDENT K_LOGICAL IDENT + /* CREATE_REPLICATION_SLOT slot TEMPORARY LOGICAL plugin */ + | K_CREATE_REPLICATION_SLOT IDENT opt_temporary K_LOGICAL IDENT { CreateReplicationSlotCmd *cmd; cmd = makeNode(CreateReplicationSlotCmd); cmd->kind = REPLICATION_KIND_LOGICAL; cmd->slotname = $2; - cmd->plugin = $4; + cmd->temporary = $3; + cmd->plugin = $5; $$ = (Node *) cmd; } ; @@ -276,6 +278,11 @@ opt_reserve_wal: | /* EMPTY */ { $$ = false; } ; +opt_temporary: + K_TEMPORARY { $$ = true; } + | /* EMPTY */ { $$ = false; } + ; + opt_slot: K_SLOT IDENT { $$ = $2; } @@ -315,7 +322,7 @@ plugin_opt_list: plugin_opt_elem: IDENT plugin_opt_arg { - $$ = makeDefElem($1, $2); + $$ = makeDefElem($1, $2, -1); } ; diff --git a/src/backend/replication/repl_scanner.l b/src/backend/replication/repl_scanner.l index f83ec538b6..a3b5f92663 100644 --- a/src/backend/replication/repl_scanner.l +++ b/src/backend/replication/repl_scanner.l @@ -4,7 +4,7 @@ * repl_scanner.l * a lexical scanner for the replication commands * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -98,6 +98,7 @@ PHYSICAL { return K_PHYSICAL; } RESERVE_WAL { return K_RESERVE_WAL; } LOGICAL { return K_LOGICAL; } SLOT { return K_SLOT; } +TEMPORARY { return K_TEMPORARY; } "," { return ','; } ";" { return ';'; } diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c index 2fb7c17d7d..10d69d0427 100644 --- a/src/backend/replication/slot.c +++ b/src/backend/replication/slot.c @@ -4,7 +4,7 @@ * Replication slot management. * * - * Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Copyright (c) 2012-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -47,6 +47,7 @@ #include "storage/fd.h" #include "storage/proc.h" #include "storage/procarray.h" +#include "utils/builtins.h" /* * Replication slot on-disk data structure. @@ -97,8 +98,8 @@ ReplicationSlot *MyReplicationSlot = NULL; int max_replication_slots = 0; /* the maximum number of replication * slots */ -static LWLockTranche ReplSlotIOLWLockTranche; static void ReplicationSlotDropAcquired(void); +static void ReplicationSlotDropPtr(ReplicationSlot *slot); /* internal persistency functions */ static void RestoreSlotFromDisk(const char *name); @@ -138,12 +139,8 @@ ReplicationSlotsShmemInit(void) ShmemInitStruct("ReplicationSlot Ctl", ReplicationSlotsShmemSize(), &found); - ReplSlotIOLWLockTranche.name = "replication_slot_io"; - ReplSlotIOLWLockTranche.array_base = - ((char *) ReplicationSlotCtl) + offsetof(ReplicationSlotCtlData, replication_slots) +offsetof(ReplicationSlot, io_in_progress_lock); - ReplSlotIOLWLockTranche.array_stride = sizeof(ReplicationSlot); LWLockRegisterTranche(LWTRANCHE_REPLICATION_SLOT_IO_IN_PROGRESS, - &ReplSlotIOLWLockTranche); + "replication_slot_io"); if (!found) { @@ -272,12 +269,22 @@ ReplicationSlotCreate(const char *name, bool db_specific, */ Assert(!slot->in_use); Assert(slot->active_pid == 0); - slot->data.persistency = persistency; - slot->data.xmin = InvalidTransactionId; - slot->effective_xmin = InvalidTransactionId; + + /* first initialize persistent data */ + memset(&slot->data, 0, sizeof(ReplicationSlotPersistentData)); StrNCpy(NameStr(slot->data.name), name, NAMEDATALEN); slot->data.database = db_specific ? MyDatabaseId : InvalidOid; - slot->data.restart_lsn = InvalidXLogRecPtr; + slot->data.persistency = persistency; + + /* and then data only present in shared memory */ + slot->just_dirtied = false; + slot->dirty = false; + slot->effective_xmin = InvalidTransactionId; + slot->effective_catalog_xmin = InvalidTransactionId; + slot->candidate_catalog_xmin = InvalidTransactionId; + slot->candidate_xmin_lsn = InvalidXLogRecPtr; + slot->candidate_restart_valid = InvalidXLogRecPtr; + slot->candidate_restart_lsn = InvalidXLogRecPtr; /* * Create the slot on disk. We haven't actually marked the slot allocated @@ -319,7 +326,7 @@ ReplicationSlotAcquire(const char *name) { ReplicationSlot *slot = NULL; int i; - int active_pid = 0; + int active_pid = 0; /* Keep compiler quiet */ Assert(MyReplicationSlot == NULL); @@ -336,7 +343,7 @@ ReplicationSlotAcquire(const char *name) SpinLockAcquire(&s->mutex); active_pid = s->active_pid; if (active_pid == 0) - s->active_pid = MyProcPid; + active_pid = s->active_pid = MyProcPid; SpinLockRelease(&s->mutex); slot = s; break; @@ -349,7 +356,7 @@ ReplicationSlotAcquire(const char *name) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("replication slot \"%s\" does not exist", name))); - if (active_pid != 0) + if (active_pid != MyProcPid) ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), errmsg("replication slot \"%s\" is active for PID %d", @@ -379,9 +386,12 @@ ReplicationSlotRelease(void) */ ReplicationSlotDropAcquired(); } - else + else if (slot->data.persistency == RS_PERSISTENT) { - /* Mark slot inactive. We're not freeing it, just disconnecting. */ + /* + * Mark persistent slot inactive. We're not freeing it, just + * disconnecting. + */ SpinLockAcquire(&slot->mutex); slot->active_pid = 0; SpinLockRelease(&slot->mutex); @@ -395,6 +405,33 @@ ReplicationSlotRelease(void) LWLockRelease(ProcArrayLock); } +/* + * Cleanup all temporary slots created in current session. + */ +void +ReplicationSlotCleanup() +{ + int i; + + Assert(MyReplicationSlot == NULL); + + /* + * No need for locking as we are only interested in slots active in + * current process and those are not touched by other processes. + */ + for (i = 0; i < max_replication_slots; i++) + { + ReplicationSlot *s = &ReplicationSlotCtl->replication_slots[i]; + + if (s->active_pid == MyProcPid) + { + Assert(s->in_use && s->data.persistency == RS_TEMPORARY); + + ReplicationSlotDropPtr(s); + } + } +} + /* * Permanently drop replication slot identified by the passed in name. */ @@ -409,14 +446,11 @@ ReplicationSlotDrop(const char *name) } /* - * Permanently drop the currently acquired replication slot which will be - * released by the point this function returns. + * Permanently drop the currently acquired replication slot. */ static void ReplicationSlotDropAcquired(void) { - char path[MAXPGPATH]; - char tmppath[MAXPGPATH]; ReplicationSlot *slot = MyReplicationSlot; Assert(MyReplicationSlot != NULL); @@ -424,6 +458,19 @@ ReplicationSlotDropAcquired(void) /* slot isn't acquired anymore */ MyReplicationSlot = NULL; + ReplicationSlotDropPtr(slot); +} + +/* + * Permanently drop the replication slot which will be released by the point + * this function returns. + */ +static void +ReplicationSlotDropPtr(ReplicationSlot *slot) +{ + char path[MAXPGPATH]; + char tmppath[MAXPGPATH]; + /* * If some other backend ran this code concurrently with us, we might try * to delete a slot with a certain name while someone else was trying to @@ -438,9 +485,9 @@ ReplicationSlotDropAcquired(void) /* * Rename the slot directory on disk, so that we'll no longer recognize * this as a valid slot. Note that if this fails, we've got to mark the - * slot inactive before bailing out. If we're dropping an ephemeral slot, - * we better never fail hard as the caller won't expect the slot to - * survive and this might get called during error handling. + * slot inactive before bailing out. If we're dropping an ephemeral or + * a temporary slot, we better never fail hard as the caller won't expect + * the slot to survive and this might get called during error handling. */ if (rename(path, tmppath) == 0) { @@ -459,7 +506,7 @@ ReplicationSlotDropAcquired(void) } else { - bool fail_softly = slot->data.persistency == RS_EPHEMERAL; + bool fail_softly = slot->data.persistency != RS_PERSISTENT; SpinLockAcquire(&slot->mutex); slot->active_pid = 0; diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c index f9087619d2..7104c94795 100644 --- a/src/backend/replication/slotfuncs.c +++ b/src/backend/replication/slotfuncs.c @@ -3,7 +3,7 @@ * slotfuncs.c * Support functions for replication slots * - * Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Copyright (c) 2012-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/slotfuncs.c @@ -41,6 +41,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS) { Name name = PG_GETARG_NAME(0); bool immediately_reserve = PG_GETARG_BOOL(1); + bool temporary = PG_GETARG_BOOL(2); Datum values[2]; bool nulls[2]; TupleDesc tupdesc; @@ -57,7 +58,8 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS) CheckSlotRequirements(); /* acquire replication slot, this will check for conflicting names */ - ReplicationSlotCreate(NameStr(*name), false, RS_PERSISTENT); + ReplicationSlotCreate(NameStr(*name), false, + temporary ? RS_TEMPORARY : RS_PERSISTENT); values[0] = NameGetDatum(&MyReplicationSlot->data.name); nulls[0] = false; @@ -96,6 +98,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS) { Name name = PG_GETARG_NAME(0); Name plugin = PG_GETARG_NAME(1); + bool temporary = PG_GETARG_BOOL(2); LogicalDecodingContext *ctx = NULL; @@ -116,11 +119,14 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS) /* * Acquire a logical decoding slot, this will check for conflicting names. - * Initially create it as ephemeral - that allows us to nicely handle - * errors during initialization because it'll get dropped if this + * Initially create persistent slot as ephemeral - that allows us to nicely + * handle errors during initialization because it'll get dropped if this * transaction fails. We'll make it persistent at the end. + * Temporary slots can be created as temporary from beginning as they get + * dropped on error as well. */ - ReplicationSlotCreate(NameStr(*name), true, RS_EPHEMERAL); + ReplicationSlotCreate(NameStr(*name), true, + temporary ? RS_TEMPORARY : RS_EPHEMERAL); /* * Create logical decoding context, to build the initial snapshot. @@ -143,8 +149,9 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS) tuple = heap_form_tuple(tupdesc, values, nulls); result = HeapTupleGetDatum(tuple); - /* ok, slot is now fully created, mark it as persistent */ - ReplicationSlotPersist(); + /* ok, slot is now fully created, mark it as persistent if needed */ + if (!temporary) + ReplicationSlotPersist(); ReplicationSlotRelease(); PG_RETURN_DATUM(result); @@ -174,7 +181,7 @@ pg_drop_replication_slot(PG_FUNCTION_ARGS) Datum pg_get_replication_slots(PG_FUNCTION_ARGS) { -#define PG_GET_REPLICATION_SLOTS_COLS 10 +#define PG_GET_REPLICATION_SLOTS_COLS 11 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; TupleDesc tupdesc; Tuplestorestate *tupstore; @@ -219,6 +226,7 @@ pg_get_replication_slots(PG_FUNCTION_ARGS) Datum values[PG_GET_REPLICATION_SLOTS_COLS]; bool nulls[PG_GET_REPLICATION_SLOTS_COLS]; + ReplicationSlotPersistency persistency; TransactionId xmin; TransactionId catalog_xmin; XLogRecPtr restart_lsn; @@ -246,6 +254,7 @@ pg_get_replication_slots(PG_FUNCTION_ARGS) namecpy(&plugin, &slot->data.plugin); active_pid = slot->active_pid; + persistency = slot->data.persistency; } SpinLockRelease(&slot->mutex); @@ -269,6 +278,7 @@ pg_get_replication_slots(PG_FUNCTION_ARGS) else values[i++] = database; + values[i++] = BoolGetDatum(persistency == RS_TEMPORARY); values[i++] = BoolGetDatum(active_pid != 0); if (active_pid != 0) diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c index b442d061ec..20a1441f0a 100644 --- a/src/backend/replication/syncrep.c +++ b/src/backend/replication/syncrep.c @@ -30,25 +30,36 @@ * searching the through all waiters each time we receive a reply. * * In 9.5 or before only a single standby could be considered as - * synchronous. In 9.6 we support multiple synchronous standbys. - * The number of synchronous standbys that transactions must wait for - * replies from is specified in synchronous_standby_names. - * This parameter also specifies a list of standby names, - * which determines the priority of each standby for being chosen as - * a synchronous standby. The standbys whose names appear earlier - * in the list are given higher priority and will be considered as - * synchronous. Other standby servers appearing later in this list - * represent potential synchronous standbys. If any of the current - * synchronous standbys disconnects for whatever reason, it will be - * replaced immediately with the next-highest-priority standby. + * synchronous. In 9.6 we support a priority-based multiple synchronous + * standbys. In 10.0 a quorum-based multiple synchronous standbys is also + * supported. The number of synchronous standbys that transactions + * must wait for replies from is specified in synchronous_standby_names. + * This parameter also specifies a list of standby names and the method + * (FIRST and ANY) to choose synchronous standbys from the listed ones. + * + * The method FIRST specifies a priority-based synchronous replication + * and makes transaction commits wait until their WAL records are + * replicated to the requested number of synchronous standbys chosen based + * on their priorities. The standbys whose names appear earlier in the list + * are given higher priority and will be considered as synchronous. + * Other standby servers appearing later in this list represent potential + * synchronous standbys. If any of the current synchronous standbys + * disconnects for whatever reason, it will be replaced immediately with + * the next-highest-priority standby. + * + * The method ANY specifies a quorum-based synchronous replication + * and makes transaction commits wait until their WAL records are + * replicated to at least the requested number of synchronous standbys + * in the list. All the standbys appearing in the list are considered as + * candidates for quorum synchronous standbys. * * Before the standbys chosen from synchronous_standby_names can * become the synchronous standbys they must have caught up with * the primary; that may take some time. Once caught up, - * the current higher priority standbys which are considered as - * synchronous at that moment will release waiters from the queue. + * the standbys which are considered as synchronous at that moment + * will release waiters from the queue. * - * Portions Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/syncrep.c @@ -61,6 +72,7 @@ #include "access/xact.h" #include "miscadmin.h" +#include "pgstat.h" #include "replication/syncrep.h" #include "replication/walsender.h" #include "replication/walsender_private.h" @@ -78,18 +90,29 @@ char *SyncRepStandbyNames; static bool announce_next_takeover = true; -static SyncRepConfigData *SyncRepConfig = NULL; +SyncRepConfigData *SyncRepConfig = NULL; static int SyncRepWaitMode = SYNC_REP_NO_WAIT; static void SyncRepQueueInsert(int mode); static void SyncRepCancelWait(void); static int SyncRepWakeQueue(bool all, int mode); -static bool SyncRepGetOldestSyncRecPtr(XLogRecPtr *writePtr, - XLogRecPtr *flushPtr, - XLogRecPtr *applyPtr, - bool *am_sync); +static bool SyncRepGetSyncRecPtr(XLogRecPtr *writePtr, + XLogRecPtr *flushPtr, + XLogRecPtr *applyPtr, + bool *am_sync); +static void SyncRepGetOldestSyncRecPtr(XLogRecPtr *writePtr, + XLogRecPtr *flushPtr, + XLogRecPtr *applyPtr, + List *sync_standbys); +static void SyncRepGetNthLatestSyncRecPtr(XLogRecPtr *writePtr, + XLogRecPtr *flushPtr, + XLogRecPtr *applyPtr, + List *sync_standbys, uint8 nth); static int SyncRepGetStandbyPriority(void); +static List *SyncRepGetSyncStandbysPriority(bool *am_sync); +static List *SyncRepGetSyncStandbysQuorum(bool *am_sync); +static int cmp_lsn(const void *a, const void *b); #ifdef USE_ASSERT_CHECKING static bool SyncRepQueueIsOrderedByLSN(int mode); @@ -258,7 +281,8 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit) * Wait on latch. Any condition that should wake us up will set the * latch, so no need for timeout. */ - WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1); + WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1, + WAIT_EVENT_SYNC_REP); } /* @@ -384,7 +408,7 @@ SyncRepReleaseWaiters(void) XLogRecPtr writePtr; XLogRecPtr flushPtr; XLogRecPtr applyPtr; - bool got_oldest; + bool got_recptr; bool am_sync; int numwrite = 0; int numflush = 0; @@ -411,11 +435,10 @@ SyncRepReleaseWaiters(void) LWLockAcquire(SyncRepLock, LW_EXCLUSIVE); /* - * Check whether we are a sync standby or not, and calculate the oldest + * Check whether we are a sync standby or not, and calculate the synced * positions among all sync standbys. */ - got_oldest = SyncRepGetOldestSyncRecPtr(&writePtr, &flushPtr, - &applyPtr, &am_sync); + got_recptr = SyncRepGetSyncRecPtr(&writePtr, &flushPtr, &applyPtr, &am_sync); /* * If we are managing a sync standby, though we weren't prior to this, @@ -424,16 +447,22 @@ SyncRepReleaseWaiters(void) if (announce_next_takeover && am_sync) { announce_next_takeover = false; - ereport(LOG, - (errmsg("standby \"%s\" is now a synchronous standby with priority %u", - application_name, MyWalSnd->sync_standby_priority))); + + if (SyncRepConfig->syncrep_method == SYNC_REP_PRIORITY) + ereport(LOG, + (errmsg("standby \"%s\" is now a synchronous standby with priority %u", + application_name, MyWalSnd->sync_standby_priority))); + else + ereport(LOG, + (errmsg("standby \"%s\" is now a candidate for quorum synchronous standby", + application_name))); } /* * If the number of sync standbys is less than requested or we aren't * managing a sync standby then just leave. */ - if (!got_oldest || !am_sync) + if (!got_recptr || !am_sync) { LWLockRelease(SyncRepLock); announce_next_takeover = !am_sync; @@ -469,21 +498,20 @@ SyncRepReleaseWaiters(void) } /* - * Calculate the oldest Write, Flush and Apply positions among sync standbys. + * Calculate the synced Write, Flush and Apply positions among sync standbys. * * Return false if the number of sync standbys is less than * synchronous_standby_names specifies. Otherwise return true and - * store the oldest positions into *writePtr, *flushPtr and *applyPtr. + * store the positions into *writePtr, *flushPtr and *applyPtr. * * On return, *am_sync is set to true if this walsender is connecting to * sync standby. Otherwise it's set to false. */ static bool -SyncRepGetOldestSyncRecPtr(XLogRecPtr *writePtr, XLogRecPtr *flushPtr, +SyncRepGetSyncRecPtr(XLogRecPtr *writePtr, XLogRecPtr *flushPtr, XLogRecPtr *applyPtr, bool *am_sync) { List *sync_standbys; - ListCell *cell; *writePtr = InvalidXLogRecPtr; *flushPtr = InvalidXLogRecPtr; @@ -506,12 +534,49 @@ SyncRepGetOldestSyncRecPtr(XLogRecPtr *writePtr, XLogRecPtr *flushPtr, } /* - * Scan through all sync standbys and calculate the oldest Write, Flush - * and Apply positions. + * In a priority-based sync replication, the synced positions are the + * oldest ones among sync standbys. In a quorum-based, they are the Nth + * latest ones. + * + * SyncRepGetNthLatestSyncRecPtr() also can calculate the oldest positions. + * But we use SyncRepGetOldestSyncRecPtr() for that calculation because + * it's a bit more efficient. + * + * XXX If the numbers of current and requested sync standbys are the same, + * we can use SyncRepGetOldestSyncRecPtr() to calculate the synced + * positions even in a quorum-based sync replication. */ - foreach(cell, sync_standbys) + if (SyncRepConfig->syncrep_method == SYNC_REP_PRIORITY) { - WalSnd *walsnd = &WalSndCtl->walsnds[lfirst_int(cell)]; + SyncRepGetOldestSyncRecPtr(writePtr, flushPtr, applyPtr, + sync_standbys); + } + else + { + SyncRepGetNthLatestSyncRecPtr(writePtr, flushPtr, applyPtr, + sync_standbys, SyncRepConfig->num_sync); + } + + list_free(sync_standbys); + return true; +} + +/* + * Calculate the oldest Write, Flush and Apply positions among sync standbys. + */ +static void +SyncRepGetOldestSyncRecPtr(XLogRecPtr *writePtr, XLogRecPtr *flushPtr, + XLogRecPtr *applyPtr, List *sync_standbys) +{ + ListCell *cell; + + /* + * Scan through all sync standbys and calculate the oldest + * Write, Flush and Apply positions. + */ + foreach (cell, sync_standbys) + { + WalSnd *walsnd = &WalSndCtl->walsnds[lfirst_int(cell)]; XLogRecPtr write; XLogRecPtr flush; XLogRecPtr apply; @@ -529,23 +594,163 @@ SyncRepGetOldestSyncRecPtr(XLogRecPtr *writePtr, XLogRecPtr *flushPtr, if (XLogRecPtrIsInvalid(*applyPtr) || *applyPtr > apply) *applyPtr = apply; } +} - list_free(sync_standbys); - return true; +/* + * Calculate the Nth latest Write, Flush and Apply positions among sync + * standbys. + */ +static void +SyncRepGetNthLatestSyncRecPtr(XLogRecPtr *writePtr, XLogRecPtr *flushPtr, + XLogRecPtr *applyPtr, List *sync_standbys, uint8 nth) +{ + ListCell *cell; + XLogRecPtr *write_array; + XLogRecPtr *flush_array; + XLogRecPtr *apply_array; + int len; + int i = 0; + + len = list_length(sync_standbys); + write_array = (XLogRecPtr *) palloc(sizeof(XLogRecPtr) * len); + flush_array = (XLogRecPtr *) palloc(sizeof(XLogRecPtr) * len); + apply_array = (XLogRecPtr *) palloc(sizeof(XLogRecPtr) * len); + + foreach (cell, sync_standbys) + { + WalSnd *walsnd = &WalSndCtl->walsnds[lfirst_int(cell)]; + + SpinLockAcquire(&walsnd->mutex); + write_array[i] = walsnd->write; + flush_array[i] = walsnd->flush; + apply_array[i] = walsnd->apply; + SpinLockRelease(&walsnd->mutex); + + i++; + } + + qsort(write_array, len, sizeof(XLogRecPtr), cmp_lsn); + qsort(flush_array, len, sizeof(XLogRecPtr), cmp_lsn); + qsort(apply_array, len, sizeof(XLogRecPtr), cmp_lsn); + + /* Get Nth latest Write, Flush, Apply positions */ + *writePtr = write_array[nth - 1]; + *flushPtr = flush_array[nth - 1]; + *applyPtr = apply_array[nth - 1]; + + pfree(write_array); + pfree(flush_array); + pfree(apply_array); +} + +/* + * Compare lsn in order to sort array in descending order. + */ +static int +cmp_lsn(const void *a, const void *b) +{ + XLogRecPtr lsn1 = *((const XLogRecPtr *) a); + XLogRecPtr lsn2 = *((const XLogRecPtr *) b); + + if (lsn1 > lsn2) + return -1; + else if (lsn1 == lsn2) + return 0; + else + return 1; } /* * Return the list of sync standbys, or NIL if no sync standby is connected. * - * If there are multiple standbys with the same priority, - * the first one found is selected preferentially. * The caller must hold SyncRepLock. * * On return, *am_sync is set to true if this walsender is connecting to * sync standby. Otherwise it's set to false. */ List * -SyncRepGetSyncStandbys(bool *am_sync) +SyncRepGetSyncStandbys(bool *am_sync) +{ + /* Set default result */ + if (am_sync != NULL) + *am_sync = false; + + /* Quick exit if sync replication is not requested */ + if (SyncRepConfig == NULL) + return NIL; + + return (SyncRepConfig->syncrep_method == SYNC_REP_PRIORITY) ? + SyncRepGetSyncStandbysPriority(am_sync) : + SyncRepGetSyncStandbysQuorum(am_sync); +} + +/* + * Return the list of all the candidates for quorum sync standbys, + * or NIL if no such standby is connected. + * + * The caller must hold SyncRepLock. This function must be called only in + * a quorum-based sync replication. + * + * On return, *am_sync is set to true if this walsender is connecting to + * sync standby. Otherwise it's set to false. + */ +static List * +SyncRepGetSyncStandbysQuorum(bool *am_sync) +{ + List *result = NIL; + int i; + volatile WalSnd *walsnd; /* Use volatile pointer to prevent code + * rearrangement */ + + Assert(SyncRepConfig->syncrep_method == SYNC_REP_QUORUM); + + for (i = 0; i < max_wal_senders; i++) + { + walsnd = &WalSndCtl->walsnds[i]; + + /* Must be active */ + if (walsnd->pid == 0) + continue; + + /* Must be streaming */ + if (walsnd->state != WALSNDSTATE_STREAMING) + continue; + + /* Must be synchronous */ + if (walsnd->sync_standby_priority == 0) + continue; + + /* Must have a valid flush position */ + if (XLogRecPtrIsInvalid(walsnd->flush)) + continue; + + /* + * Consider this standby as a candidate for quorum sync standbys + * and append it to the result. + */ + result = lappend_int(result, i); + if (am_sync != NULL && walsnd == MyWalSnd) + *am_sync = true; + } + + return result; +} + +/* + * Return the list of sync standbys chosen based on their priorities, + * or NIL if no sync standby is connected. + * + * If there are multiple standbys with the same priority, + * the first one found is selected preferentially. + * + * The caller must hold SyncRepLock. This function must be called only in + * a priority-based sync replication. + * + * On return, *am_sync is set to true if this walsender is connecting to + * sync standby. Otherwise it's set to false. + */ +static List * +SyncRepGetSyncStandbysPriority(bool *am_sync) { List *result = NIL; List *pending = NIL; @@ -558,13 +763,7 @@ SyncRepGetSyncStandbys(bool *am_sync) volatile WalSnd *walsnd; /* Use volatile pointer to prevent code * rearrangement */ - /* Set default result */ - if (am_sync != NULL) - *am_sync = false; - - /* Quick exit if sync replication is not requested */ - if (SyncRepConfig == NULL) - return NIL; + Assert(SyncRepConfig->syncrep_method == SYNC_REP_PRIORITY); lowest_priority = SyncRepConfig->nmembers; next_highest_priority = lowest_priority + 1; @@ -922,6 +1121,13 @@ check_synchronous_standby_names(char **newval, void **extra, GucSource source) return false; } + if (syncrep_parse_result->num_sync <= 0) + { + GUC_check_errmsg("number of synchronous standbys (%d) must be greater than zero", + syncrep_parse_result->num_sync); + return false; + } + /* GUC extra value must be malloc'd, not palloc'd */ pconf = (SyncRepConfigData *) malloc(syncrep_parse_result->config_size); diff --git a/src/backend/replication/syncrep_gram.y b/src/backend/replication/syncrep_gram.y index 35c27760d1..cc8622c93d 100644 --- a/src/backend/replication/syncrep_gram.y +++ b/src/backend/replication/syncrep_gram.y @@ -3,7 +3,7 @@ * * syncrep_gram.y - Parser for synchronous_standby_names * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -21,7 +21,7 @@ SyncRepConfigData *syncrep_parse_result; char *syncrep_parse_error_msg; static SyncRepConfigData *create_syncrep_config(const char *num_sync, - List *members); + List *members, uint8 syncrep_method); /* * Bison doesn't allocate anything that needs to live across parser calls, @@ -46,7 +46,7 @@ static SyncRepConfigData *create_syncrep_config(const char *num_sync, SyncRepConfigData *config; } -%token NAME NUM JUNK +%token NAME NUM JUNK ANY FIRST %type result standby_config %type standby_list @@ -60,8 +60,10 @@ result: ; standby_config: - standby_list { $$ = create_syncrep_config("1", $1); } - | NUM '(' standby_list ')' { $$ = create_syncrep_config($1, $3); } + standby_list { $$ = create_syncrep_config("1", $1, SYNC_REP_PRIORITY); } + | NUM '(' standby_list ')' { $$ = create_syncrep_config($1, $3, SYNC_REP_PRIORITY); } + | ANY NUM '(' standby_list ')' { $$ = create_syncrep_config($2, $4, SYNC_REP_QUORUM); } + | FIRST NUM '(' standby_list ')' { $$ = create_syncrep_config($2, $4, SYNC_REP_PRIORITY); } ; standby_list: @@ -75,9 +77,8 @@ standby_name: ; %% - static SyncRepConfigData * -create_syncrep_config(const char *num_sync, List *members) +create_syncrep_config(const char *num_sync, List *members, uint8 syncrep_method) { SyncRepConfigData *config; int size; @@ -98,6 +99,7 @@ create_syncrep_config(const char *num_sync, List *members) config->config_size = size; config->num_sync = atoi(num_sync); + config->syncrep_method = syncrep_method; config->nmembers = list_length(members); ptr = config->member_names; foreach(lc, members) diff --git a/src/backend/replication/syncrep_scanner.l b/src/backend/replication/syncrep_scanner.l index d20662ed03..7baf1b68d1 100644 --- a/src/backend/replication/syncrep_scanner.l +++ b/src/backend/replication/syncrep_scanner.l @@ -4,7 +4,7 @@ * syncrep_scanner.l * a lexical scanner for synchronous_standby_names * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -64,6 +64,9 @@ xdinside [^"]+ %% {space}+ { /* ignore */ } +ANY { return ANY; } +FIRST { return FIRST; } + {xdstart} { initStringInfo(&xdbuf); BEGIN(xd); diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index 413ee3a5c1..0e4a4b9d19 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -18,7 +18,7 @@ * If the primary server ends streaming, but doesn't disconnect, walreceiver * goes into "waiting" mode, and waits for the startup process to give new * instructions. The startup process will treat that the same as - * disconnection, and will rescan the archive/pg_xlog directory. But when the + * disconnection, and will rescan the archive/pg_wal directory. But when the * startup process wants to try streaming replication again, it will just * nudge the existing walreceiver process that's waiting, instead of launching * a new one. @@ -33,7 +33,7 @@ * specific parts are in the libpqwalreceiver module. It's loaded * dynamically to avoid linking the server with libpq. * - * Portions Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -55,6 +55,7 @@ #include "libpq/pqformat.h" #include "libpq/pqsignal.h" #include "miscadmin.h" +#include "pgstat.h" #include "replication/walreceiver.h" #include "replication/walsender.h" #include "storage/ipc.h" @@ -73,16 +74,9 @@ int wal_receiver_status_interval; int wal_receiver_timeout; bool hot_standby_feedback; -/* libpqreceiver hooks to these when loaded */ -walrcv_connect_type walrcv_connect = NULL; -walrcv_get_conninfo_type walrcv_get_conninfo = NULL; -walrcv_identify_system_type walrcv_identify_system = NULL; -walrcv_startstreaming_type walrcv_startstreaming = NULL; -walrcv_endstreaming_type walrcv_endstreaming = NULL; -walrcv_readtimelinehistoryfile_type walrcv_readtimelinehistoryfile = NULL; -walrcv_receive_type walrcv_receive = NULL; -walrcv_send_type walrcv_send = NULL; -walrcv_disconnect_type walrcv_disconnect = NULL; +/* libpqwalreceiver connection */ +static WalReceiverConn *wrconn = NULL; +WalReceiverFunctionsType *WalReceiverFunctions = NULL; #define NAPTIME_PER_CYCLE 100 /* max sleep time between cycles (100ms) */ @@ -202,6 +196,7 @@ WalReceiverMain(void) WalRcvData *walrcv = WalRcv; TimestampTz last_recv_timestamp; bool ping_sent; + char *err; /* * WalRcv should be set up already (if we are a backend, we inherit this @@ -260,7 +255,7 @@ WalReceiverMain(void) /* Arrange to clean up at walreceiver exit */ on_shmem_exit(WalRcvDie, 0); - OwnLatch(&walrcv->latch); + walrcv->latch = &MyProc->procLatch; /* Properly accept or ignore signals the postmaster might send us */ pqsignal(SIGHUP, WalRcvSigHupHandler); /* set flag to read config @@ -285,14 +280,7 @@ WalReceiverMain(void) /* Load the libpq-specific functions */ load_file("libpqwalreceiver", false); - if (walrcv_connect == NULL || - walrcv_get_conninfo == NULL || - walrcv_startstreaming == NULL || - walrcv_endstreaming == NULL || - walrcv_identify_system == NULL || - walrcv_readtimelinehistoryfile == NULL || - walrcv_receive == NULL || walrcv_send == NULL || - walrcv_disconnect == NULL) + if (WalReceiverFunctions == NULL) elog(ERROR, "libpqwalreceiver didn't initialize correctly"); /* @@ -306,14 +294,17 @@ WalReceiverMain(void) /* Establish the connection to the primary for XLOG streaming */ EnableWalRcvImmediateExit(); - walrcv_connect(conninfo); + wrconn = walrcv_connect(conninfo, false, "walreceiver", &err); + if (!wrconn) + ereport(ERROR, + (errmsg("could not connect to the primary server: %s", err))); DisableWalRcvImmediateExit(); /* * Save user-visible connection string. This clobbers the original * conninfo, for security. */ - tmp_conninfo = walrcv_get_conninfo(); + tmp_conninfo = walrcv_get_conninfo(wrconn); SpinLockAcquire(&walrcv->mutex); memset(walrcv->conninfo, 0, MAXCONNINFO); if (tmp_conninfo) @@ -327,12 +318,28 @@ WalReceiverMain(void) first_stream = true; for (;;) { + char *primary_sysid; + char standby_sysid[32]; + int server_version; + WalRcvStreamOptions options; + /* * Check that we're connected to a valid server using the - * IDENTIFY_SYSTEM replication command, + * IDENTIFY_SYSTEM replication command. */ EnableWalRcvImmediateExit(); - walrcv_identify_system(&primaryTLI); + primary_sysid = walrcv_identify_system(wrconn, &primaryTLI, + &server_version); + + snprintf(standby_sysid, sizeof(standby_sysid), UINT64_FORMAT, + GetSystemIdentifier()); + if (strcmp(primary_sysid, standby_sysid) != 0) + { + ereport(ERROR, + (errmsg("database system identifier differs between the primary and standby"), + errdetail("The primary's identifier is %s, the standby's identifier is %s.", + primary_sysid, standby_sysid))); + } DisableWalRcvImmediateExit(); /* @@ -364,13 +371,16 @@ WalReceiverMain(void) * we've already reached the end of the old timeline, the server will * finish the streaming immediately, and we will go back to await * orders from the startup process. If recovery_target_timeline is - * 'latest', the startup process will scan pg_xlog and find the new + * 'latest', the startup process will scan pg_wal and find the new * history file, bump recovery target timeline, and ask us to restart * on the new timeline. */ + options.logical = false; + options.startpoint = startpoint; + options.slotname = slotname[0] != '\0' ? slotname : NULL; + options.proto.physical.startpointTLI = startpointTLI; ThisTimeLineID = startpointTLI; - if (walrcv_startstreaming(startpointTLI, startpoint, - slotname[0] != '\0' ? slotname : NULL)) + if (walrcv_startstreaming(wrconn, &options)) { if (first_stream) ereport(LOG, @@ -421,7 +431,7 @@ WalReceiverMain(void) } /* See if we can read data immediately */ - len = walrcv_receive(&buf, &wait_fd); + len = walrcv_receive(wrconn, &buf, &wait_fd); if (len != 0) { /* @@ -452,7 +462,7 @@ WalReceiverMain(void) endofwal = true; break; } - len = walrcv_receive(&buf, &wait_fd); + len = walrcv_receive(wrconn, &buf, &wait_fd); } /* Let the master know that we received some data. */ @@ -482,14 +492,15 @@ WalReceiverMain(void) * avoiding some system calls. */ Assert(wait_fd != PGINVALID_SOCKET); - rc = WaitLatchOrSocket(&walrcv->latch, + rc = WaitLatchOrSocket(walrcv->latch, WL_POSTMASTER_DEATH | WL_SOCKET_READABLE | WL_TIMEOUT | WL_LATCH_SET, wait_fd, - NAPTIME_PER_CYCLE); + NAPTIME_PER_CYCLE, + WAIT_EVENT_WAL_RECEIVER_MAIN); if (rc & WL_LATCH_SET) { - ResetLatch(&walrcv->latch); + ResetLatch(walrcv->latch); if (walrcv->force_reply) { /* @@ -568,7 +579,7 @@ WalReceiverMain(void) * our side, too. */ EnableWalRcvImmediateExit(); - walrcv_endstreaming(&primaryTLI); + walrcv_endstreaming(wrconn, &primaryTLI); DisableWalRcvImmediateExit(); /* @@ -650,7 +661,7 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI) WakeupRecovery(); for (;;) { - ResetLatch(&walrcv->latch); + ResetLatch(walrcv->latch); /* * Emergency bailout if postmaster has died. This is to avoid the @@ -685,7 +696,8 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI) } SpinLockRelease(&walrcv->mutex); - WaitLatch(&walrcv->latch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0); + WaitLatch(walrcv->latch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0, + WAIT_EVENT_WAL_RECEIVER_WAIT_START); } if (update_process_title) @@ -723,7 +735,7 @@ WalRcvFetchTimeLineHistoryFiles(TimeLineID first, TimeLineID last) tli))); EnableWalRcvImmediateExit(); - walrcv_readtimelinehistoryfile(tli, &fname, &content, &len); + walrcv_readtimelinehistoryfile(wrconn, tli, &fname, &content, &len); DisableWalRcvImmediateExit(); /* @@ -739,7 +751,7 @@ WalRcvFetchTimeLineHistoryFiles(TimeLineID first, TimeLineID last) tli))); /* - * Write the file to pg_xlog. + * Write the file to pg_wal. */ writeTimeLineHistoryFile(tli, content, len); @@ -760,7 +772,7 @@ WalRcvDie(int code, Datum arg) /* Ensure that all WAL records received are flushed to disk */ XLogWalRcvFlush(true); - DisownLatch(&walrcv->latch); + walrcv->latch = NULL; SpinLockAcquire(&walrcv->mutex); Assert(walrcv->walRcvState == WALRCV_STREAMING || @@ -775,8 +787,8 @@ WalRcvDie(int code, Datum arg) SpinLockRelease(&walrcv->mutex); /* Terminate the connection gracefully. */ - if (walrcv_disconnect != NULL) - walrcv_disconnect(); + if (wrconn != NULL) + walrcv_disconnect(wrconn); /* Wake up the startup process to notice promptly that we're gone */ WakeupRecovery(); @@ -809,7 +821,8 @@ WalRcvShutdownHandler(SIGNAL_ARGS) got_SIGTERM = true; - SetLatch(&WalRcv->latch); + if (WalRcv->latch) + SetLatch(WalRcv->latch); /* Don't joggle the elbow of proc_exit */ if (!proc_exit_inprogress && WalRcvImmediateInterruptOK) @@ -1146,7 +1159,7 @@ XLogWalRcvSendReply(bool force, bool requestReply) (uint32) (applyPtr >> 32), (uint32) applyPtr, requestReply ? " (reply requested)" : ""); - walrcv_send(reply_message.data, reply_message.len); + walrcv_send(wrconn, reply_message.data, reply_message.len); } /* @@ -1224,7 +1237,7 @@ XLogWalRcvSendHSFeedback(bool immed) pq_sendint64(&reply_message, GetCurrentIntegerTimestamp()); pq_sendint(&reply_message, xmin, 4); pq_sendint(&reply_message, nextEpoch, 4); - walrcv_send(reply_message.data, reply_message.len); + walrcv_send(wrconn, reply_message.data, reply_message.len); if (TransactionIdIsValid(xmin)) master_has_standby_xmin = true; else @@ -1294,7 +1307,8 @@ void WalRcvForceReply(void) { WalRcv->force_reply = true; - SetLatch(&WalRcv->latch); + if (WalRcv->latch) + SetLatch(WalRcv->latch); } /* diff --git a/src/backend/replication/walreceiverfuncs.c b/src/backend/replication/walreceiverfuncs.c index 5f6e423f1f..df113b86e8 100644 --- a/src/backend/replication/walreceiverfuncs.c +++ b/src/backend/replication/walreceiverfuncs.c @@ -6,7 +6,7 @@ * with the walreceiver process. Functions implementing walreceiver itself * are in walreceiver.c. * - * Portions Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -64,7 +64,7 @@ WalRcvShmemInit(void) MemSet(WalRcv, 0, WalRcvShmemSize()); WalRcv->walRcvState = WALRCV_STOPPED; SpinLockInit(&WalRcv->mutex); - InitSharedLatch(&WalRcv->latch); + WalRcv->latch = NULL; } } @@ -279,8 +279,8 @@ RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo, if (launch) SendPostmasterSignal(PMSIGNAL_START_WALRECEIVER); - else - SetLatch(&walrcv->latch); + else if (walrcv->latch) + SetLatch(walrcv->latch); } /* diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index a0dba194a6..f3082c379a 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -31,7 +31,7 @@ * and then exit. * * - * Portions Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/walsender.c @@ -66,6 +66,7 @@ #include "replication/walreceiver.h" #include "replication/walsender.h" #include "replication/walsender_private.h" +#include "storage/condition_variable.h" #include "storage/fd.h" #include "storage/ipc.h" #include "storage/pmsignal.h" @@ -253,6 +254,7 @@ void WalSndErrorCleanup(void) { LWLockReleaseAll(); + ConditionVariableCancelSleep(); pgstat_report_wait_end(); if (sendFile >= 0) @@ -264,6 +266,8 @@ WalSndErrorCleanup(void) if (MyReplicationSlot != NULL) ReplicationSlotRelease(); + ReplicationSlotCleanup(); + replication_active = false; if (walsender_ready_to_stop) proc_exit(0); @@ -586,7 +590,7 @@ StartReplication(StartReplicationCmd *cmd) * segment that contains switchpoint, but on the new timeline, so * that it doesn't end up with a partial segment. If you ask for a * too old starting point, you'll get an error later when we fail - * to find the requested WAL segment in pg_xlog. + * to find the requested WAL segment in pg_wal. * * XXX: we could be more strict here and only allow a startpoint * that's older than the switchpoint, if it's still in the same @@ -794,18 +798,22 @@ CreateReplicationSlot(CreateReplicationSlotCmd *cmd) if (cmd->kind == REPLICATION_KIND_PHYSICAL) { - ReplicationSlotCreate(cmd->slotname, false, RS_PERSISTENT); + ReplicationSlotCreate(cmd->slotname, false, + cmd->temporary ? RS_TEMPORARY : RS_PERSISTENT); } else { CheckLogicalDecodingRequirements(); /* - * Initially create the slot as ephemeral - that allows us to nicely - * handle errors during initialization because it'll get dropped if - * this transaction fails. We'll make it persistent at the end. + * Initially create persistent slot as ephemeral - that allows us to + * nicely handle errors during initialization because it'll get + * dropped if this transaction fails. We'll make it persistent at the + * end. Temporary slots can be created as temporary from beginning as + * they get dropped on error as well. */ - ReplicationSlotCreate(cmd->slotname, true, RS_EPHEMERAL); + ReplicationSlotCreate(cmd->slotname, true, + cmd->temporary ? RS_TEMPORARY : RS_EPHEMERAL); } initStringInfo(&output_message); @@ -839,15 +847,18 @@ CreateReplicationSlot(CreateReplicationSlotCmd *cmd) /* don't need the decoding context anymore */ FreeDecodingContext(ctx); - ReplicationSlotPersist(); + if (!cmd->temporary) + ReplicationSlotPersist(); } else if (cmd->kind == REPLICATION_KIND_PHYSICAL && cmd->reserve_wal) { ReplicationSlotReserveWal(); - /* Write this slot to disk */ ReplicationSlotMarkDirty(); - ReplicationSlotSave(); + + /* Write this slot to disk if it's permanent one. */ + if (!cmd->temporary) + ReplicationSlotSave(); } snprintf(xpos, sizeof(xpos), "%X/%X", @@ -931,9 +942,6 @@ CreateReplicationSlot(CreateReplicationSlotCmd *cmd) pq_endmessage(&buf); - /* - * release active status again, START_REPLICATION will reacquire it - */ ReplicationSlotRelease(); } @@ -1146,7 +1154,8 @@ WalSndWriteData(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid, /* Sleep until something happens or we time out */ WaitLatchOrSocket(MyLatch, wakeEvents, - MyProcPort->sock, sleeptime); + MyProcPort->sock, sleeptime, + WAIT_EVENT_WAL_SENDER_WRITE_DATA); } /* reactivate latch so WalSndLoop knows to continue */ @@ -1272,7 +1281,8 @@ WalSndWaitForWal(XLogRecPtr loc) /* Sleep until something happens or we time out */ WaitLatchOrSocket(MyLatch, wakeEvents, - MyProcPort->sock, sleeptime); + MyProcPort->sock, sleeptime, + WAIT_EVENT_WAL_SENDER_WAIT_WAL); } /* reactivate latch so WalSndLoop knows to continue */ @@ -1309,9 +1319,7 @@ exec_replication_command(const char *cmd_string) cmd_context = AllocSetContextCreate(CurrentMemoryContext, "Replication command context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); old_context = MemoryContextSwitchTo(cmd_context); replication_scanner_init(cmd_string); @@ -1808,6 +1816,9 @@ WalSndLoop(WalSndSendDataCallback send_data) last_reply_timestamp = GetCurrentTimestamp(); waiting_for_ping_response = false; + /* Report to pgstat that this process is a WAL sender */ + pgstat_report_activity(STATE_RUNNING, "walsender"); + /* * Loop until we reach the end of this timeline or the client requests to * stop streaming. @@ -1923,7 +1934,8 @@ WalSndLoop(WalSndSendDataCallback send_data) /* Sleep until something happens or we time out */ WaitLatchOrSocket(MyLatch, wakeEvents, - MyProcPort->sock, sleeptime); + MyProcPort->sock, sleeptime, + WAIT_EVENT_WAL_SENDER_MAIN); } } return; @@ -2054,7 +2066,7 @@ XLogRead(char *buf, XLogRecPtr startptr, Size count) * * For example, imagine that this server is currently on timeline * 5, and we're streaming timeline 4. The switch from timeline 4 - * to 5 happened at 0/13002088. In pg_xlog, we have these files: + * to 5 happened at 0/13002088. In pg_wal, we have these files: * * ... * 000000040000000000000012 @@ -2856,12 +2868,20 @@ pg_stat_get_wal_senders(PG_FUNCTION_ARGS) /* * More easily understood version of standby state. This is purely - * informational, not different from priority. + * informational. + * + * In quorum-based sync replication, the role of each standby + * listed in synchronous_standby_names can be changing very + * frequently. Any standbys considered as "sync" at one moment can + * be switched to "potential" ones at the next moment. So, it's + * basically useless to report "sync" or "potential" as their sync + * states. We report just "quorum" for them. */ if (priority == 0) values[7] = CStringGetTextDatum("async"); else if (list_member_int(sync_standbys, i)) - values[7] = CStringGetTextDatum("sync"); + values[7] = SyncRepConfig->syncrep_method == SYNC_REP_PRIORITY ? + CStringGetTextDatum("sync") : CStringGetTextDatum("quorum"); else values[7] = CStringGetTextDatum("potential"); } diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index f82d891c34..864d45ff12 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -3,7 +3,7 @@ * rewriteDefine.c * routines for defining a rewrite rule * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -261,7 +261,8 @@ DefineQueryRewrite(char *rulename, */ if (event_relation->rd_rel->relkind != RELKIND_RELATION && event_relation->rd_rel->relkind != RELKIND_MATVIEW && - event_relation->rd_rel->relkind != RELKIND_VIEW) + event_relation->rd_rel->relkind != RELKIND_VIEW && + event_relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table or view", @@ -329,8 +330,7 @@ DefineQueryRewrite(char *rulename, */ query = (Query *) linitial(action); if (!is_instead || - query->commandType != CMD_SELECT || - query->utilityStmt != NULL) + query->commandType != CMD_SELECT) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("rules on SELECT must have action INSTEAD SELECT"))); diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index a22a11e2c1..d1ff3b20b6 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -3,7 +3,7 @@ * rewriteHandler.c * Primary module of query rewriter. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -446,6 +446,15 @@ rewriteRuleAction(Query *parsetree, } } + /* + * Also, we might have absorbed some RTEs with RLS conditions into the + * sub_action. If so, mark it as hasRowSecurity, whether or not those + * RTEs will be referenced after we finish rewriting. (Note: currently + * this is a no-op because RLS conditions aren't added till later, but it + * seems like good future-proofing to do this anyway.) + */ + sub_action->hasRowSecurity |= parsetree->hasRowSecurity; + /* * Each rule action's jointree should be the main parsetree's jointree * plus that rule's jointree, but usually *without* the original rtindex @@ -1222,7 +1231,8 @@ rewriteTargetListUD(Query *parsetree, RangeTblEntry *target_rte, TargetEntry *tle; if (target_relation->rd_rel->relkind == RELKIND_RELATION || - target_relation->rd_rel->relkind == RELKIND_MATVIEW) + target_relation->rd_rel->relkind == RELKIND_MATVIEW || + target_relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) { /* * Emit CTID so that executor can find the row to update or delete. @@ -1835,10 +1845,10 @@ fireRIRrules(Query *parsetree, List *activeRIRs, bool forUpdatePushedDown) } /* - * Add the new security quals to the start of the RTE's list so - * that they get applied before any existing security quals (which - * might have come from a user-written security barrier view, and - * might contain malicious code). + * Add the new security barrier quals to the start of the RTE's + * list so that they get applied before any existing barrier quals + * (which would have come from a security-barrier view, and should + * get lower priority than RLS conditions on the table itself). */ rte->securityQuals = list_concat(securityQuals, rte->securityQuals); @@ -2221,7 +2231,7 @@ view_query_is_auto_updatable(Query *viewquery, bool check_cols) if (viewquery->hasWindowFuncs) return gettext_noop("Views that return window functions are not automatically updatable."); - if (expression_returns_set((Node *) viewquery->targetList)) + if (viewquery->hasTargetSRFs) return gettext_noop("Views that return set-returning functions are not automatically updatable."); /* @@ -2957,9 +2967,9 @@ rewriteTargetView(Query *parsetree, Relation view) * only adjust their varnos to reference the new target (just the same as * we did with the view targetlist). * - * Note that there is special-case handling for the quals of a security - * barrier view, since they need to be kept separate from any - * user-supplied quals, so these quals are kept on the new target RTE. + * If it's a security-barrier view, its WHERE quals must be applied before + * quals from the outer query, so we attach them to the RTE as security + * barrier quals rather than adding them to the main WHERE clause. * * For INSERT, the view's quals can be ignored in the main query. */ @@ -2980,12 +2990,21 @@ rewriteTargetView(Query *parsetree, Relation view) if (RelationIsSecurityView(view)) { /* + * The view's quals go in front of existing barrier quals: those + * would have come from an outer level of security-barrier view, + * and so must get evaluated later. + * * Note: the parsetree has been mutated, so the new_rte pointer is * stale and needs to be re-computed. */ new_rte = rt_fetch(new_rt_index, parsetree->rtable); new_rte->securityQuals = lcons(viewqual, new_rte->securityQuals); + /* + * Do not set parsetree->hasRowSecurity, because these aren't RLS + * conditions (they aren't affected by enabling/disabling RLS). + */ + /* * Make sure that the query is marked correctly if the added qual * has sublinks. diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c index 884f4f8856..b23a3b7046 100644 --- a/src/backend/rewrite/rewriteManip.c +++ b/src/backend/rewrite/rewriteManip.c @@ -2,7 +2,7 @@ * * rewriteManip.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/rewrite/rewriteRemove.c b/src/backend/rewrite/rewriteRemove.c index 65cd29f5fa..659a311017 100644 --- a/src/backend/rewrite/rewriteRemove.c +++ b/src/backend/rewrite/rewriteRemove.c @@ -3,7 +3,7 @@ * rewriteRemove.c * routines for removing rewrite rules * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/rewrite/rewriteSupport.c b/src/backend/rewrite/rewriteSupport.c index e89d440292..0154072db1 100644 --- a/src/backend/rewrite/rewriteSupport.c +++ b/src/backend/rewrite/rewriteSupport.c @@ -3,7 +3,7 @@ * rewriteSupport.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/rewrite/rowsecurity.c b/src/backend/rewrite/rowsecurity.c index e02911656a..5c8c0cff1a 100644 --- a/src/backend/rewrite/rowsecurity.c +++ b/src/backend/rewrite/rowsecurity.c @@ -29,7 +29,7 @@ * in the current environment, but that may change if the row_security GUC or * the current role changes. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California */ #include "postgres.h" @@ -86,10 +86,10 @@ static bool check_role_for_policy(ArrayType *policy_roles, Oid user_id); * hooks to allow extensions to add their own security policies * * row_security_policy_hook_permissive can be used to add policies which - * are included in the "OR"d set of policies. + * are combined with the other permissive policies, using OR. * * row_security_policy_hook_restrictive can be used to add policies which - * are enforced, regardless of other policies (they are "AND"d). + * are enforced, regardless of other policies (they are combined using AND). */ row_security_policy_hook_type row_security_policy_hook_permissive = NULL; row_security_policy_hook_type row_security_policy_hook_restrictive = NULL; @@ -121,7 +121,8 @@ get_row_security_policies(Query *root, RangeTblEntry *rte, int rt_index, *hasSubLinks = false; /* If this is not a normal relation, just return immediately */ - if (rte->relkind != RELKIND_RELATION) + if (rte->relkind != RELKIND_RELATION && + rte->relkind != RELKIND_PARTITIONED_TABLE) return; /* Switch to checkAsUser if it's set */ @@ -212,8 +213,8 @@ get_row_security_policies(Query *root, RangeTblEntry *rte, int rt_index, /* * For SELECT, UPDATE and DELETE, add security quals to enforce the USING * policies. These security quals control access to existing table rows. - * Restrictive policies are "AND"d together, and permissive policies are - * "OR"d together. + * Restrictive policies are combined together using AND, and permissive + * policies are combined together using OR. */ get_policies_for_relation(rel, commandType, user_id, &permissive_policies, @@ -433,9 +434,20 @@ get_policies_for_relation(Relation relation, CmdType cmd, Oid user_id, * the specified role. */ if (cmd_matches && check_role_for_policy(policy->roles, user_id)) - *permissive_policies = lappend(*permissive_policies, policy); + { + if (policy->permissive) + *permissive_policies = lappend(*permissive_policies, policy); + else + *restrictive_policies = lappend(*restrictive_policies, policy); + } } + /* + * We sort restrictive policies by name so that any WCOs they generate are + * checked in a well-defined order. + */ + *restrictive_policies = sort_policies_by_name(*restrictive_policies); + /* * Then add any permissive or restrictive policies defined by extensions. * These are simply appended to the lists of internal policies, if they @@ -447,8 +459,10 @@ get_policies_for_relation(Relation relation, CmdType cmd, Oid user_id, (*row_security_policy_hook_restrictive) (cmd, relation); /* - * We sort restrictive policies by name so that any WCOs they generate - * are checked in a well-defined order. + * As with built-in restrictive policies, we sort any hook-provided + * restrictive policies by name also. Note that we also intentionally + * always check all built-in restrictive policies, in name order, + * before checking restrictive policies added by hooks, in name order. */ hook_policies = sort_policies_by_name(hook_policies); @@ -481,8 +495,8 @@ get_policies_for_relation(Relation relation, CmdType cmd, Oid user_id, * * This is only used for restrictive policies, ensuring that any * WithCheckOptions they generate are applied in a well-defined order. - * This is not necessary for permissive policies, since they are all "OR"d - * together into a single WithCheckOption check. + * This is not necessary for permissive policies, since they are all combined + * together using OR into a single WithCheckOption check. */ static List * sort_policies_by_name(List *policies) @@ -580,8 +594,8 @@ add_security_quals(int rt_index, /* * We now know that permissive policies exist, so we can now add * security quals based on the USING clauses from the restrictive - * policies. Since these need to be "AND"d together, we can just add - * them one at a time. + * policies. Since these need to be combined together using AND, we + * can just add them one at a time. */ foreach(item, restrictive_policies) { @@ -599,8 +613,8 @@ add_security_quals(int rt_index, } /* - * Then add a single security qual "OR"ing together the USING clauses - * from all the permissive policies. + * Then add a single security qual combining together the USING + * clauses from all the permissive policies using OR. */ if (list_length(permissive_quals) == 1) rowsec_expr = (Expr *) linitial(permissive_quals); @@ -681,14 +695,15 @@ add_with_check_options(Relation rel, if (permissive_quals != NIL) { /* - * Add a single WithCheckOption for all the permissive policy clauses - * "OR"d together. This check has no policy name, since if the check - * fails it means that no policy granted permission to perform the - * update, rather than any particular policy being violated. + * Add a single WithCheckOption for all the permissive policy clauses, + * combining them together using OR. This check has no policy name, + * since if the check fails it means that no policy granted permission + * to perform the update, rather than any particular policy being + * violated. */ WithCheckOption *wco; - wco = (WithCheckOption *) makeNode(WithCheckOption); + wco = makeNode(WithCheckOption); wco->kind = kind; wco->relname = pstrdup(RelationGetRelationName(rel)); wco->polname = NULL; @@ -705,9 +720,9 @@ add_with_check_options(Relation rel, /* * Now add WithCheckOptions for each of the restrictive policy clauses - * (which will be "AND"d together). We use a separate WithCheckOption - * for each restrictive policy to allow the policy name to be included - * in error reports if the policy is violated. + * (which will be combined together using AND). We use a separate + * WithCheckOption for each restrictive policy to allow the policy + * name to be included in error reports if the policy is violated. */ foreach(item, restrictive_policies) { @@ -720,7 +735,7 @@ add_with_check_options(Relation rel, qual = copyObject(qual); ChangeVarNodes((Node *) qual, 1, rt_index, 0); - wco = (WithCheckOption *) makeNode(WithCheckOption); + wco = makeNode(WithCheckOption); wco->kind = kind; wco->relname = pstrdup(RelationGetRelationName(rel)); wco->polname = pstrdup(policy->policy_name); @@ -740,7 +755,7 @@ add_with_check_options(Relation rel, */ WithCheckOption *wco; - wco = (WithCheckOption *) makeNode(WithCheckOption); + wco = makeNode(WithCheckOption); wco->kind = kind; wco->relname = pstrdup(RelationGetRelationName(rel)); wco->polname = NULL; diff --git a/src/backend/snowball/dict_snowball.c b/src/backend/snowball/dict_snowball.c index 5fa3f7b381..0c322a49c6 100644 --- a/src/backend/snowball/dict_snowball.c +++ b/src/backend/snowball/dict_snowball.c @@ -3,7 +3,7 @@ * dict_snowball.c * Snowball dictionary * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/snowball/dict_snowball.c diff --git a/src/backend/snowball/snowball.sql.in b/src/backend/snowball/snowball.sql.in index 6569258b58..844822fddb 100644 --- a/src/backend/snowball/snowball.sql.in +++ b/src/backend/snowball/snowball.sql.in @@ -1,7 +1,7 @@ /* * text search configuration for _LANGNAME_ language * - * Copyright (c) 2007-2016, PostgreSQL Global Development Group + * Copyright (c) 2007-2017, PostgreSQL Global Development Group * * src/backend/snowball/snowball.sql.in * diff --git a/src/backend/snowball/snowball_func.sql.in b/src/backend/snowball/snowball_func.sql.in index 248bc3f93d..90fa000c6d 100644 --- a/src/backend/snowball/snowball_func.sql.in +++ b/src/backend/snowball/snowball_func.sql.in @@ -1,7 +1,7 @@ /* * Create underlying C functions for Snowball stemmers * - * Copyright (c) 2007-2016, PostgreSQL Global Development Group + * Copyright (c) 2007-2017, PostgreSQL Global Development Group * * src/backend/snowball/snowball_func.sql.in * diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c index a4163cf717..147fced852 100644 --- a/src/backend/storage/buffer/buf_init.c +++ b/src/backend/storage/buffer/buf_init.c @@ -3,7 +3,7 @@ * buf_init.c * buffer manager initialization routines * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -21,8 +21,6 @@ BufferDescPadded *BufferDescriptors; char *BufferBlocks; LWLockMinimallyPadded *BufferIOLWLockArray = NULL; -LWLockTranche BufferIOLWLockTranche; -LWLockTranche BufferContentLWLockTranche; WritebackContext BackendWritebackContext; CkptSortItem *CkptBufferIds; @@ -90,18 +88,8 @@ InitBufferPool(void) NBuffers * (Size) sizeof(LWLockMinimallyPadded), &foundIOLocks); - BufferIOLWLockTranche.name = "buffer_io"; - BufferIOLWLockTranche.array_base = BufferIOLWLockArray; - BufferIOLWLockTranche.array_stride = sizeof(LWLockMinimallyPadded); - LWLockRegisterTranche(LWTRANCHE_BUFFER_IO_IN_PROGRESS, - &BufferIOLWLockTranche); - - BufferContentLWLockTranche.name = "buffer_content"; - BufferContentLWLockTranche.array_base = - ((char *) BufferDescriptors) + offsetof(BufferDesc, content_lock); - BufferContentLWLockTranche.array_stride = sizeof(BufferDescPadded); - LWLockRegisterTranche(LWTRANCHE_BUFFER_CONTENT, - &BufferContentLWLockTranche); + LWLockRegisterTranche(LWTRANCHE_BUFFER_IO_IN_PROGRESS, "buffer_io"); + LWLockRegisterTranche(LWTRANCHE_BUFFER_CONTENT, "buffer_content"); /* * The array used to sort to-be-checkpointed buffer ids is located in diff --git a/src/backend/storage/buffer/buf_table.c b/src/backend/storage/buffer/buf_table.c index 39e8bafce3..bccda066f9 100644 --- a/src/backend/storage/buffer/buf_table.c +++ b/src/backend/storage/buffer/buf_table.c @@ -10,7 +10,7 @@ * before the lock is released (see notes in README). * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 76ade3727c..3cb51204dc 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -3,7 +3,7 @@ * bufmgr.c * buffer manager interface routines * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -821,7 +821,7 @@ ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, Assert(buf_state & BM_VALID); buf_state &= ~BM_VALID; - pg_atomic_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); } else { @@ -941,7 +941,7 @@ ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); buf_state |= BM_VALID; - pg_atomic_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); } else { @@ -1460,8 +1460,8 @@ MarkBufferDirty(Buffer buffer) bufHdr = GetBufferDescriptor(buffer - 1); Assert(BufferIsPinned(buffer)); - /* unfortunately we can't check if the lock is held exclusively */ - Assert(LWLockHeldByMe(BufferDescriptorGetContentLock(bufHdr))); + Assert(LWLockHeldByMeInMode(BufferDescriptorGetContentLock(bufHdr), + LW_EXCLUSIVE)); old_buf_state = pg_atomic_read_u32(&bufHdr->state); for (;;) @@ -3167,7 +3167,7 @@ FlushRelationBuffers(Relation rel) false); buf_state &= ~(BM_DIRTY | BM_JUST_DIRTIED); - pg_atomic_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); /* Pop the error context stack */ error_context_stack = errcallback.previous; @@ -3635,9 +3635,6 @@ LockBufferForCleanup(Buffer buffer) UnlockBufHdr(bufHdr, buf_state); LockBuffer(buffer, BUFFER_LOCK_UNLOCK); - /* Report the wait */ - pgstat_report_wait_start(WAIT_BUFFER_PIN, 0); - /* Wait to be signaled by UnpinBuffer() */ if (InHotStandby) { @@ -3649,9 +3646,7 @@ LockBufferForCleanup(Buffer buffer) SetStartupBufferPinWaitBufId(-1); } else - ProcWaitForSignal(); - - pgstat_report_wait_end(); + ProcWaitForSignal(PG_WAIT_BUFFER_PIN); /* * Remove flag marking us as waiter. Normally this will not be set @@ -3750,6 +3745,55 @@ ConditionalLockBufferForCleanup(Buffer buffer) return false; } +/* + * IsBufferCleanupOK - as above, but we already have the lock + * + * Check whether it's OK to perform cleanup on a buffer we've already + * locked. If we observe that the pin count is 1, our exclusive lock + * happens to be a cleanup lock, and we can proceed with anything that + * would have been allowable had we sought a cleanup lock originally. + */ +bool +IsBufferCleanupOK(Buffer buffer) +{ + BufferDesc *bufHdr; + uint32 buf_state; + + Assert(BufferIsValid(buffer)); + + if (BufferIsLocal(buffer)) + { + /* There should be exactly one pin */ + if (LocalRefCount[-buffer - 1] != 1) + return false; + /* Nobody else to wait for */ + return true; + } + + /* There should be exactly one local pin */ + if (GetPrivateRefCount(buffer) != 1) + return false; + + bufHdr = GetBufferDescriptor(buffer - 1); + + /* caller must hold exclusive lock on buffer */ + Assert(LWLockHeldByMeInMode(BufferDescriptorGetContentLock(bufHdr), + LW_EXCLUSIVE)); + + buf_state = LockBufHdr(bufHdr); + + Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); + if (BUF_STATE_GET_REFCOUNT(buf_state) == 1) + { + /* pincount is OK. */ + UnlockBufHdr(bufHdr, buf_state); + return true; + } + + UnlockBufHdr(bufHdr, buf_state); + return false; +} + /* * Functions for buffer I/O handling diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c index 88b90dc527..b68ab2082e 100644 --- a/src/backend/storage/buffer/freelist.c +++ b/src/backend/storage/buffer/freelist.c @@ -4,7 +4,7 @@ * routines for managing the buffer pool's replacement strategy. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c index 53981794b9..6e59ce888c 100644 --- a/src/backend/storage/buffer/localbuf.c +++ b/src/backend/storage/buffer/localbuf.c @@ -4,7 +4,7 @@ * local buffer manager. Fast buffer manager for temporary tables, * which never need to be WAL-logged or checkpointed, etc. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994-5, Regents of the University of California * * @@ -138,7 +138,7 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, if (BUF_STATE_GET_USAGECOUNT(buf_state) < BM_MAX_USAGE_COUNT) { buf_state += BUF_USAGECOUNT_ONE; - pg_atomic_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); } } LocalRefCount[b]++; @@ -181,7 +181,7 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, if (BUF_STATE_GET_USAGECOUNT(buf_state) > 0) { buf_state -= BUF_USAGECOUNT_ONE; - pg_atomic_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); trycounter = NLocBuffer; } else @@ -222,7 +222,7 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, /* Mark not-dirty now in case we error out below */ buf_state &= ~BM_DIRTY; - pg_atomic_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); pgBufferUsage.local_blks_written++; } @@ -249,7 +249,7 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, /* mark buffer invalid just in case hash insert fails */ CLEAR_BUFFERTAG(bufHdr->tag); buf_state &= ~(BM_VALID | BM_TAG_VALID); - pg_atomic_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); } hresult = (LocalBufferLookupEnt *) @@ -266,7 +266,7 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, buf_state |= BM_TAG_VALID; buf_state &= ~BUF_USAGECOUNT_MASK; buf_state += BUF_USAGECOUNT_ONE; - pg_atomic_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); *foundPtr = FALSE; return bufHdr; @@ -302,7 +302,7 @@ MarkLocalBufferDirty(Buffer buffer) buf_state |= BM_DIRTY; - pg_atomic_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); } /* @@ -351,7 +351,7 @@ DropRelFileNodeLocalBuffers(RelFileNode rnode, ForkNumber forkNum, CLEAR_BUFFERTAG(bufHdr->tag); buf_state &= ~BUF_FLAG_MASK; buf_state &= ~BUF_USAGECOUNT_MASK; - pg_atomic_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); } } } @@ -395,7 +395,7 @@ DropRelFileNodeAllLocalBuffers(RelFileNode rnode) CLEAR_BUFFERTAG(bufHdr->tag); buf_state &= ~BUF_FLAG_MASK; buf_state &= ~BUF_USAGECOUNT_MASK; - pg_atomic_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); } } } @@ -511,9 +511,7 @@ GetLocalBufferStorage(void) LocalBufferContext = AllocSetContextCreate(TopMemoryContext, "LocalBufferContext", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* Start with a 16-buffer request; subsequent ones double each time */ num_bufs = Max(num_bufs_in_block * 2, 16); diff --git a/src/backend/storage/file/buffile.c b/src/backend/storage/file/buffile.c index 042be79440..7ebd6360a8 100644 --- a/src/backend/storage/file/buffile.c +++ b/src/backend/storage/file/buffile.c @@ -3,7 +3,7 @@ * buffile.c * Management of large buffered files, primarily temporary files. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/storage/file/copydir.c b/src/backend/storage/file/copydir.c index a51ee81566..101da47dac 100644 --- a/src/backend/storage/file/copydir.c +++ b/src/backend/storage/file/copydir.c @@ -3,7 +3,7 @@ * copydir.c * copies a directory * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * While "xcopy /e /i /q" works fine for copying directories, on Windows XP diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index 03143f1133..ce4bd0f3de 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -3,7 +3,7 @@ * fd.c * Virtual file descriptor code. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -2787,7 +2787,7 @@ looks_like_temp_rel_name(const char *name) * 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_xlog and immediately under pg_tblspc. + * follow symlinks only for pg_wal 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. * @@ -2811,7 +2811,7 @@ SyncDataDirectory(void) return; /* - * If pg_xlog is a symlink, we'll need to recurse into it separately, + * 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; @@ -2820,16 +2820,16 @@ SyncDataDirectory(void) { struct stat st; - if (lstat("pg_xlog", &st) < 0) + if (lstat("pg_wal", &st) < 0) ereport(LOG, (errcode_for_file_access(), errmsg("could not stat file \"%s\": %m", - "pg_xlog"))); + "pg_wal"))); else if (S_ISLNK(st.st_mode)) xlog_is_symlink = true; } #else - if (pgwin32_is_junction("pg_xlog")) + if (pgwin32_is_junction("pg_wal")) xlog_is_symlink = true; #endif @@ -2841,7 +2841,7 @@ SyncDataDirectory(void) #ifdef PG_FLUSH_DATA_WORKS walkdir(".", pre_sync_fname, false, DEBUG1); if (xlog_is_symlink) - walkdir("pg_xlog", pre_sync_fname, false, DEBUG1); + walkdir("pg_wal", pre_sync_fname, false, DEBUG1); walkdir("pg_tblspc", pre_sync_fname, true, DEBUG1); #endif @@ -2849,14 +2849,14 @@ SyncDataDirectory(void) * Now we do the fsync()s in the same order. * * The main call ignores symlinks, so in addition to specially processing - * pg_xlog if it's a symlink, pg_tblspc has to be visited separately with + * 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(".", datadir_fsync_fname, false, LOG); if (xlog_is_symlink) - walkdir("pg_xlog", datadir_fsync_fname, false, LOG); + walkdir("pg_wal", datadir_fsync_fname, false, LOG); walkdir("pg_tblspc", datadir_fsync_fname, true, LOG); } diff --git a/src/backend/storage/file/reinit.c b/src/backend/storage/file/reinit.c index 7e8138b42a..b883dfc657 100644 --- a/src/backend/storage/file/reinit.c +++ b/src/backend/storage/file/reinit.c @@ -3,7 +3,7 @@ * reinit.c * Reinitialization of unlogged relations * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -65,9 +65,7 @@ ResetUnloggedRelations(int op) */ tmpctx = AllocSetContextCreate(CurrentMemoryContext, "ResetUnloggedRelations", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldctx = MemoryContextSwitchTo(tmpctx); /* diff --git a/src/backend/storage/freespace/freespace.c b/src/backend/storage/freespace/freespace.c index bbd90c911a..4648473523 100644 --- a/src/backend/storage/freespace/freespace.c +++ b/src/backend/storage/freespace/freespace.c @@ -4,7 +4,7 @@ * POSTGRES free space map for quickly finding free space in relations * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -327,8 +327,26 @@ FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks) if (!BufferIsValid(buf)) return; /* nothing to do; the FSM was already smaller */ LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); + + /* NO EREPORT(ERROR) from here till changes are logged */ + START_CRIT_SECTION(); + fsm_truncate_avail(BufferGetPage(buf), first_removed_slot); - MarkBufferDirtyHint(buf, false); + + /* + * Truncation of a relation is WAL-logged at a higher-level, and we + * will be called at WAL replay. But if checksums are enabled, we need + * to still write a WAL record to protect against a torn page, if the + * page is flushed to disk before the truncation WAL record. We cannot + * use MarkBufferDirtyHint here, because that will not dirty the page + * during recovery. + */ + MarkBufferDirty(buf); + if (!InRecovery && RelationNeedsWAL(rel) && XLogHintBitIsNeeded()) + log_newpage_buffer(buf, false); + + END_CRIT_SECTION(); + UnlockReleaseBuffer(buf); new_nfsmblocks = fsm_logical_to_physical(first_removed_address) + 1; diff --git a/src/backend/storage/freespace/fsmpage.c b/src/backend/storage/freespace/fsmpage.c index 535a4711eb..987a2f5e53 100644 --- a/src/backend/storage/freespace/fsmpage.c +++ b/src/backend/storage/freespace/fsmpage.c @@ -4,7 +4,7 @@ * routines to search and manipulate one FSM page. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/storage/freespace/indexfsm.c b/src/backend/storage/freespace/indexfsm.c index e060a40c7d..5cfbd4c867 100644 --- a/src/backend/storage/freespace/indexfsm.c +++ b/src/backend/storage/freespace/indexfsm.c @@ -4,7 +4,7 @@ * POSTGRES free space map for quickly finding free pages in relations * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/storage/ipc/dsm.c b/src/backend/storage/ipc/dsm.c index 47f2bea0be..07af16622c 100644 --- a/src/backend/storage/ipc/dsm.c +++ b/src/backend/storage/ipc/dsm.c @@ -14,7 +14,7 @@ * hard postmaster crash, remaining segments will be removed, if they * still exist, at the next postmaster startup. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -82,6 +82,8 @@ typedef struct dsm_control_item { dsm_handle handle; uint32 refcnt; /* 2+ = active, 1 = moribund, 0 = gone */ + void *impl_private_pm_handle; /* only needed on Windows */ + bool pinned; } dsm_control_item; /* Layout of the dynamic shared memory control segment. */ @@ -180,7 +182,7 @@ dsm_postmaster_startup(PGShmemHeader *shim) Assert(dsm_control_address == NULL); Assert(dsm_control_mapped_size == 0); dsm_control_handle = random(); - if (dsm_control_handle == 0) + if (dsm_control_handle == DSM_HANDLE_INVALID) continue; if (dsm_impl_op(DSM_OP_CREATE, dsm_control_handle, segsize, &dsm_control_impl_private, &dsm_control_address, @@ -474,6 +476,8 @@ dsm_create(Size size, int flags) { Assert(seg->mapped_address == NULL && seg->mapped_size == 0); seg->handle = random(); + if (seg->handle == DSM_HANDLE_INVALID) /* Reserve sentinel */ + continue; if (dsm_impl_op(DSM_OP_CREATE, seg->handle, size, &seg->impl_private, &seg->mapped_address, &seg->mapped_size, ERROR)) break; @@ -491,6 +495,8 @@ dsm_create(Size size, int flags) dsm_control->item[i].handle = seg->handle; /* refcnt of 1 triggers destruction, so start at 2 */ dsm_control->item[i].refcnt = 2; + dsm_control->item[i].impl_private_pm_handle = NULL; + dsm_control->item[i].pinned = false; seg->control_slot = i; LWLockRelease(DynamicSharedMemoryControlLock); return seg; @@ -520,6 +526,8 @@ dsm_create(Size size, int flags) dsm_control->item[nitems].handle = seg->handle; /* refcnt of 1 triggers destruction, so start at 2 */ dsm_control->item[nitems].refcnt = 2; + dsm_control->item[nitems].impl_private_pm_handle = NULL; + dsm_control->item[nitems].pinned = false; seg->control_slot = nitems; dsm_control->nitems++; LWLockRelease(DynamicSharedMemoryControlLock); @@ -760,6 +768,9 @@ dsm_detach(dsm_segment *seg) /* If new reference count is 1, try to destroy the segment. */ if (refcnt == 1) { + /* A pinned segment should never reach 1. */ + Assert(!dsm_control->item[control_slot].pinned); + /* * If we fail to destroy the segment here, or are killed before we * finish doing so, the reference count will remain at 1, which @@ -830,11 +841,11 @@ dsm_unpin_mapping(dsm_segment *seg) } /* - * Keep a dynamic shared memory segment until postmaster shutdown. + * Keep a dynamic shared memory segment until postmaster shutdown, or until + * dsm_unpin_segment is called. * - * This function should not be called more than once per segment; - * on Windows, doing so will create unnecessary handles which will - * consume system resources to no benefit. + * This function should not be called more than once per segment, unless the + * segment is explicitly unpinned with dsm_unpin_segment in between calls. * * Note that this function does not arrange for the current process to * keep the segment mapped indefinitely; if that behavior is desired, @@ -844,16 +855,112 @@ dsm_unpin_mapping(dsm_segment *seg) void dsm_pin_segment(dsm_segment *seg) { + void *handle; + /* * Bump reference count for this segment in shared memory. This will * ensure that even if there is no session which is attached to this - * segment, it will remain until postmaster shutdown. + * segment, it will remain until postmaster shutdown or an explicit call + * to unpin. */ LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE); + if (dsm_control->item[seg->control_slot].pinned) + elog(ERROR, "cannot pin a segment that is already pinned"); + dsm_impl_pin_segment(seg->handle, seg->impl_private, &handle); + dsm_control->item[seg->control_slot].pinned = true; dsm_control->item[seg->control_slot].refcnt++; + dsm_control->item[seg->control_slot].impl_private_pm_handle = handle; + LWLockRelease(DynamicSharedMemoryControlLock); +} + +/* + * Unpin a dynamic shared memory segment that was previously pinned with + * dsm_pin_segment. This function should not be called unless dsm_pin_segment + * was previously called for this segment. + * + * The argument is a dsm_handle rather than a dsm_segment in case you want + * to unpin a segment to which you haven't attached. This turns out to be + * useful if, for example, a reference to one shared memory segment is stored + * within another shared memory segment. You might want to unpin the + * referenced segment before destroying the referencing segment. + */ +void +dsm_unpin_segment(dsm_handle handle) +{ + uint32 control_slot = INVALID_CONTROL_SLOT; + bool destroy = false; + uint32 i; + + /* Find the control slot for the given handle. */ + LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE); + for (i = 0; i < dsm_control->nitems; ++i) + { + /* Skip unused slots. */ + if (dsm_control->item[i].refcnt == 0) + continue; + + /* If we've found our handle, we can stop searching. */ + if (dsm_control->item[i].handle == handle) + { + control_slot = i; + break; + } + } + + /* + * We should definitely have found the slot, and it should not already be + * in the process of going away, because this function should only be + * called on a segment which is pinned. + */ + if (control_slot == INVALID_CONTROL_SLOT) + elog(ERROR, "cannot unpin unknown segment handle"); + if (!dsm_control->item[control_slot].pinned) + elog(ERROR, "cannot unpin a segment that is not pinned"); + Assert(dsm_control->item[control_slot].refcnt > 1); + + /* + * Allow implementation-specific code to run. We have to do this before + * releasing the lock, because impl_private_pm_handle may get modified by + * dsm_impl_unpin_segment. + */ + dsm_impl_unpin_segment(handle, + &dsm_control->item[control_slot].impl_private_pm_handle); + + /* Note that 1 means no references (0 means unused slot). */ + if (--dsm_control->item[control_slot].refcnt == 1) + destroy = true; + dsm_control->item[control_slot].pinned = false; + + /* Now we can release the lock. */ LWLockRelease(DynamicSharedMemoryControlLock); - dsm_impl_pin_segment(seg->handle, seg->impl_private); + /* Clean up resources if that was the last reference. */ + if (destroy) + { + void *junk_impl_private = NULL; + void *junk_mapped_address = NULL; + Size junk_mapped_size = 0; + + /* + * For an explanation of how error handling works in this case, see + * comments in dsm_detach. Note that if we reach this point, the + * current process certainly does not have the segment mapped, because + * if it did, the reference count would have still been greater than 1 + * even after releasing the reference count held by the pin. The fact + * that there can't be a dsm_segment for this handle makes it OK to + * pass the mapped size, mapped address, and private data as NULL + * here. + */ + if (dsm_impl_op(DSM_OP_DESTROY, handle, 0, &junk_impl_private, + &junk_mapped_address, &junk_mapped_size, WARNING)) + { + LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE); + Assert(dsm_control->item[control_slot].handle == handle); + Assert(dsm_control->item[control_slot].refcnt == 1); + dsm_control->item[control_slot].refcnt = 0; + LWLockRelease(DynamicSharedMemoryControlLock); + } + } } /* diff --git a/src/backend/storage/ipc/dsm_impl.c b/src/backend/storage/ipc/dsm_impl.c index 173b982219..7078f68c35 100644 --- a/src/backend/storage/ipc/dsm_impl.c +++ b/src/backend/storage/ipc/dsm_impl.c @@ -36,12 +36,12 @@ * * As ever, Windows requires its own implementation. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * src/backend/storage/ipc/dsm.c + * src/backend/storage/ipc/dsm_impl.c * *------------------------------------------------------------------------- */ @@ -671,6 +671,7 @@ dsm_impl_windows(dsm_op op, dsm_handle handle, Size request_size, { DWORD size_high; DWORD size_low; + DWORD errcode; /* Shifts >= the width of the type are undefined. */ #ifdef _WIN64 @@ -680,33 +681,40 @@ dsm_impl_windows(dsm_op op, dsm_handle handle, Size request_size, #endif size_low = (DWORD) request_size; + /* CreateFileMapping might not clear the error code on success */ + SetLastError(0); + hmap = CreateFileMapping(INVALID_HANDLE_VALUE, /* Use the pagefile */ NULL, /* Default security attrs */ PAGE_READWRITE, /* Memory is read/write */ size_high, /* Upper 32 bits of size */ size_low, /* Lower 32 bits of size */ name); + + errcode = GetLastError(); + if (errcode == ERROR_ALREADY_EXISTS || errcode == ERROR_ACCESS_DENIED) + { + /* + * On Windows, when the segment already exists, a handle for the + * existing segment is returned. We must close it before + * returning. However, if the existing segment is created by a + * service, then it returns ERROR_ACCESS_DENIED. We don't do + * _dosmaperr here, so errno won't be modified. + */ + if (hmap) + CloseHandle(hmap); + return false; + } + if (!hmap) { - _dosmaperr(GetLastError()); + _dosmaperr(errcode); ereport(elevel, (errcode_for_dynamic_shared_memory(), errmsg("could not create shared memory segment \"%s\": %m", name))); return false; } - _dosmaperr(GetLastError()); - if (errno == EEXIST) - { - /* - * On Windows, when the segment already exists, a handle for the - * existing segment is returned. We must close it before - * returning. We don't do _dosmaperr here, so errno won't be - * modified. - */ - CloseHandle(hmap); - return false; - } } else { @@ -987,8 +995,8 @@ dsm_impl_mmap(dsm_op op, dsm_handle handle, Size request_size, #endif /* - * Implementation-specific actions that must be performed when a segment - * is to be preserved until postmaster shutdown. + * Implementation-specific actions that must be performed when a segment is to + * be preserved even when no backend has it attached. * * Except on Windows, we don't need to do anything at all. But since Windows * cleans up segments automatically when no references remain, we duplicate @@ -996,7 +1004,8 @@ dsm_impl_mmap(dsm_op op, dsm_handle handle, Size request_size, * do anything to receive the handle; Windows transfers it automatically. */ void -dsm_impl_pin_segment(dsm_handle handle, void *impl_private) +dsm_impl_pin_segment(dsm_handle handle, void *impl_private, + void **impl_private_pm_handle) { switch (dynamic_shared_memory_type) { @@ -1018,6 +1027,56 @@ dsm_impl_pin_segment(dsm_handle handle, void *impl_private) errmsg("could not duplicate handle for \"%s\": %m", name))); } + + /* + * Here, we remember the handle that we created in the + * postmaster process. This handle isn't actually usable in + * any process other than the postmaster, but that doesn't + * matter. We're just holding onto it so that, if the segment + * is unpinned, dsm_impl_unpin_segment can close it. + */ + *impl_private_pm_handle = hmap; + break; + } +#endif + default: + break; + } +} + +/* + * Implementation-specific actions that must be performed when a segment is no + * longer to be preserved, so that it will be cleaned up when all backends + * have detached from it. + * + * Except on Windows, we don't need to do anything at all. For Windows, we + * close the extra handle that dsm_impl_pin_segment created in the + * postmaster's process space. + */ +void +dsm_impl_unpin_segment(dsm_handle handle, void **impl_private) +{ + switch (dynamic_shared_memory_type) + { +#ifdef USE_DSM_WINDOWS + case DSM_IMPL_WINDOWS: + { + if (*impl_private && + !DuplicateHandle(PostmasterHandle, *impl_private, + NULL, NULL, 0, FALSE, + DUPLICATE_CLOSE_SOURCE)) + { + char name[64]; + + snprintf(name, 64, "%s.%u", SEGMENT_NAME_PREFIX, handle); + _dosmaperr(GetLastError()); + ereport(ERROR, + (errcode_for_dynamic_shared_memory(), + errmsg("could not duplicate handle for \"%s\": %m", + name))); + } + + *impl_private = NULL; break; } #endif diff --git a/src/backend/storage/ipc/ipc.c b/src/backend/storage/ipc/ipc.c index cc36b80699..ffd91f5b0a 100644 --- a/src/backend/storage/ipc/ipc.c +++ b/src/backend/storage/ipc/ipc.c @@ -8,7 +8,7 @@ * exit-time cleanup for either a postmaster or a backend. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c index c04b17fa8e..2d1ed143e0 100644 --- a/src/backend/storage/ipc/ipci.c +++ b/src/backend/storage/ipc/ipci.c @@ -3,7 +3,7 @@ * ipci.c * POSTGRES inter-process communication initialization code. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -28,6 +28,7 @@ #include "postmaster/bgworker_internals.h" #include "postmaster/bgwriter.h" #include "postmaster/postmaster.h" +#include "replication/logicallauncher.h" #include "replication/slot.h" #include "replication/walreceiver.h" #include "replication/walsender.h" @@ -43,6 +44,7 @@ #include "storage/procsignal.h" #include "storage/sinvaladt.h" #include "storage/spin.h" +#include "utils/backend_random.h" #include "utils/snapmgr.h" @@ -101,6 +103,10 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port) Size size; int numSemas; + /* Compute number of semaphores we'll need */ + numSemas = ProcGlobalSemas(); + numSemas += SpinlockSemas(); + /* * Size of the Postgres shared-memory block is estimated via * moderately-accurate estimates for the big hogs, plus 100K for the @@ -111,6 +117,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port) * need to be so careful during the actual allocation phase. */ size = 100000; + size = add_size(size, PGSemaphoreShmemSize(numSemas)); size = add_size(size, SpinlockSemaSize()); size = add_size(size, hash_estimate_size(SHMEM_INDEX_SIZE, sizeof(ShmemIndexEnt))); @@ -137,10 +144,12 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port) size = add_size(size, ReplicationOriginShmemSize()); size = add_size(size, WalSndShmemSize()); size = add_size(size, WalRcvShmemSize()); + size = add_size(size, ApplyLauncherShmemSize()); size = add_size(size, SnapMgrShmemSize()); size = add_size(size, BTreeShmemSize()); size = add_size(size, SyncScanShmemSize()); size = add_size(size, AsyncShmemSize()); + size = add_size(size, BackendRandomShmemSize()); #ifdef EXEC_BACKEND size = add_size(size, ShmemBackendArraySize()); #endif @@ -164,9 +173,15 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port) /* * Create semaphores */ - numSemas = ProcGlobalSemas(); - numSemas += SpinlockSemas(); PGReserveSemaphores(numSemas, port); + + /* + * If spinlocks are disabled, initialize emulation layer (which + * depends on semaphores, so the order is important here). + */ +#ifndef HAVE_SPINLOCKS + SpinlockSemaInit(); +#endif } else { @@ -245,6 +260,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port) ReplicationOriginShmemInit(); WalSndShmemInit(); WalRcvShmemInit(); + ApplyLauncherShmemInit(); /* * Set up other modules that need some shared memory space @@ -253,6 +269,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port) BTreeShmemInit(); SyncScanShmemInit(); AsyncShmemInit(); + BackendRandomShmemInit(); #ifdef EXEC_BACKEND diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c index 9def8a12d3..d45a41d863 100644 --- a/src/backend/storage/ipc/latch.c +++ b/src/backend/storage/ipc/latch.c @@ -25,7 +25,7 @@ * The Windows implementation uses Windows events that are inherited by * all postmaster child processes. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -55,9 +55,10 @@ #endif #include "miscadmin.h" +#include "pgstat.h" +#include "port/atomics.h" #include "portability/instr_time.h" #include "postmaster/postmaster.h" -#include "storage/barrier.h" #include "storage/latch.h" #include "storage/pmsignal.h" #include "storage/shmem.h" @@ -297,9 +298,11 @@ DisownLatch(volatile Latch *latch) * we return all of them in one call, but we will return at least one. */ int -WaitLatch(volatile Latch *latch, int wakeEvents, long timeout) +WaitLatch(volatile Latch *latch, int wakeEvents, long timeout, + uint32 wait_event_info) { - return WaitLatchOrSocket(latch, wakeEvents, PGINVALID_SOCKET, timeout); + return WaitLatchOrSocket(latch, wakeEvents, PGINVALID_SOCKET, timeout, + wait_event_info); } /* @@ -316,7 +319,7 @@ WaitLatch(volatile Latch *latch, int wakeEvents, long timeout) */ int WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, - long timeout) + long timeout, uint32 wait_event_info) { int ret = 0; int rc; @@ -344,7 +347,7 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, AddWaitEventToSet(set, ev, sock, NULL, NULL); } - rc = WaitEventSetWait(set, timeout, &event, 1); + rc = WaitEventSetWait(set, timeout, &event, 1, wait_event_info); if (rc == 0) ret |= WL_TIMEOUT; @@ -640,6 +643,9 @@ AddWaitEventToSet(WaitEventSet *set, uint32 events, pgsocket fd, Latch *latch, event->fd = fd; event->events = events; event->user_data = user_data; +#ifdef WIN32 + event->reset = false; +#endif if (events == WL_LATCH_SET) { @@ -863,7 +869,8 @@ WaitEventAdjustWin32(WaitEventSet *set, WaitEvent *event) */ int WaitEventSetWait(WaitEventSet *set, long timeout, - WaitEvent *occurred_events, int nevents) + WaitEvent *occurred_events, int nevents, + uint32 wait_event_info) { int returned_events = 0; instr_time start_time; @@ -883,6 +890,8 @@ WaitEventSetWait(WaitEventSet *set, long timeout, cur_timeout = timeout; } + pgstat_report_wait_start(wait_event_info); + #ifndef WIN32 waiting = true; #else @@ -960,6 +969,8 @@ WaitEventSetWait(WaitEventSet *set, long timeout, waiting = false; #endif + pgstat_report_wait_end(); + return returned_events; } @@ -1381,6 +1392,18 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout, DWORD rc; WaitEvent *cur_event; + /* Reset any wait events that need it */ + for (cur_event = set->events; + cur_event < (set->events + set->nevents); + cur_event++) + { + if (cur_event->reset) + { + WaitEventAdjustWin32(set, cur_event); + cur_event->reset = false; + } + } + /* * Sleep. * @@ -1464,6 +1487,18 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout, { /* data available in socket */ occurred_events->events |= WL_SOCKET_READABLE; + + /*------ + * WaitForMultipleObjects doesn't guarantee that a read event will + * be returned if the latch is set at the same time. Even if it + * did, the caller might drop that event expecting it to reoccur + * on next call. So, we must force the event to be reset if this + * WaitEventSet is used again in order to avoid an indefinite + * hang. Refer https://msdn.microsoft.com/en-us/library/windows/desktop/ms741576(v=vs.85).aspx + * for the behavior of socket events. + *------ + */ + cur_event->reset = true; } if ((cur_event->events & WL_SOCKET_WRITEABLE) && (resEvents.lNetworkEvents & FD_WRITE)) diff --git a/src/backend/storage/ipc/pmsignal.c b/src/backend/storage/ipc/pmsignal.c index 7ae622cb12..98f4082d94 100644 --- a/src/backend/storage/ipc/pmsignal.c +++ b/src/backend/storage/ipc/pmsignal.c @@ -4,7 +4,7 @@ * routines for signaling the postmaster from its child processes * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index e5d487dbb7..3f47b984ee 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -32,7 +32,7 @@ * happen, it would tie up KnownAssignedXids indefinitely, so we protect * ourselves by pruning the array when a valid list of running XIDs arrives. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -106,9 +106,6 @@ static TransactionId *KnownAssignedXids; static bool *KnownAssignedXidsValid; static TransactionId latestObservedXid = InvalidTransactionId; -/* LWLock tranche for backend locks */ -static LWLockTranche ProcLWLockTranche; - /* * If we're in STANDBY_SNAPSHOT_PENDING state, standbySnapshotPendingXmin is * the highest xid that might still be running that we don't have in @@ -266,11 +263,7 @@ CreateSharedProcArray(void) } /* Register and initialize fields of ProcLWLockTranche */ - ProcLWLockTranche.name = "proc"; - ProcLWLockTranche.array_base = (char *) (ProcGlobal->allProcs) + - offsetof(PGPROC, backendLock); - ProcLWLockTranche.array_stride = sizeof(PGPROC); - LWLockRegisterTranche(LWTRANCHE_PROC, &ProcLWLockTranche); + LWLockRegisterTranche(LWTRANCHE_PROC, "proc"); } /* @@ -491,7 +484,6 @@ ProcArrayGroupClearXid(PGPROC *proc, TransactionId latestXid) volatile PROC_HDR *procglobal = ProcGlobal; uint32 nextidx; uint32 wakeidx; - int extraWaits = -1; /* We should definitely have an XID to clear. */ Assert(TransactionIdIsValid(allPgXact[proc->pgprocno].xid)); @@ -518,11 +510,13 @@ ProcArrayGroupClearXid(PGPROC *proc, TransactionId latestXid) */ if (nextidx != INVALID_PGPROCNO) { + int extraWaits = 0; + /* Sleep until the leader clears our XID. */ for (;;) { /* acts as a read barrier */ - PGSemaphoreLock(&proc->sem); + PGSemaphoreLock(proc->sem); if (!proc->procArrayGroupMember) break; extraWaits++; @@ -532,7 +526,7 @@ ProcArrayGroupClearXid(PGPROC *proc, TransactionId latestXid) /* Fix semaphore count for any absorbed wakeups */ while (extraWaits-- > 0) - PGSemaphoreUnlock(&proc->sem); + PGSemaphoreUnlock(proc->sem); return; } @@ -591,7 +585,7 @@ ProcArrayGroupClearXid(PGPROC *proc, TransactionId latestXid) proc->procArrayGroupMember = false; if (proc != MyProc) - PGSemaphoreUnlock(&proc->sem); + PGSemaphoreUnlock(proc->sem); } } diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c index a3d6ac5318..4a21d5512d 100644 --- a/src/backend/storage/ipc/procsignal.c +++ b/src/backend/storage/ipc/procsignal.c @@ -4,7 +4,7 @@ * Routines for interprocess signalling * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/storage/ipc/shm_mq.c b/src/backend/storage/ipc/shm_mq.c index 5b32782022..32b4d3d5d4 100644 --- a/src/backend/storage/ipc/shm_mq.c +++ b/src/backend/storage/ipc/shm_mq.c @@ -8,7 +8,7 @@ * and only the receiver may receive. This is intended to allow a user * backend to communicate with worker backends that it has registered. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/shm_mq.h @@ -19,6 +19,7 @@ #include "postgres.h" #include "miscadmin.h" +#include "pgstat.h" #include "postmaster/bgworker.h" #include "storage/procsignal.h" #include "storage/shm_mq.h" @@ -894,7 +895,7 @@ shm_mq_send_bytes(shm_mq_handle *mqh, Size nbytes, const void *data, * at top of loop, because setting an already-set latch is much * cheaper than setting one that has been reset. */ - WaitLatch(MyLatch, WL_LATCH_SET, 0); + WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_MQ_SEND); /* Reset the latch so we don't spin. */ ResetLatch(MyLatch); @@ -991,7 +992,7 @@ shm_mq_receive_bytes(shm_mq *mq, Size bytes_needed, bool nowait, * loop, because setting an already-set latch is much cheaper than * setting one that has been reset. */ - WaitLatch(MyLatch, WL_LATCH_SET, 0); + WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_MQ_RECEIVE); /* Reset the latch so we don't spin. */ ResetLatch(MyLatch); @@ -1090,7 +1091,7 @@ shm_mq_wait_internal(volatile shm_mq *mq, PGPROC *volatile * ptr, } /* Wait to be signalled. */ - WaitLatch(MyLatch, WL_LATCH_SET, 0); + WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_MQ_INTERNAL); /* Reset the latch so we don't spin. */ ResetLatch(MyLatch); diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c index 55248c2ac2..9110ffa4a0 100644 --- a/src/backend/storage/ipc/shm_toc.c +++ b/src/backend/storage/ipc/shm_toc.c @@ -3,7 +3,7 @@ * shm_toc.c * shared memory segment table of contents * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/shm_toc.c @@ -13,7 +13,7 @@ #include "postgres.h" -#include "storage/barrier.h" +#include "port/atomics.h" #include "storage/shm_toc.h" #include "storage/spin.h" diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c index 1efe0201a7..67150debf2 100644 --- a/src/backend/storage/ipc/shmem.c +++ b/src/backend/storage/ipc/shmem.c @@ -3,7 +3,7 @@ * shmem.c * create shared memory and initialize shared memory data structures. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -117,36 +117,22 @@ InitShmemAllocation(void) Assert(shmhdr != NULL); /* - * If spinlocks are disabled, initialize emulation layer. We have to do - * the space allocation the hard way, since obviously ShmemAlloc can't be - * called yet. + * Initialize the spinlock used by ShmemAlloc. We must use + * ShmemAllocUnlocked, since obviously ShmemAlloc can't be called yet. */ -#ifndef HAVE_SPINLOCKS - { - PGSemaphore spinsemas; + ShmemLock = (slock_t *) ShmemAllocUnlocked(sizeof(slock_t)); - spinsemas = (PGSemaphore) (((char *) shmhdr) + shmhdr->freeoffset); - shmhdr->freeoffset += MAXALIGN(SpinlockSemaSize()); - SpinlockSemaInit(spinsemas); - Assert(shmhdr->freeoffset <= shmhdr->totalsize); - } -#endif + SpinLockInit(ShmemLock); /* - * Initialize the spinlock used by ShmemAlloc; we have to do this the hard - * way, too, for the same reasons as above. + * Allocations after this point should go through ShmemAlloc, which + * expects to allocate everything on cache line boundaries. Make sure the + * first allocation begins on a cache line boundary. */ - ShmemLock = (slock_t *) (((char *) shmhdr) + shmhdr->freeoffset); - shmhdr->freeoffset += MAXALIGN(sizeof(slock_t)); - Assert(shmhdr->freeoffset <= shmhdr->totalsize); - - /* Make sure the first allocation begins on a cache line boundary. */ aligned = (char *) (CACHELINEALIGN((((char *) shmhdr) + shmhdr->freeoffset))); shmhdr->freeoffset = aligned - (char *) shmhdr; - SpinLockInit(ShmemLock); - /* ShmemIndex can't be set up yet (need LWLocks first) */ shmhdr->index = NULL; ShmemIndex = (HTAB *) NULL; @@ -163,14 +149,31 @@ InitShmemAllocation(void) /* * ShmemAlloc -- allocate max-aligned chunk from shared memory * - * Assumes ShmemLock and ShmemSegHdr are initialized. + * Throws error if request cannot be satisfied. * - * Returns: real pointer to memory or NULL if we are out - * of space. Has to return a real pointer in order - * to be compatible with malloc(). + * Assumes ShmemLock and ShmemSegHdr are initialized. */ void * ShmemAlloc(Size size) +{ + void *newSpace; + + newSpace = ShmemAllocNoError(size); + if (!newSpace) + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of shared memory (%zu bytes requested)", + size))); + return newSpace; +} + +/* + * ShmemAllocNoError -- allocate max-aligned chunk from shared memory + * + * As ShmemAlloc, but returns NULL if out of space, rather than erroring. + */ +void * +ShmemAllocNoError(Size size) { Size newStart; Size newFree; @@ -206,12 +209,47 @@ ShmemAlloc(Size size) SpinLockRelease(ShmemLock); - if (!newSpace) - ereport(WARNING, + /* note this assert is okay with newSpace == NULL */ + Assert(newSpace == (void *) CACHELINEALIGN(newSpace)); + + return newSpace; +} + +/* + * ShmemAllocUnlocked -- allocate max-aligned chunk from shared memory + * + * Allocate space without locking ShmemLock. This should be used for, + * and only for, allocations that must happen before ShmemLock is ready. + * + * We consider maxalign, rather than cachealign, sufficient here. + */ +void * +ShmemAllocUnlocked(Size size) +{ + Size newStart; + Size newFree; + void *newSpace; + + /* + * Ensure allocated space is adequately aligned. + */ + size = MAXALIGN(size); + + Assert(ShmemSegHdr != NULL); + + newStart = ShmemSegHdr->freeoffset; + + newFree = newStart + size; + if (newFree > ShmemSegHdr->totalsize) + ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of shared memory"))); + errmsg("out of shared memory (%zu bytes requested)", + size))); + ShmemSegHdr->freeoffset = newFree; - Assert(newSpace == (void *) CACHELINEALIGN(newSpace)); + newSpace = (void *) ((char *) ShmemBase + newStart); + + Assert(newSpace == (void *) MAXALIGN(newSpace)); return newSpace; } @@ -293,7 +331,7 @@ ShmemInitHash(const char *name, /* table string name for shmem index */ * The shared memory allocator must be specified too. */ infoP->dsize = infoP->max_dsize = hash_select_dirsize(max_size); - infoP->alloc = ShmemAlloc; + infoP->alloc = ShmemAllocNoError; hash_flags |= HASH_SHARED_MEM | HASH_ALLOC | HASH_DIRSIZE; /* look it up in the shmem index */ @@ -364,12 +402,6 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr) */ Assert(shmemseghdr->index == NULL); structPtr = ShmemAlloc(size); - if (structPtr == NULL) - ereport(ERROR, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("not enough shared memory for data structure" - " \"%s\" (%zu bytes requested)", - name, size))); shmemseghdr->index = structPtr; *foundPtr = FALSE; } @@ -410,7 +442,7 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr) else { /* It isn't in the table yet. allocate and initialize it */ - structPtr = ShmemAlloc(size); + structPtr = ShmemAllocNoError(size); if (structPtr == NULL) { /* out of memory; remove the failed ShmemIndex entry */ diff --git a/src/backend/storage/ipc/shmqueue.c b/src/backend/storage/ipc/shmqueue.c index e06ad9f628..1026e67b94 100644 --- a/src/backend/storage/ipc/shmqueue.c +++ b/src/backend/storage/ipc/shmqueue.c @@ -3,7 +3,7 @@ * shmqueue.c * shared memory linked lists * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/ipc/sinval.c b/src/backend/storage/ipc/sinval.c index a8b0f49985..13f21e0d99 100644 --- a/src/backend/storage/ipc/sinval.c +++ b/src/backend/storage/ipc/sinval.c @@ -3,7 +3,7 @@ * sinval.c * POSTGRES shared cache invalidation communication code. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c index 44a9f2cef4..18302caf5e 100644 --- a/src/backend/storage/ipc/sinvaladt.c +++ b/src/backend/storage/ipc/sinvaladt.c @@ -3,7 +3,7 @@ * sinvaladt.c * POSTGRES shared cache invalidation data manager. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c index 547f1a88fe..9cc1281766 100644 --- a/src/backend/storage/ipc/standby.c +++ b/src/backend/storage/ipc/standby.c @@ -7,7 +7,7 @@ * AccessExclusiveLocks and starting snapshots for Hot Standby mode. * Plus conflict recovery processing. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -22,6 +22,7 @@ #include "access/xlog.h" #include "access/xloginsert.h" #include "miscadmin.h" +#include "pgstat.h" #include "storage/bufmgr.h" #include "storage/lmgr.h" #include "storage/proc.h" @@ -389,7 +390,7 @@ ResolveRecoveryConflictWithLock(LOCKTAG locktag) } /* Wait to be signaled by the release of the Relation Lock */ - ProcWaitForSignal(); + ProcWaitForSignal(PG_WAIT_LOCK | locktag.locktag_type); /* * Clear any timeout requests established above. We assume here that the @@ -469,7 +470,7 @@ ResolveRecoveryConflictWithBufferPin(void) } /* Wait to be signaled by UnpinBuffer() */ - ProcWaitForSignal(); + ProcWaitForSignal(PG_WAIT_BUFFER_PIN); /* * Clear any timeout requests established above. We assume here that the @@ -960,10 +961,11 @@ LogStandbySnapshot(void) /* * Record an enhanced snapshot of running transactions into WAL. * - * The definitions of RunningTransactionsData and xl_xact_running_xacts - * are similar. We keep them separate because xl_xact_running_xacts - * is a contiguous chunk of memory and never exists fully until it is - * assembled in WAL. + * The definitions of RunningTransactionsData and xl_xact_running_xacts are + * similar. We keep them separate because xl_xact_running_xacts is a + * contiguous chunk of memory and never exists fully until it is assembled in + * WAL. The inserted records are marked as not being important for durability, + * to avoid triggering superflous checkpoint / archiving activity. */ static XLogRecPtr LogCurrentRunningXacts(RunningTransactions CurrRunningXacts) @@ -980,6 +982,7 @@ LogCurrentRunningXacts(RunningTransactions CurrRunningXacts) /* Header */ XLogBeginInsert(); + XLogSetRecordFlags(XLOG_MARK_UNIMPORTANT); XLogRegisterData((char *) (&xlrec), MinSizeOfXactRunningXacts); /* array of TransactionIds */ @@ -1034,6 +1037,7 @@ LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks) XLogBeginInsert(); XLogRegisterData((char *) &xlrec, offsetof(xl_standby_locks, locks)); XLogRegisterData((char *) locks, nlocks * sizeof(xl_standby_lock)); + XLogSetRecordFlags(XLOG_MARK_UNIMPORTANT); (void) XLogInsert(RM_STANDBY_ID, XLOG_STANDBY_LOCK); } diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c index ec6738c8b8..262b0b271a 100644 --- a/src/backend/storage/large_object/inv_api.c +++ b/src/backend/storage/large_object/inv_api.c @@ -19,7 +19,7 @@ * memory context given to inv_open (for LargeObjectDesc structs). * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/lmgr/Makefile b/src/backend/storage/lmgr/Makefile index cd6ec73f08..e1b787e838 100644 --- a/src/backend/storage/lmgr/Makefile +++ b/src/backend/storage/lmgr/Makefile @@ -13,7 +13,7 @@ top_builddir = ../../../.. include $(top_builddir)/src/Makefile.global OBJS = lmgr.o lock.o proc.o deadlock.o lwlock.o lwlocknames.o spin.o \ - s_lock.o predicate.o + s_lock.o predicate.o condition_variable.o include $(top_srcdir)/src/backend/common.mk diff --git a/src/backend/storage/lmgr/condition_variable.c b/src/backend/storage/lmgr/condition_variable.c new file mode 100644 index 0000000000..67fe177a7d --- /dev/null +++ b/src/backend/storage/lmgr/condition_variable.c @@ -0,0 +1,225 @@ +/*------------------------------------------------------------------------- + * + * condition_variable.c + * Implementation of condition variables. Condition variables provide + * a way for one process to wait until a specific condition occurs, + * without needing to know the specific identity of the process for + * which they are waiting. Waits for condition variables can be + * interrupted, unlike LWLock waits. Condition variables are safe + * to use within dynamic shared memory segments. + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/backend/storage/lmgr/condition_variable.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "miscadmin.h" +#include "storage/condition_variable.h" +#include "storage/ipc.h" +#include "storage/proc.h" +#include "storage/proclist.h" +#include "storage/spin.h" +#include "utils/memutils.h" + +/* Initially, we are not prepared to sleep on any condition variable. */ +static ConditionVariable *cv_sleep_target = NULL; + +/* Reusable WaitEventSet. */ +static WaitEventSet *cv_wait_event_set = NULL; + +/* + * Initialize a condition variable. + */ +void +ConditionVariableInit(ConditionVariable *cv) +{ + SpinLockInit(&cv->mutex); + proclist_init(&cv->wakeup); +} + +/* + * Prepare to wait on a given condition variable. This can optionally be + * called before entering a test/sleep loop. Alternatively, the call to + * ConditionVariablePrepareToSleep can be omitted. The only advantage of + * calling ConditionVariablePrepareToSleep is that it avoids an initial + * double-test of the user's predicate in the case that we need to wait. + */ +void +ConditionVariablePrepareToSleep(ConditionVariable *cv) +{ + int pgprocno = MyProc->pgprocno; + + /* + * It's not legal to prepare a sleep until the previous sleep has been + * completed or canceled. + */ + Assert(cv_sleep_target == NULL); + + /* Record the condition variable on which we will sleep. */ + cv_sleep_target = cv; + + /* Create a reusable WaitEventSet. */ + if (cv_wait_event_set == NULL) + { + cv_wait_event_set = CreateWaitEventSet(TopMemoryContext, 1); + AddWaitEventToSet(cv_wait_event_set, WL_LATCH_SET, PGINVALID_SOCKET, + &MyProc->procLatch, NULL); + } + + /* Add myself to the wait queue. */ + SpinLockAcquire(&cv->mutex); + if (!proclist_contains(&cv->wakeup, pgprocno, cvWaitLink)) + proclist_push_tail(&cv->wakeup, pgprocno, cvWaitLink); + SpinLockRelease(&cv->mutex); + + /* Reset my latch before entering the caller's predicate loop. */ + ResetLatch(&MyProc->procLatch); +} + +/*-------------------------------------------------------------------------- + * Wait for the given condition variable to be signaled. This should be + * called in a predicate loop that tests for a specific exit condition and + * otherwise sleeps, like so: + * + * ConditionVariablePrepareToSleep(cv); [optional] + * while (condition for which we are waiting is not true) + * ConditionVariableSleep(cv, wait_event_info); + * ConditionVariableCancelSleep(); + * + * Supply a value from one of the WaitEventXXX enums defined in pgstat.h to + * control the contents of pg_stat_activity's wait_event_type and wait_event + * columns while waiting. + *-------------------------------------------------------------------------*/ +void +ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info) +{ + WaitEvent event; + bool done = false; + + /* + * If the caller didn't prepare to sleep explicitly, then do so now and + * return immediately. The caller's predicate loop should immediately + * call again if its exit condition is not yet met. This initial spurious + * return can be avoided by calling ConditionVariablePrepareToSleep(cv) + * first. Whether it's worth doing that depends on whether you expect the + * condition to be met initially, in which case skipping the prepare + * allows you to skip manipulation of the wait list, or not met initially, + * in which case preparing first allows you to skip a spurious test of the + * caller's exit condition. + */ + if (cv_sleep_target == NULL) + { + ConditionVariablePrepareToSleep(cv); + return; + } + + /* Any earlier condition variable sleep must have been canceled. */ + Assert(cv_sleep_target == cv); + + while (!done) + { + CHECK_FOR_INTERRUPTS(); + + /* + * Wait for latch to be set. We don't care about the result because + * our contract permits spurious returns. + */ + WaitEventSetWait(cv_wait_event_set, -1, &event, 1, wait_event_info); + + /* Reset latch before testing whether we can return. */ + ResetLatch(&MyProc->procLatch); + + /* + * If this process has been taken out of the wait list, then we know + * that is has been signaled by ConditionVariableSignal. We put it + * back into the wait list, so we don't miss any further signals while + * the caller's loop checks its condition. If it hasn't been taken + * out of the wait list, then the latch must have been set by + * something other than ConditionVariableSignal; though we don't + * guarantee not to return spuriously, we'll avoid these obvious + * cases. + */ + SpinLockAcquire(&cv->mutex); + if (!proclist_contains(&cv->wakeup, MyProc->pgprocno, cvWaitLink)) + { + done = true; + proclist_push_tail(&cv->wakeup, MyProc->pgprocno, cvWaitLink); + } + SpinLockRelease(&cv->mutex); + } +} + +/* + * Cancel any pending sleep operation. We just need to remove ourselves + * from the wait queue of any condition variable for which we have previously + * prepared a sleep. + */ +void +ConditionVariableCancelSleep(void) +{ + ConditionVariable *cv = cv_sleep_target; + + if (cv == NULL) + return; + + SpinLockAcquire(&cv->mutex); + if (proclist_contains(&cv->wakeup, MyProc->pgprocno, cvWaitLink)) + proclist_delete(&cv->wakeup, MyProc->pgprocno, cvWaitLink); + SpinLockRelease(&cv->mutex); + + cv_sleep_target = NULL; +} + +/* + * Wake up one sleeping process, assuming there is at least one. + * + * The return value indicates whether or not we woke somebody up. + */ +bool +ConditionVariableSignal(ConditionVariable *cv) +{ + PGPROC *proc = NULL; + + /* Remove the first process from the wakeup queue (if any). */ + SpinLockAcquire(&cv->mutex); + if (!proclist_is_empty(&cv->wakeup)) + proc = proclist_pop_head_node(&cv->wakeup, cvWaitLink); + SpinLockRelease(&cv->mutex); + + /* If we found someone sleeping, set their latch to wake them up. */ + if (proc != NULL) + { + SetLatch(&proc->procLatch); + return true; + } + + /* No sleeping processes. */ + return false; +} + +/* + * Wake up all sleeping processes. + * + * The return value indicates the number of processes we woke. + */ +int +ConditionVariableBroadcast(ConditionVariable *cv) +{ + int nwoken = 0; + + /* + * Let's just do this the dumbest way possible. We could try to dequeue + * all the sleepers at once to save spinlock cycles, but it's a bit hard + * to get that right in the face of possible sleep cancelations, and + * we don't want to loop holding the mutex. + */ + while (ConditionVariableSignal(cv)) + ++nwoken; + + return nwoken; +} diff --git a/src/backend/storage/lmgr/deadlock.c b/src/backend/storage/lmgr/deadlock.c index 3f3e24fda2..de67e5db49 100644 --- a/src/backend/storage/lmgr/deadlock.c +++ b/src/backend/storage/lmgr/deadlock.c @@ -7,7 +7,7 @@ * detection and resolution algorithms. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/lmgr/generate-lwlocknames.pl b/src/backend/storage/lmgr/generate-lwlocknames.pl index f79d17ca70..f80d2c8121 100644 --- a/src/backend/storage/lmgr/generate-lwlocknames.pl +++ b/src/backend/storage/lmgr/generate-lwlocknames.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl # # Generate lwlocknames.h and lwlocknames.c from lwlocknames.txt -# Copyright (c) 2000-2016, PostgreSQL Global Development Group +# Copyright (c) 2000-2017, PostgreSQL Global Development Group use warnings; use strict; diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c index 7b08555b07..fe9889894b 100644 --- a/src/backend/storage/lmgr/lmgr.c +++ b/src/backend/storage/lmgr/lmgr.c @@ -3,7 +3,7 @@ * lmgr.c * POSTGRES lock manager code * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -33,7 +33,7 @@ * constraint violations. It's theoretically possible that a backend sees a * tuple that was speculatively inserted by another backend, but before it has * started waiting on the token, the other backend completes its insertion, - * and then then performs 2^32 unrelated insertions. And after all that, the + * and then performs 2^32 unrelated insertions. And after all that, the * first backend finally calls SpeculativeInsertionLockAcquire(), with the * intention of waiting for the first insertion to complete, but ends up * waiting for the latest unrelated insertion instead. Even then, nothing @@ -268,8 +268,8 @@ UnlockRelation(Relation relation, LOCKMODE lockmode) /* * LockHasWaitersRelation * - * This is a functiion to check if someone else is waiting on a - * lock, we are currently holding. + * This is a function to check whether someone else is waiting for a + * lock which we are currently holding. */ bool LockHasWaitersRelation(Relation relation, LOCKMODE lockmode) diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index dba3809e74..e9703f1866 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -3,7 +3,7 @@ * lock.c * POSTGRES primary lock mechanism * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -1676,7 +1676,6 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner) set_ps_display(new_status, false); new_status[len] = '\0'; /* truncate off " waiting" */ } - pgstat_report_wait_start(WAIT_LOCK, locallock->tag.lock.locktag_type); awaitedLock = locallock; awaitedOwner = owner; @@ -1724,7 +1723,6 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner) /* In this path, awaitedLock remains set until LockErrorCleanup */ /* Report change to non-waiting status */ - pgstat_report_wait_end(); if (update_process_title) { set_ps_display(new_status, false); @@ -1739,7 +1737,6 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner) awaitedLock = NULL; /* Report change to non-waiting status */ - pgstat_report_wait_end(); if (update_process_title) { set_ps_display(new_status, false); diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c index 7ffa87d914..c196bb8205 100644 --- a/src/backend/storage/lmgr/lwlock.c +++ b/src/backend/storage/lmgr/lwlock.c @@ -20,7 +20,7 @@ * appropriate value for a free lock. The meaning of the variable is up to * the caller, the lightweight lock code just assigns and compares it. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -84,6 +84,7 @@ #include "storage/ipc.h" #include "storage/predicate.h" #include "storage/proc.h" +#include "storage/proclist.h" #include "storage/spin.h" #include "utils/memutils.h" @@ -107,18 +108,14 @@ extern slock_t *ShmemLock; #define LW_SHARED_MASK ((uint32) ((1 << 24)-1)) /* - * This is indexed by tranche ID and stores metadata for all tranches known + * This is indexed by tranche ID and stores the names of all tranches known * to the current backend. */ -static LWLockTranche **LWLockTrancheArray = NULL; +static char **LWLockTrancheArray = NULL; static int LWLockTranchesAllocated = 0; #define T_NAME(lock) \ - (LWLockTrancheArray[(lock)->tranche]->name) -#define T_ID(lock) \ - ((int) ((((char *) lock) - \ - ((char *) LWLockTrancheArray[(lock)->tranche]->array_base)) / \ - LWLockTrancheArray[(lock)->tranche]->array_stride)) + (LWLockTrancheArray[(lock)->tranche]) /* * This points to the main array of LWLocks in shared memory. Backends inherit @@ -126,10 +123,6 @@ static int LWLockTranchesAllocated = 0; * where we have special measures to pass it down). */ LWLockPadded *MainLWLockArray = NULL; -static LWLockTranche MainLWLockTranche; -static LWLockTranche BufMappingLWLockTranche; -static LWLockTranche LockManagerLWLockTranche; -static LWLockTranche PredicateLockManagerLWLockTranche; /* * We use this structure to keep track of locked LWLocks for release @@ -174,7 +167,7 @@ static inline void LWLockReportWaitEnd(void); typedef struct lwlock_stats_key { int tranche; - int instance; + void *instance; } lwlock_stats_key; typedef struct lwlock_stats @@ -201,32 +194,18 @@ PRINT_LWDEBUG(const char *where, LWLock *lock, LWLockMode mode) if (Trace_lwlocks) { uint32 state = pg_atomic_read_u32(&lock->state); - int id = T_ID(lock); - - if (lock->tranche == 0 && id < NUM_INDIVIDUAL_LWLOCKS) - ereport(LOG, - (errhidestmt(true), - errhidecontext(true), - errmsg_internal("%d: %s(%s): excl %u shared %u haswaiters %u waiters %u rOK %d", - MyProcPid, - where, MainLWLockNames[id], - (state & LW_VAL_EXCLUSIVE) != 0, - state & LW_SHARED_MASK, - (state & LW_FLAG_HAS_WAITERS) != 0, - pg_atomic_read_u32(&lock->nwaiters), - (state & LW_FLAG_RELEASE_OK) != 0))); - else - ereport(LOG, - (errhidestmt(true), - errhidecontext(true), - errmsg_internal("%d: %s(%s %d): excl %u shared %u haswaiters %u waiters %u rOK %d", - MyProcPid, - where, T_NAME(lock), id, - (state & LW_VAL_EXCLUSIVE) != 0, - state & LW_SHARED_MASK, - (state & LW_FLAG_HAS_WAITERS) != 0, - pg_atomic_read_u32(&lock->nwaiters), - (state & LW_FLAG_RELEASE_OK) != 0))); + + ereport(LOG, + (errhidestmt(true), + errhidecontext(true), + errmsg_internal("%d: %s(%s %p): excl %u shared %u haswaiters %u waiters %u rOK %d", + MyProcPid, + where, T_NAME(lock), lock, + (state & LW_VAL_EXCLUSIVE) != 0, + state & LW_SHARED_MASK, + (state & LW_FLAG_HAS_WAITERS) != 0, + pg_atomic_read_u32(&lock->nwaiters), + (state & LW_FLAG_RELEASE_OK) != 0))); } } @@ -236,20 +215,11 @@ LOG_LWDEBUG(const char *where, LWLock *lock, const char *msg) /* hide statement & context here, otherwise the log is just too verbose */ if (Trace_lwlocks) { - int id = T_ID(lock); - - if (lock->tranche == 0 && id < NUM_INDIVIDUAL_LWLOCKS) - ereport(LOG, - (errhidestmt(true), - errhidecontext(true), - errmsg_internal("%s(%s): %s", where, - MainLWLockNames[id], msg))); - else - ereport(LOG, - (errhidestmt(true), - errhidecontext(true), - errmsg_internal("%s(%s %d): %s", where, - T_NAME(lock), id, msg))); + ereport(LOG, + (errhidestmt(true), + errhidecontext(true), + errmsg_internal("%s(%s %p): %s", where, + T_NAME(lock), lock, msg))); } } @@ -284,9 +254,7 @@ init_lwlock_stats(void) */ lwlock_stats_cxt = AllocSetContextCreate(TopMemoryContext, "LWLock stats", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); MemoryContextAllowInCriticalSection(lwlock_stats_cxt, true); MemSet(&ctl, 0, sizeof(ctl)); @@ -316,8 +284,8 @@ print_lwlock_stats(int code, Datum arg) while ((lwstats = (lwlock_stats *) hash_seq_search(&scan)) != NULL) { fprintf(stderr, - "PID %d lwlock %s %d: shacq %u exacq %u blk %u spindelay %u dequeue self %u\n", - MyProcPid, LWLockTrancheArray[lwstats->key.tranche]->name, + "PID %d lwlock %s %p: shacq %u exacq %u blk %u spindelay %u dequeue self %u\n", + MyProcPid, LWLockTrancheArray[lwstats->key.tranche], lwstats->key.instance, lwstats->sh_acquire_count, lwstats->ex_acquire_count, lwstats->block_count, lwstats->spin_delay_count, lwstats->dequeue_self_count); @@ -343,7 +311,7 @@ get_lwlock_stats_entry(LWLock *lock) /* Fetch or create the entry. */ key.tranche = lock->tranche; - key.instance = T_ID(lock); + key.instance = lock; lwstats = hash_search(lwlock_stats_htab, &key, HASH_ENTER, &found); if (!found) { @@ -465,7 +433,7 @@ InitializeLWLocks(void) /* Initialize all individual LWLocks in main array */ for (id = 0, lock = MainLWLockArray; id < NUM_INDIVIDUAL_LWLOCKS; id++, lock++) - LWLockInitialize(&lock->lock, LWTRANCHE_MAIN); + LWLockInitialize(&lock->lock, id); /* Initialize buffer mapping LWLocks in main array */ lock = MainLWLockArray + NUM_INDIVIDUAL_LWLOCKS; @@ -507,10 +475,8 @@ InitializeLWLocks(void) name = trancheNames; trancheNames += strlen(request->tranche_name) + 1; strcpy(name, request->tranche_name); - tranche->lwLockTranche.name = name; tranche->trancheId = LWLockNewTrancheId(); - tranche->lwLockTranche.array_base = lock; - tranche->lwLockTranche.array_stride = sizeof(LWLockPadded); + tranche->trancheName = name; for (j = 0; j < request->num_lwlocks; j++, lock++) LWLockInitialize(&lock->lock, tranche->trancheId); @@ -528,39 +494,27 @@ RegisterLWLockTranches(void) if (LWLockTrancheArray == NULL) { - LWLockTranchesAllocated = 32; - LWLockTrancheArray = (LWLockTranche **) + LWLockTranchesAllocated = 64; + LWLockTrancheArray = (char **) MemoryContextAllocZero(TopMemoryContext, - LWLockTranchesAllocated * sizeof(LWLockTranche *)); + LWLockTranchesAllocated * sizeof(char *)); Assert(LWLockTranchesAllocated >= LWTRANCHE_FIRST_USER_DEFINED); } - MainLWLockTranche.name = "main"; - MainLWLockTranche.array_base = MainLWLockArray; - MainLWLockTranche.array_stride = sizeof(LWLockPadded); - LWLockRegisterTranche(LWTRANCHE_MAIN, &MainLWLockTranche); - - BufMappingLWLockTranche.name = "buffer_mapping"; - BufMappingLWLockTranche.array_base = MainLWLockArray + NUM_INDIVIDUAL_LWLOCKS; - BufMappingLWLockTranche.array_stride = sizeof(LWLockPadded); - LWLockRegisterTranche(LWTRANCHE_BUFFER_MAPPING, &BufMappingLWLockTranche); + for (i = 0; i < NUM_INDIVIDUAL_LWLOCKS; ++i) + LWLockRegisterTranche(i, MainLWLockNames[i]); - LockManagerLWLockTranche.name = "lock_manager"; - LockManagerLWLockTranche.array_base = MainLWLockArray + NUM_INDIVIDUAL_LWLOCKS + - NUM_BUFFER_PARTITIONS; - LockManagerLWLockTranche.array_stride = sizeof(LWLockPadded); - LWLockRegisterTranche(LWTRANCHE_LOCK_MANAGER, &LockManagerLWLockTranche); - - PredicateLockManagerLWLockTranche.name = "predicate_lock_manager"; - PredicateLockManagerLWLockTranche.array_base = MainLWLockArray + NUM_INDIVIDUAL_LWLOCKS + - NUM_BUFFER_PARTITIONS + NUM_LOCK_PARTITIONS; - PredicateLockManagerLWLockTranche.array_stride = sizeof(LWLockPadded); - LWLockRegisterTranche(LWTRANCHE_PREDICATE_LOCK_MANAGER, &PredicateLockManagerLWLockTranche); + LWLockRegisterTranche(LWTRANCHE_BUFFER_MAPPING, "buffer_mapping"); + LWLockRegisterTranche(LWTRANCHE_LOCK_MANAGER, "lock_manager"); + LWLockRegisterTranche(LWTRANCHE_PREDICATE_LOCK_MANAGER, + "predicate_lock_manager"); + LWLockRegisterTranche(LWTRANCHE_PARALLEL_QUERY_DSA, + "parallel_query_dsa"); /* Register named tranches. */ for (i = 0; i < NamedLWLockTrancheRequests; i++) LWLockRegisterTranche(NamedLWLockTrancheArray[i].trancheId, - &NamedLWLockTrancheArray[i].lwLockTranche); + NamedLWLockTrancheArray[i].trancheName); } /* @@ -629,12 +583,12 @@ LWLockNewTrancheId(void) /* * Register a tranche ID in the lookup table for the current process. This - * routine will save a pointer to the tranche object passed as an argument, - * so that object should be allocated in a backend-lifetime context + * routine will save a pointer to the tranche name passed as an argument, + * so the name should be allocated in a backend-lifetime context * (TopMemoryContext, static variable, or similar). */ void -LWLockRegisterTranche(int tranche_id, LWLockTranche *tranche) +LWLockRegisterTranche(int tranche_id, char *tranche_name) { Assert(LWLockTrancheArray != NULL); @@ -646,15 +600,14 @@ LWLockRegisterTranche(int tranche_id, LWLockTranche *tranche) while (i <= tranche_id) i *= 2; - LWLockTrancheArray = (LWLockTranche **) - repalloc(LWLockTrancheArray, - i * sizeof(LWLockTranche *)); + LWLockTrancheArray = (char **) + repalloc(LWLockTrancheArray, i * sizeof(char *)); LWLockTranchesAllocated = i; while (j < LWLockTranchesAllocated) LWLockTrancheArray[j++] = NULL; } - LWLockTrancheArray[tranche_id] = tranche; + LWLockTrancheArray[tranche_id] = tranche_name; } /* @@ -717,7 +670,7 @@ LWLockInitialize(LWLock *lock, int tranche_id) pg_atomic_init_u32(&lock->nwaiters, 0); #endif lock->tranche = tranche_id; - dlist_init(&lock->waiters); + proclist_init(&lock->waiters); } /* @@ -730,12 +683,7 @@ LWLockInitialize(LWLock *lock, int tranche_id) static inline void LWLockReportWaitStart(LWLock *lock) { - int lockId = T_ID(lock); - - if (lock->tranche == 0) - pgstat_report_wait_start(WAIT_LWLOCK_NAMED, (uint16) lockId); - else - pgstat_report_wait_start(WAIT_LWLOCK_TRANCHE, lock->tranche); + pgstat_report_wait_start(PG_WAIT_LWLOCK | lock->tranche); } /* @@ -751,12 +699,9 @@ LWLockReportWaitEnd(void) * Return an identifier for an LWLock based on the wait class and event. */ const char * -GetLWLockIdentifier(uint8 classId, uint16 eventId) +GetLWLockIdentifier(uint32 classId, uint16 eventId) { - if (classId == WAIT_LWLOCK_NAMED) - return MainLWLockNames[eventId]; - - Assert(classId == WAIT_LWLOCK_TRANCHE); + Assert(classId == PG_WAIT_LWLOCK); /* * It is quite possible that user has registered tranche in one of the @@ -764,10 +709,10 @@ GetLWLockIdentifier(uint8 classId, uint16 eventId) * all of them, so we can't assume the tranche is registered here. */ if (eventId >= LWLockTranchesAllocated || - LWLockTrancheArray[eventId]->name == NULL) + LWLockTrancheArray[eventId] == NULL) return "extension"; - return LWLockTrancheArray[eventId]->name; + return LWLockTrancheArray[eventId]; } /* @@ -920,25 +865,25 @@ LWLockWakeup(LWLock *lock) { bool new_release_ok; bool wokeup_somebody = false; - dlist_head wakeup; - dlist_mutable_iter iter; + proclist_head wakeup; + proclist_mutable_iter iter; - dlist_init(&wakeup); + proclist_init(&wakeup); new_release_ok = true; /* lock wait list while collecting backends to wake up */ LWLockWaitListLock(lock); - dlist_foreach_modify(iter, &lock->waiters) + proclist_foreach_modify(iter, &lock->waiters, lwWaitLink) { - PGPROC *waiter = dlist_container(PGPROC, lwWaitLink, iter.cur); + PGPROC *waiter = GetPGProcByNumber(iter.cur); if (wokeup_somebody && waiter->lwWaitMode == LW_EXCLUSIVE) continue; - dlist_delete(&waiter->lwWaitLink); - dlist_push_tail(&wakeup, &waiter->lwWaitLink); + proclist_delete(&lock->waiters, iter.cur, lwWaitLink); + proclist_push_tail(&wakeup, iter.cur, lwWaitLink); if (waiter->lwWaitMode != LW_WAIT_UNTIL_FREE) { @@ -963,7 +908,7 @@ LWLockWakeup(LWLock *lock) break; } - Assert(dlist_is_empty(&wakeup) || pg_atomic_read_u32(&lock->state) & LW_FLAG_HAS_WAITERS); + Assert(proclist_is_empty(&wakeup) || pg_atomic_read_u32(&lock->state) & LW_FLAG_HAS_WAITERS); /* unset required flags, and release lock, in one fell swoop */ { @@ -982,7 +927,7 @@ LWLockWakeup(LWLock *lock) else desired_state &= ~LW_FLAG_RELEASE_OK; - if (dlist_is_empty(&wakeup)) + if (proclist_is_empty(&wakeup)) desired_state &= ~LW_FLAG_HAS_WAITERS; desired_state &= ~LW_FLAG_LOCKED; /* release lock */ @@ -994,12 +939,12 @@ LWLockWakeup(LWLock *lock) } /* Awaken any waiters I removed from the queue. */ - dlist_foreach_modify(iter, &wakeup) + proclist_foreach_modify(iter, &wakeup, lwWaitLink) { - PGPROC *waiter = dlist_container(PGPROC, lwWaitLink, iter.cur); + PGPROC *waiter = GetPGProcByNumber(iter.cur); LOG_LWDEBUG("LWLockRelease", lock, "release waiter"); - dlist_delete(&waiter->lwWaitLink); + proclist_delete(&wakeup, iter.cur, lwWaitLink); /* * Guarantee that lwWaiting being unset only becomes visible once the @@ -1008,12 +953,12 @@ LWLockWakeup(LWLock *lock) * that happens before the list unlink happens, the list would end up * being corrupted. * - * The barrier pairs with the LWLockWaitListLock() when enqueing for + * The barrier pairs with the LWLockWaitListLock() when enqueueing for * another lock. */ pg_write_barrier(); waiter->lwWaiting = false; - PGSemaphoreUnlock(&waiter->sem); + PGSemaphoreUnlock(waiter->sem); } } @@ -1046,9 +991,9 @@ LWLockQueueSelf(LWLock *lock, LWLockMode mode) /* LW_WAIT_UNTIL_FREE waiters are always at the front of the queue */ if (mode == LW_WAIT_UNTIL_FREE) - dlist_push_head(&lock->waiters, &MyProc->lwWaitLink); + proclist_push_head(&lock->waiters, MyProc->pgprocno, lwWaitLink); else - dlist_push_tail(&lock->waiters, &MyProc->lwWaitLink); + proclist_push_tail(&lock->waiters, MyProc->pgprocno, lwWaitLink); /* Can release the mutex now */ LWLockWaitListUnlock(lock); @@ -1070,7 +1015,7 @@ static void LWLockDequeueSelf(LWLock *lock) { bool found = false; - dlist_mutable_iter iter; + proclist_mutable_iter iter; #ifdef LWLOCK_STATS lwlock_stats *lwstats; @@ -1086,19 +1031,17 @@ LWLockDequeueSelf(LWLock *lock) * Can't just remove ourselves from the list, but we need to iterate over * all entries as somebody else could have unqueued us. */ - dlist_foreach_modify(iter, &lock->waiters) + proclist_foreach_modify(iter, &lock->waiters, lwWaitLink) { - PGPROC *proc = dlist_container(PGPROC, lwWaitLink, iter.cur); - - if (proc == MyProc) + if (iter.cur == MyProc->pgprocno) { found = true; - dlist_delete(&proc->lwWaitLink); + proclist_delete(&lock->waiters, iter.cur, lwWaitLink); break; } } - if (dlist_is_empty(&lock->waiters) && + if (proclist_is_empty(&lock->waiters) && (pg_atomic_read_u32(&lock->state) & LW_FLAG_HAS_WAITERS) != 0) { pg_atomic_fetch_and_u32(&lock->state, ~LW_FLAG_HAS_WAITERS); @@ -1132,7 +1075,7 @@ LWLockDequeueSelf(LWLock *lock) */ for (;;) { - PGSemaphoreLock(&MyProc->sem); + PGSemaphoreLock(MyProc->sem); if (!MyProc->lwWaiting) break; extraWaits++; @@ -1142,7 +1085,7 @@ LWLockDequeueSelf(LWLock *lock) * Fix the process wait semaphore's count for any absorbed wakeups. */ while (extraWaits-- > 0) - PGSemaphoreUnlock(&MyProc->sem); + PGSemaphoreUnlock(MyProc->sem); } #ifdef LOCK_DEBUG @@ -1244,7 +1187,7 @@ LWLockAcquire(LWLock *lock, LWLockMode mode) * Instead add us to the queue and try to grab the lock again. If we * succeed we need to revert the queuing and be happy, otherwise we * recheck the lock. If we still couldn't grab it, we know that the - * other lock will see our queue entries when releasing since they + * other locker will see our queue entries when releasing since they * existed before we checked for the lock. */ @@ -1282,11 +1225,11 @@ LWLockAcquire(LWLock *lock, LWLockMode mode) #endif LWLockReportWaitStart(lock); - TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), T_ID(lock), mode); + TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), mode); for (;;) { - PGSemaphoreLock(&proc->sem); + PGSemaphoreLock(proc->sem); if (!proc->lwWaiting) break; extraWaits++; @@ -1304,7 +1247,7 @@ LWLockAcquire(LWLock *lock, LWLockMode mode) } #endif - TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), T_ID(lock), mode); + TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), mode); LWLockReportWaitEnd(); LOG_LWDEBUG("LWLockAcquire", lock, "awakened"); @@ -1313,7 +1256,7 @@ LWLockAcquire(LWLock *lock, LWLockMode mode) result = false; } - TRACE_POSTGRESQL_LWLOCK_ACQUIRE(T_NAME(lock), T_ID(lock), mode); + TRACE_POSTGRESQL_LWLOCK_ACQUIRE(T_NAME(lock), mode); /* Add lock to list of locks held by this backend */ held_lwlocks[num_held_lwlocks].lock = lock; @@ -1323,7 +1266,7 @@ LWLockAcquire(LWLock *lock, LWLockMode mode) * Fix the process wait semaphore's count for any absorbed wakeups. */ while (extraWaits-- > 0) - PGSemaphoreUnlock(&proc->sem); + PGSemaphoreUnlock(proc->sem); return result; } @@ -1364,14 +1307,14 @@ LWLockConditionalAcquire(LWLock *lock, LWLockMode mode) RESUME_INTERRUPTS(); LOG_LWDEBUG("LWLockConditionalAcquire", lock, "failed"); - TRACE_POSTGRESQL_LWLOCK_CONDACQUIRE_FAIL(T_NAME(lock), T_ID(lock), mode); + TRACE_POSTGRESQL_LWLOCK_CONDACQUIRE_FAIL(T_NAME(lock), mode); } else { /* Add lock to list of locks held by this backend */ held_lwlocks[num_held_lwlocks].lock = lock; held_lwlocks[num_held_lwlocks++].mode = mode; - TRACE_POSTGRESQL_LWLOCK_CONDACQUIRE(T_NAME(lock), T_ID(lock), mode); + TRACE_POSTGRESQL_LWLOCK_CONDACQUIRE(T_NAME(lock), mode); } return !mustwait; } @@ -1443,11 +1386,11 @@ LWLockAcquireOrWait(LWLock *lock, LWLockMode mode) #endif LWLockReportWaitStart(lock); - TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), T_ID(lock), mode); + TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), mode); for (;;) { - PGSemaphoreLock(&proc->sem); + PGSemaphoreLock(proc->sem); if (!proc->lwWaiting) break; extraWaits++; @@ -1461,7 +1404,7 @@ LWLockAcquireOrWait(LWLock *lock, LWLockMode mode) Assert(nwaiters < MAX_BACKENDS); } #endif - TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), T_ID(lock), mode); + TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), mode); LWLockReportWaitEnd(); LOG_LWDEBUG("LWLockAcquireOrWait", lock, "awakened"); @@ -1484,15 +1427,14 @@ LWLockAcquireOrWait(LWLock *lock, LWLockMode mode) * Fix the process wait semaphore's count for any absorbed wakeups. */ while (extraWaits-- > 0) - PGSemaphoreUnlock(&proc->sem); + PGSemaphoreUnlock(proc->sem); if (mustwait) { /* Failed to get lock, so release interrupt holdoff */ RESUME_INTERRUPTS(); LOG_LWDEBUG("LWLockAcquireOrWait", lock, "failed"); - TRACE_POSTGRESQL_LWLOCK_ACQUIRE_OR_WAIT_FAIL(T_NAME(lock), T_ID(lock), - mode); + TRACE_POSTGRESQL_LWLOCK_ACQUIRE_OR_WAIT_FAIL(T_NAME(lock), mode); } else { @@ -1500,7 +1442,7 @@ LWLockAcquireOrWait(LWLock *lock, LWLockMode mode) /* Add lock to list of locks held by this backend */ held_lwlocks[num_held_lwlocks].lock = lock; held_lwlocks[num_held_lwlocks++].mode = mode; - TRACE_POSTGRESQL_LWLOCK_ACQUIRE_OR_WAIT(T_NAME(lock), T_ID(lock), mode); + TRACE_POSTGRESQL_LWLOCK_ACQUIRE_OR_WAIT(T_NAME(lock), mode); } return !mustwait; @@ -1660,12 +1602,11 @@ LWLockWaitForVar(LWLock *lock, uint64 *valptr, uint64 oldval, uint64 *newval) #endif LWLockReportWaitStart(lock); - TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), T_ID(lock), - LW_EXCLUSIVE); + TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), LW_EXCLUSIVE); for (;;) { - PGSemaphoreLock(&proc->sem); + PGSemaphoreLock(proc->sem); if (!proc->lwWaiting) break; extraWaits++; @@ -1680,8 +1621,7 @@ LWLockWaitForVar(LWLock *lock, uint64 *valptr, uint64 oldval, uint64 *newval) } #endif - TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), T_ID(lock), - LW_EXCLUSIVE); + TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), LW_EXCLUSIVE); LWLockReportWaitEnd(); LOG_LWDEBUG("LWLockWaitForVar", lock, "awakened"); @@ -1689,13 +1629,13 @@ LWLockWaitForVar(LWLock *lock, uint64 *valptr, uint64 oldval, uint64 *newval) /* Now loop back and check the status of the lock again. */ } - TRACE_POSTGRESQL_LWLOCK_ACQUIRE(T_NAME(lock), T_ID(lock), LW_EXCLUSIVE); + TRACE_POSTGRESQL_LWLOCK_ACQUIRE(T_NAME(lock), LW_EXCLUSIVE); /* * Fix the process wait semaphore's count for any absorbed wakeups. */ while (extraWaits-- > 0) - PGSemaphoreUnlock(&proc->sem); + PGSemaphoreUnlock(proc->sem); /* * Now okay to allow cancel/die interrupts. @@ -1719,12 +1659,12 @@ LWLockWaitForVar(LWLock *lock, uint64 *valptr, uint64 oldval, uint64 *newval) void LWLockUpdateVar(LWLock *lock, uint64 *valptr, uint64 val) { - dlist_head wakeup; - dlist_mutable_iter iter; + proclist_head wakeup; + proclist_mutable_iter iter; PRINT_LWDEBUG("LWLockUpdateVar", lock, LW_EXCLUSIVE); - dlist_init(&wakeup); + proclist_init(&wakeup); LWLockWaitListLock(lock); @@ -1737,15 +1677,15 @@ LWLockUpdateVar(LWLock *lock, uint64 *valptr, uint64 val) * See if there are any LW_WAIT_UNTIL_FREE waiters that need to be woken * up. They are always in the front of the queue. */ - dlist_foreach_modify(iter, &lock->waiters) + proclist_foreach_modify(iter, &lock->waiters, lwWaitLink) { - PGPROC *waiter = dlist_container(PGPROC, lwWaitLink, iter.cur); + PGPROC *waiter = GetPGProcByNumber(iter.cur); if (waiter->lwWaitMode != LW_WAIT_UNTIL_FREE) break; - dlist_delete(&waiter->lwWaitLink); - dlist_push_tail(&wakeup, &waiter->lwWaitLink); + proclist_delete(&lock->waiters, iter.cur, lwWaitLink); + proclist_push_tail(&wakeup, iter.cur, lwWaitLink); } /* We are done updating shared state of the lock itself. */ @@ -1754,15 +1694,15 @@ LWLockUpdateVar(LWLock *lock, uint64 *valptr, uint64 val) /* * Awaken any waiters I removed from the queue. */ - dlist_foreach_modify(iter, &wakeup) + proclist_foreach_modify(iter, &wakeup, lwWaitLink) { - PGPROC *waiter = dlist_container(PGPROC, lwWaitLink, iter.cur); + PGPROC *waiter = GetPGProcByNumber(iter.cur); - dlist_delete(&waiter->lwWaitLink); + proclist_delete(&wakeup, iter.cur, lwWaitLink); /* check comment in LWLockWakeup() about this barrier */ pg_write_barrier(); waiter->lwWaiting = false; - PGSemaphoreUnlock(&waiter->sem); + PGSemaphoreUnlock(waiter->sem); } } @@ -1783,15 +1723,14 @@ LWLockRelease(LWLock *lock) * be the latest-acquired lock; so search array backwards. */ for (i = num_held_lwlocks; --i >= 0;) - { if (lock == held_lwlocks[i].lock) - { - mode = held_lwlocks[i].mode; break; - } - } + if (i < 0) - elog(ERROR, "lock %s %d is not held", T_NAME(lock), T_ID(lock)); + elog(ERROR, "lock %s is not held", T_NAME(lock)); + + mode = held_lwlocks[i].mode; + num_held_lwlocks--; for (; i < num_held_lwlocks; i++) held_lwlocks[i] = held_lwlocks[i + 1]; @@ -1833,7 +1772,7 @@ LWLockRelease(LWLock *lock) LWLockWakeup(lock); } - TRACE_POSTGRESQL_LWLOCK_RELEASE(T_NAME(lock), T_ID(lock)); + TRACE_POSTGRESQL_LWLOCK_RELEASE(T_NAME(lock)); /* * Now okay to allow cancel/die interrupts. @@ -1883,10 +1822,9 @@ LWLockReleaseAll(void) /* - * LWLockHeldByMe - test whether my process currently holds a lock + * LWLockHeldByMe - test whether my process holds a lock in any mode * - * This is meant as debug support only. We currently do not distinguish - * whether the lock is held shared or exclusive. + * This is meant as debug support only. */ bool LWLockHeldByMe(LWLock *l) @@ -1900,3 +1838,21 @@ LWLockHeldByMe(LWLock *l) } return false; } + +/* + * LWLockHeldByMeInMode - test whether my process holds a lock in given mode + * + * This is meant as debug support only. + */ +bool +LWLockHeldByMeInMode(LWLock *l, LWLockMode mode) +{ + int i; + + for (i = 0; i < num_held_lwlocks; i++) + { + if (held_lwlocks[i].lock == l && held_lwlocks[i].mode == mode) + return true; + } + return false; +} diff --git a/src/backend/storage/lmgr/lwlocknames.txt b/src/backend/storage/lmgr/lwlocknames.txt index f8996cd21a..c95ca5b2e1 100644 --- a/src/backend/storage/lmgr/lwlocknames.txt +++ b/src/backend/storage/lmgr/lwlocknames.txt @@ -47,3 +47,6 @@ CommitTsLock 39 ReplicationOriginLock 40 MultiXactTruncationLock 41 OldSnapshotTimeMapLock 42 +BackendRandomLock 43 +LogicalRepLauncherLock 44 +LogicalRepWorkerLock 45 diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c index 7cdb35541b..9183764ca7 100644 --- a/src/backend/storage/lmgr/predicate.c +++ b/src/backend/storage/lmgr/predicate.c @@ -125,7 +125,7 @@ * - Protects both PredXact and SerializableXidHash. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -192,6 +192,7 @@ #include "access/xact.h" #include "access/xlog.h" #include "miscadmin.h" +#include "pgstat.h" #include "storage/bufmgr.h" #include "storage/predicate.h" #include "storage/predicate_internals.h" @@ -1184,12 +1185,6 @@ InitPredicateLocks(void) requestSize = mul_size((Size) max_table_size, PredXactListElementDataSize); PredXact->element = ShmemAlloc(requestSize); - if (PredXact->element == NULL) - ereport(ERROR, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("not enough shared memory for elements of data structure" - " \"%s\" (%zu bytes requested)", - "PredXactList", requestSize))); /* Add all elements to available list, clean. */ memset(PredXact->element, 0, requestSize); for (i = 0; i < max_table_size; i++) @@ -1255,12 +1250,6 @@ InitPredicateLocks(void) requestSize = mul_size((Size) max_table_size, RWConflictDataSize); RWConflictPool->element = ShmemAlloc(requestSize); - if (RWConflictPool->element == NULL) - ereport(ERROR, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("not enough shared memory for elements of data structure" - " \"%s\" (%zu bytes requested)", - "RWConflictPool", requestSize))); /* Add all elements to available list, clean. */ memset(RWConflictPool->element, 0, requestSize); for (i = 0; i < max_table_size; i++) @@ -1530,7 +1519,7 @@ GetSafeSnapshot(Snapshot origSnapshot) SxactIsROUnsafe(MySerializableXact))) { LWLockRelease(SerializableXactHashLock); - ProcWaitForSignal(); + ProcWaitForSignal(WAIT_EVENT_SAFE_SNAPSHOT); LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE); } MySerializableXact->flags &= ~SXACT_FLAG_DEFERRABLE_WAITING; diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 9a758bd916..1b836f7c0a 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -3,7 +3,7 @@ * proc.c * routines to manage per-process shared memory data structure * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -39,9 +39,11 @@ #include "access/twophase.h" #include "access/xact.h" #include "miscadmin.h" +#include "pgstat.h" #include "postmaster/autovacuum.h" #include "replication/slot.h" #include "replication/syncrep.h" +#include "storage/condition_variable.h" #include "storage/standby.h" #include "storage/ipc.h" #include "storage/lmgr.h" @@ -194,14 +196,10 @@ InitProcGlobal(void) * between groups. */ procs = (PGPROC *) ShmemAlloc(TotalProcs * sizeof(PGPROC)); + MemSet(procs, 0, TotalProcs * sizeof(PGPROC)); ProcGlobal->allProcs = procs; /* XXX allProcCount isn't really all of them; it excludes prepared xacts */ ProcGlobal->allProcCount = MaxBackends + NUM_AUXILIARY_PROCS; - if (!procs) - ereport(FATAL, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of shared memory"))); - MemSet(procs, 0, TotalProcs * sizeof(PGPROC)); /* * Also allocate a separate array of PGXACT structures. This is separate @@ -226,7 +224,7 @@ InitProcGlobal(void) */ if (i < MaxBackends + NUM_AUXILIARY_PROCS) { - PGSemaphoreCreate(&(procs[i].sem)); + procs[i].sem = PGSemaphoreCreate(); InitSharedLatch(&(procs[i].procLatch)); LWLockInitialize(&(procs[i].backendLock), LWTRANCHE_PROC); } @@ -422,7 +420,7 @@ InitProcess(void) * be careful and reinitialize its value here. (This is not strictly * necessary anymore, but seems like a good idea for cleanliness.) */ - PGSemaphoreReset(&MyProc->sem); + PGSemaphoreReset(MyProc->sem); /* * Arrange to clean up at backend exit. @@ -577,7 +575,7 @@ InitAuxiliaryProcess(void) * be careful and reinitialize its value here. (This is not strictly * necessary anymore, but seems like a good idea for cleanliness.) */ - PGSemaphoreReset(&MyProc->sem); + PGSemaphoreReset(MyProc->sem); /* * Arrange to clean up at process exit. @@ -805,10 +803,16 @@ ProcKill(int code, Datum arg) */ LWLockReleaseAll(); + /* Cancel any pending condition variable sleep, too */ + ConditionVariableCancelSleep(); + /* Make sure active replication slots are released */ if (MyReplicationSlot != NULL) ReplicationSlotRelease(); + /* Also cleanup all the temporary slots. */ + ReplicationSlotCleanup(); + /* * Detach from any lock group of which we are a member. If the leader * exist before all other group members, it's PGPROC will remain allocated @@ -910,6 +914,9 @@ AuxiliaryProcKill(int code, Datum arg) /* Release any LW locks I am holding (see notes above) */ LWLockReleaseAll(); + /* Cancel any pending condition variable sleep, too */ + ConditionVariableCancelSleep(); + /* * Reset MyLatch to the process local one. This is so that signal * handlers et al can continue using the latch after the shared latch @@ -1216,7 +1223,8 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable) } else { - WaitLatch(MyLatch, WL_LATCH_SET, 0); + WaitLatch(MyLatch, WL_LATCH_SET, 0, + PG_WAIT_LOCK | locallock->tag.lock.locktag_type); ResetLatch(MyLatch); /* check for deadlocks first, as that's probably log-worthy */ if (got_deadlock_timeout) @@ -1726,9 +1734,9 @@ CheckDeadLockAlert(void) * wait again if not. */ void -ProcWaitForSignal(void) +ProcWaitForSignal(uint32 wait_event_info) { - WaitLatch(MyLatch, WL_LATCH_SET, 0); + WaitLatch(MyLatch, WL_LATCH_SET, 0, wait_event_info); ResetLatch(MyLatch); CHECK_FOR_INTERRUPTS(); } diff --git a/src/backend/storage/lmgr/s_lock.c b/src/backend/storage/lmgr/s_lock.c index 599940cbd2..ac82e704fa 100644 --- a/src/backend/storage/lmgr/s_lock.c +++ b/src/backend/storage/lmgr/s_lock.c @@ -36,7 +36,7 @@ * the probability of unintended failure) than to fix the total time * spent. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -51,7 +51,7 @@ #include #include "storage/s_lock.h" -#include "storage/barrier.h" +#include "port/atomics.h" #define MIN_SPINS_PER_DELAY 10 diff --git a/src/backend/storage/lmgr/spin.c b/src/backend/storage/lmgr/spin.c index 5039141430..f7b1ac04f9 100644 --- a/src/backend/storage/lmgr/spin.c +++ b/src/backend/storage/lmgr/spin.c @@ -11,7 +11,7 @@ * is too slow to be very useful :-( * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -23,11 +23,12 @@ #include "postgres.h" #include "storage/pg_sema.h" +#include "storage/shmem.h" #include "storage/spin.h" #ifndef HAVE_SPINLOCKS -PGSemaphore SpinlockSemaArray; +PGSemaphore *SpinlockSemaArray; #endif /* @@ -37,7 +38,7 @@ PGSemaphore SpinlockSemaArray; Size SpinlockSemaSize(void) { - return SpinlockSemas() * sizeof(PGSemaphoreData); + return SpinlockSemas() * sizeof(PGSemaphore); } #ifdef HAVE_SPINLOCKS @@ -67,16 +68,24 @@ SpinlockSemas(void) } /* - * Initialize semaphores. + * Initialize spinlock emulation. + * + * This must be called after PGReserveSemaphores(). */ -extern void -SpinlockSemaInit(PGSemaphore spinsemas) +void +SpinlockSemaInit(void) { - int i; + PGSemaphore *spinsemas; int nsemas = SpinlockSemas(); + int i; + /* + * We must use ShmemAllocUnlocked(), since the spinlock protecting + * ShmemAlloc() obviously can't be ready yet. + */ + spinsemas = (PGSemaphore *) ShmemAllocUnlocked(SpinlockSemaSize()); for (i = 0; i < nsemas; ++i) - PGSemaphoreCreate(&spinsemas[i]); + spinsemas[i] = PGSemaphoreCreate(); SpinlockSemaArray = spinsemas; } @@ -109,7 +118,7 @@ s_unlock_sema(volatile slock_t *lock) if (lockndx <= 0 || lockndx > NUM_SPINLOCK_SEMAPHORES) elog(ERROR, "invalid spinlock number: %d", lockndx); - PGSemaphoreUnlock(&SpinlockSemaArray[lockndx - 1]); + PGSemaphoreUnlock(SpinlockSemaArray[lockndx - 1]); } bool @@ -128,7 +137,7 @@ tas_sema(volatile slock_t *lock) if (lockndx <= 0 || lockndx > NUM_SPINLOCK_SEMAPHORES) elog(ERROR, "invalid spinlock number: %d", lockndx); /* Note that TAS macros return 0 if *success* */ - return !PGSemaphoreTryLock(&SpinlockSemaArray[lockndx - 1]); + return !PGSemaphoreTryLock(SpinlockSemaArray[lockndx - 1]); } #endif /* !HAVE_SPINLOCKS */ diff --git a/src/backend/storage/page/bufpage.c b/src/backend/storage/page/bufpage.c index f2a07f2111..6fc5fa4d05 100644 --- a/src/backend/storage/page/bufpage.c +++ b/src/backend/storage/page/bufpage.c @@ -3,7 +3,7 @@ * bufpage.c * POSTGRES standard buffer page code. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -81,7 +81,7 @@ bool PageIsVerified(Page page, BlockNumber blkno) { PageHeader p = (PageHeader) page; - char *pagebytes; + size_t *pagebytes; int i; bool checksum_failure = false; bool header_sane = false; @@ -118,10 +118,17 @@ PageIsVerified(Page page, BlockNumber blkno) return true; } - /* Check all-zeroes case */ + /* + * Check all-zeroes case. Luckily BLCKSZ is guaranteed to always be a + * multiple of size_t - and it's much faster to compare memory using the + * native word size. + */ + StaticAssertStmt(BLCKSZ == (BLCKSZ / sizeof(size_t)) * sizeof(size_t), + "BLCKSZ has to be a multiple of sizeof(size_t)"); + all_zeroes = true; - pagebytes = (char *) page; - for (i = 0; i < BLCKSZ; i++) + pagebytes = (size_t *) page; + for (i = 0; i < (BLCKSZ / sizeof(size_t)); i++) { if (pagebytes[i] != 0) { @@ -159,21 +166,24 @@ PageIsVerified(Page page, BlockNumber blkno) * inserted, or InvalidOffsetNumber if the item is not inserted for any * reason. A WARNING is issued indicating the reason for the refusal. * - * If flag PAI_OVERWRITE is set, we just store the item at the specified - * offsetNumber (which must be either a currently-unused item pointer, - * or one past the last existing item). Otherwise, - * if offsetNumber is valid and <= current max offset in the page, - * insert item into the array at that position by shuffling ItemId's - * down to make room. - * If offsetNumber is not valid, then assign one by finding the first + * offsetNumber must be either InvalidOffsetNumber to specify finding a + * free item pointer, or a value between FirstOffsetNumber and one past + * the last existing item, to specify using that particular item pointer. + * + * If offsetNumber is valid and flag PAI_OVERWRITE is set, we just store + * the item at the specified offsetNumber, which must be either a + * currently-unused item pointer, or one past the last existing item. + * + * If offsetNumber is valid and flag PAI_OVERWRITE is not set, insert + * the item at the specified offsetNumber, moving existing items later + * in the array to make room. + * + * If offsetNumber is not valid, then assign a slot by finding the first * one that is both unused and deallocated. * * If flag PAI_IS_HEAP is set, we enforce that there can't be more than * MaxHeapTuplesPerPage line pointers on the page. * - * If flag PAI_ALLOW_FAR_OFFSET is not set, we disallow placing items - * beyond one past the last existing item. - * * !!! EREPORT(ERROR) IS DISALLOWED HERE !!! */ OffsetNumber @@ -260,11 +270,8 @@ PageAddItemExtended(Page page, } } - /* - * Reject placing items beyond the first unused line pointer, unless - * caller asked for that behavior specifically. - */ - if ((flags & PAI_ALLOW_FAR_OFFSET) == 0 && offsetNumber > limit) + /* Reject placing items beyond the first unused line pointer */ + if (offsetNumber > limit) { elog(WARNING, "specified item offset is too large"); return InvalidOffsetNumber; @@ -283,10 +290,7 @@ PageAddItemExtended(Page page, * Note: do arithmetic as signed ints, to avoid mistakes if, say, * alignedSize > pd_upper. */ - if ((flags & PAI_ALLOW_FAR_OFFSET) != 0) - lower = Max(phdr->pd_lower, - SizeOfPageHeaderData + sizeof(ItemIdData) * offsetNumber); - else if (offsetNumber == limit || needshuffle) + if (offsetNumber == limit || needshuffle) lower = phdr->pd_lower + sizeof(ItemIdData); else lower = phdr->pd_lower; @@ -334,26 +338,6 @@ PageAddItemExtended(Page page, return offsetNumber; } -/* - * PageAddItem - * - * Add an item to a page. Return value is offset at which it was - * inserted, or InvalidOffsetNumber if the item is not inserted for - * any reason. - * - * Passing the 'overwrite' and 'is_heap' parameters as true causes the - * PAI_OVERWRITE and PAI_IS_HEAP flags to be set, respectively. - * - * !!! EREPORT(ERROR) IS DISALLOWED HERE !!! - */ -OffsetNumber -PageAddItem(Page page, Item item, Size size, OffsetNumber offsetNumber, - bool overwrite, bool is_heap) -{ - return PageAddItemExtended(page, item, size, offsetNumber, - overwrite ? PAI_OVERWRITE : 0 | - is_heap ? PAI_IS_HEAP : 0); -} /* * PageGetTempPage @@ -431,8 +415,7 @@ PageRestoreTempPage(Page tempPage, Page oldPage) } /* - * sorting support for PageRepairFragmentation, PageIndexMultiDelete, - * PageIndexDeleteNoCompact + * sorting support for PageRepairFragmentation and PageIndexMultiDelete */ typedef struct itemIdSortData { @@ -731,7 +714,8 @@ PageIndexTupleDelete(Page page, OffsetNumber offnum) if (phdr->pd_lower < SizeOfPageHeaderData || phdr->pd_lower > phdr->pd_upper || phdr->pd_upper > phdr->pd_special || - phdr->pd_special > BLCKSZ) + phdr->pd_special > BLCKSZ || + phdr->pd_special != MAXALIGN(phdr->pd_special)) ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED), errmsg("corrupted page pointers: lower = %u, upper = %u, special = %u", @@ -750,12 +734,15 @@ PageIndexTupleDelete(Page page, OffsetNumber offnum) offset = ItemIdGetOffset(tup); if (offset < phdr->pd_upper || (offset + size) > phdr->pd_special || - offset != MAXALIGN(offset) || size != MAXALIGN(size)) + offset != MAXALIGN(offset)) ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED), errmsg("corrupted item pointer: offset = %u, size = %u", offset, (unsigned int) size))); + /* Amount of space to actually be deleted */ + size = MAXALIGN(size); + /* * First, we want to get rid of the pd_linp entry for the index tuple. We * copy all subsequent linp's back one slot in the array. We don't use @@ -774,15 +761,14 @@ PageIndexTupleDelete(Page page, OffsetNumber offnum) * Now move everything between the old upper bound (beginning of tuple * space) and the beginning of the deleted tuple forward, so that space in * the middle of the page is left free. If we've just deleted the tuple - * at the beginning of tuple space, then there's no need to do the copy - * (and bcopy on some architectures SEGV's if asked to move zero bytes). + * at the beginning of tuple space, then there's no need to do the copy. */ /* beginning of tuple space */ addr = (char *) page + phdr->pd_upper; if (offset > phdr->pd_upper) - memmove(addr + size, addr, (int) (offset - phdr->pd_upper)); + memmove(addr + size, addr, offset - phdr->pd_upper); /* adjust free space boundary pointers */ phdr->pd_upper += size; @@ -930,158 +916,215 @@ PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems) compactify_tuples(itemidbase, nused, page); } + /* - * PageIndexDeleteNoCompact - * Delete the given items for an index page, and defragment the resulting - * free space, but do not compact the item pointers array. + * PageIndexTupleDeleteNoCompact * - * itemnos is the array of tuples to delete; nitems is its size. maxIdxTuples - * is the maximum number of tuples that can exist in a page. - * - * Unused items at the end of the array are removed. + * Remove the specified tuple from an index page, but set its line pointer + * to "unused" instead of compacting it out, except that it can be removed + * if it's the last line pointer on the page. * * This is used for index AMs that require that existing TIDs of live tuples - * remain unchanged. + * remain unchanged, and are willing to allow unused line pointers instead. */ void -PageIndexDeleteNoCompact(Page page, OffsetNumber *itemnos, int nitems) +PageIndexTupleDeleteNoCompact(Page page, OffsetNumber offnum) { PageHeader phdr = (PageHeader) page; - LocationIndex pd_lower = phdr->pd_lower; - LocationIndex pd_upper = phdr->pd_upper; - LocationIndex pd_special = phdr->pd_special; + char *addr; + ItemId tup; + Size size; + unsigned offset; int nline; - bool empty; - OffsetNumber offnum; - int nextitm; /* * As with PageRepairFragmentation, paranoia seems justified. */ - if (pd_lower < SizeOfPageHeaderData || - pd_lower > pd_upper || - pd_upper > pd_special || - pd_special > BLCKSZ || - pd_special != MAXALIGN(pd_special)) + if (phdr->pd_lower < SizeOfPageHeaderData || + phdr->pd_lower > phdr->pd_upper || + phdr->pd_upper > phdr->pd_special || + phdr->pd_special > BLCKSZ || + phdr->pd_special != MAXALIGN(phdr->pd_special)) ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED), errmsg("corrupted page pointers: lower = %u, upper = %u, special = %u", - pd_lower, pd_upper, pd_special))); + phdr->pd_lower, phdr->pd_upper, phdr->pd_special))); + + nline = PageGetMaxOffsetNumber(page); + if ((int) offnum <= 0 || (int) offnum > nline) + elog(ERROR, "invalid index offnum: %u", offnum); + + tup = PageGetItemId(page, offnum); + Assert(ItemIdHasStorage(tup)); + size = ItemIdGetLength(tup); + offset = ItemIdGetOffset(tup); + + if (offset < phdr->pd_upper || (offset + size) > phdr->pd_special || + offset != MAXALIGN(offset)) + ereport(ERROR, + (errcode(ERRCODE_DATA_CORRUPTED), + errmsg("corrupted item pointer: offset = %u, size = %u", + offset, (unsigned int) size))); + + /* Amount of space to actually be deleted */ + size = MAXALIGN(size); /* - * Scan the existing item pointer array and mark as unused those that are - * in our kill-list; make sure any non-interesting ones are marked unused - * as well. + * Either set the item pointer to "unused", or zap it if it's the last + * one. (Note: it's possible that the next-to-last one(s) are already + * unused, but we do not trouble to try to compact them out if so.) */ - nline = PageGetMaxOffsetNumber(page); - empty = true; - nextitm = 0; - for (offnum = FirstOffsetNumber; offnum <= nline; offnum = OffsetNumberNext(offnum)) + if ((int) offnum < nline) + ItemIdSetUnused(tup); + else { - ItemId lp; - ItemLength itemlen; - ItemOffset offset; + phdr->pd_lower -= sizeof(ItemIdData); + nline--; /* there's one less than when we started */ + } - lp = PageGetItemId(page, offnum); + /* + * Now move everything between the old upper bound (beginning of tuple + * space) and the beginning of the deleted tuple forward, so that space in + * the middle of the page is left free. If we've just deleted the tuple + * at the beginning of tuple space, then there's no need to do the copy. + */ - itemlen = ItemIdGetLength(lp); - offset = ItemIdGetOffset(lp); + /* beginning of tuple space */ + addr = (char *) page + phdr->pd_upper; - if (ItemIdIsUsed(lp)) + if (offset > phdr->pd_upper) + memmove(addr + size, addr, offset - phdr->pd_upper); + + /* adjust free space boundary pointer */ + phdr->pd_upper += size; + + /* + * Finally, we need to adjust the linp entries that remain. + * + * Anything that used to be before the deleted tuple's data was moved + * forward by the size of the deleted tuple. + */ + if (!PageIsEmpty(page)) + { + int i; + + for (i = 1; i <= nline; i++) { - if (offset < pd_upper || - (offset + itemlen) > pd_special || - offset != MAXALIGN(offset)) - ereport(ERROR, - (errcode(ERRCODE_DATA_CORRUPTED), - errmsg("corrupted item pointer: offset = %u, length = %u", - offset, (unsigned int) itemlen))); - - if (nextitm < nitems && offnum == itemnos[nextitm]) - { - /* this one is on our list to delete, so mark it unused */ - ItemIdSetUnused(lp); - nextitm++; - } - else if (ItemIdHasStorage(lp)) - { - /* This one's live -- must do the compaction dance */ - empty = false; - } - else - { - /* get rid of this one too */ - ItemIdSetUnused(lp); - } + ItemId ii = PageGetItemId(phdr, i); + + if (ItemIdHasStorage(ii) && ItemIdGetOffset(ii) <= offset) + ii->lp_off += size; } } +} - /* this will catch invalid or out-of-order itemnos[] */ - if (nextitm != nitems) - elog(ERROR, "incorrect index offsets supplied"); - if (empty) - { - /* Page is completely empty, so just reset it quickly */ - phdr->pd_lower = SizeOfPageHeaderData; - phdr->pd_upper = pd_special; - } - else +/* + * PageIndexTupleOverwrite + * + * Replace a specified tuple on an index page. + * + * The new tuple is placed exactly where the old one had been, shifting + * other tuples' data up or down as needed to keep the page compacted. + * This is better than deleting and reinserting the tuple, because it + * avoids any data shifting when the tuple size doesn't change; and + * even when it does, we avoid moving the item pointers around. + * Conceivably this could also be of use to an index AM that cares about + * the physical order of tuples as well as their ItemId order. + * + * If there's insufficient space for the new tuple, return false. Other + * errors represent data-corruption problems, so we just elog. + */ +bool +PageIndexTupleOverwrite(Page page, OffsetNumber offnum, + Item newtup, Size newsize) +{ + PageHeader phdr = (PageHeader) page; + ItemId tupid; + int oldsize; + unsigned offset; + Size alignednewsize; + int size_diff; + int itemcount; + + /* + * As with PageRepairFragmentation, paranoia seems justified. + */ + if (phdr->pd_lower < SizeOfPageHeaderData || + phdr->pd_lower > phdr->pd_upper || + phdr->pd_upper > phdr->pd_special || + phdr->pd_special > BLCKSZ || + phdr->pd_special != MAXALIGN(phdr->pd_special)) + ereport(ERROR, + (errcode(ERRCODE_DATA_CORRUPTED), + errmsg("corrupted page pointers: lower = %u, upper = %u, special = %u", + phdr->pd_lower, phdr->pd_upper, phdr->pd_special))); + + itemcount = PageGetMaxOffsetNumber(page); + if ((int) offnum <= 0 || (int) offnum > itemcount) + elog(ERROR, "invalid index offnum: %u", offnum); + + tupid = PageGetItemId(page, offnum); + Assert(ItemIdHasStorage(tupid)); + oldsize = ItemIdGetLength(tupid); + offset = ItemIdGetOffset(tupid); + + if (offset < phdr->pd_upper || (offset + oldsize) > phdr->pd_special || + offset != MAXALIGN(offset)) + ereport(ERROR, + (errcode(ERRCODE_DATA_CORRUPTED), + errmsg("corrupted item pointer: offset = %u, size = %u", + offset, (unsigned int) oldsize))); + + /* + * Determine actual change in space requirement, check for page overflow. + */ + oldsize = MAXALIGN(oldsize); + alignednewsize = MAXALIGN(newsize); + if (alignednewsize > oldsize + (phdr->pd_upper - phdr->pd_lower)) + return false; + + /* + * Relocate existing data and update line pointers, unless the new tuple + * is the same size as the old (after alignment), in which case there's + * nothing to do. Notice that what we have to relocate is data before the + * target tuple, not data after, so it's convenient to express size_diff + * as the amount by which the tuple's size is decreasing, making it the + * delta to add to pd_upper and affected line pointers. + */ + size_diff = oldsize - (int) alignednewsize; + if (size_diff != 0) { - /* There are live items: need to compact the page the hard way */ - itemIdSortData itemidbase[MaxOffsetNumber]; - itemIdSort itemidptr; + char *addr = (char *) page + phdr->pd_upper; int i; - Size totallen; - /* - * Scan the page taking note of each item that we need to preserve. - * This includes both live items (those that contain data) and - * interspersed unused ones. It's critical to preserve these unused - * items, because otherwise the offset numbers for later live items - * would change, which is not acceptable. Unused items might get used - * again later; that is fine. - */ - itemidptr = itemidbase; - totallen = 0; - PageClearHasFreeLinePointers(page); - for (i = 0; i < nline; i++) - { - ItemId lp; + /* relocate all tuple data before the target tuple */ + memmove(addr + size_diff, addr, offset - phdr->pd_upper); - itemidptr->offsetindex = i; + /* adjust free space boundary pointer */ + phdr->pd_upper += size_diff; - lp = PageGetItemId(page, i + 1); - if (ItemIdHasStorage(lp)) - { - itemidptr->itemoff = ItemIdGetOffset(lp); - itemidptr->alignedlen = MAXALIGN(ItemIdGetLength(lp)); - totallen += itemidptr->alignedlen; - itemidptr++; - } - else - { - PageSetHasFreeLinePointers(page); - ItemIdSetUnused(lp); - } + /* adjust affected line pointers too */ + for (i = FirstOffsetNumber; i <= itemcount; i++) + { + ItemId ii = PageGetItemId(phdr, i); + + /* Allow items without storage; currently only BRIN needs that */ + if (ItemIdHasStorage(ii) && ItemIdGetOffset(ii) <= offset) + ii->lp_off += size_diff; } - nline = itemidptr - itemidbase; - /* By here, there are exactly nline elements in itemidbase array */ + } - if (totallen > (Size) (pd_special - pd_lower)) - ereport(ERROR, - (errcode(ERRCODE_DATA_CORRUPTED), - errmsg("corrupted item lengths: total %u, available space %u", - (unsigned int) totallen, pd_special - pd_lower))); + /* Update the item's tuple length (other fields shouldn't change) */ + ItemIdSetNormal(tupid, offset + size_diff, newsize); - /* - * Defragment the data areas of each tuple, being careful to preserve - * each item's position in the linp array. - */ - compactify_tuples(itemidbase, nline, page); - } + /* Copy new tuple data onto page */ + memcpy(PageGetItem(page, tupid), newtup, newsize); + + return true; } + /* * Set checksum for a page in shared buffers. * diff --git a/src/backend/storage/page/checksum.c b/src/backend/storage/page/checksum.c index 24285dbed9..b96440ae54 100644 --- a/src/backend/storage/page/checksum.c +++ b/src/backend/storage/page/checksum.c @@ -3,7 +3,7 @@ * checksum.c * Checksum implementation for data pages. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/storage/page/itemptr.c b/src/backend/storage/page/itemptr.c index dbb35b1cae..703cbb9c39 100644 --- a/src/backend/storage/page/itemptr.c +++ b/src/backend/storage/page/itemptr.c @@ -3,7 +3,7 @@ * itemptr.c * POSTGRES disk item pointer code. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c index f329d1538c..1d9384ef91 100644 --- a/src/backend/storage/smgr/md.c +++ b/src/backend/storage/smgr/md.c @@ -10,7 +10,7 @@ * It doesn't matter whether the bits are on spinning rust or some other * storage technology. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -92,27 +92,23 @@ * out to an unlinked old copy of a segment file that will eventually * disappear. * - * The file descriptor pointer (md_fd field) stored in the SMgrRelation - * cache is, therefore, just the head of a list of MdfdVec objects, one - * per segment. But note the md_fd pointer can be NULL, indicating - * relation not open. - * - * Also note that mdfd_chain == NULL does not necessarily mean the relation - * doesn't have another segment after this one; we may just not have - * opened the next segment yet. (We could not have "all segments are - * in the chain" as an invariant anyway, since another backend could - * extend the relation when we weren't looking.) We do not make chain + * File descriptors are stored in the per-fork md_seg_fds arrays inside + * SMgrRelation. The length of these arrays is stored in md_num_open_segs. + * Note that a fork's md_num_open_segs having a specific value does not + * necessarily mean the relation doesn't have additional segments; we may + * just not have opened the next segment yet. (We could not have "all + * segments are in the array" as an invariant anyway, since another backend + * could extend the relation while we aren't looking.) We do not have * entries for inactive segments, however; as soon as we find a partial * segment, we assume that any subsequent segments are inactive. * - * All MdfdVec objects are palloc'd in the MdCxt memory context. + * The entire MdfdVec array is palloc'd in the MdCxt memory context. */ typedef struct _MdfdVec { File mdfd_vfd; /* fd number in fd.c's pool */ BlockNumber mdfd_segno; /* segment number, from 0 */ - struct _MdfdVec *mdfd_chain; /* next segment, or NULL */ } MdfdVec; static MemoryContext MdCxt; /* context for all MdfdVec objects */ @@ -189,7 +185,9 @@ static MdfdVec *mdopen(SMgrRelation reln, ForkNumber forknum, int behavior); static void register_dirty_segment(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg); static void register_unlink(RelFileNodeBackend rnode); -static MdfdVec *_fdvec_alloc(void); +static void _fdvec_resize(SMgrRelation reln, + ForkNumber forknum, + int nseg); static char *_mdfd_segpath(SMgrRelation reln, ForkNumber forknum, BlockNumber segno); static MdfdVec *_mdfd_openseg(SMgrRelation reln, ForkNumber forkno, @@ -208,9 +206,7 @@ mdinit(void) { MdCxt = AllocSetContextCreate(TopMemoryContext, "MdSmgr", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* * Create pending-operations hashtable if we need it. Currently, we need @@ -231,10 +227,8 @@ mdinit(void) * practice. */ pendingOpsCxt = AllocSetContextCreate(MdCxt, - "Pending Ops Context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + "Pending ops context", + ALLOCSET_DEFAULT_SIZES); MemoryContextAllowInCriticalSection(pendingOpsCxt, true); MemSet(&hash_ctl, 0, sizeof(hash_ctl)); @@ -298,13 +292,14 @@ mdexists(SMgrRelation reln, ForkNumber forkNum) void mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo) { + MdfdVec *mdfd; char *path; File fd; - if (isRedo && reln->md_fd[forkNum] != NULL) + if (isRedo && reln->md_num_open_segs[forkNum] > 0) return; /* created and opened already... */ - Assert(reln->md_fd[forkNum] == NULL); + Assert(reln->md_num_open_segs[forkNum] == 0); path = relpath(reln->smgr_rnode, forkNum); @@ -334,11 +329,10 @@ mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo) pfree(path); - reln->md_fd[forkNum] = _fdvec_alloc(); - - reln->md_fd[forkNum]->mdfd_vfd = fd; - reln->md_fd[forkNum]->mdfd_segno = 0; - reln->md_fd[forkNum]->mdfd_chain = NULL; + _fdvec_resize(reln, forkNum, 1); + mdfd = &reln->md_seg_fds[forkNum][0]; + mdfd->mdfd_vfd = fd; + mdfd->mdfd_segno = 0; } /* @@ -583,8 +577,8 @@ mdopen(SMgrRelation reln, ForkNumber forknum, int behavior) File fd; /* No work if already open */ - if (reln->md_fd[forknum]) - return reln->md_fd[forknum]; + if (reln->md_num_open_segs[forknum] > 0) + return &reln->md_seg_fds[forknum][0]; path = relpath(reln->smgr_rnode, forknum); @@ -616,11 +610,11 @@ mdopen(SMgrRelation reln, ForkNumber forknum, int behavior) pfree(path); - reln->md_fd[forknum] = mdfd = _fdvec_alloc(); - + _fdvec_resize(reln, forknum, 1); + mdfd = &reln->md_seg_fds[forknum][0]; mdfd->mdfd_vfd = fd; mdfd->mdfd_segno = 0; - mdfd->mdfd_chain = NULL; + Assert(_mdnblocks(reln, forknum, mdfd) <= ((BlockNumber) RELSEG_SIZE)); return mdfd; @@ -632,25 +626,29 @@ mdopen(SMgrRelation reln, ForkNumber forknum, int behavior) void mdclose(SMgrRelation reln, ForkNumber forknum) { - MdfdVec *v = reln->md_fd[forknum]; + int nopensegs = reln->md_num_open_segs[forknum]; /* No work if already closed */ - if (v == NULL) + if (nopensegs == 0) return; - reln->md_fd[forknum] = NULL; /* prevent dangling pointer after error */ - - while (v != NULL) + /* close segments starting from the end */ + while (nopensegs > 0) { - MdfdVec *ov = v; + MdfdVec *v = &reln->md_seg_fds[forknum][nopensegs - 1]; /* if not closed already */ if (v->mdfd_vfd >= 0) + { FileClose(v->mdfd_vfd); - /* Now free vector */ - v = v->mdfd_chain; - pfree(ov); + v->mdfd_vfd = -1; + } + + nopensegs--; } + + /* resize just once, avoids pointless reallocations */ + _fdvec_resize(reln, forknum, 0); } /* @@ -866,9 +864,9 @@ mdwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, * mdnblocks() -- Get the number of blocks stored in a relation. * * Important side effect: all active segments of the relation are opened - * and added to the mdfd_chain list. If this routine has not been + * and added to the mdfd_seg_fds array. If this routine has not been * called, then only segments up to the last one actually touched - * are present in the chain. + * are present in the array. */ BlockNumber mdnblocks(SMgrRelation reln, ForkNumber forknum) @@ -877,24 +875,24 @@ mdnblocks(SMgrRelation reln, ForkNumber forknum) BlockNumber nblocks; BlockNumber segno = 0; + /* mdopen has opened the first segment */ + Assert(reln->md_num_open_segs[forknum] > 0); + /* - * Skip through any segments that aren't the last one, to avoid redundant - * seeks on them. We have previously verified that these segments are - * exactly RELSEG_SIZE long, and it's useless to recheck that each time. + * Start from the last open segments, to avoid redundant seeks. We have + * previously verified that these segments are exactly RELSEG_SIZE long, + * and it's useless to recheck that each time. * * NOTE: this assumption could only be wrong if another backend has * truncated the relation. We rely on higher code levels to handle that * scenario by closing and re-opening the md fd, which is handled via * relcache flush. (Since the checkpointer doesn't participate in - * relcache flush, it could have segment chain entries for inactive - * segments; that's OK because the checkpointer never needs to compute - * relation size.) + * relcache flush, it could have segment entries for inactive segments; + * that's OK because the checkpointer never needs to compute relation + * size.) */ - while (v->mdfd_chain != NULL) - { - segno++; - v = v->mdfd_chain; - } + segno = reln->md_num_open_segs[forknum] - 1; + v = &reln->md_seg_fds[forknum][segno]; for (;;) { @@ -909,21 +907,16 @@ mdnblocks(SMgrRelation reln, ForkNumber forknum) */ segno++; - if (v->mdfd_chain == NULL) - { - /* - * We used to pass O_CREAT here, but that's has the disadvantage - * that it might create a segment which has vanished through some - * operating system misadventure. In such a case, creating the - * segment here undermines _mdfd_getseg's attempts to notice and - * report an error upon access to a missing segment. - */ - v->mdfd_chain = _mdfd_openseg(reln, forknum, segno, 0); - if (v->mdfd_chain == NULL) - return segno * ((BlockNumber) RELSEG_SIZE); - } - - v = v->mdfd_chain; + /* + * We used to pass O_CREAT here, but that's has the disadvantage that + * it might create a segment which has vanished through some operating + * system misadventure. In such a case, creating the segment here + * undermines _mdfd_getseg's attempts to notice and report an error + * upon access to a missing segment. + */ + v = _mdfd_openseg(reln, forknum, segno, 0); + if (v == NULL) + return segno * ((BlockNumber) RELSEG_SIZE); } } @@ -933,9 +926,9 @@ mdnblocks(SMgrRelation reln, ForkNumber forknum) void mdtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks) { - MdfdVec *v; BlockNumber curnblk; BlockNumber priorblocks; + int curopensegs; /* * NOTE: mdnblocks makes sure we have opened all active segments, so that @@ -955,19 +948,24 @@ mdtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks) if (nblocks == curnblk) return; /* no work */ - v = mdopen(reln, forknum, EXTENSION_FAIL); - - priorblocks = 0; - while (v != NULL) + /* + * Truncate segments, starting at the last one. Starting at the end makes + * managing the memory for the fd array easier, should there be errors. + */ + curopensegs = reln->md_num_open_segs[forknum]; + while (curopensegs > 0) { - MdfdVec *ov = v; + MdfdVec *v; + + priorblocks = (curopensegs - 1) * RELSEG_SIZE; + + v = &reln->md_seg_fds[forknum][curopensegs - 1]; if (priorblocks > nblocks) { /* - * This segment is no longer active (and has already been unlinked - * from the mdfd_chain). We truncate the file, but do not delete - * it, for reasons explained in the header comments. + * This segment is no longer active. We truncate the file, but do + * not delete it, for reasons explained in the header comments. */ if (FileTruncate(v->mdfd_vfd, 0) < 0) ereport(ERROR, @@ -977,20 +975,21 @@ mdtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks) if (!SmgrIsTemp(reln)) register_dirty_segment(reln, forknum, v); - v = v->mdfd_chain; - Assert(ov != reln->md_fd[forknum]); /* we never drop the 1st - * segment */ - pfree(ov); + + /* we never drop the 1st segment */ + Assert(v != &reln->md_seg_fds[forknum][0]); + + FileClose(v->mdfd_vfd); + _fdvec_resize(reln, forknum, curopensegs - 1); } else if (priorblocks + ((BlockNumber) RELSEG_SIZE) > nblocks) { /* * This is the last segment we want to keep. Truncate the file to - * the right length, and clear chain link that points to any - * remaining segments (which we shall zap). NOTE: if nblocks is - * exactly a multiple K of RELSEG_SIZE, we will truncate the K+1st - * segment to 0 length but keep it. This adheres to the invariant - * given in the header comments. + * the right length. NOTE: if nblocks is exactly a multiple K of + * RELSEG_SIZE, we will truncate the K+1st segment to 0 length but + * keep it. This adheres to the invariant given in the header + * comments. */ BlockNumber lastsegblocks = nblocks - priorblocks; @@ -1002,18 +1001,16 @@ mdtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks) nblocks))); if (!SmgrIsTemp(reln)) register_dirty_segment(reln, forknum, v); - v = v->mdfd_chain; - ov->mdfd_chain = NULL; } else { /* - * We still need this segment and 0 or more blocks beyond it, so - * nothing to do here. + * We still need this segment, so nothing to do for this and any + * earlier segment. */ - v = v->mdfd_chain; + break; } - priorblocks += RELSEG_SIZE; + curopensegs--; } } @@ -1026,7 +1023,7 @@ mdtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks) void mdimmedsync(SMgrRelation reln, ForkNumber forknum) { - MdfdVec *v; + int segno; /* * NOTE: mdnblocks makes sure we have opened all active segments, so that @@ -1034,16 +1031,18 @@ mdimmedsync(SMgrRelation reln, ForkNumber forknum) */ mdnblocks(reln, forknum); - v = mdopen(reln, forknum, EXTENSION_FAIL); + segno = reln->md_num_open_segs[forknum]; - while (v != NULL) + while (segno > 0) { + MdfdVec *v = &reln->md_seg_fds[forknum][segno - 1]; + if (FileSync(v->mdfd_vfd) < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not fsync file \"%s\": %m", FilePathName(v->mdfd_vfd)))); - v = v->mdfd_chain; + segno--; } } @@ -1706,12 +1705,40 @@ ForgetDatabaseFsyncRequests(Oid dbid) /* - * _fdvec_alloc() -- Make a MdfdVec object. + * _fdvec_resize() -- Resize the fork's open segments array */ -static MdfdVec * -_fdvec_alloc(void) +static void +_fdvec_resize(SMgrRelation reln, + ForkNumber forknum, + int nseg) { - return (MdfdVec *) MemoryContextAlloc(MdCxt, sizeof(MdfdVec)); + if (nseg == 0) + { + if (reln->md_num_open_segs[forknum] > 0) + { + pfree(reln->md_seg_fds[forknum]); + reln->md_seg_fds[forknum] = NULL; + } + } + else if (reln->md_num_open_segs[forknum] == 0) + { + reln->md_seg_fds[forknum] = + MemoryContextAlloc(MdCxt, sizeof(MdfdVec) * nseg); + } + else + { + /* + * It doesn't seem worthwile complicating the code by having a more + * aggressive growth strategy here; the number of segments doesn't + * grow that fast, and the memory context internally will sometimes + * avoid doing an actual reallocation. + */ + reln->md_seg_fds[forknum] = + repalloc(reln->md_seg_fds[forknum], + sizeof(MdfdVec) * nseg); + } + + reln->md_num_open_segs[forknum] = nseg; } /* @@ -1759,13 +1786,14 @@ _mdfd_openseg(SMgrRelation reln, ForkNumber forknum, BlockNumber segno, if (fd < 0) return NULL; - /* allocate an mdfdvec entry for it */ - v = _fdvec_alloc(); + if (segno <= reln->md_num_open_segs[forknum]) + _fdvec_resize(reln, forknum, segno + 1); /* fill the entry */ + v = &reln->md_seg_fds[forknum][segno]; v->mdfd_vfd = fd; v->mdfd_segno = segno; - v->mdfd_chain = NULL; + Assert(_mdnblocks(reln, forknum, v) <= ((BlockNumber) RELSEG_SIZE)); /* all done */ @@ -1784,7 +1812,7 @@ static MdfdVec * _mdfd_getseg(SMgrRelation reln, ForkNumber forknum, BlockNumber blkno, bool skipFsync, int behavior) { - MdfdVec *v = mdopen(reln, forknum, behavior); + MdfdVec *v; BlockNumber targetseg; BlockNumber nextsegno; @@ -1792,98 +1820,116 @@ _mdfd_getseg(SMgrRelation reln, ForkNumber forknum, BlockNumber blkno, Assert(behavior & (EXTENSION_FAIL | EXTENSION_CREATE | EXTENSION_RETURN_NULL)); - if (!v) - return NULL; /* if behavior & EXTENSION_RETURN_NULL */ - targetseg = blkno / ((BlockNumber) RELSEG_SIZE); - for (nextsegno = 1; nextsegno <= targetseg; nextsegno++) + + /* if an existing and opened segment, we're done */ + if (targetseg < reln->md_num_open_segs[forknum]) { - Assert(nextsegno == v->mdfd_segno + 1); + v = &reln->md_seg_fds[forknum][targetseg]; + return v; + } - if (v->mdfd_chain == NULL) - { - BlockNumber nblocks = _mdnblocks(reln, forknum, v); - int flags = 0; + /* + * The target segment is not yet open. Iterate over all the segments + * between the last opened and the target segment. This way missing + * segments either raise an error, or get created (according to + * 'behavior'). Start with either the last opened, or the first segment if + * none was opened before. + */ + if (reln->md_num_open_segs[forknum] > 0) + v = &reln->md_seg_fds[forknum][reln->md_num_open_segs[forknum] - 1]; + else + { + v = mdopen(reln, forknum, behavior); + if (!v) + return NULL; /* if behavior & EXTENSION_RETURN_NULL */ + } + + for (nextsegno = reln->md_num_open_segs[forknum]; + nextsegno <= targetseg; nextsegno++) + { + BlockNumber nblocks = _mdnblocks(reln, forknum, v); + int flags = 0; - if (nblocks > ((BlockNumber) RELSEG_SIZE)) - elog(FATAL, "segment too big"); + Assert(nextsegno == v->mdfd_segno + 1); + + if (nblocks > ((BlockNumber) RELSEG_SIZE)) + elog(FATAL, "segment too big"); - if ((behavior & EXTENSION_CREATE) || - (InRecovery && (behavior & EXTENSION_CREATE_RECOVERY))) + if ((behavior & EXTENSION_CREATE) || + (InRecovery && (behavior & EXTENSION_CREATE_RECOVERY))) + { + /* + * Normally we will create new segments only if authorized by the + * caller (i.e., we are doing mdextend()). But when doing WAL + * recovery, create segments anyway; this allows cases such as + * replaying WAL data that has a write into a high-numbered + * segment of a relation that was later deleted. We want to go + * ahead and create the segments so we can finish out the replay. + * However if the caller has specified + * EXTENSION_REALLY_RETURN_NULL, then extension is not desired + * even in recovery; we won't reach this point in that case. + * + * We have to maintain the invariant that segments before the last + * active segment are of size RELSEG_SIZE; therefore, if + * extending, pad them out with zeroes if needed. (This only + * matters if in recovery, or if the caller is extending the + * relation discontiguously, but that can happen in hash indexes.) + */ + if (nblocks < ((BlockNumber) RELSEG_SIZE)) { - /* - * Normally we will create new segments only if authorized by - * the caller (i.e., we are doing mdextend()). But when doing - * WAL recovery, create segments anyway; this allows cases - * such as replaying WAL data that has a write into a - * high-numbered segment of a relation that was later deleted. - * We want to go ahead and create the segments so we can - * finish out the replay. However if the caller has specified - * EXTENSION_REALLY_RETURN_NULL, then extension is not desired - * even in recovery; we won't reach this point in that case. - * - * We have to maintain the invariant that segments before the - * last active segment are of size RELSEG_SIZE; therefore, if - * extending, pad them out with zeroes if needed. (This only - * matters if in recovery, or if the caller is extending the - * relation discontiguously, but that can happen in hash - * indexes.) - */ - if (nblocks < ((BlockNumber) RELSEG_SIZE)) - { - char *zerobuf = palloc0(BLCKSZ); + char *zerobuf = palloc0(BLCKSZ); - mdextend(reln, forknum, - nextsegno * ((BlockNumber) RELSEG_SIZE) - 1, - zerobuf, skipFsync); - pfree(zerobuf); - } - flags = O_CREAT; + mdextend(reln, forknum, + nextsegno * ((BlockNumber) RELSEG_SIZE) - 1, + zerobuf, skipFsync); + pfree(zerobuf); } - else if (!(behavior & EXTENSION_DONT_CHECK_SIZE) && - nblocks < ((BlockNumber) RELSEG_SIZE)) + flags = O_CREAT; + } + else if (!(behavior & EXTENSION_DONT_CHECK_SIZE) && + nblocks < ((BlockNumber) RELSEG_SIZE)) + { + /* + * When not extending (or explicitly including truncated + * segments), only open the next segment if the current one is + * exactly RELSEG_SIZE. If not (this branch), either return NULL + * or fail. + */ + if (behavior & EXTENSION_RETURN_NULL) { /* - * When not extending (or explicitly including truncated - * segments), only open the next segment if the current one is - * exactly RELSEG_SIZE. If not (this branch), either return - * NULL or fail. + * Some callers discern between reasons for _mdfd_getseg() + * returning NULL based on errno. As there's no failing + * syscall involved in this case, explicitly set errno to + * ENOENT, as that seems the closest interpretation. */ - if (behavior & EXTENSION_RETURN_NULL) - { - /* - * Some callers discern between reasons for _mdfd_getseg() - * returning NULL based on errno. As there's no failing - * syscall involved in this case, explicitly set errno to - * ENOENT, as that seems the closest interpretation. - */ - errno = ENOENT; - return NULL; - } - - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not open file \"%s\" (target block %u): previous segment is only %u blocks", - _mdfd_segpath(reln, forknum, nextsegno), - blkno, nblocks))); + errno = ENOENT; + return NULL; } - v->mdfd_chain = _mdfd_openseg(reln, forknum, nextsegno, flags); + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not open file \"%s\" (target block %u): previous segment is only %u blocks", + _mdfd_segpath(reln, forknum, nextsegno), + blkno, nblocks))); + } - if (v->mdfd_chain == NULL) - { - if ((behavior & EXTENSION_RETURN_NULL) && - FILE_POSSIBLY_DELETED(errno)) - return NULL; - ereport(ERROR, - (errcode_for_file_access(), + v = _mdfd_openseg(reln, forknum, nextsegno, flags); + + if (v == NULL) + { + if ((behavior & EXTENSION_RETURN_NULL) && + FILE_POSSIBLY_DELETED(errno)) + return NULL; + ereport(ERROR, + (errcode_for_file_access(), errmsg("could not open file \"%s\" (target block %u): %m", _mdfd_segpath(reln, forknum, nextsegno), blkno))); - } } - v = v->mdfd_chain; } + return v; } diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c index 94aa952bcc..0ed1fe91d5 100644 --- a/src/backend/storage/smgr/smgr.c +++ b/src/backend/storage/smgr/smgr.c @@ -6,7 +6,7 @@ * All file system operations in POSTGRES dispatch through these * routines. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -174,7 +174,7 @@ smgropen(RelFileNode rnode, BackendId backend) /* mark it not open */ for (forknum = 0; forknum <= MAX_FORKNUM; forknum++) - reln->md_fd[forknum] = NULL; + reln->md_num_open_segs[forknum] = 0; /* it has no owner yet */ add_to_unowned_list(reln); @@ -379,7 +379,7 @@ smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo) * Exit quickly in WAL replay mode if we've already opened the file. If * it's open, it surely must exist. */ - if (isRedo && reln->md_fd[forknum] != NULL) + if (isRedo && reln->md_num_open_segs[forknum] > 0) return; /* diff --git a/src/backend/storage/smgr/smgrtype.c b/src/backend/storage/smgr/smgrtype.c index 51dbac89e1..dc81fe81cf 100644 --- a/src/backend/storage/smgr/smgrtype.c +++ b/src/backend/storage/smgr/smgrtype.c @@ -3,7 +3,7 @@ * smgrtype.c * storage manager type * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -15,6 +15,7 @@ #include "postgres.h" #include "storage/smgr.h" +#include "utils/builtins.h" typedef struct smgrid diff --git a/src/backend/tcop/dest.c b/src/backend/tcop/dest.c index de45cbc4fb..6b6a893867 100644 --- a/src/backend/tcop/dest.c +++ b/src/backend/tcop/dest.c @@ -4,7 +4,7 @@ * support for communication destinations * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -76,6 +76,11 @@ static DestReceiver debugtupDR = { DestDebug }; +static DestReceiver logtupDR = { + logtup, logStartup, donothingCleanup, donothingCleanup, + DestLog +}; + static DestReceiver spi_printtupDR = { spi_printtup, spi_dest_startup, donothingCleanup, donothingCleanup, DestSPI @@ -114,6 +119,9 @@ CreateDestReceiver(CommandDest dest) case DestDebug: return &debugtupDR; + case DestLog: + return &logtupDR; + case DestSPI: return &spi_printtupDR; @@ -161,6 +169,7 @@ EndCommand(const char *commandTag, CommandDest dest) case DestNone: case DestDebug: + case DestLog: case DestSPI: case DestTuplestore: case DestIntoRel: @@ -204,6 +213,7 @@ NullCommand(CommandDest dest) case DestNone: case DestDebug: + case DestLog: case DestSPI: case DestTuplestore: case DestIntoRel: @@ -218,8 +228,8 @@ NullCommand(CommandDest dest) /* ---------------- * ReadyForQuery - tell dest that we are ready for a new query * - * The ReadyForQuery message is sent in protocol versions 2.0 and up - * so that the FE can tell when we are done processing a query string. + * The ReadyForQuery message is sent so that the FE can tell when + * we are done processing a query string. * In versions 3.0 and up, it also carries a transaction state indicator. * * Note that by flushing the stdio buffer here, we can avoid doing it @@ -241,7 +251,7 @@ ReadyForQuery(CommandDest dest) pq_sendbyte(&buf, TransactionBlockStatusCode()); pq_endmessage(&buf); } - else if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2) + else pq_putemptymessage('Z'); /* Flush output at end of cycle in any case. */ pq_flush(); @@ -249,6 +259,7 @@ ReadyForQuery(CommandDest dest) case DestNone: case DestDebug: + case DestLog: case DestSPI: case DestTuplestore: case DestIntoRel: diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c index 2cd45e642a..2efed95132 100644 --- a/src/backend/tcop/fastpath.c +++ b/src/backend/tcop/fastpath.c @@ -3,7 +3,7 @@ * fastpath.c * routines to handle function requests from the frontend * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index b185c1b5eb..c15303c7bb 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3,7 +3,7 @@ * postgres.c * POSTGRES C Backend Interface * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -183,8 +183,8 @@ static int errdetail_recovery_conflict(void); static void start_xact_command(void); static void finish_xact_command(void); static bool IsTransactionExitStmt(Node *parsetree); -static bool IsTransactionExitStmtList(List *parseTrees); -static bool IsTransactionStmtList(List *parseTrees); +static bool IsTransactionExitStmtList(List *pstmts); +static bool IsTransactionStmtList(List *pstmts); static void drop_unnamed_stmt(void); static void SigHupHandler(SIGNAL_ARGS); static void log_disconnections(int code, Datum arg); @@ -588,8 +588,8 @@ ProcessClientWriteInterrupt(bool blocked) /* * Do raw parsing (only). * - * A list of parsetrees is returned, since there might be multiple - * commands in the given string. + * A list of parsetrees (RawStmt nodes) is returned, since there might be + * multiple commands in the given string. * * NOTE: for interactive queries, it is important to keep this routine * separate from the analysis & rewrite stages. Analysis and rewriting @@ -641,7 +641,7 @@ pg_parse_query(const char *query_string) * NOTE: for reasons mentioned above, this must be separate from raw parsing. */ List * -pg_analyze_and_rewrite(Node *parsetree, const char *query_string, +pg_analyze_and_rewrite(RawStmt *parsetree, const char *query_string, Oid *paramTypes, int numParams) { Query *query; @@ -676,7 +676,7 @@ pg_analyze_and_rewrite(Node *parsetree, const char *query_string, * hooks instead of a fixed list of parameter datatypes. */ List * -pg_analyze_and_rewrite_params(Node *parsetree, +pg_analyze_and_rewrite_params(RawStmt *parsetree, const char *query_string, ParserSetupHook parserSetup, void *parserSetupArg) @@ -833,8 +833,10 @@ pg_plan_query(Query *querytree, int cursorOptions, ParamListInfo boundParams) /* * Generate plans for a list of already-rewritten queries. * - * Normal optimizable statements generate PlannedStmt entries in the result - * list. Utility statements are simply represented by their statement nodes. + * For normal optimizable statements, invoke the planner. For utility + * statements, just make a wrapper PlannedStmt node. + * + * The result is a list of PlannedStmt nodes. */ List * pg_plan_queries(List *querytrees, int cursorOptions, ParamListInfo boundParams) @@ -845,16 +847,21 @@ pg_plan_queries(List *querytrees, int cursorOptions, ParamListInfo boundParams) foreach(query_list, querytrees) { Query *query = (Query *) lfirst(query_list); - Node *stmt; + PlannedStmt *stmt; if (query->commandType == CMD_UTILITY) { - /* Utility commands have no plans. */ - stmt = query->utilityStmt; + /* Utility commands require no planning. */ + stmt = makeNode(PlannedStmt); + stmt->commandType = CMD_UTILITY; + stmt->canSetTag = query->canSetTag; + stmt->utilityStmt = query->utilityStmt; + stmt->stmt_location = query->stmt_location; + stmt->stmt_len = query->stmt_len; } else { - stmt = (Node *) pg_plan_query(query, cursorOptions, boundParams); + stmt = pg_plan_query(query, cursorOptions, boundParams); } stmt_list = lappend(stmt_list, stmt); @@ -955,7 +962,7 @@ exec_simple_query(const char *query_string) */ foreach(parsetree_item, parsetree_list) { - Node *parsetree = (Node *) lfirst(parsetree_item); + RawStmt *parsetree = (RawStmt *) lfirst(parsetree_item); bool snapshot_set = false; const char *commandTag; char completionTag[COMPLETION_TAG_BUFSIZE]; @@ -971,7 +978,7 @@ exec_simple_query(const char *query_string) * do any special start-of-SQL-command processing needed by the * destination. */ - commandTag = CreateCommandTag(parsetree); + commandTag = CreateCommandTag(parsetree->stmt); set_ps_display(commandTag, false); @@ -986,7 +993,7 @@ exec_simple_query(const char *query_string) * state, but not many...) */ if (IsAbortedTransactionBlockState() && - !IsTransactionExitStmt(parsetree)) + !IsTransactionExitStmt(parsetree->stmt)) ereport(ERROR, (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION), errmsg("current transaction is aborted, " @@ -1061,9 +1068,9 @@ exec_simple_query(const char *query_string) * backward compatibility...) */ format = 0; /* TEXT is default */ - if (IsA(parsetree, FetchStmt)) + if (IsA(parsetree->stmt, FetchStmt)) { - FetchStmt *stmt = (FetchStmt *) parsetree; + FetchStmt *stmt = (FetchStmt *) parsetree->stmt; if (!stmt->ismove) { @@ -1102,7 +1109,7 @@ exec_simple_query(const char *query_string) PortalDrop(portal, false); - if (IsA(parsetree, TransactionStmt)) + if (IsA(parsetree->stmt, TransactionStmt)) { /* * If this was a transaction control statement, commit it. We will @@ -1194,7 +1201,7 @@ exec_parse_message(const char *query_string, /* string to execute */ MemoryContext unnamed_stmt_context = NULL; MemoryContext oldcontext; List *parsetree_list; - Node *raw_parse_tree; + RawStmt *raw_parse_tree; const char *commandTag; List *querytree_list; CachedPlanSource *psrc; @@ -1253,9 +1260,7 @@ exec_parse_message(const char *query_string, /* string to execute */ unnamed_stmt_context = AllocSetContextCreate(MessageContext, "unnamed prepared statement", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldcontext = MemoryContextSwitchTo(unnamed_stmt_context); } @@ -1281,12 +1286,12 @@ exec_parse_message(const char *query_string, /* string to execute */ bool snapshot_set = false; int i; - raw_parse_tree = (Node *) linitial(parsetree_list); + raw_parse_tree = (RawStmt *) linitial(parsetree_list); /* * Get the command name for possible use in status display. */ - commandTag = CreateCommandTag(raw_parse_tree); + commandTag = CreateCommandTag(raw_parse_tree->stmt); /* * If we are in an aborted transaction, reject all commands except @@ -1297,7 +1302,7 @@ exec_parse_message(const char *query_string, /* string to execute */ * state, but not many...) */ if (IsAbortedTransactionBlockState() && - !IsTransactionExitStmt(raw_parse_tree)) + !IsTransactionExitStmt(raw_parse_tree->stmt)) ereport(ERROR, (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION), errmsg("current transaction is aborted, " @@ -1554,7 +1559,8 @@ exec_bind_message(StringInfo input_message) * functions. */ if (IsAbortedTransactionBlockState() && - (!IsTransactionExitStmt(psrc->raw_parse_tree) || + (!(psrc->raw_parse_tree && + IsTransactionExitStmt(psrc->raw_parse_tree->stmt)) || numParams != 0)) ereport(ERROR, (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION), @@ -2142,11 +2148,11 @@ errdetail_execute(List *raw_parsetree_list) foreach(parsetree_item, raw_parsetree_list) { - Node *parsetree = (Node *) lfirst(parsetree_item); + RawStmt *parsetree = (RawStmt *) lfirst(parsetree_item); - if (IsA(parsetree, ExecuteStmt)) + if (IsA(parsetree->stmt, ExecuteStmt)) { - ExecuteStmt *stmt = (ExecuteStmt *) parsetree; + ExecuteStmt *stmt = (ExecuteStmt *) parsetree->stmt; PreparedStatement *pstmt; pstmt = FetchPreparedStatement(stmt->name, false); @@ -2429,8 +2435,6 @@ start_xact_command(void) { if (!xact_started) { - ereport(DEBUG3, - (errmsg_internal("StartTransactionCommand"))); StartTransactionCommand(); /* Set statement timeout running, if any */ @@ -2452,10 +2456,6 @@ finish_xact_command(void) /* Cancel any active statement timeout before committing */ disable_timeout(STATEMENT_TIMEOUT, false); - /* Now commit the command */ - ereport(DEBUG3, - (errmsg_internal("CommitTransactionCommand"))); - CommitTransactionCommand(); #ifdef MEMORY_CONTEXT_CHECKING @@ -2496,45 +2496,33 @@ IsTransactionExitStmt(Node *parsetree) return false; } -/* Test a list that might contain Query nodes or bare parsetrees */ +/* Test a list that contains PlannedStmt nodes */ static bool -IsTransactionExitStmtList(List *parseTrees) +IsTransactionExitStmtList(List *pstmts) { - if (list_length(parseTrees) == 1) + if (list_length(pstmts) == 1) { - Node *stmt = (Node *) linitial(parseTrees); - - if (IsA(stmt, Query)) - { - Query *query = (Query *) stmt; + PlannedStmt *pstmt = (PlannedStmt *) linitial(pstmts); - if (query->commandType == CMD_UTILITY && - IsTransactionExitStmt(query->utilityStmt)) - return true; - } - else if (IsTransactionExitStmt(stmt)) + Assert(IsA(pstmt, PlannedStmt)); + if (pstmt->commandType == CMD_UTILITY && + IsTransactionExitStmt(pstmt->utilityStmt)) return true; } return false; } -/* Test a list that might contain Query nodes or bare parsetrees */ +/* Test a list that contains PlannedStmt nodes */ static bool -IsTransactionStmtList(List *parseTrees) +IsTransactionStmtList(List *pstmts) { - if (list_length(parseTrees) == 1) + if (list_length(pstmts) == 1) { - Node *stmt = (Node *) linitial(parseTrees); - - if (IsA(stmt, Query)) - { - Query *query = (Query *) stmt; + PlannedStmt *pstmt = (PlannedStmt *) linitial(pstmts); - if (query->commandType == CMD_UTILITY && - IsA(query->utilityStmt, TransactionStmt)) - return true; - } - else if (IsA(stmt, TransactionStmt)) + Assert(IsA(pstmt, PlannedStmt)); + if (pstmt->commandType == CMD_UTILITY && + IsA(pstmt->utilityStmt, TransactionStmt)) return true; } return false; @@ -3770,8 +3758,7 @@ PostgresMain(int argc, char *argv[], /* * Send this backend's cancellation info to the frontend. */ - if (whereToSendOutput == DestRemote && - PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2) + if (whereToSendOutput == DestRemote) { StringInfoData buf; @@ -3794,9 +3781,7 @@ PostgresMain(int argc, char *argv[], */ MessageContext = AllocSetContextCreate(TopMemoryContext, "MessageContext", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* * Remember stand-alone backend startup time @@ -3889,6 +3874,9 @@ PostgresMain(int argc, char *argv[], if (MyReplicationSlot != NULL) ReplicationSlotRelease(); + /* We also want to cleanup temporary slots on error. */ + ReplicationSlotCleanup(); + /* * Now return to normal top-level context and clear ErrorContext for * next time. @@ -3951,6 +3939,12 @@ PostgresMain(int argc, char *argv[], initStringInfo(&input_message); + /* + * Also consider releasing our catalog snapshot if any, so that it's + * not preventing advance of global xmin while we wait for the client. + */ + InvalidateCatalogSnapshotConditionally(); + /* * (1) If we've reached idle state, tell the frontend we're ready for * a new query. @@ -4427,15 +4421,15 @@ ShowUsage(const char *title) appendStringInfoString(&str, "! system usage stats:\n"); appendStringInfo(&str, - "!\t%ld.%06ld elapsed %ld.%06ld user %ld.%06ld system sec\n", - (long) (elapse_t.tv_sec - Save_t.tv_sec), - (long) (elapse_t.tv_usec - Save_t.tv_usec), + "!\t%ld.%06ld s user, %ld.%06ld s system, %ld.%06ld s elapsed\n", (long) (r.ru_utime.tv_sec - Save_r.ru_utime.tv_sec), (long) (r.ru_utime.tv_usec - Save_r.ru_utime.tv_usec), (long) (r.ru_stime.tv_sec - Save_r.ru_stime.tv_sec), - (long) (r.ru_stime.tv_usec - Save_r.ru_stime.tv_usec)); + (long) (r.ru_stime.tv_usec - Save_r.ru_stime.tv_usec), + (long) (elapse_t.tv_sec - Save_t.tv_sec), + (long) (elapse_t.tv_usec - Save_t.tv_usec)); appendStringInfo(&str, - "!\t[%ld.%06ld user %ld.%06ld sys total]\n", + "!\t[%ld.%06ld s user, %ld.%06ld s system total]\n", (long) user.tv_sec, (long) user.tv_usec, (long) sys.tv_sec, diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c index 92d07fcb5d..704be399cf 100644 --- a/src/backend/tcop/pquery.c +++ b/src/backend/tcop/pquery.c @@ -3,7 +3,7 @@ * pquery.c * POSTGRES process query command code * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -43,7 +43,7 @@ static uint64 RunFromStore(Portal portal, ScanDirection direction, uint64 count, DestReceiver *dest); static uint64 PortalRunSelect(Portal portal, bool forward, long count, DestReceiver *dest); -static void PortalRunUtility(Portal portal, Node *utilityStmt, +static void PortalRunUtility(Portal portal, PlannedStmt *pstmt, bool isTopLevel, bool setHoldSnapshot, DestReceiver *dest, char *completionTag); static void PortalRunMulti(Portal portal, @@ -73,7 +73,6 @@ CreateQueryDesc(PlannedStmt *plannedstmt, qd->operation = plannedstmt->commandType; /* operation */ qd->plannedstmt = plannedstmt; /* plan */ - qd->utilitystmt = plannedstmt->utilityStmt; /* in case DECLARE CURSOR */ qd->sourceText = sourceText; /* query text */ qd->snapshot = RegisterSnapshot(snapshot); /* snapshot */ /* RI check snapshot */ @@ -92,37 +91,6 @@ CreateQueryDesc(PlannedStmt *plannedstmt, return qd; } -/* - * CreateUtilityQueryDesc - */ -QueryDesc * -CreateUtilityQueryDesc(Node *utilitystmt, - const char *sourceText, - Snapshot snapshot, - DestReceiver *dest, - ParamListInfo params) -{ - QueryDesc *qd = (QueryDesc *) palloc(sizeof(QueryDesc)); - - qd->operation = CMD_UTILITY; /* operation */ - qd->plannedstmt = NULL; - qd->utilitystmt = utilitystmt; /* utility command */ - qd->sourceText = sourceText; /* query text */ - qd->snapshot = RegisterSnapshot(snapshot); /* snapshot */ - qd->crosscheck_snapshot = InvalidSnapshot; /* RI check snapshot */ - qd->dest = dest; /* output dest */ - qd->params = params; /* parameter values passed into query */ - qd->instrument_options = false; /* uninteresting for utilities */ - - /* null these fields until set by ExecutorStart */ - qd->tupDesc = NULL; - qd->estate = NULL; - qd->planstate = NULL; - qd->totaltime = NULL; - - return qd; -} - /* * FreeQueryDesc */ @@ -167,8 +135,6 @@ ProcessQuery(PlannedStmt *plan, { QueryDesc *queryDesc; - elog(DEBUG3, "ProcessQuery"); - /* * Create the QueryDesc object */ @@ -238,7 +204,7 @@ ProcessQuery(PlannedStmt *plan, * ChoosePortalStrategy * Select portal execution strategy given the intended statement list. * - * The list elements can be Querys, PlannedStmts, or utility statements. + * The list elements can be Querys or PlannedStmts. * That's more general than portals need, but plancache.c uses this too. * * See the comments in portal.h. @@ -265,16 +231,14 @@ ChoosePortalStrategy(List *stmts) if (query->canSetTag) { - if (query->commandType == CMD_SELECT && - query->utilityStmt == NULL) + if (query->commandType == CMD_SELECT) { if (query->hasModifyingCTE) return PORTAL_ONE_MOD_WITH; else return PORTAL_ONE_SELECT; } - if (query->commandType == CMD_UTILITY && - query->utilityStmt != NULL) + if (query->commandType == CMD_UTILITY) { if (UtilityReturnsTuples(query->utilityStmt)) return PORTAL_UTIL_SELECT; @@ -289,24 +253,24 @@ ChoosePortalStrategy(List *stmts) if (pstmt->canSetTag) { - if (pstmt->commandType == CMD_SELECT && - pstmt->utilityStmt == NULL) + if (pstmt->commandType == CMD_SELECT) { if (pstmt->hasModifyingCTE) return PORTAL_ONE_MOD_WITH; else return PORTAL_ONE_SELECT; } + if (pstmt->commandType == CMD_UTILITY) + { + if (UtilityReturnsTuples(pstmt->utilityStmt)) + return PORTAL_UTIL_SELECT; + /* it can't be ONE_RETURNING, so give up */ + return PORTAL_MULTI_QUERY; + } } } else - { - /* must be a utility command; assume it's canSetTag */ - if (UtilityReturnsTuples(stmt)) - return PORTAL_UTIL_SELECT; - /* it can't be ONE_RETURNING, so give up */ - return PORTAL_MULTI_QUERY; - } + elog(ERROR, "unrecognized node type: %d", (int) nodeTag(stmt)); } /* @@ -327,7 +291,8 @@ ChoosePortalStrategy(List *stmts) { if (++nSetTag > 1) return PORTAL_MULTI_QUERY; /* no need to look further */ - if (query->returningList == NIL) + if (query->commandType == CMD_UTILITY || + query->returningList == NIL) return PORTAL_MULTI_QUERY; /* no need to look further */ } } @@ -339,11 +304,13 @@ ChoosePortalStrategy(List *stmts) { if (++nSetTag > 1) return PORTAL_MULTI_QUERY; /* no need to look further */ - if (!pstmt->hasReturning) + if (pstmt->commandType == CMD_UTILITY || + !pstmt->hasReturning) return PORTAL_MULTI_QUERY; /* no need to look further */ } } - /* otherwise, utility command, assumed not canSetTag */ + else + elog(ERROR, "unrecognized node type: %d", (int) nodeTag(stmt)); } if (nSetTag == 1) return PORTAL_ONE_RETURNING; @@ -366,7 +333,7 @@ FetchPortalTargetList(Portal portal) if (portal->strategy == PORTAL_MULTI_QUERY) return NIL; /* get the primary statement and find out what it returns */ - return FetchStatementTargetList(PortalGetPrimaryStmt(portal)); + return FetchStatementTargetList((Node *) PortalGetPrimaryStmt(portal)); } /* @@ -374,7 +341,7 @@ FetchPortalTargetList(Portal portal) * Given a statement that returns tuples, extract the query targetlist. * Returns NIL if the statement doesn't have a determinable targetlist. * - * This can be applied to a Query, a PlannedStmt, or a utility statement. + * This can be applied to a Query or a PlannedStmt. * That's more general than portals need, but plancache.c uses this too. * * Note: do not modify the result. @@ -390,16 +357,14 @@ FetchStatementTargetList(Node *stmt) { Query *query = (Query *) stmt; - if (query->commandType == CMD_UTILITY && - query->utilityStmt != NULL) + if (query->commandType == CMD_UTILITY) { /* transfer attention to utility statement */ stmt = query->utilityStmt; } else { - if (query->commandType == CMD_SELECT && - query->utilityStmt == NULL) + if (query->commandType == CMD_SELECT) return query->targetList; if (query->returningList) return query->returningList; @@ -410,12 +375,19 @@ FetchStatementTargetList(Node *stmt) { PlannedStmt *pstmt = (PlannedStmt *) stmt; - if (pstmt->commandType == CMD_SELECT && - pstmt->utilityStmt == NULL) - return pstmt->planTree->targetlist; - if (pstmt->hasReturning) - return pstmt->planTree->targetlist; - return NIL; + if (pstmt->commandType == CMD_UTILITY) + { + /* transfer attention to utility statement */ + stmt = pstmt->utilityStmt; + } + else + { + if (pstmt->commandType == CMD_SELECT) + return pstmt->planTree->targetlist; + if (pstmt->hasReturning) + return pstmt->planTree->targetlist; + return NIL; + } } if (IsA(stmt, FetchStmt)) { @@ -568,8 +540,7 @@ PortalStart(Portal portal, ParamListInfo params, { PlannedStmt *pstmt; - pstmt = (PlannedStmt *) PortalGetPrimaryStmt(portal); - Assert(IsA(pstmt, PlannedStmt)); + pstmt = PortalGetPrimaryStmt(portal); portal->tupDesc = ExecCleanTypeFromTL(pstmt->planTree->targetlist, false); @@ -590,10 +561,10 @@ PortalStart(Portal portal, ParamListInfo params, * take care of it if needed. */ { - Node *ustmt = PortalGetPrimaryStmt(portal); + PlannedStmt *pstmt = PortalGetPrimaryStmt(portal); - Assert(!IsA(ustmt, PlannedStmt)); - portal->tupDesc = UtilityTupleDescriptor(ustmt); + Assert(pstmt->commandType == CMD_UTILITY); + portal->tupDesc = UtilityTupleDescriptor(pstmt->utilityStmt); } /* @@ -1049,7 +1020,7 @@ FillPortalStore(Portal portal, bool isTopLevel) break; case PORTAL_UTIL_SELECT: - PortalRunUtility(portal, (Node *) linitial(portal->stmts), + PortalRunUtility(portal, (PlannedStmt *) linitial(portal->stmts), isTopLevel, true, treceiver, completionTag); break; @@ -1145,14 +1116,13 @@ RunFromStore(Portal portal, ScanDirection direction, uint64 count, * Execute a utility statement inside a portal. */ static void -PortalRunUtility(Portal portal, Node *utilityStmt, +PortalRunUtility(Portal portal, PlannedStmt *pstmt, bool isTopLevel, bool setHoldSnapshot, DestReceiver *dest, char *completionTag) { + Node *utilityStmt = pstmt->utilityStmt; Snapshot snapshot; - elog(DEBUG3, "ProcessUtility"); - /* * Set snapshot if utility stmt needs one. Most reliable way to do this * seems to be to enumerate those that do not need one; this is a short @@ -1190,7 +1160,7 @@ PortalRunUtility(Portal portal, Node *utilityStmt, else snapshot = NULL; - ProcessUtility(utilityStmt, + ProcessUtility(pstmt, portal->sourceText, isTopLevel ? PROCESS_UTILITY_TOPLEVEL : PROCESS_UTILITY_QUERY, portal->portalParams, @@ -1245,21 +1215,18 @@ PortalRunMulti(Portal portal, */ foreach(stmtlist_item, portal->stmts) { - Node *stmt = (Node *) lfirst(stmtlist_item); + PlannedStmt *pstmt = (PlannedStmt *) lfirst(stmtlist_item); /* * If we got a cancel signal in prior command, quit */ CHECK_FOR_INTERRUPTS(); - if (IsA(stmt, PlannedStmt) && - ((PlannedStmt *) stmt)->utilityStmt == NULL) + if (pstmt->utilityStmt == NULL) { /* * process a plannable query. */ - PlannedStmt *pstmt = (PlannedStmt *) stmt; - TRACE_POSTGRESQL_QUERY_EXECUTE_START(); if (log_executor_stats) @@ -1324,9 +1291,6 @@ PortalRunMulti(Portal portal, /* * process utility functions (create, destroy, etc..) * - * These are assumed canSetTag if they're the only stmt in the - * portal. - * * We must not set a snapshot here for utility commands (if one is * needed, PortalRunUtility will do it). If a utility command is * alone in a portal then everything's fine. The only case where @@ -1335,18 +1299,18 @@ PortalRunMulti(Portal portal, * whether it has a snapshot or not, so we just leave the current * snapshot alone if we have one. */ - if (list_length(portal->stmts) == 1) + if (pstmt->canSetTag) { Assert(!active_snapshot_set); /* statement can set tag string */ - PortalRunUtility(portal, stmt, isTopLevel, false, + PortalRunUtility(portal, pstmt, isTopLevel, false, dest, completionTag); } else { - Assert(IsA(stmt, NotifyStmt)); + Assert(IsA(pstmt->utilityStmt, NotifyStmt)); /* stmt added by rewrite cannot set tag */ - PortalRunUtility(portal, stmt, isTopLevel, false, + PortalRunUtility(portal, pstmt, isTopLevel, false, altdest, NULL); } } diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index ac50c2a03d..0306247177 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -5,7 +5,7 @@ * commands. At one time acted as an interface between the Lisp and C * systems. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -44,9 +44,11 @@ #include "commands/portalcmds.h" #include "commands/prepare.h" #include "commands/proclang.h" +#include "commands/publicationcmds.h" #include "commands/schemacmds.h" #include "commands/seclabel.h" #include "commands/sequence.h" +#include "commands/subscriptioncmds.h" #include "commands/tablecmds.h" #include "commands/tablespace.h" #include "commands/trigger.h" @@ -71,7 +73,8 @@ ProcessUtility_hook_type ProcessUtility_hook = NULL; /* local function declarations */ -static void ProcessUtilitySlow(Node *parsetree, +static void ProcessUtilitySlow(ParseState *pstate, + PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, @@ -87,35 +90,33 @@ static void ExecDropStmt(DropStmt *stmt, bool isTopLevel); * the query must be *in truth* read-only, because the caller wishes * not to do CommandCounterIncrement for it. * - * Note: currently no need to support Query nodes here + * Note: currently no need to support raw or analyzed queries here */ bool -CommandIsReadOnly(Node *parsetree) +CommandIsReadOnly(PlannedStmt *pstmt) { - if (IsA(parsetree, PlannedStmt)) + Assert(IsA(pstmt, PlannedStmt)); + switch (pstmt->commandType) { - PlannedStmt *stmt = (PlannedStmt *) parsetree; - - switch (stmt->commandType) - { - case CMD_SELECT: - if (stmt->rowMarks != NIL) - return false; /* SELECT FOR [KEY] UPDATE/SHARE */ - else if (stmt->hasModifyingCTE) - return false; /* data-modifying CTE */ - else - return true; - case CMD_UPDATE: - case CMD_INSERT: - case CMD_DELETE: - return false; - default: - elog(WARNING, "unrecognized commandType: %d", - (int) stmt->commandType); - break; - } + case CMD_SELECT: + if (pstmt->rowMarks != NIL) + return false; /* SELECT FOR [KEY] UPDATE/SHARE */ + else if (pstmt->hasModifyingCTE) + return false; /* data-modifying CTE */ + else + return true; + case CMD_UPDATE: + case CMD_INSERT: + case CMD_DELETE: + return false; + case CMD_UTILITY: + /* For now, treat all utility commands as read/write */ + return false; + default: + elog(WARNING, "unrecognized commandType: %d", + (int) pstmt->commandType); + break; } - /* For now, treat all utility commands as read/write */ return false; } @@ -210,6 +211,11 @@ check_xact_readonly(Node *parsetree) case T_CreateForeignTableStmt: case T_ImportForeignSchemaStmt: case T_SecLabelStmt: + case T_CreatePublicationStmt: + case T_AlterPublicationStmt: + case T_CreateSubscriptionStmt: + case T_AlterSubscriptionStmt: + case T_DropSubscriptionStmt: PreventCommandIfReadOnly(CreateCommandTag(parsetree)); PreventCommandIfParallelMode(CreateCommandTag(parsetree)); break; @@ -296,7 +302,7 @@ CheckRestrictedOperation(const char *cmdname) * ProcessUtility * general utility function invoker * - * parsetree: the parse tree for the utility statement + * pstmt: PlannedStmt wrapper for the utility statement * queryString: original source text of command * context: identifies source of statement (toplevel client command, * non-toplevel client command, subcommand of a larger utility command) @@ -314,13 +320,15 @@ CheckRestrictedOperation(const char *cmdname) * completionTag may be NULL if caller doesn't want a status string. */ void -ProcessUtility(Node *parsetree, +ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag) { + Assert(IsA(pstmt, PlannedStmt)); + Assert(pstmt->commandType == CMD_UTILITY); Assert(queryString != NULL); /* required as of 8.4 */ /* @@ -329,11 +337,11 @@ ProcessUtility(Node *parsetree, * call standard_ProcessUtility(). */ if (ProcessUtility_hook) - (*ProcessUtility_hook) (parsetree, queryString, + (*ProcessUtility_hook) (pstmt, queryString, context, params, dest, completionTag); else - standard_ProcessUtility(parsetree, queryString, + standard_ProcessUtility(pstmt, queryString, context, params, dest, completionTag); } @@ -350,20 +358,25 @@ ProcessUtility(Node *parsetree, * which requires being in a valid transaction. */ void -standard_ProcessUtility(Node *parsetree, +standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag) { + Node *parsetree = pstmt->utilityStmt; bool isTopLevel = (context == PROCESS_UTILITY_TOPLEVEL); + ParseState *pstate; check_xact_readonly(parsetree); if (completionTag) completionTag[0] = '\0'; + pstate = make_parsestate(NULL); + pstate->p_sourcetext = queryString; + switch (nodeTag(parsetree)) { /* @@ -481,20 +494,10 @@ standard_ProcessUtility(Node *parsetree, /* * Portal (cursor) manipulation - * - * Note: DECLARE CURSOR is processed mostly as a SELECT, and - * therefore what we will get here is a PlannedStmt not a bare - * DeclareCursorStmt. */ - case T_PlannedStmt: - { - PlannedStmt *stmt = (PlannedStmt *) parsetree; - - if (stmt->utilityStmt == NULL || - !IsA(stmt->utilityStmt, DeclareCursorStmt)) - elog(ERROR, "non-DECLARE CURSOR PlannedStmt passed to ProcessUtility"); - PerformCursorOpen(stmt, params, queryString, isTopLevel); - } + case T_DeclareCursorStmt: + PerformCursorOpen((DeclareCursorStmt *) parsetree, params, + queryString, isTopLevel); break; case T_ClosePortalStmt: @@ -540,7 +543,9 @@ standard_ProcessUtility(Node *parsetree, { uint64 processed; - DoCopy((CopyStmt *) parsetree, queryString, &processed); + DoCopy(pstate, (CopyStmt *) parsetree, + pstmt->stmt_location, pstmt->stmt_len, + &processed); if (completionTag) snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "COPY " UINT64_FORMAT, processed); @@ -549,7 +554,8 @@ standard_ProcessUtility(Node *parsetree, case T_PrepareStmt: CheckRestrictedOperation("PREPARE"); - PrepareQuery((PrepareStmt *) parsetree, queryString); + PrepareQuery((PrepareStmt *) parsetree, queryString, + pstmt->stmt_location, pstmt->stmt_len); break; case T_ExecuteStmt: @@ -571,12 +577,12 @@ standard_ProcessUtility(Node *parsetree, case T_CreatedbStmt: /* no event triggers for global objects */ PreventTransactionChain(isTopLevel, "CREATE DATABASE"); - createdb((CreatedbStmt *) parsetree); + createdb(pstate, (CreatedbStmt *) parsetree); break; case T_AlterDatabaseStmt: /* no event triggers for global objects */ - AlterDatabase((AlterDatabaseStmt *) parsetree, isTopLevel); + AlterDatabase(pstate, (AlterDatabaseStmt *) parsetree, isTopLevel); break; case T_AlterDatabaseSetStmt: @@ -657,7 +663,7 @@ standard_ProcessUtility(Node *parsetree, break; case T_ExplainStmt: - ExplainQuery((ExplainStmt *) parsetree, queryString, params, dest); + ExplainQuery(pstate, (ExplainStmt *) parsetree, queryString, params, dest); break; case T_AlterSystemStmt: @@ -698,7 +704,7 @@ standard_ProcessUtility(Node *parsetree, */ case T_CreateRoleStmt: /* no event triggers for global objects */ - CreateRole((CreateRoleStmt *) parsetree); + CreateRole(pstate, (CreateRoleStmt *) parsetree); break; case T_AlterRoleStmt: @@ -803,11 +809,11 @@ standard_ProcessUtility(Node *parsetree, GrantStmt *stmt = (GrantStmt *) parsetree; if (EventTriggerSupportsGrantObjectType(stmt->objtype)) - ProcessUtilitySlow(parsetree, queryString, + ProcessUtilitySlow(pstate, pstmt, queryString, context, params, dest, completionTag); else - ExecuteGrantStmt((GrantStmt *) parsetree); + ExecuteGrantStmt(stmt); } break; @@ -816,7 +822,7 @@ standard_ProcessUtility(Node *parsetree, DropStmt *stmt = (DropStmt *) parsetree; if (EventTriggerSupportsObjectType(stmt->removeType)) - ProcessUtilitySlow(parsetree, queryString, + ProcessUtilitySlow(pstate, pstmt, queryString, context, params, dest, completionTag); else @@ -829,7 +835,7 @@ standard_ProcessUtility(Node *parsetree, RenameStmt *stmt = (RenameStmt *) parsetree; if (EventTriggerSupportsObjectType(stmt->renameType)) - ProcessUtilitySlow(parsetree, queryString, + ProcessUtilitySlow(pstate, pstmt, queryString, context, params, dest, completionTag); else @@ -842,7 +848,7 @@ standard_ProcessUtility(Node *parsetree, AlterObjectDependsStmt *stmt = (AlterObjectDependsStmt *) parsetree; if (EventTriggerSupportsObjectType(stmt->objectType)) - ProcessUtilitySlow(parsetree, queryString, + ProcessUtilitySlow(pstate, pstmt, queryString, context, params, dest, completionTag); else @@ -855,7 +861,7 @@ standard_ProcessUtility(Node *parsetree, AlterObjectSchemaStmt *stmt = (AlterObjectSchemaStmt *) parsetree; if (EventTriggerSupportsObjectType(stmt->objectType)) - ProcessUtilitySlow(parsetree, queryString, + ProcessUtilitySlow(pstate, pstmt, queryString, context, params, dest, completionTag); else @@ -868,7 +874,7 @@ standard_ProcessUtility(Node *parsetree, AlterOwnerStmt *stmt = (AlterOwnerStmt *) parsetree; if (EventTriggerSupportsObjectType(stmt->objectType)) - ProcessUtilitySlow(parsetree, queryString, + ProcessUtilitySlow(pstate, pstmt, queryString, context, params, dest, completionTag); else @@ -881,11 +887,11 @@ standard_ProcessUtility(Node *parsetree, CommentStmt *stmt = (CommentStmt *) parsetree; if (EventTriggerSupportsObjectType(stmt->objtype)) - ProcessUtilitySlow(parsetree, queryString, + ProcessUtilitySlow(pstate, pstmt, queryString, context, params, dest, completionTag); else - CommentObject((CommentStmt *) parsetree); + CommentObject(stmt); break; } @@ -894,7 +900,7 @@ standard_ProcessUtility(Node *parsetree, SecLabelStmt *stmt = (SecLabelStmt *) parsetree; if (EventTriggerSupportsObjectType(stmt->objtype)) - ProcessUtilitySlow(parsetree, queryString, + ProcessUtilitySlow(pstate, pstmt, queryString, context, params, dest, completionTag); else @@ -904,11 +910,13 @@ standard_ProcessUtility(Node *parsetree, default: /* All other statement types have event trigger support */ - ProcessUtilitySlow(parsetree, queryString, + ProcessUtilitySlow(pstate, pstmt, queryString, context, params, dest, completionTag); break; } + + free_parsestate(pstate); } /* @@ -917,13 +925,15 @@ standard_ProcessUtility(Node *parsetree, * perform the trigger support calls if the context allows it. */ static void -ProcessUtilitySlow(Node *parsetree, +ProcessUtilitySlow(ParseState *pstate, + PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag) { + Node *parsetree = pstmt->utilityStmt; bool isTopLevel = (context == PROCESS_UTILITY_TOPLEVEL); bool isCompleteQuery = (context <= PROCESS_UTILITY_QUERY); bool needCleanup; @@ -947,7 +957,9 @@ ProcessUtilitySlow(Node *parsetree, */ case T_CreateSchemaStmt: CreateSchemaCommand((CreateSchemaStmt *) parsetree, - queryString); + queryString, + pstmt->stmt_location, + pstmt->stmt_len); /* * EventTriggerCollectSimpleCommand called by @@ -979,7 +991,8 @@ ProcessUtilitySlow(Node *parsetree, /* Create the table itself */ address = DefineRelation((CreateStmt *) stmt, RELKIND_RELATION, - InvalidOid, NULL); + InvalidOid, NULL, + queryString); EventTriggerCollectSimpleCommand(address, secondaryObject, stmt); @@ -1012,7 +1025,8 @@ ProcessUtilitySlow(Node *parsetree, /* Create the table itself */ address = DefineRelation((CreateStmt *) stmt, RELKIND_FOREIGN_TABLE, - InvalidOid, NULL); + InvalidOid, NULL, + queryString); CreateForeignTable((CreateForeignTableStmt *) stmt, address.objectId); EventTriggerCollectSimpleCommand(address, @@ -1026,7 +1040,16 @@ ProcessUtilitySlow(Node *parsetree, * call will stash the objects so created into our * event trigger context. */ - ProcessUtility(stmt, + PlannedStmt *wrapper; + + wrapper = makeNode(PlannedStmt); + wrapper->commandType = CMD_UTILITY; + wrapper->canSetTag = false; + wrapper->utilityStmt = stmt; + wrapper->stmt_location = pstmt->stmt_location; + wrapper->stmt_len = pstmt->stmt_len; + + ProcessUtility(wrapper, queryString, PROCESS_UTILITY_SUBCOMMAND, params, @@ -1095,8 +1118,16 @@ ProcessUtilitySlow(Node *parsetree, * queued commands is consistent with the way * they are executed here. */ + PlannedStmt *wrapper; + EventTriggerAlterTableEnd(); - ProcessUtility(stmt, + wrapper = makeNode(PlannedStmt); + wrapper->commandType = CMD_UTILITY; + wrapper->canSetTag = false; + wrapper->utilityStmt = stmt; + wrapper->stmt_location = pstmt->stmt_location; + wrapper->stmt_len = pstmt->stmt_len; + ProcessUtility(wrapper, queryString, PROCESS_UTILITY_SUBCOMMAND, params, @@ -1191,9 +1222,9 @@ ProcessUtilitySlow(Node *parsetree, { case OBJECT_AGGREGATE: address = - DefineAggregate(stmt->defnames, stmt->args, + DefineAggregate(pstate, stmt->defnames, stmt->args, stmt->oldstyle, - stmt->definition, queryString); + stmt->definition); break; case OBJECT_OPERATOR: Assert(stmt->args == NIL); @@ -1202,7 +1233,8 @@ ProcessUtilitySlow(Node *parsetree, break; case OBJECT_TYPE: Assert(stmt->args == NIL); - address = DefineType(stmt->defnames, + address = DefineType(pstate, + stmt->defnames, stmt->definition); break; case OBJECT_TSPARSER: @@ -1228,7 +1260,8 @@ ProcessUtilitySlow(Node *parsetree, break; case OBJECT_COLLATION: Assert(stmt->args == NIL); - address = DefineCollation(stmt->defnames, + address = DefineCollation(pstate, + stmt->defnames, stmt->definition); break; default: @@ -1293,11 +1326,11 @@ ProcessUtilitySlow(Node *parsetree, break; case T_CreateExtensionStmt: - address = CreateExtension((CreateExtensionStmt *) parsetree); + address = CreateExtension(pstate, (CreateExtensionStmt *) parsetree); break; case T_AlterExtensionStmt: - address = ExecAlterExtensionStmt((AlterExtensionStmt *) parsetree); + address = ExecAlterExtensionStmt(pstate, (AlterExtensionStmt *) parsetree); break; case T_AlterExtensionContentsStmt: @@ -1359,12 +1392,13 @@ ProcessUtilitySlow(Node *parsetree, break; case T_AlterEnumStmt: /* ALTER TYPE (enum) */ - address = AlterEnum((AlterEnumStmt *) parsetree, isTopLevel); + address = AlterEnum((AlterEnumStmt *) parsetree); break; case T_ViewStmt: /* CREATE VIEW */ EventTriggerAlterTableStart(parsetree); - address = DefineView((ViewStmt *) parsetree, queryString); + address = DefineView((ViewStmt *) parsetree, queryString, + pstmt->stmt_location, pstmt->stmt_len); EventTriggerCollectSimpleCommand(address, secondaryObject, parsetree); /* stashed internally */ @@ -1373,11 +1407,11 @@ ProcessUtilitySlow(Node *parsetree, break; case T_CreateFunctionStmt: /* CREATE FUNCTION */ - address = CreateFunction((CreateFunctionStmt *) parsetree, queryString); + address = CreateFunction(pstate, (CreateFunctionStmt *) parsetree); break; case T_AlterFunctionStmt: /* ALTER FUNCTION */ - address = AlterFunction((AlterFunctionStmt *) parsetree); + address = AlterFunction(pstate, (AlterFunctionStmt *) parsetree); break; case T_RuleStmt: /* CREATE RULE */ @@ -1385,11 +1419,11 @@ ProcessUtilitySlow(Node *parsetree, break; case T_CreateSeqStmt: - address = DefineSequence((CreateSeqStmt *) parsetree); + address = DefineSequence(pstate, (CreateSeqStmt *) parsetree); break; case T_AlterSeqStmt: - address = AlterSequence((AlterSeqStmt *) parsetree); + address = AlterSequence(pstate, (AlterSeqStmt *) parsetree); break; case T_CreateTableAsStmt: @@ -1467,7 +1501,14 @@ ProcessUtilitySlow(Node *parsetree, break; case T_AlterTSConfigurationStmt: - address = AlterTSConfiguration((AlterTSConfigurationStmt *) parsetree); + AlterTSConfiguration((AlterTSConfigurationStmt *) parsetree); + + /* + * Commands are stashed in MakeConfigurationMapping and + * DropConfigurationMapping, which are called from + * AlterTSConfiguration + */ + commandCollected = true; break; case T_AlterTableMoveAllStmt: @@ -1523,7 +1564,7 @@ ProcessUtilitySlow(Node *parsetree, break; case T_AlterDefaultPrivilegesStmt: - ExecAlterDefaultPrivilegesStmt((AlterDefaultPrivilegesStmt *) parsetree); + ExecAlterDefaultPrivilegesStmt(pstate, (AlterDefaultPrivilegesStmt *) parsetree); EventTriggerCollectAlterDefPrivs((AlterDefaultPrivilegesStmt *) parsetree); commandCollected = true; break; @@ -1544,6 +1585,33 @@ ProcessUtilitySlow(Node *parsetree, address = CreateAccessMethod((CreateAmStmt *) parsetree); break; + case T_CreatePublicationStmt: + address = CreatePublication((CreatePublicationStmt *) parsetree); + break; + + case T_AlterPublicationStmt: + AlterPublication((AlterPublicationStmt *) parsetree); + /* + * AlterPublication calls EventTriggerCollectSimpleCommand + * directly + */ + commandCollected = true; + break; + + case T_CreateSubscriptionStmt: + address = CreateSubscription((CreateSubscriptionStmt *) parsetree); + break; + + case T_AlterSubscriptionStmt: + address = AlterSubscription((AlterSubscriptionStmt *) parsetree); + break; + + case T_DropSubscriptionStmt: + DropSubscription((DropSubscriptionStmt *) parsetree); + /* no commands stashed for DROP */ + commandCollected = true; + break; + default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(parsetree)); @@ -1718,10 +1786,8 @@ QueryReturnsTuples(Query *parsetree) switch (parsetree->commandType) { case CMD_SELECT: - /* returns tuples ... unless it's DECLARE CURSOR */ - if (parsetree->utilityStmt == NULL) - return true; - break; + /* returns tuples */ + return true; case CMD_INSERT: case CMD_UPDATE: case CMD_DELETE: @@ -1762,6 +1828,13 @@ UtilityContainsQuery(Node *parsetree) switch (nodeTag(parsetree)) { + case T_DeclareCursorStmt: + qry = (Query *) ((DeclareCursorStmt *) parsetree)->query; + Assert(IsA(qry, Query)); + if (qry->commandType == CMD_UTILITY) + return UtilityContainsQuery(qry->utilityStmt); + return qry; + case T_ExplainStmt: qry = (Query *) ((ExplainStmt *) parsetree)->query; Assert(IsA(qry, Query)); @@ -1902,6 +1975,12 @@ AlterObjectTypeCommandTag(ObjectType objtype) case OBJECT_MATVIEW: tag = "ALTER MATERIALIZED VIEW"; break; + case OBJECT_PUBLICATION: + tag = "ALTER PUBLICATION"; + break; + case OBJECT_SUBSCRIPTION: + tag = "ALTER SUBSCRIPTION"; + break; default: tag = "???"; break; @@ -1913,7 +1992,8 @@ AlterObjectTypeCommandTag(ObjectType objtype) /* * CreateCommandTag * utility to get a string representation of the command operation, - * given either a raw (un-analyzed) parsetree or a planned query. + * given either a raw (un-analyzed) parsetree, an analyzed Query, + * or a PlannedStmt. * * This must handle all command types, but since the vast majority * of 'em are utility commands, it seems sensible to keep it here. @@ -1928,6 +2008,11 @@ CreateCommandTag(Node *parsetree) switch (nodeTag(parsetree)) { + /* recurse if we're given a RawStmt */ + case T_RawStmt: + tag = CreateCommandTag(((RawStmt *) parsetree)->stmt); + break; + /* raw plannable queries */ case T_InsertStmt: tag = "INSERT"; @@ -2187,6 +2272,9 @@ CreateCommandTag(Node *parsetree) case OBJECT_ACCESS_METHOD: tag = "DROP ACCESS METHOD"; break; + case OBJECT_PUBLICATION: + tag = "DROP PUBLICATION"; + break; default: tag = "???"; } @@ -2557,6 +2645,26 @@ CreateCommandTag(Node *parsetree) tag = "CREATE ACCESS METHOD"; break; + case T_CreatePublicationStmt: + tag = "CREATE PUBLICATION"; + break; + + case T_AlterPublicationStmt: + tag = "ALTER PUBLICATION"; + break; + + case T_CreateSubscriptionStmt: + tag = "CREATE SUBSCRIPTION"; + break; + + case T_AlterSubscriptionStmt: + tag = "ALTER SUBSCRIPTION"; + break; + + case T_DropSubscriptionStmt: + tag = "DROP SUBSCRIPTION"; + break; + case T_PrepareStmt: tag = "PREPARE"; break; @@ -2590,12 +2698,7 @@ CreateCommandTag(Node *parsetree) * will be useful for complaints about read-only * statements */ - if (stmt->utilityStmt != NULL) - { - Assert(IsA(stmt->utilityStmt, DeclareCursorStmt)); - tag = "DECLARE CURSOR"; - } - else if (stmt->rowMarks != NIL) + if (stmt->rowMarks != NIL) { /* not 100% but probably close enough */ switch (((PlanRowMark *) linitial(stmt->rowMarks))->strength) @@ -2629,6 +2732,9 @@ CreateCommandTag(Node *parsetree) case CMD_DELETE: tag = "DELETE"; break; + case CMD_UTILITY: + tag = CreateCommandTag(stmt->utilityStmt); + break; default: elog(WARNING, "unrecognized commandType: %d", (int) stmt->commandType); @@ -2652,12 +2758,7 @@ CreateCommandTag(Node *parsetree) * will be useful for complaints about read-only * statements */ - if (stmt->utilityStmt != NULL) - { - Assert(IsA(stmt->utilityStmt, DeclareCursorStmt)); - tag = "DECLARE CURSOR"; - } - else if (stmt->rowMarks != NIL) + if (stmt->rowMarks != NIL) { /* not 100% but probably close enough */ switch (((RowMarkClause *) linitial(stmt->rowMarks))->strength) @@ -2717,7 +2818,8 @@ CreateCommandTag(Node *parsetree) /* * GetCommandLogLevel * utility to get the minimum log_statement level for a command, - * given either a raw (un-analyzed) parsetree or a planned query. + * given either a raw (un-analyzed) parsetree, an analyzed Query, + * or a PlannedStmt. * * This must handle all command types, but since the vast majority * of 'em are utility commands, it seems sensible to keep it here. @@ -2729,6 +2831,11 @@ GetCommandLogLevel(Node *parsetree) switch (nodeTag(parsetree)) { + /* recurse if we're given a RawStmt */ + case T_RawStmt: + lev = GetCommandLogLevel(((RawStmt *) parsetree)->stmt); + break; + /* raw plannable queries */ case T_InsertStmt: case T_DeleteStmt: @@ -2832,7 +2939,7 @@ GetCommandLogLevel(Node *parsetree) /* Look through an EXECUTE to the referenced stmt */ ps = FetchPreparedStatement(stmt->name, false); if (ps && ps->plansource->raw_parse_tree) - lev = GetCommandLogLevel(ps->plansource->raw_parse_tree); + lev = GetCommandLogLevel(ps->plansource->raw_parse_tree->stmt); else lev = LOGSTMT_ALL; } @@ -3122,6 +3229,26 @@ GetCommandLogLevel(Node *parsetree) lev = LOGSTMT_DDL; break; + case T_CreatePublicationStmt: + lev = LOGSTMT_DDL; + break; + + case T_AlterPublicationStmt: + lev = LOGSTMT_DDL; + break; + + case T_CreateSubscriptionStmt: + lev = LOGSTMT_DDL; + break; + + case T_AlterSubscriptionStmt: + lev = LOGSTMT_DDL; + break; + + case T_DropSubscriptionStmt: + lev = LOGSTMT_DDL; + break; + /* already-planned queries */ case T_PlannedStmt: { @@ -3139,6 +3266,10 @@ GetCommandLogLevel(Node *parsetree) lev = LOGSTMT_MOD; break; + case CMD_UTILITY: + lev = GetCommandLogLevel(stmt->utilityStmt); + break; + default: elog(WARNING, "unrecognized commandType: %d", (int) stmt->commandType); diff --git a/src/backend/tsearch/Makefile b/src/backend/tsearch/Makefile index 7a0ec0cc97..34fe4c5b3c 100644 --- a/src/backend/tsearch/Makefile +++ b/src/backend/tsearch/Makefile @@ -2,7 +2,7 @@ # # Makefile for backend/tsearch # -# Copyright (c) 2006-2016, PostgreSQL Global Development Group +# Copyright (c) 2006-2017, PostgreSQL Global Development Group # # src/backend/tsearch/Makefile # diff --git a/src/backend/tsearch/dict.c b/src/backend/tsearch/dict.c index fee6320c74..87ee8bfe2e 100644 --- a/src/backend/tsearch/dict.c +++ b/src/backend/tsearch/dict.c @@ -3,7 +3,7 @@ * dict.c * Standard interface to dictionary * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/tsearch/dict_ispell.c b/src/backend/tsearch/dict_ispell.c index a69e1deb16..b4576bf1f8 100644 --- a/src/backend/tsearch/dict_ispell.c +++ b/src/backend/tsearch/dict_ispell.c @@ -3,7 +3,7 @@ * dict_ispell.c * Ispell dictionary interface * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -17,6 +17,7 @@ #include "tsearch/dicts/spell.h" #include "tsearch/ts_locale.h" #include "tsearch/ts_utils.h" +#include "utils/builtins.h" typedef struct diff --git a/src/backend/tsearch/dict_simple.c b/src/backend/tsearch/dict_simple.c index e3f06db268..c361362880 100644 --- a/src/backend/tsearch/dict_simple.c +++ b/src/backend/tsearch/dict_simple.c @@ -3,7 +3,7 @@ * dict_simple.c * Simple dictionary: just lowercase and check for stopword * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -16,6 +16,7 @@ #include "commands/defrem.h" #include "tsearch/ts_locale.h" #include "tsearch/ts_utils.h" +#include "utils/builtins.h" typedef struct diff --git a/src/backend/tsearch/dict_synonym.c b/src/backend/tsearch/dict_synonym.c index 90dbcab4e2..e67d2e6e04 100644 --- a/src/backend/tsearch/dict_synonym.c +++ b/src/backend/tsearch/dict_synonym.c @@ -3,7 +3,7 @@ * dict_synonym.c * Synonym dictionary: replace word by its synonym * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -16,6 +16,7 @@ #include "commands/defrem.h" #include "tsearch/ts_locale.h" #include "tsearch/ts_utils.h" +#include "utils/builtins.h" typedef struct { diff --git a/src/backend/tsearch/dict_thesaurus.c b/src/backend/tsearch/dict_thesaurus.c index 105608c52c..ee23fcfac8 100644 --- a/src/backend/tsearch/dict_thesaurus.c +++ b/src/backend/tsearch/dict_thesaurus.c @@ -3,7 +3,7 @@ * dict_thesaurus.c * Thesaurus dictionary: phrase to phrase substitution * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -19,6 +19,7 @@ #include "tsearch/ts_locale.h" #include "tsearch/ts_utils.h" #include "utils/builtins.h" +#include "utils/regproc.h" /* diff --git a/src/backend/tsearch/regis.c b/src/backend/tsearch/regis.c index a63fd9dbfc..aea76e85b5 100644 --- a/src/backend/tsearch/regis.c +++ b/src/backend/tsearch/regis.c @@ -3,7 +3,7 @@ * regis.c * Fast regex subset * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/tsearch/spell.c b/src/backend/tsearch/spell.c index 821f611e4f..1c1b04c49e 100644 --- a/src/backend/tsearch/spell.c +++ b/src/backend/tsearch/spell.c @@ -3,7 +3,7 @@ * spell.c * Normalizing word with ISpell * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * Ispell dictionary * ----------------- @@ -92,9 +92,7 @@ NIStartBuild(IspellDict *Conf) */ Conf->buildCxt = AllocSetContextCreate(CurTransactionContext, "Ispell dictionary init context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); } /* diff --git a/src/backend/tsearch/to_tsany.c b/src/backend/tsearch/to_tsany.c index 80d80f2451..6e5de8f920 100644 --- a/src/backend/tsearch/to_tsany.c +++ b/src/backend/tsearch/to_tsany.c @@ -3,7 +3,7 @@ * to_tsany.c * to_ts* function definitions * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/tsearch/ts_locale.c b/src/backend/tsearch/ts_locale.c index 85e1cd003a..19d2cc3f30 100644 --- a/src/backend/tsearch/ts_locale.c +++ b/src/backend/tsearch/ts_locale.c @@ -3,7 +3,7 @@ * ts_locale.c * locale compatibility layer for tsearch * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/tsearch/ts_parse.c b/src/backend/tsearch/ts_parse.c index f0e4269e84..e0c9ffb7f4 100644 --- a/src/backend/tsearch/ts_parse.c +++ b/src/backend/tsearch/ts_parse.c @@ -3,7 +3,7 @@ * ts_parse.c * main parse functions for tsearch * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/tsearch/ts_selfuncs.c b/src/backend/tsearch/ts_selfuncs.c index c4118f1db2..904d8848c8 100644 --- a/src/backend/tsearch/ts_selfuncs.c +++ b/src/backend/tsearch/ts_selfuncs.c @@ -3,7 +3,7 @@ * ts_selfuncs.c * Selectivity estimation functions for text search operators. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -19,6 +19,7 @@ #include "miscadmin.h" #include "nodes/nodes.h" #include "tsearch/ts_type.h" +#include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/selfuncs.h" #include "utils/syscache.h" diff --git a/src/backend/tsearch/ts_typanalyze.c b/src/backend/tsearch/ts_typanalyze.c index 817453ce01..017435cc59 100644 --- a/src/backend/tsearch/ts_typanalyze.c +++ b/src/backend/tsearch/ts_typanalyze.c @@ -3,7 +3,7 @@ * ts_typanalyze.c * functions for gathering statistics from tsvector columns * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/tsearch/ts_utils.c b/src/backend/tsearch/ts_utils.c index 9c3e15c0bf..56d4cf03e5 100644 --- a/src/backend/tsearch/ts_utils.c +++ b/src/backend/tsearch/ts_utils.c @@ -3,7 +3,7 @@ * ts_utils.c * various support functions * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c index a3da8cf4d6..8ca1c62713 100644 --- a/src/backend/tsearch/wparser.c +++ b/src/backend/tsearch/wparser.c @@ -3,7 +3,7 @@ * wparser.c * Standard interface to word parser * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -20,6 +20,7 @@ #include "tsearch/ts_cache.h" #include "tsearch/ts_utils.h" #include "utils/builtins.h" +#include "utils/varlena.h" /******sql-level interface******/ diff --git a/src/backend/tsearch/wparser_def.c b/src/backend/tsearch/wparser_def.c index ac1c4d2316..6586760f15 100644 --- a/src/backend/tsearch/wparser_def.c +++ b/src/backend/tsearch/wparser_def.c @@ -3,7 +3,7 @@ * wparser_def.c * Default text search parser * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -2123,7 +2123,7 @@ hlCover(HeadlineParsedText *prs, TSQuery query, int *p, int *q) ch.words = &(prs->words[*p]); ch.len = *q - *p + 1; - if (TS_execute(GETQUERY(query), &ch, false, checkcondition_HL)) + if (TS_execute(GETQUERY(query), &ch, TS_EXEC_EMPTY, checkcondition_HL)) return true; else { diff --git a/src/backend/utils/.gitignore b/src/backend/utils/.gitignore index 5c3a565ba0..f26215c631 100644 --- a/src/backend/utils/.gitignore +++ b/src/backend/utils/.gitignore @@ -1,4 +1,5 @@ /fmgrtab.c /fmgroids.h +/fmgrprotos.h /probes.h /errcodes.h diff --git a/src/backend/utils/Gen_dummy_probes.pl b/src/backend/utils/Gen_dummy_probes.pl index 318d828c29..e6dc5630b4 100644 --- a/src/backend/utils/Gen_dummy_probes.pl +++ b/src/backend/utils/Gen_dummy_probes.pl @@ -4,7 +4,7 @@ # Gen_dummy_probes.pl # Perl script that generates probes.h file when dtrace is not available # -# Portions Copyright (c) 2008-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 2008-2017, PostgreSQL Global Development Group # # # IDENTIFICATION diff --git a/src/backend/utils/Gen_dummy_probes.sed b/src/backend/utils/Gen_dummy_probes.sed index 5a79fdb3f5..6919e41d3a 100644 --- a/src/backend/utils/Gen_dummy_probes.sed +++ b/src/backend/utils/Gen_dummy_probes.sed @@ -1,7 +1,7 @@ #------------------------------------------------------------------------- # sed script to create dummy probes.h file when dtrace is not available # -# Copyright (c) 2008-2016, PostgreSQL Global Development Group +# Copyright (c) 2008-2017, PostgreSQL Global Development Group # # src/backend/utils/Gen_dummy_probes.sed #------------------------------------------------------------------------- diff --git a/src/backend/utils/Gen_fmgrtab.pl b/src/backend/utils/Gen_fmgrtab.pl index a3f03d2734..cdd603ab6f 100644 --- a/src/backend/utils/Gen_fmgrtab.pl +++ b/src/backend/utils/Gen_fmgrtab.pl @@ -4,7 +4,7 @@ # Gen_fmgrtab.pl # Perl script that generates fmgroids.h and fmgrtab.c from pg_proc.h # -# Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # @@ -87,9 +87,11 @@ # Emit headers for both files my $tmpext = ".tmp$$"; my $oidsfile = $output_path . 'fmgroids.h'; +my $protosfile = $output_path . 'fmgrprotos.h'; my $tabfile = $output_path . 'fmgrtab.c'; open H, '>', $oidsfile . $tmpext or die "Could not open $oidsfile$tmpext: $!"; +open P, '>', $protosfile . $tmpext or die "Could not open $protosfile$tmpext: $!"; open T, '>', $tabfile . $tmpext or die "Could not open $tabfile$tmpext: $!"; print H @@ -101,7 +103,7 @@ * These macros can be used to avoid a catalog lookup when a specific * fmgr-callable function needs to be referenced. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES @@ -130,13 +132,40 @@ */ |; +print P +qq|/*------------------------------------------------------------------------- + * + * fmgrprotos.h + * Prototypes for built-in functions. + * + * Portions Copyright (c) 1996-2016, 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 $0 + * from $infile + * + *------------------------------------------------------------------------- + */ + +#ifndef FMGRPROTOS_H +#define FMGRPROTOS_H + +#include "fmgr.h" + +|; + print T qq|/*------------------------------------------------------------------------- * * fmgrtab.c * The function manager's table of internal functions. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES @@ -154,6 +183,7 @@ #include "postgres.h" #include "utils/fmgrtab.h" +#include "utils/fmgrprotos.h" |; @@ -164,7 +194,7 @@ next if $seenit{ $s->{prosrc} }; $seenit{ $s->{prosrc} } = 1; print H "#define F_" . uc $s->{prosrc} . " $s->{oid}\n"; - print T "extern Datum $s->{prosrc} (PG_FUNCTION_ARGS);\n"; + print P "extern Datum $s->{prosrc}(PG_FUNCTION_ARGS);\n"; } # Create the fmgr_builtins table @@ -180,6 +210,7 @@ # And add the file footers. print H "\n#endif /* FMGROIDS_H */\n"; +print P "\n#endif /* FMGRPROTOS_H */\n"; print T qq| /* dummy entry is easier than getting rid of comma after last real one */ @@ -193,10 +224,12 @@ |; close(H); +close(P); close(T); # Finally, rename the completed files into place. Catalog::RenameTempFile($oidsfile, $tmpext); +Catalog::RenameTempFile($protosfile, $tmpext); Catalog::RenameTempFile($tabfile, $tmpext); sub usage diff --git a/src/backend/utils/Makefile b/src/backend/utils/Makefile index 8374533718..4fa5ac26f7 100644 --- a/src/backend/utils/Makefile +++ b/src/backend/utils/Makefile @@ -16,12 +16,12 @@ catalogdir = $(top_srcdir)/src/backend/catalog include $(top_srcdir)/src/backend/common.mk -all: errcodes.h fmgroids.h probes.h +all: errcodes.h fmgroids.h fmgrprotos.h probes.h -$(SUBDIRS:%=%-recursive): fmgroids.h +$(SUBDIRS:%=%-recursive): fmgroids.h fmgrprotos.h # see explanation in ../parser/Makefile -fmgroids.h: fmgrtab.c ; +fmgroids.h fmgrprotos.h: fmgrtab.c ; fmgrtab.c: Gen_fmgrtab.pl $(catalogdir)/Catalog.pm $(top_srcdir)/src/include/catalog/pg_proc.h $(PERL) -I $(catalogdir) $< $(top_srcdir)/src/include/catalog/pg_proc.h @@ -43,10 +43,10 @@ else endif -# fmgroids.h, fmgrtab.c and errcodes.h are in the distribution tarball, so they -# are not cleaned here. +# fmgroids.h, fmgrprotos.h, fmgrtab.c and errcodes.h are in the +# distribution tarball, so they are not cleaned here. clean: rm -f probes.h maintainer-clean: clean - rm -f fmgroids.h fmgrtab.c errcodes.h + rm -f fmgroids.h fmgrprotos.h fmgrtab.c errcodes.h diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile index b9e217ae49..0f512753e4 100644 --- a/src/backend/utils/adt/Makefile +++ b/src/backend/utils/adt/Makefile @@ -17,7 +17,7 @@ OBJS = acl.o amutils.o arrayfuncs.o array_expanded.o array_selfuncs.o \ geo_ops.o geo_selfuncs.o geo_spgist.o inet_cidr_ntop.o inet_net_pton.o \ int.o int8.o json.o jsonb.o jsonb_gin.o jsonb_op.o jsonb_util.o \ jsonfuncs.o like.o lockfuncs.o mac.o misc.o nabstime.o name.o \ - network.o network_gist.o network_selfuncs.o \ + network.o network_gist.o network_selfuncs.o network_spgist.o \ numeric.o numutils.o oid.o oracle_compat.o \ orderedsetaggs.o pg_locale.o pg_lsn.o pg_upgrade_support.o \ pgstatfuncs.o \ diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index 025a99e55a..96ac1dfefd 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -3,7 +3,7 @@ * acl.c * Basic access control list data structures manipulation routines. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -36,6 +36,7 @@ #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/syscache.h" +#include "utils/varlena.h" typedef struct @@ -5143,15 +5144,10 @@ get_role_oid_or_public(const char *rolname) * case must check the case separately. */ Oid -get_rolespec_oid(const Node *node, bool missing_ok) +get_rolespec_oid(const RoleSpec *role, bool missing_ok) { - RoleSpec *role; Oid oid; - if (!IsA(node, RoleSpec)) - elog(ERROR, "invalid node type %d", node->type); - - role = (RoleSpec *) node; switch (role->roletype) { case ROLESPEC_CSTRING: @@ -5186,15 +5182,10 @@ get_rolespec_oid(const Node *node, bool missing_ok) * Caller must ReleaseSysCache when done with the result tuple. */ HeapTuple -get_rolespec_tuple(const Node *node) +get_rolespec_tuple(const RoleSpec *role) { - RoleSpec *role; HeapTuple tuple; - role = (RoleSpec *) node; - if (!IsA(node, RoleSpec)) - elog(ERROR, "invalid node type %d", node->type); - switch (role->roletype) { case ROLESPEC_CSTRING: @@ -5235,13 +5226,13 @@ get_rolespec_tuple(const Node *node) * Given a RoleSpec, returns a palloc'ed copy of the corresponding role's name. */ char * -get_rolespec_name(const Node *node) +get_rolespec_name(const RoleSpec *role) { HeapTuple tp; Form_pg_authid authForm; char *rolename; - tp = get_rolespec_tuple(node); + tp = get_rolespec_tuple(role); authForm = (Form_pg_authid) GETSTRUCT(tp); rolename = pstrdup(NameStr(authForm->rolname)); ReleaseSysCache(tp); @@ -5257,17 +5248,11 @@ get_rolespec_name(const Node *node) * message is provided. */ void -check_rolespec_name(const Node *node, const char *detail_msg) +check_rolespec_name(const RoleSpec *role, const char *detail_msg) { - RoleSpec *role; - - if (!node) + if (!role) return; - role = (RoleSpec *) node; - - Assert(IsA(node, RoleSpec)); - if (role->roletype != ROLESPEC_CSTRING) return; diff --git a/src/backend/utils/adt/amutils.c b/src/backend/utils/adt/amutils.c index ad5e45674b..b3a3a4dcc3 100644 --- a/src/backend/utils/adt/amutils.c +++ b/src/backend/utils/adt/amutils.c @@ -3,7 +3,7 @@ * amutils.c * SQL-level APIs related to index access methods. * - * Copyright (c) 2016, PostgreSQL Global Development Group + * Copyright (c) 2016-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -115,7 +115,7 @@ test_indoption(Oid relid, int attno, bool guard, bool *res) { HeapTuple tuple; - Form_pg_index rd_index; + Form_pg_index rd_index PG_USED_FOR_ASSERTS_ONLY; Datum datum; bool isnull; int2vector *indoption; diff --git a/src/backend/utils/adt/array_expanded.c b/src/backend/utils/adt/array_expanded.c index 7dd7e3fbcb..f256c7f13d 100644 --- a/src/backend/utils/adt/array_expanded.c +++ b/src/backend/utils/adt/array_expanded.c @@ -3,7 +3,7 @@ * array_expanded.c * Basic functions for manipulating expanded arrays. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -63,9 +63,7 @@ expand_array(Datum arraydatum, MemoryContext parentcontext, */ objcxt = AllocSetContextCreate(parentcontext, "expanded array", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_START_SMALL_SIZES); /* Set up expanded array header */ eah = (ExpandedArrayHeader *) diff --git a/src/backend/utils/adt/array_selfuncs.c b/src/backend/utils/adt/array_selfuncs.c index dd44d57e20..50e8145241 100644 --- a/src/backend/utils/adt/array_selfuncs.c +++ b/src/backend/utils/adt/array_selfuncs.c @@ -3,7 +3,7 @@ * array_selfuncs.c * Functions for selectivity estimation of array operators * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -22,6 +22,7 @@ #include "catalog/pg_statistic.h" #include "optimizer/clauses.h" #include "utils/array.h" +#include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/selfuncs.h" #include "utils/typcache.h" diff --git a/src/backend/utils/adt/array_typanalyze.c b/src/backend/utils/adt/array_typanalyze.c index 6f89cf9f9f..85b7a43292 100644 --- a/src/backend/utils/adt/array_typanalyze.c +++ b/src/backend/utils/adt/array_typanalyze.c @@ -3,7 +3,7 @@ * array_typanalyze.c * Functions for gathering statistics from array columns * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -18,6 +18,7 @@ #include "catalog/pg_collation.h" #include "commands/vacuum.h" #include "utils/array.h" +#include "utils/builtins.h" #include "utils/datum.h" #include "utils/lsyscache.h" #include "utils/typcache.h" diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c index 1ef15008bb..e6c1f58ae0 100644 --- a/src/backend/utils/adt/array_userfuncs.c +++ b/src/backend/utils/adt/array_userfuncs.c @@ -3,7 +3,7 @@ * array_userfuncs.c * Misc user-visible array support functions * - * Copyright (c) 2003-2016, PostgreSQL Global Development Group + * Copyright (c) 2003-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/array_userfuncs.c @@ -32,6 +32,10 @@ static Datum array_position_common(FunctionCallInfo fcinfo); * Caution: if the input is a read/write pointer, this returns the input * argument; so callers must be sure that their changes are "safe", that is * they cannot leave the array in a corrupt state. + * + * If we're being called as an aggregate function, make sure any newly-made + * expanded array is allocated in the aggregate state context, so as to save + * copying operations. */ static ExpandedArrayHeader * fetch_array_arg_replace_nulls(FunctionCallInfo fcinfo, int argno) @@ -39,6 +43,7 @@ fetch_array_arg_replace_nulls(FunctionCallInfo fcinfo, int argno) ExpandedArrayHeader *eah; Oid element_type; ArrayMetaState *my_extra; + MemoryContext resultcxt; /* If first time through, create datatype cache struct */ my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; @@ -51,10 +56,17 @@ fetch_array_arg_replace_nulls(FunctionCallInfo fcinfo, int argno) fcinfo->flinfo->fn_extra = my_extra; } + /* Figure out which context we want the result in */ + if (!AggCheckCallContext(fcinfo, &resultcxt)) + resultcxt = CurrentMemoryContext; + /* Now collect the array value */ if (!PG_ARGISNULL(argno)) { + MemoryContext oldcxt = MemoryContextSwitchTo(resultcxt); + eah = PG_GETARG_EXPANDED_ARRAYX(argno, my_extra); + MemoryContextSwitchTo(oldcxt); } else { @@ -72,7 +84,7 @@ fetch_array_arg_replace_nulls(FunctionCallInfo fcinfo, int argno) errmsg("input data type is not an array"))); eah = construct_empty_expanded_array(element_type, - CurrentMemoryContext, + resultcxt, my_extra); } @@ -783,7 +795,8 @@ array_position_common(FunctionCallInfo fcinfo) format_type_be(element_type)))); my_extra->element_type = element_type; - fmgr_info(typentry->eq_opr_finfo.fn_oid, &my_extra->proc); + fmgr_info_cxt(typentry->eq_opr_finfo.fn_oid, &my_extra->proc, + fcinfo->flinfo->fn_mcxt); } /* Examine each array element until we find a match. */ @@ -921,7 +934,8 @@ array_positions(PG_FUNCTION_ARGS) format_type_be(element_type)))); my_extra->element_type = element_type; - fmgr_info(typentry->eq_opr_finfo.fn_oid, &my_extra->proc); + fmgr_info_cxt(typentry->eq_opr_finfo.fn_oid, &my_extra->proc, + fcinfo->flinfo->fn_mcxt); } /* diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 8fbd850146..d9c8aa569c 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -3,7 +3,7 @@ * arrayfuncs.c * Support functions for arrays. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -4957,9 +4957,7 @@ initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext) if (subcontext) arr_context = AllocSetContextCreate(rcontext, "accumArrayResult", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); astate = (ArrayBuildState *) MemoryContextAlloc(arr_context, sizeof(ArrayBuildState)); @@ -5161,9 +5159,7 @@ initArrayResultArr(Oid array_type, Oid element_type, MemoryContext rcontext, if (subcontext) arr_context = AllocSetContextCreate(rcontext, "accumArrayResultArr", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* Note we initialize all fields to zero */ astate = (ArrayBuildStateArr *) @@ -5738,25 +5734,19 @@ array_fill_internal(ArrayType *dims, ArrayType *lbs, /* * Params checks */ - if (ARR_NDIM(dims) != 1) + if (ARR_NDIM(dims) > 1) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("wrong number of array subscripts"), errdetail("Dimension array must be one dimensional."))); - if (ARR_LBOUND(dims)[0] != 1) - ereport(ERROR, - (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), - errmsg("wrong range of array subscripts"), - errdetail("Lower bound of dimension array must be one."))); - if (array_contains_nulls(dims)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("dimension values cannot be null"))); dimv = (int *) ARR_DATA_PTR(dims); - ndims = ARR_DIMS(dims)[0]; + ndims = (ARR_NDIM(dims) > 0) ? ARR_DIMS(dims)[0] : 0; if (ndims < 0) /* we do allow zero-dimension arrays */ ereport(ERROR, @@ -5770,24 +5760,18 @@ array_fill_internal(ArrayType *dims, ArrayType *lbs, if (lbs != NULL) { - if (ARR_NDIM(lbs) != 1) + if (ARR_NDIM(lbs) > 1) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("wrong number of array subscripts"), errdetail("Dimension array must be one dimensional."))); - if (ARR_LBOUND(lbs)[0] != 1) - ereport(ERROR, - (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), - errmsg("wrong range of array subscripts"), - errdetail("Lower bound of dimension array must be one."))); - if (array_contains_nulls(lbs)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("dimension values cannot be null"))); - if (ARR_DIMS(lbs)[0] != ndims) + if (ndims != ((ARR_NDIM(lbs) > 0) ? ARR_DIMS(lbs)[0] : 0)) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("wrong number of array subscripts"), @@ -5805,12 +5789,12 @@ array_fill_internal(ArrayType *dims, ArrayType *lbs, lbsv = deflbs; } + nitems = ArrayGetNItems(ndims, dimv); + /* fast track for empty array */ - if (ndims == 0) + if (nitems <= 0) return construct_empty_array(elmtype); - nitems = ArrayGetNItems(ndims, dimv); - /* * We arrange to look up info about element type only once per series of * calls, assuming the element type doesn't change underneath us. diff --git a/src/backend/utils/adt/arrayutils.c b/src/backend/utils/adt/arrayutils.c index a27fcf853b..a46d8629c3 100644 --- a/src/backend/utils/adt/arrayutils.c +++ b/src/backend/utils/adt/arrayutils.c @@ -3,7 +3,7 @@ * arrayutils.c * This file contains some support routines required for array functions. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/ascii.c b/src/backend/utils/adt/ascii.c index 2b4e250c5c..e219d4b495 100644 --- a/src/backend/utils/adt/ascii.c +++ b/src/backend/utils/adt/ascii.c @@ -2,7 +2,7 @@ * ascii.c * The PostgreSQL routine for string to ascii conversion. * - * Portions Copyright (c) 1999-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1999-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/ascii.c @@ -13,6 +13,7 @@ #include "mb/pg_wchar.h" #include "utils/ascii.h" +#include "utils/builtins.h" static void pg_to_ascii(unsigned char *src, unsigned char *src_end, unsigned char *dest, int enc); diff --git a/src/backend/utils/adt/bool.c b/src/backend/utils/adt/bool.c index 0e17f1c808..6c87e21140 100644 --- a/src/backend/utils/adt/bool.c +++ b/src/backend/utils/adt/bool.c @@ -3,7 +3,7 @@ * bool.c * Functions for the built-in type "bool". * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -150,7 +150,8 @@ boolin(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type boolean: \"%s\"", in_str))); + errmsg("invalid input syntax for type %s: \"%s\"", + "boolean", in_str))); /* not reached */ PG_RETURN_BOOL(false); diff --git a/src/backend/utils/adt/cash.c b/src/backend/utils/adt/cash.c index b336185df7..ac8f74fee6 100644 --- a/src/backend/utils/adt/cash.c +++ b/src/backend/utils/adt/cash.c @@ -189,13 +189,30 @@ cash_in(PG_FUNCTION_ARGS) printf("cashin- string is '%s'\n", s); #endif + /* + * We accumulate the absolute amount in "value" and then apply the sign at + * the end. (The sign can appear before or after the digits, so it would + * be more complicated to do otherwise.) Because of the larger range of + * negative signed integers, we build "value" in the negative and then + * flip the sign at the end, catching most-negative-number overflow if + * necessary. + */ + for (; *s; s++) { /* we look for digits as long as we have found less */ /* than the required number of decimal places */ if (isdigit((unsigned char) *s) && (!seen_dot || dec < fpoint)) { - value = (value * 10) + (*s - '0'); + Cash newvalue = (value * 10) - (*s - '0'); + + if (newvalue / 10 != value) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value \"%s\" is out of range for type %s", + str, "money"))); + + value = newvalue; if (seen_dot) dec++; @@ -214,11 +231,27 @@ cash_in(PG_FUNCTION_ARGS) /* round off if there's another digit */ if (isdigit((unsigned char) *s) && *s >= '5') - value++; + value--; /* remember we build the value in the negative */ + + if (value > 0) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value \"%s\" is out of range for type %s", + str, "money"))); /* adjust for less than required decimal places */ for (; dec < fpoint; dec++) - value *= 10; + { + Cash newvalue = value * 10; + + if (newvalue / 10 != value) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value \"%s\" is out of range for type %s", + str, "money"))); + + value = newvalue; + } /* * should only be trailing digits followed by whitespace, right paren, @@ -243,11 +276,23 @@ cash_in(PG_FUNCTION_ARGS) else ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type money: \"%s\"", - str))); + errmsg("invalid input syntax for type %s: \"%s\"", + "money", str))); } - result = value * sgn; + /* If the value is supposed to be positive, flip the sign, but check for + * the most negative number. */ + if (sgn > 0) + { + result = -value; + if (result < 0) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value \"%s\" is out of range for type %s", + str, "money"))); + } + else + result = value; #ifdef CASHDEBUG printf("cashin- result is " INT64_FORMAT "\n", result); diff --git a/src/backend/utils/adt/char.c b/src/backend/utils/adt/char.c index e43dae8cbf..f0c4d25396 100644 --- a/src/backend/utils/adt/char.c +++ b/src/backend/utils/adt/char.c @@ -4,7 +4,7 @@ * Functions for the built-in type "char" (not to be confused with * bpchar, which is the SQL CHAR(n) type). * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c index 420f383a80..0a100a30ea 100644 --- a/src/backend/utils/adt/date.c +++ b/src/backend/utils/adt/date.c @@ -3,7 +3,7 @@ * date.c * implements DATE and TIME data types specified in SQL standard * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994-5, Regents of the University of California * * @@ -21,6 +21,7 @@ #include #include "access/hash.h" +#include "access/xact.h" #include "libpq/pqformat.h" #include "miscadmin.h" #include "parser/scansup.h" @@ -51,7 +52,6 @@ static void AdjustTimeForTypmod(TimeADT *time, int32 typmod); static int32 anytime_typmodin(bool istz, ArrayType *ta) { - int32 typmod; int32 *tl; int n; @@ -66,22 +66,27 @@ anytime_typmodin(bool istz, ArrayType *ta) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid type modifier"))); - if (*tl < 0) + return anytime_typmod_check(istz, tl[0]); +} + +/* exported so parse_expr.c can use it */ +int32 +anytime_typmod_check(bool istz, int32 typmod) +{ + if (typmod < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("TIME(%d)%s precision must not be negative", - *tl, (istz ? " WITH TIME ZONE" : "")))); - if (*tl > MAX_TIME_PRECISION) + typmod, (istz ? " WITH TIME ZONE" : "")))); + if (typmod > MAX_TIME_PRECISION) { ereport(WARNING, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("TIME(%d)%s precision reduced to maximum allowed, %d", - *tl, (istz ? " WITH TIME ZONE" : ""), + typmod, (istz ? " WITH TIME ZONE" : ""), MAX_TIME_PRECISION))); typmod = MAX_TIME_PRECISION; } - else - typmod = *tl; return typmod; } @@ -247,16 +252,20 @@ make_date(PG_FUNCTION_ARGS) struct pg_tm tm; DateADT date; int dterr; + bool bc = false; tm.tm_year = PG_GETARG_INT32(0); tm.tm_mon = PG_GETARG_INT32(1); tm.tm_mday = PG_GETARG_INT32(2); - /* - * Note: we'll reject zero or negative year values. Perhaps negatives - * should be allowed to represent BC years? - */ - dterr = ValidateDate(DTK_DATE_M, false, false, false, &tm); + /* Handle negative years as BC */ + if (tm.tm_year < 0) + { + bc = true; + tm.tm_year = -tm.tm_year; + } + + dterr = ValidateDate(DTK_DATE_M, false, false, bc, &tm); if (dterr != 0) ereport(ERROR, @@ -298,6 +307,80 @@ EncodeSpecialDate(DateADT dt, char *str) } +/* + * GetSQLCurrentDate -- implements CURRENT_DATE + */ +DateADT +GetSQLCurrentDate(void) +{ + TimestampTz ts; + struct pg_tm tt, + *tm = &tt; + fsec_t fsec; + int tz; + + ts = GetCurrentTransactionStartTimestamp(); + + if (timestamp2tm(ts, &tz, tm, &fsec, NULL, NULL) != 0) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); + + return date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE; +} + +/* + * GetSQLCurrentTime -- implements CURRENT_TIME, CURRENT_TIME(n) + */ +TimeTzADT * +GetSQLCurrentTime(int32 typmod) +{ + TimeTzADT *result; + TimestampTz ts; + struct pg_tm tt, + *tm = &tt; + fsec_t fsec; + int tz; + + ts = GetCurrentTransactionStartTimestamp(); + + if (timestamp2tm(ts, &tz, tm, &fsec, NULL, NULL) != 0) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); + + result = (TimeTzADT *) palloc(sizeof(TimeTzADT)); + tm2timetz(tm, fsec, tz, result); + AdjustTimeForTypmod(&(result->time), typmod); + return result; +} + +/* + * GetSQLLocalTime -- implements LOCALTIME, LOCALTIME(n) + */ +TimeADT +GetSQLLocalTime(int32 typmod) +{ + TimeADT result; + TimestampTz ts; + struct pg_tm tt, + *tm = &tt; + fsec_t fsec; + int tz; + + ts = GetCurrentTransactionStartTimestamp(); + + if (timestamp2tm(ts, &tz, tm, &fsec, NULL, NULL) != 0) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); + + tm2time(tm, fsec, &result); + AdjustTimeForTypmod(&result, typmod); + return result; +} + + /* * Comparison functions for dates */ diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c index 965c3b4ff0..7ada0e5833 100644 --- a/src/backend/utils/adt/datetime.c +++ b/src/backend/utils/adt/datetime.c @@ -3,7 +3,7 @@ * datetime.c * Support functions for date/time types. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -56,8 +56,9 @@ static void AdjustFractDays(double frac, struct pg_tm * tm, fsec_t *fsec, int scale); static int DetermineTimeZoneOffsetInternal(struct pg_tm * tm, pg_tz *tzp, pg_time_t *tp); -static int DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, - pg_tz *tzp, int *isdst); +static bool DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, + const char *abbr, pg_tz *tzp, + int *offset, int *isdst); static pg_tz *FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp); @@ -1689,19 +1690,40 @@ DetermineTimeZoneOffsetInternal(struct pg_tm * tm, pg_tz *tzp, pg_time_t *tp) * This differs from the behavior of DetermineTimeZoneOffset() in that a * standard-time or daylight-time abbreviation forces use of the corresponding * GMT offset even when the zone was then in DS or standard time respectively. + * (However, that happens only if we can match the given abbreviation to some + * abbreviation that appears in the IANA timezone data. Otherwise, we fall + * back to doing DetermineTimeZoneOffset().) */ int DetermineTimeZoneAbbrevOffset(struct pg_tm * tm, const char *abbr, pg_tz *tzp) { pg_time_t t; + int zone_offset; + int abbr_offset; + int abbr_isdst; /* * Compute the UTC time we want to probe at. (In event of overflow, we'll * probe at the epoch, which is a bit random but probably doesn't matter.) */ - (void) DetermineTimeZoneOffsetInternal(tm, tzp, &t); + zone_offset = DetermineTimeZoneOffsetInternal(tm, tzp, &t); - return DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp, &tm->tm_isdst); + /* + * Try to match the abbreviation to something in the zone definition. + */ + if (DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp, + &abbr_offset, &abbr_isdst)) + { + /* Success, so use the abbrev-specific answers. */ + tm->tm_isdst = abbr_isdst; + return abbr_offset; + } + + /* + * No match, so use the answers we already got from + * DetermineTimeZoneOffsetInternal. + */ + return zone_offset; } @@ -1715,19 +1737,41 @@ DetermineTimeZoneAbbrevOffsetTS(TimestampTz ts, const char *abbr, pg_tz *tzp, int *isdst) { pg_time_t t = timestamptz_to_time_t(ts); + int zone_offset; + int abbr_offset; + int tz; + struct pg_tm tm; + fsec_t fsec; + + /* + * If the abbrev matches anything in the zone data, this is pretty easy. + */ + if (DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp, + &abbr_offset, isdst)) + return abbr_offset; - return DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp, isdst); + /* + * Else, break down the timestamp so we can use DetermineTimeZoneOffset. + */ + if (timestamp2tm(ts, &tz, &tm, &fsec, NULL, tzp) != 0) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); + + zone_offset = DetermineTimeZoneOffset(&tm, tzp); + *isdst = tm.tm_isdst; + return zone_offset; } /* DetermineTimeZoneAbbrevOffsetInternal() * * Workhorse for above two functions: work from a pg_time_t probe instant. - * DST status is returned into *isdst. + * On success, return GMT offset and DST status into *offset and *isdst. */ -static int -DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, - pg_tz *tzp, int *isdst) +static bool +DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, pg_tz *tzp, + int *offset, int *isdst) { char upabbr[TZ_STRLEN_MAX + 1]; unsigned char *p; @@ -1739,18 +1783,17 @@ DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, *p = pg_toupper(*p); /* Look up the abbrev's meaning at this time in this zone */ - if (!pg_interpret_timezone_abbrev(upabbr, - &t, - &gmtoff, - isdst, - tzp)) - ereport(ERROR, - (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("time zone abbreviation \"%s\" is not used in time zone \"%s\"", - abbr, pg_get_timezone_name(tzp)))); - - /* Change sign to agree with DetermineTimeZoneOffset() */ - return (int) -gmtoff; + if (pg_interpret_timezone_abbrev(upabbr, + &t, + &gmtoff, + isdst, + tzp)) + { + /* Change sign to agree with DetermineTimeZoneOffset() */ + *offset = (int) -gmtoff; + return true; + } + return false; } @@ -4914,8 +4957,17 @@ pg_timezone_names(PG_FUNCTION_ARGS) &tzoff, &tm, &fsec, &tzn, tz) != 0) continue; /* ignore if conversion fails */ - /* Ignore zic's rather silly "Factory" time zone */ - if (tzn && strcmp(tzn, "Local time zone must be set--see zic manual page") == 0) + /* + * Ignore zic's rather silly "Factory" time zone. The long string + * about "see zic manual page" is used in tzdata versions before + * 2016g; we can drop it someday when we're pretty sure no such data + * exists in the wild on platforms using --with-system-tzdata. In + * 2016g and later, the time zone abbreviation "-00" is used for + * "Factory" as well as some invalid cases, all of which we can + * reasonably omit from the pg_timezone_names view. + */ + if (tzn && (strcmp(tzn, "-00") == 0 || + strcmp(tzn, "Local time zone must be set--see zic manual page") == 0)) continue; /* Found a displayable zone */ diff --git a/src/backend/utils/adt/datum.c b/src/backend/utils/adt/datum.c index c6c296b960..535e4277cc 100644 --- a/src/backend/utils/adt/datum.c +++ b/src/backend/utils/adt/datum.c @@ -3,7 +3,7 @@ * datum.c * POSTGRES Datum (abstract data type) manipulation routines. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c index 0e8a82d6f4..ec3a28cd0d 100644 --- a/src/backend/utils/adt/dbsize.c +++ b/src/backend/utils/adt/dbsize.c @@ -2,7 +2,7 @@ * dbsize.c * Database object size functions, and related inquiries * - * Copyright (c) 2002-2016, PostgreSQL Global Development Group + * Copyright (c) 2002-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/dbsize.c @@ -759,13 +759,15 @@ pg_size_bytes(PG_FUNCTION_ARGS) /* Part (4): optional exponent */ if (*endptr == 'e' || *endptr == 'E') { + long exponent; char *cp; /* * Note we might one day support EB units, so if what follows 'E' * isn't a number, just treat it all as a unit to be parsed. */ - (void) strtol(endptr + 1, &cp, 10); + exponent = strtol(endptr + 1, &cp, 10); + (void) exponent; /* Silence -Wunused-result warnings */ if (cp > endptr + 1) endptr = cp; } diff --git a/src/backend/utils/adt/domains.c b/src/backend/utils/adt/domains.c index 19ee4ce9d1..c2ad440013 100644 --- a/src/backend/utils/adt/domains.c +++ b/src/backend/utils/adt/domains.c @@ -19,7 +19,7 @@ * to evaluate them in. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -35,6 +35,7 @@ #include "executor/executor.h" #include "lib/stringinfo.h" #include "utils/builtins.h" +#include "utils/expandeddatum.h" #include "utils/lsyscache.h" #include "utils/syscache.h" #include "utils/typcache.h" @@ -72,19 +73,28 @@ static DomainIOData * domain_state_setup(Oid domainType, bool binary, MemoryContext mcxt) { DomainIOData *my_extra; + TypeCacheEntry *typentry; Oid baseType; my_extra = (DomainIOData *) MemoryContextAlloc(mcxt, sizeof(DomainIOData)); - /* Find out the base type */ - my_extra->typtypmod = -1; - baseType = getBaseTypeAndTypmod(domainType, &my_extra->typtypmod); - if (baseType == domainType) + /* + * Verify that domainType represents a valid domain type. We need to be + * careful here because domain_in and domain_recv can be called from SQL, + * possibly with incorrect arguments. We use lookup_type_cache mainly + * because it will throw a clean user-facing error for a bad OID. + */ + typentry = lookup_type_cache(domainType, 0); + if (typentry->typtype != TYPTYPE_DOMAIN) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("type %s is not a domain", format_type_be(domainType)))); + /* Find out the base type */ + my_extra->typtypmod = -1; + baseType = getBaseTypeAndTypmod(domainType, &my_extra->typtypmod); + /* Look up underlying I/O function */ if (binary) getTypeBinaryInputInfo(baseType, @@ -157,14 +167,19 @@ domain_check_input(Datum value, bool isnull, DomainIOData *my_extra) * Set up value to be returned by CoerceToDomainValue * nodes. Unlike ExecEvalCoerceToDomain, this econtext * couldn't be shared with anything else, so no need to - * save and restore fields. + * save and restore fields. But we do need to protect the + * passed-in value against being changed by called + * functions. (It couldn't be a R/W expanded object for + * most uses, but that seems possible for domain_check().) */ - econtext->domainValue_datum = value; + econtext->domainValue_datum = + MakeExpandedObjectReadOnly(value, isnull, + my_extra->constraint_ref.tcache->typlen); econtext->domainValue_isNull = isnull; conResult = ExecEvalExprSwitchContext(con->check_expr, econtext, - &conIsNull, NULL); + &conIsNull); if (!conIsNull && !DatumGetBool(conResult)) diff --git a/src/backend/utils/adt/encode.c b/src/backend/utils/adt/encode.c index d833efc32c..5e79ede295 100644 --- a/src/backend/utils/adt/encode.c +++ b/src/backend/utils/adt/encode.c @@ -3,7 +3,7 @@ * encode.c * Various data encoding/decoding things. * - * Copyright (c) 2001-2016, PostgreSQL Global Development Group + * Copyright (c) 2001-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -214,7 +214,7 @@ static const int8 b64lookup[128] = { 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, }; -static unsigned +unsigned b64_encode(const char *src, unsigned len, char *dst) { char *p, @@ -261,7 +261,7 @@ b64_encode(const char *src, unsigned len, char *dst) return p - dst; } -static unsigned +unsigned b64_decode(const char *src, unsigned len, char *dst) { const char *srcend = src + len, @@ -331,14 +331,14 @@ b64_decode(const char *src, unsigned len, char *dst) } -static unsigned +unsigned b64_enc_len(const char *src, unsigned srclen) { /* 3 bytes will be converted to 4, linefeed after 76 chars */ return (srclen + 2) * 4 / 3 + srclen / (76 * 3 / 4); } -static unsigned +unsigned b64_dec_len(const char *src, unsigned srclen) { return (srclen * 3) >> 2; @@ -439,7 +439,7 @@ esc_decode(const char *src, unsigned srclen, char *dst) */ ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type bytea"))); + errmsg("invalid input syntax for type %s", "bytea"))); } len++; @@ -504,7 +504,7 @@ esc_dec_len(const char *src, unsigned srclen) */ ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type bytea"))); + errmsg("invalid input syntax for type %s", "bytea"))); } len++; diff --git a/src/backend/utils/adt/enum.c b/src/backend/utils/adt/enum.c index 135a54428a..8110ee222c 100644 --- a/src/backend/utils/adt/enum.c +++ b/src/backend/utils/adt/enum.c @@ -3,7 +3,7 @@ * enum.c * I/O functions, operators, aggregates etc for enum types * - * Copyright (c) 2006-2016, PostgreSQL Global Development Group + * Copyright (c) 2006-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -19,6 +19,7 @@ #include "catalog/indexing.h" #include "catalog/pg_enum.h" #include "libpq/pqformat.h" +#include "storage/procarray.h" #include "utils/array.h" #include "utils/builtins.h" #include "utils/fmgroids.h" @@ -31,6 +32,93 @@ static Oid enum_endpoint(Oid enumtypoid, ScanDirection direction); static ArrayType *enum_range_internal(Oid enumtypoid, Oid lower, Oid upper); +/* + * Disallow use of an uncommitted pg_enum tuple. + * + * We need to make sure that uncommitted enum values don't get into indexes. + * If they did, and if we then rolled back the pg_enum addition, we'd have + * broken the index because value comparisons will not work reliably without + * an underlying pg_enum entry. (Note that removal of the heap entry + * containing an enum value is not sufficient to ensure that it doesn't appear + * in upper levels of indexes.) To do this we prevent an uncommitted row from + * being used for any SQL-level purpose. This is stronger than necessary, + * since the value might not be getting inserted into a table or there might + * be no index on its column, but it's easy to enforce centrally. + * + * However, it's okay to allow use of uncommitted values belonging to enum + * types that were themselves created in the same transaction, because then + * any such index would also be new and would go away altogether on rollback. + * (This case is required by pg_upgrade.) + * + * This function needs to be called (directly or indirectly) in any of the + * functions below that could return an enum value to SQL operations. + */ +static void +check_safe_enum_use(HeapTuple enumval_tup) +{ + TransactionId xmin; + Form_pg_enum en; + HeapTuple enumtyp_tup; + + /* + * If the row is hinted as committed, it's surely safe. This provides a + * fast path for all normal use-cases. + */ + if (HeapTupleHeaderXminCommitted(enumval_tup->t_data)) + return; + + /* + * Usually, a row would get hinted as committed when it's read or loaded + * into syscache; but just in case not, let's check the xmin directly. + */ + xmin = HeapTupleHeaderGetXmin(enumval_tup->t_data); + if (!TransactionIdIsInProgress(xmin) && + TransactionIdDidCommit(xmin)) + return; + + /* It is a new enum value, so check to see if the whole enum is new */ + en = (Form_pg_enum) GETSTRUCT(enumval_tup); + enumtyp_tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(en->enumtypid)); + if (!HeapTupleIsValid(enumtyp_tup)) + elog(ERROR, "cache lookup failed for type %u", en->enumtypid); + + /* + * We insist that the type have been created in the same (sub)transaction + * as the enum value. It would be safe to allow the type's originating + * xact to be a subcommitted child of the enum value's xact, but not vice + * versa (since we might now be in a subxact of the type's originating + * xact, which could roll back along with the enum value's subxact). The + * former case seems a sufficiently weird usage pattern as to not be worth + * spending code for, so we're left with a simple equality check. + * + * We also insist that the type's pg_type row not be HEAP_UPDATED. If it + * is, we can't tell whether the row was created or only modified in the + * apparent originating xact, so it might be older than that xact. (We do + * not worry whether the enum value is HEAP_UPDATED; if it is, we might + * think it's too new and throw an unnecessary error, but we won't allow + * an unsafe case.) + */ + if (xmin == HeapTupleHeaderGetXmin(enumtyp_tup->t_data) && + !(enumtyp_tup->t_data->t_infomask & HEAP_UPDATED)) + { + /* same (sub)transaction, so safe */ + ReleaseSysCache(enumtyp_tup); + return; + } + + /* + * There might well be other tests we could do here to narrow down the + * unsafe conditions, but for now just raise an exception. + */ + ereport(ERROR, + (errcode(ERRCODE_UNSAFE_NEW_ENUM_VALUE_USAGE), + errmsg("unsafe use of new value \"%s\" of enum type %s", + NameStr(en->enumlabel), + format_type_be(en->enumtypid)), + errhint("New enum values must be committed before they can be used."))); +} + + /* Basic I/O support */ Datum @@ -59,6 +147,9 @@ enum_in(PG_FUNCTION_ARGS) format_type_be(enumtypoid), name))); + /* check it's safe to use in SQL */ + check_safe_enum_use(tup); + /* * This comes from pg_enum.oid and stores system oids in user tables. This * oid must be preserved by binary upgrades. @@ -124,6 +215,9 @@ enum_recv(PG_FUNCTION_ARGS) format_type_be(enumtypoid), name))); + /* check it's safe to use in SQL */ + check_safe_enum_use(tup); + enumoid = HeapTupleGetOid(tup); ReleaseSysCache(tup); @@ -327,9 +421,16 @@ enum_endpoint(Oid enumtypoid, ScanDirection direction) enum_tuple = systable_getnext_ordered(enum_scan, direction); if (HeapTupleIsValid(enum_tuple)) + { + /* check it's safe to use in SQL */ + check_safe_enum_use(enum_tuple); minmax = HeapTupleGetOid(enum_tuple); + } else + { + /* should only happen with an empty enum */ minmax = InvalidOid; + } systable_endscan_ordered(enum_scan); index_close(enum_idx, AccessShareLock); @@ -490,6 +591,9 @@ enum_range_internal(Oid enumtypoid, Oid lower, Oid upper) if (left_found) { + /* check it's safe to use in SQL */ + check_safe_enum_use(enum_tuple); + if (cnt >= max) { max *= 2; diff --git a/src/backend/utils/adt/expandeddatum.c b/src/backend/utils/adt/expandeddatum.c index bc30150dde..3d77686af7 100644 --- a/src/backend/utils/adt/expandeddatum.c +++ b/src/backend/utils/adt/expandeddatum.c @@ -3,7 +3,7 @@ * expandeddatum.c * Support functions for "expanded" value representations. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c index 8aa17e1dcb..894f026a41 100644 --- a/src/backend/utils/adt/float.c +++ b/src/backend/utils/adt/float.c @@ -3,7 +3,7 @@ * float.c * Functions for the built-in floating-point types. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -241,8 +241,8 @@ float4in(PG_FUNCTION_ARGS) if (*num == '\0') ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type real: \"%s\"", - orig_num))); + errmsg("invalid input syntax for type %s: \"%s\"", + "real", orig_num))); errno = 0; val = strtod(num, &endptr); @@ -315,8 +315,8 @@ float4in(PG_FUNCTION_ARGS) else ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type real: \"%s\"", - orig_num))); + errmsg("invalid input syntax for type %s: \"%s\"", + "real", orig_num))); } #ifdef HAVE_BUGGY_SOLARIS_STRTOD else @@ -339,8 +339,8 @@ float4in(PG_FUNCTION_ARGS) if (*endptr != '\0') ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type real: \"%s\"", - orig_num))); + errmsg("invalid input syntax for type %s: \"%s\"", + "real", orig_num))); /* * if we get here, we have a legal double, still need to check to see if diff --git a/src/backend/utils/adt/format_type.c b/src/backend/utils/adt/format_type.c index 1b02932b79..00bfaca59e 100644 --- a/src/backend/utils/adt/format_type.c +++ b/src/backend/utils/adt/format_type.c @@ -4,7 +4,7 @@ * Display type names "nicely". * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index bbd97dc84b..16a7954ec4 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -4,7 +4,7 @@ * src/backend/utils/adt/formatting.c * * - * Portions Copyright (c) 1999-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1999-2017, PostgreSQL Global Development Group * * * TO_CHAR(); TO_TIMESTAMP(); TO_DATE(); TO_NUMBER(); @@ -354,21 +354,27 @@ typedef struct /* ---------- * Format picture cache - * (cache size: - * Number part = NUM_CACHE_SIZE * NUM_CACHE_FIELDS - * Date-time part = DCH_CACHE_SIZE * DCH_CACHE_FIELDS - * ) + * + * We will cache datetime format pictures up to DCH_CACHE_SIZE bytes long; + * likewise number format pictures up to NUM_CACHE_SIZE bytes long. + * + * For simplicity, the cache entries are fixed-size, so they allow for the + * worst case of a FormatNode for each byte in the picture string. + * + * The max number of entries in the caches is DCH_CACHE_ENTRIES + * resp. NUM_CACHE_ENTRIES. * ---------- */ #define NUM_CACHE_SIZE 64 -#define NUM_CACHE_FIELDS 16 +#define NUM_CACHE_ENTRIES 20 #define DCH_CACHE_SIZE 128 -#define DCH_CACHE_FIELDS 16 +#define DCH_CACHE_ENTRIES 20 typedef struct { FormatNode format[DCH_CACHE_SIZE + 1]; char str[DCH_CACHE_SIZE + 1]; + bool valid; int age; } DCHCacheEntry; @@ -376,22 +382,20 @@ typedef struct { FormatNode format[NUM_CACHE_SIZE + 1]; char str[NUM_CACHE_SIZE + 1]; + bool valid; int age; NUMDesc Num; } NUMCacheEntry; -/* global cache for --- date/time part */ -static DCHCacheEntry DCHCache[DCH_CACHE_FIELDS + 1]; - -static int n_DCHCache = 0; /* number of entries */ -static int DCHCounter = 0; +/* global cache for date/time format pictures */ +static DCHCacheEntry DCHCache[DCH_CACHE_ENTRIES]; +static int n_DCHCache = 0; /* current number of entries */ +static int DCHCounter = 0; /* aging-event counter */ -/* global cache for --- number part */ -static NUMCacheEntry NUMCache[NUM_CACHE_FIELDS + 1]; - -static int n_NUMCache = 0; /* number of entries */ -static int NUMCounter = 0; -static NUMCacheEntry *last_NUMCacheEntry = NUMCache + 0; +/* global cache for number format pictures */ +static NUMCacheEntry NUMCache[NUM_CACHE_ENTRIES]; +static int n_NUMCache = 0; /* current number of entries */ +static int NUMCounter = 0; /* aging-event counter */ /* ---------- * For char->date/time conversion @@ -944,11 +948,11 @@ typedef struct NUMProc * Functions * ---------- */ -static const KeyWord *index_seq_search(char *str, const KeyWord *kw, +static const KeyWord *index_seq_search(const char *str, const KeyWord *kw, const int *index); -static const KeySuffix *suff_search(char *str, const KeySuffix *suf, int type); +static const KeySuffix *suff_search(const char *str, const KeySuffix *suf, int type); static void NUMDesc_prepare(NUMDesc *num, FormatNode *n); -static void parse_format(FormatNode *node, char *str, const KeyWord *kw, +static void parse_format(FormatNode *node, const char *str, const KeyWord *kw, const KeySuffix *suf, const int *index, int ver, NUMDesc *Num); static void DCH_to_char(FormatNode *node, bool is_interval, @@ -982,12 +986,12 @@ static void NUM_numpart_to_char(NUMProc *Np, int id); static char *NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number, int from_char_input_len, int to_char_out_pre_spaces, int sign, bool is_to_char, Oid collid); -static DCHCacheEntry *DCH_cache_search(char *str); -static DCHCacheEntry *DCH_cache_getnew(char *str); - -static NUMCacheEntry *NUM_cache_search(char *str); -static NUMCacheEntry *NUM_cache_getnew(char *str); -static void NUM_cache_remove(NUMCacheEntry *ent); +static DCHCacheEntry *DCH_cache_getnew(const char *str); +static DCHCacheEntry *DCH_cache_search(const char *str); +static DCHCacheEntry *DCH_cache_fetch(const char *str); +static NUMCacheEntry *NUM_cache_getnew(const char *str); +static NUMCacheEntry *NUM_cache_search(const char *str); +static NUMCacheEntry *NUM_cache_fetch(const char *str); /* ---------- @@ -997,7 +1001,7 @@ static void NUM_cache_remove(NUMCacheEntry *ent); * ---------- */ static const KeyWord * -index_seq_search(char *str, const KeyWord *kw, const int *index) +index_seq_search(const char *str, const KeyWord *kw, const int *index) { int poz; @@ -1021,7 +1025,7 @@ index_seq_search(char *str, const KeyWord *kw, const int *index) } static const KeySuffix * -suff_search(char *str, const KeySuffix *suf, int type) +suff_search(const char *str, const KeySuffix *suf, int type) { const KeySuffix *s; @@ -1046,182 +1050,166 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n) if (n->type != NODE_TYPE_ACTION) return; - /* - * In case of an error, we need to remove the numeric from the cache. Use - * a PG_TRY block to ensure that this happens. - */ - PG_TRY(); - { - if (IS_EEEE(num) && n->key->id != NUM_E) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("\"EEEE\" must be the last pattern used"))); - - switch (n->key->id) - { - case NUM_9: - if (IS_BRACKET(num)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("\"9\" must be ahead of \"PR\""))); - if (IS_MULTI(num)) - { - ++num->multi; - break; - } - if (IS_DECIMAL(num)) - ++num->post; - else - ++num->pre; - break; - - case NUM_0: - if (IS_BRACKET(num)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("\"0\" must be ahead of \"PR\""))); - if (!IS_ZERO(num) && !IS_DECIMAL(num)) - { - num->flag |= NUM_F_ZERO; - num->zero_start = num->pre + 1; - } - if (!IS_DECIMAL(num)) - ++num->pre; - else - ++num->post; - - num->zero_end = num->pre + num->post; - break; + if (IS_EEEE(num) && n->key->id != NUM_E) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("\"EEEE\" must be the last pattern used"))); - case NUM_B: - if (num->pre == 0 && num->post == 0 && (!IS_ZERO(num))) - num->flag |= NUM_F_BLANK; + switch (n->key->id) + { + case NUM_9: + if (IS_BRACKET(num)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("\"9\" must be ahead of \"PR\""))); + if (IS_MULTI(num)) + { + ++num->multi; break; + } + if (IS_DECIMAL(num)) + ++num->post; + else + ++num->pre; + break; - case NUM_D: - num->flag |= NUM_F_LDECIMAL; - num->need_locale = TRUE; - /* FALLTHROUGH */ - case NUM_DEC: - if (IS_DECIMAL(num)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("multiple decimal points"))); - if (IS_MULTI(num)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), + case NUM_0: + if (IS_BRACKET(num)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("\"0\" must be ahead of \"PR\""))); + if (!IS_ZERO(num) && !IS_DECIMAL(num)) + { + num->flag |= NUM_F_ZERO; + num->zero_start = num->pre + 1; + } + if (!IS_DECIMAL(num)) + ++num->pre; + else + ++num->post; + + num->zero_end = num->pre + num->post; + break; + + case NUM_B: + if (num->pre == 0 && num->post == 0 && (!IS_ZERO(num))) + num->flag |= NUM_F_BLANK; + break; + + case NUM_D: + num->flag |= NUM_F_LDECIMAL; + num->need_locale = TRUE; + /* FALLTHROUGH */ + case NUM_DEC: + if (IS_DECIMAL(num)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("multiple decimal points"))); + if (IS_MULTI(num)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), errmsg("cannot use \"V\" and decimal point together"))); - num->flag |= NUM_F_DECIMAL; - break; - - case NUM_FM: - num->flag |= NUM_F_FILLMODE; - break; - - case NUM_S: - if (IS_LSIGN(num)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("cannot use \"S\" twice"))); - if (IS_PLUS(num) || IS_MINUS(num) || IS_BRACKET(num)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("cannot use \"S\" and \"PL\"/\"MI\"/\"SG\"/\"PR\" together"))); - if (!IS_DECIMAL(num)) - { - num->lsign = NUM_LSIGN_PRE; - num->pre_lsign_num = num->pre; - num->need_locale = TRUE; - num->flag |= NUM_F_LSIGN; - } - else if (num->lsign == NUM_LSIGN_NONE) - { - num->lsign = NUM_LSIGN_POST; - num->need_locale = TRUE; - num->flag |= NUM_F_LSIGN; - } - break; - - case NUM_MI: - if (IS_LSIGN(num)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("cannot use \"S\" and \"MI\" together"))); - num->flag |= NUM_F_MINUS; - if (IS_DECIMAL(num)) - num->flag |= NUM_F_MINUS_POST; - break; - - case NUM_PL: - if (IS_LSIGN(num)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("cannot use \"S\" and \"PL\" together"))); - num->flag |= NUM_F_PLUS; - if (IS_DECIMAL(num)) - num->flag |= NUM_F_PLUS_POST; - break; + num->flag |= NUM_F_DECIMAL; + break; - case NUM_SG: - if (IS_LSIGN(num)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("cannot use \"S\" and \"SG\" together"))); - num->flag |= NUM_F_MINUS; - num->flag |= NUM_F_PLUS; - break; - - case NUM_PR: - if (IS_LSIGN(num) || IS_PLUS(num) || IS_MINUS(num)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("cannot use \"PR\" and \"S\"/\"PL\"/\"MI\"/\"SG\" together"))); - num->flag |= NUM_F_BRACKET; - break; + case NUM_FM: + num->flag |= NUM_F_FILLMODE; + break; - case NUM_rn: - case NUM_RN: - num->flag |= NUM_F_ROMAN; - break; - - case NUM_L: - case NUM_G: + case NUM_S: + if (IS_LSIGN(num)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("cannot use \"S\" twice"))); + if (IS_PLUS(num) || IS_MINUS(num) || IS_BRACKET(num)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("cannot use \"S\" and \"PL\"/\"MI\"/\"SG\"/\"PR\" together"))); + if (!IS_DECIMAL(num)) + { + num->lsign = NUM_LSIGN_PRE; + num->pre_lsign_num = num->pre; num->need_locale = TRUE; - break; + num->flag |= NUM_F_LSIGN; + } + else if (num->lsign == NUM_LSIGN_NONE) + { + num->lsign = NUM_LSIGN_POST; + num->need_locale = TRUE; + num->flag |= NUM_F_LSIGN; + } + break; - case NUM_V: - if (IS_DECIMAL(num)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), + case NUM_MI: + if (IS_LSIGN(num)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("cannot use \"S\" and \"MI\" together"))); + num->flag |= NUM_F_MINUS; + if (IS_DECIMAL(num)) + num->flag |= NUM_F_MINUS_POST; + break; + + case NUM_PL: + if (IS_LSIGN(num)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("cannot use \"S\" and \"PL\" together"))); + num->flag |= NUM_F_PLUS; + if (IS_DECIMAL(num)) + num->flag |= NUM_F_PLUS_POST; + break; + + case NUM_SG: + if (IS_LSIGN(num)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("cannot use \"S\" and \"SG\" together"))); + num->flag |= NUM_F_MINUS; + num->flag |= NUM_F_PLUS; + break; + + case NUM_PR: + if (IS_LSIGN(num) || IS_PLUS(num) || IS_MINUS(num)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("cannot use \"PR\" and \"S\"/\"PL\"/\"MI\"/\"SG\" together"))); + num->flag |= NUM_F_BRACKET; + break; + + case NUM_rn: + case NUM_RN: + num->flag |= NUM_F_ROMAN; + break; + + case NUM_L: + case NUM_G: + num->need_locale = TRUE; + break; + + case NUM_V: + if (IS_DECIMAL(num)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), errmsg("cannot use \"V\" and decimal point together"))); - num->flag |= NUM_F_MULTI; - break; + num->flag |= NUM_F_MULTI; + break; - case NUM_E: - if (IS_EEEE(num)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("cannot use \"EEEE\" twice"))); - if (IS_BLANK(num) || IS_FILLMODE(num) || IS_LSIGN(num) || - IS_BRACKET(num) || IS_MINUS(num) || IS_PLUS(num) || - IS_ROMAN(num) || IS_MULTI(num)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), + case NUM_E: + if (IS_EEEE(num)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("cannot use \"EEEE\" twice"))); + if (IS_BLANK(num) || IS_FILLMODE(num) || IS_LSIGN(num) || + IS_BRACKET(num) || IS_MINUS(num) || IS_PLUS(num) || + IS_ROMAN(num) || IS_MULTI(num)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), errmsg("\"EEEE\" is incompatible with other formats"), - errdetail("\"EEEE\" may only be used together with digit and decimal point patterns."))); - num->flag |= NUM_F_EEEE; - break; - } - } - PG_CATCH(); - { - NUM_cache_remove(last_NUMCacheEntry); - PG_RE_THROW(); + errdetail("\"EEEE\" may only be used together with digit and decimal point patterns."))); + num->flag |= NUM_F_EEEE; + break; } - PG_END_TRY(); - - - return; } /* ---------- @@ -1232,7 +1220,7 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n) * ---------- */ static void -parse_format(FormatNode *node, char *str, const KeyWord *kw, +parse_format(FormatNode *node, const char *str, const KeyWord *kw, const KeySuffix *suf, const int *index, int ver, NUMDesc *Num) { const KeySuffix *s; @@ -1350,7 +1338,6 @@ parse_format(FormatNode *node, char *str, const KeyWord *kw, n->type = NODE_TYPE_END; n->suffix = 0; - return; } /* ---------- @@ -3210,41 +3197,51 @@ DCH_from_char(FormatNode *node, char *in, TmFromChar *out) } } +/* select a DCHCacheEntry to hold the given format picture */ static DCHCacheEntry * -DCH_cache_getnew(char *str) +DCH_cache_getnew(const char *str) { DCHCacheEntry *ent; /* counter overflow check - paranoia? */ - if (DCHCounter >= (INT_MAX - DCH_CACHE_FIELDS - 1)) + if (DCHCounter >= (INT_MAX - DCH_CACHE_ENTRIES)) { DCHCounter = 0; - for (ent = DCHCache; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++) + for (ent = DCHCache; ent < (DCHCache + DCH_CACHE_ENTRIES); ent++) ent->age = (++DCHCounter); } /* - * If cache is full, remove oldest entry + * If cache is full, remove oldest entry (or recycle first not-valid one) */ - if (n_DCHCache > DCH_CACHE_FIELDS) + if (n_DCHCache >= DCH_CACHE_ENTRIES) { DCHCacheEntry *old = DCHCache + 0; #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "cache is full (%d)", n_DCHCache); #endif - for (ent = DCHCache + 1; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++) + if (old->valid) { - if (ent->age < old->age) - old = ent; + for (ent = DCHCache + 1; ent < (DCHCache + DCH_CACHE_ENTRIES); ent++) + { + if (!ent->valid) + { + old = ent; + break; + } + if (ent->age < old->age) + old = ent; + } } #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "OLD: '%s' AGE: %d", old->str, old->age); #endif + old->valid = false; StrNCpy(old->str, str, DCH_CACHE_SIZE + 1); - /* old->format fill parser */ old->age = (++DCHCounter); + /* caller is expected to fill format, then set valid */ return old; } else @@ -3253,32 +3250,34 @@ DCH_cache_getnew(char *str) elog(DEBUG_elog_output, "NEW (%d)", n_DCHCache); #endif ent = DCHCache + n_DCHCache; + ent->valid = false; StrNCpy(ent->str, str, DCH_CACHE_SIZE + 1); - /* ent->format fill parser */ ent->age = (++DCHCounter); + /* caller is expected to fill format, then set valid */ ++n_DCHCache; return ent; } } +/* look for an existing DCHCacheEntry matching the given format picture */ static DCHCacheEntry * -DCH_cache_search(char *str) +DCH_cache_search(const char *str) { int i; DCHCacheEntry *ent; /* counter overflow check - paranoia? */ - if (DCHCounter >= (INT_MAX - DCH_CACHE_FIELDS - 1)) + if (DCHCounter >= (INT_MAX - DCH_CACHE_ENTRIES)) { DCHCounter = 0; - for (ent = DCHCache; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++) + for (ent = DCHCache; ent < (DCHCache + DCH_CACHE_ENTRIES); ent++) ent->age = (++DCHCounter); } for (i = 0, ent = DCHCache; i < n_DCHCache; i++, ent++) { - if (strcmp(ent->str, str) == 0) + if (ent->valid && strcmp(ent->str, str) == 0) { ent->age = (++DCHCounter); return ent; @@ -3288,6 +3287,29 @@ DCH_cache_search(char *str) return NULL; } +/* Find or create a DCHCacheEntry for the given format picture */ +static DCHCacheEntry * +DCH_cache_fetch(const char *str) +{ + DCHCacheEntry *ent; + + if ((ent = DCH_cache_search(str)) == NULL) + { + /* + * Not in the cache, must run parser and save a new format-picture to + * the cache. Do not mark the cache entry valid until parsing + * succeeds. + */ + ent = DCH_cache_getnew(str); + + parse_format(ent->format, str, DCH_keywords, + DCH_suff, DCH_index, DCH_TYPE, NULL); + + ent->valid = true; + } + return ent; +} + /* * Format a date/time or interval into a string according to fmt. * We parse fmt into a list of FormatNodes. This is then passed to DCH_to_char @@ -3315,47 +3337,27 @@ datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval, Oid collid) result = palloc((fmt_len * DCH_MAX_ITEM_SIZ) + 1); *result = '\0'; - /* - * Allocate new memory if format picture is bigger than static cache and - * not use cache (call parser always) - */ if (fmt_len > DCH_CACHE_SIZE) { - format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode)); + /* + * Allocate new memory if format picture is bigger than static cache + * and do not use cache (call parser always) + */ incache = FALSE; + format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode)); + parse_format(format, fmt_str, DCH_keywords, DCH_suff, DCH_index, DCH_TYPE, NULL); - - (format + fmt_len)->type = NODE_TYPE_END; /* Paranoia? */ } else { /* * Use cache buffers */ - DCHCacheEntry *ent; + DCHCacheEntry *ent = DCH_cache_fetch(fmt_str); incache = TRUE; - - if ((ent = DCH_cache_search(fmt_str)) == NULL) - { - ent = DCH_cache_getnew(fmt_str); - - /* - * Not in the cache, must run parser and save a new format-picture - * to the cache. - */ - parse_format(ent->format, fmt_str, DCH_keywords, - DCH_suff, DCH_index, DCH_TYPE, NULL); - - (ent->format + fmt_len)->type = NODE_TYPE_END; /* Paranoia? */ - -#ifdef DEBUG_TO_FROM_CHAR - /* dump_node(ent->format, fmt_len); */ - /* dump_index(DCH_keywords, DCH_index); */ -#endif - } format = ent->format; } @@ -3553,9 +3555,6 @@ to_date(PG_FUNCTION_ARGS) * * The TmFromChar is then analysed and converted into the final results in * struct 'tm' and 'fsec'. - * - * This function does very little error checking, e.g. - * to_timestamp('20096040','YYYYMMDD') works */ static void do_to_timestamp(text *date_txt, text *fmt, @@ -3564,73 +3563,56 @@ do_to_timestamp(text *date_txt, text *fmt, FormatNode *format; TmFromChar tmfc; int fmt_len; + char *date_str; + int fmask; + + date_str = text_to_cstring(date_txt); ZERO_tmfc(&tmfc); ZERO_tm(tm); *fsec = 0; + fmask = 0; /* bit mask for ValidateDate() */ fmt_len = VARSIZE_ANY_EXHDR(fmt); if (fmt_len) { char *fmt_str; - char *date_str; bool incache; fmt_str = text_to_cstring(fmt); - /* - * Allocate new memory if format picture is bigger than static cache - * and not use cache (call parser always) - */ if (fmt_len > DCH_CACHE_SIZE) { - format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode)); + /* + * Allocate new memory if format picture is bigger than static + * cache and do not use cache (call parser always) + */ incache = FALSE; + format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode)); + parse_format(format, fmt_str, DCH_keywords, DCH_suff, DCH_index, DCH_TYPE, NULL); - - (format + fmt_len)->type = NODE_TYPE_END; /* Paranoia? */ } else { /* * Use cache buffers */ - DCHCacheEntry *ent; + DCHCacheEntry *ent = DCH_cache_fetch(fmt_str); incache = TRUE; - - if ((ent = DCH_cache_search(fmt_str)) == NULL) - { - ent = DCH_cache_getnew(fmt_str); - - /* - * Not in the cache, must run parser and save a new - * format-picture to the cache. - */ - parse_format(ent->format, fmt_str, DCH_keywords, - DCH_suff, DCH_index, DCH_TYPE, NULL); - - (ent->format + fmt_len)->type = NODE_TYPE_END; /* Paranoia? */ -#ifdef DEBUG_TO_FROM_CHAR - /* dump_node(ent->format, fmt_len); */ - /* dump_index(DCH_keywords, DCH_index); */ -#endif - } format = ent->format; } #ifdef DEBUG_TO_FROM_CHAR /* dump_node(format, fmt_len); */ + /* dump_index(DCH_keywords, DCH_index); */ #endif - date_str = text_to_cstring(date_txt); - DCH_from_char(format, date_str, &tmfc); - pfree(date_str); pfree(fmt_str); if (!incache) pfree(format); @@ -3639,8 +3621,7 @@ do_to_timestamp(text *date_txt, text *fmt, DEBUG_TMFC(&tmfc); /* - * Convert values that user define for FROM_CHAR (to_date/to_timestamp) to - * standard 'tm' + * Convert to_date/to_timestamp input fields to standard 'tm' */ if (tmfc.ssss) { @@ -3696,19 +3677,23 @@ do_to_timestamp(text *date_txt, text *fmt, tm->tm_year = (tmfc.cc + 1) * 100 - tm->tm_year + 1; } else + { /* find century year for dates ending in "00" */ tm->tm_year = tmfc.cc * 100 + ((tmfc.cc >= 0) ? 0 : 1); + } } else - /* If a 4-digit year is provided, we use that and ignore CC. */ { + /* If a 4-digit year is provided, we use that and ignore CC. */ tm->tm_year = tmfc.year; if (tmfc.bc && tm->tm_year > 0) tm->tm_year = -(tm->tm_year - 1); } + fmask |= DTK_M(YEAR); } - else if (tmfc.cc) /* use first year of century */ + else if (tmfc.cc) { + /* use first year of century */ if (tmfc.bc) tmfc.cc = -tmfc.cc; if (tmfc.cc >= 0) @@ -3717,10 +3702,14 @@ do_to_timestamp(text *date_txt, text *fmt, else /* +1 because year == 599 is 600 BC */ tm->tm_year = tmfc.cc * 100 + 1; + fmask |= DTK_M(YEAR); } if (tmfc.j) + { j2date(tmfc.j, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); + fmask |= DTK_DATE_M; + } if (tmfc.ww) { @@ -3734,6 +3723,7 @@ do_to_timestamp(text *date_txt, text *fmt, isoweekdate2date(tmfc.ww, tmfc.d, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); else isoweek2date(tmfc.ww, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); + fmask |= DTK_DATE_M; } else tmfc.ddd = (tmfc.ww - 1) * 7 + 1; @@ -3741,14 +3731,16 @@ do_to_timestamp(text *date_txt, text *fmt, if (tmfc.w) tmfc.dd = (tmfc.w - 1) * 7 + 1; - if (tmfc.d) - tm->tm_wday = tmfc.d - 1; /* convert to native numbering */ if (tmfc.dd) + { tm->tm_mday = tmfc.dd; - if (tmfc.ddd) - tm->tm_yday = tmfc.ddd; + fmask |= DTK_M(DAY); + } if (tmfc.mm) + { tm->tm_mon = tmfc.mm; + fmask |= DTK_M(MONTH); + } if (tmfc.ddd && (tm->tm_mon <= 1 || tm->tm_mday <= 1)) { @@ -3771,6 +3763,7 @@ do_to_timestamp(text *date_txt, text *fmt, j0 = isoweek2j(tm->tm_year, 1) - 1; j2date(j0 + tmfc.ddd, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); + fmask |= DTK_DATE_M; } else { @@ -3785,7 +3778,7 @@ do_to_timestamp(text *date_txt, text *fmt, for (i = 1; i <= MONTHS_PER_YEAR; i++) { - if (tmfc.ddd < y[i]) + if (tmfc.ddd <= y[i]) break; } if (tm->tm_mon <= 1) @@ -3793,6 +3786,8 @@ do_to_timestamp(text *date_txt, text *fmt, if (tm->tm_mday <= 1) tm->tm_mday = tmfc.ddd - y[i - 1]; + + fmask |= DTK_M(MONTH) | DTK_M(DAY); } } @@ -3808,7 +3803,38 @@ do_to_timestamp(text *date_txt, text *fmt, *fsec += (double) tmfc.us / 1000000; #endif + /* Range-check date fields according to bit mask computed above */ + if (fmask != 0) + { + /* We already dealt with AD/BC, so pass isjulian = true */ + int dterr = ValidateDate(fmask, true, false, false, tm); + + if (dterr != 0) + { + /* + * Force the error to be DTERR_FIELD_OVERFLOW even if ValidateDate + * said DTERR_MD_FIELD_OVERFLOW, because we don't want to print an + * irrelevant hint about datestyle. + */ + DateTimeParseError(DTERR_FIELD_OVERFLOW, date_str, "timestamp"); + } + } + + /* Range-check time fields too */ + if (tm->tm_hour < 0 || tm->tm_hour >= HOURS_PER_DAY || + tm->tm_min < 0 || tm->tm_min >= MINS_PER_HOUR || + tm->tm_sec < 0 || tm->tm_sec >= SECS_PER_MINUTE || +#ifdef HAVE_INT64_TIMESTAMP + *fsec < INT64CONST(0) || *fsec >= USECS_PER_SEC +#else + *fsec < 0 || *fsec >= 1 +#endif + ) + DateTimeParseError(DTERR_FIELD_OVERFLOW, date_str, "timestamp"); + DEBUG_TM(tm); + + pfree(date_str); } @@ -3838,51 +3864,52 @@ do { \ (_n)->zero_end = 0; \ } while(0) +/* select a NUMCacheEntry to hold the given format picture */ static NUMCacheEntry * -NUM_cache_getnew(char *str) +NUM_cache_getnew(const char *str) { NUMCacheEntry *ent; /* counter overflow check - paranoia? */ - if (NUMCounter >= (INT_MAX - NUM_CACHE_FIELDS - 1)) + if (NUMCounter >= (INT_MAX - NUM_CACHE_ENTRIES)) { NUMCounter = 0; - for (ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++) + for (ent = NUMCache; ent < (NUMCache + NUM_CACHE_ENTRIES); ent++) ent->age = (++NUMCounter); } /* - * If cache is full, remove oldest entry + * If cache is full, remove oldest entry (or recycle first not-valid one) */ - if (n_NUMCache > NUM_CACHE_FIELDS) + if (n_NUMCache >= NUM_CACHE_ENTRIES) { NUMCacheEntry *old = NUMCache + 0; #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "Cache is full (%d)", n_NUMCache); #endif - for (ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++) + if (old->valid) { - /* - * entry removed via NUM_cache_remove() can be used here, which is - * why it's worth scanning first entry again - */ - if (ent->str[0] == '\0') + for (ent = NUMCache + 1; ent < (NUMCache + NUM_CACHE_ENTRIES); ent++) { - old = ent; - break; + if (!ent->valid) + { + old = ent; + break; + } + if (ent->age < old->age) + old = ent; } - if (ent->age < old->age) - old = ent; } #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "OLD: \"%s\" AGE: %d", old->str, old->age); #endif + old->valid = false; StrNCpy(old->str, str, NUM_CACHE_SIZE + 1); - /* old->format fill parser */ old->age = (++NUMCounter); - ent = old; + /* caller is expected to fill format and Num, then set valid */ + return old; } else { @@ -3890,39 +3917,36 @@ NUM_cache_getnew(char *str) elog(DEBUG_elog_output, "NEW (%d)", n_NUMCache); #endif ent = NUMCache + n_NUMCache; + ent->valid = false; StrNCpy(ent->str, str, NUM_CACHE_SIZE + 1); - /* ent->format fill parser */ ent->age = (++NUMCounter); + /* caller is expected to fill format and Num, then set valid */ ++n_NUMCache; + return ent; } - - zeroize_NUM(&ent->Num); - - last_NUMCacheEntry = ent; - return ent; } +/* look for an existing NUMCacheEntry matching the given format picture */ static NUMCacheEntry * -NUM_cache_search(char *str) +NUM_cache_search(const char *str) { int i; NUMCacheEntry *ent; /* counter overflow check - paranoia? */ - if (NUMCounter >= (INT_MAX - NUM_CACHE_FIELDS - 1)) + if (NUMCounter >= (INT_MAX - NUM_CACHE_ENTRIES)) { NUMCounter = 0; - for (ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++) + for (ent = NUMCache; ent < (NUMCache + NUM_CACHE_ENTRIES); ent++) ent->age = (++NUMCounter); } for (i = 0, ent = NUMCache; i < n_NUMCache; i++, ent++) { - if (strcmp(ent->str, str) == 0) + if (ent->valid && strcmp(ent->str, str) == 0) { ent->age = (++NUMCounter); - last_NUMCacheEntry = ent; return ent; } } @@ -3930,14 +3954,29 @@ NUM_cache_search(char *str) return NULL; } -static void -NUM_cache_remove(NUMCacheEntry *ent) +/* Find or create a NUMCacheEntry for the given format picture */ +static NUMCacheEntry * +NUM_cache_fetch(const char *str) { -#ifdef DEBUG_TO_FROM_CHAR - elog(DEBUG_elog_output, "REMOVING ENTRY (%s)", ent->str); -#endif - ent->str[0] = '\0'; - ent->age = 0; + NUMCacheEntry *ent; + + if ((ent = NUM_cache_search(str)) == NULL) + { + /* + * Not in the cache, must run parser and save a new format-picture to + * the cache. Do not mark the cache entry valid until parsing + * succeeds. + */ + ent = NUM_cache_getnew(str); + + zeroize_NUM(&ent->Num); + + parse_format(ent->format, str, NUM_keywords, + NULL, NUM_index, NUM_TYPE, &ent->Num); + + ent->valid = true; + } + return ent; } /* ---------- @@ -3952,13 +3991,12 @@ NUM_cache(int len, NUMDesc *Num, text *pars_str, bool *shouldFree) str = text_to_cstring(pars_str); - /* - * Allocate new memory if format picture is bigger than static cache and - * not use cache (call parser always). This branches sets shouldFree to - * true, accordingly. - */ if (len > NUM_CACHE_SIZE) { + /* + * Allocate new memory if format picture is bigger than static cache + * and do not use cache (call parser always) + */ format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode)); *shouldFree = true; @@ -3967,32 +4005,16 @@ NUM_cache(int len, NUMDesc *Num, text *pars_str, bool *shouldFree) parse_format(format, str, NUM_keywords, NULL, NUM_index, NUM_TYPE, Num); - - (format + len)->type = NODE_TYPE_END; /* Paranoia? */ } else { /* * Use cache buffers */ - NUMCacheEntry *ent; + NUMCacheEntry *ent = NUM_cache_fetch(str); *shouldFree = false; - if ((ent = NUM_cache_search(str)) == NULL) - { - ent = NUM_cache_getnew(str); - - /* - * Not in the cache, must run parser and save a new format-picture - * to the cache. - */ - parse_format(ent->format, str, NUM_keywords, - NULL, NUM_index, NUM_TYPE, &ent->Num); - - (ent->format + len)->type = NODE_TYPE_END; /* Paranoia? */ - } - format = ent->format; /* diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c index 650d1e4390..1a127d9258 100644 --- a/src/backend/utils/adt/genfile.c +++ b/src/backend/utils/adt/genfile.c @@ -4,7 +4,7 @@ * Functions for direct access to files * * - * Copyright (c) 2004-2016, PostgreSQL Global Development Group + * Copyright (c) 2004-2017, PostgreSQL Global Development Group * * Author: Andreas Pflug * diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c index 0dff40ddff..655b81cc46 100644 --- a/src/backend/utils/adt/geo_ops.c +++ b/src/backend/utils/adt/geo_ops.c @@ -3,7 +3,7 @@ * geo_ops.c * 2D geometric operations * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/geo_selfuncs.c b/src/backend/utils/adt/geo_selfuncs.c index 6fb5425c2b..774063e92c 100644 --- a/src/backend/utils/adt/geo_selfuncs.c +++ b/src/backend/utils/adt/geo_selfuncs.c @@ -4,7 +4,7 @@ * Selectivity routines registered in the operator catalog in the * "oprrest" and "oprjoin" attributes. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -18,6 +18,7 @@ */ #include "postgres.h" +#include "utils/builtins.h" #include "utils/geo_decls.h" diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c index 019015656f..aacb3409bd 100644 --- a/src/backend/utils/adt/geo_spgist.c +++ b/src/backend/utils/adt/geo_spgist.c @@ -62,7 +62,7 @@ * except the root. For the root node, we are setting the boundaries * that we don't yet have as infinity. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c index 29d92a7d04..bd4422e08a 100644 --- a/src/backend/utils/adt/int.c +++ b/src/backend/utils/adt/int.c @@ -3,7 +3,7 @@ * int.c * Functions for the built-in integer types (except int8). * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -254,21 +254,6 @@ int2vectorsend(PG_FUNCTION_ARGS) return array_send(fcinfo); } -/* - * We don't have a complete set of int2vector support routines, - * but we need int2vectoreq for catcache indexing. - */ -Datum -int2vectoreq(PG_FUNCTION_ARGS) -{ - int2vector *a = (int2vector *) PG_GETARG_POINTER(0); - int2vector *b = (int2vector *) PG_GETARG_POINTER(1); - - if (a->dim1 != b->dim1) - PG_RETURN_BOOL(false); - PG_RETURN_BOOL(memcmp(a->values, b->values, a->dim1 * sizeof(int16)) == 0); -} - /***************************************************************************** * PUBLIC ROUTINES * diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c index 17d2973280..0c6a412f2a 100644 --- a/src/backend/utils/adt/int8.c +++ b/src/backend/utils/adt/int8.c @@ -3,7 +3,7 @@ * int8.c * Internal 64-bit integer operations * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -95,8 +95,8 @@ scanint8(const char *str, bool errorOK, int64 *result) else ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for integer: \"%s\"", - str))); + errmsg("invalid input syntax for %s: \"%s\"", + "integer", str))); } /* process digits */ @@ -111,8 +111,8 @@ scanint8(const char *str, bool errorOK, int64 *result) else ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("value \"%s\" is out of range for type bigint", - str))); + errmsg("value \"%s\" is out of range for type %s", + str, "bigint"))); } tmp = newtmp; } @@ -130,8 +130,8 @@ scanint8(const char *str, bool errorOK, int64 *result) else ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for integer: \"%s\"", - str))); + errmsg("invalid input syntax for %s: \"%s\"", + "integer", str))); } *result = (sign < 0) ? -tmp : tmp; diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c index f704418603..628e9de616 100644 --- a/src/backend/utils/adt/json.c +++ b/src/backend/utils/adt/json.c @@ -3,7 +3,7 @@ * json.c * JSON data type support. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -782,7 +782,7 @@ json_lex_string(JsonLexContext *lex) lex->token_terminator = s; ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type json"), + errmsg("invalid input syntax for type %s", "json"), errdetail("Character with value 0x%02x must be escaped.", (unsigned char) *s), report_json_context(lex))); @@ -822,7 +822,8 @@ json_lex_string(JsonLexContext *lex) lex->token_terminator = s + pg_mblen(s); ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type json"), + errmsg("invalid input syntax for type %s", + "json"), errdetail("\"\\u\" must be followed by four hexadecimal digits."), report_json_context(lex))); } @@ -837,7 +838,8 @@ json_lex_string(JsonLexContext *lex) if (hi_surrogate != -1) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type json"), + errmsg("invalid input syntax for type %s", + "json"), errdetail("Unicode high surrogate must not follow a high surrogate."), report_json_context(lex))); hi_surrogate = (ch & 0x3ff) << 10; @@ -848,7 +850,7 @@ json_lex_string(JsonLexContext *lex) if (hi_surrogate == -1) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type json"), + errmsg("invalid input syntax for type %s", "json"), errdetail("Unicode low surrogate must follow a high surrogate."), report_json_context(lex))); ch = 0x10000 + hi_surrogate + (ch & 0x3ff); @@ -858,7 +860,7 @@ json_lex_string(JsonLexContext *lex) if (hi_surrogate != -1) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type json"), + errmsg("invalid input syntax for type %s", "json"), errdetail("Unicode low surrogate must follow a high surrogate."), report_json_context(lex))); @@ -909,7 +911,8 @@ json_lex_string(JsonLexContext *lex) if (hi_surrogate != -1) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type json"), + errmsg("invalid input syntax for type %s", + "json"), errdetail("Unicode low surrogate must follow a high surrogate."), report_json_context(lex))); @@ -940,7 +943,8 @@ json_lex_string(JsonLexContext *lex) lex->token_terminator = s + pg_mblen(s); ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type json"), + errmsg("invalid input syntax for type %s", + "json"), errdetail("Escape sequence \"\\%s\" is invalid.", extract_mb_char(s)), report_json_context(lex))); @@ -958,7 +962,7 @@ json_lex_string(JsonLexContext *lex) lex->token_terminator = s + pg_mblen(s); ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type json"), + errmsg("invalid input syntax for type %s", "json"), errdetail("Escape sequence \"\\%s\" is invalid.", extract_mb_char(s)), report_json_context(lex))); @@ -970,7 +974,7 @@ json_lex_string(JsonLexContext *lex) if (hi_surrogate != -1) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type json"), + errmsg("invalid input syntax for type %s", "json"), errdetail("Unicode low surrogate must follow a high surrogate."), report_json_context(lex))); @@ -982,7 +986,7 @@ json_lex_string(JsonLexContext *lex) if (hi_surrogate != -1) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type json"), + errmsg("invalid input syntax for type %s", "json"), errdetail("Unicode low surrogate must follow a high surrogate."), report_json_context(lex))); @@ -1127,7 +1131,7 @@ report_parse_error(JsonParseContext ctx, JsonLexContext *lex) if (lex->token_start == NULL || lex->token_type == JSON_TOKEN_END) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type json"), + errmsg("invalid input syntax for type %s", "json"), errdetail("The input string ended unexpectedly."), report_json_context(lex))); @@ -1141,7 +1145,7 @@ report_parse_error(JsonParseContext ctx, JsonLexContext *lex) if (ctx == JSON_PARSE_END) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type json"), + errmsg("invalid input syntax for type %s", "json"), errdetail("Expected end of input, but found \"%s\".", token), report_json_context(lex))); @@ -1152,7 +1156,7 @@ report_parse_error(JsonParseContext ctx, JsonLexContext *lex) case JSON_PARSE_VALUE: ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type json"), + errmsg("invalid input syntax for type %s", "json"), errdetail("Expected JSON value, but found \"%s\".", token), report_json_context(lex))); @@ -1160,7 +1164,7 @@ report_parse_error(JsonParseContext ctx, JsonLexContext *lex) case JSON_PARSE_STRING: ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type json"), + errmsg("invalid input syntax for type %s", "json"), errdetail("Expected string, but found \"%s\".", token), report_json_context(lex))); @@ -1168,7 +1172,7 @@ report_parse_error(JsonParseContext ctx, JsonLexContext *lex) case JSON_PARSE_ARRAY_START: ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type json"), + errmsg("invalid input syntax for type %s", "json"), errdetail("Expected array element or \"]\", but found \"%s\".", token), report_json_context(lex))); @@ -1176,7 +1180,7 @@ report_parse_error(JsonParseContext ctx, JsonLexContext *lex) case JSON_PARSE_ARRAY_NEXT: ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type json"), + errmsg("invalid input syntax for type %s", "json"), errdetail("Expected \",\" or \"]\", but found \"%s\".", token), report_json_context(lex))); @@ -1184,7 +1188,7 @@ report_parse_error(JsonParseContext ctx, JsonLexContext *lex) case JSON_PARSE_OBJECT_START: ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type json"), + errmsg("invalid input syntax for type %s", "json"), errdetail("Expected string or \"}\", but found \"%s\".", token), report_json_context(lex))); @@ -1192,7 +1196,7 @@ report_parse_error(JsonParseContext ctx, JsonLexContext *lex) case JSON_PARSE_OBJECT_LABEL: ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type json"), + errmsg("invalid input syntax for type %s", "json"), errdetail("Expected \":\", but found \"%s\".", token), report_json_context(lex))); @@ -1200,7 +1204,7 @@ report_parse_error(JsonParseContext ctx, JsonLexContext *lex) case JSON_PARSE_OBJECT_NEXT: ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type json"), + errmsg("invalid input syntax for type %s", "json"), errdetail("Expected \",\" or \"}\", but found \"%s\".", token), report_json_context(lex))); @@ -1208,7 +1212,7 @@ report_parse_error(JsonParseContext ctx, JsonLexContext *lex) case JSON_PARSE_OBJECT_COMMA: ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type json"), + errmsg("invalid input syntax for type %s", "json"), errdetail("Expected string, but found \"%s\".", token), report_json_context(lex))); @@ -1238,7 +1242,7 @@ report_invalid_token(JsonLexContext *lex) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type json"), + errmsg("invalid input syntax for type %s", "json"), errdetail("Token \"%s\" is invalid.", token), report_json_context(lex))); } diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c index 987cfd1862..b9bf18ffe5 100644 --- a/src/backend/utils/adt/jsonb.c +++ b/src/backend/utils/adt/jsonb.c @@ -3,7 +3,7 @@ * jsonb.c * I/O routines for jsonb type * - * Copyright (c) 2014-2016, PostgreSQL Global Development Group + * Copyright (c) 2014-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/jsonb.c diff --git a/src/backend/utils/adt/jsonb_gin.c b/src/backend/utils/adt/jsonb_gin.c index 18b7bc5075..16ee6a22d3 100644 --- a/src/backend/utils/adt/jsonb_gin.c +++ b/src/backend/utils/adt/jsonb_gin.c @@ -3,7 +3,7 @@ * jsonb_gin.c * GIN support functions for jsonb * - * Copyright (c) 2014-2016, PostgreSQL Global Development Group + * Copyright (c) 2014-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -20,6 +20,7 @@ #include "catalog/pg_type.h" #include "utils/builtins.h" #include "utils/jsonb.h" +#include "utils/varlena.h" typedef struct PathHashStack { diff --git a/src/backend/utils/adt/jsonb_op.c b/src/backend/utils/adt/jsonb_op.c index 54d6a6d8e4..d4c490e948 100644 --- a/src/backend/utils/adt/jsonb_op.c +++ b/src/backend/utils/adt/jsonb_op.c @@ -3,7 +3,7 @@ * jsonb_op.c * Special operators for jsonb only, used by various index access methods * - * Copyright (c) 2014-2016, PostgreSQL Global Development Group + * Copyright (c) 2014-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -15,6 +15,7 @@ #include "catalog/pg_type.h" #include "miscadmin.h" +#include "utils/builtins.h" #include "utils/jsonb.h" Datum diff --git a/src/backend/utils/adt/jsonb_util.c b/src/backend/utils/adt/jsonb_util.c index ddc34ceec7..11a1395038 100644 --- a/src/backend/utils/adt/jsonb_util.c +++ b/src/backend/utils/adt/jsonb_util.c @@ -3,7 +3,7 @@ * jsonb_util.c * converting between Jsonb and JsonbValues, and iterating. * - * Copyright (c) 2014-2016, PostgreSQL Global Development Group + * Copyright (c) 2014-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -19,6 +19,7 @@ #include "utils/builtins.h" #include "utils/jsonb.h" #include "utils/memutils.h" +#include "utils/varlena.h" /* * Maximum number of elements in an array (or key/value pairs in an object). diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c index a80a20ecee..a75df62d2a 100644 --- a/src/backend/utils/adt/jsonfuncs.c +++ b/src/backend/utils/adt/jsonfuncs.c @@ -3,7 +3,7 @@ * jsonfuncs.c * Functions to process JSON data types. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -34,121 +34,14 @@ #include "utils/typcache.h" /* Operations available for setPath */ -#define JB_PATH_NOOP 0x0000 #define JB_PATH_CREATE 0x0001 #define JB_PATH_DELETE 0x0002 -#define JB_PATH_INSERT_BEFORE 0x0004 -#define JB_PATH_INSERT_AFTER 0x0008 +#define JB_PATH_REPLACE 0x0004 +#define JB_PATH_INSERT_BEFORE 0x0008 +#define JB_PATH_INSERT_AFTER 0x0010 #define JB_PATH_CREATE_OR_INSERT \ (JB_PATH_INSERT_BEFORE | JB_PATH_INSERT_AFTER | JB_PATH_CREATE) -/* semantic action functions for json_object_keys */ -static void okeys_object_field_start(void *state, char *fname, bool isnull); -static void okeys_array_start(void *state); -static void okeys_scalar(void *state, char *token, JsonTokenType tokentype); - -/* semantic action functions for json_get* functions */ -static void get_object_start(void *state); -static void get_object_end(void *state); -static void get_object_field_start(void *state, char *fname, bool isnull); -static void get_object_field_end(void *state, char *fname, bool isnull); -static void get_array_start(void *state); -static void get_array_end(void *state); -static void get_array_element_start(void *state, bool isnull); -static void get_array_element_end(void *state, bool isnull); -static void get_scalar(void *state, char *token, JsonTokenType tokentype); - -/* common worker function for json getter functions */ -static Datum get_path_all(FunctionCallInfo fcinfo, bool as_text); -static text *get_worker(text *json, char **tpath, int *ipath, int npath, - bool normalize_results); -static Datum get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text); - -/* semantic action functions for json_array_length */ -static void alen_object_start(void *state); -static void alen_scalar(void *state, char *token, JsonTokenType tokentype); -static void alen_array_element_start(void *state, bool isnull); - -/* common workers for json{b}_each* functions */ -static Datum each_worker(FunctionCallInfo fcinfo, bool as_text); -static Datum each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, - bool as_text); - -/* semantic action functions for json_each */ -static void each_object_field_start(void *state, char *fname, bool isnull); -static void each_object_field_end(void *state, char *fname, bool isnull); -static void each_array_start(void *state); -static void each_scalar(void *state, char *token, JsonTokenType tokentype); - -/* common workers for json{b}_array_elements_* functions */ -static Datum elements_worker(FunctionCallInfo fcinfo, const char *funcname, - bool as_text); -static Datum elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, - bool as_text); - -/* semantic action functions for json_array_elements */ -static void elements_object_start(void *state); -static void elements_array_element_start(void *state, bool isnull); -static void elements_array_element_end(void *state, bool isnull); -static void elements_scalar(void *state, char *token, JsonTokenType tokentype); - -/* turn a json object into a hash table */ -static HTAB *get_json_object_as_hash(text *json, const char *funcname); - -/* common worker for populate_record and to_record */ -static Datum populate_record_worker(FunctionCallInfo fcinfo, const char *funcname, - bool have_record_arg); - -/* semantic action functions for get_json_object_as_hash */ -static void hash_object_field_start(void *state, char *fname, bool isnull); -static void hash_object_field_end(void *state, char *fname, bool isnull); -static void hash_array_start(void *state); -static void hash_scalar(void *state, char *token, JsonTokenType tokentype); - -/* semantic action functions for populate_recordset */ -static void populate_recordset_object_field_start(void *state, char *fname, bool isnull); -static void populate_recordset_object_field_end(void *state, char *fname, bool isnull); -static void populate_recordset_scalar(void *state, char *token, JsonTokenType tokentype); -static void populate_recordset_object_start(void *state); -static void populate_recordset_object_end(void *state); -static void populate_recordset_array_start(void *state); -static void populate_recordset_array_element_start(void *state, bool isnull); - -/* semantic action functions for json_strip_nulls */ -static void sn_object_start(void *state); -static void sn_object_end(void *state); -static void sn_array_start(void *state); -static void sn_array_end(void *state); -static void sn_object_field_start(void *state, char *fname, bool isnull); -static void sn_array_element_start(void *state, bool isnull); -static void sn_scalar(void *state, char *token, JsonTokenType tokentype); - -/* worker function for populate_recordset and to_recordset */ -static Datum populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname, - bool have_record_arg); - -/* Worker that takes care of common setup for us */ -static JsonbValue *findJsonbValueFromContainerLen(JsonbContainer *container, - uint32 flags, - char *key, - uint32 keylen); - -/* functions supporting jsonb_delete, jsonb_set and jsonb_concat */ -static JsonbValue *IteratorConcat(JsonbIterator **it1, JsonbIterator **it2, - JsonbParseState **state); -static JsonbValue *setPath(JsonbIterator **it, Datum *path_elems, - bool *path_nulls, int path_len, - JsonbParseState **st, int level, Jsonb *newval, - int op_type); -static void setPathObject(JsonbIterator **it, Datum *path_elems, - bool *path_nulls, int path_len, JsonbParseState **st, - int level, - Jsonb *newval, uint32 npairs, int op_type); -static void setPathArray(JsonbIterator **it, Datum *path_elems, - bool *path_nulls, int path_len, JsonbParseState **st, - int level, Jsonb *newval, uint32 nelems, int op_type); -static void addJsonbToParseState(JsonbParseState **jbps, Jsonb *jb); - /* state for json_object_keys */ typedef struct OkeysState { @@ -267,10 +160,118 @@ typedef struct StripnullState bool skip_next_null; } StripnullState; +/* semantic action functions for json_object_keys */ +static void okeys_object_field_start(void *state, char *fname, bool isnull); +static void okeys_array_start(void *state); +static void okeys_scalar(void *state, char *token, JsonTokenType tokentype); + +/* semantic action functions for json_get* functions */ +static void get_object_start(void *state); +static void get_object_end(void *state); +static void get_object_field_start(void *state, char *fname, bool isnull); +static void get_object_field_end(void *state, char *fname, bool isnull); +static void get_array_start(void *state); +static void get_array_end(void *state); +static void get_array_element_start(void *state, bool isnull); +static void get_array_element_end(void *state, bool isnull); +static void get_scalar(void *state, char *token, JsonTokenType tokentype); + +/* common worker function for json getter functions */ +static Datum get_path_all(FunctionCallInfo fcinfo, bool as_text); +static text *get_worker(text *json, char **tpath, int *ipath, int npath, + bool normalize_results); +static Datum get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text); + +/* semantic action functions for json_array_length */ +static void alen_object_start(void *state); +static void alen_scalar(void *state, char *token, JsonTokenType tokentype); +static void alen_array_element_start(void *state, bool isnull); + +/* common workers for json{b}_each* functions */ +static Datum each_worker(FunctionCallInfo fcinfo, bool as_text); +static Datum each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, + bool as_text); + +/* semantic action functions for json_each */ +static void each_object_field_start(void *state, char *fname, bool isnull); +static void each_object_field_end(void *state, char *fname, bool isnull); +static void each_array_start(void *state); +static void each_scalar(void *state, char *token, JsonTokenType tokentype); + +/* common workers for json{b}_array_elements_* functions */ +static Datum elements_worker(FunctionCallInfo fcinfo, const char *funcname, + bool as_text); +static Datum elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, + bool as_text); + +/* semantic action functions for json_array_elements */ +static void elements_object_start(void *state); +static void elements_array_element_start(void *state, bool isnull); +static void elements_array_element_end(void *state, bool isnull); +static void elements_scalar(void *state, char *token, JsonTokenType tokentype); + +/* turn a json object into a hash table */ +static HTAB *get_json_object_as_hash(text *json, const char *funcname); + +/* common worker for populate_record and to_record */ +static Datum populate_record_worker(FunctionCallInfo fcinfo, const char *funcname, + bool have_record_arg); + +/* semantic action functions for get_json_object_as_hash */ +static void hash_object_field_start(void *state, char *fname, bool isnull); +static void hash_object_field_end(void *state, char *fname, bool isnull); +static void hash_array_start(void *state); +static void hash_scalar(void *state, char *token, JsonTokenType tokentype); + +/* semantic action functions for populate_recordset */ +static void populate_recordset_object_field_start(void *state, char *fname, bool isnull); +static void populate_recordset_object_field_end(void *state, char *fname, bool isnull); +static void populate_recordset_scalar(void *state, char *token, JsonTokenType tokentype); +static void populate_recordset_object_start(void *state); +static void populate_recordset_object_end(void *state); +static void populate_recordset_array_start(void *state); +static void populate_recordset_array_element_start(void *state, bool isnull); + +/* semantic action functions for json_strip_nulls */ +static void sn_object_start(void *state); +static void sn_object_end(void *state); +static void sn_array_start(void *state); +static void sn_array_end(void *state); +static void sn_object_field_start(void *state, char *fname, bool isnull); +static void sn_array_element_start(void *state, bool isnull); +static void sn_scalar(void *state, char *token, JsonTokenType tokentype); + /* Turn a jsonb object into a record */ static void make_row_from_rec_and_jsonb(Jsonb *element, PopulateRecordsetState *state); +/* worker function for populate_recordset and to_recordset */ +static Datum populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname, + bool have_record_arg); + +/* Worker that takes care of common setup for us */ +static JsonbValue *findJsonbValueFromContainerLen(JsonbContainer *container, + uint32 flags, + char *key, + uint32 keylen); + +/* functions supporting jsonb_delete, jsonb_set and jsonb_concat */ +static JsonbValue *IteratorConcat(JsonbIterator **it1, JsonbIterator **it2, + JsonbParseState **state); +static JsonbValue *setPath(JsonbIterator **it, Datum *path_elems, + bool *path_nulls, int path_len, + JsonbParseState **st, int level, Jsonb *newval, + int op_type); +static void setPathObject(JsonbIterator **it, Datum *path_elems, + bool *path_nulls, int path_len, JsonbParseState **st, + int level, + Jsonb *newval, uint32 npairs, int op_type); +static void setPathArray(JsonbIterator **it, Datum *path_elems, + bool *path_nulls, int path_len, JsonbParseState **st, + int level, Jsonb *newval, uint32 nelems, int op_type); +static void addJsonbToParseState(JsonbParseState **jbps, Jsonb *jb); + + /* * SQL function json_object_keys * @@ -1503,9 +1504,7 @@ each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text) tmp_cxt = AllocSetContextCreate(CurrentMemoryContext, "jsonb_each temporary cxt", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); it = JsonbIteratorInit(&jb->root); @@ -1641,9 +1640,7 @@ each_worker(FunctionCallInfo fcinfo, bool as_text) state->lex = lex; state->tmp_cxt = AllocSetContextCreate(CurrentMemoryContext, "json_each temporary cxt", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); pg_parse_json(lex, sem); @@ -1822,9 +1819,7 @@ elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, tmp_cxt = AllocSetContextCreate(CurrentMemoryContext, "jsonb_array_elements temporary cxt", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); it = JsonbIteratorInit(&jb->root); @@ -1962,9 +1957,7 @@ elements_worker(FunctionCallInfo fcinfo, const char *funcname, bool as_text) state->lex = lex; state->tmp_cxt = AllocSetContextCreate(CurrentMemoryContext, "json_array_elements temporary cxt", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); pg_parse_json(lex, sem); @@ -3445,6 +3438,92 @@ jsonb_delete(PG_FUNCTION_ARGS) PG_RETURN_JSONB(JsonbValueToJsonb(res)); } +/* + * SQL function jsonb_delete (jsonb, variadic text[]) + * + * return a copy of the jsonb with the indicated items + * removed. + */ +Datum +jsonb_delete_array(PG_FUNCTION_ARGS) +{ + Jsonb *in = PG_GETARG_JSONB(0); + ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1); + Datum *keys_elems; + bool *keys_nulls; + int keys_len; + JsonbParseState *state = NULL; + JsonbIterator *it; + JsonbValue v, + *res = NULL; + bool skipNested = false; + JsonbIteratorToken r; + + if (ARR_NDIM(keys) > 1) + ereport(ERROR, + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), + errmsg("wrong number of array subscripts"))); + + if (JB_ROOT_IS_SCALAR(in)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("cannot delete from scalar"))); + + if (JB_ROOT_COUNT(in) == 0) + PG_RETURN_JSONB(in); + + deconstruct_array(keys, TEXTOID, -1, false, 'i', + &keys_elems, &keys_nulls, &keys_len); + + if (keys_len == 0) + PG_RETURN_JSONB(in); + + it = JsonbIteratorInit(&in->root); + + while ((r = JsonbIteratorNext(&it, &v, skipNested)) != 0) + { + skipNested = true; + + if ((r == WJB_ELEM || r == WJB_KEY) && v.type == jbvString) + { + int i; + bool found = false; + + for (i = 0; i < keys_len; i++) + { + char *keyptr; + int keylen; + + if (keys_nulls[i]) + continue; + + keyptr = VARDATA_ANY(keys_elems[i]); + keylen = VARSIZE_ANY_EXHDR(keys_elems[i]); + if (keylen == v.val.string.len && + memcmp(keyptr, v.val.string.val, keylen) == 0) + { + found = true; + break; + } + } + if (found) + { + /* skip corresponding value as well */ + if (r == WJB_KEY) + JsonbIteratorNext(&it, &v, true); + + continue; + } + } + + res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL); + } + + Assert(res != NULL); + + PG_RETURN_JSONB(JsonbValueToJsonb(res)); +} + /* * SQL function jsonb_delete (jsonb, int) * @@ -3553,7 +3632,7 @@ jsonb_set(PG_FUNCTION_ARGS) it = JsonbIteratorInit(&in->root); res = setPath(&it, path_elems, path_nulls, path_len, &st, - 0, newval, create ? JB_PATH_CREATE : JB_PATH_NOOP); + 0, newval, create ? JB_PATH_CREATE : JB_PATH_REPLACE); Assert(res != NULL); @@ -3562,7 +3641,7 @@ jsonb_set(PG_FUNCTION_ARGS) /* - * SQL function jsonb_delete(jsonb, text[]) + * SQL function jsonb_delete_path(jsonb, text[]) */ Datum jsonb_delete_path(PG_FUNCTION_ARGS) @@ -4011,7 +4090,7 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls, if (op_type & (JB_PATH_INSERT_AFTER | JB_PATH_INSERT_BEFORE)) (void) pushJsonbValue(st, r, &v); - if (op_type & JB_PATH_INSERT_AFTER) + if (op_type & (JB_PATH_INSERT_AFTER | JB_PATH_REPLACE)) addJsonbToParseState(st, newval); done = true; @@ -4043,7 +4122,7 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls, } } - if (op_type & JB_PATH_CREATE_OR_INSERT && !done && + if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done && level == path_len - 1 && i == nelems - 1) { addJsonbToParseState(st, newval); diff --git a/src/backend/utils/adt/levenshtein.c b/src/backend/utils/adt/levenshtein.c index f40557b847..4f40f279db 100644 --- a/src/backend/utils/adt/levenshtein.c +++ b/src/backend/utils/adt/levenshtein.c @@ -16,7 +16,7 @@ * PHP 4.0.6 distribution for inspiration. Configurable penalty costs * extension is introduced by Volkan YAZICI (7/95). * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/adt/like_match.c b/src/backend/utils/adt/like_match.c index 713a3f8603..1c37229e09 100644 --- a/src/backend/utils/adt/like_match.c +++ b/src/backend/utils/adt/like_match.c @@ -16,7 +16,7 @@ * do_like_escape - name of function if wanted - needs CHAREQ and CopyAdvChar * MATCH_LOWER - define for case (4) to specify case folding for 1-byte chars * - * Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/like_match.c diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c index 2e55368061..63f956e670 100644 --- a/src/backend/utils/adt/lockfuncs.c +++ b/src/backend/utils/adt/lockfuncs.c @@ -3,7 +3,7 @@ * lockfuncs.c * Functions for SQL access to various lock-manager capabilities. * - * Copyright (c) 2002-2016, PostgreSQL Global Development Group + * Copyright (c) 2002-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/lockfuncs.c diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c index 509315ae0e..2270b223ea 100644 --- a/src/backend/utils/adt/mac.c +++ b/src/backend/utils/adt/mac.c @@ -65,7 +65,8 @@ macaddr_in(PG_FUNCTION_ARGS) if (count != 6) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type macaddr: \"%s\"", str))); + errmsg("invalid input syntax for type %s: \"%s\"", "macaddr", + str))); if ((a < 0) || (a > 255) || (b < 0) || (b > 255) || (c < 0) || (c > 255) || (d < 0) || (d > 255) || diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index 5e705e9308..66d09bcb0c 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -3,7 +3,7 @@ * misc.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -29,6 +29,7 @@ #include "common/keywords.h" #include "funcapi.h" #include "miscadmin.h" +#include "pgstat.h" #include "parser/scansup.h" #include "postmaster/syslogger.h" #include "rewrite/rewriteHandler.h" @@ -560,7 +561,8 @@ pg_sleep(PG_FUNCTION_ARGS) (void) WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT, - delay_ms); + delay_ms, + WAIT_EVENT_PG_SLEEP); ResetLatch(MyLatch); } diff --git a/src/backend/utils/adt/nabstime.c b/src/backend/utils/adt/nabstime.c index 421ca6f229..c9d0b0d7fb 100644 --- a/src/backend/utils/adt/nabstime.c +++ b/src/backend/utils/adt/nabstime.c @@ -5,7 +5,7 @@ * Functions for the built-in type "RelativeTime". * Functions for the built-in type "TimeInterval". * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -1547,8 +1547,8 @@ parsetinterval(char *i_string, bogus: ereport(ERROR, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), - errmsg("invalid input syntax for type tinterval: \"%s\"", - i_string))); + errmsg("invalid input syntax for type %s: \"%s\"", + "tinterval", i_string))); *i_start = *i_end = INVALID_ABSTIME; /* keep compiler quiet */ } diff --git a/src/backend/utils/adt/name.c b/src/backend/utils/adt/name.c index 476ac4f659..e41ee478ec 100644 --- a/src/backend/utils/adt/name.c +++ b/src/backend/utils/adt/name.c @@ -9,7 +9,7 @@ * always use NAMEDATALEN as the symbolic constant! - jolly 8/21/95 * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c index 1f8469a2cb..dbc557e583 100644 --- a/src/backend/utils/adt/network.c +++ b/src/backend/utils/adt/network.c @@ -14,7 +14,7 @@ #include "access/hash.h" #include "catalog/pg_type.h" -#include "libpq/ip.h" +#include "common/ip.h" #include "libpq/libpq-be.h" #include "libpq/pqformat.h" #include "miscadmin.h" @@ -268,11 +268,7 @@ Datum inet_to_cidr(PG_FUNCTION_ARGS) { inet *src = PG_GETARG_INET_PP(0); - inet *dst; int bits; - int byte; - int nbits; - int maxbytes; bits = ip_bits(src); @@ -280,29 +276,7 @@ inet_to_cidr(PG_FUNCTION_ARGS) if ((bits < 0) || (bits > ip_maxbits(src))) elog(ERROR, "invalid inet bit length: %d", bits); - /* clone the original data */ - dst = (inet *) palloc(VARSIZE_ANY(src)); - memcpy(dst, src, VARSIZE_ANY(src)); - - /* zero out any bits to the right of the netmask */ - byte = bits / 8; - - nbits = bits % 8; - /* clear the first byte, this might be a partial byte */ - if (nbits != 0) - { - ip_addr(dst)[byte] &= ~(0xFF >> nbits); - byte++; - } - /* clear remaining bytes */ - maxbytes = ip_addrsize(dst); - while (byte < maxbytes) - { - ip_addr(dst)[byte] = 0; - byte++; - } - - PG_RETURN_INET_P(dst); + PG_RETURN_INET_P(cidr_set_masklen_internal(src, bits)); } Datum @@ -334,10 +308,6 @@ cidr_set_masklen(PG_FUNCTION_ARGS) { inet *src = PG_GETARG_INET_PP(0); int bits = PG_GETARG_INT32(1); - inet *dst; - int byte; - int nbits; - int maxbytes; if (bits == -1) bits = ip_maxbits(src); @@ -347,31 +317,36 @@ cidr_set_masklen(PG_FUNCTION_ARGS) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid mask length: %d", bits))); - /* clone the original data */ - dst = (inet *) palloc(VARSIZE_ANY(src)); - memcpy(dst, src, VARSIZE_ANY(src)); + PG_RETURN_INET_P(cidr_set_masklen_internal(src, bits)); +} - ip_bits(dst) = bits; +/* + * Copy src and set mask length to 'bits' (which must be valid for the family) + */ +inet * +cidr_set_masklen_internal(const inet *src, int bits) +{ + inet *dst = (inet *) palloc0(sizeof(inet)); - /* zero out any bits to the right of the new netmask */ - byte = bits / 8; + ip_family(dst) = ip_family(src); + ip_bits(dst) = bits; - nbits = bits % 8; - /* clear the first byte, this might be a partial byte */ - if (nbits != 0) + if (bits > 0) { - ip_addr(dst)[byte] &= ~(0xFF >> nbits); - byte++; - } - /* clear remaining bytes */ - maxbytes = ip_addrsize(dst); - while (byte < maxbytes) - { - ip_addr(dst)[byte] = 0; - byte++; + Assert(bits <= ip_maxbits(dst)); + + /* Clone appropriate bytes of the address, leaving the rest 0 */ + memcpy(ip_addr(dst), ip_addr(src), (bits + 7) / 8); + + /* Clear any unwanted bits in the last partial byte */ + if (bits % 8) + ip_addr(dst)[bits / 8] &= ~(0xFF >> (bits % 8)); } - PG_RETURN_INET_P(dst); + /* Set varlena header correctly */ + SET_INET_VARSIZE(dst); + + return dst; } /* @@ -719,11 +694,7 @@ network_broadcast(PG_FUNCTION_ARGS) /* make sure any unused bits are zeroed */ dst = (inet *) palloc0(sizeof(inet)); - if (ip_family(ip) == PGSQL_AF_INET) - maxbytes = 4; - else - maxbytes = 16; - + maxbytes = ip_addrsize(ip); bits = ip_bits(ip); a = ip_addr(ip); b = ip_addr(dst); @@ -853,11 +824,7 @@ network_hostmask(PG_FUNCTION_ARGS) /* make sure any unused bits are zeroed */ dst = (inet *) palloc0(sizeof(inet)); - if (ip_family(ip) == PGSQL_AF_INET) - maxbytes = 4; - else - maxbytes = 16; - + maxbytes = ip_addrsize(ip); bits = ip_maxbits(ip) - ip_bits(ip); b = ip_addr(dst); @@ -907,8 +874,7 @@ Datum inet_merge(PG_FUNCTION_ARGS) { inet *a1 = PG_GETARG_INET_PP(0), - *a2 = PG_GETARG_INET_PP(1), - *result; + *a2 = PG_GETARG_INET_PP(1); int commonbits; if (ip_family(a1) != ip_family(a2)) @@ -919,24 +885,7 @@ inet_merge(PG_FUNCTION_ARGS) commonbits = bitncommon(ip_addr(a1), ip_addr(a2), Min(ip_bits(a1), ip_bits(a2))); - /* Make sure any unused bits are zeroed. */ - result = (inet *) palloc0(sizeof(inet)); - - ip_family(result) = ip_family(a1); - ip_bits(result) = commonbits; - - /* Clone appropriate bytes of the address. */ - if (commonbits > 0) - memcpy(ip_addr(result), ip_addr(a1), (commonbits + 7) / 8); - - /* Clean any unwanted bits in the last partial byte. */ - if (commonbits % 8 != 0) - ip_addr(result)[commonbits / 8] &= ~(0xFF >> (commonbits % 8)); - - /* Set varlena header correctly. */ - SET_INET_VARSIZE(result); - - PG_RETURN_INET_P(result); + PG_RETURN_INET_P(cidr_set_masklen_internal(a1, commonbits)); } /* diff --git a/src/backend/utils/adt/network_gist.c b/src/backend/utils/adt/network_gist.c index 2caff941e7..a0097dae9c 100644 --- a/src/backend/utils/adt/network_gist.c +++ b/src/backend/utils/adt/network_gist.c @@ -34,7 +34,7 @@ * twice as fast as for a simpler design in which a single field doubles as * the common prefix length and the minimum ip_bits value. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -49,6 +49,7 @@ #include "access/gist.h" #include "access/stratnum.h" +#include "utils/builtins.h" #include "utils/inet.h" /* diff --git a/src/backend/utils/adt/network_selfuncs.c b/src/backend/utils/adt/network_selfuncs.c index 2e39687fb9..bcdd902ee8 100644 --- a/src/backend/utils/adt/network_selfuncs.c +++ b/src/backend/utils/adt/network_selfuncs.c @@ -7,7 +7,7 @@ * operators. Estimates are based on null fraction, most common values, * and histogram of inet/cidr columns. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -23,6 +23,7 @@ #include "access/htup_details.h" #include "catalog/pg_operator.h" #include "catalog/pg_statistic.h" +#include "utils/builtins.h" #include "utils/inet.h" #include "utils/lsyscache.h" #include "utils/selfuncs.h" diff --git a/src/backend/utils/adt/network_spgist.c b/src/backend/utils/adt/network_spgist.c new file mode 100644 index 0000000000..c48f45fe47 --- /dev/null +++ b/src/backend/utils/adt/network_spgist.c @@ -0,0 +1,711 @@ +/*------------------------------------------------------------------------- + * + * network_spgist.c + * SP-GiST support for network types. + * + * We split inet index entries first by address family (IPv4 or IPv6). + * If the entries below a given inner tuple are all of the same family, + * we identify their common prefix and split by the next bit of the address, + * and by whether their masklens exceed the length of the common prefix. + * + * An inner tuple that has both IPv4 and IPv6 children has a null prefix + * and exactly two nodes, the first being for IPv4 and the second for IPv6. + * + * Otherwise, the prefix is a CIDR value representing the common prefix, + * and there are exactly four nodes. Node numbers 0 and 1 are for addresses + * with the same masklen as the prefix, while node numbers 2 and 3 are for + * addresses with larger masklen. (We do not allow a tuple to contain + * entries with masklen smaller than its prefix's.) Node numbers 0 and 1 + * are distinguished by the next bit of the address after the common prefix, + * and likewise for node numbers 2 and 3. If there are no more bits in + * the address family, everything goes into node 0 (which will probably + * lead to creating an allTheSame tuple). + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/utils/adt/network_spgist.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include + +#include "access/spgist.h" +#include "catalog/pg_type.h" +#include "utils/builtins.h" +#include "utils/inet.h" + + +static int inet_spg_node_number(const inet *val, int commonbits); +static int inet_spg_consistent_bitmap(const inet *prefix, int nkeys, + ScanKey scankeys, bool leaf); + +/* + * The SP-GiST configuration function + */ +Datum +inet_spg_config(PG_FUNCTION_ARGS) +{ + /* spgConfigIn *cfgin = (spgConfigIn *) PG_GETARG_POINTER(0); */ + spgConfigOut *cfg = (spgConfigOut *) PG_GETARG_POINTER(1); + + cfg->prefixType = CIDROID; + cfg->labelType = VOIDOID; + cfg->canReturnData = true; + cfg->longValuesOK = false; + + PG_RETURN_VOID(); +} + +/* + * The SP-GiST choose function + */ +Datum +inet_spg_choose(PG_FUNCTION_ARGS) +{ + spgChooseIn *in = (spgChooseIn *) PG_GETARG_POINTER(0); + spgChooseOut *out = (spgChooseOut *) PG_GETARG_POINTER(1); + inet *val = DatumGetInetPP(in->datum), + *prefix; + int commonbits; + + /* + * If we're looking at a tuple that splits by address family, choose the + * appropriate subnode. + */ + if (!in->hasPrefix) + { + /* allTheSame isn't possible for such a tuple */ + Assert(!in->allTheSame); + Assert(in->nNodes == 2); + + out->resultType = spgMatchNode; + out->result.matchNode.nodeN = (ip_family(val) == PGSQL_AF_INET) ? 0 : 1; + out->result.matchNode.restDatum = InetPGetDatum(val); + + PG_RETURN_VOID(); + } + + /* Else it must split by prefix */ + Assert(in->nNodes == 4 || in->allTheSame); + + prefix = DatumGetInetPP(in->prefixDatum); + commonbits = ip_bits(prefix); + + /* + * We cannot put addresses from different families under the same inner + * node, so we have to split if the new value's family is different. + */ + if (ip_family(val) != ip_family(prefix)) + { + /* Set up 2-node tuple */ + out->resultType = spgSplitTuple; + out->result.splitTuple.prefixHasPrefix = false; + out->result.splitTuple.prefixNNodes = 2; + out->result.splitTuple.prefixNodeLabels = NULL; + + /* Identify which node the existing data goes into */ + out->result.splitTuple.childNodeN = + (ip_family(prefix) == PGSQL_AF_INET) ? 0 : 1; + + out->result.splitTuple.postfixHasPrefix = true; + out->result.splitTuple.postfixPrefixDatum = InetPGetDatum(prefix); + + PG_RETURN_VOID(); + } + + /* + * If the new value does not match the existing prefix, we have to split. + */ + if (ip_bits(val) < commonbits || + bitncmp(ip_addr(prefix), ip_addr(val), commonbits) != 0) + { + /* Determine new prefix length for the split tuple */ + commonbits = bitncommon(ip_addr(prefix), ip_addr(val), + Min(ip_bits(val), commonbits)); + + /* Set up 4-node tuple */ + out->resultType = spgSplitTuple; + out->result.splitTuple.prefixHasPrefix = true; + out->result.splitTuple.prefixPrefixDatum = + InetPGetDatum(cidr_set_masklen_internal(val, commonbits)); + out->result.splitTuple.prefixNNodes = 4; + out->result.splitTuple.prefixNodeLabels = NULL; + + /* Identify which node the existing data goes into */ + out->result.splitTuple.childNodeN = + inet_spg_node_number(prefix, commonbits); + + out->result.splitTuple.postfixHasPrefix = true; + out->result.splitTuple.postfixPrefixDatum = InetPGetDatum(prefix); + + PG_RETURN_VOID(); + } + + /* + * All OK, choose the node to descend into. (If this tuple is marked + * allTheSame, the core code will ignore our choice of nodeN; but we need + * not account for that case explicitly here.) + */ + out->resultType = spgMatchNode; + out->result.matchNode.nodeN = inet_spg_node_number(val, commonbits); + out->result.matchNode.restDatum = InetPGetDatum(val); + + PG_RETURN_VOID(); +} + +/* + * The GiST PickSplit method + */ +Datum +inet_spg_picksplit(PG_FUNCTION_ARGS) +{ + spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0); + spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1); + inet *prefix, + *tmp; + int i, + commonbits; + bool differentFamilies = false; + + /* Initialize the prefix with the first item */ + prefix = DatumGetInetPP(in->datums[0]); + commonbits = ip_bits(prefix); + + /* Examine remaining items to discover minimum common prefix length */ + for (i = 1; i < in->nTuples; i++) + { + tmp = DatumGetInetPP(in->datums[i]); + + if (ip_family(tmp) != ip_family(prefix)) + { + differentFamilies = true; + break; + } + + if (ip_bits(tmp) < commonbits) + commonbits = ip_bits(tmp); + commonbits = bitncommon(ip_addr(prefix), ip_addr(tmp), commonbits); + if (commonbits == 0) + break; + } + + /* Don't need labels; allocate output arrays */ + out->nodeLabels = NULL; + out->mapTuplesToNodes = (int *) palloc(sizeof(int) * in->nTuples); + out->leafTupleDatums = (Datum *) palloc(sizeof(Datum) * in->nTuples); + + if (differentFamilies) + { + /* Set up 2-node tuple */ + out->hasPrefix = false; + out->nNodes = 2; + + for (i = 0; i < in->nTuples; i++) + { + tmp = DatumGetInetPP(in->datums[i]); + out->mapTuplesToNodes[i] = + (ip_family(tmp) == PGSQL_AF_INET) ? 0 : 1; + out->leafTupleDatums[i] = InetPGetDatum(tmp); + } + } + else + { + /* Set up 4-node tuple */ + out->hasPrefix = true; + out->prefixDatum = + InetPGetDatum(cidr_set_masklen_internal(prefix, commonbits)); + out->nNodes = 4; + + for (i = 0; i < in->nTuples; i++) + { + tmp = DatumGetInetPP(in->datums[i]); + out->mapTuplesToNodes[i] = inet_spg_node_number(tmp, commonbits); + out->leafTupleDatums[i] = InetPGetDatum(tmp); + } + } + + PG_RETURN_VOID(); +} + +/* + * The SP-GiST query consistency check for inner tuples + */ +Datum +inet_spg_inner_consistent(PG_FUNCTION_ARGS) +{ + spgInnerConsistentIn *in = (spgInnerConsistentIn *) PG_GETARG_POINTER(0); + spgInnerConsistentOut *out = (spgInnerConsistentOut *) PG_GETARG_POINTER(1); + int i; + int which; + + if (!in->hasPrefix) + { + Assert(!in->allTheSame); + Assert(in->nNodes == 2); + + /* Identify which child nodes need to be visited */ + which = 1 | (1 << 1); + + for (i = 0; i < in->nkeys; i++) + { + StrategyNumber strategy = in->scankeys[i].sk_strategy; + inet *argument = DatumGetInetPP(in->scankeys[i].sk_argument); + + switch (strategy) + { + case RTLessStrategyNumber: + case RTLessEqualStrategyNumber: + if (ip_family(argument) == PGSQL_AF_INET) + which &= 1; + break; + + case RTGreaterEqualStrategyNumber: + case RTGreaterStrategyNumber: + if (ip_family(argument) == PGSQL_AF_INET6) + which &= (1 << 1); + break; + + case RTNotEqualStrategyNumber: + break; + + default: + /* all other ops can only match addrs of same family */ + if (ip_family(argument) == PGSQL_AF_INET) + which &= 1; + else + which &= (1 << 1); + break; + } + } + } + else if (!in->allTheSame) + { + Assert(in->nNodes == 4); + + /* Identify which child nodes need to be visited */ + which = inet_spg_consistent_bitmap(DatumGetInetPP(in->prefixDatum), + in->nkeys, in->scankeys, false); + } + else + { + /* Must visit all nodes; we assume there are less than 32 of 'em */ + which = ~0; + } + + out->nNodes = 0; + + if (which) + { + out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes); + + for (i = 0; i < in->nNodes; i++) + { + if (which & (1 << i)) + { + out->nodeNumbers[out->nNodes] = i; + out->nNodes++; + } + } + } + + PG_RETURN_VOID(); +} + +/* + * The SP-GiST query consistency check for leaf tuples + */ +Datum +inet_spg_leaf_consistent(PG_FUNCTION_ARGS) +{ + spgLeafConsistentIn *in = (spgLeafConsistentIn *) PG_GETARG_POINTER(0); + spgLeafConsistentOut *out = (spgLeafConsistentOut *) PG_GETARG_POINTER(1); + inet *leaf = DatumGetInetPP(in->leafDatum); + + /* All tests are exact. */ + out->recheck = false; + + /* Leaf is what it is... */ + out->leafValue = InetPGetDatum(leaf); + + /* Use common code to apply the tests. */ + PG_RETURN_BOOL(inet_spg_consistent_bitmap(leaf, in->nkeys, in->scankeys, + true)); +} + +/* + * Calculate node number (within a 4-node, single-family inner index tuple) + * + * The value must have the same family as the node's prefix, and + * commonbits is the mask length of the prefix. We use even or odd + * nodes according to the next address bit after the commonbits, + * and low or high nodes according to whether the value's mask length + * is larger than commonbits. + */ +static int +inet_spg_node_number(const inet *val, int commonbits) +{ + int nodeN = 0; + + if (commonbits < ip_maxbits(val) && + ip_addr(val)[commonbits / 8] & (1 << (7 - commonbits % 8))) + nodeN |= 1; + if (commonbits < ip_bits(val)) + nodeN |= 2; + + return nodeN; +} + +/* + * Calculate bitmap of node numbers that are consistent with the query + * + * This can be used either at a 4-way inner tuple, or at a leaf tuple. + * In the latter case, we should return a boolean result (0 or 1) + * not a bitmap. + * + * This definition is pretty odd, but the inner and leaf consistency checks + * are mostly common and it seems best to keep them in one function. + */ +static int +inet_spg_consistent_bitmap(const inet *prefix, int nkeys, ScanKey scankeys, + bool leaf) +{ + int bitmap; + int commonbits, + i; + + /* Initialize result to allow visiting all children */ + if (leaf) + bitmap = 1; + else + bitmap = 1 | (1 << 1) | (1 << 2) | (1 << 3); + + commonbits = ip_bits(prefix); + + for (i = 0; i < nkeys; i++) + { + inet *argument = DatumGetInetPP(scankeys[i].sk_argument); + StrategyNumber strategy = scankeys[i].sk_strategy; + int order; + + /* + * Check 0: different families + * + * Matching families do not help any of the strategies. + */ + if (ip_family(argument) != ip_family(prefix)) + { + switch (strategy) + { + case RTLessStrategyNumber: + case RTLessEqualStrategyNumber: + if (ip_family(argument) < ip_family(prefix)) + bitmap = 0; + break; + + case RTGreaterEqualStrategyNumber: + case RTGreaterStrategyNumber: + if (ip_family(argument) > ip_family(prefix)) + bitmap = 0; + break; + + case RTNotEqualStrategyNumber: + break; + + default: + /* For all other cases, we can be sure there is no match */ + bitmap = 0; + break; + } + + if (!bitmap) + break; + + /* Other checks make no sense with different families. */ + continue; + } + + /* + * Check 1: network bit count + * + * Network bit count (ip_bits) helps to check leaves for sub network + * and sup network operators. At non-leaf nodes, we know every child + * value has greater ip_bits, so we can avoid descending in some cases + * too. + * + * This check is less expensive than checking the address bits, so we + * are doing this before, but it has to be done after for the basic + * comparison strategies, because ip_bits only affect their results + * when the common network bits are the same. + */ + switch (strategy) + { + case RTSubStrategyNumber: + if (commonbits <= ip_bits(argument)) + bitmap &= (1 << 2) | (1 << 3); + break; + + case RTSubEqualStrategyNumber: + if (commonbits < ip_bits(argument)) + bitmap &= (1 << 2) | (1 << 3); + break; + + case RTSuperStrategyNumber: + if (commonbits == ip_bits(argument) - 1) + bitmap &= 1 | (1 << 1); + else if (commonbits >= ip_bits(argument)) + bitmap = 0; + break; + + case RTSuperEqualStrategyNumber: + if (commonbits == ip_bits(argument)) + bitmap &= 1 | (1 << 1); + else if (commonbits > ip_bits(argument)) + bitmap = 0; + break; + + case RTEqualStrategyNumber: + if (commonbits < ip_bits(argument)) + bitmap &= (1 << 2) | (1 << 3); + else if (commonbits == ip_bits(argument)) + bitmap &= 1 | (1 << 1); + else + bitmap = 0; + break; + } + + if (!bitmap) + break; + + /* + * Check 2: common network bits + * + * Compare available common prefix bits to the query, but not beyond + * either the query's netmask or the minimum netmask among the + * represented values. If these bits don't match the query, we can + * eliminate some cases. + */ + order = bitncmp(ip_addr(prefix), ip_addr(argument), + Min(commonbits, ip_bits(argument))); + + if (order != 0) + { + switch (strategy) + { + case RTLessStrategyNumber: + case RTLessEqualStrategyNumber: + if (order > 0) + bitmap = 0; + break; + + case RTGreaterEqualStrategyNumber: + case RTGreaterStrategyNumber: + if (order < 0) + bitmap = 0; + break; + + case RTNotEqualStrategyNumber: + break; + + default: + /* For all other cases, we can be sure there is no match */ + bitmap = 0; + break; + } + + if (!bitmap) + break; + + /* + * Remaining checks make no sense when common bits don't match. + */ + continue; + } + + /* + * Check 3: next network bit + * + * We can filter out branch 2 or 3 using the next network bit of the + * argument, if it is available. + * + * This check matters for the performance of the search. The results + * would be correct without it. + */ + if (bitmap & ((1 << 2) | (1 << 3)) && + commonbits < ip_bits(argument)) + { + int nextbit; + + nextbit = ip_addr(argument)[commonbits / 8] & + (1 << (7 - commonbits % 8)); + + switch (strategy) + { + case RTLessStrategyNumber: + case RTLessEqualStrategyNumber: + if (!nextbit) + bitmap &= 1 | (1 << 1) | (1 << 2); + break; + + case RTGreaterEqualStrategyNumber: + case RTGreaterStrategyNumber: + if (nextbit) + bitmap &= 1 | (1 << 1) | (1 << 3); + break; + + case RTNotEqualStrategyNumber: + break; + + default: + if (!nextbit) + bitmap &= 1 | (1 << 1) | (1 << 2); + else + bitmap &= 1 | (1 << 1) | (1 << 3); + break; + } + + if (!bitmap) + break; + } + + /* + * Remaining checks are only for the basic comparison strategies. This + * test relies on the strategy number ordering defined in stratnum.h. + */ + if (strategy < RTEqualStrategyNumber || + strategy > RTGreaterEqualStrategyNumber) + continue; + + /* + * Check 4: network bit count + * + * At this point, we know that the common network bits of the prefix + * and the argument are the same, so we can go forward and check the + * ip_bits. + */ + switch (strategy) + { + case RTLessStrategyNumber: + case RTLessEqualStrategyNumber: + if (commonbits == ip_bits(argument)) + bitmap &= 1 | (1 << 1); + else if (commonbits > ip_bits(argument)) + bitmap = 0; + break; + + case RTGreaterEqualStrategyNumber: + case RTGreaterStrategyNumber: + if (commonbits < ip_bits(argument)) + bitmap &= (1 << 2) | (1 << 3); + break; + } + + if (!bitmap) + break; + + /* Remaining checks don't make sense with different ip_bits. */ + if (commonbits != ip_bits(argument)) + continue; + + /* + * Check 5: next host bit + * + * We can filter out branch 0 or 1 using the next host bit of the + * argument, if it is available. + * + * This check matters for the performance of the search. The results + * would be correct without it. There is no point in running it for + * leafs as we have to check the whole address on the next step. + */ + if (!leaf && bitmap & (1 | (1 << 1)) && + commonbits < ip_maxbits(argument)) + { + int nextbit; + + nextbit = ip_addr(argument)[commonbits / 8] & + (1 << (7 - commonbits % 8)); + + switch (strategy) + { + case RTLessStrategyNumber: + case RTLessEqualStrategyNumber: + if (!nextbit) + bitmap &= 1 | (1 << 2) | (1 << 3); + break; + + case RTGreaterEqualStrategyNumber: + case RTGreaterStrategyNumber: + if (nextbit) + bitmap &= (1 << 1) | (1 << 2) | (1 << 3); + break; + + case RTNotEqualStrategyNumber: + break; + + default: + if (!nextbit) + bitmap &= 1 | (1 << 2) | (1 << 3); + else + bitmap &= (1 << 1) | (1 << 2) | (1 << 3); + break; + } + + if (!bitmap) + break; + } + + /* + * Check 6: whole address + * + * This is the last check for correctness of the basic comparison + * strategies. It's only appropriate at leaf entries. + */ + if (leaf) + { + /* Redo ordering comparison using all address bits */ + order = bitncmp(ip_addr(prefix), ip_addr(argument), + ip_maxbits(prefix)); + + switch (strategy) + { + case RTLessStrategyNumber: + if (order >= 0) + bitmap = 0; + break; + + case RTLessEqualStrategyNumber: + if (order > 0) + bitmap = 0; + break; + + case RTEqualStrategyNumber: + if (order != 0) + bitmap = 0; + break; + + case RTGreaterEqualStrategyNumber: + if (order < 0) + bitmap = 0; + break; + + case RTGreaterStrategyNumber: + if (order <= 0) + bitmap = 0; + break; + + case RTNotEqualStrategyNumber: + if (order == 0) + bitmap = 0; + break; + } + + if (!bitmap) + break; + } + } + + return bitmap; +} diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 620226cea1..fa4e1b1e62 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -11,7 +11,7 @@ * Transactions on Mathematical Software, Vol. 24, No. 4, December 1998, * pages 359-367. * - * Copyright (c) 1998-2016, PostgreSQL Global Development Group + * Copyright (c) 1998-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/numeric.c @@ -302,6 +302,49 @@ typedef struct hyperLogLogState abbr_card; /* cardinality estimator */ } NumericSortSupport; + +/* ---------- + * Fast sum accumulator. + * + * NumericSumAccum is used to implement SUM(), and other standard aggregates + * that track the sum of input values. It uses 32-bit integers to store the + * digits, instead of the normal 16-bit integers (with NBASE=10000). This + * way, we can safely accumulate up to NBASE - 1 values without propagating + * carry, before risking overflow of any of the digits. 'num_uncarried' + * tracks how many values have been accumulated without propagating carry. + * + * Positive and negative values are accumulated separately, in 'pos_digits' + * and 'neg_digits'. This is simpler and faster than deciding whether to add + * or subtract from the current value, for each new value (see sub_var() for + * the logic we avoid by doing this). Both buffers are of same size, and + * have the same weight and scale. In accum_sum_final(), the positive and + * negative sums are added together to produce the final result. + * + * When a new value has a larger ndigits or weight than the accumulator + * currently does, the accumulator is enlarged to accommodate the new value. + * We normally have one zero digit reserved for carry propagation, and that + * is indicated by the 'have_carry_space' flag. When accum_sum_carry() uses + * up the reserved digit, it clears the 'have_carry_space' flag. The next + * call to accum_sum_add() will enlarge the buffer, to make room for the + * extra digit, and set the flag again. + * + * To initialize a new accumulator, simply reset all fields to zeros. + * + * The accumulator does not handle NaNs. + * ---------- + */ +typedef struct NumericSumAccum +{ + int ndigits; + int weight; + int dscale; + int num_uncarried; + bool have_carry_space; + int32 *pos_digits; + int32 *neg_digits; +} NumericSumAccum; + + /* * We define our own macros for packing and unpacking abbreviated-key * representations for numeric values in order to avoid depending on @@ -490,6 +533,14 @@ static void strip_var(NumericVar *var); static void compute_bucket(Numeric operand, Numeric bound1, Numeric bound2, NumericVar *count_var, NumericVar *result_var); +static void accum_sum_add(NumericSumAccum *accum, NumericVar *var1); +static void accum_sum_rescale(NumericSumAccum *accum, NumericVar *val); +static void accum_sum_carry(NumericSumAccum *accum); +static void accum_sum_reset(NumericSumAccum *accum); +static void accum_sum_final(NumericSumAccum *accum, NumericVar *result); +static void accum_sum_copy(NumericSumAccum *dst, NumericSumAccum *src); +static void accum_sum_combine(NumericSumAccum *accum, NumericSumAccum *accum2); + /* ---------------------------------------------------------------------- * @@ -539,8 +590,8 @@ numeric_in(PG_FUNCTION_ARGS) if (!isspace((unsigned char) *cp)) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type numeric: \"%s\"", - str))); + errmsg("invalid input syntax for type %s: \"%s\"", + "numeric", str))); cp++; } } @@ -566,8 +617,8 @@ numeric_in(PG_FUNCTION_ARGS) if (!isspace((unsigned char) *cp)) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type numeric: \"%s\"", - str))); + errmsg("invalid input syntax for type %s: \"%s\"", + "numeric", str))); cp++; } @@ -3059,7 +3110,11 @@ numeric_float8(PG_FUNCTION_ARGS) } -/* Convert numeric to float8; if out of range, return +/- HUGE_VAL */ +/* + * Convert numeric to float8; if out of range, return +/- HUGE_VAL + * + * (internal helper function, not directly callable from SQL) + */ Datum numeric_float8_no_overflow(PG_FUNCTION_ARGS) { @@ -3140,8 +3195,8 @@ typedef struct NumericAggState bool calcSumX2; /* if true, calculate sumX2 */ MemoryContext agg_context; /* context we're calculating in */ int64 N; /* count of processed numbers */ - NumericVar sumX; /* sum of processed numbers */ - NumericVar sumX2; /* sum of squares of processed numbers */ + NumericSumAccum sumX; /* sum of processed numbers */ + NumericSumAccum sumX2; /* sum of squares of processed numbers */ int maxScale; /* maximum scale seen so far */ int64 maxScaleCount; /* number of values seen with maximum scale */ int64 NaNcount; /* count of NaN values (not included in N!) */ @@ -3230,22 +3285,13 @@ do_numeric_accum(NumericAggState *state, Numeric newval) /* The rest of this needs to work in the aggregate context */ old_context = MemoryContextSwitchTo(state->agg_context); - if (state->N++ > 0) - { - /* Accumulate sums */ - add_var(&X, &(state->sumX), &(state->sumX)); + state->N++; - if (state->calcSumX2) - add_var(&X2, &(state->sumX2), &(state->sumX2)); - } - else - { - /* First input, so initialize sums */ - set_var_from_var(&X, &(state->sumX)); + /* Accumulate sums */ + accum_sum_add(&(state->sumX), &X); - if (state->calcSumX2) - set_var_from_var(&X2, &(state->sumX2)); - } + if (state->calcSumX2) + accum_sum_add(&(state->sumX2), &X2); MemoryContextSwitchTo(old_context); } @@ -3324,16 +3370,25 @@ do_numeric_discard(NumericAggState *state, Numeric newval) if (state->N-- > 1) { - /* De-accumulate sums */ - sub_var(&(state->sumX), &X, &(state->sumX)); + /* Negate X, to subtract it from the sum */ + X.sign = (X.sign == NUMERIC_POS ? NUMERIC_NEG : NUMERIC_POS); + accum_sum_add(&(state->sumX), &X); if (state->calcSumX2) - sub_var(&(state->sumX2), &X2, &(state->sumX2)); + { + /* Negate X^2. X^2 is always positive */ + X2.sign = NUMERIC_NEG; + accum_sum_add(&(state->sumX2), &X2); + } } else { - /* Sums will be reset by next call to do_numeric_accum */ + /* Zero the sums */ Assert(state->N == 0); + + accum_sum_reset(&state->sumX); + if (state->calcSumX2) + accum_sum_reset(&state->sumX2); } MemoryContextSwitchTo(old_context); @@ -3392,11 +3447,8 @@ numeric_combine(PG_FUNCTION_ARGS) state1->maxScale = state2->maxScale; state1->maxScaleCount = state2->maxScaleCount; - init_var(&state1->sumX); - set_var_from_var(&state2->sumX, &state1->sumX); - - init_var(&state1->sumX2); - set_var_from_var(&state2->sumX2, &state1->sumX2); + accum_sum_copy(&state1->sumX, &state2->sumX); + accum_sum_copy(&state1->sumX2, &state2->sumX2); MemoryContextSwitchTo(old_context); @@ -3424,8 +3476,8 @@ numeric_combine(PG_FUNCTION_ARGS) old_context = MemoryContextSwitchTo(agg_context); /* Accumulate sums */ - add_var(&(state1->sumX), &(state2->sumX), &(state1->sumX)); - add_var(&(state1->sumX2), &(state2->sumX2), &(state1->sumX2)); + accum_sum_combine(&state1->sumX, &state2->sumX); + accum_sum_combine(&state1->sumX2, &state2->sumX2); MemoryContextSwitchTo(old_context); } @@ -3483,8 +3535,7 @@ numeric_avg_combine(PG_FUNCTION_ARGS) state1->maxScale = state2->maxScale; state1->maxScaleCount = state2->maxScaleCount; - init_var(&state1->sumX); - set_var_from_var(&state2->sumX, &state1->sumX); + accum_sum_copy(&state1->sumX, &state2->sumX); MemoryContextSwitchTo(old_context); @@ -3512,7 +3563,7 @@ numeric_avg_combine(PG_FUNCTION_ARGS) old_context = MemoryContextSwitchTo(agg_context); /* Accumulate sums */ - add_var(&(state1->sumX), &(state2->sumX), &(state1->sumX)); + accum_sum_combine(&state1->sumX, &state2->sumX); MemoryContextSwitchTo(old_context); } @@ -3532,6 +3583,7 @@ numeric_avg_serialize(PG_FUNCTION_ARGS) Datum temp; bytea *sumX; bytea *result; + NumericVar tmp_var; /* Ensure we disallow calling when not in aggregate context */ if (!AggCheckCallContext(fcinfo, NULL)) @@ -3545,9 +3597,13 @@ numeric_avg_serialize(PG_FUNCTION_ARGS) * splitting the tasks in numeric_send into separate functions to stop * this? Doing so would also remove the fmgr call overhead. */ + init_var(&tmp_var); + accum_sum_final(&state->sumX, &tmp_var); + temp = DirectFunctionCall1(numeric_send, - NumericGetDatum(make_result(&state->sumX))); + NumericGetDatum(make_result(&tmp_var))); sumX = DatumGetByteaP(temp); + free_var(&tmp_var); pq_begintypsend(&buf); @@ -3582,6 +3638,7 @@ numeric_avg_deserialize(PG_FUNCTION_ARGS) bytea *sstate; NumericAggState *result; Datum temp; + NumericVar tmp_var; StringInfoData buf; if (!AggCheckCallContext(fcinfo, NULL)) @@ -3606,7 +3663,8 @@ numeric_avg_deserialize(PG_FUNCTION_ARGS) PointerGetDatum(&buf), InvalidOid, -1); - set_var_from_num(DatumGetNumeric(temp), &result->sumX); + init_var_from_num(DatumGetNumeric(temp), &tmp_var); + accum_sum_add(&(result->sumX), &tmp_var); /* maxScale */ result->maxScale = pq_getmsgint(&buf, 4); @@ -3635,6 +3693,7 @@ numeric_serialize(PG_FUNCTION_ARGS) StringInfoData buf; Datum temp; bytea *sumX; + NumericVar tmp_var; bytea *sumX2; bytea *result; @@ -3650,14 +3709,20 @@ numeric_serialize(PG_FUNCTION_ARGS) * splitting the tasks in numeric_send into separate functions to stop * this? Doing so would also remove the fmgr call overhead. */ + init_var(&tmp_var); + + accum_sum_final(&state->sumX, &tmp_var); temp = DirectFunctionCall1(numeric_send, - NumericGetDatum(make_result(&state->sumX))); + NumericGetDatum(make_result(&tmp_var))); sumX = DatumGetByteaP(temp); + accum_sum_final(&state->sumX2, &tmp_var); temp = DirectFunctionCall1(numeric_send, - NumericGetDatum(make_result(&state->sumX2))); + NumericGetDatum(make_result(&tmp_var))); sumX2 = DatumGetByteaP(temp); + free_var(&tmp_var); + pq_begintypsend(&buf); /* N */ @@ -3694,6 +3759,8 @@ numeric_deserialize(PG_FUNCTION_ARGS) bytea *sstate; NumericAggState *result; Datum temp; + NumericVar sumX_var; + NumericVar sumX2_var; StringInfoData buf; if (!AggCheckCallContext(fcinfo, NULL)) @@ -3718,14 +3785,16 @@ numeric_deserialize(PG_FUNCTION_ARGS) PointerGetDatum(&buf), InvalidOid, -1); - set_var_from_num(DatumGetNumeric(temp), &result->sumX); + init_var_from_num(DatumGetNumeric(temp), &sumX_var); + accum_sum_add(&(result->sumX), &sumX_var); /* sumX2 */ temp = DirectFunctionCall3(numeric_recv, PointerGetDatum(&buf), InvalidOid, -1); - set_var_from_num(DatumGetNumeric(temp), &result->sumX2); + init_var_from_num(DatumGetNumeric(temp), &sumX2_var); + accum_sum_add(&(result->sumX2), &sumX2_var); /* maxScale */ result->maxScale = pq_getmsgint(&buf, 4); @@ -3974,11 +4043,8 @@ numeric_poly_combine(PG_FUNCTION_ARGS) state1->sumX = state2->sumX; state1->sumX2 = state2->sumX2; #else - init_var(&(state1->sumX)); - set_var_from_var(&(state2->sumX), &(state1->sumX)); - - init_var(&state1->sumX2); - set_var_from_var(&(state2->sumX2), &(state1->sumX2)); + accum_sum_copy(&state2->sumX, &state1->sumX); + accum_sum_copy(&state2->sumX2, &state1->sumX2); #endif MemoryContextSwitchTo(old_context); @@ -3998,8 +4064,8 @@ numeric_poly_combine(PG_FUNCTION_ARGS) old_context = MemoryContextSwitchTo(agg_context); /* Accumulate sums */ - add_var(&(state1->sumX), &(state2->sumX), &(state1->sumX)); - add_var(&(state1->sumX2), &(state2->sumX2), &(state1->sumX2)); + accum_sum_combine(&state1->sumX, &state2->sumX); + accum_sum_combine(&state1->sumX2, &state2->sumX2); MemoryContextSwitchTo(old_context); #endif @@ -4038,30 +4104,29 @@ numeric_poly_serialize(PG_FUNCTION_ARGS) */ { Datum temp; - -#ifdef HAVE_INT128 NumericVar num; init_var(&num); + +#ifdef HAVE_INT128 int128_to_numericvar(state->sumX, &num); +#else + accum_sum_final(&state->sumX, &num); +#endif temp = DirectFunctionCall1(numeric_send, NumericGetDatum(make_result(&num))); sumX = DatumGetByteaP(temp); +#ifdef HAVE_INT128 int128_to_numericvar(state->sumX2, &num); +#else + accum_sum_final(&state->sumX2, &num); +#endif temp = DirectFunctionCall1(numeric_send, NumericGetDatum(make_result(&num))); sumX2 = DatumGetByteaP(temp); - free_var(&num); -#else - temp = DirectFunctionCall1(numeric_send, - NumericGetDatum(make_result(&state->sumX))); - sumX = DatumGetByteaP(temp); - temp = DirectFunctionCall1(numeric_send, - NumericGetDatum(make_result(&state->sumX2))); - sumX2 = DatumGetByteaP(temp); -#endif + free_var(&num); } pq_begintypsend(&buf); @@ -4091,7 +4156,9 @@ numeric_poly_deserialize(PG_FUNCTION_ARGS) bytea *sstate; PolyNumAggState *result; Datum sumX; + NumericVar sumX_var; Datum sumX2; + NumericVar sumX2_var; StringInfoData buf; if (!AggCheckCallContext(fcinfo, NULL)) @@ -4123,22 +4190,18 @@ numeric_poly_deserialize(PG_FUNCTION_ARGS) InvalidOid, -1); + init_var_from_num(DatumGetNumeric(sumX), &sumX_var); #ifdef HAVE_INT128 - { - NumericVar num; - - init_var(&num); - set_var_from_num(DatumGetNumeric(sumX), &num); - numericvar_to_int128(&num, &result->sumX); - - set_var_from_num(DatumGetNumeric(sumX2), &num); - numericvar_to_int128(&num, &result->sumX2); + numericvar_to_int128(&sumX_var, &result->sumX); +#else + accum_sum_add(&result->sumX, &sumX_var); +#endif - free_var(&num); - } + init_var_from_num(DatumGetNumeric(sumX2), &sumX2_var); +#ifdef HAVE_INT128 + numericvar_to_int128(&sumX2_var, &result->sumX2); #else - set_var_from_num(DatumGetNumeric(sumX), &result->sumX); - set_var_from_num(DatumGetNumeric(sumX2), &result->sumX2); + accum_sum_add(&result->sumX2, &sumX2_var); #endif pq_getmsgend(&buf); @@ -4209,8 +4272,7 @@ int8_avg_combine(PG_FUNCTION_ARGS) #ifdef HAVE_INT128 state1->sumX = state2->sumX; #else - init_var(&state1->sumX); - set_var_from_var(&state2->sumX, &state1->sumX); + accum_sum_copy(&state1->sumX, &state2->sumX); #endif MemoryContextSwitchTo(old_context); @@ -4228,7 +4290,7 @@ int8_avg_combine(PG_FUNCTION_ARGS) old_context = MemoryContextSwitchTo(agg_context); /* Accumulate sums */ - add_var(&(state1->sumX), &(state2->sumX), &(state1->sumX)); + accum_sum_combine(&state1->sumX, &state2->sumX); MemoryContextSwitchTo(old_context); #endif @@ -4266,20 +4328,20 @@ int8_avg_serialize(PG_FUNCTION_ARGS) */ { Datum temp; -#ifdef HAVE_INT128 NumericVar num; init_var(&num); + +#ifdef HAVE_INT128 int128_to_numericvar(state->sumX, &num); - temp = DirectFunctionCall1(numeric_send, - NumericGetDatum(make_result(&num))); - free_var(&num); - sumX = DatumGetByteaP(temp); #else + accum_sum_final(&state->sumX, &num); +#endif temp = DirectFunctionCall1(numeric_send, - NumericGetDatum(make_result(&state->sumX))); + NumericGetDatum(make_result(&num))); sumX = DatumGetByteaP(temp); -#endif + + free_var(&num); } pq_begintypsend(&buf); @@ -4306,6 +4368,7 @@ int8_avg_deserialize(PG_FUNCTION_ARGS) PolyNumAggState *result; StringInfoData buf; Datum temp; + NumericVar num; if (!AggCheckCallContext(fcinfo, NULL)) elog(ERROR, "aggregate function called in non-aggregate context"); @@ -4329,18 +4392,11 @@ int8_avg_deserialize(PG_FUNCTION_ARGS) PointerGetDatum(&buf), InvalidOid, -1); - + init_var_from_num(DatumGetNumeric(temp), &num); #ifdef HAVE_INT128 - { - NumericVar num; - - init_var(&num); - set_var_from_num(DatumGetNumeric(temp), &num); - numericvar_to_int128(&num, &result->sumX); - free_var(&num); - } + numericvar_to_int128(&num, &result->sumX); #else - set_var_from_num(DatumGetNumeric(temp), &result->sumX); + accum_sum_add(&result->sumX, &num); #endif pq_getmsgend(&buf); @@ -4534,6 +4590,7 @@ numeric_avg(PG_FUNCTION_ARGS) NumericAggState *state; Datum N_datum; Datum sumX_datum; + NumericVar sumX_var; state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0); @@ -4545,7 +4602,11 @@ numeric_avg(PG_FUNCTION_ARGS) PG_RETURN_NUMERIC(make_result(&const_nan)); N_datum = DirectFunctionCall1(int8_numeric, Int64GetDatum(state->N)); - sumX_datum = NumericGetDatum(make_result(&state->sumX)); + + init_var(&sumX_var); + accum_sum_final(&state->sumX, &sumX_var); + sumX_datum = NumericGetDatum(make_result(&sumX_var)); + free_var(&sumX_var); PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumX_datum, N_datum)); } @@ -4554,6 +4615,8 @@ Datum numeric_sum(PG_FUNCTION_ARGS) { NumericAggState *state; + NumericVar sumX_var; + Numeric result; state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0); @@ -4564,7 +4627,12 @@ numeric_sum(PG_FUNCTION_ARGS) if (state->NaNcount > 0) /* there was at least one NaN input */ PG_RETURN_NUMERIC(make_result(&const_nan)); - PG_RETURN_NUMERIC(make_result(&(state->sumX))); + init_var(&sumX_var); + accum_sum_final(&state->sumX, &sumX_var); + result = make_result(&sumX_var); + free_var(&sumX_var); + + PG_RETURN_NUMERIC(result); } /* @@ -4608,8 +4676,8 @@ numeric_stddev_internal(NumericAggState *state, init_var(&vsumX2); int64_to_numericvar(state->N, &vN); - set_var_from_var(&(state->sumX), &vsumX); - set_var_from_var(&(state->sumX2), &vsumX2); + accum_sum_final(&(state->sumX), &vsumX); + accum_sum_final(&(state->sumX2), &vsumX2); /* * Sample stddev and variance are undefined when N <= 1; population stddev @@ -4739,26 +4807,38 @@ numeric_poly_stddev_internal(Int128AggState *state, NumericAggState numstate; Numeric res; - init_var(&numstate.sumX); - init_var(&numstate.sumX2); - numstate.NaNcount = 0; - numstate.agg_context = NULL; + /* Initialize an empty agg state */ + memset(&numstate, 0, sizeof(NumericAggState)); if (state) { + NumericVar tmp_var; + numstate.N = state->N; - int128_to_numericvar(state->sumX, &numstate.sumX); - int128_to_numericvar(state->sumX2, &numstate.sumX2); - } - else - { - numstate.N = 0; + + init_var(&tmp_var); + + int128_to_numericvar(state->sumX, &tmp_var); + accum_sum_add(&numstate.sumX, &tmp_var); + + int128_to_numericvar(state->sumX2, &tmp_var); + accum_sum_add(&numstate.sumX2, &tmp_var); + + free_var(&tmp_var); } res = numeric_stddev_internal(&numstate, variance, sample, is_null); - free_var(&numstate.sumX); - free_var(&numstate.sumX2); + if (numstate.sumX.ndigits > 0) + { + pfree(numstate.sumX.pos_digits); + pfree(numstate.sumX.neg_digits); + } + if (numstate.sumX2.ndigits > 0) + { + pfree(numstate.sumX2.pos_digits); + pfree(numstate.sumX2.neg_digits); + } return res; } @@ -5402,7 +5482,8 @@ set_var_from_str(const char *str, const char *cp, NumericVar *dest) if (!isdigit((unsigned char) *cp)) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type numeric: \"%s\"", str))); + errmsg("invalid input syntax for type %s: \"%s\"", + "numeric", str))); decdigits = (unsigned char *) palloc(strlen(cp) + DEC_DIGITS * 2); @@ -5425,8 +5506,8 @@ set_var_from_str(const char *str, const char *cp, NumericVar *dest) if (have_dp) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type numeric: \"%s\"", - str))); + errmsg("invalid input syntax for type %s: \"%s\"", + "numeric", str))); have_dp = TRUE; cp++; } @@ -5449,8 +5530,8 @@ set_var_from_str(const char *str, const char *cp, NumericVar *dest) if (endptr == cp) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type numeric: \"%s\"", - str))); + errmsg("invalid input syntax for type %s: \"%s\"", + "numeric", str))); cp = endptr; /* @@ -6251,8 +6332,8 @@ numeric_to_double_no_overflow(Numeric num) /* shouldn't happen ... */ ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type double precision: \"%s\"", - tmp))); + errmsg("invalid input syntax for type %s: \"%s\"", + "double precision", tmp))); } pfree(tmp); @@ -6277,8 +6358,8 @@ numericvar_to_double_no_overflow(NumericVar *var) /* shouldn't happen ... */ ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type double precision: \"%s\"", - tmp))); + errmsg("invalid input syntax for type %s: \"%s\"", + "double precision", tmp))); } pfree(tmp); @@ -8702,3 +8783,322 @@ strip_var(NumericVar *var) var->digits = digits; var->ndigits = ndigits; } + + +/* ---------------------------------------------------------------------- + * + * Fast sum accumulator functions + * + * ---------------------------------------------------------------------- + */ + +/* + * Reset the accumulator's value to zero. The buffers to hold the digits + * are not free'd. + */ +static void +accum_sum_reset(NumericSumAccum *accum) +{ + int i; + + accum->dscale = 0; + for (i = 0; i < accum->ndigits; i++) + { + accum->pos_digits[i] = 0; + accum->neg_digits[i] = 0; + } +} + +/* + * Accumulate a new value. + */ +static void +accum_sum_add(NumericSumAccum *accum, NumericVar *val) +{ + int32 *accum_digits; + int i, + val_i; + int val_ndigits; + NumericDigit *val_digits; + + /* + * If we have accumulated too many values since the last carry + * propagation, do it now, to avoid overflowing. (We could allow more + * than NBASE - 1, if we reserved two extra digits, rather than one, for + * carry propagation. But even with NBASE - 1, this needs to be done so + * seldom, that the performance difference is negligible.) + */ + if (accum->num_uncarried == NBASE - 1) + accum_sum_carry(accum); + + /* + * Adjust the weight or scale of the old value, so that it can accommodate + * the new value. + */ + accum_sum_rescale(accum, val); + + /* */ + if (val->sign == NUMERIC_POS) + accum_digits = accum->pos_digits; + else + accum_digits = accum->neg_digits; + + /* copy these values into local vars for speed in loop */ + val_ndigits = val->ndigits; + val_digits = val->digits; + + i = accum->weight - val->weight; + for (val_i = 0; val_i < val_ndigits; val_i++) + { + accum_digits[i] += (int32) val_digits[val_i]; + i++; + } + + accum->num_uncarried++; +} + +/* + * Propagate carries. + */ +static void +accum_sum_carry(NumericSumAccum *accum) +{ + int i; + int ndigits; + int32 *dig; + int32 carry; + int32 newdig = 0; + + /* + * If no new values have been added since last carry propagation, nothing + * to do. + */ + if (accum->num_uncarried == 0) + return; + + /* + * We maintain that the weight of the accumulator is always one larger + * than needed to hold the current value, before carrying, to make sure + * there is enough space for the possible extra digit when carry is + * propagated. We cannot expand the buffer here, unless we require + * callers of accum_sum_final() to switch to the right memory context. + */ + Assert(accum->pos_digits[0] == 0 && accum->neg_digits[0] == 0); + + ndigits = accum->ndigits; + + /* Propagate carry in the positive sum */ + dig = accum->pos_digits; + carry = 0; + for (i = ndigits - 1; i >= 0; i--) + { + newdig = dig[i] + carry; + if (newdig >= NBASE) + { + carry = newdig / NBASE; + newdig -= carry * NBASE; + } + else + carry = 0; + dig[i] = newdig; + } + /* Did we use up the digit reserved for carry propagation? */ + if (newdig > 0) + accum->have_carry_space = false; + + /* And the same for the negative sum */ + dig = accum->neg_digits; + carry = 0; + for (i = ndigits - 1; i >= 0; i--) + { + newdig = dig[i] + carry; + if (newdig >= NBASE) + { + carry = newdig / NBASE; + newdig -= carry * NBASE; + } + else + carry = 0; + dig[i] = newdig; + } + if (newdig > 0) + accum->have_carry_space = false; + + accum->num_uncarried = 0; +} + +/* + * Re-scale accumulator to accommodate new value. + * + * If the new value has more digits than the current digit buffers in the + * accumulator, enlarge the buffers. + */ +static void +accum_sum_rescale(NumericSumAccum *accum, NumericVar *val) +{ + int old_weight = accum->weight; + int old_ndigits = accum->ndigits; + int accum_ndigits; + int accum_weight; + int accum_rscale; + int val_rscale; + + accum_weight = old_weight; + accum_ndigits = old_ndigits; + + /* + * Does the new value have a larger weight? If so, enlarge the buffers, + * and shift the existing value to the new weight, by adding leading + * zeros. + * + * We enforce that the accumulator always has a weight one larger than + * needed for the inputs, so that we have space for an extra digit at the + * final carry-propagation phase, if necessary. + */ + if (val->weight >= accum_weight) + { + accum_weight = val->weight + 1; + accum_ndigits = accum_ndigits + (accum_weight - old_weight); + } + + /* + * Even though the new value is small, we might've used up the space + * reserved for the carry digit in the last call to accum_sum_carry(). If + * so, enlarge to make room for another one. + */ + else if (!accum->have_carry_space) + { + accum_weight++; + accum_ndigits++; + } + + /* Is the new value wider on the right side? */ + accum_rscale = accum_ndigits - accum_weight - 1; + val_rscale = val->ndigits - val->weight - 1; + if (val_rscale > accum_rscale) + accum_ndigits = accum_ndigits + (val_rscale - accum_rscale); + + if (accum_ndigits != old_ndigits || + accum_weight != old_weight) + { + int32 *new_pos_digits; + int32 *new_neg_digits; + int weightdiff; + + weightdiff = accum_weight - old_weight; + + new_pos_digits = palloc0(accum_ndigits * sizeof(int32)); + new_neg_digits = palloc0(accum_ndigits * sizeof(int32)); + + if (accum->pos_digits) + { + memcpy(&new_pos_digits[weightdiff], accum->pos_digits, + old_ndigits * sizeof(int32)); + pfree(accum->pos_digits); + + memcpy(&new_neg_digits[weightdiff], accum->neg_digits, + old_ndigits * sizeof(int32)); + pfree(accum->neg_digits); + } + + accum->pos_digits = new_pos_digits; + accum->neg_digits = new_neg_digits; + + accum->weight = accum_weight; + accum->ndigits = accum_ndigits; + + Assert(accum->pos_digits[0] == 0 && accum->neg_digits[0] == 0); + accum->have_carry_space = true; + } + + if (val->dscale > accum->dscale) + accum->dscale = val->dscale; +} + +/* + * Return the current value of the accumulator. This perform final carry + * propagation, and adds together the positive and negative sums. + * + * Unlike all the other routines, the caller is not required to switch to + * the memory context that holds the accumulator. + */ +static void +accum_sum_final(NumericSumAccum *accum, NumericVar *result) +{ + int i; + NumericVar pos_var; + NumericVar neg_var; + + if (accum->ndigits == 0) + { + set_var_from_var(&const_zero, result); + return; + } + + /* Perform final carry */ + accum_sum_carry(accum); + + /* Create NumericVars representing the positive and negative sums */ + init_var(&pos_var); + init_var(&neg_var); + + pos_var.ndigits = neg_var.ndigits = accum->ndigits; + pos_var.weight = neg_var.weight = accum->weight; + pos_var.dscale = neg_var.dscale = accum->dscale; + pos_var.sign = NUMERIC_POS; + neg_var.sign = NUMERIC_NEG; + + pos_var.buf = pos_var.digits = digitbuf_alloc(accum->ndigits); + neg_var.buf = neg_var.digits = digitbuf_alloc(accum->ndigits); + + for (i = 0; i < accum->ndigits; i++) + { + Assert(accum->pos_digits[i] < NBASE); + pos_var.digits[i] = (int16) accum->pos_digits[i]; + + Assert(accum->neg_digits[i] < NBASE); + neg_var.digits[i] = (int16) accum->neg_digits[i]; + } + + /* And add them together */ + add_var(&pos_var, &neg_var, result); + + /* Remove leading/trailing zeroes */ + strip_var(result); +} + +/* + * Copy an accumulator's state. + * + * 'dst' is assumed to be uninitialized beforehand. No attempt is made at + * freeing old values. + */ +static void +accum_sum_copy(NumericSumAccum *dst, NumericSumAccum *src) +{ + dst->pos_digits = palloc(src->ndigits * sizeof(int32)); + dst->neg_digits = palloc(src->ndigits * sizeof(int32)); + + memcpy(dst->pos_digits, src->pos_digits, src->ndigits * sizeof(int32)); + memcpy(dst->neg_digits, src->neg_digits, src->ndigits * sizeof(int32)); + dst->num_uncarried = src->num_uncarried; + dst->ndigits = src->ndigits; + dst->weight = src->weight; + dst->dscale = src->dscale; +} + +/* + * Add the current value of 'accum2' into 'accum'. + */ +static void +accum_sum_combine(NumericSumAccum *accum, NumericSumAccum *accum2) +{ + NumericVar tmp_var; + + init_var(&tmp_var); + + accum_sum_final(accum2, &tmp_var); + accum_sum_add(accum, &tmp_var); + + free_var(&tmp_var); +} diff --git a/src/backend/utils/adt/numutils.c b/src/backend/utils/adt/numutils.c index 362098ea1d..4ea2892c98 100644 --- a/src/backend/utils/adt/numutils.c +++ b/src/backend/utils/adt/numutils.c @@ -3,7 +3,7 @@ * numutils.c * utility functions for I/O of built-in numeric types. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -48,8 +48,8 @@ pg_atoi(const char *s, int size, int c) if (*s == 0) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for integer: \"%s\"", - s))); + errmsg("invalid input syntax for %s: \"%s\"", + "integer", s))); errno = 0; l = strtol(s, &badp, 10); @@ -58,8 +58,8 @@ pg_atoi(const char *s, int size, int c) if (s == badp) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for integer: \"%s\"", - s))); + errmsg("invalid input syntax for %s: \"%s\"", + "integer", s))); switch (size) { @@ -72,13 +72,15 @@ pg_atoi(const char *s, int size, int c) ) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("value \"%s\" is out of range for type integer", s))); + errmsg("value \"%s\" is out of range for type %s", s, + "integer"))); break; case sizeof(int16): if (errno == ERANGE || l < SHRT_MIN || l > SHRT_MAX) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("value \"%s\" is out of range for type smallint", s))); + errmsg("value \"%s\" is out of range for type %s", s, + "smallint"))); break; case sizeof(int8): if (errno == ERANGE || l < SCHAR_MIN || l > SCHAR_MAX) @@ -100,8 +102,8 @@ pg_atoi(const char *s, int size, int c) if (*badp && *badp != c) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for integer: \"%s\"", - s))); + errmsg("invalid input syntax for %s: \"%s\"", + "integer", s))); return (int32) l; } diff --git a/src/backend/utils/adt/oid.c b/src/backend/utils/adt/oid.c index bb29dfc21a..12ef783b3f 100644 --- a/src/backend/utils/adt/oid.c +++ b/src/backend/utils/adt/oid.c @@ -3,7 +3,7 @@ * oid.c * Functions for the built-in type Oid ... also oidvector. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -19,6 +19,7 @@ #include "catalog/pg_type.h" #include "libpq/pqformat.h" +#include "nodes/value.h" #include "utils/array.h" #include "utils/builtins.h" @@ -40,8 +41,8 @@ oidin_subr(const char *s, char **endloc) if (*s == '\0') ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type oid: \"%s\"", - s))); + errmsg("invalid input syntax for type %s: \"%s\"", + "oid", s))); errno = 0; cvt = strtoul(s, &endptr, 10); @@ -54,19 +55,20 @@ oidin_subr(const char *s, char **endloc) if (errno && errno != ERANGE && errno != EINVAL) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type oid: \"%s\"", - s))); + errmsg("invalid input syntax for type %s: \"%s\"", + "oid", s))); if (endptr == s && *s != '\0') ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type oid: \"%s\"", - s))); + errmsg("invalid input syntax for type %s: \"%s\"", + "oid", s))); if (errno == ERANGE) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("value \"%s\" is out of range for type oid", s))); + errmsg("value \"%s\" is out of range for type %s", + s, "oid"))); if (endloc) { @@ -81,8 +83,8 @@ oidin_subr(const char *s, char **endloc) if (*endptr) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type oid: \"%s\"", - s))); + errmsg("invalid input syntax for type %s: \"%s\"", + "oid", s))); } result = (Oid) cvt; @@ -104,7 +106,8 @@ oidin_subr(const char *s, char **endloc) cvt != (unsigned long) ((int) result)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("value \"%s\" is out of range for type oid", s))); + errmsg("value \"%s\" is out of range for type %s", + s, "oid"))); #endif return result; diff --git a/src/backend/utils/adt/oracle_compat.c b/src/backend/utils/adt/oracle_compat.c index 377a6502b4..b82016500b 100644 --- a/src/backend/utils/adt/oracle_compat.c +++ b/src/backend/utils/adt/oracle_compat.c @@ -2,7 +2,7 @@ * oracle_compat.c * Oracle compatible functions. * - * Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Copyright (c) 1996-2017, PostgreSQL Global Development Group * * Author: Edmund Mergl * Multibyte enhancement: Tatsuo Ishii diff --git a/src/backend/utils/adt/orderedsetaggs.c b/src/backend/utils/adt/orderedsetaggs.c index fe44d56129..f9f18f2cc6 100644 --- a/src/backend/utils/adt/orderedsetaggs.c +++ b/src/backend/utils/adt/orderedsetaggs.c @@ -3,7 +3,7 @@ * orderedsetaggs.c * Ordered-set aggregate functions. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c index a818023faa..4c7f1dad50 100644 --- a/src/backend/utils/adt/pg_locale.c +++ b/src/backend/utils/adt/pg_locale.c @@ -2,7 +2,7 @@ * * PostgreSQL locale utilities * - * Portions Copyright (c) 2002-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2002-2017, PostgreSQL Global Development Group * * src/backend/utils/adt/pg_locale.c * @@ -382,51 +382,91 @@ assign_locale_messages(const char *newval, void *extra) /* * Frees the malloced content of a struct lconv. (But not the struct - * itself.) + * itself.) It's important that this not throw elog(ERROR). */ static void free_struct_lconv(struct lconv * s) { - if (s->currency_symbol) - free(s->currency_symbol); if (s->decimal_point) free(s->decimal_point); - if (s->grouping) - free(s->grouping); if (s->thousands_sep) free(s->thousands_sep); + if (s->grouping) + free(s->grouping); if (s->int_curr_symbol) free(s->int_curr_symbol); + if (s->currency_symbol) + free(s->currency_symbol); if (s->mon_decimal_point) free(s->mon_decimal_point); - if (s->mon_grouping) - free(s->mon_grouping); if (s->mon_thousands_sep) free(s->mon_thousands_sep); - if (s->negative_sign) - free(s->negative_sign); + if (s->mon_grouping) + free(s->mon_grouping); if (s->positive_sign) free(s->positive_sign); + if (s->negative_sign) + free(s->negative_sign); +} + +/* + * Check that all fields of a struct lconv (or at least, the ones we care + * about) are non-NULL. The field list must match free_struct_lconv(). + */ +static bool +struct_lconv_is_valid(struct lconv * s) +{ + if (s->decimal_point == NULL) + return false; + if (s->thousands_sep == NULL) + return false; + if (s->grouping == NULL) + return false; + if (s->int_curr_symbol == NULL) + return false; + if (s->currency_symbol == NULL) + return false; + if (s->mon_decimal_point == NULL) + return false; + if (s->mon_thousands_sep == NULL) + return false; + if (s->mon_grouping == NULL) + return false; + if (s->positive_sign == NULL) + return false; + if (s->negative_sign == NULL) + return false; + return true; } /* - * Return a strdup'ed string converted from the specified encoding to the + * Convert the strdup'd string at *str from the specified encoding to the * database encoding. */ -static char * -db_encoding_strdup(int encoding, const char *str) +static void +db_encoding_convert(int encoding, char **str) { char *pstr; char *mstr; /* convert the string to the database encoding */ - pstr = pg_any_to_server(str, strlen(str), encoding); + pstr = pg_any_to_server(*str, strlen(*str), encoding); + if (pstr == *str) + return; /* no conversion happened */ + + /* need it malloc'd not palloc'd */ mstr = strdup(pstr); - if (pstr != str) - pfree(pstr); + if (mstr == NULL) + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); + + /* replace old string */ + free(*str); + *str = mstr; - return mstr; + pfree(pstr); } @@ -440,13 +480,10 @@ PGLC_localeconv(void) static struct lconv CurrentLocaleConv; static bool CurrentLocaleConvAllocated = false; struct lconv *extlconv; + struct lconv worklconv; + bool trouble = false; char *save_lc_monetary; char *save_lc_numeric; - char *decimal_point; - char *grouping; - char *thousands_sep; - int encoding; - #ifdef WIN32 char *save_lc_ctype; #endif @@ -462,6 +499,20 @@ PGLC_localeconv(void) CurrentLocaleConvAllocated = false; } + /* + * This is tricky because we really don't want to risk throwing error + * while the locale is set to other than our usual settings. Therefore, + * the process is: collect the usual settings, set locale to special + * setting, copy relevant data into worklconv using strdup(), restore + * normal settings, convert data to desired encoding, and finally stash + * the collected data in CurrentLocaleConv. This makes it safe if we + * throw an error during encoding conversion or run out of memory anywhere + * in the process. All data pointed to by struct lconv members is + * allocated with strdup, to avoid premature elog(ERROR) and to allow + * using a single cleanup routine. + */ + memset(&worklconv, 0, sizeof(worklconv)); + /* Save user's values of monetary and numeric locales */ save_lc_monetary = setlocale(LC_MONETARY, NULL); if (save_lc_monetary) @@ -477,7 +528,7 @@ PGLC_localeconv(void) * Ideally, monetary and numeric local symbols could be returned in any * server encoding. Unfortunately, the WIN32 API does not allow * setlocale() to return values in a codepage/CTYPE that uses more than - * two bytes per character, like UTF-8: + * two bytes per character, such as UTF-8: * * http://msdn.microsoft.com/en-us/library/x99tb11d.aspx * @@ -487,7 +538,7 @@ PGLC_localeconv(void) * * Therefore, we set LC_CTYPE to match LC_NUMERIC or LC_MONETARY (which * cannot be UTF8), call localeconv(), and then convert from the - * numeric/monitary LC_CTYPE to the server encoding. One example use of + * numeric/monetary LC_CTYPE to the server encoding. One example use of * this is for the Euro symbol. * * Perhaps someday we will use GetLocaleInfoW() which returns values in @@ -499,6 +550,8 @@ PGLC_localeconv(void) if (save_lc_ctype) save_lc_ctype = pstrdup(save_lc_ctype); + /* Here begins the critical section where we must not throw error */ + /* use numeric to set the ctype */ setlocale(LC_CTYPE, locale_numeric); #endif @@ -506,11 +559,11 @@ PGLC_localeconv(void) /* Get formatting information for numeric */ setlocale(LC_NUMERIC, locale_numeric); extlconv = localeconv(); - encoding = pg_get_encoding_from_locale(locale_numeric, true); - decimal_point = db_encoding_strdup(encoding, extlconv->decimal_point); - thousands_sep = db_encoding_strdup(encoding, extlconv->thousands_sep); - grouping = strdup(extlconv->grouping); + /* Must copy data now in case setlocale() overwrites it */ + worklconv.decimal_point = strdup(extlconv->decimal_point); + worklconv.thousands_sep = strdup(extlconv->thousands_sep); + worklconv.grouping = strdup(extlconv->grouping); #ifdef WIN32 /* use monetary to set the ctype */ @@ -520,40 +573,36 @@ PGLC_localeconv(void) /* Get formatting information for monetary */ setlocale(LC_MONETARY, locale_monetary); extlconv = localeconv(); - encoding = pg_get_encoding_from_locale(locale_monetary, true); - /* - * Must copy all values since restoring internal settings may overwrite - * localeconv()'s results. Note that if we were to fail within this - * sequence before reaching "CurrentLocaleConvAllocated = true", we could - * leak some memory --- but not much, so it's not worth agonizing over. - */ - CurrentLocaleConv = *extlconv; - CurrentLocaleConv.decimal_point = decimal_point; - CurrentLocaleConv.grouping = grouping; - CurrentLocaleConv.thousands_sep = thousands_sep; - CurrentLocaleConv.int_curr_symbol = db_encoding_strdup(encoding, extlconv->int_curr_symbol); - CurrentLocaleConv.currency_symbol = db_encoding_strdup(encoding, extlconv->currency_symbol); - CurrentLocaleConv.mon_decimal_point = db_encoding_strdup(encoding, extlconv->mon_decimal_point); - CurrentLocaleConv.mon_grouping = strdup(extlconv->mon_grouping); - CurrentLocaleConv.mon_thousands_sep = db_encoding_strdup(encoding, extlconv->mon_thousands_sep); - CurrentLocaleConv.negative_sign = db_encoding_strdup(encoding, extlconv->negative_sign); - CurrentLocaleConv.positive_sign = db_encoding_strdup(encoding, extlconv->positive_sign); - CurrentLocaleConvAllocated = true; + /* Must copy data now in case setlocale() overwrites it */ + worklconv.int_curr_symbol = strdup(extlconv->int_curr_symbol); + worklconv.currency_symbol = strdup(extlconv->currency_symbol); + worklconv.mon_decimal_point = strdup(extlconv->mon_decimal_point); + worklconv.mon_thousands_sep = strdup(extlconv->mon_thousands_sep); + worklconv.mon_grouping = strdup(extlconv->mon_grouping); + worklconv.positive_sign = strdup(extlconv->positive_sign); + worklconv.negative_sign = strdup(extlconv->negative_sign); + /* Copy scalar fields as well */ + worklconv.int_frac_digits = extlconv->int_frac_digits; + worklconv.frac_digits = extlconv->frac_digits; + worklconv.p_cs_precedes = extlconv->p_cs_precedes; + worklconv.p_sep_by_space = extlconv->p_sep_by_space; + worklconv.n_cs_precedes = extlconv->n_cs_precedes; + worklconv.n_sep_by_space = extlconv->n_sep_by_space; + worklconv.p_sign_posn = extlconv->p_sign_posn; + worklconv.n_sign_posn = extlconv->n_sign_posn; /* Try to restore internal settings */ if (save_lc_monetary) { if (!setlocale(LC_MONETARY, save_lc_monetary)) - elog(WARNING, "failed to restore old locale"); - pfree(save_lc_monetary); + trouble = true; } if (save_lc_numeric) { if (!setlocale(LC_NUMERIC, save_lc_numeric)) - elog(WARNING, "failed to restore old locale"); - pfree(save_lc_numeric); + trouble = true; } #ifdef WIN32 @@ -561,11 +610,74 @@ PGLC_localeconv(void) if (save_lc_ctype) { if (!setlocale(LC_CTYPE, save_lc_ctype)) - elog(WARNING, "failed to restore old locale"); - pfree(save_lc_ctype); + trouble = true; } #endif + /* + * At this point we've done our best to clean up, and can call functions + * that might possibly throw errors with a clean conscience. But let's + * make sure we don't leak any already-strdup'd fields in worklconv. + */ + PG_TRY(); + { + int encoding; + + /* + * Report it if we failed to restore anything. Perhaps this should be + * FATAL, rather than continuing with bad locale settings? + */ + if (trouble) + elog(WARNING, "failed to restore old locale"); + + /* Release the pstrdup'd locale names */ + if (save_lc_monetary) + pfree(save_lc_monetary); + if (save_lc_numeric) + pfree(save_lc_numeric); +#ifdef WIN32 + if (save_lc_ctype) + pfree(save_lc_ctype); +#endif + + /* If any of the preceding strdup calls failed, complain now. */ + if (!struct_lconv_is_valid(&worklconv)) + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); + + /* + * Now we must perform encoding conversion from whatever's associated + * with the locale into the database encoding. + */ + encoding = pg_get_encoding_from_locale(locale_numeric, true); + + db_encoding_convert(encoding, &worklconv.decimal_point); + db_encoding_convert(encoding, &worklconv.thousands_sep); + /* grouping is not text and does not require conversion */ + + encoding = pg_get_encoding_from_locale(locale_monetary, true); + + db_encoding_convert(encoding, &worklconv.int_curr_symbol); + db_encoding_convert(encoding, &worklconv.currency_symbol); + db_encoding_convert(encoding, &worklconv.mon_decimal_point); + db_encoding_convert(encoding, &worklconv.mon_thousands_sep); + /* mon_grouping is not text and does not require conversion */ + db_encoding_convert(encoding, &worklconv.positive_sign); + db_encoding_convert(encoding, &worklconv.negative_sign); + } + PG_CATCH(); + { + free_struct_lconv(&worklconv); + PG_RE_THROW(); + } + PG_END_TRY(); + + /* + * Everything is good, so save the results. + */ + CurrentLocaleConv = worklconv; + CurrentLocaleConvAllocated = true; CurrentLocaleConvValid = true; return &CurrentLocaleConv; } diff --git a/src/backend/utils/adt/pg_lsn.c b/src/backend/utils/adt/pg_lsn.c index c19ff40056..aefbb87680 100644 --- a/src/backend/utils/adt/pg_lsn.c +++ b/src/backend/utils/adt/pg_lsn.c @@ -3,7 +3,7 @@ * pg_lsn.c * Operations for the pg_lsn datatype. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -41,12 +41,14 @@ pg_lsn_in(PG_FUNCTION_ARGS) if (len1 < 1 || len1 > MAXPG_LSNCOMPONENT || str[len1] != '/') ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type pg_lsn: \"%s\"", str))); + errmsg("invalid input syntax for type %s: \"%s\"", + "pg_lsn", str))); len2 = strspn(str + len1 + 1, "0123456789abcdefABCDEF"); if (len2 < 1 || len2 > MAXPG_LSNCOMPONENT || str[len1 + 1 + len2] != '\0') ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type pg_lsn: \"%s\"", str))); + errmsg("invalid input syntax for type %s: \"%s\"", + "pg_lsn", str))); /* Decode result. */ id = (uint32) strtoul(str, NULL, 16); diff --git a/src/backend/utils/adt/pg_upgrade_support.c b/src/backend/utils/adt/pg_upgrade_support.c index 6ff035ace3..282b2649ff 100644 --- a/src/backend/utils/adt/pg_upgrade_support.c +++ b/src/backend/utils/adt/pg_upgrade_support.c @@ -5,7 +5,7 @@ * to control oid and relfilenode assignment, and do other special * hacks needed for pg_upgrade. * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * src/backend/utils/adt/pg_upgrade_support.c */ @@ -20,18 +20,6 @@ #include "utils/builtins.h" -Datum binary_upgrade_set_next_pg_type_oid(PG_FUNCTION_ARGS); -Datum binary_upgrade_set_next_array_pg_type_oid(PG_FUNCTION_ARGS); -Datum binary_upgrade_set_next_toast_pg_type_oid(PG_FUNCTION_ARGS); -Datum binary_upgrade_set_next_heap_pg_class_oid(PG_FUNCTION_ARGS); -Datum binary_upgrade_set_next_index_pg_class_oid(PG_FUNCTION_ARGS); -Datum binary_upgrade_set_next_toast_pg_class_oid(PG_FUNCTION_ARGS); -Datum binary_upgrade_set_next_pg_enum_oid(PG_FUNCTION_ARGS); -Datum binary_upgrade_set_next_pg_authid_oid(PG_FUNCTION_ARGS); -Datum binary_upgrade_create_empty_extension(PG_FUNCTION_ARGS); -Datum binary_upgrade_set_record_init_privs(PG_FUNCTION_ARGS); - - #define CHECK_IS_BINARY_UPGRADE \ do { \ if (!IsBinaryUpgrade) \ diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 1bba5fa8c8..a987d0d621 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -3,7 +3,7 @@ * pgstatfuncs.c * Functions for accessing the statistics collector data * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -16,8 +16,8 @@ #include "access/htup_details.h" #include "catalog/pg_type.h" +#include "common/ip.h" #include "funcapi.h" -#include "libpq/ip.h" #include "miscadmin.h" #include "pgstat.h" #include "storage/proc.h" @@ -29,106 +29,6 @@ #define UINT32_ACCESS_ONCE(var) ((uint32)(*((volatile uint32 *)&(var)))) -/* bogus ... these externs should be in a header file */ -extern Datum pg_stat_get_numscans(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_tuples_returned(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_tuples_fetched(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_tuples_inserted(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_tuples_updated(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_tuples_deleted(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_tuples_hot_updated(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_live_tuples(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_dead_tuples(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_mod_since_analyze(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_blocks_fetched(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_blocks_hit(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_last_vacuum_time(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_last_autovacuum_time(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_last_analyze_time(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_last_autoanalyze_time(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_vacuum_count(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_autovacuum_count(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_analyze_count(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_autoanalyze_count(PG_FUNCTION_ARGS); - -extern Datum pg_stat_get_function_calls(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_function_total_time(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_function_self_time(PG_FUNCTION_ARGS); - -extern Datum pg_stat_get_backend_idset(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_activity(PG_FUNCTION_ARGS); -extern Datum pg_backend_pid(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_backend_pid(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_backend_dbid(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_backend_userid(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_backend_activity(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_backend_wait_event_type(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_backend_wait_event(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_backend_xact_start(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_backend_start(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_backend_client_port(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_progress_info(PG_FUNCTION_ARGS); - -extern Datum pg_stat_get_db_numbackends(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_db_xact_commit(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_db_tuples_returned(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_db_tuples_fetched(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_db_tuples_inserted(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_db_tuples_updated(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_db_tuples_deleted(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_db_conflict_tablespace(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_db_conflict_lock(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_db_conflict_snapshot(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_db_conflict_bufferpin(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_db_conflict_startup_deadlock(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_db_conflict_all(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_db_deadlocks(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_db_stat_reset_time(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_db_temp_files(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_db_temp_bytes(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_db_blk_read_time(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_db_blk_write_time(PG_FUNCTION_ARGS); - -extern Datum pg_stat_get_archiver(PG_FUNCTION_ARGS); - -extern Datum pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_checkpoint_write_time(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_checkpoint_sync_time(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_bgwriter_buf_written_clean(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_buf_fsync_backend(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_buf_alloc(PG_FUNCTION_ARGS); - -extern Datum pg_stat_get_xact_numscans(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_xact_tuples_returned(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_xact_tuples_fetched(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_xact_tuples_inserted(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_xact_tuples_updated(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_xact_tuples_deleted(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_xact_tuples_hot_updated(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_xact_blocks_fetched(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_xact_blocks_hit(PG_FUNCTION_ARGS); - -extern Datum pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_xact_function_total_time(PG_FUNCTION_ARGS); -extern Datum pg_stat_get_xact_function_self_time(PG_FUNCTION_ARGS); - -extern Datum pg_stat_get_snapshot_timestamp(PG_FUNCTION_ARGS); -extern Datum pg_stat_clear_snapshot(PG_FUNCTION_ARGS); -extern Datum pg_stat_reset(PG_FUNCTION_ARGS); -extern Datum pg_stat_reset_shared(PG_FUNCTION_ARGS); -extern Datum pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS); -extern Datum pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS); - /* Global bgwriter statistics, from bgwriter.c */ extern PgStat_MsgBgWriter bgwriterStats; @@ -688,27 +588,17 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) MemSet(values, 0, sizeof(values)); MemSet(nulls, 0, sizeof(nulls)); - if (pid != -1) - { - /* Skip any which are not the one we're looking for. */ - PgBackendStatus *be = pgstat_fetch_stat_beentry(curr_backend); - - if (!be || be->st_procpid != pid) - continue; - - } - /* Get the next one in the list */ local_beentry = pgstat_fetch_stat_local_beentry(curr_backend); if (!local_beentry) - continue; - - beentry = &local_beentry->backendStatus; - if (!beentry) { int i; - for (i = 0; i < sizeof(nulls) / sizeof(nulls[0]); i++) + /* Ignore missing entries if looking for specific PID */ + if (pid != -1) + continue; + + for (i = 0; i < lengthof(nulls); i++) nulls[i] = true; nulls[5] = false; @@ -718,6 +608,12 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) continue; } + beentry = &local_beentry->backendStatus; + + /* If looking for specific PID, ignore all the others */ + if (pid != -1 && beentry->st_procpid != pid) + continue; + /* Values available to all callers */ values[0] = ObjectIdGetDatum(beentry->st_databaseid); values[1] = Int32GetDatum(beentry->st_procpid); diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c index dd447cf4e8..be793539a3 100644 --- a/src/backend/utils/adt/pseudotypes.c +++ b/src/backend/utils/adt/pseudotypes.c @@ -11,7 +11,7 @@ * we do better?) * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -83,34 +83,6 @@ cstring_send(PG_FUNCTION_ARGS) PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); } - -/* - * any_in - input routine for pseudo-type ANY. - */ -Datum -any_in(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type any"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - -/* - * any_out - output routine for pseudo-type ANY. - */ -Datum -any_out(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot display a value of type any"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - - /* * anyarray_in - input routine for pseudo-type ANYARRAY. */ @@ -119,7 +91,7 @@ anyarray_in(PG_FUNCTION_ARGS) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type anyarray"))); + errmsg("cannot accept a value of type %s", "anyarray"))); PG_RETURN_VOID(); /* keep compiler quiet */ } @@ -147,7 +119,7 @@ anyarray_recv(PG_FUNCTION_ARGS) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type anyarray"))); + errmsg("cannot accept a value of type %s", "anyarray"))); PG_RETURN_VOID(); /* keep compiler quiet */ } @@ -172,7 +144,7 @@ anyenum_in(PG_FUNCTION_ARGS) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type anyenum"))); + errmsg("cannot accept a value of type %s", "anyenum"))); PG_RETURN_VOID(); /* keep compiler quiet */ } @@ -196,7 +168,7 @@ anyrange_in(PG_FUNCTION_ARGS) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type anyrange"))); + errmsg("cannot accept a value of type %s", "anyrange"))); PG_RETURN_VOID(); /* keep compiler quiet */ } @@ -264,275 +236,6 @@ void_send(PG_FUNCTION_ARGS) PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); } - -/* - * trigger_in - input routine for pseudo-type TRIGGER. - */ -Datum -trigger_in(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type trigger"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - -/* - * trigger_out - output routine for pseudo-type TRIGGER. - */ -Datum -trigger_out(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot display a value of type trigger"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - - -/* - * event_trigger_in - input routine for pseudo-type event_trigger. - */ -Datum -event_trigger_in(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type event_trigger"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - -/* - * event_trigger_out - output routine for pseudo-type event_trigger. - */ -Datum -event_trigger_out(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot display a value of type event_trigger"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - - -/* - * language_handler_in - input routine for pseudo-type LANGUAGE_HANDLER. - */ -Datum -language_handler_in(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type language_handler"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - -/* - * language_handler_out - output routine for pseudo-type LANGUAGE_HANDLER. - */ -Datum -language_handler_out(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot display a value of type language_handler"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - - -/* - * fdw_handler_in - input routine for pseudo-type FDW_HANDLER. - */ -Datum -fdw_handler_in(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type fdw_handler"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - -/* - * fdw_handler_out - output routine for pseudo-type FDW_HANDLER. - */ -Datum -fdw_handler_out(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot display a value of type fdw_handler"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - - -/* - * index_am_handler_in - input routine for pseudo-type INDEX_AM_HANDLER. - */ -Datum -index_am_handler_in(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type index_am_handler"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - -/* - * index_am_handler_out - output routine for pseudo-type INDEX_AM_HANDLER. - */ -Datum -index_am_handler_out(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot display a value of type index_am_handler"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - - -/* - * tsm_handler_in - input routine for pseudo-type TSM_HANDLER. - */ -Datum -tsm_handler_in(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type tsm_handler"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - -/* - * tsm_handler_out - output routine for pseudo-type TSM_HANDLER. - */ -Datum -tsm_handler_out(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot display a value of type tsm_handler"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - - -/* - * internal_in - input routine for pseudo-type INTERNAL. - */ -Datum -internal_in(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type internal"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - -/* - * internal_out - output routine for pseudo-type INTERNAL. - */ -Datum -internal_out(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot display a value of type internal"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - - -/* - * opaque_in - input routine for pseudo-type OPAQUE. - */ -Datum -opaque_in(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type opaque"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - -/* - * opaque_out - output routine for pseudo-type OPAQUE. - */ -Datum -opaque_out(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot display a value of type opaque"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - - -/* - * anyelement_in - input routine for pseudo-type ANYELEMENT. - */ -Datum -anyelement_in(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type anyelement"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - -/* - * anyelement_out - output routine for pseudo-type ANYELEMENT. - */ -Datum -anyelement_out(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot display a value of type anyelement"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - -/* - * anynonarray_in - input routine for pseudo-type ANYNONARRAY. - */ -Datum -anynonarray_in(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type anynonarray"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - -/* - * anynonarray_out - output routine for pseudo-type ANYNONARRAY. - */ -Datum -anynonarray_out(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot display a value of type anynonarray"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - /* * shell_in - input routine for "shell" types (those not yet filled in). */ @@ -674,3 +377,44 @@ pg_ddl_command_send(PG_FUNCTION_ARGS) PG_RETURN_VOID(); } + + +/* + * Generate input and output functions for a pseudotype that will reject all + * input and output attempts. + */ +#define PSEUDOTYPE_DUMMY_IO_FUNCS(typname) \ +\ +Datum \ +typname##_in(PG_FUNCTION_ARGS) \ +{ \ + ereport(ERROR, \ + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \ + errmsg("cannot accept a value of type %s", #typname))); \ +\ + PG_RETURN_VOID(); /* keep compiler quiet */ \ +} \ +\ +Datum \ +typname##_out(PG_FUNCTION_ARGS) \ +{ \ + ereport(ERROR, \ + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \ + errmsg("cannot display a value of type %s", #typname))); \ +\ + PG_RETURN_VOID(); /* keep compiler quiet */ \ +} \ +\ +extern int no_such_variable + +PSEUDOTYPE_DUMMY_IO_FUNCS(any); +PSEUDOTYPE_DUMMY_IO_FUNCS(trigger); +PSEUDOTYPE_DUMMY_IO_FUNCS(event_trigger); +PSEUDOTYPE_DUMMY_IO_FUNCS(language_handler); +PSEUDOTYPE_DUMMY_IO_FUNCS(fdw_handler); +PSEUDOTYPE_DUMMY_IO_FUNCS(index_am_handler); +PSEUDOTYPE_DUMMY_IO_FUNCS(tsm_handler); +PSEUDOTYPE_DUMMY_IO_FUNCS(internal); +PSEUDOTYPE_DUMMY_IO_FUNCS(opaque); +PSEUDOTYPE_DUMMY_IO_FUNCS(anyelement); +PSEUDOTYPE_DUMMY_IO_FUNCS(anynonarray); diff --git a/src/backend/utils/adt/quote.c b/src/backend/utils/adt/quote.c index 9bdde8bf81..549c503031 100644 --- a/src/backend/utils/adt/quote.c +++ b/src/backend/utils/adt/quote.c @@ -3,7 +3,7 @@ * quote.c * Functions for quoting identifiers and literals * - * Portions Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2000-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -107,7 +107,7 @@ quote_literal_cstr(const char *rawstr) len = strlen(rawstr); /* We make a worst-case result area; wasting a little space is OK */ - result = palloc(len * 2 + 3); + result = palloc(len * 2 + 3 + 1); newlen = quote_literal_internal(result, rawstr, len); result[newlen] = '\0'; diff --git a/src/backend/utils/adt/rangetypes.c b/src/backend/utils/adt/rangetypes.c index 900bcb560f..da82d0b300 100644 --- a/src/backend/utils/adt/rangetypes.c +++ b/src/backend/utils/adt/rangetypes.c @@ -19,7 +19,7 @@ * value; we must detoast it first. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c index 01cd2342c0..f81b16c236 100644 --- a/src/backend/utils/adt/rangetypes_gist.c +++ b/src/backend/utils/adt/rangetypes_gist.c @@ -3,7 +3,7 @@ * rangetypes_gist.c * GiST support for range types. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/rangetypes_selfuncs.c b/src/backend/utils/adt/rangetypes_selfuncs.c index 8595d41e0b..cf6ecc4cf3 100644 --- a/src/backend/utils/adt/rangetypes_selfuncs.c +++ b/src/backend/utils/adt/rangetypes_selfuncs.c @@ -6,7 +6,7 @@ * Estimates are based on histograms of lower and upper bounds, and the * fraction of empty ranges. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/rangetypes_spgist.c b/src/backend/utils/adt/rangetypes_spgist.c index b89e90f908..a887e55b92 100644 --- a/src/backend/utils/adt/rangetypes_spgist.c +++ b/src/backend/utils/adt/rangetypes_spgist.c @@ -25,7 +25,7 @@ * This implementation only uses the comparison function of the range element * datatype, therefore it works for any range type. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -43,13 +43,6 @@ #include "utils/datum.h" #include "utils/rangetypes.h" -/* SP-GiST API functions */ -Datum spg_range_quad_config(PG_FUNCTION_ARGS); -Datum spg_range_quad_choose(PG_FUNCTION_ARGS); -Datum spg_range_quad_picksplit(PG_FUNCTION_ARGS); -Datum spg_range_quad_inner_consistent(PG_FUNCTION_ARGS); -Datum spg_range_quad_leaf_consistent(PG_FUNCTION_ARGS); - static int16 getQuadrant(TypeCacheEntry *typcache, RangeType *centroid, RangeType *tst); static int bound_cmp(const void *a, const void *b, void *arg); diff --git a/src/backend/utils/adt/rangetypes_typanalyze.c b/src/backend/utils/adt/rangetypes_typanalyze.c index 56504fcf3c..a8d585ce7a 100644 --- a/src/backend/utils/adt/rangetypes_typanalyze.c +++ b/src/backend/utils/adt/rangetypes_typanalyze.c @@ -13,7 +13,7 @@ * come from different tuples. In theory, the standard scalar selectivity * functions could be used with the combined histogram. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/regexp.c b/src/backend/utils/adt/regexp.c index 5b216e0b72..3a1647bc52 100644 --- a/src/backend/utils/adt/regexp.c +++ b/src/backend/utils/adt/regexp.c @@ -3,7 +3,7 @@ * regexp.c * Postgres' interface to the regular expression package. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -35,6 +35,7 @@ #include "regex/regex.h" #include "utils/array.h" #include "utils/builtins.h" +#include "utils/varlena.h" #define PG_GETARG_TEXT_PP_IF_EXISTS(_n) \ (PG_NARGS() > (_n) ? PG_GETARG_TEXT_PP(_n) : NULL) @@ -47,7 +48,7 @@ typedef struct pg_re_flags bool glob; /* do it globally (for each occurrence) */ } pg_re_flags; -/* cross-call state for regexp_matches(), also regexp_split() */ +/* cross-call state for regexp_match and regexp_split functions */ typedef struct regexp_matches_ctx { text *orig_str; /* data string in original TEXT form */ @@ -57,7 +58,7 @@ typedef struct regexp_matches_ctx /* so the number of entries in match_locs is nmatches * npatterns * 2 */ int *match_locs; /* 0-based character indexes */ int next_match; /* 0-based index of next match to process */ - /* workspace for build_regexp_matches_result() */ + /* workspace for build_regexp_match_result() */ Datum *elems; /* has npatterns elements */ bool *nulls; /* has npatterns elements */ } regexp_matches_ctx; @@ -107,13 +108,12 @@ static cached_re_str re_array[MAX_CACHED_RES]; /* cached re's */ /* Local functions */ static regexp_matches_ctx *setup_regexp_matches(text *orig_str, text *pattern, - text *flags, + pg_re_flags *flags, Oid collation, - bool force_glob, bool use_subpatterns, bool ignore_degenerate); static void cleanup_regexp_matches(regexp_matches_ctx *matchctx); -static ArrayType *build_regexp_matches_result(regexp_matches_ctx *matchctx); +static ArrayType *build_regexp_match_result(regexp_matches_ctx *matchctx); static Datum build_regexp_split_result(regexp_matches_ctx *splitctx); @@ -350,7 +350,7 @@ RE_compile_and_execute(text *text_re, char *dat, int dat_len, /* - * parse_re_flags - parse the options argument of regexp_matches and friends + * parse_re_flags - parse the options argument of regexp_match and friends * * flags --- output argument, filled with desired options * opts --- TEXT object, or NULL for defaults @@ -840,9 +840,53 @@ similar_escape(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(result); } +/* + * regexp_match() + * Return the first substring(s) matching a pattern within a string. + */ +Datum +regexp_match(PG_FUNCTION_ARGS) +{ + text *orig_str = PG_GETARG_TEXT_PP(0); + text *pattern = PG_GETARG_TEXT_PP(1); + text *flags = PG_GETARG_TEXT_PP_IF_EXISTS(2); + pg_re_flags re_flags; + regexp_matches_ctx *matchctx; + + /* Determine options */ + parse_re_flags(&re_flags, flags); + /* User mustn't specify 'g' */ + if (re_flags.glob) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("regexp_match does not support the global option"), + errhint("Use the regexp_matches function instead."))); + + matchctx = setup_regexp_matches(orig_str, pattern, &re_flags, + PG_GET_COLLATION(), true, false); + + if (matchctx->nmatches == 0) + PG_RETURN_NULL(); + + Assert(matchctx->nmatches == 1); + + /* Create workspace that build_regexp_match_result needs */ + matchctx->elems = (Datum *) palloc(sizeof(Datum) * matchctx->npatterns); + matchctx->nulls = (bool *) palloc(sizeof(bool) * matchctx->npatterns); + + PG_RETURN_DATUM(PointerGetDatum(build_regexp_match_result(matchctx))); +} + +/* This is separate to keep the opr_sanity regression test from complaining */ +Datum +regexp_match_no_flags(PG_FUNCTION_ARGS) +{ + return regexp_match(fcinfo); +} + /* * regexp_matches() - * Return a table of matches of a pattern within a string. + * Return a table of all matches of a pattern within a string. */ Datum regexp_matches(PG_FUNCTION_ARGS) @@ -854,18 +898,22 @@ regexp_matches(PG_FUNCTION_ARGS) { text *pattern = PG_GETARG_TEXT_PP(1); text *flags = PG_GETARG_TEXT_PP_IF_EXISTS(2); + pg_re_flags re_flags; MemoryContext oldcontext; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + /* Determine options */ + parse_re_flags(&re_flags, flags); + /* be sure to copy the input string into the multi-call ctx */ matchctx = setup_regexp_matches(PG_GETARG_TEXT_P_COPY(0), pattern, - flags, + &re_flags, PG_GET_COLLATION(), - false, true, false); + true, false); - /* Pre-create workspace that build_regexp_matches_result needs */ + /* Pre-create workspace that build_regexp_match_result needs */ matchctx->elems = (Datum *) palloc(sizeof(Datum) * matchctx->npatterns); matchctx->nulls = (bool *) palloc(sizeof(bool) * matchctx->npatterns); @@ -880,7 +928,7 @@ regexp_matches(PG_FUNCTION_ARGS) { ArrayType *result_ary; - result_ary = build_regexp_matches_result(matchctx); + result_ary = build_regexp_match_result(matchctx); matchctx->next_match++; SRF_RETURN_NEXT(funcctx, PointerGetDatum(result_ary)); } @@ -899,28 +947,27 @@ regexp_matches_no_flags(PG_FUNCTION_ARGS) } /* - * setup_regexp_matches --- do the initial matching for regexp_matches() - * or regexp_split() + * setup_regexp_matches --- do the initial matching for regexp_match + * and regexp_split functions * * To avoid having to re-find the compiled pattern on each call, we do * all the matching in one swoop. The returned regexp_matches_ctx contains * the locations of all the substrings matching the pattern. * - * The three bool parameters have only two patterns (one for each caller) - * but it seems clearer to distinguish the functionality this way than to - * key it all off one "is_split" flag. + * The two bool parameters have only two patterns (one for matching, one for + * splitting) but it seems clearer to distinguish the functionality this way + * than to key it all off one "is_split" flag. */ static regexp_matches_ctx * -setup_regexp_matches(text *orig_str, text *pattern, text *flags, +setup_regexp_matches(text *orig_str, text *pattern, pg_re_flags *re_flags, Oid collation, - bool force_glob, bool use_subpatterns, + bool use_subpatterns, bool ignore_degenerate) { regexp_matches_ctx *matchctx = palloc0(sizeof(regexp_matches_ctx)); int orig_len; pg_wchar *wide_str; int wide_len; - pg_re_flags re_flags; regex_t *cpattern; regmatch_t *pmatch; int pmatch_len; @@ -937,21 +984,8 @@ setup_regexp_matches(text *orig_str, text *pattern, text *flags, wide_str = (pg_wchar *) palloc(sizeof(pg_wchar) * (orig_len + 1)); wide_len = pg_mb2wchar_with_len(VARDATA_ANY(orig_str), wide_str, orig_len); - /* determine options */ - parse_re_flags(&re_flags, flags); - if (force_glob) - { - /* user mustn't specify 'g' for regexp_split */ - if (re_flags.glob) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("regexp_split does not support the global option"))); - /* but we find all the matches anyway */ - re_flags.glob = true; - } - /* set up the compiled pattern */ - cpattern = RE_compile_and_cache(pattern, re_flags.cflags, collation); + cpattern = RE_compile_and_cache(pattern, re_flags->cflags, collation); /* do we want to remember subpatterns? */ if (use_subpatterns && cpattern->re_nsub > 0) @@ -970,7 +1004,7 @@ setup_regexp_matches(text *orig_str, text *pattern, text *flags, pmatch = palloc(sizeof(regmatch_t) * pmatch_len); /* the real output space (grown dynamically if needed) */ - array_len = re_flags.glob ? 256 : 32; + array_len = re_flags->glob ? 256 : 32; matchctx->match_locs = (int *) palloc(sizeof(int) * array_len); array_idx = 0; @@ -1018,7 +1052,7 @@ setup_regexp_matches(text *orig_str, text *pattern, text *flags, prev_match_end = pmatch[0].rm_eo; /* if not glob, stop after one match */ - if (!re_flags.glob) + if (!re_flags->glob) break; /* @@ -1057,10 +1091,10 @@ cleanup_regexp_matches(regexp_matches_ctx *matchctx) } /* - * build_regexp_matches_result - build output array for current match + * build_regexp_match_result - build output array for current match */ static ArrayType * -build_regexp_matches_result(regexp_matches_ctx *matchctx) +build_regexp_match_result(regexp_matches_ctx *matchctx) { Datum *elems = matchctx->elems; bool *nulls = matchctx->nulls; @@ -1114,16 +1148,27 @@ regexp_split_to_table(PG_FUNCTION_ARGS) { text *pattern = PG_GETARG_TEXT_PP(1); text *flags = PG_GETARG_TEXT_PP_IF_EXISTS(2); + pg_re_flags re_flags; MemoryContext oldcontext; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + /* Determine options */ + parse_re_flags(&re_flags, flags); + /* User mustn't specify 'g' */ + if (re_flags.glob) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("regexp_split_to_table does not support the global option"))); + /* But we find all the matches anyway */ + re_flags.glob = true; + /* be sure to copy the input string into the multi-call ctx */ splitctx = setup_regexp_matches(PG_GETARG_TEXT_P_COPY(0), pattern, - flags, + &re_flags, PG_GET_COLLATION(), - true, false, true); + false, true); MemoryContextSwitchTo(oldcontext); funcctx->user_fctx = (void *) splitctx; @@ -1162,13 +1207,24 @@ Datum regexp_split_to_array(PG_FUNCTION_ARGS) { ArrayBuildState *astate = NULL; + pg_re_flags re_flags; regexp_matches_ctx *splitctx; + /* Determine options */ + parse_re_flags(&re_flags, PG_GETARG_TEXT_PP_IF_EXISTS(2)); + /* User mustn't specify 'g' */ + if (re_flags.glob) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("regexp_split_to_array does not support the global option"))); + /* But we find all the matches anyway */ + re_flags.glob = true; + splitctx = setup_regexp_matches(PG_GETARG_TEXT_PP(0), PG_GETARG_TEXT_PP(1), - PG_GETARG_TEXT_PP_IF_EXISTS(2), + &re_flags, PG_GET_COLLATION(), - true, false, true); + false, true); while (splitctx->next_match <= splitctx->nmatches) { diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c index 394042cbba..fa920c0d8c 100644 --- a/src/backend/utils/adt/regproc.c +++ b/src/backend/utils/adt/regproc.c @@ -8,7 +8,7 @@ * special I/O conversion routines. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -41,6 +41,8 @@ #include "utils/syscache.h" #include "utils/tqual.h" #include "utils/acl.h" +#include "utils/regproc.h" +#include "utils/varlena.h" static char *format_operator_internal(Oid operator_oid, bool force_qualify); static char *format_procedure_internal(Oid procedure_oid, bool force_qualify); diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index b4765005fe..37139f9647 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -13,7 +13,7 @@ * plan --- consider improving this someday. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * src/backend/utils/adt/ri_triggers.c * @@ -44,6 +44,7 @@ #include "parser/parse_coerce.h" #include "parser/parse_relation.h" #include "miscadmin.h" +#include "storage/bufmgr.h" #include "utils/acl.h" #include "utils/builtins.h" #include "utils/fmgroids.h" @@ -286,20 +287,17 @@ RI_FKey_check(TriggerData *trigdata) * We should not even consider checking the row if it is no longer valid, * since it was either deleted (so the deferred check should be skipped) * or updated (in which case only the latest version of the row should be - * checked). Test its liveness according to SnapshotSelf. - * - * NOTE: The normal coding rule is that one must acquire the buffer - * content lock to call HeapTupleSatisfiesVisibility. We can skip that - * here because we know that AfterTriggerExecute just fetched the tuple - * successfully, so there cannot be a VACUUM compaction in progress on the - * page (either heap_fetch would have waited for the VACUUM, or the - * VACUUM's LockBufferForCleanup would be waiting for us to drop pin). And - * since this is a row inserted by our open transaction, no one else can - * be entitled to change its xmin/xmax. - */ - Assert(new_row_buf != InvalidBuffer); + * checked). Test its liveness according to SnapshotSelf. We need pin + * and lock on the buffer to call HeapTupleSatisfiesVisibility. Caller + * should be holding pin, but not lock. + */ + LockBuffer(new_row_buf, BUFFER_LOCK_SHARE); if (!HeapTupleSatisfiesVisibility(new_row, SnapshotSelf, new_row_buf)) + { + LockBuffer(new_row_buf, BUFFER_LOCK_UNLOCK); return PointerGetDatum(NULL); + } + LockBuffer(new_row_buf, BUFFER_LOCK_UNLOCK); /* * Get the relation descriptors of the FK and PK tables. diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c index 622bb88beb..08b37b270e 100644 --- a/src/backend/utils/adt/rowtypes.c +++ b/src/backend/utils/adt/rowtypes.c @@ -3,7 +3,7 @@ * rowtypes.c * I/O and comparison functions for generic composite types. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index ec966c752e..745e009d26 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -4,7 +4,7 @@ * Functions to convert stored expressions/querytrees back to * source text * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -33,6 +33,7 @@ #include "catalog/pg_language.h" #include "catalog/pg_opclass.h" #include "catalog/pg_operator.h" +#include "catalog/pg_partitioned_table.h" #include "catalog/pg_proc.h" #include "catalog/pg_trigger.h" #include "catalog/pg_type.h" @@ -66,6 +67,7 @@ #include "utils/syscache.h" #include "utils/tqual.h" #include "utils/typcache.h" +#include "utils/varlena.h" #include "utils/xml.h" @@ -315,6 +317,7 @@ static char *pg_get_indexdef_worker(Oid indexrelid, int colno, const Oid *excludeOps, bool attrsOnly, bool showTblSpc, int prettyFlags, bool missing_ok); +static char *pg_get_partkeydef_worker(Oid relid, int prettyFlags); static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand, int prettyFlags, bool missing_ok); static text *pg_get_expr_worker(text *expr, Oid relid, const char *relname, @@ -813,6 +816,8 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty) SysScanDesc tgscan; int findx = 0; char *tgname; + char *tgoldtable; + char *tgnewtable; Oid argtypes[1]; /* dummy */ Datum value; bool isnull; @@ -924,6 +929,27 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty) appendStringInfoString(&buf, "IMMEDIATE "); } + value = fastgetattr(ht_trig, Anum_pg_trigger_tgoldtable, + tgrel->rd_att, &isnull); + if (!isnull) + tgoldtable = NameStr(*((NameData *) DatumGetPointer(value))); + else + tgoldtable = NULL; + value = fastgetattr(ht_trig, Anum_pg_trigger_tgnewtable, + tgrel->rd_att, &isnull); + if (!isnull) + tgnewtable = NameStr(*((NameData *) DatumGetPointer(value))); + else + tgnewtable = NULL; + if (tgoldtable != NULL || tgnewtable != NULL) + { + appendStringInfoString(&buf, "REFERENCING "); + if (tgoldtable != NULL) + appendStringInfo(&buf, "OLD TABLE AS %s ", tgoldtable); + if (tgnewtable != NULL) + appendStringInfo(&buf, "NEW TABLE AS %s ", tgnewtable); + } + if (TRIGGER_FOR_ROW(trigrec->tgtype)) appendStringInfoString(&buf, "FOR EACH ROW "); else @@ -1038,7 +1064,7 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty) * * Note that the SQL-function versions of this omit any info about the * index tablespace; this is intentional because pg_dump wants it that way. - * However pg_get_indexdef_string() includes index tablespace if not default. + * However pg_get_indexdef_string() includes the index tablespace. * ---------- */ Datum @@ -1079,7 +1105,11 @@ pg_get_indexdef_ext(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(string_to_text(res)); } -/* Internal version that returns a palloc'd C string; no pretty-printing */ +/* + * Internal version for use by ALTER TABLE. + * Includes a tablespace clause in the result. + * Returns a palloc'd C string; no pretty-printing. + */ char * pg_get_indexdef_string(Oid indexrelid) { @@ -1337,20 +1367,19 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, } /* - * If it's in a nondefault tablespace, say so, but only if requested + * Print tablespace, but only if requested */ if (showTblSpc) { Oid tblspc; tblspc = get_rel_tablespace(indexrelid); - if (OidIsValid(tblspc)) - { - if (isConstraint) - appendStringInfoString(&buf, " USING INDEX"); - appendStringInfo(&buf, " TABLESPACE %s", - quote_identifier(get_tablespace_name(tblspc))); - } + if (!OidIsValid(tblspc)) + tblspc = MyDatabaseTableSpace; + if (isConstraint) + appendStringInfoString(&buf, " USING INDEX"); + appendStringInfo(&buf, " TABLESPACE %s", + quote_identifier(get_tablespace_name(tblspc))); } /* @@ -1389,6 +1418,163 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, return buf.data; } +/* + * pg_get_partkeydef + * + * Returns the partition key specification, ie, the following: + * + * PARTITION BY { RANGE | LIST } (column opt_collation opt_opclass [, ...]) + */ +Datum +pg_get_partkeydef(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + + PG_RETURN_TEXT_P(string_to_text(pg_get_partkeydef_worker(relid, + PRETTYFLAG_INDENT))); +} + +/* + * Internal workhorse to decompile a partition key definition. + */ +static char * +pg_get_partkeydef_worker(Oid relid, int prettyFlags) +{ + Form_pg_partitioned_table form; + HeapTuple tuple; + oidvector *partclass; + oidvector *partcollation; + List *partexprs; + ListCell *partexpr_item; + List *context; + Datum datum; + bool isnull; + StringInfoData buf; + int keyno; + char *str; + char *sep; + + tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for partition key of %u", relid); + + form = (Form_pg_partitioned_table) GETSTRUCT(tuple); + + Assert(form->partrelid == relid); + + /* Must get partclass and partcollation the hard way */ + datum = SysCacheGetAttr(PARTRELID, tuple, + Anum_pg_partitioned_table_partclass, &isnull); + Assert(!isnull); + partclass = (oidvector *) DatumGetPointer(datum); + + datum = SysCacheGetAttr(PARTRELID, tuple, + Anum_pg_partitioned_table_partcollation, &isnull); + Assert(!isnull); + partcollation = (oidvector *) DatumGetPointer(datum); + + + /* + * Get the expressions, if any. (NOTE: we do not use the relcache + * versions of the expressions, because we want to display non-const-folded + * expressions.) + */ + if (!heap_attisnull(tuple, Anum_pg_partitioned_table_partexprs)) + { + Datum exprsDatum; + bool isnull; + char *exprsString; + + exprsDatum = SysCacheGetAttr(PARTRELID, tuple, + Anum_pg_partitioned_table_partexprs, &isnull); + Assert(!isnull); + exprsString = TextDatumGetCString(exprsDatum); + partexprs = (List *) stringToNode(exprsString); + + if (!IsA(partexprs, List)) + elog(ERROR, "unexpected node type found in partexprs: %d", + (int) nodeTag(partexprs)); + + pfree(exprsString); + } + else + partexprs = NIL; + + partexpr_item = list_head(partexprs); + context = deparse_context_for(get_relation_name(relid), relid); + + initStringInfo(&buf); + + switch (form->partstrat) + { + case PARTITION_STRATEGY_LIST: + appendStringInfo(&buf, "LIST"); + break; + case PARTITION_STRATEGY_RANGE: + appendStringInfo(&buf, "RANGE"); + break; + default: + elog(ERROR, "unexpected partition strategy: %d", + (int) form->partstrat); + } + + appendStringInfo(&buf, " ("); + sep = ""; + for (keyno = 0; keyno < form->partnatts; keyno++) + { + AttrNumber attnum = form->partattrs.values[keyno]; + Oid keycoltype; + Oid keycolcollation; + Oid partcoll; + + appendStringInfoString(&buf, sep); + sep = ", "; + if (attnum != 0) + { + /* Simple attribute reference */ + char *attname; + int32 keycoltypmod; + + attname = get_relid_attribute_name(relid, attnum); + appendStringInfoString(&buf, quote_identifier(attname)); + get_atttypetypmodcoll(relid, attnum, + &keycoltype, &keycoltypmod, + &keycolcollation); + } + else + { + /* Expression */ + Node *partkey; + + if (partexpr_item == NULL) + elog(ERROR, "too few entries in partexprs list"); + partkey = (Node *) lfirst(partexpr_item); + partexpr_item = lnext(partexpr_item); + /* Deparse */ + str = deparse_expression_pretty(partkey, context, false, false, + 0, 0); + + appendStringInfoString(&buf, str); + keycoltype = exprType(partkey); + keycolcollation = exprCollation(partkey); + } + + /* Add collation, if not default for column */ + partcoll = partcollation->values[keyno]; + if (OidIsValid(partcoll) && partcoll != keycolcollation) + appendStringInfo(&buf, " COLLATE %s", + generate_collation_name((partcoll))); + + /* Add the operator class name, if not default */ + get_opclass_name(partclass->values[keyno], keycoltype, &buf); + } + appendStringInfoChar(&buf, ')'); + + /* Clean up */ + ReleaseSysCache(tuple); + + return buf.data; +} /* * pg_get_constraintdef @@ -6884,6 +7070,7 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags) case T_RowExpr: case T_CoalesceExpr: case T_MinMaxExpr: + case T_SQLValueFunction: case T_XmlExpr: case T_NullIfExpr: case T_Aggref: @@ -7871,6 +8058,67 @@ get_rule_expr(Node *node, deparse_context *context, } break; + case T_SQLValueFunction: + { + SQLValueFunction *svf = (SQLValueFunction *) node; + + /* + * Note: this code knows that typmod for time, timestamp, and + * timestamptz just prints as integer. + */ + switch (svf->op) + { + case SVFOP_CURRENT_DATE: + appendStringInfoString(buf, "CURRENT_DATE"); + break; + case SVFOP_CURRENT_TIME: + appendStringInfoString(buf, "CURRENT_TIME"); + break; + case SVFOP_CURRENT_TIME_N: + appendStringInfo(buf, "CURRENT_TIME(%d)", svf->typmod); + break; + case SVFOP_CURRENT_TIMESTAMP: + appendStringInfoString(buf, "CURRENT_TIMESTAMP"); + break; + case SVFOP_CURRENT_TIMESTAMP_N: + appendStringInfo(buf, "CURRENT_TIMESTAMP(%d)", + svf->typmod); + break; + case SVFOP_LOCALTIME: + appendStringInfoString(buf, "LOCALTIME"); + break; + case SVFOP_LOCALTIME_N: + appendStringInfo(buf, "LOCALTIME(%d)", svf->typmod); + break; + case SVFOP_LOCALTIMESTAMP: + appendStringInfoString(buf, "LOCALTIMESTAMP"); + break; + case SVFOP_LOCALTIMESTAMP_N: + appendStringInfo(buf, "LOCALTIMESTAMP(%d)", + svf->typmod); + break; + case SVFOP_CURRENT_ROLE: + appendStringInfoString(buf, "CURRENT_ROLE"); + break; + case SVFOP_CURRENT_USER: + appendStringInfoString(buf, "CURRENT_USER"); + break; + case SVFOP_USER: + appendStringInfoString(buf, "USER"); + break; + case SVFOP_SESSION_USER: + appendStringInfoString(buf, "SESSION_USER"); + break; + case SVFOP_CURRENT_CATALOG: + appendStringInfoString(buf, "CURRENT_CATALOG"); + break; + case SVFOP_CURRENT_SCHEMA: + appendStringInfoString(buf, "CURRENT_SCHEMA"); + break; + } + } + break; + case T_XmlExpr: { XmlExpr *xexpr = (XmlExpr *) node; @@ -8203,6 +8451,88 @@ get_rule_expr(Node *node, deparse_context *context, } break; + case T_PartitionBoundSpec: + { + PartitionBoundSpec *spec = (PartitionBoundSpec *) node; + ListCell *cell; + char *sep; + + switch (spec->strategy) + { + case PARTITION_STRATEGY_LIST: + Assert(spec->listdatums != NIL); + + appendStringInfoString(buf, "FOR VALUES"); + appendStringInfoString(buf, " IN ("); + sep = ""; + foreach (cell, spec->listdatums) + { + Const *val = lfirst(cell); + + appendStringInfoString(buf, sep); + get_const_expr(val, context, -1); + sep = ", "; + } + + appendStringInfoString(buf, ")"); + break; + + case PARTITION_STRATEGY_RANGE: + Assert(spec->lowerdatums != NIL && + spec->upperdatums != NIL && + list_length(spec->lowerdatums) == + list_length(spec->upperdatums)); + + appendStringInfoString(buf, "FOR VALUES"); + appendStringInfoString(buf, " FROM"); + appendStringInfoString(buf, " ("); + sep = ""; + foreach (cell, spec->lowerdatums) + { + PartitionRangeDatum *datum = lfirst(cell); + Const *val; + + appendStringInfoString(buf, sep); + if (datum->infinite) + appendStringInfoString(buf, "UNBOUNDED"); + else + { + val = (Const *) datum->value; + get_const_expr(val, context, -1); + } + sep = ", "; + } + appendStringInfoString(buf, ")"); + + appendStringInfoString(buf, " TO"); + appendStringInfoString(buf, " ("); + sep = ""; + foreach (cell, spec->upperdatums) + { + PartitionRangeDatum *datum = lfirst(cell); + Const *val; + + appendStringInfoString(buf, sep); + if (datum->infinite) + appendStringInfoString(buf, "UNBOUNDED"); + else + { + val = (Const *) datum->value; + get_const_expr(val, context, -1); + } + sep = ", "; + } + appendStringInfoString(buf, ")"); + break; + + default: + elog(ERROR, "unrecognized partition strategy: %d", + (int) spec->strategy); + break; + } + } + break; + case T_List: { char *sep; diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 56943f2a87..fa32e9eabe 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -10,7 +10,7 @@ * Index cost functions are located via the index AM's API struct, * which is obtained from the handler function registered in pg_am. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -141,6 +141,7 @@ #include "utils/timestamp.h" #include "utils/tqual.h" #include "utils/typcache.h" +#include "utils/varlena.h" /* Hooks for plugins to get control when we ask for stats */ @@ -2511,10 +2512,24 @@ eqjoinsel_semi(Oid operator, * We can apply this clamping both with respect to the base relation from * which the join variable comes (if there is just one), and to the * immediate inner input relation of the current join. + * + * If we clamp, we can treat nd2 as being a non-default estimate; it's not + * great, maybe, but it didn't come out of nowhere either. This is most + * helpful when the inner relation is empty and consequently has no stats. */ if (vardata2->rel) - nd2 = Min(nd2, vardata2->rel->rows); - nd2 = Min(nd2, inner_rel->rows); + { + if (nd2 >= vardata2->rel->rows) + { + nd2 = vardata2->rel->rows; + isdefault2 = false; + } + } + if (nd2 >= inner_rel->rows) + { + nd2 = inner_rel->rows; + isdefault2 = false; + } if (HeapTupleIsValid(vardata1->statsTuple)) { diff --git a/src/backend/utils/adt/tid.c b/src/backend/utils/adt/tid.c index ff762bbc13..a3b372f22a 100644 --- a/src/backend/utils/adt/tid.c +++ b/src/backend/utils/adt/tid.c @@ -3,7 +3,7 @@ * tid.c * Functions for the built-in type tuple id * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -32,6 +32,7 @@ #include "utils/rel.h" #include "utils/snapmgr.h" #include "utils/tqual.h" +#include "utils/varlena.h" #define DatumGetItemPointer(X) ((ItemPointer) DatumGetPointer(X)) @@ -68,24 +69,24 @@ tidin(PG_FUNCTION_ARGS) if (i < NTIDARGS) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type tid: \"%s\"", - str))); + errmsg("invalid input syntax for type %s: \"%s\"", + "tid", str))); errno = 0; blockNumber = strtoul(coord[0], &badp, 10); if (errno || *badp != DELIM) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type tid: \"%s\"", - str))); + errmsg("invalid input syntax for type %s: \"%s\"", + "tid", str))); hold_offset = strtol(coord[1], &badp, 10); if (errno || *badp != RDELIM || hold_offset > USHRT_MAX || hold_offset < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type tid: \"%s\"", - str))); + errmsg("invalid input syntax for type %s: \"%s\"", + "tid", str))); offsetNumber = hold_offset; diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index d7ee865cf7..f2784da360 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -3,7 +3,7 @@ * timestamp.c * Functions for the built-in SQL types "timestamp" and "interval". * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -72,13 +72,13 @@ static Timestamp dt2local(Timestamp dt, int timezone); static void AdjustTimestampForTypmod(Timestamp *time, int32 typmod); static void AdjustIntervalForTypmod(Interval *interval, int32 typmod); static TimestampTz timestamp2timestamptz(Timestamp timestamp); +static Timestamp timestamptz2timestamp(TimestampTz timestamp); /* common code for timestamptypmodin and timestamptztypmodin */ static int32 anytimestamp_typmodin(bool istz, ArrayType *ta) { - int32 typmod; int32 *tl; int n; @@ -93,22 +93,27 @@ anytimestamp_typmodin(bool istz, ArrayType *ta) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid type modifier"))); - if (*tl < 0) + return anytimestamp_typmod_check(istz, tl[0]); +} + +/* exported so parse_expr.c can use it */ +int32 +anytimestamp_typmod_check(bool istz, int32 typmod) +{ + if (typmod < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("TIMESTAMP(%d)%s precision must not be negative", - *tl, (istz ? " WITH TIME ZONE" : "")))); - if (*tl > MAX_TIMESTAMP_PRECISION) + typmod, (istz ? " WITH TIME ZONE" : "")))); + if (typmod > MAX_TIMESTAMP_PRECISION) { ereport(WARNING, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("TIMESTAMP(%d)%s precision reduced to maximum allowed, %d", - *tl, (istz ? " WITH TIME ZONE" : ""), + typmod, (istz ? " WITH TIME ZONE" : ""), MAX_TIMESTAMP_PRECISION))); typmod = MAX_TIMESTAMP_PRECISION; } - else - typmod = *tl; return typmod; } @@ -336,6 +341,10 @@ timestamp_scale(PG_FUNCTION_ARGS) PG_RETURN_TIMESTAMP(result); } +/* + * AdjustTimestampForTypmod --- round off a timestamp to suit given typmod + * Works for either timestamp or timestamptz. + */ static void AdjustTimestampForTypmod(Timestamp *time, int32 typmod) { @@ -1241,6 +1250,59 @@ intervaltypmodout(PG_FUNCTION_ARGS) PG_RETURN_CSTRING(res); } +/* + * Given an interval typmod value, return a code for the least-significant + * field that the typmod allows to be nonzero, for instance given + * INTERVAL DAY TO HOUR we want to identify "hour". + * + * The results should be ordered by field significance, which means + * we can't use the dt.h macros YEAR etc, because for some odd reason + * they aren't ordered that way. Instead, arbitrarily represent + * SECOND = 0, MINUTE = 1, HOUR = 2, DAY = 3, MONTH = 4, YEAR = 5. + */ +static int +intervaltypmodleastfield(int32 typmod) +{ + if (typmod < 0) + return 0; /* SECOND */ + + switch (INTERVAL_RANGE(typmod)) + { + case INTERVAL_MASK(YEAR): + return 5; /* YEAR */ + case INTERVAL_MASK(MONTH): + return 4; /* MONTH */ + case INTERVAL_MASK(DAY): + return 3; /* DAY */ + case INTERVAL_MASK(HOUR): + return 2; /* HOUR */ + case INTERVAL_MASK(MINUTE): + return 1; /* MINUTE */ + case INTERVAL_MASK(SECOND): + return 0; /* SECOND */ + case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH): + return 4; /* MONTH */ + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR): + return 2; /* HOUR */ + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): + return 1; /* MINUTE */ + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + return 0; /* SECOND */ + case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): + return 1; /* MINUTE */ + case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + return 0; /* SECOND */ + case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + return 0; /* SECOND */ + case INTERVAL_FULL_RANGE: + return 0; /* SECOND */ + default: + elog(ERROR, "invalid INTERVAL typmod: 0x%x", typmod); + break; + } + return 0; /* can't get here, but keep compiler quiet */ +} + /* interval_transform() * Flatten superfluous calls to interval_scale(). The interval typmod is @@ -1262,39 +1324,39 @@ interval_transform(PG_FUNCTION_ARGS) if (IsA(typmod, Const) &&!((Const *) typmod)->constisnull) { Node *source = (Node *) linitial(expr->args); - int32 old_typmod = exprTypmod(source); int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue); - int old_range; - int old_precis; - int new_range = INTERVAL_RANGE(new_typmod); - int new_precis = INTERVAL_PRECISION(new_typmod); - int new_range_fls; - int old_range_fls; - - if (old_typmod < 0) - { - old_range = INTERVAL_FULL_RANGE; - old_precis = INTERVAL_FULL_PRECISION; - } + bool noop; + + if (new_typmod < 0) + noop = true; else { - old_range = INTERVAL_RANGE(old_typmod); - old_precis = INTERVAL_PRECISION(old_typmod); - } + int32 old_typmod = exprTypmod(source); + int old_least_field; + int new_least_field; + int old_precis; + int new_precis; + + old_least_field = intervaltypmodleastfield(old_typmod); + new_least_field = intervaltypmodleastfield(new_typmod); + if (old_typmod < 0) + old_precis = INTERVAL_FULL_PRECISION; + else + old_precis = INTERVAL_PRECISION(old_typmod); + new_precis = INTERVAL_PRECISION(new_typmod); - /* - * Temporally-smaller fields occupy higher positions in the range - * bitmap. Since only the temporally-smallest bit matters for length - * coercion purposes, we compare the last-set bits in the ranges. - * Precision, which is to say, sub-second precision, only affects - * ranges that include SECOND. - */ - new_range_fls = fls(new_range); - old_range_fls = fls(old_range); - if (new_typmod < 0 || - ((new_range_fls >= SECOND || new_range_fls >= old_range_fls) && - (old_range_fls < SECOND || new_precis >= MAX_INTERVAL_PRECISION || - new_precis >= old_precis))) + /* + * Cast is a no-op if least field stays the same or decreases + * while precision stays the same or increases. But precision, + * which is to say, sub-second precision, only affects ranges that + * include SECOND. + */ + noop = (new_least_field <= old_least_field) && + (old_least_field > 0 /* SECOND */ || + new_precis >= MAX_INTERVAL_PRECISION || + new_precis >= old_precis); + } + if (noop) ret = relabel_to_typmod(source, new_typmod); } @@ -1686,6 +1748,34 @@ IntegerTimestampToTimestampTz(int64 timestamp) } #endif +/* + * GetSQLCurrentTimestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n) + */ +TimestampTz +GetSQLCurrentTimestamp(int32 typmod) +{ + TimestampTz ts; + + ts = GetCurrentTransactionStartTimestamp(); + if (typmod >= 0) + AdjustTimestampForTypmod(&ts, typmod); + return ts; +} + +/* + * GetSQLLocalTimestamp -- implements LOCALTIMESTAMP, LOCALTIMESTAMP(n) + */ +Timestamp +GetSQLLocalTimestamp(int32 typmod) +{ + Timestamp ts; + + ts = timestamptz2timestamp(GetCurrentTransactionStartTimestamp()); + if (typmod >= 0) + AdjustTimestampForTypmod(&ts, typmod); + return ts; +} + /* * TimestampDifference -- convert the difference between two timestamps * into integer seconds and microseconds @@ -5112,84 +5202,15 @@ interval_part(PG_FUNCTION_ARGS) /* timestamp_zone_transform() - * If the zone argument of a timestamp_zone() or timestamptz_zone() call is a - * plan-time constant denoting a zone equivalent to UTC, the call will always - * return its second argument unchanged. Simplify the expression tree - * accordingly. Civil time zones almost never qualify, because jurisdictions - * that follow UTC today have not done so continuously. + * The original optimization here caused problems by relabeling Vars that + * could be matched to index entries. It might be possible to resurrect it + * at some point by teaching the planner to be less cavalier with RelabelType + * nodes, but that will take careful analysis. */ Datum timestamp_zone_transform(PG_FUNCTION_ARGS) { - Node *func_node = (Node *) PG_GETARG_POINTER(0); - FuncExpr *expr = (FuncExpr *) func_node; - Node *ret = NULL; - Node *zone_node; - - Assert(IsA(expr, FuncExpr)); - Assert(list_length(expr->args) == 2); - - zone_node = (Node *) linitial(expr->args); - - if (IsA(zone_node, Const) &&!((Const *) zone_node)->constisnull) - { - text *zone = DatumGetTextPP(((Const *) zone_node)->constvalue); - char tzname[TZ_STRLEN_MAX + 1]; - char *lowzone; - int type, - abbrev_offset; - pg_tz *tzp; - bool noop = false; - - /* - * If the timezone is forever UTC+0, the FuncExpr function call is a - * no-op for all possible timestamps. This passage mirrors code in - * timestamp_zone(). - */ - text_to_cstring_buffer(zone, tzname, sizeof(tzname)); - lowzone = downcase_truncate_identifier(tzname, - strlen(tzname), - false); - type = DecodeTimezoneAbbrev(0, lowzone, &abbrev_offset, &tzp); - if (type == TZ || type == DTZ) - noop = (abbrev_offset == 0); - else if (type == DYNTZ) - { - /* - * An abbreviation of a single-offset timezone ought not to be - * configured as a DYNTZ, so don't bother checking. - */ - } - else - { - long tzname_offset; - - tzp = pg_tzset(tzname); - if (tzp && pg_get_timezone_offset(tzp, &tzname_offset)) - noop = (tzname_offset == 0); - } - - if (noop) - { - Node *timestamp = (Node *) lsecond(expr->args); - - /* Strip any existing RelabelType node(s) */ - while (timestamp && IsA(timestamp, RelabelType)) - timestamp = (Node *) ((RelabelType *) timestamp)->arg; - - /* - * Replace the FuncExpr with its timestamp argument, relabeled as - * though the function call had computed it. - */ - ret = (Node *) makeRelabelType((Expr *) timestamp, - exprType(func_node), - exprTypmod(func_node), - exprCollation(func_node), - COERCE_EXPLICIT_CAST); - } - } - - PG_RETURN_POINTER(ret); + PG_RETURN_POINTER(NULL); } /* timestamp_zone() @@ -5286,49 +5307,15 @@ timestamp_zone(PG_FUNCTION_ARGS) } /* timestamp_izone_transform() - * If we deduce at plan time that a particular timestamp_izone() or - * timestamptz_izone() call can only compute tz=0, the call will always return - * its second argument unchanged. Simplify the expression tree accordingly. + * The original optimization here caused problems by relabeling Vars that + * could be matched to index entries. It might be possible to resurrect it + * at some point by teaching the planner to be less cavalier with RelabelType + * nodes, but that will take careful analysis. */ Datum timestamp_izone_transform(PG_FUNCTION_ARGS) { - Node *func_node = (Node *) PG_GETARG_POINTER(0); - FuncExpr *expr = (FuncExpr *) func_node; - Node *ret = NULL; - Node *zone_node; - - Assert(IsA(expr, FuncExpr)); - Assert(list_length(expr->args) == 2); - - zone_node = (Node *) linitial(expr->args); - - if (IsA(zone_node, Const) &&!((Const *) zone_node)->constisnull) - { - Interval *zone; - - zone = DatumGetIntervalP(((Const *) zone_node)->constvalue); - if (zone->month == 0 && zone->day == 0 && zone->time == 0) - { - Node *timestamp = (Node *) lsecond(expr->args); - - /* Strip any existing RelabelType node(s) */ - while (timestamp && IsA(timestamp, RelabelType)) - timestamp = (Node *) ((RelabelType *) timestamp)->arg; - - /* - * Replace the FuncExpr with its timestamp argument, relabeled as - * though the function call had computed it. - */ - ret = (Node *) makeRelabelType((Expr *) timestamp, - exprType(func_node), - exprTypmod(func_node), - exprCollation(func_node), - COERCE_EXPLICIT_CAST); - } - } - - PG_RETURN_POINTER(ret); + PG_RETURN_POINTER(NULL); } /* timestamp_izone() @@ -5415,6 +5402,13 @@ Datum timestamptz_timestamp(PG_FUNCTION_ARGS) { TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0); + + PG_RETURN_TIMESTAMP(timestamptz2timestamp(timestamp)); +} + +static Timestamp +timestamptz2timestamp(TimestampTz timestamp) +{ Timestamp result; struct pg_tm tt, *tm = &tt; @@ -5434,7 +5428,7 @@ timestamptz_timestamp(PG_FUNCTION_ARGS) (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); } - PG_RETURN_TIMESTAMP(result); + return result; } /* timestamptz_zone() diff --git a/src/backend/utils/adt/trigfuncs.c b/src/backend/utils/adt/trigfuncs.c index b0cde40092..50ea6d9ed3 100644 --- a/src/backend/utils/adt/trigfuncs.c +++ b/src/backend/utils/adt/trigfuncs.c @@ -4,7 +4,7 @@ * Builtin functions for useful trigger support. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/utils/adt/trigfuncs.c diff --git a/src/backend/utils/adt/tsginidx.c b/src/backend/utils/adt/tsginidx.c index c953f531ff..83a939dfd5 100644 --- a/src/backend/utils/adt/tsginidx.c +++ b/src/backend/utils/adt/tsginidx.c @@ -3,7 +3,7 @@ * tsginidx.c * GIN support functions for tsvector_ops * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -188,7 +188,7 @@ checkcondition_gin_internal(GinChkVal *gcv, QueryOperand *val, ExecPhraseData *d * information then set recheck flag */ if (val->weight != 0 || data != NULL) - *gcv->need_recheck = true; + *(gcv->need_recheck) = true; /* convert item's number to corresponding entry's (operand's) number */ j = gcv->map_item_operand[((QueryItem *) val) - gcv->first_item]; @@ -212,7 +212,7 @@ checkcondition_gin(void *checkval, QueryOperand *val, ExecPhraseData *data) * Evaluate tsquery boolean expression using ternary logic. */ static GinTernaryValue -TS_execute_ternary(GinChkVal *gcv, QueryItem *curitem) +TS_execute_ternary(GinChkVal *gcv, QueryItem *curitem, bool in_phrase) { GinTernaryValue val1, val2, @@ -230,7 +230,10 @@ TS_execute_ternary(GinChkVal *gcv, QueryItem *curitem) switch (curitem->qoperator.oper) { case OP_NOT: - result = TS_execute_ternary(gcv, curitem + 1); + /* In phrase search, always return MAYBE since we lack positions */ + if (in_phrase) + return GIN_MAYBE; + result = TS_execute_ternary(gcv, curitem + 1, in_phrase); if (result == GIN_MAYBE) return result; return !result; @@ -238,17 +241,21 @@ TS_execute_ternary(GinChkVal *gcv, QueryItem *curitem) case OP_PHRASE: /* - * GIN doesn't contain any information about positions, treat + * GIN doesn't contain any information about positions, so treat * OP_PHRASE as OP_AND with recheck requirement */ - *gcv->need_recheck = true; + *(gcv->need_recheck) = true; + /* Pass down in_phrase == true in case there's a NOT below */ + in_phrase = true; + /* FALL THRU */ case OP_AND: - val1 = TS_execute_ternary(gcv, curitem + curitem->qoperator.left); + val1 = TS_execute_ternary(gcv, curitem + curitem->qoperator.left, + in_phrase); if (val1 == GIN_FALSE) return GIN_FALSE; - val2 = TS_execute_ternary(gcv, curitem + 1); + val2 = TS_execute_ternary(gcv, curitem + 1, in_phrase); if (val2 == GIN_FALSE) return GIN_FALSE; if (val1 == GIN_TRUE && val2 == GIN_TRUE) @@ -257,10 +264,11 @@ TS_execute_ternary(GinChkVal *gcv, QueryItem *curitem) return GIN_MAYBE; case OP_OR: - val1 = TS_execute_ternary(gcv, curitem + curitem->qoperator.left); + val1 = TS_execute_ternary(gcv, curitem + curitem->qoperator.left, + in_phrase); if (val1 == GIN_TRUE) return GIN_TRUE; - val2 = TS_execute_ternary(gcv, curitem + 1); + val2 = TS_execute_ternary(gcv, curitem + 1, in_phrase); if (val2 == GIN_TRUE) return GIN_TRUE; if (val1 == GIN_FALSE && val2 == GIN_FALSE) @@ -289,26 +297,25 @@ gin_tsquery_consistent(PG_FUNCTION_ARGS) bool *recheck = (bool *) PG_GETARG_POINTER(5); bool res = FALSE; - /* The query requires recheck only if it involves weights */ + /* Initially assume query doesn't require recheck */ *recheck = false; if (query->size > 0) { - QueryItem *item; GinChkVal gcv; /* * check-parameter array has one entry for each value (operand) in the * query. */ - gcv.first_item = item = GETQUERY(query); + gcv.first_item = GETQUERY(query); gcv.check = check; gcv.map_item_operand = (int *) (extra_data[0]); gcv.need_recheck = recheck; res = TS_execute(GETQUERY(query), &gcv, - TS_EXEC_CALC_NOT | TS_EXEC_PHRASE_AS_AND, + TS_EXEC_CALC_NOT | TS_EXEC_PHRASE_NO_POS, checkcondition_gin); } @@ -328,24 +335,23 @@ gin_tsquery_triconsistent(PG_FUNCTION_ARGS) GinTernaryValue res = GIN_FALSE; bool recheck; - /* The query requires recheck only if it involves weights */ + /* Initially assume query doesn't require recheck */ recheck = false; if (query->size > 0) { - QueryItem *item; GinChkVal gcv; /* * check-parameter array has one entry for each value (operand) in the * query. */ - gcv.first_item = item = GETQUERY(query); + gcv.first_item = GETQUERY(query); gcv.check = check; gcv.map_item_operand = (int *) (extra_data[0]); gcv.need_recheck = &recheck; - res = TS_execute_ternary(&gcv, GETQUERY(query)); + res = TS_execute_ternary(&gcv, GETQUERY(query), false); if (res == GIN_TRUE && recheck) res = GIN_MAYBE; diff --git a/src/backend/utils/adt/tsgistidx.c b/src/backend/utils/adt/tsgistidx.c index 6cdfb13f6d..7ce2699b5c 100644 --- a/src/backend/utils/adt/tsgistidx.c +++ b/src/backend/utils/adt/tsgistidx.c @@ -3,7 +3,7 @@ * tsgistidx.c * GiST support functions for tsvector_ops * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -17,6 +17,7 @@ #include "access/gist.h" #include "access/tuptoaster.h" #include "tsearch/ts_utils.h" +#include "utils/builtins.h" #include "utils/pg_crc.h" @@ -359,12 +360,11 @@ gtsvector_consistent(PG_FUNCTION_ARGS) if (ISALLTRUE(key)) PG_RETURN_BOOL(true); - PG_RETURN_BOOL(TS_execute( - GETQUERY(query), + /* since signature is lossy, cannot specify CALC_NOT here */ + PG_RETURN_BOOL(TS_execute(GETQUERY(query), (void *) GETSIGN(key), - TS_EXEC_PHRASE_AS_AND, - checkcondition_bit - )); + TS_EXEC_PHRASE_NO_POS, + checkcondition_bit)); } else { /* only leaf pages */ @@ -372,12 +372,10 @@ gtsvector_consistent(PG_FUNCTION_ARGS) chkval.arrb = GETARR(key); chkval.arre = chkval.arrb + ARRNELEM(key); - PG_RETURN_BOOL(TS_execute( - GETQUERY(query), + PG_RETURN_BOOL(TS_execute(GETQUERY(query), (void *) &chkval, - TS_EXEC_PHRASE_AS_AND | TS_EXEC_CALC_NOT, - checkcondition_arr - )); + TS_EXEC_PHRASE_NO_POS | TS_EXEC_CALC_NOT, + checkcondition_arr)); } } diff --git a/src/backend/utils/adt/tsquery.c b/src/backend/utils/adt/tsquery.c index c0a4a0606b..3e2fc6e9df 100644 --- a/src/backend/utils/adt/tsquery.c +++ b/src/backend/utils/adt/tsquery.c @@ -3,7 +3,7 @@ * tsquery.c * I/O functions for tsquery * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -557,13 +557,11 @@ findoprnd_recurse(QueryItem *ptr, uint32 *pos, int nnodes, bool *needcleanup) curitem->oper == OP_OR || curitem->oper == OP_PHRASE); - if (curitem->oper == OP_PHRASE) - *needcleanup = true; /* push OP_PHRASE down later */ - (*pos)++; /* process RIGHT argument */ findoprnd_recurse(ptr, pos, nnodes, needcleanup); + curitem->left = *pos - tmp; /* set LEFT arg's offset */ /* process LEFT argument */ @@ -574,8 +572,9 @@ findoprnd_recurse(QueryItem *ptr, uint32 *pos, int nnodes, bool *needcleanup) /* - * Fills in the left-fields previously left unfilled. The input - * QueryItems must be in polish (prefix) notation. + * Fill in the left-fields previously left unfilled. + * The input QueryItems must be in polish (prefix) notation. + * Also, set *needcleanup to true if there are any QI_VALSTOP nodes. */ static void findoprnd(QueryItem *ptr, int size, bool *needcleanup) @@ -687,15 +686,17 @@ parse_tsquery(char *buf, memcpy((void *) GETOPERAND(query), (void *) state.op, state.sumlen); pfree(state.op); - /* Set left operand pointers for every operator. */ + /* + * Set left operand pointers for every operator. While we're at it, + * detect whether there are any QI_VALSTOP nodes. + */ findoprnd(ptr, query->size, &needcleanup); /* - * QI_VALSTOP nodes should be cleaned and and OP_PHRASE should be pushed - * down + * If there are QI_VALSTOP nodes, delete them and simplify the tree. */ if (needcleanup) - return cleanup_fakeval_and_phrase(query); + query = cleanup_tsquery_stopwords(query); return query; } @@ -1088,6 +1089,9 @@ tsqueryrecv(PG_FUNCTION_ARGS) */ findoprnd(item, size, &needcleanup); + /* Can't have found any QI_VALSTOP nodes */ + Assert(!needcleanup); + /* Copy operands to output struct */ for (i = 0; i < size; i++) { @@ -1105,9 +1109,6 @@ tsqueryrecv(PG_FUNCTION_ARGS) SET_VARSIZE(query, len + datalen); - if (needcleanup) - PG_RETURN_TSQUERY(cleanup_fakeval_and_phrase(query)); - PG_RETURN_TSQUERY(query); } diff --git a/src/backend/utils/adt/tsquery_cleanup.c b/src/backend/utils/adt/tsquery_cleanup.c index d9ec8ed431..350171c93d 100644 --- a/src/backend/utils/adt/tsquery_cleanup.c +++ b/src/backend/utils/adt/tsquery_cleanup.c @@ -4,7 +4,7 @@ * Cleanup query from NOT values and/or stopword * Utility functions to correct work. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -25,19 +25,6 @@ typedef struct NODE QueryItem *valnode; } NODE; -/* - * To simplify walking on query tree and pushing down of phrase operator - * we define some fake priority here: phrase operator has highest priority - * of any other operators (and we believe here that OP_PHRASE is a highest - * code of operations) and value node has ever highest priority. - * Priority values of other operations don't matter until they are less than - * phrase operator and value node. - */ -#define VALUE_PRIORITY (OP_COUNT + 1) -#define NODE_PRIORITY(x) \ - ( ((x)->valnode->qoperator.type == QI_OPR) ? \ - (x)->valnode->qoperator.oper : VALUE_PRIORITY ) - /* * make query tree from plain view of query */ @@ -207,45 +194,59 @@ clean_NOT(QueryItem *ptr, int *len) } -#ifdef V_UNKNOWN /* exists in Windows headers */ -#undef V_UNKNOWN -#endif -#ifdef V_FALSE /* exists in Solaris headers */ -#undef V_FALSE -#endif - -/* - * output values for result output parameter of clean_fakeval_intree - */ -#define V_UNKNOWN 0 /* the expression can't be evaluated - * statically */ -#define V_TRUE 1 /* the expression is always true (not - * implemented) */ -#define V_FALSE 2 /* the expression is always false (not - * implemented) */ -#define V_STOP 3 /* the expression is a stop word */ - /* - * Remove QI_VALSTOP (stopword nodes) from query tree. + * Remove QI_VALSTOP (stopword) nodes from query tree. + * + * Returns NULL if the query degenerates to nothing. Input must not be NULL. + * + * When we remove a phrase operator due to removing one or both of its + * arguments, we might need to adjust the distance of a parent phrase + * operator. For example, 'a' is a stopword, so: + * (b <-> a) <-> c should become b <2> c + * b <-> (a <-> c) should become b <2> c + * (b <-> (a <-> a)) <-> c should become b <3> c + * b <-> ((a <-> a) <-> c) should become b <3> c + * To handle that, we define two output parameters: + * ladd: amount to add to a phrase distance to the left of this node + * radd: amount to add to a phrase distance to the right of this node + * We need two outputs because we could need to bubble up adjustments to two + * different parent phrase operators. Consider + * w <-> (((a <-> x) <2> (y <3> a)) <-> z) + * After we've removed the two a's and are considering the <2> node (which is + * now just x <2> y), we have an ladd distance of 1 that needs to propagate + * up to the topmost (leftmost) <->, and an radd distance of 3 that needs to + * propagate to the rightmost <->, so that we'll end up with + * w <2> ((x <2> y) <4> z) + * Near the bottom of the tree, we may have subtrees consisting only of + * stopwords. The distances of any phrase operators within such a subtree are + * summed and propagated to both ladd and radd, since we don't know which side + * of the lowest surviving phrase operator we are in. The rule is that any + * subtree that degenerates to NULL must return equal values of ladd and radd, + * and the parent node dealing with it should incorporate only one of those. + * + * Currently, we only implement this adjustment for adjacent phrase operators. + * Thus for example 'x <-> ((a <-> y) | z)' will become 'x <-> (y | z)', which + * isn't ideal, but there is no way to represent the really desired semantics + * without some redesign of the tsquery structure. Certainly it would not be + * any better to convert that to 'x <2> (y | z)'. Since this is such a weird + * corner case, let it go for now. But we can fix it in cases where the + * intervening non-phrase operator also gets removed, for example + * '((x <-> a) | a) <-> y' will become 'x <2> y'. */ static NODE * -clean_fakeval_intree(NODE *node, char *result, int *adddistance) +clean_stopword_intree(NODE *node, int *ladd, int *radd) { - char lresult = V_UNKNOWN, - rresult = V_UNKNOWN; - /* since this function recurses, it could be driven to stack overflow. */ check_stack_depth(); - if (adddistance) - *adddistance = 0; + /* default output parameters indicate no change in parent distance */ + *ladd = *radd = 0; if (node->valnode->type == QI_VAL) return node; else if (node->valnode->type == QI_VALSTOP) { pfree(node); - *result = V_STOP; return NULL; } @@ -253,10 +254,10 @@ clean_fakeval_intree(NODE *node, char *result, int *adddistance) if (node->valnode->qoperator.oper == OP_NOT) { - node->right = clean_fakeval_intree(node->right, &rresult, NULL); + /* NOT doesn't change pattern width, so just report child distances */ + node->right = clean_stopword_intree(node->right, ladd, radd); if (!node->right) { - *result = V_STOP; freetree(node); return NULL; } @@ -264,292 +265,93 @@ clean_fakeval_intree(NODE *node, char *result, int *adddistance) else { NODE *res = node; + bool isphrase; int ndistance, - ldistance = 0, - rdistance = 0; + lladd, + lradd, + rladd, + rradd; - ndistance = (node->valnode->qoperator.oper == OP_PHRASE) ? - node->valnode->qoperator.distance : - 0; + /* First, recurse */ + node->left = clean_stopword_intree(node->left, &lladd, &lradd); + node->right = clean_stopword_intree(node->right, &rladd, &rradd); - node->left = clean_fakeval_intree(node->left, - &lresult, - ndistance ? &ldistance : NULL); + /* Check if current node is OP_PHRASE, get its distance */ + isphrase = (node->valnode->qoperator.oper == OP_PHRASE); + ndistance = isphrase ? node->valnode->qoperator.distance : 0; - node->right = clean_fakeval_intree(node->right, - &rresult, - ndistance ? &rdistance : NULL); - - /* - * ndistance, ldistance and rdistance are greater than zero if their - * corresponding nodes are OP_PHRASE - */ - - if (lresult == V_STOP && rresult == V_STOP) + if (node->left == NULL && node->right == NULL) { - if (adddistance && ndistance) - *adddistance = ldistance + ndistance + rdistance; + /* + * When we collapse out a phrase node entirely, propagate its own + * distance into both *ladd and *radd; it is the responsibility of + * the parent node to count it only once. Also, for a phrase + * node, distances coming from children are summed and propagated + * up to parent (we assume lladd == lradd and rladd == rradd, else + * rule was broken at a lower level). But if this isn't a phrase + * node, take the larger of the two child distances; that + * corresponds to what TS_execute will do in non-stopword cases. + */ + if (isphrase) + *ladd = *radd = lladd + ndistance + rladd; + else + *ladd = *radd = Max(lladd, rladd); freetree(node); - *result = V_STOP; return NULL; } - else if (lresult == V_STOP) + else if (node->left == NULL) { + /* Removing this operator and left subnode */ + /* lladd and lradd are equal/redundant, don't count both */ + if (isphrase) + { + /* operator's own distance must propagate to left */ + *ladd = lladd + ndistance + rladd; + *radd = rradd; + } + else + { + /* at non-phrase op, just forget the left subnode entirely */ + *ladd = rladd; + *radd = rradd; + } res = node->right; - - /* - * propagate distance from current node to the right upper - * subtree. - */ - if (adddistance && ndistance) - *adddistance = rdistance; pfree(node); } - else if (rresult == V_STOP) + else if (node->right == NULL) { + /* Removing this operator and right subnode */ + /* rladd and rradd are equal/redundant, don't count both */ + if (isphrase) + { + /* operator's own distance must propagate to right */ + *ladd = lladd; + *radd = lradd + ndistance + rradd; + } + else + { + /* at non-phrase op, just forget the right subnode entirely */ + *ladd = lladd; + *radd = lradd; + } res = node->left; - - /* - * propagate distance from current node to the upper tree. - */ - if (adddistance && ndistance) - *adddistance = ndistance + ldistance; pfree(node); } - else if (ndistance) - { - node->valnode->qoperator.distance += ldistance; - if (adddistance) - *adddistance = 0; - } - else if (adddistance) + else if (isphrase) { - *adddistance = 0; + /* Absorb appropriate corrections at this level */ + node->valnode->qoperator.distance += lradd + rladd; + /* Propagate up any unaccounted-for corrections */ + *ladd = lladd; + *radd = rradd; } - - return res; - } - return node; -} - -static NODE * -copyNODE(NODE *node) -{ - NODE *cnode = palloc(sizeof(NODE)); - - /* since this function recurses, it could be driven to stack overflow. */ - check_stack_depth(); - - cnode->valnode = palloc(sizeof(QueryItem)); - *(cnode->valnode) = *(node->valnode); - - if (node->valnode->type == QI_OPR) - { - cnode->right = copyNODE(node->right); - if (node->valnode->qoperator.oper != OP_NOT) - cnode->left = copyNODE(node->left); - } - - return cnode; -} - -static NODE * -makeNODE(int8 op, NODE *left, NODE *right) -{ - NODE *node = palloc(sizeof(NODE)); - - /* zeroing allocation to prevent difference in unused bytes */ - node->valnode = palloc0(sizeof(QueryItem)); - - node->valnode->qoperator.type = QI_OPR; - node->valnode->qoperator.oper = op; - - node->left = left; - node->right = right; - - return node; -} - -/* - * Move operation with high priority to the leaves. This guarantees - * that the phrase operator will be near the bottom of the tree. - * An idea behind is do not store position of lexemes during execution - * of ordinary operations (AND, OR, NOT) because it could be expensive. - * Actual transformation will be performed only on subtrees under the - * <-> () operation since it's needed solely for the phrase operator. - * - * Rules: - * a <-> (b | c) => (a <-> b) | (a <-> c) - * (a | b) <-> c => (a <-> c) | (b <-> c) - * a <-> !b => a & !(a <-> b) - * !a <-> b => b & !(a <-> b) - * - * Warnings for readers: - * a <-> b != b <-> a - * - * a (b c) != (a b) c since the phrase lengths are: - * n 2n-1 - */ -static NODE * -normalize_phrase_tree(NODE *node) -{ - /* there should be no stop words at this point */ - Assert(node->valnode->type != QI_VALSTOP); - - if (node->valnode->type == QI_VAL) - return node; - - /* since this function recurses, it could be driven to stack overflow. */ - check_stack_depth(); - - Assert(node->valnode->type == QI_OPR); - - if (node->valnode->qoperator.oper == OP_NOT) - { - NODE *orignode = node; - - /* eliminate NOT sequence */ - while (node->valnode->type == QI_OPR && - node->valnode->qoperator.oper == node->right->valnode->qoperator.oper) - { - node = node->right->right; - } - - if (orignode != node) - /* current node isn't checked yet */ - node = normalize_phrase_tree(node); else - node->right = normalize_phrase_tree(node->right); - } - else if (node->valnode->qoperator.oper == OP_PHRASE) - { - int16 distance; - NODE *X; - - node->left = normalize_phrase_tree(node->left); - node->right = normalize_phrase_tree(node->right); - - /* - * if subtree contains only nodes with higher "priority" then we are - * done. See comment near NODE_PRIORITY() - */ - if (NODE_PRIORITY(node) <= NODE_PRIORITY(node->right) && - NODE_PRIORITY(node) <= NODE_PRIORITY(node->left)) - return node; - - /* - * We can't swap left-right and works only with left child because of - * a <-> b != b <-> a - */ - - distance = node->valnode->qoperator.distance; - - if (node->right->valnode->type == QI_OPR) - { - switch (node->right->valnode->qoperator.oper) - { - case OP_AND: - /* a <-> (b & c) => (a <-> b) & (a <-> c) */ - node = makeNODE(OP_AND, - makeNODE(OP_PHRASE, - node->left, - node->right->left), - makeNODE(OP_PHRASE, - copyNODE(node->left), - node->right->right)); - node->left->valnode->qoperator.distance = - node->right->valnode->qoperator.distance = distance; - break; - case OP_OR: - /* a <-> (b | c) => (a <-> b) | (a <-> c) */ - node = makeNODE(OP_OR, - makeNODE(OP_PHRASE, - node->left, - node->right->left), - makeNODE(OP_PHRASE, - copyNODE(node->left), - node->right->right)); - node->left->valnode->qoperator.distance = - node->right->valnode->qoperator.distance = distance; - break; - case OP_NOT: - /* a <-> !b => a & !(a <-> b) */ - X = node->right; - node->right = node->right->right; - X->right = node; - node = makeNODE(OP_AND, - copyNODE(node->left), - X); - break; - case OP_PHRASE: - /* no-op */ - break; - default: - elog(ERROR, "Wrong type of tsquery node: %d", - node->right->valnode->qoperator.oper); - } - } - - if (node->left->valnode->type == QI_OPR && - node->valnode->qoperator.oper == OP_PHRASE) { - /* - * if the node is still OP_PHRASE, check the left subtree, - * otherwise the whole node will be transformed later. - */ - switch (node->left->valnode->qoperator.oper) - { - case OP_AND: - /* (a & b) <-> c => (a <-> c) & (b <-> c) */ - node = makeNODE(OP_AND, - makeNODE(OP_PHRASE, - node->left->left, - node->right), - makeNODE(OP_PHRASE, - node->left->right, - copyNODE(node->right))); - node->left->valnode->qoperator.distance = - node->right->valnode->qoperator.distance = distance; - break; - case OP_OR: - /* (a | b) <-> c => (a <-> c) | (b <-> c) */ - node = makeNODE(OP_OR, - makeNODE(OP_PHRASE, - node->left->left, - node->right), - makeNODE(OP_PHRASE, - node->left->right, - copyNODE(node->right))); - node->left->valnode->qoperator.distance = - node->right->valnode->qoperator.distance = distance; - break; - case OP_NOT: - /* !a <-> b => b & !(a <-> b) */ - X = node->left; - node->left = node->left->right; - X->right = node; - node = makeNODE(OP_AND, - X, - copyNODE(node->right)); - break; - case OP_PHRASE: - /* no-op */ - break; - default: - elog(ERROR, "Wrong type of tsquery node: %d", - node->left->valnode->qoperator.oper); - } + /* We're keeping a non-phrase operator, so ladd/radd remain 0 */ } - /* continue transformation */ - node = normalize_phrase_tree(node); - } - else /* AND or OR */ - { - node->left = normalize_phrase_tree(node->left); - node->right = normalize_phrase_tree(node->right); + return res; } - return node; } @@ -577,15 +379,19 @@ calcstrlen(NODE *node) return size; } +/* + * Remove QI_VALSTOP (stopword) nodes from TSQuery. + */ TSQuery -cleanup_fakeval_and_phrase(TSQuery in) +cleanup_tsquery_stopwords(TSQuery in) { int32 len, lenstr, commonlen, i; NODE *root; - char result = V_UNKNOWN; + int ladd, + radd; TSQuery out; QueryItem *items; char *operands; @@ -594,8 +400,8 @@ cleanup_fakeval_and_phrase(TSQuery in) return in; /* eliminate stop words */ - root = clean_fakeval_intree(maketree(GETQUERY(in)), &result, NULL); - if (result != V_UNKNOWN) + root = clean_stopword_intree(maketree(GETQUERY(in)), &ladd, &radd); + if (root == NULL) { ereport(NOTICE, (errmsg("text-search query contains only stop words or doesn't contain lexemes, ignored"))); @@ -605,9 +411,6 @@ cleanup_fakeval_and_phrase(TSQuery in) return out; } - /* push OP_PHRASE nodes down */ - root = normalize_phrase_tree(root); - /* * Build TSQuery from plain view */ diff --git a/src/backend/utils/adt/tsquery_gist.c b/src/backend/utils/adt/tsquery_gist.c index 5eebf216c0..85518dc7d9 100644 --- a/src/backend/utils/adt/tsquery_gist.c +++ b/src/backend/utils/adt/tsquery_gist.c @@ -3,7 +3,7 @@ * tsquery_gist.c * GiST index support for tsquery * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -17,6 +17,7 @@ #include "access/stratnum.h" #include "access/gist.h" #include "tsearch/ts_utils.h" +#include "utils/builtins.h" #define GETENTRY(vec,pos) DatumGetTSQuerySign((vec)->vector[pos].key) diff --git a/src/backend/utils/adt/tsquery_op.c b/src/backend/utils/adt/tsquery_op.c index a574b4b257..755c3e9ee8 100644 --- a/src/backend/utils/adt/tsquery_op.c +++ b/src/backend/utils/adt/tsquery_op.c @@ -3,7 +3,7 @@ * tsquery_op.c * Various operations with tsquery * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -15,6 +15,7 @@ #include "postgres.h" #include "tsearch/ts_utils.h" +#include "utils/builtins.h" Datum tsquery_numnode(PG_FUNCTION_ARGS) @@ -104,7 +105,7 @@ tsquery_or(PG_FUNCTION_ARGS) PG_FREE_IF_COPY(a, 0); PG_FREE_IF_COPY(b, 1); - PG_RETURN_POINTER(query); + PG_RETURN_TSQUERY(query); } Datum @@ -140,7 +141,7 @@ tsquery_phrase_distance(PG_FUNCTION_ARGS) PG_FREE_IF_COPY(a, 0); PG_FREE_IF_COPY(b, 1); - PG_RETURN_POINTER(cleanup_fakeval_and_phrase(query)); + PG_RETURN_TSQUERY(query); } Datum diff --git a/src/backend/utils/adt/tsquery_rewrite.c b/src/backend/utils/adt/tsquery_rewrite.c index 28f328ddb3..266a82d634 100644 --- a/src/backend/utils/adt/tsquery_rewrite.c +++ b/src/backend/utils/adt/tsquery_rewrite.c @@ -3,7 +3,7 @@ * tsquery_rewrite.c * Utilities for reconstructing tsquery * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -21,47 +21,43 @@ #include "utils/builtins.h" -static int -addone(int *counters, int last, int total) -{ - /* since this function recurses, it could be driven to stack overflow. */ - check_stack_depth(); - - counters[last]++; - if (counters[last] >= total) - { - if (last == 0) - return 0; - if (addone(counters, last - 1, total - 1) == 0) - return 0; - counters[last] = counters[last - 1] + 1; - } - return 1; -} - /* - * If node is equal to ex, replace it with subs. Replacement is actually done - * by returning either node or a copy of subs. + * If "node" is equal to "ex", return a copy of "subs" instead. + * If "ex" matches a subset of node's children, return a modified version + * of "node" in which those children are replaced with a copy of "subs". + * Otherwise return "node" unmodified. + * + * The QTN_NOCHANGE bit is set in successfully modified nodes, so that + * we won't uselessly recurse into them. + * Also, set *isfind true if we make a replacement. */ static QTNode * findeq(QTNode *node, QTNode *ex, QTNode *subs, bool *isfind) { + /* Can't match unless signature matches and node type matches. */ if ((node->sign & ex->sign) != ex->sign || node->valnode->type != ex->valnode->type) return node; + /* Ignore nodes marked NOCHANGE, too. */ if (node->flags & QTN_NOCHANGE) return node; if (node->valnode->type == QI_OPR) { + /* Must be same operator. */ if (node->valnode->qoperator.oper != ex->valnode->qoperator.oper) return node; if (node->nchild == ex->nchild) { + /* + * Simple case: when same number of children, match if equal. + * (This is reliable when the children were sorted earlier.) + */ if (QTNEq(node, ex)) { + /* Match; delete node and return a copy of subs instead. */ QTNFree(node); if (subs) { @@ -73,79 +69,98 @@ findeq(QTNode *node, QTNode *ex, QTNode *subs, bool *isfind) *isfind = true; } } - else if (node->nchild > ex->nchild) + else if (node->nchild > ex->nchild && ex->nchild > 0) { /* - * AND and NOT are commutative, so we check if a subset of the - * children match. For example, if tnode is A | B | C, and ex is B - * | C, we have a match after we convert tnode to A | (B | C). + * AND and OR are commutative/associative, so we should check if a + * subset of the children match. For example, if node is A|B|C, + * and ex is B|C, we have a match after we notionally convert node + * to A|(B|C). This does not work for NOT or PHRASE nodes, but we + * can't get here for those node types because they have a fixed + * number of children. + * + * Because we expect that the children are sorted, it suffices to + * make one pass through the two lists to find the matches. */ - int *counters = (int *) palloc(sizeof(int) * node->nchild); - int i; - QTNode *tnode = (QTNode *) palloc(sizeof(QTNode)); - - memset(tnode, 0, sizeof(QTNode)); - tnode->child = (QTNode **) palloc(sizeof(QTNode *) * ex->nchild); - tnode->nchild = ex->nchild; - tnode->valnode = (QueryItem *) palloc(sizeof(QueryItem)); - *(tnode->valnode) = *(ex->valnode); - - for (i = 0; i < ex->nchild; i++) - counters[i] = i; - - do + bool *matched; + int nmatched; + int i, + j; + + /* Assert that the subset rule is OK */ + Assert(node->valnode->qoperator.oper == OP_AND || + node->valnode->qoperator.oper == OP_OR); + + /* matched[] will record which children of node matched */ + matched = (bool *) palloc0(node->nchild * sizeof(bool)); + nmatched = 0; + i = j = 0; + while (i < node->nchild && j < ex->nchild) { - tnode->sign = 0; - for (i = 0; i < ex->nchild; i++) + int cmp = QTNodeCompare(node->child[i], ex->child[j]); + + if (cmp == 0) { - tnode->child[i] = node->child[counters[i]]; - tnode->sign |= tnode->child[i]->sign; + /* match! */ + matched[i] = true; + nmatched++; + i++, j++; } + else if (cmp < 0) + { + /* node->child[i] has no match, ignore it */ + i++; + } + else + { + /* ex->child[j] has no match; we can give up immediately */ + break; + } + } - if (QTNEq(tnode, ex)) + if (nmatched == ex->nchild) + { + /* collapse out the matched children of node */ + j = 0; + for (i = 0; i < node->nchild; i++) { - int j = 0; - - pfree(tnode->valnode); - pfree(tnode->child); - pfree(tnode); - if (subs) - { - tnode = QTNCopy(subs); - tnode->flags = QTN_NOCHANGE | QTN_NEEDFREE; - } + if (matched[i]) + QTNFree(node->child[i]); else - tnode = NULL; - - node->child[counters[0]] = tnode; - - for (i = 1; i < ex->nchild; i++) - node->child[counters[i]] = NULL; - for (i = 0; i < node->nchild; i++) - { - if (node->child[i]) - { - node->child[j] = node->child[i]; - j++; - } - } + node->child[j++] = node->child[i]; + } - node->nchild = j; + /* and instead insert a copy of subs */ + if (subs) + { + subs = QTNCopy(subs); + subs->flags |= QTN_NOCHANGE; + node->child[j++] = subs; + } - *isfind = true; + node->nchild = j; + + /* + * At this point we might have a node with zero or one child, + * which should be simplified. But we leave it to our caller + * (dofindsubquery) to take care of that. + */ + + /* + * Re-sort the node to put new child in the right place. This + * is a bit bogus, because it won't matter for findsubquery's + * remaining processing, and it's insufficient to prepare the + * tree for another search (we would need to re-flatten as + * well, and we don't want to do that because we'd lose the + * QTN_NOCHANGE marking on the new child). But it's needed to + * keep the results the same as the regression tests expect. + */ + QTNSort(node); - break; - } - } while (addone(counters, ex->nchild - 1, node->nchild)); - if (tnode && (tnode->flags & QTN_NOCHANGE) == 0) - { - pfree(tnode->valnode); - pfree(tnode->child); - pfree(tnode); + *isfind = true; } - else - QTNSort(node); - pfree(counters); + + pfree(matched); } } else @@ -173,47 +188,56 @@ findeq(QTNode *node, QTNode *ex, QTNode *subs, bool *isfind) return node; } +/* + * Recursive guts of findsubquery(): attempt to replace "ex" with "subs" + * at the root node, and if we failed to do so, recursively match against + * child nodes. + * + * Delete any void subtrees resulting from the replacement. + * In the following example '5' is replaced by empty operand: + * + * AND -> 6 + * / \ + * 5 OR + * / \ + * 6 5 + */ static QTNode * dofindsubquery(QTNode *root, QTNode *ex, QTNode *subs, bool *isfind) { /* since this function recurses, it could be driven to stack overflow. */ check_stack_depth(); - root = findeq(root, ex, subs, isfind); - - if (root && (root->flags & QTN_NOCHANGE) == 0 && root->valnode->type == QI_OPR) - { - int i; - - for (i = 0; i < root->nchild; i++) - root->child[i] = dofindsubquery(root->child[i], ex, subs, isfind); - } - - return root; -} + /* also, since it's a bit expensive, let's check for query cancel. */ + CHECK_FOR_INTERRUPTS(); -static QTNode * -dropvoidsubtree(QTNode *root) -{ - if (!root) - return NULL; + /* match at the node itself */ + root = findeq(root, ex, subs, isfind); - if (root->valnode->type == QI_OPR) + /* unless we matched here, consider matches at child nodes */ + if (root && (root->flags & QTN_NOCHANGE) == 0 && + root->valnode->type == QI_OPR) { int i, j = 0; + /* + * Any subtrees that are replaced by NULL must be dropped from the + * tree. + */ for (i = 0; i < root->nchild; i++) { - if (root->child[i]) - { - root->child[j] = root->child[i]; + root->child[j] = dofindsubquery(root->child[i], ex, subs, isfind); + if (root->child[j]) j++; - } } root->nchild = j; + /* + * If we have just zero or one remaining child node, simplify out this + * operator node. + */ if (root->nchild == 0) { QTNFree(root); @@ -231,6 +255,14 @@ dropvoidsubtree(QTNode *root) return root; } +/* + * Substitute "subs" for "ex" throughout the QTNode tree at root. + * + * If isfind isn't NULL, set *isfind to show whether we made any substitution. + * + * Both "root" and "ex" must have been through QTNTernary and QTNSort + * to ensure reliable matching. + */ QTNode * findsubquery(QTNode *root, QTNode *ex, QTNode *subs, bool *isfind) { @@ -238,9 +270,6 @@ findsubquery(QTNode *root, QTNode *ex, QTNode *subs, bool *isfind) root = dofindsubquery(root, ex, subs, &DidFind); - if (!subs && DidFind) - root = dropvoidsubtree(root); - if (isfind) *isfind = DidFind; @@ -344,6 +373,7 @@ tsquery_rewrite_query(PG_FUNCTION_ARGS) { /* ready the tree for another pass */ QTNClearFlags(tree, QTN_NOCHANGE); + QTNTernary(tree); QTNSort(tree); } } diff --git a/src/backend/utils/adt/tsquery_util.c b/src/backend/utils/adt/tsquery_util.c index 0f338aa653..971bb81ea6 100644 --- a/src/backend/utils/adt/tsquery_util.c +++ b/src/backend/utils/adt/tsquery_util.c @@ -3,7 +3,7 @@ * tsquery_util.c * Utilities for tsquery datatype * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -17,6 +17,9 @@ #include "tsearch/ts_utils.h" #include "miscadmin.h" +/* + * Build QTNode tree for a tsquery given in QueryItem array format. + */ QTNode * QT2QTN(QueryItem *in, char *operand) { @@ -50,6 +53,12 @@ QT2QTN(QueryItem *in, char *operand) return node; } +/* + * Free a QTNode tree. + * + * Referenced "word" and "valnode" items are freed if marked as transient + * by flags. + */ void QTNFree(QTNode *in) { @@ -62,26 +71,27 @@ QTNFree(QTNode *in) if (in->valnode->type == QI_VAL && in->word && (in->flags & QTN_WORDFREE) != 0) pfree(in->word); - if (in->child) + if (in->valnode->type == QI_OPR) { - if (in->valnode) - { - if (in->valnode->type == QI_OPR && in->nchild > 0) - { - int i; - - for (i = 0; i < in->nchild; i++) - QTNFree(in->child[i]); - } - if (in->flags & QTN_NEEDFREE) - pfree(in->valnode); - } - pfree(in->child); + int i; + + for (i = 0; i < in->nchild; i++) + QTNFree(in->child[i]); } + if (in->child) + pfree(in->child); + + if (in->flags & QTN_NEEDFREE) + pfree(in->valnode); pfree(in); } +/* + * Sort comparator for QTNodes. + * + * The sort order is somewhat arbitrary. + */ int QTNodeCompare(QTNode *an, QTNode *bn) { @@ -135,12 +145,19 @@ QTNodeCompare(QTNode *an, QTNode *bn) } } +/* + * qsort comparator for QTNode pointers. + */ static int cmpQTN(const void *a, const void *b) { return QTNodeCompare(*(QTNode *const *) a, *(QTNode *const *) b); } +/* + * Canonicalize a QTNode tree by sorting the children of AND/OR nodes + * into an arbitrary but well-defined order. + */ void QTNSort(QTNode *in) { @@ -158,13 +175,16 @@ QTNSort(QTNode *in) qsort((void *) in->child, in->nchild, sizeof(QTNode *), cmpQTN); } +/* + * Are two QTNode trees equal according to QTNodeCompare? + */ bool QTNEq(QTNode *a, QTNode *b) { uint32 sign = a->sign & b->sign; if (!(sign == a->sign && sign == b->sign)) - return 0; + return false; return (QTNodeCompare(a, b) == 0) ? true : false; } @@ -190,14 +210,17 @@ QTNTernary(QTNode *in) for (i = 0; i < in->nchild; i++) QTNTernary(in->child[i]); + /* Only AND and OR are associative, so don't flatten other node types */ + if (in->valnode->qoperator.oper != OP_AND && + in->valnode->qoperator.oper != OP_OR) + return; + for (i = 0; i < in->nchild; i++) { QTNode *cc = in->child[i]; - /* OP_Phrase isn't associative */ if (cc->valnode->type == QI_OPR && - in->valnode->qoperator.oper == cc->valnode->qoperator.oper && - in->valnode->qoperator.oper != OP_PHRASE) + in->valnode->qoperator.oper == cc->valnode->qoperator.oper) { int oldnchild = in->nchild; @@ -236,9 +259,6 @@ QTNBinary(QTNode *in) for (i = 0; i < in->nchild; i++) QTNBinary(in->child[i]); - if (in->nchild <= 2) - return; - while (in->nchild > 2) { QTNode *nn = (QTNode *) palloc0(sizeof(QTNode)); @@ -263,8 +283,9 @@ QTNBinary(QTNode *in) } /* - * Count the total length of operand string in tree, including '\0'- - * terminators. + * Count the total length of operand strings in tree (including '\0'- + * terminators) and the total number of nodes. + * Caller must initialize *sumlen and *nnode to zeroes. */ static void cntsize(QTNode *in, int *sumlen, int *nnode) @@ -293,6 +314,10 @@ typedef struct char *curoperand; } QTN2QTState; +/* + * Recursively convert a QTNode tree into flat tsquery format. + * Caller must have allocated arrays of the correct size. + */ static void fillQT(QTN2QTState *state, QTNode *in) { @@ -330,6 +355,9 @@ fillQT(QTN2QTState *state, QTNode *in) } } +/* + * Build flat tsquery from a QTNode tree. + */ TSQuery QTN2QT(QTNode *in) { @@ -358,6 +386,11 @@ QTN2QT(QTNode *in) return out; } +/* + * Copy a QTNode tree. + * + * Modifiable copies of the words and valnodes are made, too. + */ QTNode * QTNCopy(QTNode *in) { @@ -393,6 +426,9 @@ QTNCopy(QTNode *in) return out; } +/* + * Clear the specified flag bit(s) in all nodes of a QTNode tree. + */ void QTNClearFlags(QTNode *in, uint32 flags) { diff --git a/src/backend/utils/adt/tsrank.c b/src/backend/utils/adt/tsrank.c index d887a14d05..9b2cd6df41 100644 --- a/src/backend/utils/adt/tsrank.c +++ b/src/backend/utils/adt/tsrank.c @@ -3,7 +3,7 @@ * tsrank.c * rank tsvector by tsquery * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -18,6 +18,7 @@ #include "tsearch/ts_utils.h" #include "utils/array.h" +#include "utils/builtins.h" #include "miscadmin.h" diff --git a/src/backend/utils/adt/tsvector.c b/src/backend/utils/adt/tsvector.c index 41bf3fb11e..6f66c1f58c 100644 --- a/src/backend/utils/adt/tsvector.c +++ b/src/backend/utils/adt/tsvector.c @@ -3,7 +3,7 @@ * tsvector.c * I/O functions for tsvector * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -17,6 +17,7 @@ #include "libpq/pqformat.h" #include "tsearch/ts_locale.h" #include "tsearch/ts_utils.h" +#include "utils/builtins.h" #include "utils/memutils.h" typedef struct diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c index ad5a254c57..f05f913cff 100644 --- a/src/backend/utils/adt/tsvector_op.c +++ b/src/backend/utils/adt/tsvector_op.c @@ -3,7 +3,7 @@ * tsvector_op.c * operations over tsvector * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -11,9 +11,10 @@ * *------------------------------------------------------------------------- */ - #include "postgres.h" +#include + #include "access/htup_details.h" #include "catalog/namespace.h" #include "catalog/pg_type.h" @@ -26,6 +27,7 @@ #include "tsearch/ts_utils.h" #include "utils/builtins.h" #include "utils/lsyscache.h" +#include "utils/regproc.h" #include "utils/rel.h" @@ -1405,140 +1407,394 @@ checkcondition_str(void *checkval, QueryOperand *val, ExecPhraseData *data) } /* - * Check for phrase condition. Fallback to the AND operation - * if there is no positional information. + * Compute output position list for a tsquery operator in phrase mode. + * + * Merge the position lists in Ldata and Rdata as specified by "emit", + * returning the result list into *data. The input position lists must be + * sorted and unique, and the output will be as well. + * + * data: pointer to initially-all-zeroes output struct, or NULL + * Ldata, Rdata: input position lists + * emit: bitmask of TSPO_XXX flags + * Loffset: offset to be added to Ldata positions before comparing/outputting + * Roffset: offset to be added to Rdata positions before comparing/outputting + * max_npos: maximum possible required size of output position array + * + * Loffset and Roffset should not be negative, else we risk trying to output + * negative positions, which won't fit into WordEntryPos. + * + * Returns true if any positions were emitted to *data; or if data is NULL, + * returns true if any positions would have been emitted. */ +#define TSPO_L_ONLY 0x01 /* emit positions appearing only in L */ +#define TSPO_R_ONLY 0x02 /* emit positions appearing only in R */ +#define TSPO_BOTH 0x04 /* emit positions appearing in both L&R */ + static bool -TS_phrase_execute(QueryItem *curitem, - void *checkval, uint32 flags, ExecPhraseData *data, - bool (*chkcond) (void *, QueryOperand *, ExecPhraseData *)) +TS_phrase_output(ExecPhraseData *data, + ExecPhraseData *Ldata, + ExecPhraseData *Rdata, + int emit, + int Loffset, + int Roffset, + int max_npos) { - /* since this function recurses, it could be driven to stack overflow */ - check_stack_depth(); + int Lindex, + Rindex; - if (curitem->type == QI_VAL) + /* Loop until both inputs are exhausted */ + Lindex = Rindex = 0; + while (Lindex < Ldata->npos || Rindex < Rdata->npos) { - return chkcond(checkval, (QueryOperand *) curitem, data); - } - else - { - ExecPhraseData Ldata = {0, false, NULL}, - Rdata = {0, false, NULL}; - WordEntryPos *Lpos, - *LposStart, - *Rpos, - *pos_iter = NULL; - - Assert(curitem->qoperator.oper == OP_PHRASE); - - if (!TS_phrase_execute(curitem + curitem->qoperator.left, - checkval, flags, &Ldata, chkcond)) - return false; - - if (!TS_phrase_execute(curitem + 1, checkval, flags, &Rdata, chkcond)) - return false; + int Lpos, + Rpos; + int output_pos = 0; /* - * if at least one of the operands has no position information, then - * return false. But if TS_EXEC_PHRASE_AS_AND flag is set then we - * return true as it is a AND operation + * Fetch current values to compare. WEP_GETPOS() is needed because + * ExecPhraseData->data can point to a tsvector's WordEntryPosVector. */ - if (Ldata.npos == 0 || Rdata.npos == 0) - return (flags & TS_EXEC_PHRASE_AS_AND) ? true : false; + if (Lindex < Ldata->npos) + Lpos = WEP_GETPOS(Ldata->pos[Lindex]) + Loffset; + else + { + /* L array exhausted, so we're done if R_ONLY isn't set */ + if (!(emit & TSPO_R_ONLY)) + break; + Lpos = INT_MAX; + } + if (Rindex < Rdata->npos) + Rpos = WEP_GETPOS(Rdata->pos[Rindex]) + Roffset; + else + { + /* R array exhausted, so we're done if L_ONLY isn't set */ + if (!(emit & TSPO_L_ONLY)) + break; + Rpos = INT_MAX; + } - /* - * Result of the operation is a list of the corresponding positions of - * RIGHT operand. - */ - if (data) + /* Merge-join the two input lists */ + if (Lpos < Rpos) + { + /* Lpos is not matched in Rdata, should we output it? */ + if (emit & TSPO_L_ONLY) + output_pos = Lpos; + Lindex++; + } + else if (Lpos == Rpos) { - if (!Rdata.allocated) + /* Lpos and Rpos match ... should we output it? */ + if (emit & TSPO_BOTH) + output_pos = Rpos; + Lindex++; + Rindex++; + } + else /* Lpos > Rpos */ + { + /* Rpos is not matched in Ldata, should we output it? */ + if (emit & TSPO_R_ONLY) + output_pos = Rpos; + Rindex++; + } + if (output_pos > 0) + { + if (data) + { + /* Store position, first allocating output array if needed */ + if (data->pos == NULL) + { + data->pos = (WordEntryPos *) + palloc(max_npos * sizeof(WordEntryPos)); + data->allocated = true; + } + data->pos[data->npos++] = output_pos; + } + else + { /* - * OP_PHRASE is based on the OP_AND, so the number of - * resulting positions could not be greater than the total - * amount of operands. + * Exact positions not needed, so return true as soon as we + * know there is at least one. */ - data->pos = palloc(sizeof(WordEntryPos) * Min(Ldata.npos, Rdata.npos)); - else - data->pos = Rdata.pos; - - data->allocated = true; - data->npos = 0; - pos_iter = data->pos; + return true; + } } + } - /* - * Find matches by distance, WEP_GETPOS() is needed because - * ExecPhraseData->data can point to the tsvector's WordEntryPosVector - */ + if (data && data->npos > 0) + { + /* Let's assert we didn't overrun the array */ + Assert(data->npos <= max_npos); + return true; + } + return false; +} + +/* + * Execute tsquery at or below an OP_PHRASE operator. + * + * This handles tsquery execution at recursion levels where we need to care + * about match locations. + * + * In addition to the same arguments used for TS_execute, the caller may pass + * a preinitialized-to-zeroes ExecPhraseData struct, to be filled with lexeme + * match position info on success. data == NULL if no position data need be + * returned. (In practice, outside callers pass NULL, and only the internal + * recursion cases pass a data pointer.) + * Note: the function assumes data != NULL for operators other than OP_PHRASE. + * This is OK because an outside call always starts from an OP_PHRASE node. + * + * The detailed semantics of the match data, given that the function returned + * "true" (successful match, or possible match), are: + * + * npos > 0, negate = false: + * query is matched at specified position(s) (and only those positions) + * npos > 0, negate = true: + * query is matched at all positions *except* specified position(s) + * npos = 0, negate = false: + * query is possibly matched, matching position(s) are unknown + * (this should only be returned when TS_EXEC_PHRASE_NO_POS flag is set) + * npos = 0, negate = true: + * query is matched at all positions + * + * Successful matches also return a "width" value which is the match width in + * lexemes, less one. Hence, "width" is zero for simple one-lexeme matches, + * and is the sum of the phrase operator distances for phrase matches. Note + * that when width > 0, the listed positions represent the ends of matches not + * the starts. (This unintuitive rule is needed to avoid possibly generating + * negative positions, which wouldn't fit into the WordEntryPos arrays.) + * + * When the function returns "false" (no match), it must return npos = 0, + * negate = false (which is the state initialized by the caller); but the + * "width" output in such cases is undefined. + */ +static bool +TS_phrase_execute(QueryItem *curitem, void *arg, uint32 flags, + TSExecuteCallback chkcond, + ExecPhraseData *data) +{ + ExecPhraseData Ldata, + Rdata; + bool lmatch, + rmatch; + int Loffset, + Roffset, + maxwidth; + + /* since this function recurses, it could be driven to stack overflow */ + check_stack_depth(); + + if (curitem->type == QI_VAL) + return chkcond(arg, (QueryOperand *) curitem, data); + + switch (curitem->qoperator.oper) + { + case OP_NOT: - Rpos = Rdata.pos; - LposStart = Ldata.pos; - while (Rpos < Rdata.pos + Rdata.npos) - { /* - * We need to check all possible distances, so reset Lpos to - * guaranteed not yet satisfied position. + * Because a "true" result with no specific positions is taken as + * uncertain, we need no special care here for !TS_EXEC_CALC_NOT. + * If it's a false positive, the right things happen anyway. + * + * Also, we need not touch data->width, since a NOT operation does + * not change the match width. */ - Lpos = LposStart; - while (Lpos < Ldata.pos + Ldata.npos) + if (TS_phrase_execute(curitem + 1, arg, flags, chkcond, data)) { - if (WEP_GETPOS(*Rpos) - WEP_GETPOS(*Lpos) == - curitem->qoperator.distance) + if (data->npos > 0) { - /* MATCH! */ - if (data) - { - /* Store position for upper phrase operator */ - *pos_iter = WEP_GETPOS(*Rpos); - pos_iter++; - - /* - * Set left start position to next, because current - * one could not satisfy distance for any other right - * position - */ - LposStart = Lpos + 1; - break; - } - else - { - /* - * We are in the root of the phrase tree and hence we - * don't have to store the resulting positions - */ - return true; - } - + /* we have some positions, invert negate flag */ + data->negate = !data->negate; + return true; } - else if (WEP_GETPOS(*Rpos) <= WEP_GETPOS(*Lpos) || - WEP_GETPOS(*Rpos) - WEP_GETPOS(*Lpos) < - curitem->qoperator.distance) + else if (data->negate) { - /* - * Go to the next Rpos, because Lpos is ahead or on less - * distance than required by current operator - */ - break; - + /* change "match everywhere" to "match nowhere" */ + data->negate = false; + return false; } + /* match positions are, and remain, uncertain */ + return true; + } + else + { + /* change "match nowhere" to "match everywhere" */ + Assert(data->npos == 0 && !data->negate); + data->negate = true; + return true; + } + + case OP_PHRASE: + case OP_AND: + memset(&Ldata, 0, sizeof(Ldata)); + memset(&Rdata, 0, sizeof(Rdata)); - Lpos++; + if (!TS_phrase_execute(curitem + curitem->qoperator.left, + arg, flags, chkcond, &Ldata)) + return false; + + if (!TS_phrase_execute(curitem + 1, + arg, flags, chkcond, &Rdata)) + return false; + + /* + * If either operand has no position information, then we can't + * return position data, only a "possible match" result. "Possible + * match" answers are only wanted when TS_EXEC_PHRASE_NO_POS flag + * is set, otherwise return false. + */ + if ((Ldata.npos == 0 && !Ldata.negate) || + (Rdata.npos == 0 && !Rdata.negate)) + return (flags & TS_EXEC_PHRASE_NO_POS) ? true : false; + + if (curitem->qoperator.oper == OP_PHRASE) + { + /* + * Compute Loffset and Roffset suitable for phrase match, and + * compute overall width of whole phrase match. + */ + Loffset = curitem->qoperator.distance + Rdata.width; + Roffset = 0; + if (data) + data->width = curitem->qoperator.distance + + Ldata.width + Rdata.width; + } + else + { + /* + * For OP_AND, set output width and alignment like OP_OR (see + * comment below) + */ + maxwidth = Max(Ldata.width, Rdata.width); + Loffset = maxwidth - Ldata.width; + Roffset = maxwidth - Rdata.width; + if (data) + data->width = maxwidth; } - Rpos++; - } + if (Ldata.negate && Rdata.negate) + { + /* !L & !R: treat as !(L | R) */ + (void) TS_phrase_output(data, &Ldata, &Rdata, + TSPO_BOTH | TSPO_L_ONLY | TSPO_R_ONLY, + Loffset, Roffset, + Ldata.npos + Rdata.npos); + if (data) + data->negate = true; + return true; + } + else if (Ldata.negate) + { + /* !L & R */ + return TS_phrase_output(data, &Ldata, &Rdata, + TSPO_R_ONLY, + Loffset, Roffset, + Rdata.npos); + } + else if (Rdata.negate) + { + /* L & !R */ + return TS_phrase_output(data, &Ldata, &Rdata, + TSPO_L_ONLY, + Loffset, Roffset, + Ldata.npos); + } + else + { + /* straight AND */ + return TS_phrase_output(data, &Ldata, &Rdata, + TSPO_BOTH, + Loffset, Roffset, + Min(Ldata.npos, Rdata.npos)); + } - if (data) - { - data->npos = pos_iter - data->pos; + case OP_OR: + memset(&Ldata, 0, sizeof(Ldata)); + memset(&Rdata, 0, sizeof(Rdata)); - if (data->npos > 0) + lmatch = TS_phrase_execute(curitem + curitem->qoperator.left, + arg, flags, chkcond, &Ldata); + rmatch = TS_phrase_execute(curitem + 1, + arg, flags, chkcond, &Rdata); + + if (!lmatch && !rmatch) + return false; + + /* + * If a valid operand has no position information, then we can't + * return position data, only a "possible match" result. "Possible + * match" answers are only wanted when TS_EXEC_PHRASE_NO_POS flag + * is set, otherwise return false. + */ + if ((lmatch && Ldata.npos == 0 && !Ldata.negate) || + (rmatch && Rdata.npos == 0 && !Rdata.negate)) + return (flags & TS_EXEC_PHRASE_NO_POS) ? true : false; + + /* + * Cope with undefined output width from failed submatch. (This + * takes less code than trying to ensure that all failure returns + * set data->width to zero.) + */ + if (!lmatch) + Ldata.width = 0; + if (!rmatch) + Rdata.width = 0; + + /* + * For OP_AND and OP_OR, report the width of the wider of the two + * inputs, and align the narrower input's positions to the right + * end of that width. This rule deals at least somewhat + * reasonably with cases like "x <-> (y | z <-> q)". + */ + maxwidth = Max(Ldata.width, Rdata.width); + Loffset = maxwidth - Ldata.width; + Roffset = maxwidth - Rdata.width; + data->width = maxwidth; + + if (Ldata.negate && Rdata.negate) + { + /* !L | !R: treat as !(L & R) */ + (void) TS_phrase_output(data, &Ldata, &Rdata, + TSPO_BOTH, + Loffset, Roffset, + Min(Ldata.npos, Rdata.npos)); + data->negate = true; return true; - } + } + else if (Ldata.negate) + { + /* !L | R: treat as !(L & !R) */ + (void) TS_phrase_output(data, &Ldata, &Rdata, + TSPO_L_ONLY, + Loffset, Roffset, + Ldata.npos); + data->negate = true; + return true; + } + else if (Rdata.negate) + { + /* L | !R: treat as !(!L & R) */ + (void) TS_phrase_output(data, &Ldata, &Rdata, + TSPO_R_ONLY, + Loffset, Roffset, + Rdata.npos); + data->negate = true; + return true; + } + else + { + /* straight OR */ + return TS_phrase_output(data, &Ldata, &Rdata, + TSPO_BOTH | TSPO_L_ONLY | TSPO_R_ONLY, + Loffset, Roffset, + Ldata.npos + Rdata.npos); + } + + default: + elog(ERROR, "unrecognized operator: %d", curitem->qoperator.oper); } + /* not reachable, but keep compiler quiet */ return false; } @@ -1546,50 +1802,48 @@ TS_phrase_execute(QueryItem *curitem, /* * Evaluate tsquery boolean expression. * - * chkcond is a callback function used to evaluate each VAL node in the query. - * checkval can be used to pass information to the callback. TS_execute doesn't - * do anything with it. - * It believes that ordinary operators are always closier to root than phrase - * operator, so, TS_execute() may not take care of lexeme's position at all. + * curitem: current tsquery item (initially, the first one) + * arg: opaque value to pass through to callback function + * flags: bitmask of flag bits shown in ts_utils.h + * chkcond: callback function to check whether a primitive value is present + * + * The logic here deals only with operators above any phrase operator, for + * which we do not need to worry about lexeme positions. As soon as we hit an + * OP_PHRASE operator, we pass it off to TS_phrase_execute which does worry. */ bool -TS_execute(QueryItem *curitem, void *checkval, uint32 flags, - bool (*chkcond) (void *checkval, QueryOperand *val, ExecPhraseData *data)) +TS_execute(QueryItem *curitem, void *arg, uint32 flags, + TSExecuteCallback chkcond) { /* since this function recurses, it could be driven to stack overflow */ check_stack_depth(); if (curitem->type == QI_VAL) - return chkcond(checkval, (QueryOperand *) curitem, + return chkcond(arg, (QueryOperand *) curitem, NULL /* we don't need position info */ ); switch (curitem->qoperator.oper) { case OP_NOT: if (flags & TS_EXEC_CALC_NOT) - return !TS_execute(curitem + 1, checkval, flags, chkcond); + return !TS_execute(curitem + 1, arg, flags, chkcond); else return true; case OP_AND: - if (TS_execute(curitem + curitem->qoperator.left, checkval, flags, chkcond)) - return TS_execute(curitem + 1, checkval, flags, chkcond); + if (TS_execute(curitem + curitem->qoperator.left, arg, flags, chkcond)) + return TS_execute(curitem + 1, arg, flags, chkcond); else return false; case OP_OR: - if (TS_execute(curitem + curitem->qoperator.left, checkval, flags, chkcond)) + if (TS_execute(curitem + curitem->qoperator.left, arg, flags, chkcond)) return true; else - return TS_execute(curitem + 1, checkval, flags, chkcond); + return TS_execute(curitem + 1, arg, flags, chkcond); case OP_PHRASE: - - /* - * do not check TS_EXEC_PHRASE_AS_AND here because chkcond() could - * do something more if it's called from TS_phrase_execute() - */ - return TS_phrase_execute(curitem, checkval, flags, NULL, chkcond); + return TS_phrase_execute(curitem, arg, flags, chkcond, NULL); default: elog(ERROR, "unrecognized operator: %d", curitem->qoperator.oper); @@ -1684,12 +1938,10 @@ ts_match_vq(PG_FUNCTION_ARGS) chkval.arre = chkval.arrb + val->size; chkval.values = STRPTR(val); chkval.operand = GETOPERAND(query); - result = TS_execute( - GETQUERY(query), + result = TS_execute(GETQUERY(query), &chkval, TS_EXEC_CALC_NOT, - checkcondition_str - ); + checkcondition_str); PG_FREE_IF_COPY(val, 0); PG_FREE_IF_COPY(query, 1); @@ -2242,6 +2494,7 @@ tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column) (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("tsvector column \"%s\" does not exist", trigger->tgargs[0]))); + /* This will effectively reject system columns, so no separate test: */ if (!IsBinaryCoercible(SPI_gettypeid(rel->rd_att, tsvector_attr_num), TSVECTOROID)) ereport(ERROR, @@ -2328,8 +2581,10 @@ tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column) if (prs.curwords) { datum = PointerGetDatum(make_tsvector(&prs)); - rettuple = SPI_modifytuple(rel, rettuple, 1, &tsvector_attr_num, - &datum, NULL); + isnull = false; + rettuple = heap_modify_tuple_by_cols(rettuple, rel->rd_att, + 1, &tsvector_attr_num, + &datum, &isnull); pfree(DatumGetPointer(datum)); } else @@ -2339,14 +2594,12 @@ tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column) SET_VARSIZE(out, CALCDATASIZE(0, 0)); out->size = 0; datum = PointerGetDatum(out); - rettuple = SPI_modifytuple(rel, rettuple, 1, &tsvector_attr_num, - &datum, NULL); + isnull = false; + rettuple = heap_modify_tuple_by_cols(rettuple, rel->rd_att, + 1, &tsvector_attr_num, + &datum, &isnull); pfree(prs.words); } - if (rettuple == NULL) /* internal error */ - elog(ERROR, "tsvector_update_trigger: %d returned by SPI_modifytuple", - SPI_result); - return PointerGetDatum(rettuple); } diff --git a/src/backend/utils/adt/tsvector_parser.c b/src/backend/utils/adt/tsvector_parser.c index d99405824d..2680114f7c 100644 --- a/src/backend/utils/adt/tsvector_parser.c +++ b/src/backend/utils/adt/tsvector_parser.c @@ -3,7 +3,7 @@ * tsvector_parser.c * Parser for tsvector * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/adt/txid.c b/src/backend/utils/adt/txid.c index c2069a9923..772d7c7203 100644 --- a/src/backend/utils/adt/txid.c +++ b/src/backend/utils/adt/txid.c @@ -10,7 +10,7 @@ * via functions such as SubTransGetTopmostTransaction(). * * - * Copyright (c) 2003-2016, PostgreSQL Global Development Group + * Copyright (c) 2003-2017, PostgreSQL Global Development Group * Author: Jan Wieck, Afilias USA INC. * 64-bit txids: Marko Kreen, Skype Technologies * @@ -336,8 +336,8 @@ parse_snapshot(const char *str) bad_format: ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type txid_snapshot: \"%s\"", - str_start))); + errmsg("invalid input syntax for type %s: \"%s\"", + "txid_snapshot", str_start))); return NULL; /* keep compiler quiet */ } @@ -376,6 +376,27 @@ txid_current(PG_FUNCTION_ARGS) PG_RETURN_INT64(val); } +/* + * Same as txid_current() but doesn't assign a new xid if there isn't one + * yet. + */ +Datum +txid_current_if_assigned(PG_FUNCTION_ARGS) +{ + txid val; + TxidEpoch state; + TransactionId topxid = GetTopTransactionIdIfAny(); + + if (topxid == InvalidTransactionId) + PG_RETURN_NULL(); + + load_xid_epoch(&state); + + val = convert_xid(topxid, &state); + + PG_RETURN_INT64(val); +} + /* * txid_current_snapshot() returns txid_snapshot * diff --git a/src/backend/utils/adt/uuid.c b/src/backend/utils/adt/uuid.c index c59e74da3d..eaf2f8064d 100644 --- a/src/backend/utils/adt/uuid.c +++ b/src/backend/utils/adt/uuid.c @@ -3,7 +3,7 @@ * uuid.c * Functions for the built-in type "uuid". * - * Copyright (c) 2007-2016, PostgreSQL Global Development Group + * Copyright (c) 2007-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/uuid.c @@ -22,15 +22,6 @@ #include "utils/sortsupport.h" #include "utils/uuid.h" -/* uuid size in bytes */ -#define UUID_LEN 16 - -/* pg_uuid_t is declared to be struct pg_uuid_t in uuid.h */ -struct pg_uuid_t -{ - unsigned char data[UUID_LEN]; -}; - /* sortsupport for uuid */ typedef struct { @@ -142,8 +133,8 @@ string_to_uuid(const char *source, pg_uuid_t *uuid) syntax_error: ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for uuid: \"%s\"", - source))); + errmsg("invalid input syntax for type %s: \"%s\"", + "uuid", source))); } Datum diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c index 75e6a46476..af39d4cf25 100644 --- a/src/backend/utils/adt/varbit.c +++ b/src/backend/utils/adt/varbit.c @@ -5,7 +5,7 @@ * * Code originally contributed by Adriaan Joubert. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -20,6 +20,7 @@ #include "libpq/pqformat.h" #include "nodes/nodeFuncs.h" #include "utils/array.h" +#include "utils/builtins.h" #include "utils/varbit.h" #define HEXDIG(z) ((z)<10 ? ((z)+'0') : ((z)-10+'A')) @@ -305,7 +306,7 @@ bit_recv(PG_FUNCTION_ARGS) bits8 mask; bitlen = pq_getmsgint(buf, sizeof(int32)); - if (bitlen < 0) + if (bitlen < 0 || bitlen > VARBITMAXLEN) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid length in external bit string"))); @@ -368,7 +369,7 @@ bit(PG_FUNCTION_ARGS) bits8 mask; /* No work if typmod is invalid or supplied data matches it already */ - if (len <= 0 || len == VARBITLEN(arg)) + if (len <= 0 || len > VARBITMAXLEN || len == VARBITLEN(arg)) PG_RETURN_VARBIT_P(arg); if (!isExplicit) @@ -621,7 +622,7 @@ varbit_recv(PG_FUNCTION_ARGS) bits8 mask; bitlen = pq_getmsgint(buf, sizeof(int32)); - if (bitlen < 0) + if (bitlen < 0 || bitlen > VARBITMAXLEN) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid length in external bit string"))); @@ -1387,9 +1388,14 @@ bitshiftleft(PG_FUNCTION_ARGS) /* Negative shift is a shift to the right */ if (shft < 0) + { + /* Prevent integer overflow in negation */ + if (shft < -VARBITMAXLEN) + shft = -VARBITMAXLEN; PG_RETURN_DATUM(DirectFunctionCall2(bitshiftright, VarBitPGetDatum(arg), Int32GetDatum(-shft))); + } result = (VarBit *) palloc(VARSIZE(arg)); SET_VARSIZE(result, VARSIZE(arg)); @@ -1447,9 +1453,14 @@ bitshiftright(PG_FUNCTION_ARGS) /* Negative shift is a shift to the left */ if (shft < 0) + { + /* Prevent integer overflow in negation */ + if (shft < -VARBITMAXLEN) + shft = -VARBITMAXLEN; PG_RETURN_DATUM(DirectFunctionCall2(bitshiftleft, VarBitPGetDatum(arg), Int32GetDatum(-shft))); + } result = (VarBit *) palloc(VARSIZE(arg)); SET_VARSIZE(result, VARSIZE(arg)); @@ -1507,7 +1518,7 @@ bitfromint4(PG_FUNCTION_ARGS) int destbitsleft, srcbitsleft; - if (typmod <= 0) + if (typmod <= 0 || typmod > VARBITMAXLEN) typmod = 1; /* default bit length */ rlen = VARBITTOTALLEN(typmod); @@ -1587,7 +1598,7 @@ bitfromint8(PG_FUNCTION_ARGS) int destbitsleft, srcbitsleft; - if (typmod <= 0) + if (typmod <= 0 || typmod > VARBITMAXLEN) typmod = 1; /* default bit length */ rlen = VARBITTOTALLEN(typmod); diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c index 94d6da5eb5..c800beb08f 100644 --- a/src/backend/utils/adt/varchar.c +++ b/src/backend/utils/adt/varchar.c @@ -3,7 +3,7 @@ * varchar.c * Functions for the built-in types char(n) and varchar(n). * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -22,6 +22,7 @@ #include "nodes/nodeFuncs.h" #include "utils/array.h" #include "utils/builtins.h" +#include "utils/varlena.h" #include "mb/pg_wchar.h" diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index bf7c0cd735..254379ade7 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -3,7 +3,7 @@ * varlena.c * Functions for the variable-length built-in types. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -21,8 +21,8 @@ #include "access/tuptoaster.h" #include "catalog/pg_collation.h" #include "catalog/pg_type.h" +#include "common/md5.h" #include "lib/hyperloglog.h" -#include "libpq/md5.h" #include "libpq/pqformat.h" #include "miscadmin.h" #include "parser/scansup.h" @@ -34,6 +34,7 @@ #include "utils/memutils.h" #include "utils/pg_locale.h" #include "utils/sortsupport.h" +#include "utils/varlena.h" /* GUC variable */ @@ -294,7 +295,7 @@ byteain(PG_FUNCTION_ARGS) */ ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type bytea"))); + errmsg("invalid input syntax for type %s", "bytea"))); } } @@ -335,7 +336,7 @@ byteain(PG_FUNCTION_ARGS) */ ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type bytea"))); + errmsg("invalid input syntax for type %s", "bytea"))); } } @@ -1844,8 +1845,8 @@ varstr_sortsupport(SortSupport ssup, Oid collid, bool bpchar) * Even apart from the risk of broken locales, it's possible that there * are platforms where the use of abbreviated keys should be disabled at * compile time. Having only 4 byte datums could make worst-case - * performance drastically more likely, for example. Moreover, Darwin's - * strxfrm() implementations is known to not effectively concentrate a + * performance drastically more likely, for example. Moreover, macOS's + * strxfrm() implementation is known to not effectively concentrate a * significant amount of entropy from the original string in earlier * transformed blobs. It's possible that other supported platforms are * similarly encumbered. So, if we ever get past disabling this diff --git a/src/backend/utils/adt/version.c b/src/backend/utils/adt/version.c index f24799251e..5bdc8fad43 100644 --- a/src/backend/utils/adt/version.c +++ b/src/backend/utils/adt/version.c @@ -3,7 +3,7 @@ * version.c * Returns the PostgreSQL version string * - * Copyright (c) 1998-2016, PostgreSQL Global Development Group + * Copyright (c) 1998-2017, PostgreSQL Global Development Group * * IDENTIFICATION * diff --git a/src/backend/utils/adt/windowfuncs.c b/src/backend/utils/adt/windowfuncs.c index 3c1d3cf62d..4e714cd5bf 100644 --- a/src/backend/utils/adt/windowfuncs.c +++ b/src/backend/utils/adt/windowfuncs.c @@ -3,7 +3,7 @@ * windowfuncs.c * Standard window functions defined in SQL spec. * - * Portions Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2000-2017, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/adt/xid.c b/src/backend/utils/adt/xid.c index 9db5814219..2051709fde 100644 --- a/src/backend/utils/adt/xid.c +++ b/src/backend/utils/adt/xid.c @@ -3,7 +3,7 @@ * xid.c * POSTGRES transaction identifier and command identifier datatypes. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -41,13 +41,10 @@ Datum xidout(PG_FUNCTION_ARGS) { TransactionId transactionId = PG_GETARG_TRANSACTIONID(0); + char *result = (char *) palloc(16); - /* maximum 32 bit unsigned integer representation takes 10 chars */ - char *str = palloc(11); - - snprintf(str, 11, "%lu", (unsigned long) transactionId); - - PG_RETURN_CSTRING(str); + snprintf(result, 16, "%lu", (unsigned long) transactionId); + PG_RETURN_CSTRING(result); } /* @@ -160,12 +157,9 @@ xidComparator(const void *arg1, const void *arg2) Datum cidin(PG_FUNCTION_ARGS) { - char *s = PG_GETARG_CSTRING(0); - CommandId c; - - c = atoi(s); + char *str = PG_GETARG_CSTRING(0); - PG_RETURN_COMMANDID(c); + PG_RETURN_COMMANDID((CommandId) strtoul(str, NULL, 0)); } /* @@ -177,7 +171,7 @@ cidout(PG_FUNCTION_ARGS) CommandId c = PG_GETARG_COMMANDID(0); char *result = (char *) palloc(16); - snprintf(result, 16, "%u", (unsigned int) c); + snprintf(result, 16, "%lu", (unsigned long) c); PG_RETURN_CSTRING(result); } diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index 7ed5bcb93d..e8bce3b806 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -4,7 +4,7 @@ * XML data type support. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/utils/adt/xml.c @@ -603,7 +603,7 @@ xmlelement(XmlExprState *xmlExpr, ExprContext *econtext) bool isnull; char *str; - value = ExecEvalExpr(e, econtext, &isnull, NULL); + value = ExecEvalExpr(e, econtext, &isnull); if (isnull) str = NULL; else @@ -620,7 +620,7 @@ xmlelement(XmlExprState *xmlExpr, ExprContext *econtext) bool isnull; char *str; - value = ExecEvalExpr(e, econtext, &isnull, NULL); + value = ExecEvalExpr(e, econtext, &isnull); /* here we can just forget NULL elements immediately */ if (!isnull) { @@ -1455,10 +1455,8 @@ xml_memory_init(void) /* Create memory context if not there already */ if (LibxmlContext == NULL) LibxmlContext = AllocSetContextCreate(TopMemoryContext, - "LibxmlContext", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + "Libxml context", + ALLOCSET_DEFAULT_SIZES); /* Re-establish the callbacks even if already set */ xmlMemSetup(xml_pfree, xml_palloc, xml_repalloc, xml_pstrdup); @@ -2646,8 +2644,6 @@ schema_to_xml_internal(Oid nspid, const char *xmlschema, bool nulls, relid_list = schema_get_xml_visible_tables(nspid); - SPI_push(); - foreach(cell, relid_list) { Oid relid = lfirst_oid(cell); @@ -2660,7 +2656,6 @@ schema_to_xml_internal(Oid nspid, const char *xmlschema, bool nulls, appendStringInfoChar(result, '\n'); } - SPI_pop(); SPI_finish(); xmldata_root_element_end(result, xmlsn); @@ -2824,8 +2819,6 @@ database_to_xml_internal(const char *xmlschema, bool nulls, nspid_list = database_get_xml_visible_schemas(); - SPI_push(); - foreach(cell, nspid_list) { Oid nspid = lfirst_oid(cell); @@ -2838,7 +2831,6 @@ database_to_xml_internal(const char *xmlschema, bool nulls, appendStringInfoChar(result, '\n'); } - SPI_pop(); SPI_finish(); xmldata_root_element_end(result, xmlcn); diff --git a/src/backend/utils/cache/attoptcache.c b/src/backend/utils/cache/attoptcache.c index 54eb864bc6..f7f85b53db 100644 --- a/src/backend/utils/cache/attoptcache.c +++ b/src/backend/utils/cache/attoptcache.c @@ -6,7 +6,7 @@ * Attribute options are cached separately from the fixed-size portion of * pg_attribute entries, which are handled by the relcache. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c index e929616c97..c27186fa13 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -3,7 +3,7 @@ * catcache.c * System catalog cache for tuples matching a key. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -126,11 +126,6 @@ GetCCHashEqFuncs(Oid keytype, PGFunction *hashfunc, RegProcedure *eqfunc) *eqfunc = F_INT2EQ; break; - case INT2VECTOROID: - *hashfunc = hashint2vector; - - *eqfunc = F_INT2VECTOREQ; - break; case INT4OID: *hashfunc = hashint4; @@ -536,9 +531,7 @@ CreateCacheMemoryContext(void) if (!CacheMemoryContext) CacheMemoryContext = AllocSetContextCreate(TopMemoryContext, "CacheMemoryContext", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); } diff --git a/src/backend/utils/cache/evtcache.c b/src/backend/utils/cache/evtcache.c index 6fc1df880b..54ddc55f76 100644 --- a/src/backend/utils/cache/evtcache.c +++ b/src/backend/utils/cache/evtcache.c @@ -3,7 +3,7 @@ * evtcache.c * Special-purpose cache for event trigger data. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -105,9 +105,7 @@ BuildEventTriggerCache(void) EventTriggerCacheContext = AllocSetContextCreate(CacheMemoryContext, "EventTriggerCache", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); CacheRegisterSyscacheCallback(EVENTTRIGGEROID, InvalidateEventCacheCallback, (Datum) 0); diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c index 5803518229..11f9218f66 100644 --- a/src/backend/utils/cache/inval.c +++ b/src/backend/utils/cache/inval.c @@ -85,7 +85,7 @@ * problems can be overcome cheaply. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -375,11 +375,16 @@ AddRelcacheInvalidationMessage(InvalidationListHeader *hdr, { SharedInvalidationMessage msg; - /* Don't add a duplicate item */ - /* We assume dbId need not be checked because it will never change */ + /* + * Don't add a duplicate item. + * We assume dbId need not be checked because it will never change. + * InvalidOid for relId means all relations so we don't need to add + * individual ones when it is present. + */ ProcessMessageList(hdr->rclist, if (msg->rc.id == SHAREDINVALRELCACHE_ID && - msg->rc.relId == relId) + (msg->rc.relId == relId || + msg->rc.relId == InvalidOid)) return); /* OK, add the item */ @@ -509,8 +514,10 @@ RegisterRelcacheInvalidation(Oid dbId, Oid relId) /* * If the relation being invalidated is one of those cached in the local * relcache init file, mark that we need to zap that file at commit. + * Same is true when we are invalidating whole relcache. */ - if (OidIsValid(dbId) && RelationIdIsInInitFile(relId)) + if (OidIsValid(dbId) && + (RelationIdIsInInitFile(relId) || relId == InvalidOid)) transInvalInfo->RelcacheInitFileInval = true; } @@ -565,7 +572,10 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg) { int i; - RelationCacheInvalidateEntry(msg->rc.relId); + if (msg->rc.relId == InvalidOid) + RelationCacheInvalidate(); + else + RelationCacheInvalidateEntry(msg->rc.relId); for (i = 0; i < relcache_callback_count; i++) { @@ -1226,6 +1236,21 @@ CacheInvalidateRelcache(Relation relation) RegisterRelcacheInvalidation(databaseId, relationId); } +/* + * CacheInvalidateRelcacheAll + * Register invalidation of the whole relcache at the end of command. + * + * This is used by alter publication as changes in publications may affect + * large number of tables. + */ +void +CacheInvalidateRelcacheAll(void) +{ + PrepareInvalidationState(); + + RegisterRelcacheInvalidation(InvalidOid, InvalidOid); +} + /* * CacheInvalidateRelcacheByTuple * As above, but relation is identified by passing its pg_class tuple. diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index 13ae6add03..ad50787311 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -3,7 +3,7 @@ * lsyscache.c * Convenience routines for common queries in the system catalog cache. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -261,7 +261,7 @@ get_ordering_op_properties(Oid opno, * (This indicates that the operator is not a valid ordering operator.) */ Oid -get_equality_op_for_ordering_op(Oid opno, bool *reverse) +get_equality_op_for_ordering_op(Oid opno, bool * reverse) { Oid result = InvalidOid; Oid opfamily; @@ -1966,7 +1966,7 @@ get_typbyval(Oid typid) * returning a bogus value when given a bad type OID. */ void -get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval) +get_typlenbyval(Oid typid, int16 *typlen, bool * typbyval) { HeapTuple tp; Form_pg_type typtup; @@ -1986,7 +1986,7 @@ get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval) * A three-fer: given the type OID, return typlen, typbyval, typalign. */ void -get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, +get_typlenbyvalalign(Oid typid, int16 *typlen, bool * typbyval, char *typalign) { HeapTuple tp; @@ -2043,7 +2043,7 @@ void get_type_io_data(Oid typid, IOFuncSelector which_func, int16 *typlen, - bool *typbyval, + bool * typbyval, char *typalign, char *typdelim, Oid *typioparam, @@ -2401,7 +2401,7 @@ type_is_range(Oid typid) * Throws error on failure. */ void -get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred) +get_type_category_preferred(Oid typid, char *typcategory, bool * typispreferred) { HeapTuple tp; Form_pg_type typtup; @@ -2597,7 +2597,7 @@ getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam) * Get info needed for printing values of a type */ void -getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena) +getTypeOutputInfo(Oid type, Oid *typOutput, bool * typIsVarlena) { HeapTuple typeTuple; Form_pg_type pt; @@ -2663,7 +2663,7 @@ getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam) * Get info needed for binary output of values of a type */ void -getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena) +getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool * typIsVarlena) { HeapTuple typeTuple; Form_pg_type pt; @@ -3061,3 +3061,227 @@ get_range_subtype(Oid rangeOid) else return InvalidOid; } + +/* + * get_typ_name + * + * Given the type OID, find the type name + * It returns palloc'd copy of the name or NULL if the cache lookup fails... + */ +char * +get_typ_name(Oid typid) +{ + HeapTuple tp; + + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); + if (HeapTupleIsValid(tp)) + { + Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp); + char *result; + + result = pstrdup(NameStr(typtup->typname)); + ReleaseSysCache(tp); + return result; + } + else + return NULL; +} + +/* + * get_typ_namespace + * + * Given the type OID, find the namespace + * It returns InvalidOid if the cache lookup fails... + */ +Oid +get_typ_namespace(Oid typid) +{ + HeapTuple tp; + + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); + if (HeapTupleIsValid(tp)) + { + Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp); + Oid result; + + result = typtup->typnamespace; + ReleaseSysCache(tp); + return result; + } + else + return InvalidOid; +} + +/* + * get_typname_typid + * Given a type name and namespace OID, look up the type OID. + * + * Returns InvalidOid if there is no such type + */ +Oid +get_typname_typid(const char *typname, Oid typnamespace) +{ + return GetSysCacheOid2(TYPENAMENSP, + CStringGetDatum(typname), + ObjectIdGetDatum(typnamespace)); +} + +/* + * get_funcid + * Given a function name, argument types and namespace OID, look up + * the function OID. + * + * Returns InvalidOid if there is no such function + */ +Oid +get_funcid(const char *funcname, oidvector *argtypes, Oid funcnsp) +{ + return GetSysCacheOid3(PROCNAMEARGSNSP, + CStringGetDatum(funcname), + PointerGetDatum(argtypes), + ObjectIdGetDatum(funcnsp)); +} + +/* + * get_collation_namespace + * Returns the namespace id of a given pg_collation entry. + * + * Returns an Oid of the collation's namespace. + */ +Oid +get_collation_namespace(Oid colloid) +{ + HeapTuple tp; + + tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(colloid)); + if (HeapTupleIsValid(tp)) + { + Form_pg_collation colltup = (Form_pg_collation) GETSTRUCT(tp); + Oid result; + + result = colltup->collnamespace; + ReleaseSysCache(tp); + return result; + } + else + return InvalidOid; +} + +/* + * get_collation_encoding + * Returns the encoding of a given pg_collation entry. + * + * Returns the collation's encoding, or -1 if entry does not exist. + */ +int32 +get_collation_encoding(Oid colloid) +{ + HeapTuple tp; + + tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(colloid)); + if (HeapTupleIsValid(tp)) + { + Form_pg_collation colltup = (Form_pg_collation) GETSTRUCT(tp); + int32 result; + + result = colltup->collencoding; + ReleaseSysCache(tp); + return result; + } + else + return -1; +} + +/* + * get_collid + * Given a collation name, encoding and namespace OID, look up + * the collation OID. + * + * Returns InvalidOid if there is no such collation + */ +Oid +get_collid(const char *collname, int32 collencoding, Oid collnsp) +{ + return GetSysCacheOid3(COLLNAMEENCNSP, + CStringGetDatum(collname), + Int32GetDatum(collencoding), + ObjectIdGetDatum(collnsp)); +} + +/* + * get_opnamespace + * Given an opno, find the namespace + * + * Returns InvalidOid if there is no such operator + */ +Oid +get_opnamespace(Oid opno) +{ + HeapTuple tp; + + tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno)); + if (HeapTupleIsValid(tp)) + { + Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); + Oid result; + + result = optup->oprnamespace; + ReleaseSysCache(tp); + return result; + } + else + return InvalidOid; +} + +/* + * get_operid + * Given an operator name, argument types and namespace OID, look up + * the operator OID. + * + * Returns InvalidOid if there is no such operator + */ +Oid +get_operid(const char *oprname, Oid oprleft, Oid oprright, Oid oprnsp) +{ + return GetSysCacheOid4(OPERNAMENSP, + CStringGetDatum(oprname), + ObjectIdGetDatum(oprleft), + ObjectIdGetDatum(oprright), + ObjectIdGetDatum(oprnsp)); +} + +#include "catalog/pg_rewrite.h" +#include "access/sysattr.h" + +/* + * Returns rule name or NULL, if it is not exists + */ +char * +get_rule_name(Oid ruleoid, Oid *ev_class) +{ + Relation pg_rewrite; + ScanKeyData entry[1]; + SysScanDesc scan; + HeapTuple tuple; + char *name = NULL; + + Assert(ev_class != NULL); + + pg_rewrite = heap_open(RewriteRelationId, AccessShareLock); + ScanKeyInit(&entry[0], + ObjectIdAttributeNumber, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(ruleoid)); + scan = systable_beginscan(pg_rewrite, 0, false, NULL, 1, entry); + tuple = systable_getnext(scan); + + if (HeapTupleIsValid(tuple)) + { + name = pstrdup(NameStr(((Form_pg_rewrite) GETSTRUCT(tuple))->rulename)); + *ev_class = ((Form_pg_rewrite) GETSTRUCT(tuple))->ev_class; + } + + systable_endscan(scan); + heap_close(pg_rewrite, AccessShareLock); + return name; +} diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c index f42a62d500..0cee471b91 100644 --- a/src/backend/utils/cache/plancache.c +++ b/src/backend/utils/cache/plancache.c @@ -38,7 +38,7 @@ * be infrequent enough that more-detailed tracking is not worth the effort. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -53,7 +53,6 @@ #include "access/transam.h" #include "catalog/namespace.h" #include "executor/executor.h" -#include "executor/spi.h" #include "miscadmin.h" #include "nodes/nodeFuncs.h" #include "optimizer/cost.h" @@ -78,7 +77,7 @@ */ #define IsTransactionStmtPlan(plansource) \ ((plansource)->raw_parse_tree && \ - IsA((plansource)->raw_parse_tree, TransactionStmt)) + IsA((plansource)->raw_parse_tree->stmt, TransactionStmt)) /* * This is the head of the backend's list of "saved" CachedPlanSources (i.e., @@ -96,6 +95,7 @@ static CachedPlan *BuildCachedPlan(CachedPlanSource *plansource, List *qlist, static bool choose_custom_plan(CachedPlanSource *plansource, ParamListInfo boundParams); static double cached_plan_cost(CachedPlan *plan, bool include_planner); +static Query *QueryListGetPrimaryStmt(List *stmts); static void AcquireExecutorLocks(List *stmt_list, bool acquire); static void AcquirePlannerLocks(List *stmt_list, bool acquire); static void ScanQueryForLocks(Query *parsetree, bool acquire); @@ -119,6 +119,8 @@ InitPlanCache(void) CacheRegisterSyscacheCallback(NAMESPACEOID, PlanCacheSysCallback, (Datum) 0); CacheRegisterSyscacheCallback(OPEROID, PlanCacheSysCallback, (Datum) 0); CacheRegisterSyscacheCallback(AMOPOPID, PlanCacheSysCallback, (Datum) 0); + CacheRegisterSyscacheCallback(FOREIGNSERVEROID, PlanCacheSysCallback, (Datum) 0); + CacheRegisterSyscacheCallback(FOREIGNDATAWRAPPEROID, PlanCacheSysCallback, (Datum) 0); } /* @@ -146,7 +148,7 @@ InitPlanCache(void) * commandTag: compile-time-constant tag for query, or NULL if empty query */ CachedPlanSource * -CreateCachedPlan(Node *raw_parse_tree, +CreateCachedPlan(RawStmt *raw_parse_tree, const char *query_string, const char *commandTag) { @@ -159,15 +161,13 @@ CreateCachedPlan(Node *raw_parse_tree, /* * Make a dedicated memory context for the CachedPlanSource and its * permanent subsidiary data. It's probably not going to be large, but - * just in case, use the default maxsize parameter. Initially it's a - * child of the caller's context (which we assume to be transient), so - * that it will be cleaned up on error. + * just in case, allow it to grow large. Initially it's a child of the + * caller's context (which we assume to be transient), so that it will be + * cleaned up on error. */ source_context = AllocSetContextCreate(CurrentMemoryContext, "CachedPlanSource", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_START_SMALL_SIZES); /* * Create and fill the CachedPlanSource struct within the new context. @@ -231,7 +231,7 @@ CreateCachedPlan(Node *raw_parse_tree, * commandTag: compile-time-constant tag for query, or NULL if empty query */ CachedPlanSource * -CreateOneShotCachedPlan(Node *raw_parse_tree, +CreateOneShotCachedPlan(RawStmt *raw_parse_tree, const char *query_string, const char *commandTag) { @@ -359,9 +359,7 @@ CompleteCachedPlan(CachedPlanSource *plansource, /* Again, it's a good bet the querytree_context can be small */ querytree_context = AllocSetContextCreate(source_context, "CachedPlanQuery", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_START_SMALL_SIZES); MemoryContextSwitchTo(querytree_context); querytree_list = (List *) copyObject(querytree_list); } @@ -558,7 +556,7 @@ static List * RevalidateCachedQuery(CachedPlanSource *plansource) { bool snapshot_set; - Node *rawtree; + RawStmt *rawtree; List *tlist; /* transient query-tree list */ List *qlist; /* permanent query-tree list */ TupleDesc resultDesc; @@ -733,9 +731,7 @@ RevalidateCachedQuery(CachedPlanSource *plansource) */ querytree_context = AllocSetContextCreate(CurrentMemoryContext, "CachedPlanQuery", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_START_SMALL_SIZES); oldcxt = MemoryContextSwitchTo(querytree_context); qlist = (List *) copyObject(tlist); @@ -884,7 +880,6 @@ BuildCachedPlan(CachedPlanSource *plansource, List *qlist, CachedPlan *plan; List *plist; bool snapshot_set; - bool spi_pushed; bool is_transient; MemoryContext plan_context; MemoryContext oldcxt = CurrentMemoryContext; @@ -932,22 +927,11 @@ BuildCachedPlan(CachedPlanSource *plansource, List *qlist, snapshot_set = true; } - /* - * The planner may try to call SPI-using functions, which causes a problem - * if we're already inside one. Rather than expect all SPI-using code to - * do SPI_push whenever a replan could happen, it seems best to take care - * of the case here. - */ - spi_pushed = SPI_push_conditional(); - /* * Generate the plan. */ plist = pg_plan_queries(qlist, plansource->cursor_options, boundParams); - /* Clean up SPI state */ - SPI_pop_conditional(spi_pushed); - /* Release snapshot if we got one */ if (snapshot_set) PopActiveSnapshot(); @@ -955,17 +939,14 @@ BuildCachedPlan(CachedPlanSource *plansource, List *qlist, /* * Normally we make a dedicated memory context for the CachedPlan and its * subsidiary data. (It's probably not going to be large, but just in - * case, use the default maxsize parameter. It's transient for the - * moment.) But for a one-shot plan, we just leave it in the caller's - * memory context. + * case, allow it to grow large. It's transient for the moment.) But for + * a one-shot plan, we just leave it in the caller's memory context. */ if (!plansource->is_oneshot) { plan_context = AllocSetContextCreate(CurrentMemoryContext, "CachedPlan", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_START_SMALL_SIZES); /* * Copy plan into the new context. @@ -996,7 +977,7 @@ BuildCachedPlan(CachedPlanSource *plansource, List *qlist, { PlannedStmt *plannedstmt = (PlannedStmt *) lfirst(lc); - if (!IsA(plannedstmt, PlannedStmt)) + if (plannedstmt->commandType == CMD_UTILITY) continue; /* Ignore utility statements */ if (plannedstmt->transientPlan) @@ -1091,7 +1072,7 @@ cached_plan_cost(CachedPlan *plan, bool include_planner) { PlannedStmt *plannedstmt = (PlannedStmt *) lfirst(lc); - if (!IsA(plannedstmt, PlannedStmt)) + if (plannedstmt->commandType == CMD_UTILITY) continue; /* Ignore utility statements */ result += plannedstmt->planTree->total_cost; @@ -1150,7 +1131,7 @@ CachedPlan * GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams, bool useResOwner) { - CachedPlan *plan; + CachedPlan *plan = NULL; List *qlist; bool customplan; @@ -1232,6 +1213,8 @@ GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams, } } + Assert(plan != NULL); + /* Flag the plan as in use by caller */ if (useResOwner) ResourceOwnerEnlargePlanCacheRefs(CurrentResourceOwner); @@ -1351,9 +1334,7 @@ CopyCachedPlan(CachedPlanSource *plansource) source_context = AllocSetContextCreate(CurrentMemoryContext, "CachedPlanSource", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_START_SMALL_SIZES); oldcxt = MemoryContextSwitchTo(source_context); @@ -1384,9 +1365,7 @@ CopyCachedPlan(CachedPlanSource *plansource) querytree_context = AllocSetContextCreate(source_context, "CachedPlanQuery", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_START_SMALL_SIZES); MemoryContextSwitchTo(querytree_context); newsource->query_list = (List *) copyObject(plansource->query_list); newsource->relationOids = (List *) copyObject(plansource->relationOids); @@ -1441,7 +1420,7 @@ CachedPlanIsValid(CachedPlanSource *plansource) List * CachedPlanGetTargetList(CachedPlanSource *plansource) { - Node *pstmt; + Query *pstmt; /* Assert caller is doing things in a sane order */ Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC); @@ -1458,9 +1437,34 @@ CachedPlanGetTargetList(CachedPlanSource *plansource) RevalidateCachedQuery(plansource); /* Get the primary statement and find out what it returns */ - pstmt = PortalListGetPrimaryStmt(plansource->query_list); + pstmt = QueryListGetPrimaryStmt(plansource->query_list); + + return FetchStatementTargetList((Node *) pstmt); +} + +/* + * QueryListGetPrimaryStmt + * Get the "primary" stmt within a list, ie, the one marked canSetTag. + * + * Returns NULL if no such stmt. If multiple queries within the list are + * marked canSetTag, returns the first one. Neither of these cases should + * occur in present usages of this function. + */ +static Query * +QueryListGetPrimaryStmt(List *stmts) +{ + ListCell *lc; + + foreach(lc, stmts) + { + Query *stmt = (Query *) lfirst(lc); + + Assert(IsA(stmt, Query)); - return FetchStatementTargetList(pstmt); + if (stmt->canSetTag) + return stmt; + } + return NULL; } /* @@ -1478,8 +1482,9 @@ AcquireExecutorLocks(List *stmt_list, bool acquire) int rt_index; ListCell *lc2; - Assert(!IsA(plannedstmt, Query)); - if (!IsA(plannedstmt, PlannedStmt)) + Assert(IsA(plannedstmt, PlannedStmt)); + + if (plannedstmt->commandType == CMD_UTILITY) { /* * Ignore utility statements, except those (such as EXPLAIN) that @@ -1488,7 +1493,7 @@ AcquireExecutorLocks(List *stmt_list, bool acquire) * rule rewriting, because rewriting doesn't change the query * representation. */ - Query *query = UtilityContainsQuery((Node *) plannedstmt); + Query *query = UtilityContainsQuery(plannedstmt->utilityStmt); if (query) ScanQueryForLocks(query, acquire); @@ -1676,8 +1681,7 @@ PlanCacheComputeResultDesc(List *stmt_list) return ExecCleanTypeFromTL(query->targetList, false); case PORTAL_ONE_RETURNING: - query = (Query *) PortalListGetPrimaryStmt(stmt_list); - Assert(IsA(query, Query)); + query = QueryListGetPrimaryStmt(stmt_list); Assert(query->returningList); return ExecCleanTypeFromTL(query->returningList, false); @@ -1742,8 +1746,7 @@ PlanCacheRelCallback(Datum arg, Oid relid) { PlannedStmt *plannedstmt = (PlannedStmt *) lfirst(lc); - Assert(!IsA(plannedstmt, Query)); - if (!IsA(plannedstmt, PlannedStmt)) + if (plannedstmt->commandType == CMD_UTILITY) continue; /* Ignore utility statements */ if ((relid == InvalidOid) ? plannedstmt->relationOids != NIL : list_member_oid(plannedstmt->relationOids, relid)) @@ -1817,8 +1820,7 @@ PlanCacheFuncCallback(Datum arg, int cacheid, uint32 hashvalue) PlannedStmt *plannedstmt = (PlannedStmt *) lfirst(lc); ListCell *lc3; - Assert(!IsA(plannedstmt, Query)); - if (!IsA(plannedstmt, PlannedStmt)) + if (plannedstmt->commandType == CMD_UTILITY) continue; /* Ignore utility statements */ foreach(lc3, plannedstmt->invalItems) { @@ -1904,3 +1906,71 @@ ResetPlanCache(void) } } } + +void +SetRemoteSubplan(CachedPlanSource *plansource, PlannedStmt *rstmt) +{ + CachedPlan *plan; + MemoryContext plan_context; + MemoryContext oldcxt; + PlannedStmt *stmt; + + Assert(plansource->raw_parse_tree == NULL); + Assert(plansource->query_list == NIL); + + /* + * Make dedicated query context to store cached plan. It is in current + * memory context for now, later it will be reparented to + * CachedMemoryContext. If it is in CachedMemoryContext initially we would + * have to destroy it in case of error. + */ + plan_context = AllocSetContextCreate(CurrentMemoryContext, + "CachedPlan", + ALLOCSET_DEFAULT_SIZES); + oldcxt = MemoryContextSwitchTo(plan_context); + + stmt = makeNode(PlannedStmt); + + stmt->commandType = rstmt->commandType; + stmt->hasReturning = rstmt->hasReturning; + stmt->resultRelations = rstmt->resultRelations; + stmt->subplans = rstmt->subplans; + stmt->rowMarks = rstmt->rowMarks; + stmt->planTree = rstmt->planTree; + stmt->rtable = rstmt->rtable; + + stmt->canSetTag = true; + stmt->transientPlan = false; + stmt->utilityStmt = NULL; + stmt->rewindPlanIDs = NULL; + stmt->relationOids = rstmt->relationOids; + stmt->invalItems = rstmt->invalItems; + + /* + * Create and fill the CachedPlan struct within the new context. + */ + plan = (CachedPlan *) palloc(sizeof(CachedPlan)); + plan->magic = CACHEDPLAN_MAGIC; + plan->stmt_list = list_make1(stmt); + plan->saved_xmin = InvalidTransactionId; + plan->refcount = 1; /* will be referenced by plansource */ + plan->context = plan_context; + plan->dependsOnRole = false; + if (plansource->is_saved) + { + MemoryContextSetParent(plan_context, CacheMemoryContext); + plan->is_saved = true; + } + else + { + MemoryContextSetParent(plan_context, + MemoryContextGetParent(plansource->context)); + plan->is_saved = false; + } + plan->is_valid = true; + plan->is_oneshot = false; + + plansource->gplan = plan; + + MemoryContextSwitchTo(oldcxt); +} diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 8d2ad018bb..26ff7e187a 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -3,7 +3,7 @@ * relcache.c * POSTGRES relation descriptor cache code * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -32,6 +32,7 @@ #include "access/htup_details.h" #include "access/multixact.h" +#include "access/nbtree.h" #include "access/reloptions.h" #include "access/sysattr.h" #include "access/xact.h" @@ -40,6 +41,7 @@ #include "catalog/index.h" #include "catalog/indexing.h" #include "catalog/namespace.h" +#include "catalog/partition.h" #include "catalog/pg_am.h" #include "catalog/pg_amproc.h" #include "catalog/pg_attrdef.h" @@ -49,9 +51,12 @@ #include "catalog/pg_database.h" #include "catalog/pg_namespace.h" #include "catalog/pg_opclass.h" +#include "catalog/pg_partitioned_table.h" #include "catalog/pg_proc.h" +#include "catalog/pg_publication.h" #include "catalog/pg_rewrite.h" #include "catalog/pg_shseclabel.h" +#include "catalog/pg_subscription.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_trigger.h" #include "catalog/pg_type.h" @@ -100,6 +105,7 @@ static const FormData_pg_attribute Desc_pg_authid[Natts_pg_authid] = {Schema_pg_ static const FormData_pg_attribute Desc_pg_auth_members[Natts_pg_auth_members] = {Schema_pg_auth_members}; static const FormData_pg_attribute Desc_pg_index[Natts_pg_index] = {Schema_pg_index}; static const FormData_pg_attribute Desc_pg_shseclabel[Natts_pg_shseclabel] = {Schema_pg_shseclabel}; +static const FormData_pg_attribute Desc_pg_subscription[Natts_pg_subscription] = {Schema_pg_subscription}; /* * Hash tables that index the relation cache @@ -258,6 +264,8 @@ static HeapTuple ScanPgRelation(Oid targetRelId, bool indexOK, bool force_non_hi static Relation AllocateRelationDesc(Form_pg_class relp); static void RelationParseRelOptions(Relation relation, HeapTuple tuple); static void RelationBuildTupleDesc(Relation relation); +static void RelationBuildPartitionKey(Relation relation); +static PartitionKey copy_partition_key(PartitionKey fromkey); static Relation RelationBuildDesc(Oid targetRelId, bool insertIt); static void RelationInitPhysicalAddr(Relation relation); static void load_critical_index(Oid indexoid, Oid heapoid); @@ -278,6 +286,8 @@ static OpClassCacheEnt *LookupOpclassInfo(Oid operatorClassOid, StrategyNumber numSupport); static void RelationCacheInitFileRemoveInDir(const char *tblspcpath); static void unlink_initfile(const char *initfilename); +static bool equalPartitionDescs(PartitionKey key, PartitionDesc partdesc1, + PartitionDesc partdesc2); /* @@ -435,6 +445,7 @@ RelationParseRelOptions(Relation relation, HeapTuple tuple) case RELKIND_INDEX: case RELKIND_VIEW: case RELKIND_MATVIEW: + case RELKIND_PARTITIONED_TABLE: break; default: return; @@ -659,14 +670,11 @@ RelationBuildRuleLock(Relation relation) int maxlocks; /* - * Make the private context. Parameters are set on the assumption that - * it'll probably not contain much data. + * Make the private context. Assume it'll not contain much data. */ rulescxt = AllocSetContextCreate(CacheMemoryContext, RelationGetRelationName(relation), - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MAXSIZE); + ALLOCSET_SMALL_SIZES); relation->rd_rulescxt = rulescxt; /* @@ -798,6 +806,237 @@ RelationBuildRuleLock(Relation relation) relation->rd_rules = rulelock; } +/* + * RelationBuildPartitionKey + * Build and attach to relcache partition key data of relation + * + * Partitioning key data is stored in CacheMemoryContext to ensure it survives + * as long as the relcache. To avoid leaking memory in that context in case + * of an error partway through this function, we build the structure in the + * working context (which must be short-lived) and copy the completed + * structure into the cache memory. + * + * Also, since the structure being created here is sufficiently complex, we + * make a private child context of CacheMemoryContext for each relation that + * has associated partition key information. That means no complicated logic + * to free individual elements whenever the relcache entry is flushed - just + * delete the context. + */ +static void +RelationBuildPartitionKey(Relation relation) +{ + Form_pg_partitioned_table form; + HeapTuple tuple; + bool isnull; + int i; + PartitionKey key; + AttrNumber *attrs; + oidvector *opclass; + oidvector *collation; + ListCell *partexprs_item; + Datum datum; + MemoryContext partkeycxt, + oldcxt; + + tuple = SearchSysCache1(PARTRELID, + ObjectIdGetDatum(RelationGetRelid(relation))); + + /* + * The following happens when we have created our pg_class entry but not + * the pg_partitioned_table entry yet. + */ + if (!HeapTupleIsValid(tuple)) + return; + + key = (PartitionKey) palloc0(sizeof(PartitionKeyData)); + + /* Fixed-length attributes */ + form = (Form_pg_partitioned_table) GETSTRUCT(tuple); + key->strategy = form->partstrat; + key->partnatts = form->partnatts; + + /* + * We can rely on the first variable-length attribute being mapped to the + * relevant field of the catalog's C struct, because all previous + * attributes are non-nullable and fixed-length. + */ + attrs = form->partattrs.values; + + /* But use the hard way to retrieve further variable-length attributes */ + /* Operator class */ + datum = SysCacheGetAttr(PARTRELID, tuple, + Anum_pg_partitioned_table_partclass, &isnull); + Assert(!isnull); + opclass = (oidvector *) DatumGetPointer(datum); + + /* Collation */ + datum = SysCacheGetAttr(PARTRELID, tuple, + Anum_pg_partitioned_table_partcollation, &isnull); + Assert(!isnull); + collation = (oidvector *) DatumGetPointer(datum); + + /* Expressions */ + datum = SysCacheGetAttr(PARTRELID, tuple, + Anum_pg_partitioned_table_partexprs, &isnull); + if (!isnull) + { + char *exprString; + Node *expr; + + exprString = TextDatumGetCString(datum); + expr = stringToNode(exprString); + pfree(exprString); + + /* + * Run the expressions through const-simplification since the planner + * will be comparing them to similarly-processed qual clause operands, + * and may fail to detect valid matches without this step. We don't + * need to bother with canonicalize_qual() though, because partition + * expressions are not full-fledged qualification clauses. + */ + expr = eval_const_expressions(NULL, (Node *) expr); + + /* May as well fix opfuncids too */ + fix_opfuncids((Node *) expr); + key->partexprs = (List *) expr; + } + + key->partattrs = (AttrNumber *) palloc0(key->partnatts * sizeof(AttrNumber)); + key->partopfamily = (Oid *) palloc0(key->partnatts * sizeof(Oid)); + key->partopcintype = (Oid *) palloc0(key->partnatts * sizeof(Oid)); + key->partsupfunc = (FmgrInfo *) palloc0(key->partnatts * sizeof(FmgrInfo)); + + key->partcollation = (Oid *) palloc0(key->partnatts * sizeof(Oid)); + + /* Gather type and collation info as well */ + key->parttypid = (Oid *) palloc0(key->partnatts * sizeof(Oid)); + key->parttypmod = (int32 *) palloc0(key->partnatts * sizeof(int32)); + key->parttyplen = (int16 *) palloc0(key->partnatts * sizeof(int16)); + key->parttypbyval = (bool *) palloc0(key->partnatts * sizeof(bool)); + key->parttypalign = (char *) palloc0(key->partnatts * sizeof(char)); + key->parttypcoll = (Oid *) palloc0(key->partnatts * sizeof(Oid)); + + /* Copy partattrs and fill other per-attribute info */ + memcpy(key->partattrs, attrs, key->partnatts * sizeof(int16)); + partexprs_item = list_head(key->partexprs); + for (i = 0; i < key->partnatts; i++) + { + AttrNumber attno = key->partattrs[i]; + HeapTuple opclasstup; + Form_pg_opclass opclassform; + Oid funcid; + + /* Collect opfamily information */ + opclasstup = SearchSysCache1(CLAOID, + ObjectIdGetDatum(opclass->values[i])); + if (!HeapTupleIsValid(opclasstup)) + elog(ERROR, "cache lookup failed for opclass %u", opclass->values[i]); + + opclassform = (Form_pg_opclass) GETSTRUCT(opclasstup); + key->partopfamily[i] = opclassform->opcfamily; + key->partopcintype[i] = opclassform->opcintype; + + /* + * A btree support function covers the cases of list and range methods + * currently supported. + */ + funcid = get_opfamily_proc(opclassform->opcfamily, + opclassform->opcintype, + opclassform->opcintype, + BTORDER_PROC); + + fmgr_info(funcid, &key->partsupfunc[i]); + + /* Collation */ + key->partcollation[i] = collation->values[i]; + + /* Collect type information */ + if (attno != 0) + { + key->parttypid[i] = relation->rd_att->attrs[attno - 1]->atttypid; + key->parttypmod[i] = relation->rd_att->attrs[attno - 1]->atttypmod; + key->parttypcoll[i] = relation->rd_att->attrs[attno - 1]->attcollation; + } + else + { + key->parttypid[i] = exprType(lfirst(partexprs_item)); + key->parttypmod[i] = exprTypmod(lfirst(partexprs_item)); + key->parttypcoll[i] = exprCollation(lfirst(partexprs_item)); + } + get_typlenbyvalalign(key->parttypid[i], + &key->parttyplen[i], + &key->parttypbyval[i], + &key->parttypalign[i]); + + ReleaseSysCache(opclasstup); + } + + ReleaseSysCache(tuple); + + /* Success --- now copy to the cache memory */ + partkeycxt = AllocSetContextCreate(CacheMemoryContext, + RelationGetRelationName(relation), + ALLOCSET_SMALL_SIZES); + relation->rd_partkeycxt = partkeycxt; + oldcxt = MemoryContextSwitchTo(relation->rd_partkeycxt); + relation->rd_partkey = copy_partition_key(key); + MemoryContextSwitchTo(oldcxt); +} + +/* + * copy_partition_key + * + * The copy is allocated in the current memory context. + */ +static PartitionKey +copy_partition_key(PartitionKey fromkey) +{ + PartitionKey newkey; + int n; + + newkey = (PartitionKey) palloc(sizeof(PartitionKeyData)); + + newkey->strategy = fromkey->strategy; + newkey->partnatts = n = fromkey->partnatts; + + newkey->partattrs = (AttrNumber *) palloc(n * sizeof(AttrNumber)); + memcpy(newkey->partattrs, fromkey->partattrs, n * sizeof(AttrNumber)); + + newkey->partexprs = copyObject(fromkey->partexprs); + + newkey->partopfamily = (Oid *) palloc(n * sizeof(Oid)); + memcpy(newkey->partopfamily, fromkey->partopfamily, n * sizeof(Oid)); + + newkey->partopcintype = (Oid *) palloc(n * sizeof(Oid)); + memcpy(newkey->partopcintype, fromkey->partopcintype, n * sizeof(Oid)); + + newkey->partsupfunc = (FmgrInfo *) palloc(n * sizeof(FmgrInfo)); + memcpy(newkey->partsupfunc, fromkey->partsupfunc, n * sizeof(FmgrInfo)); + + newkey->partcollation = (Oid *) palloc(n * sizeof(Oid)); + memcpy(newkey->partcollation, fromkey->partcollation, n * sizeof(Oid)); + + newkey->parttypid = (Oid *) palloc(n * sizeof(Oid)); + memcpy(newkey->parttypid, fromkey->parttypid, n * sizeof(Oid)); + + newkey->parttypmod = (int32 *) palloc(n * sizeof(int32)); + memcpy(newkey->parttypmod, fromkey->parttypmod, n * sizeof(int32)); + + newkey->parttyplen = (int16 *) palloc(n * sizeof(int16)); + memcpy(newkey->parttyplen, fromkey->parttyplen, n * sizeof(int16)); + + newkey->parttypbyval = (bool *) palloc(n * sizeof(bool)); + memcpy(newkey->parttypbyval, fromkey->parttypbyval, n * sizeof(bool)); + + newkey->parttypalign = (char *) palloc(n * sizeof(bool)); + memcpy(newkey->parttypalign, fromkey->parttypalign, n * sizeof(char)); + + newkey->parttypcoll = (Oid *) palloc(n * sizeof(Oid)); + memcpy(newkey->parttypcoll, fromkey->parttypcoll, n * sizeof(Oid)); + + return newkey; +} + /* * equalRuleLocks * @@ -925,6 +1164,58 @@ equalRSDesc(RowSecurityDesc *rsdesc1, RowSecurityDesc *rsdesc2) return true; } +/* + * equalPartitionDescs + * Compare two partition descriptors for logical equality + */ +static bool +equalPartitionDescs(PartitionKey key, PartitionDesc partdesc1, + PartitionDesc partdesc2) +{ + int i; + + if (partdesc1 != NULL) + { + if (partdesc2 == NULL) + return false; + if (partdesc1->nparts != partdesc2->nparts) + return false; + + Assert(key != NULL || partdesc1->nparts == 0); + + /* + * Same oids? If the partitioning structure did not change, that is, + * no partitions were added or removed to the relation, the oids array + * should still match element-by-element. + */ + for (i = 0; i < partdesc1->nparts; i++) + { + if (partdesc1->oids[i] != partdesc2->oids[i]) + return false; + } + + /* + * Now compare partition bound collections. The logic to iterate over + * the collections is private to partition.c. + */ + if (partdesc1->boundinfo != NULL) + { + if (partdesc2->boundinfo == NULL) + return false; + + if (!partition_bounds_equal(key, partdesc1->boundinfo, + partdesc2->boundinfo)) + return false; + } + else if (partdesc2->boundinfo != NULL) + return false; + } + else if (partdesc2 != NULL) + return false; + + return true; +} + /* * RelationBuildDesc * @@ -1053,6 +1344,20 @@ RelationBuildDesc(Oid targetRelId, bool insertIt) relation->rd_fkeylist = NIL; relation->rd_fkeyvalid = false; + /* if a partitioned table, initialize key and partition descriptor info */ + if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + { + RelationBuildPartitionKey(relation); + RelationBuildPartitionDesc(relation); + } + else + { + relation->rd_partkeycxt = NULL; + relation->rd_partkey = NULL; + relation->rd_partdesc = NULL; + relation->rd_pdcxt = NULL; + } + /* * if it's an index, initialize index-related information */ @@ -1248,15 +1553,10 @@ RelationInitIndexAccessInfo(Relation relation) * Make the private context to hold index access info. The reason we need * a context, and not just a couple of pallocs, is so that we won't leak * any subsidiary info attached to fmgr lookup records. - * - * Context parameters are set on the assumption that it'll probably not - * contain much data. */ indexcxt = AllocSetContextCreate(CacheMemoryContext, RelationGetRelationName(relation), - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MAXSIZE); + ALLOCSET_SMALL_SIZES); relation->rd_indexcxt = indexcxt; /* @@ -2039,7 +2339,10 @@ RelationDestroyRelation(Relation relation, bool remember_tupdesc) list_free(relation->rd_indexlist); bms_free(relation->rd_indexattr); bms_free(relation->rd_keyattr); + bms_free(relation->rd_pkattr); bms_free(relation->rd_idattr); + if (relation->rd_pubactions) + pfree(relation->rd_pubactions); if (relation->rd_options) pfree(relation->rd_options); if (relation->rd_indextuple) @@ -2050,6 +2353,12 @@ RelationDestroyRelation(Relation relation, bool remember_tupdesc) MemoryContextDelete(relation->rd_rulescxt); if (relation->rd_rsdesc) MemoryContextDelete(relation->rd_rsdesc->rscxt); + if (relation->rd_partkeycxt) + MemoryContextDelete(relation->rd_partkeycxt); + if (relation->rd_pdcxt) + MemoryContextDelete(relation->rd_pdcxt); + if (relation->rd_partcheck) + pfree(relation->rd_partcheck); if (relation->rd_fdwroutine) pfree(relation->rd_fdwroutine); pfree(relation); @@ -2198,11 +2507,12 @@ RelationClearRelation(Relation relation, bool rebuild) * * When rebuilding an open relcache entry, we must preserve ref count, * rd_createSubid/rd_newRelfilenodeSubid, and rd_toastoid state. Also - * attempt to preserve the pg_class entry (rd_rel), tupledesc, and - * rewrite-rule substructures in place, because various places assume - * that these structures won't move while they are working with an - * open relcache entry. (Note: the refcount mechanism for tupledescs - * might someday allow us to remove this hack for the tupledesc.) + * attempt to preserve the pg_class entry (rd_rel), tupledesc, + * rewrite-rule, partition key, and partition descriptor substructures + * in place, because various places assume that these structures won't + * move while they are working with an open relcache entry. (Note: + * the refcount mechanism for tupledescs might someday allow us to + * remove this hack for the tupledesc.) * * Note that this process does not touch CurrentResourceOwner; which * is good because whatever ref counts the entry may have do not @@ -2213,6 +2523,8 @@ RelationClearRelation(Relation relation, bool rebuild) bool keep_tupdesc; bool keep_rules; bool keep_policies; + bool keep_partkey; + bool keep_partdesc; /* Build temporary entry, but don't link it into hashtable */ newrel = RelationBuildDesc(save_relid, false); @@ -2243,6 +2555,10 @@ RelationClearRelation(Relation relation, bool rebuild) keep_tupdesc = equalTupleDescs(relation->rd_att, newrel->rd_att); keep_rules = equalRuleLocks(relation->rd_rules, newrel->rd_rules); keep_policies = equalRSDesc(relation->rd_rsdesc, newrel->rd_rsdesc); + keep_partkey = (relation->rd_partkey != NULL); + keep_partdesc = equalPartitionDescs(relation->rd_partkey, + relation->rd_partdesc, + newrel->rd_partdesc); /* * Perform swapping of the relcache entry contents. Within this @@ -2297,6 +2613,18 @@ RelationClearRelation(Relation relation, bool rebuild) SWAPFIELD(Oid, rd_toastoid); /* pgstat_info must be preserved */ SWAPFIELD(struct PgStat_TableStatus *, pgstat_info); + /* partition key must be preserved, if we have one */ + if (keep_partkey) + { + SWAPFIELD(PartitionKey, rd_partkey); + SWAPFIELD(MemoryContext, rd_partkeycxt); + } + /* preserve old partdesc if no logical change */ + if (keep_partdesc) + { + SWAPFIELD(PartitionDesc, rd_partdesc); + SWAPFIELD(MemoryContext, rd_pdcxt); + } #undef SWAPFIELD @@ -2721,6 +3049,7 @@ AtEOXact_cleanup(Relation relation, bool isCommit) list_free(relation->rd_indexlist); relation->rd_indexlist = NIL; relation->rd_oidindex = InvalidOid; + relation->rd_pkindex = InvalidOid; relation->rd_replidindex = InvalidOid; relation->rd_indexvalid = 0; } @@ -2833,6 +3162,7 @@ AtEOSubXact_cleanup(Relation relation, bool isCommit, list_free(relation->rd_indexlist); relation->rd_indexlist = NIL; relation->rd_oidindex = InvalidOid; + relation->rd_pkindex = InvalidOid; relation->rd_replidindex = InvalidOid; relation->rd_indexvalid = 0; } @@ -2991,7 +3321,9 @@ RelationBuildLocalRelation(const char *relname, /* system relations and non-table objects don't have one */ if (!IsSystemNamespace(relnamespace) && - (relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW)) + (relkind == RELKIND_RELATION || + relkind == RELKIND_MATVIEW || + relkind == RELKIND_PARTITIONED_TABLE)) rel->rd_rel->relreplident = REPLICA_IDENTITY_DEFAULT; else rel->rd_rel->relreplident = REPLICA_IDENTITY_NOTHING; @@ -3264,8 +3596,10 @@ RelationCacheInitializePhase2(void) false, Natts_pg_auth_members, Desc_pg_auth_members); formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true, false, Natts_pg_shseclabel, Desc_pg_shseclabel); + formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true, + true, Natts_pg_subscription, Desc_pg_subscription); -#define NUM_CRITICAL_SHARED_RELS 4 /* fix if you change list above */ +#define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */ } MemoryContextSwitchTo(oldcxt); @@ -3522,6 +3856,20 @@ RelationCacheInitializePhase3(void) restart = true; } + /* + * Reload partition key and descriptor for a partitioned table. + */ + if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + { + RelationBuildPartitionKey(relation); + Assert(relation->rd_partkey != NULL); + + RelationBuildPartitionDesc(relation); + Assert(relation->rd_partdesc != NULL); + + restart = true; + } + /* Release hold on the relation */ RelationDecrementReferenceCount(relation); @@ -4087,6 +4435,7 @@ RelationGetIndexList(Relation relation) oldlist = relation->rd_indexlist; relation->rd_indexlist = list_copy(result); relation->rd_oidindex = oidIndex; + relation->rd_pkindex = pkeyIndex; if (replident == REPLICA_IDENTITY_DEFAULT && OidIsValid(pkeyIndex)) relation->rd_replidindex = pkeyIndex; else if (replident == REPLICA_IDENTITY_INDEX && OidIsValid(candidateIndex)) @@ -4154,7 +4503,7 @@ insert_ordered_oid(List *list, Oid datum) * to ensure that a correct rd_indexattr set has been cached before first * calling RelationSetIndexList; else a subsequent inquiry might cause a * wrong rd_indexattr set to get computed and cached. Likewise, we do not - * touch rd_keyattr or rd_idattr. + * touch rd_keyattr, rd_pkattr or rd_idattr. */ void RelationSetIndexList(Relation relation, List *indexIds, Oid oidIndex) @@ -4170,7 +4519,11 @@ RelationSetIndexList(Relation relation, List *indexIds, Oid oidIndex) list_free(relation->rd_indexlist); relation->rd_indexlist = indexIds; relation->rd_oidindex = oidIndex; - /* For the moment, assume the target rel hasn't got a replica index */ + /* + * For the moment, assume the target rel hasn't got a pk or replica + * index. We'll load them on demand in the API that wraps access to them. + */ + relation->rd_pkindex = InvalidOid; relation->rd_replidindex = InvalidOid; relation->rd_indexvalid = 2; /* mark list as forced */ /* Flag relation as needing eoxact cleanup (to reset the list) */ @@ -4205,6 +4558,27 @@ RelationGetOidIndex(Relation relation) return relation->rd_oidindex; } +/* + * RelationGetPrimaryKeyIndex -- get OID of the relation's primary key index + * + * Returns InvalidOid if there is no such index. + */ +Oid +RelationGetPrimaryKeyIndex(Relation relation) +{ + List *ilist; + + if (relation->rd_indexvalid == 0) + { + /* RelationGetIndexList does the heavy lifting. */ + ilist = RelationGetIndexList(relation); + list_free(ilist); + Assert(relation->rd_indexvalid != 0); + } + + return relation->rd_pkindex; +} + /* * RelationGetReplicaIndex -- get OID of the relation's replica identity index * @@ -4275,6 +4649,8 @@ RelationGetIndexExpressions(Relation relation) */ result = (List *) eval_const_expressions(NULL, (Node *) result); + result = (List *) canonicalize_qual((Expr *) result); + /* May as well fix opfuncids too */ fix_opfuncids((Node *) result); @@ -4382,8 +4758,10 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind) { Bitmapset *indexattrs; /* indexed columns */ Bitmapset *uindexattrs; /* columns in unique indexes */ + Bitmapset *pkindexattrs; /* columns in the primary index */ Bitmapset *idindexattrs; /* columns in the replica identity */ List *indexoidlist; + Oid relpkindex; Oid relreplindex; ListCell *l; MemoryContext oldcxt; @@ -4397,6 +4775,8 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind) return bms_copy(relation->rd_indexattr); case INDEX_ATTR_BITMAP_KEY: return bms_copy(relation->rd_keyattr); + case INDEX_ATTR_BITMAP_PRIMARY_KEY: + return bms_copy(relation->rd_pkattr); case INDEX_ATTR_BITMAP_IDENTITY_KEY: return bms_copy(relation->rd_idattr); default: @@ -4418,12 +4798,14 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind) return NULL; /* - * Copy the rd_replidindex value computed by RelationGetIndexList before - * proceeding. This is needed because a relcache flush could occur inside - * index_open below, resetting the fields managed by RelationGetIndexList. - * (The values we're computing will still be valid, assuming that caller - * has a sufficient lock on the relation.) + * Copy the rd_pkindex and rd_replidindex value computed by + * RelationGetIndexList before proceeding. This is needed because a + * relcache flush could occur inside index_open below, resetting the + * fields managed by RelationGetIndexList. (The values we're computing + * will still be valid, assuming that caller has a sufficient lock on + * the relation.) */ + relpkindex = relation->rd_pkindex; relreplindex = relation->rd_replidindex; /* @@ -4438,6 +4820,7 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind) */ indexattrs = NULL; uindexattrs = NULL; + pkindexattrs = NULL; idindexattrs = NULL; foreach(l, indexoidlist) { @@ -4446,6 +4829,7 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind) IndexInfo *indexInfo; int i; bool isKey; /* candidate key */ + bool isPK; /* primary key */ bool isIDKey; /* replica identity index */ indexDesc = index_open(indexOid, AccessShareLock); @@ -4458,6 +4842,9 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind) indexInfo->ii_Expressions == NIL && indexInfo->ii_Predicate == NIL; + /* Is this a primary key? */ + isPK = (indexOid == relpkindex); + /* Is this index the configured (or default) replica identity? */ isIDKey = (indexOid == relreplindex); @@ -4475,6 +4862,10 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind) uindexattrs = bms_add_member(uindexattrs, attrnum - FirstLowInvalidHeapAttributeNumber); + if (isPK) + pkindexattrs = bms_add_member(pkindexattrs, + attrnum - FirstLowInvalidHeapAttributeNumber); + if (isIDKey) idindexattrs = bms_add_member(idindexattrs, attrnum - FirstLowInvalidHeapAttributeNumber); @@ -4497,6 +4888,8 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind) relation->rd_indexattr = NULL; bms_free(relation->rd_keyattr); relation->rd_keyattr = NULL; + bms_free(relation->rd_pkattr); + relation->rd_pkattr = NULL; bms_free(relation->rd_idattr); relation->rd_idattr = NULL; @@ -4509,6 +4902,7 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind) */ oldcxt = MemoryContextSwitchTo(CacheMemoryContext); relation->rd_keyattr = bms_copy(uindexattrs); + relation->rd_pkattr = bms_copy(pkindexattrs); relation->rd_idattr = bms_copy(idindexattrs); relation->rd_indexattr = bms_copy(indexattrs); MemoryContextSwitchTo(oldcxt); @@ -4520,6 +4914,8 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind) return indexattrs; case INDEX_ATTR_BITMAP_KEY: return uindexattrs; + case INDEX_ATTR_BITMAP_PRIMARY_KEY: + return bms_copy(relation->rd_pkattr); case INDEX_ATTR_BITMAP_IDENTITY_KEY: return idindexattrs; default: @@ -4652,6 +5048,67 @@ RelationGetExclusionInfo(Relation indexRelation, MemoryContextSwitchTo(oldcxt); } +/* + * Get publication actions for the given relation. + */ +struct PublicationActions * +GetRelationPublicationActions(Relation relation) +{ + List *puboids; + ListCell *lc; + MemoryContext oldcxt; + PublicationActions *pubactions = palloc0(sizeof(PublicationActions)); + + if (relation->rd_pubactions) + return memcpy(pubactions, relation->rd_pubactions, + sizeof(PublicationActions)); + + /* Fetch the publication membership info. */ + puboids = GetRelationPublications(RelationGetRelid(relation)); + puboids = list_concat_unique_oid(puboids, GetAllTablesPublications()); + + foreach(lc, puboids) + { + Oid pubid = lfirst_oid(lc); + HeapTuple tup; + Form_pg_publication pubform; + + tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid)); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for publication %u", pubid); + + pubform = (Form_pg_publication) GETSTRUCT(tup); + + pubactions->pubinsert |= pubform->pubinsert; + pubactions->pubupdate |= pubform->pubupdate; + pubactions->pubdelete |= pubform->pubdelete; + + ReleaseSysCache(tup); + + /* + * If we know everything is replicated, there is no point to check + * for other publications. + */ + if (pubactions->pubinsert && pubactions->pubupdate && + pubactions->pubdelete) + break; + } + + if (relation->rd_pubactions) + { + pfree(relation->rd_pubactions); + relation->rd_pubactions = NULL; + } + + /* Now save copy of the actions in the relcache entry. */ + oldcxt = MemoryContextSwitchTo(CacheMemoryContext); + relation->rd_pubactions = palloc(sizeof(PublicationActions)); + memcpy(relation->rd_pubactions, pubactions, sizeof(PublicationActions)); + MemoryContextSwitchTo(oldcxt); + + return pubactions; +} /* * Routines to support ereport() reports of relation-related errors @@ -4948,9 +5405,7 @@ load_relcache_init_file(bool shared) */ indexcxt = AllocSetContextCreate(CacheMemoryContext, RelationGetRelationName(rel), - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MAXSIZE); + ALLOCSET_SMALL_SIZES); rel->rd_indexcxt = indexcxt; /* @@ -5045,6 +5500,10 @@ load_relcache_init_file(bool shared) rel->rd_rulescxt = NULL; rel->trigdesc = NULL; rel->rd_rsdesc = NULL; + rel->rd_partkeycxt = NULL; + rel->rd_partkey = NULL; + rel->rd_partdesc = NULL; + rel->rd_partcheck = NIL; rel->rd_indexprs = NIL; rel->rd_indpred = NIL; rel->rd_exclops = NULL; @@ -5065,10 +5524,13 @@ load_relcache_init_file(bool shared) rel->rd_fkeyvalid = false; rel->rd_indexlist = NIL; rel->rd_oidindex = InvalidOid; + rel->rd_pkindex = InvalidOid; rel->rd_replidindex = InvalidOid; rel->rd_indexattr = NULL; rel->rd_keyattr = NULL; + rel->rd_pkattr = NULL; rel->rd_idattr = NULL; + rel->rd_pubactions = NULL; rel->rd_createSubid = InvalidSubTransactionId; rel->rd_newRelfilenodeSubid = InvalidSubTransactionId; rel->rd_amcache = NULL; diff --git a/src/backend/utils/cache/relfilenodemap.c b/src/backend/utils/cache/relfilenodemap.c index 894dacb5e7..c790309caa 100644 --- a/src/backend/utils/cache/relfilenodemap.c +++ b/src/backend/utils/cache/relfilenodemap.c @@ -3,7 +3,7 @@ * relfilenodemap.c * relfilenode to oid mapping cache. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/cache/relmapper.c b/src/backend/utils/cache/relmapper.c index 6a63b5e1d7..c9d6e44d9f 100644 --- a/src/backend/utils/cache/relmapper.c +++ b/src/backend/utils/cache/relmapper.c @@ -28,7 +28,7 @@ * all these files commit in a single map file update rather than being tied * to transaction commit. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/cache/spccache.c b/src/backend/utils/cache/spccache.c index 94e27c8f58..9dcb80cde0 100644 --- a/src/backend/utils/cache/spccache.c +++ b/src/backend/utils/cache/spccache.c @@ -8,7 +8,7 @@ * be a measurable performance gain from doing this, but that might change * in the future as we add more options. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index 65ffe84409..bdfaa0ce75 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -3,7 +3,7 @@ * syscache.c * System cache management routines * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -48,15 +48,20 @@ #include "catalog/pg_opclass.h" #include "catalog/pg_operator.h" #include "catalog/pg_opfamily.h" +#include "catalog/pg_partitioned_table.h" #include "catalog/pg_proc.h" +#include "catalog/pg_publication.h" +#include "catalog/pg_publication_rel.h" #include "catalog/pg_range.h" #include "catalog/pg_rewrite.h" #include "catalog/pg_seclabel.h" +#include "catalog/pg_sequence.h" #include "catalog/pg_shdepend.h" #include "catalog/pg_shdescription.h" #include "catalog/pg_shseclabel.h" #include "catalog/pg_replication_origin.h" #include "catalog/pg_statistic.h" +#include "catalog/pg_subscription.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_transform.h" #include "catalog/pg_ts_config.h" @@ -568,6 +573,17 @@ static const struct cachedesc cacheinfo[] = { }, 8 }, + {PartitionedRelationId, /* PARTRELID */ + PartitionedRelidIndexId, + 1, + { + Anum_pg_partitioned_table_partrelid, + 0, + 0, + 0 + }, + 32 + }, {ProcedureRelationId, /* PROCNAMEARGSNSP */ ProcedureNameArgsNspIndexId, 3, @@ -645,6 +661,50 @@ static const struct cachedesc cacheinfo[] = { }, 16 }, + {PublicationRelationId, /* PUBLICATIONOID */ + PublicationObjectIndexId, + 1, + { + ObjectIdAttributeNumber, + 0, + 0, + 0 + }, + 8 + }, + {PublicationRelationId, /* PUBLICATIONNAME */ + PublicationNameIndexId, + 1, + { + Anum_pg_publication_pubname, + 0, + 0, + 0 + }, + 8 + }, + {PublicationRelRelationId, /* PUBLICATIONREL */ + PublicationRelObjectIndexId, + 1, + { + ObjectIdAttributeNumber, + 0, + 0, + 0 + }, + 64 + }, + {PublicationRelRelationId, /* PUBLICATIONRELMAP */ + PublicationRelMapIndexId, + 2, + { + Anum_pg_publication_rel_prrelid, + Anum_pg_publication_rel_prpubid, + 0, + 0 + }, + 64 + }, {RewriteRelationId, /* RULERELNAME */ RewriteRelRulenameIndexId, 2, @@ -656,6 +716,17 @@ static const struct cachedesc cacheinfo[] = { }, 8 }, + {SequenceRelationId, /* SEQRELID */ + SequenceRelidIndexId, + 1, + { + Anum_pg_sequence_seqrelid, + 0, + 0, + 0 + }, + 32 + }, {StatisticRelationId, /* STATRELATTINH */ StatisticRelidAttnumInhIndexId, 3, @@ -667,6 +738,28 @@ static const struct cachedesc cacheinfo[] = { }, 128 }, + {SubscriptionRelationId, /* SUBSCRIPTIONOID */ + SubscriptionObjectIndexId, + 1, + { + ObjectIdAttributeNumber, + 0, + 0, + 0 + }, + 4 + }, + {SubscriptionRelationId, /* SUBSCRIPTIONNAME */ + SubscriptionNameIndexId, + 2, + { + Anum_pg_subscription_subdbid, + Anum_pg_subscription_subname, + 0, + 0 + }, + 4 + }, {TableSpaceRelationId, /* TABLESPACEOID */ TablespaceOidIndexId, 1, diff --git a/src/backend/utils/cache/ts_cache.c b/src/backend/utils/cache/ts_cache.c index 5e4de431dd..88e4ffb66d 100644 --- a/src/backend/utils/cache/ts_cache.c +++ b/src/backend/utils/cache/ts_cache.c @@ -17,7 +17,7 @@ * any database access. * * - * Copyright (c) 2006-2016, PostgreSQL Global Development Group + * Copyright (c) 2006-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/cache/ts_cache.c @@ -45,6 +45,7 @@ #include "utils/inval.h" #include "utils/lsyscache.h" #include "utils/memutils.h" +#include "utils/regproc.h" #include "utils/syscache.h" #include "utils/tqual.h" @@ -295,9 +296,7 @@ lookup_ts_dictionary_cache(Oid dictId) /* Create private memory context the first time through */ saveCtx = AllocSetContextCreate(CacheMemoryContext, NameStr(dict->dictname), - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MAXSIZE); + ALLOCSET_SMALL_SIZES); } else { diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c index ea6f787a52..6992634c39 100644 --- a/src/backend/utils/cache/typcache.c +++ b/src/backend/utils/cache/typcache.c @@ -30,7 +30,7 @@ * Domain constraint changes are also tracked properly. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -182,10 +182,10 @@ static int enum_oid_cmp(const void *left, const void *right); * Fetch the type cache entry for the specified datatype, and make sure that * all the fields requested by bits in 'flags' are valid. * - * The result is never NULL --- we will elog() if the passed type OID is + * The result is never NULL --- we will ereport() if the passed type OID is * invalid. Note however that we may fail to find one or more of the - * requested opclass-dependent fields; the caller needs to check whether - * the fields are InvalidOid or not. + * values requested by 'flags'; the caller needs to check whether the fields + * are InvalidOid or not. */ TypeCacheEntry * lookup_type_cache(Oid type_id, int flags) @@ -224,14 +224,18 @@ lookup_type_cache(Oid type_id, int flags) /* * If we didn't find one, we want to make one. But first look up the * pg_type row, just to make sure we don't make a cache entry for an - * invalid type OID. + * invalid type OID. If the type OID is not valid, present a + * user-facing error, since some code paths such as domain_in() allow + * this function to be reached with a user-supplied OID. */ HeapTuple tp; Form_pg_type typtup; tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id)); if (!HeapTupleIsValid(tp)) - elog(ERROR, "cache lookup failed for type %u", type_id); + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("type with OID %u does not exist", type_id))); typtup = (Form_pg_type) GETSTRUCT(tp); if (!typtup->typisdefined) ereport(ERROR, @@ -756,9 +760,7 @@ load_domaintype_info(TypeCacheEntry *typentry) cxt = AllocSetContextCreate(CurrentMemoryContext, "Domain constraints", - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_MAXSIZE); + ALLOCSET_SMALL_SIZES); dcc = (DomainConstraintCache *) MemoryContextAlloc(cxt, sizeof(DomainConstraintCache)); dcc->constraints = NIL; @@ -841,9 +843,7 @@ load_domaintype_info(TypeCacheEntry *typentry) cxt = AllocSetContextCreate(CurrentMemoryContext, "Domain constraints", - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_MAXSIZE); + ALLOCSET_SMALL_SIZES); dcc = (DomainConstraintCache *) MemoryContextAlloc(cxt, sizeof(DomainConstraintCache)); dcc->constraints = NIL; @@ -1234,6 +1234,8 @@ lookup_rowtype_tupdesc_internal(Oid type_id, int32 typmod, bool noError) * * Given a typeid/typmod that should describe a known composite type, * return the tuple descriptor for the type. Will ereport on failure. + * (Use ereport because this is reachable with user-specified OIDs, + * for example from record_in().) * * Note: on success, we increment the refcount of the returned TupleDesc, * and log the reference in CurrentResourceOwner. Caller should call diff --git a/src/backend/utils/errcodes.txt b/src/backend/utils/errcodes.txt index be924d58bd..46aadd76f7 100644 --- a/src/backend/utils/errcodes.txt +++ b/src/backend/utils/errcodes.txt @@ -2,7 +2,7 @@ # errcodes.txt # PostgreSQL error codes # -# Copyright (c) 2003-2016, PostgreSQL Global Development Group +# Copyright (c) 2003-2017, PostgreSQL Global Development Group # # This list serves as the basis for generating source files containing error # codes. It is kept in a common format to make sure all these source files have @@ -398,6 +398,7 @@ Section: Class 55 - Object Not In Prerequisite State 55006 E ERRCODE_OBJECT_IN_USE object_in_use 55P02 E ERRCODE_CANT_CHANGE_RUNTIME_PARAM cant_change_runtime_param 55P03 E ERRCODE_LOCK_NOT_AVAILABLE lock_not_available +55P04 E ERRCODE_UNSAFE_NEW_ENUM_VALUE_USAGE unsafe_new_enum_value_usage Section: Class 57 - Operator Intervention diff --git a/src/backend/utils/error/assert.c b/src/backend/utils/error/assert.c index c4b0e007d2..2ef7792b8b 100644 --- a/src/backend/utils/error/assert.c +++ b/src/backend/utils/error/assert.c @@ -3,7 +3,7 @@ * assert.c * Assert code. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index 78d441d198..40e023c7d7 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -43,7 +43,7 @@ * overflow.) * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -79,11 +79,10 @@ #include "utils/ps_status.h" +/* In this module, access gettext() via err_gettext() */ #undef _ #define _(x) err_gettext(x) -static const char *err_gettext(const char *str) pg_attribute_format_arg(1); -static void set_errdata_field(MemoryContextData *cxt, char **ptr, const char *str); /* Global variables */ ErrorContextCallback *error_context_stack = NULL; @@ -129,10 +128,9 @@ static int syslog_facility = LOG_LOCAL0; static void write_syslog(int level, const char *line); #endif -static void write_console(const char *line, int len); - #ifdef WIN32 extern char *event_source; + static void write_eventlog(int level, const char *line, int len); #endif @@ -149,7 +147,6 @@ static int recursion_depth = 0; /* to detect actual recursion */ * Saved timeval and buffers for formatted timestamps that might be used by * both log_line_prefix and csv logs. */ - static struct timeval saved_timeval; static bool saved_timeval_set = false; @@ -169,9 +166,16 @@ static char formatted_log_time[FORMATTED_TS_LEN]; } while (0) +static const char *err_gettext(const char *str) pg_attribute_format_arg(1); +static void set_errdata_field(MemoryContextData *cxt, char **ptr, const char *str); +static void write_console(const char *line, int len); +static void setup_formatted_log_time(void); +static void setup_formatted_start_time(void); static const char *process_log_prefix_padding(const char *p, int *padding); static void log_line_prefix(StringInfo buf, ErrorData *edata); +static void write_csvlog(ErrorData *edata); static void send_message_to_server_log(ErrorData *edata); +static void write_pipe_chunks(char *data, int len, int dest); static void send_message_to_frontend(ErrorData *edata); static char *expand_fmt_string(const char *fmt, ErrorData *edata); static const char *useful_strerror(int errnum); @@ -179,10 +183,6 @@ static const char *get_errno_symbol(int errnum); static const char *error_severity(int elevel); static void append_with_tabs(StringInfo buf, const char *str); static bool is_log_level_output(int elevel, int log_min_level); -static void write_pipe_chunks(char *data, int len, int dest); -static void write_csvlog(ErrorData *edata); -static void setup_formatted_log_time(void); -static void setup_formatted_start_time(void); /* @@ -1601,7 +1601,10 @@ FlushErrorState(void) /* * ThrowErrorData --- report an error described by an ErrorData structure * - * This is intended to be used to re-report errors originally thrown by + * This is somewhat like ReThrowError, but it allows elevels besides ERROR, + * and the boolean flags such as output_to_server are computed via the + * default rules rather than being copied from the given ErrorData. + * This is primarily used to re-report errors originally reported by * background worker processes and then propagated (with or without * modification) to the backend responsible for them. */ @@ -1613,13 +1616,14 @@ ThrowErrorData(ErrorData *edata) if (!errstart(edata->elevel, edata->filename, edata->lineno, edata->funcname, NULL)) - return; + return; /* error is not to be reported at all */ newedata = &errordata[errordata_stack_depth]; - oldcontext = MemoryContextSwitchTo(edata->assoc_context); + recursion_depth++; + oldcontext = MemoryContextSwitchTo(newedata->assoc_context); - /* Copy the supplied fields to the error stack. */ - if (edata->sqlerrcode > 0) + /* Copy the supplied fields to the error stack entry. */ + if (edata->sqlerrcode != 0) newedata->sqlerrcode = edata->sqlerrcode; if (edata->message) newedata->message = pstrdup(edata->message); @@ -1631,6 +1635,7 @@ ThrowErrorData(ErrorData *edata) newedata->hint = pstrdup(edata->hint); if (edata->context) newedata->context = pstrdup(edata->context); + /* assume message_id is not available */ if (edata->schema_name) newedata->schema_name = pstrdup(edata->schema_name); if (edata->table_name) @@ -1641,11 +1646,15 @@ ThrowErrorData(ErrorData *edata) newedata->datatype_name = pstrdup(edata->datatype_name); if (edata->constraint_name) newedata->constraint_name = pstrdup(edata->constraint_name); + newedata->cursorpos = edata->cursorpos; + newedata->internalpos = edata->internalpos; if (edata->internalquery) newedata->internalquery = pstrdup(edata->internalquery); MemoryContextSwitchTo(oldcontext); + recursion_depth--; + /* Process the error. */ errfinish(0); } @@ -2475,8 +2484,9 @@ log_line_prefix(StringInfo buf, ErrorData *edata) saved_timeval_set = true; } - sprintf(strfbuf, "%ld.%03d", saved_timeval.tv_sec, - (int) (saved_timeval.tv_usec / 1000)); + snprintf(strfbuf, sizeof(strfbuf), "%ld.%03d", + (long) saved_timeval.tv_sec, + (int) (saved_timeval.tv_usec / 1000)); if (padding != 0) appendStringInfo(buf, "%*s", padding, strfbuf); @@ -2744,7 +2754,7 @@ write_csvlog(ErrorData *edata) appendStringInfoChar(&buf, ','); /* Error severity */ - appendStringInfoString(&buf, error_severity(edata->elevel)); + appendStringInfoString(&buf, _(error_severity(edata->elevel))); appendStringInfoChar(&buf, ','); /* SQL state code */ @@ -2861,7 +2871,7 @@ send_message_to_server_log(ErrorData *edata) formatted_log_time[0] = '\0'; log_line_prefix(&buf, edata); - appendStringInfo(&buf, "%s: ", error_severity(edata->elevel)); + appendStringInfo(&buf, "%s: ", _(error_severity(edata->elevel))); if (Log_error_verbosity >= PGERROR_VERBOSE) appendStringInfo(&buf, "%s: ", unpack_sql_state(edata->sqlerrcode)); @@ -3144,12 +3154,16 @@ send_message_to_frontend(ErrorData *edata) if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3) { /* New style with separate fields */ + const char *sev; char tbuf[12]; int ssval; int i; + sev = error_severity(edata->elevel); pq_sendbyte(&msgbuf, PG_DIAG_SEVERITY); - err_sendstring(&msgbuf, error_severity(edata->elevel)); + err_sendstring(&msgbuf, _(sev)); + pq_sendbyte(&msgbuf, PG_DIAG_SEVERITY_NONLOCALIZED); + err_sendstring(&msgbuf, sev); /* unpack MAKE_SQLSTATE code */ ssval = edata->sqlerrcode; @@ -3268,7 +3282,7 @@ send_message_to_frontend(ErrorData *edata) initStringInfo(&buf); - appendStringInfo(&buf, "%s: ", error_severity(edata->elevel)); + appendStringInfo(&buf, "%s: ", _(error_severity(edata->elevel))); if (edata->show_funcname && edata->funcname) appendStringInfo(&buf, "%s: ", edata->funcname); @@ -3578,7 +3592,10 @@ get_errno_symbol(int errnum) /* - * error_severity --- get localized string representing elevel + * error_severity --- get string representing elevel + * + * The string is not localized here, but we mark the strings for translation + * so that callers can invoke _() on the result. */ static const char * error_severity(int elevel) @@ -3592,29 +3609,29 @@ error_severity(int elevel) case DEBUG3: case DEBUG4: case DEBUG5: - prefix = _("DEBUG"); + prefix = gettext_noop("DEBUG"); break; case LOG: case LOG_SERVER_ONLY: - prefix = _("LOG"); + prefix = gettext_noop("LOG"); break; case INFO: - prefix = _("INFO"); + prefix = gettext_noop("INFO"); break; case NOTICE: - prefix = _("NOTICE"); + prefix = gettext_noop("NOTICE"); break; case WARNING: - prefix = _("WARNING"); + prefix = gettext_noop("WARNING"); break; case ERROR: - prefix = _("ERROR"); + prefix = gettext_noop("ERROR"); break; case FATAL: - prefix = _("FATAL"); + prefix = gettext_noop("FATAL"); break; case PANIC: - prefix = _("PANIC"); + prefix = gettext_noop("PANIC"); break; default: prefix = "???"; diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c index f41035d33c..94d7dac94c 100644 --- a/src/backend/utils/fmgr/dfmgr.c +++ b/src/backend/utils/fmgr/dfmgr.c @@ -3,7 +3,7 @@ * dfmgr.c * Dynamic function manager code. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -65,7 +65,7 @@ char *Dynamic_library_path; static void *internal_load_library(const char *libname); static void incompatible_module_error(const char *libname, - const Pg_magic_struct *module_magic_data); + const Pg_magic_struct *module_magic_data) pg_attribute_noreturn(); static void internal_unload_library(const char *libname); static bool file_exists(const char *name); static char *expand_dynamic_library_name(const char *name); @@ -300,14 +300,22 @@ incompatible_module_error(const char *libname, * block might not even have the fields we expect. */ if (magic_data.version != module_magic_data->version) + { + char library_version[32]; + + if (module_magic_data->version >= 1000) + snprintf(library_version, sizeof(library_version), "%d", + module_magic_data->version / 100); + else + snprintf(library_version, sizeof(library_version), "%d.%d", + module_magic_data->version / 100, + module_magic_data->version % 100); ereport(ERROR, (errmsg("incompatible library \"%s\": version mismatch", libname), - errdetail("Server is version %d.%d, library is version %d.%d.", - magic_data.version / 100, - magic_data.version % 100, - module_magic_data->version / 100, - module_magic_data->version % 100))); + errdetail("Server is version %d, library is version %s.", + magic_data.version / 100, library_version))); + } /* * Otherwise, spell out which fields don't agree. diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c index 7e6a60d624..3976496aef 100644 --- a/src/backend/utils/fmgr/fmgr.c +++ b/src/backend/utils/fmgr/fmgr.c @@ -3,7 +3,7 @@ * fmgr.c * The Postgres function manager. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -19,7 +19,6 @@ #include "catalog/pg_language.h" #include "catalog/pg_proc.h" #include "executor/functions.h" -#include "executor/spi.h" #include "lib/stringinfo.h" #include "miscadmin.h" #include "nodes/nodeFuncs.h" @@ -1878,25 +1877,16 @@ OidFunctionCall9Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, * the caller should assume the result is NULL, but we'll call the input * function anyway if it's not strict. So this is almost but not quite * the same as FunctionCall3. - * - * One important difference from the bare function call is that we will - * push any active SPI context, allowing SPI-using I/O functions to be - * called from other SPI functions without extra notation. This is a hack, - * but the alternative of expecting all SPI functions to do SPI_push/SPI_pop - * around I/O calls seems worse. */ Datum InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod) { FunctionCallInfoData fcinfo; Datum result; - bool pushed; if (str == NULL && flinfo->fn_strict) return (Datum) 0; /* just return null result */ - pushed = SPI_push_conditional(); - InitFunctionCallInfoData(fcinfo, flinfo, 3, InvalidOid, NULL, NULL); fcinfo.arg[0] = CStringGetDatum(str); @@ -1922,8 +1912,6 @@ InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod) fcinfo.flinfo->fn_oid); } - SPI_pop_conditional(pushed); - return result; } @@ -1932,22 +1920,12 @@ InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod) * * Do not call this on NULL datums. * - * This is almost just window dressing for FunctionCall1, but it includes - * SPI context pushing for the same reasons as InputFunctionCall. + * This is currently little more than window dressing for FunctionCall1. */ char * OutputFunctionCall(FmgrInfo *flinfo, Datum val) { - char *result; - bool pushed; - - pushed = SPI_push_conditional(); - - result = DatumGetCString(FunctionCall1(flinfo, val)); - - SPI_pop_conditional(pushed); - - return result; + return DatumGetCString(FunctionCall1(flinfo, val)); } /* @@ -1956,8 +1934,7 @@ OutputFunctionCall(FmgrInfo *flinfo, Datum val) * "buf" may be NULL to indicate we are reading a NULL. In this case * the caller should assume the result is NULL, but we'll call the receive * function anyway if it's not strict. So this is almost but not quite - * the same as FunctionCall3. Also, this includes SPI context pushing for - * the same reasons as InputFunctionCall. + * the same as FunctionCall3. */ Datum ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf, @@ -1965,13 +1942,10 @@ ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf, { FunctionCallInfoData fcinfo; Datum result; - bool pushed; if (buf == NULL && flinfo->fn_strict) return (Datum) 0; /* just return null result */ - pushed = SPI_push_conditional(); - InitFunctionCallInfoData(fcinfo, flinfo, 3, InvalidOid, NULL, NULL); fcinfo.arg[0] = PointerGetDatum(buf); @@ -1997,8 +1971,6 @@ ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf, fcinfo.flinfo->fn_oid); } - SPI_pop_conditional(pushed); - return result; } @@ -2009,22 +1981,12 @@ ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf, * * This is little more than window dressing for FunctionCall1, but it does * guarantee a non-toasted result, which strictly speaking the underlying - * function doesn't. Also, this includes SPI context pushing for the same - * reasons as InputFunctionCall. + * function doesn't. */ bytea * SendFunctionCall(FmgrInfo *flinfo, Datum val) { - bytea *result; - bool pushed; - - pushed = SPI_push_conditional(); - - result = DatumGetByteaP(FunctionCall1(flinfo, val)); - - SPI_pop_conditional(pushed); - - return result; + return DatumGetByteaP(FunctionCall1(flinfo, val)); } /* @@ -2126,10 +2088,7 @@ fmgr(Oid procedureId,...) * * int8, float4, and float8 can be passed by value if Datum is wide enough. * (For backwards-compatibility reasons, we allow pass-by-ref to be chosen - * at compile time even if pass-by-val is possible.) For the float types, - * we need a support routine even if we are passing by value, because many - * machines pass int and float function parameters/results differently; - * so we need to play weird games with unions. + * at compile time even if pass-by-val is possible.) * * Note: there is only one switch controlling the pass-by-value option for * both int8 and float8; this is to avoid making things unduly complicated @@ -2149,77 +2108,29 @@ Int64GetDatum(int64 X) } #endif /* USE_FLOAT8_BYVAL */ +#ifndef USE_FLOAT4_BYVAL + Datum Float4GetDatum(float4 X) { -#ifdef USE_FLOAT4_BYVAL - union - { - float4 value; - int32 retval; - } myunion; - - myunion.value = X; - return SET_4_BYTES(myunion.retval); -#else float4 *retval = (float4 *) palloc(sizeof(float4)); *retval = X; return PointerGetDatum(retval); -#endif } +#endif -#ifdef USE_FLOAT4_BYVAL - -float4 -DatumGetFloat4(Datum X) -{ - union - { - int32 value; - float4 retval; - } myunion; - - myunion.value = GET_4_BYTES(X); - return myunion.retval; -} -#endif /* USE_FLOAT4_BYVAL */ +#ifndef USE_FLOAT8_BYVAL Datum Float8GetDatum(float8 X) { -#ifdef USE_FLOAT8_BYVAL - union - { - float8 value; - int64 retval; - } myunion; - - myunion.value = X; - return SET_8_BYTES(myunion.retval); -#else float8 *retval = (float8 *) palloc(sizeof(float8)); *retval = X; return PointerGetDatum(retval); -#endif } - -#ifdef USE_FLOAT8_BYVAL - -float8 -DatumGetFloat8(Datum X) -{ - union - { - int64 value; - float8 retval; - } myunion; - - myunion.value = GET_8_BYTES(X); - return myunion.retval; -} -#endif /* USE_FLOAT8_BYVAL */ +#endif /*------------------------------------------------------------------------- @@ -2506,10 +2417,15 @@ CheckFunctionValidatorAccess(Oid validatorOid, Oid functionOid) Form_pg_language langStruct; AclResult aclresult; - /* Get the function's pg_proc entry */ + /* + * Get the function's pg_proc entry. Throw a user-facing error for bad + * OID, because validators can be called with user-specified OIDs. + */ procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionOid)); if (!HeapTupleIsValid(procTup)) - elog(ERROR, "cache lookup failed for function %u", functionOid); + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("function with OID %u does not exist", functionOid))); procStruct = (Form_pg_proc) GETSTRUCT(procTup); /* diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c index 5d179ae8a8..c55da54878 100644 --- a/src/backend/utils/fmgr/funcapi.c +++ b/src/backend/utils/fmgr/funcapi.c @@ -4,7 +4,7 @@ * Utility and convenience functions for fmgr functions that return * sets and/or composite types. * - * Copyright (c) 2002-2016, PostgreSQL Global Development Group + * Copyright (c) 2002-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/fmgr/funcapi.c @@ -24,6 +24,7 @@ #include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/memutils.h" +#include "utils/regproc.h" #include "utils/rel.h" #include "utils/syscache.h" #include "utils/typcache.h" @@ -73,9 +74,7 @@ init_MultiFuncCall(PG_FUNCTION_ARGS) */ multi_call_ctx = AllocSetContextCreate(fcinfo->flinfo->fn_mcxt, "SRF multi-call context", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MAXSIZE); + ALLOCSET_SMALL_SIZES); /* * Allocate suitably long-lived space and zero it diff --git a/src/backend/utils/generate-errcodes.pl b/src/backend/utils/generate-errcodes.pl index ad9c6b9bd3..b84c6b0d0f 100644 --- a/src/backend/utils/generate-errcodes.pl +++ b/src/backend/utils/generate-errcodes.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl # # Generate the errcodes.h header from errcodes.txt -# Copyright (c) 2000-2016, PostgreSQL Global Development Group +# Copyright (c) 2000-2017, PostgreSQL Global Development Group use warnings; use strict; diff --git a/src/backend/utils/hash/dynahash.c b/src/backend/utils/hash/dynahash.c index d35052aea6..d370b72719 100644 --- a/src/backend/utils/hash/dynahash.c +++ b/src/backend/utils/hash/dynahash.c @@ -40,7 +40,7 @@ * function must be supplied; comparison defaults to memcmp() and key copying * to memcpy() when a user-defined hashing function is selected. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -327,9 +327,7 @@ hash_create(const char *tabname, long nelem, HASHCTL *info, int flags) CurrentDynaHashCxt = TopMemoryContext; CurrentDynaHashCxt = AllocSetContextCreate(CurrentDynaHashCxt, tabname, - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); } /* Initialize the hash header, plus a copy of the table name */ diff --git a/src/backend/utils/hash/hashfn.c b/src/backend/utils/hash/hashfn.c index d8322863e3..9a93c089a6 100644 --- a/src/backend/utils/hash/hashfn.c +++ b/src/backend/utils/hash/hashfn.c @@ -4,7 +4,7 @@ * Hash functions for use in dynahash.c hashtables * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/hash/pg_crc.c b/src/backend/utils/hash/pg_crc.c index 69dd456899..9dc6c9dcc9 100644 --- a/src/backend/utils/hash/pg_crc.c +++ b/src/backend/utils/hash/pg_crc.c @@ -7,7 +7,7 @@ * A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS, available from * http://www.ross.net/crc/download/crc_v3.txt or several other net sites. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c index f23208353c..08b6030a64 100644 --- a/src/backend/utils/init/globals.c +++ b/src/backend/utils/init/globals.c @@ -3,7 +3,7 @@ * globals.c * global variable declarations * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -38,7 +38,7 @@ volatile uint32 CritSectionCount = 0; int MyProcPid; pg_time_t MyStartTime; struct Port *MyProcPort; -long MyCancelKey; +int32 MyCancelKey; int MyPMChildSlot; /* @@ -122,6 +122,7 @@ int replacement_sort_tuples = 150000; int NBuffers = 1000; int MaxConnections = 90; int max_worker_processes = 8; +int max_parallel_workers = 8; int MaxBackends = 0; int VacuumCostPageHit = 1; /* GUC parameters for vacuum */ diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index d4625a6238..e984e79c60 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -3,7 +3,7 @@ * miscinit.c * miscellaneous initialization support stuff * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -48,6 +48,7 @@ #include "utils/guc.h" #include "utils/memutils.h" #include "utils/syscache.h" +#include "utils/varlena.h" #define DIRECTORY_LOCK_FILE "postmaster.pid" @@ -1334,16 +1335,13 @@ ValidatePgVersion(const char *path) char full_path[MAXPGPATH]; FILE *file; int ret; - long file_major, - file_minor; - long my_major = 0, - my_minor = 0; + long file_major; + long my_major; char *endptr; - const char *version_string = PG_VERSION; + char file_version_string[64]; + const char *my_version_string = PG_VERSION; - my_major = strtol(version_string, &endptr, 10); - if (*endptr == '.') - my_minor = strtol(endptr + 1, NULL, 10); + my_major = strtol(my_version_string, &endptr, 10); snprintf(full_path, sizeof(full_path), "%s/PG_VERSION", path); @@ -1362,8 +1360,11 @@ ValidatePgVersion(const char *path) errmsg("could not open file \"%s\": %m", full_path))); } - ret = fscanf(file, "%ld.%ld", &file_major, &file_minor); - if (ret != 2) + file_version_string[0] = '\0'; + ret = fscanf(file, "%63s", file_version_string); + file_major = strtol(file_version_string, &endptr, 10); + + if (ret != 1 || endptr == file_version_string) ereport(FATAL, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("\"%s\" is not a valid data directory", @@ -1374,13 +1375,13 @@ ValidatePgVersion(const char *path) FreeFile(file); - if (my_major != file_major || my_minor != file_minor) + if (my_major != file_major) ereport(FATAL, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("database files are incompatible with server"), - errdetail("The data directory was initialized by PostgreSQL version %ld.%ld, " + errdetail("The data directory was initialized by PostgreSQL version %s, " "which is not compatible with this version %s.", - file_major, file_minor, version_string))); + file_version_string, my_version_string))); } /*------------------------------------------------------------------------- diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index d17197267e..21fdc6df6b 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -3,7 +3,7 @@ * postinit.c * postgres initialization utilities * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -201,9 +201,7 @@ PerformAuthentication(Port *port) if (PostmasterContext == NULL) PostmasterContext = AllocSetContextCreate(TopMemoryContext, "Postmaster", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); if (!load_hba()) { diff --git a/src/backend/utils/mb/Unicode/Makefile b/src/backend/utils/mb/Unicode/Makefile index 40065c3fbb..d9ea1af527 100644 --- a/src/backend/utils/mb/Unicode/Makefile +++ b/src/backend/utils/mb/Unicode/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/backend/utils/mb/Unicode # -# Copyright (c) 2001-2016, PostgreSQL Global Development Group +# Copyright (c) 2001-2017, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/Makefile # @@ -39,8 +39,6 @@ WINMAPS = win866_to_utf8.map utf8_to_win866.map \ win1258_to_utf8.map utf8_to_win1258.map GENERICMAPS = $(ISO8859MAPS) $(WINMAPS) \ - johab_to_utf8.map utf8_to_johab.map \ - uhc_to_utf8.map utf8_to_uhc.map \ gbk_to_utf8.map utf8_to_gbk.map \ koi8r_to_utf8.map utf8_to_koi8r.map @@ -51,6 +49,8 @@ SPECIALMAPS = euc_cn_to_utf8.map utf8_to_euc_cn.map \ sjis_to_utf8.map utf8_to_sjis.map \ gb18030_to_utf8.map utf8_to_gb18030.map \ big5_to_utf8.map utf8_to_big5.map \ + johab_to_utf8.map utf8_to_johab.map \ + uhc_to_utf8.map utf8_to_uhc.map \ euc_jis_2004_to_utf8.map euc_jis_2004_to_utf8_combined.map \ utf8_to_euc_jis_2004.map utf8_to_euc_jis_2004_combined.map \ shift_jis_2004_to_utf8.map shift_jis_2004_to_utf8_combined.map \ @@ -63,23 +63,29 @@ ISO8859TEXTS = 8859-2.TXT 8859-3.TXT 8859-4.TXT 8859-5.TXT \ 8859-10.TXT 8859-13.TXT 8859-14.TXT 8859-15.TXT \ 8859-16.TXT -WINTEXTS = CP866.TXT CP874.TXT CP936.TXT CP949.TXT \ +WINTEXTS = CP866.TXT CP874.TXT CP936.TXT \ CP1250.TXT CP1251.TXT \ CP1252.TXT CP1253.TXT CP1254.TXT CP1255.TXT \ CP1256.TXT CP1257.TXT CP1258.TXT GENERICTEXTS = $(ISO8859TEXTS) $(WINTEXTS) \ - KOI8-R.TXT KOI8-U.TXT JOHAB.TXT + KOI8-R.TXT KOI8-U.TXT all: $(MAPS) $(GENERICMAPS): UCS_to_most.pl $(GENERICTEXTS) $(PERL) $< -euc_jp_to_utf8.map utf8_to_euc_jp.map: UCS_to_EUC_JP.pl JIS0201.TXT JIS0208.TXT JIS0212.TXT +johab_to_utf8.map utf8_to_johab.map: UCS_to_JOHAB.pl JOHAB.TXT + $(PERL) $< + +uhc_to_utf8.map utf8_to_uhc.map: UCS_to_UHC.pl windows-949-2000.xml + $(PERL) $< + +euc_jp_to_utf8.map utf8_to_euc_jp.map: UCS_to_EUC_JP.pl CP932.TXT JIS0212.TXT $(PERL) $< -euc_cn_to_utf8.map utf8_to_euc_cn.map: UCS_to_EUC_CN.pl GB2312.TXT +euc_cn_to_utf8.map utf8_to_euc_cn.map: UCS_to_EUC_CN.pl gb-18030-2000.xml $(PERL) $< euc_kr_to_utf8.map utf8_to_euc_kr.map: UCS_to_EUC_KR.pl KSX1001.TXT @@ -108,3 +114,37 @@ distclean: clean maintainer-clean: distclean rm -f $(MAPS) + + +DOWNLOAD = wget -O $@ --no-use-server-timestamps +#DOWNLOAD = curl -o $@ + +BIG5.TXT CNS11643.TXT: + $(DOWNLOAD) http://ftp.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/OTHER/$(@F) + +euc-jis-2004-std.txt sjis-0213-2004-std.txt: + $(DOWNLOAD) http://x0213.org/codetable/$(@F) + +gb-18030-2000.xml windows-949-2000.xml: + $(DOWNLOAD) https://ssl.icu-project.org/repos/icu/data/trunk/charset/data/xml/$(@F) + +GB2312.TXT: + $(DOWNLOAD) 'http://trac.greenstone.org/browser/trunk/gsdl/unicode/MAPPINGS/EASTASIA/GB/GB2312.TXT?rev=1842&format=txt' + +JIS0201.TXT JIS0208.TXT JIS0212.TXT: + $(DOWNLOAD) http://ftp.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/JIS/$(@F) + +JOHAB.TXT KSX1001.TXT: + $(DOWNLOAD) http://ftp.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/KSC/$(@F) + +KOI8-R.TXT KOI8-U.TXT: + $(DOWNLOAD) http://ftp.unicode.org/Public/MAPPINGS/VENDORS/MISC/$(@F) + +$(ISO8859TEXTS): + $(DOWNLOAD) http://ftp.unicode.org/Public/MAPPINGS/ISO8859/$(@F) + +$(filter-out CP8%,$(WINTEXTS)) CP932.TXT CP950.TXT: + $(DOWNLOAD) http://ftp.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/$(@F) + +$(filter CP8%,$(WINTEXTS)): + $(DOWNLOAD) http://ftp.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/$(@F) diff --git a/src/backend/utils/mb/Unicode/UCS_to_BIG5.pl b/src/backend/utils/mb/Unicode/UCS_to_BIG5.pl index 127fd157b0..20f6c70854 100755 --- a/src/backend/utils/mb/Unicode/UCS_to_BIG5.pl +++ b/src/backend/utils/mb/Unicode/UCS_to_BIG5.pl @@ -1,6 +1,6 @@ #! /usr/bin/perl # -# Copyright (c) 2001-2016, PostgreSQL Global Development Group +# Copyright (c) 2001-2017, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/UCS_to_BIG5.pl # @@ -24,147 +24,18 @@ # UCS-2 code in hex # # and Unicode name (not used in this script) +use strict; +require convutils; -require "ucs2utf.pl"; +# Load BIG5.TXT +my $all = &read_source("BIG5.TXT"); +# Load CP950.TXT +my $cp950txt = &read_source("CP950.TXT"); -# -# first, generate UTF8 --> BIG5 table -# -$in_file = "BIG5.TXT"; - -open(FILE, $in_file) || die("cannot open $in_file"); - -reset 'array'; - -while () -{ - chop; - if (/^#/) - { - next; - } - ($c, $u, $rest) = split; - $ucs = hex($u); - $code = hex($c); - if ($code >= 0x80 && $ucs >= 0x0080) - { - $utf = &ucs2utf($ucs); - if ($array{$utf} ne "") - { - printf STDERR "Warning: duplicate UTF8: %04x\n", $ucs; - next; - } - $count++; - $array{$utf} = $code; - } -} -close(FILE); - -$in_file = "CP950.TXT"; - -open(FILE, $in_file) || die("cannot open $in_file"); - -while () -{ - chop; - if (/^#/) - { - next; - } - ($c, $u, $rest) = split; - $ucs = hex($u); - $code = hex($c); - - # Pick only the ETEN extended characters in the range 0xf9d6 - 0xf9dc - # from CP950.TXT - if ( $code >= 0x80 - && $ucs >= 0x0080 - && $code >= 0xf9d6 - && $code <= 0xf9dc) - { - $utf = &ucs2utf($ucs); - if ($array{$utf} ne "") - { - printf STDERR "Warning: duplicate UTF8: %04x\n", $ucs; - next; - } - $count++; - $array{$utf} = $code; - } -} -close(FILE); - -$file = lc("utf8_to_big5.map"); -open(FILE, "> $file") || die("cannot open $file"); - -print FILE "/* src/backend/utils/mb/Unicode/$file */\n\n"; -print FILE "static const pg_utf_to_local ULmapBIG5[ $count ] = {\n"; - -for $index (sort { $a <=> $b } keys(%array)) -{ - $code = $array{$index}; - $count--; - if ($count == 0) - { - printf FILE " {0x%04x, 0x%04x}\n", $index, $code; - } - else - { - printf FILE " {0x%04x, 0x%04x},\n", $index, $code; - } -} - -print FILE "};\n"; -close(FILE); - -# -# then generate BIG5 --> UTF8 table -# -$in_file = "BIG5.TXT"; - -open(FILE, $in_file) || die("cannot open $in_file"); - -reset 'array'; - -while () -{ - chop; - if (/^#/) - { - next; - } - ($c, $u, $rest) = split; - $ucs = hex($u); - $code = hex($c); - if ($code >= 0x80 && $ucs >= 0x0080) - { - $utf = &ucs2utf($ucs); - if ($array{$utf} ne "") - { - printf STDERR "Warning: duplicate UTF8: %04x\n", $ucs; - next; - } - $count++; - $array{$code} = $utf; - } -} -close(FILE); - -$in_file = "CP950.TXT"; - -open(FILE, $in_file) || die("cannot open $in_file"); - -while () -{ - chop; - if (/^#/) - { - next; - } - ($c, $u, $rest) = split; - $ucs = hex($u); - $code = hex($c); +foreach my $i (@$cp950txt) { + my $code = $i->{code}; + my $ucs = $i->{ucs}; # Pick only the ETEN extended characters in the range 0xf9d6 - 0xf9dc # from CP950.TXT @@ -173,36 +44,25 @@ && $code >= 0xf9d6 && $code <= 0xf9dc) { - $utf = &ucs2utf($ucs); - if ($array{$utf} ne "") - { - printf STDERR "Warning: duplicate UTF8: %04x\n", $ucs; - next; - } - $count++; - $array{$code} = $utf; + push @$all, {code => $code, + ucs => $ucs, + comment => $i->{comment}, + direction => "both"}; } } -close(FILE); -$file = lc("big5_to_utf8.map"); -open(FILE, "> $file") || die("cannot open $file"); +foreach my $i (@$all) { + my $code = $i->{code}; + my $ucs = $i->{ucs}; -print FILE "/* src/backend/utils/mb/Unicode/$file */\n\n"; -print FILE "static const pg_local_to_utf LUmapBIG5[ $count ] = {\n"; -for $index (sort { $a <=> $b } keys(%array)) -{ - $utf = $array{$index}; - $count--; - if ($count == 0) - { - printf FILE " {0x%04x, 0x%04x}\n", $index, $utf; - } - else + # BIG5.TXT maps several BIG5 characters to U+FFFD. The UTF-8 to BIG5 mapping can + # contain only one of them. XXX: Doesn't really make sense to include any of them, + # but for historical reasons, we map the first one of them. + if ($i->{ucs} == 0xFFFD && $i->{code} != 0xA15A) { - printf FILE " {0x%04x, 0x%04x},\n", $index, $utf; + $i->{direction} = "to_unicode"; } } -print FILE "};\n"; -close(FILE); +# Output +print_tables("BIG5", $all); diff --git a/src/backend/utils/mb/Unicode/UCS_to_EUC_CN.pl b/src/backend/utils/mb/Unicode/UCS_to_EUC_CN.pl index 53f44773c9..7566104f33 100755 --- a/src/backend/utils/mb/Unicode/UCS_to_EUC_CN.pl +++ b/src/backend/utils/mb/Unicode/UCS_to_EUC_CN.pl @@ -1,128 +1,76 @@ #! /usr/bin/perl # -# Copyright (c) 2001-2016, PostgreSQL Global Development Group +# Copyright (c) 2007-2017, PostgreSQL Global Development Group # -# src/backend/utils/mb/Unicode/UCS_to_EUC_CN.pl +# src/backend/utils/mb/Unicode/UCS_to_GB18030.pl # -# Generate UTF-8 <--> EUC_CN code conversion tables from -# map files provided by Unicode organization. -# Unfortunately it is prohibited by the organization -# to distribute the map files. So if you try to use this script, -# you have to obtain GB2312.TXT from -# the organization's ftp site. +# Generate UTF-8 <--> GB18030 code conversion tables from +# "gb-18030-2000.xml", obtained from +# http://source.icu-project.org/repos/icu/data/trunk/charset/data/xml/ # -# GB2312.TXT format: -# GB2312 code in hex -# UCS-2 code in hex -# # and Unicode name (not used in this script) +# The lines we care about in the source file look like +# +# where the "u" field is the Unicode code point in hex, +# and the "b" field is the hex byte sequence for GB18030 -require "ucs2utf.pl"; +use strict; +require convutils; -# first generate UTF-8 --> EUC_CN table +# Read the input -$in_file = "GB2312.TXT"; +my $in_file = "gb-18030-2000.xml"; -open(FILE, $in_file) || die("cannot open $in_file"); +open(my $in, '<', $in_file) || die("cannot open $in_file"); -while () -{ - chop; - if (/^#/) - { - next; - } - ($c, $u, $rest) = split; - $ucs = hex($u); - $code = hex($c); - if ($code >= 0x80 && $ucs >= 0x0080) - { - $utf = &ucs2utf($ucs); - if ($array{$utf} ne "") - { - printf STDERR "Warning: duplicate UTF8: %04x\n", $ucs; - next; - } - $count++; - - $array{$utf} = ($code | 0x8080); - } -} -close(FILE); - -$file = "utf8_to_euc_cn.map"; -open(FILE, "> $file") || die("cannot open $file"); - -print FILE "/* src/backend/utils/mb/Unicode/$file */\n\n"; -print FILE "static const pg_utf_to_local ULmapEUC_CN[ $count ] = {\n"; - -for $index (sort { $a <=> $b } keys(%array)) -{ - $code = $array{$index}; - $count--; - if ($count == 0) - { - printf FILE " {0x%04x, 0x%04x}\n", $index, $code; - } - else - { - printf FILE " {0x%04x, 0x%04x},\n", $index, $code; - } -} - -print FILE "};\n"; -close(FILE); - -# -# then generate EUC_CN --> UTF8 table -# -reset 'array'; - -open(FILE, $in_file) || die("cannot open $in_file"); +my @mapping; -while () +while (<$in>) { - chop; - if (/^#/) + next if (!m/= 0xA100 && $code <= 0xA9FF || + $code >= 0xB000 && $code <= 0xF7FF)); + + next if ($code >= 0xA2A1 && $code <= 0xA2B0); + next if ($code >= 0xA2E3 && $code <= 0xA2E4); + next if ($code >= 0xA2EF && $code <= 0xA2F0); + next if ($code >= 0xA2FD && $code <= 0xA2FE); + next if ($code >= 0xA4F4 && $code <= 0xA4FE); + next if ($code >= 0xA5F7 && $code <= 0xA5FE); + next if ($code >= 0xA6B9 && $code <= 0xA6C0); + next if ($code >= 0xA6D9 && $code <= 0xA6FE); + next if ($code >= 0xA7C2 && $code <= 0xA7D0); + next if ($code >= 0xA7F2 && $code <= 0xA7FE); + next if ($code >= 0xA8BB && $code <= 0xA8C4); + next if ($code >= 0xA8EA && $code <= 0xA8FE); + next if ($code >= 0xA9A1 && $code <= 0xA9A3); + next if ($code >= 0xA9F0 && $code <= 0xA9FE); + next if ($code >= 0xD7FA && $code <= 0xD7FE); + + # A couple of characters are mapped differently from GB-2312 or GB-18030 + if ($code == 0xA1A4) { - next; + $ucs = 0x30FB; } - ($c, $u, $rest) = split; - $ucs = hex($u); - $code = hex($c); - if ($code >= 0x80 && $ucs >= 0x0080) + if ($code == 0xA1AA) { - $utf = &ucs2utf($ucs); - if ($array{$code} ne "") - { - printf STDERR "Warning: duplicate code: %04x\n", $ucs; - next; - } - $count++; - - $code |= 0x8080; - $array{$code} = $utf; + $ucs = 0x2015; } -} -close(FILE); -$file = "euc_cn_to_utf8.map"; -open(FILE, "> $file") || die("cannot open $file"); - -print FILE "/* src/backend/utils/mb/Unicode/$file */\n\n"; -print FILE "static const pg_local_to_utf LUmapEUC_CN[ $count ] = {\n"; -for $index (sort { $a <=> $b } keys(%array)) -{ - $utf = $array{$index}; - $count--; - if ($count == 0) - { - printf FILE " {0x%04x, 0x%04x}\n", $index, $utf; - } - else - { - printf FILE " {0x%04x, 0x%04x},\n", $index, $utf; + push @mapping, { + ucs => $ucs, + code => $code, + direction => 'both' } } +close($in); -print FILE "};\n"; -close(FILE); +print_tables("EUC_CN", \@mapping); diff --git a/src/backend/utils/mb/Unicode/UCS_to_EUC_JIS_2004.pl b/src/backend/utils/mb/Unicode/UCS_to_EUC_JIS_2004.pl index d2f1b757cb..cbe2a1ec11 100755 --- a/src/backend/utils/mb/Unicode/UCS_to_EUC_JIS_2004.pl +++ b/src/backend/utils/mb/Unicode/UCS_to_EUC_JIS_2004.pl @@ -1,305 +1,53 @@ #! /usr/bin/perl # -# Copyright (c) 2007-2016, PostgreSQL Global Development Group +# Copyright (c) 2007-2017, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/UCS_to_EUC_JIS_2004.pl # # Generate UTF-8 <--> EUC_JIS_2004 code conversion tables from # "euc-jis-2004-std.txt" (http://x0213.org) -require "ucs2utf.pl"; - -$TEST = 0; +use strict; +require convutils; # first generate UTF-8 --> EUC_JIS_2004 table -$in_file = "euc-jis-2004-std.txt"; +my $in_file = "euc-jis-2004-std.txt"; -open(FILE, $in_file) || die("cannot open $in_file"); +open(my $in, '<', $in_file) || die("cannot open $in_file"); -reset 'array'; -reset 'array1'; -reset 'comment'; -reset 'comment1'; +my @all; -while ($line = ) +while (my $line = <$in>) { if ($line =~ /^0x(.*)[ \t]*U\+(.*)\+(.*)[ \t]*#(.*)$/) { - $c = $1; - $u1 = $2; - $u2 = $3; - $rest = "U+" . $u1 . "+" . $u2 . $4; - $code = hex($c); - $ucs = hex($u1); - $utf1 = &ucs2utf($ucs); - $ucs = hex($u2); - $utf2 = &ucs2utf($ucs); - $str = sprintf "%08x%08x", $utf1, $utf2; - $array1{$str} = $code; - $comment1{$str} = $rest; - $count1++; + # combined characters + my ($c, $u1, $u2) = ($1, $2, $3); + my $rest = "U+" . $u1 . "+" . $u2 . $4; + my $code = hex($c); + my $ucs1 = hex($u1); + my $ucs2 = hex($u2); + + push @all, { direction => 'both', + ucs => $ucs1, + ucs_second => $ucs2, + code => $code, + comment => $rest }; next; } elsif ($line =~ /^0x(.*)[ \t]*U\+(.*)[ \t]*#(.*)$/) { - $c = $1; - $u = $2; - $rest = "U+" . $u . $3; - } - else - { - next; - } - - $ucs = hex($u); - $code = hex($c); - $utf = &ucs2utf($ucs); - if ($array{$utf} ne "") - { - printf STDERR "Warning: duplicate UTF8: %04x\n", $ucs; - next; - } - $count++; - - $array{$utf} = $code; - $comment{$code} = $rest; -} -close(FILE); - -$file = "utf8_to_euc_jis_2004.map"; -open(FILE, "> $file") || die("cannot open $file"); -print FILE "/*\n"; -print FILE " * This file was generated by UCS_to_EUC_JIS_2004.pl\n"; -print FILE " */\n"; -print FILE "static const pg_utf_to_local ULmapEUC_JIS_2004[] = {\n"; - -for $index (sort { $a <=> $b } keys(%array)) -{ - $code = $array{$index}; - $count--; - if ($count == 0) - { - printf FILE " {0x%08x, 0x%06x} /* %s */\n", $index, $code, - $comment{$code}; - } - else - { - printf FILE " {0x%08x, 0x%06x}, /* %s */\n", $index, $code, - $comment{$code}; - } -} + # non-combined characters + my ($c, $u, $rest) = ($1, $2, "U+" . $2 . $3); + my $ucs = hex($u); + my $code = hex($c); -print FILE "};\n"; -close(FILE); + next if ($code < 0x80 && $ucs < 0x80); -if ($TEST == 1) -{ - $file1 = "utf8.data"; - $file2 = "euc_jis_2004.data"; - open(FILE1, "> $file1") || die("cannot open $file1"); - open(FILE2, "> $file2") || die("cannot open $file2"); - - for $index (sort { $a <=> $b } keys(%array)) - { - $code = $array{$index}; - if ( $code > 0x00 - && $code != 0x09 - && $code != 0x0a - && $code != 0x0d - && $code != 0x5c - && ( $code < 0x80 - || ($code >= 0x8ea1 && $code <= 0x8efe) - || ($code >= 0x8fa1a1 && $code <= 0x8ffefe) - || ($code >= 0xa1a1 && $code <= 0x8fefe))) - { - for ($i = 3; $i >= 0; $i--) - { - $s = $i * 8; - $mask = 0xff << $s; - print FILE1 pack("C", ($index & $mask) >> $s) - if $index & $mask; - print FILE2 pack("C", ($code & $mask) >> $s) if $code & $mask; - } - print FILE1 "\n"; - print FILE2 "\n"; - } - } -} - -$file = "utf8_to_euc_jis_2004_combined.map"; -open(FILE, "> $file") || die("cannot open $file"); -print FILE "/*\n"; -print FILE " * This file was generated by UCS_to_EUC_JIS_2004.pl\n"; -print FILE " */\n"; -print FILE - "static const pg_utf_to_local_combined ULmapEUC_JIS_2004_combined[] = {\n"; - -for $index (sort { $a cmp $b } keys(%array1)) -{ - $code = $array1{$index}; - $count1--; - if ($count1 == 0) - { - printf FILE " {0x%s, 0x%s, 0x%06x} /* %s */\n", substr($index, 0, 8), - substr($index, 8, 8), $code, $comment1{$index}; - } - else - { - printf FILE " {0x%s, 0x%s, 0x%06x}, /* %s */\n", - substr($index, 0, 8), substr($index, 8, 8), $code, - $comment1{$index}; - } -} - -print FILE "};\n"; -close(FILE); - -if ($TEST == 1) -{ - for $index (sort { $a cmp $b } keys(%array1)) - { - $code = $array1{$index}; - if ( $code > 0x00 - && $code != 0x09 - && $code != 0x0a - && $code != 0x0d - && $code != 0x5c - && ( $code < 0x80 - || ($code >= 0x8ea1 && $code <= 0x8efe) - || ($code >= 0x8fa1a1 && $code <= 0x8ffefe) - || ($code >= 0xa1a1 && $code <= 0x8fefe))) - { - - $v1 = hex(substr($index, 0, 8)); - $v2 = hex(substr($index, 8, 8)); - - for ($i = 3; $i >= 0; $i--) - { - $s = $i * 8; - $mask = 0xff << $s; - print FILE1 pack("C", ($v1 & $mask) >> $s) if $v1 & $mask; - print FILE2 pack("C", ($code & $mask) >> $s) if $code & $mask; - } - for ($i = 3; $i >= 0; $i--) - { - $s = $i * 8; - $mask = 0xff << $s; - print FILE1 pack("C", ($v2 & $mask) >> $s) if $v2 & $mask; - } - print FILE1 "\n"; - print FILE2 "\n"; - } - } - close(FILE1); - close(FILE2); -} - -# then generate EUC_JIS_2004 --> UTF-8 table - -$in_file = "euc-jis-2004-std.txt"; - -open(FILE, $in_file) || die("cannot open $in_file"); - -reset 'array'; -reset 'array1'; -reset 'comment'; -reset 'comment1'; - -while ($line = ) -{ - if ($line =~ /^0x(.*)[ \t]*U\+(.*)\+(.*)[ \t]*#(.*)$/) - { - $c = $1; - $u1 = $2; - $u2 = $3; - $rest = "U+" . $u1 . "+" . $u2 . $4; - $code = hex($c); - $ucs = hex($u1); - $utf1 = &ucs2utf($ucs); - $ucs = hex($u2); - $utf2 = &ucs2utf($ucs); - $str = sprintf "%08x%08x", $utf1, $utf2; - $array1{$code} = $str; - $comment1{$code} = $rest; - $count1++; - next; - } - elsif ($line =~ /^0x(.*)[ \t]*U\+(.*)[ \t]*#(.*)$/) - { - $c = $1; - $u = $2; - $rest = "U+" . $u . $3; - } - else - { - next; - } - - $ucs = hex($u); - $code = hex($c); - $utf = &ucs2utf($ucs); - if ($array{$code} ne "") - { - printf STDERR "Warning: duplicate UTF8: %04x\n", $ucs; - next; - } - $count++; - - $array{$code} = $utf; - $comment{$utf} = $rest; -} -close(FILE); - -$file = "euc_jis_2004_to_utf8.map"; -open(FILE, "> $file") || die("cannot open $file"); -print FILE "/*\n"; -print FILE " * This file was generated by UCS_to_EUC_JIS_2004.pl\n"; -print FILE " */\n"; -print FILE "static const pg_local_to_utf LUmapEUC_JIS_2004[] = {\n"; - -for $index (sort { $a <=> $b } keys(%array)) -{ - $code = $array{$index}; - $count--; - if ($count == 0) - { - printf FILE " {0x%06x, 0x%08x} /* %s */\n", $index, $code, - $comment{$code}; - } - else - { - printf FILE " {0x%06x, 0x%08x}, /* %s */\n", $index, $code, - $comment{$code}; - } -} - -print FILE "};\n"; -close(FILE); - -$file = "euc_jis_2004_to_utf8_combined.map"; -open(FILE, "> $file") || die("cannot open $file"); -print FILE "/*\n"; -print FILE " * This file was generated by UCS_to_EUC_JIS_2004.pl\n"; -print FILE " */\n"; -print FILE - "static const pg_local_to_utf_combined LUmapEUC_JIS_2004_combined[] = {\n"; - -for $index (sort { $a <=> $b } keys(%array1)) -{ - $code = $array1{$index}; - $count1--; - if ($count1 == 0) - { - printf FILE " {0x%06x, 0x%s, 0x%s} /* %s */\n", $index, - substr($code, 0, 8), substr($code, 8, 8), $comment1{$index}; - } - else - { - printf FILE " {0x%06x, 0x%s, 0x%s}, /* %s */\n", $index, - substr($code, 0, 8), substr($code, 8, 8), $comment1{$index}; + push @all, { direction => 'both', ucs => $ucs, code => $code, comment => $rest }; } } +close($in); -print FILE "};\n"; -close(FILE); +print_tables("EUC_JIS_2004", \@all, 1); diff --git a/src/backend/utils/mb/Unicode/UCS_to_EUC_JP.pl b/src/backend/utils/mb/Unicode/UCS_to_EUC_JP.pl index 055fc849ba..b70f7144c7 100755 --- a/src/backend/utils/mb/Unicode/UCS_to_EUC_JP.pl +++ b/src/backend/utils/mb/Unicode/UCS_to_EUC_JP.pl @@ -1,6 +1,6 @@ #! /usr/bin/perl # -# Copyright (c) 2001-2016, PostgreSQL Global Development Group +# Copyright (c) 2001-2017, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/UCS_to_EUC_JP.pl # @@ -8,275 +8,223 @@ # map files provided by Unicode organization. # Unfortunately it is prohibited by the organization # to distribute the map files. So if you try to use this script, -# you have to obtain JIS0201.TXT, JIS0208.TXT, JIS0212.TXT from -# the organization's ftp site. -# -# JIS0201.TXT format: -# JIS0201 code in hex -# UCS-2 code in hex -# # and Unicode name (not used in this script) -# -# JIS0208.TXT format: -# JIS0208 shift-JIS code in hex -# JIS0208 code in hex -# UCS-2 code in hex -# # and Unicode name (not used in this script) -# -# JIS0212.TXT format: -# JIS0212 code in hex -# UCS-2 code in hex -# # and Unicode name (not used in this script) - -require "ucs2utf.pl"; - -# first generate UTF-8 --> EUC_JP table +# you have to obtain CP932.TXT and JIS0212.TXT from the +# organization's ftp site. -# -# JIS0201 -# -$in_file = "JIS0201.TXT"; +use strict; +require convutils; -open(FILE, $in_file) || die("cannot open $in_file"); +# Load JIS0212.TXT +my $jis0212 = &read_source("JIS0212.TXT"); -reset 'array'; +my @mapping; -while () -{ - chop; - if (/^#/) +foreach my $i (@$jis0212) { + # We have a different mapping for this in the EUC_JP to UTF-8 direction. + if ($i->{code} == 0x2243) { - next; + $i->{direction} = "from_unicode"; } - ($c, $u, $rest) = split; - $ucs = hex($u); - $code = hex($c); - if ($code >= 0x80 && $ucs >= 0x0080) - { - $utf = &ucs2utf($ucs); - if ($array{$utf} ne "") - { - printf STDERR "Warning: duplicate UTF8: %04x\n", $ucs; - next; - } - $count++; - # add single shift 2 - $array{$utf} = ($code | 0x8e00); + if ($i->{code} == 0x2271) + { + $i->{direction} = "to_unicode"; } -} -close(FILE); - -# -# JIS0208 -# -$in_file = "JIS0208.TXT"; -open(FILE, $in_file) || die("cannot open $in_file"); - -while () -{ - chop; - if (/^#/) + if ($i->{ucs} >= 0x080) { - next; + $i->{code} = $i->{code} | 0x8f8080; } - ($s, $c, $u, $rest) = split; - $ucs = hex($u); - $code = hex($c); - if ($code >= 0x80 && $ucs >= 0x0080) + else { - $utf = &ucs2utf($ucs); - if ($array{$utf} ne "") - { - printf STDERR "Warning: duplicate UTF8: %04x\n", $ucs; - next; - } - $count++; - - $array{$utf} = ($code | 0x8080); + next; } + + push @mapping, $i; } -close(FILE); -# -# JIS0212 -# -$in_file = "JIS0212.TXT"; +# Load CP932.TXT. +my $ct932 = &read_source("CP932.TXT"); -open(FILE, $in_file) || die("cannot open $in_file"); +foreach my $i (@$ct932) { + my $sjis = $i->{code}; -while () -{ - chop; - if (/^#/) + # We have a different mapping for this in the EUC_JP to UTF-8 direction. + if ($sjis == 0xeefa || + $sjis == 0xeefb || + $sjis == 0xeefc) { next; } - ($c, $u, $rest) = split; - $ucs = hex($u); - $code = hex($c); - if ($code >= 0x80 && $ucs >= 0x0080) - { - $utf = &ucs2utf($ucs); - if ($array{$utf} ne "") - { - printf STDERR "Warning: duplicate UTF8: %04x\n", $ucs; - next; - } - $count++; - $array{$utf} = ($code | 0x8f8080); - } -} -close(FILE); + if ($sjis >= 0xa1) + { + my $jis = &sjis2jis($sjis); -$file = "utf8_to_euc_jp.map"; -open(FILE, "> $file") || die("cannot open $file"); + $i->{code} = $jis | ($jis < 0x100 ? 0x8e00 : + ($sjis >= 0xeffd ? 0x8f8080 : 0x8080)); -print FILE "/* src/backend/utils/mb/Unicode/$file */\n\n"; -print FILE "static const pg_utf_to_local ULmapEUC_JP[ $count ] = {\n"; + # Remember the SJIS code for later. + $i->{sjis} = $sjis; -for $index (sort { $a <=> $b } keys(%array)) -{ - $code = $array{$index}; - $count--; - if ($count == 0) - { - printf FILE " {0x%04x, 0x%04x}\n", $index, $code; - } - else - { - printf FILE " {0x%04x, 0x%04x},\n", $index, $code; + push @mapping, $i; } } -print FILE "};\n"; -close(FILE); - -# -# then generate EUC_JP --> UTF8 table -# +foreach my $i (@mapping) { + my $sjis = $i->{sjis}; -# -# JIS0201 -# -$in_file = "JIS0201.TXT"; - -open(FILE, $in_file) || die("cannot open $in_file"); - -reset 'array'; - -while () -{ - chop; - if (/^#/) + # These SJIS characters are excluded completely. + if ($sjis >= 0xed00 && $sjis <= 0xeef9 || + $sjis >= 0xfa54 && $sjis <= 0xfa56 || + $sjis >= 0xfa58 && $sjis <= 0xfc4b) { + $i->{direction} = "none"; next; } - ($c, $u, $rest) = split; - $ucs = hex($u); - $code = hex($c); - if ($code >= 0x80 && $ucs >= 0x0080) - { - $utf = &ucs2utf($ucs); - if ($array{$code} ne "") - { - printf STDERR "Warning: duplicate code: %04x\n", $ucs; - next; - } - $count++; - - # add single shift 2 - $code |= 0x8e00; - $array{$code} = $utf; - } -} -close(FILE); - -# -# JIS0208 -# -$in_file = "JIS0208.TXT"; - -open(FILE, $in_file) || die("cannot open $in_file"); -while () -{ - chop; - if (/^#/) + # These SJIS characters are only in the UTF-8 to EUC_JP table + if ($sjis == 0xeefa || $sjis == 0xeefb || $sjis == 0xeefc) { + $i->{direction} = "from_unicode"; next; } - ($s, $c, $u, $rest) = split; - $ucs = hex($u); - $code = hex($c); - if ($code >= 0x80 && $ucs >= 0x0080) - { - $utf = &ucs2utf($ucs); - if ($array{$code} ne "") - { - printf STDERR "Warning: duplicate code: %04x\n", $ucs; - next; - } - $count++; - $code |= 0x8080; - $array{$code} = $utf; + if ($sjis == 0x8790 || $sjis == 0x8791 || $sjis == 0x8792 || + $sjis == 0x8795 || $sjis == 0x8796 || $sjis == 0x8797 || + $sjis == 0x879a || $sjis == 0x879b || $sjis == 0x879c || + ($sjis >= 0xfa4a && $sjis <= 0xfa53)) + { + $i->{direction} = "to_unicode"; + next; } } -close(FILE); -# -# JIS0212 -# -$in_file = "JIS0212.TXT"; +push @mapping, ( + {direction => 'both', ucs => 0x4efc, code => 0x8ff4af, comment => '# CJK(4EFC)'}, + {direction => 'both', ucs => 0x50f4, code => 0x8ff4b0, comment => '# CJK(50F4)'}, + {direction => 'both', ucs => 0x51EC, code => 0x8ff4b1, comment => '# CJK(51EC)'}, + {direction => 'both', ucs => 0x5307, code => 0x8ff4b2, comment => '# CJK(5307)'}, + {direction => 'both', ucs => 0x5324, code => 0x8ff4b3, comment => '# CJK(5324)'}, + {direction => 'both', ucs => 0x548A, code => 0x8ff4b5, comment => '# CJK(548A)'}, + {direction => 'both', ucs => 0x5759, code => 0x8ff4b6, comment => '# CJK(5759)'}, + {direction => 'both', ucs => 0x589E, code => 0x8ff4b9, comment => '# CJK(589E)'}, + {direction => 'both', ucs => 0x5BEC, code => 0x8ff4ba, comment => '# CJK(5BEC)'}, + {direction => 'both', ucs => 0x5CF5, code => 0x8ff4bb, comment => '# CJK(5CF5)'}, + {direction => 'both', ucs => 0x5D53, code => 0x8ff4bc, comment => '# CJK(5D53)'}, + {direction => 'both', ucs => 0x5FB7, code => 0x8ff4be, comment => '# CJK(5FB7)'}, + {direction => 'both', ucs => 0x6085, code => 0x8ff4bf, comment => '# CJK(6085)'}, + {direction => 'both', ucs => 0x6120, code => 0x8ff4c0, comment => '# CJK(6120)'}, + {direction => 'both', ucs => 0x654E, code => 0x8ff4c1, comment => '# CJK(654E)'}, + {direction => 'both', ucs => 0x663B, code => 0x8ff4c2, comment => '# CJK(663B)'}, + {direction => 'both', ucs => 0x6665, code => 0x8ff4c3, comment => '# CJK(6665)'}, + {direction => 'both', ucs => 0x6801, code => 0x8ff4c6, comment => '# CJK(6801)'}, + {direction => 'both', ucs => 0x6A6B, code => 0x8ff4c9, comment => '# CJK(6A6B)'}, + {direction => 'both', ucs => 0x6AE2, code => 0x8ff4ca, comment => '# CJK(6AE2)'}, + {direction => 'both', ucs => 0x6DF2, code => 0x8ff4cc, comment => '# CJK(6DF2)'}, + {direction => 'both', ucs => 0x6DF8, code => 0x8ff4cb, comment => '# CJK(6DF8)'}, + {direction => 'both', ucs => 0x7028, code => 0x8ff4cd, comment => '# CJK(7028)'}, + {direction => 'both', ucs => 0x70BB, code => 0x8ff4ae, comment => '# CJK(70BB)'}, + {direction => 'both', ucs => 0x7501, code => 0x8ff4d0, comment => '# CJK(7501)'}, + {direction => 'both', ucs => 0x7682, code => 0x8ff4d1, comment => '# CJK(7682)'}, + {direction => 'both', ucs => 0x769E, code => 0x8ff4d2, comment => '# CJK(769E)'}, + {direction => 'both', ucs => 0x7930, code => 0x8ff4d4, comment => '# CJK(7930)'}, + {direction => 'both', ucs => 0x7AE7, code => 0x8ff4d9, comment => '# CJK(7AE7)'}, + {direction => 'both', ucs => 0x7DA0, code => 0x8ff4dc, comment => '# CJK(7DA0)'}, + {direction => 'both', ucs => 0x7DD6, code => 0x8ff4dd, comment => '# CJK(7DD6)'}, + {direction => 'both', ucs => 0x8362, code => 0x8ff4df, comment => '# CJK(8362)'}, + {direction => 'both', ucs => 0x85B0, code => 0x8ff4e1, comment => '# CJK(85B0)'}, + {direction => 'both', ucs => 0x8807, code => 0x8ff4e4, comment => '# CJK(8807)'}, + {direction => 'both', ucs => 0x8B7F, code => 0x8ff4e6, comment => '# CJK(8B7F)'}, + {direction => 'both', ucs => 0x8CF4, code => 0x8ff4e7, comment => '# CJK(8CF4)'}, + {direction => 'both', ucs => 0x8D76, code => 0x8ff4e8, comment => '# CJK(8D76)'}, + {direction => 'both', ucs => 0x90DE, code => 0x8ff4ec, comment => '# CJK(90DE)'}, + {direction => 'both', ucs => 0x9115, code => 0x8ff4ee, comment => '# CJK(9115)'}, + {direction => 'both', ucs => 0x9592, code => 0x8ff4f1, comment => '# CJK(9592)'}, + {direction => 'both', ucs => 0x973B, code => 0x8ff4f4, comment => '# CJK(973B)'}, + {direction => 'both', ucs => 0x974D, code => 0x8ff4f5, comment => '# CJK(974D)'}, + {direction => 'both', ucs => 0x9751, code => 0x8ff4f6, comment => '# CJK(9751)'}, + {direction => 'both', ucs => 0x999E, code => 0x8ff4fa, comment => '# CJK(999E)'}, + {direction => 'both', ucs => 0x9AD9, code => 0x8ff4fb, comment => '# CJK(9AD9)'}, + {direction => 'both', ucs => 0x9B72, code => 0x8ff4fc, comment => '# CJK(9B72)'}, + {direction => 'both', ucs => 0x9ED1, code => 0x8ff4fe, comment => '# CJK(9ED1)'}, + {direction => 'both', ucs => 0xF929, code => 0x8ff4c5, comment => '# CJK COMPATIBILITY IDEOGRAPH-F929'}, + {direction => 'both', ucs => 0xF9DC, code => 0x8ff4f2, comment => '# CJK COMPATIBILITY IDEOGRAPH-F9DC'}, + {direction => 'both', ucs => 0xFA0E, code => 0x8ff4b4, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA0E'}, + {direction => 'both', ucs => 0xFA0F, code => 0x8ff4b7, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA0F'}, + {direction => 'both', ucs => 0xFA10, code => 0x8ff4b8, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA10'}, + {direction => 'both', ucs => 0xFA11, code => 0x8ff4bd, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA11'}, + {direction => 'both', ucs => 0xFA12, code => 0x8ff4c4, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA12'}, + {direction => 'both', ucs => 0xFA13, code => 0x8ff4c7, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA13'}, + {direction => 'both', ucs => 0xFA14, code => 0x8ff4c8, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA14'}, + {direction => 'both', ucs => 0xFA15, code => 0x8ff4ce, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA15'}, + {direction => 'both', ucs => 0xFA16, code => 0x8ff4cf, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA16'}, + {direction => 'both', ucs => 0xFA17, code => 0x8ff4d3, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA17'}, + {direction => 'both', ucs => 0xFA18, code => 0x8ff4d5, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA18'}, + {direction => 'both', ucs => 0xFA19, code => 0x8ff4d6, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA19'}, + {direction => 'both', ucs => 0xFA1A, code => 0x8ff4d7, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA1A'}, + {direction => 'both', ucs => 0xFA1B, code => 0x8ff4d8, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA1B'}, + {direction => 'both', ucs => 0xFA1C, code => 0x8ff4da, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA1C'}, + {direction => 'both', ucs => 0xFA1D, code => 0x8ff4db, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA1D'}, + {direction => 'both', ucs => 0xFA1E, code => 0x8ff4de, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA1E'}, + {direction => 'both', ucs => 0xFA1F, code => 0x8ff4e0, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA1F'}, + {direction => 'both', ucs => 0xFA20, code => 0x8ff4e2, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA20'}, + {direction => 'both', ucs => 0xFA21, code => 0x8ff4e3, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA21'}, + {direction => 'both', ucs => 0xFA22, code => 0x8ff4e5, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA22'}, + {direction => 'both', ucs => 0xFA23, code => 0x8ff4e9, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA23'}, + {direction => 'both', ucs => 0xFA24, code => 0x8ff4ea, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA24'}, + {direction => 'both', ucs => 0xFA25, code => 0x8ff4eb, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA25'}, + {direction => 'both', ucs => 0xFA26, code => 0x8ff4ed, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA26'}, + {direction => 'both', ucs => 0xFA27, code => 0x8ff4ef, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA27'}, + {direction => 'both', ucs => 0xFA28, code => 0x8ff4f0, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA28'}, + {direction => 'both', ucs => 0xFA29, code => 0x8ff4f3, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA29'}, + {direction => 'both', ucs => 0xFA2A, code => 0x8ff4f7, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA2A'}, + {direction => 'both', ucs => 0xFA2B, code => 0x8ff4f8, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA2B'}, + {direction => 'both', ucs => 0xFA2C, code => 0x8ff4f9, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA2C'}, + {direction => 'both', ucs => 0xFA2D, code => 0x8ff4fd, comment => '# CJK COMPATIBILITY IDEOGRAPH-FA2D'}, + {direction => 'both', ucs => 0xFF07, code => 0x8ff4a9, comment => '# FULLWIDTH APOSTROPHE'}, + {direction => 'both', ucs => 0xFFE4, code => 0x8fa2c3, comment => '# FULLWIDTH BROKEN BAR'}, + + # additional conversions for EUC_JP -> UTF-8 conversion + {direction => 'to_unicode', ucs => 0x2116, code => 0x8ff4ac, comment => '# NUMERO SIGN'}, + {direction => 'to_unicode', ucs => 0x2121, code => 0x8ff4ad, comment => '# TELEPHONE SIGN'}, + {direction => 'to_unicode', ucs => 0x3231, code => 0x8ff4ab, comment => '# PARENTHESIZED IDEOGRAPH STOCK'} + ); + +print_tables("EUC_JP", \@mapping); + +####################################################################### +# sjis2jis ; SJIS => JIS conversion +sub sjis2jis +{ + my ($sjis) = @_; -open(FILE, $in_file) || die("cannot open $in_file"); + return $sjis if ($sjis <= 0x100); -while () -{ - chop; - if (/^#/) - { - next; - } - ($c, $u, $rest) = split; - $ucs = hex($u); - $code = hex($c); - if ($code >= 0x80 && $ucs >= 0x0080) + my $hi = $sjis >> 8; + my $lo = $sjis & 0xff; + + if ($lo >= 0x80) { $lo--; } + $lo -= 0x40; + if ($hi >= 0xe0) { $hi -= 0x40; } + $hi -= 0x81; + my $pos = $lo + $hi * 0xbc; + + if ($pos >= 114 * 0x5e && $pos <= 115 * 0x5e + 0x1b) { - $utf = &ucs2utf($ucs); - if ($array{$code} ne "") - { - printf STDERR "Warning: duplicate code: %04x\n", $ucs; - next; - } - $count++; + # This region (115-ku) is out of range of JIS code but for + # convenient to generate code in EUC CODESET 3, move this to + # seemingly duplicate region (83-84-ku). + $pos = $pos - ((31 * 0x5e) + 12); - $code |= 0x8f8080; - $array{$code} = $utf; + # after 85-ku 82-ten needs to be moved 2 codepoints + $pos = $pos - 2 if ($pos >= 84 * 0x5c + 82) } -} -close(FILE); -$file = "euc_jp_to_utf8.map"; -open(FILE, "> $file") || die("cannot open $file"); + my $hi2 = $pos / 0x5e; + my $lo2 = ($pos % 0x5e); -print FILE "/* src/backend/utils/mb/Unicode/$file */\n\n"; -print FILE "static const pg_local_to_utf LUmapEUC_JP[ $count ] = {\n"; -for $index (sort { $a <=> $b } keys(%array)) -{ - $utf = $array{$index}; - $count--; - if ($count == 0) - { - printf FILE " {0x%04x, 0x%04x}\n", $index, $utf; - } - else - { - printf FILE " {0x%04x, 0x%04x},\n", $index, $utf; - } -} + my $ret = $lo2 + 0x21 + (($hi2 + 0x21) << 8); -print FILE "};\n"; -close(FILE); + return $ret; +} diff --git a/src/backend/utils/mb/Unicode/UCS_to_EUC_KR.pl b/src/backend/utils/mb/Unicode/UCS_to_EUC_KR.pl index a7c94bca91..228fc4d67f 100755 --- a/src/backend/utils/mb/Unicode/UCS_to_EUC_KR.pl +++ b/src/backend/utils/mb/Unicode/UCS_to_EUC_KR.pl @@ -1,6 +1,6 @@ #! /usr/bin/perl # -# Copyright (c) 2001-2016, PostgreSQL Global Development Group +# Copyright (c) 2001-2017, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/UCS_to_EUC_KR.pl # @@ -16,113 +16,23 @@ # UCS-2 code in hex # # and Unicode name (not used in this script) -require "ucs2utf.pl"; +use strict; +require convutils; -# first generate UTF-8 --> EUC_KR table +# Load the source file. -$in_file = "KSX1001.TXT"; +my $mapping = &read_source("KSX1001.TXT"); -open(FILE, $in_file) || die("cannot open $in_file"); - -while () -{ - chop; - if (/^#/) - { - next; - } - ($c, $u, $rest) = split; - $ucs = hex($u); - $code = hex($c); - if ($code >= 0x80 && $ucs >= 0x0080) - { - $utf = &ucs2utf($ucs); - if ($array{$utf} ne "") - { - printf STDERR "Warning: duplicate UTF8: %04x\n", $ucs; - next; - } - $count++; - - $array{$utf} = ($code | 0x8080); - } -} -close(FILE); - -$file = "utf8_to_euc_kr.map"; -open(FILE, "> $file") || die("cannot open $file"); - -print FILE "/* src/backend/utils/mb/Unicode/$file */\n\n"; -print FILE "static const pg_utf_to_local ULmapEUC_KR[ $count ] = {\n"; - -for $index (sort { $a <=> $b } keys(%array)) +foreach my $i (@$mapping) { - $code = $array{$index}; - $count--; - if ($count == 0) - { - printf FILE " {0x%04x, 0x%04x}\n", $index, $code; - } - else - { - printf FILE " {0x%04x, 0x%04x},\n", $index, $code; - } + $i->{code} = $i->{code} | 0x8080; } -print FILE "};\n"; -close(FILE); - -# -# then generate EUC_KR --> UTF8 table -# -reset 'array'; - -open(FILE, $in_file) || die("cannot open $in_file"); - -while () -{ - chop; - if (/^#/) - { - next; - } - ($c, $u, $rest) = split; - $ucs = hex($u); - $code = hex($c); - if ($code >= 0x80 && $ucs >= 0x0080) - { - $utf = &ucs2utf($ucs); - if ($array{$code} ne "") - { - printf STDERR "Warning: duplicate code: %04x\n", $ucs; - next; - } - $count++; - - $code |= 0x8080; - $array{$code} = $utf; - } -} -close(FILE); - -$file = "euc_kr_to_utf8.map"; -open(FILE, "> $file") || die("cannot open $file"); - -print FILE "/* src/backend/utils/mb/Unicode/$file */\n\n"; -print FILE "static const pg_local_to_utf LUmapEUC_KR[ $count ] = {\n"; -for $index (sort { $a <=> $b } keys(%array)) -{ - $utf = $array{$index}; - $count--; - if ($count == 0) - { - printf FILE " {0x%04x, 0x%04x}\n", $index, $utf; - } - else - { - printf FILE " {0x%04x, 0x%04x},\n", $index, $utf; - } -} +# Some extra characters that are not in KSX1001.TXT +push @$mapping, ( + {direction => 'both', ucs => 0x20AC, code => 0xa2e6, comment => '# EURO SIGN'}, + {direction => 'both', ucs => 0x00AE, code => 0xa2e7, comment => '# REGISTERED SIGN'}, + {direction => 'both', ucs => 0x327E, code => 0xa2e8, comment => '# CIRCLED HANGUL IEUNG U'} + ); -print FILE "};\n"; -close(FILE); +print_tables("EUC_KR", $mapping); diff --git a/src/backend/utils/mb/Unicode/UCS_to_EUC_TW.pl b/src/backend/utils/mb/Unicode/UCS_to_EUC_TW.pl index e4fc535b18..91699f6d20 100755 --- a/src/backend/utils/mb/Unicode/UCS_to_EUC_TW.pl +++ b/src/backend/utils/mb/Unicode/UCS_to_EUC_TW.pl @@ -1,6 +1,6 @@ #! /usr/bin/perl # -# Copyright (c) 2001-2016, PostgreSQL Global Development Group +# Copyright (c) 2001-2017, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/UCS_to_EUC_TW.pl # @@ -17,141 +17,48 @@ # UCS-2 code in hex # # and Unicode name (not used in this script) -require "ucs2utf.pl"; +use strict; +require convutils; -# first generate UTF-8 --> EUC_TW table +my $mapping = &read_source("CNS11643.TXT"); -$in_file = "CNS11643.TXT"; +my @extras; -open(FILE, $in_file) || die("cannot open $in_file"); - -while () +foreach my $i (@$mapping) { - chop; - if (/^#/) + my $ucs = $i->{ucs}; + my $code = $i->{code}; + my $origcode = $i->{code}; + + my $plane = ($code & 0x1f0000) >> 16; + if ($plane > 16) { + printf STDERR "Warning: invalid plane No.$plane. ignored\n"; next; } - ($c, $u, $rest) = split; - $ucs = hex($u); - $code = hex($c); - if ($code >= 0x80 && $ucs >= 0x0080) - { - $utf = &ucs2utf($ucs); - if ($array{$utf} ne "") - { - printf STDERR "Warning: duplicate UTF8: %04x\n", $ucs; - next; - } - $count++; - - $plane = ($code & 0x1f0000) >> 16; - if ($plane > 16) - { - printf STDERR "Warning: invalid plane No.$plane. ignored\n"; - next; - } - - if ($plane == 1) - { - $array{$utf} = (($code & 0xffff) | 0x8080); - } - else - { - $array{$utf} = - (0x8ea00000 + ($plane << 16)) | (($code & 0xffff) | 0x8080); - } - } -} -close(FILE); - -$file = "utf8_to_euc_tw.map"; -open(FILE, "> $file") || die("cannot open $file"); -print FILE "/* src/backend/utils/mb/Unicode/$file */\n\n"; -print FILE "static const pg_utf_to_local ULmapEUC_TW[ $count ] = {\n"; - -for $index (sort { $a <=> $b } keys(%array)) -{ - $code = $array{$index}; - $count--; - if ($count == 0) + if ($plane == 1) { - printf FILE " {0x%04x, 0x%04x}\n", $index, $code; + $code = ($code & 0xffff) | 0x8080; } else { - printf FILE " {0x%04x, 0x%04x},\n", $index, $code; + $code = (0x8ea00000 + ($plane << 16)) | (($code & 0xffff) | 0x8080); } -} - -print FILE "};\n"; -close(FILE); - -# -# then generate EUC_TW --> UTF8 table -# -reset 'array'; - -open(FILE, $in_file) || die("cannot open $in_file"); + $i->{code} = $code; -while () -{ - chop; - if (/^#/) + # Some codes are mapped twice in the EUC_TW to UTF-8 table. + if ($origcode >= 0x12121 && $origcode <= 0x20000) { - next; - } - ($c, $u, $rest) = split; - $ucs = hex($u); - $code = hex($c); - if ($code >= 0x80 && $ucs >= 0x0080) - { - $utf = &ucs2utf($ucs); - if ($array{$code} ne "") - { - printf STDERR "Warning: duplicate code: %04x\n", $ucs; - next; - } - $count++; - - $plane = ($code & 0x1f0000) >> 16; - if ($plane > 16) - { - printf STDERR "Warning: invalid plane No.$plane. ignored\n"; - next; - } - - if ($plane == 1) - { - $c = (($code & 0xffff) | 0x8080); - $array{$c} = $utf; - $count++; + push @extras, { + ucs => $i->{ucs}, + code => ($i->{code} + 0x8ea10000), + rest => $i->{rest}, + direction => 'to_unicode' } - $c = (0x8ea00000 + ($plane << 16)) | (($code & 0xffff) | 0x8080); - $array{$c} = $utf; } } -close(FILE); - -$file = "euc_tw_to_utf8.map"; -open(FILE, "> $file") || die("cannot open $file"); -print FILE "/* src/backend/utils/mb/Unicode/$file */\n\n"; -print FILE "static const pg_local_to_utf LUmapEUC_TW[ $count ] = {\n"; -for $index (sort { $a <=> $b } keys(%array)) -{ - $utf = $array{$index}; - $count--; - if ($count == 0) - { - printf FILE " {0x%04x, 0x%04x}\n", $index, $utf; - } - else - { - printf FILE " {0x%04x, 0x%04x},\n", $index, $utf; - } -} +push @$mapping, @extras; -print FILE "};\n"; -close(FILE); +print_tables("EUC_TW", $mapping); diff --git a/src/backend/utils/mb/Unicode/UCS_to_GB18030.pl b/src/backend/utils/mb/Unicode/UCS_to_GB18030.pl index 043c1c27ec..701c35cfa7 100755 --- a/src/backend/utils/mb/Unicode/UCS_to_GB18030.pl +++ b/src/backend/utils/mb/Unicode/UCS_to_GB18030.pl @@ -1,6 +1,6 @@ #! /usr/bin/perl # -# Copyright (c) 2007-2016, PostgreSQL Global Development Group +# Copyright (c) 2007-2017, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/UCS_to_GB18030.pl # @@ -13,97 +13,33 @@ # where the "u" field is the Unicode code point in hex, # and the "b" field is the hex byte sequence for GB18030 -require "ucs2utf.pl"; - +use strict; +require convutils; # Read the input -$in_file = "gb-18030-2000.xml"; +my $in_file = "gb-18030-2000.xml"; + +open(my $in, '<', $in_file) || die("cannot open $in_file"); -open(FILE, $in_file) || die("cannot open $in_file"); +my @mapping; -while () +while (<$in>) { next if (!m/= 0x80 && $ucs >= 0x0080) { - $utf = &ucs2utf($ucs); - if ($arrayu{$utf} ne "") - { - printf STDERR "Warning: duplicate UTF8: %04x\n", $ucs; - next; + push @mapping, { + ucs => $ucs, + code => $code, + direction => 'both' } - if ($arrayc{$code} ne "") - { - printf STDERR "Warning: duplicate GB18030: %08x\n", $code; - next; - } - $arrayu{$utf} = $code; - $arrayc{$code} = $utf; - $count++; - } -} -close(FILE); - - -# -# first, generate UTF8 --> GB18030 table -# - -$file = "utf8_to_gb18030.map"; -open(FILE, "> $file") || die("cannot open $file"); - -print FILE "/* src/backend/utils/mb/Unicode/$file */\n\n"; -print FILE "static const pg_utf_to_local ULmapGB18030[ $count ] = {\n"; - -$cc = $count; -for $index (sort { $a <=> $b } keys(%arrayu)) -{ - $code = $arrayu{$index}; - $cc--; - if ($cc == 0) - { - printf FILE " {0x%04x, 0x%04x}\n", $index, $code; - } - else - { - printf FILE " {0x%04x, 0x%04x},\n", $index, $code; - } -} - -print FILE "};\n"; -close(FILE); - - -# -# then generate GB18030 --> UTF8 table -# - -$file = "gb18030_to_utf8.map"; -open(FILE, "> $file") || die("cannot open $file"); - -print FILE "/* src/backend/utils/mb/Unicode/$file */\n\n"; -print FILE "static const pg_local_to_utf LUmapGB18030[ $count ] = {\n"; - -$cc = $count; -for $index (sort { $a <=> $b } keys(%arrayc)) -{ - $utf = $arrayc{$index}; - $cc--; - if ($cc == 0) - { - printf FILE " {0x%04x, 0x%04x}\n", $index, $utf; - } - else - { - printf FILE " {0x%04x, 0x%04x},\n", $index, $utf; } } +close($in); -print FILE "};\n"; -close(FILE); +print_tables("GB18030", \@mapping); diff --git a/src/backend/utils/mb/Unicode/UCS_to_JOHAB.pl b/src/backend/utils/mb/Unicode/UCS_to_JOHAB.pl new file mode 100755 index 0000000000..b84d589f0c --- /dev/null +++ b/src/backend/utils/mb/Unicode/UCS_to_JOHAB.pl @@ -0,0 +1,32 @@ +#! /usr/bin/perl +# +# Copyright (c) 2001-2017, PostgreSQL Global Development Group +# +# src/backend/utils/mb/Unicode/UCS_to_JOHAB.pl +# +# Generate UTF-8 <--> JOHAB conversion tables from +# map files provided by Unicode organization. +# Unfortunately it is prohibited by the organization +# to distribute the map files. So if you try to use this script, +# you have to obtain the map files from the organization's ftp site. +# ftp://www.unicode.org/Public/MAPPINGS/ +# We assume the file include three tab-separated columns: +# JOHAB code in hex +# UCS-2 code in hex +# # and Unicode name (not used in this script) + +use strict; +require convutils; + +# Load the source file. + +my $mapping = &read_source("JOHAB.TXT"); + +# Some extra characters that are not in JOHAB.TXT +push @$mapping, ( + {direction => 'both', ucs => 0x20AC, code => 0xd9e6, comment => '# EURO SIGN'}, + {direction => 'both', ucs => 0x00AE, code => 0xd9e7, comment => '# REGISTERED SIGN'}, + {direction => 'both', ucs => 0x327E, code => 0xd9e8, comment => '# CIRCLED HANGUL IEUNG U'} + ); + +print_tables("JOHAB", $mapping); diff --git a/src/backend/utils/mb/Unicode/UCS_to_SHIFT_JIS_2004.pl b/src/backend/utils/mb/Unicode/UCS_to_SHIFT_JIS_2004.pl index 51ffd86b2c..67b6ef68f2 100755 --- a/src/backend/utils/mb/Unicode/UCS_to_SHIFT_JIS_2004.pl +++ b/src/backend/utils/mb/Unicode/UCS_to_SHIFT_JIS_2004.pl @@ -1,234 +1,76 @@ #! /usr/bin/perl # -# Copyright (c) 2007-2016, PostgreSQL Global Development Group +# Copyright (c) 2007-2017, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/UCS_to_SHIFT_JIS_2004.pl # # Generate UTF-8 <--> SHIFT_JIS_2004 code conversion tables from # "sjis-0213-2004-std.txt" (http://x0213.org) -require "ucs2utf.pl"; +use strict; +require convutils; # first generate UTF-8 --> SHIFT_JIS_2004 table -$in_file = "sjis-0213-2004-std.txt"; +my $in_file = "sjis-0213-2004-std.txt"; -open(FILE, $in_file) || die("cannot open $in_file"); +open(my $in, '<', $in_file) || die("cannot open $in_file"); -reset 'array'; -reset 'array1'; -reset 'comment'; -reset 'comment1'; +my @mapping; -while ($line = ) +while (my $line = <$in>) { if ($line =~ /^0x(.*)[ \t]*U\+(.*)\+(.*)[ \t]*#(.*)$/) { - $c = $1; - $u1 = $2; - $u2 = $3; - $rest = "U+" . $u1 . "+" . $u2 . $4; - $code = hex($c); - $ucs = hex($u1); - $utf1 = &ucs2utf($ucs); - $ucs = hex($u2); - $utf2 = &ucs2utf($ucs); - $str = sprintf "%08x%08x", $utf1, $utf2; - $array1{$str} = $code; - $comment1{$str} = $rest; - $count1++; + # combined characters + my ($c, $u1, $u2) = ($1, $2, $3); + my $rest = "U+" . $u1 . "+" . $u2 . $4; + my $code = hex($c); + my $ucs1 = hex($u1); + my $ucs2 = hex($u2); + + push @mapping, { + code => $code, + ucs => $ucs1, + ucs_second => $ucs2, + comment => $rest, + direction => 'both' + }; next; } elsif ($line =~ /^0x(.*)[ \t]*U\+(.*)[ \t]*#(.*)$/) { - $c = $1; - $u = $2; - $rest = "U+" . $u . $3; - } - else - { - next; - } - - $ucs = hex($u); - $code = hex($c); - $utf = &ucs2utf($ucs); - if ($array{$utf} ne "") - { - printf STDERR - "Warning: duplicate UTF8: %08x UCS: %04x Shift JIS: %04x\n", $utf, - $ucs, $code; - next; - } - $count++; - - $array{$utf} = $code; - $comment{$code} = $rest; -} -close(FILE); - -$file = "utf8_to_shift_jis_2004.map"; -open(FILE, "> $file") || die("cannot open $file"); -print FILE "/*\n"; -print FILE " * This file was generated by UCS_to_SHIFT_JIS_2004.pl\n"; -print FILE " */\n"; -print FILE "static const pg_utf_to_local ULmapSHIFT_JIS_2004[] = {\n"; - -for $index (sort { $a <=> $b } keys(%array)) -{ - $code = $array{$index}; - $count--; - if ($count == 0) - { - printf FILE " {0x%08x, 0x%06x} /* %s */\n", $index, $code, - $comment{$code}; - } - else - { - printf FILE " {0x%08x, 0x%06x}, /* %s */\n", $index, $code, - $comment{$code}; - } -} - -print FILE "};\n"; -close(FILE); - -$file = "utf8_to_shift_jis_2004_combined.map"; -open(FILE, "> $file") || die("cannot open $file"); -print FILE "/*\n"; -print FILE " * This file was generated by UCS_to_SHIFT_JIS_2004.pl\n"; -print FILE " */\n"; -print FILE -"static const pg_utf_to_local_combined ULmapSHIFT_JIS_2004_combined[] = {\n"; - -for $index (sort { $a cmp $b } keys(%array1)) -{ - $code = $array1{$index}; - $count1--; - if ($count1 == 0) - { - printf FILE " {0x%s, 0x%s, 0x%04x} /* %s */\n", substr($index, 0, 8), - substr($index, 8, 8), $code, $comment1{$index}; - } - else - { - printf FILE " {0x%s, 0x%s, 0x%04x}, /* %s */\n", - substr($index, 0, 8), substr($index, 8, 8), $code, - $comment1{$index}; - } -} - -print FILE "};\n"; -close(FILE); - -# then generate SHIFT_JIS_2004 --> UTF-8 table - -$in_file = "sjis-0213-2004-std.txt"; - -open(FILE, $in_file) || die("cannot open $in_file"); - -reset 'array'; -reset 'array1'; -reset 'comment'; -reset 'comment1'; - -while ($line = ) -{ - if ($line =~ /^0x(.*)[ \t]*U\+(.*)\+(.*)[ \t]*#(.*)$/) - { - $c = $1; - $u1 = $2; - $u2 = $3; - $rest = "U+" . $u1 . "+" . $u2 . $4; - $code = hex($c); - $ucs = hex($u1); - $utf1 = &ucs2utf($ucs); - $ucs = hex($u2); - $utf2 = &ucs2utf($ucs); - $str = sprintf "%08x%08x", $utf1, $utf2; - $array1{$code} = $str; - $comment1{$code} = $rest; - $count1++; - next; - } - elsif ($line =~ /^0x(.*)[ \t]*U\+(.*)[ \t]*#(.*)$/) - { - $c = $1; - $u = $2; - $rest = "U+" . $u . $3; - } - else - { - next; - } - - $ucs = hex($u); - $code = hex($c); - $utf = &ucs2utf($ucs); - if ($array{$code} ne "") - { - printf STDERR - "Warning: duplicate UTF8: %08x UCS: %04x Shift JIS: %04x\n", $utf, - $ucs, $code; - printf STDERR "Previous value: UTF8: %08x\n", $array{$utf}; - next; - } - $count++; - - $array{$code} = $utf; - $comment{$utf} = $rest; -} -close(FILE); - -$file = "shift_jis_2004_to_utf8.map"; -open(FILE, "> $file") || die("cannot open $file"); -print FILE "/*\n"; -print FILE " * This file was generated by UCS_to_SHIFTJIS_2004.pl\n"; -print FILE " */\n"; -print FILE "static const pg_local_to_utf LUmapSHIFT_JIS_2004[] = {\n"; - -for $index (sort { $a <=> $b } keys(%array)) -{ - $code = $array{$index}; - $count--; - if ($count == 0) - { - printf FILE " {0x%04x, 0x%08x} /* %s */\n", $index, $code, - $comment{$code}; - } - else - { - printf FILE " {0x%04x, 0x%08x}, /* %s */\n", $index, $code, - $comment{$code}; - } -} - -print FILE "};\n"; -close(FILE); - -$file = "shift_jis_2004_to_utf8_combined.map"; -open(FILE, "> $file") || die("cannot open $file"); -print FILE "/*\n"; -print FILE " * This file was generated by UCS_to_SHIFT_JIS_2004.pl\n"; -print FILE " */\n"; -print FILE -"static const pg_local_to_utf_combined LUmapSHIFT_JIS_2004_combined[] = {\n"; - -for $index (sort { $a <=> $b } keys(%array1)) -{ - $code = $array1{$index}; - $count1--; - if ($count1 == 0) - { - printf FILE " {0x%04x, 0x%s, 0x%s} /* %s */\n", $index, - substr($code, 0, 8), substr($code, 8, 8), $comment1{$index}; - } - else - { - printf FILE " {0x%04x, 0x%s, 0x%s}, /* %s */\n", $index, - substr($code, 0, 8), substr($code, 8, 8), $comment1{$index}; + # non-combined characters + my ($c, $u, $rest) = ($1, $2, "U+" . $2 . $3); + my $ucs = hex($u); + my $code = hex($c); + my $direction; + + if ($code < 0x80 && $ucs < 0x80) + { + next; + } + elsif ($code < 0x80) + { + $direction = 'from_unicode'; + } + elsif ($ucs < 0x80) + { + $direction = 'to_unicode'; + } + else + { + $direction = 'both'; + } + + push @mapping, { + code => $code, + ucs => $ucs, + comment => $rest, + direction => $direction + }; } } +close($in); -print FILE "};\n"; -close(FILE); +print_tables("SHIFT_JIS_2004", \@mapping, 1); diff --git a/src/backend/utils/mb/Unicode/UCS_to_SJIS.pl b/src/backend/utils/mb/Unicode/UCS_to_SJIS.pl index 10e54b157d..74e206fc86 100755 --- a/src/backend/utils/mb/Unicode/UCS_to_SJIS.pl +++ b/src/backend/utils/mb/Unicode/UCS_to_SJIS.pl @@ -1,141 +1,48 @@ #! /usr/bin/perl # -# Copyright (c) 2001-2016, PostgreSQL Global Development Group +# Copyright (c) 2001-2017, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/UCS_to_SJIS.pl # -# Generate UTF-8 <--> SJIS code conversion tables from -# map files provided by Unicode organization. -# Unfortunately it is prohibited by the organization -# to distribute the map files. So if you try to use this script, -# you have to obtain SHIFTJIS.TXT from -# the organization's ftp site. -# -# SHIFTJIS.TXT format: -# SHIFTJIS code in hex -# UCS-2 code in hex -# # and Unicode name (not used in this script) -# Warning: SHIFTJIS.TXT contains only JIS0201 and JIS0208. no JIS0212. - -require "ucs2utf.pl"; - -# first generate UTF-8 --> SJIS table - -$in_file = "CP932.TXT"; -$count = 0; - -open(FILE, $in_file) || die("cannot open $in_file"); - -while () -{ - chop; - if (/^#/) - { - next; - } - ($c, $u, $rest) = split; - $ucs = hex($u); - $code = hex($c); - if ($code >= 0x80 && $ucs >= 0x0080) - { - $utf = &ucs2utf($ucs); - if ((($code >= 0xed40) && ($code <= 0xeefc)) - || ( ($code >= 0x8754) - && ($code <= 0x875d)) - || ($code == 0x878a) - || ($code == 0x8782) - || ($code == 0x8784) - || ($code == 0xfa5b) - || ($code == 0xfa54) - || ( ($code >= 0x8790) - && ($code <= 0x8792)) - || ( ($code >= 0x8795) - && ($code <= 0x8797)) - || ( ($code >= 0x879a) - && ($code <= 0x879c))) - { - printf STDERR "Warning: duplicate UTF8: UCS=0x%04x SJIS=0x%04x\n", - $ucs, - $code; - next; - } - $count++; - $array{$utf} = $code; - } -} +# Generate UTF-8 <=> SJIS code conversion radix tree Generate UTF-8 +# <=> SJIS code conversion radix tree Unfortunately it is prohibited +# by the organization to distribute the map files. So if you try to +# use this script, you have to obtain CP932.TXT from the organization's +# ftp site. -close(FILE); +use strict; +require convutils; -$file = "utf8_to_sjis.map"; -open(FILE, "> $file") || die("cannot open $file"); +my $charset = read_source("CP932.TXT"); -print FILE "/* src/backend/utils/mb/Unicode/$file */\n\n"; -print FILE "static const pg_utf_to_local ULmapSJIS[ $count ] = {\n"; +# Drop these SJIS codes from the source for UTF8=>SJIS conversion +my @reject_sjis =( + 0xed40..0xeefc, 0x8754..0x875d, 0x878a, 0x8782, + 0x8784, 0xfa5b, 0xfa54, 0x8790..0x8792, 0x8795..0x8797, + 0x879a..0x879c +); -for $index (sort { $a <=> $b } keys(%array)) +foreach my $i (@$charset) { - $code = $array{$index}; - $count--; - if ($count == 0) - { - printf FILE " {0x%04x, 0x%04x}\n", $index, $code; - } - else - { - printf FILE " {0x%04x, 0x%04x},\n", $index, $code; - } -} - -print FILE "};\n"; -close(FILE); + my $code = $i->{code}; + my $ucs = $i->{ucs}; -# -# then generate SJIS --> UTF8 table -# - -open(FILE, $in_file) || die("cannot open $in_file"); - -reset 'array'; -$count = 0; - -while () -{ - chop; - if (/^#/) - { - next; - } - ($c, $u, $rest) = split; - $ucs = hex($u); - $code = hex($c); - if ($code >= 0x80 && $ucs >= 0x0080) - { - $utf = &ucs2utf($ucs); - $count++; - - $array{$code} = $utf; - } -} -close(FILE); - -$file = "sjis_to_utf8.map"; -open(FILE, "> $file") || die("cannot open $file"); - -print FILE "/* src/backend/utils/mb/Unicode/$file */\n\n"; -print FILE "static const pg_local_to_utf LUmapSJIS[ $count ] = {\n"; -for $index (sort { $a <=> $b } keys(%array)) -{ - $utf = $array{$index}; - $count--; - if ($count == 0) - { - printf FILE " {0x%04x, 0x%04x}\n", $index, $utf; - } - else + if (grep {$code == $_} @reject_sjis) { - printf FILE " {0x%04x, 0x%04x},\n", $index, $utf; + $i->{direction} = "to_unicode"; } } -print FILE "};\n"; -close(FILE); +# Add these UTF8->SJIS pairs to the table. +push @$charset, ( + {direction => "from_unicode", ucs => 0x00a2, code => 0x8191, comment => '# CENT SIGN'}, + {direction => "from_unicode", ucs => 0x00a3, code => 0x8192, comment => '# POUND SIGN'}, + {direction => "from_unicode", ucs => 0x00a5, code => 0x5c, comment => '# YEN SIGN'}, + {direction => "from_unicode", ucs => 0x00ac, code => 0x81ca, comment => '# NOT SIGN'}, + {direction => "from_unicode", ucs => 0x2016, code => 0x8161, comment => '# DOUBLE VERTICAL LINE'}, + {direction => "from_unicode", ucs => 0x203e, code => 0x7e, comment => '# OVERLINE'}, + {direction => "from_unicode", ucs => 0x2212, code => 0x817c, comment => '# MINUS SIGN'}, + {direction => "from_unicode", ucs => 0x301c, code => 0x8160, comment => '# WAVE DASH'} +); + +print_tables("SJIS", $charset); diff --git a/src/backend/utils/mb/Unicode/UCS_to_UHC.pl b/src/backend/utils/mb/Unicode/UCS_to_UHC.pl new file mode 100755 index 0000000000..45c6db538c --- /dev/null +++ b/src/backend/utils/mb/Unicode/UCS_to_UHC.pl @@ -0,0 +1,51 @@ +#! /usr/bin/perl +# +# Copyright (c) 2007-2017, PostgreSQL Global Development Group +# +# src/backend/utils/mb/Unicode/UCS_to_GB18030.pl +# +# Generate UTF-8 <--> UHC code conversion tables from +# "windows-949-2000.xml", obtained from +# http://source.icu-project.org/repos/icu/data/trunk/charset/data/xml/ +# +# The lines we care about in the source file look like +# +# where the "u" field is the Unicode code point in hex, +# and the "b" field is the hex byte sequence for UHC + +use strict; +require convutils; + +# Read the input + +my $in_file = "windows-949-2000.xml"; + +open(my $in, '<', $in_file) || die("cannot open $in_file"); + +my @mapping; + +while (<$in>) +{ + next if (!m/= 0x80 && $ucs >= 0x0080) + { + push @mapping, { + ucs => $ucs, + code => $code, + direction => 'both' + } + } +} +close($in); + +# One extra character that's not in the source file. +push @mapping, { direction => 'both', code => 0xa2e8, ucs => 0x327e, comment => 'CIRCLED HANGUL IEUNG U' }; + +print_tables("UHC", \@mapping); diff --git a/src/backend/utils/mb/Unicode/UCS_to_most.pl b/src/backend/utils/mb/Unicode/UCS_to_most.pl index d7ec8eff4a..acc03e3809 100755 --- a/src/backend/utils/mb/Unicode/UCS_to_most.pl +++ b/src/backend/utils/mb/Unicode/UCS_to_most.pl @@ -1,6 +1,6 @@ #! /usr/bin/perl # -# Copyright (c) 2001-2016, PostgreSQL Global Development Group +# Copyright (c) 2001-2017, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/UCS_to_most.pl # @@ -15,9 +15,10 @@ # UCS-2 code in hex # # and Unicode name (not used in this script) -require "ucs2utf.pl"; +use strict; +require convutils; -%filename = ( +my %filename = ( 'WIN866' => 'CP866.TXT', 'WIN874' => 'CP874.TXT', 'WIN1250' => 'CP1250.TXT', @@ -44,121 +45,14 @@ 'ISO8859_16' => '8859-16.TXT', 'KOI8R' => 'KOI8-R.TXT', 'KOI8U' => 'KOI8-U.TXT', - 'GBK' => 'CP936.TXT', - 'UHC' => 'CP949.TXT', - 'JOHAB' => 'JOHAB.TXT',); + 'GBK' => 'CP936.TXT'); -@charsets = keys(filename); -@charsets = @ARGV if scalar(@ARGV); -foreach $charset (@charsets) -{ - - # - # first, generate UTF8-> charset table - # - $in_file = $filename{$charset}; - - open(FILE, $in_file) || die("cannot open $in_file"); - - reset 'array'; - - while () - { - chop; - if (/^#/) - { - next; - } - ($c, $u, $rest) = split; - $ucs = hex($u); - $code = hex($c); - if ($code >= 0x80 && $ucs >= 0x0080) - { - $utf = &ucs2utf($ucs); - if ($array{$utf} ne "") - { - printf STDERR "Warning: duplicate UTF8: %04x\n", $ucs; - next; - } - $count++; - $array{$utf} = $code; - } - } - close(FILE); - - $file = lc("utf8_to_${charset}.map"); - open(FILE, "> $file") || die("cannot open $file"); - - print FILE "/* src/backend/utils/mb/Unicode/$file */\n\n"; - print FILE "static const pg_utf_to_local ULmap${charset}[ $count ] = {\n"; +# make maps for all encodings if not specified +my @charsets = (scalar(@ARGV) > 0) ? @ARGV : keys(%filename); - for $index (sort { $a <=> $b } keys(%array)) - { - $code = $array{$index}; - $count--; - if ($count == 0) - { - printf FILE " {0x%04x, 0x%04x}\n", $index, $code; - } - else - { - printf FILE " {0x%04x, 0x%04x},\n", $index, $code; - } - } - - print FILE "};\n"; - close(FILE); - - # - # then generate character set code ->UTF8 table - # - open(FILE, $in_file) || die("cannot open $in_file"); - - reset 'array'; - - while () - { - chop; - if (/^#/) - { - next; - } - ($c, $u, $rest) = split; - $ucs = hex($u); - $code = hex($c); - if ($code >= 0x80 && $ucs >= 0x0080) - { - $utf = &ucs2utf($ucs); - if ($array{$code} ne "") - { - printf STDERR "Warning: duplicate UTF8: %04x\n", $ucs; - next; - } - $count++; - $array{$code} = $utf; - } - } - close(FILE); - - $file = lc("${charset}_to_utf8.map"); - open(FILE, "> $file") || die("cannot open $file"); - - print FILE "/* src/backend/utils/mb/Unicode/$file */\n\n"; - print FILE "static const pg_local_to_utf LUmap${charset}[ $count ] = {\n"; - for $index (sort { $a <=> $b } keys(%array)) - { - $utf = $array{$index}; - $count--; - if ($count == 0) - { - printf FILE " {0x%04x, 0x%04x}\n", $index, $utf; - } - else - { - printf FILE " {0x%04x, 0x%04x},\n", $index, $utf; - } - } +foreach my $charset (@charsets) +{ + my $mapping = &read_source($filename{$charset}); - print FILE "};\n"; - close(FILE); + print_tables($charset, $mapping); } diff --git a/src/backend/utils/mb/Unicode/convutils.pm b/src/backend/utils/mb/Unicode/convutils.pm new file mode 100644 index 0000000000..7adcee4857 --- /dev/null +++ b/src/backend/utils/mb/Unicode/convutils.pm @@ -0,0 +1,282 @@ +# +# Copyright (c) 2001-2017, PostgreSQL Global Development Group +# +# src/backend/utils/mb/Unicode/convutils.pm + +use strict; + +####################################################################### +# convert UCS-4 to UTF-8 +# +sub ucs2utf +{ + my ($ucs) = @_; + my $utf; + + if ($ucs <= 0x007f) + { + $utf = $ucs; + } + elsif ($ucs > 0x007f && $ucs <= 0x07ff) + { + $utf = (($ucs & 0x003f) | 0x80) | ((($ucs >> 6) | 0xc0) << 8); + } + elsif ($ucs > 0x07ff && $ucs <= 0xffff) + { + $utf = + ((($ucs >> 12) | 0xe0) << 16) | + (((($ucs & 0x0fc0) >> 6) | 0x80) << 8) | (($ucs & 0x003f) | 0x80); + } + else + { + $utf = + ((($ucs >> 18) | 0xf0) << 24) | + (((($ucs & 0x3ffff) >> 12) | 0x80) << 16) | + (((($ucs & 0x0fc0) >> 6) | 0x80) << 8) | (($ucs & 0x003f) | 0x80); + } + return ($utf); +} + +####################################################################### +# read_source - common routine to read source file +# +# fname ; input file name +sub read_source +{ + my ($fname) = @_; + my @r; + + open(my $in, '<', $fname) || die("cannot open $fname"); + + while (<$in>) + { + next if (/^#/); + chop; + + next if (/^$/); # Ignore empty lines + + next if (/^0x([0-9A-F]+)\s+(#.*)$/); + + # Skip the first column for JIS0208.TXT + if (!/^0x([0-9A-Fa-f]+)\s+0x([0-9A-Fa-f]+)\s+(?:0x([0-9A-Fa-f]+)\s+)?(#.*)$/) + { + print STDERR "READ ERROR at line $. in $fname: $_\n"; + exit; + } + my $out = {f => $fname, l => $., + code => hex($1), + ucs => hex($2), + comment => $4, + direction => "both" + }; + + # Ignore pure ASCII mappings. PostgreSQL character conversion code + # never even passes these to the conversion code. + next if ($out->{code} < 0x80 || $out->{ucs} < 0x80); + + push(@r, $out); + } + close($in); + + return \@r; +} + +################################################################## +# print_tables : output mapping tables +# +# Arguments: +# charset - string name of the character set. +# table - mapping table (see format below) +# verbose - if 1, output comment on each line, +# if 2, also output source file name and number +# +# +# +# Mapping table format: +# +# Mapping table is a list of hashes. Each hash has the following fields: +# direction - Direction: 'both', 'from_unicode' or 'to_unicode' +# ucs - Unicode code point +# ucs_second - Second Unicode code point, if this is a "combined" character. +# code - Byte sequence in the "other" character set, as an integer +# comment - Text representation of the character +# f - Source filename +# l - Line number in source file +# +# +sub print_tables +{ + my ($charset, $table, $verbose) = @_; + + # Build an array with only the to-UTF8 direction mappings + my @to_unicode; + my @to_unicode_combined; + my @from_unicode; + my @from_unicode_combined; + + foreach my $i (@$table) + { + if (defined $i->{ucs_second}) + { + my $entry = {utf8 => ucs2utf($i->{ucs}), + utf8_second => ucs2utf($i->{ucs_second}), + code => $i->{code}, + comment => $i->{comment}, + f => $i->{f}, l => $i->{l}}; + if ($i->{direction} eq "both" || $i->{direction} eq "to_unicode") + { + push @to_unicode_combined, $entry; + } + if ($i->{direction} eq "both" || $i->{direction} eq "from_unicode") + { + push @from_unicode_combined, $entry; + } + } + else + { + my $entry = {utf8 => ucs2utf($i->{ucs}), + code => $i->{code}, + comment => $i->{comment}, + f => $i->{f}, l => $i->{l}}; + if ($i->{direction} eq "both" || $i->{direction} eq "to_unicode") + { + push @to_unicode, $entry; + } + if ($i->{direction} eq "both" || $i->{direction} eq "from_unicode") + { + push @from_unicode, $entry; + } + } + } + + print_to_utf8_map($charset, \@to_unicode, $verbose); + print_to_utf8_combined_map($charset, \@to_unicode_combined, $verbose) if (scalar @to_unicode_combined > 0); + print_from_utf8_map($charset, \@from_unicode, $verbose); + print_from_utf8_combined_map($charset, \@from_unicode_combined, $verbose) if (scalar @from_unicode_combined > 0); +} + +sub print_from_utf8_map +{ + my ($charset, $table, $verbose) = @_; + + my $last_comment = ""; + + my $fname = lc("utf8_to_${charset}.map"); + print "- Writing UTF8=>${charset} conversion table: $fname\n"; + open(my $out, '>', $fname) || die "cannot open output file : $fname\n"; + printf($out "/* src/backend/utils/mb/Unicode/$fname */\n\n". + "static const pg_utf_to_local ULmap${charset}[ %d ] = {", + scalar(@$table)); + my $first = 1; + foreach my $i (sort {$$a{utf8} <=> $$b{utf8}} @$table) + { + print($out ",") if (!$first); + $first = 0; + print($out "\t/* $last_comment */") if ($verbose); + + printf($out "\n {0x%04x, 0x%04x}", $$i{utf8}, $$i{code}); + if ($verbose >= 2) + { + $last_comment = "$$i{f}:$$i{l} $$i{comment}"; + } + else + { + $last_comment = $$i{comment}; + } + } + print($out "\t/* $last_comment */") if ($verbose); + print $out "\n};\n"; + close($out); +} + +sub print_from_utf8_combined_map +{ + my ($charset, $table, $verbose) = @_; + + my $last_comment = ""; + + my $fname = lc("utf8_to_${charset}_combined.map"); + print "- Writing UTF8=>${charset} conversion table: $fname\n"; + open(my $out, '>', $fname) || die "cannot open output file : $fname\n"; + printf($out "/* src/backend/utils/mb/Unicode/$fname */\n\n". + "static const pg_utf_to_local_combined ULmap${charset}_combined[ %d ] = {", + scalar(@$table)); + my $first = 1; + foreach my $i (sort {$$a{utf8} <=> $$b{utf8}} @$table) + { + print($out ",") if (!$first); + $first = 0; + print($out "\t/* $last_comment */") if ($verbose); + + printf($out "\n {0x%08x, 0x%08x, 0x%04x}", $$i{utf8}, $$i{utf8_second}, $$i{code}); + $last_comment = "$$i{comment}"; + } + print($out "\t/* $last_comment */") if ($verbose); + print $out "\n};\n"; + close($out); +} + +sub print_to_utf8_map +{ + my ($charset, $table, $verbose) = @_; + + my $last_comment = ""; + + my $fname = lc("${charset}_to_utf8.map"); + + print "- Writing ${charset}=>UTF8 conversion table: $fname\n"; + open(my $out, '>', $fname) || die "cannot open output file : $fname\n"; + printf($out "/* src/backend/utils/mb/Unicode/${fname} */\n\n". + "static const pg_local_to_utf LUmap${charset}[ %d ] = {", + scalar(@$table)); + my $first = 1; + foreach my $i (sort {$$a{code} <=> $$b{code}} @$table) + { + print($out ",") if (!$first); + $first = 0; + print($out "\t/* $last_comment */") if ($verbose); + + printf($out "\n {0x%04x, 0x%x}", $$i{code}, $$i{utf8}); + if ($verbose >= 2) + { + $last_comment = "$$i{f}:$$i{l} $$i{comment}"; + } + else + { + $last_comment = $$i{comment}; + } + } + print($out "\t/* $last_comment */") if ($verbose); + print $out "\n};\n"; + close($out); +} + +sub print_to_utf8_combined_map +{ + my ($charset, $table, $verbose) = @_; + + my $last_comment = ""; + + my $fname = lc("${charset}_to_utf8_combined.map"); + + print "- Writing ${charset}=>UTF8 conversion table: $fname\n"; + open(my $out, '>', $fname) || die "cannot open output file : $fname\n"; + printf($out "/* src/backend/utils/mb/Unicode/${fname} */\n\n". + "static const pg_local_to_utf_combined LUmap${charset}_combined[ %d ] = {", + scalar(@$table)); + my $first = 1; + foreach my $i (sort {$$a{code} <=> $$b{code}} @$table) + { + print($out ",") if (!$first); + $first = 0; + print($out "\t/* $last_comment */") if ($verbose); + + printf($out "\n {0x%04x, 0x%08x, 0x%08x}", $$i{code}, $$i{utf8}, $$i{utf8_second}); + $last_comment = "$$i{comment}"; + } + print($out "\t/* $last_comment */") if ($verbose); + print $out "\n};\n"; + close($out); +} + +1; diff --git a/src/backend/utils/mb/Unicode/euc_jis_2004_to_utf8.map b/src/backend/utils/mb/Unicode/euc_jis_2004_to_utf8.map index 59a1d94635..33fd42ac46 100644 --- a/src/backend/utils/mb/Unicode/euc_jis_2004_to_utf8.map +++ b/src/backend/utils/mb/Unicode/euc_jis_2004_to_utf8.map @@ -1,11436 +1,11307 @@ -/* - * This file was generated by UCS_to_EUC_JIS_2004.pl - */ -static const pg_local_to_utf LUmapEUC_JIS_2004[] = { - {0x000000, 0x00000000}, /* U+0000 */ - {0x000001, 0x00000001}, /* U+0001 */ - {0x000002, 0x00000002}, /* U+0002 */ - {0x000003, 0x00000003}, /* U+0003 */ - {0x000004, 0x00000004}, /* U+0004 */ - {0x000005, 0x00000005}, /* U+0005 */ - {0x000006, 0x00000006}, /* U+0006 */ - {0x000007, 0x00000007}, /* U+0007 */ - {0x000008, 0x00000008}, /* U+0008 */ - {0x000009, 0x00000009}, /* U+0009 */ - {0x00000a, 0x0000000a}, /* U+000A */ - {0x00000b, 0x0000000b}, /* U+000B */ - {0x00000c, 0x0000000c}, /* U+000C */ - {0x00000d, 0x0000000d}, /* U+000D */ - {0x00000e, 0x0000000e}, /* U+000E */ - {0x00000f, 0x0000000f}, /* U+000F */ - {0x000010, 0x00000010}, /* U+0010 */ - {0x000011, 0x00000011}, /* U+0011 */ - {0x000012, 0x00000012}, /* U+0012 */ - {0x000013, 0x00000013}, /* U+0013 */ - {0x000014, 0x00000014}, /* U+0014 */ - {0x000015, 0x00000015}, /* U+0015 */ - {0x000016, 0x00000016}, /* U+0016 */ - {0x000017, 0x00000017}, /* U+0017 */ - {0x000018, 0x00000018}, /* U+0018 */ - {0x000019, 0x00000019}, /* U+0019 */ - {0x00001a, 0x0000001a}, /* U+001A */ - {0x00001b, 0x0000001b}, /* U+001B */ - {0x00001c, 0x0000001c}, /* U+001C */ - {0x00001d, 0x0000001d}, /* U+001D */ - {0x00001e, 0x0000001e}, /* U+001E */ - {0x00001f, 0x0000001f}, /* U+001F */ - {0x000020, 0x00000020}, /* U+0020 SPACE */ - {0x000021, 0x00000021}, /* U+0021 EXCLAMATION MARK */ - {0x000022, 0x00000022}, /* U+0022 QUOTATION MARK */ - {0x000023, 0x00000023}, /* U+0023 NUMBER SIGN */ - {0x000024, 0x00000024}, /* U+0024 DOLLAR SIGN */ - {0x000025, 0x00000025}, /* U+0025 PERCENT SIGN */ - {0x000026, 0x00000026}, /* U+0026 AMPERSAND */ - {0x000027, 0x00000027}, /* U+0027 APOSTROPHE */ - {0x000028, 0x00000028}, /* U+0028 LEFT PARENTHESIS */ - {0x000029, 0x00000029}, /* U+0029 RIGHT PARENTHESIS */ - {0x00002a, 0x0000002a}, /* U+002A ASTERISK */ - {0x00002b, 0x0000002b}, /* U+002B PLUS SIGN */ - {0x00002c, 0x0000002c}, /* U+002C COMMA */ - {0x00002d, 0x0000002d}, /* U+002D HYPHEN-MINUS */ - {0x00002e, 0x0000002e}, /* U+002E FULL STOP */ - {0x00002f, 0x0000002f}, /* U+002F SOLIDUS */ - {0x000030, 0x00000030}, /* U+0030 DIGIT ZERO */ - {0x000031, 0x00000031}, /* U+0031 DIGIT ONE */ - {0x000032, 0x00000032}, /* U+0032 DIGIT TWO */ - {0x000033, 0x00000033}, /* U+0033 DIGIT THREE */ - {0x000034, 0x00000034}, /* U+0034 DIGIT FOUR */ - {0x000035, 0x00000035}, /* U+0035 DIGIT FIVE */ - {0x000036, 0x00000036}, /* U+0036 DIGIT SIX */ - {0x000037, 0x00000037}, /* U+0037 DIGIT SEVEN */ - {0x000038, 0x00000038}, /* U+0038 DIGIT EIGHT */ - {0x000039, 0x00000039}, /* U+0039 DIGIT NINE */ - {0x00003a, 0x0000003a}, /* U+003A COLON */ - {0x00003b, 0x0000003b}, /* U+003B SEMICOLON */ - {0x00003c, 0x0000003c}, /* U+003C LESS-THAN SIGN */ - {0x00003d, 0x0000003d}, /* U+003D EQUALS SIGN */ - {0x00003e, 0x0000003e}, /* U+003E GREATER-THAN SIGN */ - {0x00003f, 0x0000003f}, /* U+003F QUESTION MARK */ - {0x000040, 0x00000040}, /* U+0040 COMMERCIAL AT */ - {0x000041, 0x00000041}, /* U+0041 LATIN CAPITAL LETTER A */ - {0x000042, 0x00000042}, /* U+0042 LATIN CAPITAL LETTER B */ - {0x000043, 0x00000043}, /* U+0043 LATIN CAPITAL LETTER C */ - {0x000044, 0x00000044}, /* U+0044 LATIN CAPITAL LETTER D */ - {0x000045, 0x00000045}, /* U+0045 LATIN CAPITAL LETTER E */ - {0x000046, 0x00000046}, /* U+0046 LATIN CAPITAL LETTER F */ - {0x000047, 0x00000047}, /* U+0047 LATIN CAPITAL LETTER G */ - {0x000048, 0x00000048}, /* U+0048 LATIN CAPITAL LETTER H */ - {0x000049, 0x00000049}, /* U+0049 LATIN CAPITAL LETTER I */ - {0x00004a, 0x0000004a}, /* U+004A LATIN CAPITAL LETTER J */ - {0x00004b, 0x0000004b}, /* U+004B LATIN CAPITAL LETTER K */ - {0x00004c, 0x0000004c}, /* U+004C LATIN CAPITAL LETTER L */ - {0x00004d, 0x0000004d}, /* U+004D LATIN CAPITAL LETTER M */ - {0x00004e, 0x0000004e}, /* U+004E LATIN CAPITAL LETTER N */ - {0x00004f, 0x0000004f}, /* U+004F LATIN CAPITAL LETTER O */ - {0x000050, 0x00000050}, /* U+0050 LATIN CAPITAL LETTER P */ - {0x000051, 0x00000051}, /* U+0051 LATIN CAPITAL LETTER Q */ - {0x000052, 0x00000052}, /* U+0052 LATIN CAPITAL LETTER R */ - {0x000053, 0x00000053}, /* U+0053 LATIN CAPITAL LETTER S */ - {0x000054, 0x00000054}, /* U+0054 LATIN CAPITAL LETTER T */ - {0x000055, 0x00000055}, /* U+0055 LATIN CAPITAL LETTER U */ - {0x000056, 0x00000056}, /* U+0056 LATIN CAPITAL LETTER V */ - {0x000057, 0x00000057}, /* U+0057 LATIN CAPITAL LETTER W */ - {0x000058, 0x00000058}, /* U+0058 LATIN CAPITAL LETTER X */ - {0x000059, 0x00000059}, /* U+0059 LATIN CAPITAL LETTER Y */ - {0x00005a, 0x0000005a}, /* U+005A LATIN CAPITAL LETTER Z */ - {0x00005b, 0x0000005b}, /* U+005B LEFT SQUARE BRACKET */ - {0x00005c, 0x0000005c}, /* U+005C REVERSE SOLIDUS */ - {0x00005d, 0x0000005d}, /* U+005D RIGHT SQUARE BRACKET */ - {0x00005e, 0x0000005e}, /* U+005E CIRCUMFLEX ACCENT */ - {0x00005f, 0x0000005f}, /* U+005F LOW LINE */ - {0x000060, 0x00000060}, /* U+0060 GRAVE ACCENT */ - {0x000061, 0x00000061}, /* U+0061 LATIN SMALL LETTER A */ - {0x000062, 0x00000062}, /* U+0062 LATIN SMALL LETTER B */ - {0x000063, 0x00000063}, /* U+0063 LATIN SMALL LETTER C */ - {0x000064, 0x00000064}, /* U+0064 LATIN SMALL LETTER D */ - {0x000065, 0x00000065}, /* U+0065 LATIN SMALL LETTER E */ - {0x000066, 0x00000066}, /* U+0066 LATIN SMALL LETTER F */ - {0x000067, 0x00000067}, /* U+0067 LATIN SMALL LETTER G */ - {0x000068, 0x00000068}, /* U+0068 LATIN SMALL LETTER H */ - {0x000069, 0x00000069}, /* U+0069 LATIN SMALL LETTER I */ - {0x00006a, 0x0000006a}, /* U+006A LATIN SMALL LETTER J */ - {0x00006b, 0x0000006b}, /* U+006B LATIN SMALL LETTER K */ - {0x00006c, 0x0000006c}, /* U+006C LATIN SMALL LETTER L */ - {0x00006d, 0x0000006d}, /* U+006D LATIN SMALL LETTER M */ - {0x00006e, 0x0000006e}, /* U+006E LATIN SMALL LETTER N */ - {0x00006f, 0x0000006f}, /* U+006F LATIN SMALL LETTER O */ - {0x000070, 0x00000070}, /* U+0070 LATIN SMALL LETTER P */ - {0x000071, 0x00000071}, /* U+0071 LATIN SMALL LETTER Q */ - {0x000072, 0x00000072}, /* U+0072 LATIN SMALL LETTER R */ - {0x000073, 0x00000073}, /* U+0073 LATIN SMALL LETTER S */ - {0x000074, 0x00000074}, /* U+0074 LATIN SMALL LETTER T */ - {0x000075, 0x00000075}, /* U+0075 LATIN SMALL LETTER U */ - {0x000076, 0x00000076}, /* U+0076 LATIN SMALL LETTER V */ - {0x000077, 0x00000077}, /* U+0077 LATIN SMALL LETTER W */ - {0x000078, 0x00000078}, /* U+0078 LATIN SMALL LETTER X */ - {0x000079, 0x00000079}, /* U+0079 LATIN SMALL LETTER Y */ - {0x00007a, 0x0000007a}, /* U+007A LATIN SMALL LETTER Z */ - {0x00007b, 0x0000007b}, /* U+007B LEFT CURLY BRACKET */ - {0x00007c, 0x0000007c}, /* U+007C VERTICAL LINE */ - {0x00007d, 0x0000007d}, /* U+007D RIGHT CURLY BRACKET */ - {0x00007e, 0x0000007e}, /* U+007E TILDE */ - {0x00007f, 0x0000007f}, /* U+007F */ - {0x000080, 0x0000c280}, /* U+0080 */ - {0x000081, 0x0000c281}, /* U+0081 */ - {0x000082, 0x0000c282}, /* U+0082 */ - {0x000083, 0x0000c283}, /* U+0083 */ - {0x000084, 0x0000c284}, /* U+0084 */ - {0x000085, 0x0000c285}, /* U+0085 */ - {0x000086, 0x0000c286}, /* U+0086 */ - {0x000087, 0x0000c287}, /* U+0087 */ - {0x000088, 0x0000c288}, /* U+0088 */ - {0x000089, 0x0000c289}, /* U+0089 */ - {0x00008a, 0x0000c28a}, /* U+008A */ - {0x00008b, 0x0000c28b}, /* U+008B */ - {0x00008c, 0x0000c28c}, /* U+008C */ - {0x00008d, 0x0000c28d}, /* U+008D */ - {0x00008e, 0x0000c28e}, /* U+008E */ - {0x00008f, 0x0000c28f}, /* U+008F */ - {0x000090, 0x0000c290}, /* U+0090 */ - {0x000091, 0x0000c291}, /* U+0091 */ - {0x000092, 0x0000c292}, /* U+0092 */ - {0x000093, 0x0000c293}, /* U+0093 */ - {0x000094, 0x0000c294}, /* U+0094 */ - {0x000095, 0x0000c295}, /* U+0095 */ - {0x000096, 0x0000c296}, /* U+0096 */ - {0x000097, 0x0000c297}, /* U+0097 */ - {0x000098, 0x0000c298}, /* U+0098 */ - {0x000099, 0x0000c299}, /* U+0099 */ - {0x00009a, 0x0000c29a}, /* U+009A */ - {0x00009b, 0x0000c29b}, /* U+009B */ - {0x00009c, 0x0000c29c}, /* U+009C */ - {0x00009d, 0x0000c29d}, /* U+009D */ - {0x00009e, 0x0000c29e}, /* U+009E */ - {0x00009f, 0x0000c29f}, /* U+009F */ - {0x008ea1, 0x00efbda1}, /* U+FF61 HALFWIDTH IDEOGRAPHIC FULL STOP */ - {0x008ea2, 0x00efbda2}, /* U+FF62 HALFWIDTH LEFT CORNER BRACKET */ - {0x008ea3, 0x00efbda3}, /* U+FF63 HALFWIDTH RIGHT CORNER BRACKET */ - {0x008ea4, 0x00efbda4}, /* U+FF64 HALFWIDTH IDEOGRAPHIC COMMA */ - {0x008ea5, 0x00efbda5}, /* U+FF65 HALFWIDTH KATAKANA MIDDLE DOT */ - {0x008ea6, 0x00efbda6}, /* U+FF66 HALFWIDTH KATAKANA LETTER WO */ - {0x008ea7, 0x00efbda7}, /* U+FF67 HALFWIDTH KATAKANA LETTER SMALL A */ - {0x008ea8, 0x00efbda8}, /* U+FF68 HALFWIDTH KATAKANA LETTER SMALL I */ - {0x008ea9, 0x00efbda9}, /* U+FF69 HALFWIDTH KATAKANA LETTER SMALL U */ - {0x008eaa, 0x00efbdaa}, /* U+FF6A HALFWIDTH KATAKANA LETTER SMALL E */ - {0x008eab, 0x00efbdab}, /* U+FF6B HALFWIDTH KATAKANA LETTER SMALL O */ - {0x008eac, 0x00efbdac}, /* U+FF6C HALFWIDTH KATAKANA LETTER SMALL YA */ - {0x008ead, 0x00efbdad}, /* U+FF6D HALFWIDTH KATAKANA LETTER SMALL YU */ - {0x008eae, 0x00efbdae}, /* U+FF6E HALFWIDTH KATAKANA LETTER SMALL YO */ - {0x008eaf, 0x00efbdaf}, /* U+FF6F HALFWIDTH KATAKANA LETTER SMALL TU */ - {0x008eb0, 0x00efbdb0}, /* U+FF70 HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK */ - {0x008eb1, 0x00efbdb1}, /* U+FF71 HALFWIDTH KATAKANA LETTER A */ - {0x008eb2, 0x00efbdb2}, /* U+FF72 HALFWIDTH KATAKANA LETTER I */ - {0x008eb3, 0x00efbdb3}, /* U+FF73 HALFWIDTH KATAKANA LETTER U */ - {0x008eb4, 0x00efbdb4}, /* U+FF74 HALFWIDTH KATAKANA LETTER E */ - {0x008eb5, 0x00efbdb5}, /* U+FF75 HALFWIDTH KATAKANA LETTER O */ - {0x008eb6, 0x00efbdb6}, /* U+FF76 HALFWIDTH KATAKANA LETTER KA */ - {0x008eb7, 0x00efbdb7}, /* U+FF77 HALFWIDTH KATAKANA LETTER KI */ - {0x008eb8, 0x00efbdb8}, /* U+FF78 HALFWIDTH KATAKANA LETTER KU */ - {0x008eb9, 0x00efbdb9}, /* U+FF79 HALFWIDTH KATAKANA LETTER KE */ - {0x008eba, 0x00efbdba}, /* U+FF7A HALFWIDTH KATAKANA LETTER KO */ - {0x008ebb, 0x00efbdbb}, /* U+FF7B HALFWIDTH KATAKANA LETTER SA */ - {0x008ebc, 0x00efbdbc}, /* U+FF7C HALFWIDTH KATAKANA LETTER SI */ - {0x008ebd, 0x00efbdbd}, /* U+FF7D HALFWIDTH KATAKANA LETTER SU */ - {0x008ebe, 0x00efbdbe}, /* U+FF7E HALFWIDTH KATAKANA LETTER SE */ - {0x008ebf, 0x00efbdbf}, /* U+FF7F HALFWIDTH KATAKANA LETTER SO */ - {0x008ec0, 0x00efbe80}, /* U+FF80 HALFWIDTH KATAKANA LETTER TA */ - {0x008ec1, 0x00efbe81}, /* U+FF81 HALFWIDTH KATAKANA LETTER TI */ - {0x008ec2, 0x00efbe82}, /* U+FF82 HALFWIDTH KATAKANA LETTER TU */ - {0x008ec3, 0x00efbe83}, /* U+FF83 HALFWIDTH KATAKANA LETTER TE */ - {0x008ec4, 0x00efbe84}, /* U+FF84 HALFWIDTH KATAKANA LETTER TO */ - {0x008ec5, 0x00efbe85}, /* U+FF85 HALFWIDTH KATAKANA LETTER NA */ - {0x008ec6, 0x00efbe86}, /* U+FF86 HALFWIDTH KATAKANA LETTER NI */ - {0x008ec7, 0x00efbe87}, /* U+FF87 HALFWIDTH KATAKANA LETTER NU */ - {0x008ec8, 0x00efbe88}, /* U+FF88 HALFWIDTH KATAKANA LETTER NE */ - {0x008ec9, 0x00efbe89}, /* U+FF89 HALFWIDTH KATAKANA LETTER NO */ - {0x008eca, 0x00efbe8a}, /* U+FF8A HALFWIDTH KATAKANA LETTER HA */ - {0x008ecb, 0x00efbe8b}, /* U+FF8B HALFWIDTH KATAKANA LETTER HI */ - {0x008ecc, 0x00efbe8c}, /* U+FF8C HALFWIDTH KATAKANA LETTER HU */ - {0x008ecd, 0x00efbe8d}, /* U+FF8D HALFWIDTH KATAKANA LETTER HE */ - {0x008ece, 0x00efbe8e}, /* U+FF8E HALFWIDTH KATAKANA LETTER HO */ - {0x008ecf, 0x00efbe8f}, /* U+FF8F HALFWIDTH KATAKANA LETTER MA */ - {0x008ed0, 0x00efbe90}, /* U+FF90 HALFWIDTH KATAKANA LETTER MI */ - {0x008ed1, 0x00efbe91}, /* U+FF91 HALFWIDTH KATAKANA LETTER MU */ - {0x008ed2, 0x00efbe92}, /* U+FF92 HALFWIDTH KATAKANA LETTER ME */ - {0x008ed3, 0x00efbe93}, /* U+FF93 HALFWIDTH KATAKANA LETTER MO */ - {0x008ed4, 0x00efbe94}, /* U+FF94 HALFWIDTH KATAKANA LETTER YA */ - {0x008ed5, 0x00efbe95}, /* U+FF95 HALFWIDTH KATAKANA LETTER YU */ - {0x008ed6, 0x00efbe96}, /* U+FF96 HALFWIDTH KATAKANA LETTER YO */ - {0x008ed7, 0x00efbe97}, /* U+FF97 HALFWIDTH KATAKANA LETTER RA */ - {0x008ed8, 0x00efbe98}, /* U+FF98 HALFWIDTH KATAKANA LETTER RI */ - {0x008ed9, 0x00efbe99}, /* U+FF99 HALFWIDTH KATAKANA LETTER RU */ - {0x008eda, 0x00efbe9a}, /* U+FF9A HALFWIDTH KATAKANA LETTER RE */ - {0x008edb, 0x00efbe9b}, /* U+FF9B HALFWIDTH KATAKANA LETTER RO */ - {0x008edc, 0x00efbe9c}, /* U+FF9C HALFWIDTH KATAKANA LETTER WA */ - {0x008edd, 0x00efbe9d}, /* U+FF9D HALFWIDTH KATAKANA LETTER N */ - {0x008ede, 0x00efbe9e}, /* U+FF9E HALFWIDTH KATAKANA VOICED SOUND MARK */ - {0x008edf, 0x00efbe9f}, /* U+FF9F HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK */ - {0x00a1a1, 0x00e38080}, /* U+3000 IDEOGRAPHIC SPACE */ - {0x00a1a2, 0x00e38081}, /* U+3001 IDEOGRAPHIC COMMA */ - {0x00a1a3, 0x00e38082}, /* U+3002 IDEOGRAPHIC FULL STOP */ - {0x00a1a4, 0x00efbc8c}, /* U+FF0C FULLWIDTH COMMA */ - {0x00a1a5, 0x00efbc8e}, /* U+FF0E FULLWIDTH FULL STOP */ - {0x00a1a6, 0x00e383bb}, /* U+30FB KATAKANA MIDDLE DOT */ - {0x00a1a7, 0x00efbc9a}, /* U+FF1A FULLWIDTH COLON */ - {0x00a1a8, 0x00efbc9b}, /* U+FF1B FULLWIDTH SEMICOLON */ - {0x00a1a9, 0x00efbc9f}, /* U+FF1F FULLWIDTH QUESTION MARK */ - {0x00a1aa, 0x00efbc81}, /* U+FF01 FULLWIDTH EXCLAMATION MARK */ - {0x00a1ab, 0x00e3829b}, /* U+309B KATAKANA-HIRAGANA VOICED SOUND MARK */ - {0x00a1ac, 0x00e3829c}, /* U+309C KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ - {0x00a1ad, 0x0000c2b4}, /* U+00B4 ACUTE ACCENT */ - {0x00a1ae, 0x00efbd80}, /* U+FF40 FULLWIDTH GRAVE ACCENT */ - {0x00a1af, 0x0000c2a8}, /* U+00A8 DIAERESIS */ - {0x00a1b0, 0x00efbcbe}, /* U+FF3E FULLWIDTH CIRCUMFLEX ACCENT */ - {0x00a1b1, 0x00e280be}, /* U+203E OVERLINE Windows: U+FFE3 */ - {0x00a1b2, 0x00efbcbf}, /* U+FF3F FULLWIDTH LOW LINE */ - {0x00a1b3, 0x00e383bd}, /* U+30FD KATAKANA ITERATION MARK */ - {0x00a1b4, 0x00e383be}, /* U+30FE KATAKANA VOICED ITERATION MARK */ - {0x00a1b5, 0x00e3829d}, /* U+309D HIRAGANA ITERATION MARK */ - {0x00a1b6, 0x00e3829e}, /* U+309E HIRAGANA VOICED ITERATION MARK */ - {0x00a1b7, 0x00e38083}, /* U+3003 DITTO MARK */ - {0x00a1b8, 0x00e4bb9d}, /* U+4EDD */ - {0x00a1b9, 0x00e38085}, /* U+3005 IDEOGRAPHIC ITERATION MARK */ - {0x00a1ba, 0x00e38086}, /* U+3006 IDEOGRAPHIC CLOSING MARK */ - {0x00a1bb, 0x00e38087}, /* U+3007 IDEOGRAPHIC NUMBER ZERO */ - {0x00a1bc, 0x00e383bc}, /* U+30FC KATAKANA-HIRAGANA PROLONGED SOUND MARK */ - {0x00a1bd, 0x00e28094}, /* U+2014 EM DASH Windows: U+2015 */ - {0x00a1be, 0x00e28090}, /* U+2010 HYPHEN */ - {0x00a1bf, 0x00efbc8f}, /* U+FF0F FULLWIDTH SOLIDUS */ - {0x00a1c0, 0x00efbcbc}, /* U+FF3C FULLWIDTH REVERSE SOLIDUS */ - {0x00a1c1, 0x00e3809c}, /* U+301C WAVE DASH Windows: U+FF5E */ - {0x00a1c2, 0x00e28096}, /* U+2016 DOUBLE VERTICAL LINE Windows: U+2225 */ - {0x00a1c3, 0x00efbd9c}, /* U+FF5C FULLWIDTH VERTICAL LINE */ - {0x00a1c4, 0x00e280a6}, /* U+2026 HORIZONTAL ELLIPSIS */ - {0x00a1c5, 0x00e280a5}, /* U+2025 TWO DOT LEADER */ - {0x00a1c6, 0x00e28098}, /* U+2018 LEFT SINGLE QUOTATION MARK */ - {0x00a1c7, 0x00e28099}, /* U+2019 RIGHT SINGLE QUOTATION MARK */ - {0x00a1c8, 0x00e2809c}, /* U+201C LEFT DOUBLE QUOTATION MARK */ - {0x00a1c9, 0x00e2809d}, /* U+201D RIGHT DOUBLE QUOTATION MARK */ - {0x00a1ca, 0x00efbc88}, /* U+FF08 FULLWIDTH LEFT PARENTHESIS */ - {0x00a1cb, 0x00efbc89}, /* U+FF09 FULLWIDTH RIGHT PARENTHESIS */ - {0x00a1cc, 0x00e38094}, /* U+3014 LEFT TORTOISE SHELL BRACKET */ - {0x00a1cd, 0x00e38095}, /* U+3015 RIGHT TORTOISE SHELL BRACKET */ - {0x00a1ce, 0x00efbcbb}, /* U+FF3B FULLWIDTH LEFT SQUARE BRACKET */ - {0x00a1cf, 0x00efbcbd}, /* U+FF3D FULLWIDTH RIGHT SQUARE BRACKET */ - {0x00a1d0, 0x00efbd9b}, /* U+FF5B FULLWIDTH LEFT CURLY BRACKET */ - {0x00a1d1, 0x00efbd9d}, /* U+FF5D FULLWIDTH RIGHT CURLY BRACKET */ - {0x00a1d2, 0x00e38088}, /* U+3008 LEFT ANGLE BRACKET */ - {0x00a1d3, 0x00e38089}, /* U+3009 RIGHT ANGLE BRACKET */ - {0x00a1d4, 0x00e3808a}, /* U+300A LEFT DOUBLE ANGLE BRACKET */ - {0x00a1d5, 0x00e3808b}, /* U+300B RIGHT DOUBLE ANGLE BRACKET */ - {0x00a1d6, 0x00e3808c}, /* U+300C LEFT CORNER BRACKET */ - {0x00a1d7, 0x00e3808d}, /* U+300D RIGHT CORNER BRACKET */ - {0x00a1d8, 0x00e3808e}, /* U+300E LEFT WHITE CORNER BRACKET */ - {0x00a1d9, 0x00e3808f}, /* U+300F RIGHT WHITE CORNER BRACKET */ - {0x00a1da, 0x00e38090}, /* U+3010 LEFT BLACK LENTICULAR BRACKET */ - {0x00a1db, 0x00e38091}, /* U+3011 RIGHT BLACK LENTICULAR BRACKET */ - {0x00a1dc, 0x00efbc8b}, /* U+FF0B FULLWIDTH PLUS SIGN */ - {0x00a1dd, 0x00e28892}, /* U+2212 MINUS SIGN Windows: U+FF0D */ - {0x00a1de, 0x0000c2b1}, /* U+00B1 PLUS-MINUS SIGN */ - {0x00a1df, 0x0000c397}, /* U+00D7 MULTIPLICATION SIGN */ - {0x00a1e0, 0x0000c3b7}, /* U+00F7 DIVISION SIGN */ - {0x00a1e1, 0x00efbc9d}, /* U+FF1D FULLWIDTH EQUALS SIGN */ - {0x00a1e2, 0x00e289a0}, /* U+2260 NOT EQUAL TO */ - {0x00a1e3, 0x00efbc9c}, /* U+FF1C FULLWIDTH LESS-THAN SIGN */ - {0x00a1e4, 0x00efbc9e}, /* U+FF1E FULLWIDTH GREATER-THAN SIGN */ - {0x00a1e5, 0x00e289a6}, /* U+2266 LESS-THAN OVER EQUAL TO */ - {0x00a1e6, 0x00e289a7}, /* U+2267 GREATER-THAN OVER EQUAL TO */ - {0x00a1e7, 0x00e2889e}, /* U+221E INFINITY */ - {0x00a1e8, 0x00e288b4}, /* U+2234 THEREFORE */ - {0x00a1e9, 0x00e29982}, /* U+2642 MALE SIGN */ - {0x00a1ea, 0x00e29980}, /* U+2640 FEMALE SIGN */ - {0x00a1eb, 0x0000c2b0}, /* U+00B0 DEGREE SIGN */ - {0x00a1ec, 0x00e280b2}, /* U+2032 PRIME */ - {0x00a1ed, 0x00e280b3}, /* U+2033 DOUBLE PRIME */ - {0x00a1ee, 0x00e28483}, /* U+2103 DEGREE CELSIUS */ - {0x00a1ef, 0x0000c2a5}, /* U+00A5 YEN SIGN Windows: U+FFE5 */ - {0x00a1f0, 0x00efbc84}, /* U+FF04 FULLWIDTH DOLLAR SIGN */ - {0x00a1f1, 0x0000c2a2}, /* U+00A2 CENT SIGN Windows: U+FFE0 */ - {0x00a1f2, 0x0000c2a3}, /* U+00A3 POUND SIGN Windows: U+FFE1 */ - {0x00a1f3, 0x00efbc85}, /* U+FF05 FULLWIDTH PERCENT SIGN */ - {0x00a1f4, 0x00efbc83}, /* U+FF03 FULLWIDTH NUMBER SIGN */ - {0x00a1f5, 0x00efbc86}, /* U+FF06 FULLWIDTH AMPERSAND */ - {0x00a1f6, 0x00efbc8a}, /* U+FF0A FULLWIDTH ASTERISK */ - {0x00a1f7, 0x00efbca0}, /* U+FF20 FULLWIDTH COMMERCIAL AT */ - {0x00a1f8, 0x0000c2a7}, /* U+00A7 SECTION SIGN */ - {0x00a1f9, 0x00e29886}, /* U+2606 WHITE STAR */ - {0x00a1fa, 0x00e29885}, /* U+2605 BLACK STAR */ - {0x00a1fb, 0x00e2978b}, /* U+25CB WHITE CIRCLE */ - {0x00a1fc, 0x00e2978f}, /* U+25CF BLACK CIRCLE */ - {0x00a1fd, 0x00e2978e}, /* U+25CE BULLSEYE */ - {0x00a1fe, 0x00e29787}, /* U+25C7 WHITE DIAMOND */ - {0x00a2a1, 0x00e29786}, /* U+25C6 BLACK DIAMOND */ - {0x00a2a2, 0x00e296a1}, /* U+25A1 WHITE SQUARE */ - {0x00a2a3, 0x00e296a0}, /* U+25A0 BLACK SQUARE */ - {0x00a2a4, 0x00e296b3}, /* U+25B3 WHITE UP-POINTING TRIANGLE */ - {0x00a2a5, 0x00e296b2}, /* U+25B2 BLACK UP-POINTING TRIANGLE */ - {0x00a2a6, 0x00e296bd}, /* U+25BD WHITE DOWN-POINTING TRIANGLE */ - {0x00a2a7, 0x00e296bc}, /* U+25BC BLACK DOWN-POINTING TRIANGLE */ - {0x00a2a8, 0x00e280bb}, /* U+203B REFERENCE MARK */ - {0x00a2a9, 0x00e38092}, /* U+3012 POSTAL MARK */ - {0x00a2aa, 0x00e28692}, /* U+2192 RIGHTWARDS ARROW */ - {0x00a2ab, 0x00e28690}, /* U+2190 LEFTWARDS ARROW */ - {0x00a2ac, 0x00e28691}, /* U+2191 UPWARDS ARROW */ - {0x00a2ad, 0x00e28693}, /* U+2193 DOWNWARDS ARROW */ - {0x00a2ae, 0x00e38093}, /* U+3013 GETA MARK */ - {0x00a2af, 0x00efbc87}, /* U+FF07 FULLWIDTH APOSTROPHE [2000] */ - {0x00a2b0, 0x00efbc82}, /* U+FF02 FULLWIDTH QUOTATION MARK [2000] */ - {0x00a2b1, 0x00efbc8d}, /* U+FF0D FULLWIDTH HYPHEN-MINUS [2000] */ - {0x00a2b2, 0x00efbd9e}, /* U+FF5E FULLWIDTH TILDE [2000] */ - {0x00a2b3, 0x00e380b3}, /* U+3033 VERTICAL KANA REPEAT MARK UPPER HALF [2000] */ - {0x00a2b4, 0x00e380b4}, /* U+3034 VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF [2000] */ - {0x00a2b5, 0x00e380b5}, /* U+3035 VERTICAL KANA REPEAT MARK LOWER HALF [2000] */ - {0x00a2b6, 0x00e380bb}, /* U+303B VERTICAL IDEOGRAPHIC ITERATION MARK [2000] [Unicode3.2] */ - {0x00a2b7, 0x00e380bc}, /* U+303C MASU MARK [2000] [Unicode3.2] */ - {0x00a2b8, 0x00e383bf}, /* U+30FF KATAKANA DIGRAPH KOTO [2000] [Unicode3.2] */ - {0x00a2b9, 0x00e3829f}, /* U+309F HIRAGANA DIGRAPH YORI [2000] [Unicode3.2] */ - {0x00a2ba, 0x00e28888}, /* U+2208 ELEMENT OF [1983] */ - {0x00a2bb, 0x00e2888b}, /* U+220B CONTAINS AS MEMBER [1983] */ - {0x00a2bc, 0x00e28a86}, /* U+2286 SUBSET OF OR EQUAL TO [1983] */ - {0x00a2bd, 0x00e28a87}, /* U+2287 SUPERSET OF OR EQUAL TO [1983] */ - {0x00a2be, 0x00e28a82}, /* U+2282 SUBSET OF [1983] */ - {0x00a2bf, 0x00e28a83}, /* U+2283 SUPERSET OF [1983] */ - {0x00a2c0, 0x00e288aa}, /* U+222A UNION [1983] */ - {0x00a2c1, 0x00e288a9}, /* U+2229 INTERSECTION [1983] */ - {0x00a2c2, 0x00e28a84}, /* U+2284 NOT A SUBSET OF [2000] */ - {0x00a2c3, 0x00e28a85}, /* U+2285 NOT A SUPERSET OF [2000] */ - {0x00a2c4, 0x00e28a8a}, /* U+228A SUBSET OF WITH NOT EQUAL TO [2000] */ - {0x00a2c5, 0x00e28a8b}, /* U+228B SUPERSET OF WITH NOT EQUAL TO [2000] */ - {0x00a2c6, 0x00e28889}, /* U+2209 NOT AN ELEMENT OF [2000] */ - {0x00a2c7, 0x00e28885}, /* U+2205 EMPTY SET [2000] */ - {0x00a2c8, 0x00e28c85}, /* U+2305 PROJECTIVE [2000] */ - {0x00a2c9, 0x00e28c86}, /* U+2306 PERSPECTIVE [2000] */ - {0x00a2ca, 0x00e288a7}, /* U+2227 LOGICAL AND [1983] */ - {0x00a2cb, 0x00e288a8}, /* U+2228 LOGICAL OR [1983] */ - {0x00a2cc, 0x0000c2ac}, /* U+00AC NOT SIGN [1983] Windows: U+FFE2 */ - {0x00a2cd, 0x00e28792}, /* U+21D2 RIGHTWARDS DOUBLE ARROW [1983] */ - {0x00a2ce, 0x00e28794}, /* U+21D4 LEFT RIGHT DOUBLE ARROW [1983] */ - {0x00a2cf, 0x00e28880}, /* U+2200 FOR ALL [1983] */ - {0x00a2d0, 0x00e28883}, /* U+2203 THERE EXISTS [1983] */ - {0x00a2d1, 0x00e28a95}, /* U+2295 CIRCLED PLUS [2000] */ - {0x00a2d2, 0x00e28a96}, /* U+2296 CIRCLED MINUS [2000] */ - {0x00a2d3, 0x00e28a97}, /* U+2297 CIRCLED TIMES [2000] */ - {0x00a2d4, 0x00e288a5}, /* U+2225 PARALLEL TO [2000] */ - {0x00a2d5, 0x00e288a6}, /* U+2226 NOT PARALLEL TO [2000] */ - {0x00a2d6, 0x00efbd9f}, /* U+FF5F FULLWIDTH LEFT WHITE PARENTHESIS [2000] [Unicode3.2] */ - {0x00a2d7, 0x00efbda0}, /* U+FF60 FULLWIDTH RIGHT WHITE PARENTHESIS [2000] [Unicode3.2] */ - {0x00a2d8, 0x00e38098}, /* U+3018 LEFT WHITE TORTOISE SHELL BRACKET [2000] */ - {0x00a2d9, 0x00e38099}, /* U+3019 RIGHT WHITE TORTOISE SHELL BRACKET [2000] */ - {0x00a2da, 0x00e38096}, /* U+3016 LEFT WHITE LENTICULAR BRACKET [2000] */ - {0x00a2db, 0x00e38097}, /* U+3017 RIGHT WHITE LENTICULAR BRACKET [2000] */ - {0x00a2dc, 0x00e288a0}, /* U+2220 ANGLE [1983] */ - {0x00a2dd, 0x00e28aa5}, /* U+22A5 UP TACK [1983] */ - {0x00a2de, 0x00e28c92}, /* U+2312 ARC [1983] */ - {0x00a2df, 0x00e28882}, /* U+2202 PARTIAL DIFFERENTIAL [1983] */ - {0x00a2e0, 0x00e28887}, /* U+2207 NABLA [1983] */ - {0x00a2e1, 0x00e289a1}, /* U+2261 IDENTICAL TO [1983] */ - {0x00a2e2, 0x00e28992}, /* U+2252 APPROXIMATELY EQUAL TO OR THE IMAGE OF [1983] */ - {0x00a2e3, 0x00e289aa}, /* U+226A MUCH LESS-THAN [1983] */ - {0x00a2e4, 0x00e289ab}, /* U+226B MUCH GREATER-THAN [1983] */ - {0x00a2e5, 0x00e2889a}, /* U+221A SQUARE ROOT [1983] */ - {0x00a2e6, 0x00e288bd}, /* U+223D REVERSED TILDE [1983] */ - {0x00a2e7, 0x00e2889d}, /* U+221D PROPORTIONAL TO [1983] */ - {0x00a2e8, 0x00e288b5}, /* U+2235 BECAUSE [1983] */ - {0x00a2e9, 0x00e288ab}, /* U+222B INTEGRAL [1983] */ - {0x00a2ea, 0x00e288ac}, /* U+222C DOUBLE INTEGRAL [1983] */ - {0x00a2eb, 0x00e289a2}, /* U+2262 NOT IDENTICAL TO [2000] */ - {0x00a2ec, 0x00e28983}, /* U+2243 ASYMPTOTICALLY EQUAL TO [2000] */ - {0x00a2ed, 0x00e28985}, /* U+2245 APPROXIMATELY EQUAL TO [2000] */ - {0x00a2ee, 0x00e28988}, /* U+2248 ALMOST EQUAL TO [2000] */ - {0x00a2ef, 0x00e289b6}, /* U+2276 LESS-THAN OR GREATER-THAN [2000] */ - {0x00a2f0, 0x00e289b7}, /* U+2277 GREATER-THAN OR LESS-THAN [2000] */ - {0x00a2f1, 0x00e28694}, /* U+2194 LEFT RIGHT ARROW [2000] */ - {0x00a2f2, 0x00e284ab}, /* U+212B ANGSTROM SIGN [1983] */ - {0x00a2f3, 0x00e280b0}, /* U+2030 PER MILLE SIGN [1983] */ - {0x00a2f4, 0x00e299af}, /* U+266F MUSIC SHARP SIGN [1983] */ - {0x00a2f5, 0x00e299ad}, /* U+266D MUSIC FLAT SIGN [1983] */ - {0x00a2f6, 0x00e299aa}, /* U+266A EIGHTH NOTE [1983] */ - {0x00a2f7, 0x00e280a0}, /* U+2020 DAGGER [1983] */ - {0x00a2f8, 0x00e280a1}, /* U+2021 DOUBLE DAGGER [1983] */ - {0x00a2f9, 0x0000c2b6}, /* U+00B6 PILCROW SIGN [1983] */ - {0x00a2fa, 0x00e299ae}, /* U+266E MUSIC NATURAL SIGN [2000] */ - {0x00a2fb, 0x00e299ab}, /* U+266B BEAMED EIGHTH NOTES [2000] */ - {0x00a2fc, 0x00e299ac}, /* U+266C BEAMED SIXTEENTH NOTES [2000] */ - {0x00a2fd, 0x00e299a9}, /* U+2669 QUARTER NOTE [2000] */ - {0x00a2fe, 0x00e297af}, /* U+25EF LARGE CIRCLE [1983] */ - {0x00a3a1, 0x00e296b7}, /* U+25B7 WHITE RIGHT-POINTING TRIANGLE [2000] */ - {0x00a3a2, 0x00e296b6}, /* U+25B6 BLACK RIGHT-POINTING TRIANGLE [2000] */ - {0x00a3a3, 0x00e29781}, /* U+25C1 WHITE LEFT-POINTING TRIANGLE [2000] */ - {0x00a3a4, 0x00e29780}, /* U+25C0 BLACK LEFT-POINTING TRIANGLE [2000] */ - {0x00a3a5, 0x00e28697}, /* U+2197 NORTH EAST ARROW [2000] */ - {0x00a3a6, 0x00e28698}, /* U+2198 SOUTH EAST ARROW [2000] */ - {0x00a3a7, 0x00e28696}, /* U+2196 NORTH WEST ARROW [2000] */ - {0x00a3a8, 0x00e28699}, /* U+2199 SOUTH WEST ARROW [2000] */ - {0x00a3a9, 0x00e28784}, /* U+21C4 RIGHTWARDS ARROW OVER LEFTWARDS ARROW [2000] */ - {0x00a3aa, 0x00e287a8}, /* U+21E8 RIGHTWARDS WHITE ARROW [2000] */ - {0x00a3ab, 0x00e287a6}, /* U+21E6 LEFTWARDS WHITE ARROW [2000] */ - {0x00a3ac, 0x00e287a7}, /* U+21E7 UPWARDS WHITE ARROW [2000] */ - {0x00a3ad, 0x00e287a9}, /* U+21E9 DOWNWARDS WHITE ARROW [2000] */ - {0x00a3ae, 0x00e2a4b4}, /* U+2934 ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS [2000] [Unicode3.2] */ - {0x00a3af, 0x00e2a4b5}, /* U+2935 ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS [2000] [Unicode3.2] */ - {0x00a3b0, 0x00efbc90}, /* U+FF10 FULLWIDTH DIGIT ZERO */ - {0x00a3b1, 0x00efbc91}, /* U+FF11 FULLWIDTH DIGIT ONE */ - {0x00a3b2, 0x00efbc92}, /* U+FF12 FULLWIDTH DIGIT TWO */ - {0x00a3b3, 0x00efbc93}, /* U+FF13 FULLWIDTH DIGIT THREE */ - {0x00a3b4, 0x00efbc94}, /* U+FF14 FULLWIDTH DIGIT FOUR */ - {0x00a3b5, 0x00efbc95}, /* U+FF15 FULLWIDTH DIGIT FIVE */ - {0x00a3b6, 0x00efbc96}, /* U+FF16 FULLWIDTH DIGIT SIX */ - {0x00a3b7, 0x00efbc97}, /* U+FF17 FULLWIDTH DIGIT SEVEN */ - {0x00a3b8, 0x00efbc98}, /* U+FF18 FULLWIDTH DIGIT EIGHT */ - {0x00a3b9, 0x00efbc99}, /* U+FF19 FULLWIDTH DIGIT NINE */ - {0x00a3ba, 0x00e2a6bf}, /* U+29BF CIRCLED BULLET [2000] [Unicode3.2] */ - {0x00a3bb, 0x00e29789}, /* U+25C9 FISHEYE [2000] */ - {0x00a3bc, 0x00e380bd}, /* U+303D PART ALTERNATION MARK [2000] [Unicode3.2] */ - {0x00a3bd, 0x00efb986}, /* U+FE46 WHITE SESAME DOT [2000] [Unicode3.2] */ - {0x00a3be, 0x00efb985}, /* U+FE45 SESAME DOT [2000] [Unicode3.2] */ - {0x00a3bf, 0x00e297a6}, /* U+25E6 WHITE BULLET [2000] */ - {0x00a3c0, 0x00e280a2}, /* U+2022 BULLET [2000] */ - {0x00a3c1, 0x00efbca1}, /* U+FF21 FULLWIDTH LATIN CAPITAL LETTER A */ - {0x00a3c2, 0x00efbca2}, /* U+FF22 FULLWIDTH LATIN CAPITAL LETTER B */ - {0x00a3c3, 0x00efbca3}, /* U+FF23 FULLWIDTH LATIN CAPITAL LETTER C */ - {0x00a3c4, 0x00efbca4}, /* U+FF24 FULLWIDTH LATIN CAPITAL LETTER D */ - {0x00a3c5, 0x00efbca5}, /* U+FF25 FULLWIDTH LATIN CAPITAL LETTER E */ - {0x00a3c6, 0x00efbca6}, /* U+FF26 FULLWIDTH LATIN CAPITAL LETTER F */ - {0x00a3c7, 0x00efbca7}, /* U+FF27 FULLWIDTH LATIN CAPITAL LETTER G */ - {0x00a3c8, 0x00efbca8}, /* U+FF28 FULLWIDTH LATIN CAPITAL LETTER H */ - {0x00a3c9, 0x00efbca9}, /* U+FF29 FULLWIDTH LATIN CAPITAL LETTER I */ - {0x00a3ca, 0x00efbcaa}, /* U+FF2A FULLWIDTH LATIN CAPITAL LETTER J */ - {0x00a3cb, 0x00efbcab}, /* U+FF2B FULLWIDTH LATIN CAPITAL LETTER K */ - {0x00a3cc, 0x00efbcac}, /* U+FF2C FULLWIDTH LATIN CAPITAL LETTER L */ - {0x00a3cd, 0x00efbcad}, /* U+FF2D FULLWIDTH LATIN CAPITAL LETTER M */ - {0x00a3ce, 0x00efbcae}, /* U+FF2E FULLWIDTH LATIN CAPITAL LETTER N */ - {0x00a3cf, 0x00efbcaf}, /* U+FF2F FULLWIDTH LATIN CAPITAL LETTER O */ - {0x00a3d0, 0x00efbcb0}, /* U+FF30 FULLWIDTH LATIN CAPITAL LETTER P */ - {0x00a3d1, 0x00efbcb1}, /* U+FF31 FULLWIDTH LATIN CAPITAL LETTER Q */ - {0x00a3d2, 0x00efbcb2}, /* U+FF32 FULLWIDTH LATIN CAPITAL LETTER R */ - {0x00a3d3, 0x00efbcb3}, /* U+FF33 FULLWIDTH LATIN CAPITAL LETTER S */ - {0x00a3d4, 0x00efbcb4}, /* U+FF34 FULLWIDTH LATIN CAPITAL LETTER T */ - {0x00a3d5, 0x00efbcb5}, /* U+FF35 FULLWIDTH LATIN CAPITAL LETTER U */ - {0x00a3d6, 0x00efbcb6}, /* U+FF36 FULLWIDTH LATIN CAPITAL LETTER V */ - {0x00a3d7, 0x00efbcb7}, /* U+FF37 FULLWIDTH LATIN CAPITAL LETTER W */ - {0x00a3d8, 0x00efbcb8}, /* U+FF38 FULLWIDTH LATIN CAPITAL LETTER X */ - {0x00a3d9, 0x00efbcb9}, /* U+FF39 FULLWIDTH LATIN CAPITAL LETTER Y */ - {0x00a3da, 0x00efbcba}, /* U+FF3A FULLWIDTH LATIN CAPITAL LETTER Z */ - {0x00a3db, 0x00e28893}, /* U+2213 MINUS-OR-PLUS SIGN [2000] */ - {0x00a3dc, 0x00e284b5}, /* U+2135 ALEF SYMBOL [2000] */ - {0x00a3dd, 0x00e2848f}, /* U+210F PLANCK CONSTANT OVER TWO PI [2000] */ - {0x00a3de, 0x00e38f8b}, /* U+33CB SQUARE HP [2000] */ - {0x00a3df, 0x00e28493}, /* U+2113 SCRIPT SMALL L [2000] */ - {0x00a3e0, 0x00e284a7}, /* U+2127 INVERTED OHM SIGN [2000] */ - {0x00a3e1, 0x00efbd81}, /* U+FF41 FULLWIDTH LATIN SMALL LETTER A */ - {0x00a3e2, 0x00efbd82}, /* U+FF42 FULLWIDTH LATIN SMALL LETTER B */ - {0x00a3e3, 0x00efbd83}, /* U+FF43 FULLWIDTH LATIN SMALL LETTER C */ - {0x00a3e4, 0x00efbd84}, /* U+FF44 FULLWIDTH LATIN SMALL LETTER D */ - {0x00a3e5, 0x00efbd85}, /* U+FF45 FULLWIDTH LATIN SMALL LETTER E */ - {0x00a3e6, 0x00efbd86}, /* U+FF46 FULLWIDTH LATIN SMALL LETTER F */ - {0x00a3e7, 0x00efbd87}, /* U+FF47 FULLWIDTH LATIN SMALL LETTER G */ - {0x00a3e8, 0x00efbd88}, /* U+FF48 FULLWIDTH LATIN SMALL LETTER H */ - {0x00a3e9, 0x00efbd89}, /* U+FF49 FULLWIDTH LATIN SMALL LETTER I */ - {0x00a3ea, 0x00efbd8a}, /* U+FF4A FULLWIDTH LATIN SMALL LETTER J */ - {0x00a3eb, 0x00efbd8b}, /* U+FF4B FULLWIDTH LATIN SMALL LETTER K */ - {0x00a3ec, 0x00efbd8c}, /* U+FF4C FULLWIDTH LATIN SMALL LETTER L */ - {0x00a3ed, 0x00efbd8d}, /* U+FF4D FULLWIDTH LATIN SMALL LETTER M */ - {0x00a3ee, 0x00efbd8e}, /* U+FF4E FULLWIDTH LATIN SMALL LETTER N */ - {0x00a3ef, 0x00efbd8f}, /* U+FF4F FULLWIDTH LATIN SMALL LETTER O */ - {0x00a3f0, 0x00efbd90}, /* U+FF50 FULLWIDTH LATIN SMALL LETTER P */ - {0x00a3f1, 0x00efbd91}, /* U+FF51 FULLWIDTH LATIN SMALL LETTER Q */ - {0x00a3f2, 0x00efbd92}, /* U+FF52 FULLWIDTH LATIN SMALL LETTER R */ - {0x00a3f3, 0x00efbd93}, /* U+FF53 FULLWIDTH LATIN SMALL LETTER S */ - {0x00a3f4, 0x00efbd94}, /* U+FF54 FULLWIDTH LATIN SMALL LETTER T */ - {0x00a3f5, 0x00efbd95}, /* U+FF55 FULLWIDTH LATIN SMALL LETTER U */ - {0x00a3f6, 0x00efbd96}, /* U+FF56 FULLWIDTH LATIN SMALL LETTER V */ - {0x00a3f7, 0x00efbd97}, /* U+FF57 FULLWIDTH LATIN SMALL LETTER W */ - {0x00a3f8, 0x00efbd98}, /* U+FF58 FULLWIDTH LATIN SMALL LETTER X */ - {0x00a3f9, 0x00efbd99}, /* U+FF59 FULLWIDTH LATIN SMALL LETTER Y */ - {0x00a3fa, 0x00efbd9a}, /* U+FF5A FULLWIDTH LATIN SMALL LETTER Z */ - {0x00a3fb, 0x00e382a0}, /* U+30A0 KATAKANA-HIRAGANA DOUBLE HYPHEN [2000] [Unicode3.2] */ - {0x00a3fc, 0x00e28093}, /* U+2013 EN DASH [2000] */ - {0x00a3fd, 0x00e2a7ba}, /* U+29FA DOUBLE PLUS [2000] [Unicode3.2] */ - {0x00a3fe, 0x00e2a7bb}, /* U+29FB TRIPLE PLUS [2000] [Unicode3.2] */ - {0x00a4a1, 0x00e38181}, /* U+3041 HIRAGANA LETTER SMALL A */ - {0x00a4a2, 0x00e38182}, /* U+3042 HIRAGANA LETTER A */ - {0x00a4a3, 0x00e38183}, /* U+3043 HIRAGANA LETTER SMALL I */ - {0x00a4a4, 0x00e38184}, /* U+3044 HIRAGANA LETTER I */ - {0x00a4a5, 0x00e38185}, /* U+3045 HIRAGANA LETTER SMALL U */ - {0x00a4a6, 0x00e38186}, /* U+3046 HIRAGANA LETTER U */ - {0x00a4a7, 0x00e38187}, /* U+3047 HIRAGANA LETTER SMALL E */ - {0x00a4a8, 0x00e38188}, /* U+3048 HIRAGANA LETTER E */ - {0x00a4a9, 0x00e38189}, /* U+3049 HIRAGANA LETTER SMALL O */ - {0x00a4aa, 0x00e3818a}, /* U+304A HIRAGANA LETTER O */ - {0x00a4ab, 0x00e3818b}, /* U+304B HIRAGANA LETTER KA */ - {0x00a4ac, 0x00e3818c}, /* U+304C HIRAGANA LETTER GA */ - {0x00a4ad, 0x00e3818d}, /* U+304D HIRAGANA LETTER KI */ - {0x00a4ae, 0x00e3818e}, /* U+304E HIRAGANA LETTER GI */ - {0x00a4af, 0x00e3818f}, /* U+304F HIRAGANA LETTER KU */ - {0x00a4b0, 0x00e38190}, /* U+3050 HIRAGANA LETTER GU */ - {0x00a4b1, 0x00e38191}, /* U+3051 HIRAGANA LETTER KE */ - {0x00a4b2, 0x00e38192}, /* U+3052 HIRAGANA LETTER GE */ - {0x00a4b3, 0x00e38193}, /* U+3053 HIRAGANA LETTER KO */ - {0x00a4b4, 0x00e38194}, /* U+3054 HIRAGANA LETTER GO */ - {0x00a4b5, 0x00e38195}, /* U+3055 HIRAGANA LETTER SA */ - {0x00a4b6, 0x00e38196}, /* U+3056 HIRAGANA LETTER ZA */ - {0x00a4b7, 0x00e38197}, /* U+3057 HIRAGANA LETTER SI */ - {0x00a4b8, 0x00e38198}, /* U+3058 HIRAGANA LETTER ZI */ - {0x00a4b9, 0x00e38199}, /* U+3059 HIRAGANA LETTER SU */ - {0x00a4ba, 0x00e3819a}, /* U+305A HIRAGANA LETTER ZU */ - {0x00a4bb, 0x00e3819b}, /* U+305B HIRAGANA LETTER SE */ - {0x00a4bc, 0x00e3819c}, /* U+305C HIRAGANA LETTER ZE */ - {0x00a4bd, 0x00e3819d}, /* U+305D HIRAGANA LETTER SO */ - {0x00a4be, 0x00e3819e}, /* U+305E HIRAGANA LETTER ZO */ - {0x00a4bf, 0x00e3819f}, /* U+305F HIRAGANA LETTER TA */ - {0x00a4c0, 0x00e381a0}, /* U+3060 HIRAGANA LETTER DA */ - {0x00a4c1, 0x00e381a1}, /* U+3061 HIRAGANA LETTER TI */ - {0x00a4c2, 0x00e381a2}, /* U+3062 HIRAGANA LETTER DI */ - {0x00a4c3, 0x00e381a3}, /* U+3063 HIRAGANA LETTER SMALL TU */ - {0x00a4c4, 0x00e381a4}, /* U+3064 HIRAGANA LETTER TU */ - {0x00a4c5, 0x00e381a5}, /* U+3065 HIRAGANA LETTER DU */ - {0x00a4c6, 0x00e381a6}, /* U+3066 HIRAGANA LETTER TE */ - {0x00a4c7, 0x00e381a7}, /* U+3067 HIRAGANA LETTER DE */ - {0x00a4c8, 0x00e381a8}, /* U+3068 HIRAGANA LETTER TO */ - {0x00a4c9, 0x00e381a9}, /* U+3069 HIRAGANA LETTER DO */ - {0x00a4ca, 0x00e381aa}, /* U+306A HIRAGANA LETTER NA */ - {0x00a4cb, 0x00e381ab}, /* U+306B HIRAGANA LETTER NI */ - {0x00a4cc, 0x00e381ac}, /* U+306C HIRAGANA LETTER NU */ - {0x00a4cd, 0x00e381ad}, /* U+306D HIRAGANA LETTER NE */ - {0x00a4ce, 0x00e381ae}, /* U+306E HIRAGANA LETTER NO */ - {0x00a4cf, 0x00e381af}, /* U+306F HIRAGANA LETTER HA */ - {0x00a4d0, 0x00e381b0}, /* U+3070 HIRAGANA LETTER BA */ - {0x00a4d1, 0x00e381b1}, /* U+3071 HIRAGANA LETTER PA */ - {0x00a4d2, 0x00e381b2}, /* U+3072 HIRAGANA LETTER HI */ - {0x00a4d3, 0x00e381b3}, /* U+3073 HIRAGANA LETTER BI */ - {0x00a4d4, 0x00e381b4}, /* U+3074 HIRAGANA LETTER PI */ - {0x00a4d5, 0x00e381b5}, /* U+3075 HIRAGANA LETTER HU */ - {0x00a4d6, 0x00e381b6}, /* U+3076 HIRAGANA LETTER BU */ - {0x00a4d7, 0x00e381b7}, /* U+3077 HIRAGANA LETTER PU */ - {0x00a4d8, 0x00e381b8}, /* U+3078 HIRAGANA LETTER HE */ - {0x00a4d9, 0x00e381b9}, /* U+3079 HIRAGANA LETTER BE */ - {0x00a4da, 0x00e381ba}, /* U+307A HIRAGANA LETTER PE */ - {0x00a4db, 0x00e381bb}, /* U+307B HIRAGANA LETTER HO */ - {0x00a4dc, 0x00e381bc}, /* U+307C HIRAGANA LETTER BO */ - {0x00a4dd, 0x00e381bd}, /* U+307D HIRAGANA LETTER PO */ - {0x00a4de, 0x00e381be}, /* U+307E HIRAGANA LETTER MA */ - {0x00a4df, 0x00e381bf}, /* U+307F HIRAGANA LETTER MI */ - {0x00a4e0, 0x00e38280}, /* U+3080 HIRAGANA LETTER MU */ - {0x00a4e1, 0x00e38281}, /* U+3081 HIRAGANA LETTER ME */ - {0x00a4e2, 0x00e38282}, /* U+3082 HIRAGANA LETTER MO */ - {0x00a4e3, 0x00e38283}, /* U+3083 HIRAGANA LETTER SMALL YA */ - {0x00a4e4, 0x00e38284}, /* U+3084 HIRAGANA LETTER YA */ - {0x00a4e5, 0x00e38285}, /* U+3085 HIRAGANA LETTER SMALL YU */ - {0x00a4e6, 0x00e38286}, /* U+3086 HIRAGANA LETTER YU */ - {0x00a4e7, 0x00e38287}, /* U+3087 HIRAGANA LETTER SMALL YO */ - {0x00a4e8, 0x00e38288}, /* U+3088 HIRAGANA LETTER YO */ - {0x00a4e9, 0x00e38289}, /* U+3089 HIRAGANA LETTER RA */ - {0x00a4ea, 0x00e3828a}, /* U+308A HIRAGANA LETTER RI */ - {0x00a4eb, 0x00e3828b}, /* U+308B HIRAGANA LETTER RU */ - {0x00a4ec, 0x00e3828c}, /* U+308C HIRAGANA LETTER RE */ - {0x00a4ed, 0x00e3828d}, /* U+308D HIRAGANA LETTER RO */ - {0x00a4ee, 0x00e3828e}, /* U+308E HIRAGANA LETTER SMALL WA */ - {0x00a4ef, 0x00e3828f}, /* U+308F HIRAGANA LETTER WA */ - {0x00a4f0, 0x00e38290}, /* U+3090 HIRAGANA LETTER WI */ - {0x00a4f1, 0x00e38291}, /* U+3091 HIRAGANA LETTER WE */ - {0x00a4f2, 0x00e38292}, /* U+3092 HIRAGANA LETTER WO */ - {0x00a4f3, 0x00e38293}, /* U+3093 HIRAGANA LETTER N */ - {0x00a4f4, 0x00e38294}, /* U+3094 HIRAGANA LETTER VU [2000] */ - {0x00a4f5, 0x00e38295}, /* U+3095 HIRAGANA LETTER SMALL KA [2000] [Unicode3.2] */ - {0x00a4f6, 0x00e38296}, /* U+3096 HIRAGANA LETTER SMALL KE [2000] [Unicode3.2] */ - {0x00a5a1, 0x00e382a1}, /* U+30A1 KATAKANA LETTER SMALL A */ - {0x00a5a2, 0x00e382a2}, /* U+30A2 KATAKANA LETTER A */ - {0x00a5a3, 0x00e382a3}, /* U+30A3 KATAKANA LETTER SMALL I */ - {0x00a5a4, 0x00e382a4}, /* U+30A4 KATAKANA LETTER I */ - {0x00a5a5, 0x00e382a5}, /* U+30A5 KATAKANA LETTER SMALL U */ - {0x00a5a6, 0x00e382a6}, /* U+30A6 KATAKANA LETTER U */ - {0x00a5a7, 0x00e382a7}, /* U+30A7 KATAKANA LETTER SMALL E */ - {0x00a5a8, 0x00e382a8}, /* U+30A8 KATAKANA LETTER E */ - {0x00a5a9, 0x00e382a9}, /* U+30A9 KATAKANA LETTER SMALL O */ - {0x00a5aa, 0x00e382aa}, /* U+30AA KATAKANA LETTER O */ - {0x00a5ab, 0x00e382ab}, /* U+30AB KATAKANA LETTER KA */ - {0x00a5ac, 0x00e382ac}, /* U+30AC KATAKANA LETTER GA */ - {0x00a5ad, 0x00e382ad}, /* U+30AD KATAKANA LETTER KI */ - {0x00a5ae, 0x00e382ae}, /* U+30AE KATAKANA LETTER GI */ - {0x00a5af, 0x00e382af}, /* U+30AF KATAKANA LETTER KU */ - {0x00a5b0, 0x00e382b0}, /* U+30B0 KATAKANA LETTER GU */ - {0x00a5b1, 0x00e382b1}, /* U+30B1 KATAKANA LETTER KE */ - {0x00a5b2, 0x00e382b2}, /* U+30B2 KATAKANA LETTER GE */ - {0x00a5b3, 0x00e382b3}, /* U+30B3 KATAKANA LETTER KO */ - {0x00a5b4, 0x00e382b4}, /* U+30B4 KATAKANA LETTER GO */ - {0x00a5b5, 0x00e382b5}, /* U+30B5 KATAKANA LETTER SA */ - {0x00a5b6, 0x00e382b6}, /* U+30B6 KATAKANA LETTER ZA */ - {0x00a5b7, 0x00e382b7}, /* U+30B7 KATAKANA LETTER SI */ - {0x00a5b8, 0x00e382b8}, /* U+30B8 KATAKANA LETTER ZI */ - {0x00a5b9, 0x00e382b9}, /* U+30B9 KATAKANA LETTER SU */ - {0x00a5ba, 0x00e382ba}, /* U+30BA KATAKANA LETTER ZU */ - {0x00a5bb, 0x00e382bb}, /* U+30BB KATAKANA LETTER SE */ - {0x00a5bc, 0x00e382bc}, /* U+30BC KATAKANA LETTER ZE */ - {0x00a5bd, 0x00e382bd}, /* U+30BD KATAKANA LETTER SO */ - {0x00a5be, 0x00e382be}, /* U+30BE KATAKANA LETTER ZO */ - {0x00a5bf, 0x00e382bf}, /* U+30BF KATAKANA LETTER TA */ - {0x00a5c0, 0x00e38380}, /* U+30C0 KATAKANA LETTER DA */ - {0x00a5c1, 0x00e38381}, /* U+30C1 KATAKANA LETTER TI */ - {0x00a5c2, 0x00e38382}, /* U+30C2 KATAKANA LETTER DI */ - {0x00a5c3, 0x00e38383}, /* U+30C3 KATAKANA LETTER SMALL TU */ - {0x00a5c4, 0x00e38384}, /* U+30C4 KATAKANA LETTER TU */ - {0x00a5c5, 0x00e38385}, /* U+30C5 KATAKANA LETTER DU */ - {0x00a5c6, 0x00e38386}, /* U+30C6 KATAKANA LETTER TE */ - {0x00a5c7, 0x00e38387}, /* U+30C7 KATAKANA LETTER DE */ - {0x00a5c8, 0x00e38388}, /* U+30C8 KATAKANA LETTER TO */ - {0x00a5c9, 0x00e38389}, /* U+30C9 KATAKANA LETTER DO */ - {0x00a5ca, 0x00e3838a}, /* U+30CA KATAKANA LETTER NA */ - {0x00a5cb, 0x00e3838b}, /* U+30CB KATAKANA LETTER NI */ - {0x00a5cc, 0x00e3838c}, /* U+30CC KATAKANA LETTER NU */ - {0x00a5cd, 0x00e3838d}, /* U+30CD KATAKANA LETTER NE */ - {0x00a5ce, 0x00e3838e}, /* U+30CE KATAKANA LETTER NO */ - {0x00a5cf, 0x00e3838f}, /* U+30CF KATAKANA LETTER HA */ - {0x00a5d0, 0x00e38390}, /* U+30D0 KATAKANA LETTER BA */ - {0x00a5d1, 0x00e38391}, /* U+30D1 KATAKANA LETTER PA */ - {0x00a5d2, 0x00e38392}, /* U+30D2 KATAKANA LETTER HI */ - {0x00a5d3, 0x00e38393}, /* U+30D3 KATAKANA LETTER BI */ - {0x00a5d4, 0x00e38394}, /* U+30D4 KATAKANA LETTER PI */ - {0x00a5d5, 0x00e38395}, /* U+30D5 KATAKANA LETTER HU */ - {0x00a5d6, 0x00e38396}, /* U+30D6 KATAKANA LETTER BU */ - {0x00a5d7, 0x00e38397}, /* U+30D7 KATAKANA LETTER PU */ - {0x00a5d8, 0x00e38398}, /* U+30D8 KATAKANA LETTER HE */ - {0x00a5d9, 0x00e38399}, /* U+30D9 KATAKANA LETTER BE */ - {0x00a5da, 0x00e3839a}, /* U+30DA KATAKANA LETTER PE */ - {0x00a5db, 0x00e3839b}, /* U+30DB KATAKANA LETTER HO */ - {0x00a5dc, 0x00e3839c}, /* U+30DC KATAKANA LETTER BO */ - {0x00a5dd, 0x00e3839d}, /* U+30DD KATAKANA LETTER PO */ - {0x00a5de, 0x00e3839e}, /* U+30DE KATAKANA LETTER MA */ - {0x00a5df, 0x00e3839f}, /* U+30DF KATAKANA LETTER MI */ - {0x00a5e0, 0x00e383a0}, /* U+30E0 KATAKANA LETTER MU */ - {0x00a5e1, 0x00e383a1}, /* U+30E1 KATAKANA LETTER ME */ - {0x00a5e2, 0x00e383a2}, /* U+30E2 KATAKANA LETTER MO */ - {0x00a5e3, 0x00e383a3}, /* U+30E3 KATAKANA LETTER SMALL YA */ - {0x00a5e4, 0x00e383a4}, /* U+30E4 KATAKANA LETTER YA */ - {0x00a5e5, 0x00e383a5}, /* U+30E5 KATAKANA LETTER SMALL YU */ - {0x00a5e6, 0x00e383a6}, /* U+30E6 KATAKANA LETTER YU */ - {0x00a5e7, 0x00e383a7}, /* U+30E7 KATAKANA LETTER SMALL YO */ - {0x00a5e8, 0x00e383a8}, /* U+30E8 KATAKANA LETTER YO */ - {0x00a5e9, 0x00e383a9}, /* U+30E9 KATAKANA LETTER RA */ - {0x00a5ea, 0x00e383aa}, /* U+30EA KATAKANA LETTER RI */ - {0x00a5eb, 0x00e383ab}, /* U+30EB KATAKANA LETTER RU */ - {0x00a5ec, 0x00e383ac}, /* U+30EC KATAKANA LETTER RE */ - {0x00a5ed, 0x00e383ad}, /* U+30ED KATAKANA LETTER RO */ - {0x00a5ee, 0x00e383ae}, /* U+30EE KATAKANA LETTER SMALL WA */ - {0x00a5ef, 0x00e383af}, /* U+30EF KATAKANA LETTER WA */ - {0x00a5f0, 0x00e383b0}, /* U+30F0 KATAKANA LETTER WI */ - {0x00a5f1, 0x00e383b1}, /* U+30F1 KATAKANA LETTER WE */ - {0x00a5f2, 0x00e383b2}, /* U+30F2 KATAKANA LETTER WO */ - {0x00a5f3, 0x00e383b3}, /* U+30F3 KATAKANA LETTER N */ - {0x00a5f4, 0x00e383b4}, /* U+30F4 KATAKANA LETTER VU */ - {0x00a5f5, 0x00e383b5}, /* U+30F5 KATAKANA LETTER SMALL KA */ - {0x00a5f6, 0x00e383b6}, /* U+30F6 KATAKANA LETTER SMALL KE */ - {0x00a6a1, 0x0000ce91}, /* U+0391 GREEK CAPITAL LETTER ALPHA */ - {0x00a6a2, 0x0000ce92}, /* U+0392 GREEK CAPITAL LETTER BETA */ - {0x00a6a3, 0x0000ce93}, /* U+0393 GREEK CAPITAL LETTER GAMMA */ - {0x00a6a4, 0x0000ce94}, /* U+0394 GREEK CAPITAL LETTER DELTA */ - {0x00a6a5, 0x0000ce95}, /* U+0395 GREEK CAPITAL LETTER EPSILON */ - {0x00a6a6, 0x0000ce96}, /* U+0396 GREEK CAPITAL LETTER ZETA */ - {0x00a6a7, 0x0000ce97}, /* U+0397 GREEK CAPITAL LETTER ETA */ - {0x00a6a8, 0x0000ce98}, /* U+0398 GREEK CAPITAL LETTER THETA */ - {0x00a6a9, 0x0000ce99}, /* U+0399 GREEK CAPITAL LETTER IOTA */ - {0x00a6aa, 0x0000ce9a}, /* U+039A GREEK CAPITAL LETTER KAPPA */ - {0x00a6ab, 0x0000ce9b}, /* U+039B GREEK CAPITAL LETTER LAMDA */ - {0x00a6ac, 0x0000ce9c}, /* U+039C GREEK CAPITAL LETTER MU */ - {0x00a6ad, 0x0000ce9d}, /* U+039D GREEK CAPITAL LETTER NU */ - {0x00a6ae, 0x0000ce9e}, /* U+039E GREEK CAPITAL LETTER XI */ - {0x00a6af, 0x0000ce9f}, /* U+039F GREEK CAPITAL LETTER OMICRON */ - {0x00a6b0, 0x0000cea0}, /* U+03A0 GREEK CAPITAL LETTER PI */ - {0x00a6b1, 0x0000cea1}, /* U+03A1 GREEK CAPITAL LETTER RHO */ - {0x00a6b2, 0x0000cea3}, /* U+03A3 GREEK CAPITAL LETTER SIGMA */ - {0x00a6b3, 0x0000cea4}, /* U+03A4 GREEK CAPITAL LETTER TAU */ - {0x00a6b4, 0x0000cea5}, /* U+03A5 GREEK CAPITAL LETTER UPSILON */ - {0x00a6b5, 0x0000cea6}, /* U+03A6 GREEK CAPITAL LETTER PHI */ - {0x00a6b6, 0x0000cea7}, /* U+03A7 GREEK CAPITAL LETTER CHI */ - {0x00a6b7, 0x0000cea8}, /* U+03A8 GREEK CAPITAL LETTER PSI */ - {0x00a6b8, 0x0000cea9}, /* U+03A9 GREEK CAPITAL LETTER OMEGA */ - {0x00a6b9, 0x00e299a4}, /* U+2664 WHITE SPADE SUIT [2000] */ - {0x00a6ba, 0x00e299a0}, /* U+2660 BLACK SPADE SUIT [2000] */ - {0x00a6bb, 0x00e299a2}, /* U+2662 WHITE DIAMOND SUIT [2000] */ - {0x00a6bc, 0x00e299a6}, /* U+2666 BLACK DIAMOND SUIT [2000] */ - {0x00a6bd, 0x00e299a1}, /* U+2661 WHITE HEART SUIT [2000] */ - {0x00a6be, 0x00e299a5}, /* U+2665 BLACK HEART SUIT [2000] */ - {0x00a6bf, 0x00e299a7}, /* U+2667 WHITE CLUB SUIT [2000] */ - {0x00a6c0, 0x00e299a3}, /* U+2663 BLACK CLUB SUIT [2000] */ - {0x00a6c1, 0x0000ceb1}, /* U+03B1 GREEK SMALL LETTER ALPHA */ - {0x00a6c2, 0x0000ceb2}, /* U+03B2 GREEK SMALL LETTER BETA */ - {0x00a6c3, 0x0000ceb3}, /* U+03B3 GREEK SMALL LETTER GAMMA */ - {0x00a6c4, 0x0000ceb4}, /* U+03B4 GREEK SMALL LETTER DELTA */ - {0x00a6c5, 0x0000ceb5}, /* U+03B5 GREEK SMALL LETTER EPSILON */ - {0x00a6c6, 0x0000ceb6}, /* U+03B6 GREEK SMALL LETTER ZETA */ - {0x00a6c7, 0x0000ceb7}, /* U+03B7 GREEK SMALL LETTER ETA */ - {0x00a6c8, 0x0000ceb8}, /* U+03B8 GREEK SMALL LETTER THETA */ - {0x00a6c9, 0x0000ceb9}, /* U+03B9 GREEK SMALL LETTER IOTA */ - {0x00a6ca, 0x0000ceba}, /* U+03BA GREEK SMALL LETTER KAPPA */ - {0x00a6cb, 0x0000cebb}, /* U+03BB GREEK SMALL LETTER LAMDA */ - {0x00a6cc, 0x0000cebc}, /* U+03BC GREEK SMALL LETTER MU */ - {0x00a6cd, 0x0000cebd}, /* U+03BD GREEK SMALL LETTER NU */ - {0x00a6ce, 0x0000cebe}, /* U+03BE GREEK SMALL LETTER XI */ - {0x00a6cf, 0x0000cebf}, /* U+03BF GREEK SMALL LETTER OMICRON */ - {0x00a6d0, 0x0000cf80}, /* U+03C0 GREEK SMALL LETTER PI */ - {0x00a6d1, 0x0000cf81}, /* U+03C1 GREEK SMALL LETTER RHO */ - {0x00a6d2, 0x0000cf83}, /* U+03C3 GREEK SMALL LETTER SIGMA */ - {0x00a6d3, 0x0000cf84}, /* U+03C4 GREEK SMALL LETTER TAU */ - {0x00a6d4, 0x0000cf85}, /* U+03C5 GREEK SMALL LETTER UPSILON */ - {0x00a6d5, 0x0000cf86}, /* U+03C6 GREEK SMALL LETTER PHI */ - {0x00a6d6, 0x0000cf87}, /* U+03C7 GREEK SMALL LETTER CHI */ - {0x00a6d7, 0x0000cf88}, /* U+03C8 GREEK SMALL LETTER PSI */ - {0x00a6d8, 0x0000cf89}, /* U+03C9 GREEK SMALL LETTER OMEGA */ - {0x00a6d9, 0x0000cf82}, /* U+03C2 GREEK SMALL LETTER FINAL SIGMA [2000] */ - {0x00a6da, 0x00e293b5}, /* U+24F5 DOUBLE CIRCLED DIGIT ONE [2000] [Unicode3.2] */ - {0x00a6db, 0x00e293b6}, /* U+24F6 DOUBLE CIRCLED DIGIT TWO [2000] [Unicode3.2] */ - {0x00a6dc, 0x00e293b7}, /* U+24F7 DOUBLE CIRCLED DIGIT THREE [2000] [Unicode3.2] */ - {0x00a6dd, 0x00e293b8}, /* U+24F8 DOUBLE CIRCLED DIGIT FOUR [2000] [Unicode3.2] */ - {0x00a6de, 0x00e293b9}, /* U+24F9 DOUBLE CIRCLED DIGIT FIVE [2000] [Unicode3.2] */ - {0x00a6df, 0x00e293ba}, /* U+24FA DOUBLE CIRCLED DIGIT SIX [2000] [Unicode3.2] */ - {0x00a6e0, 0x00e293bb}, /* U+24FB DOUBLE CIRCLED DIGIT SEVEN [2000] [Unicode3.2] */ - {0x00a6e1, 0x00e293bc}, /* U+24FC DOUBLE CIRCLED DIGIT EIGHT [2000] [Unicode3.2] */ - {0x00a6e2, 0x00e293bd}, /* U+24FD DOUBLE CIRCLED DIGIT NINE [2000] [Unicode3.2] */ - {0x00a6e3, 0x00e293be}, /* U+24FE DOUBLE CIRCLED NUMBER TEN [2000] [Unicode3.2] */ - {0x00a6e4, 0x00e29896}, /* U+2616 WHITE SHOGI PIECE [2000] [Unicode3.2] */ - {0x00a6e5, 0x00e29897}, /* U+2617 BLACK SHOGI PIECE [2000] [Unicode3.2] */ - {0x00a6e6, 0x00e380a0}, /* U+3020 POSTAL MARK FACE [2000] */ - {0x00a6e7, 0x00e2988e}, /* U+260E BLACK TELEPHONE [2000] */ - {0x00a6e8, 0x00e29880}, /* U+2600 BLACK SUN WITH RAYS [2000] */ - {0x00a6e9, 0x00e29881}, /* U+2601 CLOUD [2000] */ - {0x00a6ea, 0x00e29882}, /* U+2602 UMBRELLA [2000] */ - {0x00a6eb, 0x00e29883}, /* U+2603 SNOWMAN [2000] */ - {0x00a6ec, 0x00e299a8}, /* U+2668 HOT SPRINGS [2000] */ - {0x00a6ed, 0x00e296b1}, /* U+25B1 WHITE PARALLELOGRAM [2000] */ - {0x00a6ee, 0x00e387b0}, /* U+31F0 KATAKANA LETTER SMALL KU [2000] [Unicode3.2] */ - {0x00a6ef, 0x00e387b1}, /* U+31F1 KATAKANA LETTER SMALL SI [2000] [Unicode3.2] */ - {0x00a6f0, 0x00e387b2}, /* U+31F2 KATAKANA LETTER SMALL SU [2000] [Unicode3.2] */ - {0x00a6f1, 0x00e387b3}, /* U+31F3 KATAKANA LETTER SMALL TO [2000] [Unicode3.2] */ - {0x00a6f2, 0x00e387b4}, /* U+31F4 KATAKANA LETTER SMALL NU [2000] [Unicode3.2] */ - {0x00a6f3, 0x00e387b5}, /* U+31F5 KATAKANA LETTER SMALL HA [2000] [Unicode3.2] */ - {0x00a6f4, 0x00e387b6}, /* U+31F6 KATAKANA LETTER SMALL HI [2000] [Unicode3.2] */ - {0x00a6f5, 0x00e387b7}, /* U+31F7 KATAKANA LETTER SMALL HU [2000] [Unicode3.2] */ - {0x00a6f6, 0x00e387b8}, /* U+31F8 KATAKANA LETTER SMALL HE [2000] [Unicode3.2] */ - {0x00a6f7, 0x00e387b9}, /* U+31F9 KATAKANA LETTER SMALL HO [2000] [Unicode3.2] */ - {0x00a6f9, 0x00e387ba}, /* U+31FA KATAKANA LETTER SMALL MU [2000] [Unicode3.2] */ - {0x00a6fa, 0x00e387bb}, /* U+31FB KATAKANA LETTER SMALL RA [2000] [Unicode3.2] */ - {0x00a6fb, 0x00e387bc}, /* U+31FC KATAKANA LETTER SMALL RI [2000] [Unicode3.2] */ - {0x00a6fc, 0x00e387bd}, /* U+31FD KATAKANA LETTER SMALL RU [2000] [Unicode3.2] */ - {0x00a6fd, 0x00e387be}, /* U+31FE KATAKANA LETTER SMALL RE [2000] [Unicode3.2] */ - {0x00a6fe, 0x00e387bf}, /* U+31FF KATAKANA LETTER SMALL RO [2000] [Unicode3.2] */ - {0x00a7a1, 0x0000d090}, /* U+0410 CYRILLIC CAPITAL LETTER A */ - {0x00a7a2, 0x0000d091}, /* U+0411 CYRILLIC CAPITAL LETTER BE */ - {0x00a7a3, 0x0000d092}, /* U+0412 CYRILLIC CAPITAL LETTER VE */ - {0x00a7a4, 0x0000d093}, /* U+0413 CYRILLIC CAPITAL LETTER GHE */ - {0x00a7a5, 0x0000d094}, /* U+0414 CYRILLIC CAPITAL LETTER DE */ - {0x00a7a6, 0x0000d095}, /* U+0415 CYRILLIC CAPITAL LETTER IE */ - {0x00a7a7, 0x0000d081}, /* U+0401 CYRILLIC CAPITAL LETTER IO */ - {0x00a7a8, 0x0000d096}, /* U+0416 CYRILLIC CAPITAL LETTER ZHE */ - {0x00a7a9, 0x0000d097}, /* U+0417 CYRILLIC CAPITAL LETTER ZE */ - {0x00a7aa, 0x0000d098}, /* U+0418 CYRILLIC CAPITAL LETTER I */ - {0x00a7ab, 0x0000d099}, /* U+0419 CYRILLIC CAPITAL LETTER SHORT I */ - {0x00a7ac, 0x0000d09a}, /* U+041A CYRILLIC CAPITAL LETTER KA */ - {0x00a7ad, 0x0000d09b}, /* U+041B CYRILLIC CAPITAL LETTER EL */ - {0x00a7ae, 0x0000d09c}, /* U+041C CYRILLIC CAPITAL LETTER EM */ - {0x00a7af, 0x0000d09d}, /* U+041D CYRILLIC CAPITAL LETTER EN */ - {0x00a7b0, 0x0000d09e}, /* U+041E CYRILLIC CAPITAL LETTER O */ - {0x00a7b1, 0x0000d09f}, /* U+041F CYRILLIC CAPITAL LETTER PE */ - {0x00a7b2, 0x0000d0a0}, /* U+0420 CYRILLIC CAPITAL LETTER ER */ - {0x00a7b3, 0x0000d0a1}, /* U+0421 CYRILLIC CAPITAL LETTER ES */ - {0x00a7b4, 0x0000d0a2}, /* U+0422 CYRILLIC CAPITAL LETTER TE */ - {0x00a7b5, 0x0000d0a3}, /* U+0423 CYRILLIC CAPITAL LETTER U */ - {0x00a7b6, 0x0000d0a4}, /* U+0424 CYRILLIC CAPITAL LETTER EF */ - {0x00a7b7, 0x0000d0a5}, /* U+0425 CYRILLIC CAPITAL LETTER HA */ - {0x00a7b8, 0x0000d0a6}, /* U+0426 CYRILLIC CAPITAL LETTER TSE */ - {0x00a7b9, 0x0000d0a7}, /* U+0427 CYRILLIC CAPITAL LETTER CHE */ - {0x00a7ba, 0x0000d0a8}, /* U+0428 CYRILLIC CAPITAL LETTER SHA */ - {0x00a7bb, 0x0000d0a9}, /* U+0429 CYRILLIC CAPITAL LETTER SHCHA */ - {0x00a7bc, 0x0000d0aa}, /* U+042A CYRILLIC CAPITAL LETTER HARD SIGN */ - {0x00a7bd, 0x0000d0ab}, /* U+042B CYRILLIC CAPITAL LETTER YERU */ - {0x00a7be, 0x0000d0ac}, /* U+042C CYRILLIC CAPITAL LETTER SOFT SIGN */ - {0x00a7bf, 0x0000d0ad}, /* U+042D CYRILLIC CAPITAL LETTER E */ - {0x00a7c0, 0x0000d0ae}, /* U+042E CYRILLIC CAPITAL LETTER YU */ - {0x00a7c1, 0x0000d0af}, /* U+042F CYRILLIC CAPITAL LETTER YA */ - {0x00a7c2, 0x00e28ebe}, /* U+23BE DENTISTRY SYMBOL LIGHT VERTICAL AND TOP RIGHT [2000] [Unicode3.2] */ - {0x00a7c3, 0x00e28ebf}, /* U+23BF DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM RIGHT [2000] [Unicode3.2] */ - {0x00a7c4, 0x00e28f80}, /* U+23C0 DENTISTRY SYMBOL LIGHT VERTICAL WITH CIRCLE [2000] [Unicode3.2] */ - {0x00a7c5, 0x00e28f81}, /* U+23C1 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH CIRCLE [2000] [Unicode3.2] */ - {0x00a7c6, 0x00e28f82}, /* U+23C2 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLE [2000] [Unicode3.2] */ - {0x00a7c7, 0x00e28f83}, /* U+23C3 DENTISTRY SYMBOL LIGHT VERTICAL WITH TRIANGLE [2000] [Unicode3.2] */ - {0x00a7c8, 0x00e28f84}, /* U+23C4 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH TRIANGLE [2000] [Unicode3.2] */ - {0x00a7c9, 0x00e28f85}, /* U+23C5 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH TRIANGLE [2000] [Unicode3.2] */ - {0x00a7ca, 0x00e28f86}, /* U+23C6 DENTISTRY SYMBOL LIGHT VERTICAL AND WAVE [2000] [Unicode3.2] */ - {0x00a7cb, 0x00e28f87}, /* U+23C7 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH WAVE [2000] [Unicode3.2] */ - {0x00a7cc, 0x00e28f88}, /* U+23C8 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH WAVE [2000] [Unicode3.2] */ - {0x00a7cd, 0x00e28f89}, /* U+23C9 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL [2000] [Unicode3.2] */ - {0x00a7ce, 0x00e28f8a}, /* U+23CA DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL [2000] [Unicode3.2] */ - {0x00a7cf, 0x00e28f8b}, /* U+23CB DENTISTRY SYMBOL LIGHT VERTICAL AND TOP LEFT [2000] [Unicode3.2] */ - {0x00a7d0, 0x00e28f8c}, /* U+23CC DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM LEFT [2000] [Unicode3.2] */ - {0x00a7d1, 0x0000d0b0}, /* U+0430 CYRILLIC SMALL LETTER A */ - {0x00a7d2, 0x0000d0b1}, /* U+0431 CYRILLIC SMALL LETTER BE */ - {0x00a7d3, 0x0000d0b2}, /* U+0432 CYRILLIC SMALL LETTER VE */ - {0x00a7d4, 0x0000d0b3}, /* U+0433 CYRILLIC SMALL LETTER GHE */ - {0x00a7d5, 0x0000d0b4}, /* U+0434 CYRILLIC SMALL LETTER DE */ - {0x00a7d6, 0x0000d0b5}, /* U+0435 CYRILLIC SMALL LETTER IE */ - {0x00a7d7, 0x0000d191}, /* U+0451 CYRILLIC SMALL LETTER IO */ - {0x00a7d8, 0x0000d0b6}, /* U+0436 CYRILLIC SMALL LETTER ZHE */ - {0x00a7d9, 0x0000d0b7}, /* U+0437 CYRILLIC SMALL LETTER ZE */ - {0x00a7da, 0x0000d0b8}, /* U+0438 CYRILLIC SMALL LETTER I */ - {0x00a7db, 0x0000d0b9}, /* U+0439 CYRILLIC SMALL LETTER SHORT I */ - {0x00a7dc, 0x0000d0ba}, /* U+043A CYRILLIC SMALL LETTER KA */ - {0x00a7dd, 0x0000d0bb}, /* U+043B CYRILLIC SMALL LETTER EL */ - {0x00a7de, 0x0000d0bc}, /* U+043C CYRILLIC SMALL LETTER EM */ - {0x00a7df, 0x0000d0bd}, /* U+043D CYRILLIC SMALL LETTER EN */ - {0x00a7e0, 0x0000d0be}, /* U+043E CYRILLIC SMALL LETTER O */ - {0x00a7e1, 0x0000d0bf}, /* U+043F CYRILLIC SMALL LETTER PE */ - {0x00a7e2, 0x0000d180}, /* U+0440 CYRILLIC SMALL LETTER ER */ - {0x00a7e3, 0x0000d181}, /* U+0441 CYRILLIC SMALL LETTER ES */ - {0x00a7e4, 0x0000d182}, /* U+0442 CYRILLIC SMALL LETTER TE */ - {0x00a7e5, 0x0000d183}, /* U+0443 CYRILLIC SMALL LETTER U */ - {0x00a7e6, 0x0000d184}, /* U+0444 CYRILLIC SMALL LETTER EF */ - {0x00a7e7, 0x0000d185}, /* U+0445 CYRILLIC SMALL LETTER HA */ - {0x00a7e8, 0x0000d186}, /* U+0446 CYRILLIC SMALL LETTER TSE */ - {0x00a7e9, 0x0000d187}, /* U+0447 CYRILLIC SMALL LETTER CHE */ - {0x00a7ea, 0x0000d188}, /* U+0448 CYRILLIC SMALL LETTER SHA */ - {0x00a7eb, 0x0000d189}, /* U+0449 CYRILLIC SMALL LETTER SHCHA */ - {0x00a7ec, 0x0000d18a}, /* U+044A CYRILLIC SMALL LETTER HARD SIGN */ - {0x00a7ed, 0x0000d18b}, /* U+044B CYRILLIC SMALL LETTER YERU */ - {0x00a7ee, 0x0000d18c}, /* U+044C CYRILLIC SMALL LETTER SOFT SIGN */ - {0x00a7ef, 0x0000d18d}, /* U+044D CYRILLIC SMALL LETTER E */ - {0x00a7f0, 0x0000d18e}, /* U+044E CYRILLIC SMALL LETTER YU */ - {0x00a7f1, 0x0000d18f}, /* U+044F CYRILLIC SMALL LETTER YA */ - {0x00a7f2, 0x00e383b7}, /* U+30F7 KATAKANA LETTER VA [2000] */ - {0x00a7f3, 0x00e383b8}, /* U+30F8 KATAKANA LETTER VI [2000] */ - {0x00a7f4, 0x00e383b9}, /* U+30F9 KATAKANA LETTER VE [2000] */ - {0x00a7f5, 0x00e383ba}, /* U+30FA KATAKANA LETTER VO [2000] */ - {0x00a7f6, 0x00e28b9a}, /* U+22DA LESS-THAN EQUAL TO OR GREATER-THAN [2000] */ - {0x00a7f7, 0x00e28b9b}, /* U+22DB GREATER-THAN EQUAL TO OR LESS-THAN [2000] */ - {0x00a7f8, 0x00e28593}, /* U+2153 VULGAR FRACTION ONE THIRD [2000] */ - {0x00a7f9, 0x00e28594}, /* U+2154 VULGAR FRACTION TWO THIRDS [2000] */ - {0x00a7fa, 0x00e28595}, /* U+2155 VULGAR FRACTION ONE FIFTH [2000] */ - {0x00a7fb, 0x00e29c93}, /* U+2713 CHECK MARK [2000] */ - {0x00a7fc, 0x00e28c98}, /* U+2318 PLACE OF INTEREST SIGN [2000] */ - {0x00a7fd, 0x00e290a3}, /* U+2423 OPEN BOX [2000] */ - {0x00a7fe, 0x00e28f8e}, /* U+23CE RETURN SYMBOL [2000] [Unicode3.2] */ - {0x00a8a1, 0x00e29480}, /* U+2500 BOX DRAWINGS LIGHT HORIZONTAL [1983] */ - {0x00a8a2, 0x00e29482}, /* U+2502 BOX DRAWINGS LIGHT VERTICAL [1983] */ - {0x00a8a3, 0x00e2948c}, /* U+250C BOX DRAWINGS LIGHT DOWN AND RIGHT [1983] */ - {0x00a8a4, 0x00e29490}, /* U+2510 BOX DRAWINGS LIGHT DOWN AND LEFT [1983] */ - {0x00a8a5, 0x00e29498}, /* U+2518 BOX DRAWINGS LIGHT UP AND LEFT [1983] */ - {0x00a8a6, 0x00e29494}, /* U+2514 BOX DRAWINGS LIGHT UP AND RIGHT [1983] */ - {0x00a8a7, 0x00e2949c}, /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT [1983] */ - {0x00a8a8, 0x00e294ac}, /* U+252C BOX DRAWINGS LIGHT DOWN AND HORIZONTAL [1983] */ - {0x00a8a9, 0x00e294a4}, /* U+2524 BOX DRAWINGS LIGHT VERTICAL AND LEFT [1983] */ - {0x00a8aa, 0x00e294b4}, /* U+2534 BOX DRAWINGS LIGHT UP AND HORIZONTAL [1983] */ - {0x00a8ab, 0x00e294bc}, /* U+253C BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL [1983] */ - {0x00a8ac, 0x00e29481}, /* U+2501 BOX DRAWINGS HEAVY HORIZONTAL [1983] */ - {0x00a8ad, 0x00e29483}, /* U+2503 BOX DRAWINGS HEAVY VERTICAL [1983] */ - {0x00a8ae, 0x00e2948f}, /* U+250F BOX DRAWINGS HEAVY DOWN AND RIGHT [1983] */ - {0x00a8af, 0x00e29493}, /* U+2513 BOX DRAWINGS HEAVY DOWN AND LEFT [1983] */ - {0x00a8b0, 0x00e2949b}, /* U+251B BOX DRAWINGS HEAVY UP AND LEFT [1983] */ - {0x00a8b1, 0x00e29497}, /* U+2517 BOX DRAWINGS HEAVY UP AND RIGHT [1983] */ - {0x00a8b2, 0x00e294a3}, /* U+2523 BOX DRAWINGS HEAVY VERTICAL AND RIGHT [1983] */ - {0x00a8b3, 0x00e294b3}, /* U+2533 BOX DRAWINGS HEAVY DOWN AND HORIZONTAL [1983] */ - {0x00a8b4, 0x00e294ab}, /* U+252B BOX DRAWINGS HEAVY VERTICAL AND LEFT [1983] */ - {0x00a8b5, 0x00e294bb}, /* U+253B BOX DRAWINGS HEAVY UP AND HORIZONTAL [1983] */ - {0x00a8b6, 0x00e2958b}, /* U+254B BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL [1983] */ - {0x00a8b7, 0x00e294a0}, /* U+2520 BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT [1983] */ - {0x00a8b8, 0x00e294af}, /* U+252F BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY [1983] */ - {0x00a8b9, 0x00e294a8}, /* U+2528 BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT [1983] */ - {0x00a8ba, 0x00e294b7}, /* U+2537 BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY [1983] */ - {0x00a8bb, 0x00e294bf}, /* U+253F BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY [1983] */ - {0x00a8bc, 0x00e2949d}, /* U+251D BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY [1983] */ - {0x00a8bd, 0x00e294b0}, /* U+2530 BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT [1983] */ - {0x00a8be, 0x00e294a5}, /* U+2525 BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY [1983] */ - {0x00a8bf, 0x00e294b8}, /* U+2538 BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT [1983] */ - {0x00a8c0, 0x00e29582}, /* U+2542 BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT [1983] */ - {0x00a8c1, 0x00e38991}, /* U+3251 CIRCLED NUMBER TWENTY ONE [2000] [Unicode3.2] */ - {0x00a8c2, 0x00e38992}, /* U+3252 CIRCLED NUMBER TWENTY TWO [2000] [Unicode3.2] */ - {0x00a8c3, 0x00e38993}, /* U+3253 CIRCLED NUMBER TWENTY THREE [2000] [Unicode3.2] */ - {0x00a8c4, 0x00e38994}, /* U+3254 CIRCLED NUMBER TWENTY FOUR [2000] [Unicode3.2] */ - {0x00a8c5, 0x00e38995}, /* U+3255 CIRCLED NUMBER TWENTY FIVE [2000] [Unicode3.2] */ - {0x00a8c6, 0x00e38996}, /* U+3256 CIRCLED NUMBER TWENTY SIX [2000] [Unicode3.2] */ - {0x00a8c7, 0x00e38997}, /* U+3257 CIRCLED NUMBER TWENTY SEVEN [2000] [Unicode3.2] */ - {0x00a8c8, 0x00e38998}, /* U+3258 CIRCLED NUMBER TWENTY EIGHT [2000] [Unicode3.2] */ - {0x00a8c9, 0x00e38999}, /* U+3259 CIRCLED NUMBER TWENTY NINE [2000] [Unicode3.2] */ - {0x00a8ca, 0x00e3899a}, /* U+325A CIRCLED NUMBER THIRTY [2000] [Unicode3.2] */ - {0x00a8cb, 0x00e3899b}, /* U+325B CIRCLED NUMBER THIRTY ONE [2000] [Unicode3.2] */ - {0x00a8cc, 0x00e3899c}, /* U+325C CIRCLED NUMBER THIRTY TWO [2000] [Unicode3.2] */ - {0x00a8cd, 0x00e3899d}, /* U+325D CIRCLED NUMBER THIRTY THREE [2000] [Unicode3.2] */ - {0x00a8ce, 0x00e3899e}, /* U+325E CIRCLED NUMBER THIRTY FOUR [2000] [Unicode3.2] */ - {0x00a8cf, 0x00e3899f}, /* U+325F CIRCLED NUMBER THIRTY FIVE [2000] [Unicode3.2] */ - {0x00a8d0, 0x00e38ab1}, /* U+32B1 CIRCLED NUMBER THIRTY SIX [2000] [Unicode3.2] */ - {0x00a8d1, 0x00e38ab2}, /* U+32B2 CIRCLED NUMBER THIRTY SEVEN [2000] [Unicode3.2] */ - {0x00a8d2, 0x00e38ab3}, /* U+32B3 CIRCLED NUMBER THIRTY EIGHT [2000] [Unicode3.2] */ - {0x00a8d3, 0x00e38ab4}, /* U+32B4 CIRCLED NUMBER THIRTY NINE [2000] [Unicode3.2] */ - {0x00a8d4, 0x00e38ab5}, /* U+32B5 CIRCLED NUMBER FORTY [2000] [Unicode3.2] */ - {0x00a8d5, 0x00e38ab6}, /* U+32B6 CIRCLED NUMBER FORTY ONE [2000] [Unicode3.2] */ - {0x00a8d6, 0x00e38ab7}, /* U+32B7 CIRCLED NUMBER FORTY TWO [2000] [Unicode3.2] */ - {0x00a8d7, 0x00e38ab8}, /* U+32B8 CIRCLED NUMBER FORTY THREE [2000] [Unicode3.2] */ - {0x00a8d8, 0x00e38ab9}, /* U+32B9 CIRCLED NUMBER FORTY FOUR [2000] [Unicode3.2] */ - {0x00a8d9, 0x00e38aba}, /* U+32BA CIRCLED NUMBER FORTY FIVE [2000] [Unicode3.2] */ - {0x00a8da, 0x00e38abb}, /* U+32BB CIRCLED NUMBER FORTY SIX [2000] [Unicode3.2] */ - {0x00a8db, 0x00e38abc}, /* U+32BC CIRCLED NUMBER FORTY SEVEN [2000] [Unicode3.2] */ - {0x00a8dc, 0x00e38abd}, /* U+32BD CIRCLED NUMBER FORTY EIGHT [2000] [Unicode3.2] */ - {0x00a8dd, 0x00e38abe}, /* U+32BE CIRCLED NUMBER FORTY NINE [2000] [Unicode3.2] */ - {0x00a8de, 0x00e38abf}, /* U+32BF CIRCLED NUMBER FIFTY [2000] [Unicode3.2] */ - {0x00a8e7, 0x00e29790}, /* U+25D0 CIRCLE WITH LEFT HALF BLACK [2000] */ - {0x00a8e8, 0x00e29791}, /* U+25D1 CIRCLE WITH RIGHT HALF BLACK [2000] */ - {0x00a8e9, 0x00e29792}, /* U+25D2 CIRCLE WITH LOWER HALF BLACK [2000] */ - {0x00a8ea, 0x00e29793}, /* U+25D3 CIRCLE WITH UPPER HALF BLACK [2000] */ - {0x00a8eb, 0x00e280bc}, /* U+203C DOUBLE EXCLAMATION MARK [2000] */ - {0x00a8ec, 0x00e28187}, /* U+2047 DOUBLE QUESTION MARK [2000] [Unicode3.2] */ - {0x00a8ed, 0x00e28188}, /* U+2048 QUESTION EXCLAMATION MARK [2000] */ - {0x00a8ee, 0x00e28189}, /* U+2049 EXCLAMATION QUESTION MARK [2000] */ - {0x00a8ef, 0x0000c78d}, /* U+01CD LATIN CAPITAL LETTER A WITH CARON [2000] */ - {0x00a8f0, 0x0000c78e}, /* U+01CE LATIN SMALL LETTER A WITH CARON [2000] */ - {0x00a8f1, 0x0000c790}, /* U+01D0 LATIN SMALL LETTER I WITH CARON [2000] */ - {0x00a8f2, 0x00e1b8be}, /* U+1E3E LATIN CAPITAL LETTER M WITH ACUTE [2000] */ - {0x00a8f3, 0x00e1b8bf}, /* U+1E3F LATIN SMALL LETTER M WITH ACUTE [2000] */ - {0x00a8f4, 0x0000c7b8}, /* U+01F8 LATIN CAPITAL LETTER N WITH GRAVE [2000] */ - {0x00a8f5, 0x0000c7b9}, /* U+01F9 LATIN SMALL LETTER N WITH GRAVE [2000] */ - {0x00a8f6, 0x0000c791}, /* U+01D1 LATIN CAPITAL LETTER O WITH CARON [2000] */ - {0x00a8f7, 0x0000c792}, /* U+01D2 LATIN SMALL LETTER O WITH CARON [2000] */ - {0x00a8f8, 0x0000c794}, /* U+01D4 LATIN SMALL LETTER U WITH CARON [2000] */ - {0x00a8f9, 0x0000c796}, /* U+01D6 LATIN SMALL LETTER U WITH DIAERESIS AND MACRON [2000] */ - {0x00a8fa, 0x0000c798}, /* U+01D8 LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE [2000] */ - {0x00a8fb, 0x0000c79a}, /* U+01DA LATIN SMALL LETTER U WITH DIAERESIS AND CARON [2000] */ - {0x00a8fc, 0x0000c79c}, /* U+01DC LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE [2000] */ - {0x00a9a1, 0x00e282ac}, /* U+20AC EURO SIGN [2000] */ - {0x00a9a2, 0x0000c2a0}, /* U+00A0 NO-BREAK SPACE [2000] */ - {0x00a9a3, 0x0000c2a1}, /* U+00A1 INVERTED EXCLAMATION MARK [2000] */ - {0x00a9a4, 0x0000c2a4}, /* U+00A4 CURRENCY SIGN [2000] */ - {0x00a9a5, 0x0000c2a6}, /* U+00A6 BROKEN BAR [2000] */ - {0x00a9a6, 0x0000c2a9}, /* U+00A9 COPYRIGHT SIGN [2000] */ - {0x00a9a7, 0x0000c2aa}, /* U+00AA FEMININE ORDINAL INDICATOR [2000] */ - {0x00a9a8, 0x0000c2ab}, /* U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK [2000] */ - {0x00a9a9, 0x0000c2ad}, /* U+00AD SOFT HYPHEN [2000] */ - {0x00a9aa, 0x0000c2ae}, /* U+00AE REGISTERED SIGN [2000] */ - {0x00a9ab, 0x0000c2af}, /* U+00AF MACRON [2000] */ - {0x00a9ac, 0x0000c2b2}, /* U+00B2 SUPERSCRIPT TWO [2000] */ - {0x00a9ad, 0x0000c2b3}, /* U+00B3 SUPERSCRIPT THREE [2000] */ - {0x00a9ae, 0x0000c2b7}, /* U+00B7 MIDDLE DOT [2000] */ - {0x00a9af, 0x0000c2b8}, /* U+00B8 CEDILLA [2000] */ - {0x00a9b0, 0x0000c2b9}, /* U+00B9 SUPERSCRIPT ONE [2000] */ - {0x00a9b1, 0x0000c2ba}, /* U+00BA MASCULINE ORDINAL INDICATOR [2000] */ - {0x00a9b2, 0x0000c2bb}, /* U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK [2000] */ - {0x00a9b3, 0x0000c2bc}, /* U+00BC VULGAR FRACTION ONE QUARTER [2000] */ - {0x00a9b4, 0x0000c2bd}, /* U+00BD VULGAR FRACTION ONE HALF [2000] */ - {0x00a9b5, 0x0000c2be}, /* U+00BE VULGAR FRACTION THREE QUARTERS [2000] */ - {0x00a9b6, 0x0000c2bf}, /* U+00BF INVERTED QUESTION MARK [2000] */ - {0x00a9b7, 0x0000c380}, /* U+00C0 LATIN CAPITAL LETTER A WITH GRAVE [2000] */ - {0x00a9b8, 0x0000c381}, /* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE [2000] */ - {0x00a9b9, 0x0000c382}, /* U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX [2000] */ - {0x00a9ba, 0x0000c383}, /* U+00C3 LATIN CAPITAL LETTER A WITH TILDE [2000] */ - {0x00a9bb, 0x0000c384}, /* U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS [2000] */ - {0x00a9bc, 0x0000c385}, /* U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE [2000] */ - {0x00a9bd, 0x0000c386}, /* U+00C6 LATIN CAPITAL LETTER AE [2000] */ - {0x00a9be, 0x0000c387}, /* U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA [2000] */ - {0x00a9bf, 0x0000c388}, /* U+00C8 LATIN CAPITAL LETTER E WITH GRAVE [2000] */ - {0x00a9c0, 0x0000c389}, /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE [2000] */ - {0x00a9c1, 0x0000c38a}, /* U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX [2000] */ - {0x00a9c2, 0x0000c38b}, /* U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS [2000] */ - {0x00a9c3, 0x0000c38c}, /* U+00CC LATIN CAPITAL LETTER I WITH GRAVE [2000] */ - {0x00a9c4, 0x0000c38d}, /* U+00CD LATIN CAPITAL LETTER I WITH ACUTE [2000] */ - {0x00a9c5, 0x0000c38e}, /* U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX [2000] */ - {0x00a9c6, 0x0000c38f}, /* U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS [2000] */ - {0x00a9c7, 0x0000c390}, /* U+00D0 LATIN CAPITAL LETTER ETH [2000] */ - {0x00a9c8, 0x0000c391}, /* U+00D1 LATIN CAPITAL LETTER N WITH TILDE [2000] */ - {0x00a9c9, 0x0000c392}, /* U+00D2 LATIN CAPITAL LETTER O WITH GRAVE [2000] */ - {0x00a9ca, 0x0000c393}, /* U+00D3 LATIN CAPITAL LETTER O WITH ACUTE [2000] */ - {0x00a9cb, 0x0000c394}, /* U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX [2000] */ - {0x00a9cc, 0x0000c395}, /* U+00D5 LATIN CAPITAL LETTER O WITH TILDE [2000] */ - {0x00a9cd, 0x0000c396}, /* U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS [2000] */ - {0x00a9ce, 0x0000c398}, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE [2000] */ - {0x00a9cf, 0x0000c399}, /* U+00D9 LATIN CAPITAL LETTER U WITH GRAVE [2000] */ - {0x00a9d0, 0x0000c39a}, /* U+00DA LATIN CAPITAL LETTER U WITH ACUTE [2000] */ - {0x00a9d1, 0x0000c39b}, /* U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX [2000] */ - {0x00a9d2, 0x0000c39c}, /* U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS [2000] */ - {0x00a9d3, 0x0000c39d}, /* U+00DD LATIN CAPITAL LETTER Y WITH ACUTE [2000] */ - {0x00a9d4, 0x0000c39e}, /* U+00DE LATIN CAPITAL LETTER THORN [2000] */ - {0x00a9d5, 0x0000c39f}, /* U+00DF LATIN SMALL LETTER SHARP S [2000] */ - {0x00a9d6, 0x0000c3a0}, /* U+00E0 LATIN SMALL LETTER A WITH GRAVE [2000] */ - {0x00a9d7, 0x0000c3a1}, /* U+00E1 LATIN SMALL LETTER A WITH ACUTE [2000] */ - {0x00a9d8, 0x0000c3a2}, /* U+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX [2000] */ - {0x00a9d9, 0x0000c3a3}, /* U+00E3 LATIN SMALL LETTER A WITH TILDE [2000] */ - {0x00a9da, 0x0000c3a4}, /* U+00E4 LATIN SMALL LETTER A WITH DIAERESIS [2000] */ - {0x00a9db, 0x0000c3a5}, /* U+00E5 LATIN SMALL LETTER A WITH RING ABOVE [2000] */ - {0x00a9dc, 0x0000c3a6}, /* U+00E6 LATIN SMALL LETTER AE [2000] */ - {0x00a9dd, 0x0000c3a7}, /* U+00E7 LATIN SMALL LETTER C WITH CEDILLA [2000] */ - {0x00a9de, 0x0000c3a8}, /* U+00E8 LATIN SMALL LETTER E WITH GRAVE [2000] */ - {0x00a9df, 0x0000c3a9}, /* U+00E9 LATIN SMALL LETTER E WITH ACUTE [2000] */ - {0x00a9e0, 0x0000c3aa}, /* U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX [2000] */ - {0x00a9e1, 0x0000c3ab}, /* U+00EB LATIN SMALL LETTER E WITH DIAERESIS [2000] */ - {0x00a9e2, 0x0000c3ac}, /* U+00EC LATIN SMALL LETTER I WITH GRAVE [2000] */ - {0x00a9e3, 0x0000c3ad}, /* U+00ED LATIN SMALL LETTER I WITH ACUTE [2000] */ - {0x00a9e4, 0x0000c3ae}, /* U+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX [2000] */ - {0x00a9e5, 0x0000c3af}, /* U+00EF LATIN SMALL LETTER I WITH DIAERESIS [2000] */ - {0x00a9e6, 0x0000c3b0}, /* U+00F0 LATIN SMALL LETTER ETH [2000] */ - {0x00a9e7, 0x0000c3b1}, /* U+00F1 LATIN SMALL LETTER N WITH TILDE [2000] */ - {0x00a9e8, 0x0000c3b2}, /* U+00F2 LATIN SMALL LETTER O WITH GRAVE [2000] */ - {0x00a9e9, 0x0000c3b3}, /* U+00F3 LATIN SMALL LETTER O WITH ACUTE [2000] */ - {0x00a9ea, 0x0000c3b4}, /* U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX [2000] */ - {0x00a9eb, 0x0000c3b5}, /* U+00F5 LATIN SMALL LETTER O WITH TILDE [2000] */ - {0x00a9ec, 0x0000c3b6}, /* U+00F6 LATIN SMALL LETTER O WITH DIAERESIS [2000] */ - {0x00a9ed, 0x0000c3b8}, /* U+00F8 LATIN SMALL LETTER O WITH STROKE [2000] */ - {0x00a9ee, 0x0000c3b9}, /* U+00F9 LATIN SMALL LETTER U WITH GRAVE [2000] */ - {0x00a9ef, 0x0000c3ba}, /* U+00FA LATIN SMALL LETTER U WITH ACUTE [2000] */ - {0x00a9f0, 0x0000c3bb}, /* U+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX [2000] */ - {0x00a9f1, 0x0000c3bc}, /* U+00FC LATIN SMALL LETTER U WITH DIAERESIS [2000] */ - {0x00a9f2, 0x0000c3bd}, /* U+00FD LATIN SMALL LETTER Y WITH ACUTE [2000] */ - {0x00a9f3, 0x0000c3be}, /* U+00FE LATIN SMALL LETTER THORN [2000] */ - {0x00a9f4, 0x0000c3bf}, /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS [2000] */ - {0x00a9f5, 0x0000c480}, /* U+0100 LATIN CAPITAL LETTER A WITH MACRON [2000] */ - {0x00a9f6, 0x0000c4aa}, /* U+012A LATIN CAPITAL LETTER I WITH MACRON [2000] */ - {0x00a9f7, 0x0000c5aa}, /* U+016A LATIN CAPITAL LETTER U WITH MACRON [2000] */ - {0x00a9f8, 0x0000c492}, /* U+0112 LATIN CAPITAL LETTER E WITH MACRON [2000] */ - {0x00a9f9, 0x0000c58c}, /* U+014C LATIN CAPITAL LETTER O WITH MACRON [2000] */ - {0x00a9fa, 0x0000c481}, /* U+0101 LATIN SMALL LETTER A WITH MACRON [2000] */ - {0x00a9fb, 0x0000c4ab}, /* U+012B LATIN SMALL LETTER I WITH MACRON [2000] */ - {0x00a9fc, 0x0000c5ab}, /* U+016B LATIN SMALL LETTER U WITH MACRON [2000] */ - {0x00a9fd, 0x0000c493}, /* U+0113 LATIN SMALL LETTER E WITH MACRON [2000] */ - {0x00a9fe, 0x0000c58d}, /* U+014D LATIN SMALL LETTER O WITH MACRON [2000] */ - {0x00aaa1, 0x0000c484}, /* U+0104 LATIN CAPITAL LETTER A WITH OGONEK [2000] */ - {0x00aaa2, 0x0000cb98}, /* U+02D8 BREVE [2000] */ - {0x00aaa3, 0x0000c581}, /* U+0141 LATIN CAPITAL LETTER L WITH STROKE [2000] */ - {0x00aaa4, 0x0000c4bd}, /* U+013D LATIN CAPITAL LETTER L WITH CARON [2000] */ - {0x00aaa5, 0x0000c59a}, /* U+015A LATIN CAPITAL LETTER S WITH ACUTE [2000] */ - {0x00aaa6, 0x0000c5a0}, /* U+0160 LATIN CAPITAL LETTER S WITH CARON [2000] */ - {0x00aaa7, 0x0000c59e}, /* U+015E LATIN CAPITAL LETTER S WITH CEDILLA [2000] */ - {0x00aaa8, 0x0000c5a4}, /* U+0164 LATIN CAPITAL LETTER T WITH CARON [2000] */ - {0x00aaa9, 0x0000c5b9}, /* U+0179 LATIN CAPITAL LETTER Z WITH ACUTE [2000] */ - {0x00aaaa, 0x0000c5bd}, /* U+017D LATIN CAPITAL LETTER Z WITH CARON [2000] */ - {0x00aaab, 0x0000c5bb}, /* U+017B LATIN CAPITAL LETTER Z WITH DOT ABOVE [2000] */ - {0x00aaac, 0x0000c485}, /* U+0105 LATIN SMALL LETTER A WITH OGONEK [2000] */ - {0x00aaad, 0x0000cb9b}, /* U+02DB OGONEK [2000] */ - {0x00aaae, 0x0000c582}, /* U+0142 LATIN SMALL LETTER L WITH STROKE [2000] */ - {0x00aaaf, 0x0000c4be}, /* U+013E LATIN SMALL LETTER L WITH CARON [2000] */ - {0x00aab0, 0x0000c59b}, /* U+015B LATIN SMALL LETTER S WITH ACUTE [2000] */ - {0x00aab1, 0x0000cb87}, /* U+02C7 CARON [2000] */ - {0x00aab2, 0x0000c5a1}, /* U+0161 LATIN SMALL LETTER S WITH CARON [2000] */ - {0x00aab3, 0x0000c59f}, /* U+015F LATIN SMALL LETTER S WITH CEDILLA [2000] */ - {0x00aab4, 0x0000c5a5}, /* U+0165 LATIN SMALL LETTER T WITH CARON [2000] */ - {0x00aab5, 0x0000c5ba}, /* U+017A LATIN SMALL LETTER Z WITH ACUTE [2000] */ - {0x00aab6, 0x0000cb9d}, /* U+02DD DOUBLE ACUTE ACCENT [2000] */ - {0x00aab7, 0x0000c5be}, /* U+017E LATIN SMALL LETTER Z WITH CARON [2000] */ - {0x00aab8, 0x0000c5bc}, /* U+017C LATIN SMALL LETTER Z WITH DOT ABOVE [2000] */ - {0x00aab9, 0x0000c594}, /* U+0154 LATIN CAPITAL LETTER R WITH ACUTE [2000] */ - {0x00aaba, 0x0000c482}, /* U+0102 LATIN CAPITAL LETTER A WITH BREVE [2000] */ - {0x00aabb, 0x0000c4b9}, /* U+0139 LATIN CAPITAL LETTER L WITH ACUTE [2000] */ - {0x00aabc, 0x0000c486}, /* U+0106 LATIN CAPITAL LETTER C WITH ACUTE [2000] */ - {0x00aabd, 0x0000c48c}, /* U+010C LATIN CAPITAL LETTER C WITH CARON [2000] */ - {0x00aabe, 0x0000c498}, /* U+0118 LATIN CAPITAL LETTER E WITH OGONEK [2000] */ - {0x00aabf, 0x0000c49a}, /* U+011A LATIN CAPITAL LETTER E WITH CARON [2000] */ - {0x00aac0, 0x0000c48e}, /* U+010E LATIN CAPITAL LETTER D WITH CARON [2000] */ - {0x00aac1, 0x0000c583}, /* U+0143 LATIN CAPITAL LETTER N WITH ACUTE [2000] */ - {0x00aac2, 0x0000c587}, /* U+0147 LATIN CAPITAL LETTER N WITH CARON [2000] */ - {0x00aac3, 0x0000c590}, /* U+0150 LATIN CAPITAL LETTER O WITH DOUBLE ACUTE [2000] */ - {0x00aac4, 0x0000c598}, /* U+0158 LATIN CAPITAL LETTER R WITH CARON [2000] */ - {0x00aac5, 0x0000c5ae}, /* U+016E LATIN CAPITAL LETTER U WITH RING ABOVE [2000] */ - {0x00aac6, 0x0000c5b0}, /* U+0170 LATIN CAPITAL LETTER U WITH DOUBLE ACUTE [2000] */ - {0x00aac7, 0x0000c5a2}, /* U+0162 LATIN CAPITAL LETTER T WITH CEDILLA [2000] */ - {0x00aac8, 0x0000c595}, /* U+0155 LATIN SMALL LETTER R WITH ACUTE [2000] */ - {0x00aac9, 0x0000c483}, /* U+0103 LATIN SMALL LETTER A WITH BREVE [2000] */ - {0x00aaca, 0x0000c4ba}, /* U+013A LATIN SMALL LETTER L WITH ACUTE [2000] */ - {0x00aacb, 0x0000c487}, /* U+0107 LATIN SMALL LETTER C WITH ACUTE [2000] */ - {0x00aacc, 0x0000c48d}, /* U+010D LATIN SMALL LETTER C WITH CARON [2000] */ - {0x00aacd, 0x0000c499}, /* U+0119 LATIN SMALL LETTER E WITH OGONEK [2000] */ - {0x00aace, 0x0000c49b}, /* U+011B LATIN SMALL LETTER E WITH CARON [2000] */ - {0x00aacf, 0x0000c48f}, /* U+010F LATIN SMALL LETTER D WITH CARON [2000] */ - {0x00aad0, 0x0000c491}, /* U+0111 LATIN SMALL LETTER D WITH STROKE [2000] */ - {0x00aad1, 0x0000c584}, /* U+0144 LATIN SMALL LETTER N WITH ACUTE [2000] */ - {0x00aad2, 0x0000c588}, /* U+0148 LATIN SMALL LETTER N WITH CARON [2000] */ - {0x00aad3, 0x0000c591}, /* U+0151 LATIN SMALL LETTER O WITH DOUBLE ACUTE [2000] */ - {0x00aad4, 0x0000c599}, /* U+0159 LATIN SMALL LETTER R WITH CARON [2000] */ - {0x00aad5, 0x0000c5af}, /* U+016F LATIN SMALL LETTER U WITH RING ABOVE [2000] */ - {0x00aad6, 0x0000c5b1}, /* U+0171 LATIN SMALL LETTER U WITH DOUBLE ACUTE [2000] */ - {0x00aad7, 0x0000c5a3}, /* U+0163 LATIN SMALL LETTER T WITH CEDILLA [2000] */ - {0x00aad8, 0x0000cb99}, /* U+02D9 DOT ABOVE [2000] */ - {0x00aad9, 0x0000c488}, /* U+0108 LATIN CAPITAL LETTER C WITH CIRCUMFLEX [2000] */ - {0x00aada, 0x0000c49c}, /* U+011C LATIN CAPITAL LETTER G WITH CIRCUMFLEX [2000] */ - {0x00aadb, 0x0000c4a4}, /* U+0124 LATIN CAPITAL LETTER H WITH CIRCUMFLEX [2000] */ - {0x00aadc, 0x0000c4b4}, /* U+0134 LATIN CAPITAL LETTER J WITH CIRCUMFLEX [2000] */ - {0x00aadd, 0x0000c59c}, /* U+015C LATIN CAPITAL LETTER S WITH CIRCUMFLEX [2000] */ - {0x00aade, 0x0000c5ac}, /* U+016C LATIN CAPITAL LETTER U WITH BREVE [2000] */ - {0x00aadf, 0x0000c489}, /* U+0109 LATIN SMALL LETTER C WITH CIRCUMFLEX [2000] */ - {0x00aae0, 0x0000c49d}, /* U+011D LATIN SMALL LETTER G WITH CIRCUMFLEX [2000] */ - {0x00aae1, 0x0000c4a5}, /* U+0125 LATIN SMALL LETTER H WITH CIRCUMFLEX [2000] */ - {0x00aae2, 0x0000c4b5}, /* U+0135 LATIN SMALL LETTER J WITH CIRCUMFLEX [2000] */ - {0x00aae3, 0x0000c59d}, /* U+015D LATIN SMALL LETTER S WITH CIRCUMFLEX [2000] */ - {0x00aae4, 0x0000c5ad}, /* U+016D LATIN SMALL LETTER U WITH BREVE [2000] */ - {0x00aae5, 0x0000c9b1}, /* U+0271 LATIN SMALL LETTER M WITH HOOK [2000] */ - {0x00aae6, 0x0000ca8b}, /* U+028B LATIN SMALL LETTER V WITH HOOK [2000] */ - {0x00aae7, 0x0000c9be}, /* U+027E LATIN SMALL LETTER R WITH FISHHOOK [2000] */ - {0x00aae8, 0x0000ca83}, /* U+0283 LATIN SMALL LETTER ESH [2000] */ - {0x00aae9, 0x0000ca92}, /* U+0292 LATIN SMALL LETTER EZH [2000] */ - {0x00aaea, 0x0000c9ac}, /* U+026C LATIN SMALL LETTER L WITH BELT [2000] */ - {0x00aaeb, 0x0000c9ae}, /* U+026E LATIN SMALL LETTER LEZH [2000] */ - {0x00aaec, 0x0000c9b9}, /* U+0279 LATIN SMALL LETTER TURNED R [2000] */ - {0x00aaed, 0x0000ca88}, /* U+0288 LATIN SMALL LETTER T WITH RETROFLEX HOOK [2000] */ - {0x00aaee, 0x0000c996}, /* U+0256 LATIN SMALL LETTER D WITH TAIL [2000] */ - {0x00aaef, 0x0000c9b3}, /* U+0273 LATIN SMALL LETTER N WITH RETROFLEX HOOK [2000] */ - {0x00aaf0, 0x0000c9bd}, /* U+027D LATIN SMALL LETTER R WITH TAIL [2000] */ - {0x00aaf1, 0x0000ca82}, /* U+0282 LATIN SMALL LETTER S WITH HOOK [2000] */ - {0x00aaf2, 0x0000ca90}, /* U+0290 LATIN SMALL LETTER Z WITH RETROFLEX HOOK [2000] */ - {0x00aaf3, 0x0000c9bb}, /* U+027B LATIN SMALL LETTER TURNED R WITH HOOK [2000] */ - {0x00aaf4, 0x0000c9ad}, /* U+026D LATIN SMALL LETTER L WITH RETROFLEX HOOK [2000] */ - {0x00aaf5, 0x0000c99f}, /* U+025F LATIN SMALL LETTER DOTLESS J WITH STROKE [2000] */ - {0x00aaf6, 0x0000c9b2}, /* U+0272 LATIN SMALL LETTER N WITH LEFT HOOK [2000] */ - {0x00aaf7, 0x0000ca9d}, /* U+029D LATIN SMALL LETTER J WITH CROSSED-TAIL [2000] */ - {0x00aaf8, 0x0000ca8e}, /* U+028E LATIN SMALL LETTER TURNED Y [2000] */ - {0x00aaf9, 0x0000c9a1}, /* U+0261 LATIN SMALL LETTER SCRIPT G [2000] */ - {0x00aafa, 0x0000c58b}, /* U+014B LATIN SMALL LETTER ENG [2000] */ - {0x00aafb, 0x0000c9b0}, /* U+0270 LATIN SMALL LETTER TURNED M WITH LONG LEG [2000] */ - {0x00aafc, 0x0000ca81}, /* U+0281 LATIN LETTER SMALL CAPITAL INVERTED R [2000] */ - {0x00aafd, 0x0000c4a7}, /* U+0127 LATIN SMALL LETTER H WITH STROKE [2000] */ - {0x00aafe, 0x0000ca95}, /* U+0295 LATIN LETTER PHARYNGEAL VOICED FRICATIVE [2000] */ - {0x00aba1, 0x0000ca94}, /* U+0294 LATIN LETTER GLOTTAL STOP [2000] */ - {0x00aba2, 0x0000c9a6}, /* U+0266 LATIN SMALL LETTER H WITH HOOK [2000] */ - {0x00aba3, 0x0000ca98}, /* U+0298 LATIN LETTER BILABIAL CLICK [2000] */ - {0x00aba4, 0x0000c782}, /* U+01C2 LATIN LETTER ALVEOLAR CLICK [2000] */ - {0x00aba5, 0x0000c993}, /* U+0253 LATIN SMALL LETTER B WITH HOOK [2000] */ - {0x00aba6, 0x0000c997}, /* U+0257 LATIN SMALL LETTER D WITH HOOK [2000] */ - {0x00aba7, 0x0000ca84}, /* U+0284 LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK [2000] */ - {0x00aba8, 0x0000c9a0}, /* U+0260 LATIN SMALL LETTER G WITH HOOK [2000] */ - {0x00aba9, 0x0000c693}, /* U+0193 LATIN CAPITAL LETTER G WITH HOOK [2000] */ - {0x00abaa, 0x0000c593}, /* U+0153 LATIN SMALL LIGATURE OE [2000] */ - {0x00abab, 0x0000c592}, /* U+0152 LATIN CAPITAL LIGATURE OE [2000] */ - {0x00abac, 0x0000c9a8}, /* U+0268 LATIN SMALL LETTER I WITH STROKE [2000] */ - {0x00abad, 0x0000ca89}, /* U+0289 LATIN SMALL LETTER U BAR [2000] */ - {0x00abae, 0x0000c998}, /* U+0258 LATIN SMALL LETTER REVERSED E [2000] */ - {0x00abaf, 0x0000c9b5}, /* U+0275 LATIN SMALL LETTER BARRED O [2000] */ - {0x00abb0, 0x0000c999}, /* U+0259 LATIN SMALL LETTER SCHWA [2000] */ - {0x00abb1, 0x0000c99c}, /* U+025C LATIN SMALL LETTER REVERSED OPEN E [2000] */ - {0x00abb2, 0x0000c99e}, /* U+025E LATIN SMALL LETTER CLOSED REVERSED OPEN E [2000] */ - {0x00abb3, 0x0000c990}, /* U+0250 LATIN SMALL LETTER TURNED A [2000] */ - {0x00abb4, 0x0000c9af}, /* U+026F LATIN SMALL LETTER TURNED M [2000] */ - {0x00abb5, 0x0000ca8a}, /* U+028A LATIN SMALL LETTER UPSILON [2000] */ - {0x00abb6, 0x0000c9a4}, /* U+0264 LATIN SMALL LETTER RAMS HORN [2000] */ - {0x00abb7, 0x0000ca8c}, /* U+028C LATIN SMALL LETTER TURNED V [2000] */ - {0x00abb8, 0x0000c994}, /* U+0254 LATIN SMALL LETTER OPEN O [2000] */ - {0x00abb9, 0x0000c991}, /* U+0251 LATIN SMALL LETTER ALPHA [2000] */ - {0x00abba, 0x0000c992}, /* U+0252 LATIN SMALL LETTER TURNED ALPHA [2000] */ - {0x00abbb, 0x0000ca8d}, /* U+028D LATIN SMALL LETTER TURNED W [2000] */ - {0x00abbc, 0x0000c9a5}, /* U+0265 LATIN SMALL LETTER TURNED H [2000] */ - {0x00abbd, 0x0000caa2}, /* U+02A2 LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE [2000] */ - {0x00abbe, 0x0000caa1}, /* U+02A1 LATIN LETTER GLOTTAL STOP WITH STROKE [2000] */ - {0x00abbf, 0x0000c995}, /* U+0255 LATIN SMALL LETTER C WITH CURL [2000] */ - {0x00abc0, 0x0000ca91}, /* U+0291 LATIN SMALL LETTER Z WITH CURL [2000] */ - {0x00abc1, 0x0000c9ba}, /* U+027A LATIN SMALL LETTER TURNED R WITH LONG LEG [2000] */ - {0x00abc2, 0x0000c9a7}, /* U+0267 LATIN SMALL LETTER HENG WITH HOOK [2000] */ - {0x00abc3, 0x0000c99a}, /* U+025A LATIN SMALL LETTER SCHWA WITH HOOK [2000] */ - {0x00abc5, 0x0000c7bd}, /* U+01FD LATIN SMALL LETTER AE WITH ACUTE [2000] */ - {0x00abc6, 0x00e1bdb0}, /* U+1F70 GREEK SMALL LETTER ALPHA WITH VARIA [2000] */ - {0x00abc7, 0x00e1bdb1}, /* U+1F71 GREEK SMALL LETTER ALPHA WITH OXIA [2000] */ - {0x00abd0, 0x00e1bdb2}, /* U+1F72 GREEK SMALL LETTER EPSILON WITH VARIA [2000] */ - {0x00abd1, 0x00e1bdb3}, /* U+1F73 GREEK SMALL LETTER EPSILON WITH OXIA [2000] */ - {0x00abd2, 0x0000cda1}, /* U+0361 COMBINING DOUBLE INVERTED BREVE [2000] */ - {0x00abd3, 0x0000cb88}, /* U+02C8 MODIFIER LETTER VERTICAL LINE [2000] */ - {0x00abd4, 0x0000cb8c}, /* U+02CC MODIFIER LETTER LOW VERTICAL LINE [2000] */ - {0x00abd5, 0x0000cb90}, /* U+02D0 MODIFIER LETTER TRIANGULAR COLON [2000] */ - {0x00abd6, 0x0000cb91}, /* U+02D1 MODIFIER LETTER HALF TRIANGULAR COLON [2000] */ - {0x00abd7, 0x0000cc86}, /* U+0306 COMBINING BREVE [2000] */ - {0x00abd8, 0x00e280bf}, /* U+203F UNDERTIE [2000] */ - {0x00abd9, 0x0000cc8b}, /* U+030B COMBINING DOUBLE ACUTE ACCENT [2000] */ - {0x00abda, 0x0000cc81}, /* U+0301 COMBINING ACUTE ACCENT [2000] */ - {0x00abdb, 0x0000cc84}, /* U+0304 COMBINING MACRON [2000] */ - {0x00abdc, 0x0000cc80}, /* U+0300 COMBINING GRAVE ACCENT [2000] */ - {0x00abdd, 0x0000cc8f}, /* U+030F COMBINING DOUBLE GRAVE ACCENT [2000] */ - {0x00abde, 0x0000cc8c}, /* U+030C COMBINING CARON [2000] */ - {0x00abdf, 0x0000cc82}, /* U+0302 COMBINING CIRCUMFLEX ACCENT [2000] */ - {0x00abe0, 0x0000cba5}, /* U+02E5 MODIFIER LETTER EXTRA-HIGH TONE BAR [2000] */ - {0x00abe1, 0x0000cba6}, /* U+02E6 MODIFIER LETTER HIGH TONE BAR [2000] */ - {0x00abe2, 0x0000cba7}, /* U+02E7 MODIFIER LETTER MID TONE BAR [2000] */ - {0x00abe3, 0x0000cba8}, /* U+02E8 MODIFIER LETTER LOW TONE BAR [2000] */ - {0x00abe4, 0x0000cba9}, /* U+02E9 MODIFIER LETTER EXTRA-LOW TONE BAR [2000] */ - {0x00abe7, 0x0000cca5}, /* U+0325 COMBINING RING BELOW [2000] */ - {0x00abe8, 0x0000ccac}, /* U+032C COMBINING CARON BELOW [2000] */ - {0x00abe9, 0x0000ccb9}, /* U+0339 COMBINING RIGHT HALF RING BELOW [2000] */ - {0x00abea, 0x0000cc9c}, /* U+031C COMBINING LEFT HALF RING BELOW [2000] */ - {0x00abeb, 0x0000cc9f}, /* U+031F COMBINING PLUS SIGN BELOW [2000] */ - {0x00abec, 0x0000cca0}, /* U+0320 COMBINING MINUS SIGN BELOW [2000] */ - {0x00abed, 0x0000cc88}, /* U+0308 COMBINING DIAERESIS [2000] */ - {0x00abee, 0x0000ccbd}, /* U+033D COMBINING X ABOVE [2000] */ - {0x00abef, 0x0000cca9}, /* U+0329 COMBINING VERTICAL LINE BELOW [2000] */ - {0x00abf0, 0x0000ccaf}, /* U+032F COMBINING INVERTED BREVE BELOW [2000] */ - {0x00abf1, 0x0000cb9e}, /* U+02DE MODIFIER LETTER RHOTIC HOOK [2000] */ - {0x00abf2, 0x0000cca4}, /* U+0324 COMBINING DIAERESIS BELOW [2000] */ - {0x00abf3, 0x0000ccb0}, /* U+0330 COMBINING TILDE BELOW [2000] */ - {0x00abf4, 0x0000ccbc}, /* U+033C COMBINING SEAGULL BELOW [2000] */ - {0x00abf5, 0x0000ccb4}, /* U+0334 COMBINING TILDE OVERLAY [2000] */ - {0x00abf6, 0x0000cc9d}, /* U+031D COMBINING UP TACK BELOW [2000] */ - {0x00abf7, 0x0000cc9e}, /* U+031E COMBINING DOWN TACK BELOW [2000] */ - {0x00abf8, 0x0000cc98}, /* U+0318 COMBINING LEFT TACK BELOW [2000] */ - {0x00abf9, 0x0000cc99}, /* U+0319 COMBINING RIGHT TACK BELOW [2000] */ - {0x00abfa, 0x0000ccaa}, /* U+032A COMBINING BRIDGE BELOW [2000] */ - {0x00abfb, 0x0000ccba}, /* U+033A COMBINING INVERTED BRIDGE BELOW [2000] */ - {0x00abfc, 0x0000ccbb}, /* U+033B COMBINING SQUARE BELOW [2000] */ - {0x00abfd, 0x0000cc83}, /* U+0303 COMBINING TILDE [2000] */ - {0x00abfe, 0x0000cc9a}, /* U+031A COMBINING LEFT ANGLE ABOVE [2000] */ - {0x00aca1, 0x00e29db6}, /* U+2776 DINGBAT NEGATIVE CIRCLED DIGIT ONE [2000] */ - {0x00aca2, 0x00e29db7}, /* U+2777 DINGBAT NEGATIVE CIRCLED DIGIT TWO [2000] */ - {0x00aca3, 0x00e29db8}, /* U+2778 DINGBAT NEGATIVE CIRCLED DIGIT THREE [2000] */ - {0x00aca4, 0x00e29db9}, /* U+2779 DINGBAT NEGATIVE CIRCLED DIGIT FOUR [2000] */ - {0x00aca5, 0x00e29dba}, /* U+277A DINGBAT NEGATIVE CIRCLED DIGIT FIVE [2000] */ - {0x00aca6, 0x00e29dbb}, /* U+277B DINGBAT NEGATIVE CIRCLED DIGIT SIX [2000] */ - {0x00aca7, 0x00e29dbc}, /* U+277C DINGBAT NEGATIVE CIRCLED DIGIT SEVEN [2000] */ - {0x00aca8, 0x00e29dbd}, /* U+277D DINGBAT NEGATIVE CIRCLED DIGIT EIGHT [2000] */ - {0x00aca9, 0x00e29dbe}, /* U+277E DINGBAT NEGATIVE CIRCLED DIGIT NINE [2000] */ - {0x00acaa, 0x00e29dbf}, /* U+277F DINGBAT NEGATIVE CIRCLED NUMBER TEN [2000] */ - {0x00acab, 0x00e293ab}, /* U+24EB NEGATIVE CIRCLED NUMBER ELEVEN [2000] [Unicode3.2] */ - {0x00acac, 0x00e293ac}, /* U+24EC NEGATIVE CIRCLED NUMBER TWELVE [2000] [Unicode3.2] */ - {0x00acad, 0x00e293ad}, /* U+24ED NEGATIVE CIRCLED NUMBER THIRTEEN [2000] [Unicode3.2] */ - {0x00acae, 0x00e293ae}, /* U+24EE NEGATIVE CIRCLED NUMBER FOURTEEN [2000] [Unicode3.2] */ - {0x00acaf, 0x00e293af}, /* U+24EF NEGATIVE CIRCLED NUMBER FIFTEEN [2000] [Unicode3.2] */ - {0x00acb0, 0x00e293b0}, /* U+24F0 NEGATIVE CIRCLED NUMBER SIXTEEN [2000] [Unicode3.2] */ - {0x00acb1, 0x00e293b1}, /* U+24F1 NEGATIVE CIRCLED NUMBER SEVENTEEN [2000] [Unicode3.2] */ - {0x00acb2, 0x00e293b2}, /* U+24F2 NEGATIVE CIRCLED NUMBER EIGHTEEN [2000] [Unicode3.2] */ - {0x00acb3, 0x00e293b3}, /* U+24F3 NEGATIVE CIRCLED NUMBER NINETEEN [2000] [Unicode3.2] */ - {0x00acb4, 0x00e293b4}, /* U+24F4 NEGATIVE CIRCLED NUMBER TWENTY [2000] [Unicode3.2] */ - {0x00acb5, 0x00e285b0}, /* U+2170 SMALL ROMAN NUMERAL ONE [2000] */ - {0x00acb6, 0x00e285b1}, /* U+2171 SMALL ROMAN NUMERAL TWO [2000] */ - {0x00acb7, 0x00e285b2}, /* U+2172 SMALL ROMAN NUMERAL THREE [2000] */ - {0x00acb8, 0x00e285b3}, /* U+2173 SMALL ROMAN NUMERAL FOUR [2000] */ - {0x00acb9, 0x00e285b4}, /* U+2174 SMALL ROMAN NUMERAL FIVE [2000] */ - {0x00acba, 0x00e285b5}, /* U+2175 SMALL ROMAN NUMERAL SIX [2000] */ - {0x00acbb, 0x00e285b6}, /* U+2176 SMALL ROMAN NUMERAL SEVEN [2000] */ - {0x00acbc, 0x00e285b7}, /* U+2177 SMALL ROMAN NUMERAL EIGHT [2000] */ - {0x00acbd, 0x00e285b8}, /* U+2178 SMALL ROMAN NUMERAL NINE [2000] */ - {0x00acbe, 0x00e285b9}, /* U+2179 SMALL ROMAN NUMERAL TEN [2000] */ - {0x00acbf, 0x00e285ba}, /* U+217A SMALL ROMAN NUMERAL ELEVEN [2000] */ - {0x00acc0, 0x00e285bb}, /* U+217B SMALL ROMAN NUMERAL TWELVE [2000] */ - {0x00acc1, 0x00e29390}, /* U+24D0 CIRCLED LATIN SMALL LETTER A [2000] */ - {0x00acc2, 0x00e29391}, /* U+24D1 CIRCLED LATIN SMALL LETTER B [2000] */ - {0x00acc3, 0x00e29392}, /* U+24D2 CIRCLED LATIN SMALL LETTER C [2000] */ - {0x00acc4, 0x00e29393}, /* U+24D3 CIRCLED LATIN SMALL LETTER D [2000] */ - {0x00acc5, 0x00e29394}, /* U+24D4 CIRCLED LATIN SMALL LETTER E [2000] */ - {0x00acc6, 0x00e29395}, /* U+24D5 CIRCLED LATIN SMALL LETTER F [2000] */ - {0x00acc7, 0x00e29396}, /* U+24D6 CIRCLED LATIN SMALL LETTER G [2000] */ - {0x00acc8, 0x00e29397}, /* U+24D7 CIRCLED LATIN SMALL LETTER H [2000] */ - {0x00acc9, 0x00e29398}, /* U+24D8 CIRCLED LATIN SMALL LETTER I [2000] */ - {0x00acca, 0x00e29399}, /* U+24D9 CIRCLED LATIN SMALL LETTER J [2000] */ - {0x00accb, 0x00e2939a}, /* U+24DA CIRCLED LATIN SMALL LETTER K [2000] */ - {0x00accc, 0x00e2939b}, /* U+24DB CIRCLED LATIN SMALL LETTER L [2000] */ - {0x00accd, 0x00e2939c}, /* U+24DC CIRCLED LATIN SMALL LETTER M [2000] */ - {0x00acce, 0x00e2939d}, /* U+24DD CIRCLED LATIN SMALL LETTER N [2000] */ - {0x00accf, 0x00e2939e}, /* U+24DE CIRCLED LATIN SMALL LETTER O [2000] */ - {0x00acd0, 0x00e2939f}, /* U+24DF CIRCLED LATIN SMALL LETTER P [2000] */ - {0x00acd1, 0x00e293a0}, /* U+24E0 CIRCLED LATIN SMALL LETTER Q [2000] */ - {0x00acd2, 0x00e293a1}, /* U+24E1 CIRCLED LATIN SMALL LETTER R [2000] */ - {0x00acd3, 0x00e293a2}, /* U+24E2 CIRCLED LATIN SMALL LETTER S [2000] */ - {0x00acd4, 0x00e293a3}, /* U+24E3 CIRCLED LATIN SMALL LETTER T [2000] */ - {0x00acd5, 0x00e293a4}, /* U+24E4 CIRCLED LATIN SMALL LETTER U [2000] */ - {0x00acd6, 0x00e293a5}, /* U+24E5 CIRCLED LATIN SMALL LETTER V [2000] */ - {0x00acd7, 0x00e293a6}, /* U+24E6 CIRCLED LATIN SMALL LETTER W [2000] */ - {0x00acd8, 0x00e293a7}, /* U+24E7 CIRCLED LATIN SMALL LETTER X [2000] */ - {0x00acd9, 0x00e293a8}, /* U+24E8 CIRCLED LATIN SMALL LETTER Y [2000] */ - {0x00acda, 0x00e293a9}, /* U+24E9 CIRCLED LATIN SMALL LETTER Z [2000] */ - {0x00acdb, 0x00e38b90}, /* U+32D0 CIRCLED KATAKANA A [2000] */ - {0x00acdc, 0x00e38b91}, /* U+32D1 CIRCLED KATAKANA I [2000] */ - {0x00acdd, 0x00e38b92}, /* U+32D2 CIRCLED KATAKANA U [2000] */ - {0x00acde, 0x00e38b93}, /* U+32D3 CIRCLED KATAKANA E [2000] */ - {0x00acdf, 0x00e38b94}, /* U+32D4 CIRCLED KATAKANA O [2000] */ - {0x00ace0, 0x00e38b95}, /* U+32D5 CIRCLED KATAKANA KA [2000] */ - {0x00ace1, 0x00e38b96}, /* U+32D6 CIRCLED KATAKANA KI [2000] */ - {0x00ace2, 0x00e38b97}, /* U+32D7 CIRCLED KATAKANA KU [2000] */ - {0x00ace3, 0x00e38b98}, /* U+32D8 CIRCLED KATAKANA KE [2000] */ - {0x00ace4, 0x00e38b99}, /* U+32D9 CIRCLED KATAKANA KO [2000] */ - {0x00ace5, 0x00e38b9a}, /* U+32DA CIRCLED KATAKANA SA [2000] */ - {0x00ace6, 0x00e38b9b}, /* U+32DB CIRCLED KATAKANA SI [2000] */ - {0x00ace7, 0x00e38b9c}, /* U+32DC CIRCLED KATAKANA SU [2000] */ - {0x00ace8, 0x00e38b9d}, /* U+32DD CIRCLED KATAKANA SE [2000] */ - {0x00ace9, 0x00e38b9e}, /* U+32DE CIRCLED KATAKANA SO [2000] */ - {0x00acea, 0x00e38b9f}, /* U+32DF CIRCLED KATAKANA TA [2000] */ - {0x00aceb, 0x00e38ba0}, /* U+32E0 CIRCLED KATAKANA TI [2000] */ - {0x00acec, 0x00e38ba1}, /* U+32E1 CIRCLED KATAKANA TU [2000] */ - {0x00aced, 0x00e38ba2}, /* U+32E2 CIRCLED KATAKANA TE [2000] */ - {0x00acee, 0x00e38ba3}, /* U+32E3 CIRCLED KATAKANA TO [2000] */ - {0x00acef, 0x00e38bba}, /* U+32FA CIRCLED KATAKANA RO [2000] */ - {0x00acf0, 0x00e38ba9}, /* U+32E9 CIRCLED KATAKANA HA [2000] */ - {0x00acf1, 0x00e38ba5}, /* U+32E5 CIRCLED KATAKANA NI [2000] */ - {0x00acf2, 0x00e38bad}, /* U+32ED CIRCLED KATAKANA HO [2000] */ - {0x00acf3, 0x00e38bac}, /* U+32EC CIRCLED KATAKANA HE [2000] */ - {0x00acfd, 0x00e28191}, /* U+2051 TWO ASTERISKS ALIGNED VERTICALLY [2000] [Unicode3.2] */ - {0x00acfe, 0x00e28182}, /* U+2042 ASTERISM [2000] */ - {0x00ada1, 0x00e291a0}, /* U+2460 CIRCLED DIGIT ONE [2000] */ - {0x00ada2, 0x00e291a1}, /* U+2461 CIRCLED DIGIT TWO [2000] */ - {0x00ada3, 0x00e291a2}, /* U+2462 CIRCLED DIGIT THREE [2000] */ - {0x00ada4, 0x00e291a3}, /* U+2463 CIRCLED DIGIT FOUR [2000] */ - {0x00ada5, 0x00e291a4}, /* U+2464 CIRCLED DIGIT FIVE [2000] */ - {0x00ada6, 0x00e291a5}, /* U+2465 CIRCLED DIGIT SIX [2000] */ - {0x00ada7, 0x00e291a6}, /* U+2466 CIRCLED DIGIT SEVEN [2000] */ - {0x00ada8, 0x00e291a7}, /* U+2467 CIRCLED DIGIT EIGHT [2000] */ - {0x00ada9, 0x00e291a8}, /* U+2468 CIRCLED DIGIT NINE [2000] */ - {0x00adaa, 0x00e291a9}, /* U+2469 CIRCLED NUMBER TEN [2000] */ - {0x00adab, 0x00e291aa}, /* U+246A CIRCLED NUMBER ELEVEN [2000] */ - {0x00adac, 0x00e291ab}, /* U+246B CIRCLED NUMBER TWELVE [2000] */ - {0x00adad, 0x00e291ac}, /* U+246C CIRCLED NUMBER THIRTEEN [2000] */ - {0x00adae, 0x00e291ad}, /* U+246D CIRCLED NUMBER FOURTEEN [2000] */ - {0x00adaf, 0x00e291ae}, /* U+246E CIRCLED NUMBER FIFTEEN [2000] */ - {0x00adb0, 0x00e291af}, /* U+246F CIRCLED NUMBER SIXTEEN [2000] */ - {0x00adb1, 0x00e291b0}, /* U+2470 CIRCLED NUMBER SEVENTEEN [2000] */ - {0x00adb2, 0x00e291b1}, /* U+2471 CIRCLED NUMBER EIGHTEEN [2000] */ - {0x00adb3, 0x00e291b2}, /* U+2472 CIRCLED NUMBER NINETEEN [2000] */ - {0x00adb4, 0x00e291b3}, /* U+2473 CIRCLED NUMBER TWENTY [2000] */ - {0x00adb5, 0x00e285a0}, /* U+2160 ROMAN NUMERAL ONE [2000] */ - {0x00adb6, 0x00e285a1}, /* U+2161 ROMAN NUMERAL TWO [2000] */ - {0x00adb7, 0x00e285a2}, /* U+2162 ROMAN NUMERAL THREE [2000] */ - {0x00adb8, 0x00e285a3}, /* U+2163 ROMAN NUMERAL FOUR [2000] */ - {0x00adb9, 0x00e285a4}, /* U+2164 ROMAN NUMERAL FIVE [2000] */ - {0x00adba, 0x00e285a5}, /* U+2165 ROMAN NUMERAL SIX [2000] */ - {0x00adbb, 0x00e285a6}, /* U+2166 ROMAN NUMERAL SEVEN [2000] */ - {0x00adbc, 0x00e285a7}, /* U+2167 ROMAN NUMERAL EIGHT [2000] */ - {0x00adbd, 0x00e285a8}, /* U+2168 ROMAN NUMERAL NINE [2000] */ - {0x00adbe, 0x00e285a9}, /* U+2169 ROMAN NUMERAL TEN [2000] */ - {0x00adbf, 0x00e285aa}, /* U+216A ROMAN NUMERAL ELEVEN [2000] */ - {0x00adc0, 0x00e38d89}, /* U+3349 SQUARE MIRI [2000] */ - {0x00adc1, 0x00e38c94}, /* U+3314 SQUARE KIRO [2000] */ - {0x00adc2, 0x00e38ca2}, /* U+3322 SQUARE SENTI [2000] */ - {0x00adc3, 0x00e38d8d}, /* U+334D SQUARE MEETORU [2000] */ - {0x00adc4, 0x00e38c98}, /* U+3318 SQUARE GURAMU [2000] */ - {0x00adc5, 0x00e38ca7}, /* U+3327 SQUARE TON [2000] */ - {0x00adc6, 0x00e38c83}, /* U+3303 SQUARE AARU [2000] */ - {0x00adc7, 0x00e38cb6}, /* U+3336 SQUARE HEKUTAARU [2000] */ - {0x00adc8, 0x00e38d91}, /* U+3351 SQUARE RITTORU [2000] */ - {0x00adc9, 0x00e38d97}, /* U+3357 SQUARE WATTO [2000] */ - {0x00adca, 0x00e38c8d}, /* U+330D SQUARE KARORII [2000] */ - {0x00adcb, 0x00e38ca6}, /* U+3326 SQUARE DORU [2000] */ - {0x00adcc, 0x00e38ca3}, /* U+3323 SQUARE SENTO [2000] */ - {0x00adcd, 0x00e38cab}, /* U+332B SQUARE PAASENTO [2000] */ - {0x00adce, 0x00e38d8a}, /* U+334A SQUARE MIRIBAARU [2000] */ - {0x00adcf, 0x00e38cbb}, /* U+333B SQUARE PEEZI [2000] */ - {0x00add0, 0x00e38e9c}, /* U+339C SQUARE MM [2000] */ - {0x00add1, 0x00e38e9d}, /* U+339D SQUARE CM [2000] */ - {0x00add2, 0x00e38e9e}, /* U+339E SQUARE KM [2000] */ - {0x00add3, 0x00e38e8e}, /* U+338E SQUARE MG [2000] */ - {0x00add4, 0x00e38e8f}, /* U+338F SQUARE KG [2000] */ - {0x00add5, 0x00e38f84}, /* U+33C4 SQUARE CC [2000] */ - {0x00add6, 0x00e38ea1}, /* U+33A1 SQUARE M SQUARED [2000] */ - {0x00add7, 0x00e285ab}, /* U+216B ROMAN NUMERAL TWELVE [2000] */ - {0x00addf, 0x00e38dbb}, /* U+337B SQUARE ERA NAME HEISEI [2000] */ - {0x00ade0, 0x00e3809d}, /* U+301D REVERSED DOUBLE PRIME QUOTATION MARK [2000] */ - {0x00ade1, 0x00e3809f}, /* U+301F LOW DOUBLE PRIME QUOTATION MARK [2000] */ - {0x00ade2, 0x00e28496}, /* U+2116 NUMERO SIGN [2000] */ - {0x00ade3, 0x00e38f8d}, /* U+33CD SQUARE KK [2000] */ - {0x00ade4, 0x00e284a1}, /* U+2121 TELEPHONE SIGN [2000] */ - {0x00ade5, 0x00e38aa4}, /* U+32A4 CIRCLED IDEOGRAPH HIGH [2000] */ - {0x00ade6, 0x00e38aa5}, /* U+32A5 CIRCLED IDEOGRAPH CENTRE [2000] */ - {0x00ade7, 0x00e38aa6}, /* U+32A6 CIRCLED IDEOGRAPH LOW [2000] */ - {0x00ade8, 0x00e38aa7}, /* U+32A7 CIRCLED IDEOGRAPH LEFT [2000] */ - {0x00ade9, 0x00e38aa8}, /* U+32A8 CIRCLED IDEOGRAPH RIGHT [2000] */ - {0x00adea, 0x00e388b1}, /* U+3231 PARENTHESIZED IDEOGRAPH STOCK [2000] */ - {0x00adeb, 0x00e388b2}, /* U+3232 PARENTHESIZED IDEOGRAPH HAVE [2000] */ - {0x00adec, 0x00e388b9}, /* U+3239 PARENTHESIZED IDEOGRAPH REPRESENT [2000] */ - {0x00aded, 0x00e38dbe}, /* U+337E SQUARE ERA NAME MEIZI [2000] */ - {0x00adee, 0x00e38dbd}, /* U+337D SQUARE ERA NAME TAISYOU [2000] */ - {0x00adef, 0x00e38dbc}, /* U+337C SQUARE ERA NAME SYOUWA [2000] */ - {0x00adf3, 0x00e288ae}, /* U+222E CONTOUR INTEGRAL [2000] */ - {0x00adf8, 0x00e2889f}, /* U+221F RIGHT ANGLE [2000] */ - {0x00adf9, 0x00e28abf}, /* U+22BF RIGHT TRIANGLE [2000] */ - {0x00adfd, 0x00e29d96}, /* U+2756 BLACK DIAMOND MINUS WHITE X [2000] */ - {0x00adfe, 0x00e2989e}, /* U+261E WHITE RIGHT POINTING INDEX [2000] */ - {0x00aea1, 0x00e4bfb1}, /* U+4FF1 [2004] */ - {0x00aea2, 0xf0a0808b}, /* U+2000B [2000] [Unicode3.1] */ - {0x00aea3, 0x00e39082}, /* U+3402 [2000] */ - {0x00aea4, 0x00e4b8a8}, /* U+4E28 [2000] */ - {0x00aea5, 0x00e4b8af}, /* U+4E2F [2000] */ - {0x00aea6, 0x00e4b8b0}, /* U+4E30 [2000] */ - {0x00aea7, 0x00e4ba8d}, /* U+4E8D [2000] */ - {0x00aea8, 0x00e4bba1}, /* U+4EE1 [2000] */ - {0x00aea9, 0x00e4bbbd}, /* U+4EFD [2000] */ - {0x00aeaa, 0x00e4bbbf}, /* U+4EFF [2000] */ - {0x00aeab, 0x00e4bc83}, /* U+4F03 [2000] */ - {0x00aeac, 0x00e4bc8b}, /* U+4F0B [2000] */ - {0x00aead, 0x00e4bda0}, /* U+4F60 [2000] */ - {0x00aeae, 0x00e4bd88}, /* U+4F48 [2000] */ - {0x00aeaf, 0x00e4bd89}, /* U+4F49 [2000] */ - {0x00aeb0, 0x00e4bd96}, /* U+4F56 [2000] */ - {0x00aeb1, 0x00e4bd9f}, /* U+4F5F [2000] */ - {0x00aeb2, 0x00e4bdaa}, /* U+4F6A [2000] */ - {0x00aeb3, 0x00e4bdac}, /* U+4F6C [2000] */ - {0x00aeb4, 0x00e4bdbe}, /* U+4F7E [2000] */ - {0x00aeb5, 0x00e4be8a}, /* U+4F8A [2000] */ - {0x00aeb6, 0x00e4be94}, /* U+4F94 [2000] */ - {0x00aeb7, 0x00e4be97}, /* U+4F97 [2000] */ - {0x00aeb8, 0x00efa8b0}, /* U+FA30 CJK COMPATIBILITY IDEOGRAPH-FA30 [2000] [Unicode3.2] */ - {0x00aeb9, 0x00e4bf89}, /* U+4FC9 [2000] */ - {0x00aeba, 0x00e4bfa0}, /* U+4FE0 [2000] */ - {0x00aebb, 0x00e58081}, /* U+5001 [2000] */ - {0x00aebc, 0x00e58082}, /* U+5002 [2000] */ - {0x00aebd, 0x00e5808e}, /* U+500E [2000] */ - {0x00aebe, 0x00e58098}, /* U+5018 [2000] */ - {0x00aebf, 0x00e580a7}, /* U+5027 [2000] */ - {0x00aec0, 0x00e580ae}, /* U+502E [2000] */ - {0x00aec1, 0x00e58180}, /* U+5040 [2000] */ - {0x00aec2, 0x00e580bb}, /* U+503B [2000] */ - {0x00aec3, 0x00e58181}, /* U+5041 [2000] */ - {0x00aec4, 0x00e58294}, /* U+5094 [2000] */ - {0x00aec5, 0x00e5838c}, /* U+50CC [2000] */ - {0x00aec6, 0x00e583b2}, /* U+50F2 [2000] */ - {0x00aec7, 0x00e58390}, /* U+50D0 [2000] */ - {0x00aec8, 0x00e583a6}, /* U+50E6 [2000] */ - {0x00aec9, 0x00efa8b1}, /* U+FA31 CJK COMPATIBILITY IDEOGRAPH-FA31 [2000] [Unicode3.2] */ - {0x00aeca, 0x00e58486}, /* U+5106 [2000] */ - {0x00aecb, 0x00e58483}, /* U+5103 [2000] */ - {0x00aecc, 0x00e5848b}, /* U+510B [2000] */ - {0x00aecd, 0x00e5849e}, /* U+511E [2000] */ - {0x00aece, 0x00e584b5}, /* U+5135 [2000] */ - {0x00aecf, 0x00e5858a}, /* U+514A [2000] */ - {0x00aed0, 0x00efa8b2}, /* U+FA32 CJK COMPATIBILITY IDEOGRAPH-FA32 [2000] [Unicode3.2] */ - {0x00aed1, 0x00e58595}, /* U+5155 [2000] */ - {0x00aed2, 0x00e58597}, /* U+5157 [2000] */ - {0x00aed3, 0x00e392b5}, /* U+34B5 [2000] */ - {0x00aed4, 0x00e5869d}, /* U+519D [2000] */ - {0x00aed5, 0x00e58783}, /* U+51C3 [2000] */ - {0x00aed6, 0x00e5878a}, /* U+51CA [2000] */ - {0x00aed7, 0x00e5879e}, /* U+51DE [2000] */ - {0x00aed8, 0x00e587a2}, /* U+51E2 [2000] */ - {0x00aed9, 0x00e587ae}, /* U+51EE [2000] */ - {0x00aeda, 0x00e58881}, /* U+5201 [2000] */ - {0x00aedb, 0x00e3939b}, /* U+34DB [2000] */ - {0x00aedc, 0x00e58893}, /* U+5213 [2000] */ - {0x00aedd, 0x00e58895}, /* U+5215 [2000] */ - {0x00aede, 0x00e58989}, /* U+5249 [2000] */ - {0x00aedf, 0x00e58997}, /* U+5257 [2000] */ - {0x00aee0, 0x00e589a1}, /* U+5261 [2000] */ - {0x00aee1, 0x00e58a93}, /* U+5293 [2000] */ - {0x00aee2, 0x00e58b88}, /* U+52C8 [2000] */ - {0x00aee3, 0x00efa8b3}, /* U+FA33 CJK COMPATIBILITY IDEOGRAPH-FA33 [2000] [Unicode3.2] */ - {0x00aee4, 0x00e58b8c}, /* U+52CC [2000] */ - {0x00aee5, 0x00e58b90}, /* U+52D0 [2000] */ - {0x00aee6, 0x00e58b96}, /* U+52D6 [2000] */ - {0x00aee7, 0x00e58b9b}, /* U+52DB [2000] */ - {0x00aee8, 0x00efa8b4}, /* U+FA34 CJK COMPATIBILITY IDEOGRAPH-FA34 [2000] [Unicode3.2] */ - {0x00aee9, 0x00e58bb0}, /* U+52F0 [2000] */ - {0x00aeea, 0x00e58bbb}, /* U+52FB [2000] */ - {0x00aeeb, 0x00e58c80}, /* U+5300 [2000] */ - {0x00aeec, 0x00e58c87}, /* U+5307 [2000] */ - {0x00aeed, 0x00e58c9c}, /* U+531C [2000] */ - {0x00aeee, 0x00efa8b5}, /* U+FA35 CJK COMPATIBILITY IDEOGRAPH-FA35 [2000] [Unicode3.2] */ - {0x00aeef, 0x00e58da1}, /* U+5361 [2000] */ - {0x00aef0, 0x00e58da3}, /* U+5363 [2000] */ - {0x00aef1, 0x00e58dbd}, /* U+537D [2000] */ - {0x00aef2, 0x00e58e93}, /* U+5393 [2000] */ - {0x00aef3, 0x00e58e9d}, /* U+539D [2000] */ - {0x00aef4, 0x00e58eb2}, /* U+53B2 [2000] */ - {0x00aef5, 0x00e59092}, /* U+5412 [2000] */ - {0x00aef6, 0x00e590a7}, /* U+5427 [2000] */ - {0x00aef7, 0x00e5918d}, /* U+544D [2000] */ - {0x00aef8, 0x00e5929c}, /* U+549C [2000] */ - {0x00aef9, 0x00e591ab}, /* U+546B [2000] */ - {0x00aefa, 0x00e591b4}, /* U+5474 [2000] */ - {0x00aefb, 0x00e591bf}, /* U+547F [2000] */ - {0x00aefc, 0x00e59288}, /* U+5488 [2000] */ - {0x00aefd, 0x00e59296}, /* U+5496 [2000] */ - {0x00aefe, 0x00e592a1}, /* U+54A1 [2000] */ - {0x00afa1, 0x00e592a9}, /* U+54A9 [2000] */ - {0x00afa2, 0x00e59386}, /* U+54C6 [2000] */ - {0x00afa3, 0x00e593bf}, /* U+54FF [2000] */ - {0x00afa4, 0x00e5948e}, /* U+550E [2000] */ - {0x00afa5, 0x00e594ab}, /* U+552B [2000] */ - {0x00afa6, 0x00e594b5}, /* U+5535 [2000] */ - {0x00afa7, 0x00e59590}, /* U+5550 [2000] */ - {0x00afa8, 0x00e5959e}, /* U+555E [2000] */ - {0x00afa9, 0x00e59681}, /* U+5581 [2000] */ - {0x00afaa, 0x00e59686}, /* U+5586 [2000] */ - {0x00afab, 0x00e5968e}, /* U+558E [2000] */ - {0x00afac, 0x00efa8b6}, /* U+FA36 CJK COMPATIBILITY IDEOGRAPH-FA36 [2000] [Unicode3.2] */ - {0x00afad, 0x00e596ad}, /* U+55AD [2000] */ - {0x00afae, 0x00e5978e}, /* U+55CE [2000] */ - {0x00afaf, 0x00efa8b7}, /* U+FA37 CJK COMPATIBILITY IDEOGRAPH-FA37 [2000] [Unicode3.2] */ - {0x00afb0, 0x00e59888}, /* U+5608 [2000] */ - {0x00afb1, 0x00e5988e}, /* U+560E [2000] */ - {0x00afb2, 0x00e598bb}, /* U+563B [2000] */ - {0x00afb3, 0x00e59989}, /* U+5649 [2000] */ - {0x00afb4, 0x00e599b6}, /* U+5676 [2000] */ - {0x00afb5, 0x00e599a6}, /* U+5666 [2000] */ - {0x00afb6, 0x00efa8b8}, /* U+FA38 CJK COMPATIBILITY IDEOGRAPH-FA38 [2000] [Unicode3.2] */ - {0x00afb7, 0x00e599af}, /* U+566F [2000] */ - {0x00afb8, 0x00e599b1}, /* U+5671 [2000] */ - {0x00afb9, 0x00e599b2}, /* U+5672 [2000] */ - {0x00afba, 0x00e59a99}, /* U+5699 [2000] */ - {0x00afbb, 0x00e59a9e}, /* U+569E [2000] */ - {0x00afbc, 0x00e59aa9}, /* U+56A9 [2000] */ - {0x00afbd, 0x00e59aac}, /* U+56AC [2000] */ - {0x00afbe, 0x00e59ab3}, /* U+56B3 [2000] */ - {0x00afbf, 0x00e59b89}, /* U+56C9 [2000] */ - {0x00afc0, 0x00e59b8a}, /* U+56CA [2000] */ - {0x00afc1, 0x00e59c8a}, /* U+570A [2000] */ - {0x00afc2, 0xf0a188bd}, /* U+2123D [2000] [Unicode3.1] */ - {0x00afc3, 0x00e59ca1}, /* U+5721 [2000] */ - {0x00afc4, 0x00e59caf}, /* U+572F [2000] */ - {0x00afc5, 0x00e59cb3}, /* U+5733 [2000] */ - {0x00afc6, 0x00e59cb4}, /* U+5734 [2000] */ - {0x00afc7, 0x00e59db0}, /* U+5770 [2000] */ - {0x00afc8, 0x00e59db7}, /* U+5777 [2000] */ - {0x00afc9, 0x00e59dbc}, /* U+577C [2000] */ - {0x00afca, 0x00e59e9c}, /* U+579C [2000] */ - {0x00afcb, 0x00efa88f}, /* U+FA0F CJK COMPATIBILITY IDEOGRAPH-FA0F [2000] */ - {0x00afcc, 0xf0a18c9b}, /* U+2131B [2000] [Unicode3.1] */ - {0x00afcd, 0x00e59eb8}, /* U+57B8 [2000] */ - {0x00afce, 0x00e59f87}, /* U+57C7 [2000] */ - {0x00afcf, 0x00e59f88}, /* U+57C8 [2000] */ - {0x00afd0, 0x00e59f8f}, /* U+57CF [2000] */ - {0x00afd1, 0x00e59fa4}, /* U+57E4 [2000] */ - {0x00afd2, 0x00e59fad}, /* U+57ED [2000] */ - {0x00afd3, 0x00e59fb5}, /* U+57F5 [2000] */ - {0x00afd4, 0x00e59fb6}, /* U+57F6 [2000] */ - {0x00afd5, 0x00e59fbf}, /* U+57FF [2000] */ - {0x00afd6, 0x00e5a089}, /* U+5809 [2000] */ - {0x00afd7, 0x00efa890}, /* U+FA10 CJK COMPATIBILITY IDEOGRAPH-FA10 [2000] */ - {0x00afd8, 0x00e5a1a1}, /* U+5861 [2000] */ - {0x00afd9, 0x00e5a1a4}, /* U+5864 [2000] */ - {0x00afda, 0x00efa8b9}, /* U+FA39 CJK COMPATIBILITY IDEOGRAPH-FA39 [2000] [Unicode3.2] */ - {0x00afdb, 0x00e5a1bc}, /* U+587C [2000] */ - {0x00afdc, 0x00e5a289}, /* U+5889 [2000] */ - {0x00afdd, 0x00e5a29e}, /* U+589E [2000] */ - {0x00afde, 0x00efa8ba}, /* U+FA3A CJK COMPATIBILITY IDEOGRAPH-FA3A [2000] [Unicode3.2] */ - {0x00afdf, 0x00e5a2a9}, /* U+58A9 [2000] */ - {0x00afe0, 0xf0a191ae}, /* U+2146E [2000] [Unicode3.1] */ - {0x00afe1, 0x00e5a392}, /* U+58D2 [2000] */ - {0x00afe2, 0x00e5a38e}, /* U+58CE [2000] */ - {0x00afe3, 0x00e5a394}, /* U+58D4 [2000] */ - {0x00afe4, 0x00e5a39a}, /* U+58DA [2000] */ - {0x00afe5, 0x00e5a3a0}, /* U+58E0 [2000] */ - {0x00afe6, 0x00e5a3a9}, /* U+58E9 [2000] */ - {0x00afe7, 0x00e5a48c}, /* U+590C [2000] */ - {0x00afe8, 0x00e89981}, /* U+8641 [2000] */ - {0x00afe9, 0x00e5a59d}, /* U+595D [2000] */ - {0x00afea, 0x00e5a5ad}, /* U+596D [2000] */ - {0x00afeb, 0x00e5a68b}, /* U+598B [2000] */ - {0x00afec, 0x00e5a692}, /* U+5992 [2000] */ - {0x00afed, 0x00e5a6a4}, /* U+59A4 [2000] */ - {0x00afee, 0x00e5a783}, /* U+59C3 [2000] */ - {0x00afef, 0x00e5a792}, /* U+59D2 [2000] */ - {0x00aff0, 0x00e5a79d}, /* U+59DD [2000] */ - {0x00aff1, 0x00e5a893}, /* U+5A13 [2000] */ - {0x00aff2, 0x00e5a8a3}, /* U+5A23 [2000] */ - {0x00aff3, 0x00e5a9a7}, /* U+5A67 [2000] */ - {0x00aff4, 0x00e5a9ad}, /* U+5A6D [2000] */ - {0x00aff5, 0x00e5a9b7}, /* U+5A77 [2000] */ - {0x00aff6, 0x00e5a9be}, /* U+5A7E [2000] */ - {0x00aff7, 0x00e5aa84}, /* U+5A84 [2000] */ - {0x00aff8, 0x00e5aa9e}, /* U+5A9E [2000] */ - {0x00aff9, 0x00e5aaa7}, /* U+5AA7 [2000] */ - {0x00affa, 0x00e5ab84}, /* U+5AC4 [2000] */ - {0x00affb, 0xf0a1a2bd}, /* U+218BD [2000] [Unicode3.1] */ - {0x00affc, 0x00e5ac99}, /* U+5B19 [2000] */ - {0x00affd, 0x00e5aca5}, /* U+5B25 [2000] */ - {0x00affe, 0x00e5899d}, /* U+525D [2004] */ - {0x00b0a1, 0x00e4ba9c}, /* U+4E9C */ - {0x00b0a2, 0x00e59496}, /* U+5516 */ - {0x00b0a3, 0x00e5a883}, /* U+5A03 */ - {0x00b0a4, 0x00e998bf}, /* U+963F */ - {0x00b0a5, 0x00e59380}, /* U+54C0 */ - {0x00b0a6, 0x00e6849b}, /* U+611B */ - {0x00b0a7, 0x00e68ca8}, /* U+6328 */ - {0x00b0a8, 0x00e5a7b6}, /* U+59F6 */ - {0x00b0a9, 0x00e980a2}, /* U+9022 */ - {0x00b0aa, 0x00e891b5}, /* U+8475 */ - {0x00b0ab, 0x00e88c9c}, /* U+831C */ - {0x00b0ac, 0x00e7a990}, /* U+7A50 */ - {0x00b0ad, 0x00e682aa}, /* U+60AA */ - {0x00b0ae, 0x00e68fa1}, /* U+63E1 */ - {0x00b0af, 0x00e6b8a5}, /* U+6E25 */ - {0x00b0b0, 0x00e697ad}, /* U+65ED */ - {0x00b0b1, 0x00e891a6}, /* U+8466 */ - {0x00b0b2, 0x00e88aa6}, /* U+82A6 */ - {0x00b0b3, 0x00e9afb5}, /* U+9BF5 */ - {0x00b0b4, 0x00e6a293}, /* U+6893 */ - {0x00b0b5, 0x00e59ca7}, /* U+5727 */ - {0x00b0b6, 0x00e696a1}, /* U+65A1 */ - {0x00b0b7, 0x00e689b1}, /* U+6271 */ - {0x00b0b8, 0x00e5ae9b}, /* U+5B9B */ - {0x00b0b9, 0x00e5a790}, /* U+59D0 */ - {0x00b0ba, 0x00e899bb}, /* U+867B */ - {0x00b0bb, 0x00e9a3b4}, /* U+98F4 */ - {0x00b0bc, 0x00e7b5a2}, /* U+7D62 */ - {0x00b0bd, 0x00e7b6be}, /* U+7DBE */ - {0x00b0be, 0x00e9ae8e}, /* U+9B8E */ - {0x00b0bf, 0x00e68896}, /* U+6216 */ - {0x00b0c0, 0x00e7b29f}, /* U+7C9F */ - {0x00b0c1, 0x00e8a2b7}, /* U+88B7 */ - {0x00b0c2, 0x00e5ae89}, /* U+5B89 */ - {0x00b0c3, 0x00e5bab5}, /* U+5EB5 */ - {0x00b0c4, 0x00e68c89}, /* U+6309 */ - {0x00b0c5, 0x00e69a97}, /* U+6697 */ - {0x00b0c6, 0x00e6a188}, /* U+6848 */ - {0x00b0c7, 0x00e99787}, /* U+95C7 */ - {0x00b0c8, 0x00e99e8d}, /* U+978D */ - {0x00b0c9, 0x00e69d8f}, /* U+674F */ - {0x00b0ca, 0x00e4bba5}, /* U+4EE5 */ - {0x00b0cb, 0x00e4bc8a}, /* U+4F0A */ - {0x00b0cc, 0x00e4bd8d}, /* U+4F4D */ - {0x00b0cd, 0x00e4be9d}, /* U+4F9D */ - {0x00b0ce, 0x00e58189}, /* U+5049 */ - {0x00b0cf, 0x00e59bb2}, /* U+56F2 */ - {0x00b0d0, 0x00e5a4b7}, /* U+5937 */ - {0x00b0d1, 0x00e5a794}, /* U+59D4 */ - {0x00b0d2, 0x00e5a881}, /* U+5A01 */ - {0x00b0d3, 0x00e5b089}, /* U+5C09 */ - {0x00b0d4, 0x00e6839f}, /* U+60DF */ - {0x00b0d5, 0x00e6848f}, /* U+610F */ - {0x00b0d6, 0x00e685b0}, /* U+6170 */ - {0x00b0d7, 0x00e69893}, /* U+6613 */ - {0x00b0d8, 0x00e6a485}, /* U+6905 */ - {0x00b0d9, 0x00e782ba}, /* U+70BA */ - {0x00b0da, 0x00e7958f}, /* U+754F */ - {0x00b0db, 0x00e795b0}, /* U+7570 */ - {0x00b0dc, 0x00e7a7bb}, /* U+79FB */ - {0x00b0dd, 0x00e7b6ad}, /* U+7DAD */ - {0x00b0de, 0x00e7b7af}, /* U+7DEF */ - {0x00b0df, 0x00e88383}, /* U+80C3 */ - {0x00b0e0, 0x00e8908e}, /* U+840E */ - {0x00b0e1, 0x00e8a1a3}, /* U+8863 */ - {0x00b0e2, 0x00e8ac82}, /* U+8B02 */ - {0x00b0e3, 0x00e98195}, /* U+9055 */ - {0x00b0e4, 0x00e981ba}, /* U+907A */ - {0x00b0e5, 0x00e58cbb}, /* U+533B */ - {0x00b0e6, 0x00e4ba95}, /* U+4E95 */ - {0x00b0e7, 0x00e4baa5}, /* U+4EA5 */ - {0x00b0e8, 0x00e59f9f}, /* U+57DF */ - {0x00b0e9, 0x00e882b2}, /* U+80B2 */ - {0x00b0ea, 0x00e98381}, /* U+90C1 */ - {0x00b0eb, 0x00e7a3af}, /* U+78EF */ - {0x00b0ec, 0x00e4b880}, /* U+4E00 */ - {0x00b0ed, 0x00e5a3b1}, /* U+58F1 */ - {0x00b0ee, 0x00e6baa2}, /* U+6EA2 */ - {0x00b0ef, 0x00e980b8}, /* U+9038 */ - {0x00b0f0, 0x00e7a8b2}, /* U+7A32 */ - {0x00b0f1, 0x00e88ca8}, /* U+8328 */ - {0x00b0f2, 0x00e88a8b}, /* U+828B */ - {0x00b0f3, 0x00e9b0af}, /* U+9C2F */ - {0x00b0f4, 0x00e58581}, /* U+5141 */ - {0x00b0f5, 0x00e58db0}, /* U+5370 */ - {0x00b0f6, 0x00e592bd}, /* U+54BD */ - {0x00b0f7, 0x00e593a1}, /* U+54E1 */ - {0x00b0f8, 0x00e59ba0}, /* U+56E0 */ - {0x00b0f9, 0x00e5a7bb}, /* U+59FB */ - {0x00b0fa, 0x00e5bc95}, /* U+5F15 */ - {0x00b0fb, 0x00e9a3b2}, /* U+98F2 */ - {0x00b0fc, 0x00e6b7ab}, /* U+6DEB */ - {0x00b0fd, 0x00e883a4}, /* U+80E4 */ - {0x00b0fe, 0x00e894ad}, /* U+852D */ - {0x00b1a1, 0x00e999a2}, /* U+9662 */ - {0x00b1a2, 0x00e999b0}, /* U+9670 */ - {0x00b1a3, 0x00e99aa0}, /* U+96A0 */ - {0x00b1a4, 0x00e99fbb}, /* U+97FB */ - {0x00b1a5, 0x00e5908b}, /* U+540B */ - {0x00b1a6, 0x00e58fb3}, /* U+53F3 */ - {0x00b1a7, 0x00e5ae87}, /* U+5B87 */ - {0x00b1a8, 0x00e7838f}, /* U+70CF */ - {0x00b1a9, 0x00e7bebd}, /* U+7FBD */ - {0x00b1aa, 0x00e8bf82}, /* U+8FC2 */ - {0x00b1ab, 0x00e99ba8}, /* U+96E8 */ - {0x00b1ac, 0x00e58daf}, /* U+536F */ - {0x00b1ad, 0x00e9b59c}, /* U+9D5C */ - {0x00b1ae, 0x00e7aaba}, /* U+7ABA */ - {0x00b1af, 0x00e4b891}, /* U+4E11 */ - {0x00b1b0, 0x00e7a293}, /* U+7893 */ - {0x00b1b1, 0x00e887bc}, /* U+81FC */ - {0x00b1b2, 0x00e6b8a6}, /* U+6E26 */ - {0x00b1b3, 0x00e59898}, /* U+5618 */ - {0x00b1b4, 0x00e59484}, /* U+5504 */ - {0x00b1b5, 0x00e6ac9d}, /* U+6B1D */ - {0x00b1b6, 0x00e8949a}, /* U+851A */ - {0x00b1b7, 0x00e9b0bb}, /* U+9C3B */ - {0x00b1b8, 0x00e5a7a5}, /* U+59E5 */ - {0x00b1b9, 0x00e58ea9}, /* U+53A9 */ - {0x00b1ba, 0x00e6b5a6}, /* U+6D66 */ - {0x00b1bb, 0x00e7939c}, /* U+74DC */ - {0x00b1bc, 0x00e9968f}, /* U+958F */ - {0x00b1bd, 0x00e59982}, /* U+5642 */ - {0x00b1be, 0x00e4ba91}, /* U+4E91 */ - {0x00b1bf, 0x00e9818b}, /* U+904B */ - {0x00b1c0, 0x00e99bb2}, /* U+96F2 */ - {0x00b1c1, 0x00e88d8f}, /* U+834F */ - {0x00b1c2, 0x00e9a48c}, /* U+990C */ - {0x00b1c3, 0x00e58fa1}, /* U+53E1 */ - {0x00b1c4, 0x00e596b6}, /* U+55B6 */ - {0x00b1c5, 0x00e5acb0}, /* U+5B30 */ - {0x00b1c6, 0x00e5bdb1}, /* U+5F71 */ - {0x00b1c7, 0x00e698a0}, /* U+6620 */ - {0x00b1c8, 0x00e69bb3}, /* U+66F3 */ - {0x00b1c9, 0x00e6a084}, /* U+6804 */ - {0x00b1ca, 0x00e6b0b8}, /* U+6C38 */ - {0x00b1cb, 0x00e6b3b3}, /* U+6CF3 */ - {0x00b1cc, 0x00e6b4a9}, /* U+6D29 */ - {0x00b1cd, 0x00e7919b}, /* U+745B */ - {0x00b1ce, 0x00e79b88}, /* U+76C8 */ - {0x00b1cf, 0x00e7a98e}, /* U+7A4E */ - {0x00b1d0, 0x00e9a0b4}, /* U+9834 */ - {0x00b1d1, 0x00e88bb1}, /* U+82F1 */ - {0x00b1d2, 0x00e8a19b}, /* U+885B */ - {0x00b1d3, 0x00e8a9a0}, /* U+8A60 */ - {0x00b1d4, 0x00e98bad}, /* U+92ED */ - {0x00b1d5, 0x00e6b6b2}, /* U+6DB2 */ - {0x00b1d6, 0x00e796ab}, /* U+75AB */ - {0x00b1d7, 0x00e79b8a}, /* U+76CA */ - {0x00b1d8, 0x00e9a785}, /* U+99C5 */ - {0x00b1d9, 0x00e682a6}, /* U+60A6 */ - {0x00b1da, 0x00e8ac81}, /* U+8B01 */ - {0x00b1db, 0x00e8b68a}, /* U+8D8A */ - {0x00b1dc, 0x00e996b2}, /* U+95B2 */ - {0x00b1dd, 0x00e6a68e}, /* U+698E */ - {0x00b1de, 0x00e58ead}, /* U+53AD */ - {0x00b1df, 0x00e58686}, /* U+5186 */ - {0x00b1e0, 0x00e59c92}, /* U+5712 */ - {0x00b1e1, 0x00e5a0b0}, /* U+5830 */ - {0x00b1e2, 0x00e5a584}, /* U+5944 */ - {0x00b1e3, 0x00e5aeb4}, /* U+5BB4 */ - {0x00b1e4, 0x00e5bbb6}, /* U+5EF6 */ - {0x00b1e5, 0x00e680a8}, /* U+6028 */ - {0x00b1e6, 0x00e68ea9}, /* U+63A9 */ - {0x00b1e7, 0x00e68fb4}, /* U+63F4 */ - {0x00b1e8, 0x00e6b2bf}, /* U+6CBF */ - {0x00b1e9, 0x00e6bc94}, /* U+6F14 */ - {0x00b1ea, 0x00e7828e}, /* U+708E */ - {0x00b1eb, 0x00e78494}, /* U+7114 */ - {0x00b1ec, 0x00e78599}, /* U+7159 */ - {0x00b1ed, 0x00e78795}, /* U+71D5 */ - {0x00b1ee, 0x00e78cbf}, /* U+733F */ - {0x00b1ef, 0x00e7b881}, /* U+7E01 */ - {0x00b1f0, 0x00e889b6}, /* U+8276 */ - {0x00b1f1, 0x00e88b91}, /* U+82D1 */ - {0x00b1f2, 0x00e89697}, /* U+8597 */ - {0x00b1f3, 0x00e981a0}, /* U+9060 */ - {0x00b1f4, 0x00e9899b}, /* U+925B */ - {0x00b1f5, 0x00e9b49b}, /* U+9D1B */ - {0x00b1f6, 0x00e5a1a9}, /* U+5869 */ - {0x00b1f7, 0x00e696bc}, /* U+65BC */ - {0x00b1f8, 0x00e6b19a}, /* U+6C5A */ - {0x00b1f9, 0x00e794a5}, /* U+7525 */ - {0x00b1fa, 0x00e587b9}, /* U+51F9 */ - {0x00b1fb, 0x00e5a4ae}, /* U+592E */ - {0x00b1fc, 0x00e5a5a5}, /* U+5965 */ - {0x00b1fd, 0x00e5be80}, /* U+5F80 */ - {0x00b1fe, 0x00e5bf9c}, /* U+5FDC */ - {0x00b2a1, 0x00e68abc}, /* U+62BC */ - {0x00b2a2, 0x00e697ba}, /* U+65FA */ - {0x00b2a3, 0x00e6a8aa}, /* U+6A2A */ - {0x00b2a4, 0x00e6aca7}, /* U+6B27 */ - {0x00b2a5, 0x00e6aeb4}, /* U+6BB4 */ - {0x00b2a6, 0x00e78e8b}, /* U+738B */ - {0x00b2a7, 0x00e7bf81}, /* U+7FC1 */ - {0x00b2a8, 0x00e8a596}, /* U+8956 */ - {0x00b2a9, 0x00e9b4ac}, /* U+9D2C */ - {0x00b2aa, 0x00e9b48e}, /* U+9D0E */ - {0x00b2ab, 0x00e9bb84}, /* U+9EC4 */ - {0x00b2ac, 0x00e5b2a1}, /* U+5CA1 */ - {0x00b2ad, 0x00e6b296}, /* U+6C96 */ - {0x00b2ae, 0x00e88dbb}, /* U+837B */ - {0x00b2af, 0x00e58484}, /* U+5104 */ - {0x00b2b0, 0x00e5b18b}, /* U+5C4B */ - {0x00b2b1, 0x00e686b6}, /* U+61B6 */ - {0x00b2b2, 0x00e88786}, /* U+81C6 */ - {0x00b2b3, 0x00e6a1b6}, /* U+6876 */ - {0x00b2b4, 0x00e789a1}, /* U+7261 */ - {0x00b2b5, 0x00e4b999}, /* U+4E59 */ - {0x00b2b6, 0x00e4bfba}, /* U+4FFA */ - {0x00b2b7, 0x00e58db8}, /* U+5378 */ - {0x00b2b8, 0x00e681a9}, /* U+6069 */ - {0x00b2b9, 0x00e6b8a9}, /* U+6E29 */ - {0x00b2ba, 0x00e7a98f}, /* U+7A4F */ - {0x00b2bb, 0x00e99fb3}, /* U+97F3 */ - {0x00b2bc, 0x00e4b88b}, /* U+4E0B */ - {0x00b2bd, 0x00e58c96}, /* U+5316 */ - {0x00b2be, 0x00e4bbae}, /* U+4EEE */ - {0x00b2bf, 0x00e4bd95}, /* U+4F55 */ - {0x00b2c0, 0x00e4bcbd}, /* U+4F3D */ - {0x00b2c1, 0x00e4bea1}, /* U+4FA1 */ - {0x00b2c2, 0x00e4bdb3}, /* U+4F73 */ - {0x00b2c3, 0x00e58aa0}, /* U+52A0 */ - {0x00b2c4, 0x00e58faf}, /* U+53EF */ - {0x00b2c5, 0x00e59889}, /* U+5609 */ - {0x00b2c6, 0x00e5a48f}, /* U+590F */ - {0x00b2c7, 0x00e5ab81}, /* U+5AC1 */ - {0x00b2c8, 0x00e5aeb6}, /* U+5BB6 */ - {0x00b2c9, 0x00e5afa1}, /* U+5BE1 */ - {0x00b2ca, 0x00e7a791}, /* U+79D1 */ - {0x00b2cb, 0x00e69a87}, /* U+6687 */ - {0x00b2cc, 0x00e69e9c}, /* U+679C */ - {0x00b2cd, 0x00e69eb6}, /* U+67B6 */ - {0x00b2ce, 0x00e6ad8c}, /* U+6B4C */ - {0x00b2cf, 0x00e6b2b3}, /* U+6CB3 */ - {0x00b2d0, 0x00e781ab}, /* U+706B */ - {0x00b2d1, 0x00e78f82}, /* U+73C2 */ - {0x00b2d2, 0x00e7a68d}, /* U+798D */ - {0x00b2d3, 0x00e7a6be}, /* U+79BE */ - {0x00b2d4, 0x00e7a8bc}, /* U+7A3C */ - {0x00b2d5, 0x00e7ae87}, /* U+7B87 */ - {0x00b2d6, 0x00e88ab1}, /* U+82B1 */ - {0x00b2d7, 0x00e88b9b}, /* U+82DB */ - {0x00b2d8, 0x00e88c84}, /* U+8304 */ - {0x00b2d9, 0x00e88db7}, /* U+8377 */ - {0x00b2da, 0x00e88faf}, /* U+83EF */ - {0x00b2db, 0x00e88f93}, /* U+83D3 */ - {0x00b2dc, 0x00e89da6}, /* U+8766 */ - {0x00b2dd, 0x00e8aab2}, /* U+8AB2 */ - {0x00b2de, 0x00e598a9}, /* U+5629 */ - {0x00b2df, 0x00e8b2a8}, /* U+8CA8 */ - {0x00b2e0, 0x00e8bfa6}, /* U+8FE6 */ - {0x00b2e1, 0x00e9818e}, /* U+904E */ - {0x00b2e2, 0x00e99c9e}, /* U+971E */ - {0x00b2e3, 0x00e89a8a}, /* U+868A */ - {0x00b2e4, 0x00e4bf84}, /* U+4FC4 */ - {0x00b2e5, 0x00e5b3a8}, /* U+5CE8 */ - {0x00b2e6, 0x00e68891}, /* U+6211 */ - {0x00b2e7, 0x00e78999}, /* U+7259 */ - {0x00b2e8, 0x00e794bb}, /* U+753B */ - {0x00b2e9, 0x00e887a5}, /* U+81E5 */ - {0x00b2ea, 0x00e88abd}, /* U+82BD */ - {0x00b2eb, 0x00e89bbe}, /* U+86FE */ - {0x00b2ec, 0x00e8b380}, /* U+8CC0 */ - {0x00b2ed, 0x00e99b85}, /* U+96C5 */ - {0x00b2ee, 0x00e9a493}, /* U+9913 */ - {0x00b2ef, 0x00e9a795}, /* U+99D5 */ - {0x00b2f0, 0x00e4bb8b}, /* U+4ECB */ - {0x00b2f1, 0x00e4bc9a}, /* U+4F1A */ - {0x00b2f2, 0x00e8a7a3}, /* U+89E3 */ - {0x00b2f3, 0x00e59b9e}, /* U+56DE */ - {0x00b2f4, 0x00e5a18a}, /* U+584A */ - {0x00b2f5, 0x00e5a38a}, /* U+58CA */ - {0x00b2f6, 0x00e5bbbb}, /* U+5EFB */ - {0x00b2f7, 0x00e5bfab}, /* U+5FEB */ - {0x00b2f8, 0x00e680aa}, /* U+602A */ - {0x00b2f9, 0x00e68294}, /* U+6094 */ - {0x00b2fa, 0x00e681a2}, /* U+6062 */ - {0x00b2fb, 0x00e68790}, /* U+61D0 */ - {0x00b2fc, 0x00e68892}, /* U+6212 */ - {0x00b2fd, 0x00e68b90}, /* U+62D0 */ - {0x00b2fe, 0x00e694b9}, /* U+6539 */ - {0x00b3a1, 0x00e9ad81}, /* U+9B41 */ - {0x00b3a2, 0x00e699a6}, /* U+6666 */ - {0x00b3a3, 0x00e6a2b0}, /* U+68B0 */ - {0x00b3a4, 0x00e6b5b7}, /* U+6D77 */ - {0x00b3a5, 0x00e781b0}, /* U+7070 */ - {0x00b3a6, 0x00e7958c}, /* U+754C */ - {0x00b3a7, 0x00e79a86}, /* U+7686 */ - {0x00b3a8, 0x00e7b5b5}, /* U+7D75 */ - {0x00b3a9, 0x00e88aa5}, /* U+82A5 */ - {0x00b3aa, 0x00e89fb9}, /* U+87F9 */ - {0x00b3ab, 0x00e9968b}, /* U+958B */ - {0x00b3ac, 0x00e99a8e}, /* U+968E */ - {0x00b3ad, 0x00e8b29d}, /* U+8C9D */ - {0x00b3ae, 0x00e587b1}, /* U+51F1 */ - {0x00b3af, 0x00e58abe}, /* U+52BE */ - {0x00b3b0, 0x00e5a496}, /* U+5916 */ - {0x00b3b1, 0x00e592b3}, /* U+54B3 */ - {0x00b3b2, 0x00e5aeb3}, /* U+5BB3 */ - {0x00b3b3, 0x00e5b496}, /* U+5D16 */ - {0x00b3b4, 0x00e685a8}, /* U+6168 */ - {0x00b3b5, 0x00e6a682}, /* U+6982 */ - {0x00b3b6, 0x00e6b6af}, /* U+6DAF */ - {0x00b3b7, 0x00e7a28d}, /* U+788D */ - {0x00b3b8, 0x00e8938b}, /* U+84CB */ - {0x00b3b9, 0x00e8a197}, /* U+8857 */ - {0x00b3ba, 0x00e8a9b2}, /* U+8A72 */ - {0x00b3bb, 0x00e98ea7}, /* U+93A7 */ - {0x00b3bc, 0x00e9aab8}, /* U+9AB8 */ - {0x00b3bd, 0x00e6b5ac}, /* U+6D6C */ - {0x00b3be, 0x00e9a6a8}, /* U+99A8 */ - {0x00b3bf, 0x00e89b99}, /* U+86D9 */ - {0x00b3c0, 0x00e59ea3}, /* U+57A3 */ - {0x00b3c1, 0x00e69fbf}, /* U+67FF */ - {0x00b3c2, 0x00e89b8e}, /* U+86CE */ - {0x00b3c3, 0x00e9888e}, /* U+920E */ - {0x00b3c4, 0x00e58a83}, /* U+5283 */ - {0x00b3c5, 0x00e59a87}, /* U+5687 */ - {0x00b3c6, 0x00e59084}, /* U+5404 */ - {0x00b3c7, 0x00e5bb93}, /* U+5ED3 */ - {0x00b3c8, 0x00e68ba1}, /* U+62E1 */ - {0x00b3c9, 0x00e692b9}, /* U+64B9 */ - {0x00b3ca, 0x00e6a0bc}, /* U+683C */ - {0x00b3cb, 0x00e6a0b8}, /* U+6838 */ - {0x00b3cc, 0x00e6aebb}, /* U+6BBB */ - {0x00b3cd, 0x00e78db2}, /* U+7372 */ - {0x00b3ce, 0x00e7a2ba}, /* U+78BA */ - {0x00b3cf, 0x00e7a9ab}, /* U+7A6B */ - {0x00b3d0, 0x00e8a69a}, /* U+899A */ - {0x00b3d1, 0x00e8a792}, /* U+89D2 */ - {0x00b3d2, 0x00e8b5ab}, /* U+8D6B */ - {0x00b3d3, 0x00e8bc83}, /* U+8F03 */ - {0x00b3d4, 0x00e983ad}, /* U+90ED */ - {0x00b3d5, 0x00e996a3}, /* U+95A3 */ - {0x00b3d6, 0x00e99a94}, /* U+9694 */ - {0x00b3d7, 0x00e99da9}, /* U+9769 */ - {0x00b3d8, 0x00e5ada6}, /* U+5B66 */ - {0x00b3d9, 0x00e5b2b3}, /* U+5CB3 */ - {0x00b3da, 0x00e6a5bd}, /* U+697D */ - {0x00b3db, 0x00e9a18d}, /* U+984D */ - {0x00b3dc, 0x00e9a18e}, /* U+984E */ - {0x00b3dd, 0x00e68e9b}, /* U+639B */ - {0x00b3de, 0x00e7aca0}, /* U+7B20 */ - {0x00b3df, 0x00e6a8ab}, /* U+6A2B */ - {0x00b3e0, 0x00e6a9bf}, /* U+6A7F */ - {0x00b3e1, 0x00e6a2b6}, /* U+68B6 */ - {0x00b3e2, 0x00e9b08d}, /* U+9C0D */ - {0x00b3e3, 0x00e6bd9f}, /* U+6F5F */ - {0x00b3e4, 0x00e589b2}, /* U+5272 */ - {0x00b3e5, 0x00e5969d}, /* U+559D */ - {0x00b3e6, 0x00e681b0}, /* U+6070 */ - {0x00b3e7, 0x00e68bac}, /* U+62EC */ - {0x00b3e8, 0x00e6b4bb}, /* U+6D3B */ - {0x00b3e9, 0x00e6b887}, /* U+6E07 */ - {0x00b3ea, 0x00e6bb91}, /* U+6ED1 */ - {0x00b3eb, 0x00e8919b}, /* U+845B */ - {0x00b3ec, 0x00e8a490}, /* U+8910 */ - {0x00b3ed, 0x00e8bd84}, /* U+8F44 */ - {0x00b3ee, 0x00e4b894}, /* U+4E14 */ - {0x00b3ef, 0x00e9b0b9}, /* U+9C39 */ - {0x00b3f0, 0x00e58fb6}, /* U+53F6 */ - {0x00b3f1, 0x00e6a49b}, /* U+691B */ - {0x00b3f2, 0x00e6a8ba}, /* U+6A3A */ - {0x00b3f3, 0x00e99e84}, /* U+9784 */ - {0x00b3f4, 0x00e6a0aa}, /* U+682A */ - {0x00b3f5, 0x00e5859c}, /* U+515C */ - {0x00b3f6, 0x00e7ab83}, /* U+7AC3 */ - {0x00b3f7, 0x00e892b2}, /* U+84B2 */ - {0x00b3f8, 0x00e9879c}, /* U+91DC */ - {0x00b3f9, 0x00e98e8c}, /* U+938C */ - {0x00b3fa, 0x00e5999b}, /* U+565B */ - {0x00b3fb, 0x00e9b4a8}, /* U+9D28 */ - {0x00b3fc, 0x00e6a0a2}, /* U+6822 */ - {0x00b3fd, 0x00e88c85}, /* U+8305 */ - {0x00b3fe, 0x00e890b1}, /* U+8431 */ - {0x00b4a1, 0x00e7b2a5}, /* U+7CA5 */ - {0x00b4a2, 0x00e58888}, /* U+5208 */ - {0x00b4a3, 0x00e88b85}, /* U+82C5 */ - {0x00b4a4, 0x00e793a6}, /* U+74E6 */ - {0x00b4a5, 0x00e4b9be}, /* U+4E7E */ - {0x00b4a6, 0x00e4be83}, /* U+4F83 */ - {0x00b4a7, 0x00e586a0}, /* U+51A0 */ - {0x00b4a8, 0x00e5af92}, /* U+5BD2 */ - {0x00b4a9, 0x00e5888a}, /* U+520A */ - {0x00b4aa, 0x00e58b98}, /* U+52D8 */ - {0x00b4ab, 0x00e58ba7}, /* U+52E7 */ - {0x00b4ac, 0x00e5b7bb}, /* U+5DFB */ - {0x00b4ad, 0x00e5969a}, /* U+559A */ - {0x00b4ae, 0x00e5a0aa}, /* U+582A */ - {0x00b4af, 0x00e5a7a6}, /* U+59E6 */ - {0x00b4b0, 0x00e5ae8c}, /* U+5B8C */ - {0x00b4b1, 0x00e5ae98}, /* U+5B98 */ - {0x00b4b2, 0x00e5af9b}, /* U+5BDB */ - {0x00b4b3, 0x00e5b9b2}, /* U+5E72 */ - {0x00b4b4, 0x00e5b9b9}, /* U+5E79 */ - {0x00b4b5, 0x00e682a3}, /* U+60A3 */ - {0x00b4b6, 0x00e6849f}, /* U+611F */ - {0x00b4b7, 0x00e685a3}, /* U+6163 */ - {0x00b4b8, 0x00e686be}, /* U+61BE */ - {0x00b4b9, 0x00e68f9b}, /* U+63DB */ - {0x00b4ba, 0x00e695a2}, /* U+6562 */ - {0x00b4bb, 0x00e69f91}, /* U+67D1 */ - {0x00b4bc, 0x00e6a193}, /* U+6853 */ - {0x00b4bd, 0x00e6a3ba}, /* U+68FA */ - {0x00b4be, 0x00e6acbe}, /* U+6B3E */ - {0x00b4bf, 0x00e6ad93}, /* U+6B53 */ - {0x00b4c0, 0x00e6b197}, /* U+6C57 */ - {0x00b4c1, 0x00e6bca2}, /* U+6F22 */ - {0x00b4c2, 0x00e6be97}, /* U+6F97 */ - {0x00b4c3, 0x00e6bd85}, /* U+6F45 */ - {0x00b4c4, 0x00e792b0}, /* U+74B0 */ - {0x00b4c5, 0x00e79498}, /* U+7518 */ - {0x00b4c6, 0x00e79ba3}, /* U+76E3 */ - {0x00b4c7, 0x00e79c8b}, /* U+770B */ - {0x00b4c8, 0x00e7abbf}, /* U+7AFF */ - {0x00b4c9, 0x00e7aea1}, /* U+7BA1 */ - {0x00b4ca, 0x00e7b0a1}, /* U+7C21 */ - {0x00b4cb, 0x00e7b7a9}, /* U+7DE9 */ - {0x00b4cc, 0x00e7bcb6}, /* U+7F36 */ - {0x00b4cd, 0x00e7bfb0}, /* U+7FF0 */ - {0x00b4ce, 0x00e8829d}, /* U+809D */ - {0x00b4cf, 0x00e889a6}, /* U+8266 */ - {0x00b4d0, 0x00e88e9e}, /* U+839E */ - {0x00b4d1, 0x00e8a6b3}, /* U+89B3 */ - {0x00b4d2, 0x00e8ab8c}, /* U+8ACC */ - {0x00b4d3, 0x00e8b2ab}, /* U+8CAB */ - {0x00b4d4, 0x00e98284}, /* U+9084 */ - {0x00b4d5, 0x00e99191}, /* U+9451 */ - {0x00b4d6, 0x00e99693}, /* U+9593 */ - {0x00b4d7, 0x00e99691}, /* U+9591 */ - {0x00b4d8, 0x00e996a2}, /* U+95A2 */ - {0x00b4d9, 0x00e999a5}, /* U+9665 */ - {0x00b4da, 0x00e99f93}, /* U+97D3 */ - {0x00b4db, 0x00e9a4a8}, /* U+9928 */ - {0x00b4dc, 0x00e88898}, /* U+8218 */ - {0x00b4dd, 0x00e4b8b8}, /* U+4E38 */ - {0x00b4de, 0x00e590ab}, /* U+542B */ - {0x00b4df, 0x00e5b2b8}, /* U+5CB8 */ - {0x00b4e0, 0x00e5b78c}, /* U+5DCC */ - {0x00b4e1, 0x00e78ea9}, /* U+73A9 */ - {0x00b4e2, 0x00e7998c}, /* U+764C */ - {0x00b4e3, 0x00e79cbc}, /* U+773C */ - {0x00b4e4, 0x00e5b2a9}, /* U+5CA9 */ - {0x00b4e5, 0x00e7bfab}, /* U+7FEB */ - {0x00b4e6, 0x00e8b48b}, /* U+8D0B */ - {0x00b4e7, 0x00e99b81}, /* U+96C1 */ - {0x00b4e8, 0x00e9a091}, /* U+9811 */ - {0x00b4e9, 0x00e9a194}, /* U+9854 */ - {0x00b4ea, 0x00e9a198}, /* U+9858 */ - {0x00b4eb, 0x00e4bc81}, /* U+4F01 */ - {0x00b4ec, 0x00e4bc8e}, /* U+4F0E */ - {0x00b4ed, 0x00e58db1}, /* U+5371 */ - {0x00b4ee, 0x00e5969c}, /* U+559C */ - {0x00b4ef, 0x00e599a8}, /* U+5668 */ - {0x00b4f0, 0x00e59fba}, /* U+57FA */ - {0x00b4f1, 0x00e5a587}, /* U+5947 */ - {0x00b4f2, 0x00e5ac89}, /* U+5B09 */ - {0x00b4f3, 0x00e5af84}, /* U+5BC4 */ - {0x00b4f4, 0x00e5b290}, /* U+5C90 */ - {0x00b4f5, 0x00e5b88c}, /* U+5E0C */ - {0x00b4f6, 0x00e5b9be}, /* U+5E7E */ - {0x00b4f7, 0x00e5bf8c}, /* U+5FCC */ - {0x00b4f8, 0x00e68fae}, /* U+63EE */ - {0x00b4f9, 0x00e69cba}, /* U+673A */ - {0x00b4fa, 0x00e69797}, /* U+65D7 */ - {0x00b4fb, 0x00e697a2}, /* U+65E2 */ - {0x00b4fc, 0x00e69c9f}, /* U+671F */ - {0x00b4fd, 0x00e6a38b}, /* U+68CB */ - {0x00b4fe, 0x00e6a384}, /* U+68C4 */ - {0x00b5a1, 0x00e6a99f}, /* U+6A5F */ - {0x00b5a2, 0x00e5b8b0}, /* U+5E30 */ - {0x00b5a3, 0x00e6af85}, /* U+6BC5 */ - {0x00b5a4, 0x00e6b097}, /* U+6C17 */ - {0x00b5a5, 0x00e6b1bd}, /* U+6C7D */ - {0x00b5a6, 0x00e795bf}, /* U+757F */ - {0x00b5a7, 0x00e7a588}, /* U+7948 */ - {0x00b5a8, 0x00e5ada3}, /* U+5B63 */ - {0x00b5a9, 0x00e7a880}, /* U+7A00 */ - {0x00b5aa, 0x00e7b480}, /* U+7D00 */ - {0x00b5ab, 0x00e5bebd}, /* U+5FBD */ - {0x00b5ac, 0x00e8a68f}, /* U+898F */ - {0x00b5ad, 0x00e8a898}, /* U+8A18 */ - {0x00b5ae, 0x00e8b2b4}, /* U+8CB4 */ - {0x00b5af, 0x00e8b5b7}, /* U+8D77 */ - {0x00b5b0, 0x00e8bb8c}, /* U+8ECC */ - {0x00b5b1, 0x00e8bc9d}, /* U+8F1D */ - {0x00b5b2, 0x00e9a3a2}, /* U+98E2 */ - {0x00b5b3, 0x00e9a88e}, /* U+9A0E */ - {0x00b5b4, 0x00e9acbc}, /* U+9B3C */ - {0x00b5b5, 0x00e4ba80}, /* U+4E80 */ - {0x00b5b6, 0x00e581bd}, /* U+507D */ - {0x00b5b7, 0x00e58480}, /* U+5100 */ - {0x00b5b8, 0x00e5a693}, /* U+5993 */ - {0x00b5b9, 0x00e5ae9c}, /* U+5B9C */ - {0x00b5ba, 0x00e688af}, /* U+622F */ - {0x00b5bb, 0x00e68a80}, /* U+6280 */ - {0x00b5bc, 0x00e693ac}, /* U+64EC */ - {0x00b5bd, 0x00e6acba}, /* U+6B3A */ - {0x00b5be, 0x00e78aa0}, /* U+72A0 */ - {0x00b5bf, 0x00e79691}, /* U+7591 */ - {0x00b5c0, 0x00e7a587}, /* U+7947 */ - {0x00b5c1, 0x00e7bea9}, /* U+7FA9 */ - {0x00b5c2, 0x00e89fbb}, /* U+87FB */ - {0x00b5c3, 0x00e8aabc}, /* U+8ABC */ - {0x00b5c4, 0x00e8adb0}, /* U+8B70 */ - {0x00b5c5, 0x00e68eac}, /* U+63AC */ - {0x00b5c6, 0x00e88f8a}, /* U+83CA */ - {0x00b5c7, 0x00e99ea0}, /* U+97A0 */ - {0x00b5c8, 0x00e59089}, /* U+5409 */ - {0x00b5c9, 0x00e59083}, /* U+5403 */ - {0x00b5ca, 0x00e596ab}, /* U+55AB */ - {0x00b5cb, 0x00e6a194}, /* U+6854 */ - {0x00b5cc, 0x00e6a998}, /* U+6A58 */ - {0x00b5cd, 0x00e8a9b0}, /* U+8A70 */ - {0x00b5ce, 0x00e7a0a7}, /* U+7827 */ - {0x00b5cf, 0x00e69db5}, /* U+6775 */ - {0x00b5d0, 0x00e9bb8d}, /* U+9ECD */ - {0x00b5d1, 0x00e58db4}, /* U+5374 */ - {0x00b5d2, 0x00e5aea2}, /* U+5BA2 */ - {0x00b5d3, 0x00e8849a}, /* U+811A */ - {0x00b5d4, 0x00e89990}, /* U+8650 */ - {0x00b5d5, 0x00e98086}, /* U+9006 */ - {0x00b5d6, 0x00e4b898}, /* U+4E18 */ - {0x00b5d7, 0x00e4b985}, /* U+4E45 */ - {0x00b5d8, 0x00e4bb87}, /* U+4EC7 */ - {0x00b5d9, 0x00e4bc91}, /* U+4F11 */ - {0x00b5da, 0x00e58f8a}, /* U+53CA */ - {0x00b5db, 0x00e590b8}, /* U+5438 */ - {0x00b5dc, 0x00e5aeae}, /* U+5BAE */ - {0x00b5dd, 0x00e5bc93}, /* U+5F13 */ - {0x00b5de, 0x00e680a5}, /* U+6025 */ - {0x00b5df, 0x00e69591}, /* U+6551 */ - {0x00b5e0, 0x00e69cbd}, /* U+673D */ - {0x00b5e1, 0x00e6b182}, /* U+6C42 */ - {0x00b5e2, 0x00e6b1b2}, /* U+6C72 */ - {0x00b5e3, 0x00e6b3a3}, /* U+6CE3 */ - {0x00b5e4, 0x00e781b8}, /* U+7078 */ - {0x00b5e5, 0x00e79083}, /* U+7403 */ - {0x00b5e6, 0x00e7a9b6}, /* U+7A76 */ - {0x00b5e7, 0x00e7aaae}, /* U+7AAE */ - {0x00b5e8, 0x00e7ac88}, /* U+7B08 */ - {0x00b5e9, 0x00e7b49a}, /* U+7D1A */ - {0x00b5ea, 0x00e7b3be}, /* U+7CFE */ - {0x00b5eb, 0x00e7b5a6}, /* U+7D66 */ - {0x00b5ec, 0x00e697a7}, /* U+65E7 */ - {0x00b5ed, 0x00e7899b}, /* U+725B */ - {0x00b5ee, 0x00e58ebb}, /* U+53BB */ - {0x00b5ef, 0x00e5b185}, /* U+5C45 */ - {0x00b5f0, 0x00e5b7a8}, /* U+5DE8 */ - {0x00b5f1, 0x00e68b92}, /* U+62D2 */ - {0x00b5f2, 0x00e68ba0}, /* U+62E0 */ - {0x00b5f3, 0x00e68c99}, /* U+6319 */ - {0x00b5f4, 0x00e6b8a0}, /* U+6E20 */ - {0x00b5f5, 0x00e8999a}, /* U+865A */ - {0x00b5f6, 0x00e8a8b1}, /* U+8A31 */ - {0x00b5f7, 0x00e8b79d}, /* U+8DDD */ - {0x00b5f8, 0x00e98bb8}, /* U+92F8 */ - {0x00b5f9, 0x00e6bc81}, /* U+6F01 */ - {0x00b5fa, 0x00e7a6a6}, /* U+79A6 */ - {0x00b5fb, 0x00e9ad9a}, /* U+9B5A */ - {0x00b5fc, 0x00e4baa8}, /* U+4EA8 */ - {0x00b5fd, 0x00e4baab}, /* U+4EAB */ - {0x00b5fe, 0x00e4baac}, /* U+4EAC */ - {0x00b6a1, 0x00e4be9b}, /* U+4F9B */ - {0x00b6a2, 0x00e4bea0}, /* U+4FA0 */ - {0x00b6a3, 0x00e58391}, /* U+50D1 */ - {0x00b6a4, 0x00e58587}, /* U+5147 */ - {0x00b6a5, 0x00e7abb6}, /* U+7AF6 */ - {0x00b6a6, 0x00e585b1}, /* U+5171 */ - {0x00b6a7, 0x00e587b6}, /* U+51F6 */ - {0x00b6a8, 0x00e58d94}, /* U+5354 */ - {0x00b6a9, 0x00e58ca1}, /* U+5321 */ - {0x00b6aa, 0x00e58dbf}, /* U+537F */ - {0x00b6ab, 0x00e58fab}, /* U+53EB */ - {0x00b6ac, 0x00e596ac}, /* U+55AC */ - {0x00b6ad, 0x00e5a283}, /* U+5883 */ - {0x00b6ae, 0x00e5b3a1}, /* U+5CE1 */ - {0x00b6af, 0x00e5bcb7}, /* U+5F37 */ - {0x00b6b0, 0x00e5bd8a}, /* U+5F4A */ - {0x00b6b1, 0x00e680af}, /* U+602F */ - {0x00b6b2, 0x00e68190}, /* U+6050 */ - {0x00b6b3, 0x00e681ad}, /* U+606D */ - {0x00b6b4, 0x00e68c9f}, /* U+631F */ - {0x00b6b5, 0x00e69599}, /* U+6559 */ - {0x00b6b6, 0x00e6a98b}, /* U+6A4B */ - {0x00b6b7, 0x00e6b381}, /* U+6CC1 */ - {0x00b6b8, 0x00e78b82}, /* U+72C2 */ - {0x00b6b9, 0x00e78bad}, /* U+72ED */ - {0x00b6ba, 0x00e79faf}, /* U+77EF */ - {0x00b6bb, 0x00e883b8}, /* U+80F8 */ - {0x00b6bc, 0x00e88485}, /* U+8105 */ - {0x00b6bd, 0x00e88888}, /* U+8208 */ - {0x00b6be, 0x00e8958e}, /* U+854E */ - {0x00b6bf, 0x00e983b7}, /* U+90F7 */ - {0x00b6c0, 0x00e98fa1}, /* U+93E1 */ - {0x00b6c1, 0x00e99fbf}, /* U+97FF */ - {0x00b6c2, 0x00e9a597}, /* U+9957 */ - {0x00b6c3, 0x00e9a99a}, /* U+9A5A */ - {0x00b6c4, 0x00e4bbb0}, /* U+4EF0 */ - {0x00b6c5, 0x00e5879d}, /* U+51DD */ - {0x00b6c6, 0x00e5b0ad}, /* U+5C2D */ - {0x00b6c7, 0x00e69a81}, /* U+6681 */ - {0x00b6c8, 0x00e6a5ad}, /* U+696D */ - {0x00b6c9, 0x00e5b180}, /* U+5C40 */ - {0x00b6ca, 0x00e69bb2}, /* U+66F2 */ - {0x00b6cb, 0x00e6a5b5}, /* U+6975 */ - {0x00b6cc, 0x00e78e89}, /* U+7389 */ - {0x00b6cd, 0x00e6a190}, /* U+6850 */ - {0x00b6ce, 0x00e7b281}, /* U+7C81 */ - {0x00b6cf, 0x00e58385}, /* U+50C5 */ - {0x00b6d0, 0x00e58ba4}, /* U+52E4 */ - {0x00b6d1, 0x00e59d87}, /* U+5747 */ - {0x00b6d2, 0x00e5b7be}, /* U+5DFE */ - {0x00b6d3, 0x00e98ca6}, /* U+9326 */ - {0x00b6d4, 0x00e696a4}, /* U+65A4 */ - {0x00b6d5, 0x00e6aca3}, /* U+6B23 */ - {0x00b6d6, 0x00e6acbd}, /* U+6B3D */ - {0x00b6d7, 0x00e790b4}, /* U+7434 */ - {0x00b6d8, 0x00e7a681}, /* U+7981 */ - {0x00b6d9, 0x00e7a6bd}, /* U+79BD */ - {0x00b6da, 0x00e7ad8b}, /* U+7B4B */ - {0x00b6db, 0x00e7b78a}, /* U+7DCA */ - {0x00b6dc, 0x00e88ab9}, /* U+82B9 */ - {0x00b6dd, 0x00e88f8c}, /* U+83CC */ - {0x00b6de, 0x00e8a1bf}, /* U+887F */ - {0x00b6df, 0x00e8a59f}, /* U+895F */ - {0x00b6e0, 0x00e8acb9}, /* U+8B39 */ - {0x00b6e1, 0x00e8bf91}, /* U+8FD1 */ - {0x00b6e2, 0x00e98791}, /* U+91D1 */ - {0x00b6e3, 0x00e5909f}, /* U+541F */ - {0x00b6e4, 0x00e98a80}, /* U+9280 */ - {0x00b6e5, 0x00e4b99d}, /* U+4E5D */ - {0x00b6e6, 0x00e580b6}, /* U+5036 */ - {0x00b6e7, 0x00e58fa5}, /* U+53E5 */ - {0x00b6e8, 0x00e58cba}, /* U+533A */ - {0x00b6e9, 0x00e78b97}, /* U+72D7 */ - {0x00b6ea, 0x00e78e96}, /* U+7396 */ - {0x00b6eb, 0x00e79fa9}, /* U+77E9 */ - {0x00b6ec, 0x00e88ba6}, /* U+82E6 */ - {0x00b6ed, 0x00e8baaf}, /* U+8EAF */ - {0x00b6ee, 0x00e9a786}, /* U+99C6 */ - {0x00b6ef, 0x00e9a788}, /* U+99C8 */ - {0x00b6f0, 0x00e9a792}, /* U+99D2 */ - {0x00b6f1, 0x00e585b7}, /* U+5177 */ - {0x00b6f2, 0x00e6849a}, /* U+611A */ - {0x00b6f3, 0x00e8999e}, /* U+865E */ - {0x00b6f4, 0x00e596b0}, /* U+55B0 */ - {0x00b6f5, 0x00e7a9ba}, /* U+7A7A */ - {0x00b6f6, 0x00e581b6}, /* U+5076 */ - {0x00b6f7, 0x00e5af93}, /* U+5BD3 */ - {0x00b6f8, 0x00e98187}, /* U+9047 */ - {0x00b6f9, 0x00e99a85}, /* U+9685 */ - {0x00b6fa, 0x00e4b8b2}, /* U+4E32 */ - {0x00b6fb, 0x00e6ab9b}, /* U+6ADB */ - {0x00b6fc, 0x00e987a7}, /* U+91E7 */ - {0x00b6fd, 0x00e5b191}, /* U+5C51 */ - {0x00b6fe, 0x00e5b188}, /* U+5C48 */ - {0x00b7a1, 0x00e68e98}, /* U+6398 */ - {0x00b7a2, 0x00e7aa9f}, /* U+7A9F */ - {0x00b7a3, 0x00e6b293}, /* U+6C93 */ - {0x00b7a4, 0x00e99db4}, /* U+9774 */ - {0x00b7a5, 0x00e8bda1}, /* U+8F61 */ - {0x00b7a6, 0x00e7aaaa}, /* U+7AAA */ - {0x00b7a7, 0x00e7868a}, /* U+718A */ - {0x00b7a8, 0x00e99a88}, /* U+9688 */ - {0x00b7a9, 0x00e7b282}, /* U+7C82 */ - {0x00b7aa, 0x00e6a097}, /* U+6817 */ - {0x00b7ab, 0x00e7b9b0}, /* U+7E70 */ - {0x00b7ac, 0x00e6a191}, /* U+6851 */ - {0x00b7ad, 0x00e98dac}, /* U+936C */ - {0x00b7ae, 0x00e58bb2}, /* U+52F2 */ - {0x00b7af, 0x00e5909b}, /* U+541B */ - {0x00b7b0, 0x00e896ab}, /* U+85AB */ - {0x00b7b1, 0x00e8a893}, /* U+8A13 */ - {0x00b7b2, 0x00e7bea4}, /* U+7FA4 */ - {0x00b7b3, 0x00e8bb8d}, /* U+8ECD */ - {0x00b7b4, 0x00e983a1}, /* U+90E1 */ - {0x00b7b5, 0x00e58da6}, /* U+5366 */ - {0x00b7b6, 0x00e8a288}, /* U+8888 */ - {0x00b7b7, 0x00e7a581}, /* U+7941 */ - {0x00b7b8, 0x00e4bf82}, /* U+4FC2 */ - {0x00b7b9, 0x00e582be}, /* U+50BE */ - {0x00b7ba, 0x00e58891}, /* U+5211 */ - {0x00b7bb, 0x00e58584}, /* U+5144 */ - {0x00b7bc, 0x00e59593}, /* U+5553 */ - {0x00b7bd, 0x00e59cad}, /* U+572D */ - {0x00b7be, 0x00e78faa}, /* U+73EA */ - {0x00b7bf, 0x00e59e8b}, /* U+578B */ - {0x00b7c0, 0x00e5a591}, /* U+5951 */ - {0x00b7c1, 0x00e5bda2}, /* U+5F62 */ - {0x00b7c2, 0x00e5be84}, /* U+5F84 */ - {0x00b7c3, 0x00e681b5}, /* U+6075 */ - {0x00b7c4, 0x00e685b6}, /* U+6176 */ - {0x00b7c5, 0x00e685a7}, /* U+6167 */ - {0x00b7c6, 0x00e686a9}, /* U+61A9 */ - {0x00b7c7, 0x00e68eb2}, /* U+63B2 */ - {0x00b7c8, 0x00e690ba}, /* U+643A */ - {0x00b7c9, 0x00e695ac}, /* U+656C */ - {0x00b7ca, 0x00e699af}, /* U+666F */ - {0x00b7cb, 0x00e6a182}, /* U+6842 */ - {0x00b7cc, 0x00e6b893}, /* U+6E13 */ - {0x00b7cd, 0x00e795a6}, /* U+7566 */ - {0x00b7ce, 0x00e7a8bd}, /* U+7A3D */ - {0x00b7cf, 0x00e7b3bb}, /* U+7CFB */ - {0x00b7d0, 0x00e7b58c}, /* U+7D4C */ - {0x00b7d1, 0x00e7b699}, /* U+7D99 */ - {0x00b7d2, 0x00e7b98b}, /* U+7E4B */ - {0x00b7d3, 0x00e7bdab}, /* U+7F6B */ - {0x00b7d4, 0x00e88c8e}, /* U+830E */ - {0x00b7d5, 0x00e88d8a}, /* U+834A */ - {0x00b7d6, 0x00e89b8d}, /* U+86CD */ - {0x00b7d7, 0x00e8a888}, /* U+8A08 */ - {0x00b7d8, 0x00e8a9a3}, /* U+8A63 */ - {0x00b7d9, 0x00e8ada6}, /* U+8B66 */ - {0x00b7da, 0x00e8bbbd}, /* U+8EFD */ - {0x00b7db, 0x00e9a09a}, /* U+981A */ - {0x00b7dc, 0x00e9b68f}, /* U+9D8F */ - {0x00b7dd, 0x00e88ab8}, /* U+82B8 */ - {0x00b7de, 0x00e8bf8e}, /* U+8FCE */ - {0x00b7df, 0x00e9afa8}, /* U+9BE8 */ - {0x00b7e0, 0x00e58a87}, /* U+5287 */ - {0x00b7e1, 0x00e6889f}, /* U+621F */ - {0x00b7e2, 0x00e69283}, /* U+6483 */ - {0x00b7e3, 0x00e6bf80}, /* U+6FC0 */ - {0x00b7e4, 0x00e99a99}, /* U+9699 */ - {0x00b7e5, 0x00e6a181}, /* U+6841 */ - {0x00b7e6, 0x00e58291}, /* U+5091 */ - {0x00b7e7, 0x00e6aca0}, /* U+6B20 */ - {0x00b7e8, 0x00e6b1ba}, /* U+6C7A */ - {0x00b7e9, 0x00e6bd94}, /* U+6F54 */ - {0x00b7ea, 0x00e7a9b4}, /* U+7A74 */ - {0x00b7eb, 0x00e7b590}, /* U+7D50 */ - {0x00b7ec, 0x00e8a180}, /* U+8840 */ - {0x00b7ed, 0x00e8a8a3}, /* U+8A23 */ - {0x00b7ee, 0x00e69c88}, /* U+6708 */ - {0x00b7ef, 0x00e4bbb6}, /* U+4EF6 */ - {0x00b7f0, 0x00e580b9}, /* U+5039 */ - {0x00b7f1, 0x00e580a6}, /* U+5026 */ - {0x00b7f2, 0x00e581a5}, /* U+5065 */ - {0x00b7f3, 0x00e585bc}, /* U+517C */ - {0x00b7f4, 0x00e588b8}, /* U+5238 */ - {0x00b7f5, 0x00e589a3}, /* U+5263 */ - {0x00b7f6, 0x00e596a7}, /* U+55A7 */ - {0x00b7f7, 0x00e59c8f}, /* U+570F */ - {0x00b7f8, 0x00e5a085}, /* U+5805 */ - {0x00b7f9, 0x00e5ab8c}, /* U+5ACC */ - {0x00b7fa, 0x00e5bbba}, /* U+5EFA */ - {0x00b7fb, 0x00e686b2}, /* U+61B2 */ - {0x00b7fc, 0x00e687b8}, /* U+61F8 */ - {0x00b7fd, 0x00e68bb3}, /* U+62F3 */ - {0x00b7fe, 0x00e68db2}, /* U+6372 */ - {0x00b8a1, 0x00e6a49c}, /* U+691C */ - {0x00b8a2, 0x00e6a8a9}, /* U+6A29 */ - {0x00b8a3, 0x00e789bd}, /* U+727D */ - {0x00b8a4, 0x00e78aac}, /* U+72AC */ - {0x00b8a5, 0x00e78cae}, /* U+732E */ - {0x00b8a6, 0x00e7a094}, /* U+7814 */ - {0x00b8a7, 0x00e7a1af}, /* U+786F */ - {0x00b8a8, 0x00e7b5b9}, /* U+7D79 */ - {0x00b8a9, 0x00e79c8c}, /* U+770C */ - {0x00b8aa, 0x00e882a9}, /* U+80A9 */ - {0x00b8ab, 0x00e8a68b}, /* U+898B */ - {0x00b8ac, 0x00e8ac99}, /* U+8B19 */ - {0x00b8ad, 0x00e8b3a2}, /* U+8CE2 */ - {0x00b8ae, 0x00e8bb92}, /* U+8ED2 */ - {0x00b8af, 0x00e981a3}, /* U+9063 */ - {0x00b8b0, 0x00e98db5}, /* U+9375 */ - {0x00b8b1, 0x00e999ba}, /* U+967A */ - {0x00b8b2, 0x00e9a195}, /* U+9855 */ - {0x00b8b3, 0x00e9a893}, /* U+9A13 */ - {0x00b8b4, 0x00e9b9b8}, /* U+9E78 */ - {0x00b8b5, 0x00e58583}, /* U+5143 */ - {0x00b8b6, 0x00e58e9f}, /* U+539F */ - {0x00b8b7, 0x00e58eb3}, /* U+53B3 */ - {0x00b8b8, 0x00e5b9bb}, /* U+5E7B */ - {0x00b8b9, 0x00e5bca6}, /* U+5F26 */ - {0x00b8ba, 0x00e6b89b}, /* U+6E1B */ - {0x00b8bb, 0x00e6ba90}, /* U+6E90 */ - {0x00b8bc, 0x00e78e84}, /* U+7384 */ - {0x00b8bd, 0x00e78fbe}, /* U+73FE */ - {0x00b8be, 0x00e7b583}, /* U+7D43 */ - {0x00b8bf, 0x00e888b7}, /* U+8237 */ - {0x00b8c0, 0x00e8a880}, /* U+8A00 */ - {0x00b8c1, 0x00e8abba}, /* U+8AFA */ - {0x00b8c2, 0x00e99990}, /* U+9650 */ - {0x00b8c3, 0x00e4b98e}, /* U+4E4E */ - {0x00b8c4, 0x00e5808b}, /* U+500B */ - {0x00b8c5, 0x00e58fa4}, /* U+53E4 */ - {0x00b8c6, 0x00e591bc}, /* U+547C */ - {0x00b8c7, 0x00e59bba}, /* U+56FA */ - {0x00b8c8, 0x00e5a791}, /* U+59D1 */ - {0x00b8c9, 0x00e5ada4}, /* U+5B64 */ - {0x00b8ca, 0x00e5b7b1}, /* U+5DF1 */ - {0x00b8cb, 0x00e5baab}, /* U+5EAB */ - {0x00b8cc, 0x00e5bca7}, /* U+5F27 */ - {0x00b8cd, 0x00e688b8}, /* U+6238 */ - {0x00b8ce, 0x00e69585}, /* U+6545 */ - {0x00b8cf, 0x00e69eaf}, /* U+67AF */ - {0x00b8d0, 0x00e6b996}, /* U+6E56 */ - {0x00b8d1, 0x00e78b90}, /* U+72D0 */ - {0x00b8d2, 0x00e7b38a}, /* U+7CCA */ - {0x00b8d3, 0x00e8a2b4}, /* U+88B4 */ - {0x00b8d4, 0x00e882a1}, /* U+80A1 */ - {0x00b8d5, 0x00e883a1}, /* U+80E1 */ - {0x00b8d6, 0x00e88fb0}, /* U+83F0 */ - {0x00b8d7, 0x00e8998e}, /* U+864E */ - {0x00b8d8, 0x00e8aa87}, /* U+8A87 */ - {0x00b8d9, 0x00e8b7a8}, /* U+8DE8 */ - {0x00b8da, 0x00e988b7}, /* U+9237 */ - {0x00b8db, 0x00e99b87}, /* U+96C7 */ - {0x00b8dc, 0x00e9a1a7}, /* U+9867 */ - {0x00b8dd, 0x00e9bc93}, /* U+9F13 */ - {0x00b8de, 0x00e4ba94}, /* U+4E94 */ - {0x00b8df, 0x00e4ba92}, /* U+4E92 */ - {0x00b8e0, 0x00e4bc8d}, /* U+4F0D */ - {0x00b8e1, 0x00e58d88}, /* U+5348 */ - {0x00b8e2, 0x00e59189}, /* U+5449 */ - {0x00b8e3, 0x00e590be}, /* U+543E */ - {0x00b8e4, 0x00e5a8af}, /* U+5A2F */ - {0x00b8e5, 0x00e5be8c}, /* U+5F8C */ - {0x00b8e6, 0x00e5bea1}, /* U+5FA1 */ - {0x00b8e7, 0x00e6829f}, /* U+609F */ - {0x00b8e8, 0x00e6a2a7}, /* U+68A7 */ - {0x00b8e9, 0x00e6aa8e}, /* U+6A8E */ - {0x00b8ea, 0x00e7919a}, /* U+745A */ - {0x00b8eb, 0x00e7a281}, /* U+7881 */ - {0x00b8ec, 0x00e8aa9e}, /* U+8A9E */ - {0x00b8ed, 0x00e8aaa4}, /* U+8AA4 */ - {0x00b8ee, 0x00e8adb7}, /* U+8B77 */ - {0x00b8ef, 0x00e98690}, /* U+9190 */ - {0x00b8f0, 0x00e4b99e}, /* U+4E5E */ - {0x00b8f1, 0x00e9af89}, /* U+9BC9 */ - {0x00b8f2, 0x00e4baa4}, /* U+4EA4 */ - {0x00b8f3, 0x00e4bdbc}, /* U+4F7C */ - {0x00b8f4, 0x00e4beaf}, /* U+4FAF */ - {0x00b8f5, 0x00e58099}, /* U+5019 */ - {0x00b8f6, 0x00e58096}, /* U+5016 */ - {0x00b8f7, 0x00e58589}, /* U+5149 */ - {0x00b8f8, 0x00e585ac}, /* U+516C */ - {0x00b8f9, 0x00e58a9f}, /* U+529F */ - {0x00b8fa, 0x00e58ab9}, /* U+52B9 */ - {0x00b8fb, 0x00e58bbe}, /* U+52FE */ - {0x00b8fc, 0x00e58e9a}, /* U+539A */ - {0x00b8fd, 0x00e58fa3}, /* U+53E3 */ - {0x00b8fe, 0x00e59091}, /* U+5411 */ - {0x00b9a1, 0x00e5908e}, /* U+540E */ - {0x00b9a2, 0x00e59689}, /* U+5589 */ - {0x00b9a3, 0x00e59d91}, /* U+5751 */ - {0x00b9a4, 0x00e59ea2}, /* U+57A2 */ - {0x00b9a5, 0x00e5a5bd}, /* U+597D */ - {0x00b9a6, 0x00e5ad94}, /* U+5B54 */ - {0x00b9a7, 0x00e5ad9d}, /* U+5B5D */ - {0x00b9a8, 0x00e5ae8f}, /* U+5B8F */ - {0x00b9a9, 0x00e5b7a5}, /* U+5DE5 */ - {0x00b9aa, 0x00e5b7a7}, /* U+5DE7 */ - {0x00b9ab, 0x00e5b7b7}, /* U+5DF7 */ - {0x00b9ac, 0x00e5b9b8}, /* U+5E78 */ - {0x00b9ad, 0x00e5ba83}, /* U+5E83 */ - {0x00b9ae, 0x00e5ba9a}, /* U+5E9A */ - {0x00b9af, 0x00e5bab7}, /* U+5EB7 */ - {0x00b9b0, 0x00e5bc98}, /* U+5F18 */ - {0x00b9b1, 0x00e68192}, /* U+6052 */ - {0x00b9b2, 0x00e6858c}, /* U+614C */ - {0x00b9b3, 0x00e68a97}, /* U+6297 */ - {0x00b9b4, 0x00e68b98}, /* U+62D8 */ - {0x00b9b5, 0x00e68ea7}, /* U+63A7 */ - {0x00b9b6, 0x00e694bb}, /* U+653B */ - {0x00b9b7, 0x00e69882}, /* U+6602 */ - {0x00b9b8, 0x00e69983}, /* U+6643 */ - {0x00b9b9, 0x00e69bb4}, /* U+66F4 */ - {0x00b9ba, 0x00e69dad}, /* U+676D */ - {0x00b9bb, 0x00e6a0a1}, /* U+6821 */ - {0x00b9bc, 0x00e6a297}, /* U+6897 */ - {0x00b9bd, 0x00e6a78b}, /* U+69CB */ - {0x00b9be, 0x00e6b19f}, /* U+6C5F */ - {0x00b9bf, 0x00e6b4aa}, /* U+6D2A */ - {0x00b9c0, 0x00e6b5a9}, /* U+6D69 */ - {0x00b9c1, 0x00e6b8af}, /* U+6E2F */ - {0x00b9c2, 0x00e6ba9d}, /* U+6E9D */ - {0x00b9c3, 0x00e794b2}, /* U+7532 */ - {0x00b9c4, 0x00e79a87}, /* U+7687 */ - {0x00b9c5, 0x00e7a1ac}, /* U+786C */ - {0x00b9c6, 0x00e7a8bf}, /* U+7A3F */ - {0x00b9c7, 0x00e7b3a0}, /* U+7CE0 */ - {0x00b9c8, 0x00e7b485}, /* U+7D05 */ - {0x00b9c9, 0x00e7b498}, /* U+7D18 */ - {0x00b9ca, 0x00e7b59e}, /* U+7D5E */ - {0x00b9cb, 0x00e7b6b1}, /* U+7DB1 */ - {0x00b9cc, 0x00e88095}, /* U+8015 */ - {0x00b9cd, 0x00e88083}, /* U+8003 */ - {0x00b9ce, 0x00e882af}, /* U+80AF */ - {0x00b9cf, 0x00e882b1}, /* U+80B1 */ - {0x00b9d0, 0x00e88594}, /* U+8154 */ - {0x00b9d1, 0x00e8868f}, /* U+818F */ - {0x00b9d2, 0x00e888aa}, /* U+822A */ - {0x00b9d3, 0x00e88d92}, /* U+8352 */ - {0x00b9d4, 0x00e8a18c}, /* U+884C */ - {0x00b9d5, 0x00e8a1a1}, /* U+8861 */ - {0x00b9d6, 0x00e8ac9b}, /* U+8B1B */ - {0x00b9d7, 0x00e8b2a2}, /* U+8CA2 */ - {0x00b9d8, 0x00e8b3bc}, /* U+8CFC */ - {0x00b9d9, 0x00e9838a}, /* U+90CA */ - {0x00b9da, 0x00e985b5}, /* U+9175 */ - {0x00b9db, 0x00e989b1}, /* U+9271 */ - {0x00b9dc, 0x00e7a0bf}, /* U+783F */ - {0x00b9dd, 0x00e98bbc}, /* U+92FC */ - {0x00b9de, 0x00e996a4}, /* U+95A4 */ - {0x00b9df, 0x00e9998d}, /* U+964D */ - {0x00b9e0, 0x00e9a085}, /* U+9805 */ - {0x00b9e1, 0x00e9a699}, /* U+9999 */ - {0x00b9e2, 0x00e9ab98}, /* U+9AD8 */ - {0x00b9e3, 0x00e9b4bb}, /* U+9D3B */ - {0x00b9e4, 0x00e5899b}, /* U+525B */ - {0x00b9e5, 0x00e58aab}, /* U+52AB */ - {0x00b9e6, 0x00e58fb7}, /* U+53F7 */ - {0x00b9e7, 0x00e59088}, /* U+5408 */ - {0x00b9e8, 0x00e5a395}, /* U+58D5 */ - {0x00b9e9, 0x00e68bb7}, /* U+62F7 */ - {0x00b9ea, 0x00e6bfa0}, /* U+6FE0 */ - {0x00b9eb, 0x00e8b1aa}, /* U+8C6A */ - {0x00b9ec, 0x00e8bd9f}, /* U+8F5F */ - {0x00b9ed, 0x00e9bab9}, /* U+9EB9 */ - {0x00b9ee, 0x00e5858b}, /* U+514B */ - {0x00b9ef, 0x00e588bb}, /* U+523B */ - {0x00b9f0, 0x00e5918a}, /* U+544A */ - {0x00b9f1, 0x00e59bbd}, /* U+56FD */ - {0x00b9f2, 0x00e7a980}, /* U+7A40 */ - {0x00b9f3, 0x00e985b7}, /* U+9177 */ - {0x00b9f4, 0x00e9b5a0}, /* U+9D60 */ - {0x00b9f5, 0x00e9bb92}, /* U+9ED2 */ - {0x00b9f6, 0x00e78d84}, /* U+7344 */ - {0x00b9f7, 0x00e6bc89}, /* U+6F09 */ - {0x00b9f8, 0x00e885b0}, /* U+8170 */ - {0x00b9f9, 0x00e79491}, /* U+7511 */ - {0x00b9fa, 0x00e5bfbd}, /* U+5FFD */ - {0x00b9fb, 0x00e6839a}, /* U+60DA */ - {0x00b9fc, 0x00e9aaa8}, /* U+9AA8 */ - {0x00b9fd, 0x00e78b9b}, /* U+72DB */ - {0x00b9fe, 0x00e8bebc}, /* U+8FBC */ - {0x00baa1, 0x00e6ada4}, /* U+6B64 */ - {0x00baa2, 0x00e9a083}, /* U+9803 */ - {0x00baa3, 0x00e4bb8a}, /* U+4ECA */ - {0x00baa4, 0x00e59bb0}, /* U+56F0 */ - {0x00baa5, 0x00e59da4}, /* U+5764 */ - {0x00baa6, 0x00e5a2be}, /* U+58BE */ - {0x00baa7, 0x00e5a99a}, /* U+5A5A */ - {0x00baa8, 0x00e681a8}, /* U+6068 */ - {0x00baa9, 0x00e68787}, /* U+61C7 */ - {0x00baaa, 0x00e6988f}, /* U+660F */ - {0x00baab, 0x00e69886}, /* U+6606 */ - {0x00baac, 0x00e6a0b9}, /* U+6839 */ - {0x00baad, 0x00e6a2b1}, /* U+68B1 */ - {0x00baae, 0x00e6b7b7}, /* U+6DF7 */ - {0x00baaf, 0x00e79795}, /* U+75D5 */ - {0x00bab0, 0x00e7b4ba}, /* U+7D3A */ - {0x00bab1, 0x00e889ae}, /* U+826E */ - {0x00bab2, 0x00e9ad82}, /* U+9B42 */ - {0x00bab3, 0x00e4ba9b}, /* U+4E9B */ - {0x00bab4, 0x00e4bd90}, /* U+4F50 */ - {0x00bab5, 0x00e58f89}, /* U+53C9 */ - {0x00bab6, 0x00e59486}, /* U+5506 */ - {0x00bab7, 0x00e5b5af}, /* U+5D6F */ - {0x00bab8, 0x00e5b7a6}, /* U+5DE6 */ - {0x00bab9, 0x00e5b7ae}, /* U+5DEE */ - {0x00baba, 0x00e69fbb}, /* U+67FB */ - {0x00babb, 0x00e6b299}, /* U+6C99 */ - {0x00babc, 0x00e791b3}, /* U+7473 */ - {0x00babd, 0x00e7a082}, /* U+7802 */ - {0x00babe, 0x00e8a990}, /* U+8A50 */ - {0x00babf, 0x00e98e96}, /* U+9396 */ - {0x00bac0, 0x00e8a39f}, /* U+88DF */ - {0x00bac1, 0x00e59d90}, /* U+5750 */ - {0x00bac2, 0x00e5baa7}, /* U+5EA7 */ - {0x00bac3, 0x00e68cab}, /* U+632B */ - {0x00bac4, 0x00e582b5}, /* U+50B5 */ - {0x00bac5, 0x00e582ac}, /* U+50AC */ - {0x00bac6, 0x00e5868d}, /* U+518D */ - {0x00bac7, 0x00e69c80}, /* U+6700 */ - {0x00bac8, 0x00e59389}, /* U+54C9 */ - {0x00bac9, 0x00e5a19e}, /* U+585E */ - {0x00baca, 0x00e5a6bb}, /* U+59BB */ - {0x00bacb, 0x00e5aeb0}, /* U+5BB0 */ - {0x00bacc, 0x00e5bda9}, /* U+5F69 */ - {0x00bacd, 0x00e6898d}, /* U+624D */ - {0x00bace, 0x00e68ea1}, /* U+63A1 */ - {0x00bacf, 0x00e6a0bd}, /* U+683D */ - {0x00bad0, 0x00e6adb3}, /* U+6B73 */ - {0x00bad1, 0x00e6b888}, /* U+6E08 */ - {0x00bad2, 0x00e781bd}, /* U+707D */ - {0x00bad3, 0x00e98787}, /* U+91C7 */ - {0x00bad4, 0x00e78a80}, /* U+7280 */ - {0x00bad5, 0x00e7a095}, /* U+7815 */ - {0x00bad6, 0x00e7a0a6}, /* U+7826 */ - {0x00bad7, 0x00e7a5ad}, /* U+796D */ - {0x00bad8, 0x00e6968e}, /* U+658E */ - {0x00bad9, 0x00e7b4b0}, /* U+7D30 */ - {0x00bada, 0x00e88f9c}, /* U+83DC */ - {0x00badb, 0x00e8a381}, /* U+88C1 */ - {0x00badc, 0x00e8bc89}, /* U+8F09 */ - {0x00badd, 0x00e99a9b}, /* U+969B */ - {0x00bade, 0x00e589a4}, /* U+5264 */ - {0x00badf, 0x00e59ca8}, /* U+5728 */ - {0x00bae0, 0x00e69d90}, /* U+6750 */ - {0x00bae1, 0x00e7bdaa}, /* U+7F6A */ - {0x00bae2, 0x00e8b2a1}, /* U+8CA1 */ - {0x00bae3, 0x00e586b4}, /* U+51B4 */ - {0x00bae4, 0x00e59d82}, /* U+5742 */ - {0x00bae5, 0x00e998aa}, /* U+962A */ - {0x00bae6, 0x00e5a0ba}, /* U+583A */ - {0x00bae7, 0x00e6a68a}, /* U+698A */ - {0x00bae8, 0x00e882b4}, /* U+80B4 */ - {0x00bae9, 0x00e592b2}, /* U+54B2 */ - {0x00baea, 0x00e5b48e}, /* U+5D0E */ - {0x00baeb, 0x00e59fbc}, /* U+57FC */ - {0x00baec, 0x00e7a295}, /* U+7895 */ - {0x00baed, 0x00e9b7ba}, /* U+9DFA */ - {0x00baee, 0x00e4bd9c}, /* U+4F5C */ - {0x00baef, 0x00e5898a}, /* U+524A */ - {0x00baf0, 0x00e5928b}, /* U+548B */ - {0x00baf1, 0x00e690be}, /* U+643E */ - {0x00baf2, 0x00e698a8}, /* U+6628 */ - {0x00baf3, 0x00e69c94}, /* U+6714 */ - {0x00baf4, 0x00e69fb5}, /* U+67F5 */ - {0x00baf5, 0x00e7aa84}, /* U+7A84 */ - {0x00baf6, 0x00e7ad96}, /* U+7B56 */ - {0x00baf7, 0x00e7b4a2}, /* U+7D22 */ - {0x00baf8, 0x00e98caf}, /* U+932F */ - {0x00baf9, 0x00e6a19c}, /* U+685C */ - {0x00bafa, 0x00e9aead}, /* U+9BAD */ - {0x00bafb, 0x00e7acb9}, /* U+7B39 */ - {0x00bafc, 0x00e58c99}, /* U+5319 */ - {0x00bafd, 0x00e5868a}, /* U+518A */ - {0x00bafe, 0x00e588b7}, /* U+5237 */ - {0x00bba1, 0x00e5af9f}, /* U+5BDF */ - {0x00bba2, 0x00e68bb6}, /* U+62F6 */ - {0x00bba3, 0x00e692ae}, /* U+64AE */ - {0x00bba4, 0x00e693a6}, /* U+64E6 */ - {0x00bba5, 0x00e69cad}, /* U+672D */ - {0x00bba6, 0x00e6aeba}, /* U+6BBA */ - {0x00bba7, 0x00e896a9}, /* U+85A9 */ - {0x00bba8, 0x00e99b91}, /* U+96D1 */ - {0x00bba9, 0x00e79a90}, /* U+7690 */ - {0x00bbaa, 0x00e9af96}, /* U+9BD6 */ - {0x00bbab, 0x00e68d8c}, /* U+634C */ - {0x00bbac, 0x00e98c86}, /* U+9306 */ - {0x00bbad, 0x00e9aeab}, /* U+9BAB */ - {0x00bbae, 0x00e79abf}, /* U+76BF */ - {0x00bbaf, 0x00e69992}, /* U+6652 */ - {0x00bbb0, 0x00e4b889}, /* U+4E09 */ - {0x00bbb1, 0x00e58298}, /* U+5098 */ - {0x00bbb2, 0x00e58f82}, /* U+53C2 */ - {0x00bbb3, 0x00e5b1b1}, /* U+5C71 */ - {0x00bbb4, 0x00e683a8}, /* U+60E8 */ - {0x00bbb5, 0x00e69292}, /* U+6492 */ - {0x00bbb6, 0x00e695a3}, /* U+6563 */ - {0x00bbb7, 0x00e6a19f}, /* U+685F */ - {0x00bbb8, 0x00e787a6}, /* U+71E6 */ - {0x00bbb9, 0x00e78f8a}, /* U+73CA */ - {0x00bbba, 0x00e794a3}, /* U+7523 */ - {0x00bbbb, 0x00e7ae97}, /* U+7B97 */ - {0x00bbbc, 0x00e7ba82}, /* U+7E82 */ - {0x00bbbd, 0x00e89a95}, /* U+8695 */ - {0x00bbbe, 0x00e8ae83}, /* U+8B83 */ - {0x00bbbf, 0x00e8b39b}, /* U+8CDB */ - {0x00bbc0, 0x00e985b8}, /* U+9178 */ - {0x00bbc1, 0x00e9a490}, /* U+9910 */ - {0x00bbc2, 0x00e696ac}, /* U+65AC */ - {0x00bbc3, 0x00e69aab}, /* U+66AB */ - {0x00bbc4, 0x00e6ae8b}, /* U+6B8B */ - {0x00bbc5, 0x00e4bb95}, /* U+4ED5 */ - {0x00bbc6, 0x00e4bb94}, /* U+4ED4 */ - {0x00bbc7, 0x00e4bcba}, /* U+4F3A */ - {0x00bbc8, 0x00e4bdbf}, /* U+4F7F */ - {0x00bbc9, 0x00e588ba}, /* U+523A */ - {0x00bbca, 0x00e58fb8}, /* U+53F8 */ - {0x00bbcb, 0x00e58fb2}, /* U+53F2 */ - {0x00bbcc, 0x00e597a3}, /* U+55E3 */ - {0x00bbcd, 0x00e59b9b}, /* U+56DB */ - {0x00bbce, 0x00e5a3ab}, /* U+58EB */ - {0x00bbcf, 0x00e5a78b}, /* U+59CB */ - {0x00bbd0, 0x00e5a789}, /* U+59C9 */ - {0x00bbd1, 0x00e5a7bf}, /* U+59FF */ - {0x00bbd2, 0x00e5ad90}, /* U+5B50 */ - {0x00bbd3, 0x00e5b18d}, /* U+5C4D */ - {0x00bbd4, 0x00e5b882}, /* U+5E02 */ - {0x00bbd5, 0x00e5b8ab}, /* U+5E2B */ - {0x00bbd6, 0x00e5bf97}, /* U+5FD7 */ - {0x00bbd7, 0x00e6809d}, /* U+601D */ - {0x00bbd8, 0x00e68c87}, /* U+6307 */ - {0x00bbd9, 0x00e694af}, /* U+652F */ - {0x00bbda, 0x00e5ad9c}, /* U+5B5C */ - {0x00bbdb, 0x00e696af}, /* U+65AF */ - {0x00bbdc, 0x00e696bd}, /* U+65BD */ - {0x00bbdd, 0x00e697a8}, /* U+65E8 */ - {0x00bbde, 0x00e69e9d}, /* U+679D */ - {0x00bbdf, 0x00e6ada2}, /* U+6B62 */ - {0x00bbe0, 0x00e6adbb}, /* U+6B7B */ - {0x00bbe1, 0x00e6b08f}, /* U+6C0F */ - {0x00bbe2, 0x00e78d85}, /* U+7345 */ - {0x00bbe3, 0x00e7a589}, /* U+7949 */ - {0x00bbe4, 0x00e7a781}, /* U+79C1 */ - {0x00bbe5, 0x00e7b3b8}, /* U+7CF8 */ - {0x00bbe6, 0x00e7b499}, /* U+7D19 */ - {0x00bbe7, 0x00e7b4ab}, /* U+7D2B */ - {0x00bbe8, 0x00e882a2}, /* U+80A2 */ - {0x00bbe9, 0x00e88482}, /* U+8102 */ - {0x00bbea, 0x00e887b3}, /* U+81F3 */ - {0x00bbeb, 0x00e8a696}, /* U+8996 */ - {0x00bbec, 0x00e8a99e}, /* U+8A5E */ - {0x00bbed, 0x00e8a9a9}, /* U+8A69 */ - {0x00bbee, 0x00e8a9a6}, /* U+8A66 */ - {0x00bbef, 0x00e8aa8c}, /* U+8A8C */ - {0x00bbf0, 0x00e8abae}, /* U+8AEE */ - {0x00bbf1, 0x00e8b387}, /* U+8CC7 */ - {0x00bbf2, 0x00e8b39c}, /* U+8CDC */ - {0x00bbf3, 0x00e99b8c}, /* U+96CC */ - {0x00bbf4, 0x00e9a3bc}, /* U+98FC */ - {0x00bbf5, 0x00e6adaf}, /* U+6B6F */ - {0x00bbf6, 0x00e4ba8b}, /* U+4E8B */ - {0x00bbf7, 0x00e4bcbc}, /* U+4F3C */ - {0x00bbf8, 0x00e4be8d}, /* U+4F8D */ - {0x00bbf9, 0x00e58590}, /* U+5150 */ - {0x00bbfa, 0x00e5ad97}, /* U+5B57 */ - {0x00bbfb, 0x00e5afba}, /* U+5BFA */ - {0x00bbfc, 0x00e68588}, /* U+6148 */ - {0x00bbfd, 0x00e68c81}, /* U+6301 */ - {0x00bbfe, 0x00e69982}, /* U+6642 */ - {0x00bca1, 0x00e6aca1}, /* U+6B21 */ - {0x00bca2, 0x00e6bb8b}, /* U+6ECB */ - {0x00bca3, 0x00e6b2bb}, /* U+6CBB */ - {0x00bca4, 0x00e788be}, /* U+723E */ - {0x00bca5, 0x00e792bd}, /* U+74BD */ - {0x00bca6, 0x00e79794}, /* U+75D4 */ - {0x00bca7, 0x00e7a381}, /* U+78C1 */ - {0x00bca8, 0x00e7a4ba}, /* U+793A */ - {0x00bca9, 0x00e8808c}, /* U+800C */ - {0x00bcaa, 0x00e880b3}, /* U+8033 */ - {0x00bcab, 0x00e887aa}, /* U+81EA */ - {0x00bcac, 0x00e89294}, /* U+8494 */ - {0x00bcad, 0x00e8be9e}, /* U+8F9E */ - {0x00bcae, 0x00e6b190}, /* U+6C50 */ - {0x00bcaf, 0x00e9b9bf}, /* U+9E7F */ - {0x00bcb0, 0x00e5bc8f}, /* U+5F0F */ - {0x00bcb1, 0x00e8ad98}, /* U+8B58 */ - {0x00bcb2, 0x00e9b4ab}, /* U+9D2B */ - {0x00bcb3, 0x00e7abba}, /* U+7AFA */ - {0x00bcb4, 0x00e8bbb8}, /* U+8EF8 */ - {0x00bcb5, 0x00e5ae8d}, /* U+5B8D */ - {0x00bcb6, 0x00e99bab}, /* U+96EB */ - {0x00bcb7, 0x00e4b883}, /* U+4E03 */ - {0x00bcb8, 0x00e58fb1}, /* U+53F1 */ - {0x00bcb9, 0x00e59fb7}, /* U+57F7 */ - {0x00bcba, 0x00e5a4b1}, /* U+5931 */ - {0x00bcbb, 0x00e5ab89}, /* U+5AC9 */ - {0x00bcbc, 0x00e5aea4}, /* U+5BA4 */ - {0x00bcbd, 0x00e68289}, /* U+6089 */ - {0x00bcbe, 0x00e6b9bf}, /* U+6E7F */ - {0x00bcbf, 0x00e6bc86}, /* U+6F06 */ - {0x00bcc0, 0x00e796be}, /* U+75BE */ - {0x00bcc1, 0x00e8b3aa}, /* U+8CEA */ - {0x00bcc2, 0x00e5ae9f}, /* U+5B9F */ - {0x00bcc3, 0x00e89480}, /* U+8500 */ - {0x00bcc4, 0x00e7afa0}, /* U+7BE0 */ - {0x00bcc5, 0x00e581b2}, /* U+5072 */ - {0x00bcc6, 0x00e69fb4}, /* U+67F4 */ - {0x00bcc7, 0x00e88a9d}, /* U+829D */ - {0x00bcc8, 0x00e5b1a1}, /* U+5C61 */ - {0x00bcc9, 0x00e8958a}, /* U+854A */ - {0x00bcca, 0x00e7b89e}, /* U+7E1E */ - {0x00bccb, 0x00e8888e}, /* U+820E */ - {0x00bccc, 0x00e58699}, /* U+5199 */ - {0x00bccd, 0x00e5b084}, /* U+5C04 */ - {0x00bcce, 0x00e68da8}, /* U+6368 */ - {0x00bccf, 0x00e8b5a6}, /* U+8D66 */ - {0x00bcd0, 0x00e6969c}, /* U+659C */ - {0x00bcd1, 0x00e785ae}, /* U+716E */ - {0x00bcd2, 0x00e7a4be}, /* U+793E */ - {0x00bcd3, 0x00e7b497}, /* U+7D17 */ - {0x00bcd4, 0x00e88085}, /* U+8005 */ - {0x00bcd5, 0x00e8ac9d}, /* U+8B1D */ - {0x00bcd6, 0x00e8bb8a}, /* U+8ECA */ - {0x00bcd7, 0x00e981ae}, /* U+906E */ - {0x00bcd8, 0x00e89b87}, /* U+86C7 */ - {0x00bcd9, 0x00e982aa}, /* U+90AA */ - {0x00bcda, 0x00e5809f}, /* U+501F */ - {0x00bcdb, 0x00e58bba}, /* U+52FA */ - {0x00bcdc, 0x00e5b0ba}, /* U+5C3A */ - {0x00bcdd, 0x00e69d93}, /* U+6753 */ - {0x00bcde, 0x00e781bc}, /* U+707C */ - {0x00bcdf, 0x00e788b5}, /* U+7235 */ - {0x00bce0, 0x00e9858c}, /* U+914C */ - {0x00bce1, 0x00e98788}, /* U+91C8 */ - {0x00bce2, 0x00e98cab}, /* U+932B */ - {0x00bce3, 0x00e88ba5}, /* U+82E5 */ - {0x00bce4, 0x00e5af82}, /* U+5BC2 */ - {0x00bce5, 0x00e5bcb1}, /* U+5F31 */ - {0x00bce6, 0x00e683b9}, /* U+60F9 */ - {0x00bce7, 0x00e4b8bb}, /* U+4E3B */ - {0x00bce8, 0x00e58f96}, /* U+53D6 */ - {0x00bce9, 0x00e5ae88}, /* U+5B88 */ - {0x00bcea, 0x00e6898b}, /* U+624B */ - {0x00bceb, 0x00e69cb1}, /* U+6731 */ - {0x00bcec, 0x00e6ae8a}, /* U+6B8A */ - {0x00bced, 0x00e78ba9}, /* U+72E9 */ - {0x00bcee, 0x00e78fa0}, /* U+73E0 */ - {0x00bcef, 0x00e7a8ae}, /* U+7A2E */ - {0x00bcf0, 0x00e885ab}, /* U+816B */ - {0x00bcf1, 0x00e8b6a3}, /* U+8DA3 */ - {0x00bcf2, 0x00e98592}, /* U+9152 */ - {0x00bcf3, 0x00e9a696}, /* U+9996 */ - {0x00bcf4, 0x00e58492}, /* U+5112 */ - {0x00bcf5, 0x00e58f97}, /* U+53D7 */ - {0x00bcf6, 0x00e591aa}, /* U+546A */ - {0x00bcf7, 0x00e5afbf}, /* U+5BFF */ - {0x00bcf8, 0x00e68e88}, /* U+6388 */ - {0x00bcf9, 0x00e6a8b9}, /* U+6A39 */ - {0x00bcfa, 0x00e7b6ac}, /* U+7DAC */ - {0x00bcfb, 0x00e99c80}, /* U+9700 */ - {0x00bcfc, 0x00e59b9a}, /* U+56DA */ - {0x00bcfd, 0x00e58f8e}, /* U+53CE */ - {0x00bcfe, 0x00e591a8}, /* U+5468 */ - {0x00bda1, 0x00e5ae97}, /* U+5B97 */ - {0x00bda2, 0x00e5b0b1}, /* U+5C31 */ - {0x00bda3, 0x00e5b79e}, /* U+5DDE */ - {0x00bda4, 0x00e4bfae}, /* U+4FEE */ - {0x00bda5, 0x00e68481}, /* U+6101 */ - {0x00bda6, 0x00e68bbe}, /* U+62FE */ - {0x00bda7, 0x00e6b4b2}, /* U+6D32 */ - {0x00bda8, 0x00e7a780}, /* U+79C0 */ - {0x00bda9, 0x00e7a78b}, /* U+79CB */ - {0x00bdaa, 0x00e7b582}, /* U+7D42 */ - {0x00bdab, 0x00e7b98d}, /* U+7E4D */ - {0x00bdac, 0x00e7bf92}, /* U+7FD2 */ - {0x00bdad, 0x00e887ad}, /* U+81ED */ - {0x00bdae, 0x00e8889f}, /* U+821F */ - {0x00bdaf, 0x00e89290}, /* U+8490 */ - {0x00bdb0, 0x00e8a186}, /* U+8846 */ - {0x00bdb1, 0x00e8a5b2}, /* U+8972 */ - {0x00bdb2, 0x00e8ae90}, /* U+8B90 */ - {0x00bdb3, 0x00e8b9b4}, /* U+8E74 */ - {0x00bdb4, 0x00e8bcaf}, /* U+8F2F */ - {0x00bdb5, 0x00e980b1}, /* U+9031 */ - {0x00bdb6, 0x00e9858b}, /* U+914B */ - {0x00bdb7, 0x00e985ac}, /* U+916C */ - {0x00bdb8, 0x00e99b86}, /* U+96C6 */ - {0x00bdb9, 0x00e9869c}, /* U+919C */ - {0x00bdba, 0x00e4bb80}, /* U+4EC0 */ - {0x00bdbb, 0x00e4bd8f}, /* U+4F4F */ - {0x00bdbc, 0x00e58585}, /* U+5145 */ - {0x00bdbd, 0x00e58d81}, /* U+5341 */ - {0x00bdbe, 0x00e5be93}, /* U+5F93 */ - {0x00bdbf, 0x00e6888e}, /* U+620E */ - {0x00bdc0, 0x00e69f94}, /* U+67D4 */ - {0x00bdc1, 0x00e6b181}, /* U+6C41 */ - {0x00bdc2, 0x00e6b88b}, /* U+6E0B */ - {0x00bdc3, 0x00e78da3}, /* U+7363 */ - {0x00bdc4, 0x00e7b8a6}, /* U+7E26 */ - {0x00bdc5, 0x00e9878d}, /* U+91CD */ - {0x00bdc6, 0x00e98a83}, /* U+9283 */ - {0x00bdc7, 0x00e58f94}, /* U+53D4 */ - {0x00bdc8, 0x00e5a499}, /* U+5919 */ - {0x00bdc9, 0x00e5aebf}, /* U+5BBF */ - {0x00bdca, 0x00e6b791}, /* U+6DD1 */ - {0x00bdcb, 0x00e7a59d}, /* U+795D */ - {0x00bdcc, 0x00e7b8ae}, /* U+7E2E */ - {0x00bdcd, 0x00e7b29b}, /* U+7C9B */ - {0x00bdce, 0x00e5a1be}, /* U+587E */ - {0x00bdcf, 0x00e7869f}, /* U+719F */ - {0x00bdd0, 0x00e587ba}, /* U+51FA */ - {0x00bdd1, 0x00e8a193}, /* U+8853 */ - {0x00bdd2, 0x00e8bfb0}, /* U+8FF0 */ - {0x00bdd3, 0x00e4bf8a}, /* U+4FCA */ - {0x00bdd4, 0x00e5b3bb}, /* U+5CFB */ - {0x00bdd5, 0x00e698a5}, /* U+6625 */ - {0x00bdd6, 0x00e79eac}, /* U+77AC */ - {0x00bdd7, 0x00e7aba3}, /* U+7AE3 */ - {0x00bdd8, 0x00e8889c}, /* U+821C */ - {0x00bdd9, 0x00e9a7bf}, /* U+99FF */ - {0x00bdda, 0x00e58786}, /* U+51C6 */ - {0x00bddb, 0x00e5beaa}, /* U+5FAA */ - {0x00bddc, 0x00e697ac}, /* U+65EC */ - {0x00bddd, 0x00e6a5af}, /* U+696F */ - {0x00bdde, 0x00e6ae89}, /* U+6B89 */ - {0x00bddf, 0x00e6b7b3}, /* U+6DF3 */ - {0x00bde0, 0x00e6ba96}, /* U+6E96 */ - {0x00bde1, 0x00e6bda4}, /* U+6F64 */ - {0x00bde2, 0x00e79bbe}, /* U+76FE */ - {0x00bde3, 0x00e7b494}, /* U+7D14 */ - {0x00bde4, 0x00e5b7a1}, /* U+5DE1 */ - {0x00bde5, 0x00e981b5}, /* U+9075 */ - {0x00bde6, 0x00e98687}, /* U+9187 */ - {0x00bde7, 0x00e9a086}, /* U+9806 */ - {0x00bde8, 0x00e587a6}, /* U+51E6 */ - {0x00bde9, 0x00e5889d}, /* U+521D */ - {0x00bdea, 0x00e68980}, /* U+6240 */ - {0x00bdeb, 0x00e69a91}, /* U+6691 */ - {0x00bdec, 0x00e69b99}, /* U+66D9 */ - {0x00bded, 0x00e6b89a}, /* U+6E1A */ - {0x00bdee, 0x00e5bab6}, /* U+5EB6 */ - {0x00bdef, 0x00e7b792}, /* U+7DD2 */ - {0x00bdf0, 0x00e7bdb2}, /* U+7F72 */ - {0x00bdf1, 0x00e69bb8}, /* U+66F8 */ - {0x00bdf2, 0x00e896af}, /* U+85AF */ - {0x00bdf3, 0x00e897b7}, /* U+85F7 */ - {0x00bdf4, 0x00e8abb8}, /* U+8AF8 */ - {0x00bdf5, 0x00e58aa9}, /* U+52A9 */ - {0x00bdf6, 0x00e58f99}, /* U+53D9 */ - {0x00bdf7, 0x00e5a5b3}, /* U+5973 */ - {0x00bdf8, 0x00e5ba8f}, /* U+5E8F */ - {0x00bdf9, 0x00e5be90}, /* U+5F90 */ - {0x00bdfa, 0x00e68195}, /* U+6055 */ - {0x00bdfb, 0x00e98ba4}, /* U+92E4 */ - {0x00bdfc, 0x00e999a4}, /* U+9664 */ - {0x00bdfd, 0x00e582b7}, /* U+50B7 */ - {0x00bdfe, 0x00e5849f}, /* U+511F */ - {0x00bea1, 0x00e58b9d}, /* U+52DD */ - {0x00bea2, 0x00e58ca0}, /* U+5320 */ - {0x00bea3, 0x00e58d87}, /* U+5347 */ - {0x00bea4, 0x00e58fac}, /* U+53EC */ - {0x00bea5, 0x00e593a8}, /* U+54E8 */ - {0x00bea6, 0x00e59586}, /* U+5546 */ - {0x00bea7, 0x00e594b1}, /* U+5531 */ - {0x00bea8, 0x00e59897}, /* U+5617 */ - {0x00bea9, 0x00e5a5a8}, /* U+5968 */ - {0x00beaa, 0x00e5a6be}, /* U+59BE */ - {0x00beab, 0x00e5a8bc}, /* U+5A3C */ - {0x00beac, 0x00e5aeb5}, /* U+5BB5 */ - {0x00bead, 0x00e5b086}, /* U+5C06 */ - {0x00beae, 0x00e5b08f}, /* U+5C0F */ - {0x00beaf, 0x00e5b091}, /* U+5C11 */ - {0x00beb0, 0x00e5b09a}, /* U+5C1A */ - {0x00beb1, 0x00e5ba84}, /* U+5E84 */ - {0x00beb2, 0x00e5ba8a}, /* U+5E8A */ - {0x00beb3, 0x00e5bba0}, /* U+5EE0 */ - {0x00beb4, 0x00e5bdb0}, /* U+5F70 */ - {0x00beb5, 0x00e689bf}, /* U+627F */ - {0x00beb6, 0x00e68a84}, /* U+6284 */ - {0x00beb7, 0x00e68b9b}, /* U+62DB */ - {0x00beb8, 0x00e68e8c}, /* U+638C */ - {0x00beb9, 0x00e68db7}, /* U+6377 */ - {0x00beba, 0x00e69887}, /* U+6607 */ - {0x00bebb, 0x00e6988c}, /* U+660C */ - {0x00bebc, 0x00e698ad}, /* U+662D */ - {0x00bebd, 0x00e699b6}, /* U+6676 */ - {0x00bebe, 0x00e69dbe}, /* U+677E */ - {0x00bebf, 0x00e6a2a2}, /* U+68A2 */ - {0x00bec0, 0x00e6a89f}, /* U+6A1F */ - {0x00bec1, 0x00e6a8b5}, /* U+6A35 */ - {0x00bec2, 0x00e6b2bc}, /* U+6CBC */ - {0x00bec3, 0x00e6b688}, /* U+6D88 */ - {0x00bec4, 0x00e6b889}, /* U+6E09 */ - {0x00bec5, 0x00e6b998}, /* U+6E58 */ - {0x00bec6, 0x00e784bc}, /* U+713C */ - {0x00bec7, 0x00e784a6}, /* U+7126 */ - {0x00bec8, 0x00e785a7}, /* U+7167 */ - {0x00bec9, 0x00e79787}, /* U+75C7 */ - {0x00beca, 0x00e79c81}, /* U+7701 */ - {0x00becb, 0x00e7a19d}, /* U+785D */ - {0x00becc, 0x00e7a481}, /* U+7901 */ - {0x00becd, 0x00e7a5a5}, /* U+7965 */ - {0x00bece, 0x00e7a7b0}, /* U+79F0 */ - {0x00becf, 0x00e7aba0}, /* U+7AE0 */ - {0x00bed0, 0x00e7ac91}, /* U+7B11 */ - {0x00bed1, 0x00e7b2a7}, /* U+7CA7 */ - {0x00bed2, 0x00e7b4b9}, /* U+7D39 */ - {0x00bed3, 0x00e88296}, /* U+8096 */ - {0x00bed4, 0x00e88f96}, /* U+83D6 */ - {0x00bed5, 0x00e8928b}, /* U+848B */ - {0x00bed6, 0x00e89589}, /* U+8549 */ - {0x00bed7, 0x00e8a19d}, /* U+885D */ - {0x00bed8, 0x00e8a3b3}, /* U+88F3 */ - {0x00bed9, 0x00e8a89f}, /* U+8A1F */ - {0x00beda, 0x00e8a8bc}, /* U+8A3C */ - {0x00bedb, 0x00e8a994}, /* U+8A54 */ - {0x00bedc, 0x00e8a9b3}, /* U+8A73 */ - {0x00bedd, 0x00e8b1a1}, /* U+8C61 */ - {0x00bede, 0x00e8b39e}, /* U+8CDE */ - {0x00bedf, 0x00e986a4}, /* U+91A4 */ - {0x00bee0, 0x00e989a6}, /* U+9266 */ - {0x00bee1, 0x00e98dbe}, /* U+937E */ - {0x00bee2, 0x00e99098}, /* U+9418 */ - {0x00bee3, 0x00e99a9c}, /* U+969C */ - {0x00bee4, 0x00e99e98}, /* U+9798 */ - {0x00bee5, 0x00e4b88a}, /* U+4E0A */ - {0x00bee6, 0x00e4b888}, /* U+4E08 */ - {0x00bee7, 0x00e4b89e}, /* U+4E1E */ - {0x00bee8, 0x00e4b997}, /* U+4E57 */ - {0x00bee9, 0x00e58697}, /* U+5197 */ - {0x00beea, 0x00e589b0}, /* U+5270 */ - {0x00beeb, 0x00e59f8e}, /* U+57CE */ - {0x00beec, 0x00e5a0b4}, /* U+5834 */ - {0x00beed, 0x00e5a38c}, /* U+58CC */ - {0x00beee, 0x00e5aca2}, /* U+5B22 */ - {0x00beef, 0x00e5b8b8}, /* U+5E38 */ - {0x00bef0, 0x00e68385}, /* U+60C5 */ - {0x00bef1, 0x00e693be}, /* U+64FE */ - {0x00bef2, 0x00e69da1}, /* U+6761 */ - {0x00bef3, 0x00e69d96}, /* U+6756 */ - {0x00bef4, 0x00e6b584}, /* U+6D44 */ - {0x00bef5, 0x00e78ab6}, /* U+72B6 */ - {0x00bef6, 0x00e795b3}, /* U+7573 */ - {0x00bef7, 0x00e7a9a3}, /* U+7A63 */ - {0x00bef8, 0x00e892b8}, /* U+84B8 */ - {0x00bef9, 0x00e8adb2}, /* U+8B72 */ - {0x00befa, 0x00e986b8}, /* U+91B8 */ - {0x00befb, 0x00e98ca0}, /* U+9320 */ - {0x00befc, 0x00e598b1}, /* U+5631 */ - {0x00befd, 0x00e59fb4}, /* U+57F4 */ - {0x00befe, 0x00e9a3be}, /* U+98FE */ - {0x00bfa1, 0x00e68bad}, /* U+62ED */ - {0x00bfa2, 0x00e6a48d}, /* U+690D */ - {0x00bfa3, 0x00e6ae96}, /* U+6B96 */ - {0x00bfa4, 0x00e787ad}, /* U+71ED */ - {0x00bfa5, 0x00e7b994}, /* U+7E54 */ - {0x00bfa6, 0x00e881b7}, /* U+8077 */ - {0x00bfa7, 0x00e889b2}, /* U+8272 */ - {0x00bfa8, 0x00e8a7a6}, /* U+89E6 */ - {0x00bfa9, 0x00e9a39f}, /* U+98DF */ - {0x00bfaa, 0x00e89d95}, /* U+8755 */ - {0x00bfab, 0x00e8beb1}, /* U+8FB1 */ - {0x00bfac, 0x00e5b0bb}, /* U+5C3B */ - {0x00bfad, 0x00e4bcb8}, /* U+4F38 */ - {0x00bfae, 0x00e4bfa1}, /* U+4FE1 */ - {0x00bfaf, 0x00e4beb5}, /* U+4FB5 */ - {0x00bfb0, 0x00e59487}, /* U+5507 */ - {0x00bfb1, 0x00e5a8a0}, /* U+5A20 */ - {0x00bfb2, 0x00e5af9d}, /* U+5BDD */ - {0x00bfb3, 0x00e5afa9}, /* U+5BE9 */ - {0x00bfb4, 0x00e5bf83}, /* U+5FC3 */ - {0x00bfb5, 0x00e6858e}, /* U+614E */ - {0x00bfb6, 0x00e68caf}, /* U+632F */ - {0x00bfb7, 0x00e696b0}, /* U+65B0 */ - {0x00bfb8, 0x00e6998b}, /* U+664B */ - {0x00bfb9, 0x00e6a3ae}, /* U+68EE */ - {0x00bfba, 0x00e6a69b}, /* U+699B */ - {0x00bfbb, 0x00e6b5b8}, /* U+6D78 */ - {0x00bfbc, 0x00e6b7b1}, /* U+6DF1 */ - {0x00bfbd, 0x00e794b3}, /* U+7533 */ - {0x00bfbe, 0x00e796b9}, /* U+75B9 */ - {0x00bfbf, 0x00e79c9f}, /* U+771F */ - {0x00bfc0, 0x00e7a59e}, /* U+795E */ - {0x00bfc1, 0x00e7a7a6}, /* U+79E6 */ - {0x00bfc2, 0x00e7b4b3}, /* U+7D33 */ - {0x00bfc3, 0x00e887a3}, /* U+81E3 */ - {0x00bfc4, 0x00e88aaf}, /* U+82AF */ - {0x00bfc5, 0x00e896aa}, /* U+85AA */ - {0x00bfc6, 0x00e8a6aa}, /* U+89AA */ - {0x00bfc7, 0x00e8a8ba}, /* U+8A3A */ - {0x00bfc8, 0x00e8baab}, /* U+8EAB */ - {0x00bfc9, 0x00e8be9b}, /* U+8F9B */ - {0x00bfca, 0x00e980b2}, /* U+9032 */ - {0x00bfcb, 0x00e9879d}, /* U+91DD */ - {0x00bfcc, 0x00e99c87}, /* U+9707 */ - {0x00bfcd, 0x00e4baba}, /* U+4EBA */ - {0x00bfce, 0x00e4bb81}, /* U+4EC1 */ - {0x00bfcf, 0x00e58883}, /* U+5203 */ - {0x00bfd0, 0x00e5a1b5}, /* U+5875 */ - {0x00bfd1, 0x00e5a3ac}, /* U+58EC */ - {0x00bfd2, 0x00e5b08b}, /* U+5C0B */ - {0x00bfd3, 0x00e7949a}, /* U+751A */ - {0x00bfd4, 0x00e5b0bd}, /* U+5C3D */ - {0x00bfd5, 0x00e8858e}, /* U+814E */ - {0x00bfd6, 0x00e8a88a}, /* U+8A0A */ - {0x00bfd7, 0x00e8bf85}, /* U+8FC5 */ - {0x00bfd8, 0x00e999a3}, /* U+9663 */ - {0x00bfd9, 0x00e99dad}, /* U+976D */ - {0x00bfda, 0x00e7aca5}, /* U+7B25 */ - {0x00bfdb, 0x00e8ab8f}, /* U+8ACF */ - {0x00bfdc, 0x00e9a088}, /* U+9808 */ - {0x00bfdd, 0x00e985a2}, /* U+9162 */ - {0x00bfde, 0x00e59bb3}, /* U+56F3 */ - {0x00bfdf, 0x00e58ea8}, /* U+53A8 */ - {0x00bfe0, 0x00e98097}, /* U+9017 */ - {0x00bfe1, 0x00e590b9}, /* U+5439 */ - {0x00bfe2, 0x00e59e82}, /* U+5782 */ - {0x00bfe3, 0x00e5b8a5}, /* U+5E25 */ - {0x00bfe4, 0x00e68ea8}, /* U+63A8 */ - {0x00bfe5, 0x00e6b0b4}, /* U+6C34 */ - {0x00bfe6, 0x00e7828a}, /* U+708A */ - {0x00bfe7, 0x00e79da1}, /* U+7761 */ - {0x00bfe8, 0x00e7b28b}, /* U+7C8B */ - {0x00bfe9, 0x00e7bfa0}, /* U+7FE0 */ - {0x00bfea, 0x00e8a1b0}, /* U+8870 */ - {0x00bfeb, 0x00e98182}, /* U+9042 */ - {0x00bfec, 0x00e98594}, /* U+9154 */ - {0x00bfed, 0x00e98c90}, /* U+9310 */ - {0x00bfee, 0x00e98c98}, /* U+9318 */ - {0x00bfef, 0x00e99a8f}, /* U+968F */ - {0x00bff0, 0x00e7919e}, /* U+745E */ - {0x00bff1, 0x00e9ab84}, /* U+9AC4 */ - {0x00bff2, 0x00e5b487}, /* U+5D07 */ - {0x00bff3, 0x00e5b5a9}, /* U+5D69 */ - {0x00bff4, 0x00e695b0}, /* U+6570 */ - {0x00bff5, 0x00e69ea2}, /* U+67A2 */ - {0x00bff6, 0x00e8b6a8}, /* U+8DA8 */ - {0x00bff7, 0x00e99b9b}, /* U+96DB */ - {0x00bff8, 0x00e68dae}, /* U+636E */ - {0x00bff9, 0x00e69d89}, /* U+6749 */ - {0x00bffa, 0x00e6a499}, /* U+6919 */ - {0x00bffb, 0x00e88f85}, /* U+83C5 */ - {0x00bffc, 0x00e9a097}, /* U+9817 */ - {0x00bffd, 0x00e99b80}, /* U+96C0 */ - {0x00bffe, 0x00e8a3be}, /* U+88FE */ - {0x00c0a1, 0x00e6be84}, /* U+6F84 */ - {0x00c0a2, 0x00e691ba}, /* U+647A */ - {0x00c0a3, 0x00e5afb8}, /* U+5BF8 */ - {0x00c0a4, 0x00e4b896}, /* U+4E16 */ - {0x00c0a5, 0x00e780ac}, /* U+702C */ - {0x00c0a6, 0x00e7959d}, /* U+755D */ - {0x00c0a7, 0x00e698af}, /* U+662F */ - {0x00c0a8, 0x00e58784}, /* U+51C4 */ - {0x00c0a9, 0x00e588b6}, /* U+5236 */ - {0x00c0aa, 0x00e58ba2}, /* U+52E2 */ - {0x00c0ab, 0x00e5a793}, /* U+59D3 */ - {0x00c0ac, 0x00e5be81}, /* U+5F81 */ - {0x00c0ad, 0x00e680a7}, /* U+6027 */ - {0x00c0ae, 0x00e68890}, /* U+6210 */ - {0x00c0af, 0x00e694bf}, /* U+653F */ - {0x00c0b0, 0x00e695b4}, /* U+6574 */ - {0x00c0b1, 0x00e6989f}, /* U+661F */ - {0x00c0b2, 0x00e699b4}, /* U+6674 */ - {0x00c0b3, 0x00e6a3b2}, /* U+68F2 */ - {0x00c0b4, 0x00e6a096}, /* U+6816 */ - {0x00c0b5, 0x00e6ada3}, /* U+6B63 */ - {0x00c0b6, 0x00e6b885}, /* U+6E05 */ - {0x00c0b7, 0x00e789b2}, /* U+7272 */ - {0x00c0b8, 0x00e7949f}, /* U+751F */ - {0x00c0b9, 0x00e79b9b}, /* U+76DB */ - {0x00c0ba, 0x00e7b2be}, /* U+7CBE */ - {0x00c0bb, 0x00e88196}, /* U+8056 */ - {0x00c0bc, 0x00e5a3b0}, /* U+58F0 */ - {0x00c0bd, 0x00e8a3bd}, /* U+88FD */ - {0x00c0be, 0x00e8a5bf}, /* U+897F */ - {0x00c0bf, 0x00e8aaa0}, /* U+8AA0 */ - {0x00c0c0, 0x00e8aa93}, /* U+8A93 */ - {0x00c0c1, 0x00e8ab8b}, /* U+8ACB */ - {0x00c0c2, 0x00e9809d}, /* U+901D */ - {0x00c0c3, 0x00e98692}, /* U+9192 */ - {0x00c0c4, 0x00e99d92}, /* U+9752 */ - {0x00c0c5, 0x00e99d99}, /* U+9759 */ - {0x00c0c6, 0x00e69689}, /* U+6589 */ - {0x00c0c7, 0x00e7a88e}, /* U+7A0E */ - {0x00c0c8, 0x00e88486}, /* U+8106 */ - {0x00c0c9, 0x00e99abb}, /* U+96BB */ - {0x00c0ca, 0x00e5b8ad}, /* U+5E2D */ - {0x00c0cb, 0x00e6839c}, /* U+60DC */ - {0x00c0cc, 0x00e6889a}, /* U+621A */ - {0x00c0cd, 0x00e696a5}, /* U+65A5 */ - {0x00c0ce, 0x00e69894}, /* U+6614 */ - {0x00c0cf, 0x00e69e90}, /* U+6790 */ - {0x00c0d0, 0x00e79fb3}, /* U+77F3 */ - {0x00c0d1, 0x00e7a98d}, /* U+7A4D */ - {0x00c0d2, 0x00e7b18d}, /* U+7C4D */ - {0x00c0d3, 0x00e7b8be}, /* U+7E3E */ - {0x00c0d4, 0x00e8848a}, /* U+810A */ - {0x00c0d5, 0x00e8b2ac}, /* U+8CAC */ - {0x00c0d6, 0x00e8b5a4}, /* U+8D64 */ - {0x00c0d7, 0x00e8b7a1}, /* U+8DE1 */ - {0x00c0d8, 0x00e8b99f}, /* U+8E5F */ - {0x00c0d9, 0x00e7a2a9}, /* U+78A9 */ - {0x00c0da, 0x00e58887}, /* U+5207 */ - {0x00c0db, 0x00e68b99}, /* U+62D9 */ - {0x00c0dc, 0x00e68ea5}, /* U+63A5 */ - {0x00c0dd, 0x00e69182}, /* U+6442 */ - {0x00c0de, 0x00e68a98}, /* U+6298 */ - {0x00c0df, 0x00e8a8ad}, /* U+8A2D */ - {0x00c0e0, 0x00e7aa83}, /* U+7A83 */ - {0x00c0e1, 0x00e7af80}, /* U+7BC0 */ - {0x00c0e2, 0x00e8aaac}, /* U+8AAC */ - {0x00c0e3, 0x00e99baa}, /* U+96EA */ - {0x00c0e4, 0x00e7b5b6}, /* U+7D76 */ - {0x00c0e5, 0x00e8888c}, /* U+820C */ - {0x00c0e6, 0x00e89d89}, /* U+8749 */ - {0x00c0e7, 0x00e4bb99}, /* U+4ED9 */ - {0x00c0e8, 0x00e58588}, /* U+5148 */ - {0x00c0e9, 0x00e58d83}, /* U+5343 */ - {0x00c0ea, 0x00e58da0}, /* U+5360 */ - {0x00c0eb, 0x00e5aea3}, /* U+5BA3 */ - {0x00c0ec, 0x00e5b082}, /* U+5C02 */ - {0x00c0ed, 0x00e5b096}, /* U+5C16 */ - {0x00c0ee, 0x00e5b79d}, /* U+5DDD */ - {0x00c0ef, 0x00e688a6}, /* U+6226 */ - {0x00c0f0, 0x00e68987}, /* U+6247 */ - {0x00c0f1, 0x00e692b0}, /* U+64B0 */ - {0x00c0f2, 0x00e6a093}, /* U+6813 */ - {0x00c0f3, 0x00e6a0b4}, /* U+6834 */ - {0x00c0f4, 0x00e6b389}, /* U+6CC9 */ - {0x00c0f5, 0x00e6b585}, /* U+6D45 */ - {0x00c0f6, 0x00e6b497}, /* U+6D17 */ - {0x00c0f7, 0x00e69f93}, /* U+67D3 */ - {0x00c0f8, 0x00e6bd9c}, /* U+6F5C */ - {0x00c0f9, 0x00e7858e}, /* U+714E */ - {0x00c0fa, 0x00e785bd}, /* U+717D */ - {0x00c0fb, 0x00e6978b}, /* U+65CB */ - {0x00c0fc, 0x00e7a9bf}, /* U+7A7F */ - {0x00c0fd, 0x00e7aead}, /* U+7BAD */ - {0x00c0fe, 0x00e7b79a}, /* U+7DDA */ - {0x00c1a1, 0x00e7b98a}, /* U+7E4A */ - {0x00c1a2, 0x00e7bea8}, /* U+7FA8 */ - {0x00c1a3, 0x00e885ba}, /* U+817A */ - {0x00c1a4, 0x00e8889b}, /* U+821B */ - {0x00c1a5, 0x00e888b9}, /* U+8239 */ - {0x00c1a6, 0x00e896a6}, /* U+85A6 */ - {0x00c1a7, 0x00e8a9ae}, /* U+8A6E */ - {0x00c1a8, 0x00e8b38e}, /* U+8CCE */ - {0x00c1a9, 0x00e8b7b5}, /* U+8DF5 */ - {0x00c1aa, 0x00e981b8}, /* U+9078 */ - {0x00c1ab, 0x00e981b7}, /* U+9077 */ - {0x00c1ac, 0x00e98aad}, /* U+92AD */ - {0x00c1ad, 0x00e98a91}, /* U+9291 */ - {0x00c1ae, 0x00e99683}, /* U+9583 */ - {0x00c1af, 0x00e9aeae}, /* U+9BAE */ - {0x00c1b0, 0x00e5898d}, /* U+524D */ - {0x00c1b1, 0x00e59684}, /* U+5584 */ - {0x00c1b2, 0x00e6bcb8}, /* U+6F38 */ - {0x00c1b3, 0x00e784b6}, /* U+7136 */ - {0x00c1b4, 0x00e585a8}, /* U+5168 */ - {0x00c1b5, 0x00e7a685}, /* U+7985 */ - {0x00c1b6, 0x00e7b995}, /* U+7E55 */ - {0x00c1b7, 0x00e886b3}, /* U+81B3 */ - {0x00c1b8, 0x00e7b38e}, /* U+7CCE */ - {0x00c1b9, 0x00e5998c}, /* U+564C */ - {0x00c1ba, 0x00e5a191}, /* U+5851 */ - {0x00c1bb, 0x00e5b2a8}, /* U+5CA8 */ - {0x00c1bc, 0x00e68eaa}, /* U+63AA */ - {0x00c1bd, 0x00e69bbe}, /* U+66FE */ - {0x00c1be, 0x00e69bbd}, /* U+66FD */ - {0x00c1bf, 0x00e6a59a}, /* U+695A */ - {0x00c1c0, 0x00e78b99}, /* U+72D9 */ - {0x00c1c1, 0x00e7968f}, /* U+758F */ - {0x00c1c2, 0x00e7968e}, /* U+758E */ - {0x00c1c3, 0x00e7a48e}, /* U+790E */ - {0x00c1c4, 0x00e7a596}, /* U+7956 */ - {0x00c1c5, 0x00e7a79f}, /* U+79DF */ - {0x00c1c6, 0x00e7b297}, /* U+7C97 */ - {0x00c1c7, 0x00e7b4a0}, /* U+7D20 */ - {0x00c1c8, 0x00e7b584}, /* U+7D44 */ - {0x00c1c9, 0x00e89887}, /* U+8607 */ - {0x00c1ca, 0x00e8a8b4}, /* U+8A34 */ - {0x00c1cb, 0x00e998bb}, /* U+963B */ - {0x00c1cc, 0x00e981a1}, /* U+9061 */ - {0x00c1cd, 0x00e9bca0}, /* U+9F20 */ - {0x00c1ce, 0x00e583a7}, /* U+50E7 */ - {0x00c1cf, 0x00e589b5}, /* U+5275 */ - {0x00c1d0, 0x00e58f8c}, /* U+53CC */ - {0x00c1d1, 0x00e58fa2}, /* U+53E2 */ - {0x00c1d2, 0x00e58089}, /* U+5009 */ - {0x00c1d3, 0x00e596aa}, /* U+55AA */ - {0x00c1d4, 0x00e5a3ae}, /* U+58EE */ - {0x00c1d5, 0x00e5a58f}, /* U+594F */ - {0x00c1d6, 0x00e788bd}, /* U+723D */ - {0x00c1d7, 0x00e5ae8b}, /* U+5B8B */ - {0x00c1d8, 0x00e5b1a4}, /* U+5C64 */ - {0x00c1d9, 0x00e58c9d}, /* U+531D */ - {0x00c1da, 0x00e683a3}, /* U+60E3 */ - {0x00c1db, 0x00e683b3}, /* U+60F3 */ - {0x00c1dc, 0x00e68d9c}, /* U+635C */ - {0x00c1dd, 0x00e68e83}, /* U+6383 */ - {0x00c1de, 0x00e68cbf}, /* U+633F */ - {0x00c1df, 0x00e68ebb}, /* U+63BB */ - {0x00c1e0, 0x00e6938d}, /* U+64CD */ - {0x00c1e1, 0x00e697a9}, /* U+65E9 */ - {0x00c1e2, 0x00e69bb9}, /* U+66F9 */ - {0x00c1e3, 0x00e5b7a3}, /* U+5DE3 */ - {0x00c1e4, 0x00e6a78d}, /* U+69CD */ - {0x00c1e5, 0x00e6a7bd}, /* U+69FD */ - {0x00c1e6, 0x00e6bc95}, /* U+6F15 */ - {0x00c1e7, 0x00e787a5}, /* U+71E5 */ - {0x00c1e8, 0x00e4ba89}, /* U+4E89 */ - {0x00c1e9, 0x00e797a9}, /* U+75E9 */ - {0x00c1ea, 0x00e79bb8}, /* U+76F8 */ - {0x00c1eb, 0x00e7aa93}, /* U+7A93 */ - {0x00c1ec, 0x00e7b39f}, /* U+7CDF */ - {0x00c1ed, 0x00e7b78f}, /* U+7DCF */ - {0x00c1ee, 0x00e7b69c}, /* U+7D9C */ - {0x00c1ef, 0x00e881a1}, /* U+8061 */ - {0x00c1f0, 0x00e88d89}, /* U+8349 */ - {0x00c1f1, 0x00e88d98}, /* U+8358 */ - {0x00c1f2, 0x00e891ac}, /* U+846C */ - {0x00c1f3, 0x00e892bc}, /* U+84BC */ - {0x00c1f4, 0x00e897bb}, /* U+85FB */ - {0x00c1f5, 0x00e8a385}, /* U+88C5 */ - {0x00c1f6, 0x00e8b5b0}, /* U+8D70 */ - {0x00c1f7, 0x00e98081}, /* U+9001 */ - {0x00c1f8, 0x00e981ad}, /* U+906D */ - {0x00c1f9, 0x00e98e97}, /* U+9397 */ - {0x00c1fa, 0x00e99c9c}, /* U+971C */ - {0x00c1fb, 0x00e9a892}, /* U+9A12 */ - {0x00c1fc, 0x00e5838f}, /* U+50CF */ - {0x00c1fd, 0x00e5a297}, /* U+5897 */ - {0x00c1fe, 0x00e6868e}, /* U+618E */ - {0x00c2a1, 0x00e88793}, /* U+81D3 */ - {0x00c2a2, 0x00e894b5}, /* U+8535 */ - {0x00c2a3, 0x00e8b488}, /* U+8D08 */ - {0x00c2a4, 0x00e980a0}, /* U+9020 */ - {0x00c2a5, 0x00e4bf83}, /* U+4FC3 */ - {0x00c2a6, 0x00e581b4}, /* U+5074 */ - {0x00c2a7, 0x00e58987}, /* U+5247 */ - {0x00c2a8, 0x00e58db3}, /* U+5373 */ - {0x00c2a9, 0x00e681af}, /* U+606F */ - {0x00c2aa, 0x00e68d89}, /* U+6349 */ - {0x00c2ab, 0x00e69d9f}, /* U+675F */ - {0x00c2ac, 0x00e6b8ac}, /* U+6E2C */ - {0x00c2ad, 0x00e8b6b3}, /* U+8DB3 */ - {0x00c2ae, 0x00e9809f}, /* U+901F */ - {0x00c2af, 0x00e4bf97}, /* U+4FD7 */ - {0x00c2b0, 0x00e5b19e}, /* U+5C5E */ - {0x00c2b1, 0x00e8b38a}, /* U+8CCA */ - {0x00c2b2, 0x00e6978f}, /* U+65CF */ - {0x00c2b3, 0x00e7b69a}, /* U+7D9A */ - {0x00c2b4, 0x00e58d92}, /* U+5352 */ - {0x00c2b5, 0x00e8a296}, /* U+8896 */ - {0x00c2b6, 0x00e585b6}, /* U+5176 */ - {0x00c2b7, 0x00e68f83}, /* U+63C3 */ - {0x00c2b8, 0x00e5ad98}, /* U+5B58 */ - {0x00c2b9, 0x00e5adab}, /* U+5B6B */ - {0x00c2ba, 0x00e5b08a}, /* U+5C0A */ - {0x00c2bb, 0x00e6908d}, /* U+640D */ - {0x00c2bc, 0x00e69d91}, /* U+6751 */ - {0x00c2bd, 0x00e9819c}, /* U+905C */ - {0x00c2be, 0x00e4bb96}, /* U+4ED6 */ - {0x00c2bf, 0x00e5a49a}, /* U+591A */ - {0x00c2c0, 0x00e5a4aa}, /* U+592A */ - {0x00c2c1, 0x00e6b1b0}, /* U+6C70 */ - {0x00c2c2, 0x00e8a991}, /* U+8A51 */ - {0x00c2c3, 0x00e594be}, /* U+553E */ - {0x00c2c4, 0x00e5a095}, /* U+5815 */ - {0x00c2c5, 0x00e5a6a5}, /* U+59A5 */ - {0x00c2c6, 0x00e683b0}, /* U+60F0 */ - {0x00c2c7, 0x00e68993}, /* U+6253 */ - {0x00c2c8, 0x00e69f81}, /* U+67C1 */ - {0x00c2c9, 0x00e888b5}, /* U+8235 */ - {0x00c2ca, 0x00e6a595}, /* U+6955 */ - {0x00c2cb, 0x00e99980}, /* U+9640 */ - {0x00c2cc, 0x00e9a784}, /* U+99C4 */ - {0x00c2cd, 0x00e9a8a8}, /* U+9A28 */ - {0x00c2ce, 0x00e4bd93}, /* U+4F53 */ - {0x00c2cf, 0x00e5a086}, /* U+5806 */ - {0x00c2d0, 0x00e5afbe}, /* U+5BFE */ - {0x00c2d1, 0x00e88090}, /* U+8010 */ - {0x00c2d2, 0x00e5b2b1}, /* U+5CB1 */ - {0x00c2d3, 0x00e5b8af}, /* U+5E2F */ - {0x00c2d4, 0x00e5be85}, /* U+5F85 */ - {0x00c2d5, 0x00e680a0}, /* U+6020 */ - {0x00c2d6, 0x00e6858b}, /* U+614B */ - {0x00c2d7, 0x00e688b4}, /* U+6234 */ - {0x00c2d8, 0x00e69bbf}, /* U+66FF */ - {0x00c2d9, 0x00e6b3b0}, /* U+6CF0 */ - {0x00c2da, 0x00e6bb9e}, /* U+6EDE */ - {0x00c2db, 0x00e8838e}, /* U+80CE */ - {0x00c2dc, 0x00e885bf}, /* U+817F */ - {0x00c2dd, 0x00e88b94}, /* U+82D4 */ - {0x00c2de, 0x00e8a28b}, /* U+888B */ - {0x00c2df, 0x00e8b2b8}, /* U+8CB8 */ - {0x00c2e0, 0x00e98080}, /* U+9000 */ - {0x00c2e1, 0x00e980ae}, /* U+902E */ - {0x00c2e2, 0x00e99a8a}, /* U+968A */ - {0x00c2e3, 0x00e9bb9b}, /* U+9EDB */ - {0x00c2e4, 0x00e9af9b}, /* U+9BDB */ - {0x00c2e5, 0x00e4bba3}, /* U+4EE3 */ - {0x00c2e6, 0x00e58fb0}, /* U+53F0 */ - {0x00c2e7, 0x00e5a4a7}, /* U+5927 */ - {0x00c2e8, 0x00e7acac}, /* U+7B2C */ - {0x00c2e9, 0x00e9868d}, /* U+918D */ - {0x00c2ea, 0x00e9a18c}, /* U+984C */ - {0x00c2eb, 0x00e9b7b9}, /* U+9DF9 */ - {0x00c2ec, 0x00e6bb9d}, /* U+6EDD */ - {0x00c2ed, 0x00e780a7}, /* U+7027 */ - {0x00c2ee, 0x00e58d93}, /* U+5353 */ - {0x00c2ef, 0x00e59584}, /* U+5544 */ - {0x00c2f0, 0x00e5ae85}, /* U+5B85 */ - {0x00c2f1, 0x00e68998}, /* U+6258 */ - {0x00c2f2, 0x00e68a9e}, /* U+629E */ - {0x00c2f3, 0x00e68b93}, /* U+62D3 */ - {0x00c2f4, 0x00e6b2a2}, /* U+6CA2 */ - {0x00c2f5, 0x00e6bfaf}, /* U+6FEF */ - {0x00c2f6, 0x00e790a2}, /* U+7422 */ - {0x00c2f7, 0x00e8a897}, /* U+8A17 */ - {0x00c2f8, 0x00e990b8}, /* U+9438 */ - {0x00c2f9, 0x00e6bf81}, /* U+6FC1 */ - {0x00c2fa, 0x00e8abbe}, /* U+8AFE */ - {0x00c2fb, 0x00e88cb8}, /* U+8338 */ - {0x00c2fc, 0x00e587a7}, /* U+51E7 */ - {0x00c2fd, 0x00e89bb8}, /* U+86F8 */ - {0x00c2fe, 0x00e58faa}, /* U+53EA */ - {0x00c3a1, 0x00e58fa9}, /* U+53E9 */ - {0x00c3a2, 0x00e4bd86}, /* U+4F46 */ - {0x00c3a3, 0x00e98194}, /* U+9054 */ - {0x00c3a4, 0x00e8beb0}, /* U+8FB0 */ - {0x00c3a5, 0x00e5a5aa}, /* U+596A */ - {0x00c3a6, 0x00e884b1}, /* U+8131 */ - {0x00c3a7, 0x00e5b7bd}, /* U+5DFD */ - {0x00c3a8, 0x00e7abaa}, /* U+7AEA */ - {0x00c3a9, 0x00e8bebf}, /* U+8FBF */ - {0x00c3aa, 0x00e6a39a}, /* U+68DA */ - {0x00c3ab, 0x00e8b0b7}, /* U+8C37 */ - {0x00c3ac, 0x00e78bb8}, /* U+72F8 */ - {0x00c3ad, 0x00e9b188}, /* U+9C48 */ - {0x00c3ae, 0x00e6a8bd}, /* U+6A3D */ - {0x00c3af, 0x00e8aab0}, /* U+8AB0 */ - {0x00c3b0, 0x00e4b8b9}, /* U+4E39 */ - {0x00c3b1, 0x00e58d98}, /* U+5358 */ - {0x00c3b2, 0x00e59886}, /* U+5606 */ - {0x00c3b3, 0x00e59da6}, /* U+5766 */ - {0x00c3b4, 0x00e68b85}, /* U+62C5 */ - {0x00c3b5, 0x00e68ea2}, /* U+63A2 */ - {0x00c3b6, 0x00e697a6}, /* U+65E6 */ - {0x00c3b7, 0x00e6ad8e}, /* U+6B4E */ - {0x00c3b8, 0x00e6b7a1}, /* U+6DE1 */ - {0x00c3b9, 0x00e6b99b}, /* U+6E5B */ - {0x00c3ba, 0x00e782ad}, /* U+70AD */ - {0x00c3bb, 0x00e79fad}, /* U+77ED */ - {0x00c3bc, 0x00e7abaf}, /* U+7AEF */ - {0x00c3bd, 0x00e7aeaa}, /* U+7BAA */ - {0x00c3be, 0x00e7b6bb}, /* U+7DBB */ - {0x00c3bf, 0x00e880bd}, /* U+803D */ - {0x00c3c0, 0x00e88386}, /* U+80C6 */ - {0x00c3c1, 0x00e89b8b}, /* U+86CB */ - {0x00c3c2, 0x00e8aa95}, /* U+8A95 */ - {0x00c3c3, 0x00e98d9b}, /* U+935B */ - {0x00c3c4, 0x00e59ba3}, /* U+56E3 */ - {0x00c3c5, 0x00e5a387}, /* U+58C7 */ - {0x00c3c6, 0x00e5bcbe}, /* U+5F3E */ - {0x00c3c7, 0x00e696ad}, /* U+65AD */ - {0x00c3c8, 0x00e69a96}, /* U+6696 */ - {0x00c3c9, 0x00e6aa80}, /* U+6A80 */ - {0x00c3ca, 0x00e6aeb5}, /* U+6BB5 */ - {0x00c3cb, 0x00e794b7}, /* U+7537 */ - {0x00c3cc, 0x00e8ab87}, /* U+8AC7 */ - {0x00c3cd, 0x00e580a4}, /* U+5024 */ - {0x00c3ce, 0x00e79fa5}, /* U+77E5 */ - {0x00c3cf, 0x00e59cb0}, /* U+5730 */ - {0x00c3d0, 0x00e5bc9b}, /* U+5F1B */ - {0x00c3d1, 0x00e681a5}, /* U+6065 */ - {0x00c3d2, 0x00e699ba}, /* U+667A */ - {0x00c3d3, 0x00e6b1a0}, /* U+6C60 */ - {0x00c3d4, 0x00e797b4}, /* U+75F4 */ - {0x00c3d5, 0x00e7a89a}, /* U+7A1A */ - {0x00c3d6, 0x00e7bdae}, /* U+7F6E */ - {0x00c3d7, 0x00e887b4}, /* U+81F4 */ - {0x00c3d8, 0x00e89c98}, /* U+8718 */ - {0x00c3d9, 0x00e98185}, /* U+9045 */ - {0x00c3da, 0x00e9a6b3}, /* U+99B3 */ - {0x00c3db, 0x00e7af89}, /* U+7BC9 */ - {0x00c3dc, 0x00e7959c}, /* U+755C */ - {0x00c3dd, 0x00e7abb9}, /* U+7AF9 */ - {0x00c3de, 0x00e7ad91}, /* U+7B51 */ - {0x00c3df, 0x00e89384}, /* U+84C4 */ - {0x00c3e0, 0x00e98090}, /* U+9010 */ - {0x00c3e1, 0x00e7a7a9}, /* U+79E9 */ - {0x00c3e2, 0x00e7aa92}, /* U+7A92 */ - {0x00c3e3, 0x00e88cb6}, /* U+8336 */ - {0x00c3e4, 0x00e5aba1}, /* U+5AE1 */ - {0x00c3e5, 0x00e79d80}, /* U+7740 */ - {0x00c3e6, 0x00e4b8ad}, /* U+4E2D */ - {0x00c3e7, 0x00e4bbb2}, /* U+4EF2 */ - {0x00c3e8, 0x00e5ae99}, /* U+5B99 */ - {0x00c3e9, 0x00e5bfa0}, /* U+5FE0 */ - {0x00c3ea, 0x00e68abd}, /* U+62BD */ - {0x00c3eb, 0x00e698bc}, /* U+663C */ - {0x00c3ec, 0x00e69fb1}, /* U+67F1 */ - {0x00c3ed, 0x00e6b3a8}, /* U+6CE8 */ - {0x00c3ee, 0x00e899ab}, /* U+866B */ - {0x00c3ef, 0x00e8a1b7}, /* U+8877 */ - {0x00c3f0, 0x00e8a8bb}, /* U+8A3B */ - {0x00c3f1, 0x00e9858e}, /* U+914E */ - {0x00c3f2, 0x00e98bb3}, /* U+92F3 */ - {0x00c3f3, 0x00e9a790}, /* U+99D0 */ - {0x00c3f4, 0x00e6a897}, /* U+6A17 */ - {0x00c3f5, 0x00e780a6}, /* U+7026 */ - {0x00c3f6, 0x00e78caa}, /* U+732A */ - {0x00c3f7, 0x00e88ba7}, /* U+82E7 */ - {0x00c3f8, 0x00e89197}, /* U+8457 */ - {0x00c3f9, 0x00e8b2af}, /* U+8CAF */ - {0x00c3fa, 0x00e4b881}, /* U+4E01 */ - {0x00c3fb, 0x00e58586}, /* U+5146 */ - {0x00c3fc, 0x00e5878b}, /* U+51CB */ - {0x00c3fd, 0x00e5968b}, /* U+558B */ - {0x00c3fe, 0x00e5afb5}, /* U+5BF5 */ - {0x00c4a1, 0x00e5b896}, /* U+5E16 */ - {0x00c4a2, 0x00e5b8b3}, /* U+5E33 */ - {0x00c4a3, 0x00e5ba81}, /* U+5E81 */ - {0x00c4a4, 0x00e5bc94}, /* U+5F14 */ - {0x00c4a5, 0x00e5bcb5}, /* U+5F35 */ - {0x00c4a6, 0x00e5bdab}, /* U+5F6B */ - {0x00c4a7, 0x00e5beb4}, /* U+5FB4 */ - {0x00c4a8, 0x00e687b2}, /* U+61F2 */ - {0x00c4a9, 0x00e68c91}, /* U+6311 */ - {0x00c4aa, 0x00e69aa2}, /* U+66A2 */ - {0x00c4ab, 0x00e69c9d}, /* U+671D */ - {0x00c4ac, 0x00e6bdae}, /* U+6F6E */ - {0x00c4ad, 0x00e78992}, /* U+7252 */ - {0x00c4ae, 0x00e794ba}, /* U+753A */ - {0x00c4af, 0x00e79cba}, /* U+773A */ - {0x00c4b0, 0x00e881b4}, /* U+8074 */ - {0x00c4b1, 0x00e884b9}, /* U+8139 */ - {0x00c4b2, 0x00e885b8}, /* U+8178 */ - {0x00c4b3, 0x00e89db6}, /* U+8776 */ - {0x00c4b4, 0x00e8aabf}, /* U+8ABF */ - {0x00c4b5, 0x00e8ab9c}, /* U+8ADC */ - {0x00c4b6, 0x00e8b685}, /* U+8D85 */ - {0x00c4b7, 0x00e8b7b3}, /* U+8DF3 */ - {0x00c4b8, 0x00e98a9a}, /* U+929A */ - {0x00c4b9, 0x00e995b7}, /* U+9577 */ - {0x00c4ba, 0x00e9a082}, /* U+9802 */ - {0x00c4bb, 0x00e9b3a5}, /* U+9CE5 */ - {0x00c4bc, 0x00e58b85}, /* U+52C5 */ - {0x00c4bd, 0x00e68d97}, /* U+6357 */ - {0x00c4be, 0x00e79bb4}, /* U+76F4 */ - {0x00c4bf, 0x00e69c95}, /* U+6715 */ - {0x00c4c0, 0x00e6b288}, /* U+6C88 */ - {0x00c4c1, 0x00e78f8d}, /* U+73CD */ - {0x00c4c2, 0x00e8b383}, /* U+8CC3 */ - {0x00c4c3, 0x00e98eae}, /* U+93AE */ - {0x00c4c4, 0x00e999b3}, /* U+9673 */ - {0x00c4c5, 0x00e6b4a5}, /* U+6D25 */ - {0x00c4c6, 0x00e5a29c}, /* U+589C */ - {0x00c4c7, 0x00e6a48e}, /* U+690E */ - {0x00c4c8, 0x00e6a78c}, /* U+69CC */ - {0x00c4c9, 0x00e8bfbd}, /* U+8FFD */ - {0x00c4ca, 0x00e98e9a}, /* U+939A */ - {0x00c4cb, 0x00e7979b}, /* U+75DB */ - {0x00c4cc, 0x00e9809a}, /* U+901A */ - {0x00c4cd, 0x00e5a19a}, /* U+585A */ - {0x00c4ce, 0x00e6a082}, /* U+6802 */ - {0x00c4cf, 0x00e68eb4}, /* U+63B4 */ - {0x00c4d0, 0x00e6a7bb}, /* U+69FB */ - {0x00c4d1, 0x00e4bd83}, /* U+4F43 */ - {0x00c4d2, 0x00e6bcac}, /* U+6F2C */ - {0x00c4d3, 0x00e69f98}, /* U+67D8 */ - {0x00c4d4, 0x00e8bebb}, /* U+8FBB */ - {0x00c4d5, 0x00e894a6}, /* U+8526 */ - {0x00c4d6, 0x00e7b6b4}, /* U+7DB4 */ - {0x00c4d7, 0x00e98d94}, /* U+9354 */ - {0x00c4d8, 0x00e6a4bf}, /* U+693F */ - {0x00c4d9, 0x00e6bdb0}, /* U+6F70 */ - {0x00c4da, 0x00e59daa}, /* U+576A */ - {0x00c4db, 0x00e5a3b7}, /* U+58F7 */ - {0x00c4dc, 0x00e5acac}, /* U+5B2C */ - {0x00c4dd, 0x00e7b4ac}, /* U+7D2C */ - {0x00c4de, 0x00e788aa}, /* U+722A */ - {0x00c4df, 0x00e5908a}, /* U+540A */ - {0x00c4e0, 0x00e987a3}, /* U+91E3 */ - {0x00c4e1, 0x00e9b6b4}, /* U+9DB4 */ - {0x00c4e2, 0x00e4baad}, /* U+4EAD */ - {0x00c4e3, 0x00e4bd8e}, /* U+4F4E */ - {0x00c4e4, 0x00e5819c}, /* U+505C */ - {0x00c4e5, 0x00e581b5}, /* U+5075 */ - {0x00c4e6, 0x00e58983}, /* U+5243 */ - {0x00c4e7, 0x00e8b29e}, /* U+8C9E */ - {0x00c4e8, 0x00e59188}, /* U+5448 */ - {0x00c4e9, 0x00e5a0a4}, /* U+5824 */ - {0x00c4ea, 0x00e5ae9a}, /* U+5B9A */ - {0x00c4eb, 0x00e5b89d}, /* U+5E1D */ - {0x00c4ec, 0x00e5ba95}, /* U+5E95 */ - {0x00c4ed, 0x00e5baad}, /* U+5EAD */ - {0x00c4ee, 0x00e5bbb7}, /* U+5EF7 */ - {0x00c4ef, 0x00e5bc9f}, /* U+5F1F */ - {0x00c4f0, 0x00e6828c}, /* U+608C */ - {0x00c4f1, 0x00e68ab5}, /* U+62B5 */ - {0x00c4f2, 0x00e68cba}, /* U+633A */ - {0x00c4f3, 0x00e68f90}, /* U+63D0 */ - {0x00c4f4, 0x00e6a2af}, /* U+68AF */ - {0x00c4f5, 0x00e6b180}, /* U+6C40 */ - {0x00c4f6, 0x00e7a287}, /* U+7887 */ - {0x00c4f7, 0x00e7a68e}, /* U+798E */ - {0x00c4f8, 0x00e7a88b}, /* U+7A0B */ - {0x00c4f9, 0x00e7b7a0}, /* U+7DE0 */ - {0x00c4fa, 0x00e88987}, /* U+8247 */ - {0x00c4fb, 0x00e8a882}, /* U+8A02 */ - {0x00c4fc, 0x00e8aba6}, /* U+8AE6 */ - {0x00c4fd, 0x00e8b984}, /* U+8E44 */ - {0x00c4fe, 0x00e98093}, /* U+9013 */ - {0x00c5a1, 0x00e982b8}, /* U+90B8 */ - {0x00c5a2, 0x00e984ad}, /* U+912D */ - {0x00c5a3, 0x00e98798}, /* U+91D8 */ - {0x00c5a4, 0x00e9bc8e}, /* U+9F0E */ - {0x00c5a5, 0x00e6b3a5}, /* U+6CE5 */ - {0x00c5a6, 0x00e69198}, /* U+6458 */ - {0x00c5a7, 0x00e693a2}, /* U+64E2 */ - {0x00c5a8, 0x00e695b5}, /* U+6575 */ - {0x00c5a9, 0x00e6bbb4}, /* U+6EF4 */ - {0x00c5aa, 0x00e79a84}, /* U+7684 */ - {0x00c5ab, 0x00e7ac9b}, /* U+7B1B */ - {0x00c5ac, 0x00e981a9}, /* U+9069 */ - {0x00c5ad, 0x00e98f91}, /* U+93D1 */ - {0x00c5ae, 0x00e6baba}, /* U+6EBA */ - {0x00c5af, 0x00e593b2}, /* U+54F2 */ - {0x00c5b0, 0x00e5beb9}, /* U+5FB9 */ - {0x00c5b1, 0x00e692a4}, /* U+64A4 */ - {0x00c5b2, 0x00e8bd8d}, /* U+8F4D */ - {0x00c5b3, 0x00e8bfad}, /* U+8FED */ - {0x00c5b4, 0x00e98984}, /* U+9244 */ - {0x00c5b5, 0x00e585b8}, /* U+5178 */ - {0x00c5b6, 0x00e5a1ab}, /* U+586B */ - {0x00c5b7, 0x00e5a4a9}, /* U+5929 */ - {0x00c5b8, 0x00e5b195}, /* U+5C55 */ - {0x00c5b9, 0x00e5ba97}, /* U+5E97 */ - {0x00c5ba, 0x00e6b7bb}, /* U+6DFB */ - {0x00c5bb, 0x00e7ba8f}, /* U+7E8F */ - {0x00c5bc, 0x00e7949c}, /* U+751C */ - {0x00c5bd, 0x00e8b2bc}, /* U+8CBC */ - {0x00c5be, 0x00e8bba2}, /* U+8EE2 */ - {0x00c5bf, 0x00e9a19b}, /* U+985B */ - {0x00c5c0, 0x00e782b9}, /* U+70B9 */ - {0x00c5c1, 0x00e4bc9d}, /* U+4F1D */ - {0x00c5c2, 0x00e6aebf}, /* U+6BBF */ - {0x00c5c3, 0x00e6beb1}, /* U+6FB1 */ - {0x00c5c4, 0x00e794b0}, /* U+7530 */ - {0x00c5c5, 0x00e99bbb}, /* U+96FB */ - {0x00c5c6, 0x00e5858e}, /* U+514E */ - {0x00c5c7, 0x00e59090}, /* U+5410 */ - {0x00c5c8, 0x00e5a0b5}, /* U+5835 */ - {0x00c5c9, 0x00e5a197}, /* U+5857 */ - {0x00c5ca, 0x00e5a6ac}, /* U+59AC */ - {0x00c5cb, 0x00e5b1a0}, /* U+5C60 */ - {0x00c5cc, 0x00e5be92}, /* U+5F92 */ - {0x00c5cd, 0x00e69697}, /* U+6597 */ - {0x00c5ce, 0x00e69d9c}, /* U+675C */ - {0x00c5cf, 0x00e6b8a1}, /* U+6E21 */ - {0x00c5d0, 0x00e799bb}, /* U+767B */ - {0x00c5d1, 0x00e88f9f}, /* U+83DF */ - {0x00c5d2, 0x00e8b3ad}, /* U+8CED */ - {0x00c5d3, 0x00e98094}, /* U+9014 */ - {0x00c5d4, 0x00e983bd}, /* U+90FD */ - {0x00c5d5, 0x00e98d8d}, /* U+934D */ - {0x00c5d6, 0x00e7a0a5}, /* U+7825 */ - {0x00c5d7, 0x00e7a0ba}, /* U+783A */ - {0x00c5d8, 0x00e58aaa}, /* U+52AA */ - {0x00c5d9, 0x00e5baa6}, /* U+5EA6 */ - {0x00c5da, 0x00e59c9f}, /* U+571F */ - {0x00c5db, 0x00e5a5b4}, /* U+5974 */ - {0x00c5dc, 0x00e68092}, /* U+6012 */ - {0x00c5dd, 0x00e58092}, /* U+5012 */ - {0x00c5de, 0x00e5859a}, /* U+515A */ - {0x00c5df, 0x00e586ac}, /* U+51AC */ - {0x00c5e0, 0x00e5878d}, /* U+51CD */ - {0x00c5e1, 0x00e58880}, /* U+5200 */ - {0x00c5e2, 0x00e59490}, /* U+5510 */ - {0x00c5e3, 0x00e5a194}, /* U+5854 */ - {0x00c5e4, 0x00e5a198}, /* U+5858 */ - {0x00c5e5, 0x00e5a597}, /* U+5957 */ - {0x00c5e6, 0x00e5ae95}, /* U+5B95 */ - {0x00c5e7, 0x00e5b3b6}, /* U+5CF6 */ - {0x00c5e8, 0x00e5b68b}, /* U+5D8B */ - {0x00c5e9, 0x00e682bc}, /* U+60BC */ - {0x00c5ea, 0x00e68a95}, /* U+6295 */ - {0x00c5eb, 0x00e690ad}, /* U+642D */ - {0x00c5ec, 0x00e69db1}, /* U+6771 */ - {0x00c5ed, 0x00e6a183}, /* U+6843 */ - {0x00c5ee, 0x00e6a2bc}, /* U+68BC */ - {0x00c5ef, 0x00e6a39f}, /* U+68DF */ - {0x00c5f0, 0x00e79b97}, /* U+76D7 */ - {0x00c5f1, 0x00e6b798}, /* U+6DD8 */ - {0x00c5f2, 0x00e6b9af}, /* U+6E6F */ - {0x00c5f3, 0x00e6b69b}, /* U+6D9B */ - {0x00c5f4, 0x00e781af}, /* U+706F */ - {0x00c5f5, 0x00e78788}, /* U+71C8 */ - {0x00c5f6, 0x00e5bd93}, /* U+5F53 */ - {0x00c5f7, 0x00e79798}, /* U+75D8 */ - {0x00c5f8, 0x00e7a5b7}, /* U+7977 */ - {0x00c5f9, 0x00e7ad89}, /* U+7B49 */ - {0x00c5fa, 0x00e7ad94}, /* U+7B54 */ - {0x00c5fb, 0x00e7ad92}, /* U+7B52 */ - {0x00c5fc, 0x00e7b396}, /* U+7CD6 */ - {0x00c5fd, 0x00e7b5b1}, /* U+7D71 */ - {0x00c5fe, 0x00e588b0}, /* U+5230 */ - {0x00c6a1, 0x00e891a3}, /* U+8463 */ - {0x00c6a2, 0x00e895a9}, /* U+8569 */ - {0x00c6a3, 0x00e897a4}, /* U+85E4 */ - {0x00c6a4, 0x00e8a88e}, /* U+8A0E */ - {0x00c6a5, 0x00e8ac84}, /* U+8B04 */ - {0x00c6a6, 0x00e8b186}, /* U+8C46 */ - {0x00c6a7, 0x00e8b88f}, /* U+8E0F */ - {0x00c6a8, 0x00e98083}, /* U+9003 */ - {0x00c6a9, 0x00e9808f}, /* U+900F */ - {0x00c6aa, 0x00e99099}, /* U+9419 */ - {0x00c6ab, 0x00e999b6}, /* U+9676 */ - {0x00c6ac, 0x00e9a0ad}, /* U+982D */ - {0x00c6ad, 0x00e9a8b0}, /* U+9A30 */ - {0x00c6ae, 0x00e99798}, /* U+95D8 */ - {0x00c6af, 0x00e5838d}, /* U+50CD */ - {0x00c6b0, 0x00e58b95}, /* U+52D5 */ - {0x00c6b1, 0x00e5908c}, /* U+540C */ - {0x00c6b2, 0x00e5a082}, /* U+5802 */ - {0x00c6b3, 0x00e5b08e}, /* U+5C0E */ - {0x00c6b4, 0x00e686a7}, /* U+61A7 */ - {0x00c6b5, 0x00e6929e}, /* U+649E */ - {0x00c6b6, 0x00e6b49e}, /* U+6D1E */ - {0x00c6b7, 0x00e79eb3}, /* U+77B3 */ - {0x00c6b8, 0x00e7aba5}, /* U+7AE5 */ - {0x00c6b9, 0x00e883b4}, /* U+80F4 */ - {0x00c6ba, 0x00e89084}, /* U+8404 */ - {0x00c6bb, 0x00e98193}, /* U+9053 */ - {0x00c6bc, 0x00e98a85}, /* U+9285 */ - {0x00c6bd, 0x00e5b3a0}, /* U+5CE0 */ - {0x00c6be, 0x00e9b487}, /* U+9D07 */ - {0x00c6bf, 0x00e58cbf}, /* U+533F */ - {0x00c6c0, 0x00e5be97}, /* U+5F97 */ - {0x00c6c1, 0x00e5beb3}, /* U+5FB3 */ - {0x00c6c2, 0x00e6b69c}, /* U+6D9C */ - {0x00c6c3, 0x00e789b9}, /* U+7279 */ - {0x00c6c4, 0x00e79da3}, /* U+7763 */ - {0x00c6c5, 0x00e7a6bf}, /* U+79BF */ - {0x00c6c6, 0x00e7afa4}, /* U+7BE4 */ - {0x00c6c7, 0x00e6af92}, /* U+6BD2 */ - {0x00c6c8, 0x00e78bac}, /* U+72EC */ - {0x00c6c9, 0x00e8aaad}, /* U+8AAD */ - {0x00c6ca, 0x00e6a083}, /* U+6803 */ - {0x00c6cb, 0x00e6a9a1}, /* U+6A61 */ - {0x00c6cc, 0x00e587b8}, /* U+51F8 */ - {0x00c6cd, 0x00e7aa81}, /* U+7A81 */ - {0x00c6ce, 0x00e6a4b4}, /* U+6934 */ - {0x00c6cf, 0x00e5b18a}, /* U+5C4A */ - {0x00c6d0, 0x00e9b3b6}, /* U+9CF6 */ - {0x00c6d1, 0x00e88bab}, /* U+82EB */ - {0x00c6d2, 0x00e5af85}, /* U+5BC5 */ - {0x00c6d3, 0x00e98589}, /* U+9149 */ - {0x00c6d4, 0x00e7809e}, /* U+701E */ - {0x00c6d5, 0x00e599b8}, /* U+5678 */ - {0x00c6d6, 0x00e5b1af}, /* U+5C6F */ - {0x00c6d7, 0x00e68387}, /* U+60C7 */ - {0x00c6d8, 0x00e695a6}, /* U+6566 */ - {0x00c6d9, 0x00e6b28c}, /* U+6C8C */ - {0x00c6da, 0x00e8b19a}, /* U+8C5A */ - {0x00c6db, 0x00e98181}, /* U+9041 */ - {0x00c6dc, 0x00e9a093}, /* U+9813 */ - {0x00c6dd, 0x00e59191}, /* U+5451 */ - {0x00c6de, 0x00e69b87}, /* U+66C7 */ - {0x00c6df, 0x00e9888d}, /* U+920D */ - {0x00c6e0, 0x00e5a588}, /* U+5948 */ - {0x00c6e1, 0x00e982a3}, /* U+90A3 */ - {0x00c6e2, 0x00e58685}, /* U+5185 */ - {0x00c6e3, 0x00e4b98d}, /* U+4E4D */ - {0x00c6e4, 0x00e587aa}, /* U+51EA */ - {0x00c6e5, 0x00e89699}, /* U+8599 */ - {0x00c6e6, 0x00e8ac8e}, /* U+8B0E */ - {0x00c6e7, 0x00e78198}, /* U+7058 */ - {0x00c6e8, 0x00e68dba}, /* U+637A */ - {0x00c6e9, 0x00e98d8b}, /* U+934B */ - {0x00c6ea, 0x00e6a5a2}, /* U+6962 */ - {0x00c6eb, 0x00e9a6b4}, /* U+99B4 */ - {0x00c6ec, 0x00e7b884}, /* U+7E04 */ - {0x00c6ed, 0x00e795b7}, /* U+7577 */ - {0x00c6ee, 0x00e58d97}, /* U+5357 */ - {0x00c6ef, 0x00e6a5a0}, /* U+6960 */ - {0x00c6f0, 0x00e8bb9f}, /* U+8EDF */ - {0x00c6f1, 0x00e99ba3}, /* U+96E3 */ - {0x00c6f2, 0x00e6b19d}, /* U+6C5D */ - {0x00c6f3, 0x00e4ba8c}, /* U+4E8C */ - {0x00c6f4, 0x00e5b0bc}, /* U+5C3C */ - {0x00c6f5, 0x00e5bc90}, /* U+5F10 */ - {0x00c6f6, 0x00e8bfa9}, /* U+8FE9 */ - {0x00c6f7, 0x00e58c82}, /* U+5302 */ - {0x00c6f8, 0x00e8b391}, /* U+8CD1 */ - {0x00c6f9, 0x00e88289}, /* U+8089 */ - {0x00c6fa, 0x00e899b9}, /* U+8679 */ - {0x00c6fb, 0x00e5bbbf}, /* U+5EFF */ - {0x00c6fc, 0x00e697a5}, /* U+65E5 */ - {0x00c6fd, 0x00e4b9b3}, /* U+4E73 */ - {0x00c6fe, 0x00e585a5}, /* U+5165 */ - {0x00c7a1, 0x00e5a682}, /* U+5982 */ - {0x00c7a2, 0x00e5b0bf}, /* U+5C3F */ - {0x00c7a3, 0x00e99fae}, /* U+97EE */ - {0x00c7a4, 0x00e4bbbb}, /* U+4EFB */ - {0x00c7a5, 0x00e5a68a}, /* U+598A */ - {0x00c7a6, 0x00e5bf8d}, /* U+5FCD */ - {0x00c7a7, 0x00e8aa8d}, /* U+8A8D */ - {0x00c7a8, 0x00e6bfa1}, /* U+6FE1 */ - {0x00c7a9, 0x00e7a6b0}, /* U+79B0 */ - {0x00c7aa, 0x00e7a5a2}, /* U+7962 */ - {0x00c7ab, 0x00e5afa7}, /* U+5BE7 */ - {0x00c7ac, 0x00e891b1}, /* U+8471 */ - {0x00c7ad, 0x00e78cab}, /* U+732B */ - {0x00c7ae, 0x00e786b1}, /* U+71B1 */ - {0x00c7af, 0x00e5b9b4}, /* U+5E74 */ - {0x00c7b0, 0x00e5bfb5}, /* U+5FF5 */ - {0x00c7b1, 0x00e68dbb}, /* U+637B */ - {0x00c7b2, 0x00e6929a}, /* U+649A */ - {0x00c7b3, 0x00e78783}, /* U+71C3 */ - {0x00c7b4, 0x00e7b298}, /* U+7C98 */ - {0x00c7b5, 0x00e4b983}, /* U+4E43 */ - {0x00c7b6, 0x00e5bbbc}, /* U+5EFC */ - {0x00c7b7, 0x00e4b98b}, /* U+4E4B */ - {0x00c7b8, 0x00e59f9c}, /* U+57DC */ - {0x00c7b9, 0x00e59aa2}, /* U+56A2 */ - {0x00c7ba, 0x00e682a9}, /* U+60A9 */ - {0x00c7bb, 0x00e6bf83}, /* U+6FC3 */ - {0x00c7bc, 0x00e7b48d}, /* U+7D0D */ - {0x00c7bd, 0x00e883bd}, /* U+80FD */ - {0x00c7be, 0x00e884b3}, /* U+8133 */ - {0x00c7bf, 0x00e886bf}, /* U+81BF */ - {0x00c7c0, 0x00e8beb2}, /* U+8FB2 */ - {0x00c7c1, 0x00e8a697}, /* U+8997 */ - {0x00c7c2, 0x00e89aa4}, /* U+86A4 */ - {0x00c7c3, 0x00e5b7b4}, /* U+5DF4 */ - {0x00c7c4, 0x00e68a8a}, /* U+628A */ - {0x00c7c5, 0x00e692ad}, /* U+64AD */ - {0x00c7c6, 0x00e8a687}, /* U+8987 */ - {0x00c7c7, 0x00e69db7}, /* U+6777 */ - {0x00c7c8, 0x00e6b3a2}, /* U+6CE2 */ - {0x00c7c9, 0x00e6b4be}, /* U+6D3E */ - {0x00c7ca, 0x00e790b6}, /* U+7436 */ - {0x00c7cb, 0x00e7a0b4}, /* U+7834 */ - {0x00c7cc, 0x00e5a986}, /* U+5A46 */ - {0x00c7cd, 0x00e7bdb5}, /* U+7F75 */ - {0x00c7ce, 0x00e88aad}, /* U+82AD */ - {0x00c7cf, 0x00e9a6ac}, /* U+99AC */ - {0x00c7d0, 0x00e4bfb3}, /* U+4FF3 */ - {0x00c7d1, 0x00e5bb83}, /* U+5EC3 */ - {0x00c7d2, 0x00e68b9d}, /* U+62DD */ - {0x00c7d3, 0x00e68e92}, /* U+6392 */ - {0x00c7d4, 0x00e69597}, /* U+6557 */ - {0x00c7d5, 0x00e69daf}, /* U+676F */ - {0x00c7d6, 0x00e79b83}, /* U+76C3 */ - {0x00c7d7, 0x00e7898c}, /* U+724C */ - {0x00c7d8, 0x00e8838c}, /* U+80CC */ - {0x00c7d9, 0x00e882ba}, /* U+80BA */ - {0x00c7da, 0x00e8bca9}, /* U+8F29 */ - {0x00c7db, 0x00e9858d}, /* U+914D */ - {0x00c7dc, 0x00e5808d}, /* U+500D */ - {0x00c7dd, 0x00e59fb9}, /* U+57F9 */ - {0x00c7de, 0x00e5aa92}, /* U+5A92 */ - {0x00c7df, 0x00e6a285}, /* U+6885 */ - {0x00c7e0, 0x00e6a5b3}, /* U+6973 */ - {0x00c7e1, 0x00e785a4}, /* U+7164 */ - {0x00c7e2, 0x00e78bbd}, /* U+72FD */ - {0x00c7e3, 0x00e8b2b7}, /* U+8CB7 */ - {0x00c7e4, 0x00e5a3b2}, /* U+58F2 */ - {0x00c7e5, 0x00e8b3a0}, /* U+8CE0 */ - {0x00c7e6, 0x00e999aa}, /* U+966A */ - {0x00c7e7, 0x00e98099}, /* U+9019 */ - {0x00c7e8, 0x00e89dbf}, /* U+877F */ - {0x00c7e9, 0x00e7a7a4}, /* U+79E4 */ - {0x00c7ea, 0x00e79fa7}, /* U+77E7 */ - {0x00c7eb, 0x00e890a9}, /* U+8429 */ - {0x00c7ec, 0x00e4bcaf}, /* U+4F2F */ - {0x00c7ed, 0x00e589a5}, /* U+5265 */ - {0x00c7ee, 0x00e58d9a}, /* U+535A */ - {0x00c7ef, 0x00e68b8d}, /* U+62CD */ - {0x00c7f0, 0x00e69f8f}, /* U+67CF */ - {0x00c7f1, 0x00e6b38a}, /* U+6CCA */ - {0x00c7f2, 0x00e799bd}, /* U+767D */ - {0x00c7f3, 0x00e7ae94}, /* U+7B94 */ - {0x00c7f4, 0x00e7b295}, /* U+7C95 */ - {0x00c7f5, 0x00e888b6}, /* U+8236 */ - {0x00c7f6, 0x00e89684}, /* U+8584 */ - {0x00c7f7, 0x00e8bfab}, /* U+8FEB */ - {0x00c7f8, 0x00e69b9d}, /* U+66DD */ - {0x00c7f9, 0x00e6bca0}, /* U+6F20 */ - {0x00c7fa, 0x00e78886}, /* U+7206 */ - {0x00c7fb, 0x00e7b89b}, /* U+7E1B */ - {0x00c7fc, 0x00e88eab}, /* U+83AB */ - {0x00c7fd, 0x00e9a781}, /* U+99C1 */ - {0x00c7fe, 0x00e9baa6}, /* U+9EA6 */ - {0x00c8a1, 0x00e587bd}, /* U+51FD */ - {0x00c8a2, 0x00e7aeb1}, /* U+7BB1 */ - {0x00c8a3, 0x00e7a1b2}, /* U+7872 */ - {0x00c8a4, 0x00e7aeb8}, /* U+7BB8 */ - {0x00c8a5, 0x00e88287}, /* U+8087 */ - {0x00c8a6, 0x00e7ad88}, /* U+7B48 */ - {0x00c8a7, 0x00e6aba8}, /* U+6AE8 */ - {0x00c8a8, 0x00e5b9a1}, /* U+5E61 */ - {0x00c8a9, 0x00e8828c}, /* U+808C */ - {0x00c8aa, 0x00e79591}, /* U+7551 */ - {0x00c8ab, 0x00e795a0}, /* U+7560 */ - {0x00c8ac, 0x00e585ab}, /* U+516B */ - {0x00c8ad, 0x00e989a2}, /* U+9262 */ - {0x00c8ae, 0x00e6ba8c}, /* U+6E8C */ - {0x00c8af, 0x00e799ba}, /* U+767A */ - {0x00c8b0, 0x00e98697}, /* U+9197 */ - {0x00c8b1, 0x00e9abaa}, /* U+9AEA */ - {0x00c8b2, 0x00e4bc90}, /* U+4F10 */ - {0x00c8b3, 0x00e7bdb0}, /* U+7F70 */ - {0x00c8b4, 0x00e68a9c}, /* U+629C */ - {0x00c8b5, 0x00e7ad8f}, /* U+7B4F */ - {0x00c8b6, 0x00e996a5}, /* U+95A5 */ - {0x00c8b7, 0x00e9b3a9}, /* U+9CE9 */ - {0x00c8b8, 0x00e599ba}, /* U+567A */ - {0x00c8b9, 0x00e5a199}, /* U+5859 */ - {0x00c8ba, 0x00e89ba4}, /* U+86E4 */ - {0x00c8bb, 0x00e99abc}, /* U+96BC */ - {0x00c8bc, 0x00e4bcb4}, /* U+4F34 */ - {0x00c8bd, 0x00e588a4}, /* U+5224 */ - {0x00c8be, 0x00e58d8a}, /* U+534A */ - {0x00c8bf, 0x00e58f8d}, /* U+53CD */ - {0x00c8c0, 0x00e58f9b}, /* U+53DB */ - {0x00c8c1, 0x00e5b886}, /* U+5E06 */ - {0x00c8c2, 0x00e690ac}, /* U+642C */ - {0x00c8c3, 0x00e69691}, /* U+6591 */ - {0x00c8c4, 0x00e69dbf}, /* U+677F */ - {0x00c8c5, 0x00e6b0be}, /* U+6C3E */ - {0x00c8c6, 0x00e6b18e}, /* U+6C4E */ - {0x00c8c7, 0x00e78988}, /* U+7248 */ - {0x00c8c8, 0x00e78aaf}, /* U+72AF */ - {0x00c8c9, 0x00e78fad}, /* U+73ED */ - {0x00c8ca, 0x00e79594}, /* U+7554 */ - {0x00c8cb, 0x00e7b981}, /* U+7E41 */ - {0x00c8cc, 0x00e888ac}, /* U+822C */ - {0x00c8cd, 0x00e897a9}, /* U+85E9 */ - {0x00c8ce, 0x00e8b2a9}, /* U+8CA9 */ - {0x00c8cf, 0x00e7af84}, /* U+7BC4 */ - {0x00c8d0, 0x00e98786}, /* U+91C6 */ - {0x00c8d1, 0x00e785a9}, /* U+7169 */ - {0x00c8d2, 0x00e9a092}, /* U+9812 */ - {0x00c8d3, 0x00e9a3af}, /* U+98EF */ - {0x00c8d4, 0x00e68cbd}, /* U+633D */ - {0x00c8d5, 0x00e699a9}, /* U+6669 */ - {0x00c8d6, 0x00e795aa}, /* U+756A */ - {0x00c8d7, 0x00e79ba4}, /* U+76E4 */ - {0x00c8d8, 0x00e7a390}, /* U+78D0 */ - {0x00c8d9, 0x00e89583}, /* U+8543 */ - {0x00c8da, 0x00e89bae}, /* U+86EE */ - {0x00c8db, 0x00e58caa}, /* U+532A */ - {0x00c8dc, 0x00e58d91}, /* U+5351 */ - {0x00c8dd, 0x00e590a6}, /* U+5426 */ - {0x00c8de, 0x00e5a683}, /* U+5983 */ - {0x00c8df, 0x00e5ba87}, /* U+5E87 */ - {0x00c8e0, 0x00e5bdbc}, /* U+5F7C */ - {0x00c8e1, 0x00e682b2}, /* U+60B2 */ - {0x00c8e2, 0x00e68989}, /* U+6249 */ - {0x00c8e3, 0x00e689b9}, /* U+6279 */ - {0x00c8e4, 0x00e68aab}, /* U+62AB */ - {0x00c8e5, 0x00e69690}, /* U+6590 */ - {0x00c8e6, 0x00e6af94}, /* U+6BD4 */ - {0x00c8e7, 0x00e6b38c}, /* U+6CCC */ - {0x00c8e8, 0x00e796b2}, /* U+75B2 */ - {0x00c8e9, 0x00e79aae}, /* U+76AE */ - {0x00c8ea, 0x00e7a291}, /* U+7891 */ - {0x00c8eb, 0x00e7a798}, /* U+79D8 */ - {0x00c8ec, 0x00e7b78b}, /* U+7DCB */ - {0x00c8ed, 0x00e7bdb7}, /* U+7F77 */ - {0x00c8ee, 0x00e882a5}, /* U+80A5 */ - {0x00c8ef, 0x00e8a2ab}, /* U+88AB */ - {0x00c8f0, 0x00e8aab9}, /* U+8AB9 */ - {0x00c8f1, 0x00e8b2bb}, /* U+8CBB */ - {0x00c8f2, 0x00e981bf}, /* U+907F */ - {0x00c8f3, 0x00e99d9e}, /* U+975E */ - {0x00c8f4, 0x00e9a39b}, /* U+98DB */ - {0x00c8f5, 0x00e6a88b}, /* U+6A0B */ - {0x00c8f6, 0x00e7b0b8}, /* U+7C38 */ - {0x00c8f7, 0x00e58299}, /* U+5099 */ - {0x00c8f8, 0x00e5b0be}, /* U+5C3E */ - {0x00c8f9, 0x00e5beae}, /* U+5FAE */ - {0x00c8fa, 0x00e69e87}, /* U+6787 */ - {0x00c8fb, 0x00e6af98}, /* U+6BD8 */ - {0x00c8fc, 0x00e790b5}, /* U+7435 */ - {0x00c8fd, 0x00e79c89}, /* U+7709 */ - {0x00c8fe, 0x00e7be8e}, /* U+7F8E */ - {0x00c9a1, 0x00e9bcbb}, /* U+9F3B */ - {0x00c9a2, 0x00e69f8a}, /* U+67CA */ - {0x00c9a3, 0x00e7a897}, /* U+7A17 */ - {0x00c9a4, 0x00e58cb9}, /* U+5339 */ - {0x00c9a5, 0x00e7968b}, /* U+758B */ - {0x00c9a6, 0x00e9abad}, /* U+9AED */ - {0x00c9a7, 0x00e5bda6}, /* U+5F66 */ - {0x00c9a8, 0x00e8869d}, /* U+819D */ - {0x00c9a9, 0x00e88fb1}, /* U+83F1 */ - {0x00c9aa, 0x00e88298}, /* U+8098 */ - {0x00c9ab, 0x00e5bcbc}, /* U+5F3C */ - {0x00c9ac, 0x00e5bf85}, /* U+5FC5 */ - {0x00c9ad, 0x00e795a2}, /* U+7562 */ - {0x00c9ae, 0x00e7ad86}, /* U+7B46 */ - {0x00c9af, 0x00e980bc}, /* U+903C */ - {0x00c9b0, 0x00e6a1a7}, /* U+6867 */ - {0x00c9b1, 0x00e5a7ab}, /* U+59EB */ - {0x00c9b2, 0x00e5aa9b}, /* U+5A9B */ - {0x00c9b3, 0x00e7b490}, /* U+7D10 */ - {0x00c9b4, 0x00e799be}, /* U+767E */ - {0x00c9b5, 0x00e8acac}, /* U+8B2C */ - {0x00c9b6, 0x00e4bfb5}, /* U+4FF5 */ - {0x00c9b7, 0x00e5bdaa}, /* U+5F6A */ - {0x00c9b8, 0x00e6a899}, /* U+6A19 */ - {0x00c9b9, 0x00e6b0b7}, /* U+6C37 */ - {0x00c9ba, 0x00e6bc82}, /* U+6F02 */ - {0x00c9bb, 0x00e793a2}, /* U+74E2 */ - {0x00c9bc, 0x00e7a5a8}, /* U+7968 */ - {0x00c9bd, 0x00e8a1a8}, /* U+8868 */ - {0x00c9be, 0x00e8a995}, /* U+8A55 */ - {0x00c9bf, 0x00e8b1b9}, /* U+8C79 */ - {0x00c9c0, 0x00e5bb9f}, /* U+5EDF */ - {0x00c9c1, 0x00e68f8f}, /* U+63CF */ - {0x00c9c2, 0x00e79785}, /* U+75C5 */ - {0x00c9c3, 0x00e7a792}, /* U+79D2 */ - {0x00c9c4, 0x00e88b97}, /* U+82D7 */ - {0x00c9c5, 0x00e98ca8}, /* U+9328 */ - {0x00c9c6, 0x00e98bb2}, /* U+92F2 */ - {0x00c9c7, 0x00e8929c}, /* U+849C */ - {0x00c9c8, 0x00e89bad}, /* U+86ED */ - {0x00c9c9, 0x00e9b0ad}, /* U+9C2D */ - {0x00c9ca, 0x00e59381}, /* U+54C1 */ - {0x00c9cb, 0x00e5bdac}, /* U+5F6C */ - {0x00c9cc, 0x00e6968c}, /* U+658C */ - {0x00c9cd, 0x00e6b59c}, /* U+6D5C */ - {0x00c9ce, 0x00e78095}, /* U+7015 */ - {0x00c9cf, 0x00e8b2a7}, /* U+8CA7 */ - {0x00c9d0, 0x00e8b393}, /* U+8CD3 */ - {0x00c9d1, 0x00e9a0bb}, /* U+983B */ - {0x00c9d2, 0x00e6958f}, /* U+654F */ - {0x00c9d3, 0x00e793b6}, /* U+74F6 */ - {0x00c9d4, 0x00e4b88d}, /* U+4E0D */ - {0x00c9d5, 0x00e4bb98}, /* U+4ED8 */ - {0x00c9d6, 0x00e59fa0}, /* U+57E0 */ - {0x00c9d7, 0x00e5a4ab}, /* U+592B */ - {0x00c9d8, 0x00e5a9a6}, /* U+5A66 */ - {0x00c9d9, 0x00e5af8c}, /* U+5BCC */ - {0x00c9da, 0x00e586a8}, /* U+51A8 */ - {0x00c9db, 0x00e5b883}, /* U+5E03 */ - {0x00c9dc, 0x00e5ba9c}, /* U+5E9C */ - {0x00c9dd, 0x00e68096}, /* U+6016 */ - {0x00c9de, 0x00e689b6}, /* U+6276 */ - {0x00c9df, 0x00e695b7}, /* U+6577 */ - {0x00c9e0, 0x00e696a7}, /* U+65A7 */ - {0x00c9e1, 0x00e699ae}, /* U+666E */ - {0x00c9e2, 0x00e6b5ae}, /* U+6D6E */ - {0x00c9e3, 0x00e788b6}, /* U+7236 */ - {0x00c9e4, 0x00e7aca6}, /* U+7B26 */ - {0x00c9e5, 0x00e88590}, /* U+8150 */ - {0x00c9e6, 0x00e8869a}, /* U+819A */ - {0x00c9e7, 0x00e88a99}, /* U+8299 */ - {0x00c9e8, 0x00e8ad9c}, /* U+8B5C */ - {0x00c9e9, 0x00e8b2a0}, /* U+8CA0 */ - {0x00c9ea, 0x00e8b3a6}, /* U+8CE6 */ - {0x00c9eb, 0x00e8b5b4}, /* U+8D74 */ - {0x00c9ec, 0x00e9989c}, /* U+961C */ - {0x00c9ed, 0x00e99984}, /* U+9644 */ - {0x00c9ee, 0x00e4beae}, /* U+4FAE */ - {0x00c9ef, 0x00e692ab}, /* U+64AB */ - {0x00c9f0, 0x00e6ada6}, /* U+6B66 */ - {0x00c9f1, 0x00e8889e}, /* U+821E */ - {0x00c9f2, 0x00e891a1}, /* U+8461 */ - {0x00c9f3, 0x00e895aa}, /* U+856A */ - {0x00c9f4, 0x00e983a8}, /* U+90E8 */ - {0x00c9f5, 0x00e5b081}, /* U+5C01 */ - {0x00c9f6, 0x00e6a593}, /* U+6953 */ - {0x00c9f7, 0x00e9a2a8}, /* U+98A8 */ - {0x00c9f8, 0x00e891ba}, /* U+847A */ - {0x00c9f9, 0x00e89597}, /* U+8557 */ - {0x00c9fa, 0x00e4bc8f}, /* U+4F0F */ - {0x00c9fb, 0x00e589af}, /* U+526F */ - {0x00c9fc, 0x00e5bea9}, /* U+5FA9 */ - {0x00c9fd, 0x00e5b985}, /* U+5E45 */ - {0x00c9fe, 0x00e69c8d}, /* U+670D */ - {0x00caa1, 0x00e7a68f}, /* U+798F */ - {0x00caa2, 0x00e885b9}, /* U+8179 */ - {0x00caa3, 0x00e8a487}, /* U+8907 */ - {0x00caa4, 0x00e8a686}, /* U+8986 */ - {0x00caa5, 0x00e6b7b5}, /* U+6DF5 */ - {0x00caa6, 0x00e5bc97}, /* U+5F17 */ - {0x00caa7, 0x00e68995}, /* U+6255 */ - {0x00caa8, 0x00e6b2b8}, /* U+6CB8 */ - {0x00caa9, 0x00e4bb8f}, /* U+4ECF */ - {0x00caaa, 0x00e789a9}, /* U+7269 */ - {0x00caab, 0x00e9ae92}, /* U+9B92 */ - {0x00caac, 0x00e58886}, /* U+5206 */ - {0x00caad, 0x00e590bb}, /* U+543B */ - {0x00caae, 0x00e599b4}, /* U+5674 */ - {0x00caaf, 0x00e5a2b3}, /* U+58B3 */ - {0x00cab0, 0x00e686a4}, /* U+61A4 */ - {0x00cab1, 0x00e689ae}, /* U+626E */ - {0x00cab2, 0x00e7849a}, /* U+711A */ - {0x00cab3, 0x00e5a5ae}, /* U+596E */ - {0x00cab4, 0x00e7b289}, /* U+7C89 */ - {0x00cab5, 0x00e7b39e}, /* U+7CDE */ - {0x00cab6, 0x00e7b49b}, /* U+7D1B */ - {0x00cab7, 0x00e99bb0}, /* U+96F0 */ - {0x00cab8, 0x00e69687}, /* U+6587 */ - {0x00cab9, 0x00e8819e}, /* U+805E */ - {0x00caba, 0x00e4b899}, /* U+4E19 */ - {0x00cabb, 0x00e4bdb5}, /* U+4F75 */ - {0x00cabc, 0x00e585b5}, /* U+5175 */ - {0x00cabd, 0x00e5a180}, /* U+5840 */ - {0x00cabe, 0x00e5b9a3}, /* U+5E63 */ - {0x00cabf, 0x00e5b9b3}, /* U+5E73 */ - {0x00cac0, 0x00e5bc8a}, /* U+5F0A */ - {0x00cac1, 0x00e69f84}, /* U+67C4 */ - {0x00cac2, 0x00e4b8a6}, /* U+4E26 */ - {0x00cac3, 0x00e894bd}, /* U+853D */ - {0x00cac4, 0x00e99689}, /* U+9589 */ - {0x00cac5, 0x00e9999b}, /* U+965B */ - {0x00cac6, 0x00e7b1b3}, /* U+7C73 */ - {0x00cac7, 0x00e9a081}, /* U+9801 */ - {0x00cac8, 0x00e583bb}, /* U+50FB */ - {0x00cac9, 0x00e5a381}, /* U+58C1 */ - {0x00caca, 0x00e79996}, /* U+7656 */ - {0x00cacb, 0x00e7a2a7}, /* U+78A7 */ - {0x00cacc, 0x00e588a5}, /* U+5225 */ - {0x00cacd, 0x00e79ea5}, /* U+77A5 */ - {0x00cace, 0x00e89491}, /* U+8511 */ - {0x00cacf, 0x00e7ae86}, /* U+7B86 */ - {0x00cad0, 0x00e5818f}, /* U+504F */ - {0x00cad1, 0x00e5a489}, /* U+5909 */ - {0x00cad2, 0x00e78987}, /* U+7247 */ - {0x00cad3, 0x00e7af87}, /* U+7BC7 */ - {0x00cad4, 0x00e7b7a8}, /* U+7DE8 */ - {0x00cad5, 0x00e8beba}, /* U+8FBA */ - {0x00cad6, 0x00e8bf94}, /* U+8FD4 */ - {0x00cad7, 0x00e9818d}, /* U+904D */ - {0x00cad8, 0x00e4bebf}, /* U+4FBF */ - {0x00cad9, 0x00e58b89}, /* U+52C9 */ - {0x00cada, 0x00e5a8a9}, /* U+5A29 */ - {0x00cadb, 0x00e5bc81}, /* U+5F01 */ - {0x00cadc, 0x00e99ead}, /* U+97AD */ - {0x00cadd, 0x00e4bf9d}, /* U+4FDD */ - {0x00cade, 0x00e88897}, /* U+8217 */ - {0x00cadf, 0x00e98baa}, /* U+92EA */ - {0x00cae0, 0x00e59c83}, /* U+5703 */ - {0x00cae1, 0x00e68d95}, /* U+6355 */ - {0x00cae2, 0x00e6ada9}, /* U+6B69 */ - {0x00cae3, 0x00e794ab}, /* U+752B */ - {0x00cae4, 0x00e8a39c}, /* U+88DC */ - {0x00cae5, 0x00e8bc94}, /* U+8F14 */ - {0x00cae6, 0x00e7a982}, /* U+7A42 */ - {0x00cae7, 0x00e58b9f}, /* U+52DF */ - {0x00cae8, 0x00e5a293}, /* U+5893 */ - {0x00cae9, 0x00e68595}, /* U+6155 */ - {0x00caea, 0x00e6888a}, /* U+620A */ - {0x00caeb, 0x00e69aae}, /* U+66AE */ - {0x00caec, 0x00e6af8d}, /* U+6BCD */ - {0x00caed, 0x00e7b0bf}, /* U+7C3F */ - {0x00caee, 0x00e88fa9}, /* U+83E9 */ - {0x00caef, 0x00e580a3}, /* U+5023 */ - {0x00caf0, 0x00e4bfb8}, /* U+4FF8 */ - {0x00caf1, 0x00e58c85}, /* U+5305 */ - {0x00caf2, 0x00e59186}, /* U+5446 */ - {0x00caf3, 0x00e5a0b1}, /* U+5831 */ - {0x00caf4, 0x00e5a589}, /* U+5949 */ - {0x00caf5, 0x00e5ae9d}, /* U+5B9D */ - {0x00caf6, 0x00e5b3b0}, /* U+5CF0 */ - {0x00caf7, 0x00e5b3af}, /* U+5CEF */ - {0x00caf8, 0x00e5b4a9}, /* U+5D29 */ - {0x00caf9, 0x00e5ba96}, /* U+5E96 */ - {0x00cafa, 0x00e68ab1}, /* U+62B1 */ - {0x00cafb, 0x00e68da7}, /* U+6367 */ - {0x00cafc, 0x00e694be}, /* U+653E */ - {0x00cafd, 0x00e696b9}, /* U+65B9 */ - {0x00cafe, 0x00e69c8b}, /* U+670B */ - {0x00cba1, 0x00e6b395}, /* U+6CD5 */ - {0x00cba2, 0x00e6b3a1}, /* U+6CE1 */ - {0x00cba3, 0x00e783b9}, /* U+70F9 */ - {0x00cba4, 0x00e7a0b2}, /* U+7832 */ - {0x00cba5, 0x00e7b8ab}, /* U+7E2B */ - {0x00cba6, 0x00e8839e}, /* U+80DE */ - {0x00cba7, 0x00e88ab3}, /* U+82B3 */ - {0x00cba8, 0x00e8908c}, /* U+840C */ - {0x00cba9, 0x00e893ac}, /* U+84EC */ - {0x00cbaa, 0x00e89c82}, /* U+8702 */ - {0x00cbab, 0x00e8a492}, /* U+8912 */ - {0x00cbac, 0x00e8a8aa}, /* U+8A2A */ - {0x00cbad, 0x00e8b18a}, /* U+8C4A */ - {0x00cbae, 0x00e982a6}, /* U+90A6 */ - {0x00cbaf, 0x00e98b92}, /* U+92D2 */ - {0x00cbb0, 0x00e9a3bd}, /* U+98FD */ - {0x00cbb1, 0x00e9b3b3}, /* U+9CF3 */ - {0x00cbb2, 0x00e9b5ac}, /* U+9D6C */ - {0x00cbb3, 0x00e4b98f}, /* U+4E4F */ - {0x00cbb4, 0x00e4baa1}, /* U+4EA1 */ - {0x00cbb5, 0x00e5828d}, /* U+508D */ - {0x00cbb6, 0x00e58996}, /* U+5256 */ - {0x00cbb7, 0x00e59d8a}, /* U+574A */ - {0x00cbb8, 0x00e5a6a8}, /* U+59A8 */ - {0x00cbb9, 0x00e5b8bd}, /* U+5E3D */ - {0x00cbba, 0x00e5bf98}, /* U+5FD8 */ - {0x00cbbb, 0x00e5bf99}, /* U+5FD9 */ - {0x00cbbc, 0x00e688bf}, /* U+623F */ - {0x00cbbd, 0x00e69ab4}, /* U+66B4 */ - {0x00cbbe, 0x00e69c9b}, /* U+671B */ - {0x00cbbf, 0x00e69f90}, /* U+67D0 */ - {0x00cbc0, 0x00e6a392}, /* U+68D2 */ - {0x00cbc1, 0x00e58692}, /* U+5192 */ - {0x00cbc2, 0x00e7b4a1}, /* U+7D21 */ - {0x00cbc3, 0x00e882aa}, /* U+80AA */ - {0x00cbc4, 0x00e886a8}, /* U+81A8 */ - {0x00cbc5, 0x00e8ac80}, /* U+8B00 */ - {0x00cbc6, 0x00e8b28c}, /* U+8C8C */ - {0x00cbc7, 0x00e8b2bf}, /* U+8CBF */ - {0x00cbc8, 0x00e989be}, /* U+927E */ - {0x00cbc9, 0x00e998b2}, /* U+9632 */ - {0x00cbca, 0x00e590a0}, /* U+5420 */ - {0x00cbcb, 0x00e9a0ac}, /* U+982C */ - {0x00cbcc, 0x00e58c97}, /* U+5317 */ - {0x00cbcd, 0x00e58395}, /* U+50D5 */ - {0x00cbce, 0x00e58d9c}, /* U+535C */ - {0x00cbcf, 0x00e5a2a8}, /* U+58A8 */ - {0x00cbd0, 0x00e692b2}, /* U+64B2 */ - {0x00cbd1, 0x00e69cb4}, /* U+6734 */ - {0x00cbd2, 0x00e789a7}, /* U+7267 */ - {0x00cbd3, 0x00e79da6}, /* U+7766 */ - {0x00cbd4, 0x00e7a986}, /* U+7A46 */ - {0x00cbd5, 0x00e987a6}, /* U+91E6 */ - {0x00cbd6, 0x00e58b83}, /* U+52C3 */ - {0x00cbd7, 0x00e6b2a1}, /* U+6CA1 */ - {0x00cbd8, 0x00e6ae86}, /* U+6B86 */ - {0x00cbd9, 0x00e5a080}, /* U+5800 */ - {0x00cbda, 0x00e5b98c}, /* U+5E4C */ - {0x00cbdb, 0x00e5a594}, /* U+5954 */ - {0x00cbdc, 0x00e69cac}, /* U+672C */ - {0x00cbdd, 0x00e7bfbb}, /* U+7FFB */ - {0x00cbde, 0x00e587a1}, /* U+51E1 */ - {0x00cbdf, 0x00e79b86}, /* U+76C6 */ - {0x00cbe0, 0x00e691a9}, /* U+6469 */ - {0x00cbe1, 0x00e7a3a8}, /* U+78E8 */ - {0x00cbe2, 0x00e9ad94}, /* U+9B54 */ - {0x00cbe3, 0x00e9babb}, /* U+9EBB */ - {0x00cbe4, 0x00e59f8b}, /* U+57CB */ - {0x00cbe5, 0x00e5a6b9}, /* U+59B9 */ - {0x00cbe6, 0x00e698a7}, /* U+6627 */ - {0x00cbe7, 0x00e69e9a}, /* U+679A */ - {0x00cbe8, 0x00e6af8e}, /* U+6BCE */ - {0x00cbe9, 0x00e593a9}, /* U+54E9 */ - {0x00cbea, 0x00e6a799}, /* U+69D9 */ - {0x00cbeb, 0x00e5b995}, /* U+5E55 */ - {0x00cbec, 0x00e8869c}, /* U+819C */ - {0x00cbed, 0x00e69e95}, /* U+6795 */ - {0x00cbee, 0x00e9aeaa}, /* U+9BAA */ - {0x00cbef, 0x00e69fbe}, /* U+67FE */ - {0x00cbf0, 0x00e9b192}, /* U+9C52 */ - {0x00cbf1, 0x00e6a19d}, /* U+685D */ - {0x00cbf2, 0x00e4baa6}, /* U+4EA6 */ - {0x00cbf3, 0x00e4bfa3}, /* U+4FE3 */ - {0x00cbf4, 0x00e58f88}, /* U+53C8 */ - {0x00cbf5, 0x00e68ab9}, /* U+62B9 */ - {0x00cbf6, 0x00e69cab}, /* U+672B */ - {0x00cbf7, 0x00e6b2ab}, /* U+6CAB */ - {0x00cbf8, 0x00e8bf84}, /* U+8FC4 */ - {0x00cbf9, 0x00e4bead}, /* U+4FAD */ - {0x00cbfa, 0x00e7b9ad}, /* U+7E6D */ - {0x00cbfb, 0x00e9babf}, /* U+9EBF */ - {0x00cbfc, 0x00e4b887}, /* U+4E07 */ - {0x00cbfd, 0x00e685a2}, /* U+6162 */ - {0x00cbfe, 0x00e6ba80}, /* U+6E80 */ - {0x00cca1, 0x00e6bcab}, /* U+6F2B */ - {0x00cca2, 0x00e89493}, /* U+8513 */ - {0x00cca3, 0x00e591b3}, /* U+5473 */ - {0x00cca4, 0x00e69caa}, /* U+672A */ - {0x00cca5, 0x00e9ad85}, /* U+9B45 */ - {0x00cca6, 0x00e5b7b3}, /* U+5DF3 */ - {0x00cca7, 0x00e7ae95}, /* U+7B95 */ - {0x00cca8, 0x00e5b2ac}, /* U+5CAC */ - {0x00cca9, 0x00e5af86}, /* U+5BC6 */ - {0x00ccaa, 0x00e89c9c}, /* U+871C */ - {0x00ccab, 0x00e6b98a}, /* U+6E4A */ - {0x00ccac, 0x00e89391}, /* U+84D1 */ - {0x00ccad, 0x00e7a894}, /* U+7A14 */ - {0x00ccae, 0x00e88488}, /* U+8108 */ - {0x00ccaf, 0x00e5a699}, /* U+5999 */ - {0x00ccb0, 0x00e7b28d}, /* U+7C8D */ - {0x00ccb1, 0x00e6b091}, /* U+6C11 */ - {0x00ccb2, 0x00e79ca0}, /* U+7720 */ - {0x00ccb3, 0x00e58b99}, /* U+52D9 */ - {0x00ccb4, 0x00e5a4a2}, /* U+5922 */ - {0x00ccb5, 0x00e784a1}, /* U+7121 */ - {0x00ccb6, 0x00e7899f}, /* U+725F */ - {0x00ccb7, 0x00e79f9b}, /* U+77DB */ - {0x00ccb8, 0x00e99ca7}, /* U+9727 */ - {0x00ccb9, 0x00e9b5a1}, /* U+9D61 */ - {0x00ccba, 0x00e6a48b}, /* U+690B */ - {0x00ccbb, 0x00e5a9bf}, /* U+5A7F */ - {0x00ccbc, 0x00e5a898}, /* U+5A18 */ - {0x00ccbd, 0x00e586a5}, /* U+51A5 */ - {0x00ccbe, 0x00e5908d}, /* U+540D */ - {0x00ccbf, 0x00e591bd}, /* U+547D */ - {0x00ccc0, 0x00e6988e}, /* U+660E */ - {0x00ccc1, 0x00e79b9f}, /* U+76DF */ - {0x00ccc2, 0x00e8bfb7}, /* U+8FF7 */ - {0x00ccc3, 0x00e98a98}, /* U+9298 */ - {0x00ccc4, 0x00e9b3b4}, /* U+9CF4 */ - {0x00ccc5, 0x00e5a7aa}, /* U+59EA */ - {0x00ccc6, 0x00e7899d}, /* U+725D */ - {0x00ccc7, 0x00e6bb85}, /* U+6EC5 */ - {0x00ccc8, 0x00e5858d}, /* U+514D */ - {0x00ccc9, 0x00e6a389}, /* U+68C9 */ - {0x00ccca, 0x00e7b6bf}, /* U+7DBF */ - {0x00cccb, 0x00e7b7ac}, /* U+7DEC */ - {0x00cccc, 0x00e99da2}, /* U+9762 */ - {0x00cccd, 0x00e9baba}, /* U+9EBA */ - {0x00ccce, 0x00e691b8}, /* U+6478 */ - {0x00cccf, 0x00e6a8a1}, /* U+6A21 */ - {0x00ccd0, 0x00e88c82}, /* U+8302 */ - {0x00ccd1, 0x00e5a684}, /* U+5984 */ - {0x00ccd2, 0x00e5ad9f}, /* U+5B5F */ - {0x00ccd3, 0x00e6af9b}, /* U+6BDB */ - {0x00ccd4, 0x00e78c9b}, /* U+731B */ - {0x00ccd5, 0x00e79bb2}, /* U+76F2 */ - {0x00ccd6, 0x00e7b6b2}, /* U+7DB2 */ - {0x00ccd7, 0x00e88097}, /* U+8017 */ - {0x00ccd8, 0x00e89299}, /* U+8499 */ - {0x00ccd9, 0x00e584b2}, /* U+5132 */ - {0x00ccda, 0x00e69ca8}, /* U+6728 */ - {0x00ccdb, 0x00e9bb99}, /* U+9ED9 */ - {0x00ccdc, 0x00e79bae}, /* U+76EE */ - {0x00ccdd, 0x00e69da2}, /* U+6762 */ - {0x00ccde, 0x00e58bbf}, /* U+52FF */ - {0x00ccdf, 0x00e9a485}, /* U+9905 */ - {0x00cce0, 0x00e5b0a4}, /* U+5C24 */ - {0x00cce1, 0x00e688bb}, /* U+623B */ - {0x00cce2, 0x00e7b1be}, /* U+7C7E */ - {0x00cce3, 0x00e8b2b0}, /* U+8CB0 */ - {0x00cce4, 0x00e5958f}, /* U+554F */ - {0x00cce5, 0x00e682b6}, /* U+60B6 */ - {0x00cce6, 0x00e7b48b}, /* U+7D0B */ - {0x00cce7, 0x00e99680}, /* U+9580 */ - {0x00cce8, 0x00e58c81}, /* U+5301 */ - {0x00cce9, 0x00e4b99f}, /* U+4E5F */ - {0x00ccea, 0x00e586b6}, /* U+51B6 */ - {0x00cceb, 0x00e5a49c}, /* U+591C */ - {0x00ccec, 0x00e788ba}, /* U+723A */ - {0x00cced, 0x00e880b6}, /* U+8036 */ - {0x00ccee, 0x00e9878e}, /* U+91CE */ - {0x00ccef, 0x00e5bca5}, /* U+5F25 */ - {0x00ccf0, 0x00e79fa2}, /* U+77E2 */ - {0x00ccf1, 0x00e58e84}, /* U+5384 */ - {0x00ccf2, 0x00e5bdb9}, /* U+5F79 */ - {0x00ccf3, 0x00e7b484}, /* U+7D04 */ - {0x00ccf4, 0x00e896ac}, /* U+85AC */ - {0x00ccf5, 0x00e8a8b3}, /* U+8A33 */ - {0x00ccf6, 0x00e8ba8d}, /* U+8E8D */ - {0x00ccf7, 0x00e99d96}, /* U+9756 */ - {0x00ccf8, 0x00e69fb3}, /* U+67F3 */ - {0x00ccf9, 0x00e896ae}, /* U+85AE */ - {0x00ccfa, 0x00e99193}, /* U+9453 */ - {0x00ccfb, 0x00e68489}, /* U+6109 */ - {0x00ccfc, 0x00e68488}, /* U+6108 */ - {0x00ccfd, 0x00e6b2b9}, /* U+6CB9 */ - {0x00ccfe, 0x00e79992}, /* U+7652 */ - {0x00cda1, 0x00e8abad}, /* U+8AED */ - {0x00cda2, 0x00e8bcb8}, /* U+8F38 */ - {0x00cda3, 0x00e594af}, /* U+552F */ - {0x00cda4, 0x00e4bd91}, /* U+4F51 */ - {0x00cda5, 0x00e584aa}, /* U+512A */ - {0x00cda6, 0x00e58b87}, /* U+52C7 */ - {0x00cda7, 0x00e58f8b}, /* U+53CB */ - {0x00cda8, 0x00e5aea5}, /* U+5BA5 */ - {0x00cda9, 0x00e5b9bd}, /* U+5E7D */ - {0x00cdaa, 0x00e682a0}, /* U+60A0 */ - {0x00cdab, 0x00e68682}, /* U+6182 */ - {0x00cdac, 0x00e68f96}, /* U+63D6 */ - {0x00cdad, 0x00e69c89}, /* U+6709 */ - {0x00cdae, 0x00e69f9a}, /* U+67DA */ - {0x00cdaf, 0x00e6b9a7}, /* U+6E67 */ - {0x00cdb0, 0x00e6b68c}, /* U+6D8C */ - {0x00cdb1, 0x00e78cb6}, /* U+7336 */ - {0x00cdb2, 0x00e78cb7}, /* U+7337 */ - {0x00cdb3, 0x00e794b1}, /* U+7531 */ - {0x00cdb4, 0x00e7a590}, /* U+7950 */ - {0x00cdb5, 0x00e8a395}, /* U+88D5 */ - {0x00cdb6, 0x00e8aa98}, /* U+8A98 */ - {0x00cdb7, 0x00e9818a}, /* U+904A */ - {0x00cdb8, 0x00e98291}, /* U+9091 */ - {0x00cdb9, 0x00e983b5}, /* U+90F5 */ - {0x00cdba, 0x00e99b84}, /* U+96C4 */ - {0x00cdbb, 0x00e89e8d}, /* U+878D */ - {0x00cdbc, 0x00e5a495}, /* U+5915 */ - {0x00cdbd, 0x00e4ba88}, /* U+4E88 */ - {0x00cdbe, 0x00e4bd99}, /* U+4F59 */ - {0x00cdbf, 0x00e4b88e}, /* U+4E0E */ - {0x00cdc0, 0x00e8aa89}, /* U+8A89 */ - {0x00cdc1, 0x00e8bcbf}, /* U+8F3F */ - {0x00cdc2, 0x00e9a090}, /* U+9810 */ - {0x00cdc3, 0x00e582ad}, /* U+50AD */ - {0x00cdc4, 0x00e5b9bc}, /* U+5E7C */ - {0x00cdc5, 0x00e5a696}, /* U+5996 */ - {0x00cdc6, 0x00e5aeb9}, /* U+5BB9 */ - {0x00cdc7, 0x00e5bab8}, /* U+5EB8 */ - {0x00cdc8, 0x00e68f9a}, /* U+63DA */ - {0x00cdc9, 0x00e68fba}, /* U+63FA */ - {0x00cdca, 0x00e69381}, /* U+64C1 */ - {0x00cdcb, 0x00e69b9c}, /* U+66DC */ - {0x00cdcc, 0x00e6a58a}, /* U+694A */ - {0x00cdcd, 0x00e6a798}, /* U+69D8 */ - {0x00cdce, 0x00e6b48b}, /* U+6D0B */ - {0x00cdcf, 0x00e6bab6}, /* U+6EB6 */ - {0x00cdd0, 0x00e78694}, /* U+7194 */ - {0x00cdd1, 0x00e794a8}, /* U+7528 */ - {0x00cdd2, 0x00e7aaaf}, /* U+7AAF */ - {0x00cdd3, 0x00e7be8a}, /* U+7F8A */ - {0x00cdd4, 0x00e88080}, /* U+8000 */ - {0x00cdd5, 0x00e89189}, /* U+8449 */ - {0x00cdd6, 0x00e89389}, /* U+84C9 */ - {0x00cdd7, 0x00e8a681}, /* U+8981 */ - {0x00cdd8, 0x00e8aca1}, /* U+8B21 */ - {0x00cdd9, 0x00e8b88a}, /* U+8E0A */ - {0x00cdda, 0x00e981a5}, /* U+9065 */ - {0x00cddb, 0x00e999bd}, /* U+967D */ - {0x00cddc, 0x00e9a48a}, /* U+990A */ - {0x00cddd, 0x00e685be}, /* U+617E */ - {0x00cdde, 0x00e68a91}, /* U+6291 */ - {0x00cddf, 0x00e6acb2}, /* U+6B32 */ - {0x00cde0, 0x00e6b283}, /* U+6C83 */ - {0x00cde1, 0x00e6b5b4}, /* U+6D74 */ - {0x00cde2, 0x00e7bf8c}, /* U+7FCC */ - {0x00cde3, 0x00e7bfbc}, /* U+7FFC */ - {0x00cde4, 0x00e6b780}, /* U+6DC0 */ - {0x00cde5, 0x00e7be85}, /* U+7F85 */ - {0x00cde6, 0x00e89eba}, /* U+87BA */ - {0x00cde7, 0x00e8a3b8}, /* U+88F8 */ - {0x00cde8, 0x00e69da5}, /* U+6765 */ - {0x00cde9, 0x00e88eb1}, /* U+83B1 */ - {0x00cdea, 0x00e9a0bc}, /* U+983C */ - {0x00cdeb, 0x00e99bb7}, /* U+96F7 */ - {0x00cdec, 0x00e6b49b}, /* U+6D1B */ - {0x00cded, 0x00e7b5a1}, /* U+7D61 */ - {0x00cdee, 0x00e890bd}, /* U+843D */ - {0x00cdef, 0x00e985aa}, /* U+916A */ - {0x00cdf0, 0x00e4b9b1}, /* U+4E71 */ - {0x00cdf1, 0x00e58db5}, /* U+5375 */ - {0x00cdf2, 0x00e5b590}, /* U+5D50 */ - {0x00cdf3, 0x00e6ac84}, /* U+6B04 */ - {0x00cdf4, 0x00e6bfab}, /* U+6FEB */ - {0x00cdf5, 0x00e8978d}, /* U+85CD */ - {0x00cdf6, 0x00e898ad}, /* U+862D */ - {0x00cdf7, 0x00e8a6a7}, /* U+89A7 */ - {0x00cdf8, 0x00e588a9}, /* U+5229 */ - {0x00cdf9, 0x00e5908f}, /* U+540F */ - {0x00cdfa, 0x00e5b1a5}, /* U+5C65 */ - {0x00cdfb, 0x00e69d8e}, /* U+674E */ - {0x00cdfc, 0x00e6a2a8}, /* U+68A8 */ - {0x00cdfd, 0x00e79086}, /* U+7406 */ - {0x00cdfe, 0x00e79283}, /* U+7483 */ - {0x00cea1, 0x00e797a2}, /* U+75E2 */ - {0x00cea2, 0x00e8a38f}, /* U+88CF */ - {0x00cea3, 0x00e8a3a1}, /* U+88E1 */ - {0x00cea4, 0x00e9878c}, /* U+91CC */ - {0x00cea5, 0x00e99ba2}, /* U+96E2 */ - {0x00cea6, 0x00e999b8}, /* U+9678 */ - {0x00cea7, 0x00e5be8b}, /* U+5F8B */ - {0x00cea8, 0x00e78e87}, /* U+7387 */ - {0x00cea9, 0x00e7ab8b}, /* U+7ACB */ - {0x00ceaa, 0x00e8918e}, /* U+844E */ - {0x00ceab, 0x00e68ea0}, /* U+63A0 */ - {0x00ceac, 0x00e795a5}, /* U+7565 */ - {0x00cead, 0x00e58a89}, /* U+5289 */ - {0x00ceae, 0x00e6b581}, /* U+6D41 */ - {0x00ceaf, 0x00e6ba9c}, /* U+6E9C */ - {0x00ceb0, 0x00e79089}, /* U+7409 */ - {0x00ceb1, 0x00e79599}, /* U+7559 */ - {0x00ceb2, 0x00e7a1ab}, /* U+786B */ - {0x00ceb3, 0x00e7b292}, /* U+7C92 */ - {0x00ceb4, 0x00e99a86}, /* U+9686 */ - {0x00ceb5, 0x00e7ab9c}, /* U+7ADC */ - {0x00ceb6, 0x00e9be8d}, /* U+9F8D */ - {0x00ceb7, 0x00e4beb6}, /* U+4FB6 */ - {0x00ceb8, 0x00e685ae}, /* U+616E */ - {0x00ceb9, 0x00e69785}, /* U+65C5 */ - {0x00ceba, 0x00e8999c}, /* U+865C */ - {0x00cebb, 0x00e4ba86}, /* U+4E86 */ - {0x00cebc, 0x00e4baae}, /* U+4EAE */ - {0x00cebd, 0x00e5839a}, /* U+50DA */ - {0x00cebe, 0x00e4b8a1}, /* U+4E21 */ - {0x00cebf, 0x00e5878c}, /* U+51CC */ - {0x00cec0, 0x00e5afae}, /* U+5BEE */ - {0x00cec1, 0x00e69699}, /* U+6599 */ - {0x00cec2, 0x00e6a281}, /* U+6881 */ - {0x00cec3, 0x00e6b6bc}, /* U+6DBC */ - {0x00cec4, 0x00e78c9f}, /* U+731F */ - {0x00cec5, 0x00e79982}, /* U+7642 */ - {0x00cec6, 0x00e79ead}, /* U+77AD */ - {0x00cec7, 0x00e7a89c}, /* U+7A1C */ - {0x00cec8, 0x00e7b3a7}, /* U+7CE7 */ - {0x00cec9, 0x00e889af}, /* U+826F */ - {0x00ceca, 0x00e8ab92}, /* U+8AD2 */ - {0x00cecb, 0x00e981bc}, /* U+907C */ - {0x00cecc, 0x00e9878f}, /* U+91CF */ - {0x00cecd, 0x00e999b5}, /* U+9675 */ - {0x00cece, 0x00e9a098}, /* U+9818 */ - {0x00cecf, 0x00e58a9b}, /* U+529B */ - {0x00ced0, 0x00e7b791}, /* U+7DD1 */ - {0x00ced1, 0x00e580ab}, /* U+502B */ - {0x00ced2, 0x00e58e98}, /* U+5398 */ - {0x00ced3, 0x00e69e97}, /* U+6797 */ - {0x00ced4, 0x00e6b78b}, /* U+6DCB */ - {0x00ced5, 0x00e78790}, /* U+71D0 */ - {0x00ced6, 0x00e790b3}, /* U+7433 */ - {0x00ced7, 0x00e887a8}, /* U+81E8 */ - {0x00ced8, 0x00e8bcaa}, /* U+8F2A */ - {0x00ced9, 0x00e99aa3}, /* U+96A3 */ - {0x00ceda, 0x00e9b197}, /* U+9C57 */ - {0x00cedb, 0x00e9ba9f}, /* U+9E9F */ - {0x00cedc, 0x00e791a0}, /* U+7460 */ - {0x00cedd, 0x00e5a181}, /* U+5841 */ - {0x00cede, 0x00e6b699}, /* U+6D99 */ - {0x00cedf, 0x00e7b4af}, /* U+7D2F */ - {0x00cee0, 0x00e9a19e}, /* U+985E */ - {0x00cee1, 0x00e4bba4}, /* U+4EE4 */ - {0x00cee2, 0x00e4bcb6}, /* U+4F36 */ - {0x00cee3, 0x00e4be8b}, /* U+4F8B */ - {0x00cee4, 0x00e586b7}, /* U+51B7 */ - {0x00cee5, 0x00e58ab1}, /* U+52B1 */ - {0x00cee6, 0x00e5b6ba}, /* U+5DBA */ - {0x00cee7, 0x00e6809c}, /* U+601C */ - {0x00cee8, 0x00e78eb2}, /* U+73B2 */ - {0x00cee9, 0x00e7a4bc}, /* U+793C */ - {0x00ceea, 0x00e88b93}, /* U+82D3 */ - {0x00ceeb, 0x00e988b4}, /* U+9234 */ - {0x00ceec, 0x00e99ab7}, /* U+96B7 */ - {0x00ceed, 0x00e99bb6}, /* U+96F6 */ - {0x00ceee, 0x00e99c8a}, /* U+970A */ - {0x00ceef, 0x00e9ba97}, /* U+9E97 */ - {0x00cef0, 0x00e9bda2}, /* U+9F62 */ - {0x00cef1, 0x00e69aa6}, /* U+66A6 */ - {0x00cef2, 0x00e6adb4}, /* U+6B74 */ - {0x00cef3, 0x00e58897}, /* U+5217 */ - {0x00cef4, 0x00e58aa3}, /* U+52A3 */ - {0x00cef5, 0x00e78388}, /* U+70C8 */ - {0x00cef6, 0x00e8a382}, /* U+88C2 */ - {0x00cef7, 0x00e5bb89}, /* U+5EC9 */ - {0x00cef8, 0x00e6818b}, /* U+604B */ - {0x00cef9, 0x00e68690}, /* U+6190 */ - {0x00cefa, 0x00e6bca3}, /* U+6F23 */ - {0x00cefb, 0x00e78589}, /* U+7149 */ - {0x00cefc, 0x00e7b0be}, /* U+7C3E */ - {0x00cefd, 0x00e7b7b4}, /* U+7DF4 */ - {0x00cefe, 0x00e881af}, /* U+806F */ - {0x00cfa1, 0x00e893ae}, /* U+84EE */ - {0x00cfa2, 0x00e980a3}, /* U+9023 */ - {0x00cfa3, 0x00e98cac}, /* U+932C */ - {0x00cfa4, 0x00e59182}, /* U+5442 */ - {0x00cfa5, 0x00e9adaf}, /* U+9B6F */ - {0x00cfa6, 0x00e6ab93}, /* U+6AD3 */ - {0x00cfa7, 0x00e78289}, /* U+7089 */ - {0x00cfa8, 0x00e8b382}, /* U+8CC2 */ - {0x00cfa9, 0x00e8b7af}, /* U+8DEF */ - {0x00cfaa, 0x00e99cb2}, /* U+9732 */ - {0x00cfab, 0x00e58ab4}, /* U+52B4 */ - {0x00cfac, 0x00e5a981}, /* U+5A41 */ - {0x00cfad, 0x00e5bb8a}, /* U+5ECA */ - {0x00cfae, 0x00e5bc84}, /* U+5F04 */ - {0x00cfaf, 0x00e69c97}, /* U+6717 */ - {0x00cfb0, 0x00e6a5bc}, /* U+697C */ - {0x00cfb1, 0x00e6a694}, /* U+6994 */ - {0x00cfb2, 0x00e6b5aa}, /* U+6D6A */ - {0x00cfb3, 0x00e6bc8f}, /* U+6F0F */ - {0x00cfb4, 0x00e789a2}, /* U+7262 */ - {0x00cfb5, 0x00e78bbc}, /* U+72FC */ - {0x00cfb6, 0x00e7afad}, /* U+7BED */ - {0x00cfb7, 0x00e88081}, /* U+8001 */ - {0x00cfb8, 0x00e881be}, /* U+807E */ - {0x00cfb9, 0x00e89d8b}, /* U+874B */ - {0x00cfba, 0x00e9838e}, /* U+90CE */ - {0x00cfbb, 0x00e585ad}, /* U+516D */ - {0x00cfbc, 0x00e9ba93}, /* U+9E93 */ - {0x00cfbd, 0x00e7a684}, /* U+7984 */ - {0x00cfbe, 0x00e8828b}, /* U+808B */ - {0x00cfbf, 0x00e98cb2}, /* U+9332 */ - {0x00cfc0, 0x00e8ab96}, /* U+8AD6 */ - {0x00cfc1, 0x00e580ad}, /* U+502D */ - {0x00cfc2, 0x00e5928c}, /* U+548C */ - {0x00cfc3, 0x00e8a9b1}, /* U+8A71 */ - {0x00cfc4, 0x00e6adaa}, /* U+6B6A */ - {0x00cfc5, 0x00e8b384}, /* U+8CC4 */ - {0x00cfc6, 0x00e88487}, /* U+8107 */ - {0x00cfc7, 0x00e68391}, /* U+60D1 */ - {0x00cfc8, 0x00e69ea0}, /* U+67A0 */ - {0x00cfc9, 0x00e9b7b2}, /* U+9DF2 */ - {0x00cfca, 0x00e4ba99}, /* U+4E99 */ - {0x00cfcb, 0x00e4ba98}, /* U+4E98 */ - {0x00cfcc, 0x00e9b090}, /* U+9C10 */ - {0x00cfcd, 0x00e8a9ab}, /* U+8A6B */ - {0x00cfce, 0x00e89781}, /* U+85C1 */ - {0x00cfcf, 0x00e895a8}, /* U+8568 */ - {0x00cfd0, 0x00e6a480}, /* U+6900 */ - {0x00cfd1, 0x00e6b9be}, /* U+6E7E */ - {0x00cfd2, 0x00e7a297}, /* U+7897 */ - {0x00cfd3, 0x00e88595}, /* U+8155 */ - {0x00cfd4, 0xf0a0ae9f}, /* U+20B9F [2004] [Unicode3.1] */ - {0x00cfd5, 0x00e5ad81}, /* U+5B41 [2000] */ - {0x00cfd6, 0x00e5ad96}, /* U+5B56 [2000] */ - {0x00cfd7, 0x00e5adbd}, /* U+5B7D [2000] */ - {0x00cfd8, 0x00e5ae93}, /* U+5B93 [2000] */ - {0x00cfd9, 0x00e5af98}, /* U+5BD8 [2000] */ - {0x00cfda, 0x00e5afac}, /* U+5BEC [2000] */ - {0x00cfdb, 0x00e5b092}, /* U+5C12 [2000] */ - {0x00cfdc, 0x00e5b09e}, /* U+5C1E [2000] */ - {0x00cfdd, 0x00e5b0a3}, /* U+5C23 [2000] */ - {0x00cfde, 0x00e5b0ab}, /* U+5C2B [2000] */ - {0x00cfdf, 0x00e39e8d}, /* U+378D [2000] */ - {0x00cfe0, 0x00e5b1a2}, /* U+5C62 [2000] */ - {0x00cfe1, 0x00efa8bb}, /* U+FA3B CJK COMPATIBILITY IDEOGRAPH-FA3B [2000] [Unicode3.2] */ - {0x00cfe2, 0x00efa8bc}, /* U+FA3C CJK COMPATIBILITY IDEOGRAPH-FA3C [2000] [Unicode3.2] */ - {0x00cfe3, 0xf0a19ab4}, /* U+216B4 [2000] [Unicode3.1] */ - {0x00cfe4, 0x00e5b1ba}, /* U+5C7A [2000] */ - {0x00cfe5, 0x00e5b28f}, /* U+5C8F [2000] */ - {0x00cfe6, 0x00e5b29f}, /* U+5C9F [2000] */ - {0x00cfe7, 0x00e5b2a3}, /* U+5CA3 [2000] */ - {0x00cfe8, 0x00e5b2aa}, /* U+5CAA [2000] */ - {0x00cfe9, 0x00e5b2ba}, /* U+5CBA [2000] */ - {0x00cfea, 0x00e5b38b}, /* U+5CCB [2000] */ - {0x00cfeb, 0x00e5b390}, /* U+5CD0 [2000] */ - {0x00cfec, 0x00e5b392}, /* U+5CD2 [2000] */ - {0x00cfed, 0x00e5b3b4}, /* U+5CF4 [2000] */ - {0x00cfee, 0xf0a1b8b4}, /* U+21E34 [2000] [Unicode3.1] */ - {0x00cfef, 0x00e39fa2}, /* U+37E2 [2000] */ - {0x00cff0, 0x00e5b48d}, /* U+5D0D [2000] */ - {0x00cff1, 0x00e5b4a7}, /* U+5D27 [2000] */ - {0x00cff2, 0x00efa891}, /* U+FA11 CJK COMPATIBILITY IDEOGRAPH-FA11 [2000] */ - {0x00cff3, 0x00e5b586}, /* U+5D46 [2000] */ - {0x00cff4, 0x00e5b587}, /* U+5D47 [2000] */ - {0x00cff5, 0x00e5b593}, /* U+5D53 [2000] */ - {0x00cff6, 0x00e5b58a}, /* U+5D4A [2000] */ - {0x00cff7, 0x00e5b5ad}, /* U+5D6D [2000] */ - {0x00cff8, 0x00e5b681}, /* U+5D81 [2000] */ - {0x00cff9, 0x00e5b6a0}, /* U+5DA0 [2000] */ - {0x00cffa, 0x00e5b6a4}, /* U+5DA4 [2000] */ - {0x00cffb, 0x00e5b6a7}, /* U+5DA7 [2000] */ - {0x00cffc, 0x00e5b6b8}, /* U+5DB8 [2000] */ - {0x00cffd, 0x00e5b78b}, /* U+5DCB [2000] */ - {0x00cffe, 0x00e5909e}, /* U+541E [2004] */ - {0x00d0a1, 0x00e5bc8c}, /* U+5F0C */ - {0x00d0a2, 0x00e4b890}, /* U+4E10 */ - {0x00d0a3, 0x00e4b895}, /* U+4E15 */ - {0x00d0a4, 0x00e4b8aa}, /* U+4E2A */ - {0x00d0a5, 0x00e4b8b1}, /* U+4E31 */ - {0x00d0a6, 0x00e4b8b6}, /* U+4E36 */ - {0x00d0a7, 0x00e4b8bc}, /* U+4E3C */ - {0x00d0a8, 0x00e4b8bf}, /* U+4E3F */ - {0x00d0a9, 0x00e4b982}, /* U+4E42 */ - {0x00d0aa, 0x00e4b996}, /* U+4E56 */ - {0x00d0ab, 0x00e4b998}, /* U+4E58 */ - {0x00d0ac, 0x00e4ba82}, /* U+4E82 */ - {0x00d0ad, 0x00e4ba85}, /* U+4E85 */ - {0x00d0ae, 0x00e8b1ab}, /* U+8C6B */ - {0x00d0af, 0x00e4ba8a}, /* U+4E8A */ - {0x00d0b0, 0x00e88892}, /* U+8212 */ - {0x00d0b1, 0x00e5bc8d}, /* U+5F0D */ - {0x00d0b2, 0x00e4ba8e}, /* U+4E8E */ - {0x00d0b3, 0x00e4ba9e}, /* U+4E9E */ - {0x00d0b4, 0x00e4ba9f}, /* U+4E9F */ - {0x00d0b5, 0x00e4baa0}, /* U+4EA0 */ - {0x00d0b6, 0x00e4baa2}, /* U+4EA2 */ - {0x00d0b7, 0x00e4bab0}, /* U+4EB0 */ - {0x00d0b8, 0x00e4bab3}, /* U+4EB3 */ - {0x00d0b9, 0x00e4bab6}, /* U+4EB6 */ - {0x00d0ba, 0x00e4bb8e}, /* U+4ECE */ - {0x00d0bb, 0x00e4bb8d}, /* U+4ECD */ - {0x00d0bc, 0x00e4bb84}, /* U+4EC4 */ - {0x00d0bd, 0x00e4bb86}, /* U+4EC6 */ - {0x00d0be, 0x00e4bb82}, /* U+4EC2 */ - {0x00d0bf, 0x00e4bb97}, /* U+4ED7 */ - {0x00d0c0, 0x00e4bb9e}, /* U+4EDE */ - {0x00d0c1, 0x00e4bbad}, /* U+4EED */ - {0x00d0c2, 0x00e4bb9f}, /* U+4EDF */ - {0x00d0c3, 0x00e4bbb7}, /* U+4EF7 */ - {0x00d0c4, 0x00e4bc89}, /* U+4F09 */ - {0x00d0c5, 0x00e4bd9a}, /* U+4F5A */ - {0x00d0c6, 0x00e4bcb0}, /* U+4F30 */ - {0x00d0c7, 0x00e4bd9b}, /* U+4F5B */ - {0x00d0c8, 0x00e4bd9d}, /* U+4F5D */ - {0x00d0c9, 0x00e4bd97}, /* U+4F57 */ - {0x00d0ca, 0x00e4bd87}, /* U+4F47 */ - {0x00d0cb, 0x00e4bdb6}, /* U+4F76 */ - {0x00d0cc, 0x00e4be88}, /* U+4F88 */ - {0x00d0cd, 0x00e4be8f}, /* U+4F8F */ - {0x00d0ce, 0x00e4be98}, /* U+4F98 */ - {0x00d0cf, 0x00e4bdbb}, /* U+4F7B */ - {0x00d0d0, 0x00e4bda9}, /* U+4F69 */ - {0x00d0d1, 0x00e4bdb0}, /* U+4F70 */ - {0x00d0d2, 0x00e4be91}, /* U+4F91 */ - {0x00d0d3, 0x00e4bdaf}, /* U+4F6F */ - {0x00d0d4, 0x00e4be86}, /* U+4F86 */ - {0x00d0d5, 0x00e4be96}, /* U+4F96 */ - {0x00d0d6, 0x00e58498}, /* U+5118 */ - {0x00d0d7, 0x00e4bf94}, /* U+4FD4 */ - {0x00d0d8, 0x00e4bf9f}, /* U+4FDF */ - {0x00d0d9, 0x00e4bf8e}, /* U+4FCE */ - {0x00d0da, 0x00e4bf98}, /* U+4FD8 */ - {0x00d0db, 0x00e4bf9b}, /* U+4FDB */ - {0x00d0dc, 0x00e4bf91}, /* U+4FD1 */ - {0x00d0dd, 0x00e4bf9a}, /* U+4FDA */ - {0x00d0de, 0x00e4bf90}, /* U+4FD0 */ - {0x00d0df, 0x00e4bfa4}, /* U+4FE4 */ - {0x00d0e0, 0x00e4bfa5}, /* U+4FE5 */ - {0x00d0e1, 0x00e5809a}, /* U+501A */ - {0x00d0e2, 0x00e580a8}, /* U+5028 */ - {0x00d0e3, 0x00e58094}, /* U+5014 */ - {0x00d0e4, 0x00e580aa}, /* U+502A */ - {0x00d0e5, 0x00e580a5}, /* U+5025 */ - {0x00d0e6, 0x00e58085}, /* U+5005 */ - {0x00d0e7, 0x00e4bc9c}, /* U+4F1C */ - {0x00d0e8, 0x00e4bfb6}, /* U+4FF6 */ - {0x00d0e9, 0x00e580a1}, /* U+5021 */ - {0x00d0ea, 0x00e580a9}, /* U+5029 */ - {0x00d0eb, 0x00e580ac}, /* U+502C */ - {0x00d0ec, 0x00e4bfbe}, /* U+4FFE */ - {0x00d0ed, 0x00e4bfaf}, /* U+4FEF */ - {0x00d0ee, 0x00e58091}, /* U+5011 */ - {0x00d0ef, 0x00e58086}, /* U+5006 */ - {0x00d0f0, 0x00e58183}, /* U+5043 */ - {0x00d0f1, 0x00e58187}, /* U+5047 */ - {0x00d0f2, 0x00e69c83}, /* U+6703 */ - {0x00d0f3, 0x00e58195}, /* U+5055 */ - {0x00d0f4, 0x00e58190}, /* U+5050 */ - {0x00d0f5, 0x00e58188}, /* U+5048 */ - {0x00d0f6, 0x00e5819a}, /* U+505A */ - {0x00d0f7, 0x00e58196}, /* U+5056 */ - {0x00d0f8, 0x00e581ac}, /* U+506C */ - {0x00d0f9, 0x00e581b8}, /* U+5078 */ - {0x00d0fa, 0x00e58280}, /* U+5080 */ - {0x00d0fb, 0x00e5829a}, /* U+509A */ - {0x00d0fc, 0x00e58285}, /* U+5085 */ - {0x00d0fd, 0x00e582b4}, /* U+50B4 */ - {0x00d0fe, 0x00e582b2}, /* U+50B2 */ - {0x00d1a1, 0x00e58389}, /* U+50C9 */ - {0x00d1a2, 0x00e5838a}, /* U+50CA */ - {0x00d1a3, 0x00e582b3}, /* U+50B3 */ - {0x00d1a4, 0x00e58382}, /* U+50C2 */ - {0x00d1a5, 0x00e58396}, /* U+50D6 */ - {0x00d1a6, 0x00e5839e}, /* U+50DE */ - {0x00d1a7, 0x00e583a5}, /* U+50E5 */ - {0x00d1a8, 0x00e583ad}, /* U+50ED */ - {0x00d1a9, 0x00e583a3}, /* U+50E3 */ - {0x00d1aa, 0x00e583ae}, /* U+50EE */ - {0x00d1ab, 0x00e583b9}, /* U+50F9 */ - {0x00d1ac, 0x00e583b5}, /* U+50F5 */ - {0x00d1ad, 0x00e58489}, /* U+5109 */ - {0x00d1ae, 0x00e58481}, /* U+5101 */ - {0x00d1af, 0x00e58482}, /* U+5102 */ - {0x00d1b0, 0x00e58496}, /* U+5116 */ - {0x00d1b1, 0x00e58495}, /* U+5115 */ - {0x00d1b2, 0x00e58494}, /* U+5114 */ - {0x00d1b3, 0x00e5849a}, /* U+511A */ - {0x00d1b4, 0x00e584a1}, /* U+5121 */ - {0x00d1b5, 0x00e584ba}, /* U+513A */ - {0x00d1b6, 0x00e584b7}, /* U+5137 */ - {0x00d1b7, 0x00e584bc}, /* U+513C */ - {0x00d1b8, 0x00e584bb}, /* U+513B */ - {0x00d1b9, 0x00e584bf}, /* U+513F */ - {0x00d1ba, 0x00e58580}, /* U+5140 */ - {0x00d1bb, 0x00e58592}, /* U+5152 */ - {0x00d1bc, 0x00e5858c}, /* U+514C */ - {0x00d1bd, 0x00e58594}, /* U+5154 */ - {0x00d1be, 0x00e585a2}, /* U+5162 */ - {0x00d1bf, 0x00e7abb8}, /* U+7AF8 */ - {0x00d1c0, 0x00e585a9}, /* U+5169 */ - {0x00d1c1, 0x00e585aa}, /* U+516A */ - {0x00d1c2, 0x00e585ae}, /* U+516E */ - {0x00d1c3, 0x00e58680}, /* U+5180 */ - {0x00d1c4, 0x00e58682}, /* U+5182 */ - {0x00d1c5, 0x00e59b98}, /* U+56D8 */ - {0x00d1c6, 0x00e5868c}, /* U+518C */ - {0x00d1c7, 0x00e58689}, /* U+5189 */ - {0x00d1c8, 0x00e5868f}, /* U+518F */ - {0x00d1c9, 0x00e58691}, /* U+5191 */ - {0x00d1ca, 0x00e58693}, /* U+5193 */ - {0x00d1cb, 0x00e58695}, /* U+5195 */ - {0x00d1cc, 0x00e58696}, /* U+5196 */ - {0x00d1cd, 0x00e586a4}, /* U+51A4 */ - {0x00d1ce, 0x00e586a6}, /* U+51A6 */ - {0x00d1cf, 0x00e586a2}, /* U+51A2 */ - {0x00d1d0, 0x00e586a9}, /* U+51A9 */ - {0x00d1d1, 0x00e586aa}, /* U+51AA */ - {0x00d1d2, 0x00e586ab}, /* U+51AB */ - {0x00d1d3, 0x00e586b3}, /* U+51B3 */ - {0x00d1d4, 0x00e586b1}, /* U+51B1 */ - {0x00d1d5, 0x00e586b2}, /* U+51B2 */ - {0x00d1d6, 0x00e586b0}, /* U+51B0 */ - {0x00d1d7, 0x00e586b5}, /* U+51B5 */ - {0x00d1d8, 0x00e586bd}, /* U+51BD */ - {0x00d1d9, 0x00e58785}, /* U+51C5 */ - {0x00d1da, 0x00e58789}, /* U+51C9 */ - {0x00d1db, 0x00e5879b}, /* U+51DB */ - {0x00d1dc, 0x00e587a0}, /* U+51E0 */ - {0x00d1dd, 0x00e89995}, /* U+8655 */ - {0x00d1de, 0x00e587a9}, /* U+51E9 */ - {0x00d1df, 0x00e587ad}, /* U+51ED */ - {0x00d1e0, 0x00e587b0}, /* U+51F0 */ - {0x00d1e1, 0x00e587b5}, /* U+51F5 */ - {0x00d1e2, 0x00e587be}, /* U+51FE */ - {0x00d1e3, 0x00e58884}, /* U+5204 */ - {0x00d1e4, 0x00e5888b}, /* U+520B */ - {0x00d1e5, 0x00e58894}, /* U+5214 */ - {0x00d1e6, 0x00e5888e}, /* U+520E */ - {0x00d1e7, 0x00e588a7}, /* U+5227 */ - {0x00d1e8, 0x00e588aa}, /* U+522A */ - {0x00d1e9, 0x00e588ae}, /* U+522E */ - {0x00d1ea, 0x00e588b3}, /* U+5233 */ - {0x00d1eb, 0x00e588b9}, /* U+5239 */ - {0x00d1ec, 0x00e5898f}, /* U+524F */ - {0x00d1ed, 0x00e58984}, /* U+5244 */ - {0x00d1ee, 0x00e5898b}, /* U+524B */ - {0x00d1ef, 0x00e5898c}, /* U+524C */ - {0x00d1f0, 0x00e5899e}, /* U+525E */ - {0x00d1f1, 0x00e58994}, /* U+5254 */ - {0x00d1f2, 0x00e589aa}, /* U+526A */ - {0x00d1f3, 0x00e589b4}, /* U+5274 */ - {0x00d1f4, 0x00e589a9}, /* U+5269 */ - {0x00d1f5, 0x00e589b3}, /* U+5273 */ - {0x00d1f6, 0x00e589bf}, /* U+527F */ - {0x00d1f7, 0x00e589bd}, /* U+527D */ - {0x00d1f8, 0x00e58a8d}, /* U+528D */ - {0x00d1f9, 0x00e58a94}, /* U+5294 */ - {0x00d1fa, 0x00e58a92}, /* U+5292 */ - {0x00d1fb, 0x00e589b1}, /* U+5271 */ - {0x00d1fc, 0x00e58a88}, /* U+5288 */ - {0x00d1fd, 0x00e58a91}, /* U+5291 */ - {0x00d1fe, 0x00e8bea8}, /* U+8FA8 */ - {0x00d2a1, 0x00e8bea7}, /* U+8FA7 */ - {0x00d2a2, 0x00e58aac}, /* U+52AC */ - {0x00d2a3, 0x00e58aad}, /* U+52AD */ - {0x00d2a4, 0x00e58abc}, /* U+52BC */ - {0x00d2a5, 0x00e58ab5}, /* U+52B5 */ - {0x00d2a6, 0x00e58b81}, /* U+52C1 */ - {0x00d2a7, 0x00e58b8d}, /* U+52CD */ - {0x00d2a8, 0x00e58b97}, /* U+52D7 */ - {0x00d2a9, 0x00e58b9e}, /* U+52DE */ - {0x00d2aa, 0x00e58ba3}, /* U+52E3 */ - {0x00d2ab, 0x00e58ba6}, /* U+52E6 */ - {0x00d2ac, 0x00e9a3ad}, /* U+98ED */ - {0x00d2ad, 0x00e58ba0}, /* U+52E0 */ - {0x00d2ae, 0x00e58bb3}, /* U+52F3 */ - {0x00d2af, 0x00e58bb5}, /* U+52F5 */ - {0x00d2b0, 0x00e58bb8}, /* U+52F8 */ - {0x00d2b1, 0x00e58bb9}, /* U+52F9 */ - {0x00d2b2, 0x00e58c86}, /* U+5306 */ - {0x00d2b3, 0x00e58c88}, /* U+5308 */ - {0x00d2b4, 0x00e794b8}, /* U+7538 */ - {0x00d2b5, 0x00e58c8d}, /* U+530D */ - {0x00d2b6, 0x00e58c90}, /* U+5310 */ - {0x00d2b7, 0x00e58c8f}, /* U+530F */ - {0x00d2b8, 0x00e58c95}, /* U+5315 */ - {0x00d2b9, 0x00e58c9a}, /* U+531A */ - {0x00d2ba, 0x00e58ca3}, /* U+5323 */ - {0x00d2bb, 0x00e58caf}, /* U+532F */ - {0x00d2bc, 0x00e58cb1}, /* U+5331 */ - {0x00d2bd, 0x00e58cb3}, /* U+5333 */ - {0x00d2be, 0x00e58cb8}, /* U+5338 */ - {0x00d2bf, 0x00e58d80}, /* U+5340 */ - {0x00d2c0, 0x00e58d86}, /* U+5346 */ - {0x00d2c1, 0x00e58d85}, /* U+5345 */ - {0x00d2c2, 0x00e4b897}, /* U+4E17 */ - {0x00d2c3, 0x00e58d89}, /* U+5349 */ - {0x00d2c4, 0x00e58d8d}, /* U+534D */ - {0x00d2c5, 0x00e58796}, /* U+51D6 */ - {0x00d2c6, 0x00e58d9e}, /* U+535E */ - {0x00d2c7, 0x00e58da9}, /* U+5369 */ - {0x00d2c8, 0x00e58dae}, /* U+536E */ - {0x00d2c9, 0x00e5a498}, /* U+5918 */ - {0x00d2ca, 0x00e58dbb}, /* U+537B */ - {0x00d2cb, 0x00e58db7}, /* U+5377 */ - {0x00d2cc, 0x00e58e82}, /* U+5382 */ - {0x00d2cd, 0x00e58e96}, /* U+5396 */ - {0x00d2ce, 0x00e58ea0}, /* U+53A0 */ - {0x00d2cf, 0x00e58ea6}, /* U+53A6 */ - {0x00d2d0, 0x00e58ea5}, /* U+53A5 */ - {0x00d2d1, 0x00e58eae}, /* U+53AE */ - {0x00d2d2, 0x00e58eb0}, /* U+53B0 */ - {0x00d2d3, 0x00e58eb6}, /* U+53B6 */ - {0x00d2d4, 0x00e58f83}, /* U+53C3 */ - {0x00d2d5, 0x00e7b092}, /* U+7C12 */ - {0x00d2d6, 0x00e99b99}, /* U+96D9 */ - {0x00d2d7, 0x00e58f9f}, /* U+53DF */ - {0x00d2d8, 0x00e69bbc}, /* U+66FC */ - {0x00d2d9, 0x00e787ae}, /* U+71EE */ - {0x00d2da, 0x00e58fae}, /* U+53EE */ - {0x00d2db, 0x00e58fa8}, /* U+53E8 */ - {0x00d2dc, 0x00e58fad}, /* U+53ED */ - {0x00d2dd, 0x00e58fba}, /* U+53FA */ - {0x00d2de, 0x00e59081}, /* U+5401 */ - {0x00d2df, 0x00e590bd}, /* U+543D */ - {0x00d2e0, 0x00e59180}, /* U+5440 */ - {0x00d2e1, 0x00e590ac}, /* U+542C */ - {0x00d2e2, 0x00e590ad}, /* U+542D */ - {0x00d2e3, 0x00e590bc}, /* U+543C */ - {0x00d2e4, 0x00e590ae}, /* U+542E */ - {0x00d2e5, 0x00e590b6}, /* U+5436 */ - {0x00d2e6, 0x00e590a9}, /* U+5429 */ - {0x00d2e7, 0x00e5909d}, /* U+541D */ - {0x00d2e8, 0x00e5918e}, /* U+544E */ - {0x00d2e9, 0x00e5928f}, /* U+548F */ - {0x00d2ea, 0x00e591b5}, /* U+5475 */ - {0x00d2eb, 0x00e5928e}, /* U+548E */ - {0x00d2ec, 0x00e5919f}, /* U+545F */ - {0x00d2ed, 0x00e591b1}, /* U+5471 */ - {0x00d2ee, 0x00e591b7}, /* U+5477 */ - {0x00d2ef, 0x00e591b0}, /* U+5470 */ - {0x00d2f0, 0x00e59292}, /* U+5492 */ - {0x00d2f1, 0x00e591bb}, /* U+547B */ - {0x00d2f2, 0x00e59280}, /* U+5480 */ - {0x00d2f3, 0x00e591b6}, /* U+5476 */ - {0x00d2f4, 0x00e59284}, /* U+5484 */ - {0x00d2f5, 0x00e59290}, /* U+5490 */ - {0x00d2f6, 0x00e59286}, /* U+5486 */ - {0x00d2f7, 0x00e59387}, /* U+54C7 */ - {0x00d2f8, 0x00e592a2}, /* U+54A2 */ - {0x00d2f9, 0x00e592b8}, /* U+54B8 */ - {0x00d2fa, 0x00e592a5}, /* U+54A5 */ - {0x00d2fb, 0x00e592ac}, /* U+54AC */ - {0x00d2fc, 0x00e59384}, /* U+54C4 */ - {0x00d2fd, 0x00e59388}, /* U+54C8 */ - {0x00d2fe, 0x00e592a8}, /* U+54A8 */ - {0x00d3a1, 0x00e592ab}, /* U+54AB */ - {0x00d3a2, 0x00e59382}, /* U+54C2 */ - {0x00d3a3, 0x00e592a4}, /* U+54A4 */ - {0x00d3a4, 0x00e592be}, /* U+54BE */ - {0x00d3a5, 0x00e592bc}, /* U+54BC */ - {0x00d3a6, 0x00e59398}, /* U+54D8 */ - {0x00d3a7, 0x00e593a5}, /* U+54E5 */ - {0x00d3a8, 0x00e593a6}, /* U+54E6 */ - {0x00d3a9, 0x00e5948f}, /* U+550F */ - {0x00d3aa, 0x00e59494}, /* U+5514 */ - {0x00d3ab, 0x00e593bd}, /* U+54FD */ - {0x00d3ac, 0x00e593ae}, /* U+54EE */ - {0x00d3ad, 0x00e593ad}, /* U+54ED */ - {0x00d3ae, 0x00e593ba}, /* U+54FA */ - {0x00d3af, 0x00e593a2}, /* U+54E2 */ - {0x00d3b0, 0x00e594b9}, /* U+5539 */ - {0x00d3b1, 0x00e59580}, /* U+5540 */ - {0x00d3b2, 0x00e595a3}, /* U+5563 */ - {0x00d3b3, 0x00e5958c}, /* U+554C */ - {0x00d3b4, 0x00e594ae}, /* U+552E */ - {0x00d3b5, 0x00e5959c}, /* U+555C */ - {0x00d3b6, 0x00e59585}, /* U+5545 */ - {0x00d3b7, 0x00e59596}, /* U+5556 */ - {0x00d3b8, 0x00e59597}, /* U+5557 */ - {0x00d3b9, 0x00e594b8}, /* U+5538 */ - {0x00d3ba, 0x00e594b3}, /* U+5533 */ - {0x00d3bb, 0x00e5959d}, /* U+555D */ - {0x00d3bc, 0x00e59699}, /* U+5599 */ - {0x00d3bd, 0x00e59680}, /* U+5580 */ - {0x00d3be, 0x00e592af}, /* U+54AF */ - {0x00d3bf, 0x00e5968a}, /* U+558A */ - {0x00d3c0, 0x00e5969f}, /* U+559F */ - {0x00d3c1, 0x00e595bb}, /* U+557B */ - {0x00d3c2, 0x00e595be}, /* U+557E */ - {0x00d3c3, 0x00e59698}, /* U+5598 */ - {0x00d3c4, 0x00e5969e}, /* U+559E */ - {0x00d3c5, 0x00e596ae}, /* U+55AE */ - {0x00d3c6, 0x00e595bc}, /* U+557C */ - {0x00d3c7, 0x00e59683}, /* U+5583 */ - {0x00d3c8, 0x00e596a9}, /* U+55A9 */ - {0x00d3c9, 0x00e59687}, /* U+5587 */ - {0x00d3ca, 0x00e596a8}, /* U+55A8 */ - {0x00d3cb, 0x00e5979a}, /* U+55DA */ - {0x00d3cc, 0x00e59785}, /* U+55C5 */ - {0x00d3cd, 0x00e5979f}, /* U+55DF */ - {0x00d3ce, 0x00e59784}, /* U+55C4 */ - {0x00d3cf, 0x00e5979c}, /* U+55DC */ - {0x00d3d0, 0x00e597a4}, /* U+55E4 */ - {0x00d3d1, 0x00e59794}, /* U+55D4 */ - {0x00d3d2, 0x00e59894}, /* U+5614 */ - {0x00d3d3, 0x00e597b7}, /* U+55F7 */ - {0x00d3d4, 0x00e59896}, /* U+5616 */ - {0x00d3d5, 0x00e597be}, /* U+55FE */ - {0x00d3d6, 0x00e597bd}, /* U+55FD */ - {0x00d3d7, 0x00e5989b}, /* U+561B */ - {0x00d3d8, 0x00e597b9}, /* U+55F9 */ - {0x00d3d9, 0x00e5998e}, /* U+564E */ - {0x00d3da, 0x00e59990}, /* U+5650 */ - {0x00d3db, 0x00e7879f}, /* U+71DF */ - {0x00d3dc, 0x00e598b4}, /* U+5634 */ - {0x00d3dd, 0x00e598b6}, /* U+5636 */ - {0x00d3de, 0x00e598b2}, /* U+5632 */ - {0x00d3df, 0x00e598b8}, /* U+5638 */ - {0x00d3e0, 0x00e599ab}, /* U+566B */ - {0x00d3e1, 0x00e599a4}, /* U+5664 */ - {0x00d3e2, 0x00e598af}, /* U+562F */ - {0x00d3e3, 0x00e599ac}, /* U+566C */ - {0x00d3e4, 0x00e599aa}, /* U+566A */ - {0x00d3e5, 0x00e59a86}, /* U+5686 */ - {0x00d3e6, 0x00e59a80}, /* U+5680 */ - {0x00d3e7, 0x00e59a8a}, /* U+568A */ - {0x00d3e8, 0x00e59aa0}, /* U+56A0 */ - {0x00d3e9, 0x00e59a94}, /* U+5694 */ - {0x00d3ea, 0x00e59a8f}, /* U+568F */ - {0x00d3eb, 0x00e59aa5}, /* U+56A5 */ - {0x00d3ec, 0x00e59aae}, /* U+56AE */ - {0x00d3ed, 0x00e59ab6}, /* U+56B6 */ - {0x00d3ee, 0x00e59ab4}, /* U+56B4 */ - {0x00d3ef, 0x00e59b82}, /* U+56C2 */ - {0x00d3f0, 0x00e59abc}, /* U+56BC */ - {0x00d3f1, 0x00e59b81}, /* U+56C1 */ - {0x00d3f2, 0x00e59b83}, /* U+56C3 */ - {0x00d3f3, 0x00e59b80}, /* U+56C0 */ - {0x00d3f4, 0x00e59b88}, /* U+56C8 */ - {0x00d3f5, 0x00e59b8e}, /* U+56CE */ - {0x00d3f6, 0x00e59b91}, /* U+56D1 */ - {0x00d3f7, 0x00e59b93}, /* U+56D3 */ - {0x00d3f8, 0x00e59b97}, /* U+56D7 */ - {0x00d3f9, 0x00e59bae}, /* U+56EE */ - {0x00d3fa, 0x00e59bb9}, /* U+56F9 */ - {0x00d3fb, 0x00e59c80}, /* U+5700 */ - {0x00d3fc, 0x00e59bbf}, /* U+56FF */ - {0x00d3fd, 0x00e59c84}, /* U+5704 */ - {0x00d3fe, 0x00e59c89}, /* U+5709 */ - {0x00d4a1, 0x00e59c88}, /* U+5708 */ - {0x00d4a2, 0x00e59c8b}, /* U+570B */ - {0x00d4a3, 0x00e59c8d}, /* U+570D */ - {0x00d4a4, 0x00e59c93}, /* U+5713 */ - {0x00d4a5, 0x00e59c98}, /* U+5718 */ - {0x00d4a6, 0x00e59c96}, /* U+5716 */ - {0x00d4a7, 0x00e59787}, /* U+55C7 */ - {0x00d4a8, 0x00e59c9c}, /* U+571C */ - {0x00d4a9, 0x00e59ca6}, /* U+5726 */ - {0x00d4aa, 0x00e59cb7}, /* U+5737 */ - {0x00d4ab, 0x00e59cb8}, /* U+5738 */ - {0x00d4ac, 0x00e59d8e}, /* U+574E */ - {0x00d4ad, 0x00e59cbb}, /* U+573B */ - {0x00d4ae, 0x00e59d80}, /* U+5740 */ - {0x00d4af, 0x00e59d8f}, /* U+574F */ - {0x00d4b0, 0x00e59da9}, /* U+5769 */ - {0x00d4b1, 0x00e59f80}, /* U+57C0 */ - {0x00d4b2, 0x00e59e88}, /* U+5788 */ - {0x00d4b3, 0x00e59da1}, /* U+5761 */ - {0x00d4b4, 0x00e59dbf}, /* U+577F */ - {0x00d4b5, 0x00e59e89}, /* U+5789 */ - {0x00d4b6, 0x00e59e93}, /* U+5793 */ - {0x00d4b7, 0x00e59ea0}, /* U+57A0 */ - {0x00d4b8, 0x00e59eb3}, /* U+57B3 */ - {0x00d4b9, 0x00e59ea4}, /* U+57A4 */ - {0x00d4ba, 0x00e59eaa}, /* U+57AA */ - {0x00d4bb, 0x00e59eb0}, /* U+57B0 */ - {0x00d4bc, 0x00e59f83}, /* U+57C3 */ - {0x00d4bd, 0x00e59f86}, /* U+57C6 */ - {0x00d4be, 0x00e59f94}, /* U+57D4 */ - {0x00d4bf, 0x00e59f92}, /* U+57D2 */ - {0x00d4c0, 0x00e59f93}, /* U+57D3 */ - {0x00d4c1, 0x00e5a08a}, /* U+580A */ - {0x00d4c2, 0x00e59f96}, /* U+57D6 */ - {0x00d4c3, 0x00e59fa3}, /* U+57E3 */ - {0x00d4c4, 0x00e5a08b}, /* U+580B */ - {0x00d4c5, 0x00e5a099}, /* U+5819 */ - {0x00d4c6, 0x00e5a09d}, /* U+581D */ - {0x00d4c7, 0x00e5a1b2}, /* U+5872 */ - {0x00d4c8, 0x00e5a0a1}, /* U+5821 */ - {0x00d4c9, 0x00e5a1a2}, /* U+5862 */ - {0x00d4ca, 0x00e5a18b}, /* U+584B */ - {0x00d4cb, 0x00e5a1b0}, /* U+5870 */ - {0x00d4cc, 0x00e6af80}, /* U+6BC0 */ - {0x00d4cd, 0x00e5a192}, /* U+5852 */ - {0x00d4ce, 0x00e5a0bd}, /* U+583D */ - {0x00d4cf, 0x00e5a1b9}, /* U+5879 */ - {0x00d4d0, 0x00e5a285}, /* U+5885 */ - {0x00d4d1, 0x00e5a2b9}, /* U+58B9 */ - {0x00d4d2, 0x00e5a29f}, /* U+589F */ - {0x00d4d3, 0x00e5a2ab}, /* U+58AB */ - {0x00d4d4, 0x00e5a2ba}, /* U+58BA */ - {0x00d4d5, 0x00e5a39e}, /* U+58DE */ - {0x00d4d6, 0x00e5a2bb}, /* U+58BB */ - {0x00d4d7, 0x00e5a2b8}, /* U+58B8 */ - {0x00d4d8, 0x00e5a2ae}, /* U+58AE */ - {0x00d4d9, 0x00e5a385}, /* U+58C5 */ - {0x00d4da, 0x00e5a393}, /* U+58D3 */ - {0x00d4db, 0x00e5a391}, /* U+58D1 */ - {0x00d4dc, 0x00e5a397}, /* U+58D7 */ - {0x00d4dd, 0x00e5a399}, /* U+58D9 */ - {0x00d4de, 0x00e5a398}, /* U+58D8 */ - {0x00d4df, 0x00e5a3a5}, /* U+58E5 */ - {0x00d4e0, 0x00e5a39c}, /* U+58DC */ - {0x00d4e1, 0x00e5a3a4}, /* U+58E4 */ - {0x00d4e2, 0x00e5a39f}, /* U+58DF */ - {0x00d4e3, 0x00e5a3af}, /* U+58EF */ - {0x00d4e4, 0x00e5a3ba}, /* U+58FA */ - {0x00d4e5, 0x00e5a3b9}, /* U+58F9 */ - {0x00d4e6, 0x00e5a3bb}, /* U+58FB */ - {0x00d4e7, 0x00e5a3bc}, /* U+58FC */ - {0x00d4e8, 0x00e5a3bd}, /* U+58FD */ - {0x00d4e9, 0x00e5a482}, /* U+5902 */ - {0x00d4ea, 0x00e5a48a}, /* U+590A */ - {0x00d4eb, 0x00e5a490}, /* U+5910 */ - {0x00d4ec, 0x00e5a49b}, /* U+591B */ - {0x00d4ed, 0x00e6a2a6}, /* U+68A6 */ - {0x00d4ee, 0x00e5a4a5}, /* U+5925 */ - {0x00d4ef, 0x00e5a4ac}, /* U+592C */ - {0x00d4f0, 0x00e5a4ad}, /* U+592D */ - {0x00d4f1, 0x00e5a4b2}, /* U+5932 */ - {0x00d4f2, 0x00e5a4b8}, /* U+5938 */ - {0x00d4f3, 0x00e5a4be}, /* U+593E */ - {0x00d4f4, 0x00e7ab92}, /* U+7AD2 */ - {0x00d4f5, 0x00e5a595}, /* U+5955 */ - {0x00d4f6, 0x00e5a590}, /* U+5950 */ - {0x00d4f7, 0x00e5a58e}, /* U+594E */ - {0x00d4f8, 0x00e5a59a}, /* U+595A */ - {0x00d4f9, 0x00e5a598}, /* U+5958 */ - {0x00d4fa, 0x00e5a5a2}, /* U+5962 */ - {0x00d4fb, 0x00e5a5a0}, /* U+5960 */ - {0x00d4fc, 0x00e5a5a7}, /* U+5967 */ - {0x00d4fd, 0x00e5a5ac}, /* U+596C */ - {0x00d4fe, 0x00e5a5a9}, /* U+5969 */ - {0x00d5a1, 0x00e5a5b8}, /* U+5978 */ - {0x00d5a2, 0x00e5a681}, /* U+5981 */ - {0x00d5a3, 0x00e5a69d}, /* U+599D */ - {0x00d5a4, 0x00e4bd9e}, /* U+4F5E */ - {0x00d5a5, 0x00e4beab}, /* U+4FAB */ - {0x00d5a6, 0x00e5a6a3}, /* U+59A3 */ - {0x00d5a7, 0x00e5a6b2}, /* U+59B2 */ - {0x00d5a8, 0x00e5a786}, /* U+59C6 */ - {0x00d5a9, 0x00e5a7a8}, /* U+59E8 */ - {0x00d5aa, 0x00e5a79c}, /* U+59DC */ - {0x00d5ab, 0x00e5a68d}, /* U+598D */ - {0x00d5ac, 0x00e5a799}, /* U+59D9 */ - {0x00d5ad, 0x00e5a79a}, /* U+59DA */ - {0x00d5ae, 0x00e5a8a5}, /* U+5A25 */ - {0x00d5af, 0x00e5a89f}, /* U+5A1F */ - {0x00d5b0, 0x00e5a891}, /* U+5A11 */ - {0x00d5b1, 0x00e5a89c}, /* U+5A1C */ - {0x00d5b2, 0x00e5a889}, /* U+5A09 */ - {0x00d5b3, 0x00e5a89a}, /* U+5A1A */ - {0x00d5b4, 0x00e5a980}, /* U+5A40 */ - {0x00d5b5, 0x00e5a9ac}, /* U+5A6C */ - {0x00d5b6, 0x00e5a989}, /* U+5A49 */ - {0x00d5b7, 0x00e5a8b5}, /* U+5A35 */ - {0x00d5b8, 0x00e5a8b6}, /* U+5A36 */ - {0x00d5b9, 0x00e5a9a2}, /* U+5A62 */ - {0x00d5ba, 0x00e5a9aa}, /* U+5A6A */ - {0x00d5bb, 0x00e5aa9a}, /* U+5A9A */ - {0x00d5bc, 0x00e5aabc}, /* U+5ABC */ - {0x00d5bd, 0x00e5aabe}, /* U+5ABE */ - {0x00d5be, 0x00e5ab8b}, /* U+5ACB */ - {0x00d5bf, 0x00e5ab82}, /* U+5AC2 */ - {0x00d5c0, 0x00e5aabd}, /* U+5ABD */ - {0x00d5c1, 0x00e5aba3}, /* U+5AE3 */ - {0x00d5c2, 0x00e5ab97}, /* U+5AD7 */ - {0x00d5c3, 0x00e5aba6}, /* U+5AE6 */ - {0x00d5c4, 0x00e5aba9}, /* U+5AE9 */ - {0x00d5c5, 0x00e5ab96}, /* U+5AD6 */ - {0x00d5c6, 0x00e5abba}, /* U+5AFA */ - {0x00d5c7, 0x00e5abbb}, /* U+5AFB */ - {0x00d5c8, 0x00e5ac8c}, /* U+5B0C */ - {0x00d5c9, 0x00e5ac8b}, /* U+5B0B */ - {0x00d5ca, 0x00e5ac96}, /* U+5B16 */ - {0x00d5cb, 0x00e5acb2}, /* U+5B32 */ - {0x00d5cc, 0x00e5ab90}, /* U+5AD0 */ - {0x00d5cd, 0x00e5acaa}, /* U+5B2A */ - {0x00d5ce, 0x00e5acb6}, /* U+5B36 */ - {0x00d5cf, 0x00e5acbe}, /* U+5B3E */ - {0x00d5d0, 0x00e5ad83}, /* U+5B43 */ - {0x00d5d1, 0x00e5ad85}, /* U+5B45 */ - {0x00d5d2, 0x00e5ad80}, /* U+5B40 */ - {0x00d5d3, 0x00e5ad91}, /* U+5B51 */ - {0x00d5d4, 0x00e5ad95}, /* U+5B55 */ - {0x00d5d5, 0x00e5ad9a}, /* U+5B5A */ - {0x00d5d6, 0x00e5ad9b}, /* U+5B5B */ - {0x00d5d7, 0x00e5ada5}, /* U+5B65 */ - {0x00d5d8, 0x00e5ada9}, /* U+5B69 */ - {0x00d5d9, 0x00e5adb0}, /* U+5B70 */ - {0x00d5da, 0x00e5adb3}, /* U+5B73 */ - {0x00d5db, 0x00e5adb5}, /* U+5B75 */ - {0x00d5dc, 0x00e5adb8}, /* U+5B78 */ - {0x00d5dd, 0x00e69688}, /* U+6588 */ - {0x00d5de, 0x00e5adba}, /* U+5B7A */ - {0x00d5df, 0x00e5ae80}, /* U+5B80 */ - {0x00d5e0, 0x00e5ae83}, /* U+5B83 */ - {0x00d5e1, 0x00e5aea6}, /* U+5BA6 */ - {0x00d5e2, 0x00e5aeb8}, /* U+5BB8 */ - {0x00d5e3, 0x00e5af83}, /* U+5BC3 */ - {0x00d5e4, 0x00e5af87}, /* U+5BC7 */ - {0x00d5e5, 0x00e5af89}, /* U+5BC9 */ - {0x00d5e6, 0x00e5af94}, /* U+5BD4 */ - {0x00d5e7, 0x00e5af90}, /* U+5BD0 */ - {0x00d5e8, 0x00e5afa4}, /* U+5BE4 */ - {0x00d5e9, 0x00e5afa6}, /* U+5BE6 */ - {0x00d5ea, 0x00e5afa2}, /* U+5BE2 */ - {0x00d5eb, 0x00e5af9e}, /* U+5BDE */ - {0x00d5ec, 0x00e5afa5}, /* U+5BE5 */ - {0x00d5ed, 0x00e5afab}, /* U+5BEB */ - {0x00d5ee, 0x00e5afb0}, /* U+5BF0 */ - {0x00d5ef, 0x00e5afb6}, /* U+5BF6 */ - {0x00d5f0, 0x00e5afb3}, /* U+5BF3 */ - {0x00d5f1, 0x00e5b085}, /* U+5C05 */ - {0x00d5f2, 0x00e5b087}, /* U+5C07 */ - {0x00d5f3, 0x00e5b088}, /* U+5C08 */ - {0x00d5f4, 0x00e5b08d}, /* U+5C0D */ - {0x00d5f5, 0x00e5b093}, /* U+5C13 */ - {0x00d5f6, 0x00e5b0a0}, /* U+5C20 */ - {0x00d5f7, 0x00e5b0a2}, /* U+5C22 */ - {0x00d5f8, 0x00e5b0a8}, /* U+5C28 */ - {0x00d5f9, 0x00e5b0b8}, /* U+5C38 */ - {0x00d5fa, 0x00e5b0b9}, /* U+5C39 */ - {0x00d5fb, 0x00e5b181}, /* U+5C41 */ - {0x00d5fc, 0x00e5b186}, /* U+5C46 */ - {0x00d5fd, 0x00e5b18e}, /* U+5C4E */ - {0x00d5fe, 0x00e5b193}, /* U+5C53 */ - {0x00d6a1, 0x00e5b190}, /* U+5C50 */ - {0x00d6a2, 0x00e5b18f}, /* U+5C4F */ - {0x00d6a3, 0x00e5adb1}, /* U+5B71 */ - {0x00d6a4, 0x00e5b1ac}, /* U+5C6C */ - {0x00d6a5, 0x00e5b1ae}, /* U+5C6E */ - {0x00d6a6, 0x00e4b9a2}, /* U+4E62 */ - {0x00d6a7, 0x00e5b1b6}, /* U+5C76 */ - {0x00d6a8, 0x00e5b1b9}, /* U+5C79 */ - {0x00d6a9, 0x00e5b28c}, /* U+5C8C */ - {0x00d6aa, 0x00e5b291}, /* U+5C91 */ - {0x00d6ab, 0x00e5b294}, /* U+5C94 */ - {0x00d6ac, 0x00e5a69b}, /* U+599B */ - {0x00d6ad, 0x00e5b2ab}, /* U+5CAB */ - {0x00d6ae, 0x00e5b2bb}, /* U+5CBB */ - {0x00d6af, 0x00e5b2b6}, /* U+5CB6 */ - {0x00d6b0, 0x00e5b2bc}, /* U+5CBC */ - {0x00d6b1, 0x00e5b2b7}, /* U+5CB7 */ - {0x00d6b2, 0x00e5b385}, /* U+5CC5 */ - {0x00d6b3, 0x00e5b2be}, /* U+5CBE */ - {0x00d6b4, 0x00e5b387}, /* U+5CC7 */ - {0x00d6b5, 0x00e5b399}, /* U+5CD9 */ - {0x00d6b6, 0x00e5b3a9}, /* U+5CE9 */ - {0x00d6b7, 0x00e5b3bd}, /* U+5CFD */ - {0x00d6b8, 0x00e5b3ba}, /* U+5CFA */ - {0x00d6b9, 0x00e5b3ad}, /* U+5CED */ - {0x00d6ba, 0x00e5b68c}, /* U+5D8C */ - {0x00d6bb, 0x00e5b3aa}, /* U+5CEA */ - {0x00d6bc, 0x00e5b48b}, /* U+5D0B */ - {0x00d6bd, 0x00e5b495}, /* U+5D15 */ - {0x00d6be, 0x00e5b497}, /* U+5D17 */ - {0x00d6bf, 0x00e5b59c}, /* U+5D5C */ - {0x00d6c0, 0x00e5b49f}, /* U+5D1F */ - {0x00d6c1, 0x00e5b49b}, /* U+5D1B */ - {0x00d6c2, 0x00e5b491}, /* U+5D11 */ - {0x00d6c3, 0x00e5b494}, /* U+5D14 */ - {0x00d6c4, 0x00e5b4a2}, /* U+5D22 */ - {0x00d6c5, 0x00e5b49a}, /* U+5D1A */ - {0x00d6c6, 0x00e5b499}, /* U+5D19 */ - {0x00d6c7, 0x00e5b498}, /* U+5D18 */ - {0x00d6c8, 0x00e5b58c}, /* U+5D4C */ - {0x00d6c9, 0x00e5b592}, /* U+5D52 */ - {0x00d6ca, 0x00e5b58e}, /* U+5D4E */ - {0x00d6cb, 0x00e5b58b}, /* U+5D4B */ - {0x00d6cc, 0x00e5b5ac}, /* U+5D6C */ - {0x00d6cd, 0x00e5b5b3}, /* U+5D73 */ - {0x00d6ce, 0x00e5b5b6}, /* U+5D76 */ - {0x00d6cf, 0x00e5b687}, /* U+5D87 */ - {0x00d6d0, 0x00e5b684}, /* U+5D84 */ - {0x00d6d1, 0x00e5b682}, /* U+5D82 */ - {0x00d6d2, 0x00e5b6a2}, /* U+5DA2 */ - {0x00d6d3, 0x00e5b69d}, /* U+5D9D */ - {0x00d6d4, 0x00e5b6ac}, /* U+5DAC */ - {0x00d6d5, 0x00e5b6ae}, /* U+5DAE */ - {0x00d6d6, 0x00e5b6bd}, /* U+5DBD */ - {0x00d6d7, 0x00e5b690}, /* U+5D90 */ - {0x00d6d8, 0x00e5b6b7}, /* U+5DB7 */ - {0x00d6d9, 0x00e5b6bc}, /* U+5DBC */ - {0x00d6da, 0x00e5b789}, /* U+5DC9 */ - {0x00d6db, 0x00e5b78d}, /* U+5DCD */ - {0x00d6dc, 0x00e5b793}, /* U+5DD3 */ - {0x00d6dd, 0x00e5b792}, /* U+5DD2 */ - {0x00d6de, 0x00e5b796}, /* U+5DD6 */ - {0x00d6df, 0x00e5b79b}, /* U+5DDB */ - {0x00d6e0, 0x00e5b7ab}, /* U+5DEB */ - {0x00d6e1, 0x00e5b7b2}, /* U+5DF2 */ - {0x00d6e2, 0x00e5b7b5}, /* U+5DF5 */ - {0x00d6e3, 0x00e5b88b}, /* U+5E0B */ - {0x00d6e4, 0x00e5b89a}, /* U+5E1A */ - {0x00d6e5, 0x00e5b899}, /* U+5E19 */ - {0x00d6e6, 0x00e5b891}, /* U+5E11 */ - {0x00d6e7, 0x00e5b89b}, /* U+5E1B */ - {0x00d6e8, 0x00e5b8b6}, /* U+5E36 */ - {0x00d6e9, 0x00e5b8b7}, /* U+5E37 */ - {0x00d6ea, 0x00e5b984}, /* U+5E44 */ - {0x00d6eb, 0x00e5b983}, /* U+5E43 */ - {0x00d6ec, 0x00e5b980}, /* U+5E40 */ - {0x00d6ed, 0x00e5b98e}, /* U+5E4E */ - {0x00d6ee, 0x00e5b997}, /* U+5E57 */ - {0x00d6ef, 0x00e5b994}, /* U+5E54 */ - {0x00d6f0, 0x00e5b99f}, /* U+5E5F */ - {0x00d6f1, 0x00e5b9a2}, /* U+5E62 */ - {0x00d6f2, 0x00e5b9a4}, /* U+5E64 */ - {0x00d6f3, 0x00e5b987}, /* U+5E47 */ - {0x00d6f4, 0x00e5b9b5}, /* U+5E75 */ - {0x00d6f5, 0x00e5b9b6}, /* U+5E76 */ - {0x00d6f6, 0x00e5b9ba}, /* U+5E7A */ - {0x00d6f7, 0x00e9babc}, /* U+9EBC */ - {0x00d6f8, 0x00e5b9bf}, /* U+5E7F */ - {0x00d6f9, 0x00e5baa0}, /* U+5EA0 */ - {0x00d6fa, 0x00e5bb81}, /* U+5EC1 */ - {0x00d6fb, 0x00e5bb82}, /* U+5EC2 */ - {0x00d6fc, 0x00e5bb88}, /* U+5EC8 */ - {0x00d6fd, 0x00e5bb90}, /* U+5ED0 */ - {0x00d6fe, 0x00e5bb8f}, /* U+5ECF */ - {0x00d7a1, 0x00e5bb96}, /* U+5ED6 */ - {0x00d7a2, 0x00e5bba3}, /* U+5EE3 */ - {0x00d7a3, 0x00e5bb9d}, /* U+5EDD */ - {0x00d7a4, 0x00e5bb9a}, /* U+5EDA */ - {0x00d7a5, 0x00e5bb9b}, /* U+5EDB */ - {0x00d7a6, 0x00e5bba2}, /* U+5EE2 */ - {0x00d7a7, 0x00e5bba1}, /* U+5EE1 */ - {0x00d7a8, 0x00e5bba8}, /* U+5EE8 */ - {0x00d7a9, 0x00e5bba9}, /* U+5EE9 */ - {0x00d7aa, 0x00e5bbac}, /* U+5EEC */ - {0x00d7ab, 0x00e5bbb1}, /* U+5EF1 */ - {0x00d7ac, 0x00e5bbb3}, /* U+5EF3 */ - {0x00d7ad, 0x00e5bbb0}, /* U+5EF0 */ - {0x00d7ae, 0x00e5bbb4}, /* U+5EF4 */ - {0x00d7af, 0x00e5bbb8}, /* U+5EF8 */ - {0x00d7b0, 0x00e5bbbe}, /* U+5EFE */ - {0x00d7b1, 0x00e5bc83}, /* U+5F03 */ - {0x00d7b2, 0x00e5bc89}, /* U+5F09 */ - {0x00d7b3, 0x00e5bd9d}, /* U+5F5D */ - {0x00d7b4, 0x00e5bd9c}, /* U+5F5C */ - {0x00d7b5, 0x00e5bc8b}, /* U+5F0B */ - {0x00d7b6, 0x00e5bc91}, /* U+5F11 */ - {0x00d7b7, 0x00e5bc96}, /* U+5F16 */ - {0x00d7b8, 0x00e5bca9}, /* U+5F29 */ - {0x00d7b9, 0x00e5bcad}, /* U+5F2D */ - {0x00d7ba, 0x00e5bcb8}, /* U+5F38 */ - {0x00d7bb, 0x00e5bd81}, /* U+5F41 */ - {0x00d7bc, 0x00e5bd88}, /* U+5F48 */ - {0x00d7bd, 0x00e5bd8c}, /* U+5F4C */ - {0x00d7be, 0x00e5bd8e}, /* U+5F4E */ - {0x00d7bf, 0x00e5bcaf}, /* U+5F2F */ - {0x00d7c0, 0x00e5bd91}, /* U+5F51 */ - {0x00d7c1, 0x00e5bd96}, /* U+5F56 */ - {0x00d7c2, 0x00e5bd97}, /* U+5F57 */ - {0x00d7c3, 0x00e5bd99}, /* U+5F59 */ - {0x00d7c4, 0x00e5bda1}, /* U+5F61 */ - {0x00d7c5, 0x00e5bdad}, /* U+5F6D */ - {0x00d7c6, 0x00e5bdb3}, /* U+5F73 */ - {0x00d7c7, 0x00e5bdb7}, /* U+5F77 */ - {0x00d7c8, 0x00e5be83}, /* U+5F83 */ - {0x00d7c9, 0x00e5be82}, /* U+5F82 */ - {0x00d7ca, 0x00e5bdbf}, /* U+5F7F */ - {0x00d7cb, 0x00e5be8a}, /* U+5F8A */ - {0x00d7cc, 0x00e5be88}, /* U+5F88 */ - {0x00d7cd, 0x00e5be91}, /* U+5F91 */ - {0x00d7ce, 0x00e5be87}, /* U+5F87 */ - {0x00d7cf, 0x00e5be9e}, /* U+5F9E */ - {0x00d7d0, 0x00e5be99}, /* U+5F99 */ - {0x00d7d1, 0x00e5be98}, /* U+5F98 */ - {0x00d7d2, 0x00e5bea0}, /* U+5FA0 */ - {0x00d7d3, 0x00e5bea8}, /* U+5FA8 */ - {0x00d7d4, 0x00e5bead}, /* U+5FAD */ - {0x00d7d5, 0x00e5bebc}, /* U+5FBC */ - {0x00d7d6, 0x00e5bf96}, /* U+5FD6 */ - {0x00d7d7, 0x00e5bfbb}, /* U+5FFB */ - {0x00d7d8, 0x00e5bfa4}, /* U+5FE4 */ - {0x00d7d9, 0x00e5bfb8}, /* U+5FF8 */ - {0x00d7da, 0x00e5bfb1}, /* U+5FF1 */ - {0x00d7db, 0x00e5bf9d}, /* U+5FDD */ - {0x00d7dc, 0x00e682b3}, /* U+60B3 */ - {0x00d7dd, 0x00e5bfbf}, /* U+5FFF */ - {0x00d7de, 0x00e680a1}, /* U+6021 */ - {0x00d7df, 0x00e681a0}, /* U+6060 */ - {0x00d7e0, 0x00e68099}, /* U+6019 */ - {0x00d7e1, 0x00e68090}, /* U+6010 */ - {0x00d7e2, 0x00e680a9}, /* U+6029 */ - {0x00d7e3, 0x00e6808e}, /* U+600E */ - {0x00d7e4, 0x00e680b1}, /* U+6031 */ - {0x00d7e5, 0x00e6809b}, /* U+601B */ - {0x00d7e6, 0x00e68095}, /* U+6015 */ - {0x00d7e7, 0x00e680ab}, /* U+602B */ - {0x00d7e8, 0x00e680a6}, /* U+6026 */ - {0x00d7e9, 0x00e6808f}, /* U+600F */ - {0x00d7ea, 0x00e680ba}, /* U+603A */ - {0x00d7eb, 0x00e6819a}, /* U+605A */ - {0x00d7ec, 0x00e68181}, /* U+6041 */ - {0x00d7ed, 0x00e681aa}, /* U+606A */ - {0x00d7ee, 0x00e681b7}, /* U+6077 */ - {0x00d7ef, 0x00e6819f}, /* U+605F */ - {0x00d7f0, 0x00e6818a}, /* U+604A */ - {0x00d7f1, 0x00e68186}, /* U+6046 */ - {0x00d7f2, 0x00e6818d}, /* U+604D */ - {0x00d7f3, 0x00e681a3}, /* U+6063 */ - {0x00d7f4, 0x00e68183}, /* U+6043 */ - {0x00d7f5, 0x00e681a4}, /* U+6064 */ - {0x00d7f6, 0x00e68182}, /* U+6042 */ - {0x00d7f7, 0x00e681ac}, /* U+606C */ - {0x00d7f8, 0x00e681ab}, /* U+606B */ - {0x00d7f9, 0x00e68199}, /* U+6059 */ - {0x00d7fa, 0x00e68281}, /* U+6081 */ - {0x00d7fb, 0x00e6828d}, /* U+608D */ - {0x00d7fc, 0x00e683a7}, /* U+60E7 */ - {0x00d7fd, 0x00e68283}, /* U+6083 */ - {0x00d7fe, 0x00e6829a}, /* U+609A */ - {0x00d8a1, 0x00e68284}, /* U+6084 */ - {0x00d8a2, 0x00e6829b}, /* U+609B */ - {0x00d8a3, 0x00e68296}, /* U+6096 */ - {0x00d8a4, 0x00e68297}, /* U+6097 */ - {0x00d8a5, 0x00e68292}, /* U+6092 */ - {0x00d8a6, 0x00e682a7}, /* U+60A7 */ - {0x00d8a7, 0x00e6828b}, /* U+608B */ - {0x00d8a8, 0x00e683a1}, /* U+60E1 */ - {0x00d8a9, 0x00e682b8}, /* U+60B8 */ - {0x00d8aa, 0x00e683a0}, /* U+60E0 */ - {0x00d8ab, 0x00e68393}, /* U+60D3 */ - {0x00d8ac, 0x00e682b4}, /* U+60B4 */ - {0x00d8ad, 0x00e5bfb0}, /* U+5FF0 */ - {0x00d8ae, 0x00e682bd}, /* U+60BD */ - {0x00d8af, 0x00e68386}, /* U+60C6 */ - {0x00d8b0, 0x00e682b5}, /* U+60B5 */ - {0x00d8b1, 0x00e68398}, /* U+60D8 */ - {0x00d8b2, 0x00e6858d}, /* U+614D */ - {0x00d8b3, 0x00e68495}, /* U+6115 */ - {0x00d8b4, 0x00e68486}, /* U+6106 */ - {0x00d8b5, 0x00e683b6}, /* U+60F6 */ - {0x00d8b6, 0x00e683b7}, /* U+60F7 */ - {0x00d8b7, 0x00e68480}, /* U+6100 */ - {0x00d8b8, 0x00e683b4}, /* U+60F4 */ - {0x00d8b9, 0x00e683ba}, /* U+60FA */ - {0x00d8ba, 0x00e68483}, /* U+6103 */ - {0x00d8bb, 0x00e684a1}, /* U+6121 */ - {0x00d8bc, 0x00e683bb}, /* U+60FB */ - {0x00d8bd, 0x00e683b1}, /* U+60F1 */ - {0x00d8be, 0x00e6848d}, /* U+610D */ - {0x00d8bf, 0x00e6848e}, /* U+610E */ - {0x00d8c0, 0x00e68587}, /* U+6147 */ - {0x00d8c1, 0x00e684be}, /* U+613E */ - {0x00d8c2, 0x00e684a8}, /* U+6128 */ - {0x00d8c3, 0x00e684a7}, /* U+6127 */ - {0x00d8c4, 0x00e6858a}, /* U+614A */ - {0x00d8c5, 0x00e684bf}, /* U+613F */ - {0x00d8c6, 0x00e684bc}, /* U+613C */ - {0x00d8c7, 0x00e684ac}, /* U+612C */ - {0x00d8c8, 0x00e684b4}, /* U+6134 */ - {0x00d8c9, 0x00e684bd}, /* U+613D */ - {0x00d8ca, 0x00e68582}, /* U+6142 */ - {0x00d8cb, 0x00e68584}, /* U+6144 */ - {0x00d8cc, 0x00e685b3}, /* U+6173 */ - {0x00d8cd, 0x00e685b7}, /* U+6177 */ - {0x00d8ce, 0x00e68598}, /* U+6158 */ - {0x00d8cf, 0x00e68599}, /* U+6159 */ - {0x00d8d0, 0x00e6859a}, /* U+615A */ - {0x00d8d1, 0x00e685ab}, /* U+616B */ - {0x00d8d2, 0x00e685b4}, /* U+6174 */ - {0x00d8d3, 0x00e685af}, /* U+616F */ - {0x00d8d4, 0x00e685a5}, /* U+6165 */ - {0x00d8d5, 0x00e685b1}, /* U+6171 */ - {0x00d8d6, 0x00e6859f}, /* U+615F */ - {0x00d8d7, 0x00e6859d}, /* U+615D */ - {0x00d8d8, 0x00e68593}, /* U+6153 */ - {0x00d8d9, 0x00e685b5}, /* U+6175 */ - {0x00d8da, 0x00e68699}, /* U+6199 */ - {0x00d8db, 0x00e68696}, /* U+6196 */ - {0x00d8dc, 0x00e68687}, /* U+6187 */ - {0x00d8dd, 0x00e686ac}, /* U+61AC */ - {0x00d8de, 0x00e68694}, /* U+6194 */ - {0x00d8df, 0x00e6869a}, /* U+619A */ - {0x00d8e0, 0x00e6868a}, /* U+618A */ - {0x00d8e1, 0x00e68691}, /* U+6191 */ - {0x00d8e2, 0x00e686ab}, /* U+61AB */ - {0x00d8e3, 0x00e686ae}, /* U+61AE */ - {0x00d8e4, 0x00e6878c}, /* U+61CC */ - {0x00d8e5, 0x00e6878a}, /* U+61CA */ - {0x00d8e6, 0x00e68789}, /* U+61C9 */ - {0x00d8e7, 0x00e687b7}, /* U+61F7 */ - {0x00d8e8, 0x00e68788}, /* U+61C8 */ - {0x00d8e9, 0x00e68783}, /* U+61C3 */ - {0x00d8ea, 0x00e68786}, /* U+61C6 */ - {0x00d8eb, 0x00e686ba}, /* U+61BA */ - {0x00d8ec, 0x00e6878b}, /* U+61CB */ - {0x00d8ed, 0x00e7bdb9}, /* U+7F79 */ - {0x00d8ee, 0x00e6878d}, /* U+61CD */ - {0x00d8ef, 0x00e687a6}, /* U+61E6 */ - {0x00d8f0, 0x00e687a3}, /* U+61E3 */ - {0x00d8f1, 0x00e687b6}, /* U+61F6 */ - {0x00d8f2, 0x00e687ba}, /* U+61FA */ - {0x00d8f3, 0x00e687b4}, /* U+61F4 */ - {0x00d8f4, 0x00e687bf}, /* U+61FF */ - {0x00d8f5, 0x00e687bd}, /* U+61FD */ - {0x00d8f6, 0x00e687bc}, /* U+61FC */ - {0x00d8f7, 0x00e687be}, /* U+61FE */ - {0x00d8f8, 0x00e68880}, /* U+6200 */ - {0x00d8f9, 0x00e68888}, /* U+6208 */ - {0x00d8fa, 0x00e68889}, /* U+6209 */ - {0x00d8fb, 0x00e6888d}, /* U+620D */ - {0x00d8fc, 0x00e6888c}, /* U+620C */ - {0x00d8fd, 0x00e68894}, /* U+6214 */ - {0x00d8fe, 0x00e6889b}, /* U+621B */ - {0x00d9a1, 0x00e6889e}, /* U+621E */ - {0x00d9a2, 0x00e688a1}, /* U+6221 */ - {0x00d9a3, 0x00e688aa}, /* U+622A */ - {0x00d9a4, 0x00e688ae}, /* U+622E */ - {0x00d9a5, 0x00e688b0}, /* U+6230 */ - {0x00d9a6, 0x00e688b2}, /* U+6232 */ - {0x00d9a7, 0x00e688b3}, /* U+6233 */ - {0x00d9a8, 0x00e68981}, /* U+6241 */ - {0x00d9a9, 0x00e6898e}, /* U+624E */ - {0x00d9aa, 0x00e6899e}, /* U+625E */ - {0x00d9ab, 0x00e689a3}, /* U+6263 */ - {0x00d9ac, 0x00e6899b}, /* U+625B */ - {0x00d9ad, 0x00e689a0}, /* U+6260 */ - {0x00d9ae, 0x00e689a8}, /* U+6268 */ - {0x00d9af, 0x00e689bc}, /* U+627C */ - {0x00d9b0, 0x00e68a82}, /* U+6282 */ - {0x00d9b1, 0x00e68a89}, /* U+6289 */ - {0x00d9b2, 0x00e689be}, /* U+627E */ - {0x00d9b3, 0x00e68a92}, /* U+6292 */ - {0x00d9b4, 0x00e68a93}, /* U+6293 */ - {0x00d9b5, 0x00e68a96}, /* U+6296 */ - {0x00d9b6, 0x00e68b94}, /* U+62D4 */ - {0x00d9b7, 0x00e68a83}, /* U+6283 */ - {0x00d9b8, 0x00e68a94}, /* U+6294 */ - {0x00d9b9, 0x00e68b97}, /* U+62D7 */ - {0x00d9ba, 0x00e68b91}, /* U+62D1 */ - {0x00d9bb, 0x00e68abb}, /* U+62BB */ - {0x00d9bc, 0x00e68b8f}, /* U+62CF */ - {0x00d9bd, 0x00e68bbf}, /* U+62FF */ - {0x00d9be, 0x00e68b86}, /* U+62C6 */ - {0x00d9bf, 0x00e69394}, /* U+64D4 */ - {0x00d9c0, 0x00e68b88}, /* U+62C8 */ - {0x00d9c1, 0x00e68b9c}, /* U+62DC */ - {0x00d9c2, 0x00e68b8c}, /* U+62CC */ - {0x00d9c3, 0x00e68b8a}, /* U+62CA */ - {0x00d9c4, 0x00e68b82}, /* U+62C2 */ - {0x00d9c5, 0x00e68b87}, /* U+62C7 */ - {0x00d9c6, 0x00e68a9b}, /* U+629B */ - {0x00d9c7, 0x00e68b89}, /* U+62C9 */ - {0x00d9c8, 0x00e68c8c}, /* U+630C */ - {0x00d9c9, 0x00e68bae}, /* U+62EE */ - {0x00d9ca, 0x00e68bb1}, /* U+62F1 */ - {0x00d9cb, 0x00e68ca7}, /* U+6327 */ - {0x00d9cc, 0x00e68c82}, /* U+6302 */ - {0x00d9cd, 0x00e68c88}, /* U+6308 */ - {0x00d9ce, 0x00e68baf}, /* U+62EF */ - {0x00d9cf, 0x00e68bb5}, /* U+62F5 */ - {0x00d9d0, 0x00e68d90}, /* U+6350 */ - {0x00d9d1, 0x00e68cbe}, /* U+633E */ - {0x00d9d2, 0x00e68d8d}, /* U+634D */ - {0x00d9d3, 0x00e6909c}, /* U+641C */ - {0x00d9d4, 0x00e68d8f}, /* U+634F */ - {0x00d9d5, 0x00e68e96}, /* U+6396 */ - {0x00d9d6, 0x00e68e8e}, /* U+638E */ - {0x00d9d7, 0x00e68e80}, /* U+6380 */ - {0x00d9d8, 0x00e68eab}, /* U+63AB */ - {0x00d9d9, 0x00e68db6}, /* U+6376 */ - {0x00d9da, 0x00e68ea3}, /* U+63A3 */ - {0x00d9db, 0x00e68e8f}, /* U+638F */ - {0x00d9dc, 0x00e68e89}, /* U+6389 */ - {0x00d9dd, 0x00e68e9f}, /* U+639F */ - {0x00d9de, 0x00e68eb5}, /* U+63B5 */ - {0x00d9df, 0x00e68dab}, /* U+636B */ - {0x00d9e0, 0x00e68da9}, /* U+6369 */ - {0x00d9e1, 0x00e68ebe}, /* U+63BE */ - {0x00d9e2, 0x00e68fa9}, /* U+63E9 */ - {0x00d9e3, 0x00e68f80}, /* U+63C0 */ - {0x00d9e4, 0x00e68f86}, /* U+63C6 */ - {0x00d9e5, 0x00e68fa3}, /* U+63E3 */ - {0x00d9e6, 0x00e68f89}, /* U+63C9 */ - {0x00d9e7, 0x00e68f92}, /* U+63D2 */ - {0x00d9e8, 0x00e68fb6}, /* U+63F6 */ - {0x00d9e9, 0x00e68f84}, /* U+63C4 */ - {0x00d9ea, 0x00e69096}, /* U+6416 */ - {0x00d9eb, 0x00e690b4}, /* U+6434 */ - {0x00d9ec, 0x00e69086}, /* U+6406 */ - {0x00d9ed, 0x00e69093}, /* U+6413 */ - {0x00d9ee, 0x00e690a6}, /* U+6426 */ - {0x00d9ef, 0x00e690b6}, /* U+6436 */ - {0x00d9f0, 0x00e6949d}, /* U+651D */ - {0x00d9f1, 0x00e69097}, /* U+6417 */ - {0x00d9f2, 0x00e690a8}, /* U+6428 */ - {0x00d9f3, 0x00e6908f}, /* U+640F */ - {0x00d9f4, 0x00e691a7}, /* U+6467 */ - {0x00d9f5, 0x00e691af}, /* U+646F */ - {0x00d9f6, 0x00e691b6}, /* U+6476 */ - {0x00d9f7, 0x00e6918e}, /* U+644E */ - {0x00d9f8, 0x00e694aa}, /* U+652A */ - {0x00d9f9, 0x00e69295}, /* U+6495 */ - {0x00d9fa, 0x00e69293}, /* U+6493 */ - {0x00d9fb, 0x00e692a5}, /* U+64A5 */ - {0x00d9fc, 0x00e692a9}, /* U+64A9 */ - {0x00d9fd, 0x00e69288}, /* U+6488 */ - {0x00d9fe, 0x00e692bc}, /* U+64BC */ - {0x00daa1, 0x00e6939a}, /* U+64DA */ - {0x00daa2, 0x00e69392}, /* U+64D2 */ - {0x00daa3, 0x00e69385}, /* U+64C5 */ - {0x00daa4, 0x00e69387}, /* U+64C7 */ - {0x00daa5, 0x00e692bb}, /* U+64BB */ - {0x00daa6, 0x00e69398}, /* U+64D8 */ - {0x00daa7, 0x00e69382}, /* U+64C2 */ - {0x00daa8, 0x00e693b1}, /* U+64F1 */ - {0x00daa9, 0x00e693a7}, /* U+64E7 */ - {0x00daaa, 0x00e88889}, /* U+8209 */ - {0x00daab, 0x00e693a0}, /* U+64E0 */ - {0x00daac, 0x00e693a1}, /* U+64E1 */ - {0x00daad, 0x00e68aac}, /* U+62AC */ - {0x00daae, 0x00e693a3}, /* U+64E3 */ - {0x00daaf, 0x00e693af}, /* U+64EF */ - {0x00dab0, 0x00e694ac}, /* U+652C */ - {0x00dab1, 0x00e693b6}, /* U+64F6 */ - {0x00dab2, 0x00e693b4}, /* U+64F4 */ - {0x00dab3, 0x00e693b2}, /* U+64F2 */ - {0x00dab4, 0x00e693ba}, /* U+64FA */ - {0x00dab5, 0x00e69480}, /* U+6500 */ - {0x00dab6, 0x00e693bd}, /* U+64FD */ - {0x00dab7, 0x00e69498}, /* U+6518 */ - {0x00dab8, 0x00e6949c}, /* U+651C */ - {0x00dab9, 0x00e69485}, /* U+6505 */ - {0x00daba, 0x00e694a4}, /* U+6524 */ - {0x00dabb, 0x00e694a3}, /* U+6523 */ - {0x00dabc, 0x00e694ab}, /* U+652B */ - {0x00dabd, 0x00e694b4}, /* U+6534 */ - {0x00dabe, 0x00e694b5}, /* U+6535 */ - {0x00dabf, 0x00e694b7}, /* U+6537 */ - {0x00dac0, 0x00e694b6}, /* U+6536 */ - {0x00dac1, 0x00e694b8}, /* U+6538 */ - {0x00dac2, 0x00e7958b}, /* U+754B */ - {0x00dac3, 0x00e69588}, /* U+6548 */ - {0x00dac4, 0x00e69596}, /* U+6556 */ - {0x00dac5, 0x00e69595}, /* U+6555 */ - {0x00dac6, 0x00e6958d}, /* U+654D */ - {0x00dac7, 0x00e69598}, /* U+6558 */ - {0x00dac8, 0x00e6959e}, /* U+655E */ - {0x00dac9, 0x00e6959d}, /* U+655D */ - {0x00daca, 0x00e695b2}, /* U+6572 */ - {0x00dacb, 0x00e695b8}, /* U+6578 */ - {0x00dacc, 0x00e69682}, /* U+6582 */ - {0x00dacd, 0x00e69683}, /* U+6583 */ - {0x00dace, 0x00e8ae8a}, /* U+8B8A */ - {0x00dacf, 0x00e6969b}, /* U+659B */ - {0x00dad0, 0x00e6969f}, /* U+659F */ - {0x00dad1, 0x00e696ab}, /* U+65AB */ - {0x00dad2, 0x00e696b7}, /* U+65B7 */ - {0x00dad3, 0x00e69783}, /* U+65C3 */ - {0x00dad4, 0x00e69786}, /* U+65C6 */ - {0x00dad5, 0x00e69781}, /* U+65C1 */ - {0x00dad6, 0x00e69784}, /* U+65C4 */ - {0x00dad7, 0x00e6978c}, /* U+65CC */ - {0x00dad8, 0x00e69792}, /* U+65D2 */ - {0x00dad9, 0x00e6979b}, /* U+65DB */ - {0x00dada, 0x00e69799}, /* U+65D9 */ - {0x00dadb, 0x00e697a0}, /* U+65E0 */ - {0x00dadc, 0x00e697a1}, /* U+65E1 */ - {0x00dadd, 0x00e697b1}, /* U+65F1 */ - {0x00dade, 0x00e69db2}, /* U+6772 */ - {0x00dadf, 0x00e6988a}, /* U+660A */ - {0x00dae0, 0x00e69883}, /* U+6603 */ - {0x00dae1, 0x00e697bb}, /* U+65FB */ - {0x00dae2, 0x00e69db3}, /* U+6773 */ - {0x00dae3, 0x00e698b5}, /* U+6635 */ - {0x00dae4, 0x00e698b6}, /* U+6636 */ - {0x00dae5, 0x00e698b4}, /* U+6634 */ - {0x00dae6, 0x00e6989c}, /* U+661C */ - {0x00dae7, 0x00e6998f}, /* U+664F */ - {0x00dae8, 0x00e69984}, /* U+6644 */ - {0x00dae9, 0x00e69989}, /* U+6649 */ - {0x00daea, 0x00e69981}, /* U+6641 */ - {0x00daeb, 0x00e6999e}, /* U+665E */ - {0x00daec, 0x00e6999d}, /* U+665D */ - {0x00daed, 0x00e699a4}, /* U+6664 */ - {0x00daee, 0x00e699a7}, /* U+6667 */ - {0x00daef, 0x00e699a8}, /* U+6668 */ - {0x00daf0, 0x00e6999f}, /* U+665F */ - {0x00daf1, 0x00e699a2}, /* U+6662 */ - {0x00daf2, 0x00e699b0}, /* U+6670 */ - {0x00daf3, 0x00e69a83}, /* U+6683 */ - {0x00daf4, 0x00e69a88}, /* U+6688 */ - {0x00daf5, 0x00e69a8e}, /* U+668E */ - {0x00daf6, 0x00e69a89}, /* U+6689 */ - {0x00daf7, 0x00e69a84}, /* U+6684 */ - {0x00daf8, 0x00e69a98}, /* U+6698 */ - {0x00daf9, 0x00e69a9d}, /* U+669D */ - {0x00dafa, 0x00e69b81}, /* U+66C1 */ - {0x00dafb, 0x00e69ab9}, /* U+66B9 */ - {0x00dafc, 0x00e69b89}, /* U+66C9 */ - {0x00dafd, 0x00e69abe}, /* U+66BE */ - {0x00dafe, 0x00e69abc}, /* U+66BC */ - {0x00dba1, 0x00e69b84}, /* U+66C4 */ - {0x00dba2, 0x00e69ab8}, /* U+66B8 */ - {0x00dba3, 0x00e69b96}, /* U+66D6 */ - {0x00dba4, 0x00e69b9a}, /* U+66DA */ - {0x00dba5, 0x00e69ba0}, /* U+66E0 */ - {0x00dba6, 0x00e698bf}, /* U+663F */ - {0x00dba7, 0x00e69ba6}, /* U+66E6 */ - {0x00dba8, 0x00e69ba9}, /* U+66E9 */ - {0x00dba9, 0x00e69bb0}, /* U+66F0 */ - {0x00dbaa, 0x00e69bb5}, /* U+66F5 */ - {0x00dbab, 0x00e69bb7}, /* U+66F7 */ - {0x00dbac, 0x00e69c8f}, /* U+670F */ - {0x00dbad, 0x00e69c96}, /* U+6716 */ - {0x00dbae, 0x00e69c9e}, /* U+671E */ - {0x00dbaf, 0x00e69ca6}, /* U+6726 */ - {0x00dbb0, 0x00e69ca7}, /* U+6727 */ - {0x00dbb1, 0x00e99cb8}, /* U+9738 */ - {0x00dbb2, 0x00e69cae}, /* U+672E */ - {0x00dbb3, 0x00e69cbf}, /* U+673F */ - {0x00dbb4, 0x00e69cb6}, /* U+6736 */ - {0x00dbb5, 0x00e69d81}, /* U+6741 */ - {0x00dbb6, 0x00e69cb8}, /* U+6738 */ - {0x00dbb7, 0x00e69cb7}, /* U+6737 */ - {0x00dbb8, 0x00e69d86}, /* U+6746 */ - {0x00dbb9, 0x00e69d9e}, /* U+675E */ - {0x00dbba, 0x00e69da0}, /* U+6760 */ - {0x00dbbb, 0x00e69d99}, /* U+6759 */ - {0x00dbbc, 0x00e69da3}, /* U+6763 */ - {0x00dbbd, 0x00e69da4}, /* U+6764 */ - {0x00dbbe, 0x00e69e89}, /* U+6789 */ - {0x00dbbf, 0x00e69db0}, /* U+6770 */ - {0x00dbc0, 0x00e69ea9}, /* U+67A9 */ - {0x00dbc1, 0x00e69dbc}, /* U+677C */ - {0x00dbc2, 0x00e69daa}, /* U+676A */ - {0x00dbc3, 0x00e69e8c}, /* U+678C */ - {0x00dbc4, 0x00e69e8b}, /* U+678B */ - {0x00dbc5, 0x00e69ea6}, /* U+67A6 */ - {0x00dbc6, 0x00e69ea1}, /* U+67A1 */ - {0x00dbc7, 0x00e69e85}, /* U+6785 */ - {0x00dbc8, 0x00e69eb7}, /* U+67B7 */ - {0x00dbc9, 0x00e69faf}, /* U+67EF */ - {0x00dbca, 0x00e69eb4}, /* U+67B4 */ - {0x00dbcb, 0x00e69fac}, /* U+67EC */ - {0x00dbcc, 0x00e69eb3}, /* U+67B3 */ - {0x00dbcd, 0x00e69fa9}, /* U+67E9 */ - {0x00dbce, 0x00e69eb8}, /* U+67B8 */ - {0x00dbcf, 0x00e69fa4}, /* U+67E4 */ - {0x00dbd0, 0x00e69f9e}, /* U+67DE */ - {0x00dbd1, 0x00e69f9d}, /* U+67DD */ - {0x00dbd2, 0x00e69fa2}, /* U+67E2 */ - {0x00dbd3, 0x00e69fae}, /* U+67EE */ - {0x00dbd4, 0x00e69eb9}, /* U+67B9 */ - {0x00dbd5, 0x00e69f8e}, /* U+67CE */ - {0x00dbd6, 0x00e69f86}, /* U+67C6 */ - {0x00dbd7, 0x00e69fa7}, /* U+67E7 */ - {0x00dbd8, 0x00e6aa9c}, /* U+6A9C */ - {0x00dbd9, 0x00e6a09e}, /* U+681E */ - {0x00dbda, 0x00e6a186}, /* U+6846 */ - {0x00dbdb, 0x00e6a0a9}, /* U+6829 */ - {0x00dbdc, 0x00e6a180}, /* U+6840 */ - {0x00dbdd, 0x00e6a18d}, /* U+684D */ - {0x00dbde, 0x00e6a0b2}, /* U+6832 */ - {0x00dbdf, 0x00e6a18e}, /* U+684E */ - {0x00dbe0, 0x00e6a2b3}, /* U+68B3 */ - {0x00dbe1, 0x00e6a0ab}, /* U+682B */ - {0x00dbe2, 0x00e6a199}, /* U+6859 */ - {0x00dbe3, 0x00e6a1a3}, /* U+6863 */ - {0x00dbe4, 0x00e6a1b7}, /* U+6877 */ - {0x00dbe5, 0x00e6a1bf}, /* U+687F */ - {0x00dbe6, 0x00e6a29f}, /* U+689F */ - {0x00dbe7, 0x00e6a28f}, /* U+688F */ - {0x00dbe8, 0x00e6a2ad}, /* U+68AD */ - {0x00dbe9, 0x00e6a294}, /* U+6894 */ - {0x00dbea, 0x00e6a29d}, /* U+689D */ - {0x00dbeb, 0x00e6a29b}, /* U+689B */ - {0x00dbec, 0x00e6a283}, /* U+6883 */ - {0x00dbed, 0x00e6aaae}, /* U+6AAE */ - {0x00dbee, 0x00e6a2b9}, /* U+68B9 */ - {0x00dbef, 0x00e6a1b4}, /* U+6874 */ - {0x00dbf0, 0x00e6a2b5}, /* U+68B5 */ - {0x00dbf1, 0x00e6a2a0}, /* U+68A0 */ - {0x00dbf2, 0x00e6a2ba}, /* U+68BA */ - {0x00dbf3, 0x00e6a48f}, /* U+690F */ - {0x00dbf4, 0x00e6a28d}, /* U+688D */ - {0x00dbf5, 0x00e6a1be}, /* U+687E */ - {0x00dbf6, 0x00e6a481}, /* U+6901 */ - {0x00dbf7, 0x00e6a38a}, /* U+68CA */ - {0x00dbf8, 0x00e6a488}, /* U+6908 */ - {0x00dbf9, 0x00e6a398}, /* U+68D8 */ - {0x00dbfa, 0x00e6a4a2}, /* U+6922 */ - {0x00dbfb, 0x00e6a4a6}, /* U+6926 */ - {0x00dbfc, 0x00e6a3a1}, /* U+68E1 */ - {0x00dbfd, 0x00e6a48c}, /* U+690C */ - {0x00dbfe, 0x00e6a38d}, /* U+68CD */ - {0x00dca1, 0x00e6a394}, /* U+68D4 */ - {0x00dca2, 0x00e6a3a7}, /* U+68E7 */ - {0x00dca3, 0x00e6a395}, /* U+68D5 */ - {0x00dca4, 0x00e6a4b6}, /* U+6936 */ - {0x00dca5, 0x00e6a492}, /* U+6912 */ - {0x00dca6, 0x00e6a484}, /* U+6904 */ - {0x00dca7, 0x00e6a397}, /* U+68D7 */ - {0x00dca8, 0x00e6a3a3}, /* U+68E3 */ - {0x00dca9, 0x00e6a4a5}, /* U+6925 */ - {0x00dcaa, 0x00e6a3b9}, /* U+68F9 */ - {0x00dcab, 0x00e6a3a0}, /* U+68E0 */ - {0x00dcac, 0x00e6a3af}, /* U+68EF */ - {0x00dcad, 0x00e6a4a8}, /* U+6928 */ - {0x00dcae, 0x00e6a4aa}, /* U+692A */ - {0x00dcaf, 0x00e6a49a}, /* U+691A */ - {0x00dcb0, 0x00e6a4a3}, /* U+6923 */ - {0x00dcb1, 0x00e6a4a1}, /* U+6921 */ - {0x00dcb2, 0x00e6a386}, /* U+68C6 */ - {0x00dcb3, 0x00e6a5b9}, /* U+6979 */ - {0x00dcb4, 0x00e6a5b7}, /* U+6977 */ - {0x00dcb5, 0x00e6a59c}, /* U+695C */ - {0x00dcb6, 0x00e6a5b8}, /* U+6978 */ - {0x00dcb7, 0x00e6a5ab}, /* U+696B */ - {0x00dcb8, 0x00e6a594}, /* U+6954 */ - {0x00dcb9, 0x00e6a5be}, /* U+697E */ - {0x00dcba, 0x00e6a5ae}, /* U+696E */ - {0x00dcbb, 0x00e6a4b9}, /* U+6939 */ - {0x00dcbc, 0x00e6a5b4}, /* U+6974 */ - {0x00dcbd, 0x00e6a4bd}, /* U+693D */ - {0x00dcbe, 0x00e6a599}, /* U+6959 */ - {0x00dcbf, 0x00e6a4b0}, /* U+6930 */ - {0x00dcc0, 0x00e6a5a1}, /* U+6961 */ - {0x00dcc1, 0x00e6a59e}, /* U+695E */ - {0x00dcc2, 0x00e6a59d}, /* U+695D */ - {0x00dcc3, 0x00e6a681}, /* U+6981 */ - {0x00dcc4, 0x00e6a5aa}, /* U+696A */ - {0x00dcc5, 0x00e6a6b2}, /* U+69B2 */ - {0x00dcc6, 0x00e6a6ae}, /* U+69AE */ - {0x00dcc7, 0x00e6a790}, /* U+69D0 */ - {0x00dcc8, 0x00e6a6bf}, /* U+69BF */ - {0x00dcc9, 0x00e6a781}, /* U+69C1 */ - {0x00dcca, 0x00e6a793}, /* U+69D3 */ - {0x00dccb, 0x00e6a6be}, /* U+69BE */ - {0x00dccc, 0x00e6a78e}, /* U+69CE */ - {0x00dccd, 0x00e5afa8}, /* U+5BE8 */ - {0x00dcce, 0x00e6a78a}, /* U+69CA */ - {0x00dccf, 0x00e6a79d}, /* U+69DD */ - {0x00dcd0, 0x00e6a6bb}, /* U+69BB */ - {0x00dcd1, 0x00e6a783}, /* U+69C3 */ - {0x00dcd2, 0x00e6a6a7}, /* U+69A7 */ - {0x00dcd3, 0x00e6a8ae}, /* U+6A2E */ - {0x00dcd4, 0x00e6a691}, /* U+6991 */ - {0x00dcd5, 0x00e6a6a0}, /* U+69A0 */ - {0x00dcd6, 0x00e6a69c}, /* U+699C */ - {0x00dcd7, 0x00e6a695}, /* U+6995 */ - {0x00dcd8, 0x00e6a6b4}, /* U+69B4 */ - {0x00dcd9, 0x00e6a79e}, /* U+69DE */ - {0x00dcda, 0x00e6a7a8}, /* U+69E8 */ - {0x00dcdb, 0x00e6a882}, /* U+6A02 */ - {0x00dcdc, 0x00e6a89b}, /* U+6A1B */ - {0x00dcdd, 0x00e6a7bf}, /* U+69FF */ - {0x00dcde, 0x00e6ac8a}, /* U+6B0A */ - {0x00dcdf, 0x00e6a7b9}, /* U+69F9 */ - {0x00dce0, 0x00e6a7b2}, /* U+69F2 */ - {0x00dce1, 0x00e6a7a7}, /* U+69E7 */ - {0x00dce2, 0x00e6a885}, /* U+6A05 */ - {0x00dce3, 0x00e6a6b1}, /* U+69B1 */ - {0x00dce4, 0x00e6a89e}, /* U+6A1E */ - {0x00dce5, 0x00e6a7ad}, /* U+69ED */ - {0x00dce6, 0x00e6a894}, /* U+6A14 */ - {0x00dce7, 0x00e6a7ab}, /* U+69EB */ - {0x00dce8, 0x00e6a88a}, /* U+6A0A */ - {0x00dce9, 0x00e6a892}, /* U+6A12 */ - {0x00dcea, 0x00e6ab81}, /* U+6AC1 */ - {0x00dceb, 0x00e6a8a3}, /* U+6A23 */ - {0x00dcec, 0x00e6a893}, /* U+6A13 */ - {0x00dced, 0x00e6a984}, /* U+6A44 */ - {0x00dcee, 0x00e6a88c}, /* U+6A0C */ - {0x00dcef, 0x00e6a9b2}, /* U+6A72 */ - {0x00dcf0, 0x00e6a8b6}, /* U+6A36 */ - {0x00dcf1, 0x00e6a9b8}, /* U+6A78 */ - {0x00dcf2, 0x00e6a987}, /* U+6A47 */ - {0x00dcf3, 0x00e6a9a2}, /* U+6A62 */ - {0x00dcf4, 0x00e6a999}, /* U+6A59 */ - {0x00dcf5, 0x00e6a9a6}, /* U+6A66 */ - {0x00dcf6, 0x00e6a988}, /* U+6A48 */ - {0x00dcf7, 0x00e6a8b8}, /* U+6A38 */ - {0x00dcf8, 0x00e6a8a2}, /* U+6A22 */ - {0x00dcf9, 0x00e6aa90}, /* U+6A90 */ - {0x00dcfa, 0x00e6aa8d}, /* U+6A8D */ - {0x00dcfb, 0x00e6aaa0}, /* U+6AA0 */ - {0x00dcfc, 0x00e6aa84}, /* U+6A84 */ - {0x00dcfd, 0x00e6aaa2}, /* U+6AA2 */ - {0x00dcfe, 0x00e6aaa3}, /* U+6AA3 */ - {0x00dda1, 0x00e6aa97}, /* U+6A97 */ - {0x00dda2, 0x00e89897}, /* U+8617 */ - {0x00dda3, 0x00e6aabb}, /* U+6ABB */ - {0x00dda4, 0x00e6ab83}, /* U+6AC3 */ - {0x00dda5, 0x00e6ab82}, /* U+6AC2 */ - {0x00dda6, 0x00e6aab8}, /* U+6AB8 */ - {0x00dda7, 0x00e6aab3}, /* U+6AB3 */ - {0x00dda8, 0x00e6aaac}, /* U+6AAC */ - {0x00dda9, 0x00e6ab9e}, /* U+6ADE */ - {0x00ddaa, 0x00e6ab91}, /* U+6AD1 */ - {0x00ddab, 0x00e6ab9f}, /* U+6ADF */ - {0x00ddac, 0x00e6aaaa}, /* U+6AAA */ - {0x00ddad, 0x00e6ab9a}, /* U+6ADA */ - {0x00ddae, 0x00e6abaa}, /* U+6AEA */ - {0x00ddaf, 0x00e6abbb}, /* U+6AFB */ - {0x00ddb0, 0x00e6ac85}, /* U+6B05 */ - {0x00ddb1, 0x00e89896}, /* U+8616 */ - {0x00ddb2, 0x00e6abba}, /* U+6AFA */ - {0x00ddb3, 0x00e6ac92}, /* U+6B12 */ - {0x00ddb4, 0x00e6ac96}, /* U+6B16 */ - {0x00ddb5, 0x00e9acb1}, /* U+9B31 */ - {0x00ddb6, 0x00e6ac9f}, /* U+6B1F */ - {0x00ddb7, 0x00e6acb8}, /* U+6B38 */ - {0x00ddb8, 0x00e6acb7}, /* U+6B37 */ - {0x00ddb9, 0x00e79b9c}, /* U+76DC */ - {0x00ddba, 0x00e6acb9}, /* U+6B39 */ - {0x00ddbb, 0x00e9a3ae}, /* U+98EE */ - {0x00ddbc, 0x00e6ad87}, /* U+6B47 */ - {0x00ddbd, 0x00e6ad83}, /* U+6B43 */ - {0x00ddbe, 0x00e6ad89}, /* U+6B49 */ - {0x00ddbf, 0x00e6ad90}, /* U+6B50 */ - {0x00ddc0, 0x00e6ad99}, /* U+6B59 */ - {0x00ddc1, 0x00e6ad94}, /* U+6B54 */ - {0x00ddc2, 0x00e6ad9b}, /* U+6B5B */ - {0x00ddc3, 0x00e6ad9f}, /* U+6B5F */ - {0x00ddc4, 0x00e6ada1}, /* U+6B61 */ - {0x00ddc5, 0x00e6adb8}, /* U+6B78 */ - {0x00ddc6, 0x00e6adb9}, /* U+6B79 */ - {0x00ddc7, 0x00e6adbf}, /* U+6B7F */ - {0x00ddc8, 0x00e6ae80}, /* U+6B80 */ - {0x00ddc9, 0x00e6ae84}, /* U+6B84 */ - {0x00ddca, 0x00e6ae83}, /* U+6B83 */ - {0x00ddcb, 0x00e6ae8d}, /* U+6B8D */ - {0x00ddcc, 0x00e6ae98}, /* U+6B98 */ - {0x00ddcd, 0x00e6ae95}, /* U+6B95 */ - {0x00ddce, 0x00e6ae9e}, /* U+6B9E */ - {0x00ddcf, 0x00e6aea4}, /* U+6BA4 */ - {0x00ddd0, 0x00e6aeaa}, /* U+6BAA */ - {0x00ddd1, 0x00e6aeab}, /* U+6BAB */ - {0x00ddd2, 0x00e6aeaf}, /* U+6BAF */ - {0x00ddd3, 0x00e6aeb2}, /* U+6BB2 */ - {0x00ddd4, 0x00e6aeb1}, /* U+6BB1 */ - {0x00ddd5, 0x00e6aeb3}, /* U+6BB3 */ - {0x00ddd6, 0x00e6aeb7}, /* U+6BB7 */ - {0x00ddd7, 0x00e6aebc}, /* U+6BBC */ - {0x00ddd8, 0x00e6af86}, /* U+6BC6 */ - {0x00ddd9, 0x00e6af8b}, /* U+6BCB */ - {0x00ddda, 0x00e6af93}, /* U+6BD3 */ - {0x00dddb, 0x00e6af9f}, /* U+6BDF */ - {0x00dddc, 0x00e6afac}, /* U+6BEC */ - {0x00dddd, 0x00e6afab}, /* U+6BEB */ - {0x00ddde, 0x00e6afb3}, /* U+6BF3 */ - {0x00dddf, 0x00e6afaf}, /* U+6BEF */ - {0x00dde0, 0x00e9babe}, /* U+9EBE */ - {0x00dde1, 0x00e6b088}, /* U+6C08 */ - {0x00dde2, 0x00e6b093}, /* U+6C13 */ - {0x00dde3, 0x00e6b094}, /* U+6C14 */ - {0x00dde4, 0x00e6b09b}, /* U+6C1B */ - {0x00dde5, 0x00e6b0a4}, /* U+6C24 */ - {0x00dde6, 0x00e6b0a3}, /* U+6C23 */ - {0x00dde7, 0x00e6b19e}, /* U+6C5E */ - {0x00dde8, 0x00e6b195}, /* U+6C55 */ - {0x00dde9, 0x00e6b1a2}, /* U+6C62 */ - {0x00ddea, 0x00e6b1aa}, /* U+6C6A */ - {0x00ddeb, 0x00e6b282}, /* U+6C82 */ - {0x00ddec, 0x00e6b28d}, /* U+6C8D */ - {0x00dded, 0x00e6b29a}, /* U+6C9A */ - {0x00ddee, 0x00e6b281}, /* U+6C81 */ - {0x00ddef, 0x00e6b29b}, /* U+6C9B */ - {0x00ddf0, 0x00e6b1be}, /* U+6C7E */ - {0x00ddf1, 0x00e6b1a8}, /* U+6C68 */ - {0x00ddf2, 0x00e6b1b3}, /* U+6C73 */ - {0x00ddf3, 0x00e6b292}, /* U+6C92 */ - {0x00ddf4, 0x00e6b290}, /* U+6C90 */ - {0x00ddf5, 0x00e6b384}, /* U+6CC4 */ - {0x00ddf6, 0x00e6b3b1}, /* U+6CF1 */ - {0x00ddf7, 0x00e6b393}, /* U+6CD3 */ - {0x00ddf8, 0x00e6b2bd}, /* U+6CBD */ - {0x00ddf9, 0x00e6b397}, /* U+6CD7 */ - {0x00ddfa, 0x00e6b385}, /* U+6CC5 */ - {0x00ddfb, 0x00e6b39d}, /* U+6CDD */ - {0x00ddfc, 0x00e6b2ae}, /* U+6CAE */ - {0x00ddfd, 0x00e6b2b1}, /* U+6CB1 */ - {0x00ddfe, 0x00e6b2be}, /* U+6CBE */ - {0x00dea1, 0x00e6b2ba}, /* U+6CBA */ - {0x00dea2, 0x00e6b39b}, /* U+6CDB */ - {0x00dea3, 0x00e6b3af}, /* U+6CEF */ - {0x00dea4, 0x00e6b399}, /* U+6CD9 */ - {0x00dea5, 0x00e6b3aa}, /* U+6CEA */ - {0x00dea6, 0x00e6b49f}, /* U+6D1F */ - {0x00dea7, 0x00e8a18d}, /* U+884D */ - {0x00dea8, 0x00e6b4b6}, /* U+6D36 */ - {0x00dea9, 0x00e6b4ab}, /* U+6D2B */ - {0x00deaa, 0x00e6b4bd}, /* U+6D3D */ - {0x00deab, 0x00e6b4b8}, /* U+6D38 */ - {0x00deac, 0x00e6b499}, /* U+6D19 */ - {0x00dead, 0x00e6b4b5}, /* U+6D35 */ - {0x00deae, 0x00e6b4b3}, /* U+6D33 */ - {0x00deaf, 0x00e6b492}, /* U+6D12 */ - {0x00deb0, 0x00e6b48c}, /* U+6D0C */ - {0x00deb1, 0x00e6b5a3}, /* U+6D63 */ - {0x00deb2, 0x00e6b693}, /* U+6D93 */ - {0x00deb3, 0x00e6b5a4}, /* U+6D64 */ - {0x00deb4, 0x00e6b59a}, /* U+6D5A */ - {0x00deb5, 0x00e6b5b9}, /* U+6D79 */ - {0x00deb6, 0x00e6b599}, /* U+6D59 */ - {0x00deb7, 0x00e6b68e}, /* U+6D8E */ - {0x00deb8, 0x00e6b695}, /* U+6D95 */ - {0x00deb9, 0x00e6bfa4}, /* U+6FE4 */ - {0x00deba, 0x00e6b685}, /* U+6D85 */ - {0x00debb, 0x00e6b7b9}, /* U+6DF9 */ - {0x00debc, 0x00e6b895}, /* U+6E15 */ - {0x00debd, 0x00e6b88a}, /* U+6E0A */ - {0x00debe, 0x00e6b6b5}, /* U+6DB5 */ - {0x00debf, 0x00e6b787}, /* U+6DC7 */ - {0x00dec0, 0x00e6b7a6}, /* U+6DE6 */ - {0x00dec1, 0x00e6b6b8}, /* U+6DB8 */ - {0x00dec2, 0x00e6b786}, /* U+6DC6 */ - {0x00dec3, 0x00e6b7ac}, /* U+6DEC */ - {0x00dec4, 0x00e6b79e}, /* U+6DDE */ - {0x00dec5, 0x00e6b78c}, /* U+6DCC */ - {0x00dec6, 0x00e6b7a8}, /* U+6DE8 */ - {0x00dec7, 0x00e6b792}, /* U+6DD2 */ - {0x00dec8, 0x00e6b785}, /* U+6DC5 */ - {0x00dec9, 0x00e6b7ba}, /* U+6DFA */ - {0x00deca, 0x00e6b799}, /* U+6DD9 */ - {0x00decb, 0x00e6b7a4}, /* U+6DE4 */ - {0x00decc, 0x00e6b795}, /* U+6DD5 */ - {0x00decd, 0x00e6b7aa}, /* U+6DEA */ - {0x00dece, 0x00e6b7ae}, /* U+6DEE */ - {0x00decf, 0x00e6b8ad}, /* U+6E2D */ - {0x00ded0, 0x00e6b9ae}, /* U+6E6E */ - {0x00ded1, 0x00e6b8ae}, /* U+6E2E */ - {0x00ded2, 0x00e6b899}, /* U+6E19 */ - {0x00ded3, 0x00e6b9b2}, /* U+6E72 */ - {0x00ded4, 0x00e6b99f}, /* U+6E5F */ - {0x00ded5, 0x00e6b8be}, /* U+6E3E */ - {0x00ded6, 0x00e6b8a3}, /* U+6E23 */ - {0x00ded7, 0x00e6b9ab}, /* U+6E6B */ - {0x00ded8, 0x00e6b8ab}, /* U+6E2B */ - {0x00ded9, 0x00e6b9b6}, /* U+6E76 */ - {0x00deda, 0x00e6b98d}, /* U+6E4D */ - {0x00dedb, 0x00e6b89f}, /* U+6E1F */ - {0x00dedc, 0x00e6b983}, /* U+6E43 */ - {0x00dedd, 0x00e6b8ba}, /* U+6E3A */ - {0x00dede, 0x00e6b98e}, /* U+6E4E */ - {0x00dedf, 0x00e6b8a4}, /* U+6E24 */ - {0x00dee0, 0x00e6bbbf}, /* U+6EFF */ - {0x00dee1, 0x00e6b89d}, /* U+6E1D */ - {0x00dee2, 0x00e6b8b8}, /* U+6E38 */ - {0x00dee3, 0x00e6ba82}, /* U+6E82 */ - {0x00dee4, 0x00e6baaa}, /* U+6EAA */ - {0x00dee5, 0x00e6ba98}, /* U+6E98 */ - {0x00dee6, 0x00e6bb89}, /* U+6EC9 */ - {0x00dee7, 0x00e6bab7}, /* U+6EB7 */ - {0x00dee8, 0x00e6bb93}, /* U+6ED3 */ - {0x00dee9, 0x00e6babd}, /* U+6EBD */ - {0x00deea, 0x00e6baaf}, /* U+6EAF */ - {0x00deeb, 0x00e6bb84}, /* U+6EC4 */ - {0x00deec, 0x00e6bab2}, /* U+6EB2 */ - {0x00deed, 0x00e6bb94}, /* U+6ED4 */ - {0x00deee, 0x00e6bb95}, /* U+6ED5 */ - {0x00deef, 0x00e6ba8f}, /* U+6E8F */ - {0x00def0, 0x00e6baa5}, /* U+6EA5 */ - {0x00def1, 0x00e6bb82}, /* U+6EC2 */ - {0x00def2, 0x00e6ba9f}, /* U+6E9F */ - {0x00def3, 0x00e6bd81}, /* U+6F41 */ - {0x00def4, 0x00e6bc91}, /* U+6F11 */ - {0x00def5, 0x00e7818c}, /* U+704C */ - {0x00def6, 0x00e6bbac}, /* U+6EEC */ - {0x00def7, 0x00e6bbb8}, /* U+6EF8 */ - {0x00def8, 0x00e6bbbe}, /* U+6EFE */ - {0x00def9, 0x00e6bcbf}, /* U+6F3F */ - {0x00defa, 0x00e6bbb2}, /* U+6EF2 */ - {0x00defb, 0x00e6bcb1}, /* U+6F31 */ - {0x00defc, 0x00e6bbaf}, /* U+6EEF */ - {0x00defd, 0x00e6bcb2}, /* U+6F32 */ - {0x00defe, 0x00e6bb8c}, /* U+6ECC */ - {0x00dfa1, 0x00e6bcbe}, /* U+6F3E */ - {0x00dfa2, 0x00e6bc93}, /* U+6F13 */ - {0x00dfa3, 0x00e6bbb7}, /* U+6EF7 */ - {0x00dfa4, 0x00e6be86}, /* U+6F86 */ - {0x00dfa5, 0x00e6bdba}, /* U+6F7A */ - {0x00dfa6, 0x00e6bdb8}, /* U+6F78 */ - {0x00dfa7, 0x00e6be81}, /* U+6F81 */ - {0x00dfa8, 0x00e6be80}, /* U+6F80 */ - {0x00dfa9, 0x00e6bdaf}, /* U+6F6F */ - {0x00dfaa, 0x00e6bd9b}, /* U+6F5B */ - {0x00dfab, 0x00e6bfb3}, /* U+6FF3 */ - {0x00dfac, 0x00e6bdad}, /* U+6F6D */ - {0x00dfad, 0x00e6be82}, /* U+6F82 */ - {0x00dfae, 0x00e6bdbc}, /* U+6F7C */ - {0x00dfaf, 0x00e6bd98}, /* U+6F58 */ - {0x00dfb0, 0x00e6be8e}, /* U+6F8E */ - {0x00dfb1, 0x00e6be91}, /* U+6F91 */ - {0x00dfb2, 0x00e6bf82}, /* U+6FC2 */ - {0x00dfb3, 0x00e6bda6}, /* U+6F66 */ - {0x00dfb4, 0x00e6beb3}, /* U+6FB3 */ - {0x00dfb5, 0x00e6bea3}, /* U+6FA3 */ - {0x00dfb6, 0x00e6bea1}, /* U+6FA1 */ - {0x00dfb7, 0x00e6bea4}, /* U+6FA4 */ - {0x00dfb8, 0x00e6beb9}, /* U+6FB9 */ - {0x00dfb9, 0x00e6bf86}, /* U+6FC6 */ - {0x00dfba, 0x00e6beaa}, /* U+6FAA */ - {0x00dfbb, 0x00e6bf9f}, /* U+6FDF */ - {0x00dfbc, 0x00e6bf95}, /* U+6FD5 */ - {0x00dfbd, 0x00e6bfac}, /* U+6FEC */ - {0x00dfbe, 0x00e6bf94}, /* U+6FD4 */ - {0x00dfbf, 0x00e6bf98}, /* U+6FD8 */ - {0x00dfc0, 0x00e6bfb1}, /* U+6FF1 */ - {0x00dfc1, 0x00e6bfae}, /* U+6FEE */ - {0x00dfc2, 0x00e6bf9b}, /* U+6FDB */ - {0x00dfc3, 0x00e78089}, /* U+7009 */ - {0x00dfc4, 0x00e7808b}, /* U+700B */ - {0x00dfc5, 0x00e6bfba}, /* U+6FFA */ - {0x00dfc6, 0x00e78091}, /* U+7011 */ - {0x00dfc7, 0x00e78081}, /* U+7001 */ - {0x00dfc8, 0x00e7808f}, /* U+700F */ - {0x00dfc9, 0x00e6bfbe}, /* U+6FFE */ - {0x00dfca, 0x00e7809b}, /* U+701B */ - {0x00dfcb, 0x00e7809a}, /* U+701A */ - {0x00dfcc, 0x00e6bdb4}, /* U+6F74 */ - {0x00dfcd, 0x00e7809d}, /* U+701D */ - {0x00dfce, 0x00e78098}, /* U+7018 */ - {0x00dfcf, 0x00e7809f}, /* U+701F */ - {0x00dfd0, 0x00e780b0}, /* U+7030 */ - {0x00dfd1, 0x00e780be}, /* U+703E */ - {0x00dfd2, 0x00e780b2}, /* U+7032 */ - {0x00dfd3, 0x00e78191}, /* U+7051 */ - {0x00dfd4, 0x00e781a3}, /* U+7063 */ - {0x00dfd5, 0x00e78299}, /* U+7099 */ - {0x00dfd6, 0x00e78292}, /* U+7092 */ - {0x00dfd7, 0x00e782af}, /* U+70AF */ - {0x00dfd8, 0x00e783b1}, /* U+70F1 */ - {0x00dfd9, 0x00e782ac}, /* U+70AC */ - {0x00dfda, 0x00e782b8}, /* U+70B8 */ - {0x00dfdb, 0x00e782b3}, /* U+70B3 */ - {0x00dfdc, 0x00e782ae}, /* U+70AE */ - {0x00dfdd, 0x00e7839f}, /* U+70DF */ - {0x00dfde, 0x00e7838b}, /* U+70CB */ - {0x00dfdf, 0x00e7839d}, /* U+70DD */ - {0x00dfe0, 0x00e78399}, /* U+70D9 */ - {0x00dfe1, 0x00e78489}, /* U+7109 */ - {0x00dfe2, 0x00e783bd}, /* U+70FD */ - {0x00dfe3, 0x00e7849c}, /* U+711C */ - {0x00dfe4, 0x00e78499}, /* U+7119 */ - {0x00dfe5, 0x00e785a5}, /* U+7165 */ - {0x00dfe6, 0x00e78595}, /* U+7155 */ - {0x00dfe7, 0x00e78688}, /* U+7188 */ - {0x00dfe8, 0x00e785a6}, /* U+7166 */ - {0x00dfe9, 0x00e785a2}, /* U+7162 */ - {0x00dfea, 0x00e7858c}, /* U+714C */ - {0x00dfeb, 0x00e78596}, /* U+7156 */ - {0x00dfec, 0x00e785ac}, /* U+716C */ - {0x00dfed, 0x00e7868f}, /* U+718F */ - {0x00dfee, 0x00e787bb}, /* U+71FB */ - {0x00dfef, 0x00e78684}, /* U+7184 */ - {0x00dff0, 0x00e78695}, /* U+7195 */ - {0x00dff1, 0x00e786a8}, /* U+71A8 */ - {0x00dff2, 0x00e786ac}, /* U+71AC */ - {0x00dff3, 0x00e78797}, /* U+71D7 */ - {0x00dff4, 0x00e786b9}, /* U+71B9 */ - {0x00dff5, 0x00e786be}, /* U+71BE */ - {0x00dff6, 0x00e78792}, /* U+71D2 */ - {0x00dff7, 0x00e78789}, /* U+71C9 */ - {0x00dff8, 0x00e78794}, /* U+71D4 */ - {0x00dff9, 0x00e7878e}, /* U+71CE */ - {0x00dffa, 0x00e787a0}, /* U+71E0 */ - {0x00dffb, 0x00e787ac}, /* U+71EC */ - {0x00dffc, 0x00e787a7}, /* U+71E7 */ - {0x00dffd, 0x00e787b5}, /* U+71F5 */ - {0x00dffe, 0x00e787bc}, /* U+71FC */ - {0x00e0a1, 0x00e787b9}, /* U+71F9 */ - {0x00e0a2, 0x00e787bf}, /* U+71FF */ - {0x00e0a3, 0x00e7888d}, /* U+720D */ - {0x00e0a4, 0x00e78890}, /* U+7210 */ - {0x00e0a5, 0x00e7889b}, /* U+721B */ - {0x00e0a6, 0x00e788a8}, /* U+7228 */ - {0x00e0a7, 0x00e788ad}, /* U+722D */ - {0x00e0a8, 0x00e788ac}, /* U+722C */ - {0x00e0a9, 0x00e788b0}, /* U+7230 */ - {0x00e0aa, 0x00e788b2}, /* U+7232 */ - {0x00e0ab, 0x00e788bb}, /* U+723B */ - {0x00e0ac, 0x00e788bc}, /* U+723C */ - {0x00e0ad, 0x00e788bf}, /* U+723F */ - {0x00e0ae, 0x00e78980}, /* U+7240 */ - {0x00e0af, 0x00e78986}, /* U+7246 */ - {0x00e0b0, 0x00e7898b}, /* U+724B */ - {0x00e0b1, 0x00e78998}, /* U+7258 */ - {0x00e0b2, 0x00e789b4}, /* U+7274 */ - {0x00e0b3, 0x00e789be}, /* U+727E */ - {0x00e0b4, 0x00e78a82}, /* U+7282 */ - {0x00e0b5, 0x00e78a81}, /* U+7281 */ - {0x00e0b6, 0x00e78a87}, /* U+7287 */ - {0x00e0b7, 0x00e78a92}, /* U+7292 */ - {0x00e0b8, 0x00e78a96}, /* U+7296 */ - {0x00e0b9, 0x00e78aa2}, /* U+72A2 */ - {0x00e0ba, 0x00e78aa7}, /* U+72A7 */ - {0x00e0bb, 0x00e78ab9}, /* U+72B9 */ - {0x00e0bc, 0x00e78ab2}, /* U+72B2 */ - {0x00e0bd, 0x00e78b83}, /* U+72C3 */ - {0x00e0be, 0x00e78b86}, /* U+72C6 */ - {0x00e0bf, 0x00e78b84}, /* U+72C4 */ - {0x00e0c0, 0x00e78b8e}, /* U+72CE */ - {0x00e0c1, 0x00e78b92}, /* U+72D2 */ - {0x00e0c2, 0x00e78ba2}, /* U+72E2 */ - {0x00e0c3, 0x00e78ba0}, /* U+72E0 */ - {0x00e0c4, 0x00e78ba1}, /* U+72E1 */ - {0x00e0c5, 0x00e78bb9}, /* U+72F9 */ - {0x00e0c6, 0x00e78bb7}, /* U+72F7 */ - {0x00e0c7, 0x00e5808f}, /* U+500F */ - {0x00e0c8, 0x00e78c97}, /* U+7317 */ - {0x00e0c9, 0x00e78c8a}, /* U+730A */ - {0x00e0ca, 0x00e78c9c}, /* U+731C */ - {0x00e0cb, 0x00e78c96}, /* U+7316 */ - {0x00e0cc, 0x00e78c9d}, /* U+731D */ - {0x00e0cd, 0x00e78cb4}, /* U+7334 */ - {0x00e0ce, 0x00e78caf}, /* U+732F */ - {0x00e0cf, 0x00e78ca9}, /* U+7329 */ - {0x00e0d0, 0x00e78ca5}, /* U+7325 */ - {0x00e0d1, 0x00e78cbe}, /* U+733E */ - {0x00e0d2, 0x00e78d8e}, /* U+734E */ - {0x00e0d3, 0x00e78d8f}, /* U+734F */ - {0x00e0d4, 0x00e9bb98}, /* U+9ED8 */ - {0x00e0d5, 0x00e78d97}, /* U+7357 */ - {0x00e0d6, 0x00e78daa}, /* U+736A */ - {0x00e0d7, 0x00e78da8}, /* U+7368 */ - {0x00e0d8, 0x00e78db0}, /* U+7370 */ - {0x00e0d9, 0x00e78db8}, /* U+7378 */ - {0x00e0da, 0x00e78db5}, /* U+7375 */ - {0x00e0db, 0x00e78dbb}, /* U+737B */ - {0x00e0dc, 0x00e78dba}, /* U+737A */ - {0x00e0dd, 0x00e78f88}, /* U+73C8 */ - {0x00e0de, 0x00e78eb3}, /* U+73B3 */ - {0x00e0df, 0x00e78f8e}, /* U+73CE */ - {0x00e0e0, 0x00e78ebb}, /* U+73BB */ - {0x00e0e1, 0x00e78f80}, /* U+73C0 */ - {0x00e0e2, 0x00e78fa5}, /* U+73E5 */ - {0x00e0e3, 0x00e78fae}, /* U+73EE */ - {0x00e0e4, 0x00e78f9e}, /* U+73DE */ - {0x00e0e5, 0x00e792a2}, /* U+74A2 */ - {0x00e0e6, 0x00e79085}, /* U+7405 */ - {0x00e0e7, 0x00e791af}, /* U+746F */ - {0x00e0e8, 0x00e790a5}, /* U+7425 */ - {0x00e0e9, 0x00e78fb8}, /* U+73F8 */ - {0x00e0ea, 0x00e790b2}, /* U+7432 */ - {0x00e0eb, 0x00e790ba}, /* U+743A */ - {0x00e0ec, 0x00e79195}, /* U+7455 */ - {0x00e0ed, 0x00e790bf}, /* U+743F */ - {0x00e0ee, 0x00e7919f}, /* U+745F */ - {0x00e0ef, 0x00e79199}, /* U+7459 */ - {0x00e0f0, 0x00e79181}, /* U+7441 */ - {0x00e0f1, 0x00e7919c}, /* U+745C */ - {0x00e0f2, 0x00e791a9}, /* U+7469 */ - {0x00e0f3, 0x00e791b0}, /* U+7470 */ - {0x00e0f4, 0x00e791a3}, /* U+7463 */ - {0x00e0f5, 0x00e791aa}, /* U+746A */ - {0x00e0f6, 0x00e791b6}, /* U+7476 */ - {0x00e0f7, 0x00e791be}, /* U+747E */ - {0x00e0f8, 0x00e7928b}, /* U+748B */ - {0x00e0f9, 0x00e7929e}, /* U+749E */ - {0x00e0fa, 0x00e792a7}, /* U+74A7 */ - {0x00e0fb, 0x00e7938a}, /* U+74CA */ - {0x00e0fc, 0x00e7938f}, /* U+74CF */ - {0x00e0fd, 0x00e79394}, /* U+74D4 */ - {0x00e0fe, 0x00e78fb1}, /* U+73F1 */ - {0x00e1a1, 0x00e793a0}, /* U+74E0 */ - {0x00e1a2, 0x00e793a3}, /* U+74E3 */ - {0x00e1a3, 0x00e793a7}, /* U+74E7 */ - {0x00e1a4, 0x00e793a9}, /* U+74E9 */ - {0x00e1a5, 0x00e793ae}, /* U+74EE */ - {0x00e1a6, 0x00e793b2}, /* U+74F2 */ - {0x00e1a7, 0x00e793b0}, /* U+74F0 */ - {0x00e1a8, 0x00e793b1}, /* U+74F1 */ - {0x00e1a9, 0x00e793b8}, /* U+74F8 */ - {0x00e1aa, 0x00e793b7}, /* U+74F7 */ - {0x00e1ab, 0x00e79484}, /* U+7504 */ - {0x00e1ac, 0x00e79483}, /* U+7503 */ - {0x00e1ad, 0x00e79485}, /* U+7505 */ - {0x00e1ae, 0x00e7948c}, /* U+750C */ - {0x00e1af, 0x00e7948e}, /* U+750E */ - {0x00e1b0, 0x00e7948d}, /* U+750D */ - {0x00e1b1, 0x00e79495}, /* U+7515 */ - {0x00e1b2, 0x00e79493}, /* U+7513 */ - {0x00e1b3, 0x00e7949e}, /* U+751E */ - {0x00e1b4, 0x00e794a6}, /* U+7526 */ - {0x00e1b5, 0x00e794ac}, /* U+752C */ - {0x00e1b6, 0x00e794bc}, /* U+753C */ - {0x00e1b7, 0x00e79584}, /* U+7544 */ - {0x00e1b8, 0x00e7958d}, /* U+754D */ - {0x00e1b9, 0x00e7958a}, /* U+754A */ - {0x00e1ba, 0x00e79589}, /* U+7549 */ - {0x00e1bb, 0x00e7959b}, /* U+755B */ - {0x00e1bc, 0x00e79586}, /* U+7546 */ - {0x00e1bd, 0x00e7959a}, /* U+755A */ - {0x00e1be, 0x00e795a9}, /* U+7569 */ - {0x00e1bf, 0x00e795a4}, /* U+7564 */ - {0x00e1c0, 0x00e795a7}, /* U+7567 */ - {0x00e1c1, 0x00e795ab}, /* U+756B */ - {0x00e1c2, 0x00e795ad}, /* U+756D */ - {0x00e1c3, 0x00e795b8}, /* U+7578 */ - {0x00e1c4, 0x00e795b6}, /* U+7576 */ - {0x00e1c5, 0x00e79686}, /* U+7586 */ - {0x00e1c6, 0x00e79687}, /* U+7587 */ - {0x00e1c7, 0x00e795b4}, /* U+7574 */ - {0x00e1c8, 0x00e7968a}, /* U+758A */ - {0x00e1c9, 0x00e79689}, /* U+7589 */ - {0x00e1ca, 0x00e79682}, /* U+7582 */ - {0x00e1cb, 0x00e79694}, /* U+7594 */ - {0x00e1cc, 0x00e7969a}, /* U+759A */ - {0x00e1cd, 0x00e7969d}, /* U+759D */ - {0x00e1ce, 0x00e796a5}, /* U+75A5 */ - {0x00e1cf, 0x00e796a3}, /* U+75A3 */ - {0x00e1d0, 0x00e79782}, /* U+75C2 */ - {0x00e1d1, 0x00e796b3}, /* U+75B3 */ - {0x00e1d2, 0x00e79783}, /* U+75C3 */ - {0x00e1d3, 0x00e796b5}, /* U+75B5 */ - {0x00e1d4, 0x00e796bd}, /* U+75BD */ - {0x00e1d5, 0x00e796b8}, /* U+75B8 */ - {0x00e1d6, 0x00e796bc}, /* U+75BC */ - {0x00e1d7, 0x00e796b1}, /* U+75B1 */ - {0x00e1d8, 0x00e7978d}, /* U+75CD */ - {0x00e1d9, 0x00e7978a}, /* U+75CA */ - {0x00e1da, 0x00e79792}, /* U+75D2 */ - {0x00e1db, 0x00e79799}, /* U+75D9 */ - {0x00e1dc, 0x00e797a3}, /* U+75E3 */ - {0x00e1dd, 0x00e7979e}, /* U+75DE */ - {0x00e1de, 0x00e797be}, /* U+75FE */ - {0x00e1df, 0x00e797bf}, /* U+75FF */ - {0x00e1e0, 0x00e797bc}, /* U+75FC */ - {0x00e1e1, 0x00e79881}, /* U+7601 */ - {0x00e1e2, 0x00e797b0}, /* U+75F0 */ - {0x00e1e3, 0x00e797ba}, /* U+75FA */ - {0x00e1e4, 0x00e797b2}, /* U+75F2 */ - {0x00e1e5, 0x00e797b3}, /* U+75F3 */ - {0x00e1e6, 0x00e7988b}, /* U+760B */ - {0x00e1e7, 0x00e7988d}, /* U+760D */ - {0x00e1e8, 0x00e79889}, /* U+7609 */ - {0x00e1e9, 0x00e7989f}, /* U+761F */ - {0x00e1ea, 0x00e798a7}, /* U+7627 */ - {0x00e1eb, 0x00e798a0}, /* U+7620 */ - {0x00e1ec, 0x00e798a1}, /* U+7621 */ - {0x00e1ed, 0x00e798a2}, /* U+7622 */ - {0x00e1ee, 0x00e798a4}, /* U+7624 */ - {0x00e1ef, 0x00e798b4}, /* U+7634 */ - {0x00e1f0, 0x00e798b0}, /* U+7630 */ - {0x00e1f1, 0x00e798bb}, /* U+763B */ - {0x00e1f2, 0x00e79987}, /* U+7647 */ - {0x00e1f3, 0x00e79988}, /* U+7648 */ - {0x00e1f4, 0x00e79986}, /* U+7646 */ - {0x00e1f5, 0x00e7999c}, /* U+765C */ - {0x00e1f6, 0x00e79998}, /* U+7658 */ - {0x00e1f7, 0x00e799a1}, /* U+7661 */ - {0x00e1f8, 0x00e799a2}, /* U+7662 */ - {0x00e1f9, 0x00e799a8}, /* U+7668 */ - {0x00e1fa, 0x00e799a9}, /* U+7669 */ - {0x00e1fb, 0x00e799aa}, /* U+766A */ - {0x00e1fc, 0x00e799a7}, /* U+7667 */ - {0x00e1fd, 0x00e799ac}, /* U+766C */ - {0x00e1fe, 0x00e799b0}, /* U+7670 */ - {0x00e2a1, 0x00e799b2}, /* U+7672 */ - {0x00e2a2, 0x00e799b6}, /* U+7676 */ - {0x00e2a3, 0x00e799b8}, /* U+7678 */ - {0x00e2a4, 0x00e799bc}, /* U+767C */ - {0x00e2a5, 0x00e79a80}, /* U+7680 */ - {0x00e2a6, 0x00e79a83}, /* U+7683 */ - {0x00e2a7, 0x00e79a88}, /* U+7688 */ - {0x00e2a8, 0x00e79a8b}, /* U+768B */ - {0x00e2a9, 0x00e79a8e}, /* U+768E */ - {0x00e2aa, 0x00e79a96}, /* U+7696 */ - {0x00e2ab, 0x00e79a93}, /* U+7693 */ - {0x00e2ac, 0x00e79a99}, /* U+7699 */ - {0x00e2ad, 0x00e79a9a}, /* U+769A */ - {0x00e2ae, 0x00e79ab0}, /* U+76B0 */ - {0x00e2af, 0x00e79ab4}, /* U+76B4 */ - {0x00e2b0, 0x00e79ab8}, /* U+76B8 */ - {0x00e2b1, 0x00e79ab9}, /* U+76B9 */ - {0x00e2b2, 0x00e79aba}, /* U+76BA */ - {0x00e2b3, 0x00e79b82}, /* U+76C2 */ - {0x00e2b4, 0x00e79b8d}, /* U+76CD */ - {0x00e2b5, 0x00e79b96}, /* U+76D6 */ - {0x00e2b6, 0x00e79b92}, /* U+76D2 */ - {0x00e2b7, 0x00e79b9e}, /* U+76DE */ - {0x00e2b8, 0x00e79ba1}, /* U+76E1 */ - {0x00e2b9, 0x00e79ba5}, /* U+76E5 */ - {0x00e2ba, 0x00e79ba7}, /* U+76E7 */ - {0x00e2bb, 0x00e79baa}, /* U+76EA */ - {0x00e2bc, 0x00e898af}, /* U+862F */ - {0x00e2bd, 0x00e79bbb}, /* U+76FB */ - {0x00e2be, 0x00e79c88}, /* U+7708 */ - {0x00e2bf, 0x00e79c87}, /* U+7707 */ - {0x00e2c0, 0x00e79c84}, /* U+7704 */ - {0x00e2c1, 0x00e79ca9}, /* U+7729 */ - {0x00e2c2, 0x00e79ca4}, /* U+7724 */ - {0x00e2c3, 0x00e79c9e}, /* U+771E */ - {0x00e2c4, 0x00e79ca5}, /* U+7725 */ - {0x00e2c5, 0x00e79ca6}, /* U+7726 */ - {0x00e2c6, 0x00e79c9b}, /* U+771B */ - {0x00e2c7, 0x00e79cb7}, /* U+7737 */ - {0x00e2c8, 0x00e79cb8}, /* U+7738 */ - {0x00e2c9, 0x00e79d87}, /* U+7747 */ - {0x00e2ca, 0x00e79d9a}, /* U+775A */ - {0x00e2cb, 0x00e79da8}, /* U+7768 */ - {0x00e2cc, 0x00e79dab}, /* U+776B */ - {0x00e2cd, 0x00e79d9b}, /* U+775B */ - {0x00e2ce, 0x00e79da5}, /* U+7765 */ - {0x00e2cf, 0x00e79dbf}, /* U+777F */ - {0x00e2d0, 0x00e79dbe}, /* U+777E */ - {0x00e2d1, 0x00e79db9}, /* U+7779 */ - {0x00e2d2, 0x00e79e8e}, /* U+778E */ - {0x00e2d3, 0x00e79e8b}, /* U+778B */ - {0x00e2d4, 0x00e79e91}, /* U+7791 */ - {0x00e2d5, 0x00e79ea0}, /* U+77A0 */ - {0x00e2d6, 0x00e79e9e}, /* U+779E */ - {0x00e2d7, 0x00e79eb0}, /* U+77B0 */ - {0x00e2d8, 0x00e79eb6}, /* U+77B6 */ - {0x00e2d9, 0x00e79eb9}, /* U+77B9 */ - {0x00e2da, 0x00e79ebf}, /* U+77BF */ - {0x00e2db, 0x00e79ebc}, /* U+77BC */ - {0x00e2dc, 0x00e79ebd}, /* U+77BD */ - {0x00e2dd, 0x00e79ebb}, /* U+77BB */ - {0x00e2de, 0x00e79f87}, /* U+77C7 */ - {0x00e2df, 0x00e79f8d}, /* U+77CD */ - {0x00e2e0, 0x00e79f97}, /* U+77D7 */ - {0x00e2e1, 0x00e79f9a}, /* U+77DA */ - {0x00e2e2, 0x00e79f9c}, /* U+77DC */ - {0x00e2e3, 0x00e79fa3}, /* U+77E3 */ - {0x00e2e4, 0x00e79fae}, /* U+77EE */ - {0x00e2e5, 0x00e79fbc}, /* U+77FC */ - {0x00e2e6, 0x00e7a08c}, /* U+780C */ - {0x00e2e7, 0x00e7a092}, /* U+7812 */ - {0x00e2e8, 0x00e7a4a6}, /* U+7926 */ - {0x00e2e9, 0x00e7a0a0}, /* U+7820 */ - {0x00e2ea, 0x00e7a4aa}, /* U+792A */ - {0x00e2eb, 0x00e7a185}, /* U+7845 */ - {0x00e2ec, 0x00e7a28e}, /* U+788E */ - {0x00e2ed, 0x00e7a1b4}, /* U+7874 */ - {0x00e2ee, 0x00e7a286}, /* U+7886 */ - {0x00e2ef, 0x00e7a1bc}, /* U+787C */ - {0x00e2f0, 0x00e7a29a}, /* U+789A */ - {0x00e2f1, 0x00e7a28c}, /* U+788C */ - {0x00e2f2, 0x00e7a2a3}, /* U+78A3 */ - {0x00e2f3, 0x00e7a2b5}, /* U+78B5 */ - {0x00e2f4, 0x00e7a2aa}, /* U+78AA */ - {0x00e2f5, 0x00e7a2af}, /* U+78AF */ - {0x00e2f6, 0x00e7a391}, /* U+78D1 */ - {0x00e2f7, 0x00e7a386}, /* U+78C6 */ - {0x00e2f8, 0x00e7a38b}, /* U+78CB */ - {0x00e2f9, 0x00e7a394}, /* U+78D4 */ - {0x00e2fa, 0x00e7a2be}, /* U+78BE */ - {0x00e2fb, 0x00e7a2bc}, /* U+78BC */ - {0x00e2fc, 0x00e7a385}, /* U+78C5 */ - {0x00e2fd, 0x00e7a38a}, /* U+78CA */ - {0x00e2fe, 0x00e7a3ac}, /* U+78EC */ - {0x00e3a1, 0x00e7a3a7}, /* U+78E7 */ - {0x00e3a2, 0x00e7a39a}, /* U+78DA */ - {0x00e3a3, 0x00e7a3bd}, /* U+78FD */ - {0x00e3a4, 0x00e7a3b4}, /* U+78F4 */ - {0x00e3a5, 0x00e7a487}, /* U+7907 */ - {0x00e3a6, 0x00e7a492}, /* U+7912 */ - {0x00e3a7, 0x00e7a491}, /* U+7911 */ - {0x00e3a8, 0x00e7a499}, /* U+7919 */ - {0x00e3a9, 0x00e7a4ac}, /* U+792C */ - {0x00e3aa, 0x00e7a4ab}, /* U+792B */ - {0x00e3ab, 0x00e7a580}, /* U+7940 */ - {0x00e3ac, 0x00e7a5a0}, /* U+7960 */ - {0x00e3ad, 0x00e7a597}, /* U+7957 */ - {0x00e3ae, 0x00e7a59f}, /* U+795F */ - {0x00e3af, 0x00e7a59a}, /* U+795A */ - {0x00e3b0, 0x00e7a595}, /* U+7955 */ - {0x00e3b1, 0x00e7a593}, /* U+7953 */ - {0x00e3b2, 0x00e7a5ba}, /* U+797A */ - {0x00e3b3, 0x00e7a5bf}, /* U+797F */ - {0x00e3b4, 0x00e7a68a}, /* U+798A */ - {0x00e3b5, 0x00e7a69d}, /* U+799D */ - {0x00e3b6, 0x00e7a6a7}, /* U+79A7 */ - {0x00e3b7, 0x00e9bd8b}, /* U+9F4B */ - {0x00e3b8, 0x00e7a6aa}, /* U+79AA */ - {0x00e3b9, 0x00e7a6ae}, /* U+79AE */ - {0x00e3ba, 0x00e7a6b3}, /* U+79B3 */ - {0x00e3bb, 0x00e7a6b9}, /* U+79B9 */ - {0x00e3bc, 0x00e7a6ba}, /* U+79BA */ - {0x00e3bd, 0x00e7a789}, /* U+79C9 */ - {0x00e3be, 0x00e7a795}, /* U+79D5 */ - {0x00e3bf, 0x00e7a7a7}, /* U+79E7 */ - {0x00e3c0, 0x00e7a7ac}, /* U+79EC */ - {0x00e3c1, 0x00e7a7a1}, /* U+79E1 */ - {0x00e3c2, 0x00e7a7a3}, /* U+79E3 */ - {0x00e3c3, 0x00e7a888}, /* U+7A08 */ - {0x00e3c4, 0x00e7a88d}, /* U+7A0D */ - {0x00e3c5, 0x00e7a898}, /* U+7A18 */ - {0x00e3c6, 0x00e7a899}, /* U+7A19 */ - {0x00e3c7, 0x00e7a8a0}, /* U+7A20 */ - {0x00e3c8, 0x00e7a89f}, /* U+7A1F */ - {0x00e3c9, 0x00e7a680}, /* U+7980 */ - {0x00e3ca, 0x00e7a8b1}, /* U+7A31 */ - {0x00e3cb, 0x00e7a8bb}, /* U+7A3B */ - {0x00e3cc, 0x00e7a8be}, /* U+7A3E */ - {0x00e3cd, 0x00e7a8b7}, /* U+7A37 */ - {0x00e3ce, 0x00e7a983}, /* U+7A43 */ - {0x00e3cf, 0x00e7a997}, /* U+7A57 */ - {0x00e3d0, 0x00e7a989}, /* U+7A49 */ - {0x00e3d1, 0x00e7a9a1}, /* U+7A61 */ - {0x00e3d2, 0x00e7a9a2}, /* U+7A62 */ - {0x00e3d3, 0x00e7a9a9}, /* U+7A69 */ - {0x00e3d4, 0x00e9be9d}, /* U+9F9D */ - {0x00e3d5, 0x00e7a9b0}, /* U+7A70 */ - {0x00e3d6, 0x00e7a9b9}, /* U+7A79 */ - {0x00e3d7, 0x00e7a9bd}, /* U+7A7D */ - {0x00e3d8, 0x00e7aa88}, /* U+7A88 */ - {0x00e3d9, 0x00e7aa97}, /* U+7A97 */ - {0x00e3da, 0x00e7aa95}, /* U+7A95 */ - {0x00e3db, 0x00e7aa98}, /* U+7A98 */ - {0x00e3dc, 0x00e7aa96}, /* U+7A96 */ - {0x00e3dd, 0x00e7aaa9}, /* U+7AA9 */ - {0x00e3de, 0x00e7ab88}, /* U+7AC8 */ - {0x00e3df, 0x00e7aab0}, /* U+7AB0 */ - {0x00e3e0, 0x00e7aab6}, /* U+7AB6 */ - {0x00e3e1, 0x00e7ab85}, /* U+7AC5 */ - {0x00e3e2, 0x00e7ab84}, /* U+7AC4 */ - {0x00e3e3, 0x00e7aabf}, /* U+7ABF */ - {0x00e3e4, 0x00e98283}, /* U+9083 */ - {0x00e3e5, 0x00e7ab87}, /* U+7AC7 */ - {0x00e3e6, 0x00e7ab8a}, /* U+7ACA */ - {0x00e3e7, 0x00e7ab8d}, /* U+7ACD */ - {0x00e3e8, 0x00e7ab8f}, /* U+7ACF */ - {0x00e3e9, 0x00e7ab95}, /* U+7AD5 */ - {0x00e3ea, 0x00e7ab93}, /* U+7AD3 */ - {0x00e3eb, 0x00e7ab99}, /* U+7AD9 */ - {0x00e3ec, 0x00e7ab9a}, /* U+7ADA */ - {0x00e3ed, 0x00e7ab9d}, /* U+7ADD */ - {0x00e3ee, 0x00e7aba1}, /* U+7AE1 */ - {0x00e3ef, 0x00e7aba2}, /* U+7AE2 */ - {0x00e3f0, 0x00e7aba6}, /* U+7AE6 */ - {0x00e3f1, 0x00e7abad}, /* U+7AED */ - {0x00e3f2, 0x00e7abb0}, /* U+7AF0 */ - {0x00e3f3, 0x00e7ac82}, /* U+7B02 */ - {0x00e3f4, 0x00e7ac8f}, /* U+7B0F */ - {0x00e3f5, 0x00e7ac8a}, /* U+7B0A */ - {0x00e3f6, 0x00e7ac86}, /* U+7B06 */ - {0x00e3f7, 0x00e7acb3}, /* U+7B33 */ - {0x00e3f8, 0x00e7ac98}, /* U+7B18 */ - {0x00e3f9, 0x00e7ac99}, /* U+7B19 */ - {0x00e3fa, 0x00e7ac9e}, /* U+7B1E */ - {0x00e3fb, 0x00e7acb5}, /* U+7B35 */ - {0x00e3fc, 0x00e7aca8}, /* U+7B28 */ - {0x00e3fd, 0x00e7acb6}, /* U+7B36 */ - {0x00e3fe, 0x00e7ad90}, /* U+7B50 */ - {0x00e4a1, 0x00e7adba}, /* U+7B7A */ - {0x00e4a2, 0x00e7ac84}, /* U+7B04 */ - {0x00e4a3, 0x00e7ad8d}, /* U+7B4D */ - {0x00e4a4, 0x00e7ac8b}, /* U+7B0B */ - {0x00e4a5, 0x00e7ad8c}, /* U+7B4C */ - {0x00e4a6, 0x00e7ad85}, /* U+7B45 */ - {0x00e4a7, 0x00e7adb5}, /* U+7B75 */ - {0x00e4a8, 0x00e7ada5}, /* U+7B65 */ - {0x00e4a9, 0x00e7adb4}, /* U+7B74 */ - {0x00e4aa, 0x00e7ada7}, /* U+7B67 */ - {0x00e4ab, 0x00e7adb0}, /* U+7B70 */ - {0x00e4ac, 0x00e7adb1}, /* U+7B71 */ - {0x00e4ad, 0x00e7adac}, /* U+7B6C */ - {0x00e4ae, 0x00e7adae}, /* U+7B6E */ - {0x00e4af, 0x00e7ae9d}, /* U+7B9D */ - {0x00e4b0, 0x00e7ae98}, /* U+7B98 */ - {0x00e4b1, 0x00e7ae9f}, /* U+7B9F */ - {0x00e4b2, 0x00e7ae8d}, /* U+7B8D */ - {0x00e4b3, 0x00e7ae9c}, /* U+7B9C */ - {0x00e4b4, 0x00e7ae9a}, /* U+7B9A */ - {0x00e4b5, 0x00e7ae8b}, /* U+7B8B */ - {0x00e4b6, 0x00e7ae92}, /* U+7B92 */ - {0x00e4b7, 0x00e7ae8f}, /* U+7B8F */ - {0x00e4b8, 0x00e7ad9d}, /* U+7B5D */ - {0x00e4b9, 0x00e7ae99}, /* U+7B99 */ - {0x00e4ba, 0x00e7af8b}, /* U+7BCB */ - {0x00e4bb, 0x00e7af81}, /* U+7BC1 */ - {0x00e4bc, 0x00e7af8c}, /* U+7BCC */ - {0x00e4bd, 0x00e7af8f}, /* U+7BCF */ - {0x00e4be, 0x00e7aeb4}, /* U+7BB4 */ - {0x00e4bf, 0x00e7af86}, /* U+7BC6 */ - {0x00e4c0, 0x00e7af9d}, /* U+7BDD */ - {0x00e4c1, 0x00e7afa9}, /* U+7BE9 */ - {0x00e4c2, 0x00e7b091}, /* U+7C11 */ - {0x00e4c3, 0x00e7b094}, /* U+7C14 */ - {0x00e4c4, 0x00e7afa6}, /* U+7BE6 */ - {0x00e4c5, 0x00e7afa5}, /* U+7BE5 */ - {0x00e4c6, 0x00e7b1a0}, /* U+7C60 */ - {0x00e4c7, 0x00e7b080}, /* U+7C00 */ - {0x00e4c8, 0x00e7b087}, /* U+7C07 */ - {0x00e4c9, 0x00e7b093}, /* U+7C13 */ - {0x00e4ca, 0x00e7afb3}, /* U+7BF3 */ - {0x00e4cb, 0x00e7afb7}, /* U+7BF7 */ - {0x00e4cc, 0x00e7b097}, /* U+7C17 */ - {0x00e4cd, 0x00e7b08d}, /* U+7C0D */ - {0x00e4ce, 0x00e7afb6}, /* U+7BF6 */ - {0x00e4cf, 0x00e7b0a3}, /* U+7C23 */ - {0x00e4d0, 0x00e7b0a7}, /* U+7C27 */ - {0x00e4d1, 0x00e7b0aa}, /* U+7C2A */ - {0x00e4d2, 0x00e7b09f}, /* U+7C1F */ - {0x00e4d3, 0x00e7b0b7}, /* U+7C37 */ - {0x00e4d4, 0x00e7b0ab}, /* U+7C2B */ - {0x00e4d5, 0x00e7b0bd}, /* U+7C3D */ - {0x00e4d6, 0x00e7b18c}, /* U+7C4C */ - {0x00e4d7, 0x00e7b183}, /* U+7C43 */ - {0x00e4d8, 0x00e7b194}, /* U+7C54 */ - {0x00e4d9, 0x00e7b18f}, /* U+7C4F */ - {0x00e4da, 0x00e7b180}, /* U+7C40 */ - {0x00e4db, 0x00e7b190}, /* U+7C50 */ - {0x00e4dc, 0x00e7b198}, /* U+7C58 */ - {0x00e4dd, 0x00e7b19f}, /* U+7C5F */ - {0x00e4de, 0x00e7b1a4}, /* U+7C64 */ - {0x00e4df, 0x00e7b196}, /* U+7C56 */ - {0x00e4e0, 0x00e7b1a5}, /* U+7C65 */ - {0x00e4e1, 0x00e7b1ac}, /* U+7C6C */ - {0x00e4e2, 0x00e7b1b5}, /* U+7C75 */ - {0x00e4e3, 0x00e7b283}, /* U+7C83 */ - {0x00e4e4, 0x00e7b290}, /* U+7C90 */ - {0x00e4e5, 0x00e7b2a4}, /* U+7CA4 */ - {0x00e4e6, 0x00e7b2ad}, /* U+7CAD */ - {0x00e4e7, 0x00e7b2a2}, /* U+7CA2 */ - {0x00e4e8, 0x00e7b2ab}, /* U+7CAB */ - {0x00e4e9, 0x00e7b2a1}, /* U+7CA1 */ - {0x00e4ea, 0x00e7b2a8}, /* U+7CA8 */ - {0x00e4eb, 0x00e7b2b3}, /* U+7CB3 */ - {0x00e4ec, 0x00e7b2b2}, /* U+7CB2 */ - {0x00e4ed, 0x00e7b2b1}, /* U+7CB1 */ - {0x00e4ee, 0x00e7b2ae}, /* U+7CAE */ - {0x00e4ef, 0x00e7b2b9}, /* U+7CB9 */ - {0x00e4f0, 0x00e7b2bd}, /* U+7CBD */ - {0x00e4f1, 0x00e7b380}, /* U+7CC0 */ - {0x00e4f2, 0x00e7b385}, /* U+7CC5 */ - {0x00e4f3, 0x00e7b382}, /* U+7CC2 */ - {0x00e4f4, 0x00e7b398}, /* U+7CD8 */ - {0x00e4f5, 0x00e7b392}, /* U+7CD2 */ - {0x00e4f6, 0x00e7b39c}, /* U+7CDC */ - {0x00e4f7, 0x00e7b3a2}, /* U+7CE2 */ - {0x00e4f8, 0x00e9acbb}, /* U+9B3B */ - {0x00e4f9, 0x00e7b3af}, /* U+7CEF */ - {0x00e4fa, 0x00e7b3b2}, /* U+7CF2 */ - {0x00e4fb, 0x00e7b3b4}, /* U+7CF4 */ - {0x00e4fc, 0x00e7b3b6}, /* U+7CF6 */ - {0x00e4fd, 0x00e7b3ba}, /* U+7CFA */ - {0x00e4fe, 0x00e7b486}, /* U+7D06 */ - {0x00e5a1, 0x00e7b482}, /* U+7D02 */ - {0x00e5a2, 0x00e7b49c}, /* U+7D1C */ - {0x00e5a3, 0x00e7b495}, /* U+7D15 */ - {0x00e5a4, 0x00e7b48a}, /* U+7D0A */ - {0x00e5a5, 0x00e7b585}, /* U+7D45 */ - {0x00e5a6, 0x00e7b58b}, /* U+7D4B */ - {0x00e5a7, 0x00e7b4ae}, /* U+7D2E */ - {0x00e5a8, 0x00e7b4b2}, /* U+7D32 */ - {0x00e5a9, 0x00e7b4bf}, /* U+7D3F */ - {0x00e5aa, 0x00e7b4b5}, /* U+7D35 */ - {0x00e5ab, 0x00e7b586}, /* U+7D46 */ - {0x00e5ac, 0x00e7b5b3}, /* U+7D73 */ - {0x00e5ad, 0x00e7b596}, /* U+7D56 */ - {0x00e5ae, 0x00e7b58e}, /* U+7D4E */ - {0x00e5af, 0x00e7b5b2}, /* U+7D72 */ - {0x00e5b0, 0x00e7b5a8}, /* U+7D68 */ - {0x00e5b1, 0x00e7b5ae}, /* U+7D6E */ - {0x00e5b2, 0x00e7b58f}, /* U+7D4F */ - {0x00e5b3, 0x00e7b5a3}, /* U+7D63 */ - {0x00e5b4, 0x00e7b693}, /* U+7D93 */ - {0x00e5b5, 0x00e7b689}, /* U+7D89 */ - {0x00e5b6, 0x00e7b59b}, /* U+7D5B */ - {0x00e5b7, 0x00e7b68f}, /* U+7D8F */ - {0x00e5b8, 0x00e7b5bd}, /* U+7D7D */ - {0x00e5b9, 0x00e7b69b}, /* U+7D9B */ - {0x00e5ba, 0x00e7b6ba}, /* U+7DBA */ - {0x00e5bb, 0x00e7b6ae}, /* U+7DAE */ - {0x00e5bc, 0x00e7b6a3}, /* U+7DA3 */ - {0x00e5bd, 0x00e7b6b5}, /* U+7DB5 */ - {0x00e5be, 0x00e7b787}, /* U+7DC7 */ - {0x00e5bf, 0x00e7b6bd}, /* U+7DBD */ - {0x00e5c0, 0x00e7b6ab}, /* U+7DAB */ - {0x00e5c1, 0x00e7b8bd}, /* U+7E3D */ - {0x00e5c2, 0x00e7b6a2}, /* U+7DA2 */ - {0x00e5c3, 0x00e7b6af}, /* U+7DAF */ - {0x00e5c4, 0x00e7b79c}, /* U+7DDC */ - {0x00e5c5, 0x00e7b6b8}, /* U+7DB8 */ - {0x00e5c6, 0x00e7b69f}, /* U+7D9F */ - {0x00e5c7, 0x00e7b6b0}, /* U+7DB0 */ - {0x00e5c8, 0x00e7b798}, /* U+7DD8 */ - {0x00e5c9, 0x00e7b79d}, /* U+7DDD */ - {0x00e5ca, 0x00e7b7a4}, /* U+7DE4 */ - {0x00e5cb, 0x00e7b79e}, /* U+7DDE */ - {0x00e5cc, 0x00e7b7bb}, /* U+7DFB */ - {0x00e5cd, 0x00e7b7b2}, /* U+7DF2 */ - {0x00e5ce, 0x00e7b7a1}, /* U+7DE1 */ - {0x00e5cf, 0x00e7b885}, /* U+7E05 */ - {0x00e5d0, 0x00e7b88a}, /* U+7E0A */ - {0x00e5d1, 0x00e7b8a3}, /* U+7E23 */ - {0x00e5d2, 0x00e7b8a1}, /* U+7E21 */ - {0x00e5d3, 0x00e7b892}, /* U+7E12 */ - {0x00e5d4, 0x00e7b8b1}, /* U+7E31 */ - {0x00e5d5, 0x00e7b89f}, /* U+7E1F */ - {0x00e5d6, 0x00e7b889}, /* U+7E09 */ - {0x00e5d7, 0x00e7b88b}, /* U+7E0B */ - {0x00e5d8, 0x00e7b8a2}, /* U+7E22 */ - {0x00e5d9, 0x00e7b986}, /* U+7E46 */ - {0x00e5da, 0x00e7b9a6}, /* U+7E66 */ - {0x00e5db, 0x00e7b8bb}, /* U+7E3B */ - {0x00e5dc, 0x00e7b8b5}, /* U+7E35 */ - {0x00e5dd, 0x00e7b8b9}, /* U+7E39 */ - {0x00e5de, 0x00e7b983}, /* U+7E43 */ - {0x00e5df, 0x00e7b8b7}, /* U+7E37 */ - {0x00e5e0, 0x00e7b8b2}, /* U+7E32 */ - {0x00e5e1, 0x00e7b8ba}, /* U+7E3A */ - {0x00e5e2, 0x00e7b9a7}, /* U+7E67 */ - {0x00e5e3, 0x00e7b99d}, /* U+7E5D */ - {0x00e5e4, 0x00e7b996}, /* U+7E56 */ - {0x00e5e5, 0x00e7b99e}, /* U+7E5E */ - {0x00e5e6, 0x00e7b999}, /* U+7E59 */ - {0x00e5e7, 0x00e7b99a}, /* U+7E5A */ - {0x00e5e8, 0x00e7b9b9}, /* U+7E79 */ - {0x00e5e9, 0x00e7b9aa}, /* U+7E6A */ - {0x00e5ea, 0x00e7b9a9}, /* U+7E69 */ - {0x00e5eb, 0x00e7b9bc}, /* U+7E7C */ - {0x00e5ec, 0x00e7b9bb}, /* U+7E7B */ - {0x00e5ed, 0x00e7ba83}, /* U+7E83 */ - {0x00e5ee, 0x00e7b795}, /* U+7DD5 */ - {0x00e5ef, 0x00e7b9bd}, /* U+7E7D */ - {0x00e5f0, 0x00e8beae}, /* U+8FAE */ - {0x00e5f1, 0x00e7b9bf}, /* U+7E7F */ - {0x00e5f2, 0x00e7ba88}, /* U+7E88 */ - {0x00e5f3, 0x00e7ba89}, /* U+7E89 */ - {0x00e5f4, 0x00e7ba8c}, /* U+7E8C */ - {0x00e5f5, 0x00e7ba92}, /* U+7E92 */ - {0x00e5f6, 0x00e7ba90}, /* U+7E90 */ - {0x00e5f7, 0x00e7ba93}, /* U+7E93 */ - {0x00e5f8, 0x00e7ba94}, /* U+7E94 */ - {0x00e5f9, 0x00e7ba96}, /* U+7E96 */ - {0x00e5fa, 0x00e7ba8e}, /* U+7E8E */ - {0x00e5fb, 0x00e7ba9b}, /* U+7E9B */ - {0x00e5fc, 0x00e7ba9c}, /* U+7E9C */ - {0x00e5fd, 0x00e7bcb8}, /* U+7F38 */ - {0x00e5fe, 0x00e7bcba}, /* U+7F3A */ - {0x00e6a1, 0x00e7bd85}, /* U+7F45 */ - {0x00e6a2, 0x00e7bd8c}, /* U+7F4C */ - {0x00e6a3, 0x00e7bd8d}, /* U+7F4D */ - {0x00e6a4, 0x00e7bd8e}, /* U+7F4E */ - {0x00e6a5, 0x00e7bd90}, /* U+7F50 */ - {0x00e6a6, 0x00e7bd91}, /* U+7F51 */ - {0x00e6a7, 0x00e7bd95}, /* U+7F55 */ - {0x00e6a8, 0x00e7bd94}, /* U+7F54 */ - {0x00e6a9, 0x00e7bd98}, /* U+7F58 */ - {0x00e6aa, 0x00e7bd9f}, /* U+7F5F */ - {0x00e6ab, 0x00e7bda0}, /* U+7F60 */ - {0x00e6ac, 0x00e7bda8}, /* U+7F68 */ - {0x00e6ad, 0x00e7bda9}, /* U+7F69 */ - {0x00e6ae, 0x00e7bda7}, /* U+7F67 */ - {0x00e6af, 0x00e7bdb8}, /* U+7F78 */ - {0x00e6b0, 0x00e7be82}, /* U+7F82 */ - {0x00e6b1, 0x00e7be86}, /* U+7F86 */ - {0x00e6b2, 0x00e7be83}, /* U+7F83 */ - {0x00e6b3, 0x00e7be88}, /* U+7F88 */ - {0x00e6b4, 0x00e7be87}, /* U+7F87 */ - {0x00e6b5, 0x00e7be8c}, /* U+7F8C */ - {0x00e6b6, 0x00e7be94}, /* U+7F94 */ - {0x00e6b7, 0x00e7be9e}, /* U+7F9E */ - {0x00e6b8, 0x00e7be9d}, /* U+7F9D */ - {0x00e6b9, 0x00e7be9a}, /* U+7F9A */ - {0x00e6ba, 0x00e7bea3}, /* U+7FA3 */ - {0x00e6bb, 0x00e7beaf}, /* U+7FAF */ - {0x00e6bc, 0x00e7beb2}, /* U+7FB2 */ - {0x00e6bd, 0x00e7beb9}, /* U+7FB9 */ - {0x00e6be, 0x00e7beae}, /* U+7FAE */ - {0x00e6bf, 0x00e7beb6}, /* U+7FB6 */ - {0x00e6c0, 0x00e7beb8}, /* U+7FB8 */ - {0x00e6c1, 0x00e8adb1}, /* U+8B71 */ - {0x00e6c2, 0x00e7bf85}, /* U+7FC5 */ - {0x00e6c3, 0x00e7bf86}, /* U+7FC6 */ - {0x00e6c4, 0x00e7bf8a}, /* U+7FCA */ - {0x00e6c5, 0x00e7bf95}, /* U+7FD5 */ - {0x00e6c6, 0x00e7bf94}, /* U+7FD4 */ - {0x00e6c7, 0x00e7bfa1}, /* U+7FE1 */ - {0x00e6c8, 0x00e7bfa6}, /* U+7FE6 */ - {0x00e6c9, 0x00e7bfa9}, /* U+7FE9 */ - {0x00e6ca, 0x00e7bfb3}, /* U+7FF3 */ - {0x00e6cb, 0x00e7bfb9}, /* U+7FF9 */ - {0x00e6cc, 0x00e9a39c}, /* U+98DC */ - {0x00e6cd, 0x00e88086}, /* U+8006 */ - {0x00e6ce, 0x00e88084}, /* U+8004 */ - {0x00e6cf, 0x00e8808b}, /* U+800B */ - {0x00e6d0, 0x00e88092}, /* U+8012 */ - {0x00e6d1, 0x00e88098}, /* U+8018 */ - {0x00e6d2, 0x00e88099}, /* U+8019 */ - {0x00e6d3, 0x00e8809c}, /* U+801C */ - {0x00e6d4, 0x00e880a1}, /* U+8021 */ - {0x00e6d5, 0x00e880a8}, /* U+8028 */ - {0x00e6d6, 0x00e880bf}, /* U+803F */ - {0x00e6d7, 0x00e880bb}, /* U+803B */ - {0x00e6d8, 0x00e8818a}, /* U+804A */ - {0x00e6d9, 0x00e88186}, /* U+8046 */ - {0x00e6da, 0x00e88192}, /* U+8052 */ - {0x00e6db, 0x00e88198}, /* U+8058 */ - {0x00e6dc, 0x00e8819a}, /* U+805A */ - {0x00e6dd, 0x00e8819f}, /* U+805F */ - {0x00e6de, 0x00e881a2}, /* U+8062 */ - {0x00e6df, 0x00e881a8}, /* U+8068 */ - {0x00e6e0, 0x00e881b3}, /* U+8073 */ - {0x00e6e1, 0x00e881b2}, /* U+8072 */ - {0x00e6e2, 0x00e881b0}, /* U+8070 */ - {0x00e6e3, 0x00e881b6}, /* U+8076 */ - {0x00e6e4, 0x00e881b9}, /* U+8079 */ - {0x00e6e5, 0x00e881bd}, /* U+807D */ - {0x00e6e6, 0x00e881bf}, /* U+807F */ - {0x00e6e7, 0x00e88284}, /* U+8084 */ - {0x00e6e8, 0x00e88286}, /* U+8086 */ - {0x00e6e9, 0x00e88285}, /* U+8085 */ - {0x00e6ea, 0x00e8829b}, /* U+809B */ - {0x00e6eb, 0x00e88293}, /* U+8093 */ - {0x00e6ec, 0x00e8829a}, /* U+809A */ - {0x00e6ed, 0x00e882ad}, /* U+80AD */ - {0x00e6ee, 0x00e58690}, /* U+5190 */ - {0x00e6ef, 0x00e882ac}, /* U+80AC */ - {0x00e6f0, 0x00e8839b}, /* U+80DB */ - {0x00e6f1, 0x00e883a5}, /* U+80E5 */ - {0x00e6f2, 0x00e88399}, /* U+80D9 */ - {0x00e6f3, 0x00e8839d}, /* U+80DD */ - {0x00e6f4, 0x00e88384}, /* U+80C4 */ - {0x00e6f5, 0x00e8839a}, /* U+80DA */ - {0x00e6f6, 0x00e88396}, /* U+80D6 */ - {0x00e6f7, 0x00e88489}, /* U+8109 */ - {0x00e6f8, 0x00e883af}, /* U+80EF */ - {0x00e6f9, 0x00e883b1}, /* U+80F1 */ - {0x00e6fa, 0x00e8849b}, /* U+811B */ - {0x00e6fb, 0x00e884a9}, /* U+8129 */ - {0x00e6fc, 0x00e884a3}, /* U+8123 */ - {0x00e6fd, 0x00e884af}, /* U+812F */ - {0x00e6fe, 0x00e8858b}, /* U+814B */ - {0x00e7a1, 0x00e99a8b}, /* U+968B */ - {0x00e7a2, 0x00e88586}, /* U+8146 */ - {0x00e7a3, 0x00e884be}, /* U+813E */ - {0x00e7a4, 0x00e88593}, /* U+8153 */ - {0x00e7a5, 0x00e88591}, /* U+8151 */ - {0x00e7a6, 0x00e883bc}, /* U+80FC */ - {0x00e7a7, 0x00e885b1}, /* U+8171 */ - {0x00e7a8, 0x00e885ae}, /* U+816E */ - {0x00e7a9, 0x00e885a5}, /* U+8165 */ - {0x00e7aa, 0x00e885a6}, /* U+8166 */ - {0x00e7ab, 0x00e885b4}, /* U+8174 */ - {0x00e7ac, 0x00e88683}, /* U+8183 */ - {0x00e7ad, 0x00e88688}, /* U+8188 */ - {0x00e7ae, 0x00e8868a}, /* U+818A */ - {0x00e7af, 0x00e88680}, /* U+8180 */ - {0x00e7b0, 0x00e88682}, /* U+8182 */ - {0x00e7b1, 0x00e886a0}, /* U+81A0 */ - {0x00e7b2, 0x00e88695}, /* U+8195 */ - {0x00e7b3, 0x00e886a4}, /* U+81A4 */ - {0x00e7b4, 0x00e886a3}, /* U+81A3 */ - {0x00e7b5, 0x00e8859f}, /* U+815F */ - {0x00e7b6, 0x00e88693}, /* U+8193 */ - {0x00e7b7, 0x00e886a9}, /* U+81A9 */ - {0x00e7b8, 0x00e886b0}, /* U+81B0 */ - {0x00e7b9, 0x00e886b5}, /* U+81B5 */ - {0x00e7ba, 0x00e886be}, /* U+81BE */ - {0x00e7bb, 0x00e886b8}, /* U+81B8 */ - {0x00e7bc, 0x00e886bd}, /* U+81BD */ - {0x00e7bd, 0x00e88780}, /* U+81C0 */ - {0x00e7be, 0x00e88782}, /* U+81C2 */ - {0x00e7bf, 0x00e886ba}, /* U+81BA */ - {0x00e7c0, 0x00e88789}, /* U+81C9 */ - {0x00e7c1, 0x00e8878d}, /* U+81CD */ - {0x00e7c2, 0x00e88791}, /* U+81D1 */ - {0x00e7c3, 0x00e88799}, /* U+81D9 */ - {0x00e7c4, 0x00e88798}, /* U+81D8 */ - {0x00e7c5, 0x00e88788}, /* U+81C8 */ - {0x00e7c6, 0x00e8879a}, /* U+81DA */ - {0x00e7c7, 0x00e8879f}, /* U+81DF */ - {0x00e7c8, 0x00e887a0}, /* U+81E0 */ - {0x00e7c9, 0x00e887a7}, /* U+81E7 */ - {0x00e7ca, 0x00e887ba}, /* U+81FA */ - {0x00e7cb, 0x00e887bb}, /* U+81FB */ - {0x00e7cc, 0x00e887be}, /* U+81FE */ - {0x00e7cd, 0x00e88881}, /* U+8201 */ - {0x00e7ce, 0x00e88882}, /* U+8202 */ - {0x00e7cf, 0x00e88885}, /* U+8205 */ - {0x00e7d0, 0x00e88887}, /* U+8207 */ - {0x00e7d1, 0x00e8888a}, /* U+820A */ - {0x00e7d2, 0x00e8888d}, /* U+820D */ - {0x00e7d3, 0x00e88890}, /* U+8210 */ - {0x00e7d4, 0x00e88896}, /* U+8216 */ - {0x00e7d5, 0x00e888a9}, /* U+8229 */ - {0x00e7d6, 0x00e888ab}, /* U+822B */ - {0x00e7d7, 0x00e888b8}, /* U+8238 */ - {0x00e7d8, 0x00e888b3}, /* U+8233 */ - {0x00e7d9, 0x00e88980}, /* U+8240 */ - {0x00e7da, 0x00e88999}, /* U+8259 */ - {0x00e7db, 0x00e88998}, /* U+8258 */ - {0x00e7dc, 0x00e8899d}, /* U+825D */ - {0x00e7dd, 0x00e8899a}, /* U+825A */ - {0x00e7de, 0x00e8899f}, /* U+825F */ - {0x00e7df, 0x00e889a4}, /* U+8264 */ - {0x00e7e0, 0x00e889a2}, /* U+8262 */ - {0x00e7e1, 0x00e889a8}, /* U+8268 */ - {0x00e7e2, 0x00e889aa}, /* U+826A */ - {0x00e7e3, 0x00e889ab}, /* U+826B */ - {0x00e7e4, 0x00e888ae}, /* U+822E */ - {0x00e7e5, 0x00e889b1}, /* U+8271 */ - {0x00e7e6, 0x00e889b7}, /* U+8277 */ - {0x00e7e7, 0x00e889b8}, /* U+8278 */ - {0x00e7e8, 0x00e889be}, /* U+827E */ - {0x00e7e9, 0x00e88a8d}, /* U+828D */ - {0x00e7ea, 0x00e88a92}, /* U+8292 */ - {0x00e7eb, 0x00e88aab}, /* U+82AB */ - {0x00e7ec, 0x00e88a9f}, /* U+829F */ - {0x00e7ed, 0x00e88abb}, /* U+82BB */ - {0x00e7ee, 0x00e88aac}, /* U+82AC */ - {0x00e7ef, 0x00e88ba1}, /* U+82E1 */ - {0x00e7f0, 0x00e88ba3}, /* U+82E3 */ - {0x00e7f1, 0x00e88b9f}, /* U+82DF */ - {0x00e7f2, 0x00e88b92}, /* U+82D2 */ - {0x00e7f3, 0x00e88bb4}, /* U+82F4 */ - {0x00e7f4, 0x00e88bb3}, /* U+82F3 */ - {0x00e7f5, 0x00e88bba}, /* U+82FA */ - {0x00e7f6, 0x00e88e93}, /* U+8393 */ - {0x00e7f7, 0x00e88c83}, /* U+8303 */ - {0x00e7f8, 0x00e88bbb}, /* U+82FB */ - {0x00e7f9, 0x00e88bb9}, /* U+82F9 */ - {0x00e7fa, 0x00e88b9e}, /* U+82DE */ - {0x00e7fb, 0x00e88c86}, /* U+8306 */ - {0x00e7fc, 0x00e88b9c}, /* U+82DC */ - {0x00e7fd, 0x00e88c89}, /* U+8309 */ - {0x00e7fe, 0x00e88b99}, /* U+82D9 */ - {0x00e8a1, 0x00e88cb5}, /* U+8335 */ - {0x00e8a2, 0x00e88cb4}, /* U+8334 */ - {0x00e8a3, 0x00e88c96}, /* U+8316 */ - {0x00e8a4, 0x00e88cb2}, /* U+8332 */ - {0x00e8a5, 0x00e88cb1}, /* U+8331 */ - {0x00e8a6, 0x00e88d80}, /* U+8340 */ - {0x00e8a7, 0x00e88cb9}, /* U+8339 */ - {0x00e8a8, 0x00e88d90}, /* U+8350 */ - {0x00e8a9, 0x00e88d85}, /* U+8345 */ - {0x00e8aa, 0x00e88caf}, /* U+832F */ - {0x00e8ab, 0x00e88cab}, /* U+832B */ - {0x00e8ac, 0x00e88c97}, /* U+8317 */ - {0x00e8ad, 0x00e88c98}, /* U+8318 */ - {0x00e8ae, 0x00e88e85}, /* U+8385 */ - {0x00e8af, 0x00e88e9a}, /* U+839A */ - {0x00e8b0, 0x00e88eaa}, /* U+83AA */ - {0x00e8b1, 0x00e88e9f}, /* U+839F */ - {0x00e8b2, 0x00e88ea2}, /* U+83A2 */ - {0x00e8b3, 0x00e88e96}, /* U+8396 */ - {0x00e8b4, 0x00e88ca3}, /* U+8323 */ - {0x00e8b5, 0x00e88e8e}, /* U+838E */ - {0x00e8b6, 0x00e88e87}, /* U+8387 */ - {0x00e8b7, 0x00e88e8a}, /* U+838A */ - {0x00e8b8, 0x00e88dbc}, /* U+837C */ - {0x00e8b9, 0x00e88eb5}, /* U+83B5 */ - {0x00e8ba, 0x00e88db3}, /* U+8373 */ - {0x00e8bb, 0x00e88db5}, /* U+8375 */ - {0x00e8bc, 0x00e88ea0}, /* U+83A0 */ - {0x00e8bd, 0x00e88e89}, /* U+8389 */ - {0x00e8be, 0x00e88ea8}, /* U+83A8 */ - {0x00e8bf, 0x00e88fb4}, /* U+83F4 */ - {0x00e8c0, 0x00e89093}, /* U+8413 */ - {0x00e8c1, 0x00e88fab}, /* U+83EB */ - {0x00e8c2, 0x00e88f8e}, /* U+83CE */ - {0x00e8c3, 0x00e88fbd}, /* U+83FD */ - {0x00e8c4, 0x00e89083}, /* U+8403 */ - {0x00e8c5, 0x00e88f98}, /* U+83D8 */ - {0x00e8c6, 0x00e8908b}, /* U+840B */ - {0x00e8c7, 0x00e88f81}, /* U+83C1 */ - {0x00e8c8, 0x00e88fb7}, /* U+83F7 */ - {0x00e8c9, 0x00e89087}, /* U+8407 */ - {0x00e8ca, 0x00e88fa0}, /* U+83E0 */ - {0x00e8cb, 0x00e88fb2}, /* U+83F2 */ - {0x00e8cc, 0x00e8908d}, /* U+840D */ - {0x00e8cd, 0x00e890a2}, /* U+8422 */ - {0x00e8ce, 0x00e890a0}, /* U+8420 */ - {0x00e8cf, 0x00e88ebd}, /* U+83BD */ - {0x00e8d0, 0x00e890b8}, /* U+8438 */ - {0x00e8d1, 0x00e89486}, /* U+8506 */ - {0x00e8d2, 0x00e88fbb}, /* U+83FB */ - {0x00e8d3, 0x00e891ad}, /* U+846D */ - {0x00e8d4, 0x00e890aa}, /* U+842A */ - {0x00e8d5, 0x00e890bc}, /* U+843C */ - {0x00e8d6, 0x00e8959a}, /* U+855A */ - {0x00e8d7, 0x00e89284}, /* U+8484 */ - {0x00e8d8, 0x00e891b7}, /* U+8477 */ - {0x00e8d9, 0x00e891ab}, /* U+846B */ - {0x00e8da, 0x00e892ad}, /* U+84AD */ - {0x00e8db, 0x00e891ae}, /* U+846E */ - {0x00e8dc, 0x00e89282}, /* U+8482 */ - {0x00e8dd, 0x00e891a9}, /* U+8469 */ - {0x00e8de, 0x00e89186}, /* U+8446 */ - {0x00e8df, 0x00e890ac}, /* U+842C */ - {0x00e8e0, 0x00e891af}, /* U+846F */ - {0x00e8e1, 0x00e891b9}, /* U+8479 */ - {0x00e8e2, 0x00e890b5}, /* U+8435 */ - {0x00e8e3, 0x00e8938a}, /* U+84CA */ - {0x00e8e4, 0x00e891a2}, /* U+8462 */ - {0x00e8e5, 0x00e892b9}, /* U+84B9 */ - {0x00e8e6, 0x00e892bf}, /* U+84BF */ - {0x00e8e7, 0x00e8929f}, /* U+849F */ - {0x00e8e8, 0x00e89399}, /* U+84D9 */ - {0x00e8e9, 0x00e8938d}, /* U+84CD */ - {0x00e8ea, 0x00e892bb}, /* U+84BB */ - {0x00e8eb, 0x00e8939a}, /* U+84DA */ - {0x00e8ec, 0x00e89390}, /* U+84D0 */ - {0x00e8ed, 0x00e89381}, /* U+84C1 */ - {0x00e8ee, 0x00e89386}, /* U+84C6 */ - {0x00e8ef, 0x00e89396}, /* U+84D6 */ - {0x00e8f0, 0x00e892a1}, /* U+84A1 */ - {0x00e8f1, 0x00e894a1}, /* U+8521 */ - {0x00e8f2, 0x00e893bf}, /* U+84FF */ - {0x00e8f3, 0x00e893b4}, /* U+84F4 */ - {0x00e8f4, 0x00e89497}, /* U+8517 */ - {0x00e8f5, 0x00e89498}, /* U+8518 */ - {0x00e8f6, 0x00e894ac}, /* U+852C */ - {0x00e8f7, 0x00e8949f}, /* U+851F */ - {0x00e8f8, 0x00e89495}, /* U+8515 */ - {0x00e8f9, 0x00e89494}, /* U+8514 */ - {0x00e8fa, 0x00e893bc}, /* U+84FC */ - {0x00e8fb, 0x00e89580}, /* U+8540 */ - {0x00e8fc, 0x00e895a3}, /* U+8563 */ - {0x00e8fd, 0x00e89598}, /* U+8558 */ - {0x00e8fe, 0x00e89588}, /* U+8548 */ - {0x00e9a1, 0x00e89581}, /* U+8541 */ - {0x00e9a2, 0x00e89882}, /* U+8602 */ - {0x00e9a3, 0x00e8958b}, /* U+854B */ - {0x00e9a4, 0x00e89595}, /* U+8555 */ - {0x00e9a5, 0x00e89680}, /* U+8580 */ - {0x00e9a6, 0x00e896a4}, /* U+85A4 */ - {0x00e9a7, 0x00e89688}, /* U+8588 */ - {0x00e9a8, 0x00e89691}, /* U+8591 */ - {0x00e9a9, 0x00e8968a}, /* U+858A */ - {0x00e9aa, 0x00e896a8}, /* U+85A8 */ - {0x00e9ab, 0x00e895ad}, /* U+856D */ - {0x00e9ac, 0x00e89694}, /* U+8594 */ - {0x00e9ad, 0x00e8969b}, /* U+859B */ - {0x00e9ae, 0x00e897aa}, /* U+85EA */ - {0x00e9af, 0x00e89687}, /* U+8587 */ - {0x00e9b0, 0x00e8969c}, /* U+859C */ - {0x00e9b1, 0x00e895b7}, /* U+8577 */ - {0x00e9b2, 0x00e895be}, /* U+857E */ - {0x00e9b3, 0x00e89690}, /* U+8590 */ - {0x00e9b4, 0x00e89789}, /* U+85C9 */ - {0x00e9b5, 0x00e896ba}, /* U+85BA */ - {0x00e9b6, 0x00e8978f}, /* U+85CF */ - {0x00e9b7, 0x00e896b9}, /* U+85B9 */ - {0x00e9b8, 0x00e89790}, /* U+85D0 */ - {0x00e9b9, 0x00e89795}, /* U+85D5 */ - {0x00e9ba, 0x00e8979d}, /* U+85DD */ - {0x00e9bb, 0x00e897a5}, /* U+85E5 */ - {0x00e9bc, 0x00e8979c}, /* U+85DC */ - {0x00e9bd, 0x00e897b9}, /* U+85F9 */ - {0x00e9be, 0x00e8988a}, /* U+860A */ - {0x00e9bf, 0x00e89893}, /* U+8613 */ - {0x00e9c0, 0x00e8988b}, /* U+860B */ - {0x00e9c1, 0x00e897be}, /* U+85FE */ - {0x00e9c2, 0x00e897ba}, /* U+85FA */ - {0x00e9c3, 0x00e89886}, /* U+8606 */ - {0x00e9c4, 0x00e898a2}, /* U+8622 */ - {0x00e9c5, 0x00e8989a}, /* U+861A */ - {0x00e9c6, 0x00e898b0}, /* U+8630 */ - {0x00e9c7, 0x00e898bf}, /* U+863F */ - {0x00e9c8, 0x00e8998d}, /* U+864D */ - {0x00e9c9, 0x00e4b995}, /* U+4E55 */ - {0x00e9ca, 0x00e89994}, /* U+8654 */ - {0x00e9cb, 0x00e8999f}, /* U+865F */ - {0x00e9cc, 0x00e899a7}, /* U+8667 */ - {0x00e9cd, 0x00e899b1}, /* U+8671 */ - {0x00e9ce, 0x00e89a93}, /* U+8693 */ - {0x00e9cf, 0x00e89aa3}, /* U+86A3 */ - {0x00e9d0, 0x00e89aa9}, /* U+86A9 */ - {0x00e9d1, 0x00e89aaa}, /* U+86AA */ - {0x00e9d2, 0x00e89a8b}, /* U+868B */ - {0x00e9d3, 0x00e89a8c}, /* U+868C */ - {0x00e9d4, 0x00e89ab6}, /* U+86B6 */ - {0x00e9d5, 0x00e89aaf}, /* U+86AF */ - {0x00e9d6, 0x00e89b84}, /* U+86C4 */ - {0x00e9d7, 0x00e89b86}, /* U+86C6 */ - {0x00e9d8, 0x00e89ab0}, /* U+86B0 */ - {0x00e9d9, 0x00e89b89}, /* U+86C9 */ - {0x00e9da, 0x00e8a0a3}, /* U+8823 */ - {0x00e9db, 0x00e89aab}, /* U+86AB */ - {0x00e9dc, 0x00e89b94}, /* U+86D4 */ - {0x00e9dd, 0x00e89b9e}, /* U+86DE */ - {0x00e9de, 0x00e89ba9}, /* U+86E9 */ - {0x00e9df, 0x00e89bac}, /* U+86EC */ - {0x00e9e0, 0x00e89b9f}, /* U+86DF */ - {0x00e9e1, 0x00e89b9b}, /* U+86DB */ - {0x00e9e2, 0x00e89baf}, /* U+86EF */ - {0x00e9e3, 0x00e89c92}, /* U+8712 */ - {0x00e9e4, 0x00e89c86}, /* U+8706 */ - {0x00e9e5, 0x00e89c88}, /* U+8708 */ - {0x00e9e6, 0x00e89c80}, /* U+8700 */ - {0x00e9e7, 0x00e89c83}, /* U+8703 */ - {0x00e9e8, 0x00e89bbb}, /* U+86FB */ - {0x00e9e9, 0x00e89c91}, /* U+8711 */ - {0x00e9ea, 0x00e89c89}, /* U+8709 */ - {0x00e9eb, 0x00e89c8d}, /* U+870D */ - {0x00e9ec, 0x00e89bb9}, /* U+86F9 */ - {0x00e9ed, 0x00e89c8a}, /* U+870A */ - {0x00e9ee, 0x00e89cb4}, /* U+8734 */ - {0x00e9ef, 0x00e89cbf}, /* U+873F */ - {0x00e9f0, 0x00e89cb7}, /* U+8737 */ - {0x00e9f1, 0x00e89cbb}, /* U+873B */ - {0x00e9f2, 0x00e89ca5}, /* U+8725 */ - {0x00e9f3, 0x00e89ca9}, /* U+8729 */ - {0x00e9f4, 0x00e89c9a}, /* U+871A */ - {0x00e9f5, 0x00e89da0}, /* U+8760 */ - {0x00e9f6, 0x00e89d9f}, /* U+875F */ - {0x00e9f7, 0x00e89db8}, /* U+8778 */ - {0x00e9f8, 0x00e89d8c}, /* U+874C */ - {0x00e9f9, 0x00e89d8e}, /* U+874E */ - {0x00e9fa, 0x00e89db4}, /* U+8774 */ - {0x00e9fb, 0x00e89d97}, /* U+8757 */ - {0x00e9fc, 0x00e89da8}, /* U+8768 */ - {0x00e9fd, 0x00e89dae}, /* U+876E */ - {0x00e9fe, 0x00e89d99}, /* U+8759 */ - {0x00eaa1, 0x00e89d93}, /* U+8753 */ - {0x00eaa2, 0x00e89da3}, /* U+8763 */ - {0x00eaa3, 0x00e89daa}, /* U+876A */ - {0x00eaa4, 0x00e8a085}, /* U+8805 */ - {0x00eaa5, 0x00e89ea2}, /* U+87A2 */ - {0x00eaa6, 0x00e89e9f}, /* U+879F */ - {0x00eaa7, 0x00e89e82}, /* U+8782 */ - {0x00eaa8, 0x00e89eaf}, /* U+87AF */ - {0x00eaa9, 0x00e89f8b}, /* U+87CB */ - {0x00eaaa, 0x00e89ebd}, /* U+87BD */ - {0x00eaab, 0x00e89f80}, /* U+87C0 */ - {0x00eaac, 0x00e89f90}, /* U+87D0 */ - {0x00eaad, 0x00e99b96}, /* U+96D6 */ - {0x00eaae, 0x00e89eab}, /* U+87AB */ - {0x00eaaf, 0x00e89f84}, /* U+87C4 */ - {0x00eab0, 0x00e89eb3}, /* U+87B3 */ - {0x00eab1, 0x00e89f87}, /* U+87C7 */ - {0x00eab2, 0x00e89f86}, /* U+87C6 */ - {0x00eab3, 0x00e89ebb}, /* U+87BB */ - {0x00eab4, 0x00e89faf}, /* U+87EF */ - {0x00eab5, 0x00e89fb2}, /* U+87F2 */ - {0x00eab6, 0x00e89fa0}, /* U+87E0 */ - {0x00eab7, 0x00e8a08f}, /* U+880F */ - {0x00eab8, 0x00e8a08d}, /* U+880D */ - {0x00eab9, 0x00e89fbe}, /* U+87FE */ - {0x00eaba, 0x00e89fb6}, /* U+87F6 */ - {0x00eabb, 0x00e89fb7}, /* U+87F7 */ - {0x00eabc, 0x00e8a08e}, /* U+880E */ - {0x00eabd, 0x00e89f92}, /* U+87D2 */ - {0x00eabe, 0x00e8a091}, /* U+8811 */ - {0x00eabf, 0x00e8a096}, /* U+8816 */ - {0x00eac0, 0x00e8a095}, /* U+8815 */ - {0x00eac1, 0x00e8a0a2}, /* U+8822 */ - {0x00eac2, 0x00e8a0a1}, /* U+8821 */ - {0x00eac3, 0x00e8a0b1}, /* U+8831 */ - {0x00eac4, 0x00e8a0b6}, /* U+8836 */ - {0x00eac5, 0x00e8a0b9}, /* U+8839 */ - {0x00eac6, 0x00e8a0a7}, /* U+8827 */ - {0x00eac7, 0x00e8a0bb}, /* U+883B */ - {0x00eac8, 0x00e8a184}, /* U+8844 */ - {0x00eac9, 0x00e8a182}, /* U+8842 */ - {0x00eaca, 0x00e8a192}, /* U+8852 */ - {0x00eacb, 0x00e8a199}, /* U+8859 */ - {0x00eacc, 0x00e8a19e}, /* U+885E */ - {0x00eacd, 0x00e8a1a2}, /* U+8862 */ - {0x00eace, 0x00e8a1ab}, /* U+886B */ - {0x00eacf, 0x00e8a281}, /* U+8881 */ - {0x00ead0, 0x00e8a1be}, /* U+887E */ - {0x00ead1, 0x00e8a29e}, /* U+889E */ - {0x00ead2, 0x00e8a1b5}, /* U+8875 */ - {0x00ead3, 0x00e8a1bd}, /* U+887D */ - {0x00ead4, 0x00e8a2b5}, /* U+88B5 */ - {0x00ead5, 0x00e8a1b2}, /* U+8872 */ - {0x00ead6, 0x00e8a282}, /* U+8882 */ - {0x00ead7, 0x00e8a297}, /* U+8897 */ - {0x00ead8, 0x00e8a292}, /* U+8892 */ - {0x00ead9, 0x00e8a2ae}, /* U+88AE */ - {0x00eada, 0x00e8a299}, /* U+8899 */ - {0x00eadb, 0x00e8a2a2}, /* U+88A2 */ - {0x00eadc, 0x00e8a28d}, /* U+888D */ - {0x00eadd, 0x00e8a2a4}, /* U+88A4 */ - {0x00eade, 0x00e8a2b0}, /* U+88B0 */ - {0x00eadf, 0x00e8a2bf}, /* U+88BF */ - {0x00eae0, 0x00e8a2b1}, /* U+88B1 */ - {0x00eae1, 0x00e8a383}, /* U+88C3 */ - {0x00eae2, 0x00e8a384}, /* U+88C4 */ - {0x00eae3, 0x00e8a394}, /* U+88D4 */ - {0x00eae4, 0x00e8a398}, /* U+88D8 */ - {0x00eae5, 0x00e8a399}, /* U+88D9 */ - {0x00eae6, 0x00e8a39d}, /* U+88DD */ - {0x00eae7, 0x00e8a3b9}, /* U+88F9 */ - {0x00eae8, 0x00e8a482}, /* U+8902 */ - {0x00eae9, 0x00e8a3bc}, /* U+88FC */ - {0x00eaea, 0x00e8a3b4}, /* U+88F4 */ - {0x00eaeb, 0x00e8a3a8}, /* U+88E8 */ - {0x00eaec, 0x00e8a3b2}, /* U+88F2 */ - {0x00eaed, 0x00e8a484}, /* U+8904 */ - {0x00eaee, 0x00e8a48c}, /* U+890C */ - {0x00eaef, 0x00e8a48a}, /* U+890A */ - {0x00eaf0, 0x00e8a493}, /* U+8913 */ - {0x00eaf1, 0x00e8a583}, /* U+8943 */ - {0x00eaf2, 0x00e8a49e}, /* U+891E */ - {0x00eaf3, 0x00e8a4a5}, /* U+8925 */ - {0x00eaf4, 0x00e8a4aa}, /* U+892A */ - {0x00eaf5, 0x00e8a4ab}, /* U+892B */ - {0x00eaf6, 0x00e8a581}, /* U+8941 */ - {0x00eaf7, 0x00e8a584}, /* U+8944 */ - {0x00eaf8, 0x00e8a4bb}, /* U+893B */ - {0x00eaf9, 0x00e8a4b6}, /* U+8936 */ - {0x00eafa, 0x00e8a4b8}, /* U+8938 */ - {0x00eafb, 0x00e8a58c}, /* U+894C */ - {0x00eafc, 0x00e8a49d}, /* U+891D */ - {0x00eafd, 0x00e8a5a0}, /* U+8960 */ - {0x00eafe, 0x00e8a59e}, /* U+895E */ - {0x00eba1, 0x00e8a5a6}, /* U+8966 */ - {0x00eba2, 0x00e8a5a4}, /* U+8964 */ - {0x00eba3, 0x00e8a5ad}, /* U+896D */ - {0x00eba4, 0x00e8a5aa}, /* U+896A */ - {0x00eba5, 0x00e8a5af}, /* U+896F */ - {0x00eba6, 0x00e8a5b4}, /* U+8974 */ - {0x00eba7, 0x00e8a5b7}, /* U+8977 */ - {0x00eba8, 0x00e8a5be}, /* U+897E */ - {0x00eba9, 0x00e8a683}, /* U+8983 */ - {0x00ebaa, 0x00e8a688}, /* U+8988 */ - {0x00ebab, 0x00e8a68a}, /* U+898A */ - {0x00ebac, 0x00e8a693}, /* U+8993 */ - {0x00ebad, 0x00e8a698}, /* U+8998 */ - {0x00ebae, 0x00e8a6a1}, /* U+89A1 */ - {0x00ebaf, 0x00e8a6a9}, /* U+89A9 */ - {0x00ebb0, 0x00e8a6a6}, /* U+89A6 */ - {0x00ebb1, 0x00e8a6ac}, /* U+89AC */ - {0x00ebb2, 0x00e8a6af}, /* U+89AF */ - {0x00ebb3, 0x00e8a6b2}, /* U+89B2 */ - {0x00ebb4, 0x00e8a6ba}, /* U+89BA */ - {0x00ebb5, 0x00e8a6bd}, /* U+89BD */ - {0x00ebb6, 0x00e8a6bf}, /* U+89BF */ - {0x00ebb7, 0x00e8a780}, /* U+89C0 */ - {0x00ebb8, 0x00e8a79a}, /* U+89DA */ - {0x00ebb9, 0x00e8a79c}, /* U+89DC */ - {0x00ebba, 0x00e8a79d}, /* U+89DD */ - {0x00ebbb, 0x00e8a7a7}, /* U+89E7 */ - {0x00ebbc, 0x00e8a7b4}, /* U+89F4 */ - {0x00ebbd, 0x00e8a7b8}, /* U+89F8 */ - {0x00ebbe, 0x00e8a883}, /* U+8A03 */ - {0x00ebbf, 0x00e8a896}, /* U+8A16 */ - {0x00ebc0, 0x00e8a890}, /* U+8A10 */ - {0x00ebc1, 0x00e8a88c}, /* U+8A0C */ - {0x00ebc2, 0x00e8a89b}, /* U+8A1B */ - {0x00ebc3, 0x00e8a89d}, /* U+8A1D */ - {0x00ebc4, 0x00e8a8a5}, /* U+8A25 */ - {0x00ebc5, 0x00e8a8b6}, /* U+8A36 */ - {0x00ebc6, 0x00e8a981}, /* U+8A41 */ - {0x00ebc7, 0x00e8a99b}, /* U+8A5B */ - {0x00ebc8, 0x00e8a992}, /* U+8A52 */ - {0x00ebc9, 0x00e8a986}, /* U+8A46 */ - {0x00ebca, 0x00e8a988}, /* U+8A48 */ - {0x00ebcb, 0x00e8a9bc}, /* U+8A7C */ - {0x00ebcc, 0x00e8a9ad}, /* U+8A6D */ - {0x00ebcd, 0x00e8a9ac}, /* U+8A6C */ - {0x00ebce, 0x00e8a9a2}, /* U+8A62 */ - {0x00ebcf, 0x00e8aa85}, /* U+8A85 */ - {0x00ebd0, 0x00e8aa82}, /* U+8A82 */ - {0x00ebd1, 0x00e8aa84}, /* U+8A84 */ - {0x00ebd2, 0x00e8aaa8}, /* U+8AA8 */ - {0x00ebd3, 0x00e8aaa1}, /* U+8AA1 */ - {0x00ebd4, 0x00e8aa91}, /* U+8A91 */ - {0x00ebd5, 0x00e8aaa5}, /* U+8AA5 */ - {0x00ebd6, 0x00e8aaa6}, /* U+8AA6 */ - {0x00ebd7, 0x00e8aa9a}, /* U+8A9A */ - {0x00ebd8, 0x00e8aaa3}, /* U+8AA3 */ - {0x00ebd9, 0x00e8ab84}, /* U+8AC4 */ - {0x00ebda, 0x00e8ab8d}, /* U+8ACD */ - {0x00ebdb, 0x00e8ab82}, /* U+8AC2 */ - {0x00ebdc, 0x00e8ab9a}, /* U+8ADA */ - {0x00ebdd, 0x00e8abab}, /* U+8AEB */ - {0x00ebde, 0x00e8abb3}, /* U+8AF3 */ - {0x00ebdf, 0x00e8aba7}, /* U+8AE7 */ - {0x00ebe0, 0x00e8aba4}, /* U+8AE4 */ - {0x00ebe1, 0x00e8abb1}, /* U+8AF1 */ - {0x00ebe2, 0x00e8ac94}, /* U+8B14 */ - {0x00ebe3, 0x00e8aba0}, /* U+8AE0 */ - {0x00ebe4, 0x00e8aba2}, /* U+8AE2 */ - {0x00ebe5, 0x00e8abb7}, /* U+8AF7 */ - {0x00ebe6, 0x00e8ab9e}, /* U+8ADE */ - {0x00ebe7, 0x00e8ab9b}, /* U+8ADB */ - {0x00ebe8, 0x00e8ac8c}, /* U+8B0C */ - {0x00ebe9, 0x00e8ac87}, /* U+8B07 */ - {0x00ebea, 0x00e8ac9a}, /* U+8B1A */ - {0x00ebeb, 0x00e8aba1}, /* U+8AE1 */ - {0x00ebec, 0x00e8ac96}, /* U+8B16 */ - {0x00ebed, 0x00e8ac90}, /* U+8B10 */ - {0x00ebee, 0x00e8ac97}, /* U+8B17 */ - {0x00ebef, 0x00e8aca0}, /* U+8B20 */ - {0x00ebf0, 0x00e8acb3}, /* U+8B33 */ - {0x00ebf1, 0x00e99eab}, /* U+97AB */ - {0x00ebf2, 0x00e8aca6}, /* U+8B26 */ - {0x00ebf3, 0x00e8acab}, /* U+8B2B */ - {0x00ebf4, 0x00e8acbe}, /* U+8B3E */ - {0x00ebf5, 0x00e8aca8}, /* U+8B28 */ - {0x00ebf6, 0x00e8ad81}, /* U+8B41 */ - {0x00ebf7, 0x00e8ad8c}, /* U+8B4C */ - {0x00ebf8, 0x00e8ad8f}, /* U+8B4F */ - {0x00ebf9, 0x00e8ad8e}, /* U+8B4E */ - {0x00ebfa, 0x00e8ad89}, /* U+8B49 */ - {0x00ebfb, 0x00e8ad96}, /* U+8B56 */ - {0x00ebfc, 0x00e8ad9b}, /* U+8B5B */ - {0x00ebfd, 0x00e8ad9a}, /* U+8B5A */ - {0x00ebfe, 0x00e8adab}, /* U+8B6B */ - {0x00eca1, 0x00e8ad9f}, /* U+8B5F */ - {0x00eca2, 0x00e8adac}, /* U+8B6C */ - {0x00eca3, 0x00e8adaf}, /* U+8B6F */ - {0x00eca4, 0x00e8adb4}, /* U+8B74 */ - {0x00eca5, 0x00e8adbd}, /* U+8B7D */ - {0x00eca6, 0x00e8ae80}, /* U+8B80 */ - {0x00eca7, 0x00e8ae8c}, /* U+8B8C */ - {0x00eca8, 0x00e8ae8e}, /* U+8B8E */ - {0x00eca9, 0x00e8ae92}, /* U+8B92 */ - {0x00ecaa, 0x00e8ae93}, /* U+8B93 */ - {0x00ecab, 0x00e8ae96}, /* U+8B96 */ - {0x00ecac, 0x00e8ae99}, /* U+8B99 */ - {0x00ecad, 0x00e8ae9a}, /* U+8B9A */ - {0x00ecae, 0x00e8b0ba}, /* U+8C3A */ - {0x00ecaf, 0x00e8b181}, /* U+8C41 */ - {0x00ecb0, 0x00e8b0bf}, /* U+8C3F */ - {0x00ecb1, 0x00e8b188}, /* U+8C48 */ - {0x00ecb2, 0x00e8b18c}, /* U+8C4C */ - {0x00ecb3, 0x00e8b18e}, /* U+8C4E */ - {0x00ecb4, 0x00e8b190}, /* U+8C50 */ - {0x00ecb5, 0x00e8b195}, /* U+8C55 */ - {0x00ecb6, 0x00e8b1a2}, /* U+8C62 */ - {0x00ecb7, 0x00e8b1ac}, /* U+8C6C */ - {0x00ecb8, 0x00e8b1b8}, /* U+8C78 */ - {0x00ecb9, 0x00e8b1ba}, /* U+8C7A */ - {0x00ecba, 0x00e8b282}, /* U+8C82 */ - {0x00ecbb, 0x00e8b289}, /* U+8C89 */ - {0x00ecbc, 0x00e8b285}, /* U+8C85 */ - {0x00ecbd, 0x00e8b28a}, /* U+8C8A */ - {0x00ecbe, 0x00e8b28d}, /* U+8C8D */ - {0x00ecbf, 0x00e8b28e}, /* U+8C8E */ - {0x00ecc0, 0x00e8b294}, /* U+8C94 */ - {0x00ecc1, 0x00e8b1bc}, /* U+8C7C */ - {0x00ecc2, 0x00e8b298}, /* U+8C98 */ - {0x00ecc3, 0x00e6889d}, /* U+621D */ - {0x00ecc4, 0x00e8b2ad}, /* U+8CAD */ - {0x00ecc5, 0x00e8b2aa}, /* U+8CAA */ - {0x00ecc6, 0x00e8b2bd}, /* U+8CBD */ - {0x00ecc7, 0x00e8b2b2}, /* U+8CB2 */ - {0x00ecc8, 0x00e8b2b3}, /* U+8CB3 */ - {0x00ecc9, 0x00e8b2ae}, /* U+8CAE */ - {0x00ecca, 0x00e8b2b6}, /* U+8CB6 */ - {0x00eccb, 0x00e8b388}, /* U+8CC8 */ - {0x00eccc, 0x00e8b381}, /* U+8CC1 */ - {0x00eccd, 0x00e8b3a4}, /* U+8CE4 */ - {0x00ecce, 0x00e8b3a3}, /* U+8CE3 */ - {0x00eccf, 0x00e8b39a}, /* U+8CDA */ - {0x00ecd0, 0x00e8b3bd}, /* U+8CFD */ - {0x00ecd1, 0x00e8b3ba}, /* U+8CFA */ - {0x00ecd2, 0x00e8b3bb}, /* U+8CFB */ - {0x00ecd3, 0x00e8b484}, /* U+8D04 */ - {0x00ecd4, 0x00e8b485}, /* U+8D05 */ - {0x00ecd5, 0x00e8b48a}, /* U+8D0A */ - {0x00ecd6, 0x00e8b487}, /* U+8D07 */ - {0x00ecd7, 0x00e8b48f}, /* U+8D0F */ - {0x00ecd8, 0x00e8b48d}, /* U+8D0D */ - {0x00ecd9, 0x00e8b490}, /* U+8D10 */ - {0x00ecda, 0x00e9bd8e}, /* U+9F4E */ - {0x00ecdb, 0x00e8b493}, /* U+8D13 */ - {0x00ecdc, 0x00e8b38d}, /* U+8CCD */ - {0x00ecdd, 0x00e8b494}, /* U+8D14 */ - {0x00ecde, 0x00e8b496}, /* U+8D16 */ - {0x00ecdf, 0x00e8b5a7}, /* U+8D67 */ - {0x00ece0, 0x00e8b5ad}, /* U+8D6D */ - {0x00ece1, 0x00e8b5b1}, /* U+8D71 */ - {0x00ece2, 0x00e8b5b3}, /* U+8D73 */ - {0x00ece3, 0x00e8b681}, /* U+8D81 */ - {0x00ece4, 0x00e8b699}, /* U+8D99 */ - {0x00ece5, 0x00e8b782}, /* U+8DC2 */ - {0x00ece6, 0x00e8b6be}, /* U+8DBE */ - {0x00ece7, 0x00e8b6ba}, /* U+8DBA */ - {0x00ece8, 0x00e8b78f}, /* U+8DCF */ - {0x00ece9, 0x00e8b79a}, /* U+8DDA */ - {0x00ecea, 0x00e8b796}, /* U+8DD6 */ - {0x00eceb, 0x00e8b78c}, /* U+8DCC */ - {0x00ecec, 0x00e8b79b}, /* U+8DDB */ - {0x00eced, 0x00e8b78b}, /* U+8DCB */ - {0x00ecee, 0x00e8b7aa}, /* U+8DEA */ - {0x00ecef, 0x00e8b7ab}, /* U+8DEB */ - {0x00ecf0, 0x00e8b79f}, /* U+8DDF */ - {0x00ecf1, 0x00e8b7a3}, /* U+8DE3 */ - {0x00ecf2, 0x00e8b7bc}, /* U+8DFC */ - {0x00ecf3, 0x00e8b888}, /* U+8E08 */ - {0x00ecf4, 0x00e8b889}, /* U+8E09 */ - {0x00ecf5, 0x00e8b7bf}, /* U+8DFF */ - {0x00ecf6, 0x00e8b89d}, /* U+8E1D */ - {0x00ecf7, 0x00e8b89e}, /* U+8E1E */ - {0x00ecf8, 0x00e8b890}, /* U+8E10 */ - {0x00ecf9, 0x00e8b89f}, /* U+8E1F */ - {0x00ecfa, 0x00e8b982}, /* U+8E42 */ - {0x00ecfb, 0x00e8b8b5}, /* U+8E35 */ - {0x00ecfc, 0x00e8b8b0}, /* U+8E30 */ - {0x00ecfd, 0x00e8b8b4}, /* U+8E34 */ - {0x00ecfe, 0x00e8b98a}, /* U+8E4A */ - {0x00eda1, 0x00e8b987}, /* U+8E47 */ - {0x00eda2, 0x00e8b989}, /* U+8E49 */ - {0x00eda3, 0x00e8b98c}, /* U+8E4C */ - {0x00eda4, 0x00e8b990}, /* U+8E50 */ - {0x00eda5, 0x00e8b988}, /* U+8E48 */ - {0x00eda6, 0x00e8b999}, /* U+8E59 */ - {0x00eda7, 0x00e8b9a4}, /* U+8E64 */ - {0x00eda8, 0x00e8b9a0}, /* U+8E60 */ - {0x00eda9, 0x00e8b8aa}, /* U+8E2A */ - {0x00edaa, 0x00e8b9a3}, /* U+8E63 */ - {0x00edab, 0x00e8b995}, /* U+8E55 */ - {0x00edac, 0x00e8b9b6}, /* U+8E76 */ - {0x00edad, 0x00e8b9b2}, /* U+8E72 */ - {0x00edae, 0x00e8b9bc}, /* U+8E7C */ - {0x00edaf, 0x00e8ba81}, /* U+8E81 */ - {0x00edb0, 0x00e8ba87}, /* U+8E87 */ - {0x00edb1, 0x00e8ba85}, /* U+8E85 */ - {0x00edb2, 0x00e8ba84}, /* U+8E84 */ - {0x00edb3, 0x00e8ba8b}, /* U+8E8B */ - {0x00edb4, 0x00e8ba8a}, /* U+8E8A */ - {0x00edb5, 0x00e8ba93}, /* U+8E93 */ - {0x00edb6, 0x00e8ba91}, /* U+8E91 */ - {0x00edb7, 0x00e8ba94}, /* U+8E94 */ - {0x00edb8, 0x00e8ba99}, /* U+8E99 */ - {0x00edb9, 0x00e8baaa}, /* U+8EAA */ - {0x00edba, 0x00e8baa1}, /* U+8EA1 */ - {0x00edbb, 0x00e8baac}, /* U+8EAC */ - {0x00edbc, 0x00e8bab0}, /* U+8EB0 */ - {0x00edbd, 0x00e8bb86}, /* U+8EC6 */ - {0x00edbe, 0x00e8bab1}, /* U+8EB1 */ - {0x00edbf, 0x00e8babe}, /* U+8EBE */ - {0x00edc0, 0x00e8bb85}, /* U+8EC5 */ - {0x00edc1, 0x00e8bb88}, /* U+8EC8 */ - {0x00edc2, 0x00e8bb8b}, /* U+8ECB */ - {0x00edc3, 0x00e8bb9b}, /* U+8EDB */ - {0x00edc4, 0x00e8bba3}, /* U+8EE3 */ - {0x00edc5, 0x00e8bbbc}, /* U+8EFC */ - {0x00edc6, 0x00e8bbbb}, /* U+8EFB */ - {0x00edc7, 0x00e8bbab}, /* U+8EEB */ - {0x00edc8, 0x00e8bbbe}, /* U+8EFE */ - {0x00edc9, 0x00e8bc8a}, /* U+8F0A */ - {0x00edca, 0x00e8bc85}, /* U+8F05 */ - {0x00edcb, 0x00e8bc95}, /* U+8F15 */ - {0x00edcc, 0x00e8bc92}, /* U+8F12 */ - {0x00edcd, 0x00e8bc99}, /* U+8F19 */ - {0x00edce, 0x00e8bc93}, /* U+8F13 */ - {0x00edcf, 0x00e8bc9c}, /* U+8F1C */ - {0x00edd0, 0x00e8bc9f}, /* U+8F1F */ - {0x00edd1, 0x00e8bc9b}, /* U+8F1B */ - {0x00edd2, 0x00e8bc8c}, /* U+8F0C */ - {0x00edd3, 0x00e8bca6}, /* U+8F26 */ - {0x00edd4, 0x00e8bcb3}, /* U+8F33 */ - {0x00edd5, 0x00e8bcbb}, /* U+8F3B */ - {0x00edd6, 0x00e8bcb9}, /* U+8F39 */ - {0x00edd7, 0x00e8bd85}, /* U+8F45 */ - {0x00edd8, 0x00e8bd82}, /* U+8F42 */ - {0x00edd9, 0x00e8bcbe}, /* U+8F3E */ - {0x00edda, 0x00e8bd8c}, /* U+8F4C */ - {0x00eddb, 0x00e8bd89}, /* U+8F49 */ - {0x00eddc, 0x00e8bd86}, /* U+8F46 */ - {0x00eddd, 0x00e8bd8e}, /* U+8F4E */ - {0x00edde, 0x00e8bd97}, /* U+8F57 */ - {0x00eddf, 0x00e8bd9c}, /* U+8F5C */ - {0x00ede0, 0x00e8bda2}, /* U+8F62 */ - {0x00ede1, 0x00e8bda3}, /* U+8F63 */ - {0x00ede2, 0x00e8bda4}, /* U+8F64 */ - {0x00ede3, 0x00e8be9c}, /* U+8F9C */ - {0x00ede4, 0x00e8be9f}, /* U+8F9F */ - {0x00ede5, 0x00e8bea3}, /* U+8FA3 */ - {0x00ede6, 0x00e8bead}, /* U+8FAD */ - {0x00ede7, 0x00e8beaf}, /* U+8FAF */ - {0x00ede8, 0x00e8beb7}, /* U+8FB7 */ - {0x00ede9, 0x00e8bf9a}, /* U+8FDA */ - {0x00edea, 0x00e8bfa5}, /* U+8FE5 */ - {0x00edeb, 0x00e8bfa2}, /* U+8FE2 */ - {0x00edec, 0x00e8bfaa}, /* U+8FEA */ - {0x00eded, 0x00e8bfaf}, /* U+8FEF */ - {0x00edee, 0x00e98287}, /* U+9087 */ - {0x00edef, 0x00e8bfb4}, /* U+8FF4 */ - {0x00edf0, 0x00e98085}, /* U+9005 */ - {0x00edf1, 0x00e8bfb9}, /* U+8FF9 */ - {0x00edf2, 0x00e8bfba}, /* U+8FFA */ - {0x00edf3, 0x00e98091}, /* U+9011 */ - {0x00edf4, 0x00e98095}, /* U+9015 */ - {0x00edf5, 0x00e980a1}, /* U+9021 */ - {0x00edf6, 0x00e9808d}, /* U+900D */ - {0x00edf7, 0x00e9809e}, /* U+901E */ - {0x00edf8, 0x00e98096}, /* U+9016 */ - {0x00edf9, 0x00e9808b}, /* U+900B */ - {0x00edfa, 0x00e980a7}, /* U+9027 */ - {0x00edfb, 0x00e980b6}, /* U+9036 */ - {0x00edfc, 0x00e980b5}, /* U+9035 */ - {0x00edfd, 0x00e980b9}, /* U+9039 */ - {0x00edfe, 0x00e8bfb8}, /* U+8FF8 */ - {0x00eea1, 0x00e9818f}, /* U+904F */ - {0x00eea2, 0x00e98190}, /* U+9050 */ - {0x00eea3, 0x00e98191}, /* U+9051 */ - {0x00eea4, 0x00e98192}, /* U+9052 */ - {0x00eea5, 0x00e9808e}, /* U+900E */ - {0x00eea6, 0x00e98189}, /* U+9049 */ - {0x00eea7, 0x00e980be}, /* U+903E */ - {0x00eea8, 0x00e98196}, /* U+9056 */ - {0x00eea9, 0x00e98198}, /* U+9058 */ - {0x00eeaa, 0x00e9819e}, /* U+905E */ - {0x00eeab, 0x00e981a8}, /* U+9068 */ - {0x00eeac, 0x00e981af}, /* U+906F */ - {0x00eead, 0x00e981b6}, /* U+9076 */ - {0x00eeae, 0x00e99aa8}, /* U+96A8 */ - {0x00eeaf, 0x00e981b2}, /* U+9072 */ - {0x00eeb0, 0x00e98282}, /* U+9082 */ - {0x00eeb1, 0x00e981bd}, /* U+907D */ - {0x00eeb2, 0x00e98281}, /* U+9081 */ - {0x00eeb3, 0x00e98280}, /* U+9080 */ - {0x00eeb4, 0x00e9828a}, /* U+908A */ - {0x00eeb5, 0x00e98289}, /* U+9089 */ - {0x00eeb6, 0x00e9828f}, /* U+908F */ - {0x00eeb7, 0x00e982a8}, /* U+90A8 */ - {0x00eeb8, 0x00e982af}, /* U+90AF */ - {0x00eeb9, 0x00e982b1}, /* U+90B1 */ - {0x00eeba, 0x00e982b5}, /* U+90B5 */ - {0x00eebb, 0x00e983a2}, /* U+90E2 */ - {0x00eebc, 0x00e983a4}, /* U+90E4 */ - {0x00eebd, 0x00e68988}, /* U+6248 */ - {0x00eebe, 0x00e9839b}, /* U+90DB */ - {0x00eebf, 0x00e98482}, /* U+9102 */ - {0x00eec0, 0x00e98492}, /* U+9112 */ - {0x00eec1, 0x00e98499}, /* U+9119 */ - {0x00eec2, 0x00e984b2}, /* U+9132 */ - {0x00eec3, 0x00e984b0}, /* U+9130 */ - {0x00eec4, 0x00e9858a}, /* U+914A */ - {0x00eec5, 0x00e98596}, /* U+9156 */ - {0x00eec6, 0x00e98598}, /* U+9158 */ - {0x00eec7, 0x00e985a3}, /* U+9163 */ - {0x00eec8, 0x00e985a5}, /* U+9165 */ - {0x00eec9, 0x00e985a9}, /* U+9169 */ - {0x00eeca, 0x00e985b3}, /* U+9173 */ - {0x00eecb, 0x00e985b2}, /* U+9172 */ - {0x00eecc, 0x00e9868b}, /* U+918B */ - {0x00eecd, 0x00e98689}, /* U+9189 */ - {0x00eece, 0x00e98682}, /* U+9182 */ - {0x00eecf, 0x00e986a2}, /* U+91A2 */ - {0x00eed0, 0x00e986ab}, /* U+91AB */ - {0x00eed1, 0x00e986af}, /* U+91AF */ - {0x00eed2, 0x00e986aa}, /* U+91AA */ - {0x00eed3, 0x00e986b5}, /* U+91B5 */ - {0x00eed4, 0x00e986b4}, /* U+91B4 */ - {0x00eed5, 0x00e986ba}, /* U+91BA */ - {0x00eed6, 0x00e98780}, /* U+91C0 */ - {0x00eed7, 0x00e98781}, /* U+91C1 */ - {0x00eed8, 0x00e98789}, /* U+91C9 */ - {0x00eed9, 0x00e9878b}, /* U+91CB */ - {0x00eeda, 0x00e98790}, /* U+91D0 */ - {0x00eedb, 0x00e98796}, /* U+91D6 */ - {0x00eedc, 0x00e9879f}, /* U+91DF */ - {0x00eedd, 0x00e987a1}, /* U+91E1 */ - {0x00eede, 0x00e9879b}, /* U+91DB */ - {0x00eedf, 0x00e987bc}, /* U+91FC */ - {0x00eee0, 0x00e987b5}, /* U+91F5 */ - {0x00eee1, 0x00e987b6}, /* U+91F6 */ - {0x00eee2, 0x00e9889e}, /* U+921E */ - {0x00eee3, 0x00e987bf}, /* U+91FF */ - {0x00eee4, 0x00e98894}, /* U+9214 */ - {0x00eee5, 0x00e988ac}, /* U+922C */ - {0x00eee6, 0x00e98895}, /* U+9215 */ - {0x00eee7, 0x00e98891}, /* U+9211 */ - {0x00eee8, 0x00e9899e}, /* U+925E */ - {0x00eee9, 0x00e98997}, /* U+9257 */ - {0x00eeea, 0x00e98985}, /* U+9245 */ - {0x00eeeb, 0x00e98989}, /* U+9249 */ - {0x00eeec, 0x00e989a4}, /* U+9264 */ - {0x00eeed, 0x00e98988}, /* U+9248 */ - {0x00eeee, 0x00e98a95}, /* U+9295 */ - {0x00eeef, 0x00e988bf}, /* U+923F */ - {0x00eef0, 0x00e9898b}, /* U+924B */ - {0x00eef1, 0x00e98990}, /* U+9250 */ - {0x00eef2, 0x00e98a9c}, /* U+929C */ - {0x00eef3, 0x00e98a96}, /* U+9296 */ - {0x00eef4, 0x00e98a93}, /* U+9293 */ - {0x00eef5, 0x00e98a9b}, /* U+929B */ - {0x00eef6, 0x00e9899a}, /* U+925A */ - {0x00eef7, 0x00e98b8f}, /* U+92CF */ - {0x00eef8, 0x00e98ab9}, /* U+92B9 */ - {0x00eef9, 0x00e98ab7}, /* U+92B7 */ - {0x00eefa, 0x00e98ba9}, /* U+92E9 */ - {0x00eefb, 0x00e98c8f}, /* U+930F */ - {0x00eefc, 0x00e98bba}, /* U+92FA */ - {0x00eefd, 0x00e98d84}, /* U+9344 */ - {0x00eefe, 0x00e98cae}, /* U+932E */ - {0x00efa1, 0x00e98c99}, /* U+9319 */ - {0x00efa2, 0x00e98ca2}, /* U+9322 */ - {0x00efa3, 0x00e98c9a}, /* U+931A */ - {0x00efa4, 0x00e98ca3}, /* U+9323 */ - {0x00efa5, 0x00e98cba}, /* U+933A */ - {0x00efa6, 0x00e98cb5}, /* U+9335 */ - {0x00efa7, 0x00e98cbb}, /* U+933B */ - {0x00efa8, 0x00e98d9c}, /* U+935C */ - {0x00efa9, 0x00e98da0}, /* U+9360 */ - {0x00efaa, 0x00e98dbc}, /* U+937C */ - {0x00efab, 0x00e98dae}, /* U+936E */ - {0x00efac, 0x00e98d96}, /* U+9356 */ - {0x00efad, 0x00e98eb0}, /* U+93B0 */ - {0x00efae, 0x00e98eac}, /* U+93AC */ - {0x00efaf, 0x00e98ead}, /* U+93AD */ - {0x00efb0, 0x00e98e94}, /* U+9394 */ - {0x00efb1, 0x00e98eb9}, /* U+93B9 */ - {0x00efb2, 0x00e98f96}, /* U+93D6 */ - {0x00efb3, 0x00e98f97}, /* U+93D7 */ - {0x00efb4, 0x00e98fa8}, /* U+93E8 */ - {0x00efb5, 0x00e98fa5}, /* U+93E5 */ - {0x00efb6, 0x00e98f98}, /* U+93D8 */ - {0x00efb7, 0x00e98f83}, /* U+93C3 */ - {0x00efb8, 0x00e98f9d}, /* U+93DD */ - {0x00efb9, 0x00e98f90}, /* U+93D0 */ - {0x00efba, 0x00e98f88}, /* U+93C8 */ - {0x00efbb, 0x00e98fa4}, /* U+93E4 */ - {0x00efbc, 0x00e9909a}, /* U+941A */ - {0x00efbd, 0x00e99094}, /* U+9414 */ - {0x00efbe, 0x00e99093}, /* U+9413 */ - {0x00efbf, 0x00e99083}, /* U+9403 */ - {0x00efc0, 0x00e99087}, /* U+9407 */ - {0x00efc1, 0x00e99090}, /* U+9410 */ - {0x00efc2, 0x00e990b6}, /* U+9436 */ - {0x00efc3, 0x00e990ab}, /* U+942B */ - {0x00efc4, 0x00e990b5}, /* U+9435 */ - {0x00efc5, 0x00e990a1}, /* U+9421 */ - {0x00efc6, 0x00e990ba}, /* U+943A */ - {0x00efc7, 0x00e99181}, /* U+9441 */ - {0x00efc8, 0x00e99192}, /* U+9452 */ - {0x00efc9, 0x00e99184}, /* U+9444 */ - {0x00efca, 0x00e9919b}, /* U+945B */ - {0x00efcb, 0x00e991a0}, /* U+9460 */ - {0x00efcc, 0x00e991a2}, /* U+9462 */ - {0x00efcd, 0x00e9919e}, /* U+945E */ - {0x00efce, 0x00e991aa}, /* U+946A */ - {0x00efcf, 0x00e988a9}, /* U+9229 */ - {0x00efd0, 0x00e991b0}, /* U+9470 */ - {0x00efd1, 0x00e991b5}, /* U+9475 */ - {0x00efd2, 0x00e991b7}, /* U+9477 */ - {0x00efd3, 0x00e991bd}, /* U+947D */ - {0x00efd4, 0x00e9919a}, /* U+945A */ - {0x00efd5, 0x00e991bc}, /* U+947C */ - {0x00efd6, 0x00e991be}, /* U+947E */ - {0x00efd7, 0x00e99281}, /* U+9481 */ - {0x00efd8, 0x00e991bf}, /* U+947F */ - {0x00efd9, 0x00e99682}, /* U+9582 */ - {0x00efda, 0x00e99687}, /* U+9587 */ - {0x00efdb, 0x00e9968a}, /* U+958A */ - {0x00efdc, 0x00e99694}, /* U+9594 */ - {0x00efdd, 0x00e99696}, /* U+9596 */ - {0x00efde, 0x00e99698}, /* U+9598 */ - {0x00efdf, 0x00e99699}, /* U+9599 */ - {0x00efe0, 0x00e996a0}, /* U+95A0 */ - {0x00efe1, 0x00e996a8}, /* U+95A8 */ - {0x00efe2, 0x00e996a7}, /* U+95A7 */ - {0x00efe3, 0x00e996ad}, /* U+95AD */ - {0x00efe4, 0x00e996bc}, /* U+95BC */ - {0x00efe5, 0x00e996bb}, /* U+95BB */ - {0x00efe6, 0x00e996b9}, /* U+95B9 */ - {0x00efe7, 0x00e996be}, /* U+95BE */ - {0x00efe8, 0x00e9978a}, /* U+95CA */ - {0x00efe9, 0x00e6bfb6}, /* U+6FF6 */ - {0x00efea, 0x00e99783}, /* U+95C3 */ - {0x00efeb, 0x00e9978d}, /* U+95CD */ - {0x00efec, 0x00e9978c}, /* U+95CC */ - {0x00efed, 0x00e99795}, /* U+95D5 */ - {0x00efee, 0x00e99794}, /* U+95D4 */ - {0x00efef, 0x00e99796}, /* U+95D6 */ - {0x00eff0, 0x00e9979c}, /* U+95DC */ - {0x00eff1, 0x00e997a1}, /* U+95E1 */ - {0x00eff2, 0x00e997a5}, /* U+95E5 */ - {0x00eff3, 0x00e997a2}, /* U+95E2 */ - {0x00eff4, 0x00e998a1}, /* U+9621 */ - {0x00eff5, 0x00e998a8}, /* U+9628 */ - {0x00eff6, 0x00e998ae}, /* U+962E */ - {0x00eff7, 0x00e998af}, /* U+962F */ - {0x00eff8, 0x00e99982}, /* U+9642 */ - {0x00eff9, 0x00e9998c}, /* U+964C */ - {0x00effa, 0x00e9998f}, /* U+964F */ - {0x00effb, 0x00e9998b}, /* U+964B */ - {0x00effc, 0x00e999b7}, /* U+9677 */ - {0x00effd, 0x00e9999c}, /* U+965C */ - {0x00effe, 0x00e9999e}, /* U+965E */ - {0x00f0a1, 0x00e9999d}, /* U+965D */ - {0x00f0a2, 0x00e9999f}, /* U+965F */ - {0x00f0a3, 0x00e999a6}, /* U+9666 */ - {0x00f0a4, 0x00e999b2}, /* U+9672 */ - {0x00f0a5, 0x00e999ac}, /* U+966C */ - {0x00f0a6, 0x00e99a8d}, /* U+968D */ - {0x00f0a7, 0x00e99a98}, /* U+9698 */ - {0x00f0a8, 0x00e99a95}, /* U+9695 */ - {0x00f0a9, 0x00e99a97}, /* U+9697 */ - {0x00f0aa, 0x00e99aaa}, /* U+96AA */ - {0x00f0ab, 0x00e99aa7}, /* U+96A7 */ - {0x00f0ac, 0x00e99ab1}, /* U+96B1 */ - {0x00f0ad, 0x00e99ab2}, /* U+96B2 */ - {0x00f0ae, 0x00e99ab0}, /* U+96B0 */ - {0x00f0af, 0x00e99ab4}, /* U+96B4 */ - {0x00f0b0, 0x00e99ab6}, /* U+96B6 */ - {0x00f0b1, 0x00e99ab8}, /* U+96B8 */ - {0x00f0b2, 0x00e99ab9}, /* U+96B9 */ - {0x00f0b3, 0x00e99b8e}, /* U+96CE */ - {0x00f0b4, 0x00e99b8b}, /* U+96CB */ - {0x00f0b5, 0x00e99b89}, /* U+96C9 */ - {0x00f0b6, 0x00e99b8d}, /* U+96CD */ - {0x00f0b7, 0x00e8a58d}, /* U+894D */ - {0x00f0b8, 0x00e99b9c}, /* U+96DC */ - {0x00f0b9, 0x00e99c8d}, /* U+970D */ - {0x00f0ba, 0x00e99b95}, /* U+96D5 */ - {0x00f0bb, 0x00e99bb9}, /* U+96F9 */ - {0x00f0bc, 0x00e99c84}, /* U+9704 */ - {0x00f0bd, 0x00e99c86}, /* U+9706 */ - {0x00f0be, 0x00e99c88}, /* U+9708 */ - {0x00f0bf, 0x00e99c93}, /* U+9713 */ - {0x00f0c0, 0x00e99c8e}, /* U+970E */ - {0x00f0c1, 0x00e99c91}, /* U+9711 */ - {0x00f0c2, 0x00e99c8f}, /* U+970F */ - {0x00f0c3, 0x00e99c96}, /* U+9716 */ - {0x00f0c4, 0x00e99c99}, /* U+9719 */ - {0x00f0c5, 0x00e99ca4}, /* U+9724 */ - {0x00f0c6, 0x00e99caa}, /* U+972A */ - {0x00f0c7, 0x00e99cb0}, /* U+9730 */ - {0x00f0c8, 0x00e99cb9}, /* U+9739 */ - {0x00f0c9, 0x00e99cbd}, /* U+973D */ - {0x00f0ca, 0x00e99cbe}, /* U+973E */ - {0x00f0cb, 0x00e99d84}, /* U+9744 */ - {0x00f0cc, 0x00e99d86}, /* U+9746 */ - {0x00f0cd, 0x00e99d88}, /* U+9748 */ - {0x00f0ce, 0x00e99d82}, /* U+9742 */ - {0x00f0cf, 0x00e99d89}, /* U+9749 */ - {0x00f0d0, 0x00e99d9c}, /* U+975C */ - {0x00f0d1, 0x00e99da0}, /* U+9760 */ - {0x00f0d2, 0x00e99da4}, /* U+9764 */ - {0x00f0d3, 0x00e99da6}, /* U+9766 */ - {0x00f0d4, 0x00e99da8}, /* U+9768 */ - {0x00f0d5, 0x00e58b92}, /* U+52D2 */ - {0x00f0d6, 0x00e99dab}, /* U+976B */ - {0x00f0d7, 0x00e99db1}, /* U+9771 */ - {0x00f0d8, 0x00e99db9}, /* U+9779 */ - {0x00f0d9, 0x00e99e85}, /* U+9785 */ - {0x00f0da, 0x00e99dbc}, /* U+977C */ - {0x00f0db, 0x00e99e81}, /* U+9781 */ - {0x00f0dc, 0x00e99dba}, /* U+977A */ - {0x00f0dd, 0x00e99e86}, /* U+9786 */ - {0x00f0de, 0x00e99e8b}, /* U+978B */ - {0x00f0df, 0x00e99e8f}, /* U+978F */ - {0x00f0e0, 0x00e99e90}, /* U+9790 */ - {0x00f0e1, 0x00e99e9c}, /* U+979C */ - {0x00f0e2, 0x00e99ea8}, /* U+97A8 */ - {0x00f0e3, 0x00e99ea6}, /* U+97A6 */ - {0x00f0e4, 0x00e99ea3}, /* U+97A3 */ - {0x00f0e5, 0x00e99eb3}, /* U+97B3 */ - {0x00f0e6, 0x00e99eb4}, /* U+97B4 */ - {0x00f0e7, 0x00e99f83}, /* U+97C3 */ - {0x00f0e8, 0x00e99f86}, /* U+97C6 */ - {0x00f0e9, 0x00e99f88}, /* U+97C8 */ - {0x00f0ea, 0x00e99f8b}, /* U+97CB */ - {0x00f0eb, 0x00e99f9c}, /* U+97DC */ - {0x00f0ec, 0x00e99fad}, /* U+97ED */ - {0x00f0ed, 0x00e9bd8f}, /* U+9F4F */ - {0x00f0ee, 0x00e99fb2}, /* U+97F2 */ - {0x00f0ef, 0x00e7ab9f}, /* U+7ADF */ - {0x00f0f0, 0x00e99fb6}, /* U+97F6 */ - {0x00f0f1, 0x00e99fb5}, /* U+97F5 */ - {0x00f0f2, 0x00e9a08f}, /* U+980F */ - {0x00f0f3, 0x00e9a08c}, /* U+980C */ - {0x00f0f4, 0x00e9a0b8}, /* U+9838 */ - {0x00f0f5, 0x00e9a0a4}, /* U+9824 */ - {0x00f0f6, 0x00e9a0a1}, /* U+9821 */ - {0x00f0f7, 0x00e9a0b7}, /* U+9837 */ - {0x00f0f8, 0x00e9a0bd}, /* U+983D */ - {0x00f0f9, 0x00e9a186}, /* U+9846 */ - {0x00f0fa, 0x00e9a18f}, /* U+984F */ - {0x00f0fb, 0x00e9a18b}, /* U+984B */ - {0x00f0fc, 0x00e9a1ab}, /* U+986B */ - {0x00f0fd, 0x00e9a1af}, /* U+986F */ - {0x00f0fe, 0x00e9a1b0}, /* U+9870 */ - {0x00f1a1, 0x00e9a1b1}, /* U+9871 */ - {0x00f1a2, 0x00e9a1b4}, /* U+9874 */ - {0x00f1a3, 0x00e9a1b3}, /* U+9873 */ - {0x00f1a4, 0x00e9a2aa}, /* U+98AA */ - {0x00f1a5, 0x00e9a2af}, /* U+98AF */ - {0x00f1a6, 0x00e9a2b1}, /* U+98B1 */ - {0x00f1a7, 0x00e9a2b6}, /* U+98B6 */ - {0x00f1a8, 0x00e9a384}, /* U+98C4 */ - {0x00f1a9, 0x00e9a383}, /* U+98C3 */ - {0x00f1aa, 0x00e9a386}, /* U+98C6 */ - {0x00f1ab, 0x00e9a3a9}, /* U+98E9 */ - {0x00f1ac, 0x00e9a3ab}, /* U+98EB */ - {0x00f1ad, 0x00e9a483}, /* U+9903 */ - {0x00f1ae, 0x00e9a489}, /* U+9909 */ - {0x00f1af, 0x00e9a492}, /* U+9912 */ - {0x00f1b0, 0x00e9a494}, /* U+9914 */ - {0x00f1b1, 0x00e9a498}, /* U+9918 */ - {0x00f1b2, 0x00e9a4a1}, /* U+9921 */ - {0x00f1b3, 0x00e9a49d}, /* U+991D */ - {0x00f1b4, 0x00e9a49e}, /* U+991E */ - {0x00f1b5, 0x00e9a4a4}, /* U+9924 */ - {0x00f1b6, 0x00e9a4a0}, /* U+9920 */ - {0x00f1b7, 0x00e9a4ac}, /* U+992C */ - {0x00f1b8, 0x00e9a4ae}, /* U+992E */ - {0x00f1b9, 0x00e9a4bd}, /* U+993D */ - {0x00f1ba, 0x00e9a4be}, /* U+993E */ - {0x00f1bb, 0x00e9a582}, /* U+9942 */ - {0x00f1bc, 0x00e9a589}, /* U+9949 */ - {0x00f1bd, 0x00e9a585}, /* U+9945 */ - {0x00f1be, 0x00e9a590}, /* U+9950 */ - {0x00f1bf, 0x00e9a58b}, /* U+994B */ - {0x00f1c0, 0x00e9a591}, /* U+9951 */ - {0x00f1c1, 0x00e9a592}, /* U+9952 */ - {0x00f1c2, 0x00e9a58c}, /* U+994C */ - {0x00f1c3, 0x00e9a595}, /* U+9955 */ - {0x00f1c4, 0x00e9a697}, /* U+9997 */ - {0x00f1c5, 0x00e9a698}, /* U+9998 */ - {0x00f1c6, 0x00e9a6a5}, /* U+99A5 */ - {0x00f1c7, 0x00e9a6ad}, /* U+99AD */ - {0x00f1c8, 0x00e9a6ae}, /* U+99AE */ - {0x00f1c9, 0x00e9a6bc}, /* U+99BC */ - {0x00f1ca, 0x00e9a79f}, /* U+99DF */ - {0x00f1cb, 0x00e9a79b}, /* U+99DB */ - {0x00f1cc, 0x00e9a79d}, /* U+99DD */ - {0x00f1cd, 0x00e9a798}, /* U+99D8 */ - {0x00f1ce, 0x00e9a791}, /* U+99D1 */ - {0x00f1cf, 0x00e9a7ad}, /* U+99ED */ - {0x00f1d0, 0x00e9a7ae}, /* U+99EE */ - {0x00f1d1, 0x00e9a7b1}, /* U+99F1 */ - {0x00f1d2, 0x00e9a7b2}, /* U+99F2 */ - {0x00f1d3, 0x00e9a7bb}, /* U+99FB */ - {0x00f1d4, 0x00e9a7b8}, /* U+99F8 */ - {0x00f1d5, 0x00e9a881}, /* U+9A01 */ - {0x00f1d6, 0x00e9a88f}, /* U+9A0F */ - {0x00f1d7, 0x00e9a885}, /* U+9A05 */ - {0x00f1d8, 0x00e9a7a2}, /* U+99E2 */ - {0x00f1d9, 0x00e9a899}, /* U+9A19 */ - {0x00f1da, 0x00e9a8ab}, /* U+9A2B */ - {0x00f1db, 0x00e9a8b7}, /* U+9A37 */ - {0x00f1dc, 0x00e9a985}, /* U+9A45 */ - {0x00f1dd, 0x00e9a982}, /* U+9A42 */ - {0x00f1de, 0x00e9a980}, /* U+9A40 */ - {0x00f1df, 0x00e9a983}, /* U+9A43 */ - {0x00f1e0, 0x00e9a8be}, /* U+9A3E */ - {0x00f1e1, 0x00e9a995}, /* U+9A55 */ - {0x00f1e2, 0x00e9a98d}, /* U+9A4D */ - {0x00f1e3, 0x00e9a99b}, /* U+9A5B */ - {0x00f1e4, 0x00e9a997}, /* U+9A57 */ - {0x00f1e5, 0x00e9a99f}, /* U+9A5F */ - {0x00f1e6, 0x00e9a9a2}, /* U+9A62 */ - {0x00f1e7, 0x00e9a9a5}, /* U+9A65 */ - {0x00f1e8, 0x00e9a9a4}, /* U+9A64 */ - {0x00f1e9, 0x00e9a9a9}, /* U+9A69 */ - {0x00f1ea, 0x00e9a9ab}, /* U+9A6B */ - {0x00f1eb, 0x00e9a9aa}, /* U+9A6A */ - {0x00f1ec, 0x00e9aaad}, /* U+9AAD */ - {0x00f1ed, 0x00e9aab0}, /* U+9AB0 */ - {0x00f1ee, 0x00e9aabc}, /* U+9ABC */ - {0x00f1ef, 0x00e9ab80}, /* U+9AC0 */ - {0x00f1f0, 0x00e9ab8f}, /* U+9ACF */ - {0x00f1f1, 0x00e9ab91}, /* U+9AD1 */ - {0x00f1f2, 0x00e9ab93}, /* U+9AD3 */ - {0x00f1f3, 0x00e9ab94}, /* U+9AD4 */ - {0x00f1f4, 0x00e9ab9e}, /* U+9ADE */ - {0x00f1f5, 0x00e9ab9f}, /* U+9ADF */ - {0x00f1f6, 0x00e9aba2}, /* U+9AE2 */ - {0x00f1f7, 0x00e9aba3}, /* U+9AE3 */ - {0x00f1f8, 0x00e9aba6}, /* U+9AE6 */ - {0x00f1f9, 0x00e9abaf}, /* U+9AEF */ - {0x00f1fa, 0x00e9abab}, /* U+9AEB */ - {0x00f1fb, 0x00e9abae}, /* U+9AEE */ - {0x00f1fc, 0x00e9abb4}, /* U+9AF4 */ - {0x00f1fd, 0x00e9abb1}, /* U+9AF1 */ - {0x00f1fe, 0x00e9abb7}, /* U+9AF7 */ - {0x00f2a1, 0x00e9abbb}, /* U+9AFB */ - {0x00f2a2, 0x00e9ac86}, /* U+9B06 */ - {0x00f2a3, 0x00e9ac98}, /* U+9B18 */ - {0x00f2a4, 0x00e9ac9a}, /* U+9B1A */ - {0x00f2a5, 0x00e9ac9f}, /* U+9B1F */ - {0x00f2a6, 0x00e9aca2}, /* U+9B22 */ - {0x00f2a7, 0x00e9aca3}, /* U+9B23 */ - {0x00f2a8, 0x00e9aca5}, /* U+9B25 */ - {0x00f2a9, 0x00e9aca7}, /* U+9B27 */ - {0x00f2aa, 0x00e9aca8}, /* U+9B28 */ - {0x00f2ab, 0x00e9aca9}, /* U+9B29 */ - {0x00f2ac, 0x00e9acaa}, /* U+9B2A */ - {0x00f2ad, 0x00e9acae}, /* U+9B2E */ - {0x00f2ae, 0x00e9acaf}, /* U+9B2F */ - {0x00f2af, 0x00e9acb2}, /* U+9B32 */ - {0x00f2b0, 0x00e9ad84}, /* U+9B44 */ - {0x00f2b1, 0x00e9ad83}, /* U+9B43 */ - {0x00f2b2, 0x00e9ad8f}, /* U+9B4F */ - {0x00f2b3, 0x00e9ad8d}, /* U+9B4D */ - {0x00f2b4, 0x00e9ad8e}, /* U+9B4E */ - {0x00f2b5, 0x00e9ad91}, /* U+9B51 */ - {0x00f2b6, 0x00e9ad98}, /* U+9B58 */ - {0x00f2b7, 0x00e9adb4}, /* U+9B74 */ - {0x00f2b8, 0x00e9ae93}, /* U+9B93 */ - {0x00f2b9, 0x00e9ae83}, /* U+9B83 */ - {0x00f2ba, 0x00e9ae91}, /* U+9B91 */ - {0x00f2bb, 0x00e9ae96}, /* U+9B96 */ - {0x00f2bc, 0x00e9ae97}, /* U+9B97 */ - {0x00f2bd, 0x00e9ae9f}, /* U+9B9F */ - {0x00f2be, 0x00e9aea0}, /* U+9BA0 */ - {0x00f2bf, 0x00e9aea8}, /* U+9BA8 */ - {0x00f2c0, 0x00e9aeb4}, /* U+9BB4 */ - {0x00f2c1, 0x00e9af80}, /* U+9BC0 */ - {0x00f2c2, 0x00e9af8a}, /* U+9BCA */ - {0x00f2c3, 0x00e9aeb9}, /* U+9BB9 */ - {0x00f2c4, 0x00e9af86}, /* U+9BC6 */ - {0x00f2c5, 0x00e9af8f}, /* U+9BCF */ - {0x00f2c6, 0x00e9af91}, /* U+9BD1 */ - {0x00f2c7, 0x00e9af92}, /* U+9BD2 */ - {0x00f2c8, 0x00e9afa3}, /* U+9BE3 */ - {0x00f2c9, 0x00e9afa2}, /* U+9BE2 */ - {0x00f2ca, 0x00e9afa4}, /* U+9BE4 */ - {0x00f2cb, 0x00e9af94}, /* U+9BD4 */ - {0x00f2cc, 0x00e9afa1}, /* U+9BE1 */ - {0x00f2cd, 0x00e9b0ba}, /* U+9C3A */ - {0x00f2ce, 0x00e9afb2}, /* U+9BF2 */ - {0x00f2cf, 0x00e9afb1}, /* U+9BF1 */ - {0x00f2d0, 0x00e9afb0}, /* U+9BF0 */ - {0x00f2d1, 0x00e9b095}, /* U+9C15 */ - {0x00f2d2, 0x00e9b094}, /* U+9C14 */ - {0x00f2d3, 0x00e9b089}, /* U+9C09 */ - {0x00f2d4, 0x00e9b093}, /* U+9C13 */ - {0x00f2d5, 0x00e9b08c}, /* U+9C0C */ - {0x00f2d6, 0x00e9b086}, /* U+9C06 */ - {0x00f2d7, 0x00e9b088}, /* U+9C08 */ - {0x00f2d8, 0x00e9b092}, /* U+9C12 */ - {0x00f2d9, 0x00e9b08a}, /* U+9C0A */ - {0x00f2da, 0x00e9b084}, /* U+9C04 */ - {0x00f2db, 0x00e9b0ae}, /* U+9C2E */ - {0x00f2dc, 0x00e9b09b}, /* U+9C1B */ - {0x00f2dd, 0x00e9b0a5}, /* U+9C25 */ - {0x00f2de, 0x00e9b0a4}, /* U+9C24 */ - {0x00f2df, 0x00e9b0a1}, /* U+9C21 */ - {0x00f2e0, 0x00e9b0b0}, /* U+9C30 */ - {0x00f2e1, 0x00e9b187}, /* U+9C47 */ - {0x00f2e2, 0x00e9b0b2}, /* U+9C32 */ - {0x00f2e3, 0x00e9b186}, /* U+9C46 */ - {0x00f2e4, 0x00e9b0be}, /* U+9C3E */ - {0x00f2e5, 0x00e9b19a}, /* U+9C5A */ - {0x00f2e6, 0x00e9b1a0}, /* U+9C60 */ - {0x00f2e7, 0x00e9b1a7}, /* U+9C67 */ - {0x00f2e8, 0x00e9b1b6}, /* U+9C76 */ - {0x00f2e9, 0x00e9b1b8}, /* U+9C78 */ - {0x00f2ea, 0x00e9b3a7}, /* U+9CE7 */ - {0x00f2eb, 0x00e9b3ac}, /* U+9CEC */ - {0x00f2ec, 0x00e9b3b0}, /* U+9CF0 */ - {0x00f2ed, 0x00e9b489}, /* U+9D09 */ - {0x00f2ee, 0x00e9b488}, /* U+9D08 */ - {0x00f2ef, 0x00e9b3ab}, /* U+9CEB */ - {0x00f2f0, 0x00e9b483}, /* U+9D03 */ - {0x00f2f1, 0x00e9b486}, /* U+9D06 */ - {0x00f2f2, 0x00e9b4aa}, /* U+9D2A */ - {0x00f2f3, 0x00e9b4a6}, /* U+9D26 */ - {0x00f2f4, 0x00e9b6af}, /* U+9DAF */ - {0x00f2f5, 0x00e9b4a3}, /* U+9D23 */ - {0x00f2f6, 0x00e9b49f}, /* U+9D1F */ - {0x00f2f7, 0x00e9b584}, /* U+9D44 */ - {0x00f2f8, 0x00e9b495}, /* U+9D15 */ - {0x00f2f9, 0x00e9b492}, /* U+9D12 */ - {0x00f2fa, 0x00e9b581}, /* U+9D41 */ - {0x00f2fb, 0x00e9b4bf}, /* U+9D3F */ - {0x00f2fc, 0x00e9b4be}, /* U+9D3E */ - {0x00f2fd, 0x00e9b586}, /* U+9D46 */ - {0x00f2fe, 0x00e9b588}, /* U+9D48 */ - {0x00f3a1, 0x00e9b59d}, /* U+9D5D */ - {0x00f3a2, 0x00e9b59e}, /* U+9D5E */ - {0x00f3a3, 0x00e9b5a4}, /* U+9D64 */ - {0x00f3a4, 0x00e9b591}, /* U+9D51 */ - {0x00f3a5, 0x00e9b590}, /* U+9D50 */ - {0x00f3a6, 0x00e9b599}, /* U+9D59 */ - {0x00f3a7, 0x00e9b5b2}, /* U+9D72 */ - {0x00f3a8, 0x00e9b689}, /* U+9D89 */ - {0x00f3a9, 0x00e9b687}, /* U+9D87 */ - {0x00f3aa, 0x00e9b6ab}, /* U+9DAB */ - {0x00f3ab, 0x00e9b5af}, /* U+9D6F */ - {0x00f3ac, 0x00e9b5ba}, /* U+9D7A */ - {0x00f3ad, 0x00e9b69a}, /* U+9D9A */ - {0x00f3ae, 0x00e9b6a4}, /* U+9DA4 */ - {0x00f3af, 0x00e9b6a9}, /* U+9DA9 */ - {0x00f3b0, 0x00e9b6b2}, /* U+9DB2 */ - {0x00f3b1, 0x00e9b784}, /* U+9DC4 */ - {0x00f3b2, 0x00e9b781}, /* U+9DC1 */ - {0x00f3b3, 0x00e9b6bb}, /* U+9DBB */ - {0x00f3b4, 0x00e9b6b8}, /* U+9DB8 */ - {0x00f3b5, 0x00e9b6ba}, /* U+9DBA */ - {0x00f3b6, 0x00e9b786}, /* U+9DC6 */ - {0x00f3b7, 0x00e9b78f}, /* U+9DCF */ - {0x00f3b8, 0x00e9b782}, /* U+9DC2 */ - {0x00f3b9, 0x00e9b799}, /* U+9DD9 */ - {0x00f3ba, 0x00e9b793}, /* U+9DD3 */ - {0x00f3bb, 0x00e9b7b8}, /* U+9DF8 */ - {0x00f3bc, 0x00e9b7a6}, /* U+9DE6 */ - {0x00f3bd, 0x00e9b7ad}, /* U+9DED */ - {0x00f3be, 0x00e9b7af}, /* U+9DEF */ - {0x00f3bf, 0x00e9b7bd}, /* U+9DFD */ - {0x00f3c0, 0x00e9b89a}, /* U+9E1A */ - {0x00f3c1, 0x00e9b89b}, /* U+9E1B */ - {0x00f3c2, 0x00e9b89e}, /* U+9E1E */ - {0x00f3c3, 0x00e9b9b5}, /* U+9E75 */ - {0x00f3c4, 0x00e9b9b9}, /* U+9E79 */ - {0x00f3c5, 0x00e9b9bd}, /* U+9E7D */ - {0x00f3c6, 0x00e9ba81}, /* U+9E81 */ - {0x00f3c7, 0x00e9ba88}, /* U+9E88 */ - {0x00f3c8, 0x00e9ba8b}, /* U+9E8B */ - {0x00f3c9, 0x00e9ba8c}, /* U+9E8C */ - {0x00f3ca, 0x00e9ba92}, /* U+9E92 */ - {0x00f3cb, 0x00e9ba95}, /* U+9E95 */ - {0x00f3cc, 0x00e9ba91}, /* U+9E91 */ - {0x00f3cd, 0x00e9ba9d}, /* U+9E9D */ - {0x00f3ce, 0x00e9baa5}, /* U+9EA5 */ - {0x00f3cf, 0x00e9baa9}, /* U+9EA9 */ - {0x00f3d0, 0x00e9bab8}, /* U+9EB8 */ - {0x00f3d1, 0x00e9baaa}, /* U+9EAA */ - {0x00f3d2, 0x00e9baad}, /* U+9EAD */ - {0x00f3d3, 0x00e99da1}, /* U+9761 */ - {0x00f3d4, 0x00e9bb8c}, /* U+9ECC */ - {0x00f3d5, 0x00e9bb8e}, /* U+9ECE */ - {0x00f3d6, 0x00e9bb8f}, /* U+9ECF */ - {0x00f3d7, 0x00e9bb90}, /* U+9ED0 */ - {0x00f3d8, 0x00e9bb94}, /* U+9ED4 */ - {0x00f3d9, 0x00e9bb9c}, /* U+9EDC */ - {0x00f3da, 0x00e9bb9e}, /* U+9EDE */ - {0x00f3db, 0x00e9bb9d}, /* U+9EDD */ - {0x00f3dc, 0x00e9bba0}, /* U+9EE0 */ - {0x00f3dd, 0x00e9bba5}, /* U+9EE5 */ - {0x00f3de, 0x00e9bba8}, /* U+9EE8 */ - {0x00f3df, 0x00e9bbaf}, /* U+9EEF */ - {0x00f3e0, 0x00e9bbb4}, /* U+9EF4 */ - {0x00f3e1, 0x00e9bbb6}, /* U+9EF6 */ - {0x00f3e2, 0x00e9bbb7}, /* U+9EF7 */ - {0x00f3e3, 0x00e9bbb9}, /* U+9EF9 */ - {0x00f3e4, 0x00e9bbbb}, /* U+9EFB */ - {0x00f3e5, 0x00e9bbbc}, /* U+9EFC */ - {0x00f3e6, 0x00e9bbbd}, /* U+9EFD */ - {0x00f3e7, 0x00e9bc87}, /* U+9F07 */ - {0x00f3e8, 0x00e9bc88}, /* U+9F08 */ - {0x00f3e9, 0x00e79ab7}, /* U+76B7 */ - {0x00f3ea, 0x00e9bc95}, /* U+9F15 */ - {0x00f3eb, 0x00e9bca1}, /* U+9F21 */ - {0x00f3ec, 0x00e9bcac}, /* U+9F2C */ - {0x00f3ed, 0x00e9bcbe}, /* U+9F3E */ - {0x00f3ee, 0x00e9bd8a}, /* U+9F4A */ - {0x00f3ef, 0x00e9bd92}, /* U+9F52 */ - {0x00f3f0, 0x00e9bd94}, /* U+9F54 */ - {0x00f3f1, 0x00e9bda3}, /* U+9F63 */ - {0x00f3f2, 0x00e9bd9f}, /* U+9F5F */ - {0x00f3f3, 0x00e9bda0}, /* U+9F60 */ - {0x00f3f4, 0x00e9bda1}, /* U+9F61 */ - {0x00f3f5, 0x00e9bda6}, /* U+9F66 */ - {0x00f3f6, 0x00e9bda7}, /* U+9F67 */ - {0x00f3f7, 0x00e9bdac}, /* U+9F6C */ - {0x00f3f8, 0x00e9bdaa}, /* U+9F6A */ - {0x00f3f9, 0x00e9bdb7}, /* U+9F77 */ - {0x00f3fa, 0x00e9bdb2}, /* U+9F72 */ - {0x00f3fb, 0x00e9bdb6}, /* U+9F76 */ - {0x00f3fc, 0x00e9be95}, /* U+9F95 */ - {0x00f3fd, 0x00e9be9c}, /* U+9F9C */ - {0x00f3fe, 0x00e9bea0}, /* U+9FA0 */ - {0x00f4a1, 0x00e5a0af}, /* U+582F [1983] */ - {0x00f4a2, 0x00e6a787}, /* U+69C7 [1983] */ - {0x00f4a3, 0x00e98199}, /* U+9059 [1983] */ - {0x00f4a4, 0x00e791a4}, /* U+7464 [1983] */ - {0x00f4a5, 0x00e5879c}, /* U+51DC [1990] */ - {0x00f4a6, 0x00e78699}, /* U+7199 [1990] */ - {0x00f4a7, 0x00e59993}, /* U+5653 [2004] */ - {0x00f4a8, 0x00e5b7a2}, /* U+5DE2 [2000] */ - {0x00f4a9, 0x00e5b894}, /* U+5E14 [2000] */ - {0x00f4aa, 0x00e5b898}, /* U+5E18 [2000] */ - {0x00f4ab, 0x00e5b998}, /* U+5E58 [2000] */ - {0x00f4ac, 0x00e5b99e}, /* U+5E5E [2000] */ - {0x00f4ad, 0x00e5babe}, /* U+5EBE [2000] */ - {0x00f4ae, 0x00efa4a8}, /* U+F928 CJK COMPATIBILITY IDEOGRAPH-F928 [2000] */ - {0x00f4af, 0x00e5bb8b}, /* U+5ECB [2000] */ - {0x00f4b0, 0x00e5bbb9}, /* U+5EF9 [2000] */ - {0x00f4b1, 0x00e5bc80}, /* U+5F00 [2000] */ - {0x00f4b2, 0x00e5bc82}, /* U+5F02 [2000] */ - {0x00f4b3, 0x00e5bc87}, /* U+5F07 [2000] */ - {0x00f4b4, 0x00e5bc9d}, /* U+5F1D [2000] */ - {0x00f4b5, 0x00e5bca3}, /* U+5F23 [2000] */ - {0x00f4b6, 0x00e5bcb4}, /* U+5F34 [2000] */ - {0x00f4b7, 0x00e5bcb6}, /* U+5F36 [2000] */ - {0x00f4b8, 0x00e5bcbd}, /* U+5F3D [2000] */ - {0x00f4b9, 0x00e5bd80}, /* U+5F40 [2000] */ - {0x00f4ba, 0x00e5bd85}, /* U+5F45 [2000] */ - {0x00f4bb, 0x00e5bd94}, /* U+5F54 [2000] */ - {0x00f4bc, 0x00e5bd98}, /* U+5F58 [2000] */ - {0x00f4bd, 0x00e5bda4}, /* U+5F64 [2000] */ - {0x00f4be, 0x00e5bda7}, /* U+5F67 [2000] */ - {0x00f4bf, 0x00e5bdbd}, /* U+5F7D [2000] */ - {0x00f4c0, 0x00e5be89}, /* U+5F89 [2000] */ - {0x00f4c1, 0x00e5be9c}, /* U+5F9C [2000] */ - {0x00f4c2, 0x00e5bea7}, /* U+5FA7 [2000] */ - {0x00f4c3, 0x00e5beaf}, /* U+5FAF [2000] */ - {0x00f4c4, 0x00e5beb5}, /* U+5FB5 [2000] */ - {0x00f4c5, 0x00e5beb7}, /* U+5FB7 [2000] */ - {0x00f4c6, 0x00e5bf89}, /* U+5FC9 [2000] */ - {0x00f4c7, 0x00e5bf9e}, /* U+5FDE [2000] */ - {0x00f4c8, 0x00e5bfa1}, /* U+5FE1 [2000] */ - {0x00f4c9, 0x00e5bfa9}, /* U+5FE9 [2000] */ - {0x00f4ca, 0x00e6808d}, /* U+600D [2000] */ - {0x00f4cb, 0x00e68094}, /* U+6014 [2000] */ - {0x00f4cc, 0x00e68098}, /* U+6018 [2000] */ - {0x00f4cd, 0x00e680b3}, /* U+6033 [2000] */ - {0x00f4ce, 0x00e680b5}, /* U+6035 [2000] */ - {0x00f4cf, 0x00e68187}, /* U+6047 [2000] */ - {0x00f4d0, 0x00efa8bd}, /* U+FA3D CJK COMPATIBILITY IDEOGRAPH-FA3D [2000] [Unicode3.2] */ - {0x00f4d1, 0x00e6829d}, /* U+609D [2000] */ - {0x00f4d2, 0x00e6829e}, /* U+609E [2000] */ - {0x00f4d3, 0x00e6838b}, /* U+60CB [2000] */ - {0x00f4d4, 0x00e68394}, /* U+60D4 [2000] */ - {0x00f4d5, 0x00e68395}, /* U+60D5 [2000] */ - {0x00f4d6, 0x00e6839d}, /* U+60DD [2000] */ - {0x00f4d7, 0x00e683b8}, /* U+60F8 [2000] */ - {0x00f4d8, 0x00e6849c}, /* U+611C [2000] */ - {0x00f4d9, 0x00e684ab}, /* U+612B [2000] */ - {0x00f4da, 0x00e684b0}, /* U+6130 [2000] */ - {0x00f4db, 0x00e684b7}, /* U+6137 [2000] */ - {0x00f4dc, 0x00efa8be}, /* U+FA3E CJK COMPATIBILITY IDEOGRAPH-FA3E [2000] [Unicode3.2] */ - {0x00f4dd, 0x00e6868d}, /* U+618D [2000] */ - {0x00f4de, 0x00efa8bf}, /* U+FA3F CJK COMPATIBILITY IDEOGRAPH-FA3F [2000] [Unicode3.2] */ - {0x00f4df, 0x00e686bc}, /* U+61BC [2000] */ - {0x00f4e0, 0x00e686b9}, /* U+61B9 [2000] */ - {0x00f4e1, 0x00efa980}, /* U+FA40 CJK COMPATIBILITY IDEOGRAPH-FA40 [2000] [Unicode3.2] */ - {0x00f4e2, 0x00e688a2}, /* U+6222 [2000] */ - {0x00f4e3, 0x00e688be}, /* U+623E [2000] */ - {0x00f4e4, 0x00e68983}, /* U+6243 [2000] */ - {0x00f4e5, 0x00e68996}, /* U+6256 [2000] */ - {0x00f4e6, 0x00e6899a}, /* U+625A [2000] */ - {0x00f4e7, 0x00e689af}, /* U+626F [2000] */ - {0x00f4e8, 0x00e68a85}, /* U+6285 [2000] */ - {0x00f4e9, 0x00e68b84}, /* U+62C4 [2000] */ - {0x00f4ea, 0x00e68b96}, /* U+62D6 [2000] */ - {0x00f4eb, 0x00e68bbc}, /* U+62FC [2000] */ - {0x00f4ec, 0x00e68c8a}, /* U+630A [2000] */ - {0x00f4ed, 0x00e68c98}, /* U+6318 [2000] */ - {0x00f4ee, 0x00e68cb9}, /* U+6339 [2000] */ - {0x00f4ef, 0x00e68d83}, /* U+6343 [2000] */ - {0x00f4f0, 0x00e68da5}, /* U+6365 [2000] */ - {0x00f4f1, 0x00e68dbc}, /* U+637C [2000] */ - {0x00f4f2, 0x00e68fa5}, /* U+63E5 [2000] */ - {0x00f4f3, 0x00e68fad}, /* U+63ED [2000] */ - {0x00f4f4, 0x00e68fb5}, /* U+63F5 [2000] */ - {0x00f4f5, 0x00e69090}, /* U+6410 [2000] */ - {0x00f4f6, 0x00e69094}, /* U+6414 [2000] */ - {0x00f4f7, 0x00e690a2}, /* U+6422 [2000] */ - {0x00f4f8, 0x00e691b9}, /* U+6479 [2000] */ - {0x00f4f9, 0x00e69191}, /* U+6451 [2000] */ - {0x00f4fa, 0x00e691a0}, /* U+6460 [2000] */ - {0x00f4fb, 0x00e691ad}, /* U+646D [2000] */ - {0x00f4fc, 0x00e6938e}, /* U+64CE [2000] */ - {0x00f4fd, 0x00e692be}, /* U+64BE [2000] */ - {0x00f4fe, 0x00e692bf}, /* U+64BF [2000] */ - {0x00f5a1, 0x00e69384}, /* U+64C4 [2000] */ - {0x00f5a2, 0x00e6938a}, /* U+64CA [2000] */ - {0x00f5a3, 0x00e69390}, /* U+64D0 [2000] */ - {0x00f5a4, 0x00e693b7}, /* U+64F7 [2000] */ - {0x00f5a5, 0x00e693bb}, /* U+64FB [2000] */ - {0x00f5a6, 0x00e694a2}, /* U+6522 [2000] */ - {0x00f5a7, 0x00e694a9}, /* U+6529 [2000] */ - {0x00f5a8, 0x00efa981}, /* U+FA41 CJK COMPATIBILITY IDEOGRAPH-FA41 [2000] [Unicode3.2] */ - {0x00f5a9, 0x00e695a7}, /* U+6567 [2000] */ - {0x00f5aa, 0x00e6969d}, /* U+659D [2000] */ - {0x00f5ab, 0x00efa982}, /* U+FA42 CJK COMPATIBILITY IDEOGRAPH-FA42 [2000] [Unicode3.2] */ - {0x00f5ac, 0x00e69880}, /* U+6600 [2000] */ - {0x00f5ad, 0x00e69889}, /* U+6609 [2000] */ - {0x00f5ae, 0x00e69895}, /* U+6615 [2000] */ - {0x00f5af, 0x00e6989e}, /* U+661E [2000] */ - {0x00f5b0, 0x00e698ba}, /* U+663A [2000] */ - {0x00f5b1, 0x00e698a2}, /* U+6622 [2000] */ - {0x00f5b2, 0x00e698a4}, /* U+6624 [2000] */ - {0x00f5b3, 0x00e698ab}, /* U+662B [2000] */ - {0x00f5b4, 0x00e698b0}, /* U+6630 [2000] */ - {0x00f5b5, 0x00e698b1}, /* U+6631 [2000] */ - {0x00f5b6, 0x00e698b3}, /* U+6633 [2000] */ - {0x00f5b7, 0x00e69bbb}, /* U+66FB [2000] */ - {0x00f5b8, 0x00e69988}, /* U+6648 [2000] */ - {0x00f5b9, 0x00e6998c}, /* U+664C [2000] */ - {0x00f5ba, 0xf0a38784}, /* U+231C4 [2000] [Unicode3.1] */ - {0x00f5bb, 0x00e69999}, /* U+6659 [2000] */ - {0x00f5bc, 0x00e6999a}, /* U+665A [2000] */ - {0x00f5bd, 0x00e699a1}, /* U+6661 [2000] */ - {0x00f5be, 0x00e699a5}, /* U+6665 [2000] */ - {0x00f5bf, 0x00e699b3}, /* U+6673 [2000] */ - {0x00f5c0, 0x00e699b7}, /* U+6677 [2000] */ - {0x00f5c1, 0x00e699b8}, /* U+6678 [2000] */ - {0x00f5c2, 0x00e69a8d}, /* U+668D [2000] */ - {0x00f5c3, 0x00efa983}, /* U+FA43 CJK COMPATIBILITY IDEOGRAPH-FA43 [2000] [Unicode3.2] */ - {0x00f5c4, 0x00e69aa0}, /* U+66A0 [2000] */ - {0x00f5c5, 0x00e69ab2}, /* U+66B2 [2000] */ - {0x00f5c6, 0x00e69abb}, /* U+66BB [2000] */ - {0x00f5c7, 0x00e69b86}, /* U+66C6 [2000] */ - {0x00f5c8, 0x00e69b88}, /* U+66C8 [2000] */ - {0x00f5c9, 0x00e3aca2}, /* U+3B22 [2000] */ - {0x00f5ca, 0x00e69b9b}, /* U+66DB [2000] */ - {0x00f5cb, 0x00e69ba8}, /* U+66E8 [2000] */ - {0x00f5cc, 0x00e69bba}, /* U+66FA [2000] */ - {0x00f5cd, 0x00e69c93}, /* U+6713 [2000] */ - {0x00f5ce, 0x00efa4a9}, /* U+F929 CJK COMPATIBILITY IDEOGRAPH-F929 [2000] */ - {0x00f5cf, 0x00e69cb3}, /* U+6733 [2000] */ - {0x00f5d0, 0x00e69da6}, /* U+6766 [2000] */ - {0x00f5d1, 0x00e69d87}, /* U+6747 [2000] */ - {0x00f5d2, 0x00e69d88}, /* U+6748 [2000] */ - {0x00f5d3, 0x00e69dbb}, /* U+677B [2000] */ - {0x00f5d4, 0x00e69e81}, /* U+6781 [2000] */ - {0x00f5d5, 0x00e69e93}, /* U+6793 [2000] */ - {0x00f5d6, 0x00e69e98}, /* U+6798 [2000] */ - {0x00f5d7, 0x00e69e9b}, /* U+679B [2000] */ - {0x00f5d8, 0x00e69ebb}, /* U+67BB [2000] */ - {0x00f5d9, 0x00e69fb9}, /* U+67F9 [2000] */ - {0x00f5da, 0x00e69f80}, /* U+67C0 [2000] */ - {0x00f5db, 0x00e69f97}, /* U+67D7 [2000] */ - {0x00f5dc, 0x00e69fbc}, /* U+67FC [2000] */ - {0x00f5dd, 0x00e6a081}, /* U+6801 [2000] */ - {0x00f5de, 0x00e6a192}, /* U+6852 [2000] */ - {0x00f5df, 0x00e6a09d}, /* U+681D [2000] */ - {0x00f5e0, 0x00e6a0ac}, /* U+682C [2000] */ - {0x00f5e1, 0x00e6a0b1}, /* U+6831 [2000] */ - {0x00f5e2, 0x00e6a19b}, /* U+685B [2000] */ - {0x00f5e3, 0x00e6a1b2}, /* U+6872 [2000] */ - {0x00f5e4, 0x00e6a1b5}, /* U+6875 [2000] */ - {0x00f5e5, 0x00efa984}, /* U+FA44 CJK COMPATIBILITY IDEOGRAPH-FA44 [2000] [Unicode3.2] */ - {0x00f5e6, 0x00e6a2a3}, /* U+68A3 [2000] */ - {0x00f5e7, 0x00e6a2a5}, /* U+68A5 [2000] */ - {0x00f5e8, 0x00e6a2b2}, /* U+68B2 [2000] */ - {0x00f5e9, 0x00e6a388}, /* U+68C8 [2000] */ - {0x00f5ea, 0x00e6a390}, /* U+68D0 [2000] */ - {0x00f5eb, 0x00e6a3a8}, /* U+68E8 [2000] */ - {0x00f5ec, 0x00e6a3ad}, /* U+68ED [2000] */ - {0x00f5ed, 0x00e6a3b0}, /* U+68F0 [2000] */ - {0x00f5ee, 0x00e6a3b1}, /* U+68F1 [2000] */ - {0x00f5ef, 0x00e6a3bc}, /* U+68FC [2000] */ - {0x00f5f0, 0x00e6a48a}, /* U+690A [2000] */ - {0x00f5f1, 0x00e6a589}, /* U+6949 [2000] */ - {0x00f5f2, 0xf0a39784}, /* U+235C4 [2000] [Unicode3.1] */ - {0x00f5f3, 0x00e6a4b5}, /* U+6935 [2000] */ - {0x00f5f4, 0x00e6a582}, /* U+6942 [2000] */ - {0x00f5f5, 0x00e6a597}, /* U+6957 [2000] */ - {0x00f5f6, 0x00e6a5a3}, /* U+6963 [2000] */ - {0x00f5f7, 0x00e6a5a4}, /* U+6964 [2000] */ - {0x00f5f8, 0x00e6a5a8}, /* U+6968 [2000] */ - {0x00f5f9, 0x00e6a680}, /* U+6980 [2000] */ - {0x00f5fa, 0x00efa894}, /* U+FA14 CJK COMPATIBILITY IDEOGRAPH-FA14 [2000] */ - {0x00f5fb, 0x00e6a6a5}, /* U+69A5 [2000] */ - {0x00f5fc, 0x00e6a6ad}, /* U+69AD [2000] */ - {0x00f5fd, 0x00e6a78f}, /* U+69CF [2000] */ - {0x00f5fe, 0x00e3aeb6}, /* U+3BB6 [2000] */ - {0x00f6a1, 0x00e3af83}, /* U+3BC3 [2000] */ - {0x00f6a2, 0x00e6a7a2}, /* U+69E2 [2000] */ - {0x00f6a3, 0x00e6a7a9}, /* U+69E9 [2000] */ - {0x00f6a4, 0x00e6a7aa}, /* U+69EA [2000] */ - {0x00f6a5, 0x00e6a7b5}, /* U+69F5 [2000] */ - {0x00f6a6, 0x00e6a7b6}, /* U+69F6 [2000] */ - {0x00f6a7, 0x00e6a88f}, /* U+6A0F [2000] */ - {0x00f6a8, 0x00e6a895}, /* U+6A15 [2000] */ - {0x00f6a9, 0xf0a39cbf}, /* U+2373F [2000] [Unicode3.1] */ - {0x00f6aa, 0x00e6a8bb}, /* U+6A3B [2000] */ - {0x00f6ab, 0x00e6a8be}, /* U+6A3E [2000] */ - {0x00f6ac, 0x00e6a985}, /* U+6A45 [2000] */ - {0x00f6ad, 0x00e6a990}, /* U+6A50 [2000] */ - {0x00f6ae, 0x00e6a996}, /* U+6A56 [2000] */ - {0x00f6af, 0x00e6a99b}, /* U+6A5B [2000] */ - {0x00f6b0, 0x00e6a9ab}, /* U+6A6B [2000] */ - {0x00f6b1, 0x00e6a9b3}, /* U+6A73 [2000] */ - {0x00f6b2, 0xf0a39da3}, /* U+23763 [2000] [Unicode3.1] */ - {0x00f6b3, 0x00e6aa89}, /* U+6A89 [2000] */ - {0x00f6b4, 0x00e6aa94}, /* U+6A94 [2000] */ - {0x00f6b5, 0x00e6aa9d}, /* U+6A9D [2000] */ - {0x00f6b6, 0x00e6aa9e}, /* U+6A9E [2000] */ - {0x00f6b7, 0x00e6aaa5}, /* U+6AA5 [2000] */ - {0x00f6b8, 0x00e6aba4}, /* U+6AE4 [2000] */ - {0x00f6b9, 0x00e6aba7}, /* U+6AE7 [2000] */ - {0x00f6ba, 0x00e3b08f}, /* U+3C0F [2000] */ - {0x00f6bb, 0x00efa49d}, /* U+F91D CJK COMPATIBILITY IDEOGRAPH-F91D [2000] */ - {0x00f6bc, 0x00e6ac9b}, /* U+6B1B [2000] */ - {0x00f6bd, 0x00e6ac9e}, /* U+6B1E [2000] */ - {0x00f6be, 0x00e6acac}, /* U+6B2C [2000] */ - {0x00f6bf, 0x00e6acb5}, /* U+6B35 [2000] */ - {0x00f6c0, 0x00e6ad86}, /* U+6B46 [2000] */ - {0x00f6c1, 0x00e6ad96}, /* U+6B56 [2000] */ - {0x00f6c2, 0x00e6ada0}, /* U+6B60 [2000] */ - {0x00f6c3, 0x00e6ada5}, /* U+6B65 [2000] */ - {0x00f6c4, 0x00e6ada7}, /* U+6B67 [2000] */ - {0x00f6c5, 0x00e6adb7}, /* U+6B77 [2000] */ - {0x00f6c6, 0x00e6ae82}, /* U+6B82 [2000] */ - {0x00f6c7, 0x00e6aea9}, /* U+6BA9 [2000] */ - {0x00f6c8, 0x00e6aead}, /* U+6BAD [2000] */ - {0x00f6c9, 0x00efa5b0}, /* U+F970 CJK COMPATIBILITY IDEOGRAPH-F970 [2000] */ - {0x00f6ca, 0x00e6af8f}, /* U+6BCF [2000] */ - {0x00f6cb, 0x00e6af96}, /* U+6BD6 [2000] */ - {0x00f6cc, 0x00e6af97}, /* U+6BD7 [2000] */ - {0x00f6cd, 0x00e6afbf}, /* U+6BFF [2000] */ - {0x00f6ce, 0x00e6b085}, /* U+6C05 [2000] */ - {0x00f6cf, 0x00e6b090}, /* U+6C10 [2000] */ - {0x00f6d0, 0x00e6b0b3}, /* U+6C33 [2000] */ - {0x00f6d1, 0x00e6b199}, /* U+6C59 [2000] */ - {0x00f6d2, 0x00e6b19c}, /* U+6C5C [2000] */ - {0x00f6d3, 0x00e6b2aa}, /* U+6CAA [2000] */ - {0x00f6d4, 0x00e6b1b4}, /* U+6C74 [2000] */ - {0x00f6d5, 0x00e6b1b6}, /* U+6C76 [2000] */ - {0x00f6d6, 0x00e6b285}, /* U+6C85 [2000] */ - {0x00f6d7, 0x00e6b286}, /* U+6C86 [2000] */ - {0x00f6d8, 0x00e6b298}, /* U+6C98 [2000] */ - {0x00f6d9, 0x00e6b29c}, /* U+6C9C [2000] */ - {0x00f6da, 0x00e6b3bb}, /* U+6CFB [2000] */ - {0x00f6db, 0x00e6b386}, /* U+6CC6 [2000] */ - {0x00f6dc, 0x00e6b394}, /* U+6CD4 [2000] */ - {0x00f6dd, 0x00e6b3a0}, /* U+6CE0 [2000] */ - {0x00f6de, 0x00e6b3ab}, /* U+6CEB [2000] */ - {0x00f6df, 0x00e6b3ae}, /* U+6CEE [2000] */ - {0x00f6e0, 0xf0a3b3be}, /* U+23CFE [2000] [Unicode3.1] */ - {0x00f6e1, 0x00e6b484}, /* U+6D04 [2000] */ - {0x00f6e2, 0x00e6b48e}, /* U+6D0E [2000] */ - {0x00f6e3, 0x00e6b4ae}, /* U+6D2E [2000] */ - {0x00f6e4, 0x00e6b4b1}, /* U+6D31 [2000] */ - {0x00f6e5, 0x00e6b4b9}, /* U+6D39 [2000] */ - {0x00f6e6, 0x00e6b4bf}, /* U+6D3F [2000] */ - {0x00f6e7, 0x00e6b598}, /* U+6D58 [2000] */ - {0x00f6e8, 0x00e6b5a5}, /* U+6D65 [2000] */ - {0x00f6e9, 0x00efa985}, /* U+FA45 CJK COMPATIBILITY IDEOGRAPH-FA45 [2000] [Unicode3.2] */ - {0x00f6ea, 0x00e6b682}, /* U+6D82 [2000] */ - {0x00f6eb, 0x00e6b687}, /* U+6D87 [2000] */ - {0x00f6ec, 0x00e6b689}, /* U+6D89 [2000] */ - {0x00f6ed, 0x00e6b694}, /* U+6D94 [2000] */ - {0x00f6ee, 0x00e6b6aa}, /* U+6DAA [2000] */ - {0x00f6ef, 0x00e6b6ac}, /* U+6DAC [2000] */ - {0x00f6f0, 0x00e6b6bf}, /* U+6DBF [2000] */ - {0x00f6f1, 0x00e6b784}, /* U+6DC4 [2000] */ - {0x00f6f2, 0x00e6b796}, /* U+6DD6 [2000] */ - {0x00f6f3, 0x00e6b79a}, /* U+6DDA [2000] */ - {0x00f6f4, 0x00e6b79b}, /* U+6DDB [2000] */ - {0x00f6f5, 0x00e6b79d}, /* U+6DDD [2000] */ - {0x00f6f6, 0x00e6b7bc}, /* U+6DFC [2000] */ - {0x00f6f7, 0x00efa986}, /* U+FA46 CJK COMPATIBILITY IDEOGRAPH-FA46 [2000] [Unicode3.2] */ - {0x00f6f8, 0x00e6b8b4}, /* U+6E34 [2000] */ - {0x00f6f9, 0x00e6b984}, /* U+6E44 [2000] */ - {0x00f6fa, 0x00e6b99c}, /* U+6E5C [2000] */ - {0x00f6fb, 0x00e6b99e}, /* U+6E5E [2000] */ - {0x00f6fc, 0x00e6baab}, /* U+6EAB [2000] */ - {0x00f6fd, 0x00e6bab1}, /* U+6EB1 [2000] */ - {0x00f6fe, 0x00e6bb81}, /* U+6EC1 [2000] */ - {0x00f7a1, 0x00e6bb87}, /* U+6EC7 [2000] */ - {0x00f7a2, 0x00e6bb8e}, /* U+6ECE [2000] */ - {0x00f7a3, 0x00e6bc90}, /* U+6F10 [2000] */ - {0x00f7a4, 0x00e6bc9a}, /* U+6F1A [2000] */ - {0x00f7a5, 0x00efa987}, /* U+FA47 CJK COMPATIBILITY IDEOGRAPH-FA47 [2000] [Unicode3.2] */ - {0x00f7a6, 0x00e6bcaa}, /* U+6F2A [2000] */ - {0x00f7a7, 0x00e6bcaf}, /* U+6F2F [2000] */ - {0x00f7a8, 0x00e6bcb3}, /* U+6F33 [2000] */ - {0x00f7a9, 0x00e6bd91}, /* U+6F51 [2000] */ - {0x00f7aa, 0x00e6bd99}, /* U+6F59 [2000] */ - {0x00f7ab, 0x00e6bd9e}, /* U+6F5E [2000] */ - {0x00f7ac, 0x00e6bda1}, /* U+6F61 [2000] */ - {0x00f7ad, 0x00e6bda2}, /* U+6F62 [2000] */ - {0x00f7ae, 0x00e6bdbe}, /* U+6F7E [2000] */ - {0x00f7af, 0x00e6be88}, /* U+6F88 [2000] */ - {0x00f7b0, 0x00e6be8c}, /* U+6F8C [2000] */ - {0x00f7b1, 0x00e6be8d}, /* U+6F8D [2000] */ - {0x00f7b2, 0x00e6be94}, /* U+6F94 [2000] */ - {0x00f7b3, 0x00e6bea0}, /* U+6FA0 [2000] */ - {0x00f7b4, 0x00e6bea7}, /* U+6FA7 [2000] */ - {0x00f7b5, 0x00e6beb6}, /* U+6FB6 [2000] */ - {0x00f7b6, 0x00e6bebc}, /* U+6FBC [2000] */ - {0x00f7b7, 0x00e6bf87}, /* U+6FC7 [2000] */ - {0x00f7b8, 0x00e6bf8a}, /* U+6FCA [2000] */ - {0x00f7b9, 0x00e6bfb9}, /* U+6FF9 [2000] */ - {0x00f7ba, 0x00e6bfb0}, /* U+6FF0 [2000] */ - {0x00f7bb, 0x00e6bfb5}, /* U+6FF5 [2000] */ - {0x00f7bc, 0x00e78085}, /* U+7005 [2000] */ - {0x00f7bd, 0x00e78086}, /* U+7006 [2000] */ - {0x00f7be, 0x00e780a8}, /* U+7028 [2000] */ - {0x00f7bf, 0x00e7818a}, /* U+704A [2000] */ - {0x00f7c0, 0x00e7819d}, /* U+705D [2000] */ - {0x00f7c1, 0x00e7819e}, /* U+705E [2000] */ - {0x00f7c2, 0x00e7818e}, /* U+704E [2000] */ - {0x00f7c3, 0x00e781a4}, /* U+7064 [2000] */ - {0x00f7c4, 0x00e781b5}, /* U+7075 [2000] */ - {0x00f7c5, 0x00e78285}, /* U+7085 [2000] */ - {0x00f7c6, 0x00e782a4}, /* U+70A4 [2000] */ - {0x00f7c7, 0x00e782ab}, /* U+70AB [2000] */ - {0x00f7c8, 0x00e782b7}, /* U+70B7 [2000] */ - {0x00f7c9, 0x00e78394}, /* U+70D4 [2000] */ - {0x00f7ca, 0x00e78398}, /* U+70D8 [2000] */ - {0x00f7cb, 0x00e783a4}, /* U+70E4 [2000] */ - {0x00f7cc, 0x00e7848f}, /* U+710F [2000] */ - {0x00f7cd, 0x00e784ab}, /* U+712B [2000] */ - {0x00f7ce, 0x00e7849e}, /* U+711E [2000] */ - {0x00f7cf, 0x00e784a0}, /* U+7120 [2000] */ - {0x00f7d0, 0x00e784ae}, /* U+712E [2000] */ - {0x00f7d1, 0x00e784b0}, /* U+7130 [2000] */ - {0x00f7d2, 0x00e78586}, /* U+7146 [2000] */ - {0x00f7d3, 0x00e78587}, /* U+7147 [2000] */ - {0x00f7d4, 0x00e78591}, /* U+7151 [2000] */ - {0x00f7d5, 0x00efa988}, /* U+FA48 CJK COMPATIBILITY IDEOGRAPH-FA48 [2000] [Unicode3.2] */ - {0x00f7d6, 0x00e78592}, /* U+7152 [2000] */ - {0x00f7d7, 0x00e7859c}, /* U+715C [2000] */ - {0x00f7d8, 0x00e785a0}, /* U+7160 [2000] */ - {0x00f7d9, 0x00e785a8}, /* U+7168 [2000] */ - {0x00f7da, 0x00efa895}, /* U+FA15 CJK COMPATIBILITY IDEOGRAPH-FA15 [2000] */ - {0x00f7db, 0x00e78685}, /* U+7185 [2000] */ - {0x00f7dc, 0x00e78687}, /* U+7187 [2000] */ - {0x00f7dd, 0x00e78692}, /* U+7192 [2000] */ - {0x00f7de, 0x00e78781}, /* U+71C1 [2000] */ - {0x00f7df, 0x00e786ba}, /* U+71BA [2000] */ - {0x00f7e0, 0x00e78784}, /* U+71C4 [2000] */ - {0x00f7e1, 0x00e787be}, /* U+71FE [2000] */ - {0x00f7e2, 0x00e78880}, /* U+7200 [2000] */ - {0x00f7e3, 0x00e78895}, /* U+7215 [2000] */ - {0x00f7e4, 0x00e78995}, /* U+7255 [2000] */ - {0x00f7e5, 0x00e78996}, /* U+7256 [2000] */ - {0x00f7e6, 0x00e3b8bf}, /* U+3E3F [2000] */ - {0x00f7e7, 0x00e78a8d}, /* U+728D [2000] */ - {0x00f7e8, 0x00e78a9b}, /* U+729B [2000] */ - {0x00f7e9, 0x00e78abe}, /* U+72BE [2000] */ - {0x00f7ea, 0x00e78b80}, /* U+72C0 [2000] */ - {0x00f7eb, 0x00e78bbb}, /* U+72FB [2000] */ - {0x00f7ec, 0xf0a49fb1}, /* U+247F1 [2000] [Unicode3.1] */ - {0x00f7ed, 0x00e78ca7}, /* U+7327 [2000] */ - {0x00f7ee, 0x00e78ca8}, /* U+7328 [2000] */ - {0x00f7ef, 0x00efa896}, /* U+FA16 CJK COMPATIBILITY IDEOGRAPH-FA16 [2000] */ - {0x00f7f0, 0x00e78d90}, /* U+7350 [2000] */ - {0x00f7f1, 0x00e78da6}, /* U+7366 [2000] */ - {0x00f7f2, 0x00e78dbc}, /* U+737C [2000] */ - {0x00f7f3, 0x00e78e95}, /* U+7395 [2000] */ - {0x00f7f4, 0x00e78e9f}, /* U+739F [2000] */ - {0x00f7f5, 0x00e78ea0}, /* U+73A0 [2000] */ - {0x00f7f6, 0x00e78ea2}, /* U+73A2 [2000] */ - {0x00f7f7, 0x00e78ea6}, /* U+73A6 [2000] */ - {0x00f7f8, 0x00e78eab}, /* U+73AB [2000] */ - {0x00f7f9, 0x00e78f89}, /* U+73C9 [2000] */ - {0x00f7fa, 0x00e78f8f}, /* U+73CF [2000] */ - {0x00f7fb, 0x00e78f96}, /* U+73D6 [2000] */ - {0x00f7fc, 0x00e78f99}, /* U+73D9 [2000] */ - {0x00f7fd, 0x00e78fa3}, /* U+73E3 [2000] */ - {0x00f7fe, 0x00e78fa9}, /* U+73E9 [2000] */ - {0x00f8a1, 0x00e79087}, /* U+7407 [2000] */ - {0x00f8a2, 0x00e7908a}, /* U+740A [2000] */ - {0x00f8a3, 0x00e7909a}, /* U+741A [2000] */ - {0x00f8a4, 0x00e7909b}, /* U+741B [2000] */ - {0x00f8a5, 0x00efa98a}, /* U+FA4A CJK COMPATIBILITY IDEOGRAPH-FA4A [2000] [Unicode3.2] */ - {0x00f8a6, 0x00e790a6}, /* U+7426 [2000] */ - {0x00f8a7, 0x00e790a8}, /* U+7428 [2000] */ - {0x00f8a8, 0x00e790aa}, /* U+742A [2000] */ - {0x00f8a9, 0x00e790ab}, /* U+742B [2000] */ - {0x00f8aa, 0x00e790ac}, /* U+742C [2000] */ - {0x00f8ab, 0x00e790ae}, /* U+742E [2000] */ - {0x00f8ac, 0x00e790af}, /* U+742F [2000] */ - {0x00f8ad, 0x00e790b0}, /* U+7430 [2000] */ - {0x00f8ae, 0x00e79184}, /* U+7444 [2000] */ - {0x00f8af, 0x00e79186}, /* U+7446 [2000] */ - {0x00f8b0, 0x00e79187}, /* U+7447 [2000] */ - {0x00f8b1, 0x00e7918b}, /* U+744B [2000] */ - {0x00f8b2, 0x00e79197}, /* U+7457 [2000] */ - {0x00f8b3, 0x00e791a2}, /* U+7462 [2000] */ - {0x00f8b4, 0x00e791ab}, /* U+746B [2000] */ - {0x00f8b5, 0x00e791ad}, /* U+746D [2000] */ - {0x00f8b6, 0x00e79286}, /* U+7486 [2000] */ - {0x00f8b7, 0x00e79287}, /* U+7487 [2000] */ - {0x00f8b8, 0x00e79289}, /* U+7489 [2000] */ - {0x00f8b9, 0x00e79298}, /* U+7498 [2000] */ - {0x00f8ba, 0x00e7929c}, /* U+749C [2000] */ - {0x00f8bb, 0x00e7929f}, /* U+749F [2000] */ - {0x00f8bc, 0x00e792a3}, /* U+74A3 [2000] */ - {0x00f8bd, 0x00e79290}, /* U+7490 [2000] */ - {0x00f8be, 0x00e792a6}, /* U+74A6 [2000] */ - {0x00f8bf, 0x00e792a8}, /* U+74A8 [2000] */ - {0x00f8c0, 0x00e792a9}, /* U+74A9 [2000] */ - {0x00f8c1, 0x00e792b5}, /* U+74B5 [2000] */ - {0x00f8c2, 0x00e792bf}, /* U+74BF [2000] */ - {0x00f8c3, 0x00e79388}, /* U+74C8 [2000] */ - {0x00f8c4, 0x00e79389}, /* U+74C9 [2000] */ - {0x00f8c5, 0x00e7939a}, /* U+74DA [2000] */ - {0x00f8c6, 0x00e793bf}, /* U+74FF [2000] */ - {0x00f8c7, 0x00e79481}, /* U+7501 [2000] */ - {0x00f8c8, 0x00e79497}, /* U+7517 [2000] */ - {0x00f8c9, 0x00e794af}, /* U+752F [2000] */ - {0x00f8ca, 0x00e795af}, /* U+756F [2000] */ - {0x00f8cb, 0x00e795b9}, /* U+7579 [2000] */ - {0x00f8cc, 0x00e79692}, /* U+7592 [2000] */ - {0x00f8cd, 0x00e3bdb2}, /* U+3F72 [2000] */ - {0x00f8ce, 0x00e7978e}, /* U+75CE [2000] */ - {0x00f8cf, 0x00e797a4}, /* U+75E4 [2000] */ - {0x00f8d0, 0x00e79880}, /* U+7600 [2000] */ - {0x00f8d1, 0x00e79882}, /* U+7602 [2000] */ - {0x00f8d2, 0x00e79888}, /* U+7608 [2000] */ - {0x00f8d3, 0x00e79895}, /* U+7615 [2000] */ - {0x00f8d4, 0x00e79896}, /* U+7616 [2000] */ - {0x00f8d5, 0x00e79899}, /* U+7619 [2000] */ - {0x00f8d6, 0x00e7989e}, /* U+761E [2000] */ - {0x00f8d7, 0x00e798ad}, /* U+762D [2000] */ - {0x00f8d8, 0x00e798b5}, /* U+7635 [2000] */ - {0x00f8d9, 0x00e79983}, /* U+7643 [2000] */ - {0x00f8da, 0x00e7998b}, /* U+764B [2000] */ - {0x00f8db, 0x00e799a4}, /* U+7664 [2000] */ - {0x00f8dc, 0x00e799a5}, /* U+7665 [2000] */ - {0x00f8dd, 0x00e799ad}, /* U+766D [2000] */ - {0x00f8de, 0x00e799af}, /* U+766F [2000] */ - {0x00f8df, 0x00e799b1}, /* U+7671 [2000] */ - {0x00f8e0, 0x00e79a81}, /* U+7681 [2000] */ - {0x00f8e1, 0x00e79a9b}, /* U+769B [2000] */ - {0x00f8e2, 0x00e79a9d}, /* U+769D [2000] */ - {0x00f8e3, 0x00e79a9e}, /* U+769E [2000] */ - {0x00f8e4, 0x00e79aa6}, /* U+76A6 [2000] */ - {0x00f8e5, 0x00e79aaa}, /* U+76AA [2000] */ - {0x00f8e6, 0x00e79ab6}, /* U+76B6 [2000] */ - {0x00f8e7, 0x00e79b85}, /* U+76C5 [2000] */ - {0x00f8e8, 0x00e79b8c}, /* U+76CC [2000] */ - {0x00f8e9, 0x00e79b8e}, /* U+76CE [2000] */ - {0x00f8ea, 0x00e79b94}, /* U+76D4 [2000] */ - {0x00f8eb, 0x00e79ba6}, /* U+76E6 [2000] */ - {0x00f8ec, 0x00e79bb1}, /* U+76F1 [2000] */ - {0x00f8ed, 0x00e79bbc}, /* U+76FC [2000] */ - {0x00f8ee, 0x00e79c8a}, /* U+770A [2000] */ - {0x00f8ef, 0x00e79c99}, /* U+7719 [2000] */ - {0x00f8f0, 0x00e79cb4}, /* U+7734 [2000] */ - {0x00f8f1, 0x00e79cb6}, /* U+7736 [2000] */ - {0x00f8f2, 0x00e79d86}, /* U+7746 [2000] */ - {0x00f8f3, 0x00e79d8d}, /* U+774D [2000] */ - {0x00f8f4, 0x00e79d8e}, /* U+774E [2000] */ - {0x00f8f5, 0x00e79d9c}, /* U+775C [2000] */ - {0x00f8f6, 0x00e79d9f}, /* U+775F [2000] */ - {0x00f8f7, 0x00e79da2}, /* U+7762 [2000] */ - {0x00f8f8, 0x00e79dba}, /* U+777A [2000] */ - {0x00f8f9, 0x00e79e80}, /* U+7780 [2000] */ - {0x00f8fa, 0x00e79e94}, /* U+7794 [2000] */ - {0x00f8fb, 0x00e79eaa}, /* U+77AA [2000] */ - {0x00f8fc, 0x00e79fa0}, /* U+77E0 [2000] */ - {0x00f8fd, 0x00e7a0ad}, /* U+782D [2000] */ - {0x00f8fe, 0xf0a5928e}, /* U+2548E [2000] [Unicode3.1] */ - {0x00f9a1, 0x00e7a183}, /* U+7843 [2000] */ - {0x00f9a2, 0x00e7a18e}, /* U+784E [2000] */ - {0x00f9a3, 0x00e7a18f}, /* U+784F [2000] */ - {0x00f9a4, 0x00e7a191}, /* U+7851 [2000] */ - {0x00f9a5, 0x00e7a1a8}, /* U+7868 [2000] */ - {0x00f9a6, 0x00e7a1ae}, /* U+786E [2000] */ - {0x00f9a7, 0x00efa98b}, /* U+FA4B CJK COMPATIBILITY IDEOGRAPH-FA4B [2000] [Unicode3.2] */ - {0x00f9a8, 0x00e7a2b0}, /* U+78B0 [2000] */ - {0x00f9a9, 0xf0a5948e}, /* U+2550E [2000] [Unicode3.1] */ - {0x00f9aa, 0x00e7a2ad}, /* U+78AD [2000] */ - {0x00f9ab, 0x00e7a3a4}, /* U+78E4 [2000] */ - {0x00f9ac, 0x00e7a3b2}, /* U+78F2 [2000] */ - {0x00f9ad, 0x00e7a480}, /* U+7900 [2000] */ - {0x00f9ae, 0x00e7a3b7}, /* U+78F7 [2000] */ - {0x00f9af, 0x00e7a49c}, /* U+791C [2000] */ - {0x00f9b0, 0x00e7a4ae}, /* U+792E [2000] */ - {0x00f9b1, 0x00e7a4b1}, /* U+7931 [2000] */ - {0x00f9b2, 0x00e7a4b4}, /* U+7934 [2000] */ - {0x00f9b3, 0x00efa98c}, /* U+FA4C CJK COMPATIBILITY IDEOGRAPH-FA4C [2000] [Unicode3.2] */ - {0x00f9b4, 0x00efa98d}, /* U+FA4D CJK COMPATIBILITY IDEOGRAPH-FA4D [2000] [Unicode3.2] */ - {0x00f9b5, 0x00e7a585}, /* U+7945 [2000] */ - {0x00f9b6, 0x00e7a586}, /* U+7946 [2000] */ - {0x00f9b7, 0x00efa98e}, /* U+FA4E CJK COMPATIBILITY IDEOGRAPH-FA4E [2000] [Unicode3.2] */ - {0x00f9b8, 0x00efa98f}, /* U+FA4F CJK COMPATIBILITY IDEOGRAPH-FA4F [2000] [Unicode3.2] */ - {0x00f9b9, 0x00efa990}, /* U+FA50 CJK COMPATIBILITY IDEOGRAPH-FA50 [2000] [Unicode3.2] */ - {0x00f9ba, 0x00e7a59c}, /* U+795C [2000] */ - {0x00f9bb, 0x00efa991}, /* U+FA51 CJK COMPATIBILITY IDEOGRAPH-FA51 [2000] [Unicode3.2] */ - {0x00f9bc, 0x00efa899}, /* U+FA19 CJK COMPATIBILITY IDEOGRAPH-FA19 [2000] */ - {0x00f9bd, 0x00efa89a}, /* U+FA1A CJK COMPATIBILITY IDEOGRAPH-FA1A [2000] */ - {0x00f9be, 0x00e7a5b9}, /* U+7979 [2000] */ - {0x00f9bf, 0x00efa992}, /* U+FA52 CJK COMPATIBILITY IDEOGRAPH-FA52 [2000] [Unicode3.2] */ - {0x00f9c0, 0x00efa993}, /* U+FA53 CJK COMPATIBILITY IDEOGRAPH-FA53 [2000] [Unicode3.2] */ - {0x00f9c1, 0x00efa89b}, /* U+FA1B CJK COMPATIBILITY IDEOGRAPH-FA1B [2000] */ - {0x00f9c2, 0x00e7a698}, /* U+7998 [2000] */ - {0x00f9c3, 0x00e7a6b1}, /* U+79B1 [2000] */ - {0x00f9c4, 0x00e7a6b8}, /* U+79B8 [2000] */ - {0x00f9c5, 0x00e7a788}, /* U+79C8 [2000] */ - {0x00f9c6, 0x00e7a78a}, /* U+79CA [2000] */ - {0x00f9c7, 0xf0a59db1}, /* U+25771 [2000] [Unicode3.1] */ - {0x00f9c8, 0x00e7a794}, /* U+79D4 [2000] */ - {0x00f9c9, 0x00e7a79e}, /* U+79DE [2000] */ - {0x00f9ca, 0x00e7a7ab}, /* U+79EB [2000] */ - {0x00f9cb, 0x00e7a7ad}, /* U+79ED [2000] */ - {0x00f9cc, 0x00e7a883}, /* U+7A03 [2000] */ - {0x00f9cd, 0x00efa994}, /* U+FA54 CJK COMPATIBILITY IDEOGRAPH-FA54 [2000] [Unicode3.2] */ - {0x00f9ce, 0x00e7a8b9}, /* U+7A39 [2000] */ - {0x00f9cf, 0x00e7a99d}, /* U+7A5D [2000] */ - {0x00f9d0, 0x00e7a9ad}, /* U+7A6D [2000] */ - {0x00f9d1, 0x00efa995}, /* U+FA55 CJK COMPATIBILITY IDEOGRAPH-FA55 [2000] [Unicode3.2] */ - {0x00f9d2, 0x00e7aa85}, /* U+7A85 [2000] */ - {0x00f9d3, 0x00e7aaa0}, /* U+7AA0 [2000] */ - {0x00f9d4, 0xf0a5a784}, /* U+259C4 [2000] [Unicode3.1] */ - {0x00f9d5, 0x00e7aab3}, /* U+7AB3 [2000] */ - {0x00f9d6, 0x00e7aabb}, /* U+7ABB [2000] */ - {0x00f9d7, 0x00e7ab8e}, /* U+7ACE [2000] */ - {0x00f9d8, 0x00e7abab}, /* U+7AEB [2000] */ - {0x00f9d9, 0x00e7abbd}, /* U+7AFD [2000] */ - {0x00f9da, 0x00e7ac92}, /* U+7B12 [2000] */ - {0x00f9db, 0x00e7acad}, /* U+7B2D [2000] */ - {0x00f9dc, 0x00e7acbb}, /* U+7B3B [2000] */ - {0x00f9dd, 0x00e7ad87}, /* U+7B47 [2000] */ - {0x00f9de, 0x00e7ad8e}, /* U+7B4E [2000] */ - {0x00f9df, 0x00e7ada0}, /* U+7B60 [2000] */ - {0x00f9e0, 0x00e7adad}, /* U+7B6D [2000] */ - {0x00f9e1, 0x00e7adaf}, /* U+7B6F [2000] */ - {0x00f9e2, 0x00e7adb2}, /* U+7B72 [2000] */ - {0x00f9e3, 0x00e7ae9e}, /* U+7B9E [2000] */ - {0x00f9e4, 0x00efa996}, /* U+FA56 CJK COMPATIBILITY IDEOGRAPH-FA56 [2000] [Unicode3.2] */ - {0x00f9e5, 0x00e7af97}, /* U+7BD7 [2000] */ - {0x00f9e6, 0x00e7af99}, /* U+7BD9 [2000] */ - {0x00f9e7, 0x00e7b081}, /* U+7C01 [2000] */ - {0x00f9e8, 0x00e7b0b1}, /* U+7C31 [2000] */ - {0x00f9e9, 0x00e7b09e}, /* U+7C1E [2000] */ - {0x00f9ea, 0x00e7b0a0}, /* U+7C20 [2000] */ - {0x00f9eb, 0x00e7b0b3}, /* U+7C33 [2000] */ - {0x00f9ec, 0x00e7b0b6}, /* U+7C36 [2000] */ - {0x00f9ed, 0x00e489a4}, /* U+4264 [2000] */ - {0x00f9ee, 0xf0a5b6a1}, /* U+25DA1 [2000] [Unicode3.1] */ - {0x00f9ef, 0x00e7b199}, /* U+7C59 [2000] */ - {0x00f9f0, 0x00e7b1ad}, /* U+7C6D [2000] */ - {0x00f9f1, 0x00e7b1b9}, /* U+7C79 [2000] */ - {0x00f9f2, 0x00e7b28f}, /* U+7C8F [2000] */ - {0x00f9f3, 0x00e7b294}, /* U+7C94 [2000] */ - {0x00f9f4, 0x00e7b2a0}, /* U+7CA0 [2000] */ - {0x00f9f5, 0x00e7b2bc}, /* U+7CBC [2000] */ - {0x00f9f6, 0x00e7b395}, /* U+7CD5 [2000] */ - {0x00f9f7, 0x00e7b399}, /* U+7CD9 [2000] */ - {0x00f9f8, 0x00e7b39d}, /* U+7CDD [2000] */ - {0x00f9f9, 0x00e7b487}, /* U+7D07 [2000] */ - {0x00f9fa, 0x00e7b488}, /* U+7D08 [2000] */ - {0x00f9fb, 0x00e7b493}, /* U+7D13 [2000] */ - {0x00f9fc, 0x00e7b49d}, /* U+7D1D [2000] */ - {0x00f9fd, 0x00e7b4a3}, /* U+7D23 [2000] */ - {0x00f9fe, 0x00e7b4b1}, /* U+7D31 [2000] */ - {0x00faa1, 0x00e7b581}, /* U+7D41 [2000] */ - {0x00faa2, 0x00e7b588}, /* U+7D48 [2000] */ - {0x00faa3, 0x00e7b593}, /* U+7D53 [2000] */ - {0x00faa4, 0x00e7b59c}, /* U+7D5C [2000] */ - {0x00faa5, 0x00e7b5ba}, /* U+7D7A [2000] */ - {0x00faa6, 0x00e7b683}, /* U+7D83 [2000] */ - {0x00faa7, 0x00e7b68b}, /* U+7D8B [2000] */ - {0x00faa8, 0x00e7b6a0}, /* U+7DA0 [2000] */ - {0x00faa9, 0x00e7b6a6}, /* U+7DA6 [2000] */ - {0x00faaa, 0x00e7b782}, /* U+7DC2 [2000] */ - {0x00faab, 0x00e7b78c}, /* U+7DCC [2000] */ - {0x00faac, 0x00e7b796}, /* U+7DD6 [2000] */ - {0x00faad, 0x00e7b7a3}, /* U+7DE3 [2000] */ - {0x00faae, 0x00efa997}, /* U+FA57 CJK COMPATIBILITY IDEOGRAPH-FA57 [2000] [Unicode3.2] */ - {0x00faaf, 0x00e7b8a8}, /* U+7E28 [2000] */ - {0x00fab0, 0x00e7b888}, /* U+7E08 [2000] */ - {0x00fab1, 0x00e7b891}, /* U+7E11 [2000] */ - {0x00fab2, 0x00e7b895}, /* U+7E15 [2000] */ - {0x00fab3, 0x00efa999}, /* U+FA59 CJK COMPATIBILITY IDEOGRAPH-FA59 [2000] [Unicode3.2] */ - {0x00fab4, 0x00e7b987}, /* U+7E47 [2000] */ - {0x00fab5, 0x00e7b992}, /* U+7E52 [2000] */ - {0x00fab6, 0x00e7b9a1}, /* U+7E61 [2000] */ - {0x00fab7, 0x00e7ba8a}, /* U+7E8A [2000] */ - {0x00fab8, 0x00e7ba8d}, /* U+7E8D [2000] */ - {0x00fab9, 0x00e7bd87}, /* U+7F47 [2000] */ - {0x00faba, 0x00efa99a}, /* U+FA5A CJK COMPATIBILITY IDEOGRAPH-FA5A [2000] [Unicode3.2] */ - {0x00fabb, 0x00e7be91}, /* U+7F91 [2000] */ - {0x00fabc, 0x00e7be97}, /* U+7F97 [2000] */ - {0x00fabd, 0x00e7bebf}, /* U+7FBF [2000] */ - {0x00fabe, 0x00e7bf8e}, /* U+7FCE [2000] */ - {0x00fabf, 0x00e7bf9b}, /* U+7FDB [2000] */ - {0x00fac0, 0x00e7bf9f}, /* U+7FDF [2000] */ - {0x00fac1, 0x00e7bfac}, /* U+7FEC [2000] */ - {0x00fac2, 0x00e7bfae}, /* U+7FEE [2000] */ - {0x00fac3, 0x00e7bfba}, /* U+7FFA [2000] */ - {0x00fac4, 0x00efa99b}, /* U+FA5B CJK COMPATIBILITY IDEOGRAPH-FA5B [2000] [Unicode3.2] */ - {0x00fac5, 0x00e88094}, /* U+8014 [2000] */ - {0x00fac6, 0x00e880a6}, /* U+8026 [2000] */ - {0x00fac7, 0x00e880b5}, /* U+8035 [2000] */ - {0x00fac8, 0x00e880b7}, /* U+8037 [2000] */ - {0x00fac9, 0x00e880bc}, /* U+803C [2000] */ - {0x00faca, 0x00e8838a}, /* U+80CA [2000] */ - {0x00facb, 0x00e88397}, /* U+80D7 [2000] */ - {0x00facc, 0x00e883a0}, /* U+80E0 [2000] */ - {0x00facd, 0x00e883b3}, /* U+80F3 [2000] */ - {0x00face, 0x00e88498}, /* U+8118 [2000] */ - {0x00facf, 0x00e8858a}, /* U+814A [2000] */ - {0x00fad0, 0x00e885a0}, /* U+8160 [2000] */ - {0x00fad1, 0x00e885a7}, /* U+8167 [2000] */ - {0x00fad2, 0x00e885a8}, /* U+8168 [2000] */ - {0x00fad3, 0x00e885ad}, /* U+816D [2000] */ - {0x00fad4, 0x00e886bb}, /* U+81BB [2000] */ - {0x00fad5, 0x00e8878a}, /* U+81CA [2000] */ - {0x00fad6, 0x00e8878f}, /* U+81CF [2000] */ - {0x00fad7, 0x00e88797}, /* U+81D7 [2000] */ - {0x00fad8, 0x00efa99c}, /* U+FA5C CJK COMPATIBILITY IDEOGRAPH-FA5C [2000] [Unicode3.2] */ - {0x00fad9, 0x00e49193}, /* U+4453 [2000] */ - {0x00fada, 0x00e4919b}, /* U+445B [2000] */ - {0x00fadb, 0x00e889a0}, /* U+8260 [2000] */ - {0x00fadc, 0x00e889b4}, /* U+8274 [2000] */ - {0x00fadd, 0xf0a6abbf}, /* U+26AFF [2000] [Unicode3.1] */ - {0x00fade, 0x00e88a8e}, /* U+828E [2000] */ - {0x00fadf, 0x00e88aa1}, /* U+82A1 [2000] */ - {0x00fae0, 0x00e88aa3}, /* U+82A3 [2000] */ - {0x00fae1, 0x00e88aa4}, /* U+82A4 [2000] */ - {0x00fae2, 0x00e88aa9}, /* U+82A9 [2000] */ - {0x00fae3, 0x00e88aae}, /* U+82AE [2000] */ - {0x00fae4, 0x00e88ab7}, /* U+82B7 [2000] */ - {0x00fae5, 0x00e88abe}, /* U+82BE [2000] */ - {0x00fae6, 0x00e88abf}, /* U+82BF [2000] */ - {0x00fae7, 0x00e88b86}, /* U+82C6 [2000] */ - {0x00fae8, 0x00e88b95}, /* U+82D5 [2000] */ - {0x00fae9, 0x00e88bbd}, /* U+82FD [2000] */ - {0x00faea, 0x00e88bbe}, /* U+82FE [2000] */ - {0x00faeb, 0x00e88c80}, /* U+8300 [2000] */ - {0x00faec, 0x00e88c81}, /* U+8301 [2000] */ - {0x00faed, 0x00e88da2}, /* U+8362 [2000] */ - {0x00faee, 0x00e88ca2}, /* U+8322 [2000] */ - {0x00faef, 0x00e88cad}, /* U+832D [2000] */ - {0x00faf0, 0x00e88cba}, /* U+833A [2000] */ - {0x00faf1, 0x00e88d83}, /* U+8343 [2000] */ - {0x00faf2, 0x00e88d87}, /* U+8347 [2000] */ - {0x00faf3, 0x00e88d91}, /* U+8351 [2000] */ - {0x00faf4, 0x00e88d95}, /* U+8355 [2000] */ - {0x00faf5, 0x00e88dbd}, /* U+837D [2000] */ - {0x00faf6, 0x00e88e86}, /* U+8386 [2000] */ - {0x00faf7, 0x00e88e92}, /* U+8392 [2000] */ - {0x00faf8, 0x00e88e98}, /* U+8398 [2000] */ - {0x00faf9, 0x00e88ea7}, /* U+83A7 [2000] */ - {0x00fafa, 0x00e88ea9}, /* U+83A9 [2000] */ - {0x00fafb, 0x00e88ebf}, /* U+83BF [2000] */ - {0x00fafc, 0x00e88f80}, /* U+83C0 [2000] */ - {0x00fafd, 0x00e88f87}, /* U+83C7 [2000] */ - {0x00fafe, 0x00e88f8f}, /* U+83CF [2000] */ - {0x00fba1, 0x00e88f91}, /* U+83D1 [2000] */ - {0x00fba2, 0x00e88fa1}, /* U+83E1 [2000] */ - {0x00fba3, 0x00e88faa}, /* U+83EA [2000] */ - {0x00fba4, 0x00e89081}, /* U+8401 [2000] */ - {0x00fba5, 0x00e89086}, /* U+8406 [2000] */ - {0x00fba6, 0x00e8908a}, /* U+840A [2000] */ - {0x00fba7, 0x00efa99f}, /* U+FA5F CJK COMPATIBILITY IDEOGRAPH-FA5F [2000] [Unicode3.2] */ - {0x00fba8, 0x00e89188}, /* U+8448 [2000] */ - {0x00fba9, 0x00e8919f}, /* U+845F [2000] */ - {0x00fbaa, 0x00e891b0}, /* U+8470 [2000] */ - {0x00fbab, 0x00e891b3}, /* U+8473 [2000] */ - {0x00fbac, 0x00e89285}, /* U+8485 [2000] */ - {0x00fbad, 0x00e8929e}, /* U+849E [2000] */ - {0x00fbae, 0x00e892af}, /* U+84AF [2000] */ - {0x00fbaf, 0x00e892b4}, /* U+84B4 [2000] */ - {0x00fbb0, 0x00e892ba}, /* U+84BA [2000] */ - {0x00fbb1, 0x00e89380}, /* U+84C0 [2000] */ - {0x00fbb2, 0x00e89382}, /* U+84C2 [2000] */ - {0x00fbb3, 0xf0a6b980}, /* U+26E40 [2000] [Unicode3.1] */ - {0x00fbb4, 0x00e894b2}, /* U+8532 [2000] */ - {0x00fbb5, 0x00e8949e}, /* U+851E [2000] */ - {0x00fbb6, 0x00e894a3}, /* U+8523 [2000] */ - {0x00fbb7, 0x00e894af}, /* U+852F [2000] */ - {0x00fbb8, 0x00e89599}, /* U+8559 [2000] */ - {0x00fbb9, 0x00e895a4}, /* U+8564 [2000] */ - {0x00fbba, 0x00efa89f}, /* U+FA1F CJK COMPATIBILITY IDEOGRAPH-FA1F [2000] */ - {0x00fbbb, 0x00e896ad}, /* U+85AD [2000] */ - {0x00fbbc, 0x00e895ba}, /* U+857A [2000] */ - {0x00fbbd, 0x00e8968c}, /* U+858C [2000] */ - {0x00fbbe, 0x00e8968f}, /* U+858F [2000] */ - {0x00fbbf, 0x00e896a2}, /* U+85A2 [2000] */ - {0x00fbc0, 0x00e896b0}, /* U+85B0 [2000] */ - {0x00fbc1, 0x00e8978b}, /* U+85CB [2000] */ - {0x00fbc2, 0x00e8978e}, /* U+85CE [2000] */ - {0x00fbc3, 0x00e897ad}, /* U+85ED [2000] */ - {0x00fbc4, 0x00e89892}, /* U+8612 [2000] */ - {0x00fbc5, 0x00e897bf}, /* U+85FF [2000] */ - {0x00fbc6, 0x00e89884}, /* U+8604 [2000] */ - {0x00fbc7, 0x00e89885}, /* U+8605 [2000] */ - {0x00fbc8, 0x00e89890}, /* U+8610 [2000] */ - {0x00fbc9, 0xf0a783b4}, /* U+270F4 [2000] [Unicode3.1] */ - {0x00fbca, 0x00e89898}, /* U+8618 [2000] */ - {0x00fbcb, 0x00e898a9}, /* U+8629 [2000] */ - {0x00fbcc, 0x00e898b8}, /* U+8638 [2000] */ - {0x00fbcd, 0x00e89997}, /* U+8657 [2000] */ - {0x00fbce, 0x00e8999b}, /* U+865B [2000] */ - {0x00fbcf, 0x00efa4b6}, /* U+F936 CJK COMPATIBILITY IDEOGRAPH-F936 [2000] */ - {0x00fbd0, 0x00e899a2}, /* U+8662 [2000] */ - {0x00fbd1, 0x00e4969d}, /* U+459D [2000] */ - {0x00fbd2, 0x00e899ac}, /* U+866C [2000] */ - {0x00fbd3, 0x00e899b5}, /* U+8675 [2000] */ - {0x00fbd4, 0x00e89a98}, /* U+8698 [2000] */ - {0x00fbd5, 0x00e89ab8}, /* U+86B8 [2000] */ - {0x00fbd6, 0x00e89bba}, /* U+86FA [2000] */ - {0x00fbd7, 0x00e89bbc}, /* U+86FC [2000] */ - {0x00fbd8, 0x00e89bbd}, /* U+86FD [2000] */ - {0x00fbd9, 0x00e89c8b}, /* U+870B [2000] */ - {0x00fbda, 0x00e89db1}, /* U+8771 [2000] */ - {0x00fbdb, 0x00e89e87}, /* U+8787 [2000] */ - {0x00fbdc, 0x00e89e88}, /* U+8788 [2000] */ - {0x00fbdd, 0x00e89eac}, /* U+87AC [2000] */ - {0x00fbde, 0x00e89ead}, /* U+87AD [2000] */ - {0x00fbdf, 0x00e89eb5}, /* U+87B5 [2000] */ - {0x00fbe0, 0x00e497aa}, /* U+45EA [2000] */ - {0x00fbe1, 0x00e89f96}, /* U+87D6 [2000] */ - {0x00fbe2, 0x00e89fac}, /* U+87EC [2000] */ - {0x00fbe3, 0x00e8a086}, /* U+8806 [2000] */ - {0x00fbe4, 0x00e8a08a}, /* U+880A [2000] */ - {0x00fbe5, 0x00e8a090}, /* U+8810 [2000] */ - {0x00fbe6, 0x00e8a094}, /* U+8814 [2000] */ - {0x00fbe7, 0x00e8a09f}, /* U+881F [2000] */ - {0x00fbe8, 0x00e8a298}, /* U+8898 [2000] */ - {0x00fbe9, 0x00e8a2aa}, /* U+88AA [2000] */ - {0x00fbea, 0x00e8a38a}, /* U+88CA [2000] */ - {0x00fbeb, 0x00e8a38e}, /* U+88CE [2000] */ - {0x00fbec, 0xf0a79a84}, /* U+27684 [2000] [Unicode3.1] */ - {0x00fbed, 0x00e8a3b5}, /* U+88F5 [2000] */ - {0x00fbee, 0x00e8a49c}, /* U+891C [2000] */ - {0x00fbef, 0x00efa9a0}, /* U+FA60 CJK COMPATIBILITY IDEOGRAPH-FA60 [2000] [Unicode3.2] */ - {0x00fbf0, 0x00e8a498}, /* U+8918 [2000] */ - {0x00fbf1, 0x00e8a499}, /* U+8919 [2000] */ - {0x00fbf2, 0x00e8a49a}, /* U+891A [2000] */ - {0x00fbf3, 0x00e8a4a7}, /* U+8927 [2000] */ - {0x00fbf4, 0x00e8a4b0}, /* U+8930 [2000] */ - {0x00fbf5, 0x00e8a4b2}, /* U+8932 [2000] */ - {0x00fbf6, 0x00e8a4b9}, /* U+8939 [2000] */ - {0x00fbf7, 0x00e8a580}, /* U+8940 [2000] */ - {0x00fbf8, 0x00e8a694}, /* U+8994 [2000] */ - {0x00fbf9, 0x00efa9a1}, /* U+FA61 CJK COMPATIBILITY IDEOGRAPH-FA61 [2000] [Unicode3.2] */ - {0x00fbfa, 0x00e8a794}, /* U+89D4 [2000] */ - {0x00fbfb, 0x00e8a7a5}, /* U+89E5 [2000] */ - {0x00fbfc, 0x00e8a7b6}, /* U+89F6 [2000] */ - {0x00fbfd, 0x00e8a892}, /* U+8A12 [2000] */ - {0x00fbfe, 0x00e8a895}, /* U+8A15 [2000] */ - {0x00fca1, 0x00e8a8a2}, /* U+8A22 [2000] */ - {0x00fca2, 0x00e8a8b7}, /* U+8A37 [2000] */ - {0x00fca3, 0x00e8a987}, /* U+8A47 [2000] */ - {0x00fca4, 0x00e8a98e}, /* U+8A4E [2000] */ - {0x00fca5, 0x00e8a99d}, /* U+8A5D [2000] */ - {0x00fca6, 0x00e8a9a1}, /* U+8A61 [2000] */ - {0x00fca7, 0x00e8a9b5}, /* U+8A75 [2000] */ - {0x00fca8, 0x00e8a9b9}, /* U+8A79 [2000] */ - {0x00fca9, 0x00e8aaa7}, /* U+8AA7 [2000] */ - {0x00fcaa, 0x00e8ab90}, /* U+8AD0 [2000] */ - {0x00fcab, 0x00e8ab9f}, /* U+8ADF [2000] */ - {0x00fcac, 0x00e8abb4}, /* U+8AF4 [2000] */ - {0x00fcad, 0x00e8abb6}, /* U+8AF6 [2000] */ - {0x00fcae, 0x00efa8a2}, /* U+FA22 CJK COMPATIBILITY IDEOGRAPH-FA22 [2000] */ - {0x00fcaf, 0x00efa9a2}, /* U+FA62 CJK COMPATIBILITY IDEOGRAPH-FA62 [2000] [Unicode3.2] */ - {0x00fcb0, 0x00efa9a3}, /* U+FA63 CJK COMPATIBILITY IDEOGRAPH-FA63 [2000] [Unicode3.2] */ - {0x00fcb1, 0x00e8ad86}, /* U+8B46 [2000] */ - {0x00fcb2, 0x00e8ad94}, /* U+8B54 [2000] */ - {0x00fcb3, 0x00e8ad99}, /* U+8B59 [2000] */ - {0x00fcb4, 0x00e8ada9}, /* U+8B69 [2000] */ - {0x00fcb5, 0x00e8ae9d}, /* U+8B9D [2000] */ - {0x00fcb6, 0x00e8b189}, /* U+8C49 [2000] */ - {0x00fcb7, 0x00e8b1a8}, /* U+8C68 [2000] */ - {0x00fcb8, 0x00efa9a4}, /* U+FA64 CJK COMPATIBILITY IDEOGRAPH-FA64 [2000] [Unicode3.2] */ - {0x00fcb9, 0x00e8b3a1}, /* U+8CE1 [2000] */ - {0x00fcba, 0x00e8b3b4}, /* U+8CF4 [2000] */ - {0x00fcbb, 0x00e8b3b8}, /* U+8CF8 [2000] */ - {0x00fcbc, 0x00e8b3be}, /* U+8CFE [2000] */ - {0x00fcbd, 0x00efa9a5}, /* U+FA65 CJK COMPATIBILITY IDEOGRAPH-FA65 [2000] [Unicode3.2] */ - {0x00fcbe, 0x00e8b492}, /* U+8D12 [2000] */ - {0x00fcbf, 0x00e8b49b}, /* U+8D1B [2000] */ - {0x00fcc0, 0x00e8b6af}, /* U+8DAF [2000] */ - {0x00fcc1, 0x00e8b78e}, /* U+8DCE [2000] */ - {0x00fcc2, 0x00e8b791}, /* U+8DD1 [2000] */ - {0x00fcc3, 0x00e8b797}, /* U+8DD7 [2000] */ - {0x00fcc4, 0x00e8b8a0}, /* U+8E20 [2000] */ - {0x00fcc5, 0x00e8b8a3}, /* U+8E23 [2000] */ - {0x00fcc6, 0x00e8b8bd}, /* U+8E3D [2000] */ - {0x00fcc7, 0x00e8b9b0}, /* U+8E70 [2000] */ - {0x00fcc8, 0x00e8b9bb}, /* U+8E7B [2000] */ - {0x00fcc9, 0xf0a889b7}, /* U+28277 [2000] [Unicode3.1] */ - {0x00fcca, 0x00e8bb80}, /* U+8EC0 [2000] */ - {0x00fccb, 0x00e4a184}, /* U+4844 [2000] */ - {0x00fccc, 0x00e8bbba}, /* U+8EFA [2000] */ - {0x00fccd, 0x00e8bc9e}, /* U+8F1E [2000] */ - {0x00fcce, 0x00e8bcad}, /* U+8F2D [2000] */ - {0x00fccf, 0x00e8bcb6}, /* U+8F36 [2000] */ - {0x00fcd0, 0x00e8bd94}, /* U+8F54 [2000] */ - {0x00fcd1, 0xf0a88f8d}, /* U+283CD [2000] [Unicode3.1] */ - {0x00fcd2, 0x00e8bea6}, /* U+8FA6 [2000] */ - {0x00fcd3, 0x00e8beb5}, /* U+8FB5 [2000] */ - {0x00fcd4, 0x00e8bfa4}, /* U+8FE4 [2000] */ - {0x00fcd5, 0x00e8bfa8}, /* U+8FE8 [2000] */ - {0x00fcd6, 0x00e8bfae}, /* U+8FEE [2000] */ - {0x00fcd7, 0x00e98088}, /* U+9008 [2000] */ - {0x00fcd8, 0x00e980ad}, /* U+902D [2000] */ - {0x00fcd9, 0x00efa9a7}, /* U+FA67 CJK COMPATIBILITY IDEOGRAPH-FA67 [2000] [Unicode3.2] */ - {0x00fcda, 0x00e98288}, /* U+9088 [2000] */ - {0x00fcdb, 0x00e98295}, /* U+9095 [2000] */ - {0x00fcdc, 0x00e98297}, /* U+9097 [2000] */ - {0x00fcdd, 0x00e98299}, /* U+9099 [2000] */ - {0x00fcde, 0x00e9829b}, /* U+909B [2000] */ - {0x00fcdf, 0x00e982a2}, /* U+90A2 [2000] */ - {0x00fce0, 0x00e982b3}, /* U+90B3 [2000] */ - {0x00fce1, 0x00e982be}, /* U+90BE [2000] */ - {0x00fce2, 0x00e98384}, /* U+90C4 [2000] */ - {0x00fce3, 0x00e98385}, /* U+90C5 [2000] */ - {0x00fce4, 0x00e98387}, /* U+90C7 [2000] */ - {0x00fce5, 0x00e98397}, /* U+90D7 [2000] */ - {0x00fce6, 0x00e9839d}, /* U+90DD [2000] */ - {0x00fce7, 0x00e9839e}, /* U+90DE [2000] */ - {0x00fce8, 0x00e983af}, /* U+90EF [2000] */ - {0x00fce9, 0x00e983b4}, /* U+90F4 [2000] */ - {0x00fcea, 0x00efa8a6}, /* U+FA26 CJK COMPATIBILITY IDEOGRAPH-FA26 [2000] */ - {0x00fceb, 0x00e98494}, /* U+9114 [2000] */ - {0x00fcec, 0x00e98495}, /* U+9115 [2000] */ - {0x00fced, 0x00e98496}, /* U+9116 [2000] */ - {0x00fcee, 0x00e984a2}, /* U+9122 [2000] */ - {0x00fcef, 0x00e984a3}, /* U+9123 [2000] */ - {0x00fcf0, 0x00e984a7}, /* U+9127 [2000] */ - {0x00fcf1, 0x00e984af}, /* U+912F [2000] */ - {0x00fcf2, 0x00e984b1}, /* U+9131 [2000] */ - {0x00fcf3, 0x00e984b4}, /* U+9134 [2000] */ - {0x00fcf4, 0x00e984bd}, /* U+913D [2000] */ - {0x00fcf5, 0x00e98588}, /* U+9148 [2000] */ - {0x00fcf6, 0x00e9859b}, /* U+915B [2000] */ - {0x00fcf7, 0x00e98683}, /* U+9183 [2000] */ - {0x00fcf8, 0x00e9869e}, /* U+919E [2000] */ - {0x00fcf9, 0x00e986ac}, /* U+91AC [2000] */ - {0x00fcfa, 0x00e986b1}, /* U+91B1 [2000] */ - {0x00fcfb, 0x00e986bc}, /* U+91BC [2000] */ - {0x00fcfc, 0x00e98797}, /* U+91D7 [2000] */ - {0x00fcfd, 0x00e987bb}, /* U+91FB [2000] */ - {0x00fcfe, 0x00e987a4}, /* U+91E4 [2000] */ - {0x00fda1, 0x00e987a5}, /* U+91E5 [2000] */ - {0x00fda2, 0x00e987ad}, /* U+91ED [2000] */ - {0x00fda3, 0x00e987b1}, /* U+91F1 [2000] */ - {0x00fda4, 0x00e98887}, /* U+9207 [2000] */ - {0x00fda5, 0x00e98890}, /* U+9210 [2000] */ - {0x00fda6, 0x00e988b8}, /* U+9238 [2000] */ - {0x00fda7, 0x00e988b9}, /* U+9239 [2000] */ - {0x00fda8, 0x00e988ba}, /* U+923A [2000] */ - {0x00fda9, 0x00e988bc}, /* U+923C [2000] */ - {0x00fdaa, 0x00e98980}, /* U+9240 [2000] */ - {0x00fdab, 0x00e98983}, /* U+9243 [2000] */ - {0x00fdac, 0x00e9898f}, /* U+924F [2000] */ - {0x00fdad, 0x00e989b8}, /* U+9278 [2000] */ - {0x00fdae, 0x00e98a88}, /* U+9288 [2000] */ - {0x00fdaf, 0x00e98b82}, /* U+92C2 [2000] */ - {0x00fdb0, 0x00e98b8b}, /* U+92CB [2000] */ - {0x00fdb1, 0x00e98b8c}, /* U+92CC [2000] */ - {0x00fdb2, 0x00e98b93}, /* U+92D3 [2000] */ - {0x00fdb3, 0x00e98ba0}, /* U+92E0 [2000] */ - {0x00fdb4, 0x00e98bbf}, /* U+92FF [2000] */ - {0x00fdb5, 0x00e98c84}, /* U+9304 [2000] */ - {0x00fdb6, 0x00e98c9f}, /* U+931F [2000] */ - {0x00fdb7, 0x00e98ca1}, /* U+9321 [2000] */ - {0x00fdb8, 0x00e98ca5}, /* U+9325 [2000] */ - {0x00fdb9, 0x00e98d88}, /* U+9348 [2000] */ - {0x00fdba, 0x00e98d89}, /* U+9349 [2000] */ - {0x00fdbb, 0x00e98d8a}, /* U+934A [2000] */ - {0x00fdbc, 0x00e98da4}, /* U+9364 [2000] */ - {0x00fdbd, 0x00e98da5}, /* U+9365 [2000] */ - {0x00fdbe, 0x00e98daa}, /* U+936A [2000] */ - {0x00fdbf, 0x00e98db0}, /* U+9370 [2000] */ - {0x00fdc0, 0x00e98e9b}, /* U+939B [2000] */ - {0x00fdc1, 0x00e98ea3}, /* U+93A3 [2000] */ - {0x00fdc2, 0x00e98eba}, /* U+93BA [2000] */ - {0x00fdc3, 0x00e98f86}, /* U+93C6 [2000] */ - {0x00fdc4, 0x00e98f9e}, /* U+93DE [2000] */ - {0x00fdc5, 0x00e98f9f}, /* U+93DF [2000] */ - {0x00fdc6, 0x00e99084}, /* U+9404 [2000] */ - {0x00fdc7, 0x00e98fbd}, /* U+93FD [2000] */ - {0x00fdc8, 0x00e990b3}, /* U+9433 [2000] */ - {0x00fdc9, 0x00e9918a}, /* U+944A [2000] */ - {0x00fdca, 0x00e991a3}, /* U+9463 [2000] */ - {0x00fdcb, 0x00e991ab}, /* U+946B [2000] */ - {0x00fdcc, 0x00e991b1}, /* U+9471 [2000] */ - {0x00fdcd, 0x00e991b2}, /* U+9472 [2000] */ - {0x00fdce, 0x00e9968e}, /* U+958E [2000] */ - {0x00fdcf, 0x00e9969f}, /* U+959F [2000] */ - {0x00fdd0, 0x00e996a6}, /* U+95A6 [2000] */ - {0x00fdd1, 0x00e996a9}, /* U+95A9 [2000] */ - {0x00fdd2, 0x00e996ac}, /* U+95AC [2000] */ - {0x00fdd3, 0x00e996b6}, /* U+95B6 [2000] */ - {0x00fdd4, 0x00e996bd}, /* U+95BD [2000] */ - {0x00fdd5, 0x00e9978b}, /* U+95CB [2000] */ - {0x00fdd6, 0x00e99790}, /* U+95D0 [2000] */ - {0x00fdd7, 0x00e99793}, /* U+95D3 [2000] */ - {0x00fdd8, 0x00e4a6b0}, /* U+49B0 [2000] */ - {0x00fdd9, 0x00e9979a}, /* U+95DA [2000] */ - {0x00fdda, 0x00e9979e}, /* U+95DE [2000] */ - {0x00fddb, 0x00e99998}, /* U+9658 [2000] */ - {0x00fddc, 0x00e99a84}, /* U+9684 [2000] */ - {0x00fddd, 0x00efa79c}, /* U+F9DC CJK COMPATIBILITY IDEOGRAPH-F9DC [2000] */ - {0x00fdde, 0x00e99a9d}, /* U+969D [2000] */ - {0x00fddf, 0x00e99aa4}, /* U+96A4 [2000] */ - {0x00fde0, 0x00e99aa5}, /* U+96A5 [2000] */ - {0x00fde1, 0x00e99b92}, /* U+96D2 [2000] */ - {0x00fde2, 0x00e99b9e}, /* U+96DE [2000] */ - {0x00fde3, 0x00efa9a8}, /* U+FA68 CJK COMPATIBILITY IDEOGRAPH-FA68 [2000] [Unicode3.2] */ - {0x00fde4, 0x00e99ba9}, /* U+96E9 [2000] */ - {0x00fde5, 0x00e99baf}, /* U+96EF [2000] */ - {0x00fde6, 0x00e99cb3}, /* U+9733 [2000] */ - {0x00fde7, 0x00e99cbb}, /* U+973B [2000] */ - {0x00fde8, 0x00e99d8d}, /* U+974D [2000] */ - {0x00fde9, 0x00e99d8e}, /* U+974E [2000] */ - {0x00fdea, 0x00e99d8f}, /* U+974F [2000] */ - {0x00fdeb, 0x00e99d9a}, /* U+975A [2000] */ - {0x00fdec, 0x00e99dae}, /* U+976E [2000] */ - {0x00fded, 0x00e99db3}, /* U+9773 [2000] */ - {0x00fdee, 0x00e99e95}, /* U+9795 [2000] */ - {0x00fdef, 0x00e99eae}, /* U+97AE [2000] */ - {0x00fdf0, 0x00e99eba}, /* U+97BA [2000] */ - {0x00fdf1, 0x00e99f81}, /* U+97C1 [2000] */ - {0x00fdf2, 0x00e99f89}, /* U+97C9 [2000] */ - {0x00fdf3, 0x00e99f9e}, /* U+97DE [2000] */ - {0x00fdf4, 0x00e99f9b}, /* U+97DB [2000] */ - {0x00fdf5, 0x00e99fb4}, /* U+97F4 [2000] */ - {0x00fdf6, 0x00efa9a9}, /* U+FA69 CJK COMPATIBILITY IDEOGRAPH-FA69 [2000] [Unicode3.2] */ - {0x00fdf7, 0x00e9a08a}, /* U+980A [2000] */ - {0x00fdf8, 0x00e9a09e}, /* U+981E [2000] */ - {0x00fdf9, 0x00e9a0ab}, /* U+982B [2000] */ - {0x00fdfa, 0x00e9a0b0}, /* U+9830 [2000] */ - {0x00fdfb, 0x00efa9aa}, /* U+FA6A CJK COMPATIBILITY IDEOGRAPH-FA6A [2000] [Unicode3.2] */ - {0x00fdfc, 0x00e9a192}, /* U+9852 [2000] */ - {0x00fdfd, 0x00e9a193}, /* U+9853 [2000] */ - {0x00fdfe, 0x00e9a196}, /* U+9856 [2000] */ - {0x00fea1, 0x00e9a197}, /* U+9857 [2000] */ - {0x00fea2, 0x00e9a199}, /* U+9859 [2000] */ - {0x00fea3, 0x00e9a19a}, /* U+985A [2000] */ - {0x00fea4, 0x00efa790}, /* U+F9D0 CJK COMPATIBILITY IDEOGRAPH-F9D0 [2000] */ - {0x00fea5, 0x00e9a1a5}, /* U+9865 [2000] */ - {0x00fea6, 0x00e9a1ac}, /* U+986C [2000] */ - {0x00fea7, 0x00e9a2ba}, /* U+98BA [2000] */ - {0x00fea8, 0x00e9a388}, /* U+98C8 [2000] */ - {0x00fea9, 0x00e9a3a7}, /* U+98E7 [2000] */ - {0x00feaa, 0x00e9a598}, /* U+9958 [2000] */ - {0x00feab, 0x00e9a69e}, /* U+999E [2000] */ - {0x00feac, 0x00e9a882}, /* U+9A02 [2000] */ - {0x00fead, 0x00e9a883}, /* U+9A03 [2000] */ - {0x00feae, 0x00e9a8a4}, /* U+9A24 [2000] */ - {0x00feaf, 0x00e9a8ad}, /* U+9A2D [2000] */ - {0x00feb0, 0x00e9a8ae}, /* U+9A2E [2000] */ - {0x00feb1, 0x00e9a8b8}, /* U+9A38 [2000] */ - {0x00feb2, 0x00e9a98a}, /* U+9A4A [2000] */ - {0x00feb3, 0x00e9a98e}, /* U+9A4E [2000] */ - {0x00feb4, 0x00e9a992}, /* U+9A52 [2000] */ - {0x00feb5, 0x00e9aab6}, /* U+9AB6 [2000] */ - {0x00feb6, 0x00e9ab81}, /* U+9AC1 [2000] */ - {0x00feb7, 0x00e9ab83}, /* U+9AC3 [2000] */ - {0x00feb8, 0x00e9ab8e}, /* U+9ACE [2000] */ - {0x00feb9, 0x00e9ab96}, /* U+9AD6 [2000] */ - {0x00feba, 0x00e9abb9}, /* U+9AF9 [2000] */ - {0x00febb, 0x00e9ac82}, /* U+9B02 [2000] */ - {0x00febc, 0x00e9ac88}, /* U+9B08 [2000] */ - {0x00febd, 0x00e9aca0}, /* U+9B20 [2000] */ - {0x00febe, 0x00e4b097}, /* U+4C17 [2000] */ - {0x00febf, 0x00e9acad}, /* U+9B2D [2000] */ - {0x00fec0, 0x00e9ad9e}, /* U+9B5E [2000] */ - {0x00fec1, 0x00e9adb9}, /* U+9B79 [2000] */ - {0x00fec2, 0x00e9ada6}, /* U+9B66 [2000] */ - {0x00fec3, 0x00e9adb2}, /* U+9B72 [2000] */ - {0x00fec4, 0x00e9adb5}, /* U+9B75 [2000] */ - {0x00fec5, 0x00e9ae84}, /* U+9B84 [2000] */ - {0x00fec6, 0x00e9ae8a}, /* U+9B8A [2000] */ - {0x00fec7, 0x00e9ae8f}, /* U+9B8F [2000] */ - {0x00fec8, 0x00e9ae9e}, /* U+9B9E [2000] */ - {0x00fec9, 0x00e9aea7}, /* U+9BA7 [2000] */ - {0x00feca, 0x00e9af81}, /* U+9BC1 [2000] */ - {0x00fecb, 0x00e9af8e}, /* U+9BCE [2000] */ - {0x00fecc, 0x00e9afa5}, /* U+9BE5 [2000] */ - {0x00fecd, 0x00e9afb8}, /* U+9BF8 [2000] */ - {0x00fece, 0x00e9afbd}, /* U+9BFD [2000] */ - {0x00fecf, 0x00e9b080}, /* U+9C00 [2000] */ - {0x00fed0, 0x00e9b0a3}, /* U+9C23 [2000] */ - {0x00fed1, 0x00e9b181}, /* U+9C41 [2000] */ - {0x00fed2, 0x00e9b18f}, /* U+9C4F [2000] */ - {0x00fed3, 0x00e9b190}, /* U+9C50 [2000] */ - {0x00fed4, 0x00e9b193}, /* U+9C53 [2000] */ - {0x00fed5, 0x00e9b1a3}, /* U+9C63 [2000] */ - {0x00fed6, 0x00e9b1a5}, /* U+9C65 [2000] */ - {0x00fed7, 0x00e9b1b7}, /* U+9C77 [2000] */ - {0x00fed8, 0x00e9b49d}, /* U+9D1D [2000] */ - {0x00fed9, 0x00e9b49e}, /* U+9D1E [2000] */ - {0x00feda, 0x00e9b583}, /* U+9D43 [2000] */ - {0x00fedb, 0x00e9b587}, /* U+9D47 [2000] */ - {0x00fedc, 0x00e9b592}, /* U+9D52 [2000] */ - {0x00fedd, 0x00e9b5a3}, /* U+9D63 [2000] */ - {0x00fede, 0x00e9b5b0}, /* U+9D70 [2000] */ - {0x00fedf, 0x00e9b5bc}, /* U+9D7C [2000] */ - {0x00fee0, 0x00e9b68a}, /* U+9D8A [2000] */ - {0x00fee1, 0x00e9b696}, /* U+9D96 [2000] */ - {0x00fee2, 0x00e9b780}, /* U+9DC0 [2000] */ - {0x00fee3, 0x00e9b6ac}, /* U+9DAC [2000] */ - {0x00fee4, 0x00e9b6bc}, /* U+9DBC [2000] */ - {0x00fee5, 0x00e9b797}, /* U+9DD7 [2000] */ - {0x00fee6, 0xf0aa8690}, /* U+2A190 [2000] [Unicode3.1] */ - {0x00fee7, 0x00e9b7a7}, /* U+9DE7 [2000] */ - {0x00fee8, 0x00e9b887}, /* U+9E07 [2000] */ - {0x00fee9, 0x00e9b895}, /* U+9E15 [2000] */ - {0x00feea, 0x00e9b9bc}, /* U+9E7C [2000] */ - {0x00feeb, 0x00e9ba9e}, /* U+9E9E [2000] */ - {0x00feec, 0x00e9baa4}, /* U+9EA4 [2000] */ - {0x00feed, 0x00e9baac}, /* U+9EAC [2000] */ - {0x00feee, 0x00e9baaf}, /* U+9EAF [2000] */ - {0x00feef, 0x00e9bab4}, /* U+9EB4 [2000] */ - {0x00fef0, 0x00e9bab5}, /* U+9EB5 [2000] */ - {0x00fef1, 0x00e9bb83}, /* U+9EC3 [2000] */ - {0x00fef2, 0x00e9bb91}, /* U+9ED1 [2000] */ - {0x00fef3, 0x00e9bc90}, /* U+9F10 [2000] */ - {0x00fef4, 0x00e9bcb9}, /* U+9F39 [2000] */ - {0x00fef5, 0x00e9bd97}, /* U+9F57 [2000] */ - {0x00fef6, 0x00e9be90}, /* U+9F90 [2000] */ - {0x00fef7, 0x00e9be94}, /* U+9F94 [2000] */ - {0x00fef8, 0x00e9be97}, /* U+9F97 [2000] */ - {0x00fef9, 0x00e9bea2}, /* U+9FA2 [2000] */ - {0x00fefa, 0x00e5a7b8}, /* U+59F8 [2004] */ - {0x00fefb, 0x00e5b19b}, /* U+5C5B [2004] */ - {0x00fefc, 0x00e5b9b7}, /* U+5E77 [2004] */ - {0x00fefd, 0x00e798a6}, /* U+7626 [2004] */ - {0x00fefe, 0x00e7b9ab}, /* U+7E6B [2004] */ +/* src/backend/utils/mb/Unicode/euc_jis_2004_to_utf8.map */ + +static const pg_local_to_utf LUmapEUC_JIS_2004[ 11303 ] = { /* */ + {0x0080, 0xc280}, /* U+0080 */ + {0x0081, 0xc281}, /* U+0081 */ + {0x0082, 0xc282}, /* U+0082 */ + {0x0083, 0xc283}, /* U+0083 */ + {0x0084, 0xc284}, /* U+0084 */ + {0x0085, 0xc285}, /* U+0085 */ + {0x0086, 0xc286}, /* U+0086 */ + {0x0087, 0xc287}, /* U+0087 */ + {0x0088, 0xc288}, /* U+0088 */ + {0x0089, 0xc289}, /* U+0089 */ + {0x008a, 0xc28a}, /* U+008A */ + {0x008b, 0xc28b}, /* U+008B */ + {0x008c, 0xc28c}, /* U+008C */ + {0x008d, 0xc28d}, /* U+008D */ + {0x008e, 0xc28e}, /* U+008E */ + {0x008f, 0xc28f}, /* U+008F */ + {0x0090, 0xc290}, /* U+0090 */ + {0x0091, 0xc291}, /* U+0091 */ + {0x0092, 0xc292}, /* U+0092 */ + {0x0093, 0xc293}, /* U+0093 */ + {0x0094, 0xc294}, /* U+0094 */ + {0x0095, 0xc295}, /* U+0095 */ + {0x0096, 0xc296}, /* U+0096 */ + {0x0097, 0xc297}, /* U+0097 */ + {0x0098, 0xc298}, /* U+0098 */ + {0x0099, 0xc299}, /* U+0099 */ + {0x009a, 0xc29a}, /* U+009A */ + {0x009b, 0xc29b}, /* U+009B */ + {0x009c, 0xc29c}, /* U+009C */ + {0x009d, 0xc29d}, /* U+009D */ + {0x009e, 0xc29e}, /* U+009E */ + {0x009f, 0xc29f}, /* U+009F */ + {0x8ea1, 0xefbda1}, /* U+FF61 HALFWIDTH IDEOGRAPHIC FULL STOP */ + {0x8ea2, 0xefbda2}, /* U+FF62 HALFWIDTH LEFT CORNER BRACKET */ + {0x8ea3, 0xefbda3}, /* U+FF63 HALFWIDTH RIGHT CORNER BRACKET */ + {0x8ea4, 0xefbda4}, /* U+FF64 HALFWIDTH IDEOGRAPHIC COMMA */ + {0x8ea5, 0xefbda5}, /* U+FF65 HALFWIDTH KATAKANA MIDDLE DOT */ + {0x8ea6, 0xefbda6}, /* U+FF66 HALFWIDTH KATAKANA LETTER WO */ + {0x8ea7, 0xefbda7}, /* U+FF67 HALFWIDTH KATAKANA LETTER SMALL A */ + {0x8ea8, 0xefbda8}, /* U+FF68 HALFWIDTH KATAKANA LETTER SMALL I */ + {0x8ea9, 0xefbda9}, /* U+FF69 HALFWIDTH KATAKANA LETTER SMALL U */ + {0x8eaa, 0xefbdaa}, /* U+FF6A HALFWIDTH KATAKANA LETTER SMALL E */ + {0x8eab, 0xefbdab}, /* U+FF6B HALFWIDTH KATAKANA LETTER SMALL O */ + {0x8eac, 0xefbdac}, /* U+FF6C HALFWIDTH KATAKANA LETTER SMALL YA */ + {0x8ead, 0xefbdad}, /* U+FF6D HALFWIDTH KATAKANA LETTER SMALL YU */ + {0x8eae, 0xefbdae}, /* U+FF6E HALFWIDTH KATAKANA LETTER SMALL YO */ + {0x8eaf, 0xefbdaf}, /* U+FF6F HALFWIDTH KATAKANA LETTER SMALL TU */ + {0x8eb0, 0xefbdb0}, /* U+FF70 HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK */ + {0x8eb1, 0xefbdb1}, /* U+FF71 HALFWIDTH KATAKANA LETTER A */ + {0x8eb2, 0xefbdb2}, /* U+FF72 HALFWIDTH KATAKANA LETTER I */ + {0x8eb3, 0xefbdb3}, /* U+FF73 HALFWIDTH KATAKANA LETTER U */ + {0x8eb4, 0xefbdb4}, /* U+FF74 HALFWIDTH KATAKANA LETTER E */ + {0x8eb5, 0xefbdb5}, /* U+FF75 HALFWIDTH KATAKANA LETTER O */ + {0x8eb6, 0xefbdb6}, /* U+FF76 HALFWIDTH KATAKANA LETTER KA */ + {0x8eb7, 0xefbdb7}, /* U+FF77 HALFWIDTH KATAKANA LETTER KI */ + {0x8eb8, 0xefbdb8}, /* U+FF78 HALFWIDTH KATAKANA LETTER KU */ + {0x8eb9, 0xefbdb9}, /* U+FF79 HALFWIDTH KATAKANA LETTER KE */ + {0x8eba, 0xefbdba}, /* U+FF7A HALFWIDTH KATAKANA LETTER KO */ + {0x8ebb, 0xefbdbb}, /* U+FF7B HALFWIDTH KATAKANA LETTER SA */ + {0x8ebc, 0xefbdbc}, /* U+FF7C HALFWIDTH KATAKANA LETTER SI */ + {0x8ebd, 0xefbdbd}, /* U+FF7D HALFWIDTH KATAKANA LETTER SU */ + {0x8ebe, 0xefbdbe}, /* U+FF7E HALFWIDTH KATAKANA LETTER SE */ + {0x8ebf, 0xefbdbf}, /* U+FF7F HALFWIDTH KATAKANA LETTER SO */ + {0x8ec0, 0xefbe80}, /* U+FF80 HALFWIDTH KATAKANA LETTER TA */ + {0x8ec1, 0xefbe81}, /* U+FF81 HALFWIDTH KATAKANA LETTER TI */ + {0x8ec2, 0xefbe82}, /* U+FF82 HALFWIDTH KATAKANA LETTER TU */ + {0x8ec3, 0xefbe83}, /* U+FF83 HALFWIDTH KATAKANA LETTER TE */ + {0x8ec4, 0xefbe84}, /* U+FF84 HALFWIDTH KATAKANA LETTER TO */ + {0x8ec5, 0xefbe85}, /* U+FF85 HALFWIDTH KATAKANA LETTER NA */ + {0x8ec6, 0xefbe86}, /* U+FF86 HALFWIDTH KATAKANA LETTER NI */ + {0x8ec7, 0xefbe87}, /* U+FF87 HALFWIDTH KATAKANA LETTER NU */ + {0x8ec8, 0xefbe88}, /* U+FF88 HALFWIDTH KATAKANA LETTER NE */ + {0x8ec9, 0xefbe89}, /* U+FF89 HALFWIDTH KATAKANA LETTER NO */ + {0x8eca, 0xefbe8a}, /* U+FF8A HALFWIDTH KATAKANA LETTER HA */ + {0x8ecb, 0xefbe8b}, /* U+FF8B HALFWIDTH KATAKANA LETTER HI */ + {0x8ecc, 0xefbe8c}, /* U+FF8C HALFWIDTH KATAKANA LETTER HU */ + {0x8ecd, 0xefbe8d}, /* U+FF8D HALFWIDTH KATAKANA LETTER HE */ + {0x8ece, 0xefbe8e}, /* U+FF8E HALFWIDTH KATAKANA LETTER HO */ + {0x8ecf, 0xefbe8f}, /* U+FF8F HALFWIDTH KATAKANA LETTER MA */ + {0x8ed0, 0xefbe90}, /* U+FF90 HALFWIDTH KATAKANA LETTER MI */ + {0x8ed1, 0xefbe91}, /* U+FF91 HALFWIDTH KATAKANA LETTER MU */ + {0x8ed2, 0xefbe92}, /* U+FF92 HALFWIDTH KATAKANA LETTER ME */ + {0x8ed3, 0xefbe93}, /* U+FF93 HALFWIDTH KATAKANA LETTER MO */ + {0x8ed4, 0xefbe94}, /* U+FF94 HALFWIDTH KATAKANA LETTER YA */ + {0x8ed5, 0xefbe95}, /* U+FF95 HALFWIDTH KATAKANA LETTER YU */ + {0x8ed6, 0xefbe96}, /* U+FF96 HALFWIDTH KATAKANA LETTER YO */ + {0x8ed7, 0xefbe97}, /* U+FF97 HALFWIDTH KATAKANA LETTER RA */ + {0x8ed8, 0xefbe98}, /* U+FF98 HALFWIDTH KATAKANA LETTER RI */ + {0x8ed9, 0xefbe99}, /* U+FF99 HALFWIDTH KATAKANA LETTER RU */ + {0x8eda, 0xefbe9a}, /* U+FF9A HALFWIDTH KATAKANA LETTER RE */ + {0x8edb, 0xefbe9b}, /* U+FF9B HALFWIDTH KATAKANA LETTER RO */ + {0x8edc, 0xefbe9c}, /* U+FF9C HALFWIDTH KATAKANA LETTER WA */ + {0x8edd, 0xefbe9d}, /* U+FF9D HALFWIDTH KATAKANA LETTER N */ + {0x8ede, 0xefbe9e}, /* U+FF9E HALFWIDTH KATAKANA VOICED SOUND MARK */ + {0x8edf, 0xefbe9f}, /* U+FF9F HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK */ + {0xa1a1, 0xe38080}, /* U+3000 IDEOGRAPHIC SPACE */ + {0xa1a2, 0xe38081}, /* U+3001 IDEOGRAPHIC COMMA */ + {0xa1a3, 0xe38082}, /* U+3002 IDEOGRAPHIC FULL STOP */ + {0xa1a4, 0xefbc8c}, /* U+FF0C FULLWIDTH COMMA */ + {0xa1a5, 0xefbc8e}, /* U+FF0E FULLWIDTH FULL STOP */ + {0xa1a6, 0xe383bb}, /* U+30FB KATAKANA MIDDLE DOT */ + {0xa1a7, 0xefbc9a}, /* U+FF1A FULLWIDTH COLON */ + {0xa1a8, 0xefbc9b}, /* U+FF1B FULLWIDTH SEMICOLON */ + {0xa1a9, 0xefbc9f}, /* U+FF1F FULLWIDTH QUESTION MARK */ + {0xa1aa, 0xefbc81}, /* U+FF01 FULLWIDTH EXCLAMATION MARK */ + {0xa1ab, 0xe3829b}, /* U+309B KATAKANA-HIRAGANA VOICED SOUND MARK */ + {0xa1ac, 0xe3829c}, /* U+309C KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ + {0xa1ad, 0xc2b4}, /* U+00B4 ACUTE ACCENT */ + {0xa1ae, 0xefbd80}, /* U+FF40 FULLWIDTH GRAVE ACCENT */ + {0xa1af, 0xc2a8}, /* U+00A8 DIAERESIS */ + {0xa1b0, 0xefbcbe}, /* U+FF3E FULLWIDTH CIRCUMFLEX ACCENT */ + {0xa1b1, 0xe280be}, /* U+203E OVERLINE Windows: U+FFE3 */ + {0xa1b2, 0xefbcbf}, /* U+FF3F FULLWIDTH LOW LINE */ + {0xa1b3, 0xe383bd}, /* U+30FD KATAKANA ITERATION MARK */ + {0xa1b4, 0xe383be}, /* U+30FE KATAKANA VOICED ITERATION MARK */ + {0xa1b5, 0xe3829d}, /* U+309D HIRAGANA ITERATION MARK */ + {0xa1b6, 0xe3829e}, /* U+309E HIRAGANA VOICED ITERATION MARK */ + {0xa1b7, 0xe38083}, /* U+3003 DITTO MARK */ + {0xa1b8, 0xe4bb9d}, /* U+4EDD */ + {0xa1b9, 0xe38085}, /* U+3005 IDEOGRAPHIC ITERATION MARK */ + {0xa1ba, 0xe38086}, /* U+3006 IDEOGRAPHIC CLOSING MARK */ + {0xa1bb, 0xe38087}, /* U+3007 IDEOGRAPHIC NUMBER ZERO */ + {0xa1bc, 0xe383bc}, /* U+30FC KATAKANA-HIRAGANA PROLONGED SOUND MARK */ + {0xa1bd, 0xe28094}, /* U+2014 EM DASH Windows: U+2015 */ + {0xa1be, 0xe28090}, /* U+2010 HYPHEN */ + {0xa1bf, 0xefbc8f}, /* U+FF0F FULLWIDTH SOLIDUS */ + {0xa1c0, 0xefbcbc}, /* U+FF3C FULLWIDTH REVERSE SOLIDUS */ + {0xa1c1, 0xe3809c}, /* U+301C WAVE DASH Windows: U+FF5E */ + {0xa1c2, 0xe28096}, /* U+2016 DOUBLE VERTICAL LINE Windows: U+2225 */ + {0xa1c3, 0xefbd9c}, /* U+FF5C FULLWIDTH VERTICAL LINE */ + {0xa1c4, 0xe280a6}, /* U+2026 HORIZONTAL ELLIPSIS */ + {0xa1c5, 0xe280a5}, /* U+2025 TWO DOT LEADER */ + {0xa1c6, 0xe28098}, /* U+2018 LEFT SINGLE QUOTATION MARK */ + {0xa1c7, 0xe28099}, /* U+2019 RIGHT SINGLE QUOTATION MARK */ + {0xa1c8, 0xe2809c}, /* U+201C LEFT DOUBLE QUOTATION MARK */ + {0xa1c9, 0xe2809d}, /* U+201D RIGHT DOUBLE QUOTATION MARK */ + {0xa1ca, 0xefbc88}, /* U+FF08 FULLWIDTH LEFT PARENTHESIS */ + {0xa1cb, 0xefbc89}, /* U+FF09 FULLWIDTH RIGHT PARENTHESIS */ + {0xa1cc, 0xe38094}, /* U+3014 LEFT TORTOISE SHELL BRACKET */ + {0xa1cd, 0xe38095}, /* U+3015 RIGHT TORTOISE SHELL BRACKET */ + {0xa1ce, 0xefbcbb}, /* U+FF3B FULLWIDTH LEFT SQUARE BRACKET */ + {0xa1cf, 0xefbcbd}, /* U+FF3D FULLWIDTH RIGHT SQUARE BRACKET */ + {0xa1d0, 0xefbd9b}, /* U+FF5B FULLWIDTH LEFT CURLY BRACKET */ + {0xa1d1, 0xefbd9d}, /* U+FF5D FULLWIDTH RIGHT CURLY BRACKET */ + {0xa1d2, 0xe38088}, /* U+3008 LEFT ANGLE BRACKET */ + {0xa1d3, 0xe38089}, /* U+3009 RIGHT ANGLE BRACKET */ + {0xa1d4, 0xe3808a}, /* U+300A LEFT DOUBLE ANGLE BRACKET */ + {0xa1d5, 0xe3808b}, /* U+300B RIGHT DOUBLE ANGLE BRACKET */ + {0xa1d6, 0xe3808c}, /* U+300C LEFT CORNER BRACKET */ + {0xa1d7, 0xe3808d}, /* U+300D RIGHT CORNER BRACKET */ + {0xa1d8, 0xe3808e}, /* U+300E LEFT WHITE CORNER BRACKET */ + {0xa1d9, 0xe3808f}, /* U+300F RIGHT WHITE CORNER BRACKET */ + {0xa1da, 0xe38090}, /* U+3010 LEFT BLACK LENTICULAR BRACKET */ + {0xa1db, 0xe38091}, /* U+3011 RIGHT BLACK LENTICULAR BRACKET */ + {0xa1dc, 0xefbc8b}, /* U+FF0B FULLWIDTH PLUS SIGN */ + {0xa1dd, 0xe28892}, /* U+2212 MINUS SIGN Windows: U+FF0D */ + {0xa1de, 0xc2b1}, /* U+00B1 PLUS-MINUS SIGN */ + {0xa1df, 0xc397}, /* U+00D7 MULTIPLICATION SIGN */ + {0xa1e0, 0xc3b7}, /* U+00F7 DIVISION SIGN */ + {0xa1e1, 0xefbc9d}, /* U+FF1D FULLWIDTH EQUALS SIGN */ + {0xa1e2, 0xe289a0}, /* U+2260 NOT EQUAL TO */ + {0xa1e3, 0xefbc9c}, /* U+FF1C FULLWIDTH LESS-THAN SIGN */ + {0xa1e4, 0xefbc9e}, /* U+FF1E FULLWIDTH GREATER-THAN SIGN */ + {0xa1e5, 0xe289a6}, /* U+2266 LESS-THAN OVER EQUAL TO */ + {0xa1e6, 0xe289a7}, /* U+2267 GREATER-THAN OVER EQUAL TO */ + {0xa1e7, 0xe2889e}, /* U+221E INFINITY */ + {0xa1e8, 0xe288b4}, /* U+2234 THEREFORE */ + {0xa1e9, 0xe29982}, /* U+2642 MALE SIGN */ + {0xa1ea, 0xe29980}, /* U+2640 FEMALE SIGN */ + {0xa1eb, 0xc2b0}, /* U+00B0 DEGREE SIGN */ + {0xa1ec, 0xe280b2}, /* U+2032 PRIME */ + {0xa1ed, 0xe280b3}, /* U+2033 DOUBLE PRIME */ + {0xa1ee, 0xe28483}, /* U+2103 DEGREE CELSIUS */ + {0xa1ef, 0xc2a5}, /* U+00A5 YEN SIGN Windows: U+FFE5 */ + {0xa1f0, 0xefbc84}, /* U+FF04 FULLWIDTH DOLLAR SIGN */ + {0xa1f1, 0xc2a2}, /* U+00A2 CENT SIGN Windows: U+FFE0 */ + {0xa1f2, 0xc2a3}, /* U+00A3 POUND SIGN Windows: U+FFE1 */ + {0xa1f3, 0xefbc85}, /* U+FF05 FULLWIDTH PERCENT SIGN */ + {0xa1f4, 0xefbc83}, /* U+FF03 FULLWIDTH NUMBER SIGN */ + {0xa1f5, 0xefbc86}, /* U+FF06 FULLWIDTH AMPERSAND */ + {0xa1f6, 0xefbc8a}, /* U+FF0A FULLWIDTH ASTERISK */ + {0xa1f7, 0xefbca0}, /* U+FF20 FULLWIDTH COMMERCIAL AT */ + {0xa1f8, 0xc2a7}, /* U+00A7 SECTION SIGN */ + {0xa1f9, 0xe29886}, /* U+2606 WHITE STAR */ + {0xa1fa, 0xe29885}, /* U+2605 BLACK STAR */ + {0xa1fb, 0xe2978b}, /* U+25CB WHITE CIRCLE */ + {0xa1fc, 0xe2978f}, /* U+25CF BLACK CIRCLE */ + {0xa1fd, 0xe2978e}, /* U+25CE BULLSEYE */ + {0xa1fe, 0xe29787}, /* U+25C7 WHITE DIAMOND */ + {0xa2a1, 0xe29786}, /* U+25C6 BLACK DIAMOND */ + {0xa2a2, 0xe296a1}, /* U+25A1 WHITE SQUARE */ + {0xa2a3, 0xe296a0}, /* U+25A0 BLACK SQUARE */ + {0xa2a4, 0xe296b3}, /* U+25B3 WHITE UP-POINTING TRIANGLE */ + {0xa2a5, 0xe296b2}, /* U+25B2 BLACK UP-POINTING TRIANGLE */ + {0xa2a6, 0xe296bd}, /* U+25BD WHITE DOWN-POINTING TRIANGLE */ + {0xa2a7, 0xe296bc}, /* U+25BC BLACK DOWN-POINTING TRIANGLE */ + {0xa2a8, 0xe280bb}, /* U+203B REFERENCE MARK */ + {0xa2a9, 0xe38092}, /* U+3012 POSTAL MARK */ + {0xa2aa, 0xe28692}, /* U+2192 RIGHTWARDS ARROW */ + {0xa2ab, 0xe28690}, /* U+2190 LEFTWARDS ARROW */ + {0xa2ac, 0xe28691}, /* U+2191 UPWARDS ARROW */ + {0xa2ad, 0xe28693}, /* U+2193 DOWNWARDS ARROW */ + {0xa2ae, 0xe38093}, /* U+3013 GETA MARK */ + {0xa2af, 0xefbc87}, /* U+FF07 FULLWIDTH APOSTROPHE */ + {0xa2b0, 0xefbc82}, /* U+FF02 FULLWIDTH QUOTATION MARK [2000] */ + {0xa2b1, 0xefbc8d}, /* U+FF0D FULLWIDTH HYPHEN-MINUS [2000] */ + {0xa2b2, 0xefbd9e}, /* U+FF5E FULLWIDTH TILDE [2000] */ + {0xa2b3, 0xe380b3}, /* U+3033 VERTICAL KANA REPEAT MARK UPPER HALF [2000] */ + {0xa2b4, 0xe380b4}, /* U+3034 VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF [2000] */ + {0xa2b5, 0xe380b5}, /* U+3035 VERTICAL KANA REPEAT MARK LOWER HALF [2000] */ + {0xa2b6, 0xe380bb}, /* U+303B VERTICAL IDEOGRAPHIC ITERATION MARK [2000] [Unicode3.2] */ + {0xa2b7, 0xe380bc}, /* U+303C MASU MARK [2000] [Unicode3.2] */ + {0xa2b8, 0xe383bf}, /* U+30FF KATAKANA DIGRAPH KOTO [2000] [Unicode3.2] */ + {0xa2b9, 0xe3829f}, /* U+309F HIRAGANA DIGRAPH YORI [2000] [Unicode3.2] */ + {0xa2ba, 0xe28888}, /* U+2208 ELEMENT OF [1983] */ + {0xa2bb, 0xe2888b}, /* U+220B CONTAINS AS MEMBER [1983] */ + {0xa2bc, 0xe28a86}, /* U+2286 SUBSET OF OR EQUAL TO [1983] */ + {0xa2bd, 0xe28a87}, /* U+2287 SUPERSET OF OR EQUAL TO [1983] */ + {0xa2be, 0xe28a82}, /* U+2282 SUBSET OF [1983] */ + {0xa2bf, 0xe28a83}, /* U+2283 SUPERSET OF [1983] */ + {0xa2c0, 0xe288aa}, /* U+222A UNION [1983] */ + {0xa2c1, 0xe288a9}, /* U+2229 INTERSECTION [1983] */ + {0xa2c2, 0xe28a84}, /* U+2284 NOT A SUBSET OF [2000] */ + {0xa2c3, 0xe28a85}, /* U+2285 NOT A SUPERSET OF [2000] */ + {0xa2c4, 0xe28a8a}, /* U+228A SUBSET OF WITH NOT EQUAL TO [2000] */ + {0xa2c5, 0xe28a8b}, /* U+228B SUPERSET OF WITH NOT EQUAL TO [2000] */ + {0xa2c6, 0xe28889}, /* U+2209 NOT AN ELEMENT OF [2000] */ + {0xa2c7, 0xe28885}, /* U+2205 EMPTY SET [2000] */ + {0xa2c8, 0xe28c85}, /* U+2305 PROJECTIVE [2000] */ + {0xa2c9, 0xe28c86}, /* U+2306 PERSPECTIVE [2000] */ + {0xa2ca, 0xe288a7}, /* U+2227 LOGICAL AND [1983] */ + {0xa2cb, 0xe288a8}, /* U+2228 LOGICAL OR [1983] */ + {0xa2cc, 0xc2ac}, /* U+00AC NOT SIGN [1983] Windows: U+FFE2 */ + {0xa2cd, 0xe28792}, /* U+21D2 RIGHTWARDS DOUBLE ARROW [1983] */ + {0xa2ce, 0xe28794}, /* U+21D4 LEFT RIGHT DOUBLE ARROW [1983] */ + {0xa2cf, 0xe28880}, /* U+2200 FOR ALL [1983] */ + {0xa2d0, 0xe28883}, /* U+2203 THERE EXISTS [1983] */ + {0xa2d1, 0xe28a95}, /* U+2295 CIRCLED PLUS [2000] */ + {0xa2d2, 0xe28a96}, /* U+2296 CIRCLED MINUS [2000] */ + {0xa2d3, 0xe28a97}, /* U+2297 CIRCLED TIMES [2000] */ + {0xa2d4, 0xe288a5}, /* U+2225 PARALLEL TO [2000] */ + {0xa2d5, 0xe288a6}, /* U+2226 NOT PARALLEL TO [2000] */ + {0xa2d6, 0xefbd9f}, /* U+FF5F FULLWIDTH LEFT WHITE PARENTHESIS [2000] [Unicode3.2] */ + {0xa2d7, 0xefbda0}, /* U+FF60 FULLWIDTH RIGHT WHITE PARENTHESIS [2000] [Unicode3.2] */ + {0xa2d8, 0xe38098}, /* U+3018 LEFT WHITE TORTOISE SHELL BRACKET [2000] */ + {0xa2d9, 0xe38099}, /* U+3019 RIGHT WHITE TORTOISE SHELL BRACKET [2000] */ + {0xa2da, 0xe38096}, /* U+3016 LEFT WHITE LENTICULAR BRACKET [2000] */ + {0xa2db, 0xe38097}, /* U+3017 RIGHT WHITE LENTICULAR BRACKET [2000] */ + {0xa2dc, 0xe288a0}, /* U+2220 ANGLE [1983] */ + {0xa2dd, 0xe28aa5}, /* U+22A5 UP TACK [1983] */ + {0xa2de, 0xe28c92}, /* U+2312 ARC [1983] */ + {0xa2df, 0xe28882}, /* U+2202 PARTIAL DIFFERENTIAL [1983] */ + {0xa2e0, 0xe28887}, /* U+2207 NABLA [1983] */ + {0xa2e1, 0xe289a1}, /* U+2261 IDENTICAL TO [1983] */ + {0xa2e2, 0xe28992}, /* U+2252 APPROXIMATELY EQUAL TO OR THE IMAGE OF [1983] */ + {0xa2e3, 0xe289aa}, /* U+226A MUCH LESS-THAN [1983] */ + {0xa2e4, 0xe289ab}, /* U+226B MUCH GREATER-THAN [1983] */ + {0xa2e5, 0xe2889a}, /* U+221A SQUARE ROOT [1983] */ + {0xa2e6, 0xe288bd}, /* U+223D REVERSED TILDE [1983] */ + {0xa2e7, 0xe2889d}, /* U+221D PROPORTIONAL TO [1983] */ + {0xa2e8, 0xe288b5}, /* U+2235 BECAUSE [1983] */ + {0xa2e9, 0xe288ab}, /* U+222B INTEGRAL [1983] */ + {0xa2ea, 0xe288ac}, /* U+222C DOUBLE INTEGRAL [1983] */ + {0xa2eb, 0xe289a2}, /* U+2262 NOT IDENTICAL TO [2000] */ + {0xa2ec, 0xe28983}, /* U+2243 ASYMPTOTICALLY EQUAL TO [2000] */ + {0xa2ed, 0xe28985}, /* U+2245 APPROXIMATELY EQUAL TO [2000] */ + {0xa2ee, 0xe28988}, /* U+2248 ALMOST EQUAL TO [2000] */ + {0xa2ef, 0xe289b6}, /* U+2276 LESS-THAN OR GREATER-THAN [2000] */ + {0xa2f0, 0xe289b7}, /* U+2277 GREATER-THAN OR LESS-THAN [2000] */ + {0xa2f1, 0xe28694}, /* U+2194 LEFT RIGHT ARROW [2000] */ + {0xa2f2, 0xe284ab}, /* U+212B ANGSTROM SIGN [1983] */ + {0xa2f3, 0xe280b0}, /* U+2030 PER MILLE SIGN [1983] */ + {0xa2f4, 0xe299af}, /* U+266F MUSIC SHARP SIGN [1983] */ + {0xa2f5, 0xe299ad}, /* U+266D MUSIC FLAT SIGN [1983] */ + {0xa2f6, 0xe299aa}, /* U+266A EIGHTH NOTE [1983] */ + {0xa2f7, 0xe280a0}, /* U+2020 DAGGER [1983] */ + {0xa2f8, 0xe280a1}, /* U+2021 DOUBLE DAGGER [1983] */ + {0xa2f9, 0xc2b6}, /* U+00B6 PILCROW SIGN [1983] */ + {0xa2fa, 0xe299ae}, /* U+266E MUSIC NATURAL SIGN [2000] */ + {0xa2fb, 0xe299ab}, /* U+266B BEAMED EIGHTH NOTES [2000] */ + {0xa2fc, 0xe299ac}, /* U+266C BEAMED SIXTEENTH NOTES [2000] */ + {0xa2fd, 0xe299a9}, /* U+2669 QUARTER NOTE [2000] */ + {0xa2fe, 0xe297af}, /* U+25EF LARGE CIRCLE [1983] */ + {0xa3a1, 0xe296b7}, /* U+25B7 WHITE RIGHT-POINTING TRIANGLE [2000] */ + {0xa3a2, 0xe296b6}, /* U+25B6 BLACK RIGHT-POINTING TRIANGLE [2000] */ + {0xa3a3, 0xe29781}, /* U+25C1 WHITE LEFT-POINTING TRIANGLE [2000] */ + {0xa3a4, 0xe29780}, /* U+25C0 BLACK LEFT-POINTING TRIANGLE [2000] */ + {0xa3a5, 0xe28697}, /* U+2197 NORTH EAST ARROW [2000] */ + {0xa3a6, 0xe28698}, /* U+2198 SOUTH EAST ARROW [2000] */ + {0xa3a7, 0xe28696}, /* U+2196 NORTH WEST ARROW [2000] */ + {0xa3a8, 0xe28699}, /* U+2199 SOUTH WEST ARROW [2000] */ + {0xa3a9, 0xe28784}, /* U+21C4 RIGHTWARDS ARROW OVER LEFTWARDS ARROW [2000] */ + {0xa3aa, 0xe287a8}, /* U+21E8 RIGHTWARDS WHITE ARROW [2000] */ + {0xa3ab, 0xe287a6}, /* U+21E6 LEFTWARDS WHITE ARROW [2000] */ + {0xa3ac, 0xe287a7}, /* U+21E7 UPWARDS WHITE ARROW [2000] */ + {0xa3ad, 0xe287a9}, /* U+21E9 DOWNWARDS WHITE ARROW [2000] */ + {0xa3ae, 0xe2a4b4}, /* U+2934 ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS [2000] [Unicode3.2] */ + {0xa3af, 0xe2a4b5}, /* U+2935 ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS [2000] [Unicode3.2] */ + {0xa3b0, 0xefbc90}, /* U+FF10 FULLWIDTH DIGIT ZERO */ + {0xa3b1, 0xefbc91}, /* U+FF11 FULLWIDTH DIGIT ONE */ + {0xa3b2, 0xefbc92}, /* U+FF12 FULLWIDTH DIGIT TWO */ + {0xa3b3, 0xefbc93}, /* U+FF13 FULLWIDTH DIGIT THREE */ + {0xa3b4, 0xefbc94}, /* U+FF14 FULLWIDTH DIGIT FOUR */ + {0xa3b5, 0xefbc95}, /* U+FF15 FULLWIDTH DIGIT FIVE */ + {0xa3b6, 0xefbc96}, /* U+FF16 FULLWIDTH DIGIT SIX */ + {0xa3b7, 0xefbc97}, /* U+FF17 FULLWIDTH DIGIT SEVEN */ + {0xa3b8, 0xefbc98}, /* U+FF18 FULLWIDTH DIGIT EIGHT */ + {0xa3b9, 0xefbc99}, /* U+FF19 FULLWIDTH DIGIT NINE */ + {0xa3ba, 0xe2a6bf}, /* U+29BF CIRCLED BULLET [2000] [Unicode3.2] */ + {0xa3bb, 0xe29789}, /* U+25C9 FISHEYE [2000] */ + {0xa3bc, 0xe380bd}, /* U+303D PART ALTERNATION MARK [2000] [Unicode3.2] */ + {0xa3bd, 0xefb986}, /* U+FE46 WHITE SESAME DOT [2000] [Unicode3.2] */ + {0xa3be, 0xefb985}, /* U+FE45 SESAME DOT [2000] [Unicode3.2] */ + {0xa3bf, 0xe297a6}, /* U+25E6 WHITE BULLET [2000] */ + {0xa3c0, 0xe280a2}, /* U+2022 BULLET [2000] */ + {0xa3c1, 0xefbca1}, /* U+FF21 FULLWIDTH LATIN CAPITAL LETTER A */ + {0xa3c2, 0xefbca2}, /* U+FF22 FULLWIDTH LATIN CAPITAL LETTER B */ + {0xa3c3, 0xefbca3}, /* U+FF23 FULLWIDTH LATIN CAPITAL LETTER C */ + {0xa3c4, 0xefbca4}, /* U+FF24 FULLWIDTH LATIN CAPITAL LETTER D */ + {0xa3c5, 0xefbca5}, /* U+FF25 FULLWIDTH LATIN CAPITAL LETTER E */ + {0xa3c6, 0xefbca6}, /* U+FF26 FULLWIDTH LATIN CAPITAL LETTER F */ + {0xa3c7, 0xefbca7}, /* U+FF27 FULLWIDTH LATIN CAPITAL LETTER G */ + {0xa3c8, 0xefbca8}, /* U+FF28 FULLWIDTH LATIN CAPITAL LETTER H */ + {0xa3c9, 0xefbca9}, /* U+FF29 FULLWIDTH LATIN CAPITAL LETTER I */ + {0xa3ca, 0xefbcaa}, /* U+FF2A FULLWIDTH LATIN CAPITAL LETTER J */ + {0xa3cb, 0xefbcab}, /* U+FF2B FULLWIDTH LATIN CAPITAL LETTER K */ + {0xa3cc, 0xefbcac}, /* U+FF2C FULLWIDTH LATIN CAPITAL LETTER L */ + {0xa3cd, 0xefbcad}, /* U+FF2D FULLWIDTH LATIN CAPITAL LETTER M */ + {0xa3ce, 0xefbcae}, /* U+FF2E FULLWIDTH LATIN CAPITAL LETTER N */ + {0xa3cf, 0xefbcaf}, /* U+FF2F FULLWIDTH LATIN CAPITAL LETTER O */ + {0xa3d0, 0xefbcb0}, /* U+FF30 FULLWIDTH LATIN CAPITAL LETTER P */ + {0xa3d1, 0xefbcb1}, /* U+FF31 FULLWIDTH LATIN CAPITAL LETTER Q */ + {0xa3d2, 0xefbcb2}, /* U+FF32 FULLWIDTH LATIN CAPITAL LETTER R */ + {0xa3d3, 0xefbcb3}, /* U+FF33 FULLWIDTH LATIN CAPITAL LETTER S */ + {0xa3d4, 0xefbcb4}, /* U+FF34 FULLWIDTH LATIN CAPITAL LETTER T */ + {0xa3d5, 0xefbcb5}, /* U+FF35 FULLWIDTH LATIN CAPITAL LETTER U */ + {0xa3d6, 0xefbcb6}, /* U+FF36 FULLWIDTH LATIN CAPITAL LETTER V */ + {0xa3d7, 0xefbcb7}, /* U+FF37 FULLWIDTH LATIN CAPITAL LETTER W */ + {0xa3d8, 0xefbcb8}, /* U+FF38 FULLWIDTH LATIN CAPITAL LETTER X */ + {0xa3d9, 0xefbcb9}, /* U+FF39 FULLWIDTH LATIN CAPITAL LETTER Y */ + {0xa3da, 0xefbcba}, /* U+FF3A FULLWIDTH LATIN CAPITAL LETTER Z */ + {0xa3db, 0xe28893}, /* U+2213 MINUS-OR-PLUS SIGN [2000] */ + {0xa3dc, 0xe284b5}, /* U+2135 ALEF SYMBOL [2000] */ + {0xa3dd, 0xe2848f}, /* U+210F PLANCK CONSTANT OVER TWO PI [2000] */ + {0xa3de, 0xe38f8b}, /* U+33CB SQUARE HP [2000] */ + {0xa3df, 0xe28493}, /* U+2113 SCRIPT SMALL L [2000] */ + {0xa3e0, 0xe284a7}, /* U+2127 INVERTED OHM SIGN [2000] */ + {0xa3e1, 0xefbd81}, /* U+FF41 FULLWIDTH LATIN SMALL LETTER A */ + {0xa3e2, 0xefbd82}, /* U+FF42 FULLWIDTH LATIN SMALL LETTER B */ + {0xa3e3, 0xefbd83}, /* U+FF43 FULLWIDTH LATIN SMALL LETTER C */ + {0xa3e4, 0xefbd84}, /* U+FF44 FULLWIDTH LATIN SMALL LETTER D */ + {0xa3e5, 0xefbd85}, /* U+FF45 FULLWIDTH LATIN SMALL LETTER E */ + {0xa3e6, 0xefbd86}, /* U+FF46 FULLWIDTH LATIN SMALL LETTER F */ + {0xa3e7, 0xefbd87}, /* U+FF47 FULLWIDTH LATIN SMALL LETTER G */ + {0xa3e8, 0xefbd88}, /* U+FF48 FULLWIDTH LATIN SMALL LETTER H */ + {0xa3e9, 0xefbd89}, /* U+FF49 FULLWIDTH LATIN SMALL LETTER I */ + {0xa3ea, 0xefbd8a}, /* U+FF4A FULLWIDTH LATIN SMALL LETTER J */ + {0xa3eb, 0xefbd8b}, /* U+FF4B FULLWIDTH LATIN SMALL LETTER K */ + {0xa3ec, 0xefbd8c}, /* U+FF4C FULLWIDTH LATIN SMALL LETTER L */ + {0xa3ed, 0xefbd8d}, /* U+FF4D FULLWIDTH LATIN SMALL LETTER M */ + {0xa3ee, 0xefbd8e}, /* U+FF4E FULLWIDTH LATIN SMALL LETTER N */ + {0xa3ef, 0xefbd8f}, /* U+FF4F FULLWIDTH LATIN SMALL LETTER O */ + {0xa3f0, 0xefbd90}, /* U+FF50 FULLWIDTH LATIN SMALL LETTER P */ + {0xa3f1, 0xefbd91}, /* U+FF51 FULLWIDTH LATIN SMALL LETTER Q */ + {0xa3f2, 0xefbd92}, /* U+FF52 FULLWIDTH LATIN SMALL LETTER R */ + {0xa3f3, 0xefbd93}, /* U+FF53 FULLWIDTH LATIN SMALL LETTER S */ + {0xa3f4, 0xefbd94}, /* U+FF54 FULLWIDTH LATIN SMALL LETTER T */ + {0xa3f5, 0xefbd95}, /* U+FF55 FULLWIDTH LATIN SMALL LETTER U */ + {0xa3f6, 0xefbd96}, /* U+FF56 FULLWIDTH LATIN SMALL LETTER V */ + {0xa3f7, 0xefbd97}, /* U+FF57 FULLWIDTH LATIN SMALL LETTER W */ + {0xa3f8, 0xefbd98}, /* U+FF58 FULLWIDTH LATIN SMALL LETTER X */ + {0xa3f9, 0xefbd99}, /* U+FF59 FULLWIDTH LATIN SMALL LETTER Y */ + {0xa3fa, 0xefbd9a}, /* U+FF5A FULLWIDTH LATIN SMALL LETTER Z */ + {0xa3fb, 0xe382a0}, /* U+30A0 KATAKANA-HIRAGANA DOUBLE HYPHEN [2000] [Unicode3.2] */ + {0xa3fc, 0xe28093}, /* U+2013 EN DASH [2000] */ + {0xa3fd, 0xe2a7ba}, /* U+29FA DOUBLE PLUS [2000] [Unicode3.2] */ + {0xa3fe, 0xe2a7bb}, /* U+29FB TRIPLE PLUS [2000] [Unicode3.2] */ + {0xa4a1, 0xe38181}, /* U+3041 HIRAGANA LETTER SMALL A */ + {0xa4a2, 0xe38182}, /* U+3042 HIRAGANA LETTER A */ + {0xa4a3, 0xe38183}, /* U+3043 HIRAGANA LETTER SMALL I */ + {0xa4a4, 0xe38184}, /* U+3044 HIRAGANA LETTER I */ + {0xa4a5, 0xe38185}, /* U+3045 HIRAGANA LETTER SMALL U */ + {0xa4a6, 0xe38186}, /* U+3046 HIRAGANA LETTER U */ + {0xa4a7, 0xe38187}, /* U+3047 HIRAGANA LETTER SMALL E */ + {0xa4a8, 0xe38188}, /* U+3048 HIRAGANA LETTER E */ + {0xa4a9, 0xe38189}, /* U+3049 HIRAGANA LETTER SMALL O */ + {0xa4aa, 0xe3818a}, /* U+304A HIRAGANA LETTER O */ + {0xa4ab, 0xe3818b}, /* U+304B HIRAGANA LETTER KA */ + {0xa4ac, 0xe3818c}, /* U+304C HIRAGANA LETTER GA */ + {0xa4ad, 0xe3818d}, /* U+304D HIRAGANA LETTER KI */ + {0xa4ae, 0xe3818e}, /* U+304E HIRAGANA LETTER GI */ + {0xa4af, 0xe3818f}, /* U+304F HIRAGANA LETTER KU */ + {0xa4b0, 0xe38190}, /* U+3050 HIRAGANA LETTER GU */ + {0xa4b1, 0xe38191}, /* U+3051 HIRAGANA LETTER KE */ + {0xa4b2, 0xe38192}, /* U+3052 HIRAGANA LETTER GE */ + {0xa4b3, 0xe38193}, /* U+3053 HIRAGANA LETTER KO */ + {0xa4b4, 0xe38194}, /* U+3054 HIRAGANA LETTER GO */ + {0xa4b5, 0xe38195}, /* U+3055 HIRAGANA LETTER SA */ + {0xa4b6, 0xe38196}, /* U+3056 HIRAGANA LETTER ZA */ + {0xa4b7, 0xe38197}, /* U+3057 HIRAGANA LETTER SI */ + {0xa4b8, 0xe38198}, /* U+3058 HIRAGANA LETTER ZI */ + {0xa4b9, 0xe38199}, /* U+3059 HIRAGANA LETTER SU */ + {0xa4ba, 0xe3819a}, /* U+305A HIRAGANA LETTER ZU */ + {0xa4bb, 0xe3819b}, /* U+305B HIRAGANA LETTER SE */ + {0xa4bc, 0xe3819c}, /* U+305C HIRAGANA LETTER ZE */ + {0xa4bd, 0xe3819d}, /* U+305D HIRAGANA LETTER SO */ + {0xa4be, 0xe3819e}, /* U+305E HIRAGANA LETTER ZO */ + {0xa4bf, 0xe3819f}, /* U+305F HIRAGANA LETTER TA */ + {0xa4c0, 0xe381a0}, /* U+3060 HIRAGANA LETTER DA */ + {0xa4c1, 0xe381a1}, /* U+3061 HIRAGANA LETTER TI */ + {0xa4c2, 0xe381a2}, /* U+3062 HIRAGANA LETTER DI */ + {0xa4c3, 0xe381a3}, /* U+3063 HIRAGANA LETTER SMALL TU */ + {0xa4c4, 0xe381a4}, /* U+3064 HIRAGANA LETTER TU */ + {0xa4c5, 0xe381a5}, /* U+3065 HIRAGANA LETTER DU */ + {0xa4c6, 0xe381a6}, /* U+3066 HIRAGANA LETTER TE */ + {0xa4c7, 0xe381a7}, /* U+3067 HIRAGANA LETTER DE */ + {0xa4c8, 0xe381a8}, /* U+3068 HIRAGANA LETTER TO */ + {0xa4c9, 0xe381a9}, /* U+3069 HIRAGANA LETTER DO */ + {0xa4ca, 0xe381aa}, /* U+306A HIRAGANA LETTER NA */ + {0xa4cb, 0xe381ab}, /* U+306B HIRAGANA LETTER NI */ + {0xa4cc, 0xe381ac}, /* U+306C HIRAGANA LETTER NU */ + {0xa4cd, 0xe381ad}, /* U+306D HIRAGANA LETTER NE */ + {0xa4ce, 0xe381ae}, /* U+306E HIRAGANA LETTER NO */ + {0xa4cf, 0xe381af}, /* U+306F HIRAGANA LETTER HA */ + {0xa4d0, 0xe381b0}, /* U+3070 HIRAGANA LETTER BA */ + {0xa4d1, 0xe381b1}, /* U+3071 HIRAGANA LETTER PA */ + {0xa4d2, 0xe381b2}, /* U+3072 HIRAGANA LETTER HI */ + {0xa4d3, 0xe381b3}, /* U+3073 HIRAGANA LETTER BI */ + {0xa4d4, 0xe381b4}, /* U+3074 HIRAGANA LETTER PI */ + {0xa4d5, 0xe381b5}, /* U+3075 HIRAGANA LETTER HU */ + {0xa4d6, 0xe381b6}, /* U+3076 HIRAGANA LETTER BU */ + {0xa4d7, 0xe381b7}, /* U+3077 HIRAGANA LETTER PU */ + {0xa4d8, 0xe381b8}, /* U+3078 HIRAGANA LETTER HE */ + {0xa4d9, 0xe381b9}, /* U+3079 HIRAGANA LETTER BE */ + {0xa4da, 0xe381ba}, /* U+307A HIRAGANA LETTER PE */ + {0xa4db, 0xe381bb}, /* U+307B HIRAGANA LETTER HO */ + {0xa4dc, 0xe381bc}, /* U+307C HIRAGANA LETTER BO */ + {0xa4dd, 0xe381bd}, /* U+307D HIRAGANA LETTER PO */ + {0xa4de, 0xe381be}, /* U+307E HIRAGANA LETTER MA */ + {0xa4df, 0xe381bf}, /* U+307F HIRAGANA LETTER MI */ + {0xa4e0, 0xe38280}, /* U+3080 HIRAGANA LETTER MU */ + {0xa4e1, 0xe38281}, /* U+3081 HIRAGANA LETTER ME */ + {0xa4e2, 0xe38282}, /* U+3082 HIRAGANA LETTER MO */ + {0xa4e3, 0xe38283}, /* U+3083 HIRAGANA LETTER SMALL YA */ + {0xa4e4, 0xe38284}, /* U+3084 HIRAGANA LETTER YA */ + {0xa4e5, 0xe38285}, /* U+3085 HIRAGANA LETTER SMALL YU */ + {0xa4e6, 0xe38286}, /* U+3086 HIRAGANA LETTER YU */ + {0xa4e7, 0xe38287}, /* U+3087 HIRAGANA LETTER SMALL YO */ + {0xa4e8, 0xe38288}, /* U+3088 HIRAGANA LETTER YO */ + {0xa4e9, 0xe38289}, /* U+3089 HIRAGANA LETTER RA */ + {0xa4ea, 0xe3828a}, /* U+308A HIRAGANA LETTER RI */ + {0xa4eb, 0xe3828b}, /* U+308B HIRAGANA LETTER RU */ + {0xa4ec, 0xe3828c}, /* U+308C HIRAGANA LETTER RE */ + {0xa4ed, 0xe3828d}, /* U+308D HIRAGANA LETTER RO */ + {0xa4ee, 0xe3828e}, /* U+308E HIRAGANA LETTER SMALL WA */ + {0xa4ef, 0xe3828f}, /* U+308F HIRAGANA LETTER WA */ + {0xa4f0, 0xe38290}, /* U+3090 HIRAGANA LETTER WI */ + {0xa4f1, 0xe38291}, /* U+3091 HIRAGANA LETTER WE */ + {0xa4f2, 0xe38292}, /* U+3092 HIRAGANA LETTER WO */ + {0xa4f3, 0xe38293}, /* U+3093 HIRAGANA LETTER N */ + {0xa4f4, 0xe38294}, /* U+3094 HIRAGANA LETTER VU [2000] */ + {0xa4f5, 0xe38295}, /* U+3095 HIRAGANA LETTER SMALL KA [2000] [Unicode3.2] */ + {0xa4f6, 0xe38296}, /* U+3096 HIRAGANA LETTER SMALL KE [2000] [Unicode3.2] */ + {0xa5a1, 0xe382a1}, /* U+30A1 KATAKANA LETTER SMALL A */ + {0xa5a2, 0xe382a2}, /* U+30A2 KATAKANA LETTER A */ + {0xa5a3, 0xe382a3}, /* U+30A3 KATAKANA LETTER SMALL I */ + {0xa5a4, 0xe382a4}, /* U+30A4 KATAKANA LETTER I */ + {0xa5a5, 0xe382a5}, /* U+30A5 KATAKANA LETTER SMALL U */ + {0xa5a6, 0xe382a6}, /* U+30A6 KATAKANA LETTER U */ + {0xa5a7, 0xe382a7}, /* U+30A7 KATAKANA LETTER SMALL E */ + {0xa5a8, 0xe382a8}, /* U+30A8 KATAKANA LETTER E */ + {0xa5a9, 0xe382a9}, /* U+30A9 KATAKANA LETTER SMALL O */ + {0xa5aa, 0xe382aa}, /* U+30AA KATAKANA LETTER O */ + {0xa5ab, 0xe382ab}, /* U+30AB KATAKANA LETTER KA */ + {0xa5ac, 0xe382ac}, /* U+30AC KATAKANA LETTER GA */ + {0xa5ad, 0xe382ad}, /* U+30AD KATAKANA LETTER KI */ + {0xa5ae, 0xe382ae}, /* U+30AE KATAKANA LETTER GI */ + {0xa5af, 0xe382af}, /* U+30AF KATAKANA LETTER KU */ + {0xa5b0, 0xe382b0}, /* U+30B0 KATAKANA LETTER GU */ + {0xa5b1, 0xe382b1}, /* U+30B1 KATAKANA LETTER KE */ + {0xa5b2, 0xe382b2}, /* U+30B2 KATAKANA LETTER GE */ + {0xa5b3, 0xe382b3}, /* U+30B3 KATAKANA LETTER KO */ + {0xa5b4, 0xe382b4}, /* U+30B4 KATAKANA LETTER GO */ + {0xa5b5, 0xe382b5}, /* U+30B5 KATAKANA LETTER SA */ + {0xa5b6, 0xe382b6}, /* U+30B6 KATAKANA LETTER ZA */ + {0xa5b7, 0xe382b7}, /* U+30B7 KATAKANA LETTER SI */ + {0xa5b8, 0xe382b8}, /* U+30B8 KATAKANA LETTER ZI */ + {0xa5b9, 0xe382b9}, /* U+30B9 KATAKANA LETTER SU */ + {0xa5ba, 0xe382ba}, /* U+30BA KATAKANA LETTER ZU */ + {0xa5bb, 0xe382bb}, /* U+30BB KATAKANA LETTER SE */ + {0xa5bc, 0xe382bc}, /* U+30BC KATAKANA LETTER ZE */ + {0xa5bd, 0xe382bd}, /* U+30BD KATAKANA LETTER SO */ + {0xa5be, 0xe382be}, /* U+30BE KATAKANA LETTER ZO */ + {0xa5bf, 0xe382bf}, /* U+30BF KATAKANA LETTER TA */ + {0xa5c0, 0xe38380}, /* U+30C0 KATAKANA LETTER DA */ + {0xa5c1, 0xe38381}, /* U+30C1 KATAKANA LETTER TI */ + {0xa5c2, 0xe38382}, /* U+30C2 KATAKANA LETTER DI */ + {0xa5c3, 0xe38383}, /* U+30C3 KATAKANA LETTER SMALL TU */ + {0xa5c4, 0xe38384}, /* U+30C4 KATAKANA LETTER TU */ + {0xa5c5, 0xe38385}, /* U+30C5 KATAKANA LETTER DU */ + {0xa5c6, 0xe38386}, /* U+30C6 KATAKANA LETTER TE */ + {0xa5c7, 0xe38387}, /* U+30C7 KATAKANA LETTER DE */ + {0xa5c8, 0xe38388}, /* U+30C8 KATAKANA LETTER TO */ + {0xa5c9, 0xe38389}, /* U+30C9 KATAKANA LETTER DO */ + {0xa5ca, 0xe3838a}, /* U+30CA KATAKANA LETTER NA */ + {0xa5cb, 0xe3838b}, /* U+30CB KATAKANA LETTER NI */ + {0xa5cc, 0xe3838c}, /* U+30CC KATAKANA LETTER NU */ + {0xa5cd, 0xe3838d}, /* U+30CD KATAKANA LETTER NE */ + {0xa5ce, 0xe3838e}, /* U+30CE KATAKANA LETTER NO */ + {0xa5cf, 0xe3838f}, /* U+30CF KATAKANA LETTER HA */ + {0xa5d0, 0xe38390}, /* U+30D0 KATAKANA LETTER BA */ + {0xa5d1, 0xe38391}, /* U+30D1 KATAKANA LETTER PA */ + {0xa5d2, 0xe38392}, /* U+30D2 KATAKANA LETTER HI */ + {0xa5d3, 0xe38393}, /* U+30D3 KATAKANA LETTER BI */ + {0xa5d4, 0xe38394}, /* U+30D4 KATAKANA LETTER PI */ + {0xa5d5, 0xe38395}, /* U+30D5 KATAKANA LETTER HU */ + {0xa5d6, 0xe38396}, /* U+30D6 KATAKANA LETTER BU */ + {0xa5d7, 0xe38397}, /* U+30D7 KATAKANA LETTER PU */ + {0xa5d8, 0xe38398}, /* U+30D8 KATAKANA LETTER HE */ + {0xa5d9, 0xe38399}, /* U+30D9 KATAKANA LETTER BE */ + {0xa5da, 0xe3839a}, /* U+30DA KATAKANA LETTER PE */ + {0xa5db, 0xe3839b}, /* U+30DB KATAKANA LETTER HO */ + {0xa5dc, 0xe3839c}, /* U+30DC KATAKANA LETTER BO */ + {0xa5dd, 0xe3839d}, /* U+30DD KATAKANA LETTER PO */ + {0xa5de, 0xe3839e}, /* U+30DE KATAKANA LETTER MA */ + {0xa5df, 0xe3839f}, /* U+30DF KATAKANA LETTER MI */ + {0xa5e0, 0xe383a0}, /* U+30E0 KATAKANA LETTER MU */ + {0xa5e1, 0xe383a1}, /* U+30E1 KATAKANA LETTER ME */ + {0xa5e2, 0xe383a2}, /* U+30E2 KATAKANA LETTER MO */ + {0xa5e3, 0xe383a3}, /* U+30E3 KATAKANA LETTER SMALL YA */ + {0xa5e4, 0xe383a4}, /* U+30E4 KATAKANA LETTER YA */ + {0xa5e5, 0xe383a5}, /* U+30E5 KATAKANA LETTER SMALL YU */ + {0xa5e6, 0xe383a6}, /* U+30E6 KATAKANA LETTER YU */ + {0xa5e7, 0xe383a7}, /* U+30E7 KATAKANA LETTER SMALL YO */ + {0xa5e8, 0xe383a8}, /* U+30E8 KATAKANA LETTER YO */ + {0xa5e9, 0xe383a9}, /* U+30E9 KATAKANA LETTER RA */ + {0xa5ea, 0xe383aa}, /* U+30EA KATAKANA LETTER RI */ + {0xa5eb, 0xe383ab}, /* U+30EB KATAKANA LETTER RU */ + {0xa5ec, 0xe383ac}, /* U+30EC KATAKANA LETTER RE */ + {0xa5ed, 0xe383ad}, /* U+30ED KATAKANA LETTER RO */ + {0xa5ee, 0xe383ae}, /* U+30EE KATAKANA LETTER SMALL WA */ + {0xa5ef, 0xe383af}, /* U+30EF KATAKANA LETTER WA */ + {0xa5f0, 0xe383b0}, /* U+30F0 KATAKANA LETTER WI */ + {0xa5f1, 0xe383b1}, /* U+30F1 KATAKANA LETTER WE */ + {0xa5f2, 0xe383b2}, /* U+30F2 KATAKANA LETTER WO */ + {0xa5f3, 0xe383b3}, /* U+30F3 KATAKANA LETTER N */ + {0xa5f4, 0xe383b4}, /* U+30F4 KATAKANA LETTER VU */ + {0xa5f5, 0xe383b5}, /* U+30F5 KATAKANA LETTER SMALL KA */ + {0xa5f6, 0xe383b6}, /* U+30F6 KATAKANA LETTER SMALL KE */ + {0xa6a1, 0xce91}, /* U+0391 GREEK CAPITAL LETTER ALPHA */ + {0xa6a2, 0xce92}, /* U+0392 GREEK CAPITAL LETTER BETA */ + {0xa6a3, 0xce93}, /* U+0393 GREEK CAPITAL LETTER GAMMA */ + {0xa6a4, 0xce94}, /* U+0394 GREEK CAPITAL LETTER DELTA */ + {0xa6a5, 0xce95}, /* U+0395 GREEK CAPITAL LETTER EPSILON */ + {0xa6a6, 0xce96}, /* U+0396 GREEK CAPITAL LETTER ZETA */ + {0xa6a7, 0xce97}, /* U+0397 GREEK CAPITAL LETTER ETA */ + {0xa6a8, 0xce98}, /* U+0398 GREEK CAPITAL LETTER THETA */ + {0xa6a9, 0xce99}, /* U+0399 GREEK CAPITAL LETTER IOTA */ + {0xa6aa, 0xce9a}, /* U+039A GREEK CAPITAL LETTER KAPPA */ + {0xa6ab, 0xce9b}, /* U+039B GREEK CAPITAL LETTER LAMDA */ + {0xa6ac, 0xce9c}, /* U+039C GREEK CAPITAL LETTER MU */ + {0xa6ad, 0xce9d}, /* U+039D GREEK CAPITAL LETTER NU */ + {0xa6ae, 0xce9e}, /* U+039E GREEK CAPITAL LETTER XI */ + {0xa6af, 0xce9f}, /* U+039F GREEK CAPITAL LETTER OMICRON */ + {0xa6b0, 0xcea0}, /* U+03A0 GREEK CAPITAL LETTER PI */ + {0xa6b1, 0xcea1}, /* U+03A1 GREEK CAPITAL LETTER RHO */ + {0xa6b2, 0xcea3}, /* U+03A3 GREEK CAPITAL LETTER SIGMA */ + {0xa6b3, 0xcea4}, /* U+03A4 GREEK CAPITAL LETTER TAU */ + {0xa6b4, 0xcea5}, /* U+03A5 GREEK CAPITAL LETTER UPSILON */ + {0xa6b5, 0xcea6}, /* U+03A6 GREEK CAPITAL LETTER PHI */ + {0xa6b6, 0xcea7}, /* U+03A7 GREEK CAPITAL LETTER CHI */ + {0xa6b7, 0xcea8}, /* U+03A8 GREEK CAPITAL LETTER PSI */ + {0xa6b8, 0xcea9}, /* U+03A9 GREEK CAPITAL LETTER OMEGA */ + {0xa6b9, 0xe299a4}, /* U+2664 WHITE SPADE SUIT [2000] */ + {0xa6ba, 0xe299a0}, /* U+2660 BLACK SPADE SUIT [2000] */ + {0xa6bb, 0xe299a2}, /* U+2662 WHITE DIAMOND SUIT [2000] */ + {0xa6bc, 0xe299a6}, /* U+2666 BLACK DIAMOND SUIT [2000] */ + {0xa6bd, 0xe299a1}, /* U+2661 WHITE HEART SUIT [2000] */ + {0xa6be, 0xe299a5}, /* U+2665 BLACK HEART SUIT [2000] */ + {0xa6bf, 0xe299a7}, /* U+2667 WHITE CLUB SUIT [2000] */ + {0xa6c0, 0xe299a3}, /* U+2663 BLACK CLUB SUIT [2000] */ + {0xa6c1, 0xceb1}, /* U+03B1 GREEK SMALL LETTER ALPHA */ + {0xa6c2, 0xceb2}, /* U+03B2 GREEK SMALL LETTER BETA */ + {0xa6c3, 0xceb3}, /* U+03B3 GREEK SMALL LETTER GAMMA */ + {0xa6c4, 0xceb4}, /* U+03B4 GREEK SMALL LETTER DELTA */ + {0xa6c5, 0xceb5}, /* U+03B5 GREEK SMALL LETTER EPSILON */ + {0xa6c6, 0xceb6}, /* U+03B6 GREEK SMALL LETTER ZETA */ + {0xa6c7, 0xceb7}, /* U+03B7 GREEK SMALL LETTER ETA */ + {0xa6c8, 0xceb8}, /* U+03B8 GREEK SMALL LETTER THETA */ + {0xa6c9, 0xceb9}, /* U+03B9 GREEK SMALL LETTER IOTA */ + {0xa6ca, 0xceba}, /* U+03BA GREEK SMALL LETTER KAPPA */ + {0xa6cb, 0xcebb}, /* U+03BB GREEK SMALL LETTER LAMDA */ + {0xa6cc, 0xcebc}, /* U+03BC GREEK SMALL LETTER MU */ + {0xa6cd, 0xcebd}, /* U+03BD GREEK SMALL LETTER NU */ + {0xa6ce, 0xcebe}, /* U+03BE GREEK SMALL LETTER XI */ + {0xa6cf, 0xcebf}, /* U+03BF GREEK SMALL LETTER OMICRON */ + {0xa6d0, 0xcf80}, /* U+03C0 GREEK SMALL LETTER PI */ + {0xa6d1, 0xcf81}, /* U+03C1 GREEK SMALL LETTER RHO */ + {0xa6d2, 0xcf83}, /* U+03C3 GREEK SMALL LETTER SIGMA */ + {0xa6d3, 0xcf84}, /* U+03C4 GREEK SMALL LETTER TAU */ + {0xa6d4, 0xcf85}, /* U+03C5 GREEK SMALL LETTER UPSILON */ + {0xa6d5, 0xcf86}, /* U+03C6 GREEK SMALL LETTER PHI */ + {0xa6d6, 0xcf87}, /* U+03C7 GREEK SMALL LETTER CHI */ + {0xa6d7, 0xcf88}, /* U+03C8 GREEK SMALL LETTER PSI */ + {0xa6d8, 0xcf89}, /* U+03C9 GREEK SMALL LETTER OMEGA */ + {0xa6d9, 0xcf82}, /* U+03C2 GREEK SMALL LETTER FINAL SIGMA [2000] */ + {0xa6da, 0xe293b5}, /* U+24F5 DOUBLE CIRCLED DIGIT ONE [2000] [Unicode3.2] */ + {0xa6db, 0xe293b6}, /* U+24F6 DOUBLE CIRCLED DIGIT TWO [2000] [Unicode3.2] */ + {0xa6dc, 0xe293b7}, /* U+24F7 DOUBLE CIRCLED DIGIT THREE [2000] [Unicode3.2] */ + {0xa6dd, 0xe293b8}, /* U+24F8 DOUBLE CIRCLED DIGIT FOUR [2000] [Unicode3.2] */ + {0xa6de, 0xe293b9}, /* U+24F9 DOUBLE CIRCLED DIGIT FIVE [2000] [Unicode3.2] */ + {0xa6df, 0xe293ba}, /* U+24FA DOUBLE CIRCLED DIGIT SIX [2000] [Unicode3.2] */ + {0xa6e0, 0xe293bb}, /* U+24FB DOUBLE CIRCLED DIGIT SEVEN [2000] [Unicode3.2] */ + {0xa6e1, 0xe293bc}, /* U+24FC DOUBLE CIRCLED DIGIT EIGHT [2000] [Unicode3.2] */ + {0xa6e2, 0xe293bd}, /* U+24FD DOUBLE CIRCLED DIGIT NINE [2000] [Unicode3.2] */ + {0xa6e3, 0xe293be}, /* U+24FE DOUBLE CIRCLED NUMBER TEN [2000] [Unicode3.2] */ + {0xa6e4, 0xe29896}, /* U+2616 WHITE SHOGI PIECE [2000] [Unicode3.2] */ + {0xa6e5, 0xe29897}, /* U+2617 BLACK SHOGI PIECE [2000] [Unicode3.2] */ + {0xa6e6, 0xe380a0}, /* U+3020 POSTAL MARK FACE [2000] */ + {0xa6e7, 0xe2988e}, /* U+260E BLACK TELEPHONE [2000] */ + {0xa6e8, 0xe29880}, /* U+2600 BLACK SUN WITH RAYS [2000] */ + {0xa6e9, 0xe29881}, /* U+2601 CLOUD [2000] */ + {0xa6ea, 0xe29882}, /* U+2602 UMBRELLA [2000] */ + {0xa6eb, 0xe29883}, /* U+2603 SNOWMAN [2000] */ + {0xa6ec, 0xe299a8}, /* U+2668 HOT SPRINGS [2000] */ + {0xa6ed, 0xe296b1}, /* U+25B1 WHITE PARALLELOGRAM [2000] */ + {0xa6ee, 0xe387b0}, /* U+31F0 KATAKANA LETTER SMALL KU [2000] [Unicode3.2] */ + {0xa6ef, 0xe387b1}, /* U+31F1 KATAKANA LETTER SMALL SI [2000] [Unicode3.2] */ + {0xa6f0, 0xe387b2}, /* U+31F2 KATAKANA LETTER SMALL SU [2000] [Unicode3.2] */ + {0xa6f1, 0xe387b3}, /* U+31F3 KATAKANA LETTER SMALL TO [2000] [Unicode3.2] */ + {0xa6f2, 0xe387b4}, /* U+31F4 KATAKANA LETTER SMALL NU [2000] [Unicode3.2] */ + {0xa6f3, 0xe387b5}, /* U+31F5 KATAKANA LETTER SMALL HA [2000] [Unicode3.2] */ + {0xa6f4, 0xe387b6}, /* U+31F6 KATAKANA LETTER SMALL HI [2000] [Unicode3.2] */ + {0xa6f5, 0xe387b7}, /* U+31F7 KATAKANA LETTER SMALL HU [2000] [Unicode3.2] */ + {0xa6f6, 0xe387b8}, /* U+31F8 KATAKANA LETTER SMALL HE [2000] [Unicode3.2] */ + {0xa6f7, 0xe387b9}, /* U+31F9 KATAKANA LETTER SMALL HO [2000] [Unicode3.2] */ + {0xa6f9, 0xe387ba}, /* U+31FA KATAKANA LETTER SMALL MU [2000] [Unicode3.2] */ + {0xa6fa, 0xe387bb}, /* U+31FB KATAKANA LETTER SMALL RA [2000] [Unicode3.2] */ + {0xa6fb, 0xe387bc}, /* U+31FC KATAKANA LETTER SMALL RI [2000] [Unicode3.2] */ + {0xa6fc, 0xe387bd}, /* U+31FD KATAKANA LETTER SMALL RU [2000] [Unicode3.2] */ + {0xa6fd, 0xe387be}, /* U+31FE KATAKANA LETTER SMALL RE [2000] [Unicode3.2] */ + {0xa6fe, 0xe387bf}, /* U+31FF KATAKANA LETTER SMALL RO [2000] [Unicode3.2] */ + {0xa7a1, 0xd090}, /* U+0410 CYRILLIC CAPITAL LETTER A */ + {0xa7a2, 0xd091}, /* U+0411 CYRILLIC CAPITAL LETTER BE */ + {0xa7a3, 0xd092}, /* U+0412 CYRILLIC CAPITAL LETTER VE */ + {0xa7a4, 0xd093}, /* U+0413 CYRILLIC CAPITAL LETTER GHE */ + {0xa7a5, 0xd094}, /* U+0414 CYRILLIC CAPITAL LETTER DE */ + {0xa7a6, 0xd095}, /* U+0415 CYRILLIC CAPITAL LETTER IE */ + {0xa7a7, 0xd081}, /* U+0401 CYRILLIC CAPITAL LETTER IO */ + {0xa7a8, 0xd096}, /* U+0416 CYRILLIC CAPITAL LETTER ZHE */ + {0xa7a9, 0xd097}, /* U+0417 CYRILLIC CAPITAL LETTER ZE */ + {0xa7aa, 0xd098}, /* U+0418 CYRILLIC CAPITAL LETTER I */ + {0xa7ab, 0xd099}, /* U+0419 CYRILLIC CAPITAL LETTER SHORT I */ + {0xa7ac, 0xd09a}, /* U+041A CYRILLIC CAPITAL LETTER KA */ + {0xa7ad, 0xd09b}, /* U+041B CYRILLIC CAPITAL LETTER EL */ + {0xa7ae, 0xd09c}, /* U+041C CYRILLIC CAPITAL LETTER EM */ + {0xa7af, 0xd09d}, /* U+041D CYRILLIC CAPITAL LETTER EN */ + {0xa7b0, 0xd09e}, /* U+041E CYRILLIC CAPITAL LETTER O */ + {0xa7b1, 0xd09f}, /* U+041F CYRILLIC CAPITAL LETTER PE */ + {0xa7b2, 0xd0a0}, /* U+0420 CYRILLIC CAPITAL LETTER ER */ + {0xa7b3, 0xd0a1}, /* U+0421 CYRILLIC CAPITAL LETTER ES */ + {0xa7b4, 0xd0a2}, /* U+0422 CYRILLIC CAPITAL LETTER TE */ + {0xa7b5, 0xd0a3}, /* U+0423 CYRILLIC CAPITAL LETTER U */ + {0xa7b6, 0xd0a4}, /* U+0424 CYRILLIC CAPITAL LETTER EF */ + {0xa7b7, 0xd0a5}, /* U+0425 CYRILLIC CAPITAL LETTER HA */ + {0xa7b8, 0xd0a6}, /* U+0426 CYRILLIC CAPITAL LETTER TSE */ + {0xa7b9, 0xd0a7}, /* U+0427 CYRILLIC CAPITAL LETTER CHE */ + {0xa7ba, 0xd0a8}, /* U+0428 CYRILLIC CAPITAL LETTER SHA */ + {0xa7bb, 0xd0a9}, /* U+0429 CYRILLIC CAPITAL LETTER SHCHA */ + {0xa7bc, 0xd0aa}, /* U+042A CYRILLIC CAPITAL LETTER HARD SIGN */ + {0xa7bd, 0xd0ab}, /* U+042B CYRILLIC CAPITAL LETTER YERU */ + {0xa7be, 0xd0ac}, /* U+042C CYRILLIC CAPITAL LETTER SOFT SIGN */ + {0xa7bf, 0xd0ad}, /* U+042D CYRILLIC CAPITAL LETTER E */ + {0xa7c0, 0xd0ae}, /* U+042E CYRILLIC CAPITAL LETTER YU */ + {0xa7c1, 0xd0af}, /* U+042F CYRILLIC CAPITAL LETTER YA */ + {0xa7c2, 0xe28ebe}, /* U+23BE DENTISTRY SYMBOL LIGHT VERTICAL AND TOP RIGHT [2000] [Unicode3.2] */ + {0xa7c3, 0xe28ebf}, /* U+23BF DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM RIGHT [2000] [Unicode3.2] */ + {0xa7c4, 0xe28f80}, /* U+23C0 DENTISTRY SYMBOL LIGHT VERTICAL WITH CIRCLE [2000] [Unicode3.2] */ + {0xa7c5, 0xe28f81}, /* U+23C1 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH CIRCLE [2000] [Unicode3.2] */ + {0xa7c6, 0xe28f82}, /* U+23C2 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLE [2000] [Unicode3.2] */ + {0xa7c7, 0xe28f83}, /* U+23C3 DENTISTRY SYMBOL LIGHT VERTICAL WITH TRIANGLE [2000] [Unicode3.2] */ + {0xa7c8, 0xe28f84}, /* U+23C4 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH TRIANGLE [2000] [Unicode3.2] */ + {0xa7c9, 0xe28f85}, /* U+23C5 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH TRIANGLE [2000] [Unicode3.2] */ + {0xa7ca, 0xe28f86}, /* U+23C6 DENTISTRY SYMBOL LIGHT VERTICAL AND WAVE [2000] [Unicode3.2] */ + {0xa7cb, 0xe28f87}, /* U+23C7 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH WAVE [2000] [Unicode3.2] */ + {0xa7cc, 0xe28f88}, /* U+23C8 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH WAVE [2000] [Unicode3.2] */ + {0xa7cd, 0xe28f89}, /* U+23C9 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL [2000] [Unicode3.2] */ + {0xa7ce, 0xe28f8a}, /* U+23CA DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL [2000] [Unicode3.2] */ + {0xa7cf, 0xe28f8b}, /* U+23CB DENTISTRY SYMBOL LIGHT VERTICAL AND TOP LEFT [2000] [Unicode3.2] */ + {0xa7d0, 0xe28f8c}, /* U+23CC DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM LEFT [2000] [Unicode3.2] */ + {0xa7d1, 0xd0b0}, /* U+0430 CYRILLIC SMALL LETTER A */ + {0xa7d2, 0xd0b1}, /* U+0431 CYRILLIC SMALL LETTER BE */ + {0xa7d3, 0xd0b2}, /* U+0432 CYRILLIC SMALL LETTER VE */ + {0xa7d4, 0xd0b3}, /* U+0433 CYRILLIC SMALL LETTER GHE */ + {0xa7d5, 0xd0b4}, /* U+0434 CYRILLIC SMALL LETTER DE */ + {0xa7d6, 0xd0b5}, /* U+0435 CYRILLIC SMALL LETTER IE */ + {0xa7d7, 0xd191}, /* U+0451 CYRILLIC SMALL LETTER IO */ + {0xa7d8, 0xd0b6}, /* U+0436 CYRILLIC SMALL LETTER ZHE */ + {0xa7d9, 0xd0b7}, /* U+0437 CYRILLIC SMALL LETTER ZE */ + {0xa7da, 0xd0b8}, /* U+0438 CYRILLIC SMALL LETTER I */ + {0xa7db, 0xd0b9}, /* U+0439 CYRILLIC SMALL LETTER SHORT I */ + {0xa7dc, 0xd0ba}, /* U+043A CYRILLIC SMALL LETTER KA */ + {0xa7dd, 0xd0bb}, /* U+043B CYRILLIC SMALL LETTER EL */ + {0xa7de, 0xd0bc}, /* U+043C CYRILLIC SMALL LETTER EM */ + {0xa7df, 0xd0bd}, /* U+043D CYRILLIC SMALL LETTER EN */ + {0xa7e0, 0xd0be}, /* U+043E CYRILLIC SMALL LETTER O */ + {0xa7e1, 0xd0bf}, /* U+043F CYRILLIC SMALL LETTER PE */ + {0xa7e2, 0xd180}, /* U+0440 CYRILLIC SMALL LETTER ER */ + {0xa7e3, 0xd181}, /* U+0441 CYRILLIC SMALL LETTER ES */ + {0xa7e4, 0xd182}, /* U+0442 CYRILLIC SMALL LETTER TE */ + {0xa7e5, 0xd183}, /* U+0443 CYRILLIC SMALL LETTER U */ + {0xa7e6, 0xd184}, /* U+0444 CYRILLIC SMALL LETTER EF */ + {0xa7e7, 0xd185}, /* U+0445 CYRILLIC SMALL LETTER HA */ + {0xa7e8, 0xd186}, /* U+0446 CYRILLIC SMALL LETTER TSE */ + {0xa7e9, 0xd187}, /* U+0447 CYRILLIC SMALL LETTER CHE */ + {0xa7ea, 0xd188}, /* U+0448 CYRILLIC SMALL LETTER SHA */ + {0xa7eb, 0xd189}, /* U+0449 CYRILLIC SMALL LETTER SHCHA */ + {0xa7ec, 0xd18a}, /* U+044A CYRILLIC SMALL LETTER HARD SIGN */ + {0xa7ed, 0xd18b}, /* U+044B CYRILLIC SMALL LETTER YERU */ + {0xa7ee, 0xd18c}, /* U+044C CYRILLIC SMALL LETTER SOFT SIGN */ + {0xa7ef, 0xd18d}, /* U+044D CYRILLIC SMALL LETTER E */ + {0xa7f0, 0xd18e}, /* U+044E CYRILLIC SMALL LETTER YU */ + {0xa7f1, 0xd18f}, /* U+044F CYRILLIC SMALL LETTER YA */ + {0xa7f2, 0xe383b7}, /* U+30F7 KATAKANA LETTER VA [2000] */ + {0xa7f3, 0xe383b8}, /* U+30F8 KATAKANA LETTER VI [2000] */ + {0xa7f4, 0xe383b9}, /* U+30F9 KATAKANA LETTER VE [2000] */ + {0xa7f5, 0xe383ba}, /* U+30FA KATAKANA LETTER VO [2000] */ + {0xa7f6, 0xe28b9a}, /* U+22DA LESS-THAN EQUAL TO OR GREATER-THAN [2000] */ + {0xa7f7, 0xe28b9b}, /* U+22DB GREATER-THAN EQUAL TO OR LESS-THAN [2000] */ + {0xa7f8, 0xe28593}, /* U+2153 VULGAR FRACTION ONE THIRD [2000] */ + {0xa7f9, 0xe28594}, /* U+2154 VULGAR FRACTION TWO THIRDS [2000] */ + {0xa7fa, 0xe28595}, /* U+2155 VULGAR FRACTION ONE FIFTH [2000] */ + {0xa7fb, 0xe29c93}, /* U+2713 CHECK MARK [2000] */ + {0xa7fc, 0xe28c98}, /* U+2318 PLACE OF INTEREST SIGN [2000] */ + {0xa7fd, 0xe290a3}, /* U+2423 OPEN BOX [2000] */ + {0xa7fe, 0xe28f8e}, /* U+23CE RETURN SYMBOL [2000] [Unicode3.2] */ + {0xa8a1, 0xe29480}, /* U+2500 BOX DRAWINGS LIGHT HORIZONTAL [1983] */ + {0xa8a2, 0xe29482}, /* U+2502 BOX DRAWINGS LIGHT VERTICAL [1983] */ + {0xa8a3, 0xe2948c}, /* U+250C BOX DRAWINGS LIGHT DOWN AND RIGHT [1983] */ + {0xa8a4, 0xe29490}, /* U+2510 BOX DRAWINGS LIGHT DOWN AND LEFT [1983] */ + {0xa8a5, 0xe29498}, /* U+2518 BOX DRAWINGS LIGHT UP AND LEFT [1983] */ + {0xa8a6, 0xe29494}, /* U+2514 BOX DRAWINGS LIGHT UP AND RIGHT [1983] */ + {0xa8a7, 0xe2949c}, /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT [1983] */ + {0xa8a8, 0xe294ac}, /* U+252C BOX DRAWINGS LIGHT DOWN AND HORIZONTAL [1983] */ + {0xa8a9, 0xe294a4}, /* U+2524 BOX DRAWINGS LIGHT VERTICAL AND LEFT [1983] */ + {0xa8aa, 0xe294b4}, /* U+2534 BOX DRAWINGS LIGHT UP AND HORIZONTAL [1983] */ + {0xa8ab, 0xe294bc}, /* U+253C BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL [1983] */ + {0xa8ac, 0xe29481}, /* U+2501 BOX DRAWINGS HEAVY HORIZONTAL [1983] */ + {0xa8ad, 0xe29483}, /* U+2503 BOX DRAWINGS HEAVY VERTICAL [1983] */ + {0xa8ae, 0xe2948f}, /* U+250F BOX DRAWINGS HEAVY DOWN AND RIGHT [1983] */ + {0xa8af, 0xe29493}, /* U+2513 BOX DRAWINGS HEAVY DOWN AND LEFT [1983] */ + {0xa8b0, 0xe2949b}, /* U+251B BOX DRAWINGS HEAVY UP AND LEFT [1983] */ + {0xa8b1, 0xe29497}, /* U+2517 BOX DRAWINGS HEAVY UP AND RIGHT [1983] */ + {0xa8b2, 0xe294a3}, /* U+2523 BOX DRAWINGS HEAVY VERTICAL AND RIGHT [1983] */ + {0xa8b3, 0xe294b3}, /* U+2533 BOX DRAWINGS HEAVY DOWN AND HORIZONTAL [1983] */ + {0xa8b4, 0xe294ab}, /* U+252B BOX DRAWINGS HEAVY VERTICAL AND LEFT [1983] */ + {0xa8b5, 0xe294bb}, /* U+253B BOX DRAWINGS HEAVY UP AND HORIZONTAL [1983] */ + {0xa8b6, 0xe2958b}, /* U+254B BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL [1983] */ + {0xa8b7, 0xe294a0}, /* U+2520 BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT [1983] */ + {0xa8b8, 0xe294af}, /* U+252F BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY [1983] */ + {0xa8b9, 0xe294a8}, /* U+2528 BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT [1983] */ + {0xa8ba, 0xe294b7}, /* U+2537 BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY [1983] */ + {0xa8bb, 0xe294bf}, /* U+253F BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY [1983] */ + {0xa8bc, 0xe2949d}, /* U+251D BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY [1983] */ + {0xa8bd, 0xe294b0}, /* U+2530 BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT [1983] */ + {0xa8be, 0xe294a5}, /* U+2525 BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY [1983] */ + {0xa8bf, 0xe294b8}, /* U+2538 BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT [1983] */ + {0xa8c0, 0xe29582}, /* U+2542 BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT [1983] */ + {0xa8c1, 0xe38991}, /* U+3251 CIRCLED NUMBER TWENTY ONE [2000] [Unicode3.2] */ + {0xa8c2, 0xe38992}, /* U+3252 CIRCLED NUMBER TWENTY TWO [2000] [Unicode3.2] */ + {0xa8c3, 0xe38993}, /* U+3253 CIRCLED NUMBER TWENTY THREE [2000] [Unicode3.2] */ + {0xa8c4, 0xe38994}, /* U+3254 CIRCLED NUMBER TWENTY FOUR [2000] [Unicode3.2] */ + {0xa8c5, 0xe38995}, /* U+3255 CIRCLED NUMBER TWENTY FIVE [2000] [Unicode3.2] */ + {0xa8c6, 0xe38996}, /* U+3256 CIRCLED NUMBER TWENTY SIX [2000] [Unicode3.2] */ + {0xa8c7, 0xe38997}, /* U+3257 CIRCLED NUMBER TWENTY SEVEN [2000] [Unicode3.2] */ + {0xa8c8, 0xe38998}, /* U+3258 CIRCLED NUMBER TWENTY EIGHT [2000] [Unicode3.2] */ + {0xa8c9, 0xe38999}, /* U+3259 CIRCLED NUMBER TWENTY NINE [2000] [Unicode3.2] */ + {0xa8ca, 0xe3899a}, /* U+325A CIRCLED NUMBER THIRTY [2000] [Unicode3.2] */ + {0xa8cb, 0xe3899b}, /* U+325B CIRCLED NUMBER THIRTY ONE [2000] [Unicode3.2] */ + {0xa8cc, 0xe3899c}, /* U+325C CIRCLED NUMBER THIRTY TWO [2000] [Unicode3.2] */ + {0xa8cd, 0xe3899d}, /* U+325D CIRCLED NUMBER THIRTY THREE [2000] [Unicode3.2] */ + {0xa8ce, 0xe3899e}, /* U+325E CIRCLED NUMBER THIRTY FOUR [2000] [Unicode3.2] */ + {0xa8cf, 0xe3899f}, /* U+325F CIRCLED NUMBER THIRTY FIVE [2000] [Unicode3.2] */ + {0xa8d0, 0xe38ab1}, /* U+32B1 CIRCLED NUMBER THIRTY SIX [2000] [Unicode3.2] */ + {0xa8d1, 0xe38ab2}, /* U+32B2 CIRCLED NUMBER THIRTY SEVEN [2000] [Unicode3.2] */ + {0xa8d2, 0xe38ab3}, /* U+32B3 CIRCLED NUMBER THIRTY EIGHT [2000] [Unicode3.2] */ + {0xa8d3, 0xe38ab4}, /* U+32B4 CIRCLED NUMBER THIRTY NINE [2000] [Unicode3.2] */ + {0xa8d4, 0xe38ab5}, /* U+32B5 CIRCLED NUMBER FORTY [2000] [Unicode3.2] */ + {0xa8d5, 0xe38ab6}, /* U+32B6 CIRCLED NUMBER FORTY ONE [2000] [Unicode3.2] */ + {0xa8d6, 0xe38ab7}, /* U+32B7 CIRCLED NUMBER FORTY TWO [2000] [Unicode3.2] */ + {0xa8d7, 0xe38ab8}, /* U+32B8 CIRCLED NUMBER FORTY THREE [2000] [Unicode3.2] */ + {0xa8d8, 0xe38ab9}, /* U+32B9 CIRCLED NUMBER FORTY FOUR [2000] [Unicode3.2] */ + {0xa8d9, 0xe38aba}, /* U+32BA CIRCLED NUMBER FORTY FIVE [2000] [Unicode3.2] */ + {0xa8da, 0xe38abb}, /* U+32BB CIRCLED NUMBER FORTY SIX [2000] [Unicode3.2] */ + {0xa8db, 0xe38abc}, /* U+32BC CIRCLED NUMBER FORTY SEVEN [2000] [Unicode3.2] */ + {0xa8dc, 0xe38abd}, /* U+32BD CIRCLED NUMBER FORTY EIGHT [2000] [Unicode3.2] */ + {0xa8dd, 0xe38abe}, /* U+32BE CIRCLED NUMBER FORTY NINE [2000] [Unicode3.2] */ + {0xa8de, 0xe38abf}, /* U+32BF CIRCLED NUMBER FIFTY [2000] [Unicode3.2] */ + {0xa8e7, 0xe29790}, /* U+25D0 CIRCLE WITH LEFT HALF BLACK [2000] */ + {0xa8e8, 0xe29791}, /* U+25D1 CIRCLE WITH RIGHT HALF BLACK [2000] */ + {0xa8e9, 0xe29792}, /* U+25D2 CIRCLE WITH LOWER HALF BLACK [2000] */ + {0xa8ea, 0xe29793}, /* U+25D3 CIRCLE WITH UPPER HALF BLACK [2000] */ + {0xa8eb, 0xe280bc}, /* U+203C DOUBLE EXCLAMATION MARK [2000] */ + {0xa8ec, 0xe28187}, /* U+2047 DOUBLE QUESTION MARK [2000] [Unicode3.2] */ + {0xa8ed, 0xe28188}, /* U+2048 QUESTION EXCLAMATION MARK [2000] */ + {0xa8ee, 0xe28189}, /* U+2049 EXCLAMATION QUESTION MARK [2000] */ + {0xa8ef, 0xc78d}, /* U+01CD LATIN CAPITAL LETTER A WITH CARON [2000] */ + {0xa8f0, 0xc78e}, /* U+01CE LATIN SMALL LETTER A WITH CARON [2000] */ + {0xa8f1, 0xc790}, /* U+01D0 LATIN SMALL LETTER I WITH CARON [2000] */ + {0xa8f2, 0xe1b8be}, /* U+1E3E LATIN CAPITAL LETTER M WITH ACUTE [2000] */ + {0xa8f3, 0xe1b8bf}, /* U+1E3F LATIN SMALL LETTER M WITH ACUTE [2000] */ + {0xa8f4, 0xc7b8}, /* U+01F8 LATIN CAPITAL LETTER N WITH GRAVE [2000] */ + {0xa8f5, 0xc7b9}, /* U+01F9 LATIN SMALL LETTER N WITH GRAVE [2000] */ + {0xa8f6, 0xc791}, /* U+01D1 LATIN CAPITAL LETTER O WITH CARON [2000] */ + {0xa8f7, 0xc792}, /* U+01D2 LATIN SMALL LETTER O WITH CARON [2000] */ + {0xa8f8, 0xc794}, /* U+01D4 LATIN SMALL LETTER U WITH CARON [2000] */ + {0xa8f9, 0xc796}, /* U+01D6 LATIN SMALL LETTER U WITH DIAERESIS AND MACRON [2000] */ + {0xa8fa, 0xc798}, /* U+01D8 LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE [2000] */ + {0xa8fb, 0xc79a}, /* U+01DA LATIN SMALL LETTER U WITH DIAERESIS AND CARON [2000] */ + {0xa8fc, 0xc79c}, /* U+01DC LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE [2000] */ + {0xa9a1, 0xe282ac}, /* U+20AC EURO SIGN [2000] */ + {0xa9a2, 0xc2a0}, /* U+00A0 NO-BREAK SPACE [2000] */ + {0xa9a3, 0xc2a1}, /* U+00A1 INVERTED EXCLAMATION MARK [2000] */ + {0xa9a4, 0xc2a4}, /* U+00A4 CURRENCY SIGN [2000] */ + {0xa9a5, 0xc2a6}, /* U+00A6 BROKEN BAR [2000] */ + {0xa9a6, 0xc2a9}, /* U+00A9 COPYRIGHT SIGN [2000] */ + {0xa9a7, 0xc2aa}, /* U+00AA FEMININE ORDINAL INDICATOR [2000] */ + {0xa9a8, 0xc2ab}, /* U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK [2000] */ + {0xa9a9, 0xc2ad}, /* U+00AD SOFT HYPHEN [2000] */ + {0xa9aa, 0xc2ae}, /* U+00AE REGISTERED SIGN [2000] */ + {0xa9ab, 0xc2af}, /* U+00AF MACRON [2000] */ + {0xa9ac, 0xc2b2}, /* U+00B2 SUPERSCRIPT TWO [2000] */ + {0xa9ad, 0xc2b3}, /* U+00B3 SUPERSCRIPT THREE [2000] */ + {0xa9ae, 0xc2b7}, /* U+00B7 MIDDLE DOT [2000] */ + {0xa9af, 0xc2b8}, /* U+00B8 CEDILLA [2000] */ + {0xa9b0, 0xc2b9}, /* U+00B9 SUPERSCRIPT ONE [2000] */ + {0xa9b1, 0xc2ba}, /* U+00BA MASCULINE ORDINAL INDICATOR [2000] */ + {0xa9b2, 0xc2bb}, /* U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK [2000] */ + {0xa9b3, 0xc2bc}, /* U+00BC VULGAR FRACTION ONE QUARTER [2000] */ + {0xa9b4, 0xc2bd}, /* U+00BD VULGAR FRACTION ONE HALF [2000] */ + {0xa9b5, 0xc2be}, /* U+00BE VULGAR FRACTION THREE QUARTERS [2000] */ + {0xa9b6, 0xc2bf}, /* U+00BF INVERTED QUESTION MARK [2000] */ + {0xa9b7, 0xc380}, /* U+00C0 LATIN CAPITAL LETTER A WITH GRAVE [2000] */ + {0xa9b8, 0xc381}, /* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE [2000] */ + {0xa9b9, 0xc382}, /* U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX [2000] */ + {0xa9ba, 0xc383}, /* U+00C3 LATIN CAPITAL LETTER A WITH TILDE [2000] */ + {0xa9bb, 0xc384}, /* U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS [2000] */ + {0xa9bc, 0xc385}, /* U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE [2000] */ + {0xa9bd, 0xc386}, /* U+00C6 LATIN CAPITAL LETTER AE [2000] */ + {0xa9be, 0xc387}, /* U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA [2000] */ + {0xa9bf, 0xc388}, /* U+00C8 LATIN CAPITAL LETTER E WITH GRAVE [2000] */ + {0xa9c0, 0xc389}, /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE [2000] */ + {0xa9c1, 0xc38a}, /* U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX [2000] */ + {0xa9c2, 0xc38b}, /* U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS [2000] */ + {0xa9c3, 0xc38c}, /* U+00CC LATIN CAPITAL LETTER I WITH GRAVE [2000] */ + {0xa9c4, 0xc38d}, /* U+00CD LATIN CAPITAL LETTER I WITH ACUTE [2000] */ + {0xa9c5, 0xc38e}, /* U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX [2000] */ + {0xa9c6, 0xc38f}, /* U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS [2000] */ + {0xa9c7, 0xc390}, /* U+00D0 LATIN CAPITAL LETTER ETH [2000] */ + {0xa9c8, 0xc391}, /* U+00D1 LATIN CAPITAL LETTER N WITH TILDE [2000] */ + {0xa9c9, 0xc392}, /* U+00D2 LATIN CAPITAL LETTER O WITH GRAVE [2000] */ + {0xa9ca, 0xc393}, /* U+00D3 LATIN CAPITAL LETTER O WITH ACUTE [2000] */ + {0xa9cb, 0xc394}, /* U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX [2000] */ + {0xa9cc, 0xc395}, /* U+00D5 LATIN CAPITAL LETTER O WITH TILDE [2000] */ + {0xa9cd, 0xc396}, /* U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS [2000] */ + {0xa9ce, 0xc398}, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE [2000] */ + {0xa9cf, 0xc399}, /* U+00D9 LATIN CAPITAL LETTER U WITH GRAVE [2000] */ + {0xa9d0, 0xc39a}, /* U+00DA LATIN CAPITAL LETTER U WITH ACUTE [2000] */ + {0xa9d1, 0xc39b}, /* U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX [2000] */ + {0xa9d2, 0xc39c}, /* U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS [2000] */ + {0xa9d3, 0xc39d}, /* U+00DD LATIN CAPITAL LETTER Y WITH ACUTE [2000] */ + {0xa9d4, 0xc39e}, /* U+00DE LATIN CAPITAL LETTER THORN [2000] */ + {0xa9d5, 0xc39f}, /* U+00DF LATIN SMALL LETTER SHARP S [2000] */ + {0xa9d6, 0xc3a0}, /* U+00E0 LATIN SMALL LETTER A WITH GRAVE [2000] */ + {0xa9d7, 0xc3a1}, /* U+00E1 LATIN SMALL LETTER A WITH ACUTE [2000] */ + {0xa9d8, 0xc3a2}, /* U+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX [2000] */ + {0xa9d9, 0xc3a3}, /* U+00E3 LATIN SMALL LETTER A WITH TILDE [2000] */ + {0xa9da, 0xc3a4}, /* U+00E4 LATIN SMALL LETTER A WITH DIAERESIS [2000] */ + {0xa9db, 0xc3a5}, /* U+00E5 LATIN SMALL LETTER A WITH RING ABOVE [2000] */ + {0xa9dc, 0xc3a6}, /* U+00E6 LATIN SMALL LETTER AE [2000] */ + {0xa9dd, 0xc3a7}, /* U+00E7 LATIN SMALL LETTER C WITH CEDILLA [2000] */ + {0xa9de, 0xc3a8}, /* U+00E8 LATIN SMALL LETTER E WITH GRAVE [2000] */ + {0xa9df, 0xc3a9}, /* U+00E9 LATIN SMALL LETTER E WITH ACUTE [2000] */ + {0xa9e0, 0xc3aa}, /* U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX [2000] */ + {0xa9e1, 0xc3ab}, /* U+00EB LATIN SMALL LETTER E WITH DIAERESIS [2000] */ + {0xa9e2, 0xc3ac}, /* U+00EC LATIN SMALL LETTER I WITH GRAVE [2000] */ + {0xa9e3, 0xc3ad}, /* U+00ED LATIN SMALL LETTER I WITH ACUTE [2000] */ + {0xa9e4, 0xc3ae}, /* U+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX [2000] */ + {0xa9e5, 0xc3af}, /* U+00EF LATIN SMALL LETTER I WITH DIAERESIS [2000] */ + {0xa9e6, 0xc3b0}, /* U+00F0 LATIN SMALL LETTER ETH [2000] */ + {0xa9e7, 0xc3b1}, /* U+00F1 LATIN SMALL LETTER N WITH TILDE [2000] */ + {0xa9e8, 0xc3b2}, /* U+00F2 LATIN SMALL LETTER O WITH GRAVE [2000] */ + {0xa9e9, 0xc3b3}, /* U+00F3 LATIN SMALL LETTER O WITH ACUTE [2000] */ + {0xa9ea, 0xc3b4}, /* U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX [2000] */ + {0xa9eb, 0xc3b5}, /* U+00F5 LATIN SMALL LETTER O WITH TILDE [2000] */ + {0xa9ec, 0xc3b6}, /* U+00F6 LATIN SMALL LETTER O WITH DIAERESIS [2000] */ + {0xa9ed, 0xc3b8}, /* U+00F8 LATIN SMALL LETTER O WITH STROKE [2000] */ + {0xa9ee, 0xc3b9}, /* U+00F9 LATIN SMALL LETTER U WITH GRAVE [2000] */ + {0xa9ef, 0xc3ba}, /* U+00FA LATIN SMALL LETTER U WITH ACUTE [2000] */ + {0xa9f0, 0xc3bb}, /* U+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX [2000] */ + {0xa9f1, 0xc3bc}, /* U+00FC LATIN SMALL LETTER U WITH DIAERESIS [2000] */ + {0xa9f2, 0xc3bd}, /* U+00FD LATIN SMALL LETTER Y WITH ACUTE [2000] */ + {0xa9f3, 0xc3be}, /* U+00FE LATIN SMALL LETTER THORN [2000] */ + {0xa9f4, 0xc3bf}, /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS [2000] */ + {0xa9f5, 0xc480}, /* U+0100 LATIN CAPITAL LETTER A WITH MACRON [2000] */ + {0xa9f6, 0xc4aa}, /* U+012A LATIN CAPITAL LETTER I WITH MACRON [2000] */ + {0xa9f7, 0xc5aa}, /* U+016A LATIN CAPITAL LETTER U WITH MACRON [2000] */ + {0xa9f8, 0xc492}, /* U+0112 LATIN CAPITAL LETTER E WITH MACRON [2000] */ + {0xa9f9, 0xc58c}, /* U+014C LATIN CAPITAL LETTER O WITH MACRON [2000] */ + {0xa9fa, 0xc481}, /* U+0101 LATIN SMALL LETTER A WITH MACRON [2000] */ + {0xa9fb, 0xc4ab}, /* U+012B LATIN SMALL LETTER I WITH MACRON [2000] */ + {0xa9fc, 0xc5ab}, /* U+016B LATIN SMALL LETTER U WITH MACRON [2000] */ + {0xa9fd, 0xc493}, /* U+0113 LATIN SMALL LETTER E WITH MACRON [2000] */ + {0xa9fe, 0xc58d}, /* U+014D LATIN SMALL LETTER O WITH MACRON [2000] */ + {0xaaa1, 0xc484}, /* U+0104 LATIN CAPITAL LETTER A WITH OGONEK [2000] */ + {0xaaa2, 0xcb98}, /* U+02D8 BREVE [2000] */ + {0xaaa3, 0xc581}, /* U+0141 LATIN CAPITAL LETTER L WITH STROKE [2000] */ + {0xaaa4, 0xc4bd}, /* U+013D LATIN CAPITAL LETTER L WITH CARON [2000] */ + {0xaaa5, 0xc59a}, /* U+015A LATIN CAPITAL LETTER S WITH ACUTE [2000] */ + {0xaaa6, 0xc5a0}, /* U+0160 LATIN CAPITAL LETTER S WITH CARON [2000] */ + {0xaaa7, 0xc59e}, /* U+015E LATIN CAPITAL LETTER S WITH CEDILLA [2000] */ + {0xaaa8, 0xc5a4}, /* U+0164 LATIN CAPITAL LETTER T WITH CARON [2000] */ + {0xaaa9, 0xc5b9}, /* U+0179 LATIN CAPITAL LETTER Z WITH ACUTE [2000] */ + {0xaaaa, 0xc5bd}, /* U+017D LATIN CAPITAL LETTER Z WITH CARON [2000] */ + {0xaaab, 0xc5bb}, /* U+017B LATIN CAPITAL LETTER Z WITH DOT ABOVE [2000] */ + {0xaaac, 0xc485}, /* U+0105 LATIN SMALL LETTER A WITH OGONEK [2000] */ + {0xaaad, 0xcb9b}, /* U+02DB OGONEK [2000] */ + {0xaaae, 0xc582}, /* U+0142 LATIN SMALL LETTER L WITH STROKE [2000] */ + {0xaaaf, 0xc4be}, /* U+013E LATIN SMALL LETTER L WITH CARON [2000] */ + {0xaab0, 0xc59b}, /* U+015B LATIN SMALL LETTER S WITH ACUTE [2000] */ + {0xaab1, 0xcb87}, /* U+02C7 CARON [2000] */ + {0xaab2, 0xc5a1}, /* U+0161 LATIN SMALL LETTER S WITH CARON [2000] */ + {0xaab3, 0xc59f}, /* U+015F LATIN SMALL LETTER S WITH CEDILLA [2000] */ + {0xaab4, 0xc5a5}, /* U+0165 LATIN SMALL LETTER T WITH CARON [2000] */ + {0xaab5, 0xc5ba}, /* U+017A LATIN SMALL LETTER Z WITH ACUTE [2000] */ + {0xaab6, 0xcb9d}, /* U+02DD DOUBLE ACUTE ACCENT [2000] */ + {0xaab7, 0xc5be}, /* U+017E LATIN SMALL LETTER Z WITH CARON [2000] */ + {0xaab8, 0xc5bc}, /* U+017C LATIN SMALL LETTER Z WITH DOT ABOVE [2000] */ + {0xaab9, 0xc594}, /* U+0154 LATIN CAPITAL LETTER R WITH ACUTE [2000] */ + {0xaaba, 0xc482}, /* U+0102 LATIN CAPITAL LETTER A WITH BREVE [2000] */ + {0xaabb, 0xc4b9}, /* U+0139 LATIN CAPITAL LETTER L WITH ACUTE [2000] */ + {0xaabc, 0xc486}, /* U+0106 LATIN CAPITAL LETTER C WITH ACUTE [2000] */ + {0xaabd, 0xc48c}, /* U+010C LATIN CAPITAL LETTER C WITH CARON [2000] */ + {0xaabe, 0xc498}, /* U+0118 LATIN CAPITAL LETTER E WITH OGONEK [2000] */ + {0xaabf, 0xc49a}, /* U+011A LATIN CAPITAL LETTER E WITH CARON [2000] */ + {0xaac0, 0xc48e}, /* U+010E LATIN CAPITAL LETTER D WITH CARON [2000] */ + {0xaac1, 0xc583}, /* U+0143 LATIN CAPITAL LETTER N WITH ACUTE [2000] */ + {0xaac2, 0xc587}, /* U+0147 LATIN CAPITAL LETTER N WITH CARON [2000] */ + {0xaac3, 0xc590}, /* U+0150 LATIN CAPITAL LETTER O WITH DOUBLE ACUTE [2000] */ + {0xaac4, 0xc598}, /* U+0158 LATIN CAPITAL LETTER R WITH CARON [2000] */ + {0xaac5, 0xc5ae}, /* U+016E LATIN CAPITAL LETTER U WITH RING ABOVE [2000] */ + {0xaac6, 0xc5b0}, /* U+0170 LATIN CAPITAL LETTER U WITH DOUBLE ACUTE [2000] */ + {0xaac7, 0xc5a2}, /* U+0162 LATIN CAPITAL LETTER T WITH CEDILLA [2000] */ + {0xaac8, 0xc595}, /* U+0155 LATIN SMALL LETTER R WITH ACUTE [2000] */ + {0xaac9, 0xc483}, /* U+0103 LATIN SMALL LETTER A WITH BREVE [2000] */ + {0xaaca, 0xc4ba}, /* U+013A LATIN SMALL LETTER L WITH ACUTE [2000] */ + {0xaacb, 0xc487}, /* U+0107 LATIN SMALL LETTER C WITH ACUTE [2000] */ + {0xaacc, 0xc48d}, /* U+010D LATIN SMALL LETTER C WITH CARON [2000] */ + {0xaacd, 0xc499}, /* U+0119 LATIN SMALL LETTER E WITH OGONEK [2000] */ + {0xaace, 0xc49b}, /* U+011B LATIN SMALL LETTER E WITH CARON [2000] */ + {0xaacf, 0xc48f}, /* U+010F LATIN SMALL LETTER D WITH CARON [2000] */ + {0xaad0, 0xc491}, /* U+0111 LATIN SMALL LETTER D WITH STROKE [2000] */ + {0xaad1, 0xc584}, /* U+0144 LATIN SMALL LETTER N WITH ACUTE [2000] */ + {0xaad2, 0xc588}, /* U+0148 LATIN SMALL LETTER N WITH CARON [2000] */ + {0xaad3, 0xc591}, /* U+0151 LATIN SMALL LETTER O WITH DOUBLE ACUTE [2000] */ + {0xaad4, 0xc599}, /* U+0159 LATIN SMALL LETTER R WITH CARON [2000] */ + {0xaad5, 0xc5af}, /* U+016F LATIN SMALL LETTER U WITH RING ABOVE [2000] */ + {0xaad6, 0xc5b1}, /* U+0171 LATIN SMALL LETTER U WITH DOUBLE ACUTE [2000] */ + {0xaad7, 0xc5a3}, /* U+0163 LATIN SMALL LETTER T WITH CEDILLA [2000] */ + {0xaad8, 0xcb99}, /* U+02D9 DOT ABOVE [2000] */ + {0xaad9, 0xc488}, /* U+0108 LATIN CAPITAL LETTER C WITH CIRCUMFLEX [2000] */ + {0xaada, 0xc49c}, /* U+011C LATIN CAPITAL LETTER G WITH CIRCUMFLEX [2000] */ + {0xaadb, 0xc4a4}, /* U+0124 LATIN CAPITAL LETTER H WITH CIRCUMFLEX [2000] */ + {0xaadc, 0xc4b4}, /* U+0134 LATIN CAPITAL LETTER J WITH CIRCUMFLEX [2000] */ + {0xaadd, 0xc59c}, /* U+015C LATIN CAPITAL LETTER S WITH CIRCUMFLEX [2000] */ + {0xaade, 0xc5ac}, /* U+016C LATIN CAPITAL LETTER U WITH BREVE [2000] */ + {0xaadf, 0xc489}, /* U+0109 LATIN SMALL LETTER C WITH CIRCUMFLEX [2000] */ + {0xaae0, 0xc49d}, /* U+011D LATIN SMALL LETTER G WITH CIRCUMFLEX [2000] */ + {0xaae1, 0xc4a5}, /* U+0125 LATIN SMALL LETTER H WITH CIRCUMFLEX [2000] */ + {0xaae2, 0xc4b5}, /* U+0135 LATIN SMALL LETTER J WITH CIRCUMFLEX [2000] */ + {0xaae3, 0xc59d}, /* U+015D LATIN SMALL LETTER S WITH CIRCUMFLEX [2000] */ + {0xaae4, 0xc5ad}, /* U+016D LATIN SMALL LETTER U WITH BREVE [2000] */ + {0xaae5, 0xc9b1}, /* U+0271 LATIN SMALL LETTER M WITH HOOK [2000] */ + {0xaae6, 0xca8b}, /* U+028B LATIN SMALL LETTER V WITH HOOK [2000] */ + {0xaae7, 0xc9be}, /* U+027E LATIN SMALL LETTER R WITH FISHHOOK [2000] */ + {0xaae8, 0xca83}, /* U+0283 LATIN SMALL LETTER ESH [2000] */ + {0xaae9, 0xca92}, /* U+0292 LATIN SMALL LETTER EZH [2000] */ + {0xaaea, 0xc9ac}, /* U+026C LATIN SMALL LETTER L WITH BELT [2000] */ + {0xaaeb, 0xc9ae}, /* U+026E LATIN SMALL LETTER LEZH [2000] */ + {0xaaec, 0xc9b9}, /* U+0279 LATIN SMALL LETTER TURNED R [2000] */ + {0xaaed, 0xca88}, /* U+0288 LATIN SMALL LETTER T WITH RETROFLEX HOOK [2000] */ + {0xaaee, 0xc996}, /* U+0256 LATIN SMALL LETTER D WITH TAIL [2000] */ + {0xaaef, 0xc9b3}, /* U+0273 LATIN SMALL LETTER N WITH RETROFLEX HOOK [2000] */ + {0xaaf0, 0xc9bd}, /* U+027D LATIN SMALL LETTER R WITH TAIL [2000] */ + {0xaaf1, 0xca82}, /* U+0282 LATIN SMALL LETTER S WITH HOOK [2000] */ + {0xaaf2, 0xca90}, /* U+0290 LATIN SMALL LETTER Z WITH RETROFLEX HOOK [2000] */ + {0xaaf3, 0xc9bb}, /* U+027B LATIN SMALL LETTER TURNED R WITH HOOK [2000] */ + {0xaaf4, 0xc9ad}, /* U+026D LATIN SMALL LETTER L WITH RETROFLEX HOOK [2000] */ + {0xaaf5, 0xc99f}, /* U+025F LATIN SMALL LETTER DOTLESS J WITH STROKE [2000] */ + {0xaaf6, 0xc9b2}, /* U+0272 LATIN SMALL LETTER N WITH LEFT HOOK [2000] */ + {0xaaf7, 0xca9d}, /* U+029D LATIN SMALL LETTER J WITH CROSSED-TAIL [2000] */ + {0xaaf8, 0xca8e}, /* U+028E LATIN SMALL LETTER TURNED Y [2000] */ + {0xaaf9, 0xc9a1}, /* U+0261 LATIN SMALL LETTER SCRIPT G [2000] */ + {0xaafa, 0xc58b}, /* U+014B LATIN SMALL LETTER ENG [2000] */ + {0xaafb, 0xc9b0}, /* U+0270 LATIN SMALL LETTER TURNED M WITH LONG LEG [2000] */ + {0xaafc, 0xca81}, /* U+0281 LATIN LETTER SMALL CAPITAL INVERTED R [2000] */ + {0xaafd, 0xc4a7}, /* U+0127 LATIN SMALL LETTER H WITH STROKE [2000] */ + {0xaafe, 0xca95}, /* U+0295 LATIN LETTER PHARYNGEAL VOICED FRICATIVE [2000] */ + {0xaba1, 0xca94}, /* U+0294 LATIN LETTER GLOTTAL STOP [2000] */ + {0xaba2, 0xc9a6}, /* U+0266 LATIN SMALL LETTER H WITH HOOK [2000] */ + {0xaba3, 0xca98}, /* U+0298 LATIN LETTER BILABIAL CLICK [2000] */ + {0xaba4, 0xc782}, /* U+01C2 LATIN LETTER ALVEOLAR CLICK [2000] */ + {0xaba5, 0xc993}, /* U+0253 LATIN SMALL LETTER B WITH HOOK [2000] */ + {0xaba6, 0xc997}, /* U+0257 LATIN SMALL LETTER D WITH HOOK [2000] */ + {0xaba7, 0xca84}, /* U+0284 LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK [2000] */ + {0xaba8, 0xc9a0}, /* U+0260 LATIN SMALL LETTER G WITH HOOK [2000] */ + {0xaba9, 0xc693}, /* U+0193 LATIN CAPITAL LETTER G WITH HOOK [2000] */ + {0xabaa, 0xc593}, /* U+0153 LATIN SMALL LIGATURE OE [2000] */ + {0xabab, 0xc592}, /* U+0152 LATIN CAPITAL LIGATURE OE [2000] */ + {0xabac, 0xc9a8}, /* U+0268 LATIN SMALL LETTER I WITH STROKE [2000] */ + {0xabad, 0xca89}, /* U+0289 LATIN SMALL LETTER U BAR [2000] */ + {0xabae, 0xc998}, /* U+0258 LATIN SMALL LETTER REVERSED E [2000] */ + {0xabaf, 0xc9b5}, /* U+0275 LATIN SMALL LETTER BARRED O [2000] */ + {0xabb0, 0xc999}, /* U+0259 LATIN SMALL LETTER SCHWA [2000] */ + {0xabb1, 0xc99c}, /* U+025C LATIN SMALL LETTER REVERSED OPEN E [2000] */ + {0xabb2, 0xc99e}, /* U+025E LATIN SMALL LETTER CLOSED REVERSED OPEN E [2000] */ + {0xabb3, 0xc990}, /* U+0250 LATIN SMALL LETTER TURNED A [2000] */ + {0xabb4, 0xc9af}, /* U+026F LATIN SMALL LETTER TURNED M [2000] */ + {0xabb5, 0xca8a}, /* U+028A LATIN SMALL LETTER UPSILON [2000] */ + {0xabb6, 0xc9a4}, /* U+0264 LATIN SMALL LETTER RAMS HORN [2000] */ + {0xabb7, 0xca8c}, /* U+028C LATIN SMALL LETTER TURNED V [2000] */ + {0xabb8, 0xc994}, /* U+0254 LATIN SMALL LETTER OPEN O [2000] */ + {0xabb9, 0xc991}, /* U+0251 LATIN SMALL LETTER ALPHA [2000] */ + {0xabba, 0xc992}, /* U+0252 LATIN SMALL LETTER TURNED ALPHA [2000] */ + {0xabbb, 0xca8d}, /* U+028D LATIN SMALL LETTER TURNED W [2000] */ + {0xabbc, 0xc9a5}, /* U+0265 LATIN SMALL LETTER TURNED H [2000] */ + {0xabbd, 0xcaa2}, /* U+02A2 LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE [2000] */ + {0xabbe, 0xcaa1}, /* U+02A1 LATIN LETTER GLOTTAL STOP WITH STROKE [2000] */ + {0xabbf, 0xc995}, /* U+0255 LATIN SMALL LETTER C WITH CURL [2000] */ + {0xabc0, 0xca91}, /* U+0291 LATIN SMALL LETTER Z WITH CURL [2000] */ + {0xabc1, 0xc9ba}, /* U+027A LATIN SMALL LETTER TURNED R WITH LONG LEG [2000] */ + {0xabc2, 0xc9a7}, /* U+0267 LATIN SMALL LETTER HENG WITH HOOK [2000] */ + {0xabc3, 0xc99a}, /* U+025A LATIN SMALL LETTER SCHWA WITH HOOK [2000] */ + {0xabc5, 0xc7bd}, /* U+01FD LATIN SMALL LETTER AE WITH ACUTE [2000] */ + {0xabc6, 0xe1bdb0}, /* U+1F70 GREEK SMALL LETTER ALPHA WITH VARIA [2000] */ + {0xabc7, 0xe1bdb1}, /* U+1F71 GREEK SMALL LETTER ALPHA WITH OXIA [2000] */ + {0xabd0, 0xe1bdb2}, /* U+1F72 GREEK SMALL LETTER EPSILON WITH VARIA [2000] */ + {0xabd1, 0xe1bdb3}, /* U+1F73 GREEK SMALL LETTER EPSILON WITH OXIA [2000] */ + {0xabd2, 0xcda1}, /* U+0361 COMBINING DOUBLE INVERTED BREVE [2000] */ + {0xabd3, 0xcb88}, /* U+02C8 MODIFIER LETTER VERTICAL LINE [2000] */ + {0xabd4, 0xcb8c}, /* U+02CC MODIFIER LETTER LOW VERTICAL LINE [2000] */ + {0xabd5, 0xcb90}, /* U+02D0 MODIFIER LETTER TRIANGULAR COLON [2000] */ + {0xabd6, 0xcb91}, /* U+02D1 MODIFIER LETTER HALF TRIANGULAR COLON [2000] */ + {0xabd7, 0xcc86}, /* U+0306 COMBINING BREVE [2000] */ + {0xabd8, 0xe280bf}, /* U+203F UNDERTIE [2000] */ + {0xabd9, 0xcc8b}, /* U+030B COMBINING DOUBLE ACUTE ACCENT [2000] */ + {0xabda, 0xcc81}, /* U+0301 COMBINING ACUTE ACCENT [2000] */ + {0xabdb, 0xcc84}, /* U+0304 COMBINING MACRON [2000] */ + {0xabdc, 0xcc80}, /* U+0300 COMBINING GRAVE ACCENT [2000] */ + {0xabdd, 0xcc8f}, /* U+030F COMBINING DOUBLE GRAVE ACCENT [2000] */ + {0xabde, 0xcc8c}, /* U+030C COMBINING CARON [2000] */ + {0xabdf, 0xcc82}, /* U+0302 COMBINING CIRCUMFLEX ACCENT [2000] */ + {0xabe0, 0xcba5}, /* U+02E5 MODIFIER LETTER EXTRA-HIGH TONE BAR [2000] */ + {0xabe1, 0xcba6}, /* U+02E6 MODIFIER LETTER HIGH TONE BAR [2000] */ + {0xabe2, 0xcba7}, /* U+02E7 MODIFIER LETTER MID TONE BAR [2000] */ + {0xabe3, 0xcba8}, /* U+02E8 MODIFIER LETTER LOW TONE BAR [2000] */ + {0xabe4, 0xcba9}, /* U+02E9 MODIFIER LETTER EXTRA-LOW TONE BAR [2000] */ + {0xabe7, 0xcca5}, /* U+0325 COMBINING RING BELOW [2000] */ + {0xabe8, 0xccac}, /* U+032C COMBINING CARON BELOW [2000] */ + {0xabe9, 0xccb9}, /* U+0339 COMBINING RIGHT HALF RING BELOW [2000] */ + {0xabea, 0xcc9c}, /* U+031C COMBINING LEFT HALF RING BELOW [2000] */ + {0xabeb, 0xcc9f}, /* U+031F COMBINING PLUS SIGN BELOW [2000] */ + {0xabec, 0xcca0}, /* U+0320 COMBINING MINUS SIGN BELOW [2000] */ + {0xabed, 0xcc88}, /* U+0308 COMBINING DIAERESIS [2000] */ + {0xabee, 0xccbd}, /* U+033D COMBINING X ABOVE [2000] */ + {0xabef, 0xcca9}, /* U+0329 COMBINING VERTICAL LINE BELOW [2000] */ + {0xabf0, 0xccaf}, /* U+032F COMBINING INVERTED BREVE BELOW [2000] */ + {0xabf1, 0xcb9e}, /* U+02DE MODIFIER LETTER RHOTIC HOOK [2000] */ + {0xabf2, 0xcca4}, /* U+0324 COMBINING DIAERESIS BELOW [2000] */ + {0xabf3, 0xccb0}, /* U+0330 COMBINING TILDE BELOW [2000] */ + {0xabf4, 0xccbc}, /* U+033C COMBINING SEAGULL BELOW [2000] */ + {0xabf5, 0xccb4}, /* U+0334 COMBINING TILDE OVERLAY [2000] */ + {0xabf6, 0xcc9d}, /* U+031D COMBINING UP TACK BELOW [2000] */ + {0xabf7, 0xcc9e}, /* U+031E COMBINING DOWN TACK BELOW [2000] */ + {0xabf8, 0xcc98}, /* U+0318 COMBINING LEFT TACK BELOW [2000] */ + {0xabf9, 0xcc99}, /* U+0319 COMBINING RIGHT TACK BELOW [2000] */ + {0xabfa, 0xccaa}, /* U+032A COMBINING BRIDGE BELOW [2000] */ + {0xabfb, 0xccba}, /* U+033A COMBINING INVERTED BRIDGE BELOW [2000] */ + {0xabfc, 0xccbb}, /* U+033B COMBINING SQUARE BELOW [2000] */ + {0xabfd, 0xcc83}, /* U+0303 COMBINING TILDE [2000] */ + {0xabfe, 0xcc9a}, /* U+031A COMBINING LEFT ANGLE ABOVE [2000] */ + {0xaca1, 0xe29db6}, /* U+2776 DINGBAT NEGATIVE CIRCLED DIGIT ONE [2000] */ + {0xaca2, 0xe29db7}, /* U+2777 DINGBAT NEGATIVE CIRCLED DIGIT TWO [2000] */ + {0xaca3, 0xe29db8}, /* U+2778 DINGBAT NEGATIVE CIRCLED DIGIT THREE [2000] */ + {0xaca4, 0xe29db9}, /* U+2779 DINGBAT NEGATIVE CIRCLED DIGIT FOUR [2000] */ + {0xaca5, 0xe29dba}, /* U+277A DINGBAT NEGATIVE CIRCLED DIGIT FIVE [2000] */ + {0xaca6, 0xe29dbb}, /* U+277B DINGBAT NEGATIVE CIRCLED DIGIT SIX [2000] */ + {0xaca7, 0xe29dbc}, /* U+277C DINGBAT NEGATIVE CIRCLED DIGIT SEVEN [2000] */ + {0xaca8, 0xe29dbd}, /* U+277D DINGBAT NEGATIVE CIRCLED DIGIT EIGHT [2000] */ + {0xaca9, 0xe29dbe}, /* U+277E DINGBAT NEGATIVE CIRCLED DIGIT NINE [2000] */ + {0xacaa, 0xe29dbf}, /* U+277F DINGBAT NEGATIVE CIRCLED NUMBER TEN [2000] */ + {0xacab, 0xe293ab}, /* U+24EB NEGATIVE CIRCLED NUMBER ELEVEN [2000] [Unicode3.2] */ + {0xacac, 0xe293ac}, /* U+24EC NEGATIVE CIRCLED NUMBER TWELVE [2000] [Unicode3.2] */ + {0xacad, 0xe293ad}, /* U+24ED NEGATIVE CIRCLED NUMBER THIRTEEN [2000] [Unicode3.2] */ + {0xacae, 0xe293ae}, /* U+24EE NEGATIVE CIRCLED NUMBER FOURTEEN [2000] [Unicode3.2] */ + {0xacaf, 0xe293af}, /* U+24EF NEGATIVE CIRCLED NUMBER FIFTEEN [2000] [Unicode3.2] */ + {0xacb0, 0xe293b0}, /* U+24F0 NEGATIVE CIRCLED NUMBER SIXTEEN [2000] [Unicode3.2] */ + {0xacb1, 0xe293b1}, /* U+24F1 NEGATIVE CIRCLED NUMBER SEVENTEEN [2000] [Unicode3.2] */ + {0xacb2, 0xe293b2}, /* U+24F2 NEGATIVE CIRCLED NUMBER EIGHTEEN [2000] [Unicode3.2] */ + {0xacb3, 0xe293b3}, /* U+24F3 NEGATIVE CIRCLED NUMBER NINETEEN [2000] [Unicode3.2] */ + {0xacb4, 0xe293b4}, /* U+24F4 NEGATIVE CIRCLED NUMBER TWENTY [2000] [Unicode3.2] */ + {0xacb5, 0xe285b0}, /* U+2170 SMALL ROMAN NUMERAL ONE [2000] */ + {0xacb6, 0xe285b1}, /* U+2171 SMALL ROMAN NUMERAL TWO [2000] */ + {0xacb7, 0xe285b2}, /* U+2172 SMALL ROMAN NUMERAL THREE [2000] */ + {0xacb8, 0xe285b3}, /* U+2173 SMALL ROMAN NUMERAL FOUR [2000] */ + {0xacb9, 0xe285b4}, /* U+2174 SMALL ROMAN NUMERAL FIVE [2000] */ + {0xacba, 0xe285b5}, /* U+2175 SMALL ROMAN NUMERAL SIX [2000] */ + {0xacbb, 0xe285b6}, /* U+2176 SMALL ROMAN NUMERAL SEVEN [2000] */ + {0xacbc, 0xe285b7}, /* U+2177 SMALL ROMAN NUMERAL EIGHT [2000] */ + {0xacbd, 0xe285b8}, /* U+2178 SMALL ROMAN NUMERAL NINE [2000] */ + {0xacbe, 0xe285b9}, /* U+2179 SMALL ROMAN NUMERAL TEN [2000] */ + {0xacbf, 0xe285ba}, /* U+217A SMALL ROMAN NUMERAL ELEVEN [2000] */ + {0xacc0, 0xe285bb}, /* U+217B SMALL ROMAN NUMERAL TWELVE [2000] */ + {0xacc1, 0xe29390}, /* U+24D0 CIRCLED LATIN SMALL LETTER A [2000] */ + {0xacc2, 0xe29391}, /* U+24D1 CIRCLED LATIN SMALL LETTER B [2000] */ + {0xacc3, 0xe29392}, /* U+24D2 CIRCLED LATIN SMALL LETTER C [2000] */ + {0xacc4, 0xe29393}, /* U+24D3 CIRCLED LATIN SMALL LETTER D [2000] */ + {0xacc5, 0xe29394}, /* U+24D4 CIRCLED LATIN SMALL LETTER E [2000] */ + {0xacc6, 0xe29395}, /* U+24D5 CIRCLED LATIN SMALL LETTER F [2000] */ + {0xacc7, 0xe29396}, /* U+24D6 CIRCLED LATIN SMALL LETTER G [2000] */ + {0xacc8, 0xe29397}, /* U+24D7 CIRCLED LATIN SMALL LETTER H [2000] */ + {0xacc9, 0xe29398}, /* U+24D8 CIRCLED LATIN SMALL LETTER I [2000] */ + {0xacca, 0xe29399}, /* U+24D9 CIRCLED LATIN SMALL LETTER J [2000] */ + {0xaccb, 0xe2939a}, /* U+24DA CIRCLED LATIN SMALL LETTER K [2000] */ + {0xaccc, 0xe2939b}, /* U+24DB CIRCLED LATIN SMALL LETTER L [2000] */ + {0xaccd, 0xe2939c}, /* U+24DC CIRCLED LATIN SMALL LETTER M [2000] */ + {0xacce, 0xe2939d}, /* U+24DD CIRCLED LATIN SMALL LETTER N [2000] */ + {0xaccf, 0xe2939e}, /* U+24DE CIRCLED LATIN SMALL LETTER O [2000] */ + {0xacd0, 0xe2939f}, /* U+24DF CIRCLED LATIN SMALL LETTER P [2000] */ + {0xacd1, 0xe293a0}, /* U+24E0 CIRCLED LATIN SMALL LETTER Q [2000] */ + {0xacd2, 0xe293a1}, /* U+24E1 CIRCLED LATIN SMALL LETTER R [2000] */ + {0xacd3, 0xe293a2}, /* U+24E2 CIRCLED LATIN SMALL LETTER S [2000] */ + {0xacd4, 0xe293a3}, /* U+24E3 CIRCLED LATIN SMALL LETTER T [2000] */ + {0xacd5, 0xe293a4}, /* U+24E4 CIRCLED LATIN SMALL LETTER U [2000] */ + {0xacd6, 0xe293a5}, /* U+24E5 CIRCLED LATIN SMALL LETTER V [2000] */ + {0xacd7, 0xe293a6}, /* U+24E6 CIRCLED LATIN SMALL LETTER W [2000] */ + {0xacd8, 0xe293a7}, /* U+24E7 CIRCLED LATIN SMALL LETTER X [2000] */ + {0xacd9, 0xe293a8}, /* U+24E8 CIRCLED LATIN SMALL LETTER Y [2000] */ + {0xacda, 0xe293a9}, /* U+24E9 CIRCLED LATIN SMALL LETTER Z [2000] */ + {0xacdb, 0xe38b90}, /* U+32D0 CIRCLED KATAKANA A [2000] */ + {0xacdc, 0xe38b91}, /* U+32D1 CIRCLED KATAKANA I [2000] */ + {0xacdd, 0xe38b92}, /* U+32D2 CIRCLED KATAKANA U [2000] */ + {0xacde, 0xe38b93}, /* U+32D3 CIRCLED KATAKANA E [2000] */ + {0xacdf, 0xe38b94}, /* U+32D4 CIRCLED KATAKANA O [2000] */ + {0xace0, 0xe38b95}, /* U+32D5 CIRCLED KATAKANA KA [2000] */ + {0xace1, 0xe38b96}, /* U+32D6 CIRCLED KATAKANA KI [2000] */ + {0xace2, 0xe38b97}, /* U+32D7 CIRCLED KATAKANA KU [2000] */ + {0xace3, 0xe38b98}, /* U+32D8 CIRCLED KATAKANA KE [2000] */ + {0xace4, 0xe38b99}, /* U+32D9 CIRCLED KATAKANA KO [2000] */ + {0xace5, 0xe38b9a}, /* U+32DA CIRCLED KATAKANA SA [2000] */ + {0xace6, 0xe38b9b}, /* U+32DB CIRCLED KATAKANA SI [2000] */ + {0xace7, 0xe38b9c}, /* U+32DC CIRCLED KATAKANA SU [2000] */ + {0xace8, 0xe38b9d}, /* U+32DD CIRCLED KATAKANA SE [2000] */ + {0xace9, 0xe38b9e}, /* U+32DE CIRCLED KATAKANA SO [2000] */ + {0xacea, 0xe38b9f}, /* U+32DF CIRCLED KATAKANA TA [2000] */ + {0xaceb, 0xe38ba0}, /* U+32E0 CIRCLED KATAKANA TI [2000] */ + {0xacec, 0xe38ba1}, /* U+32E1 CIRCLED KATAKANA TU [2000] */ + {0xaced, 0xe38ba2}, /* U+32E2 CIRCLED KATAKANA TE [2000] */ + {0xacee, 0xe38ba3}, /* U+32E3 CIRCLED KATAKANA TO [2000] */ + {0xacef, 0xe38bba}, /* U+32FA CIRCLED KATAKANA RO [2000] */ + {0xacf0, 0xe38ba9}, /* U+32E9 CIRCLED KATAKANA HA [2000] */ + {0xacf1, 0xe38ba5}, /* U+32E5 CIRCLED KATAKANA NI [2000] */ + {0xacf2, 0xe38bad}, /* U+32ED CIRCLED KATAKANA HO [2000] */ + {0xacf3, 0xe38bac}, /* U+32EC CIRCLED KATAKANA HE [2000] */ + {0xacfd, 0xe28191}, /* U+2051 TWO ASTERISKS ALIGNED VERTICALLY [2000] [Unicode3.2] */ + {0xacfe, 0xe28182}, /* U+2042 ASTERISM [2000] */ + {0xada1, 0xe291a0}, /* U+2460 CIRCLED DIGIT ONE [2000] */ + {0xada2, 0xe291a1}, /* U+2461 CIRCLED DIGIT TWO [2000] */ + {0xada3, 0xe291a2}, /* U+2462 CIRCLED DIGIT THREE [2000] */ + {0xada4, 0xe291a3}, /* U+2463 CIRCLED DIGIT FOUR [2000] */ + {0xada5, 0xe291a4}, /* U+2464 CIRCLED DIGIT FIVE [2000] */ + {0xada6, 0xe291a5}, /* U+2465 CIRCLED DIGIT SIX [2000] */ + {0xada7, 0xe291a6}, /* U+2466 CIRCLED DIGIT SEVEN [2000] */ + {0xada8, 0xe291a7}, /* U+2467 CIRCLED DIGIT EIGHT [2000] */ + {0xada9, 0xe291a8}, /* U+2468 CIRCLED DIGIT NINE [2000] */ + {0xadaa, 0xe291a9}, /* U+2469 CIRCLED NUMBER TEN [2000] */ + {0xadab, 0xe291aa}, /* U+246A CIRCLED NUMBER ELEVEN [2000] */ + {0xadac, 0xe291ab}, /* U+246B CIRCLED NUMBER TWELVE [2000] */ + {0xadad, 0xe291ac}, /* U+246C CIRCLED NUMBER THIRTEEN [2000] */ + {0xadae, 0xe291ad}, /* U+246D CIRCLED NUMBER FOURTEEN [2000] */ + {0xadaf, 0xe291ae}, /* U+246E CIRCLED NUMBER FIFTEEN [2000] */ + {0xadb0, 0xe291af}, /* U+246F CIRCLED NUMBER SIXTEEN [2000] */ + {0xadb1, 0xe291b0}, /* U+2470 CIRCLED NUMBER SEVENTEEN [2000] */ + {0xadb2, 0xe291b1}, /* U+2471 CIRCLED NUMBER EIGHTEEN [2000] */ + {0xadb3, 0xe291b2}, /* U+2472 CIRCLED NUMBER NINETEEN [2000] */ + {0xadb4, 0xe291b3}, /* U+2473 CIRCLED NUMBER TWENTY [2000] */ + {0xadb5, 0xe285a0}, /* U+2160 ROMAN NUMERAL ONE [2000] */ + {0xadb6, 0xe285a1}, /* U+2161 ROMAN NUMERAL TWO [2000] */ + {0xadb7, 0xe285a2}, /* U+2162 ROMAN NUMERAL THREE [2000] */ + {0xadb8, 0xe285a3}, /* U+2163 ROMAN NUMERAL FOUR [2000] */ + {0xadb9, 0xe285a4}, /* U+2164 ROMAN NUMERAL FIVE [2000] */ + {0xadba, 0xe285a5}, /* U+2165 ROMAN NUMERAL SIX [2000] */ + {0xadbb, 0xe285a6}, /* U+2166 ROMAN NUMERAL SEVEN [2000] */ + {0xadbc, 0xe285a7}, /* U+2167 ROMAN NUMERAL EIGHT [2000] */ + {0xadbd, 0xe285a8}, /* U+2168 ROMAN NUMERAL NINE [2000] */ + {0xadbe, 0xe285a9}, /* U+2169 ROMAN NUMERAL TEN [2000] */ + {0xadbf, 0xe285aa}, /* U+216A ROMAN NUMERAL ELEVEN [2000] */ + {0xadc0, 0xe38d89}, /* U+3349 SQUARE MIRI [2000] */ + {0xadc1, 0xe38c94}, /* U+3314 SQUARE KIRO [2000] */ + {0xadc2, 0xe38ca2}, /* U+3322 SQUARE SENTI [2000] */ + {0xadc3, 0xe38d8d}, /* U+334D SQUARE MEETORU [2000] */ + {0xadc4, 0xe38c98}, /* U+3318 SQUARE GURAMU [2000] */ + {0xadc5, 0xe38ca7}, /* U+3327 SQUARE TON [2000] */ + {0xadc6, 0xe38c83}, /* U+3303 SQUARE AARU [2000] */ + {0xadc7, 0xe38cb6}, /* U+3336 SQUARE HEKUTAARU [2000] */ + {0xadc8, 0xe38d91}, /* U+3351 SQUARE RITTORU [2000] */ + {0xadc9, 0xe38d97}, /* U+3357 SQUARE WATTO [2000] */ + {0xadca, 0xe38c8d}, /* U+330D SQUARE KARORII [2000] */ + {0xadcb, 0xe38ca6}, /* U+3326 SQUARE DORU [2000] */ + {0xadcc, 0xe38ca3}, /* U+3323 SQUARE SENTO [2000] */ + {0xadcd, 0xe38cab}, /* U+332B SQUARE PAASENTO [2000] */ + {0xadce, 0xe38d8a}, /* U+334A SQUARE MIRIBAARU [2000] */ + {0xadcf, 0xe38cbb}, /* U+333B SQUARE PEEZI [2000] */ + {0xadd0, 0xe38e9c}, /* U+339C SQUARE MM [2000] */ + {0xadd1, 0xe38e9d}, /* U+339D SQUARE CM [2000] */ + {0xadd2, 0xe38e9e}, /* U+339E SQUARE KM [2000] */ + {0xadd3, 0xe38e8e}, /* U+338E SQUARE MG [2000] */ + {0xadd4, 0xe38e8f}, /* U+338F SQUARE KG [2000] */ + {0xadd5, 0xe38f84}, /* U+33C4 SQUARE CC [2000] */ + {0xadd6, 0xe38ea1}, /* U+33A1 SQUARE M SQUARED [2000] */ + {0xadd7, 0xe285ab}, /* U+216B ROMAN NUMERAL TWELVE [2000] */ + {0xaddf, 0xe38dbb}, /* U+337B SQUARE ERA NAME HEISEI [2000] */ + {0xade0, 0xe3809d}, /* U+301D REVERSED DOUBLE PRIME QUOTATION MARK [2000] */ + {0xade1, 0xe3809f}, /* U+301F LOW DOUBLE PRIME QUOTATION MARK [2000] */ + {0xade2, 0xe28496}, /* U+2116 NUMERO SIGN [2000] */ + {0xade3, 0xe38f8d}, /* U+33CD SQUARE KK [2000] */ + {0xade4, 0xe284a1}, /* U+2121 TELEPHONE SIGN [2000] */ + {0xade5, 0xe38aa4}, /* U+32A4 CIRCLED IDEOGRAPH HIGH [2000] */ + {0xade6, 0xe38aa5}, /* U+32A5 CIRCLED IDEOGRAPH CENTRE [2000] */ + {0xade7, 0xe38aa6}, /* U+32A6 CIRCLED IDEOGRAPH LOW [2000] */ + {0xade8, 0xe38aa7}, /* U+32A7 CIRCLED IDEOGRAPH LEFT [2000] */ + {0xade9, 0xe38aa8}, /* U+32A8 CIRCLED IDEOGRAPH RIGHT [2000] */ + {0xadea, 0xe388b1}, /* U+3231 PARENTHESIZED IDEOGRAPH STOCK [2000] */ + {0xadeb, 0xe388b2}, /* U+3232 PARENTHESIZED IDEOGRAPH HAVE [2000] */ + {0xadec, 0xe388b9}, /* U+3239 PARENTHESIZED IDEOGRAPH REPRESENT [2000] */ + {0xaded, 0xe38dbe}, /* U+337E SQUARE ERA NAME MEIZI [2000] */ + {0xadee, 0xe38dbd}, /* U+337D SQUARE ERA NAME TAISYOU [2000] */ + {0xadef, 0xe38dbc}, /* U+337C SQUARE ERA NAME SYOUWA [2000] */ + {0xadf3, 0xe288ae}, /* U+222E CONTOUR INTEGRAL [2000] */ + {0xadf8, 0xe2889f}, /* U+221F RIGHT ANGLE [2000] */ + {0xadf9, 0xe28abf}, /* U+22BF RIGHT TRIANGLE [2000] */ + {0xadfd, 0xe29d96}, /* U+2756 BLACK DIAMOND MINUS WHITE X [2000] */ + {0xadfe, 0xe2989e}, /* U+261E WHITE RIGHT POINTING INDEX [2000] */ + {0xaea1, 0xe4bfb1}, /* U+4FF1 [2004] */ + {0xaea2, 0xf0a0808b}, /* U+2000B [2000] [Unicode3.1] */ + {0xaea3, 0xe39082}, /* U+3402 [2000] */ + {0xaea4, 0xe4b8a8}, /* U+4E28 [2000] */ + {0xaea5, 0xe4b8af}, /* U+4E2F [2000] */ + {0xaea6, 0xe4b8b0}, /* U+4E30 [2000] */ + {0xaea7, 0xe4ba8d}, /* U+4E8D [2000] */ + {0xaea8, 0xe4bba1}, /* U+4EE1 [2000] */ + {0xaea9, 0xe4bbbd}, /* U+4EFD [2000] */ + {0xaeaa, 0xe4bbbf}, /* U+4EFF [2000] */ + {0xaeab, 0xe4bc83}, /* U+4F03 [2000] */ + {0xaeac, 0xe4bc8b}, /* U+4F0B [2000] */ + {0xaead, 0xe4bda0}, /* U+4F60 [2000] */ + {0xaeae, 0xe4bd88}, /* U+4F48 [2000] */ + {0xaeaf, 0xe4bd89}, /* U+4F49 [2000] */ + {0xaeb0, 0xe4bd96}, /* U+4F56 [2000] */ + {0xaeb1, 0xe4bd9f}, /* U+4F5F [2000] */ + {0xaeb2, 0xe4bdaa}, /* U+4F6A [2000] */ + {0xaeb3, 0xe4bdac}, /* U+4F6C [2000] */ + {0xaeb4, 0xe4bdbe}, /* U+4F7E [2000] */ + {0xaeb5, 0xe4be8a}, /* U+4F8A [2000] */ + {0xaeb6, 0xe4be94}, /* U+4F94 [2000] */ + {0xaeb7, 0xe4be97}, /* U+4F97 [2000] */ + {0xaeb8, 0xefa8b0}, /* U+FA30 CJK COMPATIBILITY IDEOGRAPH-FA30 [2000] [Unicode3.2] */ + {0xaeb9, 0xe4bf89}, /* U+4FC9 [2000] */ + {0xaeba, 0xe4bfa0}, /* U+4FE0 [2000] */ + {0xaebb, 0xe58081}, /* U+5001 [2000] */ + {0xaebc, 0xe58082}, /* U+5002 [2000] */ + {0xaebd, 0xe5808e}, /* U+500E [2000] */ + {0xaebe, 0xe58098}, /* U+5018 [2000] */ + {0xaebf, 0xe580a7}, /* U+5027 [2000] */ + {0xaec0, 0xe580ae}, /* U+502E [2000] */ + {0xaec1, 0xe58180}, /* U+5040 [2000] */ + {0xaec2, 0xe580bb}, /* U+503B [2000] */ + {0xaec3, 0xe58181}, /* U+5041 [2000] */ + {0xaec4, 0xe58294}, /* U+5094 [2000] */ + {0xaec5, 0xe5838c}, /* U+50CC [2000] */ + {0xaec6, 0xe583b2}, /* U+50F2 [2000] */ + {0xaec7, 0xe58390}, /* U+50D0 [2000] */ + {0xaec8, 0xe583a6}, /* U+50E6 [2000] */ + {0xaec9, 0xefa8b1}, /* U+FA31 CJK COMPATIBILITY IDEOGRAPH-FA31 [2000] [Unicode3.2] */ + {0xaeca, 0xe58486}, /* U+5106 [2000] */ + {0xaecb, 0xe58483}, /* U+5103 [2000] */ + {0xaecc, 0xe5848b}, /* U+510B [2000] */ + {0xaecd, 0xe5849e}, /* U+511E [2000] */ + {0xaece, 0xe584b5}, /* U+5135 [2000] */ + {0xaecf, 0xe5858a}, /* U+514A [2000] */ + {0xaed0, 0xefa8b2}, /* U+FA32 CJK COMPATIBILITY IDEOGRAPH-FA32 [2000] [Unicode3.2] */ + {0xaed1, 0xe58595}, /* U+5155 [2000] */ + {0xaed2, 0xe58597}, /* U+5157 [2000] */ + {0xaed3, 0xe392b5}, /* U+34B5 [2000] */ + {0xaed4, 0xe5869d}, /* U+519D [2000] */ + {0xaed5, 0xe58783}, /* U+51C3 [2000] */ + {0xaed6, 0xe5878a}, /* U+51CA [2000] */ + {0xaed7, 0xe5879e}, /* U+51DE [2000] */ + {0xaed8, 0xe587a2}, /* U+51E2 [2000] */ + {0xaed9, 0xe587ae}, /* U+51EE [2000] */ + {0xaeda, 0xe58881}, /* U+5201 [2000] */ + {0xaedb, 0xe3939b}, /* U+34DB [2000] */ + {0xaedc, 0xe58893}, /* U+5213 [2000] */ + {0xaedd, 0xe58895}, /* U+5215 [2000] */ + {0xaede, 0xe58989}, /* U+5249 [2000] */ + {0xaedf, 0xe58997}, /* U+5257 [2000] */ + {0xaee0, 0xe589a1}, /* U+5261 [2000] */ + {0xaee1, 0xe58a93}, /* U+5293 [2000] */ + {0xaee2, 0xe58b88}, /* U+52C8 [2000] */ + {0xaee3, 0xefa8b3}, /* U+FA33 CJK COMPATIBILITY IDEOGRAPH-FA33 [2000] [Unicode3.2] */ + {0xaee4, 0xe58b8c}, /* U+52CC [2000] */ + {0xaee5, 0xe58b90}, /* U+52D0 [2000] */ + {0xaee6, 0xe58b96}, /* U+52D6 [2000] */ + {0xaee7, 0xe58b9b}, /* U+52DB [2000] */ + {0xaee8, 0xefa8b4}, /* U+FA34 CJK COMPATIBILITY IDEOGRAPH-FA34 [2000] [Unicode3.2] */ + {0xaee9, 0xe58bb0}, /* U+52F0 [2000] */ + {0xaeea, 0xe58bbb}, /* U+52FB [2000] */ + {0xaeeb, 0xe58c80}, /* U+5300 [2000] */ + {0xaeec, 0xe58c87}, /* U+5307 [2000] */ + {0xaeed, 0xe58c9c}, /* U+531C [2000] */ + {0xaeee, 0xefa8b5}, /* U+FA35 CJK COMPATIBILITY IDEOGRAPH-FA35 [2000] [Unicode3.2] */ + {0xaeef, 0xe58da1}, /* U+5361 [2000] */ + {0xaef0, 0xe58da3}, /* U+5363 [2000] */ + {0xaef1, 0xe58dbd}, /* U+537D [2000] */ + {0xaef2, 0xe58e93}, /* U+5393 [2000] */ + {0xaef3, 0xe58e9d}, /* U+539D [2000] */ + {0xaef4, 0xe58eb2}, /* U+53B2 [2000] */ + {0xaef5, 0xe59092}, /* U+5412 [2000] */ + {0xaef6, 0xe590a7}, /* U+5427 [2000] */ + {0xaef7, 0xe5918d}, /* U+544D [2000] */ + {0xaef8, 0xe5929c}, /* U+549C [2000] */ + {0xaef9, 0xe591ab}, /* U+546B [2000] */ + {0xaefa, 0xe591b4}, /* U+5474 [2000] */ + {0xaefb, 0xe591bf}, /* U+547F [2000] */ + {0xaefc, 0xe59288}, /* U+5488 [2000] */ + {0xaefd, 0xe59296}, /* U+5496 [2000] */ + {0xaefe, 0xe592a1}, /* U+54A1 [2000] */ + {0xafa1, 0xe592a9}, /* U+54A9 [2000] */ + {0xafa2, 0xe59386}, /* U+54C6 [2000] */ + {0xafa3, 0xe593bf}, /* U+54FF [2000] */ + {0xafa4, 0xe5948e}, /* U+550E [2000] */ + {0xafa5, 0xe594ab}, /* U+552B [2000] */ + {0xafa6, 0xe594b5}, /* U+5535 [2000] */ + {0xafa7, 0xe59590}, /* U+5550 [2000] */ + {0xafa8, 0xe5959e}, /* U+555E [2000] */ + {0xafa9, 0xe59681}, /* U+5581 [2000] */ + {0xafaa, 0xe59686}, /* U+5586 [2000] */ + {0xafab, 0xe5968e}, /* U+558E [2000] */ + {0xafac, 0xefa8b6}, /* U+FA36 CJK COMPATIBILITY IDEOGRAPH-FA36 [2000] [Unicode3.2] */ + {0xafad, 0xe596ad}, /* U+55AD [2000] */ + {0xafae, 0xe5978e}, /* U+55CE [2000] */ + {0xafaf, 0xefa8b7}, /* U+FA37 CJK COMPATIBILITY IDEOGRAPH-FA37 [2000] [Unicode3.2] */ + {0xafb0, 0xe59888}, /* U+5608 [2000] */ + {0xafb1, 0xe5988e}, /* U+560E [2000] */ + {0xafb2, 0xe598bb}, /* U+563B [2000] */ + {0xafb3, 0xe59989}, /* U+5649 [2000] */ + {0xafb4, 0xe599b6}, /* U+5676 [2000] */ + {0xafb5, 0xe599a6}, /* U+5666 [2000] */ + {0xafb6, 0xefa8b8}, /* U+FA38 CJK COMPATIBILITY IDEOGRAPH-FA38 [2000] [Unicode3.2] */ + {0xafb7, 0xe599af}, /* U+566F [2000] */ + {0xafb8, 0xe599b1}, /* U+5671 [2000] */ + {0xafb9, 0xe599b2}, /* U+5672 [2000] */ + {0xafba, 0xe59a99}, /* U+5699 [2000] */ + {0xafbb, 0xe59a9e}, /* U+569E [2000] */ + {0xafbc, 0xe59aa9}, /* U+56A9 [2000] */ + {0xafbd, 0xe59aac}, /* U+56AC [2000] */ + {0xafbe, 0xe59ab3}, /* U+56B3 [2000] */ + {0xafbf, 0xe59b89}, /* U+56C9 [2000] */ + {0xafc0, 0xe59b8a}, /* U+56CA [2000] */ + {0xafc1, 0xe59c8a}, /* U+570A [2000] */ + {0xafc2, 0xf0a188bd}, /* U+2123D [2000] [Unicode3.1] */ + {0xafc3, 0xe59ca1}, /* U+5721 [2000] */ + {0xafc4, 0xe59caf}, /* U+572F [2000] */ + {0xafc5, 0xe59cb3}, /* U+5733 [2000] */ + {0xafc6, 0xe59cb4}, /* U+5734 [2000] */ + {0xafc7, 0xe59db0}, /* U+5770 [2000] */ + {0xafc8, 0xe59db7}, /* U+5777 [2000] */ + {0xafc9, 0xe59dbc}, /* U+577C [2000] */ + {0xafca, 0xe59e9c}, /* U+579C [2000] */ + {0xafcb, 0xefa88f}, /* U+FA0F CJK COMPATIBILITY IDEOGRAPH-FA0F [2000] */ + {0xafcc, 0xf0a18c9b}, /* U+2131B [2000] [Unicode3.1] */ + {0xafcd, 0xe59eb8}, /* U+57B8 [2000] */ + {0xafce, 0xe59f87}, /* U+57C7 [2000] */ + {0xafcf, 0xe59f88}, /* U+57C8 [2000] */ + {0xafd0, 0xe59f8f}, /* U+57CF [2000] */ + {0xafd1, 0xe59fa4}, /* U+57E4 [2000] */ + {0xafd2, 0xe59fad}, /* U+57ED [2000] */ + {0xafd3, 0xe59fb5}, /* U+57F5 [2000] */ + {0xafd4, 0xe59fb6}, /* U+57F6 [2000] */ + {0xafd5, 0xe59fbf}, /* U+57FF [2000] */ + {0xafd6, 0xe5a089}, /* U+5809 [2000] */ + {0xafd7, 0xefa890}, /* U+FA10 CJK COMPATIBILITY IDEOGRAPH-FA10 [2000] */ + {0xafd8, 0xe5a1a1}, /* U+5861 [2000] */ + {0xafd9, 0xe5a1a4}, /* U+5864 [2000] */ + {0xafda, 0xefa8b9}, /* U+FA39 CJK COMPATIBILITY IDEOGRAPH-FA39 [2000] [Unicode3.2] */ + {0xafdb, 0xe5a1bc}, /* U+587C [2000] */ + {0xafdc, 0xe5a289}, /* U+5889 [2000] */ + {0xafdd, 0xe5a29e}, /* U+589E [2000] */ + {0xafde, 0xefa8ba}, /* U+FA3A CJK COMPATIBILITY IDEOGRAPH-FA3A [2000] [Unicode3.2] */ + {0xafdf, 0xe5a2a9}, /* U+58A9 [2000] */ + {0xafe0, 0xf0a191ae}, /* U+2146E [2000] [Unicode3.1] */ + {0xafe1, 0xe5a392}, /* U+58D2 [2000] */ + {0xafe2, 0xe5a38e}, /* U+58CE [2000] */ + {0xafe3, 0xe5a394}, /* U+58D4 [2000] */ + {0xafe4, 0xe5a39a}, /* U+58DA [2000] */ + {0xafe5, 0xe5a3a0}, /* U+58E0 [2000] */ + {0xafe6, 0xe5a3a9}, /* U+58E9 [2000] */ + {0xafe7, 0xe5a48c}, /* U+590C [2000] */ + {0xafe8, 0xe89981}, /* U+8641 [2000] */ + {0xafe9, 0xe5a59d}, /* U+595D [2000] */ + {0xafea, 0xe5a5ad}, /* U+596D [2000] */ + {0xafeb, 0xe5a68b}, /* U+598B [2000] */ + {0xafec, 0xe5a692}, /* U+5992 [2000] */ + {0xafed, 0xe5a6a4}, /* U+59A4 [2000] */ + {0xafee, 0xe5a783}, /* U+59C3 [2000] */ + {0xafef, 0xe5a792}, /* U+59D2 [2000] */ + {0xaff0, 0xe5a79d}, /* U+59DD [2000] */ + {0xaff1, 0xe5a893}, /* U+5A13 [2000] */ + {0xaff2, 0xe5a8a3}, /* U+5A23 [2000] */ + {0xaff3, 0xe5a9a7}, /* U+5A67 [2000] */ + {0xaff4, 0xe5a9ad}, /* U+5A6D [2000] */ + {0xaff5, 0xe5a9b7}, /* U+5A77 [2000] */ + {0xaff6, 0xe5a9be}, /* U+5A7E [2000] */ + {0xaff7, 0xe5aa84}, /* U+5A84 [2000] */ + {0xaff8, 0xe5aa9e}, /* U+5A9E [2000] */ + {0xaff9, 0xe5aaa7}, /* U+5AA7 [2000] */ + {0xaffa, 0xe5ab84}, /* U+5AC4 [2000] */ + {0xaffb, 0xf0a1a2bd}, /* U+218BD [2000] [Unicode3.1] */ + {0xaffc, 0xe5ac99}, /* U+5B19 [2000] */ + {0xaffd, 0xe5aca5}, /* U+5B25 [2000] */ + {0xaffe, 0xe5899d}, /* U+525D [2004] */ + {0xb0a1, 0xe4ba9c}, /* U+4E9C */ + {0xb0a2, 0xe59496}, /* U+5516 */ + {0xb0a3, 0xe5a883}, /* U+5A03 */ + {0xb0a4, 0xe998bf}, /* U+963F */ + {0xb0a5, 0xe59380}, /* U+54C0 */ + {0xb0a6, 0xe6849b}, /* U+611B */ + {0xb0a7, 0xe68ca8}, /* U+6328 */ + {0xb0a8, 0xe5a7b6}, /* U+59F6 */ + {0xb0a9, 0xe980a2}, /* U+9022 */ + {0xb0aa, 0xe891b5}, /* U+8475 */ + {0xb0ab, 0xe88c9c}, /* U+831C */ + {0xb0ac, 0xe7a990}, /* U+7A50 */ + {0xb0ad, 0xe682aa}, /* U+60AA */ + {0xb0ae, 0xe68fa1}, /* U+63E1 */ + {0xb0af, 0xe6b8a5}, /* U+6E25 */ + {0xb0b0, 0xe697ad}, /* U+65ED */ + {0xb0b1, 0xe891a6}, /* U+8466 */ + {0xb0b2, 0xe88aa6}, /* U+82A6 */ + {0xb0b3, 0xe9afb5}, /* U+9BF5 */ + {0xb0b4, 0xe6a293}, /* U+6893 */ + {0xb0b5, 0xe59ca7}, /* U+5727 */ + {0xb0b6, 0xe696a1}, /* U+65A1 */ + {0xb0b7, 0xe689b1}, /* U+6271 */ + {0xb0b8, 0xe5ae9b}, /* U+5B9B */ + {0xb0b9, 0xe5a790}, /* U+59D0 */ + {0xb0ba, 0xe899bb}, /* U+867B */ + {0xb0bb, 0xe9a3b4}, /* U+98F4 */ + {0xb0bc, 0xe7b5a2}, /* U+7D62 */ + {0xb0bd, 0xe7b6be}, /* U+7DBE */ + {0xb0be, 0xe9ae8e}, /* U+9B8E */ + {0xb0bf, 0xe68896}, /* U+6216 */ + {0xb0c0, 0xe7b29f}, /* U+7C9F */ + {0xb0c1, 0xe8a2b7}, /* U+88B7 */ + {0xb0c2, 0xe5ae89}, /* U+5B89 */ + {0xb0c3, 0xe5bab5}, /* U+5EB5 */ + {0xb0c4, 0xe68c89}, /* U+6309 */ + {0xb0c5, 0xe69a97}, /* U+6697 */ + {0xb0c6, 0xe6a188}, /* U+6848 */ + {0xb0c7, 0xe99787}, /* U+95C7 */ + {0xb0c8, 0xe99e8d}, /* U+978D */ + {0xb0c9, 0xe69d8f}, /* U+674F */ + {0xb0ca, 0xe4bba5}, /* U+4EE5 */ + {0xb0cb, 0xe4bc8a}, /* U+4F0A */ + {0xb0cc, 0xe4bd8d}, /* U+4F4D */ + {0xb0cd, 0xe4be9d}, /* U+4F9D */ + {0xb0ce, 0xe58189}, /* U+5049 */ + {0xb0cf, 0xe59bb2}, /* U+56F2 */ + {0xb0d0, 0xe5a4b7}, /* U+5937 */ + {0xb0d1, 0xe5a794}, /* U+59D4 */ + {0xb0d2, 0xe5a881}, /* U+5A01 */ + {0xb0d3, 0xe5b089}, /* U+5C09 */ + {0xb0d4, 0xe6839f}, /* U+60DF */ + {0xb0d5, 0xe6848f}, /* U+610F */ + {0xb0d6, 0xe685b0}, /* U+6170 */ + {0xb0d7, 0xe69893}, /* U+6613 */ + {0xb0d8, 0xe6a485}, /* U+6905 */ + {0xb0d9, 0xe782ba}, /* U+70BA */ + {0xb0da, 0xe7958f}, /* U+754F */ + {0xb0db, 0xe795b0}, /* U+7570 */ + {0xb0dc, 0xe7a7bb}, /* U+79FB */ + {0xb0dd, 0xe7b6ad}, /* U+7DAD */ + {0xb0de, 0xe7b7af}, /* U+7DEF */ + {0xb0df, 0xe88383}, /* U+80C3 */ + {0xb0e0, 0xe8908e}, /* U+840E */ + {0xb0e1, 0xe8a1a3}, /* U+8863 */ + {0xb0e2, 0xe8ac82}, /* U+8B02 */ + {0xb0e3, 0xe98195}, /* U+9055 */ + {0xb0e4, 0xe981ba}, /* U+907A */ + {0xb0e5, 0xe58cbb}, /* U+533B */ + {0xb0e6, 0xe4ba95}, /* U+4E95 */ + {0xb0e7, 0xe4baa5}, /* U+4EA5 */ + {0xb0e8, 0xe59f9f}, /* U+57DF */ + {0xb0e9, 0xe882b2}, /* U+80B2 */ + {0xb0ea, 0xe98381}, /* U+90C1 */ + {0xb0eb, 0xe7a3af}, /* U+78EF */ + {0xb0ec, 0xe4b880}, /* U+4E00 */ + {0xb0ed, 0xe5a3b1}, /* U+58F1 */ + {0xb0ee, 0xe6baa2}, /* U+6EA2 */ + {0xb0ef, 0xe980b8}, /* U+9038 */ + {0xb0f0, 0xe7a8b2}, /* U+7A32 */ + {0xb0f1, 0xe88ca8}, /* U+8328 */ + {0xb0f2, 0xe88a8b}, /* U+828B */ + {0xb0f3, 0xe9b0af}, /* U+9C2F */ + {0xb0f4, 0xe58581}, /* U+5141 */ + {0xb0f5, 0xe58db0}, /* U+5370 */ + {0xb0f6, 0xe592bd}, /* U+54BD */ + {0xb0f7, 0xe593a1}, /* U+54E1 */ + {0xb0f8, 0xe59ba0}, /* U+56E0 */ + {0xb0f9, 0xe5a7bb}, /* U+59FB */ + {0xb0fa, 0xe5bc95}, /* U+5F15 */ + {0xb0fb, 0xe9a3b2}, /* U+98F2 */ + {0xb0fc, 0xe6b7ab}, /* U+6DEB */ + {0xb0fd, 0xe883a4}, /* U+80E4 */ + {0xb0fe, 0xe894ad}, /* U+852D */ + {0xb1a1, 0xe999a2}, /* U+9662 */ + {0xb1a2, 0xe999b0}, /* U+9670 */ + {0xb1a3, 0xe99aa0}, /* U+96A0 */ + {0xb1a4, 0xe99fbb}, /* U+97FB */ + {0xb1a5, 0xe5908b}, /* U+540B */ + {0xb1a6, 0xe58fb3}, /* U+53F3 */ + {0xb1a7, 0xe5ae87}, /* U+5B87 */ + {0xb1a8, 0xe7838f}, /* U+70CF */ + {0xb1a9, 0xe7bebd}, /* U+7FBD */ + {0xb1aa, 0xe8bf82}, /* U+8FC2 */ + {0xb1ab, 0xe99ba8}, /* U+96E8 */ + {0xb1ac, 0xe58daf}, /* U+536F */ + {0xb1ad, 0xe9b59c}, /* U+9D5C */ + {0xb1ae, 0xe7aaba}, /* U+7ABA */ + {0xb1af, 0xe4b891}, /* U+4E11 */ + {0xb1b0, 0xe7a293}, /* U+7893 */ + {0xb1b1, 0xe887bc}, /* U+81FC */ + {0xb1b2, 0xe6b8a6}, /* U+6E26 */ + {0xb1b3, 0xe59898}, /* U+5618 */ + {0xb1b4, 0xe59484}, /* U+5504 */ + {0xb1b5, 0xe6ac9d}, /* U+6B1D */ + {0xb1b6, 0xe8949a}, /* U+851A */ + {0xb1b7, 0xe9b0bb}, /* U+9C3B */ + {0xb1b8, 0xe5a7a5}, /* U+59E5 */ + {0xb1b9, 0xe58ea9}, /* U+53A9 */ + {0xb1ba, 0xe6b5a6}, /* U+6D66 */ + {0xb1bb, 0xe7939c}, /* U+74DC */ + {0xb1bc, 0xe9968f}, /* U+958F */ + {0xb1bd, 0xe59982}, /* U+5642 */ + {0xb1be, 0xe4ba91}, /* U+4E91 */ + {0xb1bf, 0xe9818b}, /* U+904B */ + {0xb1c0, 0xe99bb2}, /* U+96F2 */ + {0xb1c1, 0xe88d8f}, /* U+834F */ + {0xb1c2, 0xe9a48c}, /* U+990C */ + {0xb1c3, 0xe58fa1}, /* U+53E1 */ + {0xb1c4, 0xe596b6}, /* U+55B6 */ + {0xb1c5, 0xe5acb0}, /* U+5B30 */ + {0xb1c6, 0xe5bdb1}, /* U+5F71 */ + {0xb1c7, 0xe698a0}, /* U+6620 */ + {0xb1c8, 0xe69bb3}, /* U+66F3 */ + {0xb1c9, 0xe6a084}, /* U+6804 */ + {0xb1ca, 0xe6b0b8}, /* U+6C38 */ + {0xb1cb, 0xe6b3b3}, /* U+6CF3 */ + {0xb1cc, 0xe6b4a9}, /* U+6D29 */ + {0xb1cd, 0xe7919b}, /* U+745B */ + {0xb1ce, 0xe79b88}, /* U+76C8 */ + {0xb1cf, 0xe7a98e}, /* U+7A4E */ + {0xb1d0, 0xe9a0b4}, /* U+9834 */ + {0xb1d1, 0xe88bb1}, /* U+82F1 */ + {0xb1d2, 0xe8a19b}, /* U+885B */ + {0xb1d3, 0xe8a9a0}, /* U+8A60 */ + {0xb1d4, 0xe98bad}, /* U+92ED */ + {0xb1d5, 0xe6b6b2}, /* U+6DB2 */ + {0xb1d6, 0xe796ab}, /* U+75AB */ + {0xb1d7, 0xe79b8a}, /* U+76CA */ + {0xb1d8, 0xe9a785}, /* U+99C5 */ + {0xb1d9, 0xe682a6}, /* U+60A6 */ + {0xb1da, 0xe8ac81}, /* U+8B01 */ + {0xb1db, 0xe8b68a}, /* U+8D8A */ + {0xb1dc, 0xe996b2}, /* U+95B2 */ + {0xb1dd, 0xe6a68e}, /* U+698E */ + {0xb1de, 0xe58ead}, /* U+53AD */ + {0xb1df, 0xe58686}, /* U+5186 */ + {0xb1e0, 0xe59c92}, /* U+5712 */ + {0xb1e1, 0xe5a0b0}, /* U+5830 */ + {0xb1e2, 0xe5a584}, /* U+5944 */ + {0xb1e3, 0xe5aeb4}, /* U+5BB4 */ + {0xb1e4, 0xe5bbb6}, /* U+5EF6 */ + {0xb1e5, 0xe680a8}, /* U+6028 */ + {0xb1e6, 0xe68ea9}, /* U+63A9 */ + {0xb1e7, 0xe68fb4}, /* U+63F4 */ + {0xb1e8, 0xe6b2bf}, /* U+6CBF */ + {0xb1e9, 0xe6bc94}, /* U+6F14 */ + {0xb1ea, 0xe7828e}, /* U+708E */ + {0xb1eb, 0xe78494}, /* U+7114 */ + {0xb1ec, 0xe78599}, /* U+7159 */ + {0xb1ed, 0xe78795}, /* U+71D5 */ + {0xb1ee, 0xe78cbf}, /* U+733F */ + {0xb1ef, 0xe7b881}, /* U+7E01 */ + {0xb1f0, 0xe889b6}, /* U+8276 */ + {0xb1f1, 0xe88b91}, /* U+82D1 */ + {0xb1f2, 0xe89697}, /* U+8597 */ + {0xb1f3, 0xe981a0}, /* U+9060 */ + {0xb1f4, 0xe9899b}, /* U+925B */ + {0xb1f5, 0xe9b49b}, /* U+9D1B */ + {0xb1f6, 0xe5a1a9}, /* U+5869 */ + {0xb1f7, 0xe696bc}, /* U+65BC */ + {0xb1f8, 0xe6b19a}, /* U+6C5A */ + {0xb1f9, 0xe794a5}, /* U+7525 */ + {0xb1fa, 0xe587b9}, /* U+51F9 */ + {0xb1fb, 0xe5a4ae}, /* U+592E */ + {0xb1fc, 0xe5a5a5}, /* U+5965 */ + {0xb1fd, 0xe5be80}, /* U+5F80 */ + {0xb1fe, 0xe5bf9c}, /* U+5FDC */ + {0xb2a1, 0xe68abc}, /* U+62BC */ + {0xb2a2, 0xe697ba}, /* U+65FA */ + {0xb2a3, 0xe6a8aa}, /* U+6A2A */ + {0xb2a4, 0xe6aca7}, /* U+6B27 */ + {0xb2a5, 0xe6aeb4}, /* U+6BB4 */ + {0xb2a6, 0xe78e8b}, /* U+738B */ + {0xb2a7, 0xe7bf81}, /* U+7FC1 */ + {0xb2a8, 0xe8a596}, /* U+8956 */ + {0xb2a9, 0xe9b4ac}, /* U+9D2C */ + {0xb2aa, 0xe9b48e}, /* U+9D0E */ + {0xb2ab, 0xe9bb84}, /* U+9EC4 */ + {0xb2ac, 0xe5b2a1}, /* U+5CA1 */ + {0xb2ad, 0xe6b296}, /* U+6C96 */ + {0xb2ae, 0xe88dbb}, /* U+837B */ + {0xb2af, 0xe58484}, /* U+5104 */ + {0xb2b0, 0xe5b18b}, /* U+5C4B */ + {0xb2b1, 0xe686b6}, /* U+61B6 */ + {0xb2b2, 0xe88786}, /* U+81C6 */ + {0xb2b3, 0xe6a1b6}, /* U+6876 */ + {0xb2b4, 0xe789a1}, /* U+7261 */ + {0xb2b5, 0xe4b999}, /* U+4E59 */ + {0xb2b6, 0xe4bfba}, /* U+4FFA */ + {0xb2b7, 0xe58db8}, /* U+5378 */ + {0xb2b8, 0xe681a9}, /* U+6069 */ + {0xb2b9, 0xe6b8a9}, /* U+6E29 */ + {0xb2ba, 0xe7a98f}, /* U+7A4F */ + {0xb2bb, 0xe99fb3}, /* U+97F3 */ + {0xb2bc, 0xe4b88b}, /* U+4E0B */ + {0xb2bd, 0xe58c96}, /* U+5316 */ + {0xb2be, 0xe4bbae}, /* U+4EEE */ + {0xb2bf, 0xe4bd95}, /* U+4F55 */ + {0xb2c0, 0xe4bcbd}, /* U+4F3D */ + {0xb2c1, 0xe4bea1}, /* U+4FA1 */ + {0xb2c2, 0xe4bdb3}, /* U+4F73 */ + {0xb2c3, 0xe58aa0}, /* U+52A0 */ + {0xb2c4, 0xe58faf}, /* U+53EF */ + {0xb2c5, 0xe59889}, /* U+5609 */ + {0xb2c6, 0xe5a48f}, /* U+590F */ + {0xb2c7, 0xe5ab81}, /* U+5AC1 */ + {0xb2c8, 0xe5aeb6}, /* U+5BB6 */ + {0xb2c9, 0xe5afa1}, /* U+5BE1 */ + {0xb2ca, 0xe7a791}, /* U+79D1 */ + {0xb2cb, 0xe69a87}, /* U+6687 */ + {0xb2cc, 0xe69e9c}, /* U+679C */ + {0xb2cd, 0xe69eb6}, /* U+67B6 */ + {0xb2ce, 0xe6ad8c}, /* U+6B4C */ + {0xb2cf, 0xe6b2b3}, /* U+6CB3 */ + {0xb2d0, 0xe781ab}, /* U+706B */ + {0xb2d1, 0xe78f82}, /* U+73C2 */ + {0xb2d2, 0xe7a68d}, /* U+798D */ + {0xb2d3, 0xe7a6be}, /* U+79BE */ + {0xb2d4, 0xe7a8bc}, /* U+7A3C */ + {0xb2d5, 0xe7ae87}, /* U+7B87 */ + {0xb2d6, 0xe88ab1}, /* U+82B1 */ + {0xb2d7, 0xe88b9b}, /* U+82DB */ + {0xb2d8, 0xe88c84}, /* U+8304 */ + {0xb2d9, 0xe88db7}, /* U+8377 */ + {0xb2da, 0xe88faf}, /* U+83EF */ + {0xb2db, 0xe88f93}, /* U+83D3 */ + {0xb2dc, 0xe89da6}, /* U+8766 */ + {0xb2dd, 0xe8aab2}, /* U+8AB2 */ + {0xb2de, 0xe598a9}, /* U+5629 */ + {0xb2df, 0xe8b2a8}, /* U+8CA8 */ + {0xb2e0, 0xe8bfa6}, /* U+8FE6 */ + {0xb2e1, 0xe9818e}, /* U+904E */ + {0xb2e2, 0xe99c9e}, /* U+971E */ + {0xb2e3, 0xe89a8a}, /* U+868A */ + {0xb2e4, 0xe4bf84}, /* U+4FC4 */ + {0xb2e5, 0xe5b3a8}, /* U+5CE8 */ + {0xb2e6, 0xe68891}, /* U+6211 */ + {0xb2e7, 0xe78999}, /* U+7259 */ + {0xb2e8, 0xe794bb}, /* U+753B */ + {0xb2e9, 0xe887a5}, /* U+81E5 */ + {0xb2ea, 0xe88abd}, /* U+82BD */ + {0xb2eb, 0xe89bbe}, /* U+86FE */ + {0xb2ec, 0xe8b380}, /* U+8CC0 */ + {0xb2ed, 0xe99b85}, /* U+96C5 */ + {0xb2ee, 0xe9a493}, /* U+9913 */ + {0xb2ef, 0xe9a795}, /* U+99D5 */ + {0xb2f0, 0xe4bb8b}, /* U+4ECB */ + {0xb2f1, 0xe4bc9a}, /* U+4F1A */ + {0xb2f2, 0xe8a7a3}, /* U+89E3 */ + {0xb2f3, 0xe59b9e}, /* U+56DE */ + {0xb2f4, 0xe5a18a}, /* U+584A */ + {0xb2f5, 0xe5a38a}, /* U+58CA */ + {0xb2f6, 0xe5bbbb}, /* U+5EFB */ + {0xb2f7, 0xe5bfab}, /* U+5FEB */ + {0xb2f8, 0xe680aa}, /* U+602A */ + {0xb2f9, 0xe68294}, /* U+6094 */ + {0xb2fa, 0xe681a2}, /* U+6062 */ + {0xb2fb, 0xe68790}, /* U+61D0 */ + {0xb2fc, 0xe68892}, /* U+6212 */ + {0xb2fd, 0xe68b90}, /* U+62D0 */ + {0xb2fe, 0xe694b9}, /* U+6539 */ + {0xb3a1, 0xe9ad81}, /* U+9B41 */ + {0xb3a2, 0xe699a6}, /* U+6666 */ + {0xb3a3, 0xe6a2b0}, /* U+68B0 */ + {0xb3a4, 0xe6b5b7}, /* U+6D77 */ + {0xb3a5, 0xe781b0}, /* U+7070 */ + {0xb3a6, 0xe7958c}, /* U+754C */ + {0xb3a7, 0xe79a86}, /* U+7686 */ + {0xb3a8, 0xe7b5b5}, /* U+7D75 */ + {0xb3a9, 0xe88aa5}, /* U+82A5 */ + {0xb3aa, 0xe89fb9}, /* U+87F9 */ + {0xb3ab, 0xe9968b}, /* U+958B */ + {0xb3ac, 0xe99a8e}, /* U+968E */ + {0xb3ad, 0xe8b29d}, /* U+8C9D */ + {0xb3ae, 0xe587b1}, /* U+51F1 */ + {0xb3af, 0xe58abe}, /* U+52BE */ + {0xb3b0, 0xe5a496}, /* U+5916 */ + {0xb3b1, 0xe592b3}, /* U+54B3 */ + {0xb3b2, 0xe5aeb3}, /* U+5BB3 */ + {0xb3b3, 0xe5b496}, /* U+5D16 */ + {0xb3b4, 0xe685a8}, /* U+6168 */ + {0xb3b5, 0xe6a682}, /* U+6982 */ + {0xb3b6, 0xe6b6af}, /* U+6DAF */ + {0xb3b7, 0xe7a28d}, /* U+788D */ + {0xb3b8, 0xe8938b}, /* U+84CB */ + {0xb3b9, 0xe8a197}, /* U+8857 */ + {0xb3ba, 0xe8a9b2}, /* U+8A72 */ + {0xb3bb, 0xe98ea7}, /* U+93A7 */ + {0xb3bc, 0xe9aab8}, /* U+9AB8 */ + {0xb3bd, 0xe6b5ac}, /* U+6D6C */ + {0xb3be, 0xe9a6a8}, /* U+99A8 */ + {0xb3bf, 0xe89b99}, /* U+86D9 */ + {0xb3c0, 0xe59ea3}, /* U+57A3 */ + {0xb3c1, 0xe69fbf}, /* U+67FF */ + {0xb3c2, 0xe89b8e}, /* U+86CE */ + {0xb3c3, 0xe9888e}, /* U+920E */ + {0xb3c4, 0xe58a83}, /* U+5283 */ + {0xb3c5, 0xe59a87}, /* U+5687 */ + {0xb3c6, 0xe59084}, /* U+5404 */ + {0xb3c7, 0xe5bb93}, /* U+5ED3 */ + {0xb3c8, 0xe68ba1}, /* U+62E1 */ + {0xb3c9, 0xe692b9}, /* U+64B9 */ + {0xb3ca, 0xe6a0bc}, /* U+683C */ + {0xb3cb, 0xe6a0b8}, /* U+6838 */ + {0xb3cc, 0xe6aebb}, /* U+6BBB */ + {0xb3cd, 0xe78db2}, /* U+7372 */ + {0xb3ce, 0xe7a2ba}, /* U+78BA */ + {0xb3cf, 0xe7a9ab}, /* U+7A6B */ + {0xb3d0, 0xe8a69a}, /* U+899A */ + {0xb3d1, 0xe8a792}, /* U+89D2 */ + {0xb3d2, 0xe8b5ab}, /* U+8D6B */ + {0xb3d3, 0xe8bc83}, /* U+8F03 */ + {0xb3d4, 0xe983ad}, /* U+90ED */ + {0xb3d5, 0xe996a3}, /* U+95A3 */ + {0xb3d6, 0xe99a94}, /* U+9694 */ + {0xb3d7, 0xe99da9}, /* U+9769 */ + {0xb3d8, 0xe5ada6}, /* U+5B66 */ + {0xb3d9, 0xe5b2b3}, /* U+5CB3 */ + {0xb3da, 0xe6a5bd}, /* U+697D */ + {0xb3db, 0xe9a18d}, /* U+984D */ + {0xb3dc, 0xe9a18e}, /* U+984E */ + {0xb3dd, 0xe68e9b}, /* U+639B */ + {0xb3de, 0xe7aca0}, /* U+7B20 */ + {0xb3df, 0xe6a8ab}, /* U+6A2B */ + {0xb3e0, 0xe6a9bf}, /* U+6A7F */ + {0xb3e1, 0xe6a2b6}, /* U+68B6 */ + {0xb3e2, 0xe9b08d}, /* U+9C0D */ + {0xb3e3, 0xe6bd9f}, /* U+6F5F */ + {0xb3e4, 0xe589b2}, /* U+5272 */ + {0xb3e5, 0xe5969d}, /* U+559D */ + {0xb3e6, 0xe681b0}, /* U+6070 */ + {0xb3e7, 0xe68bac}, /* U+62EC */ + {0xb3e8, 0xe6b4bb}, /* U+6D3B */ + {0xb3e9, 0xe6b887}, /* U+6E07 */ + {0xb3ea, 0xe6bb91}, /* U+6ED1 */ + {0xb3eb, 0xe8919b}, /* U+845B */ + {0xb3ec, 0xe8a490}, /* U+8910 */ + {0xb3ed, 0xe8bd84}, /* U+8F44 */ + {0xb3ee, 0xe4b894}, /* U+4E14 */ + {0xb3ef, 0xe9b0b9}, /* U+9C39 */ + {0xb3f0, 0xe58fb6}, /* U+53F6 */ + {0xb3f1, 0xe6a49b}, /* U+691B */ + {0xb3f2, 0xe6a8ba}, /* U+6A3A */ + {0xb3f3, 0xe99e84}, /* U+9784 */ + {0xb3f4, 0xe6a0aa}, /* U+682A */ + {0xb3f5, 0xe5859c}, /* U+515C */ + {0xb3f6, 0xe7ab83}, /* U+7AC3 */ + {0xb3f7, 0xe892b2}, /* U+84B2 */ + {0xb3f8, 0xe9879c}, /* U+91DC */ + {0xb3f9, 0xe98e8c}, /* U+938C */ + {0xb3fa, 0xe5999b}, /* U+565B */ + {0xb3fb, 0xe9b4a8}, /* U+9D28 */ + {0xb3fc, 0xe6a0a2}, /* U+6822 */ + {0xb3fd, 0xe88c85}, /* U+8305 */ + {0xb3fe, 0xe890b1}, /* U+8431 */ + {0xb4a1, 0xe7b2a5}, /* U+7CA5 */ + {0xb4a2, 0xe58888}, /* U+5208 */ + {0xb4a3, 0xe88b85}, /* U+82C5 */ + {0xb4a4, 0xe793a6}, /* U+74E6 */ + {0xb4a5, 0xe4b9be}, /* U+4E7E */ + {0xb4a6, 0xe4be83}, /* U+4F83 */ + {0xb4a7, 0xe586a0}, /* U+51A0 */ + {0xb4a8, 0xe5af92}, /* U+5BD2 */ + {0xb4a9, 0xe5888a}, /* U+520A */ + {0xb4aa, 0xe58b98}, /* U+52D8 */ + {0xb4ab, 0xe58ba7}, /* U+52E7 */ + {0xb4ac, 0xe5b7bb}, /* U+5DFB */ + {0xb4ad, 0xe5969a}, /* U+559A */ + {0xb4ae, 0xe5a0aa}, /* U+582A */ + {0xb4af, 0xe5a7a6}, /* U+59E6 */ + {0xb4b0, 0xe5ae8c}, /* U+5B8C */ + {0xb4b1, 0xe5ae98}, /* U+5B98 */ + {0xb4b2, 0xe5af9b}, /* U+5BDB */ + {0xb4b3, 0xe5b9b2}, /* U+5E72 */ + {0xb4b4, 0xe5b9b9}, /* U+5E79 */ + {0xb4b5, 0xe682a3}, /* U+60A3 */ + {0xb4b6, 0xe6849f}, /* U+611F */ + {0xb4b7, 0xe685a3}, /* U+6163 */ + {0xb4b8, 0xe686be}, /* U+61BE */ + {0xb4b9, 0xe68f9b}, /* U+63DB */ + {0xb4ba, 0xe695a2}, /* U+6562 */ + {0xb4bb, 0xe69f91}, /* U+67D1 */ + {0xb4bc, 0xe6a193}, /* U+6853 */ + {0xb4bd, 0xe6a3ba}, /* U+68FA */ + {0xb4be, 0xe6acbe}, /* U+6B3E */ + {0xb4bf, 0xe6ad93}, /* U+6B53 */ + {0xb4c0, 0xe6b197}, /* U+6C57 */ + {0xb4c1, 0xe6bca2}, /* U+6F22 */ + {0xb4c2, 0xe6be97}, /* U+6F97 */ + {0xb4c3, 0xe6bd85}, /* U+6F45 */ + {0xb4c4, 0xe792b0}, /* U+74B0 */ + {0xb4c5, 0xe79498}, /* U+7518 */ + {0xb4c6, 0xe79ba3}, /* U+76E3 */ + {0xb4c7, 0xe79c8b}, /* U+770B */ + {0xb4c8, 0xe7abbf}, /* U+7AFF */ + {0xb4c9, 0xe7aea1}, /* U+7BA1 */ + {0xb4ca, 0xe7b0a1}, /* U+7C21 */ + {0xb4cb, 0xe7b7a9}, /* U+7DE9 */ + {0xb4cc, 0xe7bcb6}, /* U+7F36 */ + {0xb4cd, 0xe7bfb0}, /* U+7FF0 */ + {0xb4ce, 0xe8829d}, /* U+809D */ + {0xb4cf, 0xe889a6}, /* U+8266 */ + {0xb4d0, 0xe88e9e}, /* U+839E */ + {0xb4d1, 0xe8a6b3}, /* U+89B3 */ + {0xb4d2, 0xe8ab8c}, /* U+8ACC */ + {0xb4d3, 0xe8b2ab}, /* U+8CAB */ + {0xb4d4, 0xe98284}, /* U+9084 */ + {0xb4d5, 0xe99191}, /* U+9451 */ + {0xb4d6, 0xe99693}, /* U+9593 */ + {0xb4d7, 0xe99691}, /* U+9591 */ + {0xb4d8, 0xe996a2}, /* U+95A2 */ + {0xb4d9, 0xe999a5}, /* U+9665 */ + {0xb4da, 0xe99f93}, /* U+97D3 */ + {0xb4db, 0xe9a4a8}, /* U+9928 */ + {0xb4dc, 0xe88898}, /* U+8218 */ + {0xb4dd, 0xe4b8b8}, /* U+4E38 */ + {0xb4de, 0xe590ab}, /* U+542B */ + {0xb4df, 0xe5b2b8}, /* U+5CB8 */ + {0xb4e0, 0xe5b78c}, /* U+5DCC */ + {0xb4e1, 0xe78ea9}, /* U+73A9 */ + {0xb4e2, 0xe7998c}, /* U+764C */ + {0xb4e3, 0xe79cbc}, /* U+773C */ + {0xb4e4, 0xe5b2a9}, /* U+5CA9 */ + {0xb4e5, 0xe7bfab}, /* U+7FEB */ + {0xb4e6, 0xe8b48b}, /* U+8D0B */ + {0xb4e7, 0xe99b81}, /* U+96C1 */ + {0xb4e8, 0xe9a091}, /* U+9811 */ + {0xb4e9, 0xe9a194}, /* U+9854 */ + {0xb4ea, 0xe9a198}, /* U+9858 */ + {0xb4eb, 0xe4bc81}, /* U+4F01 */ + {0xb4ec, 0xe4bc8e}, /* U+4F0E */ + {0xb4ed, 0xe58db1}, /* U+5371 */ + {0xb4ee, 0xe5969c}, /* U+559C */ + {0xb4ef, 0xe599a8}, /* U+5668 */ + {0xb4f0, 0xe59fba}, /* U+57FA */ + {0xb4f1, 0xe5a587}, /* U+5947 */ + {0xb4f2, 0xe5ac89}, /* U+5B09 */ + {0xb4f3, 0xe5af84}, /* U+5BC4 */ + {0xb4f4, 0xe5b290}, /* U+5C90 */ + {0xb4f5, 0xe5b88c}, /* U+5E0C */ + {0xb4f6, 0xe5b9be}, /* U+5E7E */ + {0xb4f7, 0xe5bf8c}, /* U+5FCC */ + {0xb4f8, 0xe68fae}, /* U+63EE */ + {0xb4f9, 0xe69cba}, /* U+673A */ + {0xb4fa, 0xe69797}, /* U+65D7 */ + {0xb4fb, 0xe697a2}, /* U+65E2 */ + {0xb4fc, 0xe69c9f}, /* U+671F */ + {0xb4fd, 0xe6a38b}, /* U+68CB */ + {0xb4fe, 0xe6a384}, /* U+68C4 */ + {0xb5a1, 0xe6a99f}, /* U+6A5F */ + {0xb5a2, 0xe5b8b0}, /* U+5E30 */ + {0xb5a3, 0xe6af85}, /* U+6BC5 */ + {0xb5a4, 0xe6b097}, /* U+6C17 */ + {0xb5a5, 0xe6b1bd}, /* U+6C7D */ + {0xb5a6, 0xe795bf}, /* U+757F */ + {0xb5a7, 0xe7a588}, /* U+7948 */ + {0xb5a8, 0xe5ada3}, /* U+5B63 */ + {0xb5a9, 0xe7a880}, /* U+7A00 */ + {0xb5aa, 0xe7b480}, /* U+7D00 */ + {0xb5ab, 0xe5bebd}, /* U+5FBD */ + {0xb5ac, 0xe8a68f}, /* U+898F */ + {0xb5ad, 0xe8a898}, /* U+8A18 */ + {0xb5ae, 0xe8b2b4}, /* U+8CB4 */ + {0xb5af, 0xe8b5b7}, /* U+8D77 */ + {0xb5b0, 0xe8bb8c}, /* U+8ECC */ + {0xb5b1, 0xe8bc9d}, /* U+8F1D */ + {0xb5b2, 0xe9a3a2}, /* U+98E2 */ + {0xb5b3, 0xe9a88e}, /* U+9A0E */ + {0xb5b4, 0xe9acbc}, /* U+9B3C */ + {0xb5b5, 0xe4ba80}, /* U+4E80 */ + {0xb5b6, 0xe581bd}, /* U+507D */ + {0xb5b7, 0xe58480}, /* U+5100 */ + {0xb5b8, 0xe5a693}, /* U+5993 */ + {0xb5b9, 0xe5ae9c}, /* U+5B9C */ + {0xb5ba, 0xe688af}, /* U+622F */ + {0xb5bb, 0xe68a80}, /* U+6280 */ + {0xb5bc, 0xe693ac}, /* U+64EC */ + {0xb5bd, 0xe6acba}, /* U+6B3A */ + {0xb5be, 0xe78aa0}, /* U+72A0 */ + {0xb5bf, 0xe79691}, /* U+7591 */ + {0xb5c0, 0xe7a587}, /* U+7947 */ + {0xb5c1, 0xe7bea9}, /* U+7FA9 */ + {0xb5c2, 0xe89fbb}, /* U+87FB */ + {0xb5c3, 0xe8aabc}, /* U+8ABC */ + {0xb5c4, 0xe8adb0}, /* U+8B70 */ + {0xb5c5, 0xe68eac}, /* U+63AC */ + {0xb5c6, 0xe88f8a}, /* U+83CA */ + {0xb5c7, 0xe99ea0}, /* U+97A0 */ + {0xb5c8, 0xe59089}, /* U+5409 */ + {0xb5c9, 0xe59083}, /* U+5403 */ + {0xb5ca, 0xe596ab}, /* U+55AB */ + {0xb5cb, 0xe6a194}, /* U+6854 */ + {0xb5cc, 0xe6a998}, /* U+6A58 */ + {0xb5cd, 0xe8a9b0}, /* U+8A70 */ + {0xb5ce, 0xe7a0a7}, /* U+7827 */ + {0xb5cf, 0xe69db5}, /* U+6775 */ + {0xb5d0, 0xe9bb8d}, /* U+9ECD */ + {0xb5d1, 0xe58db4}, /* U+5374 */ + {0xb5d2, 0xe5aea2}, /* U+5BA2 */ + {0xb5d3, 0xe8849a}, /* U+811A */ + {0xb5d4, 0xe89990}, /* U+8650 */ + {0xb5d5, 0xe98086}, /* U+9006 */ + {0xb5d6, 0xe4b898}, /* U+4E18 */ + {0xb5d7, 0xe4b985}, /* U+4E45 */ + {0xb5d8, 0xe4bb87}, /* U+4EC7 */ + {0xb5d9, 0xe4bc91}, /* U+4F11 */ + {0xb5da, 0xe58f8a}, /* U+53CA */ + {0xb5db, 0xe590b8}, /* U+5438 */ + {0xb5dc, 0xe5aeae}, /* U+5BAE */ + {0xb5dd, 0xe5bc93}, /* U+5F13 */ + {0xb5de, 0xe680a5}, /* U+6025 */ + {0xb5df, 0xe69591}, /* U+6551 */ + {0xb5e0, 0xe69cbd}, /* U+673D */ + {0xb5e1, 0xe6b182}, /* U+6C42 */ + {0xb5e2, 0xe6b1b2}, /* U+6C72 */ + {0xb5e3, 0xe6b3a3}, /* U+6CE3 */ + {0xb5e4, 0xe781b8}, /* U+7078 */ + {0xb5e5, 0xe79083}, /* U+7403 */ + {0xb5e6, 0xe7a9b6}, /* U+7A76 */ + {0xb5e7, 0xe7aaae}, /* U+7AAE */ + {0xb5e8, 0xe7ac88}, /* U+7B08 */ + {0xb5e9, 0xe7b49a}, /* U+7D1A */ + {0xb5ea, 0xe7b3be}, /* U+7CFE */ + {0xb5eb, 0xe7b5a6}, /* U+7D66 */ + {0xb5ec, 0xe697a7}, /* U+65E7 */ + {0xb5ed, 0xe7899b}, /* U+725B */ + {0xb5ee, 0xe58ebb}, /* U+53BB */ + {0xb5ef, 0xe5b185}, /* U+5C45 */ + {0xb5f0, 0xe5b7a8}, /* U+5DE8 */ + {0xb5f1, 0xe68b92}, /* U+62D2 */ + {0xb5f2, 0xe68ba0}, /* U+62E0 */ + {0xb5f3, 0xe68c99}, /* U+6319 */ + {0xb5f4, 0xe6b8a0}, /* U+6E20 */ + {0xb5f5, 0xe8999a}, /* U+865A */ + {0xb5f6, 0xe8a8b1}, /* U+8A31 */ + {0xb5f7, 0xe8b79d}, /* U+8DDD */ + {0xb5f8, 0xe98bb8}, /* U+92F8 */ + {0xb5f9, 0xe6bc81}, /* U+6F01 */ + {0xb5fa, 0xe7a6a6}, /* U+79A6 */ + {0xb5fb, 0xe9ad9a}, /* U+9B5A */ + {0xb5fc, 0xe4baa8}, /* U+4EA8 */ + {0xb5fd, 0xe4baab}, /* U+4EAB */ + {0xb5fe, 0xe4baac}, /* U+4EAC */ + {0xb6a1, 0xe4be9b}, /* U+4F9B */ + {0xb6a2, 0xe4bea0}, /* U+4FA0 */ + {0xb6a3, 0xe58391}, /* U+50D1 */ + {0xb6a4, 0xe58587}, /* U+5147 */ + {0xb6a5, 0xe7abb6}, /* U+7AF6 */ + {0xb6a6, 0xe585b1}, /* U+5171 */ + {0xb6a7, 0xe587b6}, /* U+51F6 */ + {0xb6a8, 0xe58d94}, /* U+5354 */ + {0xb6a9, 0xe58ca1}, /* U+5321 */ + {0xb6aa, 0xe58dbf}, /* U+537F */ + {0xb6ab, 0xe58fab}, /* U+53EB */ + {0xb6ac, 0xe596ac}, /* U+55AC */ + {0xb6ad, 0xe5a283}, /* U+5883 */ + {0xb6ae, 0xe5b3a1}, /* U+5CE1 */ + {0xb6af, 0xe5bcb7}, /* U+5F37 */ + {0xb6b0, 0xe5bd8a}, /* U+5F4A */ + {0xb6b1, 0xe680af}, /* U+602F */ + {0xb6b2, 0xe68190}, /* U+6050 */ + {0xb6b3, 0xe681ad}, /* U+606D */ + {0xb6b4, 0xe68c9f}, /* U+631F */ + {0xb6b5, 0xe69599}, /* U+6559 */ + {0xb6b6, 0xe6a98b}, /* U+6A4B */ + {0xb6b7, 0xe6b381}, /* U+6CC1 */ + {0xb6b8, 0xe78b82}, /* U+72C2 */ + {0xb6b9, 0xe78bad}, /* U+72ED */ + {0xb6ba, 0xe79faf}, /* U+77EF */ + {0xb6bb, 0xe883b8}, /* U+80F8 */ + {0xb6bc, 0xe88485}, /* U+8105 */ + {0xb6bd, 0xe88888}, /* U+8208 */ + {0xb6be, 0xe8958e}, /* U+854E */ + {0xb6bf, 0xe983b7}, /* U+90F7 */ + {0xb6c0, 0xe98fa1}, /* U+93E1 */ + {0xb6c1, 0xe99fbf}, /* U+97FF */ + {0xb6c2, 0xe9a597}, /* U+9957 */ + {0xb6c3, 0xe9a99a}, /* U+9A5A */ + {0xb6c4, 0xe4bbb0}, /* U+4EF0 */ + {0xb6c5, 0xe5879d}, /* U+51DD */ + {0xb6c6, 0xe5b0ad}, /* U+5C2D */ + {0xb6c7, 0xe69a81}, /* U+6681 */ + {0xb6c8, 0xe6a5ad}, /* U+696D */ + {0xb6c9, 0xe5b180}, /* U+5C40 */ + {0xb6ca, 0xe69bb2}, /* U+66F2 */ + {0xb6cb, 0xe6a5b5}, /* U+6975 */ + {0xb6cc, 0xe78e89}, /* U+7389 */ + {0xb6cd, 0xe6a190}, /* U+6850 */ + {0xb6ce, 0xe7b281}, /* U+7C81 */ + {0xb6cf, 0xe58385}, /* U+50C5 */ + {0xb6d0, 0xe58ba4}, /* U+52E4 */ + {0xb6d1, 0xe59d87}, /* U+5747 */ + {0xb6d2, 0xe5b7be}, /* U+5DFE */ + {0xb6d3, 0xe98ca6}, /* U+9326 */ + {0xb6d4, 0xe696a4}, /* U+65A4 */ + {0xb6d5, 0xe6aca3}, /* U+6B23 */ + {0xb6d6, 0xe6acbd}, /* U+6B3D */ + {0xb6d7, 0xe790b4}, /* U+7434 */ + {0xb6d8, 0xe7a681}, /* U+7981 */ + {0xb6d9, 0xe7a6bd}, /* U+79BD */ + {0xb6da, 0xe7ad8b}, /* U+7B4B */ + {0xb6db, 0xe7b78a}, /* U+7DCA */ + {0xb6dc, 0xe88ab9}, /* U+82B9 */ + {0xb6dd, 0xe88f8c}, /* U+83CC */ + {0xb6de, 0xe8a1bf}, /* U+887F */ + {0xb6df, 0xe8a59f}, /* U+895F */ + {0xb6e0, 0xe8acb9}, /* U+8B39 */ + {0xb6e1, 0xe8bf91}, /* U+8FD1 */ + {0xb6e2, 0xe98791}, /* U+91D1 */ + {0xb6e3, 0xe5909f}, /* U+541F */ + {0xb6e4, 0xe98a80}, /* U+9280 */ + {0xb6e5, 0xe4b99d}, /* U+4E5D */ + {0xb6e6, 0xe580b6}, /* U+5036 */ + {0xb6e7, 0xe58fa5}, /* U+53E5 */ + {0xb6e8, 0xe58cba}, /* U+533A */ + {0xb6e9, 0xe78b97}, /* U+72D7 */ + {0xb6ea, 0xe78e96}, /* U+7396 */ + {0xb6eb, 0xe79fa9}, /* U+77E9 */ + {0xb6ec, 0xe88ba6}, /* U+82E6 */ + {0xb6ed, 0xe8baaf}, /* U+8EAF */ + {0xb6ee, 0xe9a786}, /* U+99C6 */ + {0xb6ef, 0xe9a788}, /* U+99C8 */ + {0xb6f0, 0xe9a792}, /* U+99D2 */ + {0xb6f1, 0xe585b7}, /* U+5177 */ + {0xb6f2, 0xe6849a}, /* U+611A */ + {0xb6f3, 0xe8999e}, /* U+865E */ + {0xb6f4, 0xe596b0}, /* U+55B0 */ + {0xb6f5, 0xe7a9ba}, /* U+7A7A */ + {0xb6f6, 0xe581b6}, /* U+5076 */ + {0xb6f7, 0xe5af93}, /* U+5BD3 */ + {0xb6f8, 0xe98187}, /* U+9047 */ + {0xb6f9, 0xe99a85}, /* U+9685 */ + {0xb6fa, 0xe4b8b2}, /* U+4E32 */ + {0xb6fb, 0xe6ab9b}, /* U+6ADB */ + {0xb6fc, 0xe987a7}, /* U+91E7 */ + {0xb6fd, 0xe5b191}, /* U+5C51 */ + {0xb6fe, 0xe5b188}, /* U+5C48 */ + {0xb7a1, 0xe68e98}, /* U+6398 */ + {0xb7a2, 0xe7aa9f}, /* U+7A9F */ + {0xb7a3, 0xe6b293}, /* U+6C93 */ + {0xb7a4, 0xe99db4}, /* U+9774 */ + {0xb7a5, 0xe8bda1}, /* U+8F61 */ + {0xb7a6, 0xe7aaaa}, /* U+7AAA */ + {0xb7a7, 0xe7868a}, /* U+718A */ + {0xb7a8, 0xe99a88}, /* U+9688 */ + {0xb7a9, 0xe7b282}, /* U+7C82 */ + {0xb7aa, 0xe6a097}, /* U+6817 */ + {0xb7ab, 0xe7b9b0}, /* U+7E70 */ + {0xb7ac, 0xe6a191}, /* U+6851 */ + {0xb7ad, 0xe98dac}, /* U+936C */ + {0xb7ae, 0xe58bb2}, /* U+52F2 */ + {0xb7af, 0xe5909b}, /* U+541B */ + {0xb7b0, 0xe896ab}, /* U+85AB */ + {0xb7b1, 0xe8a893}, /* U+8A13 */ + {0xb7b2, 0xe7bea4}, /* U+7FA4 */ + {0xb7b3, 0xe8bb8d}, /* U+8ECD */ + {0xb7b4, 0xe983a1}, /* U+90E1 */ + {0xb7b5, 0xe58da6}, /* U+5366 */ + {0xb7b6, 0xe8a288}, /* U+8888 */ + {0xb7b7, 0xe7a581}, /* U+7941 */ + {0xb7b8, 0xe4bf82}, /* U+4FC2 */ + {0xb7b9, 0xe582be}, /* U+50BE */ + {0xb7ba, 0xe58891}, /* U+5211 */ + {0xb7bb, 0xe58584}, /* U+5144 */ + {0xb7bc, 0xe59593}, /* U+5553 */ + {0xb7bd, 0xe59cad}, /* U+572D */ + {0xb7be, 0xe78faa}, /* U+73EA */ + {0xb7bf, 0xe59e8b}, /* U+578B */ + {0xb7c0, 0xe5a591}, /* U+5951 */ + {0xb7c1, 0xe5bda2}, /* U+5F62 */ + {0xb7c2, 0xe5be84}, /* U+5F84 */ + {0xb7c3, 0xe681b5}, /* U+6075 */ + {0xb7c4, 0xe685b6}, /* U+6176 */ + {0xb7c5, 0xe685a7}, /* U+6167 */ + {0xb7c6, 0xe686a9}, /* U+61A9 */ + {0xb7c7, 0xe68eb2}, /* U+63B2 */ + {0xb7c8, 0xe690ba}, /* U+643A */ + {0xb7c9, 0xe695ac}, /* U+656C */ + {0xb7ca, 0xe699af}, /* U+666F */ + {0xb7cb, 0xe6a182}, /* U+6842 */ + {0xb7cc, 0xe6b893}, /* U+6E13 */ + {0xb7cd, 0xe795a6}, /* U+7566 */ + {0xb7ce, 0xe7a8bd}, /* U+7A3D */ + {0xb7cf, 0xe7b3bb}, /* U+7CFB */ + {0xb7d0, 0xe7b58c}, /* U+7D4C */ + {0xb7d1, 0xe7b699}, /* U+7D99 */ + {0xb7d2, 0xe7b98b}, /* U+7E4B */ + {0xb7d3, 0xe7bdab}, /* U+7F6B */ + {0xb7d4, 0xe88c8e}, /* U+830E */ + {0xb7d5, 0xe88d8a}, /* U+834A */ + {0xb7d6, 0xe89b8d}, /* U+86CD */ + {0xb7d7, 0xe8a888}, /* U+8A08 */ + {0xb7d8, 0xe8a9a3}, /* U+8A63 */ + {0xb7d9, 0xe8ada6}, /* U+8B66 */ + {0xb7da, 0xe8bbbd}, /* U+8EFD */ + {0xb7db, 0xe9a09a}, /* U+981A */ + {0xb7dc, 0xe9b68f}, /* U+9D8F */ + {0xb7dd, 0xe88ab8}, /* U+82B8 */ + {0xb7de, 0xe8bf8e}, /* U+8FCE */ + {0xb7df, 0xe9afa8}, /* U+9BE8 */ + {0xb7e0, 0xe58a87}, /* U+5287 */ + {0xb7e1, 0xe6889f}, /* U+621F */ + {0xb7e2, 0xe69283}, /* U+6483 */ + {0xb7e3, 0xe6bf80}, /* U+6FC0 */ + {0xb7e4, 0xe99a99}, /* U+9699 */ + {0xb7e5, 0xe6a181}, /* U+6841 */ + {0xb7e6, 0xe58291}, /* U+5091 */ + {0xb7e7, 0xe6aca0}, /* U+6B20 */ + {0xb7e8, 0xe6b1ba}, /* U+6C7A */ + {0xb7e9, 0xe6bd94}, /* U+6F54 */ + {0xb7ea, 0xe7a9b4}, /* U+7A74 */ + {0xb7eb, 0xe7b590}, /* U+7D50 */ + {0xb7ec, 0xe8a180}, /* U+8840 */ + {0xb7ed, 0xe8a8a3}, /* U+8A23 */ + {0xb7ee, 0xe69c88}, /* U+6708 */ + {0xb7ef, 0xe4bbb6}, /* U+4EF6 */ + {0xb7f0, 0xe580b9}, /* U+5039 */ + {0xb7f1, 0xe580a6}, /* U+5026 */ + {0xb7f2, 0xe581a5}, /* U+5065 */ + {0xb7f3, 0xe585bc}, /* U+517C */ + {0xb7f4, 0xe588b8}, /* U+5238 */ + {0xb7f5, 0xe589a3}, /* U+5263 */ + {0xb7f6, 0xe596a7}, /* U+55A7 */ + {0xb7f7, 0xe59c8f}, /* U+570F */ + {0xb7f8, 0xe5a085}, /* U+5805 */ + {0xb7f9, 0xe5ab8c}, /* U+5ACC */ + {0xb7fa, 0xe5bbba}, /* U+5EFA */ + {0xb7fb, 0xe686b2}, /* U+61B2 */ + {0xb7fc, 0xe687b8}, /* U+61F8 */ + {0xb7fd, 0xe68bb3}, /* U+62F3 */ + {0xb7fe, 0xe68db2}, /* U+6372 */ + {0xb8a1, 0xe6a49c}, /* U+691C */ + {0xb8a2, 0xe6a8a9}, /* U+6A29 */ + {0xb8a3, 0xe789bd}, /* U+727D */ + {0xb8a4, 0xe78aac}, /* U+72AC */ + {0xb8a5, 0xe78cae}, /* U+732E */ + {0xb8a6, 0xe7a094}, /* U+7814 */ + {0xb8a7, 0xe7a1af}, /* U+786F */ + {0xb8a8, 0xe7b5b9}, /* U+7D79 */ + {0xb8a9, 0xe79c8c}, /* U+770C */ + {0xb8aa, 0xe882a9}, /* U+80A9 */ + {0xb8ab, 0xe8a68b}, /* U+898B */ + {0xb8ac, 0xe8ac99}, /* U+8B19 */ + {0xb8ad, 0xe8b3a2}, /* U+8CE2 */ + {0xb8ae, 0xe8bb92}, /* U+8ED2 */ + {0xb8af, 0xe981a3}, /* U+9063 */ + {0xb8b0, 0xe98db5}, /* U+9375 */ + {0xb8b1, 0xe999ba}, /* U+967A */ + {0xb8b2, 0xe9a195}, /* U+9855 */ + {0xb8b3, 0xe9a893}, /* U+9A13 */ + {0xb8b4, 0xe9b9b8}, /* U+9E78 */ + {0xb8b5, 0xe58583}, /* U+5143 */ + {0xb8b6, 0xe58e9f}, /* U+539F */ + {0xb8b7, 0xe58eb3}, /* U+53B3 */ + {0xb8b8, 0xe5b9bb}, /* U+5E7B */ + {0xb8b9, 0xe5bca6}, /* U+5F26 */ + {0xb8ba, 0xe6b89b}, /* U+6E1B */ + {0xb8bb, 0xe6ba90}, /* U+6E90 */ + {0xb8bc, 0xe78e84}, /* U+7384 */ + {0xb8bd, 0xe78fbe}, /* U+73FE */ + {0xb8be, 0xe7b583}, /* U+7D43 */ + {0xb8bf, 0xe888b7}, /* U+8237 */ + {0xb8c0, 0xe8a880}, /* U+8A00 */ + {0xb8c1, 0xe8abba}, /* U+8AFA */ + {0xb8c2, 0xe99990}, /* U+9650 */ + {0xb8c3, 0xe4b98e}, /* U+4E4E */ + {0xb8c4, 0xe5808b}, /* U+500B */ + {0xb8c5, 0xe58fa4}, /* U+53E4 */ + {0xb8c6, 0xe591bc}, /* U+547C */ + {0xb8c7, 0xe59bba}, /* U+56FA */ + {0xb8c8, 0xe5a791}, /* U+59D1 */ + {0xb8c9, 0xe5ada4}, /* U+5B64 */ + {0xb8ca, 0xe5b7b1}, /* U+5DF1 */ + {0xb8cb, 0xe5baab}, /* U+5EAB */ + {0xb8cc, 0xe5bca7}, /* U+5F27 */ + {0xb8cd, 0xe688b8}, /* U+6238 */ + {0xb8ce, 0xe69585}, /* U+6545 */ + {0xb8cf, 0xe69eaf}, /* U+67AF */ + {0xb8d0, 0xe6b996}, /* U+6E56 */ + {0xb8d1, 0xe78b90}, /* U+72D0 */ + {0xb8d2, 0xe7b38a}, /* U+7CCA */ + {0xb8d3, 0xe8a2b4}, /* U+88B4 */ + {0xb8d4, 0xe882a1}, /* U+80A1 */ + {0xb8d5, 0xe883a1}, /* U+80E1 */ + {0xb8d6, 0xe88fb0}, /* U+83F0 */ + {0xb8d7, 0xe8998e}, /* U+864E */ + {0xb8d8, 0xe8aa87}, /* U+8A87 */ + {0xb8d9, 0xe8b7a8}, /* U+8DE8 */ + {0xb8da, 0xe988b7}, /* U+9237 */ + {0xb8db, 0xe99b87}, /* U+96C7 */ + {0xb8dc, 0xe9a1a7}, /* U+9867 */ + {0xb8dd, 0xe9bc93}, /* U+9F13 */ + {0xb8de, 0xe4ba94}, /* U+4E94 */ + {0xb8df, 0xe4ba92}, /* U+4E92 */ + {0xb8e0, 0xe4bc8d}, /* U+4F0D */ + {0xb8e1, 0xe58d88}, /* U+5348 */ + {0xb8e2, 0xe59189}, /* U+5449 */ + {0xb8e3, 0xe590be}, /* U+543E */ + {0xb8e4, 0xe5a8af}, /* U+5A2F */ + {0xb8e5, 0xe5be8c}, /* U+5F8C */ + {0xb8e6, 0xe5bea1}, /* U+5FA1 */ + {0xb8e7, 0xe6829f}, /* U+609F */ + {0xb8e8, 0xe6a2a7}, /* U+68A7 */ + {0xb8e9, 0xe6aa8e}, /* U+6A8E */ + {0xb8ea, 0xe7919a}, /* U+745A */ + {0xb8eb, 0xe7a281}, /* U+7881 */ + {0xb8ec, 0xe8aa9e}, /* U+8A9E */ + {0xb8ed, 0xe8aaa4}, /* U+8AA4 */ + {0xb8ee, 0xe8adb7}, /* U+8B77 */ + {0xb8ef, 0xe98690}, /* U+9190 */ + {0xb8f0, 0xe4b99e}, /* U+4E5E */ + {0xb8f1, 0xe9af89}, /* U+9BC9 */ + {0xb8f2, 0xe4baa4}, /* U+4EA4 */ + {0xb8f3, 0xe4bdbc}, /* U+4F7C */ + {0xb8f4, 0xe4beaf}, /* U+4FAF */ + {0xb8f5, 0xe58099}, /* U+5019 */ + {0xb8f6, 0xe58096}, /* U+5016 */ + {0xb8f7, 0xe58589}, /* U+5149 */ + {0xb8f8, 0xe585ac}, /* U+516C */ + {0xb8f9, 0xe58a9f}, /* U+529F */ + {0xb8fa, 0xe58ab9}, /* U+52B9 */ + {0xb8fb, 0xe58bbe}, /* U+52FE */ + {0xb8fc, 0xe58e9a}, /* U+539A */ + {0xb8fd, 0xe58fa3}, /* U+53E3 */ + {0xb8fe, 0xe59091}, /* U+5411 */ + {0xb9a1, 0xe5908e}, /* U+540E */ + {0xb9a2, 0xe59689}, /* U+5589 */ + {0xb9a3, 0xe59d91}, /* U+5751 */ + {0xb9a4, 0xe59ea2}, /* U+57A2 */ + {0xb9a5, 0xe5a5bd}, /* U+597D */ + {0xb9a6, 0xe5ad94}, /* U+5B54 */ + {0xb9a7, 0xe5ad9d}, /* U+5B5D */ + {0xb9a8, 0xe5ae8f}, /* U+5B8F */ + {0xb9a9, 0xe5b7a5}, /* U+5DE5 */ + {0xb9aa, 0xe5b7a7}, /* U+5DE7 */ + {0xb9ab, 0xe5b7b7}, /* U+5DF7 */ + {0xb9ac, 0xe5b9b8}, /* U+5E78 */ + {0xb9ad, 0xe5ba83}, /* U+5E83 */ + {0xb9ae, 0xe5ba9a}, /* U+5E9A */ + {0xb9af, 0xe5bab7}, /* U+5EB7 */ + {0xb9b0, 0xe5bc98}, /* U+5F18 */ + {0xb9b1, 0xe68192}, /* U+6052 */ + {0xb9b2, 0xe6858c}, /* U+614C */ + {0xb9b3, 0xe68a97}, /* U+6297 */ + {0xb9b4, 0xe68b98}, /* U+62D8 */ + {0xb9b5, 0xe68ea7}, /* U+63A7 */ + {0xb9b6, 0xe694bb}, /* U+653B */ + {0xb9b7, 0xe69882}, /* U+6602 */ + {0xb9b8, 0xe69983}, /* U+6643 */ + {0xb9b9, 0xe69bb4}, /* U+66F4 */ + {0xb9ba, 0xe69dad}, /* U+676D */ + {0xb9bb, 0xe6a0a1}, /* U+6821 */ + {0xb9bc, 0xe6a297}, /* U+6897 */ + {0xb9bd, 0xe6a78b}, /* U+69CB */ + {0xb9be, 0xe6b19f}, /* U+6C5F */ + {0xb9bf, 0xe6b4aa}, /* U+6D2A */ + {0xb9c0, 0xe6b5a9}, /* U+6D69 */ + {0xb9c1, 0xe6b8af}, /* U+6E2F */ + {0xb9c2, 0xe6ba9d}, /* U+6E9D */ + {0xb9c3, 0xe794b2}, /* U+7532 */ + {0xb9c4, 0xe79a87}, /* U+7687 */ + {0xb9c5, 0xe7a1ac}, /* U+786C */ + {0xb9c6, 0xe7a8bf}, /* U+7A3F */ + {0xb9c7, 0xe7b3a0}, /* U+7CE0 */ + {0xb9c8, 0xe7b485}, /* U+7D05 */ + {0xb9c9, 0xe7b498}, /* U+7D18 */ + {0xb9ca, 0xe7b59e}, /* U+7D5E */ + {0xb9cb, 0xe7b6b1}, /* U+7DB1 */ + {0xb9cc, 0xe88095}, /* U+8015 */ + {0xb9cd, 0xe88083}, /* U+8003 */ + {0xb9ce, 0xe882af}, /* U+80AF */ + {0xb9cf, 0xe882b1}, /* U+80B1 */ + {0xb9d0, 0xe88594}, /* U+8154 */ + {0xb9d1, 0xe8868f}, /* U+818F */ + {0xb9d2, 0xe888aa}, /* U+822A */ + {0xb9d3, 0xe88d92}, /* U+8352 */ + {0xb9d4, 0xe8a18c}, /* U+884C */ + {0xb9d5, 0xe8a1a1}, /* U+8861 */ + {0xb9d6, 0xe8ac9b}, /* U+8B1B */ + {0xb9d7, 0xe8b2a2}, /* U+8CA2 */ + {0xb9d8, 0xe8b3bc}, /* U+8CFC */ + {0xb9d9, 0xe9838a}, /* U+90CA */ + {0xb9da, 0xe985b5}, /* U+9175 */ + {0xb9db, 0xe989b1}, /* U+9271 */ + {0xb9dc, 0xe7a0bf}, /* U+783F */ + {0xb9dd, 0xe98bbc}, /* U+92FC */ + {0xb9de, 0xe996a4}, /* U+95A4 */ + {0xb9df, 0xe9998d}, /* U+964D */ + {0xb9e0, 0xe9a085}, /* U+9805 */ + {0xb9e1, 0xe9a699}, /* U+9999 */ + {0xb9e2, 0xe9ab98}, /* U+9AD8 */ + {0xb9e3, 0xe9b4bb}, /* U+9D3B */ + {0xb9e4, 0xe5899b}, /* U+525B */ + {0xb9e5, 0xe58aab}, /* U+52AB */ + {0xb9e6, 0xe58fb7}, /* U+53F7 */ + {0xb9e7, 0xe59088}, /* U+5408 */ + {0xb9e8, 0xe5a395}, /* U+58D5 */ + {0xb9e9, 0xe68bb7}, /* U+62F7 */ + {0xb9ea, 0xe6bfa0}, /* U+6FE0 */ + {0xb9eb, 0xe8b1aa}, /* U+8C6A */ + {0xb9ec, 0xe8bd9f}, /* U+8F5F */ + {0xb9ed, 0xe9bab9}, /* U+9EB9 */ + {0xb9ee, 0xe5858b}, /* U+514B */ + {0xb9ef, 0xe588bb}, /* U+523B */ + {0xb9f0, 0xe5918a}, /* U+544A */ + {0xb9f1, 0xe59bbd}, /* U+56FD */ + {0xb9f2, 0xe7a980}, /* U+7A40 */ + {0xb9f3, 0xe985b7}, /* U+9177 */ + {0xb9f4, 0xe9b5a0}, /* U+9D60 */ + {0xb9f5, 0xe9bb92}, /* U+9ED2 */ + {0xb9f6, 0xe78d84}, /* U+7344 */ + {0xb9f7, 0xe6bc89}, /* U+6F09 */ + {0xb9f8, 0xe885b0}, /* U+8170 */ + {0xb9f9, 0xe79491}, /* U+7511 */ + {0xb9fa, 0xe5bfbd}, /* U+5FFD */ + {0xb9fb, 0xe6839a}, /* U+60DA */ + {0xb9fc, 0xe9aaa8}, /* U+9AA8 */ + {0xb9fd, 0xe78b9b}, /* U+72DB */ + {0xb9fe, 0xe8bebc}, /* U+8FBC */ + {0xbaa1, 0xe6ada4}, /* U+6B64 */ + {0xbaa2, 0xe9a083}, /* U+9803 */ + {0xbaa3, 0xe4bb8a}, /* U+4ECA */ + {0xbaa4, 0xe59bb0}, /* U+56F0 */ + {0xbaa5, 0xe59da4}, /* U+5764 */ + {0xbaa6, 0xe5a2be}, /* U+58BE */ + {0xbaa7, 0xe5a99a}, /* U+5A5A */ + {0xbaa8, 0xe681a8}, /* U+6068 */ + {0xbaa9, 0xe68787}, /* U+61C7 */ + {0xbaaa, 0xe6988f}, /* U+660F */ + {0xbaab, 0xe69886}, /* U+6606 */ + {0xbaac, 0xe6a0b9}, /* U+6839 */ + {0xbaad, 0xe6a2b1}, /* U+68B1 */ + {0xbaae, 0xe6b7b7}, /* U+6DF7 */ + {0xbaaf, 0xe79795}, /* U+75D5 */ + {0xbab0, 0xe7b4ba}, /* U+7D3A */ + {0xbab1, 0xe889ae}, /* U+826E */ + {0xbab2, 0xe9ad82}, /* U+9B42 */ + {0xbab3, 0xe4ba9b}, /* U+4E9B */ + {0xbab4, 0xe4bd90}, /* U+4F50 */ + {0xbab5, 0xe58f89}, /* U+53C9 */ + {0xbab6, 0xe59486}, /* U+5506 */ + {0xbab7, 0xe5b5af}, /* U+5D6F */ + {0xbab8, 0xe5b7a6}, /* U+5DE6 */ + {0xbab9, 0xe5b7ae}, /* U+5DEE */ + {0xbaba, 0xe69fbb}, /* U+67FB */ + {0xbabb, 0xe6b299}, /* U+6C99 */ + {0xbabc, 0xe791b3}, /* U+7473 */ + {0xbabd, 0xe7a082}, /* U+7802 */ + {0xbabe, 0xe8a990}, /* U+8A50 */ + {0xbabf, 0xe98e96}, /* U+9396 */ + {0xbac0, 0xe8a39f}, /* U+88DF */ + {0xbac1, 0xe59d90}, /* U+5750 */ + {0xbac2, 0xe5baa7}, /* U+5EA7 */ + {0xbac3, 0xe68cab}, /* U+632B */ + {0xbac4, 0xe582b5}, /* U+50B5 */ + {0xbac5, 0xe582ac}, /* U+50AC */ + {0xbac6, 0xe5868d}, /* U+518D */ + {0xbac7, 0xe69c80}, /* U+6700 */ + {0xbac8, 0xe59389}, /* U+54C9 */ + {0xbac9, 0xe5a19e}, /* U+585E */ + {0xbaca, 0xe5a6bb}, /* U+59BB */ + {0xbacb, 0xe5aeb0}, /* U+5BB0 */ + {0xbacc, 0xe5bda9}, /* U+5F69 */ + {0xbacd, 0xe6898d}, /* U+624D */ + {0xbace, 0xe68ea1}, /* U+63A1 */ + {0xbacf, 0xe6a0bd}, /* U+683D */ + {0xbad0, 0xe6adb3}, /* U+6B73 */ + {0xbad1, 0xe6b888}, /* U+6E08 */ + {0xbad2, 0xe781bd}, /* U+707D */ + {0xbad3, 0xe98787}, /* U+91C7 */ + {0xbad4, 0xe78a80}, /* U+7280 */ + {0xbad5, 0xe7a095}, /* U+7815 */ + {0xbad6, 0xe7a0a6}, /* U+7826 */ + {0xbad7, 0xe7a5ad}, /* U+796D */ + {0xbad8, 0xe6968e}, /* U+658E */ + {0xbad9, 0xe7b4b0}, /* U+7D30 */ + {0xbada, 0xe88f9c}, /* U+83DC */ + {0xbadb, 0xe8a381}, /* U+88C1 */ + {0xbadc, 0xe8bc89}, /* U+8F09 */ + {0xbadd, 0xe99a9b}, /* U+969B */ + {0xbade, 0xe589a4}, /* U+5264 */ + {0xbadf, 0xe59ca8}, /* U+5728 */ + {0xbae0, 0xe69d90}, /* U+6750 */ + {0xbae1, 0xe7bdaa}, /* U+7F6A */ + {0xbae2, 0xe8b2a1}, /* U+8CA1 */ + {0xbae3, 0xe586b4}, /* U+51B4 */ + {0xbae4, 0xe59d82}, /* U+5742 */ + {0xbae5, 0xe998aa}, /* U+962A */ + {0xbae6, 0xe5a0ba}, /* U+583A */ + {0xbae7, 0xe6a68a}, /* U+698A */ + {0xbae8, 0xe882b4}, /* U+80B4 */ + {0xbae9, 0xe592b2}, /* U+54B2 */ + {0xbaea, 0xe5b48e}, /* U+5D0E */ + {0xbaeb, 0xe59fbc}, /* U+57FC */ + {0xbaec, 0xe7a295}, /* U+7895 */ + {0xbaed, 0xe9b7ba}, /* U+9DFA */ + {0xbaee, 0xe4bd9c}, /* U+4F5C */ + {0xbaef, 0xe5898a}, /* U+524A */ + {0xbaf0, 0xe5928b}, /* U+548B */ + {0xbaf1, 0xe690be}, /* U+643E */ + {0xbaf2, 0xe698a8}, /* U+6628 */ + {0xbaf3, 0xe69c94}, /* U+6714 */ + {0xbaf4, 0xe69fb5}, /* U+67F5 */ + {0xbaf5, 0xe7aa84}, /* U+7A84 */ + {0xbaf6, 0xe7ad96}, /* U+7B56 */ + {0xbaf7, 0xe7b4a2}, /* U+7D22 */ + {0xbaf8, 0xe98caf}, /* U+932F */ + {0xbaf9, 0xe6a19c}, /* U+685C */ + {0xbafa, 0xe9aead}, /* U+9BAD */ + {0xbafb, 0xe7acb9}, /* U+7B39 */ + {0xbafc, 0xe58c99}, /* U+5319 */ + {0xbafd, 0xe5868a}, /* U+518A */ + {0xbafe, 0xe588b7}, /* U+5237 */ + {0xbba1, 0xe5af9f}, /* U+5BDF */ + {0xbba2, 0xe68bb6}, /* U+62F6 */ + {0xbba3, 0xe692ae}, /* U+64AE */ + {0xbba4, 0xe693a6}, /* U+64E6 */ + {0xbba5, 0xe69cad}, /* U+672D */ + {0xbba6, 0xe6aeba}, /* U+6BBA */ + {0xbba7, 0xe896a9}, /* U+85A9 */ + {0xbba8, 0xe99b91}, /* U+96D1 */ + {0xbba9, 0xe79a90}, /* U+7690 */ + {0xbbaa, 0xe9af96}, /* U+9BD6 */ + {0xbbab, 0xe68d8c}, /* U+634C */ + {0xbbac, 0xe98c86}, /* U+9306 */ + {0xbbad, 0xe9aeab}, /* U+9BAB */ + {0xbbae, 0xe79abf}, /* U+76BF */ + {0xbbaf, 0xe69992}, /* U+6652 */ + {0xbbb0, 0xe4b889}, /* U+4E09 */ + {0xbbb1, 0xe58298}, /* U+5098 */ + {0xbbb2, 0xe58f82}, /* U+53C2 */ + {0xbbb3, 0xe5b1b1}, /* U+5C71 */ + {0xbbb4, 0xe683a8}, /* U+60E8 */ + {0xbbb5, 0xe69292}, /* U+6492 */ + {0xbbb6, 0xe695a3}, /* U+6563 */ + {0xbbb7, 0xe6a19f}, /* U+685F */ + {0xbbb8, 0xe787a6}, /* U+71E6 */ + {0xbbb9, 0xe78f8a}, /* U+73CA */ + {0xbbba, 0xe794a3}, /* U+7523 */ + {0xbbbb, 0xe7ae97}, /* U+7B97 */ + {0xbbbc, 0xe7ba82}, /* U+7E82 */ + {0xbbbd, 0xe89a95}, /* U+8695 */ + {0xbbbe, 0xe8ae83}, /* U+8B83 */ + {0xbbbf, 0xe8b39b}, /* U+8CDB */ + {0xbbc0, 0xe985b8}, /* U+9178 */ + {0xbbc1, 0xe9a490}, /* U+9910 */ + {0xbbc2, 0xe696ac}, /* U+65AC */ + {0xbbc3, 0xe69aab}, /* U+66AB */ + {0xbbc4, 0xe6ae8b}, /* U+6B8B */ + {0xbbc5, 0xe4bb95}, /* U+4ED5 */ + {0xbbc6, 0xe4bb94}, /* U+4ED4 */ + {0xbbc7, 0xe4bcba}, /* U+4F3A */ + {0xbbc8, 0xe4bdbf}, /* U+4F7F */ + {0xbbc9, 0xe588ba}, /* U+523A */ + {0xbbca, 0xe58fb8}, /* U+53F8 */ + {0xbbcb, 0xe58fb2}, /* U+53F2 */ + {0xbbcc, 0xe597a3}, /* U+55E3 */ + {0xbbcd, 0xe59b9b}, /* U+56DB */ + {0xbbce, 0xe5a3ab}, /* U+58EB */ + {0xbbcf, 0xe5a78b}, /* U+59CB */ + {0xbbd0, 0xe5a789}, /* U+59C9 */ + {0xbbd1, 0xe5a7bf}, /* U+59FF */ + {0xbbd2, 0xe5ad90}, /* U+5B50 */ + {0xbbd3, 0xe5b18d}, /* U+5C4D */ + {0xbbd4, 0xe5b882}, /* U+5E02 */ + {0xbbd5, 0xe5b8ab}, /* U+5E2B */ + {0xbbd6, 0xe5bf97}, /* U+5FD7 */ + {0xbbd7, 0xe6809d}, /* U+601D */ + {0xbbd8, 0xe68c87}, /* U+6307 */ + {0xbbd9, 0xe694af}, /* U+652F */ + {0xbbda, 0xe5ad9c}, /* U+5B5C */ + {0xbbdb, 0xe696af}, /* U+65AF */ + {0xbbdc, 0xe696bd}, /* U+65BD */ + {0xbbdd, 0xe697a8}, /* U+65E8 */ + {0xbbde, 0xe69e9d}, /* U+679D */ + {0xbbdf, 0xe6ada2}, /* U+6B62 */ + {0xbbe0, 0xe6adbb}, /* U+6B7B */ + {0xbbe1, 0xe6b08f}, /* U+6C0F */ + {0xbbe2, 0xe78d85}, /* U+7345 */ + {0xbbe3, 0xe7a589}, /* U+7949 */ + {0xbbe4, 0xe7a781}, /* U+79C1 */ + {0xbbe5, 0xe7b3b8}, /* U+7CF8 */ + {0xbbe6, 0xe7b499}, /* U+7D19 */ + {0xbbe7, 0xe7b4ab}, /* U+7D2B */ + {0xbbe8, 0xe882a2}, /* U+80A2 */ + {0xbbe9, 0xe88482}, /* U+8102 */ + {0xbbea, 0xe887b3}, /* U+81F3 */ + {0xbbeb, 0xe8a696}, /* U+8996 */ + {0xbbec, 0xe8a99e}, /* U+8A5E */ + {0xbbed, 0xe8a9a9}, /* U+8A69 */ + {0xbbee, 0xe8a9a6}, /* U+8A66 */ + {0xbbef, 0xe8aa8c}, /* U+8A8C */ + {0xbbf0, 0xe8abae}, /* U+8AEE */ + {0xbbf1, 0xe8b387}, /* U+8CC7 */ + {0xbbf2, 0xe8b39c}, /* U+8CDC */ + {0xbbf3, 0xe99b8c}, /* U+96CC */ + {0xbbf4, 0xe9a3bc}, /* U+98FC */ + {0xbbf5, 0xe6adaf}, /* U+6B6F */ + {0xbbf6, 0xe4ba8b}, /* U+4E8B */ + {0xbbf7, 0xe4bcbc}, /* U+4F3C */ + {0xbbf8, 0xe4be8d}, /* U+4F8D */ + {0xbbf9, 0xe58590}, /* U+5150 */ + {0xbbfa, 0xe5ad97}, /* U+5B57 */ + {0xbbfb, 0xe5afba}, /* U+5BFA */ + {0xbbfc, 0xe68588}, /* U+6148 */ + {0xbbfd, 0xe68c81}, /* U+6301 */ + {0xbbfe, 0xe69982}, /* U+6642 */ + {0xbca1, 0xe6aca1}, /* U+6B21 */ + {0xbca2, 0xe6bb8b}, /* U+6ECB */ + {0xbca3, 0xe6b2bb}, /* U+6CBB */ + {0xbca4, 0xe788be}, /* U+723E */ + {0xbca5, 0xe792bd}, /* U+74BD */ + {0xbca6, 0xe79794}, /* U+75D4 */ + {0xbca7, 0xe7a381}, /* U+78C1 */ + {0xbca8, 0xe7a4ba}, /* U+793A */ + {0xbca9, 0xe8808c}, /* U+800C */ + {0xbcaa, 0xe880b3}, /* U+8033 */ + {0xbcab, 0xe887aa}, /* U+81EA */ + {0xbcac, 0xe89294}, /* U+8494 */ + {0xbcad, 0xe8be9e}, /* U+8F9E */ + {0xbcae, 0xe6b190}, /* U+6C50 */ + {0xbcaf, 0xe9b9bf}, /* U+9E7F */ + {0xbcb0, 0xe5bc8f}, /* U+5F0F */ + {0xbcb1, 0xe8ad98}, /* U+8B58 */ + {0xbcb2, 0xe9b4ab}, /* U+9D2B */ + {0xbcb3, 0xe7abba}, /* U+7AFA */ + {0xbcb4, 0xe8bbb8}, /* U+8EF8 */ + {0xbcb5, 0xe5ae8d}, /* U+5B8D */ + {0xbcb6, 0xe99bab}, /* U+96EB */ + {0xbcb7, 0xe4b883}, /* U+4E03 */ + {0xbcb8, 0xe58fb1}, /* U+53F1 */ + {0xbcb9, 0xe59fb7}, /* U+57F7 */ + {0xbcba, 0xe5a4b1}, /* U+5931 */ + {0xbcbb, 0xe5ab89}, /* U+5AC9 */ + {0xbcbc, 0xe5aea4}, /* U+5BA4 */ + {0xbcbd, 0xe68289}, /* U+6089 */ + {0xbcbe, 0xe6b9bf}, /* U+6E7F */ + {0xbcbf, 0xe6bc86}, /* U+6F06 */ + {0xbcc0, 0xe796be}, /* U+75BE */ + {0xbcc1, 0xe8b3aa}, /* U+8CEA */ + {0xbcc2, 0xe5ae9f}, /* U+5B9F */ + {0xbcc3, 0xe89480}, /* U+8500 */ + {0xbcc4, 0xe7afa0}, /* U+7BE0 */ + {0xbcc5, 0xe581b2}, /* U+5072 */ + {0xbcc6, 0xe69fb4}, /* U+67F4 */ + {0xbcc7, 0xe88a9d}, /* U+829D */ + {0xbcc8, 0xe5b1a1}, /* U+5C61 */ + {0xbcc9, 0xe8958a}, /* U+854A */ + {0xbcca, 0xe7b89e}, /* U+7E1E */ + {0xbccb, 0xe8888e}, /* U+820E */ + {0xbccc, 0xe58699}, /* U+5199 */ + {0xbccd, 0xe5b084}, /* U+5C04 */ + {0xbcce, 0xe68da8}, /* U+6368 */ + {0xbccf, 0xe8b5a6}, /* U+8D66 */ + {0xbcd0, 0xe6969c}, /* U+659C */ + {0xbcd1, 0xe785ae}, /* U+716E */ + {0xbcd2, 0xe7a4be}, /* U+793E */ + {0xbcd3, 0xe7b497}, /* U+7D17 */ + {0xbcd4, 0xe88085}, /* U+8005 */ + {0xbcd5, 0xe8ac9d}, /* U+8B1D */ + {0xbcd6, 0xe8bb8a}, /* U+8ECA */ + {0xbcd7, 0xe981ae}, /* U+906E */ + {0xbcd8, 0xe89b87}, /* U+86C7 */ + {0xbcd9, 0xe982aa}, /* U+90AA */ + {0xbcda, 0xe5809f}, /* U+501F */ + {0xbcdb, 0xe58bba}, /* U+52FA */ + {0xbcdc, 0xe5b0ba}, /* U+5C3A */ + {0xbcdd, 0xe69d93}, /* U+6753 */ + {0xbcde, 0xe781bc}, /* U+707C */ + {0xbcdf, 0xe788b5}, /* U+7235 */ + {0xbce0, 0xe9858c}, /* U+914C */ + {0xbce1, 0xe98788}, /* U+91C8 */ + {0xbce2, 0xe98cab}, /* U+932B */ + {0xbce3, 0xe88ba5}, /* U+82E5 */ + {0xbce4, 0xe5af82}, /* U+5BC2 */ + {0xbce5, 0xe5bcb1}, /* U+5F31 */ + {0xbce6, 0xe683b9}, /* U+60F9 */ + {0xbce7, 0xe4b8bb}, /* U+4E3B */ + {0xbce8, 0xe58f96}, /* U+53D6 */ + {0xbce9, 0xe5ae88}, /* U+5B88 */ + {0xbcea, 0xe6898b}, /* U+624B */ + {0xbceb, 0xe69cb1}, /* U+6731 */ + {0xbcec, 0xe6ae8a}, /* U+6B8A */ + {0xbced, 0xe78ba9}, /* U+72E9 */ + {0xbcee, 0xe78fa0}, /* U+73E0 */ + {0xbcef, 0xe7a8ae}, /* U+7A2E */ + {0xbcf0, 0xe885ab}, /* U+816B */ + {0xbcf1, 0xe8b6a3}, /* U+8DA3 */ + {0xbcf2, 0xe98592}, /* U+9152 */ + {0xbcf3, 0xe9a696}, /* U+9996 */ + {0xbcf4, 0xe58492}, /* U+5112 */ + {0xbcf5, 0xe58f97}, /* U+53D7 */ + {0xbcf6, 0xe591aa}, /* U+546A */ + {0xbcf7, 0xe5afbf}, /* U+5BFF */ + {0xbcf8, 0xe68e88}, /* U+6388 */ + {0xbcf9, 0xe6a8b9}, /* U+6A39 */ + {0xbcfa, 0xe7b6ac}, /* U+7DAC */ + {0xbcfb, 0xe99c80}, /* U+9700 */ + {0xbcfc, 0xe59b9a}, /* U+56DA */ + {0xbcfd, 0xe58f8e}, /* U+53CE */ + {0xbcfe, 0xe591a8}, /* U+5468 */ + {0xbda1, 0xe5ae97}, /* U+5B97 */ + {0xbda2, 0xe5b0b1}, /* U+5C31 */ + {0xbda3, 0xe5b79e}, /* U+5DDE */ + {0xbda4, 0xe4bfae}, /* U+4FEE */ + {0xbda5, 0xe68481}, /* U+6101 */ + {0xbda6, 0xe68bbe}, /* U+62FE */ + {0xbda7, 0xe6b4b2}, /* U+6D32 */ + {0xbda8, 0xe7a780}, /* U+79C0 */ + {0xbda9, 0xe7a78b}, /* U+79CB */ + {0xbdaa, 0xe7b582}, /* U+7D42 */ + {0xbdab, 0xe7b98d}, /* U+7E4D */ + {0xbdac, 0xe7bf92}, /* U+7FD2 */ + {0xbdad, 0xe887ad}, /* U+81ED */ + {0xbdae, 0xe8889f}, /* U+821F */ + {0xbdaf, 0xe89290}, /* U+8490 */ + {0xbdb0, 0xe8a186}, /* U+8846 */ + {0xbdb1, 0xe8a5b2}, /* U+8972 */ + {0xbdb2, 0xe8ae90}, /* U+8B90 */ + {0xbdb3, 0xe8b9b4}, /* U+8E74 */ + {0xbdb4, 0xe8bcaf}, /* U+8F2F */ + {0xbdb5, 0xe980b1}, /* U+9031 */ + {0xbdb6, 0xe9858b}, /* U+914B */ + {0xbdb7, 0xe985ac}, /* U+916C */ + {0xbdb8, 0xe99b86}, /* U+96C6 */ + {0xbdb9, 0xe9869c}, /* U+919C */ + {0xbdba, 0xe4bb80}, /* U+4EC0 */ + {0xbdbb, 0xe4bd8f}, /* U+4F4F */ + {0xbdbc, 0xe58585}, /* U+5145 */ + {0xbdbd, 0xe58d81}, /* U+5341 */ + {0xbdbe, 0xe5be93}, /* U+5F93 */ + {0xbdbf, 0xe6888e}, /* U+620E */ + {0xbdc0, 0xe69f94}, /* U+67D4 */ + {0xbdc1, 0xe6b181}, /* U+6C41 */ + {0xbdc2, 0xe6b88b}, /* U+6E0B */ + {0xbdc3, 0xe78da3}, /* U+7363 */ + {0xbdc4, 0xe7b8a6}, /* U+7E26 */ + {0xbdc5, 0xe9878d}, /* U+91CD */ + {0xbdc6, 0xe98a83}, /* U+9283 */ + {0xbdc7, 0xe58f94}, /* U+53D4 */ + {0xbdc8, 0xe5a499}, /* U+5919 */ + {0xbdc9, 0xe5aebf}, /* U+5BBF */ + {0xbdca, 0xe6b791}, /* U+6DD1 */ + {0xbdcb, 0xe7a59d}, /* U+795D */ + {0xbdcc, 0xe7b8ae}, /* U+7E2E */ + {0xbdcd, 0xe7b29b}, /* U+7C9B */ + {0xbdce, 0xe5a1be}, /* U+587E */ + {0xbdcf, 0xe7869f}, /* U+719F */ + {0xbdd0, 0xe587ba}, /* U+51FA */ + {0xbdd1, 0xe8a193}, /* U+8853 */ + {0xbdd2, 0xe8bfb0}, /* U+8FF0 */ + {0xbdd3, 0xe4bf8a}, /* U+4FCA */ + {0xbdd4, 0xe5b3bb}, /* U+5CFB */ + {0xbdd5, 0xe698a5}, /* U+6625 */ + {0xbdd6, 0xe79eac}, /* U+77AC */ + {0xbdd7, 0xe7aba3}, /* U+7AE3 */ + {0xbdd8, 0xe8889c}, /* U+821C */ + {0xbdd9, 0xe9a7bf}, /* U+99FF */ + {0xbdda, 0xe58786}, /* U+51C6 */ + {0xbddb, 0xe5beaa}, /* U+5FAA */ + {0xbddc, 0xe697ac}, /* U+65EC */ + {0xbddd, 0xe6a5af}, /* U+696F */ + {0xbdde, 0xe6ae89}, /* U+6B89 */ + {0xbddf, 0xe6b7b3}, /* U+6DF3 */ + {0xbde0, 0xe6ba96}, /* U+6E96 */ + {0xbde1, 0xe6bda4}, /* U+6F64 */ + {0xbde2, 0xe79bbe}, /* U+76FE */ + {0xbde3, 0xe7b494}, /* U+7D14 */ + {0xbde4, 0xe5b7a1}, /* U+5DE1 */ + {0xbde5, 0xe981b5}, /* U+9075 */ + {0xbde6, 0xe98687}, /* U+9187 */ + {0xbde7, 0xe9a086}, /* U+9806 */ + {0xbde8, 0xe587a6}, /* U+51E6 */ + {0xbde9, 0xe5889d}, /* U+521D */ + {0xbdea, 0xe68980}, /* U+6240 */ + {0xbdeb, 0xe69a91}, /* U+6691 */ + {0xbdec, 0xe69b99}, /* U+66D9 */ + {0xbded, 0xe6b89a}, /* U+6E1A */ + {0xbdee, 0xe5bab6}, /* U+5EB6 */ + {0xbdef, 0xe7b792}, /* U+7DD2 */ + {0xbdf0, 0xe7bdb2}, /* U+7F72 */ + {0xbdf1, 0xe69bb8}, /* U+66F8 */ + {0xbdf2, 0xe896af}, /* U+85AF */ + {0xbdf3, 0xe897b7}, /* U+85F7 */ + {0xbdf4, 0xe8abb8}, /* U+8AF8 */ + {0xbdf5, 0xe58aa9}, /* U+52A9 */ + {0xbdf6, 0xe58f99}, /* U+53D9 */ + {0xbdf7, 0xe5a5b3}, /* U+5973 */ + {0xbdf8, 0xe5ba8f}, /* U+5E8F */ + {0xbdf9, 0xe5be90}, /* U+5F90 */ + {0xbdfa, 0xe68195}, /* U+6055 */ + {0xbdfb, 0xe98ba4}, /* U+92E4 */ + {0xbdfc, 0xe999a4}, /* U+9664 */ + {0xbdfd, 0xe582b7}, /* U+50B7 */ + {0xbdfe, 0xe5849f}, /* U+511F */ + {0xbea1, 0xe58b9d}, /* U+52DD */ + {0xbea2, 0xe58ca0}, /* U+5320 */ + {0xbea3, 0xe58d87}, /* U+5347 */ + {0xbea4, 0xe58fac}, /* U+53EC */ + {0xbea5, 0xe593a8}, /* U+54E8 */ + {0xbea6, 0xe59586}, /* U+5546 */ + {0xbea7, 0xe594b1}, /* U+5531 */ + {0xbea8, 0xe59897}, /* U+5617 */ + {0xbea9, 0xe5a5a8}, /* U+5968 */ + {0xbeaa, 0xe5a6be}, /* U+59BE */ + {0xbeab, 0xe5a8bc}, /* U+5A3C */ + {0xbeac, 0xe5aeb5}, /* U+5BB5 */ + {0xbead, 0xe5b086}, /* U+5C06 */ + {0xbeae, 0xe5b08f}, /* U+5C0F */ + {0xbeaf, 0xe5b091}, /* U+5C11 */ + {0xbeb0, 0xe5b09a}, /* U+5C1A */ + {0xbeb1, 0xe5ba84}, /* U+5E84 */ + {0xbeb2, 0xe5ba8a}, /* U+5E8A */ + {0xbeb3, 0xe5bba0}, /* U+5EE0 */ + {0xbeb4, 0xe5bdb0}, /* U+5F70 */ + {0xbeb5, 0xe689bf}, /* U+627F */ + {0xbeb6, 0xe68a84}, /* U+6284 */ + {0xbeb7, 0xe68b9b}, /* U+62DB */ + {0xbeb8, 0xe68e8c}, /* U+638C */ + {0xbeb9, 0xe68db7}, /* U+6377 */ + {0xbeba, 0xe69887}, /* U+6607 */ + {0xbebb, 0xe6988c}, /* U+660C */ + {0xbebc, 0xe698ad}, /* U+662D */ + {0xbebd, 0xe699b6}, /* U+6676 */ + {0xbebe, 0xe69dbe}, /* U+677E */ + {0xbebf, 0xe6a2a2}, /* U+68A2 */ + {0xbec0, 0xe6a89f}, /* U+6A1F */ + {0xbec1, 0xe6a8b5}, /* U+6A35 */ + {0xbec2, 0xe6b2bc}, /* U+6CBC */ + {0xbec3, 0xe6b688}, /* U+6D88 */ + {0xbec4, 0xe6b889}, /* U+6E09 */ + {0xbec5, 0xe6b998}, /* U+6E58 */ + {0xbec6, 0xe784bc}, /* U+713C */ + {0xbec7, 0xe784a6}, /* U+7126 */ + {0xbec8, 0xe785a7}, /* U+7167 */ + {0xbec9, 0xe79787}, /* U+75C7 */ + {0xbeca, 0xe79c81}, /* U+7701 */ + {0xbecb, 0xe7a19d}, /* U+785D */ + {0xbecc, 0xe7a481}, /* U+7901 */ + {0xbecd, 0xe7a5a5}, /* U+7965 */ + {0xbece, 0xe7a7b0}, /* U+79F0 */ + {0xbecf, 0xe7aba0}, /* U+7AE0 */ + {0xbed0, 0xe7ac91}, /* U+7B11 */ + {0xbed1, 0xe7b2a7}, /* U+7CA7 */ + {0xbed2, 0xe7b4b9}, /* U+7D39 */ + {0xbed3, 0xe88296}, /* U+8096 */ + {0xbed4, 0xe88f96}, /* U+83D6 */ + {0xbed5, 0xe8928b}, /* U+848B */ + {0xbed6, 0xe89589}, /* U+8549 */ + {0xbed7, 0xe8a19d}, /* U+885D */ + {0xbed8, 0xe8a3b3}, /* U+88F3 */ + {0xbed9, 0xe8a89f}, /* U+8A1F */ + {0xbeda, 0xe8a8bc}, /* U+8A3C */ + {0xbedb, 0xe8a994}, /* U+8A54 */ + {0xbedc, 0xe8a9b3}, /* U+8A73 */ + {0xbedd, 0xe8b1a1}, /* U+8C61 */ + {0xbede, 0xe8b39e}, /* U+8CDE */ + {0xbedf, 0xe986a4}, /* U+91A4 */ + {0xbee0, 0xe989a6}, /* U+9266 */ + {0xbee1, 0xe98dbe}, /* U+937E */ + {0xbee2, 0xe99098}, /* U+9418 */ + {0xbee3, 0xe99a9c}, /* U+969C */ + {0xbee4, 0xe99e98}, /* U+9798 */ + {0xbee5, 0xe4b88a}, /* U+4E0A */ + {0xbee6, 0xe4b888}, /* U+4E08 */ + {0xbee7, 0xe4b89e}, /* U+4E1E */ + {0xbee8, 0xe4b997}, /* U+4E57 */ + {0xbee9, 0xe58697}, /* U+5197 */ + {0xbeea, 0xe589b0}, /* U+5270 */ + {0xbeeb, 0xe59f8e}, /* U+57CE */ + {0xbeec, 0xe5a0b4}, /* U+5834 */ + {0xbeed, 0xe5a38c}, /* U+58CC */ + {0xbeee, 0xe5aca2}, /* U+5B22 */ + {0xbeef, 0xe5b8b8}, /* U+5E38 */ + {0xbef0, 0xe68385}, /* U+60C5 */ + {0xbef1, 0xe693be}, /* U+64FE */ + {0xbef2, 0xe69da1}, /* U+6761 */ + {0xbef3, 0xe69d96}, /* U+6756 */ + {0xbef4, 0xe6b584}, /* U+6D44 */ + {0xbef5, 0xe78ab6}, /* U+72B6 */ + {0xbef6, 0xe795b3}, /* U+7573 */ + {0xbef7, 0xe7a9a3}, /* U+7A63 */ + {0xbef8, 0xe892b8}, /* U+84B8 */ + {0xbef9, 0xe8adb2}, /* U+8B72 */ + {0xbefa, 0xe986b8}, /* U+91B8 */ + {0xbefb, 0xe98ca0}, /* U+9320 */ + {0xbefc, 0xe598b1}, /* U+5631 */ + {0xbefd, 0xe59fb4}, /* U+57F4 */ + {0xbefe, 0xe9a3be}, /* U+98FE */ + {0xbfa1, 0xe68bad}, /* U+62ED */ + {0xbfa2, 0xe6a48d}, /* U+690D */ + {0xbfa3, 0xe6ae96}, /* U+6B96 */ + {0xbfa4, 0xe787ad}, /* U+71ED */ + {0xbfa5, 0xe7b994}, /* U+7E54 */ + {0xbfa6, 0xe881b7}, /* U+8077 */ + {0xbfa7, 0xe889b2}, /* U+8272 */ + {0xbfa8, 0xe8a7a6}, /* U+89E6 */ + {0xbfa9, 0xe9a39f}, /* U+98DF */ + {0xbfaa, 0xe89d95}, /* U+8755 */ + {0xbfab, 0xe8beb1}, /* U+8FB1 */ + {0xbfac, 0xe5b0bb}, /* U+5C3B */ + {0xbfad, 0xe4bcb8}, /* U+4F38 */ + {0xbfae, 0xe4bfa1}, /* U+4FE1 */ + {0xbfaf, 0xe4beb5}, /* U+4FB5 */ + {0xbfb0, 0xe59487}, /* U+5507 */ + {0xbfb1, 0xe5a8a0}, /* U+5A20 */ + {0xbfb2, 0xe5af9d}, /* U+5BDD */ + {0xbfb3, 0xe5afa9}, /* U+5BE9 */ + {0xbfb4, 0xe5bf83}, /* U+5FC3 */ + {0xbfb5, 0xe6858e}, /* U+614E */ + {0xbfb6, 0xe68caf}, /* U+632F */ + {0xbfb7, 0xe696b0}, /* U+65B0 */ + {0xbfb8, 0xe6998b}, /* U+664B */ + {0xbfb9, 0xe6a3ae}, /* U+68EE */ + {0xbfba, 0xe6a69b}, /* U+699B */ + {0xbfbb, 0xe6b5b8}, /* U+6D78 */ + {0xbfbc, 0xe6b7b1}, /* U+6DF1 */ + {0xbfbd, 0xe794b3}, /* U+7533 */ + {0xbfbe, 0xe796b9}, /* U+75B9 */ + {0xbfbf, 0xe79c9f}, /* U+771F */ + {0xbfc0, 0xe7a59e}, /* U+795E */ + {0xbfc1, 0xe7a7a6}, /* U+79E6 */ + {0xbfc2, 0xe7b4b3}, /* U+7D33 */ + {0xbfc3, 0xe887a3}, /* U+81E3 */ + {0xbfc4, 0xe88aaf}, /* U+82AF */ + {0xbfc5, 0xe896aa}, /* U+85AA */ + {0xbfc6, 0xe8a6aa}, /* U+89AA */ + {0xbfc7, 0xe8a8ba}, /* U+8A3A */ + {0xbfc8, 0xe8baab}, /* U+8EAB */ + {0xbfc9, 0xe8be9b}, /* U+8F9B */ + {0xbfca, 0xe980b2}, /* U+9032 */ + {0xbfcb, 0xe9879d}, /* U+91DD */ + {0xbfcc, 0xe99c87}, /* U+9707 */ + {0xbfcd, 0xe4baba}, /* U+4EBA */ + {0xbfce, 0xe4bb81}, /* U+4EC1 */ + {0xbfcf, 0xe58883}, /* U+5203 */ + {0xbfd0, 0xe5a1b5}, /* U+5875 */ + {0xbfd1, 0xe5a3ac}, /* U+58EC */ + {0xbfd2, 0xe5b08b}, /* U+5C0B */ + {0xbfd3, 0xe7949a}, /* U+751A */ + {0xbfd4, 0xe5b0bd}, /* U+5C3D */ + {0xbfd5, 0xe8858e}, /* U+814E */ + {0xbfd6, 0xe8a88a}, /* U+8A0A */ + {0xbfd7, 0xe8bf85}, /* U+8FC5 */ + {0xbfd8, 0xe999a3}, /* U+9663 */ + {0xbfd9, 0xe99dad}, /* U+976D */ + {0xbfda, 0xe7aca5}, /* U+7B25 */ + {0xbfdb, 0xe8ab8f}, /* U+8ACF */ + {0xbfdc, 0xe9a088}, /* U+9808 */ + {0xbfdd, 0xe985a2}, /* U+9162 */ + {0xbfde, 0xe59bb3}, /* U+56F3 */ + {0xbfdf, 0xe58ea8}, /* U+53A8 */ + {0xbfe0, 0xe98097}, /* U+9017 */ + {0xbfe1, 0xe590b9}, /* U+5439 */ + {0xbfe2, 0xe59e82}, /* U+5782 */ + {0xbfe3, 0xe5b8a5}, /* U+5E25 */ + {0xbfe4, 0xe68ea8}, /* U+63A8 */ + {0xbfe5, 0xe6b0b4}, /* U+6C34 */ + {0xbfe6, 0xe7828a}, /* U+708A */ + {0xbfe7, 0xe79da1}, /* U+7761 */ + {0xbfe8, 0xe7b28b}, /* U+7C8B */ + {0xbfe9, 0xe7bfa0}, /* U+7FE0 */ + {0xbfea, 0xe8a1b0}, /* U+8870 */ + {0xbfeb, 0xe98182}, /* U+9042 */ + {0xbfec, 0xe98594}, /* U+9154 */ + {0xbfed, 0xe98c90}, /* U+9310 */ + {0xbfee, 0xe98c98}, /* U+9318 */ + {0xbfef, 0xe99a8f}, /* U+968F */ + {0xbff0, 0xe7919e}, /* U+745E */ + {0xbff1, 0xe9ab84}, /* U+9AC4 */ + {0xbff2, 0xe5b487}, /* U+5D07 */ + {0xbff3, 0xe5b5a9}, /* U+5D69 */ + {0xbff4, 0xe695b0}, /* U+6570 */ + {0xbff5, 0xe69ea2}, /* U+67A2 */ + {0xbff6, 0xe8b6a8}, /* U+8DA8 */ + {0xbff7, 0xe99b9b}, /* U+96DB */ + {0xbff8, 0xe68dae}, /* U+636E */ + {0xbff9, 0xe69d89}, /* U+6749 */ + {0xbffa, 0xe6a499}, /* U+6919 */ + {0xbffb, 0xe88f85}, /* U+83C5 */ + {0xbffc, 0xe9a097}, /* U+9817 */ + {0xbffd, 0xe99b80}, /* U+96C0 */ + {0xbffe, 0xe8a3be}, /* U+88FE */ + {0xc0a1, 0xe6be84}, /* U+6F84 */ + {0xc0a2, 0xe691ba}, /* U+647A */ + {0xc0a3, 0xe5afb8}, /* U+5BF8 */ + {0xc0a4, 0xe4b896}, /* U+4E16 */ + {0xc0a5, 0xe780ac}, /* U+702C */ + {0xc0a6, 0xe7959d}, /* U+755D */ + {0xc0a7, 0xe698af}, /* U+662F */ + {0xc0a8, 0xe58784}, /* U+51C4 */ + {0xc0a9, 0xe588b6}, /* U+5236 */ + {0xc0aa, 0xe58ba2}, /* U+52E2 */ + {0xc0ab, 0xe5a793}, /* U+59D3 */ + {0xc0ac, 0xe5be81}, /* U+5F81 */ + {0xc0ad, 0xe680a7}, /* U+6027 */ + {0xc0ae, 0xe68890}, /* U+6210 */ + {0xc0af, 0xe694bf}, /* U+653F */ + {0xc0b0, 0xe695b4}, /* U+6574 */ + {0xc0b1, 0xe6989f}, /* U+661F */ + {0xc0b2, 0xe699b4}, /* U+6674 */ + {0xc0b3, 0xe6a3b2}, /* U+68F2 */ + {0xc0b4, 0xe6a096}, /* U+6816 */ + {0xc0b5, 0xe6ada3}, /* U+6B63 */ + {0xc0b6, 0xe6b885}, /* U+6E05 */ + {0xc0b7, 0xe789b2}, /* U+7272 */ + {0xc0b8, 0xe7949f}, /* U+751F */ + {0xc0b9, 0xe79b9b}, /* U+76DB */ + {0xc0ba, 0xe7b2be}, /* U+7CBE */ + {0xc0bb, 0xe88196}, /* U+8056 */ + {0xc0bc, 0xe5a3b0}, /* U+58F0 */ + {0xc0bd, 0xe8a3bd}, /* U+88FD */ + {0xc0be, 0xe8a5bf}, /* U+897F */ + {0xc0bf, 0xe8aaa0}, /* U+8AA0 */ + {0xc0c0, 0xe8aa93}, /* U+8A93 */ + {0xc0c1, 0xe8ab8b}, /* U+8ACB */ + {0xc0c2, 0xe9809d}, /* U+901D */ + {0xc0c3, 0xe98692}, /* U+9192 */ + {0xc0c4, 0xe99d92}, /* U+9752 */ + {0xc0c5, 0xe99d99}, /* U+9759 */ + {0xc0c6, 0xe69689}, /* U+6589 */ + {0xc0c7, 0xe7a88e}, /* U+7A0E */ + {0xc0c8, 0xe88486}, /* U+8106 */ + {0xc0c9, 0xe99abb}, /* U+96BB */ + {0xc0ca, 0xe5b8ad}, /* U+5E2D */ + {0xc0cb, 0xe6839c}, /* U+60DC */ + {0xc0cc, 0xe6889a}, /* U+621A */ + {0xc0cd, 0xe696a5}, /* U+65A5 */ + {0xc0ce, 0xe69894}, /* U+6614 */ + {0xc0cf, 0xe69e90}, /* U+6790 */ + {0xc0d0, 0xe79fb3}, /* U+77F3 */ + {0xc0d1, 0xe7a98d}, /* U+7A4D */ + {0xc0d2, 0xe7b18d}, /* U+7C4D */ + {0xc0d3, 0xe7b8be}, /* U+7E3E */ + {0xc0d4, 0xe8848a}, /* U+810A */ + {0xc0d5, 0xe8b2ac}, /* U+8CAC */ + {0xc0d6, 0xe8b5a4}, /* U+8D64 */ + {0xc0d7, 0xe8b7a1}, /* U+8DE1 */ + {0xc0d8, 0xe8b99f}, /* U+8E5F */ + {0xc0d9, 0xe7a2a9}, /* U+78A9 */ + {0xc0da, 0xe58887}, /* U+5207 */ + {0xc0db, 0xe68b99}, /* U+62D9 */ + {0xc0dc, 0xe68ea5}, /* U+63A5 */ + {0xc0dd, 0xe69182}, /* U+6442 */ + {0xc0de, 0xe68a98}, /* U+6298 */ + {0xc0df, 0xe8a8ad}, /* U+8A2D */ + {0xc0e0, 0xe7aa83}, /* U+7A83 */ + {0xc0e1, 0xe7af80}, /* U+7BC0 */ + {0xc0e2, 0xe8aaac}, /* U+8AAC */ + {0xc0e3, 0xe99baa}, /* U+96EA */ + {0xc0e4, 0xe7b5b6}, /* U+7D76 */ + {0xc0e5, 0xe8888c}, /* U+820C */ + {0xc0e6, 0xe89d89}, /* U+8749 */ + {0xc0e7, 0xe4bb99}, /* U+4ED9 */ + {0xc0e8, 0xe58588}, /* U+5148 */ + {0xc0e9, 0xe58d83}, /* U+5343 */ + {0xc0ea, 0xe58da0}, /* U+5360 */ + {0xc0eb, 0xe5aea3}, /* U+5BA3 */ + {0xc0ec, 0xe5b082}, /* U+5C02 */ + {0xc0ed, 0xe5b096}, /* U+5C16 */ + {0xc0ee, 0xe5b79d}, /* U+5DDD */ + {0xc0ef, 0xe688a6}, /* U+6226 */ + {0xc0f0, 0xe68987}, /* U+6247 */ + {0xc0f1, 0xe692b0}, /* U+64B0 */ + {0xc0f2, 0xe6a093}, /* U+6813 */ + {0xc0f3, 0xe6a0b4}, /* U+6834 */ + {0xc0f4, 0xe6b389}, /* U+6CC9 */ + {0xc0f5, 0xe6b585}, /* U+6D45 */ + {0xc0f6, 0xe6b497}, /* U+6D17 */ + {0xc0f7, 0xe69f93}, /* U+67D3 */ + {0xc0f8, 0xe6bd9c}, /* U+6F5C */ + {0xc0f9, 0xe7858e}, /* U+714E */ + {0xc0fa, 0xe785bd}, /* U+717D */ + {0xc0fb, 0xe6978b}, /* U+65CB */ + {0xc0fc, 0xe7a9bf}, /* U+7A7F */ + {0xc0fd, 0xe7aead}, /* U+7BAD */ + {0xc0fe, 0xe7b79a}, /* U+7DDA */ + {0xc1a1, 0xe7b98a}, /* U+7E4A */ + {0xc1a2, 0xe7bea8}, /* U+7FA8 */ + {0xc1a3, 0xe885ba}, /* U+817A */ + {0xc1a4, 0xe8889b}, /* U+821B */ + {0xc1a5, 0xe888b9}, /* U+8239 */ + {0xc1a6, 0xe896a6}, /* U+85A6 */ + {0xc1a7, 0xe8a9ae}, /* U+8A6E */ + {0xc1a8, 0xe8b38e}, /* U+8CCE */ + {0xc1a9, 0xe8b7b5}, /* U+8DF5 */ + {0xc1aa, 0xe981b8}, /* U+9078 */ + {0xc1ab, 0xe981b7}, /* U+9077 */ + {0xc1ac, 0xe98aad}, /* U+92AD */ + {0xc1ad, 0xe98a91}, /* U+9291 */ + {0xc1ae, 0xe99683}, /* U+9583 */ + {0xc1af, 0xe9aeae}, /* U+9BAE */ + {0xc1b0, 0xe5898d}, /* U+524D */ + {0xc1b1, 0xe59684}, /* U+5584 */ + {0xc1b2, 0xe6bcb8}, /* U+6F38 */ + {0xc1b3, 0xe784b6}, /* U+7136 */ + {0xc1b4, 0xe585a8}, /* U+5168 */ + {0xc1b5, 0xe7a685}, /* U+7985 */ + {0xc1b6, 0xe7b995}, /* U+7E55 */ + {0xc1b7, 0xe886b3}, /* U+81B3 */ + {0xc1b8, 0xe7b38e}, /* U+7CCE */ + {0xc1b9, 0xe5998c}, /* U+564C */ + {0xc1ba, 0xe5a191}, /* U+5851 */ + {0xc1bb, 0xe5b2a8}, /* U+5CA8 */ + {0xc1bc, 0xe68eaa}, /* U+63AA */ + {0xc1bd, 0xe69bbe}, /* U+66FE */ + {0xc1be, 0xe69bbd}, /* U+66FD */ + {0xc1bf, 0xe6a59a}, /* U+695A */ + {0xc1c0, 0xe78b99}, /* U+72D9 */ + {0xc1c1, 0xe7968f}, /* U+758F */ + {0xc1c2, 0xe7968e}, /* U+758E */ + {0xc1c3, 0xe7a48e}, /* U+790E */ + {0xc1c4, 0xe7a596}, /* U+7956 */ + {0xc1c5, 0xe7a79f}, /* U+79DF */ + {0xc1c6, 0xe7b297}, /* U+7C97 */ + {0xc1c7, 0xe7b4a0}, /* U+7D20 */ + {0xc1c8, 0xe7b584}, /* U+7D44 */ + {0xc1c9, 0xe89887}, /* U+8607 */ + {0xc1ca, 0xe8a8b4}, /* U+8A34 */ + {0xc1cb, 0xe998bb}, /* U+963B */ + {0xc1cc, 0xe981a1}, /* U+9061 */ + {0xc1cd, 0xe9bca0}, /* U+9F20 */ + {0xc1ce, 0xe583a7}, /* U+50E7 */ + {0xc1cf, 0xe589b5}, /* U+5275 */ + {0xc1d0, 0xe58f8c}, /* U+53CC */ + {0xc1d1, 0xe58fa2}, /* U+53E2 */ + {0xc1d2, 0xe58089}, /* U+5009 */ + {0xc1d3, 0xe596aa}, /* U+55AA */ + {0xc1d4, 0xe5a3ae}, /* U+58EE */ + {0xc1d5, 0xe5a58f}, /* U+594F */ + {0xc1d6, 0xe788bd}, /* U+723D */ + {0xc1d7, 0xe5ae8b}, /* U+5B8B */ + {0xc1d8, 0xe5b1a4}, /* U+5C64 */ + {0xc1d9, 0xe58c9d}, /* U+531D */ + {0xc1da, 0xe683a3}, /* U+60E3 */ + {0xc1db, 0xe683b3}, /* U+60F3 */ + {0xc1dc, 0xe68d9c}, /* U+635C */ + {0xc1dd, 0xe68e83}, /* U+6383 */ + {0xc1de, 0xe68cbf}, /* U+633F */ + {0xc1df, 0xe68ebb}, /* U+63BB */ + {0xc1e0, 0xe6938d}, /* U+64CD */ + {0xc1e1, 0xe697a9}, /* U+65E9 */ + {0xc1e2, 0xe69bb9}, /* U+66F9 */ + {0xc1e3, 0xe5b7a3}, /* U+5DE3 */ + {0xc1e4, 0xe6a78d}, /* U+69CD */ + {0xc1e5, 0xe6a7bd}, /* U+69FD */ + {0xc1e6, 0xe6bc95}, /* U+6F15 */ + {0xc1e7, 0xe787a5}, /* U+71E5 */ + {0xc1e8, 0xe4ba89}, /* U+4E89 */ + {0xc1e9, 0xe797a9}, /* U+75E9 */ + {0xc1ea, 0xe79bb8}, /* U+76F8 */ + {0xc1eb, 0xe7aa93}, /* U+7A93 */ + {0xc1ec, 0xe7b39f}, /* U+7CDF */ + {0xc1ed, 0xe7b78f}, /* U+7DCF */ + {0xc1ee, 0xe7b69c}, /* U+7D9C */ + {0xc1ef, 0xe881a1}, /* U+8061 */ + {0xc1f0, 0xe88d89}, /* U+8349 */ + {0xc1f1, 0xe88d98}, /* U+8358 */ + {0xc1f2, 0xe891ac}, /* U+846C */ + {0xc1f3, 0xe892bc}, /* U+84BC */ + {0xc1f4, 0xe897bb}, /* U+85FB */ + {0xc1f5, 0xe8a385}, /* U+88C5 */ + {0xc1f6, 0xe8b5b0}, /* U+8D70 */ + {0xc1f7, 0xe98081}, /* U+9001 */ + {0xc1f8, 0xe981ad}, /* U+906D */ + {0xc1f9, 0xe98e97}, /* U+9397 */ + {0xc1fa, 0xe99c9c}, /* U+971C */ + {0xc1fb, 0xe9a892}, /* U+9A12 */ + {0xc1fc, 0xe5838f}, /* U+50CF */ + {0xc1fd, 0xe5a297}, /* U+5897 */ + {0xc1fe, 0xe6868e}, /* U+618E */ + {0xc2a1, 0xe88793}, /* U+81D3 */ + {0xc2a2, 0xe894b5}, /* U+8535 */ + {0xc2a3, 0xe8b488}, /* U+8D08 */ + {0xc2a4, 0xe980a0}, /* U+9020 */ + {0xc2a5, 0xe4bf83}, /* U+4FC3 */ + {0xc2a6, 0xe581b4}, /* U+5074 */ + {0xc2a7, 0xe58987}, /* U+5247 */ + {0xc2a8, 0xe58db3}, /* U+5373 */ + {0xc2a9, 0xe681af}, /* U+606F */ + {0xc2aa, 0xe68d89}, /* U+6349 */ + {0xc2ab, 0xe69d9f}, /* U+675F */ + {0xc2ac, 0xe6b8ac}, /* U+6E2C */ + {0xc2ad, 0xe8b6b3}, /* U+8DB3 */ + {0xc2ae, 0xe9809f}, /* U+901F */ + {0xc2af, 0xe4bf97}, /* U+4FD7 */ + {0xc2b0, 0xe5b19e}, /* U+5C5E */ + {0xc2b1, 0xe8b38a}, /* U+8CCA */ + {0xc2b2, 0xe6978f}, /* U+65CF */ + {0xc2b3, 0xe7b69a}, /* U+7D9A */ + {0xc2b4, 0xe58d92}, /* U+5352 */ + {0xc2b5, 0xe8a296}, /* U+8896 */ + {0xc2b6, 0xe585b6}, /* U+5176 */ + {0xc2b7, 0xe68f83}, /* U+63C3 */ + {0xc2b8, 0xe5ad98}, /* U+5B58 */ + {0xc2b9, 0xe5adab}, /* U+5B6B */ + {0xc2ba, 0xe5b08a}, /* U+5C0A */ + {0xc2bb, 0xe6908d}, /* U+640D */ + {0xc2bc, 0xe69d91}, /* U+6751 */ + {0xc2bd, 0xe9819c}, /* U+905C */ + {0xc2be, 0xe4bb96}, /* U+4ED6 */ + {0xc2bf, 0xe5a49a}, /* U+591A */ + {0xc2c0, 0xe5a4aa}, /* U+592A */ + {0xc2c1, 0xe6b1b0}, /* U+6C70 */ + {0xc2c2, 0xe8a991}, /* U+8A51 */ + {0xc2c3, 0xe594be}, /* U+553E */ + {0xc2c4, 0xe5a095}, /* U+5815 */ + {0xc2c5, 0xe5a6a5}, /* U+59A5 */ + {0xc2c6, 0xe683b0}, /* U+60F0 */ + {0xc2c7, 0xe68993}, /* U+6253 */ + {0xc2c8, 0xe69f81}, /* U+67C1 */ + {0xc2c9, 0xe888b5}, /* U+8235 */ + {0xc2ca, 0xe6a595}, /* U+6955 */ + {0xc2cb, 0xe99980}, /* U+9640 */ + {0xc2cc, 0xe9a784}, /* U+99C4 */ + {0xc2cd, 0xe9a8a8}, /* U+9A28 */ + {0xc2ce, 0xe4bd93}, /* U+4F53 */ + {0xc2cf, 0xe5a086}, /* U+5806 */ + {0xc2d0, 0xe5afbe}, /* U+5BFE */ + {0xc2d1, 0xe88090}, /* U+8010 */ + {0xc2d2, 0xe5b2b1}, /* U+5CB1 */ + {0xc2d3, 0xe5b8af}, /* U+5E2F */ + {0xc2d4, 0xe5be85}, /* U+5F85 */ + {0xc2d5, 0xe680a0}, /* U+6020 */ + {0xc2d6, 0xe6858b}, /* U+614B */ + {0xc2d7, 0xe688b4}, /* U+6234 */ + {0xc2d8, 0xe69bbf}, /* U+66FF */ + {0xc2d9, 0xe6b3b0}, /* U+6CF0 */ + {0xc2da, 0xe6bb9e}, /* U+6EDE */ + {0xc2db, 0xe8838e}, /* U+80CE */ + {0xc2dc, 0xe885bf}, /* U+817F */ + {0xc2dd, 0xe88b94}, /* U+82D4 */ + {0xc2de, 0xe8a28b}, /* U+888B */ + {0xc2df, 0xe8b2b8}, /* U+8CB8 */ + {0xc2e0, 0xe98080}, /* U+9000 */ + {0xc2e1, 0xe980ae}, /* U+902E */ + {0xc2e2, 0xe99a8a}, /* U+968A */ + {0xc2e3, 0xe9bb9b}, /* U+9EDB */ + {0xc2e4, 0xe9af9b}, /* U+9BDB */ + {0xc2e5, 0xe4bba3}, /* U+4EE3 */ + {0xc2e6, 0xe58fb0}, /* U+53F0 */ + {0xc2e7, 0xe5a4a7}, /* U+5927 */ + {0xc2e8, 0xe7acac}, /* U+7B2C */ + {0xc2e9, 0xe9868d}, /* U+918D */ + {0xc2ea, 0xe9a18c}, /* U+984C */ + {0xc2eb, 0xe9b7b9}, /* U+9DF9 */ + {0xc2ec, 0xe6bb9d}, /* U+6EDD */ + {0xc2ed, 0xe780a7}, /* U+7027 */ + {0xc2ee, 0xe58d93}, /* U+5353 */ + {0xc2ef, 0xe59584}, /* U+5544 */ + {0xc2f0, 0xe5ae85}, /* U+5B85 */ + {0xc2f1, 0xe68998}, /* U+6258 */ + {0xc2f2, 0xe68a9e}, /* U+629E */ + {0xc2f3, 0xe68b93}, /* U+62D3 */ + {0xc2f4, 0xe6b2a2}, /* U+6CA2 */ + {0xc2f5, 0xe6bfaf}, /* U+6FEF */ + {0xc2f6, 0xe790a2}, /* U+7422 */ + {0xc2f7, 0xe8a897}, /* U+8A17 */ + {0xc2f8, 0xe990b8}, /* U+9438 */ + {0xc2f9, 0xe6bf81}, /* U+6FC1 */ + {0xc2fa, 0xe8abbe}, /* U+8AFE */ + {0xc2fb, 0xe88cb8}, /* U+8338 */ + {0xc2fc, 0xe587a7}, /* U+51E7 */ + {0xc2fd, 0xe89bb8}, /* U+86F8 */ + {0xc2fe, 0xe58faa}, /* U+53EA */ + {0xc3a1, 0xe58fa9}, /* U+53E9 */ + {0xc3a2, 0xe4bd86}, /* U+4F46 */ + {0xc3a3, 0xe98194}, /* U+9054 */ + {0xc3a4, 0xe8beb0}, /* U+8FB0 */ + {0xc3a5, 0xe5a5aa}, /* U+596A */ + {0xc3a6, 0xe884b1}, /* U+8131 */ + {0xc3a7, 0xe5b7bd}, /* U+5DFD */ + {0xc3a8, 0xe7abaa}, /* U+7AEA */ + {0xc3a9, 0xe8bebf}, /* U+8FBF */ + {0xc3aa, 0xe6a39a}, /* U+68DA */ + {0xc3ab, 0xe8b0b7}, /* U+8C37 */ + {0xc3ac, 0xe78bb8}, /* U+72F8 */ + {0xc3ad, 0xe9b188}, /* U+9C48 */ + {0xc3ae, 0xe6a8bd}, /* U+6A3D */ + {0xc3af, 0xe8aab0}, /* U+8AB0 */ + {0xc3b0, 0xe4b8b9}, /* U+4E39 */ + {0xc3b1, 0xe58d98}, /* U+5358 */ + {0xc3b2, 0xe59886}, /* U+5606 */ + {0xc3b3, 0xe59da6}, /* U+5766 */ + {0xc3b4, 0xe68b85}, /* U+62C5 */ + {0xc3b5, 0xe68ea2}, /* U+63A2 */ + {0xc3b6, 0xe697a6}, /* U+65E6 */ + {0xc3b7, 0xe6ad8e}, /* U+6B4E */ + {0xc3b8, 0xe6b7a1}, /* U+6DE1 */ + {0xc3b9, 0xe6b99b}, /* U+6E5B */ + {0xc3ba, 0xe782ad}, /* U+70AD */ + {0xc3bb, 0xe79fad}, /* U+77ED */ + {0xc3bc, 0xe7abaf}, /* U+7AEF */ + {0xc3bd, 0xe7aeaa}, /* U+7BAA */ + {0xc3be, 0xe7b6bb}, /* U+7DBB */ + {0xc3bf, 0xe880bd}, /* U+803D */ + {0xc3c0, 0xe88386}, /* U+80C6 */ + {0xc3c1, 0xe89b8b}, /* U+86CB */ + {0xc3c2, 0xe8aa95}, /* U+8A95 */ + {0xc3c3, 0xe98d9b}, /* U+935B */ + {0xc3c4, 0xe59ba3}, /* U+56E3 */ + {0xc3c5, 0xe5a387}, /* U+58C7 */ + {0xc3c6, 0xe5bcbe}, /* U+5F3E */ + {0xc3c7, 0xe696ad}, /* U+65AD */ + {0xc3c8, 0xe69a96}, /* U+6696 */ + {0xc3c9, 0xe6aa80}, /* U+6A80 */ + {0xc3ca, 0xe6aeb5}, /* U+6BB5 */ + {0xc3cb, 0xe794b7}, /* U+7537 */ + {0xc3cc, 0xe8ab87}, /* U+8AC7 */ + {0xc3cd, 0xe580a4}, /* U+5024 */ + {0xc3ce, 0xe79fa5}, /* U+77E5 */ + {0xc3cf, 0xe59cb0}, /* U+5730 */ + {0xc3d0, 0xe5bc9b}, /* U+5F1B */ + {0xc3d1, 0xe681a5}, /* U+6065 */ + {0xc3d2, 0xe699ba}, /* U+667A */ + {0xc3d3, 0xe6b1a0}, /* U+6C60 */ + {0xc3d4, 0xe797b4}, /* U+75F4 */ + {0xc3d5, 0xe7a89a}, /* U+7A1A */ + {0xc3d6, 0xe7bdae}, /* U+7F6E */ + {0xc3d7, 0xe887b4}, /* U+81F4 */ + {0xc3d8, 0xe89c98}, /* U+8718 */ + {0xc3d9, 0xe98185}, /* U+9045 */ + {0xc3da, 0xe9a6b3}, /* U+99B3 */ + {0xc3db, 0xe7af89}, /* U+7BC9 */ + {0xc3dc, 0xe7959c}, /* U+755C */ + {0xc3dd, 0xe7abb9}, /* U+7AF9 */ + {0xc3de, 0xe7ad91}, /* U+7B51 */ + {0xc3df, 0xe89384}, /* U+84C4 */ + {0xc3e0, 0xe98090}, /* U+9010 */ + {0xc3e1, 0xe7a7a9}, /* U+79E9 */ + {0xc3e2, 0xe7aa92}, /* U+7A92 */ + {0xc3e3, 0xe88cb6}, /* U+8336 */ + {0xc3e4, 0xe5aba1}, /* U+5AE1 */ + {0xc3e5, 0xe79d80}, /* U+7740 */ + {0xc3e6, 0xe4b8ad}, /* U+4E2D */ + {0xc3e7, 0xe4bbb2}, /* U+4EF2 */ + {0xc3e8, 0xe5ae99}, /* U+5B99 */ + {0xc3e9, 0xe5bfa0}, /* U+5FE0 */ + {0xc3ea, 0xe68abd}, /* U+62BD */ + {0xc3eb, 0xe698bc}, /* U+663C */ + {0xc3ec, 0xe69fb1}, /* U+67F1 */ + {0xc3ed, 0xe6b3a8}, /* U+6CE8 */ + {0xc3ee, 0xe899ab}, /* U+866B */ + {0xc3ef, 0xe8a1b7}, /* U+8877 */ + {0xc3f0, 0xe8a8bb}, /* U+8A3B */ + {0xc3f1, 0xe9858e}, /* U+914E */ + {0xc3f2, 0xe98bb3}, /* U+92F3 */ + {0xc3f3, 0xe9a790}, /* U+99D0 */ + {0xc3f4, 0xe6a897}, /* U+6A17 */ + {0xc3f5, 0xe780a6}, /* U+7026 */ + {0xc3f6, 0xe78caa}, /* U+732A */ + {0xc3f7, 0xe88ba7}, /* U+82E7 */ + {0xc3f8, 0xe89197}, /* U+8457 */ + {0xc3f9, 0xe8b2af}, /* U+8CAF */ + {0xc3fa, 0xe4b881}, /* U+4E01 */ + {0xc3fb, 0xe58586}, /* U+5146 */ + {0xc3fc, 0xe5878b}, /* U+51CB */ + {0xc3fd, 0xe5968b}, /* U+558B */ + {0xc3fe, 0xe5afb5}, /* U+5BF5 */ + {0xc4a1, 0xe5b896}, /* U+5E16 */ + {0xc4a2, 0xe5b8b3}, /* U+5E33 */ + {0xc4a3, 0xe5ba81}, /* U+5E81 */ + {0xc4a4, 0xe5bc94}, /* U+5F14 */ + {0xc4a5, 0xe5bcb5}, /* U+5F35 */ + {0xc4a6, 0xe5bdab}, /* U+5F6B */ + {0xc4a7, 0xe5beb4}, /* U+5FB4 */ + {0xc4a8, 0xe687b2}, /* U+61F2 */ + {0xc4a9, 0xe68c91}, /* U+6311 */ + {0xc4aa, 0xe69aa2}, /* U+66A2 */ + {0xc4ab, 0xe69c9d}, /* U+671D */ + {0xc4ac, 0xe6bdae}, /* U+6F6E */ + {0xc4ad, 0xe78992}, /* U+7252 */ + {0xc4ae, 0xe794ba}, /* U+753A */ + {0xc4af, 0xe79cba}, /* U+773A */ + {0xc4b0, 0xe881b4}, /* U+8074 */ + {0xc4b1, 0xe884b9}, /* U+8139 */ + {0xc4b2, 0xe885b8}, /* U+8178 */ + {0xc4b3, 0xe89db6}, /* U+8776 */ + {0xc4b4, 0xe8aabf}, /* U+8ABF */ + {0xc4b5, 0xe8ab9c}, /* U+8ADC */ + {0xc4b6, 0xe8b685}, /* U+8D85 */ + {0xc4b7, 0xe8b7b3}, /* U+8DF3 */ + {0xc4b8, 0xe98a9a}, /* U+929A */ + {0xc4b9, 0xe995b7}, /* U+9577 */ + {0xc4ba, 0xe9a082}, /* U+9802 */ + {0xc4bb, 0xe9b3a5}, /* U+9CE5 */ + {0xc4bc, 0xe58b85}, /* U+52C5 */ + {0xc4bd, 0xe68d97}, /* U+6357 */ + {0xc4be, 0xe79bb4}, /* U+76F4 */ + {0xc4bf, 0xe69c95}, /* U+6715 */ + {0xc4c0, 0xe6b288}, /* U+6C88 */ + {0xc4c1, 0xe78f8d}, /* U+73CD */ + {0xc4c2, 0xe8b383}, /* U+8CC3 */ + {0xc4c3, 0xe98eae}, /* U+93AE */ + {0xc4c4, 0xe999b3}, /* U+9673 */ + {0xc4c5, 0xe6b4a5}, /* U+6D25 */ + {0xc4c6, 0xe5a29c}, /* U+589C */ + {0xc4c7, 0xe6a48e}, /* U+690E */ + {0xc4c8, 0xe6a78c}, /* U+69CC */ + {0xc4c9, 0xe8bfbd}, /* U+8FFD */ + {0xc4ca, 0xe98e9a}, /* U+939A */ + {0xc4cb, 0xe7979b}, /* U+75DB */ + {0xc4cc, 0xe9809a}, /* U+901A */ + {0xc4cd, 0xe5a19a}, /* U+585A */ + {0xc4ce, 0xe6a082}, /* U+6802 */ + {0xc4cf, 0xe68eb4}, /* U+63B4 */ + {0xc4d0, 0xe6a7bb}, /* U+69FB */ + {0xc4d1, 0xe4bd83}, /* U+4F43 */ + {0xc4d2, 0xe6bcac}, /* U+6F2C */ + {0xc4d3, 0xe69f98}, /* U+67D8 */ + {0xc4d4, 0xe8bebb}, /* U+8FBB */ + {0xc4d5, 0xe894a6}, /* U+8526 */ + {0xc4d6, 0xe7b6b4}, /* U+7DB4 */ + {0xc4d7, 0xe98d94}, /* U+9354 */ + {0xc4d8, 0xe6a4bf}, /* U+693F */ + {0xc4d9, 0xe6bdb0}, /* U+6F70 */ + {0xc4da, 0xe59daa}, /* U+576A */ + {0xc4db, 0xe5a3b7}, /* U+58F7 */ + {0xc4dc, 0xe5acac}, /* U+5B2C */ + {0xc4dd, 0xe7b4ac}, /* U+7D2C */ + {0xc4de, 0xe788aa}, /* U+722A */ + {0xc4df, 0xe5908a}, /* U+540A */ + {0xc4e0, 0xe987a3}, /* U+91E3 */ + {0xc4e1, 0xe9b6b4}, /* U+9DB4 */ + {0xc4e2, 0xe4baad}, /* U+4EAD */ + {0xc4e3, 0xe4bd8e}, /* U+4F4E */ + {0xc4e4, 0xe5819c}, /* U+505C */ + {0xc4e5, 0xe581b5}, /* U+5075 */ + {0xc4e6, 0xe58983}, /* U+5243 */ + {0xc4e7, 0xe8b29e}, /* U+8C9E */ + {0xc4e8, 0xe59188}, /* U+5448 */ + {0xc4e9, 0xe5a0a4}, /* U+5824 */ + {0xc4ea, 0xe5ae9a}, /* U+5B9A */ + {0xc4eb, 0xe5b89d}, /* U+5E1D */ + {0xc4ec, 0xe5ba95}, /* U+5E95 */ + {0xc4ed, 0xe5baad}, /* U+5EAD */ + {0xc4ee, 0xe5bbb7}, /* U+5EF7 */ + {0xc4ef, 0xe5bc9f}, /* U+5F1F */ + {0xc4f0, 0xe6828c}, /* U+608C */ + {0xc4f1, 0xe68ab5}, /* U+62B5 */ + {0xc4f2, 0xe68cba}, /* U+633A */ + {0xc4f3, 0xe68f90}, /* U+63D0 */ + {0xc4f4, 0xe6a2af}, /* U+68AF */ + {0xc4f5, 0xe6b180}, /* U+6C40 */ + {0xc4f6, 0xe7a287}, /* U+7887 */ + {0xc4f7, 0xe7a68e}, /* U+798E */ + {0xc4f8, 0xe7a88b}, /* U+7A0B */ + {0xc4f9, 0xe7b7a0}, /* U+7DE0 */ + {0xc4fa, 0xe88987}, /* U+8247 */ + {0xc4fb, 0xe8a882}, /* U+8A02 */ + {0xc4fc, 0xe8aba6}, /* U+8AE6 */ + {0xc4fd, 0xe8b984}, /* U+8E44 */ + {0xc4fe, 0xe98093}, /* U+9013 */ + {0xc5a1, 0xe982b8}, /* U+90B8 */ + {0xc5a2, 0xe984ad}, /* U+912D */ + {0xc5a3, 0xe98798}, /* U+91D8 */ + {0xc5a4, 0xe9bc8e}, /* U+9F0E */ + {0xc5a5, 0xe6b3a5}, /* U+6CE5 */ + {0xc5a6, 0xe69198}, /* U+6458 */ + {0xc5a7, 0xe693a2}, /* U+64E2 */ + {0xc5a8, 0xe695b5}, /* U+6575 */ + {0xc5a9, 0xe6bbb4}, /* U+6EF4 */ + {0xc5aa, 0xe79a84}, /* U+7684 */ + {0xc5ab, 0xe7ac9b}, /* U+7B1B */ + {0xc5ac, 0xe981a9}, /* U+9069 */ + {0xc5ad, 0xe98f91}, /* U+93D1 */ + {0xc5ae, 0xe6baba}, /* U+6EBA */ + {0xc5af, 0xe593b2}, /* U+54F2 */ + {0xc5b0, 0xe5beb9}, /* U+5FB9 */ + {0xc5b1, 0xe692a4}, /* U+64A4 */ + {0xc5b2, 0xe8bd8d}, /* U+8F4D */ + {0xc5b3, 0xe8bfad}, /* U+8FED */ + {0xc5b4, 0xe98984}, /* U+9244 */ + {0xc5b5, 0xe585b8}, /* U+5178 */ + {0xc5b6, 0xe5a1ab}, /* U+586B */ + {0xc5b7, 0xe5a4a9}, /* U+5929 */ + {0xc5b8, 0xe5b195}, /* U+5C55 */ + {0xc5b9, 0xe5ba97}, /* U+5E97 */ + {0xc5ba, 0xe6b7bb}, /* U+6DFB */ + {0xc5bb, 0xe7ba8f}, /* U+7E8F */ + {0xc5bc, 0xe7949c}, /* U+751C */ + {0xc5bd, 0xe8b2bc}, /* U+8CBC */ + {0xc5be, 0xe8bba2}, /* U+8EE2 */ + {0xc5bf, 0xe9a19b}, /* U+985B */ + {0xc5c0, 0xe782b9}, /* U+70B9 */ + {0xc5c1, 0xe4bc9d}, /* U+4F1D */ + {0xc5c2, 0xe6aebf}, /* U+6BBF */ + {0xc5c3, 0xe6beb1}, /* U+6FB1 */ + {0xc5c4, 0xe794b0}, /* U+7530 */ + {0xc5c5, 0xe99bbb}, /* U+96FB */ + {0xc5c6, 0xe5858e}, /* U+514E */ + {0xc5c7, 0xe59090}, /* U+5410 */ + {0xc5c8, 0xe5a0b5}, /* U+5835 */ + {0xc5c9, 0xe5a197}, /* U+5857 */ + {0xc5ca, 0xe5a6ac}, /* U+59AC */ + {0xc5cb, 0xe5b1a0}, /* U+5C60 */ + {0xc5cc, 0xe5be92}, /* U+5F92 */ + {0xc5cd, 0xe69697}, /* U+6597 */ + {0xc5ce, 0xe69d9c}, /* U+675C */ + {0xc5cf, 0xe6b8a1}, /* U+6E21 */ + {0xc5d0, 0xe799bb}, /* U+767B */ + {0xc5d1, 0xe88f9f}, /* U+83DF */ + {0xc5d2, 0xe8b3ad}, /* U+8CED */ + {0xc5d3, 0xe98094}, /* U+9014 */ + {0xc5d4, 0xe983bd}, /* U+90FD */ + {0xc5d5, 0xe98d8d}, /* U+934D */ + {0xc5d6, 0xe7a0a5}, /* U+7825 */ + {0xc5d7, 0xe7a0ba}, /* U+783A */ + {0xc5d8, 0xe58aaa}, /* U+52AA */ + {0xc5d9, 0xe5baa6}, /* U+5EA6 */ + {0xc5da, 0xe59c9f}, /* U+571F */ + {0xc5db, 0xe5a5b4}, /* U+5974 */ + {0xc5dc, 0xe68092}, /* U+6012 */ + {0xc5dd, 0xe58092}, /* U+5012 */ + {0xc5de, 0xe5859a}, /* U+515A */ + {0xc5df, 0xe586ac}, /* U+51AC */ + {0xc5e0, 0xe5878d}, /* U+51CD */ + {0xc5e1, 0xe58880}, /* U+5200 */ + {0xc5e2, 0xe59490}, /* U+5510 */ + {0xc5e3, 0xe5a194}, /* U+5854 */ + {0xc5e4, 0xe5a198}, /* U+5858 */ + {0xc5e5, 0xe5a597}, /* U+5957 */ + {0xc5e6, 0xe5ae95}, /* U+5B95 */ + {0xc5e7, 0xe5b3b6}, /* U+5CF6 */ + {0xc5e8, 0xe5b68b}, /* U+5D8B */ + {0xc5e9, 0xe682bc}, /* U+60BC */ + {0xc5ea, 0xe68a95}, /* U+6295 */ + {0xc5eb, 0xe690ad}, /* U+642D */ + {0xc5ec, 0xe69db1}, /* U+6771 */ + {0xc5ed, 0xe6a183}, /* U+6843 */ + {0xc5ee, 0xe6a2bc}, /* U+68BC */ + {0xc5ef, 0xe6a39f}, /* U+68DF */ + {0xc5f0, 0xe79b97}, /* U+76D7 */ + {0xc5f1, 0xe6b798}, /* U+6DD8 */ + {0xc5f2, 0xe6b9af}, /* U+6E6F */ + {0xc5f3, 0xe6b69b}, /* U+6D9B */ + {0xc5f4, 0xe781af}, /* U+706F */ + {0xc5f5, 0xe78788}, /* U+71C8 */ + {0xc5f6, 0xe5bd93}, /* U+5F53 */ + {0xc5f7, 0xe79798}, /* U+75D8 */ + {0xc5f8, 0xe7a5b7}, /* U+7977 */ + {0xc5f9, 0xe7ad89}, /* U+7B49 */ + {0xc5fa, 0xe7ad94}, /* U+7B54 */ + {0xc5fb, 0xe7ad92}, /* U+7B52 */ + {0xc5fc, 0xe7b396}, /* U+7CD6 */ + {0xc5fd, 0xe7b5b1}, /* U+7D71 */ + {0xc5fe, 0xe588b0}, /* U+5230 */ + {0xc6a1, 0xe891a3}, /* U+8463 */ + {0xc6a2, 0xe895a9}, /* U+8569 */ + {0xc6a3, 0xe897a4}, /* U+85E4 */ + {0xc6a4, 0xe8a88e}, /* U+8A0E */ + {0xc6a5, 0xe8ac84}, /* U+8B04 */ + {0xc6a6, 0xe8b186}, /* U+8C46 */ + {0xc6a7, 0xe8b88f}, /* U+8E0F */ + {0xc6a8, 0xe98083}, /* U+9003 */ + {0xc6a9, 0xe9808f}, /* U+900F */ + {0xc6aa, 0xe99099}, /* U+9419 */ + {0xc6ab, 0xe999b6}, /* U+9676 */ + {0xc6ac, 0xe9a0ad}, /* U+982D */ + {0xc6ad, 0xe9a8b0}, /* U+9A30 */ + {0xc6ae, 0xe99798}, /* U+95D8 */ + {0xc6af, 0xe5838d}, /* U+50CD */ + {0xc6b0, 0xe58b95}, /* U+52D5 */ + {0xc6b1, 0xe5908c}, /* U+540C */ + {0xc6b2, 0xe5a082}, /* U+5802 */ + {0xc6b3, 0xe5b08e}, /* U+5C0E */ + {0xc6b4, 0xe686a7}, /* U+61A7 */ + {0xc6b5, 0xe6929e}, /* U+649E */ + {0xc6b6, 0xe6b49e}, /* U+6D1E */ + {0xc6b7, 0xe79eb3}, /* U+77B3 */ + {0xc6b8, 0xe7aba5}, /* U+7AE5 */ + {0xc6b9, 0xe883b4}, /* U+80F4 */ + {0xc6ba, 0xe89084}, /* U+8404 */ + {0xc6bb, 0xe98193}, /* U+9053 */ + {0xc6bc, 0xe98a85}, /* U+9285 */ + {0xc6bd, 0xe5b3a0}, /* U+5CE0 */ + {0xc6be, 0xe9b487}, /* U+9D07 */ + {0xc6bf, 0xe58cbf}, /* U+533F */ + {0xc6c0, 0xe5be97}, /* U+5F97 */ + {0xc6c1, 0xe5beb3}, /* U+5FB3 */ + {0xc6c2, 0xe6b69c}, /* U+6D9C */ + {0xc6c3, 0xe789b9}, /* U+7279 */ + {0xc6c4, 0xe79da3}, /* U+7763 */ + {0xc6c5, 0xe7a6bf}, /* U+79BF */ + {0xc6c6, 0xe7afa4}, /* U+7BE4 */ + {0xc6c7, 0xe6af92}, /* U+6BD2 */ + {0xc6c8, 0xe78bac}, /* U+72EC */ + {0xc6c9, 0xe8aaad}, /* U+8AAD */ + {0xc6ca, 0xe6a083}, /* U+6803 */ + {0xc6cb, 0xe6a9a1}, /* U+6A61 */ + {0xc6cc, 0xe587b8}, /* U+51F8 */ + {0xc6cd, 0xe7aa81}, /* U+7A81 */ + {0xc6ce, 0xe6a4b4}, /* U+6934 */ + {0xc6cf, 0xe5b18a}, /* U+5C4A */ + {0xc6d0, 0xe9b3b6}, /* U+9CF6 */ + {0xc6d1, 0xe88bab}, /* U+82EB */ + {0xc6d2, 0xe5af85}, /* U+5BC5 */ + {0xc6d3, 0xe98589}, /* U+9149 */ + {0xc6d4, 0xe7809e}, /* U+701E */ + {0xc6d5, 0xe599b8}, /* U+5678 */ + {0xc6d6, 0xe5b1af}, /* U+5C6F */ + {0xc6d7, 0xe68387}, /* U+60C7 */ + {0xc6d8, 0xe695a6}, /* U+6566 */ + {0xc6d9, 0xe6b28c}, /* U+6C8C */ + {0xc6da, 0xe8b19a}, /* U+8C5A */ + {0xc6db, 0xe98181}, /* U+9041 */ + {0xc6dc, 0xe9a093}, /* U+9813 */ + {0xc6dd, 0xe59191}, /* U+5451 */ + {0xc6de, 0xe69b87}, /* U+66C7 */ + {0xc6df, 0xe9888d}, /* U+920D */ + {0xc6e0, 0xe5a588}, /* U+5948 */ + {0xc6e1, 0xe982a3}, /* U+90A3 */ + {0xc6e2, 0xe58685}, /* U+5185 */ + {0xc6e3, 0xe4b98d}, /* U+4E4D */ + {0xc6e4, 0xe587aa}, /* U+51EA */ + {0xc6e5, 0xe89699}, /* U+8599 */ + {0xc6e6, 0xe8ac8e}, /* U+8B0E */ + {0xc6e7, 0xe78198}, /* U+7058 */ + {0xc6e8, 0xe68dba}, /* U+637A */ + {0xc6e9, 0xe98d8b}, /* U+934B */ + {0xc6ea, 0xe6a5a2}, /* U+6962 */ + {0xc6eb, 0xe9a6b4}, /* U+99B4 */ + {0xc6ec, 0xe7b884}, /* U+7E04 */ + {0xc6ed, 0xe795b7}, /* U+7577 */ + {0xc6ee, 0xe58d97}, /* U+5357 */ + {0xc6ef, 0xe6a5a0}, /* U+6960 */ + {0xc6f0, 0xe8bb9f}, /* U+8EDF */ + {0xc6f1, 0xe99ba3}, /* U+96E3 */ + {0xc6f2, 0xe6b19d}, /* U+6C5D */ + {0xc6f3, 0xe4ba8c}, /* U+4E8C */ + {0xc6f4, 0xe5b0bc}, /* U+5C3C */ + {0xc6f5, 0xe5bc90}, /* U+5F10 */ + {0xc6f6, 0xe8bfa9}, /* U+8FE9 */ + {0xc6f7, 0xe58c82}, /* U+5302 */ + {0xc6f8, 0xe8b391}, /* U+8CD1 */ + {0xc6f9, 0xe88289}, /* U+8089 */ + {0xc6fa, 0xe899b9}, /* U+8679 */ + {0xc6fb, 0xe5bbbf}, /* U+5EFF */ + {0xc6fc, 0xe697a5}, /* U+65E5 */ + {0xc6fd, 0xe4b9b3}, /* U+4E73 */ + {0xc6fe, 0xe585a5}, /* U+5165 */ + {0xc7a1, 0xe5a682}, /* U+5982 */ + {0xc7a2, 0xe5b0bf}, /* U+5C3F */ + {0xc7a3, 0xe99fae}, /* U+97EE */ + {0xc7a4, 0xe4bbbb}, /* U+4EFB */ + {0xc7a5, 0xe5a68a}, /* U+598A */ + {0xc7a6, 0xe5bf8d}, /* U+5FCD */ + {0xc7a7, 0xe8aa8d}, /* U+8A8D */ + {0xc7a8, 0xe6bfa1}, /* U+6FE1 */ + {0xc7a9, 0xe7a6b0}, /* U+79B0 */ + {0xc7aa, 0xe7a5a2}, /* U+7962 */ + {0xc7ab, 0xe5afa7}, /* U+5BE7 */ + {0xc7ac, 0xe891b1}, /* U+8471 */ + {0xc7ad, 0xe78cab}, /* U+732B */ + {0xc7ae, 0xe786b1}, /* U+71B1 */ + {0xc7af, 0xe5b9b4}, /* U+5E74 */ + {0xc7b0, 0xe5bfb5}, /* U+5FF5 */ + {0xc7b1, 0xe68dbb}, /* U+637B */ + {0xc7b2, 0xe6929a}, /* U+649A */ + {0xc7b3, 0xe78783}, /* U+71C3 */ + {0xc7b4, 0xe7b298}, /* U+7C98 */ + {0xc7b5, 0xe4b983}, /* U+4E43 */ + {0xc7b6, 0xe5bbbc}, /* U+5EFC */ + {0xc7b7, 0xe4b98b}, /* U+4E4B */ + {0xc7b8, 0xe59f9c}, /* U+57DC */ + {0xc7b9, 0xe59aa2}, /* U+56A2 */ + {0xc7ba, 0xe682a9}, /* U+60A9 */ + {0xc7bb, 0xe6bf83}, /* U+6FC3 */ + {0xc7bc, 0xe7b48d}, /* U+7D0D */ + {0xc7bd, 0xe883bd}, /* U+80FD */ + {0xc7be, 0xe884b3}, /* U+8133 */ + {0xc7bf, 0xe886bf}, /* U+81BF */ + {0xc7c0, 0xe8beb2}, /* U+8FB2 */ + {0xc7c1, 0xe8a697}, /* U+8997 */ + {0xc7c2, 0xe89aa4}, /* U+86A4 */ + {0xc7c3, 0xe5b7b4}, /* U+5DF4 */ + {0xc7c4, 0xe68a8a}, /* U+628A */ + {0xc7c5, 0xe692ad}, /* U+64AD */ + {0xc7c6, 0xe8a687}, /* U+8987 */ + {0xc7c7, 0xe69db7}, /* U+6777 */ + {0xc7c8, 0xe6b3a2}, /* U+6CE2 */ + {0xc7c9, 0xe6b4be}, /* U+6D3E */ + {0xc7ca, 0xe790b6}, /* U+7436 */ + {0xc7cb, 0xe7a0b4}, /* U+7834 */ + {0xc7cc, 0xe5a986}, /* U+5A46 */ + {0xc7cd, 0xe7bdb5}, /* U+7F75 */ + {0xc7ce, 0xe88aad}, /* U+82AD */ + {0xc7cf, 0xe9a6ac}, /* U+99AC */ + {0xc7d0, 0xe4bfb3}, /* U+4FF3 */ + {0xc7d1, 0xe5bb83}, /* U+5EC3 */ + {0xc7d2, 0xe68b9d}, /* U+62DD */ + {0xc7d3, 0xe68e92}, /* U+6392 */ + {0xc7d4, 0xe69597}, /* U+6557 */ + {0xc7d5, 0xe69daf}, /* U+676F */ + {0xc7d6, 0xe79b83}, /* U+76C3 */ + {0xc7d7, 0xe7898c}, /* U+724C */ + {0xc7d8, 0xe8838c}, /* U+80CC */ + {0xc7d9, 0xe882ba}, /* U+80BA */ + {0xc7da, 0xe8bca9}, /* U+8F29 */ + {0xc7db, 0xe9858d}, /* U+914D */ + {0xc7dc, 0xe5808d}, /* U+500D */ + {0xc7dd, 0xe59fb9}, /* U+57F9 */ + {0xc7de, 0xe5aa92}, /* U+5A92 */ + {0xc7df, 0xe6a285}, /* U+6885 */ + {0xc7e0, 0xe6a5b3}, /* U+6973 */ + {0xc7e1, 0xe785a4}, /* U+7164 */ + {0xc7e2, 0xe78bbd}, /* U+72FD */ + {0xc7e3, 0xe8b2b7}, /* U+8CB7 */ + {0xc7e4, 0xe5a3b2}, /* U+58F2 */ + {0xc7e5, 0xe8b3a0}, /* U+8CE0 */ + {0xc7e6, 0xe999aa}, /* U+966A */ + {0xc7e7, 0xe98099}, /* U+9019 */ + {0xc7e8, 0xe89dbf}, /* U+877F */ + {0xc7e9, 0xe7a7a4}, /* U+79E4 */ + {0xc7ea, 0xe79fa7}, /* U+77E7 */ + {0xc7eb, 0xe890a9}, /* U+8429 */ + {0xc7ec, 0xe4bcaf}, /* U+4F2F */ + {0xc7ed, 0xe589a5}, /* U+5265 */ + {0xc7ee, 0xe58d9a}, /* U+535A */ + {0xc7ef, 0xe68b8d}, /* U+62CD */ + {0xc7f0, 0xe69f8f}, /* U+67CF */ + {0xc7f1, 0xe6b38a}, /* U+6CCA */ + {0xc7f2, 0xe799bd}, /* U+767D */ + {0xc7f3, 0xe7ae94}, /* U+7B94 */ + {0xc7f4, 0xe7b295}, /* U+7C95 */ + {0xc7f5, 0xe888b6}, /* U+8236 */ + {0xc7f6, 0xe89684}, /* U+8584 */ + {0xc7f7, 0xe8bfab}, /* U+8FEB */ + {0xc7f8, 0xe69b9d}, /* U+66DD */ + {0xc7f9, 0xe6bca0}, /* U+6F20 */ + {0xc7fa, 0xe78886}, /* U+7206 */ + {0xc7fb, 0xe7b89b}, /* U+7E1B */ + {0xc7fc, 0xe88eab}, /* U+83AB */ + {0xc7fd, 0xe9a781}, /* U+99C1 */ + {0xc7fe, 0xe9baa6}, /* U+9EA6 */ + {0xc8a1, 0xe587bd}, /* U+51FD */ + {0xc8a2, 0xe7aeb1}, /* U+7BB1 */ + {0xc8a3, 0xe7a1b2}, /* U+7872 */ + {0xc8a4, 0xe7aeb8}, /* U+7BB8 */ + {0xc8a5, 0xe88287}, /* U+8087 */ + {0xc8a6, 0xe7ad88}, /* U+7B48 */ + {0xc8a7, 0xe6aba8}, /* U+6AE8 */ + {0xc8a8, 0xe5b9a1}, /* U+5E61 */ + {0xc8a9, 0xe8828c}, /* U+808C */ + {0xc8aa, 0xe79591}, /* U+7551 */ + {0xc8ab, 0xe795a0}, /* U+7560 */ + {0xc8ac, 0xe585ab}, /* U+516B */ + {0xc8ad, 0xe989a2}, /* U+9262 */ + {0xc8ae, 0xe6ba8c}, /* U+6E8C */ + {0xc8af, 0xe799ba}, /* U+767A */ + {0xc8b0, 0xe98697}, /* U+9197 */ + {0xc8b1, 0xe9abaa}, /* U+9AEA */ + {0xc8b2, 0xe4bc90}, /* U+4F10 */ + {0xc8b3, 0xe7bdb0}, /* U+7F70 */ + {0xc8b4, 0xe68a9c}, /* U+629C */ + {0xc8b5, 0xe7ad8f}, /* U+7B4F */ + {0xc8b6, 0xe996a5}, /* U+95A5 */ + {0xc8b7, 0xe9b3a9}, /* U+9CE9 */ + {0xc8b8, 0xe599ba}, /* U+567A */ + {0xc8b9, 0xe5a199}, /* U+5859 */ + {0xc8ba, 0xe89ba4}, /* U+86E4 */ + {0xc8bb, 0xe99abc}, /* U+96BC */ + {0xc8bc, 0xe4bcb4}, /* U+4F34 */ + {0xc8bd, 0xe588a4}, /* U+5224 */ + {0xc8be, 0xe58d8a}, /* U+534A */ + {0xc8bf, 0xe58f8d}, /* U+53CD */ + {0xc8c0, 0xe58f9b}, /* U+53DB */ + {0xc8c1, 0xe5b886}, /* U+5E06 */ + {0xc8c2, 0xe690ac}, /* U+642C */ + {0xc8c3, 0xe69691}, /* U+6591 */ + {0xc8c4, 0xe69dbf}, /* U+677F */ + {0xc8c5, 0xe6b0be}, /* U+6C3E */ + {0xc8c6, 0xe6b18e}, /* U+6C4E */ + {0xc8c7, 0xe78988}, /* U+7248 */ + {0xc8c8, 0xe78aaf}, /* U+72AF */ + {0xc8c9, 0xe78fad}, /* U+73ED */ + {0xc8ca, 0xe79594}, /* U+7554 */ + {0xc8cb, 0xe7b981}, /* U+7E41 */ + {0xc8cc, 0xe888ac}, /* U+822C */ + {0xc8cd, 0xe897a9}, /* U+85E9 */ + {0xc8ce, 0xe8b2a9}, /* U+8CA9 */ + {0xc8cf, 0xe7af84}, /* U+7BC4 */ + {0xc8d0, 0xe98786}, /* U+91C6 */ + {0xc8d1, 0xe785a9}, /* U+7169 */ + {0xc8d2, 0xe9a092}, /* U+9812 */ + {0xc8d3, 0xe9a3af}, /* U+98EF */ + {0xc8d4, 0xe68cbd}, /* U+633D */ + {0xc8d5, 0xe699a9}, /* U+6669 */ + {0xc8d6, 0xe795aa}, /* U+756A */ + {0xc8d7, 0xe79ba4}, /* U+76E4 */ + {0xc8d8, 0xe7a390}, /* U+78D0 */ + {0xc8d9, 0xe89583}, /* U+8543 */ + {0xc8da, 0xe89bae}, /* U+86EE */ + {0xc8db, 0xe58caa}, /* U+532A */ + {0xc8dc, 0xe58d91}, /* U+5351 */ + {0xc8dd, 0xe590a6}, /* U+5426 */ + {0xc8de, 0xe5a683}, /* U+5983 */ + {0xc8df, 0xe5ba87}, /* U+5E87 */ + {0xc8e0, 0xe5bdbc}, /* U+5F7C */ + {0xc8e1, 0xe682b2}, /* U+60B2 */ + {0xc8e2, 0xe68989}, /* U+6249 */ + {0xc8e3, 0xe689b9}, /* U+6279 */ + {0xc8e4, 0xe68aab}, /* U+62AB */ + {0xc8e5, 0xe69690}, /* U+6590 */ + {0xc8e6, 0xe6af94}, /* U+6BD4 */ + {0xc8e7, 0xe6b38c}, /* U+6CCC */ + {0xc8e8, 0xe796b2}, /* U+75B2 */ + {0xc8e9, 0xe79aae}, /* U+76AE */ + {0xc8ea, 0xe7a291}, /* U+7891 */ + {0xc8eb, 0xe7a798}, /* U+79D8 */ + {0xc8ec, 0xe7b78b}, /* U+7DCB */ + {0xc8ed, 0xe7bdb7}, /* U+7F77 */ + {0xc8ee, 0xe882a5}, /* U+80A5 */ + {0xc8ef, 0xe8a2ab}, /* U+88AB */ + {0xc8f0, 0xe8aab9}, /* U+8AB9 */ + {0xc8f1, 0xe8b2bb}, /* U+8CBB */ + {0xc8f2, 0xe981bf}, /* U+907F */ + {0xc8f3, 0xe99d9e}, /* U+975E */ + {0xc8f4, 0xe9a39b}, /* U+98DB */ + {0xc8f5, 0xe6a88b}, /* U+6A0B */ + {0xc8f6, 0xe7b0b8}, /* U+7C38 */ + {0xc8f7, 0xe58299}, /* U+5099 */ + {0xc8f8, 0xe5b0be}, /* U+5C3E */ + {0xc8f9, 0xe5beae}, /* U+5FAE */ + {0xc8fa, 0xe69e87}, /* U+6787 */ + {0xc8fb, 0xe6af98}, /* U+6BD8 */ + {0xc8fc, 0xe790b5}, /* U+7435 */ + {0xc8fd, 0xe79c89}, /* U+7709 */ + {0xc8fe, 0xe7be8e}, /* U+7F8E */ + {0xc9a1, 0xe9bcbb}, /* U+9F3B */ + {0xc9a2, 0xe69f8a}, /* U+67CA */ + {0xc9a3, 0xe7a897}, /* U+7A17 */ + {0xc9a4, 0xe58cb9}, /* U+5339 */ + {0xc9a5, 0xe7968b}, /* U+758B */ + {0xc9a6, 0xe9abad}, /* U+9AED */ + {0xc9a7, 0xe5bda6}, /* U+5F66 */ + {0xc9a8, 0xe8869d}, /* U+819D */ + {0xc9a9, 0xe88fb1}, /* U+83F1 */ + {0xc9aa, 0xe88298}, /* U+8098 */ + {0xc9ab, 0xe5bcbc}, /* U+5F3C */ + {0xc9ac, 0xe5bf85}, /* U+5FC5 */ + {0xc9ad, 0xe795a2}, /* U+7562 */ + {0xc9ae, 0xe7ad86}, /* U+7B46 */ + {0xc9af, 0xe980bc}, /* U+903C */ + {0xc9b0, 0xe6a1a7}, /* U+6867 */ + {0xc9b1, 0xe5a7ab}, /* U+59EB */ + {0xc9b2, 0xe5aa9b}, /* U+5A9B */ + {0xc9b3, 0xe7b490}, /* U+7D10 */ + {0xc9b4, 0xe799be}, /* U+767E */ + {0xc9b5, 0xe8acac}, /* U+8B2C */ + {0xc9b6, 0xe4bfb5}, /* U+4FF5 */ + {0xc9b7, 0xe5bdaa}, /* U+5F6A */ + {0xc9b8, 0xe6a899}, /* U+6A19 */ + {0xc9b9, 0xe6b0b7}, /* U+6C37 */ + {0xc9ba, 0xe6bc82}, /* U+6F02 */ + {0xc9bb, 0xe793a2}, /* U+74E2 */ + {0xc9bc, 0xe7a5a8}, /* U+7968 */ + {0xc9bd, 0xe8a1a8}, /* U+8868 */ + {0xc9be, 0xe8a995}, /* U+8A55 */ + {0xc9bf, 0xe8b1b9}, /* U+8C79 */ + {0xc9c0, 0xe5bb9f}, /* U+5EDF */ + {0xc9c1, 0xe68f8f}, /* U+63CF */ + {0xc9c2, 0xe79785}, /* U+75C5 */ + {0xc9c3, 0xe7a792}, /* U+79D2 */ + {0xc9c4, 0xe88b97}, /* U+82D7 */ + {0xc9c5, 0xe98ca8}, /* U+9328 */ + {0xc9c6, 0xe98bb2}, /* U+92F2 */ + {0xc9c7, 0xe8929c}, /* U+849C */ + {0xc9c8, 0xe89bad}, /* U+86ED */ + {0xc9c9, 0xe9b0ad}, /* U+9C2D */ + {0xc9ca, 0xe59381}, /* U+54C1 */ + {0xc9cb, 0xe5bdac}, /* U+5F6C */ + {0xc9cc, 0xe6968c}, /* U+658C */ + {0xc9cd, 0xe6b59c}, /* U+6D5C */ + {0xc9ce, 0xe78095}, /* U+7015 */ + {0xc9cf, 0xe8b2a7}, /* U+8CA7 */ + {0xc9d0, 0xe8b393}, /* U+8CD3 */ + {0xc9d1, 0xe9a0bb}, /* U+983B */ + {0xc9d2, 0xe6958f}, /* U+654F */ + {0xc9d3, 0xe793b6}, /* U+74F6 */ + {0xc9d4, 0xe4b88d}, /* U+4E0D */ + {0xc9d5, 0xe4bb98}, /* U+4ED8 */ + {0xc9d6, 0xe59fa0}, /* U+57E0 */ + {0xc9d7, 0xe5a4ab}, /* U+592B */ + {0xc9d8, 0xe5a9a6}, /* U+5A66 */ + {0xc9d9, 0xe5af8c}, /* U+5BCC */ + {0xc9da, 0xe586a8}, /* U+51A8 */ + {0xc9db, 0xe5b883}, /* U+5E03 */ + {0xc9dc, 0xe5ba9c}, /* U+5E9C */ + {0xc9dd, 0xe68096}, /* U+6016 */ + {0xc9de, 0xe689b6}, /* U+6276 */ + {0xc9df, 0xe695b7}, /* U+6577 */ + {0xc9e0, 0xe696a7}, /* U+65A7 */ + {0xc9e1, 0xe699ae}, /* U+666E */ + {0xc9e2, 0xe6b5ae}, /* U+6D6E */ + {0xc9e3, 0xe788b6}, /* U+7236 */ + {0xc9e4, 0xe7aca6}, /* U+7B26 */ + {0xc9e5, 0xe88590}, /* U+8150 */ + {0xc9e6, 0xe8869a}, /* U+819A */ + {0xc9e7, 0xe88a99}, /* U+8299 */ + {0xc9e8, 0xe8ad9c}, /* U+8B5C */ + {0xc9e9, 0xe8b2a0}, /* U+8CA0 */ + {0xc9ea, 0xe8b3a6}, /* U+8CE6 */ + {0xc9eb, 0xe8b5b4}, /* U+8D74 */ + {0xc9ec, 0xe9989c}, /* U+961C */ + {0xc9ed, 0xe99984}, /* U+9644 */ + {0xc9ee, 0xe4beae}, /* U+4FAE */ + {0xc9ef, 0xe692ab}, /* U+64AB */ + {0xc9f0, 0xe6ada6}, /* U+6B66 */ + {0xc9f1, 0xe8889e}, /* U+821E */ + {0xc9f2, 0xe891a1}, /* U+8461 */ + {0xc9f3, 0xe895aa}, /* U+856A */ + {0xc9f4, 0xe983a8}, /* U+90E8 */ + {0xc9f5, 0xe5b081}, /* U+5C01 */ + {0xc9f6, 0xe6a593}, /* U+6953 */ + {0xc9f7, 0xe9a2a8}, /* U+98A8 */ + {0xc9f8, 0xe891ba}, /* U+847A */ + {0xc9f9, 0xe89597}, /* U+8557 */ + {0xc9fa, 0xe4bc8f}, /* U+4F0F */ + {0xc9fb, 0xe589af}, /* U+526F */ + {0xc9fc, 0xe5bea9}, /* U+5FA9 */ + {0xc9fd, 0xe5b985}, /* U+5E45 */ + {0xc9fe, 0xe69c8d}, /* U+670D */ + {0xcaa1, 0xe7a68f}, /* U+798F */ + {0xcaa2, 0xe885b9}, /* U+8179 */ + {0xcaa3, 0xe8a487}, /* U+8907 */ + {0xcaa4, 0xe8a686}, /* U+8986 */ + {0xcaa5, 0xe6b7b5}, /* U+6DF5 */ + {0xcaa6, 0xe5bc97}, /* U+5F17 */ + {0xcaa7, 0xe68995}, /* U+6255 */ + {0xcaa8, 0xe6b2b8}, /* U+6CB8 */ + {0xcaa9, 0xe4bb8f}, /* U+4ECF */ + {0xcaaa, 0xe789a9}, /* U+7269 */ + {0xcaab, 0xe9ae92}, /* U+9B92 */ + {0xcaac, 0xe58886}, /* U+5206 */ + {0xcaad, 0xe590bb}, /* U+543B */ + {0xcaae, 0xe599b4}, /* U+5674 */ + {0xcaaf, 0xe5a2b3}, /* U+58B3 */ + {0xcab0, 0xe686a4}, /* U+61A4 */ + {0xcab1, 0xe689ae}, /* U+626E */ + {0xcab2, 0xe7849a}, /* U+711A */ + {0xcab3, 0xe5a5ae}, /* U+596E */ + {0xcab4, 0xe7b289}, /* U+7C89 */ + {0xcab5, 0xe7b39e}, /* U+7CDE */ + {0xcab6, 0xe7b49b}, /* U+7D1B */ + {0xcab7, 0xe99bb0}, /* U+96F0 */ + {0xcab8, 0xe69687}, /* U+6587 */ + {0xcab9, 0xe8819e}, /* U+805E */ + {0xcaba, 0xe4b899}, /* U+4E19 */ + {0xcabb, 0xe4bdb5}, /* U+4F75 */ + {0xcabc, 0xe585b5}, /* U+5175 */ + {0xcabd, 0xe5a180}, /* U+5840 */ + {0xcabe, 0xe5b9a3}, /* U+5E63 */ + {0xcabf, 0xe5b9b3}, /* U+5E73 */ + {0xcac0, 0xe5bc8a}, /* U+5F0A */ + {0xcac1, 0xe69f84}, /* U+67C4 */ + {0xcac2, 0xe4b8a6}, /* U+4E26 */ + {0xcac3, 0xe894bd}, /* U+853D */ + {0xcac4, 0xe99689}, /* U+9589 */ + {0xcac5, 0xe9999b}, /* U+965B */ + {0xcac6, 0xe7b1b3}, /* U+7C73 */ + {0xcac7, 0xe9a081}, /* U+9801 */ + {0xcac8, 0xe583bb}, /* U+50FB */ + {0xcac9, 0xe5a381}, /* U+58C1 */ + {0xcaca, 0xe79996}, /* U+7656 */ + {0xcacb, 0xe7a2a7}, /* U+78A7 */ + {0xcacc, 0xe588a5}, /* U+5225 */ + {0xcacd, 0xe79ea5}, /* U+77A5 */ + {0xcace, 0xe89491}, /* U+8511 */ + {0xcacf, 0xe7ae86}, /* U+7B86 */ + {0xcad0, 0xe5818f}, /* U+504F */ + {0xcad1, 0xe5a489}, /* U+5909 */ + {0xcad2, 0xe78987}, /* U+7247 */ + {0xcad3, 0xe7af87}, /* U+7BC7 */ + {0xcad4, 0xe7b7a8}, /* U+7DE8 */ + {0xcad5, 0xe8beba}, /* U+8FBA */ + {0xcad6, 0xe8bf94}, /* U+8FD4 */ + {0xcad7, 0xe9818d}, /* U+904D */ + {0xcad8, 0xe4bebf}, /* U+4FBF */ + {0xcad9, 0xe58b89}, /* U+52C9 */ + {0xcada, 0xe5a8a9}, /* U+5A29 */ + {0xcadb, 0xe5bc81}, /* U+5F01 */ + {0xcadc, 0xe99ead}, /* U+97AD */ + {0xcadd, 0xe4bf9d}, /* U+4FDD */ + {0xcade, 0xe88897}, /* U+8217 */ + {0xcadf, 0xe98baa}, /* U+92EA */ + {0xcae0, 0xe59c83}, /* U+5703 */ + {0xcae1, 0xe68d95}, /* U+6355 */ + {0xcae2, 0xe6ada9}, /* U+6B69 */ + {0xcae3, 0xe794ab}, /* U+752B */ + {0xcae4, 0xe8a39c}, /* U+88DC */ + {0xcae5, 0xe8bc94}, /* U+8F14 */ + {0xcae6, 0xe7a982}, /* U+7A42 */ + {0xcae7, 0xe58b9f}, /* U+52DF */ + {0xcae8, 0xe5a293}, /* U+5893 */ + {0xcae9, 0xe68595}, /* U+6155 */ + {0xcaea, 0xe6888a}, /* U+620A */ + {0xcaeb, 0xe69aae}, /* U+66AE */ + {0xcaec, 0xe6af8d}, /* U+6BCD */ + {0xcaed, 0xe7b0bf}, /* U+7C3F */ + {0xcaee, 0xe88fa9}, /* U+83E9 */ + {0xcaef, 0xe580a3}, /* U+5023 */ + {0xcaf0, 0xe4bfb8}, /* U+4FF8 */ + {0xcaf1, 0xe58c85}, /* U+5305 */ + {0xcaf2, 0xe59186}, /* U+5446 */ + {0xcaf3, 0xe5a0b1}, /* U+5831 */ + {0xcaf4, 0xe5a589}, /* U+5949 */ + {0xcaf5, 0xe5ae9d}, /* U+5B9D */ + {0xcaf6, 0xe5b3b0}, /* U+5CF0 */ + {0xcaf7, 0xe5b3af}, /* U+5CEF */ + {0xcaf8, 0xe5b4a9}, /* U+5D29 */ + {0xcaf9, 0xe5ba96}, /* U+5E96 */ + {0xcafa, 0xe68ab1}, /* U+62B1 */ + {0xcafb, 0xe68da7}, /* U+6367 */ + {0xcafc, 0xe694be}, /* U+653E */ + {0xcafd, 0xe696b9}, /* U+65B9 */ + {0xcafe, 0xe69c8b}, /* U+670B */ + {0xcba1, 0xe6b395}, /* U+6CD5 */ + {0xcba2, 0xe6b3a1}, /* U+6CE1 */ + {0xcba3, 0xe783b9}, /* U+70F9 */ + {0xcba4, 0xe7a0b2}, /* U+7832 */ + {0xcba5, 0xe7b8ab}, /* U+7E2B */ + {0xcba6, 0xe8839e}, /* U+80DE */ + {0xcba7, 0xe88ab3}, /* U+82B3 */ + {0xcba8, 0xe8908c}, /* U+840C */ + {0xcba9, 0xe893ac}, /* U+84EC */ + {0xcbaa, 0xe89c82}, /* U+8702 */ + {0xcbab, 0xe8a492}, /* U+8912 */ + {0xcbac, 0xe8a8aa}, /* U+8A2A */ + {0xcbad, 0xe8b18a}, /* U+8C4A */ + {0xcbae, 0xe982a6}, /* U+90A6 */ + {0xcbaf, 0xe98b92}, /* U+92D2 */ + {0xcbb0, 0xe9a3bd}, /* U+98FD */ + {0xcbb1, 0xe9b3b3}, /* U+9CF3 */ + {0xcbb2, 0xe9b5ac}, /* U+9D6C */ + {0xcbb3, 0xe4b98f}, /* U+4E4F */ + {0xcbb4, 0xe4baa1}, /* U+4EA1 */ + {0xcbb5, 0xe5828d}, /* U+508D */ + {0xcbb6, 0xe58996}, /* U+5256 */ + {0xcbb7, 0xe59d8a}, /* U+574A */ + {0xcbb8, 0xe5a6a8}, /* U+59A8 */ + {0xcbb9, 0xe5b8bd}, /* U+5E3D */ + {0xcbba, 0xe5bf98}, /* U+5FD8 */ + {0xcbbb, 0xe5bf99}, /* U+5FD9 */ + {0xcbbc, 0xe688bf}, /* U+623F */ + {0xcbbd, 0xe69ab4}, /* U+66B4 */ + {0xcbbe, 0xe69c9b}, /* U+671B */ + {0xcbbf, 0xe69f90}, /* U+67D0 */ + {0xcbc0, 0xe6a392}, /* U+68D2 */ + {0xcbc1, 0xe58692}, /* U+5192 */ + {0xcbc2, 0xe7b4a1}, /* U+7D21 */ + {0xcbc3, 0xe882aa}, /* U+80AA */ + {0xcbc4, 0xe886a8}, /* U+81A8 */ + {0xcbc5, 0xe8ac80}, /* U+8B00 */ + {0xcbc6, 0xe8b28c}, /* U+8C8C */ + {0xcbc7, 0xe8b2bf}, /* U+8CBF */ + {0xcbc8, 0xe989be}, /* U+927E */ + {0xcbc9, 0xe998b2}, /* U+9632 */ + {0xcbca, 0xe590a0}, /* U+5420 */ + {0xcbcb, 0xe9a0ac}, /* U+982C */ + {0xcbcc, 0xe58c97}, /* U+5317 */ + {0xcbcd, 0xe58395}, /* U+50D5 */ + {0xcbce, 0xe58d9c}, /* U+535C */ + {0xcbcf, 0xe5a2a8}, /* U+58A8 */ + {0xcbd0, 0xe692b2}, /* U+64B2 */ + {0xcbd1, 0xe69cb4}, /* U+6734 */ + {0xcbd2, 0xe789a7}, /* U+7267 */ + {0xcbd3, 0xe79da6}, /* U+7766 */ + {0xcbd4, 0xe7a986}, /* U+7A46 */ + {0xcbd5, 0xe987a6}, /* U+91E6 */ + {0xcbd6, 0xe58b83}, /* U+52C3 */ + {0xcbd7, 0xe6b2a1}, /* U+6CA1 */ + {0xcbd8, 0xe6ae86}, /* U+6B86 */ + {0xcbd9, 0xe5a080}, /* U+5800 */ + {0xcbda, 0xe5b98c}, /* U+5E4C */ + {0xcbdb, 0xe5a594}, /* U+5954 */ + {0xcbdc, 0xe69cac}, /* U+672C */ + {0xcbdd, 0xe7bfbb}, /* U+7FFB */ + {0xcbde, 0xe587a1}, /* U+51E1 */ + {0xcbdf, 0xe79b86}, /* U+76C6 */ + {0xcbe0, 0xe691a9}, /* U+6469 */ + {0xcbe1, 0xe7a3a8}, /* U+78E8 */ + {0xcbe2, 0xe9ad94}, /* U+9B54 */ + {0xcbe3, 0xe9babb}, /* U+9EBB */ + {0xcbe4, 0xe59f8b}, /* U+57CB */ + {0xcbe5, 0xe5a6b9}, /* U+59B9 */ + {0xcbe6, 0xe698a7}, /* U+6627 */ + {0xcbe7, 0xe69e9a}, /* U+679A */ + {0xcbe8, 0xe6af8e}, /* U+6BCE */ + {0xcbe9, 0xe593a9}, /* U+54E9 */ + {0xcbea, 0xe6a799}, /* U+69D9 */ + {0xcbeb, 0xe5b995}, /* U+5E55 */ + {0xcbec, 0xe8869c}, /* U+819C */ + {0xcbed, 0xe69e95}, /* U+6795 */ + {0xcbee, 0xe9aeaa}, /* U+9BAA */ + {0xcbef, 0xe69fbe}, /* U+67FE */ + {0xcbf0, 0xe9b192}, /* U+9C52 */ + {0xcbf1, 0xe6a19d}, /* U+685D */ + {0xcbf2, 0xe4baa6}, /* U+4EA6 */ + {0xcbf3, 0xe4bfa3}, /* U+4FE3 */ + {0xcbf4, 0xe58f88}, /* U+53C8 */ + {0xcbf5, 0xe68ab9}, /* U+62B9 */ + {0xcbf6, 0xe69cab}, /* U+672B */ + {0xcbf7, 0xe6b2ab}, /* U+6CAB */ + {0xcbf8, 0xe8bf84}, /* U+8FC4 */ + {0xcbf9, 0xe4bead}, /* U+4FAD */ + {0xcbfa, 0xe7b9ad}, /* U+7E6D */ + {0xcbfb, 0xe9babf}, /* U+9EBF */ + {0xcbfc, 0xe4b887}, /* U+4E07 */ + {0xcbfd, 0xe685a2}, /* U+6162 */ + {0xcbfe, 0xe6ba80}, /* U+6E80 */ + {0xcca1, 0xe6bcab}, /* U+6F2B */ + {0xcca2, 0xe89493}, /* U+8513 */ + {0xcca3, 0xe591b3}, /* U+5473 */ + {0xcca4, 0xe69caa}, /* U+672A */ + {0xcca5, 0xe9ad85}, /* U+9B45 */ + {0xcca6, 0xe5b7b3}, /* U+5DF3 */ + {0xcca7, 0xe7ae95}, /* U+7B95 */ + {0xcca8, 0xe5b2ac}, /* U+5CAC */ + {0xcca9, 0xe5af86}, /* U+5BC6 */ + {0xccaa, 0xe89c9c}, /* U+871C */ + {0xccab, 0xe6b98a}, /* U+6E4A */ + {0xccac, 0xe89391}, /* U+84D1 */ + {0xccad, 0xe7a894}, /* U+7A14 */ + {0xccae, 0xe88488}, /* U+8108 */ + {0xccaf, 0xe5a699}, /* U+5999 */ + {0xccb0, 0xe7b28d}, /* U+7C8D */ + {0xccb1, 0xe6b091}, /* U+6C11 */ + {0xccb2, 0xe79ca0}, /* U+7720 */ + {0xccb3, 0xe58b99}, /* U+52D9 */ + {0xccb4, 0xe5a4a2}, /* U+5922 */ + {0xccb5, 0xe784a1}, /* U+7121 */ + {0xccb6, 0xe7899f}, /* U+725F */ + {0xccb7, 0xe79f9b}, /* U+77DB */ + {0xccb8, 0xe99ca7}, /* U+9727 */ + {0xccb9, 0xe9b5a1}, /* U+9D61 */ + {0xccba, 0xe6a48b}, /* U+690B */ + {0xccbb, 0xe5a9bf}, /* U+5A7F */ + {0xccbc, 0xe5a898}, /* U+5A18 */ + {0xccbd, 0xe586a5}, /* U+51A5 */ + {0xccbe, 0xe5908d}, /* U+540D */ + {0xccbf, 0xe591bd}, /* U+547D */ + {0xccc0, 0xe6988e}, /* U+660E */ + {0xccc1, 0xe79b9f}, /* U+76DF */ + {0xccc2, 0xe8bfb7}, /* U+8FF7 */ + {0xccc3, 0xe98a98}, /* U+9298 */ + {0xccc4, 0xe9b3b4}, /* U+9CF4 */ + {0xccc5, 0xe5a7aa}, /* U+59EA */ + {0xccc6, 0xe7899d}, /* U+725D */ + {0xccc7, 0xe6bb85}, /* U+6EC5 */ + {0xccc8, 0xe5858d}, /* U+514D */ + {0xccc9, 0xe6a389}, /* U+68C9 */ + {0xccca, 0xe7b6bf}, /* U+7DBF */ + {0xcccb, 0xe7b7ac}, /* U+7DEC */ + {0xcccc, 0xe99da2}, /* U+9762 */ + {0xcccd, 0xe9baba}, /* U+9EBA */ + {0xccce, 0xe691b8}, /* U+6478 */ + {0xcccf, 0xe6a8a1}, /* U+6A21 */ + {0xccd0, 0xe88c82}, /* U+8302 */ + {0xccd1, 0xe5a684}, /* U+5984 */ + {0xccd2, 0xe5ad9f}, /* U+5B5F */ + {0xccd3, 0xe6af9b}, /* U+6BDB */ + {0xccd4, 0xe78c9b}, /* U+731B */ + {0xccd5, 0xe79bb2}, /* U+76F2 */ + {0xccd6, 0xe7b6b2}, /* U+7DB2 */ + {0xccd7, 0xe88097}, /* U+8017 */ + {0xccd8, 0xe89299}, /* U+8499 */ + {0xccd9, 0xe584b2}, /* U+5132 */ + {0xccda, 0xe69ca8}, /* U+6728 */ + {0xccdb, 0xe9bb99}, /* U+9ED9 */ + {0xccdc, 0xe79bae}, /* U+76EE */ + {0xccdd, 0xe69da2}, /* U+6762 */ + {0xccde, 0xe58bbf}, /* U+52FF */ + {0xccdf, 0xe9a485}, /* U+9905 */ + {0xcce0, 0xe5b0a4}, /* U+5C24 */ + {0xcce1, 0xe688bb}, /* U+623B */ + {0xcce2, 0xe7b1be}, /* U+7C7E */ + {0xcce3, 0xe8b2b0}, /* U+8CB0 */ + {0xcce4, 0xe5958f}, /* U+554F */ + {0xcce5, 0xe682b6}, /* U+60B6 */ + {0xcce6, 0xe7b48b}, /* U+7D0B */ + {0xcce7, 0xe99680}, /* U+9580 */ + {0xcce8, 0xe58c81}, /* U+5301 */ + {0xcce9, 0xe4b99f}, /* U+4E5F */ + {0xccea, 0xe586b6}, /* U+51B6 */ + {0xcceb, 0xe5a49c}, /* U+591C */ + {0xccec, 0xe788ba}, /* U+723A */ + {0xcced, 0xe880b6}, /* U+8036 */ + {0xccee, 0xe9878e}, /* U+91CE */ + {0xccef, 0xe5bca5}, /* U+5F25 */ + {0xccf0, 0xe79fa2}, /* U+77E2 */ + {0xccf1, 0xe58e84}, /* U+5384 */ + {0xccf2, 0xe5bdb9}, /* U+5F79 */ + {0xccf3, 0xe7b484}, /* U+7D04 */ + {0xccf4, 0xe896ac}, /* U+85AC */ + {0xccf5, 0xe8a8b3}, /* U+8A33 */ + {0xccf6, 0xe8ba8d}, /* U+8E8D */ + {0xccf7, 0xe99d96}, /* U+9756 */ + {0xccf8, 0xe69fb3}, /* U+67F3 */ + {0xccf9, 0xe896ae}, /* U+85AE */ + {0xccfa, 0xe99193}, /* U+9453 */ + {0xccfb, 0xe68489}, /* U+6109 */ + {0xccfc, 0xe68488}, /* U+6108 */ + {0xccfd, 0xe6b2b9}, /* U+6CB9 */ + {0xccfe, 0xe79992}, /* U+7652 */ + {0xcda1, 0xe8abad}, /* U+8AED */ + {0xcda2, 0xe8bcb8}, /* U+8F38 */ + {0xcda3, 0xe594af}, /* U+552F */ + {0xcda4, 0xe4bd91}, /* U+4F51 */ + {0xcda5, 0xe584aa}, /* U+512A */ + {0xcda6, 0xe58b87}, /* U+52C7 */ + {0xcda7, 0xe58f8b}, /* U+53CB */ + {0xcda8, 0xe5aea5}, /* U+5BA5 */ + {0xcda9, 0xe5b9bd}, /* U+5E7D */ + {0xcdaa, 0xe682a0}, /* U+60A0 */ + {0xcdab, 0xe68682}, /* U+6182 */ + {0xcdac, 0xe68f96}, /* U+63D6 */ + {0xcdad, 0xe69c89}, /* U+6709 */ + {0xcdae, 0xe69f9a}, /* U+67DA */ + {0xcdaf, 0xe6b9a7}, /* U+6E67 */ + {0xcdb0, 0xe6b68c}, /* U+6D8C */ + {0xcdb1, 0xe78cb6}, /* U+7336 */ + {0xcdb2, 0xe78cb7}, /* U+7337 */ + {0xcdb3, 0xe794b1}, /* U+7531 */ + {0xcdb4, 0xe7a590}, /* U+7950 */ + {0xcdb5, 0xe8a395}, /* U+88D5 */ + {0xcdb6, 0xe8aa98}, /* U+8A98 */ + {0xcdb7, 0xe9818a}, /* U+904A */ + {0xcdb8, 0xe98291}, /* U+9091 */ + {0xcdb9, 0xe983b5}, /* U+90F5 */ + {0xcdba, 0xe99b84}, /* U+96C4 */ + {0xcdbb, 0xe89e8d}, /* U+878D */ + {0xcdbc, 0xe5a495}, /* U+5915 */ + {0xcdbd, 0xe4ba88}, /* U+4E88 */ + {0xcdbe, 0xe4bd99}, /* U+4F59 */ + {0xcdbf, 0xe4b88e}, /* U+4E0E */ + {0xcdc0, 0xe8aa89}, /* U+8A89 */ + {0xcdc1, 0xe8bcbf}, /* U+8F3F */ + {0xcdc2, 0xe9a090}, /* U+9810 */ + {0xcdc3, 0xe582ad}, /* U+50AD */ + {0xcdc4, 0xe5b9bc}, /* U+5E7C */ + {0xcdc5, 0xe5a696}, /* U+5996 */ + {0xcdc6, 0xe5aeb9}, /* U+5BB9 */ + {0xcdc7, 0xe5bab8}, /* U+5EB8 */ + {0xcdc8, 0xe68f9a}, /* U+63DA */ + {0xcdc9, 0xe68fba}, /* U+63FA */ + {0xcdca, 0xe69381}, /* U+64C1 */ + {0xcdcb, 0xe69b9c}, /* U+66DC */ + {0xcdcc, 0xe6a58a}, /* U+694A */ + {0xcdcd, 0xe6a798}, /* U+69D8 */ + {0xcdce, 0xe6b48b}, /* U+6D0B */ + {0xcdcf, 0xe6bab6}, /* U+6EB6 */ + {0xcdd0, 0xe78694}, /* U+7194 */ + {0xcdd1, 0xe794a8}, /* U+7528 */ + {0xcdd2, 0xe7aaaf}, /* U+7AAF */ + {0xcdd3, 0xe7be8a}, /* U+7F8A */ + {0xcdd4, 0xe88080}, /* U+8000 */ + {0xcdd5, 0xe89189}, /* U+8449 */ + {0xcdd6, 0xe89389}, /* U+84C9 */ + {0xcdd7, 0xe8a681}, /* U+8981 */ + {0xcdd8, 0xe8aca1}, /* U+8B21 */ + {0xcdd9, 0xe8b88a}, /* U+8E0A */ + {0xcdda, 0xe981a5}, /* U+9065 */ + {0xcddb, 0xe999bd}, /* U+967D */ + {0xcddc, 0xe9a48a}, /* U+990A */ + {0xcddd, 0xe685be}, /* U+617E */ + {0xcdde, 0xe68a91}, /* U+6291 */ + {0xcddf, 0xe6acb2}, /* U+6B32 */ + {0xcde0, 0xe6b283}, /* U+6C83 */ + {0xcde1, 0xe6b5b4}, /* U+6D74 */ + {0xcde2, 0xe7bf8c}, /* U+7FCC */ + {0xcde3, 0xe7bfbc}, /* U+7FFC */ + {0xcde4, 0xe6b780}, /* U+6DC0 */ + {0xcde5, 0xe7be85}, /* U+7F85 */ + {0xcde6, 0xe89eba}, /* U+87BA */ + {0xcde7, 0xe8a3b8}, /* U+88F8 */ + {0xcde8, 0xe69da5}, /* U+6765 */ + {0xcde9, 0xe88eb1}, /* U+83B1 */ + {0xcdea, 0xe9a0bc}, /* U+983C */ + {0xcdeb, 0xe99bb7}, /* U+96F7 */ + {0xcdec, 0xe6b49b}, /* U+6D1B */ + {0xcded, 0xe7b5a1}, /* U+7D61 */ + {0xcdee, 0xe890bd}, /* U+843D */ + {0xcdef, 0xe985aa}, /* U+916A */ + {0xcdf0, 0xe4b9b1}, /* U+4E71 */ + {0xcdf1, 0xe58db5}, /* U+5375 */ + {0xcdf2, 0xe5b590}, /* U+5D50 */ + {0xcdf3, 0xe6ac84}, /* U+6B04 */ + {0xcdf4, 0xe6bfab}, /* U+6FEB */ + {0xcdf5, 0xe8978d}, /* U+85CD */ + {0xcdf6, 0xe898ad}, /* U+862D */ + {0xcdf7, 0xe8a6a7}, /* U+89A7 */ + {0xcdf8, 0xe588a9}, /* U+5229 */ + {0xcdf9, 0xe5908f}, /* U+540F */ + {0xcdfa, 0xe5b1a5}, /* U+5C65 */ + {0xcdfb, 0xe69d8e}, /* U+674E */ + {0xcdfc, 0xe6a2a8}, /* U+68A8 */ + {0xcdfd, 0xe79086}, /* U+7406 */ + {0xcdfe, 0xe79283}, /* U+7483 */ + {0xcea1, 0xe797a2}, /* U+75E2 */ + {0xcea2, 0xe8a38f}, /* U+88CF */ + {0xcea3, 0xe8a3a1}, /* U+88E1 */ + {0xcea4, 0xe9878c}, /* U+91CC */ + {0xcea5, 0xe99ba2}, /* U+96E2 */ + {0xcea6, 0xe999b8}, /* U+9678 */ + {0xcea7, 0xe5be8b}, /* U+5F8B */ + {0xcea8, 0xe78e87}, /* U+7387 */ + {0xcea9, 0xe7ab8b}, /* U+7ACB */ + {0xceaa, 0xe8918e}, /* U+844E */ + {0xceab, 0xe68ea0}, /* U+63A0 */ + {0xceac, 0xe795a5}, /* U+7565 */ + {0xcead, 0xe58a89}, /* U+5289 */ + {0xceae, 0xe6b581}, /* U+6D41 */ + {0xceaf, 0xe6ba9c}, /* U+6E9C */ + {0xceb0, 0xe79089}, /* U+7409 */ + {0xceb1, 0xe79599}, /* U+7559 */ + {0xceb2, 0xe7a1ab}, /* U+786B */ + {0xceb3, 0xe7b292}, /* U+7C92 */ + {0xceb4, 0xe99a86}, /* U+9686 */ + {0xceb5, 0xe7ab9c}, /* U+7ADC */ + {0xceb6, 0xe9be8d}, /* U+9F8D */ + {0xceb7, 0xe4beb6}, /* U+4FB6 */ + {0xceb8, 0xe685ae}, /* U+616E */ + {0xceb9, 0xe69785}, /* U+65C5 */ + {0xceba, 0xe8999c}, /* U+865C */ + {0xcebb, 0xe4ba86}, /* U+4E86 */ + {0xcebc, 0xe4baae}, /* U+4EAE */ + {0xcebd, 0xe5839a}, /* U+50DA */ + {0xcebe, 0xe4b8a1}, /* U+4E21 */ + {0xcebf, 0xe5878c}, /* U+51CC */ + {0xcec0, 0xe5afae}, /* U+5BEE */ + {0xcec1, 0xe69699}, /* U+6599 */ + {0xcec2, 0xe6a281}, /* U+6881 */ + {0xcec3, 0xe6b6bc}, /* U+6DBC */ + {0xcec4, 0xe78c9f}, /* U+731F */ + {0xcec5, 0xe79982}, /* U+7642 */ + {0xcec6, 0xe79ead}, /* U+77AD */ + {0xcec7, 0xe7a89c}, /* U+7A1C */ + {0xcec8, 0xe7b3a7}, /* U+7CE7 */ + {0xcec9, 0xe889af}, /* U+826F */ + {0xceca, 0xe8ab92}, /* U+8AD2 */ + {0xcecb, 0xe981bc}, /* U+907C */ + {0xcecc, 0xe9878f}, /* U+91CF */ + {0xcecd, 0xe999b5}, /* U+9675 */ + {0xcece, 0xe9a098}, /* U+9818 */ + {0xcecf, 0xe58a9b}, /* U+529B */ + {0xced0, 0xe7b791}, /* U+7DD1 */ + {0xced1, 0xe580ab}, /* U+502B */ + {0xced2, 0xe58e98}, /* U+5398 */ + {0xced3, 0xe69e97}, /* U+6797 */ + {0xced4, 0xe6b78b}, /* U+6DCB */ + {0xced5, 0xe78790}, /* U+71D0 */ + {0xced6, 0xe790b3}, /* U+7433 */ + {0xced7, 0xe887a8}, /* U+81E8 */ + {0xced8, 0xe8bcaa}, /* U+8F2A */ + {0xced9, 0xe99aa3}, /* U+96A3 */ + {0xceda, 0xe9b197}, /* U+9C57 */ + {0xcedb, 0xe9ba9f}, /* U+9E9F */ + {0xcedc, 0xe791a0}, /* U+7460 */ + {0xcedd, 0xe5a181}, /* U+5841 */ + {0xcede, 0xe6b699}, /* U+6D99 */ + {0xcedf, 0xe7b4af}, /* U+7D2F */ + {0xcee0, 0xe9a19e}, /* U+985E */ + {0xcee1, 0xe4bba4}, /* U+4EE4 */ + {0xcee2, 0xe4bcb6}, /* U+4F36 */ + {0xcee3, 0xe4be8b}, /* U+4F8B */ + {0xcee4, 0xe586b7}, /* U+51B7 */ + {0xcee5, 0xe58ab1}, /* U+52B1 */ + {0xcee6, 0xe5b6ba}, /* U+5DBA */ + {0xcee7, 0xe6809c}, /* U+601C */ + {0xcee8, 0xe78eb2}, /* U+73B2 */ + {0xcee9, 0xe7a4bc}, /* U+793C */ + {0xceea, 0xe88b93}, /* U+82D3 */ + {0xceeb, 0xe988b4}, /* U+9234 */ + {0xceec, 0xe99ab7}, /* U+96B7 */ + {0xceed, 0xe99bb6}, /* U+96F6 */ + {0xceee, 0xe99c8a}, /* U+970A */ + {0xceef, 0xe9ba97}, /* U+9E97 */ + {0xcef0, 0xe9bda2}, /* U+9F62 */ + {0xcef1, 0xe69aa6}, /* U+66A6 */ + {0xcef2, 0xe6adb4}, /* U+6B74 */ + {0xcef3, 0xe58897}, /* U+5217 */ + {0xcef4, 0xe58aa3}, /* U+52A3 */ + {0xcef5, 0xe78388}, /* U+70C8 */ + {0xcef6, 0xe8a382}, /* U+88C2 */ + {0xcef7, 0xe5bb89}, /* U+5EC9 */ + {0xcef8, 0xe6818b}, /* U+604B */ + {0xcef9, 0xe68690}, /* U+6190 */ + {0xcefa, 0xe6bca3}, /* U+6F23 */ + {0xcefb, 0xe78589}, /* U+7149 */ + {0xcefc, 0xe7b0be}, /* U+7C3E */ + {0xcefd, 0xe7b7b4}, /* U+7DF4 */ + {0xcefe, 0xe881af}, /* U+806F */ + {0xcfa1, 0xe893ae}, /* U+84EE */ + {0xcfa2, 0xe980a3}, /* U+9023 */ + {0xcfa3, 0xe98cac}, /* U+932C */ + {0xcfa4, 0xe59182}, /* U+5442 */ + {0xcfa5, 0xe9adaf}, /* U+9B6F */ + {0xcfa6, 0xe6ab93}, /* U+6AD3 */ + {0xcfa7, 0xe78289}, /* U+7089 */ + {0xcfa8, 0xe8b382}, /* U+8CC2 */ + {0xcfa9, 0xe8b7af}, /* U+8DEF */ + {0xcfaa, 0xe99cb2}, /* U+9732 */ + {0xcfab, 0xe58ab4}, /* U+52B4 */ + {0xcfac, 0xe5a981}, /* U+5A41 */ + {0xcfad, 0xe5bb8a}, /* U+5ECA */ + {0xcfae, 0xe5bc84}, /* U+5F04 */ + {0xcfaf, 0xe69c97}, /* U+6717 */ + {0xcfb0, 0xe6a5bc}, /* U+697C */ + {0xcfb1, 0xe6a694}, /* U+6994 */ + {0xcfb2, 0xe6b5aa}, /* U+6D6A */ + {0xcfb3, 0xe6bc8f}, /* U+6F0F */ + {0xcfb4, 0xe789a2}, /* U+7262 */ + {0xcfb5, 0xe78bbc}, /* U+72FC */ + {0xcfb6, 0xe7afad}, /* U+7BED */ + {0xcfb7, 0xe88081}, /* U+8001 */ + {0xcfb8, 0xe881be}, /* U+807E */ + {0xcfb9, 0xe89d8b}, /* U+874B */ + {0xcfba, 0xe9838e}, /* U+90CE */ + {0xcfbb, 0xe585ad}, /* U+516D */ + {0xcfbc, 0xe9ba93}, /* U+9E93 */ + {0xcfbd, 0xe7a684}, /* U+7984 */ + {0xcfbe, 0xe8828b}, /* U+808B */ + {0xcfbf, 0xe98cb2}, /* U+9332 */ + {0xcfc0, 0xe8ab96}, /* U+8AD6 */ + {0xcfc1, 0xe580ad}, /* U+502D */ + {0xcfc2, 0xe5928c}, /* U+548C */ + {0xcfc3, 0xe8a9b1}, /* U+8A71 */ + {0xcfc4, 0xe6adaa}, /* U+6B6A */ + {0xcfc5, 0xe8b384}, /* U+8CC4 */ + {0xcfc6, 0xe88487}, /* U+8107 */ + {0xcfc7, 0xe68391}, /* U+60D1 */ + {0xcfc8, 0xe69ea0}, /* U+67A0 */ + {0xcfc9, 0xe9b7b2}, /* U+9DF2 */ + {0xcfca, 0xe4ba99}, /* U+4E99 */ + {0xcfcb, 0xe4ba98}, /* U+4E98 */ + {0xcfcc, 0xe9b090}, /* U+9C10 */ + {0xcfcd, 0xe8a9ab}, /* U+8A6B */ + {0xcfce, 0xe89781}, /* U+85C1 */ + {0xcfcf, 0xe895a8}, /* U+8568 */ + {0xcfd0, 0xe6a480}, /* U+6900 */ + {0xcfd1, 0xe6b9be}, /* U+6E7E */ + {0xcfd2, 0xe7a297}, /* U+7897 */ + {0xcfd3, 0xe88595}, /* U+8155 */ + {0xcfd4, 0xf0a0ae9f}, /* U+20B9F [2004] [Unicode3.1] */ + {0xcfd5, 0xe5ad81}, /* U+5B41 [2000] */ + {0xcfd6, 0xe5ad96}, /* U+5B56 [2000] */ + {0xcfd7, 0xe5adbd}, /* U+5B7D [2000] */ + {0xcfd8, 0xe5ae93}, /* U+5B93 [2000] */ + {0xcfd9, 0xe5af98}, /* U+5BD8 [2000] */ + {0xcfda, 0xe5afac}, /* U+5BEC [2000] */ + {0xcfdb, 0xe5b092}, /* U+5C12 [2000] */ + {0xcfdc, 0xe5b09e}, /* U+5C1E [2000] */ + {0xcfdd, 0xe5b0a3}, /* U+5C23 [2000] */ + {0xcfde, 0xe5b0ab}, /* U+5C2B [2000] */ + {0xcfdf, 0xe39e8d}, /* U+378D [2000] */ + {0xcfe0, 0xe5b1a2}, /* U+5C62 [2000] */ + {0xcfe1, 0xefa8bb}, /* U+FA3B CJK COMPATIBILITY IDEOGRAPH-FA3B [2000] [Unicode3.2] */ + {0xcfe2, 0xefa8bc}, /* U+FA3C CJK COMPATIBILITY IDEOGRAPH-FA3C [2000] [Unicode3.2] */ + {0xcfe3, 0xf0a19ab4}, /* U+216B4 [2000] [Unicode3.1] */ + {0xcfe4, 0xe5b1ba}, /* U+5C7A [2000] */ + {0xcfe5, 0xe5b28f}, /* U+5C8F [2000] */ + {0xcfe6, 0xe5b29f}, /* U+5C9F [2000] */ + {0xcfe7, 0xe5b2a3}, /* U+5CA3 [2000] */ + {0xcfe8, 0xe5b2aa}, /* U+5CAA [2000] */ + {0xcfe9, 0xe5b2ba}, /* U+5CBA [2000] */ + {0xcfea, 0xe5b38b}, /* U+5CCB [2000] */ + {0xcfeb, 0xe5b390}, /* U+5CD0 [2000] */ + {0xcfec, 0xe5b392}, /* U+5CD2 [2000] */ + {0xcfed, 0xe5b3b4}, /* U+5CF4 [2000] */ + {0xcfee, 0xf0a1b8b4}, /* U+21E34 [2000] [Unicode3.1] */ + {0xcfef, 0xe39fa2}, /* U+37E2 [2000] */ + {0xcff0, 0xe5b48d}, /* U+5D0D [2000] */ + {0xcff1, 0xe5b4a7}, /* U+5D27 [2000] */ + {0xcff2, 0xefa891}, /* U+FA11 CJK COMPATIBILITY IDEOGRAPH-FA11 [2000] */ + {0xcff3, 0xe5b586}, /* U+5D46 [2000] */ + {0xcff4, 0xe5b587}, /* U+5D47 [2000] */ + {0xcff5, 0xe5b593}, /* U+5D53 [2000] */ + {0xcff6, 0xe5b58a}, /* U+5D4A [2000] */ + {0xcff7, 0xe5b5ad}, /* U+5D6D [2000] */ + {0xcff8, 0xe5b681}, /* U+5D81 [2000] */ + {0xcff9, 0xe5b6a0}, /* U+5DA0 [2000] */ + {0xcffa, 0xe5b6a4}, /* U+5DA4 [2000] */ + {0xcffb, 0xe5b6a7}, /* U+5DA7 [2000] */ + {0xcffc, 0xe5b6b8}, /* U+5DB8 [2000] */ + {0xcffd, 0xe5b78b}, /* U+5DCB [2000] */ + {0xcffe, 0xe5909e}, /* U+541E [2004] */ + {0xd0a1, 0xe5bc8c}, /* U+5F0C */ + {0xd0a2, 0xe4b890}, /* U+4E10 */ + {0xd0a3, 0xe4b895}, /* U+4E15 */ + {0xd0a4, 0xe4b8aa}, /* U+4E2A */ + {0xd0a5, 0xe4b8b1}, /* U+4E31 */ + {0xd0a6, 0xe4b8b6}, /* U+4E36 */ + {0xd0a7, 0xe4b8bc}, /* U+4E3C */ + {0xd0a8, 0xe4b8bf}, /* U+4E3F */ + {0xd0a9, 0xe4b982}, /* U+4E42 */ + {0xd0aa, 0xe4b996}, /* U+4E56 */ + {0xd0ab, 0xe4b998}, /* U+4E58 */ + {0xd0ac, 0xe4ba82}, /* U+4E82 */ + {0xd0ad, 0xe4ba85}, /* U+4E85 */ + {0xd0ae, 0xe8b1ab}, /* U+8C6B */ + {0xd0af, 0xe4ba8a}, /* U+4E8A */ + {0xd0b0, 0xe88892}, /* U+8212 */ + {0xd0b1, 0xe5bc8d}, /* U+5F0D */ + {0xd0b2, 0xe4ba8e}, /* U+4E8E */ + {0xd0b3, 0xe4ba9e}, /* U+4E9E */ + {0xd0b4, 0xe4ba9f}, /* U+4E9F */ + {0xd0b5, 0xe4baa0}, /* U+4EA0 */ + {0xd0b6, 0xe4baa2}, /* U+4EA2 */ + {0xd0b7, 0xe4bab0}, /* U+4EB0 */ + {0xd0b8, 0xe4bab3}, /* U+4EB3 */ + {0xd0b9, 0xe4bab6}, /* U+4EB6 */ + {0xd0ba, 0xe4bb8e}, /* U+4ECE */ + {0xd0bb, 0xe4bb8d}, /* U+4ECD */ + {0xd0bc, 0xe4bb84}, /* U+4EC4 */ + {0xd0bd, 0xe4bb86}, /* U+4EC6 */ + {0xd0be, 0xe4bb82}, /* U+4EC2 */ + {0xd0bf, 0xe4bb97}, /* U+4ED7 */ + {0xd0c0, 0xe4bb9e}, /* U+4EDE */ + {0xd0c1, 0xe4bbad}, /* U+4EED */ + {0xd0c2, 0xe4bb9f}, /* U+4EDF */ + {0xd0c3, 0xe4bbb7}, /* U+4EF7 */ + {0xd0c4, 0xe4bc89}, /* U+4F09 */ + {0xd0c5, 0xe4bd9a}, /* U+4F5A */ + {0xd0c6, 0xe4bcb0}, /* U+4F30 */ + {0xd0c7, 0xe4bd9b}, /* U+4F5B */ + {0xd0c8, 0xe4bd9d}, /* U+4F5D */ + {0xd0c9, 0xe4bd97}, /* U+4F57 */ + {0xd0ca, 0xe4bd87}, /* U+4F47 */ + {0xd0cb, 0xe4bdb6}, /* U+4F76 */ + {0xd0cc, 0xe4be88}, /* U+4F88 */ + {0xd0cd, 0xe4be8f}, /* U+4F8F */ + {0xd0ce, 0xe4be98}, /* U+4F98 */ + {0xd0cf, 0xe4bdbb}, /* U+4F7B */ + {0xd0d0, 0xe4bda9}, /* U+4F69 */ + {0xd0d1, 0xe4bdb0}, /* U+4F70 */ + {0xd0d2, 0xe4be91}, /* U+4F91 */ + {0xd0d3, 0xe4bdaf}, /* U+4F6F */ + {0xd0d4, 0xe4be86}, /* U+4F86 */ + {0xd0d5, 0xe4be96}, /* U+4F96 */ + {0xd0d6, 0xe58498}, /* U+5118 */ + {0xd0d7, 0xe4bf94}, /* U+4FD4 */ + {0xd0d8, 0xe4bf9f}, /* U+4FDF */ + {0xd0d9, 0xe4bf8e}, /* U+4FCE */ + {0xd0da, 0xe4bf98}, /* U+4FD8 */ + {0xd0db, 0xe4bf9b}, /* U+4FDB */ + {0xd0dc, 0xe4bf91}, /* U+4FD1 */ + {0xd0dd, 0xe4bf9a}, /* U+4FDA */ + {0xd0de, 0xe4bf90}, /* U+4FD0 */ + {0xd0df, 0xe4bfa4}, /* U+4FE4 */ + {0xd0e0, 0xe4bfa5}, /* U+4FE5 */ + {0xd0e1, 0xe5809a}, /* U+501A */ + {0xd0e2, 0xe580a8}, /* U+5028 */ + {0xd0e3, 0xe58094}, /* U+5014 */ + {0xd0e4, 0xe580aa}, /* U+502A */ + {0xd0e5, 0xe580a5}, /* U+5025 */ + {0xd0e6, 0xe58085}, /* U+5005 */ + {0xd0e7, 0xe4bc9c}, /* U+4F1C */ + {0xd0e8, 0xe4bfb6}, /* U+4FF6 */ + {0xd0e9, 0xe580a1}, /* U+5021 */ + {0xd0ea, 0xe580a9}, /* U+5029 */ + {0xd0eb, 0xe580ac}, /* U+502C */ + {0xd0ec, 0xe4bfbe}, /* U+4FFE */ + {0xd0ed, 0xe4bfaf}, /* U+4FEF */ + {0xd0ee, 0xe58091}, /* U+5011 */ + {0xd0ef, 0xe58086}, /* U+5006 */ + {0xd0f0, 0xe58183}, /* U+5043 */ + {0xd0f1, 0xe58187}, /* U+5047 */ + {0xd0f2, 0xe69c83}, /* U+6703 */ + {0xd0f3, 0xe58195}, /* U+5055 */ + {0xd0f4, 0xe58190}, /* U+5050 */ + {0xd0f5, 0xe58188}, /* U+5048 */ + {0xd0f6, 0xe5819a}, /* U+505A */ + {0xd0f7, 0xe58196}, /* U+5056 */ + {0xd0f8, 0xe581ac}, /* U+506C */ + {0xd0f9, 0xe581b8}, /* U+5078 */ + {0xd0fa, 0xe58280}, /* U+5080 */ + {0xd0fb, 0xe5829a}, /* U+509A */ + {0xd0fc, 0xe58285}, /* U+5085 */ + {0xd0fd, 0xe582b4}, /* U+50B4 */ + {0xd0fe, 0xe582b2}, /* U+50B2 */ + {0xd1a1, 0xe58389}, /* U+50C9 */ + {0xd1a2, 0xe5838a}, /* U+50CA */ + {0xd1a3, 0xe582b3}, /* U+50B3 */ + {0xd1a4, 0xe58382}, /* U+50C2 */ + {0xd1a5, 0xe58396}, /* U+50D6 */ + {0xd1a6, 0xe5839e}, /* U+50DE */ + {0xd1a7, 0xe583a5}, /* U+50E5 */ + {0xd1a8, 0xe583ad}, /* U+50ED */ + {0xd1a9, 0xe583a3}, /* U+50E3 */ + {0xd1aa, 0xe583ae}, /* U+50EE */ + {0xd1ab, 0xe583b9}, /* U+50F9 */ + {0xd1ac, 0xe583b5}, /* U+50F5 */ + {0xd1ad, 0xe58489}, /* U+5109 */ + {0xd1ae, 0xe58481}, /* U+5101 */ + {0xd1af, 0xe58482}, /* U+5102 */ + {0xd1b0, 0xe58496}, /* U+5116 */ + {0xd1b1, 0xe58495}, /* U+5115 */ + {0xd1b2, 0xe58494}, /* U+5114 */ + {0xd1b3, 0xe5849a}, /* U+511A */ + {0xd1b4, 0xe584a1}, /* U+5121 */ + {0xd1b5, 0xe584ba}, /* U+513A */ + {0xd1b6, 0xe584b7}, /* U+5137 */ + {0xd1b7, 0xe584bc}, /* U+513C */ + {0xd1b8, 0xe584bb}, /* U+513B */ + {0xd1b9, 0xe584bf}, /* U+513F */ + {0xd1ba, 0xe58580}, /* U+5140 */ + {0xd1bb, 0xe58592}, /* U+5152 */ + {0xd1bc, 0xe5858c}, /* U+514C */ + {0xd1bd, 0xe58594}, /* U+5154 */ + {0xd1be, 0xe585a2}, /* U+5162 */ + {0xd1bf, 0xe7abb8}, /* U+7AF8 */ + {0xd1c0, 0xe585a9}, /* U+5169 */ + {0xd1c1, 0xe585aa}, /* U+516A */ + {0xd1c2, 0xe585ae}, /* U+516E */ + {0xd1c3, 0xe58680}, /* U+5180 */ + {0xd1c4, 0xe58682}, /* U+5182 */ + {0xd1c5, 0xe59b98}, /* U+56D8 */ + {0xd1c6, 0xe5868c}, /* U+518C */ + {0xd1c7, 0xe58689}, /* U+5189 */ + {0xd1c8, 0xe5868f}, /* U+518F */ + {0xd1c9, 0xe58691}, /* U+5191 */ + {0xd1ca, 0xe58693}, /* U+5193 */ + {0xd1cb, 0xe58695}, /* U+5195 */ + {0xd1cc, 0xe58696}, /* U+5196 */ + {0xd1cd, 0xe586a4}, /* U+51A4 */ + {0xd1ce, 0xe586a6}, /* U+51A6 */ + {0xd1cf, 0xe586a2}, /* U+51A2 */ + {0xd1d0, 0xe586a9}, /* U+51A9 */ + {0xd1d1, 0xe586aa}, /* U+51AA */ + {0xd1d2, 0xe586ab}, /* U+51AB */ + {0xd1d3, 0xe586b3}, /* U+51B3 */ + {0xd1d4, 0xe586b1}, /* U+51B1 */ + {0xd1d5, 0xe586b2}, /* U+51B2 */ + {0xd1d6, 0xe586b0}, /* U+51B0 */ + {0xd1d7, 0xe586b5}, /* U+51B5 */ + {0xd1d8, 0xe586bd}, /* U+51BD */ + {0xd1d9, 0xe58785}, /* U+51C5 */ + {0xd1da, 0xe58789}, /* U+51C9 */ + {0xd1db, 0xe5879b}, /* U+51DB */ + {0xd1dc, 0xe587a0}, /* U+51E0 */ + {0xd1dd, 0xe89995}, /* U+8655 */ + {0xd1de, 0xe587a9}, /* U+51E9 */ + {0xd1df, 0xe587ad}, /* U+51ED */ + {0xd1e0, 0xe587b0}, /* U+51F0 */ + {0xd1e1, 0xe587b5}, /* U+51F5 */ + {0xd1e2, 0xe587be}, /* U+51FE */ + {0xd1e3, 0xe58884}, /* U+5204 */ + {0xd1e4, 0xe5888b}, /* U+520B */ + {0xd1e5, 0xe58894}, /* U+5214 */ + {0xd1e6, 0xe5888e}, /* U+520E */ + {0xd1e7, 0xe588a7}, /* U+5227 */ + {0xd1e8, 0xe588aa}, /* U+522A */ + {0xd1e9, 0xe588ae}, /* U+522E */ + {0xd1ea, 0xe588b3}, /* U+5233 */ + {0xd1eb, 0xe588b9}, /* U+5239 */ + {0xd1ec, 0xe5898f}, /* U+524F */ + {0xd1ed, 0xe58984}, /* U+5244 */ + {0xd1ee, 0xe5898b}, /* U+524B */ + {0xd1ef, 0xe5898c}, /* U+524C */ + {0xd1f0, 0xe5899e}, /* U+525E */ + {0xd1f1, 0xe58994}, /* U+5254 */ + {0xd1f2, 0xe589aa}, /* U+526A */ + {0xd1f3, 0xe589b4}, /* U+5274 */ + {0xd1f4, 0xe589a9}, /* U+5269 */ + {0xd1f5, 0xe589b3}, /* U+5273 */ + {0xd1f6, 0xe589bf}, /* U+527F */ + {0xd1f7, 0xe589bd}, /* U+527D */ + {0xd1f8, 0xe58a8d}, /* U+528D */ + {0xd1f9, 0xe58a94}, /* U+5294 */ + {0xd1fa, 0xe58a92}, /* U+5292 */ + {0xd1fb, 0xe589b1}, /* U+5271 */ + {0xd1fc, 0xe58a88}, /* U+5288 */ + {0xd1fd, 0xe58a91}, /* U+5291 */ + {0xd1fe, 0xe8bea8}, /* U+8FA8 */ + {0xd2a1, 0xe8bea7}, /* U+8FA7 */ + {0xd2a2, 0xe58aac}, /* U+52AC */ + {0xd2a3, 0xe58aad}, /* U+52AD */ + {0xd2a4, 0xe58abc}, /* U+52BC */ + {0xd2a5, 0xe58ab5}, /* U+52B5 */ + {0xd2a6, 0xe58b81}, /* U+52C1 */ + {0xd2a7, 0xe58b8d}, /* U+52CD */ + {0xd2a8, 0xe58b97}, /* U+52D7 */ + {0xd2a9, 0xe58b9e}, /* U+52DE */ + {0xd2aa, 0xe58ba3}, /* U+52E3 */ + {0xd2ab, 0xe58ba6}, /* U+52E6 */ + {0xd2ac, 0xe9a3ad}, /* U+98ED */ + {0xd2ad, 0xe58ba0}, /* U+52E0 */ + {0xd2ae, 0xe58bb3}, /* U+52F3 */ + {0xd2af, 0xe58bb5}, /* U+52F5 */ + {0xd2b0, 0xe58bb8}, /* U+52F8 */ + {0xd2b1, 0xe58bb9}, /* U+52F9 */ + {0xd2b2, 0xe58c86}, /* U+5306 */ + {0xd2b3, 0xe58c88}, /* U+5308 */ + {0xd2b4, 0xe794b8}, /* U+7538 */ + {0xd2b5, 0xe58c8d}, /* U+530D */ + {0xd2b6, 0xe58c90}, /* U+5310 */ + {0xd2b7, 0xe58c8f}, /* U+530F */ + {0xd2b8, 0xe58c95}, /* U+5315 */ + {0xd2b9, 0xe58c9a}, /* U+531A */ + {0xd2ba, 0xe58ca3}, /* U+5323 */ + {0xd2bb, 0xe58caf}, /* U+532F */ + {0xd2bc, 0xe58cb1}, /* U+5331 */ + {0xd2bd, 0xe58cb3}, /* U+5333 */ + {0xd2be, 0xe58cb8}, /* U+5338 */ + {0xd2bf, 0xe58d80}, /* U+5340 */ + {0xd2c0, 0xe58d86}, /* U+5346 */ + {0xd2c1, 0xe58d85}, /* U+5345 */ + {0xd2c2, 0xe4b897}, /* U+4E17 */ + {0xd2c3, 0xe58d89}, /* U+5349 */ + {0xd2c4, 0xe58d8d}, /* U+534D */ + {0xd2c5, 0xe58796}, /* U+51D6 */ + {0xd2c6, 0xe58d9e}, /* U+535E */ + {0xd2c7, 0xe58da9}, /* U+5369 */ + {0xd2c8, 0xe58dae}, /* U+536E */ + {0xd2c9, 0xe5a498}, /* U+5918 */ + {0xd2ca, 0xe58dbb}, /* U+537B */ + {0xd2cb, 0xe58db7}, /* U+5377 */ + {0xd2cc, 0xe58e82}, /* U+5382 */ + {0xd2cd, 0xe58e96}, /* U+5396 */ + {0xd2ce, 0xe58ea0}, /* U+53A0 */ + {0xd2cf, 0xe58ea6}, /* U+53A6 */ + {0xd2d0, 0xe58ea5}, /* U+53A5 */ + {0xd2d1, 0xe58eae}, /* U+53AE */ + {0xd2d2, 0xe58eb0}, /* U+53B0 */ + {0xd2d3, 0xe58eb6}, /* U+53B6 */ + {0xd2d4, 0xe58f83}, /* U+53C3 */ + {0xd2d5, 0xe7b092}, /* U+7C12 */ + {0xd2d6, 0xe99b99}, /* U+96D9 */ + {0xd2d7, 0xe58f9f}, /* U+53DF */ + {0xd2d8, 0xe69bbc}, /* U+66FC */ + {0xd2d9, 0xe787ae}, /* U+71EE */ + {0xd2da, 0xe58fae}, /* U+53EE */ + {0xd2db, 0xe58fa8}, /* U+53E8 */ + {0xd2dc, 0xe58fad}, /* U+53ED */ + {0xd2dd, 0xe58fba}, /* U+53FA */ + {0xd2de, 0xe59081}, /* U+5401 */ + {0xd2df, 0xe590bd}, /* U+543D */ + {0xd2e0, 0xe59180}, /* U+5440 */ + {0xd2e1, 0xe590ac}, /* U+542C */ + {0xd2e2, 0xe590ad}, /* U+542D */ + {0xd2e3, 0xe590bc}, /* U+543C */ + {0xd2e4, 0xe590ae}, /* U+542E */ + {0xd2e5, 0xe590b6}, /* U+5436 */ + {0xd2e6, 0xe590a9}, /* U+5429 */ + {0xd2e7, 0xe5909d}, /* U+541D */ + {0xd2e8, 0xe5918e}, /* U+544E */ + {0xd2e9, 0xe5928f}, /* U+548F */ + {0xd2ea, 0xe591b5}, /* U+5475 */ + {0xd2eb, 0xe5928e}, /* U+548E */ + {0xd2ec, 0xe5919f}, /* U+545F */ + {0xd2ed, 0xe591b1}, /* U+5471 */ + {0xd2ee, 0xe591b7}, /* U+5477 */ + {0xd2ef, 0xe591b0}, /* U+5470 */ + {0xd2f0, 0xe59292}, /* U+5492 */ + {0xd2f1, 0xe591bb}, /* U+547B */ + {0xd2f2, 0xe59280}, /* U+5480 */ + {0xd2f3, 0xe591b6}, /* U+5476 */ + {0xd2f4, 0xe59284}, /* U+5484 */ + {0xd2f5, 0xe59290}, /* U+5490 */ + {0xd2f6, 0xe59286}, /* U+5486 */ + {0xd2f7, 0xe59387}, /* U+54C7 */ + {0xd2f8, 0xe592a2}, /* U+54A2 */ + {0xd2f9, 0xe592b8}, /* U+54B8 */ + {0xd2fa, 0xe592a5}, /* U+54A5 */ + {0xd2fb, 0xe592ac}, /* U+54AC */ + {0xd2fc, 0xe59384}, /* U+54C4 */ + {0xd2fd, 0xe59388}, /* U+54C8 */ + {0xd2fe, 0xe592a8}, /* U+54A8 */ + {0xd3a1, 0xe592ab}, /* U+54AB */ + {0xd3a2, 0xe59382}, /* U+54C2 */ + {0xd3a3, 0xe592a4}, /* U+54A4 */ + {0xd3a4, 0xe592be}, /* U+54BE */ + {0xd3a5, 0xe592bc}, /* U+54BC */ + {0xd3a6, 0xe59398}, /* U+54D8 */ + {0xd3a7, 0xe593a5}, /* U+54E5 */ + {0xd3a8, 0xe593a6}, /* U+54E6 */ + {0xd3a9, 0xe5948f}, /* U+550F */ + {0xd3aa, 0xe59494}, /* U+5514 */ + {0xd3ab, 0xe593bd}, /* U+54FD */ + {0xd3ac, 0xe593ae}, /* U+54EE */ + {0xd3ad, 0xe593ad}, /* U+54ED */ + {0xd3ae, 0xe593ba}, /* U+54FA */ + {0xd3af, 0xe593a2}, /* U+54E2 */ + {0xd3b0, 0xe594b9}, /* U+5539 */ + {0xd3b1, 0xe59580}, /* U+5540 */ + {0xd3b2, 0xe595a3}, /* U+5563 */ + {0xd3b3, 0xe5958c}, /* U+554C */ + {0xd3b4, 0xe594ae}, /* U+552E */ + {0xd3b5, 0xe5959c}, /* U+555C */ + {0xd3b6, 0xe59585}, /* U+5545 */ + {0xd3b7, 0xe59596}, /* U+5556 */ + {0xd3b8, 0xe59597}, /* U+5557 */ + {0xd3b9, 0xe594b8}, /* U+5538 */ + {0xd3ba, 0xe594b3}, /* U+5533 */ + {0xd3bb, 0xe5959d}, /* U+555D */ + {0xd3bc, 0xe59699}, /* U+5599 */ + {0xd3bd, 0xe59680}, /* U+5580 */ + {0xd3be, 0xe592af}, /* U+54AF */ + {0xd3bf, 0xe5968a}, /* U+558A */ + {0xd3c0, 0xe5969f}, /* U+559F */ + {0xd3c1, 0xe595bb}, /* U+557B */ + {0xd3c2, 0xe595be}, /* U+557E */ + {0xd3c3, 0xe59698}, /* U+5598 */ + {0xd3c4, 0xe5969e}, /* U+559E */ + {0xd3c5, 0xe596ae}, /* U+55AE */ + {0xd3c6, 0xe595bc}, /* U+557C */ + {0xd3c7, 0xe59683}, /* U+5583 */ + {0xd3c8, 0xe596a9}, /* U+55A9 */ + {0xd3c9, 0xe59687}, /* U+5587 */ + {0xd3ca, 0xe596a8}, /* U+55A8 */ + {0xd3cb, 0xe5979a}, /* U+55DA */ + {0xd3cc, 0xe59785}, /* U+55C5 */ + {0xd3cd, 0xe5979f}, /* U+55DF */ + {0xd3ce, 0xe59784}, /* U+55C4 */ + {0xd3cf, 0xe5979c}, /* U+55DC */ + {0xd3d0, 0xe597a4}, /* U+55E4 */ + {0xd3d1, 0xe59794}, /* U+55D4 */ + {0xd3d2, 0xe59894}, /* U+5614 */ + {0xd3d3, 0xe597b7}, /* U+55F7 */ + {0xd3d4, 0xe59896}, /* U+5616 */ + {0xd3d5, 0xe597be}, /* U+55FE */ + {0xd3d6, 0xe597bd}, /* U+55FD */ + {0xd3d7, 0xe5989b}, /* U+561B */ + {0xd3d8, 0xe597b9}, /* U+55F9 */ + {0xd3d9, 0xe5998e}, /* U+564E */ + {0xd3da, 0xe59990}, /* U+5650 */ + {0xd3db, 0xe7879f}, /* U+71DF */ + {0xd3dc, 0xe598b4}, /* U+5634 */ + {0xd3dd, 0xe598b6}, /* U+5636 */ + {0xd3de, 0xe598b2}, /* U+5632 */ + {0xd3df, 0xe598b8}, /* U+5638 */ + {0xd3e0, 0xe599ab}, /* U+566B */ + {0xd3e1, 0xe599a4}, /* U+5664 */ + {0xd3e2, 0xe598af}, /* U+562F */ + {0xd3e3, 0xe599ac}, /* U+566C */ + {0xd3e4, 0xe599aa}, /* U+566A */ + {0xd3e5, 0xe59a86}, /* U+5686 */ + {0xd3e6, 0xe59a80}, /* U+5680 */ + {0xd3e7, 0xe59a8a}, /* U+568A */ + {0xd3e8, 0xe59aa0}, /* U+56A0 */ + {0xd3e9, 0xe59a94}, /* U+5694 */ + {0xd3ea, 0xe59a8f}, /* U+568F */ + {0xd3eb, 0xe59aa5}, /* U+56A5 */ + {0xd3ec, 0xe59aae}, /* U+56AE */ + {0xd3ed, 0xe59ab6}, /* U+56B6 */ + {0xd3ee, 0xe59ab4}, /* U+56B4 */ + {0xd3ef, 0xe59b82}, /* U+56C2 */ + {0xd3f0, 0xe59abc}, /* U+56BC */ + {0xd3f1, 0xe59b81}, /* U+56C1 */ + {0xd3f2, 0xe59b83}, /* U+56C3 */ + {0xd3f3, 0xe59b80}, /* U+56C0 */ + {0xd3f4, 0xe59b88}, /* U+56C8 */ + {0xd3f5, 0xe59b8e}, /* U+56CE */ + {0xd3f6, 0xe59b91}, /* U+56D1 */ + {0xd3f7, 0xe59b93}, /* U+56D3 */ + {0xd3f8, 0xe59b97}, /* U+56D7 */ + {0xd3f9, 0xe59bae}, /* U+56EE */ + {0xd3fa, 0xe59bb9}, /* U+56F9 */ + {0xd3fb, 0xe59c80}, /* U+5700 */ + {0xd3fc, 0xe59bbf}, /* U+56FF */ + {0xd3fd, 0xe59c84}, /* U+5704 */ + {0xd3fe, 0xe59c89}, /* U+5709 */ + {0xd4a1, 0xe59c88}, /* U+5708 */ + {0xd4a2, 0xe59c8b}, /* U+570B */ + {0xd4a3, 0xe59c8d}, /* U+570D */ + {0xd4a4, 0xe59c93}, /* U+5713 */ + {0xd4a5, 0xe59c98}, /* U+5718 */ + {0xd4a6, 0xe59c96}, /* U+5716 */ + {0xd4a7, 0xe59787}, /* U+55C7 */ + {0xd4a8, 0xe59c9c}, /* U+571C */ + {0xd4a9, 0xe59ca6}, /* U+5726 */ + {0xd4aa, 0xe59cb7}, /* U+5737 */ + {0xd4ab, 0xe59cb8}, /* U+5738 */ + {0xd4ac, 0xe59d8e}, /* U+574E */ + {0xd4ad, 0xe59cbb}, /* U+573B */ + {0xd4ae, 0xe59d80}, /* U+5740 */ + {0xd4af, 0xe59d8f}, /* U+574F */ + {0xd4b0, 0xe59da9}, /* U+5769 */ + {0xd4b1, 0xe59f80}, /* U+57C0 */ + {0xd4b2, 0xe59e88}, /* U+5788 */ + {0xd4b3, 0xe59da1}, /* U+5761 */ + {0xd4b4, 0xe59dbf}, /* U+577F */ + {0xd4b5, 0xe59e89}, /* U+5789 */ + {0xd4b6, 0xe59e93}, /* U+5793 */ + {0xd4b7, 0xe59ea0}, /* U+57A0 */ + {0xd4b8, 0xe59eb3}, /* U+57B3 */ + {0xd4b9, 0xe59ea4}, /* U+57A4 */ + {0xd4ba, 0xe59eaa}, /* U+57AA */ + {0xd4bb, 0xe59eb0}, /* U+57B0 */ + {0xd4bc, 0xe59f83}, /* U+57C3 */ + {0xd4bd, 0xe59f86}, /* U+57C6 */ + {0xd4be, 0xe59f94}, /* U+57D4 */ + {0xd4bf, 0xe59f92}, /* U+57D2 */ + {0xd4c0, 0xe59f93}, /* U+57D3 */ + {0xd4c1, 0xe5a08a}, /* U+580A */ + {0xd4c2, 0xe59f96}, /* U+57D6 */ + {0xd4c3, 0xe59fa3}, /* U+57E3 */ + {0xd4c4, 0xe5a08b}, /* U+580B */ + {0xd4c5, 0xe5a099}, /* U+5819 */ + {0xd4c6, 0xe5a09d}, /* U+581D */ + {0xd4c7, 0xe5a1b2}, /* U+5872 */ + {0xd4c8, 0xe5a0a1}, /* U+5821 */ + {0xd4c9, 0xe5a1a2}, /* U+5862 */ + {0xd4ca, 0xe5a18b}, /* U+584B */ + {0xd4cb, 0xe5a1b0}, /* U+5870 */ + {0xd4cc, 0xe6af80}, /* U+6BC0 */ + {0xd4cd, 0xe5a192}, /* U+5852 */ + {0xd4ce, 0xe5a0bd}, /* U+583D */ + {0xd4cf, 0xe5a1b9}, /* U+5879 */ + {0xd4d0, 0xe5a285}, /* U+5885 */ + {0xd4d1, 0xe5a2b9}, /* U+58B9 */ + {0xd4d2, 0xe5a29f}, /* U+589F */ + {0xd4d3, 0xe5a2ab}, /* U+58AB */ + {0xd4d4, 0xe5a2ba}, /* U+58BA */ + {0xd4d5, 0xe5a39e}, /* U+58DE */ + {0xd4d6, 0xe5a2bb}, /* U+58BB */ + {0xd4d7, 0xe5a2b8}, /* U+58B8 */ + {0xd4d8, 0xe5a2ae}, /* U+58AE */ + {0xd4d9, 0xe5a385}, /* U+58C5 */ + {0xd4da, 0xe5a393}, /* U+58D3 */ + {0xd4db, 0xe5a391}, /* U+58D1 */ + {0xd4dc, 0xe5a397}, /* U+58D7 */ + {0xd4dd, 0xe5a399}, /* U+58D9 */ + {0xd4de, 0xe5a398}, /* U+58D8 */ + {0xd4df, 0xe5a3a5}, /* U+58E5 */ + {0xd4e0, 0xe5a39c}, /* U+58DC */ + {0xd4e1, 0xe5a3a4}, /* U+58E4 */ + {0xd4e2, 0xe5a39f}, /* U+58DF */ + {0xd4e3, 0xe5a3af}, /* U+58EF */ + {0xd4e4, 0xe5a3ba}, /* U+58FA */ + {0xd4e5, 0xe5a3b9}, /* U+58F9 */ + {0xd4e6, 0xe5a3bb}, /* U+58FB */ + {0xd4e7, 0xe5a3bc}, /* U+58FC */ + {0xd4e8, 0xe5a3bd}, /* U+58FD */ + {0xd4e9, 0xe5a482}, /* U+5902 */ + {0xd4ea, 0xe5a48a}, /* U+590A */ + {0xd4eb, 0xe5a490}, /* U+5910 */ + {0xd4ec, 0xe5a49b}, /* U+591B */ + {0xd4ed, 0xe6a2a6}, /* U+68A6 */ + {0xd4ee, 0xe5a4a5}, /* U+5925 */ + {0xd4ef, 0xe5a4ac}, /* U+592C */ + {0xd4f0, 0xe5a4ad}, /* U+592D */ + {0xd4f1, 0xe5a4b2}, /* U+5932 */ + {0xd4f2, 0xe5a4b8}, /* U+5938 */ + {0xd4f3, 0xe5a4be}, /* U+593E */ + {0xd4f4, 0xe7ab92}, /* U+7AD2 */ + {0xd4f5, 0xe5a595}, /* U+5955 */ + {0xd4f6, 0xe5a590}, /* U+5950 */ + {0xd4f7, 0xe5a58e}, /* U+594E */ + {0xd4f8, 0xe5a59a}, /* U+595A */ + {0xd4f9, 0xe5a598}, /* U+5958 */ + {0xd4fa, 0xe5a5a2}, /* U+5962 */ + {0xd4fb, 0xe5a5a0}, /* U+5960 */ + {0xd4fc, 0xe5a5a7}, /* U+5967 */ + {0xd4fd, 0xe5a5ac}, /* U+596C */ + {0xd4fe, 0xe5a5a9}, /* U+5969 */ + {0xd5a1, 0xe5a5b8}, /* U+5978 */ + {0xd5a2, 0xe5a681}, /* U+5981 */ + {0xd5a3, 0xe5a69d}, /* U+599D */ + {0xd5a4, 0xe4bd9e}, /* U+4F5E */ + {0xd5a5, 0xe4beab}, /* U+4FAB */ + {0xd5a6, 0xe5a6a3}, /* U+59A3 */ + {0xd5a7, 0xe5a6b2}, /* U+59B2 */ + {0xd5a8, 0xe5a786}, /* U+59C6 */ + {0xd5a9, 0xe5a7a8}, /* U+59E8 */ + {0xd5aa, 0xe5a79c}, /* U+59DC */ + {0xd5ab, 0xe5a68d}, /* U+598D */ + {0xd5ac, 0xe5a799}, /* U+59D9 */ + {0xd5ad, 0xe5a79a}, /* U+59DA */ + {0xd5ae, 0xe5a8a5}, /* U+5A25 */ + {0xd5af, 0xe5a89f}, /* U+5A1F */ + {0xd5b0, 0xe5a891}, /* U+5A11 */ + {0xd5b1, 0xe5a89c}, /* U+5A1C */ + {0xd5b2, 0xe5a889}, /* U+5A09 */ + {0xd5b3, 0xe5a89a}, /* U+5A1A */ + {0xd5b4, 0xe5a980}, /* U+5A40 */ + {0xd5b5, 0xe5a9ac}, /* U+5A6C */ + {0xd5b6, 0xe5a989}, /* U+5A49 */ + {0xd5b7, 0xe5a8b5}, /* U+5A35 */ + {0xd5b8, 0xe5a8b6}, /* U+5A36 */ + {0xd5b9, 0xe5a9a2}, /* U+5A62 */ + {0xd5ba, 0xe5a9aa}, /* U+5A6A */ + {0xd5bb, 0xe5aa9a}, /* U+5A9A */ + {0xd5bc, 0xe5aabc}, /* U+5ABC */ + {0xd5bd, 0xe5aabe}, /* U+5ABE */ + {0xd5be, 0xe5ab8b}, /* U+5ACB */ + {0xd5bf, 0xe5ab82}, /* U+5AC2 */ + {0xd5c0, 0xe5aabd}, /* U+5ABD */ + {0xd5c1, 0xe5aba3}, /* U+5AE3 */ + {0xd5c2, 0xe5ab97}, /* U+5AD7 */ + {0xd5c3, 0xe5aba6}, /* U+5AE6 */ + {0xd5c4, 0xe5aba9}, /* U+5AE9 */ + {0xd5c5, 0xe5ab96}, /* U+5AD6 */ + {0xd5c6, 0xe5abba}, /* U+5AFA */ + {0xd5c7, 0xe5abbb}, /* U+5AFB */ + {0xd5c8, 0xe5ac8c}, /* U+5B0C */ + {0xd5c9, 0xe5ac8b}, /* U+5B0B */ + {0xd5ca, 0xe5ac96}, /* U+5B16 */ + {0xd5cb, 0xe5acb2}, /* U+5B32 */ + {0xd5cc, 0xe5ab90}, /* U+5AD0 */ + {0xd5cd, 0xe5acaa}, /* U+5B2A */ + {0xd5ce, 0xe5acb6}, /* U+5B36 */ + {0xd5cf, 0xe5acbe}, /* U+5B3E */ + {0xd5d0, 0xe5ad83}, /* U+5B43 */ + {0xd5d1, 0xe5ad85}, /* U+5B45 */ + {0xd5d2, 0xe5ad80}, /* U+5B40 */ + {0xd5d3, 0xe5ad91}, /* U+5B51 */ + {0xd5d4, 0xe5ad95}, /* U+5B55 */ + {0xd5d5, 0xe5ad9a}, /* U+5B5A */ + {0xd5d6, 0xe5ad9b}, /* U+5B5B */ + {0xd5d7, 0xe5ada5}, /* U+5B65 */ + {0xd5d8, 0xe5ada9}, /* U+5B69 */ + {0xd5d9, 0xe5adb0}, /* U+5B70 */ + {0xd5da, 0xe5adb3}, /* U+5B73 */ + {0xd5db, 0xe5adb5}, /* U+5B75 */ + {0xd5dc, 0xe5adb8}, /* U+5B78 */ + {0xd5dd, 0xe69688}, /* U+6588 */ + {0xd5de, 0xe5adba}, /* U+5B7A */ + {0xd5df, 0xe5ae80}, /* U+5B80 */ + {0xd5e0, 0xe5ae83}, /* U+5B83 */ + {0xd5e1, 0xe5aea6}, /* U+5BA6 */ + {0xd5e2, 0xe5aeb8}, /* U+5BB8 */ + {0xd5e3, 0xe5af83}, /* U+5BC3 */ + {0xd5e4, 0xe5af87}, /* U+5BC7 */ + {0xd5e5, 0xe5af89}, /* U+5BC9 */ + {0xd5e6, 0xe5af94}, /* U+5BD4 */ + {0xd5e7, 0xe5af90}, /* U+5BD0 */ + {0xd5e8, 0xe5afa4}, /* U+5BE4 */ + {0xd5e9, 0xe5afa6}, /* U+5BE6 */ + {0xd5ea, 0xe5afa2}, /* U+5BE2 */ + {0xd5eb, 0xe5af9e}, /* U+5BDE */ + {0xd5ec, 0xe5afa5}, /* U+5BE5 */ + {0xd5ed, 0xe5afab}, /* U+5BEB */ + {0xd5ee, 0xe5afb0}, /* U+5BF0 */ + {0xd5ef, 0xe5afb6}, /* U+5BF6 */ + {0xd5f0, 0xe5afb3}, /* U+5BF3 */ + {0xd5f1, 0xe5b085}, /* U+5C05 */ + {0xd5f2, 0xe5b087}, /* U+5C07 */ + {0xd5f3, 0xe5b088}, /* U+5C08 */ + {0xd5f4, 0xe5b08d}, /* U+5C0D */ + {0xd5f5, 0xe5b093}, /* U+5C13 */ + {0xd5f6, 0xe5b0a0}, /* U+5C20 */ + {0xd5f7, 0xe5b0a2}, /* U+5C22 */ + {0xd5f8, 0xe5b0a8}, /* U+5C28 */ + {0xd5f9, 0xe5b0b8}, /* U+5C38 */ + {0xd5fa, 0xe5b0b9}, /* U+5C39 */ + {0xd5fb, 0xe5b181}, /* U+5C41 */ + {0xd5fc, 0xe5b186}, /* U+5C46 */ + {0xd5fd, 0xe5b18e}, /* U+5C4E */ + {0xd5fe, 0xe5b193}, /* U+5C53 */ + {0xd6a1, 0xe5b190}, /* U+5C50 */ + {0xd6a2, 0xe5b18f}, /* U+5C4F */ + {0xd6a3, 0xe5adb1}, /* U+5B71 */ + {0xd6a4, 0xe5b1ac}, /* U+5C6C */ + {0xd6a5, 0xe5b1ae}, /* U+5C6E */ + {0xd6a6, 0xe4b9a2}, /* U+4E62 */ + {0xd6a7, 0xe5b1b6}, /* U+5C76 */ + {0xd6a8, 0xe5b1b9}, /* U+5C79 */ + {0xd6a9, 0xe5b28c}, /* U+5C8C */ + {0xd6aa, 0xe5b291}, /* U+5C91 */ + {0xd6ab, 0xe5b294}, /* U+5C94 */ + {0xd6ac, 0xe5a69b}, /* U+599B */ + {0xd6ad, 0xe5b2ab}, /* U+5CAB */ + {0xd6ae, 0xe5b2bb}, /* U+5CBB */ + {0xd6af, 0xe5b2b6}, /* U+5CB6 */ + {0xd6b0, 0xe5b2bc}, /* U+5CBC */ + {0xd6b1, 0xe5b2b7}, /* U+5CB7 */ + {0xd6b2, 0xe5b385}, /* U+5CC5 */ + {0xd6b3, 0xe5b2be}, /* U+5CBE */ + {0xd6b4, 0xe5b387}, /* U+5CC7 */ + {0xd6b5, 0xe5b399}, /* U+5CD9 */ + {0xd6b6, 0xe5b3a9}, /* U+5CE9 */ + {0xd6b7, 0xe5b3bd}, /* U+5CFD */ + {0xd6b8, 0xe5b3ba}, /* U+5CFA */ + {0xd6b9, 0xe5b3ad}, /* U+5CED */ + {0xd6ba, 0xe5b68c}, /* U+5D8C */ + {0xd6bb, 0xe5b3aa}, /* U+5CEA */ + {0xd6bc, 0xe5b48b}, /* U+5D0B */ + {0xd6bd, 0xe5b495}, /* U+5D15 */ + {0xd6be, 0xe5b497}, /* U+5D17 */ + {0xd6bf, 0xe5b59c}, /* U+5D5C */ + {0xd6c0, 0xe5b49f}, /* U+5D1F */ + {0xd6c1, 0xe5b49b}, /* U+5D1B */ + {0xd6c2, 0xe5b491}, /* U+5D11 */ + {0xd6c3, 0xe5b494}, /* U+5D14 */ + {0xd6c4, 0xe5b4a2}, /* U+5D22 */ + {0xd6c5, 0xe5b49a}, /* U+5D1A */ + {0xd6c6, 0xe5b499}, /* U+5D19 */ + {0xd6c7, 0xe5b498}, /* U+5D18 */ + {0xd6c8, 0xe5b58c}, /* U+5D4C */ + {0xd6c9, 0xe5b592}, /* U+5D52 */ + {0xd6ca, 0xe5b58e}, /* U+5D4E */ + {0xd6cb, 0xe5b58b}, /* U+5D4B */ + {0xd6cc, 0xe5b5ac}, /* U+5D6C */ + {0xd6cd, 0xe5b5b3}, /* U+5D73 */ + {0xd6ce, 0xe5b5b6}, /* U+5D76 */ + {0xd6cf, 0xe5b687}, /* U+5D87 */ + {0xd6d0, 0xe5b684}, /* U+5D84 */ + {0xd6d1, 0xe5b682}, /* U+5D82 */ + {0xd6d2, 0xe5b6a2}, /* U+5DA2 */ + {0xd6d3, 0xe5b69d}, /* U+5D9D */ + {0xd6d4, 0xe5b6ac}, /* U+5DAC */ + {0xd6d5, 0xe5b6ae}, /* U+5DAE */ + {0xd6d6, 0xe5b6bd}, /* U+5DBD */ + {0xd6d7, 0xe5b690}, /* U+5D90 */ + {0xd6d8, 0xe5b6b7}, /* U+5DB7 */ + {0xd6d9, 0xe5b6bc}, /* U+5DBC */ + {0xd6da, 0xe5b789}, /* U+5DC9 */ + {0xd6db, 0xe5b78d}, /* U+5DCD */ + {0xd6dc, 0xe5b793}, /* U+5DD3 */ + {0xd6dd, 0xe5b792}, /* U+5DD2 */ + {0xd6de, 0xe5b796}, /* U+5DD6 */ + {0xd6df, 0xe5b79b}, /* U+5DDB */ + {0xd6e0, 0xe5b7ab}, /* U+5DEB */ + {0xd6e1, 0xe5b7b2}, /* U+5DF2 */ + {0xd6e2, 0xe5b7b5}, /* U+5DF5 */ + {0xd6e3, 0xe5b88b}, /* U+5E0B */ + {0xd6e4, 0xe5b89a}, /* U+5E1A */ + {0xd6e5, 0xe5b899}, /* U+5E19 */ + {0xd6e6, 0xe5b891}, /* U+5E11 */ + {0xd6e7, 0xe5b89b}, /* U+5E1B */ + {0xd6e8, 0xe5b8b6}, /* U+5E36 */ + {0xd6e9, 0xe5b8b7}, /* U+5E37 */ + {0xd6ea, 0xe5b984}, /* U+5E44 */ + {0xd6eb, 0xe5b983}, /* U+5E43 */ + {0xd6ec, 0xe5b980}, /* U+5E40 */ + {0xd6ed, 0xe5b98e}, /* U+5E4E */ + {0xd6ee, 0xe5b997}, /* U+5E57 */ + {0xd6ef, 0xe5b994}, /* U+5E54 */ + {0xd6f0, 0xe5b99f}, /* U+5E5F */ + {0xd6f1, 0xe5b9a2}, /* U+5E62 */ + {0xd6f2, 0xe5b9a4}, /* U+5E64 */ + {0xd6f3, 0xe5b987}, /* U+5E47 */ + {0xd6f4, 0xe5b9b5}, /* U+5E75 */ + {0xd6f5, 0xe5b9b6}, /* U+5E76 */ + {0xd6f6, 0xe5b9ba}, /* U+5E7A */ + {0xd6f7, 0xe9babc}, /* U+9EBC */ + {0xd6f8, 0xe5b9bf}, /* U+5E7F */ + {0xd6f9, 0xe5baa0}, /* U+5EA0 */ + {0xd6fa, 0xe5bb81}, /* U+5EC1 */ + {0xd6fb, 0xe5bb82}, /* U+5EC2 */ + {0xd6fc, 0xe5bb88}, /* U+5EC8 */ + {0xd6fd, 0xe5bb90}, /* U+5ED0 */ + {0xd6fe, 0xe5bb8f}, /* U+5ECF */ + {0xd7a1, 0xe5bb96}, /* U+5ED6 */ + {0xd7a2, 0xe5bba3}, /* U+5EE3 */ + {0xd7a3, 0xe5bb9d}, /* U+5EDD */ + {0xd7a4, 0xe5bb9a}, /* U+5EDA */ + {0xd7a5, 0xe5bb9b}, /* U+5EDB */ + {0xd7a6, 0xe5bba2}, /* U+5EE2 */ + {0xd7a7, 0xe5bba1}, /* U+5EE1 */ + {0xd7a8, 0xe5bba8}, /* U+5EE8 */ + {0xd7a9, 0xe5bba9}, /* U+5EE9 */ + {0xd7aa, 0xe5bbac}, /* U+5EEC */ + {0xd7ab, 0xe5bbb1}, /* U+5EF1 */ + {0xd7ac, 0xe5bbb3}, /* U+5EF3 */ + {0xd7ad, 0xe5bbb0}, /* U+5EF0 */ + {0xd7ae, 0xe5bbb4}, /* U+5EF4 */ + {0xd7af, 0xe5bbb8}, /* U+5EF8 */ + {0xd7b0, 0xe5bbbe}, /* U+5EFE */ + {0xd7b1, 0xe5bc83}, /* U+5F03 */ + {0xd7b2, 0xe5bc89}, /* U+5F09 */ + {0xd7b3, 0xe5bd9d}, /* U+5F5D */ + {0xd7b4, 0xe5bd9c}, /* U+5F5C */ + {0xd7b5, 0xe5bc8b}, /* U+5F0B */ + {0xd7b6, 0xe5bc91}, /* U+5F11 */ + {0xd7b7, 0xe5bc96}, /* U+5F16 */ + {0xd7b8, 0xe5bca9}, /* U+5F29 */ + {0xd7b9, 0xe5bcad}, /* U+5F2D */ + {0xd7ba, 0xe5bcb8}, /* U+5F38 */ + {0xd7bb, 0xe5bd81}, /* U+5F41 */ + {0xd7bc, 0xe5bd88}, /* U+5F48 */ + {0xd7bd, 0xe5bd8c}, /* U+5F4C */ + {0xd7be, 0xe5bd8e}, /* U+5F4E */ + {0xd7bf, 0xe5bcaf}, /* U+5F2F */ + {0xd7c0, 0xe5bd91}, /* U+5F51 */ + {0xd7c1, 0xe5bd96}, /* U+5F56 */ + {0xd7c2, 0xe5bd97}, /* U+5F57 */ + {0xd7c3, 0xe5bd99}, /* U+5F59 */ + {0xd7c4, 0xe5bda1}, /* U+5F61 */ + {0xd7c5, 0xe5bdad}, /* U+5F6D */ + {0xd7c6, 0xe5bdb3}, /* U+5F73 */ + {0xd7c7, 0xe5bdb7}, /* U+5F77 */ + {0xd7c8, 0xe5be83}, /* U+5F83 */ + {0xd7c9, 0xe5be82}, /* U+5F82 */ + {0xd7ca, 0xe5bdbf}, /* U+5F7F */ + {0xd7cb, 0xe5be8a}, /* U+5F8A */ + {0xd7cc, 0xe5be88}, /* U+5F88 */ + {0xd7cd, 0xe5be91}, /* U+5F91 */ + {0xd7ce, 0xe5be87}, /* U+5F87 */ + {0xd7cf, 0xe5be9e}, /* U+5F9E */ + {0xd7d0, 0xe5be99}, /* U+5F99 */ + {0xd7d1, 0xe5be98}, /* U+5F98 */ + {0xd7d2, 0xe5bea0}, /* U+5FA0 */ + {0xd7d3, 0xe5bea8}, /* U+5FA8 */ + {0xd7d4, 0xe5bead}, /* U+5FAD */ + {0xd7d5, 0xe5bebc}, /* U+5FBC */ + {0xd7d6, 0xe5bf96}, /* U+5FD6 */ + {0xd7d7, 0xe5bfbb}, /* U+5FFB */ + {0xd7d8, 0xe5bfa4}, /* U+5FE4 */ + {0xd7d9, 0xe5bfb8}, /* U+5FF8 */ + {0xd7da, 0xe5bfb1}, /* U+5FF1 */ + {0xd7db, 0xe5bf9d}, /* U+5FDD */ + {0xd7dc, 0xe682b3}, /* U+60B3 */ + {0xd7dd, 0xe5bfbf}, /* U+5FFF */ + {0xd7de, 0xe680a1}, /* U+6021 */ + {0xd7df, 0xe681a0}, /* U+6060 */ + {0xd7e0, 0xe68099}, /* U+6019 */ + {0xd7e1, 0xe68090}, /* U+6010 */ + {0xd7e2, 0xe680a9}, /* U+6029 */ + {0xd7e3, 0xe6808e}, /* U+600E */ + {0xd7e4, 0xe680b1}, /* U+6031 */ + {0xd7e5, 0xe6809b}, /* U+601B */ + {0xd7e6, 0xe68095}, /* U+6015 */ + {0xd7e7, 0xe680ab}, /* U+602B */ + {0xd7e8, 0xe680a6}, /* U+6026 */ + {0xd7e9, 0xe6808f}, /* U+600F */ + {0xd7ea, 0xe680ba}, /* U+603A */ + {0xd7eb, 0xe6819a}, /* U+605A */ + {0xd7ec, 0xe68181}, /* U+6041 */ + {0xd7ed, 0xe681aa}, /* U+606A */ + {0xd7ee, 0xe681b7}, /* U+6077 */ + {0xd7ef, 0xe6819f}, /* U+605F */ + {0xd7f0, 0xe6818a}, /* U+604A */ + {0xd7f1, 0xe68186}, /* U+6046 */ + {0xd7f2, 0xe6818d}, /* U+604D */ + {0xd7f3, 0xe681a3}, /* U+6063 */ + {0xd7f4, 0xe68183}, /* U+6043 */ + {0xd7f5, 0xe681a4}, /* U+6064 */ + {0xd7f6, 0xe68182}, /* U+6042 */ + {0xd7f7, 0xe681ac}, /* U+606C */ + {0xd7f8, 0xe681ab}, /* U+606B */ + {0xd7f9, 0xe68199}, /* U+6059 */ + {0xd7fa, 0xe68281}, /* U+6081 */ + {0xd7fb, 0xe6828d}, /* U+608D */ + {0xd7fc, 0xe683a7}, /* U+60E7 */ + {0xd7fd, 0xe68283}, /* U+6083 */ + {0xd7fe, 0xe6829a}, /* U+609A */ + {0xd8a1, 0xe68284}, /* U+6084 */ + {0xd8a2, 0xe6829b}, /* U+609B */ + {0xd8a3, 0xe68296}, /* U+6096 */ + {0xd8a4, 0xe68297}, /* U+6097 */ + {0xd8a5, 0xe68292}, /* U+6092 */ + {0xd8a6, 0xe682a7}, /* U+60A7 */ + {0xd8a7, 0xe6828b}, /* U+608B */ + {0xd8a8, 0xe683a1}, /* U+60E1 */ + {0xd8a9, 0xe682b8}, /* U+60B8 */ + {0xd8aa, 0xe683a0}, /* U+60E0 */ + {0xd8ab, 0xe68393}, /* U+60D3 */ + {0xd8ac, 0xe682b4}, /* U+60B4 */ + {0xd8ad, 0xe5bfb0}, /* U+5FF0 */ + {0xd8ae, 0xe682bd}, /* U+60BD */ + {0xd8af, 0xe68386}, /* U+60C6 */ + {0xd8b0, 0xe682b5}, /* U+60B5 */ + {0xd8b1, 0xe68398}, /* U+60D8 */ + {0xd8b2, 0xe6858d}, /* U+614D */ + {0xd8b3, 0xe68495}, /* U+6115 */ + {0xd8b4, 0xe68486}, /* U+6106 */ + {0xd8b5, 0xe683b6}, /* U+60F6 */ + {0xd8b6, 0xe683b7}, /* U+60F7 */ + {0xd8b7, 0xe68480}, /* U+6100 */ + {0xd8b8, 0xe683b4}, /* U+60F4 */ + {0xd8b9, 0xe683ba}, /* U+60FA */ + {0xd8ba, 0xe68483}, /* U+6103 */ + {0xd8bb, 0xe684a1}, /* U+6121 */ + {0xd8bc, 0xe683bb}, /* U+60FB */ + {0xd8bd, 0xe683b1}, /* U+60F1 */ + {0xd8be, 0xe6848d}, /* U+610D */ + {0xd8bf, 0xe6848e}, /* U+610E */ + {0xd8c0, 0xe68587}, /* U+6147 */ + {0xd8c1, 0xe684be}, /* U+613E */ + {0xd8c2, 0xe684a8}, /* U+6128 */ + {0xd8c3, 0xe684a7}, /* U+6127 */ + {0xd8c4, 0xe6858a}, /* U+614A */ + {0xd8c5, 0xe684bf}, /* U+613F */ + {0xd8c6, 0xe684bc}, /* U+613C */ + {0xd8c7, 0xe684ac}, /* U+612C */ + {0xd8c8, 0xe684b4}, /* U+6134 */ + {0xd8c9, 0xe684bd}, /* U+613D */ + {0xd8ca, 0xe68582}, /* U+6142 */ + {0xd8cb, 0xe68584}, /* U+6144 */ + {0xd8cc, 0xe685b3}, /* U+6173 */ + {0xd8cd, 0xe685b7}, /* U+6177 */ + {0xd8ce, 0xe68598}, /* U+6158 */ + {0xd8cf, 0xe68599}, /* U+6159 */ + {0xd8d0, 0xe6859a}, /* U+615A */ + {0xd8d1, 0xe685ab}, /* U+616B */ + {0xd8d2, 0xe685b4}, /* U+6174 */ + {0xd8d3, 0xe685af}, /* U+616F */ + {0xd8d4, 0xe685a5}, /* U+6165 */ + {0xd8d5, 0xe685b1}, /* U+6171 */ + {0xd8d6, 0xe6859f}, /* U+615F */ + {0xd8d7, 0xe6859d}, /* U+615D */ + {0xd8d8, 0xe68593}, /* U+6153 */ + {0xd8d9, 0xe685b5}, /* U+6175 */ + {0xd8da, 0xe68699}, /* U+6199 */ + {0xd8db, 0xe68696}, /* U+6196 */ + {0xd8dc, 0xe68687}, /* U+6187 */ + {0xd8dd, 0xe686ac}, /* U+61AC */ + {0xd8de, 0xe68694}, /* U+6194 */ + {0xd8df, 0xe6869a}, /* U+619A */ + {0xd8e0, 0xe6868a}, /* U+618A */ + {0xd8e1, 0xe68691}, /* U+6191 */ + {0xd8e2, 0xe686ab}, /* U+61AB */ + {0xd8e3, 0xe686ae}, /* U+61AE */ + {0xd8e4, 0xe6878c}, /* U+61CC */ + {0xd8e5, 0xe6878a}, /* U+61CA */ + {0xd8e6, 0xe68789}, /* U+61C9 */ + {0xd8e7, 0xe687b7}, /* U+61F7 */ + {0xd8e8, 0xe68788}, /* U+61C8 */ + {0xd8e9, 0xe68783}, /* U+61C3 */ + {0xd8ea, 0xe68786}, /* U+61C6 */ + {0xd8eb, 0xe686ba}, /* U+61BA */ + {0xd8ec, 0xe6878b}, /* U+61CB */ + {0xd8ed, 0xe7bdb9}, /* U+7F79 */ + {0xd8ee, 0xe6878d}, /* U+61CD */ + {0xd8ef, 0xe687a6}, /* U+61E6 */ + {0xd8f0, 0xe687a3}, /* U+61E3 */ + {0xd8f1, 0xe687b6}, /* U+61F6 */ + {0xd8f2, 0xe687ba}, /* U+61FA */ + {0xd8f3, 0xe687b4}, /* U+61F4 */ + {0xd8f4, 0xe687bf}, /* U+61FF */ + {0xd8f5, 0xe687bd}, /* U+61FD */ + {0xd8f6, 0xe687bc}, /* U+61FC */ + {0xd8f7, 0xe687be}, /* U+61FE */ + {0xd8f8, 0xe68880}, /* U+6200 */ + {0xd8f9, 0xe68888}, /* U+6208 */ + {0xd8fa, 0xe68889}, /* U+6209 */ + {0xd8fb, 0xe6888d}, /* U+620D */ + {0xd8fc, 0xe6888c}, /* U+620C */ + {0xd8fd, 0xe68894}, /* U+6214 */ + {0xd8fe, 0xe6889b}, /* U+621B */ + {0xd9a1, 0xe6889e}, /* U+621E */ + {0xd9a2, 0xe688a1}, /* U+6221 */ + {0xd9a3, 0xe688aa}, /* U+622A */ + {0xd9a4, 0xe688ae}, /* U+622E */ + {0xd9a5, 0xe688b0}, /* U+6230 */ + {0xd9a6, 0xe688b2}, /* U+6232 */ + {0xd9a7, 0xe688b3}, /* U+6233 */ + {0xd9a8, 0xe68981}, /* U+6241 */ + {0xd9a9, 0xe6898e}, /* U+624E */ + {0xd9aa, 0xe6899e}, /* U+625E */ + {0xd9ab, 0xe689a3}, /* U+6263 */ + {0xd9ac, 0xe6899b}, /* U+625B */ + {0xd9ad, 0xe689a0}, /* U+6260 */ + {0xd9ae, 0xe689a8}, /* U+6268 */ + {0xd9af, 0xe689bc}, /* U+627C */ + {0xd9b0, 0xe68a82}, /* U+6282 */ + {0xd9b1, 0xe68a89}, /* U+6289 */ + {0xd9b2, 0xe689be}, /* U+627E */ + {0xd9b3, 0xe68a92}, /* U+6292 */ + {0xd9b4, 0xe68a93}, /* U+6293 */ + {0xd9b5, 0xe68a96}, /* U+6296 */ + {0xd9b6, 0xe68b94}, /* U+62D4 */ + {0xd9b7, 0xe68a83}, /* U+6283 */ + {0xd9b8, 0xe68a94}, /* U+6294 */ + {0xd9b9, 0xe68b97}, /* U+62D7 */ + {0xd9ba, 0xe68b91}, /* U+62D1 */ + {0xd9bb, 0xe68abb}, /* U+62BB */ + {0xd9bc, 0xe68b8f}, /* U+62CF */ + {0xd9bd, 0xe68bbf}, /* U+62FF */ + {0xd9be, 0xe68b86}, /* U+62C6 */ + {0xd9bf, 0xe69394}, /* U+64D4 */ + {0xd9c0, 0xe68b88}, /* U+62C8 */ + {0xd9c1, 0xe68b9c}, /* U+62DC */ + {0xd9c2, 0xe68b8c}, /* U+62CC */ + {0xd9c3, 0xe68b8a}, /* U+62CA */ + {0xd9c4, 0xe68b82}, /* U+62C2 */ + {0xd9c5, 0xe68b87}, /* U+62C7 */ + {0xd9c6, 0xe68a9b}, /* U+629B */ + {0xd9c7, 0xe68b89}, /* U+62C9 */ + {0xd9c8, 0xe68c8c}, /* U+630C */ + {0xd9c9, 0xe68bae}, /* U+62EE */ + {0xd9ca, 0xe68bb1}, /* U+62F1 */ + {0xd9cb, 0xe68ca7}, /* U+6327 */ + {0xd9cc, 0xe68c82}, /* U+6302 */ + {0xd9cd, 0xe68c88}, /* U+6308 */ + {0xd9ce, 0xe68baf}, /* U+62EF */ + {0xd9cf, 0xe68bb5}, /* U+62F5 */ + {0xd9d0, 0xe68d90}, /* U+6350 */ + {0xd9d1, 0xe68cbe}, /* U+633E */ + {0xd9d2, 0xe68d8d}, /* U+634D */ + {0xd9d3, 0xe6909c}, /* U+641C */ + {0xd9d4, 0xe68d8f}, /* U+634F */ + {0xd9d5, 0xe68e96}, /* U+6396 */ + {0xd9d6, 0xe68e8e}, /* U+638E */ + {0xd9d7, 0xe68e80}, /* U+6380 */ + {0xd9d8, 0xe68eab}, /* U+63AB */ + {0xd9d9, 0xe68db6}, /* U+6376 */ + {0xd9da, 0xe68ea3}, /* U+63A3 */ + {0xd9db, 0xe68e8f}, /* U+638F */ + {0xd9dc, 0xe68e89}, /* U+6389 */ + {0xd9dd, 0xe68e9f}, /* U+639F */ + {0xd9de, 0xe68eb5}, /* U+63B5 */ + {0xd9df, 0xe68dab}, /* U+636B */ + {0xd9e0, 0xe68da9}, /* U+6369 */ + {0xd9e1, 0xe68ebe}, /* U+63BE */ + {0xd9e2, 0xe68fa9}, /* U+63E9 */ + {0xd9e3, 0xe68f80}, /* U+63C0 */ + {0xd9e4, 0xe68f86}, /* U+63C6 */ + {0xd9e5, 0xe68fa3}, /* U+63E3 */ + {0xd9e6, 0xe68f89}, /* U+63C9 */ + {0xd9e7, 0xe68f92}, /* U+63D2 */ + {0xd9e8, 0xe68fb6}, /* U+63F6 */ + {0xd9e9, 0xe68f84}, /* U+63C4 */ + {0xd9ea, 0xe69096}, /* U+6416 */ + {0xd9eb, 0xe690b4}, /* U+6434 */ + {0xd9ec, 0xe69086}, /* U+6406 */ + {0xd9ed, 0xe69093}, /* U+6413 */ + {0xd9ee, 0xe690a6}, /* U+6426 */ + {0xd9ef, 0xe690b6}, /* U+6436 */ + {0xd9f0, 0xe6949d}, /* U+651D */ + {0xd9f1, 0xe69097}, /* U+6417 */ + {0xd9f2, 0xe690a8}, /* U+6428 */ + {0xd9f3, 0xe6908f}, /* U+640F */ + {0xd9f4, 0xe691a7}, /* U+6467 */ + {0xd9f5, 0xe691af}, /* U+646F */ + {0xd9f6, 0xe691b6}, /* U+6476 */ + {0xd9f7, 0xe6918e}, /* U+644E */ + {0xd9f8, 0xe694aa}, /* U+652A */ + {0xd9f9, 0xe69295}, /* U+6495 */ + {0xd9fa, 0xe69293}, /* U+6493 */ + {0xd9fb, 0xe692a5}, /* U+64A5 */ + {0xd9fc, 0xe692a9}, /* U+64A9 */ + {0xd9fd, 0xe69288}, /* U+6488 */ + {0xd9fe, 0xe692bc}, /* U+64BC */ + {0xdaa1, 0xe6939a}, /* U+64DA */ + {0xdaa2, 0xe69392}, /* U+64D2 */ + {0xdaa3, 0xe69385}, /* U+64C5 */ + {0xdaa4, 0xe69387}, /* U+64C7 */ + {0xdaa5, 0xe692bb}, /* U+64BB */ + {0xdaa6, 0xe69398}, /* U+64D8 */ + {0xdaa7, 0xe69382}, /* U+64C2 */ + {0xdaa8, 0xe693b1}, /* U+64F1 */ + {0xdaa9, 0xe693a7}, /* U+64E7 */ + {0xdaaa, 0xe88889}, /* U+8209 */ + {0xdaab, 0xe693a0}, /* U+64E0 */ + {0xdaac, 0xe693a1}, /* U+64E1 */ + {0xdaad, 0xe68aac}, /* U+62AC */ + {0xdaae, 0xe693a3}, /* U+64E3 */ + {0xdaaf, 0xe693af}, /* U+64EF */ + {0xdab0, 0xe694ac}, /* U+652C */ + {0xdab1, 0xe693b6}, /* U+64F6 */ + {0xdab2, 0xe693b4}, /* U+64F4 */ + {0xdab3, 0xe693b2}, /* U+64F2 */ + {0xdab4, 0xe693ba}, /* U+64FA */ + {0xdab5, 0xe69480}, /* U+6500 */ + {0xdab6, 0xe693bd}, /* U+64FD */ + {0xdab7, 0xe69498}, /* U+6518 */ + {0xdab8, 0xe6949c}, /* U+651C */ + {0xdab9, 0xe69485}, /* U+6505 */ + {0xdaba, 0xe694a4}, /* U+6524 */ + {0xdabb, 0xe694a3}, /* U+6523 */ + {0xdabc, 0xe694ab}, /* U+652B */ + {0xdabd, 0xe694b4}, /* U+6534 */ + {0xdabe, 0xe694b5}, /* U+6535 */ + {0xdabf, 0xe694b7}, /* U+6537 */ + {0xdac0, 0xe694b6}, /* U+6536 */ + {0xdac1, 0xe694b8}, /* U+6538 */ + {0xdac2, 0xe7958b}, /* U+754B */ + {0xdac3, 0xe69588}, /* U+6548 */ + {0xdac4, 0xe69596}, /* U+6556 */ + {0xdac5, 0xe69595}, /* U+6555 */ + {0xdac6, 0xe6958d}, /* U+654D */ + {0xdac7, 0xe69598}, /* U+6558 */ + {0xdac8, 0xe6959e}, /* U+655E */ + {0xdac9, 0xe6959d}, /* U+655D */ + {0xdaca, 0xe695b2}, /* U+6572 */ + {0xdacb, 0xe695b8}, /* U+6578 */ + {0xdacc, 0xe69682}, /* U+6582 */ + {0xdacd, 0xe69683}, /* U+6583 */ + {0xdace, 0xe8ae8a}, /* U+8B8A */ + {0xdacf, 0xe6969b}, /* U+659B */ + {0xdad0, 0xe6969f}, /* U+659F */ + {0xdad1, 0xe696ab}, /* U+65AB */ + {0xdad2, 0xe696b7}, /* U+65B7 */ + {0xdad3, 0xe69783}, /* U+65C3 */ + {0xdad4, 0xe69786}, /* U+65C6 */ + {0xdad5, 0xe69781}, /* U+65C1 */ + {0xdad6, 0xe69784}, /* U+65C4 */ + {0xdad7, 0xe6978c}, /* U+65CC */ + {0xdad8, 0xe69792}, /* U+65D2 */ + {0xdad9, 0xe6979b}, /* U+65DB */ + {0xdada, 0xe69799}, /* U+65D9 */ + {0xdadb, 0xe697a0}, /* U+65E0 */ + {0xdadc, 0xe697a1}, /* U+65E1 */ + {0xdadd, 0xe697b1}, /* U+65F1 */ + {0xdade, 0xe69db2}, /* U+6772 */ + {0xdadf, 0xe6988a}, /* U+660A */ + {0xdae0, 0xe69883}, /* U+6603 */ + {0xdae1, 0xe697bb}, /* U+65FB */ + {0xdae2, 0xe69db3}, /* U+6773 */ + {0xdae3, 0xe698b5}, /* U+6635 */ + {0xdae4, 0xe698b6}, /* U+6636 */ + {0xdae5, 0xe698b4}, /* U+6634 */ + {0xdae6, 0xe6989c}, /* U+661C */ + {0xdae7, 0xe6998f}, /* U+664F */ + {0xdae8, 0xe69984}, /* U+6644 */ + {0xdae9, 0xe69989}, /* U+6649 */ + {0xdaea, 0xe69981}, /* U+6641 */ + {0xdaeb, 0xe6999e}, /* U+665E */ + {0xdaec, 0xe6999d}, /* U+665D */ + {0xdaed, 0xe699a4}, /* U+6664 */ + {0xdaee, 0xe699a7}, /* U+6667 */ + {0xdaef, 0xe699a8}, /* U+6668 */ + {0xdaf0, 0xe6999f}, /* U+665F */ + {0xdaf1, 0xe699a2}, /* U+6662 */ + {0xdaf2, 0xe699b0}, /* U+6670 */ + {0xdaf3, 0xe69a83}, /* U+6683 */ + {0xdaf4, 0xe69a88}, /* U+6688 */ + {0xdaf5, 0xe69a8e}, /* U+668E */ + {0xdaf6, 0xe69a89}, /* U+6689 */ + {0xdaf7, 0xe69a84}, /* U+6684 */ + {0xdaf8, 0xe69a98}, /* U+6698 */ + {0xdaf9, 0xe69a9d}, /* U+669D */ + {0xdafa, 0xe69b81}, /* U+66C1 */ + {0xdafb, 0xe69ab9}, /* U+66B9 */ + {0xdafc, 0xe69b89}, /* U+66C9 */ + {0xdafd, 0xe69abe}, /* U+66BE */ + {0xdafe, 0xe69abc}, /* U+66BC */ + {0xdba1, 0xe69b84}, /* U+66C4 */ + {0xdba2, 0xe69ab8}, /* U+66B8 */ + {0xdba3, 0xe69b96}, /* U+66D6 */ + {0xdba4, 0xe69b9a}, /* U+66DA */ + {0xdba5, 0xe69ba0}, /* U+66E0 */ + {0xdba6, 0xe698bf}, /* U+663F */ + {0xdba7, 0xe69ba6}, /* U+66E6 */ + {0xdba8, 0xe69ba9}, /* U+66E9 */ + {0xdba9, 0xe69bb0}, /* U+66F0 */ + {0xdbaa, 0xe69bb5}, /* U+66F5 */ + {0xdbab, 0xe69bb7}, /* U+66F7 */ + {0xdbac, 0xe69c8f}, /* U+670F */ + {0xdbad, 0xe69c96}, /* U+6716 */ + {0xdbae, 0xe69c9e}, /* U+671E */ + {0xdbaf, 0xe69ca6}, /* U+6726 */ + {0xdbb0, 0xe69ca7}, /* U+6727 */ + {0xdbb1, 0xe99cb8}, /* U+9738 */ + {0xdbb2, 0xe69cae}, /* U+672E */ + {0xdbb3, 0xe69cbf}, /* U+673F */ + {0xdbb4, 0xe69cb6}, /* U+6736 */ + {0xdbb5, 0xe69d81}, /* U+6741 */ + {0xdbb6, 0xe69cb8}, /* U+6738 */ + {0xdbb7, 0xe69cb7}, /* U+6737 */ + {0xdbb8, 0xe69d86}, /* U+6746 */ + {0xdbb9, 0xe69d9e}, /* U+675E */ + {0xdbba, 0xe69da0}, /* U+6760 */ + {0xdbbb, 0xe69d99}, /* U+6759 */ + {0xdbbc, 0xe69da3}, /* U+6763 */ + {0xdbbd, 0xe69da4}, /* U+6764 */ + {0xdbbe, 0xe69e89}, /* U+6789 */ + {0xdbbf, 0xe69db0}, /* U+6770 */ + {0xdbc0, 0xe69ea9}, /* U+67A9 */ + {0xdbc1, 0xe69dbc}, /* U+677C */ + {0xdbc2, 0xe69daa}, /* U+676A */ + {0xdbc3, 0xe69e8c}, /* U+678C */ + {0xdbc4, 0xe69e8b}, /* U+678B */ + {0xdbc5, 0xe69ea6}, /* U+67A6 */ + {0xdbc6, 0xe69ea1}, /* U+67A1 */ + {0xdbc7, 0xe69e85}, /* U+6785 */ + {0xdbc8, 0xe69eb7}, /* U+67B7 */ + {0xdbc9, 0xe69faf}, /* U+67EF */ + {0xdbca, 0xe69eb4}, /* U+67B4 */ + {0xdbcb, 0xe69fac}, /* U+67EC */ + {0xdbcc, 0xe69eb3}, /* U+67B3 */ + {0xdbcd, 0xe69fa9}, /* U+67E9 */ + {0xdbce, 0xe69eb8}, /* U+67B8 */ + {0xdbcf, 0xe69fa4}, /* U+67E4 */ + {0xdbd0, 0xe69f9e}, /* U+67DE */ + {0xdbd1, 0xe69f9d}, /* U+67DD */ + {0xdbd2, 0xe69fa2}, /* U+67E2 */ + {0xdbd3, 0xe69fae}, /* U+67EE */ + {0xdbd4, 0xe69eb9}, /* U+67B9 */ + {0xdbd5, 0xe69f8e}, /* U+67CE */ + {0xdbd6, 0xe69f86}, /* U+67C6 */ + {0xdbd7, 0xe69fa7}, /* U+67E7 */ + {0xdbd8, 0xe6aa9c}, /* U+6A9C */ + {0xdbd9, 0xe6a09e}, /* U+681E */ + {0xdbda, 0xe6a186}, /* U+6846 */ + {0xdbdb, 0xe6a0a9}, /* U+6829 */ + {0xdbdc, 0xe6a180}, /* U+6840 */ + {0xdbdd, 0xe6a18d}, /* U+684D */ + {0xdbde, 0xe6a0b2}, /* U+6832 */ + {0xdbdf, 0xe6a18e}, /* U+684E */ + {0xdbe0, 0xe6a2b3}, /* U+68B3 */ + {0xdbe1, 0xe6a0ab}, /* U+682B */ + {0xdbe2, 0xe6a199}, /* U+6859 */ + {0xdbe3, 0xe6a1a3}, /* U+6863 */ + {0xdbe4, 0xe6a1b7}, /* U+6877 */ + {0xdbe5, 0xe6a1bf}, /* U+687F */ + {0xdbe6, 0xe6a29f}, /* U+689F */ + {0xdbe7, 0xe6a28f}, /* U+688F */ + {0xdbe8, 0xe6a2ad}, /* U+68AD */ + {0xdbe9, 0xe6a294}, /* U+6894 */ + {0xdbea, 0xe6a29d}, /* U+689D */ + {0xdbeb, 0xe6a29b}, /* U+689B */ + {0xdbec, 0xe6a283}, /* U+6883 */ + {0xdbed, 0xe6aaae}, /* U+6AAE */ + {0xdbee, 0xe6a2b9}, /* U+68B9 */ + {0xdbef, 0xe6a1b4}, /* U+6874 */ + {0xdbf0, 0xe6a2b5}, /* U+68B5 */ + {0xdbf1, 0xe6a2a0}, /* U+68A0 */ + {0xdbf2, 0xe6a2ba}, /* U+68BA */ + {0xdbf3, 0xe6a48f}, /* U+690F */ + {0xdbf4, 0xe6a28d}, /* U+688D */ + {0xdbf5, 0xe6a1be}, /* U+687E */ + {0xdbf6, 0xe6a481}, /* U+6901 */ + {0xdbf7, 0xe6a38a}, /* U+68CA */ + {0xdbf8, 0xe6a488}, /* U+6908 */ + {0xdbf9, 0xe6a398}, /* U+68D8 */ + {0xdbfa, 0xe6a4a2}, /* U+6922 */ + {0xdbfb, 0xe6a4a6}, /* U+6926 */ + {0xdbfc, 0xe6a3a1}, /* U+68E1 */ + {0xdbfd, 0xe6a48c}, /* U+690C */ + {0xdbfe, 0xe6a38d}, /* U+68CD */ + {0xdca1, 0xe6a394}, /* U+68D4 */ + {0xdca2, 0xe6a3a7}, /* U+68E7 */ + {0xdca3, 0xe6a395}, /* U+68D5 */ + {0xdca4, 0xe6a4b6}, /* U+6936 */ + {0xdca5, 0xe6a492}, /* U+6912 */ + {0xdca6, 0xe6a484}, /* U+6904 */ + {0xdca7, 0xe6a397}, /* U+68D7 */ + {0xdca8, 0xe6a3a3}, /* U+68E3 */ + {0xdca9, 0xe6a4a5}, /* U+6925 */ + {0xdcaa, 0xe6a3b9}, /* U+68F9 */ + {0xdcab, 0xe6a3a0}, /* U+68E0 */ + {0xdcac, 0xe6a3af}, /* U+68EF */ + {0xdcad, 0xe6a4a8}, /* U+6928 */ + {0xdcae, 0xe6a4aa}, /* U+692A */ + {0xdcaf, 0xe6a49a}, /* U+691A */ + {0xdcb0, 0xe6a4a3}, /* U+6923 */ + {0xdcb1, 0xe6a4a1}, /* U+6921 */ + {0xdcb2, 0xe6a386}, /* U+68C6 */ + {0xdcb3, 0xe6a5b9}, /* U+6979 */ + {0xdcb4, 0xe6a5b7}, /* U+6977 */ + {0xdcb5, 0xe6a59c}, /* U+695C */ + {0xdcb6, 0xe6a5b8}, /* U+6978 */ + {0xdcb7, 0xe6a5ab}, /* U+696B */ + {0xdcb8, 0xe6a594}, /* U+6954 */ + {0xdcb9, 0xe6a5be}, /* U+697E */ + {0xdcba, 0xe6a5ae}, /* U+696E */ + {0xdcbb, 0xe6a4b9}, /* U+6939 */ + {0xdcbc, 0xe6a5b4}, /* U+6974 */ + {0xdcbd, 0xe6a4bd}, /* U+693D */ + {0xdcbe, 0xe6a599}, /* U+6959 */ + {0xdcbf, 0xe6a4b0}, /* U+6930 */ + {0xdcc0, 0xe6a5a1}, /* U+6961 */ + {0xdcc1, 0xe6a59e}, /* U+695E */ + {0xdcc2, 0xe6a59d}, /* U+695D */ + {0xdcc3, 0xe6a681}, /* U+6981 */ + {0xdcc4, 0xe6a5aa}, /* U+696A */ + {0xdcc5, 0xe6a6b2}, /* U+69B2 */ + {0xdcc6, 0xe6a6ae}, /* U+69AE */ + {0xdcc7, 0xe6a790}, /* U+69D0 */ + {0xdcc8, 0xe6a6bf}, /* U+69BF */ + {0xdcc9, 0xe6a781}, /* U+69C1 */ + {0xdcca, 0xe6a793}, /* U+69D3 */ + {0xdccb, 0xe6a6be}, /* U+69BE */ + {0xdccc, 0xe6a78e}, /* U+69CE */ + {0xdccd, 0xe5afa8}, /* U+5BE8 */ + {0xdcce, 0xe6a78a}, /* U+69CA */ + {0xdccf, 0xe6a79d}, /* U+69DD */ + {0xdcd0, 0xe6a6bb}, /* U+69BB */ + {0xdcd1, 0xe6a783}, /* U+69C3 */ + {0xdcd2, 0xe6a6a7}, /* U+69A7 */ + {0xdcd3, 0xe6a8ae}, /* U+6A2E */ + {0xdcd4, 0xe6a691}, /* U+6991 */ + {0xdcd5, 0xe6a6a0}, /* U+69A0 */ + {0xdcd6, 0xe6a69c}, /* U+699C */ + {0xdcd7, 0xe6a695}, /* U+6995 */ + {0xdcd8, 0xe6a6b4}, /* U+69B4 */ + {0xdcd9, 0xe6a79e}, /* U+69DE */ + {0xdcda, 0xe6a7a8}, /* U+69E8 */ + {0xdcdb, 0xe6a882}, /* U+6A02 */ + {0xdcdc, 0xe6a89b}, /* U+6A1B */ + {0xdcdd, 0xe6a7bf}, /* U+69FF */ + {0xdcde, 0xe6ac8a}, /* U+6B0A */ + {0xdcdf, 0xe6a7b9}, /* U+69F9 */ + {0xdce0, 0xe6a7b2}, /* U+69F2 */ + {0xdce1, 0xe6a7a7}, /* U+69E7 */ + {0xdce2, 0xe6a885}, /* U+6A05 */ + {0xdce3, 0xe6a6b1}, /* U+69B1 */ + {0xdce4, 0xe6a89e}, /* U+6A1E */ + {0xdce5, 0xe6a7ad}, /* U+69ED */ + {0xdce6, 0xe6a894}, /* U+6A14 */ + {0xdce7, 0xe6a7ab}, /* U+69EB */ + {0xdce8, 0xe6a88a}, /* U+6A0A */ + {0xdce9, 0xe6a892}, /* U+6A12 */ + {0xdcea, 0xe6ab81}, /* U+6AC1 */ + {0xdceb, 0xe6a8a3}, /* U+6A23 */ + {0xdcec, 0xe6a893}, /* U+6A13 */ + {0xdced, 0xe6a984}, /* U+6A44 */ + {0xdcee, 0xe6a88c}, /* U+6A0C */ + {0xdcef, 0xe6a9b2}, /* U+6A72 */ + {0xdcf0, 0xe6a8b6}, /* U+6A36 */ + {0xdcf1, 0xe6a9b8}, /* U+6A78 */ + {0xdcf2, 0xe6a987}, /* U+6A47 */ + {0xdcf3, 0xe6a9a2}, /* U+6A62 */ + {0xdcf4, 0xe6a999}, /* U+6A59 */ + {0xdcf5, 0xe6a9a6}, /* U+6A66 */ + {0xdcf6, 0xe6a988}, /* U+6A48 */ + {0xdcf7, 0xe6a8b8}, /* U+6A38 */ + {0xdcf8, 0xe6a8a2}, /* U+6A22 */ + {0xdcf9, 0xe6aa90}, /* U+6A90 */ + {0xdcfa, 0xe6aa8d}, /* U+6A8D */ + {0xdcfb, 0xe6aaa0}, /* U+6AA0 */ + {0xdcfc, 0xe6aa84}, /* U+6A84 */ + {0xdcfd, 0xe6aaa2}, /* U+6AA2 */ + {0xdcfe, 0xe6aaa3}, /* U+6AA3 */ + {0xdda1, 0xe6aa97}, /* U+6A97 */ + {0xdda2, 0xe89897}, /* U+8617 */ + {0xdda3, 0xe6aabb}, /* U+6ABB */ + {0xdda4, 0xe6ab83}, /* U+6AC3 */ + {0xdda5, 0xe6ab82}, /* U+6AC2 */ + {0xdda6, 0xe6aab8}, /* U+6AB8 */ + {0xdda7, 0xe6aab3}, /* U+6AB3 */ + {0xdda8, 0xe6aaac}, /* U+6AAC */ + {0xdda9, 0xe6ab9e}, /* U+6ADE */ + {0xddaa, 0xe6ab91}, /* U+6AD1 */ + {0xddab, 0xe6ab9f}, /* U+6ADF */ + {0xddac, 0xe6aaaa}, /* U+6AAA */ + {0xddad, 0xe6ab9a}, /* U+6ADA */ + {0xddae, 0xe6abaa}, /* U+6AEA */ + {0xddaf, 0xe6abbb}, /* U+6AFB */ + {0xddb0, 0xe6ac85}, /* U+6B05 */ + {0xddb1, 0xe89896}, /* U+8616 */ + {0xddb2, 0xe6abba}, /* U+6AFA */ + {0xddb3, 0xe6ac92}, /* U+6B12 */ + {0xddb4, 0xe6ac96}, /* U+6B16 */ + {0xddb5, 0xe9acb1}, /* U+9B31 */ + {0xddb6, 0xe6ac9f}, /* U+6B1F */ + {0xddb7, 0xe6acb8}, /* U+6B38 */ + {0xddb8, 0xe6acb7}, /* U+6B37 */ + {0xddb9, 0xe79b9c}, /* U+76DC */ + {0xddba, 0xe6acb9}, /* U+6B39 */ + {0xddbb, 0xe9a3ae}, /* U+98EE */ + {0xddbc, 0xe6ad87}, /* U+6B47 */ + {0xddbd, 0xe6ad83}, /* U+6B43 */ + {0xddbe, 0xe6ad89}, /* U+6B49 */ + {0xddbf, 0xe6ad90}, /* U+6B50 */ + {0xddc0, 0xe6ad99}, /* U+6B59 */ + {0xddc1, 0xe6ad94}, /* U+6B54 */ + {0xddc2, 0xe6ad9b}, /* U+6B5B */ + {0xddc3, 0xe6ad9f}, /* U+6B5F */ + {0xddc4, 0xe6ada1}, /* U+6B61 */ + {0xddc5, 0xe6adb8}, /* U+6B78 */ + {0xddc6, 0xe6adb9}, /* U+6B79 */ + {0xddc7, 0xe6adbf}, /* U+6B7F */ + {0xddc8, 0xe6ae80}, /* U+6B80 */ + {0xddc9, 0xe6ae84}, /* U+6B84 */ + {0xddca, 0xe6ae83}, /* U+6B83 */ + {0xddcb, 0xe6ae8d}, /* U+6B8D */ + {0xddcc, 0xe6ae98}, /* U+6B98 */ + {0xddcd, 0xe6ae95}, /* U+6B95 */ + {0xddce, 0xe6ae9e}, /* U+6B9E */ + {0xddcf, 0xe6aea4}, /* U+6BA4 */ + {0xddd0, 0xe6aeaa}, /* U+6BAA */ + {0xddd1, 0xe6aeab}, /* U+6BAB */ + {0xddd2, 0xe6aeaf}, /* U+6BAF */ + {0xddd3, 0xe6aeb2}, /* U+6BB2 */ + {0xddd4, 0xe6aeb1}, /* U+6BB1 */ + {0xddd5, 0xe6aeb3}, /* U+6BB3 */ + {0xddd6, 0xe6aeb7}, /* U+6BB7 */ + {0xddd7, 0xe6aebc}, /* U+6BBC */ + {0xddd8, 0xe6af86}, /* U+6BC6 */ + {0xddd9, 0xe6af8b}, /* U+6BCB */ + {0xddda, 0xe6af93}, /* U+6BD3 */ + {0xdddb, 0xe6af9f}, /* U+6BDF */ + {0xdddc, 0xe6afac}, /* U+6BEC */ + {0xdddd, 0xe6afab}, /* U+6BEB */ + {0xddde, 0xe6afb3}, /* U+6BF3 */ + {0xdddf, 0xe6afaf}, /* U+6BEF */ + {0xdde0, 0xe9babe}, /* U+9EBE */ + {0xdde1, 0xe6b088}, /* U+6C08 */ + {0xdde2, 0xe6b093}, /* U+6C13 */ + {0xdde3, 0xe6b094}, /* U+6C14 */ + {0xdde4, 0xe6b09b}, /* U+6C1B */ + {0xdde5, 0xe6b0a4}, /* U+6C24 */ + {0xdde6, 0xe6b0a3}, /* U+6C23 */ + {0xdde7, 0xe6b19e}, /* U+6C5E */ + {0xdde8, 0xe6b195}, /* U+6C55 */ + {0xdde9, 0xe6b1a2}, /* U+6C62 */ + {0xddea, 0xe6b1aa}, /* U+6C6A */ + {0xddeb, 0xe6b282}, /* U+6C82 */ + {0xddec, 0xe6b28d}, /* U+6C8D */ + {0xdded, 0xe6b29a}, /* U+6C9A */ + {0xddee, 0xe6b281}, /* U+6C81 */ + {0xddef, 0xe6b29b}, /* U+6C9B */ + {0xddf0, 0xe6b1be}, /* U+6C7E */ + {0xddf1, 0xe6b1a8}, /* U+6C68 */ + {0xddf2, 0xe6b1b3}, /* U+6C73 */ + {0xddf3, 0xe6b292}, /* U+6C92 */ + {0xddf4, 0xe6b290}, /* U+6C90 */ + {0xddf5, 0xe6b384}, /* U+6CC4 */ + {0xddf6, 0xe6b3b1}, /* U+6CF1 */ + {0xddf7, 0xe6b393}, /* U+6CD3 */ + {0xddf8, 0xe6b2bd}, /* U+6CBD */ + {0xddf9, 0xe6b397}, /* U+6CD7 */ + {0xddfa, 0xe6b385}, /* U+6CC5 */ + {0xddfb, 0xe6b39d}, /* U+6CDD */ + {0xddfc, 0xe6b2ae}, /* U+6CAE */ + {0xddfd, 0xe6b2b1}, /* U+6CB1 */ + {0xddfe, 0xe6b2be}, /* U+6CBE */ + {0xdea1, 0xe6b2ba}, /* U+6CBA */ + {0xdea2, 0xe6b39b}, /* U+6CDB */ + {0xdea3, 0xe6b3af}, /* U+6CEF */ + {0xdea4, 0xe6b399}, /* U+6CD9 */ + {0xdea5, 0xe6b3aa}, /* U+6CEA */ + {0xdea6, 0xe6b49f}, /* U+6D1F */ + {0xdea7, 0xe8a18d}, /* U+884D */ + {0xdea8, 0xe6b4b6}, /* U+6D36 */ + {0xdea9, 0xe6b4ab}, /* U+6D2B */ + {0xdeaa, 0xe6b4bd}, /* U+6D3D */ + {0xdeab, 0xe6b4b8}, /* U+6D38 */ + {0xdeac, 0xe6b499}, /* U+6D19 */ + {0xdead, 0xe6b4b5}, /* U+6D35 */ + {0xdeae, 0xe6b4b3}, /* U+6D33 */ + {0xdeaf, 0xe6b492}, /* U+6D12 */ + {0xdeb0, 0xe6b48c}, /* U+6D0C */ + {0xdeb1, 0xe6b5a3}, /* U+6D63 */ + {0xdeb2, 0xe6b693}, /* U+6D93 */ + {0xdeb3, 0xe6b5a4}, /* U+6D64 */ + {0xdeb4, 0xe6b59a}, /* U+6D5A */ + {0xdeb5, 0xe6b5b9}, /* U+6D79 */ + {0xdeb6, 0xe6b599}, /* U+6D59 */ + {0xdeb7, 0xe6b68e}, /* U+6D8E */ + {0xdeb8, 0xe6b695}, /* U+6D95 */ + {0xdeb9, 0xe6bfa4}, /* U+6FE4 */ + {0xdeba, 0xe6b685}, /* U+6D85 */ + {0xdebb, 0xe6b7b9}, /* U+6DF9 */ + {0xdebc, 0xe6b895}, /* U+6E15 */ + {0xdebd, 0xe6b88a}, /* U+6E0A */ + {0xdebe, 0xe6b6b5}, /* U+6DB5 */ + {0xdebf, 0xe6b787}, /* U+6DC7 */ + {0xdec0, 0xe6b7a6}, /* U+6DE6 */ + {0xdec1, 0xe6b6b8}, /* U+6DB8 */ + {0xdec2, 0xe6b786}, /* U+6DC6 */ + {0xdec3, 0xe6b7ac}, /* U+6DEC */ + {0xdec4, 0xe6b79e}, /* U+6DDE */ + {0xdec5, 0xe6b78c}, /* U+6DCC */ + {0xdec6, 0xe6b7a8}, /* U+6DE8 */ + {0xdec7, 0xe6b792}, /* U+6DD2 */ + {0xdec8, 0xe6b785}, /* U+6DC5 */ + {0xdec9, 0xe6b7ba}, /* U+6DFA */ + {0xdeca, 0xe6b799}, /* U+6DD9 */ + {0xdecb, 0xe6b7a4}, /* U+6DE4 */ + {0xdecc, 0xe6b795}, /* U+6DD5 */ + {0xdecd, 0xe6b7aa}, /* U+6DEA */ + {0xdece, 0xe6b7ae}, /* U+6DEE */ + {0xdecf, 0xe6b8ad}, /* U+6E2D */ + {0xded0, 0xe6b9ae}, /* U+6E6E */ + {0xded1, 0xe6b8ae}, /* U+6E2E */ + {0xded2, 0xe6b899}, /* U+6E19 */ + {0xded3, 0xe6b9b2}, /* U+6E72 */ + {0xded4, 0xe6b99f}, /* U+6E5F */ + {0xded5, 0xe6b8be}, /* U+6E3E */ + {0xded6, 0xe6b8a3}, /* U+6E23 */ + {0xded7, 0xe6b9ab}, /* U+6E6B */ + {0xded8, 0xe6b8ab}, /* U+6E2B */ + {0xded9, 0xe6b9b6}, /* U+6E76 */ + {0xdeda, 0xe6b98d}, /* U+6E4D */ + {0xdedb, 0xe6b89f}, /* U+6E1F */ + {0xdedc, 0xe6b983}, /* U+6E43 */ + {0xdedd, 0xe6b8ba}, /* U+6E3A */ + {0xdede, 0xe6b98e}, /* U+6E4E */ + {0xdedf, 0xe6b8a4}, /* U+6E24 */ + {0xdee0, 0xe6bbbf}, /* U+6EFF */ + {0xdee1, 0xe6b89d}, /* U+6E1D */ + {0xdee2, 0xe6b8b8}, /* U+6E38 */ + {0xdee3, 0xe6ba82}, /* U+6E82 */ + {0xdee4, 0xe6baaa}, /* U+6EAA */ + {0xdee5, 0xe6ba98}, /* U+6E98 */ + {0xdee6, 0xe6bb89}, /* U+6EC9 */ + {0xdee7, 0xe6bab7}, /* U+6EB7 */ + {0xdee8, 0xe6bb93}, /* U+6ED3 */ + {0xdee9, 0xe6babd}, /* U+6EBD */ + {0xdeea, 0xe6baaf}, /* U+6EAF */ + {0xdeeb, 0xe6bb84}, /* U+6EC4 */ + {0xdeec, 0xe6bab2}, /* U+6EB2 */ + {0xdeed, 0xe6bb94}, /* U+6ED4 */ + {0xdeee, 0xe6bb95}, /* U+6ED5 */ + {0xdeef, 0xe6ba8f}, /* U+6E8F */ + {0xdef0, 0xe6baa5}, /* U+6EA5 */ + {0xdef1, 0xe6bb82}, /* U+6EC2 */ + {0xdef2, 0xe6ba9f}, /* U+6E9F */ + {0xdef3, 0xe6bd81}, /* U+6F41 */ + {0xdef4, 0xe6bc91}, /* U+6F11 */ + {0xdef5, 0xe7818c}, /* U+704C */ + {0xdef6, 0xe6bbac}, /* U+6EEC */ + {0xdef7, 0xe6bbb8}, /* U+6EF8 */ + {0xdef8, 0xe6bbbe}, /* U+6EFE */ + {0xdef9, 0xe6bcbf}, /* U+6F3F */ + {0xdefa, 0xe6bbb2}, /* U+6EF2 */ + {0xdefb, 0xe6bcb1}, /* U+6F31 */ + {0xdefc, 0xe6bbaf}, /* U+6EEF */ + {0xdefd, 0xe6bcb2}, /* U+6F32 */ + {0xdefe, 0xe6bb8c}, /* U+6ECC */ + {0xdfa1, 0xe6bcbe}, /* U+6F3E */ + {0xdfa2, 0xe6bc93}, /* U+6F13 */ + {0xdfa3, 0xe6bbb7}, /* U+6EF7 */ + {0xdfa4, 0xe6be86}, /* U+6F86 */ + {0xdfa5, 0xe6bdba}, /* U+6F7A */ + {0xdfa6, 0xe6bdb8}, /* U+6F78 */ + {0xdfa7, 0xe6be81}, /* U+6F81 */ + {0xdfa8, 0xe6be80}, /* U+6F80 */ + {0xdfa9, 0xe6bdaf}, /* U+6F6F */ + {0xdfaa, 0xe6bd9b}, /* U+6F5B */ + {0xdfab, 0xe6bfb3}, /* U+6FF3 */ + {0xdfac, 0xe6bdad}, /* U+6F6D */ + {0xdfad, 0xe6be82}, /* U+6F82 */ + {0xdfae, 0xe6bdbc}, /* U+6F7C */ + {0xdfaf, 0xe6bd98}, /* U+6F58 */ + {0xdfb0, 0xe6be8e}, /* U+6F8E */ + {0xdfb1, 0xe6be91}, /* U+6F91 */ + {0xdfb2, 0xe6bf82}, /* U+6FC2 */ + {0xdfb3, 0xe6bda6}, /* U+6F66 */ + {0xdfb4, 0xe6beb3}, /* U+6FB3 */ + {0xdfb5, 0xe6bea3}, /* U+6FA3 */ + {0xdfb6, 0xe6bea1}, /* U+6FA1 */ + {0xdfb7, 0xe6bea4}, /* U+6FA4 */ + {0xdfb8, 0xe6beb9}, /* U+6FB9 */ + {0xdfb9, 0xe6bf86}, /* U+6FC6 */ + {0xdfba, 0xe6beaa}, /* U+6FAA */ + {0xdfbb, 0xe6bf9f}, /* U+6FDF */ + {0xdfbc, 0xe6bf95}, /* U+6FD5 */ + {0xdfbd, 0xe6bfac}, /* U+6FEC */ + {0xdfbe, 0xe6bf94}, /* U+6FD4 */ + {0xdfbf, 0xe6bf98}, /* U+6FD8 */ + {0xdfc0, 0xe6bfb1}, /* U+6FF1 */ + {0xdfc1, 0xe6bfae}, /* U+6FEE */ + {0xdfc2, 0xe6bf9b}, /* U+6FDB */ + {0xdfc3, 0xe78089}, /* U+7009 */ + {0xdfc4, 0xe7808b}, /* U+700B */ + {0xdfc5, 0xe6bfba}, /* U+6FFA */ + {0xdfc6, 0xe78091}, /* U+7011 */ + {0xdfc7, 0xe78081}, /* U+7001 */ + {0xdfc8, 0xe7808f}, /* U+700F */ + {0xdfc9, 0xe6bfbe}, /* U+6FFE */ + {0xdfca, 0xe7809b}, /* U+701B */ + {0xdfcb, 0xe7809a}, /* U+701A */ + {0xdfcc, 0xe6bdb4}, /* U+6F74 */ + {0xdfcd, 0xe7809d}, /* U+701D */ + {0xdfce, 0xe78098}, /* U+7018 */ + {0xdfcf, 0xe7809f}, /* U+701F */ + {0xdfd0, 0xe780b0}, /* U+7030 */ + {0xdfd1, 0xe780be}, /* U+703E */ + {0xdfd2, 0xe780b2}, /* U+7032 */ + {0xdfd3, 0xe78191}, /* U+7051 */ + {0xdfd4, 0xe781a3}, /* U+7063 */ + {0xdfd5, 0xe78299}, /* U+7099 */ + {0xdfd6, 0xe78292}, /* U+7092 */ + {0xdfd7, 0xe782af}, /* U+70AF */ + {0xdfd8, 0xe783b1}, /* U+70F1 */ + {0xdfd9, 0xe782ac}, /* U+70AC */ + {0xdfda, 0xe782b8}, /* U+70B8 */ + {0xdfdb, 0xe782b3}, /* U+70B3 */ + {0xdfdc, 0xe782ae}, /* U+70AE */ + {0xdfdd, 0xe7839f}, /* U+70DF */ + {0xdfde, 0xe7838b}, /* U+70CB */ + {0xdfdf, 0xe7839d}, /* U+70DD */ + {0xdfe0, 0xe78399}, /* U+70D9 */ + {0xdfe1, 0xe78489}, /* U+7109 */ + {0xdfe2, 0xe783bd}, /* U+70FD */ + {0xdfe3, 0xe7849c}, /* U+711C */ + {0xdfe4, 0xe78499}, /* U+7119 */ + {0xdfe5, 0xe785a5}, /* U+7165 */ + {0xdfe6, 0xe78595}, /* U+7155 */ + {0xdfe7, 0xe78688}, /* U+7188 */ + {0xdfe8, 0xe785a6}, /* U+7166 */ + {0xdfe9, 0xe785a2}, /* U+7162 */ + {0xdfea, 0xe7858c}, /* U+714C */ + {0xdfeb, 0xe78596}, /* U+7156 */ + {0xdfec, 0xe785ac}, /* U+716C */ + {0xdfed, 0xe7868f}, /* U+718F */ + {0xdfee, 0xe787bb}, /* U+71FB */ + {0xdfef, 0xe78684}, /* U+7184 */ + {0xdff0, 0xe78695}, /* U+7195 */ + {0xdff1, 0xe786a8}, /* U+71A8 */ + {0xdff2, 0xe786ac}, /* U+71AC */ + {0xdff3, 0xe78797}, /* U+71D7 */ + {0xdff4, 0xe786b9}, /* U+71B9 */ + {0xdff5, 0xe786be}, /* U+71BE */ + {0xdff6, 0xe78792}, /* U+71D2 */ + {0xdff7, 0xe78789}, /* U+71C9 */ + {0xdff8, 0xe78794}, /* U+71D4 */ + {0xdff9, 0xe7878e}, /* U+71CE */ + {0xdffa, 0xe787a0}, /* U+71E0 */ + {0xdffb, 0xe787ac}, /* U+71EC */ + {0xdffc, 0xe787a7}, /* U+71E7 */ + {0xdffd, 0xe787b5}, /* U+71F5 */ + {0xdffe, 0xe787bc}, /* U+71FC */ + {0xe0a1, 0xe787b9}, /* U+71F9 */ + {0xe0a2, 0xe787bf}, /* U+71FF */ + {0xe0a3, 0xe7888d}, /* U+720D */ + {0xe0a4, 0xe78890}, /* U+7210 */ + {0xe0a5, 0xe7889b}, /* U+721B */ + {0xe0a6, 0xe788a8}, /* U+7228 */ + {0xe0a7, 0xe788ad}, /* U+722D */ + {0xe0a8, 0xe788ac}, /* U+722C */ + {0xe0a9, 0xe788b0}, /* U+7230 */ + {0xe0aa, 0xe788b2}, /* U+7232 */ + {0xe0ab, 0xe788bb}, /* U+723B */ + {0xe0ac, 0xe788bc}, /* U+723C */ + {0xe0ad, 0xe788bf}, /* U+723F */ + {0xe0ae, 0xe78980}, /* U+7240 */ + {0xe0af, 0xe78986}, /* U+7246 */ + {0xe0b0, 0xe7898b}, /* U+724B */ + {0xe0b1, 0xe78998}, /* U+7258 */ + {0xe0b2, 0xe789b4}, /* U+7274 */ + {0xe0b3, 0xe789be}, /* U+727E */ + {0xe0b4, 0xe78a82}, /* U+7282 */ + {0xe0b5, 0xe78a81}, /* U+7281 */ + {0xe0b6, 0xe78a87}, /* U+7287 */ + {0xe0b7, 0xe78a92}, /* U+7292 */ + {0xe0b8, 0xe78a96}, /* U+7296 */ + {0xe0b9, 0xe78aa2}, /* U+72A2 */ + {0xe0ba, 0xe78aa7}, /* U+72A7 */ + {0xe0bb, 0xe78ab9}, /* U+72B9 */ + {0xe0bc, 0xe78ab2}, /* U+72B2 */ + {0xe0bd, 0xe78b83}, /* U+72C3 */ + {0xe0be, 0xe78b86}, /* U+72C6 */ + {0xe0bf, 0xe78b84}, /* U+72C4 */ + {0xe0c0, 0xe78b8e}, /* U+72CE */ + {0xe0c1, 0xe78b92}, /* U+72D2 */ + {0xe0c2, 0xe78ba2}, /* U+72E2 */ + {0xe0c3, 0xe78ba0}, /* U+72E0 */ + {0xe0c4, 0xe78ba1}, /* U+72E1 */ + {0xe0c5, 0xe78bb9}, /* U+72F9 */ + {0xe0c6, 0xe78bb7}, /* U+72F7 */ + {0xe0c7, 0xe5808f}, /* U+500F */ + {0xe0c8, 0xe78c97}, /* U+7317 */ + {0xe0c9, 0xe78c8a}, /* U+730A */ + {0xe0ca, 0xe78c9c}, /* U+731C */ + {0xe0cb, 0xe78c96}, /* U+7316 */ + {0xe0cc, 0xe78c9d}, /* U+731D */ + {0xe0cd, 0xe78cb4}, /* U+7334 */ + {0xe0ce, 0xe78caf}, /* U+732F */ + {0xe0cf, 0xe78ca9}, /* U+7329 */ + {0xe0d0, 0xe78ca5}, /* U+7325 */ + {0xe0d1, 0xe78cbe}, /* U+733E */ + {0xe0d2, 0xe78d8e}, /* U+734E */ + {0xe0d3, 0xe78d8f}, /* U+734F */ + {0xe0d4, 0xe9bb98}, /* U+9ED8 */ + {0xe0d5, 0xe78d97}, /* U+7357 */ + {0xe0d6, 0xe78daa}, /* U+736A */ + {0xe0d7, 0xe78da8}, /* U+7368 */ + {0xe0d8, 0xe78db0}, /* U+7370 */ + {0xe0d9, 0xe78db8}, /* U+7378 */ + {0xe0da, 0xe78db5}, /* U+7375 */ + {0xe0db, 0xe78dbb}, /* U+737B */ + {0xe0dc, 0xe78dba}, /* U+737A */ + {0xe0dd, 0xe78f88}, /* U+73C8 */ + {0xe0de, 0xe78eb3}, /* U+73B3 */ + {0xe0df, 0xe78f8e}, /* U+73CE */ + {0xe0e0, 0xe78ebb}, /* U+73BB */ + {0xe0e1, 0xe78f80}, /* U+73C0 */ + {0xe0e2, 0xe78fa5}, /* U+73E5 */ + {0xe0e3, 0xe78fae}, /* U+73EE */ + {0xe0e4, 0xe78f9e}, /* U+73DE */ + {0xe0e5, 0xe792a2}, /* U+74A2 */ + {0xe0e6, 0xe79085}, /* U+7405 */ + {0xe0e7, 0xe791af}, /* U+746F */ + {0xe0e8, 0xe790a5}, /* U+7425 */ + {0xe0e9, 0xe78fb8}, /* U+73F8 */ + {0xe0ea, 0xe790b2}, /* U+7432 */ + {0xe0eb, 0xe790ba}, /* U+743A */ + {0xe0ec, 0xe79195}, /* U+7455 */ + {0xe0ed, 0xe790bf}, /* U+743F */ + {0xe0ee, 0xe7919f}, /* U+745F */ + {0xe0ef, 0xe79199}, /* U+7459 */ + {0xe0f0, 0xe79181}, /* U+7441 */ + {0xe0f1, 0xe7919c}, /* U+745C */ + {0xe0f2, 0xe791a9}, /* U+7469 */ + {0xe0f3, 0xe791b0}, /* U+7470 */ + {0xe0f4, 0xe791a3}, /* U+7463 */ + {0xe0f5, 0xe791aa}, /* U+746A */ + {0xe0f6, 0xe791b6}, /* U+7476 */ + {0xe0f7, 0xe791be}, /* U+747E */ + {0xe0f8, 0xe7928b}, /* U+748B */ + {0xe0f9, 0xe7929e}, /* U+749E */ + {0xe0fa, 0xe792a7}, /* U+74A7 */ + {0xe0fb, 0xe7938a}, /* U+74CA */ + {0xe0fc, 0xe7938f}, /* U+74CF */ + {0xe0fd, 0xe79394}, /* U+74D4 */ + {0xe0fe, 0xe78fb1}, /* U+73F1 */ + {0xe1a1, 0xe793a0}, /* U+74E0 */ + {0xe1a2, 0xe793a3}, /* U+74E3 */ + {0xe1a3, 0xe793a7}, /* U+74E7 */ + {0xe1a4, 0xe793a9}, /* U+74E9 */ + {0xe1a5, 0xe793ae}, /* U+74EE */ + {0xe1a6, 0xe793b2}, /* U+74F2 */ + {0xe1a7, 0xe793b0}, /* U+74F0 */ + {0xe1a8, 0xe793b1}, /* U+74F1 */ + {0xe1a9, 0xe793b8}, /* U+74F8 */ + {0xe1aa, 0xe793b7}, /* U+74F7 */ + {0xe1ab, 0xe79484}, /* U+7504 */ + {0xe1ac, 0xe79483}, /* U+7503 */ + {0xe1ad, 0xe79485}, /* U+7505 */ + {0xe1ae, 0xe7948c}, /* U+750C */ + {0xe1af, 0xe7948e}, /* U+750E */ + {0xe1b0, 0xe7948d}, /* U+750D */ + {0xe1b1, 0xe79495}, /* U+7515 */ + {0xe1b2, 0xe79493}, /* U+7513 */ + {0xe1b3, 0xe7949e}, /* U+751E */ + {0xe1b4, 0xe794a6}, /* U+7526 */ + {0xe1b5, 0xe794ac}, /* U+752C */ + {0xe1b6, 0xe794bc}, /* U+753C */ + {0xe1b7, 0xe79584}, /* U+7544 */ + {0xe1b8, 0xe7958d}, /* U+754D */ + {0xe1b9, 0xe7958a}, /* U+754A */ + {0xe1ba, 0xe79589}, /* U+7549 */ + {0xe1bb, 0xe7959b}, /* U+755B */ + {0xe1bc, 0xe79586}, /* U+7546 */ + {0xe1bd, 0xe7959a}, /* U+755A */ + {0xe1be, 0xe795a9}, /* U+7569 */ + {0xe1bf, 0xe795a4}, /* U+7564 */ + {0xe1c0, 0xe795a7}, /* U+7567 */ + {0xe1c1, 0xe795ab}, /* U+756B */ + {0xe1c2, 0xe795ad}, /* U+756D */ + {0xe1c3, 0xe795b8}, /* U+7578 */ + {0xe1c4, 0xe795b6}, /* U+7576 */ + {0xe1c5, 0xe79686}, /* U+7586 */ + {0xe1c6, 0xe79687}, /* U+7587 */ + {0xe1c7, 0xe795b4}, /* U+7574 */ + {0xe1c8, 0xe7968a}, /* U+758A */ + {0xe1c9, 0xe79689}, /* U+7589 */ + {0xe1ca, 0xe79682}, /* U+7582 */ + {0xe1cb, 0xe79694}, /* U+7594 */ + {0xe1cc, 0xe7969a}, /* U+759A */ + {0xe1cd, 0xe7969d}, /* U+759D */ + {0xe1ce, 0xe796a5}, /* U+75A5 */ + {0xe1cf, 0xe796a3}, /* U+75A3 */ + {0xe1d0, 0xe79782}, /* U+75C2 */ + {0xe1d1, 0xe796b3}, /* U+75B3 */ + {0xe1d2, 0xe79783}, /* U+75C3 */ + {0xe1d3, 0xe796b5}, /* U+75B5 */ + {0xe1d4, 0xe796bd}, /* U+75BD */ + {0xe1d5, 0xe796b8}, /* U+75B8 */ + {0xe1d6, 0xe796bc}, /* U+75BC */ + {0xe1d7, 0xe796b1}, /* U+75B1 */ + {0xe1d8, 0xe7978d}, /* U+75CD */ + {0xe1d9, 0xe7978a}, /* U+75CA */ + {0xe1da, 0xe79792}, /* U+75D2 */ + {0xe1db, 0xe79799}, /* U+75D9 */ + {0xe1dc, 0xe797a3}, /* U+75E3 */ + {0xe1dd, 0xe7979e}, /* U+75DE */ + {0xe1de, 0xe797be}, /* U+75FE */ + {0xe1df, 0xe797bf}, /* U+75FF */ + {0xe1e0, 0xe797bc}, /* U+75FC */ + {0xe1e1, 0xe79881}, /* U+7601 */ + {0xe1e2, 0xe797b0}, /* U+75F0 */ + {0xe1e3, 0xe797ba}, /* U+75FA */ + {0xe1e4, 0xe797b2}, /* U+75F2 */ + {0xe1e5, 0xe797b3}, /* U+75F3 */ + {0xe1e6, 0xe7988b}, /* U+760B */ + {0xe1e7, 0xe7988d}, /* U+760D */ + {0xe1e8, 0xe79889}, /* U+7609 */ + {0xe1e9, 0xe7989f}, /* U+761F */ + {0xe1ea, 0xe798a7}, /* U+7627 */ + {0xe1eb, 0xe798a0}, /* U+7620 */ + {0xe1ec, 0xe798a1}, /* U+7621 */ + {0xe1ed, 0xe798a2}, /* U+7622 */ + {0xe1ee, 0xe798a4}, /* U+7624 */ + {0xe1ef, 0xe798b4}, /* U+7634 */ + {0xe1f0, 0xe798b0}, /* U+7630 */ + {0xe1f1, 0xe798bb}, /* U+763B */ + {0xe1f2, 0xe79987}, /* U+7647 */ + {0xe1f3, 0xe79988}, /* U+7648 */ + {0xe1f4, 0xe79986}, /* U+7646 */ + {0xe1f5, 0xe7999c}, /* U+765C */ + {0xe1f6, 0xe79998}, /* U+7658 */ + {0xe1f7, 0xe799a1}, /* U+7661 */ + {0xe1f8, 0xe799a2}, /* U+7662 */ + {0xe1f9, 0xe799a8}, /* U+7668 */ + {0xe1fa, 0xe799a9}, /* U+7669 */ + {0xe1fb, 0xe799aa}, /* U+766A */ + {0xe1fc, 0xe799a7}, /* U+7667 */ + {0xe1fd, 0xe799ac}, /* U+766C */ + {0xe1fe, 0xe799b0}, /* U+7670 */ + {0xe2a1, 0xe799b2}, /* U+7672 */ + {0xe2a2, 0xe799b6}, /* U+7676 */ + {0xe2a3, 0xe799b8}, /* U+7678 */ + {0xe2a4, 0xe799bc}, /* U+767C */ + {0xe2a5, 0xe79a80}, /* U+7680 */ + {0xe2a6, 0xe79a83}, /* U+7683 */ + {0xe2a7, 0xe79a88}, /* U+7688 */ + {0xe2a8, 0xe79a8b}, /* U+768B */ + {0xe2a9, 0xe79a8e}, /* U+768E */ + {0xe2aa, 0xe79a96}, /* U+7696 */ + {0xe2ab, 0xe79a93}, /* U+7693 */ + {0xe2ac, 0xe79a99}, /* U+7699 */ + {0xe2ad, 0xe79a9a}, /* U+769A */ + {0xe2ae, 0xe79ab0}, /* U+76B0 */ + {0xe2af, 0xe79ab4}, /* U+76B4 */ + {0xe2b0, 0xe79ab8}, /* U+76B8 */ + {0xe2b1, 0xe79ab9}, /* U+76B9 */ + {0xe2b2, 0xe79aba}, /* U+76BA */ + {0xe2b3, 0xe79b82}, /* U+76C2 */ + {0xe2b4, 0xe79b8d}, /* U+76CD */ + {0xe2b5, 0xe79b96}, /* U+76D6 */ + {0xe2b6, 0xe79b92}, /* U+76D2 */ + {0xe2b7, 0xe79b9e}, /* U+76DE */ + {0xe2b8, 0xe79ba1}, /* U+76E1 */ + {0xe2b9, 0xe79ba5}, /* U+76E5 */ + {0xe2ba, 0xe79ba7}, /* U+76E7 */ + {0xe2bb, 0xe79baa}, /* U+76EA */ + {0xe2bc, 0xe898af}, /* U+862F */ + {0xe2bd, 0xe79bbb}, /* U+76FB */ + {0xe2be, 0xe79c88}, /* U+7708 */ + {0xe2bf, 0xe79c87}, /* U+7707 */ + {0xe2c0, 0xe79c84}, /* U+7704 */ + {0xe2c1, 0xe79ca9}, /* U+7729 */ + {0xe2c2, 0xe79ca4}, /* U+7724 */ + {0xe2c3, 0xe79c9e}, /* U+771E */ + {0xe2c4, 0xe79ca5}, /* U+7725 */ + {0xe2c5, 0xe79ca6}, /* U+7726 */ + {0xe2c6, 0xe79c9b}, /* U+771B */ + {0xe2c7, 0xe79cb7}, /* U+7737 */ + {0xe2c8, 0xe79cb8}, /* U+7738 */ + {0xe2c9, 0xe79d87}, /* U+7747 */ + {0xe2ca, 0xe79d9a}, /* U+775A */ + {0xe2cb, 0xe79da8}, /* U+7768 */ + {0xe2cc, 0xe79dab}, /* U+776B */ + {0xe2cd, 0xe79d9b}, /* U+775B */ + {0xe2ce, 0xe79da5}, /* U+7765 */ + {0xe2cf, 0xe79dbf}, /* U+777F */ + {0xe2d0, 0xe79dbe}, /* U+777E */ + {0xe2d1, 0xe79db9}, /* U+7779 */ + {0xe2d2, 0xe79e8e}, /* U+778E */ + {0xe2d3, 0xe79e8b}, /* U+778B */ + {0xe2d4, 0xe79e91}, /* U+7791 */ + {0xe2d5, 0xe79ea0}, /* U+77A0 */ + {0xe2d6, 0xe79e9e}, /* U+779E */ + {0xe2d7, 0xe79eb0}, /* U+77B0 */ + {0xe2d8, 0xe79eb6}, /* U+77B6 */ + {0xe2d9, 0xe79eb9}, /* U+77B9 */ + {0xe2da, 0xe79ebf}, /* U+77BF */ + {0xe2db, 0xe79ebc}, /* U+77BC */ + {0xe2dc, 0xe79ebd}, /* U+77BD */ + {0xe2dd, 0xe79ebb}, /* U+77BB */ + {0xe2de, 0xe79f87}, /* U+77C7 */ + {0xe2df, 0xe79f8d}, /* U+77CD */ + {0xe2e0, 0xe79f97}, /* U+77D7 */ + {0xe2e1, 0xe79f9a}, /* U+77DA */ + {0xe2e2, 0xe79f9c}, /* U+77DC */ + {0xe2e3, 0xe79fa3}, /* U+77E3 */ + {0xe2e4, 0xe79fae}, /* U+77EE */ + {0xe2e5, 0xe79fbc}, /* U+77FC */ + {0xe2e6, 0xe7a08c}, /* U+780C */ + {0xe2e7, 0xe7a092}, /* U+7812 */ + {0xe2e8, 0xe7a4a6}, /* U+7926 */ + {0xe2e9, 0xe7a0a0}, /* U+7820 */ + {0xe2ea, 0xe7a4aa}, /* U+792A */ + {0xe2eb, 0xe7a185}, /* U+7845 */ + {0xe2ec, 0xe7a28e}, /* U+788E */ + {0xe2ed, 0xe7a1b4}, /* U+7874 */ + {0xe2ee, 0xe7a286}, /* U+7886 */ + {0xe2ef, 0xe7a1bc}, /* U+787C */ + {0xe2f0, 0xe7a29a}, /* U+789A */ + {0xe2f1, 0xe7a28c}, /* U+788C */ + {0xe2f2, 0xe7a2a3}, /* U+78A3 */ + {0xe2f3, 0xe7a2b5}, /* U+78B5 */ + {0xe2f4, 0xe7a2aa}, /* U+78AA */ + {0xe2f5, 0xe7a2af}, /* U+78AF */ + {0xe2f6, 0xe7a391}, /* U+78D1 */ + {0xe2f7, 0xe7a386}, /* U+78C6 */ + {0xe2f8, 0xe7a38b}, /* U+78CB */ + {0xe2f9, 0xe7a394}, /* U+78D4 */ + {0xe2fa, 0xe7a2be}, /* U+78BE */ + {0xe2fb, 0xe7a2bc}, /* U+78BC */ + {0xe2fc, 0xe7a385}, /* U+78C5 */ + {0xe2fd, 0xe7a38a}, /* U+78CA */ + {0xe2fe, 0xe7a3ac}, /* U+78EC */ + {0xe3a1, 0xe7a3a7}, /* U+78E7 */ + {0xe3a2, 0xe7a39a}, /* U+78DA */ + {0xe3a3, 0xe7a3bd}, /* U+78FD */ + {0xe3a4, 0xe7a3b4}, /* U+78F4 */ + {0xe3a5, 0xe7a487}, /* U+7907 */ + {0xe3a6, 0xe7a492}, /* U+7912 */ + {0xe3a7, 0xe7a491}, /* U+7911 */ + {0xe3a8, 0xe7a499}, /* U+7919 */ + {0xe3a9, 0xe7a4ac}, /* U+792C */ + {0xe3aa, 0xe7a4ab}, /* U+792B */ + {0xe3ab, 0xe7a580}, /* U+7940 */ + {0xe3ac, 0xe7a5a0}, /* U+7960 */ + {0xe3ad, 0xe7a597}, /* U+7957 */ + {0xe3ae, 0xe7a59f}, /* U+795F */ + {0xe3af, 0xe7a59a}, /* U+795A */ + {0xe3b0, 0xe7a595}, /* U+7955 */ + {0xe3b1, 0xe7a593}, /* U+7953 */ + {0xe3b2, 0xe7a5ba}, /* U+797A */ + {0xe3b3, 0xe7a5bf}, /* U+797F */ + {0xe3b4, 0xe7a68a}, /* U+798A */ + {0xe3b5, 0xe7a69d}, /* U+799D */ + {0xe3b6, 0xe7a6a7}, /* U+79A7 */ + {0xe3b7, 0xe9bd8b}, /* U+9F4B */ + {0xe3b8, 0xe7a6aa}, /* U+79AA */ + {0xe3b9, 0xe7a6ae}, /* U+79AE */ + {0xe3ba, 0xe7a6b3}, /* U+79B3 */ + {0xe3bb, 0xe7a6b9}, /* U+79B9 */ + {0xe3bc, 0xe7a6ba}, /* U+79BA */ + {0xe3bd, 0xe7a789}, /* U+79C9 */ + {0xe3be, 0xe7a795}, /* U+79D5 */ + {0xe3bf, 0xe7a7a7}, /* U+79E7 */ + {0xe3c0, 0xe7a7ac}, /* U+79EC */ + {0xe3c1, 0xe7a7a1}, /* U+79E1 */ + {0xe3c2, 0xe7a7a3}, /* U+79E3 */ + {0xe3c3, 0xe7a888}, /* U+7A08 */ + {0xe3c4, 0xe7a88d}, /* U+7A0D */ + {0xe3c5, 0xe7a898}, /* U+7A18 */ + {0xe3c6, 0xe7a899}, /* U+7A19 */ + {0xe3c7, 0xe7a8a0}, /* U+7A20 */ + {0xe3c8, 0xe7a89f}, /* U+7A1F */ + {0xe3c9, 0xe7a680}, /* U+7980 */ + {0xe3ca, 0xe7a8b1}, /* U+7A31 */ + {0xe3cb, 0xe7a8bb}, /* U+7A3B */ + {0xe3cc, 0xe7a8be}, /* U+7A3E */ + {0xe3cd, 0xe7a8b7}, /* U+7A37 */ + {0xe3ce, 0xe7a983}, /* U+7A43 */ + {0xe3cf, 0xe7a997}, /* U+7A57 */ + {0xe3d0, 0xe7a989}, /* U+7A49 */ + {0xe3d1, 0xe7a9a1}, /* U+7A61 */ + {0xe3d2, 0xe7a9a2}, /* U+7A62 */ + {0xe3d3, 0xe7a9a9}, /* U+7A69 */ + {0xe3d4, 0xe9be9d}, /* U+9F9D */ + {0xe3d5, 0xe7a9b0}, /* U+7A70 */ + {0xe3d6, 0xe7a9b9}, /* U+7A79 */ + {0xe3d7, 0xe7a9bd}, /* U+7A7D */ + {0xe3d8, 0xe7aa88}, /* U+7A88 */ + {0xe3d9, 0xe7aa97}, /* U+7A97 */ + {0xe3da, 0xe7aa95}, /* U+7A95 */ + {0xe3db, 0xe7aa98}, /* U+7A98 */ + {0xe3dc, 0xe7aa96}, /* U+7A96 */ + {0xe3dd, 0xe7aaa9}, /* U+7AA9 */ + {0xe3de, 0xe7ab88}, /* U+7AC8 */ + {0xe3df, 0xe7aab0}, /* U+7AB0 */ + {0xe3e0, 0xe7aab6}, /* U+7AB6 */ + {0xe3e1, 0xe7ab85}, /* U+7AC5 */ + {0xe3e2, 0xe7ab84}, /* U+7AC4 */ + {0xe3e3, 0xe7aabf}, /* U+7ABF */ + {0xe3e4, 0xe98283}, /* U+9083 */ + {0xe3e5, 0xe7ab87}, /* U+7AC7 */ + {0xe3e6, 0xe7ab8a}, /* U+7ACA */ + {0xe3e7, 0xe7ab8d}, /* U+7ACD */ + {0xe3e8, 0xe7ab8f}, /* U+7ACF */ + {0xe3e9, 0xe7ab95}, /* U+7AD5 */ + {0xe3ea, 0xe7ab93}, /* U+7AD3 */ + {0xe3eb, 0xe7ab99}, /* U+7AD9 */ + {0xe3ec, 0xe7ab9a}, /* U+7ADA */ + {0xe3ed, 0xe7ab9d}, /* U+7ADD */ + {0xe3ee, 0xe7aba1}, /* U+7AE1 */ + {0xe3ef, 0xe7aba2}, /* U+7AE2 */ + {0xe3f0, 0xe7aba6}, /* U+7AE6 */ + {0xe3f1, 0xe7abad}, /* U+7AED */ + {0xe3f2, 0xe7abb0}, /* U+7AF0 */ + {0xe3f3, 0xe7ac82}, /* U+7B02 */ + {0xe3f4, 0xe7ac8f}, /* U+7B0F */ + {0xe3f5, 0xe7ac8a}, /* U+7B0A */ + {0xe3f6, 0xe7ac86}, /* U+7B06 */ + {0xe3f7, 0xe7acb3}, /* U+7B33 */ + {0xe3f8, 0xe7ac98}, /* U+7B18 */ + {0xe3f9, 0xe7ac99}, /* U+7B19 */ + {0xe3fa, 0xe7ac9e}, /* U+7B1E */ + {0xe3fb, 0xe7acb5}, /* U+7B35 */ + {0xe3fc, 0xe7aca8}, /* U+7B28 */ + {0xe3fd, 0xe7acb6}, /* U+7B36 */ + {0xe3fe, 0xe7ad90}, /* U+7B50 */ + {0xe4a1, 0xe7adba}, /* U+7B7A */ + {0xe4a2, 0xe7ac84}, /* U+7B04 */ + {0xe4a3, 0xe7ad8d}, /* U+7B4D */ + {0xe4a4, 0xe7ac8b}, /* U+7B0B */ + {0xe4a5, 0xe7ad8c}, /* U+7B4C */ + {0xe4a6, 0xe7ad85}, /* U+7B45 */ + {0xe4a7, 0xe7adb5}, /* U+7B75 */ + {0xe4a8, 0xe7ada5}, /* U+7B65 */ + {0xe4a9, 0xe7adb4}, /* U+7B74 */ + {0xe4aa, 0xe7ada7}, /* U+7B67 */ + {0xe4ab, 0xe7adb0}, /* U+7B70 */ + {0xe4ac, 0xe7adb1}, /* U+7B71 */ + {0xe4ad, 0xe7adac}, /* U+7B6C */ + {0xe4ae, 0xe7adae}, /* U+7B6E */ + {0xe4af, 0xe7ae9d}, /* U+7B9D */ + {0xe4b0, 0xe7ae98}, /* U+7B98 */ + {0xe4b1, 0xe7ae9f}, /* U+7B9F */ + {0xe4b2, 0xe7ae8d}, /* U+7B8D */ + {0xe4b3, 0xe7ae9c}, /* U+7B9C */ + {0xe4b4, 0xe7ae9a}, /* U+7B9A */ + {0xe4b5, 0xe7ae8b}, /* U+7B8B */ + {0xe4b6, 0xe7ae92}, /* U+7B92 */ + {0xe4b7, 0xe7ae8f}, /* U+7B8F */ + {0xe4b8, 0xe7ad9d}, /* U+7B5D */ + {0xe4b9, 0xe7ae99}, /* U+7B99 */ + {0xe4ba, 0xe7af8b}, /* U+7BCB */ + {0xe4bb, 0xe7af81}, /* U+7BC1 */ + {0xe4bc, 0xe7af8c}, /* U+7BCC */ + {0xe4bd, 0xe7af8f}, /* U+7BCF */ + {0xe4be, 0xe7aeb4}, /* U+7BB4 */ + {0xe4bf, 0xe7af86}, /* U+7BC6 */ + {0xe4c0, 0xe7af9d}, /* U+7BDD */ + {0xe4c1, 0xe7afa9}, /* U+7BE9 */ + {0xe4c2, 0xe7b091}, /* U+7C11 */ + {0xe4c3, 0xe7b094}, /* U+7C14 */ + {0xe4c4, 0xe7afa6}, /* U+7BE6 */ + {0xe4c5, 0xe7afa5}, /* U+7BE5 */ + {0xe4c6, 0xe7b1a0}, /* U+7C60 */ + {0xe4c7, 0xe7b080}, /* U+7C00 */ + {0xe4c8, 0xe7b087}, /* U+7C07 */ + {0xe4c9, 0xe7b093}, /* U+7C13 */ + {0xe4ca, 0xe7afb3}, /* U+7BF3 */ + {0xe4cb, 0xe7afb7}, /* U+7BF7 */ + {0xe4cc, 0xe7b097}, /* U+7C17 */ + {0xe4cd, 0xe7b08d}, /* U+7C0D */ + {0xe4ce, 0xe7afb6}, /* U+7BF6 */ + {0xe4cf, 0xe7b0a3}, /* U+7C23 */ + {0xe4d0, 0xe7b0a7}, /* U+7C27 */ + {0xe4d1, 0xe7b0aa}, /* U+7C2A */ + {0xe4d2, 0xe7b09f}, /* U+7C1F */ + {0xe4d3, 0xe7b0b7}, /* U+7C37 */ + {0xe4d4, 0xe7b0ab}, /* U+7C2B */ + {0xe4d5, 0xe7b0bd}, /* U+7C3D */ + {0xe4d6, 0xe7b18c}, /* U+7C4C */ + {0xe4d7, 0xe7b183}, /* U+7C43 */ + {0xe4d8, 0xe7b194}, /* U+7C54 */ + {0xe4d9, 0xe7b18f}, /* U+7C4F */ + {0xe4da, 0xe7b180}, /* U+7C40 */ + {0xe4db, 0xe7b190}, /* U+7C50 */ + {0xe4dc, 0xe7b198}, /* U+7C58 */ + {0xe4dd, 0xe7b19f}, /* U+7C5F */ + {0xe4de, 0xe7b1a4}, /* U+7C64 */ + {0xe4df, 0xe7b196}, /* U+7C56 */ + {0xe4e0, 0xe7b1a5}, /* U+7C65 */ + {0xe4e1, 0xe7b1ac}, /* U+7C6C */ + {0xe4e2, 0xe7b1b5}, /* U+7C75 */ + {0xe4e3, 0xe7b283}, /* U+7C83 */ + {0xe4e4, 0xe7b290}, /* U+7C90 */ + {0xe4e5, 0xe7b2a4}, /* U+7CA4 */ + {0xe4e6, 0xe7b2ad}, /* U+7CAD */ + {0xe4e7, 0xe7b2a2}, /* U+7CA2 */ + {0xe4e8, 0xe7b2ab}, /* U+7CAB */ + {0xe4e9, 0xe7b2a1}, /* U+7CA1 */ + {0xe4ea, 0xe7b2a8}, /* U+7CA8 */ + {0xe4eb, 0xe7b2b3}, /* U+7CB3 */ + {0xe4ec, 0xe7b2b2}, /* U+7CB2 */ + {0xe4ed, 0xe7b2b1}, /* U+7CB1 */ + {0xe4ee, 0xe7b2ae}, /* U+7CAE */ + {0xe4ef, 0xe7b2b9}, /* U+7CB9 */ + {0xe4f0, 0xe7b2bd}, /* U+7CBD */ + {0xe4f1, 0xe7b380}, /* U+7CC0 */ + {0xe4f2, 0xe7b385}, /* U+7CC5 */ + {0xe4f3, 0xe7b382}, /* U+7CC2 */ + {0xe4f4, 0xe7b398}, /* U+7CD8 */ + {0xe4f5, 0xe7b392}, /* U+7CD2 */ + {0xe4f6, 0xe7b39c}, /* U+7CDC */ + {0xe4f7, 0xe7b3a2}, /* U+7CE2 */ + {0xe4f8, 0xe9acbb}, /* U+9B3B */ + {0xe4f9, 0xe7b3af}, /* U+7CEF */ + {0xe4fa, 0xe7b3b2}, /* U+7CF2 */ + {0xe4fb, 0xe7b3b4}, /* U+7CF4 */ + {0xe4fc, 0xe7b3b6}, /* U+7CF6 */ + {0xe4fd, 0xe7b3ba}, /* U+7CFA */ + {0xe4fe, 0xe7b486}, /* U+7D06 */ + {0xe5a1, 0xe7b482}, /* U+7D02 */ + {0xe5a2, 0xe7b49c}, /* U+7D1C */ + {0xe5a3, 0xe7b495}, /* U+7D15 */ + {0xe5a4, 0xe7b48a}, /* U+7D0A */ + {0xe5a5, 0xe7b585}, /* U+7D45 */ + {0xe5a6, 0xe7b58b}, /* U+7D4B */ + {0xe5a7, 0xe7b4ae}, /* U+7D2E */ + {0xe5a8, 0xe7b4b2}, /* U+7D32 */ + {0xe5a9, 0xe7b4bf}, /* U+7D3F */ + {0xe5aa, 0xe7b4b5}, /* U+7D35 */ + {0xe5ab, 0xe7b586}, /* U+7D46 */ + {0xe5ac, 0xe7b5b3}, /* U+7D73 */ + {0xe5ad, 0xe7b596}, /* U+7D56 */ + {0xe5ae, 0xe7b58e}, /* U+7D4E */ + {0xe5af, 0xe7b5b2}, /* U+7D72 */ + {0xe5b0, 0xe7b5a8}, /* U+7D68 */ + {0xe5b1, 0xe7b5ae}, /* U+7D6E */ + {0xe5b2, 0xe7b58f}, /* U+7D4F */ + {0xe5b3, 0xe7b5a3}, /* U+7D63 */ + {0xe5b4, 0xe7b693}, /* U+7D93 */ + {0xe5b5, 0xe7b689}, /* U+7D89 */ + {0xe5b6, 0xe7b59b}, /* U+7D5B */ + {0xe5b7, 0xe7b68f}, /* U+7D8F */ + {0xe5b8, 0xe7b5bd}, /* U+7D7D */ + {0xe5b9, 0xe7b69b}, /* U+7D9B */ + {0xe5ba, 0xe7b6ba}, /* U+7DBA */ + {0xe5bb, 0xe7b6ae}, /* U+7DAE */ + {0xe5bc, 0xe7b6a3}, /* U+7DA3 */ + {0xe5bd, 0xe7b6b5}, /* U+7DB5 */ + {0xe5be, 0xe7b787}, /* U+7DC7 */ + {0xe5bf, 0xe7b6bd}, /* U+7DBD */ + {0xe5c0, 0xe7b6ab}, /* U+7DAB */ + {0xe5c1, 0xe7b8bd}, /* U+7E3D */ + {0xe5c2, 0xe7b6a2}, /* U+7DA2 */ + {0xe5c3, 0xe7b6af}, /* U+7DAF */ + {0xe5c4, 0xe7b79c}, /* U+7DDC */ + {0xe5c5, 0xe7b6b8}, /* U+7DB8 */ + {0xe5c6, 0xe7b69f}, /* U+7D9F */ + {0xe5c7, 0xe7b6b0}, /* U+7DB0 */ + {0xe5c8, 0xe7b798}, /* U+7DD8 */ + {0xe5c9, 0xe7b79d}, /* U+7DDD */ + {0xe5ca, 0xe7b7a4}, /* U+7DE4 */ + {0xe5cb, 0xe7b79e}, /* U+7DDE */ + {0xe5cc, 0xe7b7bb}, /* U+7DFB */ + {0xe5cd, 0xe7b7b2}, /* U+7DF2 */ + {0xe5ce, 0xe7b7a1}, /* U+7DE1 */ + {0xe5cf, 0xe7b885}, /* U+7E05 */ + {0xe5d0, 0xe7b88a}, /* U+7E0A */ + {0xe5d1, 0xe7b8a3}, /* U+7E23 */ + {0xe5d2, 0xe7b8a1}, /* U+7E21 */ + {0xe5d3, 0xe7b892}, /* U+7E12 */ + {0xe5d4, 0xe7b8b1}, /* U+7E31 */ + {0xe5d5, 0xe7b89f}, /* U+7E1F */ + {0xe5d6, 0xe7b889}, /* U+7E09 */ + {0xe5d7, 0xe7b88b}, /* U+7E0B */ + {0xe5d8, 0xe7b8a2}, /* U+7E22 */ + {0xe5d9, 0xe7b986}, /* U+7E46 */ + {0xe5da, 0xe7b9a6}, /* U+7E66 */ + {0xe5db, 0xe7b8bb}, /* U+7E3B */ + {0xe5dc, 0xe7b8b5}, /* U+7E35 */ + {0xe5dd, 0xe7b8b9}, /* U+7E39 */ + {0xe5de, 0xe7b983}, /* U+7E43 */ + {0xe5df, 0xe7b8b7}, /* U+7E37 */ + {0xe5e0, 0xe7b8b2}, /* U+7E32 */ + {0xe5e1, 0xe7b8ba}, /* U+7E3A */ + {0xe5e2, 0xe7b9a7}, /* U+7E67 */ + {0xe5e3, 0xe7b99d}, /* U+7E5D */ + {0xe5e4, 0xe7b996}, /* U+7E56 */ + {0xe5e5, 0xe7b99e}, /* U+7E5E */ + {0xe5e6, 0xe7b999}, /* U+7E59 */ + {0xe5e7, 0xe7b99a}, /* U+7E5A */ + {0xe5e8, 0xe7b9b9}, /* U+7E79 */ + {0xe5e9, 0xe7b9aa}, /* U+7E6A */ + {0xe5ea, 0xe7b9a9}, /* U+7E69 */ + {0xe5eb, 0xe7b9bc}, /* U+7E7C */ + {0xe5ec, 0xe7b9bb}, /* U+7E7B */ + {0xe5ed, 0xe7ba83}, /* U+7E83 */ + {0xe5ee, 0xe7b795}, /* U+7DD5 */ + {0xe5ef, 0xe7b9bd}, /* U+7E7D */ + {0xe5f0, 0xe8beae}, /* U+8FAE */ + {0xe5f1, 0xe7b9bf}, /* U+7E7F */ + {0xe5f2, 0xe7ba88}, /* U+7E88 */ + {0xe5f3, 0xe7ba89}, /* U+7E89 */ + {0xe5f4, 0xe7ba8c}, /* U+7E8C */ + {0xe5f5, 0xe7ba92}, /* U+7E92 */ + {0xe5f6, 0xe7ba90}, /* U+7E90 */ + {0xe5f7, 0xe7ba93}, /* U+7E93 */ + {0xe5f8, 0xe7ba94}, /* U+7E94 */ + {0xe5f9, 0xe7ba96}, /* U+7E96 */ + {0xe5fa, 0xe7ba8e}, /* U+7E8E */ + {0xe5fb, 0xe7ba9b}, /* U+7E9B */ + {0xe5fc, 0xe7ba9c}, /* U+7E9C */ + {0xe5fd, 0xe7bcb8}, /* U+7F38 */ + {0xe5fe, 0xe7bcba}, /* U+7F3A */ + {0xe6a1, 0xe7bd85}, /* U+7F45 */ + {0xe6a2, 0xe7bd8c}, /* U+7F4C */ + {0xe6a3, 0xe7bd8d}, /* U+7F4D */ + {0xe6a4, 0xe7bd8e}, /* U+7F4E */ + {0xe6a5, 0xe7bd90}, /* U+7F50 */ + {0xe6a6, 0xe7bd91}, /* U+7F51 */ + {0xe6a7, 0xe7bd95}, /* U+7F55 */ + {0xe6a8, 0xe7bd94}, /* U+7F54 */ + {0xe6a9, 0xe7bd98}, /* U+7F58 */ + {0xe6aa, 0xe7bd9f}, /* U+7F5F */ + {0xe6ab, 0xe7bda0}, /* U+7F60 */ + {0xe6ac, 0xe7bda8}, /* U+7F68 */ + {0xe6ad, 0xe7bda9}, /* U+7F69 */ + {0xe6ae, 0xe7bda7}, /* U+7F67 */ + {0xe6af, 0xe7bdb8}, /* U+7F78 */ + {0xe6b0, 0xe7be82}, /* U+7F82 */ + {0xe6b1, 0xe7be86}, /* U+7F86 */ + {0xe6b2, 0xe7be83}, /* U+7F83 */ + {0xe6b3, 0xe7be88}, /* U+7F88 */ + {0xe6b4, 0xe7be87}, /* U+7F87 */ + {0xe6b5, 0xe7be8c}, /* U+7F8C */ + {0xe6b6, 0xe7be94}, /* U+7F94 */ + {0xe6b7, 0xe7be9e}, /* U+7F9E */ + {0xe6b8, 0xe7be9d}, /* U+7F9D */ + {0xe6b9, 0xe7be9a}, /* U+7F9A */ + {0xe6ba, 0xe7bea3}, /* U+7FA3 */ + {0xe6bb, 0xe7beaf}, /* U+7FAF */ + {0xe6bc, 0xe7beb2}, /* U+7FB2 */ + {0xe6bd, 0xe7beb9}, /* U+7FB9 */ + {0xe6be, 0xe7beae}, /* U+7FAE */ + {0xe6bf, 0xe7beb6}, /* U+7FB6 */ + {0xe6c0, 0xe7beb8}, /* U+7FB8 */ + {0xe6c1, 0xe8adb1}, /* U+8B71 */ + {0xe6c2, 0xe7bf85}, /* U+7FC5 */ + {0xe6c3, 0xe7bf86}, /* U+7FC6 */ + {0xe6c4, 0xe7bf8a}, /* U+7FCA */ + {0xe6c5, 0xe7bf95}, /* U+7FD5 */ + {0xe6c6, 0xe7bf94}, /* U+7FD4 */ + {0xe6c7, 0xe7bfa1}, /* U+7FE1 */ + {0xe6c8, 0xe7bfa6}, /* U+7FE6 */ + {0xe6c9, 0xe7bfa9}, /* U+7FE9 */ + {0xe6ca, 0xe7bfb3}, /* U+7FF3 */ + {0xe6cb, 0xe7bfb9}, /* U+7FF9 */ + {0xe6cc, 0xe9a39c}, /* U+98DC */ + {0xe6cd, 0xe88086}, /* U+8006 */ + {0xe6ce, 0xe88084}, /* U+8004 */ + {0xe6cf, 0xe8808b}, /* U+800B */ + {0xe6d0, 0xe88092}, /* U+8012 */ + {0xe6d1, 0xe88098}, /* U+8018 */ + {0xe6d2, 0xe88099}, /* U+8019 */ + {0xe6d3, 0xe8809c}, /* U+801C */ + {0xe6d4, 0xe880a1}, /* U+8021 */ + {0xe6d5, 0xe880a8}, /* U+8028 */ + {0xe6d6, 0xe880bf}, /* U+803F */ + {0xe6d7, 0xe880bb}, /* U+803B */ + {0xe6d8, 0xe8818a}, /* U+804A */ + {0xe6d9, 0xe88186}, /* U+8046 */ + {0xe6da, 0xe88192}, /* U+8052 */ + {0xe6db, 0xe88198}, /* U+8058 */ + {0xe6dc, 0xe8819a}, /* U+805A */ + {0xe6dd, 0xe8819f}, /* U+805F */ + {0xe6de, 0xe881a2}, /* U+8062 */ + {0xe6df, 0xe881a8}, /* U+8068 */ + {0xe6e0, 0xe881b3}, /* U+8073 */ + {0xe6e1, 0xe881b2}, /* U+8072 */ + {0xe6e2, 0xe881b0}, /* U+8070 */ + {0xe6e3, 0xe881b6}, /* U+8076 */ + {0xe6e4, 0xe881b9}, /* U+8079 */ + {0xe6e5, 0xe881bd}, /* U+807D */ + {0xe6e6, 0xe881bf}, /* U+807F */ + {0xe6e7, 0xe88284}, /* U+8084 */ + {0xe6e8, 0xe88286}, /* U+8086 */ + {0xe6e9, 0xe88285}, /* U+8085 */ + {0xe6ea, 0xe8829b}, /* U+809B */ + {0xe6eb, 0xe88293}, /* U+8093 */ + {0xe6ec, 0xe8829a}, /* U+809A */ + {0xe6ed, 0xe882ad}, /* U+80AD */ + {0xe6ee, 0xe58690}, /* U+5190 */ + {0xe6ef, 0xe882ac}, /* U+80AC */ + {0xe6f0, 0xe8839b}, /* U+80DB */ + {0xe6f1, 0xe883a5}, /* U+80E5 */ + {0xe6f2, 0xe88399}, /* U+80D9 */ + {0xe6f3, 0xe8839d}, /* U+80DD */ + {0xe6f4, 0xe88384}, /* U+80C4 */ + {0xe6f5, 0xe8839a}, /* U+80DA */ + {0xe6f6, 0xe88396}, /* U+80D6 */ + {0xe6f7, 0xe88489}, /* U+8109 */ + {0xe6f8, 0xe883af}, /* U+80EF */ + {0xe6f9, 0xe883b1}, /* U+80F1 */ + {0xe6fa, 0xe8849b}, /* U+811B */ + {0xe6fb, 0xe884a9}, /* U+8129 */ + {0xe6fc, 0xe884a3}, /* U+8123 */ + {0xe6fd, 0xe884af}, /* U+812F */ + {0xe6fe, 0xe8858b}, /* U+814B */ + {0xe7a1, 0xe99a8b}, /* U+968B */ + {0xe7a2, 0xe88586}, /* U+8146 */ + {0xe7a3, 0xe884be}, /* U+813E */ + {0xe7a4, 0xe88593}, /* U+8153 */ + {0xe7a5, 0xe88591}, /* U+8151 */ + {0xe7a6, 0xe883bc}, /* U+80FC */ + {0xe7a7, 0xe885b1}, /* U+8171 */ + {0xe7a8, 0xe885ae}, /* U+816E */ + {0xe7a9, 0xe885a5}, /* U+8165 */ + {0xe7aa, 0xe885a6}, /* U+8166 */ + {0xe7ab, 0xe885b4}, /* U+8174 */ + {0xe7ac, 0xe88683}, /* U+8183 */ + {0xe7ad, 0xe88688}, /* U+8188 */ + {0xe7ae, 0xe8868a}, /* U+818A */ + {0xe7af, 0xe88680}, /* U+8180 */ + {0xe7b0, 0xe88682}, /* U+8182 */ + {0xe7b1, 0xe886a0}, /* U+81A0 */ + {0xe7b2, 0xe88695}, /* U+8195 */ + {0xe7b3, 0xe886a4}, /* U+81A4 */ + {0xe7b4, 0xe886a3}, /* U+81A3 */ + {0xe7b5, 0xe8859f}, /* U+815F */ + {0xe7b6, 0xe88693}, /* U+8193 */ + {0xe7b7, 0xe886a9}, /* U+81A9 */ + {0xe7b8, 0xe886b0}, /* U+81B0 */ + {0xe7b9, 0xe886b5}, /* U+81B5 */ + {0xe7ba, 0xe886be}, /* U+81BE */ + {0xe7bb, 0xe886b8}, /* U+81B8 */ + {0xe7bc, 0xe886bd}, /* U+81BD */ + {0xe7bd, 0xe88780}, /* U+81C0 */ + {0xe7be, 0xe88782}, /* U+81C2 */ + {0xe7bf, 0xe886ba}, /* U+81BA */ + {0xe7c0, 0xe88789}, /* U+81C9 */ + {0xe7c1, 0xe8878d}, /* U+81CD */ + {0xe7c2, 0xe88791}, /* U+81D1 */ + {0xe7c3, 0xe88799}, /* U+81D9 */ + {0xe7c4, 0xe88798}, /* U+81D8 */ + {0xe7c5, 0xe88788}, /* U+81C8 */ + {0xe7c6, 0xe8879a}, /* U+81DA */ + {0xe7c7, 0xe8879f}, /* U+81DF */ + {0xe7c8, 0xe887a0}, /* U+81E0 */ + {0xe7c9, 0xe887a7}, /* U+81E7 */ + {0xe7ca, 0xe887ba}, /* U+81FA */ + {0xe7cb, 0xe887bb}, /* U+81FB */ + {0xe7cc, 0xe887be}, /* U+81FE */ + {0xe7cd, 0xe88881}, /* U+8201 */ + {0xe7ce, 0xe88882}, /* U+8202 */ + {0xe7cf, 0xe88885}, /* U+8205 */ + {0xe7d0, 0xe88887}, /* U+8207 */ + {0xe7d1, 0xe8888a}, /* U+820A */ + {0xe7d2, 0xe8888d}, /* U+820D */ + {0xe7d3, 0xe88890}, /* U+8210 */ + {0xe7d4, 0xe88896}, /* U+8216 */ + {0xe7d5, 0xe888a9}, /* U+8229 */ + {0xe7d6, 0xe888ab}, /* U+822B */ + {0xe7d7, 0xe888b8}, /* U+8238 */ + {0xe7d8, 0xe888b3}, /* U+8233 */ + {0xe7d9, 0xe88980}, /* U+8240 */ + {0xe7da, 0xe88999}, /* U+8259 */ + {0xe7db, 0xe88998}, /* U+8258 */ + {0xe7dc, 0xe8899d}, /* U+825D */ + {0xe7dd, 0xe8899a}, /* U+825A */ + {0xe7de, 0xe8899f}, /* U+825F */ + {0xe7df, 0xe889a4}, /* U+8264 */ + {0xe7e0, 0xe889a2}, /* U+8262 */ + {0xe7e1, 0xe889a8}, /* U+8268 */ + {0xe7e2, 0xe889aa}, /* U+826A */ + {0xe7e3, 0xe889ab}, /* U+826B */ + {0xe7e4, 0xe888ae}, /* U+822E */ + {0xe7e5, 0xe889b1}, /* U+8271 */ + {0xe7e6, 0xe889b7}, /* U+8277 */ + {0xe7e7, 0xe889b8}, /* U+8278 */ + {0xe7e8, 0xe889be}, /* U+827E */ + {0xe7e9, 0xe88a8d}, /* U+828D */ + {0xe7ea, 0xe88a92}, /* U+8292 */ + {0xe7eb, 0xe88aab}, /* U+82AB */ + {0xe7ec, 0xe88a9f}, /* U+829F */ + {0xe7ed, 0xe88abb}, /* U+82BB */ + {0xe7ee, 0xe88aac}, /* U+82AC */ + {0xe7ef, 0xe88ba1}, /* U+82E1 */ + {0xe7f0, 0xe88ba3}, /* U+82E3 */ + {0xe7f1, 0xe88b9f}, /* U+82DF */ + {0xe7f2, 0xe88b92}, /* U+82D2 */ + {0xe7f3, 0xe88bb4}, /* U+82F4 */ + {0xe7f4, 0xe88bb3}, /* U+82F3 */ + {0xe7f5, 0xe88bba}, /* U+82FA */ + {0xe7f6, 0xe88e93}, /* U+8393 */ + {0xe7f7, 0xe88c83}, /* U+8303 */ + {0xe7f8, 0xe88bbb}, /* U+82FB */ + {0xe7f9, 0xe88bb9}, /* U+82F9 */ + {0xe7fa, 0xe88b9e}, /* U+82DE */ + {0xe7fb, 0xe88c86}, /* U+8306 */ + {0xe7fc, 0xe88b9c}, /* U+82DC */ + {0xe7fd, 0xe88c89}, /* U+8309 */ + {0xe7fe, 0xe88b99}, /* U+82D9 */ + {0xe8a1, 0xe88cb5}, /* U+8335 */ + {0xe8a2, 0xe88cb4}, /* U+8334 */ + {0xe8a3, 0xe88c96}, /* U+8316 */ + {0xe8a4, 0xe88cb2}, /* U+8332 */ + {0xe8a5, 0xe88cb1}, /* U+8331 */ + {0xe8a6, 0xe88d80}, /* U+8340 */ + {0xe8a7, 0xe88cb9}, /* U+8339 */ + {0xe8a8, 0xe88d90}, /* U+8350 */ + {0xe8a9, 0xe88d85}, /* U+8345 */ + {0xe8aa, 0xe88caf}, /* U+832F */ + {0xe8ab, 0xe88cab}, /* U+832B */ + {0xe8ac, 0xe88c97}, /* U+8317 */ + {0xe8ad, 0xe88c98}, /* U+8318 */ + {0xe8ae, 0xe88e85}, /* U+8385 */ + {0xe8af, 0xe88e9a}, /* U+839A */ + {0xe8b0, 0xe88eaa}, /* U+83AA */ + {0xe8b1, 0xe88e9f}, /* U+839F */ + {0xe8b2, 0xe88ea2}, /* U+83A2 */ + {0xe8b3, 0xe88e96}, /* U+8396 */ + {0xe8b4, 0xe88ca3}, /* U+8323 */ + {0xe8b5, 0xe88e8e}, /* U+838E */ + {0xe8b6, 0xe88e87}, /* U+8387 */ + {0xe8b7, 0xe88e8a}, /* U+838A */ + {0xe8b8, 0xe88dbc}, /* U+837C */ + {0xe8b9, 0xe88eb5}, /* U+83B5 */ + {0xe8ba, 0xe88db3}, /* U+8373 */ + {0xe8bb, 0xe88db5}, /* U+8375 */ + {0xe8bc, 0xe88ea0}, /* U+83A0 */ + {0xe8bd, 0xe88e89}, /* U+8389 */ + {0xe8be, 0xe88ea8}, /* U+83A8 */ + {0xe8bf, 0xe88fb4}, /* U+83F4 */ + {0xe8c0, 0xe89093}, /* U+8413 */ + {0xe8c1, 0xe88fab}, /* U+83EB */ + {0xe8c2, 0xe88f8e}, /* U+83CE */ + {0xe8c3, 0xe88fbd}, /* U+83FD */ + {0xe8c4, 0xe89083}, /* U+8403 */ + {0xe8c5, 0xe88f98}, /* U+83D8 */ + {0xe8c6, 0xe8908b}, /* U+840B */ + {0xe8c7, 0xe88f81}, /* U+83C1 */ + {0xe8c8, 0xe88fb7}, /* U+83F7 */ + {0xe8c9, 0xe89087}, /* U+8407 */ + {0xe8ca, 0xe88fa0}, /* U+83E0 */ + {0xe8cb, 0xe88fb2}, /* U+83F2 */ + {0xe8cc, 0xe8908d}, /* U+840D */ + {0xe8cd, 0xe890a2}, /* U+8422 */ + {0xe8ce, 0xe890a0}, /* U+8420 */ + {0xe8cf, 0xe88ebd}, /* U+83BD */ + {0xe8d0, 0xe890b8}, /* U+8438 */ + {0xe8d1, 0xe89486}, /* U+8506 */ + {0xe8d2, 0xe88fbb}, /* U+83FB */ + {0xe8d3, 0xe891ad}, /* U+846D */ + {0xe8d4, 0xe890aa}, /* U+842A */ + {0xe8d5, 0xe890bc}, /* U+843C */ + {0xe8d6, 0xe8959a}, /* U+855A */ + {0xe8d7, 0xe89284}, /* U+8484 */ + {0xe8d8, 0xe891b7}, /* U+8477 */ + {0xe8d9, 0xe891ab}, /* U+846B */ + {0xe8da, 0xe892ad}, /* U+84AD */ + {0xe8db, 0xe891ae}, /* U+846E */ + {0xe8dc, 0xe89282}, /* U+8482 */ + {0xe8dd, 0xe891a9}, /* U+8469 */ + {0xe8de, 0xe89186}, /* U+8446 */ + {0xe8df, 0xe890ac}, /* U+842C */ + {0xe8e0, 0xe891af}, /* U+846F */ + {0xe8e1, 0xe891b9}, /* U+8479 */ + {0xe8e2, 0xe890b5}, /* U+8435 */ + {0xe8e3, 0xe8938a}, /* U+84CA */ + {0xe8e4, 0xe891a2}, /* U+8462 */ + {0xe8e5, 0xe892b9}, /* U+84B9 */ + {0xe8e6, 0xe892bf}, /* U+84BF */ + {0xe8e7, 0xe8929f}, /* U+849F */ + {0xe8e8, 0xe89399}, /* U+84D9 */ + {0xe8e9, 0xe8938d}, /* U+84CD */ + {0xe8ea, 0xe892bb}, /* U+84BB */ + {0xe8eb, 0xe8939a}, /* U+84DA */ + {0xe8ec, 0xe89390}, /* U+84D0 */ + {0xe8ed, 0xe89381}, /* U+84C1 */ + {0xe8ee, 0xe89386}, /* U+84C6 */ + {0xe8ef, 0xe89396}, /* U+84D6 */ + {0xe8f0, 0xe892a1}, /* U+84A1 */ + {0xe8f1, 0xe894a1}, /* U+8521 */ + {0xe8f2, 0xe893bf}, /* U+84FF */ + {0xe8f3, 0xe893b4}, /* U+84F4 */ + {0xe8f4, 0xe89497}, /* U+8517 */ + {0xe8f5, 0xe89498}, /* U+8518 */ + {0xe8f6, 0xe894ac}, /* U+852C */ + {0xe8f7, 0xe8949f}, /* U+851F */ + {0xe8f8, 0xe89495}, /* U+8515 */ + {0xe8f9, 0xe89494}, /* U+8514 */ + {0xe8fa, 0xe893bc}, /* U+84FC */ + {0xe8fb, 0xe89580}, /* U+8540 */ + {0xe8fc, 0xe895a3}, /* U+8563 */ + {0xe8fd, 0xe89598}, /* U+8558 */ + {0xe8fe, 0xe89588}, /* U+8548 */ + {0xe9a1, 0xe89581}, /* U+8541 */ + {0xe9a2, 0xe89882}, /* U+8602 */ + {0xe9a3, 0xe8958b}, /* U+854B */ + {0xe9a4, 0xe89595}, /* U+8555 */ + {0xe9a5, 0xe89680}, /* U+8580 */ + {0xe9a6, 0xe896a4}, /* U+85A4 */ + {0xe9a7, 0xe89688}, /* U+8588 */ + {0xe9a8, 0xe89691}, /* U+8591 */ + {0xe9a9, 0xe8968a}, /* U+858A */ + {0xe9aa, 0xe896a8}, /* U+85A8 */ + {0xe9ab, 0xe895ad}, /* U+856D */ + {0xe9ac, 0xe89694}, /* U+8594 */ + {0xe9ad, 0xe8969b}, /* U+859B */ + {0xe9ae, 0xe897aa}, /* U+85EA */ + {0xe9af, 0xe89687}, /* U+8587 */ + {0xe9b0, 0xe8969c}, /* U+859C */ + {0xe9b1, 0xe895b7}, /* U+8577 */ + {0xe9b2, 0xe895be}, /* U+857E */ + {0xe9b3, 0xe89690}, /* U+8590 */ + {0xe9b4, 0xe89789}, /* U+85C9 */ + {0xe9b5, 0xe896ba}, /* U+85BA */ + {0xe9b6, 0xe8978f}, /* U+85CF */ + {0xe9b7, 0xe896b9}, /* U+85B9 */ + {0xe9b8, 0xe89790}, /* U+85D0 */ + {0xe9b9, 0xe89795}, /* U+85D5 */ + {0xe9ba, 0xe8979d}, /* U+85DD */ + {0xe9bb, 0xe897a5}, /* U+85E5 */ + {0xe9bc, 0xe8979c}, /* U+85DC */ + {0xe9bd, 0xe897b9}, /* U+85F9 */ + {0xe9be, 0xe8988a}, /* U+860A */ + {0xe9bf, 0xe89893}, /* U+8613 */ + {0xe9c0, 0xe8988b}, /* U+860B */ + {0xe9c1, 0xe897be}, /* U+85FE */ + {0xe9c2, 0xe897ba}, /* U+85FA */ + {0xe9c3, 0xe89886}, /* U+8606 */ + {0xe9c4, 0xe898a2}, /* U+8622 */ + {0xe9c5, 0xe8989a}, /* U+861A */ + {0xe9c6, 0xe898b0}, /* U+8630 */ + {0xe9c7, 0xe898bf}, /* U+863F */ + {0xe9c8, 0xe8998d}, /* U+864D */ + {0xe9c9, 0xe4b995}, /* U+4E55 */ + {0xe9ca, 0xe89994}, /* U+8654 */ + {0xe9cb, 0xe8999f}, /* U+865F */ + {0xe9cc, 0xe899a7}, /* U+8667 */ + {0xe9cd, 0xe899b1}, /* U+8671 */ + {0xe9ce, 0xe89a93}, /* U+8693 */ + {0xe9cf, 0xe89aa3}, /* U+86A3 */ + {0xe9d0, 0xe89aa9}, /* U+86A9 */ + {0xe9d1, 0xe89aaa}, /* U+86AA */ + {0xe9d2, 0xe89a8b}, /* U+868B */ + {0xe9d3, 0xe89a8c}, /* U+868C */ + {0xe9d4, 0xe89ab6}, /* U+86B6 */ + {0xe9d5, 0xe89aaf}, /* U+86AF */ + {0xe9d6, 0xe89b84}, /* U+86C4 */ + {0xe9d7, 0xe89b86}, /* U+86C6 */ + {0xe9d8, 0xe89ab0}, /* U+86B0 */ + {0xe9d9, 0xe89b89}, /* U+86C9 */ + {0xe9da, 0xe8a0a3}, /* U+8823 */ + {0xe9db, 0xe89aab}, /* U+86AB */ + {0xe9dc, 0xe89b94}, /* U+86D4 */ + {0xe9dd, 0xe89b9e}, /* U+86DE */ + {0xe9de, 0xe89ba9}, /* U+86E9 */ + {0xe9df, 0xe89bac}, /* U+86EC */ + {0xe9e0, 0xe89b9f}, /* U+86DF */ + {0xe9e1, 0xe89b9b}, /* U+86DB */ + {0xe9e2, 0xe89baf}, /* U+86EF */ + {0xe9e3, 0xe89c92}, /* U+8712 */ + {0xe9e4, 0xe89c86}, /* U+8706 */ + {0xe9e5, 0xe89c88}, /* U+8708 */ + {0xe9e6, 0xe89c80}, /* U+8700 */ + {0xe9e7, 0xe89c83}, /* U+8703 */ + {0xe9e8, 0xe89bbb}, /* U+86FB */ + {0xe9e9, 0xe89c91}, /* U+8711 */ + {0xe9ea, 0xe89c89}, /* U+8709 */ + {0xe9eb, 0xe89c8d}, /* U+870D */ + {0xe9ec, 0xe89bb9}, /* U+86F9 */ + {0xe9ed, 0xe89c8a}, /* U+870A */ + {0xe9ee, 0xe89cb4}, /* U+8734 */ + {0xe9ef, 0xe89cbf}, /* U+873F */ + {0xe9f0, 0xe89cb7}, /* U+8737 */ + {0xe9f1, 0xe89cbb}, /* U+873B */ + {0xe9f2, 0xe89ca5}, /* U+8725 */ + {0xe9f3, 0xe89ca9}, /* U+8729 */ + {0xe9f4, 0xe89c9a}, /* U+871A */ + {0xe9f5, 0xe89da0}, /* U+8760 */ + {0xe9f6, 0xe89d9f}, /* U+875F */ + {0xe9f7, 0xe89db8}, /* U+8778 */ + {0xe9f8, 0xe89d8c}, /* U+874C */ + {0xe9f9, 0xe89d8e}, /* U+874E */ + {0xe9fa, 0xe89db4}, /* U+8774 */ + {0xe9fb, 0xe89d97}, /* U+8757 */ + {0xe9fc, 0xe89da8}, /* U+8768 */ + {0xe9fd, 0xe89dae}, /* U+876E */ + {0xe9fe, 0xe89d99}, /* U+8759 */ + {0xeaa1, 0xe89d93}, /* U+8753 */ + {0xeaa2, 0xe89da3}, /* U+8763 */ + {0xeaa3, 0xe89daa}, /* U+876A */ + {0xeaa4, 0xe8a085}, /* U+8805 */ + {0xeaa5, 0xe89ea2}, /* U+87A2 */ + {0xeaa6, 0xe89e9f}, /* U+879F */ + {0xeaa7, 0xe89e82}, /* U+8782 */ + {0xeaa8, 0xe89eaf}, /* U+87AF */ + {0xeaa9, 0xe89f8b}, /* U+87CB */ + {0xeaaa, 0xe89ebd}, /* U+87BD */ + {0xeaab, 0xe89f80}, /* U+87C0 */ + {0xeaac, 0xe89f90}, /* U+87D0 */ + {0xeaad, 0xe99b96}, /* U+96D6 */ + {0xeaae, 0xe89eab}, /* U+87AB */ + {0xeaaf, 0xe89f84}, /* U+87C4 */ + {0xeab0, 0xe89eb3}, /* U+87B3 */ + {0xeab1, 0xe89f87}, /* U+87C7 */ + {0xeab2, 0xe89f86}, /* U+87C6 */ + {0xeab3, 0xe89ebb}, /* U+87BB */ + {0xeab4, 0xe89faf}, /* U+87EF */ + {0xeab5, 0xe89fb2}, /* U+87F2 */ + {0xeab6, 0xe89fa0}, /* U+87E0 */ + {0xeab7, 0xe8a08f}, /* U+880F */ + {0xeab8, 0xe8a08d}, /* U+880D */ + {0xeab9, 0xe89fbe}, /* U+87FE */ + {0xeaba, 0xe89fb6}, /* U+87F6 */ + {0xeabb, 0xe89fb7}, /* U+87F7 */ + {0xeabc, 0xe8a08e}, /* U+880E */ + {0xeabd, 0xe89f92}, /* U+87D2 */ + {0xeabe, 0xe8a091}, /* U+8811 */ + {0xeabf, 0xe8a096}, /* U+8816 */ + {0xeac0, 0xe8a095}, /* U+8815 */ + {0xeac1, 0xe8a0a2}, /* U+8822 */ + {0xeac2, 0xe8a0a1}, /* U+8821 */ + {0xeac3, 0xe8a0b1}, /* U+8831 */ + {0xeac4, 0xe8a0b6}, /* U+8836 */ + {0xeac5, 0xe8a0b9}, /* U+8839 */ + {0xeac6, 0xe8a0a7}, /* U+8827 */ + {0xeac7, 0xe8a0bb}, /* U+883B */ + {0xeac8, 0xe8a184}, /* U+8844 */ + {0xeac9, 0xe8a182}, /* U+8842 */ + {0xeaca, 0xe8a192}, /* U+8852 */ + {0xeacb, 0xe8a199}, /* U+8859 */ + {0xeacc, 0xe8a19e}, /* U+885E */ + {0xeacd, 0xe8a1a2}, /* U+8862 */ + {0xeace, 0xe8a1ab}, /* U+886B */ + {0xeacf, 0xe8a281}, /* U+8881 */ + {0xead0, 0xe8a1be}, /* U+887E */ + {0xead1, 0xe8a29e}, /* U+889E */ + {0xead2, 0xe8a1b5}, /* U+8875 */ + {0xead3, 0xe8a1bd}, /* U+887D */ + {0xead4, 0xe8a2b5}, /* U+88B5 */ + {0xead5, 0xe8a1b2}, /* U+8872 */ + {0xead6, 0xe8a282}, /* U+8882 */ + {0xead7, 0xe8a297}, /* U+8897 */ + {0xead8, 0xe8a292}, /* U+8892 */ + {0xead9, 0xe8a2ae}, /* U+88AE */ + {0xeada, 0xe8a299}, /* U+8899 */ + {0xeadb, 0xe8a2a2}, /* U+88A2 */ + {0xeadc, 0xe8a28d}, /* U+888D */ + {0xeadd, 0xe8a2a4}, /* U+88A4 */ + {0xeade, 0xe8a2b0}, /* U+88B0 */ + {0xeadf, 0xe8a2bf}, /* U+88BF */ + {0xeae0, 0xe8a2b1}, /* U+88B1 */ + {0xeae1, 0xe8a383}, /* U+88C3 */ + {0xeae2, 0xe8a384}, /* U+88C4 */ + {0xeae3, 0xe8a394}, /* U+88D4 */ + {0xeae4, 0xe8a398}, /* U+88D8 */ + {0xeae5, 0xe8a399}, /* U+88D9 */ + {0xeae6, 0xe8a39d}, /* U+88DD */ + {0xeae7, 0xe8a3b9}, /* U+88F9 */ + {0xeae8, 0xe8a482}, /* U+8902 */ + {0xeae9, 0xe8a3bc}, /* U+88FC */ + {0xeaea, 0xe8a3b4}, /* U+88F4 */ + {0xeaeb, 0xe8a3a8}, /* U+88E8 */ + {0xeaec, 0xe8a3b2}, /* U+88F2 */ + {0xeaed, 0xe8a484}, /* U+8904 */ + {0xeaee, 0xe8a48c}, /* U+890C */ + {0xeaef, 0xe8a48a}, /* U+890A */ + {0xeaf0, 0xe8a493}, /* U+8913 */ + {0xeaf1, 0xe8a583}, /* U+8943 */ + {0xeaf2, 0xe8a49e}, /* U+891E */ + {0xeaf3, 0xe8a4a5}, /* U+8925 */ + {0xeaf4, 0xe8a4aa}, /* U+892A */ + {0xeaf5, 0xe8a4ab}, /* U+892B */ + {0xeaf6, 0xe8a581}, /* U+8941 */ + {0xeaf7, 0xe8a584}, /* U+8944 */ + {0xeaf8, 0xe8a4bb}, /* U+893B */ + {0xeaf9, 0xe8a4b6}, /* U+8936 */ + {0xeafa, 0xe8a4b8}, /* U+8938 */ + {0xeafb, 0xe8a58c}, /* U+894C */ + {0xeafc, 0xe8a49d}, /* U+891D */ + {0xeafd, 0xe8a5a0}, /* U+8960 */ + {0xeafe, 0xe8a59e}, /* U+895E */ + {0xeba1, 0xe8a5a6}, /* U+8966 */ + {0xeba2, 0xe8a5a4}, /* U+8964 */ + {0xeba3, 0xe8a5ad}, /* U+896D */ + {0xeba4, 0xe8a5aa}, /* U+896A */ + {0xeba5, 0xe8a5af}, /* U+896F */ + {0xeba6, 0xe8a5b4}, /* U+8974 */ + {0xeba7, 0xe8a5b7}, /* U+8977 */ + {0xeba8, 0xe8a5be}, /* U+897E */ + {0xeba9, 0xe8a683}, /* U+8983 */ + {0xebaa, 0xe8a688}, /* U+8988 */ + {0xebab, 0xe8a68a}, /* U+898A */ + {0xebac, 0xe8a693}, /* U+8993 */ + {0xebad, 0xe8a698}, /* U+8998 */ + {0xebae, 0xe8a6a1}, /* U+89A1 */ + {0xebaf, 0xe8a6a9}, /* U+89A9 */ + {0xebb0, 0xe8a6a6}, /* U+89A6 */ + {0xebb1, 0xe8a6ac}, /* U+89AC */ + {0xebb2, 0xe8a6af}, /* U+89AF */ + {0xebb3, 0xe8a6b2}, /* U+89B2 */ + {0xebb4, 0xe8a6ba}, /* U+89BA */ + {0xebb5, 0xe8a6bd}, /* U+89BD */ + {0xebb6, 0xe8a6bf}, /* U+89BF */ + {0xebb7, 0xe8a780}, /* U+89C0 */ + {0xebb8, 0xe8a79a}, /* U+89DA */ + {0xebb9, 0xe8a79c}, /* U+89DC */ + {0xebba, 0xe8a79d}, /* U+89DD */ + {0xebbb, 0xe8a7a7}, /* U+89E7 */ + {0xebbc, 0xe8a7b4}, /* U+89F4 */ + {0xebbd, 0xe8a7b8}, /* U+89F8 */ + {0xebbe, 0xe8a883}, /* U+8A03 */ + {0xebbf, 0xe8a896}, /* U+8A16 */ + {0xebc0, 0xe8a890}, /* U+8A10 */ + {0xebc1, 0xe8a88c}, /* U+8A0C */ + {0xebc2, 0xe8a89b}, /* U+8A1B */ + {0xebc3, 0xe8a89d}, /* U+8A1D */ + {0xebc4, 0xe8a8a5}, /* U+8A25 */ + {0xebc5, 0xe8a8b6}, /* U+8A36 */ + {0xebc6, 0xe8a981}, /* U+8A41 */ + {0xebc7, 0xe8a99b}, /* U+8A5B */ + {0xebc8, 0xe8a992}, /* U+8A52 */ + {0xebc9, 0xe8a986}, /* U+8A46 */ + {0xebca, 0xe8a988}, /* U+8A48 */ + {0xebcb, 0xe8a9bc}, /* U+8A7C */ + {0xebcc, 0xe8a9ad}, /* U+8A6D */ + {0xebcd, 0xe8a9ac}, /* U+8A6C */ + {0xebce, 0xe8a9a2}, /* U+8A62 */ + {0xebcf, 0xe8aa85}, /* U+8A85 */ + {0xebd0, 0xe8aa82}, /* U+8A82 */ + {0xebd1, 0xe8aa84}, /* U+8A84 */ + {0xebd2, 0xe8aaa8}, /* U+8AA8 */ + {0xebd3, 0xe8aaa1}, /* U+8AA1 */ + {0xebd4, 0xe8aa91}, /* U+8A91 */ + {0xebd5, 0xe8aaa5}, /* U+8AA5 */ + {0xebd6, 0xe8aaa6}, /* U+8AA6 */ + {0xebd7, 0xe8aa9a}, /* U+8A9A */ + {0xebd8, 0xe8aaa3}, /* U+8AA3 */ + {0xebd9, 0xe8ab84}, /* U+8AC4 */ + {0xebda, 0xe8ab8d}, /* U+8ACD */ + {0xebdb, 0xe8ab82}, /* U+8AC2 */ + {0xebdc, 0xe8ab9a}, /* U+8ADA */ + {0xebdd, 0xe8abab}, /* U+8AEB */ + {0xebde, 0xe8abb3}, /* U+8AF3 */ + {0xebdf, 0xe8aba7}, /* U+8AE7 */ + {0xebe0, 0xe8aba4}, /* U+8AE4 */ + {0xebe1, 0xe8abb1}, /* U+8AF1 */ + {0xebe2, 0xe8ac94}, /* U+8B14 */ + {0xebe3, 0xe8aba0}, /* U+8AE0 */ + {0xebe4, 0xe8aba2}, /* U+8AE2 */ + {0xebe5, 0xe8abb7}, /* U+8AF7 */ + {0xebe6, 0xe8ab9e}, /* U+8ADE */ + {0xebe7, 0xe8ab9b}, /* U+8ADB */ + {0xebe8, 0xe8ac8c}, /* U+8B0C */ + {0xebe9, 0xe8ac87}, /* U+8B07 */ + {0xebea, 0xe8ac9a}, /* U+8B1A */ + {0xebeb, 0xe8aba1}, /* U+8AE1 */ + {0xebec, 0xe8ac96}, /* U+8B16 */ + {0xebed, 0xe8ac90}, /* U+8B10 */ + {0xebee, 0xe8ac97}, /* U+8B17 */ + {0xebef, 0xe8aca0}, /* U+8B20 */ + {0xebf0, 0xe8acb3}, /* U+8B33 */ + {0xebf1, 0xe99eab}, /* U+97AB */ + {0xebf2, 0xe8aca6}, /* U+8B26 */ + {0xebf3, 0xe8acab}, /* U+8B2B */ + {0xebf4, 0xe8acbe}, /* U+8B3E */ + {0xebf5, 0xe8aca8}, /* U+8B28 */ + {0xebf6, 0xe8ad81}, /* U+8B41 */ + {0xebf7, 0xe8ad8c}, /* U+8B4C */ + {0xebf8, 0xe8ad8f}, /* U+8B4F */ + {0xebf9, 0xe8ad8e}, /* U+8B4E */ + {0xebfa, 0xe8ad89}, /* U+8B49 */ + {0xebfb, 0xe8ad96}, /* U+8B56 */ + {0xebfc, 0xe8ad9b}, /* U+8B5B */ + {0xebfd, 0xe8ad9a}, /* U+8B5A */ + {0xebfe, 0xe8adab}, /* U+8B6B */ + {0xeca1, 0xe8ad9f}, /* U+8B5F */ + {0xeca2, 0xe8adac}, /* U+8B6C */ + {0xeca3, 0xe8adaf}, /* U+8B6F */ + {0xeca4, 0xe8adb4}, /* U+8B74 */ + {0xeca5, 0xe8adbd}, /* U+8B7D */ + {0xeca6, 0xe8ae80}, /* U+8B80 */ + {0xeca7, 0xe8ae8c}, /* U+8B8C */ + {0xeca8, 0xe8ae8e}, /* U+8B8E */ + {0xeca9, 0xe8ae92}, /* U+8B92 */ + {0xecaa, 0xe8ae93}, /* U+8B93 */ + {0xecab, 0xe8ae96}, /* U+8B96 */ + {0xecac, 0xe8ae99}, /* U+8B99 */ + {0xecad, 0xe8ae9a}, /* U+8B9A */ + {0xecae, 0xe8b0ba}, /* U+8C3A */ + {0xecaf, 0xe8b181}, /* U+8C41 */ + {0xecb0, 0xe8b0bf}, /* U+8C3F */ + {0xecb1, 0xe8b188}, /* U+8C48 */ + {0xecb2, 0xe8b18c}, /* U+8C4C */ + {0xecb3, 0xe8b18e}, /* U+8C4E */ + {0xecb4, 0xe8b190}, /* U+8C50 */ + {0xecb5, 0xe8b195}, /* U+8C55 */ + {0xecb6, 0xe8b1a2}, /* U+8C62 */ + {0xecb7, 0xe8b1ac}, /* U+8C6C */ + {0xecb8, 0xe8b1b8}, /* U+8C78 */ + {0xecb9, 0xe8b1ba}, /* U+8C7A */ + {0xecba, 0xe8b282}, /* U+8C82 */ + {0xecbb, 0xe8b289}, /* U+8C89 */ + {0xecbc, 0xe8b285}, /* U+8C85 */ + {0xecbd, 0xe8b28a}, /* U+8C8A */ + {0xecbe, 0xe8b28d}, /* U+8C8D */ + {0xecbf, 0xe8b28e}, /* U+8C8E */ + {0xecc0, 0xe8b294}, /* U+8C94 */ + {0xecc1, 0xe8b1bc}, /* U+8C7C */ + {0xecc2, 0xe8b298}, /* U+8C98 */ + {0xecc3, 0xe6889d}, /* U+621D */ + {0xecc4, 0xe8b2ad}, /* U+8CAD */ + {0xecc5, 0xe8b2aa}, /* U+8CAA */ + {0xecc6, 0xe8b2bd}, /* U+8CBD */ + {0xecc7, 0xe8b2b2}, /* U+8CB2 */ + {0xecc8, 0xe8b2b3}, /* U+8CB3 */ + {0xecc9, 0xe8b2ae}, /* U+8CAE */ + {0xecca, 0xe8b2b6}, /* U+8CB6 */ + {0xeccb, 0xe8b388}, /* U+8CC8 */ + {0xeccc, 0xe8b381}, /* U+8CC1 */ + {0xeccd, 0xe8b3a4}, /* U+8CE4 */ + {0xecce, 0xe8b3a3}, /* U+8CE3 */ + {0xeccf, 0xe8b39a}, /* U+8CDA */ + {0xecd0, 0xe8b3bd}, /* U+8CFD */ + {0xecd1, 0xe8b3ba}, /* U+8CFA */ + {0xecd2, 0xe8b3bb}, /* U+8CFB */ + {0xecd3, 0xe8b484}, /* U+8D04 */ + {0xecd4, 0xe8b485}, /* U+8D05 */ + {0xecd5, 0xe8b48a}, /* U+8D0A */ + {0xecd6, 0xe8b487}, /* U+8D07 */ + {0xecd7, 0xe8b48f}, /* U+8D0F */ + {0xecd8, 0xe8b48d}, /* U+8D0D */ + {0xecd9, 0xe8b490}, /* U+8D10 */ + {0xecda, 0xe9bd8e}, /* U+9F4E */ + {0xecdb, 0xe8b493}, /* U+8D13 */ + {0xecdc, 0xe8b38d}, /* U+8CCD */ + {0xecdd, 0xe8b494}, /* U+8D14 */ + {0xecde, 0xe8b496}, /* U+8D16 */ + {0xecdf, 0xe8b5a7}, /* U+8D67 */ + {0xece0, 0xe8b5ad}, /* U+8D6D */ + {0xece1, 0xe8b5b1}, /* U+8D71 */ + {0xece2, 0xe8b5b3}, /* U+8D73 */ + {0xece3, 0xe8b681}, /* U+8D81 */ + {0xece4, 0xe8b699}, /* U+8D99 */ + {0xece5, 0xe8b782}, /* U+8DC2 */ + {0xece6, 0xe8b6be}, /* U+8DBE */ + {0xece7, 0xe8b6ba}, /* U+8DBA */ + {0xece8, 0xe8b78f}, /* U+8DCF */ + {0xece9, 0xe8b79a}, /* U+8DDA */ + {0xecea, 0xe8b796}, /* U+8DD6 */ + {0xeceb, 0xe8b78c}, /* U+8DCC */ + {0xecec, 0xe8b79b}, /* U+8DDB */ + {0xeced, 0xe8b78b}, /* U+8DCB */ + {0xecee, 0xe8b7aa}, /* U+8DEA */ + {0xecef, 0xe8b7ab}, /* U+8DEB */ + {0xecf0, 0xe8b79f}, /* U+8DDF */ + {0xecf1, 0xe8b7a3}, /* U+8DE3 */ + {0xecf2, 0xe8b7bc}, /* U+8DFC */ + {0xecf3, 0xe8b888}, /* U+8E08 */ + {0xecf4, 0xe8b889}, /* U+8E09 */ + {0xecf5, 0xe8b7bf}, /* U+8DFF */ + {0xecf6, 0xe8b89d}, /* U+8E1D */ + {0xecf7, 0xe8b89e}, /* U+8E1E */ + {0xecf8, 0xe8b890}, /* U+8E10 */ + {0xecf9, 0xe8b89f}, /* U+8E1F */ + {0xecfa, 0xe8b982}, /* U+8E42 */ + {0xecfb, 0xe8b8b5}, /* U+8E35 */ + {0xecfc, 0xe8b8b0}, /* U+8E30 */ + {0xecfd, 0xe8b8b4}, /* U+8E34 */ + {0xecfe, 0xe8b98a}, /* U+8E4A */ + {0xeda1, 0xe8b987}, /* U+8E47 */ + {0xeda2, 0xe8b989}, /* U+8E49 */ + {0xeda3, 0xe8b98c}, /* U+8E4C */ + {0xeda4, 0xe8b990}, /* U+8E50 */ + {0xeda5, 0xe8b988}, /* U+8E48 */ + {0xeda6, 0xe8b999}, /* U+8E59 */ + {0xeda7, 0xe8b9a4}, /* U+8E64 */ + {0xeda8, 0xe8b9a0}, /* U+8E60 */ + {0xeda9, 0xe8b8aa}, /* U+8E2A */ + {0xedaa, 0xe8b9a3}, /* U+8E63 */ + {0xedab, 0xe8b995}, /* U+8E55 */ + {0xedac, 0xe8b9b6}, /* U+8E76 */ + {0xedad, 0xe8b9b2}, /* U+8E72 */ + {0xedae, 0xe8b9bc}, /* U+8E7C */ + {0xedaf, 0xe8ba81}, /* U+8E81 */ + {0xedb0, 0xe8ba87}, /* U+8E87 */ + {0xedb1, 0xe8ba85}, /* U+8E85 */ + {0xedb2, 0xe8ba84}, /* U+8E84 */ + {0xedb3, 0xe8ba8b}, /* U+8E8B */ + {0xedb4, 0xe8ba8a}, /* U+8E8A */ + {0xedb5, 0xe8ba93}, /* U+8E93 */ + {0xedb6, 0xe8ba91}, /* U+8E91 */ + {0xedb7, 0xe8ba94}, /* U+8E94 */ + {0xedb8, 0xe8ba99}, /* U+8E99 */ + {0xedb9, 0xe8baaa}, /* U+8EAA */ + {0xedba, 0xe8baa1}, /* U+8EA1 */ + {0xedbb, 0xe8baac}, /* U+8EAC */ + {0xedbc, 0xe8bab0}, /* U+8EB0 */ + {0xedbd, 0xe8bb86}, /* U+8EC6 */ + {0xedbe, 0xe8bab1}, /* U+8EB1 */ + {0xedbf, 0xe8babe}, /* U+8EBE */ + {0xedc0, 0xe8bb85}, /* U+8EC5 */ + {0xedc1, 0xe8bb88}, /* U+8EC8 */ + {0xedc2, 0xe8bb8b}, /* U+8ECB */ + {0xedc3, 0xe8bb9b}, /* U+8EDB */ + {0xedc4, 0xe8bba3}, /* U+8EE3 */ + {0xedc5, 0xe8bbbc}, /* U+8EFC */ + {0xedc6, 0xe8bbbb}, /* U+8EFB */ + {0xedc7, 0xe8bbab}, /* U+8EEB */ + {0xedc8, 0xe8bbbe}, /* U+8EFE */ + {0xedc9, 0xe8bc8a}, /* U+8F0A */ + {0xedca, 0xe8bc85}, /* U+8F05 */ + {0xedcb, 0xe8bc95}, /* U+8F15 */ + {0xedcc, 0xe8bc92}, /* U+8F12 */ + {0xedcd, 0xe8bc99}, /* U+8F19 */ + {0xedce, 0xe8bc93}, /* U+8F13 */ + {0xedcf, 0xe8bc9c}, /* U+8F1C */ + {0xedd0, 0xe8bc9f}, /* U+8F1F */ + {0xedd1, 0xe8bc9b}, /* U+8F1B */ + {0xedd2, 0xe8bc8c}, /* U+8F0C */ + {0xedd3, 0xe8bca6}, /* U+8F26 */ + {0xedd4, 0xe8bcb3}, /* U+8F33 */ + {0xedd5, 0xe8bcbb}, /* U+8F3B */ + {0xedd6, 0xe8bcb9}, /* U+8F39 */ + {0xedd7, 0xe8bd85}, /* U+8F45 */ + {0xedd8, 0xe8bd82}, /* U+8F42 */ + {0xedd9, 0xe8bcbe}, /* U+8F3E */ + {0xedda, 0xe8bd8c}, /* U+8F4C */ + {0xeddb, 0xe8bd89}, /* U+8F49 */ + {0xeddc, 0xe8bd86}, /* U+8F46 */ + {0xeddd, 0xe8bd8e}, /* U+8F4E */ + {0xedde, 0xe8bd97}, /* U+8F57 */ + {0xeddf, 0xe8bd9c}, /* U+8F5C */ + {0xede0, 0xe8bda2}, /* U+8F62 */ + {0xede1, 0xe8bda3}, /* U+8F63 */ + {0xede2, 0xe8bda4}, /* U+8F64 */ + {0xede3, 0xe8be9c}, /* U+8F9C */ + {0xede4, 0xe8be9f}, /* U+8F9F */ + {0xede5, 0xe8bea3}, /* U+8FA3 */ + {0xede6, 0xe8bead}, /* U+8FAD */ + {0xede7, 0xe8beaf}, /* U+8FAF */ + {0xede8, 0xe8beb7}, /* U+8FB7 */ + {0xede9, 0xe8bf9a}, /* U+8FDA */ + {0xedea, 0xe8bfa5}, /* U+8FE5 */ + {0xedeb, 0xe8bfa2}, /* U+8FE2 */ + {0xedec, 0xe8bfaa}, /* U+8FEA */ + {0xeded, 0xe8bfaf}, /* U+8FEF */ + {0xedee, 0xe98287}, /* U+9087 */ + {0xedef, 0xe8bfb4}, /* U+8FF4 */ + {0xedf0, 0xe98085}, /* U+9005 */ + {0xedf1, 0xe8bfb9}, /* U+8FF9 */ + {0xedf2, 0xe8bfba}, /* U+8FFA */ + {0xedf3, 0xe98091}, /* U+9011 */ + {0xedf4, 0xe98095}, /* U+9015 */ + {0xedf5, 0xe980a1}, /* U+9021 */ + {0xedf6, 0xe9808d}, /* U+900D */ + {0xedf7, 0xe9809e}, /* U+901E */ + {0xedf8, 0xe98096}, /* U+9016 */ + {0xedf9, 0xe9808b}, /* U+900B */ + {0xedfa, 0xe980a7}, /* U+9027 */ + {0xedfb, 0xe980b6}, /* U+9036 */ + {0xedfc, 0xe980b5}, /* U+9035 */ + {0xedfd, 0xe980b9}, /* U+9039 */ + {0xedfe, 0xe8bfb8}, /* U+8FF8 */ + {0xeea1, 0xe9818f}, /* U+904F */ + {0xeea2, 0xe98190}, /* U+9050 */ + {0xeea3, 0xe98191}, /* U+9051 */ + {0xeea4, 0xe98192}, /* U+9052 */ + {0xeea5, 0xe9808e}, /* U+900E */ + {0xeea6, 0xe98189}, /* U+9049 */ + {0xeea7, 0xe980be}, /* U+903E */ + {0xeea8, 0xe98196}, /* U+9056 */ + {0xeea9, 0xe98198}, /* U+9058 */ + {0xeeaa, 0xe9819e}, /* U+905E */ + {0xeeab, 0xe981a8}, /* U+9068 */ + {0xeeac, 0xe981af}, /* U+906F */ + {0xeead, 0xe981b6}, /* U+9076 */ + {0xeeae, 0xe99aa8}, /* U+96A8 */ + {0xeeaf, 0xe981b2}, /* U+9072 */ + {0xeeb0, 0xe98282}, /* U+9082 */ + {0xeeb1, 0xe981bd}, /* U+907D */ + {0xeeb2, 0xe98281}, /* U+9081 */ + {0xeeb3, 0xe98280}, /* U+9080 */ + {0xeeb4, 0xe9828a}, /* U+908A */ + {0xeeb5, 0xe98289}, /* U+9089 */ + {0xeeb6, 0xe9828f}, /* U+908F */ + {0xeeb7, 0xe982a8}, /* U+90A8 */ + {0xeeb8, 0xe982af}, /* U+90AF */ + {0xeeb9, 0xe982b1}, /* U+90B1 */ + {0xeeba, 0xe982b5}, /* U+90B5 */ + {0xeebb, 0xe983a2}, /* U+90E2 */ + {0xeebc, 0xe983a4}, /* U+90E4 */ + {0xeebd, 0xe68988}, /* U+6248 */ + {0xeebe, 0xe9839b}, /* U+90DB */ + {0xeebf, 0xe98482}, /* U+9102 */ + {0xeec0, 0xe98492}, /* U+9112 */ + {0xeec1, 0xe98499}, /* U+9119 */ + {0xeec2, 0xe984b2}, /* U+9132 */ + {0xeec3, 0xe984b0}, /* U+9130 */ + {0xeec4, 0xe9858a}, /* U+914A */ + {0xeec5, 0xe98596}, /* U+9156 */ + {0xeec6, 0xe98598}, /* U+9158 */ + {0xeec7, 0xe985a3}, /* U+9163 */ + {0xeec8, 0xe985a5}, /* U+9165 */ + {0xeec9, 0xe985a9}, /* U+9169 */ + {0xeeca, 0xe985b3}, /* U+9173 */ + {0xeecb, 0xe985b2}, /* U+9172 */ + {0xeecc, 0xe9868b}, /* U+918B */ + {0xeecd, 0xe98689}, /* U+9189 */ + {0xeece, 0xe98682}, /* U+9182 */ + {0xeecf, 0xe986a2}, /* U+91A2 */ + {0xeed0, 0xe986ab}, /* U+91AB */ + {0xeed1, 0xe986af}, /* U+91AF */ + {0xeed2, 0xe986aa}, /* U+91AA */ + {0xeed3, 0xe986b5}, /* U+91B5 */ + {0xeed4, 0xe986b4}, /* U+91B4 */ + {0xeed5, 0xe986ba}, /* U+91BA */ + {0xeed6, 0xe98780}, /* U+91C0 */ + {0xeed7, 0xe98781}, /* U+91C1 */ + {0xeed8, 0xe98789}, /* U+91C9 */ + {0xeed9, 0xe9878b}, /* U+91CB */ + {0xeeda, 0xe98790}, /* U+91D0 */ + {0xeedb, 0xe98796}, /* U+91D6 */ + {0xeedc, 0xe9879f}, /* U+91DF */ + {0xeedd, 0xe987a1}, /* U+91E1 */ + {0xeede, 0xe9879b}, /* U+91DB */ + {0xeedf, 0xe987bc}, /* U+91FC */ + {0xeee0, 0xe987b5}, /* U+91F5 */ + {0xeee1, 0xe987b6}, /* U+91F6 */ + {0xeee2, 0xe9889e}, /* U+921E */ + {0xeee3, 0xe987bf}, /* U+91FF */ + {0xeee4, 0xe98894}, /* U+9214 */ + {0xeee5, 0xe988ac}, /* U+922C */ + {0xeee6, 0xe98895}, /* U+9215 */ + {0xeee7, 0xe98891}, /* U+9211 */ + {0xeee8, 0xe9899e}, /* U+925E */ + {0xeee9, 0xe98997}, /* U+9257 */ + {0xeeea, 0xe98985}, /* U+9245 */ + {0xeeeb, 0xe98989}, /* U+9249 */ + {0xeeec, 0xe989a4}, /* U+9264 */ + {0xeeed, 0xe98988}, /* U+9248 */ + {0xeeee, 0xe98a95}, /* U+9295 */ + {0xeeef, 0xe988bf}, /* U+923F */ + {0xeef0, 0xe9898b}, /* U+924B */ + {0xeef1, 0xe98990}, /* U+9250 */ + {0xeef2, 0xe98a9c}, /* U+929C */ + {0xeef3, 0xe98a96}, /* U+9296 */ + {0xeef4, 0xe98a93}, /* U+9293 */ + {0xeef5, 0xe98a9b}, /* U+929B */ + {0xeef6, 0xe9899a}, /* U+925A */ + {0xeef7, 0xe98b8f}, /* U+92CF */ + {0xeef8, 0xe98ab9}, /* U+92B9 */ + {0xeef9, 0xe98ab7}, /* U+92B7 */ + {0xeefa, 0xe98ba9}, /* U+92E9 */ + {0xeefb, 0xe98c8f}, /* U+930F */ + {0xeefc, 0xe98bba}, /* U+92FA */ + {0xeefd, 0xe98d84}, /* U+9344 */ + {0xeefe, 0xe98cae}, /* U+932E */ + {0xefa1, 0xe98c99}, /* U+9319 */ + {0xefa2, 0xe98ca2}, /* U+9322 */ + {0xefa3, 0xe98c9a}, /* U+931A */ + {0xefa4, 0xe98ca3}, /* U+9323 */ + {0xefa5, 0xe98cba}, /* U+933A */ + {0xefa6, 0xe98cb5}, /* U+9335 */ + {0xefa7, 0xe98cbb}, /* U+933B */ + {0xefa8, 0xe98d9c}, /* U+935C */ + {0xefa9, 0xe98da0}, /* U+9360 */ + {0xefaa, 0xe98dbc}, /* U+937C */ + {0xefab, 0xe98dae}, /* U+936E */ + {0xefac, 0xe98d96}, /* U+9356 */ + {0xefad, 0xe98eb0}, /* U+93B0 */ + {0xefae, 0xe98eac}, /* U+93AC */ + {0xefaf, 0xe98ead}, /* U+93AD */ + {0xefb0, 0xe98e94}, /* U+9394 */ + {0xefb1, 0xe98eb9}, /* U+93B9 */ + {0xefb2, 0xe98f96}, /* U+93D6 */ + {0xefb3, 0xe98f97}, /* U+93D7 */ + {0xefb4, 0xe98fa8}, /* U+93E8 */ + {0xefb5, 0xe98fa5}, /* U+93E5 */ + {0xefb6, 0xe98f98}, /* U+93D8 */ + {0xefb7, 0xe98f83}, /* U+93C3 */ + {0xefb8, 0xe98f9d}, /* U+93DD */ + {0xefb9, 0xe98f90}, /* U+93D0 */ + {0xefba, 0xe98f88}, /* U+93C8 */ + {0xefbb, 0xe98fa4}, /* U+93E4 */ + {0xefbc, 0xe9909a}, /* U+941A */ + {0xefbd, 0xe99094}, /* U+9414 */ + {0xefbe, 0xe99093}, /* U+9413 */ + {0xefbf, 0xe99083}, /* U+9403 */ + {0xefc0, 0xe99087}, /* U+9407 */ + {0xefc1, 0xe99090}, /* U+9410 */ + {0xefc2, 0xe990b6}, /* U+9436 */ + {0xefc3, 0xe990ab}, /* U+942B */ + {0xefc4, 0xe990b5}, /* U+9435 */ + {0xefc5, 0xe990a1}, /* U+9421 */ + {0xefc6, 0xe990ba}, /* U+943A */ + {0xefc7, 0xe99181}, /* U+9441 */ + {0xefc8, 0xe99192}, /* U+9452 */ + {0xefc9, 0xe99184}, /* U+9444 */ + {0xefca, 0xe9919b}, /* U+945B */ + {0xefcb, 0xe991a0}, /* U+9460 */ + {0xefcc, 0xe991a2}, /* U+9462 */ + {0xefcd, 0xe9919e}, /* U+945E */ + {0xefce, 0xe991aa}, /* U+946A */ + {0xefcf, 0xe988a9}, /* U+9229 */ + {0xefd0, 0xe991b0}, /* U+9470 */ + {0xefd1, 0xe991b5}, /* U+9475 */ + {0xefd2, 0xe991b7}, /* U+9477 */ + {0xefd3, 0xe991bd}, /* U+947D */ + {0xefd4, 0xe9919a}, /* U+945A */ + {0xefd5, 0xe991bc}, /* U+947C */ + {0xefd6, 0xe991be}, /* U+947E */ + {0xefd7, 0xe99281}, /* U+9481 */ + {0xefd8, 0xe991bf}, /* U+947F */ + {0xefd9, 0xe99682}, /* U+9582 */ + {0xefda, 0xe99687}, /* U+9587 */ + {0xefdb, 0xe9968a}, /* U+958A */ + {0xefdc, 0xe99694}, /* U+9594 */ + {0xefdd, 0xe99696}, /* U+9596 */ + {0xefde, 0xe99698}, /* U+9598 */ + {0xefdf, 0xe99699}, /* U+9599 */ + {0xefe0, 0xe996a0}, /* U+95A0 */ + {0xefe1, 0xe996a8}, /* U+95A8 */ + {0xefe2, 0xe996a7}, /* U+95A7 */ + {0xefe3, 0xe996ad}, /* U+95AD */ + {0xefe4, 0xe996bc}, /* U+95BC */ + {0xefe5, 0xe996bb}, /* U+95BB */ + {0xefe6, 0xe996b9}, /* U+95B9 */ + {0xefe7, 0xe996be}, /* U+95BE */ + {0xefe8, 0xe9978a}, /* U+95CA */ + {0xefe9, 0xe6bfb6}, /* U+6FF6 */ + {0xefea, 0xe99783}, /* U+95C3 */ + {0xefeb, 0xe9978d}, /* U+95CD */ + {0xefec, 0xe9978c}, /* U+95CC */ + {0xefed, 0xe99795}, /* U+95D5 */ + {0xefee, 0xe99794}, /* U+95D4 */ + {0xefef, 0xe99796}, /* U+95D6 */ + {0xeff0, 0xe9979c}, /* U+95DC */ + {0xeff1, 0xe997a1}, /* U+95E1 */ + {0xeff2, 0xe997a5}, /* U+95E5 */ + {0xeff3, 0xe997a2}, /* U+95E2 */ + {0xeff4, 0xe998a1}, /* U+9621 */ + {0xeff5, 0xe998a8}, /* U+9628 */ + {0xeff6, 0xe998ae}, /* U+962E */ + {0xeff7, 0xe998af}, /* U+962F */ + {0xeff8, 0xe99982}, /* U+9642 */ + {0xeff9, 0xe9998c}, /* U+964C */ + {0xeffa, 0xe9998f}, /* U+964F */ + {0xeffb, 0xe9998b}, /* U+964B */ + {0xeffc, 0xe999b7}, /* U+9677 */ + {0xeffd, 0xe9999c}, /* U+965C */ + {0xeffe, 0xe9999e}, /* U+965E */ + {0xf0a1, 0xe9999d}, /* U+965D */ + {0xf0a2, 0xe9999f}, /* U+965F */ + {0xf0a3, 0xe999a6}, /* U+9666 */ + {0xf0a4, 0xe999b2}, /* U+9672 */ + {0xf0a5, 0xe999ac}, /* U+966C */ + {0xf0a6, 0xe99a8d}, /* U+968D */ + {0xf0a7, 0xe99a98}, /* U+9698 */ + {0xf0a8, 0xe99a95}, /* U+9695 */ + {0xf0a9, 0xe99a97}, /* U+9697 */ + {0xf0aa, 0xe99aaa}, /* U+96AA */ + {0xf0ab, 0xe99aa7}, /* U+96A7 */ + {0xf0ac, 0xe99ab1}, /* U+96B1 */ + {0xf0ad, 0xe99ab2}, /* U+96B2 */ + {0xf0ae, 0xe99ab0}, /* U+96B0 */ + {0xf0af, 0xe99ab4}, /* U+96B4 */ + {0xf0b0, 0xe99ab6}, /* U+96B6 */ + {0xf0b1, 0xe99ab8}, /* U+96B8 */ + {0xf0b2, 0xe99ab9}, /* U+96B9 */ + {0xf0b3, 0xe99b8e}, /* U+96CE */ + {0xf0b4, 0xe99b8b}, /* U+96CB */ + {0xf0b5, 0xe99b89}, /* U+96C9 */ + {0xf0b6, 0xe99b8d}, /* U+96CD */ + {0xf0b7, 0xe8a58d}, /* U+894D */ + {0xf0b8, 0xe99b9c}, /* U+96DC */ + {0xf0b9, 0xe99c8d}, /* U+970D */ + {0xf0ba, 0xe99b95}, /* U+96D5 */ + {0xf0bb, 0xe99bb9}, /* U+96F9 */ + {0xf0bc, 0xe99c84}, /* U+9704 */ + {0xf0bd, 0xe99c86}, /* U+9706 */ + {0xf0be, 0xe99c88}, /* U+9708 */ + {0xf0bf, 0xe99c93}, /* U+9713 */ + {0xf0c0, 0xe99c8e}, /* U+970E */ + {0xf0c1, 0xe99c91}, /* U+9711 */ + {0xf0c2, 0xe99c8f}, /* U+970F */ + {0xf0c3, 0xe99c96}, /* U+9716 */ + {0xf0c4, 0xe99c99}, /* U+9719 */ + {0xf0c5, 0xe99ca4}, /* U+9724 */ + {0xf0c6, 0xe99caa}, /* U+972A */ + {0xf0c7, 0xe99cb0}, /* U+9730 */ + {0xf0c8, 0xe99cb9}, /* U+9739 */ + {0xf0c9, 0xe99cbd}, /* U+973D */ + {0xf0ca, 0xe99cbe}, /* U+973E */ + {0xf0cb, 0xe99d84}, /* U+9744 */ + {0xf0cc, 0xe99d86}, /* U+9746 */ + {0xf0cd, 0xe99d88}, /* U+9748 */ + {0xf0ce, 0xe99d82}, /* U+9742 */ + {0xf0cf, 0xe99d89}, /* U+9749 */ + {0xf0d0, 0xe99d9c}, /* U+975C */ + {0xf0d1, 0xe99da0}, /* U+9760 */ + {0xf0d2, 0xe99da4}, /* U+9764 */ + {0xf0d3, 0xe99da6}, /* U+9766 */ + {0xf0d4, 0xe99da8}, /* U+9768 */ + {0xf0d5, 0xe58b92}, /* U+52D2 */ + {0xf0d6, 0xe99dab}, /* U+976B */ + {0xf0d7, 0xe99db1}, /* U+9771 */ + {0xf0d8, 0xe99db9}, /* U+9779 */ + {0xf0d9, 0xe99e85}, /* U+9785 */ + {0xf0da, 0xe99dbc}, /* U+977C */ + {0xf0db, 0xe99e81}, /* U+9781 */ + {0xf0dc, 0xe99dba}, /* U+977A */ + {0xf0dd, 0xe99e86}, /* U+9786 */ + {0xf0de, 0xe99e8b}, /* U+978B */ + {0xf0df, 0xe99e8f}, /* U+978F */ + {0xf0e0, 0xe99e90}, /* U+9790 */ + {0xf0e1, 0xe99e9c}, /* U+979C */ + {0xf0e2, 0xe99ea8}, /* U+97A8 */ + {0xf0e3, 0xe99ea6}, /* U+97A6 */ + {0xf0e4, 0xe99ea3}, /* U+97A3 */ + {0xf0e5, 0xe99eb3}, /* U+97B3 */ + {0xf0e6, 0xe99eb4}, /* U+97B4 */ + {0xf0e7, 0xe99f83}, /* U+97C3 */ + {0xf0e8, 0xe99f86}, /* U+97C6 */ + {0xf0e9, 0xe99f88}, /* U+97C8 */ + {0xf0ea, 0xe99f8b}, /* U+97CB */ + {0xf0eb, 0xe99f9c}, /* U+97DC */ + {0xf0ec, 0xe99fad}, /* U+97ED */ + {0xf0ed, 0xe9bd8f}, /* U+9F4F */ + {0xf0ee, 0xe99fb2}, /* U+97F2 */ + {0xf0ef, 0xe7ab9f}, /* U+7ADF */ + {0xf0f0, 0xe99fb6}, /* U+97F6 */ + {0xf0f1, 0xe99fb5}, /* U+97F5 */ + {0xf0f2, 0xe9a08f}, /* U+980F */ + {0xf0f3, 0xe9a08c}, /* U+980C */ + {0xf0f4, 0xe9a0b8}, /* U+9838 */ + {0xf0f5, 0xe9a0a4}, /* U+9824 */ + {0xf0f6, 0xe9a0a1}, /* U+9821 */ + {0xf0f7, 0xe9a0b7}, /* U+9837 */ + {0xf0f8, 0xe9a0bd}, /* U+983D */ + {0xf0f9, 0xe9a186}, /* U+9846 */ + {0xf0fa, 0xe9a18f}, /* U+984F */ + {0xf0fb, 0xe9a18b}, /* U+984B */ + {0xf0fc, 0xe9a1ab}, /* U+986B */ + {0xf0fd, 0xe9a1af}, /* U+986F */ + {0xf0fe, 0xe9a1b0}, /* U+9870 */ + {0xf1a1, 0xe9a1b1}, /* U+9871 */ + {0xf1a2, 0xe9a1b4}, /* U+9874 */ + {0xf1a3, 0xe9a1b3}, /* U+9873 */ + {0xf1a4, 0xe9a2aa}, /* U+98AA */ + {0xf1a5, 0xe9a2af}, /* U+98AF */ + {0xf1a6, 0xe9a2b1}, /* U+98B1 */ + {0xf1a7, 0xe9a2b6}, /* U+98B6 */ + {0xf1a8, 0xe9a384}, /* U+98C4 */ + {0xf1a9, 0xe9a383}, /* U+98C3 */ + {0xf1aa, 0xe9a386}, /* U+98C6 */ + {0xf1ab, 0xe9a3a9}, /* U+98E9 */ + {0xf1ac, 0xe9a3ab}, /* U+98EB */ + {0xf1ad, 0xe9a483}, /* U+9903 */ + {0xf1ae, 0xe9a489}, /* U+9909 */ + {0xf1af, 0xe9a492}, /* U+9912 */ + {0xf1b0, 0xe9a494}, /* U+9914 */ + {0xf1b1, 0xe9a498}, /* U+9918 */ + {0xf1b2, 0xe9a4a1}, /* U+9921 */ + {0xf1b3, 0xe9a49d}, /* U+991D */ + {0xf1b4, 0xe9a49e}, /* U+991E */ + {0xf1b5, 0xe9a4a4}, /* U+9924 */ + {0xf1b6, 0xe9a4a0}, /* U+9920 */ + {0xf1b7, 0xe9a4ac}, /* U+992C */ + {0xf1b8, 0xe9a4ae}, /* U+992E */ + {0xf1b9, 0xe9a4bd}, /* U+993D */ + {0xf1ba, 0xe9a4be}, /* U+993E */ + {0xf1bb, 0xe9a582}, /* U+9942 */ + {0xf1bc, 0xe9a589}, /* U+9949 */ + {0xf1bd, 0xe9a585}, /* U+9945 */ + {0xf1be, 0xe9a590}, /* U+9950 */ + {0xf1bf, 0xe9a58b}, /* U+994B */ + {0xf1c0, 0xe9a591}, /* U+9951 */ + {0xf1c1, 0xe9a592}, /* U+9952 */ + {0xf1c2, 0xe9a58c}, /* U+994C */ + {0xf1c3, 0xe9a595}, /* U+9955 */ + {0xf1c4, 0xe9a697}, /* U+9997 */ + {0xf1c5, 0xe9a698}, /* U+9998 */ + {0xf1c6, 0xe9a6a5}, /* U+99A5 */ + {0xf1c7, 0xe9a6ad}, /* U+99AD */ + {0xf1c8, 0xe9a6ae}, /* U+99AE */ + {0xf1c9, 0xe9a6bc}, /* U+99BC */ + {0xf1ca, 0xe9a79f}, /* U+99DF */ + {0xf1cb, 0xe9a79b}, /* U+99DB */ + {0xf1cc, 0xe9a79d}, /* U+99DD */ + {0xf1cd, 0xe9a798}, /* U+99D8 */ + {0xf1ce, 0xe9a791}, /* U+99D1 */ + {0xf1cf, 0xe9a7ad}, /* U+99ED */ + {0xf1d0, 0xe9a7ae}, /* U+99EE */ + {0xf1d1, 0xe9a7b1}, /* U+99F1 */ + {0xf1d2, 0xe9a7b2}, /* U+99F2 */ + {0xf1d3, 0xe9a7bb}, /* U+99FB */ + {0xf1d4, 0xe9a7b8}, /* U+99F8 */ + {0xf1d5, 0xe9a881}, /* U+9A01 */ + {0xf1d6, 0xe9a88f}, /* U+9A0F */ + {0xf1d7, 0xe9a885}, /* U+9A05 */ + {0xf1d8, 0xe9a7a2}, /* U+99E2 */ + {0xf1d9, 0xe9a899}, /* U+9A19 */ + {0xf1da, 0xe9a8ab}, /* U+9A2B */ + {0xf1db, 0xe9a8b7}, /* U+9A37 */ + {0xf1dc, 0xe9a985}, /* U+9A45 */ + {0xf1dd, 0xe9a982}, /* U+9A42 */ + {0xf1de, 0xe9a980}, /* U+9A40 */ + {0xf1df, 0xe9a983}, /* U+9A43 */ + {0xf1e0, 0xe9a8be}, /* U+9A3E */ + {0xf1e1, 0xe9a995}, /* U+9A55 */ + {0xf1e2, 0xe9a98d}, /* U+9A4D */ + {0xf1e3, 0xe9a99b}, /* U+9A5B */ + {0xf1e4, 0xe9a997}, /* U+9A57 */ + {0xf1e5, 0xe9a99f}, /* U+9A5F */ + {0xf1e6, 0xe9a9a2}, /* U+9A62 */ + {0xf1e7, 0xe9a9a5}, /* U+9A65 */ + {0xf1e8, 0xe9a9a4}, /* U+9A64 */ + {0xf1e9, 0xe9a9a9}, /* U+9A69 */ + {0xf1ea, 0xe9a9ab}, /* U+9A6B */ + {0xf1eb, 0xe9a9aa}, /* U+9A6A */ + {0xf1ec, 0xe9aaad}, /* U+9AAD */ + {0xf1ed, 0xe9aab0}, /* U+9AB0 */ + {0xf1ee, 0xe9aabc}, /* U+9ABC */ + {0xf1ef, 0xe9ab80}, /* U+9AC0 */ + {0xf1f0, 0xe9ab8f}, /* U+9ACF */ + {0xf1f1, 0xe9ab91}, /* U+9AD1 */ + {0xf1f2, 0xe9ab93}, /* U+9AD3 */ + {0xf1f3, 0xe9ab94}, /* U+9AD4 */ + {0xf1f4, 0xe9ab9e}, /* U+9ADE */ + {0xf1f5, 0xe9ab9f}, /* U+9ADF */ + {0xf1f6, 0xe9aba2}, /* U+9AE2 */ + {0xf1f7, 0xe9aba3}, /* U+9AE3 */ + {0xf1f8, 0xe9aba6}, /* U+9AE6 */ + {0xf1f9, 0xe9abaf}, /* U+9AEF */ + {0xf1fa, 0xe9abab}, /* U+9AEB */ + {0xf1fb, 0xe9abae}, /* U+9AEE */ + {0xf1fc, 0xe9abb4}, /* U+9AF4 */ + {0xf1fd, 0xe9abb1}, /* U+9AF1 */ + {0xf1fe, 0xe9abb7}, /* U+9AF7 */ + {0xf2a1, 0xe9abbb}, /* U+9AFB */ + {0xf2a2, 0xe9ac86}, /* U+9B06 */ + {0xf2a3, 0xe9ac98}, /* U+9B18 */ + {0xf2a4, 0xe9ac9a}, /* U+9B1A */ + {0xf2a5, 0xe9ac9f}, /* U+9B1F */ + {0xf2a6, 0xe9aca2}, /* U+9B22 */ + {0xf2a7, 0xe9aca3}, /* U+9B23 */ + {0xf2a8, 0xe9aca5}, /* U+9B25 */ + {0xf2a9, 0xe9aca7}, /* U+9B27 */ + {0xf2aa, 0xe9aca8}, /* U+9B28 */ + {0xf2ab, 0xe9aca9}, /* U+9B29 */ + {0xf2ac, 0xe9acaa}, /* U+9B2A */ + {0xf2ad, 0xe9acae}, /* U+9B2E */ + {0xf2ae, 0xe9acaf}, /* U+9B2F */ + {0xf2af, 0xe9acb2}, /* U+9B32 */ + {0xf2b0, 0xe9ad84}, /* U+9B44 */ + {0xf2b1, 0xe9ad83}, /* U+9B43 */ + {0xf2b2, 0xe9ad8f}, /* U+9B4F */ + {0xf2b3, 0xe9ad8d}, /* U+9B4D */ + {0xf2b4, 0xe9ad8e}, /* U+9B4E */ + {0xf2b5, 0xe9ad91}, /* U+9B51 */ + {0xf2b6, 0xe9ad98}, /* U+9B58 */ + {0xf2b7, 0xe9adb4}, /* U+9B74 */ + {0xf2b8, 0xe9ae93}, /* U+9B93 */ + {0xf2b9, 0xe9ae83}, /* U+9B83 */ + {0xf2ba, 0xe9ae91}, /* U+9B91 */ + {0xf2bb, 0xe9ae96}, /* U+9B96 */ + {0xf2bc, 0xe9ae97}, /* U+9B97 */ + {0xf2bd, 0xe9ae9f}, /* U+9B9F */ + {0xf2be, 0xe9aea0}, /* U+9BA0 */ + {0xf2bf, 0xe9aea8}, /* U+9BA8 */ + {0xf2c0, 0xe9aeb4}, /* U+9BB4 */ + {0xf2c1, 0xe9af80}, /* U+9BC0 */ + {0xf2c2, 0xe9af8a}, /* U+9BCA */ + {0xf2c3, 0xe9aeb9}, /* U+9BB9 */ + {0xf2c4, 0xe9af86}, /* U+9BC6 */ + {0xf2c5, 0xe9af8f}, /* U+9BCF */ + {0xf2c6, 0xe9af91}, /* U+9BD1 */ + {0xf2c7, 0xe9af92}, /* U+9BD2 */ + {0xf2c8, 0xe9afa3}, /* U+9BE3 */ + {0xf2c9, 0xe9afa2}, /* U+9BE2 */ + {0xf2ca, 0xe9afa4}, /* U+9BE4 */ + {0xf2cb, 0xe9af94}, /* U+9BD4 */ + {0xf2cc, 0xe9afa1}, /* U+9BE1 */ + {0xf2cd, 0xe9b0ba}, /* U+9C3A */ + {0xf2ce, 0xe9afb2}, /* U+9BF2 */ + {0xf2cf, 0xe9afb1}, /* U+9BF1 */ + {0xf2d0, 0xe9afb0}, /* U+9BF0 */ + {0xf2d1, 0xe9b095}, /* U+9C15 */ + {0xf2d2, 0xe9b094}, /* U+9C14 */ + {0xf2d3, 0xe9b089}, /* U+9C09 */ + {0xf2d4, 0xe9b093}, /* U+9C13 */ + {0xf2d5, 0xe9b08c}, /* U+9C0C */ + {0xf2d6, 0xe9b086}, /* U+9C06 */ + {0xf2d7, 0xe9b088}, /* U+9C08 */ + {0xf2d8, 0xe9b092}, /* U+9C12 */ + {0xf2d9, 0xe9b08a}, /* U+9C0A */ + {0xf2da, 0xe9b084}, /* U+9C04 */ + {0xf2db, 0xe9b0ae}, /* U+9C2E */ + {0xf2dc, 0xe9b09b}, /* U+9C1B */ + {0xf2dd, 0xe9b0a5}, /* U+9C25 */ + {0xf2de, 0xe9b0a4}, /* U+9C24 */ + {0xf2df, 0xe9b0a1}, /* U+9C21 */ + {0xf2e0, 0xe9b0b0}, /* U+9C30 */ + {0xf2e1, 0xe9b187}, /* U+9C47 */ + {0xf2e2, 0xe9b0b2}, /* U+9C32 */ + {0xf2e3, 0xe9b186}, /* U+9C46 */ + {0xf2e4, 0xe9b0be}, /* U+9C3E */ + {0xf2e5, 0xe9b19a}, /* U+9C5A */ + {0xf2e6, 0xe9b1a0}, /* U+9C60 */ + {0xf2e7, 0xe9b1a7}, /* U+9C67 */ + {0xf2e8, 0xe9b1b6}, /* U+9C76 */ + {0xf2e9, 0xe9b1b8}, /* U+9C78 */ + {0xf2ea, 0xe9b3a7}, /* U+9CE7 */ + {0xf2eb, 0xe9b3ac}, /* U+9CEC */ + {0xf2ec, 0xe9b3b0}, /* U+9CF0 */ + {0xf2ed, 0xe9b489}, /* U+9D09 */ + {0xf2ee, 0xe9b488}, /* U+9D08 */ + {0xf2ef, 0xe9b3ab}, /* U+9CEB */ + {0xf2f0, 0xe9b483}, /* U+9D03 */ + {0xf2f1, 0xe9b486}, /* U+9D06 */ + {0xf2f2, 0xe9b4aa}, /* U+9D2A */ + {0xf2f3, 0xe9b4a6}, /* U+9D26 */ + {0xf2f4, 0xe9b6af}, /* U+9DAF */ + {0xf2f5, 0xe9b4a3}, /* U+9D23 */ + {0xf2f6, 0xe9b49f}, /* U+9D1F */ + {0xf2f7, 0xe9b584}, /* U+9D44 */ + {0xf2f8, 0xe9b495}, /* U+9D15 */ + {0xf2f9, 0xe9b492}, /* U+9D12 */ + {0xf2fa, 0xe9b581}, /* U+9D41 */ + {0xf2fb, 0xe9b4bf}, /* U+9D3F */ + {0xf2fc, 0xe9b4be}, /* U+9D3E */ + {0xf2fd, 0xe9b586}, /* U+9D46 */ + {0xf2fe, 0xe9b588}, /* U+9D48 */ + {0xf3a1, 0xe9b59d}, /* U+9D5D */ + {0xf3a2, 0xe9b59e}, /* U+9D5E */ + {0xf3a3, 0xe9b5a4}, /* U+9D64 */ + {0xf3a4, 0xe9b591}, /* U+9D51 */ + {0xf3a5, 0xe9b590}, /* U+9D50 */ + {0xf3a6, 0xe9b599}, /* U+9D59 */ + {0xf3a7, 0xe9b5b2}, /* U+9D72 */ + {0xf3a8, 0xe9b689}, /* U+9D89 */ + {0xf3a9, 0xe9b687}, /* U+9D87 */ + {0xf3aa, 0xe9b6ab}, /* U+9DAB */ + {0xf3ab, 0xe9b5af}, /* U+9D6F */ + {0xf3ac, 0xe9b5ba}, /* U+9D7A */ + {0xf3ad, 0xe9b69a}, /* U+9D9A */ + {0xf3ae, 0xe9b6a4}, /* U+9DA4 */ + {0xf3af, 0xe9b6a9}, /* U+9DA9 */ + {0xf3b0, 0xe9b6b2}, /* U+9DB2 */ + {0xf3b1, 0xe9b784}, /* U+9DC4 */ + {0xf3b2, 0xe9b781}, /* U+9DC1 */ + {0xf3b3, 0xe9b6bb}, /* U+9DBB */ + {0xf3b4, 0xe9b6b8}, /* U+9DB8 */ + {0xf3b5, 0xe9b6ba}, /* U+9DBA */ + {0xf3b6, 0xe9b786}, /* U+9DC6 */ + {0xf3b7, 0xe9b78f}, /* U+9DCF */ + {0xf3b8, 0xe9b782}, /* U+9DC2 */ + {0xf3b9, 0xe9b799}, /* U+9DD9 */ + {0xf3ba, 0xe9b793}, /* U+9DD3 */ + {0xf3bb, 0xe9b7b8}, /* U+9DF8 */ + {0xf3bc, 0xe9b7a6}, /* U+9DE6 */ + {0xf3bd, 0xe9b7ad}, /* U+9DED */ + {0xf3be, 0xe9b7af}, /* U+9DEF */ + {0xf3bf, 0xe9b7bd}, /* U+9DFD */ + {0xf3c0, 0xe9b89a}, /* U+9E1A */ + {0xf3c1, 0xe9b89b}, /* U+9E1B */ + {0xf3c2, 0xe9b89e}, /* U+9E1E */ + {0xf3c3, 0xe9b9b5}, /* U+9E75 */ + {0xf3c4, 0xe9b9b9}, /* U+9E79 */ + {0xf3c5, 0xe9b9bd}, /* U+9E7D */ + {0xf3c6, 0xe9ba81}, /* U+9E81 */ + {0xf3c7, 0xe9ba88}, /* U+9E88 */ + {0xf3c8, 0xe9ba8b}, /* U+9E8B */ + {0xf3c9, 0xe9ba8c}, /* U+9E8C */ + {0xf3ca, 0xe9ba92}, /* U+9E92 */ + {0xf3cb, 0xe9ba95}, /* U+9E95 */ + {0xf3cc, 0xe9ba91}, /* U+9E91 */ + {0xf3cd, 0xe9ba9d}, /* U+9E9D */ + {0xf3ce, 0xe9baa5}, /* U+9EA5 */ + {0xf3cf, 0xe9baa9}, /* U+9EA9 */ + {0xf3d0, 0xe9bab8}, /* U+9EB8 */ + {0xf3d1, 0xe9baaa}, /* U+9EAA */ + {0xf3d2, 0xe9baad}, /* U+9EAD */ + {0xf3d3, 0xe99da1}, /* U+9761 */ + {0xf3d4, 0xe9bb8c}, /* U+9ECC */ + {0xf3d5, 0xe9bb8e}, /* U+9ECE */ + {0xf3d6, 0xe9bb8f}, /* U+9ECF */ + {0xf3d7, 0xe9bb90}, /* U+9ED0 */ + {0xf3d8, 0xe9bb94}, /* U+9ED4 */ + {0xf3d9, 0xe9bb9c}, /* U+9EDC */ + {0xf3da, 0xe9bb9e}, /* U+9EDE */ + {0xf3db, 0xe9bb9d}, /* U+9EDD */ + {0xf3dc, 0xe9bba0}, /* U+9EE0 */ + {0xf3dd, 0xe9bba5}, /* U+9EE5 */ + {0xf3de, 0xe9bba8}, /* U+9EE8 */ + {0xf3df, 0xe9bbaf}, /* U+9EEF */ + {0xf3e0, 0xe9bbb4}, /* U+9EF4 */ + {0xf3e1, 0xe9bbb6}, /* U+9EF6 */ + {0xf3e2, 0xe9bbb7}, /* U+9EF7 */ + {0xf3e3, 0xe9bbb9}, /* U+9EF9 */ + {0xf3e4, 0xe9bbbb}, /* U+9EFB */ + {0xf3e5, 0xe9bbbc}, /* U+9EFC */ + {0xf3e6, 0xe9bbbd}, /* U+9EFD */ + {0xf3e7, 0xe9bc87}, /* U+9F07 */ + {0xf3e8, 0xe9bc88}, /* U+9F08 */ + {0xf3e9, 0xe79ab7}, /* U+76B7 */ + {0xf3ea, 0xe9bc95}, /* U+9F15 */ + {0xf3eb, 0xe9bca1}, /* U+9F21 */ + {0xf3ec, 0xe9bcac}, /* U+9F2C */ + {0xf3ed, 0xe9bcbe}, /* U+9F3E */ + {0xf3ee, 0xe9bd8a}, /* U+9F4A */ + {0xf3ef, 0xe9bd92}, /* U+9F52 */ + {0xf3f0, 0xe9bd94}, /* U+9F54 */ + {0xf3f1, 0xe9bda3}, /* U+9F63 */ + {0xf3f2, 0xe9bd9f}, /* U+9F5F */ + {0xf3f3, 0xe9bda0}, /* U+9F60 */ + {0xf3f4, 0xe9bda1}, /* U+9F61 */ + {0xf3f5, 0xe9bda6}, /* U+9F66 */ + {0xf3f6, 0xe9bda7}, /* U+9F67 */ + {0xf3f7, 0xe9bdac}, /* U+9F6C */ + {0xf3f8, 0xe9bdaa}, /* U+9F6A */ + {0xf3f9, 0xe9bdb7}, /* U+9F77 */ + {0xf3fa, 0xe9bdb2}, /* U+9F72 */ + {0xf3fb, 0xe9bdb6}, /* U+9F76 */ + {0xf3fc, 0xe9be95}, /* U+9F95 */ + {0xf3fd, 0xe9be9c}, /* U+9F9C */ + {0xf3fe, 0xe9bea0}, /* U+9FA0 */ + {0xf4a1, 0xe5a0af}, /* U+582F [1983] */ + {0xf4a2, 0xe6a787}, /* U+69C7 [1983] */ + {0xf4a3, 0xe98199}, /* U+9059 [1983] */ + {0xf4a4, 0xe791a4}, /* U+7464 [1983] */ + {0xf4a5, 0xe5879c}, /* U+51DC [1990] */ + {0xf4a6, 0xe78699}, /* U+7199 [1990] */ + {0xf4a7, 0xe59993}, /* U+5653 [2004] */ + {0xf4a8, 0xe5b7a2}, /* U+5DE2 [2000] */ + {0xf4a9, 0xe5b894}, /* U+5E14 [2000] */ + {0xf4aa, 0xe5b898}, /* U+5E18 [2000] */ + {0xf4ab, 0xe5b998}, /* U+5E58 [2000] */ + {0xf4ac, 0xe5b99e}, /* U+5E5E [2000] */ + {0xf4ad, 0xe5babe}, /* U+5EBE [2000] */ + {0xf4ae, 0xefa4a8}, /* U+F928 CJK COMPATIBILITY IDEOGRAPH-F928 [2000] */ + {0xf4af, 0xe5bb8b}, /* U+5ECB [2000] */ + {0xf4b0, 0xe5bbb9}, /* U+5EF9 [2000] */ + {0xf4b1, 0xe5bc80}, /* U+5F00 [2000] */ + {0xf4b2, 0xe5bc82}, /* U+5F02 [2000] */ + {0xf4b3, 0xe5bc87}, /* U+5F07 [2000] */ + {0xf4b4, 0xe5bc9d}, /* U+5F1D [2000] */ + {0xf4b5, 0xe5bca3}, /* U+5F23 [2000] */ + {0xf4b6, 0xe5bcb4}, /* U+5F34 [2000] */ + {0xf4b7, 0xe5bcb6}, /* U+5F36 [2000] */ + {0xf4b8, 0xe5bcbd}, /* U+5F3D [2000] */ + {0xf4b9, 0xe5bd80}, /* U+5F40 [2000] */ + {0xf4ba, 0xe5bd85}, /* U+5F45 [2000] */ + {0xf4bb, 0xe5bd94}, /* U+5F54 [2000] */ + {0xf4bc, 0xe5bd98}, /* U+5F58 [2000] */ + {0xf4bd, 0xe5bda4}, /* U+5F64 [2000] */ + {0xf4be, 0xe5bda7}, /* U+5F67 [2000] */ + {0xf4bf, 0xe5bdbd}, /* U+5F7D [2000] */ + {0xf4c0, 0xe5be89}, /* U+5F89 [2000] */ + {0xf4c1, 0xe5be9c}, /* U+5F9C [2000] */ + {0xf4c2, 0xe5bea7}, /* U+5FA7 [2000] */ + {0xf4c3, 0xe5beaf}, /* U+5FAF [2000] */ + {0xf4c4, 0xe5beb5}, /* U+5FB5 [2000] */ + {0xf4c5, 0xe5beb7}, /* U+5FB7 [2000] */ + {0xf4c6, 0xe5bf89}, /* U+5FC9 [2000] */ + {0xf4c7, 0xe5bf9e}, /* U+5FDE [2000] */ + {0xf4c8, 0xe5bfa1}, /* U+5FE1 [2000] */ + {0xf4c9, 0xe5bfa9}, /* U+5FE9 [2000] */ + {0xf4ca, 0xe6808d}, /* U+600D [2000] */ + {0xf4cb, 0xe68094}, /* U+6014 [2000] */ + {0xf4cc, 0xe68098}, /* U+6018 [2000] */ + {0xf4cd, 0xe680b3}, /* U+6033 [2000] */ + {0xf4ce, 0xe680b5}, /* U+6035 [2000] */ + {0xf4cf, 0xe68187}, /* U+6047 [2000] */ + {0xf4d0, 0xefa8bd}, /* U+FA3D CJK COMPATIBILITY IDEOGRAPH-FA3D [2000] [Unicode3.2] */ + {0xf4d1, 0xe6829d}, /* U+609D [2000] */ + {0xf4d2, 0xe6829e}, /* U+609E [2000] */ + {0xf4d3, 0xe6838b}, /* U+60CB [2000] */ + {0xf4d4, 0xe68394}, /* U+60D4 [2000] */ + {0xf4d5, 0xe68395}, /* U+60D5 [2000] */ + {0xf4d6, 0xe6839d}, /* U+60DD [2000] */ + {0xf4d7, 0xe683b8}, /* U+60F8 [2000] */ + {0xf4d8, 0xe6849c}, /* U+611C [2000] */ + {0xf4d9, 0xe684ab}, /* U+612B [2000] */ + {0xf4da, 0xe684b0}, /* U+6130 [2000] */ + {0xf4db, 0xe684b7}, /* U+6137 [2000] */ + {0xf4dc, 0xefa8be}, /* U+FA3E CJK COMPATIBILITY IDEOGRAPH-FA3E [2000] [Unicode3.2] */ + {0xf4dd, 0xe6868d}, /* U+618D [2000] */ + {0xf4de, 0xefa8bf}, /* U+FA3F CJK COMPATIBILITY IDEOGRAPH-FA3F [2000] [Unicode3.2] */ + {0xf4df, 0xe686bc}, /* U+61BC [2000] */ + {0xf4e0, 0xe686b9}, /* U+61B9 [2000] */ + {0xf4e1, 0xefa980}, /* U+FA40 CJK COMPATIBILITY IDEOGRAPH-FA40 [2000] [Unicode3.2] */ + {0xf4e2, 0xe688a2}, /* U+6222 [2000] */ + {0xf4e3, 0xe688be}, /* U+623E [2000] */ + {0xf4e4, 0xe68983}, /* U+6243 [2000] */ + {0xf4e5, 0xe68996}, /* U+6256 [2000] */ + {0xf4e6, 0xe6899a}, /* U+625A [2000] */ + {0xf4e7, 0xe689af}, /* U+626F [2000] */ + {0xf4e8, 0xe68a85}, /* U+6285 [2000] */ + {0xf4e9, 0xe68b84}, /* U+62C4 [2000] */ + {0xf4ea, 0xe68b96}, /* U+62D6 [2000] */ + {0xf4eb, 0xe68bbc}, /* U+62FC [2000] */ + {0xf4ec, 0xe68c8a}, /* U+630A [2000] */ + {0xf4ed, 0xe68c98}, /* U+6318 [2000] */ + {0xf4ee, 0xe68cb9}, /* U+6339 [2000] */ + {0xf4ef, 0xe68d83}, /* U+6343 [2000] */ + {0xf4f0, 0xe68da5}, /* U+6365 [2000] */ + {0xf4f1, 0xe68dbc}, /* U+637C [2000] */ + {0xf4f2, 0xe68fa5}, /* U+63E5 [2000] */ + {0xf4f3, 0xe68fad}, /* U+63ED [2000] */ + {0xf4f4, 0xe68fb5}, /* U+63F5 [2000] */ + {0xf4f5, 0xe69090}, /* U+6410 [2000] */ + {0xf4f6, 0xe69094}, /* U+6414 [2000] */ + {0xf4f7, 0xe690a2}, /* U+6422 [2000] */ + {0xf4f8, 0xe691b9}, /* U+6479 [2000] */ + {0xf4f9, 0xe69191}, /* U+6451 [2000] */ + {0xf4fa, 0xe691a0}, /* U+6460 [2000] */ + {0xf4fb, 0xe691ad}, /* U+646D [2000] */ + {0xf4fc, 0xe6938e}, /* U+64CE [2000] */ + {0xf4fd, 0xe692be}, /* U+64BE [2000] */ + {0xf4fe, 0xe692bf}, /* U+64BF [2000] */ + {0xf5a1, 0xe69384}, /* U+64C4 [2000] */ + {0xf5a2, 0xe6938a}, /* U+64CA [2000] */ + {0xf5a3, 0xe69390}, /* U+64D0 [2000] */ + {0xf5a4, 0xe693b7}, /* U+64F7 [2000] */ + {0xf5a5, 0xe693bb}, /* U+64FB [2000] */ + {0xf5a6, 0xe694a2}, /* U+6522 [2000] */ + {0xf5a7, 0xe694a9}, /* U+6529 [2000] */ + {0xf5a8, 0xefa981}, /* U+FA41 CJK COMPATIBILITY IDEOGRAPH-FA41 [2000] [Unicode3.2] */ + {0xf5a9, 0xe695a7}, /* U+6567 [2000] */ + {0xf5aa, 0xe6969d}, /* U+659D [2000] */ + {0xf5ab, 0xefa982}, /* U+FA42 CJK COMPATIBILITY IDEOGRAPH-FA42 [2000] [Unicode3.2] */ + {0xf5ac, 0xe69880}, /* U+6600 [2000] */ + {0xf5ad, 0xe69889}, /* U+6609 [2000] */ + {0xf5ae, 0xe69895}, /* U+6615 [2000] */ + {0xf5af, 0xe6989e}, /* U+661E [2000] */ + {0xf5b0, 0xe698ba}, /* U+663A [2000] */ + {0xf5b1, 0xe698a2}, /* U+6622 [2000] */ + {0xf5b2, 0xe698a4}, /* U+6624 [2000] */ + {0xf5b3, 0xe698ab}, /* U+662B [2000] */ + {0xf5b4, 0xe698b0}, /* U+6630 [2000] */ + {0xf5b5, 0xe698b1}, /* U+6631 [2000] */ + {0xf5b6, 0xe698b3}, /* U+6633 [2000] */ + {0xf5b7, 0xe69bbb}, /* U+66FB [2000] */ + {0xf5b8, 0xe69988}, /* U+6648 [2000] */ + {0xf5b9, 0xe6998c}, /* U+664C [2000] */ + {0xf5ba, 0xf0a38784}, /* U+231C4 [2000] [Unicode3.1] */ + {0xf5bb, 0xe69999}, /* U+6659 [2000] */ + {0xf5bc, 0xe6999a}, /* U+665A [2000] */ + {0xf5bd, 0xe699a1}, /* U+6661 [2000] */ + {0xf5be, 0xe699a5}, /* U+6665 [2000] */ + {0xf5bf, 0xe699b3}, /* U+6673 [2000] */ + {0xf5c0, 0xe699b7}, /* U+6677 [2000] */ + {0xf5c1, 0xe699b8}, /* U+6678 [2000] */ + {0xf5c2, 0xe69a8d}, /* U+668D [2000] */ + {0xf5c3, 0xefa983}, /* U+FA43 CJK COMPATIBILITY IDEOGRAPH-FA43 [2000] [Unicode3.2] */ + {0xf5c4, 0xe69aa0}, /* U+66A0 [2000] */ + {0xf5c5, 0xe69ab2}, /* U+66B2 [2000] */ + {0xf5c6, 0xe69abb}, /* U+66BB [2000] */ + {0xf5c7, 0xe69b86}, /* U+66C6 [2000] */ + {0xf5c8, 0xe69b88}, /* U+66C8 [2000] */ + {0xf5c9, 0xe3aca2}, /* U+3B22 [2000] */ + {0xf5ca, 0xe69b9b}, /* U+66DB [2000] */ + {0xf5cb, 0xe69ba8}, /* U+66E8 [2000] */ + {0xf5cc, 0xe69bba}, /* U+66FA [2000] */ + {0xf5cd, 0xe69c93}, /* U+6713 [2000] */ + {0xf5ce, 0xefa4a9}, /* U+F929 CJK COMPATIBILITY IDEOGRAPH-F929 [2000] */ + {0xf5cf, 0xe69cb3}, /* U+6733 [2000] */ + {0xf5d0, 0xe69da6}, /* U+6766 [2000] */ + {0xf5d1, 0xe69d87}, /* U+6747 [2000] */ + {0xf5d2, 0xe69d88}, /* U+6748 [2000] */ + {0xf5d3, 0xe69dbb}, /* U+677B [2000] */ + {0xf5d4, 0xe69e81}, /* U+6781 [2000] */ + {0xf5d5, 0xe69e93}, /* U+6793 [2000] */ + {0xf5d6, 0xe69e98}, /* U+6798 [2000] */ + {0xf5d7, 0xe69e9b}, /* U+679B [2000] */ + {0xf5d8, 0xe69ebb}, /* U+67BB [2000] */ + {0xf5d9, 0xe69fb9}, /* U+67F9 [2000] */ + {0xf5da, 0xe69f80}, /* U+67C0 [2000] */ + {0xf5db, 0xe69f97}, /* U+67D7 [2000] */ + {0xf5dc, 0xe69fbc}, /* U+67FC [2000] */ + {0xf5dd, 0xe6a081}, /* U+6801 [2000] */ + {0xf5de, 0xe6a192}, /* U+6852 [2000] */ + {0xf5df, 0xe6a09d}, /* U+681D [2000] */ + {0xf5e0, 0xe6a0ac}, /* U+682C [2000] */ + {0xf5e1, 0xe6a0b1}, /* U+6831 [2000] */ + {0xf5e2, 0xe6a19b}, /* U+685B [2000] */ + {0xf5e3, 0xe6a1b2}, /* U+6872 [2000] */ + {0xf5e4, 0xe6a1b5}, /* U+6875 [2000] */ + {0xf5e5, 0xefa984}, /* U+FA44 CJK COMPATIBILITY IDEOGRAPH-FA44 [2000] [Unicode3.2] */ + {0xf5e6, 0xe6a2a3}, /* U+68A3 [2000] */ + {0xf5e7, 0xe6a2a5}, /* U+68A5 [2000] */ + {0xf5e8, 0xe6a2b2}, /* U+68B2 [2000] */ + {0xf5e9, 0xe6a388}, /* U+68C8 [2000] */ + {0xf5ea, 0xe6a390}, /* U+68D0 [2000] */ + {0xf5eb, 0xe6a3a8}, /* U+68E8 [2000] */ + {0xf5ec, 0xe6a3ad}, /* U+68ED [2000] */ + {0xf5ed, 0xe6a3b0}, /* U+68F0 [2000] */ + {0xf5ee, 0xe6a3b1}, /* U+68F1 [2000] */ + {0xf5ef, 0xe6a3bc}, /* U+68FC [2000] */ + {0xf5f0, 0xe6a48a}, /* U+690A [2000] */ + {0xf5f1, 0xe6a589}, /* U+6949 [2000] */ + {0xf5f2, 0xf0a39784}, /* U+235C4 [2000] [Unicode3.1] */ + {0xf5f3, 0xe6a4b5}, /* U+6935 [2000] */ + {0xf5f4, 0xe6a582}, /* U+6942 [2000] */ + {0xf5f5, 0xe6a597}, /* U+6957 [2000] */ + {0xf5f6, 0xe6a5a3}, /* U+6963 [2000] */ + {0xf5f7, 0xe6a5a4}, /* U+6964 [2000] */ + {0xf5f8, 0xe6a5a8}, /* U+6968 [2000] */ + {0xf5f9, 0xe6a680}, /* U+6980 [2000] */ + {0xf5fa, 0xefa894}, /* U+FA14 CJK COMPATIBILITY IDEOGRAPH-FA14 [2000] */ + {0xf5fb, 0xe6a6a5}, /* U+69A5 [2000] */ + {0xf5fc, 0xe6a6ad}, /* U+69AD [2000] */ + {0xf5fd, 0xe6a78f}, /* U+69CF [2000] */ + {0xf5fe, 0xe3aeb6}, /* U+3BB6 [2000] */ + {0xf6a1, 0xe3af83}, /* U+3BC3 [2000] */ + {0xf6a2, 0xe6a7a2}, /* U+69E2 [2000] */ + {0xf6a3, 0xe6a7a9}, /* U+69E9 [2000] */ + {0xf6a4, 0xe6a7aa}, /* U+69EA [2000] */ + {0xf6a5, 0xe6a7b5}, /* U+69F5 [2000] */ + {0xf6a6, 0xe6a7b6}, /* U+69F6 [2000] */ + {0xf6a7, 0xe6a88f}, /* U+6A0F [2000] */ + {0xf6a8, 0xe6a895}, /* U+6A15 [2000] */ + {0xf6a9, 0xf0a39cbf}, /* U+2373F [2000] [Unicode3.1] */ + {0xf6aa, 0xe6a8bb}, /* U+6A3B [2000] */ + {0xf6ab, 0xe6a8be}, /* U+6A3E [2000] */ + {0xf6ac, 0xe6a985}, /* U+6A45 [2000] */ + {0xf6ad, 0xe6a990}, /* U+6A50 [2000] */ + {0xf6ae, 0xe6a996}, /* U+6A56 [2000] */ + {0xf6af, 0xe6a99b}, /* U+6A5B [2000] */ + {0xf6b0, 0xe6a9ab}, /* U+6A6B [2000] */ + {0xf6b1, 0xe6a9b3}, /* U+6A73 [2000] */ + {0xf6b2, 0xf0a39da3}, /* U+23763 [2000] [Unicode3.1] */ + {0xf6b3, 0xe6aa89}, /* U+6A89 [2000] */ + {0xf6b4, 0xe6aa94}, /* U+6A94 [2000] */ + {0xf6b5, 0xe6aa9d}, /* U+6A9D [2000] */ + {0xf6b6, 0xe6aa9e}, /* U+6A9E [2000] */ + {0xf6b7, 0xe6aaa5}, /* U+6AA5 [2000] */ + {0xf6b8, 0xe6aba4}, /* U+6AE4 [2000] */ + {0xf6b9, 0xe6aba7}, /* U+6AE7 [2000] */ + {0xf6ba, 0xe3b08f}, /* U+3C0F [2000] */ + {0xf6bb, 0xefa49d}, /* U+F91D CJK COMPATIBILITY IDEOGRAPH-F91D [2000] */ + {0xf6bc, 0xe6ac9b}, /* U+6B1B [2000] */ + {0xf6bd, 0xe6ac9e}, /* U+6B1E [2000] */ + {0xf6be, 0xe6acac}, /* U+6B2C [2000] */ + {0xf6bf, 0xe6acb5}, /* U+6B35 [2000] */ + {0xf6c0, 0xe6ad86}, /* U+6B46 [2000] */ + {0xf6c1, 0xe6ad96}, /* U+6B56 [2000] */ + {0xf6c2, 0xe6ada0}, /* U+6B60 [2000] */ + {0xf6c3, 0xe6ada5}, /* U+6B65 [2000] */ + {0xf6c4, 0xe6ada7}, /* U+6B67 [2000] */ + {0xf6c5, 0xe6adb7}, /* U+6B77 [2000] */ + {0xf6c6, 0xe6ae82}, /* U+6B82 [2000] */ + {0xf6c7, 0xe6aea9}, /* U+6BA9 [2000] */ + {0xf6c8, 0xe6aead}, /* U+6BAD [2000] */ + {0xf6c9, 0xefa5b0}, /* U+F970 CJK COMPATIBILITY IDEOGRAPH-F970 [2000] */ + {0xf6ca, 0xe6af8f}, /* U+6BCF [2000] */ + {0xf6cb, 0xe6af96}, /* U+6BD6 [2000] */ + {0xf6cc, 0xe6af97}, /* U+6BD7 [2000] */ + {0xf6cd, 0xe6afbf}, /* U+6BFF [2000] */ + {0xf6ce, 0xe6b085}, /* U+6C05 [2000] */ + {0xf6cf, 0xe6b090}, /* U+6C10 [2000] */ + {0xf6d0, 0xe6b0b3}, /* U+6C33 [2000] */ + {0xf6d1, 0xe6b199}, /* U+6C59 [2000] */ + {0xf6d2, 0xe6b19c}, /* U+6C5C [2000] */ + {0xf6d3, 0xe6b2aa}, /* U+6CAA [2000] */ + {0xf6d4, 0xe6b1b4}, /* U+6C74 [2000] */ + {0xf6d5, 0xe6b1b6}, /* U+6C76 [2000] */ + {0xf6d6, 0xe6b285}, /* U+6C85 [2000] */ + {0xf6d7, 0xe6b286}, /* U+6C86 [2000] */ + {0xf6d8, 0xe6b298}, /* U+6C98 [2000] */ + {0xf6d9, 0xe6b29c}, /* U+6C9C [2000] */ + {0xf6da, 0xe6b3bb}, /* U+6CFB [2000] */ + {0xf6db, 0xe6b386}, /* U+6CC6 [2000] */ + {0xf6dc, 0xe6b394}, /* U+6CD4 [2000] */ + {0xf6dd, 0xe6b3a0}, /* U+6CE0 [2000] */ + {0xf6de, 0xe6b3ab}, /* U+6CEB [2000] */ + {0xf6df, 0xe6b3ae}, /* U+6CEE [2000] */ + {0xf6e0, 0xf0a3b3be}, /* U+23CFE [2000] [Unicode3.1] */ + {0xf6e1, 0xe6b484}, /* U+6D04 [2000] */ + {0xf6e2, 0xe6b48e}, /* U+6D0E [2000] */ + {0xf6e3, 0xe6b4ae}, /* U+6D2E [2000] */ + {0xf6e4, 0xe6b4b1}, /* U+6D31 [2000] */ + {0xf6e5, 0xe6b4b9}, /* U+6D39 [2000] */ + {0xf6e6, 0xe6b4bf}, /* U+6D3F [2000] */ + {0xf6e7, 0xe6b598}, /* U+6D58 [2000] */ + {0xf6e8, 0xe6b5a5}, /* U+6D65 [2000] */ + {0xf6e9, 0xefa985}, /* U+FA45 CJK COMPATIBILITY IDEOGRAPH-FA45 [2000] [Unicode3.2] */ + {0xf6ea, 0xe6b682}, /* U+6D82 [2000] */ + {0xf6eb, 0xe6b687}, /* U+6D87 [2000] */ + {0xf6ec, 0xe6b689}, /* U+6D89 [2000] */ + {0xf6ed, 0xe6b694}, /* U+6D94 [2000] */ + {0xf6ee, 0xe6b6aa}, /* U+6DAA [2000] */ + {0xf6ef, 0xe6b6ac}, /* U+6DAC [2000] */ + {0xf6f0, 0xe6b6bf}, /* U+6DBF [2000] */ + {0xf6f1, 0xe6b784}, /* U+6DC4 [2000] */ + {0xf6f2, 0xe6b796}, /* U+6DD6 [2000] */ + {0xf6f3, 0xe6b79a}, /* U+6DDA [2000] */ + {0xf6f4, 0xe6b79b}, /* U+6DDB [2000] */ + {0xf6f5, 0xe6b79d}, /* U+6DDD [2000] */ + {0xf6f6, 0xe6b7bc}, /* U+6DFC [2000] */ + {0xf6f7, 0xefa986}, /* U+FA46 CJK COMPATIBILITY IDEOGRAPH-FA46 [2000] [Unicode3.2] */ + {0xf6f8, 0xe6b8b4}, /* U+6E34 [2000] */ + {0xf6f9, 0xe6b984}, /* U+6E44 [2000] */ + {0xf6fa, 0xe6b99c}, /* U+6E5C [2000] */ + {0xf6fb, 0xe6b99e}, /* U+6E5E [2000] */ + {0xf6fc, 0xe6baab}, /* U+6EAB [2000] */ + {0xf6fd, 0xe6bab1}, /* U+6EB1 [2000] */ + {0xf6fe, 0xe6bb81}, /* U+6EC1 [2000] */ + {0xf7a1, 0xe6bb87}, /* U+6EC7 [2000] */ + {0xf7a2, 0xe6bb8e}, /* U+6ECE [2000] */ + {0xf7a3, 0xe6bc90}, /* U+6F10 [2000] */ + {0xf7a4, 0xe6bc9a}, /* U+6F1A [2000] */ + {0xf7a5, 0xefa987}, /* U+FA47 CJK COMPATIBILITY IDEOGRAPH-FA47 [2000] [Unicode3.2] */ + {0xf7a6, 0xe6bcaa}, /* U+6F2A [2000] */ + {0xf7a7, 0xe6bcaf}, /* U+6F2F [2000] */ + {0xf7a8, 0xe6bcb3}, /* U+6F33 [2000] */ + {0xf7a9, 0xe6bd91}, /* U+6F51 [2000] */ + {0xf7aa, 0xe6bd99}, /* U+6F59 [2000] */ + {0xf7ab, 0xe6bd9e}, /* U+6F5E [2000] */ + {0xf7ac, 0xe6bda1}, /* U+6F61 [2000] */ + {0xf7ad, 0xe6bda2}, /* U+6F62 [2000] */ + {0xf7ae, 0xe6bdbe}, /* U+6F7E [2000] */ + {0xf7af, 0xe6be88}, /* U+6F88 [2000] */ + {0xf7b0, 0xe6be8c}, /* U+6F8C [2000] */ + {0xf7b1, 0xe6be8d}, /* U+6F8D [2000] */ + {0xf7b2, 0xe6be94}, /* U+6F94 [2000] */ + {0xf7b3, 0xe6bea0}, /* U+6FA0 [2000] */ + {0xf7b4, 0xe6bea7}, /* U+6FA7 [2000] */ + {0xf7b5, 0xe6beb6}, /* U+6FB6 [2000] */ + {0xf7b6, 0xe6bebc}, /* U+6FBC [2000] */ + {0xf7b7, 0xe6bf87}, /* U+6FC7 [2000] */ + {0xf7b8, 0xe6bf8a}, /* U+6FCA [2000] */ + {0xf7b9, 0xe6bfb9}, /* U+6FF9 [2000] */ + {0xf7ba, 0xe6bfb0}, /* U+6FF0 [2000] */ + {0xf7bb, 0xe6bfb5}, /* U+6FF5 [2000] */ + {0xf7bc, 0xe78085}, /* U+7005 [2000] */ + {0xf7bd, 0xe78086}, /* U+7006 [2000] */ + {0xf7be, 0xe780a8}, /* U+7028 [2000] */ + {0xf7bf, 0xe7818a}, /* U+704A [2000] */ + {0xf7c0, 0xe7819d}, /* U+705D [2000] */ + {0xf7c1, 0xe7819e}, /* U+705E [2000] */ + {0xf7c2, 0xe7818e}, /* U+704E [2000] */ + {0xf7c3, 0xe781a4}, /* U+7064 [2000] */ + {0xf7c4, 0xe781b5}, /* U+7075 [2000] */ + {0xf7c5, 0xe78285}, /* U+7085 [2000] */ + {0xf7c6, 0xe782a4}, /* U+70A4 [2000] */ + {0xf7c7, 0xe782ab}, /* U+70AB [2000] */ + {0xf7c8, 0xe782b7}, /* U+70B7 [2000] */ + {0xf7c9, 0xe78394}, /* U+70D4 [2000] */ + {0xf7ca, 0xe78398}, /* U+70D8 [2000] */ + {0xf7cb, 0xe783a4}, /* U+70E4 [2000] */ + {0xf7cc, 0xe7848f}, /* U+710F [2000] */ + {0xf7cd, 0xe784ab}, /* U+712B [2000] */ + {0xf7ce, 0xe7849e}, /* U+711E [2000] */ + {0xf7cf, 0xe784a0}, /* U+7120 [2000] */ + {0xf7d0, 0xe784ae}, /* U+712E [2000] */ + {0xf7d1, 0xe784b0}, /* U+7130 [2000] */ + {0xf7d2, 0xe78586}, /* U+7146 [2000] */ + {0xf7d3, 0xe78587}, /* U+7147 [2000] */ + {0xf7d4, 0xe78591}, /* U+7151 [2000] */ + {0xf7d5, 0xefa988}, /* U+FA48 CJK COMPATIBILITY IDEOGRAPH-FA48 [2000] [Unicode3.2] */ + {0xf7d6, 0xe78592}, /* U+7152 [2000] */ + {0xf7d7, 0xe7859c}, /* U+715C [2000] */ + {0xf7d8, 0xe785a0}, /* U+7160 [2000] */ + {0xf7d9, 0xe785a8}, /* U+7168 [2000] */ + {0xf7da, 0xefa895}, /* U+FA15 CJK COMPATIBILITY IDEOGRAPH-FA15 [2000] */ + {0xf7db, 0xe78685}, /* U+7185 [2000] */ + {0xf7dc, 0xe78687}, /* U+7187 [2000] */ + {0xf7dd, 0xe78692}, /* U+7192 [2000] */ + {0xf7de, 0xe78781}, /* U+71C1 [2000] */ + {0xf7df, 0xe786ba}, /* U+71BA [2000] */ + {0xf7e0, 0xe78784}, /* U+71C4 [2000] */ + {0xf7e1, 0xe787be}, /* U+71FE [2000] */ + {0xf7e2, 0xe78880}, /* U+7200 [2000] */ + {0xf7e3, 0xe78895}, /* U+7215 [2000] */ + {0xf7e4, 0xe78995}, /* U+7255 [2000] */ + {0xf7e5, 0xe78996}, /* U+7256 [2000] */ + {0xf7e6, 0xe3b8bf}, /* U+3E3F [2000] */ + {0xf7e7, 0xe78a8d}, /* U+728D [2000] */ + {0xf7e8, 0xe78a9b}, /* U+729B [2000] */ + {0xf7e9, 0xe78abe}, /* U+72BE [2000] */ + {0xf7ea, 0xe78b80}, /* U+72C0 [2000] */ + {0xf7eb, 0xe78bbb}, /* U+72FB [2000] */ + {0xf7ec, 0xf0a49fb1}, /* U+247F1 [2000] [Unicode3.1] */ + {0xf7ed, 0xe78ca7}, /* U+7327 [2000] */ + {0xf7ee, 0xe78ca8}, /* U+7328 [2000] */ + {0xf7ef, 0xefa896}, /* U+FA16 CJK COMPATIBILITY IDEOGRAPH-FA16 [2000] */ + {0xf7f0, 0xe78d90}, /* U+7350 [2000] */ + {0xf7f1, 0xe78da6}, /* U+7366 [2000] */ + {0xf7f2, 0xe78dbc}, /* U+737C [2000] */ + {0xf7f3, 0xe78e95}, /* U+7395 [2000] */ + {0xf7f4, 0xe78e9f}, /* U+739F [2000] */ + {0xf7f5, 0xe78ea0}, /* U+73A0 [2000] */ + {0xf7f6, 0xe78ea2}, /* U+73A2 [2000] */ + {0xf7f7, 0xe78ea6}, /* U+73A6 [2000] */ + {0xf7f8, 0xe78eab}, /* U+73AB [2000] */ + {0xf7f9, 0xe78f89}, /* U+73C9 [2000] */ + {0xf7fa, 0xe78f8f}, /* U+73CF [2000] */ + {0xf7fb, 0xe78f96}, /* U+73D6 [2000] */ + {0xf7fc, 0xe78f99}, /* U+73D9 [2000] */ + {0xf7fd, 0xe78fa3}, /* U+73E3 [2000] */ + {0xf7fe, 0xe78fa9}, /* U+73E9 [2000] */ + {0xf8a1, 0xe79087}, /* U+7407 [2000] */ + {0xf8a2, 0xe7908a}, /* U+740A [2000] */ + {0xf8a3, 0xe7909a}, /* U+741A [2000] */ + {0xf8a4, 0xe7909b}, /* U+741B [2000] */ + {0xf8a5, 0xefa98a}, /* U+FA4A CJK COMPATIBILITY IDEOGRAPH-FA4A [2000] [Unicode3.2] */ + {0xf8a6, 0xe790a6}, /* U+7426 [2000] */ + {0xf8a7, 0xe790a8}, /* U+7428 [2000] */ + {0xf8a8, 0xe790aa}, /* U+742A [2000] */ + {0xf8a9, 0xe790ab}, /* U+742B [2000] */ + {0xf8aa, 0xe790ac}, /* U+742C [2000] */ + {0xf8ab, 0xe790ae}, /* U+742E [2000] */ + {0xf8ac, 0xe790af}, /* U+742F [2000] */ + {0xf8ad, 0xe790b0}, /* U+7430 [2000] */ + {0xf8ae, 0xe79184}, /* U+7444 [2000] */ + {0xf8af, 0xe79186}, /* U+7446 [2000] */ + {0xf8b0, 0xe79187}, /* U+7447 [2000] */ + {0xf8b1, 0xe7918b}, /* U+744B [2000] */ + {0xf8b2, 0xe79197}, /* U+7457 [2000] */ + {0xf8b3, 0xe791a2}, /* U+7462 [2000] */ + {0xf8b4, 0xe791ab}, /* U+746B [2000] */ + {0xf8b5, 0xe791ad}, /* U+746D [2000] */ + {0xf8b6, 0xe79286}, /* U+7486 [2000] */ + {0xf8b7, 0xe79287}, /* U+7487 [2000] */ + {0xf8b8, 0xe79289}, /* U+7489 [2000] */ + {0xf8b9, 0xe79298}, /* U+7498 [2000] */ + {0xf8ba, 0xe7929c}, /* U+749C [2000] */ + {0xf8bb, 0xe7929f}, /* U+749F [2000] */ + {0xf8bc, 0xe792a3}, /* U+74A3 [2000] */ + {0xf8bd, 0xe79290}, /* U+7490 [2000] */ + {0xf8be, 0xe792a6}, /* U+74A6 [2000] */ + {0xf8bf, 0xe792a8}, /* U+74A8 [2000] */ + {0xf8c0, 0xe792a9}, /* U+74A9 [2000] */ + {0xf8c1, 0xe792b5}, /* U+74B5 [2000] */ + {0xf8c2, 0xe792bf}, /* U+74BF [2000] */ + {0xf8c3, 0xe79388}, /* U+74C8 [2000] */ + {0xf8c4, 0xe79389}, /* U+74C9 [2000] */ + {0xf8c5, 0xe7939a}, /* U+74DA [2000] */ + {0xf8c6, 0xe793bf}, /* U+74FF [2000] */ + {0xf8c7, 0xe79481}, /* U+7501 [2000] */ + {0xf8c8, 0xe79497}, /* U+7517 [2000] */ + {0xf8c9, 0xe794af}, /* U+752F [2000] */ + {0xf8ca, 0xe795af}, /* U+756F [2000] */ + {0xf8cb, 0xe795b9}, /* U+7579 [2000] */ + {0xf8cc, 0xe79692}, /* U+7592 [2000] */ + {0xf8cd, 0xe3bdb2}, /* U+3F72 [2000] */ + {0xf8ce, 0xe7978e}, /* U+75CE [2000] */ + {0xf8cf, 0xe797a4}, /* U+75E4 [2000] */ + {0xf8d0, 0xe79880}, /* U+7600 [2000] */ + {0xf8d1, 0xe79882}, /* U+7602 [2000] */ + {0xf8d2, 0xe79888}, /* U+7608 [2000] */ + {0xf8d3, 0xe79895}, /* U+7615 [2000] */ + {0xf8d4, 0xe79896}, /* U+7616 [2000] */ + {0xf8d5, 0xe79899}, /* U+7619 [2000] */ + {0xf8d6, 0xe7989e}, /* U+761E [2000] */ + {0xf8d7, 0xe798ad}, /* U+762D [2000] */ + {0xf8d8, 0xe798b5}, /* U+7635 [2000] */ + {0xf8d9, 0xe79983}, /* U+7643 [2000] */ + {0xf8da, 0xe7998b}, /* U+764B [2000] */ + {0xf8db, 0xe799a4}, /* U+7664 [2000] */ + {0xf8dc, 0xe799a5}, /* U+7665 [2000] */ + {0xf8dd, 0xe799ad}, /* U+766D [2000] */ + {0xf8de, 0xe799af}, /* U+766F [2000] */ + {0xf8df, 0xe799b1}, /* U+7671 [2000] */ + {0xf8e0, 0xe79a81}, /* U+7681 [2000] */ + {0xf8e1, 0xe79a9b}, /* U+769B [2000] */ + {0xf8e2, 0xe79a9d}, /* U+769D [2000] */ + {0xf8e3, 0xe79a9e}, /* U+769E [2000] */ + {0xf8e4, 0xe79aa6}, /* U+76A6 [2000] */ + {0xf8e5, 0xe79aaa}, /* U+76AA [2000] */ + {0xf8e6, 0xe79ab6}, /* U+76B6 [2000] */ + {0xf8e7, 0xe79b85}, /* U+76C5 [2000] */ + {0xf8e8, 0xe79b8c}, /* U+76CC [2000] */ + {0xf8e9, 0xe79b8e}, /* U+76CE [2000] */ + {0xf8ea, 0xe79b94}, /* U+76D4 [2000] */ + {0xf8eb, 0xe79ba6}, /* U+76E6 [2000] */ + {0xf8ec, 0xe79bb1}, /* U+76F1 [2000] */ + {0xf8ed, 0xe79bbc}, /* U+76FC [2000] */ + {0xf8ee, 0xe79c8a}, /* U+770A [2000] */ + {0xf8ef, 0xe79c99}, /* U+7719 [2000] */ + {0xf8f0, 0xe79cb4}, /* U+7734 [2000] */ + {0xf8f1, 0xe79cb6}, /* U+7736 [2000] */ + {0xf8f2, 0xe79d86}, /* U+7746 [2000] */ + {0xf8f3, 0xe79d8d}, /* U+774D [2000] */ + {0xf8f4, 0xe79d8e}, /* U+774E [2000] */ + {0xf8f5, 0xe79d9c}, /* U+775C [2000] */ + {0xf8f6, 0xe79d9f}, /* U+775F [2000] */ + {0xf8f7, 0xe79da2}, /* U+7762 [2000] */ + {0xf8f8, 0xe79dba}, /* U+777A [2000] */ + {0xf8f9, 0xe79e80}, /* U+7780 [2000] */ + {0xf8fa, 0xe79e94}, /* U+7794 [2000] */ + {0xf8fb, 0xe79eaa}, /* U+77AA [2000] */ + {0xf8fc, 0xe79fa0}, /* U+77E0 [2000] */ + {0xf8fd, 0xe7a0ad}, /* U+782D [2000] */ + {0xf8fe, 0xf0a5928e}, /* U+2548E [2000] [Unicode3.1] */ + {0xf9a1, 0xe7a183}, /* U+7843 [2000] */ + {0xf9a2, 0xe7a18e}, /* U+784E [2000] */ + {0xf9a3, 0xe7a18f}, /* U+784F [2000] */ + {0xf9a4, 0xe7a191}, /* U+7851 [2000] */ + {0xf9a5, 0xe7a1a8}, /* U+7868 [2000] */ + {0xf9a6, 0xe7a1ae}, /* U+786E [2000] */ + {0xf9a7, 0xefa98b}, /* U+FA4B CJK COMPATIBILITY IDEOGRAPH-FA4B [2000] [Unicode3.2] */ + {0xf9a8, 0xe7a2b0}, /* U+78B0 [2000] */ + {0xf9a9, 0xf0a5948e}, /* U+2550E [2000] [Unicode3.1] */ + {0xf9aa, 0xe7a2ad}, /* U+78AD [2000] */ + {0xf9ab, 0xe7a3a4}, /* U+78E4 [2000] */ + {0xf9ac, 0xe7a3b2}, /* U+78F2 [2000] */ + {0xf9ad, 0xe7a480}, /* U+7900 [2000] */ + {0xf9ae, 0xe7a3b7}, /* U+78F7 [2000] */ + {0xf9af, 0xe7a49c}, /* U+791C [2000] */ + {0xf9b0, 0xe7a4ae}, /* U+792E [2000] */ + {0xf9b1, 0xe7a4b1}, /* U+7931 [2000] */ + {0xf9b2, 0xe7a4b4}, /* U+7934 [2000] */ + {0xf9b3, 0xefa98c}, /* U+FA4C CJK COMPATIBILITY IDEOGRAPH-FA4C [2000] [Unicode3.2] */ + {0xf9b4, 0xefa98d}, /* U+FA4D CJK COMPATIBILITY IDEOGRAPH-FA4D [2000] [Unicode3.2] */ + {0xf9b5, 0xe7a585}, /* U+7945 [2000] */ + {0xf9b6, 0xe7a586}, /* U+7946 [2000] */ + {0xf9b7, 0xefa98e}, /* U+FA4E CJK COMPATIBILITY IDEOGRAPH-FA4E [2000] [Unicode3.2] */ + {0xf9b8, 0xefa98f}, /* U+FA4F CJK COMPATIBILITY IDEOGRAPH-FA4F [2000] [Unicode3.2] */ + {0xf9b9, 0xefa990}, /* U+FA50 CJK COMPATIBILITY IDEOGRAPH-FA50 [2000] [Unicode3.2] */ + {0xf9ba, 0xe7a59c}, /* U+795C [2000] */ + {0xf9bb, 0xefa991}, /* U+FA51 CJK COMPATIBILITY IDEOGRAPH-FA51 [2000] [Unicode3.2] */ + {0xf9bc, 0xefa899}, /* U+FA19 CJK COMPATIBILITY IDEOGRAPH-FA19 [2000] */ + {0xf9bd, 0xefa89a}, /* U+FA1A CJK COMPATIBILITY IDEOGRAPH-FA1A [2000] */ + {0xf9be, 0xe7a5b9}, /* U+7979 [2000] */ + {0xf9bf, 0xefa992}, /* U+FA52 CJK COMPATIBILITY IDEOGRAPH-FA52 [2000] [Unicode3.2] */ + {0xf9c0, 0xefa993}, /* U+FA53 CJK COMPATIBILITY IDEOGRAPH-FA53 [2000] [Unicode3.2] */ + {0xf9c1, 0xefa89b}, /* U+FA1B CJK COMPATIBILITY IDEOGRAPH-FA1B [2000] */ + {0xf9c2, 0xe7a698}, /* U+7998 [2000] */ + {0xf9c3, 0xe7a6b1}, /* U+79B1 [2000] */ + {0xf9c4, 0xe7a6b8}, /* U+79B8 [2000] */ + {0xf9c5, 0xe7a788}, /* U+79C8 [2000] */ + {0xf9c6, 0xe7a78a}, /* U+79CA [2000] */ + {0xf9c7, 0xf0a59db1}, /* U+25771 [2000] [Unicode3.1] */ + {0xf9c8, 0xe7a794}, /* U+79D4 [2000] */ + {0xf9c9, 0xe7a79e}, /* U+79DE [2000] */ + {0xf9ca, 0xe7a7ab}, /* U+79EB [2000] */ + {0xf9cb, 0xe7a7ad}, /* U+79ED [2000] */ + {0xf9cc, 0xe7a883}, /* U+7A03 [2000] */ + {0xf9cd, 0xefa994}, /* U+FA54 CJK COMPATIBILITY IDEOGRAPH-FA54 [2000] [Unicode3.2] */ + {0xf9ce, 0xe7a8b9}, /* U+7A39 [2000] */ + {0xf9cf, 0xe7a99d}, /* U+7A5D [2000] */ + {0xf9d0, 0xe7a9ad}, /* U+7A6D [2000] */ + {0xf9d1, 0xefa995}, /* U+FA55 CJK COMPATIBILITY IDEOGRAPH-FA55 [2000] [Unicode3.2] */ + {0xf9d2, 0xe7aa85}, /* U+7A85 [2000] */ + {0xf9d3, 0xe7aaa0}, /* U+7AA0 [2000] */ + {0xf9d4, 0xf0a5a784}, /* U+259C4 [2000] [Unicode3.1] */ + {0xf9d5, 0xe7aab3}, /* U+7AB3 [2000] */ + {0xf9d6, 0xe7aabb}, /* U+7ABB [2000] */ + {0xf9d7, 0xe7ab8e}, /* U+7ACE [2000] */ + {0xf9d8, 0xe7abab}, /* U+7AEB [2000] */ + {0xf9d9, 0xe7abbd}, /* U+7AFD [2000] */ + {0xf9da, 0xe7ac92}, /* U+7B12 [2000] */ + {0xf9db, 0xe7acad}, /* U+7B2D [2000] */ + {0xf9dc, 0xe7acbb}, /* U+7B3B [2000] */ + {0xf9dd, 0xe7ad87}, /* U+7B47 [2000] */ + {0xf9de, 0xe7ad8e}, /* U+7B4E [2000] */ + {0xf9df, 0xe7ada0}, /* U+7B60 [2000] */ + {0xf9e0, 0xe7adad}, /* U+7B6D [2000] */ + {0xf9e1, 0xe7adaf}, /* U+7B6F [2000] */ + {0xf9e2, 0xe7adb2}, /* U+7B72 [2000] */ + {0xf9e3, 0xe7ae9e}, /* U+7B9E [2000] */ + {0xf9e4, 0xefa996}, /* U+FA56 CJK COMPATIBILITY IDEOGRAPH-FA56 [2000] [Unicode3.2] */ + {0xf9e5, 0xe7af97}, /* U+7BD7 [2000] */ + {0xf9e6, 0xe7af99}, /* U+7BD9 [2000] */ + {0xf9e7, 0xe7b081}, /* U+7C01 [2000] */ + {0xf9e8, 0xe7b0b1}, /* U+7C31 [2000] */ + {0xf9e9, 0xe7b09e}, /* U+7C1E [2000] */ + {0xf9ea, 0xe7b0a0}, /* U+7C20 [2000] */ + {0xf9eb, 0xe7b0b3}, /* U+7C33 [2000] */ + {0xf9ec, 0xe7b0b6}, /* U+7C36 [2000] */ + {0xf9ed, 0xe489a4}, /* U+4264 [2000] */ + {0xf9ee, 0xf0a5b6a1}, /* U+25DA1 [2000] [Unicode3.1] */ + {0xf9ef, 0xe7b199}, /* U+7C59 [2000] */ + {0xf9f0, 0xe7b1ad}, /* U+7C6D [2000] */ + {0xf9f1, 0xe7b1b9}, /* U+7C79 [2000] */ + {0xf9f2, 0xe7b28f}, /* U+7C8F [2000] */ + {0xf9f3, 0xe7b294}, /* U+7C94 [2000] */ + {0xf9f4, 0xe7b2a0}, /* U+7CA0 [2000] */ + {0xf9f5, 0xe7b2bc}, /* U+7CBC [2000] */ + {0xf9f6, 0xe7b395}, /* U+7CD5 [2000] */ + {0xf9f7, 0xe7b399}, /* U+7CD9 [2000] */ + {0xf9f8, 0xe7b39d}, /* U+7CDD [2000] */ + {0xf9f9, 0xe7b487}, /* U+7D07 [2000] */ + {0xf9fa, 0xe7b488}, /* U+7D08 [2000] */ + {0xf9fb, 0xe7b493}, /* U+7D13 [2000] */ + {0xf9fc, 0xe7b49d}, /* U+7D1D [2000] */ + {0xf9fd, 0xe7b4a3}, /* U+7D23 [2000] */ + {0xf9fe, 0xe7b4b1}, /* U+7D31 [2000] */ + {0xfaa1, 0xe7b581}, /* U+7D41 [2000] */ + {0xfaa2, 0xe7b588}, /* U+7D48 [2000] */ + {0xfaa3, 0xe7b593}, /* U+7D53 [2000] */ + {0xfaa4, 0xe7b59c}, /* U+7D5C [2000] */ + {0xfaa5, 0xe7b5ba}, /* U+7D7A [2000] */ + {0xfaa6, 0xe7b683}, /* U+7D83 [2000] */ + {0xfaa7, 0xe7b68b}, /* U+7D8B [2000] */ + {0xfaa8, 0xe7b6a0}, /* U+7DA0 [2000] */ + {0xfaa9, 0xe7b6a6}, /* U+7DA6 [2000] */ + {0xfaaa, 0xe7b782}, /* U+7DC2 [2000] */ + {0xfaab, 0xe7b78c}, /* U+7DCC [2000] */ + {0xfaac, 0xe7b796}, /* U+7DD6 [2000] */ + {0xfaad, 0xe7b7a3}, /* U+7DE3 [2000] */ + {0xfaae, 0xefa997}, /* U+FA57 CJK COMPATIBILITY IDEOGRAPH-FA57 [2000] [Unicode3.2] */ + {0xfaaf, 0xe7b8a8}, /* U+7E28 [2000] */ + {0xfab0, 0xe7b888}, /* U+7E08 [2000] */ + {0xfab1, 0xe7b891}, /* U+7E11 [2000] */ + {0xfab2, 0xe7b895}, /* U+7E15 [2000] */ + {0xfab3, 0xefa999}, /* U+FA59 CJK COMPATIBILITY IDEOGRAPH-FA59 [2000] [Unicode3.2] */ + {0xfab4, 0xe7b987}, /* U+7E47 [2000] */ + {0xfab5, 0xe7b992}, /* U+7E52 [2000] */ + {0xfab6, 0xe7b9a1}, /* U+7E61 [2000] */ + {0xfab7, 0xe7ba8a}, /* U+7E8A [2000] */ + {0xfab8, 0xe7ba8d}, /* U+7E8D [2000] */ + {0xfab9, 0xe7bd87}, /* U+7F47 [2000] */ + {0xfaba, 0xefa99a}, /* U+FA5A CJK COMPATIBILITY IDEOGRAPH-FA5A [2000] [Unicode3.2] */ + {0xfabb, 0xe7be91}, /* U+7F91 [2000] */ + {0xfabc, 0xe7be97}, /* U+7F97 [2000] */ + {0xfabd, 0xe7bebf}, /* U+7FBF [2000] */ + {0xfabe, 0xe7bf8e}, /* U+7FCE [2000] */ + {0xfabf, 0xe7bf9b}, /* U+7FDB [2000] */ + {0xfac0, 0xe7bf9f}, /* U+7FDF [2000] */ + {0xfac1, 0xe7bfac}, /* U+7FEC [2000] */ + {0xfac2, 0xe7bfae}, /* U+7FEE [2000] */ + {0xfac3, 0xe7bfba}, /* U+7FFA [2000] */ + {0xfac4, 0xefa99b}, /* U+FA5B CJK COMPATIBILITY IDEOGRAPH-FA5B [2000] [Unicode3.2] */ + {0xfac5, 0xe88094}, /* U+8014 [2000] */ + {0xfac6, 0xe880a6}, /* U+8026 [2000] */ + {0xfac7, 0xe880b5}, /* U+8035 [2000] */ + {0xfac8, 0xe880b7}, /* U+8037 [2000] */ + {0xfac9, 0xe880bc}, /* U+803C [2000] */ + {0xfaca, 0xe8838a}, /* U+80CA [2000] */ + {0xfacb, 0xe88397}, /* U+80D7 [2000] */ + {0xfacc, 0xe883a0}, /* U+80E0 [2000] */ + {0xfacd, 0xe883b3}, /* U+80F3 [2000] */ + {0xface, 0xe88498}, /* U+8118 [2000] */ + {0xfacf, 0xe8858a}, /* U+814A [2000] */ + {0xfad0, 0xe885a0}, /* U+8160 [2000] */ + {0xfad1, 0xe885a7}, /* U+8167 [2000] */ + {0xfad2, 0xe885a8}, /* U+8168 [2000] */ + {0xfad3, 0xe885ad}, /* U+816D [2000] */ + {0xfad4, 0xe886bb}, /* U+81BB [2000] */ + {0xfad5, 0xe8878a}, /* U+81CA [2000] */ + {0xfad6, 0xe8878f}, /* U+81CF [2000] */ + {0xfad7, 0xe88797}, /* U+81D7 [2000] */ + {0xfad8, 0xefa99c}, /* U+FA5C CJK COMPATIBILITY IDEOGRAPH-FA5C [2000] [Unicode3.2] */ + {0xfad9, 0xe49193}, /* U+4453 [2000] */ + {0xfada, 0xe4919b}, /* U+445B [2000] */ + {0xfadb, 0xe889a0}, /* U+8260 [2000] */ + {0xfadc, 0xe889b4}, /* U+8274 [2000] */ + {0xfadd, 0xf0a6abbf}, /* U+26AFF [2000] [Unicode3.1] */ + {0xfade, 0xe88a8e}, /* U+828E [2000] */ + {0xfadf, 0xe88aa1}, /* U+82A1 [2000] */ + {0xfae0, 0xe88aa3}, /* U+82A3 [2000] */ + {0xfae1, 0xe88aa4}, /* U+82A4 [2000] */ + {0xfae2, 0xe88aa9}, /* U+82A9 [2000] */ + {0xfae3, 0xe88aae}, /* U+82AE [2000] */ + {0xfae4, 0xe88ab7}, /* U+82B7 [2000] */ + {0xfae5, 0xe88abe}, /* U+82BE [2000] */ + {0xfae6, 0xe88abf}, /* U+82BF [2000] */ + {0xfae7, 0xe88b86}, /* U+82C6 [2000] */ + {0xfae8, 0xe88b95}, /* U+82D5 [2000] */ + {0xfae9, 0xe88bbd}, /* U+82FD [2000] */ + {0xfaea, 0xe88bbe}, /* U+82FE [2000] */ + {0xfaeb, 0xe88c80}, /* U+8300 [2000] */ + {0xfaec, 0xe88c81}, /* U+8301 [2000] */ + {0xfaed, 0xe88da2}, /* U+8362 [2000] */ + {0xfaee, 0xe88ca2}, /* U+8322 [2000] */ + {0xfaef, 0xe88cad}, /* U+832D [2000] */ + {0xfaf0, 0xe88cba}, /* U+833A [2000] */ + {0xfaf1, 0xe88d83}, /* U+8343 [2000] */ + {0xfaf2, 0xe88d87}, /* U+8347 [2000] */ + {0xfaf3, 0xe88d91}, /* U+8351 [2000] */ + {0xfaf4, 0xe88d95}, /* U+8355 [2000] */ + {0xfaf5, 0xe88dbd}, /* U+837D [2000] */ + {0xfaf6, 0xe88e86}, /* U+8386 [2000] */ + {0xfaf7, 0xe88e92}, /* U+8392 [2000] */ + {0xfaf8, 0xe88e98}, /* U+8398 [2000] */ + {0xfaf9, 0xe88ea7}, /* U+83A7 [2000] */ + {0xfafa, 0xe88ea9}, /* U+83A9 [2000] */ + {0xfafb, 0xe88ebf}, /* U+83BF [2000] */ + {0xfafc, 0xe88f80}, /* U+83C0 [2000] */ + {0xfafd, 0xe88f87}, /* U+83C7 [2000] */ + {0xfafe, 0xe88f8f}, /* U+83CF [2000] */ + {0xfba1, 0xe88f91}, /* U+83D1 [2000] */ + {0xfba2, 0xe88fa1}, /* U+83E1 [2000] */ + {0xfba3, 0xe88faa}, /* U+83EA [2000] */ + {0xfba4, 0xe89081}, /* U+8401 [2000] */ + {0xfba5, 0xe89086}, /* U+8406 [2000] */ + {0xfba6, 0xe8908a}, /* U+840A [2000] */ + {0xfba7, 0xefa99f}, /* U+FA5F CJK COMPATIBILITY IDEOGRAPH-FA5F [2000] [Unicode3.2] */ + {0xfba8, 0xe89188}, /* U+8448 [2000] */ + {0xfba9, 0xe8919f}, /* U+845F [2000] */ + {0xfbaa, 0xe891b0}, /* U+8470 [2000] */ + {0xfbab, 0xe891b3}, /* U+8473 [2000] */ + {0xfbac, 0xe89285}, /* U+8485 [2000] */ + {0xfbad, 0xe8929e}, /* U+849E [2000] */ + {0xfbae, 0xe892af}, /* U+84AF [2000] */ + {0xfbaf, 0xe892b4}, /* U+84B4 [2000] */ + {0xfbb0, 0xe892ba}, /* U+84BA [2000] */ + {0xfbb1, 0xe89380}, /* U+84C0 [2000] */ + {0xfbb2, 0xe89382}, /* U+84C2 [2000] */ + {0xfbb3, 0xf0a6b980}, /* U+26E40 [2000] [Unicode3.1] */ + {0xfbb4, 0xe894b2}, /* U+8532 [2000] */ + {0xfbb5, 0xe8949e}, /* U+851E [2000] */ + {0xfbb6, 0xe894a3}, /* U+8523 [2000] */ + {0xfbb7, 0xe894af}, /* U+852F [2000] */ + {0xfbb8, 0xe89599}, /* U+8559 [2000] */ + {0xfbb9, 0xe895a4}, /* U+8564 [2000] */ + {0xfbba, 0xefa89f}, /* U+FA1F CJK COMPATIBILITY IDEOGRAPH-FA1F [2000] */ + {0xfbbb, 0xe896ad}, /* U+85AD [2000] */ + {0xfbbc, 0xe895ba}, /* U+857A [2000] */ + {0xfbbd, 0xe8968c}, /* U+858C [2000] */ + {0xfbbe, 0xe8968f}, /* U+858F [2000] */ + {0xfbbf, 0xe896a2}, /* U+85A2 [2000] */ + {0xfbc0, 0xe896b0}, /* U+85B0 [2000] */ + {0xfbc1, 0xe8978b}, /* U+85CB [2000] */ + {0xfbc2, 0xe8978e}, /* U+85CE [2000] */ + {0xfbc3, 0xe897ad}, /* U+85ED [2000] */ + {0xfbc4, 0xe89892}, /* U+8612 [2000] */ + {0xfbc5, 0xe897bf}, /* U+85FF [2000] */ + {0xfbc6, 0xe89884}, /* U+8604 [2000] */ + {0xfbc7, 0xe89885}, /* U+8605 [2000] */ + {0xfbc8, 0xe89890}, /* U+8610 [2000] */ + {0xfbc9, 0xf0a783b4}, /* U+270F4 [2000] [Unicode3.1] */ + {0xfbca, 0xe89898}, /* U+8618 [2000] */ + {0xfbcb, 0xe898a9}, /* U+8629 [2000] */ + {0xfbcc, 0xe898b8}, /* U+8638 [2000] */ + {0xfbcd, 0xe89997}, /* U+8657 [2000] */ + {0xfbce, 0xe8999b}, /* U+865B [2000] */ + {0xfbcf, 0xefa4b6}, /* U+F936 CJK COMPATIBILITY IDEOGRAPH-F936 [2000] */ + {0xfbd0, 0xe899a2}, /* U+8662 [2000] */ + {0xfbd1, 0xe4969d}, /* U+459D [2000] */ + {0xfbd2, 0xe899ac}, /* U+866C [2000] */ + {0xfbd3, 0xe899b5}, /* U+8675 [2000] */ + {0xfbd4, 0xe89a98}, /* U+8698 [2000] */ + {0xfbd5, 0xe89ab8}, /* U+86B8 [2000] */ + {0xfbd6, 0xe89bba}, /* U+86FA [2000] */ + {0xfbd7, 0xe89bbc}, /* U+86FC [2000] */ + {0xfbd8, 0xe89bbd}, /* U+86FD [2000] */ + {0xfbd9, 0xe89c8b}, /* U+870B [2000] */ + {0xfbda, 0xe89db1}, /* U+8771 [2000] */ + {0xfbdb, 0xe89e87}, /* U+8787 [2000] */ + {0xfbdc, 0xe89e88}, /* U+8788 [2000] */ + {0xfbdd, 0xe89eac}, /* U+87AC [2000] */ + {0xfbde, 0xe89ead}, /* U+87AD [2000] */ + {0xfbdf, 0xe89eb5}, /* U+87B5 [2000] */ + {0xfbe0, 0xe497aa}, /* U+45EA [2000] */ + {0xfbe1, 0xe89f96}, /* U+87D6 [2000] */ + {0xfbe2, 0xe89fac}, /* U+87EC [2000] */ + {0xfbe3, 0xe8a086}, /* U+8806 [2000] */ + {0xfbe4, 0xe8a08a}, /* U+880A [2000] */ + {0xfbe5, 0xe8a090}, /* U+8810 [2000] */ + {0xfbe6, 0xe8a094}, /* U+8814 [2000] */ + {0xfbe7, 0xe8a09f}, /* U+881F [2000] */ + {0xfbe8, 0xe8a298}, /* U+8898 [2000] */ + {0xfbe9, 0xe8a2aa}, /* U+88AA [2000] */ + {0xfbea, 0xe8a38a}, /* U+88CA [2000] */ + {0xfbeb, 0xe8a38e}, /* U+88CE [2000] */ + {0xfbec, 0xf0a79a84}, /* U+27684 [2000] [Unicode3.1] */ + {0xfbed, 0xe8a3b5}, /* U+88F5 [2000] */ + {0xfbee, 0xe8a49c}, /* U+891C [2000] */ + {0xfbef, 0xefa9a0}, /* U+FA60 CJK COMPATIBILITY IDEOGRAPH-FA60 [2000] [Unicode3.2] */ + {0xfbf0, 0xe8a498}, /* U+8918 [2000] */ + {0xfbf1, 0xe8a499}, /* U+8919 [2000] */ + {0xfbf2, 0xe8a49a}, /* U+891A [2000] */ + {0xfbf3, 0xe8a4a7}, /* U+8927 [2000] */ + {0xfbf4, 0xe8a4b0}, /* U+8930 [2000] */ + {0xfbf5, 0xe8a4b2}, /* U+8932 [2000] */ + {0xfbf6, 0xe8a4b9}, /* U+8939 [2000] */ + {0xfbf7, 0xe8a580}, /* U+8940 [2000] */ + {0xfbf8, 0xe8a694}, /* U+8994 [2000] */ + {0xfbf9, 0xefa9a1}, /* U+FA61 CJK COMPATIBILITY IDEOGRAPH-FA61 [2000] [Unicode3.2] */ + {0xfbfa, 0xe8a794}, /* U+89D4 [2000] */ + {0xfbfb, 0xe8a7a5}, /* U+89E5 [2000] */ + {0xfbfc, 0xe8a7b6}, /* U+89F6 [2000] */ + {0xfbfd, 0xe8a892}, /* U+8A12 [2000] */ + {0xfbfe, 0xe8a895}, /* U+8A15 [2000] */ + {0xfca1, 0xe8a8a2}, /* U+8A22 [2000] */ + {0xfca2, 0xe8a8b7}, /* U+8A37 [2000] */ + {0xfca3, 0xe8a987}, /* U+8A47 [2000] */ + {0xfca4, 0xe8a98e}, /* U+8A4E [2000] */ + {0xfca5, 0xe8a99d}, /* U+8A5D [2000] */ + {0xfca6, 0xe8a9a1}, /* U+8A61 [2000] */ + {0xfca7, 0xe8a9b5}, /* U+8A75 [2000] */ + {0xfca8, 0xe8a9b9}, /* U+8A79 [2000] */ + {0xfca9, 0xe8aaa7}, /* U+8AA7 [2000] */ + {0xfcaa, 0xe8ab90}, /* U+8AD0 [2000] */ + {0xfcab, 0xe8ab9f}, /* U+8ADF [2000] */ + {0xfcac, 0xe8abb4}, /* U+8AF4 [2000] */ + {0xfcad, 0xe8abb6}, /* U+8AF6 [2000] */ + {0xfcae, 0xefa8a2}, /* U+FA22 CJK COMPATIBILITY IDEOGRAPH-FA22 [2000] */ + {0xfcaf, 0xefa9a2}, /* U+FA62 CJK COMPATIBILITY IDEOGRAPH-FA62 [2000] [Unicode3.2] */ + {0xfcb0, 0xefa9a3}, /* U+FA63 CJK COMPATIBILITY IDEOGRAPH-FA63 [2000] [Unicode3.2] */ + {0xfcb1, 0xe8ad86}, /* U+8B46 [2000] */ + {0xfcb2, 0xe8ad94}, /* U+8B54 [2000] */ + {0xfcb3, 0xe8ad99}, /* U+8B59 [2000] */ + {0xfcb4, 0xe8ada9}, /* U+8B69 [2000] */ + {0xfcb5, 0xe8ae9d}, /* U+8B9D [2000] */ + {0xfcb6, 0xe8b189}, /* U+8C49 [2000] */ + {0xfcb7, 0xe8b1a8}, /* U+8C68 [2000] */ + {0xfcb8, 0xefa9a4}, /* U+FA64 CJK COMPATIBILITY IDEOGRAPH-FA64 [2000] [Unicode3.2] */ + {0xfcb9, 0xe8b3a1}, /* U+8CE1 [2000] */ + {0xfcba, 0xe8b3b4}, /* U+8CF4 [2000] */ + {0xfcbb, 0xe8b3b8}, /* U+8CF8 [2000] */ + {0xfcbc, 0xe8b3be}, /* U+8CFE [2000] */ + {0xfcbd, 0xefa9a5}, /* U+FA65 CJK COMPATIBILITY IDEOGRAPH-FA65 [2000] [Unicode3.2] */ + {0xfcbe, 0xe8b492}, /* U+8D12 [2000] */ + {0xfcbf, 0xe8b49b}, /* U+8D1B [2000] */ + {0xfcc0, 0xe8b6af}, /* U+8DAF [2000] */ + {0xfcc1, 0xe8b78e}, /* U+8DCE [2000] */ + {0xfcc2, 0xe8b791}, /* U+8DD1 [2000] */ + {0xfcc3, 0xe8b797}, /* U+8DD7 [2000] */ + {0xfcc4, 0xe8b8a0}, /* U+8E20 [2000] */ + {0xfcc5, 0xe8b8a3}, /* U+8E23 [2000] */ + {0xfcc6, 0xe8b8bd}, /* U+8E3D [2000] */ + {0xfcc7, 0xe8b9b0}, /* U+8E70 [2000] */ + {0xfcc8, 0xe8b9bb}, /* U+8E7B [2000] */ + {0xfcc9, 0xf0a889b7}, /* U+28277 [2000] [Unicode3.1] */ + {0xfcca, 0xe8bb80}, /* U+8EC0 [2000] */ + {0xfccb, 0xe4a184}, /* U+4844 [2000] */ + {0xfccc, 0xe8bbba}, /* U+8EFA [2000] */ + {0xfccd, 0xe8bc9e}, /* U+8F1E [2000] */ + {0xfcce, 0xe8bcad}, /* U+8F2D [2000] */ + {0xfccf, 0xe8bcb6}, /* U+8F36 [2000] */ + {0xfcd0, 0xe8bd94}, /* U+8F54 [2000] */ + {0xfcd1, 0xf0a88f8d}, /* U+283CD [2000] [Unicode3.1] */ + {0xfcd2, 0xe8bea6}, /* U+8FA6 [2000] */ + {0xfcd3, 0xe8beb5}, /* U+8FB5 [2000] */ + {0xfcd4, 0xe8bfa4}, /* U+8FE4 [2000] */ + {0xfcd5, 0xe8bfa8}, /* U+8FE8 [2000] */ + {0xfcd6, 0xe8bfae}, /* U+8FEE [2000] */ + {0xfcd7, 0xe98088}, /* U+9008 [2000] */ + {0xfcd8, 0xe980ad}, /* U+902D [2000] */ + {0xfcd9, 0xefa9a7}, /* U+FA67 CJK COMPATIBILITY IDEOGRAPH-FA67 [2000] [Unicode3.2] */ + {0xfcda, 0xe98288}, /* U+9088 [2000] */ + {0xfcdb, 0xe98295}, /* U+9095 [2000] */ + {0xfcdc, 0xe98297}, /* U+9097 [2000] */ + {0xfcdd, 0xe98299}, /* U+9099 [2000] */ + {0xfcde, 0xe9829b}, /* U+909B [2000] */ + {0xfcdf, 0xe982a2}, /* U+90A2 [2000] */ + {0xfce0, 0xe982b3}, /* U+90B3 [2000] */ + {0xfce1, 0xe982be}, /* U+90BE [2000] */ + {0xfce2, 0xe98384}, /* U+90C4 [2000] */ + {0xfce3, 0xe98385}, /* U+90C5 [2000] */ + {0xfce4, 0xe98387}, /* U+90C7 [2000] */ + {0xfce5, 0xe98397}, /* U+90D7 [2000] */ + {0xfce6, 0xe9839d}, /* U+90DD [2000] */ + {0xfce7, 0xe9839e}, /* U+90DE [2000] */ + {0xfce8, 0xe983af}, /* U+90EF [2000] */ + {0xfce9, 0xe983b4}, /* U+90F4 [2000] */ + {0xfcea, 0xefa8a6}, /* U+FA26 CJK COMPATIBILITY IDEOGRAPH-FA26 [2000] */ + {0xfceb, 0xe98494}, /* U+9114 [2000] */ + {0xfcec, 0xe98495}, /* U+9115 [2000] */ + {0xfced, 0xe98496}, /* U+9116 [2000] */ + {0xfcee, 0xe984a2}, /* U+9122 [2000] */ + {0xfcef, 0xe984a3}, /* U+9123 [2000] */ + {0xfcf0, 0xe984a7}, /* U+9127 [2000] */ + {0xfcf1, 0xe984af}, /* U+912F [2000] */ + {0xfcf2, 0xe984b1}, /* U+9131 [2000] */ + {0xfcf3, 0xe984b4}, /* U+9134 [2000] */ + {0xfcf4, 0xe984bd}, /* U+913D [2000] */ + {0xfcf5, 0xe98588}, /* U+9148 [2000] */ + {0xfcf6, 0xe9859b}, /* U+915B [2000] */ + {0xfcf7, 0xe98683}, /* U+9183 [2000] */ + {0xfcf8, 0xe9869e}, /* U+919E [2000] */ + {0xfcf9, 0xe986ac}, /* U+91AC [2000] */ + {0xfcfa, 0xe986b1}, /* U+91B1 [2000] */ + {0xfcfb, 0xe986bc}, /* U+91BC [2000] */ + {0xfcfc, 0xe98797}, /* U+91D7 [2000] */ + {0xfcfd, 0xe987bb}, /* U+91FB [2000] */ + {0xfcfe, 0xe987a4}, /* U+91E4 [2000] */ + {0xfda1, 0xe987a5}, /* U+91E5 [2000] */ + {0xfda2, 0xe987ad}, /* U+91ED [2000] */ + {0xfda3, 0xe987b1}, /* U+91F1 [2000] */ + {0xfda4, 0xe98887}, /* U+9207 [2000] */ + {0xfda5, 0xe98890}, /* U+9210 [2000] */ + {0xfda6, 0xe988b8}, /* U+9238 [2000] */ + {0xfda7, 0xe988b9}, /* U+9239 [2000] */ + {0xfda8, 0xe988ba}, /* U+923A [2000] */ + {0xfda9, 0xe988bc}, /* U+923C [2000] */ + {0xfdaa, 0xe98980}, /* U+9240 [2000] */ + {0xfdab, 0xe98983}, /* U+9243 [2000] */ + {0xfdac, 0xe9898f}, /* U+924F [2000] */ + {0xfdad, 0xe989b8}, /* U+9278 [2000] */ + {0xfdae, 0xe98a88}, /* U+9288 [2000] */ + {0xfdaf, 0xe98b82}, /* U+92C2 [2000] */ + {0xfdb0, 0xe98b8b}, /* U+92CB [2000] */ + {0xfdb1, 0xe98b8c}, /* U+92CC [2000] */ + {0xfdb2, 0xe98b93}, /* U+92D3 [2000] */ + {0xfdb3, 0xe98ba0}, /* U+92E0 [2000] */ + {0xfdb4, 0xe98bbf}, /* U+92FF [2000] */ + {0xfdb5, 0xe98c84}, /* U+9304 [2000] */ + {0xfdb6, 0xe98c9f}, /* U+931F [2000] */ + {0xfdb7, 0xe98ca1}, /* U+9321 [2000] */ + {0xfdb8, 0xe98ca5}, /* U+9325 [2000] */ + {0xfdb9, 0xe98d88}, /* U+9348 [2000] */ + {0xfdba, 0xe98d89}, /* U+9349 [2000] */ + {0xfdbb, 0xe98d8a}, /* U+934A [2000] */ + {0xfdbc, 0xe98da4}, /* U+9364 [2000] */ + {0xfdbd, 0xe98da5}, /* U+9365 [2000] */ + {0xfdbe, 0xe98daa}, /* U+936A [2000] */ + {0xfdbf, 0xe98db0}, /* U+9370 [2000] */ + {0xfdc0, 0xe98e9b}, /* U+939B [2000] */ + {0xfdc1, 0xe98ea3}, /* U+93A3 [2000] */ + {0xfdc2, 0xe98eba}, /* U+93BA [2000] */ + {0xfdc3, 0xe98f86}, /* U+93C6 [2000] */ + {0xfdc4, 0xe98f9e}, /* U+93DE [2000] */ + {0xfdc5, 0xe98f9f}, /* U+93DF [2000] */ + {0xfdc6, 0xe99084}, /* U+9404 [2000] */ + {0xfdc7, 0xe98fbd}, /* U+93FD [2000] */ + {0xfdc8, 0xe990b3}, /* U+9433 [2000] */ + {0xfdc9, 0xe9918a}, /* U+944A [2000] */ + {0xfdca, 0xe991a3}, /* U+9463 [2000] */ + {0xfdcb, 0xe991ab}, /* U+946B [2000] */ + {0xfdcc, 0xe991b1}, /* U+9471 [2000] */ + {0xfdcd, 0xe991b2}, /* U+9472 [2000] */ + {0xfdce, 0xe9968e}, /* U+958E [2000] */ + {0xfdcf, 0xe9969f}, /* U+959F [2000] */ + {0xfdd0, 0xe996a6}, /* U+95A6 [2000] */ + {0xfdd1, 0xe996a9}, /* U+95A9 [2000] */ + {0xfdd2, 0xe996ac}, /* U+95AC [2000] */ + {0xfdd3, 0xe996b6}, /* U+95B6 [2000] */ + {0xfdd4, 0xe996bd}, /* U+95BD [2000] */ + {0xfdd5, 0xe9978b}, /* U+95CB [2000] */ + {0xfdd6, 0xe99790}, /* U+95D0 [2000] */ + {0xfdd7, 0xe99793}, /* U+95D3 [2000] */ + {0xfdd8, 0xe4a6b0}, /* U+49B0 [2000] */ + {0xfdd9, 0xe9979a}, /* U+95DA [2000] */ + {0xfdda, 0xe9979e}, /* U+95DE [2000] */ + {0xfddb, 0xe99998}, /* U+9658 [2000] */ + {0xfddc, 0xe99a84}, /* U+9684 [2000] */ + {0xfddd, 0xefa79c}, /* U+F9DC CJK COMPATIBILITY IDEOGRAPH-F9DC [2000] */ + {0xfdde, 0xe99a9d}, /* U+969D [2000] */ + {0xfddf, 0xe99aa4}, /* U+96A4 [2000] */ + {0xfde0, 0xe99aa5}, /* U+96A5 [2000] */ + {0xfde1, 0xe99b92}, /* U+96D2 [2000] */ + {0xfde2, 0xe99b9e}, /* U+96DE [2000] */ + {0xfde3, 0xefa9a8}, /* U+FA68 CJK COMPATIBILITY IDEOGRAPH-FA68 [2000] [Unicode3.2] */ + {0xfde4, 0xe99ba9}, /* U+96E9 [2000] */ + {0xfde5, 0xe99baf}, /* U+96EF [2000] */ + {0xfde6, 0xe99cb3}, /* U+9733 [2000] */ + {0xfde7, 0xe99cbb}, /* U+973B [2000] */ + {0xfde8, 0xe99d8d}, /* U+974D [2000] */ + {0xfde9, 0xe99d8e}, /* U+974E [2000] */ + {0xfdea, 0xe99d8f}, /* U+974F [2000] */ + {0xfdeb, 0xe99d9a}, /* U+975A [2000] */ + {0xfdec, 0xe99dae}, /* U+976E [2000] */ + {0xfded, 0xe99db3}, /* U+9773 [2000] */ + {0xfdee, 0xe99e95}, /* U+9795 [2000] */ + {0xfdef, 0xe99eae}, /* U+97AE [2000] */ + {0xfdf0, 0xe99eba}, /* U+97BA [2000] */ + {0xfdf1, 0xe99f81}, /* U+97C1 [2000] */ + {0xfdf2, 0xe99f89}, /* U+97C9 [2000] */ + {0xfdf3, 0xe99f9e}, /* U+97DE [2000] */ + {0xfdf4, 0xe99f9b}, /* U+97DB [2000] */ + {0xfdf5, 0xe99fb4}, /* U+97F4 [2000] */ + {0xfdf6, 0xefa9a9}, /* U+FA69 CJK COMPATIBILITY IDEOGRAPH-FA69 [2000] [Unicode3.2] */ + {0xfdf7, 0xe9a08a}, /* U+980A [2000] */ + {0xfdf8, 0xe9a09e}, /* U+981E [2000] */ + {0xfdf9, 0xe9a0ab}, /* U+982B [2000] */ + {0xfdfa, 0xe9a0b0}, /* U+9830 [2000] */ + {0xfdfb, 0xefa9aa}, /* U+FA6A CJK COMPATIBILITY IDEOGRAPH-FA6A [2000] [Unicode3.2] */ + {0xfdfc, 0xe9a192}, /* U+9852 [2000] */ + {0xfdfd, 0xe9a193}, /* U+9853 [2000] */ + {0xfdfe, 0xe9a196}, /* U+9856 [2000] */ + {0xfea1, 0xe9a197}, /* U+9857 [2000] */ + {0xfea2, 0xe9a199}, /* U+9859 [2000] */ + {0xfea3, 0xe9a19a}, /* U+985A [2000] */ + {0xfea4, 0xefa790}, /* U+F9D0 CJK COMPATIBILITY IDEOGRAPH-F9D0 [2000] */ + {0xfea5, 0xe9a1a5}, /* U+9865 [2000] */ + {0xfea6, 0xe9a1ac}, /* U+986C [2000] */ + {0xfea7, 0xe9a2ba}, /* U+98BA [2000] */ + {0xfea8, 0xe9a388}, /* U+98C8 [2000] */ + {0xfea9, 0xe9a3a7}, /* U+98E7 [2000] */ + {0xfeaa, 0xe9a598}, /* U+9958 [2000] */ + {0xfeab, 0xe9a69e}, /* U+999E [2000] */ + {0xfeac, 0xe9a882}, /* U+9A02 [2000] */ + {0xfead, 0xe9a883}, /* U+9A03 [2000] */ + {0xfeae, 0xe9a8a4}, /* U+9A24 [2000] */ + {0xfeaf, 0xe9a8ad}, /* U+9A2D [2000] */ + {0xfeb0, 0xe9a8ae}, /* U+9A2E [2000] */ + {0xfeb1, 0xe9a8b8}, /* U+9A38 [2000] */ + {0xfeb2, 0xe9a98a}, /* U+9A4A [2000] */ + {0xfeb3, 0xe9a98e}, /* U+9A4E [2000] */ + {0xfeb4, 0xe9a992}, /* U+9A52 [2000] */ + {0xfeb5, 0xe9aab6}, /* U+9AB6 [2000] */ + {0xfeb6, 0xe9ab81}, /* U+9AC1 [2000] */ + {0xfeb7, 0xe9ab83}, /* U+9AC3 [2000] */ + {0xfeb8, 0xe9ab8e}, /* U+9ACE [2000] */ + {0xfeb9, 0xe9ab96}, /* U+9AD6 [2000] */ + {0xfeba, 0xe9abb9}, /* U+9AF9 [2000] */ + {0xfebb, 0xe9ac82}, /* U+9B02 [2000] */ + {0xfebc, 0xe9ac88}, /* U+9B08 [2000] */ + {0xfebd, 0xe9aca0}, /* U+9B20 [2000] */ + {0xfebe, 0xe4b097}, /* U+4C17 [2000] */ + {0xfebf, 0xe9acad}, /* U+9B2D [2000] */ + {0xfec0, 0xe9ad9e}, /* U+9B5E [2000] */ + {0xfec1, 0xe9adb9}, /* U+9B79 [2000] */ + {0xfec2, 0xe9ada6}, /* U+9B66 [2000] */ + {0xfec3, 0xe9adb2}, /* U+9B72 [2000] */ + {0xfec4, 0xe9adb5}, /* U+9B75 [2000] */ + {0xfec5, 0xe9ae84}, /* U+9B84 [2000] */ + {0xfec6, 0xe9ae8a}, /* U+9B8A [2000] */ + {0xfec7, 0xe9ae8f}, /* U+9B8F [2000] */ + {0xfec8, 0xe9ae9e}, /* U+9B9E [2000] */ + {0xfec9, 0xe9aea7}, /* U+9BA7 [2000] */ + {0xfeca, 0xe9af81}, /* U+9BC1 [2000] */ + {0xfecb, 0xe9af8e}, /* U+9BCE [2000] */ + {0xfecc, 0xe9afa5}, /* U+9BE5 [2000] */ + {0xfecd, 0xe9afb8}, /* U+9BF8 [2000] */ + {0xfece, 0xe9afbd}, /* U+9BFD [2000] */ + {0xfecf, 0xe9b080}, /* U+9C00 [2000] */ + {0xfed0, 0xe9b0a3}, /* U+9C23 [2000] */ + {0xfed1, 0xe9b181}, /* U+9C41 [2000] */ + {0xfed2, 0xe9b18f}, /* U+9C4F [2000] */ + {0xfed3, 0xe9b190}, /* U+9C50 [2000] */ + {0xfed4, 0xe9b193}, /* U+9C53 [2000] */ + {0xfed5, 0xe9b1a3}, /* U+9C63 [2000] */ + {0xfed6, 0xe9b1a5}, /* U+9C65 [2000] */ + {0xfed7, 0xe9b1b7}, /* U+9C77 [2000] */ + {0xfed8, 0xe9b49d}, /* U+9D1D [2000] */ + {0xfed9, 0xe9b49e}, /* U+9D1E [2000] */ + {0xfeda, 0xe9b583}, /* U+9D43 [2000] */ + {0xfedb, 0xe9b587}, /* U+9D47 [2000] */ + {0xfedc, 0xe9b592}, /* U+9D52 [2000] */ + {0xfedd, 0xe9b5a3}, /* U+9D63 [2000] */ + {0xfede, 0xe9b5b0}, /* U+9D70 [2000] */ + {0xfedf, 0xe9b5bc}, /* U+9D7C [2000] */ + {0xfee0, 0xe9b68a}, /* U+9D8A [2000] */ + {0xfee1, 0xe9b696}, /* U+9D96 [2000] */ + {0xfee2, 0xe9b780}, /* U+9DC0 [2000] */ + {0xfee3, 0xe9b6ac}, /* U+9DAC [2000] */ + {0xfee4, 0xe9b6bc}, /* U+9DBC [2000] */ + {0xfee5, 0xe9b797}, /* U+9DD7 [2000] */ + {0xfee6, 0xf0aa8690}, /* U+2A190 [2000] [Unicode3.1] */ + {0xfee7, 0xe9b7a7}, /* U+9DE7 [2000] */ + {0xfee8, 0xe9b887}, /* U+9E07 [2000] */ + {0xfee9, 0xe9b895}, /* U+9E15 [2000] */ + {0xfeea, 0xe9b9bc}, /* U+9E7C [2000] */ + {0xfeeb, 0xe9ba9e}, /* U+9E9E [2000] */ + {0xfeec, 0xe9baa4}, /* U+9EA4 [2000] */ + {0xfeed, 0xe9baac}, /* U+9EAC [2000] */ + {0xfeee, 0xe9baaf}, /* U+9EAF [2000] */ + {0xfeef, 0xe9bab4}, /* U+9EB4 [2000] */ + {0xfef0, 0xe9bab5}, /* U+9EB5 [2000] */ + {0xfef1, 0xe9bb83}, /* U+9EC3 [2000] */ + {0xfef2, 0xe9bb91}, /* U+9ED1 [2000] */ + {0xfef3, 0xe9bc90}, /* U+9F10 [2000] */ + {0xfef4, 0xe9bcb9}, /* U+9F39 [2000] */ + {0xfef5, 0xe9bd97}, /* U+9F57 [2000] */ + {0xfef6, 0xe9be90}, /* U+9F90 [2000] */ + {0xfef7, 0xe9be94}, /* U+9F94 [2000] */ + {0xfef8, 0xe9be97}, /* U+9F97 [2000] */ + {0xfef9, 0xe9bea2}, /* U+9FA2 [2000] */ + {0xfefa, 0xe5a7b8}, /* U+59F8 [2004] */ + {0xfefb, 0xe5b19b}, /* U+5C5B [2004] */ + {0xfefc, 0xe5b9b7}, /* U+5E77 [2004] */ + {0xfefd, 0xe798a6}, /* U+7626 [2004] */ + {0xfefe, 0xe7b9ab}, /* U+7E6B [2004] */ {0x8fa1a1, 0xf0a08289}, /* U+20089 [2000] [Unicode3.1] */ - {0x8fa1a2, 0x00e4b882}, /* U+4E02 [2000] */ - {0x8fa1a3, 0x00e4b88f}, /* U+4E0F [2000] */ - {0x8fa1a4, 0x00e4b892}, /* U+4E12 [2000] */ - {0x8fa1a5, 0x00e4b8a9}, /* U+4E29 [2000] */ - {0x8fa1a6, 0x00e4b8ab}, /* U+4E2B [2000] */ - {0x8fa1a7, 0x00e4b8ae}, /* U+4E2E [2000] */ - {0x8fa1a8, 0x00e4b980}, /* U+4E40 [2000] */ - {0x8fa1a9, 0x00e4b987}, /* U+4E47 [2000] */ - {0x8fa1aa, 0x00e4b988}, /* U+4E48 [2000] */ + {0x8fa1a2, 0xe4b882}, /* U+4E02 [2000] */ + {0x8fa1a3, 0xe4b88f}, /* U+4E0F [2000] */ + {0x8fa1a4, 0xe4b892}, /* U+4E12 [2000] */ + {0x8fa1a5, 0xe4b8a9}, /* U+4E29 [2000] */ + {0x8fa1a6, 0xe4b8ab}, /* U+4E2B [2000] */ + {0x8fa1a7, 0xe4b8ae}, /* U+4E2E [2000] */ + {0x8fa1a8, 0xe4b980}, /* U+4E40 [2000] */ + {0x8fa1a9, 0xe4b987}, /* U+4E47 [2000] */ + {0x8fa1aa, 0xe4b988}, /* U+4E48 [2000] */ {0x8fa1ab, 0xf0a082a2}, /* U+200A2 [2000] [Unicode3.1] */ - {0x8fa1ac, 0x00e4b991}, /* U+4E51 [2000] */ - {0x8fa1ad, 0x00e39086}, /* U+3406 [2000] */ + {0x8fa1ac, 0xe4b991}, /* U+4E51 [2000] */ + {0x8fa1ad, 0xe39086}, /* U+3406 [2000] */ {0x8fa1ae, 0xf0a082a4}, /* U+200A4 [2000] [Unicode3.1] */ - {0x8fa1af, 0x00e4b99a}, /* U+4E5A [2000] */ - {0x8fa1b0, 0x00e4b9a9}, /* U+4E69 [2000] */ - {0x8fa1b1, 0x00e4ba9d}, /* U+4E9D [2000] */ - {0x8fa1b2, 0x00e390ac}, /* U+342C [2000] */ - {0x8fa1b3, 0x00e390ae}, /* U+342E [2000] */ - {0x8fa1b4, 0x00e4bab9}, /* U+4EB9 [2000] */ - {0x8fa1b5, 0x00e4babb}, /* U+4EBB [2000] */ + {0x8fa1af, 0xe4b99a}, /* U+4E5A [2000] */ + {0x8fa1b0, 0xe4b9a9}, /* U+4E69 [2000] */ + {0x8fa1b1, 0xe4ba9d}, /* U+4E9D [2000] */ + {0x8fa1b2, 0xe390ac}, /* U+342C [2000] */ + {0x8fa1b3, 0xe390ae}, /* U+342E [2000] */ + {0x8fa1b4, 0xe4bab9}, /* U+4EB9 [2000] */ + {0x8fa1b5, 0xe4babb}, /* U+4EBB [2000] */ {0x8fa1b6, 0xf0a086a2}, /* U+201A2 [2000] [Unicode3.1] */ - {0x8fa1b7, 0x00e4babc}, /* U+4EBC [2000] */ - {0x8fa1b8, 0x00e4bb83}, /* U+4EC3 [2000] */ - {0x8fa1b9, 0x00e4bb88}, /* U+4EC8 [2000] */ - {0x8fa1ba, 0x00e4bb90}, /* U+4ED0 [2000] */ - {0x8fa1bb, 0x00e4bbab}, /* U+4EEB [2000] */ - {0x8fa1bc, 0x00e4bb9a}, /* U+4EDA [2000] */ - {0x8fa1bd, 0x00e4bbb1}, /* U+4EF1 [2000] */ - {0x8fa1be, 0x00e4bbb5}, /* U+4EF5 [2000] */ - {0x8fa1bf, 0x00e4bc80}, /* U+4F00 [2000] */ - {0x8fa1c0, 0x00e4bc96}, /* U+4F16 [2000] */ - {0x8fa1c1, 0x00e4bda4}, /* U+4F64 [2000] */ - {0x8fa1c2, 0x00e4bcb7}, /* U+4F37 [2000] */ - {0x8fa1c3, 0x00e4bcbe}, /* U+4F3E [2000] */ - {0x8fa1c4, 0x00e4bd94}, /* U+4F54 [2000] */ - {0x8fa1c5, 0x00e4bd98}, /* U+4F58 [2000] */ + {0x8fa1b7, 0xe4babc}, /* U+4EBC [2000] */ + {0x8fa1b8, 0xe4bb83}, /* U+4EC3 [2000] */ + {0x8fa1b9, 0xe4bb88}, /* U+4EC8 [2000] */ + {0x8fa1ba, 0xe4bb90}, /* U+4ED0 [2000] */ + {0x8fa1bb, 0xe4bbab}, /* U+4EEB [2000] */ + {0x8fa1bc, 0xe4bb9a}, /* U+4EDA [2000] */ + {0x8fa1bd, 0xe4bbb1}, /* U+4EF1 [2000] */ + {0x8fa1be, 0xe4bbb5}, /* U+4EF5 [2000] */ + {0x8fa1bf, 0xe4bc80}, /* U+4F00 [2000] */ + {0x8fa1c0, 0xe4bc96}, /* U+4F16 [2000] */ + {0x8fa1c1, 0xe4bda4}, /* U+4F64 [2000] */ + {0x8fa1c2, 0xe4bcb7}, /* U+4F37 [2000] */ + {0x8fa1c3, 0xe4bcbe}, /* U+4F3E [2000] */ + {0x8fa1c4, 0xe4bd94}, /* U+4F54 [2000] */ + {0x8fa1c5, 0xe4bd98}, /* U+4F58 [2000] */ {0x8fa1c6, 0xf0a08893}, /* U+20213 [2000] [Unicode3.1] */ - {0x8fa1c7, 0x00e4bdb7}, /* U+4F77 [2000] */ - {0x8fa1c8, 0x00e4bdb8}, /* U+4F78 [2000] */ - {0x8fa1c9, 0x00e4bdba}, /* U+4F7A [2000] */ - {0x8fa1ca, 0x00e4bdbd}, /* U+4F7D [2000] */ - {0x8fa1cb, 0x00e4be82}, /* U+4F82 [2000] */ - {0x8fa1cc, 0x00e4be85}, /* U+4F85 [2000] */ - {0x8fa1cd, 0x00e4be92}, /* U+4F92 [2000] */ - {0x8fa1ce, 0x00e4be9a}, /* U+4F9A [2000] */ - {0x8fa1cf, 0x00e4bfa6}, /* U+4FE6 [2000] */ - {0x8fa1d0, 0x00e4beb2}, /* U+4FB2 [2000] */ - {0x8fa1d1, 0x00e4bebe}, /* U+4FBE [2000] */ - {0x8fa1d2, 0x00e4bf85}, /* U+4FC5 [2000] */ - {0x8fa1d3, 0x00e4bf8b}, /* U+4FCB [2000] */ - {0x8fa1d4, 0x00e4bf8f}, /* U+4FCF [2000] */ - {0x8fa1d5, 0x00e4bf92}, /* U+4FD2 [2000] */ - {0x8fa1d6, 0x00e391aa}, /* U+346A [2000] */ - {0x8fa1d7, 0x00e4bfb2}, /* U+4FF2 [2000] */ - {0x8fa1d8, 0x00e58080}, /* U+5000 [2000] */ - {0x8fa1d9, 0x00e58090}, /* U+5010 [2000] */ - {0x8fa1da, 0x00e58093}, /* U+5013 [2000] */ - {0x8fa1db, 0x00e5809c}, /* U+501C [2000] */ - {0x8fa1dc, 0x00e5809e}, /* U+501E [2000] */ - {0x8fa1dd, 0x00e580a2}, /* U+5022 [2000] */ - {0x8fa1de, 0x00e391a8}, /* U+3468 [2000] */ - {0x8fa1df, 0x00e58182}, /* U+5042 [2000] */ - {0x8fa1e0, 0x00e58186}, /* U+5046 [2000] */ - {0x8fa1e1, 0x00e5818e}, /* U+504E [2000] */ - {0x8fa1e2, 0x00e58193}, /* U+5053 [2000] */ - {0x8fa1e3, 0x00e58197}, /* U+5057 [2000] */ - {0x8fa1e4, 0x00e581a3}, /* U+5063 [2000] */ - {0x8fa1e5, 0x00e581a6}, /* U+5066 [2000] */ - {0x8fa1e6, 0x00e581aa}, /* U+506A [2000] */ - {0x8fa1e7, 0x00e581b0}, /* U+5070 [2000] */ - {0x8fa1e8, 0x00e582a3}, /* U+50A3 [2000] */ - {0x8fa1e9, 0x00e58288}, /* U+5088 [2000] */ - {0x8fa1ea, 0x00e58292}, /* U+5092 [2000] */ - {0x8fa1eb, 0x00e58293}, /* U+5093 [2000] */ - {0x8fa1ec, 0x00e58295}, /* U+5095 [2000] */ - {0x8fa1ed, 0x00e58296}, /* U+5096 [2000] */ - {0x8fa1ee, 0x00e5829c}, /* U+509C [2000] */ - {0x8fa1ef, 0x00e582aa}, /* U+50AA [2000] */ + {0x8fa1c7, 0xe4bdb7}, /* U+4F77 [2000] */ + {0x8fa1c8, 0xe4bdb8}, /* U+4F78 [2000] */ + {0x8fa1c9, 0xe4bdba}, /* U+4F7A [2000] */ + {0x8fa1ca, 0xe4bdbd}, /* U+4F7D [2000] */ + {0x8fa1cb, 0xe4be82}, /* U+4F82 [2000] */ + {0x8fa1cc, 0xe4be85}, /* U+4F85 [2000] */ + {0x8fa1cd, 0xe4be92}, /* U+4F92 [2000] */ + {0x8fa1ce, 0xe4be9a}, /* U+4F9A [2000] */ + {0x8fa1cf, 0xe4bfa6}, /* U+4FE6 [2000] */ + {0x8fa1d0, 0xe4beb2}, /* U+4FB2 [2000] */ + {0x8fa1d1, 0xe4bebe}, /* U+4FBE [2000] */ + {0x8fa1d2, 0xe4bf85}, /* U+4FC5 [2000] */ + {0x8fa1d3, 0xe4bf8b}, /* U+4FCB [2000] */ + {0x8fa1d4, 0xe4bf8f}, /* U+4FCF [2000] */ + {0x8fa1d5, 0xe4bf92}, /* U+4FD2 [2000] */ + {0x8fa1d6, 0xe391aa}, /* U+346A [2000] */ + {0x8fa1d7, 0xe4bfb2}, /* U+4FF2 [2000] */ + {0x8fa1d8, 0xe58080}, /* U+5000 [2000] */ + {0x8fa1d9, 0xe58090}, /* U+5010 [2000] */ + {0x8fa1da, 0xe58093}, /* U+5013 [2000] */ + {0x8fa1db, 0xe5809c}, /* U+501C [2000] */ + {0x8fa1dc, 0xe5809e}, /* U+501E [2000] */ + {0x8fa1dd, 0xe580a2}, /* U+5022 [2000] */ + {0x8fa1de, 0xe391a8}, /* U+3468 [2000] */ + {0x8fa1df, 0xe58182}, /* U+5042 [2000] */ + {0x8fa1e0, 0xe58186}, /* U+5046 [2000] */ + {0x8fa1e1, 0xe5818e}, /* U+504E [2000] */ + {0x8fa1e2, 0xe58193}, /* U+5053 [2000] */ + {0x8fa1e3, 0xe58197}, /* U+5057 [2000] */ + {0x8fa1e4, 0xe581a3}, /* U+5063 [2000] */ + {0x8fa1e5, 0xe581a6}, /* U+5066 [2000] */ + {0x8fa1e6, 0xe581aa}, /* U+506A [2000] */ + {0x8fa1e7, 0xe581b0}, /* U+5070 [2000] */ + {0x8fa1e8, 0xe582a3}, /* U+50A3 [2000] */ + {0x8fa1e9, 0xe58288}, /* U+5088 [2000] */ + {0x8fa1ea, 0xe58292}, /* U+5092 [2000] */ + {0x8fa1eb, 0xe58293}, /* U+5093 [2000] */ + {0x8fa1ec, 0xe58295}, /* U+5095 [2000] */ + {0x8fa1ed, 0xe58296}, /* U+5096 [2000] */ + {0x8fa1ee, 0xe5829c}, /* U+509C [2000] */ + {0x8fa1ef, 0xe582aa}, /* U+50AA [2000] */ {0x8fa1f0, 0xf0a08cab}, /* U+2032B [2000] [Unicode3.1] */ - {0x8fa1f1, 0x00e582b1}, /* U+50B1 [2000] */ - {0x8fa1f2, 0x00e582ba}, /* U+50BA [2000] */ - {0x8fa1f3, 0x00e582bb}, /* U+50BB [2000] */ - {0x8fa1f4, 0x00e58384}, /* U+50C4 [2000] */ - {0x8fa1f5, 0x00e58387}, /* U+50C7 [2000] */ - {0x8fa1f6, 0x00e583b3}, /* U+50F3 [2000] */ + {0x8fa1f1, 0xe582b1}, /* U+50B1 [2000] */ + {0x8fa1f2, 0xe582ba}, /* U+50BA [2000] */ + {0x8fa1f3, 0xe582bb}, /* U+50BB [2000] */ + {0x8fa1f4, 0xe58384}, /* U+50C4 [2000] */ + {0x8fa1f5, 0xe58387}, /* U+50C7 [2000] */ + {0x8fa1f6, 0xe583b3}, /* U+50F3 [2000] */ {0x8fa1f7, 0xf0a08e81}, /* U+20381 [2000] [Unicode3.1] */ - {0x8fa1f8, 0x00e5838e}, /* U+50CE [2000] */ + {0x8fa1f8, 0xe5838e}, /* U+50CE [2000] */ {0x8fa1f9, 0xf0a08db1}, /* U+20371 [2000] [Unicode3.1] */ - {0x8fa1fa, 0x00e58394}, /* U+50D4 [2000] */ - {0x8fa1fb, 0x00e58399}, /* U+50D9 [2000] */ - {0x8fa1fc, 0x00e583a1}, /* U+50E1 [2000] */ - {0x8fa1fd, 0x00e583a9}, /* U+50E9 [2000] */ - {0x8fa1fe, 0x00e39292}, /* U+3492 [2000] */ - {0x8fa3a1, 0x00e58488}, /* U+5108 [2000] */ + {0x8fa1fa, 0xe58394}, /* U+50D4 [2000] */ + {0x8fa1fb, 0xe58399}, /* U+50D9 [2000] */ + {0x8fa1fc, 0xe583a1}, /* U+50E1 [2000] */ + {0x8fa1fd, 0xe583a9}, /* U+50E9 [2000] */ + {0x8fa1fe, 0xe39292}, /* U+3492 [2000] */ + {0x8fa3a1, 0xe58488}, /* U+5108 [2000] */ {0x8fa3a2, 0xf0a08fb9}, /* U+203F9 [2000] [Unicode3.1] */ - {0x8fa3a3, 0x00e58497}, /* U+5117 [2000] */ - {0x8fa3a4, 0x00e5849b}, /* U+511B [2000] */ + {0x8fa3a3, 0xe58497}, /* U+5117 [2000] */ + {0x8fa3a4, 0xe5849b}, /* U+511B [2000] */ {0x8fa3a5, 0xf0a0918a}, /* U+2044A [2000] [Unicode3.1] */ - {0x8fa3a6, 0x00e585a0}, /* U+5160 [2000] */ + {0x8fa3a6, 0xe585a0}, /* U+5160 [2000] */ {0x8fa3a7, 0xf0a09489}, /* U+20509 [2000] [Unicode3.1] */ - {0x8fa3a8, 0x00e585b3}, /* U+5173 [2000] */ - {0x8fa3a9, 0x00e58683}, /* U+5183 [2000] */ - {0x8fa3aa, 0x00e5868b}, /* U+518B [2000] */ - {0x8fa3ab, 0x00e392bc}, /* U+34BC [2000] */ - {0x8fa3ac, 0x00e58698}, /* U+5198 [2000] */ - {0x8fa3ad, 0x00e586a3}, /* U+51A3 [2000] */ - {0x8fa3ae, 0x00e586ad}, /* U+51AD [2000] */ - {0x8fa3af, 0x00e39387}, /* U+34C7 [2000] */ - {0x8fa3b0, 0x00e586bc}, /* U+51BC [2000] */ + {0x8fa3a8, 0xe585b3}, /* U+5173 [2000] */ + {0x8fa3a9, 0xe58683}, /* U+5183 [2000] */ + {0x8fa3aa, 0xe5868b}, /* U+518B [2000] */ + {0x8fa3ab, 0xe392bc}, /* U+34BC [2000] */ + {0x8fa3ac, 0xe58698}, /* U+5198 [2000] */ + {0x8fa3ad, 0xe586a3}, /* U+51A3 [2000] */ + {0x8fa3ae, 0xe586ad}, /* U+51AD [2000] */ + {0x8fa3af, 0xe39387}, /* U+34C7 [2000] */ + {0x8fa3b0, 0xe586bc}, /* U+51BC [2000] */ {0x8fa3b1, 0xf0a09796}, /* U+205D6 [2000] [Unicode3.1] */ {0x8fa3b2, 0xf0a098a8}, /* U+20628 [2000] [Unicode3.1] */ - {0x8fa3b3, 0x00e587b3}, /* U+51F3 [2000] */ - {0x8fa3b4, 0x00e587b4}, /* U+51F4 [2000] */ - {0x8fa3b5, 0x00e58882}, /* U+5202 [2000] */ - {0x8fa3b6, 0x00e58892}, /* U+5212 [2000] */ - {0x8fa3b7, 0x00e58896}, /* U+5216 [2000] */ + {0x8fa3b3, 0xe587b3}, /* U+51F3 [2000] */ + {0x8fa3b4, 0xe587b4}, /* U+51F4 [2000] */ + {0x8fa3b5, 0xe58882}, /* U+5202 [2000] */ + {0x8fa3b6, 0xe58892}, /* U+5212 [2000] */ + {0x8fa3b7, 0xe58896}, /* U+5216 [2000] */ {0x8fa3b8, 0xf0a09d8f}, /* U+2074F [2000] [Unicode3.1] */ - {0x8fa3b9, 0x00e58995}, /* U+5255 [2000] */ - {0x8fa3ba, 0x00e5899c}, /* U+525C [2000] */ - {0x8fa3bb, 0x00e589ac}, /* U+526C [2000] */ - {0x8fa3bc, 0x00e589b7}, /* U+5277 [2000] */ - {0x8fa3bd, 0x00e58a84}, /* U+5284 [2000] */ - {0x8fa3be, 0x00e58a82}, /* U+5282 [2000] */ + {0x8fa3b9, 0xe58995}, /* U+5255 [2000] */ + {0x8fa3ba, 0xe5899c}, /* U+525C [2000] */ + {0x8fa3bb, 0xe589ac}, /* U+526C [2000] */ + {0x8fa3bc, 0xe589b7}, /* U+5277 [2000] */ + {0x8fa3bd, 0xe58a84}, /* U+5284 [2000] */ + {0x8fa3be, 0xe58a82}, /* U+5282 [2000] */ {0x8fa3bf, 0xf0a0a087}, /* U+20807 [2000] [Unicode3.1] */ - {0x8fa3c0, 0x00e58a98}, /* U+5298 [2000] */ + {0x8fa3c0, 0xe58a98}, /* U+5298 [2000] */ {0x8fa3c1, 0xf0a0a0ba}, /* U+2083A [2000] [Unicode3.1] */ - {0x8fa3c2, 0x00e58aa4}, /* U+52A4 [2000] */ - {0x8fa3c3, 0x00e58aa6}, /* U+52A6 [2000] */ - {0x8fa3c4, 0x00e58aaf}, /* U+52AF [2000] */ - {0x8fa3c5, 0x00e58aba}, /* U+52BA [2000] */ - {0x8fa3c6, 0x00e58abb}, /* U+52BB [2000] */ - {0x8fa3c7, 0x00e58b8a}, /* U+52CA [2000] */ - {0x8fa3c8, 0x00e3949f}, /* U+351F [2000] */ - {0x8fa3c9, 0x00e58b91}, /* U+52D1 [2000] */ + {0x8fa3c2, 0xe58aa4}, /* U+52A4 [2000] */ + {0x8fa3c3, 0xe58aa6}, /* U+52A6 [2000] */ + {0x8fa3c4, 0xe58aaf}, /* U+52AF [2000] */ + {0x8fa3c5, 0xe58aba}, /* U+52BA [2000] */ + {0x8fa3c6, 0xe58abb}, /* U+52BB [2000] */ + {0x8fa3c7, 0xe58b8a}, /* U+52CA [2000] */ + {0x8fa3c8, 0xe3949f}, /* U+351F [2000] */ + {0x8fa3c9, 0xe58b91}, /* U+52D1 [2000] */ {0x8fa3ca, 0xf0a0a2b9}, /* U+208B9 [2000] [Unicode3.1] */ - {0x8fa3cb, 0x00e58bb7}, /* U+52F7 [2000] */ - {0x8fa3cc, 0x00e58c8a}, /* U+530A [2000] */ - {0x8fa3cd, 0x00e58c8b}, /* U+530B [2000] */ - {0x8fa3ce, 0x00e58ca4}, /* U+5324 [2000] */ - {0x8fa3cf, 0x00e58cb5}, /* U+5335 [2000] */ - {0x8fa3d0, 0x00e58cbe}, /* U+533E [2000] */ - {0x8fa3d1, 0x00e58d82}, /* U+5342 [2000] */ + {0x8fa3cb, 0xe58bb7}, /* U+52F7 [2000] */ + {0x8fa3cc, 0xe58c8a}, /* U+530A [2000] */ + {0x8fa3cd, 0xe58c8b}, /* U+530B [2000] */ + {0x8fa3ce, 0xe58ca4}, /* U+5324 [2000] */ + {0x8fa3cf, 0xe58cb5}, /* U+5335 [2000] */ + {0x8fa3d0, 0xe58cbe}, /* U+533E [2000] */ + {0x8fa3d1, 0xe58d82}, /* U+5342 [2000] */ {0x8fa3d2, 0xf0a0a5bc}, /* U+2097C [2000] [Unicode3.1] */ {0x8fa3d3, 0xf0a0a69d}, /* U+2099D [2000] [Unicode3.1] */ - {0x8fa3d4, 0x00e58da7}, /* U+5367 [2000] */ - {0x8fa3d5, 0x00e58dac}, /* U+536C [2000] */ - {0x8fa3d6, 0x00e58dba}, /* U+537A [2000] */ - {0x8fa3d7, 0x00e58ea4}, /* U+53A4 [2000] */ - {0x8fa3d8, 0x00e58eb4}, /* U+53B4 [2000] */ + {0x8fa3d4, 0xe58da7}, /* U+5367 [2000] */ + {0x8fa3d5, 0xe58dac}, /* U+536C [2000] */ + {0x8fa3d6, 0xe58dba}, /* U+537A [2000] */ + {0x8fa3d7, 0xe58ea4}, /* U+53A4 [2000] */ + {0x8fa3d8, 0xe58eb4}, /* U+53B4 [2000] */ {0x8fa3d9, 0xf0a0ab93}, /* U+20AD3 [2000] [Unicode3.1] */ - {0x8fa3da, 0x00e58eb7}, /* U+53B7 [2000] */ - {0x8fa3db, 0x00e58f80}, /* U+53C0 [2000] */ + {0x8fa3da, 0xe58eb7}, /* U+53B7 [2000] */ + {0x8fa3db, 0xe58f80}, /* U+53C0 [2000] */ {0x8fa3dc, 0xf0a0ac9d}, /* U+20B1D [2000] [Unicode3.1] */ - {0x8fa3dd, 0x00e3959d}, /* U+355D [2000] */ - {0x8fa3de, 0x00e3959e}, /* U+355E [2000] */ - {0x8fa3df, 0x00e58f95}, /* U+53D5 [2000] */ - {0x8fa3e0, 0x00e58f9a}, /* U+53DA [2000] */ - {0x8fa3e1, 0x00e395a3}, /* U+3563 [2000] */ - {0x8fa3e2, 0x00e58fb4}, /* U+53F4 [2000] */ - {0x8fa3e3, 0x00e58fb5}, /* U+53F5 [2000] */ - {0x8fa3e4, 0x00e59195}, /* U+5455 [2000] */ - {0x8fa3e5, 0x00e590a4}, /* U+5424 [2000] */ - {0x8fa3e6, 0x00e590a8}, /* U+5428 [2000] */ - {0x8fa3e7, 0x00e395ae}, /* U+356E [2000] */ - {0x8fa3e8, 0x00e59183}, /* U+5443 [2000] */ - {0x8fa3e9, 0x00e591a2}, /* U+5462 [2000] */ - {0x8fa3ea, 0x00e591a6}, /* U+5466 [2000] */ - {0x8fa3eb, 0x00e591ac}, /* U+546C [2000] */ - {0x8fa3ec, 0x00e5928a}, /* U+548A [2000] */ - {0x8fa3ed, 0x00e5928d}, /* U+548D [2000] */ - {0x8fa3ee, 0x00e59295}, /* U+5495 [2000] */ - {0x8fa3ef, 0x00e592a0}, /* U+54A0 [2000] */ - {0x8fa3f0, 0x00e592a6}, /* U+54A6 [2000] */ - {0x8fa3f1, 0x00e592ad}, /* U+54AD [2000] */ - {0x8fa3f2, 0x00e592ae}, /* U+54AE [2000] */ - {0x8fa3f3, 0x00e592b7}, /* U+54B7 [2000] */ - {0x8fa3f4, 0x00e592ba}, /* U+54BA [2000] */ - {0x8fa3f5, 0x00e592bf}, /* U+54BF [2000] */ - {0x8fa3f6, 0x00e59383}, /* U+54C3 [2000] */ + {0x8fa3dd, 0xe3959d}, /* U+355D [2000] */ + {0x8fa3de, 0xe3959e}, /* U+355E [2000] */ + {0x8fa3df, 0xe58f95}, /* U+53D5 [2000] */ + {0x8fa3e0, 0xe58f9a}, /* U+53DA [2000] */ + {0x8fa3e1, 0xe395a3}, /* U+3563 [2000] */ + {0x8fa3e2, 0xe58fb4}, /* U+53F4 [2000] */ + {0x8fa3e3, 0xe58fb5}, /* U+53F5 [2000] */ + {0x8fa3e4, 0xe59195}, /* U+5455 [2000] */ + {0x8fa3e5, 0xe590a4}, /* U+5424 [2000] */ + {0x8fa3e6, 0xe590a8}, /* U+5428 [2000] */ + {0x8fa3e7, 0xe395ae}, /* U+356E [2000] */ + {0x8fa3e8, 0xe59183}, /* U+5443 [2000] */ + {0x8fa3e9, 0xe591a2}, /* U+5462 [2000] */ + {0x8fa3ea, 0xe591a6}, /* U+5466 [2000] */ + {0x8fa3eb, 0xe591ac}, /* U+546C [2000] */ + {0x8fa3ec, 0xe5928a}, /* U+548A [2000] */ + {0x8fa3ed, 0xe5928d}, /* U+548D [2000] */ + {0x8fa3ee, 0xe59295}, /* U+5495 [2000] */ + {0x8fa3ef, 0xe592a0}, /* U+54A0 [2000] */ + {0x8fa3f0, 0xe592a6}, /* U+54A6 [2000] */ + {0x8fa3f1, 0xe592ad}, /* U+54AD [2000] */ + {0x8fa3f2, 0xe592ae}, /* U+54AE [2000] */ + {0x8fa3f3, 0xe592b7}, /* U+54B7 [2000] */ + {0x8fa3f4, 0xe592ba}, /* U+54BA [2000] */ + {0x8fa3f5, 0xe592bf}, /* U+54BF [2000] */ + {0x8fa3f6, 0xe59383}, /* U+54C3 [2000] */ {0x8fa3f7, 0xf0a0b585}, /* U+20D45 [2000] [Unicode3.1] */ - {0x8fa3f8, 0x00e593ac}, /* U+54EC [2000] */ - {0x8fa3f9, 0x00e593af}, /* U+54EF [2000] */ - {0x8fa3fa, 0x00e593b1}, /* U+54F1 [2000] */ - {0x8fa3fb, 0x00e593b3}, /* U+54F3 [2000] */ - {0x8fa3fc, 0x00e59480}, /* U+5500 [2000] */ - {0x8fa3fd, 0x00e59481}, /* U+5501 [2000] */ - {0x8fa3fe, 0x00e59489}, /* U+5509 [2000] */ - {0x8fa4a1, 0x00e594bc}, /* U+553C [2000] */ - {0x8fa4a2, 0x00e59581}, /* U+5541 [2000] */ - {0x8fa4a3, 0x00e396a6}, /* U+35A6 [2000] */ - {0x8fa4a4, 0x00e59587}, /* U+5547 [2000] */ - {0x8fa4a5, 0x00e5958a}, /* U+554A [2000] */ - {0x8fa4a6, 0x00e396a8}, /* U+35A8 [2000] */ - {0x8fa4a7, 0x00e595a0}, /* U+5560 [2000] */ - {0x8fa4a8, 0x00e595a1}, /* U+5561 [2000] */ - {0x8fa4a9, 0x00e595a4}, /* U+5564 [2000] */ + {0x8fa3f8, 0xe593ac}, /* U+54EC [2000] */ + {0x8fa3f9, 0xe593af}, /* U+54EF [2000] */ + {0x8fa3fa, 0xe593b1}, /* U+54F1 [2000] */ + {0x8fa3fb, 0xe593b3}, /* U+54F3 [2000] */ + {0x8fa3fc, 0xe59480}, /* U+5500 [2000] */ + {0x8fa3fd, 0xe59481}, /* U+5501 [2000] */ + {0x8fa3fe, 0xe59489}, /* U+5509 [2000] */ + {0x8fa4a1, 0xe594bc}, /* U+553C [2000] */ + {0x8fa4a2, 0xe59581}, /* U+5541 [2000] */ + {0x8fa4a3, 0xe396a6}, /* U+35A6 [2000] */ + {0x8fa4a4, 0xe59587}, /* U+5547 [2000] */ + {0x8fa4a5, 0xe5958a}, /* U+554A [2000] */ + {0x8fa4a6, 0xe396a8}, /* U+35A8 [2000] */ + {0x8fa4a7, 0xe595a0}, /* U+5560 [2000] */ + {0x8fa4a8, 0xe595a1}, /* U+5561 [2000] */ + {0x8fa4a9, 0xe595a4}, /* U+5564 [2000] */ {0x8fa4aa, 0xf0a0b7a1}, /* U+20DE1 [2000] [Unicode3.1] */ - {0x8fa4ab, 0x00e595bd}, /* U+557D [2000] */ - {0x8fa4ac, 0x00e59682}, /* U+5582 [2000] */ - {0x8fa4ad, 0x00e59688}, /* U+5588 [2000] */ - {0x8fa4ae, 0x00e59691}, /* U+5591 [2000] */ - {0x8fa4af, 0x00e39785}, /* U+35C5 [2000] */ - {0x8fa4b0, 0x00e59792}, /* U+55D2 [2000] */ + {0x8fa4ab, 0xe595bd}, /* U+557D [2000] */ + {0x8fa4ac, 0xe59682}, /* U+5582 [2000] */ + {0x8fa4ad, 0xe59688}, /* U+5588 [2000] */ + {0x8fa4ae, 0xe59691}, /* U+5591 [2000] */ + {0x8fa4af, 0xe39785}, /* U+35C5 [2000] */ + {0x8fa4b0, 0xe59792}, /* U+55D2 [2000] */ {0x8fa4b1, 0xf0a0ba95}, /* U+20E95 [2000] [Unicode3.1] */ {0x8fa4b2, 0xf0a0b9ad}, /* U+20E6D [2000] [Unicode3.1] */ - {0x8fa4b3, 0x00e596bf}, /* U+55BF [2000] */ - {0x8fa4b4, 0x00e59789}, /* U+55C9 [2000] */ - {0x8fa4b5, 0x00e5978c}, /* U+55CC [2000] */ - {0x8fa4b6, 0x00e59791}, /* U+55D1 [2000] */ - {0x8fa4b7, 0x00e5979d}, /* U+55DD [2000] */ - {0x8fa4b8, 0x00e3979a}, /* U+35DA [2000] */ - {0x8fa4b9, 0x00e597a2}, /* U+55E2 [2000] */ + {0x8fa4b3, 0xe596bf}, /* U+55BF [2000] */ + {0x8fa4b4, 0xe59789}, /* U+55C9 [2000] */ + {0x8fa4b5, 0xe5978c}, /* U+55CC [2000] */ + {0x8fa4b6, 0xe59791}, /* U+55D1 [2000] */ + {0x8fa4b7, 0xe5979d}, /* U+55DD [2000] */ + {0x8fa4b8, 0xe3979a}, /* U+35DA [2000] */ + {0x8fa4b9, 0xe597a2}, /* U+55E2 [2000] */ {0x8fa4ba, 0xf0a0b9a4}, /* U+20E64 [2000] [Unicode3.1] */ - {0x8fa4bb, 0x00e597a9}, /* U+55E9 [2000] */ - {0x8fa4bc, 0x00e598a8}, /* U+5628 [2000] */ + {0x8fa4bb, 0xe597a9}, /* U+55E9 [2000] */ + {0x8fa4bc, 0xe598a8}, /* U+5628 [2000] */ {0x8fa4bd, 0xf0a0bd9f}, /* U+20F5F [2000] [Unicode3.1] */ - {0x8fa4be, 0x00e59887}, /* U+5607 [2000] */ - {0x8fa4bf, 0x00e59890}, /* U+5610 [2000] */ - {0x8fa4c0, 0x00e598b0}, /* U+5630 [2000] */ - {0x8fa4c1, 0x00e598b7}, /* U+5637 [2000] */ - {0x8fa4c2, 0x00e397b4}, /* U+35F4 [2000] */ - {0x8fa4c3, 0x00e598bd}, /* U+563D [2000] */ - {0x8fa4c4, 0x00e598bf}, /* U+563F [2000] */ - {0x8fa4c5, 0x00e59980}, /* U+5640 [2000] */ - {0x8fa4c6, 0x00e59987}, /* U+5647 [2000] */ - {0x8fa4c7, 0x00e5999e}, /* U+565E [2000] */ - {0x8fa4c8, 0x00e599a0}, /* U+5660 [2000] */ - {0x8fa4c9, 0x00e599ad}, /* U+566D [2000] */ - {0x8fa4ca, 0x00e39885}, /* U+3605 [2000] */ - {0x8fa4cb, 0x00e59a88}, /* U+5688 [2000] */ - {0x8fa4cc, 0x00e59a8c}, /* U+568C [2000] */ - {0x8fa4cd, 0x00e59a95}, /* U+5695 [2000] */ - {0x8fa4ce, 0x00e59a9a}, /* U+569A [2000] */ - {0x8fa4cf, 0x00e59a9d}, /* U+569D [2000] */ - {0x8fa4d0, 0x00e59aa8}, /* U+56A8 [2000] */ - {0x8fa4d1, 0x00e59aad}, /* U+56AD [2000] */ - {0x8fa4d2, 0x00e59ab2}, /* U+56B2 [2000] */ - {0x8fa4d3, 0x00e59b85}, /* U+56C5 [2000] */ - {0x8fa4d4, 0x00e59b8d}, /* U+56CD [2000] */ - {0x8fa4d5, 0x00e59b9f}, /* U+56DF [2000] */ - {0x8fa4d6, 0x00e59ba8}, /* U+56E8 [2000] */ - {0x8fa4d7, 0x00e59bb6}, /* U+56F6 [2000] */ - {0x8fa4d8, 0x00e59bb7}, /* U+56F7 [2000] */ + {0x8fa4be, 0xe59887}, /* U+5607 [2000] */ + {0x8fa4bf, 0xe59890}, /* U+5610 [2000] */ + {0x8fa4c0, 0xe598b0}, /* U+5630 [2000] */ + {0x8fa4c1, 0xe598b7}, /* U+5637 [2000] */ + {0x8fa4c2, 0xe397b4}, /* U+35F4 [2000] */ + {0x8fa4c3, 0xe598bd}, /* U+563D [2000] */ + {0x8fa4c4, 0xe598bf}, /* U+563F [2000] */ + {0x8fa4c5, 0xe59980}, /* U+5640 [2000] */ + {0x8fa4c6, 0xe59987}, /* U+5647 [2000] */ + {0x8fa4c7, 0xe5999e}, /* U+565E [2000] */ + {0x8fa4c8, 0xe599a0}, /* U+5660 [2000] */ + {0x8fa4c9, 0xe599ad}, /* U+566D [2000] */ + {0x8fa4ca, 0xe39885}, /* U+3605 [2000] */ + {0x8fa4cb, 0xe59a88}, /* U+5688 [2000] */ + {0x8fa4cc, 0xe59a8c}, /* U+568C [2000] */ + {0x8fa4cd, 0xe59a95}, /* U+5695 [2000] */ + {0x8fa4ce, 0xe59a9a}, /* U+569A [2000] */ + {0x8fa4cf, 0xe59a9d}, /* U+569D [2000] */ + {0x8fa4d0, 0xe59aa8}, /* U+56A8 [2000] */ + {0x8fa4d1, 0xe59aad}, /* U+56AD [2000] */ + {0x8fa4d2, 0xe59ab2}, /* U+56B2 [2000] */ + {0x8fa4d3, 0xe59b85}, /* U+56C5 [2000] */ + {0x8fa4d4, 0xe59b8d}, /* U+56CD [2000] */ + {0x8fa4d5, 0xe59b9f}, /* U+56DF [2000] */ + {0x8fa4d6, 0xe59ba8}, /* U+56E8 [2000] */ + {0x8fa4d7, 0xe59bb6}, /* U+56F6 [2000] */ + {0x8fa4d8, 0xe59bb7}, /* U+56F7 [2000] */ {0x8fa4d9, 0xf0a18881}, /* U+21201 [2000] [Unicode3.1] */ - {0x8fa4da, 0x00e59c95}, /* U+5715 [2000] */ - {0x8fa4db, 0x00e59ca3}, /* U+5723 [2000] */ + {0x8fa4da, 0xe59c95}, /* U+5715 [2000] */ + {0x8fa4db, 0xe59ca3}, /* U+5723 [2000] */ {0x8fa4dc, 0xf0a18995}, /* U+21255 [2000] [Unicode3.1] */ - {0x8fa4dd, 0x00e59ca9}, /* U+5729 [2000] */ + {0x8fa4dd, 0xe59ca9}, /* U+5729 [2000] */ {0x8fa4de, 0xf0a189bb}, /* U+2127B [2000] [Unicode3.1] */ - {0x8fa4df, 0x00e59d85}, /* U+5745 [2000] */ - {0x8fa4e0, 0x00e59d86}, /* U+5746 [2000] */ - {0x8fa4e1, 0x00e59d8c}, /* U+574C [2000] */ - {0x8fa4e2, 0x00e59d8d}, /* U+574D [2000] */ + {0x8fa4df, 0xe59d85}, /* U+5745 [2000] */ + {0x8fa4e0, 0xe59d86}, /* U+5746 [2000] */ + {0x8fa4e1, 0xe59d8c}, /* U+574C [2000] */ + {0x8fa4e2, 0xe59d8d}, /* U+574D [2000] */ {0x8fa4e3, 0xf0a189b4}, /* U+21274 [2000] [Unicode3.1] */ - {0x8fa4e4, 0x00e59da8}, /* U+5768 [2000] */ - {0x8fa4e5, 0x00e59daf}, /* U+576F [2000] */ - {0x8fa4e6, 0x00e59db3}, /* U+5773 [2000] */ - {0x8fa4e7, 0x00e59db4}, /* U+5774 [2000] */ - {0x8fa4e8, 0x00e59db5}, /* U+5775 [2000] */ - {0x8fa4e9, 0x00e59dbb}, /* U+577B [2000] */ + {0x8fa4e4, 0xe59da8}, /* U+5768 [2000] */ + {0x8fa4e5, 0xe59daf}, /* U+576F [2000] */ + {0x8fa4e6, 0xe59db3}, /* U+5773 [2000] */ + {0x8fa4e7, 0xe59db4}, /* U+5774 [2000] */ + {0x8fa4e8, 0xe59db5}, /* U+5775 [2000] */ + {0x8fa4e9, 0xe59dbb}, /* U+577B [2000] */ {0x8fa4ea, 0xf0a18ba4}, /* U+212E4 [2000] [Unicode3.1] */ {0x8fa4eb, 0xf0a18b97}, /* U+212D7 [2000] [Unicode3.1] */ - {0x8fa4ec, 0x00e59eac}, /* U+57AC [2000] */ - {0x8fa4ed, 0x00e59e9a}, /* U+579A [2000] */ - {0x8fa4ee, 0x00e59e9d}, /* U+579D [2000] */ - {0x8fa4ef, 0x00e59e9e}, /* U+579E [2000] */ - {0x8fa4f0, 0x00e59ea8}, /* U+57A8 [2000] */ - {0x8fa4f1, 0x00e59f97}, /* U+57D7 [2000] */ + {0x8fa4ec, 0xe59eac}, /* U+57AC [2000] */ + {0x8fa4ed, 0xe59e9a}, /* U+579A [2000] */ + {0x8fa4ee, 0xe59e9d}, /* U+579D [2000] */ + {0x8fa4ef, 0xe59e9e}, /* U+579E [2000] */ + {0x8fa4f0, 0xe59ea8}, /* U+57A8 [2000] */ + {0x8fa4f1, 0xe59f97}, /* U+57D7 [2000] */ {0x8fa4f2, 0xf0a18bbd}, /* U+212FD [2000] [Unicode3.1] */ - {0x8fa4f3, 0x00e59f8c}, /* U+57CC [2000] */ + {0x8fa4f3, 0xe59f8c}, /* U+57CC [2000] */ {0x8fa4f4, 0xf0a18cb6}, /* U+21336 [2000] [Unicode3.1] */ {0x8fa4f5, 0xf0a18d84}, /* U+21344 [2000] [Unicode3.1] */ - {0x8fa4f6, 0x00e59f9e}, /* U+57DE [2000] */ - {0x8fa4f7, 0x00e59fa6}, /* U+57E6 [2000] */ - {0x8fa4f8, 0x00e59fb0}, /* U+57F0 [2000] */ - {0x8fa4f9, 0x00e3998a}, /* U+364A [2000] */ - {0x8fa4fa, 0x00e59fb8}, /* U+57F8 [2000] */ - {0x8fa4fb, 0x00e59fbb}, /* U+57FB [2000] */ - {0x8fa4fc, 0x00e59fbd}, /* U+57FD [2000] */ - {0x8fa4fd, 0x00e5a084}, /* U+5804 [2000] */ - {0x8fa4fe, 0x00e5a09e}, /* U+581E [2000] */ - {0x8fa5a1, 0x00e5a0a0}, /* U+5820 [2000] */ - {0x8fa5a2, 0x00e5a0a7}, /* U+5827 [2000] */ - {0x8fa5a3, 0x00e5a0b2}, /* U+5832 [2000] */ - {0x8fa5a4, 0x00e5a0b9}, /* U+5839 [2000] */ + {0x8fa4f6, 0xe59f9e}, /* U+57DE [2000] */ + {0x8fa4f7, 0xe59fa6}, /* U+57E6 [2000] */ + {0x8fa4f8, 0xe59fb0}, /* U+57F0 [2000] */ + {0x8fa4f9, 0xe3998a}, /* U+364A [2000] */ + {0x8fa4fa, 0xe59fb8}, /* U+57F8 [2000] */ + {0x8fa4fb, 0xe59fbb}, /* U+57FB [2000] */ + {0x8fa4fc, 0xe59fbd}, /* U+57FD [2000] */ + {0x8fa4fd, 0xe5a084}, /* U+5804 [2000] */ + {0x8fa4fe, 0xe5a09e}, /* U+581E [2000] */ + {0x8fa5a1, 0xe5a0a0}, /* U+5820 [2000] */ + {0x8fa5a2, 0xe5a0a7}, /* U+5827 [2000] */ + {0x8fa5a3, 0xe5a0b2}, /* U+5832 [2000] */ + {0x8fa5a4, 0xe5a0b9}, /* U+5839 [2000] */ {0x8fa5a5, 0xf0a18f84}, /* U+213C4 [2000] [Unicode3.1] */ - {0x8fa5a6, 0x00e5a189}, /* U+5849 [2000] */ - {0x8fa5a7, 0x00e5a18c}, /* U+584C [2000] */ - {0x8fa5a8, 0x00e5a1a7}, /* U+5867 [2000] */ - {0x8fa5a9, 0x00e5a28a}, /* U+588A [2000] */ - {0x8fa5aa, 0x00e5a28b}, /* U+588B [2000] */ - {0x8fa5ab, 0x00e5a28d}, /* U+588D [2000] */ - {0x8fa5ac, 0x00e5a28f}, /* U+588F [2000] */ - {0x8fa5ad, 0x00e5a290}, /* U+5890 [2000] */ - {0x8fa5ae, 0x00e5a294}, /* U+5894 [2000] */ - {0x8fa5af, 0x00e5a29d}, /* U+589D [2000] */ - {0x8fa5b0, 0x00e5a2aa}, /* U+58AA [2000] */ - {0x8fa5b1, 0x00e5a2b1}, /* U+58B1 [2000] */ + {0x8fa5a6, 0xe5a189}, /* U+5849 [2000] */ + {0x8fa5a7, 0xe5a18c}, /* U+584C [2000] */ + {0x8fa5a8, 0xe5a1a7}, /* U+5867 [2000] */ + {0x8fa5a9, 0xe5a28a}, /* U+588A [2000] */ + {0x8fa5aa, 0xe5a28b}, /* U+588B [2000] */ + {0x8fa5ab, 0xe5a28d}, /* U+588D [2000] */ + {0x8fa5ac, 0xe5a28f}, /* U+588F [2000] */ + {0x8fa5ad, 0xe5a290}, /* U+5890 [2000] */ + {0x8fa5ae, 0xe5a294}, /* U+5894 [2000] */ + {0x8fa5af, 0xe5a29d}, /* U+589D [2000] */ + {0x8fa5b0, 0xe5a2aa}, /* U+58AA [2000] */ + {0x8fa5b1, 0xe5a2b1}, /* U+58B1 [2000] */ {0x8fa5b2, 0xf0a191ad}, /* U+2146D [2000] [Unicode3.1] */ - {0x8fa5b3, 0x00e5a383}, /* U+58C3 [2000] */ - {0x8fa5b4, 0x00e5a38d}, /* U+58CD [2000] */ - {0x8fa5b5, 0x00e5a3a2}, /* U+58E2 [2000] */ - {0x8fa5b6, 0x00e5a3b3}, /* U+58F3 [2000] */ - {0x8fa5b7, 0x00e5a3b4}, /* U+58F4 [2000] */ - {0x8fa5b8, 0x00e5a485}, /* U+5905 [2000] */ - {0x8fa5b9, 0x00e5a486}, /* U+5906 [2000] */ - {0x8fa5ba, 0x00e5a48b}, /* U+590B [2000] */ - {0x8fa5bb, 0x00e5a48d}, /* U+590D [2000] */ - {0x8fa5bc, 0x00e5a494}, /* U+5914 [2000] */ - {0x8fa5bd, 0x00e5a4a4}, /* U+5924 [2000] */ + {0x8fa5b3, 0xe5a383}, /* U+58C3 [2000] */ + {0x8fa5b4, 0xe5a38d}, /* U+58CD [2000] */ + {0x8fa5b5, 0xe5a3a2}, /* U+58E2 [2000] */ + {0x8fa5b6, 0xe5a3b3}, /* U+58F3 [2000] */ + {0x8fa5b7, 0xe5a3b4}, /* U+58F4 [2000] */ + {0x8fa5b8, 0xe5a485}, /* U+5905 [2000] */ + {0x8fa5b9, 0xe5a486}, /* U+5906 [2000] */ + {0x8fa5ba, 0xe5a48b}, /* U+590B [2000] */ + {0x8fa5bb, 0xe5a48d}, /* U+590D [2000] */ + {0x8fa5bc, 0xe5a494}, /* U+5914 [2000] */ + {0x8fa5bd, 0xe5a4a4}, /* U+5924 [2000] */ {0x8fa5be, 0xf0a19797}, /* U+215D7 [2000] [Unicode3.1] */ - {0x8fa5bf, 0x00e39a91}, /* U+3691 [2000] */ - {0x8fa5c0, 0x00e5a4bd}, /* U+593D [2000] */ - {0x8fa5c1, 0x00e39a99}, /* U+3699 [2000] */ - {0x8fa5c2, 0x00e5a586}, /* U+5946 [2000] */ - {0x8fa5c3, 0x00e39a96}, /* U+3696 [2000] */ + {0x8fa5bf, 0xe39a91}, /* U+3691 [2000] */ + {0x8fa5c0, 0xe5a4bd}, /* U+593D [2000] */ + {0x8fa5c1, 0xe39a99}, /* U+3699 [2000] */ + {0x8fa5c2, 0xe5a586}, /* U+5946 [2000] */ + {0x8fa5c3, 0xe39a96}, /* U+3696 [2000] */ {0x8fa5c4, 0xf0a6b0a9}, /* U+26C29 [2000] [Unicode3.1] */ - {0x8fa5c5, 0x00e5a59b}, /* U+595B [2000] */ - {0x8fa5c6, 0x00e5a59f}, /* U+595F [2000] */ + {0x8fa5c5, 0xe5a59b}, /* U+595B [2000] */ + {0x8fa5c6, 0xe5a59f}, /* U+595F [2000] */ {0x8fa5c7, 0xf0a19987}, /* U+21647 [2000] [Unicode3.1] */ - {0x8fa5c8, 0x00e5a5b5}, /* U+5975 [2000] */ - {0x8fa5c9, 0x00e5a5b6}, /* U+5976 [2000] */ - {0x8fa5ca, 0x00e5a5bc}, /* U+597C [2000] */ - {0x8fa5cb, 0x00e5a69f}, /* U+599F [2000] */ - {0x8fa5cc, 0x00e5a6ae}, /* U+59AE [2000] */ - {0x8fa5cd, 0x00e5a6bc}, /* U+59BC [2000] */ - {0x8fa5ce, 0x00e5a788}, /* U+59C8 [2000] */ - {0x8fa5cf, 0x00e5a78d}, /* U+59CD [2000] */ - {0x8fa5d0, 0x00e5a79e}, /* U+59DE [2000] */ - {0x8fa5d1, 0x00e5a7a3}, /* U+59E3 [2000] */ - {0x8fa5d2, 0x00e5a7a4}, /* U+59E4 [2000] */ - {0x8fa5d3, 0x00e5a7a7}, /* U+59E7 [2000] */ - {0x8fa5d4, 0x00e5a7ae}, /* U+59EE [2000] */ + {0x8fa5c8, 0xe5a5b5}, /* U+5975 [2000] */ + {0x8fa5c9, 0xe5a5b6}, /* U+5976 [2000] */ + {0x8fa5ca, 0xe5a5bc}, /* U+597C [2000] */ + {0x8fa5cb, 0xe5a69f}, /* U+599F [2000] */ + {0x8fa5cc, 0xe5a6ae}, /* U+59AE [2000] */ + {0x8fa5cd, 0xe5a6bc}, /* U+59BC [2000] */ + {0x8fa5ce, 0xe5a788}, /* U+59C8 [2000] */ + {0x8fa5cf, 0xe5a78d}, /* U+59CD [2000] */ + {0x8fa5d0, 0xe5a79e}, /* U+59DE [2000] */ + {0x8fa5d1, 0xe5a7a3}, /* U+59E3 [2000] */ + {0x8fa5d2, 0xe5a7a4}, /* U+59E4 [2000] */ + {0x8fa5d3, 0xe5a7a7}, /* U+59E7 [2000] */ + {0x8fa5d4, 0xe5a7ae}, /* U+59EE [2000] */ {0x8fa5d5, 0xf0a19c86}, /* U+21706 [2000] [Unicode3.1] */ {0x8fa5d6, 0xf0a19d82}, /* U+21742 [2000] [Unicode3.1] */ - {0x8fa5d7, 0x00e39b8f}, /* U+36CF [2000] */ - {0x8fa5d8, 0x00e5a88c}, /* U+5A0C [2000] */ - {0x8fa5d9, 0x00e5a88d}, /* U+5A0D [2000] */ - {0x8fa5da, 0x00e5a897}, /* U+5A17 [2000] */ - {0x8fa5db, 0x00e5a8a7}, /* U+5A27 [2000] */ - {0x8fa5dc, 0x00e5a8ad}, /* U+5A2D [2000] */ - {0x8fa5dd, 0x00e5a995}, /* U+5A55 [2000] */ - {0x8fa5de, 0x00e5a9a5}, /* U+5A65 [2000] */ - {0x8fa5df, 0x00e5a9ba}, /* U+5A7A [2000] */ - {0x8fa5e0, 0x00e5aa8b}, /* U+5A8B [2000] */ - {0x8fa5e1, 0x00e5aa9c}, /* U+5A9C [2000] */ - {0x8fa5e2, 0x00e5aa9f}, /* U+5A9F [2000] */ - {0x8fa5e3, 0x00e5aaa0}, /* U+5AA0 [2000] */ - {0x8fa5e4, 0x00e5aaa2}, /* U+5AA2 [2000] */ - {0x8fa5e5, 0x00e5aab1}, /* U+5AB1 [2000] */ - {0x8fa5e6, 0x00e5aab3}, /* U+5AB3 [2000] */ - {0x8fa5e7, 0x00e5aab5}, /* U+5AB5 [2000] */ - {0x8fa5e8, 0x00e5aaba}, /* U+5ABA [2000] */ - {0x8fa5e9, 0x00e5aabf}, /* U+5ABF [2000] */ - {0x8fa5ea, 0x00e5ab9a}, /* U+5ADA [2000] */ - {0x8fa5eb, 0x00e5ab9c}, /* U+5ADC [2000] */ - {0x8fa5ec, 0x00e5aba0}, /* U+5AE0 [2000] */ - {0x8fa5ed, 0x00e5aba5}, /* U+5AE5 [2000] */ - {0x8fa5ee, 0x00e5abb0}, /* U+5AF0 [2000] */ - {0x8fa5ef, 0x00e5abae}, /* U+5AEE [2000] */ - {0x8fa5f0, 0x00e5abb5}, /* U+5AF5 [2000] */ - {0x8fa5f1, 0x00e5ac80}, /* U+5B00 [2000] */ - {0x8fa5f2, 0x00e5ac88}, /* U+5B08 [2000] */ - {0x8fa5f3, 0x00e5ac97}, /* U+5B17 [2000] */ - {0x8fa5f4, 0x00e5acb4}, /* U+5B34 [2000] */ - {0x8fa5f5, 0x00e5acad}, /* U+5B2D [2000] */ - {0x8fa5f6, 0x00e5ad8c}, /* U+5B4C [2000] */ - {0x8fa5f7, 0x00e5ad92}, /* U+5B52 [2000] */ - {0x8fa5f8, 0x00e5ada8}, /* U+5B68 [2000] */ - {0x8fa5f9, 0x00e5adaf}, /* U+5B6F [2000] */ - {0x8fa5fa, 0x00e5adbc}, /* U+5B7C [2000] */ - {0x8fa5fb, 0x00e5adbf}, /* U+5B7F [2000] */ - {0x8fa5fc, 0x00e5ae81}, /* U+5B81 [2000] */ - {0x8fa5fd, 0x00e5ae84}, /* U+5B84 [2000] */ + {0x8fa5d7, 0xe39b8f}, /* U+36CF [2000] */ + {0x8fa5d8, 0xe5a88c}, /* U+5A0C [2000] */ + {0x8fa5d9, 0xe5a88d}, /* U+5A0D [2000] */ + {0x8fa5da, 0xe5a897}, /* U+5A17 [2000] */ + {0x8fa5db, 0xe5a8a7}, /* U+5A27 [2000] */ + {0x8fa5dc, 0xe5a8ad}, /* U+5A2D [2000] */ + {0x8fa5dd, 0xe5a995}, /* U+5A55 [2000] */ + {0x8fa5de, 0xe5a9a5}, /* U+5A65 [2000] */ + {0x8fa5df, 0xe5a9ba}, /* U+5A7A [2000] */ + {0x8fa5e0, 0xe5aa8b}, /* U+5A8B [2000] */ + {0x8fa5e1, 0xe5aa9c}, /* U+5A9C [2000] */ + {0x8fa5e2, 0xe5aa9f}, /* U+5A9F [2000] */ + {0x8fa5e3, 0xe5aaa0}, /* U+5AA0 [2000] */ + {0x8fa5e4, 0xe5aaa2}, /* U+5AA2 [2000] */ + {0x8fa5e5, 0xe5aab1}, /* U+5AB1 [2000] */ + {0x8fa5e6, 0xe5aab3}, /* U+5AB3 [2000] */ + {0x8fa5e7, 0xe5aab5}, /* U+5AB5 [2000] */ + {0x8fa5e8, 0xe5aaba}, /* U+5ABA [2000] */ + {0x8fa5e9, 0xe5aabf}, /* U+5ABF [2000] */ + {0x8fa5ea, 0xe5ab9a}, /* U+5ADA [2000] */ + {0x8fa5eb, 0xe5ab9c}, /* U+5ADC [2000] */ + {0x8fa5ec, 0xe5aba0}, /* U+5AE0 [2000] */ + {0x8fa5ed, 0xe5aba5}, /* U+5AE5 [2000] */ + {0x8fa5ee, 0xe5abb0}, /* U+5AF0 [2000] */ + {0x8fa5ef, 0xe5abae}, /* U+5AEE [2000] */ + {0x8fa5f0, 0xe5abb5}, /* U+5AF5 [2000] */ + {0x8fa5f1, 0xe5ac80}, /* U+5B00 [2000] */ + {0x8fa5f2, 0xe5ac88}, /* U+5B08 [2000] */ + {0x8fa5f3, 0xe5ac97}, /* U+5B17 [2000] */ + {0x8fa5f4, 0xe5acb4}, /* U+5B34 [2000] */ + {0x8fa5f5, 0xe5acad}, /* U+5B2D [2000] */ + {0x8fa5f6, 0xe5ad8c}, /* U+5B4C [2000] */ + {0x8fa5f7, 0xe5ad92}, /* U+5B52 [2000] */ + {0x8fa5f8, 0xe5ada8}, /* U+5B68 [2000] */ + {0x8fa5f9, 0xe5adaf}, /* U+5B6F [2000] */ + {0x8fa5fa, 0xe5adbc}, /* U+5B7C [2000] */ + {0x8fa5fb, 0xe5adbf}, /* U+5B7F [2000] */ + {0x8fa5fc, 0xe5ae81}, /* U+5B81 [2000] */ + {0x8fa5fd, 0xe5ae84}, /* U+5B84 [2000] */ {0x8fa5fe, 0xf0a1a783}, /* U+219C3 [2000] [Unicode3.1] */ - {0x8fa8a1, 0x00e5ae96}, /* U+5B96 [2000] */ - {0x8fa8a2, 0x00e5aeac}, /* U+5BAC [2000] */ - {0x8fa8a3, 0x00e39da1}, /* U+3761 [2000] */ - {0x8fa8a4, 0x00e5af80}, /* U+5BC0 [2000] */ - {0x8fa8a5, 0x00e39da2}, /* U+3762 [2000] */ - {0x8fa8a6, 0x00e5af8e}, /* U+5BCE [2000] */ - {0x8fa8a7, 0x00e5af96}, /* U+5BD6 [2000] */ - {0x8fa8a8, 0x00e39dac}, /* U+376C [2000] */ - {0x8fa8a9, 0x00e39dab}, /* U+376B [2000] */ - {0x8fa8aa, 0x00e5afb1}, /* U+5BF1 [2000] */ - {0x8fa8ab, 0x00e5afbd}, /* U+5BFD [2000] */ - {0x8fa8ac, 0x00e39db5}, /* U+3775 [2000] */ - {0x8fa8ad, 0x00e5b083}, /* U+5C03 [2000] */ - {0x8fa8ae, 0x00e5b0a9}, /* U+5C29 [2000] */ - {0x8fa8af, 0x00e5b0b0}, /* U+5C30 [2000] */ + {0x8fa8a1, 0xe5ae96}, /* U+5B96 [2000] */ + {0x8fa8a2, 0xe5aeac}, /* U+5BAC [2000] */ + {0x8fa8a3, 0xe39da1}, /* U+3761 [2000] */ + {0x8fa8a4, 0xe5af80}, /* U+5BC0 [2000] */ + {0x8fa8a5, 0xe39da2}, /* U+3762 [2000] */ + {0x8fa8a6, 0xe5af8e}, /* U+5BCE [2000] */ + {0x8fa8a7, 0xe5af96}, /* U+5BD6 [2000] */ + {0x8fa8a8, 0xe39dac}, /* U+376C [2000] */ + {0x8fa8a9, 0xe39dab}, /* U+376B [2000] */ + {0x8fa8aa, 0xe5afb1}, /* U+5BF1 [2000] */ + {0x8fa8ab, 0xe5afbd}, /* U+5BFD [2000] */ + {0x8fa8ac, 0xe39db5}, /* U+3775 [2000] */ + {0x8fa8ad, 0xe5b083}, /* U+5C03 [2000] */ + {0x8fa8ae, 0xe5b0a9}, /* U+5C29 [2000] */ + {0x8fa8af, 0xe5b0b0}, /* U+5C30 [2000] */ {0x8fa8b0, 0xf0a1b196}, /* U+21C56 [2000] [Unicode3.1] */ - {0x8fa8b1, 0x00e5b19f}, /* U+5C5F [2000] */ - {0x8fa8b2, 0x00e5b1a3}, /* U+5C63 [2000] */ - {0x8fa8b3, 0x00e5b1a7}, /* U+5C67 [2000] */ - {0x8fa8b4, 0x00e5b1a8}, /* U+5C68 [2000] */ - {0x8fa8b5, 0x00e5b1a9}, /* U+5C69 [2000] */ - {0x8fa8b6, 0x00e5b1b0}, /* U+5C70 [2000] */ + {0x8fa8b1, 0xe5b19f}, /* U+5C5F [2000] */ + {0x8fa8b2, 0xe5b1a3}, /* U+5C63 [2000] */ + {0x8fa8b3, 0xe5b1a7}, /* U+5C67 [2000] */ + {0x8fa8b4, 0xe5b1a8}, /* U+5C68 [2000] */ + {0x8fa8b5, 0xe5b1a9}, /* U+5C69 [2000] */ + {0x8fa8b6, 0xe5b1b0}, /* U+5C70 [2000] */ {0x8fa8b7, 0xf0a1b4ad}, /* U+21D2D [2000] [Unicode3.1] */ {0x8fa8b8, 0xf0a1b585}, /* U+21D45 [2000] [Unicode3.1] */ - {0x8fa8b9, 0x00e5b1bc}, /* U+5C7C [2000] */ + {0x8fa8b9, 0xe5b1bc}, /* U+5C7C [2000] */ {0x8fa8ba, 0xf0a1b5b8}, /* U+21D78 [2000] [Unicode3.1] */ {0x8fa8bb, 0xf0a1b5a2}, /* U+21D62 [2000] [Unicode3.1] */ - {0x8fa8bc, 0x00e5b288}, /* U+5C88 [2000] */ - {0x8fa8bd, 0x00e5b28a}, /* U+5C8A [2000] */ - {0x8fa8be, 0x00e39f81}, /* U+37C1 [2000] */ + {0x8fa8bc, 0xe5b288}, /* U+5C88 [2000] */ + {0x8fa8bd, 0xe5b28a}, /* U+5C8A [2000] */ + {0x8fa8be, 0xe39f81}, /* U+37C1 [2000] */ {0x8fa8bf, 0xf0a1b6a1}, /* U+21DA1 [2000] [Unicode3.1] */ {0x8fa8c0, 0xf0a1b69c}, /* U+21D9C [2000] [Unicode3.1] */ - {0x8fa8c1, 0x00e5b2a0}, /* U+5CA0 [2000] */ - {0x8fa8c2, 0x00e5b2a2}, /* U+5CA2 [2000] */ - {0x8fa8c3, 0x00e5b2a6}, /* U+5CA6 [2000] */ - {0x8fa8c4, 0x00e5b2a7}, /* U+5CA7 [2000] */ + {0x8fa8c1, 0xe5b2a0}, /* U+5CA0 [2000] */ + {0x8fa8c2, 0xe5b2a2}, /* U+5CA2 [2000] */ + {0x8fa8c3, 0xe5b2a6}, /* U+5CA6 [2000] */ + {0x8fa8c4, 0xe5b2a7}, /* U+5CA7 [2000] */ {0x8fa8c5, 0xf0a1b692}, /* U+21D92 [2000] [Unicode3.1] */ - {0x8fa8c6, 0x00e5b2ad}, /* U+5CAD [2000] */ - {0x8fa8c7, 0x00e5b2b5}, /* U+5CB5 [2000] */ + {0x8fa8c6, 0xe5b2ad}, /* U+5CAD [2000] */ + {0x8fa8c7, 0xe5b2b5}, /* U+5CB5 [2000] */ {0x8fa8c8, 0xf0a1b6b7}, /* U+21DB7 [2000] [Unicode3.1] */ - {0x8fa8c9, 0x00e5b389}, /* U+5CC9 [2000] */ + {0x8fa8c9, 0xe5b389}, /* U+5CC9 [2000] */ {0x8fa8ca, 0xf0a1b7a0}, /* U+21DE0 [2000] [Unicode3.1] */ {0x8fa8cb, 0xf0a1b8b3}, /* U+21E33 [2000] [Unicode3.1] */ - {0x8fa8cc, 0x00e5b486}, /* U+5D06 [2000] */ - {0x8fa8cd, 0x00e5b490}, /* U+5D10 [2000] */ - {0x8fa8ce, 0x00e5b4ab}, /* U+5D2B [2000] */ - {0x8fa8cf, 0x00e5b49d}, /* U+5D1D [2000] */ - {0x8fa8d0, 0x00e5b4a0}, /* U+5D20 [2000] */ - {0x8fa8d1, 0x00e5b4a4}, /* U+5D24 [2000] */ - {0x8fa8d2, 0x00e5b4a6}, /* U+5D26 [2000] */ - {0x8fa8d3, 0x00e5b4b1}, /* U+5D31 [2000] */ - {0x8fa8d4, 0x00e5b4b9}, /* U+5D39 [2000] */ - {0x8fa8d5, 0x00e5b582}, /* U+5D42 [2000] */ - {0x8fa8d6, 0x00e39fa8}, /* U+37E8 [2000] */ - {0x8fa8d7, 0x00e5b5a1}, /* U+5D61 [2000] */ - {0x8fa8d8, 0x00e5b5aa}, /* U+5D6A [2000] */ - {0x8fa8d9, 0x00e39fb4}, /* U+37F4 [2000] */ - {0x8fa8da, 0x00e5b5b0}, /* U+5D70 [2000] */ + {0x8fa8cc, 0xe5b486}, /* U+5D06 [2000] */ + {0x8fa8cd, 0xe5b490}, /* U+5D10 [2000] */ + {0x8fa8ce, 0xe5b4ab}, /* U+5D2B [2000] */ + {0x8fa8cf, 0xe5b49d}, /* U+5D1D [2000] */ + {0x8fa8d0, 0xe5b4a0}, /* U+5D20 [2000] */ + {0x8fa8d1, 0xe5b4a4}, /* U+5D24 [2000] */ + {0x8fa8d2, 0xe5b4a6}, /* U+5D26 [2000] */ + {0x8fa8d3, 0xe5b4b1}, /* U+5D31 [2000] */ + {0x8fa8d4, 0xe5b4b9}, /* U+5D39 [2000] */ + {0x8fa8d5, 0xe5b582}, /* U+5D42 [2000] */ + {0x8fa8d6, 0xe39fa8}, /* U+37E8 [2000] */ + {0x8fa8d7, 0xe5b5a1}, /* U+5D61 [2000] */ + {0x8fa8d8, 0xe5b5aa}, /* U+5D6A [2000] */ + {0x8fa8d9, 0xe39fb4}, /* U+37F4 [2000] */ + {0x8fa8da, 0xe5b5b0}, /* U+5D70 [2000] */ {0x8fa8db, 0xf0a1bc9e}, /* U+21F1E [2000] [Unicode3.1] */ - {0x8fa8dc, 0x00e39fbd}, /* U+37FD [2000] */ - {0x8fa8dd, 0x00e5b688}, /* U+5D88 [2000] */ - {0x8fa8de, 0x00e3a080}, /* U+3800 [2000] */ - {0x8fa8df, 0x00e5b692}, /* U+5D92 [2000] */ - {0x8fa8e0, 0x00e5b694}, /* U+5D94 [2000] */ - {0x8fa8e1, 0x00e5b697}, /* U+5D97 [2000] */ - {0x8fa8e2, 0x00e5b699}, /* U+5D99 [2000] */ - {0x8fa8e3, 0x00e5b6b0}, /* U+5DB0 [2000] */ - {0x8fa8e4, 0x00e5b6b2}, /* U+5DB2 [2000] */ - {0x8fa8e5, 0x00e5b6b4}, /* U+5DB4 [2000] */ + {0x8fa8dc, 0xe39fbd}, /* U+37FD [2000] */ + {0x8fa8dd, 0xe5b688}, /* U+5D88 [2000] */ + {0x8fa8de, 0xe3a080}, /* U+3800 [2000] */ + {0x8fa8df, 0xe5b692}, /* U+5D92 [2000] */ + {0x8fa8e0, 0xe5b694}, /* U+5D94 [2000] */ + {0x8fa8e1, 0xe5b697}, /* U+5D97 [2000] */ + {0x8fa8e2, 0xe5b699}, /* U+5D99 [2000] */ + {0x8fa8e3, 0xe5b6b0}, /* U+5DB0 [2000] */ + {0x8fa8e4, 0xe5b6b2}, /* U+5DB2 [2000] */ + {0x8fa8e5, 0xe5b6b4}, /* U+5DB4 [2000] */ {0x8fa8e6, 0xf0a1bdb6}, /* U+21F76 [2000] [Unicode3.1] */ - {0x8fa8e7, 0x00e5b6b9}, /* U+5DB9 [2000] */ - {0x8fa8e8, 0x00e5b791}, /* U+5DD1 [2000] */ - {0x8fa8e9, 0x00e5b797}, /* U+5DD7 [2000] */ - {0x8fa8ea, 0x00e5b798}, /* U+5DD8 [2000] */ - {0x8fa8eb, 0x00e5b7a0}, /* U+5DE0 [2000] */ + {0x8fa8e7, 0xe5b6b9}, /* U+5DB9 [2000] */ + {0x8fa8e8, 0xe5b791}, /* U+5DD1 [2000] */ + {0x8fa8e9, 0xe5b797}, /* U+5DD7 [2000] */ + {0x8fa8ea, 0xe5b798}, /* U+5DD8 [2000] */ + {0x8fa8eb, 0xe5b7a0}, /* U+5DE0 [2000] */ {0x8fa8ec, 0xf0a1bfba}, /* U+21FFA [2000] [Unicode3.1] */ - {0x8fa8ed, 0x00e5b7a4}, /* U+5DE4 [2000] */ - {0x8fa8ee, 0x00e5b7a9}, /* U+5DE9 [2000] */ - {0x8fa8ef, 0x00e3a0af}, /* U+382F [2000] */ - {0x8fa8f0, 0x00e5b880}, /* U+5E00 [2000] */ - {0x8fa8f1, 0x00e3a0b6}, /* U+3836 [2000] */ - {0x8fa8f2, 0x00e5b892}, /* U+5E12 [2000] */ - {0x8fa8f3, 0x00e5b895}, /* U+5E15 [2000] */ - {0x8fa8f4, 0x00e3a180}, /* U+3840 [2000] */ - {0x8fa8f5, 0x00e5b89f}, /* U+5E1F [2000] */ - {0x8fa8f6, 0x00e5b8ae}, /* U+5E2E [2000] */ - {0x8fa8f7, 0x00e5b8be}, /* U+5E3E [2000] */ - {0x8fa8f8, 0x00e5b989}, /* U+5E49 [2000] */ - {0x8fa8f9, 0x00e3a19c}, /* U+385C [2000] */ - {0x8fa8fa, 0x00e5b996}, /* U+5E56 [2000] */ - {0x8fa8fb, 0x00e3a1a1}, /* U+3861 [2000] */ - {0x8fa8fc, 0x00e5b9ab}, /* U+5E6B [2000] */ - {0x8fa8fd, 0x00e5b9ac}, /* U+5E6C [2000] */ - {0x8fa8fe, 0x00e5b9ad}, /* U+5E6D [2000] */ - {0x8faca1, 0x00e5b9ae}, /* U+5E6E [2000] */ + {0x8fa8ed, 0xe5b7a4}, /* U+5DE4 [2000] */ + {0x8fa8ee, 0xe5b7a9}, /* U+5DE9 [2000] */ + {0x8fa8ef, 0xe3a0af}, /* U+382F [2000] */ + {0x8fa8f0, 0xe5b880}, /* U+5E00 [2000] */ + {0x8fa8f1, 0xe3a0b6}, /* U+3836 [2000] */ + {0x8fa8f2, 0xe5b892}, /* U+5E12 [2000] */ + {0x8fa8f3, 0xe5b895}, /* U+5E15 [2000] */ + {0x8fa8f4, 0xe3a180}, /* U+3840 [2000] */ + {0x8fa8f5, 0xe5b89f}, /* U+5E1F [2000] */ + {0x8fa8f6, 0xe5b8ae}, /* U+5E2E [2000] */ + {0x8fa8f7, 0xe5b8be}, /* U+5E3E [2000] */ + {0x8fa8f8, 0xe5b989}, /* U+5E49 [2000] */ + {0x8fa8f9, 0xe3a19c}, /* U+385C [2000] */ + {0x8fa8fa, 0xe5b996}, /* U+5E56 [2000] */ + {0x8fa8fb, 0xe3a1a1}, /* U+3861 [2000] */ + {0x8fa8fc, 0xe5b9ab}, /* U+5E6B [2000] */ + {0x8fa8fd, 0xe5b9ac}, /* U+5E6C [2000] */ + {0x8fa8fe, 0xe5b9ad}, /* U+5E6D [2000] */ + {0x8faca1, 0xe5b9ae}, /* U+5E6E [2000] */ {0x8faca2, 0xf0a285bb}, /* U+2217B [2000] [Unicode3.1] */ - {0x8faca3, 0x00e5baa5}, /* U+5EA5 [2000] */ - {0x8faca4, 0x00e5baaa}, /* U+5EAA [2000] */ - {0x8faca5, 0x00e5baac}, /* U+5EAC [2000] */ - {0x8faca6, 0x00e5bab9}, /* U+5EB9 [2000] */ - {0x8faca7, 0x00e5babf}, /* U+5EBF [2000] */ - {0x8faca8, 0x00e5bb86}, /* U+5EC6 [2000] */ - {0x8faca9, 0x00e5bb92}, /* U+5ED2 [2000] */ - {0x8facaa, 0x00e5bb99}, /* U+5ED9 [2000] */ + {0x8faca3, 0xe5baa5}, /* U+5EA5 [2000] */ + {0x8faca4, 0xe5baaa}, /* U+5EAA [2000] */ + {0x8faca5, 0xe5baac}, /* U+5EAC [2000] */ + {0x8faca6, 0xe5bab9}, /* U+5EB9 [2000] */ + {0x8faca7, 0xe5babf}, /* U+5EBF [2000] */ + {0x8faca8, 0xe5bb86}, /* U+5EC6 [2000] */ + {0x8faca9, 0xe5bb92}, /* U+5ED2 [2000] */ + {0x8facaa, 0xe5bb99}, /* U+5ED9 [2000] */ {0x8facab, 0xf0a28c9e}, /* U+2231E [2000] [Unicode3.1] */ - {0x8facac, 0x00e5bbbd}, /* U+5EFD [2000] */ - {0x8facad, 0x00e5bc88}, /* U+5F08 [2000] */ - {0x8facae, 0x00e5bc8e}, /* U+5F0E [2000] */ - {0x8facaf, 0x00e5bc9c}, /* U+5F1C [2000] */ + {0x8facac, 0xe5bbbd}, /* U+5EFD [2000] */ + {0x8facad, 0xe5bc88}, /* U+5F08 [2000] */ + {0x8facae, 0xe5bc8e}, /* U+5F0E [2000] */ + {0x8facaf, 0xe5bc9c}, /* U+5F1C [2000] */ {0x8facb0, 0xf0a28ead}, /* U+223AD [2000] [Unicode3.1] */ - {0x8facb1, 0x00e5bc9e}, /* U+5F1E [2000] */ - {0x8facb2, 0x00e5bd87}, /* U+5F47 [2000] */ - {0x8facb3, 0x00e5bda3}, /* U+5F63 [2000] */ - {0x8facb4, 0x00e5bdb2}, /* U+5F72 [2000] */ - {0x8facb5, 0x00e5bdbe}, /* U+5F7E [2000] */ - {0x8facb6, 0x00e5be8f}, /* U+5F8F [2000] */ - {0x8facb7, 0x00e5bea2}, /* U+5FA2 [2000] */ - {0x8facb8, 0x00e5bea4}, /* U+5FA4 [2000] */ - {0x8facb9, 0x00e5beb8}, /* U+5FB8 [2000] */ - {0x8facba, 0x00e5bf84}, /* U+5FC4 [2000] */ - {0x8facbb, 0x00e3a3ba}, /* U+38FA [2000] */ - {0x8facbc, 0x00e5bf87}, /* U+5FC7 [2000] */ - {0x8facbd, 0x00e5bf8b}, /* U+5FCB [2000] */ - {0x8facbe, 0x00e5bf92}, /* U+5FD2 [2000] */ - {0x8facbf, 0x00e5bf93}, /* U+5FD3 [2000] */ - {0x8facc0, 0x00e5bf94}, /* U+5FD4 [2000] */ - {0x8facc1, 0x00e5bfa2}, /* U+5FE2 [2000] */ - {0x8facc2, 0x00e5bfae}, /* U+5FEE [2000] */ - {0x8facc3, 0x00e5bfaf}, /* U+5FEF [2000] */ - {0x8facc4, 0x00e5bfb3}, /* U+5FF3 [2000] */ - {0x8facc5, 0x00e5bfbc}, /* U+5FFC [2000] */ - {0x8facc6, 0x00e3a497}, /* U+3917 [2000] */ - {0x8facc7, 0x00e68097}, /* U+6017 [2000] */ - {0x8facc8, 0x00e680a2}, /* U+6022 [2000] */ - {0x8facc9, 0x00e680a4}, /* U+6024 [2000] */ - {0x8facca, 0x00e3a49a}, /* U+391A [2000] */ - {0x8faccb, 0x00e6818c}, /* U+604C [2000] */ - {0x8faccc, 0x00e681bf}, /* U+607F [2000] */ - {0x8faccd, 0x00e6828a}, /* U+608A [2000] */ - {0x8facce, 0x00e68295}, /* U+6095 [2000] */ - {0x8faccf, 0x00e682a8}, /* U+60A8 [2000] */ + {0x8facb1, 0xe5bc9e}, /* U+5F1E [2000] */ + {0x8facb2, 0xe5bd87}, /* U+5F47 [2000] */ + {0x8facb3, 0xe5bda3}, /* U+5F63 [2000] */ + {0x8facb4, 0xe5bdb2}, /* U+5F72 [2000] */ + {0x8facb5, 0xe5bdbe}, /* U+5F7E [2000] */ + {0x8facb6, 0xe5be8f}, /* U+5F8F [2000] */ + {0x8facb7, 0xe5bea2}, /* U+5FA2 [2000] */ + {0x8facb8, 0xe5bea4}, /* U+5FA4 [2000] */ + {0x8facb9, 0xe5beb8}, /* U+5FB8 [2000] */ + {0x8facba, 0xe5bf84}, /* U+5FC4 [2000] */ + {0x8facbb, 0xe3a3ba}, /* U+38FA [2000] */ + {0x8facbc, 0xe5bf87}, /* U+5FC7 [2000] */ + {0x8facbd, 0xe5bf8b}, /* U+5FCB [2000] */ + {0x8facbe, 0xe5bf92}, /* U+5FD2 [2000] */ + {0x8facbf, 0xe5bf93}, /* U+5FD3 [2000] */ + {0x8facc0, 0xe5bf94}, /* U+5FD4 [2000] */ + {0x8facc1, 0xe5bfa2}, /* U+5FE2 [2000] */ + {0x8facc2, 0xe5bfae}, /* U+5FEE [2000] */ + {0x8facc3, 0xe5bfaf}, /* U+5FEF [2000] */ + {0x8facc4, 0xe5bfb3}, /* U+5FF3 [2000] */ + {0x8facc5, 0xe5bfbc}, /* U+5FFC [2000] */ + {0x8facc6, 0xe3a497}, /* U+3917 [2000] */ + {0x8facc7, 0xe68097}, /* U+6017 [2000] */ + {0x8facc8, 0xe680a2}, /* U+6022 [2000] */ + {0x8facc9, 0xe680a4}, /* U+6024 [2000] */ + {0x8facca, 0xe3a49a}, /* U+391A [2000] */ + {0x8faccb, 0xe6818c}, /* U+604C [2000] */ + {0x8faccc, 0xe681bf}, /* U+607F [2000] */ + {0x8faccd, 0xe6828a}, /* U+608A [2000] */ + {0x8facce, 0xe68295}, /* U+6095 [2000] */ + {0x8faccf, 0xe682a8}, /* U+60A8 [2000] */ {0x8facd0, 0xf0a29bb3}, /* U+226F3 [2000] [Unicode3.1] */ - {0x8facd1, 0x00e682b0}, /* U+60B0 [2000] */ - {0x8facd2, 0x00e682b1}, /* U+60B1 [2000] */ - {0x8facd3, 0x00e682be}, /* U+60BE [2000] */ - {0x8facd4, 0x00e68388}, /* U+60C8 [2000] */ - {0x8facd5, 0x00e68399}, /* U+60D9 [2000] */ - {0x8facd6, 0x00e6839b}, /* U+60DB [2000] */ - {0x8facd7, 0x00e683ae}, /* U+60EE [2000] */ - {0x8facd8, 0x00e683b2}, /* U+60F2 [2000] */ - {0x8facd9, 0x00e683b5}, /* U+60F5 [2000] */ - {0x8facda, 0x00e68490}, /* U+6110 [2000] */ - {0x8facdb, 0x00e68492}, /* U+6112 [2000] */ - {0x8facdc, 0x00e68493}, /* U+6113 [2000] */ - {0x8facdd, 0x00e68499}, /* U+6119 [2000] */ - {0x8facde, 0x00e6849e}, /* U+611E [2000] */ - {0x8facdf, 0x00e684ba}, /* U+613A [2000] */ - {0x8face0, 0x00e3a5af}, /* U+396F [2000] */ - {0x8face1, 0x00e68581}, /* U+6141 [2000] */ - {0x8face2, 0x00e68586}, /* U+6146 [2000] */ - {0x8face3, 0x00e685a0}, /* U+6160 [2000] */ - {0x8face4, 0x00e685bc}, /* U+617C [2000] */ + {0x8facd1, 0xe682b0}, /* U+60B0 [2000] */ + {0x8facd2, 0xe682b1}, /* U+60B1 [2000] */ + {0x8facd3, 0xe682be}, /* U+60BE [2000] */ + {0x8facd4, 0xe68388}, /* U+60C8 [2000] */ + {0x8facd5, 0xe68399}, /* U+60D9 [2000] */ + {0x8facd6, 0xe6839b}, /* U+60DB [2000] */ + {0x8facd7, 0xe683ae}, /* U+60EE [2000] */ + {0x8facd8, 0xe683b2}, /* U+60F2 [2000] */ + {0x8facd9, 0xe683b5}, /* U+60F5 [2000] */ + {0x8facda, 0xe68490}, /* U+6110 [2000] */ + {0x8facdb, 0xe68492}, /* U+6112 [2000] */ + {0x8facdc, 0xe68493}, /* U+6113 [2000] */ + {0x8facdd, 0xe68499}, /* U+6119 [2000] */ + {0x8facde, 0xe6849e}, /* U+611E [2000] */ + {0x8facdf, 0xe684ba}, /* U+613A [2000] */ + {0x8face0, 0xe3a5af}, /* U+396F [2000] */ + {0x8face1, 0xe68581}, /* U+6141 [2000] */ + {0x8face2, 0xe68586}, /* U+6146 [2000] */ + {0x8face3, 0xe685a0}, /* U+6160 [2000] */ + {0x8face4, 0xe685bc}, /* U+617C [2000] */ {0x8face5, 0xf0a2a19b}, /* U+2285B [2000] [Unicode3.1] */ - {0x8face6, 0x00e68692}, /* U+6192 [2000] */ - {0x8face7, 0x00e68693}, /* U+6193 [2000] */ - {0x8face8, 0x00e68697}, /* U+6197 [2000] */ - {0x8face9, 0x00e68698}, /* U+6198 [2000] */ - {0x8facea, 0x00e686a5}, /* U+61A5 [2000] */ - {0x8faceb, 0x00e686a8}, /* U+61A8 [2000] */ - {0x8facec, 0x00e686ad}, /* U+61AD [2000] */ + {0x8face6, 0xe68692}, /* U+6192 [2000] */ + {0x8face7, 0xe68693}, /* U+6193 [2000] */ + {0x8face8, 0xe68697}, /* U+6197 [2000] */ + {0x8face9, 0xe68698}, /* U+6198 [2000] */ + {0x8facea, 0xe686a5}, /* U+61A5 [2000] */ + {0x8faceb, 0xe686a8}, /* U+61A8 [2000] */ + {0x8facec, 0xe686ad}, /* U+61AD [2000] */ {0x8faced, 0xf0a2a2ab}, /* U+228AB [2000] [Unicode3.1] */ - {0x8facee, 0x00e68795}, /* U+61D5 [2000] */ - {0x8facef, 0x00e6879d}, /* U+61DD [2000] */ - {0x8facf0, 0x00e6879f}, /* U+61DF [2000] */ - {0x8facf1, 0x00e687b5}, /* U+61F5 [2000] */ + {0x8facee, 0xe68795}, /* U+61D5 [2000] */ + {0x8facef, 0xe6879d}, /* U+61DD [2000] */ + {0x8facf0, 0xe6879f}, /* U+61DF [2000] */ + {0x8facf1, 0xe687b5}, /* U+61F5 [2000] */ {0x8facf2, 0xf0a2a68f}, /* U+2298F [2000] [Unicode3.1] */ - {0x8facf3, 0x00e68895}, /* U+6215 [2000] */ - {0x8facf4, 0x00e688a3}, /* U+6223 [2000] */ - {0x8facf5, 0x00e688a9}, /* U+6229 [2000] */ - {0x8facf6, 0x00e68986}, /* U+6246 [2000] */ - {0x8facf7, 0x00e6898c}, /* U+624C [2000] */ - {0x8facf8, 0x00e68991}, /* U+6251 [2000] */ - {0x8facf9, 0x00e68992}, /* U+6252 [2000] */ - {0x8facfa, 0x00e689a1}, /* U+6261 [2000] */ - {0x8facfb, 0x00e689a4}, /* U+6264 [2000] */ - {0x8facfc, 0x00e689bb}, /* U+627B [2000] */ - {0x8facfd, 0x00e689ad}, /* U+626D [2000] */ - {0x8facfe, 0x00e689b3}, /* U+6273 [2000] */ - {0x8fada1, 0x00e68a99}, /* U+6299 [2000] */ - {0x8fada2, 0x00e68aa6}, /* U+62A6 [2000] */ - {0x8fada3, 0x00e68b95}, /* U+62D5 [2000] */ + {0x8facf3, 0xe68895}, /* U+6215 [2000] */ + {0x8facf4, 0xe688a3}, /* U+6223 [2000] */ + {0x8facf5, 0xe688a9}, /* U+6229 [2000] */ + {0x8facf6, 0xe68986}, /* U+6246 [2000] */ + {0x8facf7, 0xe6898c}, /* U+624C [2000] */ + {0x8facf8, 0xe68991}, /* U+6251 [2000] */ + {0x8facf9, 0xe68992}, /* U+6252 [2000] */ + {0x8facfa, 0xe689a1}, /* U+6261 [2000] */ + {0x8facfb, 0xe689a4}, /* U+6264 [2000] */ + {0x8facfc, 0xe689bb}, /* U+627B [2000] */ + {0x8facfd, 0xe689ad}, /* U+626D [2000] */ + {0x8facfe, 0xe689b3}, /* U+6273 [2000] */ + {0x8fada1, 0xe68a99}, /* U+6299 [2000] */ + {0x8fada2, 0xe68aa6}, /* U+62A6 [2000] */ + {0x8fada3, 0xe68b95}, /* U+62D5 [2000] */ {0x8fada4, 0xf0a2aab8}, /* U+22AB8 [2000] [Unicode3.1] */ - {0x8fada5, 0x00e68bbd}, /* U+62FD [2000] */ - {0x8fada6, 0x00e68c83}, /* U+6303 [2000] */ - {0x8fada7, 0x00e68c8d}, /* U+630D [2000] */ - {0x8fada8, 0x00e68c90}, /* U+6310 [2000] */ + {0x8fada5, 0xe68bbd}, /* U+62FD [2000] */ + {0x8fada6, 0xe68c83}, /* U+6303 [2000] */ + {0x8fada7, 0xe68c8d}, /* U+630D [2000] */ + {0x8fada8, 0xe68c90}, /* U+6310 [2000] */ {0x8fada9, 0xf0a2ad8f}, /* U+22B4F [2000] [Unicode3.1] */ {0x8fadaa, 0xf0a2ad90}, /* U+22B50 [2000] [Unicode3.1] */ - {0x8fadab, 0x00e68cb2}, /* U+6332 [2000] */ - {0x8fadac, 0x00e68cb5}, /* U+6335 [2000] */ - {0x8fadad, 0x00e68cbb}, /* U+633B [2000] */ - {0x8fadae, 0x00e68cbc}, /* U+633C [2000] */ - {0x8fadaf, 0x00e68d81}, /* U+6341 [2000] */ - {0x8fadb0, 0x00e68d84}, /* U+6344 [2000] */ - {0x8fadb1, 0x00e68d8e}, /* U+634E [2000] */ + {0x8fadab, 0xe68cb2}, /* U+6332 [2000] */ + {0x8fadac, 0xe68cb5}, /* U+6335 [2000] */ + {0x8fadad, 0xe68cbb}, /* U+633B [2000] */ + {0x8fadae, 0xe68cbc}, /* U+633C [2000] */ + {0x8fadaf, 0xe68d81}, /* U+6341 [2000] */ + {0x8fadb0, 0xe68d84}, /* U+6344 [2000] */ + {0x8fadb1, 0xe68d8e}, /* U+634E [2000] */ {0x8fadb2, 0xf0a2ad86}, /* U+22B46 [2000] [Unicode3.1] */ - {0x8fadb3, 0x00e68d99}, /* U+6359 [2000] */ + {0x8fadb3, 0xe68d99}, /* U+6359 [2000] */ {0x8fadb4, 0xf0a2b09d}, /* U+22C1D [2000] [Unicode3.1] */ {0x8fadb5, 0xf0a2aea6}, /* U+22BA6 [2000] [Unicode3.1] */ - {0x8fadb6, 0x00e68dac}, /* U+636C [2000] */ - {0x8fadb7, 0x00e68e84}, /* U+6384 [2000] */ - {0x8fadb8, 0x00e68e99}, /* U+6399 [2000] */ + {0x8fadb6, 0xe68dac}, /* U+636C [2000] */ + {0x8fadb7, 0xe68e84}, /* U+6384 [2000] */ + {0x8fadb8, 0xe68e99}, /* U+6399 [2000] */ {0x8fadb9, 0xf0a2b0a4}, /* U+22C24 [2000] [Unicode3.1] */ - {0x8fadba, 0x00e68e94}, /* U+6394 [2000] */ - {0x8fadbb, 0x00e68ebd}, /* U+63BD [2000] */ - {0x8fadbc, 0x00e68fb7}, /* U+63F7 [2000] */ - {0x8fadbd, 0x00e68f94}, /* U+63D4 [2000] */ - {0x8fadbe, 0x00e68f95}, /* U+63D5 [2000] */ - {0x8fadbf, 0x00e68f9c}, /* U+63DC [2000] */ - {0x8fadc0, 0x00e68fa0}, /* U+63E0 [2000] */ - {0x8fadc1, 0x00e68fab}, /* U+63EB [2000] */ - {0x8fadc2, 0x00e68fac}, /* U+63EC [2000] */ - {0x8fadc3, 0x00e68fb2}, /* U+63F2 [2000] */ - {0x8fadc4, 0x00e69089}, /* U+6409 [2000] */ - {0x8fadc5, 0x00e6909e}, /* U+641E [2000] */ - {0x8fadc6, 0x00e690a5}, /* U+6425 [2000] */ - {0x8fadc7, 0x00e690a9}, /* U+6429 [2000] */ - {0x8fadc8, 0x00e690af}, /* U+642F [2000] */ - {0x8fadc9, 0x00e6919a}, /* U+645A [2000] */ - {0x8fadca, 0x00e6919b}, /* U+645B [2000] */ - {0x8fadcb, 0x00e6919d}, /* U+645D [2000] */ - {0x8fadcc, 0x00e691b3}, /* U+6473 [2000] */ - {0x8fadcd, 0x00e691bd}, /* U+647D [2000] */ - {0x8fadce, 0x00e69287}, /* U+6487 [2000] */ - {0x8fadcf, 0x00e69291}, /* U+6491 [2000] */ - {0x8fadd0, 0x00e6929d}, /* U+649D [2000] */ - {0x8fadd1, 0x00e6929f}, /* U+649F [2000] */ - {0x8fadd2, 0x00e6938b}, /* U+64CB [2000] */ - {0x8fadd3, 0x00e6938c}, /* U+64CC [2000] */ - {0x8fadd4, 0x00e69395}, /* U+64D5 [2000] */ - {0x8fadd5, 0x00e69397}, /* U+64D7 [2000] */ + {0x8fadba, 0xe68e94}, /* U+6394 [2000] */ + {0x8fadbb, 0xe68ebd}, /* U+63BD [2000] */ + {0x8fadbc, 0xe68fb7}, /* U+63F7 [2000] */ + {0x8fadbd, 0xe68f94}, /* U+63D4 [2000] */ + {0x8fadbe, 0xe68f95}, /* U+63D5 [2000] */ + {0x8fadbf, 0xe68f9c}, /* U+63DC [2000] */ + {0x8fadc0, 0xe68fa0}, /* U+63E0 [2000] */ + {0x8fadc1, 0xe68fab}, /* U+63EB [2000] */ + {0x8fadc2, 0xe68fac}, /* U+63EC [2000] */ + {0x8fadc3, 0xe68fb2}, /* U+63F2 [2000] */ + {0x8fadc4, 0xe69089}, /* U+6409 [2000] */ + {0x8fadc5, 0xe6909e}, /* U+641E [2000] */ + {0x8fadc6, 0xe690a5}, /* U+6425 [2000] */ + {0x8fadc7, 0xe690a9}, /* U+6429 [2000] */ + {0x8fadc8, 0xe690af}, /* U+642F [2000] */ + {0x8fadc9, 0xe6919a}, /* U+645A [2000] */ + {0x8fadca, 0xe6919b}, /* U+645B [2000] */ + {0x8fadcb, 0xe6919d}, /* U+645D [2000] */ + {0x8fadcc, 0xe691b3}, /* U+6473 [2000] */ + {0x8fadcd, 0xe691bd}, /* U+647D [2000] */ + {0x8fadce, 0xe69287}, /* U+6487 [2000] */ + {0x8fadcf, 0xe69291}, /* U+6491 [2000] */ + {0x8fadd0, 0xe6929d}, /* U+649D [2000] */ + {0x8fadd1, 0xe6929f}, /* U+649F [2000] */ + {0x8fadd2, 0xe6938b}, /* U+64CB [2000] */ + {0x8fadd3, 0xe6938c}, /* U+64CC [2000] */ + {0x8fadd4, 0xe69395}, /* U+64D5 [2000] */ + {0x8fadd5, 0xe69397}, /* U+64D7 [2000] */ {0x8fadd6, 0xf0a2b7a1}, /* U+22DE1 [2000] [Unicode3.1] */ - {0x8fadd7, 0x00e693a4}, /* U+64E4 [2000] */ - {0x8fadd8, 0x00e693a5}, /* U+64E5 [2000] */ - {0x8fadd9, 0x00e693bf}, /* U+64FF [2000] */ - {0x8fadda, 0x00e69484}, /* U+6504 [2000] */ - {0x8faddb, 0x00e3a9ae}, /* U+3A6E [2000] */ - {0x8faddc, 0x00e6948f}, /* U+650F [2000] */ - {0x8faddd, 0x00e69494}, /* U+6514 [2000] */ - {0x8fadde, 0x00e69496}, /* U+6516 [2000] */ - {0x8faddf, 0x00e3a9b3}, /* U+3A73 [2000] */ - {0x8fade0, 0x00e6949e}, /* U+651E [2000] */ - {0x8fade1, 0x00e694b2}, /* U+6532 [2000] */ - {0x8fade2, 0x00e69584}, /* U+6544 [2000] */ - {0x8fade3, 0x00e69594}, /* U+6554 [2000] */ - {0x8fade4, 0x00e695ab}, /* U+656B [2000] */ - {0x8fade5, 0x00e695ba}, /* U+657A [2000] */ - {0x8fade6, 0x00e69681}, /* U+6581 [2000] */ - {0x8fade7, 0x00e69684}, /* U+6584 [2000] */ - {0x8fade8, 0x00e69685}, /* U+6585 [2000] */ - {0x8fade9, 0x00e6968a}, /* U+658A [2000] */ - {0x8fadea, 0x00e696b2}, /* U+65B2 [2000] */ - {0x8fadeb, 0x00e696b5}, /* U+65B5 [2000] */ - {0x8fadec, 0x00e696b8}, /* U+65B8 [2000] */ - {0x8faded, 0x00e696bf}, /* U+65BF [2000] */ - {0x8fadee, 0x00e69782}, /* U+65C2 [2000] */ - {0x8fadef, 0x00e69789}, /* U+65C9 [2000] */ - {0x8fadf0, 0x00e69794}, /* U+65D4 [2000] */ - {0x8fadf1, 0x00e3ab96}, /* U+3AD6 [2000] */ - {0x8fadf2, 0x00e697b2}, /* U+65F2 [2000] */ - {0x8fadf3, 0x00e697b9}, /* U+65F9 [2000] */ - {0x8fadf4, 0x00e697bc}, /* U+65FC [2000] */ - {0x8fadf5, 0x00e69884}, /* U+6604 [2000] */ - {0x8fadf6, 0x00e69888}, /* U+6608 [2000] */ - {0x8fadf7, 0x00e698a1}, /* U+6621 [2000] */ - {0x8fadf8, 0x00e698aa}, /* U+662A [2000] */ - {0x8fadf9, 0x00e69985}, /* U+6645 [2000] */ - {0x8fadfa, 0x00e69991}, /* U+6651 [2000] */ - {0x8fadfb, 0x00e6998e}, /* U+664E [2000] */ - {0x8fadfc, 0x00e3abaa}, /* U+3AEA [2000] */ + {0x8fadd7, 0xe693a4}, /* U+64E4 [2000] */ + {0x8fadd8, 0xe693a5}, /* U+64E5 [2000] */ + {0x8fadd9, 0xe693bf}, /* U+64FF [2000] */ + {0x8fadda, 0xe69484}, /* U+6504 [2000] */ + {0x8faddb, 0xe3a9ae}, /* U+3A6E [2000] */ + {0x8faddc, 0xe6948f}, /* U+650F [2000] */ + {0x8faddd, 0xe69494}, /* U+6514 [2000] */ + {0x8fadde, 0xe69496}, /* U+6516 [2000] */ + {0x8faddf, 0xe3a9b3}, /* U+3A73 [2000] */ + {0x8fade0, 0xe6949e}, /* U+651E [2000] */ + {0x8fade1, 0xe694b2}, /* U+6532 [2000] */ + {0x8fade2, 0xe69584}, /* U+6544 [2000] */ + {0x8fade3, 0xe69594}, /* U+6554 [2000] */ + {0x8fade4, 0xe695ab}, /* U+656B [2000] */ + {0x8fade5, 0xe695ba}, /* U+657A [2000] */ + {0x8fade6, 0xe69681}, /* U+6581 [2000] */ + {0x8fade7, 0xe69684}, /* U+6584 [2000] */ + {0x8fade8, 0xe69685}, /* U+6585 [2000] */ + {0x8fade9, 0xe6968a}, /* U+658A [2000] */ + {0x8fadea, 0xe696b2}, /* U+65B2 [2000] */ + {0x8fadeb, 0xe696b5}, /* U+65B5 [2000] */ + {0x8fadec, 0xe696b8}, /* U+65B8 [2000] */ + {0x8faded, 0xe696bf}, /* U+65BF [2000] */ + {0x8fadee, 0xe69782}, /* U+65C2 [2000] */ + {0x8fadef, 0xe69789}, /* U+65C9 [2000] */ + {0x8fadf0, 0xe69794}, /* U+65D4 [2000] */ + {0x8fadf1, 0xe3ab96}, /* U+3AD6 [2000] */ + {0x8fadf2, 0xe697b2}, /* U+65F2 [2000] */ + {0x8fadf3, 0xe697b9}, /* U+65F9 [2000] */ + {0x8fadf4, 0xe697bc}, /* U+65FC [2000] */ + {0x8fadf5, 0xe69884}, /* U+6604 [2000] */ + {0x8fadf6, 0xe69888}, /* U+6608 [2000] */ + {0x8fadf7, 0xe698a1}, /* U+6621 [2000] */ + {0x8fadf8, 0xe698aa}, /* U+662A [2000] */ + {0x8fadf9, 0xe69985}, /* U+6645 [2000] */ + {0x8fadfa, 0xe69991}, /* U+6651 [2000] */ + {0x8fadfb, 0xe6998e}, /* U+664E [2000] */ + {0x8fadfc, 0xe3abaa}, /* U+3AEA [2000] */ {0x8fadfd, 0xf0a38783}, /* U+231C3 [2000] [Unicode3.1] */ - {0x8fadfe, 0x00e69997}, /* U+6657 [2000] */ - {0x8faea1, 0x00e6999b}, /* U+665B [2000] */ - {0x8faea2, 0x00e699a3}, /* U+6663 [2000] */ + {0x8fadfe, 0xe69997}, /* U+6657 [2000] */ + {0x8faea1, 0xe6999b}, /* U+665B [2000] */ + {0x8faea2, 0xe699a3}, /* U+6663 [2000] */ {0x8faea3, 0xf0a387b5}, /* U+231F5 [2000] [Unicode3.1] */ {0x8faea4, 0xf0a386b6}, /* U+231B6 [2000] [Unicode3.1] */ - {0x8faea5, 0x00e699aa}, /* U+666A [2000] */ - {0x8faea6, 0x00e699ab}, /* U+666B [2000] */ - {0x8faea7, 0x00e699ac}, /* U+666C [2000] */ - {0x8faea8, 0x00e699ad}, /* U+666D [2000] */ - {0x8faea9, 0x00e699bb}, /* U+667B [2000] */ - {0x8faeaa, 0x00e69a80}, /* U+6680 [2000] */ - {0x8faeab, 0x00e69a90}, /* U+6690 [2000] */ - {0x8faeac, 0x00e69a92}, /* U+6692 [2000] */ - {0x8faead, 0x00e69a99}, /* U+6699 [2000] */ - {0x8faeae, 0x00e3ac8e}, /* U+3B0E [2000] */ - {0x8faeaf, 0x00e69aad}, /* U+66AD [2000] */ - {0x8faeb0, 0x00e69ab1}, /* U+66B1 [2000] */ - {0x8faeb1, 0x00e69ab5}, /* U+66B5 [2000] */ - {0x8faeb2, 0x00e3ac9a}, /* U+3B1A [2000] */ - {0x8faeb3, 0x00e69abf}, /* U+66BF [2000] */ - {0x8faeb4, 0x00e3ac9c}, /* U+3B1C [2000] */ - {0x8faeb5, 0x00e69bac}, /* U+66EC [2000] */ - {0x8faeb6, 0x00e3ab97}, /* U+3AD7 [2000] */ - {0x8faeb7, 0x00e69c81}, /* U+6701 [2000] */ - {0x8faeb8, 0x00e69c85}, /* U+6705 [2000] */ - {0x8faeb9, 0x00e69c92}, /* U+6712 [2000] */ + {0x8faea5, 0xe699aa}, /* U+666A [2000] */ + {0x8faea6, 0xe699ab}, /* U+666B [2000] */ + {0x8faea7, 0xe699ac}, /* U+666C [2000] */ + {0x8faea8, 0xe699ad}, /* U+666D [2000] */ + {0x8faea9, 0xe699bb}, /* U+667B [2000] */ + {0x8faeaa, 0xe69a80}, /* U+6680 [2000] */ + {0x8faeab, 0xe69a90}, /* U+6690 [2000] */ + {0x8faeac, 0xe69a92}, /* U+6692 [2000] */ + {0x8faead, 0xe69a99}, /* U+6699 [2000] */ + {0x8faeae, 0xe3ac8e}, /* U+3B0E [2000] */ + {0x8faeaf, 0xe69aad}, /* U+66AD [2000] */ + {0x8faeb0, 0xe69ab1}, /* U+66B1 [2000] */ + {0x8faeb1, 0xe69ab5}, /* U+66B5 [2000] */ + {0x8faeb2, 0xe3ac9a}, /* U+3B1A [2000] */ + {0x8faeb3, 0xe69abf}, /* U+66BF [2000] */ + {0x8faeb4, 0xe3ac9c}, /* U+3B1C [2000] */ + {0x8faeb5, 0xe69bac}, /* U+66EC [2000] */ + {0x8faeb6, 0xe3ab97}, /* U+3AD7 [2000] */ + {0x8faeb7, 0xe69c81}, /* U+6701 [2000] */ + {0x8faeb8, 0xe69c85}, /* U+6705 [2000] */ + {0x8faeb9, 0xe69c92}, /* U+6712 [2000] */ {0x8faeba, 0xf0a38db2}, /* U+23372 [2000] [Unicode3.1] */ - {0x8faebb, 0x00e69c99}, /* U+6719 [2000] */ + {0x8faebb, 0xe69c99}, /* U+6719 [2000] */ {0x8faebc, 0xf0a38f93}, /* U+233D3 [2000] [Unicode3.1] */ {0x8faebd, 0xf0a38f92}, /* U+233D2 [2000] [Unicode3.1] */ - {0x8faebe, 0x00e69d8c}, /* U+674C [2000] */ - {0x8faebf, 0x00e69d8d}, /* U+674D [2000] */ - {0x8faec0, 0x00e69d94}, /* U+6754 [2000] */ - {0x8faec1, 0x00e69d9d}, /* U+675D [2000] */ + {0x8faebe, 0xe69d8c}, /* U+674C [2000] */ + {0x8faebf, 0xe69d8d}, /* U+674D [2000] */ + {0x8faec0, 0xe69d94}, /* U+6754 [2000] */ + {0x8faec1, 0xe69d9d}, /* U+675D [2000] */ {0x8faec2, 0xf0a38f90}, /* U+233D0 [2000] [Unicode3.1] */ {0x8faec3, 0xf0a38fa4}, /* U+233E4 [2000] [Unicode3.1] */ {0x8faec4, 0xf0a38f95}, /* U+233D5 [2000] [Unicode3.1] */ - {0x8faec5, 0x00e69db4}, /* U+6774 [2000] */ - {0x8faec6, 0x00e69db6}, /* U+6776 [2000] */ + {0x8faec5, 0xe69db4}, /* U+6774 [2000] */ + {0x8faec6, 0xe69db6}, /* U+6776 [2000] */ {0x8faec7, 0xf0a38f9a}, /* U+233DA [2000] [Unicode3.1] */ - {0x8faec8, 0x00e69e92}, /* U+6792 [2000] */ + {0x8faec8, 0xe69e92}, /* U+6792 [2000] */ {0x8faec9, 0xf0a38f9f}, /* U+233DF [2000] [Unicode3.1] */ - {0x8faeca, 0x00e88da3}, /* U+8363 [2000] */ - {0x8faecb, 0x00e6a090}, /* U+6810 [2000] */ - {0x8faecc, 0x00e69eb0}, /* U+67B0 [2000] */ - {0x8faecd, 0x00e69eb2}, /* U+67B2 [2000] */ - {0x8faece, 0x00e69f83}, /* U+67C3 [2000] */ - {0x8faecf, 0x00e69f88}, /* U+67C8 [2000] */ - {0x8faed0, 0x00e69f92}, /* U+67D2 [2000] */ - {0x8faed1, 0x00e69f99}, /* U+67D9 [2000] */ - {0x8faed2, 0x00e69f9b}, /* U+67DB [2000] */ - {0x8faed3, 0x00e69fb0}, /* U+67F0 [2000] */ - {0x8faed4, 0x00e69fb7}, /* U+67F7 [2000] */ + {0x8faeca, 0xe88da3}, /* U+8363 [2000] */ + {0x8faecb, 0xe6a090}, /* U+6810 [2000] */ + {0x8faecc, 0xe69eb0}, /* U+67B0 [2000] */ + {0x8faecd, 0xe69eb2}, /* U+67B2 [2000] */ + {0x8faece, 0xe69f83}, /* U+67C3 [2000] */ + {0x8faecf, 0xe69f88}, /* U+67C8 [2000] */ + {0x8faed0, 0xe69f92}, /* U+67D2 [2000] */ + {0x8faed1, 0xe69f99}, /* U+67D9 [2000] */ + {0x8faed2, 0xe69f9b}, /* U+67DB [2000] */ + {0x8faed3, 0xe69fb0}, /* U+67F0 [2000] */ + {0x8faed4, 0xe69fb7}, /* U+67F7 [2000] */ {0x8faed5, 0xf0a3918a}, /* U+2344A [2000] [Unicode3.1] */ {0x8faed6, 0xf0a39191}, /* U+23451 [2000] [Unicode3.1] */ {0x8faed7, 0xf0a3918b}, /* U+2344B [2000] [Unicode3.1] */ - {0x8faed8, 0x00e6a098}, /* U+6818 [2000] */ - {0x8faed9, 0x00e6a09f}, /* U+681F [2000] */ - {0x8faeda, 0x00e6a0ad}, /* U+682D [2000] */ + {0x8faed8, 0xe6a098}, /* U+6818 [2000] */ + {0x8faed9, 0xe6a09f}, /* U+681F [2000] */ + {0x8faeda, 0xe6a0ad}, /* U+682D [2000] */ {0x8faedb, 0xf0a391a5}, /* U+23465 [2000] [Unicode3.1] */ - {0x8faedc, 0x00e6a0b3}, /* U+6833 [2000] */ - {0x8faedd, 0x00e6a0bb}, /* U+683B [2000] */ - {0x8faede, 0x00e6a0be}, /* U+683E [2000] */ - {0x8faedf, 0x00e6a184}, /* U+6844 [2000] */ - {0x8faee0, 0x00e6a185}, /* U+6845 [2000] */ - {0x8faee1, 0x00e6a189}, /* U+6849 [2000] */ - {0x8faee2, 0x00e6a18c}, /* U+684C [2000] */ - {0x8faee3, 0x00e6a195}, /* U+6855 [2000] */ - {0x8faee4, 0x00e6a197}, /* U+6857 [2000] */ - {0x8faee5, 0x00e3adb7}, /* U+3B77 [2000] */ - {0x8faee6, 0x00e6a1ab}, /* U+686B [2000] */ - {0x8faee7, 0x00e6a1ae}, /* U+686E [2000] */ - {0x8faee8, 0x00e6a1ba}, /* U+687A [2000] */ - {0x8faee9, 0x00e6a1bc}, /* U+687C [2000] */ - {0x8faeea, 0x00e6a282}, /* U+6882 [2000] */ - {0x8faeeb, 0x00e6a290}, /* U+6890 [2000] */ - {0x8faeec, 0x00e6a296}, /* U+6896 [2000] */ - {0x8faeed, 0x00e3adad}, /* U+3B6D [2000] */ - {0x8faeee, 0x00e6a298}, /* U+6898 [2000] */ - {0x8faeef, 0x00e6a299}, /* U+6899 [2000] */ - {0x8faef0, 0x00e6a29a}, /* U+689A [2000] */ - {0x8faef1, 0x00e6a29c}, /* U+689C [2000] */ - {0x8faef2, 0x00e6a2aa}, /* U+68AA [2000] */ - {0x8faef3, 0x00e6a2ab}, /* U+68AB [2000] */ - {0x8faef4, 0x00e6a2b4}, /* U+68B4 [2000] */ - {0x8faef5, 0x00e6a2bb}, /* U+68BB [2000] */ - {0x8faef6, 0x00e6a3bb}, /* U+68FB [2000] */ + {0x8faedc, 0xe6a0b3}, /* U+6833 [2000] */ + {0x8faedd, 0xe6a0bb}, /* U+683B [2000] */ + {0x8faede, 0xe6a0be}, /* U+683E [2000] */ + {0x8faedf, 0xe6a184}, /* U+6844 [2000] */ + {0x8faee0, 0xe6a185}, /* U+6845 [2000] */ + {0x8faee1, 0xe6a189}, /* U+6849 [2000] */ + {0x8faee2, 0xe6a18c}, /* U+684C [2000] */ + {0x8faee3, 0xe6a195}, /* U+6855 [2000] */ + {0x8faee4, 0xe6a197}, /* U+6857 [2000] */ + {0x8faee5, 0xe3adb7}, /* U+3B77 [2000] */ + {0x8faee6, 0xe6a1ab}, /* U+686B [2000] */ + {0x8faee7, 0xe6a1ae}, /* U+686E [2000] */ + {0x8faee8, 0xe6a1ba}, /* U+687A [2000] */ + {0x8faee9, 0xe6a1bc}, /* U+687C [2000] */ + {0x8faeea, 0xe6a282}, /* U+6882 [2000] */ + {0x8faeeb, 0xe6a290}, /* U+6890 [2000] */ + {0x8faeec, 0xe6a296}, /* U+6896 [2000] */ + {0x8faeed, 0xe3adad}, /* U+3B6D [2000] */ + {0x8faeee, 0xe6a298}, /* U+6898 [2000] */ + {0x8faeef, 0xe6a299}, /* U+6899 [2000] */ + {0x8faef0, 0xe6a29a}, /* U+689A [2000] */ + {0x8faef1, 0xe6a29c}, /* U+689C [2000] */ + {0x8faef2, 0xe6a2aa}, /* U+68AA [2000] */ + {0x8faef3, 0xe6a2ab}, /* U+68AB [2000] */ + {0x8faef4, 0xe6a2b4}, /* U+68B4 [2000] */ + {0x8faef5, 0xe6a2bb}, /* U+68BB [2000] */ + {0x8faef6, 0xe6a3bb}, /* U+68FB [2000] */ {0x8faef7, 0xf0a393a4}, /* U+234E4 [2000] [Unicode3.1] */ {0x8faef8, 0xf0a3959a}, /* U+2355A [2000] [Unicode3.1] */ - {0x8faef9, 0x00efa893}, /* U+FA13 CJK COMPATIBILITY IDEOGRAPH-FA13 [2000] */ - {0x8faefa, 0x00e6a383}, /* U+68C3 [2000] */ - {0x8faefb, 0x00e6a385}, /* U+68C5 [2000] */ - {0x8faefc, 0x00e6a38c}, /* U+68CC [2000] */ - {0x8faefd, 0x00e6a38f}, /* U+68CF [2000] */ - {0x8faefe, 0x00e6a396}, /* U+68D6 [2000] */ - {0x8fafa1, 0x00e6a399}, /* U+68D9 [2000] */ - {0x8fafa2, 0x00e6a3a4}, /* U+68E4 [2000] */ - {0x8fafa3, 0x00e6a3a5}, /* U+68E5 [2000] */ - {0x8fafa4, 0x00e6a3ac}, /* U+68EC [2000] */ - {0x8fafa5, 0x00e6a3b7}, /* U+68F7 [2000] */ - {0x8fafa6, 0x00e6a483}, /* U+6903 [2000] */ - {0x8fafa7, 0x00e6a487}, /* U+6907 [2000] */ - {0x8fafa8, 0x00e3ae87}, /* U+3B87 [2000] */ - {0x8fafa9, 0x00e3ae88}, /* U+3B88 [2000] */ + {0x8faef9, 0xefa893}, /* U+FA13 CJK COMPATIBILITY IDEOGRAPH-FA13 [2000] */ + {0x8faefa, 0xe6a383}, /* U+68C3 [2000] */ + {0x8faefb, 0xe6a385}, /* U+68C5 [2000] */ + {0x8faefc, 0xe6a38c}, /* U+68CC [2000] */ + {0x8faefd, 0xe6a38f}, /* U+68CF [2000] */ + {0x8faefe, 0xe6a396}, /* U+68D6 [2000] */ + {0x8fafa1, 0xe6a399}, /* U+68D9 [2000] */ + {0x8fafa2, 0xe6a3a4}, /* U+68E4 [2000] */ + {0x8fafa3, 0xe6a3a5}, /* U+68E5 [2000] */ + {0x8fafa4, 0xe6a3ac}, /* U+68EC [2000] */ + {0x8fafa5, 0xe6a3b7}, /* U+68F7 [2000] */ + {0x8fafa6, 0xe6a483}, /* U+6903 [2000] */ + {0x8fafa7, 0xe6a487}, /* U+6907 [2000] */ + {0x8fafa8, 0xe3ae87}, /* U+3B87 [2000] */ + {0x8fafa9, 0xe3ae88}, /* U+3B88 [2000] */ {0x8fafaa, 0xf0a39694}, /* U+23594 [2000] [Unicode3.1] */ - {0x8fafab, 0x00e6a4bb}, /* U+693B [2000] */ - {0x8fafac, 0x00e3ae8d}, /* U+3B8D [2000] */ - {0x8fafad, 0x00e6a586}, /* U+6946 [2000] */ - {0x8fafae, 0x00e6a5a9}, /* U+6969 [2000] */ - {0x8fafaf, 0x00e6a5ac}, /* U+696C [2000] */ - {0x8fafb0, 0x00e6a5b2}, /* U+6972 [2000] */ - {0x8fafb1, 0x00e6a5ba}, /* U+697A [2000] */ - {0x8fafb2, 0x00e6a5bf}, /* U+697F [2000] */ - {0x8fafb3, 0x00e6a692}, /* U+6992 [2000] */ - {0x8fafb4, 0x00e3aea4}, /* U+3BA4 [2000] */ - {0x8fafb5, 0x00e6a696}, /* U+6996 [2000] */ - {0x8fafb6, 0x00e6a698}, /* U+6998 [2000] */ - {0x8fafb7, 0x00e6a6a6}, /* U+69A6 [2000] */ - {0x8fafb8, 0x00e6a6b0}, /* U+69B0 [2000] */ - {0x8fafb9, 0x00e6a6b7}, /* U+69B7 [2000] */ - {0x8fafba, 0x00e6a6ba}, /* U+69BA [2000] */ - {0x8fafbb, 0x00e6a6bc}, /* U+69BC [2000] */ - {0x8fafbc, 0x00e6a780}, /* U+69C0 [2000] */ - {0x8fafbd, 0x00e6a791}, /* U+69D1 [2000] */ - {0x8fafbe, 0x00e6a796}, /* U+69D6 [2000] */ + {0x8fafab, 0xe6a4bb}, /* U+693B [2000] */ + {0x8fafac, 0xe3ae8d}, /* U+3B8D [2000] */ + {0x8fafad, 0xe6a586}, /* U+6946 [2000] */ + {0x8fafae, 0xe6a5a9}, /* U+6969 [2000] */ + {0x8fafaf, 0xe6a5ac}, /* U+696C [2000] */ + {0x8fafb0, 0xe6a5b2}, /* U+6972 [2000] */ + {0x8fafb1, 0xe6a5ba}, /* U+697A [2000] */ + {0x8fafb2, 0xe6a5bf}, /* U+697F [2000] */ + {0x8fafb3, 0xe6a692}, /* U+6992 [2000] */ + {0x8fafb4, 0xe3aea4}, /* U+3BA4 [2000] */ + {0x8fafb5, 0xe6a696}, /* U+6996 [2000] */ + {0x8fafb6, 0xe6a698}, /* U+6998 [2000] */ + {0x8fafb7, 0xe6a6a6}, /* U+69A6 [2000] */ + {0x8fafb8, 0xe6a6b0}, /* U+69B0 [2000] */ + {0x8fafb9, 0xe6a6b7}, /* U+69B7 [2000] */ + {0x8fafba, 0xe6a6ba}, /* U+69BA [2000] */ + {0x8fafbb, 0xe6a6bc}, /* U+69BC [2000] */ + {0x8fafbc, 0xe6a780}, /* U+69C0 [2000] */ + {0x8fafbd, 0xe6a791}, /* U+69D1 [2000] */ + {0x8fafbe, 0xe6a796}, /* U+69D6 [2000] */ {0x8fafbf, 0xf0a398b9}, /* U+23639 [2000] [Unicode3.1] */ {0x8fafc0, 0xf0a39987}, /* U+23647 [2000] [Unicode3.1] */ - {0x8fafc1, 0x00e6a8b0}, /* U+6A30 [2000] */ + {0x8fafc1, 0xe6a8b0}, /* U+6A30 [2000] */ {0x8fafc2, 0xf0a398b8}, /* U+23638 [2000] [Unicode3.1] */ {0x8fafc3, 0xf0a398ba}, /* U+2363A [2000] [Unicode3.1] */ - {0x8fafc4, 0x00e6a7a3}, /* U+69E3 [2000] */ - {0x8fafc5, 0x00e6a7ae}, /* U+69EE [2000] */ - {0x8fafc6, 0x00e6a7af}, /* U+69EF [2000] */ - {0x8fafc7, 0x00e6a7b3}, /* U+69F3 [2000] */ - {0x8fafc8, 0x00e3af8d}, /* U+3BCD [2000] */ - {0x8fafc9, 0x00e6a7b4}, /* U+69F4 [2000] */ - {0x8fafca, 0x00e6a7be}, /* U+69FE [2000] */ - {0x8fafcb, 0x00e6a891}, /* U+6A11 [2000] */ - {0x8fafcc, 0x00e6a89a}, /* U+6A1A [2000] */ - {0x8fafcd, 0x00e6a89d}, /* U+6A1D [2000] */ + {0x8fafc4, 0xe6a7a3}, /* U+69E3 [2000] */ + {0x8fafc5, 0xe6a7ae}, /* U+69EE [2000] */ + {0x8fafc6, 0xe6a7af}, /* U+69EF [2000] */ + {0x8fafc7, 0xe6a7b3}, /* U+69F3 [2000] */ + {0x8fafc8, 0xe3af8d}, /* U+3BCD [2000] */ + {0x8fafc9, 0xe6a7b4}, /* U+69F4 [2000] */ + {0x8fafca, 0xe6a7be}, /* U+69FE [2000] */ + {0x8fafcb, 0xe6a891}, /* U+6A11 [2000] */ + {0x8fafcc, 0xe6a89a}, /* U+6A1A [2000] */ + {0x8fafcd, 0xe6a89d}, /* U+6A1D [2000] */ {0x8fafce, 0xf0a39c9c}, /* U+2371C [2000] [Unicode3.1] */ - {0x8fafcf, 0x00e6a8b2}, /* U+6A32 [2000] */ - {0x8fafd0, 0x00e6a8b3}, /* U+6A33 [2000] */ - {0x8fafd1, 0x00e6a8b4}, /* U+6A34 [2000] */ - {0x8fafd2, 0x00e6a8bf}, /* U+6A3F [2000] */ - {0x8fafd3, 0x00e6a986}, /* U+6A46 [2000] */ - {0x8fafd4, 0x00e6a989}, /* U+6A49 [2000] */ - {0x8fafd5, 0x00e6a9ba}, /* U+6A7A [2000] */ - {0x8fafd6, 0x00e6a98e}, /* U+6A4E [2000] */ - {0x8fafd7, 0x00e6a992}, /* U+6A52 [2000] */ - {0x8fafd8, 0x00e6a9a4}, /* U+6A64 [2000] */ + {0x8fafcf, 0xe6a8b2}, /* U+6A32 [2000] */ + {0x8fafd0, 0xe6a8b3}, /* U+6A33 [2000] */ + {0x8fafd1, 0xe6a8b4}, /* U+6A34 [2000] */ + {0x8fafd2, 0xe6a8bf}, /* U+6A3F [2000] */ + {0x8fafd3, 0xe6a986}, /* U+6A46 [2000] */ + {0x8fafd4, 0xe6a989}, /* U+6A49 [2000] */ + {0x8fafd5, 0xe6a9ba}, /* U+6A7A [2000] */ + {0x8fafd6, 0xe6a98e}, /* U+6A4E [2000] */ + {0x8fafd7, 0xe6a992}, /* U+6A52 [2000] */ + {0x8fafd8, 0xe6a9a4}, /* U+6A64 [2000] */ {0x8fafd9, 0xf0a39c8c}, /* U+2370C [2000] [Unicode3.1] */ - {0x8fafda, 0x00e6a9be}, /* U+6A7E [2000] */ - {0x8fafdb, 0x00e6aa83}, /* U+6A83 [2000] */ - {0x8fafdc, 0x00e6aa8b}, /* U+6A8B [2000] */ - {0x8fafdd, 0x00e3afb0}, /* U+3BF0 [2000] */ - {0x8fafde, 0x00e6aa91}, /* U+6A91 [2000] */ - {0x8fafdf, 0x00e6aa9f}, /* U+6A9F [2000] */ - {0x8fafe0, 0x00e6aaa1}, /* U+6AA1 [2000] */ + {0x8fafda, 0xe6a9be}, /* U+6A7E [2000] */ + {0x8fafdb, 0xe6aa83}, /* U+6A83 [2000] */ + {0x8fafdc, 0xe6aa8b}, /* U+6A8B [2000] */ + {0x8fafdd, 0xe3afb0}, /* U+3BF0 [2000] */ + {0x8fafde, 0xe6aa91}, /* U+6A91 [2000] */ + {0x8fafdf, 0xe6aa9f}, /* U+6A9F [2000] */ + {0x8fafe0, 0xe6aaa1}, /* U+6AA1 [2000] */ {0x8fafe1, 0xf0a39da4}, /* U+23764 [2000] [Unicode3.1] */ - {0x8fafe2, 0x00e6aaab}, /* U+6AAB [2000] */ - {0x8fafe3, 0x00e6aabd}, /* U+6ABD [2000] */ - {0x8fafe4, 0x00e6ab86}, /* U+6AC6 [2000] */ - {0x8fafe5, 0x00e6ab94}, /* U+6AD4 [2000] */ - {0x8fafe6, 0x00e6ab90}, /* U+6AD0 [2000] */ - {0x8fafe7, 0x00e6ab9c}, /* U+6ADC [2000] */ - {0x8fafe8, 0x00e6ab9d}, /* U+6ADD [2000] */ + {0x8fafe2, 0xe6aaab}, /* U+6AAB [2000] */ + {0x8fafe3, 0xe6aabd}, /* U+6ABD [2000] */ + {0x8fafe4, 0xe6ab86}, /* U+6AC6 [2000] */ + {0x8fafe5, 0xe6ab94}, /* U+6AD4 [2000] */ + {0x8fafe6, 0xe6ab90}, /* U+6AD0 [2000] */ + {0x8fafe7, 0xe6ab9c}, /* U+6ADC [2000] */ + {0x8fafe8, 0xe6ab9d}, /* U+6ADD [2000] */ {0x8fafe9, 0xf0a39fbf}, /* U+237FF [2000] [Unicode3.1] */ {0x8fafea, 0xf0a39fa7}, /* U+237E7 [2000] [Unicode3.1] */ - {0x8fafeb, 0x00e6abac}, /* U+6AEC [2000] */ - {0x8fafec, 0x00e6abb1}, /* U+6AF1 [2000] */ - {0x8fafed, 0x00e6abb2}, /* U+6AF2 [2000] */ - {0x8fafee, 0x00e6abb3}, /* U+6AF3 [2000] */ - {0x8fafef, 0x00e6abbd}, /* U+6AFD [2000] */ + {0x8fafeb, 0xe6abac}, /* U+6AEC [2000] */ + {0x8fafec, 0xe6abb1}, /* U+6AF1 [2000] */ + {0x8fafed, 0xe6abb2}, /* U+6AF2 [2000] */ + {0x8fafee, 0xe6abb3}, /* U+6AF3 [2000] */ + {0x8fafef, 0xe6abbd}, /* U+6AFD [2000] */ {0x8faff0, 0xf0a3a0a4}, /* U+23824 [2000] [Unicode3.1] */ - {0x8faff1, 0x00e6ac8b}, /* U+6B0B [2000] */ - {0x8faff2, 0x00e6ac8f}, /* U+6B0F [2000] */ - {0x8faff3, 0x00e6ac90}, /* U+6B10 [2000] */ - {0x8faff4, 0x00e6ac91}, /* U+6B11 [2000] */ + {0x8faff1, 0xe6ac8b}, /* U+6B0B [2000] */ + {0x8faff2, 0xe6ac8f}, /* U+6B0F [2000] */ + {0x8faff3, 0xe6ac90}, /* U+6B10 [2000] */ + {0x8faff4, 0xe6ac91}, /* U+6B11 [2000] */ {0x8faff5, 0xf0a3a0bd}, /* U+2383D [2000] [Unicode3.1] */ - {0x8faff6, 0x00e6ac97}, /* U+6B17 [2000] */ - {0x8faff7, 0x00e3b0a6}, /* U+3C26 [2000] */ - {0x8faff8, 0x00e6acaf}, /* U+6B2F [2000] */ - {0x8faff9, 0x00e6ad8a}, /* U+6B4A [2000] */ - {0x8faffa, 0x00e6ad98}, /* U+6B58 [2000] */ - {0x8faffb, 0x00e6adac}, /* U+6B6C [2000] */ - {0x8faffc, 0x00e6adb5}, /* U+6B75 [2000] */ - {0x8faffd, 0x00e6adba}, /* U+6B7A [2000] */ - {0x8faffe, 0x00e6ae81}, /* U+6B81 [2000] */ - {0x8feea1, 0x00e6ae9b}, /* U+6B9B [2000] */ - {0x8feea2, 0x00e6aeae}, /* U+6BAE [2000] */ + {0x8faff6, 0xe6ac97}, /* U+6B17 [2000] */ + {0x8faff7, 0xe3b0a6}, /* U+3C26 [2000] */ + {0x8faff8, 0xe6acaf}, /* U+6B2F [2000] */ + {0x8faff9, 0xe6ad8a}, /* U+6B4A [2000] */ + {0x8faffa, 0xe6ad98}, /* U+6B58 [2000] */ + {0x8faffb, 0xe6adac}, /* U+6B6C [2000] */ + {0x8faffc, 0xe6adb5}, /* U+6B75 [2000] */ + {0x8faffd, 0xe6adba}, /* U+6B7A [2000] */ + {0x8faffe, 0xe6ae81}, /* U+6B81 [2000] */ + {0x8feea1, 0xe6ae9b}, /* U+6B9B [2000] */ + {0x8feea2, 0xe6aeae}, /* U+6BAE [2000] */ {0x8feea3, 0xf0a3aa98}, /* U+23A98 [2000] [Unicode3.1] */ - {0x8feea4, 0x00e6aebd}, /* U+6BBD [2000] */ - {0x8feea5, 0x00e6aebe}, /* U+6BBE [2000] */ - {0x8feea6, 0x00e6af87}, /* U+6BC7 [2000] */ - {0x8feea7, 0x00e6af88}, /* U+6BC8 [2000] */ - {0x8feea8, 0x00e6af89}, /* U+6BC9 [2000] */ - {0x8feea9, 0x00e6af9a}, /* U+6BDA [2000] */ - {0x8feeaa, 0x00e6afa6}, /* U+6BE6 [2000] */ - {0x8feeab, 0x00e6afa7}, /* U+6BE7 [2000] */ - {0x8feeac, 0x00e6afae}, /* U+6BEE [2000] */ - {0x8feead, 0x00e6afb1}, /* U+6BF1 [2000] */ - {0x8feeae, 0x00e6b082}, /* U+6C02 [2000] */ - {0x8feeaf, 0x00e6b08a}, /* U+6C0A [2000] */ - {0x8feeb0, 0x00e6b08e}, /* U+6C0E [2000] */ - {0x8feeb1, 0x00e6b0b5}, /* U+6C35 [2000] */ - {0x8feeb2, 0x00e6b0b6}, /* U+6C36 [2000] */ - {0x8feeb3, 0x00e6b0ba}, /* U+6C3A [2000] */ + {0x8feea4, 0xe6aebd}, /* U+6BBD [2000] */ + {0x8feea5, 0xe6aebe}, /* U+6BBE [2000] */ + {0x8feea6, 0xe6af87}, /* U+6BC7 [2000] */ + {0x8feea7, 0xe6af88}, /* U+6BC8 [2000] */ + {0x8feea8, 0xe6af89}, /* U+6BC9 [2000] */ + {0x8feea9, 0xe6af9a}, /* U+6BDA [2000] */ + {0x8feeaa, 0xe6afa6}, /* U+6BE6 [2000] */ + {0x8feeab, 0xe6afa7}, /* U+6BE7 [2000] */ + {0x8feeac, 0xe6afae}, /* U+6BEE [2000] */ + {0x8feead, 0xe6afb1}, /* U+6BF1 [2000] */ + {0x8feeae, 0xe6b082}, /* U+6C02 [2000] */ + {0x8feeaf, 0xe6b08a}, /* U+6C0A [2000] */ + {0x8feeb0, 0xe6b08e}, /* U+6C0E [2000] */ + {0x8feeb1, 0xe6b0b5}, /* U+6C35 [2000] */ + {0x8feeb2, 0xe6b0b6}, /* U+6C36 [2000] */ + {0x8feeb3, 0xe6b0ba}, /* U+6C3A [2000] */ {0x8feeb4, 0xf0a3b1bf}, /* U+23C7F [2000] [Unicode3.1] */ - {0x8feeb5, 0x00e6b0bf}, /* U+6C3F [2000] */ - {0x8feeb6, 0x00e6b18d}, /* U+6C4D [2000] */ - {0x8feeb7, 0x00e6b19b}, /* U+6C5B [2000] */ - {0x8feeb8, 0x00e6b1ad}, /* U+6C6D [2000] */ - {0x8feeb9, 0x00e6b284}, /* U+6C84 [2000] */ - {0x8feeba, 0x00e6b289}, /* U+6C89 [2000] */ - {0x8feebb, 0x00e3b383}, /* U+3CC3 [2000] */ - {0x8feebc, 0x00e6b294}, /* U+6C94 [2000] */ - {0x8feebd, 0x00e6b295}, /* U+6C95 [2000] */ - {0x8feebe, 0x00e6b297}, /* U+6C97 [2000] */ - {0x8feebf, 0x00e6b2ad}, /* U+6CAD [2000] */ - {0x8feec0, 0x00e6b382}, /* U+6CC2 [2000] */ - {0x8feec1, 0x00e6b390}, /* U+6CD0 [2000] */ - {0x8feec2, 0x00e3b392}, /* U+3CD2 [2000] */ - {0x8feec3, 0x00e6b396}, /* U+6CD6 [2000] */ - {0x8feec4, 0x00e6b39a}, /* U+6CDA [2000] */ - {0x8feec5, 0x00e6b39c}, /* U+6CDC [2000] */ - {0x8feec6, 0x00e6b3a9}, /* U+6CE9 [2000] */ - {0x8feec7, 0x00e6b3ac}, /* U+6CEC [2000] */ - {0x8feec8, 0x00e6b3ad}, /* U+6CED [2000] */ + {0x8feeb5, 0xe6b0bf}, /* U+6C3F [2000] */ + {0x8feeb6, 0xe6b18d}, /* U+6C4D [2000] */ + {0x8feeb7, 0xe6b19b}, /* U+6C5B [2000] */ + {0x8feeb8, 0xe6b1ad}, /* U+6C6D [2000] */ + {0x8feeb9, 0xe6b284}, /* U+6C84 [2000] */ + {0x8feeba, 0xe6b289}, /* U+6C89 [2000] */ + {0x8feebb, 0xe3b383}, /* U+3CC3 [2000] */ + {0x8feebc, 0xe6b294}, /* U+6C94 [2000] */ + {0x8feebd, 0xe6b295}, /* U+6C95 [2000] */ + {0x8feebe, 0xe6b297}, /* U+6C97 [2000] */ + {0x8feebf, 0xe6b2ad}, /* U+6CAD [2000] */ + {0x8feec0, 0xe6b382}, /* U+6CC2 [2000] */ + {0x8feec1, 0xe6b390}, /* U+6CD0 [2000] */ + {0x8feec2, 0xe3b392}, /* U+3CD2 [2000] */ + {0x8feec3, 0xe6b396}, /* U+6CD6 [2000] */ + {0x8feec4, 0xe6b39a}, /* U+6CDA [2000] */ + {0x8feec5, 0xe6b39c}, /* U+6CDC [2000] */ + {0x8feec6, 0xe6b3a9}, /* U+6CE9 [2000] */ + {0x8feec7, 0xe6b3ac}, /* U+6CEC [2000] */ + {0x8feec8, 0xe6b3ad}, /* U+6CED [2000] */ {0x8feec9, 0xf0a3b480}, /* U+23D00 [2000] [Unicode3.1] */ - {0x8feeca, 0x00e6b480}, /* U+6D00 [2000] */ - {0x8feecb, 0x00e6b48a}, /* U+6D0A [2000] */ - {0x8feecc, 0x00e6b4a4}, /* U+6D24 [2000] */ - {0x8feecd, 0x00e6b4a6}, /* U+6D26 [2000] */ - {0x8feece, 0x00e6b4a7}, /* U+6D27 [2000] */ - {0x8feecf, 0x00e6b1a7}, /* U+6C67 [2000] */ - {0x8feed0, 0x00e6b4af}, /* U+6D2F [2000] */ - {0x8feed1, 0x00e6b4bc}, /* U+6D3C [2000] */ - {0x8feed2, 0x00e6b59b}, /* U+6D5B [2000] */ - {0x8feed3, 0x00e6b59e}, /* U+6D5E [2000] */ - {0x8feed4, 0x00e6b5a0}, /* U+6D60 [2000] */ - {0x8feed5, 0x00e6b5b0}, /* U+6D70 [2000] */ - {0x8feed6, 0x00e6b680}, /* U+6D80 [2000] */ - {0x8feed7, 0x00e6b681}, /* U+6D81 [2000] */ - {0x8feed8, 0x00e6b68a}, /* U+6D8A [2000] */ - {0x8feed9, 0x00e6b68d}, /* U+6D8D [2000] */ - {0x8feeda, 0x00e6b691}, /* U+6D91 [2000] */ - {0x8feedb, 0x00e6b698}, /* U+6D98 [2000] */ + {0x8feeca, 0xe6b480}, /* U+6D00 [2000] */ + {0x8feecb, 0xe6b48a}, /* U+6D0A [2000] */ + {0x8feecc, 0xe6b4a4}, /* U+6D24 [2000] */ + {0x8feecd, 0xe6b4a6}, /* U+6D26 [2000] */ + {0x8feece, 0xe6b4a7}, /* U+6D27 [2000] */ + {0x8feecf, 0xe6b1a7}, /* U+6C67 [2000] */ + {0x8feed0, 0xe6b4af}, /* U+6D2F [2000] */ + {0x8feed1, 0xe6b4bc}, /* U+6D3C [2000] */ + {0x8feed2, 0xe6b59b}, /* U+6D5B [2000] */ + {0x8feed3, 0xe6b59e}, /* U+6D5E [2000] */ + {0x8feed4, 0xe6b5a0}, /* U+6D60 [2000] */ + {0x8feed5, 0xe6b5b0}, /* U+6D70 [2000] */ + {0x8feed6, 0xe6b680}, /* U+6D80 [2000] */ + {0x8feed7, 0xe6b681}, /* U+6D81 [2000] */ + {0x8feed8, 0xe6b68a}, /* U+6D8A [2000] */ + {0x8feed9, 0xe6b68d}, /* U+6D8D [2000] */ + {0x8feeda, 0xe6b691}, /* U+6D91 [2000] */ + {0x8feedb, 0xe6b698}, /* U+6D98 [2000] */ {0x8feedc, 0xf0a3b580}, /* U+23D40 [2000] [Unicode3.1] */ - {0x8feedd, 0x00e6b897}, /* U+6E17 [2000] */ + {0x8feedd, 0xe6b897}, /* U+6E17 [2000] */ {0x8feede, 0xf0a3b7ba}, /* U+23DFA [2000] [Unicode3.1] */ {0x8feedf, 0xf0a3b7b9}, /* U+23DF9 [2000] [Unicode3.1] */ {0x8feee0, 0xf0a3b793}, /* U+23DD3 [2000] [Unicode3.1] */ - {0x8feee1, 0x00e6b6ab}, /* U+6DAB [2000] */ - {0x8feee2, 0x00e6b6ae}, /* U+6DAE [2000] */ - {0x8feee3, 0x00e6b6b4}, /* U+6DB4 [2000] */ - {0x8feee4, 0x00e6b782}, /* U+6DC2 [2000] */ - {0x8feee5, 0x00e6b4b4}, /* U+6D34 [2000] */ - {0x8feee6, 0x00e6b788}, /* U+6DC8 [2000] */ - {0x8feee7, 0x00e6b78e}, /* U+6DCE [2000] */ - {0x8feee8, 0x00e6b78f}, /* U+6DCF [2000] */ - {0x8feee9, 0x00e6b790}, /* U+6DD0 [2000] */ - {0x8feeea, 0x00e6b79f}, /* U+6DDF [2000] */ - {0x8feeeb, 0x00e6b7a9}, /* U+6DE9 [2000] */ - {0x8feeec, 0x00e6b7b6}, /* U+6DF6 [2000] */ - {0x8feeed, 0x00e6b8b6}, /* U+6E36 [2000] */ - {0x8feeee, 0x00e6b89e}, /* U+6E1E [2000] */ - {0x8feeef, 0x00e6b8a2}, /* U+6E22 [2000] */ - {0x8feef0, 0x00e6b8a7}, /* U+6E27 [2000] */ - {0x8feef1, 0x00e3b491}, /* U+3D11 [2000] */ - {0x8feef2, 0x00e6b8b2}, /* U+6E32 [2000] */ - {0x8feef3, 0x00e6b8bc}, /* U+6E3C [2000] */ - {0x8feef4, 0x00e6b988}, /* U+6E48 [2000] */ - {0x8feef5, 0x00e6b989}, /* U+6E49 [2000] */ - {0x8feef6, 0x00e6b98b}, /* U+6E4B [2000] */ - {0x8feef7, 0x00e6b98c}, /* U+6E4C [2000] */ - {0x8feef8, 0x00e6b98f}, /* U+6E4F [2000] */ - {0x8feef9, 0x00e6b991}, /* U+6E51 [2000] */ - {0x8feefa, 0x00e6b993}, /* U+6E53 [2000] */ - {0x8feefb, 0x00e6b994}, /* U+6E54 [2000] */ - {0x8feefc, 0x00e6b997}, /* U+6E57 [2000] */ - {0x8feefd, 0x00e6b9a3}, /* U+6E63 [2000] */ - {0x8feefe, 0x00e3b49e}, /* U+3D1E [2000] */ - {0x8fefa1, 0x00e6ba93}, /* U+6E93 [2000] */ - {0x8fefa2, 0x00e6baa7}, /* U+6EA7 [2000] */ - {0x8fefa3, 0x00e6bab4}, /* U+6EB4 [2000] */ - {0x8fefa4, 0x00e6babf}, /* U+6EBF [2000] */ - {0x8fefa5, 0x00e6bb83}, /* U+6EC3 [2000] */ - {0x8fefa6, 0x00e6bb8a}, /* U+6ECA [2000] */ - {0x8fefa7, 0x00e6bb99}, /* U+6ED9 [2000] */ - {0x8fefa8, 0x00e6bcb5}, /* U+6F35 [2000] */ - {0x8fefa9, 0x00e6bbab}, /* U+6EEB [2000] */ - {0x8fefaa, 0x00e6bbb9}, /* U+6EF9 [2000] */ - {0x8fefab, 0x00e6bbbb}, /* U+6EFB [2000] */ - {0x8fefac, 0x00e6bc8a}, /* U+6F0A [2000] */ - {0x8fefad, 0x00e6bc8c}, /* U+6F0C [2000] */ - {0x8fefae, 0x00e6bc98}, /* U+6F18 [2000] */ - {0x8fefaf, 0x00e6bca5}, /* U+6F25 [2000] */ - {0x8fefb0, 0x00e6bcb6}, /* U+6F36 [2000] */ - {0x8fefb1, 0x00e6bcbc}, /* U+6F3C [2000] */ + {0x8feee1, 0xe6b6ab}, /* U+6DAB [2000] */ + {0x8feee2, 0xe6b6ae}, /* U+6DAE [2000] */ + {0x8feee3, 0xe6b6b4}, /* U+6DB4 [2000] */ + {0x8feee4, 0xe6b782}, /* U+6DC2 [2000] */ + {0x8feee5, 0xe6b4b4}, /* U+6D34 [2000] */ + {0x8feee6, 0xe6b788}, /* U+6DC8 [2000] */ + {0x8feee7, 0xe6b78e}, /* U+6DCE [2000] */ + {0x8feee8, 0xe6b78f}, /* U+6DCF [2000] */ + {0x8feee9, 0xe6b790}, /* U+6DD0 [2000] */ + {0x8feeea, 0xe6b79f}, /* U+6DDF [2000] */ + {0x8feeeb, 0xe6b7a9}, /* U+6DE9 [2000] */ + {0x8feeec, 0xe6b7b6}, /* U+6DF6 [2000] */ + {0x8feeed, 0xe6b8b6}, /* U+6E36 [2000] */ + {0x8feeee, 0xe6b89e}, /* U+6E1E [2000] */ + {0x8feeef, 0xe6b8a2}, /* U+6E22 [2000] */ + {0x8feef0, 0xe6b8a7}, /* U+6E27 [2000] */ + {0x8feef1, 0xe3b491}, /* U+3D11 [2000] */ + {0x8feef2, 0xe6b8b2}, /* U+6E32 [2000] */ + {0x8feef3, 0xe6b8bc}, /* U+6E3C [2000] */ + {0x8feef4, 0xe6b988}, /* U+6E48 [2000] */ + {0x8feef5, 0xe6b989}, /* U+6E49 [2000] */ + {0x8feef6, 0xe6b98b}, /* U+6E4B [2000] */ + {0x8feef7, 0xe6b98c}, /* U+6E4C [2000] */ + {0x8feef8, 0xe6b98f}, /* U+6E4F [2000] */ + {0x8feef9, 0xe6b991}, /* U+6E51 [2000] */ + {0x8feefa, 0xe6b993}, /* U+6E53 [2000] */ + {0x8feefb, 0xe6b994}, /* U+6E54 [2000] */ + {0x8feefc, 0xe6b997}, /* U+6E57 [2000] */ + {0x8feefd, 0xe6b9a3}, /* U+6E63 [2000] */ + {0x8feefe, 0xe3b49e}, /* U+3D1E [2000] */ + {0x8fefa1, 0xe6ba93}, /* U+6E93 [2000] */ + {0x8fefa2, 0xe6baa7}, /* U+6EA7 [2000] */ + {0x8fefa3, 0xe6bab4}, /* U+6EB4 [2000] */ + {0x8fefa4, 0xe6babf}, /* U+6EBF [2000] */ + {0x8fefa5, 0xe6bb83}, /* U+6EC3 [2000] */ + {0x8fefa6, 0xe6bb8a}, /* U+6ECA [2000] */ + {0x8fefa7, 0xe6bb99}, /* U+6ED9 [2000] */ + {0x8fefa8, 0xe6bcb5}, /* U+6F35 [2000] */ + {0x8fefa9, 0xe6bbab}, /* U+6EEB [2000] */ + {0x8fefaa, 0xe6bbb9}, /* U+6EF9 [2000] */ + {0x8fefab, 0xe6bbbb}, /* U+6EFB [2000] */ + {0x8fefac, 0xe6bc8a}, /* U+6F0A [2000] */ + {0x8fefad, 0xe6bc8c}, /* U+6F0C [2000] */ + {0x8fefae, 0xe6bc98}, /* U+6F18 [2000] */ + {0x8fefaf, 0xe6bca5}, /* U+6F25 [2000] */ + {0x8fefb0, 0xe6bcb6}, /* U+6F36 [2000] */ + {0x8fefb1, 0xe6bcbc}, /* U+6F3C [2000] */ {0x8fefb2, 0xf0a3bdbe}, /* U+23F7E [2000] [Unicode3.1] */ - {0x8fefb3, 0x00e6bd92}, /* U+6F52 [2000] */ - {0x8fefb4, 0x00e6bd97}, /* U+6F57 [2000] */ - {0x8fefb5, 0x00e6bd9a}, /* U+6F5A [2000] */ - {0x8fefb6, 0x00e6bda0}, /* U+6F60 [2000] */ - {0x8fefb7, 0x00e6bda8}, /* U+6F68 [2000] */ - {0x8fefb8, 0x00e6be98}, /* U+6F98 [2000] */ - {0x8fefb9, 0x00e6bdbd}, /* U+6F7D [2000] */ - {0x8fefba, 0x00e6be90}, /* U+6F90 [2000] */ - {0x8fefbb, 0x00e6be96}, /* U+6F96 [2000] */ - {0x8fefbc, 0x00e6bebe}, /* U+6FBE [2000] */ - {0x8fefbd, 0x00e6be9f}, /* U+6F9F [2000] */ - {0x8fefbe, 0x00e6bea5}, /* U+6FA5 [2000] */ - {0x8fefbf, 0x00e6beaf}, /* U+6FAF [2000] */ - {0x8fefc0, 0x00e3b5a4}, /* U+3D64 [2000] */ - {0x8fefc1, 0x00e6beb5}, /* U+6FB5 [2000] */ - {0x8fefc2, 0x00e6bf88}, /* U+6FC8 [2000] */ - {0x8fefc3, 0x00e6bf89}, /* U+6FC9 [2000] */ - {0x8fefc4, 0x00e6bf9a}, /* U+6FDA [2000] */ - {0x8fefc5, 0x00e6bf9e}, /* U+6FDE [2000] */ - {0x8fefc6, 0x00e6bfa9}, /* U+6FE9 [2000] */ + {0x8fefb3, 0xe6bd92}, /* U+6F52 [2000] */ + {0x8fefb4, 0xe6bd97}, /* U+6F57 [2000] */ + {0x8fefb5, 0xe6bd9a}, /* U+6F5A [2000] */ + {0x8fefb6, 0xe6bda0}, /* U+6F60 [2000] */ + {0x8fefb7, 0xe6bda8}, /* U+6F68 [2000] */ + {0x8fefb8, 0xe6be98}, /* U+6F98 [2000] */ + {0x8fefb9, 0xe6bdbd}, /* U+6F7D [2000] */ + {0x8fefba, 0xe6be90}, /* U+6F90 [2000] */ + {0x8fefbb, 0xe6be96}, /* U+6F96 [2000] */ + {0x8fefbc, 0xe6bebe}, /* U+6FBE [2000] */ + {0x8fefbd, 0xe6be9f}, /* U+6F9F [2000] */ + {0x8fefbe, 0xe6bea5}, /* U+6FA5 [2000] */ + {0x8fefbf, 0xe6beaf}, /* U+6FAF [2000] */ + {0x8fefc0, 0xe3b5a4}, /* U+3D64 [2000] */ + {0x8fefc1, 0xe6beb5}, /* U+6FB5 [2000] */ + {0x8fefc2, 0xe6bf88}, /* U+6FC8 [2000] */ + {0x8fefc3, 0xe6bf89}, /* U+6FC9 [2000] */ + {0x8fefc4, 0xe6bf9a}, /* U+6FDA [2000] */ + {0x8fefc5, 0xe6bf9e}, /* U+6FDE [2000] */ + {0x8fefc6, 0xe6bfa9}, /* U+6FE9 [2000] */ {0x8fefc7, 0xf0a48296}, /* U+24096 [2000] [Unicode3.1] */ - {0x8fefc8, 0x00e6bfbc}, /* U+6FFC [2000] */ - {0x8fefc9, 0x00e78080}, /* U+7000 [2000] */ - {0x8fefca, 0x00e78087}, /* U+7007 [2000] */ - {0x8fefcb, 0x00e7808a}, /* U+700A [2000] */ - {0x8fefcc, 0x00e780a3}, /* U+7023 [2000] */ + {0x8fefc8, 0xe6bfbc}, /* U+6FFC [2000] */ + {0x8fefc9, 0xe78080}, /* U+7000 [2000] */ + {0x8fefca, 0xe78087}, /* U+7007 [2000] */ + {0x8fefcb, 0xe7808a}, /* U+700A [2000] */ + {0x8fefcc, 0xe780a3}, /* U+7023 [2000] */ {0x8fefcd, 0xf0a48483}, /* U+24103 [2000] [Unicode3.1] */ - {0x8fefce, 0x00e780b9}, /* U+7039 [2000] */ - {0x8fefcf, 0x00e780ba}, /* U+703A [2000] */ - {0x8fefd0, 0x00e780bc}, /* U+703C [2000] */ - {0x8fefd1, 0x00e78183}, /* U+7043 [2000] */ - {0x8fefd2, 0x00e78187}, /* U+7047 [2000] */ - {0x8fefd3, 0x00e7818b}, /* U+704B [2000] */ - {0x8fefd4, 0x00e3b69a}, /* U+3D9A [2000] */ - {0x8fefd5, 0x00e78194}, /* U+7054 [2000] */ - {0x8fefd6, 0x00e781a5}, /* U+7065 [2000] */ - {0x8fefd7, 0x00e781a9}, /* U+7069 [2000] */ - {0x8fefd8, 0x00e781ac}, /* U+706C [2000] */ - {0x8fefd9, 0x00e781ae}, /* U+706E [2000] */ - {0x8fefda, 0x00e781b6}, /* U+7076 [2000] */ - {0x8fefdb, 0x00e781be}, /* U+707E [2000] */ - {0x8fefdc, 0x00e78281}, /* U+7081 [2000] */ - {0x8fefdd, 0x00e78286}, /* U+7086 [2000] */ - {0x8fefde, 0x00e78295}, /* U+7095 [2000] */ - {0x8fefdf, 0x00e78297}, /* U+7097 [2000] */ - {0x8fefe0, 0x00e782bb}, /* U+70BB [2000] */ + {0x8fefce, 0xe780b9}, /* U+7039 [2000] */ + {0x8fefcf, 0xe780ba}, /* U+703A [2000] */ + {0x8fefd0, 0xe780bc}, /* U+703C [2000] */ + {0x8fefd1, 0xe78183}, /* U+7043 [2000] */ + {0x8fefd2, 0xe78187}, /* U+7047 [2000] */ + {0x8fefd3, 0xe7818b}, /* U+704B [2000] */ + {0x8fefd4, 0xe3b69a}, /* U+3D9A [2000] */ + {0x8fefd5, 0xe78194}, /* U+7054 [2000] */ + {0x8fefd6, 0xe781a5}, /* U+7065 [2000] */ + {0x8fefd7, 0xe781a9}, /* U+7069 [2000] */ + {0x8fefd8, 0xe781ac}, /* U+706C [2000] */ + {0x8fefd9, 0xe781ae}, /* U+706E [2000] */ + {0x8fefda, 0xe781b6}, /* U+7076 [2000] */ + {0x8fefdb, 0xe781be}, /* U+707E [2000] */ + {0x8fefdc, 0xe78281}, /* U+7081 [2000] */ + {0x8fefdd, 0xe78286}, /* U+7086 [2000] */ + {0x8fefde, 0xe78295}, /* U+7095 [2000] */ + {0x8fefdf, 0xe78297}, /* U+7097 [2000] */ + {0x8fefe0, 0xe782bb}, /* U+70BB [2000] */ {0x8fefe1, 0xf0a48786}, /* U+241C6 [2000] [Unicode3.1] */ - {0x8fefe2, 0x00e7829f}, /* U+709F [2000] */ - {0x8fefe3, 0x00e782b1}, /* U+70B1 [2000] */ + {0x8fefe2, 0xe7829f}, /* U+709F [2000] */ + {0x8fefe3, 0xe782b1}, /* U+70B1 [2000] */ {0x8fefe4, 0xf0a487be}, /* U+241FE [2000] [Unicode3.1] */ - {0x8fefe5, 0x00e783ac}, /* U+70EC [2000] */ - {0x8fefe6, 0x00e7838a}, /* U+70CA [2000] */ - {0x8fefe7, 0x00e78391}, /* U+70D1 [2000] */ - {0x8fefe8, 0x00e78393}, /* U+70D3 [2000] */ - {0x8fefe9, 0x00e7839c}, /* U+70DC [2000] */ - {0x8fefea, 0x00e78483}, /* U+7103 [2000] */ - {0x8fefeb, 0x00e78484}, /* U+7104 [2000] */ - {0x8fefec, 0x00e78486}, /* U+7106 [2000] */ - {0x8fefed, 0x00e78487}, /* U+7107 [2000] */ - {0x8fefee, 0x00e78488}, /* U+7108 [2000] */ - {0x8fefef, 0x00e7848c}, /* U+710C [2000] */ - {0x8feff0, 0x00e3b780}, /* U+3DC0 [2000] */ - {0x8feff1, 0x00e784af}, /* U+712F [2000] */ - {0x8feff2, 0x00e784b1}, /* U+7131 [2000] */ - {0x8feff3, 0x00e78590}, /* U+7150 [2000] */ - {0x8feff4, 0x00e7858a}, /* U+714A [2000] */ - {0x8feff5, 0x00e78593}, /* U+7153 [2000] */ - {0x8feff6, 0x00e7859e}, /* U+715E [2000] */ - {0x8feff7, 0x00e3b794}, /* U+3DD4 [2000] */ - {0x8feff8, 0x00e78696}, /* U+7196 [2000] */ - {0x8feff9, 0x00e78680}, /* U+7180 [2000] */ - {0x8feffa, 0x00e7869b}, /* U+719B [2000] */ - {0x8feffb, 0x00e786a0}, /* U+71A0 [2000] */ - {0x8feffc, 0x00e786a2}, /* U+71A2 [2000] */ - {0x8feffd, 0x00e786ae}, /* U+71AE [2000] */ - {0x8feffe, 0x00e786af}, /* U+71AF [2000] */ - {0x8ff0a1, 0x00e786b3}, /* U+71B3 [2000] */ + {0x8fefe5, 0xe783ac}, /* U+70EC [2000] */ + {0x8fefe6, 0xe7838a}, /* U+70CA [2000] */ + {0x8fefe7, 0xe78391}, /* U+70D1 [2000] */ + {0x8fefe8, 0xe78393}, /* U+70D3 [2000] */ + {0x8fefe9, 0xe7839c}, /* U+70DC [2000] */ + {0x8fefea, 0xe78483}, /* U+7103 [2000] */ + {0x8fefeb, 0xe78484}, /* U+7104 [2000] */ + {0x8fefec, 0xe78486}, /* U+7106 [2000] */ + {0x8fefed, 0xe78487}, /* U+7107 [2000] */ + {0x8fefee, 0xe78488}, /* U+7108 [2000] */ + {0x8fefef, 0xe7848c}, /* U+710C [2000] */ + {0x8feff0, 0xe3b780}, /* U+3DC0 [2000] */ + {0x8feff1, 0xe784af}, /* U+712F [2000] */ + {0x8feff2, 0xe784b1}, /* U+7131 [2000] */ + {0x8feff3, 0xe78590}, /* U+7150 [2000] */ + {0x8feff4, 0xe7858a}, /* U+714A [2000] */ + {0x8feff5, 0xe78593}, /* U+7153 [2000] */ + {0x8feff6, 0xe7859e}, /* U+715E [2000] */ + {0x8feff7, 0xe3b794}, /* U+3DD4 [2000] */ + {0x8feff8, 0xe78696}, /* U+7196 [2000] */ + {0x8feff9, 0xe78680}, /* U+7180 [2000] */ + {0x8feffa, 0xe7869b}, /* U+719B [2000] */ + {0x8feffb, 0xe786a0}, /* U+71A0 [2000] */ + {0x8feffc, 0xe786a2}, /* U+71A2 [2000] */ + {0x8feffd, 0xe786ae}, /* U+71AE [2000] */ + {0x8feffe, 0xe786af}, /* U+71AF [2000] */ + {0x8ff0a1, 0xe786b3}, /* U+71B3 [2000] */ {0x8ff0a2, 0xf0a48ebc}, /* U+243BC [2000] [Unicode3.1] */ - {0x8ff0a3, 0x00e7878b}, /* U+71CB [2000] */ - {0x8ff0a4, 0x00e78793}, /* U+71D3 [2000] */ - {0x8ff0a5, 0x00e78799}, /* U+71D9 [2000] */ - {0x8ff0a6, 0x00e7879c}, /* U+71DC [2000] */ - {0x8ff0a7, 0x00e78887}, /* U+7207 [2000] */ - {0x8ff0a8, 0x00e3b885}, /* U+3E05 [2000] */ - {0x8ff0a9, 0x00efa989}, /* U+FA49 CJK COMPATIBILITY IDEOGRAPH-FA49 [2000] [Unicode3.2] */ - {0x8ff0aa, 0x00e788ab}, /* U+722B [2000] */ - {0x8ff0ab, 0x00e788b4}, /* U+7234 [2000] */ - {0x8ff0ac, 0x00e788b8}, /* U+7238 [2000] */ - {0x8ff0ad, 0x00e788b9}, /* U+7239 [2000] */ - {0x8ff0ae, 0x00e4b8ac}, /* U+4E2C [2000] */ - {0x8ff0af, 0x00e78982}, /* U+7242 [2000] */ - {0x8ff0b0, 0x00e78993}, /* U+7253 [2000] */ - {0x8ff0b1, 0x00e78997}, /* U+7257 [2000] */ - {0x8ff0b2, 0x00e789a3}, /* U+7263 [2000] */ + {0x8ff0a3, 0xe7878b}, /* U+71CB [2000] */ + {0x8ff0a4, 0xe78793}, /* U+71D3 [2000] */ + {0x8ff0a5, 0xe78799}, /* U+71D9 [2000] */ + {0x8ff0a6, 0xe7879c}, /* U+71DC [2000] */ + {0x8ff0a7, 0xe78887}, /* U+7207 [2000] */ + {0x8ff0a8, 0xe3b885}, /* U+3E05 [2000] */ + {0x8ff0a9, 0xefa989}, /* U+FA49 CJK COMPATIBILITY IDEOGRAPH-FA49 [2000] [Unicode3.2] */ + {0x8ff0aa, 0xe788ab}, /* U+722B [2000] */ + {0x8ff0ab, 0xe788b4}, /* U+7234 [2000] */ + {0x8ff0ac, 0xe788b8}, /* U+7238 [2000] */ + {0x8ff0ad, 0xe788b9}, /* U+7239 [2000] */ + {0x8ff0ae, 0xe4b8ac}, /* U+4E2C [2000] */ + {0x8ff0af, 0xe78982}, /* U+7242 [2000] */ + {0x8ff0b0, 0xe78993}, /* U+7253 [2000] */ + {0x8ff0b1, 0xe78997}, /* U+7257 [2000] */ + {0x8ff0b2, 0xe789a3}, /* U+7263 [2000] */ {0x8ff0b3, 0xf0a498a9}, /* U+24629 [2000] [Unicode3.1] */ - {0x8ff0b4, 0x00e789ae}, /* U+726E [2000] */ - {0x8ff0b5, 0x00e789af}, /* U+726F [2000] */ - {0x8ff0b6, 0x00e789b8}, /* U+7278 [2000] */ - {0x8ff0b7, 0x00e789bf}, /* U+727F [2000] */ - {0x8ff0b8, 0x00e78a8e}, /* U+728E [2000] */ + {0x8ff0b4, 0xe789ae}, /* U+726E [2000] */ + {0x8ff0b5, 0xe789af}, /* U+726F [2000] */ + {0x8ff0b6, 0xe789b8}, /* U+7278 [2000] */ + {0x8ff0b7, 0xe789bf}, /* U+727F [2000] */ + {0x8ff0b8, 0xe78a8e}, /* U+728E [2000] */ {0x8ff0b9, 0xf0a49aa5}, /* U+246A5 [2000] [Unicode3.1] */ - {0x8ff0ba, 0x00e78aad}, /* U+72AD [2000] */ - {0x8ff0bb, 0x00e78aae}, /* U+72AE [2000] */ - {0x8ff0bc, 0x00e78ab0}, /* U+72B0 [2000] */ - {0x8ff0bd, 0x00e78ab1}, /* U+72B1 [2000] */ - {0x8ff0be, 0x00e78b81}, /* U+72C1 [2000] */ - {0x8ff0bf, 0x00e3b9a0}, /* U+3E60 [2000] */ - {0x8ff0c0, 0x00e78b8c}, /* U+72CC [2000] */ - {0x8ff0c1, 0x00e3b9a6}, /* U+3E66 [2000] */ - {0x8ff0c2, 0x00e3b9a8}, /* U+3E68 [2000] */ - {0x8ff0c3, 0x00e78bb3}, /* U+72F3 [2000] */ - {0x8ff0c4, 0x00e78bba}, /* U+72FA [2000] */ - {0x8ff0c5, 0x00e78c87}, /* U+7307 [2000] */ - {0x8ff0c6, 0x00e78c92}, /* U+7312 [2000] */ - {0x8ff0c7, 0x00e78c98}, /* U+7318 [2000] */ - {0x8ff0c8, 0x00e78c99}, /* U+7319 [2000] */ - {0x8ff0c9, 0x00e3ba83}, /* U+3E83 [2000] */ - {0x8ff0ca, 0x00e78cb9}, /* U+7339 [2000] */ - {0x8ff0cb, 0x00e78cac}, /* U+732C [2000] */ - {0x8ff0cc, 0x00e78cb1}, /* U+7331 [2000] */ - {0x8ff0cd, 0x00e78cb3}, /* U+7333 [2000] */ - {0x8ff0ce, 0x00e78cbd}, /* U+733D [2000] */ - {0x8ff0cf, 0x00e78d92}, /* U+7352 [2000] */ - {0x8ff0d0, 0x00e3ba94}, /* U+3E94 [2000] */ - {0x8ff0d1, 0x00e78dab}, /* U+736B [2000] */ - {0x8ff0d2, 0x00e78dac}, /* U+736C [2000] */ + {0x8ff0ba, 0xe78aad}, /* U+72AD [2000] */ + {0x8ff0bb, 0xe78aae}, /* U+72AE [2000] */ + {0x8ff0bc, 0xe78ab0}, /* U+72B0 [2000] */ + {0x8ff0bd, 0xe78ab1}, /* U+72B1 [2000] */ + {0x8ff0be, 0xe78b81}, /* U+72C1 [2000] */ + {0x8ff0bf, 0xe3b9a0}, /* U+3E60 [2000] */ + {0x8ff0c0, 0xe78b8c}, /* U+72CC [2000] */ + {0x8ff0c1, 0xe3b9a6}, /* U+3E66 [2000] */ + {0x8ff0c2, 0xe3b9a8}, /* U+3E68 [2000] */ + {0x8ff0c3, 0xe78bb3}, /* U+72F3 [2000] */ + {0x8ff0c4, 0xe78bba}, /* U+72FA [2000] */ + {0x8ff0c5, 0xe78c87}, /* U+7307 [2000] */ + {0x8ff0c6, 0xe78c92}, /* U+7312 [2000] */ + {0x8ff0c7, 0xe78c98}, /* U+7318 [2000] */ + {0x8ff0c8, 0xe78c99}, /* U+7319 [2000] */ + {0x8ff0c9, 0xe3ba83}, /* U+3E83 [2000] */ + {0x8ff0ca, 0xe78cb9}, /* U+7339 [2000] */ + {0x8ff0cb, 0xe78cac}, /* U+732C [2000] */ + {0x8ff0cc, 0xe78cb1}, /* U+7331 [2000] */ + {0x8ff0cd, 0xe78cb3}, /* U+7333 [2000] */ + {0x8ff0ce, 0xe78cbd}, /* U+733D [2000] */ + {0x8ff0cf, 0xe78d92}, /* U+7352 [2000] */ + {0x8ff0d0, 0xe3ba94}, /* U+3E94 [2000] */ + {0x8ff0d1, 0xe78dab}, /* U+736B [2000] */ + {0x8ff0d2, 0xe78dac}, /* U+736C [2000] */ {0x8ff0d3, 0xf0a4a296}, /* U+24896 [2000] [Unicode3.1] */ - {0x8ff0d4, 0x00e78dae}, /* U+736E [2000] */ - {0x8ff0d5, 0x00e78daf}, /* U+736F [2000] */ - {0x8ff0d6, 0x00e78db1}, /* U+7371 [2000] */ - {0x8ff0d7, 0x00e78db7}, /* U+7377 [2000] */ - {0x8ff0d8, 0x00e78e81}, /* U+7381 [2000] */ - {0x8ff0d9, 0x00e78e85}, /* U+7385 [2000] */ - {0x8ff0da, 0x00e78e8a}, /* U+738A [2000] */ - {0x8ff0db, 0x00e78e94}, /* U+7394 [2000] */ - {0x8ff0dc, 0x00e78e98}, /* U+7398 [2000] */ - {0x8ff0dd, 0x00e78e9c}, /* U+739C [2000] */ - {0x8ff0de, 0x00e78e9e}, /* U+739E [2000] */ - {0x8ff0df, 0x00e78ea5}, /* U+73A5 [2000] */ - {0x8ff0e0, 0x00e78ea8}, /* U+73A8 [2000] */ - {0x8ff0e1, 0x00e78eb5}, /* U+73B5 [2000] */ - {0x8ff0e2, 0x00e78eb7}, /* U+73B7 [2000] */ - {0x8ff0e3, 0x00e78eb9}, /* U+73B9 [2000] */ - {0x8ff0e4, 0x00e78ebc}, /* U+73BC [2000] */ - {0x8ff0e5, 0x00e78ebf}, /* U+73BF [2000] */ - {0x8ff0e6, 0x00e78f85}, /* U+73C5 [2000] */ - {0x8ff0e7, 0x00e78f8b}, /* U+73CB [2000] */ - {0x8ff0e8, 0x00e78fa1}, /* U+73E1 [2000] */ - {0x8ff0e9, 0x00e78fa7}, /* U+73E7 [2000] */ - {0x8ff0ea, 0x00e78fb9}, /* U+73F9 [2000] */ - {0x8ff0eb, 0x00e79093}, /* U+7413 [2000] */ - {0x8ff0ec, 0x00e78fba}, /* U+73FA [2000] */ - {0x8ff0ed, 0x00e79081}, /* U+7401 [2000] */ - {0x8ff0ee, 0x00e790a4}, /* U+7424 [2000] */ - {0x8ff0ef, 0x00e790b1}, /* U+7431 [2000] */ - {0x8ff0f0, 0x00e790b9}, /* U+7439 [2000] */ - {0x8ff0f1, 0x00e79193}, /* U+7453 [2000] */ - {0x8ff0f2, 0x00e79180}, /* U+7440 [2000] */ - {0x8ff0f3, 0x00e79183}, /* U+7443 [2000] */ - {0x8ff0f4, 0x00e7918d}, /* U+744D [2000] */ - {0x8ff0f5, 0x00e79192}, /* U+7452 [2000] */ - {0x8ff0f6, 0x00e7919d}, /* U+745D [2000] */ - {0x8ff0f7, 0x00e791b1}, /* U+7471 [2000] */ - {0x8ff0f8, 0x00e79281}, /* U+7481 [2000] */ - {0x8ff0f9, 0x00e79285}, /* U+7485 [2000] */ - {0x8ff0fa, 0x00e79288}, /* U+7488 [2000] */ + {0x8ff0d4, 0xe78dae}, /* U+736E [2000] */ + {0x8ff0d5, 0xe78daf}, /* U+736F [2000] */ + {0x8ff0d6, 0xe78db1}, /* U+7371 [2000] */ + {0x8ff0d7, 0xe78db7}, /* U+7377 [2000] */ + {0x8ff0d8, 0xe78e81}, /* U+7381 [2000] */ + {0x8ff0d9, 0xe78e85}, /* U+7385 [2000] */ + {0x8ff0da, 0xe78e8a}, /* U+738A [2000] */ + {0x8ff0db, 0xe78e94}, /* U+7394 [2000] */ + {0x8ff0dc, 0xe78e98}, /* U+7398 [2000] */ + {0x8ff0dd, 0xe78e9c}, /* U+739C [2000] */ + {0x8ff0de, 0xe78e9e}, /* U+739E [2000] */ + {0x8ff0df, 0xe78ea5}, /* U+73A5 [2000] */ + {0x8ff0e0, 0xe78ea8}, /* U+73A8 [2000] */ + {0x8ff0e1, 0xe78eb5}, /* U+73B5 [2000] */ + {0x8ff0e2, 0xe78eb7}, /* U+73B7 [2000] */ + {0x8ff0e3, 0xe78eb9}, /* U+73B9 [2000] */ + {0x8ff0e4, 0xe78ebc}, /* U+73BC [2000] */ + {0x8ff0e5, 0xe78ebf}, /* U+73BF [2000] */ + {0x8ff0e6, 0xe78f85}, /* U+73C5 [2000] */ + {0x8ff0e7, 0xe78f8b}, /* U+73CB [2000] */ + {0x8ff0e8, 0xe78fa1}, /* U+73E1 [2000] */ + {0x8ff0e9, 0xe78fa7}, /* U+73E7 [2000] */ + {0x8ff0ea, 0xe78fb9}, /* U+73F9 [2000] */ + {0x8ff0eb, 0xe79093}, /* U+7413 [2000] */ + {0x8ff0ec, 0xe78fba}, /* U+73FA [2000] */ + {0x8ff0ed, 0xe79081}, /* U+7401 [2000] */ + {0x8ff0ee, 0xe790a4}, /* U+7424 [2000] */ + {0x8ff0ef, 0xe790b1}, /* U+7431 [2000] */ + {0x8ff0f0, 0xe790b9}, /* U+7439 [2000] */ + {0x8ff0f1, 0xe79193}, /* U+7453 [2000] */ + {0x8ff0f2, 0xe79180}, /* U+7440 [2000] */ + {0x8ff0f3, 0xe79183}, /* U+7443 [2000] */ + {0x8ff0f4, 0xe7918d}, /* U+744D [2000] */ + {0x8ff0f5, 0xe79192}, /* U+7452 [2000] */ + {0x8ff0f6, 0xe7919d}, /* U+745D [2000] */ + {0x8ff0f7, 0xe791b1}, /* U+7471 [2000] */ + {0x8ff0f8, 0xe79281}, /* U+7481 [2000] */ + {0x8ff0f9, 0xe79285}, /* U+7485 [2000] */ + {0x8ff0fa, 0xe79288}, /* U+7488 [2000] */ {0x8ff0fb, 0xf0a4a98d}, /* U+24A4D [2000] [Unicode3.1] */ - {0x8ff0fc, 0x00e79292}, /* U+7492 [2000] */ - {0x8ff0fd, 0x00e79297}, /* U+7497 [2000] */ - {0x8ff0fe, 0x00e79299}, /* U+7499 [2000] */ - {0x8ff1a1, 0x00e792a0}, /* U+74A0 [2000] */ - {0x8ff1a2, 0x00e792a1}, /* U+74A1 [2000] */ - {0x8ff1a3, 0x00e792a5}, /* U+74A5 [2000] */ - {0x8ff1a4, 0x00e792aa}, /* U+74AA [2000] */ - {0x8ff1a5, 0x00e792ab}, /* U+74AB [2000] */ - {0x8ff1a6, 0x00e792b9}, /* U+74B9 [2000] */ - {0x8ff1a7, 0x00e792bb}, /* U+74BB [2000] */ - {0x8ff1a8, 0x00e792ba}, /* U+74BA [2000] */ - {0x8ff1a9, 0x00e79396}, /* U+74D6 [2000] */ - {0x8ff1aa, 0x00e79398}, /* U+74D8 [2000] */ - {0x8ff1ab, 0x00e7939e}, /* U+74DE [2000] */ - {0x8ff1ac, 0x00e793af}, /* U+74EF [2000] */ - {0x8ff1ad, 0x00e793ab}, /* U+74EB [2000] */ + {0x8ff0fc, 0xe79292}, /* U+7492 [2000] */ + {0x8ff0fd, 0xe79297}, /* U+7497 [2000] */ + {0x8ff0fe, 0xe79299}, /* U+7499 [2000] */ + {0x8ff1a1, 0xe792a0}, /* U+74A0 [2000] */ + {0x8ff1a2, 0xe792a1}, /* U+74A1 [2000] */ + {0x8ff1a3, 0xe792a5}, /* U+74A5 [2000] */ + {0x8ff1a4, 0xe792aa}, /* U+74AA [2000] */ + {0x8ff1a5, 0xe792ab}, /* U+74AB [2000] */ + {0x8ff1a6, 0xe792b9}, /* U+74B9 [2000] */ + {0x8ff1a7, 0xe792bb}, /* U+74BB [2000] */ + {0x8ff1a8, 0xe792ba}, /* U+74BA [2000] */ + {0x8ff1a9, 0xe79396}, /* U+74D6 [2000] */ + {0x8ff1aa, 0xe79398}, /* U+74D8 [2000] */ + {0x8ff1ab, 0xe7939e}, /* U+74DE [2000] */ + {0x8ff1ac, 0xe793af}, /* U+74EF [2000] */ + {0x8ff1ad, 0xe793ab}, /* U+74EB [2000] */ {0x8ff1ae, 0xf0a4ad96}, /* U+24B56 [2000] [Unicode3.1] */ - {0x8ff1af, 0x00e793ba}, /* U+74FA [2000] */ + {0x8ff1af, 0xe793ba}, /* U+74FA [2000] */ {0x8ff1b0, 0xf0a4adaf}, /* U+24B6F [2000] [Unicode3.1] */ - {0x8ff1b1, 0x00e794a0}, /* U+7520 [2000] */ - {0x8ff1b2, 0x00e794a4}, /* U+7524 [2000] */ - {0x8ff1b3, 0x00e794aa}, /* U+752A [2000] */ - {0x8ff1b4, 0x00e3bd97}, /* U+3F57 [2000] */ + {0x8ff1b1, 0xe794a0}, /* U+7520 [2000] */ + {0x8ff1b2, 0xe794a4}, /* U+7524 [2000] */ + {0x8ff1b3, 0xe794aa}, /* U+752A [2000] */ + {0x8ff1b4, 0xe3bd97}, /* U+3F57 [2000] */ {0x8ff1b5, 0xf0a4b096}, /* U+24C16 [2000] [Unicode3.1] */ - {0x8ff1b6, 0x00e794bd}, /* U+753D [2000] */ - {0x8ff1b7, 0x00e794be}, /* U+753E [2000] */ - {0x8ff1b8, 0x00e79580}, /* U+7540 [2000] */ - {0x8ff1b9, 0x00e79588}, /* U+7548 [2000] */ - {0x8ff1ba, 0x00e7958e}, /* U+754E [2000] */ - {0x8ff1bb, 0x00e79590}, /* U+7550 [2000] */ - {0x8ff1bc, 0x00e79592}, /* U+7552 [2000] */ - {0x8ff1bd, 0x00e795ac}, /* U+756C [2000] */ - {0x8ff1be, 0x00e795b2}, /* U+7572 [2000] */ - {0x8ff1bf, 0x00e795b1}, /* U+7571 [2000] */ - {0x8ff1c0, 0x00e795ba}, /* U+757A [2000] */ - {0x8ff1c1, 0x00e795bd}, /* U+757D [2000] */ - {0x8ff1c2, 0x00e795be}, /* U+757E [2000] */ - {0x8ff1c3, 0x00e79681}, /* U+7581 [2000] */ + {0x8ff1b6, 0xe794bd}, /* U+753D [2000] */ + {0x8ff1b7, 0xe794be}, /* U+753E [2000] */ + {0x8ff1b8, 0xe79580}, /* U+7540 [2000] */ + {0x8ff1b9, 0xe79588}, /* U+7548 [2000] */ + {0x8ff1ba, 0xe7958e}, /* U+754E [2000] */ + {0x8ff1bb, 0xe79590}, /* U+7550 [2000] */ + {0x8ff1bc, 0xe79592}, /* U+7552 [2000] */ + {0x8ff1bd, 0xe795ac}, /* U+756C [2000] */ + {0x8ff1be, 0xe795b2}, /* U+7572 [2000] */ + {0x8ff1bf, 0xe795b1}, /* U+7571 [2000] */ + {0x8ff1c0, 0xe795ba}, /* U+757A [2000] */ + {0x8ff1c1, 0xe795bd}, /* U+757D [2000] */ + {0x8ff1c2, 0xe795be}, /* U+757E [2000] */ + {0x8ff1c3, 0xe79681}, /* U+7581 [2000] */ {0x8ff1c4, 0xf0a4b494}, /* U+24D14 [2000] [Unicode3.1] */ - {0x8ff1c5, 0x00e7968c}, /* U+758C [2000] */ - {0x8ff1c6, 0x00e3bdb5}, /* U+3F75 [2000] */ - {0x8ff1c7, 0x00e796a2}, /* U+75A2 [2000] */ - {0x8ff1c8, 0x00e3bdb7}, /* U+3F77 [2000] */ - {0x8ff1c9, 0x00e796b0}, /* U+75B0 [2000] */ - {0x8ff1ca, 0x00e796b7}, /* U+75B7 [2000] */ - {0x8ff1cb, 0x00e796bf}, /* U+75BF [2000] */ - {0x8ff1cc, 0x00e79780}, /* U+75C0 [2000] */ - {0x8ff1cd, 0x00e79786}, /* U+75C6 [2000] */ - {0x8ff1ce, 0x00e7978f}, /* U+75CF [2000] */ - {0x8ff1cf, 0x00e79793}, /* U+75D3 [2000] */ - {0x8ff1d0, 0x00e7979d}, /* U+75DD [2000] */ - {0x8ff1d1, 0x00e7979f}, /* U+75DF [2000] */ - {0x8ff1d2, 0x00e797a0}, /* U+75E0 [2000] */ - {0x8ff1d3, 0x00e797a7}, /* U+75E7 [2000] */ - {0x8ff1d4, 0x00e797ac}, /* U+75EC [2000] */ - {0x8ff1d5, 0x00e797ae}, /* U+75EE [2000] */ - {0x8ff1d6, 0x00e797b1}, /* U+75F1 [2000] */ - {0x8ff1d7, 0x00e797b9}, /* U+75F9 [2000] */ - {0x8ff1d8, 0x00e79883}, /* U+7603 [2000] */ - {0x8ff1d9, 0x00e79898}, /* U+7618 [2000] */ - {0x8ff1da, 0x00e79887}, /* U+7607 [2000] */ - {0x8ff1db, 0x00e7988f}, /* U+760F [2000] */ - {0x8ff1dc, 0x00e3beae}, /* U+3FAE [2000] */ + {0x8ff1c5, 0xe7968c}, /* U+758C [2000] */ + {0x8ff1c6, 0xe3bdb5}, /* U+3F75 [2000] */ + {0x8ff1c7, 0xe796a2}, /* U+75A2 [2000] */ + {0x8ff1c8, 0xe3bdb7}, /* U+3F77 [2000] */ + {0x8ff1c9, 0xe796b0}, /* U+75B0 [2000] */ + {0x8ff1ca, 0xe796b7}, /* U+75B7 [2000] */ + {0x8ff1cb, 0xe796bf}, /* U+75BF [2000] */ + {0x8ff1cc, 0xe79780}, /* U+75C0 [2000] */ + {0x8ff1cd, 0xe79786}, /* U+75C6 [2000] */ + {0x8ff1ce, 0xe7978f}, /* U+75CF [2000] */ + {0x8ff1cf, 0xe79793}, /* U+75D3 [2000] */ + {0x8ff1d0, 0xe7979d}, /* U+75DD [2000] */ + {0x8ff1d1, 0xe7979f}, /* U+75DF [2000] */ + {0x8ff1d2, 0xe797a0}, /* U+75E0 [2000] */ + {0x8ff1d3, 0xe797a7}, /* U+75E7 [2000] */ + {0x8ff1d4, 0xe797ac}, /* U+75EC [2000] */ + {0x8ff1d5, 0xe797ae}, /* U+75EE [2000] */ + {0x8ff1d6, 0xe797b1}, /* U+75F1 [2000] */ + {0x8ff1d7, 0xe797b9}, /* U+75F9 [2000] */ + {0x8ff1d8, 0xe79883}, /* U+7603 [2000] */ + {0x8ff1d9, 0xe79898}, /* U+7618 [2000] */ + {0x8ff1da, 0xe79887}, /* U+7607 [2000] */ + {0x8ff1db, 0xe7988f}, /* U+760F [2000] */ + {0x8ff1dc, 0xe3beae}, /* U+3FAE [2000] */ {0x8ff1dd, 0xf0a4b88e}, /* U+24E0E [2000] [Unicode3.1] */ - {0x8ff1de, 0x00e79893}, /* U+7613 [2000] */ - {0x8ff1df, 0x00e7989b}, /* U+761B [2000] */ - {0x8ff1e0, 0x00e7989c}, /* U+761C [2000] */ + {0x8ff1de, 0xe79893}, /* U+7613 [2000] */ + {0x8ff1df, 0xe7989b}, /* U+761B [2000] */ + {0x8ff1e0, 0xe7989c}, /* U+761C [2000] */ {0x8ff1e1, 0xf0a4b8b7}, /* U+24E37 [2000] [Unicode3.1] */ - {0x8ff1e2, 0x00e798a5}, /* U+7625 [2000] */ - {0x8ff1e3, 0x00e798a8}, /* U+7628 [2000] */ - {0x8ff1e4, 0x00e798bc}, /* U+763C [2000] */ - {0x8ff1e5, 0x00e798b3}, /* U+7633 [2000] */ + {0x8ff1e2, 0xe798a5}, /* U+7625 [2000] */ + {0x8ff1e3, 0xe798a8}, /* U+7628 [2000] */ + {0x8ff1e4, 0xe798bc}, /* U+763C [2000] */ + {0x8ff1e5, 0xe798b3}, /* U+7633 [2000] */ {0x8ff1e6, 0xf0a4b9aa}, /* U+24E6A [2000] [Unicode3.1] */ - {0x8ff1e7, 0x00e3bf89}, /* U+3FC9 [2000] */ - {0x8ff1e8, 0x00e79981}, /* U+7641 [2000] */ + {0x8ff1e7, 0xe3bf89}, /* U+3FC9 [2000] */ + {0x8ff1e8, 0xe79981}, /* U+7641 [2000] */ {0x8ff1e9, 0xf0a4ba8b}, /* U+24E8B [2000] [Unicode3.1] */ - {0x8ff1ea, 0x00e79989}, /* U+7649 [2000] */ - {0x8ff1eb, 0x00e79995}, /* U+7655 [2000] */ - {0x8ff1ec, 0x00e3bf97}, /* U+3FD7 [2000] */ - {0x8ff1ed, 0x00e799ae}, /* U+766E [2000] */ - {0x8ff1ee, 0x00e79a95}, /* U+7695 [2000] */ - {0x8ff1ef, 0x00e79a9c}, /* U+769C [2000] */ - {0x8ff1f0, 0x00e79aa1}, /* U+76A1 [2000] */ - {0x8ff1f1, 0x00e79aa0}, /* U+76A0 [2000] */ - {0x8ff1f2, 0x00e79aa7}, /* U+76A7 [2000] */ - {0x8ff1f3, 0x00e79aa8}, /* U+76A8 [2000] */ - {0x8ff1f4, 0x00e79aaf}, /* U+76AF [2000] */ + {0x8ff1ea, 0xe79989}, /* U+7649 [2000] */ + {0x8ff1eb, 0xe79995}, /* U+7655 [2000] */ + {0x8ff1ec, 0xe3bf97}, /* U+3FD7 [2000] */ + {0x8ff1ed, 0xe799ae}, /* U+766E [2000] */ + {0x8ff1ee, 0xe79a95}, /* U+7695 [2000] */ + {0x8ff1ef, 0xe79a9c}, /* U+769C [2000] */ + {0x8ff1f0, 0xe79aa1}, /* U+76A1 [2000] */ + {0x8ff1f1, 0xe79aa0}, /* U+76A0 [2000] */ + {0x8ff1f2, 0xe79aa7}, /* U+76A7 [2000] */ + {0x8ff1f3, 0xe79aa8}, /* U+76A8 [2000] */ + {0x8ff1f4, 0xe79aaf}, /* U+76AF [2000] */ {0x8ff1f5, 0xf0a5818a}, /* U+2504A [2000] [Unicode3.1] */ - {0x8ff1f6, 0x00e79b89}, /* U+76C9 [2000] */ + {0x8ff1f6, 0xe79b89}, /* U+76C9 [2000] */ {0x8ff1f7, 0xf0a58195}, /* U+25055 [2000] [Unicode3.1] */ - {0x8ff1f8, 0x00e79ba8}, /* U+76E8 [2000] */ - {0x8ff1f9, 0x00e79bac}, /* U+76EC [2000] */ + {0x8ff1f8, 0xe79ba8}, /* U+76E8 [2000] */ + {0x8ff1f9, 0xe79bac}, /* U+76EC [2000] */ {0x8ff1fa, 0xf0a584a2}, /* U+25122 [2000] [Unicode3.1] */ - {0x8ff1fb, 0x00e79c97}, /* U+7717 [2000] */ - {0x8ff1fc, 0x00e79c9a}, /* U+771A [2000] */ - {0x8ff1fd, 0x00e79cad}, /* U+772D [2000] */ - {0x8ff1fe, 0x00e79cb5}, /* U+7735 [2000] */ + {0x8ff1fb, 0xe79c97}, /* U+7717 [2000] */ + {0x8ff1fc, 0xe79c9a}, /* U+771A [2000] */ + {0x8ff1fd, 0xe79cad}, /* U+772D [2000] */ + {0x8ff1fe, 0xe79cb5}, /* U+7735 [2000] */ {0x8ff2a1, 0xf0a586a9}, /* U+251A9 [2000] [Unicode3.1] */ - {0x8ff2a2, 0x00e480b9}, /* U+4039 [2000] */ + {0x8ff2a2, 0xe480b9}, /* U+4039 [2000] */ {0x8ff2a3, 0xf0a587a5}, /* U+251E5 [2000] [Unicode3.1] */ {0x8ff2a4, 0xf0a5878d}, /* U+251CD [2000] [Unicode3.1] */ - {0x8ff2a5, 0x00e79d98}, /* U+7758 [2000] */ - {0x8ff2a6, 0x00e79da0}, /* U+7760 [2000] */ - {0x8ff2a7, 0x00e79daa}, /* U+776A [2000] */ + {0x8ff2a5, 0xe79d98}, /* U+7758 [2000] */ + {0x8ff2a6, 0xe79da0}, /* U+7760 [2000] */ + {0x8ff2a7, 0xe79daa}, /* U+776A [2000] */ {0x8ff2a8, 0xf0a5889e}, /* U+2521E [2000] [Unicode3.1] */ - {0x8ff2a9, 0x00e79db2}, /* U+7772 [2000] */ - {0x8ff2aa, 0x00e79dbc}, /* U+777C [2000] */ - {0x8ff2ab, 0x00e79dbd}, /* U+777D [2000] */ + {0x8ff2a9, 0xe79db2}, /* U+7772 [2000] */ + {0x8ff2aa, 0xe79dbc}, /* U+777C [2000] */ + {0x8ff2ab, 0xe79dbd}, /* U+777D [2000] */ {0x8ff2ac, 0xf0a5898c}, /* U+2524C [2000] [Unicode3.1] */ - {0x8ff2ad, 0x00e48198}, /* U+4058 [2000] */ - {0x8ff2ae, 0x00e79e9a}, /* U+779A [2000] */ - {0x8ff2af, 0x00e79e9f}, /* U+779F [2000] */ - {0x8ff2b0, 0x00e79ea2}, /* U+77A2 [2000] */ - {0x8ff2b1, 0x00e79ea4}, /* U+77A4 [2000] */ - {0x8ff2b2, 0x00e79ea9}, /* U+77A9 [2000] */ - {0x8ff2b3, 0x00e79f9e}, /* U+77DE [2000] */ - {0x8ff2b4, 0x00e79f9f}, /* U+77DF [2000] */ - {0x8ff2b5, 0x00e79fa4}, /* U+77E4 [2000] */ - {0x8ff2b6, 0x00e79fa6}, /* U+77E6 [2000] */ - {0x8ff2b7, 0x00e79faa}, /* U+77EA [2000] */ - {0x8ff2b8, 0x00e79fac}, /* U+77EC [2000] */ - {0x8ff2b9, 0x00e48293}, /* U+4093 [2000] */ - {0x8ff2ba, 0x00e79fb0}, /* U+77F0 [2000] */ - {0x8ff2bb, 0x00e79fb4}, /* U+77F4 [2000] */ - {0x8ff2bc, 0x00e79fbb}, /* U+77FB [2000] */ + {0x8ff2ad, 0xe48198}, /* U+4058 [2000] */ + {0x8ff2ae, 0xe79e9a}, /* U+779A [2000] */ + {0x8ff2af, 0xe79e9f}, /* U+779F [2000] */ + {0x8ff2b0, 0xe79ea2}, /* U+77A2 [2000] */ + {0x8ff2b1, 0xe79ea4}, /* U+77A4 [2000] */ + {0x8ff2b2, 0xe79ea9}, /* U+77A9 [2000] */ + {0x8ff2b3, 0xe79f9e}, /* U+77DE [2000] */ + {0x8ff2b4, 0xe79f9f}, /* U+77DF [2000] */ + {0x8ff2b5, 0xe79fa4}, /* U+77E4 [2000] */ + {0x8ff2b6, 0xe79fa6}, /* U+77E6 [2000] */ + {0x8ff2b7, 0xe79faa}, /* U+77EA [2000] */ + {0x8ff2b8, 0xe79fac}, /* U+77EC [2000] */ + {0x8ff2b9, 0xe48293}, /* U+4093 [2000] */ + {0x8ff2ba, 0xe79fb0}, /* U+77F0 [2000] */ + {0x8ff2bb, 0xe79fb4}, /* U+77F4 [2000] */ + {0x8ff2bc, 0xe79fbb}, /* U+77FB [2000] */ {0x8ff2bd, 0xf0a590ae}, /* U+2542E [2000] [Unicode3.1] */ - {0x8ff2be, 0x00e7a085}, /* U+7805 [2000] */ - {0x8ff2bf, 0x00e7a086}, /* U+7806 [2000] */ - {0x8ff2c0, 0x00e7a089}, /* U+7809 [2000] */ - {0x8ff2c1, 0x00e7a08d}, /* U+780D [2000] */ - {0x8ff2c2, 0x00e7a099}, /* U+7819 [2000] */ - {0x8ff2c3, 0x00e7a0a1}, /* U+7821 [2000] */ - {0x8ff2c4, 0x00e7a0ac}, /* U+782C [2000] */ - {0x8ff2c5, 0x00e7a187}, /* U+7847 [2000] */ - {0x8ff2c6, 0x00e7a1a4}, /* U+7864 [2000] */ - {0x8ff2c7, 0x00e7a1aa}, /* U+786A [2000] */ + {0x8ff2be, 0xe7a085}, /* U+7805 [2000] */ + {0x8ff2bf, 0xe7a086}, /* U+7806 [2000] */ + {0x8ff2c0, 0xe7a089}, /* U+7809 [2000] */ + {0x8ff2c1, 0xe7a08d}, /* U+780D [2000] */ + {0x8ff2c2, 0xe7a099}, /* U+7819 [2000] */ + {0x8ff2c3, 0xe7a0a1}, /* U+7821 [2000] */ + {0x8ff2c4, 0xe7a0ac}, /* U+782C [2000] */ + {0x8ff2c5, 0xe7a187}, /* U+7847 [2000] */ + {0x8ff2c6, 0xe7a1a4}, /* U+7864 [2000] */ + {0x8ff2c7, 0xe7a1aa}, /* U+786A [2000] */ {0x8ff2c8, 0xf0a59399}, /* U+254D9 [2000] [Unicode3.1] */ - {0x8ff2c9, 0x00e7a28a}, /* U+788A [2000] */ - {0x8ff2ca, 0x00e7a294}, /* U+7894 [2000] */ - {0x8ff2cb, 0x00e7a2a4}, /* U+78A4 [2000] */ - {0x8ff2cc, 0x00e7a29d}, /* U+789D [2000] */ - {0x8ff2cd, 0x00e7a29e}, /* U+789E [2000] */ - {0x8ff2ce, 0x00e7a29f}, /* U+789F [2000] */ - {0x8ff2cf, 0x00e7a2bb}, /* U+78BB [2000] */ - {0x8ff2d0, 0x00e7a388}, /* U+78C8 [2000] */ - {0x8ff2d1, 0x00e7a38c}, /* U+78CC [2000] */ - {0x8ff2d2, 0x00e7a38e}, /* U+78CE [2000] */ - {0x8ff2d3, 0x00e7a395}, /* U+78D5 [2000] */ - {0x8ff2d4, 0x00e7a3a0}, /* U+78E0 [2000] */ - {0x8ff2d5, 0x00e7a3a1}, /* U+78E1 [2000] */ - {0x8ff2d6, 0x00e7a3a6}, /* U+78E6 [2000] */ - {0x8ff2d7, 0x00e7a3b9}, /* U+78F9 [2000] */ - {0x8ff2d8, 0x00e7a3ba}, /* U+78FA [2000] */ - {0x8ff2d9, 0x00e7a3bb}, /* U+78FB [2000] */ - {0x8ff2da, 0x00e7a3be}, /* U+78FE [2000] */ + {0x8ff2c9, 0xe7a28a}, /* U+788A [2000] */ + {0x8ff2ca, 0xe7a294}, /* U+7894 [2000] */ + {0x8ff2cb, 0xe7a2a4}, /* U+78A4 [2000] */ + {0x8ff2cc, 0xe7a29d}, /* U+789D [2000] */ + {0x8ff2cd, 0xe7a29e}, /* U+789E [2000] */ + {0x8ff2ce, 0xe7a29f}, /* U+789F [2000] */ + {0x8ff2cf, 0xe7a2bb}, /* U+78BB [2000] */ + {0x8ff2d0, 0xe7a388}, /* U+78C8 [2000] */ + {0x8ff2d1, 0xe7a38c}, /* U+78CC [2000] */ + {0x8ff2d2, 0xe7a38e}, /* U+78CE [2000] */ + {0x8ff2d3, 0xe7a395}, /* U+78D5 [2000] */ + {0x8ff2d4, 0xe7a3a0}, /* U+78E0 [2000] */ + {0x8ff2d5, 0xe7a3a1}, /* U+78E1 [2000] */ + {0x8ff2d6, 0xe7a3a6}, /* U+78E6 [2000] */ + {0x8ff2d7, 0xe7a3b9}, /* U+78F9 [2000] */ + {0x8ff2d8, 0xe7a3ba}, /* U+78FA [2000] */ + {0x8ff2d9, 0xe7a3bb}, /* U+78FB [2000] */ + {0x8ff2da, 0xe7a3be}, /* U+78FE [2000] */ {0x8ff2db, 0xf0a596a7}, /* U+255A7 [2000] [Unicode3.1] */ - {0x8ff2dc, 0x00e7a490}, /* U+7910 [2000] */ - {0x8ff2dd, 0x00e7a49b}, /* U+791B [2000] */ - {0x8ff2de, 0x00e7a4b0}, /* U+7930 [2000] */ - {0x8ff2df, 0x00e7a4a5}, /* U+7925 [2000] */ - {0x8ff2e0, 0x00e7a4bb}, /* U+793B [2000] */ - {0x8ff2e1, 0x00e7a58a}, /* U+794A [2000] */ - {0x8ff2e2, 0x00e7a598}, /* U+7958 [2000] */ - {0x8ff2e3, 0x00e7a59b}, /* U+795B [2000] */ - {0x8ff2e4, 0x00e48485}, /* U+4105 [2000] */ - {0x8ff2e5, 0x00e7a5a7}, /* U+7967 [2000] */ - {0x8ff2e6, 0x00e7a5b2}, /* U+7972 [2000] */ - {0x8ff2e7, 0x00e7a694}, /* U+7994 [2000] */ - {0x8ff2e8, 0x00e7a695}, /* U+7995 [2000] */ - {0x8ff2e9, 0x00e7a696}, /* U+7996 [2000] */ - {0x8ff2ea, 0x00e7a69b}, /* U+799B [2000] */ - {0x8ff2eb, 0x00e7a6a1}, /* U+79A1 [2000] */ - {0x8ff2ec, 0x00e7a6a9}, /* U+79A9 [2000] */ - {0x8ff2ed, 0x00e7a6b4}, /* U+79B4 [2000] */ - {0x8ff2ee, 0x00e7a6bb}, /* U+79BB [2000] */ - {0x8ff2ef, 0x00e7a782}, /* U+79C2 [2000] */ - {0x8ff2f0, 0x00e7a787}, /* U+79C7 [2000] */ - {0x8ff2f1, 0x00e7a78c}, /* U+79CC [2000] */ - {0x8ff2f2, 0x00e7a78d}, /* U+79CD [2000] */ - {0x8ff2f3, 0x00e7a796}, /* U+79D6 [2000] */ - {0x8ff2f4, 0x00e48588}, /* U+4148 [2000] */ + {0x8ff2dc, 0xe7a490}, /* U+7910 [2000] */ + {0x8ff2dd, 0xe7a49b}, /* U+791B [2000] */ + {0x8ff2de, 0xe7a4b0}, /* U+7930 [2000] */ + {0x8ff2df, 0xe7a4a5}, /* U+7925 [2000] */ + {0x8ff2e0, 0xe7a4bb}, /* U+793B [2000] */ + {0x8ff2e1, 0xe7a58a}, /* U+794A [2000] */ + {0x8ff2e2, 0xe7a598}, /* U+7958 [2000] */ + {0x8ff2e3, 0xe7a59b}, /* U+795B [2000] */ + {0x8ff2e4, 0xe48485}, /* U+4105 [2000] */ + {0x8ff2e5, 0xe7a5a7}, /* U+7967 [2000] */ + {0x8ff2e6, 0xe7a5b2}, /* U+7972 [2000] */ + {0x8ff2e7, 0xe7a694}, /* U+7994 [2000] */ + {0x8ff2e8, 0xe7a695}, /* U+7995 [2000] */ + {0x8ff2e9, 0xe7a696}, /* U+7996 [2000] */ + {0x8ff2ea, 0xe7a69b}, /* U+799B [2000] */ + {0x8ff2eb, 0xe7a6a1}, /* U+79A1 [2000] */ + {0x8ff2ec, 0xe7a6a9}, /* U+79A9 [2000] */ + {0x8ff2ed, 0xe7a6b4}, /* U+79B4 [2000] */ + {0x8ff2ee, 0xe7a6bb}, /* U+79BB [2000] */ + {0x8ff2ef, 0xe7a782}, /* U+79C2 [2000] */ + {0x8ff2f0, 0xe7a787}, /* U+79C7 [2000] */ + {0x8ff2f1, 0xe7a78c}, /* U+79CC [2000] */ + {0x8ff2f2, 0xe7a78d}, /* U+79CD [2000] */ + {0x8ff2f3, 0xe7a796}, /* U+79D6 [2000] */ + {0x8ff2f4, 0xe48588}, /* U+4148 [2000] */ {0x8ff2f5, 0xf0a59ea9}, /* U+257A9 [2000] [Unicode3.1] */ {0x8ff2f6, 0xf0a59eb4}, /* U+257B4 [2000] [Unicode3.1] */ - {0x8ff2f7, 0x00e4858f}, /* U+414F [2000] */ - {0x8ff2f8, 0x00e7a88a}, /* U+7A0A [2000] */ - {0x8ff2f9, 0x00e7a891}, /* U+7A11 [2000] */ - {0x8ff2fa, 0x00e7a895}, /* U+7A15 [2000] */ - {0x8ff2fb, 0x00e7a89b}, /* U+7A1B [2000] */ - {0x8ff2fc, 0x00e7a89e}, /* U+7A1E [2000] */ - {0x8ff2fd, 0x00e485a3}, /* U+4163 [2000] */ - {0x8ff2fe, 0x00e7a8ad}, /* U+7A2D [2000] */ - {0x8ff3a1, 0x00e7a8b8}, /* U+7A38 [2000] */ - {0x8ff3a2, 0x00e7a987}, /* U+7A47 [2000] */ - {0x8ff3a3, 0x00e7a98c}, /* U+7A4C [2000] */ - {0x8ff3a4, 0x00e7a996}, /* U+7A56 [2000] */ - {0x8ff3a5, 0x00e7a999}, /* U+7A59 [2000] */ - {0x8ff3a6, 0x00e7a99c}, /* U+7A5C [2000] */ - {0x8ff3a7, 0x00e7a99f}, /* U+7A5F [2000] */ - {0x8ff3a8, 0x00e7a9a0}, /* U+7A60 [2000] */ - {0x8ff3a9, 0x00e7a9a7}, /* U+7A67 [2000] */ - {0x8ff3aa, 0x00e7a9aa}, /* U+7A6A [2000] */ - {0x8ff3ab, 0x00e7a9b5}, /* U+7A75 [2000] */ - {0x8ff3ac, 0x00e7a9b8}, /* U+7A78 [2000] */ - {0x8ff3ad, 0x00e7aa82}, /* U+7A82 [2000] */ - {0x8ff3ae, 0x00e7aa8a}, /* U+7A8A [2000] */ - {0x8ff3af, 0x00e7aa90}, /* U+7A90 [2000] */ - {0x8ff3b0, 0x00e7aaa3}, /* U+7AA3 [2000] */ - {0x8ff3b1, 0x00e7aaac}, /* U+7AAC [2000] */ + {0x8ff2f7, 0xe4858f}, /* U+414F [2000] */ + {0x8ff2f8, 0xe7a88a}, /* U+7A0A [2000] */ + {0x8ff2f9, 0xe7a891}, /* U+7A11 [2000] */ + {0x8ff2fa, 0xe7a895}, /* U+7A15 [2000] */ + {0x8ff2fb, 0xe7a89b}, /* U+7A1B [2000] */ + {0x8ff2fc, 0xe7a89e}, /* U+7A1E [2000] */ + {0x8ff2fd, 0xe485a3}, /* U+4163 [2000] */ + {0x8ff2fe, 0xe7a8ad}, /* U+7A2D [2000] */ + {0x8ff3a1, 0xe7a8b8}, /* U+7A38 [2000] */ + {0x8ff3a2, 0xe7a987}, /* U+7A47 [2000] */ + {0x8ff3a3, 0xe7a98c}, /* U+7A4C [2000] */ + {0x8ff3a4, 0xe7a996}, /* U+7A56 [2000] */ + {0x8ff3a5, 0xe7a999}, /* U+7A59 [2000] */ + {0x8ff3a6, 0xe7a99c}, /* U+7A5C [2000] */ + {0x8ff3a7, 0xe7a99f}, /* U+7A5F [2000] */ + {0x8ff3a8, 0xe7a9a0}, /* U+7A60 [2000] */ + {0x8ff3a9, 0xe7a9a7}, /* U+7A67 [2000] */ + {0x8ff3aa, 0xe7a9aa}, /* U+7A6A [2000] */ + {0x8ff3ab, 0xe7a9b5}, /* U+7A75 [2000] */ + {0x8ff3ac, 0xe7a9b8}, /* U+7A78 [2000] */ + {0x8ff3ad, 0xe7aa82}, /* U+7A82 [2000] */ + {0x8ff3ae, 0xe7aa8a}, /* U+7A8A [2000] */ + {0x8ff3af, 0xe7aa90}, /* U+7A90 [2000] */ + {0x8ff3b0, 0xe7aaa3}, /* U+7AA3 [2000] */ + {0x8ff3b1, 0xe7aaac}, /* U+7AAC [2000] */ {0x8ff3b2, 0xf0a5a794}, /* U+259D4 [2000] [Unicode3.1] */ - {0x8ff3b3, 0x00e486b4}, /* U+41B4 [2000] */ - {0x8ff3b4, 0x00e7aab9}, /* U+7AB9 [2000] */ - {0x8ff3b5, 0x00e7aabc}, /* U+7ABC [2000] */ - {0x8ff3b6, 0x00e7aabe}, /* U+7ABE [2000] */ - {0x8ff3b7, 0x00e486bf}, /* U+41BF [2000] */ - {0x8ff3b8, 0x00e7ab8c}, /* U+7ACC [2000] */ - {0x8ff3b9, 0x00e7ab91}, /* U+7AD1 [2000] */ - {0x8ff3ba, 0x00e7aba7}, /* U+7AE7 [2000] */ - {0x8ff3bb, 0x00e7aba8}, /* U+7AE8 [2000] */ - {0x8ff3bc, 0x00e7abb4}, /* U+7AF4 [2000] */ + {0x8ff3b3, 0xe486b4}, /* U+41B4 [2000] */ + {0x8ff3b4, 0xe7aab9}, /* U+7AB9 [2000] */ + {0x8ff3b5, 0xe7aabc}, /* U+7ABC [2000] */ + {0x8ff3b6, 0xe7aabe}, /* U+7ABE [2000] */ + {0x8ff3b7, 0xe486bf}, /* U+41BF [2000] */ + {0x8ff3b8, 0xe7ab8c}, /* U+7ACC [2000] */ + {0x8ff3b9, 0xe7ab91}, /* U+7AD1 [2000] */ + {0x8ff3ba, 0xe7aba7}, /* U+7AE7 [2000] */ + {0x8ff3bb, 0xe7aba8}, /* U+7AE8 [2000] */ + {0x8ff3bc, 0xe7abb4}, /* U+7AF4 [2000] */ {0x8ff3bd, 0xf0a5aba4}, /* U+25AE4 [2000] [Unicode3.1] */ {0x8ff3be, 0xf0a5aba3}, /* U+25AE3 [2000] [Unicode3.1] */ - {0x8ff3bf, 0x00e7ac87}, /* U+7B07 [2000] */ + {0x8ff3bf, 0xe7ac87}, /* U+7B07 [2000] */ {0x8ff3c0, 0xf0a5abb1}, /* U+25AF1 [2000] [Unicode3.1] */ - {0x8ff3c1, 0x00e7acbd}, /* U+7B3D [2000] */ - {0x8ff3c2, 0x00e7aca7}, /* U+7B27 [2000] */ - {0x8ff3c3, 0x00e7acaa}, /* U+7B2A [2000] */ - {0x8ff3c4, 0x00e7acae}, /* U+7B2E [2000] */ - {0x8ff3c5, 0x00e7acaf}, /* U+7B2F [2000] */ - {0x8ff3c6, 0x00e7acb1}, /* U+7B31 [2000] */ - {0x8ff3c7, 0x00e487a6}, /* U+41E6 [2000] */ - {0x8ff3c8, 0x00e487b3}, /* U+41F3 [2000] */ - {0x8ff3c9, 0x00e7adbf}, /* U+7B7F [2000] */ - {0x8ff3ca, 0x00e7ad81}, /* U+7B41 [2000] */ - {0x8ff3cb, 0x00e487ae}, /* U+41EE [2000] */ - {0x8ff3cc, 0x00e7ad95}, /* U+7B55 [2000] */ - {0x8ff3cd, 0x00e7adb9}, /* U+7B79 [2000] */ - {0x8ff3ce, 0x00e7ada4}, /* U+7B64 [2000] */ - {0x8ff3cf, 0x00e7ada6}, /* U+7B66 [2000] */ - {0x8ff3d0, 0x00e7ada9}, /* U+7B69 [2000] */ - {0x8ff3d1, 0x00e7adb3}, /* U+7B73 [2000] */ + {0x8ff3c1, 0xe7acbd}, /* U+7B3D [2000] */ + {0x8ff3c2, 0xe7aca7}, /* U+7B27 [2000] */ + {0x8ff3c3, 0xe7acaa}, /* U+7B2A [2000] */ + {0x8ff3c4, 0xe7acae}, /* U+7B2E [2000] */ + {0x8ff3c5, 0xe7acaf}, /* U+7B2F [2000] */ + {0x8ff3c6, 0xe7acb1}, /* U+7B31 [2000] */ + {0x8ff3c7, 0xe487a6}, /* U+41E6 [2000] */ + {0x8ff3c8, 0xe487b3}, /* U+41F3 [2000] */ + {0x8ff3c9, 0xe7adbf}, /* U+7B7F [2000] */ + {0x8ff3ca, 0xe7ad81}, /* U+7B41 [2000] */ + {0x8ff3cb, 0xe487ae}, /* U+41EE [2000] */ + {0x8ff3cc, 0xe7ad95}, /* U+7B55 [2000] */ + {0x8ff3cd, 0xe7adb9}, /* U+7B79 [2000] */ + {0x8ff3ce, 0xe7ada4}, /* U+7B64 [2000] */ + {0x8ff3cf, 0xe7ada6}, /* U+7B66 [2000] */ + {0x8ff3d0, 0xe7ada9}, /* U+7B69 [2000] */ + {0x8ff3d1, 0xe7adb3}, /* U+7B73 [2000] */ {0x8ff3d2, 0xf0a5aeb2}, /* U+25BB2 [2000] [Unicode3.1] */ - {0x8ff3d3, 0x00e48887}, /* U+4207 [2000] */ - {0x8ff3d4, 0x00e7ae90}, /* U+7B90 [2000] */ - {0x8ff3d5, 0x00e7ae91}, /* U+7B91 [2000] */ - {0x8ff3d6, 0x00e7ae9b}, /* U+7B9B [2000] */ - {0x8ff3d7, 0x00e4888e}, /* U+420E [2000] */ - {0x8ff3d8, 0x00e7aeaf}, /* U+7BAF [2000] */ - {0x8ff3d9, 0x00e7aeb5}, /* U+7BB5 [2000] */ - {0x8ff3da, 0x00e7aebc}, /* U+7BBC [2000] */ - {0x8ff3db, 0x00e7af85}, /* U+7BC5 [2000] */ - {0x8ff3dc, 0x00e7af8a}, /* U+7BCA [2000] */ + {0x8ff3d3, 0xe48887}, /* U+4207 [2000] */ + {0x8ff3d4, 0xe7ae90}, /* U+7B90 [2000] */ + {0x8ff3d5, 0xe7ae91}, /* U+7B91 [2000] */ + {0x8ff3d6, 0xe7ae9b}, /* U+7B9B [2000] */ + {0x8ff3d7, 0xe4888e}, /* U+420E [2000] */ + {0x8ff3d8, 0xe7aeaf}, /* U+7BAF [2000] */ + {0x8ff3d9, 0xe7aeb5}, /* U+7BB5 [2000] */ + {0x8ff3da, 0xe7aebc}, /* U+7BBC [2000] */ + {0x8ff3db, 0xe7af85}, /* U+7BC5 [2000] */ + {0x8ff3dc, 0xe7af8a}, /* U+7BCA [2000] */ {0x8ff3dd, 0xf0a5b18b}, /* U+25C4B [2000] [Unicode3.1] */ {0x8ff3de, 0xf0a5b1a4}, /* U+25C64 [2000] [Unicode3.1] */ - {0x8ff3df, 0x00e7af94}, /* U+7BD4 [2000] */ - {0x8ff3e0, 0x00e7af96}, /* U+7BD6 [2000] */ - {0x8ff3e1, 0x00e7af9a}, /* U+7BDA [2000] */ - {0x8ff3e2, 0x00e7afaa}, /* U+7BEA [2000] */ - {0x8ff3e3, 0x00e7afb0}, /* U+7BF0 [2000] */ - {0x8ff3e4, 0x00e7b083}, /* U+7C03 [2000] */ - {0x8ff3e5, 0x00e7b08b}, /* U+7C0B [2000] */ - {0x8ff3e6, 0x00e7b08e}, /* U+7C0E [2000] */ - {0x8ff3e7, 0x00e7b08f}, /* U+7C0F [2000] */ - {0x8ff3e8, 0x00e7b0a6}, /* U+7C26 [2000] */ - {0x8ff3e9, 0x00e7b185}, /* U+7C45 [2000] */ - {0x8ff3ea, 0x00e7b18a}, /* U+7C4A [2000] */ - {0x8ff3eb, 0x00e7b191}, /* U+7C51 [2000] */ - {0x8ff3ec, 0x00e7b197}, /* U+7C57 [2000] */ - {0x8ff3ed, 0x00e7b19e}, /* U+7C5E [2000] */ - {0x8ff3ee, 0x00e7b1a1}, /* U+7C61 [2000] */ - {0x8ff3ef, 0x00e7b1a9}, /* U+7C69 [2000] */ - {0x8ff3f0, 0x00e7b1ae}, /* U+7C6E [2000] */ - {0x8ff3f1, 0x00e7b1af}, /* U+7C6F [2000] */ - {0x8ff3f2, 0x00e7b1b0}, /* U+7C70 [2000] */ + {0x8ff3df, 0xe7af94}, /* U+7BD4 [2000] */ + {0x8ff3e0, 0xe7af96}, /* U+7BD6 [2000] */ + {0x8ff3e1, 0xe7af9a}, /* U+7BDA [2000] */ + {0x8ff3e2, 0xe7afaa}, /* U+7BEA [2000] */ + {0x8ff3e3, 0xe7afb0}, /* U+7BF0 [2000] */ + {0x8ff3e4, 0xe7b083}, /* U+7C03 [2000] */ + {0x8ff3e5, 0xe7b08b}, /* U+7C0B [2000] */ + {0x8ff3e6, 0xe7b08e}, /* U+7C0E [2000] */ + {0x8ff3e7, 0xe7b08f}, /* U+7C0F [2000] */ + {0x8ff3e8, 0xe7b0a6}, /* U+7C26 [2000] */ + {0x8ff3e9, 0xe7b185}, /* U+7C45 [2000] */ + {0x8ff3ea, 0xe7b18a}, /* U+7C4A [2000] */ + {0x8ff3eb, 0xe7b191}, /* U+7C51 [2000] */ + {0x8ff3ec, 0xe7b197}, /* U+7C57 [2000] */ + {0x8ff3ed, 0xe7b19e}, /* U+7C5E [2000] */ + {0x8ff3ee, 0xe7b1a1}, /* U+7C61 [2000] */ + {0x8ff3ef, 0xe7b1a9}, /* U+7C69 [2000] */ + {0x8ff3f0, 0xe7b1ae}, /* U+7C6E [2000] */ + {0x8ff3f1, 0xe7b1af}, /* U+7C6F [2000] */ + {0x8ff3f2, 0xe7b1b0}, /* U+7C70 [2000] */ {0x8ff3f3, 0xf0a5b8ae}, /* U+25E2E [2000] [Unicode3.1] */ {0x8ff3f4, 0xf0a5b996}, /* U+25E56 [2000] [Unicode3.1] */ {0x8ff3f5, 0xf0a5b9a5}, /* U+25E65 [2000] [Unicode3.1] */ - {0x8ff3f6, 0x00e7b2a6}, /* U+7CA6 [2000] */ + {0x8ff3f6, 0xe7b2a6}, /* U+7CA6 [2000] */ {0x8ff3f7, 0xf0a5b9a2}, /* U+25E62 [2000] [Unicode3.1] */ - {0x8ff3f8, 0x00e7b2b6}, /* U+7CB6 [2000] */ - {0x8ff3f9, 0x00e7b2b7}, /* U+7CB7 [2000] */ - {0x8ff3fa, 0x00e7b2bf}, /* U+7CBF [2000] */ + {0x8ff3f8, 0xe7b2b6}, /* U+7CB6 [2000] */ + {0x8ff3f9, 0xe7b2b7}, /* U+7CB7 [2000] */ + {0x8ff3fa, 0xe7b2bf}, /* U+7CBF [2000] */ {0x8ff3fb, 0xf0a5bb98}, /* U+25ED8 [2000] [Unicode3.1] */ - {0x8ff3fc, 0x00e7b384}, /* U+7CC4 [2000] */ + {0x8ff3fc, 0xe7b384}, /* U+7CC4 [2000] */ {0x8ff3fd, 0xf0a5bb82}, /* U+25EC2 [2000] [Unicode3.1] */ - {0x8ff3fe, 0x00e7b388}, /* U+7CC8 [2000] */ - {0x8ff4a1, 0x00e7b38d}, /* U+7CCD [2000] */ + {0x8ff3fe, 0xe7b388}, /* U+7CC8 [2000] */ + {0x8ff4a1, 0xe7b38d}, /* U+7CCD [2000] */ {0x8ff4a2, 0xf0a5bba8}, /* U+25EE8 [2000] [Unicode3.1] */ - {0x8ff4a3, 0x00e7b397}, /* U+7CD7 [2000] */ + {0x8ff4a3, 0xe7b397}, /* U+7CD7 [2000] */ {0x8ff4a4, 0xf0a5bca3}, /* U+25F23 [2000] [Unicode3.1] */ - {0x8ff4a5, 0x00e7b3a6}, /* U+7CE6 [2000] */ - {0x8ff4a6, 0x00e7b3ab}, /* U+7CEB [2000] */ + {0x8ff4a5, 0xe7b3a6}, /* U+7CE6 [2000] */ + {0x8ff4a6, 0xe7b3ab}, /* U+7CEB [2000] */ {0x8ff4a7, 0xf0a5bd9c}, /* U+25F5C [2000] [Unicode3.1] */ - {0x8ff4a8, 0x00e7b3b5}, /* U+7CF5 [2000] */ - {0x8ff4a9, 0x00e7b483}, /* U+7D03 [2000] */ - {0x8ff4aa, 0x00e7b489}, /* U+7D09 [2000] */ - {0x8ff4ab, 0x00e48b86}, /* U+42C6 [2000] */ - {0x8ff4ac, 0x00e7b492}, /* U+7D12 [2000] */ - {0x8ff4ad, 0x00e7b49e}, /* U+7D1E [2000] */ + {0x8ff4a8, 0xe7b3b5}, /* U+7CF5 [2000] */ + {0x8ff4a9, 0xe7b483}, /* U+7D03 [2000] */ + {0x8ff4aa, 0xe7b489}, /* U+7D09 [2000] */ + {0x8ff4ab, 0xe48b86}, /* U+42C6 [2000] */ + {0x8ff4ac, 0xe7b492}, /* U+7D12 [2000] */ + {0x8ff4ad, 0xe7b49e}, /* U+7D1E [2000] */ {0x8ff4ae, 0xf0a5bfa0}, /* U+25FE0 [2000] [Unicode3.1] */ {0x8ff4af, 0xf0a5bf94}, /* U+25FD4 [2000] [Unicode3.1] */ - {0x8ff4b0, 0x00e7b4bd}, /* U+7D3D [2000] */ - {0x8ff4b1, 0x00e7b4be}, /* U+7D3E [2000] */ - {0x8ff4b2, 0x00e7b580}, /* U+7D40 [2000] */ - {0x8ff4b3, 0x00e7b587}, /* U+7D47 [2000] */ + {0x8ff4b0, 0xe7b4bd}, /* U+7D3D [2000] */ + {0x8ff4b1, 0xe7b4be}, /* U+7D3E [2000] */ + {0x8ff4b2, 0xe7b580}, /* U+7D40 [2000] */ + {0x8ff4b3, 0xe7b587}, /* U+7D47 [2000] */ {0x8ff4b4, 0xf0a6808c}, /* U+2600C [2000] [Unicode3.1] */ {0x8ff4b5, 0xf0a5bfbb}, /* U+25FFB [2000] [Unicode3.1] */ - {0x8ff4b6, 0x00e48b96}, /* U+42D6 [2000] */ - {0x8ff4b7, 0x00e7b599}, /* U+7D59 [2000] */ - {0x8ff4b8, 0x00e7b59a}, /* U+7D5A [2000] */ - {0x8ff4b9, 0x00e7b5aa}, /* U+7D6A [2000] */ - {0x8ff4ba, 0x00e7b5b0}, /* U+7D70 [2000] */ - {0x8ff4bb, 0x00e48b9d}, /* U+42DD [2000] */ - {0x8ff4bc, 0x00e7b5bf}, /* U+7D7F [2000] */ + {0x8ff4b6, 0xe48b96}, /* U+42D6 [2000] */ + {0x8ff4b7, 0xe7b599}, /* U+7D59 [2000] */ + {0x8ff4b8, 0xe7b59a}, /* U+7D5A [2000] */ + {0x8ff4b9, 0xe7b5aa}, /* U+7D6A [2000] */ + {0x8ff4ba, 0xe7b5b0}, /* U+7D70 [2000] */ + {0x8ff4bb, 0xe48b9d}, /* U+42DD [2000] */ + {0x8ff4bc, 0xe7b5bf}, /* U+7D7F [2000] */ {0x8ff4bd, 0xf0a68097}, /* U+26017 [2000] [Unicode3.1] */ - {0x8ff4be, 0x00e7b686}, /* U+7D86 [2000] */ - {0x8ff4bf, 0x00e7b688}, /* U+7D88 [2000] */ - {0x8ff4c0, 0x00e7b68c}, /* U+7D8C [2000] */ - {0x8ff4c1, 0x00e7b697}, /* U+7D97 [2000] */ + {0x8ff4be, 0xe7b686}, /* U+7D86 [2000] */ + {0x8ff4bf, 0xe7b688}, /* U+7D88 [2000] */ + {0x8ff4c0, 0xe7b68c}, /* U+7D8C [2000] */ + {0x8ff4c1, 0xe7b697}, /* U+7D97 [2000] */ {0x8ff4c2, 0xf0a681a0}, /* U+26060 [2000] [Unicode3.1] */ - {0x8ff4c3, 0x00e7b69d}, /* U+7D9D [2000] */ - {0x8ff4c4, 0x00e7b6a7}, /* U+7DA7 [2000] */ - {0x8ff4c5, 0x00e7b6aa}, /* U+7DAA [2000] */ - {0x8ff4c6, 0x00e7b6b6}, /* U+7DB6 [2000] */ - {0x8ff4c7, 0x00e7b6b7}, /* U+7DB7 [2000] */ - {0x8ff4c8, 0x00e7b780}, /* U+7DC0 [2000] */ - {0x8ff4c9, 0x00e7b797}, /* U+7DD7 [2000] */ - {0x8ff4ca, 0x00e7b799}, /* U+7DD9 [2000] */ - {0x8ff4cb, 0x00e7b7a6}, /* U+7DE6 [2000] */ - {0x8ff4cc, 0x00e7b7b1}, /* U+7DF1 [2000] */ - {0x8ff4cd, 0x00e7b7b9}, /* U+7DF9 [2000] */ - {0x8ff4ce, 0x00e48c82}, /* U+4302 [2000] */ + {0x8ff4c3, 0xe7b69d}, /* U+7D9D [2000] */ + {0x8ff4c4, 0xe7b6a7}, /* U+7DA7 [2000] */ + {0x8ff4c5, 0xe7b6aa}, /* U+7DAA [2000] */ + {0x8ff4c6, 0xe7b6b6}, /* U+7DB6 [2000] */ + {0x8ff4c7, 0xe7b6b7}, /* U+7DB7 [2000] */ + {0x8ff4c8, 0xe7b780}, /* U+7DC0 [2000] */ + {0x8ff4c9, 0xe7b797}, /* U+7DD7 [2000] */ + {0x8ff4ca, 0xe7b799}, /* U+7DD9 [2000] */ + {0x8ff4cb, 0xe7b7a6}, /* U+7DE6 [2000] */ + {0x8ff4cc, 0xe7b7b1}, /* U+7DF1 [2000] */ + {0x8ff4cd, 0xe7b7b9}, /* U+7DF9 [2000] */ + {0x8ff4ce, 0xe48c82}, /* U+4302 [2000] */ {0x8ff4cf, 0xf0a683ad}, /* U+260ED [2000] [Unicode3.1] */ - {0x8ff4d0, 0x00efa998}, /* U+FA58 CJK COMPATIBILITY IDEOGRAPH-FA58 [2000] [Unicode3.2] */ - {0x8ff4d1, 0x00e7b890}, /* U+7E10 [2000] */ - {0x8ff4d2, 0x00e7b897}, /* U+7E17 [2000] */ - {0x8ff4d3, 0x00e7b89d}, /* U+7E1D [2000] */ - {0x8ff4d4, 0x00e7b8a0}, /* U+7E20 [2000] */ - {0x8ff4d5, 0x00e7b8a7}, /* U+7E27 [2000] */ - {0x8ff4d6, 0x00e7b8ac}, /* U+7E2C [2000] */ - {0x8ff4d7, 0x00e7b985}, /* U+7E45 [2000] */ - {0x8ff4d8, 0x00e7b9b3}, /* U+7E73 [2000] */ - {0x8ff4d9, 0x00e7b9b5}, /* U+7E75 [2000] */ - {0x8ff4da, 0x00e7b9be}, /* U+7E7E [2000] */ - {0x8ff4db, 0x00e7ba86}, /* U+7E86 [2000] */ - {0x8ff4dc, 0x00e7ba87}, /* U+7E87 [2000] */ - {0x8ff4dd, 0x00e48cab}, /* U+432B [2000] */ - {0x8ff4de, 0x00e7ba91}, /* U+7E91 [2000] */ - {0x8ff4df, 0x00e7ba98}, /* U+7E98 [2000] */ - {0x8ff4e0, 0x00e7ba9a}, /* U+7E9A [2000] */ - {0x8ff4e1, 0x00e48d83}, /* U+4343 [2000] */ - {0x8ff4e2, 0x00e7bcbc}, /* U+7F3C [2000] */ - {0x8ff4e3, 0x00e7bcbb}, /* U+7F3B [2000] */ - {0x8ff4e4, 0x00e7bcbe}, /* U+7F3E [2000] */ - {0x8ff4e5, 0x00e7bd83}, /* U+7F43 [2000] */ - {0x8ff4e6, 0x00e7bd84}, /* U+7F44 [2000] */ - {0x8ff4e7, 0x00e7bd8f}, /* U+7F4F [2000] */ - {0x8ff4e8, 0x00e39381}, /* U+34C1 [2000] */ + {0x8ff4d0, 0xefa998}, /* U+FA58 CJK COMPATIBILITY IDEOGRAPH-FA58 [2000] [Unicode3.2] */ + {0x8ff4d1, 0xe7b890}, /* U+7E10 [2000] */ + {0x8ff4d2, 0xe7b897}, /* U+7E17 [2000] */ + {0x8ff4d3, 0xe7b89d}, /* U+7E1D [2000] */ + {0x8ff4d4, 0xe7b8a0}, /* U+7E20 [2000] */ + {0x8ff4d5, 0xe7b8a7}, /* U+7E27 [2000] */ + {0x8ff4d6, 0xe7b8ac}, /* U+7E2C [2000] */ + {0x8ff4d7, 0xe7b985}, /* U+7E45 [2000] */ + {0x8ff4d8, 0xe7b9b3}, /* U+7E73 [2000] */ + {0x8ff4d9, 0xe7b9b5}, /* U+7E75 [2000] */ + {0x8ff4da, 0xe7b9be}, /* U+7E7E [2000] */ + {0x8ff4db, 0xe7ba86}, /* U+7E86 [2000] */ + {0x8ff4dc, 0xe7ba87}, /* U+7E87 [2000] */ + {0x8ff4dd, 0xe48cab}, /* U+432B [2000] */ + {0x8ff4de, 0xe7ba91}, /* U+7E91 [2000] */ + {0x8ff4df, 0xe7ba98}, /* U+7E98 [2000] */ + {0x8ff4e0, 0xe7ba9a}, /* U+7E9A [2000] */ + {0x8ff4e1, 0xe48d83}, /* U+4343 [2000] */ + {0x8ff4e2, 0xe7bcbc}, /* U+7F3C [2000] */ + {0x8ff4e3, 0xe7bcbb}, /* U+7F3B [2000] */ + {0x8ff4e4, 0xe7bcbe}, /* U+7F3E [2000] */ + {0x8ff4e5, 0xe7bd83}, /* U+7F43 [2000] */ + {0x8ff4e6, 0xe7bd84}, /* U+7F44 [2000] */ + {0x8ff4e7, 0xe7bd8f}, /* U+7F4F [2000] */ + {0x8ff4e8, 0xe39381}, /* U+34C1 [2000] */ {0x8ff4e9, 0xf0a689b0}, /* U+26270 [2000] [Unicode3.1] */ - {0x8ff4ea, 0x00e7bd92}, /* U+7F52 [2000] */ + {0x8ff4ea, 0xe7bd92}, /* U+7F52 [2000] */ {0x8ff4eb, 0xf0a68a86}, /* U+26286 [2000] [Unicode3.1] */ - {0x8ff4ec, 0x00e7bda1}, /* U+7F61 [2000] */ - {0x8ff4ed, 0x00e7bda3}, /* U+7F63 [2000] */ - {0x8ff4ee, 0x00e7bda4}, /* U+7F64 [2000] */ - {0x8ff4ef, 0x00e7bdad}, /* U+7F6D [2000] */ - {0x8ff4f0, 0x00e7bdbd}, /* U+7F7D [2000] */ - {0x8ff4f1, 0x00e7bdbe}, /* U+7F7E [2000] */ + {0x8ff4ec, 0xe7bda1}, /* U+7F61 [2000] */ + {0x8ff4ed, 0xe7bda3}, /* U+7F63 [2000] */ + {0x8ff4ee, 0xe7bda4}, /* U+7F64 [2000] */ + {0x8ff4ef, 0xe7bdad}, /* U+7F6D [2000] */ + {0x8ff4f0, 0xe7bdbd}, /* U+7F7D [2000] */ + {0x8ff4f1, 0xe7bdbe}, /* U+7F7E [2000] */ {0x8ff4f2, 0xf0a68d8c}, /* U+2634C [2000] [Unicode3.1] */ - {0x8ff4f3, 0x00e7be90}, /* U+7F90 [2000] */ - {0x8ff4f4, 0x00e585bb}, /* U+517B [2000] */ + {0x8ff4f3, 0xe7be90}, /* U+7F90 [2000] */ + {0x8ff4f4, 0xe585bb}, /* U+517B [2000] */ {0x8ff4f5, 0xf0a3b48e}, /* U+23D0E [2000] [Unicode3.1] */ - {0x8ff4f6, 0x00e7be96}, /* U+7F96 [2000] */ - {0x8ff4f7, 0x00e7be9c}, /* U+7F9C [2000] */ - {0x8ff4f8, 0x00e7bead}, /* U+7FAD [2000] */ + {0x8ff4f6, 0xe7be96}, /* U+7F96 [2000] */ + {0x8ff4f7, 0xe7be9c}, /* U+7F9C [2000] */ + {0x8ff4f8, 0xe7bead}, /* U+7FAD [2000] */ {0x8ff4f9, 0xf0a69082}, /* U+26402 [2000] [Unicode3.1] */ - {0x8ff4fa, 0x00e7bf83}, /* U+7FC3 [2000] */ - {0x8ff4fb, 0x00e7bf8f}, /* U+7FCF [2000] */ - {0x8ff4fc, 0x00e7bfa3}, /* U+7FE3 [2000] */ - {0x8ff4fd, 0x00e7bfa5}, /* U+7FE5 [2000] */ - {0x8ff4fe, 0x00e7bfaf}, /* U+7FEF [2000] */ - {0x8ff5a1, 0x00e7bfb2}, /* U+7FF2 [2000] */ - {0x8ff5a2, 0x00e88082}, /* U+8002 [2000] */ - {0x8ff5a3, 0x00e8808a}, /* U+800A [2000] */ - {0x8ff5a4, 0x00e88088}, /* U+8008 [2000] */ - {0x8ff5a5, 0x00e8808e}, /* U+800E [2000] */ - {0x8ff5a6, 0x00e88091}, /* U+8011 [2000] */ - {0x8ff5a7, 0x00e88096}, /* U+8016 [2000] */ - {0x8ff5a8, 0x00e880a4}, /* U+8024 [2000] */ - {0x8ff5a9, 0x00e880ac}, /* U+802C [2000] */ - {0x8ff5aa, 0x00e880b0}, /* U+8030 [2000] */ - {0x8ff5ab, 0x00e88183}, /* U+8043 [2000] */ - {0x8ff5ac, 0x00e881a6}, /* U+8066 [2000] */ - {0x8ff5ad, 0x00e881b1}, /* U+8071 [2000] */ - {0x8ff5ae, 0x00e881b5}, /* U+8075 [2000] */ - {0x8ff5af, 0x00e881bb}, /* U+807B [2000] */ - {0x8ff5b0, 0x00e88299}, /* U+8099 [2000] */ - {0x8ff5b1, 0x00e8829c}, /* U+809C [2000] */ - {0x8ff5b2, 0x00e882a4}, /* U+80A4 [2000] */ - {0x8ff5b3, 0x00e882a7}, /* U+80A7 [2000] */ - {0x8ff5b4, 0x00e882b8}, /* U+80B8 [2000] */ + {0x8ff4fa, 0xe7bf83}, /* U+7FC3 [2000] */ + {0x8ff4fb, 0xe7bf8f}, /* U+7FCF [2000] */ + {0x8ff4fc, 0xe7bfa3}, /* U+7FE3 [2000] */ + {0x8ff4fd, 0xe7bfa5}, /* U+7FE5 [2000] */ + {0x8ff4fe, 0xe7bfaf}, /* U+7FEF [2000] */ + {0x8ff5a1, 0xe7bfb2}, /* U+7FF2 [2000] */ + {0x8ff5a2, 0xe88082}, /* U+8002 [2000] */ + {0x8ff5a3, 0xe8808a}, /* U+800A [2000] */ + {0x8ff5a4, 0xe88088}, /* U+8008 [2000] */ + {0x8ff5a5, 0xe8808e}, /* U+800E [2000] */ + {0x8ff5a6, 0xe88091}, /* U+8011 [2000] */ + {0x8ff5a7, 0xe88096}, /* U+8016 [2000] */ + {0x8ff5a8, 0xe880a4}, /* U+8024 [2000] */ + {0x8ff5a9, 0xe880ac}, /* U+802C [2000] */ + {0x8ff5aa, 0xe880b0}, /* U+8030 [2000] */ + {0x8ff5ab, 0xe88183}, /* U+8043 [2000] */ + {0x8ff5ac, 0xe881a6}, /* U+8066 [2000] */ + {0x8ff5ad, 0xe881b1}, /* U+8071 [2000] */ + {0x8ff5ae, 0xe881b5}, /* U+8075 [2000] */ + {0x8ff5af, 0xe881bb}, /* U+807B [2000] */ + {0x8ff5b0, 0xe88299}, /* U+8099 [2000] */ + {0x8ff5b1, 0xe8829c}, /* U+809C [2000] */ + {0x8ff5b2, 0xe882a4}, /* U+80A4 [2000] */ + {0x8ff5b3, 0xe882a7}, /* U+80A7 [2000] */ + {0x8ff5b4, 0xe882b8}, /* U+80B8 [2000] */ {0x8ff5b5, 0xf0a699be}, /* U+2667E [2000] [Unicode3.1] */ - {0x8ff5b6, 0x00e88385}, /* U+80C5 [2000] */ - {0x8ff5b7, 0x00e88395}, /* U+80D5 [2000] */ - {0x8ff5b8, 0x00e88398}, /* U+80D8 [2000] */ - {0x8ff5b9, 0x00e883a6}, /* U+80E6 [2000] */ + {0x8ff5b6, 0xe88385}, /* U+80C5 [2000] */ + {0x8ff5b7, 0xe88395}, /* U+80D5 [2000] */ + {0x8ff5b8, 0xe88398}, /* U+80D8 [2000] */ + {0x8ff5b9, 0xe883a6}, /* U+80E6 [2000] */ {0x8ff5ba, 0xf0a69ab0}, /* U+266B0 [2000] [Unicode3.1] */ - {0x8ff5bb, 0x00e8848d}, /* U+810D [2000] */ - {0x8ff5bc, 0x00e883b5}, /* U+80F5 [2000] */ - {0x8ff5bd, 0x00e883bb}, /* U+80FB [2000] */ - {0x8ff5be, 0x00e48fae}, /* U+43EE [2000] */ - {0x8ff5bf, 0x00e884b5}, /* U+8135 [2000] */ - {0x8ff5c0, 0x00e88496}, /* U+8116 [2000] */ - {0x8ff5c1, 0x00e8849e}, /* U+811E [2000] */ - {0x8ff5c2, 0x00e48fb0}, /* U+43F0 [2000] */ - {0x8ff5c3, 0x00e884a4}, /* U+8124 [2000] */ - {0x8ff5c4, 0x00e884a7}, /* U+8127 [2000] */ - {0x8ff5c5, 0x00e884ac}, /* U+812C [2000] */ + {0x8ff5bb, 0xe8848d}, /* U+810D [2000] */ + {0x8ff5bc, 0xe883b5}, /* U+80F5 [2000] */ + {0x8ff5bd, 0xe883bb}, /* U+80FB [2000] */ + {0x8ff5be, 0xe48fae}, /* U+43EE [2000] */ + {0x8ff5bf, 0xe884b5}, /* U+8135 [2000] */ + {0x8ff5c0, 0xe88496}, /* U+8116 [2000] */ + {0x8ff5c1, 0xe8849e}, /* U+811E [2000] */ + {0x8ff5c2, 0xe48fb0}, /* U+43F0 [2000] */ + {0x8ff5c3, 0xe884a4}, /* U+8124 [2000] */ + {0x8ff5c4, 0xe884a7}, /* U+8127 [2000] */ + {0x8ff5c5, 0xe884ac}, /* U+812C [2000] */ {0x8ff5c6, 0xf0a69c9d}, /* U+2671D [2000] [Unicode3.1] */ - {0x8ff5c7, 0x00e884bd}, /* U+813D [2000] */ - {0x8ff5c8, 0x00e49088}, /* U+4408 [2000] */ - {0x8ff5c9, 0x00e885a9}, /* U+8169 [2000] */ - {0x8ff5ca, 0x00e49097}, /* U+4417 [2000] */ - {0x8ff5cb, 0x00e88681}, /* U+8181 [2000] */ - {0x8ff5cc, 0x00e4909c}, /* U+441C [2000] */ - {0x8ff5cd, 0x00e88684}, /* U+8184 [2000] */ - {0x8ff5ce, 0x00e88685}, /* U+8185 [2000] */ - {0x8ff5cf, 0x00e490a2}, /* U+4422 [2000] */ - {0x8ff5d0, 0x00e88698}, /* U+8198 [2000] */ - {0x8ff5d1, 0x00e886b2}, /* U+81B2 [2000] */ - {0x8ff5d2, 0x00e88781}, /* U+81C1 [2000] */ - {0x8ff5d3, 0x00e88783}, /* U+81C3 [2000] */ - {0x8ff5d4, 0x00e88796}, /* U+81D6 [2000] */ - {0x8ff5d5, 0x00e8879b}, /* U+81DB [2000] */ + {0x8ff5c7, 0xe884bd}, /* U+813D [2000] */ + {0x8ff5c8, 0xe49088}, /* U+4408 [2000] */ + {0x8ff5c9, 0xe885a9}, /* U+8169 [2000] */ + {0x8ff5ca, 0xe49097}, /* U+4417 [2000] */ + {0x8ff5cb, 0xe88681}, /* U+8181 [2000] */ + {0x8ff5cc, 0xe4909c}, /* U+441C [2000] */ + {0x8ff5cd, 0xe88684}, /* U+8184 [2000] */ + {0x8ff5ce, 0xe88685}, /* U+8185 [2000] */ + {0x8ff5cf, 0xe490a2}, /* U+4422 [2000] */ + {0x8ff5d0, 0xe88698}, /* U+8198 [2000] */ + {0x8ff5d1, 0xe886b2}, /* U+81B2 [2000] */ + {0x8ff5d2, 0xe88781}, /* U+81C1 [2000] */ + {0x8ff5d3, 0xe88783}, /* U+81C3 [2000] */ + {0x8ff5d4, 0xe88796}, /* U+81D6 [2000] */ + {0x8ff5d5, 0xe8879b}, /* U+81DB [2000] */ {0x8ff5d6, 0xf0a6a39d}, /* U+268DD [2000] [Unicode3.1] */ - {0x8ff5d7, 0x00e887a4}, /* U+81E4 [2000] */ + {0x8ff5d7, 0xe887a4}, /* U+81E4 [2000] */ {0x8ff5d8, 0xf0a6a3aa}, /* U+268EA [2000] [Unicode3.1] */ - {0x8ff5d9, 0x00e887ac}, /* U+81EC [2000] */ + {0x8ff5d9, 0xe887ac}, /* U+81EC [2000] */ {0x8ff5da, 0xf0a6a591}, /* U+26951 [2000] [Unicode3.1] */ - {0x8ff5db, 0x00e887bd}, /* U+81FD [2000] */ - {0x8ff5dc, 0x00e887bf}, /* U+81FF [2000] */ + {0x8ff5db, 0xe887bd}, /* U+81FD [2000] */ + {0x8ff5dc, 0xe887bf}, /* U+81FF [2000] */ {0x8ff5dd, 0xf0a6a5af}, /* U+2696F [2000] [Unicode3.1] */ - {0x8ff5de, 0x00e88884}, /* U+8204 [2000] */ + {0x8ff5de, 0xe88884}, /* U+8204 [2000] */ {0x8ff5df, 0xf0a6a79d}, /* U+269DD [2000] [Unicode3.1] */ - {0x8ff5e0, 0x00e88899}, /* U+8219 [2000] */ - {0x8ff5e1, 0x00e888a1}, /* U+8221 [2000] */ - {0x8ff5e2, 0x00e888a2}, /* U+8222 [2000] */ + {0x8ff5e0, 0xe88899}, /* U+8219 [2000] */ + {0x8ff5e1, 0xe888a1}, /* U+8221 [2000] */ + {0x8ff5e2, 0xe888a2}, /* U+8222 [2000] */ {0x8ff5e3, 0xf0a6a89e}, /* U+26A1E [2000] [Unicode3.1] */ - {0x8ff5e4, 0x00e888b2}, /* U+8232 [2000] */ - {0x8ff5e5, 0x00e888b4}, /* U+8234 [2000] */ - {0x8ff5e6, 0x00e888bc}, /* U+823C [2000] */ - {0x8ff5e7, 0x00e88986}, /* U+8246 [2000] */ - {0x8ff5e8, 0x00e88989}, /* U+8249 [2000] */ - {0x8ff5e9, 0x00e88985}, /* U+8245 [2000] */ + {0x8ff5e4, 0xe888b2}, /* U+8232 [2000] */ + {0x8ff5e5, 0xe888b4}, /* U+8234 [2000] */ + {0x8ff5e6, 0xe888bc}, /* U+823C [2000] */ + {0x8ff5e7, 0xe88986}, /* U+8246 [2000] */ + {0x8ff5e8, 0xe88989}, /* U+8249 [2000] */ + {0x8ff5e9, 0xe88985}, /* U+8245 [2000] */ {0x8ff5ea, 0xf0a6a998}, /* U+26A58 [2000] [Unicode3.1] */ - {0x8ff5eb, 0x00e8898b}, /* U+824B [2000] */ - {0x8ff5ec, 0x00e491b6}, /* U+4476 [2000] */ - {0x8ff5ed, 0x00e8898f}, /* U+824F [2000] */ - {0x8ff5ee, 0x00e491ba}, /* U+447A [2000] */ - {0x8ff5ef, 0x00e88997}, /* U+8257 [2000] */ + {0x8ff5eb, 0xe8898b}, /* U+824B [2000] */ + {0x8ff5ec, 0xe491b6}, /* U+4476 [2000] */ + {0x8ff5ed, 0xe8898f}, /* U+824F [2000] */ + {0x8ff5ee, 0xe491ba}, /* U+447A [2000] */ + {0x8ff5ef, 0xe88997}, /* U+8257 [2000] */ {0x8ff5f0, 0xf0a6aa8c}, /* U+26A8C [2000] [Unicode3.1] */ - {0x8ff5f1, 0x00e8899c}, /* U+825C [2000] */ - {0x8ff5f2, 0x00e889a3}, /* U+8263 [2000] */ + {0x8ff5f1, 0xe8899c}, /* U+825C [2000] */ + {0x8ff5f2, 0xe889a3}, /* U+8263 [2000] */ {0x8ff5f3, 0xf0a6aab7}, /* U+26AB7 [2000] [Unicode3.1] */ - {0x8ff5f4, 0x00efa99d}, /* U+FA5D CJK COMPATIBILITY IDEOGRAPH-FA5D [2000] [Unicode3.2] */ - {0x8ff5f5, 0x00efa99e}, /* U+FA5E CJK COMPATIBILITY IDEOGRAPH-FA5E [2000] [Unicode3.2] */ - {0x8ff5f6, 0x00e889b9}, /* U+8279 [2000] */ - {0x8ff5f7, 0x00e49291}, /* U+4491 [2000] */ - {0x8ff5f8, 0x00e889bd}, /* U+827D [2000] */ - {0x8ff5f9, 0x00e889bf}, /* U+827F [2000] */ - {0x8ff5fa, 0x00e88a83}, /* U+8283 [2000] */ - {0x8ff5fb, 0x00e88a8a}, /* U+828A [2000] */ - {0x8ff5fc, 0x00e88a93}, /* U+8293 [2000] */ - {0x8ff5fd, 0x00e88aa7}, /* U+82A7 [2000] */ - {0x8ff5fe, 0x00e88aa8}, /* U+82A8 [2000] */ - {0x8ff6a1, 0x00e88ab2}, /* U+82B2 [2000] */ - {0x8ff6a2, 0x00e88ab4}, /* U+82B4 [2000] */ - {0x8ff6a3, 0x00e88aba}, /* U+82BA [2000] */ - {0x8ff6a4, 0x00e88abc}, /* U+82BC [2000] */ - {0x8ff6a5, 0x00e88ba2}, /* U+82E2 [2000] */ - {0x8ff6a6, 0x00e88ba8}, /* U+82E8 [2000] */ - {0x8ff6a7, 0x00e88bb7}, /* U+82F7 [2000] */ - {0x8ff6a8, 0x00e88c87}, /* U+8307 [2000] */ - {0x8ff6a9, 0x00e88c88}, /* U+8308 [2000] */ - {0x8ff6aa, 0x00e88c8c}, /* U+830C [2000] */ - {0x8ff6ab, 0x00e88d94}, /* U+8354 [2000] */ - {0x8ff6ac, 0x00e88c9b}, /* U+831B [2000] */ - {0x8ff6ad, 0x00e88c9d}, /* U+831D [2000] */ - {0x8ff6ae, 0x00e88cb0}, /* U+8330 [2000] */ - {0x8ff6af, 0x00e88cbc}, /* U+833C [2000] */ - {0x8ff6b0, 0x00e88d84}, /* U+8344 [2000] */ - {0x8ff6b1, 0x00e88d97}, /* U+8357 [2000] */ - {0x8ff6b2, 0x00e492be}, /* U+44BE [2000] */ - {0x8ff6b3, 0x00e88dbf}, /* U+837F [2000] */ - {0x8ff6b4, 0x00e49394}, /* U+44D4 [2000] */ - {0x8ff6b5, 0x00e492b3}, /* U+44B3 [2000] */ - {0x8ff6b6, 0x00e88e8d}, /* U+838D [2000] */ - {0x8ff6b7, 0x00e88e94}, /* U+8394 [2000] */ - {0x8ff6b8, 0x00e88e95}, /* U+8395 [2000] */ - {0x8ff6b9, 0x00e88e9b}, /* U+839B [2000] */ - {0x8ff6ba, 0x00e88e9d}, /* U+839D [2000] */ - {0x8ff6bb, 0x00e88f89}, /* U+83C9 [2000] */ - {0x8ff6bc, 0x00e88f90}, /* U+83D0 [2000] */ - {0x8ff6bd, 0x00e88f94}, /* U+83D4 [2000] */ - {0x8ff6be, 0x00e88f9d}, /* U+83DD [2000] */ - {0x8ff6bf, 0x00e88fa5}, /* U+83E5 [2000] */ - {0x8ff6c0, 0x00e88fb9}, /* U+83F9 [2000] */ - {0x8ff6c1, 0x00e8908f}, /* U+840F [2000] */ - {0x8ff6c2, 0x00e89091}, /* U+8411 [2000] */ - {0x8ff6c3, 0x00e89095}, /* U+8415 [2000] */ + {0x8ff5f4, 0xefa99d}, /* U+FA5D CJK COMPATIBILITY IDEOGRAPH-FA5D [2000] [Unicode3.2] */ + {0x8ff5f5, 0xefa99e}, /* U+FA5E CJK COMPATIBILITY IDEOGRAPH-FA5E [2000] [Unicode3.2] */ + {0x8ff5f6, 0xe889b9}, /* U+8279 [2000] */ + {0x8ff5f7, 0xe49291}, /* U+4491 [2000] */ + {0x8ff5f8, 0xe889bd}, /* U+827D [2000] */ + {0x8ff5f9, 0xe889bf}, /* U+827F [2000] */ + {0x8ff5fa, 0xe88a83}, /* U+8283 [2000] */ + {0x8ff5fb, 0xe88a8a}, /* U+828A [2000] */ + {0x8ff5fc, 0xe88a93}, /* U+8293 [2000] */ + {0x8ff5fd, 0xe88aa7}, /* U+82A7 [2000] */ + {0x8ff5fe, 0xe88aa8}, /* U+82A8 [2000] */ + {0x8ff6a1, 0xe88ab2}, /* U+82B2 [2000] */ + {0x8ff6a2, 0xe88ab4}, /* U+82B4 [2000] */ + {0x8ff6a3, 0xe88aba}, /* U+82BA [2000] */ + {0x8ff6a4, 0xe88abc}, /* U+82BC [2000] */ + {0x8ff6a5, 0xe88ba2}, /* U+82E2 [2000] */ + {0x8ff6a6, 0xe88ba8}, /* U+82E8 [2000] */ + {0x8ff6a7, 0xe88bb7}, /* U+82F7 [2000] */ + {0x8ff6a8, 0xe88c87}, /* U+8307 [2000] */ + {0x8ff6a9, 0xe88c88}, /* U+8308 [2000] */ + {0x8ff6aa, 0xe88c8c}, /* U+830C [2000] */ + {0x8ff6ab, 0xe88d94}, /* U+8354 [2000] */ + {0x8ff6ac, 0xe88c9b}, /* U+831B [2000] */ + {0x8ff6ad, 0xe88c9d}, /* U+831D [2000] */ + {0x8ff6ae, 0xe88cb0}, /* U+8330 [2000] */ + {0x8ff6af, 0xe88cbc}, /* U+833C [2000] */ + {0x8ff6b0, 0xe88d84}, /* U+8344 [2000] */ + {0x8ff6b1, 0xe88d97}, /* U+8357 [2000] */ + {0x8ff6b2, 0xe492be}, /* U+44BE [2000] */ + {0x8ff6b3, 0xe88dbf}, /* U+837F [2000] */ + {0x8ff6b4, 0xe49394}, /* U+44D4 [2000] */ + {0x8ff6b5, 0xe492b3}, /* U+44B3 [2000] */ + {0x8ff6b6, 0xe88e8d}, /* U+838D [2000] */ + {0x8ff6b7, 0xe88e94}, /* U+8394 [2000] */ + {0x8ff6b8, 0xe88e95}, /* U+8395 [2000] */ + {0x8ff6b9, 0xe88e9b}, /* U+839B [2000] */ + {0x8ff6ba, 0xe88e9d}, /* U+839D [2000] */ + {0x8ff6bb, 0xe88f89}, /* U+83C9 [2000] */ + {0x8ff6bc, 0xe88f90}, /* U+83D0 [2000] */ + {0x8ff6bd, 0xe88f94}, /* U+83D4 [2000] */ + {0x8ff6be, 0xe88f9d}, /* U+83DD [2000] */ + {0x8ff6bf, 0xe88fa5}, /* U+83E5 [2000] */ + {0x8ff6c0, 0xe88fb9}, /* U+83F9 [2000] */ + {0x8ff6c1, 0xe8908f}, /* U+840F [2000] */ + {0x8ff6c2, 0xe89091}, /* U+8411 [2000] */ + {0x8ff6c3, 0xe89095}, /* U+8415 [2000] */ {0x8ff6c4, 0xf0a6b1b3}, /* U+26C73 [2000] [Unicode3.1] */ - {0x8ff6c5, 0x00e89097}, /* U+8417 [2000] */ - {0x8ff6c6, 0x00e890b9}, /* U+8439 [2000] */ - {0x8ff6c7, 0x00e8918a}, /* U+844A [2000] */ - {0x8ff6c8, 0x00e8918f}, /* U+844F [2000] */ - {0x8ff6c9, 0x00e89191}, /* U+8451 [2000] */ - {0x8ff6ca, 0x00e89192}, /* U+8452 [2000] */ - {0x8ff6cb, 0x00e89199}, /* U+8459 [2000] */ - {0x8ff6cc, 0x00e8919a}, /* U+845A [2000] */ - {0x8ff6cd, 0x00e8919c}, /* U+845C [2000] */ + {0x8ff6c5, 0xe89097}, /* U+8417 [2000] */ + {0x8ff6c6, 0xe890b9}, /* U+8439 [2000] */ + {0x8ff6c7, 0xe8918a}, /* U+844A [2000] */ + {0x8ff6c8, 0xe8918f}, /* U+844F [2000] */ + {0x8ff6c9, 0xe89191}, /* U+8451 [2000] */ + {0x8ff6ca, 0xe89192}, /* U+8452 [2000] */ + {0x8ff6cb, 0xe89199}, /* U+8459 [2000] */ + {0x8ff6cc, 0xe8919a}, /* U+845A [2000] */ + {0x8ff6cd, 0xe8919c}, /* U+845C [2000] */ {0x8ff6ce, 0xf0a6b39d}, /* U+26CDD [2000] [Unicode3.1] */ - {0x8ff6cf, 0x00e891a5}, /* U+8465 [2000] */ - {0x8ff6d0, 0x00e891b6}, /* U+8476 [2000] */ - {0x8ff6d1, 0x00e891b8}, /* U+8478 [2000] */ - {0x8ff6d2, 0x00e891bc}, /* U+847C [2000] */ - {0x8ff6d3, 0x00e89281}, /* U+8481 [2000] */ - {0x8ff6d4, 0x00e4948d}, /* U+450D [2000] */ - {0x8ff6d5, 0x00e8939c}, /* U+84DC [2000] */ - {0x8ff6d6, 0x00e89297}, /* U+8497 [2000] */ - {0x8ff6d7, 0x00e892a6}, /* U+84A6 [2000] */ - {0x8ff6d8, 0x00e892be}, /* U+84BE [2000] */ - {0x8ff6d9, 0x00e49488}, /* U+4508 [2000] */ - {0x8ff6da, 0x00e8938e}, /* U+84CE [2000] */ - {0x8ff6db, 0x00e8938f}, /* U+84CF [2000] */ - {0x8ff6dc, 0x00e89393}, /* U+84D3 [2000] */ + {0x8ff6cf, 0xe891a5}, /* U+8465 [2000] */ + {0x8ff6d0, 0xe891b6}, /* U+8476 [2000] */ + {0x8ff6d1, 0xe891b8}, /* U+8478 [2000] */ + {0x8ff6d2, 0xe891bc}, /* U+847C [2000] */ + {0x8ff6d3, 0xe89281}, /* U+8481 [2000] */ + {0x8ff6d4, 0xe4948d}, /* U+450D [2000] */ + {0x8ff6d5, 0xe8939c}, /* U+84DC [2000] */ + {0x8ff6d6, 0xe89297}, /* U+8497 [2000] */ + {0x8ff6d7, 0xe892a6}, /* U+84A6 [2000] */ + {0x8ff6d8, 0xe892be}, /* U+84BE [2000] */ + {0x8ff6d9, 0xe49488}, /* U+4508 [2000] */ + {0x8ff6da, 0xe8938e}, /* U+84CE [2000] */ + {0x8ff6db, 0xe8938f}, /* U+84CF [2000] */ + {0x8ff6dc, 0xe89393}, /* U+84D3 [2000] */ {0x8ff6dd, 0xf0a6b9a5}, /* U+26E65 [2000] [Unicode3.1] */ - {0x8ff6de, 0x00e893a7}, /* U+84E7 [2000] */ - {0x8ff6df, 0x00e893aa}, /* U+84EA [2000] */ - {0x8ff6e0, 0x00e893af}, /* U+84EF [2000] */ - {0x8ff6e1, 0x00e893b0}, /* U+84F0 [2000] */ - {0x8ff6e2, 0x00e893b1}, /* U+84F1 [2000] */ - {0x8ff6e3, 0x00e893ba}, /* U+84FA [2000] */ - {0x8ff6e4, 0x00e893bd}, /* U+84FD [2000] */ - {0x8ff6e5, 0x00e8948c}, /* U+850C [2000] */ - {0x8ff6e6, 0x00e8949b}, /* U+851B [2000] */ - {0x8ff6e7, 0x00e894a4}, /* U+8524 [2000] */ - {0x8ff6e8, 0x00e894a5}, /* U+8525 [2000] */ - {0x8ff6e9, 0x00e894ab}, /* U+852B [2000] */ - {0x8ff6ea, 0x00e894b4}, /* U+8534 [2000] */ - {0x8ff6eb, 0x00e8958f}, /* U+854F [2000] */ - {0x8ff6ec, 0x00e895af}, /* U+856F [2000] */ - {0x8ff6ed, 0x00e494a5}, /* U+4525 [2000] */ - {0x8ff6ee, 0x00e49583}, /* U+4543 [2000] */ - {0x8ff6ef, 0x00e894be}, /* U+853E [2000] */ - {0x8ff6f0, 0x00e89591}, /* U+8551 [2000] */ - {0x8ff6f1, 0x00e89593}, /* U+8553 [2000] */ - {0x8ff6f2, 0x00e8959e}, /* U+855E [2000] */ - {0x8ff6f3, 0x00e895a1}, /* U+8561 [2000] */ - {0x8ff6f4, 0x00e895a2}, /* U+8562 [2000] */ + {0x8ff6de, 0xe893a7}, /* U+84E7 [2000] */ + {0x8ff6df, 0xe893aa}, /* U+84EA [2000] */ + {0x8ff6e0, 0xe893af}, /* U+84EF [2000] */ + {0x8ff6e1, 0xe893b0}, /* U+84F0 [2000] */ + {0x8ff6e2, 0xe893b1}, /* U+84F1 [2000] */ + {0x8ff6e3, 0xe893ba}, /* U+84FA [2000] */ + {0x8ff6e4, 0xe893bd}, /* U+84FD [2000] */ + {0x8ff6e5, 0xe8948c}, /* U+850C [2000] */ + {0x8ff6e6, 0xe8949b}, /* U+851B [2000] */ + {0x8ff6e7, 0xe894a4}, /* U+8524 [2000] */ + {0x8ff6e8, 0xe894a5}, /* U+8525 [2000] */ + {0x8ff6e9, 0xe894ab}, /* U+852B [2000] */ + {0x8ff6ea, 0xe894b4}, /* U+8534 [2000] */ + {0x8ff6eb, 0xe8958f}, /* U+854F [2000] */ + {0x8ff6ec, 0xe895af}, /* U+856F [2000] */ + {0x8ff6ed, 0xe494a5}, /* U+4525 [2000] */ + {0x8ff6ee, 0xe49583}, /* U+4543 [2000] */ + {0x8ff6ef, 0xe894be}, /* U+853E [2000] */ + {0x8ff6f0, 0xe89591}, /* U+8551 [2000] */ + {0x8ff6f1, 0xe89593}, /* U+8553 [2000] */ + {0x8ff6f2, 0xe8959e}, /* U+855E [2000] */ + {0x8ff6f3, 0xe895a1}, /* U+8561 [2000] */ + {0x8ff6f4, 0xe895a2}, /* U+8562 [2000] */ {0x8ff6f5, 0xf0a6be94}, /* U+26F94 [2000] [Unicode3.1] */ - {0x8ff6f6, 0x00e895bb}, /* U+857B [2000] */ - {0x8ff6f7, 0x00e895bd}, /* U+857D [2000] */ - {0x8ff6f8, 0x00e895bf}, /* U+857F [2000] */ - {0x8ff6f9, 0x00e89681}, /* U+8581 [2000] */ - {0x8ff6fa, 0x00e89686}, /* U+8586 [2000] */ - {0x8ff6fb, 0x00e89693}, /* U+8593 [2000] */ - {0x8ff6fc, 0x00e8969d}, /* U+859D [2000] */ - {0x8ff6fd, 0x00e8969f}, /* U+859F [2000] */ + {0x8ff6f6, 0xe895bb}, /* U+857B [2000] */ + {0x8ff6f7, 0xe895bd}, /* U+857D [2000] */ + {0x8ff6f8, 0xe895bf}, /* U+857F [2000] */ + {0x8ff6f9, 0xe89681}, /* U+8581 [2000] */ + {0x8ff6fa, 0xe89686}, /* U+8586 [2000] */ + {0x8ff6fb, 0xe89693}, /* U+8593 [2000] */ + {0x8ff6fc, 0xe8969d}, /* U+859D [2000] */ + {0x8ff6fd, 0xe8969f}, /* U+859F [2000] */ {0x8ff6fe, 0xf0a6bfb8}, /* U+26FF8 [2000] [Unicode3.1] */ {0x8ff7a1, 0xf0a6bfb6}, /* U+26FF6 [2000] [Unicode3.1] */ {0x8ff7a2, 0xf0a6bfb7}, /* U+26FF7 [2000] [Unicode3.1] */ - {0x8ff7a3, 0x00e896b7}, /* U+85B7 [2000] */ - {0x8ff7a4, 0x00e896bc}, /* U+85BC [2000] */ - {0x8ff7a5, 0x00e89787}, /* U+85C7 [2000] */ - {0x8ff7a6, 0x00e8978a}, /* U+85CA [2000] */ - {0x8ff7a7, 0x00e89798}, /* U+85D8 [2000] */ - {0x8ff7a8, 0x00e89799}, /* U+85D9 [2000] */ - {0x8ff7a9, 0x00e8979f}, /* U+85DF [2000] */ - {0x8ff7aa, 0x00e897a1}, /* U+85E1 [2000] */ - {0x8ff7ab, 0x00e897a6}, /* U+85E6 [2000] */ - {0x8ff7ac, 0x00e897b6}, /* U+85F6 [2000] */ - {0x8ff7ad, 0x00e89880}, /* U+8600 [2000] */ - {0x8ff7ae, 0x00e89891}, /* U+8611 [2000] */ - {0x8ff7af, 0x00e8989e}, /* U+861E [2000] */ - {0x8ff7b0, 0x00e898a1}, /* U+8621 [2000] */ - {0x8ff7b1, 0x00e898a4}, /* U+8624 [2000] */ - {0x8ff7b2, 0x00e898a7}, /* U+8627 [2000] */ + {0x8ff7a3, 0xe896b7}, /* U+85B7 [2000] */ + {0x8ff7a4, 0xe896bc}, /* U+85BC [2000] */ + {0x8ff7a5, 0xe89787}, /* U+85C7 [2000] */ + {0x8ff7a6, 0xe8978a}, /* U+85CA [2000] */ + {0x8ff7a7, 0xe89798}, /* U+85D8 [2000] */ + {0x8ff7a8, 0xe89799}, /* U+85D9 [2000] */ + {0x8ff7a9, 0xe8979f}, /* U+85DF [2000] */ + {0x8ff7aa, 0xe897a1}, /* U+85E1 [2000] */ + {0x8ff7ab, 0xe897a6}, /* U+85E6 [2000] */ + {0x8ff7ac, 0xe897b6}, /* U+85F6 [2000] */ + {0x8ff7ad, 0xe89880}, /* U+8600 [2000] */ + {0x8ff7ae, 0xe89891}, /* U+8611 [2000] */ + {0x8ff7af, 0xe8989e}, /* U+861E [2000] */ + {0x8ff7b0, 0xe898a1}, /* U+8621 [2000] */ + {0x8ff7b1, 0xe898a4}, /* U+8624 [2000] */ + {0x8ff7b2, 0xe898a7}, /* U+8627 [2000] */ {0x8ff7b3, 0xf0a7848d}, /* U+2710D [2000] [Unicode3.1] */ - {0x8ff7b4, 0x00e898b9}, /* U+8639 [2000] */ - {0x8ff7b5, 0x00e898bc}, /* U+863C [2000] */ + {0x8ff7b4, 0xe898b9}, /* U+8639 [2000] */ + {0x8ff7b5, 0xe898bc}, /* U+863C [2000] */ {0x8ff7b6, 0xf0a784b9}, /* U+27139 [2000] [Unicode3.1] */ - {0x8ff7b7, 0x00e89980}, /* U+8640 [2000] */ - {0x8ff7b8, 0x00efa8a0}, /* U+FA20 CJK COMPATIBILITY IDEOGRAPH-FA20 [2000] */ - {0x8ff7b9, 0x00e89993}, /* U+8653 [2000] */ - {0x8ff7ba, 0x00e89996}, /* U+8656 [2000] */ - {0x8ff7bb, 0x00e899af}, /* U+866F [2000] */ - {0x8ff7bc, 0x00e899b7}, /* U+8677 [2000] */ - {0x8ff7bd, 0x00e899ba}, /* U+867A [2000] */ - {0x8ff7be, 0x00e89a87}, /* U+8687 [2000] */ - {0x8ff7bf, 0x00e89a89}, /* U+8689 [2000] */ - {0x8ff7c0, 0x00e89a8d}, /* U+868D [2000] */ - {0x8ff7c1, 0x00e89a91}, /* U+8691 [2000] */ - {0x8ff7c2, 0x00e89a9c}, /* U+869C [2000] */ - {0x8ff7c3, 0x00e89a9d}, /* U+869D [2000] */ - {0x8ff7c4, 0x00e89aa8}, /* U+86A8 [2000] */ - {0x8ff7c5, 0x00efa8a1}, /* U+FA21 CJK COMPATIBILITY IDEOGRAPH-FA21 [2000] */ - {0x8ff7c6, 0x00e89ab1}, /* U+86B1 [2000] */ - {0x8ff7c7, 0x00e89ab3}, /* U+86B3 [2000] */ - {0x8ff7c8, 0x00e89b81}, /* U+86C1 [2000] */ - {0x8ff7c9, 0x00e89b83}, /* U+86C3 [2000] */ - {0x8ff7ca, 0x00e89b91}, /* U+86D1 [2000] */ - {0x8ff7cb, 0x00e89b95}, /* U+86D5 [2000] */ - {0x8ff7cc, 0x00e89b97}, /* U+86D7 [2000] */ - {0x8ff7cd, 0x00e89ba3}, /* U+86E3 [2000] */ - {0x8ff7ce, 0x00e89ba6}, /* U+86E6 [2000] */ - {0x8ff7cf, 0x00e496b8}, /* U+45B8 [2000] */ - {0x8ff7d0, 0x00e89c85}, /* U+8705 [2000] */ - {0x8ff7d1, 0x00e89c87}, /* U+8707 [2000] */ - {0x8ff7d2, 0x00e89c8e}, /* U+870E [2000] */ - {0x8ff7d3, 0x00e89c90}, /* U+8710 [2000] */ - {0x8ff7d4, 0x00e89c93}, /* U+8713 [2000] */ - {0x8ff7d5, 0x00e89c99}, /* U+8719 [2000] */ - {0x8ff7d6, 0x00e89c9f}, /* U+871F [2000] */ - {0x8ff7d7, 0x00e89ca1}, /* U+8721 [2000] */ - {0x8ff7d8, 0x00e89ca3}, /* U+8723 [2000] */ - {0x8ff7d9, 0x00e89cb1}, /* U+8731 [2000] */ - {0x8ff7da, 0x00e89cba}, /* U+873A [2000] */ - {0x8ff7db, 0x00e89cbe}, /* U+873E [2000] */ - {0x8ff7dc, 0x00e89d80}, /* U+8740 [2000] */ - {0x8ff7dd, 0x00e89d83}, /* U+8743 [2000] */ - {0x8ff7de, 0x00e89d91}, /* U+8751 [2000] */ - {0x8ff7df, 0x00e89d98}, /* U+8758 [2000] */ - {0x8ff7e0, 0x00e89da4}, /* U+8764 [2000] */ - {0x8ff7e1, 0x00e89da5}, /* U+8765 [2000] */ - {0x8ff7e2, 0x00e89db2}, /* U+8772 [2000] */ - {0x8ff7e3, 0x00e89dbc}, /* U+877C [2000] */ + {0x8ff7b7, 0xe89980}, /* U+8640 [2000] */ + {0x8ff7b8, 0xefa8a0}, /* U+FA20 CJK COMPATIBILITY IDEOGRAPH-FA20 [2000] */ + {0x8ff7b9, 0xe89993}, /* U+8653 [2000] */ + {0x8ff7ba, 0xe89996}, /* U+8656 [2000] */ + {0x8ff7bb, 0xe899af}, /* U+866F [2000] */ + {0x8ff7bc, 0xe899b7}, /* U+8677 [2000] */ + {0x8ff7bd, 0xe899ba}, /* U+867A [2000] */ + {0x8ff7be, 0xe89a87}, /* U+8687 [2000] */ + {0x8ff7bf, 0xe89a89}, /* U+8689 [2000] */ + {0x8ff7c0, 0xe89a8d}, /* U+868D [2000] */ + {0x8ff7c1, 0xe89a91}, /* U+8691 [2000] */ + {0x8ff7c2, 0xe89a9c}, /* U+869C [2000] */ + {0x8ff7c3, 0xe89a9d}, /* U+869D [2000] */ + {0x8ff7c4, 0xe89aa8}, /* U+86A8 [2000] */ + {0x8ff7c5, 0xefa8a1}, /* U+FA21 CJK COMPATIBILITY IDEOGRAPH-FA21 [2000] */ + {0x8ff7c6, 0xe89ab1}, /* U+86B1 [2000] */ + {0x8ff7c7, 0xe89ab3}, /* U+86B3 [2000] */ + {0x8ff7c8, 0xe89b81}, /* U+86C1 [2000] */ + {0x8ff7c9, 0xe89b83}, /* U+86C3 [2000] */ + {0x8ff7ca, 0xe89b91}, /* U+86D1 [2000] */ + {0x8ff7cb, 0xe89b95}, /* U+86D5 [2000] */ + {0x8ff7cc, 0xe89b97}, /* U+86D7 [2000] */ + {0x8ff7cd, 0xe89ba3}, /* U+86E3 [2000] */ + {0x8ff7ce, 0xe89ba6}, /* U+86E6 [2000] */ + {0x8ff7cf, 0xe496b8}, /* U+45B8 [2000] */ + {0x8ff7d0, 0xe89c85}, /* U+8705 [2000] */ + {0x8ff7d1, 0xe89c87}, /* U+8707 [2000] */ + {0x8ff7d2, 0xe89c8e}, /* U+870E [2000] */ + {0x8ff7d3, 0xe89c90}, /* U+8710 [2000] */ + {0x8ff7d4, 0xe89c93}, /* U+8713 [2000] */ + {0x8ff7d5, 0xe89c99}, /* U+8719 [2000] */ + {0x8ff7d6, 0xe89c9f}, /* U+871F [2000] */ + {0x8ff7d7, 0xe89ca1}, /* U+8721 [2000] */ + {0x8ff7d8, 0xe89ca3}, /* U+8723 [2000] */ + {0x8ff7d9, 0xe89cb1}, /* U+8731 [2000] */ + {0x8ff7da, 0xe89cba}, /* U+873A [2000] */ + {0x8ff7db, 0xe89cbe}, /* U+873E [2000] */ + {0x8ff7dc, 0xe89d80}, /* U+8740 [2000] */ + {0x8ff7dd, 0xe89d83}, /* U+8743 [2000] */ + {0x8ff7de, 0xe89d91}, /* U+8751 [2000] */ + {0x8ff7df, 0xe89d98}, /* U+8758 [2000] */ + {0x8ff7e0, 0xe89da4}, /* U+8764 [2000] */ + {0x8ff7e1, 0xe89da5}, /* U+8765 [2000] */ + {0x8ff7e2, 0xe89db2}, /* U+8772 [2000] */ + {0x8ff7e3, 0xe89dbc}, /* U+877C [2000] */ {0x8ff7e4, 0xf0a78f9b}, /* U+273DB [2000] [Unicode3.1] */ {0x8ff7e5, 0xf0a78f9a}, /* U+273DA [2000] [Unicode3.1] */ - {0x8ff7e6, 0x00e89ea7}, /* U+87A7 [2000] */ - {0x8ff7e7, 0x00e89e89}, /* U+8789 [2000] */ - {0x8ff7e8, 0x00e89e8b}, /* U+878B [2000] */ - {0x8ff7e9, 0x00e89e93}, /* U+8793 [2000] */ - {0x8ff7ea, 0x00e89ea0}, /* U+87A0 [2000] */ + {0x8ff7e6, 0xe89ea7}, /* U+87A7 [2000] */ + {0x8ff7e7, 0xe89e89}, /* U+8789 [2000] */ + {0x8ff7e8, 0xe89e8b}, /* U+878B [2000] */ + {0x8ff7e9, 0xe89e93}, /* U+8793 [2000] */ + {0x8ff7ea, 0xe89ea0}, /* U+87A0 [2000] */ {0x8ff7eb, 0xf0a78fbe}, /* U+273FE [2000] [Unicode3.1] */ - {0x8ff7ec, 0x00e497a5}, /* U+45E5 [2000] */ - {0x8ff7ed, 0x00e89ebe}, /* U+87BE [2000] */ + {0x8ff7ec, 0xe497a5}, /* U+45E5 [2000] */ + {0x8ff7ed, 0xe89ebe}, /* U+87BE [2000] */ {0x8ff7ee, 0xf0a79090}, /* U+27410 [2000] [Unicode3.1] */ - {0x8ff7ef, 0x00e89f81}, /* U+87C1 [2000] */ - {0x8ff7f0, 0x00e89f8e}, /* U+87CE [2000] */ - {0x8ff7f1, 0x00e89fb5}, /* U+87F5 [2000] */ - {0x8ff7f2, 0x00e89f9f}, /* U+87DF [2000] */ + {0x8ff7ef, 0xe89f81}, /* U+87C1 [2000] */ + {0x8ff7f0, 0xe89f8e}, /* U+87CE [2000] */ + {0x8ff7f1, 0xe89fb5}, /* U+87F5 [2000] */ + {0x8ff7f2, 0xe89f9f}, /* U+87DF [2000] */ {0x8ff7f3, 0xf0a79189}, /* U+27449 [2000] [Unicode3.1] */ - {0x8ff7f4, 0x00e89fa3}, /* U+87E3 [2000] */ - {0x8ff7f5, 0x00e89fa5}, /* U+87E5 [2000] */ - {0x8ff7f6, 0x00e89fa6}, /* U+87E6 [2000] */ - {0x8ff7f7, 0x00e89faa}, /* U+87EA [2000] */ - {0x8ff7f8, 0x00e89fab}, /* U+87EB [2000] */ - {0x8ff7f9, 0x00e89fad}, /* U+87ED [2000] */ - {0x8ff7fa, 0x00e8a081}, /* U+8801 [2000] */ - {0x8ff7fb, 0x00e8a083}, /* U+8803 [2000] */ - {0x8ff7fc, 0x00e8a08b}, /* U+880B [2000] */ - {0x8ff7fd, 0x00e8a093}, /* U+8813 [2000] */ - {0x8ff7fe, 0x00e8a0a8}, /* U+8828 [2000] */ - {0x8ff8a1, 0x00e8a0ae}, /* U+882E [2000] */ - {0x8ff8a2, 0x00e8a0b2}, /* U+8832 [2000] */ - {0x8ff8a3, 0x00e8a0bc}, /* U+883C [2000] */ - {0x8ff8a4, 0x00e4988f}, /* U+460F [2000] */ - {0x8ff8a5, 0x00e8a18a}, /* U+884A [2000] */ - {0x8ff8a6, 0x00e8a198}, /* U+8858 [2000] */ - {0x8ff8a7, 0x00e8a19f}, /* U+885F [2000] */ - {0x8ff8a8, 0x00e8a1a4}, /* U+8864 [2000] */ + {0x8ff7f4, 0xe89fa3}, /* U+87E3 [2000] */ + {0x8ff7f5, 0xe89fa5}, /* U+87E5 [2000] */ + {0x8ff7f6, 0xe89fa6}, /* U+87E6 [2000] */ + {0x8ff7f7, 0xe89faa}, /* U+87EA [2000] */ + {0x8ff7f8, 0xe89fab}, /* U+87EB [2000] */ + {0x8ff7f9, 0xe89fad}, /* U+87ED [2000] */ + {0x8ff7fa, 0xe8a081}, /* U+8801 [2000] */ + {0x8ff7fb, 0xe8a083}, /* U+8803 [2000] */ + {0x8ff7fc, 0xe8a08b}, /* U+880B [2000] */ + {0x8ff7fd, 0xe8a093}, /* U+8813 [2000] */ + {0x8ff7fe, 0xe8a0a8}, /* U+8828 [2000] */ + {0x8ff8a1, 0xe8a0ae}, /* U+882E [2000] */ + {0x8ff8a2, 0xe8a0b2}, /* U+8832 [2000] */ + {0x8ff8a3, 0xe8a0bc}, /* U+883C [2000] */ + {0x8ff8a4, 0xe4988f}, /* U+460F [2000] */ + {0x8ff8a5, 0xe8a18a}, /* U+884A [2000] */ + {0x8ff8a6, 0xe8a198}, /* U+8858 [2000] */ + {0x8ff8a7, 0xe8a19f}, /* U+885F [2000] */ + {0x8ff8a8, 0xe8a1a4}, /* U+8864 [2000] */ {0x8ff8a9, 0xf0a79895}, /* U+27615 [2000] [Unicode3.1] */ {0x8ff8aa, 0xf0a79894}, /* U+27614 [2000] [Unicode3.1] */ - {0x8ff8ab, 0x00e8a1a9}, /* U+8869 [2000] */ + {0x8ff8ab, 0xe8a1a9}, /* U+8869 [2000] */ {0x8ff8ac, 0xf0a798b1}, /* U+27631 [2000] [Unicode3.1] */ - {0x8ff8ad, 0x00e8a1af}, /* U+886F [2000] */ - {0x8ff8ae, 0x00e8a2a0}, /* U+88A0 [2000] */ - {0x8ff8af, 0x00e8a2bc}, /* U+88BC [2000] */ - {0x8ff8b0, 0x00e8a2bd}, /* U+88BD [2000] */ - {0x8ff8b1, 0x00e8a2be}, /* U+88BE [2000] */ - {0x8ff8b2, 0x00e8a380}, /* U+88C0 [2000] */ - {0x8ff8b3, 0x00e8a392}, /* U+88D2 [2000] */ + {0x8ff8ad, 0xe8a1af}, /* U+886F [2000] */ + {0x8ff8ae, 0xe8a2a0}, /* U+88A0 [2000] */ + {0x8ff8af, 0xe8a2bc}, /* U+88BC [2000] */ + {0x8ff8b0, 0xe8a2bd}, /* U+88BD [2000] */ + {0x8ff8b1, 0xe8a2be}, /* U+88BE [2000] */ + {0x8ff8b2, 0xe8a380}, /* U+88C0 [2000] */ + {0x8ff8b3, 0xe8a392}, /* U+88D2 [2000] */ {0x8ff8b4, 0xf0a79a93}, /* U+27693 [2000] [Unicode3.1] */ - {0x8ff8b5, 0x00e8a391}, /* U+88D1 [2000] */ - {0x8ff8b6, 0x00e8a393}, /* U+88D3 [2000] */ - {0x8ff8b7, 0x00e8a39b}, /* U+88DB [2000] */ - {0x8ff8b8, 0x00e8a3b0}, /* U+88F0 [2000] */ - {0x8ff8b9, 0x00e8a3b1}, /* U+88F1 [2000] */ - {0x8ff8ba, 0x00e49981}, /* U+4641 [2000] */ - {0x8ff8bb, 0x00e8a481}, /* U+8901 [2000] */ + {0x8ff8b5, 0xe8a391}, /* U+88D1 [2000] */ + {0x8ff8b6, 0xe8a393}, /* U+88D3 [2000] */ + {0x8ff8b7, 0xe8a39b}, /* U+88DB [2000] */ + {0x8ff8b8, 0xe8a3b0}, /* U+88F0 [2000] */ + {0x8ff8b9, 0xe8a3b1}, /* U+88F1 [2000] */ + {0x8ff8ba, 0xe49981}, /* U+4641 [2000] */ + {0x8ff8bb, 0xe8a481}, /* U+8901 [2000] */ {0x8ff8bc, 0xf0a79c8e}, /* U+2770E [2000] [Unicode3.1] */ - {0x8ff8bd, 0x00e8a4b7}, /* U+8937 [2000] */ + {0x8ff8bd, 0xe8a4b7}, /* U+8937 [2000] */ {0x8ff8be, 0xf0a79ca3}, /* U+27723 [2000] [Unicode3.1] */ - {0x8ff8bf, 0x00e8a582}, /* U+8942 [2000] */ - {0x8ff8c0, 0x00e8a585}, /* U+8945 [2000] */ - {0x8ff8c1, 0x00e8a589}, /* U+8949 [2000] */ + {0x8ff8bf, 0xe8a582}, /* U+8942 [2000] */ + {0x8ff8c0, 0xe8a585}, /* U+8945 [2000] */ + {0x8ff8c1, 0xe8a589}, /* U+8949 [2000] */ {0x8ff8c2, 0xf0a79d92}, /* U+27752 [2000] [Unicode3.1] */ - {0x8ff8c3, 0x00e499a5}, /* U+4665 [2000] */ - {0x8ff8c4, 0x00e8a5a2}, /* U+8962 [2000] */ - {0x8ff8c5, 0x00e8a680}, /* U+8980 [2000] */ - {0x8ff8c6, 0x00e8a689}, /* U+8989 [2000] */ - {0x8ff8c7, 0x00e8a690}, /* U+8990 [2000] */ - {0x8ff8c8, 0x00e8a69f}, /* U+899F [2000] */ - {0x8ff8c9, 0x00e8a6b0}, /* U+89B0 [2000] */ - {0x8ff8ca, 0x00e8a6b7}, /* U+89B7 [2000] */ - {0x8ff8cb, 0x00e8a796}, /* U+89D6 [2000] */ - {0x8ff8cc, 0x00e8a798}, /* U+89D8 [2000] */ - {0x8ff8cd, 0x00e8a7ab}, /* U+89EB [2000] */ - {0x8ff8ce, 0x00e49aa1}, /* U+46A1 [2000] */ - {0x8ff8cf, 0x00e8a7b1}, /* U+89F1 [2000] */ - {0x8ff8d0, 0x00e8a7b3}, /* U+89F3 [2000] */ - {0x8ff8d1, 0x00e8a7bd}, /* U+89FD [2000] */ - {0x8ff8d2, 0x00e8a7bf}, /* U+89FF [2000] */ - {0x8ff8d3, 0x00e49aaf}, /* U+46AF [2000] */ - {0x8ff8d4, 0x00e8a891}, /* U+8A11 [2000] */ - {0x8ff8d5, 0x00e8a894}, /* U+8A14 [2000] */ + {0x8ff8c3, 0xe499a5}, /* U+4665 [2000] */ + {0x8ff8c4, 0xe8a5a2}, /* U+8962 [2000] */ + {0x8ff8c5, 0xe8a680}, /* U+8980 [2000] */ + {0x8ff8c6, 0xe8a689}, /* U+8989 [2000] */ + {0x8ff8c7, 0xe8a690}, /* U+8990 [2000] */ + {0x8ff8c8, 0xe8a69f}, /* U+899F [2000] */ + {0x8ff8c9, 0xe8a6b0}, /* U+89B0 [2000] */ + {0x8ff8ca, 0xe8a6b7}, /* U+89B7 [2000] */ + {0x8ff8cb, 0xe8a796}, /* U+89D6 [2000] */ + {0x8ff8cc, 0xe8a798}, /* U+89D8 [2000] */ + {0x8ff8cd, 0xe8a7ab}, /* U+89EB [2000] */ + {0x8ff8ce, 0xe49aa1}, /* U+46A1 [2000] */ + {0x8ff8cf, 0xe8a7b1}, /* U+89F1 [2000] */ + {0x8ff8d0, 0xe8a7b3}, /* U+89F3 [2000] */ + {0x8ff8d1, 0xe8a7bd}, /* U+89FD [2000] */ + {0x8ff8d2, 0xe8a7bf}, /* U+89FF [2000] */ + {0x8ff8d3, 0xe49aaf}, /* U+46AF [2000] */ + {0x8ff8d4, 0xe8a891}, /* U+8A11 [2000] */ + {0x8ff8d5, 0xe8a894}, /* U+8A14 [2000] */ {0x8ff8d6, 0xf0a7a685}, /* U+27985 [2000] [Unicode3.1] */ - {0x8ff8d7, 0x00e8a8a1}, /* U+8A21 [2000] */ - {0x8ff8d8, 0x00e8a8b5}, /* U+8A35 [2000] */ - {0x8ff8d9, 0x00e8a8be}, /* U+8A3E [2000] */ - {0x8ff8da, 0x00e8a985}, /* U+8A45 [2000] */ - {0x8ff8db, 0x00e8a98d}, /* U+8A4D [2000] */ - {0x8ff8dc, 0x00e8a998}, /* U+8A58 [2000] */ - {0x8ff8dd, 0x00e8aaae}, /* U+8AAE [2000] */ - {0x8ff8de, 0x00e8aa90}, /* U+8A90 [2000] */ - {0x8ff8df, 0x00e8aab7}, /* U+8AB7 [2000] */ - {0x8ff8e0, 0x00e8aabe}, /* U+8ABE [2000] */ - {0x8ff8e1, 0x00e8ab97}, /* U+8AD7 [2000] */ - {0x8ff8e2, 0x00e8abbc}, /* U+8AFC [2000] */ + {0x8ff8d7, 0xe8a8a1}, /* U+8A21 [2000] */ + {0x8ff8d8, 0xe8a8b5}, /* U+8A35 [2000] */ + {0x8ff8d9, 0xe8a8be}, /* U+8A3E [2000] */ + {0x8ff8da, 0xe8a985}, /* U+8A45 [2000] */ + {0x8ff8db, 0xe8a98d}, /* U+8A4D [2000] */ + {0x8ff8dc, 0xe8a998}, /* U+8A58 [2000] */ + {0x8ff8dd, 0xe8aaae}, /* U+8AAE [2000] */ + {0x8ff8de, 0xe8aa90}, /* U+8A90 [2000] */ + {0x8ff8df, 0xe8aab7}, /* U+8AB7 [2000] */ + {0x8ff8e0, 0xe8aabe}, /* U+8ABE [2000] */ + {0x8ff8e1, 0xe8ab97}, /* U+8AD7 [2000] */ + {0x8ff8e2, 0xe8abbc}, /* U+8AFC [2000] */ {0x8ff8e3, 0xf0a7aa84}, /* U+27A84 [2000] [Unicode3.1] */ - {0x8ff8e4, 0x00e8ac8a}, /* U+8B0A [2000] */ - {0x8ff8e5, 0x00e8ac85}, /* U+8B05 [2000] */ - {0x8ff8e6, 0x00e8ac8d}, /* U+8B0D [2000] */ - {0x8ff8e7, 0x00e8ac9c}, /* U+8B1C [2000] */ - {0x8ff8e8, 0x00e8ac9f}, /* U+8B1F [2000] */ - {0x8ff8e9, 0x00e8acad}, /* U+8B2D [2000] */ - {0x8ff8ea, 0x00e8ad83}, /* U+8B43 [2000] */ - {0x8ff8eb, 0x00e49c8c}, /* U+470C [2000] */ - {0x8ff8ec, 0x00e8ad91}, /* U+8B51 [2000] */ - {0x8ff8ed, 0x00e8ad9e}, /* U+8B5E [2000] */ - {0x8ff8ee, 0x00e8adb6}, /* U+8B76 [2000] */ - {0x8ff8ef, 0x00e8adbf}, /* U+8B7F [2000] */ - {0x8ff8f0, 0x00e8ae81}, /* U+8B81 [2000] */ - {0x8ff8f1, 0x00e8ae8b}, /* U+8B8B [2000] */ - {0x8ff8f2, 0x00e8ae94}, /* U+8B94 [2000] */ - {0x8ff8f3, 0x00e8ae95}, /* U+8B95 [2000] */ - {0x8ff8f4, 0x00e8ae9c}, /* U+8B9C [2000] */ - {0x8ff8f5, 0x00e8ae9e}, /* U+8B9E [2000] */ - {0x8ff8f6, 0x00e8b0b9}, /* U+8C39 [2000] */ + {0x8ff8e4, 0xe8ac8a}, /* U+8B0A [2000] */ + {0x8ff8e5, 0xe8ac85}, /* U+8B05 [2000] */ + {0x8ff8e6, 0xe8ac8d}, /* U+8B0D [2000] */ + {0x8ff8e7, 0xe8ac9c}, /* U+8B1C [2000] */ + {0x8ff8e8, 0xe8ac9f}, /* U+8B1F [2000] */ + {0x8ff8e9, 0xe8acad}, /* U+8B2D [2000] */ + {0x8ff8ea, 0xe8ad83}, /* U+8B43 [2000] */ + {0x8ff8eb, 0xe49c8c}, /* U+470C [2000] */ + {0x8ff8ec, 0xe8ad91}, /* U+8B51 [2000] */ + {0x8ff8ed, 0xe8ad9e}, /* U+8B5E [2000] */ + {0x8ff8ee, 0xe8adb6}, /* U+8B76 [2000] */ + {0x8ff8ef, 0xe8adbf}, /* U+8B7F [2000] */ + {0x8ff8f0, 0xe8ae81}, /* U+8B81 [2000] */ + {0x8ff8f1, 0xe8ae8b}, /* U+8B8B [2000] */ + {0x8ff8f2, 0xe8ae94}, /* U+8B94 [2000] */ + {0x8ff8f3, 0xe8ae95}, /* U+8B95 [2000] */ + {0x8ff8f4, 0xe8ae9c}, /* U+8B9C [2000] */ + {0x8ff8f5, 0xe8ae9e}, /* U+8B9E [2000] */ + {0x8ff8f6, 0xe8b0b9}, /* U+8C39 [2000] */ {0x8ff8f7, 0xf0a7aeb3}, /* U+27BB3 [2000] [Unicode3.1] */ - {0x8ff8f8, 0x00e8b0bd}, /* U+8C3D [2000] */ + {0x8ff8f8, 0xe8b0bd}, /* U+8C3D [2000] */ {0x8ff8f9, 0xf0a7aebe}, /* U+27BBE [2000] [Unicode3.1] */ {0x8ff8fa, 0xf0a7af87}, /* U+27BC7 [2000] [Unicode3.1] */ - {0x8ff8fb, 0x00e8b185}, /* U+8C45 [2000] */ - {0x8ff8fc, 0x00e8b187}, /* U+8C47 [2000] */ - {0x8ff8fd, 0x00e8b18f}, /* U+8C4F [2000] */ - {0x8ff8fe, 0x00e8b194}, /* U+8C54 [2000] */ - {0x8ff9a1, 0x00e8b197}, /* U+8C57 [2000] */ - {0x8ff9a2, 0x00e8b1a9}, /* U+8C69 [2000] */ - {0x8ff9a3, 0x00e8b1ad}, /* U+8C6D [2000] */ - {0x8ff9a4, 0x00e8b1b3}, /* U+8C73 [2000] */ + {0x8ff8fb, 0xe8b185}, /* U+8C45 [2000] */ + {0x8ff8fc, 0xe8b187}, /* U+8C47 [2000] */ + {0x8ff8fd, 0xe8b18f}, /* U+8C4F [2000] */ + {0x8ff8fe, 0xe8b194}, /* U+8C54 [2000] */ + {0x8ff9a1, 0xe8b197}, /* U+8C57 [2000] */ + {0x8ff9a2, 0xe8b1a9}, /* U+8C69 [2000] */ + {0x8ff9a3, 0xe8b1ad}, /* U+8C6D [2000] */ + {0x8ff9a4, 0xe8b1b3}, /* U+8C73 [2000] */ {0x8ff9a5, 0xf0a7b2b8}, /* U+27CB8 [2000] [Unicode3.1] */ - {0x8ff9a6, 0x00e8b293}, /* U+8C93 [2000] */ - {0x8ff9a7, 0x00e8b292}, /* U+8C92 [2000] */ - {0x8ff9a8, 0x00e8b299}, /* U+8C99 [2000] */ - {0x8ff9a9, 0x00e49da4}, /* U+4764 [2000] */ - {0x8ff9aa, 0x00e8b29b}, /* U+8C9B [2000] */ - {0x8ff9ab, 0x00e8b2a4}, /* U+8CA4 [2000] */ - {0x8ff9ac, 0x00e8b396}, /* U+8CD6 [2000] */ - {0x8ff9ad, 0x00e8b395}, /* U+8CD5 [2000] */ - {0x8ff9ae, 0x00e8b399}, /* U+8CD9 [2000] */ + {0x8ff9a6, 0xe8b293}, /* U+8C93 [2000] */ + {0x8ff9a7, 0xe8b292}, /* U+8C92 [2000] */ + {0x8ff9a8, 0xe8b299}, /* U+8C99 [2000] */ + {0x8ff9a9, 0xe49da4}, /* U+4764 [2000] */ + {0x8ff9aa, 0xe8b29b}, /* U+8C9B [2000] */ + {0x8ff9ab, 0xe8b2a4}, /* U+8CA4 [2000] */ + {0x8ff9ac, 0xe8b396}, /* U+8CD6 [2000] */ + {0x8ff9ad, 0xe8b395}, /* U+8CD5 [2000] */ + {0x8ff9ae, 0xe8b399}, /* U+8CD9 [2000] */ {0x8ff9af, 0xf0a7b6a0}, /* U+27DA0 [2000] [Unicode3.1] */ - {0x8ff9b0, 0x00e8b3b0}, /* U+8CF0 [2000] */ - {0x8ff9b1, 0x00e8b3b1}, /* U+8CF1 [2000] */ + {0x8ff9b0, 0xe8b3b0}, /* U+8CF0 [2000] */ + {0x8ff9b1, 0xe8b3b1}, /* U+8CF1 [2000] */ {0x8ff9b2, 0xf0a7b890}, /* U+27E10 [2000] [Unicode3.1] */ - {0x8ff9b3, 0x00e8b489}, /* U+8D09 [2000] */ - {0x8ff9b4, 0x00e8b48e}, /* U+8D0E [2000] */ - {0x8ff9b5, 0x00e8b5ac}, /* U+8D6C [2000] */ - {0x8ff9b6, 0x00e8b684}, /* U+8D84 [2000] */ - {0x8ff9b7, 0x00e8b695}, /* U+8D95 [2000] */ - {0x8ff9b8, 0x00e8b6a6}, /* U+8DA6 [2000] */ + {0x8ff9b3, 0xe8b489}, /* U+8D09 [2000] */ + {0x8ff9b4, 0xe8b48e}, /* U+8D0E [2000] */ + {0x8ff9b5, 0xe8b5ac}, /* U+8D6C [2000] */ + {0x8ff9b6, 0xe8b684}, /* U+8D84 [2000] */ + {0x8ff9b7, 0xe8b695}, /* U+8D95 [2000] */ + {0x8ff9b8, 0xe8b6a6}, /* U+8DA6 [2000] */ {0x8ff9b9, 0xf0a7beb7}, /* U+27FB7 [2000] [Unicode3.1] */ - {0x8ff9ba, 0x00e8b786}, /* U+8DC6 [2000] */ - {0x8ff9bb, 0x00e8b788}, /* U+8DC8 [2000] */ - {0x8ff9bc, 0x00e8b799}, /* U+8DD9 [2000] */ - {0x8ff9bd, 0x00e8b7ac}, /* U+8DEC [2000] */ - {0x8ff9be, 0x00e8b88c}, /* U+8E0C [2000] */ - {0x8ff9bf, 0x00e49fbd}, /* U+47FD [2000] */ - {0x8ff9c0, 0x00e8b7bd}, /* U+8DFD [2000] */ - {0x8ff9c1, 0x00e8b886}, /* U+8E06 [2000] */ + {0x8ff9ba, 0xe8b786}, /* U+8DC6 [2000] */ + {0x8ff9bb, 0xe8b788}, /* U+8DC8 [2000] */ + {0x8ff9bc, 0xe8b799}, /* U+8DD9 [2000] */ + {0x8ff9bd, 0xe8b7ac}, /* U+8DEC [2000] */ + {0x8ff9be, 0xe8b88c}, /* U+8E0C [2000] */ + {0x8ff9bf, 0xe49fbd}, /* U+47FD [2000] */ + {0x8ff9c0, 0xe8b7bd}, /* U+8DFD [2000] */ + {0x8ff9c1, 0xe8b886}, /* U+8E06 [2000] */ {0x8ff9c2, 0xf0a8828a}, /* U+2808A [2000] [Unicode3.1] */ - {0x8ff9c3, 0x00e8b894}, /* U+8E14 [2000] */ - {0x8ff9c4, 0x00e8b896}, /* U+8E16 [2000] */ - {0x8ff9c5, 0x00e8b8a1}, /* U+8E21 [2000] */ - {0x8ff9c6, 0x00e8b8a2}, /* U+8E22 [2000] */ - {0x8ff9c7, 0x00e8b8a7}, /* U+8E27 [2000] */ + {0x8ff9c3, 0xe8b894}, /* U+8E14 [2000] */ + {0x8ff9c4, 0xe8b896}, /* U+8E16 [2000] */ + {0x8ff9c5, 0xe8b8a1}, /* U+8E21 [2000] */ + {0x8ff9c6, 0xe8b8a2}, /* U+8E22 [2000] */ + {0x8ff9c7, 0xe8b8a7}, /* U+8E27 [2000] */ {0x8ff9c8, 0xf0a882bb}, /* U+280BB [2000] [Unicode3.1] */ - {0x8ff9c9, 0x00e4a096}, /* U+4816 [2000] */ - {0x8ff9ca, 0x00e8b8b6}, /* U+8E36 [2000] */ - {0x8ff9cb, 0x00e8b8b9}, /* U+8E39 [2000] */ - {0x8ff9cc, 0x00e8b98b}, /* U+8E4B [2000] */ - {0x8ff9cd, 0x00e8b994}, /* U+8E54 [2000] */ - {0x8ff9ce, 0x00e8b9a2}, /* U+8E62 [2000] */ - {0x8ff9cf, 0x00e8b9ac}, /* U+8E6C [2000] */ - {0x8ff9d0, 0x00e8b9ad}, /* U+8E6D [2000] */ - {0x8ff9d1, 0x00e8b9af}, /* U+8E6F [2000] */ - {0x8ff9d2, 0x00e8ba98}, /* U+8E98 [2000] */ - {0x8ff9d3, 0x00e8ba9e}, /* U+8E9E [2000] */ - {0x8ff9d4, 0x00e8baae}, /* U+8EAE [2000] */ - {0x8ff9d5, 0x00e8bab3}, /* U+8EB3 [2000] */ - {0x8ff9d6, 0x00e8bab5}, /* U+8EB5 [2000] */ - {0x8ff9d7, 0x00e8bab6}, /* U+8EB6 [2000] */ - {0x8ff9d8, 0x00e8babb}, /* U+8EBB [2000] */ + {0x8ff9c9, 0xe4a096}, /* U+4816 [2000] */ + {0x8ff9ca, 0xe8b8b6}, /* U+8E36 [2000] */ + {0x8ff9cb, 0xe8b8b9}, /* U+8E39 [2000] */ + {0x8ff9cc, 0xe8b98b}, /* U+8E4B [2000] */ + {0x8ff9cd, 0xe8b994}, /* U+8E54 [2000] */ + {0x8ff9ce, 0xe8b9a2}, /* U+8E62 [2000] */ + {0x8ff9cf, 0xe8b9ac}, /* U+8E6C [2000] */ + {0x8ff9d0, 0xe8b9ad}, /* U+8E6D [2000] */ + {0x8ff9d1, 0xe8b9af}, /* U+8E6F [2000] */ + {0x8ff9d2, 0xe8ba98}, /* U+8E98 [2000] */ + {0x8ff9d3, 0xe8ba9e}, /* U+8E9E [2000] */ + {0x8ff9d4, 0xe8baae}, /* U+8EAE [2000] */ + {0x8ff9d5, 0xe8bab3}, /* U+8EB3 [2000] */ + {0x8ff9d6, 0xe8bab5}, /* U+8EB5 [2000] */ + {0x8ff9d7, 0xe8bab6}, /* U+8EB6 [2000] */ + {0x8ff9d8, 0xe8babb}, /* U+8EBB [2000] */ {0x8ff9d9, 0xf0a88a82}, /* U+28282 [2000] [Unicode3.1] */ - {0x8ff9da, 0x00e8bb91}, /* U+8ED1 [2000] */ - {0x8ff9db, 0x00e8bb94}, /* U+8ED4 [2000] */ - {0x8ff9dc, 0x00e4a18e}, /* U+484E [2000] */ - {0x8ff9dd, 0x00e8bbb9}, /* U+8EF9 [2000] */ + {0x8ff9da, 0xe8bb91}, /* U+8ED1 [2000] */ + {0x8ff9db, 0xe8bb94}, /* U+8ED4 [2000] */ + {0x8ff9dc, 0xe4a18e}, /* U+484E [2000] */ + {0x8ff9dd, 0xe8bbb9}, /* U+8EF9 [2000] */ {0x8ff9de, 0xf0a88bb3}, /* U+282F3 [2000] [Unicode3.1] */ - {0x8ff9df, 0x00e8bc80}, /* U+8F00 [2000] */ - {0x8ff9e0, 0x00e8bc88}, /* U+8F08 [2000] */ - {0x8ff9e1, 0x00e8bc97}, /* U+8F17 [2000] */ - {0x8ff9e2, 0x00e8bcab}, /* U+8F2B [2000] */ - {0x8ff9e3, 0x00e8bd80}, /* U+8F40 [2000] */ - {0x8ff9e4, 0x00e8bd8a}, /* U+8F4A [2000] */ - {0x8ff9e5, 0x00e8bd98}, /* U+8F58 [2000] */ + {0x8ff9df, 0xe8bc80}, /* U+8F00 [2000] */ + {0x8ff9e0, 0xe8bc88}, /* U+8F08 [2000] */ + {0x8ff9e1, 0xe8bc97}, /* U+8F17 [2000] */ + {0x8ff9e2, 0xe8bcab}, /* U+8F2B [2000] */ + {0x8ff9e3, 0xe8bd80}, /* U+8F40 [2000] */ + {0x8ff9e4, 0xe8bd8a}, /* U+8F4A [2000] */ + {0x8ff9e5, 0xe8bd98}, /* U+8F58 [2000] */ {0x8ff9e6, 0xf0a8908c}, /* U+2840C [2000] [Unicode3.1] */ - {0x8ff9e7, 0x00e8bea4}, /* U+8FA4 [2000] */ - {0x8ff9e8, 0x00e8beb4}, /* U+8FB4 [2000] */ - {0x8ff9e9, 0x00efa9a6}, /* U+FA66 CJK COMPATIBILITY IDEOGRAPH-FA66 [2000] [Unicode3.2] */ - {0x8ff9ea, 0x00e8beb6}, /* U+8FB6 [2000] */ + {0x8ff9e7, 0xe8bea4}, /* U+8FA4 [2000] */ + {0x8ff9e8, 0xe8beb4}, /* U+8FB4 [2000] */ + {0x8ff9e9, 0xefa9a6}, /* U+FA66 CJK COMPATIBILITY IDEOGRAPH-FA66 [2000] [Unicode3.2] */ + {0x8ff9ea, 0xe8beb6}, /* U+8FB6 [2000] */ {0x8ff9eb, 0xf0a89195}, /* U+28455 [2000] [Unicode3.1] */ - {0x8ff9ec, 0x00e8bf81}, /* U+8FC1 [2000] */ - {0x8ff9ed, 0x00e8bf86}, /* U+8FC6 [2000] */ - {0x8ff9ee, 0x00efa8a4}, /* U+FA24 CJK COMPATIBILITY IDEOGRAPH-FA24 [2000] */ - {0x8ff9ef, 0x00e8bf8a}, /* U+8FCA [2000] */ - {0x8ff9f0, 0x00e8bf8d}, /* U+8FCD [2000] */ - {0x8ff9f1, 0x00e8bf93}, /* U+8FD3 [2000] */ - {0x8ff9f2, 0x00e8bf95}, /* U+8FD5 [2000] */ - {0x8ff9f3, 0x00e8bfa0}, /* U+8FE0 [2000] */ - {0x8ff9f4, 0x00e8bfb1}, /* U+8FF1 [2000] */ - {0x8ff9f5, 0x00e8bfb5}, /* U+8FF5 [2000] */ - {0x8ff9f6, 0x00e8bfbb}, /* U+8FFB [2000] */ - {0x8ff9f7, 0x00e98082}, /* U+9002 [2000] */ - {0x8ff9f8, 0x00e9808c}, /* U+900C [2000] */ - {0x8ff9f9, 0x00e980b7}, /* U+9037 [2000] */ + {0x8ff9ec, 0xe8bf81}, /* U+8FC1 [2000] */ + {0x8ff9ed, 0xe8bf86}, /* U+8FC6 [2000] */ + {0x8ff9ee, 0xefa8a4}, /* U+FA24 CJK COMPATIBILITY IDEOGRAPH-FA24 [2000] */ + {0x8ff9ef, 0xe8bf8a}, /* U+8FCA [2000] */ + {0x8ff9f0, 0xe8bf8d}, /* U+8FCD [2000] */ + {0x8ff9f1, 0xe8bf93}, /* U+8FD3 [2000] */ + {0x8ff9f2, 0xe8bf95}, /* U+8FD5 [2000] */ + {0x8ff9f3, 0xe8bfa0}, /* U+8FE0 [2000] */ + {0x8ff9f4, 0xe8bfb1}, /* U+8FF1 [2000] */ + {0x8ff9f5, 0xe8bfb5}, /* U+8FF5 [2000] */ + {0x8ff9f6, 0xe8bfbb}, /* U+8FFB [2000] */ + {0x8ff9f7, 0xe98082}, /* U+9002 [2000] */ + {0x8ff9f8, 0xe9808c}, /* U+900C [2000] */ + {0x8ff9f9, 0xe980b7}, /* U+9037 [2000] */ {0x8ff9fa, 0xf0a895ab}, /* U+2856B [2000] [Unicode3.1] */ - {0x8ff9fb, 0x00e98183}, /* U+9043 [2000] */ - {0x8ff9fc, 0x00e98184}, /* U+9044 [2000] */ - {0x8ff9fd, 0x00e9819d}, /* U+905D [2000] */ + {0x8ff9fb, 0xe98183}, /* U+9043 [2000] */ + {0x8ff9fc, 0xe98184}, /* U+9044 [2000] */ + {0x8ff9fd, 0xe9819d}, /* U+905D [2000] */ {0x8ff9fe, 0xf0a89788}, /* U+285C8 [2000] [Unicode3.1] */ {0x8ffaa1, 0xf0a89789}, /* U+285C9 [2000] [Unicode3.1] */ - {0x8ffaa2, 0x00e98285}, /* U+9085 [2000] */ - {0x8ffaa3, 0x00e9828c}, /* U+908C [2000] */ - {0x8ffaa4, 0x00e98290}, /* U+9090 [2000] */ - {0x8ffaa5, 0x00e9989d}, /* U+961D [2000] */ - {0x8ffaa6, 0x00e982a1}, /* U+90A1 [2000] */ - {0x8ffaa7, 0x00e4a2b5}, /* U+48B5 [2000] */ - {0x8ffaa8, 0x00e982b0}, /* U+90B0 [2000] */ - {0x8ffaa9, 0x00e982b6}, /* U+90B6 [2000] */ - {0x8ffaaa, 0x00e98383}, /* U+90C3 [2000] */ - {0x8ffaab, 0x00e98388}, /* U+90C8 [2000] */ + {0x8ffaa2, 0xe98285}, /* U+9085 [2000] */ + {0x8ffaa3, 0xe9828c}, /* U+908C [2000] */ + {0x8ffaa4, 0xe98290}, /* U+9090 [2000] */ + {0x8ffaa5, 0xe9989d}, /* U+961D [2000] */ + {0x8ffaa6, 0xe982a1}, /* U+90A1 [2000] */ + {0x8ffaa7, 0xe4a2b5}, /* U+48B5 [2000] */ + {0x8ffaa8, 0xe982b0}, /* U+90B0 [2000] */ + {0x8ffaa9, 0xe982b6}, /* U+90B6 [2000] */ + {0x8ffaaa, 0xe98383}, /* U+90C3 [2000] */ + {0x8ffaab, 0xe98388}, /* U+90C8 [2000] */ {0x8ffaac, 0xf0a89b97}, /* U+286D7 [2000] [Unicode3.1] */ - {0x8ffaad, 0x00e9839c}, /* U+90DC [2000] */ - {0x8ffaae, 0x00e9839f}, /* U+90DF [2000] */ + {0x8ffaad, 0xe9839c}, /* U+90DC [2000] */ + {0x8ffaae, 0xe9839f}, /* U+90DF [2000] */ {0x8ffaaf, 0xf0a89bba}, /* U+286FA [2000] [Unicode3.1] */ - {0x8ffab0, 0x00e983b6}, /* U+90F6 [2000] */ - {0x8ffab1, 0x00e983b2}, /* U+90F2 [2000] */ - {0x8ffab2, 0x00e98480}, /* U+9100 [2000] */ - {0x8ffab3, 0x00e983ab}, /* U+90EB [2000] */ - {0x8ffab4, 0x00e983be}, /* U+90FE [2000] */ - {0x8ffab5, 0x00e983bf}, /* U+90FF [2000] */ - {0x8ffab6, 0x00e98484}, /* U+9104 [2000] */ - {0x8ffab7, 0x00e98486}, /* U+9106 [2000] */ - {0x8ffab8, 0x00e98498}, /* U+9118 [2000] */ - {0x8ffab9, 0x00e9849c}, /* U+911C [2000] */ - {0x8ffaba, 0x00e9849e}, /* U+911E [2000] */ - {0x8ffabb, 0x00e984b7}, /* U+9137 [2000] */ - {0x8ffabc, 0x00e984b9}, /* U+9139 [2000] */ - {0x8ffabd, 0x00e984ba}, /* U+913A [2000] */ - {0x8ffabe, 0x00e98586}, /* U+9146 [2000] */ - {0x8ffabf, 0x00e98587}, /* U+9147 [2000] */ - {0x8ffac0, 0x00e98597}, /* U+9157 [2000] */ - {0x8ffac1, 0x00e98599}, /* U+9159 [2000] */ - {0x8ffac2, 0x00e985a1}, /* U+9161 [2000] */ - {0x8ffac3, 0x00e985a4}, /* U+9164 [2000] */ - {0x8ffac4, 0x00e985b4}, /* U+9174 [2000] */ - {0x8ffac5, 0x00e985b9}, /* U+9179 [2000] */ - {0x8ffac6, 0x00e98685}, /* U+9185 [2000] */ - {0x8ffac7, 0x00e9868e}, /* U+918E [2000] */ - {0x8ffac8, 0x00e986a8}, /* U+91A8 [2000] */ - {0x8ffac9, 0x00e986ae}, /* U+91AE [2000] */ - {0x8ffaca, 0x00e986b3}, /* U+91B3 [2000] */ - {0x8ffacb, 0x00e986b6}, /* U+91B6 [2000] */ - {0x8ffacc, 0x00e98783}, /* U+91C3 [2000] */ - {0x8ffacd, 0x00e98784}, /* U+91C4 [2000] */ - {0x8fface, 0x00e9879a}, /* U+91DA [2000] */ + {0x8ffab0, 0xe983b6}, /* U+90F6 [2000] */ + {0x8ffab1, 0xe983b2}, /* U+90F2 [2000] */ + {0x8ffab2, 0xe98480}, /* U+9100 [2000] */ + {0x8ffab3, 0xe983ab}, /* U+90EB [2000] */ + {0x8ffab4, 0xe983be}, /* U+90FE [2000] */ + {0x8ffab5, 0xe983bf}, /* U+90FF [2000] */ + {0x8ffab6, 0xe98484}, /* U+9104 [2000] */ + {0x8ffab7, 0xe98486}, /* U+9106 [2000] */ + {0x8ffab8, 0xe98498}, /* U+9118 [2000] */ + {0x8ffab9, 0xe9849c}, /* U+911C [2000] */ + {0x8ffaba, 0xe9849e}, /* U+911E [2000] */ + {0x8ffabb, 0xe984b7}, /* U+9137 [2000] */ + {0x8ffabc, 0xe984b9}, /* U+9139 [2000] */ + {0x8ffabd, 0xe984ba}, /* U+913A [2000] */ + {0x8ffabe, 0xe98586}, /* U+9146 [2000] */ + {0x8ffabf, 0xe98587}, /* U+9147 [2000] */ + {0x8ffac0, 0xe98597}, /* U+9157 [2000] */ + {0x8ffac1, 0xe98599}, /* U+9159 [2000] */ + {0x8ffac2, 0xe985a1}, /* U+9161 [2000] */ + {0x8ffac3, 0xe985a4}, /* U+9164 [2000] */ + {0x8ffac4, 0xe985b4}, /* U+9174 [2000] */ + {0x8ffac5, 0xe985b9}, /* U+9179 [2000] */ + {0x8ffac6, 0xe98685}, /* U+9185 [2000] */ + {0x8ffac7, 0xe9868e}, /* U+918E [2000] */ + {0x8ffac8, 0xe986a8}, /* U+91A8 [2000] */ + {0x8ffac9, 0xe986ae}, /* U+91AE [2000] */ + {0x8ffaca, 0xe986b3}, /* U+91B3 [2000] */ + {0x8ffacb, 0xe986b6}, /* U+91B6 [2000] */ + {0x8ffacc, 0xe98783}, /* U+91C3 [2000] */ + {0x8ffacd, 0xe98784}, /* U+91C4 [2000] */ + {0x8fface, 0xe9879a}, /* U+91DA [2000] */ {0x8ffacf, 0xf0a8a589}, /* U+28949 [2000] [Unicode3.1] */ {0x8ffad0, 0xf0a8a586}, /* U+28946 [2000] [Unicode3.1] */ - {0x8ffad1, 0x00e987ac}, /* U+91EC [2000] */ - {0x8ffad2, 0x00e987ae}, /* U+91EE [2000] */ - {0x8ffad3, 0x00e98881}, /* U+9201 [2000] */ - {0x8ffad4, 0x00e9888a}, /* U+920A [2000] */ - {0x8ffad5, 0x00e98896}, /* U+9216 [2000] */ - {0x8ffad6, 0x00e98897}, /* U+9217 [2000] */ + {0x8ffad1, 0xe987ac}, /* U+91EC [2000] */ + {0x8ffad2, 0xe987ae}, /* U+91EE [2000] */ + {0x8ffad3, 0xe98881}, /* U+9201 [2000] */ + {0x8ffad4, 0xe9888a}, /* U+920A [2000] */ + {0x8ffad5, 0xe98896}, /* U+9216 [2000] */ + {0x8ffad6, 0xe98897}, /* U+9217 [2000] */ {0x8ffad7, 0xf0a8a5ab}, /* U+2896B [2000] [Unicode3.1] */ - {0x8ffad8, 0x00e988b3}, /* U+9233 [2000] */ - {0x8ffad9, 0x00e98982}, /* U+9242 [2000] */ - {0x8ffada, 0x00e98987}, /* U+9247 [2000] */ - {0x8ffadb, 0x00e9898a}, /* U+924A [2000] */ - {0x8ffadc, 0x00e9898e}, /* U+924E [2000] */ - {0x8ffadd, 0x00e98991}, /* U+9251 [2000] */ - {0x8ffade, 0x00e98996}, /* U+9256 [2000] */ - {0x8ffadf, 0x00e98999}, /* U+9259 [2000] */ - {0x8ffae0, 0x00e989a0}, /* U+9260 [2000] */ - {0x8ffae1, 0x00e989a1}, /* U+9261 [2000] */ - {0x8ffae2, 0x00e989a5}, /* U+9265 [2000] */ - {0x8ffae3, 0x00e989a7}, /* U+9267 [2000] */ - {0x8ffae4, 0x00e989a8}, /* U+9268 [2000] */ + {0x8ffad8, 0xe988b3}, /* U+9233 [2000] */ + {0x8ffad9, 0xe98982}, /* U+9242 [2000] */ + {0x8ffada, 0xe98987}, /* U+9247 [2000] */ + {0x8ffadb, 0xe9898a}, /* U+924A [2000] */ + {0x8ffadc, 0xe9898e}, /* U+924E [2000] */ + {0x8ffadd, 0xe98991}, /* U+9251 [2000] */ + {0x8ffade, 0xe98996}, /* U+9256 [2000] */ + {0x8ffadf, 0xe98999}, /* U+9259 [2000] */ + {0x8ffae0, 0xe989a0}, /* U+9260 [2000] */ + {0x8ffae1, 0xe989a1}, /* U+9261 [2000] */ + {0x8ffae2, 0xe989a5}, /* U+9265 [2000] */ + {0x8ffae3, 0xe989a7}, /* U+9267 [2000] */ + {0x8ffae4, 0xe989a8}, /* U+9268 [2000] */ {0x8ffae5, 0xf0a8a687}, /* U+28987 [2000] [Unicode3.1] */ {0x8ffae6, 0xf0a8a688}, /* U+28988 [2000] [Unicode3.1] */ - {0x8ffae7, 0x00e989bc}, /* U+927C [2000] */ - {0x8ffae8, 0x00e989bd}, /* U+927D [2000] */ - {0x8ffae9, 0x00e989bf}, /* U+927F [2000] */ - {0x8ffaea, 0x00e98a89}, /* U+9289 [2000] */ - {0x8ffaeb, 0x00e98a8d}, /* U+928D [2000] */ - {0x8ffaec, 0x00e98a97}, /* U+9297 [2000] */ - {0x8ffaed, 0x00e98a99}, /* U+9299 [2000] */ - {0x8ffaee, 0x00e98a9f}, /* U+929F [2000] */ - {0x8ffaef, 0x00e98aa7}, /* U+92A7 [2000] */ - {0x8ffaf0, 0x00e98aab}, /* U+92AB [2000] */ + {0x8ffae7, 0xe989bc}, /* U+927C [2000] */ + {0x8ffae8, 0xe989bd}, /* U+927D [2000] */ + {0x8ffae9, 0xe989bf}, /* U+927F [2000] */ + {0x8ffaea, 0xe98a89}, /* U+9289 [2000] */ + {0x8ffaeb, 0xe98a8d}, /* U+928D [2000] */ + {0x8ffaec, 0xe98a97}, /* U+9297 [2000] */ + {0x8ffaed, 0xe98a99}, /* U+9299 [2000] */ + {0x8ffaee, 0xe98a9f}, /* U+929F [2000] */ + {0x8ffaef, 0xe98aa7}, /* U+92A7 [2000] */ + {0x8ffaf0, 0xe98aab}, /* U+92AB [2000] */ {0x8ffaf1, 0xf0a8a6ba}, /* U+289BA [2000] [Unicode3.1] */ {0x8ffaf2, 0xf0a8a6bb}, /* U+289BB [2000] [Unicode3.1] */ - {0x8ffaf3, 0x00e98ab2}, /* U+92B2 [2000] */ - {0x8ffaf4, 0x00e98abf}, /* U+92BF [2000] */ - {0x8ffaf5, 0x00e98b80}, /* U+92C0 [2000] */ - {0x8ffaf6, 0x00e98b86}, /* U+92C6 [2000] */ - {0x8ffaf7, 0x00e98b8e}, /* U+92CE [2000] */ - {0x8ffaf8, 0x00e98b90}, /* U+92D0 [2000] */ - {0x8ffaf9, 0x00e98b97}, /* U+92D7 [2000] */ - {0x8ffafa, 0x00e98b99}, /* U+92D9 [2000] */ - {0x8ffafb, 0x00e98ba5}, /* U+92E5 [2000] */ - {0x8ffafc, 0x00e98ba7}, /* U+92E7 [2000] */ - {0x8ffafd, 0x00e98c91}, /* U+9311 [2000] */ + {0x8ffaf3, 0xe98ab2}, /* U+92B2 [2000] */ + {0x8ffaf4, 0xe98abf}, /* U+92BF [2000] */ + {0x8ffaf5, 0xe98b80}, /* U+92C0 [2000] */ + {0x8ffaf6, 0xe98b86}, /* U+92C6 [2000] */ + {0x8ffaf7, 0xe98b8e}, /* U+92CE [2000] */ + {0x8ffaf8, 0xe98b90}, /* U+92D0 [2000] */ + {0x8ffaf9, 0xe98b97}, /* U+92D7 [2000] */ + {0x8ffafa, 0xe98b99}, /* U+92D9 [2000] */ + {0x8ffafb, 0xe98ba5}, /* U+92E5 [2000] */ + {0x8ffafc, 0xe98ba7}, /* U+92E7 [2000] */ + {0x8ffafd, 0xe98c91}, /* U+9311 [2000] */ {0x8ffafe, 0xf0a8a89e}, /* U+28A1E [2000] [Unicode3.1] */ {0x8ffba1, 0xf0a8a8a9}, /* U+28A29 [2000] [Unicode3.1] */ - {0x8ffba2, 0x00e98bb7}, /* U+92F7 [2000] */ - {0x8ffba3, 0x00e98bb9}, /* U+92F9 [2000] */ - {0x8ffba4, 0x00e98bbb}, /* U+92FB [2000] */ - {0x8ffba5, 0x00e98c82}, /* U+9302 [2000] */ - {0x8ffba6, 0x00e98c8d}, /* U+930D [2000] */ - {0x8ffba7, 0x00e98c95}, /* U+9315 [2000] */ - {0x8ffba8, 0x00e98c9d}, /* U+931D [2000] */ - {0x8ffba9, 0x00e98c9e}, /* U+931E [2000] */ - {0x8ffbaa, 0x00e98ca7}, /* U+9327 [2000] */ - {0x8ffbab, 0x00e98ca9}, /* U+9329 [2000] */ + {0x8ffba2, 0xe98bb7}, /* U+92F7 [2000] */ + {0x8ffba3, 0xe98bb9}, /* U+92F9 [2000] */ + {0x8ffba4, 0xe98bbb}, /* U+92FB [2000] */ + {0x8ffba5, 0xe98c82}, /* U+9302 [2000] */ + {0x8ffba6, 0xe98c8d}, /* U+930D [2000] */ + {0x8ffba7, 0xe98c95}, /* U+9315 [2000] */ + {0x8ffba8, 0xe98c9d}, /* U+931D [2000] */ + {0x8ffba9, 0xe98c9e}, /* U+931E [2000] */ + {0x8ffbaa, 0xe98ca7}, /* U+9327 [2000] */ + {0x8ffbab, 0xe98ca9}, /* U+9329 [2000] */ {0x8ffbac, 0xf0a8a9b1}, /* U+28A71 [2000] [Unicode3.1] */ {0x8ffbad, 0xf0a8a983}, /* U+28A43 [2000] [Unicode3.1] */ - {0x8ffbae, 0x00e98d87}, /* U+9347 [2000] */ - {0x8ffbaf, 0x00e98d91}, /* U+9351 [2000] */ - {0x8ffbb0, 0x00e98d97}, /* U+9357 [2000] */ - {0x8ffbb1, 0x00e98d9a}, /* U+935A [2000] */ - {0x8ffbb2, 0x00e98dab}, /* U+936B [2000] */ - {0x8ffbb3, 0x00e98db1}, /* U+9371 [2000] */ - {0x8ffbb4, 0x00e98db3}, /* U+9373 [2000] */ - {0x8ffbb5, 0x00e98ea1}, /* U+93A1 [2000] */ + {0x8ffbae, 0xe98d87}, /* U+9347 [2000] */ + {0x8ffbaf, 0xe98d91}, /* U+9351 [2000] */ + {0x8ffbb0, 0xe98d97}, /* U+9357 [2000] */ + {0x8ffbb1, 0xe98d9a}, /* U+935A [2000] */ + {0x8ffbb2, 0xe98dab}, /* U+936B [2000] */ + {0x8ffbb3, 0xe98db1}, /* U+9371 [2000] */ + {0x8ffbb4, 0xe98db3}, /* U+9373 [2000] */ + {0x8ffbb5, 0xe98ea1}, /* U+93A1 [2000] */ {0x8ffbb6, 0xf0a8aa99}, /* U+28A99 [2000] [Unicode3.1] */ {0x8ffbb7, 0xf0a8ab8d}, /* U+28ACD [2000] [Unicode3.1] */ - {0x8ffbb8, 0x00e98e88}, /* U+9388 [2000] */ - {0x8ffbb9, 0x00e98e8b}, /* U+938B [2000] */ - {0x8ffbba, 0x00e98e8f}, /* U+938F [2000] */ - {0x8ffbbb, 0x00e98e9e}, /* U+939E [2000] */ - {0x8ffbbc, 0x00e98fb5}, /* U+93F5 [2000] */ + {0x8ffbb8, 0xe98e88}, /* U+9388 [2000] */ + {0x8ffbb9, 0xe98e8b}, /* U+938B [2000] */ + {0x8ffbba, 0xe98e8f}, /* U+938F [2000] */ + {0x8ffbbb, 0xe98e9e}, /* U+939E [2000] */ + {0x8ffbbc, 0xe98fb5}, /* U+93F5 [2000] */ {0x8ffbbd, 0xf0a8aba4}, /* U+28AE4 [2000] [Unicode3.1] */ {0x8ffbbe, 0xf0a8ab9d}, /* U+28ADD [2000] [Unicode3.1] */ - {0x8ffbbf, 0x00e98fb1}, /* U+93F1 [2000] */ - {0x8ffbc0, 0x00e98f81}, /* U+93C1 [2000] */ - {0x8ffbc1, 0x00e98f87}, /* U+93C7 [2000] */ - {0x8ffbc2, 0x00e98f9c}, /* U+93DC [2000] */ - {0x8ffbc3, 0x00e98fa2}, /* U+93E2 [2000] */ - {0x8ffbc4, 0x00e98fa7}, /* U+93E7 [2000] */ - {0x8ffbc5, 0x00e99089}, /* U+9409 [2000] */ - {0x8ffbc6, 0x00e9908f}, /* U+940F [2000] */ - {0x8ffbc7, 0x00e99096}, /* U+9416 [2000] */ - {0x8ffbc8, 0x00e99097}, /* U+9417 [2000] */ - {0x8ffbc9, 0x00e98fbb}, /* U+93FB [2000] */ - {0x8ffbca, 0x00e990b2}, /* U+9432 [2000] */ - {0x8ffbcb, 0x00e990b4}, /* U+9434 [2000] */ - {0x8ffbcc, 0x00e990bb}, /* U+943B [2000] */ - {0x8ffbcd, 0x00e99185}, /* U+9445 [2000] */ + {0x8ffbbf, 0xe98fb1}, /* U+93F1 [2000] */ + {0x8ffbc0, 0xe98f81}, /* U+93C1 [2000] */ + {0x8ffbc1, 0xe98f87}, /* U+93C7 [2000] */ + {0x8ffbc2, 0xe98f9c}, /* U+93DC [2000] */ + {0x8ffbc3, 0xe98fa2}, /* U+93E2 [2000] */ + {0x8ffbc4, 0xe98fa7}, /* U+93E7 [2000] */ + {0x8ffbc5, 0xe99089}, /* U+9409 [2000] */ + {0x8ffbc6, 0xe9908f}, /* U+940F [2000] */ + {0x8ffbc7, 0xe99096}, /* U+9416 [2000] */ + {0x8ffbc8, 0xe99097}, /* U+9417 [2000] */ + {0x8ffbc9, 0xe98fbb}, /* U+93FB [2000] */ + {0x8ffbca, 0xe990b2}, /* U+9432 [2000] */ + {0x8ffbcb, 0xe990b4}, /* U+9434 [2000] */ + {0x8ffbcc, 0xe990bb}, /* U+943B [2000] */ + {0x8ffbcd, 0xe99185}, /* U+9445 [2000] */ {0x8ffbce, 0xf0a8af81}, /* U+28BC1 [2000] [Unicode3.1] */ {0x8ffbcf, 0xf0a8afaf}, /* U+28BEF [2000] [Unicode3.1] */ - {0x8ffbd0, 0x00e991ad}, /* U+946D [2000] */ - {0x8ffbd1, 0x00e991af}, /* U+946F [2000] */ - {0x8ffbd2, 0x00e995b8}, /* U+9578 [2000] */ - {0x8ffbd3, 0x00e995b9}, /* U+9579 [2000] */ - {0x8ffbd4, 0x00e99686}, /* U+9586 [2000] */ - {0x8ffbd5, 0x00e9968c}, /* U+958C [2000] */ - {0x8ffbd6, 0x00e9968d}, /* U+958D [2000] */ + {0x8ffbd0, 0xe991ad}, /* U+946D [2000] */ + {0x8ffbd1, 0xe991af}, /* U+946F [2000] */ + {0x8ffbd2, 0xe995b8}, /* U+9578 [2000] */ + {0x8ffbd3, 0xe995b9}, /* U+9579 [2000] */ + {0x8ffbd4, 0xe99686}, /* U+9586 [2000] */ + {0x8ffbd5, 0xe9968c}, /* U+958C [2000] */ + {0x8ffbd6, 0xe9968d}, /* U+958D [2000] */ {0x8ffbd7, 0xf0a8b490}, /* U+28D10 [2000] [Unicode3.1] */ - {0x8ffbd8, 0x00e996ab}, /* U+95AB [2000] */ - {0x8ffbd9, 0x00e996b4}, /* U+95B4 [2000] */ + {0x8ffbd8, 0xe996ab}, /* U+95AB [2000] */ + {0x8ffbd9, 0xe996b4}, /* U+95B4 [2000] */ {0x8ffbda, 0xf0a8b5b1}, /* U+28D71 [2000] [Unicode3.1] */ - {0x8ffbdb, 0x00e99788}, /* U+95C8 [2000] */ + {0x8ffbdb, 0xe99788}, /* U+95C8 [2000] */ {0x8ffbdc, 0xf0a8b7bb}, /* U+28DFB [2000] [Unicode3.1] */ {0x8ffbdd, 0xf0a8b89f}, /* U+28E1F [2000] [Unicode3.1] */ - {0x8ffbde, 0x00e998ac}, /* U+962C [2000] */ - {0x8ffbdf, 0x00e998b3}, /* U+9633 [2000] */ - {0x8ffbe0, 0x00e998b4}, /* U+9634 [2000] */ + {0x8ffbde, 0xe998ac}, /* U+962C [2000] */ + {0x8ffbdf, 0xe998b3}, /* U+9633 [2000] */ + {0x8ffbe0, 0xe998b4}, /* U+9634 [2000] */ {0x8ffbe1, 0xf0a8b8b6}, /* U+28E36 [2000] [Unicode3.1] */ - {0x8ffbe2, 0x00e998bc}, /* U+963C [2000] */ - {0x8ffbe3, 0x00e99981}, /* U+9641 [2000] */ - {0x8ffbe4, 0x00e999a1}, /* U+9661 [2000] */ + {0x8ffbe2, 0xe998bc}, /* U+963C [2000] */ + {0x8ffbe3, 0xe99981}, /* U+9641 [2000] */ + {0x8ffbe4, 0xe999a1}, /* U+9661 [2000] */ {0x8ffbe5, 0xf0a8ba89}, /* U+28E89 [2000] [Unicode3.1] */ - {0x8ffbe6, 0x00e99a82}, /* U+9682 [2000] */ + {0x8ffbe6, 0xe99a82}, /* U+9682 [2000] */ {0x8ffbe7, 0xf0a8bbab}, /* U+28EEB [2000] [Unicode3.1] */ - {0x8ffbe8, 0x00e99a9a}, /* U+969A [2000] */ + {0x8ffbe8, 0xe99a9a}, /* U+969A [2000] */ {0x8ffbe9, 0xf0a8bcb2}, /* U+28F32 [2000] [Unicode3.1] */ - {0x8ffbea, 0x00e4a7a7}, /* U+49E7 [2000] */ - {0x8ffbeb, 0x00e99aa9}, /* U+96A9 [2000] */ - {0x8ffbec, 0x00e99aaf}, /* U+96AF [2000] */ - {0x8ffbed, 0x00e99ab3}, /* U+96B3 [2000] */ - {0x8ffbee, 0x00e99aba}, /* U+96BA [2000] */ - {0x8ffbef, 0x00e99abd}, /* U+96BD [2000] */ - {0x8ffbf0, 0x00e4a7ba}, /* U+49FA [2000] */ + {0x8ffbea, 0xe4a7a7}, /* U+49E7 [2000] */ + {0x8ffbeb, 0xe99aa9}, /* U+96A9 [2000] */ + {0x8ffbec, 0xe99aaf}, /* U+96AF [2000] */ + {0x8ffbed, 0xe99ab3}, /* U+96B3 [2000] */ + {0x8ffbee, 0xe99aba}, /* U+96BA [2000] */ + {0x8ffbef, 0xe99abd}, /* U+96BD [2000] */ + {0x8ffbf0, 0xe4a7ba}, /* U+49FA [2000] */ {0x8ffbf1, 0xf0a8bfb8}, /* U+28FF8 [2000] [Unicode3.1] */ - {0x8ffbf2, 0x00e99b98}, /* U+96D8 [2000] */ - {0x8ffbf3, 0x00e99b9a}, /* U+96DA [2000] */ - {0x8ffbf4, 0x00e99b9d}, /* U+96DD [2000] */ - {0x8ffbf5, 0x00e4a884}, /* U+4A04 [2000] */ - {0x8ffbf6, 0x00e99c94}, /* U+9714 [2000] */ - {0x8ffbf7, 0x00e99ca3}, /* U+9723 [2000] */ - {0x8ffbf8, 0x00e4a8a9}, /* U+4A29 [2000] */ - {0x8ffbf9, 0x00e99cb6}, /* U+9736 [2000] */ - {0x8ffbfa, 0x00e99d81}, /* U+9741 [2000] */ - {0x8ffbfb, 0x00e99d87}, /* U+9747 [2000] */ - {0x8ffbfc, 0x00e99d95}, /* U+9755 [2000] */ - {0x8ffbfd, 0x00e99d97}, /* U+9757 [2000] */ - {0x8ffbfe, 0x00e99d9b}, /* U+975B [2000] */ - {0x8ffca1, 0x00e99daa}, /* U+976A [2000] */ + {0x8ffbf2, 0xe99b98}, /* U+96D8 [2000] */ + {0x8ffbf3, 0xe99b9a}, /* U+96DA [2000] */ + {0x8ffbf4, 0xe99b9d}, /* U+96DD [2000] */ + {0x8ffbf5, 0xe4a884}, /* U+4A04 [2000] */ + {0x8ffbf6, 0xe99c94}, /* U+9714 [2000] */ + {0x8ffbf7, 0xe99ca3}, /* U+9723 [2000] */ + {0x8ffbf8, 0xe4a8a9}, /* U+4A29 [2000] */ + {0x8ffbf9, 0xe99cb6}, /* U+9736 [2000] */ + {0x8ffbfa, 0xe99d81}, /* U+9741 [2000] */ + {0x8ffbfb, 0xe99d87}, /* U+9747 [2000] */ + {0x8ffbfc, 0xe99d95}, /* U+9755 [2000] */ + {0x8ffbfd, 0xe99d97}, /* U+9757 [2000] */ + {0x8ffbfe, 0xe99d9b}, /* U+975B [2000] */ + {0x8ffca1, 0xe99daa}, /* U+976A [2000] */ {0x8ffca2, 0xf0a98aa0}, /* U+292A0 [2000] [Unicode3.1] */ {0x8ffca3, 0xf0a98ab1}, /* U+292B1 [2000] [Unicode3.1] */ - {0x8ffca4, 0x00e99e96}, /* U+9796 [2000] */ - {0x8ffca5, 0x00e99e9a}, /* U+979A [2000] */ - {0x8ffca6, 0x00e99e9e}, /* U+979E [2000] */ - {0x8ffca7, 0x00e99ea2}, /* U+97A2 [2000] */ - {0x8ffca8, 0x00e99eb1}, /* U+97B1 [2000] */ - {0x8ffca9, 0x00e99eb2}, /* U+97B2 [2000] */ - {0x8ffcaa, 0x00e99ebe}, /* U+97BE [2000] */ - {0x8ffcab, 0x00e99f8c}, /* U+97CC [2000] */ - {0x8ffcac, 0x00e99f91}, /* U+97D1 [2000] */ - {0x8ffcad, 0x00e99f94}, /* U+97D4 [2000] */ - {0x8ffcae, 0x00e99f98}, /* U+97D8 [2000] */ - {0x8ffcaf, 0x00e99f99}, /* U+97D9 [2000] */ - {0x8ffcb0, 0x00e99fa1}, /* U+97E1 [2000] */ - {0x8ffcb1, 0x00e99fb1}, /* U+97F1 [2000] */ - {0x8ffcb2, 0x00e9a084}, /* U+9804 [2000] */ - {0x8ffcb3, 0x00e9a08d}, /* U+980D [2000] */ - {0x8ffcb4, 0x00e9a08e}, /* U+980E [2000] */ - {0x8ffcb5, 0x00e9a094}, /* U+9814 [2000] */ - {0x8ffcb6, 0x00e9a096}, /* U+9816 [2000] */ - {0x8ffcb7, 0x00e4aabc}, /* U+4ABC [2000] */ + {0x8ffca4, 0xe99e96}, /* U+9796 [2000] */ + {0x8ffca5, 0xe99e9a}, /* U+979A [2000] */ + {0x8ffca6, 0xe99e9e}, /* U+979E [2000] */ + {0x8ffca7, 0xe99ea2}, /* U+97A2 [2000] */ + {0x8ffca8, 0xe99eb1}, /* U+97B1 [2000] */ + {0x8ffca9, 0xe99eb2}, /* U+97B2 [2000] */ + {0x8ffcaa, 0xe99ebe}, /* U+97BE [2000] */ + {0x8ffcab, 0xe99f8c}, /* U+97CC [2000] */ + {0x8ffcac, 0xe99f91}, /* U+97D1 [2000] */ + {0x8ffcad, 0xe99f94}, /* U+97D4 [2000] */ + {0x8ffcae, 0xe99f98}, /* U+97D8 [2000] */ + {0x8ffcaf, 0xe99f99}, /* U+97D9 [2000] */ + {0x8ffcb0, 0xe99fa1}, /* U+97E1 [2000] */ + {0x8ffcb1, 0xe99fb1}, /* U+97F1 [2000] */ + {0x8ffcb2, 0xe9a084}, /* U+9804 [2000] */ + {0x8ffcb3, 0xe9a08d}, /* U+980D [2000] */ + {0x8ffcb4, 0xe9a08e}, /* U+980E [2000] */ + {0x8ffcb5, 0xe9a094}, /* U+9814 [2000] */ + {0x8ffcb6, 0xe9a096}, /* U+9816 [2000] */ + {0x8ffcb7, 0xe4aabc}, /* U+4ABC [2000] */ {0x8ffcb8, 0xf0a99290}, /* U+29490 [2000] [Unicode3.1] */ - {0x8ffcb9, 0x00e9a0a3}, /* U+9823 [2000] */ - {0x8ffcba, 0x00e9a0b2}, /* U+9832 [2000] */ - {0x8ffcbb, 0x00e9a0b3}, /* U+9833 [2000] */ - {0x8ffcbc, 0x00e9a0a5}, /* U+9825 [2000] */ - {0x8ffcbd, 0x00e9a187}, /* U+9847 [2000] */ - {0x8ffcbe, 0x00e9a1a6}, /* U+9866 [2000] */ - {0x8ffcbf, 0x00e9a2ab}, /* U+98AB [2000] */ - {0x8ffcc0, 0x00e9a2ad}, /* U+98AD [2000] */ - {0x8ffcc1, 0x00e9a2b0}, /* U+98B0 [2000] */ + {0x8ffcb9, 0xe9a0a3}, /* U+9823 [2000] */ + {0x8ffcba, 0xe9a0b2}, /* U+9832 [2000] */ + {0x8ffcbb, 0xe9a0b3}, /* U+9833 [2000] */ + {0x8ffcbc, 0xe9a0a5}, /* U+9825 [2000] */ + {0x8ffcbd, 0xe9a187}, /* U+9847 [2000] */ + {0x8ffcbe, 0xe9a1a6}, /* U+9866 [2000] */ + {0x8ffcbf, 0xe9a2ab}, /* U+98AB [2000] */ + {0x8ffcc0, 0xe9a2ad}, /* U+98AD [2000] */ + {0x8ffcc1, 0xe9a2b0}, /* U+98B0 [2000] */ {0x8ffcc2, 0xf0a9978f}, /* U+295CF [2000] [Unicode3.1] */ - {0x8ffcc3, 0x00e9a2b7}, /* U+98B7 [2000] */ - {0x8ffcc4, 0x00e9a2b8}, /* U+98B8 [2000] */ - {0x8ffcc5, 0x00e9a2bb}, /* U+98BB [2000] */ - {0x8ffcc6, 0x00e9a2bc}, /* U+98BC [2000] */ - {0x8ffcc7, 0x00e9a2bf}, /* U+98BF [2000] */ - {0x8ffcc8, 0x00e9a382}, /* U+98C2 [2000] */ - {0x8ffcc9, 0x00e9a387}, /* U+98C7 [2000] */ - {0x8ffcca, 0x00e9a38b}, /* U+98CB [2000] */ - {0x8ffccb, 0x00e9a3a0}, /* U+98E0 [2000] */ + {0x8ffcc3, 0xe9a2b7}, /* U+98B7 [2000] */ + {0x8ffcc4, 0xe9a2b8}, /* U+98B8 [2000] */ + {0x8ffcc5, 0xe9a2bb}, /* U+98BB [2000] */ + {0x8ffcc6, 0xe9a2bc}, /* U+98BC [2000] */ + {0x8ffcc7, 0xe9a2bf}, /* U+98BF [2000] */ + {0x8ffcc8, 0xe9a382}, /* U+98C2 [2000] */ + {0x8ffcc9, 0xe9a387}, /* U+98C7 [2000] */ + {0x8ffcca, 0xe9a38b}, /* U+98CB [2000] */ + {0x8ffccb, 0xe9a3a0}, /* U+98E0 [2000] */ {0x8ffccc, 0xf0a999bf}, /* U+2967F [2000] [Unicode3.1] */ - {0x8ffccd, 0x00e9a3a1}, /* U+98E1 [2000] */ - {0x8ffcce, 0x00e9a3a3}, /* U+98E3 [2000] */ - {0x8ffccf, 0x00e9a3a5}, /* U+98E5 [2000] */ - {0x8ffcd0, 0x00e9a3aa}, /* U+98EA [2000] */ - {0x8ffcd1, 0x00e9a3b0}, /* U+98F0 [2000] */ - {0x8ffcd2, 0x00e9a3b1}, /* U+98F1 [2000] */ - {0x8ffcd3, 0x00e9a3b3}, /* U+98F3 [2000] */ - {0x8ffcd4, 0x00e9a488}, /* U+9908 [2000] */ - {0x8ffcd5, 0x00e4acbb}, /* U+4B3B [2000] */ + {0x8ffccd, 0xe9a3a1}, /* U+98E1 [2000] */ + {0x8ffcce, 0xe9a3a3}, /* U+98E3 [2000] */ + {0x8ffccf, 0xe9a3a5}, /* U+98E5 [2000] */ + {0x8ffcd0, 0xe9a3aa}, /* U+98EA [2000] */ + {0x8ffcd1, 0xe9a3b0}, /* U+98F0 [2000] */ + {0x8ffcd2, 0xe9a3b1}, /* U+98F1 [2000] */ + {0x8ffcd3, 0xe9a3b3}, /* U+98F3 [2000] */ + {0x8ffcd4, 0xe9a488}, /* U+9908 [2000] */ + {0x8ffcd5, 0xe4acbb}, /* U+4B3B [2000] */ {0x8ffcd6, 0xf0a99bb0}, /* U+296F0 [2000] [Unicode3.1] */ - {0x8ffcd7, 0x00e9a496}, /* U+9916 [2000] */ - {0x8ffcd8, 0x00e9a497}, /* U+9917 [2000] */ + {0x8ffcd7, 0xe9a496}, /* U+9916 [2000] */ + {0x8ffcd8, 0xe9a497}, /* U+9917 [2000] */ {0x8ffcd9, 0xf0a99c99}, /* U+29719 [2000] [Unicode3.1] */ - {0x8ffcda, 0x00e9a49a}, /* U+991A [2000] */ - {0x8ffcdb, 0x00e9a49b}, /* U+991B [2000] */ - {0x8ffcdc, 0x00e9a49c}, /* U+991C [2000] */ + {0x8ffcda, 0xe9a49a}, /* U+991A [2000] */ + {0x8ffcdb, 0xe9a49b}, /* U+991B [2000] */ + {0x8ffcdc, 0xe9a49c}, /* U+991C [2000] */ {0x8ffcdd, 0xf0a99d90}, /* U+29750 [2000] [Unicode3.1] */ - {0x8ffcde, 0x00e9a4b1}, /* U+9931 [2000] */ - {0x8ffcdf, 0x00e9a4b2}, /* U+9932 [2000] */ - {0x8ffce0, 0x00e9a4b3}, /* U+9933 [2000] */ - {0x8ffce1, 0x00e9a4ba}, /* U+993A [2000] */ - {0x8ffce2, 0x00e9a4bb}, /* U+993B [2000] */ - {0x8ffce3, 0x00e9a4bc}, /* U+993C [2000] */ - {0x8ffce4, 0x00e9a580}, /* U+9940 [2000] */ - {0x8ffce5, 0x00e9a581}, /* U+9941 [2000] */ - {0x8ffce6, 0x00e9a586}, /* U+9946 [2000] */ - {0x8ffce7, 0x00e9a58d}, /* U+994D [2000] */ - {0x8ffce8, 0x00e9a58e}, /* U+994E [2000] */ - {0x8ffce9, 0x00e9a59c}, /* U+995C [2000] */ - {0x8ffcea, 0x00e9a59f}, /* U+995F [2000] */ - {0x8ffceb, 0x00e9a5a0}, /* U+9960 [2000] */ - {0x8ffcec, 0x00e9a6a3}, /* U+99A3 [2000] */ - {0x8ffced, 0x00e9a6a6}, /* U+99A6 [2000] */ - {0x8ffcee, 0x00e9a6b9}, /* U+99B9 [2000] */ - {0x8ffcef, 0x00e9a6bd}, /* U+99BD [2000] */ - {0x8ffcf0, 0x00e9a6bf}, /* U+99BF [2000] */ - {0x8ffcf1, 0x00e9a783}, /* U+99C3 [2000] */ - {0x8ffcf2, 0x00e9a789}, /* U+99C9 [2000] */ - {0x8ffcf3, 0x00e9a794}, /* U+99D4 [2000] */ - {0x8ffcf4, 0x00e9a799}, /* U+99D9 [2000] */ - {0x8ffcf5, 0x00e9a79e}, /* U+99DE [2000] */ + {0x8ffcde, 0xe9a4b1}, /* U+9931 [2000] */ + {0x8ffcdf, 0xe9a4b2}, /* U+9932 [2000] */ + {0x8ffce0, 0xe9a4b3}, /* U+9933 [2000] */ + {0x8ffce1, 0xe9a4ba}, /* U+993A [2000] */ + {0x8ffce2, 0xe9a4bb}, /* U+993B [2000] */ + {0x8ffce3, 0xe9a4bc}, /* U+993C [2000] */ + {0x8ffce4, 0xe9a580}, /* U+9940 [2000] */ + {0x8ffce5, 0xe9a581}, /* U+9941 [2000] */ + {0x8ffce6, 0xe9a586}, /* U+9946 [2000] */ + {0x8ffce7, 0xe9a58d}, /* U+994D [2000] */ + {0x8ffce8, 0xe9a58e}, /* U+994E [2000] */ + {0x8ffce9, 0xe9a59c}, /* U+995C [2000] */ + {0x8ffcea, 0xe9a59f}, /* U+995F [2000] */ + {0x8ffceb, 0xe9a5a0}, /* U+9960 [2000] */ + {0x8ffcec, 0xe9a6a3}, /* U+99A3 [2000] */ + {0x8ffced, 0xe9a6a6}, /* U+99A6 [2000] */ + {0x8ffcee, 0xe9a6b9}, /* U+99B9 [2000] */ + {0x8ffcef, 0xe9a6bd}, /* U+99BD [2000] */ + {0x8ffcf0, 0xe9a6bf}, /* U+99BF [2000] */ + {0x8ffcf1, 0xe9a783}, /* U+99C3 [2000] */ + {0x8ffcf2, 0xe9a789}, /* U+99C9 [2000] */ + {0x8ffcf3, 0xe9a794}, /* U+99D4 [2000] */ + {0x8ffcf4, 0xe9a799}, /* U+99D9 [2000] */ + {0x8ffcf5, 0xe9a79e}, /* U+99DE [2000] */ {0x8ffcf6, 0xf0a9a386}, /* U+298C6 [2000] [Unicode3.1] */ - {0x8ffcf7, 0x00e9a7b0}, /* U+99F0 [2000] */ - {0x8ffcf8, 0x00e9a7b9}, /* U+99F9 [2000] */ - {0x8ffcf9, 0x00e9a7bc}, /* U+99FC [2000] */ - {0x8ffcfa, 0x00e9a88a}, /* U+9A0A [2000] */ - {0x8ffcfb, 0x00e9a891}, /* U+9A11 [2000] */ - {0x8ffcfc, 0x00e9a896}, /* U+9A16 [2000] */ - {0x8ffcfd, 0x00e9a89a}, /* U+9A1A [2000] */ - {0x8ffcfe, 0x00e9a8a0}, /* U+9A20 [2000] */ - {0x8ffda1, 0x00e9a8b1}, /* U+9A31 [2000] */ - {0x8ffda2, 0x00e9a8b6}, /* U+9A36 [2000] */ - {0x8ffda3, 0x00e9a984}, /* U+9A44 [2000] */ - {0x8ffda4, 0x00e9a98c}, /* U+9A4C [2000] */ - {0x8ffda5, 0x00e9a998}, /* U+9A58 [2000] */ - {0x8ffda6, 0x00e4af82}, /* U+4BC2 [2000] */ - {0x8ffda7, 0x00e9aaaf}, /* U+9AAF [2000] */ - {0x8ffda8, 0x00e4af8a}, /* U+4BCA [2000] */ - {0x8ffda9, 0x00e9aab7}, /* U+9AB7 [2000] */ - {0x8ffdaa, 0x00e4af92}, /* U+4BD2 [2000] */ - {0x8ffdab, 0x00e9aab9}, /* U+9AB9 [2000] */ + {0x8ffcf7, 0xe9a7b0}, /* U+99F0 [2000] */ + {0x8ffcf8, 0xe9a7b9}, /* U+99F9 [2000] */ + {0x8ffcf9, 0xe9a7bc}, /* U+99FC [2000] */ + {0x8ffcfa, 0xe9a88a}, /* U+9A0A [2000] */ + {0x8ffcfb, 0xe9a891}, /* U+9A11 [2000] */ + {0x8ffcfc, 0xe9a896}, /* U+9A16 [2000] */ + {0x8ffcfd, 0xe9a89a}, /* U+9A1A [2000] */ + {0x8ffcfe, 0xe9a8a0}, /* U+9A20 [2000] */ + {0x8ffda1, 0xe9a8b1}, /* U+9A31 [2000] */ + {0x8ffda2, 0xe9a8b6}, /* U+9A36 [2000] */ + {0x8ffda3, 0xe9a984}, /* U+9A44 [2000] */ + {0x8ffda4, 0xe9a98c}, /* U+9A4C [2000] */ + {0x8ffda5, 0xe9a998}, /* U+9A58 [2000] */ + {0x8ffda6, 0xe4af82}, /* U+4BC2 [2000] */ + {0x8ffda7, 0xe9aaaf}, /* U+9AAF [2000] */ + {0x8ffda8, 0xe4af8a}, /* U+4BCA [2000] */ + {0x8ffda9, 0xe9aab7}, /* U+9AB7 [2000] */ + {0x8ffdaa, 0xe4af92}, /* U+4BD2 [2000] */ + {0x8ffdab, 0xe9aab9}, /* U+9AB9 [2000] */ {0x8ffdac, 0xf0a9a9b2}, /* U+29A72 [2000] [Unicode3.1] */ - {0x8ffdad, 0x00e9ab86}, /* U+9AC6 [2000] */ - {0x8ffdae, 0x00e9ab90}, /* U+9AD0 [2000] */ - {0x8ffdaf, 0x00e9ab92}, /* U+9AD2 [2000] */ - {0x8ffdb0, 0x00e9ab95}, /* U+9AD5 [2000] */ - {0x8ffdb1, 0x00e4afa8}, /* U+4BE8 [2000] */ - {0x8ffdb2, 0x00e9ab9c}, /* U+9ADC [2000] */ - {0x8ffdb3, 0x00e9aba0}, /* U+9AE0 [2000] */ - {0x8ffdb4, 0x00e9aba5}, /* U+9AE5 [2000] */ - {0x8ffdb5, 0x00e9aba9}, /* U+9AE9 [2000] */ - {0x8ffdb6, 0x00e9ac83}, /* U+9B03 [2000] */ - {0x8ffdb7, 0x00e9ac8c}, /* U+9B0C [2000] */ - {0x8ffdb8, 0x00e9ac90}, /* U+9B10 [2000] */ - {0x8ffdb9, 0x00e9ac92}, /* U+9B12 [2000] */ - {0x8ffdba, 0x00e9ac96}, /* U+9B16 [2000] */ - {0x8ffdbb, 0x00e9ac9c}, /* U+9B1C [2000] */ - {0x8ffdbc, 0x00e9acab}, /* U+9B2B [2000] */ - {0x8ffdbd, 0x00e9acb3}, /* U+9B33 [2000] */ - {0x8ffdbe, 0x00e9acbd}, /* U+9B3D [2000] */ - {0x8ffdbf, 0x00e4b0a0}, /* U+4C20 [2000] */ - {0x8ffdc0, 0x00e9ad8b}, /* U+9B4B [2000] */ - {0x8ffdc1, 0x00e9ada3}, /* U+9B63 [2000] */ - {0x8ffdc2, 0x00e9ada5}, /* U+9B65 [2000] */ - {0x8ffdc3, 0x00e9adab}, /* U+9B6B [2000] */ - {0x8ffdc4, 0x00e9adac}, /* U+9B6C [2000] */ - {0x8ffdc5, 0x00e9adb3}, /* U+9B73 [2000] */ - {0x8ffdc6, 0x00e9adb6}, /* U+9B76 [2000] */ - {0x8ffdc7, 0x00e9adb7}, /* U+9B77 [2000] */ - {0x8ffdc8, 0x00e9aea6}, /* U+9BA6 [2000] */ - {0x8ffdc9, 0x00e9aeac}, /* U+9BAC [2000] */ - {0x8ffdca, 0x00e9aeb1}, /* U+9BB1 [2000] */ + {0x8ffdad, 0xe9ab86}, /* U+9AC6 [2000] */ + {0x8ffdae, 0xe9ab90}, /* U+9AD0 [2000] */ + {0x8ffdaf, 0xe9ab92}, /* U+9AD2 [2000] */ + {0x8ffdb0, 0xe9ab95}, /* U+9AD5 [2000] */ + {0x8ffdb1, 0xe4afa8}, /* U+4BE8 [2000] */ + {0x8ffdb2, 0xe9ab9c}, /* U+9ADC [2000] */ + {0x8ffdb3, 0xe9aba0}, /* U+9AE0 [2000] */ + {0x8ffdb4, 0xe9aba5}, /* U+9AE5 [2000] */ + {0x8ffdb5, 0xe9aba9}, /* U+9AE9 [2000] */ + {0x8ffdb6, 0xe9ac83}, /* U+9B03 [2000] */ + {0x8ffdb7, 0xe9ac8c}, /* U+9B0C [2000] */ + {0x8ffdb8, 0xe9ac90}, /* U+9B10 [2000] */ + {0x8ffdb9, 0xe9ac92}, /* U+9B12 [2000] */ + {0x8ffdba, 0xe9ac96}, /* U+9B16 [2000] */ + {0x8ffdbb, 0xe9ac9c}, /* U+9B1C [2000] */ + {0x8ffdbc, 0xe9acab}, /* U+9B2B [2000] */ + {0x8ffdbd, 0xe9acb3}, /* U+9B33 [2000] */ + {0x8ffdbe, 0xe9acbd}, /* U+9B3D [2000] */ + {0x8ffdbf, 0xe4b0a0}, /* U+4C20 [2000] */ + {0x8ffdc0, 0xe9ad8b}, /* U+9B4B [2000] */ + {0x8ffdc1, 0xe9ada3}, /* U+9B63 [2000] */ + {0x8ffdc2, 0xe9ada5}, /* U+9B65 [2000] */ + {0x8ffdc3, 0xe9adab}, /* U+9B6B [2000] */ + {0x8ffdc4, 0xe9adac}, /* U+9B6C [2000] */ + {0x8ffdc5, 0xe9adb3}, /* U+9B73 [2000] */ + {0x8ffdc6, 0xe9adb6}, /* U+9B76 [2000] */ + {0x8ffdc7, 0xe9adb7}, /* U+9B77 [2000] */ + {0x8ffdc8, 0xe9aea6}, /* U+9BA6 [2000] */ + {0x8ffdc9, 0xe9aeac}, /* U+9BAC [2000] */ + {0x8ffdca, 0xe9aeb1}, /* U+9BB1 [2000] */ {0x8ffdcb, 0xf0a9b79b}, /* U+29DDB [2000] [Unicode3.1] */ {0x8ffdcc, 0xf0a9b8bd}, /* U+29E3D [2000] [Unicode3.1] */ - {0x8ffdcd, 0x00e9aeb2}, /* U+9BB2 [2000] */ - {0x8ffdce, 0x00e9aeb8}, /* U+9BB8 [2000] */ - {0x8ffdcf, 0x00e9aebe}, /* U+9BBE [2000] */ - {0x8ffdd0, 0x00e9af87}, /* U+9BC7 [2000] */ - {0x8ffdd1, 0x00e9afb3}, /* U+9BF3 [2000] */ - {0x8ffdd2, 0x00e9af98}, /* U+9BD8 [2000] */ - {0x8ffdd3, 0x00e9af9d}, /* U+9BDD [2000] */ - {0x8ffdd4, 0x00e9afa7}, /* U+9BE7 [2000] */ - {0x8ffdd5, 0x00e9afaa}, /* U+9BEA [2000] */ - {0x8ffdd6, 0x00e9afab}, /* U+9BEB [2000] */ - {0x8ffdd7, 0x00e9afaf}, /* U+9BEF [2000] */ - {0x8ffdd8, 0x00e9afae}, /* U+9BEE [2000] */ + {0x8ffdcd, 0xe9aeb2}, /* U+9BB2 [2000] */ + {0x8ffdce, 0xe9aeb8}, /* U+9BB8 [2000] */ + {0x8ffdcf, 0xe9aebe}, /* U+9BBE [2000] */ + {0x8ffdd0, 0xe9af87}, /* U+9BC7 [2000] */ + {0x8ffdd1, 0xe9afb3}, /* U+9BF3 [2000] */ + {0x8ffdd2, 0xe9af98}, /* U+9BD8 [2000] */ + {0x8ffdd3, 0xe9af9d}, /* U+9BDD [2000] */ + {0x8ffdd4, 0xe9afa7}, /* U+9BE7 [2000] */ + {0x8ffdd5, 0xe9afaa}, /* U+9BEA [2000] */ + {0x8ffdd6, 0xe9afab}, /* U+9BEB [2000] */ + {0x8ffdd7, 0xe9afaf}, /* U+9BEF [2000] */ + {0x8ffdd8, 0xe9afae}, /* U+9BEE [2000] */ {0x8ffdd9, 0xf0a9b895}, /* U+29E15 [2000] [Unicode3.1] */ - {0x8ffdda, 0x00e9afba}, /* U+9BFA [2000] */ + {0x8ffdda, 0xe9afba}, /* U+9BFA [2000] */ {0x8ffddb, 0xf0a9ba8a}, /* U+29E8A [2000] [Unicode3.1] */ - {0x8ffddc, 0x00e9afb7}, /* U+9BF7 [2000] */ + {0x8ffddc, 0xe9afb7}, /* U+9BF7 [2000] */ {0x8ffddd, 0xf0a9b989}, /* U+29E49 [2000] [Unicode3.1] */ - {0x8ffdde, 0x00e9b096}, /* U+9C16 [2000] */ - {0x8ffddf, 0x00e9b098}, /* U+9C18 [2000] */ - {0x8ffde0, 0x00e9b099}, /* U+9C19 [2000] */ - {0x8ffde1, 0x00e9b09a}, /* U+9C1A [2000] */ - {0x8ffde2, 0x00e9b09d}, /* U+9C1D [2000] */ - {0x8ffde3, 0x00e9b0a2}, /* U+9C22 [2000] */ - {0x8ffde4, 0x00e9b0a7}, /* U+9C27 [2000] */ - {0x8ffde5, 0x00e9b0a9}, /* U+9C29 [2000] */ - {0x8ffde6, 0x00e9b0aa}, /* U+9C2A [2000] */ + {0x8ffdde, 0xe9b096}, /* U+9C16 [2000] */ + {0x8ffddf, 0xe9b098}, /* U+9C18 [2000] */ + {0x8ffde0, 0xe9b099}, /* U+9C19 [2000] */ + {0x8ffde1, 0xe9b09a}, /* U+9C1A [2000] */ + {0x8ffde2, 0xe9b09d}, /* U+9C1D [2000] */ + {0x8ffde3, 0xe9b0a2}, /* U+9C22 [2000] */ + {0x8ffde4, 0xe9b0a7}, /* U+9C27 [2000] */ + {0x8ffde5, 0xe9b0a9}, /* U+9C29 [2000] */ + {0x8ffde6, 0xe9b0aa}, /* U+9C2A [2000] */ {0x8ffde7, 0xf0a9bb84}, /* U+29EC4 [2000] [Unicode3.1] */ - {0x8ffde8, 0x00e9b0b1}, /* U+9C31 [2000] */ - {0x8ffde9, 0x00e9b0b6}, /* U+9C36 [2000] */ - {0x8ffdea, 0x00e9b0b7}, /* U+9C37 [2000] */ - {0x8ffdeb, 0x00e9b185}, /* U+9C45 [2000] */ - {0x8ffdec, 0x00e9b19c}, /* U+9C5C [2000] */ + {0x8ffde8, 0xe9b0b1}, /* U+9C31 [2000] */ + {0x8ffde9, 0xe9b0b6}, /* U+9C36 [2000] */ + {0x8ffdea, 0xe9b0b7}, /* U+9C37 [2000] */ + {0x8ffdeb, 0xe9b185}, /* U+9C45 [2000] */ + {0x8ffdec, 0xe9b19c}, /* U+9C5C [2000] */ {0x8ffded, 0xf0a9bba9}, /* U+29EE9 [2000] [Unicode3.1] */ - {0x8ffdee, 0x00e9b189}, /* U+9C49 [2000] */ - {0x8ffdef, 0x00e9b18a}, /* U+9C4A [2000] */ + {0x8ffdee, 0xe9b189}, /* U+9C49 [2000] */ + {0x8ffdef, 0xe9b18a}, /* U+9C4A [2000] */ {0x8ffdf0, 0xf0a9bb9b}, /* U+29EDB [2000] [Unicode3.1] */ - {0x8ffdf1, 0x00e9b194}, /* U+9C54 [2000] */ - {0x8ffdf2, 0x00e9b198}, /* U+9C58 [2000] */ - {0x8ffdf3, 0x00e9b19b}, /* U+9C5B [2000] */ - {0x8ffdf4, 0x00e9b19d}, /* U+9C5D [2000] */ - {0x8ffdf5, 0x00e9b19f}, /* U+9C5F [2000] */ - {0x8ffdf6, 0x00e9b1a9}, /* U+9C69 [2000] */ - {0x8ffdf7, 0x00e9b1aa}, /* U+9C6A [2000] */ - {0x8ffdf8, 0x00e9b1ab}, /* U+9C6B [2000] */ - {0x8ffdf9, 0x00e9b1ad}, /* U+9C6D [2000] */ - {0x8ffdfa, 0x00e9b1ae}, /* U+9C6E [2000] */ - {0x8ffdfb, 0x00e9b1b0}, /* U+9C70 [2000] */ - {0x8ffdfc, 0x00e9b1b2}, /* U+9C72 [2000] */ - {0x8ffdfd, 0x00e9b1b5}, /* U+9C75 [2000] */ - {0x8ffdfe, 0x00e9b1ba}, /* U+9C7A [2000] */ - {0x8ffea1, 0x00e9b3a6}, /* U+9CE6 [2000] */ - {0x8ffea2, 0x00e9b3b2}, /* U+9CF2 [2000] */ - {0x8ffea3, 0x00e9b48b}, /* U+9D0B [2000] */ - {0x8ffea4, 0x00e9b482}, /* U+9D02 [2000] */ + {0x8ffdf1, 0xe9b194}, /* U+9C54 [2000] */ + {0x8ffdf2, 0xe9b198}, /* U+9C58 [2000] */ + {0x8ffdf3, 0xe9b19b}, /* U+9C5B [2000] */ + {0x8ffdf4, 0xe9b19d}, /* U+9C5D [2000] */ + {0x8ffdf5, 0xe9b19f}, /* U+9C5F [2000] */ + {0x8ffdf6, 0xe9b1a9}, /* U+9C69 [2000] */ + {0x8ffdf7, 0xe9b1aa}, /* U+9C6A [2000] */ + {0x8ffdf8, 0xe9b1ab}, /* U+9C6B [2000] */ + {0x8ffdf9, 0xe9b1ad}, /* U+9C6D [2000] */ + {0x8ffdfa, 0xe9b1ae}, /* U+9C6E [2000] */ + {0x8ffdfb, 0xe9b1b0}, /* U+9C70 [2000] */ + {0x8ffdfc, 0xe9b1b2}, /* U+9C72 [2000] */ + {0x8ffdfd, 0xe9b1b5}, /* U+9C75 [2000] */ + {0x8ffdfe, 0xe9b1ba}, /* U+9C7A [2000] */ + {0x8ffea1, 0xe9b3a6}, /* U+9CE6 [2000] */ + {0x8ffea2, 0xe9b3b2}, /* U+9CF2 [2000] */ + {0x8ffea3, 0xe9b48b}, /* U+9D0B [2000] */ + {0x8ffea4, 0xe9b482}, /* U+9D02 [2000] */ {0x8ffea5, 0xf0a9bf8e}, /* U+29FCE [2000] [Unicode3.1] */ - {0x8ffea6, 0x00e9b491}, /* U+9D11 [2000] */ - {0x8ffea7, 0x00e9b497}, /* U+9D17 [2000] */ - {0x8ffea8, 0x00e9b498}, /* U+9D18 [2000] */ + {0x8ffea6, 0xe9b491}, /* U+9D11 [2000] */ + {0x8ffea7, 0xe9b497}, /* U+9D17 [2000] */ + {0x8ffea8, 0xe9b498}, /* U+9D18 [2000] */ {0x8ffea9, 0xf0aa80af}, /* U+2A02F [2000] [Unicode3.1] */ - {0x8ffeaa, 0x00e4b384}, /* U+4CC4 [2000] */ + {0x8ffeaa, 0xe4b384}, /* U+4CC4 [2000] */ {0x8ffeab, 0xf0aa809a}, /* U+2A01A [2000] [Unicode3.1] */ - {0x8ffeac, 0x00e9b4b2}, /* U+9D32 [2000] */ - {0x8ffead, 0x00e4b391}, /* U+4CD1 [2000] */ - {0x8ffeae, 0x00e9b582}, /* U+9D42 [2000] */ - {0x8ffeaf, 0x00e9b58a}, /* U+9D4A [2000] */ - {0x8ffeb0, 0x00e9b59f}, /* U+9D5F [2000] */ - {0x8ffeb1, 0x00e9b5a2}, /* U+9D62 [2000] */ + {0x8ffeac, 0xe9b4b2}, /* U+9D32 [2000] */ + {0x8ffead, 0xe4b391}, /* U+4CD1 [2000] */ + {0x8ffeae, 0xe9b582}, /* U+9D42 [2000] */ + {0x8ffeaf, 0xe9b58a}, /* U+9D4A [2000] */ + {0x8ffeb0, 0xe9b59f}, /* U+9D5F [2000] */ + {0x8ffeb1, 0xe9b5a2}, /* U+9D62 [2000] */ {0x8ffeb2, 0xf0aa83b9}, /* U+2A0F9 [2000] [Unicode3.1] */ - {0x8ffeb3, 0x00e9b5a9}, /* U+9D69 [2000] */ - {0x8ffeb4, 0x00e9b5ab}, /* U+9D6B [2000] */ + {0x8ffeb3, 0xe9b5a9}, /* U+9D69 [2000] */ + {0x8ffeb4, 0xe9b5ab}, /* U+9D6B [2000] */ {0x8ffeb5, 0xf0aa8282}, /* U+2A082 [2000] [Unicode3.1] */ - {0x8ffeb6, 0x00e9b5b3}, /* U+9D73 [2000] */ - {0x8ffeb7, 0x00e9b5b6}, /* U+9D76 [2000] */ - {0x8ffeb8, 0x00e9b5b7}, /* U+9D77 [2000] */ - {0x8ffeb9, 0x00e9b5be}, /* U+9D7E [2000] */ - {0x8ffeba, 0x00e9b684}, /* U+9D84 [2000] */ - {0x8ffebb, 0x00e9b68d}, /* U+9D8D [2000] */ - {0x8ffebc, 0x00e9b699}, /* U+9D99 [2000] */ - {0x8ffebd, 0x00e9b6a1}, /* U+9DA1 [2000] */ - {0x8ffebe, 0x00e9b6bf}, /* U+9DBF [2000] */ - {0x8ffebf, 0x00e9b6b5}, /* U+9DB5 [2000] */ - {0x8ffec0, 0x00e9b6b9}, /* U+9DB9 [2000] */ - {0x8ffec1, 0x00e9b6bd}, /* U+9DBD [2000] */ - {0x8ffec2, 0x00e9b783}, /* U+9DC3 [2000] */ - {0x8ffec3, 0x00e9b787}, /* U+9DC7 [2000] */ - {0x8ffec4, 0x00e9b789}, /* U+9DC9 [2000] */ - {0x8ffec5, 0x00e9b796}, /* U+9DD6 [2000] */ - {0x8ffec6, 0x00e9b79a}, /* U+9DDA [2000] */ - {0x8ffec7, 0x00e9b79f}, /* U+9DDF [2000] */ - {0x8ffec8, 0x00e9b7a0}, /* U+9DE0 [2000] */ - {0x8ffec9, 0x00e9b7a3}, /* U+9DE3 [2000] */ - {0x8ffeca, 0x00e9b7b4}, /* U+9DF4 [2000] */ - {0x8ffecb, 0x00e4b487}, /* U+4D07 [2000] */ - {0x8ffecc, 0x00e9b88a}, /* U+9E0A [2000] */ - {0x8ffecd, 0x00e9b882}, /* U+9E02 [2000] */ - {0x8ffece, 0x00e9b88d}, /* U+9E0D [2000] */ - {0x8ffecf, 0x00e9b899}, /* U+9E19 [2000] */ - {0x8ffed0, 0x00e9b89c}, /* U+9E1C [2000] */ - {0x8ffed1, 0x00e9b89d}, /* U+9E1D [2000] */ - {0x8ffed2, 0x00e9b9bb}, /* U+9E7B [2000] */ + {0x8ffeb6, 0xe9b5b3}, /* U+9D73 [2000] */ + {0x8ffeb7, 0xe9b5b6}, /* U+9D76 [2000] */ + {0x8ffeb8, 0xe9b5b7}, /* U+9D77 [2000] */ + {0x8ffeb9, 0xe9b5be}, /* U+9D7E [2000] */ + {0x8ffeba, 0xe9b684}, /* U+9D84 [2000] */ + {0x8ffebb, 0xe9b68d}, /* U+9D8D [2000] */ + {0x8ffebc, 0xe9b699}, /* U+9D99 [2000] */ + {0x8ffebd, 0xe9b6a1}, /* U+9DA1 [2000] */ + {0x8ffebe, 0xe9b6bf}, /* U+9DBF [2000] */ + {0x8ffebf, 0xe9b6b5}, /* U+9DB5 [2000] */ + {0x8ffec0, 0xe9b6b9}, /* U+9DB9 [2000] */ + {0x8ffec1, 0xe9b6bd}, /* U+9DBD [2000] */ + {0x8ffec2, 0xe9b783}, /* U+9DC3 [2000] */ + {0x8ffec3, 0xe9b787}, /* U+9DC7 [2000] */ + {0x8ffec4, 0xe9b789}, /* U+9DC9 [2000] */ + {0x8ffec5, 0xe9b796}, /* U+9DD6 [2000] */ + {0x8ffec6, 0xe9b79a}, /* U+9DDA [2000] */ + {0x8ffec7, 0xe9b79f}, /* U+9DDF [2000] */ + {0x8ffec8, 0xe9b7a0}, /* U+9DE0 [2000] */ + {0x8ffec9, 0xe9b7a3}, /* U+9DE3 [2000] */ + {0x8ffeca, 0xe9b7b4}, /* U+9DF4 [2000] */ + {0x8ffecb, 0xe4b487}, /* U+4D07 [2000] */ + {0x8ffecc, 0xe9b88a}, /* U+9E0A [2000] */ + {0x8ffecd, 0xe9b882}, /* U+9E02 [2000] */ + {0x8ffece, 0xe9b88d}, /* U+9E0D [2000] */ + {0x8ffecf, 0xe9b899}, /* U+9E19 [2000] */ + {0x8ffed0, 0xe9b89c}, /* U+9E1C [2000] */ + {0x8ffed1, 0xe9b89d}, /* U+9E1D [2000] */ + {0x8ffed2, 0xe9b9bb}, /* U+9E7B [2000] */ {0x8ffed3, 0xf0a28898}, /* U+22218 [2000] [Unicode3.1] */ - {0x8ffed4, 0x00e9ba80}, /* U+9E80 [2000] */ - {0x8ffed5, 0x00e9ba85}, /* U+9E85 [2000] */ - {0x8ffed6, 0x00e9ba9b}, /* U+9E9B [2000] */ - {0x8ffed7, 0x00e9baa8}, /* U+9EA8 [2000] */ + {0x8ffed4, 0xe9ba80}, /* U+9E80 [2000] */ + {0x8ffed5, 0xe9ba85}, /* U+9E85 [2000] */ + {0x8ffed6, 0xe9ba9b}, /* U+9E9B [2000] */ + {0x8ffed7, 0xe9baa8}, /* U+9EA8 [2000] */ {0x8ffed8, 0xf0aa8e8c}, /* U+2A38C [2000] [Unicode3.1] */ - {0x8ffed9, 0x00e9babd}, /* U+9EBD [2000] */ + {0x8ffed9, 0xe9babd}, /* U+9EBD [2000] */ {0x8ffeda, 0xf0aa90b7}, /* U+2A437 [2000] [Unicode3.1] */ - {0x8ffedb, 0x00e9bb9f}, /* U+9EDF [2000] */ - {0x8ffedc, 0x00e9bba7}, /* U+9EE7 [2000] */ - {0x8ffedd, 0x00e9bbae}, /* U+9EEE [2000] */ - {0x8ffede, 0x00e9bbbf}, /* U+9EFF [2000] */ - {0x8ffedf, 0x00e9bc82}, /* U+9F02 [2000] */ - {0x8ffee0, 0x00e4b5b7}, /* U+4D77 [2000] */ - {0x8ffee1, 0x00e9bc83}, /* U+9F03 [2000] */ - {0x8ffee2, 0x00e9bc97}, /* U+9F17 [2000] */ - {0x8ffee3, 0x00e9bc99}, /* U+9F19 [2000] */ - {0x8ffee4, 0x00e9bcaf}, /* U+9F2F [2000] */ - {0x8ffee5, 0x00e9bcb7}, /* U+9F37 [2000] */ - {0x8ffee6, 0x00e9bcba}, /* U+9F3A [2000] */ - {0x8ffee7, 0x00e9bcbd}, /* U+9F3D [2000] */ - {0x8ffee8, 0x00e9bd81}, /* U+9F41 [2000] */ - {0x8ffee9, 0x00e9bd85}, /* U+9F45 [2000] */ - {0x8ffeea, 0x00e9bd86}, /* U+9F46 [2000] */ - {0x8ffeeb, 0x00e9bd93}, /* U+9F53 [2000] */ - {0x8ffeec, 0x00e9bd95}, /* U+9F55 [2000] */ - {0x8ffeed, 0x00e9bd98}, /* U+9F58 [2000] */ + {0x8ffedb, 0xe9bb9f}, /* U+9EDF [2000] */ + {0x8ffedc, 0xe9bba7}, /* U+9EE7 [2000] */ + {0x8ffedd, 0xe9bbae}, /* U+9EEE [2000] */ + {0x8ffede, 0xe9bbbf}, /* U+9EFF [2000] */ + {0x8ffedf, 0xe9bc82}, /* U+9F02 [2000] */ + {0x8ffee0, 0xe4b5b7}, /* U+4D77 [2000] */ + {0x8ffee1, 0xe9bc83}, /* U+9F03 [2000] */ + {0x8ffee2, 0xe9bc97}, /* U+9F17 [2000] */ + {0x8ffee3, 0xe9bc99}, /* U+9F19 [2000] */ + {0x8ffee4, 0xe9bcaf}, /* U+9F2F [2000] */ + {0x8ffee5, 0xe9bcb7}, /* U+9F37 [2000] */ + {0x8ffee6, 0xe9bcba}, /* U+9F3A [2000] */ + {0x8ffee7, 0xe9bcbd}, /* U+9F3D [2000] */ + {0x8ffee8, 0xe9bd81}, /* U+9F41 [2000] */ + {0x8ffee9, 0xe9bd85}, /* U+9F45 [2000] */ + {0x8ffeea, 0xe9bd86}, /* U+9F46 [2000] */ + {0x8ffeeb, 0xe9bd93}, /* U+9F53 [2000] */ + {0x8ffeec, 0xe9bd95}, /* U+9F55 [2000] */ + {0x8ffeed, 0xe9bd98}, /* U+9F58 [2000] */ {0x8ffeee, 0xf0aa97b1}, /* U+2A5F1 [2000] [Unicode3.1] */ - {0x8ffeef, 0x00e9bd9d}, /* U+9F5D [2000] */ + {0x8ffeef, 0xe9bd9d}, /* U+9F5D [2000] */ {0x8ffef0, 0xf0aa9882}, /* U+2A602 [2000] [Unicode3.1] */ - {0x8ffef1, 0x00e9bda9}, /* U+9F69 [2000] */ + {0x8ffef1, 0xe9bda9}, /* U+9F69 [2000] */ {0x8ffef2, 0xf0aa989a}, /* U+2A61A [2000] [Unicode3.1] */ - {0x8ffef3, 0x00e9bdad}, /* U+9F6D [2000] */ - {0x8ffef4, 0x00e9bdb0}, /* U+9F70 [2000] */ - {0x8ffef5, 0x00e9bdb5}, /* U+9F75 [2000] */ + {0x8ffef3, 0xe9bdad}, /* U+9F6D [2000] */ + {0x8ffef4, 0xe9bdb0}, /* U+9F70 [2000] */ + {0x8ffef5, 0xe9bdb5}, /* U+9F75 [2000] */ {0x8ffef6, 0xf0aa9ab2} /* U+2A6B2 [2000] [Unicode3.1] */ }; diff --git a/src/backend/utils/mb/Unicode/euc_jis_2004_to_utf8_combined.map b/src/backend/utils/mb/Unicode/euc_jis_2004_to_utf8_combined.map index fb4b247772..2d8987b990 100644 --- a/src/backend/utils/mb/Unicode/euc_jis_2004_to_utf8_combined.map +++ b/src/backend/utils/mb/Unicode/euc_jis_2004_to_utf8_combined.map @@ -1,30 +1,29 @@ -/* - * This file was generated by UCS_to_EUC_JIS_2004.pl - */ -static const pg_local_to_utf_combined LUmapEUC_JIS_2004_combined[] = { - {0x00a4f7, 0x00e3818b, 0x00e3829a}, /* U+304B+309A [2000] */ - {0x00a4f8, 0x00e3818d, 0x00e3829a}, /* U+304D+309A [2000] */ - {0x00a4f9, 0x00e3818f, 0x00e3829a}, /* U+304F+309A [2000] */ - {0x00a4fa, 0x00e38191, 0x00e3829a}, /* U+3051+309A [2000] */ - {0x00a4fb, 0x00e38193, 0x00e3829a}, /* U+3053+309A [2000] */ - {0x00a5f7, 0x00e382ab, 0x00e3829a}, /* U+30AB+309A [2000] */ - {0x00a5f8, 0x00e382ad, 0x00e3829a}, /* U+30AD+309A [2000] */ - {0x00a5f9, 0x00e382af, 0x00e3829a}, /* U+30AF+309A [2000] */ - {0x00a5fa, 0x00e382b1, 0x00e3829a}, /* U+30B1+309A [2000] */ - {0x00a5fb, 0x00e382b3, 0x00e3829a}, /* U+30B3+309A [2000] */ - {0x00a5fc, 0x00e382bb, 0x00e3829a}, /* U+30BB+309A [2000] */ - {0x00a5fd, 0x00e38384, 0x00e3829a}, /* U+30C4+309A [2000] */ - {0x00a5fe, 0x00e38388, 0x00e3829a}, /* U+30C8+309A [2000] */ - {0x00a6f8, 0x00e387b7, 0x00e3829a}, /* U+31F7+309A [2000] */ - {0x00abc4, 0x0000c3a6, 0x0000cc80}, /* U+00E6+0300 [2000] */ - {0x00abc8, 0x0000c994, 0x0000cc80}, /* U+0254+0300 [2000] */ - {0x00abc9, 0x0000c994, 0x0000cc81}, /* U+0254+0301 [2000] */ - {0x00abca, 0x0000ca8c, 0x0000cc80}, /* U+028C+0300 [2000] */ - {0x00abcb, 0x0000ca8c, 0x0000cc81}, /* U+028C+0301 [2000] */ - {0x00abcc, 0x0000c999, 0x0000cc80}, /* U+0259+0300 [2000] */ - {0x00abcd, 0x0000c999, 0x0000cc81}, /* U+0259+0301 [2000] */ - {0x00abce, 0x0000c99a, 0x0000cc80}, /* U+025A+0300 [2000] */ - {0x00abcf, 0x0000c99a, 0x0000cc81}, /* U+025A+0301 [2000] */ - {0x00abe5, 0x0000cba9, 0x0000cba5}, /* U+02E9+02E5 [2000] */ - {0x00abe6, 0x0000cba5, 0x0000cba9} /* U+02E5+02E9 [2000] */ +/* src/backend/utils/mb/Unicode/euc_jis_2004_to_utf8_combined.map */ + +static const pg_local_to_utf_combined LUmapEUC_JIS_2004_combined[ 25 ] = { /* */ + {0xa4f7, 0x00e3818b, 0x00e3829a}, /* U+304B+309A [2000] */ + {0xa4f8, 0x00e3818d, 0x00e3829a}, /* U+304D+309A [2000] */ + {0xa4f9, 0x00e3818f, 0x00e3829a}, /* U+304F+309A [2000] */ + {0xa4fa, 0x00e38191, 0x00e3829a}, /* U+3051+309A [2000] */ + {0xa4fb, 0x00e38193, 0x00e3829a}, /* U+3053+309A [2000] */ + {0xa5f7, 0x00e382ab, 0x00e3829a}, /* U+30AB+309A [2000] */ + {0xa5f8, 0x00e382ad, 0x00e3829a}, /* U+30AD+309A [2000] */ + {0xa5f9, 0x00e382af, 0x00e3829a}, /* U+30AF+309A [2000] */ + {0xa5fa, 0x00e382b1, 0x00e3829a}, /* U+30B1+309A [2000] */ + {0xa5fb, 0x00e382b3, 0x00e3829a}, /* U+30B3+309A [2000] */ + {0xa5fc, 0x00e382bb, 0x00e3829a}, /* U+30BB+309A [2000] */ + {0xa5fd, 0x00e38384, 0x00e3829a}, /* U+30C4+309A [2000] */ + {0xa5fe, 0x00e38388, 0x00e3829a}, /* U+30C8+309A [2000] */ + {0xa6f8, 0x00e387b7, 0x00e3829a}, /* U+31F7+309A [2000] */ + {0xabc4, 0x0000c3a6, 0x0000cc80}, /* U+00E6+0300 [2000] */ + {0xabc8, 0x0000c994, 0x0000cc80}, /* U+0254+0300 [2000] */ + {0xabc9, 0x0000c994, 0x0000cc81}, /* U+0254+0301 [2000] */ + {0xabca, 0x0000ca8c, 0x0000cc80}, /* U+028C+0300 [2000] */ + {0xabcb, 0x0000ca8c, 0x0000cc81}, /* U+028C+0301 [2000] */ + {0xabcc, 0x0000c999, 0x0000cc80}, /* U+0259+0300 [2000] */ + {0xabcd, 0x0000c999, 0x0000cc81}, /* U+0259+0301 [2000] */ + {0xabce, 0x0000c99a, 0x0000cc80}, /* U+025A+0300 [2000] */ + {0xabcf, 0x0000c99a, 0x0000cc81}, /* U+025A+0301 [2000] */ + {0xabe5, 0x0000cba9, 0x0000cba5}, /* U+02E9+02E5 [2000] */ + {0xabe6, 0x0000cba5, 0x0000cba9} /* U+02E5+02E9 [2000] */ }; diff --git a/src/backend/utils/mb/Unicode/euc_jp_to_utf8.map b/src/backend/utils/mb/Unicode/euc_jp_to_utf8.map index db427cbb24..eb17f9829c 100644 --- a/src/backend/utils/mb/Unicode/euc_jp_to_utf8.map +++ b/src/backend/utils/mb/Unicode/euc_jp_to_utf8.map @@ -1,6 +1,6 @@ /* src/backend/utils/mb/Unicode/euc_jp_to_utf8.map */ -static const pg_local_to_utf LUmapEUC_JP[] = { +static const pg_local_to_utf LUmapEUC_JP[ 13197 ] = { {0x8ea1, 0xefbda1}, {0x8ea2, 0xefbda2}, {0x8ea3, 0xefbda3}, @@ -13197,5 +13197,5 @@ static const pg_local_to_utf LUmapEUC_JP[] = { {0x8ff4fb, 0xe9ab99}, {0x8ff4fc, 0xe9adb2}, {0x8ff4fd, 0xefa8ad}, - {0x8ff4fe, 0xe9bb91}, + {0x8ff4fe, 0xe9bb91} }; diff --git a/src/backend/utils/mb/Unicode/euc_kr_to_utf8.map b/src/backend/utils/mb/Unicode/euc_kr_to_utf8.map index e37152137d..701a7a476f 100644 --- a/src/backend/utils/mb/Unicode/euc_kr_to_utf8.map +++ b/src/backend/utils/mb/Unicode/euc_kr_to_utf8.map @@ -1,3 +1,5 @@ +/* src/backend/utils/mb/Unicode/euc_kr_to_utf8.map */ + static const pg_local_to_utf LUmapEUC_KR[ 8227 ] = { {0xa1a1, 0xe38080}, {0xa1a2, 0xe38081}, diff --git a/src/backend/utils/mb/Unicode/johab_to_utf8.map b/src/backend/utils/mb/Unicode/johab_to_utf8.map index 8110f6e853..e31d24184c 100644 --- a/src/backend/utils/mb/Unicode/johab_to_utf8.map +++ b/src/backend/utils/mb/Unicode/johab_to_utf8.map @@ -1,3 +1,5 @@ +/* src/backend/utils/mb/Unicode/johab_to_utf8.map */ + static const pg_local_to_utf LUmapJOHAB[ 17049 ] = { {0x8444, 0xe384b3}, {0x8446, 0xe384b5}, diff --git a/src/backend/utils/mb/Unicode/shift_jis_2004_to_utf8.map b/src/backend/utils/mb/Unicode/shift_jis_2004_to_utf8.map index f4e03e90d8..958dde7b83 100644 --- a/src/backend/utils/mb/Unicode/shift_jis_2004_to_utf8.map +++ b/src/backend/utils/mb/Unicode/shift_jis_2004_to_utf8.map @@ -1,11404 +1,11275 @@ -/* - * This file was generated by UCS_to_SHIFTJIS_2004.pl - */ -static const pg_local_to_utf LUmapSHIFT_JIS_2004[] = { - {0x0000, 0x00000000}, /* U+0000 */ - {0x0001, 0x00000001}, /* U+0001 */ - {0x0002, 0x00000002}, /* U+0002 */ - {0x0003, 0x00000003}, /* U+0003 */ - {0x0004, 0x00000004}, /* U+0004 */ - {0x0005, 0x00000005}, /* U+0005 */ - {0x0006, 0x00000006}, /* U+0006 */ - {0x0007, 0x00000007}, /* U+0007 */ - {0x0008, 0x00000008}, /* U+0008 */ - {0x0009, 0x00000009}, /* U+0009 */ - {0x000a, 0x0000000a}, /* U+000A */ - {0x000b, 0x0000000b}, /* U+000B */ - {0x000c, 0x0000000c}, /* U+000C */ - {0x000d, 0x0000000d}, /* U+000D */ - {0x000e, 0x0000000e}, /* U+000E */ - {0x000f, 0x0000000f}, /* U+000F */ - {0x0010, 0x00000010}, /* U+0010 */ - {0x0011, 0x00000011}, /* U+0011 */ - {0x0012, 0x00000012}, /* U+0012 */ - {0x0013, 0x00000013}, /* U+0013 */ - {0x0014, 0x00000014}, /* U+0014 */ - {0x0015, 0x00000015}, /* U+0015 */ - {0x0016, 0x00000016}, /* U+0016 */ - {0x0017, 0x00000017}, /* U+0017 */ - {0x0018, 0x00000018}, /* U+0018 */ - {0x0019, 0x00000019}, /* U+0019 */ - {0x001a, 0x0000001a}, /* U+001A */ - {0x001b, 0x0000001b}, /* U+001B */ - {0x001c, 0x0000001c}, /* U+001C */ - {0x001d, 0x0000001d}, /* U+001D */ - {0x001e, 0x0000001e}, /* U+001E */ - {0x001f, 0x0000001f}, /* U+001F */ - {0x0020, 0x00000020}, /* U+0020 SPACE */ - {0x0021, 0x00000021}, /* U+0021 EXCLAMATION MARK */ - {0x0022, 0x00000022}, /* U+0022 QUOTATION MARK */ - {0x0023, 0x00000023}, /* U+0023 NUMBER SIGN */ - {0x0024, 0x00000024}, /* U+0024 DOLLAR SIGN */ - {0x0025, 0x00000025}, /* U+0025 PERCENT SIGN */ - {0x0026, 0x00000026}, /* U+0026 AMPERSAND */ - {0x0027, 0x00000027}, /* U+0027 APOSTROPHE */ - {0x0028, 0x00000028}, /* U+0028 LEFT PARENTHESIS */ - {0x0029, 0x00000029}, /* U+0029 RIGHT PARENTHESIS */ - {0x002a, 0x0000002a}, /* U+002A ASTERISK */ - {0x002b, 0x0000002b}, /* U+002B PLUS SIGN */ - {0x002c, 0x0000002c}, /* U+002C COMMA */ - {0x002d, 0x0000002d}, /* U+002D HYPHEN-MINUS */ - {0x002e, 0x0000002e}, /* U+002E FULL STOP */ - {0x002f, 0x0000002f}, /* U+002F SOLIDUS */ - {0x0030, 0x00000030}, /* U+0030 DIGIT ZERO */ - {0x0031, 0x00000031}, /* U+0031 DIGIT ONE */ - {0x0032, 0x00000032}, /* U+0032 DIGIT TWO */ - {0x0033, 0x00000033}, /* U+0033 DIGIT THREE */ - {0x0034, 0x00000034}, /* U+0034 DIGIT FOUR */ - {0x0035, 0x00000035}, /* U+0035 DIGIT FIVE */ - {0x0036, 0x00000036}, /* U+0036 DIGIT SIX */ - {0x0037, 0x00000037}, /* U+0037 DIGIT SEVEN */ - {0x0038, 0x00000038}, /* U+0038 DIGIT EIGHT */ - {0x0039, 0x00000039}, /* U+0039 DIGIT NINE */ - {0x003a, 0x0000003a}, /* U+003A COLON */ - {0x003b, 0x0000003b}, /* U+003B SEMICOLON */ - {0x003c, 0x0000003c}, /* U+003C LESS-THAN SIGN */ - {0x003d, 0x0000003d}, /* U+003D EQUALS SIGN */ - {0x003e, 0x0000003e}, /* U+003E GREATER-THAN SIGN */ - {0x003f, 0x0000003f}, /* U+003F QUESTION MARK */ - {0x0040, 0x00000040}, /* U+0040 COMMERCIAL AT */ - {0x0041, 0x00000041}, /* U+0041 LATIN CAPITAL LETTER A */ - {0x0042, 0x00000042}, /* U+0042 LATIN CAPITAL LETTER B */ - {0x0043, 0x00000043}, /* U+0043 LATIN CAPITAL LETTER C */ - {0x0044, 0x00000044}, /* U+0044 LATIN CAPITAL LETTER D */ - {0x0045, 0x00000045}, /* U+0045 LATIN CAPITAL LETTER E */ - {0x0046, 0x00000046}, /* U+0046 LATIN CAPITAL LETTER F */ - {0x0047, 0x00000047}, /* U+0047 LATIN CAPITAL LETTER G */ - {0x0048, 0x00000048}, /* U+0048 LATIN CAPITAL LETTER H */ - {0x0049, 0x00000049}, /* U+0049 LATIN CAPITAL LETTER I */ - {0x004a, 0x0000004a}, /* U+004A LATIN CAPITAL LETTER J */ - {0x004b, 0x0000004b}, /* U+004B LATIN CAPITAL LETTER K */ - {0x004c, 0x0000004c}, /* U+004C LATIN CAPITAL LETTER L */ - {0x004d, 0x0000004d}, /* U+004D LATIN CAPITAL LETTER M */ - {0x004e, 0x0000004e}, /* U+004E LATIN CAPITAL LETTER N */ - {0x004f, 0x0000004f}, /* U+004F LATIN CAPITAL LETTER O */ - {0x0050, 0x00000050}, /* U+0050 LATIN CAPITAL LETTER P */ - {0x0051, 0x00000051}, /* U+0051 LATIN CAPITAL LETTER Q */ - {0x0052, 0x00000052}, /* U+0052 LATIN CAPITAL LETTER R */ - {0x0053, 0x00000053}, /* U+0053 LATIN CAPITAL LETTER S */ - {0x0054, 0x00000054}, /* U+0054 LATIN CAPITAL LETTER T */ - {0x0055, 0x00000055}, /* U+0055 LATIN CAPITAL LETTER U */ - {0x0056, 0x00000056}, /* U+0056 LATIN CAPITAL LETTER V */ - {0x0057, 0x00000057}, /* U+0057 LATIN CAPITAL LETTER W */ - {0x0058, 0x00000058}, /* U+0058 LATIN CAPITAL LETTER X */ - {0x0059, 0x00000059}, /* U+0059 LATIN CAPITAL LETTER Y */ - {0x005a, 0x0000005a}, /* U+005A LATIN CAPITAL LETTER Z */ - {0x005b, 0x0000005b}, /* U+005B LEFT SQUARE BRACKET */ - {0x005c, 0x0000c2a5}, /* U+00A5 YEN SIGN */ - {0x005d, 0x0000005d}, /* U+005D RIGHT SQUARE BRACKET */ - {0x005e, 0x0000005e}, /* U+005E CIRCUMFLEX ACCENT */ - {0x005f, 0x0000005f}, /* U+005F LOW LINE */ - {0x0060, 0x00000060}, /* U+0060 GRAVE ACCENT */ - {0x0061, 0x00000061}, /* U+0061 LATIN SMALL LETTER A */ - {0x0062, 0x00000062}, /* U+0062 LATIN SMALL LETTER B */ - {0x0063, 0x00000063}, /* U+0063 LATIN SMALL LETTER C */ - {0x0064, 0x00000064}, /* U+0064 LATIN SMALL LETTER D */ - {0x0065, 0x00000065}, /* U+0065 LATIN SMALL LETTER E */ - {0x0066, 0x00000066}, /* U+0066 LATIN SMALL LETTER F */ - {0x0067, 0x00000067}, /* U+0067 LATIN SMALL LETTER G */ - {0x0068, 0x00000068}, /* U+0068 LATIN SMALL LETTER H */ - {0x0069, 0x00000069}, /* U+0069 LATIN SMALL LETTER I */ - {0x006a, 0x0000006a}, /* U+006A LATIN SMALL LETTER J */ - {0x006b, 0x0000006b}, /* U+006B LATIN SMALL LETTER K */ - {0x006c, 0x0000006c}, /* U+006C LATIN SMALL LETTER L */ - {0x006d, 0x0000006d}, /* U+006D LATIN SMALL LETTER M */ - {0x006e, 0x0000006e}, /* U+006E LATIN SMALL LETTER N */ - {0x006f, 0x0000006f}, /* U+006F LATIN SMALL LETTER O */ - {0x0070, 0x00000070}, /* U+0070 LATIN SMALL LETTER P */ - {0x0071, 0x00000071}, /* U+0071 LATIN SMALL LETTER Q */ - {0x0072, 0x00000072}, /* U+0072 LATIN SMALL LETTER R */ - {0x0073, 0x00000073}, /* U+0073 LATIN SMALL LETTER S */ - {0x0074, 0x00000074}, /* U+0074 LATIN SMALL LETTER T */ - {0x0075, 0x00000075}, /* U+0075 LATIN SMALL LETTER U */ - {0x0076, 0x00000076}, /* U+0076 LATIN SMALL LETTER V */ - {0x0077, 0x00000077}, /* U+0077 LATIN SMALL LETTER W */ - {0x0078, 0x00000078}, /* U+0078 LATIN SMALL LETTER X */ - {0x0079, 0x00000079}, /* U+0079 LATIN SMALL LETTER Y */ - {0x007a, 0x0000007a}, /* U+007A LATIN SMALL LETTER Z */ - {0x007b, 0x0000007b}, /* U+007B LEFT CURLY BRACKET */ - {0x007c, 0x0000007c}, /* U+007C VERTICAL LINE */ - {0x007d, 0x0000007d}, /* U+007D RIGHT CURLY BRACKET */ - {0x007e, 0x00e280be}, /* U+203E OVERLINE */ - {0x007f, 0x0000007f}, /* U+007F */ - {0x00a1, 0x00efbda1}, /* U+FF61 HALFWIDTH IDEOGRAPHIC FULL STOP */ - {0x00a2, 0x00efbda2}, /* U+FF62 HALFWIDTH LEFT CORNER BRACKET */ - {0x00a3, 0x00efbda3}, /* U+FF63 HALFWIDTH RIGHT CORNER BRACKET */ - {0x00a4, 0x00efbda4}, /* U+FF64 HALFWIDTH IDEOGRAPHIC COMMA */ - {0x00a5, 0x00efbda5}, /* U+FF65 HALFWIDTH KATAKANA MIDDLE DOT */ - {0x00a6, 0x00efbda6}, /* U+FF66 HALFWIDTH KATAKANA LETTER WO */ - {0x00a7, 0x00efbda7}, /* U+FF67 HALFWIDTH KATAKANA LETTER SMALL A */ - {0x00a8, 0x00efbda8}, /* U+FF68 HALFWIDTH KATAKANA LETTER SMALL I */ - {0x00a9, 0x00efbda9}, /* U+FF69 HALFWIDTH KATAKANA LETTER SMALL U */ - {0x00aa, 0x00efbdaa}, /* U+FF6A HALFWIDTH KATAKANA LETTER SMALL E */ - {0x00ab, 0x00efbdab}, /* U+FF6B HALFWIDTH KATAKANA LETTER SMALL O */ - {0x00ac, 0x00efbdac}, /* U+FF6C HALFWIDTH KATAKANA LETTER SMALL YA */ - {0x00ad, 0x00efbdad}, /* U+FF6D HALFWIDTH KATAKANA LETTER SMALL YU */ - {0x00ae, 0x00efbdae}, /* U+FF6E HALFWIDTH KATAKANA LETTER SMALL YO */ - {0x00af, 0x00efbdaf}, /* U+FF6F HALFWIDTH KATAKANA LETTER SMALL TU */ - {0x00b0, 0x00efbdb0}, /* U+FF70 HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK */ - {0x00b1, 0x00efbdb1}, /* U+FF71 HALFWIDTH KATAKANA LETTER A */ - {0x00b2, 0x00efbdb2}, /* U+FF72 HALFWIDTH KATAKANA LETTER I */ - {0x00b3, 0x00efbdb3}, /* U+FF73 HALFWIDTH KATAKANA LETTER U */ - {0x00b4, 0x00efbdb4}, /* U+FF74 HALFWIDTH KATAKANA LETTER E */ - {0x00b5, 0x00efbdb5}, /* U+FF75 HALFWIDTH KATAKANA LETTER O */ - {0x00b6, 0x00efbdb6}, /* U+FF76 HALFWIDTH KATAKANA LETTER KA */ - {0x00b7, 0x00efbdb7}, /* U+FF77 HALFWIDTH KATAKANA LETTER KI */ - {0x00b8, 0x00efbdb8}, /* U+FF78 HALFWIDTH KATAKANA LETTER KU */ - {0x00b9, 0x00efbdb9}, /* U+FF79 HALFWIDTH KATAKANA LETTER KE */ - {0x00ba, 0x00efbdba}, /* U+FF7A HALFWIDTH KATAKANA LETTER KO */ - {0x00bb, 0x00efbdbb}, /* U+FF7B HALFWIDTH KATAKANA LETTER SA */ - {0x00bc, 0x00efbdbc}, /* U+FF7C HALFWIDTH KATAKANA LETTER SI */ - {0x00bd, 0x00efbdbd}, /* U+FF7D HALFWIDTH KATAKANA LETTER SU */ - {0x00be, 0x00efbdbe}, /* U+FF7E HALFWIDTH KATAKANA LETTER SE */ - {0x00bf, 0x00efbdbf}, /* U+FF7F HALFWIDTH KATAKANA LETTER SO */ - {0x00c0, 0x00efbe80}, /* U+FF80 HALFWIDTH KATAKANA LETTER TA */ - {0x00c1, 0x00efbe81}, /* U+FF81 HALFWIDTH KATAKANA LETTER TI */ - {0x00c2, 0x00efbe82}, /* U+FF82 HALFWIDTH KATAKANA LETTER TU */ - {0x00c3, 0x00efbe83}, /* U+FF83 HALFWIDTH KATAKANA LETTER TE */ - {0x00c4, 0x00efbe84}, /* U+FF84 HALFWIDTH KATAKANA LETTER TO */ - {0x00c5, 0x00efbe85}, /* U+FF85 HALFWIDTH KATAKANA LETTER NA */ - {0x00c6, 0x00efbe86}, /* U+FF86 HALFWIDTH KATAKANA LETTER NI */ - {0x00c7, 0x00efbe87}, /* U+FF87 HALFWIDTH KATAKANA LETTER NU */ - {0x00c8, 0x00efbe88}, /* U+FF88 HALFWIDTH KATAKANA LETTER NE */ - {0x00c9, 0x00efbe89}, /* U+FF89 HALFWIDTH KATAKANA LETTER NO */ - {0x00ca, 0x00efbe8a}, /* U+FF8A HALFWIDTH KATAKANA LETTER HA */ - {0x00cb, 0x00efbe8b}, /* U+FF8B HALFWIDTH KATAKANA LETTER HI */ - {0x00cc, 0x00efbe8c}, /* U+FF8C HALFWIDTH KATAKANA LETTER HU */ - {0x00cd, 0x00efbe8d}, /* U+FF8D HALFWIDTH KATAKANA LETTER HE */ - {0x00ce, 0x00efbe8e}, /* U+FF8E HALFWIDTH KATAKANA LETTER HO */ - {0x00cf, 0x00efbe8f}, /* U+FF8F HALFWIDTH KATAKANA LETTER MA */ - {0x00d0, 0x00efbe90}, /* U+FF90 HALFWIDTH KATAKANA LETTER MI */ - {0x00d1, 0x00efbe91}, /* U+FF91 HALFWIDTH KATAKANA LETTER MU */ - {0x00d2, 0x00efbe92}, /* U+FF92 HALFWIDTH KATAKANA LETTER ME */ - {0x00d3, 0x00efbe93}, /* U+FF93 HALFWIDTH KATAKANA LETTER MO */ - {0x00d4, 0x00efbe94}, /* U+FF94 HALFWIDTH KATAKANA LETTER YA */ - {0x00d5, 0x00efbe95}, /* U+FF95 HALFWIDTH KATAKANA LETTER YU */ - {0x00d6, 0x00efbe96}, /* U+FF96 HALFWIDTH KATAKANA LETTER YO */ - {0x00d7, 0x00efbe97}, /* U+FF97 HALFWIDTH KATAKANA LETTER RA */ - {0x00d8, 0x00efbe98}, /* U+FF98 HALFWIDTH KATAKANA LETTER RI */ - {0x00d9, 0x00efbe99}, /* U+FF99 HALFWIDTH KATAKANA LETTER RU */ - {0x00da, 0x00efbe9a}, /* U+FF9A HALFWIDTH KATAKANA LETTER RE */ - {0x00db, 0x00efbe9b}, /* U+FF9B HALFWIDTH KATAKANA LETTER RO */ - {0x00dc, 0x00efbe9c}, /* U+FF9C HALFWIDTH KATAKANA LETTER WA */ - {0x00dd, 0x00efbe9d}, /* U+FF9D HALFWIDTH KATAKANA LETTER N */ - {0x00de, 0x00efbe9e}, /* U+FF9E HALFWIDTH KATAKANA VOICED SOUND MARK */ - {0x00df, 0x00efbe9f}, /* U+FF9F HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK */ - {0x8140, 0x00e38080}, /* U+3000 IDEOGRAPHIC SPACE */ - {0x8141, 0x00e38081}, /* U+3001 IDEOGRAPHIC COMMA */ - {0x8142, 0x00e38082}, /* U+3002 IDEOGRAPHIC FULL STOP */ - {0x8143, 0x00efbc8c}, /* U+FF0C FULLWIDTH COMMA */ - {0x8144, 0x00efbc8e}, /* U+FF0E FULLWIDTH FULL STOP */ - {0x8145, 0x00e383bb}, /* U+30FB KATAKANA MIDDLE DOT */ - {0x8146, 0x00efbc9a}, /* U+FF1A FULLWIDTH COLON */ - {0x8147, 0x00efbc9b}, /* U+FF1B FULLWIDTH SEMICOLON */ - {0x8148, 0x00efbc9f}, /* U+FF1F FULLWIDTH QUESTION MARK */ - {0x8149, 0x00efbc81}, /* U+FF01 FULLWIDTH EXCLAMATION MARK */ - {0x814a, 0x00e3829b}, /* U+309B KATAKANA-HIRAGANA VOICED SOUND MARK */ - {0x814b, 0x00e3829c}, /* U+309C KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ - {0x814c, 0x0000c2b4}, /* U+00B4 ACUTE ACCENT */ - {0x814d, 0x00efbd80}, /* U+FF40 FULLWIDTH GRAVE ACCENT */ - {0x814e, 0x0000c2a8}, /* U+00A8 DIAERESIS */ - {0x814f, 0x00efbcbe}, /* U+FF3E FULLWIDTH CIRCUMFLEX ACCENT */ - {0x8150, 0x00efbfa3}, /* U+FFE3 FULLWIDTH MACRON */ - {0x8151, 0x00efbcbf}, /* U+FF3F FULLWIDTH LOW LINE */ - {0x8152, 0x00e383bd}, /* U+30FD KATAKANA ITERATION MARK */ - {0x8153, 0x00e383be}, /* U+30FE KATAKANA VOICED ITERATION MARK */ - {0x8154, 0x00e3829d}, /* U+309D HIRAGANA ITERATION MARK */ - {0x8155, 0x00e3829e}, /* U+309E HIRAGANA VOICED ITERATION MARK */ - {0x8156, 0x00e38083}, /* U+3003 DITTO MARK */ - {0x8157, 0x00e4bb9d}, /* U+4EDD */ - {0x8158, 0x00e38085}, /* U+3005 IDEOGRAPHIC ITERATION MARK */ - {0x8159, 0x00e38086}, /* U+3006 IDEOGRAPHIC CLOSING MARK */ - {0x815a, 0x00e38087}, /* U+3007 IDEOGRAPHIC NUMBER ZERO */ - {0x815b, 0x00e383bc}, /* U+30FC KATAKANA-HIRAGANA PROLONGED SOUND MARK */ - {0x815c, 0x00e28094}, /* U+2014 EM DASH Windows: U+2015 */ - {0x815d, 0x00e28090}, /* U+2010 HYPHEN */ - {0x815e, 0x00efbc8f}, /* U+FF0F FULLWIDTH SOLIDUS */ - {0x815f, 0x0000005c}, /* U+005C REVERSE SOLIDUS Fullwidth: U+FF3C */ - {0x8160, 0x00e3809c}, /* U+301C WAVE DASH Windows: U+FF5E */ - {0x8161, 0x00e28096}, /* U+2016 DOUBLE VERTICAL LINE Windows: U+2225 */ - {0x8162, 0x00efbd9c}, /* U+FF5C FULLWIDTH VERTICAL LINE */ - {0x8163, 0x00e280a6}, /* U+2026 HORIZONTAL ELLIPSIS */ - {0x8164, 0x00e280a5}, /* U+2025 TWO DOT LEADER */ - {0x8165, 0x00e28098}, /* U+2018 LEFT SINGLE QUOTATION MARK */ - {0x8166, 0x00e28099}, /* U+2019 RIGHT SINGLE QUOTATION MARK */ - {0x8167, 0x00e2809c}, /* U+201C LEFT DOUBLE QUOTATION MARK */ - {0x8168, 0x00e2809d}, /* U+201D RIGHT DOUBLE QUOTATION MARK */ - {0x8169, 0x00efbc88}, /* U+FF08 FULLWIDTH LEFT PARENTHESIS */ - {0x816a, 0x00efbc89}, /* U+FF09 FULLWIDTH RIGHT PARENTHESIS */ - {0x816b, 0x00e38094}, /* U+3014 LEFT TORTOISE SHELL BRACKET */ - {0x816c, 0x00e38095}, /* U+3015 RIGHT TORTOISE SHELL BRACKET */ - {0x816d, 0x00efbcbb}, /* U+FF3B FULLWIDTH LEFT SQUARE BRACKET */ - {0x816e, 0x00efbcbd}, /* U+FF3D FULLWIDTH RIGHT SQUARE BRACKET */ - {0x816f, 0x00efbd9b}, /* U+FF5B FULLWIDTH LEFT CURLY BRACKET */ - {0x8170, 0x00efbd9d}, /* U+FF5D FULLWIDTH RIGHT CURLY BRACKET */ - {0x8171, 0x00e38088}, /* U+3008 LEFT ANGLE BRACKET */ - {0x8172, 0x00e38089}, /* U+3009 RIGHT ANGLE BRACKET */ - {0x8173, 0x00e3808a}, /* U+300A LEFT DOUBLE ANGLE BRACKET */ - {0x8174, 0x00e3808b}, /* U+300B RIGHT DOUBLE ANGLE BRACKET */ - {0x8175, 0x00e3808c}, /* U+300C LEFT CORNER BRACKET */ - {0x8176, 0x00e3808d}, /* U+300D RIGHT CORNER BRACKET */ - {0x8177, 0x00e3808e}, /* U+300E LEFT WHITE CORNER BRACKET */ - {0x8178, 0x00e3808f}, /* U+300F RIGHT WHITE CORNER BRACKET */ - {0x8179, 0x00e38090}, /* U+3010 LEFT BLACK LENTICULAR BRACKET */ - {0x817a, 0x00e38091}, /* U+3011 RIGHT BLACK LENTICULAR BRACKET */ - {0x817b, 0x00efbc8b}, /* U+FF0B FULLWIDTH PLUS SIGN */ - {0x817c, 0x00e28892}, /* U+2212 MINUS SIGN Windows: U+FF0D */ - {0x817d, 0x0000c2b1}, /* U+00B1 PLUS-MINUS SIGN */ - {0x817e, 0x0000c397}, /* U+00D7 MULTIPLICATION SIGN */ - {0x8180, 0x0000c3b7}, /* U+00F7 DIVISION SIGN */ - {0x8181, 0x00efbc9d}, /* U+FF1D FULLWIDTH EQUALS SIGN */ - {0x8182, 0x00e289a0}, /* U+2260 NOT EQUAL TO */ - {0x8183, 0x00efbc9c}, /* U+FF1C FULLWIDTH LESS-THAN SIGN */ - {0x8184, 0x00efbc9e}, /* U+FF1E FULLWIDTH GREATER-THAN SIGN */ - {0x8185, 0x00e289a6}, /* U+2266 LESS-THAN OVER EQUAL TO */ - {0x8186, 0x00e289a7}, /* U+2267 GREATER-THAN OVER EQUAL TO */ - {0x8187, 0x00e2889e}, /* U+221E INFINITY */ - {0x8188, 0x00e288b4}, /* U+2234 THEREFORE */ - {0x8189, 0x00e29982}, /* U+2642 MALE SIGN */ - {0x818a, 0x00e29980}, /* U+2640 FEMALE SIGN */ - {0x818b, 0x0000c2b0}, /* U+00B0 DEGREE SIGN */ - {0x818c, 0x00e280b2}, /* U+2032 PRIME */ - {0x818d, 0x00e280b3}, /* U+2033 DOUBLE PRIME */ - {0x818e, 0x00e28483}, /* U+2103 DEGREE CELSIUS */ - {0x818f, 0x00efbfa5}, /* U+FFE5 FULLWIDTH YEN SIGN */ - {0x8190, 0x00efbc84}, /* U+FF04 FULLWIDTH DOLLAR SIGN */ - {0x8191, 0x0000c2a2}, /* U+00A2 CENT SIGN Windows: U+FFE0 */ - {0x8192, 0x0000c2a3}, /* U+00A3 POUND SIGN Windows: U+FFE1 */ - {0x8193, 0x00efbc85}, /* U+FF05 FULLWIDTH PERCENT SIGN */ - {0x8194, 0x00efbc83}, /* U+FF03 FULLWIDTH NUMBER SIGN */ - {0x8195, 0x00efbc86}, /* U+FF06 FULLWIDTH AMPERSAND */ - {0x8196, 0x00efbc8a}, /* U+FF0A FULLWIDTH ASTERISK */ - {0x8197, 0x00efbca0}, /* U+FF20 FULLWIDTH COMMERCIAL AT */ - {0x8198, 0x0000c2a7}, /* U+00A7 SECTION SIGN */ - {0x8199, 0x00e29886}, /* U+2606 WHITE STAR */ - {0x819a, 0x00e29885}, /* U+2605 BLACK STAR */ - {0x819b, 0x00e2978b}, /* U+25CB WHITE CIRCLE */ - {0x819c, 0x00e2978f}, /* U+25CF BLACK CIRCLE */ - {0x819d, 0x00e2978e}, /* U+25CE BULLSEYE */ - {0x819e, 0x00e29787}, /* U+25C7 WHITE DIAMOND */ - {0x819f, 0x00e29786}, /* U+25C6 BLACK DIAMOND */ - {0x81a0, 0x00e296a1}, /* U+25A1 WHITE SQUARE */ - {0x81a1, 0x00e296a0}, /* U+25A0 BLACK SQUARE */ - {0x81a2, 0x00e296b3}, /* U+25B3 WHITE UP-POINTING TRIANGLE */ - {0x81a3, 0x00e296b2}, /* U+25B2 BLACK UP-POINTING TRIANGLE */ - {0x81a4, 0x00e296bd}, /* U+25BD WHITE DOWN-POINTING TRIANGLE */ - {0x81a5, 0x00e296bc}, /* U+25BC BLACK DOWN-POINTING TRIANGLE */ - {0x81a6, 0x00e280bb}, /* U+203B REFERENCE MARK */ - {0x81a7, 0x00e38092}, /* U+3012 POSTAL MARK */ - {0x81a8, 0x00e28692}, /* U+2192 RIGHTWARDS ARROW */ - {0x81a9, 0x00e28690}, /* U+2190 LEFTWARDS ARROW */ - {0x81aa, 0x00e28691}, /* U+2191 UPWARDS ARROW */ - {0x81ab, 0x00e28693}, /* U+2193 DOWNWARDS ARROW */ - {0x81ac, 0x00e38093}, /* U+3013 GETA MARK */ - {0x81ad, 0x00efbc87}, /* U+FF07 FULLWIDTH APOSTROPHE [2000] */ - {0x81ae, 0x00efbc82}, /* U+FF02 FULLWIDTH QUOTATION MARK [2000] */ - {0x81af, 0x00efbc8d}, /* U+FF0D FULLWIDTH HYPHEN-MINUS [2000] */ - {0x81b0, 0x0000007e}, /* U+007E TILDE [2000] Fullwidth: U+FF5E */ - {0x81b1, 0x00e380b3}, /* U+3033 VERTICAL KANA REPEAT MARK UPPER HALF [2000] */ - {0x81b2, 0x00e380b4}, /* U+3034 VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF [2000] */ - {0x81b3, 0x00e380b5}, /* U+3035 VERTICAL KANA REPEAT MARK LOWER HALF [2000] */ - {0x81b4, 0x00e380bb}, /* U+303B VERTICAL IDEOGRAPHIC ITERATION MARK [2000] [Unicode3.2] */ - {0x81b5, 0x00e380bc}, /* U+303C MASU MARK [2000] [Unicode3.2] */ - {0x81b6, 0x00e383bf}, /* U+30FF KATAKANA DIGRAPH KOTO [2000] [Unicode3.2] */ - {0x81b7, 0x00e3829f}, /* U+309F HIRAGANA DIGRAPH YORI [2000] [Unicode3.2] */ - {0x81b8, 0x00e28888}, /* U+2208 ELEMENT OF [1983] */ - {0x81b9, 0x00e2888b}, /* U+220B CONTAINS AS MEMBER [1983] */ - {0x81ba, 0x00e28a86}, /* U+2286 SUBSET OF OR EQUAL TO [1983] */ - {0x81bb, 0x00e28a87}, /* U+2287 SUPERSET OF OR EQUAL TO [1983] */ - {0x81bc, 0x00e28a82}, /* U+2282 SUBSET OF [1983] */ - {0x81bd, 0x00e28a83}, /* U+2283 SUPERSET OF [1983] */ - {0x81be, 0x00e288aa}, /* U+222A UNION [1983] */ - {0x81bf, 0x00e288a9}, /* U+2229 INTERSECTION [1983] */ - {0x81c0, 0x00e28a84}, /* U+2284 NOT A SUBSET OF [2000] */ - {0x81c1, 0x00e28a85}, /* U+2285 NOT A SUPERSET OF [2000] */ - {0x81c2, 0x00e28a8a}, /* U+228A SUBSET OF WITH NOT EQUAL TO [2000] */ - {0x81c3, 0x00e28a8b}, /* U+228B SUPERSET OF WITH NOT EQUAL TO [2000] */ - {0x81c4, 0x00e28889}, /* U+2209 NOT AN ELEMENT OF [2000] */ - {0x81c5, 0x00e28885}, /* U+2205 EMPTY SET [2000] */ - {0x81c6, 0x00e28c85}, /* U+2305 PROJECTIVE [2000] */ - {0x81c7, 0x00e28c86}, /* U+2306 PERSPECTIVE [2000] */ - {0x81c8, 0x00e288a7}, /* U+2227 LOGICAL AND [1983] */ - {0x81c9, 0x00e288a8}, /* U+2228 LOGICAL OR [1983] */ - {0x81ca, 0x0000c2ac}, /* U+00AC NOT SIGN [1983] Windows: U+FFE2 */ - {0x81cb, 0x00e28792}, /* U+21D2 RIGHTWARDS DOUBLE ARROW [1983] */ - {0x81cc, 0x00e28794}, /* U+21D4 LEFT RIGHT DOUBLE ARROW [1983] */ - {0x81cd, 0x00e28880}, /* U+2200 FOR ALL [1983] */ - {0x81ce, 0x00e28883}, /* U+2203 THERE EXISTS [1983] */ - {0x81cf, 0x00e28a95}, /* U+2295 CIRCLED PLUS [2000] */ - {0x81d0, 0x00e28a96}, /* U+2296 CIRCLED MINUS [2000] */ - {0x81d1, 0x00e28a97}, /* U+2297 CIRCLED TIMES [2000] */ - {0x81d2, 0x00e288a5}, /* U+2225 PARALLEL TO [2000] */ - {0x81d3, 0x00e288a6}, /* U+2226 NOT PARALLEL TO [2000] */ - {0x81d4, 0x00efbd9f}, /* U+FF5F FULLWIDTH LEFT WHITE PARENTHESIS [2000] [Unicode3.2] */ - {0x81d5, 0x00efbda0}, /* U+FF60 FULLWIDTH RIGHT WHITE PARENTHESIS [2000] [Unicode3.2] */ - {0x81d6, 0x00e38098}, /* U+3018 LEFT WHITE TORTOISE SHELL BRACKET [2000] */ - {0x81d7, 0x00e38099}, /* U+3019 RIGHT WHITE TORTOISE SHELL BRACKET [2000] */ - {0x81d8, 0x00e38096}, /* U+3016 LEFT WHITE LENTICULAR BRACKET [2000] */ - {0x81d9, 0x00e38097}, /* U+3017 RIGHT WHITE LENTICULAR BRACKET [2000] */ - {0x81da, 0x00e288a0}, /* U+2220 ANGLE [1983] */ - {0x81db, 0x00e28aa5}, /* U+22A5 UP TACK [1983] */ - {0x81dc, 0x00e28c92}, /* U+2312 ARC [1983] */ - {0x81dd, 0x00e28882}, /* U+2202 PARTIAL DIFFERENTIAL [1983] */ - {0x81de, 0x00e28887}, /* U+2207 NABLA [1983] */ - {0x81df, 0x00e289a1}, /* U+2261 IDENTICAL TO [1983] */ - {0x81e0, 0x00e28992}, /* U+2252 APPROXIMATELY EQUAL TO OR THE IMAGE OF [1983] */ - {0x81e1, 0x00e289aa}, /* U+226A MUCH LESS-THAN [1983] */ - {0x81e2, 0x00e289ab}, /* U+226B MUCH GREATER-THAN [1983] */ - {0x81e3, 0x00e2889a}, /* U+221A SQUARE ROOT [1983] */ - {0x81e4, 0x00e288bd}, /* U+223D REVERSED TILDE [1983] */ - {0x81e5, 0x00e2889d}, /* U+221D PROPORTIONAL TO [1983] */ - {0x81e6, 0x00e288b5}, /* U+2235 BECAUSE [1983] */ - {0x81e7, 0x00e288ab}, /* U+222B INTEGRAL [1983] */ - {0x81e8, 0x00e288ac}, /* U+222C DOUBLE INTEGRAL [1983] */ - {0x81e9, 0x00e289a2}, /* U+2262 NOT IDENTICAL TO [2000] */ - {0x81ea, 0x00e28983}, /* U+2243 ASYMPTOTICALLY EQUAL TO [2000] */ - {0x81eb, 0x00e28985}, /* U+2245 APPROXIMATELY EQUAL TO [2000] */ - {0x81ec, 0x00e28988}, /* U+2248 ALMOST EQUAL TO [2000] */ - {0x81ed, 0x00e289b6}, /* U+2276 LESS-THAN OR GREATER-THAN [2000] */ - {0x81ee, 0x00e289b7}, /* U+2277 GREATER-THAN OR LESS-THAN [2000] */ - {0x81ef, 0x00e28694}, /* U+2194 LEFT RIGHT ARROW [2000] */ - {0x81f0, 0x00e284ab}, /* U+212B ANGSTROM SIGN [1983] */ - {0x81f1, 0x00e280b0}, /* U+2030 PER MILLE SIGN [1983] */ - {0x81f2, 0x00e299af}, /* U+266F MUSIC SHARP SIGN [1983] */ - {0x81f3, 0x00e299ad}, /* U+266D MUSIC FLAT SIGN [1983] */ - {0x81f4, 0x00e299aa}, /* U+266A EIGHTH NOTE [1983] */ - {0x81f5, 0x00e280a0}, /* U+2020 DAGGER [1983] */ - {0x81f6, 0x00e280a1}, /* U+2021 DOUBLE DAGGER [1983] */ - {0x81f7, 0x0000c2b6}, /* U+00B6 PILCROW SIGN [1983] */ - {0x81f8, 0x00e299ae}, /* U+266E MUSIC NATURAL SIGN [2000] */ - {0x81f9, 0x00e299ab}, /* U+266B BEAMED EIGHTH NOTES [2000] */ - {0x81fa, 0x00e299ac}, /* U+266C BEAMED SIXTEENTH NOTES [2000] */ - {0x81fb, 0x00e299a9}, /* U+2669 QUARTER NOTE [2000] */ - {0x81fc, 0x00e297af}, /* U+25EF LARGE CIRCLE [1983] */ - {0x8240, 0x00e296b7}, /* U+25B7 WHITE RIGHT-POINTING TRIANGLE [2000] */ - {0x8241, 0x00e296b6}, /* U+25B6 BLACK RIGHT-POINTING TRIANGLE [2000] */ - {0x8242, 0x00e29781}, /* U+25C1 WHITE LEFT-POINTING TRIANGLE [2000] */ - {0x8243, 0x00e29780}, /* U+25C0 BLACK LEFT-POINTING TRIANGLE [2000] */ - {0x8244, 0x00e28697}, /* U+2197 NORTH EAST ARROW [2000] */ - {0x8245, 0x00e28698}, /* U+2198 SOUTH EAST ARROW [2000] */ - {0x8246, 0x00e28696}, /* U+2196 NORTH WEST ARROW [2000] */ - {0x8247, 0x00e28699}, /* U+2199 SOUTH WEST ARROW [2000] */ - {0x8248, 0x00e28784}, /* U+21C4 RIGHTWARDS ARROW OVER LEFTWARDS ARROW [2000] */ - {0x8249, 0x00e287a8}, /* U+21E8 RIGHTWARDS WHITE ARROW [2000] */ - {0x824a, 0x00e287a6}, /* U+21E6 LEFTWARDS WHITE ARROW [2000] */ - {0x824b, 0x00e287a7}, /* U+21E7 UPWARDS WHITE ARROW [2000] */ - {0x824c, 0x00e287a9}, /* U+21E9 DOWNWARDS WHITE ARROW [2000] */ - {0x824d, 0x00e2a4b4}, /* U+2934 ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS [2000] [Unicode3.2] */ - {0x824e, 0x00e2a4b5}, /* U+2935 ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS [2000] [Unicode3.2] */ - {0x824f, 0x00efbc90}, /* U+FF10 FULLWIDTH DIGIT ZERO */ - {0x8250, 0x00efbc91}, /* U+FF11 FULLWIDTH DIGIT ONE */ - {0x8251, 0x00efbc92}, /* U+FF12 FULLWIDTH DIGIT TWO */ - {0x8252, 0x00efbc93}, /* U+FF13 FULLWIDTH DIGIT THREE */ - {0x8253, 0x00efbc94}, /* U+FF14 FULLWIDTH DIGIT FOUR */ - {0x8254, 0x00efbc95}, /* U+FF15 FULLWIDTH DIGIT FIVE */ - {0x8255, 0x00efbc96}, /* U+FF16 FULLWIDTH DIGIT SIX */ - {0x8256, 0x00efbc97}, /* U+FF17 FULLWIDTH DIGIT SEVEN */ - {0x8257, 0x00efbc98}, /* U+FF18 FULLWIDTH DIGIT EIGHT */ - {0x8258, 0x00efbc99}, /* U+FF19 FULLWIDTH DIGIT NINE */ - {0x8259, 0x00e2a6bf}, /* U+29BF CIRCLED BULLET [2000] [Unicode3.2] */ - {0x825a, 0x00e29789}, /* U+25C9 FISHEYE [2000] */ - {0x825b, 0x00e380bd}, /* U+303D PART ALTERNATION MARK [2000] [Unicode3.2] */ - {0x825c, 0x00efb986}, /* U+FE46 WHITE SESAME DOT [2000] [Unicode3.2] */ - {0x825d, 0x00efb985}, /* U+FE45 SESAME DOT [2000] [Unicode3.2] */ - {0x825e, 0x00e297a6}, /* U+25E6 WHITE BULLET [2000] */ - {0x825f, 0x00e280a2}, /* U+2022 BULLET [2000] */ - {0x8260, 0x00efbca1}, /* U+FF21 FULLWIDTH LATIN CAPITAL LETTER A */ - {0x8261, 0x00efbca2}, /* U+FF22 FULLWIDTH LATIN CAPITAL LETTER B */ - {0x8262, 0x00efbca3}, /* U+FF23 FULLWIDTH LATIN CAPITAL LETTER C */ - {0x8263, 0x00efbca4}, /* U+FF24 FULLWIDTH LATIN CAPITAL LETTER D */ - {0x8264, 0x00efbca5}, /* U+FF25 FULLWIDTH LATIN CAPITAL LETTER E */ - {0x8265, 0x00efbca6}, /* U+FF26 FULLWIDTH LATIN CAPITAL LETTER F */ - {0x8266, 0x00efbca7}, /* U+FF27 FULLWIDTH LATIN CAPITAL LETTER G */ - {0x8267, 0x00efbca8}, /* U+FF28 FULLWIDTH LATIN CAPITAL LETTER H */ - {0x8268, 0x00efbca9}, /* U+FF29 FULLWIDTH LATIN CAPITAL LETTER I */ - {0x8269, 0x00efbcaa}, /* U+FF2A FULLWIDTH LATIN CAPITAL LETTER J */ - {0x826a, 0x00efbcab}, /* U+FF2B FULLWIDTH LATIN CAPITAL LETTER K */ - {0x826b, 0x00efbcac}, /* U+FF2C FULLWIDTH LATIN CAPITAL LETTER L */ - {0x826c, 0x00efbcad}, /* U+FF2D FULLWIDTH LATIN CAPITAL LETTER M */ - {0x826d, 0x00efbcae}, /* U+FF2E FULLWIDTH LATIN CAPITAL LETTER N */ - {0x826e, 0x00efbcaf}, /* U+FF2F FULLWIDTH LATIN CAPITAL LETTER O */ - {0x826f, 0x00efbcb0}, /* U+FF30 FULLWIDTH LATIN CAPITAL LETTER P */ - {0x8270, 0x00efbcb1}, /* U+FF31 FULLWIDTH LATIN CAPITAL LETTER Q */ - {0x8271, 0x00efbcb2}, /* U+FF32 FULLWIDTH LATIN CAPITAL LETTER R */ - {0x8272, 0x00efbcb3}, /* U+FF33 FULLWIDTH LATIN CAPITAL LETTER S */ - {0x8273, 0x00efbcb4}, /* U+FF34 FULLWIDTH LATIN CAPITAL LETTER T */ - {0x8274, 0x00efbcb5}, /* U+FF35 FULLWIDTH LATIN CAPITAL LETTER U */ - {0x8275, 0x00efbcb6}, /* U+FF36 FULLWIDTH LATIN CAPITAL LETTER V */ - {0x8276, 0x00efbcb7}, /* U+FF37 FULLWIDTH LATIN CAPITAL LETTER W */ - {0x8277, 0x00efbcb8}, /* U+FF38 FULLWIDTH LATIN CAPITAL LETTER X */ - {0x8278, 0x00efbcb9}, /* U+FF39 FULLWIDTH LATIN CAPITAL LETTER Y */ - {0x8279, 0x00efbcba}, /* U+FF3A FULLWIDTH LATIN CAPITAL LETTER Z */ - {0x827a, 0x00e28893}, /* U+2213 MINUS-OR-PLUS SIGN [2000] */ - {0x827b, 0x00e284b5}, /* U+2135 ALEF SYMBOL [2000] */ - {0x827c, 0x00e2848f}, /* U+210F PLANCK CONSTANT OVER TWO PI [2000] */ - {0x827d, 0x00e38f8b}, /* U+33CB SQUARE HP [2000] */ - {0x827e, 0x00e28493}, /* U+2113 SCRIPT SMALL L [2000] */ - {0x8280, 0x00e284a7}, /* U+2127 INVERTED OHM SIGN [2000] */ - {0x8281, 0x00efbd81}, /* U+FF41 FULLWIDTH LATIN SMALL LETTER A */ - {0x8282, 0x00efbd82}, /* U+FF42 FULLWIDTH LATIN SMALL LETTER B */ - {0x8283, 0x00efbd83}, /* U+FF43 FULLWIDTH LATIN SMALL LETTER C */ - {0x8284, 0x00efbd84}, /* U+FF44 FULLWIDTH LATIN SMALL LETTER D */ - {0x8285, 0x00efbd85}, /* U+FF45 FULLWIDTH LATIN SMALL LETTER E */ - {0x8286, 0x00efbd86}, /* U+FF46 FULLWIDTH LATIN SMALL LETTER F */ - {0x8287, 0x00efbd87}, /* U+FF47 FULLWIDTH LATIN SMALL LETTER G */ - {0x8288, 0x00efbd88}, /* U+FF48 FULLWIDTH LATIN SMALL LETTER H */ - {0x8289, 0x00efbd89}, /* U+FF49 FULLWIDTH LATIN SMALL LETTER I */ - {0x828a, 0x00efbd8a}, /* U+FF4A FULLWIDTH LATIN SMALL LETTER J */ - {0x828b, 0x00efbd8b}, /* U+FF4B FULLWIDTH LATIN SMALL LETTER K */ - {0x828c, 0x00efbd8c}, /* U+FF4C FULLWIDTH LATIN SMALL LETTER L */ - {0x828d, 0x00efbd8d}, /* U+FF4D FULLWIDTH LATIN SMALL LETTER M */ - {0x828e, 0x00efbd8e}, /* U+FF4E FULLWIDTH LATIN SMALL LETTER N */ - {0x828f, 0x00efbd8f}, /* U+FF4F FULLWIDTH LATIN SMALL LETTER O */ - {0x8290, 0x00efbd90}, /* U+FF50 FULLWIDTH LATIN SMALL LETTER P */ - {0x8291, 0x00efbd91}, /* U+FF51 FULLWIDTH LATIN SMALL LETTER Q */ - {0x8292, 0x00efbd92}, /* U+FF52 FULLWIDTH LATIN SMALL LETTER R */ - {0x8293, 0x00efbd93}, /* U+FF53 FULLWIDTH LATIN SMALL LETTER S */ - {0x8294, 0x00efbd94}, /* U+FF54 FULLWIDTH LATIN SMALL LETTER T */ - {0x8295, 0x00efbd95}, /* U+FF55 FULLWIDTH LATIN SMALL LETTER U */ - {0x8296, 0x00efbd96}, /* U+FF56 FULLWIDTH LATIN SMALL LETTER V */ - {0x8297, 0x00efbd97}, /* U+FF57 FULLWIDTH LATIN SMALL LETTER W */ - {0x8298, 0x00efbd98}, /* U+FF58 FULLWIDTH LATIN SMALL LETTER X */ - {0x8299, 0x00efbd99}, /* U+FF59 FULLWIDTH LATIN SMALL LETTER Y */ - {0x829a, 0x00efbd9a}, /* U+FF5A FULLWIDTH LATIN SMALL LETTER Z */ - {0x829b, 0x00e382a0}, /* U+30A0 KATAKANA-HIRAGANA DOUBLE HYPHEN [2000] [Unicode3.2] */ - {0x829c, 0x00e28093}, /* U+2013 EN DASH [2000] */ - {0x829d, 0x00e2a7ba}, /* U+29FA DOUBLE PLUS [2000] [Unicode3.2] */ - {0x829e, 0x00e2a7bb}, /* U+29FB TRIPLE PLUS [2000] [Unicode3.2] */ - {0x829f, 0x00e38181}, /* U+3041 HIRAGANA LETTER SMALL A */ - {0x82a0, 0x00e38182}, /* U+3042 HIRAGANA LETTER A */ - {0x82a1, 0x00e38183}, /* U+3043 HIRAGANA LETTER SMALL I */ - {0x82a2, 0x00e38184}, /* U+3044 HIRAGANA LETTER I */ - {0x82a3, 0x00e38185}, /* U+3045 HIRAGANA LETTER SMALL U */ - {0x82a4, 0x00e38186}, /* U+3046 HIRAGANA LETTER U */ - {0x82a5, 0x00e38187}, /* U+3047 HIRAGANA LETTER SMALL E */ - {0x82a6, 0x00e38188}, /* U+3048 HIRAGANA LETTER E */ - {0x82a7, 0x00e38189}, /* U+3049 HIRAGANA LETTER SMALL O */ - {0x82a8, 0x00e3818a}, /* U+304A HIRAGANA LETTER O */ - {0x82a9, 0x00e3818b}, /* U+304B HIRAGANA LETTER KA */ - {0x82aa, 0x00e3818c}, /* U+304C HIRAGANA LETTER GA */ - {0x82ab, 0x00e3818d}, /* U+304D HIRAGANA LETTER KI */ - {0x82ac, 0x00e3818e}, /* U+304E HIRAGANA LETTER GI */ - {0x82ad, 0x00e3818f}, /* U+304F HIRAGANA LETTER KU */ - {0x82ae, 0x00e38190}, /* U+3050 HIRAGANA LETTER GU */ - {0x82af, 0x00e38191}, /* U+3051 HIRAGANA LETTER KE */ - {0x82b0, 0x00e38192}, /* U+3052 HIRAGANA LETTER GE */ - {0x82b1, 0x00e38193}, /* U+3053 HIRAGANA LETTER KO */ - {0x82b2, 0x00e38194}, /* U+3054 HIRAGANA LETTER GO */ - {0x82b3, 0x00e38195}, /* U+3055 HIRAGANA LETTER SA */ - {0x82b4, 0x00e38196}, /* U+3056 HIRAGANA LETTER ZA */ - {0x82b5, 0x00e38197}, /* U+3057 HIRAGANA LETTER SI */ - {0x82b6, 0x00e38198}, /* U+3058 HIRAGANA LETTER ZI */ - {0x82b7, 0x00e38199}, /* U+3059 HIRAGANA LETTER SU */ - {0x82b8, 0x00e3819a}, /* U+305A HIRAGANA LETTER ZU */ - {0x82b9, 0x00e3819b}, /* U+305B HIRAGANA LETTER SE */ - {0x82ba, 0x00e3819c}, /* U+305C HIRAGANA LETTER ZE */ - {0x82bb, 0x00e3819d}, /* U+305D HIRAGANA LETTER SO */ - {0x82bc, 0x00e3819e}, /* U+305E HIRAGANA LETTER ZO */ - {0x82bd, 0x00e3819f}, /* U+305F HIRAGANA LETTER TA */ - {0x82be, 0x00e381a0}, /* U+3060 HIRAGANA LETTER DA */ - {0x82bf, 0x00e381a1}, /* U+3061 HIRAGANA LETTER TI */ - {0x82c0, 0x00e381a2}, /* U+3062 HIRAGANA LETTER DI */ - {0x82c1, 0x00e381a3}, /* U+3063 HIRAGANA LETTER SMALL TU */ - {0x82c2, 0x00e381a4}, /* U+3064 HIRAGANA LETTER TU */ - {0x82c3, 0x00e381a5}, /* U+3065 HIRAGANA LETTER DU */ - {0x82c4, 0x00e381a6}, /* U+3066 HIRAGANA LETTER TE */ - {0x82c5, 0x00e381a7}, /* U+3067 HIRAGANA LETTER DE */ - {0x82c6, 0x00e381a8}, /* U+3068 HIRAGANA LETTER TO */ - {0x82c7, 0x00e381a9}, /* U+3069 HIRAGANA LETTER DO */ - {0x82c8, 0x00e381aa}, /* U+306A HIRAGANA LETTER NA */ - {0x82c9, 0x00e381ab}, /* U+306B HIRAGANA LETTER NI */ - {0x82ca, 0x00e381ac}, /* U+306C HIRAGANA LETTER NU */ - {0x82cb, 0x00e381ad}, /* U+306D HIRAGANA LETTER NE */ - {0x82cc, 0x00e381ae}, /* U+306E HIRAGANA LETTER NO */ - {0x82cd, 0x00e381af}, /* U+306F HIRAGANA LETTER HA */ - {0x82ce, 0x00e381b0}, /* U+3070 HIRAGANA LETTER BA */ - {0x82cf, 0x00e381b1}, /* U+3071 HIRAGANA LETTER PA */ - {0x82d0, 0x00e381b2}, /* U+3072 HIRAGANA LETTER HI */ - {0x82d1, 0x00e381b3}, /* U+3073 HIRAGANA LETTER BI */ - {0x82d2, 0x00e381b4}, /* U+3074 HIRAGANA LETTER PI */ - {0x82d3, 0x00e381b5}, /* U+3075 HIRAGANA LETTER HU */ - {0x82d4, 0x00e381b6}, /* U+3076 HIRAGANA LETTER BU */ - {0x82d5, 0x00e381b7}, /* U+3077 HIRAGANA LETTER PU */ - {0x82d6, 0x00e381b8}, /* U+3078 HIRAGANA LETTER HE */ - {0x82d7, 0x00e381b9}, /* U+3079 HIRAGANA LETTER BE */ - {0x82d8, 0x00e381ba}, /* U+307A HIRAGANA LETTER PE */ - {0x82d9, 0x00e381bb}, /* U+307B HIRAGANA LETTER HO */ - {0x82da, 0x00e381bc}, /* U+307C HIRAGANA LETTER BO */ - {0x82db, 0x00e381bd}, /* U+307D HIRAGANA LETTER PO */ - {0x82dc, 0x00e381be}, /* U+307E HIRAGANA LETTER MA */ - {0x82dd, 0x00e381bf}, /* U+307F HIRAGANA LETTER MI */ - {0x82de, 0x00e38280}, /* U+3080 HIRAGANA LETTER MU */ - {0x82df, 0x00e38281}, /* U+3081 HIRAGANA LETTER ME */ - {0x82e0, 0x00e38282}, /* U+3082 HIRAGANA LETTER MO */ - {0x82e1, 0x00e38283}, /* U+3083 HIRAGANA LETTER SMALL YA */ - {0x82e2, 0x00e38284}, /* U+3084 HIRAGANA LETTER YA */ - {0x82e3, 0x00e38285}, /* U+3085 HIRAGANA LETTER SMALL YU */ - {0x82e4, 0x00e38286}, /* U+3086 HIRAGANA LETTER YU */ - {0x82e5, 0x00e38287}, /* U+3087 HIRAGANA LETTER SMALL YO */ - {0x82e6, 0x00e38288}, /* U+3088 HIRAGANA LETTER YO */ - {0x82e7, 0x00e38289}, /* U+3089 HIRAGANA LETTER RA */ - {0x82e8, 0x00e3828a}, /* U+308A HIRAGANA LETTER RI */ - {0x82e9, 0x00e3828b}, /* U+308B HIRAGANA LETTER RU */ - {0x82ea, 0x00e3828c}, /* U+308C HIRAGANA LETTER RE */ - {0x82eb, 0x00e3828d}, /* U+308D HIRAGANA LETTER RO */ - {0x82ec, 0x00e3828e}, /* U+308E HIRAGANA LETTER SMALL WA */ - {0x82ed, 0x00e3828f}, /* U+308F HIRAGANA LETTER WA */ - {0x82ee, 0x00e38290}, /* U+3090 HIRAGANA LETTER WI */ - {0x82ef, 0x00e38291}, /* U+3091 HIRAGANA LETTER WE */ - {0x82f0, 0x00e38292}, /* U+3092 HIRAGANA LETTER WO */ - {0x82f1, 0x00e38293}, /* U+3093 HIRAGANA LETTER N */ - {0x82f2, 0x00e38294}, /* U+3094 HIRAGANA LETTER VU [2000] */ - {0x82f3, 0x00e38295}, /* U+3095 HIRAGANA LETTER SMALL KA [2000] [Unicode3.2] */ - {0x82f4, 0x00e38296}, /* U+3096 HIRAGANA LETTER SMALL KE [2000] [Unicode3.2] */ - {0x8340, 0x00e382a1}, /* U+30A1 KATAKANA LETTER SMALL A */ - {0x8341, 0x00e382a2}, /* U+30A2 KATAKANA LETTER A */ - {0x8342, 0x00e382a3}, /* U+30A3 KATAKANA LETTER SMALL I */ - {0x8343, 0x00e382a4}, /* U+30A4 KATAKANA LETTER I */ - {0x8344, 0x00e382a5}, /* U+30A5 KATAKANA LETTER SMALL U */ - {0x8345, 0x00e382a6}, /* U+30A6 KATAKANA LETTER U */ - {0x8346, 0x00e382a7}, /* U+30A7 KATAKANA LETTER SMALL E */ - {0x8347, 0x00e382a8}, /* U+30A8 KATAKANA LETTER E */ - {0x8348, 0x00e382a9}, /* U+30A9 KATAKANA LETTER SMALL O */ - {0x8349, 0x00e382aa}, /* U+30AA KATAKANA LETTER O */ - {0x834a, 0x00e382ab}, /* U+30AB KATAKANA LETTER KA */ - {0x834b, 0x00e382ac}, /* U+30AC KATAKANA LETTER GA */ - {0x834c, 0x00e382ad}, /* U+30AD KATAKANA LETTER KI */ - {0x834d, 0x00e382ae}, /* U+30AE KATAKANA LETTER GI */ - {0x834e, 0x00e382af}, /* U+30AF KATAKANA LETTER KU */ - {0x834f, 0x00e382b0}, /* U+30B0 KATAKANA LETTER GU */ - {0x8350, 0x00e382b1}, /* U+30B1 KATAKANA LETTER KE */ - {0x8351, 0x00e382b2}, /* U+30B2 KATAKANA LETTER GE */ - {0x8352, 0x00e382b3}, /* U+30B3 KATAKANA LETTER KO */ - {0x8353, 0x00e382b4}, /* U+30B4 KATAKANA LETTER GO */ - {0x8354, 0x00e382b5}, /* U+30B5 KATAKANA LETTER SA */ - {0x8355, 0x00e382b6}, /* U+30B6 KATAKANA LETTER ZA */ - {0x8356, 0x00e382b7}, /* U+30B7 KATAKANA LETTER SI */ - {0x8357, 0x00e382b8}, /* U+30B8 KATAKANA LETTER ZI */ - {0x8358, 0x00e382b9}, /* U+30B9 KATAKANA LETTER SU */ - {0x8359, 0x00e382ba}, /* U+30BA KATAKANA LETTER ZU */ - {0x835a, 0x00e382bb}, /* U+30BB KATAKANA LETTER SE */ - {0x835b, 0x00e382bc}, /* U+30BC KATAKANA LETTER ZE */ - {0x835c, 0x00e382bd}, /* U+30BD KATAKANA LETTER SO */ - {0x835d, 0x00e382be}, /* U+30BE KATAKANA LETTER ZO */ - {0x835e, 0x00e382bf}, /* U+30BF KATAKANA LETTER TA */ - {0x835f, 0x00e38380}, /* U+30C0 KATAKANA LETTER DA */ - {0x8360, 0x00e38381}, /* U+30C1 KATAKANA LETTER TI */ - {0x8361, 0x00e38382}, /* U+30C2 KATAKANA LETTER DI */ - {0x8362, 0x00e38383}, /* U+30C3 KATAKANA LETTER SMALL TU */ - {0x8363, 0x00e38384}, /* U+30C4 KATAKANA LETTER TU */ - {0x8364, 0x00e38385}, /* U+30C5 KATAKANA LETTER DU */ - {0x8365, 0x00e38386}, /* U+30C6 KATAKANA LETTER TE */ - {0x8366, 0x00e38387}, /* U+30C7 KATAKANA LETTER DE */ - {0x8367, 0x00e38388}, /* U+30C8 KATAKANA LETTER TO */ - {0x8368, 0x00e38389}, /* U+30C9 KATAKANA LETTER DO */ - {0x8369, 0x00e3838a}, /* U+30CA KATAKANA LETTER NA */ - {0x836a, 0x00e3838b}, /* U+30CB KATAKANA LETTER NI */ - {0x836b, 0x00e3838c}, /* U+30CC KATAKANA LETTER NU */ - {0x836c, 0x00e3838d}, /* U+30CD KATAKANA LETTER NE */ - {0x836d, 0x00e3838e}, /* U+30CE KATAKANA LETTER NO */ - {0x836e, 0x00e3838f}, /* U+30CF KATAKANA LETTER HA */ - {0x836f, 0x00e38390}, /* U+30D0 KATAKANA LETTER BA */ - {0x8370, 0x00e38391}, /* U+30D1 KATAKANA LETTER PA */ - {0x8371, 0x00e38392}, /* U+30D2 KATAKANA LETTER HI */ - {0x8372, 0x00e38393}, /* U+30D3 KATAKANA LETTER BI */ - {0x8373, 0x00e38394}, /* U+30D4 KATAKANA LETTER PI */ - {0x8374, 0x00e38395}, /* U+30D5 KATAKANA LETTER HU */ - {0x8375, 0x00e38396}, /* U+30D6 KATAKANA LETTER BU */ - {0x8376, 0x00e38397}, /* U+30D7 KATAKANA LETTER PU */ - {0x8377, 0x00e38398}, /* U+30D8 KATAKANA LETTER HE */ - {0x8378, 0x00e38399}, /* U+30D9 KATAKANA LETTER BE */ - {0x8379, 0x00e3839a}, /* U+30DA KATAKANA LETTER PE */ - {0x837a, 0x00e3839b}, /* U+30DB KATAKANA LETTER HO */ - {0x837b, 0x00e3839c}, /* U+30DC KATAKANA LETTER BO */ - {0x837c, 0x00e3839d}, /* U+30DD KATAKANA LETTER PO */ - {0x837d, 0x00e3839e}, /* U+30DE KATAKANA LETTER MA */ - {0x837e, 0x00e3839f}, /* U+30DF KATAKANA LETTER MI */ - {0x8380, 0x00e383a0}, /* U+30E0 KATAKANA LETTER MU */ - {0x8381, 0x00e383a1}, /* U+30E1 KATAKANA LETTER ME */ - {0x8382, 0x00e383a2}, /* U+30E2 KATAKANA LETTER MO */ - {0x8383, 0x00e383a3}, /* U+30E3 KATAKANA LETTER SMALL YA */ - {0x8384, 0x00e383a4}, /* U+30E4 KATAKANA LETTER YA */ - {0x8385, 0x00e383a5}, /* U+30E5 KATAKANA LETTER SMALL YU */ - {0x8386, 0x00e383a6}, /* U+30E6 KATAKANA LETTER YU */ - {0x8387, 0x00e383a7}, /* U+30E7 KATAKANA LETTER SMALL YO */ - {0x8388, 0x00e383a8}, /* U+30E8 KATAKANA LETTER YO */ - {0x8389, 0x00e383a9}, /* U+30E9 KATAKANA LETTER RA */ - {0x838a, 0x00e383aa}, /* U+30EA KATAKANA LETTER RI */ - {0x838b, 0x00e383ab}, /* U+30EB KATAKANA LETTER RU */ - {0x838c, 0x00e383ac}, /* U+30EC KATAKANA LETTER RE */ - {0x838d, 0x00e383ad}, /* U+30ED KATAKANA LETTER RO */ - {0x838e, 0x00e383ae}, /* U+30EE KATAKANA LETTER SMALL WA */ - {0x838f, 0x00e383af}, /* U+30EF KATAKANA LETTER WA */ - {0x8390, 0x00e383b0}, /* U+30F0 KATAKANA LETTER WI */ - {0x8391, 0x00e383b1}, /* U+30F1 KATAKANA LETTER WE */ - {0x8392, 0x00e383b2}, /* U+30F2 KATAKANA LETTER WO */ - {0x8393, 0x00e383b3}, /* U+30F3 KATAKANA LETTER N */ - {0x8394, 0x00e383b4}, /* U+30F4 KATAKANA LETTER VU */ - {0x8395, 0x00e383b5}, /* U+30F5 KATAKANA LETTER SMALL KA */ - {0x8396, 0x00e383b6}, /* U+30F6 KATAKANA LETTER SMALL KE */ - {0x839f, 0x0000ce91}, /* U+0391 GREEK CAPITAL LETTER ALPHA */ - {0x83a0, 0x0000ce92}, /* U+0392 GREEK CAPITAL LETTER BETA */ - {0x83a1, 0x0000ce93}, /* U+0393 GREEK CAPITAL LETTER GAMMA */ - {0x83a2, 0x0000ce94}, /* U+0394 GREEK CAPITAL LETTER DELTA */ - {0x83a3, 0x0000ce95}, /* U+0395 GREEK CAPITAL LETTER EPSILON */ - {0x83a4, 0x0000ce96}, /* U+0396 GREEK CAPITAL LETTER ZETA */ - {0x83a5, 0x0000ce97}, /* U+0397 GREEK CAPITAL LETTER ETA */ - {0x83a6, 0x0000ce98}, /* U+0398 GREEK CAPITAL LETTER THETA */ - {0x83a7, 0x0000ce99}, /* U+0399 GREEK CAPITAL LETTER IOTA */ - {0x83a8, 0x0000ce9a}, /* U+039A GREEK CAPITAL LETTER KAPPA */ - {0x83a9, 0x0000ce9b}, /* U+039B GREEK CAPITAL LETTER LAMDA */ - {0x83aa, 0x0000ce9c}, /* U+039C GREEK CAPITAL LETTER MU */ - {0x83ab, 0x0000ce9d}, /* U+039D GREEK CAPITAL LETTER NU */ - {0x83ac, 0x0000ce9e}, /* U+039E GREEK CAPITAL LETTER XI */ - {0x83ad, 0x0000ce9f}, /* U+039F GREEK CAPITAL LETTER OMICRON */ - {0x83ae, 0x0000cea0}, /* U+03A0 GREEK CAPITAL LETTER PI */ - {0x83af, 0x0000cea1}, /* U+03A1 GREEK CAPITAL LETTER RHO */ - {0x83b0, 0x0000cea3}, /* U+03A3 GREEK CAPITAL LETTER SIGMA */ - {0x83b1, 0x0000cea4}, /* U+03A4 GREEK CAPITAL LETTER TAU */ - {0x83b2, 0x0000cea5}, /* U+03A5 GREEK CAPITAL LETTER UPSILON */ - {0x83b3, 0x0000cea6}, /* U+03A6 GREEK CAPITAL LETTER PHI */ - {0x83b4, 0x0000cea7}, /* U+03A7 GREEK CAPITAL LETTER CHI */ - {0x83b5, 0x0000cea8}, /* U+03A8 GREEK CAPITAL LETTER PSI */ - {0x83b6, 0x0000cea9}, /* U+03A9 GREEK CAPITAL LETTER OMEGA */ - {0x83b7, 0x00e299a4}, /* U+2664 WHITE SPADE SUIT [2000] */ - {0x83b8, 0x00e299a0}, /* U+2660 BLACK SPADE SUIT [2000] */ - {0x83b9, 0x00e299a2}, /* U+2662 WHITE DIAMOND SUIT [2000] */ - {0x83ba, 0x00e299a6}, /* U+2666 BLACK DIAMOND SUIT [2000] */ - {0x83bb, 0x00e299a1}, /* U+2661 WHITE HEART SUIT [2000] */ - {0x83bc, 0x00e299a5}, /* U+2665 BLACK HEART SUIT [2000] */ - {0x83bd, 0x00e299a7}, /* U+2667 WHITE CLUB SUIT [2000] */ - {0x83be, 0x00e299a3}, /* U+2663 BLACK CLUB SUIT [2000] */ - {0x83bf, 0x0000ceb1}, /* U+03B1 GREEK SMALL LETTER ALPHA */ - {0x83c0, 0x0000ceb2}, /* U+03B2 GREEK SMALL LETTER BETA */ - {0x83c1, 0x0000ceb3}, /* U+03B3 GREEK SMALL LETTER GAMMA */ - {0x83c2, 0x0000ceb4}, /* U+03B4 GREEK SMALL LETTER DELTA */ - {0x83c3, 0x0000ceb5}, /* U+03B5 GREEK SMALL LETTER EPSILON */ - {0x83c4, 0x0000ceb6}, /* U+03B6 GREEK SMALL LETTER ZETA */ - {0x83c5, 0x0000ceb7}, /* U+03B7 GREEK SMALL LETTER ETA */ - {0x83c6, 0x0000ceb8}, /* U+03B8 GREEK SMALL LETTER THETA */ - {0x83c7, 0x0000ceb9}, /* U+03B9 GREEK SMALL LETTER IOTA */ - {0x83c8, 0x0000ceba}, /* U+03BA GREEK SMALL LETTER KAPPA */ - {0x83c9, 0x0000cebb}, /* U+03BB GREEK SMALL LETTER LAMDA */ - {0x83ca, 0x0000cebc}, /* U+03BC GREEK SMALL LETTER MU */ - {0x83cb, 0x0000cebd}, /* U+03BD GREEK SMALL LETTER NU */ - {0x83cc, 0x0000cebe}, /* U+03BE GREEK SMALL LETTER XI */ - {0x83cd, 0x0000cebf}, /* U+03BF GREEK SMALL LETTER OMICRON */ - {0x83ce, 0x0000cf80}, /* U+03C0 GREEK SMALL LETTER PI */ - {0x83cf, 0x0000cf81}, /* U+03C1 GREEK SMALL LETTER RHO */ - {0x83d0, 0x0000cf83}, /* U+03C3 GREEK SMALL LETTER SIGMA */ - {0x83d1, 0x0000cf84}, /* U+03C4 GREEK SMALL LETTER TAU */ - {0x83d2, 0x0000cf85}, /* U+03C5 GREEK SMALL LETTER UPSILON */ - {0x83d3, 0x0000cf86}, /* U+03C6 GREEK SMALL LETTER PHI */ - {0x83d4, 0x0000cf87}, /* U+03C7 GREEK SMALL LETTER CHI */ - {0x83d5, 0x0000cf88}, /* U+03C8 GREEK SMALL LETTER PSI */ - {0x83d6, 0x0000cf89}, /* U+03C9 GREEK SMALL LETTER OMEGA */ - {0x83d7, 0x0000cf82}, /* U+03C2 GREEK SMALL LETTER FINAL SIGMA [2000] */ - {0x83d8, 0x00e293b5}, /* U+24F5 DOUBLE CIRCLED DIGIT ONE [2000] [Unicode3.2] */ - {0x83d9, 0x00e293b6}, /* U+24F6 DOUBLE CIRCLED DIGIT TWO [2000] [Unicode3.2] */ - {0x83da, 0x00e293b7}, /* U+24F7 DOUBLE CIRCLED DIGIT THREE [2000] [Unicode3.2] */ - {0x83db, 0x00e293b8}, /* U+24F8 DOUBLE CIRCLED DIGIT FOUR [2000] [Unicode3.2] */ - {0x83dc, 0x00e293b9}, /* U+24F9 DOUBLE CIRCLED DIGIT FIVE [2000] [Unicode3.2] */ - {0x83dd, 0x00e293ba}, /* U+24FA DOUBLE CIRCLED DIGIT SIX [2000] [Unicode3.2] */ - {0x83de, 0x00e293bb}, /* U+24FB DOUBLE CIRCLED DIGIT SEVEN [2000] [Unicode3.2] */ - {0x83df, 0x00e293bc}, /* U+24FC DOUBLE CIRCLED DIGIT EIGHT [2000] [Unicode3.2] */ - {0x83e0, 0x00e293bd}, /* U+24FD DOUBLE CIRCLED DIGIT NINE [2000] [Unicode3.2] */ - {0x83e1, 0x00e293be}, /* U+24FE DOUBLE CIRCLED NUMBER TEN [2000] [Unicode3.2] */ - {0x83e2, 0x00e29896}, /* U+2616 WHITE SHOGI PIECE [2000] [Unicode3.2] */ - {0x83e3, 0x00e29897}, /* U+2617 BLACK SHOGI PIECE [2000] [Unicode3.2] */ - {0x83e4, 0x00e380a0}, /* U+3020 POSTAL MARK FACE [2000] */ - {0x83e5, 0x00e2988e}, /* U+260E BLACK TELEPHONE [2000] */ - {0x83e6, 0x00e29880}, /* U+2600 BLACK SUN WITH RAYS [2000] */ - {0x83e7, 0x00e29881}, /* U+2601 CLOUD [2000] */ - {0x83e8, 0x00e29882}, /* U+2602 UMBRELLA [2000] */ - {0x83e9, 0x00e29883}, /* U+2603 SNOWMAN [2000] */ - {0x83ea, 0x00e299a8}, /* U+2668 HOT SPRINGS [2000] */ - {0x83eb, 0x00e296b1}, /* U+25B1 WHITE PARALLELOGRAM [2000] */ - {0x83ec, 0x00e387b0}, /* U+31F0 KATAKANA LETTER SMALL KU [2000] [Unicode3.2] */ - {0x83ed, 0x00e387b1}, /* U+31F1 KATAKANA LETTER SMALL SI [2000] [Unicode3.2] */ - {0x83ee, 0x00e387b2}, /* U+31F2 KATAKANA LETTER SMALL SU [2000] [Unicode3.2] */ - {0x83ef, 0x00e387b3}, /* U+31F3 KATAKANA LETTER SMALL TO [2000] [Unicode3.2] */ - {0x83f0, 0x00e387b4}, /* U+31F4 KATAKANA LETTER SMALL NU [2000] [Unicode3.2] */ - {0x83f1, 0x00e387b5}, /* U+31F5 KATAKANA LETTER SMALL HA [2000] [Unicode3.2] */ - {0x83f2, 0x00e387b6}, /* U+31F6 KATAKANA LETTER SMALL HI [2000] [Unicode3.2] */ - {0x83f3, 0x00e387b7}, /* U+31F7 KATAKANA LETTER SMALL HU [2000] [Unicode3.2] */ - {0x83f4, 0x00e387b8}, /* U+31F8 KATAKANA LETTER SMALL HE [2000] [Unicode3.2] */ - {0x83f5, 0x00e387b9}, /* U+31F9 KATAKANA LETTER SMALL HO [2000] [Unicode3.2] */ - {0x83f7, 0x00e387ba}, /* U+31FA KATAKANA LETTER SMALL MU [2000] [Unicode3.2] */ - {0x83f8, 0x00e387bb}, /* U+31FB KATAKANA LETTER SMALL RA [2000] [Unicode3.2] */ - {0x83f9, 0x00e387bc}, /* U+31FC KATAKANA LETTER SMALL RI [2000] [Unicode3.2] */ - {0x83fa, 0x00e387bd}, /* U+31FD KATAKANA LETTER SMALL RU [2000] [Unicode3.2] */ - {0x83fb, 0x00e387be}, /* U+31FE KATAKANA LETTER SMALL RE [2000] [Unicode3.2] */ - {0x83fc, 0x00e387bf}, /* U+31FF KATAKANA LETTER SMALL RO [2000] [Unicode3.2] */ - {0x8440, 0x0000d090}, /* U+0410 CYRILLIC CAPITAL LETTER A */ - {0x8441, 0x0000d091}, /* U+0411 CYRILLIC CAPITAL LETTER BE */ - {0x8442, 0x0000d092}, /* U+0412 CYRILLIC CAPITAL LETTER VE */ - {0x8443, 0x0000d093}, /* U+0413 CYRILLIC CAPITAL LETTER GHE */ - {0x8444, 0x0000d094}, /* U+0414 CYRILLIC CAPITAL LETTER DE */ - {0x8445, 0x0000d095}, /* U+0415 CYRILLIC CAPITAL LETTER IE */ - {0x8446, 0x0000d081}, /* U+0401 CYRILLIC CAPITAL LETTER IO */ - {0x8447, 0x0000d096}, /* U+0416 CYRILLIC CAPITAL LETTER ZHE */ - {0x8448, 0x0000d097}, /* U+0417 CYRILLIC CAPITAL LETTER ZE */ - {0x8449, 0x0000d098}, /* U+0418 CYRILLIC CAPITAL LETTER I */ - {0x844a, 0x0000d099}, /* U+0419 CYRILLIC CAPITAL LETTER SHORT I */ - {0x844b, 0x0000d09a}, /* U+041A CYRILLIC CAPITAL LETTER KA */ - {0x844c, 0x0000d09b}, /* U+041B CYRILLIC CAPITAL LETTER EL */ - {0x844d, 0x0000d09c}, /* U+041C CYRILLIC CAPITAL LETTER EM */ - {0x844e, 0x0000d09d}, /* U+041D CYRILLIC CAPITAL LETTER EN */ - {0x844f, 0x0000d09e}, /* U+041E CYRILLIC CAPITAL LETTER O */ - {0x8450, 0x0000d09f}, /* U+041F CYRILLIC CAPITAL LETTER PE */ - {0x8451, 0x0000d0a0}, /* U+0420 CYRILLIC CAPITAL LETTER ER */ - {0x8452, 0x0000d0a1}, /* U+0421 CYRILLIC CAPITAL LETTER ES */ - {0x8453, 0x0000d0a2}, /* U+0422 CYRILLIC CAPITAL LETTER TE */ - {0x8454, 0x0000d0a3}, /* U+0423 CYRILLIC CAPITAL LETTER U */ - {0x8455, 0x0000d0a4}, /* U+0424 CYRILLIC CAPITAL LETTER EF */ - {0x8456, 0x0000d0a5}, /* U+0425 CYRILLIC CAPITAL LETTER HA */ - {0x8457, 0x0000d0a6}, /* U+0426 CYRILLIC CAPITAL LETTER TSE */ - {0x8458, 0x0000d0a7}, /* U+0427 CYRILLIC CAPITAL LETTER CHE */ - {0x8459, 0x0000d0a8}, /* U+0428 CYRILLIC CAPITAL LETTER SHA */ - {0x845a, 0x0000d0a9}, /* U+0429 CYRILLIC CAPITAL LETTER SHCHA */ - {0x845b, 0x0000d0aa}, /* U+042A CYRILLIC CAPITAL LETTER HARD SIGN */ - {0x845c, 0x0000d0ab}, /* U+042B CYRILLIC CAPITAL LETTER YERU */ - {0x845d, 0x0000d0ac}, /* U+042C CYRILLIC CAPITAL LETTER SOFT SIGN */ - {0x845e, 0x0000d0ad}, /* U+042D CYRILLIC CAPITAL LETTER E */ - {0x845f, 0x0000d0ae}, /* U+042E CYRILLIC CAPITAL LETTER YU */ - {0x8460, 0x0000d0af}, /* U+042F CYRILLIC CAPITAL LETTER YA */ - {0x8461, 0x00e28ebe}, /* U+23BE DENTISTRY SYMBOL LIGHT VERTICAL AND TOP RIGHT [2000] [Unicode3.2] */ - {0x8462, 0x00e28ebf}, /* U+23BF DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM RIGHT [2000] [Unicode3.2] */ - {0x8463, 0x00e28f80}, /* U+23C0 DENTISTRY SYMBOL LIGHT VERTICAL WITH CIRCLE [2000] [Unicode3.2] */ - {0x8464, 0x00e28f81}, /* U+23C1 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH CIRCLE [2000] [Unicode3.2] */ - {0x8465, 0x00e28f82}, /* U+23C2 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLE [2000] [Unicode3.2] */ - {0x8466, 0x00e28f83}, /* U+23C3 DENTISTRY SYMBOL LIGHT VERTICAL WITH TRIANGLE [2000] [Unicode3.2] */ - {0x8467, 0x00e28f84}, /* U+23C4 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH TRIANGLE [2000] [Unicode3.2] */ - {0x8468, 0x00e28f85}, /* U+23C5 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH TRIANGLE [2000] [Unicode3.2] */ - {0x8469, 0x00e28f86}, /* U+23C6 DENTISTRY SYMBOL LIGHT VERTICAL AND WAVE [2000] [Unicode3.2] */ - {0x846a, 0x00e28f87}, /* U+23C7 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH WAVE [2000] [Unicode3.2] */ - {0x846b, 0x00e28f88}, /* U+23C8 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH WAVE [2000] [Unicode3.2] */ - {0x846c, 0x00e28f89}, /* U+23C9 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL [2000] [Unicode3.2] */ - {0x846d, 0x00e28f8a}, /* U+23CA DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL [2000] [Unicode3.2] */ - {0x846e, 0x00e28f8b}, /* U+23CB DENTISTRY SYMBOL LIGHT VERTICAL AND TOP LEFT [2000] [Unicode3.2] */ - {0x846f, 0x00e28f8c}, /* U+23CC DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM LEFT [2000] [Unicode3.2] */ - {0x8470, 0x0000d0b0}, /* U+0430 CYRILLIC SMALL LETTER A */ - {0x8471, 0x0000d0b1}, /* U+0431 CYRILLIC SMALL LETTER BE */ - {0x8472, 0x0000d0b2}, /* U+0432 CYRILLIC SMALL LETTER VE */ - {0x8473, 0x0000d0b3}, /* U+0433 CYRILLIC SMALL LETTER GHE */ - {0x8474, 0x0000d0b4}, /* U+0434 CYRILLIC SMALL LETTER DE */ - {0x8475, 0x0000d0b5}, /* U+0435 CYRILLIC SMALL LETTER IE */ - {0x8476, 0x0000d191}, /* U+0451 CYRILLIC SMALL LETTER IO */ - {0x8477, 0x0000d0b6}, /* U+0436 CYRILLIC SMALL LETTER ZHE */ - {0x8478, 0x0000d0b7}, /* U+0437 CYRILLIC SMALL LETTER ZE */ - {0x8479, 0x0000d0b8}, /* U+0438 CYRILLIC SMALL LETTER I */ - {0x847a, 0x0000d0b9}, /* U+0439 CYRILLIC SMALL LETTER SHORT I */ - {0x847b, 0x0000d0ba}, /* U+043A CYRILLIC SMALL LETTER KA */ - {0x847c, 0x0000d0bb}, /* U+043B CYRILLIC SMALL LETTER EL */ - {0x847d, 0x0000d0bc}, /* U+043C CYRILLIC SMALL LETTER EM */ - {0x847e, 0x0000d0bd}, /* U+043D CYRILLIC SMALL LETTER EN */ - {0x8480, 0x0000d0be}, /* U+043E CYRILLIC SMALL LETTER O */ - {0x8481, 0x0000d0bf}, /* U+043F CYRILLIC SMALL LETTER PE */ - {0x8482, 0x0000d180}, /* U+0440 CYRILLIC SMALL LETTER ER */ - {0x8483, 0x0000d181}, /* U+0441 CYRILLIC SMALL LETTER ES */ - {0x8484, 0x0000d182}, /* U+0442 CYRILLIC SMALL LETTER TE */ - {0x8485, 0x0000d183}, /* U+0443 CYRILLIC SMALL LETTER U */ - {0x8486, 0x0000d184}, /* U+0444 CYRILLIC SMALL LETTER EF */ - {0x8487, 0x0000d185}, /* U+0445 CYRILLIC SMALL LETTER HA */ - {0x8488, 0x0000d186}, /* U+0446 CYRILLIC SMALL LETTER TSE */ - {0x8489, 0x0000d187}, /* U+0447 CYRILLIC SMALL LETTER CHE */ - {0x848a, 0x0000d188}, /* U+0448 CYRILLIC SMALL LETTER SHA */ - {0x848b, 0x0000d189}, /* U+0449 CYRILLIC SMALL LETTER SHCHA */ - {0x848c, 0x0000d18a}, /* U+044A CYRILLIC SMALL LETTER HARD SIGN */ - {0x848d, 0x0000d18b}, /* U+044B CYRILLIC SMALL LETTER YERU */ - {0x848e, 0x0000d18c}, /* U+044C CYRILLIC SMALL LETTER SOFT SIGN */ - {0x848f, 0x0000d18d}, /* U+044D CYRILLIC SMALL LETTER E */ - {0x8490, 0x0000d18e}, /* U+044E CYRILLIC SMALL LETTER YU */ - {0x8491, 0x0000d18f}, /* U+044F CYRILLIC SMALL LETTER YA */ - {0x8492, 0x00e383b7}, /* U+30F7 KATAKANA LETTER VA [2000] */ - {0x8493, 0x00e383b8}, /* U+30F8 KATAKANA LETTER VI [2000] */ - {0x8494, 0x00e383b9}, /* U+30F9 KATAKANA LETTER VE [2000] */ - {0x8495, 0x00e383ba}, /* U+30FA KATAKANA LETTER VO [2000] */ - {0x8496, 0x00e28b9a}, /* U+22DA LESS-THAN EQUAL TO OR GREATER-THAN [2000] */ - {0x8497, 0x00e28b9b}, /* U+22DB GREATER-THAN EQUAL TO OR LESS-THAN [2000] */ - {0x8498, 0x00e28593}, /* U+2153 VULGAR FRACTION ONE THIRD [2000] */ - {0x8499, 0x00e28594}, /* U+2154 VULGAR FRACTION TWO THIRDS [2000] */ - {0x849a, 0x00e28595}, /* U+2155 VULGAR FRACTION ONE FIFTH [2000] */ - {0x849b, 0x00e29c93}, /* U+2713 CHECK MARK [2000] */ - {0x849c, 0x00e28c98}, /* U+2318 PLACE OF INTEREST SIGN [2000] */ - {0x849d, 0x00e290a3}, /* U+2423 OPEN BOX [2000] */ - {0x849e, 0x00e28f8e}, /* U+23CE RETURN SYMBOL [2000] [Unicode3.2] */ - {0x849f, 0x00e29480}, /* U+2500 BOX DRAWINGS LIGHT HORIZONTAL [1983] */ - {0x84a0, 0x00e29482}, /* U+2502 BOX DRAWINGS LIGHT VERTICAL [1983] */ - {0x84a1, 0x00e2948c}, /* U+250C BOX DRAWINGS LIGHT DOWN AND RIGHT [1983] */ - {0x84a2, 0x00e29490}, /* U+2510 BOX DRAWINGS LIGHT DOWN AND LEFT [1983] */ - {0x84a3, 0x00e29498}, /* U+2518 BOX DRAWINGS LIGHT UP AND LEFT [1983] */ - {0x84a4, 0x00e29494}, /* U+2514 BOX DRAWINGS LIGHT UP AND RIGHT [1983] */ - {0x84a5, 0x00e2949c}, /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT [1983] */ - {0x84a6, 0x00e294ac}, /* U+252C BOX DRAWINGS LIGHT DOWN AND HORIZONTAL [1983] */ - {0x84a7, 0x00e294a4}, /* U+2524 BOX DRAWINGS LIGHT VERTICAL AND LEFT [1983] */ - {0x84a8, 0x00e294b4}, /* U+2534 BOX DRAWINGS LIGHT UP AND HORIZONTAL [1983] */ - {0x84a9, 0x00e294bc}, /* U+253C BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL [1983] */ - {0x84aa, 0x00e29481}, /* U+2501 BOX DRAWINGS HEAVY HORIZONTAL [1983] */ - {0x84ab, 0x00e29483}, /* U+2503 BOX DRAWINGS HEAVY VERTICAL [1983] */ - {0x84ac, 0x00e2948f}, /* U+250F BOX DRAWINGS HEAVY DOWN AND RIGHT [1983] */ - {0x84ad, 0x00e29493}, /* U+2513 BOX DRAWINGS HEAVY DOWN AND LEFT [1983] */ - {0x84ae, 0x00e2949b}, /* U+251B BOX DRAWINGS HEAVY UP AND LEFT [1983] */ - {0x84af, 0x00e29497}, /* U+2517 BOX DRAWINGS HEAVY UP AND RIGHT [1983] */ - {0x84b0, 0x00e294a3}, /* U+2523 BOX DRAWINGS HEAVY VERTICAL AND RIGHT [1983] */ - {0x84b1, 0x00e294b3}, /* U+2533 BOX DRAWINGS HEAVY DOWN AND HORIZONTAL [1983] */ - {0x84b2, 0x00e294ab}, /* U+252B BOX DRAWINGS HEAVY VERTICAL AND LEFT [1983] */ - {0x84b3, 0x00e294bb}, /* U+253B BOX DRAWINGS HEAVY UP AND HORIZONTAL [1983] */ - {0x84b4, 0x00e2958b}, /* U+254B BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL [1983] */ - {0x84b5, 0x00e294a0}, /* U+2520 BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT [1983] */ - {0x84b6, 0x00e294af}, /* U+252F BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY [1983] */ - {0x84b7, 0x00e294a8}, /* U+2528 BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT [1983] */ - {0x84b8, 0x00e294b7}, /* U+2537 BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY [1983] */ - {0x84b9, 0x00e294bf}, /* U+253F BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY [1983] */ - {0x84ba, 0x00e2949d}, /* U+251D BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY [1983] */ - {0x84bb, 0x00e294b0}, /* U+2530 BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT [1983] */ - {0x84bc, 0x00e294a5}, /* U+2525 BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY [1983] */ - {0x84bd, 0x00e294b8}, /* U+2538 BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT [1983] */ - {0x84be, 0x00e29582}, /* U+2542 BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT [1983] */ - {0x84bf, 0x00e38991}, /* U+3251 CIRCLED NUMBER TWENTY ONE [2000] [Unicode3.2] */ - {0x84c0, 0x00e38992}, /* U+3252 CIRCLED NUMBER TWENTY TWO [2000] [Unicode3.2] */ - {0x84c1, 0x00e38993}, /* U+3253 CIRCLED NUMBER TWENTY THREE [2000] [Unicode3.2] */ - {0x84c2, 0x00e38994}, /* U+3254 CIRCLED NUMBER TWENTY FOUR [2000] [Unicode3.2] */ - {0x84c3, 0x00e38995}, /* U+3255 CIRCLED NUMBER TWENTY FIVE [2000] [Unicode3.2] */ - {0x84c4, 0x00e38996}, /* U+3256 CIRCLED NUMBER TWENTY SIX [2000] [Unicode3.2] */ - {0x84c5, 0x00e38997}, /* U+3257 CIRCLED NUMBER TWENTY SEVEN [2000] [Unicode3.2] */ - {0x84c6, 0x00e38998}, /* U+3258 CIRCLED NUMBER TWENTY EIGHT [2000] [Unicode3.2] */ - {0x84c7, 0x00e38999}, /* U+3259 CIRCLED NUMBER TWENTY NINE [2000] [Unicode3.2] */ - {0x84c8, 0x00e3899a}, /* U+325A CIRCLED NUMBER THIRTY [2000] [Unicode3.2] */ - {0x84c9, 0x00e3899b}, /* U+325B CIRCLED NUMBER THIRTY ONE [2000] [Unicode3.2] */ - {0x84ca, 0x00e3899c}, /* U+325C CIRCLED NUMBER THIRTY TWO [2000] [Unicode3.2] */ - {0x84cb, 0x00e3899d}, /* U+325D CIRCLED NUMBER THIRTY THREE [2000] [Unicode3.2] */ - {0x84cc, 0x00e3899e}, /* U+325E CIRCLED NUMBER THIRTY FOUR [2000] [Unicode3.2] */ - {0x84cd, 0x00e3899f}, /* U+325F CIRCLED NUMBER THIRTY FIVE [2000] [Unicode3.2] */ - {0x84ce, 0x00e38ab1}, /* U+32B1 CIRCLED NUMBER THIRTY SIX [2000] [Unicode3.2] */ - {0x84cf, 0x00e38ab2}, /* U+32B2 CIRCLED NUMBER THIRTY SEVEN [2000] [Unicode3.2] */ - {0x84d0, 0x00e38ab3}, /* U+32B3 CIRCLED NUMBER THIRTY EIGHT [2000] [Unicode3.2] */ - {0x84d1, 0x00e38ab4}, /* U+32B4 CIRCLED NUMBER THIRTY NINE [2000] [Unicode3.2] */ - {0x84d2, 0x00e38ab5}, /* U+32B5 CIRCLED NUMBER FORTY [2000] [Unicode3.2] */ - {0x84d3, 0x00e38ab6}, /* U+32B6 CIRCLED NUMBER FORTY ONE [2000] [Unicode3.2] */ - {0x84d4, 0x00e38ab7}, /* U+32B7 CIRCLED NUMBER FORTY TWO [2000] [Unicode3.2] */ - {0x84d5, 0x00e38ab8}, /* U+32B8 CIRCLED NUMBER FORTY THREE [2000] [Unicode3.2] */ - {0x84d6, 0x00e38ab9}, /* U+32B9 CIRCLED NUMBER FORTY FOUR [2000] [Unicode3.2] */ - {0x84d7, 0x00e38aba}, /* U+32BA CIRCLED NUMBER FORTY FIVE [2000] [Unicode3.2] */ - {0x84d8, 0x00e38abb}, /* U+32BB CIRCLED NUMBER FORTY SIX [2000] [Unicode3.2] */ - {0x84d9, 0x00e38abc}, /* U+32BC CIRCLED NUMBER FORTY SEVEN [2000] [Unicode3.2] */ - {0x84da, 0x00e38abd}, /* U+32BD CIRCLED NUMBER FORTY EIGHT [2000] [Unicode3.2] */ - {0x84db, 0x00e38abe}, /* U+32BE CIRCLED NUMBER FORTY NINE [2000] [Unicode3.2] */ - {0x84dc, 0x00e38abf}, /* U+32BF CIRCLED NUMBER FIFTY [2000] [Unicode3.2] */ - {0x84e5, 0x00e29790}, /* U+25D0 CIRCLE WITH LEFT HALF BLACK [2000] */ - {0x84e6, 0x00e29791}, /* U+25D1 CIRCLE WITH RIGHT HALF BLACK [2000] */ - {0x84e7, 0x00e29792}, /* U+25D2 CIRCLE WITH LOWER HALF BLACK [2000] */ - {0x84e8, 0x00e29793}, /* U+25D3 CIRCLE WITH UPPER HALF BLACK [2000] */ - {0x84e9, 0x00e280bc}, /* U+203C DOUBLE EXCLAMATION MARK [2000] */ - {0x84ea, 0x00e28187}, /* U+2047 DOUBLE QUESTION MARK [2000] [Unicode3.2] */ - {0x84eb, 0x00e28188}, /* U+2048 QUESTION EXCLAMATION MARK [2000] */ - {0x84ec, 0x00e28189}, /* U+2049 EXCLAMATION QUESTION MARK [2000] */ - {0x84ed, 0x0000c78d}, /* U+01CD LATIN CAPITAL LETTER A WITH CARON [2000] */ - {0x84ee, 0x0000c78e}, /* U+01CE LATIN SMALL LETTER A WITH CARON [2000] */ - {0x84ef, 0x0000c790}, /* U+01D0 LATIN SMALL LETTER I WITH CARON [2000] */ - {0x84f0, 0x00e1b8be}, /* U+1E3E LATIN CAPITAL LETTER M WITH ACUTE [2000] */ - {0x84f1, 0x00e1b8bf}, /* U+1E3F LATIN SMALL LETTER M WITH ACUTE [2000] */ - {0x84f2, 0x0000c7b8}, /* U+01F8 LATIN CAPITAL LETTER N WITH GRAVE [2000] */ - {0x84f3, 0x0000c7b9}, /* U+01F9 LATIN SMALL LETTER N WITH GRAVE [2000] */ - {0x84f4, 0x0000c791}, /* U+01D1 LATIN CAPITAL LETTER O WITH CARON [2000] */ - {0x84f5, 0x0000c792}, /* U+01D2 LATIN SMALL LETTER O WITH CARON [2000] */ - {0x84f6, 0x0000c794}, /* U+01D4 LATIN SMALL LETTER U WITH CARON [2000] */ - {0x84f7, 0x0000c796}, /* U+01D6 LATIN SMALL LETTER U WITH DIAERESIS AND MACRON [2000] */ - {0x84f8, 0x0000c798}, /* U+01D8 LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE [2000] */ - {0x84f9, 0x0000c79a}, /* U+01DA LATIN SMALL LETTER U WITH DIAERESIS AND CARON [2000] */ - {0x84fa, 0x0000c79c}, /* U+01DC LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE [2000] */ - {0x8540, 0x00e282ac}, /* U+20AC EURO SIGN [2000] */ - {0x8541, 0x0000c2a0}, /* U+00A0 NO-BREAK SPACE [2000] */ - {0x8542, 0x0000c2a1}, /* U+00A1 INVERTED EXCLAMATION MARK [2000] */ - {0x8543, 0x0000c2a4}, /* U+00A4 CURRENCY SIGN [2000] */ - {0x8544, 0x0000c2a6}, /* U+00A6 BROKEN BAR [2000] */ - {0x8545, 0x0000c2a9}, /* U+00A9 COPYRIGHT SIGN [2000] */ - {0x8546, 0x0000c2aa}, /* U+00AA FEMININE ORDINAL INDICATOR [2000] */ - {0x8547, 0x0000c2ab}, /* U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK [2000] */ - {0x8548, 0x0000c2ad}, /* U+00AD SOFT HYPHEN [2000] */ - {0x8549, 0x0000c2ae}, /* U+00AE REGISTERED SIGN [2000] */ - {0x854a, 0x0000c2af}, /* U+00AF MACRON [2000] */ - {0x854b, 0x0000c2b2}, /* U+00B2 SUPERSCRIPT TWO [2000] */ - {0x854c, 0x0000c2b3}, /* U+00B3 SUPERSCRIPT THREE [2000] */ - {0x854d, 0x0000c2b7}, /* U+00B7 MIDDLE DOT [2000] */ - {0x854e, 0x0000c2b8}, /* U+00B8 CEDILLA [2000] */ - {0x854f, 0x0000c2b9}, /* U+00B9 SUPERSCRIPT ONE [2000] */ - {0x8550, 0x0000c2ba}, /* U+00BA MASCULINE ORDINAL INDICATOR [2000] */ - {0x8551, 0x0000c2bb}, /* U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK [2000] */ - {0x8552, 0x0000c2bc}, /* U+00BC VULGAR FRACTION ONE QUARTER [2000] */ - {0x8553, 0x0000c2bd}, /* U+00BD VULGAR FRACTION ONE HALF [2000] */ - {0x8554, 0x0000c2be}, /* U+00BE VULGAR FRACTION THREE QUARTERS [2000] */ - {0x8555, 0x0000c2bf}, /* U+00BF INVERTED QUESTION MARK [2000] */ - {0x8556, 0x0000c380}, /* U+00C0 LATIN CAPITAL LETTER A WITH GRAVE [2000] */ - {0x8557, 0x0000c381}, /* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE [2000] */ - {0x8558, 0x0000c382}, /* U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX [2000] */ - {0x8559, 0x0000c383}, /* U+00C3 LATIN CAPITAL LETTER A WITH TILDE [2000] */ - {0x855a, 0x0000c384}, /* U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS [2000] */ - {0x855b, 0x0000c385}, /* U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE [2000] */ - {0x855c, 0x0000c386}, /* U+00C6 LATIN CAPITAL LETTER AE [2000] */ - {0x855d, 0x0000c387}, /* U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA [2000] */ - {0x855e, 0x0000c388}, /* U+00C8 LATIN CAPITAL LETTER E WITH GRAVE [2000] */ - {0x855f, 0x0000c389}, /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE [2000] */ - {0x8560, 0x0000c38a}, /* U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX [2000] */ - {0x8561, 0x0000c38b}, /* U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS [2000] */ - {0x8562, 0x0000c38c}, /* U+00CC LATIN CAPITAL LETTER I WITH GRAVE [2000] */ - {0x8563, 0x0000c38d}, /* U+00CD LATIN CAPITAL LETTER I WITH ACUTE [2000] */ - {0x8564, 0x0000c38e}, /* U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX [2000] */ - {0x8565, 0x0000c38f}, /* U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS [2000] */ - {0x8566, 0x0000c390}, /* U+00D0 LATIN CAPITAL LETTER ETH [2000] */ - {0x8567, 0x0000c391}, /* U+00D1 LATIN CAPITAL LETTER N WITH TILDE [2000] */ - {0x8568, 0x0000c392}, /* U+00D2 LATIN CAPITAL LETTER O WITH GRAVE [2000] */ - {0x8569, 0x0000c393}, /* U+00D3 LATIN CAPITAL LETTER O WITH ACUTE [2000] */ - {0x856a, 0x0000c394}, /* U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX [2000] */ - {0x856b, 0x0000c395}, /* U+00D5 LATIN CAPITAL LETTER O WITH TILDE [2000] */ - {0x856c, 0x0000c396}, /* U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS [2000] */ - {0x856d, 0x0000c398}, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE [2000] */ - {0x856e, 0x0000c399}, /* U+00D9 LATIN CAPITAL LETTER U WITH GRAVE [2000] */ - {0x856f, 0x0000c39a}, /* U+00DA LATIN CAPITAL LETTER U WITH ACUTE [2000] */ - {0x8570, 0x0000c39b}, /* U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX [2000] */ - {0x8571, 0x0000c39c}, /* U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS [2000] */ - {0x8572, 0x0000c39d}, /* U+00DD LATIN CAPITAL LETTER Y WITH ACUTE [2000] */ - {0x8573, 0x0000c39e}, /* U+00DE LATIN CAPITAL LETTER THORN [2000] */ - {0x8574, 0x0000c39f}, /* U+00DF LATIN SMALL LETTER SHARP S [2000] */ - {0x8575, 0x0000c3a0}, /* U+00E0 LATIN SMALL LETTER A WITH GRAVE [2000] */ - {0x8576, 0x0000c3a1}, /* U+00E1 LATIN SMALL LETTER A WITH ACUTE [2000] */ - {0x8577, 0x0000c3a2}, /* U+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX [2000] */ - {0x8578, 0x0000c3a3}, /* U+00E3 LATIN SMALL LETTER A WITH TILDE [2000] */ - {0x8579, 0x0000c3a4}, /* U+00E4 LATIN SMALL LETTER A WITH DIAERESIS [2000] */ - {0x857a, 0x0000c3a5}, /* U+00E5 LATIN SMALL LETTER A WITH RING ABOVE [2000] */ - {0x857b, 0x0000c3a6}, /* U+00E6 LATIN SMALL LETTER AE [2000] */ - {0x857c, 0x0000c3a7}, /* U+00E7 LATIN SMALL LETTER C WITH CEDILLA [2000] */ - {0x857d, 0x0000c3a8}, /* U+00E8 LATIN SMALL LETTER E WITH GRAVE [2000] */ - {0x857e, 0x0000c3a9}, /* U+00E9 LATIN SMALL LETTER E WITH ACUTE [2000] */ - {0x8580, 0x0000c3aa}, /* U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX [2000] */ - {0x8581, 0x0000c3ab}, /* U+00EB LATIN SMALL LETTER E WITH DIAERESIS [2000] */ - {0x8582, 0x0000c3ac}, /* U+00EC LATIN SMALL LETTER I WITH GRAVE [2000] */ - {0x8583, 0x0000c3ad}, /* U+00ED LATIN SMALL LETTER I WITH ACUTE [2000] */ - {0x8584, 0x0000c3ae}, /* U+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX [2000] */ - {0x8585, 0x0000c3af}, /* U+00EF LATIN SMALL LETTER I WITH DIAERESIS [2000] */ - {0x8586, 0x0000c3b0}, /* U+00F0 LATIN SMALL LETTER ETH [2000] */ - {0x8587, 0x0000c3b1}, /* U+00F1 LATIN SMALL LETTER N WITH TILDE [2000] */ - {0x8588, 0x0000c3b2}, /* U+00F2 LATIN SMALL LETTER O WITH GRAVE [2000] */ - {0x8589, 0x0000c3b3}, /* U+00F3 LATIN SMALL LETTER O WITH ACUTE [2000] */ - {0x858a, 0x0000c3b4}, /* U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX [2000] */ - {0x858b, 0x0000c3b5}, /* U+00F5 LATIN SMALL LETTER O WITH TILDE [2000] */ - {0x858c, 0x0000c3b6}, /* U+00F6 LATIN SMALL LETTER O WITH DIAERESIS [2000] */ - {0x858d, 0x0000c3b8}, /* U+00F8 LATIN SMALL LETTER O WITH STROKE [2000] */ - {0x858e, 0x0000c3b9}, /* U+00F9 LATIN SMALL LETTER U WITH GRAVE [2000] */ - {0x858f, 0x0000c3ba}, /* U+00FA LATIN SMALL LETTER U WITH ACUTE [2000] */ - {0x8590, 0x0000c3bb}, /* U+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX [2000] */ - {0x8591, 0x0000c3bc}, /* U+00FC LATIN SMALL LETTER U WITH DIAERESIS [2000] */ - {0x8592, 0x0000c3bd}, /* U+00FD LATIN SMALL LETTER Y WITH ACUTE [2000] */ - {0x8593, 0x0000c3be}, /* U+00FE LATIN SMALL LETTER THORN [2000] */ - {0x8594, 0x0000c3bf}, /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS [2000] */ - {0x8595, 0x0000c480}, /* U+0100 LATIN CAPITAL LETTER A WITH MACRON [2000] */ - {0x8596, 0x0000c4aa}, /* U+012A LATIN CAPITAL LETTER I WITH MACRON [2000] */ - {0x8597, 0x0000c5aa}, /* U+016A LATIN CAPITAL LETTER U WITH MACRON [2000] */ - {0x8598, 0x0000c492}, /* U+0112 LATIN CAPITAL LETTER E WITH MACRON [2000] */ - {0x8599, 0x0000c58c}, /* U+014C LATIN CAPITAL LETTER O WITH MACRON [2000] */ - {0x859a, 0x0000c481}, /* U+0101 LATIN SMALL LETTER A WITH MACRON [2000] */ - {0x859b, 0x0000c4ab}, /* U+012B LATIN SMALL LETTER I WITH MACRON [2000] */ - {0x859c, 0x0000c5ab}, /* U+016B LATIN SMALL LETTER U WITH MACRON [2000] */ - {0x859d, 0x0000c493}, /* U+0113 LATIN SMALL LETTER E WITH MACRON [2000] */ - {0x859e, 0x0000c58d}, /* U+014D LATIN SMALL LETTER O WITH MACRON [2000] */ - {0x859f, 0x0000c484}, /* U+0104 LATIN CAPITAL LETTER A WITH OGONEK [2000] */ - {0x85a0, 0x0000cb98}, /* U+02D8 BREVE [2000] */ - {0x85a1, 0x0000c581}, /* U+0141 LATIN CAPITAL LETTER L WITH STROKE [2000] */ - {0x85a2, 0x0000c4bd}, /* U+013D LATIN CAPITAL LETTER L WITH CARON [2000] */ - {0x85a3, 0x0000c59a}, /* U+015A LATIN CAPITAL LETTER S WITH ACUTE [2000] */ - {0x85a4, 0x0000c5a0}, /* U+0160 LATIN CAPITAL LETTER S WITH CARON [2000] */ - {0x85a5, 0x0000c59e}, /* U+015E LATIN CAPITAL LETTER S WITH CEDILLA [2000] */ - {0x85a6, 0x0000c5a4}, /* U+0164 LATIN CAPITAL LETTER T WITH CARON [2000] */ - {0x85a7, 0x0000c5b9}, /* U+0179 LATIN CAPITAL LETTER Z WITH ACUTE [2000] */ - {0x85a8, 0x0000c5bd}, /* U+017D LATIN CAPITAL LETTER Z WITH CARON [2000] */ - {0x85a9, 0x0000c5bb}, /* U+017B LATIN CAPITAL LETTER Z WITH DOT ABOVE [2000] */ - {0x85aa, 0x0000c485}, /* U+0105 LATIN SMALL LETTER A WITH OGONEK [2000] */ - {0x85ab, 0x0000cb9b}, /* U+02DB OGONEK [2000] */ - {0x85ac, 0x0000c582}, /* U+0142 LATIN SMALL LETTER L WITH STROKE [2000] */ - {0x85ad, 0x0000c4be}, /* U+013E LATIN SMALL LETTER L WITH CARON [2000] */ - {0x85ae, 0x0000c59b}, /* U+015B LATIN SMALL LETTER S WITH ACUTE [2000] */ - {0x85af, 0x0000cb87}, /* U+02C7 CARON [2000] */ - {0x85b0, 0x0000c5a1}, /* U+0161 LATIN SMALL LETTER S WITH CARON [2000] */ - {0x85b1, 0x0000c59f}, /* U+015F LATIN SMALL LETTER S WITH CEDILLA [2000] */ - {0x85b2, 0x0000c5a5}, /* U+0165 LATIN SMALL LETTER T WITH CARON [2000] */ - {0x85b3, 0x0000c5ba}, /* U+017A LATIN SMALL LETTER Z WITH ACUTE [2000] */ - {0x85b4, 0x0000cb9d}, /* U+02DD DOUBLE ACUTE ACCENT [2000] */ - {0x85b5, 0x0000c5be}, /* U+017E LATIN SMALL LETTER Z WITH CARON [2000] */ - {0x85b6, 0x0000c5bc}, /* U+017C LATIN SMALL LETTER Z WITH DOT ABOVE [2000] */ - {0x85b7, 0x0000c594}, /* U+0154 LATIN CAPITAL LETTER R WITH ACUTE [2000] */ - {0x85b8, 0x0000c482}, /* U+0102 LATIN CAPITAL LETTER A WITH BREVE [2000] */ - {0x85b9, 0x0000c4b9}, /* U+0139 LATIN CAPITAL LETTER L WITH ACUTE [2000] */ - {0x85ba, 0x0000c486}, /* U+0106 LATIN CAPITAL LETTER C WITH ACUTE [2000] */ - {0x85bb, 0x0000c48c}, /* U+010C LATIN CAPITAL LETTER C WITH CARON [2000] */ - {0x85bc, 0x0000c498}, /* U+0118 LATIN CAPITAL LETTER E WITH OGONEK [2000] */ - {0x85bd, 0x0000c49a}, /* U+011A LATIN CAPITAL LETTER E WITH CARON [2000] */ - {0x85be, 0x0000c48e}, /* U+010E LATIN CAPITAL LETTER D WITH CARON [2000] */ - {0x85bf, 0x0000c583}, /* U+0143 LATIN CAPITAL LETTER N WITH ACUTE [2000] */ - {0x85c0, 0x0000c587}, /* U+0147 LATIN CAPITAL LETTER N WITH CARON [2000] */ - {0x85c1, 0x0000c590}, /* U+0150 LATIN CAPITAL LETTER O WITH DOUBLE ACUTE [2000] */ - {0x85c2, 0x0000c598}, /* U+0158 LATIN CAPITAL LETTER R WITH CARON [2000] */ - {0x85c3, 0x0000c5ae}, /* U+016E LATIN CAPITAL LETTER U WITH RING ABOVE [2000] */ - {0x85c4, 0x0000c5b0}, /* U+0170 LATIN CAPITAL LETTER U WITH DOUBLE ACUTE [2000] */ - {0x85c5, 0x0000c5a2}, /* U+0162 LATIN CAPITAL LETTER T WITH CEDILLA [2000] */ - {0x85c6, 0x0000c595}, /* U+0155 LATIN SMALL LETTER R WITH ACUTE [2000] */ - {0x85c7, 0x0000c483}, /* U+0103 LATIN SMALL LETTER A WITH BREVE [2000] */ - {0x85c8, 0x0000c4ba}, /* U+013A LATIN SMALL LETTER L WITH ACUTE [2000] */ - {0x85c9, 0x0000c487}, /* U+0107 LATIN SMALL LETTER C WITH ACUTE [2000] */ - {0x85ca, 0x0000c48d}, /* U+010D LATIN SMALL LETTER C WITH CARON [2000] */ - {0x85cb, 0x0000c499}, /* U+0119 LATIN SMALL LETTER E WITH OGONEK [2000] */ - {0x85cc, 0x0000c49b}, /* U+011B LATIN SMALL LETTER E WITH CARON [2000] */ - {0x85cd, 0x0000c48f}, /* U+010F LATIN SMALL LETTER D WITH CARON [2000] */ - {0x85ce, 0x0000c491}, /* U+0111 LATIN SMALL LETTER D WITH STROKE [2000] */ - {0x85cf, 0x0000c584}, /* U+0144 LATIN SMALL LETTER N WITH ACUTE [2000] */ - {0x85d0, 0x0000c588}, /* U+0148 LATIN SMALL LETTER N WITH CARON [2000] */ - {0x85d1, 0x0000c591}, /* U+0151 LATIN SMALL LETTER O WITH DOUBLE ACUTE [2000] */ - {0x85d2, 0x0000c599}, /* U+0159 LATIN SMALL LETTER R WITH CARON [2000] */ - {0x85d3, 0x0000c5af}, /* U+016F LATIN SMALL LETTER U WITH RING ABOVE [2000] */ - {0x85d4, 0x0000c5b1}, /* U+0171 LATIN SMALL LETTER U WITH DOUBLE ACUTE [2000] */ - {0x85d5, 0x0000c5a3}, /* U+0163 LATIN SMALL LETTER T WITH CEDILLA [2000] */ - {0x85d6, 0x0000cb99}, /* U+02D9 DOT ABOVE [2000] */ - {0x85d7, 0x0000c488}, /* U+0108 LATIN CAPITAL LETTER C WITH CIRCUMFLEX [2000] */ - {0x85d8, 0x0000c49c}, /* U+011C LATIN CAPITAL LETTER G WITH CIRCUMFLEX [2000] */ - {0x85d9, 0x0000c4a4}, /* U+0124 LATIN CAPITAL LETTER H WITH CIRCUMFLEX [2000] */ - {0x85da, 0x0000c4b4}, /* U+0134 LATIN CAPITAL LETTER J WITH CIRCUMFLEX [2000] */ - {0x85db, 0x0000c59c}, /* U+015C LATIN CAPITAL LETTER S WITH CIRCUMFLEX [2000] */ - {0x85dc, 0x0000c5ac}, /* U+016C LATIN CAPITAL LETTER U WITH BREVE [2000] */ - {0x85dd, 0x0000c489}, /* U+0109 LATIN SMALL LETTER C WITH CIRCUMFLEX [2000] */ - {0x85de, 0x0000c49d}, /* U+011D LATIN SMALL LETTER G WITH CIRCUMFLEX [2000] */ - {0x85df, 0x0000c4a5}, /* U+0125 LATIN SMALL LETTER H WITH CIRCUMFLEX [2000] */ - {0x85e0, 0x0000c4b5}, /* U+0135 LATIN SMALL LETTER J WITH CIRCUMFLEX [2000] */ - {0x85e1, 0x0000c59d}, /* U+015D LATIN SMALL LETTER S WITH CIRCUMFLEX [2000] */ - {0x85e2, 0x0000c5ad}, /* U+016D LATIN SMALL LETTER U WITH BREVE [2000] */ - {0x85e3, 0x0000c9b1}, /* U+0271 LATIN SMALL LETTER M WITH HOOK [2000] */ - {0x85e4, 0x0000ca8b}, /* U+028B LATIN SMALL LETTER V WITH HOOK [2000] */ - {0x85e5, 0x0000c9be}, /* U+027E LATIN SMALL LETTER R WITH FISHHOOK [2000] */ - {0x85e6, 0x0000ca83}, /* U+0283 LATIN SMALL LETTER ESH [2000] */ - {0x85e7, 0x0000ca92}, /* U+0292 LATIN SMALL LETTER EZH [2000] */ - {0x85e8, 0x0000c9ac}, /* U+026C LATIN SMALL LETTER L WITH BELT [2000] */ - {0x85e9, 0x0000c9ae}, /* U+026E LATIN SMALL LETTER LEZH [2000] */ - {0x85ea, 0x0000c9b9}, /* U+0279 LATIN SMALL LETTER TURNED R [2000] */ - {0x85eb, 0x0000ca88}, /* U+0288 LATIN SMALL LETTER T WITH RETROFLEX HOOK [2000] */ - {0x85ec, 0x0000c996}, /* U+0256 LATIN SMALL LETTER D WITH TAIL [2000] */ - {0x85ed, 0x0000c9b3}, /* U+0273 LATIN SMALL LETTER N WITH RETROFLEX HOOK [2000] */ - {0x85ee, 0x0000c9bd}, /* U+027D LATIN SMALL LETTER R WITH TAIL [2000] */ - {0x85ef, 0x0000ca82}, /* U+0282 LATIN SMALL LETTER S WITH HOOK [2000] */ - {0x85f0, 0x0000ca90}, /* U+0290 LATIN SMALL LETTER Z WITH RETROFLEX HOOK [2000] */ - {0x85f1, 0x0000c9bb}, /* U+027B LATIN SMALL LETTER TURNED R WITH HOOK [2000] */ - {0x85f2, 0x0000c9ad}, /* U+026D LATIN SMALL LETTER L WITH RETROFLEX HOOK [2000] */ - {0x85f3, 0x0000c99f}, /* U+025F LATIN SMALL LETTER DOTLESS J WITH STROKE [2000] */ - {0x85f4, 0x0000c9b2}, /* U+0272 LATIN SMALL LETTER N WITH LEFT HOOK [2000] */ - {0x85f5, 0x0000ca9d}, /* U+029D LATIN SMALL LETTER J WITH CROSSED-TAIL [2000] */ - {0x85f6, 0x0000ca8e}, /* U+028E LATIN SMALL LETTER TURNED Y [2000] */ - {0x85f7, 0x0000c9a1}, /* U+0261 LATIN SMALL LETTER SCRIPT G [2000] */ - {0x85f8, 0x0000c58b}, /* U+014B LATIN SMALL LETTER ENG [2000] */ - {0x85f9, 0x0000c9b0}, /* U+0270 LATIN SMALL LETTER TURNED M WITH LONG LEG [2000] */ - {0x85fa, 0x0000ca81}, /* U+0281 LATIN LETTER SMALL CAPITAL INVERTED R [2000] */ - {0x85fb, 0x0000c4a7}, /* U+0127 LATIN SMALL LETTER H WITH STROKE [2000] */ - {0x85fc, 0x0000ca95}, /* U+0295 LATIN LETTER PHARYNGEAL VOICED FRICATIVE [2000] */ - {0x8640, 0x0000ca94}, /* U+0294 LATIN LETTER GLOTTAL STOP [2000] */ - {0x8641, 0x0000c9a6}, /* U+0266 LATIN SMALL LETTER H WITH HOOK [2000] */ - {0x8642, 0x0000ca98}, /* U+0298 LATIN LETTER BILABIAL CLICK [2000] */ - {0x8643, 0x0000c782}, /* U+01C2 LATIN LETTER ALVEOLAR CLICK [2000] */ - {0x8644, 0x0000c993}, /* U+0253 LATIN SMALL LETTER B WITH HOOK [2000] */ - {0x8645, 0x0000c997}, /* U+0257 LATIN SMALL LETTER D WITH HOOK [2000] */ - {0x8646, 0x0000ca84}, /* U+0284 LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK [2000] */ - {0x8647, 0x0000c9a0}, /* U+0260 LATIN SMALL LETTER G WITH HOOK [2000] */ - {0x8648, 0x0000c693}, /* U+0193 LATIN CAPITAL LETTER G WITH HOOK [2000] */ - {0x8649, 0x0000c593}, /* U+0153 LATIN SMALL LIGATURE OE [2000] */ - {0x864a, 0x0000c592}, /* U+0152 LATIN CAPITAL LIGATURE OE [2000] */ - {0x864b, 0x0000c9a8}, /* U+0268 LATIN SMALL LETTER I WITH STROKE [2000] */ - {0x864c, 0x0000ca89}, /* U+0289 LATIN SMALL LETTER U BAR [2000] */ - {0x864d, 0x0000c998}, /* U+0258 LATIN SMALL LETTER REVERSED E [2000] */ - {0x864e, 0x0000c9b5}, /* U+0275 LATIN SMALL LETTER BARRED O [2000] */ - {0x864f, 0x0000c999}, /* U+0259 LATIN SMALL LETTER SCHWA [2000] */ - {0x8650, 0x0000c99c}, /* U+025C LATIN SMALL LETTER REVERSED OPEN E [2000] */ - {0x8651, 0x0000c99e}, /* U+025E LATIN SMALL LETTER CLOSED REVERSED OPEN E [2000] */ - {0x8652, 0x0000c990}, /* U+0250 LATIN SMALL LETTER TURNED A [2000] */ - {0x8653, 0x0000c9af}, /* U+026F LATIN SMALL LETTER TURNED M [2000] */ - {0x8654, 0x0000ca8a}, /* U+028A LATIN SMALL LETTER UPSILON [2000] */ - {0x8655, 0x0000c9a4}, /* U+0264 LATIN SMALL LETTER RAMS HORN [2000] */ - {0x8656, 0x0000ca8c}, /* U+028C LATIN SMALL LETTER TURNED V [2000] */ - {0x8657, 0x0000c994}, /* U+0254 LATIN SMALL LETTER OPEN O [2000] */ - {0x8658, 0x0000c991}, /* U+0251 LATIN SMALL LETTER ALPHA [2000] */ - {0x8659, 0x0000c992}, /* U+0252 LATIN SMALL LETTER TURNED ALPHA [2000] */ - {0x865a, 0x0000ca8d}, /* U+028D LATIN SMALL LETTER TURNED W [2000] */ - {0x865b, 0x0000c9a5}, /* U+0265 LATIN SMALL LETTER TURNED H [2000] */ - {0x865c, 0x0000caa2}, /* U+02A2 LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE [2000] */ - {0x865d, 0x0000caa1}, /* U+02A1 LATIN LETTER GLOTTAL STOP WITH STROKE [2000] */ - {0x865e, 0x0000c995}, /* U+0255 LATIN SMALL LETTER C WITH CURL [2000] */ - {0x865f, 0x0000ca91}, /* U+0291 LATIN SMALL LETTER Z WITH CURL [2000] */ - {0x8660, 0x0000c9ba}, /* U+027A LATIN SMALL LETTER TURNED R WITH LONG LEG [2000] */ - {0x8661, 0x0000c9a7}, /* U+0267 LATIN SMALL LETTER HENG WITH HOOK [2000] */ - {0x8662, 0x0000c99a}, /* U+025A LATIN SMALL LETTER SCHWA WITH HOOK [2000] */ - {0x8664, 0x0000c7bd}, /* U+01FD LATIN SMALL LETTER AE WITH ACUTE [2000] */ - {0x8665, 0x00e1bdb0}, /* U+1F70 GREEK SMALL LETTER ALPHA WITH VARIA [2000] */ - {0x8666, 0x00e1bdb1}, /* U+1F71 GREEK SMALL LETTER ALPHA WITH OXIA [2000] */ - {0x866f, 0x00e1bdb2}, /* U+1F72 GREEK SMALL LETTER EPSILON WITH VARIA [2000] */ - {0x8670, 0x00e1bdb3}, /* U+1F73 GREEK SMALL LETTER EPSILON WITH OXIA [2000] */ - {0x8671, 0x0000cda1}, /* U+0361 COMBINING DOUBLE INVERTED BREVE [2000] */ - {0x8672, 0x0000cb88}, /* U+02C8 MODIFIER LETTER VERTICAL LINE [2000] */ - {0x8673, 0x0000cb8c}, /* U+02CC MODIFIER LETTER LOW VERTICAL LINE [2000] */ - {0x8674, 0x0000cb90}, /* U+02D0 MODIFIER LETTER TRIANGULAR COLON [2000] */ - {0x8675, 0x0000cb91}, /* U+02D1 MODIFIER LETTER HALF TRIANGULAR COLON [2000] */ - {0x8676, 0x0000cc86}, /* U+0306 COMBINING BREVE [2000] */ - {0x8677, 0x00e280bf}, /* U+203F UNDERTIE [2000] */ - {0x8678, 0x0000cc8b}, /* U+030B COMBINING DOUBLE ACUTE ACCENT [2000] */ - {0x8679, 0x0000cc81}, /* U+0301 COMBINING ACUTE ACCENT [2000] */ - {0x867a, 0x0000cc84}, /* U+0304 COMBINING MACRON [2000] */ - {0x867b, 0x0000cc80}, /* U+0300 COMBINING GRAVE ACCENT [2000] */ - {0x867c, 0x0000cc8f}, /* U+030F COMBINING DOUBLE GRAVE ACCENT [2000] */ - {0x867d, 0x0000cc8c}, /* U+030C COMBINING CARON [2000] */ - {0x867e, 0x0000cc82}, /* U+0302 COMBINING CIRCUMFLEX ACCENT [2000] */ - {0x8680, 0x0000cba5}, /* U+02E5 MODIFIER LETTER EXTRA-HIGH TONE BAR [2000] */ - {0x8681, 0x0000cba6}, /* U+02E6 MODIFIER LETTER HIGH TONE BAR [2000] */ - {0x8682, 0x0000cba7}, /* U+02E7 MODIFIER LETTER MID TONE BAR [2000] */ - {0x8683, 0x0000cba8}, /* U+02E8 MODIFIER LETTER LOW TONE BAR [2000] */ - {0x8684, 0x0000cba9}, /* U+02E9 MODIFIER LETTER EXTRA-LOW TONE BAR [2000] */ - {0x8687, 0x0000cca5}, /* U+0325 COMBINING RING BELOW [2000] */ - {0x8688, 0x0000ccac}, /* U+032C COMBINING CARON BELOW [2000] */ - {0x8689, 0x0000ccb9}, /* U+0339 COMBINING RIGHT HALF RING BELOW [2000] */ - {0x868a, 0x0000cc9c}, /* U+031C COMBINING LEFT HALF RING BELOW [2000] */ - {0x868b, 0x0000cc9f}, /* U+031F COMBINING PLUS SIGN BELOW [2000] */ - {0x868c, 0x0000cca0}, /* U+0320 COMBINING MINUS SIGN BELOW [2000] */ - {0x868d, 0x0000cc88}, /* U+0308 COMBINING DIAERESIS [2000] */ - {0x868e, 0x0000ccbd}, /* U+033D COMBINING X ABOVE [2000] */ - {0x868f, 0x0000cca9}, /* U+0329 COMBINING VERTICAL LINE BELOW [2000] */ - {0x8690, 0x0000ccaf}, /* U+032F COMBINING INVERTED BREVE BELOW [2000] */ - {0x8691, 0x0000cb9e}, /* U+02DE MODIFIER LETTER RHOTIC HOOK [2000] */ - {0x8692, 0x0000cca4}, /* U+0324 COMBINING DIAERESIS BELOW [2000] */ - {0x8693, 0x0000ccb0}, /* U+0330 COMBINING TILDE BELOW [2000] */ - {0x8694, 0x0000ccbc}, /* U+033C COMBINING SEAGULL BELOW [2000] */ - {0x8695, 0x0000ccb4}, /* U+0334 COMBINING TILDE OVERLAY [2000] */ - {0x8696, 0x0000cc9d}, /* U+031D COMBINING UP TACK BELOW [2000] */ - {0x8697, 0x0000cc9e}, /* U+031E COMBINING DOWN TACK BELOW [2000] */ - {0x8698, 0x0000cc98}, /* U+0318 COMBINING LEFT TACK BELOW [2000] */ - {0x8699, 0x0000cc99}, /* U+0319 COMBINING RIGHT TACK BELOW [2000] */ - {0x869a, 0x0000ccaa}, /* U+032A COMBINING BRIDGE BELOW [2000] */ - {0x869b, 0x0000ccba}, /* U+033A COMBINING INVERTED BRIDGE BELOW [2000] */ - {0x869c, 0x0000ccbb}, /* U+033B COMBINING SQUARE BELOW [2000] */ - {0x869d, 0x0000cc83}, /* U+0303 COMBINING TILDE [2000] */ - {0x869e, 0x0000cc9a}, /* U+031A COMBINING LEFT ANGLE ABOVE [2000] */ - {0x869f, 0x00e29db6}, /* U+2776 DINGBAT NEGATIVE CIRCLED DIGIT ONE [2000] */ - {0x86a0, 0x00e29db7}, /* U+2777 DINGBAT NEGATIVE CIRCLED DIGIT TWO [2000] */ - {0x86a1, 0x00e29db8}, /* U+2778 DINGBAT NEGATIVE CIRCLED DIGIT THREE [2000] */ - {0x86a2, 0x00e29db9}, /* U+2779 DINGBAT NEGATIVE CIRCLED DIGIT FOUR [2000] */ - {0x86a3, 0x00e29dba}, /* U+277A DINGBAT NEGATIVE CIRCLED DIGIT FIVE [2000] */ - {0x86a4, 0x00e29dbb}, /* U+277B DINGBAT NEGATIVE CIRCLED DIGIT SIX [2000] */ - {0x86a5, 0x00e29dbc}, /* U+277C DINGBAT NEGATIVE CIRCLED DIGIT SEVEN [2000] */ - {0x86a6, 0x00e29dbd}, /* U+277D DINGBAT NEGATIVE CIRCLED DIGIT EIGHT [2000] */ - {0x86a7, 0x00e29dbe}, /* U+277E DINGBAT NEGATIVE CIRCLED DIGIT NINE [2000] */ - {0x86a8, 0x00e29dbf}, /* U+277F DINGBAT NEGATIVE CIRCLED NUMBER TEN [2000] */ - {0x86a9, 0x00e293ab}, /* U+24EB NEGATIVE CIRCLED NUMBER ELEVEN [2000] [Unicode3.2] */ - {0x86aa, 0x00e293ac}, /* U+24EC NEGATIVE CIRCLED NUMBER TWELVE [2000] [Unicode3.2] */ - {0x86ab, 0x00e293ad}, /* U+24ED NEGATIVE CIRCLED NUMBER THIRTEEN [2000] [Unicode3.2] */ - {0x86ac, 0x00e293ae}, /* U+24EE NEGATIVE CIRCLED NUMBER FOURTEEN [2000] [Unicode3.2] */ - {0x86ad, 0x00e293af}, /* U+24EF NEGATIVE CIRCLED NUMBER FIFTEEN [2000] [Unicode3.2] */ - {0x86ae, 0x00e293b0}, /* U+24F0 NEGATIVE CIRCLED NUMBER SIXTEEN [2000] [Unicode3.2] */ - {0x86af, 0x00e293b1}, /* U+24F1 NEGATIVE CIRCLED NUMBER SEVENTEEN [2000] [Unicode3.2] */ - {0x86b0, 0x00e293b2}, /* U+24F2 NEGATIVE CIRCLED NUMBER EIGHTEEN [2000] [Unicode3.2] */ - {0x86b1, 0x00e293b3}, /* U+24F3 NEGATIVE CIRCLED NUMBER NINETEEN [2000] [Unicode3.2] */ - {0x86b2, 0x00e293b4}, /* U+24F4 NEGATIVE CIRCLED NUMBER TWENTY [2000] [Unicode3.2] */ - {0x86b3, 0x00e285b0}, /* U+2170 SMALL ROMAN NUMERAL ONE [2000] */ - {0x86b4, 0x00e285b1}, /* U+2171 SMALL ROMAN NUMERAL TWO [2000] */ - {0x86b5, 0x00e285b2}, /* U+2172 SMALL ROMAN NUMERAL THREE [2000] */ - {0x86b6, 0x00e285b3}, /* U+2173 SMALL ROMAN NUMERAL FOUR [2000] */ - {0x86b7, 0x00e285b4}, /* U+2174 SMALL ROMAN NUMERAL FIVE [2000] */ - {0x86b8, 0x00e285b5}, /* U+2175 SMALL ROMAN NUMERAL SIX [2000] */ - {0x86b9, 0x00e285b6}, /* U+2176 SMALL ROMAN NUMERAL SEVEN [2000] */ - {0x86ba, 0x00e285b7}, /* U+2177 SMALL ROMAN NUMERAL EIGHT [2000] */ - {0x86bb, 0x00e285b8}, /* U+2178 SMALL ROMAN NUMERAL NINE [2000] */ - {0x86bc, 0x00e285b9}, /* U+2179 SMALL ROMAN NUMERAL TEN [2000] */ - {0x86bd, 0x00e285ba}, /* U+217A SMALL ROMAN NUMERAL ELEVEN [2000] */ - {0x86be, 0x00e285bb}, /* U+217B SMALL ROMAN NUMERAL TWELVE [2000] */ - {0x86bf, 0x00e29390}, /* U+24D0 CIRCLED LATIN SMALL LETTER A [2000] */ - {0x86c0, 0x00e29391}, /* U+24D1 CIRCLED LATIN SMALL LETTER B [2000] */ - {0x86c1, 0x00e29392}, /* U+24D2 CIRCLED LATIN SMALL LETTER C [2000] */ - {0x86c2, 0x00e29393}, /* U+24D3 CIRCLED LATIN SMALL LETTER D [2000] */ - {0x86c3, 0x00e29394}, /* U+24D4 CIRCLED LATIN SMALL LETTER E [2000] */ - {0x86c4, 0x00e29395}, /* U+24D5 CIRCLED LATIN SMALL LETTER F [2000] */ - {0x86c5, 0x00e29396}, /* U+24D6 CIRCLED LATIN SMALL LETTER G [2000] */ - {0x86c6, 0x00e29397}, /* U+24D7 CIRCLED LATIN SMALL LETTER H [2000] */ - {0x86c7, 0x00e29398}, /* U+24D8 CIRCLED LATIN SMALL LETTER I [2000] */ - {0x86c8, 0x00e29399}, /* U+24D9 CIRCLED LATIN SMALL LETTER J [2000] */ - {0x86c9, 0x00e2939a}, /* U+24DA CIRCLED LATIN SMALL LETTER K [2000] */ - {0x86ca, 0x00e2939b}, /* U+24DB CIRCLED LATIN SMALL LETTER L [2000] */ - {0x86cb, 0x00e2939c}, /* U+24DC CIRCLED LATIN SMALL LETTER M [2000] */ - {0x86cc, 0x00e2939d}, /* U+24DD CIRCLED LATIN SMALL LETTER N [2000] */ - {0x86cd, 0x00e2939e}, /* U+24DE CIRCLED LATIN SMALL LETTER O [2000] */ - {0x86ce, 0x00e2939f}, /* U+24DF CIRCLED LATIN SMALL LETTER P [2000] */ - {0x86cf, 0x00e293a0}, /* U+24E0 CIRCLED LATIN SMALL LETTER Q [2000] */ - {0x86d0, 0x00e293a1}, /* U+24E1 CIRCLED LATIN SMALL LETTER R [2000] */ - {0x86d1, 0x00e293a2}, /* U+24E2 CIRCLED LATIN SMALL LETTER S [2000] */ - {0x86d2, 0x00e293a3}, /* U+24E3 CIRCLED LATIN SMALL LETTER T [2000] */ - {0x86d3, 0x00e293a4}, /* U+24E4 CIRCLED LATIN SMALL LETTER U [2000] */ - {0x86d4, 0x00e293a5}, /* U+24E5 CIRCLED LATIN SMALL LETTER V [2000] */ - {0x86d5, 0x00e293a6}, /* U+24E6 CIRCLED LATIN SMALL LETTER W [2000] */ - {0x86d6, 0x00e293a7}, /* U+24E7 CIRCLED LATIN SMALL LETTER X [2000] */ - {0x86d7, 0x00e293a8}, /* U+24E8 CIRCLED LATIN SMALL LETTER Y [2000] */ - {0x86d8, 0x00e293a9}, /* U+24E9 CIRCLED LATIN SMALL LETTER Z [2000] */ - {0x86d9, 0x00e38b90}, /* U+32D0 CIRCLED KATAKANA A [2000] */ - {0x86da, 0x00e38b91}, /* U+32D1 CIRCLED KATAKANA I [2000] */ - {0x86db, 0x00e38b92}, /* U+32D2 CIRCLED KATAKANA U [2000] */ - {0x86dc, 0x00e38b93}, /* U+32D3 CIRCLED KATAKANA E [2000] */ - {0x86dd, 0x00e38b94}, /* U+32D4 CIRCLED KATAKANA O [2000] */ - {0x86de, 0x00e38b95}, /* U+32D5 CIRCLED KATAKANA KA [2000] */ - {0x86df, 0x00e38b96}, /* U+32D6 CIRCLED KATAKANA KI [2000] */ - {0x86e0, 0x00e38b97}, /* U+32D7 CIRCLED KATAKANA KU [2000] */ - {0x86e1, 0x00e38b98}, /* U+32D8 CIRCLED KATAKANA KE [2000] */ - {0x86e2, 0x00e38b99}, /* U+32D9 CIRCLED KATAKANA KO [2000] */ - {0x86e3, 0x00e38b9a}, /* U+32DA CIRCLED KATAKANA SA [2000] */ - {0x86e4, 0x00e38b9b}, /* U+32DB CIRCLED KATAKANA SI [2000] */ - {0x86e5, 0x00e38b9c}, /* U+32DC CIRCLED KATAKANA SU [2000] */ - {0x86e6, 0x00e38b9d}, /* U+32DD CIRCLED KATAKANA SE [2000] */ - {0x86e7, 0x00e38b9e}, /* U+32DE CIRCLED KATAKANA SO [2000] */ - {0x86e8, 0x00e38b9f}, /* U+32DF CIRCLED KATAKANA TA [2000] */ - {0x86e9, 0x00e38ba0}, /* U+32E0 CIRCLED KATAKANA TI [2000] */ - {0x86ea, 0x00e38ba1}, /* U+32E1 CIRCLED KATAKANA TU [2000] */ - {0x86eb, 0x00e38ba2}, /* U+32E2 CIRCLED KATAKANA TE [2000] */ - {0x86ec, 0x00e38ba3}, /* U+32E3 CIRCLED KATAKANA TO [2000] */ - {0x86ed, 0x00e38bba}, /* U+32FA CIRCLED KATAKANA RO [2000] */ - {0x86ee, 0x00e38ba9}, /* U+32E9 CIRCLED KATAKANA HA [2000] */ - {0x86ef, 0x00e38ba5}, /* U+32E5 CIRCLED KATAKANA NI [2000] */ - {0x86f0, 0x00e38bad}, /* U+32ED CIRCLED KATAKANA HO [2000] */ - {0x86f1, 0x00e38bac}, /* U+32EC CIRCLED KATAKANA HE [2000] */ - {0x86fb, 0x00e28191}, /* U+2051 TWO ASTERISKS ALIGNED VERTICALLY [2000] [Unicode3.2] */ - {0x86fc, 0x00e28182}, /* U+2042 ASTERISM [2000] */ - {0x8740, 0x00e291a0}, /* U+2460 CIRCLED DIGIT ONE [2000] */ - {0x8741, 0x00e291a1}, /* U+2461 CIRCLED DIGIT TWO [2000] */ - {0x8742, 0x00e291a2}, /* U+2462 CIRCLED DIGIT THREE [2000] */ - {0x8743, 0x00e291a3}, /* U+2463 CIRCLED DIGIT FOUR [2000] */ - {0x8744, 0x00e291a4}, /* U+2464 CIRCLED DIGIT FIVE [2000] */ - {0x8745, 0x00e291a5}, /* U+2465 CIRCLED DIGIT SIX [2000] */ - {0x8746, 0x00e291a6}, /* U+2466 CIRCLED DIGIT SEVEN [2000] */ - {0x8747, 0x00e291a7}, /* U+2467 CIRCLED DIGIT EIGHT [2000] */ - {0x8748, 0x00e291a8}, /* U+2468 CIRCLED DIGIT NINE [2000] */ - {0x8749, 0x00e291a9}, /* U+2469 CIRCLED NUMBER TEN [2000] */ - {0x874a, 0x00e291aa}, /* U+246A CIRCLED NUMBER ELEVEN [2000] */ - {0x874b, 0x00e291ab}, /* U+246B CIRCLED NUMBER TWELVE [2000] */ - {0x874c, 0x00e291ac}, /* U+246C CIRCLED NUMBER THIRTEEN [2000] */ - {0x874d, 0x00e291ad}, /* U+246D CIRCLED NUMBER FOURTEEN [2000] */ - {0x874e, 0x00e291ae}, /* U+246E CIRCLED NUMBER FIFTEEN [2000] */ - {0x874f, 0x00e291af}, /* U+246F CIRCLED NUMBER SIXTEEN [2000] */ - {0x8750, 0x00e291b0}, /* U+2470 CIRCLED NUMBER SEVENTEEN [2000] */ - {0x8751, 0x00e291b1}, /* U+2471 CIRCLED NUMBER EIGHTEEN [2000] */ - {0x8752, 0x00e291b2}, /* U+2472 CIRCLED NUMBER NINETEEN [2000] */ - {0x8753, 0x00e291b3}, /* U+2473 CIRCLED NUMBER TWENTY [2000] */ - {0x8754, 0x00e285a0}, /* U+2160 ROMAN NUMERAL ONE [2000] */ - {0x8755, 0x00e285a1}, /* U+2161 ROMAN NUMERAL TWO [2000] */ - {0x8756, 0x00e285a2}, /* U+2162 ROMAN NUMERAL THREE [2000] */ - {0x8757, 0x00e285a3}, /* U+2163 ROMAN NUMERAL FOUR [2000] */ - {0x8758, 0x00e285a4}, /* U+2164 ROMAN NUMERAL FIVE [2000] */ - {0x8759, 0x00e285a5}, /* U+2165 ROMAN NUMERAL SIX [2000] */ - {0x875a, 0x00e285a6}, /* U+2166 ROMAN NUMERAL SEVEN [2000] */ - {0x875b, 0x00e285a7}, /* U+2167 ROMAN NUMERAL EIGHT [2000] */ - {0x875c, 0x00e285a8}, /* U+2168 ROMAN NUMERAL NINE [2000] */ - {0x875d, 0x00e285a9}, /* U+2169 ROMAN NUMERAL TEN [2000] */ - {0x875e, 0x00e285aa}, /* U+216A ROMAN NUMERAL ELEVEN [2000] */ - {0x875f, 0x00e38d89}, /* U+3349 SQUARE MIRI [2000] */ - {0x8760, 0x00e38c94}, /* U+3314 SQUARE KIRO [2000] */ - {0x8761, 0x00e38ca2}, /* U+3322 SQUARE SENTI [2000] */ - {0x8762, 0x00e38d8d}, /* U+334D SQUARE MEETORU [2000] */ - {0x8763, 0x00e38c98}, /* U+3318 SQUARE GURAMU [2000] */ - {0x8764, 0x00e38ca7}, /* U+3327 SQUARE TON [2000] */ - {0x8765, 0x00e38c83}, /* U+3303 SQUARE AARU [2000] */ - {0x8766, 0x00e38cb6}, /* U+3336 SQUARE HEKUTAARU [2000] */ - {0x8767, 0x00e38d91}, /* U+3351 SQUARE RITTORU [2000] */ - {0x8768, 0x00e38d97}, /* U+3357 SQUARE WATTO [2000] */ - {0x8769, 0x00e38c8d}, /* U+330D SQUARE KARORII [2000] */ - {0x876a, 0x00e38ca6}, /* U+3326 SQUARE DORU [2000] */ - {0x876b, 0x00e38ca3}, /* U+3323 SQUARE SENTO [2000] */ - {0x876c, 0x00e38cab}, /* U+332B SQUARE PAASENTO [2000] */ - {0x876d, 0x00e38d8a}, /* U+334A SQUARE MIRIBAARU [2000] */ - {0x876e, 0x00e38cbb}, /* U+333B SQUARE PEEZI [2000] */ - {0x876f, 0x00e38e9c}, /* U+339C SQUARE MM [2000] */ - {0x8770, 0x00e38e9d}, /* U+339D SQUARE CM [2000] */ - {0x8771, 0x00e38e9e}, /* U+339E SQUARE KM [2000] */ - {0x8772, 0x00e38e8e}, /* U+338E SQUARE MG [2000] */ - {0x8773, 0x00e38e8f}, /* U+338F SQUARE KG [2000] */ - {0x8774, 0x00e38f84}, /* U+33C4 SQUARE CC [2000] */ - {0x8775, 0x00e38ea1}, /* U+33A1 SQUARE M SQUARED [2000] */ - {0x8776, 0x00e285ab}, /* U+216B ROMAN NUMERAL TWELVE [2000] */ - {0x877e, 0x00e38dbb}, /* U+337B SQUARE ERA NAME HEISEI [2000] */ - {0x8780, 0x00e3809d}, /* U+301D REVERSED DOUBLE PRIME QUOTATION MARK [2000] */ - {0x8781, 0x00e3809f}, /* U+301F LOW DOUBLE PRIME QUOTATION MARK [2000] */ - {0x8782, 0x00e28496}, /* U+2116 NUMERO SIGN [2000] */ - {0x8783, 0x00e38f8d}, /* U+33CD SQUARE KK [2000] */ - {0x8784, 0x00e284a1}, /* U+2121 TELEPHONE SIGN [2000] */ - {0x8785, 0x00e38aa4}, /* U+32A4 CIRCLED IDEOGRAPH HIGH [2000] */ - {0x8786, 0x00e38aa5}, /* U+32A5 CIRCLED IDEOGRAPH CENTRE [2000] */ - {0x8787, 0x00e38aa6}, /* U+32A6 CIRCLED IDEOGRAPH LOW [2000] */ - {0x8788, 0x00e38aa7}, /* U+32A7 CIRCLED IDEOGRAPH LEFT [2000] */ - {0x8789, 0x00e38aa8}, /* U+32A8 CIRCLED IDEOGRAPH RIGHT [2000] */ - {0x878a, 0x00e388b1}, /* U+3231 PARENTHESIZED IDEOGRAPH STOCK [2000] */ - {0x878b, 0x00e388b2}, /* U+3232 PARENTHESIZED IDEOGRAPH HAVE [2000] */ - {0x878c, 0x00e388b9}, /* U+3239 PARENTHESIZED IDEOGRAPH REPRESENT [2000] */ - {0x878d, 0x00e38dbe}, /* U+337E SQUARE ERA NAME MEIZI [2000] */ - {0x878e, 0x00e38dbd}, /* U+337D SQUARE ERA NAME TAISYOU [2000] */ - {0x878f, 0x00e38dbc}, /* U+337C SQUARE ERA NAME SYOUWA [2000] */ - {0x8793, 0x00e288ae}, /* U+222E CONTOUR INTEGRAL [2000] */ - {0x8798, 0x00e2889f}, /* U+221F RIGHT ANGLE [2000] */ - {0x8799, 0x00e28abf}, /* U+22BF RIGHT TRIANGLE [2000] */ - {0x879d, 0x00e29d96}, /* U+2756 BLACK DIAMOND MINUS WHITE X [2000] */ - {0x879e, 0x00e2989e}, /* U+261E WHITE RIGHT POINTING INDEX [2000] */ - {0x879f, 0x00e4bfb1}, /* U+4FF1 [2004] */ +/* src/backend/utils/mb/Unicode/shift_jis_2004_to_utf8.map */ + +static const pg_local_to_utf LUmapSHIFT_JIS_2004[ 11271 ] = { /* */ + {0x00a1, 0xefbda1}, /* U+FF61 HALFWIDTH IDEOGRAPHIC FULL STOP */ + {0x00a2, 0xefbda2}, /* U+FF62 HALFWIDTH LEFT CORNER BRACKET */ + {0x00a3, 0xefbda3}, /* U+FF63 HALFWIDTH RIGHT CORNER BRACKET */ + {0x00a4, 0xefbda4}, /* U+FF64 HALFWIDTH IDEOGRAPHIC COMMA */ + {0x00a5, 0xefbda5}, /* U+FF65 HALFWIDTH KATAKANA MIDDLE DOT */ + {0x00a6, 0xefbda6}, /* U+FF66 HALFWIDTH KATAKANA LETTER WO */ + {0x00a7, 0xefbda7}, /* U+FF67 HALFWIDTH KATAKANA LETTER SMALL A */ + {0x00a8, 0xefbda8}, /* U+FF68 HALFWIDTH KATAKANA LETTER SMALL I */ + {0x00a9, 0xefbda9}, /* U+FF69 HALFWIDTH KATAKANA LETTER SMALL U */ + {0x00aa, 0xefbdaa}, /* U+FF6A HALFWIDTH KATAKANA LETTER SMALL E */ + {0x00ab, 0xefbdab}, /* U+FF6B HALFWIDTH KATAKANA LETTER SMALL O */ + {0x00ac, 0xefbdac}, /* U+FF6C HALFWIDTH KATAKANA LETTER SMALL YA */ + {0x00ad, 0xefbdad}, /* U+FF6D HALFWIDTH KATAKANA LETTER SMALL YU */ + {0x00ae, 0xefbdae}, /* U+FF6E HALFWIDTH KATAKANA LETTER SMALL YO */ + {0x00af, 0xefbdaf}, /* U+FF6F HALFWIDTH KATAKANA LETTER SMALL TU */ + {0x00b0, 0xefbdb0}, /* U+FF70 HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK */ + {0x00b1, 0xefbdb1}, /* U+FF71 HALFWIDTH KATAKANA LETTER A */ + {0x00b2, 0xefbdb2}, /* U+FF72 HALFWIDTH KATAKANA LETTER I */ + {0x00b3, 0xefbdb3}, /* U+FF73 HALFWIDTH KATAKANA LETTER U */ + {0x00b4, 0xefbdb4}, /* U+FF74 HALFWIDTH KATAKANA LETTER E */ + {0x00b5, 0xefbdb5}, /* U+FF75 HALFWIDTH KATAKANA LETTER O */ + {0x00b6, 0xefbdb6}, /* U+FF76 HALFWIDTH KATAKANA LETTER KA */ + {0x00b7, 0xefbdb7}, /* U+FF77 HALFWIDTH KATAKANA LETTER KI */ + {0x00b8, 0xefbdb8}, /* U+FF78 HALFWIDTH KATAKANA LETTER KU */ + {0x00b9, 0xefbdb9}, /* U+FF79 HALFWIDTH KATAKANA LETTER KE */ + {0x00ba, 0xefbdba}, /* U+FF7A HALFWIDTH KATAKANA LETTER KO */ + {0x00bb, 0xefbdbb}, /* U+FF7B HALFWIDTH KATAKANA LETTER SA */ + {0x00bc, 0xefbdbc}, /* U+FF7C HALFWIDTH KATAKANA LETTER SI */ + {0x00bd, 0xefbdbd}, /* U+FF7D HALFWIDTH KATAKANA LETTER SU */ + {0x00be, 0xefbdbe}, /* U+FF7E HALFWIDTH KATAKANA LETTER SE */ + {0x00bf, 0xefbdbf}, /* U+FF7F HALFWIDTH KATAKANA LETTER SO */ + {0x00c0, 0xefbe80}, /* U+FF80 HALFWIDTH KATAKANA LETTER TA */ + {0x00c1, 0xefbe81}, /* U+FF81 HALFWIDTH KATAKANA LETTER TI */ + {0x00c2, 0xefbe82}, /* U+FF82 HALFWIDTH KATAKANA LETTER TU */ + {0x00c3, 0xefbe83}, /* U+FF83 HALFWIDTH KATAKANA LETTER TE */ + {0x00c4, 0xefbe84}, /* U+FF84 HALFWIDTH KATAKANA LETTER TO */ + {0x00c5, 0xefbe85}, /* U+FF85 HALFWIDTH KATAKANA LETTER NA */ + {0x00c6, 0xefbe86}, /* U+FF86 HALFWIDTH KATAKANA LETTER NI */ + {0x00c7, 0xefbe87}, /* U+FF87 HALFWIDTH KATAKANA LETTER NU */ + {0x00c8, 0xefbe88}, /* U+FF88 HALFWIDTH KATAKANA LETTER NE */ + {0x00c9, 0xefbe89}, /* U+FF89 HALFWIDTH KATAKANA LETTER NO */ + {0x00ca, 0xefbe8a}, /* U+FF8A HALFWIDTH KATAKANA LETTER HA */ + {0x00cb, 0xefbe8b}, /* U+FF8B HALFWIDTH KATAKANA LETTER HI */ + {0x00cc, 0xefbe8c}, /* U+FF8C HALFWIDTH KATAKANA LETTER HU */ + {0x00cd, 0xefbe8d}, /* U+FF8D HALFWIDTH KATAKANA LETTER HE */ + {0x00ce, 0xefbe8e}, /* U+FF8E HALFWIDTH KATAKANA LETTER HO */ + {0x00cf, 0xefbe8f}, /* U+FF8F HALFWIDTH KATAKANA LETTER MA */ + {0x00d0, 0xefbe90}, /* U+FF90 HALFWIDTH KATAKANA LETTER MI */ + {0x00d1, 0xefbe91}, /* U+FF91 HALFWIDTH KATAKANA LETTER MU */ + {0x00d2, 0xefbe92}, /* U+FF92 HALFWIDTH KATAKANA LETTER ME */ + {0x00d3, 0xefbe93}, /* U+FF93 HALFWIDTH KATAKANA LETTER MO */ + {0x00d4, 0xefbe94}, /* U+FF94 HALFWIDTH KATAKANA LETTER YA */ + {0x00d5, 0xefbe95}, /* U+FF95 HALFWIDTH KATAKANA LETTER YU */ + {0x00d6, 0xefbe96}, /* U+FF96 HALFWIDTH KATAKANA LETTER YO */ + {0x00d7, 0xefbe97}, /* U+FF97 HALFWIDTH KATAKANA LETTER RA */ + {0x00d8, 0xefbe98}, /* U+FF98 HALFWIDTH KATAKANA LETTER RI */ + {0x00d9, 0xefbe99}, /* U+FF99 HALFWIDTH KATAKANA LETTER RU */ + {0x00da, 0xefbe9a}, /* U+FF9A HALFWIDTH KATAKANA LETTER RE */ + {0x00db, 0xefbe9b}, /* U+FF9B HALFWIDTH KATAKANA LETTER RO */ + {0x00dc, 0xefbe9c}, /* U+FF9C HALFWIDTH KATAKANA LETTER WA */ + {0x00dd, 0xefbe9d}, /* U+FF9D HALFWIDTH KATAKANA LETTER N */ + {0x00de, 0xefbe9e}, /* U+FF9E HALFWIDTH KATAKANA VOICED SOUND MARK */ + {0x00df, 0xefbe9f}, /* U+FF9F HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK */ + {0x8140, 0xe38080}, /* U+3000 IDEOGRAPHIC SPACE */ + {0x8141, 0xe38081}, /* U+3001 IDEOGRAPHIC COMMA */ + {0x8142, 0xe38082}, /* U+3002 IDEOGRAPHIC FULL STOP */ + {0x8143, 0xefbc8c}, /* U+FF0C FULLWIDTH COMMA */ + {0x8144, 0xefbc8e}, /* U+FF0E FULLWIDTH FULL STOP */ + {0x8145, 0xe383bb}, /* U+30FB KATAKANA MIDDLE DOT */ + {0x8146, 0xefbc9a}, /* U+FF1A FULLWIDTH COLON */ + {0x8147, 0xefbc9b}, /* U+FF1B FULLWIDTH SEMICOLON */ + {0x8148, 0xefbc9f}, /* U+FF1F FULLWIDTH QUESTION MARK */ + {0x8149, 0xefbc81}, /* U+FF01 FULLWIDTH EXCLAMATION MARK */ + {0x814a, 0xe3829b}, /* U+309B KATAKANA-HIRAGANA VOICED SOUND MARK */ + {0x814b, 0xe3829c}, /* U+309C KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ + {0x814c, 0xc2b4}, /* U+00B4 ACUTE ACCENT */ + {0x814d, 0xefbd80}, /* U+FF40 FULLWIDTH GRAVE ACCENT */ + {0x814e, 0xc2a8}, /* U+00A8 DIAERESIS */ + {0x814f, 0xefbcbe}, /* U+FF3E FULLWIDTH CIRCUMFLEX ACCENT */ + {0x8150, 0xefbfa3}, /* U+FFE3 FULLWIDTH MACRON */ + {0x8151, 0xefbcbf}, /* U+FF3F FULLWIDTH LOW LINE */ + {0x8152, 0xe383bd}, /* U+30FD KATAKANA ITERATION MARK */ + {0x8153, 0xe383be}, /* U+30FE KATAKANA VOICED ITERATION MARK */ + {0x8154, 0xe3829d}, /* U+309D HIRAGANA ITERATION MARK */ + {0x8155, 0xe3829e}, /* U+309E HIRAGANA VOICED ITERATION MARK */ + {0x8156, 0xe38083}, /* U+3003 DITTO MARK */ + {0x8157, 0xe4bb9d}, /* U+4EDD */ + {0x8158, 0xe38085}, /* U+3005 IDEOGRAPHIC ITERATION MARK */ + {0x8159, 0xe38086}, /* U+3006 IDEOGRAPHIC CLOSING MARK */ + {0x815a, 0xe38087}, /* U+3007 IDEOGRAPHIC NUMBER ZERO */ + {0x815b, 0xe383bc}, /* U+30FC KATAKANA-HIRAGANA PROLONGED SOUND MARK */ + {0x815c, 0xe28094}, /* U+2014 EM DASH Windows: U+2015 */ + {0x815d, 0xe28090}, /* U+2010 HYPHEN */ + {0x815e, 0xefbc8f}, /* U+FF0F FULLWIDTH SOLIDUS */ + {0x815f, 0x5c}, /* U+005C REVERSE SOLIDUS Fullwidth: U+FF3C */ + {0x8160, 0xe3809c}, /* U+301C WAVE DASH Windows: U+FF5E */ + {0x8161, 0xe28096}, /* U+2016 DOUBLE VERTICAL LINE Windows: U+2225 */ + {0x8162, 0xefbd9c}, /* U+FF5C FULLWIDTH VERTICAL LINE */ + {0x8163, 0xe280a6}, /* U+2026 HORIZONTAL ELLIPSIS */ + {0x8164, 0xe280a5}, /* U+2025 TWO DOT LEADER */ + {0x8165, 0xe28098}, /* U+2018 LEFT SINGLE QUOTATION MARK */ + {0x8166, 0xe28099}, /* U+2019 RIGHT SINGLE QUOTATION MARK */ + {0x8167, 0xe2809c}, /* U+201C LEFT DOUBLE QUOTATION MARK */ + {0x8168, 0xe2809d}, /* U+201D RIGHT DOUBLE QUOTATION MARK */ + {0x8169, 0xefbc88}, /* U+FF08 FULLWIDTH LEFT PARENTHESIS */ + {0x816a, 0xefbc89}, /* U+FF09 FULLWIDTH RIGHT PARENTHESIS */ + {0x816b, 0xe38094}, /* U+3014 LEFT TORTOISE SHELL BRACKET */ + {0x816c, 0xe38095}, /* U+3015 RIGHT TORTOISE SHELL BRACKET */ + {0x816d, 0xefbcbb}, /* U+FF3B FULLWIDTH LEFT SQUARE BRACKET */ + {0x816e, 0xefbcbd}, /* U+FF3D FULLWIDTH RIGHT SQUARE BRACKET */ + {0x816f, 0xefbd9b}, /* U+FF5B FULLWIDTH LEFT CURLY BRACKET */ + {0x8170, 0xefbd9d}, /* U+FF5D FULLWIDTH RIGHT CURLY BRACKET */ + {0x8171, 0xe38088}, /* U+3008 LEFT ANGLE BRACKET */ + {0x8172, 0xe38089}, /* U+3009 RIGHT ANGLE BRACKET */ + {0x8173, 0xe3808a}, /* U+300A LEFT DOUBLE ANGLE BRACKET */ + {0x8174, 0xe3808b}, /* U+300B RIGHT DOUBLE ANGLE BRACKET */ + {0x8175, 0xe3808c}, /* U+300C LEFT CORNER BRACKET */ + {0x8176, 0xe3808d}, /* U+300D RIGHT CORNER BRACKET */ + {0x8177, 0xe3808e}, /* U+300E LEFT WHITE CORNER BRACKET */ + {0x8178, 0xe3808f}, /* U+300F RIGHT WHITE CORNER BRACKET */ + {0x8179, 0xe38090}, /* U+3010 LEFT BLACK LENTICULAR BRACKET */ + {0x817a, 0xe38091}, /* U+3011 RIGHT BLACK LENTICULAR BRACKET */ + {0x817b, 0xefbc8b}, /* U+FF0B FULLWIDTH PLUS SIGN */ + {0x817c, 0xe28892}, /* U+2212 MINUS SIGN Windows: U+FF0D */ + {0x817d, 0xc2b1}, /* U+00B1 PLUS-MINUS SIGN */ + {0x817e, 0xc397}, /* U+00D7 MULTIPLICATION SIGN */ + {0x8180, 0xc3b7}, /* U+00F7 DIVISION SIGN */ + {0x8181, 0xefbc9d}, /* U+FF1D FULLWIDTH EQUALS SIGN */ + {0x8182, 0xe289a0}, /* U+2260 NOT EQUAL TO */ + {0x8183, 0xefbc9c}, /* U+FF1C FULLWIDTH LESS-THAN SIGN */ + {0x8184, 0xefbc9e}, /* U+FF1E FULLWIDTH GREATER-THAN SIGN */ + {0x8185, 0xe289a6}, /* U+2266 LESS-THAN OVER EQUAL TO */ + {0x8186, 0xe289a7}, /* U+2267 GREATER-THAN OVER EQUAL TO */ + {0x8187, 0xe2889e}, /* U+221E INFINITY */ + {0x8188, 0xe288b4}, /* U+2234 THEREFORE */ + {0x8189, 0xe29982}, /* U+2642 MALE SIGN */ + {0x818a, 0xe29980}, /* U+2640 FEMALE SIGN */ + {0x818b, 0xc2b0}, /* U+00B0 DEGREE SIGN */ + {0x818c, 0xe280b2}, /* U+2032 PRIME */ + {0x818d, 0xe280b3}, /* U+2033 DOUBLE PRIME */ + {0x818e, 0xe28483}, /* U+2103 DEGREE CELSIUS */ + {0x818f, 0xefbfa5}, /* U+FFE5 FULLWIDTH YEN SIGN */ + {0x8190, 0xefbc84}, /* U+FF04 FULLWIDTH DOLLAR SIGN */ + {0x8191, 0xc2a2}, /* U+00A2 CENT SIGN Windows: U+FFE0 */ + {0x8192, 0xc2a3}, /* U+00A3 POUND SIGN Windows: U+FFE1 */ + {0x8193, 0xefbc85}, /* U+FF05 FULLWIDTH PERCENT SIGN */ + {0x8194, 0xefbc83}, /* U+FF03 FULLWIDTH NUMBER SIGN */ + {0x8195, 0xefbc86}, /* U+FF06 FULLWIDTH AMPERSAND */ + {0x8196, 0xefbc8a}, /* U+FF0A FULLWIDTH ASTERISK */ + {0x8197, 0xefbca0}, /* U+FF20 FULLWIDTH COMMERCIAL AT */ + {0x8198, 0xc2a7}, /* U+00A7 SECTION SIGN */ + {0x8199, 0xe29886}, /* U+2606 WHITE STAR */ + {0x819a, 0xe29885}, /* U+2605 BLACK STAR */ + {0x819b, 0xe2978b}, /* U+25CB WHITE CIRCLE */ + {0x819c, 0xe2978f}, /* U+25CF BLACK CIRCLE */ + {0x819d, 0xe2978e}, /* U+25CE BULLSEYE */ + {0x819e, 0xe29787}, /* U+25C7 WHITE DIAMOND */ + {0x819f, 0xe29786}, /* U+25C6 BLACK DIAMOND */ + {0x81a0, 0xe296a1}, /* U+25A1 WHITE SQUARE */ + {0x81a1, 0xe296a0}, /* U+25A0 BLACK SQUARE */ + {0x81a2, 0xe296b3}, /* U+25B3 WHITE UP-POINTING TRIANGLE */ + {0x81a3, 0xe296b2}, /* U+25B2 BLACK UP-POINTING TRIANGLE */ + {0x81a4, 0xe296bd}, /* U+25BD WHITE DOWN-POINTING TRIANGLE */ + {0x81a5, 0xe296bc}, /* U+25BC BLACK DOWN-POINTING TRIANGLE */ + {0x81a6, 0xe280bb}, /* U+203B REFERENCE MARK */ + {0x81a7, 0xe38092}, /* U+3012 POSTAL MARK */ + {0x81a8, 0xe28692}, /* U+2192 RIGHTWARDS ARROW */ + {0x81a9, 0xe28690}, /* U+2190 LEFTWARDS ARROW */ + {0x81aa, 0xe28691}, /* U+2191 UPWARDS ARROW */ + {0x81ab, 0xe28693}, /* U+2193 DOWNWARDS ARROW */ + {0x81ac, 0xe38093}, /* U+3013 GETA MARK */ + {0x81ad, 0xefbc87}, /* U+FF07 FULLWIDTH APOSTROPHE */ + {0x81ae, 0xefbc82}, /* U+FF02 FULLWIDTH QUOTATION MARK [2000] */ + {0x81af, 0xefbc8d}, /* U+FF0D FULLWIDTH HYPHEN-MINUS [2000] */ + {0x81b0, 0x7e}, /* U+007E TILDE [2000] Fullwidth: U+FF5E */ + {0x81b1, 0xe380b3}, /* U+3033 VERTICAL KANA REPEAT MARK UPPER HALF [2000] */ + {0x81b2, 0xe380b4}, /* U+3034 VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF [2000] */ + {0x81b3, 0xe380b5}, /* U+3035 VERTICAL KANA REPEAT MARK LOWER HALF [2000] */ + {0x81b4, 0xe380bb}, /* U+303B VERTICAL IDEOGRAPHIC ITERATION MARK [2000] [Unicode3.2] */ + {0x81b5, 0xe380bc}, /* U+303C MASU MARK [2000] [Unicode3.2] */ + {0x81b6, 0xe383bf}, /* U+30FF KATAKANA DIGRAPH KOTO [2000] [Unicode3.2] */ + {0x81b7, 0xe3829f}, /* U+309F HIRAGANA DIGRAPH YORI [2000] [Unicode3.2] */ + {0x81b8, 0xe28888}, /* U+2208 ELEMENT OF [1983] */ + {0x81b9, 0xe2888b}, /* U+220B CONTAINS AS MEMBER [1983] */ + {0x81ba, 0xe28a86}, /* U+2286 SUBSET OF OR EQUAL TO [1983] */ + {0x81bb, 0xe28a87}, /* U+2287 SUPERSET OF OR EQUAL TO [1983] */ + {0x81bc, 0xe28a82}, /* U+2282 SUBSET OF [1983] */ + {0x81bd, 0xe28a83}, /* U+2283 SUPERSET OF [1983] */ + {0x81be, 0xe288aa}, /* U+222A UNION [1983] */ + {0x81bf, 0xe288a9}, /* U+2229 INTERSECTION [1983] */ + {0x81c0, 0xe28a84}, /* U+2284 NOT A SUBSET OF [2000] */ + {0x81c1, 0xe28a85}, /* U+2285 NOT A SUPERSET OF [2000] */ + {0x81c2, 0xe28a8a}, /* U+228A SUBSET OF WITH NOT EQUAL TO [2000] */ + {0x81c3, 0xe28a8b}, /* U+228B SUPERSET OF WITH NOT EQUAL TO [2000] */ + {0x81c4, 0xe28889}, /* U+2209 NOT AN ELEMENT OF [2000] */ + {0x81c5, 0xe28885}, /* U+2205 EMPTY SET [2000] */ + {0x81c6, 0xe28c85}, /* U+2305 PROJECTIVE [2000] */ + {0x81c7, 0xe28c86}, /* U+2306 PERSPECTIVE [2000] */ + {0x81c8, 0xe288a7}, /* U+2227 LOGICAL AND [1983] */ + {0x81c9, 0xe288a8}, /* U+2228 LOGICAL OR [1983] */ + {0x81ca, 0xc2ac}, /* U+00AC NOT SIGN [1983] Windows: U+FFE2 */ + {0x81cb, 0xe28792}, /* U+21D2 RIGHTWARDS DOUBLE ARROW [1983] */ + {0x81cc, 0xe28794}, /* U+21D4 LEFT RIGHT DOUBLE ARROW [1983] */ + {0x81cd, 0xe28880}, /* U+2200 FOR ALL [1983] */ + {0x81ce, 0xe28883}, /* U+2203 THERE EXISTS [1983] */ + {0x81cf, 0xe28a95}, /* U+2295 CIRCLED PLUS [2000] */ + {0x81d0, 0xe28a96}, /* U+2296 CIRCLED MINUS [2000] */ + {0x81d1, 0xe28a97}, /* U+2297 CIRCLED TIMES [2000] */ + {0x81d2, 0xe288a5}, /* U+2225 PARALLEL TO [2000] */ + {0x81d3, 0xe288a6}, /* U+2226 NOT PARALLEL TO [2000] */ + {0x81d4, 0xefbd9f}, /* U+FF5F FULLWIDTH LEFT WHITE PARENTHESIS [2000] [Unicode3.2] */ + {0x81d5, 0xefbda0}, /* U+FF60 FULLWIDTH RIGHT WHITE PARENTHESIS [2000] [Unicode3.2] */ + {0x81d6, 0xe38098}, /* U+3018 LEFT WHITE TORTOISE SHELL BRACKET [2000] */ + {0x81d7, 0xe38099}, /* U+3019 RIGHT WHITE TORTOISE SHELL BRACKET [2000] */ + {0x81d8, 0xe38096}, /* U+3016 LEFT WHITE LENTICULAR BRACKET [2000] */ + {0x81d9, 0xe38097}, /* U+3017 RIGHT WHITE LENTICULAR BRACKET [2000] */ + {0x81da, 0xe288a0}, /* U+2220 ANGLE [1983] */ + {0x81db, 0xe28aa5}, /* U+22A5 UP TACK [1983] */ + {0x81dc, 0xe28c92}, /* U+2312 ARC [1983] */ + {0x81dd, 0xe28882}, /* U+2202 PARTIAL DIFFERENTIAL [1983] */ + {0x81de, 0xe28887}, /* U+2207 NABLA [1983] */ + {0x81df, 0xe289a1}, /* U+2261 IDENTICAL TO [1983] */ + {0x81e0, 0xe28992}, /* U+2252 APPROXIMATELY EQUAL TO OR THE IMAGE OF [1983] */ + {0x81e1, 0xe289aa}, /* U+226A MUCH LESS-THAN [1983] */ + {0x81e2, 0xe289ab}, /* U+226B MUCH GREATER-THAN [1983] */ + {0x81e3, 0xe2889a}, /* U+221A SQUARE ROOT [1983] */ + {0x81e4, 0xe288bd}, /* U+223D REVERSED TILDE [1983] */ + {0x81e5, 0xe2889d}, /* U+221D PROPORTIONAL TO [1983] */ + {0x81e6, 0xe288b5}, /* U+2235 BECAUSE [1983] */ + {0x81e7, 0xe288ab}, /* U+222B INTEGRAL [1983] */ + {0x81e8, 0xe288ac}, /* U+222C DOUBLE INTEGRAL [1983] */ + {0x81e9, 0xe289a2}, /* U+2262 NOT IDENTICAL TO [2000] */ + {0x81ea, 0xe28983}, /* U+2243 ASYMPTOTICALLY EQUAL TO [2000] */ + {0x81eb, 0xe28985}, /* U+2245 APPROXIMATELY EQUAL TO [2000] */ + {0x81ec, 0xe28988}, /* U+2248 ALMOST EQUAL TO [2000] */ + {0x81ed, 0xe289b6}, /* U+2276 LESS-THAN OR GREATER-THAN [2000] */ + {0x81ee, 0xe289b7}, /* U+2277 GREATER-THAN OR LESS-THAN [2000] */ + {0x81ef, 0xe28694}, /* U+2194 LEFT RIGHT ARROW [2000] */ + {0x81f0, 0xe284ab}, /* U+212B ANGSTROM SIGN [1983] */ + {0x81f1, 0xe280b0}, /* U+2030 PER MILLE SIGN [1983] */ + {0x81f2, 0xe299af}, /* U+266F MUSIC SHARP SIGN [1983] */ + {0x81f3, 0xe299ad}, /* U+266D MUSIC FLAT SIGN [1983] */ + {0x81f4, 0xe299aa}, /* U+266A EIGHTH NOTE [1983] */ + {0x81f5, 0xe280a0}, /* U+2020 DAGGER [1983] */ + {0x81f6, 0xe280a1}, /* U+2021 DOUBLE DAGGER [1983] */ + {0x81f7, 0xc2b6}, /* U+00B6 PILCROW SIGN [1983] */ + {0x81f8, 0xe299ae}, /* U+266E MUSIC NATURAL SIGN [2000] */ + {0x81f9, 0xe299ab}, /* U+266B BEAMED EIGHTH NOTES [2000] */ + {0x81fa, 0xe299ac}, /* U+266C BEAMED SIXTEENTH NOTES [2000] */ + {0x81fb, 0xe299a9}, /* U+2669 QUARTER NOTE [2000] */ + {0x81fc, 0xe297af}, /* U+25EF LARGE CIRCLE [1983] */ + {0x8240, 0xe296b7}, /* U+25B7 WHITE RIGHT-POINTING TRIANGLE [2000] */ + {0x8241, 0xe296b6}, /* U+25B6 BLACK RIGHT-POINTING TRIANGLE [2000] */ + {0x8242, 0xe29781}, /* U+25C1 WHITE LEFT-POINTING TRIANGLE [2000] */ + {0x8243, 0xe29780}, /* U+25C0 BLACK LEFT-POINTING TRIANGLE [2000] */ + {0x8244, 0xe28697}, /* U+2197 NORTH EAST ARROW [2000] */ + {0x8245, 0xe28698}, /* U+2198 SOUTH EAST ARROW [2000] */ + {0x8246, 0xe28696}, /* U+2196 NORTH WEST ARROW [2000] */ + {0x8247, 0xe28699}, /* U+2199 SOUTH WEST ARROW [2000] */ + {0x8248, 0xe28784}, /* U+21C4 RIGHTWARDS ARROW OVER LEFTWARDS ARROW [2000] */ + {0x8249, 0xe287a8}, /* U+21E8 RIGHTWARDS WHITE ARROW [2000] */ + {0x824a, 0xe287a6}, /* U+21E6 LEFTWARDS WHITE ARROW [2000] */ + {0x824b, 0xe287a7}, /* U+21E7 UPWARDS WHITE ARROW [2000] */ + {0x824c, 0xe287a9}, /* U+21E9 DOWNWARDS WHITE ARROW [2000] */ + {0x824d, 0xe2a4b4}, /* U+2934 ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS [2000] [Unicode3.2] */ + {0x824e, 0xe2a4b5}, /* U+2935 ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS [2000] [Unicode3.2] */ + {0x824f, 0xefbc90}, /* U+FF10 FULLWIDTH DIGIT ZERO */ + {0x8250, 0xefbc91}, /* U+FF11 FULLWIDTH DIGIT ONE */ + {0x8251, 0xefbc92}, /* U+FF12 FULLWIDTH DIGIT TWO */ + {0x8252, 0xefbc93}, /* U+FF13 FULLWIDTH DIGIT THREE */ + {0x8253, 0xefbc94}, /* U+FF14 FULLWIDTH DIGIT FOUR */ + {0x8254, 0xefbc95}, /* U+FF15 FULLWIDTH DIGIT FIVE */ + {0x8255, 0xefbc96}, /* U+FF16 FULLWIDTH DIGIT SIX */ + {0x8256, 0xefbc97}, /* U+FF17 FULLWIDTH DIGIT SEVEN */ + {0x8257, 0xefbc98}, /* U+FF18 FULLWIDTH DIGIT EIGHT */ + {0x8258, 0xefbc99}, /* U+FF19 FULLWIDTH DIGIT NINE */ + {0x8259, 0xe2a6bf}, /* U+29BF CIRCLED BULLET [2000] [Unicode3.2] */ + {0x825a, 0xe29789}, /* U+25C9 FISHEYE [2000] */ + {0x825b, 0xe380bd}, /* U+303D PART ALTERNATION MARK [2000] [Unicode3.2] */ + {0x825c, 0xefb986}, /* U+FE46 WHITE SESAME DOT [2000] [Unicode3.2] */ + {0x825d, 0xefb985}, /* U+FE45 SESAME DOT [2000] [Unicode3.2] */ + {0x825e, 0xe297a6}, /* U+25E6 WHITE BULLET [2000] */ + {0x825f, 0xe280a2}, /* U+2022 BULLET [2000] */ + {0x8260, 0xefbca1}, /* U+FF21 FULLWIDTH LATIN CAPITAL LETTER A */ + {0x8261, 0xefbca2}, /* U+FF22 FULLWIDTH LATIN CAPITAL LETTER B */ + {0x8262, 0xefbca3}, /* U+FF23 FULLWIDTH LATIN CAPITAL LETTER C */ + {0x8263, 0xefbca4}, /* U+FF24 FULLWIDTH LATIN CAPITAL LETTER D */ + {0x8264, 0xefbca5}, /* U+FF25 FULLWIDTH LATIN CAPITAL LETTER E */ + {0x8265, 0xefbca6}, /* U+FF26 FULLWIDTH LATIN CAPITAL LETTER F */ + {0x8266, 0xefbca7}, /* U+FF27 FULLWIDTH LATIN CAPITAL LETTER G */ + {0x8267, 0xefbca8}, /* U+FF28 FULLWIDTH LATIN CAPITAL LETTER H */ + {0x8268, 0xefbca9}, /* U+FF29 FULLWIDTH LATIN CAPITAL LETTER I */ + {0x8269, 0xefbcaa}, /* U+FF2A FULLWIDTH LATIN CAPITAL LETTER J */ + {0x826a, 0xefbcab}, /* U+FF2B FULLWIDTH LATIN CAPITAL LETTER K */ + {0x826b, 0xefbcac}, /* U+FF2C FULLWIDTH LATIN CAPITAL LETTER L */ + {0x826c, 0xefbcad}, /* U+FF2D FULLWIDTH LATIN CAPITAL LETTER M */ + {0x826d, 0xefbcae}, /* U+FF2E FULLWIDTH LATIN CAPITAL LETTER N */ + {0x826e, 0xefbcaf}, /* U+FF2F FULLWIDTH LATIN CAPITAL LETTER O */ + {0x826f, 0xefbcb0}, /* U+FF30 FULLWIDTH LATIN CAPITAL LETTER P */ + {0x8270, 0xefbcb1}, /* U+FF31 FULLWIDTH LATIN CAPITAL LETTER Q */ + {0x8271, 0xefbcb2}, /* U+FF32 FULLWIDTH LATIN CAPITAL LETTER R */ + {0x8272, 0xefbcb3}, /* U+FF33 FULLWIDTH LATIN CAPITAL LETTER S */ + {0x8273, 0xefbcb4}, /* U+FF34 FULLWIDTH LATIN CAPITAL LETTER T */ + {0x8274, 0xefbcb5}, /* U+FF35 FULLWIDTH LATIN CAPITAL LETTER U */ + {0x8275, 0xefbcb6}, /* U+FF36 FULLWIDTH LATIN CAPITAL LETTER V */ + {0x8276, 0xefbcb7}, /* U+FF37 FULLWIDTH LATIN CAPITAL LETTER W */ + {0x8277, 0xefbcb8}, /* U+FF38 FULLWIDTH LATIN CAPITAL LETTER X */ + {0x8278, 0xefbcb9}, /* U+FF39 FULLWIDTH LATIN CAPITAL LETTER Y */ + {0x8279, 0xefbcba}, /* U+FF3A FULLWIDTH LATIN CAPITAL LETTER Z */ + {0x827a, 0xe28893}, /* U+2213 MINUS-OR-PLUS SIGN [2000] */ + {0x827b, 0xe284b5}, /* U+2135 ALEF SYMBOL [2000] */ + {0x827c, 0xe2848f}, /* U+210F PLANCK CONSTANT OVER TWO PI [2000] */ + {0x827d, 0xe38f8b}, /* U+33CB SQUARE HP [2000] */ + {0x827e, 0xe28493}, /* U+2113 SCRIPT SMALL L [2000] */ + {0x8280, 0xe284a7}, /* U+2127 INVERTED OHM SIGN [2000] */ + {0x8281, 0xefbd81}, /* U+FF41 FULLWIDTH LATIN SMALL LETTER A */ + {0x8282, 0xefbd82}, /* U+FF42 FULLWIDTH LATIN SMALL LETTER B */ + {0x8283, 0xefbd83}, /* U+FF43 FULLWIDTH LATIN SMALL LETTER C */ + {0x8284, 0xefbd84}, /* U+FF44 FULLWIDTH LATIN SMALL LETTER D */ + {0x8285, 0xefbd85}, /* U+FF45 FULLWIDTH LATIN SMALL LETTER E */ + {0x8286, 0xefbd86}, /* U+FF46 FULLWIDTH LATIN SMALL LETTER F */ + {0x8287, 0xefbd87}, /* U+FF47 FULLWIDTH LATIN SMALL LETTER G */ + {0x8288, 0xefbd88}, /* U+FF48 FULLWIDTH LATIN SMALL LETTER H */ + {0x8289, 0xefbd89}, /* U+FF49 FULLWIDTH LATIN SMALL LETTER I */ + {0x828a, 0xefbd8a}, /* U+FF4A FULLWIDTH LATIN SMALL LETTER J */ + {0x828b, 0xefbd8b}, /* U+FF4B FULLWIDTH LATIN SMALL LETTER K */ + {0x828c, 0xefbd8c}, /* U+FF4C FULLWIDTH LATIN SMALL LETTER L */ + {0x828d, 0xefbd8d}, /* U+FF4D FULLWIDTH LATIN SMALL LETTER M */ + {0x828e, 0xefbd8e}, /* U+FF4E FULLWIDTH LATIN SMALL LETTER N */ + {0x828f, 0xefbd8f}, /* U+FF4F FULLWIDTH LATIN SMALL LETTER O */ + {0x8290, 0xefbd90}, /* U+FF50 FULLWIDTH LATIN SMALL LETTER P */ + {0x8291, 0xefbd91}, /* U+FF51 FULLWIDTH LATIN SMALL LETTER Q */ + {0x8292, 0xefbd92}, /* U+FF52 FULLWIDTH LATIN SMALL LETTER R */ + {0x8293, 0xefbd93}, /* U+FF53 FULLWIDTH LATIN SMALL LETTER S */ + {0x8294, 0xefbd94}, /* U+FF54 FULLWIDTH LATIN SMALL LETTER T */ + {0x8295, 0xefbd95}, /* U+FF55 FULLWIDTH LATIN SMALL LETTER U */ + {0x8296, 0xefbd96}, /* U+FF56 FULLWIDTH LATIN SMALL LETTER V */ + {0x8297, 0xefbd97}, /* U+FF57 FULLWIDTH LATIN SMALL LETTER W */ + {0x8298, 0xefbd98}, /* U+FF58 FULLWIDTH LATIN SMALL LETTER X */ + {0x8299, 0xefbd99}, /* U+FF59 FULLWIDTH LATIN SMALL LETTER Y */ + {0x829a, 0xefbd9a}, /* U+FF5A FULLWIDTH LATIN SMALL LETTER Z */ + {0x829b, 0xe382a0}, /* U+30A0 KATAKANA-HIRAGANA DOUBLE HYPHEN [2000] [Unicode3.2] */ + {0x829c, 0xe28093}, /* U+2013 EN DASH [2000] */ + {0x829d, 0xe2a7ba}, /* U+29FA DOUBLE PLUS [2000] [Unicode3.2] */ + {0x829e, 0xe2a7bb}, /* U+29FB TRIPLE PLUS [2000] [Unicode3.2] */ + {0x829f, 0xe38181}, /* U+3041 HIRAGANA LETTER SMALL A */ + {0x82a0, 0xe38182}, /* U+3042 HIRAGANA LETTER A */ + {0x82a1, 0xe38183}, /* U+3043 HIRAGANA LETTER SMALL I */ + {0x82a2, 0xe38184}, /* U+3044 HIRAGANA LETTER I */ + {0x82a3, 0xe38185}, /* U+3045 HIRAGANA LETTER SMALL U */ + {0x82a4, 0xe38186}, /* U+3046 HIRAGANA LETTER U */ + {0x82a5, 0xe38187}, /* U+3047 HIRAGANA LETTER SMALL E */ + {0x82a6, 0xe38188}, /* U+3048 HIRAGANA LETTER E */ + {0x82a7, 0xe38189}, /* U+3049 HIRAGANA LETTER SMALL O */ + {0x82a8, 0xe3818a}, /* U+304A HIRAGANA LETTER O */ + {0x82a9, 0xe3818b}, /* U+304B HIRAGANA LETTER KA */ + {0x82aa, 0xe3818c}, /* U+304C HIRAGANA LETTER GA */ + {0x82ab, 0xe3818d}, /* U+304D HIRAGANA LETTER KI */ + {0x82ac, 0xe3818e}, /* U+304E HIRAGANA LETTER GI */ + {0x82ad, 0xe3818f}, /* U+304F HIRAGANA LETTER KU */ + {0x82ae, 0xe38190}, /* U+3050 HIRAGANA LETTER GU */ + {0x82af, 0xe38191}, /* U+3051 HIRAGANA LETTER KE */ + {0x82b0, 0xe38192}, /* U+3052 HIRAGANA LETTER GE */ + {0x82b1, 0xe38193}, /* U+3053 HIRAGANA LETTER KO */ + {0x82b2, 0xe38194}, /* U+3054 HIRAGANA LETTER GO */ + {0x82b3, 0xe38195}, /* U+3055 HIRAGANA LETTER SA */ + {0x82b4, 0xe38196}, /* U+3056 HIRAGANA LETTER ZA */ + {0x82b5, 0xe38197}, /* U+3057 HIRAGANA LETTER SI */ + {0x82b6, 0xe38198}, /* U+3058 HIRAGANA LETTER ZI */ + {0x82b7, 0xe38199}, /* U+3059 HIRAGANA LETTER SU */ + {0x82b8, 0xe3819a}, /* U+305A HIRAGANA LETTER ZU */ + {0x82b9, 0xe3819b}, /* U+305B HIRAGANA LETTER SE */ + {0x82ba, 0xe3819c}, /* U+305C HIRAGANA LETTER ZE */ + {0x82bb, 0xe3819d}, /* U+305D HIRAGANA LETTER SO */ + {0x82bc, 0xe3819e}, /* U+305E HIRAGANA LETTER ZO */ + {0x82bd, 0xe3819f}, /* U+305F HIRAGANA LETTER TA */ + {0x82be, 0xe381a0}, /* U+3060 HIRAGANA LETTER DA */ + {0x82bf, 0xe381a1}, /* U+3061 HIRAGANA LETTER TI */ + {0x82c0, 0xe381a2}, /* U+3062 HIRAGANA LETTER DI */ + {0x82c1, 0xe381a3}, /* U+3063 HIRAGANA LETTER SMALL TU */ + {0x82c2, 0xe381a4}, /* U+3064 HIRAGANA LETTER TU */ + {0x82c3, 0xe381a5}, /* U+3065 HIRAGANA LETTER DU */ + {0x82c4, 0xe381a6}, /* U+3066 HIRAGANA LETTER TE */ + {0x82c5, 0xe381a7}, /* U+3067 HIRAGANA LETTER DE */ + {0x82c6, 0xe381a8}, /* U+3068 HIRAGANA LETTER TO */ + {0x82c7, 0xe381a9}, /* U+3069 HIRAGANA LETTER DO */ + {0x82c8, 0xe381aa}, /* U+306A HIRAGANA LETTER NA */ + {0x82c9, 0xe381ab}, /* U+306B HIRAGANA LETTER NI */ + {0x82ca, 0xe381ac}, /* U+306C HIRAGANA LETTER NU */ + {0x82cb, 0xe381ad}, /* U+306D HIRAGANA LETTER NE */ + {0x82cc, 0xe381ae}, /* U+306E HIRAGANA LETTER NO */ + {0x82cd, 0xe381af}, /* U+306F HIRAGANA LETTER HA */ + {0x82ce, 0xe381b0}, /* U+3070 HIRAGANA LETTER BA */ + {0x82cf, 0xe381b1}, /* U+3071 HIRAGANA LETTER PA */ + {0x82d0, 0xe381b2}, /* U+3072 HIRAGANA LETTER HI */ + {0x82d1, 0xe381b3}, /* U+3073 HIRAGANA LETTER BI */ + {0x82d2, 0xe381b4}, /* U+3074 HIRAGANA LETTER PI */ + {0x82d3, 0xe381b5}, /* U+3075 HIRAGANA LETTER HU */ + {0x82d4, 0xe381b6}, /* U+3076 HIRAGANA LETTER BU */ + {0x82d5, 0xe381b7}, /* U+3077 HIRAGANA LETTER PU */ + {0x82d6, 0xe381b8}, /* U+3078 HIRAGANA LETTER HE */ + {0x82d7, 0xe381b9}, /* U+3079 HIRAGANA LETTER BE */ + {0x82d8, 0xe381ba}, /* U+307A HIRAGANA LETTER PE */ + {0x82d9, 0xe381bb}, /* U+307B HIRAGANA LETTER HO */ + {0x82da, 0xe381bc}, /* U+307C HIRAGANA LETTER BO */ + {0x82db, 0xe381bd}, /* U+307D HIRAGANA LETTER PO */ + {0x82dc, 0xe381be}, /* U+307E HIRAGANA LETTER MA */ + {0x82dd, 0xe381bf}, /* U+307F HIRAGANA LETTER MI */ + {0x82de, 0xe38280}, /* U+3080 HIRAGANA LETTER MU */ + {0x82df, 0xe38281}, /* U+3081 HIRAGANA LETTER ME */ + {0x82e0, 0xe38282}, /* U+3082 HIRAGANA LETTER MO */ + {0x82e1, 0xe38283}, /* U+3083 HIRAGANA LETTER SMALL YA */ + {0x82e2, 0xe38284}, /* U+3084 HIRAGANA LETTER YA */ + {0x82e3, 0xe38285}, /* U+3085 HIRAGANA LETTER SMALL YU */ + {0x82e4, 0xe38286}, /* U+3086 HIRAGANA LETTER YU */ + {0x82e5, 0xe38287}, /* U+3087 HIRAGANA LETTER SMALL YO */ + {0x82e6, 0xe38288}, /* U+3088 HIRAGANA LETTER YO */ + {0x82e7, 0xe38289}, /* U+3089 HIRAGANA LETTER RA */ + {0x82e8, 0xe3828a}, /* U+308A HIRAGANA LETTER RI */ + {0x82e9, 0xe3828b}, /* U+308B HIRAGANA LETTER RU */ + {0x82ea, 0xe3828c}, /* U+308C HIRAGANA LETTER RE */ + {0x82eb, 0xe3828d}, /* U+308D HIRAGANA LETTER RO */ + {0x82ec, 0xe3828e}, /* U+308E HIRAGANA LETTER SMALL WA */ + {0x82ed, 0xe3828f}, /* U+308F HIRAGANA LETTER WA */ + {0x82ee, 0xe38290}, /* U+3090 HIRAGANA LETTER WI */ + {0x82ef, 0xe38291}, /* U+3091 HIRAGANA LETTER WE */ + {0x82f0, 0xe38292}, /* U+3092 HIRAGANA LETTER WO */ + {0x82f1, 0xe38293}, /* U+3093 HIRAGANA LETTER N */ + {0x82f2, 0xe38294}, /* U+3094 HIRAGANA LETTER VU [2000] */ + {0x82f3, 0xe38295}, /* U+3095 HIRAGANA LETTER SMALL KA [2000] [Unicode3.2] */ + {0x82f4, 0xe38296}, /* U+3096 HIRAGANA LETTER SMALL KE [2000] [Unicode3.2] */ + {0x8340, 0xe382a1}, /* U+30A1 KATAKANA LETTER SMALL A */ + {0x8341, 0xe382a2}, /* U+30A2 KATAKANA LETTER A */ + {0x8342, 0xe382a3}, /* U+30A3 KATAKANA LETTER SMALL I */ + {0x8343, 0xe382a4}, /* U+30A4 KATAKANA LETTER I */ + {0x8344, 0xe382a5}, /* U+30A5 KATAKANA LETTER SMALL U */ + {0x8345, 0xe382a6}, /* U+30A6 KATAKANA LETTER U */ + {0x8346, 0xe382a7}, /* U+30A7 KATAKANA LETTER SMALL E */ + {0x8347, 0xe382a8}, /* U+30A8 KATAKANA LETTER E */ + {0x8348, 0xe382a9}, /* U+30A9 KATAKANA LETTER SMALL O */ + {0x8349, 0xe382aa}, /* U+30AA KATAKANA LETTER O */ + {0x834a, 0xe382ab}, /* U+30AB KATAKANA LETTER KA */ + {0x834b, 0xe382ac}, /* U+30AC KATAKANA LETTER GA */ + {0x834c, 0xe382ad}, /* U+30AD KATAKANA LETTER KI */ + {0x834d, 0xe382ae}, /* U+30AE KATAKANA LETTER GI */ + {0x834e, 0xe382af}, /* U+30AF KATAKANA LETTER KU */ + {0x834f, 0xe382b0}, /* U+30B0 KATAKANA LETTER GU */ + {0x8350, 0xe382b1}, /* U+30B1 KATAKANA LETTER KE */ + {0x8351, 0xe382b2}, /* U+30B2 KATAKANA LETTER GE */ + {0x8352, 0xe382b3}, /* U+30B3 KATAKANA LETTER KO */ + {0x8353, 0xe382b4}, /* U+30B4 KATAKANA LETTER GO */ + {0x8354, 0xe382b5}, /* U+30B5 KATAKANA LETTER SA */ + {0x8355, 0xe382b6}, /* U+30B6 KATAKANA LETTER ZA */ + {0x8356, 0xe382b7}, /* U+30B7 KATAKANA LETTER SI */ + {0x8357, 0xe382b8}, /* U+30B8 KATAKANA LETTER ZI */ + {0x8358, 0xe382b9}, /* U+30B9 KATAKANA LETTER SU */ + {0x8359, 0xe382ba}, /* U+30BA KATAKANA LETTER ZU */ + {0x835a, 0xe382bb}, /* U+30BB KATAKANA LETTER SE */ + {0x835b, 0xe382bc}, /* U+30BC KATAKANA LETTER ZE */ + {0x835c, 0xe382bd}, /* U+30BD KATAKANA LETTER SO */ + {0x835d, 0xe382be}, /* U+30BE KATAKANA LETTER ZO */ + {0x835e, 0xe382bf}, /* U+30BF KATAKANA LETTER TA */ + {0x835f, 0xe38380}, /* U+30C0 KATAKANA LETTER DA */ + {0x8360, 0xe38381}, /* U+30C1 KATAKANA LETTER TI */ + {0x8361, 0xe38382}, /* U+30C2 KATAKANA LETTER DI */ + {0x8362, 0xe38383}, /* U+30C3 KATAKANA LETTER SMALL TU */ + {0x8363, 0xe38384}, /* U+30C4 KATAKANA LETTER TU */ + {0x8364, 0xe38385}, /* U+30C5 KATAKANA LETTER DU */ + {0x8365, 0xe38386}, /* U+30C6 KATAKANA LETTER TE */ + {0x8366, 0xe38387}, /* U+30C7 KATAKANA LETTER DE */ + {0x8367, 0xe38388}, /* U+30C8 KATAKANA LETTER TO */ + {0x8368, 0xe38389}, /* U+30C9 KATAKANA LETTER DO */ + {0x8369, 0xe3838a}, /* U+30CA KATAKANA LETTER NA */ + {0x836a, 0xe3838b}, /* U+30CB KATAKANA LETTER NI */ + {0x836b, 0xe3838c}, /* U+30CC KATAKANA LETTER NU */ + {0x836c, 0xe3838d}, /* U+30CD KATAKANA LETTER NE */ + {0x836d, 0xe3838e}, /* U+30CE KATAKANA LETTER NO */ + {0x836e, 0xe3838f}, /* U+30CF KATAKANA LETTER HA */ + {0x836f, 0xe38390}, /* U+30D0 KATAKANA LETTER BA */ + {0x8370, 0xe38391}, /* U+30D1 KATAKANA LETTER PA */ + {0x8371, 0xe38392}, /* U+30D2 KATAKANA LETTER HI */ + {0x8372, 0xe38393}, /* U+30D3 KATAKANA LETTER BI */ + {0x8373, 0xe38394}, /* U+30D4 KATAKANA LETTER PI */ + {0x8374, 0xe38395}, /* U+30D5 KATAKANA LETTER HU */ + {0x8375, 0xe38396}, /* U+30D6 KATAKANA LETTER BU */ + {0x8376, 0xe38397}, /* U+30D7 KATAKANA LETTER PU */ + {0x8377, 0xe38398}, /* U+30D8 KATAKANA LETTER HE */ + {0x8378, 0xe38399}, /* U+30D9 KATAKANA LETTER BE */ + {0x8379, 0xe3839a}, /* U+30DA KATAKANA LETTER PE */ + {0x837a, 0xe3839b}, /* U+30DB KATAKANA LETTER HO */ + {0x837b, 0xe3839c}, /* U+30DC KATAKANA LETTER BO */ + {0x837c, 0xe3839d}, /* U+30DD KATAKANA LETTER PO */ + {0x837d, 0xe3839e}, /* U+30DE KATAKANA LETTER MA */ + {0x837e, 0xe3839f}, /* U+30DF KATAKANA LETTER MI */ + {0x8380, 0xe383a0}, /* U+30E0 KATAKANA LETTER MU */ + {0x8381, 0xe383a1}, /* U+30E1 KATAKANA LETTER ME */ + {0x8382, 0xe383a2}, /* U+30E2 KATAKANA LETTER MO */ + {0x8383, 0xe383a3}, /* U+30E3 KATAKANA LETTER SMALL YA */ + {0x8384, 0xe383a4}, /* U+30E4 KATAKANA LETTER YA */ + {0x8385, 0xe383a5}, /* U+30E5 KATAKANA LETTER SMALL YU */ + {0x8386, 0xe383a6}, /* U+30E6 KATAKANA LETTER YU */ + {0x8387, 0xe383a7}, /* U+30E7 KATAKANA LETTER SMALL YO */ + {0x8388, 0xe383a8}, /* U+30E8 KATAKANA LETTER YO */ + {0x8389, 0xe383a9}, /* U+30E9 KATAKANA LETTER RA */ + {0x838a, 0xe383aa}, /* U+30EA KATAKANA LETTER RI */ + {0x838b, 0xe383ab}, /* U+30EB KATAKANA LETTER RU */ + {0x838c, 0xe383ac}, /* U+30EC KATAKANA LETTER RE */ + {0x838d, 0xe383ad}, /* U+30ED KATAKANA LETTER RO */ + {0x838e, 0xe383ae}, /* U+30EE KATAKANA LETTER SMALL WA */ + {0x838f, 0xe383af}, /* U+30EF KATAKANA LETTER WA */ + {0x8390, 0xe383b0}, /* U+30F0 KATAKANA LETTER WI */ + {0x8391, 0xe383b1}, /* U+30F1 KATAKANA LETTER WE */ + {0x8392, 0xe383b2}, /* U+30F2 KATAKANA LETTER WO */ + {0x8393, 0xe383b3}, /* U+30F3 KATAKANA LETTER N */ + {0x8394, 0xe383b4}, /* U+30F4 KATAKANA LETTER VU */ + {0x8395, 0xe383b5}, /* U+30F5 KATAKANA LETTER SMALL KA */ + {0x8396, 0xe383b6}, /* U+30F6 KATAKANA LETTER SMALL KE */ + {0x839f, 0xce91}, /* U+0391 GREEK CAPITAL LETTER ALPHA */ + {0x83a0, 0xce92}, /* U+0392 GREEK CAPITAL LETTER BETA */ + {0x83a1, 0xce93}, /* U+0393 GREEK CAPITAL LETTER GAMMA */ + {0x83a2, 0xce94}, /* U+0394 GREEK CAPITAL LETTER DELTA */ + {0x83a3, 0xce95}, /* U+0395 GREEK CAPITAL LETTER EPSILON */ + {0x83a4, 0xce96}, /* U+0396 GREEK CAPITAL LETTER ZETA */ + {0x83a5, 0xce97}, /* U+0397 GREEK CAPITAL LETTER ETA */ + {0x83a6, 0xce98}, /* U+0398 GREEK CAPITAL LETTER THETA */ + {0x83a7, 0xce99}, /* U+0399 GREEK CAPITAL LETTER IOTA */ + {0x83a8, 0xce9a}, /* U+039A GREEK CAPITAL LETTER KAPPA */ + {0x83a9, 0xce9b}, /* U+039B GREEK CAPITAL LETTER LAMDA */ + {0x83aa, 0xce9c}, /* U+039C GREEK CAPITAL LETTER MU */ + {0x83ab, 0xce9d}, /* U+039D GREEK CAPITAL LETTER NU */ + {0x83ac, 0xce9e}, /* U+039E GREEK CAPITAL LETTER XI */ + {0x83ad, 0xce9f}, /* U+039F GREEK CAPITAL LETTER OMICRON */ + {0x83ae, 0xcea0}, /* U+03A0 GREEK CAPITAL LETTER PI */ + {0x83af, 0xcea1}, /* U+03A1 GREEK CAPITAL LETTER RHO */ + {0x83b0, 0xcea3}, /* U+03A3 GREEK CAPITAL LETTER SIGMA */ + {0x83b1, 0xcea4}, /* U+03A4 GREEK CAPITAL LETTER TAU */ + {0x83b2, 0xcea5}, /* U+03A5 GREEK CAPITAL LETTER UPSILON */ + {0x83b3, 0xcea6}, /* U+03A6 GREEK CAPITAL LETTER PHI */ + {0x83b4, 0xcea7}, /* U+03A7 GREEK CAPITAL LETTER CHI */ + {0x83b5, 0xcea8}, /* U+03A8 GREEK CAPITAL LETTER PSI */ + {0x83b6, 0xcea9}, /* U+03A9 GREEK CAPITAL LETTER OMEGA */ + {0x83b7, 0xe299a4}, /* U+2664 WHITE SPADE SUIT [2000] */ + {0x83b8, 0xe299a0}, /* U+2660 BLACK SPADE SUIT [2000] */ + {0x83b9, 0xe299a2}, /* U+2662 WHITE DIAMOND SUIT [2000] */ + {0x83ba, 0xe299a6}, /* U+2666 BLACK DIAMOND SUIT [2000] */ + {0x83bb, 0xe299a1}, /* U+2661 WHITE HEART SUIT [2000] */ + {0x83bc, 0xe299a5}, /* U+2665 BLACK HEART SUIT [2000] */ + {0x83bd, 0xe299a7}, /* U+2667 WHITE CLUB SUIT [2000] */ + {0x83be, 0xe299a3}, /* U+2663 BLACK CLUB SUIT [2000] */ + {0x83bf, 0xceb1}, /* U+03B1 GREEK SMALL LETTER ALPHA */ + {0x83c0, 0xceb2}, /* U+03B2 GREEK SMALL LETTER BETA */ + {0x83c1, 0xceb3}, /* U+03B3 GREEK SMALL LETTER GAMMA */ + {0x83c2, 0xceb4}, /* U+03B4 GREEK SMALL LETTER DELTA */ + {0x83c3, 0xceb5}, /* U+03B5 GREEK SMALL LETTER EPSILON */ + {0x83c4, 0xceb6}, /* U+03B6 GREEK SMALL LETTER ZETA */ + {0x83c5, 0xceb7}, /* U+03B7 GREEK SMALL LETTER ETA */ + {0x83c6, 0xceb8}, /* U+03B8 GREEK SMALL LETTER THETA */ + {0x83c7, 0xceb9}, /* U+03B9 GREEK SMALL LETTER IOTA */ + {0x83c8, 0xceba}, /* U+03BA GREEK SMALL LETTER KAPPA */ + {0x83c9, 0xcebb}, /* U+03BB GREEK SMALL LETTER LAMDA */ + {0x83ca, 0xcebc}, /* U+03BC GREEK SMALL LETTER MU */ + {0x83cb, 0xcebd}, /* U+03BD GREEK SMALL LETTER NU */ + {0x83cc, 0xcebe}, /* U+03BE GREEK SMALL LETTER XI */ + {0x83cd, 0xcebf}, /* U+03BF GREEK SMALL LETTER OMICRON */ + {0x83ce, 0xcf80}, /* U+03C0 GREEK SMALL LETTER PI */ + {0x83cf, 0xcf81}, /* U+03C1 GREEK SMALL LETTER RHO */ + {0x83d0, 0xcf83}, /* U+03C3 GREEK SMALL LETTER SIGMA */ + {0x83d1, 0xcf84}, /* U+03C4 GREEK SMALL LETTER TAU */ + {0x83d2, 0xcf85}, /* U+03C5 GREEK SMALL LETTER UPSILON */ + {0x83d3, 0xcf86}, /* U+03C6 GREEK SMALL LETTER PHI */ + {0x83d4, 0xcf87}, /* U+03C7 GREEK SMALL LETTER CHI */ + {0x83d5, 0xcf88}, /* U+03C8 GREEK SMALL LETTER PSI */ + {0x83d6, 0xcf89}, /* U+03C9 GREEK SMALL LETTER OMEGA */ + {0x83d7, 0xcf82}, /* U+03C2 GREEK SMALL LETTER FINAL SIGMA [2000] */ + {0x83d8, 0xe293b5}, /* U+24F5 DOUBLE CIRCLED DIGIT ONE [2000] [Unicode3.2] */ + {0x83d9, 0xe293b6}, /* U+24F6 DOUBLE CIRCLED DIGIT TWO [2000] [Unicode3.2] */ + {0x83da, 0xe293b7}, /* U+24F7 DOUBLE CIRCLED DIGIT THREE [2000] [Unicode3.2] */ + {0x83db, 0xe293b8}, /* U+24F8 DOUBLE CIRCLED DIGIT FOUR [2000] [Unicode3.2] */ + {0x83dc, 0xe293b9}, /* U+24F9 DOUBLE CIRCLED DIGIT FIVE [2000] [Unicode3.2] */ + {0x83dd, 0xe293ba}, /* U+24FA DOUBLE CIRCLED DIGIT SIX [2000] [Unicode3.2] */ + {0x83de, 0xe293bb}, /* U+24FB DOUBLE CIRCLED DIGIT SEVEN [2000] [Unicode3.2] */ + {0x83df, 0xe293bc}, /* U+24FC DOUBLE CIRCLED DIGIT EIGHT [2000] [Unicode3.2] */ + {0x83e0, 0xe293bd}, /* U+24FD DOUBLE CIRCLED DIGIT NINE [2000] [Unicode3.2] */ + {0x83e1, 0xe293be}, /* U+24FE DOUBLE CIRCLED NUMBER TEN [2000] [Unicode3.2] */ + {0x83e2, 0xe29896}, /* U+2616 WHITE SHOGI PIECE [2000] [Unicode3.2] */ + {0x83e3, 0xe29897}, /* U+2617 BLACK SHOGI PIECE [2000] [Unicode3.2] */ + {0x83e4, 0xe380a0}, /* U+3020 POSTAL MARK FACE [2000] */ + {0x83e5, 0xe2988e}, /* U+260E BLACK TELEPHONE [2000] */ + {0x83e6, 0xe29880}, /* U+2600 BLACK SUN WITH RAYS [2000] */ + {0x83e7, 0xe29881}, /* U+2601 CLOUD [2000] */ + {0x83e8, 0xe29882}, /* U+2602 UMBRELLA [2000] */ + {0x83e9, 0xe29883}, /* U+2603 SNOWMAN [2000] */ + {0x83ea, 0xe299a8}, /* U+2668 HOT SPRINGS [2000] */ + {0x83eb, 0xe296b1}, /* U+25B1 WHITE PARALLELOGRAM [2000] */ + {0x83ec, 0xe387b0}, /* U+31F0 KATAKANA LETTER SMALL KU [2000] [Unicode3.2] */ + {0x83ed, 0xe387b1}, /* U+31F1 KATAKANA LETTER SMALL SI [2000] [Unicode3.2] */ + {0x83ee, 0xe387b2}, /* U+31F2 KATAKANA LETTER SMALL SU [2000] [Unicode3.2] */ + {0x83ef, 0xe387b3}, /* U+31F3 KATAKANA LETTER SMALL TO [2000] [Unicode3.2] */ + {0x83f0, 0xe387b4}, /* U+31F4 KATAKANA LETTER SMALL NU [2000] [Unicode3.2] */ + {0x83f1, 0xe387b5}, /* U+31F5 KATAKANA LETTER SMALL HA [2000] [Unicode3.2] */ + {0x83f2, 0xe387b6}, /* U+31F6 KATAKANA LETTER SMALL HI [2000] [Unicode3.2] */ + {0x83f3, 0xe387b7}, /* U+31F7 KATAKANA LETTER SMALL HU [2000] [Unicode3.2] */ + {0x83f4, 0xe387b8}, /* U+31F8 KATAKANA LETTER SMALL HE [2000] [Unicode3.2] */ + {0x83f5, 0xe387b9}, /* U+31F9 KATAKANA LETTER SMALL HO [2000] [Unicode3.2] */ + {0x83f7, 0xe387ba}, /* U+31FA KATAKANA LETTER SMALL MU [2000] [Unicode3.2] */ + {0x83f8, 0xe387bb}, /* U+31FB KATAKANA LETTER SMALL RA [2000] [Unicode3.2] */ + {0x83f9, 0xe387bc}, /* U+31FC KATAKANA LETTER SMALL RI [2000] [Unicode3.2] */ + {0x83fa, 0xe387bd}, /* U+31FD KATAKANA LETTER SMALL RU [2000] [Unicode3.2] */ + {0x83fb, 0xe387be}, /* U+31FE KATAKANA LETTER SMALL RE [2000] [Unicode3.2] */ + {0x83fc, 0xe387bf}, /* U+31FF KATAKANA LETTER SMALL RO [2000] [Unicode3.2] */ + {0x8440, 0xd090}, /* U+0410 CYRILLIC CAPITAL LETTER A */ + {0x8441, 0xd091}, /* U+0411 CYRILLIC CAPITAL LETTER BE */ + {0x8442, 0xd092}, /* U+0412 CYRILLIC CAPITAL LETTER VE */ + {0x8443, 0xd093}, /* U+0413 CYRILLIC CAPITAL LETTER GHE */ + {0x8444, 0xd094}, /* U+0414 CYRILLIC CAPITAL LETTER DE */ + {0x8445, 0xd095}, /* U+0415 CYRILLIC CAPITAL LETTER IE */ + {0x8446, 0xd081}, /* U+0401 CYRILLIC CAPITAL LETTER IO */ + {0x8447, 0xd096}, /* U+0416 CYRILLIC CAPITAL LETTER ZHE */ + {0x8448, 0xd097}, /* U+0417 CYRILLIC CAPITAL LETTER ZE */ + {0x8449, 0xd098}, /* U+0418 CYRILLIC CAPITAL LETTER I */ + {0x844a, 0xd099}, /* U+0419 CYRILLIC CAPITAL LETTER SHORT I */ + {0x844b, 0xd09a}, /* U+041A CYRILLIC CAPITAL LETTER KA */ + {0x844c, 0xd09b}, /* U+041B CYRILLIC CAPITAL LETTER EL */ + {0x844d, 0xd09c}, /* U+041C CYRILLIC CAPITAL LETTER EM */ + {0x844e, 0xd09d}, /* U+041D CYRILLIC CAPITAL LETTER EN */ + {0x844f, 0xd09e}, /* U+041E CYRILLIC CAPITAL LETTER O */ + {0x8450, 0xd09f}, /* U+041F CYRILLIC CAPITAL LETTER PE */ + {0x8451, 0xd0a0}, /* U+0420 CYRILLIC CAPITAL LETTER ER */ + {0x8452, 0xd0a1}, /* U+0421 CYRILLIC CAPITAL LETTER ES */ + {0x8453, 0xd0a2}, /* U+0422 CYRILLIC CAPITAL LETTER TE */ + {0x8454, 0xd0a3}, /* U+0423 CYRILLIC CAPITAL LETTER U */ + {0x8455, 0xd0a4}, /* U+0424 CYRILLIC CAPITAL LETTER EF */ + {0x8456, 0xd0a5}, /* U+0425 CYRILLIC CAPITAL LETTER HA */ + {0x8457, 0xd0a6}, /* U+0426 CYRILLIC CAPITAL LETTER TSE */ + {0x8458, 0xd0a7}, /* U+0427 CYRILLIC CAPITAL LETTER CHE */ + {0x8459, 0xd0a8}, /* U+0428 CYRILLIC CAPITAL LETTER SHA */ + {0x845a, 0xd0a9}, /* U+0429 CYRILLIC CAPITAL LETTER SHCHA */ + {0x845b, 0xd0aa}, /* U+042A CYRILLIC CAPITAL LETTER HARD SIGN */ + {0x845c, 0xd0ab}, /* U+042B CYRILLIC CAPITAL LETTER YERU */ + {0x845d, 0xd0ac}, /* U+042C CYRILLIC CAPITAL LETTER SOFT SIGN */ + {0x845e, 0xd0ad}, /* U+042D CYRILLIC CAPITAL LETTER E */ + {0x845f, 0xd0ae}, /* U+042E CYRILLIC CAPITAL LETTER YU */ + {0x8460, 0xd0af}, /* U+042F CYRILLIC CAPITAL LETTER YA */ + {0x8461, 0xe28ebe}, /* U+23BE DENTISTRY SYMBOL LIGHT VERTICAL AND TOP RIGHT [2000] [Unicode3.2] */ + {0x8462, 0xe28ebf}, /* U+23BF DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM RIGHT [2000] [Unicode3.2] */ + {0x8463, 0xe28f80}, /* U+23C0 DENTISTRY SYMBOL LIGHT VERTICAL WITH CIRCLE [2000] [Unicode3.2] */ + {0x8464, 0xe28f81}, /* U+23C1 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH CIRCLE [2000] [Unicode3.2] */ + {0x8465, 0xe28f82}, /* U+23C2 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLE [2000] [Unicode3.2] */ + {0x8466, 0xe28f83}, /* U+23C3 DENTISTRY SYMBOL LIGHT VERTICAL WITH TRIANGLE [2000] [Unicode3.2] */ + {0x8467, 0xe28f84}, /* U+23C4 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH TRIANGLE [2000] [Unicode3.2] */ + {0x8468, 0xe28f85}, /* U+23C5 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH TRIANGLE [2000] [Unicode3.2] */ + {0x8469, 0xe28f86}, /* U+23C6 DENTISTRY SYMBOL LIGHT VERTICAL AND WAVE [2000] [Unicode3.2] */ + {0x846a, 0xe28f87}, /* U+23C7 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH WAVE [2000] [Unicode3.2] */ + {0x846b, 0xe28f88}, /* U+23C8 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH WAVE [2000] [Unicode3.2] */ + {0x846c, 0xe28f89}, /* U+23C9 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL [2000] [Unicode3.2] */ + {0x846d, 0xe28f8a}, /* U+23CA DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL [2000] [Unicode3.2] */ + {0x846e, 0xe28f8b}, /* U+23CB DENTISTRY SYMBOL LIGHT VERTICAL AND TOP LEFT [2000] [Unicode3.2] */ + {0x846f, 0xe28f8c}, /* U+23CC DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM LEFT [2000] [Unicode3.2] */ + {0x8470, 0xd0b0}, /* U+0430 CYRILLIC SMALL LETTER A */ + {0x8471, 0xd0b1}, /* U+0431 CYRILLIC SMALL LETTER BE */ + {0x8472, 0xd0b2}, /* U+0432 CYRILLIC SMALL LETTER VE */ + {0x8473, 0xd0b3}, /* U+0433 CYRILLIC SMALL LETTER GHE */ + {0x8474, 0xd0b4}, /* U+0434 CYRILLIC SMALL LETTER DE */ + {0x8475, 0xd0b5}, /* U+0435 CYRILLIC SMALL LETTER IE */ + {0x8476, 0xd191}, /* U+0451 CYRILLIC SMALL LETTER IO */ + {0x8477, 0xd0b6}, /* U+0436 CYRILLIC SMALL LETTER ZHE */ + {0x8478, 0xd0b7}, /* U+0437 CYRILLIC SMALL LETTER ZE */ + {0x8479, 0xd0b8}, /* U+0438 CYRILLIC SMALL LETTER I */ + {0x847a, 0xd0b9}, /* U+0439 CYRILLIC SMALL LETTER SHORT I */ + {0x847b, 0xd0ba}, /* U+043A CYRILLIC SMALL LETTER KA */ + {0x847c, 0xd0bb}, /* U+043B CYRILLIC SMALL LETTER EL */ + {0x847d, 0xd0bc}, /* U+043C CYRILLIC SMALL LETTER EM */ + {0x847e, 0xd0bd}, /* U+043D CYRILLIC SMALL LETTER EN */ + {0x8480, 0xd0be}, /* U+043E CYRILLIC SMALL LETTER O */ + {0x8481, 0xd0bf}, /* U+043F CYRILLIC SMALL LETTER PE */ + {0x8482, 0xd180}, /* U+0440 CYRILLIC SMALL LETTER ER */ + {0x8483, 0xd181}, /* U+0441 CYRILLIC SMALL LETTER ES */ + {0x8484, 0xd182}, /* U+0442 CYRILLIC SMALL LETTER TE */ + {0x8485, 0xd183}, /* U+0443 CYRILLIC SMALL LETTER U */ + {0x8486, 0xd184}, /* U+0444 CYRILLIC SMALL LETTER EF */ + {0x8487, 0xd185}, /* U+0445 CYRILLIC SMALL LETTER HA */ + {0x8488, 0xd186}, /* U+0446 CYRILLIC SMALL LETTER TSE */ + {0x8489, 0xd187}, /* U+0447 CYRILLIC SMALL LETTER CHE */ + {0x848a, 0xd188}, /* U+0448 CYRILLIC SMALL LETTER SHA */ + {0x848b, 0xd189}, /* U+0449 CYRILLIC SMALL LETTER SHCHA */ + {0x848c, 0xd18a}, /* U+044A CYRILLIC SMALL LETTER HARD SIGN */ + {0x848d, 0xd18b}, /* U+044B CYRILLIC SMALL LETTER YERU */ + {0x848e, 0xd18c}, /* U+044C CYRILLIC SMALL LETTER SOFT SIGN */ + {0x848f, 0xd18d}, /* U+044D CYRILLIC SMALL LETTER E */ + {0x8490, 0xd18e}, /* U+044E CYRILLIC SMALL LETTER YU */ + {0x8491, 0xd18f}, /* U+044F CYRILLIC SMALL LETTER YA */ + {0x8492, 0xe383b7}, /* U+30F7 KATAKANA LETTER VA [2000] */ + {0x8493, 0xe383b8}, /* U+30F8 KATAKANA LETTER VI [2000] */ + {0x8494, 0xe383b9}, /* U+30F9 KATAKANA LETTER VE [2000] */ + {0x8495, 0xe383ba}, /* U+30FA KATAKANA LETTER VO [2000] */ + {0x8496, 0xe28b9a}, /* U+22DA LESS-THAN EQUAL TO OR GREATER-THAN [2000] */ + {0x8497, 0xe28b9b}, /* U+22DB GREATER-THAN EQUAL TO OR LESS-THAN [2000] */ + {0x8498, 0xe28593}, /* U+2153 VULGAR FRACTION ONE THIRD [2000] */ + {0x8499, 0xe28594}, /* U+2154 VULGAR FRACTION TWO THIRDS [2000] */ + {0x849a, 0xe28595}, /* U+2155 VULGAR FRACTION ONE FIFTH [2000] */ + {0x849b, 0xe29c93}, /* U+2713 CHECK MARK [2000] */ + {0x849c, 0xe28c98}, /* U+2318 PLACE OF INTEREST SIGN [2000] */ + {0x849d, 0xe290a3}, /* U+2423 OPEN BOX [2000] */ + {0x849e, 0xe28f8e}, /* U+23CE RETURN SYMBOL [2000] [Unicode3.2] */ + {0x849f, 0xe29480}, /* U+2500 BOX DRAWINGS LIGHT HORIZONTAL [1983] */ + {0x84a0, 0xe29482}, /* U+2502 BOX DRAWINGS LIGHT VERTICAL [1983] */ + {0x84a1, 0xe2948c}, /* U+250C BOX DRAWINGS LIGHT DOWN AND RIGHT [1983] */ + {0x84a2, 0xe29490}, /* U+2510 BOX DRAWINGS LIGHT DOWN AND LEFT [1983] */ + {0x84a3, 0xe29498}, /* U+2518 BOX DRAWINGS LIGHT UP AND LEFT [1983] */ + {0x84a4, 0xe29494}, /* U+2514 BOX DRAWINGS LIGHT UP AND RIGHT [1983] */ + {0x84a5, 0xe2949c}, /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT [1983] */ + {0x84a6, 0xe294ac}, /* U+252C BOX DRAWINGS LIGHT DOWN AND HORIZONTAL [1983] */ + {0x84a7, 0xe294a4}, /* U+2524 BOX DRAWINGS LIGHT VERTICAL AND LEFT [1983] */ + {0x84a8, 0xe294b4}, /* U+2534 BOX DRAWINGS LIGHT UP AND HORIZONTAL [1983] */ + {0x84a9, 0xe294bc}, /* U+253C BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL [1983] */ + {0x84aa, 0xe29481}, /* U+2501 BOX DRAWINGS HEAVY HORIZONTAL [1983] */ + {0x84ab, 0xe29483}, /* U+2503 BOX DRAWINGS HEAVY VERTICAL [1983] */ + {0x84ac, 0xe2948f}, /* U+250F BOX DRAWINGS HEAVY DOWN AND RIGHT [1983] */ + {0x84ad, 0xe29493}, /* U+2513 BOX DRAWINGS HEAVY DOWN AND LEFT [1983] */ + {0x84ae, 0xe2949b}, /* U+251B BOX DRAWINGS HEAVY UP AND LEFT [1983] */ + {0x84af, 0xe29497}, /* U+2517 BOX DRAWINGS HEAVY UP AND RIGHT [1983] */ + {0x84b0, 0xe294a3}, /* U+2523 BOX DRAWINGS HEAVY VERTICAL AND RIGHT [1983] */ + {0x84b1, 0xe294b3}, /* U+2533 BOX DRAWINGS HEAVY DOWN AND HORIZONTAL [1983] */ + {0x84b2, 0xe294ab}, /* U+252B BOX DRAWINGS HEAVY VERTICAL AND LEFT [1983] */ + {0x84b3, 0xe294bb}, /* U+253B BOX DRAWINGS HEAVY UP AND HORIZONTAL [1983] */ + {0x84b4, 0xe2958b}, /* U+254B BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL [1983] */ + {0x84b5, 0xe294a0}, /* U+2520 BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT [1983] */ + {0x84b6, 0xe294af}, /* U+252F BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY [1983] */ + {0x84b7, 0xe294a8}, /* U+2528 BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT [1983] */ + {0x84b8, 0xe294b7}, /* U+2537 BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY [1983] */ + {0x84b9, 0xe294bf}, /* U+253F BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY [1983] */ + {0x84ba, 0xe2949d}, /* U+251D BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY [1983] */ + {0x84bb, 0xe294b0}, /* U+2530 BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT [1983] */ + {0x84bc, 0xe294a5}, /* U+2525 BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY [1983] */ + {0x84bd, 0xe294b8}, /* U+2538 BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT [1983] */ + {0x84be, 0xe29582}, /* U+2542 BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT [1983] */ + {0x84bf, 0xe38991}, /* U+3251 CIRCLED NUMBER TWENTY ONE [2000] [Unicode3.2] */ + {0x84c0, 0xe38992}, /* U+3252 CIRCLED NUMBER TWENTY TWO [2000] [Unicode3.2] */ + {0x84c1, 0xe38993}, /* U+3253 CIRCLED NUMBER TWENTY THREE [2000] [Unicode3.2] */ + {0x84c2, 0xe38994}, /* U+3254 CIRCLED NUMBER TWENTY FOUR [2000] [Unicode3.2] */ + {0x84c3, 0xe38995}, /* U+3255 CIRCLED NUMBER TWENTY FIVE [2000] [Unicode3.2] */ + {0x84c4, 0xe38996}, /* U+3256 CIRCLED NUMBER TWENTY SIX [2000] [Unicode3.2] */ + {0x84c5, 0xe38997}, /* U+3257 CIRCLED NUMBER TWENTY SEVEN [2000] [Unicode3.2] */ + {0x84c6, 0xe38998}, /* U+3258 CIRCLED NUMBER TWENTY EIGHT [2000] [Unicode3.2] */ + {0x84c7, 0xe38999}, /* U+3259 CIRCLED NUMBER TWENTY NINE [2000] [Unicode3.2] */ + {0x84c8, 0xe3899a}, /* U+325A CIRCLED NUMBER THIRTY [2000] [Unicode3.2] */ + {0x84c9, 0xe3899b}, /* U+325B CIRCLED NUMBER THIRTY ONE [2000] [Unicode3.2] */ + {0x84ca, 0xe3899c}, /* U+325C CIRCLED NUMBER THIRTY TWO [2000] [Unicode3.2] */ + {0x84cb, 0xe3899d}, /* U+325D CIRCLED NUMBER THIRTY THREE [2000] [Unicode3.2] */ + {0x84cc, 0xe3899e}, /* U+325E CIRCLED NUMBER THIRTY FOUR [2000] [Unicode3.2] */ + {0x84cd, 0xe3899f}, /* U+325F CIRCLED NUMBER THIRTY FIVE [2000] [Unicode3.2] */ + {0x84ce, 0xe38ab1}, /* U+32B1 CIRCLED NUMBER THIRTY SIX [2000] [Unicode3.2] */ + {0x84cf, 0xe38ab2}, /* U+32B2 CIRCLED NUMBER THIRTY SEVEN [2000] [Unicode3.2] */ + {0x84d0, 0xe38ab3}, /* U+32B3 CIRCLED NUMBER THIRTY EIGHT [2000] [Unicode3.2] */ + {0x84d1, 0xe38ab4}, /* U+32B4 CIRCLED NUMBER THIRTY NINE [2000] [Unicode3.2] */ + {0x84d2, 0xe38ab5}, /* U+32B5 CIRCLED NUMBER FORTY [2000] [Unicode3.2] */ + {0x84d3, 0xe38ab6}, /* U+32B6 CIRCLED NUMBER FORTY ONE [2000] [Unicode3.2] */ + {0x84d4, 0xe38ab7}, /* U+32B7 CIRCLED NUMBER FORTY TWO [2000] [Unicode3.2] */ + {0x84d5, 0xe38ab8}, /* U+32B8 CIRCLED NUMBER FORTY THREE [2000] [Unicode3.2] */ + {0x84d6, 0xe38ab9}, /* U+32B9 CIRCLED NUMBER FORTY FOUR [2000] [Unicode3.2] */ + {0x84d7, 0xe38aba}, /* U+32BA CIRCLED NUMBER FORTY FIVE [2000] [Unicode3.2] */ + {0x84d8, 0xe38abb}, /* U+32BB CIRCLED NUMBER FORTY SIX [2000] [Unicode3.2] */ + {0x84d9, 0xe38abc}, /* U+32BC CIRCLED NUMBER FORTY SEVEN [2000] [Unicode3.2] */ + {0x84da, 0xe38abd}, /* U+32BD CIRCLED NUMBER FORTY EIGHT [2000] [Unicode3.2] */ + {0x84db, 0xe38abe}, /* U+32BE CIRCLED NUMBER FORTY NINE [2000] [Unicode3.2] */ + {0x84dc, 0xe38abf}, /* U+32BF CIRCLED NUMBER FIFTY [2000] [Unicode3.2] */ + {0x84e5, 0xe29790}, /* U+25D0 CIRCLE WITH LEFT HALF BLACK [2000] */ + {0x84e6, 0xe29791}, /* U+25D1 CIRCLE WITH RIGHT HALF BLACK [2000] */ + {0x84e7, 0xe29792}, /* U+25D2 CIRCLE WITH LOWER HALF BLACK [2000] */ + {0x84e8, 0xe29793}, /* U+25D3 CIRCLE WITH UPPER HALF BLACK [2000] */ + {0x84e9, 0xe280bc}, /* U+203C DOUBLE EXCLAMATION MARK [2000] */ + {0x84ea, 0xe28187}, /* U+2047 DOUBLE QUESTION MARK [2000] [Unicode3.2] */ + {0x84eb, 0xe28188}, /* U+2048 QUESTION EXCLAMATION MARK [2000] */ + {0x84ec, 0xe28189}, /* U+2049 EXCLAMATION QUESTION MARK [2000] */ + {0x84ed, 0xc78d}, /* U+01CD LATIN CAPITAL LETTER A WITH CARON [2000] */ + {0x84ee, 0xc78e}, /* U+01CE LATIN SMALL LETTER A WITH CARON [2000] */ + {0x84ef, 0xc790}, /* U+01D0 LATIN SMALL LETTER I WITH CARON [2000] */ + {0x84f0, 0xe1b8be}, /* U+1E3E LATIN CAPITAL LETTER M WITH ACUTE [2000] */ + {0x84f1, 0xe1b8bf}, /* U+1E3F LATIN SMALL LETTER M WITH ACUTE [2000] */ + {0x84f2, 0xc7b8}, /* U+01F8 LATIN CAPITAL LETTER N WITH GRAVE [2000] */ + {0x84f3, 0xc7b9}, /* U+01F9 LATIN SMALL LETTER N WITH GRAVE [2000] */ + {0x84f4, 0xc791}, /* U+01D1 LATIN CAPITAL LETTER O WITH CARON [2000] */ + {0x84f5, 0xc792}, /* U+01D2 LATIN SMALL LETTER O WITH CARON [2000] */ + {0x84f6, 0xc794}, /* U+01D4 LATIN SMALL LETTER U WITH CARON [2000] */ + {0x84f7, 0xc796}, /* U+01D6 LATIN SMALL LETTER U WITH DIAERESIS AND MACRON [2000] */ + {0x84f8, 0xc798}, /* U+01D8 LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE [2000] */ + {0x84f9, 0xc79a}, /* U+01DA LATIN SMALL LETTER U WITH DIAERESIS AND CARON [2000] */ + {0x84fa, 0xc79c}, /* U+01DC LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE [2000] */ + {0x8540, 0xe282ac}, /* U+20AC EURO SIGN [2000] */ + {0x8541, 0xc2a0}, /* U+00A0 NO-BREAK SPACE [2000] */ + {0x8542, 0xc2a1}, /* U+00A1 INVERTED EXCLAMATION MARK [2000] */ + {0x8543, 0xc2a4}, /* U+00A4 CURRENCY SIGN [2000] */ + {0x8544, 0xc2a6}, /* U+00A6 BROKEN BAR [2000] */ + {0x8545, 0xc2a9}, /* U+00A9 COPYRIGHT SIGN [2000] */ + {0x8546, 0xc2aa}, /* U+00AA FEMININE ORDINAL INDICATOR [2000] */ + {0x8547, 0xc2ab}, /* U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK [2000] */ + {0x8548, 0xc2ad}, /* U+00AD SOFT HYPHEN [2000] */ + {0x8549, 0xc2ae}, /* U+00AE REGISTERED SIGN [2000] */ + {0x854a, 0xc2af}, /* U+00AF MACRON [2000] */ + {0x854b, 0xc2b2}, /* U+00B2 SUPERSCRIPT TWO [2000] */ + {0x854c, 0xc2b3}, /* U+00B3 SUPERSCRIPT THREE [2000] */ + {0x854d, 0xc2b7}, /* U+00B7 MIDDLE DOT [2000] */ + {0x854e, 0xc2b8}, /* U+00B8 CEDILLA [2000] */ + {0x854f, 0xc2b9}, /* U+00B9 SUPERSCRIPT ONE [2000] */ + {0x8550, 0xc2ba}, /* U+00BA MASCULINE ORDINAL INDICATOR [2000] */ + {0x8551, 0xc2bb}, /* U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK [2000] */ + {0x8552, 0xc2bc}, /* U+00BC VULGAR FRACTION ONE QUARTER [2000] */ + {0x8553, 0xc2bd}, /* U+00BD VULGAR FRACTION ONE HALF [2000] */ + {0x8554, 0xc2be}, /* U+00BE VULGAR FRACTION THREE QUARTERS [2000] */ + {0x8555, 0xc2bf}, /* U+00BF INVERTED QUESTION MARK [2000] */ + {0x8556, 0xc380}, /* U+00C0 LATIN CAPITAL LETTER A WITH GRAVE [2000] */ + {0x8557, 0xc381}, /* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE [2000] */ + {0x8558, 0xc382}, /* U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX [2000] */ + {0x8559, 0xc383}, /* U+00C3 LATIN CAPITAL LETTER A WITH TILDE [2000] */ + {0x855a, 0xc384}, /* U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS [2000] */ + {0x855b, 0xc385}, /* U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE [2000] */ + {0x855c, 0xc386}, /* U+00C6 LATIN CAPITAL LETTER AE [2000] */ + {0x855d, 0xc387}, /* U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA [2000] */ + {0x855e, 0xc388}, /* U+00C8 LATIN CAPITAL LETTER E WITH GRAVE [2000] */ + {0x855f, 0xc389}, /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE [2000] */ + {0x8560, 0xc38a}, /* U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX [2000] */ + {0x8561, 0xc38b}, /* U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS [2000] */ + {0x8562, 0xc38c}, /* U+00CC LATIN CAPITAL LETTER I WITH GRAVE [2000] */ + {0x8563, 0xc38d}, /* U+00CD LATIN CAPITAL LETTER I WITH ACUTE [2000] */ + {0x8564, 0xc38e}, /* U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX [2000] */ + {0x8565, 0xc38f}, /* U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS [2000] */ + {0x8566, 0xc390}, /* U+00D0 LATIN CAPITAL LETTER ETH [2000] */ + {0x8567, 0xc391}, /* U+00D1 LATIN CAPITAL LETTER N WITH TILDE [2000] */ + {0x8568, 0xc392}, /* U+00D2 LATIN CAPITAL LETTER O WITH GRAVE [2000] */ + {0x8569, 0xc393}, /* U+00D3 LATIN CAPITAL LETTER O WITH ACUTE [2000] */ + {0x856a, 0xc394}, /* U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX [2000] */ + {0x856b, 0xc395}, /* U+00D5 LATIN CAPITAL LETTER O WITH TILDE [2000] */ + {0x856c, 0xc396}, /* U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS [2000] */ + {0x856d, 0xc398}, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE [2000] */ + {0x856e, 0xc399}, /* U+00D9 LATIN CAPITAL LETTER U WITH GRAVE [2000] */ + {0x856f, 0xc39a}, /* U+00DA LATIN CAPITAL LETTER U WITH ACUTE [2000] */ + {0x8570, 0xc39b}, /* U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX [2000] */ + {0x8571, 0xc39c}, /* U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS [2000] */ + {0x8572, 0xc39d}, /* U+00DD LATIN CAPITAL LETTER Y WITH ACUTE [2000] */ + {0x8573, 0xc39e}, /* U+00DE LATIN CAPITAL LETTER THORN [2000] */ + {0x8574, 0xc39f}, /* U+00DF LATIN SMALL LETTER SHARP S [2000] */ + {0x8575, 0xc3a0}, /* U+00E0 LATIN SMALL LETTER A WITH GRAVE [2000] */ + {0x8576, 0xc3a1}, /* U+00E1 LATIN SMALL LETTER A WITH ACUTE [2000] */ + {0x8577, 0xc3a2}, /* U+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX [2000] */ + {0x8578, 0xc3a3}, /* U+00E3 LATIN SMALL LETTER A WITH TILDE [2000] */ + {0x8579, 0xc3a4}, /* U+00E4 LATIN SMALL LETTER A WITH DIAERESIS [2000] */ + {0x857a, 0xc3a5}, /* U+00E5 LATIN SMALL LETTER A WITH RING ABOVE [2000] */ + {0x857b, 0xc3a6}, /* U+00E6 LATIN SMALL LETTER AE [2000] */ + {0x857c, 0xc3a7}, /* U+00E7 LATIN SMALL LETTER C WITH CEDILLA [2000] */ + {0x857d, 0xc3a8}, /* U+00E8 LATIN SMALL LETTER E WITH GRAVE [2000] */ + {0x857e, 0xc3a9}, /* U+00E9 LATIN SMALL LETTER E WITH ACUTE [2000] */ + {0x8580, 0xc3aa}, /* U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX [2000] */ + {0x8581, 0xc3ab}, /* U+00EB LATIN SMALL LETTER E WITH DIAERESIS [2000] */ + {0x8582, 0xc3ac}, /* U+00EC LATIN SMALL LETTER I WITH GRAVE [2000] */ + {0x8583, 0xc3ad}, /* U+00ED LATIN SMALL LETTER I WITH ACUTE [2000] */ + {0x8584, 0xc3ae}, /* U+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX [2000] */ + {0x8585, 0xc3af}, /* U+00EF LATIN SMALL LETTER I WITH DIAERESIS [2000] */ + {0x8586, 0xc3b0}, /* U+00F0 LATIN SMALL LETTER ETH [2000] */ + {0x8587, 0xc3b1}, /* U+00F1 LATIN SMALL LETTER N WITH TILDE [2000] */ + {0x8588, 0xc3b2}, /* U+00F2 LATIN SMALL LETTER O WITH GRAVE [2000] */ + {0x8589, 0xc3b3}, /* U+00F3 LATIN SMALL LETTER O WITH ACUTE [2000] */ + {0x858a, 0xc3b4}, /* U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX [2000] */ + {0x858b, 0xc3b5}, /* U+00F5 LATIN SMALL LETTER O WITH TILDE [2000] */ + {0x858c, 0xc3b6}, /* U+00F6 LATIN SMALL LETTER O WITH DIAERESIS [2000] */ + {0x858d, 0xc3b8}, /* U+00F8 LATIN SMALL LETTER O WITH STROKE [2000] */ + {0x858e, 0xc3b9}, /* U+00F9 LATIN SMALL LETTER U WITH GRAVE [2000] */ + {0x858f, 0xc3ba}, /* U+00FA LATIN SMALL LETTER U WITH ACUTE [2000] */ + {0x8590, 0xc3bb}, /* U+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX [2000] */ + {0x8591, 0xc3bc}, /* U+00FC LATIN SMALL LETTER U WITH DIAERESIS [2000] */ + {0x8592, 0xc3bd}, /* U+00FD LATIN SMALL LETTER Y WITH ACUTE [2000] */ + {0x8593, 0xc3be}, /* U+00FE LATIN SMALL LETTER THORN [2000] */ + {0x8594, 0xc3bf}, /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS [2000] */ + {0x8595, 0xc480}, /* U+0100 LATIN CAPITAL LETTER A WITH MACRON [2000] */ + {0x8596, 0xc4aa}, /* U+012A LATIN CAPITAL LETTER I WITH MACRON [2000] */ + {0x8597, 0xc5aa}, /* U+016A LATIN CAPITAL LETTER U WITH MACRON [2000] */ + {0x8598, 0xc492}, /* U+0112 LATIN CAPITAL LETTER E WITH MACRON [2000] */ + {0x8599, 0xc58c}, /* U+014C LATIN CAPITAL LETTER O WITH MACRON [2000] */ + {0x859a, 0xc481}, /* U+0101 LATIN SMALL LETTER A WITH MACRON [2000] */ + {0x859b, 0xc4ab}, /* U+012B LATIN SMALL LETTER I WITH MACRON [2000] */ + {0x859c, 0xc5ab}, /* U+016B LATIN SMALL LETTER U WITH MACRON [2000] */ + {0x859d, 0xc493}, /* U+0113 LATIN SMALL LETTER E WITH MACRON [2000] */ + {0x859e, 0xc58d}, /* U+014D LATIN SMALL LETTER O WITH MACRON [2000] */ + {0x859f, 0xc484}, /* U+0104 LATIN CAPITAL LETTER A WITH OGONEK [2000] */ + {0x85a0, 0xcb98}, /* U+02D8 BREVE [2000] */ + {0x85a1, 0xc581}, /* U+0141 LATIN CAPITAL LETTER L WITH STROKE [2000] */ + {0x85a2, 0xc4bd}, /* U+013D LATIN CAPITAL LETTER L WITH CARON [2000] */ + {0x85a3, 0xc59a}, /* U+015A LATIN CAPITAL LETTER S WITH ACUTE [2000] */ + {0x85a4, 0xc5a0}, /* U+0160 LATIN CAPITAL LETTER S WITH CARON [2000] */ + {0x85a5, 0xc59e}, /* U+015E LATIN CAPITAL LETTER S WITH CEDILLA [2000] */ + {0x85a6, 0xc5a4}, /* U+0164 LATIN CAPITAL LETTER T WITH CARON [2000] */ + {0x85a7, 0xc5b9}, /* U+0179 LATIN CAPITAL LETTER Z WITH ACUTE [2000] */ + {0x85a8, 0xc5bd}, /* U+017D LATIN CAPITAL LETTER Z WITH CARON [2000] */ + {0x85a9, 0xc5bb}, /* U+017B LATIN CAPITAL LETTER Z WITH DOT ABOVE [2000] */ + {0x85aa, 0xc485}, /* U+0105 LATIN SMALL LETTER A WITH OGONEK [2000] */ + {0x85ab, 0xcb9b}, /* U+02DB OGONEK [2000] */ + {0x85ac, 0xc582}, /* U+0142 LATIN SMALL LETTER L WITH STROKE [2000] */ + {0x85ad, 0xc4be}, /* U+013E LATIN SMALL LETTER L WITH CARON [2000] */ + {0x85ae, 0xc59b}, /* U+015B LATIN SMALL LETTER S WITH ACUTE [2000] */ + {0x85af, 0xcb87}, /* U+02C7 CARON [2000] */ + {0x85b0, 0xc5a1}, /* U+0161 LATIN SMALL LETTER S WITH CARON [2000] */ + {0x85b1, 0xc59f}, /* U+015F LATIN SMALL LETTER S WITH CEDILLA [2000] */ + {0x85b2, 0xc5a5}, /* U+0165 LATIN SMALL LETTER T WITH CARON [2000] */ + {0x85b3, 0xc5ba}, /* U+017A LATIN SMALL LETTER Z WITH ACUTE [2000] */ + {0x85b4, 0xcb9d}, /* U+02DD DOUBLE ACUTE ACCENT [2000] */ + {0x85b5, 0xc5be}, /* U+017E LATIN SMALL LETTER Z WITH CARON [2000] */ + {0x85b6, 0xc5bc}, /* U+017C LATIN SMALL LETTER Z WITH DOT ABOVE [2000] */ + {0x85b7, 0xc594}, /* U+0154 LATIN CAPITAL LETTER R WITH ACUTE [2000] */ + {0x85b8, 0xc482}, /* U+0102 LATIN CAPITAL LETTER A WITH BREVE [2000] */ + {0x85b9, 0xc4b9}, /* U+0139 LATIN CAPITAL LETTER L WITH ACUTE [2000] */ + {0x85ba, 0xc486}, /* U+0106 LATIN CAPITAL LETTER C WITH ACUTE [2000] */ + {0x85bb, 0xc48c}, /* U+010C LATIN CAPITAL LETTER C WITH CARON [2000] */ + {0x85bc, 0xc498}, /* U+0118 LATIN CAPITAL LETTER E WITH OGONEK [2000] */ + {0x85bd, 0xc49a}, /* U+011A LATIN CAPITAL LETTER E WITH CARON [2000] */ + {0x85be, 0xc48e}, /* U+010E LATIN CAPITAL LETTER D WITH CARON [2000] */ + {0x85bf, 0xc583}, /* U+0143 LATIN CAPITAL LETTER N WITH ACUTE [2000] */ + {0x85c0, 0xc587}, /* U+0147 LATIN CAPITAL LETTER N WITH CARON [2000] */ + {0x85c1, 0xc590}, /* U+0150 LATIN CAPITAL LETTER O WITH DOUBLE ACUTE [2000] */ + {0x85c2, 0xc598}, /* U+0158 LATIN CAPITAL LETTER R WITH CARON [2000] */ + {0x85c3, 0xc5ae}, /* U+016E LATIN CAPITAL LETTER U WITH RING ABOVE [2000] */ + {0x85c4, 0xc5b0}, /* U+0170 LATIN CAPITAL LETTER U WITH DOUBLE ACUTE [2000] */ + {0x85c5, 0xc5a2}, /* U+0162 LATIN CAPITAL LETTER T WITH CEDILLA [2000] */ + {0x85c6, 0xc595}, /* U+0155 LATIN SMALL LETTER R WITH ACUTE [2000] */ + {0x85c7, 0xc483}, /* U+0103 LATIN SMALL LETTER A WITH BREVE [2000] */ + {0x85c8, 0xc4ba}, /* U+013A LATIN SMALL LETTER L WITH ACUTE [2000] */ + {0x85c9, 0xc487}, /* U+0107 LATIN SMALL LETTER C WITH ACUTE [2000] */ + {0x85ca, 0xc48d}, /* U+010D LATIN SMALL LETTER C WITH CARON [2000] */ + {0x85cb, 0xc499}, /* U+0119 LATIN SMALL LETTER E WITH OGONEK [2000] */ + {0x85cc, 0xc49b}, /* U+011B LATIN SMALL LETTER E WITH CARON [2000] */ + {0x85cd, 0xc48f}, /* U+010F LATIN SMALL LETTER D WITH CARON [2000] */ + {0x85ce, 0xc491}, /* U+0111 LATIN SMALL LETTER D WITH STROKE [2000] */ + {0x85cf, 0xc584}, /* U+0144 LATIN SMALL LETTER N WITH ACUTE [2000] */ + {0x85d0, 0xc588}, /* U+0148 LATIN SMALL LETTER N WITH CARON [2000] */ + {0x85d1, 0xc591}, /* U+0151 LATIN SMALL LETTER O WITH DOUBLE ACUTE [2000] */ + {0x85d2, 0xc599}, /* U+0159 LATIN SMALL LETTER R WITH CARON [2000] */ + {0x85d3, 0xc5af}, /* U+016F LATIN SMALL LETTER U WITH RING ABOVE [2000] */ + {0x85d4, 0xc5b1}, /* U+0171 LATIN SMALL LETTER U WITH DOUBLE ACUTE [2000] */ + {0x85d5, 0xc5a3}, /* U+0163 LATIN SMALL LETTER T WITH CEDILLA [2000] */ + {0x85d6, 0xcb99}, /* U+02D9 DOT ABOVE [2000] */ + {0x85d7, 0xc488}, /* U+0108 LATIN CAPITAL LETTER C WITH CIRCUMFLEX [2000] */ + {0x85d8, 0xc49c}, /* U+011C LATIN CAPITAL LETTER G WITH CIRCUMFLEX [2000] */ + {0x85d9, 0xc4a4}, /* U+0124 LATIN CAPITAL LETTER H WITH CIRCUMFLEX [2000] */ + {0x85da, 0xc4b4}, /* U+0134 LATIN CAPITAL LETTER J WITH CIRCUMFLEX [2000] */ + {0x85db, 0xc59c}, /* U+015C LATIN CAPITAL LETTER S WITH CIRCUMFLEX [2000] */ + {0x85dc, 0xc5ac}, /* U+016C LATIN CAPITAL LETTER U WITH BREVE [2000] */ + {0x85dd, 0xc489}, /* U+0109 LATIN SMALL LETTER C WITH CIRCUMFLEX [2000] */ + {0x85de, 0xc49d}, /* U+011D LATIN SMALL LETTER G WITH CIRCUMFLEX [2000] */ + {0x85df, 0xc4a5}, /* U+0125 LATIN SMALL LETTER H WITH CIRCUMFLEX [2000] */ + {0x85e0, 0xc4b5}, /* U+0135 LATIN SMALL LETTER J WITH CIRCUMFLEX [2000] */ + {0x85e1, 0xc59d}, /* U+015D LATIN SMALL LETTER S WITH CIRCUMFLEX [2000] */ + {0x85e2, 0xc5ad}, /* U+016D LATIN SMALL LETTER U WITH BREVE [2000] */ + {0x85e3, 0xc9b1}, /* U+0271 LATIN SMALL LETTER M WITH HOOK [2000] */ + {0x85e4, 0xca8b}, /* U+028B LATIN SMALL LETTER V WITH HOOK [2000] */ + {0x85e5, 0xc9be}, /* U+027E LATIN SMALL LETTER R WITH FISHHOOK [2000] */ + {0x85e6, 0xca83}, /* U+0283 LATIN SMALL LETTER ESH [2000] */ + {0x85e7, 0xca92}, /* U+0292 LATIN SMALL LETTER EZH [2000] */ + {0x85e8, 0xc9ac}, /* U+026C LATIN SMALL LETTER L WITH BELT [2000] */ + {0x85e9, 0xc9ae}, /* U+026E LATIN SMALL LETTER LEZH [2000] */ + {0x85ea, 0xc9b9}, /* U+0279 LATIN SMALL LETTER TURNED R [2000] */ + {0x85eb, 0xca88}, /* U+0288 LATIN SMALL LETTER T WITH RETROFLEX HOOK [2000] */ + {0x85ec, 0xc996}, /* U+0256 LATIN SMALL LETTER D WITH TAIL [2000] */ + {0x85ed, 0xc9b3}, /* U+0273 LATIN SMALL LETTER N WITH RETROFLEX HOOK [2000] */ + {0x85ee, 0xc9bd}, /* U+027D LATIN SMALL LETTER R WITH TAIL [2000] */ + {0x85ef, 0xca82}, /* U+0282 LATIN SMALL LETTER S WITH HOOK [2000] */ + {0x85f0, 0xca90}, /* U+0290 LATIN SMALL LETTER Z WITH RETROFLEX HOOK [2000] */ + {0x85f1, 0xc9bb}, /* U+027B LATIN SMALL LETTER TURNED R WITH HOOK [2000] */ + {0x85f2, 0xc9ad}, /* U+026D LATIN SMALL LETTER L WITH RETROFLEX HOOK [2000] */ + {0x85f3, 0xc99f}, /* U+025F LATIN SMALL LETTER DOTLESS J WITH STROKE [2000] */ + {0x85f4, 0xc9b2}, /* U+0272 LATIN SMALL LETTER N WITH LEFT HOOK [2000] */ + {0x85f5, 0xca9d}, /* U+029D LATIN SMALL LETTER J WITH CROSSED-TAIL [2000] */ + {0x85f6, 0xca8e}, /* U+028E LATIN SMALL LETTER TURNED Y [2000] */ + {0x85f7, 0xc9a1}, /* U+0261 LATIN SMALL LETTER SCRIPT G [2000] */ + {0x85f8, 0xc58b}, /* U+014B LATIN SMALL LETTER ENG [2000] */ + {0x85f9, 0xc9b0}, /* U+0270 LATIN SMALL LETTER TURNED M WITH LONG LEG [2000] */ + {0x85fa, 0xca81}, /* U+0281 LATIN LETTER SMALL CAPITAL INVERTED R [2000] */ + {0x85fb, 0xc4a7}, /* U+0127 LATIN SMALL LETTER H WITH STROKE [2000] */ + {0x85fc, 0xca95}, /* U+0295 LATIN LETTER PHARYNGEAL VOICED FRICATIVE [2000] */ + {0x8640, 0xca94}, /* U+0294 LATIN LETTER GLOTTAL STOP [2000] */ + {0x8641, 0xc9a6}, /* U+0266 LATIN SMALL LETTER H WITH HOOK [2000] */ + {0x8642, 0xca98}, /* U+0298 LATIN LETTER BILABIAL CLICK [2000] */ + {0x8643, 0xc782}, /* U+01C2 LATIN LETTER ALVEOLAR CLICK [2000] */ + {0x8644, 0xc993}, /* U+0253 LATIN SMALL LETTER B WITH HOOK [2000] */ + {0x8645, 0xc997}, /* U+0257 LATIN SMALL LETTER D WITH HOOK [2000] */ + {0x8646, 0xca84}, /* U+0284 LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK [2000] */ + {0x8647, 0xc9a0}, /* U+0260 LATIN SMALL LETTER G WITH HOOK [2000] */ + {0x8648, 0xc693}, /* U+0193 LATIN CAPITAL LETTER G WITH HOOK [2000] */ + {0x8649, 0xc593}, /* U+0153 LATIN SMALL LIGATURE OE [2000] */ + {0x864a, 0xc592}, /* U+0152 LATIN CAPITAL LIGATURE OE [2000] */ + {0x864b, 0xc9a8}, /* U+0268 LATIN SMALL LETTER I WITH STROKE [2000] */ + {0x864c, 0xca89}, /* U+0289 LATIN SMALL LETTER U BAR [2000] */ + {0x864d, 0xc998}, /* U+0258 LATIN SMALL LETTER REVERSED E [2000] */ + {0x864e, 0xc9b5}, /* U+0275 LATIN SMALL LETTER BARRED O [2000] */ + {0x864f, 0xc999}, /* U+0259 LATIN SMALL LETTER SCHWA [2000] */ + {0x8650, 0xc99c}, /* U+025C LATIN SMALL LETTER REVERSED OPEN E [2000] */ + {0x8651, 0xc99e}, /* U+025E LATIN SMALL LETTER CLOSED REVERSED OPEN E [2000] */ + {0x8652, 0xc990}, /* U+0250 LATIN SMALL LETTER TURNED A [2000] */ + {0x8653, 0xc9af}, /* U+026F LATIN SMALL LETTER TURNED M [2000] */ + {0x8654, 0xca8a}, /* U+028A LATIN SMALL LETTER UPSILON [2000] */ + {0x8655, 0xc9a4}, /* U+0264 LATIN SMALL LETTER RAMS HORN [2000] */ + {0x8656, 0xca8c}, /* U+028C LATIN SMALL LETTER TURNED V [2000] */ + {0x8657, 0xc994}, /* U+0254 LATIN SMALL LETTER OPEN O [2000] */ + {0x8658, 0xc991}, /* U+0251 LATIN SMALL LETTER ALPHA [2000] */ + {0x8659, 0xc992}, /* U+0252 LATIN SMALL LETTER TURNED ALPHA [2000] */ + {0x865a, 0xca8d}, /* U+028D LATIN SMALL LETTER TURNED W [2000] */ + {0x865b, 0xc9a5}, /* U+0265 LATIN SMALL LETTER TURNED H [2000] */ + {0x865c, 0xcaa2}, /* U+02A2 LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE [2000] */ + {0x865d, 0xcaa1}, /* U+02A1 LATIN LETTER GLOTTAL STOP WITH STROKE [2000] */ + {0x865e, 0xc995}, /* U+0255 LATIN SMALL LETTER C WITH CURL [2000] */ + {0x865f, 0xca91}, /* U+0291 LATIN SMALL LETTER Z WITH CURL [2000] */ + {0x8660, 0xc9ba}, /* U+027A LATIN SMALL LETTER TURNED R WITH LONG LEG [2000] */ + {0x8661, 0xc9a7}, /* U+0267 LATIN SMALL LETTER HENG WITH HOOK [2000] */ + {0x8662, 0xc99a}, /* U+025A LATIN SMALL LETTER SCHWA WITH HOOK [2000] */ + {0x8664, 0xc7bd}, /* U+01FD LATIN SMALL LETTER AE WITH ACUTE [2000] */ + {0x8665, 0xe1bdb0}, /* U+1F70 GREEK SMALL LETTER ALPHA WITH VARIA [2000] */ + {0x8666, 0xe1bdb1}, /* U+1F71 GREEK SMALL LETTER ALPHA WITH OXIA [2000] */ + {0x866f, 0xe1bdb2}, /* U+1F72 GREEK SMALL LETTER EPSILON WITH VARIA [2000] */ + {0x8670, 0xe1bdb3}, /* U+1F73 GREEK SMALL LETTER EPSILON WITH OXIA [2000] */ + {0x8671, 0xcda1}, /* U+0361 COMBINING DOUBLE INVERTED BREVE [2000] */ + {0x8672, 0xcb88}, /* U+02C8 MODIFIER LETTER VERTICAL LINE [2000] */ + {0x8673, 0xcb8c}, /* U+02CC MODIFIER LETTER LOW VERTICAL LINE [2000] */ + {0x8674, 0xcb90}, /* U+02D0 MODIFIER LETTER TRIANGULAR COLON [2000] */ + {0x8675, 0xcb91}, /* U+02D1 MODIFIER LETTER HALF TRIANGULAR COLON [2000] */ + {0x8676, 0xcc86}, /* U+0306 COMBINING BREVE [2000] */ + {0x8677, 0xe280bf}, /* U+203F UNDERTIE [2000] */ + {0x8678, 0xcc8b}, /* U+030B COMBINING DOUBLE ACUTE ACCENT [2000] */ + {0x8679, 0xcc81}, /* U+0301 COMBINING ACUTE ACCENT [2000] */ + {0x867a, 0xcc84}, /* U+0304 COMBINING MACRON [2000] */ + {0x867b, 0xcc80}, /* U+0300 COMBINING GRAVE ACCENT [2000] */ + {0x867c, 0xcc8f}, /* U+030F COMBINING DOUBLE GRAVE ACCENT [2000] */ + {0x867d, 0xcc8c}, /* U+030C COMBINING CARON [2000] */ + {0x867e, 0xcc82}, /* U+0302 COMBINING CIRCUMFLEX ACCENT [2000] */ + {0x8680, 0xcba5}, /* U+02E5 MODIFIER LETTER EXTRA-HIGH TONE BAR [2000] */ + {0x8681, 0xcba6}, /* U+02E6 MODIFIER LETTER HIGH TONE BAR [2000] */ + {0x8682, 0xcba7}, /* U+02E7 MODIFIER LETTER MID TONE BAR [2000] */ + {0x8683, 0xcba8}, /* U+02E8 MODIFIER LETTER LOW TONE BAR [2000] */ + {0x8684, 0xcba9}, /* U+02E9 MODIFIER LETTER EXTRA-LOW TONE BAR [2000] */ + {0x8687, 0xcca5}, /* U+0325 COMBINING RING BELOW [2000] */ + {0x8688, 0xccac}, /* U+032C COMBINING CARON BELOW [2000] */ + {0x8689, 0xccb9}, /* U+0339 COMBINING RIGHT HALF RING BELOW [2000] */ + {0x868a, 0xcc9c}, /* U+031C COMBINING LEFT HALF RING BELOW [2000] */ + {0x868b, 0xcc9f}, /* U+031F COMBINING PLUS SIGN BELOW [2000] */ + {0x868c, 0xcca0}, /* U+0320 COMBINING MINUS SIGN BELOW [2000] */ + {0x868d, 0xcc88}, /* U+0308 COMBINING DIAERESIS [2000] */ + {0x868e, 0xccbd}, /* U+033D COMBINING X ABOVE [2000] */ + {0x868f, 0xcca9}, /* U+0329 COMBINING VERTICAL LINE BELOW [2000] */ + {0x8690, 0xccaf}, /* U+032F COMBINING INVERTED BREVE BELOW [2000] */ + {0x8691, 0xcb9e}, /* U+02DE MODIFIER LETTER RHOTIC HOOK [2000] */ + {0x8692, 0xcca4}, /* U+0324 COMBINING DIAERESIS BELOW [2000] */ + {0x8693, 0xccb0}, /* U+0330 COMBINING TILDE BELOW [2000] */ + {0x8694, 0xccbc}, /* U+033C COMBINING SEAGULL BELOW [2000] */ + {0x8695, 0xccb4}, /* U+0334 COMBINING TILDE OVERLAY [2000] */ + {0x8696, 0xcc9d}, /* U+031D COMBINING UP TACK BELOW [2000] */ + {0x8697, 0xcc9e}, /* U+031E COMBINING DOWN TACK BELOW [2000] */ + {0x8698, 0xcc98}, /* U+0318 COMBINING LEFT TACK BELOW [2000] */ + {0x8699, 0xcc99}, /* U+0319 COMBINING RIGHT TACK BELOW [2000] */ + {0x869a, 0xccaa}, /* U+032A COMBINING BRIDGE BELOW [2000] */ + {0x869b, 0xccba}, /* U+033A COMBINING INVERTED BRIDGE BELOW [2000] */ + {0x869c, 0xccbb}, /* U+033B COMBINING SQUARE BELOW [2000] */ + {0x869d, 0xcc83}, /* U+0303 COMBINING TILDE [2000] */ + {0x869e, 0xcc9a}, /* U+031A COMBINING LEFT ANGLE ABOVE [2000] */ + {0x869f, 0xe29db6}, /* U+2776 DINGBAT NEGATIVE CIRCLED DIGIT ONE [2000] */ + {0x86a0, 0xe29db7}, /* U+2777 DINGBAT NEGATIVE CIRCLED DIGIT TWO [2000] */ + {0x86a1, 0xe29db8}, /* U+2778 DINGBAT NEGATIVE CIRCLED DIGIT THREE [2000] */ + {0x86a2, 0xe29db9}, /* U+2779 DINGBAT NEGATIVE CIRCLED DIGIT FOUR [2000] */ + {0x86a3, 0xe29dba}, /* U+277A DINGBAT NEGATIVE CIRCLED DIGIT FIVE [2000] */ + {0x86a4, 0xe29dbb}, /* U+277B DINGBAT NEGATIVE CIRCLED DIGIT SIX [2000] */ + {0x86a5, 0xe29dbc}, /* U+277C DINGBAT NEGATIVE CIRCLED DIGIT SEVEN [2000] */ + {0x86a6, 0xe29dbd}, /* U+277D DINGBAT NEGATIVE CIRCLED DIGIT EIGHT [2000] */ + {0x86a7, 0xe29dbe}, /* U+277E DINGBAT NEGATIVE CIRCLED DIGIT NINE [2000] */ + {0x86a8, 0xe29dbf}, /* U+277F DINGBAT NEGATIVE CIRCLED NUMBER TEN [2000] */ + {0x86a9, 0xe293ab}, /* U+24EB NEGATIVE CIRCLED NUMBER ELEVEN [2000] [Unicode3.2] */ + {0x86aa, 0xe293ac}, /* U+24EC NEGATIVE CIRCLED NUMBER TWELVE [2000] [Unicode3.2] */ + {0x86ab, 0xe293ad}, /* U+24ED NEGATIVE CIRCLED NUMBER THIRTEEN [2000] [Unicode3.2] */ + {0x86ac, 0xe293ae}, /* U+24EE NEGATIVE CIRCLED NUMBER FOURTEEN [2000] [Unicode3.2] */ + {0x86ad, 0xe293af}, /* U+24EF NEGATIVE CIRCLED NUMBER FIFTEEN [2000] [Unicode3.2] */ + {0x86ae, 0xe293b0}, /* U+24F0 NEGATIVE CIRCLED NUMBER SIXTEEN [2000] [Unicode3.2] */ + {0x86af, 0xe293b1}, /* U+24F1 NEGATIVE CIRCLED NUMBER SEVENTEEN [2000] [Unicode3.2] */ + {0x86b0, 0xe293b2}, /* U+24F2 NEGATIVE CIRCLED NUMBER EIGHTEEN [2000] [Unicode3.2] */ + {0x86b1, 0xe293b3}, /* U+24F3 NEGATIVE CIRCLED NUMBER NINETEEN [2000] [Unicode3.2] */ + {0x86b2, 0xe293b4}, /* U+24F4 NEGATIVE CIRCLED NUMBER TWENTY [2000] [Unicode3.2] */ + {0x86b3, 0xe285b0}, /* U+2170 SMALL ROMAN NUMERAL ONE [2000] */ + {0x86b4, 0xe285b1}, /* U+2171 SMALL ROMAN NUMERAL TWO [2000] */ + {0x86b5, 0xe285b2}, /* U+2172 SMALL ROMAN NUMERAL THREE [2000] */ + {0x86b6, 0xe285b3}, /* U+2173 SMALL ROMAN NUMERAL FOUR [2000] */ + {0x86b7, 0xe285b4}, /* U+2174 SMALL ROMAN NUMERAL FIVE [2000] */ + {0x86b8, 0xe285b5}, /* U+2175 SMALL ROMAN NUMERAL SIX [2000] */ + {0x86b9, 0xe285b6}, /* U+2176 SMALL ROMAN NUMERAL SEVEN [2000] */ + {0x86ba, 0xe285b7}, /* U+2177 SMALL ROMAN NUMERAL EIGHT [2000] */ + {0x86bb, 0xe285b8}, /* U+2178 SMALL ROMAN NUMERAL NINE [2000] */ + {0x86bc, 0xe285b9}, /* U+2179 SMALL ROMAN NUMERAL TEN [2000] */ + {0x86bd, 0xe285ba}, /* U+217A SMALL ROMAN NUMERAL ELEVEN [2000] */ + {0x86be, 0xe285bb}, /* U+217B SMALL ROMAN NUMERAL TWELVE [2000] */ + {0x86bf, 0xe29390}, /* U+24D0 CIRCLED LATIN SMALL LETTER A [2000] */ + {0x86c0, 0xe29391}, /* U+24D1 CIRCLED LATIN SMALL LETTER B [2000] */ + {0x86c1, 0xe29392}, /* U+24D2 CIRCLED LATIN SMALL LETTER C [2000] */ + {0x86c2, 0xe29393}, /* U+24D3 CIRCLED LATIN SMALL LETTER D [2000] */ + {0x86c3, 0xe29394}, /* U+24D4 CIRCLED LATIN SMALL LETTER E [2000] */ + {0x86c4, 0xe29395}, /* U+24D5 CIRCLED LATIN SMALL LETTER F [2000] */ + {0x86c5, 0xe29396}, /* U+24D6 CIRCLED LATIN SMALL LETTER G [2000] */ + {0x86c6, 0xe29397}, /* U+24D7 CIRCLED LATIN SMALL LETTER H [2000] */ + {0x86c7, 0xe29398}, /* U+24D8 CIRCLED LATIN SMALL LETTER I [2000] */ + {0x86c8, 0xe29399}, /* U+24D9 CIRCLED LATIN SMALL LETTER J [2000] */ + {0x86c9, 0xe2939a}, /* U+24DA CIRCLED LATIN SMALL LETTER K [2000] */ + {0x86ca, 0xe2939b}, /* U+24DB CIRCLED LATIN SMALL LETTER L [2000] */ + {0x86cb, 0xe2939c}, /* U+24DC CIRCLED LATIN SMALL LETTER M [2000] */ + {0x86cc, 0xe2939d}, /* U+24DD CIRCLED LATIN SMALL LETTER N [2000] */ + {0x86cd, 0xe2939e}, /* U+24DE CIRCLED LATIN SMALL LETTER O [2000] */ + {0x86ce, 0xe2939f}, /* U+24DF CIRCLED LATIN SMALL LETTER P [2000] */ + {0x86cf, 0xe293a0}, /* U+24E0 CIRCLED LATIN SMALL LETTER Q [2000] */ + {0x86d0, 0xe293a1}, /* U+24E1 CIRCLED LATIN SMALL LETTER R [2000] */ + {0x86d1, 0xe293a2}, /* U+24E2 CIRCLED LATIN SMALL LETTER S [2000] */ + {0x86d2, 0xe293a3}, /* U+24E3 CIRCLED LATIN SMALL LETTER T [2000] */ + {0x86d3, 0xe293a4}, /* U+24E4 CIRCLED LATIN SMALL LETTER U [2000] */ + {0x86d4, 0xe293a5}, /* U+24E5 CIRCLED LATIN SMALL LETTER V [2000] */ + {0x86d5, 0xe293a6}, /* U+24E6 CIRCLED LATIN SMALL LETTER W [2000] */ + {0x86d6, 0xe293a7}, /* U+24E7 CIRCLED LATIN SMALL LETTER X [2000] */ + {0x86d7, 0xe293a8}, /* U+24E8 CIRCLED LATIN SMALL LETTER Y [2000] */ + {0x86d8, 0xe293a9}, /* U+24E9 CIRCLED LATIN SMALL LETTER Z [2000] */ + {0x86d9, 0xe38b90}, /* U+32D0 CIRCLED KATAKANA A [2000] */ + {0x86da, 0xe38b91}, /* U+32D1 CIRCLED KATAKANA I [2000] */ + {0x86db, 0xe38b92}, /* U+32D2 CIRCLED KATAKANA U [2000] */ + {0x86dc, 0xe38b93}, /* U+32D3 CIRCLED KATAKANA E [2000] */ + {0x86dd, 0xe38b94}, /* U+32D4 CIRCLED KATAKANA O [2000] */ + {0x86de, 0xe38b95}, /* U+32D5 CIRCLED KATAKANA KA [2000] */ + {0x86df, 0xe38b96}, /* U+32D6 CIRCLED KATAKANA KI [2000] */ + {0x86e0, 0xe38b97}, /* U+32D7 CIRCLED KATAKANA KU [2000] */ + {0x86e1, 0xe38b98}, /* U+32D8 CIRCLED KATAKANA KE [2000] */ + {0x86e2, 0xe38b99}, /* U+32D9 CIRCLED KATAKANA KO [2000] */ + {0x86e3, 0xe38b9a}, /* U+32DA CIRCLED KATAKANA SA [2000] */ + {0x86e4, 0xe38b9b}, /* U+32DB CIRCLED KATAKANA SI [2000] */ + {0x86e5, 0xe38b9c}, /* U+32DC CIRCLED KATAKANA SU [2000] */ + {0x86e6, 0xe38b9d}, /* U+32DD CIRCLED KATAKANA SE [2000] */ + {0x86e7, 0xe38b9e}, /* U+32DE CIRCLED KATAKANA SO [2000] */ + {0x86e8, 0xe38b9f}, /* U+32DF CIRCLED KATAKANA TA [2000] */ + {0x86e9, 0xe38ba0}, /* U+32E0 CIRCLED KATAKANA TI [2000] */ + {0x86ea, 0xe38ba1}, /* U+32E1 CIRCLED KATAKANA TU [2000] */ + {0x86eb, 0xe38ba2}, /* U+32E2 CIRCLED KATAKANA TE [2000] */ + {0x86ec, 0xe38ba3}, /* U+32E3 CIRCLED KATAKANA TO [2000] */ + {0x86ed, 0xe38bba}, /* U+32FA CIRCLED KATAKANA RO [2000] */ + {0x86ee, 0xe38ba9}, /* U+32E9 CIRCLED KATAKANA HA [2000] */ + {0x86ef, 0xe38ba5}, /* U+32E5 CIRCLED KATAKANA NI [2000] */ + {0x86f0, 0xe38bad}, /* U+32ED CIRCLED KATAKANA HO [2000] */ + {0x86f1, 0xe38bac}, /* U+32EC CIRCLED KATAKANA HE [2000] */ + {0x86fb, 0xe28191}, /* U+2051 TWO ASTERISKS ALIGNED VERTICALLY [2000] [Unicode3.2] */ + {0x86fc, 0xe28182}, /* U+2042 ASTERISM [2000] */ + {0x8740, 0xe291a0}, /* U+2460 CIRCLED DIGIT ONE [2000] */ + {0x8741, 0xe291a1}, /* U+2461 CIRCLED DIGIT TWO [2000] */ + {0x8742, 0xe291a2}, /* U+2462 CIRCLED DIGIT THREE [2000] */ + {0x8743, 0xe291a3}, /* U+2463 CIRCLED DIGIT FOUR [2000] */ + {0x8744, 0xe291a4}, /* U+2464 CIRCLED DIGIT FIVE [2000] */ + {0x8745, 0xe291a5}, /* U+2465 CIRCLED DIGIT SIX [2000] */ + {0x8746, 0xe291a6}, /* U+2466 CIRCLED DIGIT SEVEN [2000] */ + {0x8747, 0xe291a7}, /* U+2467 CIRCLED DIGIT EIGHT [2000] */ + {0x8748, 0xe291a8}, /* U+2468 CIRCLED DIGIT NINE [2000] */ + {0x8749, 0xe291a9}, /* U+2469 CIRCLED NUMBER TEN [2000] */ + {0x874a, 0xe291aa}, /* U+246A CIRCLED NUMBER ELEVEN [2000] */ + {0x874b, 0xe291ab}, /* U+246B CIRCLED NUMBER TWELVE [2000] */ + {0x874c, 0xe291ac}, /* U+246C CIRCLED NUMBER THIRTEEN [2000] */ + {0x874d, 0xe291ad}, /* U+246D CIRCLED NUMBER FOURTEEN [2000] */ + {0x874e, 0xe291ae}, /* U+246E CIRCLED NUMBER FIFTEEN [2000] */ + {0x874f, 0xe291af}, /* U+246F CIRCLED NUMBER SIXTEEN [2000] */ + {0x8750, 0xe291b0}, /* U+2470 CIRCLED NUMBER SEVENTEEN [2000] */ + {0x8751, 0xe291b1}, /* U+2471 CIRCLED NUMBER EIGHTEEN [2000] */ + {0x8752, 0xe291b2}, /* U+2472 CIRCLED NUMBER NINETEEN [2000] */ + {0x8753, 0xe291b3}, /* U+2473 CIRCLED NUMBER TWENTY [2000] */ + {0x8754, 0xe285a0}, /* U+2160 ROMAN NUMERAL ONE [2000] */ + {0x8755, 0xe285a1}, /* U+2161 ROMAN NUMERAL TWO [2000] */ + {0x8756, 0xe285a2}, /* U+2162 ROMAN NUMERAL THREE [2000] */ + {0x8757, 0xe285a3}, /* U+2163 ROMAN NUMERAL FOUR [2000] */ + {0x8758, 0xe285a4}, /* U+2164 ROMAN NUMERAL FIVE [2000] */ + {0x8759, 0xe285a5}, /* U+2165 ROMAN NUMERAL SIX [2000] */ + {0x875a, 0xe285a6}, /* U+2166 ROMAN NUMERAL SEVEN [2000] */ + {0x875b, 0xe285a7}, /* U+2167 ROMAN NUMERAL EIGHT [2000] */ + {0x875c, 0xe285a8}, /* U+2168 ROMAN NUMERAL NINE [2000] */ + {0x875d, 0xe285a9}, /* U+2169 ROMAN NUMERAL TEN [2000] */ + {0x875e, 0xe285aa}, /* U+216A ROMAN NUMERAL ELEVEN [2000] */ + {0x875f, 0xe38d89}, /* U+3349 SQUARE MIRI [2000] */ + {0x8760, 0xe38c94}, /* U+3314 SQUARE KIRO [2000] */ + {0x8761, 0xe38ca2}, /* U+3322 SQUARE SENTI [2000] */ + {0x8762, 0xe38d8d}, /* U+334D SQUARE MEETORU [2000] */ + {0x8763, 0xe38c98}, /* U+3318 SQUARE GURAMU [2000] */ + {0x8764, 0xe38ca7}, /* U+3327 SQUARE TON [2000] */ + {0x8765, 0xe38c83}, /* U+3303 SQUARE AARU [2000] */ + {0x8766, 0xe38cb6}, /* U+3336 SQUARE HEKUTAARU [2000] */ + {0x8767, 0xe38d91}, /* U+3351 SQUARE RITTORU [2000] */ + {0x8768, 0xe38d97}, /* U+3357 SQUARE WATTO [2000] */ + {0x8769, 0xe38c8d}, /* U+330D SQUARE KARORII [2000] */ + {0x876a, 0xe38ca6}, /* U+3326 SQUARE DORU [2000] */ + {0x876b, 0xe38ca3}, /* U+3323 SQUARE SENTO [2000] */ + {0x876c, 0xe38cab}, /* U+332B SQUARE PAASENTO [2000] */ + {0x876d, 0xe38d8a}, /* U+334A SQUARE MIRIBAARU [2000] */ + {0x876e, 0xe38cbb}, /* U+333B SQUARE PEEZI [2000] */ + {0x876f, 0xe38e9c}, /* U+339C SQUARE MM [2000] */ + {0x8770, 0xe38e9d}, /* U+339D SQUARE CM [2000] */ + {0x8771, 0xe38e9e}, /* U+339E SQUARE KM [2000] */ + {0x8772, 0xe38e8e}, /* U+338E SQUARE MG [2000] */ + {0x8773, 0xe38e8f}, /* U+338F SQUARE KG [2000] */ + {0x8774, 0xe38f84}, /* U+33C4 SQUARE CC [2000] */ + {0x8775, 0xe38ea1}, /* U+33A1 SQUARE M SQUARED [2000] */ + {0x8776, 0xe285ab}, /* U+216B ROMAN NUMERAL TWELVE [2000] */ + {0x877e, 0xe38dbb}, /* U+337B SQUARE ERA NAME HEISEI [2000] */ + {0x8780, 0xe3809d}, /* U+301D REVERSED DOUBLE PRIME QUOTATION MARK [2000] */ + {0x8781, 0xe3809f}, /* U+301F LOW DOUBLE PRIME QUOTATION MARK [2000] */ + {0x8782, 0xe28496}, /* U+2116 NUMERO SIGN [2000] */ + {0x8783, 0xe38f8d}, /* U+33CD SQUARE KK [2000] */ + {0x8784, 0xe284a1}, /* U+2121 TELEPHONE SIGN [2000] */ + {0x8785, 0xe38aa4}, /* U+32A4 CIRCLED IDEOGRAPH HIGH [2000] */ + {0x8786, 0xe38aa5}, /* U+32A5 CIRCLED IDEOGRAPH CENTRE [2000] */ + {0x8787, 0xe38aa6}, /* U+32A6 CIRCLED IDEOGRAPH LOW [2000] */ + {0x8788, 0xe38aa7}, /* U+32A7 CIRCLED IDEOGRAPH LEFT [2000] */ + {0x8789, 0xe38aa8}, /* U+32A8 CIRCLED IDEOGRAPH RIGHT [2000] */ + {0x878a, 0xe388b1}, /* U+3231 PARENTHESIZED IDEOGRAPH STOCK [2000] */ + {0x878b, 0xe388b2}, /* U+3232 PARENTHESIZED IDEOGRAPH HAVE [2000] */ + {0x878c, 0xe388b9}, /* U+3239 PARENTHESIZED IDEOGRAPH REPRESENT [2000] */ + {0x878d, 0xe38dbe}, /* U+337E SQUARE ERA NAME MEIZI [2000] */ + {0x878e, 0xe38dbd}, /* U+337D SQUARE ERA NAME TAISYOU [2000] */ + {0x878f, 0xe38dbc}, /* U+337C SQUARE ERA NAME SYOUWA [2000] */ + {0x8793, 0xe288ae}, /* U+222E CONTOUR INTEGRAL [2000] */ + {0x8798, 0xe2889f}, /* U+221F RIGHT ANGLE [2000] */ + {0x8799, 0xe28abf}, /* U+22BF RIGHT TRIANGLE [2000] */ + {0x879d, 0xe29d96}, /* U+2756 BLACK DIAMOND MINUS WHITE X [2000] */ + {0x879e, 0xe2989e}, /* U+261E WHITE RIGHT POINTING INDEX [2000] */ + {0x879f, 0xe4bfb1}, /* U+4FF1 [2004] */ {0x87a0, 0xf0a0808b}, /* U+2000B [2000] [Unicode3.1] */ - {0x87a1, 0x00e39082}, /* U+3402 [2000] */ - {0x87a2, 0x00e4b8a8}, /* U+4E28 [2000] */ - {0x87a3, 0x00e4b8af}, /* U+4E2F [2000] */ - {0x87a4, 0x00e4b8b0}, /* U+4E30 [2000] */ - {0x87a5, 0x00e4ba8d}, /* U+4E8D [2000] */ - {0x87a6, 0x00e4bba1}, /* U+4EE1 [2000] */ - {0x87a7, 0x00e4bbbd}, /* U+4EFD [2000] */ - {0x87a8, 0x00e4bbbf}, /* U+4EFF [2000] */ - {0x87a9, 0x00e4bc83}, /* U+4F03 [2000] */ - {0x87aa, 0x00e4bc8b}, /* U+4F0B [2000] */ - {0x87ab, 0x00e4bda0}, /* U+4F60 [2000] */ - {0x87ac, 0x00e4bd88}, /* U+4F48 [2000] */ - {0x87ad, 0x00e4bd89}, /* U+4F49 [2000] */ - {0x87ae, 0x00e4bd96}, /* U+4F56 [2000] */ - {0x87af, 0x00e4bd9f}, /* U+4F5F [2000] */ - {0x87b0, 0x00e4bdaa}, /* U+4F6A [2000] */ - {0x87b1, 0x00e4bdac}, /* U+4F6C [2000] */ - {0x87b2, 0x00e4bdbe}, /* U+4F7E [2000] */ - {0x87b3, 0x00e4be8a}, /* U+4F8A [2000] */ - {0x87b4, 0x00e4be94}, /* U+4F94 [2000] */ - {0x87b5, 0x00e4be97}, /* U+4F97 [2000] */ - {0x87b6, 0x00efa8b0}, /* U+FA30 CJK COMPATIBILITY IDEOGRAPH-FA30 [2000] [Unicode3.2] */ - {0x87b7, 0x00e4bf89}, /* U+4FC9 [2000] */ - {0x87b8, 0x00e4bfa0}, /* U+4FE0 [2000] */ - {0x87b9, 0x00e58081}, /* U+5001 [2000] */ - {0x87ba, 0x00e58082}, /* U+5002 [2000] */ - {0x87bb, 0x00e5808e}, /* U+500E [2000] */ - {0x87bc, 0x00e58098}, /* U+5018 [2000] */ - {0x87bd, 0x00e580a7}, /* U+5027 [2000] */ - {0x87be, 0x00e580ae}, /* U+502E [2000] */ - {0x87bf, 0x00e58180}, /* U+5040 [2000] */ - {0x87c0, 0x00e580bb}, /* U+503B [2000] */ - {0x87c1, 0x00e58181}, /* U+5041 [2000] */ - {0x87c2, 0x00e58294}, /* U+5094 [2000] */ - {0x87c3, 0x00e5838c}, /* U+50CC [2000] */ - {0x87c4, 0x00e583b2}, /* U+50F2 [2000] */ - {0x87c5, 0x00e58390}, /* U+50D0 [2000] */ - {0x87c6, 0x00e583a6}, /* U+50E6 [2000] */ - {0x87c7, 0x00efa8b1}, /* U+FA31 CJK COMPATIBILITY IDEOGRAPH-FA31 [2000] [Unicode3.2] */ - {0x87c8, 0x00e58486}, /* U+5106 [2000] */ - {0x87c9, 0x00e58483}, /* U+5103 [2000] */ - {0x87ca, 0x00e5848b}, /* U+510B [2000] */ - {0x87cb, 0x00e5849e}, /* U+511E [2000] */ - {0x87cc, 0x00e584b5}, /* U+5135 [2000] */ - {0x87cd, 0x00e5858a}, /* U+514A [2000] */ - {0x87ce, 0x00efa8b2}, /* U+FA32 CJK COMPATIBILITY IDEOGRAPH-FA32 [2000] [Unicode3.2] */ - {0x87cf, 0x00e58595}, /* U+5155 [2000] */ - {0x87d0, 0x00e58597}, /* U+5157 [2000] */ - {0x87d1, 0x00e392b5}, /* U+34B5 [2000] */ - {0x87d2, 0x00e5869d}, /* U+519D [2000] */ - {0x87d3, 0x00e58783}, /* U+51C3 [2000] */ - {0x87d4, 0x00e5878a}, /* U+51CA [2000] */ - {0x87d5, 0x00e5879e}, /* U+51DE [2000] */ - {0x87d6, 0x00e587a2}, /* U+51E2 [2000] */ - {0x87d7, 0x00e587ae}, /* U+51EE [2000] */ - {0x87d8, 0x00e58881}, /* U+5201 [2000] */ - {0x87d9, 0x00e3939b}, /* U+34DB [2000] */ - {0x87da, 0x00e58893}, /* U+5213 [2000] */ - {0x87db, 0x00e58895}, /* U+5215 [2000] */ - {0x87dc, 0x00e58989}, /* U+5249 [2000] */ - {0x87dd, 0x00e58997}, /* U+5257 [2000] */ - {0x87de, 0x00e589a1}, /* U+5261 [2000] */ - {0x87df, 0x00e58a93}, /* U+5293 [2000] */ - {0x87e0, 0x00e58b88}, /* U+52C8 [2000] */ - {0x87e1, 0x00efa8b3}, /* U+FA33 CJK COMPATIBILITY IDEOGRAPH-FA33 [2000] [Unicode3.2] */ - {0x87e2, 0x00e58b8c}, /* U+52CC [2000] */ - {0x87e3, 0x00e58b90}, /* U+52D0 [2000] */ - {0x87e4, 0x00e58b96}, /* U+52D6 [2000] */ - {0x87e5, 0x00e58b9b}, /* U+52DB [2000] */ - {0x87e6, 0x00efa8b4}, /* U+FA34 CJK COMPATIBILITY IDEOGRAPH-FA34 [2000] [Unicode3.2] */ - {0x87e7, 0x00e58bb0}, /* U+52F0 [2000] */ - {0x87e8, 0x00e58bbb}, /* U+52FB [2000] */ - {0x87e9, 0x00e58c80}, /* U+5300 [2000] */ - {0x87ea, 0x00e58c87}, /* U+5307 [2000] */ - {0x87eb, 0x00e58c9c}, /* U+531C [2000] */ - {0x87ec, 0x00efa8b5}, /* U+FA35 CJK COMPATIBILITY IDEOGRAPH-FA35 [2000] [Unicode3.2] */ - {0x87ed, 0x00e58da1}, /* U+5361 [2000] */ - {0x87ee, 0x00e58da3}, /* U+5363 [2000] */ - {0x87ef, 0x00e58dbd}, /* U+537D [2000] */ - {0x87f0, 0x00e58e93}, /* U+5393 [2000] */ - {0x87f1, 0x00e58e9d}, /* U+539D [2000] */ - {0x87f2, 0x00e58eb2}, /* U+53B2 [2000] */ - {0x87f3, 0x00e59092}, /* U+5412 [2000] */ - {0x87f4, 0x00e590a7}, /* U+5427 [2000] */ - {0x87f5, 0x00e5918d}, /* U+544D [2000] */ - {0x87f6, 0x00e5929c}, /* U+549C [2000] */ - {0x87f7, 0x00e591ab}, /* U+546B [2000] */ - {0x87f8, 0x00e591b4}, /* U+5474 [2000] */ - {0x87f9, 0x00e591bf}, /* U+547F [2000] */ - {0x87fa, 0x00e59288}, /* U+5488 [2000] */ - {0x87fb, 0x00e59296}, /* U+5496 [2000] */ - {0x87fc, 0x00e592a1}, /* U+54A1 [2000] */ - {0x8840, 0x00e592a9}, /* U+54A9 [2000] */ - {0x8841, 0x00e59386}, /* U+54C6 [2000] */ - {0x8842, 0x00e593bf}, /* U+54FF [2000] */ - {0x8843, 0x00e5948e}, /* U+550E [2000] */ - {0x8844, 0x00e594ab}, /* U+552B [2000] */ - {0x8845, 0x00e594b5}, /* U+5535 [2000] */ - {0x8846, 0x00e59590}, /* U+5550 [2000] */ - {0x8847, 0x00e5959e}, /* U+555E [2000] */ - {0x8848, 0x00e59681}, /* U+5581 [2000] */ - {0x8849, 0x00e59686}, /* U+5586 [2000] */ - {0x884a, 0x00e5968e}, /* U+558E [2000] */ - {0x884b, 0x00efa8b6}, /* U+FA36 CJK COMPATIBILITY IDEOGRAPH-FA36 [2000] [Unicode3.2] */ - {0x884c, 0x00e596ad}, /* U+55AD [2000] */ - {0x884d, 0x00e5978e}, /* U+55CE [2000] */ - {0x884e, 0x00efa8b7}, /* U+FA37 CJK COMPATIBILITY IDEOGRAPH-FA37 [2000] [Unicode3.2] */ - {0x884f, 0x00e59888}, /* U+5608 [2000] */ - {0x8850, 0x00e5988e}, /* U+560E [2000] */ - {0x8851, 0x00e598bb}, /* U+563B [2000] */ - {0x8852, 0x00e59989}, /* U+5649 [2000] */ - {0x8853, 0x00e599b6}, /* U+5676 [2000] */ - {0x8854, 0x00e599a6}, /* U+5666 [2000] */ - {0x8855, 0x00efa8b8}, /* U+FA38 CJK COMPATIBILITY IDEOGRAPH-FA38 [2000] [Unicode3.2] */ - {0x8856, 0x00e599af}, /* U+566F [2000] */ - {0x8857, 0x00e599b1}, /* U+5671 [2000] */ - {0x8858, 0x00e599b2}, /* U+5672 [2000] */ - {0x8859, 0x00e59a99}, /* U+5699 [2000] */ - {0x885a, 0x00e59a9e}, /* U+569E [2000] */ - {0x885b, 0x00e59aa9}, /* U+56A9 [2000] */ - {0x885c, 0x00e59aac}, /* U+56AC [2000] */ - {0x885d, 0x00e59ab3}, /* U+56B3 [2000] */ - {0x885e, 0x00e59b89}, /* U+56C9 [2000] */ - {0x885f, 0x00e59b8a}, /* U+56CA [2000] */ - {0x8860, 0x00e59c8a}, /* U+570A [2000] */ + {0x87a1, 0xe39082}, /* U+3402 [2000] */ + {0x87a2, 0xe4b8a8}, /* U+4E28 [2000] */ + {0x87a3, 0xe4b8af}, /* U+4E2F [2000] */ + {0x87a4, 0xe4b8b0}, /* U+4E30 [2000] */ + {0x87a5, 0xe4ba8d}, /* U+4E8D [2000] */ + {0x87a6, 0xe4bba1}, /* U+4EE1 [2000] */ + {0x87a7, 0xe4bbbd}, /* U+4EFD [2000] */ + {0x87a8, 0xe4bbbf}, /* U+4EFF [2000] */ + {0x87a9, 0xe4bc83}, /* U+4F03 [2000] */ + {0x87aa, 0xe4bc8b}, /* U+4F0B [2000] */ + {0x87ab, 0xe4bda0}, /* U+4F60 [2000] */ + {0x87ac, 0xe4bd88}, /* U+4F48 [2000] */ + {0x87ad, 0xe4bd89}, /* U+4F49 [2000] */ + {0x87ae, 0xe4bd96}, /* U+4F56 [2000] */ + {0x87af, 0xe4bd9f}, /* U+4F5F [2000] */ + {0x87b0, 0xe4bdaa}, /* U+4F6A [2000] */ + {0x87b1, 0xe4bdac}, /* U+4F6C [2000] */ + {0x87b2, 0xe4bdbe}, /* U+4F7E [2000] */ + {0x87b3, 0xe4be8a}, /* U+4F8A [2000] */ + {0x87b4, 0xe4be94}, /* U+4F94 [2000] */ + {0x87b5, 0xe4be97}, /* U+4F97 [2000] */ + {0x87b6, 0xefa8b0}, /* U+FA30 CJK COMPATIBILITY IDEOGRAPH-FA30 [2000] [Unicode3.2] */ + {0x87b7, 0xe4bf89}, /* U+4FC9 [2000] */ + {0x87b8, 0xe4bfa0}, /* U+4FE0 [2000] */ + {0x87b9, 0xe58081}, /* U+5001 [2000] */ + {0x87ba, 0xe58082}, /* U+5002 [2000] */ + {0x87bb, 0xe5808e}, /* U+500E [2000] */ + {0x87bc, 0xe58098}, /* U+5018 [2000] */ + {0x87bd, 0xe580a7}, /* U+5027 [2000] */ + {0x87be, 0xe580ae}, /* U+502E [2000] */ + {0x87bf, 0xe58180}, /* U+5040 [2000] */ + {0x87c0, 0xe580bb}, /* U+503B [2000] */ + {0x87c1, 0xe58181}, /* U+5041 [2000] */ + {0x87c2, 0xe58294}, /* U+5094 [2000] */ + {0x87c3, 0xe5838c}, /* U+50CC [2000] */ + {0x87c4, 0xe583b2}, /* U+50F2 [2000] */ + {0x87c5, 0xe58390}, /* U+50D0 [2000] */ + {0x87c6, 0xe583a6}, /* U+50E6 [2000] */ + {0x87c7, 0xefa8b1}, /* U+FA31 CJK COMPATIBILITY IDEOGRAPH-FA31 [2000] [Unicode3.2] */ + {0x87c8, 0xe58486}, /* U+5106 [2000] */ + {0x87c9, 0xe58483}, /* U+5103 [2000] */ + {0x87ca, 0xe5848b}, /* U+510B [2000] */ + {0x87cb, 0xe5849e}, /* U+511E [2000] */ + {0x87cc, 0xe584b5}, /* U+5135 [2000] */ + {0x87cd, 0xe5858a}, /* U+514A [2000] */ + {0x87ce, 0xefa8b2}, /* U+FA32 CJK COMPATIBILITY IDEOGRAPH-FA32 [2000] [Unicode3.2] */ + {0x87cf, 0xe58595}, /* U+5155 [2000] */ + {0x87d0, 0xe58597}, /* U+5157 [2000] */ + {0x87d1, 0xe392b5}, /* U+34B5 [2000] */ + {0x87d2, 0xe5869d}, /* U+519D [2000] */ + {0x87d3, 0xe58783}, /* U+51C3 [2000] */ + {0x87d4, 0xe5878a}, /* U+51CA [2000] */ + {0x87d5, 0xe5879e}, /* U+51DE [2000] */ + {0x87d6, 0xe587a2}, /* U+51E2 [2000] */ + {0x87d7, 0xe587ae}, /* U+51EE [2000] */ + {0x87d8, 0xe58881}, /* U+5201 [2000] */ + {0x87d9, 0xe3939b}, /* U+34DB [2000] */ + {0x87da, 0xe58893}, /* U+5213 [2000] */ + {0x87db, 0xe58895}, /* U+5215 [2000] */ + {0x87dc, 0xe58989}, /* U+5249 [2000] */ + {0x87dd, 0xe58997}, /* U+5257 [2000] */ + {0x87de, 0xe589a1}, /* U+5261 [2000] */ + {0x87df, 0xe58a93}, /* U+5293 [2000] */ + {0x87e0, 0xe58b88}, /* U+52C8 [2000] */ + {0x87e1, 0xefa8b3}, /* U+FA33 CJK COMPATIBILITY IDEOGRAPH-FA33 [2000] [Unicode3.2] */ + {0x87e2, 0xe58b8c}, /* U+52CC [2000] */ + {0x87e3, 0xe58b90}, /* U+52D0 [2000] */ + {0x87e4, 0xe58b96}, /* U+52D6 [2000] */ + {0x87e5, 0xe58b9b}, /* U+52DB [2000] */ + {0x87e6, 0xefa8b4}, /* U+FA34 CJK COMPATIBILITY IDEOGRAPH-FA34 [2000] [Unicode3.2] */ + {0x87e7, 0xe58bb0}, /* U+52F0 [2000] */ + {0x87e8, 0xe58bbb}, /* U+52FB [2000] */ + {0x87e9, 0xe58c80}, /* U+5300 [2000] */ + {0x87ea, 0xe58c87}, /* U+5307 [2000] */ + {0x87eb, 0xe58c9c}, /* U+531C [2000] */ + {0x87ec, 0xefa8b5}, /* U+FA35 CJK COMPATIBILITY IDEOGRAPH-FA35 [2000] [Unicode3.2] */ + {0x87ed, 0xe58da1}, /* U+5361 [2000] */ + {0x87ee, 0xe58da3}, /* U+5363 [2000] */ + {0x87ef, 0xe58dbd}, /* U+537D [2000] */ + {0x87f0, 0xe58e93}, /* U+5393 [2000] */ + {0x87f1, 0xe58e9d}, /* U+539D [2000] */ + {0x87f2, 0xe58eb2}, /* U+53B2 [2000] */ + {0x87f3, 0xe59092}, /* U+5412 [2000] */ + {0x87f4, 0xe590a7}, /* U+5427 [2000] */ + {0x87f5, 0xe5918d}, /* U+544D [2000] */ + {0x87f6, 0xe5929c}, /* U+549C [2000] */ + {0x87f7, 0xe591ab}, /* U+546B [2000] */ + {0x87f8, 0xe591b4}, /* U+5474 [2000] */ + {0x87f9, 0xe591bf}, /* U+547F [2000] */ + {0x87fa, 0xe59288}, /* U+5488 [2000] */ + {0x87fb, 0xe59296}, /* U+5496 [2000] */ + {0x87fc, 0xe592a1}, /* U+54A1 [2000] */ + {0x8840, 0xe592a9}, /* U+54A9 [2000] */ + {0x8841, 0xe59386}, /* U+54C6 [2000] */ + {0x8842, 0xe593bf}, /* U+54FF [2000] */ + {0x8843, 0xe5948e}, /* U+550E [2000] */ + {0x8844, 0xe594ab}, /* U+552B [2000] */ + {0x8845, 0xe594b5}, /* U+5535 [2000] */ + {0x8846, 0xe59590}, /* U+5550 [2000] */ + {0x8847, 0xe5959e}, /* U+555E [2000] */ + {0x8848, 0xe59681}, /* U+5581 [2000] */ + {0x8849, 0xe59686}, /* U+5586 [2000] */ + {0x884a, 0xe5968e}, /* U+558E [2000] */ + {0x884b, 0xefa8b6}, /* U+FA36 CJK COMPATIBILITY IDEOGRAPH-FA36 [2000] [Unicode3.2] */ + {0x884c, 0xe596ad}, /* U+55AD [2000] */ + {0x884d, 0xe5978e}, /* U+55CE [2000] */ + {0x884e, 0xefa8b7}, /* U+FA37 CJK COMPATIBILITY IDEOGRAPH-FA37 [2000] [Unicode3.2] */ + {0x884f, 0xe59888}, /* U+5608 [2000] */ + {0x8850, 0xe5988e}, /* U+560E [2000] */ + {0x8851, 0xe598bb}, /* U+563B [2000] */ + {0x8852, 0xe59989}, /* U+5649 [2000] */ + {0x8853, 0xe599b6}, /* U+5676 [2000] */ + {0x8854, 0xe599a6}, /* U+5666 [2000] */ + {0x8855, 0xefa8b8}, /* U+FA38 CJK COMPATIBILITY IDEOGRAPH-FA38 [2000] [Unicode3.2] */ + {0x8856, 0xe599af}, /* U+566F [2000] */ + {0x8857, 0xe599b1}, /* U+5671 [2000] */ + {0x8858, 0xe599b2}, /* U+5672 [2000] */ + {0x8859, 0xe59a99}, /* U+5699 [2000] */ + {0x885a, 0xe59a9e}, /* U+569E [2000] */ + {0x885b, 0xe59aa9}, /* U+56A9 [2000] */ + {0x885c, 0xe59aac}, /* U+56AC [2000] */ + {0x885d, 0xe59ab3}, /* U+56B3 [2000] */ + {0x885e, 0xe59b89}, /* U+56C9 [2000] */ + {0x885f, 0xe59b8a}, /* U+56CA [2000] */ + {0x8860, 0xe59c8a}, /* U+570A [2000] */ {0x8861, 0xf0a188bd}, /* U+2123D [2000] [Unicode3.1] */ - {0x8862, 0x00e59ca1}, /* U+5721 [2000] */ - {0x8863, 0x00e59caf}, /* U+572F [2000] */ - {0x8864, 0x00e59cb3}, /* U+5733 [2000] */ - {0x8865, 0x00e59cb4}, /* U+5734 [2000] */ - {0x8866, 0x00e59db0}, /* U+5770 [2000] */ - {0x8867, 0x00e59db7}, /* U+5777 [2000] */ - {0x8868, 0x00e59dbc}, /* U+577C [2000] */ - {0x8869, 0x00e59e9c}, /* U+579C [2000] */ - {0x886a, 0x00efa88f}, /* U+FA0F CJK COMPATIBILITY IDEOGRAPH-FA0F [2000] */ + {0x8862, 0xe59ca1}, /* U+5721 [2000] */ + {0x8863, 0xe59caf}, /* U+572F [2000] */ + {0x8864, 0xe59cb3}, /* U+5733 [2000] */ + {0x8865, 0xe59cb4}, /* U+5734 [2000] */ + {0x8866, 0xe59db0}, /* U+5770 [2000] */ + {0x8867, 0xe59db7}, /* U+5777 [2000] */ + {0x8868, 0xe59dbc}, /* U+577C [2000] */ + {0x8869, 0xe59e9c}, /* U+579C [2000] */ + {0x886a, 0xefa88f}, /* U+FA0F CJK COMPATIBILITY IDEOGRAPH-FA0F [2000] */ {0x886b, 0xf0a18c9b}, /* U+2131B [2000] [Unicode3.1] */ - {0x886c, 0x00e59eb8}, /* U+57B8 [2000] */ - {0x886d, 0x00e59f87}, /* U+57C7 [2000] */ - {0x886e, 0x00e59f88}, /* U+57C8 [2000] */ - {0x886f, 0x00e59f8f}, /* U+57CF [2000] */ - {0x8870, 0x00e59fa4}, /* U+57E4 [2000] */ - {0x8871, 0x00e59fad}, /* U+57ED [2000] */ - {0x8872, 0x00e59fb5}, /* U+57F5 [2000] */ - {0x8873, 0x00e59fb6}, /* U+57F6 [2000] */ - {0x8874, 0x00e59fbf}, /* U+57FF [2000] */ - {0x8875, 0x00e5a089}, /* U+5809 [2000] */ - {0x8876, 0x00efa890}, /* U+FA10 CJK COMPATIBILITY IDEOGRAPH-FA10 [2000] */ - {0x8877, 0x00e5a1a1}, /* U+5861 [2000] */ - {0x8878, 0x00e5a1a4}, /* U+5864 [2000] */ - {0x8879, 0x00efa8b9}, /* U+FA39 CJK COMPATIBILITY IDEOGRAPH-FA39 [2000] [Unicode3.2] */ - {0x887a, 0x00e5a1bc}, /* U+587C [2000] */ - {0x887b, 0x00e5a289}, /* U+5889 [2000] */ - {0x887c, 0x00e5a29e}, /* U+589E [2000] */ - {0x887d, 0x00efa8ba}, /* U+FA3A CJK COMPATIBILITY IDEOGRAPH-FA3A [2000] [Unicode3.2] */ - {0x887e, 0x00e5a2a9}, /* U+58A9 [2000] */ + {0x886c, 0xe59eb8}, /* U+57B8 [2000] */ + {0x886d, 0xe59f87}, /* U+57C7 [2000] */ + {0x886e, 0xe59f88}, /* U+57C8 [2000] */ + {0x886f, 0xe59f8f}, /* U+57CF [2000] */ + {0x8870, 0xe59fa4}, /* U+57E4 [2000] */ + {0x8871, 0xe59fad}, /* U+57ED [2000] */ + {0x8872, 0xe59fb5}, /* U+57F5 [2000] */ + {0x8873, 0xe59fb6}, /* U+57F6 [2000] */ + {0x8874, 0xe59fbf}, /* U+57FF [2000] */ + {0x8875, 0xe5a089}, /* U+5809 [2000] */ + {0x8876, 0xefa890}, /* U+FA10 CJK COMPATIBILITY IDEOGRAPH-FA10 [2000] */ + {0x8877, 0xe5a1a1}, /* U+5861 [2000] */ + {0x8878, 0xe5a1a4}, /* U+5864 [2000] */ + {0x8879, 0xefa8b9}, /* U+FA39 CJK COMPATIBILITY IDEOGRAPH-FA39 [2000] [Unicode3.2] */ + {0x887a, 0xe5a1bc}, /* U+587C [2000] */ + {0x887b, 0xe5a289}, /* U+5889 [2000] */ + {0x887c, 0xe5a29e}, /* U+589E [2000] */ + {0x887d, 0xefa8ba}, /* U+FA3A CJK COMPATIBILITY IDEOGRAPH-FA3A [2000] [Unicode3.2] */ + {0x887e, 0xe5a2a9}, /* U+58A9 [2000] */ {0x8880, 0xf0a191ae}, /* U+2146E [2000] [Unicode3.1] */ - {0x8881, 0x00e5a392}, /* U+58D2 [2000] */ - {0x8882, 0x00e5a38e}, /* U+58CE [2000] */ - {0x8883, 0x00e5a394}, /* U+58D4 [2000] */ - {0x8884, 0x00e5a39a}, /* U+58DA [2000] */ - {0x8885, 0x00e5a3a0}, /* U+58E0 [2000] */ - {0x8886, 0x00e5a3a9}, /* U+58E9 [2000] */ - {0x8887, 0x00e5a48c}, /* U+590C [2000] */ - {0x8888, 0x00e89981}, /* U+8641 [2000] */ - {0x8889, 0x00e5a59d}, /* U+595D [2000] */ - {0x888a, 0x00e5a5ad}, /* U+596D [2000] */ - {0x888b, 0x00e5a68b}, /* U+598B [2000] */ - {0x888c, 0x00e5a692}, /* U+5992 [2000] */ - {0x888d, 0x00e5a6a4}, /* U+59A4 [2000] */ - {0x888e, 0x00e5a783}, /* U+59C3 [2000] */ - {0x888f, 0x00e5a792}, /* U+59D2 [2000] */ - {0x8890, 0x00e5a79d}, /* U+59DD [2000] */ - {0x8891, 0x00e5a893}, /* U+5A13 [2000] */ - {0x8892, 0x00e5a8a3}, /* U+5A23 [2000] */ - {0x8893, 0x00e5a9a7}, /* U+5A67 [2000] */ - {0x8894, 0x00e5a9ad}, /* U+5A6D [2000] */ - {0x8895, 0x00e5a9b7}, /* U+5A77 [2000] */ - {0x8896, 0x00e5a9be}, /* U+5A7E [2000] */ - {0x8897, 0x00e5aa84}, /* U+5A84 [2000] */ - {0x8898, 0x00e5aa9e}, /* U+5A9E [2000] */ - {0x8899, 0x00e5aaa7}, /* U+5AA7 [2000] */ - {0x889a, 0x00e5ab84}, /* U+5AC4 [2000] */ + {0x8881, 0xe5a392}, /* U+58D2 [2000] */ + {0x8882, 0xe5a38e}, /* U+58CE [2000] */ + {0x8883, 0xe5a394}, /* U+58D4 [2000] */ + {0x8884, 0xe5a39a}, /* U+58DA [2000] */ + {0x8885, 0xe5a3a0}, /* U+58E0 [2000] */ + {0x8886, 0xe5a3a9}, /* U+58E9 [2000] */ + {0x8887, 0xe5a48c}, /* U+590C [2000] */ + {0x8888, 0xe89981}, /* U+8641 [2000] */ + {0x8889, 0xe5a59d}, /* U+595D [2000] */ + {0x888a, 0xe5a5ad}, /* U+596D [2000] */ + {0x888b, 0xe5a68b}, /* U+598B [2000] */ + {0x888c, 0xe5a692}, /* U+5992 [2000] */ + {0x888d, 0xe5a6a4}, /* U+59A4 [2000] */ + {0x888e, 0xe5a783}, /* U+59C3 [2000] */ + {0x888f, 0xe5a792}, /* U+59D2 [2000] */ + {0x8890, 0xe5a79d}, /* U+59DD [2000] */ + {0x8891, 0xe5a893}, /* U+5A13 [2000] */ + {0x8892, 0xe5a8a3}, /* U+5A23 [2000] */ + {0x8893, 0xe5a9a7}, /* U+5A67 [2000] */ + {0x8894, 0xe5a9ad}, /* U+5A6D [2000] */ + {0x8895, 0xe5a9b7}, /* U+5A77 [2000] */ + {0x8896, 0xe5a9be}, /* U+5A7E [2000] */ + {0x8897, 0xe5aa84}, /* U+5A84 [2000] */ + {0x8898, 0xe5aa9e}, /* U+5A9E [2000] */ + {0x8899, 0xe5aaa7}, /* U+5AA7 [2000] */ + {0x889a, 0xe5ab84}, /* U+5AC4 [2000] */ {0x889b, 0xf0a1a2bd}, /* U+218BD [2000] [Unicode3.1] */ - {0x889c, 0x00e5ac99}, /* U+5B19 [2000] */ - {0x889d, 0x00e5aca5}, /* U+5B25 [2000] */ - {0x889e, 0x00e5899d}, /* U+525D [2004] */ - {0x889f, 0x00e4ba9c}, /* U+4E9C */ - {0x88a0, 0x00e59496}, /* U+5516 */ - {0x88a1, 0x00e5a883}, /* U+5A03 */ - {0x88a2, 0x00e998bf}, /* U+963F */ - {0x88a3, 0x00e59380}, /* U+54C0 */ - {0x88a4, 0x00e6849b}, /* U+611B */ - {0x88a5, 0x00e68ca8}, /* U+6328 */ - {0x88a6, 0x00e5a7b6}, /* U+59F6 */ - {0x88a7, 0x00e980a2}, /* U+9022 */ - {0x88a8, 0x00e891b5}, /* U+8475 */ - {0x88a9, 0x00e88c9c}, /* U+831C */ - {0x88aa, 0x00e7a990}, /* U+7A50 */ - {0x88ab, 0x00e682aa}, /* U+60AA */ - {0x88ac, 0x00e68fa1}, /* U+63E1 */ - {0x88ad, 0x00e6b8a5}, /* U+6E25 */ - {0x88ae, 0x00e697ad}, /* U+65ED */ - {0x88af, 0x00e891a6}, /* U+8466 */ - {0x88b0, 0x00e88aa6}, /* U+82A6 */ - {0x88b1, 0x00e9afb5}, /* U+9BF5 */ - {0x88b2, 0x00e6a293}, /* U+6893 */ - {0x88b3, 0x00e59ca7}, /* U+5727 */ - {0x88b4, 0x00e696a1}, /* U+65A1 */ - {0x88b5, 0x00e689b1}, /* U+6271 */ - {0x88b6, 0x00e5ae9b}, /* U+5B9B */ - {0x88b7, 0x00e5a790}, /* U+59D0 */ - {0x88b8, 0x00e899bb}, /* U+867B */ - {0x88b9, 0x00e9a3b4}, /* U+98F4 */ - {0x88ba, 0x00e7b5a2}, /* U+7D62 */ - {0x88bb, 0x00e7b6be}, /* U+7DBE */ - {0x88bc, 0x00e9ae8e}, /* U+9B8E */ - {0x88bd, 0x00e68896}, /* U+6216 */ - {0x88be, 0x00e7b29f}, /* U+7C9F */ - {0x88bf, 0x00e8a2b7}, /* U+88B7 */ - {0x88c0, 0x00e5ae89}, /* U+5B89 */ - {0x88c1, 0x00e5bab5}, /* U+5EB5 */ - {0x88c2, 0x00e68c89}, /* U+6309 */ - {0x88c3, 0x00e69a97}, /* U+6697 */ - {0x88c4, 0x00e6a188}, /* U+6848 */ - {0x88c5, 0x00e99787}, /* U+95C7 */ - {0x88c6, 0x00e99e8d}, /* U+978D */ - {0x88c7, 0x00e69d8f}, /* U+674F */ - {0x88c8, 0x00e4bba5}, /* U+4EE5 */ - {0x88c9, 0x00e4bc8a}, /* U+4F0A */ - {0x88ca, 0x00e4bd8d}, /* U+4F4D */ - {0x88cb, 0x00e4be9d}, /* U+4F9D */ - {0x88cc, 0x00e58189}, /* U+5049 */ - {0x88cd, 0x00e59bb2}, /* U+56F2 */ - {0x88ce, 0x00e5a4b7}, /* U+5937 */ - {0x88cf, 0x00e5a794}, /* U+59D4 */ - {0x88d0, 0x00e5a881}, /* U+5A01 */ - {0x88d1, 0x00e5b089}, /* U+5C09 */ - {0x88d2, 0x00e6839f}, /* U+60DF */ - {0x88d3, 0x00e6848f}, /* U+610F */ - {0x88d4, 0x00e685b0}, /* U+6170 */ - {0x88d5, 0x00e69893}, /* U+6613 */ - {0x88d6, 0x00e6a485}, /* U+6905 */ - {0x88d7, 0x00e782ba}, /* U+70BA */ - {0x88d8, 0x00e7958f}, /* U+754F */ - {0x88d9, 0x00e795b0}, /* U+7570 */ - {0x88da, 0x00e7a7bb}, /* U+79FB */ - {0x88db, 0x00e7b6ad}, /* U+7DAD */ - {0x88dc, 0x00e7b7af}, /* U+7DEF */ - {0x88dd, 0x00e88383}, /* U+80C3 */ - {0x88de, 0x00e8908e}, /* U+840E */ - {0x88df, 0x00e8a1a3}, /* U+8863 */ - {0x88e0, 0x00e8ac82}, /* U+8B02 */ - {0x88e1, 0x00e98195}, /* U+9055 */ - {0x88e2, 0x00e981ba}, /* U+907A */ - {0x88e3, 0x00e58cbb}, /* U+533B */ - {0x88e4, 0x00e4ba95}, /* U+4E95 */ - {0x88e5, 0x00e4baa5}, /* U+4EA5 */ - {0x88e6, 0x00e59f9f}, /* U+57DF */ - {0x88e7, 0x00e882b2}, /* U+80B2 */ - {0x88e8, 0x00e98381}, /* U+90C1 */ - {0x88e9, 0x00e7a3af}, /* U+78EF */ - {0x88ea, 0x00e4b880}, /* U+4E00 */ - {0x88eb, 0x00e5a3b1}, /* U+58F1 */ - {0x88ec, 0x00e6baa2}, /* U+6EA2 */ - {0x88ed, 0x00e980b8}, /* U+9038 */ - {0x88ee, 0x00e7a8b2}, /* U+7A32 */ - {0x88ef, 0x00e88ca8}, /* U+8328 */ - {0x88f0, 0x00e88a8b}, /* U+828B */ - {0x88f1, 0x00e9b0af}, /* U+9C2F */ - {0x88f2, 0x00e58581}, /* U+5141 */ - {0x88f3, 0x00e58db0}, /* U+5370 */ - {0x88f4, 0x00e592bd}, /* U+54BD */ - {0x88f5, 0x00e593a1}, /* U+54E1 */ - {0x88f6, 0x00e59ba0}, /* U+56E0 */ - {0x88f7, 0x00e5a7bb}, /* U+59FB */ - {0x88f8, 0x00e5bc95}, /* U+5F15 */ - {0x88f9, 0x00e9a3b2}, /* U+98F2 */ - {0x88fa, 0x00e6b7ab}, /* U+6DEB */ - {0x88fb, 0x00e883a4}, /* U+80E4 */ - {0x88fc, 0x00e894ad}, /* U+852D */ - {0x8940, 0x00e999a2}, /* U+9662 */ - {0x8941, 0x00e999b0}, /* U+9670 */ - {0x8942, 0x00e99aa0}, /* U+96A0 */ - {0x8943, 0x00e99fbb}, /* U+97FB */ - {0x8944, 0x00e5908b}, /* U+540B */ - {0x8945, 0x00e58fb3}, /* U+53F3 */ - {0x8946, 0x00e5ae87}, /* U+5B87 */ - {0x8947, 0x00e7838f}, /* U+70CF */ - {0x8948, 0x00e7bebd}, /* U+7FBD */ - {0x8949, 0x00e8bf82}, /* U+8FC2 */ - {0x894a, 0x00e99ba8}, /* U+96E8 */ - {0x894b, 0x00e58daf}, /* U+536F */ - {0x894c, 0x00e9b59c}, /* U+9D5C */ - {0x894d, 0x00e7aaba}, /* U+7ABA */ - {0x894e, 0x00e4b891}, /* U+4E11 */ - {0x894f, 0x00e7a293}, /* U+7893 */ - {0x8950, 0x00e887bc}, /* U+81FC */ - {0x8951, 0x00e6b8a6}, /* U+6E26 */ - {0x8952, 0x00e59898}, /* U+5618 */ - {0x8953, 0x00e59484}, /* U+5504 */ - {0x8954, 0x00e6ac9d}, /* U+6B1D */ - {0x8955, 0x00e8949a}, /* U+851A */ - {0x8956, 0x00e9b0bb}, /* U+9C3B */ - {0x8957, 0x00e5a7a5}, /* U+59E5 */ - {0x8958, 0x00e58ea9}, /* U+53A9 */ - {0x8959, 0x00e6b5a6}, /* U+6D66 */ - {0x895a, 0x00e7939c}, /* U+74DC */ - {0x895b, 0x00e9968f}, /* U+958F */ - {0x895c, 0x00e59982}, /* U+5642 */ - {0x895d, 0x00e4ba91}, /* U+4E91 */ - {0x895e, 0x00e9818b}, /* U+904B */ - {0x895f, 0x00e99bb2}, /* U+96F2 */ - {0x8960, 0x00e88d8f}, /* U+834F */ - {0x8961, 0x00e9a48c}, /* U+990C */ - {0x8962, 0x00e58fa1}, /* U+53E1 */ - {0x8963, 0x00e596b6}, /* U+55B6 */ - {0x8964, 0x00e5acb0}, /* U+5B30 */ - {0x8965, 0x00e5bdb1}, /* U+5F71 */ - {0x8966, 0x00e698a0}, /* U+6620 */ - {0x8967, 0x00e69bb3}, /* U+66F3 */ - {0x8968, 0x00e6a084}, /* U+6804 */ - {0x8969, 0x00e6b0b8}, /* U+6C38 */ - {0x896a, 0x00e6b3b3}, /* U+6CF3 */ - {0x896b, 0x00e6b4a9}, /* U+6D29 */ - {0x896c, 0x00e7919b}, /* U+745B */ - {0x896d, 0x00e79b88}, /* U+76C8 */ - {0x896e, 0x00e7a98e}, /* U+7A4E */ - {0x896f, 0x00e9a0b4}, /* U+9834 */ - {0x8970, 0x00e88bb1}, /* U+82F1 */ - {0x8971, 0x00e8a19b}, /* U+885B */ - {0x8972, 0x00e8a9a0}, /* U+8A60 */ - {0x8973, 0x00e98bad}, /* U+92ED */ - {0x8974, 0x00e6b6b2}, /* U+6DB2 */ - {0x8975, 0x00e796ab}, /* U+75AB */ - {0x8976, 0x00e79b8a}, /* U+76CA */ - {0x8977, 0x00e9a785}, /* U+99C5 */ - {0x8978, 0x00e682a6}, /* U+60A6 */ - {0x8979, 0x00e8ac81}, /* U+8B01 */ - {0x897a, 0x00e8b68a}, /* U+8D8A */ - {0x897b, 0x00e996b2}, /* U+95B2 */ - {0x897c, 0x00e6a68e}, /* U+698E */ - {0x897d, 0x00e58ead}, /* U+53AD */ - {0x897e, 0x00e58686}, /* U+5186 */ - {0x8980, 0x00e59c92}, /* U+5712 */ - {0x8981, 0x00e5a0b0}, /* U+5830 */ - {0x8982, 0x00e5a584}, /* U+5944 */ - {0x8983, 0x00e5aeb4}, /* U+5BB4 */ - {0x8984, 0x00e5bbb6}, /* U+5EF6 */ - {0x8985, 0x00e680a8}, /* U+6028 */ - {0x8986, 0x00e68ea9}, /* U+63A9 */ - {0x8987, 0x00e68fb4}, /* U+63F4 */ - {0x8988, 0x00e6b2bf}, /* U+6CBF */ - {0x8989, 0x00e6bc94}, /* U+6F14 */ - {0x898a, 0x00e7828e}, /* U+708E */ - {0x898b, 0x00e78494}, /* U+7114 */ - {0x898c, 0x00e78599}, /* U+7159 */ - {0x898d, 0x00e78795}, /* U+71D5 */ - {0x898e, 0x00e78cbf}, /* U+733F */ - {0x898f, 0x00e7b881}, /* U+7E01 */ - {0x8990, 0x00e889b6}, /* U+8276 */ - {0x8991, 0x00e88b91}, /* U+82D1 */ - {0x8992, 0x00e89697}, /* U+8597 */ - {0x8993, 0x00e981a0}, /* U+9060 */ - {0x8994, 0x00e9899b}, /* U+925B */ - {0x8995, 0x00e9b49b}, /* U+9D1B */ - {0x8996, 0x00e5a1a9}, /* U+5869 */ - {0x8997, 0x00e696bc}, /* U+65BC */ - {0x8998, 0x00e6b19a}, /* U+6C5A */ - {0x8999, 0x00e794a5}, /* U+7525 */ - {0x899a, 0x00e587b9}, /* U+51F9 */ - {0x899b, 0x00e5a4ae}, /* U+592E */ - {0x899c, 0x00e5a5a5}, /* U+5965 */ - {0x899d, 0x00e5be80}, /* U+5F80 */ - {0x899e, 0x00e5bf9c}, /* U+5FDC */ - {0x899f, 0x00e68abc}, /* U+62BC */ - {0x89a0, 0x00e697ba}, /* U+65FA */ - {0x89a1, 0x00e6a8aa}, /* U+6A2A */ - {0x89a2, 0x00e6aca7}, /* U+6B27 */ - {0x89a3, 0x00e6aeb4}, /* U+6BB4 */ - {0x89a4, 0x00e78e8b}, /* U+738B */ - {0x89a5, 0x00e7bf81}, /* U+7FC1 */ - {0x89a6, 0x00e8a596}, /* U+8956 */ - {0x89a7, 0x00e9b4ac}, /* U+9D2C */ - {0x89a8, 0x00e9b48e}, /* U+9D0E */ - {0x89a9, 0x00e9bb84}, /* U+9EC4 */ - {0x89aa, 0x00e5b2a1}, /* U+5CA1 */ - {0x89ab, 0x00e6b296}, /* U+6C96 */ - {0x89ac, 0x00e88dbb}, /* U+837B */ - {0x89ad, 0x00e58484}, /* U+5104 */ - {0x89ae, 0x00e5b18b}, /* U+5C4B */ - {0x89af, 0x00e686b6}, /* U+61B6 */ - {0x89b0, 0x00e88786}, /* U+81C6 */ - {0x89b1, 0x00e6a1b6}, /* U+6876 */ - {0x89b2, 0x00e789a1}, /* U+7261 */ - {0x89b3, 0x00e4b999}, /* U+4E59 */ - {0x89b4, 0x00e4bfba}, /* U+4FFA */ - {0x89b5, 0x00e58db8}, /* U+5378 */ - {0x89b6, 0x00e681a9}, /* U+6069 */ - {0x89b7, 0x00e6b8a9}, /* U+6E29 */ - {0x89b8, 0x00e7a98f}, /* U+7A4F */ - {0x89b9, 0x00e99fb3}, /* U+97F3 */ - {0x89ba, 0x00e4b88b}, /* U+4E0B */ - {0x89bb, 0x00e58c96}, /* U+5316 */ - {0x89bc, 0x00e4bbae}, /* U+4EEE */ - {0x89bd, 0x00e4bd95}, /* U+4F55 */ - {0x89be, 0x00e4bcbd}, /* U+4F3D */ - {0x89bf, 0x00e4bea1}, /* U+4FA1 */ - {0x89c0, 0x00e4bdb3}, /* U+4F73 */ - {0x89c1, 0x00e58aa0}, /* U+52A0 */ - {0x89c2, 0x00e58faf}, /* U+53EF */ - {0x89c3, 0x00e59889}, /* U+5609 */ - {0x89c4, 0x00e5a48f}, /* U+590F */ - {0x89c5, 0x00e5ab81}, /* U+5AC1 */ - {0x89c6, 0x00e5aeb6}, /* U+5BB6 */ - {0x89c7, 0x00e5afa1}, /* U+5BE1 */ - {0x89c8, 0x00e7a791}, /* U+79D1 */ - {0x89c9, 0x00e69a87}, /* U+6687 */ - {0x89ca, 0x00e69e9c}, /* U+679C */ - {0x89cb, 0x00e69eb6}, /* U+67B6 */ - {0x89cc, 0x00e6ad8c}, /* U+6B4C */ - {0x89cd, 0x00e6b2b3}, /* U+6CB3 */ - {0x89ce, 0x00e781ab}, /* U+706B */ - {0x89cf, 0x00e78f82}, /* U+73C2 */ - {0x89d0, 0x00e7a68d}, /* U+798D */ - {0x89d1, 0x00e7a6be}, /* U+79BE */ - {0x89d2, 0x00e7a8bc}, /* U+7A3C */ - {0x89d3, 0x00e7ae87}, /* U+7B87 */ - {0x89d4, 0x00e88ab1}, /* U+82B1 */ - {0x89d5, 0x00e88b9b}, /* U+82DB */ - {0x89d6, 0x00e88c84}, /* U+8304 */ - {0x89d7, 0x00e88db7}, /* U+8377 */ - {0x89d8, 0x00e88faf}, /* U+83EF */ - {0x89d9, 0x00e88f93}, /* U+83D3 */ - {0x89da, 0x00e89da6}, /* U+8766 */ - {0x89db, 0x00e8aab2}, /* U+8AB2 */ - {0x89dc, 0x00e598a9}, /* U+5629 */ - {0x89dd, 0x00e8b2a8}, /* U+8CA8 */ - {0x89de, 0x00e8bfa6}, /* U+8FE6 */ - {0x89df, 0x00e9818e}, /* U+904E */ - {0x89e0, 0x00e99c9e}, /* U+971E */ - {0x89e1, 0x00e89a8a}, /* U+868A */ - {0x89e2, 0x00e4bf84}, /* U+4FC4 */ - {0x89e3, 0x00e5b3a8}, /* U+5CE8 */ - {0x89e4, 0x00e68891}, /* U+6211 */ - {0x89e5, 0x00e78999}, /* U+7259 */ - {0x89e6, 0x00e794bb}, /* U+753B */ - {0x89e7, 0x00e887a5}, /* U+81E5 */ - {0x89e8, 0x00e88abd}, /* U+82BD */ - {0x89e9, 0x00e89bbe}, /* U+86FE */ - {0x89ea, 0x00e8b380}, /* U+8CC0 */ - {0x89eb, 0x00e99b85}, /* U+96C5 */ - {0x89ec, 0x00e9a493}, /* U+9913 */ - {0x89ed, 0x00e9a795}, /* U+99D5 */ - {0x89ee, 0x00e4bb8b}, /* U+4ECB */ - {0x89ef, 0x00e4bc9a}, /* U+4F1A */ - {0x89f0, 0x00e8a7a3}, /* U+89E3 */ - {0x89f1, 0x00e59b9e}, /* U+56DE */ - {0x89f2, 0x00e5a18a}, /* U+584A */ - {0x89f3, 0x00e5a38a}, /* U+58CA */ - {0x89f4, 0x00e5bbbb}, /* U+5EFB */ - {0x89f5, 0x00e5bfab}, /* U+5FEB */ - {0x89f6, 0x00e680aa}, /* U+602A */ - {0x89f7, 0x00e68294}, /* U+6094 */ - {0x89f8, 0x00e681a2}, /* U+6062 */ - {0x89f9, 0x00e68790}, /* U+61D0 */ - {0x89fa, 0x00e68892}, /* U+6212 */ - {0x89fb, 0x00e68b90}, /* U+62D0 */ - {0x89fc, 0x00e694b9}, /* U+6539 */ - {0x8a40, 0x00e9ad81}, /* U+9B41 */ - {0x8a41, 0x00e699a6}, /* U+6666 */ - {0x8a42, 0x00e6a2b0}, /* U+68B0 */ - {0x8a43, 0x00e6b5b7}, /* U+6D77 */ - {0x8a44, 0x00e781b0}, /* U+7070 */ - {0x8a45, 0x00e7958c}, /* U+754C */ - {0x8a46, 0x00e79a86}, /* U+7686 */ - {0x8a47, 0x00e7b5b5}, /* U+7D75 */ - {0x8a48, 0x00e88aa5}, /* U+82A5 */ - {0x8a49, 0x00e89fb9}, /* U+87F9 */ - {0x8a4a, 0x00e9968b}, /* U+958B */ - {0x8a4b, 0x00e99a8e}, /* U+968E */ - {0x8a4c, 0x00e8b29d}, /* U+8C9D */ - {0x8a4d, 0x00e587b1}, /* U+51F1 */ - {0x8a4e, 0x00e58abe}, /* U+52BE */ - {0x8a4f, 0x00e5a496}, /* U+5916 */ - {0x8a50, 0x00e592b3}, /* U+54B3 */ - {0x8a51, 0x00e5aeb3}, /* U+5BB3 */ - {0x8a52, 0x00e5b496}, /* U+5D16 */ - {0x8a53, 0x00e685a8}, /* U+6168 */ - {0x8a54, 0x00e6a682}, /* U+6982 */ - {0x8a55, 0x00e6b6af}, /* U+6DAF */ - {0x8a56, 0x00e7a28d}, /* U+788D */ - {0x8a57, 0x00e8938b}, /* U+84CB */ - {0x8a58, 0x00e8a197}, /* U+8857 */ - {0x8a59, 0x00e8a9b2}, /* U+8A72 */ - {0x8a5a, 0x00e98ea7}, /* U+93A7 */ - {0x8a5b, 0x00e9aab8}, /* U+9AB8 */ - {0x8a5c, 0x00e6b5ac}, /* U+6D6C */ - {0x8a5d, 0x00e9a6a8}, /* U+99A8 */ - {0x8a5e, 0x00e89b99}, /* U+86D9 */ - {0x8a5f, 0x00e59ea3}, /* U+57A3 */ - {0x8a60, 0x00e69fbf}, /* U+67FF */ - {0x8a61, 0x00e89b8e}, /* U+86CE */ - {0x8a62, 0x00e9888e}, /* U+920E */ - {0x8a63, 0x00e58a83}, /* U+5283 */ - {0x8a64, 0x00e59a87}, /* U+5687 */ - {0x8a65, 0x00e59084}, /* U+5404 */ - {0x8a66, 0x00e5bb93}, /* U+5ED3 */ - {0x8a67, 0x00e68ba1}, /* U+62E1 */ - {0x8a68, 0x00e692b9}, /* U+64B9 */ - {0x8a69, 0x00e6a0bc}, /* U+683C */ - {0x8a6a, 0x00e6a0b8}, /* U+6838 */ - {0x8a6b, 0x00e6aebb}, /* U+6BBB */ - {0x8a6c, 0x00e78db2}, /* U+7372 */ - {0x8a6d, 0x00e7a2ba}, /* U+78BA */ - {0x8a6e, 0x00e7a9ab}, /* U+7A6B */ - {0x8a6f, 0x00e8a69a}, /* U+899A */ - {0x8a70, 0x00e8a792}, /* U+89D2 */ - {0x8a71, 0x00e8b5ab}, /* U+8D6B */ - {0x8a72, 0x00e8bc83}, /* U+8F03 */ - {0x8a73, 0x00e983ad}, /* U+90ED */ - {0x8a74, 0x00e996a3}, /* U+95A3 */ - {0x8a75, 0x00e99a94}, /* U+9694 */ - {0x8a76, 0x00e99da9}, /* U+9769 */ - {0x8a77, 0x00e5ada6}, /* U+5B66 */ - {0x8a78, 0x00e5b2b3}, /* U+5CB3 */ - {0x8a79, 0x00e6a5bd}, /* U+697D */ - {0x8a7a, 0x00e9a18d}, /* U+984D */ - {0x8a7b, 0x00e9a18e}, /* U+984E */ - {0x8a7c, 0x00e68e9b}, /* U+639B */ - {0x8a7d, 0x00e7aca0}, /* U+7B20 */ - {0x8a7e, 0x00e6a8ab}, /* U+6A2B */ - {0x8a80, 0x00e6a9bf}, /* U+6A7F */ - {0x8a81, 0x00e6a2b6}, /* U+68B6 */ - {0x8a82, 0x00e9b08d}, /* U+9C0D */ - {0x8a83, 0x00e6bd9f}, /* U+6F5F */ - {0x8a84, 0x00e589b2}, /* U+5272 */ - {0x8a85, 0x00e5969d}, /* U+559D */ - {0x8a86, 0x00e681b0}, /* U+6070 */ - {0x8a87, 0x00e68bac}, /* U+62EC */ - {0x8a88, 0x00e6b4bb}, /* U+6D3B */ - {0x8a89, 0x00e6b887}, /* U+6E07 */ - {0x8a8a, 0x00e6bb91}, /* U+6ED1 */ - {0x8a8b, 0x00e8919b}, /* U+845B */ - {0x8a8c, 0x00e8a490}, /* U+8910 */ - {0x8a8d, 0x00e8bd84}, /* U+8F44 */ - {0x8a8e, 0x00e4b894}, /* U+4E14 */ - {0x8a8f, 0x00e9b0b9}, /* U+9C39 */ - {0x8a90, 0x00e58fb6}, /* U+53F6 */ - {0x8a91, 0x00e6a49b}, /* U+691B */ - {0x8a92, 0x00e6a8ba}, /* U+6A3A */ - {0x8a93, 0x00e99e84}, /* U+9784 */ - {0x8a94, 0x00e6a0aa}, /* U+682A */ - {0x8a95, 0x00e5859c}, /* U+515C */ - {0x8a96, 0x00e7ab83}, /* U+7AC3 */ - {0x8a97, 0x00e892b2}, /* U+84B2 */ - {0x8a98, 0x00e9879c}, /* U+91DC */ - {0x8a99, 0x00e98e8c}, /* U+938C */ - {0x8a9a, 0x00e5999b}, /* U+565B */ - {0x8a9b, 0x00e9b4a8}, /* U+9D28 */ - {0x8a9c, 0x00e6a0a2}, /* U+6822 */ - {0x8a9d, 0x00e88c85}, /* U+8305 */ - {0x8a9e, 0x00e890b1}, /* U+8431 */ - {0x8a9f, 0x00e7b2a5}, /* U+7CA5 */ - {0x8aa0, 0x00e58888}, /* U+5208 */ - {0x8aa1, 0x00e88b85}, /* U+82C5 */ - {0x8aa2, 0x00e793a6}, /* U+74E6 */ - {0x8aa3, 0x00e4b9be}, /* U+4E7E */ - {0x8aa4, 0x00e4be83}, /* U+4F83 */ - {0x8aa5, 0x00e586a0}, /* U+51A0 */ - {0x8aa6, 0x00e5af92}, /* U+5BD2 */ - {0x8aa7, 0x00e5888a}, /* U+520A */ - {0x8aa8, 0x00e58b98}, /* U+52D8 */ - {0x8aa9, 0x00e58ba7}, /* U+52E7 */ - {0x8aaa, 0x00e5b7bb}, /* U+5DFB */ - {0x8aab, 0x00e5969a}, /* U+559A */ - {0x8aac, 0x00e5a0aa}, /* U+582A */ - {0x8aad, 0x00e5a7a6}, /* U+59E6 */ - {0x8aae, 0x00e5ae8c}, /* U+5B8C */ - {0x8aaf, 0x00e5ae98}, /* U+5B98 */ - {0x8ab0, 0x00e5af9b}, /* U+5BDB */ - {0x8ab1, 0x00e5b9b2}, /* U+5E72 */ - {0x8ab2, 0x00e5b9b9}, /* U+5E79 */ - {0x8ab3, 0x00e682a3}, /* U+60A3 */ - {0x8ab4, 0x00e6849f}, /* U+611F */ - {0x8ab5, 0x00e685a3}, /* U+6163 */ - {0x8ab6, 0x00e686be}, /* U+61BE */ - {0x8ab7, 0x00e68f9b}, /* U+63DB */ - {0x8ab8, 0x00e695a2}, /* U+6562 */ - {0x8ab9, 0x00e69f91}, /* U+67D1 */ - {0x8aba, 0x00e6a193}, /* U+6853 */ - {0x8abb, 0x00e6a3ba}, /* U+68FA */ - {0x8abc, 0x00e6acbe}, /* U+6B3E */ - {0x8abd, 0x00e6ad93}, /* U+6B53 */ - {0x8abe, 0x00e6b197}, /* U+6C57 */ - {0x8abf, 0x00e6bca2}, /* U+6F22 */ - {0x8ac0, 0x00e6be97}, /* U+6F97 */ - {0x8ac1, 0x00e6bd85}, /* U+6F45 */ - {0x8ac2, 0x00e792b0}, /* U+74B0 */ - {0x8ac3, 0x00e79498}, /* U+7518 */ - {0x8ac4, 0x00e79ba3}, /* U+76E3 */ - {0x8ac5, 0x00e79c8b}, /* U+770B */ - {0x8ac6, 0x00e7abbf}, /* U+7AFF */ - {0x8ac7, 0x00e7aea1}, /* U+7BA1 */ - {0x8ac8, 0x00e7b0a1}, /* U+7C21 */ - {0x8ac9, 0x00e7b7a9}, /* U+7DE9 */ - {0x8aca, 0x00e7bcb6}, /* U+7F36 */ - {0x8acb, 0x00e7bfb0}, /* U+7FF0 */ - {0x8acc, 0x00e8829d}, /* U+809D */ - {0x8acd, 0x00e889a6}, /* U+8266 */ - {0x8ace, 0x00e88e9e}, /* U+839E */ - {0x8acf, 0x00e8a6b3}, /* U+89B3 */ - {0x8ad0, 0x00e8ab8c}, /* U+8ACC */ - {0x8ad1, 0x00e8b2ab}, /* U+8CAB */ - {0x8ad2, 0x00e98284}, /* U+9084 */ - {0x8ad3, 0x00e99191}, /* U+9451 */ - {0x8ad4, 0x00e99693}, /* U+9593 */ - {0x8ad5, 0x00e99691}, /* U+9591 */ - {0x8ad6, 0x00e996a2}, /* U+95A2 */ - {0x8ad7, 0x00e999a5}, /* U+9665 */ - {0x8ad8, 0x00e99f93}, /* U+97D3 */ - {0x8ad9, 0x00e9a4a8}, /* U+9928 */ - {0x8ada, 0x00e88898}, /* U+8218 */ - {0x8adb, 0x00e4b8b8}, /* U+4E38 */ - {0x8adc, 0x00e590ab}, /* U+542B */ - {0x8add, 0x00e5b2b8}, /* U+5CB8 */ - {0x8ade, 0x00e5b78c}, /* U+5DCC */ - {0x8adf, 0x00e78ea9}, /* U+73A9 */ - {0x8ae0, 0x00e7998c}, /* U+764C */ - {0x8ae1, 0x00e79cbc}, /* U+773C */ - {0x8ae2, 0x00e5b2a9}, /* U+5CA9 */ - {0x8ae3, 0x00e7bfab}, /* U+7FEB */ - {0x8ae4, 0x00e8b48b}, /* U+8D0B */ - {0x8ae5, 0x00e99b81}, /* U+96C1 */ - {0x8ae6, 0x00e9a091}, /* U+9811 */ - {0x8ae7, 0x00e9a194}, /* U+9854 */ - {0x8ae8, 0x00e9a198}, /* U+9858 */ - {0x8ae9, 0x00e4bc81}, /* U+4F01 */ - {0x8aea, 0x00e4bc8e}, /* U+4F0E */ - {0x8aeb, 0x00e58db1}, /* U+5371 */ - {0x8aec, 0x00e5969c}, /* U+559C */ - {0x8aed, 0x00e599a8}, /* U+5668 */ - {0x8aee, 0x00e59fba}, /* U+57FA */ - {0x8aef, 0x00e5a587}, /* U+5947 */ - {0x8af0, 0x00e5ac89}, /* U+5B09 */ - {0x8af1, 0x00e5af84}, /* U+5BC4 */ - {0x8af2, 0x00e5b290}, /* U+5C90 */ - {0x8af3, 0x00e5b88c}, /* U+5E0C */ - {0x8af4, 0x00e5b9be}, /* U+5E7E */ - {0x8af5, 0x00e5bf8c}, /* U+5FCC */ - {0x8af6, 0x00e68fae}, /* U+63EE */ - {0x8af7, 0x00e69cba}, /* U+673A */ - {0x8af8, 0x00e69797}, /* U+65D7 */ - {0x8af9, 0x00e697a2}, /* U+65E2 */ - {0x8afa, 0x00e69c9f}, /* U+671F */ - {0x8afb, 0x00e6a38b}, /* U+68CB */ - {0x8afc, 0x00e6a384}, /* U+68C4 */ - {0x8b40, 0x00e6a99f}, /* U+6A5F */ - {0x8b41, 0x00e5b8b0}, /* U+5E30 */ - {0x8b42, 0x00e6af85}, /* U+6BC5 */ - {0x8b43, 0x00e6b097}, /* U+6C17 */ - {0x8b44, 0x00e6b1bd}, /* U+6C7D */ - {0x8b45, 0x00e795bf}, /* U+757F */ - {0x8b46, 0x00e7a588}, /* U+7948 */ - {0x8b47, 0x00e5ada3}, /* U+5B63 */ - {0x8b48, 0x00e7a880}, /* U+7A00 */ - {0x8b49, 0x00e7b480}, /* U+7D00 */ - {0x8b4a, 0x00e5bebd}, /* U+5FBD */ - {0x8b4b, 0x00e8a68f}, /* U+898F */ - {0x8b4c, 0x00e8a898}, /* U+8A18 */ - {0x8b4d, 0x00e8b2b4}, /* U+8CB4 */ - {0x8b4e, 0x00e8b5b7}, /* U+8D77 */ - {0x8b4f, 0x00e8bb8c}, /* U+8ECC */ - {0x8b50, 0x00e8bc9d}, /* U+8F1D */ - {0x8b51, 0x00e9a3a2}, /* U+98E2 */ - {0x8b52, 0x00e9a88e}, /* U+9A0E */ - {0x8b53, 0x00e9acbc}, /* U+9B3C */ - {0x8b54, 0x00e4ba80}, /* U+4E80 */ - {0x8b55, 0x00e581bd}, /* U+507D */ - {0x8b56, 0x00e58480}, /* U+5100 */ - {0x8b57, 0x00e5a693}, /* U+5993 */ - {0x8b58, 0x00e5ae9c}, /* U+5B9C */ - {0x8b59, 0x00e688af}, /* U+622F */ - {0x8b5a, 0x00e68a80}, /* U+6280 */ - {0x8b5b, 0x00e693ac}, /* U+64EC */ - {0x8b5c, 0x00e6acba}, /* U+6B3A */ - {0x8b5d, 0x00e78aa0}, /* U+72A0 */ - {0x8b5e, 0x00e79691}, /* U+7591 */ - {0x8b5f, 0x00e7a587}, /* U+7947 */ - {0x8b60, 0x00e7bea9}, /* U+7FA9 */ - {0x8b61, 0x00e89fbb}, /* U+87FB */ - {0x8b62, 0x00e8aabc}, /* U+8ABC */ - {0x8b63, 0x00e8adb0}, /* U+8B70 */ - {0x8b64, 0x00e68eac}, /* U+63AC */ - {0x8b65, 0x00e88f8a}, /* U+83CA */ - {0x8b66, 0x00e99ea0}, /* U+97A0 */ - {0x8b67, 0x00e59089}, /* U+5409 */ - {0x8b68, 0x00e59083}, /* U+5403 */ - {0x8b69, 0x00e596ab}, /* U+55AB */ - {0x8b6a, 0x00e6a194}, /* U+6854 */ - {0x8b6b, 0x00e6a998}, /* U+6A58 */ - {0x8b6c, 0x00e8a9b0}, /* U+8A70 */ - {0x8b6d, 0x00e7a0a7}, /* U+7827 */ - {0x8b6e, 0x00e69db5}, /* U+6775 */ - {0x8b6f, 0x00e9bb8d}, /* U+9ECD */ - {0x8b70, 0x00e58db4}, /* U+5374 */ - {0x8b71, 0x00e5aea2}, /* U+5BA2 */ - {0x8b72, 0x00e8849a}, /* U+811A */ - {0x8b73, 0x00e89990}, /* U+8650 */ - {0x8b74, 0x00e98086}, /* U+9006 */ - {0x8b75, 0x00e4b898}, /* U+4E18 */ - {0x8b76, 0x00e4b985}, /* U+4E45 */ - {0x8b77, 0x00e4bb87}, /* U+4EC7 */ - {0x8b78, 0x00e4bc91}, /* U+4F11 */ - {0x8b79, 0x00e58f8a}, /* U+53CA */ - {0x8b7a, 0x00e590b8}, /* U+5438 */ - {0x8b7b, 0x00e5aeae}, /* U+5BAE */ - {0x8b7c, 0x00e5bc93}, /* U+5F13 */ - {0x8b7d, 0x00e680a5}, /* U+6025 */ - {0x8b7e, 0x00e69591}, /* U+6551 */ - {0x8b80, 0x00e69cbd}, /* U+673D */ - {0x8b81, 0x00e6b182}, /* U+6C42 */ - {0x8b82, 0x00e6b1b2}, /* U+6C72 */ - {0x8b83, 0x00e6b3a3}, /* U+6CE3 */ - {0x8b84, 0x00e781b8}, /* U+7078 */ - {0x8b85, 0x00e79083}, /* U+7403 */ - {0x8b86, 0x00e7a9b6}, /* U+7A76 */ - {0x8b87, 0x00e7aaae}, /* U+7AAE */ - {0x8b88, 0x00e7ac88}, /* U+7B08 */ - {0x8b89, 0x00e7b49a}, /* U+7D1A */ - {0x8b8a, 0x00e7b3be}, /* U+7CFE */ - {0x8b8b, 0x00e7b5a6}, /* U+7D66 */ - {0x8b8c, 0x00e697a7}, /* U+65E7 */ - {0x8b8d, 0x00e7899b}, /* U+725B */ - {0x8b8e, 0x00e58ebb}, /* U+53BB */ - {0x8b8f, 0x00e5b185}, /* U+5C45 */ - {0x8b90, 0x00e5b7a8}, /* U+5DE8 */ - {0x8b91, 0x00e68b92}, /* U+62D2 */ - {0x8b92, 0x00e68ba0}, /* U+62E0 */ - {0x8b93, 0x00e68c99}, /* U+6319 */ - {0x8b94, 0x00e6b8a0}, /* U+6E20 */ - {0x8b95, 0x00e8999a}, /* U+865A */ - {0x8b96, 0x00e8a8b1}, /* U+8A31 */ - {0x8b97, 0x00e8b79d}, /* U+8DDD */ - {0x8b98, 0x00e98bb8}, /* U+92F8 */ - {0x8b99, 0x00e6bc81}, /* U+6F01 */ - {0x8b9a, 0x00e7a6a6}, /* U+79A6 */ - {0x8b9b, 0x00e9ad9a}, /* U+9B5A */ - {0x8b9c, 0x00e4baa8}, /* U+4EA8 */ - {0x8b9d, 0x00e4baab}, /* U+4EAB */ - {0x8b9e, 0x00e4baac}, /* U+4EAC */ - {0x8b9f, 0x00e4be9b}, /* U+4F9B */ - {0x8ba0, 0x00e4bea0}, /* U+4FA0 */ - {0x8ba1, 0x00e58391}, /* U+50D1 */ - {0x8ba2, 0x00e58587}, /* U+5147 */ - {0x8ba3, 0x00e7abb6}, /* U+7AF6 */ - {0x8ba4, 0x00e585b1}, /* U+5171 */ - {0x8ba5, 0x00e587b6}, /* U+51F6 */ - {0x8ba6, 0x00e58d94}, /* U+5354 */ - {0x8ba7, 0x00e58ca1}, /* U+5321 */ - {0x8ba8, 0x00e58dbf}, /* U+537F */ - {0x8ba9, 0x00e58fab}, /* U+53EB */ - {0x8baa, 0x00e596ac}, /* U+55AC */ - {0x8bab, 0x00e5a283}, /* U+5883 */ - {0x8bac, 0x00e5b3a1}, /* U+5CE1 */ - {0x8bad, 0x00e5bcb7}, /* U+5F37 */ - {0x8bae, 0x00e5bd8a}, /* U+5F4A */ - {0x8baf, 0x00e680af}, /* U+602F */ - {0x8bb0, 0x00e68190}, /* U+6050 */ - {0x8bb1, 0x00e681ad}, /* U+606D */ - {0x8bb2, 0x00e68c9f}, /* U+631F */ - {0x8bb3, 0x00e69599}, /* U+6559 */ - {0x8bb4, 0x00e6a98b}, /* U+6A4B */ - {0x8bb5, 0x00e6b381}, /* U+6CC1 */ - {0x8bb6, 0x00e78b82}, /* U+72C2 */ - {0x8bb7, 0x00e78bad}, /* U+72ED */ - {0x8bb8, 0x00e79faf}, /* U+77EF */ - {0x8bb9, 0x00e883b8}, /* U+80F8 */ - {0x8bba, 0x00e88485}, /* U+8105 */ - {0x8bbb, 0x00e88888}, /* U+8208 */ - {0x8bbc, 0x00e8958e}, /* U+854E */ - {0x8bbd, 0x00e983b7}, /* U+90F7 */ - {0x8bbe, 0x00e98fa1}, /* U+93E1 */ - {0x8bbf, 0x00e99fbf}, /* U+97FF */ - {0x8bc0, 0x00e9a597}, /* U+9957 */ - {0x8bc1, 0x00e9a99a}, /* U+9A5A */ - {0x8bc2, 0x00e4bbb0}, /* U+4EF0 */ - {0x8bc3, 0x00e5879d}, /* U+51DD */ - {0x8bc4, 0x00e5b0ad}, /* U+5C2D */ - {0x8bc5, 0x00e69a81}, /* U+6681 */ - {0x8bc6, 0x00e6a5ad}, /* U+696D */ - {0x8bc7, 0x00e5b180}, /* U+5C40 */ - {0x8bc8, 0x00e69bb2}, /* U+66F2 */ - {0x8bc9, 0x00e6a5b5}, /* U+6975 */ - {0x8bca, 0x00e78e89}, /* U+7389 */ - {0x8bcb, 0x00e6a190}, /* U+6850 */ - {0x8bcc, 0x00e7b281}, /* U+7C81 */ - {0x8bcd, 0x00e58385}, /* U+50C5 */ - {0x8bce, 0x00e58ba4}, /* U+52E4 */ - {0x8bcf, 0x00e59d87}, /* U+5747 */ - {0x8bd0, 0x00e5b7be}, /* U+5DFE */ - {0x8bd1, 0x00e98ca6}, /* U+9326 */ - {0x8bd2, 0x00e696a4}, /* U+65A4 */ - {0x8bd3, 0x00e6aca3}, /* U+6B23 */ - {0x8bd4, 0x00e6acbd}, /* U+6B3D */ - {0x8bd5, 0x00e790b4}, /* U+7434 */ - {0x8bd6, 0x00e7a681}, /* U+7981 */ - {0x8bd7, 0x00e7a6bd}, /* U+79BD */ - {0x8bd8, 0x00e7ad8b}, /* U+7B4B */ - {0x8bd9, 0x00e7b78a}, /* U+7DCA */ - {0x8bda, 0x00e88ab9}, /* U+82B9 */ - {0x8bdb, 0x00e88f8c}, /* U+83CC */ - {0x8bdc, 0x00e8a1bf}, /* U+887F */ - {0x8bdd, 0x00e8a59f}, /* U+895F */ - {0x8bde, 0x00e8acb9}, /* U+8B39 */ - {0x8bdf, 0x00e8bf91}, /* U+8FD1 */ - {0x8be0, 0x00e98791}, /* U+91D1 */ - {0x8be1, 0x00e5909f}, /* U+541F */ - {0x8be2, 0x00e98a80}, /* U+9280 */ - {0x8be3, 0x00e4b99d}, /* U+4E5D */ - {0x8be4, 0x00e580b6}, /* U+5036 */ - {0x8be5, 0x00e58fa5}, /* U+53E5 */ - {0x8be6, 0x00e58cba}, /* U+533A */ - {0x8be7, 0x00e78b97}, /* U+72D7 */ - {0x8be8, 0x00e78e96}, /* U+7396 */ - {0x8be9, 0x00e79fa9}, /* U+77E9 */ - {0x8bea, 0x00e88ba6}, /* U+82E6 */ - {0x8beb, 0x00e8baaf}, /* U+8EAF */ - {0x8bec, 0x00e9a786}, /* U+99C6 */ - {0x8bed, 0x00e9a788}, /* U+99C8 */ - {0x8bee, 0x00e9a792}, /* U+99D2 */ - {0x8bef, 0x00e585b7}, /* U+5177 */ - {0x8bf0, 0x00e6849a}, /* U+611A */ - {0x8bf1, 0x00e8999e}, /* U+865E */ - {0x8bf2, 0x00e596b0}, /* U+55B0 */ - {0x8bf3, 0x00e7a9ba}, /* U+7A7A */ - {0x8bf4, 0x00e581b6}, /* U+5076 */ - {0x8bf5, 0x00e5af93}, /* U+5BD3 */ - {0x8bf6, 0x00e98187}, /* U+9047 */ - {0x8bf7, 0x00e99a85}, /* U+9685 */ - {0x8bf8, 0x00e4b8b2}, /* U+4E32 */ - {0x8bf9, 0x00e6ab9b}, /* U+6ADB */ - {0x8bfa, 0x00e987a7}, /* U+91E7 */ - {0x8bfb, 0x00e5b191}, /* U+5C51 */ - {0x8bfc, 0x00e5b188}, /* U+5C48 */ - {0x8c40, 0x00e68e98}, /* U+6398 */ - {0x8c41, 0x00e7aa9f}, /* U+7A9F */ - {0x8c42, 0x00e6b293}, /* U+6C93 */ - {0x8c43, 0x00e99db4}, /* U+9774 */ - {0x8c44, 0x00e8bda1}, /* U+8F61 */ - {0x8c45, 0x00e7aaaa}, /* U+7AAA */ - {0x8c46, 0x00e7868a}, /* U+718A */ - {0x8c47, 0x00e99a88}, /* U+9688 */ - {0x8c48, 0x00e7b282}, /* U+7C82 */ - {0x8c49, 0x00e6a097}, /* U+6817 */ - {0x8c4a, 0x00e7b9b0}, /* U+7E70 */ - {0x8c4b, 0x00e6a191}, /* U+6851 */ - {0x8c4c, 0x00e98dac}, /* U+936C */ - {0x8c4d, 0x00e58bb2}, /* U+52F2 */ - {0x8c4e, 0x00e5909b}, /* U+541B */ - {0x8c4f, 0x00e896ab}, /* U+85AB */ - {0x8c50, 0x00e8a893}, /* U+8A13 */ - {0x8c51, 0x00e7bea4}, /* U+7FA4 */ - {0x8c52, 0x00e8bb8d}, /* U+8ECD */ - {0x8c53, 0x00e983a1}, /* U+90E1 */ - {0x8c54, 0x00e58da6}, /* U+5366 */ - {0x8c55, 0x00e8a288}, /* U+8888 */ - {0x8c56, 0x00e7a581}, /* U+7941 */ - {0x8c57, 0x00e4bf82}, /* U+4FC2 */ - {0x8c58, 0x00e582be}, /* U+50BE */ - {0x8c59, 0x00e58891}, /* U+5211 */ - {0x8c5a, 0x00e58584}, /* U+5144 */ - {0x8c5b, 0x00e59593}, /* U+5553 */ - {0x8c5c, 0x00e59cad}, /* U+572D */ - {0x8c5d, 0x00e78faa}, /* U+73EA */ - {0x8c5e, 0x00e59e8b}, /* U+578B */ - {0x8c5f, 0x00e5a591}, /* U+5951 */ - {0x8c60, 0x00e5bda2}, /* U+5F62 */ - {0x8c61, 0x00e5be84}, /* U+5F84 */ - {0x8c62, 0x00e681b5}, /* U+6075 */ - {0x8c63, 0x00e685b6}, /* U+6176 */ - {0x8c64, 0x00e685a7}, /* U+6167 */ - {0x8c65, 0x00e686a9}, /* U+61A9 */ - {0x8c66, 0x00e68eb2}, /* U+63B2 */ - {0x8c67, 0x00e690ba}, /* U+643A */ - {0x8c68, 0x00e695ac}, /* U+656C */ - {0x8c69, 0x00e699af}, /* U+666F */ - {0x8c6a, 0x00e6a182}, /* U+6842 */ - {0x8c6b, 0x00e6b893}, /* U+6E13 */ - {0x8c6c, 0x00e795a6}, /* U+7566 */ - {0x8c6d, 0x00e7a8bd}, /* U+7A3D */ - {0x8c6e, 0x00e7b3bb}, /* U+7CFB */ - {0x8c6f, 0x00e7b58c}, /* U+7D4C */ - {0x8c70, 0x00e7b699}, /* U+7D99 */ - {0x8c71, 0x00e7b98b}, /* U+7E4B */ - {0x8c72, 0x00e7bdab}, /* U+7F6B */ - {0x8c73, 0x00e88c8e}, /* U+830E */ - {0x8c74, 0x00e88d8a}, /* U+834A */ - {0x8c75, 0x00e89b8d}, /* U+86CD */ - {0x8c76, 0x00e8a888}, /* U+8A08 */ - {0x8c77, 0x00e8a9a3}, /* U+8A63 */ - {0x8c78, 0x00e8ada6}, /* U+8B66 */ - {0x8c79, 0x00e8bbbd}, /* U+8EFD */ - {0x8c7a, 0x00e9a09a}, /* U+981A */ - {0x8c7b, 0x00e9b68f}, /* U+9D8F */ - {0x8c7c, 0x00e88ab8}, /* U+82B8 */ - {0x8c7d, 0x00e8bf8e}, /* U+8FCE */ - {0x8c7e, 0x00e9afa8}, /* U+9BE8 */ - {0x8c80, 0x00e58a87}, /* U+5287 */ - {0x8c81, 0x00e6889f}, /* U+621F */ - {0x8c82, 0x00e69283}, /* U+6483 */ - {0x8c83, 0x00e6bf80}, /* U+6FC0 */ - {0x8c84, 0x00e99a99}, /* U+9699 */ - {0x8c85, 0x00e6a181}, /* U+6841 */ - {0x8c86, 0x00e58291}, /* U+5091 */ - {0x8c87, 0x00e6aca0}, /* U+6B20 */ - {0x8c88, 0x00e6b1ba}, /* U+6C7A */ - {0x8c89, 0x00e6bd94}, /* U+6F54 */ - {0x8c8a, 0x00e7a9b4}, /* U+7A74 */ - {0x8c8b, 0x00e7b590}, /* U+7D50 */ - {0x8c8c, 0x00e8a180}, /* U+8840 */ - {0x8c8d, 0x00e8a8a3}, /* U+8A23 */ - {0x8c8e, 0x00e69c88}, /* U+6708 */ - {0x8c8f, 0x00e4bbb6}, /* U+4EF6 */ - {0x8c90, 0x00e580b9}, /* U+5039 */ - {0x8c91, 0x00e580a6}, /* U+5026 */ - {0x8c92, 0x00e581a5}, /* U+5065 */ - {0x8c93, 0x00e585bc}, /* U+517C */ - {0x8c94, 0x00e588b8}, /* U+5238 */ - {0x8c95, 0x00e589a3}, /* U+5263 */ - {0x8c96, 0x00e596a7}, /* U+55A7 */ - {0x8c97, 0x00e59c8f}, /* U+570F */ - {0x8c98, 0x00e5a085}, /* U+5805 */ - {0x8c99, 0x00e5ab8c}, /* U+5ACC */ - {0x8c9a, 0x00e5bbba}, /* U+5EFA */ - {0x8c9b, 0x00e686b2}, /* U+61B2 */ - {0x8c9c, 0x00e687b8}, /* U+61F8 */ - {0x8c9d, 0x00e68bb3}, /* U+62F3 */ - {0x8c9e, 0x00e68db2}, /* U+6372 */ - {0x8c9f, 0x00e6a49c}, /* U+691C */ - {0x8ca0, 0x00e6a8a9}, /* U+6A29 */ - {0x8ca1, 0x00e789bd}, /* U+727D */ - {0x8ca2, 0x00e78aac}, /* U+72AC */ - {0x8ca3, 0x00e78cae}, /* U+732E */ - {0x8ca4, 0x00e7a094}, /* U+7814 */ - {0x8ca5, 0x00e7a1af}, /* U+786F */ - {0x8ca6, 0x00e7b5b9}, /* U+7D79 */ - {0x8ca7, 0x00e79c8c}, /* U+770C */ - {0x8ca8, 0x00e882a9}, /* U+80A9 */ - {0x8ca9, 0x00e8a68b}, /* U+898B */ - {0x8caa, 0x00e8ac99}, /* U+8B19 */ - {0x8cab, 0x00e8b3a2}, /* U+8CE2 */ - {0x8cac, 0x00e8bb92}, /* U+8ED2 */ - {0x8cad, 0x00e981a3}, /* U+9063 */ - {0x8cae, 0x00e98db5}, /* U+9375 */ - {0x8caf, 0x00e999ba}, /* U+967A */ - {0x8cb0, 0x00e9a195}, /* U+9855 */ - {0x8cb1, 0x00e9a893}, /* U+9A13 */ - {0x8cb2, 0x00e9b9b8}, /* U+9E78 */ - {0x8cb3, 0x00e58583}, /* U+5143 */ - {0x8cb4, 0x00e58e9f}, /* U+539F */ - {0x8cb5, 0x00e58eb3}, /* U+53B3 */ - {0x8cb6, 0x00e5b9bb}, /* U+5E7B */ - {0x8cb7, 0x00e5bca6}, /* U+5F26 */ - {0x8cb8, 0x00e6b89b}, /* U+6E1B */ - {0x8cb9, 0x00e6ba90}, /* U+6E90 */ - {0x8cba, 0x00e78e84}, /* U+7384 */ - {0x8cbb, 0x00e78fbe}, /* U+73FE */ - {0x8cbc, 0x00e7b583}, /* U+7D43 */ - {0x8cbd, 0x00e888b7}, /* U+8237 */ - {0x8cbe, 0x00e8a880}, /* U+8A00 */ - {0x8cbf, 0x00e8abba}, /* U+8AFA */ - {0x8cc0, 0x00e99990}, /* U+9650 */ - {0x8cc1, 0x00e4b98e}, /* U+4E4E */ - {0x8cc2, 0x00e5808b}, /* U+500B */ - {0x8cc3, 0x00e58fa4}, /* U+53E4 */ - {0x8cc4, 0x00e591bc}, /* U+547C */ - {0x8cc5, 0x00e59bba}, /* U+56FA */ - {0x8cc6, 0x00e5a791}, /* U+59D1 */ - {0x8cc7, 0x00e5ada4}, /* U+5B64 */ - {0x8cc8, 0x00e5b7b1}, /* U+5DF1 */ - {0x8cc9, 0x00e5baab}, /* U+5EAB */ - {0x8cca, 0x00e5bca7}, /* U+5F27 */ - {0x8ccb, 0x00e688b8}, /* U+6238 */ - {0x8ccc, 0x00e69585}, /* U+6545 */ - {0x8ccd, 0x00e69eaf}, /* U+67AF */ - {0x8cce, 0x00e6b996}, /* U+6E56 */ - {0x8ccf, 0x00e78b90}, /* U+72D0 */ - {0x8cd0, 0x00e7b38a}, /* U+7CCA */ - {0x8cd1, 0x00e8a2b4}, /* U+88B4 */ - {0x8cd2, 0x00e882a1}, /* U+80A1 */ - {0x8cd3, 0x00e883a1}, /* U+80E1 */ - {0x8cd4, 0x00e88fb0}, /* U+83F0 */ - {0x8cd5, 0x00e8998e}, /* U+864E */ - {0x8cd6, 0x00e8aa87}, /* U+8A87 */ - {0x8cd7, 0x00e8b7a8}, /* U+8DE8 */ - {0x8cd8, 0x00e988b7}, /* U+9237 */ - {0x8cd9, 0x00e99b87}, /* U+96C7 */ - {0x8cda, 0x00e9a1a7}, /* U+9867 */ - {0x8cdb, 0x00e9bc93}, /* U+9F13 */ - {0x8cdc, 0x00e4ba94}, /* U+4E94 */ - {0x8cdd, 0x00e4ba92}, /* U+4E92 */ - {0x8cde, 0x00e4bc8d}, /* U+4F0D */ - {0x8cdf, 0x00e58d88}, /* U+5348 */ - {0x8ce0, 0x00e59189}, /* U+5449 */ - {0x8ce1, 0x00e590be}, /* U+543E */ - {0x8ce2, 0x00e5a8af}, /* U+5A2F */ - {0x8ce3, 0x00e5be8c}, /* U+5F8C */ - {0x8ce4, 0x00e5bea1}, /* U+5FA1 */ - {0x8ce5, 0x00e6829f}, /* U+609F */ - {0x8ce6, 0x00e6a2a7}, /* U+68A7 */ - {0x8ce7, 0x00e6aa8e}, /* U+6A8E */ - {0x8ce8, 0x00e7919a}, /* U+745A */ - {0x8ce9, 0x00e7a281}, /* U+7881 */ - {0x8cea, 0x00e8aa9e}, /* U+8A9E */ - {0x8ceb, 0x00e8aaa4}, /* U+8AA4 */ - {0x8cec, 0x00e8adb7}, /* U+8B77 */ - {0x8ced, 0x00e98690}, /* U+9190 */ - {0x8cee, 0x00e4b99e}, /* U+4E5E */ - {0x8cef, 0x00e9af89}, /* U+9BC9 */ - {0x8cf0, 0x00e4baa4}, /* U+4EA4 */ - {0x8cf1, 0x00e4bdbc}, /* U+4F7C */ - {0x8cf2, 0x00e4beaf}, /* U+4FAF */ - {0x8cf3, 0x00e58099}, /* U+5019 */ - {0x8cf4, 0x00e58096}, /* U+5016 */ - {0x8cf5, 0x00e58589}, /* U+5149 */ - {0x8cf6, 0x00e585ac}, /* U+516C */ - {0x8cf7, 0x00e58a9f}, /* U+529F */ - {0x8cf8, 0x00e58ab9}, /* U+52B9 */ - {0x8cf9, 0x00e58bbe}, /* U+52FE */ - {0x8cfa, 0x00e58e9a}, /* U+539A */ - {0x8cfb, 0x00e58fa3}, /* U+53E3 */ - {0x8cfc, 0x00e59091}, /* U+5411 */ - {0x8d40, 0x00e5908e}, /* U+540E */ - {0x8d41, 0x00e59689}, /* U+5589 */ - {0x8d42, 0x00e59d91}, /* U+5751 */ - {0x8d43, 0x00e59ea2}, /* U+57A2 */ - {0x8d44, 0x00e5a5bd}, /* U+597D */ - {0x8d45, 0x00e5ad94}, /* U+5B54 */ - {0x8d46, 0x00e5ad9d}, /* U+5B5D */ - {0x8d47, 0x00e5ae8f}, /* U+5B8F */ - {0x8d48, 0x00e5b7a5}, /* U+5DE5 */ - {0x8d49, 0x00e5b7a7}, /* U+5DE7 */ - {0x8d4a, 0x00e5b7b7}, /* U+5DF7 */ - {0x8d4b, 0x00e5b9b8}, /* U+5E78 */ - {0x8d4c, 0x00e5ba83}, /* U+5E83 */ - {0x8d4d, 0x00e5ba9a}, /* U+5E9A */ - {0x8d4e, 0x00e5bab7}, /* U+5EB7 */ - {0x8d4f, 0x00e5bc98}, /* U+5F18 */ - {0x8d50, 0x00e68192}, /* U+6052 */ - {0x8d51, 0x00e6858c}, /* U+614C */ - {0x8d52, 0x00e68a97}, /* U+6297 */ - {0x8d53, 0x00e68b98}, /* U+62D8 */ - {0x8d54, 0x00e68ea7}, /* U+63A7 */ - {0x8d55, 0x00e694bb}, /* U+653B */ - {0x8d56, 0x00e69882}, /* U+6602 */ - {0x8d57, 0x00e69983}, /* U+6643 */ - {0x8d58, 0x00e69bb4}, /* U+66F4 */ - {0x8d59, 0x00e69dad}, /* U+676D */ - {0x8d5a, 0x00e6a0a1}, /* U+6821 */ - {0x8d5b, 0x00e6a297}, /* U+6897 */ - {0x8d5c, 0x00e6a78b}, /* U+69CB */ - {0x8d5d, 0x00e6b19f}, /* U+6C5F */ - {0x8d5e, 0x00e6b4aa}, /* U+6D2A */ - {0x8d5f, 0x00e6b5a9}, /* U+6D69 */ - {0x8d60, 0x00e6b8af}, /* U+6E2F */ - {0x8d61, 0x00e6ba9d}, /* U+6E9D */ - {0x8d62, 0x00e794b2}, /* U+7532 */ - {0x8d63, 0x00e79a87}, /* U+7687 */ - {0x8d64, 0x00e7a1ac}, /* U+786C */ - {0x8d65, 0x00e7a8bf}, /* U+7A3F */ - {0x8d66, 0x00e7b3a0}, /* U+7CE0 */ - {0x8d67, 0x00e7b485}, /* U+7D05 */ - {0x8d68, 0x00e7b498}, /* U+7D18 */ - {0x8d69, 0x00e7b59e}, /* U+7D5E */ - {0x8d6a, 0x00e7b6b1}, /* U+7DB1 */ - {0x8d6b, 0x00e88095}, /* U+8015 */ - {0x8d6c, 0x00e88083}, /* U+8003 */ - {0x8d6d, 0x00e882af}, /* U+80AF */ - {0x8d6e, 0x00e882b1}, /* U+80B1 */ - {0x8d6f, 0x00e88594}, /* U+8154 */ - {0x8d70, 0x00e8868f}, /* U+818F */ - {0x8d71, 0x00e888aa}, /* U+822A */ - {0x8d72, 0x00e88d92}, /* U+8352 */ - {0x8d73, 0x00e8a18c}, /* U+884C */ - {0x8d74, 0x00e8a1a1}, /* U+8861 */ - {0x8d75, 0x00e8ac9b}, /* U+8B1B */ - {0x8d76, 0x00e8b2a2}, /* U+8CA2 */ - {0x8d77, 0x00e8b3bc}, /* U+8CFC */ - {0x8d78, 0x00e9838a}, /* U+90CA */ - {0x8d79, 0x00e985b5}, /* U+9175 */ - {0x8d7a, 0x00e989b1}, /* U+9271 */ - {0x8d7b, 0x00e7a0bf}, /* U+783F */ - {0x8d7c, 0x00e98bbc}, /* U+92FC */ - {0x8d7d, 0x00e996a4}, /* U+95A4 */ - {0x8d7e, 0x00e9998d}, /* U+964D */ - {0x8d80, 0x00e9a085}, /* U+9805 */ - {0x8d81, 0x00e9a699}, /* U+9999 */ - {0x8d82, 0x00e9ab98}, /* U+9AD8 */ - {0x8d83, 0x00e9b4bb}, /* U+9D3B */ - {0x8d84, 0x00e5899b}, /* U+525B */ - {0x8d85, 0x00e58aab}, /* U+52AB */ - {0x8d86, 0x00e58fb7}, /* U+53F7 */ - {0x8d87, 0x00e59088}, /* U+5408 */ - {0x8d88, 0x00e5a395}, /* U+58D5 */ - {0x8d89, 0x00e68bb7}, /* U+62F7 */ - {0x8d8a, 0x00e6bfa0}, /* U+6FE0 */ - {0x8d8b, 0x00e8b1aa}, /* U+8C6A */ - {0x8d8c, 0x00e8bd9f}, /* U+8F5F */ - {0x8d8d, 0x00e9bab9}, /* U+9EB9 */ - {0x8d8e, 0x00e5858b}, /* U+514B */ - {0x8d8f, 0x00e588bb}, /* U+523B */ - {0x8d90, 0x00e5918a}, /* U+544A */ - {0x8d91, 0x00e59bbd}, /* U+56FD */ - {0x8d92, 0x00e7a980}, /* U+7A40 */ - {0x8d93, 0x00e985b7}, /* U+9177 */ - {0x8d94, 0x00e9b5a0}, /* U+9D60 */ - {0x8d95, 0x00e9bb92}, /* U+9ED2 */ - {0x8d96, 0x00e78d84}, /* U+7344 */ - {0x8d97, 0x00e6bc89}, /* U+6F09 */ - {0x8d98, 0x00e885b0}, /* U+8170 */ - {0x8d99, 0x00e79491}, /* U+7511 */ - {0x8d9a, 0x00e5bfbd}, /* U+5FFD */ - {0x8d9b, 0x00e6839a}, /* U+60DA */ - {0x8d9c, 0x00e9aaa8}, /* U+9AA8 */ - {0x8d9d, 0x00e78b9b}, /* U+72DB */ - {0x8d9e, 0x00e8bebc}, /* U+8FBC */ - {0x8d9f, 0x00e6ada4}, /* U+6B64 */ - {0x8da0, 0x00e9a083}, /* U+9803 */ - {0x8da1, 0x00e4bb8a}, /* U+4ECA */ - {0x8da2, 0x00e59bb0}, /* U+56F0 */ - {0x8da3, 0x00e59da4}, /* U+5764 */ - {0x8da4, 0x00e5a2be}, /* U+58BE */ - {0x8da5, 0x00e5a99a}, /* U+5A5A */ - {0x8da6, 0x00e681a8}, /* U+6068 */ - {0x8da7, 0x00e68787}, /* U+61C7 */ - {0x8da8, 0x00e6988f}, /* U+660F */ - {0x8da9, 0x00e69886}, /* U+6606 */ - {0x8daa, 0x00e6a0b9}, /* U+6839 */ - {0x8dab, 0x00e6a2b1}, /* U+68B1 */ - {0x8dac, 0x00e6b7b7}, /* U+6DF7 */ - {0x8dad, 0x00e79795}, /* U+75D5 */ - {0x8dae, 0x00e7b4ba}, /* U+7D3A */ - {0x8daf, 0x00e889ae}, /* U+826E */ - {0x8db0, 0x00e9ad82}, /* U+9B42 */ - {0x8db1, 0x00e4ba9b}, /* U+4E9B */ - {0x8db2, 0x00e4bd90}, /* U+4F50 */ - {0x8db3, 0x00e58f89}, /* U+53C9 */ - {0x8db4, 0x00e59486}, /* U+5506 */ - {0x8db5, 0x00e5b5af}, /* U+5D6F */ - {0x8db6, 0x00e5b7a6}, /* U+5DE6 */ - {0x8db7, 0x00e5b7ae}, /* U+5DEE */ - {0x8db8, 0x00e69fbb}, /* U+67FB */ - {0x8db9, 0x00e6b299}, /* U+6C99 */ - {0x8dba, 0x00e791b3}, /* U+7473 */ - {0x8dbb, 0x00e7a082}, /* U+7802 */ - {0x8dbc, 0x00e8a990}, /* U+8A50 */ - {0x8dbd, 0x00e98e96}, /* U+9396 */ - {0x8dbe, 0x00e8a39f}, /* U+88DF */ - {0x8dbf, 0x00e59d90}, /* U+5750 */ - {0x8dc0, 0x00e5baa7}, /* U+5EA7 */ - {0x8dc1, 0x00e68cab}, /* U+632B */ - {0x8dc2, 0x00e582b5}, /* U+50B5 */ - {0x8dc3, 0x00e582ac}, /* U+50AC */ - {0x8dc4, 0x00e5868d}, /* U+518D */ - {0x8dc5, 0x00e69c80}, /* U+6700 */ - {0x8dc6, 0x00e59389}, /* U+54C9 */ - {0x8dc7, 0x00e5a19e}, /* U+585E */ - {0x8dc8, 0x00e5a6bb}, /* U+59BB */ - {0x8dc9, 0x00e5aeb0}, /* U+5BB0 */ - {0x8dca, 0x00e5bda9}, /* U+5F69 */ - {0x8dcb, 0x00e6898d}, /* U+624D */ - {0x8dcc, 0x00e68ea1}, /* U+63A1 */ - {0x8dcd, 0x00e6a0bd}, /* U+683D */ - {0x8dce, 0x00e6adb3}, /* U+6B73 */ - {0x8dcf, 0x00e6b888}, /* U+6E08 */ - {0x8dd0, 0x00e781bd}, /* U+707D */ - {0x8dd1, 0x00e98787}, /* U+91C7 */ - {0x8dd2, 0x00e78a80}, /* U+7280 */ - {0x8dd3, 0x00e7a095}, /* U+7815 */ - {0x8dd4, 0x00e7a0a6}, /* U+7826 */ - {0x8dd5, 0x00e7a5ad}, /* U+796D */ - {0x8dd6, 0x00e6968e}, /* U+658E */ - {0x8dd7, 0x00e7b4b0}, /* U+7D30 */ - {0x8dd8, 0x00e88f9c}, /* U+83DC */ - {0x8dd9, 0x00e8a381}, /* U+88C1 */ - {0x8dda, 0x00e8bc89}, /* U+8F09 */ - {0x8ddb, 0x00e99a9b}, /* U+969B */ - {0x8ddc, 0x00e589a4}, /* U+5264 */ - {0x8ddd, 0x00e59ca8}, /* U+5728 */ - {0x8dde, 0x00e69d90}, /* U+6750 */ - {0x8ddf, 0x00e7bdaa}, /* U+7F6A */ - {0x8de0, 0x00e8b2a1}, /* U+8CA1 */ - {0x8de1, 0x00e586b4}, /* U+51B4 */ - {0x8de2, 0x00e59d82}, /* U+5742 */ - {0x8de3, 0x00e998aa}, /* U+962A */ - {0x8de4, 0x00e5a0ba}, /* U+583A */ - {0x8de5, 0x00e6a68a}, /* U+698A */ - {0x8de6, 0x00e882b4}, /* U+80B4 */ - {0x8de7, 0x00e592b2}, /* U+54B2 */ - {0x8de8, 0x00e5b48e}, /* U+5D0E */ - {0x8de9, 0x00e59fbc}, /* U+57FC */ - {0x8dea, 0x00e7a295}, /* U+7895 */ - {0x8deb, 0x00e9b7ba}, /* U+9DFA */ - {0x8dec, 0x00e4bd9c}, /* U+4F5C */ - {0x8ded, 0x00e5898a}, /* U+524A */ - {0x8dee, 0x00e5928b}, /* U+548B */ - {0x8def, 0x00e690be}, /* U+643E */ - {0x8df0, 0x00e698a8}, /* U+6628 */ - {0x8df1, 0x00e69c94}, /* U+6714 */ - {0x8df2, 0x00e69fb5}, /* U+67F5 */ - {0x8df3, 0x00e7aa84}, /* U+7A84 */ - {0x8df4, 0x00e7ad96}, /* U+7B56 */ - {0x8df5, 0x00e7b4a2}, /* U+7D22 */ - {0x8df6, 0x00e98caf}, /* U+932F */ - {0x8df7, 0x00e6a19c}, /* U+685C */ - {0x8df8, 0x00e9aead}, /* U+9BAD */ - {0x8df9, 0x00e7acb9}, /* U+7B39 */ - {0x8dfa, 0x00e58c99}, /* U+5319 */ - {0x8dfb, 0x00e5868a}, /* U+518A */ - {0x8dfc, 0x00e588b7}, /* U+5237 */ - {0x8e40, 0x00e5af9f}, /* U+5BDF */ - {0x8e41, 0x00e68bb6}, /* U+62F6 */ - {0x8e42, 0x00e692ae}, /* U+64AE */ - {0x8e43, 0x00e693a6}, /* U+64E6 */ - {0x8e44, 0x00e69cad}, /* U+672D */ - {0x8e45, 0x00e6aeba}, /* U+6BBA */ - {0x8e46, 0x00e896a9}, /* U+85A9 */ - {0x8e47, 0x00e99b91}, /* U+96D1 */ - {0x8e48, 0x00e79a90}, /* U+7690 */ - {0x8e49, 0x00e9af96}, /* U+9BD6 */ - {0x8e4a, 0x00e68d8c}, /* U+634C */ - {0x8e4b, 0x00e98c86}, /* U+9306 */ - {0x8e4c, 0x00e9aeab}, /* U+9BAB */ - {0x8e4d, 0x00e79abf}, /* U+76BF */ - {0x8e4e, 0x00e69992}, /* U+6652 */ - {0x8e4f, 0x00e4b889}, /* U+4E09 */ - {0x8e50, 0x00e58298}, /* U+5098 */ - {0x8e51, 0x00e58f82}, /* U+53C2 */ - {0x8e52, 0x00e5b1b1}, /* U+5C71 */ - {0x8e53, 0x00e683a8}, /* U+60E8 */ - {0x8e54, 0x00e69292}, /* U+6492 */ - {0x8e55, 0x00e695a3}, /* U+6563 */ - {0x8e56, 0x00e6a19f}, /* U+685F */ - {0x8e57, 0x00e787a6}, /* U+71E6 */ - {0x8e58, 0x00e78f8a}, /* U+73CA */ - {0x8e59, 0x00e794a3}, /* U+7523 */ - {0x8e5a, 0x00e7ae97}, /* U+7B97 */ - {0x8e5b, 0x00e7ba82}, /* U+7E82 */ - {0x8e5c, 0x00e89a95}, /* U+8695 */ - {0x8e5d, 0x00e8ae83}, /* U+8B83 */ - {0x8e5e, 0x00e8b39b}, /* U+8CDB */ - {0x8e5f, 0x00e985b8}, /* U+9178 */ - {0x8e60, 0x00e9a490}, /* U+9910 */ - {0x8e61, 0x00e696ac}, /* U+65AC */ - {0x8e62, 0x00e69aab}, /* U+66AB */ - {0x8e63, 0x00e6ae8b}, /* U+6B8B */ - {0x8e64, 0x00e4bb95}, /* U+4ED5 */ - {0x8e65, 0x00e4bb94}, /* U+4ED4 */ - {0x8e66, 0x00e4bcba}, /* U+4F3A */ - {0x8e67, 0x00e4bdbf}, /* U+4F7F */ - {0x8e68, 0x00e588ba}, /* U+523A */ - {0x8e69, 0x00e58fb8}, /* U+53F8 */ - {0x8e6a, 0x00e58fb2}, /* U+53F2 */ - {0x8e6b, 0x00e597a3}, /* U+55E3 */ - {0x8e6c, 0x00e59b9b}, /* U+56DB */ - {0x8e6d, 0x00e5a3ab}, /* U+58EB */ - {0x8e6e, 0x00e5a78b}, /* U+59CB */ - {0x8e6f, 0x00e5a789}, /* U+59C9 */ - {0x8e70, 0x00e5a7bf}, /* U+59FF */ - {0x8e71, 0x00e5ad90}, /* U+5B50 */ - {0x8e72, 0x00e5b18d}, /* U+5C4D */ - {0x8e73, 0x00e5b882}, /* U+5E02 */ - {0x8e74, 0x00e5b8ab}, /* U+5E2B */ - {0x8e75, 0x00e5bf97}, /* U+5FD7 */ - {0x8e76, 0x00e6809d}, /* U+601D */ - {0x8e77, 0x00e68c87}, /* U+6307 */ - {0x8e78, 0x00e694af}, /* U+652F */ - {0x8e79, 0x00e5ad9c}, /* U+5B5C */ - {0x8e7a, 0x00e696af}, /* U+65AF */ - {0x8e7b, 0x00e696bd}, /* U+65BD */ - {0x8e7c, 0x00e697a8}, /* U+65E8 */ - {0x8e7d, 0x00e69e9d}, /* U+679D */ - {0x8e7e, 0x00e6ada2}, /* U+6B62 */ - {0x8e80, 0x00e6adbb}, /* U+6B7B */ - {0x8e81, 0x00e6b08f}, /* U+6C0F */ - {0x8e82, 0x00e78d85}, /* U+7345 */ - {0x8e83, 0x00e7a589}, /* U+7949 */ - {0x8e84, 0x00e7a781}, /* U+79C1 */ - {0x8e85, 0x00e7b3b8}, /* U+7CF8 */ - {0x8e86, 0x00e7b499}, /* U+7D19 */ - {0x8e87, 0x00e7b4ab}, /* U+7D2B */ - {0x8e88, 0x00e882a2}, /* U+80A2 */ - {0x8e89, 0x00e88482}, /* U+8102 */ - {0x8e8a, 0x00e887b3}, /* U+81F3 */ - {0x8e8b, 0x00e8a696}, /* U+8996 */ - {0x8e8c, 0x00e8a99e}, /* U+8A5E */ - {0x8e8d, 0x00e8a9a9}, /* U+8A69 */ - {0x8e8e, 0x00e8a9a6}, /* U+8A66 */ - {0x8e8f, 0x00e8aa8c}, /* U+8A8C */ - {0x8e90, 0x00e8abae}, /* U+8AEE */ - {0x8e91, 0x00e8b387}, /* U+8CC7 */ - {0x8e92, 0x00e8b39c}, /* U+8CDC */ - {0x8e93, 0x00e99b8c}, /* U+96CC */ - {0x8e94, 0x00e9a3bc}, /* U+98FC */ - {0x8e95, 0x00e6adaf}, /* U+6B6F */ - {0x8e96, 0x00e4ba8b}, /* U+4E8B */ - {0x8e97, 0x00e4bcbc}, /* U+4F3C */ - {0x8e98, 0x00e4be8d}, /* U+4F8D */ - {0x8e99, 0x00e58590}, /* U+5150 */ - {0x8e9a, 0x00e5ad97}, /* U+5B57 */ - {0x8e9b, 0x00e5afba}, /* U+5BFA */ - {0x8e9c, 0x00e68588}, /* U+6148 */ - {0x8e9d, 0x00e68c81}, /* U+6301 */ - {0x8e9e, 0x00e69982}, /* U+6642 */ - {0x8e9f, 0x00e6aca1}, /* U+6B21 */ - {0x8ea0, 0x00e6bb8b}, /* U+6ECB */ - {0x8ea1, 0x00e6b2bb}, /* U+6CBB */ - {0x8ea2, 0x00e788be}, /* U+723E */ - {0x8ea3, 0x00e792bd}, /* U+74BD */ - {0x8ea4, 0x00e79794}, /* U+75D4 */ - {0x8ea5, 0x00e7a381}, /* U+78C1 */ - {0x8ea6, 0x00e7a4ba}, /* U+793A */ - {0x8ea7, 0x00e8808c}, /* U+800C */ - {0x8ea8, 0x00e880b3}, /* U+8033 */ - {0x8ea9, 0x00e887aa}, /* U+81EA */ - {0x8eaa, 0x00e89294}, /* U+8494 */ - {0x8eab, 0x00e8be9e}, /* U+8F9E */ - {0x8eac, 0x00e6b190}, /* U+6C50 */ - {0x8ead, 0x00e9b9bf}, /* U+9E7F */ - {0x8eae, 0x00e5bc8f}, /* U+5F0F */ - {0x8eaf, 0x00e8ad98}, /* U+8B58 */ - {0x8eb0, 0x00e9b4ab}, /* U+9D2B */ - {0x8eb1, 0x00e7abba}, /* U+7AFA */ - {0x8eb2, 0x00e8bbb8}, /* U+8EF8 */ - {0x8eb3, 0x00e5ae8d}, /* U+5B8D */ - {0x8eb4, 0x00e99bab}, /* U+96EB */ - {0x8eb5, 0x00e4b883}, /* U+4E03 */ - {0x8eb6, 0x00e58fb1}, /* U+53F1 */ - {0x8eb7, 0x00e59fb7}, /* U+57F7 */ - {0x8eb8, 0x00e5a4b1}, /* U+5931 */ - {0x8eb9, 0x00e5ab89}, /* U+5AC9 */ - {0x8eba, 0x00e5aea4}, /* U+5BA4 */ - {0x8ebb, 0x00e68289}, /* U+6089 */ - {0x8ebc, 0x00e6b9bf}, /* U+6E7F */ - {0x8ebd, 0x00e6bc86}, /* U+6F06 */ - {0x8ebe, 0x00e796be}, /* U+75BE */ - {0x8ebf, 0x00e8b3aa}, /* U+8CEA */ - {0x8ec0, 0x00e5ae9f}, /* U+5B9F */ - {0x8ec1, 0x00e89480}, /* U+8500 */ - {0x8ec2, 0x00e7afa0}, /* U+7BE0 */ - {0x8ec3, 0x00e581b2}, /* U+5072 */ - {0x8ec4, 0x00e69fb4}, /* U+67F4 */ - {0x8ec5, 0x00e88a9d}, /* U+829D */ - {0x8ec6, 0x00e5b1a1}, /* U+5C61 */ - {0x8ec7, 0x00e8958a}, /* U+854A */ - {0x8ec8, 0x00e7b89e}, /* U+7E1E */ - {0x8ec9, 0x00e8888e}, /* U+820E */ - {0x8eca, 0x00e58699}, /* U+5199 */ - {0x8ecb, 0x00e5b084}, /* U+5C04 */ - {0x8ecc, 0x00e68da8}, /* U+6368 */ - {0x8ecd, 0x00e8b5a6}, /* U+8D66 */ - {0x8ece, 0x00e6969c}, /* U+659C */ - {0x8ecf, 0x00e785ae}, /* U+716E */ - {0x8ed0, 0x00e7a4be}, /* U+793E */ - {0x8ed1, 0x00e7b497}, /* U+7D17 */ - {0x8ed2, 0x00e88085}, /* U+8005 */ - {0x8ed3, 0x00e8ac9d}, /* U+8B1D */ - {0x8ed4, 0x00e8bb8a}, /* U+8ECA */ - {0x8ed5, 0x00e981ae}, /* U+906E */ - {0x8ed6, 0x00e89b87}, /* U+86C7 */ - {0x8ed7, 0x00e982aa}, /* U+90AA */ - {0x8ed8, 0x00e5809f}, /* U+501F */ - {0x8ed9, 0x00e58bba}, /* U+52FA */ - {0x8eda, 0x00e5b0ba}, /* U+5C3A */ - {0x8edb, 0x00e69d93}, /* U+6753 */ - {0x8edc, 0x00e781bc}, /* U+707C */ - {0x8edd, 0x00e788b5}, /* U+7235 */ - {0x8ede, 0x00e9858c}, /* U+914C */ - {0x8edf, 0x00e98788}, /* U+91C8 */ - {0x8ee0, 0x00e98cab}, /* U+932B */ - {0x8ee1, 0x00e88ba5}, /* U+82E5 */ - {0x8ee2, 0x00e5af82}, /* U+5BC2 */ - {0x8ee3, 0x00e5bcb1}, /* U+5F31 */ - {0x8ee4, 0x00e683b9}, /* U+60F9 */ - {0x8ee5, 0x00e4b8bb}, /* U+4E3B */ - {0x8ee6, 0x00e58f96}, /* U+53D6 */ - {0x8ee7, 0x00e5ae88}, /* U+5B88 */ - {0x8ee8, 0x00e6898b}, /* U+624B */ - {0x8ee9, 0x00e69cb1}, /* U+6731 */ - {0x8eea, 0x00e6ae8a}, /* U+6B8A */ - {0x8eeb, 0x00e78ba9}, /* U+72E9 */ - {0x8eec, 0x00e78fa0}, /* U+73E0 */ - {0x8eed, 0x00e7a8ae}, /* U+7A2E */ - {0x8eee, 0x00e885ab}, /* U+816B */ - {0x8eef, 0x00e8b6a3}, /* U+8DA3 */ - {0x8ef0, 0x00e98592}, /* U+9152 */ - {0x8ef1, 0x00e9a696}, /* U+9996 */ - {0x8ef2, 0x00e58492}, /* U+5112 */ - {0x8ef3, 0x00e58f97}, /* U+53D7 */ - {0x8ef4, 0x00e591aa}, /* U+546A */ - {0x8ef5, 0x00e5afbf}, /* U+5BFF */ - {0x8ef6, 0x00e68e88}, /* U+6388 */ - {0x8ef7, 0x00e6a8b9}, /* U+6A39 */ - {0x8ef8, 0x00e7b6ac}, /* U+7DAC */ - {0x8ef9, 0x00e99c80}, /* U+9700 */ - {0x8efa, 0x00e59b9a}, /* U+56DA */ - {0x8efb, 0x00e58f8e}, /* U+53CE */ - {0x8efc, 0x00e591a8}, /* U+5468 */ - {0x8f40, 0x00e5ae97}, /* U+5B97 */ - {0x8f41, 0x00e5b0b1}, /* U+5C31 */ - {0x8f42, 0x00e5b79e}, /* U+5DDE */ - {0x8f43, 0x00e4bfae}, /* U+4FEE */ - {0x8f44, 0x00e68481}, /* U+6101 */ - {0x8f45, 0x00e68bbe}, /* U+62FE */ - {0x8f46, 0x00e6b4b2}, /* U+6D32 */ - {0x8f47, 0x00e7a780}, /* U+79C0 */ - {0x8f48, 0x00e7a78b}, /* U+79CB */ - {0x8f49, 0x00e7b582}, /* U+7D42 */ - {0x8f4a, 0x00e7b98d}, /* U+7E4D */ - {0x8f4b, 0x00e7bf92}, /* U+7FD2 */ - {0x8f4c, 0x00e887ad}, /* U+81ED */ - {0x8f4d, 0x00e8889f}, /* U+821F */ - {0x8f4e, 0x00e89290}, /* U+8490 */ - {0x8f4f, 0x00e8a186}, /* U+8846 */ - {0x8f50, 0x00e8a5b2}, /* U+8972 */ - {0x8f51, 0x00e8ae90}, /* U+8B90 */ - {0x8f52, 0x00e8b9b4}, /* U+8E74 */ - {0x8f53, 0x00e8bcaf}, /* U+8F2F */ - {0x8f54, 0x00e980b1}, /* U+9031 */ - {0x8f55, 0x00e9858b}, /* U+914B */ - {0x8f56, 0x00e985ac}, /* U+916C */ - {0x8f57, 0x00e99b86}, /* U+96C6 */ - {0x8f58, 0x00e9869c}, /* U+919C */ - {0x8f59, 0x00e4bb80}, /* U+4EC0 */ - {0x8f5a, 0x00e4bd8f}, /* U+4F4F */ - {0x8f5b, 0x00e58585}, /* U+5145 */ - {0x8f5c, 0x00e58d81}, /* U+5341 */ - {0x8f5d, 0x00e5be93}, /* U+5F93 */ - {0x8f5e, 0x00e6888e}, /* U+620E */ - {0x8f5f, 0x00e69f94}, /* U+67D4 */ - {0x8f60, 0x00e6b181}, /* U+6C41 */ - {0x8f61, 0x00e6b88b}, /* U+6E0B */ - {0x8f62, 0x00e78da3}, /* U+7363 */ - {0x8f63, 0x00e7b8a6}, /* U+7E26 */ - {0x8f64, 0x00e9878d}, /* U+91CD */ - {0x8f65, 0x00e98a83}, /* U+9283 */ - {0x8f66, 0x00e58f94}, /* U+53D4 */ - {0x8f67, 0x00e5a499}, /* U+5919 */ - {0x8f68, 0x00e5aebf}, /* U+5BBF */ - {0x8f69, 0x00e6b791}, /* U+6DD1 */ - {0x8f6a, 0x00e7a59d}, /* U+795D */ - {0x8f6b, 0x00e7b8ae}, /* U+7E2E */ - {0x8f6c, 0x00e7b29b}, /* U+7C9B */ - {0x8f6d, 0x00e5a1be}, /* U+587E */ - {0x8f6e, 0x00e7869f}, /* U+719F */ - {0x8f6f, 0x00e587ba}, /* U+51FA */ - {0x8f70, 0x00e8a193}, /* U+8853 */ - {0x8f71, 0x00e8bfb0}, /* U+8FF0 */ - {0x8f72, 0x00e4bf8a}, /* U+4FCA */ - {0x8f73, 0x00e5b3bb}, /* U+5CFB */ - {0x8f74, 0x00e698a5}, /* U+6625 */ - {0x8f75, 0x00e79eac}, /* U+77AC */ - {0x8f76, 0x00e7aba3}, /* U+7AE3 */ - {0x8f77, 0x00e8889c}, /* U+821C */ - {0x8f78, 0x00e9a7bf}, /* U+99FF */ - {0x8f79, 0x00e58786}, /* U+51C6 */ - {0x8f7a, 0x00e5beaa}, /* U+5FAA */ - {0x8f7b, 0x00e697ac}, /* U+65EC */ - {0x8f7c, 0x00e6a5af}, /* U+696F */ - {0x8f7d, 0x00e6ae89}, /* U+6B89 */ - {0x8f7e, 0x00e6b7b3}, /* U+6DF3 */ - {0x8f80, 0x00e6ba96}, /* U+6E96 */ - {0x8f81, 0x00e6bda4}, /* U+6F64 */ - {0x8f82, 0x00e79bbe}, /* U+76FE */ - {0x8f83, 0x00e7b494}, /* U+7D14 */ - {0x8f84, 0x00e5b7a1}, /* U+5DE1 */ - {0x8f85, 0x00e981b5}, /* U+9075 */ - {0x8f86, 0x00e98687}, /* U+9187 */ - {0x8f87, 0x00e9a086}, /* U+9806 */ - {0x8f88, 0x00e587a6}, /* U+51E6 */ - {0x8f89, 0x00e5889d}, /* U+521D */ - {0x8f8a, 0x00e68980}, /* U+6240 */ - {0x8f8b, 0x00e69a91}, /* U+6691 */ - {0x8f8c, 0x00e69b99}, /* U+66D9 */ - {0x8f8d, 0x00e6b89a}, /* U+6E1A */ - {0x8f8e, 0x00e5bab6}, /* U+5EB6 */ - {0x8f8f, 0x00e7b792}, /* U+7DD2 */ - {0x8f90, 0x00e7bdb2}, /* U+7F72 */ - {0x8f91, 0x00e69bb8}, /* U+66F8 */ - {0x8f92, 0x00e896af}, /* U+85AF */ - {0x8f93, 0x00e897b7}, /* U+85F7 */ - {0x8f94, 0x00e8abb8}, /* U+8AF8 */ - {0x8f95, 0x00e58aa9}, /* U+52A9 */ - {0x8f96, 0x00e58f99}, /* U+53D9 */ - {0x8f97, 0x00e5a5b3}, /* U+5973 */ - {0x8f98, 0x00e5ba8f}, /* U+5E8F */ - {0x8f99, 0x00e5be90}, /* U+5F90 */ - {0x8f9a, 0x00e68195}, /* U+6055 */ - {0x8f9b, 0x00e98ba4}, /* U+92E4 */ - {0x8f9c, 0x00e999a4}, /* U+9664 */ - {0x8f9d, 0x00e582b7}, /* U+50B7 */ - {0x8f9e, 0x00e5849f}, /* U+511F */ - {0x8f9f, 0x00e58b9d}, /* U+52DD */ - {0x8fa0, 0x00e58ca0}, /* U+5320 */ - {0x8fa1, 0x00e58d87}, /* U+5347 */ - {0x8fa2, 0x00e58fac}, /* U+53EC */ - {0x8fa3, 0x00e593a8}, /* U+54E8 */ - {0x8fa4, 0x00e59586}, /* U+5546 */ - {0x8fa5, 0x00e594b1}, /* U+5531 */ - {0x8fa6, 0x00e59897}, /* U+5617 */ - {0x8fa7, 0x00e5a5a8}, /* U+5968 */ - {0x8fa8, 0x00e5a6be}, /* U+59BE */ - {0x8fa9, 0x00e5a8bc}, /* U+5A3C */ - {0x8faa, 0x00e5aeb5}, /* U+5BB5 */ - {0x8fab, 0x00e5b086}, /* U+5C06 */ - {0x8fac, 0x00e5b08f}, /* U+5C0F */ - {0x8fad, 0x00e5b091}, /* U+5C11 */ - {0x8fae, 0x00e5b09a}, /* U+5C1A */ - {0x8faf, 0x00e5ba84}, /* U+5E84 */ - {0x8fb0, 0x00e5ba8a}, /* U+5E8A */ - {0x8fb1, 0x00e5bba0}, /* U+5EE0 */ - {0x8fb2, 0x00e5bdb0}, /* U+5F70 */ - {0x8fb3, 0x00e689bf}, /* U+627F */ - {0x8fb4, 0x00e68a84}, /* U+6284 */ - {0x8fb5, 0x00e68b9b}, /* U+62DB */ - {0x8fb6, 0x00e68e8c}, /* U+638C */ - {0x8fb7, 0x00e68db7}, /* U+6377 */ - {0x8fb8, 0x00e69887}, /* U+6607 */ - {0x8fb9, 0x00e6988c}, /* U+660C */ - {0x8fba, 0x00e698ad}, /* U+662D */ - {0x8fbb, 0x00e699b6}, /* U+6676 */ - {0x8fbc, 0x00e69dbe}, /* U+677E */ - {0x8fbd, 0x00e6a2a2}, /* U+68A2 */ - {0x8fbe, 0x00e6a89f}, /* U+6A1F */ - {0x8fbf, 0x00e6a8b5}, /* U+6A35 */ - {0x8fc0, 0x00e6b2bc}, /* U+6CBC */ - {0x8fc1, 0x00e6b688}, /* U+6D88 */ - {0x8fc2, 0x00e6b889}, /* U+6E09 */ - {0x8fc3, 0x00e6b998}, /* U+6E58 */ - {0x8fc4, 0x00e784bc}, /* U+713C */ - {0x8fc5, 0x00e784a6}, /* U+7126 */ - {0x8fc6, 0x00e785a7}, /* U+7167 */ - {0x8fc7, 0x00e79787}, /* U+75C7 */ - {0x8fc8, 0x00e79c81}, /* U+7701 */ - {0x8fc9, 0x00e7a19d}, /* U+785D */ - {0x8fca, 0x00e7a481}, /* U+7901 */ - {0x8fcb, 0x00e7a5a5}, /* U+7965 */ - {0x8fcc, 0x00e7a7b0}, /* U+79F0 */ - {0x8fcd, 0x00e7aba0}, /* U+7AE0 */ - {0x8fce, 0x00e7ac91}, /* U+7B11 */ - {0x8fcf, 0x00e7b2a7}, /* U+7CA7 */ - {0x8fd0, 0x00e7b4b9}, /* U+7D39 */ - {0x8fd1, 0x00e88296}, /* U+8096 */ - {0x8fd2, 0x00e88f96}, /* U+83D6 */ - {0x8fd3, 0x00e8928b}, /* U+848B */ - {0x8fd4, 0x00e89589}, /* U+8549 */ - {0x8fd5, 0x00e8a19d}, /* U+885D */ - {0x8fd6, 0x00e8a3b3}, /* U+88F3 */ - {0x8fd7, 0x00e8a89f}, /* U+8A1F */ - {0x8fd8, 0x00e8a8bc}, /* U+8A3C */ - {0x8fd9, 0x00e8a994}, /* U+8A54 */ - {0x8fda, 0x00e8a9b3}, /* U+8A73 */ - {0x8fdb, 0x00e8b1a1}, /* U+8C61 */ - {0x8fdc, 0x00e8b39e}, /* U+8CDE */ - {0x8fdd, 0x00e986a4}, /* U+91A4 */ - {0x8fde, 0x00e989a6}, /* U+9266 */ - {0x8fdf, 0x00e98dbe}, /* U+937E */ - {0x8fe0, 0x00e99098}, /* U+9418 */ - {0x8fe1, 0x00e99a9c}, /* U+969C */ - {0x8fe2, 0x00e99e98}, /* U+9798 */ - {0x8fe3, 0x00e4b88a}, /* U+4E0A */ - {0x8fe4, 0x00e4b888}, /* U+4E08 */ - {0x8fe5, 0x00e4b89e}, /* U+4E1E */ - {0x8fe6, 0x00e4b997}, /* U+4E57 */ - {0x8fe7, 0x00e58697}, /* U+5197 */ - {0x8fe8, 0x00e589b0}, /* U+5270 */ - {0x8fe9, 0x00e59f8e}, /* U+57CE */ - {0x8fea, 0x00e5a0b4}, /* U+5834 */ - {0x8feb, 0x00e5a38c}, /* U+58CC */ - {0x8fec, 0x00e5aca2}, /* U+5B22 */ - {0x8fed, 0x00e5b8b8}, /* U+5E38 */ - {0x8fee, 0x00e68385}, /* U+60C5 */ - {0x8fef, 0x00e693be}, /* U+64FE */ - {0x8ff0, 0x00e69da1}, /* U+6761 */ - {0x8ff1, 0x00e69d96}, /* U+6756 */ - {0x8ff2, 0x00e6b584}, /* U+6D44 */ - {0x8ff3, 0x00e78ab6}, /* U+72B6 */ - {0x8ff4, 0x00e795b3}, /* U+7573 */ - {0x8ff5, 0x00e7a9a3}, /* U+7A63 */ - {0x8ff6, 0x00e892b8}, /* U+84B8 */ - {0x8ff7, 0x00e8adb2}, /* U+8B72 */ - {0x8ff8, 0x00e986b8}, /* U+91B8 */ - {0x8ff9, 0x00e98ca0}, /* U+9320 */ - {0x8ffa, 0x00e598b1}, /* U+5631 */ - {0x8ffb, 0x00e59fb4}, /* U+57F4 */ - {0x8ffc, 0x00e9a3be}, /* U+98FE */ - {0x9040, 0x00e68bad}, /* U+62ED */ - {0x9041, 0x00e6a48d}, /* U+690D */ - {0x9042, 0x00e6ae96}, /* U+6B96 */ - {0x9043, 0x00e787ad}, /* U+71ED */ - {0x9044, 0x00e7b994}, /* U+7E54 */ - {0x9045, 0x00e881b7}, /* U+8077 */ - {0x9046, 0x00e889b2}, /* U+8272 */ - {0x9047, 0x00e8a7a6}, /* U+89E6 */ - {0x9048, 0x00e9a39f}, /* U+98DF */ - {0x9049, 0x00e89d95}, /* U+8755 */ - {0x904a, 0x00e8beb1}, /* U+8FB1 */ - {0x904b, 0x00e5b0bb}, /* U+5C3B */ - {0x904c, 0x00e4bcb8}, /* U+4F38 */ - {0x904d, 0x00e4bfa1}, /* U+4FE1 */ - {0x904e, 0x00e4beb5}, /* U+4FB5 */ - {0x904f, 0x00e59487}, /* U+5507 */ - {0x9050, 0x00e5a8a0}, /* U+5A20 */ - {0x9051, 0x00e5af9d}, /* U+5BDD */ - {0x9052, 0x00e5afa9}, /* U+5BE9 */ - {0x9053, 0x00e5bf83}, /* U+5FC3 */ - {0x9054, 0x00e6858e}, /* U+614E */ - {0x9055, 0x00e68caf}, /* U+632F */ - {0x9056, 0x00e696b0}, /* U+65B0 */ - {0x9057, 0x00e6998b}, /* U+664B */ - {0x9058, 0x00e6a3ae}, /* U+68EE */ - {0x9059, 0x00e6a69b}, /* U+699B */ - {0x905a, 0x00e6b5b8}, /* U+6D78 */ - {0x905b, 0x00e6b7b1}, /* U+6DF1 */ - {0x905c, 0x00e794b3}, /* U+7533 */ - {0x905d, 0x00e796b9}, /* U+75B9 */ - {0x905e, 0x00e79c9f}, /* U+771F */ - {0x905f, 0x00e7a59e}, /* U+795E */ - {0x9060, 0x00e7a7a6}, /* U+79E6 */ - {0x9061, 0x00e7b4b3}, /* U+7D33 */ - {0x9062, 0x00e887a3}, /* U+81E3 */ - {0x9063, 0x00e88aaf}, /* U+82AF */ - {0x9064, 0x00e896aa}, /* U+85AA */ - {0x9065, 0x00e8a6aa}, /* U+89AA */ - {0x9066, 0x00e8a8ba}, /* U+8A3A */ - {0x9067, 0x00e8baab}, /* U+8EAB */ - {0x9068, 0x00e8be9b}, /* U+8F9B */ - {0x9069, 0x00e980b2}, /* U+9032 */ - {0x906a, 0x00e9879d}, /* U+91DD */ - {0x906b, 0x00e99c87}, /* U+9707 */ - {0x906c, 0x00e4baba}, /* U+4EBA */ - {0x906d, 0x00e4bb81}, /* U+4EC1 */ - {0x906e, 0x00e58883}, /* U+5203 */ - {0x906f, 0x00e5a1b5}, /* U+5875 */ - {0x9070, 0x00e5a3ac}, /* U+58EC */ - {0x9071, 0x00e5b08b}, /* U+5C0B */ - {0x9072, 0x00e7949a}, /* U+751A */ - {0x9073, 0x00e5b0bd}, /* U+5C3D */ - {0x9074, 0x00e8858e}, /* U+814E */ - {0x9075, 0x00e8a88a}, /* U+8A0A */ - {0x9076, 0x00e8bf85}, /* U+8FC5 */ - {0x9077, 0x00e999a3}, /* U+9663 */ - {0x9078, 0x00e99dad}, /* U+976D */ - {0x9079, 0x00e7aca5}, /* U+7B25 */ - {0x907a, 0x00e8ab8f}, /* U+8ACF */ - {0x907b, 0x00e9a088}, /* U+9808 */ - {0x907c, 0x00e985a2}, /* U+9162 */ - {0x907d, 0x00e59bb3}, /* U+56F3 */ - {0x907e, 0x00e58ea8}, /* U+53A8 */ - {0x9080, 0x00e98097}, /* U+9017 */ - {0x9081, 0x00e590b9}, /* U+5439 */ - {0x9082, 0x00e59e82}, /* U+5782 */ - {0x9083, 0x00e5b8a5}, /* U+5E25 */ - {0x9084, 0x00e68ea8}, /* U+63A8 */ - {0x9085, 0x00e6b0b4}, /* U+6C34 */ - {0x9086, 0x00e7828a}, /* U+708A */ - {0x9087, 0x00e79da1}, /* U+7761 */ - {0x9088, 0x00e7b28b}, /* U+7C8B */ - {0x9089, 0x00e7bfa0}, /* U+7FE0 */ - {0x908a, 0x00e8a1b0}, /* U+8870 */ - {0x908b, 0x00e98182}, /* U+9042 */ - {0x908c, 0x00e98594}, /* U+9154 */ - {0x908d, 0x00e98c90}, /* U+9310 */ - {0x908e, 0x00e98c98}, /* U+9318 */ - {0x908f, 0x00e99a8f}, /* U+968F */ - {0x9090, 0x00e7919e}, /* U+745E */ - {0x9091, 0x00e9ab84}, /* U+9AC4 */ - {0x9092, 0x00e5b487}, /* U+5D07 */ - {0x9093, 0x00e5b5a9}, /* U+5D69 */ - {0x9094, 0x00e695b0}, /* U+6570 */ - {0x9095, 0x00e69ea2}, /* U+67A2 */ - {0x9096, 0x00e8b6a8}, /* U+8DA8 */ - {0x9097, 0x00e99b9b}, /* U+96DB */ - {0x9098, 0x00e68dae}, /* U+636E */ - {0x9099, 0x00e69d89}, /* U+6749 */ - {0x909a, 0x00e6a499}, /* U+6919 */ - {0x909b, 0x00e88f85}, /* U+83C5 */ - {0x909c, 0x00e9a097}, /* U+9817 */ - {0x909d, 0x00e99b80}, /* U+96C0 */ - {0x909e, 0x00e8a3be}, /* U+88FE */ - {0x909f, 0x00e6be84}, /* U+6F84 */ - {0x90a0, 0x00e691ba}, /* U+647A */ - {0x90a1, 0x00e5afb8}, /* U+5BF8 */ - {0x90a2, 0x00e4b896}, /* U+4E16 */ - {0x90a3, 0x00e780ac}, /* U+702C */ - {0x90a4, 0x00e7959d}, /* U+755D */ - {0x90a5, 0x00e698af}, /* U+662F */ - {0x90a6, 0x00e58784}, /* U+51C4 */ - {0x90a7, 0x00e588b6}, /* U+5236 */ - {0x90a8, 0x00e58ba2}, /* U+52E2 */ - {0x90a9, 0x00e5a793}, /* U+59D3 */ - {0x90aa, 0x00e5be81}, /* U+5F81 */ - {0x90ab, 0x00e680a7}, /* U+6027 */ - {0x90ac, 0x00e68890}, /* U+6210 */ - {0x90ad, 0x00e694bf}, /* U+653F */ - {0x90ae, 0x00e695b4}, /* U+6574 */ - {0x90af, 0x00e6989f}, /* U+661F */ - {0x90b0, 0x00e699b4}, /* U+6674 */ - {0x90b1, 0x00e6a3b2}, /* U+68F2 */ - {0x90b2, 0x00e6a096}, /* U+6816 */ - {0x90b3, 0x00e6ada3}, /* U+6B63 */ - {0x90b4, 0x00e6b885}, /* U+6E05 */ - {0x90b5, 0x00e789b2}, /* U+7272 */ - {0x90b6, 0x00e7949f}, /* U+751F */ - {0x90b7, 0x00e79b9b}, /* U+76DB */ - {0x90b8, 0x00e7b2be}, /* U+7CBE */ - {0x90b9, 0x00e88196}, /* U+8056 */ - {0x90ba, 0x00e5a3b0}, /* U+58F0 */ - {0x90bb, 0x00e8a3bd}, /* U+88FD */ - {0x90bc, 0x00e8a5bf}, /* U+897F */ - {0x90bd, 0x00e8aaa0}, /* U+8AA0 */ - {0x90be, 0x00e8aa93}, /* U+8A93 */ - {0x90bf, 0x00e8ab8b}, /* U+8ACB */ - {0x90c0, 0x00e9809d}, /* U+901D */ - {0x90c1, 0x00e98692}, /* U+9192 */ - {0x90c2, 0x00e99d92}, /* U+9752 */ - {0x90c3, 0x00e99d99}, /* U+9759 */ - {0x90c4, 0x00e69689}, /* U+6589 */ - {0x90c5, 0x00e7a88e}, /* U+7A0E */ - {0x90c6, 0x00e88486}, /* U+8106 */ - {0x90c7, 0x00e99abb}, /* U+96BB */ - {0x90c8, 0x00e5b8ad}, /* U+5E2D */ - {0x90c9, 0x00e6839c}, /* U+60DC */ - {0x90ca, 0x00e6889a}, /* U+621A */ - {0x90cb, 0x00e696a5}, /* U+65A5 */ - {0x90cc, 0x00e69894}, /* U+6614 */ - {0x90cd, 0x00e69e90}, /* U+6790 */ - {0x90ce, 0x00e79fb3}, /* U+77F3 */ - {0x90cf, 0x00e7a98d}, /* U+7A4D */ - {0x90d0, 0x00e7b18d}, /* U+7C4D */ - {0x90d1, 0x00e7b8be}, /* U+7E3E */ - {0x90d2, 0x00e8848a}, /* U+810A */ - {0x90d3, 0x00e8b2ac}, /* U+8CAC */ - {0x90d4, 0x00e8b5a4}, /* U+8D64 */ - {0x90d5, 0x00e8b7a1}, /* U+8DE1 */ - {0x90d6, 0x00e8b99f}, /* U+8E5F */ - {0x90d7, 0x00e7a2a9}, /* U+78A9 */ - {0x90d8, 0x00e58887}, /* U+5207 */ - {0x90d9, 0x00e68b99}, /* U+62D9 */ - {0x90da, 0x00e68ea5}, /* U+63A5 */ - {0x90db, 0x00e69182}, /* U+6442 */ - {0x90dc, 0x00e68a98}, /* U+6298 */ - {0x90dd, 0x00e8a8ad}, /* U+8A2D */ - {0x90de, 0x00e7aa83}, /* U+7A83 */ - {0x90df, 0x00e7af80}, /* U+7BC0 */ - {0x90e0, 0x00e8aaac}, /* U+8AAC */ - {0x90e1, 0x00e99baa}, /* U+96EA */ - {0x90e2, 0x00e7b5b6}, /* U+7D76 */ - {0x90e3, 0x00e8888c}, /* U+820C */ - {0x90e4, 0x00e89d89}, /* U+8749 */ - {0x90e5, 0x00e4bb99}, /* U+4ED9 */ - {0x90e6, 0x00e58588}, /* U+5148 */ - {0x90e7, 0x00e58d83}, /* U+5343 */ - {0x90e8, 0x00e58da0}, /* U+5360 */ - {0x90e9, 0x00e5aea3}, /* U+5BA3 */ - {0x90ea, 0x00e5b082}, /* U+5C02 */ - {0x90eb, 0x00e5b096}, /* U+5C16 */ - {0x90ec, 0x00e5b79d}, /* U+5DDD */ - {0x90ed, 0x00e688a6}, /* U+6226 */ - {0x90ee, 0x00e68987}, /* U+6247 */ - {0x90ef, 0x00e692b0}, /* U+64B0 */ - {0x90f0, 0x00e6a093}, /* U+6813 */ - {0x90f1, 0x00e6a0b4}, /* U+6834 */ - {0x90f2, 0x00e6b389}, /* U+6CC9 */ - {0x90f3, 0x00e6b585}, /* U+6D45 */ - {0x90f4, 0x00e6b497}, /* U+6D17 */ - {0x90f5, 0x00e69f93}, /* U+67D3 */ - {0x90f6, 0x00e6bd9c}, /* U+6F5C */ - {0x90f7, 0x00e7858e}, /* U+714E */ - {0x90f8, 0x00e785bd}, /* U+717D */ - {0x90f9, 0x00e6978b}, /* U+65CB */ - {0x90fa, 0x00e7a9bf}, /* U+7A7F */ - {0x90fb, 0x00e7aead}, /* U+7BAD */ - {0x90fc, 0x00e7b79a}, /* U+7DDA */ - {0x9140, 0x00e7b98a}, /* U+7E4A */ - {0x9141, 0x00e7bea8}, /* U+7FA8 */ - {0x9142, 0x00e885ba}, /* U+817A */ - {0x9143, 0x00e8889b}, /* U+821B */ - {0x9144, 0x00e888b9}, /* U+8239 */ - {0x9145, 0x00e896a6}, /* U+85A6 */ - {0x9146, 0x00e8a9ae}, /* U+8A6E */ - {0x9147, 0x00e8b38e}, /* U+8CCE */ - {0x9148, 0x00e8b7b5}, /* U+8DF5 */ - {0x9149, 0x00e981b8}, /* U+9078 */ - {0x914a, 0x00e981b7}, /* U+9077 */ - {0x914b, 0x00e98aad}, /* U+92AD */ - {0x914c, 0x00e98a91}, /* U+9291 */ - {0x914d, 0x00e99683}, /* U+9583 */ - {0x914e, 0x00e9aeae}, /* U+9BAE */ - {0x914f, 0x00e5898d}, /* U+524D */ - {0x9150, 0x00e59684}, /* U+5584 */ - {0x9151, 0x00e6bcb8}, /* U+6F38 */ - {0x9152, 0x00e784b6}, /* U+7136 */ - {0x9153, 0x00e585a8}, /* U+5168 */ - {0x9154, 0x00e7a685}, /* U+7985 */ - {0x9155, 0x00e7b995}, /* U+7E55 */ - {0x9156, 0x00e886b3}, /* U+81B3 */ - {0x9157, 0x00e7b38e}, /* U+7CCE */ - {0x9158, 0x00e5998c}, /* U+564C */ - {0x9159, 0x00e5a191}, /* U+5851 */ - {0x915a, 0x00e5b2a8}, /* U+5CA8 */ - {0x915b, 0x00e68eaa}, /* U+63AA */ - {0x915c, 0x00e69bbe}, /* U+66FE */ - {0x915d, 0x00e69bbd}, /* U+66FD */ - {0x915e, 0x00e6a59a}, /* U+695A */ - {0x915f, 0x00e78b99}, /* U+72D9 */ - {0x9160, 0x00e7968f}, /* U+758F */ - {0x9161, 0x00e7968e}, /* U+758E */ - {0x9162, 0x00e7a48e}, /* U+790E */ - {0x9163, 0x00e7a596}, /* U+7956 */ - {0x9164, 0x00e7a79f}, /* U+79DF */ - {0x9165, 0x00e7b297}, /* U+7C97 */ - {0x9166, 0x00e7b4a0}, /* U+7D20 */ - {0x9167, 0x00e7b584}, /* U+7D44 */ - {0x9168, 0x00e89887}, /* U+8607 */ - {0x9169, 0x00e8a8b4}, /* U+8A34 */ - {0x916a, 0x00e998bb}, /* U+963B */ - {0x916b, 0x00e981a1}, /* U+9061 */ - {0x916c, 0x00e9bca0}, /* U+9F20 */ - {0x916d, 0x00e583a7}, /* U+50E7 */ - {0x916e, 0x00e589b5}, /* U+5275 */ - {0x916f, 0x00e58f8c}, /* U+53CC */ - {0x9170, 0x00e58fa2}, /* U+53E2 */ - {0x9171, 0x00e58089}, /* U+5009 */ - {0x9172, 0x00e596aa}, /* U+55AA */ - {0x9173, 0x00e5a3ae}, /* U+58EE */ - {0x9174, 0x00e5a58f}, /* U+594F */ - {0x9175, 0x00e788bd}, /* U+723D */ - {0x9176, 0x00e5ae8b}, /* U+5B8B */ - {0x9177, 0x00e5b1a4}, /* U+5C64 */ - {0x9178, 0x00e58c9d}, /* U+531D */ - {0x9179, 0x00e683a3}, /* U+60E3 */ - {0x917a, 0x00e683b3}, /* U+60F3 */ - {0x917b, 0x00e68d9c}, /* U+635C */ - {0x917c, 0x00e68e83}, /* U+6383 */ - {0x917d, 0x00e68cbf}, /* U+633F */ - {0x917e, 0x00e68ebb}, /* U+63BB */ - {0x9180, 0x00e6938d}, /* U+64CD */ - {0x9181, 0x00e697a9}, /* U+65E9 */ - {0x9182, 0x00e69bb9}, /* U+66F9 */ - {0x9183, 0x00e5b7a3}, /* U+5DE3 */ - {0x9184, 0x00e6a78d}, /* U+69CD */ - {0x9185, 0x00e6a7bd}, /* U+69FD */ - {0x9186, 0x00e6bc95}, /* U+6F15 */ - {0x9187, 0x00e787a5}, /* U+71E5 */ - {0x9188, 0x00e4ba89}, /* U+4E89 */ - {0x9189, 0x00e797a9}, /* U+75E9 */ - {0x918a, 0x00e79bb8}, /* U+76F8 */ - {0x918b, 0x00e7aa93}, /* U+7A93 */ - {0x918c, 0x00e7b39f}, /* U+7CDF */ - {0x918d, 0x00e7b78f}, /* U+7DCF */ - {0x918e, 0x00e7b69c}, /* U+7D9C */ - {0x918f, 0x00e881a1}, /* U+8061 */ - {0x9190, 0x00e88d89}, /* U+8349 */ - {0x9191, 0x00e88d98}, /* U+8358 */ - {0x9192, 0x00e891ac}, /* U+846C */ - {0x9193, 0x00e892bc}, /* U+84BC */ - {0x9194, 0x00e897bb}, /* U+85FB */ - {0x9195, 0x00e8a385}, /* U+88C5 */ - {0x9196, 0x00e8b5b0}, /* U+8D70 */ - {0x9197, 0x00e98081}, /* U+9001 */ - {0x9198, 0x00e981ad}, /* U+906D */ - {0x9199, 0x00e98e97}, /* U+9397 */ - {0x919a, 0x00e99c9c}, /* U+971C */ - {0x919b, 0x00e9a892}, /* U+9A12 */ - {0x919c, 0x00e5838f}, /* U+50CF */ - {0x919d, 0x00e5a297}, /* U+5897 */ - {0x919e, 0x00e6868e}, /* U+618E */ - {0x919f, 0x00e88793}, /* U+81D3 */ - {0x91a0, 0x00e894b5}, /* U+8535 */ - {0x91a1, 0x00e8b488}, /* U+8D08 */ - {0x91a2, 0x00e980a0}, /* U+9020 */ - {0x91a3, 0x00e4bf83}, /* U+4FC3 */ - {0x91a4, 0x00e581b4}, /* U+5074 */ - {0x91a5, 0x00e58987}, /* U+5247 */ - {0x91a6, 0x00e58db3}, /* U+5373 */ - {0x91a7, 0x00e681af}, /* U+606F */ - {0x91a8, 0x00e68d89}, /* U+6349 */ - {0x91a9, 0x00e69d9f}, /* U+675F */ - {0x91aa, 0x00e6b8ac}, /* U+6E2C */ - {0x91ab, 0x00e8b6b3}, /* U+8DB3 */ - {0x91ac, 0x00e9809f}, /* U+901F */ - {0x91ad, 0x00e4bf97}, /* U+4FD7 */ - {0x91ae, 0x00e5b19e}, /* U+5C5E */ - {0x91af, 0x00e8b38a}, /* U+8CCA */ - {0x91b0, 0x00e6978f}, /* U+65CF */ - {0x91b1, 0x00e7b69a}, /* U+7D9A */ - {0x91b2, 0x00e58d92}, /* U+5352 */ - {0x91b3, 0x00e8a296}, /* U+8896 */ - {0x91b4, 0x00e585b6}, /* U+5176 */ - {0x91b5, 0x00e68f83}, /* U+63C3 */ - {0x91b6, 0x00e5ad98}, /* U+5B58 */ - {0x91b7, 0x00e5adab}, /* U+5B6B */ - {0x91b8, 0x00e5b08a}, /* U+5C0A */ - {0x91b9, 0x00e6908d}, /* U+640D */ - {0x91ba, 0x00e69d91}, /* U+6751 */ - {0x91bb, 0x00e9819c}, /* U+905C */ - {0x91bc, 0x00e4bb96}, /* U+4ED6 */ - {0x91bd, 0x00e5a49a}, /* U+591A */ - {0x91be, 0x00e5a4aa}, /* U+592A */ - {0x91bf, 0x00e6b1b0}, /* U+6C70 */ - {0x91c0, 0x00e8a991}, /* U+8A51 */ - {0x91c1, 0x00e594be}, /* U+553E */ - {0x91c2, 0x00e5a095}, /* U+5815 */ - {0x91c3, 0x00e5a6a5}, /* U+59A5 */ - {0x91c4, 0x00e683b0}, /* U+60F0 */ - {0x91c5, 0x00e68993}, /* U+6253 */ - {0x91c6, 0x00e69f81}, /* U+67C1 */ - {0x91c7, 0x00e888b5}, /* U+8235 */ - {0x91c8, 0x00e6a595}, /* U+6955 */ - {0x91c9, 0x00e99980}, /* U+9640 */ - {0x91ca, 0x00e9a784}, /* U+99C4 */ - {0x91cb, 0x00e9a8a8}, /* U+9A28 */ - {0x91cc, 0x00e4bd93}, /* U+4F53 */ - {0x91cd, 0x00e5a086}, /* U+5806 */ - {0x91ce, 0x00e5afbe}, /* U+5BFE */ - {0x91cf, 0x00e88090}, /* U+8010 */ - {0x91d0, 0x00e5b2b1}, /* U+5CB1 */ - {0x91d1, 0x00e5b8af}, /* U+5E2F */ - {0x91d2, 0x00e5be85}, /* U+5F85 */ - {0x91d3, 0x00e680a0}, /* U+6020 */ - {0x91d4, 0x00e6858b}, /* U+614B */ - {0x91d5, 0x00e688b4}, /* U+6234 */ - {0x91d6, 0x00e69bbf}, /* U+66FF */ - {0x91d7, 0x00e6b3b0}, /* U+6CF0 */ - {0x91d8, 0x00e6bb9e}, /* U+6EDE */ - {0x91d9, 0x00e8838e}, /* U+80CE */ - {0x91da, 0x00e885bf}, /* U+817F */ - {0x91db, 0x00e88b94}, /* U+82D4 */ - {0x91dc, 0x00e8a28b}, /* U+888B */ - {0x91dd, 0x00e8b2b8}, /* U+8CB8 */ - {0x91de, 0x00e98080}, /* U+9000 */ - {0x91df, 0x00e980ae}, /* U+902E */ - {0x91e0, 0x00e99a8a}, /* U+968A */ - {0x91e1, 0x00e9bb9b}, /* U+9EDB */ - {0x91e2, 0x00e9af9b}, /* U+9BDB */ - {0x91e3, 0x00e4bba3}, /* U+4EE3 */ - {0x91e4, 0x00e58fb0}, /* U+53F0 */ - {0x91e5, 0x00e5a4a7}, /* U+5927 */ - {0x91e6, 0x00e7acac}, /* U+7B2C */ - {0x91e7, 0x00e9868d}, /* U+918D */ - {0x91e8, 0x00e9a18c}, /* U+984C */ - {0x91e9, 0x00e9b7b9}, /* U+9DF9 */ - {0x91ea, 0x00e6bb9d}, /* U+6EDD */ - {0x91eb, 0x00e780a7}, /* U+7027 */ - {0x91ec, 0x00e58d93}, /* U+5353 */ - {0x91ed, 0x00e59584}, /* U+5544 */ - {0x91ee, 0x00e5ae85}, /* U+5B85 */ - {0x91ef, 0x00e68998}, /* U+6258 */ - {0x91f0, 0x00e68a9e}, /* U+629E */ - {0x91f1, 0x00e68b93}, /* U+62D3 */ - {0x91f2, 0x00e6b2a2}, /* U+6CA2 */ - {0x91f3, 0x00e6bfaf}, /* U+6FEF */ - {0x91f4, 0x00e790a2}, /* U+7422 */ - {0x91f5, 0x00e8a897}, /* U+8A17 */ - {0x91f6, 0x00e990b8}, /* U+9438 */ - {0x91f7, 0x00e6bf81}, /* U+6FC1 */ - {0x91f8, 0x00e8abbe}, /* U+8AFE */ - {0x91f9, 0x00e88cb8}, /* U+8338 */ - {0x91fa, 0x00e587a7}, /* U+51E7 */ - {0x91fb, 0x00e89bb8}, /* U+86F8 */ - {0x91fc, 0x00e58faa}, /* U+53EA */ - {0x9240, 0x00e58fa9}, /* U+53E9 */ - {0x9241, 0x00e4bd86}, /* U+4F46 */ - {0x9242, 0x00e98194}, /* U+9054 */ - {0x9243, 0x00e8beb0}, /* U+8FB0 */ - {0x9244, 0x00e5a5aa}, /* U+596A */ - {0x9245, 0x00e884b1}, /* U+8131 */ - {0x9246, 0x00e5b7bd}, /* U+5DFD */ - {0x9247, 0x00e7abaa}, /* U+7AEA */ - {0x9248, 0x00e8bebf}, /* U+8FBF */ - {0x9249, 0x00e6a39a}, /* U+68DA */ - {0x924a, 0x00e8b0b7}, /* U+8C37 */ - {0x924b, 0x00e78bb8}, /* U+72F8 */ - {0x924c, 0x00e9b188}, /* U+9C48 */ - {0x924d, 0x00e6a8bd}, /* U+6A3D */ - {0x924e, 0x00e8aab0}, /* U+8AB0 */ - {0x924f, 0x00e4b8b9}, /* U+4E39 */ - {0x9250, 0x00e58d98}, /* U+5358 */ - {0x9251, 0x00e59886}, /* U+5606 */ - {0x9252, 0x00e59da6}, /* U+5766 */ - {0x9253, 0x00e68b85}, /* U+62C5 */ - {0x9254, 0x00e68ea2}, /* U+63A2 */ - {0x9255, 0x00e697a6}, /* U+65E6 */ - {0x9256, 0x00e6ad8e}, /* U+6B4E */ - {0x9257, 0x00e6b7a1}, /* U+6DE1 */ - {0x9258, 0x00e6b99b}, /* U+6E5B */ - {0x9259, 0x00e782ad}, /* U+70AD */ - {0x925a, 0x00e79fad}, /* U+77ED */ - {0x925b, 0x00e7abaf}, /* U+7AEF */ - {0x925c, 0x00e7aeaa}, /* U+7BAA */ - {0x925d, 0x00e7b6bb}, /* U+7DBB */ - {0x925e, 0x00e880bd}, /* U+803D */ - {0x925f, 0x00e88386}, /* U+80C6 */ - {0x9260, 0x00e89b8b}, /* U+86CB */ - {0x9261, 0x00e8aa95}, /* U+8A95 */ - {0x9262, 0x00e98d9b}, /* U+935B */ - {0x9263, 0x00e59ba3}, /* U+56E3 */ - {0x9264, 0x00e5a387}, /* U+58C7 */ - {0x9265, 0x00e5bcbe}, /* U+5F3E */ - {0x9266, 0x00e696ad}, /* U+65AD */ - {0x9267, 0x00e69a96}, /* U+6696 */ - {0x9268, 0x00e6aa80}, /* U+6A80 */ - {0x9269, 0x00e6aeb5}, /* U+6BB5 */ - {0x926a, 0x00e794b7}, /* U+7537 */ - {0x926b, 0x00e8ab87}, /* U+8AC7 */ - {0x926c, 0x00e580a4}, /* U+5024 */ - {0x926d, 0x00e79fa5}, /* U+77E5 */ - {0x926e, 0x00e59cb0}, /* U+5730 */ - {0x926f, 0x00e5bc9b}, /* U+5F1B */ - {0x9270, 0x00e681a5}, /* U+6065 */ - {0x9271, 0x00e699ba}, /* U+667A */ - {0x9272, 0x00e6b1a0}, /* U+6C60 */ - {0x9273, 0x00e797b4}, /* U+75F4 */ - {0x9274, 0x00e7a89a}, /* U+7A1A */ - {0x9275, 0x00e7bdae}, /* U+7F6E */ - {0x9276, 0x00e887b4}, /* U+81F4 */ - {0x9277, 0x00e89c98}, /* U+8718 */ - {0x9278, 0x00e98185}, /* U+9045 */ - {0x9279, 0x00e9a6b3}, /* U+99B3 */ - {0x927a, 0x00e7af89}, /* U+7BC9 */ - {0x927b, 0x00e7959c}, /* U+755C */ - {0x927c, 0x00e7abb9}, /* U+7AF9 */ - {0x927d, 0x00e7ad91}, /* U+7B51 */ - {0x927e, 0x00e89384}, /* U+84C4 */ - {0x9280, 0x00e98090}, /* U+9010 */ - {0x9281, 0x00e7a7a9}, /* U+79E9 */ - {0x9282, 0x00e7aa92}, /* U+7A92 */ - {0x9283, 0x00e88cb6}, /* U+8336 */ - {0x9284, 0x00e5aba1}, /* U+5AE1 */ - {0x9285, 0x00e79d80}, /* U+7740 */ - {0x9286, 0x00e4b8ad}, /* U+4E2D */ - {0x9287, 0x00e4bbb2}, /* U+4EF2 */ - {0x9288, 0x00e5ae99}, /* U+5B99 */ - {0x9289, 0x00e5bfa0}, /* U+5FE0 */ - {0x928a, 0x00e68abd}, /* U+62BD */ - {0x928b, 0x00e698bc}, /* U+663C */ - {0x928c, 0x00e69fb1}, /* U+67F1 */ - {0x928d, 0x00e6b3a8}, /* U+6CE8 */ - {0x928e, 0x00e899ab}, /* U+866B */ - {0x928f, 0x00e8a1b7}, /* U+8877 */ - {0x9290, 0x00e8a8bb}, /* U+8A3B */ - {0x9291, 0x00e9858e}, /* U+914E */ - {0x9292, 0x00e98bb3}, /* U+92F3 */ - {0x9293, 0x00e9a790}, /* U+99D0 */ - {0x9294, 0x00e6a897}, /* U+6A17 */ - {0x9295, 0x00e780a6}, /* U+7026 */ - {0x9296, 0x00e78caa}, /* U+732A */ - {0x9297, 0x00e88ba7}, /* U+82E7 */ - {0x9298, 0x00e89197}, /* U+8457 */ - {0x9299, 0x00e8b2af}, /* U+8CAF */ - {0x929a, 0x00e4b881}, /* U+4E01 */ - {0x929b, 0x00e58586}, /* U+5146 */ - {0x929c, 0x00e5878b}, /* U+51CB */ - {0x929d, 0x00e5968b}, /* U+558B */ - {0x929e, 0x00e5afb5}, /* U+5BF5 */ - {0x929f, 0x00e5b896}, /* U+5E16 */ - {0x92a0, 0x00e5b8b3}, /* U+5E33 */ - {0x92a1, 0x00e5ba81}, /* U+5E81 */ - {0x92a2, 0x00e5bc94}, /* U+5F14 */ - {0x92a3, 0x00e5bcb5}, /* U+5F35 */ - {0x92a4, 0x00e5bdab}, /* U+5F6B */ - {0x92a5, 0x00e5beb4}, /* U+5FB4 */ - {0x92a6, 0x00e687b2}, /* U+61F2 */ - {0x92a7, 0x00e68c91}, /* U+6311 */ - {0x92a8, 0x00e69aa2}, /* U+66A2 */ - {0x92a9, 0x00e69c9d}, /* U+671D */ - {0x92aa, 0x00e6bdae}, /* U+6F6E */ - {0x92ab, 0x00e78992}, /* U+7252 */ - {0x92ac, 0x00e794ba}, /* U+753A */ - {0x92ad, 0x00e79cba}, /* U+773A */ - {0x92ae, 0x00e881b4}, /* U+8074 */ - {0x92af, 0x00e884b9}, /* U+8139 */ - {0x92b0, 0x00e885b8}, /* U+8178 */ - {0x92b1, 0x00e89db6}, /* U+8776 */ - {0x92b2, 0x00e8aabf}, /* U+8ABF */ - {0x92b3, 0x00e8ab9c}, /* U+8ADC */ - {0x92b4, 0x00e8b685}, /* U+8D85 */ - {0x92b5, 0x00e8b7b3}, /* U+8DF3 */ - {0x92b6, 0x00e98a9a}, /* U+929A */ - {0x92b7, 0x00e995b7}, /* U+9577 */ - {0x92b8, 0x00e9a082}, /* U+9802 */ - {0x92b9, 0x00e9b3a5}, /* U+9CE5 */ - {0x92ba, 0x00e58b85}, /* U+52C5 */ - {0x92bb, 0x00e68d97}, /* U+6357 */ - {0x92bc, 0x00e79bb4}, /* U+76F4 */ - {0x92bd, 0x00e69c95}, /* U+6715 */ - {0x92be, 0x00e6b288}, /* U+6C88 */ - {0x92bf, 0x00e78f8d}, /* U+73CD */ - {0x92c0, 0x00e8b383}, /* U+8CC3 */ - {0x92c1, 0x00e98eae}, /* U+93AE */ - {0x92c2, 0x00e999b3}, /* U+9673 */ - {0x92c3, 0x00e6b4a5}, /* U+6D25 */ - {0x92c4, 0x00e5a29c}, /* U+589C */ - {0x92c5, 0x00e6a48e}, /* U+690E */ - {0x92c6, 0x00e6a78c}, /* U+69CC */ - {0x92c7, 0x00e8bfbd}, /* U+8FFD */ - {0x92c8, 0x00e98e9a}, /* U+939A */ - {0x92c9, 0x00e7979b}, /* U+75DB */ - {0x92ca, 0x00e9809a}, /* U+901A */ - {0x92cb, 0x00e5a19a}, /* U+585A */ - {0x92cc, 0x00e6a082}, /* U+6802 */ - {0x92cd, 0x00e68eb4}, /* U+63B4 */ - {0x92ce, 0x00e6a7bb}, /* U+69FB */ - {0x92cf, 0x00e4bd83}, /* U+4F43 */ - {0x92d0, 0x00e6bcac}, /* U+6F2C */ - {0x92d1, 0x00e69f98}, /* U+67D8 */ - {0x92d2, 0x00e8bebb}, /* U+8FBB */ - {0x92d3, 0x00e894a6}, /* U+8526 */ - {0x92d4, 0x00e7b6b4}, /* U+7DB4 */ - {0x92d5, 0x00e98d94}, /* U+9354 */ - {0x92d6, 0x00e6a4bf}, /* U+693F */ - {0x92d7, 0x00e6bdb0}, /* U+6F70 */ - {0x92d8, 0x00e59daa}, /* U+576A */ - {0x92d9, 0x00e5a3b7}, /* U+58F7 */ - {0x92da, 0x00e5acac}, /* U+5B2C */ - {0x92db, 0x00e7b4ac}, /* U+7D2C */ - {0x92dc, 0x00e788aa}, /* U+722A */ - {0x92dd, 0x00e5908a}, /* U+540A */ - {0x92de, 0x00e987a3}, /* U+91E3 */ - {0x92df, 0x00e9b6b4}, /* U+9DB4 */ - {0x92e0, 0x00e4baad}, /* U+4EAD */ - {0x92e1, 0x00e4bd8e}, /* U+4F4E */ - {0x92e2, 0x00e5819c}, /* U+505C */ - {0x92e3, 0x00e581b5}, /* U+5075 */ - {0x92e4, 0x00e58983}, /* U+5243 */ - {0x92e5, 0x00e8b29e}, /* U+8C9E */ - {0x92e6, 0x00e59188}, /* U+5448 */ - {0x92e7, 0x00e5a0a4}, /* U+5824 */ - {0x92e8, 0x00e5ae9a}, /* U+5B9A */ - {0x92e9, 0x00e5b89d}, /* U+5E1D */ - {0x92ea, 0x00e5ba95}, /* U+5E95 */ - {0x92eb, 0x00e5baad}, /* U+5EAD */ - {0x92ec, 0x00e5bbb7}, /* U+5EF7 */ - {0x92ed, 0x00e5bc9f}, /* U+5F1F */ - {0x92ee, 0x00e6828c}, /* U+608C */ - {0x92ef, 0x00e68ab5}, /* U+62B5 */ - {0x92f0, 0x00e68cba}, /* U+633A */ - {0x92f1, 0x00e68f90}, /* U+63D0 */ - {0x92f2, 0x00e6a2af}, /* U+68AF */ - {0x92f3, 0x00e6b180}, /* U+6C40 */ - {0x92f4, 0x00e7a287}, /* U+7887 */ - {0x92f5, 0x00e7a68e}, /* U+798E */ - {0x92f6, 0x00e7a88b}, /* U+7A0B */ - {0x92f7, 0x00e7b7a0}, /* U+7DE0 */ - {0x92f8, 0x00e88987}, /* U+8247 */ - {0x92f9, 0x00e8a882}, /* U+8A02 */ - {0x92fa, 0x00e8aba6}, /* U+8AE6 */ - {0x92fb, 0x00e8b984}, /* U+8E44 */ - {0x92fc, 0x00e98093}, /* U+9013 */ - {0x9340, 0x00e982b8}, /* U+90B8 */ - {0x9341, 0x00e984ad}, /* U+912D */ - {0x9342, 0x00e98798}, /* U+91D8 */ - {0x9343, 0x00e9bc8e}, /* U+9F0E */ - {0x9344, 0x00e6b3a5}, /* U+6CE5 */ - {0x9345, 0x00e69198}, /* U+6458 */ - {0x9346, 0x00e693a2}, /* U+64E2 */ - {0x9347, 0x00e695b5}, /* U+6575 */ - {0x9348, 0x00e6bbb4}, /* U+6EF4 */ - {0x9349, 0x00e79a84}, /* U+7684 */ - {0x934a, 0x00e7ac9b}, /* U+7B1B */ - {0x934b, 0x00e981a9}, /* U+9069 */ - {0x934c, 0x00e98f91}, /* U+93D1 */ - {0x934d, 0x00e6baba}, /* U+6EBA */ - {0x934e, 0x00e593b2}, /* U+54F2 */ - {0x934f, 0x00e5beb9}, /* U+5FB9 */ - {0x9350, 0x00e692a4}, /* U+64A4 */ - {0x9351, 0x00e8bd8d}, /* U+8F4D */ - {0x9352, 0x00e8bfad}, /* U+8FED */ - {0x9353, 0x00e98984}, /* U+9244 */ - {0x9354, 0x00e585b8}, /* U+5178 */ - {0x9355, 0x00e5a1ab}, /* U+586B */ - {0x9356, 0x00e5a4a9}, /* U+5929 */ - {0x9357, 0x00e5b195}, /* U+5C55 */ - {0x9358, 0x00e5ba97}, /* U+5E97 */ - {0x9359, 0x00e6b7bb}, /* U+6DFB */ - {0x935a, 0x00e7ba8f}, /* U+7E8F */ - {0x935b, 0x00e7949c}, /* U+751C */ - {0x935c, 0x00e8b2bc}, /* U+8CBC */ - {0x935d, 0x00e8bba2}, /* U+8EE2 */ - {0x935e, 0x00e9a19b}, /* U+985B */ - {0x935f, 0x00e782b9}, /* U+70B9 */ - {0x9360, 0x00e4bc9d}, /* U+4F1D */ - {0x9361, 0x00e6aebf}, /* U+6BBF */ - {0x9362, 0x00e6beb1}, /* U+6FB1 */ - {0x9363, 0x00e794b0}, /* U+7530 */ - {0x9364, 0x00e99bbb}, /* U+96FB */ - {0x9365, 0x00e5858e}, /* U+514E */ - {0x9366, 0x00e59090}, /* U+5410 */ - {0x9367, 0x00e5a0b5}, /* U+5835 */ - {0x9368, 0x00e5a197}, /* U+5857 */ - {0x9369, 0x00e5a6ac}, /* U+59AC */ - {0x936a, 0x00e5b1a0}, /* U+5C60 */ - {0x936b, 0x00e5be92}, /* U+5F92 */ - {0x936c, 0x00e69697}, /* U+6597 */ - {0x936d, 0x00e69d9c}, /* U+675C */ - {0x936e, 0x00e6b8a1}, /* U+6E21 */ - {0x936f, 0x00e799bb}, /* U+767B */ - {0x9370, 0x00e88f9f}, /* U+83DF */ - {0x9371, 0x00e8b3ad}, /* U+8CED */ - {0x9372, 0x00e98094}, /* U+9014 */ - {0x9373, 0x00e983bd}, /* U+90FD */ - {0x9374, 0x00e98d8d}, /* U+934D */ - {0x9375, 0x00e7a0a5}, /* U+7825 */ - {0x9376, 0x00e7a0ba}, /* U+783A */ - {0x9377, 0x00e58aaa}, /* U+52AA */ - {0x9378, 0x00e5baa6}, /* U+5EA6 */ - {0x9379, 0x00e59c9f}, /* U+571F */ - {0x937a, 0x00e5a5b4}, /* U+5974 */ - {0x937b, 0x00e68092}, /* U+6012 */ - {0x937c, 0x00e58092}, /* U+5012 */ - {0x937d, 0x00e5859a}, /* U+515A */ - {0x937e, 0x00e586ac}, /* U+51AC */ - {0x9380, 0x00e5878d}, /* U+51CD */ - {0x9381, 0x00e58880}, /* U+5200 */ - {0x9382, 0x00e59490}, /* U+5510 */ - {0x9383, 0x00e5a194}, /* U+5854 */ - {0x9384, 0x00e5a198}, /* U+5858 */ - {0x9385, 0x00e5a597}, /* U+5957 */ - {0x9386, 0x00e5ae95}, /* U+5B95 */ - {0x9387, 0x00e5b3b6}, /* U+5CF6 */ - {0x9388, 0x00e5b68b}, /* U+5D8B */ - {0x9389, 0x00e682bc}, /* U+60BC */ - {0x938a, 0x00e68a95}, /* U+6295 */ - {0x938b, 0x00e690ad}, /* U+642D */ - {0x938c, 0x00e69db1}, /* U+6771 */ - {0x938d, 0x00e6a183}, /* U+6843 */ - {0x938e, 0x00e6a2bc}, /* U+68BC */ - {0x938f, 0x00e6a39f}, /* U+68DF */ - {0x9390, 0x00e79b97}, /* U+76D7 */ - {0x9391, 0x00e6b798}, /* U+6DD8 */ - {0x9392, 0x00e6b9af}, /* U+6E6F */ - {0x9393, 0x00e6b69b}, /* U+6D9B */ - {0x9394, 0x00e781af}, /* U+706F */ - {0x9395, 0x00e78788}, /* U+71C8 */ - {0x9396, 0x00e5bd93}, /* U+5F53 */ - {0x9397, 0x00e79798}, /* U+75D8 */ - {0x9398, 0x00e7a5b7}, /* U+7977 */ - {0x9399, 0x00e7ad89}, /* U+7B49 */ - {0x939a, 0x00e7ad94}, /* U+7B54 */ - {0x939b, 0x00e7ad92}, /* U+7B52 */ - {0x939c, 0x00e7b396}, /* U+7CD6 */ - {0x939d, 0x00e7b5b1}, /* U+7D71 */ - {0x939e, 0x00e588b0}, /* U+5230 */ - {0x939f, 0x00e891a3}, /* U+8463 */ - {0x93a0, 0x00e895a9}, /* U+8569 */ - {0x93a1, 0x00e897a4}, /* U+85E4 */ - {0x93a2, 0x00e8a88e}, /* U+8A0E */ - {0x93a3, 0x00e8ac84}, /* U+8B04 */ - {0x93a4, 0x00e8b186}, /* U+8C46 */ - {0x93a5, 0x00e8b88f}, /* U+8E0F */ - {0x93a6, 0x00e98083}, /* U+9003 */ - {0x93a7, 0x00e9808f}, /* U+900F */ - {0x93a8, 0x00e99099}, /* U+9419 */ - {0x93a9, 0x00e999b6}, /* U+9676 */ - {0x93aa, 0x00e9a0ad}, /* U+982D */ - {0x93ab, 0x00e9a8b0}, /* U+9A30 */ - {0x93ac, 0x00e99798}, /* U+95D8 */ - {0x93ad, 0x00e5838d}, /* U+50CD */ - {0x93ae, 0x00e58b95}, /* U+52D5 */ - {0x93af, 0x00e5908c}, /* U+540C */ - {0x93b0, 0x00e5a082}, /* U+5802 */ - {0x93b1, 0x00e5b08e}, /* U+5C0E */ - {0x93b2, 0x00e686a7}, /* U+61A7 */ - {0x93b3, 0x00e6929e}, /* U+649E */ - {0x93b4, 0x00e6b49e}, /* U+6D1E */ - {0x93b5, 0x00e79eb3}, /* U+77B3 */ - {0x93b6, 0x00e7aba5}, /* U+7AE5 */ - {0x93b7, 0x00e883b4}, /* U+80F4 */ - {0x93b8, 0x00e89084}, /* U+8404 */ - {0x93b9, 0x00e98193}, /* U+9053 */ - {0x93ba, 0x00e98a85}, /* U+9285 */ - {0x93bb, 0x00e5b3a0}, /* U+5CE0 */ - {0x93bc, 0x00e9b487}, /* U+9D07 */ - {0x93bd, 0x00e58cbf}, /* U+533F */ - {0x93be, 0x00e5be97}, /* U+5F97 */ - {0x93bf, 0x00e5beb3}, /* U+5FB3 */ - {0x93c0, 0x00e6b69c}, /* U+6D9C */ - {0x93c1, 0x00e789b9}, /* U+7279 */ - {0x93c2, 0x00e79da3}, /* U+7763 */ - {0x93c3, 0x00e7a6bf}, /* U+79BF */ - {0x93c4, 0x00e7afa4}, /* U+7BE4 */ - {0x93c5, 0x00e6af92}, /* U+6BD2 */ - {0x93c6, 0x00e78bac}, /* U+72EC */ - {0x93c7, 0x00e8aaad}, /* U+8AAD */ - {0x93c8, 0x00e6a083}, /* U+6803 */ - {0x93c9, 0x00e6a9a1}, /* U+6A61 */ - {0x93ca, 0x00e587b8}, /* U+51F8 */ - {0x93cb, 0x00e7aa81}, /* U+7A81 */ - {0x93cc, 0x00e6a4b4}, /* U+6934 */ - {0x93cd, 0x00e5b18a}, /* U+5C4A */ - {0x93ce, 0x00e9b3b6}, /* U+9CF6 */ - {0x93cf, 0x00e88bab}, /* U+82EB */ - {0x93d0, 0x00e5af85}, /* U+5BC5 */ - {0x93d1, 0x00e98589}, /* U+9149 */ - {0x93d2, 0x00e7809e}, /* U+701E */ - {0x93d3, 0x00e599b8}, /* U+5678 */ - {0x93d4, 0x00e5b1af}, /* U+5C6F */ - {0x93d5, 0x00e68387}, /* U+60C7 */ - {0x93d6, 0x00e695a6}, /* U+6566 */ - {0x93d7, 0x00e6b28c}, /* U+6C8C */ - {0x93d8, 0x00e8b19a}, /* U+8C5A */ - {0x93d9, 0x00e98181}, /* U+9041 */ - {0x93da, 0x00e9a093}, /* U+9813 */ - {0x93db, 0x00e59191}, /* U+5451 */ - {0x93dc, 0x00e69b87}, /* U+66C7 */ - {0x93dd, 0x00e9888d}, /* U+920D */ - {0x93de, 0x00e5a588}, /* U+5948 */ - {0x93df, 0x00e982a3}, /* U+90A3 */ - {0x93e0, 0x00e58685}, /* U+5185 */ - {0x93e1, 0x00e4b98d}, /* U+4E4D */ - {0x93e2, 0x00e587aa}, /* U+51EA */ - {0x93e3, 0x00e89699}, /* U+8599 */ - {0x93e4, 0x00e8ac8e}, /* U+8B0E */ - {0x93e5, 0x00e78198}, /* U+7058 */ - {0x93e6, 0x00e68dba}, /* U+637A */ - {0x93e7, 0x00e98d8b}, /* U+934B */ - {0x93e8, 0x00e6a5a2}, /* U+6962 */ - {0x93e9, 0x00e9a6b4}, /* U+99B4 */ - {0x93ea, 0x00e7b884}, /* U+7E04 */ - {0x93eb, 0x00e795b7}, /* U+7577 */ - {0x93ec, 0x00e58d97}, /* U+5357 */ - {0x93ed, 0x00e6a5a0}, /* U+6960 */ - {0x93ee, 0x00e8bb9f}, /* U+8EDF */ - {0x93ef, 0x00e99ba3}, /* U+96E3 */ - {0x93f0, 0x00e6b19d}, /* U+6C5D */ - {0x93f1, 0x00e4ba8c}, /* U+4E8C */ - {0x93f2, 0x00e5b0bc}, /* U+5C3C */ - {0x93f3, 0x00e5bc90}, /* U+5F10 */ - {0x93f4, 0x00e8bfa9}, /* U+8FE9 */ - {0x93f5, 0x00e58c82}, /* U+5302 */ - {0x93f6, 0x00e8b391}, /* U+8CD1 */ - {0x93f7, 0x00e88289}, /* U+8089 */ - {0x93f8, 0x00e899b9}, /* U+8679 */ - {0x93f9, 0x00e5bbbf}, /* U+5EFF */ - {0x93fa, 0x00e697a5}, /* U+65E5 */ - {0x93fb, 0x00e4b9b3}, /* U+4E73 */ - {0x93fc, 0x00e585a5}, /* U+5165 */ - {0x9440, 0x00e5a682}, /* U+5982 */ - {0x9441, 0x00e5b0bf}, /* U+5C3F */ - {0x9442, 0x00e99fae}, /* U+97EE */ - {0x9443, 0x00e4bbbb}, /* U+4EFB */ - {0x9444, 0x00e5a68a}, /* U+598A */ - {0x9445, 0x00e5bf8d}, /* U+5FCD */ - {0x9446, 0x00e8aa8d}, /* U+8A8D */ - {0x9447, 0x00e6bfa1}, /* U+6FE1 */ - {0x9448, 0x00e7a6b0}, /* U+79B0 */ - {0x9449, 0x00e7a5a2}, /* U+7962 */ - {0x944a, 0x00e5afa7}, /* U+5BE7 */ - {0x944b, 0x00e891b1}, /* U+8471 */ - {0x944c, 0x00e78cab}, /* U+732B */ - {0x944d, 0x00e786b1}, /* U+71B1 */ - {0x944e, 0x00e5b9b4}, /* U+5E74 */ - {0x944f, 0x00e5bfb5}, /* U+5FF5 */ - {0x9450, 0x00e68dbb}, /* U+637B */ - {0x9451, 0x00e6929a}, /* U+649A */ - {0x9452, 0x00e78783}, /* U+71C3 */ - {0x9453, 0x00e7b298}, /* U+7C98 */ - {0x9454, 0x00e4b983}, /* U+4E43 */ - {0x9455, 0x00e5bbbc}, /* U+5EFC */ - {0x9456, 0x00e4b98b}, /* U+4E4B */ - {0x9457, 0x00e59f9c}, /* U+57DC */ - {0x9458, 0x00e59aa2}, /* U+56A2 */ - {0x9459, 0x00e682a9}, /* U+60A9 */ - {0x945a, 0x00e6bf83}, /* U+6FC3 */ - {0x945b, 0x00e7b48d}, /* U+7D0D */ - {0x945c, 0x00e883bd}, /* U+80FD */ - {0x945d, 0x00e884b3}, /* U+8133 */ - {0x945e, 0x00e886bf}, /* U+81BF */ - {0x945f, 0x00e8beb2}, /* U+8FB2 */ - {0x9460, 0x00e8a697}, /* U+8997 */ - {0x9461, 0x00e89aa4}, /* U+86A4 */ - {0x9462, 0x00e5b7b4}, /* U+5DF4 */ - {0x9463, 0x00e68a8a}, /* U+628A */ - {0x9464, 0x00e692ad}, /* U+64AD */ - {0x9465, 0x00e8a687}, /* U+8987 */ - {0x9466, 0x00e69db7}, /* U+6777 */ - {0x9467, 0x00e6b3a2}, /* U+6CE2 */ - {0x9468, 0x00e6b4be}, /* U+6D3E */ - {0x9469, 0x00e790b6}, /* U+7436 */ - {0x946a, 0x00e7a0b4}, /* U+7834 */ - {0x946b, 0x00e5a986}, /* U+5A46 */ - {0x946c, 0x00e7bdb5}, /* U+7F75 */ - {0x946d, 0x00e88aad}, /* U+82AD */ - {0x946e, 0x00e9a6ac}, /* U+99AC */ - {0x946f, 0x00e4bfb3}, /* U+4FF3 */ - {0x9470, 0x00e5bb83}, /* U+5EC3 */ - {0x9471, 0x00e68b9d}, /* U+62DD */ - {0x9472, 0x00e68e92}, /* U+6392 */ - {0x9473, 0x00e69597}, /* U+6557 */ - {0x9474, 0x00e69daf}, /* U+676F */ - {0x9475, 0x00e79b83}, /* U+76C3 */ - {0x9476, 0x00e7898c}, /* U+724C */ - {0x9477, 0x00e8838c}, /* U+80CC */ - {0x9478, 0x00e882ba}, /* U+80BA */ - {0x9479, 0x00e8bca9}, /* U+8F29 */ - {0x947a, 0x00e9858d}, /* U+914D */ - {0x947b, 0x00e5808d}, /* U+500D */ - {0x947c, 0x00e59fb9}, /* U+57F9 */ - {0x947d, 0x00e5aa92}, /* U+5A92 */ - {0x947e, 0x00e6a285}, /* U+6885 */ - {0x9480, 0x00e6a5b3}, /* U+6973 */ - {0x9481, 0x00e785a4}, /* U+7164 */ - {0x9482, 0x00e78bbd}, /* U+72FD */ - {0x9483, 0x00e8b2b7}, /* U+8CB7 */ - {0x9484, 0x00e5a3b2}, /* U+58F2 */ - {0x9485, 0x00e8b3a0}, /* U+8CE0 */ - {0x9486, 0x00e999aa}, /* U+966A */ - {0x9487, 0x00e98099}, /* U+9019 */ - {0x9488, 0x00e89dbf}, /* U+877F */ - {0x9489, 0x00e7a7a4}, /* U+79E4 */ - {0x948a, 0x00e79fa7}, /* U+77E7 */ - {0x948b, 0x00e890a9}, /* U+8429 */ - {0x948c, 0x00e4bcaf}, /* U+4F2F */ - {0x948d, 0x00e589a5}, /* U+5265 */ - {0x948e, 0x00e58d9a}, /* U+535A */ - {0x948f, 0x00e68b8d}, /* U+62CD */ - {0x9490, 0x00e69f8f}, /* U+67CF */ - {0x9491, 0x00e6b38a}, /* U+6CCA */ - {0x9492, 0x00e799bd}, /* U+767D */ - {0x9493, 0x00e7ae94}, /* U+7B94 */ - {0x9494, 0x00e7b295}, /* U+7C95 */ - {0x9495, 0x00e888b6}, /* U+8236 */ - {0x9496, 0x00e89684}, /* U+8584 */ - {0x9497, 0x00e8bfab}, /* U+8FEB */ - {0x9498, 0x00e69b9d}, /* U+66DD */ - {0x9499, 0x00e6bca0}, /* U+6F20 */ - {0x949a, 0x00e78886}, /* U+7206 */ - {0x949b, 0x00e7b89b}, /* U+7E1B */ - {0x949c, 0x00e88eab}, /* U+83AB */ - {0x949d, 0x00e9a781}, /* U+99C1 */ - {0x949e, 0x00e9baa6}, /* U+9EA6 */ - {0x949f, 0x00e587bd}, /* U+51FD */ - {0x94a0, 0x00e7aeb1}, /* U+7BB1 */ - {0x94a1, 0x00e7a1b2}, /* U+7872 */ - {0x94a2, 0x00e7aeb8}, /* U+7BB8 */ - {0x94a3, 0x00e88287}, /* U+8087 */ - {0x94a4, 0x00e7ad88}, /* U+7B48 */ - {0x94a5, 0x00e6aba8}, /* U+6AE8 */ - {0x94a6, 0x00e5b9a1}, /* U+5E61 */ - {0x94a7, 0x00e8828c}, /* U+808C */ - {0x94a8, 0x00e79591}, /* U+7551 */ - {0x94a9, 0x00e795a0}, /* U+7560 */ - {0x94aa, 0x00e585ab}, /* U+516B */ - {0x94ab, 0x00e989a2}, /* U+9262 */ - {0x94ac, 0x00e6ba8c}, /* U+6E8C */ - {0x94ad, 0x00e799ba}, /* U+767A */ - {0x94ae, 0x00e98697}, /* U+9197 */ - {0x94af, 0x00e9abaa}, /* U+9AEA */ - {0x94b0, 0x00e4bc90}, /* U+4F10 */ - {0x94b1, 0x00e7bdb0}, /* U+7F70 */ - {0x94b2, 0x00e68a9c}, /* U+629C */ - {0x94b3, 0x00e7ad8f}, /* U+7B4F */ - {0x94b4, 0x00e996a5}, /* U+95A5 */ - {0x94b5, 0x00e9b3a9}, /* U+9CE9 */ - {0x94b6, 0x00e599ba}, /* U+567A */ - {0x94b7, 0x00e5a199}, /* U+5859 */ - {0x94b8, 0x00e89ba4}, /* U+86E4 */ - {0x94b9, 0x00e99abc}, /* U+96BC */ - {0x94ba, 0x00e4bcb4}, /* U+4F34 */ - {0x94bb, 0x00e588a4}, /* U+5224 */ - {0x94bc, 0x00e58d8a}, /* U+534A */ - {0x94bd, 0x00e58f8d}, /* U+53CD */ - {0x94be, 0x00e58f9b}, /* U+53DB */ - {0x94bf, 0x00e5b886}, /* U+5E06 */ - {0x94c0, 0x00e690ac}, /* U+642C */ - {0x94c1, 0x00e69691}, /* U+6591 */ - {0x94c2, 0x00e69dbf}, /* U+677F */ - {0x94c3, 0x00e6b0be}, /* U+6C3E */ - {0x94c4, 0x00e6b18e}, /* U+6C4E */ - {0x94c5, 0x00e78988}, /* U+7248 */ - {0x94c6, 0x00e78aaf}, /* U+72AF */ - {0x94c7, 0x00e78fad}, /* U+73ED */ - {0x94c8, 0x00e79594}, /* U+7554 */ - {0x94c9, 0x00e7b981}, /* U+7E41 */ - {0x94ca, 0x00e888ac}, /* U+822C */ - {0x94cb, 0x00e897a9}, /* U+85E9 */ - {0x94cc, 0x00e8b2a9}, /* U+8CA9 */ - {0x94cd, 0x00e7af84}, /* U+7BC4 */ - {0x94ce, 0x00e98786}, /* U+91C6 */ - {0x94cf, 0x00e785a9}, /* U+7169 */ - {0x94d0, 0x00e9a092}, /* U+9812 */ - {0x94d1, 0x00e9a3af}, /* U+98EF */ - {0x94d2, 0x00e68cbd}, /* U+633D */ - {0x94d3, 0x00e699a9}, /* U+6669 */ - {0x94d4, 0x00e795aa}, /* U+756A */ - {0x94d5, 0x00e79ba4}, /* U+76E4 */ - {0x94d6, 0x00e7a390}, /* U+78D0 */ - {0x94d7, 0x00e89583}, /* U+8543 */ - {0x94d8, 0x00e89bae}, /* U+86EE */ - {0x94d9, 0x00e58caa}, /* U+532A */ - {0x94da, 0x00e58d91}, /* U+5351 */ - {0x94db, 0x00e590a6}, /* U+5426 */ - {0x94dc, 0x00e5a683}, /* U+5983 */ - {0x94dd, 0x00e5ba87}, /* U+5E87 */ - {0x94de, 0x00e5bdbc}, /* U+5F7C */ - {0x94df, 0x00e682b2}, /* U+60B2 */ - {0x94e0, 0x00e68989}, /* U+6249 */ - {0x94e1, 0x00e689b9}, /* U+6279 */ - {0x94e2, 0x00e68aab}, /* U+62AB */ - {0x94e3, 0x00e69690}, /* U+6590 */ - {0x94e4, 0x00e6af94}, /* U+6BD4 */ - {0x94e5, 0x00e6b38c}, /* U+6CCC */ - {0x94e6, 0x00e796b2}, /* U+75B2 */ - {0x94e7, 0x00e79aae}, /* U+76AE */ - {0x94e8, 0x00e7a291}, /* U+7891 */ - {0x94e9, 0x00e7a798}, /* U+79D8 */ - {0x94ea, 0x00e7b78b}, /* U+7DCB */ - {0x94eb, 0x00e7bdb7}, /* U+7F77 */ - {0x94ec, 0x00e882a5}, /* U+80A5 */ - {0x94ed, 0x00e8a2ab}, /* U+88AB */ - {0x94ee, 0x00e8aab9}, /* U+8AB9 */ - {0x94ef, 0x00e8b2bb}, /* U+8CBB */ - {0x94f0, 0x00e981bf}, /* U+907F */ - {0x94f1, 0x00e99d9e}, /* U+975E */ - {0x94f2, 0x00e9a39b}, /* U+98DB */ - {0x94f3, 0x00e6a88b}, /* U+6A0B */ - {0x94f4, 0x00e7b0b8}, /* U+7C38 */ - {0x94f5, 0x00e58299}, /* U+5099 */ - {0x94f6, 0x00e5b0be}, /* U+5C3E */ - {0x94f7, 0x00e5beae}, /* U+5FAE */ - {0x94f8, 0x00e69e87}, /* U+6787 */ - {0x94f9, 0x00e6af98}, /* U+6BD8 */ - {0x94fa, 0x00e790b5}, /* U+7435 */ - {0x94fb, 0x00e79c89}, /* U+7709 */ - {0x94fc, 0x00e7be8e}, /* U+7F8E */ - {0x9540, 0x00e9bcbb}, /* U+9F3B */ - {0x9541, 0x00e69f8a}, /* U+67CA */ - {0x9542, 0x00e7a897}, /* U+7A17 */ - {0x9543, 0x00e58cb9}, /* U+5339 */ - {0x9544, 0x00e7968b}, /* U+758B */ - {0x9545, 0x00e9abad}, /* U+9AED */ - {0x9546, 0x00e5bda6}, /* U+5F66 */ - {0x9547, 0x00e8869d}, /* U+819D */ - {0x9548, 0x00e88fb1}, /* U+83F1 */ - {0x9549, 0x00e88298}, /* U+8098 */ - {0x954a, 0x00e5bcbc}, /* U+5F3C */ - {0x954b, 0x00e5bf85}, /* U+5FC5 */ - {0x954c, 0x00e795a2}, /* U+7562 */ - {0x954d, 0x00e7ad86}, /* U+7B46 */ - {0x954e, 0x00e980bc}, /* U+903C */ - {0x954f, 0x00e6a1a7}, /* U+6867 */ - {0x9550, 0x00e5a7ab}, /* U+59EB */ - {0x9551, 0x00e5aa9b}, /* U+5A9B */ - {0x9552, 0x00e7b490}, /* U+7D10 */ - {0x9553, 0x00e799be}, /* U+767E */ - {0x9554, 0x00e8acac}, /* U+8B2C */ - {0x9555, 0x00e4bfb5}, /* U+4FF5 */ - {0x9556, 0x00e5bdaa}, /* U+5F6A */ - {0x9557, 0x00e6a899}, /* U+6A19 */ - {0x9558, 0x00e6b0b7}, /* U+6C37 */ - {0x9559, 0x00e6bc82}, /* U+6F02 */ - {0x955a, 0x00e793a2}, /* U+74E2 */ - {0x955b, 0x00e7a5a8}, /* U+7968 */ - {0x955c, 0x00e8a1a8}, /* U+8868 */ - {0x955d, 0x00e8a995}, /* U+8A55 */ - {0x955e, 0x00e8b1b9}, /* U+8C79 */ - {0x955f, 0x00e5bb9f}, /* U+5EDF */ - {0x9560, 0x00e68f8f}, /* U+63CF */ - {0x9561, 0x00e79785}, /* U+75C5 */ - {0x9562, 0x00e7a792}, /* U+79D2 */ - {0x9563, 0x00e88b97}, /* U+82D7 */ - {0x9564, 0x00e98ca8}, /* U+9328 */ - {0x9565, 0x00e98bb2}, /* U+92F2 */ - {0x9566, 0x00e8929c}, /* U+849C */ - {0x9567, 0x00e89bad}, /* U+86ED */ - {0x9568, 0x00e9b0ad}, /* U+9C2D */ - {0x9569, 0x00e59381}, /* U+54C1 */ - {0x956a, 0x00e5bdac}, /* U+5F6C */ - {0x956b, 0x00e6968c}, /* U+658C */ - {0x956c, 0x00e6b59c}, /* U+6D5C */ - {0x956d, 0x00e78095}, /* U+7015 */ - {0x956e, 0x00e8b2a7}, /* U+8CA7 */ - {0x956f, 0x00e8b393}, /* U+8CD3 */ - {0x9570, 0x00e9a0bb}, /* U+983B */ - {0x9571, 0x00e6958f}, /* U+654F */ - {0x9572, 0x00e793b6}, /* U+74F6 */ - {0x9573, 0x00e4b88d}, /* U+4E0D */ - {0x9574, 0x00e4bb98}, /* U+4ED8 */ - {0x9575, 0x00e59fa0}, /* U+57E0 */ - {0x9576, 0x00e5a4ab}, /* U+592B */ - {0x9577, 0x00e5a9a6}, /* U+5A66 */ - {0x9578, 0x00e5af8c}, /* U+5BCC */ - {0x9579, 0x00e586a8}, /* U+51A8 */ - {0x957a, 0x00e5b883}, /* U+5E03 */ - {0x957b, 0x00e5ba9c}, /* U+5E9C */ - {0x957c, 0x00e68096}, /* U+6016 */ - {0x957d, 0x00e689b6}, /* U+6276 */ - {0x957e, 0x00e695b7}, /* U+6577 */ - {0x9580, 0x00e696a7}, /* U+65A7 */ - {0x9581, 0x00e699ae}, /* U+666E */ - {0x9582, 0x00e6b5ae}, /* U+6D6E */ - {0x9583, 0x00e788b6}, /* U+7236 */ - {0x9584, 0x00e7aca6}, /* U+7B26 */ - {0x9585, 0x00e88590}, /* U+8150 */ - {0x9586, 0x00e8869a}, /* U+819A */ - {0x9587, 0x00e88a99}, /* U+8299 */ - {0x9588, 0x00e8ad9c}, /* U+8B5C */ - {0x9589, 0x00e8b2a0}, /* U+8CA0 */ - {0x958a, 0x00e8b3a6}, /* U+8CE6 */ - {0x958b, 0x00e8b5b4}, /* U+8D74 */ - {0x958c, 0x00e9989c}, /* U+961C */ - {0x958d, 0x00e99984}, /* U+9644 */ - {0x958e, 0x00e4beae}, /* U+4FAE */ - {0x958f, 0x00e692ab}, /* U+64AB */ - {0x9590, 0x00e6ada6}, /* U+6B66 */ - {0x9591, 0x00e8889e}, /* U+821E */ - {0x9592, 0x00e891a1}, /* U+8461 */ - {0x9593, 0x00e895aa}, /* U+856A */ - {0x9594, 0x00e983a8}, /* U+90E8 */ - {0x9595, 0x00e5b081}, /* U+5C01 */ - {0x9596, 0x00e6a593}, /* U+6953 */ - {0x9597, 0x00e9a2a8}, /* U+98A8 */ - {0x9598, 0x00e891ba}, /* U+847A */ - {0x9599, 0x00e89597}, /* U+8557 */ - {0x959a, 0x00e4bc8f}, /* U+4F0F */ - {0x959b, 0x00e589af}, /* U+526F */ - {0x959c, 0x00e5bea9}, /* U+5FA9 */ - {0x959d, 0x00e5b985}, /* U+5E45 */ - {0x959e, 0x00e69c8d}, /* U+670D */ - {0x959f, 0x00e7a68f}, /* U+798F */ - {0x95a0, 0x00e885b9}, /* U+8179 */ - {0x95a1, 0x00e8a487}, /* U+8907 */ - {0x95a2, 0x00e8a686}, /* U+8986 */ - {0x95a3, 0x00e6b7b5}, /* U+6DF5 */ - {0x95a4, 0x00e5bc97}, /* U+5F17 */ - {0x95a5, 0x00e68995}, /* U+6255 */ - {0x95a6, 0x00e6b2b8}, /* U+6CB8 */ - {0x95a7, 0x00e4bb8f}, /* U+4ECF */ - {0x95a8, 0x00e789a9}, /* U+7269 */ - {0x95a9, 0x00e9ae92}, /* U+9B92 */ - {0x95aa, 0x00e58886}, /* U+5206 */ - {0x95ab, 0x00e590bb}, /* U+543B */ - {0x95ac, 0x00e599b4}, /* U+5674 */ - {0x95ad, 0x00e5a2b3}, /* U+58B3 */ - {0x95ae, 0x00e686a4}, /* U+61A4 */ - {0x95af, 0x00e689ae}, /* U+626E */ - {0x95b0, 0x00e7849a}, /* U+711A */ - {0x95b1, 0x00e5a5ae}, /* U+596E */ - {0x95b2, 0x00e7b289}, /* U+7C89 */ - {0x95b3, 0x00e7b39e}, /* U+7CDE */ - {0x95b4, 0x00e7b49b}, /* U+7D1B */ - {0x95b5, 0x00e99bb0}, /* U+96F0 */ - {0x95b6, 0x00e69687}, /* U+6587 */ - {0x95b7, 0x00e8819e}, /* U+805E */ - {0x95b8, 0x00e4b899}, /* U+4E19 */ - {0x95b9, 0x00e4bdb5}, /* U+4F75 */ - {0x95ba, 0x00e585b5}, /* U+5175 */ - {0x95bb, 0x00e5a180}, /* U+5840 */ - {0x95bc, 0x00e5b9a3}, /* U+5E63 */ - {0x95bd, 0x00e5b9b3}, /* U+5E73 */ - {0x95be, 0x00e5bc8a}, /* U+5F0A */ - {0x95bf, 0x00e69f84}, /* U+67C4 */ - {0x95c0, 0x00e4b8a6}, /* U+4E26 */ - {0x95c1, 0x00e894bd}, /* U+853D */ - {0x95c2, 0x00e99689}, /* U+9589 */ - {0x95c3, 0x00e9999b}, /* U+965B */ - {0x95c4, 0x00e7b1b3}, /* U+7C73 */ - {0x95c5, 0x00e9a081}, /* U+9801 */ - {0x95c6, 0x00e583bb}, /* U+50FB */ - {0x95c7, 0x00e5a381}, /* U+58C1 */ - {0x95c8, 0x00e79996}, /* U+7656 */ - {0x95c9, 0x00e7a2a7}, /* U+78A7 */ - {0x95ca, 0x00e588a5}, /* U+5225 */ - {0x95cb, 0x00e79ea5}, /* U+77A5 */ - {0x95cc, 0x00e89491}, /* U+8511 */ - {0x95cd, 0x00e7ae86}, /* U+7B86 */ - {0x95ce, 0x00e5818f}, /* U+504F */ - {0x95cf, 0x00e5a489}, /* U+5909 */ - {0x95d0, 0x00e78987}, /* U+7247 */ - {0x95d1, 0x00e7af87}, /* U+7BC7 */ - {0x95d2, 0x00e7b7a8}, /* U+7DE8 */ - {0x95d3, 0x00e8beba}, /* U+8FBA */ - {0x95d4, 0x00e8bf94}, /* U+8FD4 */ - {0x95d5, 0x00e9818d}, /* U+904D */ - {0x95d6, 0x00e4bebf}, /* U+4FBF */ - {0x95d7, 0x00e58b89}, /* U+52C9 */ - {0x95d8, 0x00e5a8a9}, /* U+5A29 */ - {0x95d9, 0x00e5bc81}, /* U+5F01 */ - {0x95da, 0x00e99ead}, /* U+97AD */ - {0x95db, 0x00e4bf9d}, /* U+4FDD */ - {0x95dc, 0x00e88897}, /* U+8217 */ - {0x95dd, 0x00e98baa}, /* U+92EA */ - {0x95de, 0x00e59c83}, /* U+5703 */ - {0x95df, 0x00e68d95}, /* U+6355 */ - {0x95e0, 0x00e6ada9}, /* U+6B69 */ - {0x95e1, 0x00e794ab}, /* U+752B */ - {0x95e2, 0x00e8a39c}, /* U+88DC */ - {0x95e3, 0x00e8bc94}, /* U+8F14 */ - {0x95e4, 0x00e7a982}, /* U+7A42 */ - {0x95e5, 0x00e58b9f}, /* U+52DF */ - {0x95e6, 0x00e5a293}, /* U+5893 */ - {0x95e7, 0x00e68595}, /* U+6155 */ - {0x95e8, 0x00e6888a}, /* U+620A */ - {0x95e9, 0x00e69aae}, /* U+66AE */ - {0x95ea, 0x00e6af8d}, /* U+6BCD */ - {0x95eb, 0x00e7b0bf}, /* U+7C3F */ - {0x95ec, 0x00e88fa9}, /* U+83E9 */ - {0x95ed, 0x00e580a3}, /* U+5023 */ - {0x95ee, 0x00e4bfb8}, /* U+4FF8 */ - {0x95ef, 0x00e58c85}, /* U+5305 */ - {0x95f0, 0x00e59186}, /* U+5446 */ - {0x95f1, 0x00e5a0b1}, /* U+5831 */ - {0x95f2, 0x00e5a589}, /* U+5949 */ - {0x95f3, 0x00e5ae9d}, /* U+5B9D */ - {0x95f4, 0x00e5b3b0}, /* U+5CF0 */ - {0x95f5, 0x00e5b3af}, /* U+5CEF */ - {0x95f6, 0x00e5b4a9}, /* U+5D29 */ - {0x95f7, 0x00e5ba96}, /* U+5E96 */ - {0x95f8, 0x00e68ab1}, /* U+62B1 */ - {0x95f9, 0x00e68da7}, /* U+6367 */ - {0x95fa, 0x00e694be}, /* U+653E */ - {0x95fb, 0x00e696b9}, /* U+65B9 */ - {0x95fc, 0x00e69c8b}, /* U+670B */ - {0x9640, 0x00e6b395}, /* U+6CD5 */ - {0x9641, 0x00e6b3a1}, /* U+6CE1 */ - {0x9642, 0x00e783b9}, /* U+70F9 */ - {0x9643, 0x00e7a0b2}, /* U+7832 */ - {0x9644, 0x00e7b8ab}, /* U+7E2B */ - {0x9645, 0x00e8839e}, /* U+80DE */ - {0x9646, 0x00e88ab3}, /* U+82B3 */ - {0x9647, 0x00e8908c}, /* U+840C */ - {0x9648, 0x00e893ac}, /* U+84EC */ - {0x9649, 0x00e89c82}, /* U+8702 */ - {0x964a, 0x00e8a492}, /* U+8912 */ - {0x964b, 0x00e8a8aa}, /* U+8A2A */ - {0x964c, 0x00e8b18a}, /* U+8C4A */ - {0x964d, 0x00e982a6}, /* U+90A6 */ - {0x964e, 0x00e98b92}, /* U+92D2 */ - {0x964f, 0x00e9a3bd}, /* U+98FD */ - {0x9650, 0x00e9b3b3}, /* U+9CF3 */ - {0x9651, 0x00e9b5ac}, /* U+9D6C */ - {0x9652, 0x00e4b98f}, /* U+4E4F */ - {0x9653, 0x00e4baa1}, /* U+4EA1 */ - {0x9654, 0x00e5828d}, /* U+508D */ - {0x9655, 0x00e58996}, /* U+5256 */ - {0x9656, 0x00e59d8a}, /* U+574A */ - {0x9657, 0x00e5a6a8}, /* U+59A8 */ - {0x9658, 0x00e5b8bd}, /* U+5E3D */ - {0x9659, 0x00e5bf98}, /* U+5FD8 */ - {0x965a, 0x00e5bf99}, /* U+5FD9 */ - {0x965b, 0x00e688bf}, /* U+623F */ - {0x965c, 0x00e69ab4}, /* U+66B4 */ - {0x965d, 0x00e69c9b}, /* U+671B */ - {0x965e, 0x00e69f90}, /* U+67D0 */ - {0x965f, 0x00e6a392}, /* U+68D2 */ - {0x9660, 0x00e58692}, /* U+5192 */ - {0x9661, 0x00e7b4a1}, /* U+7D21 */ - {0x9662, 0x00e882aa}, /* U+80AA */ - {0x9663, 0x00e886a8}, /* U+81A8 */ - {0x9664, 0x00e8ac80}, /* U+8B00 */ - {0x9665, 0x00e8b28c}, /* U+8C8C */ - {0x9666, 0x00e8b2bf}, /* U+8CBF */ - {0x9667, 0x00e989be}, /* U+927E */ - {0x9668, 0x00e998b2}, /* U+9632 */ - {0x9669, 0x00e590a0}, /* U+5420 */ - {0x966a, 0x00e9a0ac}, /* U+982C */ - {0x966b, 0x00e58c97}, /* U+5317 */ - {0x966c, 0x00e58395}, /* U+50D5 */ - {0x966d, 0x00e58d9c}, /* U+535C */ - {0x966e, 0x00e5a2a8}, /* U+58A8 */ - {0x966f, 0x00e692b2}, /* U+64B2 */ - {0x9670, 0x00e69cb4}, /* U+6734 */ - {0x9671, 0x00e789a7}, /* U+7267 */ - {0x9672, 0x00e79da6}, /* U+7766 */ - {0x9673, 0x00e7a986}, /* U+7A46 */ - {0x9674, 0x00e987a6}, /* U+91E6 */ - {0x9675, 0x00e58b83}, /* U+52C3 */ - {0x9676, 0x00e6b2a1}, /* U+6CA1 */ - {0x9677, 0x00e6ae86}, /* U+6B86 */ - {0x9678, 0x00e5a080}, /* U+5800 */ - {0x9679, 0x00e5b98c}, /* U+5E4C */ - {0x967a, 0x00e5a594}, /* U+5954 */ - {0x967b, 0x00e69cac}, /* U+672C */ - {0x967c, 0x00e7bfbb}, /* U+7FFB */ - {0x967d, 0x00e587a1}, /* U+51E1 */ - {0x967e, 0x00e79b86}, /* U+76C6 */ - {0x9680, 0x00e691a9}, /* U+6469 */ - {0x9681, 0x00e7a3a8}, /* U+78E8 */ - {0x9682, 0x00e9ad94}, /* U+9B54 */ - {0x9683, 0x00e9babb}, /* U+9EBB */ - {0x9684, 0x00e59f8b}, /* U+57CB */ - {0x9685, 0x00e5a6b9}, /* U+59B9 */ - {0x9686, 0x00e698a7}, /* U+6627 */ - {0x9687, 0x00e69e9a}, /* U+679A */ - {0x9688, 0x00e6af8e}, /* U+6BCE */ - {0x9689, 0x00e593a9}, /* U+54E9 */ - {0x968a, 0x00e6a799}, /* U+69D9 */ - {0x968b, 0x00e5b995}, /* U+5E55 */ - {0x968c, 0x00e8869c}, /* U+819C */ - {0x968d, 0x00e69e95}, /* U+6795 */ - {0x968e, 0x00e9aeaa}, /* U+9BAA */ - {0x968f, 0x00e69fbe}, /* U+67FE */ - {0x9690, 0x00e9b192}, /* U+9C52 */ - {0x9691, 0x00e6a19d}, /* U+685D */ - {0x9692, 0x00e4baa6}, /* U+4EA6 */ - {0x9693, 0x00e4bfa3}, /* U+4FE3 */ - {0x9694, 0x00e58f88}, /* U+53C8 */ - {0x9695, 0x00e68ab9}, /* U+62B9 */ - {0x9696, 0x00e69cab}, /* U+672B */ - {0x9697, 0x00e6b2ab}, /* U+6CAB */ - {0x9698, 0x00e8bf84}, /* U+8FC4 */ - {0x9699, 0x00e4bead}, /* U+4FAD */ - {0x969a, 0x00e7b9ad}, /* U+7E6D */ - {0x969b, 0x00e9babf}, /* U+9EBF */ - {0x969c, 0x00e4b887}, /* U+4E07 */ - {0x969d, 0x00e685a2}, /* U+6162 */ - {0x969e, 0x00e6ba80}, /* U+6E80 */ - {0x969f, 0x00e6bcab}, /* U+6F2B */ - {0x96a0, 0x00e89493}, /* U+8513 */ - {0x96a1, 0x00e591b3}, /* U+5473 */ - {0x96a2, 0x00e69caa}, /* U+672A */ - {0x96a3, 0x00e9ad85}, /* U+9B45 */ - {0x96a4, 0x00e5b7b3}, /* U+5DF3 */ - {0x96a5, 0x00e7ae95}, /* U+7B95 */ - {0x96a6, 0x00e5b2ac}, /* U+5CAC */ - {0x96a7, 0x00e5af86}, /* U+5BC6 */ - {0x96a8, 0x00e89c9c}, /* U+871C */ - {0x96a9, 0x00e6b98a}, /* U+6E4A */ - {0x96aa, 0x00e89391}, /* U+84D1 */ - {0x96ab, 0x00e7a894}, /* U+7A14 */ - {0x96ac, 0x00e88488}, /* U+8108 */ - {0x96ad, 0x00e5a699}, /* U+5999 */ - {0x96ae, 0x00e7b28d}, /* U+7C8D */ - {0x96af, 0x00e6b091}, /* U+6C11 */ - {0x96b0, 0x00e79ca0}, /* U+7720 */ - {0x96b1, 0x00e58b99}, /* U+52D9 */ - {0x96b2, 0x00e5a4a2}, /* U+5922 */ - {0x96b3, 0x00e784a1}, /* U+7121 */ - {0x96b4, 0x00e7899f}, /* U+725F */ - {0x96b5, 0x00e79f9b}, /* U+77DB */ - {0x96b6, 0x00e99ca7}, /* U+9727 */ - {0x96b7, 0x00e9b5a1}, /* U+9D61 */ - {0x96b8, 0x00e6a48b}, /* U+690B */ - {0x96b9, 0x00e5a9bf}, /* U+5A7F */ - {0x96ba, 0x00e5a898}, /* U+5A18 */ - {0x96bb, 0x00e586a5}, /* U+51A5 */ - {0x96bc, 0x00e5908d}, /* U+540D */ - {0x96bd, 0x00e591bd}, /* U+547D */ - {0x96be, 0x00e6988e}, /* U+660E */ - {0x96bf, 0x00e79b9f}, /* U+76DF */ - {0x96c0, 0x00e8bfb7}, /* U+8FF7 */ - {0x96c1, 0x00e98a98}, /* U+9298 */ - {0x96c2, 0x00e9b3b4}, /* U+9CF4 */ - {0x96c3, 0x00e5a7aa}, /* U+59EA */ - {0x96c4, 0x00e7899d}, /* U+725D */ - {0x96c5, 0x00e6bb85}, /* U+6EC5 */ - {0x96c6, 0x00e5858d}, /* U+514D */ - {0x96c7, 0x00e6a389}, /* U+68C9 */ - {0x96c8, 0x00e7b6bf}, /* U+7DBF */ - {0x96c9, 0x00e7b7ac}, /* U+7DEC */ - {0x96ca, 0x00e99da2}, /* U+9762 */ - {0x96cb, 0x00e9baba}, /* U+9EBA */ - {0x96cc, 0x00e691b8}, /* U+6478 */ - {0x96cd, 0x00e6a8a1}, /* U+6A21 */ - {0x96ce, 0x00e88c82}, /* U+8302 */ - {0x96cf, 0x00e5a684}, /* U+5984 */ - {0x96d0, 0x00e5ad9f}, /* U+5B5F */ - {0x96d1, 0x00e6af9b}, /* U+6BDB */ - {0x96d2, 0x00e78c9b}, /* U+731B */ - {0x96d3, 0x00e79bb2}, /* U+76F2 */ - {0x96d4, 0x00e7b6b2}, /* U+7DB2 */ - {0x96d5, 0x00e88097}, /* U+8017 */ - {0x96d6, 0x00e89299}, /* U+8499 */ - {0x96d7, 0x00e584b2}, /* U+5132 */ - {0x96d8, 0x00e69ca8}, /* U+6728 */ - {0x96d9, 0x00e9bb99}, /* U+9ED9 */ - {0x96da, 0x00e79bae}, /* U+76EE */ - {0x96db, 0x00e69da2}, /* U+6762 */ - {0x96dc, 0x00e58bbf}, /* U+52FF */ - {0x96dd, 0x00e9a485}, /* U+9905 */ - {0x96de, 0x00e5b0a4}, /* U+5C24 */ - {0x96df, 0x00e688bb}, /* U+623B */ - {0x96e0, 0x00e7b1be}, /* U+7C7E */ - {0x96e1, 0x00e8b2b0}, /* U+8CB0 */ - {0x96e2, 0x00e5958f}, /* U+554F */ - {0x96e3, 0x00e682b6}, /* U+60B6 */ - {0x96e4, 0x00e7b48b}, /* U+7D0B */ - {0x96e5, 0x00e99680}, /* U+9580 */ - {0x96e6, 0x00e58c81}, /* U+5301 */ - {0x96e7, 0x00e4b99f}, /* U+4E5F */ - {0x96e8, 0x00e586b6}, /* U+51B6 */ - {0x96e9, 0x00e5a49c}, /* U+591C */ - {0x96ea, 0x00e788ba}, /* U+723A */ - {0x96eb, 0x00e880b6}, /* U+8036 */ - {0x96ec, 0x00e9878e}, /* U+91CE */ - {0x96ed, 0x00e5bca5}, /* U+5F25 */ - {0x96ee, 0x00e79fa2}, /* U+77E2 */ - {0x96ef, 0x00e58e84}, /* U+5384 */ - {0x96f0, 0x00e5bdb9}, /* U+5F79 */ - {0x96f1, 0x00e7b484}, /* U+7D04 */ - {0x96f2, 0x00e896ac}, /* U+85AC */ - {0x96f3, 0x00e8a8b3}, /* U+8A33 */ - {0x96f4, 0x00e8ba8d}, /* U+8E8D */ - {0x96f5, 0x00e99d96}, /* U+9756 */ - {0x96f6, 0x00e69fb3}, /* U+67F3 */ - {0x96f7, 0x00e896ae}, /* U+85AE */ - {0x96f8, 0x00e99193}, /* U+9453 */ - {0x96f9, 0x00e68489}, /* U+6109 */ - {0x96fa, 0x00e68488}, /* U+6108 */ - {0x96fb, 0x00e6b2b9}, /* U+6CB9 */ - {0x96fc, 0x00e79992}, /* U+7652 */ - {0x9740, 0x00e8abad}, /* U+8AED */ - {0x9741, 0x00e8bcb8}, /* U+8F38 */ - {0x9742, 0x00e594af}, /* U+552F */ - {0x9743, 0x00e4bd91}, /* U+4F51 */ - {0x9744, 0x00e584aa}, /* U+512A */ - {0x9745, 0x00e58b87}, /* U+52C7 */ - {0x9746, 0x00e58f8b}, /* U+53CB */ - {0x9747, 0x00e5aea5}, /* U+5BA5 */ - {0x9748, 0x00e5b9bd}, /* U+5E7D */ - {0x9749, 0x00e682a0}, /* U+60A0 */ - {0x974a, 0x00e68682}, /* U+6182 */ - {0x974b, 0x00e68f96}, /* U+63D6 */ - {0x974c, 0x00e69c89}, /* U+6709 */ - {0x974d, 0x00e69f9a}, /* U+67DA */ - {0x974e, 0x00e6b9a7}, /* U+6E67 */ - {0x974f, 0x00e6b68c}, /* U+6D8C */ - {0x9750, 0x00e78cb6}, /* U+7336 */ - {0x9751, 0x00e78cb7}, /* U+7337 */ - {0x9752, 0x00e794b1}, /* U+7531 */ - {0x9753, 0x00e7a590}, /* U+7950 */ - {0x9754, 0x00e8a395}, /* U+88D5 */ - {0x9755, 0x00e8aa98}, /* U+8A98 */ - {0x9756, 0x00e9818a}, /* U+904A */ - {0x9757, 0x00e98291}, /* U+9091 */ - {0x9758, 0x00e983b5}, /* U+90F5 */ - {0x9759, 0x00e99b84}, /* U+96C4 */ - {0x975a, 0x00e89e8d}, /* U+878D */ - {0x975b, 0x00e5a495}, /* U+5915 */ - {0x975c, 0x00e4ba88}, /* U+4E88 */ - {0x975d, 0x00e4bd99}, /* U+4F59 */ - {0x975e, 0x00e4b88e}, /* U+4E0E */ - {0x975f, 0x00e8aa89}, /* U+8A89 */ - {0x9760, 0x00e8bcbf}, /* U+8F3F */ - {0x9761, 0x00e9a090}, /* U+9810 */ - {0x9762, 0x00e582ad}, /* U+50AD */ - {0x9763, 0x00e5b9bc}, /* U+5E7C */ - {0x9764, 0x00e5a696}, /* U+5996 */ - {0x9765, 0x00e5aeb9}, /* U+5BB9 */ - {0x9766, 0x00e5bab8}, /* U+5EB8 */ - {0x9767, 0x00e68f9a}, /* U+63DA */ - {0x9768, 0x00e68fba}, /* U+63FA */ - {0x9769, 0x00e69381}, /* U+64C1 */ - {0x976a, 0x00e69b9c}, /* U+66DC */ - {0x976b, 0x00e6a58a}, /* U+694A */ - {0x976c, 0x00e6a798}, /* U+69D8 */ - {0x976d, 0x00e6b48b}, /* U+6D0B */ - {0x976e, 0x00e6bab6}, /* U+6EB6 */ - {0x976f, 0x00e78694}, /* U+7194 */ - {0x9770, 0x00e794a8}, /* U+7528 */ - {0x9771, 0x00e7aaaf}, /* U+7AAF */ - {0x9772, 0x00e7be8a}, /* U+7F8A */ - {0x9773, 0x00e88080}, /* U+8000 */ - {0x9774, 0x00e89189}, /* U+8449 */ - {0x9775, 0x00e89389}, /* U+84C9 */ - {0x9776, 0x00e8a681}, /* U+8981 */ - {0x9777, 0x00e8aca1}, /* U+8B21 */ - {0x9778, 0x00e8b88a}, /* U+8E0A */ - {0x9779, 0x00e981a5}, /* U+9065 */ - {0x977a, 0x00e999bd}, /* U+967D */ - {0x977b, 0x00e9a48a}, /* U+990A */ - {0x977c, 0x00e685be}, /* U+617E */ - {0x977d, 0x00e68a91}, /* U+6291 */ - {0x977e, 0x00e6acb2}, /* U+6B32 */ - {0x9780, 0x00e6b283}, /* U+6C83 */ - {0x9781, 0x00e6b5b4}, /* U+6D74 */ - {0x9782, 0x00e7bf8c}, /* U+7FCC */ - {0x9783, 0x00e7bfbc}, /* U+7FFC */ - {0x9784, 0x00e6b780}, /* U+6DC0 */ - {0x9785, 0x00e7be85}, /* U+7F85 */ - {0x9786, 0x00e89eba}, /* U+87BA */ - {0x9787, 0x00e8a3b8}, /* U+88F8 */ - {0x9788, 0x00e69da5}, /* U+6765 */ - {0x9789, 0x00e88eb1}, /* U+83B1 */ - {0x978a, 0x00e9a0bc}, /* U+983C */ - {0x978b, 0x00e99bb7}, /* U+96F7 */ - {0x978c, 0x00e6b49b}, /* U+6D1B */ - {0x978d, 0x00e7b5a1}, /* U+7D61 */ - {0x978e, 0x00e890bd}, /* U+843D */ - {0x978f, 0x00e985aa}, /* U+916A */ - {0x9790, 0x00e4b9b1}, /* U+4E71 */ - {0x9791, 0x00e58db5}, /* U+5375 */ - {0x9792, 0x00e5b590}, /* U+5D50 */ - {0x9793, 0x00e6ac84}, /* U+6B04 */ - {0x9794, 0x00e6bfab}, /* U+6FEB */ - {0x9795, 0x00e8978d}, /* U+85CD */ - {0x9796, 0x00e898ad}, /* U+862D */ - {0x9797, 0x00e8a6a7}, /* U+89A7 */ - {0x9798, 0x00e588a9}, /* U+5229 */ - {0x9799, 0x00e5908f}, /* U+540F */ - {0x979a, 0x00e5b1a5}, /* U+5C65 */ - {0x979b, 0x00e69d8e}, /* U+674E */ - {0x979c, 0x00e6a2a8}, /* U+68A8 */ - {0x979d, 0x00e79086}, /* U+7406 */ - {0x979e, 0x00e79283}, /* U+7483 */ - {0x979f, 0x00e797a2}, /* U+75E2 */ - {0x97a0, 0x00e8a38f}, /* U+88CF */ - {0x97a1, 0x00e8a3a1}, /* U+88E1 */ - {0x97a2, 0x00e9878c}, /* U+91CC */ - {0x97a3, 0x00e99ba2}, /* U+96E2 */ - {0x97a4, 0x00e999b8}, /* U+9678 */ - {0x97a5, 0x00e5be8b}, /* U+5F8B */ - {0x97a6, 0x00e78e87}, /* U+7387 */ - {0x97a7, 0x00e7ab8b}, /* U+7ACB */ - {0x97a8, 0x00e8918e}, /* U+844E */ - {0x97a9, 0x00e68ea0}, /* U+63A0 */ - {0x97aa, 0x00e795a5}, /* U+7565 */ - {0x97ab, 0x00e58a89}, /* U+5289 */ - {0x97ac, 0x00e6b581}, /* U+6D41 */ - {0x97ad, 0x00e6ba9c}, /* U+6E9C */ - {0x97ae, 0x00e79089}, /* U+7409 */ - {0x97af, 0x00e79599}, /* U+7559 */ - {0x97b0, 0x00e7a1ab}, /* U+786B */ - {0x97b1, 0x00e7b292}, /* U+7C92 */ - {0x97b2, 0x00e99a86}, /* U+9686 */ - {0x97b3, 0x00e7ab9c}, /* U+7ADC */ - {0x97b4, 0x00e9be8d}, /* U+9F8D */ - {0x97b5, 0x00e4beb6}, /* U+4FB6 */ - {0x97b6, 0x00e685ae}, /* U+616E */ - {0x97b7, 0x00e69785}, /* U+65C5 */ - {0x97b8, 0x00e8999c}, /* U+865C */ - {0x97b9, 0x00e4ba86}, /* U+4E86 */ - {0x97ba, 0x00e4baae}, /* U+4EAE */ - {0x97bb, 0x00e5839a}, /* U+50DA */ - {0x97bc, 0x00e4b8a1}, /* U+4E21 */ - {0x97bd, 0x00e5878c}, /* U+51CC */ - {0x97be, 0x00e5afae}, /* U+5BEE */ - {0x97bf, 0x00e69699}, /* U+6599 */ - {0x97c0, 0x00e6a281}, /* U+6881 */ - {0x97c1, 0x00e6b6bc}, /* U+6DBC */ - {0x97c2, 0x00e78c9f}, /* U+731F */ - {0x97c3, 0x00e79982}, /* U+7642 */ - {0x97c4, 0x00e79ead}, /* U+77AD */ - {0x97c5, 0x00e7a89c}, /* U+7A1C */ - {0x97c6, 0x00e7b3a7}, /* U+7CE7 */ - {0x97c7, 0x00e889af}, /* U+826F */ - {0x97c8, 0x00e8ab92}, /* U+8AD2 */ - {0x97c9, 0x00e981bc}, /* U+907C */ - {0x97ca, 0x00e9878f}, /* U+91CF */ - {0x97cb, 0x00e999b5}, /* U+9675 */ - {0x97cc, 0x00e9a098}, /* U+9818 */ - {0x97cd, 0x00e58a9b}, /* U+529B */ - {0x97ce, 0x00e7b791}, /* U+7DD1 */ - {0x97cf, 0x00e580ab}, /* U+502B */ - {0x97d0, 0x00e58e98}, /* U+5398 */ - {0x97d1, 0x00e69e97}, /* U+6797 */ - {0x97d2, 0x00e6b78b}, /* U+6DCB */ - {0x97d3, 0x00e78790}, /* U+71D0 */ - {0x97d4, 0x00e790b3}, /* U+7433 */ - {0x97d5, 0x00e887a8}, /* U+81E8 */ - {0x97d6, 0x00e8bcaa}, /* U+8F2A */ - {0x97d7, 0x00e99aa3}, /* U+96A3 */ - {0x97d8, 0x00e9b197}, /* U+9C57 */ - {0x97d9, 0x00e9ba9f}, /* U+9E9F */ - {0x97da, 0x00e791a0}, /* U+7460 */ - {0x97db, 0x00e5a181}, /* U+5841 */ - {0x97dc, 0x00e6b699}, /* U+6D99 */ - {0x97dd, 0x00e7b4af}, /* U+7D2F */ - {0x97de, 0x00e9a19e}, /* U+985E */ - {0x97df, 0x00e4bba4}, /* U+4EE4 */ - {0x97e0, 0x00e4bcb6}, /* U+4F36 */ - {0x97e1, 0x00e4be8b}, /* U+4F8B */ - {0x97e2, 0x00e586b7}, /* U+51B7 */ - {0x97e3, 0x00e58ab1}, /* U+52B1 */ - {0x97e4, 0x00e5b6ba}, /* U+5DBA */ - {0x97e5, 0x00e6809c}, /* U+601C */ - {0x97e6, 0x00e78eb2}, /* U+73B2 */ - {0x97e7, 0x00e7a4bc}, /* U+793C */ - {0x97e8, 0x00e88b93}, /* U+82D3 */ - {0x97e9, 0x00e988b4}, /* U+9234 */ - {0x97ea, 0x00e99ab7}, /* U+96B7 */ - {0x97eb, 0x00e99bb6}, /* U+96F6 */ - {0x97ec, 0x00e99c8a}, /* U+970A */ - {0x97ed, 0x00e9ba97}, /* U+9E97 */ - {0x97ee, 0x00e9bda2}, /* U+9F62 */ - {0x97ef, 0x00e69aa6}, /* U+66A6 */ - {0x97f0, 0x00e6adb4}, /* U+6B74 */ - {0x97f1, 0x00e58897}, /* U+5217 */ - {0x97f2, 0x00e58aa3}, /* U+52A3 */ - {0x97f3, 0x00e78388}, /* U+70C8 */ - {0x97f4, 0x00e8a382}, /* U+88C2 */ - {0x97f5, 0x00e5bb89}, /* U+5EC9 */ - {0x97f6, 0x00e6818b}, /* U+604B */ - {0x97f7, 0x00e68690}, /* U+6190 */ - {0x97f8, 0x00e6bca3}, /* U+6F23 */ - {0x97f9, 0x00e78589}, /* U+7149 */ - {0x97fa, 0x00e7b0be}, /* U+7C3E */ - {0x97fb, 0x00e7b7b4}, /* U+7DF4 */ - {0x97fc, 0x00e881af}, /* U+806F */ - {0x9840, 0x00e893ae}, /* U+84EE */ - {0x9841, 0x00e980a3}, /* U+9023 */ - {0x9842, 0x00e98cac}, /* U+932C */ - {0x9843, 0x00e59182}, /* U+5442 */ - {0x9844, 0x00e9adaf}, /* U+9B6F */ - {0x9845, 0x00e6ab93}, /* U+6AD3 */ - {0x9846, 0x00e78289}, /* U+7089 */ - {0x9847, 0x00e8b382}, /* U+8CC2 */ - {0x9848, 0x00e8b7af}, /* U+8DEF */ - {0x9849, 0x00e99cb2}, /* U+9732 */ - {0x984a, 0x00e58ab4}, /* U+52B4 */ - {0x984b, 0x00e5a981}, /* U+5A41 */ - {0x984c, 0x00e5bb8a}, /* U+5ECA */ - {0x984d, 0x00e5bc84}, /* U+5F04 */ - {0x984e, 0x00e69c97}, /* U+6717 */ - {0x984f, 0x00e6a5bc}, /* U+697C */ - {0x9850, 0x00e6a694}, /* U+6994 */ - {0x9851, 0x00e6b5aa}, /* U+6D6A */ - {0x9852, 0x00e6bc8f}, /* U+6F0F */ - {0x9853, 0x00e789a2}, /* U+7262 */ - {0x9854, 0x00e78bbc}, /* U+72FC */ - {0x9855, 0x00e7afad}, /* U+7BED */ - {0x9856, 0x00e88081}, /* U+8001 */ - {0x9857, 0x00e881be}, /* U+807E */ - {0x9858, 0x00e89d8b}, /* U+874B */ - {0x9859, 0x00e9838e}, /* U+90CE */ - {0x985a, 0x00e585ad}, /* U+516D */ - {0x985b, 0x00e9ba93}, /* U+9E93 */ - {0x985c, 0x00e7a684}, /* U+7984 */ - {0x985d, 0x00e8828b}, /* U+808B */ - {0x985e, 0x00e98cb2}, /* U+9332 */ - {0x985f, 0x00e8ab96}, /* U+8AD6 */ - {0x9860, 0x00e580ad}, /* U+502D */ - {0x9861, 0x00e5928c}, /* U+548C */ - {0x9862, 0x00e8a9b1}, /* U+8A71 */ - {0x9863, 0x00e6adaa}, /* U+6B6A */ - {0x9864, 0x00e8b384}, /* U+8CC4 */ - {0x9865, 0x00e88487}, /* U+8107 */ - {0x9866, 0x00e68391}, /* U+60D1 */ - {0x9867, 0x00e69ea0}, /* U+67A0 */ - {0x9868, 0x00e9b7b2}, /* U+9DF2 */ - {0x9869, 0x00e4ba99}, /* U+4E99 */ - {0x986a, 0x00e4ba98}, /* U+4E98 */ - {0x986b, 0x00e9b090}, /* U+9C10 */ - {0x986c, 0x00e8a9ab}, /* U+8A6B */ - {0x986d, 0x00e89781}, /* U+85C1 */ - {0x986e, 0x00e895a8}, /* U+8568 */ - {0x986f, 0x00e6a480}, /* U+6900 */ - {0x9870, 0x00e6b9be}, /* U+6E7E */ - {0x9871, 0x00e7a297}, /* U+7897 */ - {0x9872, 0x00e88595}, /* U+8155 */ + {0x889c, 0xe5ac99}, /* U+5B19 [2000] */ + {0x889d, 0xe5aca5}, /* U+5B25 [2000] */ + {0x889e, 0xe5899d}, /* U+525D [2004] */ + {0x889f, 0xe4ba9c}, /* U+4E9C */ + {0x88a0, 0xe59496}, /* U+5516 */ + {0x88a1, 0xe5a883}, /* U+5A03 */ + {0x88a2, 0xe998bf}, /* U+963F */ + {0x88a3, 0xe59380}, /* U+54C0 */ + {0x88a4, 0xe6849b}, /* U+611B */ + {0x88a5, 0xe68ca8}, /* U+6328 */ + {0x88a6, 0xe5a7b6}, /* U+59F6 */ + {0x88a7, 0xe980a2}, /* U+9022 */ + {0x88a8, 0xe891b5}, /* U+8475 */ + {0x88a9, 0xe88c9c}, /* U+831C */ + {0x88aa, 0xe7a990}, /* U+7A50 */ + {0x88ab, 0xe682aa}, /* U+60AA */ + {0x88ac, 0xe68fa1}, /* U+63E1 */ + {0x88ad, 0xe6b8a5}, /* U+6E25 */ + {0x88ae, 0xe697ad}, /* U+65ED */ + {0x88af, 0xe891a6}, /* U+8466 */ + {0x88b0, 0xe88aa6}, /* U+82A6 */ + {0x88b1, 0xe9afb5}, /* U+9BF5 */ + {0x88b2, 0xe6a293}, /* U+6893 */ + {0x88b3, 0xe59ca7}, /* U+5727 */ + {0x88b4, 0xe696a1}, /* U+65A1 */ + {0x88b5, 0xe689b1}, /* U+6271 */ + {0x88b6, 0xe5ae9b}, /* U+5B9B */ + {0x88b7, 0xe5a790}, /* U+59D0 */ + {0x88b8, 0xe899bb}, /* U+867B */ + {0x88b9, 0xe9a3b4}, /* U+98F4 */ + {0x88ba, 0xe7b5a2}, /* U+7D62 */ + {0x88bb, 0xe7b6be}, /* U+7DBE */ + {0x88bc, 0xe9ae8e}, /* U+9B8E */ + {0x88bd, 0xe68896}, /* U+6216 */ + {0x88be, 0xe7b29f}, /* U+7C9F */ + {0x88bf, 0xe8a2b7}, /* U+88B7 */ + {0x88c0, 0xe5ae89}, /* U+5B89 */ + {0x88c1, 0xe5bab5}, /* U+5EB5 */ + {0x88c2, 0xe68c89}, /* U+6309 */ + {0x88c3, 0xe69a97}, /* U+6697 */ + {0x88c4, 0xe6a188}, /* U+6848 */ + {0x88c5, 0xe99787}, /* U+95C7 */ + {0x88c6, 0xe99e8d}, /* U+978D */ + {0x88c7, 0xe69d8f}, /* U+674F */ + {0x88c8, 0xe4bba5}, /* U+4EE5 */ + {0x88c9, 0xe4bc8a}, /* U+4F0A */ + {0x88ca, 0xe4bd8d}, /* U+4F4D */ + {0x88cb, 0xe4be9d}, /* U+4F9D */ + {0x88cc, 0xe58189}, /* U+5049 */ + {0x88cd, 0xe59bb2}, /* U+56F2 */ + {0x88ce, 0xe5a4b7}, /* U+5937 */ + {0x88cf, 0xe5a794}, /* U+59D4 */ + {0x88d0, 0xe5a881}, /* U+5A01 */ + {0x88d1, 0xe5b089}, /* U+5C09 */ + {0x88d2, 0xe6839f}, /* U+60DF */ + {0x88d3, 0xe6848f}, /* U+610F */ + {0x88d4, 0xe685b0}, /* U+6170 */ + {0x88d5, 0xe69893}, /* U+6613 */ + {0x88d6, 0xe6a485}, /* U+6905 */ + {0x88d7, 0xe782ba}, /* U+70BA */ + {0x88d8, 0xe7958f}, /* U+754F */ + {0x88d9, 0xe795b0}, /* U+7570 */ + {0x88da, 0xe7a7bb}, /* U+79FB */ + {0x88db, 0xe7b6ad}, /* U+7DAD */ + {0x88dc, 0xe7b7af}, /* U+7DEF */ + {0x88dd, 0xe88383}, /* U+80C3 */ + {0x88de, 0xe8908e}, /* U+840E */ + {0x88df, 0xe8a1a3}, /* U+8863 */ + {0x88e0, 0xe8ac82}, /* U+8B02 */ + {0x88e1, 0xe98195}, /* U+9055 */ + {0x88e2, 0xe981ba}, /* U+907A */ + {0x88e3, 0xe58cbb}, /* U+533B */ + {0x88e4, 0xe4ba95}, /* U+4E95 */ + {0x88e5, 0xe4baa5}, /* U+4EA5 */ + {0x88e6, 0xe59f9f}, /* U+57DF */ + {0x88e7, 0xe882b2}, /* U+80B2 */ + {0x88e8, 0xe98381}, /* U+90C1 */ + {0x88e9, 0xe7a3af}, /* U+78EF */ + {0x88ea, 0xe4b880}, /* U+4E00 */ + {0x88eb, 0xe5a3b1}, /* U+58F1 */ + {0x88ec, 0xe6baa2}, /* U+6EA2 */ + {0x88ed, 0xe980b8}, /* U+9038 */ + {0x88ee, 0xe7a8b2}, /* U+7A32 */ + {0x88ef, 0xe88ca8}, /* U+8328 */ + {0x88f0, 0xe88a8b}, /* U+828B */ + {0x88f1, 0xe9b0af}, /* U+9C2F */ + {0x88f2, 0xe58581}, /* U+5141 */ + {0x88f3, 0xe58db0}, /* U+5370 */ + {0x88f4, 0xe592bd}, /* U+54BD */ + {0x88f5, 0xe593a1}, /* U+54E1 */ + {0x88f6, 0xe59ba0}, /* U+56E0 */ + {0x88f7, 0xe5a7bb}, /* U+59FB */ + {0x88f8, 0xe5bc95}, /* U+5F15 */ + {0x88f9, 0xe9a3b2}, /* U+98F2 */ + {0x88fa, 0xe6b7ab}, /* U+6DEB */ + {0x88fb, 0xe883a4}, /* U+80E4 */ + {0x88fc, 0xe894ad}, /* U+852D */ + {0x8940, 0xe999a2}, /* U+9662 */ + {0x8941, 0xe999b0}, /* U+9670 */ + {0x8942, 0xe99aa0}, /* U+96A0 */ + {0x8943, 0xe99fbb}, /* U+97FB */ + {0x8944, 0xe5908b}, /* U+540B */ + {0x8945, 0xe58fb3}, /* U+53F3 */ + {0x8946, 0xe5ae87}, /* U+5B87 */ + {0x8947, 0xe7838f}, /* U+70CF */ + {0x8948, 0xe7bebd}, /* U+7FBD */ + {0x8949, 0xe8bf82}, /* U+8FC2 */ + {0x894a, 0xe99ba8}, /* U+96E8 */ + {0x894b, 0xe58daf}, /* U+536F */ + {0x894c, 0xe9b59c}, /* U+9D5C */ + {0x894d, 0xe7aaba}, /* U+7ABA */ + {0x894e, 0xe4b891}, /* U+4E11 */ + {0x894f, 0xe7a293}, /* U+7893 */ + {0x8950, 0xe887bc}, /* U+81FC */ + {0x8951, 0xe6b8a6}, /* U+6E26 */ + {0x8952, 0xe59898}, /* U+5618 */ + {0x8953, 0xe59484}, /* U+5504 */ + {0x8954, 0xe6ac9d}, /* U+6B1D */ + {0x8955, 0xe8949a}, /* U+851A */ + {0x8956, 0xe9b0bb}, /* U+9C3B */ + {0x8957, 0xe5a7a5}, /* U+59E5 */ + {0x8958, 0xe58ea9}, /* U+53A9 */ + {0x8959, 0xe6b5a6}, /* U+6D66 */ + {0x895a, 0xe7939c}, /* U+74DC */ + {0x895b, 0xe9968f}, /* U+958F */ + {0x895c, 0xe59982}, /* U+5642 */ + {0x895d, 0xe4ba91}, /* U+4E91 */ + {0x895e, 0xe9818b}, /* U+904B */ + {0x895f, 0xe99bb2}, /* U+96F2 */ + {0x8960, 0xe88d8f}, /* U+834F */ + {0x8961, 0xe9a48c}, /* U+990C */ + {0x8962, 0xe58fa1}, /* U+53E1 */ + {0x8963, 0xe596b6}, /* U+55B6 */ + {0x8964, 0xe5acb0}, /* U+5B30 */ + {0x8965, 0xe5bdb1}, /* U+5F71 */ + {0x8966, 0xe698a0}, /* U+6620 */ + {0x8967, 0xe69bb3}, /* U+66F3 */ + {0x8968, 0xe6a084}, /* U+6804 */ + {0x8969, 0xe6b0b8}, /* U+6C38 */ + {0x896a, 0xe6b3b3}, /* U+6CF3 */ + {0x896b, 0xe6b4a9}, /* U+6D29 */ + {0x896c, 0xe7919b}, /* U+745B */ + {0x896d, 0xe79b88}, /* U+76C8 */ + {0x896e, 0xe7a98e}, /* U+7A4E */ + {0x896f, 0xe9a0b4}, /* U+9834 */ + {0x8970, 0xe88bb1}, /* U+82F1 */ + {0x8971, 0xe8a19b}, /* U+885B */ + {0x8972, 0xe8a9a0}, /* U+8A60 */ + {0x8973, 0xe98bad}, /* U+92ED */ + {0x8974, 0xe6b6b2}, /* U+6DB2 */ + {0x8975, 0xe796ab}, /* U+75AB */ + {0x8976, 0xe79b8a}, /* U+76CA */ + {0x8977, 0xe9a785}, /* U+99C5 */ + {0x8978, 0xe682a6}, /* U+60A6 */ + {0x8979, 0xe8ac81}, /* U+8B01 */ + {0x897a, 0xe8b68a}, /* U+8D8A */ + {0x897b, 0xe996b2}, /* U+95B2 */ + {0x897c, 0xe6a68e}, /* U+698E */ + {0x897d, 0xe58ead}, /* U+53AD */ + {0x897e, 0xe58686}, /* U+5186 */ + {0x8980, 0xe59c92}, /* U+5712 */ + {0x8981, 0xe5a0b0}, /* U+5830 */ + {0x8982, 0xe5a584}, /* U+5944 */ + {0x8983, 0xe5aeb4}, /* U+5BB4 */ + {0x8984, 0xe5bbb6}, /* U+5EF6 */ + {0x8985, 0xe680a8}, /* U+6028 */ + {0x8986, 0xe68ea9}, /* U+63A9 */ + {0x8987, 0xe68fb4}, /* U+63F4 */ + {0x8988, 0xe6b2bf}, /* U+6CBF */ + {0x8989, 0xe6bc94}, /* U+6F14 */ + {0x898a, 0xe7828e}, /* U+708E */ + {0x898b, 0xe78494}, /* U+7114 */ + {0x898c, 0xe78599}, /* U+7159 */ + {0x898d, 0xe78795}, /* U+71D5 */ + {0x898e, 0xe78cbf}, /* U+733F */ + {0x898f, 0xe7b881}, /* U+7E01 */ + {0x8990, 0xe889b6}, /* U+8276 */ + {0x8991, 0xe88b91}, /* U+82D1 */ + {0x8992, 0xe89697}, /* U+8597 */ + {0x8993, 0xe981a0}, /* U+9060 */ + {0x8994, 0xe9899b}, /* U+925B */ + {0x8995, 0xe9b49b}, /* U+9D1B */ + {0x8996, 0xe5a1a9}, /* U+5869 */ + {0x8997, 0xe696bc}, /* U+65BC */ + {0x8998, 0xe6b19a}, /* U+6C5A */ + {0x8999, 0xe794a5}, /* U+7525 */ + {0x899a, 0xe587b9}, /* U+51F9 */ + {0x899b, 0xe5a4ae}, /* U+592E */ + {0x899c, 0xe5a5a5}, /* U+5965 */ + {0x899d, 0xe5be80}, /* U+5F80 */ + {0x899e, 0xe5bf9c}, /* U+5FDC */ + {0x899f, 0xe68abc}, /* U+62BC */ + {0x89a0, 0xe697ba}, /* U+65FA */ + {0x89a1, 0xe6a8aa}, /* U+6A2A */ + {0x89a2, 0xe6aca7}, /* U+6B27 */ + {0x89a3, 0xe6aeb4}, /* U+6BB4 */ + {0x89a4, 0xe78e8b}, /* U+738B */ + {0x89a5, 0xe7bf81}, /* U+7FC1 */ + {0x89a6, 0xe8a596}, /* U+8956 */ + {0x89a7, 0xe9b4ac}, /* U+9D2C */ + {0x89a8, 0xe9b48e}, /* U+9D0E */ + {0x89a9, 0xe9bb84}, /* U+9EC4 */ + {0x89aa, 0xe5b2a1}, /* U+5CA1 */ + {0x89ab, 0xe6b296}, /* U+6C96 */ + {0x89ac, 0xe88dbb}, /* U+837B */ + {0x89ad, 0xe58484}, /* U+5104 */ + {0x89ae, 0xe5b18b}, /* U+5C4B */ + {0x89af, 0xe686b6}, /* U+61B6 */ + {0x89b0, 0xe88786}, /* U+81C6 */ + {0x89b1, 0xe6a1b6}, /* U+6876 */ + {0x89b2, 0xe789a1}, /* U+7261 */ + {0x89b3, 0xe4b999}, /* U+4E59 */ + {0x89b4, 0xe4bfba}, /* U+4FFA */ + {0x89b5, 0xe58db8}, /* U+5378 */ + {0x89b6, 0xe681a9}, /* U+6069 */ + {0x89b7, 0xe6b8a9}, /* U+6E29 */ + {0x89b8, 0xe7a98f}, /* U+7A4F */ + {0x89b9, 0xe99fb3}, /* U+97F3 */ + {0x89ba, 0xe4b88b}, /* U+4E0B */ + {0x89bb, 0xe58c96}, /* U+5316 */ + {0x89bc, 0xe4bbae}, /* U+4EEE */ + {0x89bd, 0xe4bd95}, /* U+4F55 */ + {0x89be, 0xe4bcbd}, /* U+4F3D */ + {0x89bf, 0xe4bea1}, /* U+4FA1 */ + {0x89c0, 0xe4bdb3}, /* U+4F73 */ + {0x89c1, 0xe58aa0}, /* U+52A0 */ + {0x89c2, 0xe58faf}, /* U+53EF */ + {0x89c3, 0xe59889}, /* U+5609 */ + {0x89c4, 0xe5a48f}, /* U+590F */ + {0x89c5, 0xe5ab81}, /* U+5AC1 */ + {0x89c6, 0xe5aeb6}, /* U+5BB6 */ + {0x89c7, 0xe5afa1}, /* U+5BE1 */ + {0x89c8, 0xe7a791}, /* U+79D1 */ + {0x89c9, 0xe69a87}, /* U+6687 */ + {0x89ca, 0xe69e9c}, /* U+679C */ + {0x89cb, 0xe69eb6}, /* U+67B6 */ + {0x89cc, 0xe6ad8c}, /* U+6B4C */ + {0x89cd, 0xe6b2b3}, /* U+6CB3 */ + {0x89ce, 0xe781ab}, /* U+706B */ + {0x89cf, 0xe78f82}, /* U+73C2 */ + {0x89d0, 0xe7a68d}, /* U+798D */ + {0x89d1, 0xe7a6be}, /* U+79BE */ + {0x89d2, 0xe7a8bc}, /* U+7A3C */ + {0x89d3, 0xe7ae87}, /* U+7B87 */ + {0x89d4, 0xe88ab1}, /* U+82B1 */ + {0x89d5, 0xe88b9b}, /* U+82DB */ + {0x89d6, 0xe88c84}, /* U+8304 */ + {0x89d7, 0xe88db7}, /* U+8377 */ + {0x89d8, 0xe88faf}, /* U+83EF */ + {0x89d9, 0xe88f93}, /* U+83D3 */ + {0x89da, 0xe89da6}, /* U+8766 */ + {0x89db, 0xe8aab2}, /* U+8AB2 */ + {0x89dc, 0xe598a9}, /* U+5629 */ + {0x89dd, 0xe8b2a8}, /* U+8CA8 */ + {0x89de, 0xe8bfa6}, /* U+8FE6 */ + {0x89df, 0xe9818e}, /* U+904E */ + {0x89e0, 0xe99c9e}, /* U+971E */ + {0x89e1, 0xe89a8a}, /* U+868A */ + {0x89e2, 0xe4bf84}, /* U+4FC4 */ + {0x89e3, 0xe5b3a8}, /* U+5CE8 */ + {0x89e4, 0xe68891}, /* U+6211 */ + {0x89e5, 0xe78999}, /* U+7259 */ + {0x89e6, 0xe794bb}, /* U+753B */ + {0x89e7, 0xe887a5}, /* U+81E5 */ + {0x89e8, 0xe88abd}, /* U+82BD */ + {0x89e9, 0xe89bbe}, /* U+86FE */ + {0x89ea, 0xe8b380}, /* U+8CC0 */ + {0x89eb, 0xe99b85}, /* U+96C5 */ + {0x89ec, 0xe9a493}, /* U+9913 */ + {0x89ed, 0xe9a795}, /* U+99D5 */ + {0x89ee, 0xe4bb8b}, /* U+4ECB */ + {0x89ef, 0xe4bc9a}, /* U+4F1A */ + {0x89f0, 0xe8a7a3}, /* U+89E3 */ + {0x89f1, 0xe59b9e}, /* U+56DE */ + {0x89f2, 0xe5a18a}, /* U+584A */ + {0x89f3, 0xe5a38a}, /* U+58CA */ + {0x89f4, 0xe5bbbb}, /* U+5EFB */ + {0x89f5, 0xe5bfab}, /* U+5FEB */ + {0x89f6, 0xe680aa}, /* U+602A */ + {0x89f7, 0xe68294}, /* U+6094 */ + {0x89f8, 0xe681a2}, /* U+6062 */ + {0x89f9, 0xe68790}, /* U+61D0 */ + {0x89fa, 0xe68892}, /* U+6212 */ + {0x89fb, 0xe68b90}, /* U+62D0 */ + {0x89fc, 0xe694b9}, /* U+6539 */ + {0x8a40, 0xe9ad81}, /* U+9B41 */ + {0x8a41, 0xe699a6}, /* U+6666 */ + {0x8a42, 0xe6a2b0}, /* U+68B0 */ + {0x8a43, 0xe6b5b7}, /* U+6D77 */ + {0x8a44, 0xe781b0}, /* U+7070 */ + {0x8a45, 0xe7958c}, /* U+754C */ + {0x8a46, 0xe79a86}, /* U+7686 */ + {0x8a47, 0xe7b5b5}, /* U+7D75 */ + {0x8a48, 0xe88aa5}, /* U+82A5 */ + {0x8a49, 0xe89fb9}, /* U+87F9 */ + {0x8a4a, 0xe9968b}, /* U+958B */ + {0x8a4b, 0xe99a8e}, /* U+968E */ + {0x8a4c, 0xe8b29d}, /* U+8C9D */ + {0x8a4d, 0xe587b1}, /* U+51F1 */ + {0x8a4e, 0xe58abe}, /* U+52BE */ + {0x8a4f, 0xe5a496}, /* U+5916 */ + {0x8a50, 0xe592b3}, /* U+54B3 */ + {0x8a51, 0xe5aeb3}, /* U+5BB3 */ + {0x8a52, 0xe5b496}, /* U+5D16 */ + {0x8a53, 0xe685a8}, /* U+6168 */ + {0x8a54, 0xe6a682}, /* U+6982 */ + {0x8a55, 0xe6b6af}, /* U+6DAF */ + {0x8a56, 0xe7a28d}, /* U+788D */ + {0x8a57, 0xe8938b}, /* U+84CB */ + {0x8a58, 0xe8a197}, /* U+8857 */ + {0x8a59, 0xe8a9b2}, /* U+8A72 */ + {0x8a5a, 0xe98ea7}, /* U+93A7 */ + {0x8a5b, 0xe9aab8}, /* U+9AB8 */ + {0x8a5c, 0xe6b5ac}, /* U+6D6C */ + {0x8a5d, 0xe9a6a8}, /* U+99A8 */ + {0x8a5e, 0xe89b99}, /* U+86D9 */ + {0x8a5f, 0xe59ea3}, /* U+57A3 */ + {0x8a60, 0xe69fbf}, /* U+67FF */ + {0x8a61, 0xe89b8e}, /* U+86CE */ + {0x8a62, 0xe9888e}, /* U+920E */ + {0x8a63, 0xe58a83}, /* U+5283 */ + {0x8a64, 0xe59a87}, /* U+5687 */ + {0x8a65, 0xe59084}, /* U+5404 */ + {0x8a66, 0xe5bb93}, /* U+5ED3 */ + {0x8a67, 0xe68ba1}, /* U+62E1 */ + {0x8a68, 0xe692b9}, /* U+64B9 */ + {0x8a69, 0xe6a0bc}, /* U+683C */ + {0x8a6a, 0xe6a0b8}, /* U+6838 */ + {0x8a6b, 0xe6aebb}, /* U+6BBB */ + {0x8a6c, 0xe78db2}, /* U+7372 */ + {0x8a6d, 0xe7a2ba}, /* U+78BA */ + {0x8a6e, 0xe7a9ab}, /* U+7A6B */ + {0x8a6f, 0xe8a69a}, /* U+899A */ + {0x8a70, 0xe8a792}, /* U+89D2 */ + {0x8a71, 0xe8b5ab}, /* U+8D6B */ + {0x8a72, 0xe8bc83}, /* U+8F03 */ + {0x8a73, 0xe983ad}, /* U+90ED */ + {0x8a74, 0xe996a3}, /* U+95A3 */ + {0x8a75, 0xe99a94}, /* U+9694 */ + {0x8a76, 0xe99da9}, /* U+9769 */ + {0x8a77, 0xe5ada6}, /* U+5B66 */ + {0x8a78, 0xe5b2b3}, /* U+5CB3 */ + {0x8a79, 0xe6a5bd}, /* U+697D */ + {0x8a7a, 0xe9a18d}, /* U+984D */ + {0x8a7b, 0xe9a18e}, /* U+984E */ + {0x8a7c, 0xe68e9b}, /* U+639B */ + {0x8a7d, 0xe7aca0}, /* U+7B20 */ + {0x8a7e, 0xe6a8ab}, /* U+6A2B */ + {0x8a80, 0xe6a9bf}, /* U+6A7F */ + {0x8a81, 0xe6a2b6}, /* U+68B6 */ + {0x8a82, 0xe9b08d}, /* U+9C0D */ + {0x8a83, 0xe6bd9f}, /* U+6F5F */ + {0x8a84, 0xe589b2}, /* U+5272 */ + {0x8a85, 0xe5969d}, /* U+559D */ + {0x8a86, 0xe681b0}, /* U+6070 */ + {0x8a87, 0xe68bac}, /* U+62EC */ + {0x8a88, 0xe6b4bb}, /* U+6D3B */ + {0x8a89, 0xe6b887}, /* U+6E07 */ + {0x8a8a, 0xe6bb91}, /* U+6ED1 */ + {0x8a8b, 0xe8919b}, /* U+845B */ + {0x8a8c, 0xe8a490}, /* U+8910 */ + {0x8a8d, 0xe8bd84}, /* U+8F44 */ + {0x8a8e, 0xe4b894}, /* U+4E14 */ + {0x8a8f, 0xe9b0b9}, /* U+9C39 */ + {0x8a90, 0xe58fb6}, /* U+53F6 */ + {0x8a91, 0xe6a49b}, /* U+691B */ + {0x8a92, 0xe6a8ba}, /* U+6A3A */ + {0x8a93, 0xe99e84}, /* U+9784 */ + {0x8a94, 0xe6a0aa}, /* U+682A */ + {0x8a95, 0xe5859c}, /* U+515C */ + {0x8a96, 0xe7ab83}, /* U+7AC3 */ + {0x8a97, 0xe892b2}, /* U+84B2 */ + {0x8a98, 0xe9879c}, /* U+91DC */ + {0x8a99, 0xe98e8c}, /* U+938C */ + {0x8a9a, 0xe5999b}, /* U+565B */ + {0x8a9b, 0xe9b4a8}, /* U+9D28 */ + {0x8a9c, 0xe6a0a2}, /* U+6822 */ + {0x8a9d, 0xe88c85}, /* U+8305 */ + {0x8a9e, 0xe890b1}, /* U+8431 */ + {0x8a9f, 0xe7b2a5}, /* U+7CA5 */ + {0x8aa0, 0xe58888}, /* U+5208 */ + {0x8aa1, 0xe88b85}, /* U+82C5 */ + {0x8aa2, 0xe793a6}, /* U+74E6 */ + {0x8aa3, 0xe4b9be}, /* U+4E7E */ + {0x8aa4, 0xe4be83}, /* U+4F83 */ + {0x8aa5, 0xe586a0}, /* U+51A0 */ + {0x8aa6, 0xe5af92}, /* U+5BD2 */ + {0x8aa7, 0xe5888a}, /* U+520A */ + {0x8aa8, 0xe58b98}, /* U+52D8 */ + {0x8aa9, 0xe58ba7}, /* U+52E7 */ + {0x8aaa, 0xe5b7bb}, /* U+5DFB */ + {0x8aab, 0xe5969a}, /* U+559A */ + {0x8aac, 0xe5a0aa}, /* U+582A */ + {0x8aad, 0xe5a7a6}, /* U+59E6 */ + {0x8aae, 0xe5ae8c}, /* U+5B8C */ + {0x8aaf, 0xe5ae98}, /* U+5B98 */ + {0x8ab0, 0xe5af9b}, /* U+5BDB */ + {0x8ab1, 0xe5b9b2}, /* U+5E72 */ + {0x8ab2, 0xe5b9b9}, /* U+5E79 */ + {0x8ab3, 0xe682a3}, /* U+60A3 */ + {0x8ab4, 0xe6849f}, /* U+611F */ + {0x8ab5, 0xe685a3}, /* U+6163 */ + {0x8ab6, 0xe686be}, /* U+61BE */ + {0x8ab7, 0xe68f9b}, /* U+63DB */ + {0x8ab8, 0xe695a2}, /* U+6562 */ + {0x8ab9, 0xe69f91}, /* U+67D1 */ + {0x8aba, 0xe6a193}, /* U+6853 */ + {0x8abb, 0xe6a3ba}, /* U+68FA */ + {0x8abc, 0xe6acbe}, /* U+6B3E */ + {0x8abd, 0xe6ad93}, /* U+6B53 */ + {0x8abe, 0xe6b197}, /* U+6C57 */ + {0x8abf, 0xe6bca2}, /* U+6F22 */ + {0x8ac0, 0xe6be97}, /* U+6F97 */ + {0x8ac1, 0xe6bd85}, /* U+6F45 */ + {0x8ac2, 0xe792b0}, /* U+74B0 */ + {0x8ac3, 0xe79498}, /* U+7518 */ + {0x8ac4, 0xe79ba3}, /* U+76E3 */ + {0x8ac5, 0xe79c8b}, /* U+770B */ + {0x8ac6, 0xe7abbf}, /* U+7AFF */ + {0x8ac7, 0xe7aea1}, /* U+7BA1 */ + {0x8ac8, 0xe7b0a1}, /* U+7C21 */ + {0x8ac9, 0xe7b7a9}, /* U+7DE9 */ + {0x8aca, 0xe7bcb6}, /* U+7F36 */ + {0x8acb, 0xe7bfb0}, /* U+7FF0 */ + {0x8acc, 0xe8829d}, /* U+809D */ + {0x8acd, 0xe889a6}, /* U+8266 */ + {0x8ace, 0xe88e9e}, /* U+839E */ + {0x8acf, 0xe8a6b3}, /* U+89B3 */ + {0x8ad0, 0xe8ab8c}, /* U+8ACC */ + {0x8ad1, 0xe8b2ab}, /* U+8CAB */ + {0x8ad2, 0xe98284}, /* U+9084 */ + {0x8ad3, 0xe99191}, /* U+9451 */ + {0x8ad4, 0xe99693}, /* U+9593 */ + {0x8ad5, 0xe99691}, /* U+9591 */ + {0x8ad6, 0xe996a2}, /* U+95A2 */ + {0x8ad7, 0xe999a5}, /* U+9665 */ + {0x8ad8, 0xe99f93}, /* U+97D3 */ + {0x8ad9, 0xe9a4a8}, /* U+9928 */ + {0x8ada, 0xe88898}, /* U+8218 */ + {0x8adb, 0xe4b8b8}, /* U+4E38 */ + {0x8adc, 0xe590ab}, /* U+542B */ + {0x8add, 0xe5b2b8}, /* U+5CB8 */ + {0x8ade, 0xe5b78c}, /* U+5DCC */ + {0x8adf, 0xe78ea9}, /* U+73A9 */ + {0x8ae0, 0xe7998c}, /* U+764C */ + {0x8ae1, 0xe79cbc}, /* U+773C */ + {0x8ae2, 0xe5b2a9}, /* U+5CA9 */ + {0x8ae3, 0xe7bfab}, /* U+7FEB */ + {0x8ae4, 0xe8b48b}, /* U+8D0B */ + {0x8ae5, 0xe99b81}, /* U+96C1 */ + {0x8ae6, 0xe9a091}, /* U+9811 */ + {0x8ae7, 0xe9a194}, /* U+9854 */ + {0x8ae8, 0xe9a198}, /* U+9858 */ + {0x8ae9, 0xe4bc81}, /* U+4F01 */ + {0x8aea, 0xe4bc8e}, /* U+4F0E */ + {0x8aeb, 0xe58db1}, /* U+5371 */ + {0x8aec, 0xe5969c}, /* U+559C */ + {0x8aed, 0xe599a8}, /* U+5668 */ + {0x8aee, 0xe59fba}, /* U+57FA */ + {0x8aef, 0xe5a587}, /* U+5947 */ + {0x8af0, 0xe5ac89}, /* U+5B09 */ + {0x8af1, 0xe5af84}, /* U+5BC4 */ + {0x8af2, 0xe5b290}, /* U+5C90 */ + {0x8af3, 0xe5b88c}, /* U+5E0C */ + {0x8af4, 0xe5b9be}, /* U+5E7E */ + {0x8af5, 0xe5bf8c}, /* U+5FCC */ + {0x8af6, 0xe68fae}, /* U+63EE */ + {0x8af7, 0xe69cba}, /* U+673A */ + {0x8af8, 0xe69797}, /* U+65D7 */ + {0x8af9, 0xe697a2}, /* U+65E2 */ + {0x8afa, 0xe69c9f}, /* U+671F */ + {0x8afb, 0xe6a38b}, /* U+68CB */ + {0x8afc, 0xe6a384}, /* U+68C4 */ + {0x8b40, 0xe6a99f}, /* U+6A5F */ + {0x8b41, 0xe5b8b0}, /* U+5E30 */ + {0x8b42, 0xe6af85}, /* U+6BC5 */ + {0x8b43, 0xe6b097}, /* U+6C17 */ + {0x8b44, 0xe6b1bd}, /* U+6C7D */ + {0x8b45, 0xe795bf}, /* U+757F */ + {0x8b46, 0xe7a588}, /* U+7948 */ + {0x8b47, 0xe5ada3}, /* U+5B63 */ + {0x8b48, 0xe7a880}, /* U+7A00 */ + {0x8b49, 0xe7b480}, /* U+7D00 */ + {0x8b4a, 0xe5bebd}, /* U+5FBD */ + {0x8b4b, 0xe8a68f}, /* U+898F */ + {0x8b4c, 0xe8a898}, /* U+8A18 */ + {0x8b4d, 0xe8b2b4}, /* U+8CB4 */ + {0x8b4e, 0xe8b5b7}, /* U+8D77 */ + {0x8b4f, 0xe8bb8c}, /* U+8ECC */ + {0x8b50, 0xe8bc9d}, /* U+8F1D */ + {0x8b51, 0xe9a3a2}, /* U+98E2 */ + {0x8b52, 0xe9a88e}, /* U+9A0E */ + {0x8b53, 0xe9acbc}, /* U+9B3C */ + {0x8b54, 0xe4ba80}, /* U+4E80 */ + {0x8b55, 0xe581bd}, /* U+507D */ + {0x8b56, 0xe58480}, /* U+5100 */ + {0x8b57, 0xe5a693}, /* U+5993 */ + {0x8b58, 0xe5ae9c}, /* U+5B9C */ + {0x8b59, 0xe688af}, /* U+622F */ + {0x8b5a, 0xe68a80}, /* U+6280 */ + {0x8b5b, 0xe693ac}, /* U+64EC */ + {0x8b5c, 0xe6acba}, /* U+6B3A */ + {0x8b5d, 0xe78aa0}, /* U+72A0 */ + {0x8b5e, 0xe79691}, /* U+7591 */ + {0x8b5f, 0xe7a587}, /* U+7947 */ + {0x8b60, 0xe7bea9}, /* U+7FA9 */ + {0x8b61, 0xe89fbb}, /* U+87FB */ + {0x8b62, 0xe8aabc}, /* U+8ABC */ + {0x8b63, 0xe8adb0}, /* U+8B70 */ + {0x8b64, 0xe68eac}, /* U+63AC */ + {0x8b65, 0xe88f8a}, /* U+83CA */ + {0x8b66, 0xe99ea0}, /* U+97A0 */ + {0x8b67, 0xe59089}, /* U+5409 */ + {0x8b68, 0xe59083}, /* U+5403 */ + {0x8b69, 0xe596ab}, /* U+55AB */ + {0x8b6a, 0xe6a194}, /* U+6854 */ + {0x8b6b, 0xe6a998}, /* U+6A58 */ + {0x8b6c, 0xe8a9b0}, /* U+8A70 */ + {0x8b6d, 0xe7a0a7}, /* U+7827 */ + {0x8b6e, 0xe69db5}, /* U+6775 */ + {0x8b6f, 0xe9bb8d}, /* U+9ECD */ + {0x8b70, 0xe58db4}, /* U+5374 */ + {0x8b71, 0xe5aea2}, /* U+5BA2 */ + {0x8b72, 0xe8849a}, /* U+811A */ + {0x8b73, 0xe89990}, /* U+8650 */ + {0x8b74, 0xe98086}, /* U+9006 */ + {0x8b75, 0xe4b898}, /* U+4E18 */ + {0x8b76, 0xe4b985}, /* U+4E45 */ + {0x8b77, 0xe4bb87}, /* U+4EC7 */ + {0x8b78, 0xe4bc91}, /* U+4F11 */ + {0x8b79, 0xe58f8a}, /* U+53CA */ + {0x8b7a, 0xe590b8}, /* U+5438 */ + {0x8b7b, 0xe5aeae}, /* U+5BAE */ + {0x8b7c, 0xe5bc93}, /* U+5F13 */ + {0x8b7d, 0xe680a5}, /* U+6025 */ + {0x8b7e, 0xe69591}, /* U+6551 */ + {0x8b80, 0xe69cbd}, /* U+673D */ + {0x8b81, 0xe6b182}, /* U+6C42 */ + {0x8b82, 0xe6b1b2}, /* U+6C72 */ + {0x8b83, 0xe6b3a3}, /* U+6CE3 */ + {0x8b84, 0xe781b8}, /* U+7078 */ + {0x8b85, 0xe79083}, /* U+7403 */ + {0x8b86, 0xe7a9b6}, /* U+7A76 */ + {0x8b87, 0xe7aaae}, /* U+7AAE */ + {0x8b88, 0xe7ac88}, /* U+7B08 */ + {0x8b89, 0xe7b49a}, /* U+7D1A */ + {0x8b8a, 0xe7b3be}, /* U+7CFE */ + {0x8b8b, 0xe7b5a6}, /* U+7D66 */ + {0x8b8c, 0xe697a7}, /* U+65E7 */ + {0x8b8d, 0xe7899b}, /* U+725B */ + {0x8b8e, 0xe58ebb}, /* U+53BB */ + {0x8b8f, 0xe5b185}, /* U+5C45 */ + {0x8b90, 0xe5b7a8}, /* U+5DE8 */ + {0x8b91, 0xe68b92}, /* U+62D2 */ + {0x8b92, 0xe68ba0}, /* U+62E0 */ + {0x8b93, 0xe68c99}, /* U+6319 */ + {0x8b94, 0xe6b8a0}, /* U+6E20 */ + {0x8b95, 0xe8999a}, /* U+865A */ + {0x8b96, 0xe8a8b1}, /* U+8A31 */ + {0x8b97, 0xe8b79d}, /* U+8DDD */ + {0x8b98, 0xe98bb8}, /* U+92F8 */ + {0x8b99, 0xe6bc81}, /* U+6F01 */ + {0x8b9a, 0xe7a6a6}, /* U+79A6 */ + {0x8b9b, 0xe9ad9a}, /* U+9B5A */ + {0x8b9c, 0xe4baa8}, /* U+4EA8 */ + {0x8b9d, 0xe4baab}, /* U+4EAB */ + {0x8b9e, 0xe4baac}, /* U+4EAC */ + {0x8b9f, 0xe4be9b}, /* U+4F9B */ + {0x8ba0, 0xe4bea0}, /* U+4FA0 */ + {0x8ba1, 0xe58391}, /* U+50D1 */ + {0x8ba2, 0xe58587}, /* U+5147 */ + {0x8ba3, 0xe7abb6}, /* U+7AF6 */ + {0x8ba4, 0xe585b1}, /* U+5171 */ + {0x8ba5, 0xe587b6}, /* U+51F6 */ + {0x8ba6, 0xe58d94}, /* U+5354 */ + {0x8ba7, 0xe58ca1}, /* U+5321 */ + {0x8ba8, 0xe58dbf}, /* U+537F */ + {0x8ba9, 0xe58fab}, /* U+53EB */ + {0x8baa, 0xe596ac}, /* U+55AC */ + {0x8bab, 0xe5a283}, /* U+5883 */ + {0x8bac, 0xe5b3a1}, /* U+5CE1 */ + {0x8bad, 0xe5bcb7}, /* U+5F37 */ + {0x8bae, 0xe5bd8a}, /* U+5F4A */ + {0x8baf, 0xe680af}, /* U+602F */ + {0x8bb0, 0xe68190}, /* U+6050 */ + {0x8bb1, 0xe681ad}, /* U+606D */ + {0x8bb2, 0xe68c9f}, /* U+631F */ + {0x8bb3, 0xe69599}, /* U+6559 */ + {0x8bb4, 0xe6a98b}, /* U+6A4B */ + {0x8bb5, 0xe6b381}, /* U+6CC1 */ + {0x8bb6, 0xe78b82}, /* U+72C2 */ + {0x8bb7, 0xe78bad}, /* U+72ED */ + {0x8bb8, 0xe79faf}, /* U+77EF */ + {0x8bb9, 0xe883b8}, /* U+80F8 */ + {0x8bba, 0xe88485}, /* U+8105 */ + {0x8bbb, 0xe88888}, /* U+8208 */ + {0x8bbc, 0xe8958e}, /* U+854E */ + {0x8bbd, 0xe983b7}, /* U+90F7 */ + {0x8bbe, 0xe98fa1}, /* U+93E1 */ + {0x8bbf, 0xe99fbf}, /* U+97FF */ + {0x8bc0, 0xe9a597}, /* U+9957 */ + {0x8bc1, 0xe9a99a}, /* U+9A5A */ + {0x8bc2, 0xe4bbb0}, /* U+4EF0 */ + {0x8bc3, 0xe5879d}, /* U+51DD */ + {0x8bc4, 0xe5b0ad}, /* U+5C2D */ + {0x8bc5, 0xe69a81}, /* U+6681 */ + {0x8bc6, 0xe6a5ad}, /* U+696D */ + {0x8bc7, 0xe5b180}, /* U+5C40 */ + {0x8bc8, 0xe69bb2}, /* U+66F2 */ + {0x8bc9, 0xe6a5b5}, /* U+6975 */ + {0x8bca, 0xe78e89}, /* U+7389 */ + {0x8bcb, 0xe6a190}, /* U+6850 */ + {0x8bcc, 0xe7b281}, /* U+7C81 */ + {0x8bcd, 0xe58385}, /* U+50C5 */ + {0x8bce, 0xe58ba4}, /* U+52E4 */ + {0x8bcf, 0xe59d87}, /* U+5747 */ + {0x8bd0, 0xe5b7be}, /* U+5DFE */ + {0x8bd1, 0xe98ca6}, /* U+9326 */ + {0x8bd2, 0xe696a4}, /* U+65A4 */ + {0x8bd3, 0xe6aca3}, /* U+6B23 */ + {0x8bd4, 0xe6acbd}, /* U+6B3D */ + {0x8bd5, 0xe790b4}, /* U+7434 */ + {0x8bd6, 0xe7a681}, /* U+7981 */ + {0x8bd7, 0xe7a6bd}, /* U+79BD */ + {0x8bd8, 0xe7ad8b}, /* U+7B4B */ + {0x8bd9, 0xe7b78a}, /* U+7DCA */ + {0x8bda, 0xe88ab9}, /* U+82B9 */ + {0x8bdb, 0xe88f8c}, /* U+83CC */ + {0x8bdc, 0xe8a1bf}, /* U+887F */ + {0x8bdd, 0xe8a59f}, /* U+895F */ + {0x8bde, 0xe8acb9}, /* U+8B39 */ + {0x8bdf, 0xe8bf91}, /* U+8FD1 */ + {0x8be0, 0xe98791}, /* U+91D1 */ + {0x8be1, 0xe5909f}, /* U+541F */ + {0x8be2, 0xe98a80}, /* U+9280 */ + {0x8be3, 0xe4b99d}, /* U+4E5D */ + {0x8be4, 0xe580b6}, /* U+5036 */ + {0x8be5, 0xe58fa5}, /* U+53E5 */ + {0x8be6, 0xe58cba}, /* U+533A */ + {0x8be7, 0xe78b97}, /* U+72D7 */ + {0x8be8, 0xe78e96}, /* U+7396 */ + {0x8be9, 0xe79fa9}, /* U+77E9 */ + {0x8bea, 0xe88ba6}, /* U+82E6 */ + {0x8beb, 0xe8baaf}, /* U+8EAF */ + {0x8bec, 0xe9a786}, /* U+99C6 */ + {0x8bed, 0xe9a788}, /* U+99C8 */ + {0x8bee, 0xe9a792}, /* U+99D2 */ + {0x8bef, 0xe585b7}, /* U+5177 */ + {0x8bf0, 0xe6849a}, /* U+611A */ + {0x8bf1, 0xe8999e}, /* U+865E */ + {0x8bf2, 0xe596b0}, /* U+55B0 */ + {0x8bf3, 0xe7a9ba}, /* U+7A7A */ + {0x8bf4, 0xe581b6}, /* U+5076 */ + {0x8bf5, 0xe5af93}, /* U+5BD3 */ + {0x8bf6, 0xe98187}, /* U+9047 */ + {0x8bf7, 0xe99a85}, /* U+9685 */ + {0x8bf8, 0xe4b8b2}, /* U+4E32 */ + {0x8bf9, 0xe6ab9b}, /* U+6ADB */ + {0x8bfa, 0xe987a7}, /* U+91E7 */ + {0x8bfb, 0xe5b191}, /* U+5C51 */ + {0x8bfc, 0xe5b188}, /* U+5C48 */ + {0x8c40, 0xe68e98}, /* U+6398 */ + {0x8c41, 0xe7aa9f}, /* U+7A9F */ + {0x8c42, 0xe6b293}, /* U+6C93 */ + {0x8c43, 0xe99db4}, /* U+9774 */ + {0x8c44, 0xe8bda1}, /* U+8F61 */ + {0x8c45, 0xe7aaaa}, /* U+7AAA */ + {0x8c46, 0xe7868a}, /* U+718A */ + {0x8c47, 0xe99a88}, /* U+9688 */ + {0x8c48, 0xe7b282}, /* U+7C82 */ + {0x8c49, 0xe6a097}, /* U+6817 */ + {0x8c4a, 0xe7b9b0}, /* U+7E70 */ + {0x8c4b, 0xe6a191}, /* U+6851 */ + {0x8c4c, 0xe98dac}, /* U+936C */ + {0x8c4d, 0xe58bb2}, /* U+52F2 */ + {0x8c4e, 0xe5909b}, /* U+541B */ + {0x8c4f, 0xe896ab}, /* U+85AB */ + {0x8c50, 0xe8a893}, /* U+8A13 */ + {0x8c51, 0xe7bea4}, /* U+7FA4 */ + {0x8c52, 0xe8bb8d}, /* U+8ECD */ + {0x8c53, 0xe983a1}, /* U+90E1 */ + {0x8c54, 0xe58da6}, /* U+5366 */ + {0x8c55, 0xe8a288}, /* U+8888 */ + {0x8c56, 0xe7a581}, /* U+7941 */ + {0x8c57, 0xe4bf82}, /* U+4FC2 */ + {0x8c58, 0xe582be}, /* U+50BE */ + {0x8c59, 0xe58891}, /* U+5211 */ + {0x8c5a, 0xe58584}, /* U+5144 */ + {0x8c5b, 0xe59593}, /* U+5553 */ + {0x8c5c, 0xe59cad}, /* U+572D */ + {0x8c5d, 0xe78faa}, /* U+73EA */ + {0x8c5e, 0xe59e8b}, /* U+578B */ + {0x8c5f, 0xe5a591}, /* U+5951 */ + {0x8c60, 0xe5bda2}, /* U+5F62 */ + {0x8c61, 0xe5be84}, /* U+5F84 */ + {0x8c62, 0xe681b5}, /* U+6075 */ + {0x8c63, 0xe685b6}, /* U+6176 */ + {0x8c64, 0xe685a7}, /* U+6167 */ + {0x8c65, 0xe686a9}, /* U+61A9 */ + {0x8c66, 0xe68eb2}, /* U+63B2 */ + {0x8c67, 0xe690ba}, /* U+643A */ + {0x8c68, 0xe695ac}, /* U+656C */ + {0x8c69, 0xe699af}, /* U+666F */ + {0x8c6a, 0xe6a182}, /* U+6842 */ + {0x8c6b, 0xe6b893}, /* U+6E13 */ + {0x8c6c, 0xe795a6}, /* U+7566 */ + {0x8c6d, 0xe7a8bd}, /* U+7A3D */ + {0x8c6e, 0xe7b3bb}, /* U+7CFB */ + {0x8c6f, 0xe7b58c}, /* U+7D4C */ + {0x8c70, 0xe7b699}, /* U+7D99 */ + {0x8c71, 0xe7b98b}, /* U+7E4B */ + {0x8c72, 0xe7bdab}, /* U+7F6B */ + {0x8c73, 0xe88c8e}, /* U+830E */ + {0x8c74, 0xe88d8a}, /* U+834A */ + {0x8c75, 0xe89b8d}, /* U+86CD */ + {0x8c76, 0xe8a888}, /* U+8A08 */ + {0x8c77, 0xe8a9a3}, /* U+8A63 */ + {0x8c78, 0xe8ada6}, /* U+8B66 */ + {0x8c79, 0xe8bbbd}, /* U+8EFD */ + {0x8c7a, 0xe9a09a}, /* U+981A */ + {0x8c7b, 0xe9b68f}, /* U+9D8F */ + {0x8c7c, 0xe88ab8}, /* U+82B8 */ + {0x8c7d, 0xe8bf8e}, /* U+8FCE */ + {0x8c7e, 0xe9afa8}, /* U+9BE8 */ + {0x8c80, 0xe58a87}, /* U+5287 */ + {0x8c81, 0xe6889f}, /* U+621F */ + {0x8c82, 0xe69283}, /* U+6483 */ + {0x8c83, 0xe6bf80}, /* U+6FC0 */ + {0x8c84, 0xe99a99}, /* U+9699 */ + {0x8c85, 0xe6a181}, /* U+6841 */ + {0x8c86, 0xe58291}, /* U+5091 */ + {0x8c87, 0xe6aca0}, /* U+6B20 */ + {0x8c88, 0xe6b1ba}, /* U+6C7A */ + {0x8c89, 0xe6bd94}, /* U+6F54 */ + {0x8c8a, 0xe7a9b4}, /* U+7A74 */ + {0x8c8b, 0xe7b590}, /* U+7D50 */ + {0x8c8c, 0xe8a180}, /* U+8840 */ + {0x8c8d, 0xe8a8a3}, /* U+8A23 */ + {0x8c8e, 0xe69c88}, /* U+6708 */ + {0x8c8f, 0xe4bbb6}, /* U+4EF6 */ + {0x8c90, 0xe580b9}, /* U+5039 */ + {0x8c91, 0xe580a6}, /* U+5026 */ + {0x8c92, 0xe581a5}, /* U+5065 */ + {0x8c93, 0xe585bc}, /* U+517C */ + {0x8c94, 0xe588b8}, /* U+5238 */ + {0x8c95, 0xe589a3}, /* U+5263 */ + {0x8c96, 0xe596a7}, /* U+55A7 */ + {0x8c97, 0xe59c8f}, /* U+570F */ + {0x8c98, 0xe5a085}, /* U+5805 */ + {0x8c99, 0xe5ab8c}, /* U+5ACC */ + {0x8c9a, 0xe5bbba}, /* U+5EFA */ + {0x8c9b, 0xe686b2}, /* U+61B2 */ + {0x8c9c, 0xe687b8}, /* U+61F8 */ + {0x8c9d, 0xe68bb3}, /* U+62F3 */ + {0x8c9e, 0xe68db2}, /* U+6372 */ + {0x8c9f, 0xe6a49c}, /* U+691C */ + {0x8ca0, 0xe6a8a9}, /* U+6A29 */ + {0x8ca1, 0xe789bd}, /* U+727D */ + {0x8ca2, 0xe78aac}, /* U+72AC */ + {0x8ca3, 0xe78cae}, /* U+732E */ + {0x8ca4, 0xe7a094}, /* U+7814 */ + {0x8ca5, 0xe7a1af}, /* U+786F */ + {0x8ca6, 0xe7b5b9}, /* U+7D79 */ + {0x8ca7, 0xe79c8c}, /* U+770C */ + {0x8ca8, 0xe882a9}, /* U+80A9 */ + {0x8ca9, 0xe8a68b}, /* U+898B */ + {0x8caa, 0xe8ac99}, /* U+8B19 */ + {0x8cab, 0xe8b3a2}, /* U+8CE2 */ + {0x8cac, 0xe8bb92}, /* U+8ED2 */ + {0x8cad, 0xe981a3}, /* U+9063 */ + {0x8cae, 0xe98db5}, /* U+9375 */ + {0x8caf, 0xe999ba}, /* U+967A */ + {0x8cb0, 0xe9a195}, /* U+9855 */ + {0x8cb1, 0xe9a893}, /* U+9A13 */ + {0x8cb2, 0xe9b9b8}, /* U+9E78 */ + {0x8cb3, 0xe58583}, /* U+5143 */ + {0x8cb4, 0xe58e9f}, /* U+539F */ + {0x8cb5, 0xe58eb3}, /* U+53B3 */ + {0x8cb6, 0xe5b9bb}, /* U+5E7B */ + {0x8cb7, 0xe5bca6}, /* U+5F26 */ + {0x8cb8, 0xe6b89b}, /* U+6E1B */ + {0x8cb9, 0xe6ba90}, /* U+6E90 */ + {0x8cba, 0xe78e84}, /* U+7384 */ + {0x8cbb, 0xe78fbe}, /* U+73FE */ + {0x8cbc, 0xe7b583}, /* U+7D43 */ + {0x8cbd, 0xe888b7}, /* U+8237 */ + {0x8cbe, 0xe8a880}, /* U+8A00 */ + {0x8cbf, 0xe8abba}, /* U+8AFA */ + {0x8cc0, 0xe99990}, /* U+9650 */ + {0x8cc1, 0xe4b98e}, /* U+4E4E */ + {0x8cc2, 0xe5808b}, /* U+500B */ + {0x8cc3, 0xe58fa4}, /* U+53E4 */ + {0x8cc4, 0xe591bc}, /* U+547C */ + {0x8cc5, 0xe59bba}, /* U+56FA */ + {0x8cc6, 0xe5a791}, /* U+59D1 */ + {0x8cc7, 0xe5ada4}, /* U+5B64 */ + {0x8cc8, 0xe5b7b1}, /* U+5DF1 */ + {0x8cc9, 0xe5baab}, /* U+5EAB */ + {0x8cca, 0xe5bca7}, /* U+5F27 */ + {0x8ccb, 0xe688b8}, /* U+6238 */ + {0x8ccc, 0xe69585}, /* U+6545 */ + {0x8ccd, 0xe69eaf}, /* U+67AF */ + {0x8cce, 0xe6b996}, /* U+6E56 */ + {0x8ccf, 0xe78b90}, /* U+72D0 */ + {0x8cd0, 0xe7b38a}, /* U+7CCA */ + {0x8cd1, 0xe8a2b4}, /* U+88B4 */ + {0x8cd2, 0xe882a1}, /* U+80A1 */ + {0x8cd3, 0xe883a1}, /* U+80E1 */ + {0x8cd4, 0xe88fb0}, /* U+83F0 */ + {0x8cd5, 0xe8998e}, /* U+864E */ + {0x8cd6, 0xe8aa87}, /* U+8A87 */ + {0x8cd7, 0xe8b7a8}, /* U+8DE8 */ + {0x8cd8, 0xe988b7}, /* U+9237 */ + {0x8cd9, 0xe99b87}, /* U+96C7 */ + {0x8cda, 0xe9a1a7}, /* U+9867 */ + {0x8cdb, 0xe9bc93}, /* U+9F13 */ + {0x8cdc, 0xe4ba94}, /* U+4E94 */ + {0x8cdd, 0xe4ba92}, /* U+4E92 */ + {0x8cde, 0xe4bc8d}, /* U+4F0D */ + {0x8cdf, 0xe58d88}, /* U+5348 */ + {0x8ce0, 0xe59189}, /* U+5449 */ + {0x8ce1, 0xe590be}, /* U+543E */ + {0x8ce2, 0xe5a8af}, /* U+5A2F */ + {0x8ce3, 0xe5be8c}, /* U+5F8C */ + {0x8ce4, 0xe5bea1}, /* U+5FA1 */ + {0x8ce5, 0xe6829f}, /* U+609F */ + {0x8ce6, 0xe6a2a7}, /* U+68A7 */ + {0x8ce7, 0xe6aa8e}, /* U+6A8E */ + {0x8ce8, 0xe7919a}, /* U+745A */ + {0x8ce9, 0xe7a281}, /* U+7881 */ + {0x8cea, 0xe8aa9e}, /* U+8A9E */ + {0x8ceb, 0xe8aaa4}, /* U+8AA4 */ + {0x8cec, 0xe8adb7}, /* U+8B77 */ + {0x8ced, 0xe98690}, /* U+9190 */ + {0x8cee, 0xe4b99e}, /* U+4E5E */ + {0x8cef, 0xe9af89}, /* U+9BC9 */ + {0x8cf0, 0xe4baa4}, /* U+4EA4 */ + {0x8cf1, 0xe4bdbc}, /* U+4F7C */ + {0x8cf2, 0xe4beaf}, /* U+4FAF */ + {0x8cf3, 0xe58099}, /* U+5019 */ + {0x8cf4, 0xe58096}, /* U+5016 */ + {0x8cf5, 0xe58589}, /* U+5149 */ + {0x8cf6, 0xe585ac}, /* U+516C */ + {0x8cf7, 0xe58a9f}, /* U+529F */ + {0x8cf8, 0xe58ab9}, /* U+52B9 */ + {0x8cf9, 0xe58bbe}, /* U+52FE */ + {0x8cfa, 0xe58e9a}, /* U+539A */ + {0x8cfb, 0xe58fa3}, /* U+53E3 */ + {0x8cfc, 0xe59091}, /* U+5411 */ + {0x8d40, 0xe5908e}, /* U+540E */ + {0x8d41, 0xe59689}, /* U+5589 */ + {0x8d42, 0xe59d91}, /* U+5751 */ + {0x8d43, 0xe59ea2}, /* U+57A2 */ + {0x8d44, 0xe5a5bd}, /* U+597D */ + {0x8d45, 0xe5ad94}, /* U+5B54 */ + {0x8d46, 0xe5ad9d}, /* U+5B5D */ + {0x8d47, 0xe5ae8f}, /* U+5B8F */ + {0x8d48, 0xe5b7a5}, /* U+5DE5 */ + {0x8d49, 0xe5b7a7}, /* U+5DE7 */ + {0x8d4a, 0xe5b7b7}, /* U+5DF7 */ + {0x8d4b, 0xe5b9b8}, /* U+5E78 */ + {0x8d4c, 0xe5ba83}, /* U+5E83 */ + {0x8d4d, 0xe5ba9a}, /* U+5E9A */ + {0x8d4e, 0xe5bab7}, /* U+5EB7 */ + {0x8d4f, 0xe5bc98}, /* U+5F18 */ + {0x8d50, 0xe68192}, /* U+6052 */ + {0x8d51, 0xe6858c}, /* U+614C */ + {0x8d52, 0xe68a97}, /* U+6297 */ + {0x8d53, 0xe68b98}, /* U+62D8 */ + {0x8d54, 0xe68ea7}, /* U+63A7 */ + {0x8d55, 0xe694bb}, /* U+653B */ + {0x8d56, 0xe69882}, /* U+6602 */ + {0x8d57, 0xe69983}, /* U+6643 */ + {0x8d58, 0xe69bb4}, /* U+66F4 */ + {0x8d59, 0xe69dad}, /* U+676D */ + {0x8d5a, 0xe6a0a1}, /* U+6821 */ + {0x8d5b, 0xe6a297}, /* U+6897 */ + {0x8d5c, 0xe6a78b}, /* U+69CB */ + {0x8d5d, 0xe6b19f}, /* U+6C5F */ + {0x8d5e, 0xe6b4aa}, /* U+6D2A */ + {0x8d5f, 0xe6b5a9}, /* U+6D69 */ + {0x8d60, 0xe6b8af}, /* U+6E2F */ + {0x8d61, 0xe6ba9d}, /* U+6E9D */ + {0x8d62, 0xe794b2}, /* U+7532 */ + {0x8d63, 0xe79a87}, /* U+7687 */ + {0x8d64, 0xe7a1ac}, /* U+786C */ + {0x8d65, 0xe7a8bf}, /* U+7A3F */ + {0x8d66, 0xe7b3a0}, /* U+7CE0 */ + {0x8d67, 0xe7b485}, /* U+7D05 */ + {0x8d68, 0xe7b498}, /* U+7D18 */ + {0x8d69, 0xe7b59e}, /* U+7D5E */ + {0x8d6a, 0xe7b6b1}, /* U+7DB1 */ + {0x8d6b, 0xe88095}, /* U+8015 */ + {0x8d6c, 0xe88083}, /* U+8003 */ + {0x8d6d, 0xe882af}, /* U+80AF */ + {0x8d6e, 0xe882b1}, /* U+80B1 */ + {0x8d6f, 0xe88594}, /* U+8154 */ + {0x8d70, 0xe8868f}, /* U+818F */ + {0x8d71, 0xe888aa}, /* U+822A */ + {0x8d72, 0xe88d92}, /* U+8352 */ + {0x8d73, 0xe8a18c}, /* U+884C */ + {0x8d74, 0xe8a1a1}, /* U+8861 */ + {0x8d75, 0xe8ac9b}, /* U+8B1B */ + {0x8d76, 0xe8b2a2}, /* U+8CA2 */ + {0x8d77, 0xe8b3bc}, /* U+8CFC */ + {0x8d78, 0xe9838a}, /* U+90CA */ + {0x8d79, 0xe985b5}, /* U+9175 */ + {0x8d7a, 0xe989b1}, /* U+9271 */ + {0x8d7b, 0xe7a0bf}, /* U+783F */ + {0x8d7c, 0xe98bbc}, /* U+92FC */ + {0x8d7d, 0xe996a4}, /* U+95A4 */ + {0x8d7e, 0xe9998d}, /* U+964D */ + {0x8d80, 0xe9a085}, /* U+9805 */ + {0x8d81, 0xe9a699}, /* U+9999 */ + {0x8d82, 0xe9ab98}, /* U+9AD8 */ + {0x8d83, 0xe9b4bb}, /* U+9D3B */ + {0x8d84, 0xe5899b}, /* U+525B */ + {0x8d85, 0xe58aab}, /* U+52AB */ + {0x8d86, 0xe58fb7}, /* U+53F7 */ + {0x8d87, 0xe59088}, /* U+5408 */ + {0x8d88, 0xe5a395}, /* U+58D5 */ + {0x8d89, 0xe68bb7}, /* U+62F7 */ + {0x8d8a, 0xe6bfa0}, /* U+6FE0 */ + {0x8d8b, 0xe8b1aa}, /* U+8C6A */ + {0x8d8c, 0xe8bd9f}, /* U+8F5F */ + {0x8d8d, 0xe9bab9}, /* U+9EB9 */ + {0x8d8e, 0xe5858b}, /* U+514B */ + {0x8d8f, 0xe588bb}, /* U+523B */ + {0x8d90, 0xe5918a}, /* U+544A */ + {0x8d91, 0xe59bbd}, /* U+56FD */ + {0x8d92, 0xe7a980}, /* U+7A40 */ + {0x8d93, 0xe985b7}, /* U+9177 */ + {0x8d94, 0xe9b5a0}, /* U+9D60 */ + {0x8d95, 0xe9bb92}, /* U+9ED2 */ + {0x8d96, 0xe78d84}, /* U+7344 */ + {0x8d97, 0xe6bc89}, /* U+6F09 */ + {0x8d98, 0xe885b0}, /* U+8170 */ + {0x8d99, 0xe79491}, /* U+7511 */ + {0x8d9a, 0xe5bfbd}, /* U+5FFD */ + {0x8d9b, 0xe6839a}, /* U+60DA */ + {0x8d9c, 0xe9aaa8}, /* U+9AA8 */ + {0x8d9d, 0xe78b9b}, /* U+72DB */ + {0x8d9e, 0xe8bebc}, /* U+8FBC */ + {0x8d9f, 0xe6ada4}, /* U+6B64 */ + {0x8da0, 0xe9a083}, /* U+9803 */ + {0x8da1, 0xe4bb8a}, /* U+4ECA */ + {0x8da2, 0xe59bb0}, /* U+56F0 */ + {0x8da3, 0xe59da4}, /* U+5764 */ + {0x8da4, 0xe5a2be}, /* U+58BE */ + {0x8da5, 0xe5a99a}, /* U+5A5A */ + {0x8da6, 0xe681a8}, /* U+6068 */ + {0x8da7, 0xe68787}, /* U+61C7 */ + {0x8da8, 0xe6988f}, /* U+660F */ + {0x8da9, 0xe69886}, /* U+6606 */ + {0x8daa, 0xe6a0b9}, /* U+6839 */ + {0x8dab, 0xe6a2b1}, /* U+68B1 */ + {0x8dac, 0xe6b7b7}, /* U+6DF7 */ + {0x8dad, 0xe79795}, /* U+75D5 */ + {0x8dae, 0xe7b4ba}, /* U+7D3A */ + {0x8daf, 0xe889ae}, /* U+826E */ + {0x8db0, 0xe9ad82}, /* U+9B42 */ + {0x8db1, 0xe4ba9b}, /* U+4E9B */ + {0x8db2, 0xe4bd90}, /* U+4F50 */ + {0x8db3, 0xe58f89}, /* U+53C9 */ + {0x8db4, 0xe59486}, /* U+5506 */ + {0x8db5, 0xe5b5af}, /* U+5D6F */ + {0x8db6, 0xe5b7a6}, /* U+5DE6 */ + {0x8db7, 0xe5b7ae}, /* U+5DEE */ + {0x8db8, 0xe69fbb}, /* U+67FB */ + {0x8db9, 0xe6b299}, /* U+6C99 */ + {0x8dba, 0xe791b3}, /* U+7473 */ + {0x8dbb, 0xe7a082}, /* U+7802 */ + {0x8dbc, 0xe8a990}, /* U+8A50 */ + {0x8dbd, 0xe98e96}, /* U+9396 */ + {0x8dbe, 0xe8a39f}, /* U+88DF */ + {0x8dbf, 0xe59d90}, /* U+5750 */ + {0x8dc0, 0xe5baa7}, /* U+5EA7 */ + {0x8dc1, 0xe68cab}, /* U+632B */ + {0x8dc2, 0xe582b5}, /* U+50B5 */ + {0x8dc3, 0xe582ac}, /* U+50AC */ + {0x8dc4, 0xe5868d}, /* U+518D */ + {0x8dc5, 0xe69c80}, /* U+6700 */ + {0x8dc6, 0xe59389}, /* U+54C9 */ + {0x8dc7, 0xe5a19e}, /* U+585E */ + {0x8dc8, 0xe5a6bb}, /* U+59BB */ + {0x8dc9, 0xe5aeb0}, /* U+5BB0 */ + {0x8dca, 0xe5bda9}, /* U+5F69 */ + {0x8dcb, 0xe6898d}, /* U+624D */ + {0x8dcc, 0xe68ea1}, /* U+63A1 */ + {0x8dcd, 0xe6a0bd}, /* U+683D */ + {0x8dce, 0xe6adb3}, /* U+6B73 */ + {0x8dcf, 0xe6b888}, /* U+6E08 */ + {0x8dd0, 0xe781bd}, /* U+707D */ + {0x8dd1, 0xe98787}, /* U+91C7 */ + {0x8dd2, 0xe78a80}, /* U+7280 */ + {0x8dd3, 0xe7a095}, /* U+7815 */ + {0x8dd4, 0xe7a0a6}, /* U+7826 */ + {0x8dd5, 0xe7a5ad}, /* U+796D */ + {0x8dd6, 0xe6968e}, /* U+658E */ + {0x8dd7, 0xe7b4b0}, /* U+7D30 */ + {0x8dd8, 0xe88f9c}, /* U+83DC */ + {0x8dd9, 0xe8a381}, /* U+88C1 */ + {0x8dda, 0xe8bc89}, /* U+8F09 */ + {0x8ddb, 0xe99a9b}, /* U+969B */ + {0x8ddc, 0xe589a4}, /* U+5264 */ + {0x8ddd, 0xe59ca8}, /* U+5728 */ + {0x8dde, 0xe69d90}, /* U+6750 */ + {0x8ddf, 0xe7bdaa}, /* U+7F6A */ + {0x8de0, 0xe8b2a1}, /* U+8CA1 */ + {0x8de1, 0xe586b4}, /* U+51B4 */ + {0x8de2, 0xe59d82}, /* U+5742 */ + {0x8de3, 0xe998aa}, /* U+962A */ + {0x8de4, 0xe5a0ba}, /* U+583A */ + {0x8de5, 0xe6a68a}, /* U+698A */ + {0x8de6, 0xe882b4}, /* U+80B4 */ + {0x8de7, 0xe592b2}, /* U+54B2 */ + {0x8de8, 0xe5b48e}, /* U+5D0E */ + {0x8de9, 0xe59fbc}, /* U+57FC */ + {0x8dea, 0xe7a295}, /* U+7895 */ + {0x8deb, 0xe9b7ba}, /* U+9DFA */ + {0x8dec, 0xe4bd9c}, /* U+4F5C */ + {0x8ded, 0xe5898a}, /* U+524A */ + {0x8dee, 0xe5928b}, /* U+548B */ + {0x8def, 0xe690be}, /* U+643E */ + {0x8df0, 0xe698a8}, /* U+6628 */ + {0x8df1, 0xe69c94}, /* U+6714 */ + {0x8df2, 0xe69fb5}, /* U+67F5 */ + {0x8df3, 0xe7aa84}, /* U+7A84 */ + {0x8df4, 0xe7ad96}, /* U+7B56 */ + {0x8df5, 0xe7b4a2}, /* U+7D22 */ + {0x8df6, 0xe98caf}, /* U+932F */ + {0x8df7, 0xe6a19c}, /* U+685C */ + {0x8df8, 0xe9aead}, /* U+9BAD */ + {0x8df9, 0xe7acb9}, /* U+7B39 */ + {0x8dfa, 0xe58c99}, /* U+5319 */ + {0x8dfb, 0xe5868a}, /* U+518A */ + {0x8dfc, 0xe588b7}, /* U+5237 */ + {0x8e40, 0xe5af9f}, /* U+5BDF */ + {0x8e41, 0xe68bb6}, /* U+62F6 */ + {0x8e42, 0xe692ae}, /* U+64AE */ + {0x8e43, 0xe693a6}, /* U+64E6 */ + {0x8e44, 0xe69cad}, /* U+672D */ + {0x8e45, 0xe6aeba}, /* U+6BBA */ + {0x8e46, 0xe896a9}, /* U+85A9 */ + {0x8e47, 0xe99b91}, /* U+96D1 */ + {0x8e48, 0xe79a90}, /* U+7690 */ + {0x8e49, 0xe9af96}, /* U+9BD6 */ + {0x8e4a, 0xe68d8c}, /* U+634C */ + {0x8e4b, 0xe98c86}, /* U+9306 */ + {0x8e4c, 0xe9aeab}, /* U+9BAB */ + {0x8e4d, 0xe79abf}, /* U+76BF */ + {0x8e4e, 0xe69992}, /* U+6652 */ + {0x8e4f, 0xe4b889}, /* U+4E09 */ + {0x8e50, 0xe58298}, /* U+5098 */ + {0x8e51, 0xe58f82}, /* U+53C2 */ + {0x8e52, 0xe5b1b1}, /* U+5C71 */ + {0x8e53, 0xe683a8}, /* U+60E8 */ + {0x8e54, 0xe69292}, /* U+6492 */ + {0x8e55, 0xe695a3}, /* U+6563 */ + {0x8e56, 0xe6a19f}, /* U+685F */ + {0x8e57, 0xe787a6}, /* U+71E6 */ + {0x8e58, 0xe78f8a}, /* U+73CA */ + {0x8e59, 0xe794a3}, /* U+7523 */ + {0x8e5a, 0xe7ae97}, /* U+7B97 */ + {0x8e5b, 0xe7ba82}, /* U+7E82 */ + {0x8e5c, 0xe89a95}, /* U+8695 */ + {0x8e5d, 0xe8ae83}, /* U+8B83 */ + {0x8e5e, 0xe8b39b}, /* U+8CDB */ + {0x8e5f, 0xe985b8}, /* U+9178 */ + {0x8e60, 0xe9a490}, /* U+9910 */ + {0x8e61, 0xe696ac}, /* U+65AC */ + {0x8e62, 0xe69aab}, /* U+66AB */ + {0x8e63, 0xe6ae8b}, /* U+6B8B */ + {0x8e64, 0xe4bb95}, /* U+4ED5 */ + {0x8e65, 0xe4bb94}, /* U+4ED4 */ + {0x8e66, 0xe4bcba}, /* U+4F3A */ + {0x8e67, 0xe4bdbf}, /* U+4F7F */ + {0x8e68, 0xe588ba}, /* U+523A */ + {0x8e69, 0xe58fb8}, /* U+53F8 */ + {0x8e6a, 0xe58fb2}, /* U+53F2 */ + {0x8e6b, 0xe597a3}, /* U+55E3 */ + {0x8e6c, 0xe59b9b}, /* U+56DB */ + {0x8e6d, 0xe5a3ab}, /* U+58EB */ + {0x8e6e, 0xe5a78b}, /* U+59CB */ + {0x8e6f, 0xe5a789}, /* U+59C9 */ + {0x8e70, 0xe5a7bf}, /* U+59FF */ + {0x8e71, 0xe5ad90}, /* U+5B50 */ + {0x8e72, 0xe5b18d}, /* U+5C4D */ + {0x8e73, 0xe5b882}, /* U+5E02 */ + {0x8e74, 0xe5b8ab}, /* U+5E2B */ + {0x8e75, 0xe5bf97}, /* U+5FD7 */ + {0x8e76, 0xe6809d}, /* U+601D */ + {0x8e77, 0xe68c87}, /* U+6307 */ + {0x8e78, 0xe694af}, /* U+652F */ + {0x8e79, 0xe5ad9c}, /* U+5B5C */ + {0x8e7a, 0xe696af}, /* U+65AF */ + {0x8e7b, 0xe696bd}, /* U+65BD */ + {0x8e7c, 0xe697a8}, /* U+65E8 */ + {0x8e7d, 0xe69e9d}, /* U+679D */ + {0x8e7e, 0xe6ada2}, /* U+6B62 */ + {0x8e80, 0xe6adbb}, /* U+6B7B */ + {0x8e81, 0xe6b08f}, /* U+6C0F */ + {0x8e82, 0xe78d85}, /* U+7345 */ + {0x8e83, 0xe7a589}, /* U+7949 */ + {0x8e84, 0xe7a781}, /* U+79C1 */ + {0x8e85, 0xe7b3b8}, /* U+7CF8 */ + {0x8e86, 0xe7b499}, /* U+7D19 */ + {0x8e87, 0xe7b4ab}, /* U+7D2B */ + {0x8e88, 0xe882a2}, /* U+80A2 */ + {0x8e89, 0xe88482}, /* U+8102 */ + {0x8e8a, 0xe887b3}, /* U+81F3 */ + {0x8e8b, 0xe8a696}, /* U+8996 */ + {0x8e8c, 0xe8a99e}, /* U+8A5E */ + {0x8e8d, 0xe8a9a9}, /* U+8A69 */ + {0x8e8e, 0xe8a9a6}, /* U+8A66 */ + {0x8e8f, 0xe8aa8c}, /* U+8A8C */ + {0x8e90, 0xe8abae}, /* U+8AEE */ + {0x8e91, 0xe8b387}, /* U+8CC7 */ + {0x8e92, 0xe8b39c}, /* U+8CDC */ + {0x8e93, 0xe99b8c}, /* U+96CC */ + {0x8e94, 0xe9a3bc}, /* U+98FC */ + {0x8e95, 0xe6adaf}, /* U+6B6F */ + {0x8e96, 0xe4ba8b}, /* U+4E8B */ + {0x8e97, 0xe4bcbc}, /* U+4F3C */ + {0x8e98, 0xe4be8d}, /* U+4F8D */ + {0x8e99, 0xe58590}, /* U+5150 */ + {0x8e9a, 0xe5ad97}, /* U+5B57 */ + {0x8e9b, 0xe5afba}, /* U+5BFA */ + {0x8e9c, 0xe68588}, /* U+6148 */ + {0x8e9d, 0xe68c81}, /* U+6301 */ + {0x8e9e, 0xe69982}, /* U+6642 */ + {0x8e9f, 0xe6aca1}, /* U+6B21 */ + {0x8ea0, 0xe6bb8b}, /* U+6ECB */ + {0x8ea1, 0xe6b2bb}, /* U+6CBB */ + {0x8ea2, 0xe788be}, /* U+723E */ + {0x8ea3, 0xe792bd}, /* U+74BD */ + {0x8ea4, 0xe79794}, /* U+75D4 */ + {0x8ea5, 0xe7a381}, /* U+78C1 */ + {0x8ea6, 0xe7a4ba}, /* U+793A */ + {0x8ea7, 0xe8808c}, /* U+800C */ + {0x8ea8, 0xe880b3}, /* U+8033 */ + {0x8ea9, 0xe887aa}, /* U+81EA */ + {0x8eaa, 0xe89294}, /* U+8494 */ + {0x8eab, 0xe8be9e}, /* U+8F9E */ + {0x8eac, 0xe6b190}, /* U+6C50 */ + {0x8ead, 0xe9b9bf}, /* U+9E7F */ + {0x8eae, 0xe5bc8f}, /* U+5F0F */ + {0x8eaf, 0xe8ad98}, /* U+8B58 */ + {0x8eb0, 0xe9b4ab}, /* U+9D2B */ + {0x8eb1, 0xe7abba}, /* U+7AFA */ + {0x8eb2, 0xe8bbb8}, /* U+8EF8 */ + {0x8eb3, 0xe5ae8d}, /* U+5B8D */ + {0x8eb4, 0xe99bab}, /* U+96EB */ + {0x8eb5, 0xe4b883}, /* U+4E03 */ + {0x8eb6, 0xe58fb1}, /* U+53F1 */ + {0x8eb7, 0xe59fb7}, /* U+57F7 */ + {0x8eb8, 0xe5a4b1}, /* U+5931 */ + {0x8eb9, 0xe5ab89}, /* U+5AC9 */ + {0x8eba, 0xe5aea4}, /* U+5BA4 */ + {0x8ebb, 0xe68289}, /* U+6089 */ + {0x8ebc, 0xe6b9bf}, /* U+6E7F */ + {0x8ebd, 0xe6bc86}, /* U+6F06 */ + {0x8ebe, 0xe796be}, /* U+75BE */ + {0x8ebf, 0xe8b3aa}, /* U+8CEA */ + {0x8ec0, 0xe5ae9f}, /* U+5B9F */ + {0x8ec1, 0xe89480}, /* U+8500 */ + {0x8ec2, 0xe7afa0}, /* U+7BE0 */ + {0x8ec3, 0xe581b2}, /* U+5072 */ + {0x8ec4, 0xe69fb4}, /* U+67F4 */ + {0x8ec5, 0xe88a9d}, /* U+829D */ + {0x8ec6, 0xe5b1a1}, /* U+5C61 */ + {0x8ec7, 0xe8958a}, /* U+854A */ + {0x8ec8, 0xe7b89e}, /* U+7E1E */ + {0x8ec9, 0xe8888e}, /* U+820E */ + {0x8eca, 0xe58699}, /* U+5199 */ + {0x8ecb, 0xe5b084}, /* U+5C04 */ + {0x8ecc, 0xe68da8}, /* U+6368 */ + {0x8ecd, 0xe8b5a6}, /* U+8D66 */ + {0x8ece, 0xe6969c}, /* U+659C */ + {0x8ecf, 0xe785ae}, /* U+716E */ + {0x8ed0, 0xe7a4be}, /* U+793E */ + {0x8ed1, 0xe7b497}, /* U+7D17 */ + {0x8ed2, 0xe88085}, /* U+8005 */ + {0x8ed3, 0xe8ac9d}, /* U+8B1D */ + {0x8ed4, 0xe8bb8a}, /* U+8ECA */ + {0x8ed5, 0xe981ae}, /* U+906E */ + {0x8ed6, 0xe89b87}, /* U+86C7 */ + {0x8ed7, 0xe982aa}, /* U+90AA */ + {0x8ed8, 0xe5809f}, /* U+501F */ + {0x8ed9, 0xe58bba}, /* U+52FA */ + {0x8eda, 0xe5b0ba}, /* U+5C3A */ + {0x8edb, 0xe69d93}, /* U+6753 */ + {0x8edc, 0xe781bc}, /* U+707C */ + {0x8edd, 0xe788b5}, /* U+7235 */ + {0x8ede, 0xe9858c}, /* U+914C */ + {0x8edf, 0xe98788}, /* U+91C8 */ + {0x8ee0, 0xe98cab}, /* U+932B */ + {0x8ee1, 0xe88ba5}, /* U+82E5 */ + {0x8ee2, 0xe5af82}, /* U+5BC2 */ + {0x8ee3, 0xe5bcb1}, /* U+5F31 */ + {0x8ee4, 0xe683b9}, /* U+60F9 */ + {0x8ee5, 0xe4b8bb}, /* U+4E3B */ + {0x8ee6, 0xe58f96}, /* U+53D6 */ + {0x8ee7, 0xe5ae88}, /* U+5B88 */ + {0x8ee8, 0xe6898b}, /* U+624B */ + {0x8ee9, 0xe69cb1}, /* U+6731 */ + {0x8eea, 0xe6ae8a}, /* U+6B8A */ + {0x8eeb, 0xe78ba9}, /* U+72E9 */ + {0x8eec, 0xe78fa0}, /* U+73E0 */ + {0x8eed, 0xe7a8ae}, /* U+7A2E */ + {0x8eee, 0xe885ab}, /* U+816B */ + {0x8eef, 0xe8b6a3}, /* U+8DA3 */ + {0x8ef0, 0xe98592}, /* U+9152 */ + {0x8ef1, 0xe9a696}, /* U+9996 */ + {0x8ef2, 0xe58492}, /* U+5112 */ + {0x8ef3, 0xe58f97}, /* U+53D7 */ + {0x8ef4, 0xe591aa}, /* U+546A */ + {0x8ef5, 0xe5afbf}, /* U+5BFF */ + {0x8ef6, 0xe68e88}, /* U+6388 */ + {0x8ef7, 0xe6a8b9}, /* U+6A39 */ + {0x8ef8, 0xe7b6ac}, /* U+7DAC */ + {0x8ef9, 0xe99c80}, /* U+9700 */ + {0x8efa, 0xe59b9a}, /* U+56DA */ + {0x8efb, 0xe58f8e}, /* U+53CE */ + {0x8efc, 0xe591a8}, /* U+5468 */ + {0x8f40, 0xe5ae97}, /* U+5B97 */ + {0x8f41, 0xe5b0b1}, /* U+5C31 */ + {0x8f42, 0xe5b79e}, /* U+5DDE */ + {0x8f43, 0xe4bfae}, /* U+4FEE */ + {0x8f44, 0xe68481}, /* U+6101 */ + {0x8f45, 0xe68bbe}, /* U+62FE */ + {0x8f46, 0xe6b4b2}, /* U+6D32 */ + {0x8f47, 0xe7a780}, /* U+79C0 */ + {0x8f48, 0xe7a78b}, /* U+79CB */ + {0x8f49, 0xe7b582}, /* U+7D42 */ + {0x8f4a, 0xe7b98d}, /* U+7E4D */ + {0x8f4b, 0xe7bf92}, /* U+7FD2 */ + {0x8f4c, 0xe887ad}, /* U+81ED */ + {0x8f4d, 0xe8889f}, /* U+821F */ + {0x8f4e, 0xe89290}, /* U+8490 */ + {0x8f4f, 0xe8a186}, /* U+8846 */ + {0x8f50, 0xe8a5b2}, /* U+8972 */ + {0x8f51, 0xe8ae90}, /* U+8B90 */ + {0x8f52, 0xe8b9b4}, /* U+8E74 */ + {0x8f53, 0xe8bcaf}, /* U+8F2F */ + {0x8f54, 0xe980b1}, /* U+9031 */ + {0x8f55, 0xe9858b}, /* U+914B */ + {0x8f56, 0xe985ac}, /* U+916C */ + {0x8f57, 0xe99b86}, /* U+96C6 */ + {0x8f58, 0xe9869c}, /* U+919C */ + {0x8f59, 0xe4bb80}, /* U+4EC0 */ + {0x8f5a, 0xe4bd8f}, /* U+4F4F */ + {0x8f5b, 0xe58585}, /* U+5145 */ + {0x8f5c, 0xe58d81}, /* U+5341 */ + {0x8f5d, 0xe5be93}, /* U+5F93 */ + {0x8f5e, 0xe6888e}, /* U+620E */ + {0x8f5f, 0xe69f94}, /* U+67D4 */ + {0x8f60, 0xe6b181}, /* U+6C41 */ + {0x8f61, 0xe6b88b}, /* U+6E0B */ + {0x8f62, 0xe78da3}, /* U+7363 */ + {0x8f63, 0xe7b8a6}, /* U+7E26 */ + {0x8f64, 0xe9878d}, /* U+91CD */ + {0x8f65, 0xe98a83}, /* U+9283 */ + {0x8f66, 0xe58f94}, /* U+53D4 */ + {0x8f67, 0xe5a499}, /* U+5919 */ + {0x8f68, 0xe5aebf}, /* U+5BBF */ + {0x8f69, 0xe6b791}, /* U+6DD1 */ + {0x8f6a, 0xe7a59d}, /* U+795D */ + {0x8f6b, 0xe7b8ae}, /* U+7E2E */ + {0x8f6c, 0xe7b29b}, /* U+7C9B */ + {0x8f6d, 0xe5a1be}, /* U+587E */ + {0x8f6e, 0xe7869f}, /* U+719F */ + {0x8f6f, 0xe587ba}, /* U+51FA */ + {0x8f70, 0xe8a193}, /* U+8853 */ + {0x8f71, 0xe8bfb0}, /* U+8FF0 */ + {0x8f72, 0xe4bf8a}, /* U+4FCA */ + {0x8f73, 0xe5b3bb}, /* U+5CFB */ + {0x8f74, 0xe698a5}, /* U+6625 */ + {0x8f75, 0xe79eac}, /* U+77AC */ + {0x8f76, 0xe7aba3}, /* U+7AE3 */ + {0x8f77, 0xe8889c}, /* U+821C */ + {0x8f78, 0xe9a7bf}, /* U+99FF */ + {0x8f79, 0xe58786}, /* U+51C6 */ + {0x8f7a, 0xe5beaa}, /* U+5FAA */ + {0x8f7b, 0xe697ac}, /* U+65EC */ + {0x8f7c, 0xe6a5af}, /* U+696F */ + {0x8f7d, 0xe6ae89}, /* U+6B89 */ + {0x8f7e, 0xe6b7b3}, /* U+6DF3 */ + {0x8f80, 0xe6ba96}, /* U+6E96 */ + {0x8f81, 0xe6bda4}, /* U+6F64 */ + {0x8f82, 0xe79bbe}, /* U+76FE */ + {0x8f83, 0xe7b494}, /* U+7D14 */ + {0x8f84, 0xe5b7a1}, /* U+5DE1 */ + {0x8f85, 0xe981b5}, /* U+9075 */ + {0x8f86, 0xe98687}, /* U+9187 */ + {0x8f87, 0xe9a086}, /* U+9806 */ + {0x8f88, 0xe587a6}, /* U+51E6 */ + {0x8f89, 0xe5889d}, /* U+521D */ + {0x8f8a, 0xe68980}, /* U+6240 */ + {0x8f8b, 0xe69a91}, /* U+6691 */ + {0x8f8c, 0xe69b99}, /* U+66D9 */ + {0x8f8d, 0xe6b89a}, /* U+6E1A */ + {0x8f8e, 0xe5bab6}, /* U+5EB6 */ + {0x8f8f, 0xe7b792}, /* U+7DD2 */ + {0x8f90, 0xe7bdb2}, /* U+7F72 */ + {0x8f91, 0xe69bb8}, /* U+66F8 */ + {0x8f92, 0xe896af}, /* U+85AF */ + {0x8f93, 0xe897b7}, /* U+85F7 */ + {0x8f94, 0xe8abb8}, /* U+8AF8 */ + {0x8f95, 0xe58aa9}, /* U+52A9 */ + {0x8f96, 0xe58f99}, /* U+53D9 */ + {0x8f97, 0xe5a5b3}, /* U+5973 */ + {0x8f98, 0xe5ba8f}, /* U+5E8F */ + {0x8f99, 0xe5be90}, /* U+5F90 */ + {0x8f9a, 0xe68195}, /* U+6055 */ + {0x8f9b, 0xe98ba4}, /* U+92E4 */ + {0x8f9c, 0xe999a4}, /* U+9664 */ + {0x8f9d, 0xe582b7}, /* U+50B7 */ + {0x8f9e, 0xe5849f}, /* U+511F */ + {0x8f9f, 0xe58b9d}, /* U+52DD */ + {0x8fa0, 0xe58ca0}, /* U+5320 */ + {0x8fa1, 0xe58d87}, /* U+5347 */ + {0x8fa2, 0xe58fac}, /* U+53EC */ + {0x8fa3, 0xe593a8}, /* U+54E8 */ + {0x8fa4, 0xe59586}, /* U+5546 */ + {0x8fa5, 0xe594b1}, /* U+5531 */ + {0x8fa6, 0xe59897}, /* U+5617 */ + {0x8fa7, 0xe5a5a8}, /* U+5968 */ + {0x8fa8, 0xe5a6be}, /* U+59BE */ + {0x8fa9, 0xe5a8bc}, /* U+5A3C */ + {0x8faa, 0xe5aeb5}, /* U+5BB5 */ + {0x8fab, 0xe5b086}, /* U+5C06 */ + {0x8fac, 0xe5b08f}, /* U+5C0F */ + {0x8fad, 0xe5b091}, /* U+5C11 */ + {0x8fae, 0xe5b09a}, /* U+5C1A */ + {0x8faf, 0xe5ba84}, /* U+5E84 */ + {0x8fb0, 0xe5ba8a}, /* U+5E8A */ + {0x8fb1, 0xe5bba0}, /* U+5EE0 */ + {0x8fb2, 0xe5bdb0}, /* U+5F70 */ + {0x8fb3, 0xe689bf}, /* U+627F */ + {0x8fb4, 0xe68a84}, /* U+6284 */ + {0x8fb5, 0xe68b9b}, /* U+62DB */ + {0x8fb6, 0xe68e8c}, /* U+638C */ + {0x8fb7, 0xe68db7}, /* U+6377 */ + {0x8fb8, 0xe69887}, /* U+6607 */ + {0x8fb9, 0xe6988c}, /* U+660C */ + {0x8fba, 0xe698ad}, /* U+662D */ + {0x8fbb, 0xe699b6}, /* U+6676 */ + {0x8fbc, 0xe69dbe}, /* U+677E */ + {0x8fbd, 0xe6a2a2}, /* U+68A2 */ + {0x8fbe, 0xe6a89f}, /* U+6A1F */ + {0x8fbf, 0xe6a8b5}, /* U+6A35 */ + {0x8fc0, 0xe6b2bc}, /* U+6CBC */ + {0x8fc1, 0xe6b688}, /* U+6D88 */ + {0x8fc2, 0xe6b889}, /* U+6E09 */ + {0x8fc3, 0xe6b998}, /* U+6E58 */ + {0x8fc4, 0xe784bc}, /* U+713C */ + {0x8fc5, 0xe784a6}, /* U+7126 */ + {0x8fc6, 0xe785a7}, /* U+7167 */ + {0x8fc7, 0xe79787}, /* U+75C7 */ + {0x8fc8, 0xe79c81}, /* U+7701 */ + {0x8fc9, 0xe7a19d}, /* U+785D */ + {0x8fca, 0xe7a481}, /* U+7901 */ + {0x8fcb, 0xe7a5a5}, /* U+7965 */ + {0x8fcc, 0xe7a7b0}, /* U+79F0 */ + {0x8fcd, 0xe7aba0}, /* U+7AE0 */ + {0x8fce, 0xe7ac91}, /* U+7B11 */ + {0x8fcf, 0xe7b2a7}, /* U+7CA7 */ + {0x8fd0, 0xe7b4b9}, /* U+7D39 */ + {0x8fd1, 0xe88296}, /* U+8096 */ + {0x8fd2, 0xe88f96}, /* U+83D6 */ + {0x8fd3, 0xe8928b}, /* U+848B */ + {0x8fd4, 0xe89589}, /* U+8549 */ + {0x8fd5, 0xe8a19d}, /* U+885D */ + {0x8fd6, 0xe8a3b3}, /* U+88F3 */ + {0x8fd7, 0xe8a89f}, /* U+8A1F */ + {0x8fd8, 0xe8a8bc}, /* U+8A3C */ + {0x8fd9, 0xe8a994}, /* U+8A54 */ + {0x8fda, 0xe8a9b3}, /* U+8A73 */ + {0x8fdb, 0xe8b1a1}, /* U+8C61 */ + {0x8fdc, 0xe8b39e}, /* U+8CDE */ + {0x8fdd, 0xe986a4}, /* U+91A4 */ + {0x8fde, 0xe989a6}, /* U+9266 */ + {0x8fdf, 0xe98dbe}, /* U+937E */ + {0x8fe0, 0xe99098}, /* U+9418 */ + {0x8fe1, 0xe99a9c}, /* U+969C */ + {0x8fe2, 0xe99e98}, /* U+9798 */ + {0x8fe3, 0xe4b88a}, /* U+4E0A */ + {0x8fe4, 0xe4b888}, /* U+4E08 */ + {0x8fe5, 0xe4b89e}, /* U+4E1E */ + {0x8fe6, 0xe4b997}, /* U+4E57 */ + {0x8fe7, 0xe58697}, /* U+5197 */ + {0x8fe8, 0xe589b0}, /* U+5270 */ + {0x8fe9, 0xe59f8e}, /* U+57CE */ + {0x8fea, 0xe5a0b4}, /* U+5834 */ + {0x8feb, 0xe5a38c}, /* U+58CC */ + {0x8fec, 0xe5aca2}, /* U+5B22 */ + {0x8fed, 0xe5b8b8}, /* U+5E38 */ + {0x8fee, 0xe68385}, /* U+60C5 */ + {0x8fef, 0xe693be}, /* U+64FE */ + {0x8ff0, 0xe69da1}, /* U+6761 */ + {0x8ff1, 0xe69d96}, /* U+6756 */ + {0x8ff2, 0xe6b584}, /* U+6D44 */ + {0x8ff3, 0xe78ab6}, /* U+72B6 */ + {0x8ff4, 0xe795b3}, /* U+7573 */ + {0x8ff5, 0xe7a9a3}, /* U+7A63 */ + {0x8ff6, 0xe892b8}, /* U+84B8 */ + {0x8ff7, 0xe8adb2}, /* U+8B72 */ + {0x8ff8, 0xe986b8}, /* U+91B8 */ + {0x8ff9, 0xe98ca0}, /* U+9320 */ + {0x8ffa, 0xe598b1}, /* U+5631 */ + {0x8ffb, 0xe59fb4}, /* U+57F4 */ + {0x8ffc, 0xe9a3be}, /* U+98FE */ + {0x9040, 0xe68bad}, /* U+62ED */ + {0x9041, 0xe6a48d}, /* U+690D */ + {0x9042, 0xe6ae96}, /* U+6B96 */ + {0x9043, 0xe787ad}, /* U+71ED */ + {0x9044, 0xe7b994}, /* U+7E54 */ + {0x9045, 0xe881b7}, /* U+8077 */ + {0x9046, 0xe889b2}, /* U+8272 */ + {0x9047, 0xe8a7a6}, /* U+89E6 */ + {0x9048, 0xe9a39f}, /* U+98DF */ + {0x9049, 0xe89d95}, /* U+8755 */ + {0x904a, 0xe8beb1}, /* U+8FB1 */ + {0x904b, 0xe5b0bb}, /* U+5C3B */ + {0x904c, 0xe4bcb8}, /* U+4F38 */ + {0x904d, 0xe4bfa1}, /* U+4FE1 */ + {0x904e, 0xe4beb5}, /* U+4FB5 */ + {0x904f, 0xe59487}, /* U+5507 */ + {0x9050, 0xe5a8a0}, /* U+5A20 */ + {0x9051, 0xe5af9d}, /* U+5BDD */ + {0x9052, 0xe5afa9}, /* U+5BE9 */ + {0x9053, 0xe5bf83}, /* U+5FC3 */ + {0x9054, 0xe6858e}, /* U+614E */ + {0x9055, 0xe68caf}, /* U+632F */ + {0x9056, 0xe696b0}, /* U+65B0 */ + {0x9057, 0xe6998b}, /* U+664B */ + {0x9058, 0xe6a3ae}, /* U+68EE */ + {0x9059, 0xe6a69b}, /* U+699B */ + {0x905a, 0xe6b5b8}, /* U+6D78 */ + {0x905b, 0xe6b7b1}, /* U+6DF1 */ + {0x905c, 0xe794b3}, /* U+7533 */ + {0x905d, 0xe796b9}, /* U+75B9 */ + {0x905e, 0xe79c9f}, /* U+771F */ + {0x905f, 0xe7a59e}, /* U+795E */ + {0x9060, 0xe7a7a6}, /* U+79E6 */ + {0x9061, 0xe7b4b3}, /* U+7D33 */ + {0x9062, 0xe887a3}, /* U+81E3 */ + {0x9063, 0xe88aaf}, /* U+82AF */ + {0x9064, 0xe896aa}, /* U+85AA */ + {0x9065, 0xe8a6aa}, /* U+89AA */ + {0x9066, 0xe8a8ba}, /* U+8A3A */ + {0x9067, 0xe8baab}, /* U+8EAB */ + {0x9068, 0xe8be9b}, /* U+8F9B */ + {0x9069, 0xe980b2}, /* U+9032 */ + {0x906a, 0xe9879d}, /* U+91DD */ + {0x906b, 0xe99c87}, /* U+9707 */ + {0x906c, 0xe4baba}, /* U+4EBA */ + {0x906d, 0xe4bb81}, /* U+4EC1 */ + {0x906e, 0xe58883}, /* U+5203 */ + {0x906f, 0xe5a1b5}, /* U+5875 */ + {0x9070, 0xe5a3ac}, /* U+58EC */ + {0x9071, 0xe5b08b}, /* U+5C0B */ + {0x9072, 0xe7949a}, /* U+751A */ + {0x9073, 0xe5b0bd}, /* U+5C3D */ + {0x9074, 0xe8858e}, /* U+814E */ + {0x9075, 0xe8a88a}, /* U+8A0A */ + {0x9076, 0xe8bf85}, /* U+8FC5 */ + {0x9077, 0xe999a3}, /* U+9663 */ + {0x9078, 0xe99dad}, /* U+976D */ + {0x9079, 0xe7aca5}, /* U+7B25 */ + {0x907a, 0xe8ab8f}, /* U+8ACF */ + {0x907b, 0xe9a088}, /* U+9808 */ + {0x907c, 0xe985a2}, /* U+9162 */ + {0x907d, 0xe59bb3}, /* U+56F3 */ + {0x907e, 0xe58ea8}, /* U+53A8 */ + {0x9080, 0xe98097}, /* U+9017 */ + {0x9081, 0xe590b9}, /* U+5439 */ + {0x9082, 0xe59e82}, /* U+5782 */ + {0x9083, 0xe5b8a5}, /* U+5E25 */ + {0x9084, 0xe68ea8}, /* U+63A8 */ + {0x9085, 0xe6b0b4}, /* U+6C34 */ + {0x9086, 0xe7828a}, /* U+708A */ + {0x9087, 0xe79da1}, /* U+7761 */ + {0x9088, 0xe7b28b}, /* U+7C8B */ + {0x9089, 0xe7bfa0}, /* U+7FE0 */ + {0x908a, 0xe8a1b0}, /* U+8870 */ + {0x908b, 0xe98182}, /* U+9042 */ + {0x908c, 0xe98594}, /* U+9154 */ + {0x908d, 0xe98c90}, /* U+9310 */ + {0x908e, 0xe98c98}, /* U+9318 */ + {0x908f, 0xe99a8f}, /* U+968F */ + {0x9090, 0xe7919e}, /* U+745E */ + {0x9091, 0xe9ab84}, /* U+9AC4 */ + {0x9092, 0xe5b487}, /* U+5D07 */ + {0x9093, 0xe5b5a9}, /* U+5D69 */ + {0x9094, 0xe695b0}, /* U+6570 */ + {0x9095, 0xe69ea2}, /* U+67A2 */ + {0x9096, 0xe8b6a8}, /* U+8DA8 */ + {0x9097, 0xe99b9b}, /* U+96DB */ + {0x9098, 0xe68dae}, /* U+636E */ + {0x9099, 0xe69d89}, /* U+6749 */ + {0x909a, 0xe6a499}, /* U+6919 */ + {0x909b, 0xe88f85}, /* U+83C5 */ + {0x909c, 0xe9a097}, /* U+9817 */ + {0x909d, 0xe99b80}, /* U+96C0 */ + {0x909e, 0xe8a3be}, /* U+88FE */ + {0x909f, 0xe6be84}, /* U+6F84 */ + {0x90a0, 0xe691ba}, /* U+647A */ + {0x90a1, 0xe5afb8}, /* U+5BF8 */ + {0x90a2, 0xe4b896}, /* U+4E16 */ + {0x90a3, 0xe780ac}, /* U+702C */ + {0x90a4, 0xe7959d}, /* U+755D */ + {0x90a5, 0xe698af}, /* U+662F */ + {0x90a6, 0xe58784}, /* U+51C4 */ + {0x90a7, 0xe588b6}, /* U+5236 */ + {0x90a8, 0xe58ba2}, /* U+52E2 */ + {0x90a9, 0xe5a793}, /* U+59D3 */ + {0x90aa, 0xe5be81}, /* U+5F81 */ + {0x90ab, 0xe680a7}, /* U+6027 */ + {0x90ac, 0xe68890}, /* U+6210 */ + {0x90ad, 0xe694bf}, /* U+653F */ + {0x90ae, 0xe695b4}, /* U+6574 */ + {0x90af, 0xe6989f}, /* U+661F */ + {0x90b0, 0xe699b4}, /* U+6674 */ + {0x90b1, 0xe6a3b2}, /* U+68F2 */ + {0x90b2, 0xe6a096}, /* U+6816 */ + {0x90b3, 0xe6ada3}, /* U+6B63 */ + {0x90b4, 0xe6b885}, /* U+6E05 */ + {0x90b5, 0xe789b2}, /* U+7272 */ + {0x90b6, 0xe7949f}, /* U+751F */ + {0x90b7, 0xe79b9b}, /* U+76DB */ + {0x90b8, 0xe7b2be}, /* U+7CBE */ + {0x90b9, 0xe88196}, /* U+8056 */ + {0x90ba, 0xe5a3b0}, /* U+58F0 */ + {0x90bb, 0xe8a3bd}, /* U+88FD */ + {0x90bc, 0xe8a5bf}, /* U+897F */ + {0x90bd, 0xe8aaa0}, /* U+8AA0 */ + {0x90be, 0xe8aa93}, /* U+8A93 */ + {0x90bf, 0xe8ab8b}, /* U+8ACB */ + {0x90c0, 0xe9809d}, /* U+901D */ + {0x90c1, 0xe98692}, /* U+9192 */ + {0x90c2, 0xe99d92}, /* U+9752 */ + {0x90c3, 0xe99d99}, /* U+9759 */ + {0x90c4, 0xe69689}, /* U+6589 */ + {0x90c5, 0xe7a88e}, /* U+7A0E */ + {0x90c6, 0xe88486}, /* U+8106 */ + {0x90c7, 0xe99abb}, /* U+96BB */ + {0x90c8, 0xe5b8ad}, /* U+5E2D */ + {0x90c9, 0xe6839c}, /* U+60DC */ + {0x90ca, 0xe6889a}, /* U+621A */ + {0x90cb, 0xe696a5}, /* U+65A5 */ + {0x90cc, 0xe69894}, /* U+6614 */ + {0x90cd, 0xe69e90}, /* U+6790 */ + {0x90ce, 0xe79fb3}, /* U+77F3 */ + {0x90cf, 0xe7a98d}, /* U+7A4D */ + {0x90d0, 0xe7b18d}, /* U+7C4D */ + {0x90d1, 0xe7b8be}, /* U+7E3E */ + {0x90d2, 0xe8848a}, /* U+810A */ + {0x90d3, 0xe8b2ac}, /* U+8CAC */ + {0x90d4, 0xe8b5a4}, /* U+8D64 */ + {0x90d5, 0xe8b7a1}, /* U+8DE1 */ + {0x90d6, 0xe8b99f}, /* U+8E5F */ + {0x90d7, 0xe7a2a9}, /* U+78A9 */ + {0x90d8, 0xe58887}, /* U+5207 */ + {0x90d9, 0xe68b99}, /* U+62D9 */ + {0x90da, 0xe68ea5}, /* U+63A5 */ + {0x90db, 0xe69182}, /* U+6442 */ + {0x90dc, 0xe68a98}, /* U+6298 */ + {0x90dd, 0xe8a8ad}, /* U+8A2D */ + {0x90de, 0xe7aa83}, /* U+7A83 */ + {0x90df, 0xe7af80}, /* U+7BC0 */ + {0x90e0, 0xe8aaac}, /* U+8AAC */ + {0x90e1, 0xe99baa}, /* U+96EA */ + {0x90e2, 0xe7b5b6}, /* U+7D76 */ + {0x90e3, 0xe8888c}, /* U+820C */ + {0x90e4, 0xe89d89}, /* U+8749 */ + {0x90e5, 0xe4bb99}, /* U+4ED9 */ + {0x90e6, 0xe58588}, /* U+5148 */ + {0x90e7, 0xe58d83}, /* U+5343 */ + {0x90e8, 0xe58da0}, /* U+5360 */ + {0x90e9, 0xe5aea3}, /* U+5BA3 */ + {0x90ea, 0xe5b082}, /* U+5C02 */ + {0x90eb, 0xe5b096}, /* U+5C16 */ + {0x90ec, 0xe5b79d}, /* U+5DDD */ + {0x90ed, 0xe688a6}, /* U+6226 */ + {0x90ee, 0xe68987}, /* U+6247 */ + {0x90ef, 0xe692b0}, /* U+64B0 */ + {0x90f0, 0xe6a093}, /* U+6813 */ + {0x90f1, 0xe6a0b4}, /* U+6834 */ + {0x90f2, 0xe6b389}, /* U+6CC9 */ + {0x90f3, 0xe6b585}, /* U+6D45 */ + {0x90f4, 0xe6b497}, /* U+6D17 */ + {0x90f5, 0xe69f93}, /* U+67D3 */ + {0x90f6, 0xe6bd9c}, /* U+6F5C */ + {0x90f7, 0xe7858e}, /* U+714E */ + {0x90f8, 0xe785bd}, /* U+717D */ + {0x90f9, 0xe6978b}, /* U+65CB */ + {0x90fa, 0xe7a9bf}, /* U+7A7F */ + {0x90fb, 0xe7aead}, /* U+7BAD */ + {0x90fc, 0xe7b79a}, /* U+7DDA */ + {0x9140, 0xe7b98a}, /* U+7E4A */ + {0x9141, 0xe7bea8}, /* U+7FA8 */ + {0x9142, 0xe885ba}, /* U+817A */ + {0x9143, 0xe8889b}, /* U+821B */ + {0x9144, 0xe888b9}, /* U+8239 */ + {0x9145, 0xe896a6}, /* U+85A6 */ + {0x9146, 0xe8a9ae}, /* U+8A6E */ + {0x9147, 0xe8b38e}, /* U+8CCE */ + {0x9148, 0xe8b7b5}, /* U+8DF5 */ + {0x9149, 0xe981b8}, /* U+9078 */ + {0x914a, 0xe981b7}, /* U+9077 */ + {0x914b, 0xe98aad}, /* U+92AD */ + {0x914c, 0xe98a91}, /* U+9291 */ + {0x914d, 0xe99683}, /* U+9583 */ + {0x914e, 0xe9aeae}, /* U+9BAE */ + {0x914f, 0xe5898d}, /* U+524D */ + {0x9150, 0xe59684}, /* U+5584 */ + {0x9151, 0xe6bcb8}, /* U+6F38 */ + {0x9152, 0xe784b6}, /* U+7136 */ + {0x9153, 0xe585a8}, /* U+5168 */ + {0x9154, 0xe7a685}, /* U+7985 */ + {0x9155, 0xe7b995}, /* U+7E55 */ + {0x9156, 0xe886b3}, /* U+81B3 */ + {0x9157, 0xe7b38e}, /* U+7CCE */ + {0x9158, 0xe5998c}, /* U+564C */ + {0x9159, 0xe5a191}, /* U+5851 */ + {0x915a, 0xe5b2a8}, /* U+5CA8 */ + {0x915b, 0xe68eaa}, /* U+63AA */ + {0x915c, 0xe69bbe}, /* U+66FE */ + {0x915d, 0xe69bbd}, /* U+66FD */ + {0x915e, 0xe6a59a}, /* U+695A */ + {0x915f, 0xe78b99}, /* U+72D9 */ + {0x9160, 0xe7968f}, /* U+758F */ + {0x9161, 0xe7968e}, /* U+758E */ + {0x9162, 0xe7a48e}, /* U+790E */ + {0x9163, 0xe7a596}, /* U+7956 */ + {0x9164, 0xe7a79f}, /* U+79DF */ + {0x9165, 0xe7b297}, /* U+7C97 */ + {0x9166, 0xe7b4a0}, /* U+7D20 */ + {0x9167, 0xe7b584}, /* U+7D44 */ + {0x9168, 0xe89887}, /* U+8607 */ + {0x9169, 0xe8a8b4}, /* U+8A34 */ + {0x916a, 0xe998bb}, /* U+963B */ + {0x916b, 0xe981a1}, /* U+9061 */ + {0x916c, 0xe9bca0}, /* U+9F20 */ + {0x916d, 0xe583a7}, /* U+50E7 */ + {0x916e, 0xe589b5}, /* U+5275 */ + {0x916f, 0xe58f8c}, /* U+53CC */ + {0x9170, 0xe58fa2}, /* U+53E2 */ + {0x9171, 0xe58089}, /* U+5009 */ + {0x9172, 0xe596aa}, /* U+55AA */ + {0x9173, 0xe5a3ae}, /* U+58EE */ + {0x9174, 0xe5a58f}, /* U+594F */ + {0x9175, 0xe788bd}, /* U+723D */ + {0x9176, 0xe5ae8b}, /* U+5B8B */ + {0x9177, 0xe5b1a4}, /* U+5C64 */ + {0x9178, 0xe58c9d}, /* U+531D */ + {0x9179, 0xe683a3}, /* U+60E3 */ + {0x917a, 0xe683b3}, /* U+60F3 */ + {0x917b, 0xe68d9c}, /* U+635C */ + {0x917c, 0xe68e83}, /* U+6383 */ + {0x917d, 0xe68cbf}, /* U+633F */ + {0x917e, 0xe68ebb}, /* U+63BB */ + {0x9180, 0xe6938d}, /* U+64CD */ + {0x9181, 0xe697a9}, /* U+65E9 */ + {0x9182, 0xe69bb9}, /* U+66F9 */ + {0x9183, 0xe5b7a3}, /* U+5DE3 */ + {0x9184, 0xe6a78d}, /* U+69CD */ + {0x9185, 0xe6a7bd}, /* U+69FD */ + {0x9186, 0xe6bc95}, /* U+6F15 */ + {0x9187, 0xe787a5}, /* U+71E5 */ + {0x9188, 0xe4ba89}, /* U+4E89 */ + {0x9189, 0xe797a9}, /* U+75E9 */ + {0x918a, 0xe79bb8}, /* U+76F8 */ + {0x918b, 0xe7aa93}, /* U+7A93 */ + {0x918c, 0xe7b39f}, /* U+7CDF */ + {0x918d, 0xe7b78f}, /* U+7DCF */ + {0x918e, 0xe7b69c}, /* U+7D9C */ + {0x918f, 0xe881a1}, /* U+8061 */ + {0x9190, 0xe88d89}, /* U+8349 */ + {0x9191, 0xe88d98}, /* U+8358 */ + {0x9192, 0xe891ac}, /* U+846C */ + {0x9193, 0xe892bc}, /* U+84BC */ + {0x9194, 0xe897bb}, /* U+85FB */ + {0x9195, 0xe8a385}, /* U+88C5 */ + {0x9196, 0xe8b5b0}, /* U+8D70 */ + {0x9197, 0xe98081}, /* U+9001 */ + {0x9198, 0xe981ad}, /* U+906D */ + {0x9199, 0xe98e97}, /* U+9397 */ + {0x919a, 0xe99c9c}, /* U+971C */ + {0x919b, 0xe9a892}, /* U+9A12 */ + {0x919c, 0xe5838f}, /* U+50CF */ + {0x919d, 0xe5a297}, /* U+5897 */ + {0x919e, 0xe6868e}, /* U+618E */ + {0x919f, 0xe88793}, /* U+81D3 */ + {0x91a0, 0xe894b5}, /* U+8535 */ + {0x91a1, 0xe8b488}, /* U+8D08 */ + {0x91a2, 0xe980a0}, /* U+9020 */ + {0x91a3, 0xe4bf83}, /* U+4FC3 */ + {0x91a4, 0xe581b4}, /* U+5074 */ + {0x91a5, 0xe58987}, /* U+5247 */ + {0x91a6, 0xe58db3}, /* U+5373 */ + {0x91a7, 0xe681af}, /* U+606F */ + {0x91a8, 0xe68d89}, /* U+6349 */ + {0x91a9, 0xe69d9f}, /* U+675F */ + {0x91aa, 0xe6b8ac}, /* U+6E2C */ + {0x91ab, 0xe8b6b3}, /* U+8DB3 */ + {0x91ac, 0xe9809f}, /* U+901F */ + {0x91ad, 0xe4bf97}, /* U+4FD7 */ + {0x91ae, 0xe5b19e}, /* U+5C5E */ + {0x91af, 0xe8b38a}, /* U+8CCA */ + {0x91b0, 0xe6978f}, /* U+65CF */ + {0x91b1, 0xe7b69a}, /* U+7D9A */ + {0x91b2, 0xe58d92}, /* U+5352 */ + {0x91b3, 0xe8a296}, /* U+8896 */ + {0x91b4, 0xe585b6}, /* U+5176 */ + {0x91b5, 0xe68f83}, /* U+63C3 */ + {0x91b6, 0xe5ad98}, /* U+5B58 */ + {0x91b7, 0xe5adab}, /* U+5B6B */ + {0x91b8, 0xe5b08a}, /* U+5C0A */ + {0x91b9, 0xe6908d}, /* U+640D */ + {0x91ba, 0xe69d91}, /* U+6751 */ + {0x91bb, 0xe9819c}, /* U+905C */ + {0x91bc, 0xe4bb96}, /* U+4ED6 */ + {0x91bd, 0xe5a49a}, /* U+591A */ + {0x91be, 0xe5a4aa}, /* U+592A */ + {0x91bf, 0xe6b1b0}, /* U+6C70 */ + {0x91c0, 0xe8a991}, /* U+8A51 */ + {0x91c1, 0xe594be}, /* U+553E */ + {0x91c2, 0xe5a095}, /* U+5815 */ + {0x91c3, 0xe5a6a5}, /* U+59A5 */ + {0x91c4, 0xe683b0}, /* U+60F0 */ + {0x91c5, 0xe68993}, /* U+6253 */ + {0x91c6, 0xe69f81}, /* U+67C1 */ + {0x91c7, 0xe888b5}, /* U+8235 */ + {0x91c8, 0xe6a595}, /* U+6955 */ + {0x91c9, 0xe99980}, /* U+9640 */ + {0x91ca, 0xe9a784}, /* U+99C4 */ + {0x91cb, 0xe9a8a8}, /* U+9A28 */ + {0x91cc, 0xe4bd93}, /* U+4F53 */ + {0x91cd, 0xe5a086}, /* U+5806 */ + {0x91ce, 0xe5afbe}, /* U+5BFE */ + {0x91cf, 0xe88090}, /* U+8010 */ + {0x91d0, 0xe5b2b1}, /* U+5CB1 */ + {0x91d1, 0xe5b8af}, /* U+5E2F */ + {0x91d2, 0xe5be85}, /* U+5F85 */ + {0x91d3, 0xe680a0}, /* U+6020 */ + {0x91d4, 0xe6858b}, /* U+614B */ + {0x91d5, 0xe688b4}, /* U+6234 */ + {0x91d6, 0xe69bbf}, /* U+66FF */ + {0x91d7, 0xe6b3b0}, /* U+6CF0 */ + {0x91d8, 0xe6bb9e}, /* U+6EDE */ + {0x91d9, 0xe8838e}, /* U+80CE */ + {0x91da, 0xe885bf}, /* U+817F */ + {0x91db, 0xe88b94}, /* U+82D4 */ + {0x91dc, 0xe8a28b}, /* U+888B */ + {0x91dd, 0xe8b2b8}, /* U+8CB8 */ + {0x91de, 0xe98080}, /* U+9000 */ + {0x91df, 0xe980ae}, /* U+902E */ + {0x91e0, 0xe99a8a}, /* U+968A */ + {0x91e1, 0xe9bb9b}, /* U+9EDB */ + {0x91e2, 0xe9af9b}, /* U+9BDB */ + {0x91e3, 0xe4bba3}, /* U+4EE3 */ + {0x91e4, 0xe58fb0}, /* U+53F0 */ + {0x91e5, 0xe5a4a7}, /* U+5927 */ + {0x91e6, 0xe7acac}, /* U+7B2C */ + {0x91e7, 0xe9868d}, /* U+918D */ + {0x91e8, 0xe9a18c}, /* U+984C */ + {0x91e9, 0xe9b7b9}, /* U+9DF9 */ + {0x91ea, 0xe6bb9d}, /* U+6EDD */ + {0x91eb, 0xe780a7}, /* U+7027 */ + {0x91ec, 0xe58d93}, /* U+5353 */ + {0x91ed, 0xe59584}, /* U+5544 */ + {0x91ee, 0xe5ae85}, /* U+5B85 */ + {0x91ef, 0xe68998}, /* U+6258 */ + {0x91f0, 0xe68a9e}, /* U+629E */ + {0x91f1, 0xe68b93}, /* U+62D3 */ + {0x91f2, 0xe6b2a2}, /* U+6CA2 */ + {0x91f3, 0xe6bfaf}, /* U+6FEF */ + {0x91f4, 0xe790a2}, /* U+7422 */ + {0x91f5, 0xe8a897}, /* U+8A17 */ + {0x91f6, 0xe990b8}, /* U+9438 */ + {0x91f7, 0xe6bf81}, /* U+6FC1 */ + {0x91f8, 0xe8abbe}, /* U+8AFE */ + {0x91f9, 0xe88cb8}, /* U+8338 */ + {0x91fa, 0xe587a7}, /* U+51E7 */ + {0x91fb, 0xe89bb8}, /* U+86F8 */ + {0x91fc, 0xe58faa}, /* U+53EA */ + {0x9240, 0xe58fa9}, /* U+53E9 */ + {0x9241, 0xe4bd86}, /* U+4F46 */ + {0x9242, 0xe98194}, /* U+9054 */ + {0x9243, 0xe8beb0}, /* U+8FB0 */ + {0x9244, 0xe5a5aa}, /* U+596A */ + {0x9245, 0xe884b1}, /* U+8131 */ + {0x9246, 0xe5b7bd}, /* U+5DFD */ + {0x9247, 0xe7abaa}, /* U+7AEA */ + {0x9248, 0xe8bebf}, /* U+8FBF */ + {0x9249, 0xe6a39a}, /* U+68DA */ + {0x924a, 0xe8b0b7}, /* U+8C37 */ + {0x924b, 0xe78bb8}, /* U+72F8 */ + {0x924c, 0xe9b188}, /* U+9C48 */ + {0x924d, 0xe6a8bd}, /* U+6A3D */ + {0x924e, 0xe8aab0}, /* U+8AB0 */ + {0x924f, 0xe4b8b9}, /* U+4E39 */ + {0x9250, 0xe58d98}, /* U+5358 */ + {0x9251, 0xe59886}, /* U+5606 */ + {0x9252, 0xe59da6}, /* U+5766 */ + {0x9253, 0xe68b85}, /* U+62C5 */ + {0x9254, 0xe68ea2}, /* U+63A2 */ + {0x9255, 0xe697a6}, /* U+65E6 */ + {0x9256, 0xe6ad8e}, /* U+6B4E */ + {0x9257, 0xe6b7a1}, /* U+6DE1 */ + {0x9258, 0xe6b99b}, /* U+6E5B */ + {0x9259, 0xe782ad}, /* U+70AD */ + {0x925a, 0xe79fad}, /* U+77ED */ + {0x925b, 0xe7abaf}, /* U+7AEF */ + {0x925c, 0xe7aeaa}, /* U+7BAA */ + {0x925d, 0xe7b6bb}, /* U+7DBB */ + {0x925e, 0xe880bd}, /* U+803D */ + {0x925f, 0xe88386}, /* U+80C6 */ + {0x9260, 0xe89b8b}, /* U+86CB */ + {0x9261, 0xe8aa95}, /* U+8A95 */ + {0x9262, 0xe98d9b}, /* U+935B */ + {0x9263, 0xe59ba3}, /* U+56E3 */ + {0x9264, 0xe5a387}, /* U+58C7 */ + {0x9265, 0xe5bcbe}, /* U+5F3E */ + {0x9266, 0xe696ad}, /* U+65AD */ + {0x9267, 0xe69a96}, /* U+6696 */ + {0x9268, 0xe6aa80}, /* U+6A80 */ + {0x9269, 0xe6aeb5}, /* U+6BB5 */ + {0x926a, 0xe794b7}, /* U+7537 */ + {0x926b, 0xe8ab87}, /* U+8AC7 */ + {0x926c, 0xe580a4}, /* U+5024 */ + {0x926d, 0xe79fa5}, /* U+77E5 */ + {0x926e, 0xe59cb0}, /* U+5730 */ + {0x926f, 0xe5bc9b}, /* U+5F1B */ + {0x9270, 0xe681a5}, /* U+6065 */ + {0x9271, 0xe699ba}, /* U+667A */ + {0x9272, 0xe6b1a0}, /* U+6C60 */ + {0x9273, 0xe797b4}, /* U+75F4 */ + {0x9274, 0xe7a89a}, /* U+7A1A */ + {0x9275, 0xe7bdae}, /* U+7F6E */ + {0x9276, 0xe887b4}, /* U+81F4 */ + {0x9277, 0xe89c98}, /* U+8718 */ + {0x9278, 0xe98185}, /* U+9045 */ + {0x9279, 0xe9a6b3}, /* U+99B3 */ + {0x927a, 0xe7af89}, /* U+7BC9 */ + {0x927b, 0xe7959c}, /* U+755C */ + {0x927c, 0xe7abb9}, /* U+7AF9 */ + {0x927d, 0xe7ad91}, /* U+7B51 */ + {0x927e, 0xe89384}, /* U+84C4 */ + {0x9280, 0xe98090}, /* U+9010 */ + {0x9281, 0xe7a7a9}, /* U+79E9 */ + {0x9282, 0xe7aa92}, /* U+7A92 */ + {0x9283, 0xe88cb6}, /* U+8336 */ + {0x9284, 0xe5aba1}, /* U+5AE1 */ + {0x9285, 0xe79d80}, /* U+7740 */ + {0x9286, 0xe4b8ad}, /* U+4E2D */ + {0x9287, 0xe4bbb2}, /* U+4EF2 */ + {0x9288, 0xe5ae99}, /* U+5B99 */ + {0x9289, 0xe5bfa0}, /* U+5FE0 */ + {0x928a, 0xe68abd}, /* U+62BD */ + {0x928b, 0xe698bc}, /* U+663C */ + {0x928c, 0xe69fb1}, /* U+67F1 */ + {0x928d, 0xe6b3a8}, /* U+6CE8 */ + {0x928e, 0xe899ab}, /* U+866B */ + {0x928f, 0xe8a1b7}, /* U+8877 */ + {0x9290, 0xe8a8bb}, /* U+8A3B */ + {0x9291, 0xe9858e}, /* U+914E */ + {0x9292, 0xe98bb3}, /* U+92F3 */ + {0x9293, 0xe9a790}, /* U+99D0 */ + {0x9294, 0xe6a897}, /* U+6A17 */ + {0x9295, 0xe780a6}, /* U+7026 */ + {0x9296, 0xe78caa}, /* U+732A */ + {0x9297, 0xe88ba7}, /* U+82E7 */ + {0x9298, 0xe89197}, /* U+8457 */ + {0x9299, 0xe8b2af}, /* U+8CAF */ + {0x929a, 0xe4b881}, /* U+4E01 */ + {0x929b, 0xe58586}, /* U+5146 */ + {0x929c, 0xe5878b}, /* U+51CB */ + {0x929d, 0xe5968b}, /* U+558B */ + {0x929e, 0xe5afb5}, /* U+5BF5 */ + {0x929f, 0xe5b896}, /* U+5E16 */ + {0x92a0, 0xe5b8b3}, /* U+5E33 */ + {0x92a1, 0xe5ba81}, /* U+5E81 */ + {0x92a2, 0xe5bc94}, /* U+5F14 */ + {0x92a3, 0xe5bcb5}, /* U+5F35 */ + {0x92a4, 0xe5bdab}, /* U+5F6B */ + {0x92a5, 0xe5beb4}, /* U+5FB4 */ + {0x92a6, 0xe687b2}, /* U+61F2 */ + {0x92a7, 0xe68c91}, /* U+6311 */ + {0x92a8, 0xe69aa2}, /* U+66A2 */ + {0x92a9, 0xe69c9d}, /* U+671D */ + {0x92aa, 0xe6bdae}, /* U+6F6E */ + {0x92ab, 0xe78992}, /* U+7252 */ + {0x92ac, 0xe794ba}, /* U+753A */ + {0x92ad, 0xe79cba}, /* U+773A */ + {0x92ae, 0xe881b4}, /* U+8074 */ + {0x92af, 0xe884b9}, /* U+8139 */ + {0x92b0, 0xe885b8}, /* U+8178 */ + {0x92b1, 0xe89db6}, /* U+8776 */ + {0x92b2, 0xe8aabf}, /* U+8ABF */ + {0x92b3, 0xe8ab9c}, /* U+8ADC */ + {0x92b4, 0xe8b685}, /* U+8D85 */ + {0x92b5, 0xe8b7b3}, /* U+8DF3 */ + {0x92b6, 0xe98a9a}, /* U+929A */ + {0x92b7, 0xe995b7}, /* U+9577 */ + {0x92b8, 0xe9a082}, /* U+9802 */ + {0x92b9, 0xe9b3a5}, /* U+9CE5 */ + {0x92ba, 0xe58b85}, /* U+52C5 */ + {0x92bb, 0xe68d97}, /* U+6357 */ + {0x92bc, 0xe79bb4}, /* U+76F4 */ + {0x92bd, 0xe69c95}, /* U+6715 */ + {0x92be, 0xe6b288}, /* U+6C88 */ + {0x92bf, 0xe78f8d}, /* U+73CD */ + {0x92c0, 0xe8b383}, /* U+8CC3 */ + {0x92c1, 0xe98eae}, /* U+93AE */ + {0x92c2, 0xe999b3}, /* U+9673 */ + {0x92c3, 0xe6b4a5}, /* U+6D25 */ + {0x92c4, 0xe5a29c}, /* U+589C */ + {0x92c5, 0xe6a48e}, /* U+690E */ + {0x92c6, 0xe6a78c}, /* U+69CC */ + {0x92c7, 0xe8bfbd}, /* U+8FFD */ + {0x92c8, 0xe98e9a}, /* U+939A */ + {0x92c9, 0xe7979b}, /* U+75DB */ + {0x92ca, 0xe9809a}, /* U+901A */ + {0x92cb, 0xe5a19a}, /* U+585A */ + {0x92cc, 0xe6a082}, /* U+6802 */ + {0x92cd, 0xe68eb4}, /* U+63B4 */ + {0x92ce, 0xe6a7bb}, /* U+69FB */ + {0x92cf, 0xe4bd83}, /* U+4F43 */ + {0x92d0, 0xe6bcac}, /* U+6F2C */ + {0x92d1, 0xe69f98}, /* U+67D8 */ + {0x92d2, 0xe8bebb}, /* U+8FBB */ + {0x92d3, 0xe894a6}, /* U+8526 */ + {0x92d4, 0xe7b6b4}, /* U+7DB4 */ + {0x92d5, 0xe98d94}, /* U+9354 */ + {0x92d6, 0xe6a4bf}, /* U+693F */ + {0x92d7, 0xe6bdb0}, /* U+6F70 */ + {0x92d8, 0xe59daa}, /* U+576A */ + {0x92d9, 0xe5a3b7}, /* U+58F7 */ + {0x92da, 0xe5acac}, /* U+5B2C */ + {0x92db, 0xe7b4ac}, /* U+7D2C */ + {0x92dc, 0xe788aa}, /* U+722A */ + {0x92dd, 0xe5908a}, /* U+540A */ + {0x92de, 0xe987a3}, /* U+91E3 */ + {0x92df, 0xe9b6b4}, /* U+9DB4 */ + {0x92e0, 0xe4baad}, /* U+4EAD */ + {0x92e1, 0xe4bd8e}, /* U+4F4E */ + {0x92e2, 0xe5819c}, /* U+505C */ + {0x92e3, 0xe581b5}, /* U+5075 */ + {0x92e4, 0xe58983}, /* U+5243 */ + {0x92e5, 0xe8b29e}, /* U+8C9E */ + {0x92e6, 0xe59188}, /* U+5448 */ + {0x92e7, 0xe5a0a4}, /* U+5824 */ + {0x92e8, 0xe5ae9a}, /* U+5B9A */ + {0x92e9, 0xe5b89d}, /* U+5E1D */ + {0x92ea, 0xe5ba95}, /* U+5E95 */ + {0x92eb, 0xe5baad}, /* U+5EAD */ + {0x92ec, 0xe5bbb7}, /* U+5EF7 */ + {0x92ed, 0xe5bc9f}, /* U+5F1F */ + {0x92ee, 0xe6828c}, /* U+608C */ + {0x92ef, 0xe68ab5}, /* U+62B5 */ + {0x92f0, 0xe68cba}, /* U+633A */ + {0x92f1, 0xe68f90}, /* U+63D0 */ + {0x92f2, 0xe6a2af}, /* U+68AF */ + {0x92f3, 0xe6b180}, /* U+6C40 */ + {0x92f4, 0xe7a287}, /* U+7887 */ + {0x92f5, 0xe7a68e}, /* U+798E */ + {0x92f6, 0xe7a88b}, /* U+7A0B */ + {0x92f7, 0xe7b7a0}, /* U+7DE0 */ + {0x92f8, 0xe88987}, /* U+8247 */ + {0x92f9, 0xe8a882}, /* U+8A02 */ + {0x92fa, 0xe8aba6}, /* U+8AE6 */ + {0x92fb, 0xe8b984}, /* U+8E44 */ + {0x92fc, 0xe98093}, /* U+9013 */ + {0x9340, 0xe982b8}, /* U+90B8 */ + {0x9341, 0xe984ad}, /* U+912D */ + {0x9342, 0xe98798}, /* U+91D8 */ + {0x9343, 0xe9bc8e}, /* U+9F0E */ + {0x9344, 0xe6b3a5}, /* U+6CE5 */ + {0x9345, 0xe69198}, /* U+6458 */ + {0x9346, 0xe693a2}, /* U+64E2 */ + {0x9347, 0xe695b5}, /* U+6575 */ + {0x9348, 0xe6bbb4}, /* U+6EF4 */ + {0x9349, 0xe79a84}, /* U+7684 */ + {0x934a, 0xe7ac9b}, /* U+7B1B */ + {0x934b, 0xe981a9}, /* U+9069 */ + {0x934c, 0xe98f91}, /* U+93D1 */ + {0x934d, 0xe6baba}, /* U+6EBA */ + {0x934e, 0xe593b2}, /* U+54F2 */ + {0x934f, 0xe5beb9}, /* U+5FB9 */ + {0x9350, 0xe692a4}, /* U+64A4 */ + {0x9351, 0xe8bd8d}, /* U+8F4D */ + {0x9352, 0xe8bfad}, /* U+8FED */ + {0x9353, 0xe98984}, /* U+9244 */ + {0x9354, 0xe585b8}, /* U+5178 */ + {0x9355, 0xe5a1ab}, /* U+586B */ + {0x9356, 0xe5a4a9}, /* U+5929 */ + {0x9357, 0xe5b195}, /* U+5C55 */ + {0x9358, 0xe5ba97}, /* U+5E97 */ + {0x9359, 0xe6b7bb}, /* U+6DFB */ + {0x935a, 0xe7ba8f}, /* U+7E8F */ + {0x935b, 0xe7949c}, /* U+751C */ + {0x935c, 0xe8b2bc}, /* U+8CBC */ + {0x935d, 0xe8bba2}, /* U+8EE2 */ + {0x935e, 0xe9a19b}, /* U+985B */ + {0x935f, 0xe782b9}, /* U+70B9 */ + {0x9360, 0xe4bc9d}, /* U+4F1D */ + {0x9361, 0xe6aebf}, /* U+6BBF */ + {0x9362, 0xe6beb1}, /* U+6FB1 */ + {0x9363, 0xe794b0}, /* U+7530 */ + {0x9364, 0xe99bbb}, /* U+96FB */ + {0x9365, 0xe5858e}, /* U+514E */ + {0x9366, 0xe59090}, /* U+5410 */ + {0x9367, 0xe5a0b5}, /* U+5835 */ + {0x9368, 0xe5a197}, /* U+5857 */ + {0x9369, 0xe5a6ac}, /* U+59AC */ + {0x936a, 0xe5b1a0}, /* U+5C60 */ + {0x936b, 0xe5be92}, /* U+5F92 */ + {0x936c, 0xe69697}, /* U+6597 */ + {0x936d, 0xe69d9c}, /* U+675C */ + {0x936e, 0xe6b8a1}, /* U+6E21 */ + {0x936f, 0xe799bb}, /* U+767B */ + {0x9370, 0xe88f9f}, /* U+83DF */ + {0x9371, 0xe8b3ad}, /* U+8CED */ + {0x9372, 0xe98094}, /* U+9014 */ + {0x9373, 0xe983bd}, /* U+90FD */ + {0x9374, 0xe98d8d}, /* U+934D */ + {0x9375, 0xe7a0a5}, /* U+7825 */ + {0x9376, 0xe7a0ba}, /* U+783A */ + {0x9377, 0xe58aaa}, /* U+52AA */ + {0x9378, 0xe5baa6}, /* U+5EA6 */ + {0x9379, 0xe59c9f}, /* U+571F */ + {0x937a, 0xe5a5b4}, /* U+5974 */ + {0x937b, 0xe68092}, /* U+6012 */ + {0x937c, 0xe58092}, /* U+5012 */ + {0x937d, 0xe5859a}, /* U+515A */ + {0x937e, 0xe586ac}, /* U+51AC */ + {0x9380, 0xe5878d}, /* U+51CD */ + {0x9381, 0xe58880}, /* U+5200 */ + {0x9382, 0xe59490}, /* U+5510 */ + {0x9383, 0xe5a194}, /* U+5854 */ + {0x9384, 0xe5a198}, /* U+5858 */ + {0x9385, 0xe5a597}, /* U+5957 */ + {0x9386, 0xe5ae95}, /* U+5B95 */ + {0x9387, 0xe5b3b6}, /* U+5CF6 */ + {0x9388, 0xe5b68b}, /* U+5D8B */ + {0x9389, 0xe682bc}, /* U+60BC */ + {0x938a, 0xe68a95}, /* U+6295 */ + {0x938b, 0xe690ad}, /* U+642D */ + {0x938c, 0xe69db1}, /* U+6771 */ + {0x938d, 0xe6a183}, /* U+6843 */ + {0x938e, 0xe6a2bc}, /* U+68BC */ + {0x938f, 0xe6a39f}, /* U+68DF */ + {0x9390, 0xe79b97}, /* U+76D7 */ + {0x9391, 0xe6b798}, /* U+6DD8 */ + {0x9392, 0xe6b9af}, /* U+6E6F */ + {0x9393, 0xe6b69b}, /* U+6D9B */ + {0x9394, 0xe781af}, /* U+706F */ + {0x9395, 0xe78788}, /* U+71C8 */ + {0x9396, 0xe5bd93}, /* U+5F53 */ + {0x9397, 0xe79798}, /* U+75D8 */ + {0x9398, 0xe7a5b7}, /* U+7977 */ + {0x9399, 0xe7ad89}, /* U+7B49 */ + {0x939a, 0xe7ad94}, /* U+7B54 */ + {0x939b, 0xe7ad92}, /* U+7B52 */ + {0x939c, 0xe7b396}, /* U+7CD6 */ + {0x939d, 0xe7b5b1}, /* U+7D71 */ + {0x939e, 0xe588b0}, /* U+5230 */ + {0x939f, 0xe891a3}, /* U+8463 */ + {0x93a0, 0xe895a9}, /* U+8569 */ + {0x93a1, 0xe897a4}, /* U+85E4 */ + {0x93a2, 0xe8a88e}, /* U+8A0E */ + {0x93a3, 0xe8ac84}, /* U+8B04 */ + {0x93a4, 0xe8b186}, /* U+8C46 */ + {0x93a5, 0xe8b88f}, /* U+8E0F */ + {0x93a6, 0xe98083}, /* U+9003 */ + {0x93a7, 0xe9808f}, /* U+900F */ + {0x93a8, 0xe99099}, /* U+9419 */ + {0x93a9, 0xe999b6}, /* U+9676 */ + {0x93aa, 0xe9a0ad}, /* U+982D */ + {0x93ab, 0xe9a8b0}, /* U+9A30 */ + {0x93ac, 0xe99798}, /* U+95D8 */ + {0x93ad, 0xe5838d}, /* U+50CD */ + {0x93ae, 0xe58b95}, /* U+52D5 */ + {0x93af, 0xe5908c}, /* U+540C */ + {0x93b0, 0xe5a082}, /* U+5802 */ + {0x93b1, 0xe5b08e}, /* U+5C0E */ + {0x93b2, 0xe686a7}, /* U+61A7 */ + {0x93b3, 0xe6929e}, /* U+649E */ + {0x93b4, 0xe6b49e}, /* U+6D1E */ + {0x93b5, 0xe79eb3}, /* U+77B3 */ + {0x93b6, 0xe7aba5}, /* U+7AE5 */ + {0x93b7, 0xe883b4}, /* U+80F4 */ + {0x93b8, 0xe89084}, /* U+8404 */ + {0x93b9, 0xe98193}, /* U+9053 */ + {0x93ba, 0xe98a85}, /* U+9285 */ + {0x93bb, 0xe5b3a0}, /* U+5CE0 */ + {0x93bc, 0xe9b487}, /* U+9D07 */ + {0x93bd, 0xe58cbf}, /* U+533F */ + {0x93be, 0xe5be97}, /* U+5F97 */ + {0x93bf, 0xe5beb3}, /* U+5FB3 */ + {0x93c0, 0xe6b69c}, /* U+6D9C */ + {0x93c1, 0xe789b9}, /* U+7279 */ + {0x93c2, 0xe79da3}, /* U+7763 */ + {0x93c3, 0xe7a6bf}, /* U+79BF */ + {0x93c4, 0xe7afa4}, /* U+7BE4 */ + {0x93c5, 0xe6af92}, /* U+6BD2 */ + {0x93c6, 0xe78bac}, /* U+72EC */ + {0x93c7, 0xe8aaad}, /* U+8AAD */ + {0x93c8, 0xe6a083}, /* U+6803 */ + {0x93c9, 0xe6a9a1}, /* U+6A61 */ + {0x93ca, 0xe587b8}, /* U+51F8 */ + {0x93cb, 0xe7aa81}, /* U+7A81 */ + {0x93cc, 0xe6a4b4}, /* U+6934 */ + {0x93cd, 0xe5b18a}, /* U+5C4A */ + {0x93ce, 0xe9b3b6}, /* U+9CF6 */ + {0x93cf, 0xe88bab}, /* U+82EB */ + {0x93d0, 0xe5af85}, /* U+5BC5 */ + {0x93d1, 0xe98589}, /* U+9149 */ + {0x93d2, 0xe7809e}, /* U+701E */ + {0x93d3, 0xe599b8}, /* U+5678 */ + {0x93d4, 0xe5b1af}, /* U+5C6F */ + {0x93d5, 0xe68387}, /* U+60C7 */ + {0x93d6, 0xe695a6}, /* U+6566 */ + {0x93d7, 0xe6b28c}, /* U+6C8C */ + {0x93d8, 0xe8b19a}, /* U+8C5A */ + {0x93d9, 0xe98181}, /* U+9041 */ + {0x93da, 0xe9a093}, /* U+9813 */ + {0x93db, 0xe59191}, /* U+5451 */ + {0x93dc, 0xe69b87}, /* U+66C7 */ + {0x93dd, 0xe9888d}, /* U+920D */ + {0x93de, 0xe5a588}, /* U+5948 */ + {0x93df, 0xe982a3}, /* U+90A3 */ + {0x93e0, 0xe58685}, /* U+5185 */ + {0x93e1, 0xe4b98d}, /* U+4E4D */ + {0x93e2, 0xe587aa}, /* U+51EA */ + {0x93e3, 0xe89699}, /* U+8599 */ + {0x93e4, 0xe8ac8e}, /* U+8B0E */ + {0x93e5, 0xe78198}, /* U+7058 */ + {0x93e6, 0xe68dba}, /* U+637A */ + {0x93e7, 0xe98d8b}, /* U+934B */ + {0x93e8, 0xe6a5a2}, /* U+6962 */ + {0x93e9, 0xe9a6b4}, /* U+99B4 */ + {0x93ea, 0xe7b884}, /* U+7E04 */ + {0x93eb, 0xe795b7}, /* U+7577 */ + {0x93ec, 0xe58d97}, /* U+5357 */ + {0x93ed, 0xe6a5a0}, /* U+6960 */ + {0x93ee, 0xe8bb9f}, /* U+8EDF */ + {0x93ef, 0xe99ba3}, /* U+96E3 */ + {0x93f0, 0xe6b19d}, /* U+6C5D */ + {0x93f1, 0xe4ba8c}, /* U+4E8C */ + {0x93f2, 0xe5b0bc}, /* U+5C3C */ + {0x93f3, 0xe5bc90}, /* U+5F10 */ + {0x93f4, 0xe8bfa9}, /* U+8FE9 */ + {0x93f5, 0xe58c82}, /* U+5302 */ + {0x93f6, 0xe8b391}, /* U+8CD1 */ + {0x93f7, 0xe88289}, /* U+8089 */ + {0x93f8, 0xe899b9}, /* U+8679 */ + {0x93f9, 0xe5bbbf}, /* U+5EFF */ + {0x93fa, 0xe697a5}, /* U+65E5 */ + {0x93fb, 0xe4b9b3}, /* U+4E73 */ + {0x93fc, 0xe585a5}, /* U+5165 */ + {0x9440, 0xe5a682}, /* U+5982 */ + {0x9441, 0xe5b0bf}, /* U+5C3F */ + {0x9442, 0xe99fae}, /* U+97EE */ + {0x9443, 0xe4bbbb}, /* U+4EFB */ + {0x9444, 0xe5a68a}, /* U+598A */ + {0x9445, 0xe5bf8d}, /* U+5FCD */ + {0x9446, 0xe8aa8d}, /* U+8A8D */ + {0x9447, 0xe6bfa1}, /* U+6FE1 */ + {0x9448, 0xe7a6b0}, /* U+79B0 */ + {0x9449, 0xe7a5a2}, /* U+7962 */ + {0x944a, 0xe5afa7}, /* U+5BE7 */ + {0x944b, 0xe891b1}, /* U+8471 */ + {0x944c, 0xe78cab}, /* U+732B */ + {0x944d, 0xe786b1}, /* U+71B1 */ + {0x944e, 0xe5b9b4}, /* U+5E74 */ + {0x944f, 0xe5bfb5}, /* U+5FF5 */ + {0x9450, 0xe68dbb}, /* U+637B */ + {0x9451, 0xe6929a}, /* U+649A */ + {0x9452, 0xe78783}, /* U+71C3 */ + {0x9453, 0xe7b298}, /* U+7C98 */ + {0x9454, 0xe4b983}, /* U+4E43 */ + {0x9455, 0xe5bbbc}, /* U+5EFC */ + {0x9456, 0xe4b98b}, /* U+4E4B */ + {0x9457, 0xe59f9c}, /* U+57DC */ + {0x9458, 0xe59aa2}, /* U+56A2 */ + {0x9459, 0xe682a9}, /* U+60A9 */ + {0x945a, 0xe6bf83}, /* U+6FC3 */ + {0x945b, 0xe7b48d}, /* U+7D0D */ + {0x945c, 0xe883bd}, /* U+80FD */ + {0x945d, 0xe884b3}, /* U+8133 */ + {0x945e, 0xe886bf}, /* U+81BF */ + {0x945f, 0xe8beb2}, /* U+8FB2 */ + {0x9460, 0xe8a697}, /* U+8997 */ + {0x9461, 0xe89aa4}, /* U+86A4 */ + {0x9462, 0xe5b7b4}, /* U+5DF4 */ + {0x9463, 0xe68a8a}, /* U+628A */ + {0x9464, 0xe692ad}, /* U+64AD */ + {0x9465, 0xe8a687}, /* U+8987 */ + {0x9466, 0xe69db7}, /* U+6777 */ + {0x9467, 0xe6b3a2}, /* U+6CE2 */ + {0x9468, 0xe6b4be}, /* U+6D3E */ + {0x9469, 0xe790b6}, /* U+7436 */ + {0x946a, 0xe7a0b4}, /* U+7834 */ + {0x946b, 0xe5a986}, /* U+5A46 */ + {0x946c, 0xe7bdb5}, /* U+7F75 */ + {0x946d, 0xe88aad}, /* U+82AD */ + {0x946e, 0xe9a6ac}, /* U+99AC */ + {0x946f, 0xe4bfb3}, /* U+4FF3 */ + {0x9470, 0xe5bb83}, /* U+5EC3 */ + {0x9471, 0xe68b9d}, /* U+62DD */ + {0x9472, 0xe68e92}, /* U+6392 */ + {0x9473, 0xe69597}, /* U+6557 */ + {0x9474, 0xe69daf}, /* U+676F */ + {0x9475, 0xe79b83}, /* U+76C3 */ + {0x9476, 0xe7898c}, /* U+724C */ + {0x9477, 0xe8838c}, /* U+80CC */ + {0x9478, 0xe882ba}, /* U+80BA */ + {0x9479, 0xe8bca9}, /* U+8F29 */ + {0x947a, 0xe9858d}, /* U+914D */ + {0x947b, 0xe5808d}, /* U+500D */ + {0x947c, 0xe59fb9}, /* U+57F9 */ + {0x947d, 0xe5aa92}, /* U+5A92 */ + {0x947e, 0xe6a285}, /* U+6885 */ + {0x9480, 0xe6a5b3}, /* U+6973 */ + {0x9481, 0xe785a4}, /* U+7164 */ + {0x9482, 0xe78bbd}, /* U+72FD */ + {0x9483, 0xe8b2b7}, /* U+8CB7 */ + {0x9484, 0xe5a3b2}, /* U+58F2 */ + {0x9485, 0xe8b3a0}, /* U+8CE0 */ + {0x9486, 0xe999aa}, /* U+966A */ + {0x9487, 0xe98099}, /* U+9019 */ + {0x9488, 0xe89dbf}, /* U+877F */ + {0x9489, 0xe7a7a4}, /* U+79E4 */ + {0x948a, 0xe79fa7}, /* U+77E7 */ + {0x948b, 0xe890a9}, /* U+8429 */ + {0x948c, 0xe4bcaf}, /* U+4F2F */ + {0x948d, 0xe589a5}, /* U+5265 */ + {0x948e, 0xe58d9a}, /* U+535A */ + {0x948f, 0xe68b8d}, /* U+62CD */ + {0x9490, 0xe69f8f}, /* U+67CF */ + {0x9491, 0xe6b38a}, /* U+6CCA */ + {0x9492, 0xe799bd}, /* U+767D */ + {0x9493, 0xe7ae94}, /* U+7B94 */ + {0x9494, 0xe7b295}, /* U+7C95 */ + {0x9495, 0xe888b6}, /* U+8236 */ + {0x9496, 0xe89684}, /* U+8584 */ + {0x9497, 0xe8bfab}, /* U+8FEB */ + {0x9498, 0xe69b9d}, /* U+66DD */ + {0x9499, 0xe6bca0}, /* U+6F20 */ + {0x949a, 0xe78886}, /* U+7206 */ + {0x949b, 0xe7b89b}, /* U+7E1B */ + {0x949c, 0xe88eab}, /* U+83AB */ + {0x949d, 0xe9a781}, /* U+99C1 */ + {0x949e, 0xe9baa6}, /* U+9EA6 */ + {0x949f, 0xe587bd}, /* U+51FD */ + {0x94a0, 0xe7aeb1}, /* U+7BB1 */ + {0x94a1, 0xe7a1b2}, /* U+7872 */ + {0x94a2, 0xe7aeb8}, /* U+7BB8 */ + {0x94a3, 0xe88287}, /* U+8087 */ + {0x94a4, 0xe7ad88}, /* U+7B48 */ + {0x94a5, 0xe6aba8}, /* U+6AE8 */ + {0x94a6, 0xe5b9a1}, /* U+5E61 */ + {0x94a7, 0xe8828c}, /* U+808C */ + {0x94a8, 0xe79591}, /* U+7551 */ + {0x94a9, 0xe795a0}, /* U+7560 */ + {0x94aa, 0xe585ab}, /* U+516B */ + {0x94ab, 0xe989a2}, /* U+9262 */ + {0x94ac, 0xe6ba8c}, /* U+6E8C */ + {0x94ad, 0xe799ba}, /* U+767A */ + {0x94ae, 0xe98697}, /* U+9197 */ + {0x94af, 0xe9abaa}, /* U+9AEA */ + {0x94b0, 0xe4bc90}, /* U+4F10 */ + {0x94b1, 0xe7bdb0}, /* U+7F70 */ + {0x94b2, 0xe68a9c}, /* U+629C */ + {0x94b3, 0xe7ad8f}, /* U+7B4F */ + {0x94b4, 0xe996a5}, /* U+95A5 */ + {0x94b5, 0xe9b3a9}, /* U+9CE9 */ + {0x94b6, 0xe599ba}, /* U+567A */ + {0x94b7, 0xe5a199}, /* U+5859 */ + {0x94b8, 0xe89ba4}, /* U+86E4 */ + {0x94b9, 0xe99abc}, /* U+96BC */ + {0x94ba, 0xe4bcb4}, /* U+4F34 */ + {0x94bb, 0xe588a4}, /* U+5224 */ + {0x94bc, 0xe58d8a}, /* U+534A */ + {0x94bd, 0xe58f8d}, /* U+53CD */ + {0x94be, 0xe58f9b}, /* U+53DB */ + {0x94bf, 0xe5b886}, /* U+5E06 */ + {0x94c0, 0xe690ac}, /* U+642C */ + {0x94c1, 0xe69691}, /* U+6591 */ + {0x94c2, 0xe69dbf}, /* U+677F */ + {0x94c3, 0xe6b0be}, /* U+6C3E */ + {0x94c4, 0xe6b18e}, /* U+6C4E */ + {0x94c5, 0xe78988}, /* U+7248 */ + {0x94c6, 0xe78aaf}, /* U+72AF */ + {0x94c7, 0xe78fad}, /* U+73ED */ + {0x94c8, 0xe79594}, /* U+7554 */ + {0x94c9, 0xe7b981}, /* U+7E41 */ + {0x94ca, 0xe888ac}, /* U+822C */ + {0x94cb, 0xe897a9}, /* U+85E9 */ + {0x94cc, 0xe8b2a9}, /* U+8CA9 */ + {0x94cd, 0xe7af84}, /* U+7BC4 */ + {0x94ce, 0xe98786}, /* U+91C6 */ + {0x94cf, 0xe785a9}, /* U+7169 */ + {0x94d0, 0xe9a092}, /* U+9812 */ + {0x94d1, 0xe9a3af}, /* U+98EF */ + {0x94d2, 0xe68cbd}, /* U+633D */ + {0x94d3, 0xe699a9}, /* U+6669 */ + {0x94d4, 0xe795aa}, /* U+756A */ + {0x94d5, 0xe79ba4}, /* U+76E4 */ + {0x94d6, 0xe7a390}, /* U+78D0 */ + {0x94d7, 0xe89583}, /* U+8543 */ + {0x94d8, 0xe89bae}, /* U+86EE */ + {0x94d9, 0xe58caa}, /* U+532A */ + {0x94da, 0xe58d91}, /* U+5351 */ + {0x94db, 0xe590a6}, /* U+5426 */ + {0x94dc, 0xe5a683}, /* U+5983 */ + {0x94dd, 0xe5ba87}, /* U+5E87 */ + {0x94de, 0xe5bdbc}, /* U+5F7C */ + {0x94df, 0xe682b2}, /* U+60B2 */ + {0x94e0, 0xe68989}, /* U+6249 */ + {0x94e1, 0xe689b9}, /* U+6279 */ + {0x94e2, 0xe68aab}, /* U+62AB */ + {0x94e3, 0xe69690}, /* U+6590 */ + {0x94e4, 0xe6af94}, /* U+6BD4 */ + {0x94e5, 0xe6b38c}, /* U+6CCC */ + {0x94e6, 0xe796b2}, /* U+75B2 */ + {0x94e7, 0xe79aae}, /* U+76AE */ + {0x94e8, 0xe7a291}, /* U+7891 */ + {0x94e9, 0xe7a798}, /* U+79D8 */ + {0x94ea, 0xe7b78b}, /* U+7DCB */ + {0x94eb, 0xe7bdb7}, /* U+7F77 */ + {0x94ec, 0xe882a5}, /* U+80A5 */ + {0x94ed, 0xe8a2ab}, /* U+88AB */ + {0x94ee, 0xe8aab9}, /* U+8AB9 */ + {0x94ef, 0xe8b2bb}, /* U+8CBB */ + {0x94f0, 0xe981bf}, /* U+907F */ + {0x94f1, 0xe99d9e}, /* U+975E */ + {0x94f2, 0xe9a39b}, /* U+98DB */ + {0x94f3, 0xe6a88b}, /* U+6A0B */ + {0x94f4, 0xe7b0b8}, /* U+7C38 */ + {0x94f5, 0xe58299}, /* U+5099 */ + {0x94f6, 0xe5b0be}, /* U+5C3E */ + {0x94f7, 0xe5beae}, /* U+5FAE */ + {0x94f8, 0xe69e87}, /* U+6787 */ + {0x94f9, 0xe6af98}, /* U+6BD8 */ + {0x94fa, 0xe790b5}, /* U+7435 */ + {0x94fb, 0xe79c89}, /* U+7709 */ + {0x94fc, 0xe7be8e}, /* U+7F8E */ + {0x9540, 0xe9bcbb}, /* U+9F3B */ + {0x9541, 0xe69f8a}, /* U+67CA */ + {0x9542, 0xe7a897}, /* U+7A17 */ + {0x9543, 0xe58cb9}, /* U+5339 */ + {0x9544, 0xe7968b}, /* U+758B */ + {0x9545, 0xe9abad}, /* U+9AED */ + {0x9546, 0xe5bda6}, /* U+5F66 */ + {0x9547, 0xe8869d}, /* U+819D */ + {0x9548, 0xe88fb1}, /* U+83F1 */ + {0x9549, 0xe88298}, /* U+8098 */ + {0x954a, 0xe5bcbc}, /* U+5F3C */ + {0x954b, 0xe5bf85}, /* U+5FC5 */ + {0x954c, 0xe795a2}, /* U+7562 */ + {0x954d, 0xe7ad86}, /* U+7B46 */ + {0x954e, 0xe980bc}, /* U+903C */ + {0x954f, 0xe6a1a7}, /* U+6867 */ + {0x9550, 0xe5a7ab}, /* U+59EB */ + {0x9551, 0xe5aa9b}, /* U+5A9B */ + {0x9552, 0xe7b490}, /* U+7D10 */ + {0x9553, 0xe799be}, /* U+767E */ + {0x9554, 0xe8acac}, /* U+8B2C */ + {0x9555, 0xe4bfb5}, /* U+4FF5 */ + {0x9556, 0xe5bdaa}, /* U+5F6A */ + {0x9557, 0xe6a899}, /* U+6A19 */ + {0x9558, 0xe6b0b7}, /* U+6C37 */ + {0x9559, 0xe6bc82}, /* U+6F02 */ + {0x955a, 0xe793a2}, /* U+74E2 */ + {0x955b, 0xe7a5a8}, /* U+7968 */ + {0x955c, 0xe8a1a8}, /* U+8868 */ + {0x955d, 0xe8a995}, /* U+8A55 */ + {0x955e, 0xe8b1b9}, /* U+8C79 */ + {0x955f, 0xe5bb9f}, /* U+5EDF */ + {0x9560, 0xe68f8f}, /* U+63CF */ + {0x9561, 0xe79785}, /* U+75C5 */ + {0x9562, 0xe7a792}, /* U+79D2 */ + {0x9563, 0xe88b97}, /* U+82D7 */ + {0x9564, 0xe98ca8}, /* U+9328 */ + {0x9565, 0xe98bb2}, /* U+92F2 */ + {0x9566, 0xe8929c}, /* U+849C */ + {0x9567, 0xe89bad}, /* U+86ED */ + {0x9568, 0xe9b0ad}, /* U+9C2D */ + {0x9569, 0xe59381}, /* U+54C1 */ + {0x956a, 0xe5bdac}, /* U+5F6C */ + {0x956b, 0xe6968c}, /* U+658C */ + {0x956c, 0xe6b59c}, /* U+6D5C */ + {0x956d, 0xe78095}, /* U+7015 */ + {0x956e, 0xe8b2a7}, /* U+8CA7 */ + {0x956f, 0xe8b393}, /* U+8CD3 */ + {0x9570, 0xe9a0bb}, /* U+983B */ + {0x9571, 0xe6958f}, /* U+654F */ + {0x9572, 0xe793b6}, /* U+74F6 */ + {0x9573, 0xe4b88d}, /* U+4E0D */ + {0x9574, 0xe4bb98}, /* U+4ED8 */ + {0x9575, 0xe59fa0}, /* U+57E0 */ + {0x9576, 0xe5a4ab}, /* U+592B */ + {0x9577, 0xe5a9a6}, /* U+5A66 */ + {0x9578, 0xe5af8c}, /* U+5BCC */ + {0x9579, 0xe586a8}, /* U+51A8 */ + {0x957a, 0xe5b883}, /* U+5E03 */ + {0x957b, 0xe5ba9c}, /* U+5E9C */ + {0x957c, 0xe68096}, /* U+6016 */ + {0x957d, 0xe689b6}, /* U+6276 */ + {0x957e, 0xe695b7}, /* U+6577 */ + {0x9580, 0xe696a7}, /* U+65A7 */ + {0x9581, 0xe699ae}, /* U+666E */ + {0x9582, 0xe6b5ae}, /* U+6D6E */ + {0x9583, 0xe788b6}, /* U+7236 */ + {0x9584, 0xe7aca6}, /* U+7B26 */ + {0x9585, 0xe88590}, /* U+8150 */ + {0x9586, 0xe8869a}, /* U+819A */ + {0x9587, 0xe88a99}, /* U+8299 */ + {0x9588, 0xe8ad9c}, /* U+8B5C */ + {0x9589, 0xe8b2a0}, /* U+8CA0 */ + {0x958a, 0xe8b3a6}, /* U+8CE6 */ + {0x958b, 0xe8b5b4}, /* U+8D74 */ + {0x958c, 0xe9989c}, /* U+961C */ + {0x958d, 0xe99984}, /* U+9644 */ + {0x958e, 0xe4beae}, /* U+4FAE */ + {0x958f, 0xe692ab}, /* U+64AB */ + {0x9590, 0xe6ada6}, /* U+6B66 */ + {0x9591, 0xe8889e}, /* U+821E */ + {0x9592, 0xe891a1}, /* U+8461 */ + {0x9593, 0xe895aa}, /* U+856A */ + {0x9594, 0xe983a8}, /* U+90E8 */ + {0x9595, 0xe5b081}, /* U+5C01 */ + {0x9596, 0xe6a593}, /* U+6953 */ + {0x9597, 0xe9a2a8}, /* U+98A8 */ + {0x9598, 0xe891ba}, /* U+847A */ + {0x9599, 0xe89597}, /* U+8557 */ + {0x959a, 0xe4bc8f}, /* U+4F0F */ + {0x959b, 0xe589af}, /* U+526F */ + {0x959c, 0xe5bea9}, /* U+5FA9 */ + {0x959d, 0xe5b985}, /* U+5E45 */ + {0x959e, 0xe69c8d}, /* U+670D */ + {0x959f, 0xe7a68f}, /* U+798F */ + {0x95a0, 0xe885b9}, /* U+8179 */ + {0x95a1, 0xe8a487}, /* U+8907 */ + {0x95a2, 0xe8a686}, /* U+8986 */ + {0x95a3, 0xe6b7b5}, /* U+6DF5 */ + {0x95a4, 0xe5bc97}, /* U+5F17 */ + {0x95a5, 0xe68995}, /* U+6255 */ + {0x95a6, 0xe6b2b8}, /* U+6CB8 */ + {0x95a7, 0xe4bb8f}, /* U+4ECF */ + {0x95a8, 0xe789a9}, /* U+7269 */ + {0x95a9, 0xe9ae92}, /* U+9B92 */ + {0x95aa, 0xe58886}, /* U+5206 */ + {0x95ab, 0xe590bb}, /* U+543B */ + {0x95ac, 0xe599b4}, /* U+5674 */ + {0x95ad, 0xe5a2b3}, /* U+58B3 */ + {0x95ae, 0xe686a4}, /* U+61A4 */ + {0x95af, 0xe689ae}, /* U+626E */ + {0x95b0, 0xe7849a}, /* U+711A */ + {0x95b1, 0xe5a5ae}, /* U+596E */ + {0x95b2, 0xe7b289}, /* U+7C89 */ + {0x95b3, 0xe7b39e}, /* U+7CDE */ + {0x95b4, 0xe7b49b}, /* U+7D1B */ + {0x95b5, 0xe99bb0}, /* U+96F0 */ + {0x95b6, 0xe69687}, /* U+6587 */ + {0x95b7, 0xe8819e}, /* U+805E */ + {0x95b8, 0xe4b899}, /* U+4E19 */ + {0x95b9, 0xe4bdb5}, /* U+4F75 */ + {0x95ba, 0xe585b5}, /* U+5175 */ + {0x95bb, 0xe5a180}, /* U+5840 */ + {0x95bc, 0xe5b9a3}, /* U+5E63 */ + {0x95bd, 0xe5b9b3}, /* U+5E73 */ + {0x95be, 0xe5bc8a}, /* U+5F0A */ + {0x95bf, 0xe69f84}, /* U+67C4 */ + {0x95c0, 0xe4b8a6}, /* U+4E26 */ + {0x95c1, 0xe894bd}, /* U+853D */ + {0x95c2, 0xe99689}, /* U+9589 */ + {0x95c3, 0xe9999b}, /* U+965B */ + {0x95c4, 0xe7b1b3}, /* U+7C73 */ + {0x95c5, 0xe9a081}, /* U+9801 */ + {0x95c6, 0xe583bb}, /* U+50FB */ + {0x95c7, 0xe5a381}, /* U+58C1 */ + {0x95c8, 0xe79996}, /* U+7656 */ + {0x95c9, 0xe7a2a7}, /* U+78A7 */ + {0x95ca, 0xe588a5}, /* U+5225 */ + {0x95cb, 0xe79ea5}, /* U+77A5 */ + {0x95cc, 0xe89491}, /* U+8511 */ + {0x95cd, 0xe7ae86}, /* U+7B86 */ + {0x95ce, 0xe5818f}, /* U+504F */ + {0x95cf, 0xe5a489}, /* U+5909 */ + {0x95d0, 0xe78987}, /* U+7247 */ + {0x95d1, 0xe7af87}, /* U+7BC7 */ + {0x95d2, 0xe7b7a8}, /* U+7DE8 */ + {0x95d3, 0xe8beba}, /* U+8FBA */ + {0x95d4, 0xe8bf94}, /* U+8FD4 */ + {0x95d5, 0xe9818d}, /* U+904D */ + {0x95d6, 0xe4bebf}, /* U+4FBF */ + {0x95d7, 0xe58b89}, /* U+52C9 */ + {0x95d8, 0xe5a8a9}, /* U+5A29 */ + {0x95d9, 0xe5bc81}, /* U+5F01 */ + {0x95da, 0xe99ead}, /* U+97AD */ + {0x95db, 0xe4bf9d}, /* U+4FDD */ + {0x95dc, 0xe88897}, /* U+8217 */ + {0x95dd, 0xe98baa}, /* U+92EA */ + {0x95de, 0xe59c83}, /* U+5703 */ + {0x95df, 0xe68d95}, /* U+6355 */ + {0x95e0, 0xe6ada9}, /* U+6B69 */ + {0x95e1, 0xe794ab}, /* U+752B */ + {0x95e2, 0xe8a39c}, /* U+88DC */ + {0x95e3, 0xe8bc94}, /* U+8F14 */ + {0x95e4, 0xe7a982}, /* U+7A42 */ + {0x95e5, 0xe58b9f}, /* U+52DF */ + {0x95e6, 0xe5a293}, /* U+5893 */ + {0x95e7, 0xe68595}, /* U+6155 */ + {0x95e8, 0xe6888a}, /* U+620A */ + {0x95e9, 0xe69aae}, /* U+66AE */ + {0x95ea, 0xe6af8d}, /* U+6BCD */ + {0x95eb, 0xe7b0bf}, /* U+7C3F */ + {0x95ec, 0xe88fa9}, /* U+83E9 */ + {0x95ed, 0xe580a3}, /* U+5023 */ + {0x95ee, 0xe4bfb8}, /* U+4FF8 */ + {0x95ef, 0xe58c85}, /* U+5305 */ + {0x95f0, 0xe59186}, /* U+5446 */ + {0x95f1, 0xe5a0b1}, /* U+5831 */ + {0x95f2, 0xe5a589}, /* U+5949 */ + {0x95f3, 0xe5ae9d}, /* U+5B9D */ + {0x95f4, 0xe5b3b0}, /* U+5CF0 */ + {0x95f5, 0xe5b3af}, /* U+5CEF */ + {0x95f6, 0xe5b4a9}, /* U+5D29 */ + {0x95f7, 0xe5ba96}, /* U+5E96 */ + {0x95f8, 0xe68ab1}, /* U+62B1 */ + {0x95f9, 0xe68da7}, /* U+6367 */ + {0x95fa, 0xe694be}, /* U+653E */ + {0x95fb, 0xe696b9}, /* U+65B9 */ + {0x95fc, 0xe69c8b}, /* U+670B */ + {0x9640, 0xe6b395}, /* U+6CD5 */ + {0x9641, 0xe6b3a1}, /* U+6CE1 */ + {0x9642, 0xe783b9}, /* U+70F9 */ + {0x9643, 0xe7a0b2}, /* U+7832 */ + {0x9644, 0xe7b8ab}, /* U+7E2B */ + {0x9645, 0xe8839e}, /* U+80DE */ + {0x9646, 0xe88ab3}, /* U+82B3 */ + {0x9647, 0xe8908c}, /* U+840C */ + {0x9648, 0xe893ac}, /* U+84EC */ + {0x9649, 0xe89c82}, /* U+8702 */ + {0x964a, 0xe8a492}, /* U+8912 */ + {0x964b, 0xe8a8aa}, /* U+8A2A */ + {0x964c, 0xe8b18a}, /* U+8C4A */ + {0x964d, 0xe982a6}, /* U+90A6 */ + {0x964e, 0xe98b92}, /* U+92D2 */ + {0x964f, 0xe9a3bd}, /* U+98FD */ + {0x9650, 0xe9b3b3}, /* U+9CF3 */ + {0x9651, 0xe9b5ac}, /* U+9D6C */ + {0x9652, 0xe4b98f}, /* U+4E4F */ + {0x9653, 0xe4baa1}, /* U+4EA1 */ + {0x9654, 0xe5828d}, /* U+508D */ + {0x9655, 0xe58996}, /* U+5256 */ + {0x9656, 0xe59d8a}, /* U+574A */ + {0x9657, 0xe5a6a8}, /* U+59A8 */ + {0x9658, 0xe5b8bd}, /* U+5E3D */ + {0x9659, 0xe5bf98}, /* U+5FD8 */ + {0x965a, 0xe5bf99}, /* U+5FD9 */ + {0x965b, 0xe688bf}, /* U+623F */ + {0x965c, 0xe69ab4}, /* U+66B4 */ + {0x965d, 0xe69c9b}, /* U+671B */ + {0x965e, 0xe69f90}, /* U+67D0 */ + {0x965f, 0xe6a392}, /* U+68D2 */ + {0x9660, 0xe58692}, /* U+5192 */ + {0x9661, 0xe7b4a1}, /* U+7D21 */ + {0x9662, 0xe882aa}, /* U+80AA */ + {0x9663, 0xe886a8}, /* U+81A8 */ + {0x9664, 0xe8ac80}, /* U+8B00 */ + {0x9665, 0xe8b28c}, /* U+8C8C */ + {0x9666, 0xe8b2bf}, /* U+8CBF */ + {0x9667, 0xe989be}, /* U+927E */ + {0x9668, 0xe998b2}, /* U+9632 */ + {0x9669, 0xe590a0}, /* U+5420 */ + {0x966a, 0xe9a0ac}, /* U+982C */ + {0x966b, 0xe58c97}, /* U+5317 */ + {0x966c, 0xe58395}, /* U+50D5 */ + {0x966d, 0xe58d9c}, /* U+535C */ + {0x966e, 0xe5a2a8}, /* U+58A8 */ + {0x966f, 0xe692b2}, /* U+64B2 */ + {0x9670, 0xe69cb4}, /* U+6734 */ + {0x9671, 0xe789a7}, /* U+7267 */ + {0x9672, 0xe79da6}, /* U+7766 */ + {0x9673, 0xe7a986}, /* U+7A46 */ + {0x9674, 0xe987a6}, /* U+91E6 */ + {0x9675, 0xe58b83}, /* U+52C3 */ + {0x9676, 0xe6b2a1}, /* U+6CA1 */ + {0x9677, 0xe6ae86}, /* U+6B86 */ + {0x9678, 0xe5a080}, /* U+5800 */ + {0x9679, 0xe5b98c}, /* U+5E4C */ + {0x967a, 0xe5a594}, /* U+5954 */ + {0x967b, 0xe69cac}, /* U+672C */ + {0x967c, 0xe7bfbb}, /* U+7FFB */ + {0x967d, 0xe587a1}, /* U+51E1 */ + {0x967e, 0xe79b86}, /* U+76C6 */ + {0x9680, 0xe691a9}, /* U+6469 */ + {0x9681, 0xe7a3a8}, /* U+78E8 */ + {0x9682, 0xe9ad94}, /* U+9B54 */ + {0x9683, 0xe9babb}, /* U+9EBB */ + {0x9684, 0xe59f8b}, /* U+57CB */ + {0x9685, 0xe5a6b9}, /* U+59B9 */ + {0x9686, 0xe698a7}, /* U+6627 */ + {0x9687, 0xe69e9a}, /* U+679A */ + {0x9688, 0xe6af8e}, /* U+6BCE */ + {0x9689, 0xe593a9}, /* U+54E9 */ + {0x968a, 0xe6a799}, /* U+69D9 */ + {0x968b, 0xe5b995}, /* U+5E55 */ + {0x968c, 0xe8869c}, /* U+819C */ + {0x968d, 0xe69e95}, /* U+6795 */ + {0x968e, 0xe9aeaa}, /* U+9BAA */ + {0x968f, 0xe69fbe}, /* U+67FE */ + {0x9690, 0xe9b192}, /* U+9C52 */ + {0x9691, 0xe6a19d}, /* U+685D */ + {0x9692, 0xe4baa6}, /* U+4EA6 */ + {0x9693, 0xe4bfa3}, /* U+4FE3 */ + {0x9694, 0xe58f88}, /* U+53C8 */ + {0x9695, 0xe68ab9}, /* U+62B9 */ + {0x9696, 0xe69cab}, /* U+672B */ + {0x9697, 0xe6b2ab}, /* U+6CAB */ + {0x9698, 0xe8bf84}, /* U+8FC4 */ + {0x9699, 0xe4bead}, /* U+4FAD */ + {0x969a, 0xe7b9ad}, /* U+7E6D */ + {0x969b, 0xe9babf}, /* U+9EBF */ + {0x969c, 0xe4b887}, /* U+4E07 */ + {0x969d, 0xe685a2}, /* U+6162 */ + {0x969e, 0xe6ba80}, /* U+6E80 */ + {0x969f, 0xe6bcab}, /* U+6F2B */ + {0x96a0, 0xe89493}, /* U+8513 */ + {0x96a1, 0xe591b3}, /* U+5473 */ + {0x96a2, 0xe69caa}, /* U+672A */ + {0x96a3, 0xe9ad85}, /* U+9B45 */ + {0x96a4, 0xe5b7b3}, /* U+5DF3 */ + {0x96a5, 0xe7ae95}, /* U+7B95 */ + {0x96a6, 0xe5b2ac}, /* U+5CAC */ + {0x96a7, 0xe5af86}, /* U+5BC6 */ + {0x96a8, 0xe89c9c}, /* U+871C */ + {0x96a9, 0xe6b98a}, /* U+6E4A */ + {0x96aa, 0xe89391}, /* U+84D1 */ + {0x96ab, 0xe7a894}, /* U+7A14 */ + {0x96ac, 0xe88488}, /* U+8108 */ + {0x96ad, 0xe5a699}, /* U+5999 */ + {0x96ae, 0xe7b28d}, /* U+7C8D */ + {0x96af, 0xe6b091}, /* U+6C11 */ + {0x96b0, 0xe79ca0}, /* U+7720 */ + {0x96b1, 0xe58b99}, /* U+52D9 */ + {0x96b2, 0xe5a4a2}, /* U+5922 */ + {0x96b3, 0xe784a1}, /* U+7121 */ + {0x96b4, 0xe7899f}, /* U+725F */ + {0x96b5, 0xe79f9b}, /* U+77DB */ + {0x96b6, 0xe99ca7}, /* U+9727 */ + {0x96b7, 0xe9b5a1}, /* U+9D61 */ + {0x96b8, 0xe6a48b}, /* U+690B */ + {0x96b9, 0xe5a9bf}, /* U+5A7F */ + {0x96ba, 0xe5a898}, /* U+5A18 */ + {0x96bb, 0xe586a5}, /* U+51A5 */ + {0x96bc, 0xe5908d}, /* U+540D */ + {0x96bd, 0xe591bd}, /* U+547D */ + {0x96be, 0xe6988e}, /* U+660E */ + {0x96bf, 0xe79b9f}, /* U+76DF */ + {0x96c0, 0xe8bfb7}, /* U+8FF7 */ + {0x96c1, 0xe98a98}, /* U+9298 */ + {0x96c2, 0xe9b3b4}, /* U+9CF4 */ + {0x96c3, 0xe5a7aa}, /* U+59EA */ + {0x96c4, 0xe7899d}, /* U+725D */ + {0x96c5, 0xe6bb85}, /* U+6EC5 */ + {0x96c6, 0xe5858d}, /* U+514D */ + {0x96c7, 0xe6a389}, /* U+68C9 */ + {0x96c8, 0xe7b6bf}, /* U+7DBF */ + {0x96c9, 0xe7b7ac}, /* U+7DEC */ + {0x96ca, 0xe99da2}, /* U+9762 */ + {0x96cb, 0xe9baba}, /* U+9EBA */ + {0x96cc, 0xe691b8}, /* U+6478 */ + {0x96cd, 0xe6a8a1}, /* U+6A21 */ + {0x96ce, 0xe88c82}, /* U+8302 */ + {0x96cf, 0xe5a684}, /* U+5984 */ + {0x96d0, 0xe5ad9f}, /* U+5B5F */ + {0x96d1, 0xe6af9b}, /* U+6BDB */ + {0x96d2, 0xe78c9b}, /* U+731B */ + {0x96d3, 0xe79bb2}, /* U+76F2 */ + {0x96d4, 0xe7b6b2}, /* U+7DB2 */ + {0x96d5, 0xe88097}, /* U+8017 */ + {0x96d6, 0xe89299}, /* U+8499 */ + {0x96d7, 0xe584b2}, /* U+5132 */ + {0x96d8, 0xe69ca8}, /* U+6728 */ + {0x96d9, 0xe9bb99}, /* U+9ED9 */ + {0x96da, 0xe79bae}, /* U+76EE */ + {0x96db, 0xe69da2}, /* U+6762 */ + {0x96dc, 0xe58bbf}, /* U+52FF */ + {0x96dd, 0xe9a485}, /* U+9905 */ + {0x96de, 0xe5b0a4}, /* U+5C24 */ + {0x96df, 0xe688bb}, /* U+623B */ + {0x96e0, 0xe7b1be}, /* U+7C7E */ + {0x96e1, 0xe8b2b0}, /* U+8CB0 */ + {0x96e2, 0xe5958f}, /* U+554F */ + {0x96e3, 0xe682b6}, /* U+60B6 */ + {0x96e4, 0xe7b48b}, /* U+7D0B */ + {0x96e5, 0xe99680}, /* U+9580 */ + {0x96e6, 0xe58c81}, /* U+5301 */ + {0x96e7, 0xe4b99f}, /* U+4E5F */ + {0x96e8, 0xe586b6}, /* U+51B6 */ + {0x96e9, 0xe5a49c}, /* U+591C */ + {0x96ea, 0xe788ba}, /* U+723A */ + {0x96eb, 0xe880b6}, /* U+8036 */ + {0x96ec, 0xe9878e}, /* U+91CE */ + {0x96ed, 0xe5bca5}, /* U+5F25 */ + {0x96ee, 0xe79fa2}, /* U+77E2 */ + {0x96ef, 0xe58e84}, /* U+5384 */ + {0x96f0, 0xe5bdb9}, /* U+5F79 */ + {0x96f1, 0xe7b484}, /* U+7D04 */ + {0x96f2, 0xe896ac}, /* U+85AC */ + {0x96f3, 0xe8a8b3}, /* U+8A33 */ + {0x96f4, 0xe8ba8d}, /* U+8E8D */ + {0x96f5, 0xe99d96}, /* U+9756 */ + {0x96f6, 0xe69fb3}, /* U+67F3 */ + {0x96f7, 0xe896ae}, /* U+85AE */ + {0x96f8, 0xe99193}, /* U+9453 */ + {0x96f9, 0xe68489}, /* U+6109 */ + {0x96fa, 0xe68488}, /* U+6108 */ + {0x96fb, 0xe6b2b9}, /* U+6CB9 */ + {0x96fc, 0xe79992}, /* U+7652 */ + {0x9740, 0xe8abad}, /* U+8AED */ + {0x9741, 0xe8bcb8}, /* U+8F38 */ + {0x9742, 0xe594af}, /* U+552F */ + {0x9743, 0xe4bd91}, /* U+4F51 */ + {0x9744, 0xe584aa}, /* U+512A */ + {0x9745, 0xe58b87}, /* U+52C7 */ + {0x9746, 0xe58f8b}, /* U+53CB */ + {0x9747, 0xe5aea5}, /* U+5BA5 */ + {0x9748, 0xe5b9bd}, /* U+5E7D */ + {0x9749, 0xe682a0}, /* U+60A0 */ + {0x974a, 0xe68682}, /* U+6182 */ + {0x974b, 0xe68f96}, /* U+63D6 */ + {0x974c, 0xe69c89}, /* U+6709 */ + {0x974d, 0xe69f9a}, /* U+67DA */ + {0x974e, 0xe6b9a7}, /* U+6E67 */ + {0x974f, 0xe6b68c}, /* U+6D8C */ + {0x9750, 0xe78cb6}, /* U+7336 */ + {0x9751, 0xe78cb7}, /* U+7337 */ + {0x9752, 0xe794b1}, /* U+7531 */ + {0x9753, 0xe7a590}, /* U+7950 */ + {0x9754, 0xe8a395}, /* U+88D5 */ + {0x9755, 0xe8aa98}, /* U+8A98 */ + {0x9756, 0xe9818a}, /* U+904A */ + {0x9757, 0xe98291}, /* U+9091 */ + {0x9758, 0xe983b5}, /* U+90F5 */ + {0x9759, 0xe99b84}, /* U+96C4 */ + {0x975a, 0xe89e8d}, /* U+878D */ + {0x975b, 0xe5a495}, /* U+5915 */ + {0x975c, 0xe4ba88}, /* U+4E88 */ + {0x975d, 0xe4bd99}, /* U+4F59 */ + {0x975e, 0xe4b88e}, /* U+4E0E */ + {0x975f, 0xe8aa89}, /* U+8A89 */ + {0x9760, 0xe8bcbf}, /* U+8F3F */ + {0x9761, 0xe9a090}, /* U+9810 */ + {0x9762, 0xe582ad}, /* U+50AD */ + {0x9763, 0xe5b9bc}, /* U+5E7C */ + {0x9764, 0xe5a696}, /* U+5996 */ + {0x9765, 0xe5aeb9}, /* U+5BB9 */ + {0x9766, 0xe5bab8}, /* U+5EB8 */ + {0x9767, 0xe68f9a}, /* U+63DA */ + {0x9768, 0xe68fba}, /* U+63FA */ + {0x9769, 0xe69381}, /* U+64C1 */ + {0x976a, 0xe69b9c}, /* U+66DC */ + {0x976b, 0xe6a58a}, /* U+694A */ + {0x976c, 0xe6a798}, /* U+69D8 */ + {0x976d, 0xe6b48b}, /* U+6D0B */ + {0x976e, 0xe6bab6}, /* U+6EB6 */ + {0x976f, 0xe78694}, /* U+7194 */ + {0x9770, 0xe794a8}, /* U+7528 */ + {0x9771, 0xe7aaaf}, /* U+7AAF */ + {0x9772, 0xe7be8a}, /* U+7F8A */ + {0x9773, 0xe88080}, /* U+8000 */ + {0x9774, 0xe89189}, /* U+8449 */ + {0x9775, 0xe89389}, /* U+84C9 */ + {0x9776, 0xe8a681}, /* U+8981 */ + {0x9777, 0xe8aca1}, /* U+8B21 */ + {0x9778, 0xe8b88a}, /* U+8E0A */ + {0x9779, 0xe981a5}, /* U+9065 */ + {0x977a, 0xe999bd}, /* U+967D */ + {0x977b, 0xe9a48a}, /* U+990A */ + {0x977c, 0xe685be}, /* U+617E */ + {0x977d, 0xe68a91}, /* U+6291 */ + {0x977e, 0xe6acb2}, /* U+6B32 */ + {0x9780, 0xe6b283}, /* U+6C83 */ + {0x9781, 0xe6b5b4}, /* U+6D74 */ + {0x9782, 0xe7bf8c}, /* U+7FCC */ + {0x9783, 0xe7bfbc}, /* U+7FFC */ + {0x9784, 0xe6b780}, /* U+6DC0 */ + {0x9785, 0xe7be85}, /* U+7F85 */ + {0x9786, 0xe89eba}, /* U+87BA */ + {0x9787, 0xe8a3b8}, /* U+88F8 */ + {0x9788, 0xe69da5}, /* U+6765 */ + {0x9789, 0xe88eb1}, /* U+83B1 */ + {0x978a, 0xe9a0bc}, /* U+983C */ + {0x978b, 0xe99bb7}, /* U+96F7 */ + {0x978c, 0xe6b49b}, /* U+6D1B */ + {0x978d, 0xe7b5a1}, /* U+7D61 */ + {0x978e, 0xe890bd}, /* U+843D */ + {0x978f, 0xe985aa}, /* U+916A */ + {0x9790, 0xe4b9b1}, /* U+4E71 */ + {0x9791, 0xe58db5}, /* U+5375 */ + {0x9792, 0xe5b590}, /* U+5D50 */ + {0x9793, 0xe6ac84}, /* U+6B04 */ + {0x9794, 0xe6bfab}, /* U+6FEB */ + {0x9795, 0xe8978d}, /* U+85CD */ + {0x9796, 0xe898ad}, /* U+862D */ + {0x9797, 0xe8a6a7}, /* U+89A7 */ + {0x9798, 0xe588a9}, /* U+5229 */ + {0x9799, 0xe5908f}, /* U+540F */ + {0x979a, 0xe5b1a5}, /* U+5C65 */ + {0x979b, 0xe69d8e}, /* U+674E */ + {0x979c, 0xe6a2a8}, /* U+68A8 */ + {0x979d, 0xe79086}, /* U+7406 */ + {0x979e, 0xe79283}, /* U+7483 */ + {0x979f, 0xe797a2}, /* U+75E2 */ + {0x97a0, 0xe8a38f}, /* U+88CF */ + {0x97a1, 0xe8a3a1}, /* U+88E1 */ + {0x97a2, 0xe9878c}, /* U+91CC */ + {0x97a3, 0xe99ba2}, /* U+96E2 */ + {0x97a4, 0xe999b8}, /* U+9678 */ + {0x97a5, 0xe5be8b}, /* U+5F8B */ + {0x97a6, 0xe78e87}, /* U+7387 */ + {0x97a7, 0xe7ab8b}, /* U+7ACB */ + {0x97a8, 0xe8918e}, /* U+844E */ + {0x97a9, 0xe68ea0}, /* U+63A0 */ + {0x97aa, 0xe795a5}, /* U+7565 */ + {0x97ab, 0xe58a89}, /* U+5289 */ + {0x97ac, 0xe6b581}, /* U+6D41 */ + {0x97ad, 0xe6ba9c}, /* U+6E9C */ + {0x97ae, 0xe79089}, /* U+7409 */ + {0x97af, 0xe79599}, /* U+7559 */ + {0x97b0, 0xe7a1ab}, /* U+786B */ + {0x97b1, 0xe7b292}, /* U+7C92 */ + {0x97b2, 0xe99a86}, /* U+9686 */ + {0x97b3, 0xe7ab9c}, /* U+7ADC */ + {0x97b4, 0xe9be8d}, /* U+9F8D */ + {0x97b5, 0xe4beb6}, /* U+4FB6 */ + {0x97b6, 0xe685ae}, /* U+616E */ + {0x97b7, 0xe69785}, /* U+65C5 */ + {0x97b8, 0xe8999c}, /* U+865C */ + {0x97b9, 0xe4ba86}, /* U+4E86 */ + {0x97ba, 0xe4baae}, /* U+4EAE */ + {0x97bb, 0xe5839a}, /* U+50DA */ + {0x97bc, 0xe4b8a1}, /* U+4E21 */ + {0x97bd, 0xe5878c}, /* U+51CC */ + {0x97be, 0xe5afae}, /* U+5BEE */ + {0x97bf, 0xe69699}, /* U+6599 */ + {0x97c0, 0xe6a281}, /* U+6881 */ + {0x97c1, 0xe6b6bc}, /* U+6DBC */ + {0x97c2, 0xe78c9f}, /* U+731F */ + {0x97c3, 0xe79982}, /* U+7642 */ + {0x97c4, 0xe79ead}, /* U+77AD */ + {0x97c5, 0xe7a89c}, /* U+7A1C */ + {0x97c6, 0xe7b3a7}, /* U+7CE7 */ + {0x97c7, 0xe889af}, /* U+826F */ + {0x97c8, 0xe8ab92}, /* U+8AD2 */ + {0x97c9, 0xe981bc}, /* U+907C */ + {0x97ca, 0xe9878f}, /* U+91CF */ + {0x97cb, 0xe999b5}, /* U+9675 */ + {0x97cc, 0xe9a098}, /* U+9818 */ + {0x97cd, 0xe58a9b}, /* U+529B */ + {0x97ce, 0xe7b791}, /* U+7DD1 */ + {0x97cf, 0xe580ab}, /* U+502B */ + {0x97d0, 0xe58e98}, /* U+5398 */ + {0x97d1, 0xe69e97}, /* U+6797 */ + {0x97d2, 0xe6b78b}, /* U+6DCB */ + {0x97d3, 0xe78790}, /* U+71D0 */ + {0x97d4, 0xe790b3}, /* U+7433 */ + {0x97d5, 0xe887a8}, /* U+81E8 */ + {0x97d6, 0xe8bcaa}, /* U+8F2A */ + {0x97d7, 0xe99aa3}, /* U+96A3 */ + {0x97d8, 0xe9b197}, /* U+9C57 */ + {0x97d9, 0xe9ba9f}, /* U+9E9F */ + {0x97da, 0xe791a0}, /* U+7460 */ + {0x97db, 0xe5a181}, /* U+5841 */ + {0x97dc, 0xe6b699}, /* U+6D99 */ + {0x97dd, 0xe7b4af}, /* U+7D2F */ + {0x97de, 0xe9a19e}, /* U+985E */ + {0x97df, 0xe4bba4}, /* U+4EE4 */ + {0x97e0, 0xe4bcb6}, /* U+4F36 */ + {0x97e1, 0xe4be8b}, /* U+4F8B */ + {0x97e2, 0xe586b7}, /* U+51B7 */ + {0x97e3, 0xe58ab1}, /* U+52B1 */ + {0x97e4, 0xe5b6ba}, /* U+5DBA */ + {0x97e5, 0xe6809c}, /* U+601C */ + {0x97e6, 0xe78eb2}, /* U+73B2 */ + {0x97e7, 0xe7a4bc}, /* U+793C */ + {0x97e8, 0xe88b93}, /* U+82D3 */ + {0x97e9, 0xe988b4}, /* U+9234 */ + {0x97ea, 0xe99ab7}, /* U+96B7 */ + {0x97eb, 0xe99bb6}, /* U+96F6 */ + {0x97ec, 0xe99c8a}, /* U+970A */ + {0x97ed, 0xe9ba97}, /* U+9E97 */ + {0x97ee, 0xe9bda2}, /* U+9F62 */ + {0x97ef, 0xe69aa6}, /* U+66A6 */ + {0x97f0, 0xe6adb4}, /* U+6B74 */ + {0x97f1, 0xe58897}, /* U+5217 */ + {0x97f2, 0xe58aa3}, /* U+52A3 */ + {0x97f3, 0xe78388}, /* U+70C8 */ + {0x97f4, 0xe8a382}, /* U+88C2 */ + {0x97f5, 0xe5bb89}, /* U+5EC9 */ + {0x97f6, 0xe6818b}, /* U+604B */ + {0x97f7, 0xe68690}, /* U+6190 */ + {0x97f8, 0xe6bca3}, /* U+6F23 */ + {0x97f9, 0xe78589}, /* U+7149 */ + {0x97fa, 0xe7b0be}, /* U+7C3E */ + {0x97fb, 0xe7b7b4}, /* U+7DF4 */ + {0x97fc, 0xe881af}, /* U+806F */ + {0x9840, 0xe893ae}, /* U+84EE */ + {0x9841, 0xe980a3}, /* U+9023 */ + {0x9842, 0xe98cac}, /* U+932C */ + {0x9843, 0xe59182}, /* U+5442 */ + {0x9844, 0xe9adaf}, /* U+9B6F */ + {0x9845, 0xe6ab93}, /* U+6AD3 */ + {0x9846, 0xe78289}, /* U+7089 */ + {0x9847, 0xe8b382}, /* U+8CC2 */ + {0x9848, 0xe8b7af}, /* U+8DEF */ + {0x9849, 0xe99cb2}, /* U+9732 */ + {0x984a, 0xe58ab4}, /* U+52B4 */ + {0x984b, 0xe5a981}, /* U+5A41 */ + {0x984c, 0xe5bb8a}, /* U+5ECA */ + {0x984d, 0xe5bc84}, /* U+5F04 */ + {0x984e, 0xe69c97}, /* U+6717 */ + {0x984f, 0xe6a5bc}, /* U+697C */ + {0x9850, 0xe6a694}, /* U+6994 */ + {0x9851, 0xe6b5aa}, /* U+6D6A */ + {0x9852, 0xe6bc8f}, /* U+6F0F */ + {0x9853, 0xe789a2}, /* U+7262 */ + {0x9854, 0xe78bbc}, /* U+72FC */ + {0x9855, 0xe7afad}, /* U+7BED */ + {0x9856, 0xe88081}, /* U+8001 */ + {0x9857, 0xe881be}, /* U+807E */ + {0x9858, 0xe89d8b}, /* U+874B */ + {0x9859, 0xe9838e}, /* U+90CE */ + {0x985a, 0xe585ad}, /* U+516D */ + {0x985b, 0xe9ba93}, /* U+9E93 */ + {0x985c, 0xe7a684}, /* U+7984 */ + {0x985d, 0xe8828b}, /* U+808B */ + {0x985e, 0xe98cb2}, /* U+9332 */ + {0x985f, 0xe8ab96}, /* U+8AD6 */ + {0x9860, 0xe580ad}, /* U+502D */ + {0x9861, 0xe5928c}, /* U+548C */ + {0x9862, 0xe8a9b1}, /* U+8A71 */ + {0x9863, 0xe6adaa}, /* U+6B6A */ + {0x9864, 0xe8b384}, /* U+8CC4 */ + {0x9865, 0xe88487}, /* U+8107 */ + {0x9866, 0xe68391}, /* U+60D1 */ + {0x9867, 0xe69ea0}, /* U+67A0 */ + {0x9868, 0xe9b7b2}, /* U+9DF2 */ + {0x9869, 0xe4ba99}, /* U+4E99 */ + {0x986a, 0xe4ba98}, /* U+4E98 */ + {0x986b, 0xe9b090}, /* U+9C10 */ + {0x986c, 0xe8a9ab}, /* U+8A6B */ + {0x986d, 0xe89781}, /* U+85C1 */ + {0x986e, 0xe895a8}, /* U+8568 */ + {0x986f, 0xe6a480}, /* U+6900 */ + {0x9870, 0xe6b9be}, /* U+6E7E */ + {0x9871, 0xe7a297}, /* U+7897 */ + {0x9872, 0xe88595}, /* U+8155 */ {0x9873, 0xf0a0ae9f}, /* U+20B9F [2004] [Unicode3.1] */ - {0x9874, 0x00e5ad81}, /* U+5B41 [2000] */ - {0x9875, 0x00e5ad96}, /* U+5B56 [2000] */ - {0x9876, 0x00e5adbd}, /* U+5B7D [2000] */ - {0x9877, 0x00e5ae93}, /* U+5B93 [2000] */ - {0x9878, 0x00e5af98}, /* U+5BD8 [2000] */ - {0x9879, 0x00e5afac}, /* U+5BEC [2000] */ - {0x987a, 0x00e5b092}, /* U+5C12 [2000] */ - {0x987b, 0x00e5b09e}, /* U+5C1E [2000] */ - {0x987c, 0x00e5b0a3}, /* U+5C23 [2000] */ - {0x987d, 0x00e5b0ab}, /* U+5C2B [2000] */ - {0x987e, 0x00e39e8d}, /* U+378D [2000] */ - {0x9880, 0x00e5b1a2}, /* U+5C62 [2000] */ - {0x9881, 0x00efa8bb}, /* U+FA3B CJK COMPATIBILITY IDEOGRAPH-FA3B [2000] [Unicode3.2] */ - {0x9882, 0x00efa8bc}, /* U+FA3C CJK COMPATIBILITY IDEOGRAPH-FA3C [2000] [Unicode3.2] */ + {0x9874, 0xe5ad81}, /* U+5B41 [2000] */ + {0x9875, 0xe5ad96}, /* U+5B56 [2000] */ + {0x9876, 0xe5adbd}, /* U+5B7D [2000] */ + {0x9877, 0xe5ae93}, /* U+5B93 [2000] */ + {0x9878, 0xe5af98}, /* U+5BD8 [2000] */ + {0x9879, 0xe5afac}, /* U+5BEC [2000] */ + {0x987a, 0xe5b092}, /* U+5C12 [2000] */ + {0x987b, 0xe5b09e}, /* U+5C1E [2000] */ + {0x987c, 0xe5b0a3}, /* U+5C23 [2000] */ + {0x987d, 0xe5b0ab}, /* U+5C2B [2000] */ + {0x987e, 0xe39e8d}, /* U+378D [2000] */ + {0x9880, 0xe5b1a2}, /* U+5C62 [2000] */ + {0x9881, 0xefa8bb}, /* U+FA3B CJK COMPATIBILITY IDEOGRAPH-FA3B [2000] [Unicode3.2] */ + {0x9882, 0xefa8bc}, /* U+FA3C CJK COMPATIBILITY IDEOGRAPH-FA3C [2000] [Unicode3.2] */ {0x9883, 0xf0a19ab4}, /* U+216B4 [2000] [Unicode3.1] */ - {0x9884, 0x00e5b1ba}, /* U+5C7A [2000] */ - {0x9885, 0x00e5b28f}, /* U+5C8F [2000] */ - {0x9886, 0x00e5b29f}, /* U+5C9F [2000] */ - {0x9887, 0x00e5b2a3}, /* U+5CA3 [2000] */ - {0x9888, 0x00e5b2aa}, /* U+5CAA [2000] */ - {0x9889, 0x00e5b2ba}, /* U+5CBA [2000] */ - {0x988a, 0x00e5b38b}, /* U+5CCB [2000] */ - {0x988b, 0x00e5b390}, /* U+5CD0 [2000] */ - {0x988c, 0x00e5b392}, /* U+5CD2 [2000] */ - {0x988d, 0x00e5b3b4}, /* U+5CF4 [2000] */ + {0x9884, 0xe5b1ba}, /* U+5C7A [2000] */ + {0x9885, 0xe5b28f}, /* U+5C8F [2000] */ + {0x9886, 0xe5b29f}, /* U+5C9F [2000] */ + {0x9887, 0xe5b2a3}, /* U+5CA3 [2000] */ + {0x9888, 0xe5b2aa}, /* U+5CAA [2000] */ + {0x9889, 0xe5b2ba}, /* U+5CBA [2000] */ + {0x988a, 0xe5b38b}, /* U+5CCB [2000] */ + {0x988b, 0xe5b390}, /* U+5CD0 [2000] */ + {0x988c, 0xe5b392}, /* U+5CD2 [2000] */ + {0x988d, 0xe5b3b4}, /* U+5CF4 [2000] */ {0x988e, 0xf0a1b8b4}, /* U+21E34 [2000] [Unicode3.1] */ - {0x988f, 0x00e39fa2}, /* U+37E2 [2000] */ - {0x9890, 0x00e5b48d}, /* U+5D0D [2000] */ - {0x9891, 0x00e5b4a7}, /* U+5D27 [2000] */ - {0x9892, 0x00efa891}, /* U+FA11 CJK COMPATIBILITY IDEOGRAPH-FA11 [2000] */ - {0x9893, 0x00e5b586}, /* U+5D46 [2000] */ - {0x9894, 0x00e5b587}, /* U+5D47 [2000] */ - {0x9895, 0x00e5b593}, /* U+5D53 [2000] */ - {0x9896, 0x00e5b58a}, /* U+5D4A [2000] */ - {0x9897, 0x00e5b5ad}, /* U+5D6D [2000] */ - {0x9898, 0x00e5b681}, /* U+5D81 [2000] */ - {0x9899, 0x00e5b6a0}, /* U+5DA0 [2000] */ - {0x989a, 0x00e5b6a4}, /* U+5DA4 [2000] */ - {0x989b, 0x00e5b6a7}, /* U+5DA7 [2000] */ - {0x989c, 0x00e5b6b8}, /* U+5DB8 [2000] */ - {0x989d, 0x00e5b78b}, /* U+5DCB [2000] */ - {0x989e, 0x00e5909e}, /* U+541E [2004] */ - {0x989f, 0x00e5bc8c}, /* U+5F0C */ - {0x98a0, 0x00e4b890}, /* U+4E10 */ - {0x98a1, 0x00e4b895}, /* U+4E15 */ - {0x98a2, 0x00e4b8aa}, /* U+4E2A */ - {0x98a3, 0x00e4b8b1}, /* U+4E31 */ - {0x98a4, 0x00e4b8b6}, /* U+4E36 */ - {0x98a5, 0x00e4b8bc}, /* U+4E3C */ - {0x98a6, 0x00e4b8bf}, /* U+4E3F */ - {0x98a7, 0x00e4b982}, /* U+4E42 */ - {0x98a8, 0x00e4b996}, /* U+4E56 */ - {0x98a9, 0x00e4b998}, /* U+4E58 */ - {0x98aa, 0x00e4ba82}, /* U+4E82 */ - {0x98ab, 0x00e4ba85}, /* U+4E85 */ - {0x98ac, 0x00e8b1ab}, /* U+8C6B */ - {0x98ad, 0x00e4ba8a}, /* U+4E8A */ - {0x98ae, 0x00e88892}, /* U+8212 */ - {0x98af, 0x00e5bc8d}, /* U+5F0D */ - {0x98b0, 0x00e4ba8e}, /* U+4E8E */ - {0x98b1, 0x00e4ba9e}, /* U+4E9E */ - {0x98b2, 0x00e4ba9f}, /* U+4E9F */ - {0x98b3, 0x00e4baa0}, /* U+4EA0 */ - {0x98b4, 0x00e4baa2}, /* U+4EA2 */ - {0x98b5, 0x00e4bab0}, /* U+4EB0 */ - {0x98b6, 0x00e4bab3}, /* U+4EB3 */ - {0x98b7, 0x00e4bab6}, /* U+4EB6 */ - {0x98b8, 0x00e4bb8e}, /* U+4ECE */ - {0x98b9, 0x00e4bb8d}, /* U+4ECD */ - {0x98ba, 0x00e4bb84}, /* U+4EC4 */ - {0x98bb, 0x00e4bb86}, /* U+4EC6 */ - {0x98bc, 0x00e4bb82}, /* U+4EC2 */ - {0x98bd, 0x00e4bb97}, /* U+4ED7 */ - {0x98be, 0x00e4bb9e}, /* U+4EDE */ - {0x98bf, 0x00e4bbad}, /* U+4EED */ - {0x98c0, 0x00e4bb9f}, /* U+4EDF */ - {0x98c1, 0x00e4bbb7}, /* U+4EF7 */ - {0x98c2, 0x00e4bc89}, /* U+4F09 */ - {0x98c3, 0x00e4bd9a}, /* U+4F5A */ - {0x98c4, 0x00e4bcb0}, /* U+4F30 */ - {0x98c5, 0x00e4bd9b}, /* U+4F5B */ - {0x98c6, 0x00e4bd9d}, /* U+4F5D */ - {0x98c7, 0x00e4bd97}, /* U+4F57 */ - {0x98c8, 0x00e4bd87}, /* U+4F47 */ - {0x98c9, 0x00e4bdb6}, /* U+4F76 */ - {0x98ca, 0x00e4be88}, /* U+4F88 */ - {0x98cb, 0x00e4be8f}, /* U+4F8F */ - {0x98cc, 0x00e4be98}, /* U+4F98 */ - {0x98cd, 0x00e4bdbb}, /* U+4F7B */ - {0x98ce, 0x00e4bda9}, /* U+4F69 */ - {0x98cf, 0x00e4bdb0}, /* U+4F70 */ - {0x98d0, 0x00e4be91}, /* U+4F91 */ - {0x98d1, 0x00e4bdaf}, /* U+4F6F */ - {0x98d2, 0x00e4be86}, /* U+4F86 */ - {0x98d3, 0x00e4be96}, /* U+4F96 */ - {0x98d4, 0x00e58498}, /* U+5118 */ - {0x98d5, 0x00e4bf94}, /* U+4FD4 */ - {0x98d6, 0x00e4bf9f}, /* U+4FDF */ - {0x98d7, 0x00e4bf8e}, /* U+4FCE */ - {0x98d8, 0x00e4bf98}, /* U+4FD8 */ - {0x98d9, 0x00e4bf9b}, /* U+4FDB */ - {0x98da, 0x00e4bf91}, /* U+4FD1 */ - {0x98db, 0x00e4bf9a}, /* U+4FDA */ - {0x98dc, 0x00e4bf90}, /* U+4FD0 */ - {0x98dd, 0x00e4bfa4}, /* U+4FE4 */ - {0x98de, 0x00e4bfa5}, /* U+4FE5 */ - {0x98df, 0x00e5809a}, /* U+501A */ - {0x98e0, 0x00e580a8}, /* U+5028 */ - {0x98e1, 0x00e58094}, /* U+5014 */ - {0x98e2, 0x00e580aa}, /* U+502A */ - {0x98e3, 0x00e580a5}, /* U+5025 */ - {0x98e4, 0x00e58085}, /* U+5005 */ - {0x98e5, 0x00e4bc9c}, /* U+4F1C */ - {0x98e6, 0x00e4bfb6}, /* U+4FF6 */ - {0x98e7, 0x00e580a1}, /* U+5021 */ - {0x98e8, 0x00e580a9}, /* U+5029 */ - {0x98e9, 0x00e580ac}, /* U+502C */ - {0x98ea, 0x00e4bfbe}, /* U+4FFE */ - {0x98eb, 0x00e4bfaf}, /* U+4FEF */ - {0x98ec, 0x00e58091}, /* U+5011 */ - {0x98ed, 0x00e58086}, /* U+5006 */ - {0x98ee, 0x00e58183}, /* U+5043 */ - {0x98ef, 0x00e58187}, /* U+5047 */ - {0x98f0, 0x00e69c83}, /* U+6703 */ - {0x98f1, 0x00e58195}, /* U+5055 */ - {0x98f2, 0x00e58190}, /* U+5050 */ - {0x98f3, 0x00e58188}, /* U+5048 */ - {0x98f4, 0x00e5819a}, /* U+505A */ - {0x98f5, 0x00e58196}, /* U+5056 */ - {0x98f6, 0x00e581ac}, /* U+506C */ - {0x98f7, 0x00e581b8}, /* U+5078 */ - {0x98f8, 0x00e58280}, /* U+5080 */ - {0x98f9, 0x00e5829a}, /* U+509A */ - {0x98fa, 0x00e58285}, /* U+5085 */ - {0x98fb, 0x00e582b4}, /* U+50B4 */ - {0x98fc, 0x00e582b2}, /* U+50B2 */ - {0x9940, 0x00e58389}, /* U+50C9 */ - {0x9941, 0x00e5838a}, /* U+50CA */ - {0x9942, 0x00e582b3}, /* U+50B3 */ - {0x9943, 0x00e58382}, /* U+50C2 */ - {0x9944, 0x00e58396}, /* U+50D6 */ - {0x9945, 0x00e5839e}, /* U+50DE */ - {0x9946, 0x00e583a5}, /* U+50E5 */ - {0x9947, 0x00e583ad}, /* U+50ED */ - {0x9948, 0x00e583a3}, /* U+50E3 */ - {0x9949, 0x00e583ae}, /* U+50EE */ - {0x994a, 0x00e583b9}, /* U+50F9 */ - {0x994b, 0x00e583b5}, /* U+50F5 */ - {0x994c, 0x00e58489}, /* U+5109 */ - {0x994d, 0x00e58481}, /* U+5101 */ - {0x994e, 0x00e58482}, /* U+5102 */ - {0x994f, 0x00e58496}, /* U+5116 */ - {0x9950, 0x00e58495}, /* U+5115 */ - {0x9951, 0x00e58494}, /* U+5114 */ - {0x9952, 0x00e5849a}, /* U+511A */ - {0x9953, 0x00e584a1}, /* U+5121 */ - {0x9954, 0x00e584ba}, /* U+513A */ - {0x9955, 0x00e584b7}, /* U+5137 */ - {0x9956, 0x00e584bc}, /* U+513C */ - {0x9957, 0x00e584bb}, /* U+513B */ - {0x9958, 0x00e584bf}, /* U+513F */ - {0x9959, 0x00e58580}, /* U+5140 */ - {0x995a, 0x00e58592}, /* U+5152 */ - {0x995b, 0x00e5858c}, /* U+514C */ - {0x995c, 0x00e58594}, /* U+5154 */ - {0x995d, 0x00e585a2}, /* U+5162 */ - {0x995e, 0x00e7abb8}, /* U+7AF8 */ - {0x995f, 0x00e585a9}, /* U+5169 */ - {0x9960, 0x00e585aa}, /* U+516A */ - {0x9961, 0x00e585ae}, /* U+516E */ - {0x9962, 0x00e58680}, /* U+5180 */ - {0x9963, 0x00e58682}, /* U+5182 */ - {0x9964, 0x00e59b98}, /* U+56D8 */ - {0x9965, 0x00e5868c}, /* U+518C */ - {0x9966, 0x00e58689}, /* U+5189 */ - {0x9967, 0x00e5868f}, /* U+518F */ - {0x9968, 0x00e58691}, /* U+5191 */ - {0x9969, 0x00e58693}, /* U+5193 */ - {0x996a, 0x00e58695}, /* U+5195 */ - {0x996b, 0x00e58696}, /* U+5196 */ - {0x996c, 0x00e586a4}, /* U+51A4 */ - {0x996d, 0x00e586a6}, /* U+51A6 */ - {0x996e, 0x00e586a2}, /* U+51A2 */ - {0x996f, 0x00e586a9}, /* U+51A9 */ - {0x9970, 0x00e586aa}, /* U+51AA */ - {0x9971, 0x00e586ab}, /* U+51AB */ - {0x9972, 0x00e586b3}, /* U+51B3 */ - {0x9973, 0x00e586b1}, /* U+51B1 */ - {0x9974, 0x00e586b2}, /* U+51B2 */ - {0x9975, 0x00e586b0}, /* U+51B0 */ - {0x9976, 0x00e586b5}, /* U+51B5 */ - {0x9977, 0x00e586bd}, /* U+51BD */ - {0x9978, 0x00e58785}, /* U+51C5 */ - {0x9979, 0x00e58789}, /* U+51C9 */ - {0x997a, 0x00e5879b}, /* U+51DB */ - {0x997b, 0x00e587a0}, /* U+51E0 */ - {0x997c, 0x00e89995}, /* U+8655 */ - {0x997d, 0x00e587a9}, /* U+51E9 */ - {0x997e, 0x00e587ad}, /* U+51ED */ - {0x9980, 0x00e587b0}, /* U+51F0 */ - {0x9981, 0x00e587b5}, /* U+51F5 */ - {0x9982, 0x00e587be}, /* U+51FE */ - {0x9983, 0x00e58884}, /* U+5204 */ - {0x9984, 0x00e5888b}, /* U+520B */ - {0x9985, 0x00e58894}, /* U+5214 */ - {0x9986, 0x00e5888e}, /* U+520E */ - {0x9987, 0x00e588a7}, /* U+5227 */ - {0x9988, 0x00e588aa}, /* U+522A */ - {0x9989, 0x00e588ae}, /* U+522E */ - {0x998a, 0x00e588b3}, /* U+5233 */ - {0x998b, 0x00e588b9}, /* U+5239 */ - {0x998c, 0x00e5898f}, /* U+524F */ - {0x998d, 0x00e58984}, /* U+5244 */ - {0x998e, 0x00e5898b}, /* U+524B */ - {0x998f, 0x00e5898c}, /* U+524C */ - {0x9990, 0x00e5899e}, /* U+525E */ - {0x9991, 0x00e58994}, /* U+5254 */ - {0x9992, 0x00e589aa}, /* U+526A */ - {0x9993, 0x00e589b4}, /* U+5274 */ - {0x9994, 0x00e589a9}, /* U+5269 */ - {0x9995, 0x00e589b3}, /* U+5273 */ - {0x9996, 0x00e589bf}, /* U+527F */ - {0x9997, 0x00e589bd}, /* U+527D */ - {0x9998, 0x00e58a8d}, /* U+528D */ - {0x9999, 0x00e58a94}, /* U+5294 */ - {0x999a, 0x00e58a92}, /* U+5292 */ - {0x999b, 0x00e589b1}, /* U+5271 */ - {0x999c, 0x00e58a88}, /* U+5288 */ - {0x999d, 0x00e58a91}, /* U+5291 */ - {0x999e, 0x00e8bea8}, /* U+8FA8 */ - {0x999f, 0x00e8bea7}, /* U+8FA7 */ - {0x99a0, 0x00e58aac}, /* U+52AC */ - {0x99a1, 0x00e58aad}, /* U+52AD */ - {0x99a2, 0x00e58abc}, /* U+52BC */ - {0x99a3, 0x00e58ab5}, /* U+52B5 */ - {0x99a4, 0x00e58b81}, /* U+52C1 */ - {0x99a5, 0x00e58b8d}, /* U+52CD */ - {0x99a6, 0x00e58b97}, /* U+52D7 */ - {0x99a7, 0x00e58b9e}, /* U+52DE */ - {0x99a8, 0x00e58ba3}, /* U+52E3 */ - {0x99a9, 0x00e58ba6}, /* U+52E6 */ - {0x99aa, 0x00e9a3ad}, /* U+98ED */ - {0x99ab, 0x00e58ba0}, /* U+52E0 */ - {0x99ac, 0x00e58bb3}, /* U+52F3 */ - {0x99ad, 0x00e58bb5}, /* U+52F5 */ - {0x99ae, 0x00e58bb8}, /* U+52F8 */ - {0x99af, 0x00e58bb9}, /* U+52F9 */ - {0x99b0, 0x00e58c86}, /* U+5306 */ - {0x99b1, 0x00e58c88}, /* U+5308 */ - {0x99b2, 0x00e794b8}, /* U+7538 */ - {0x99b3, 0x00e58c8d}, /* U+530D */ - {0x99b4, 0x00e58c90}, /* U+5310 */ - {0x99b5, 0x00e58c8f}, /* U+530F */ - {0x99b6, 0x00e58c95}, /* U+5315 */ - {0x99b7, 0x00e58c9a}, /* U+531A */ - {0x99b8, 0x00e58ca3}, /* U+5323 */ - {0x99b9, 0x00e58caf}, /* U+532F */ - {0x99ba, 0x00e58cb1}, /* U+5331 */ - {0x99bb, 0x00e58cb3}, /* U+5333 */ - {0x99bc, 0x00e58cb8}, /* U+5338 */ - {0x99bd, 0x00e58d80}, /* U+5340 */ - {0x99be, 0x00e58d86}, /* U+5346 */ - {0x99bf, 0x00e58d85}, /* U+5345 */ - {0x99c0, 0x00e4b897}, /* U+4E17 */ - {0x99c1, 0x00e58d89}, /* U+5349 */ - {0x99c2, 0x00e58d8d}, /* U+534D */ - {0x99c3, 0x00e58796}, /* U+51D6 */ - {0x99c4, 0x00e58d9e}, /* U+535E */ - {0x99c5, 0x00e58da9}, /* U+5369 */ - {0x99c6, 0x00e58dae}, /* U+536E */ - {0x99c7, 0x00e5a498}, /* U+5918 */ - {0x99c8, 0x00e58dbb}, /* U+537B */ - {0x99c9, 0x00e58db7}, /* U+5377 */ - {0x99ca, 0x00e58e82}, /* U+5382 */ - {0x99cb, 0x00e58e96}, /* U+5396 */ - {0x99cc, 0x00e58ea0}, /* U+53A0 */ - {0x99cd, 0x00e58ea6}, /* U+53A6 */ - {0x99ce, 0x00e58ea5}, /* U+53A5 */ - {0x99cf, 0x00e58eae}, /* U+53AE */ - {0x99d0, 0x00e58eb0}, /* U+53B0 */ - {0x99d1, 0x00e58eb6}, /* U+53B6 */ - {0x99d2, 0x00e58f83}, /* U+53C3 */ - {0x99d3, 0x00e7b092}, /* U+7C12 */ - {0x99d4, 0x00e99b99}, /* U+96D9 */ - {0x99d5, 0x00e58f9f}, /* U+53DF */ - {0x99d6, 0x00e69bbc}, /* U+66FC */ - {0x99d7, 0x00e787ae}, /* U+71EE */ - {0x99d8, 0x00e58fae}, /* U+53EE */ - {0x99d9, 0x00e58fa8}, /* U+53E8 */ - {0x99da, 0x00e58fad}, /* U+53ED */ - {0x99db, 0x00e58fba}, /* U+53FA */ - {0x99dc, 0x00e59081}, /* U+5401 */ - {0x99dd, 0x00e590bd}, /* U+543D */ - {0x99de, 0x00e59180}, /* U+5440 */ - {0x99df, 0x00e590ac}, /* U+542C */ - {0x99e0, 0x00e590ad}, /* U+542D */ - {0x99e1, 0x00e590bc}, /* U+543C */ - {0x99e2, 0x00e590ae}, /* U+542E */ - {0x99e3, 0x00e590b6}, /* U+5436 */ - {0x99e4, 0x00e590a9}, /* U+5429 */ - {0x99e5, 0x00e5909d}, /* U+541D */ - {0x99e6, 0x00e5918e}, /* U+544E */ - {0x99e7, 0x00e5928f}, /* U+548F */ - {0x99e8, 0x00e591b5}, /* U+5475 */ - {0x99e9, 0x00e5928e}, /* U+548E */ - {0x99ea, 0x00e5919f}, /* U+545F */ - {0x99eb, 0x00e591b1}, /* U+5471 */ - {0x99ec, 0x00e591b7}, /* U+5477 */ - {0x99ed, 0x00e591b0}, /* U+5470 */ - {0x99ee, 0x00e59292}, /* U+5492 */ - {0x99ef, 0x00e591bb}, /* U+547B */ - {0x99f0, 0x00e59280}, /* U+5480 */ - {0x99f1, 0x00e591b6}, /* U+5476 */ - {0x99f2, 0x00e59284}, /* U+5484 */ - {0x99f3, 0x00e59290}, /* U+5490 */ - {0x99f4, 0x00e59286}, /* U+5486 */ - {0x99f5, 0x00e59387}, /* U+54C7 */ - {0x99f6, 0x00e592a2}, /* U+54A2 */ - {0x99f7, 0x00e592b8}, /* U+54B8 */ - {0x99f8, 0x00e592a5}, /* U+54A5 */ - {0x99f9, 0x00e592ac}, /* U+54AC */ - {0x99fa, 0x00e59384}, /* U+54C4 */ - {0x99fb, 0x00e59388}, /* U+54C8 */ - {0x99fc, 0x00e592a8}, /* U+54A8 */ - {0x9a40, 0x00e592ab}, /* U+54AB */ - {0x9a41, 0x00e59382}, /* U+54C2 */ - {0x9a42, 0x00e592a4}, /* U+54A4 */ - {0x9a43, 0x00e592be}, /* U+54BE */ - {0x9a44, 0x00e592bc}, /* U+54BC */ - {0x9a45, 0x00e59398}, /* U+54D8 */ - {0x9a46, 0x00e593a5}, /* U+54E5 */ - {0x9a47, 0x00e593a6}, /* U+54E6 */ - {0x9a48, 0x00e5948f}, /* U+550F */ - {0x9a49, 0x00e59494}, /* U+5514 */ - {0x9a4a, 0x00e593bd}, /* U+54FD */ - {0x9a4b, 0x00e593ae}, /* U+54EE */ - {0x9a4c, 0x00e593ad}, /* U+54ED */ - {0x9a4d, 0x00e593ba}, /* U+54FA */ - {0x9a4e, 0x00e593a2}, /* U+54E2 */ - {0x9a4f, 0x00e594b9}, /* U+5539 */ - {0x9a50, 0x00e59580}, /* U+5540 */ - {0x9a51, 0x00e595a3}, /* U+5563 */ - {0x9a52, 0x00e5958c}, /* U+554C */ - {0x9a53, 0x00e594ae}, /* U+552E */ - {0x9a54, 0x00e5959c}, /* U+555C */ - {0x9a55, 0x00e59585}, /* U+5545 */ - {0x9a56, 0x00e59596}, /* U+5556 */ - {0x9a57, 0x00e59597}, /* U+5557 */ - {0x9a58, 0x00e594b8}, /* U+5538 */ - {0x9a59, 0x00e594b3}, /* U+5533 */ - {0x9a5a, 0x00e5959d}, /* U+555D */ - {0x9a5b, 0x00e59699}, /* U+5599 */ - {0x9a5c, 0x00e59680}, /* U+5580 */ - {0x9a5d, 0x00e592af}, /* U+54AF */ - {0x9a5e, 0x00e5968a}, /* U+558A */ - {0x9a5f, 0x00e5969f}, /* U+559F */ - {0x9a60, 0x00e595bb}, /* U+557B */ - {0x9a61, 0x00e595be}, /* U+557E */ - {0x9a62, 0x00e59698}, /* U+5598 */ - {0x9a63, 0x00e5969e}, /* U+559E */ - {0x9a64, 0x00e596ae}, /* U+55AE */ - {0x9a65, 0x00e595bc}, /* U+557C */ - {0x9a66, 0x00e59683}, /* U+5583 */ - {0x9a67, 0x00e596a9}, /* U+55A9 */ - {0x9a68, 0x00e59687}, /* U+5587 */ - {0x9a69, 0x00e596a8}, /* U+55A8 */ - {0x9a6a, 0x00e5979a}, /* U+55DA */ - {0x9a6b, 0x00e59785}, /* U+55C5 */ - {0x9a6c, 0x00e5979f}, /* U+55DF */ - {0x9a6d, 0x00e59784}, /* U+55C4 */ - {0x9a6e, 0x00e5979c}, /* U+55DC */ - {0x9a6f, 0x00e597a4}, /* U+55E4 */ - {0x9a70, 0x00e59794}, /* U+55D4 */ - {0x9a71, 0x00e59894}, /* U+5614 */ - {0x9a72, 0x00e597b7}, /* U+55F7 */ - {0x9a73, 0x00e59896}, /* U+5616 */ - {0x9a74, 0x00e597be}, /* U+55FE */ - {0x9a75, 0x00e597bd}, /* U+55FD */ - {0x9a76, 0x00e5989b}, /* U+561B */ - {0x9a77, 0x00e597b9}, /* U+55F9 */ - {0x9a78, 0x00e5998e}, /* U+564E */ - {0x9a79, 0x00e59990}, /* U+5650 */ - {0x9a7a, 0x00e7879f}, /* U+71DF */ - {0x9a7b, 0x00e598b4}, /* U+5634 */ - {0x9a7c, 0x00e598b6}, /* U+5636 */ - {0x9a7d, 0x00e598b2}, /* U+5632 */ - {0x9a7e, 0x00e598b8}, /* U+5638 */ - {0x9a80, 0x00e599ab}, /* U+566B */ - {0x9a81, 0x00e599a4}, /* U+5664 */ - {0x9a82, 0x00e598af}, /* U+562F */ - {0x9a83, 0x00e599ac}, /* U+566C */ - {0x9a84, 0x00e599aa}, /* U+566A */ - {0x9a85, 0x00e59a86}, /* U+5686 */ - {0x9a86, 0x00e59a80}, /* U+5680 */ - {0x9a87, 0x00e59a8a}, /* U+568A */ - {0x9a88, 0x00e59aa0}, /* U+56A0 */ - {0x9a89, 0x00e59a94}, /* U+5694 */ - {0x9a8a, 0x00e59a8f}, /* U+568F */ - {0x9a8b, 0x00e59aa5}, /* U+56A5 */ - {0x9a8c, 0x00e59aae}, /* U+56AE */ - {0x9a8d, 0x00e59ab6}, /* U+56B6 */ - {0x9a8e, 0x00e59ab4}, /* U+56B4 */ - {0x9a8f, 0x00e59b82}, /* U+56C2 */ - {0x9a90, 0x00e59abc}, /* U+56BC */ - {0x9a91, 0x00e59b81}, /* U+56C1 */ - {0x9a92, 0x00e59b83}, /* U+56C3 */ - {0x9a93, 0x00e59b80}, /* U+56C0 */ - {0x9a94, 0x00e59b88}, /* U+56C8 */ - {0x9a95, 0x00e59b8e}, /* U+56CE */ - {0x9a96, 0x00e59b91}, /* U+56D1 */ - {0x9a97, 0x00e59b93}, /* U+56D3 */ - {0x9a98, 0x00e59b97}, /* U+56D7 */ - {0x9a99, 0x00e59bae}, /* U+56EE */ - {0x9a9a, 0x00e59bb9}, /* U+56F9 */ - {0x9a9b, 0x00e59c80}, /* U+5700 */ - {0x9a9c, 0x00e59bbf}, /* U+56FF */ - {0x9a9d, 0x00e59c84}, /* U+5704 */ - {0x9a9e, 0x00e59c89}, /* U+5709 */ - {0x9a9f, 0x00e59c88}, /* U+5708 */ - {0x9aa0, 0x00e59c8b}, /* U+570B */ - {0x9aa1, 0x00e59c8d}, /* U+570D */ - {0x9aa2, 0x00e59c93}, /* U+5713 */ - {0x9aa3, 0x00e59c98}, /* U+5718 */ - {0x9aa4, 0x00e59c96}, /* U+5716 */ - {0x9aa5, 0x00e59787}, /* U+55C7 */ - {0x9aa6, 0x00e59c9c}, /* U+571C */ - {0x9aa7, 0x00e59ca6}, /* U+5726 */ - {0x9aa8, 0x00e59cb7}, /* U+5737 */ - {0x9aa9, 0x00e59cb8}, /* U+5738 */ - {0x9aaa, 0x00e59d8e}, /* U+574E */ - {0x9aab, 0x00e59cbb}, /* U+573B */ - {0x9aac, 0x00e59d80}, /* U+5740 */ - {0x9aad, 0x00e59d8f}, /* U+574F */ - {0x9aae, 0x00e59da9}, /* U+5769 */ - {0x9aaf, 0x00e59f80}, /* U+57C0 */ - {0x9ab0, 0x00e59e88}, /* U+5788 */ - {0x9ab1, 0x00e59da1}, /* U+5761 */ - {0x9ab2, 0x00e59dbf}, /* U+577F */ - {0x9ab3, 0x00e59e89}, /* U+5789 */ - {0x9ab4, 0x00e59e93}, /* U+5793 */ - {0x9ab5, 0x00e59ea0}, /* U+57A0 */ - {0x9ab6, 0x00e59eb3}, /* U+57B3 */ - {0x9ab7, 0x00e59ea4}, /* U+57A4 */ - {0x9ab8, 0x00e59eaa}, /* U+57AA */ - {0x9ab9, 0x00e59eb0}, /* U+57B0 */ - {0x9aba, 0x00e59f83}, /* U+57C3 */ - {0x9abb, 0x00e59f86}, /* U+57C6 */ - {0x9abc, 0x00e59f94}, /* U+57D4 */ - {0x9abd, 0x00e59f92}, /* U+57D2 */ - {0x9abe, 0x00e59f93}, /* U+57D3 */ - {0x9abf, 0x00e5a08a}, /* U+580A */ - {0x9ac0, 0x00e59f96}, /* U+57D6 */ - {0x9ac1, 0x00e59fa3}, /* U+57E3 */ - {0x9ac2, 0x00e5a08b}, /* U+580B */ - {0x9ac3, 0x00e5a099}, /* U+5819 */ - {0x9ac4, 0x00e5a09d}, /* U+581D */ - {0x9ac5, 0x00e5a1b2}, /* U+5872 */ - {0x9ac6, 0x00e5a0a1}, /* U+5821 */ - {0x9ac7, 0x00e5a1a2}, /* U+5862 */ - {0x9ac8, 0x00e5a18b}, /* U+584B */ - {0x9ac9, 0x00e5a1b0}, /* U+5870 */ - {0x9aca, 0x00e6af80}, /* U+6BC0 */ - {0x9acb, 0x00e5a192}, /* U+5852 */ - {0x9acc, 0x00e5a0bd}, /* U+583D */ - {0x9acd, 0x00e5a1b9}, /* U+5879 */ - {0x9ace, 0x00e5a285}, /* U+5885 */ - {0x9acf, 0x00e5a2b9}, /* U+58B9 */ - {0x9ad0, 0x00e5a29f}, /* U+589F */ - {0x9ad1, 0x00e5a2ab}, /* U+58AB */ - {0x9ad2, 0x00e5a2ba}, /* U+58BA */ - {0x9ad3, 0x00e5a39e}, /* U+58DE */ - {0x9ad4, 0x00e5a2bb}, /* U+58BB */ - {0x9ad5, 0x00e5a2b8}, /* U+58B8 */ - {0x9ad6, 0x00e5a2ae}, /* U+58AE */ - {0x9ad7, 0x00e5a385}, /* U+58C5 */ - {0x9ad8, 0x00e5a393}, /* U+58D3 */ - {0x9ad9, 0x00e5a391}, /* U+58D1 */ - {0x9ada, 0x00e5a397}, /* U+58D7 */ - {0x9adb, 0x00e5a399}, /* U+58D9 */ - {0x9adc, 0x00e5a398}, /* U+58D8 */ - {0x9add, 0x00e5a3a5}, /* U+58E5 */ - {0x9ade, 0x00e5a39c}, /* U+58DC */ - {0x9adf, 0x00e5a3a4}, /* U+58E4 */ - {0x9ae0, 0x00e5a39f}, /* U+58DF */ - {0x9ae1, 0x00e5a3af}, /* U+58EF */ - {0x9ae2, 0x00e5a3ba}, /* U+58FA */ - {0x9ae3, 0x00e5a3b9}, /* U+58F9 */ - {0x9ae4, 0x00e5a3bb}, /* U+58FB */ - {0x9ae5, 0x00e5a3bc}, /* U+58FC */ - {0x9ae6, 0x00e5a3bd}, /* U+58FD */ - {0x9ae7, 0x00e5a482}, /* U+5902 */ - {0x9ae8, 0x00e5a48a}, /* U+590A */ - {0x9ae9, 0x00e5a490}, /* U+5910 */ - {0x9aea, 0x00e5a49b}, /* U+591B */ - {0x9aeb, 0x00e6a2a6}, /* U+68A6 */ - {0x9aec, 0x00e5a4a5}, /* U+5925 */ - {0x9aed, 0x00e5a4ac}, /* U+592C */ - {0x9aee, 0x00e5a4ad}, /* U+592D */ - {0x9aef, 0x00e5a4b2}, /* U+5932 */ - {0x9af0, 0x00e5a4b8}, /* U+5938 */ - {0x9af1, 0x00e5a4be}, /* U+593E */ - {0x9af2, 0x00e7ab92}, /* U+7AD2 */ - {0x9af3, 0x00e5a595}, /* U+5955 */ - {0x9af4, 0x00e5a590}, /* U+5950 */ - {0x9af5, 0x00e5a58e}, /* U+594E */ - {0x9af6, 0x00e5a59a}, /* U+595A */ - {0x9af7, 0x00e5a598}, /* U+5958 */ - {0x9af8, 0x00e5a5a2}, /* U+5962 */ - {0x9af9, 0x00e5a5a0}, /* U+5960 */ - {0x9afa, 0x00e5a5a7}, /* U+5967 */ - {0x9afb, 0x00e5a5ac}, /* U+596C */ - {0x9afc, 0x00e5a5a9}, /* U+5969 */ - {0x9b40, 0x00e5a5b8}, /* U+5978 */ - {0x9b41, 0x00e5a681}, /* U+5981 */ - {0x9b42, 0x00e5a69d}, /* U+599D */ - {0x9b43, 0x00e4bd9e}, /* U+4F5E */ - {0x9b44, 0x00e4beab}, /* U+4FAB */ - {0x9b45, 0x00e5a6a3}, /* U+59A3 */ - {0x9b46, 0x00e5a6b2}, /* U+59B2 */ - {0x9b47, 0x00e5a786}, /* U+59C6 */ - {0x9b48, 0x00e5a7a8}, /* U+59E8 */ - {0x9b49, 0x00e5a79c}, /* U+59DC */ - {0x9b4a, 0x00e5a68d}, /* U+598D */ - {0x9b4b, 0x00e5a799}, /* U+59D9 */ - {0x9b4c, 0x00e5a79a}, /* U+59DA */ - {0x9b4d, 0x00e5a8a5}, /* U+5A25 */ - {0x9b4e, 0x00e5a89f}, /* U+5A1F */ - {0x9b4f, 0x00e5a891}, /* U+5A11 */ - {0x9b50, 0x00e5a89c}, /* U+5A1C */ - {0x9b51, 0x00e5a889}, /* U+5A09 */ - {0x9b52, 0x00e5a89a}, /* U+5A1A */ - {0x9b53, 0x00e5a980}, /* U+5A40 */ - {0x9b54, 0x00e5a9ac}, /* U+5A6C */ - {0x9b55, 0x00e5a989}, /* U+5A49 */ - {0x9b56, 0x00e5a8b5}, /* U+5A35 */ - {0x9b57, 0x00e5a8b6}, /* U+5A36 */ - {0x9b58, 0x00e5a9a2}, /* U+5A62 */ - {0x9b59, 0x00e5a9aa}, /* U+5A6A */ - {0x9b5a, 0x00e5aa9a}, /* U+5A9A */ - {0x9b5b, 0x00e5aabc}, /* U+5ABC */ - {0x9b5c, 0x00e5aabe}, /* U+5ABE */ - {0x9b5d, 0x00e5ab8b}, /* U+5ACB */ - {0x9b5e, 0x00e5ab82}, /* U+5AC2 */ - {0x9b5f, 0x00e5aabd}, /* U+5ABD */ - {0x9b60, 0x00e5aba3}, /* U+5AE3 */ - {0x9b61, 0x00e5ab97}, /* U+5AD7 */ - {0x9b62, 0x00e5aba6}, /* U+5AE6 */ - {0x9b63, 0x00e5aba9}, /* U+5AE9 */ - {0x9b64, 0x00e5ab96}, /* U+5AD6 */ - {0x9b65, 0x00e5abba}, /* U+5AFA */ - {0x9b66, 0x00e5abbb}, /* U+5AFB */ - {0x9b67, 0x00e5ac8c}, /* U+5B0C */ - {0x9b68, 0x00e5ac8b}, /* U+5B0B */ - {0x9b69, 0x00e5ac96}, /* U+5B16 */ - {0x9b6a, 0x00e5acb2}, /* U+5B32 */ - {0x9b6b, 0x00e5ab90}, /* U+5AD0 */ - {0x9b6c, 0x00e5acaa}, /* U+5B2A */ - {0x9b6d, 0x00e5acb6}, /* U+5B36 */ - {0x9b6e, 0x00e5acbe}, /* U+5B3E */ - {0x9b6f, 0x00e5ad83}, /* U+5B43 */ - {0x9b70, 0x00e5ad85}, /* U+5B45 */ - {0x9b71, 0x00e5ad80}, /* U+5B40 */ - {0x9b72, 0x00e5ad91}, /* U+5B51 */ - {0x9b73, 0x00e5ad95}, /* U+5B55 */ - {0x9b74, 0x00e5ad9a}, /* U+5B5A */ - {0x9b75, 0x00e5ad9b}, /* U+5B5B */ - {0x9b76, 0x00e5ada5}, /* U+5B65 */ - {0x9b77, 0x00e5ada9}, /* U+5B69 */ - {0x9b78, 0x00e5adb0}, /* U+5B70 */ - {0x9b79, 0x00e5adb3}, /* U+5B73 */ - {0x9b7a, 0x00e5adb5}, /* U+5B75 */ - {0x9b7b, 0x00e5adb8}, /* U+5B78 */ - {0x9b7c, 0x00e69688}, /* U+6588 */ - {0x9b7d, 0x00e5adba}, /* U+5B7A */ - {0x9b7e, 0x00e5ae80}, /* U+5B80 */ - {0x9b80, 0x00e5ae83}, /* U+5B83 */ - {0x9b81, 0x00e5aea6}, /* U+5BA6 */ - {0x9b82, 0x00e5aeb8}, /* U+5BB8 */ - {0x9b83, 0x00e5af83}, /* U+5BC3 */ - {0x9b84, 0x00e5af87}, /* U+5BC7 */ - {0x9b85, 0x00e5af89}, /* U+5BC9 */ - {0x9b86, 0x00e5af94}, /* U+5BD4 */ - {0x9b87, 0x00e5af90}, /* U+5BD0 */ - {0x9b88, 0x00e5afa4}, /* U+5BE4 */ - {0x9b89, 0x00e5afa6}, /* U+5BE6 */ - {0x9b8a, 0x00e5afa2}, /* U+5BE2 */ - {0x9b8b, 0x00e5af9e}, /* U+5BDE */ - {0x9b8c, 0x00e5afa5}, /* U+5BE5 */ - {0x9b8d, 0x00e5afab}, /* U+5BEB */ - {0x9b8e, 0x00e5afb0}, /* U+5BF0 */ - {0x9b8f, 0x00e5afb6}, /* U+5BF6 */ - {0x9b90, 0x00e5afb3}, /* U+5BF3 */ - {0x9b91, 0x00e5b085}, /* U+5C05 */ - {0x9b92, 0x00e5b087}, /* U+5C07 */ - {0x9b93, 0x00e5b088}, /* U+5C08 */ - {0x9b94, 0x00e5b08d}, /* U+5C0D */ - {0x9b95, 0x00e5b093}, /* U+5C13 */ - {0x9b96, 0x00e5b0a0}, /* U+5C20 */ - {0x9b97, 0x00e5b0a2}, /* U+5C22 */ - {0x9b98, 0x00e5b0a8}, /* U+5C28 */ - {0x9b99, 0x00e5b0b8}, /* U+5C38 */ - {0x9b9a, 0x00e5b0b9}, /* U+5C39 */ - {0x9b9b, 0x00e5b181}, /* U+5C41 */ - {0x9b9c, 0x00e5b186}, /* U+5C46 */ - {0x9b9d, 0x00e5b18e}, /* U+5C4E */ - {0x9b9e, 0x00e5b193}, /* U+5C53 */ - {0x9b9f, 0x00e5b190}, /* U+5C50 */ - {0x9ba0, 0x00e5b18f}, /* U+5C4F */ - {0x9ba1, 0x00e5adb1}, /* U+5B71 */ - {0x9ba2, 0x00e5b1ac}, /* U+5C6C */ - {0x9ba3, 0x00e5b1ae}, /* U+5C6E */ - {0x9ba4, 0x00e4b9a2}, /* U+4E62 */ - {0x9ba5, 0x00e5b1b6}, /* U+5C76 */ - {0x9ba6, 0x00e5b1b9}, /* U+5C79 */ - {0x9ba7, 0x00e5b28c}, /* U+5C8C */ - {0x9ba8, 0x00e5b291}, /* U+5C91 */ - {0x9ba9, 0x00e5b294}, /* U+5C94 */ - {0x9baa, 0x00e5a69b}, /* U+599B */ - {0x9bab, 0x00e5b2ab}, /* U+5CAB */ - {0x9bac, 0x00e5b2bb}, /* U+5CBB */ - {0x9bad, 0x00e5b2b6}, /* U+5CB6 */ - {0x9bae, 0x00e5b2bc}, /* U+5CBC */ - {0x9baf, 0x00e5b2b7}, /* U+5CB7 */ - {0x9bb0, 0x00e5b385}, /* U+5CC5 */ - {0x9bb1, 0x00e5b2be}, /* U+5CBE */ - {0x9bb2, 0x00e5b387}, /* U+5CC7 */ - {0x9bb3, 0x00e5b399}, /* U+5CD9 */ - {0x9bb4, 0x00e5b3a9}, /* U+5CE9 */ - {0x9bb5, 0x00e5b3bd}, /* U+5CFD */ - {0x9bb6, 0x00e5b3ba}, /* U+5CFA */ - {0x9bb7, 0x00e5b3ad}, /* U+5CED */ - {0x9bb8, 0x00e5b68c}, /* U+5D8C */ - {0x9bb9, 0x00e5b3aa}, /* U+5CEA */ - {0x9bba, 0x00e5b48b}, /* U+5D0B */ - {0x9bbb, 0x00e5b495}, /* U+5D15 */ - {0x9bbc, 0x00e5b497}, /* U+5D17 */ - {0x9bbd, 0x00e5b59c}, /* U+5D5C */ - {0x9bbe, 0x00e5b49f}, /* U+5D1F */ - {0x9bbf, 0x00e5b49b}, /* U+5D1B */ - {0x9bc0, 0x00e5b491}, /* U+5D11 */ - {0x9bc1, 0x00e5b494}, /* U+5D14 */ - {0x9bc2, 0x00e5b4a2}, /* U+5D22 */ - {0x9bc3, 0x00e5b49a}, /* U+5D1A */ - {0x9bc4, 0x00e5b499}, /* U+5D19 */ - {0x9bc5, 0x00e5b498}, /* U+5D18 */ - {0x9bc6, 0x00e5b58c}, /* U+5D4C */ - {0x9bc7, 0x00e5b592}, /* U+5D52 */ - {0x9bc8, 0x00e5b58e}, /* U+5D4E */ - {0x9bc9, 0x00e5b58b}, /* U+5D4B */ - {0x9bca, 0x00e5b5ac}, /* U+5D6C */ - {0x9bcb, 0x00e5b5b3}, /* U+5D73 */ - {0x9bcc, 0x00e5b5b6}, /* U+5D76 */ - {0x9bcd, 0x00e5b687}, /* U+5D87 */ - {0x9bce, 0x00e5b684}, /* U+5D84 */ - {0x9bcf, 0x00e5b682}, /* U+5D82 */ - {0x9bd0, 0x00e5b6a2}, /* U+5DA2 */ - {0x9bd1, 0x00e5b69d}, /* U+5D9D */ - {0x9bd2, 0x00e5b6ac}, /* U+5DAC */ - {0x9bd3, 0x00e5b6ae}, /* U+5DAE */ - {0x9bd4, 0x00e5b6bd}, /* U+5DBD */ - {0x9bd5, 0x00e5b690}, /* U+5D90 */ - {0x9bd6, 0x00e5b6b7}, /* U+5DB7 */ - {0x9bd7, 0x00e5b6bc}, /* U+5DBC */ - {0x9bd8, 0x00e5b789}, /* U+5DC9 */ - {0x9bd9, 0x00e5b78d}, /* U+5DCD */ - {0x9bda, 0x00e5b793}, /* U+5DD3 */ - {0x9bdb, 0x00e5b792}, /* U+5DD2 */ - {0x9bdc, 0x00e5b796}, /* U+5DD6 */ - {0x9bdd, 0x00e5b79b}, /* U+5DDB */ - {0x9bde, 0x00e5b7ab}, /* U+5DEB */ - {0x9bdf, 0x00e5b7b2}, /* U+5DF2 */ - {0x9be0, 0x00e5b7b5}, /* U+5DF5 */ - {0x9be1, 0x00e5b88b}, /* U+5E0B */ - {0x9be2, 0x00e5b89a}, /* U+5E1A */ - {0x9be3, 0x00e5b899}, /* U+5E19 */ - {0x9be4, 0x00e5b891}, /* U+5E11 */ - {0x9be5, 0x00e5b89b}, /* U+5E1B */ - {0x9be6, 0x00e5b8b6}, /* U+5E36 */ - {0x9be7, 0x00e5b8b7}, /* U+5E37 */ - {0x9be8, 0x00e5b984}, /* U+5E44 */ - {0x9be9, 0x00e5b983}, /* U+5E43 */ - {0x9bea, 0x00e5b980}, /* U+5E40 */ - {0x9beb, 0x00e5b98e}, /* U+5E4E */ - {0x9bec, 0x00e5b997}, /* U+5E57 */ - {0x9bed, 0x00e5b994}, /* U+5E54 */ - {0x9bee, 0x00e5b99f}, /* U+5E5F */ - {0x9bef, 0x00e5b9a2}, /* U+5E62 */ - {0x9bf0, 0x00e5b9a4}, /* U+5E64 */ - {0x9bf1, 0x00e5b987}, /* U+5E47 */ - {0x9bf2, 0x00e5b9b5}, /* U+5E75 */ - {0x9bf3, 0x00e5b9b6}, /* U+5E76 */ - {0x9bf4, 0x00e5b9ba}, /* U+5E7A */ - {0x9bf5, 0x00e9babc}, /* U+9EBC */ - {0x9bf6, 0x00e5b9bf}, /* U+5E7F */ - {0x9bf7, 0x00e5baa0}, /* U+5EA0 */ - {0x9bf8, 0x00e5bb81}, /* U+5EC1 */ - {0x9bf9, 0x00e5bb82}, /* U+5EC2 */ - {0x9bfa, 0x00e5bb88}, /* U+5EC8 */ - {0x9bfb, 0x00e5bb90}, /* U+5ED0 */ - {0x9bfc, 0x00e5bb8f}, /* U+5ECF */ - {0x9c40, 0x00e5bb96}, /* U+5ED6 */ - {0x9c41, 0x00e5bba3}, /* U+5EE3 */ - {0x9c42, 0x00e5bb9d}, /* U+5EDD */ - {0x9c43, 0x00e5bb9a}, /* U+5EDA */ - {0x9c44, 0x00e5bb9b}, /* U+5EDB */ - {0x9c45, 0x00e5bba2}, /* U+5EE2 */ - {0x9c46, 0x00e5bba1}, /* U+5EE1 */ - {0x9c47, 0x00e5bba8}, /* U+5EE8 */ - {0x9c48, 0x00e5bba9}, /* U+5EE9 */ - {0x9c49, 0x00e5bbac}, /* U+5EEC */ - {0x9c4a, 0x00e5bbb1}, /* U+5EF1 */ - {0x9c4b, 0x00e5bbb3}, /* U+5EF3 */ - {0x9c4c, 0x00e5bbb0}, /* U+5EF0 */ - {0x9c4d, 0x00e5bbb4}, /* U+5EF4 */ - {0x9c4e, 0x00e5bbb8}, /* U+5EF8 */ - {0x9c4f, 0x00e5bbbe}, /* U+5EFE */ - {0x9c50, 0x00e5bc83}, /* U+5F03 */ - {0x9c51, 0x00e5bc89}, /* U+5F09 */ - {0x9c52, 0x00e5bd9d}, /* U+5F5D */ - {0x9c53, 0x00e5bd9c}, /* U+5F5C */ - {0x9c54, 0x00e5bc8b}, /* U+5F0B */ - {0x9c55, 0x00e5bc91}, /* U+5F11 */ - {0x9c56, 0x00e5bc96}, /* U+5F16 */ - {0x9c57, 0x00e5bca9}, /* U+5F29 */ - {0x9c58, 0x00e5bcad}, /* U+5F2D */ - {0x9c59, 0x00e5bcb8}, /* U+5F38 */ - {0x9c5a, 0x00e5bd81}, /* U+5F41 */ - {0x9c5b, 0x00e5bd88}, /* U+5F48 */ - {0x9c5c, 0x00e5bd8c}, /* U+5F4C */ - {0x9c5d, 0x00e5bd8e}, /* U+5F4E */ - {0x9c5e, 0x00e5bcaf}, /* U+5F2F */ - {0x9c5f, 0x00e5bd91}, /* U+5F51 */ - {0x9c60, 0x00e5bd96}, /* U+5F56 */ - {0x9c61, 0x00e5bd97}, /* U+5F57 */ - {0x9c62, 0x00e5bd99}, /* U+5F59 */ - {0x9c63, 0x00e5bda1}, /* U+5F61 */ - {0x9c64, 0x00e5bdad}, /* U+5F6D */ - {0x9c65, 0x00e5bdb3}, /* U+5F73 */ - {0x9c66, 0x00e5bdb7}, /* U+5F77 */ - {0x9c67, 0x00e5be83}, /* U+5F83 */ - {0x9c68, 0x00e5be82}, /* U+5F82 */ - {0x9c69, 0x00e5bdbf}, /* U+5F7F */ - {0x9c6a, 0x00e5be8a}, /* U+5F8A */ - {0x9c6b, 0x00e5be88}, /* U+5F88 */ - {0x9c6c, 0x00e5be91}, /* U+5F91 */ - {0x9c6d, 0x00e5be87}, /* U+5F87 */ - {0x9c6e, 0x00e5be9e}, /* U+5F9E */ - {0x9c6f, 0x00e5be99}, /* U+5F99 */ - {0x9c70, 0x00e5be98}, /* U+5F98 */ - {0x9c71, 0x00e5bea0}, /* U+5FA0 */ - {0x9c72, 0x00e5bea8}, /* U+5FA8 */ - {0x9c73, 0x00e5bead}, /* U+5FAD */ - {0x9c74, 0x00e5bebc}, /* U+5FBC */ - {0x9c75, 0x00e5bf96}, /* U+5FD6 */ - {0x9c76, 0x00e5bfbb}, /* U+5FFB */ - {0x9c77, 0x00e5bfa4}, /* U+5FE4 */ - {0x9c78, 0x00e5bfb8}, /* U+5FF8 */ - {0x9c79, 0x00e5bfb1}, /* U+5FF1 */ - {0x9c7a, 0x00e5bf9d}, /* U+5FDD */ - {0x9c7b, 0x00e682b3}, /* U+60B3 */ - {0x9c7c, 0x00e5bfbf}, /* U+5FFF */ - {0x9c7d, 0x00e680a1}, /* U+6021 */ - {0x9c7e, 0x00e681a0}, /* U+6060 */ - {0x9c80, 0x00e68099}, /* U+6019 */ - {0x9c81, 0x00e68090}, /* U+6010 */ - {0x9c82, 0x00e680a9}, /* U+6029 */ - {0x9c83, 0x00e6808e}, /* U+600E */ - {0x9c84, 0x00e680b1}, /* U+6031 */ - {0x9c85, 0x00e6809b}, /* U+601B */ - {0x9c86, 0x00e68095}, /* U+6015 */ - {0x9c87, 0x00e680ab}, /* U+602B */ - {0x9c88, 0x00e680a6}, /* U+6026 */ - {0x9c89, 0x00e6808f}, /* U+600F */ - {0x9c8a, 0x00e680ba}, /* U+603A */ - {0x9c8b, 0x00e6819a}, /* U+605A */ - {0x9c8c, 0x00e68181}, /* U+6041 */ - {0x9c8d, 0x00e681aa}, /* U+606A */ - {0x9c8e, 0x00e681b7}, /* U+6077 */ - {0x9c8f, 0x00e6819f}, /* U+605F */ - {0x9c90, 0x00e6818a}, /* U+604A */ - {0x9c91, 0x00e68186}, /* U+6046 */ - {0x9c92, 0x00e6818d}, /* U+604D */ - {0x9c93, 0x00e681a3}, /* U+6063 */ - {0x9c94, 0x00e68183}, /* U+6043 */ - {0x9c95, 0x00e681a4}, /* U+6064 */ - {0x9c96, 0x00e68182}, /* U+6042 */ - {0x9c97, 0x00e681ac}, /* U+606C */ - {0x9c98, 0x00e681ab}, /* U+606B */ - {0x9c99, 0x00e68199}, /* U+6059 */ - {0x9c9a, 0x00e68281}, /* U+6081 */ - {0x9c9b, 0x00e6828d}, /* U+608D */ - {0x9c9c, 0x00e683a7}, /* U+60E7 */ - {0x9c9d, 0x00e68283}, /* U+6083 */ - {0x9c9e, 0x00e6829a}, /* U+609A */ - {0x9c9f, 0x00e68284}, /* U+6084 */ - {0x9ca0, 0x00e6829b}, /* U+609B */ - {0x9ca1, 0x00e68296}, /* U+6096 */ - {0x9ca2, 0x00e68297}, /* U+6097 */ - {0x9ca3, 0x00e68292}, /* U+6092 */ - {0x9ca4, 0x00e682a7}, /* U+60A7 */ - {0x9ca5, 0x00e6828b}, /* U+608B */ - {0x9ca6, 0x00e683a1}, /* U+60E1 */ - {0x9ca7, 0x00e682b8}, /* U+60B8 */ - {0x9ca8, 0x00e683a0}, /* U+60E0 */ - {0x9ca9, 0x00e68393}, /* U+60D3 */ - {0x9caa, 0x00e682b4}, /* U+60B4 */ - {0x9cab, 0x00e5bfb0}, /* U+5FF0 */ - {0x9cac, 0x00e682bd}, /* U+60BD */ - {0x9cad, 0x00e68386}, /* U+60C6 */ - {0x9cae, 0x00e682b5}, /* U+60B5 */ - {0x9caf, 0x00e68398}, /* U+60D8 */ - {0x9cb0, 0x00e6858d}, /* U+614D */ - {0x9cb1, 0x00e68495}, /* U+6115 */ - {0x9cb2, 0x00e68486}, /* U+6106 */ - {0x9cb3, 0x00e683b6}, /* U+60F6 */ - {0x9cb4, 0x00e683b7}, /* U+60F7 */ - {0x9cb5, 0x00e68480}, /* U+6100 */ - {0x9cb6, 0x00e683b4}, /* U+60F4 */ - {0x9cb7, 0x00e683ba}, /* U+60FA */ - {0x9cb8, 0x00e68483}, /* U+6103 */ - {0x9cb9, 0x00e684a1}, /* U+6121 */ - {0x9cba, 0x00e683bb}, /* U+60FB */ - {0x9cbb, 0x00e683b1}, /* U+60F1 */ - {0x9cbc, 0x00e6848d}, /* U+610D */ - {0x9cbd, 0x00e6848e}, /* U+610E */ - {0x9cbe, 0x00e68587}, /* U+6147 */ - {0x9cbf, 0x00e684be}, /* U+613E */ - {0x9cc0, 0x00e684a8}, /* U+6128 */ - {0x9cc1, 0x00e684a7}, /* U+6127 */ - {0x9cc2, 0x00e6858a}, /* U+614A */ - {0x9cc3, 0x00e684bf}, /* U+613F */ - {0x9cc4, 0x00e684bc}, /* U+613C */ - {0x9cc5, 0x00e684ac}, /* U+612C */ - {0x9cc6, 0x00e684b4}, /* U+6134 */ - {0x9cc7, 0x00e684bd}, /* U+613D */ - {0x9cc8, 0x00e68582}, /* U+6142 */ - {0x9cc9, 0x00e68584}, /* U+6144 */ - {0x9cca, 0x00e685b3}, /* U+6173 */ - {0x9ccb, 0x00e685b7}, /* U+6177 */ - {0x9ccc, 0x00e68598}, /* U+6158 */ - {0x9ccd, 0x00e68599}, /* U+6159 */ - {0x9cce, 0x00e6859a}, /* U+615A */ - {0x9ccf, 0x00e685ab}, /* U+616B */ - {0x9cd0, 0x00e685b4}, /* U+6174 */ - {0x9cd1, 0x00e685af}, /* U+616F */ - {0x9cd2, 0x00e685a5}, /* U+6165 */ - {0x9cd3, 0x00e685b1}, /* U+6171 */ - {0x9cd4, 0x00e6859f}, /* U+615F */ - {0x9cd5, 0x00e6859d}, /* U+615D */ - {0x9cd6, 0x00e68593}, /* U+6153 */ - {0x9cd7, 0x00e685b5}, /* U+6175 */ - {0x9cd8, 0x00e68699}, /* U+6199 */ - {0x9cd9, 0x00e68696}, /* U+6196 */ - {0x9cda, 0x00e68687}, /* U+6187 */ - {0x9cdb, 0x00e686ac}, /* U+61AC */ - {0x9cdc, 0x00e68694}, /* U+6194 */ - {0x9cdd, 0x00e6869a}, /* U+619A */ - {0x9cde, 0x00e6868a}, /* U+618A */ - {0x9cdf, 0x00e68691}, /* U+6191 */ - {0x9ce0, 0x00e686ab}, /* U+61AB */ - {0x9ce1, 0x00e686ae}, /* U+61AE */ - {0x9ce2, 0x00e6878c}, /* U+61CC */ - {0x9ce3, 0x00e6878a}, /* U+61CA */ - {0x9ce4, 0x00e68789}, /* U+61C9 */ - {0x9ce5, 0x00e687b7}, /* U+61F7 */ - {0x9ce6, 0x00e68788}, /* U+61C8 */ - {0x9ce7, 0x00e68783}, /* U+61C3 */ - {0x9ce8, 0x00e68786}, /* U+61C6 */ - {0x9ce9, 0x00e686ba}, /* U+61BA */ - {0x9cea, 0x00e6878b}, /* U+61CB */ - {0x9ceb, 0x00e7bdb9}, /* U+7F79 */ - {0x9cec, 0x00e6878d}, /* U+61CD */ - {0x9ced, 0x00e687a6}, /* U+61E6 */ - {0x9cee, 0x00e687a3}, /* U+61E3 */ - {0x9cef, 0x00e687b6}, /* U+61F6 */ - {0x9cf0, 0x00e687ba}, /* U+61FA */ - {0x9cf1, 0x00e687b4}, /* U+61F4 */ - {0x9cf2, 0x00e687bf}, /* U+61FF */ - {0x9cf3, 0x00e687bd}, /* U+61FD */ - {0x9cf4, 0x00e687bc}, /* U+61FC */ - {0x9cf5, 0x00e687be}, /* U+61FE */ - {0x9cf6, 0x00e68880}, /* U+6200 */ - {0x9cf7, 0x00e68888}, /* U+6208 */ - {0x9cf8, 0x00e68889}, /* U+6209 */ - {0x9cf9, 0x00e6888d}, /* U+620D */ - {0x9cfa, 0x00e6888c}, /* U+620C */ - {0x9cfb, 0x00e68894}, /* U+6214 */ - {0x9cfc, 0x00e6889b}, /* U+621B */ - {0x9d40, 0x00e6889e}, /* U+621E */ - {0x9d41, 0x00e688a1}, /* U+6221 */ - {0x9d42, 0x00e688aa}, /* U+622A */ - {0x9d43, 0x00e688ae}, /* U+622E */ - {0x9d44, 0x00e688b0}, /* U+6230 */ - {0x9d45, 0x00e688b2}, /* U+6232 */ - {0x9d46, 0x00e688b3}, /* U+6233 */ - {0x9d47, 0x00e68981}, /* U+6241 */ - {0x9d48, 0x00e6898e}, /* U+624E */ - {0x9d49, 0x00e6899e}, /* U+625E */ - {0x9d4a, 0x00e689a3}, /* U+6263 */ - {0x9d4b, 0x00e6899b}, /* U+625B */ - {0x9d4c, 0x00e689a0}, /* U+6260 */ - {0x9d4d, 0x00e689a8}, /* U+6268 */ - {0x9d4e, 0x00e689bc}, /* U+627C */ - {0x9d4f, 0x00e68a82}, /* U+6282 */ - {0x9d50, 0x00e68a89}, /* U+6289 */ - {0x9d51, 0x00e689be}, /* U+627E */ - {0x9d52, 0x00e68a92}, /* U+6292 */ - {0x9d53, 0x00e68a93}, /* U+6293 */ - {0x9d54, 0x00e68a96}, /* U+6296 */ - {0x9d55, 0x00e68b94}, /* U+62D4 */ - {0x9d56, 0x00e68a83}, /* U+6283 */ - {0x9d57, 0x00e68a94}, /* U+6294 */ - {0x9d58, 0x00e68b97}, /* U+62D7 */ - {0x9d59, 0x00e68b91}, /* U+62D1 */ - {0x9d5a, 0x00e68abb}, /* U+62BB */ - {0x9d5b, 0x00e68b8f}, /* U+62CF */ - {0x9d5c, 0x00e68bbf}, /* U+62FF */ - {0x9d5d, 0x00e68b86}, /* U+62C6 */ - {0x9d5e, 0x00e69394}, /* U+64D4 */ - {0x9d5f, 0x00e68b88}, /* U+62C8 */ - {0x9d60, 0x00e68b9c}, /* U+62DC */ - {0x9d61, 0x00e68b8c}, /* U+62CC */ - {0x9d62, 0x00e68b8a}, /* U+62CA */ - {0x9d63, 0x00e68b82}, /* U+62C2 */ - {0x9d64, 0x00e68b87}, /* U+62C7 */ - {0x9d65, 0x00e68a9b}, /* U+629B */ - {0x9d66, 0x00e68b89}, /* U+62C9 */ - {0x9d67, 0x00e68c8c}, /* U+630C */ - {0x9d68, 0x00e68bae}, /* U+62EE */ - {0x9d69, 0x00e68bb1}, /* U+62F1 */ - {0x9d6a, 0x00e68ca7}, /* U+6327 */ - {0x9d6b, 0x00e68c82}, /* U+6302 */ - {0x9d6c, 0x00e68c88}, /* U+6308 */ - {0x9d6d, 0x00e68baf}, /* U+62EF */ - {0x9d6e, 0x00e68bb5}, /* U+62F5 */ - {0x9d6f, 0x00e68d90}, /* U+6350 */ - {0x9d70, 0x00e68cbe}, /* U+633E */ - {0x9d71, 0x00e68d8d}, /* U+634D */ - {0x9d72, 0x00e6909c}, /* U+641C */ - {0x9d73, 0x00e68d8f}, /* U+634F */ - {0x9d74, 0x00e68e96}, /* U+6396 */ - {0x9d75, 0x00e68e8e}, /* U+638E */ - {0x9d76, 0x00e68e80}, /* U+6380 */ - {0x9d77, 0x00e68eab}, /* U+63AB */ - {0x9d78, 0x00e68db6}, /* U+6376 */ - {0x9d79, 0x00e68ea3}, /* U+63A3 */ - {0x9d7a, 0x00e68e8f}, /* U+638F */ - {0x9d7b, 0x00e68e89}, /* U+6389 */ - {0x9d7c, 0x00e68e9f}, /* U+639F */ - {0x9d7d, 0x00e68eb5}, /* U+63B5 */ - {0x9d7e, 0x00e68dab}, /* U+636B */ - {0x9d80, 0x00e68da9}, /* U+6369 */ - {0x9d81, 0x00e68ebe}, /* U+63BE */ - {0x9d82, 0x00e68fa9}, /* U+63E9 */ - {0x9d83, 0x00e68f80}, /* U+63C0 */ - {0x9d84, 0x00e68f86}, /* U+63C6 */ - {0x9d85, 0x00e68fa3}, /* U+63E3 */ - {0x9d86, 0x00e68f89}, /* U+63C9 */ - {0x9d87, 0x00e68f92}, /* U+63D2 */ - {0x9d88, 0x00e68fb6}, /* U+63F6 */ - {0x9d89, 0x00e68f84}, /* U+63C4 */ - {0x9d8a, 0x00e69096}, /* U+6416 */ - {0x9d8b, 0x00e690b4}, /* U+6434 */ - {0x9d8c, 0x00e69086}, /* U+6406 */ - {0x9d8d, 0x00e69093}, /* U+6413 */ - {0x9d8e, 0x00e690a6}, /* U+6426 */ - {0x9d8f, 0x00e690b6}, /* U+6436 */ - {0x9d90, 0x00e6949d}, /* U+651D */ - {0x9d91, 0x00e69097}, /* U+6417 */ - {0x9d92, 0x00e690a8}, /* U+6428 */ - {0x9d93, 0x00e6908f}, /* U+640F */ - {0x9d94, 0x00e691a7}, /* U+6467 */ - {0x9d95, 0x00e691af}, /* U+646F */ - {0x9d96, 0x00e691b6}, /* U+6476 */ - {0x9d97, 0x00e6918e}, /* U+644E */ - {0x9d98, 0x00e694aa}, /* U+652A */ - {0x9d99, 0x00e69295}, /* U+6495 */ - {0x9d9a, 0x00e69293}, /* U+6493 */ - {0x9d9b, 0x00e692a5}, /* U+64A5 */ - {0x9d9c, 0x00e692a9}, /* U+64A9 */ - {0x9d9d, 0x00e69288}, /* U+6488 */ - {0x9d9e, 0x00e692bc}, /* U+64BC */ - {0x9d9f, 0x00e6939a}, /* U+64DA */ - {0x9da0, 0x00e69392}, /* U+64D2 */ - {0x9da1, 0x00e69385}, /* U+64C5 */ - {0x9da2, 0x00e69387}, /* U+64C7 */ - {0x9da3, 0x00e692bb}, /* U+64BB */ - {0x9da4, 0x00e69398}, /* U+64D8 */ - {0x9da5, 0x00e69382}, /* U+64C2 */ - {0x9da6, 0x00e693b1}, /* U+64F1 */ - {0x9da7, 0x00e693a7}, /* U+64E7 */ - {0x9da8, 0x00e88889}, /* U+8209 */ - {0x9da9, 0x00e693a0}, /* U+64E0 */ - {0x9daa, 0x00e693a1}, /* U+64E1 */ - {0x9dab, 0x00e68aac}, /* U+62AC */ - {0x9dac, 0x00e693a3}, /* U+64E3 */ - {0x9dad, 0x00e693af}, /* U+64EF */ - {0x9dae, 0x00e694ac}, /* U+652C */ - {0x9daf, 0x00e693b6}, /* U+64F6 */ - {0x9db0, 0x00e693b4}, /* U+64F4 */ - {0x9db1, 0x00e693b2}, /* U+64F2 */ - {0x9db2, 0x00e693ba}, /* U+64FA */ - {0x9db3, 0x00e69480}, /* U+6500 */ - {0x9db4, 0x00e693bd}, /* U+64FD */ - {0x9db5, 0x00e69498}, /* U+6518 */ - {0x9db6, 0x00e6949c}, /* U+651C */ - {0x9db7, 0x00e69485}, /* U+6505 */ - {0x9db8, 0x00e694a4}, /* U+6524 */ - {0x9db9, 0x00e694a3}, /* U+6523 */ - {0x9dba, 0x00e694ab}, /* U+652B */ - {0x9dbb, 0x00e694b4}, /* U+6534 */ - {0x9dbc, 0x00e694b5}, /* U+6535 */ - {0x9dbd, 0x00e694b7}, /* U+6537 */ - {0x9dbe, 0x00e694b6}, /* U+6536 */ - {0x9dbf, 0x00e694b8}, /* U+6538 */ - {0x9dc0, 0x00e7958b}, /* U+754B */ - {0x9dc1, 0x00e69588}, /* U+6548 */ - {0x9dc2, 0x00e69596}, /* U+6556 */ - {0x9dc3, 0x00e69595}, /* U+6555 */ - {0x9dc4, 0x00e6958d}, /* U+654D */ - {0x9dc5, 0x00e69598}, /* U+6558 */ - {0x9dc6, 0x00e6959e}, /* U+655E */ - {0x9dc7, 0x00e6959d}, /* U+655D */ - {0x9dc8, 0x00e695b2}, /* U+6572 */ - {0x9dc9, 0x00e695b8}, /* U+6578 */ - {0x9dca, 0x00e69682}, /* U+6582 */ - {0x9dcb, 0x00e69683}, /* U+6583 */ - {0x9dcc, 0x00e8ae8a}, /* U+8B8A */ - {0x9dcd, 0x00e6969b}, /* U+659B */ - {0x9dce, 0x00e6969f}, /* U+659F */ - {0x9dcf, 0x00e696ab}, /* U+65AB */ - {0x9dd0, 0x00e696b7}, /* U+65B7 */ - {0x9dd1, 0x00e69783}, /* U+65C3 */ - {0x9dd2, 0x00e69786}, /* U+65C6 */ - {0x9dd3, 0x00e69781}, /* U+65C1 */ - {0x9dd4, 0x00e69784}, /* U+65C4 */ - {0x9dd5, 0x00e6978c}, /* U+65CC */ - {0x9dd6, 0x00e69792}, /* U+65D2 */ - {0x9dd7, 0x00e6979b}, /* U+65DB */ - {0x9dd8, 0x00e69799}, /* U+65D9 */ - {0x9dd9, 0x00e697a0}, /* U+65E0 */ - {0x9dda, 0x00e697a1}, /* U+65E1 */ - {0x9ddb, 0x00e697b1}, /* U+65F1 */ - {0x9ddc, 0x00e69db2}, /* U+6772 */ - {0x9ddd, 0x00e6988a}, /* U+660A */ - {0x9dde, 0x00e69883}, /* U+6603 */ - {0x9ddf, 0x00e697bb}, /* U+65FB */ - {0x9de0, 0x00e69db3}, /* U+6773 */ - {0x9de1, 0x00e698b5}, /* U+6635 */ - {0x9de2, 0x00e698b6}, /* U+6636 */ - {0x9de3, 0x00e698b4}, /* U+6634 */ - {0x9de4, 0x00e6989c}, /* U+661C */ - {0x9de5, 0x00e6998f}, /* U+664F */ - {0x9de6, 0x00e69984}, /* U+6644 */ - {0x9de7, 0x00e69989}, /* U+6649 */ - {0x9de8, 0x00e69981}, /* U+6641 */ - {0x9de9, 0x00e6999e}, /* U+665E */ - {0x9dea, 0x00e6999d}, /* U+665D */ - {0x9deb, 0x00e699a4}, /* U+6664 */ - {0x9dec, 0x00e699a7}, /* U+6667 */ - {0x9ded, 0x00e699a8}, /* U+6668 */ - {0x9dee, 0x00e6999f}, /* U+665F */ - {0x9def, 0x00e699a2}, /* U+6662 */ - {0x9df0, 0x00e699b0}, /* U+6670 */ - {0x9df1, 0x00e69a83}, /* U+6683 */ - {0x9df2, 0x00e69a88}, /* U+6688 */ - {0x9df3, 0x00e69a8e}, /* U+668E */ - {0x9df4, 0x00e69a89}, /* U+6689 */ - {0x9df5, 0x00e69a84}, /* U+6684 */ - {0x9df6, 0x00e69a98}, /* U+6698 */ - {0x9df7, 0x00e69a9d}, /* U+669D */ - {0x9df8, 0x00e69b81}, /* U+66C1 */ - {0x9df9, 0x00e69ab9}, /* U+66B9 */ - {0x9dfa, 0x00e69b89}, /* U+66C9 */ - {0x9dfb, 0x00e69abe}, /* U+66BE */ - {0x9dfc, 0x00e69abc}, /* U+66BC */ - {0x9e40, 0x00e69b84}, /* U+66C4 */ - {0x9e41, 0x00e69ab8}, /* U+66B8 */ - {0x9e42, 0x00e69b96}, /* U+66D6 */ - {0x9e43, 0x00e69b9a}, /* U+66DA */ - {0x9e44, 0x00e69ba0}, /* U+66E0 */ - {0x9e45, 0x00e698bf}, /* U+663F */ - {0x9e46, 0x00e69ba6}, /* U+66E6 */ - {0x9e47, 0x00e69ba9}, /* U+66E9 */ - {0x9e48, 0x00e69bb0}, /* U+66F0 */ - {0x9e49, 0x00e69bb5}, /* U+66F5 */ - {0x9e4a, 0x00e69bb7}, /* U+66F7 */ - {0x9e4b, 0x00e69c8f}, /* U+670F */ - {0x9e4c, 0x00e69c96}, /* U+6716 */ - {0x9e4d, 0x00e69c9e}, /* U+671E */ - {0x9e4e, 0x00e69ca6}, /* U+6726 */ - {0x9e4f, 0x00e69ca7}, /* U+6727 */ - {0x9e50, 0x00e99cb8}, /* U+9738 */ - {0x9e51, 0x00e69cae}, /* U+672E */ - {0x9e52, 0x00e69cbf}, /* U+673F */ - {0x9e53, 0x00e69cb6}, /* U+6736 */ - {0x9e54, 0x00e69d81}, /* U+6741 */ - {0x9e55, 0x00e69cb8}, /* U+6738 */ - {0x9e56, 0x00e69cb7}, /* U+6737 */ - {0x9e57, 0x00e69d86}, /* U+6746 */ - {0x9e58, 0x00e69d9e}, /* U+675E */ - {0x9e59, 0x00e69da0}, /* U+6760 */ - {0x9e5a, 0x00e69d99}, /* U+6759 */ - {0x9e5b, 0x00e69da3}, /* U+6763 */ - {0x9e5c, 0x00e69da4}, /* U+6764 */ - {0x9e5d, 0x00e69e89}, /* U+6789 */ - {0x9e5e, 0x00e69db0}, /* U+6770 */ - {0x9e5f, 0x00e69ea9}, /* U+67A9 */ - {0x9e60, 0x00e69dbc}, /* U+677C */ - {0x9e61, 0x00e69daa}, /* U+676A */ - {0x9e62, 0x00e69e8c}, /* U+678C */ - {0x9e63, 0x00e69e8b}, /* U+678B */ - {0x9e64, 0x00e69ea6}, /* U+67A6 */ - {0x9e65, 0x00e69ea1}, /* U+67A1 */ - {0x9e66, 0x00e69e85}, /* U+6785 */ - {0x9e67, 0x00e69eb7}, /* U+67B7 */ - {0x9e68, 0x00e69faf}, /* U+67EF */ - {0x9e69, 0x00e69eb4}, /* U+67B4 */ - {0x9e6a, 0x00e69fac}, /* U+67EC */ - {0x9e6b, 0x00e69eb3}, /* U+67B3 */ - {0x9e6c, 0x00e69fa9}, /* U+67E9 */ - {0x9e6d, 0x00e69eb8}, /* U+67B8 */ - {0x9e6e, 0x00e69fa4}, /* U+67E4 */ - {0x9e6f, 0x00e69f9e}, /* U+67DE */ - {0x9e70, 0x00e69f9d}, /* U+67DD */ - {0x9e71, 0x00e69fa2}, /* U+67E2 */ - {0x9e72, 0x00e69fae}, /* U+67EE */ - {0x9e73, 0x00e69eb9}, /* U+67B9 */ - {0x9e74, 0x00e69f8e}, /* U+67CE */ - {0x9e75, 0x00e69f86}, /* U+67C6 */ - {0x9e76, 0x00e69fa7}, /* U+67E7 */ - {0x9e77, 0x00e6aa9c}, /* U+6A9C */ - {0x9e78, 0x00e6a09e}, /* U+681E */ - {0x9e79, 0x00e6a186}, /* U+6846 */ - {0x9e7a, 0x00e6a0a9}, /* U+6829 */ - {0x9e7b, 0x00e6a180}, /* U+6840 */ - {0x9e7c, 0x00e6a18d}, /* U+684D */ - {0x9e7d, 0x00e6a0b2}, /* U+6832 */ - {0x9e7e, 0x00e6a18e}, /* U+684E */ - {0x9e80, 0x00e6a2b3}, /* U+68B3 */ - {0x9e81, 0x00e6a0ab}, /* U+682B */ - {0x9e82, 0x00e6a199}, /* U+6859 */ - {0x9e83, 0x00e6a1a3}, /* U+6863 */ - {0x9e84, 0x00e6a1b7}, /* U+6877 */ - {0x9e85, 0x00e6a1bf}, /* U+687F */ - {0x9e86, 0x00e6a29f}, /* U+689F */ - {0x9e87, 0x00e6a28f}, /* U+688F */ - {0x9e88, 0x00e6a2ad}, /* U+68AD */ - {0x9e89, 0x00e6a294}, /* U+6894 */ - {0x9e8a, 0x00e6a29d}, /* U+689D */ - {0x9e8b, 0x00e6a29b}, /* U+689B */ - {0x9e8c, 0x00e6a283}, /* U+6883 */ - {0x9e8d, 0x00e6aaae}, /* U+6AAE */ - {0x9e8e, 0x00e6a2b9}, /* U+68B9 */ - {0x9e8f, 0x00e6a1b4}, /* U+6874 */ - {0x9e90, 0x00e6a2b5}, /* U+68B5 */ - {0x9e91, 0x00e6a2a0}, /* U+68A0 */ - {0x9e92, 0x00e6a2ba}, /* U+68BA */ - {0x9e93, 0x00e6a48f}, /* U+690F */ - {0x9e94, 0x00e6a28d}, /* U+688D */ - {0x9e95, 0x00e6a1be}, /* U+687E */ - {0x9e96, 0x00e6a481}, /* U+6901 */ - {0x9e97, 0x00e6a38a}, /* U+68CA */ - {0x9e98, 0x00e6a488}, /* U+6908 */ - {0x9e99, 0x00e6a398}, /* U+68D8 */ - {0x9e9a, 0x00e6a4a2}, /* U+6922 */ - {0x9e9b, 0x00e6a4a6}, /* U+6926 */ - {0x9e9c, 0x00e6a3a1}, /* U+68E1 */ - {0x9e9d, 0x00e6a48c}, /* U+690C */ - {0x9e9e, 0x00e6a38d}, /* U+68CD */ - {0x9e9f, 0x00e6a394}, /* U+68D4 */ - {0x9ea0, 0x00e6a3a7}, /* U+68E7 */ - {0x9ea1, 0x00e6a395}, /* U+68D5 */ - {0x9ea2, 0x00e6a4b6}, /* U+6936 */ - {0x9ea3, 0x00e6a492}, /* U+6912 */ - {0x9ea4, 0x00e6a484}, /* U+6904 */ - {0x9ea5, 0x00e6a397}, /* U+68D7 */ - {0x9ea6, 0x00e6a3a3}, /* U+68E3 */ - {0x9ea7, 0x00e6a4a5}, /* U+6925 */ - {0x9ea8, 0x00e6a3b9}, /* U+68F9 */ - {0x9ea9, 0x00e6a3a0}, /* U+68E0 */ - {0x9eaa, 0x00e6a3af}, /* U+68EF */ - {0x9eab, 0x00e6a4a8}, /* U+6928 */ - {0x9eac, 0x00e6a4aa}, /* U+692A */ - {0x9ead, 0x00e6a49a}, /* U+691A */ - {0x9eae, 0x00e6a4a3}, /* U+6923 */ - {0x9eaf, 0x00e6a4a1}, /* U+6921 */ - {0x9eb0, 0x00e6a386}, /* U+68C6 */ - {0x9eb1, 0x00e6a5b9}, /* U+6979 */ - {0x9eb2, 0x00e6a5b7}, /* U+6977 */ - {0x9eb3, 0x00e6a59c}, /* U+695C */ - {0x9eb4, 0x00e6a5b8}, /* U+6978 */ - {0x9eb5, 0x00e6a5ab}, /* U+696B */ - {0x9eb6, 0x00e6a594}, /* U+6954 */ - {0x9eb7, 0x00e6a5be}, /* U+697E */ - {0x9eb8, 0x00e6a5ae}, /* U+696E */ - {0x9eb9, 0x00e6a4b9}, /* U+6939 */ - {0x9eba, 0x00e6a5b4}, /* U+6974 */ - {0x9ebb, 0x00e6a4bd}, /* U+693D */ - {0x9ebc, 0x00e6a599}, /* U+6959 */ - {0x9ebd, 0x00e6a4b0}, /* U+6930 */ - {0x9ebe, 0x00e6a5a1}, /* U+6961 */ - {0x9ebf, 0x00e6a59e}, /* U+695E */ - {0x9ec0, 0x00e6a59d}, /* U+695D */ - {0x9ec1, 0x00e6a681}, /* U+6981 */ - {0x9ec2, 0x00e6a5aa}, /* U+696A */ - {0x9ec3, 0x00e6a6b2}, /* U+69B2 */ - {0x9ec4, 0x00e6a6ae}, /* U+69AE */ - {0x9ec5, 0x00e6a790}, /* U+69D0 */ - {0x9ec6, 0x00e6a6bf}, /* U+69BF */ - {0x9ec7, 0x00e6a781}, /* U+69C1 */ - {0x9ec8, 0x00e6a793}, /* U+69D3 */ - {0x9ec9, 0x00e6a6be}, /* U+69BE */ - {0x9eca, 0x00e6a78e}, /* U+69CE */ - {0x9ecb, 0x00e5afa8}, /* U+5BE8 */ - {0x9ecc, 0x00e6a78a}, /* U+69CA */ - {0x9ecd, 0x00e6a79d}, /* U+69DD */ - {0x9ece, 0x00e6a6bb}, /* U+69BB */ - {0x9ecf, 0x00e6a783}, /* U+69C3 */ - {0x9ed0, 0x00e6a6a7}, /* U+69A7 */ - {0x9ed1, 0x00e6a8ae}, /* U+6A2E */ - {0x9ed2, 0x00e6a691}, /* U+6991 */ - {0x9ed3, 0x00e6a6a0}, /* U+69A0 */ - {0x9ed4, 0x00e6a69c}, /* U+699C */ - {0x9ed5, 0x00e6a695}, /* U+6995 */ - {0x9ed6, 0x00e6a6b4}, /* U+69B4 */ - {0x9ed7, 0x00e6a79e}, /* U+69DE */ - {0x9ed8, 0x00e6a7a8}, /* U+69E8 */ - {0x9ed9, 0x00e6a882}, /* U+6A02 */ - {0x9eda, 0x00e6a89b}, /* U+6A1B */ - {0x9edb, 0x00e6a7bf}, /* U+69FF */ - {0x9edc, 0x00e6ac8a}, /* U+6B0A */ - {0x9edd, 0x00e6a7b9}, /* U+69F9 */ - {0x9ede, 0x00e6a7b2}, /* U+69F2 */ - {0x9edf, 0x00e6a7a7}, /* U+69E7 */ - {0x9ee0, 0x00e6a885}, /* U+6A05 */ - {0x9ee1, 0x00e6a6b1}, /* U+69B1 */ - {0x9ee2, 0x00e6a89e}, /* U+6A1E */ - {0x9ee3, 0x00e6a7ad}, /* U+69ED */ - {0x9ee4, 0x00e6a894}, /* U+6A14 */ - {0x9ee5, 0x00e6a7ab}, /* U+69EB */ - {0x9ee6, 0x00e6a88a}, /* U+6A0A */ - {0x9ee7, 0x00e6a892}, /* U+6A12 */ - {0x9ee8, 0x00e6ab81}, /* U+6AC1 */ - {0x9ee9, 0x00e6a8a3}, /* U+6A23 */ - {0x9eea, 0x00e6a893}, /* U+6A13 */ - {0x9eeb, 0x00e6a984}, /* U+6A44 */ - {0x9eec, 0x00e6a88c}, /* U+6A0C */ - {0x9eed, 0x00e6a9b2}, /* U+6A72 */ - {0x9eee, 0x00e6a8b6}, /* U+6A36 */ - {0x9eef, 0x00e6a9b8}, /* U+6A78 */ - {0x9ef0, 0x00e6a987}, /* U+6A47 */ - {0x9ef1, 0x00e6a9a2}, /* U+6A62 */ - {0x9ef2, 0x00e6a999}, /* U+6A59 */ - {0x9ef3, 0x00e6a9a6}, /* U+6A66 */ - {0x9ef4, 0x00e6a988}, /* U+6A48 */ - {0x9ef5, 0x00e6a8b8}, /* U+6A38 */ - {0x9ef6, 0x00e6a8a2}, /* U+6A22 */ - {0x9ef7, 0x00e6aa90}, /* U+6A90 */ - {0x9ef8, 0x00e6aa8d}, /* U+6A8D */ - {0x9ef9, 0x00e6aaa0}, /* U+6AA0 */ - {0x9efa, 0x00e6aa84}, /* U+6A84 */ - {0x9efb, 0x00e6aaa2}, /* U+6AA2 */ - {0x9efc, 0x00e6aaa3}, /* U+6AA3 */ - {0x9f40, 0x00e6aa97}, /* U+6A97 */ - {0x9f41, 0x00e89897}, /* U+8617 */ - {0x9f42, 0x00e6aabb}, /* U+6ABB */ - {0x9f43, 0x00e6ab83}, /* U+6AC3 */ - {0x9f44, 0x00e6ab82}, /* U+6AC2 */ - {0x9f45, 0x00e6aab8}, /* U+6AB8 */ - {0x9f46, 0x00e6aab3}, /* U+6AB3 */ - {0x9f47, 0x00e6aaac}, /* U+6AAC */ - {0x9f48, 0x00e6ab9e}, /* U+6ADE */ - {0x9f49, 0x00e6ab91}, /* U+6AD1 */ - {0x9f4a, 0x00e6ab9f}, /* U+6ADF */ - {0x9f4b, 0x00e6aaaa}, /* U+6AAA */ - {0x9f4c, 0x00e6ab9a}, /* U+6ADA */ - {0x9f4d, 0x00e6abaa}, /* U+6AEA */ - {0x9f4e, 0x00e6abbb}, /* U+6AFB */ - {0x9f4f, 0x00e6ac85}, /* U+6B05 */ - {0x9f50, 0x00e89896}, /* U+8616 */ - {0x9f51, 0x00e6abba}, /* U+6AFA */ - {0x9f52, 0x00e6ac92}, /* U+6B12 */ - {0x9f53, 0x00e6ac96}, /* U+6B16 */ - {0x9f54, 0x00e9acb1}, /* U+9B31 */ - {0x9f55, 0x00e6ac9f}, /* U+6B1F */ - {0x9f56, 0x00e6acb8}, /* U+6B38 */ - {0x9f57, 0x00e6acb7}, /* U+6B37 */ - {0x9f58, 0x00e79b9c}, /* U+76DC */ - {0x9f59, 0x00e6acb9}, /* U+6B39 */ - {0x9f5a, 0x00e9a3ae}, /* U+98EE */ - {0x9f5b, 0x00e6ad87}, /* U+6B47 */ - {0x9f5c, 0x00e6ad83}, /* U+6B43 */ - {0x9f5d, 0x00e6ad89}, /* U+6B49 */ - {0x9f5e, 0x00e6ad90}, /* U+6B50 */ - {0x9f5f, 0x00e6ad99}, /* U+6B59 */ - {0x9f60, 0x00e6ad94}, /* U+6B54 */ - {0x9f61, 0x00e6ad9b}, /* U+6B5B */ - {0x9f62, 0x00e6ad9f}, /* U+6B5F */ - {0x9f63, 0x00e6ada1}, /* U+6B61 */ - {0x9f64, 0x00e6adb8}, /* U+6B78 */ - {0x9f65, 0x00e6adb9}, /* U+6B79 */ - {0x9f66, 0x00e6adbf}, /* U+6B7F */ - {0x9f67, 0x00e6ae80}, /* U+6B80 */ - {0x9f68, 0x00e6ae84}, /* U+6B84 */ - {0x9f69, 0x00e6ae83}, /* U+6B83 */ - {0x9f6a, 0x00e6ae8d}, /* U+6B8D */ - {0x9f6b, 0x00e6ae98}, /* U+6B98 */ - {0x9f6c, 0x00e6ae95}, /* U+6B95 */ - {0x9f6d, 0x00e6ae9e}, /* U+6B9E */ - {0x9f6e, 0x00e6aea4}, /* U+6BA4 */ - {0x9f6f, 0x00e6aeaa}, /* U+6BAA */ - {0x9f70, 0x00e6aeab}, /* U+6BAB */ - {0x9f71, 0x00e6aeaf}, /* U+6BAF */ - {0x9f72, 0x00e6aeb2}, /* U+6BB2 */ - {0x9f73, 0x00e6aeb1}, /* U+6BB1 */ - {0x9f74, 0x00e6aeb3}, /* U+6BB3 */ - {0x9f75, 0x00e6aeb7}, /* U+6BB7 */ - {0x9f76, 0x00e6aebc}, /* U+6BBC */ - {0x9f77, 0x00e6af86}, /* U+6BC6 */ - {0x9f78, 0x00e6af8b}, /* U+6BCB */ - {0x9f79, 0x00e6af93}, /* U+6BD3 */ - {0x9f7a, 0x00e6af9f}, /* U+6BDF */ - {0x9f7b, 0x00e6afac}, /* U+6BEC */ - {0x9f7c, 0x00e6afab}, /* U+6BEB */ - {0x9f7d, 0x00e6afb3}, /* U+6BF3 */ - {0x9f7e, 0x00e6afaf}, /* U+6BEF */ - {0x9f80, 0x00e9babe}, /* U+9EBE */ - {0x9f81, 0x00e6b088}, /* U+6C08 */ - {0x9f82, 0x00e6b093}, /* U+6C13 */ - {0x9f83, 0x00e6b094}, /* U+6C14 */ - {0x9f84, 0x00e6b09b}, /* U+6C1B */ - {0x9f85, 0x00e6b0a4}, /* U+6C24 */ - {0x9f86, 0x00e6b0a3}, /* U+6C23 */ - {0x9f87, 0x00e6b19e}, /* U+6C5E */ - {0x9f88, 0x00e6b195}, /* U+6C55 */ - {0x9f89, 0x00e6b1a2}, /* U+6C62 */ - {0x9f8a, 0x00e6b1aa}, /* U+6C6A */ - {0x9f8b, 0x00e6b282}, /* U+6C82 */ - {0x9f8c, 0x00e6b28d}, /* U+6C8D */ - {0x9f8d, 0x00e6b29a}, /* U+6C9A */ - {0x9f8e, 0x00e6b281}, /* U+6C81 */ - {0x9f8f, 0x00e6b29b}, /* U+6C9B */ - {0x9f90, 0x00e6b1be}, /* U+6C7E */ - {0x9f91, 0x00e6b1a8}, /* U+6C68 */ - {0x9f92, 0x00e6b1b3}, /* U+6C73 */ - {0x9f93, 0x00e6b292}, /* U+6C92 */ - {0x9f94, 0x00e6b290}, /* U+6C90 */ - {0x9f95, 0x00e6b384}, /* U+6CC4 */ - {0x9f96, 0x00e6b3b1}, /* U+6CF1 */ - {0x9f97, 0x00e6b393}, /* U+6CD3 */ - {0x9f98, 0x00e6b2bd}, /* U+6CBD */ - {0x9f99, 0x00e6b397}, /* U+6CD7 */ - {0x9f9a, 0x00e6b385}, /* U+6CC5 */ - {0x9f9b, 0x00e6b39d}, /* U+6CDD */ - {0x9f9c, 0x00e6b2ae}, /* U+6CAE */ - {0x9f9d, 0x00e6b2b1}, /* U+6CB1 */ - {0x9f9e, 0x00e6b2be}, /* U+6CBE */ - {0x9f9f, 0x00e6b2ba}, /* U+6CBA */ - {0x9fa0, 0x00e6b39b}, /* U+6CDB */ - {0x9fa1, 0x00e6b3af}, /* U+6CEF */ - {0x9fa2, 0x00e6b399}, /* U+6CD9 */ - {0x9fa3, 0x00e6b3aa}, /* U+6CEA */ - {0x9fa4, 0x00e6b49f}, /* U+6D1F */ - {0x9fa5, 0x00e8a18d}, /* U+884D */ - {0x9fa6, 0x00e6b4b6}, /* U+6D36 */ - {0x9fa7, 0x00e6b4ab}, /* U+6D2B */ - {0x9fa8, 0x00e6b4bd}, /* U+6D3D */ - {0x9fa9, 0x00e6b4b8}, /* U+6D38 */ - {0x9faa, 0x00e6b499}, /* U+6D19 */ - {0x9fab, 0x00e6b4b5}, /* U+6D35 */ - {0x9fac, 0x00e6b4b3}, /* U+6D33 */ - {0x9fad, 0x00e6b492}, /* U+6D12 */ - {0x9fae, 0x00e6b48c}, /* U+6D0C */ - {0x9faf, 0x00e6b5a3}, /* U+6D63 */ - {0x9fb0, 0x00e6b693}, /* U+6D93 */ - {0x9fb1, 0x00e6b5a4}, /* U+6D64 */ - {0x9fb2, 0x00e6b59a}, /* U+6D5A */ - {0x9fb3, 0x00e6b5b9}, /* U+6D79 */ - {0x9fb4, 0x00e6b599}, /* U+6D59 */ - {0x9fb5, 0x00e6b68e}, /* U+6D8E */ - {0x9fb6, 0x00e6b695}, /* U+6D95 */ - {0x9fb7, 0x00e6bfa4}, /* U+6FE4 */ - {0x9fb8, 0x00e6b685}, /* U+6D85 */ - {0x9fb9, 0x00e6b7b9}, /* U+6DF9 */ - {0x9fba, 0x00e6b895}, /* U+6E15 */ - {0x9fbb, 0x00e6b88a}, /* U+6E0A */ - {0x9fbc, 0x00e6b6b5}, /* U+6DB5 */ - {0x9fbd, 0x00e6b787}, /* U+6DC7 */ - {0x9fbe, 0x00e6b7a6}, /* U+6DE6 */ - {0x9fbf, 0x00e6b6b8}, /* U+6DB8 */ - {0x9fc0, 0x00e6b786}, /* U+6DC6 */ - {0x9fc1, 0x00e6b7ac}, /* U+6DEC */ - {0x9fc2, 0x00e6b79e}, /* U+6DDE */ - {0x9fc3, 0x00e6b78c}, /* U+6DCC */ - {0x9fc4, 0x00e6b7a8}, /* U+6DE8 */ - {0x9fc5, 0x00e6b792}, /* U+6DD2 */ - {0x9fc6, 0x00e6b785}, /* U+6DC5 */ - {0x9fc7, 0x00e6b7ba}, /* U+6DFA */ - {0x9fc8, 0x00e6b799}, /* U+6DD9 */ - {0x9fc9, 0x00e6b7a4}, /* U+6DE4 */ - {0x9fca, 0x00e6b795}, /* U+6DD5 */ - {0x9fcb, 0x00e6b7aa}, /* U+6DEA */ - {0x9fcc, 0x00e6b7ae}, /* U+6DEE */ - {0x9fcd, 0x00e6b8ad}, /* U+6E2D */ - {0x9fce, 0x00e6b9ae}, /* U+6E6E */ - {0x9fcf, 0x00e6b8ae}, /* U+6E2E */ - {0x9fd0, 0x00e6b899}, /* U+6E19 */ - {0x9fd1, 0x00e6b9b2}, /* U+6E72 */ - {0x9fd2, 0x00e6b99f}, /* U+6E5F */ - {0x9fd3, 0x00e6b8be}, /* U+6E3E */ - {0x9fd4, 0x00e6b8a3}, /* U+6E23 */ - {0x9fd5, 0x00e6b9ab}, /* U+6E6B */ - {0x9fd6, 0x00e6b8ab}, /* U+6E2B */ - {0x9fd7, 0x00e6b9b6}, /* U+6E76 */ - {0x9fd8, 0x00e6b98d}, /* U+6E4D */ - {0x9fd9, 0x00e6b89f}, /* U+6E1F */ - {0x9fda, 0x00e6b983}, /* U+6E43 */ - {0x9fdb, 0x00e6b8ba}, /* U+6E3A */ - {0x9fdc, 0x00e6b98e}, /* U+6E4E */ - {0x9fdd, 0x00e6b8a4}, /* U+6E24 */ - {0x9fde, 0x00e6bbbf}, /* U+6EFF */ - {0x9fdf, 0x00e6b89d}, /* U+6E1D */ - {0x9fe0, 0x00e6b8b8}, /* U+6E38 */ - {0x9fe1, 0x00e6ba82}, /* U+6E82 */ - {0x9fe2, 0x00e6baaa}, /* U+6EAA */ - {0x9fe3, 0x00e6ba98}, /* U+6E98 */ - {0x9fe4, 0x00e6bb89}, /* U+6EC9 */ - {0x9fe5, 0x00e6bab7}, /* U+6EB7 */ - {0x9fe6, 0x00e6bb93}, /* U+6ED3 */ - {0x9fe7, 0x00e6babd}, /* U+6EBD */ - {0x9fe8, 0x00e6baaf}, /* U+6EAF */ - {0x9fe9, 0x00e6bb84}, /* U+6EC4 */ - {0x9fea, 0x00e6bab2}, /* U+6EB2 */ - {0x9feb, 0x00e6bb94}, /* U+6ED4 */ - {0x9fec, 0x00e6bb95}, /* U+6ED5 */ - {0x9fed, 0x00e6ba8f}, /* U+6E8F */ - {0x9fee, 0x00e6baa5}, /* U+6EA5 */ - {0x9fef, 0x00e6bb82}, /* U+6EC2 */ - {0x9ff0, 0x00e6ba9f}, /* U+6E9F */ - {0x9ff1, 0x00e6bd81}, /* U+6F41 */ - {0x9ff2, 0x00e6bc91}, /* U+6F11 */ - {0x9ff3, 0x00e7818c}, /* U+704C */ - {0x9ff4, 0x00e6bbac}, /* U+6EEC */ - {0x9ff5, 0x00e6bbb8}, /* U+6EF8 */ - {0x9ff6, 0x00e6bbbe}, /* U+6EFE */ - {0x9ff7, 0x00e6bcbf}, /* U+6F3F */ - {0x9ff8, 0x00e6bbb2}, /* U+6EF2 */ - {0x9ff9, 0x00e6bcb1}, /* U+6F31 */ - {0x9ffa, 0x00e6bbaf}, /* U+6EEF */ - {0x9ffb, 0x00e6bcb2}, /* U+6F32 */ - {0x9ffc, 0x00e6bb8c}, /* U+6ECC */ - {0xe040, 0x00e6bcbe}, /* U+6F3E */ - {0xe041, 0x00e6bc93}, /* U+6F13 */ - {0xe042, 0x00e6bbb7}, /* U+6EF7 */ - {0xe043, 0x00e6be86}, /* U+6F86 */ - {0xe044, 0x00e6bdba}, /* U+6F7A */ - {0xe045, 0x00e6bdb8}, /* U+6F78 */ - {0xe046, 0x00e6be81}, /* U+6F81 */ - {0xe047, 0x00e6be80}, /* U+6F80 */ - {0xe048, 0x00e6bdaf}, /* U+6F6F */ - {0xe049, 0x00e6bd9b}, /* U+6F5B */ - {0xe04a, 0x00e6bfb3}, /* U+6FF3 */ - {0xe04b, 0x00e6bdad}, /* U+6F6D */ - {0xe04c, 0x00e6be82}, /* U+6F82 */ - {0xe04d, 0x00e6bdbc}, /* U+6F7C */ - {0xe04e, 0x00e6bd98}, /* U+6F58 */ - {0xe04f, 0x00e6be8e}, /* U+6F8E */ - {0xe050, 0x00e6be91}, /* U+6F91 */ - {0xe051, 0x00e6bf82}, /* U+6FC2 */ - {0xe052, 0x00e6bda6}, /* U+6F66 */ - {0xe053, 0x00e6beb3}, /* U+6FB3 */ - {0xe054, 0x00e6bea3}, /* U+6FA3 */ - {0xe055, 0x00e6bea1}, /* U+6FA1 */ - {0xe056, 0x00e6bea4}, /* U+6FA4 */ - {0xe057, 0x00e6beb9}, /* U+6FB9 */ - {0xe058, 0x00e6bf86}, /* U+6FC6 */ - {0xe059, 0x00e6beaa}, /* U+6FAA */ - {0xe05a, 0x00e6bf9f}, /* U+6FDF */ - {0xe05b, 0x00e6bf95}, /* U+6FD5 */ - {0xe05c, 0x00e6bfac}, /* U+6FEC */ - {0xe05d, 0x00e6bf94}, /* U+6FD4 */ - {0xe05e, 0x00e6bf98}, /* U+6FD8 */ - {0xe05f, 0x00e6bfb1}, /* U+6FF1 */ - {0xe060, 0x00e6bfae}, /* U+6FEE */ - {0xe061, 0x00e6bf9b}, /* U+6FDB */ - {0xe062, 0x00e78089}, /* U+7009 */ - {0xe063, 0x00e7808b}, /* U+700B */ - {0xe064, 0x00e6bfba}, /* U+6FFA */ - {0xe065, 0x00e78091}, /* U+7011 */ - {0xe066, 0x00e78081}, /* U+7001 */ - {0xe067, 0x00e7808f}, /* U+700F */ - {0xe068, 0x00e6bfbe}, /* U+6FFE */ - {0xe069, 0x00e7809b}, /* U+701B */ - {0xe06a, 0x00e7809a}, /* U+701A */ - {0xe06b, 0x00e6bdb4}, /* U+6F74 */ - {0xe06c, 0x00e7809d}, /* U+701D */ - {0xe06d, 0x00e78098}, /* U+7018 */ - {0xe06e, 0x00e7809f}, /* U+701F */ - {0xe06f, 0x00e780b0}, /* U+7030 */ - {0xe070, 0x00e780be}, /* U+703E */ - {0xe071, 0x00e780b2}, /* U+7032 */ - {0xe072, 0x00e78191}, /* U+7051 */ - {0xe073, 0x00e781a3}, /* U+7063 */ - {0xe074, 0x00e78299}, /* U+7099 */ - {0xe075, 0x00e78292}, /* U+7092 */ - {0xe076, 0x00e782af}, /* U+70AF */ - {0xe077, 0x00e783b1}, /* U+70F1 */ - {0xe078, 0x00e782ac}, /* U+70AC */ - {0xe079, 0x00e782b8}, /* U+70B8 */ - {0xe07a, 0x00e782b3}, /* U+70B3 */ - {0xe07b, 0x00e782ae}, /* U+70AE */ - {0xe07c, 0x00e7839f}, /* U+70DF */ - {0xe07d, 0x00e7838b}, /* U+70CB */ - {0xe07e, 0x00e7839d}, /* U+70DD */ - {0xe080, 0x00e78399}, /* U+70D9 */ - {0xe081, 0x00e78489}, /* U+7109 */ - {0xe082, 0x00e783bd}, /* U+70FD */ - {0xe083, 0x00e7849c}, /* U+711C */ - {0xe084, 0x00e78499}, /* U+7119 */ - {0xe085, 0x00e785a5}, /* U+7165 */ - {0xe086, 0x00e78595}, /* U+7155 */ - {0xe087, 0x00e78688}, /* U+7188 */ - {0xe088, 0x00e785a6}, /* U+7166 */ - {0xe089, 0x00e785a2}, /* U+7162 */ - {0xe08a, 0x00e7858c}, /* U+714C */ - {0xe08b, 0x00e78596}, /* U+7156 */ - {0xe08c, 0x00e785ac}, /* U+716C */ - {0xe08d, 0x00e7868f}, /* U+718F */ - {0xe08e, 0x00e787bb}, /* U+71FB */ - {0xe08f, 0x00e78684}, /* U+7184 */ - {0xe090, 0x00e78695}, /* U+7195 */ - {0xe091, 0x00e786a8}, /* U+71A8 */ - {0xe092, 0x00e786ac}, /* U+71AC */ - {0xe093, 0x00e78797}, /* U+71D7 */ - {0xe094, 0x00e786b9}, /* U+71B9 */ - {0xe095, 0x00e786be}, /* U+71BE */ - {0xe096, 0x00e78792}, /* U+71D2 */ - {0xe097, 0x00e78789}, /* U+71C9 */ - {0xe098, 0x00e78794}, /* U+71D4 */ - {0xe099, 0x00e7878e}, /* U+71CE */ - {0xe09a, 0x00e787a0}, /* U+71E0 */ - {0xe09b, 0x00e787ac}, /* U+71EC */ - {0xe09c, 0x00e787a7}, /* U+71E7 */ - {0xe09d, 0x00e787b5}, /* U+71F5 */ - {0xe09e, 0x00e787bc}, /* U+71FC */ - {0xe09f, 0x00e787b9}, /* U+71F9 */ - {0xe0a0, 0x00e787bf}, /* U+71FF */ - {0xe0a1, 0x00e7888d}, /* U+720D */ - {0xe0a2, 0x00e78890}, /* U+7210 */ - {0xe0a3, 0x00e7889b}, /* U+721B */ - {0xe0a4, 0x00e788a8}, /* U+7228 */ - {0xe0a5, 0x00e788ad}, /* U+722D */ - {0xe0a6, 0x00e788ac}, /* U+722C */ - {0xe0a7, 0x00e788b0}, /* U+7230 */ - {0xe0a8, 0x00e788b2}, /* U+7232 */ - {0xe0a9, 0x00e788bb}, /* U+723B */ - {0xe0aa, 0x00e788bc}, /* U+723C */ - {0xe0ab, 0x00e788bf}, /* U+723F */ - {0xe0ac, 0x00e78980}, /* U+7240 */ - {0xe0ad, 0x00e78986}, /* U+7246 */ - {0xe0ae, 0x00e7898b}, /* U+724B */ - {0xe0af, 0x00e78998}, /* U+7258 */ - {0xe0b0, 0x00e789b4}, /* U+7274 */ - {0xe0b1, 0x00e789be}, /* U+727E */ - {0xe0b2, 0x00e78a82}, /* U+7282 */ - {0xe0b3, 0x00e78a81}, /* U+7281 */ - {0xe0b4, 0x00e78a87}, /* U+7287 */ - {0xe0b5, 0x00e78a92}, /* U+7292 */ - {0xe0b6, 0x00e78a96}, /* U+7296 */ - {0xe0b7, 0x00e78aa2}, /* U+72A2 */ - {0xe0b8, 0x00e78aa7}, /* U+72A7 */ - {0xe0b9, 0x00e78ab9}, /* U+72B9 */ - {0xe0ba, 0x00e78ab2}, /* U+72B2 */ - {0xe0bb, 0x00e78b83}, /* U+72C3 */ - {0xe0bc, 0x00e78b86}, /* U+72C6 */ - {0xe0bd, 0x00e78b84}, /* U+72C4 */ - {0xe0be, 0x00e78b8e}, /* U+72CE */ - {0xe0bf, 0x00e78b92}, /* U+72D2 */ - {0xe0c0, 0x00e78ba2}, /* U+72E2 */ - {0xe0c1, 0x00e78ba0}, /* U+72E0 */ - {0xe0c2, 0x00e78ba1}, /* U+72E1 */ - {0xe0c3, 0x00e78bb9}, /* U+72F9 */ - {0xe0c4, 0x00e78bb7}, /* U+72F7 */ - {0xe0c5, 0x00e5808f}, /* U+500F */ - {0xe0c6, 0x00e78c97}, /* U+7317 */ - {0xe0c7, 0x00e78c8a}, /* U+730A */ - {0xe0c8, 0x00e78c9c}, /* U+731C */ - {0xe0c9, 0x00e78c96}, /* U+7316 */ - {0xe0ca, 0x00e78c9d}, /* U+731D */ - {0xe0cb, 0x00e78cb4}, /* U+7334 */ - {0xe0cc, 0x00e78caf}, /* U+732F */ - {0xe0cd, 0x00e78ca9}, /* U+7329 */ - {0xe0ce, 0x00e78ca5}, /* U+7325 */ - {0xe0cf, 0x00e78cbe}, /* U+733E */ - {0xe0d0, 0x00e78d8e}, /* U+734E */ - {0xe0d1, 0x00e78d8f}, /* U+734F */ - {0xe0d2, 0x00e9bb98}, /* U+9ED8 */ - {0xe0d3, 0x00e78d97}, /* U+7357 */ - {0xe0d4, 0x00e78daa}, /* U+736A */ - {0xe0d5, 0x00e78da8}, /* U+7368 */ - {0xe0d6, 0x00e78db0}, /* U+7370 */ - {0xe0d7, 0x00e78db8}, /* U+7378 */ - {0xe0d8, 0x00e78db5}, /* U+7375 */ - {0xe0d9, 0x00e78dbb}, /* U+737B */ - {0xe0da, 0x00e78dba}, /* U+737A */ - {0xe0db, 0x00e78f88}, /* U+73C8 */ - {0xe0dc, 0x00e78eb3}, /* U+73B3 */ - {0xe0dd, 0x00e78f8e}, /* U+73CE */ - {0xe0de, 0x00e78ebb}, /* U+73BB */ - {0xe0df, 0x00e78f80}, /* U+73C0 */ - {0xe0e0, 0x00e78fa5}, /* U+73E5 */ - {0xe0e1, 0x00e78fae}, /* U+73EE */ - {0xe0e2, 0x00e78f9e}, /* U+73DE */ - {0xe0e3, 0x00e792a2}, /* U+74A2 */ - {0xe0e4, 0x00e79085}, /* U+7405 */ - {0xe0e5, 0x00e791af}, /* U+746F */ - {0xe0e6, 0x00e790a5}, /* U+7425 */ - {0xe0e7, 0x00e78fb8}, /* U+73F8 */ - {0xe0e8, 0x00e790b2}, /* U+7432 */ - {0xe0e9, 0x00e790ba}, /* U+743A */ - {0xe0ea, 0x00e79195}, /* U+7455 */ - {0xe0eb, 0x00e790bf}, /* U+743F */ - {0xe0ec, 0x00e7919f}, /* U+745F */ - {0xe0ed, 0x00e79199}, /* U+7459 */ - {0xe0ee, 0x00e79181}, /* U+7441 */ - {0xe0ef, 0x00e7919c}, /* U+745C */ - {0xe0f0, 0x00e791a9}, /* U+7469 */ - {0xe0f1, 0x00e791b0}, /* U+7470 */ - {0xe0f2, 0x00e791a3}, /* U+7463 */ - {0xe0f3, 0x00e791aa}, /* U+746A */ - {0xe0f4, 0x00e791b6}, /* U+7476 */ - {0xe0f5, 0x00e791be}, /* U+747E */ - {0xe0f6, 0x00e7928b}, /* U+748B */ - {0xe0f7, 0x00e7929e}, /* U+749E */ - {0xe0f8, 0x00e792a7}, /* U+74A7 */ - {0xe0f9, 0x00e7938a}, /* U+74CA */ - {0xe0fa, 0x00e7938f}, /* U+74CF */ - {0xe0fb, 0x00e79394}, /* U+74D4 */ - {0xe0fc, 0x00e78fb1}, /* U+73F1 */ - {0xe140, 0x00e793a0}, /* U+74E0 */ - {0xe141, 0x00e793a3}, /* U+74E3 */ - {0xe142, 0x00e793a7}, /* U+74E7 */ - {0xe143, 0x00e793a9}, /* U+74E9 */ - {0xe144, 0x00e793ae}, /* U+74EE */ - {0xe145, 0x00e793b2}, /* U+74F2 */ - {0xe146, 0x00e793b0}, /* U+74F0 */ - {0xe147, 0x00e793b1}, /* U+74F1 */ - {0xe148, 0x00e793b8}, /* U+74F8 */ - {0xe149, 0x00e793b7}, /* U+74F7 */ - {0xe14a, 0x00e79484}, /* U+7504 */ - {0xe14b, 0x00e79483}, /* U+7503 */ - {0xe14c, 0x00e79485}, /* U+7505 */ - {0xe14d, 0x00e7948c}, /* U+750C */ - {0xe14e, 0x00e7948e}, /* U+750E */ - {0xe14f, 0x00e7948d}, /* U+750D */ - {0xe150, 0x00e79495}, /* U+7515 */ - {0xe151, 0x00e79493}, /* U+7513 */ - {0xe152, 0x00e7949e}, /* U+751E */ - {0xe153, 0x00e794a6}, /* U+7526 */ - {0xe154, 0x00e794ac}, /* U+752C */ - {0xe155, 0x00e794bc}, /* U+753C */ - {0xe156, 0x00e79584}, /* U+7544 */ - {0xe157, 0x00e7958d}, /* U+754D */ - {0xe158, 0x00e7958a}, /* U+754A */ - {0xe159, 0x00e79589}, /* U+7549 */ - {0xe15a, 0x00e7959b}, /* U+755B */ - {0xe15b, 0x00e79586}, /* U+7546 */ - {0xe15c, 0x00e7959a}, /* U+755A */ - {0xe15d, 0x00e795a9}, /* U+7569 */ - {0xe15e, 0x00e795a4}, /* U+7564 */ - {0xe15f, 0x00e795a7}, /* U+7567 */ - {0xe160, 0x00e795ab}, /* U+756B */ - {0xe161, 0x00e795ad}, /* U+756D */ - {0xe162, 0x00e795b8}, /* U+7578 */ - {0xe163, 0x00e795b6}, /* U+7576 */ - {0xe164, 0x00e79686}, /* U+7586 */ - {0xe165, 0x00e79687}, /* U+7587 */ - {0xe166, 0x00e795b4}, /* U+7574 */ - {0xe167, 0x00e7968a}, /* U+758A */ - {0xe168, 0x00e79689}, /* U+7589 */ - {0xe169, 0x00e79682}, /* U+7582 */ - {0xe16a, 0x00e79694}, /* U+7594 */ - {0xe16b, 0x00e7969a}, /* U+759A */ - {0xe16c, 0x00e7969d}, /* U+759D */ - {0xe16d, 0x00e796a5}, /* U+75A5 */ - {0xe16e, 0x00e796a3}, /* U+75A3 */ - {0xe16f, 0x00e79782}, /* U+75C2 */ - {0xe170, 0x00e796b3}, /* U+75B3 */ - {0xe171, 0x00e79783}, /* U+75C3 */ - {0xe172, 0x00e796b5}, /* U+75B5 */ - {0xe173, 0x00e796bd}, /* U+75BD */ - {0xe174, 0x00e796b8}, /* U+75B8 */ - {0xe175, 0x00e796bc}, /* U+75BC */ - {0xe176, 0x00e796b1}, /* U+75B1 */ - {0xe177, 0x00e7978d}, /* U+75CD */ - {0xe178, 0x00e7978a}, /* U+75CA */ - {0xe179, 0x00e79792}, /* U+75D2 */ - {0xe17a, 0x00e79799}, /* U+75D9 */ - {0xe17b, 0x00e797a3}, /* U+75E3 */ - {0xe17c, 0x00e7979e}, /* U+75DE */ - {0xe17d, 0x00e797be}, /* U+75FE */ - {0xe17e, 0x00e797bf}, /* U+75FF */ - {0xe180, 0x00e797bc}, /* U+75FC */ - {0xe181, 0x00e79881}, /* U+7601 */ - {0xe182, 0x00e797b0}, /* U+75F0 */ - {0xe183, 0x00e797ba}, /* U+75FA */ - {0xe184, 0x00e797b2}, /* U+75F2 */ - {0xe185, 0x00e797b3}, /* U+75F3 */ - {0xe186, 0x00e7988b}, /* U+760B */ - {0xe187, 0x00e7988d}, /* U+760D */ - {0xe188, 0x00e79889}, /* U+7609 */ - {0xe189, 0x00e7989f}, /* U+761F */ - {0xe18a, 0x00e798a7}, /* U+7627 */ - {0xe18b, 0x00e798a0}, /* U+7620 */ - {0xe18c, 0x00e798a1}, /* U+7621 */ - {0xe18d, 0x00e798a2}, /* U+7622 */ - {0xe18e, 0x00e798a4}, /* U+7624 */ - {0xe18f, 0x00e798b4}, /* U+7634 */ - {0xe190, 0x00e798b0}, /* U+7630 */ - {0xe191, 0x00e798bb}, /* U+763B */ - {0xe192, 0x00e79987}, /* U+7647 */ - {0xe193, 0x00e79988}, /* U+7648 */ - {0xe194, 0x00e79986}, /* U+7646 */ - {0xe195, 0x00e7999c}, /* U+765C */ - {0xe196, 0x00e79998}, /* U+7658 */ - {0xe197, 0x00e799a1}, /* U+7661 */ - {0xe198, 0x00e799a2}, /* U+7662 */ - {0xe199, 0x00e799a8}, /* U+7668 */ - {0xe19a, 0x00e799a9}, /* U+7669 */ - {0xe19b, 0x00e799aa}, /* U+766A */ - {0xe19c, 0x00e799a7}, /* U+7667 */ - {0xe19d, 0x00e799ac}, /* U+766C */ - {0xe19e, 0x00e799b0}, /* U+7670 */ - {0xe19f, 0x00e799b2}, /* U+7672 */ - {0xe1a0, 0x00e799b6}, /* U+7676 */ - {0xe1a1, 0x00e799b8}, /* U+7678 */ - {0xe1a2, 0x00e799bc}, /* U+767C */ - {0xe1a3, 0x00e79a80}, /* U+7680 */ - {0xe1a4, 0x00e79a83}, /* U+7683 */ - {0xe1a5, 0x00e79a88}, /* U+7688 */ - {0xe1a6, 0x00e79a8b}, /* U+768B */ - {0xe1a7, 0x00e79a8e}, /* U+768E */ - {0xe1a8, 0x00e79a96}, /* U+7696 */ - {0xe1a9, 0x00e79a93}, /* U+7693 */ - {0xe1aa, 0x00e79a99}, /* U+7699 */ - {0xe1ab, 0x00e79a9a}, /* U+769A */ - {0xe1ac, 0x00e79ab0}, /* U+76B0 */ - {0xe1ad, 0x00e79ab4}, /* U+76B4 */ - {0xe1ae, 0x00e79ab8}, /* U+76B8 */ - {0xe1af, 0x00e79ab9}, /* U+76B9 */ - {0xe1b0, 0x00e79aba}, /* U+76BA */ - {0xe1b1, 0x00e79b82}, /* U+76C2 */ - {0xe1b2, 0x00e79b8d}, /* U+76CD */ - {0xe1b3, 0x00e79b96}, /* U+76D6 */ - {0xe1b4, 0x00e79b92}, /* U+76D2 */ - {0xe1b5, 0x00e79b9e}, /* U+76DE */ - {0xe1b6, 0x00e79ba1}, /* U+76E1 */ - {0xe1b7, 0x00e79ba5}, /* U+76E5 */ - {0xe1b8, 0x00e79ba7}, /* U+76E7 */ - {0xe1b9, 0x00e79baa}, /* U+76EA */ - {0xe1ba, 0x00e898af}, /* U+862F */ - {0xe1bb, 0x00e79bbb}, /* U+76FB */ - {0xe1bc, 0x00e79c88}, /* U+7708 */ - {0xe1bd, 0x00e79c87}, /* U+7707 */ - {0xe1be, 0x00e79c84}, /* U+7704 */ - {0xe1bf, 0x00e79ca9}, /* U+7729 */ - {0xe1c0, 0x00e79ca4}, /* U+7724 */ - {0xe1c1, 0x00e79c9e}, /* U+771E */ - {0xe1c2, 0x00e79ca5}, /* U+7725 */ - {0xe1c3, 0x00e79ca6}, /* U+7726 */ - {0xe1c4, 0x00e79c9b}, /* U+771B */ - {0xe1c5, 0x00e79cb7}, /* U+7737 */ - {0xe1c6, 0x00e79cb8}, /* U+7738 */ - {0xe1c7, 0x00e79d87}, /* U+7747 */ - {0xe1c8, 0x00e79d9a}, /* U+775A */ - {0xe1c9, 0x00e79da8}, /* U+7768 */ - {0xe1ca, 0x00e79dab}, /* U+776B */ - {0xe1cb, 0x00e79d9b}, /* U+775B */ - {0xe1cc, 0x00e79da5}, /* U+7765 */ - {0xe1cd, 0x00e79dbf}, /* U+777F */ - {0xe1ce, 0x00e79dbe}, /* U+777E */ - {0xe1cf, 0x00e79db9}, /* U+7779 */ - {0xe1d0, 0x00e79e8e}, /* U+778E */ - {0xe1d1, 0x00e79e8b}, /* U+778B */ - {0xe1d2, 0x00e79e91}, /* U+7791 */ - {0xe1d3, 0x00e79ea0}, /* U+77A0 */ - {0xe1d4, 0x00e79e9e}, /* U+779E */ - {0xe1d5, 0x00e79eb0}, /* U+77B0 */ - {0xe1d6, 0x00e79eb6}, /* U+77B6 */ - {0xe1d7, 0x00e79eb9}, /* U+77B9 */ - {0xe1d8, 0x00e79ebf}, /* U+77BF */ - {0xe1d9, 0x00e79ebc}, /* U+77BC */ - {0xe1da, 0x00e79ebd}, /* U+77BD */ - {0xe1db, 0x00e79ebb}, /* U+77BB */ - {0xe1dc, 0x00e79f87}, /* U+77C7 */ - {0xe1dd, 0x00e79f8d}, /* U+77CD */ - {0xe1de, 0x00e79f97}, /* U+77D7 */ - {0xe1df, 0x00e79f9a}, /* U+77DA */ - {0xe1e0, 0x00e79f9c}, /* U+77DC */ - {0xe1e1, 0x00e79fa3}, /* U+77E3 */ - {0xe1e2, 0x00e79fae}, /* U+77EE */ - {0xe1e3, 0x00e79fbc}, /* U+77FC */ - {0xe1e4, 0x00e7a08c}, /* U+780C */ - {0xe1e5, 0x00e7a092}, /* U+7812 */ - {0xe1e6, 0x00e7a4a6}, /* U+7926 */ - {0xe1e7, 0x00e7a0a0}, /* U+7820 */ - {0xe1e8, 0x00e7a4aa}, /* U+792A */ - {0xe1e9, 0x00e7a185}, /* U+7845 */ - {0xe1ea, 0x00e7a28e}, /* U+788E */ - {0xe1eb, 0x00e7a1b4}, /* U+7874 */ - {0xe1ec, 0x00e7a286}, /* U+7886 */ - {0xe1ed, 0x00e7a1bc}, /* U+787C */ - {0xe1ee, 0x00e7a29a}, /* U+789A */ - {0xe1ef, 0x00e7a28c}, /* U+788C */ - {0xe1f0, 0x00e7a2a3}, /* U+78A3 */ - {0xe1f1, 0x00e7a2b5}, /* U+78B5 */ - {0xe1f2, 0x00e7a2aa}, /* U+78AA */ - {0xe1f3, 0x00e7a2af}, /* U+78AF */ - {0xe1f4, 0x00e7a391}, /* U+78D1 */ - {0xe1f5, 0x00e7a386}, /* U+78C6 */ - {0xe1f6, 0x00e7a38b}, /* U+78CB */ - {0xe1f7, 0x00e7a394}, /* U+78D4 */ - {0xe1f8, 0x00e7a2be}, /* U+78BE */ - {0xe1f9, 0x00e7a2bc}, /* U+78BC */ - {0xe1fa, 0x00e7a385}, /* U+78C5 */ - {0xe1fb, 0x00e7a38a}, /* U+78CA */ - {0xe1fc, 0x00e7a3ac}, /* U+78EC */ - {0xe240, 0x00e7a3a7}, /* U+78E7 */ - {0xe241, 0x00e7a39a}, /* U+78DA */ - {0xe242, 0x00e7a3bd}, /* U+78FD */ - {0xe243, 0x00e7a3b4}, /* U+78F4 */ - {0xe244, 0x00e7a487}, /* U+7907 */ - {0xe245, 0x00e7a492}, /* U+7912 */ - {0xe246, 0x00e7a491}, /* U+7911 */ - {0xe247, 0x00e7a499}, /* U+7919 */ - {0xe248, 0x00e7a4ac}, /* U+792C */ - {0xe249, 0x00e7a4ab}, /* U+792B */ - {0xe24a, 0x00e7a580}, /* U+7940 */ - {0xe24b, 0x00e7a5a0}, /* U+7960 */ - {0xe24c, 0x00e7a597}, /* U+7957 */ - {0xe24d, 0x00e7a59f}, /* U+795F */ - {0xe24e, 0x00e7a59a}, /* U+795A */ - {0xe24f, 0x00e7a595}, /* U+7955 */ - {0xe250, 0x00e7a593}, /* U+7953 */ - {0xe251, 0x00e7a5ba}, /* U+797A */ - {0xe252, 0x00e7a5bf}, /* U+797F */ - {0xe253, 0x00e7a68a}, /* U+798A */ - {0xe254, 0x00e7a69d}, /* U+799D */ - {0xe255, 0x00e7a6a7}, /* U+79A7 */ - {0xe256, 0x00e9bd8b}, /* U+9F4B */ - {0xe257, 0x00e7a6aa}, /* U+79AA */ - {0xe258, 0x00e7a6ae}, /* U+79AE */ - {0xe259, 0x00e7a6b3}, /* U+79B3 */ - {0xe25a, 0x00e7a6b9}, /* U+79B9 */ - {0xe25b, 0x00e7a6ba}, /* U+79BA */ - {0xe25c, 0x00e7a789}, /* U+79C9 */ - {0xe25d, 0x00e7a795}, /* U+79D5 */ - {0xe25e, 0x00e7a7a7}, /* U+79E7 */ - {0xe25f, 0x00e7a7ac}, /* U+79EC */ - {0xe260, 0x00e7a7a1}, /* U+79E1 */ - {0xe261, 0x00e7a7a3}, /* U+79E3 */ - {0xe262, 0x00e7a888}, /* U+7A08 */ - {0xe263, 0x00e7a88d}, /* U+7A0D */ - {0xe264, 0x00e7a898}, /* U+7A18 */ - {0xe265, 0x00e7a899}, /* U+7A19 */ - {0xe266, 0x00e7a8a0}, /* U+7A20 */ - {0xe267, 0x00e7a89f}, /* U+7A1F */ - {0xe268, 0x00e7a680}, /* U+7980 */ - {0xe269, 0x00e7a8b1}, /* U+7A31 */ - {0xe26a, 0x00e7a8bb}, /* U+7A3B */ - {0xe26b, 0x00e7a8be}, /* U+7A3E */ - {0xe26c, 0x00e7a8b7}, /* U+7A37 */ - {0xe26d, 0x00e7a983}, /* U+7A43 */ - {0xe26e, 0x00e7a997}, /* U+7A57 */ - {0xe26f, 0x00e7a989}, /* U+7A49 */ - {0xe270, 0x00e7a9a1}, /* U+7A61 */ - {0xe271, 0x00e7a9a2}, /* U+7A62 */ - {0xe272, 0x00e7a9a9}, /* U+7A69 */ - {0xe273, 0x00e9be9d}, /* U+9F9D */ - {0xe274, 0x00e7a9b0}, /* U+7A70 */ - {0xe275, 0x00e7a9b9}, /* U+7A79 */ - {0xe276, 0x00e7a9bd}, /* U+7A7D */ - {0xe277, 0x00e7aa88}, /* U+7A88 */ - {0xe278, 0x00e7aa97}, /* U+7A97 */ - {0xe279, 0x00e7aa95}, /* U+7A95 */ - {0xe27a, 0x00e7aa98}, /* U+7A98 */ - {0xe27b, 0x00e7aa96}, /* U+7A96 */ - {0xe27c, 0x00e7aaa9}, /* U+7AA9 */ - {0xe27d, 0x00e7ab88}, /* U+7AC8 */ - {0xe27e, 0x00e7aab0}, /* U+7AB0 */ - {0xe280, 0x00e7aab6}, /* U+7AB6 */ - {0xe281, 0x00e7ab85}, /* U+7AC5 */ - {0xe282, 0x00e7ab84}, /* U+7AC4 */ - {0xe283, 0x00e7aabf}, /* U+7ABF */ - {0xe284, 0x00e98283}, /* U+9083 */ - {0xe285, 0x00e7ab87}, /* U+7AC7 */ - {0xe286, 0x00e7ab8a}, /* U+7ACA */ - {0xe287, 0x00e7ab8d}, /* U+7ACD */ - {0xe288, 0x00e7ab8f}, /* U+7ACF */ - {0xe289, 0x00e7ab95}, /* U+7AD5 */ - {0xe28a, 0x00e7ab93}, /* U+7AD3 */ - {0xe28b, 0x00e7ab99}, /* U+7AD9 */ - {0xe28c, 0x00e7ab9a}, /* U+7ADA */ - {0xe28d, 0x00e7ab9d}, /* U+7ADD */ - {0xe28e, 0x00e7aba1}, /* U+7AE1 */ - {0xe28f, 0x00e7aba2}, /* U+7AE2 */ - {0xe290, 0x00e7aba6}, /* U+7AE6 */ - {0xe291, 0x00e7abad}, /* U+7AED */ - {0xe292, 0x00e7abb0}, /* U+7AF0 */ - {0xe293, 0x00e7ac82}, /* U+7B02 */ - {0xe294, 0x00e7ac8f}, /* U+7B0F */ - {0xe295, 0x00e7ac8a}, /* U+7B0A */ - {0xe296, 0x00e7ac86}, /* U+7B06 */ - {0xe297, 0x00e7acb3}, /* U+7B33 */ - {0xe298, 0x00e7ac98}, /* U+7B18 */ - {0xe299, 0x00e7ac99}, /* U+7B19 */ - {0xe29a, 0x00e7ac9e}, /* U+7B1E */ - {0xe29b, 0x00e7acb5}, /* U+7B35 */ - {0xe29c, 0x00e7aca8}, /* U+7B28 */ - {0xe29d, 0x00e7acb6}, /* U+7B36 */ - {0xe29e, 0x00e7ad90}, /* U+7B50 */ - {0xe29f, 0x00e7adba}, /* U+7B7A */ - {0xe2a0, 0x00e7ac84}, /* U+7B04 */ - {0xe2a1, 0x00e7ad8d}, /* U+7B4D */ - {0xe2a2, 0x00e7ac8b}, /* U+7B0B */ - {0xe2a3, 0x00e7ad8c}, /* U+7B4C */ - {0xe2a4, 0x00e7ad85}, /* U+7B45 */ - {0xe2a5, 0x00e7adb5}, /* U+7B75 */ - {0xe2a6, 0x00e7ada5}, /* U+7B65 */ - {0xe2a7, 0x00e7adb4}, /* U+7B74 */ - {0xe2a8, 0x00e7ada7}, /* U+7B67 */ - {0xe2a9, 0x00e7adb0}, /* U+7B70 */ - {0xe2aa, 0x00e7adb1}, /* U+7B71 */ - {0xe2ab, 0x00e7adac}, /* U+7B6C */ - {0xe2ac, 0x00e7adae}, /* U+7B6E */ - {0xe2ad, 0x00e7ae9d}, /* U+7B9D */ - {0xe2ae, 0x00e7ae98}, /* U+7B98 */ - {0xe2af, 0x00e7ae9f}, /* U+7B9F */ - {0xe2b0, 0x00e7ae8d}, /* U+7B8D */ - {0xe2b1, 0x00e7ae9c}, /* U+7B9C */ - {0xe2b2, 0x00e7ae9a}, /* U+7B9A */ - {0xe2b3, 0x00e7ae8b}, /* U+7B8B */ - {0xe2b4, 0x00e7ae92}, /* U+7B92 */ - {0xe2b5, 0x00e7ae8f}, /* U+7B8F */ - {0xe2b6, 0x00e7ad9d}, /* U+7B5D */ - {0xe2b7, 0x00e7ae99}, /* U+7B99 */ - {0xe2b8, 0x00e7af8b}, /* U+7BCB */ - {0xe2b9, 0x00e7af81}, /* U+7BC1 */ - {0xe2ba, 0x00e7af8c}, /* U+7BCC */ - {0xe2bb, 0x00e7af8f}, /* U+7BCF */ - {0xe2bc, 0x00e7aeb4}, /* U+7BB4 */ - {0xe2bd, 0x00e7af86}, /* U+7BC6 */ - {0xe2be, 0x00e7af9d}, /* U+7BDD */ - {0xe2bf, 0x00e7afa9}, /* U+7BE9 */ - {0xe2c0, 0x00e7b091}, /* U+7C11 */ - {0xe2c1, 0x00e7b094}, /* U+7C14 */ - {0xe2c2, 0x00e7afa6}, /* U+7BE6 */ - {0xe2c3, 0x00e7afa5}, /* U+7BE5 */ - {0xe2c4, 0x00e7b1a0}, /* U+7C60 */ - {0xe2c5, 0x00e7b080}, /* U+7C00 */ - {0xe2c6, 0x00e7b087}, /* U+7C07 */ - {0xe2c7, 0x00e7b093}, /* U+7C13 */ - {0xe2c8, 0x00e7afb3}, /* U+7BF3 */ - {0xe2c9, 0x00e7afb7}, /* U+7BF7 */ - {0xe2ca, 0x00e7b097}, /* U+7C17 */ - {0xe2cb, 0x00e7b08d}, /* U+7C0D */ - {0xe2cc, 0x00e7afb6}, /* U+7BF6 */ - {0xe2cd, 0x00e7b0a3}, /* U+7C23 */ - {0xe2ce, 0x00e7b0a7}, /* U+7C27 */ - {0xe2cf, 0x00e7b0aa}, /* U+7C2A */ - {0xe2d0, 0x00e7b09f}, /* U+7C1F */ - {0xe2d1, 0x00e7b0b7}, /* U+7C37 */ - {0xe2d2, 0x00e7b0ab}, /* U+7C2B */ - {0xe2d3, 0x00e7b0bd}, /* U+7C3D */ - {0xe2d4, 0x00e7b18c}, /* U+7C4C */ - {0xe2d5, 0x00e7b183}, /* U+7C43 */ - {0xe2d6, 0x00e7b194}, /* U+7C54 */ - {0xe2d7, 0x00e7b18f}, /* U+7C4F */ - {0xe2d8, 0x00e7b180}, /* U+7C40 */ - {0xe2d9, 0x00e7b190}, /* U+7C50 */ - {0xe2da, 0x00e7b198}, /* U+7C58 */ - {0xe2db, 0x00e7b19f}, /* U+7C5F */ - {0xe2dc, 0x00e7b1a4}, /* U+7C64 */ - {0xe2dd, 0x00e7b196}, /* U+7C56 */ - {0xe2de, 0x00e7b1a5}, /* U+7C65 */ - {0xe2df, 0x00e7b1ac}, /* U+7C6C */ - {0xe2e0, 0x00e7b1b5}, /* U+7C75 */ - {0xe2e1, 0x00e7b283}, /* U+7C83 */ - {0xe2e2, 0x00e7b290}, /* U+7C90 */ - {0xe2e3, 0x00e7b2a4}, /* U+7CA4 */ - {0xe2e4, 0x00e7b2ad}, /* U+7CAD */ - {0xe2e5, 0x00e7b2a2}, /* U+7CA2 */ - {0xe2e6, 0x00e7b2ab}, /* U+7CAB */ - {0xe2e7, 0x00e7b2a1}, /* U+7CA1 */ - {0xe2e8, 0x00e7b2a8}, /* U+7CA8 */ - {0xe2e9, 0x00e7b2b3}, /* U+7CB3 */ - {0xe2ea, 0x00e7b2b2}, /* U+7CB2 */ - {0xe2eb, 0x00e7b2b1}, /* U+7CB1 */ - {0xe2ec, 0x00e7b2ae}, /* U+7CAE */ - {0xe2ed, 0x00e7b2b9}, /* U+7CB9 */ - {0xe2ee, 0x00e7b2bd}, /* U+7CBD */ - {0xe2ef, 0x00e7b380}, /* U+7CC0 */ - {0xe2f0, 0x00e7b385}, /* U+7CC5 */ - {0xe2f1, 0x00e7b382}, /* U+7CC2 */ - {0xe2f2, 0x00e7b398}, /* U+7CD8 */ - {0xe2f3, 0x00e7b392}, /* U+7CD2 */ - {0xe2f4, 0x00e7b39c}, /* U+7CDC */ - {0xe2f5, 0x00e7b3a2}, /* U+7CE2 */ - {0xe2f6, 0x00e9acbb}, /* U+9B3B */ - {0xe2f7, 0x00e7b3af}, /* U+7CEF */ - {0xe2f8, 0x00e7b3b2}, /* U+7CF2 */ - {0xe2f9, 0x00e7b3b4}, /* U+7CF4 */ - {0xe2fa, 0x00e7b3b6}, /* U+7CF6 */ - {0xe2fb, 0x00e7b3ba}, /* U+7CFA */ - {0xe2fc, 0x00e7b486}, /* U+7D06 */ - {0xe340, 0x00e7b482}, /* U+7D02 */ - {0xe341, 0x00e7b49c}, /* U+7D1C */ - {0xe342, 0x00e7b495}, /* U+7D15 */ - {0xe343, 0x00e7b48a}, /* U+7D0A */ - {0xe344, 0x00e7b585}, /* U+7D45 */ - {0xe345, 0x00e7b58b}, /* U+7D4B */ - {0xe346, 0x00e7b4ae}, /* U+7D2E */ - {0xe347, 0x00e7b4b2}, /* U+7D32 */ - {0xe348, 0x00e7b4bf}, /* U+7D3F */ - {0xe349, 0x00e7b4b5}, /* U+7D35 */ - {0xe34a, 0x00e7b586}, /* U+7D46 */ - {0xe34b, 0x00e7b5b3}, /* U+7D73 */ - {0xe34c, 0x00e7b596}, /* U+7D56 */ - {0xe34d, 0x00e7b58e}, /* U+7D4E */ - {0xe34e, 0x00e7b5b2}, /* U+7D72 */ - {0xe34f, 0x00e7b5a8}, /* U+7D68 */ - {0xe350, 0x00e7b5ae}, /* U+7D6E */ - {0xe351, 0x00e7b58f}, /* U+7D4F */ - {0xe352, 0x00e7b5a3}, /* U+7D63 */ - {0xe353, 0x00e7b693}, /* U+7D93 */ - {0xe354, 0x00e7b689}, /* U+7D89 */ - {0xe355, 0x00e7b59b}, /* U+7D5B */ - {0xe356, 0x00e7b68f}, /* U+7D8F */ - {0xe357, 0x00e7b5bd}, /* U+7D7D */ - {0xe358, 0x00e7b69b}, /* U+7D9B */ - {0xe359, 0x00e7b6ba}, /* U+7DBA */ - {0xe35a, 0x00e7b6ae}, /* U+7DAE */ - {0xe35b, 0x00e7b6a3}, /* U+7DA3 */ - {0xe35c, 0x00e7b6b5}, /* U+7DB5 */ - {0xe35d, 0x00e7b787}, /* U+7DC7 */ - {0xe35e, 0x00e7b6bd}, /* U+7DBD */ - {0xe35f, 0x00e7b6ab}, /* U+7DAB */ - {0xe360, 0x00e7b8bd}, /* U+7E3D */ - {0xe361, 0x00e7b6a2}, /* U+7DA2 */ - {0xe362, 0x00e7b6af}, /* U+7DAF */ - {0xe363, 0x00e7b79c}, /* U+7DDC */ - {0xe364, 0x00e7b6b8}, /* U+7DB8 */ - {0xe365, 0x00e7b69f}, /* U+7D9F */ - {0xe366, 0x00e7b6b0}, /* U+7DB0 */ - {0xe367, 0x00e7b798}, /* U+7DD8 */ - {0xe368, 0x00e7b79d}, /* U+7DDD */ - {0xe369, 0x00e7b7a4}, /* U+7DE4 */ - {0xe36a, 0x00e7b79e}, /* U+7DDE */ - {0xe36b, 0x00e7b7bb}, /* U+7DFB */ - {0xe36c, 0x00e7b7b2}, /* U+7DF2 */ - {0xe36d, 0x00e7b7a1}, /* U+7DE1 */ - {0xe36e, 0x00e7b885}, /* U+7E05 */ - {0xe36f, 0x00e7b88a}, /* U+7E0A */ - {0xe370, 0x00e7b8a3}, /* U+7E23 */ - {0xe371, 0x00e7b8a1}, /* U+7E21 */ - {0xe372, 0x00e7b892}, /* U+7E12 */ - {0xe373, 0x00e7b8b1}, /* U+7E31 */ - {0xe374, 0x00e7b89f}, /* U+7E1F */ - {0xe375, 0x00e7b889}, /* U+7E09 */ - {0xe376, 0x00e7b88b}, /* U+7E0B */ - {0xe377, 0x00e7b8a2}, /* U+7E22 */ - {0xe378, 0x00e7b986}, /* U+7E46 */ - {0xe379, 0x00e7b9a6}, /* U+7E66 */ - {0xe37a, 0x00e7b8bb}, /* U+7E3B */ - {0xe37b, 0x00e7b8b5}, /* U+7E35 */ - {0xe37c, 0x00e7b8b9}, /* U+7E39 */ - {0xe37d, 0x00e7b983}, /* U+7E43 */ - {0xe37e, 0x00e7b8b7}, /* U+7E37 */ - {0xe380, 0x00e7b8b2}, /* U+7E32 */ - {0xe381, 0x00e7b8ba}, /* U+7E3A */ - {0xe382, 0x00e7b9a7}, /* U+7E67 */ - {0xe383, 0x00e7b99d}, /* U+7E5D */ - {0xe384, 0x00e7b996}, /* U+7E56 */ - {0xe385, 0x00e7b99e}, /* U+7E5E */ - {0xe386, 0x00e7b999}, /* U+7E59 */ - {0xe387, 0x00e7b99a}, /* U+7E5A */ - {0xe388, 0x00e7b9b9}, /* U+7E79 */ - {0xe389, 0x00e7b9aa}, /* U+7E6A */ - {0xe38a, 0x00e7b9a9}, /* U+7E69 */ - {0xe38b, 0x00e7b9bc}, /* U+7E7C */ - {0xe38c, 0x00e7b9bb}, /* U+7E7B */ - {0xe38d, 0x00e7ba83}, /* U+7E83 */ - {0xe38e, 0x00e7b795}, /* U+7DD5 */ - {0xe38f, 0x00e7b9bd}, /* U+7E7D */ - {0xe390, 0x00e8beae}, /* U+8FAE */ - {0xe391, 0x00e7b9bf}, /* U+7E7F */ - {0xe392, 0x00e7ba88}, /* U+7E88 */ - {0xe393, 0x00e7ba89}, /* U+7E89 */ - {0xe394, 0x00e7ba8c}, /* U+7E8C */ - {0xe395, 0x00e7ba92}, /* U+7E92 */ - {0xe396, 0x00e7ba90}, /* U+7E90 */ - {0xe397, 0x00e7ba93}, /* U+7E93 */ - {0xe398, 0x00e7ba94}, /* U+7E94 */ - {0xe399, 0x00e7ba96}, /* U+7E96 */ - {0xe39a, 0x00e7ba8e}, /* U+7E8E */ - {0xe39b, 0x00e7ba9b}, /* U+7E9B */ - {0xe39c, 0x00e7ba9c}, /* U+7E9C */ - {0xe39d, 0x00e7bcb8}, /* U+7F38 */ - {0xe39e, 0x00e7bcba}, /* U+7F3A */ - {0xe39f, 0x00e7bd85}, /* U+7F45 */ - {0xe3a0, 0x00e7bd8c}, /* U+7F4C */ - {0xe3a1, 0x00e7bd8d}, /* U+7F4D */ - {0xe3a2, 0x00e7bd8e}, /* U+7F4E */ - {0xe3a3, 0x00e7bd90}, /* U+7F50 */ - {0xe3a4, 0x00e7bd91}, /* U+7F51 */ - {0xe3a5, 0x00e7bd95}, /* U+7F55 */ - {0xe3a6, 0x00e7bd94}, /* U+7F54 */ - {0xe3a7, 0x00e7bd98}, /* U+7F58 */ - {0xe3a8, 0x00e7bd9f}, /* U+7F5F */ - {0xe3a9, 0x00e7bda0}, /* U+7F60 */ - {0xe3aa, 0x00e7bda8}, /* U+7F68 */ - {0xe3ab, 0x00e7bda9}, /* U+7F69 */ - {0xe3ac, 0x00e7bda7}, /* U+7F67 */ - {0xe3ad, 0x00e7bdb8}, /* U+7F78 */ - {0xe3ae, 0x00e7be82}, /* U+7F82 */ - {0xe3af, 0x00e7be86}, /* U+7F86 */ - {0xe3b0, 0x00e7be83}, /* U+7F83 */ - {0xe3b1, 0x00e7be88}, /* U+7F88 */ - {0xe3b2, 0x00e7be87}, /* U+7F87 */ - {0xe3b3, 0x00e7be8c}, /* U+7F8C */ - {0xe3b4, 0x00e7be94}, /* U+7F94 */ - {0xe3b5, 0x00e7be9e}, /* U+7F9E */ - {0xe3b6, 0x00e7be9d}, /* U+7F9D */ - {0xe3b7, 0x00e7be9a}, /* U+7F9A */ - {0xe3b8, 0x00e7bea3}, /* U+7FA3 */ - {0xe3b9, 0x00e7beaf}, /* U+7FAF */ - {0xe3ba, 0x00e7beb2}, /* U+7FB2 */ - {0xe3bb, 0x00e7beb9}, /* U+7FB9 */ - {0xe3bc, 0x00e7beae}, /* U+7FAE */ - {0xe3bd, 0x00e7beb6}, /* U+7FB6 */ - {0xe3be, 0x00e7beb8}, /* U+7FB8 */ - {0xe3bf, 0x00e8adb1}, /* U+8B71 */ - {0xe3c0, 0x00e7bf85}, /* U+7FC5 */ - {0xe3c1, 0x00e7bf86}, /* U+7FC6 */ - {0xe3c2, 0x00e7bf8a}, /* U+7FCA */ - {0xe3c3, 0x00e7bf95}, /* U+7FD5 */ - {0xe3c4, 0x00e7bf94}, /* U+7FD4 */ - {0xe3c5, 0x00e7bfa1}, /* U+7FE1 */ - {0xe3c6, 0x00e7bfa6}, /* U+7FE6 */ - {0xe3c7, 0x00e7bfa9}, /* U+7FE9 */ - {0xe3c8, 0x00e7bfb3}, /* U+7FF3 */ - {0xe3c9, 0x00e7bfb9}, /* U+7FF9 */ - {0xe3ca, 0x00e9a39c}, /* U+98DC */ - {0xe3cb, 0x00e88086}, /* U+8006 */ - {0xe3cc, 0x00e88084}, /* U+8004 */ - {0xe3cd, 0x00e8808b}, /* U+800B */ - {0xe3ce, 0x00e88092}, /* U+8012 */ - {0xe3cf, 0x00e88098}, /* U+8018 */ - {0xe3d0, 0x00e88099}, /* U+8019 */ - {0xe3d1, 0x00e8809c}, /* U+801C */ - {0xe3d2, 0x00e880a1}, /* U+8021 */ - {0xe3d3, 0x00e880a8}, /* U+8028 */ - {0xe3d4, 0x00e880bf}, /* U+803F */ - {0xe3d5, 0x00e880bb}, /* U+803B */ - {0xe3d6, 0x00e8818a}, /* U+804A */ - {0xe3d7, 0x00e88186}, /* U+8046 */ - {0xe3d8, 0x00e88192}, /* U+8052 */ - {0xe3d9, 0x00e88198}, /* U+8058 */ - {0xe3da, 0x00e8819a}, /* U+805A */ - {0xe3db, 0x00e8819f}, /* U+805F */ - {0xe3dc, 0x00e881a2}, /* U+8062 */ - {0xe3dd, 0x00e881a8}, /* U+8068 */ - {0xe3de, 0x00e881b3}, /* U+8073 */ - {0xe3df, 0x00e881b2}, /* U+8072 */ - {0xe3e0, 0x00e881b0}, /* U+8070 */ - {0xe3e1, 0x00e881b6}, /* U+8076 */ - {0xe3e2, 0x00e881b9}, /* U+8079 */ - {0xe3e3, 0x00e881bd}, /* U+807D */ - {0xe3e4, 0x00e881bf}, /* U+807F */ - {0xe3e5, 0x00e88284}, /* U+8084 */ - {0xe3e6, 0x00e88286}, /* U+8086 */ - {0xe3e7, 0x00e88285}, /* U+8085 */ - {0xe3e8, 0x00e8829b}, /* U+809B */ - {0xe3e9, 0x00e88293}, /* U+8093 */ - {0xe3ea, 0x00e8829a}, /* U+809A */ - {0xe3eb, 0x00e882ad}, /* U+80AD */ - {0xe3ec, 0x00e58690}, /* U+5190 */ - {0xe3ed, 0x00e882ac}, /* U+80AC */ - {0xe3ee, 0x00e8839b}, /* U+80DB */ - {0xe3ef, 0x00e883a5}, /* U+80E5 */ - {0xe3f0, 0x00e88399}, /* U+80D9 */ - {0xe3f1, 0x00e8839d}, /* U+80DD */ - {0xe3f2, 0x00e88384}, /* U+80C4 */ - {0xe3f3, 0x00e8839a}, /* U+80DA */ - {0xe3f4, 0x00e88396}, /* U+80D6 */ - {0xe3f5, 0x00e88489}, /* U+8109 */ - {0xe3f6, 0x00e883af}, /* U+80EF */ - {0xe3f7, 0x00e883b1}, /* U+80F1 */ - {0xe3f8, 0x00e8849b}, /* U+811B */ - {0xe3f9, 0x00e884a9}, /* U+8129 */ - {0xe3fa, 0x00e884a3}, /* U+8123 */ - {0xe3fb, 0x00e884af}, /* U+812F */ - {0xe3fc, 0x00e8858b}, /* U+814B */ - {0xe440, 0x00e99a8b}, /* U+968B */ - {0xe441, 0x00e88586}, /* U+8146 */ - {0xe442, 0x00e884be}, /* U+813E */ - {0xe443, 0x00e88593}, /* U+8153 */ - {0xe444, 0x00e88591}, /* U+8151 */ - {0xe445, 0x00e883bc}, /* U+80FC */ - {0xe446, 0x00e885b1}, /* U+8171 */ - {0xe447, 0x00e885ae}, /* U+816E */ - {0xe448, 0x00e885a5}, /* U+8165 */ - {0xe449, 0x00e885a6}, /* U+8166 */ - {0xe44a, 0x00e885b4}, /* U+8174 */ - {0xe44b, 0x00e88683}, /* U+8183 */ - {0xe44c, 0x00e88688}, /* U+8188 */ - {0xe44d, 0x00e8868a}, /* U+818A */ - {0xe44e, 0x00e88680}, /* U+8180 */ - {0xe44f, 0x00e88682}, /* U+8182 */ - {0xe450, 0x00e886a0}, /* U+81A0 */ - {0xe451, 0x00e88695}, /* U+8195 */ - {0xe452, 0x00e886a4}, /* U+81A4 */ - {0xe453, 0x00e886a3}, /* U+81A3 */ - {0xe454, 0x00e8859f}, /* U+815F */ - {0xe455, 0x00e88693}, /* U+8193 */ - {0xe456, 0x00e886a9}, /* U+81A9 */ - {0xe457, 0x00e886b0}, /* U+81B0 */ - {0xe458, 0x00e886b5}, /* U+81B5 */ - {0xe459, 0x00e886be}, /* U+81BE */ - {0xe45a, 0x00e886b8}, /* U+81B8 */ - {0xe45b, 0x00e886bd}, /* U+81BD */ - {0xe45c, 0x00e88780}, /* U+81C0 */ - {0xe45d, 0x00e88782}, /* U+81C2 */ - {0xe45e, 0x00e886ba}, /* U+81BA */ - {0xe45f, 0x00e88789}, /* U+81C9 */ - {0xe460, 0x00e8878d}, /* U+81CD */ - {0xe461, 0x00e88791}, /* U+81D1 */ - {0xe462, 0x00e88799}, /* U+81D9 */ - {0xe463, 0x00e88798}, /* U+81D8 */ - {0xe464, 0x00e88788}, /* U+81C8 */ - {0xe465, 0x00e8879a}, /* U+81DA */ - {0xe466, 0x00e8879f}, /* U+81DF */ - {0xe467, 0x00e887a0}, /* U+81E0 */ - {0xe468, 0x00e887a7}, /* U+81E7 */ - {0xe469, 0x00e887ba}, /* U+81FA */ - {0xe46a, 0x00e887bb}, /* U+81FB */ - {0xe46b, 0x00e887be}, /* U+81FE */ - {0xe46c, 0x00e88881}, /* U+8201 */ - {0xe46d, 0x00e88882}, /* U+8202 */ - {0xe46e, 0x00e88885}, /* U+8205 */ - {0xe46f, 0x00e88887}, /* U+8207 */ - {0xe470, 0x00e8888a}, /* U+820A */ - {0xe471, 0x00e8888d}, /* U+820D */ - {0xe472, 0x00e88890}, /* U+8210 */ - {0xe473, 0x00e88896}, /* U+8216 */ - {0xe474, 0x00e888a9}, /* U+8229 */ - {0xe475, 0x00e888ab}, /* U+822B */ - {0xe476, 0x00e888b8}, /* U+8238 */ - {0xe477, 0x00e888b3}, /* U+8233 */ - {0xe478, 0x00e88980}, /* U+8240 */ - {0xe479, 0x00e88999}, /* U+8259 */ - {0xe47a, 0x00e88998}, /* U+8258 */ - {0xe47b, 0x00e8899d}, /* U+825D */ - {0xe47c, 0x00e8899a}, /* U+825A */ - {0xe47d, 0x00e8899f}, /* U+825F */ - {0xe47e, 0x00e889a4}, /* U+8264 */ - {0xe480, 0x00e889a2}, /* U+8262 */ - {0xe481, 0x00e889a8}, /* U+8268 */ - {0xe482, 0x00e889aa}, /* U+826A */ - {0xe483, 0x00e889ab}, /* U+826B */ - {0xe484, 0x00e888ae}, /* U+822E */ - {0xe485, 0x00e889b1}, /* U+8271 */ - {0xe486, 0x00e889b7}, /* U+8277 */ - {0xe487, 0x00e889b8}, /* U+8278 */ - {0xe488, 0x00e889be}, /* U+827E */ - {0xe489, 0x00e88a8d}, /* U+828D */ - {0xe48a, 0x00e88a92}, /* U+8292 */ - {0xe48b, 0x00e88aab}, /* U+82AB */ - {0xe48c, 0x00e88a9f}, /* U+829F */ - {0xe48d, 0x00e88abb}, /* U+82BB */ - {0xe48e, 0x00e88aac}, /* U+82AC */ - {0xe48f, 0x00e88ba1}, /* U+82E1 */ - {0xe490, 0x00e88ba3}, /* U+82E3 */ - {0xe491, 0x00e88b9f}, /* U+82DF */ - {0xe492, 0x00e88b92}, /* U+82D2 */ - {0xe493, 0x00e88bb4}, /* U+82F4 */ - {0xe494, 0x00e88bb3}, /* U+82F3 */ - {0xe495, 0x00e88bba}, /* U+82FA */ - {0xe496, 0x00e88e93}, /* U+8393 */ - {0xe497, 0x00e88c83}, /* U+8303 */ - {0xe498, 0x00e88bbb}, /* U+82FB */ - {0xe499, 0x00e88bb9}, /* U+82F9 */ - {0xe49a, 0x00e88b9e}, /* U+82DE */ - {0xe49b, 0x00e88c86}, /* U+8306 */ - {0xe49c, 0x00e88b9c}, /* U+82DC */ - {0xe49d, 0x00e88c89}, /* U+8309 */ - {0xe49e, 0x00e88b99}, /* U+82D9 */ - {0xe49f, 0x00e88cb5}, /* U+8335 */ - {0xe4a0, 0x00e88cb4}, /* U+8334 */ - {0xe4a1, 0x00e88c96}, /* U+8316 */ - {0xe4a2, 0x00e88cb2}, /* U+8332 */ - {0xe4a3, 0x00e88cb1}, /* U+8331 */ - {0xe4a4, 0x00e88d80}, /* U+8340 */ - {0xe4a5, 0x00e88cb9}, /* U+8339 */ - {0xe4a6, 0x00e88d90}, /* U+8350 */ - {0xe4a7, 0x00e88d85}, /* U+8345 */ - {0xe4a8, 0x00e88caf}, /* U+832F */ - {0xe4a9, 0x00e88cab}, /* U+832B */ - {0xe4aa, 0x00e88c97}, /* U+8317 */ - {0xe4ab, 0x00e88c98}, /* U+8318 */ - {0xe4ac, 0x00e88e85}, /* U+8385 */ - {0xe4ad, 0x00e88e9a}, /* U+839A */ - {0xe4ae, 0x00e88eaa}, /* U+83AA */ - {0xe4af, 0x00e88e9f}, /* U+839F */ - {0xe4b0, 0x00e88ea2}, /* U+83A2 */ - {0xe4b1, 0x00e88e96}, /* U+8396 */ - {0xe4b2, 0x00e88ca3}, /* U+8323 */ - {0xe4b3, 0x00e88e8e}, /* U+838E */ - {0xe4b4, 0x00e88e87}, /* U+8387 */ - {0xe4b5, 0x00e88e8a}, /* U+838A */ - {0xe4b6, 0x00e88dbc}, /* U+837C */ - {0xe4b7, 0x00e88eb5}, /* U+83B5 */ - {0xe4b8, 0x00e88db3}, /* U+8373 */ - {0xe4b9, 0x00e88db5}, /* U+8375 */ - {0xe4ba, 0x00e88ea0}, /* U+83A0 */ - {0xe4bb, 0x00e88e89}, /* U+8389 */ - {0xe4bc, 0x00e88ea8}, /* U+83A8 */ - {0xe4bd, 0x00e88fb4}, /* U+83F4 */ - {0xe4be, 0x00e89093}, /* U+8413 */ - {0xe4bf, 0x00e88fab}, /* U+83EB */ - {0xe4c0, 0x00e88f8e}, /* U+83CE */ - {0xe4c1, 0x00e88fbd}, /* U+83FD */ - {0xe4c2, 0x00e89083}, /* U+8403 */ - {0xe4c3, 0x00e88f98}, /* U+83D8 */ - {0xe4c4, 0x00e8908b}, /* U+840B */ - {0xe4c5, 0x00e88f81}, /* U+83C1 */ - {0xe4c6, 0x00e88fb7}, /* U+83F7 */ - {0xe4c7, 0x00e89087}, /* U+8407 */ - {0xe4c8, 0x00e88fa0}, /* U+83E0 */ - {0xe4c9, 0x00e88fb2}, /* U+83F2 */ - {0xe4ca, 0x00e8908d}, /* U+840D */ - {0xe4cb, 0x00e890a2}, /* U+8422 */ - {0xe4cc, 0x00e890a0}, /* U+8420 */ - {0xe4cd, 0x00e88ebd}, /* U+83BD */ - {0xe4ce, 0x00e890b8}, /* U+8438 */ - {0xe4cf, 0x00e89486}, /* U+8506 */ - {0xe4d0, 0x00e88fbb}, /* U+83FB */ - {0xe4d1, 0x00e891ad}, /* U+846D */ - {0xe4d2, 0x00e890aa}, /* U+842A */ - {0xe4d3, 0x00e890bc}, /* U+843C */ - {0xe4d4, 0x00e8959a}, /* U+855A */ - {0xe4d5, 0x00e89284}, /* U+8484 */ - {0xe4d6, 0x00e891b7}, /* U+8477 */ - {0xe4d7, 0x00e891ab}, /* U+846B */ - {0xe4d8, 0x00e892ad}, /* U+84AD */ - {0xe4d9, 0x00e891ae}, /* U+846E */ - {0xe4da, 0x00e89282}, /* U+8482 */ - {0xe4db, 0x00e891a9}, /* U+8469 */ - {0xe4dc, 0x00e89186}, /* U+8446 */ - {0xe4dd, 0x00e890ac}, /* U+842C */ - {0xe4de, 0x00e891af}, /* U+846F */ - {0xe4df, 0x00e891b9}, /* U+8479 */ - {0xe4e0, 0x00e890b5}, /* U+8435 */ - {0xe4e1, 0x00e8938a}, /* U+84CA */ - {0xe4e2, 0x00e891a2}, /* U+8462 */ - {0xe4e3, 0x00e892b9}, /* U+84B9 */ - {0xe4e4, 0x00e892bf}, /* U+84BF */ - {0xe4e5, 0x00e8929f}, /* U+849F */ - {0xe4e6, 0x00e89399}, /* U+84D9 */ - {0xe4e7, 0x00e8938d}, /* U+84CD */ - {0xe4e8, 0x00e892bb}, /* U+84BB */ - {0xe4e9, 0x00e8939a}, /* U+84DA */ - {0xe4ea, 0x00e89390}, /* U+84D0 */ - {0xe4eb, 0x00e89381}, /* U+84C1 */ - {0xe4ec, 0x00e89386}, /* U+84C6 */ - {0xe4ed, 0x00e89396}, /* U+84D6 */ - {0xe4ee, 0x00e892a1}, /* U+84A1 */ - {0xe4ef, 0x00e894a1}, /* U+8521 */ - {0xe4f0, 0x00e893bf}, /* U+84FF */ - {0xe4f1, 0x00e893b4}, /* U+84F4 */ - {0xe4f2, 0x00e89497}, /* U+8517 */ - {0xe4f3, 0x00e89498}, /* U+8518 */ - {0xe4f4, 0x00e894ac}, /* U+852C */ - {0xe4f5, 0x00e8949f}, /* U+851F */ - {0xe4f6, 0x00e89495}, /* U+8515 */ - {0xe4f7, 0x00e89494}, /* U+8514 */ - {0xe4f8, 0x00e893bc}, /* U+84FC */ - {0xe4f9, 0x00e89580}, /* U+8540 */ - {0xe4fa, 0x00e895a3}, /* U+8563 */ - {0xe4fb, 0x00e89598}, /* U+8558 */ - {0xe4fc, 0x00e89588}, /* U+8548 */ - {0xe540, 0x00e89581}, /* U+8541 */ - {0xe541, 0x00e89882}, /* U+8602 */ - {0xe542, 0x00e8958b}, /* U+854B */ - {0xe543, 0x00e89595}, /* U+8555 */ - {0xe544, 0x00e89680}, /* U+8580 */ - {0xe545, 0x00e896a4}, /* U+85A4 */ - {0xe546, 0x00e89688}, /* U+8588 */ - {0xe547, 0x00e89691}, /* U+8591 */ - {0xe548, 0x00e8968a}, /* U+858A */ - {0xe549, 0x00e896a8}, /* U+85A8 */ - {0xe54a, 0x00e895ad}, /* U+856D */ - {0xe54b, 0x00e89694}, /* U+8594 */ - {0xe54c, 0x00e8969b}, /* U+859B */ - {0xe54d, 0x00e897aa}, /* U+85EA */ - {0xe54e, 0x00e89687}, /* U+8587 */ - {0xe54f, 0x00e8969c}, /* U+859C */ - {0xe550, 0x00e895b7}, /* U+8577 */ - {0xe551, 0x00e895be}, /* U+857E */ - {0xe552, 0x00e89690}, /* U+8590 */ - {0xe553, 0x00e89789}, /* U+85C9 */ - {0xe554, 0x00e896ba}, /* U+85BA */ - {0xe555, 0x00e8978f}, /* U+85CF */ - {0xe556, 0x00e896b9}, /* U+85B9 */ - {0xe557, 0x00e89790}, /* U+85D0 */ - {0xe558, 0x00e89795}, /* U+85D5 */ - {0xe559, 0x00e8979d}, /* U+85DD */ - {0xe55a, 0x00e897a5}, /* U+85E5 */ - {0xe55b, 0x00e8979c}, /* U+85DC */ - {0xe55c, 0x00e897b9}, /* U+85F9 */ - {0xe55d, 0x00e8988a}, /* U+860A */ - {0xe55e, 0x00e89893}, /* U+8613 */ - {0xe55f, 0x00e8988b}, /* U+860B */ - {0xe560, 0x00e897be}, /* U+85FE */ - {0xe561, 0x00e897ba}, /* U+85FA */ - {0xe562, 0x00e89886}, /* U+8606 */ - {0xe563, 0x00e898a2}, /* U+8622 */ - {0xe564, 0x00e8989a}, /* U+861A */ - {0xe565, 0x00e898b0}, /* U+8630 */ - {0xe566, 0x00e898bf}, /* U+863F */ - {0xe567, 0x00e8998d}, /* U+864D */ - {0xe568, 0x00e4b995}, /* U+4E55 */ - {0xe569, 0x00e89994}, /* U+8654 */ - {0xe56a, 0x00e8999f}, /* U+865F */ - {0xe56b, 0x00e899a7}, /* U+8667 */ - {0xe56c, 0x00e899b1}, /* U+8671 */ - {0xe56d, 0x00e89a93}, /* U+8693 */ - {0xe56e, 0x00e89aa3}, /* U+86A3 */ - {0xe56f, 0x00e89aa9}, /* U+86A9 */ - {0xe570, 0x00e89aaa}, /* U+86AA */ - {0xe571, 0x00e89a8b}, /* U+868B */ - {0xe572, 0x00e89a8c}, /* U+868C */ - {0xe573, 0x00e89ab6}, /* U+86B6 */ - {0xe574, 0x00e89aaf}, /* U+86AF */ - {0xe575, 0x00e89b84}, /* U+86C4 */ - {0xe576, 0x00e89b86}, /* U+86C6 */ - {0xe577, 0x00e89ab0}, /* U+86B0 */ - {0xe578, 0x00e89b89}, /* U+86C9 */ - {0xe579, 0x00e8a0a3}, /* U+8823 */ - {0xe57a, 0x00e89aab}, /* U+86AB */ - {0xe57b, 0x00e89b94}, /* U+86D4 */ - {0xe57c, 0x00e89b9e}, /* U+86DE */ - {0xe57d, 0x00e89ba9}, /* U+86E9 */ - {0xe57e, 0x00e89bac}, /* U+86EC */ - {0xe580, 0x00e89b9f}, /* U+86DF */ - {0xe581, 0x00e89b9b}, /* U+86DB */ - {0xe582, 0x00e89baf}, /* U+86EF */ - {0xe583, 0x00e89c92}, /* U+8712 */ - {0xe584, 0x00e89c86}, /* U+8706 */ - {0xe585, 0x00e89c88}, /* U+8708 */ - {0xe586, 0x00e89c80}, /* U+8700 */ - {0xe587, 0x00e89c83}, /* U+8703 */ - {0xe588, 0x00e89bbb}, /* U+86FB */ - {0xe589, 0x00e89c91}, /* U+8711 */ - {0xe58a, 0x00e89c89}, /* U+8709 */ - {0xe58b, 0x00e89c8d}, /* U+870D */ - {0xe58c, 0x00e89bb9}, /* U+86F9 */ - {0xe58d, 0x00e89c8a}, /* U+870A */ - {0xe58e, 0x00e89cb4}, /* U+8734 */ - {0xe58f, 0x00e89cbf}, /* U+873F */ - {0xe590, 0x00e89cb7}, /* U+8737 */ - {0xe591, 0x00e89cbb}, /* U+873B */ - {0xe592, 0x00e89ca5}, /* U+8725 */ - {0xe593, 0x00e89ca9}, /* U+8729 */ - {0xe594, 0x00e89c9a}, /* U+871A */ - {0xe595, 0x00e89da0}, /* U+8760 */ - {0xe596, 0x00e89d9f}, /* U+875F */ - {0xe597, 0x00e89db8}, /* U+8778 */ - {0xe598, 0x00e89d8c}, /* U+874C */ - {0xe599, 0x00e89d8e}, /* U+874E */ - {0xe59a, 0x00e89db4}, /* U+8774 */ - {0xe59b, 0x00e89d97}, /* U+8757 */ - {0xe59c, 0x00e89da8}, /* U+8768 */ - {0xe59d, 0x00e89dae}, /* U+876E */ - {0xe59e, 0x00e89d99}, /* U+8759 */ - {0xe59f, 0x00e89d93}, /* U+8753 */ - {0xe5a0, 0x00e89da3}, /* U+8763 */ - {0xe5a1, 0x00e89daa}, /* U+876A */ - {0xe5a2, 0x00e8a085}, /* U+8805 */ - {0xe5a3, 0x00e89ea2}, /* U+87A2 */ - {0xe5a4, 0x00e89e9f}, /* U+879F */ - {0xe5a5, 0x00e89e82}, /* U+8782 */ - {0xe5a6, 0x00e89eaf}, /* U+87AF */ - {0xe5a7, 0x00e89f8b}, /* U+87CB */ - {0xe5a8, 0x00e89ebd}, /* U+87BD */ - {0xe5a9, 0x00e89f80}, /* U+87C0 */ - {0xe5aa, 0x00e89f90}, /* U+87D0 */ - {0xe5ab, 0x00e99b96}, /* U+96D6 */ - {0xe5ac, 0x00e89eab}, /* U+87AB */ - {0xe5ad, 0x00e89f84}, /* U+87C4 */ - {0xe5ae, 0x00e89eb3}, /* U+87B3 */ - {0xe5af, 0x00e89f87}, /* U+87C7 */ - {0xe5b0, 0x00e89f86}, /* U+87C6 */ - {0xe5b1, 0x00e89ebb}, /* U+87BB */ - {0xe5b2, 0x00e89faf}, /* U+87EF */ - {0xe5b3, 0x00e89fb2}, /* U+87F2 */ - {0xe5b4, 0x00e89fa0}, /* U+87E0 */ - {0xe5b5, 0x00e8a08f}, /* U+880F */ - {0xe5b6, 0x00e8a08d}, /* U+880D */ - {0xe5b7, 0x00e89fbe}, /* U+87FE */ - {0xe5b8, 0x00e89fb6}, /* U+87F6 */ - {0xe5b9, 0x00e89fb7}, /* U+87F7 */ - {0xe5ba, 0x00e8a08e}, /* U+880E */ - {0xe5bb, 0x00e89f92}, /* U+87D2 */ - {0xe5bc, 0x00e8a091}, /* U+8811 */ - {0xe5bd, 0x00e8a096}, /* U+8816 */ - {0xe5be, 0x00e8a095}, /* U+8815 */ - {0xe5bf, 0x00e8a0a2}, /* U+8822 */ - {0xe5c0, 0x00e8a0a1}, /* U+8821 */ - {0xe5c1, 0x00e8a0b1}, /* U+8831 */ - {0xe5c2, 0x00e8a0b6}, /* U+8836 */ - {0xe5c3, 0x00e8a0b9}, /* U+8839 */ - {0xe5c4, 0x00e8a0a7}, /* U+8827 */ - {0xe5c5, 0x00e8a0bb}, /* U+883B */ - {0xe5c6, 0x00e8a184}, /* U+8844 */ - {0xe5c7, 0x00e8a182}, /* U+8842 */ - {0xe5c8, 0x00e8a192}, /* U+8852 */ - {0xe5c9, 0x00e8a199}, /* U+8859 */ - {0xe5ca, 0x00e8a19e}, /* U+885E */ - {0xe5cb, 0x00e8a1a2}, /* U+8862 */ - {0xe5cc, 0x00e8a1ab}, /* U+886B */ - {0xe5cd, 0x00e8a281}, /* U+8881 */ - {0xe5ce, 0x00e8a1be}, /* U+887E */ - {0xe5cf, 0x00e8a29e}, /* U+889E */ - {0xe5d0, 0x00e8a1b5}, /* U+8875 */ - {0xe5d1, 0x00e8a1bd}, /* U+887D */ - {0xe5d2, 0x00e8a2b5}, /* U+88B5 */ - {0xe5d3, 0x00e8a1b2}, /* U+8872 */ - {0xe5d4, 0x00e8a282}, /* U+8882 */ - {0xe5d5, 0x00e8a297}, /* U+8897 */ - {0xe5d6, 0x00e8a292}, /* U+8892 */ - {0xe5d7, 0x00e8a2ae}, /* U+88AE */ - {0xe5d8, 0x00e8a299}, /* U+8899 */ - {0xe5d9, 0x00e8a2a2}, /* U+88A2 */ - {0xe5da, 0x00e8a28d}, /* U+888D */ - {0xe5db, 0x00e8a2a4}, /* U+88A4 */ - {0xe5dc, 0x00e8a2b0}, /* U+88B0 */ - {0xe5dd, 0x00e8a2bf}, /* U+88BF */ - {0xe5de, 0x00e8a2b1}, /* U+88B1 */ - {0xe5df, 0x00e8a383}, /* U+88C3 */ - {0xe5e0, 0x00e8a384}, /* U+88C4 */ - {0xe5e1, 0x00e8a394}, /* U+88D4 */ - {0xe5e2, 0x00e8a398}, /* U+88D8 */ - {0xe5e3, 0x00e8a399}, /* U+88D9 */ - {0xe5e4, 0x00e8a39d}, /* U+88DD */ - {0xe5e5, 0x00e8a3b9}, /* U+88F9 */ - {0xe5e6, 0x00e8a482}, /* U+8902 */ - {0xe5e7, 0x00e8a3bc}, /* U+88FC */ - {0xe5e8, 0x00e8a3b4}, /* U+88F4 */ - {0xe5e9, 0x00e8a3a8}, /* U+88E8 */ - {0xe5ea, 0x00e8a3b2}, /* U+88F2 */ - {0xe5eb, 0x00e8a484}, /* U+8904 */ - {0xe5ec, 0x00e8a48c}, /* U+890C */ - {0xe5ed, 0x00e8a48a}, /* U+890A */ - {0xe5ee, 0x00e8a493}, /* U+8913 */ - {0xe5ef, 0x00e8a583}, /* U+8943 */ - {0xe5f0, 0x00e8a49e}, /* U+891E */ - {0xe5f1, 0x00e8a4a5}, /* U+8925 */ - {0xe5f2, 0x00e8a4aa}, /* U+892A */ - {0xe5f3, 0x00e8a4ab}, /* U+892B */ - {0xe5f4, 0x00e8a581}, /* U+8941 */ - {0xe5f5, 0x00e8a584}, /* U+8944 */ - {0xe5f6, 0x00e8a4bb}, /* U+893B */ - {0xe5f7, 0x00e8a4b6}, /* U+8936 */ - {0xe5f8, 0x00e8a4b8}, /* U+8938 */ - {0xe5f9, 0x00e8a58c}, /* U+894C */ - {0xe5fa, 0x00e8a49d}, /* U+891D */ - {0xe5fb, 0x00e8a5a0}, /* U+8960 */ - {0xe5fc, 0x00e8a59e}, /* U+895E */ - {0xe640, 0x00e8a5a6}, /* U+8966 */ - {0xe641, 0x00e8a5a4}, /* U+8964 */ - {0xe642, 0x00e8a5ad}, /* U+896D */ - {0xe643, 0x00e8a5aa}, /* U+896A */ - {0xe644, 0x00e8a5af}, /* U+896F */ - {0xe645, 0x00e8a5b4}, /* U+8974 */ - {0xe646, 0x00e8a5b7}, /* U+8977 */ - {0xe647, 0x00e8a5be}, /* U+897E */ - {0xe648, 0x00e8a683}, /* U+8983 */ - {0xe649, 0x00e8a688}, /* U+8988 */ - {0xe64a, 0x00e8a68a}, /* U+898A */ - {0xe64b, 0x00e8a693}, /* U+8993 */ - {0xe64c, 0x00e8a698}, /* U+8998 */ - {0xe64d, 0x00e8a6a1}, /* U+89A1 */ - {0xe64e, 0x00e8a6a9}, /* U+89A9 */ - {0xe64f, 0x00e8a6a6}, /* U+89A6 */ - {0xe650, 0x00e8a6ac}, /* U+89AC */ - {0xe651, 0x00e8a6af}, /* U+89AF */ - {0xe652, 0x00e8a6b2}, /* U+89B2 */ - {0xe653, 0x00e8a6ba}, /* U+89BA */ - {0xe654, 0x00e8a6bd}, /* U+89BD */ - {0xe655, 0x00e8a6bf}, /* U+89BF */ - {0xe656, 0x00e8a780}, /* U+89C0 */ - {0xe657, 0x00e8a79a}, /* U+89DA */ - {0xe658, 0x00e8a79c}, /* U+89DC */ - {0xe659, 0x00e8a79d}, /* U+89DD */ - {0xe65a, 0x00e8a7a7}, /* U+89E7 */ - {0xe65b, 0x00e8a7b4}, /* U+89F4 */ - {0xe65c, 0x00e8a7b8}, /* U+89F8 */ - {0xe65d, 0x00e8a883}, /* U+8A03 */ - {0xe65e, 0x00e8a896}, /* U+8A16 */ - {0xe65f, 0x00e8a890}, /* U+8A10 */ - {0xe660, 0x00e8a88c}, /* U+8A0C */ - {0xe661, 0x00e8a89b}, /* U+8A1B */ - {0xe662, 0x00e8a89d}, /* U+8A1D */ - {0xe663, 0x00e8a8a5}, /* U+8A25 */ - {0xe664, 0x00e8a8b6}, /* U+8A36 */ - {0xe665, 0x00e8a981}, /* U+8A41 */ - {0xe666, 0x00e8a99b}, /* U+8A5B */ - {0xe667, 0x00e8a992}, /* U+8A52 */ - {0xe668, 0x00e8a986}, /* U+8A46 */ - {0xe669, 0x00e8a988}, /* U+8A48 */ - {0xe66a, 0x00e8a9bc}, /* U+8A7C */ - {0xe66b, 0x00e8a9ad}, /* U+8A6D */ - {0xe66c, 0x00e8a9ac}, /* U+8A6C */ - {0xe66d, 0x00e8a9a2}, /* U+8A62 */ - {0xe66e, 0x00e8aa85}, /* U+8A85 */ - {0xe66f, 0x00e8aa82}, /* U+8A82 */ - {0xe670, 0x00e8aa84}, /* U+8A84 */ - {0xe671, 0x00e8aaa8}, /* U+8AA8 */ - {0xe672, 0x00e8aaa1}, /* U+8AA1 */ - {0xe673, 0x00e8aa91}, /* U+8A91 */ - {0xe674, 0x00e8aaa5}, /* U+8AA5 */ - {0xe675, 0x00e8aaa6}, /* U+8AA6 */ - {0xe676, 0x00e8aa9a}, /* U+8A9A */ - {0xe677, 0x00e8aaa3}, /* U+8AA3 */ - {0xe678, 0x00e8ab84}, /* U+8AC4 */ - {0xe679, 0x00e8ab8d}, /* U+8ACD */ - {0xe67a, 0x00e8ab82}, /* U+8AC2 */ - {0xe67b, 0x00e8ab9a}, /* U+8ADA */ - {0xe67c, 0x00e8abab}, /* U+8AEB */ - {0xe67d, 0x00e8abb3}, /* U+8AF3 */ - {0xe67e, 0x00e8aba7}, /* U+8AE7 */ - {0xe680, 0x00e8aba4}, /* U+8AE4 */ - {0xe681, 0x00e8abb1}, /* U+8AF1 */ - {0xe682, 0x00e8ac94}, /* U+8B14 */ - {0xe683, 0x00e8aba0}, /* U+8AE0 */ - {0xe684, 0x00e8aba2}, /* U+8AE2 */ - {0xe685, 0x00e8abb7}, /* U+8AF7 */ - {0xe686, 0x00e8ab9e}, /* U+8ADE */ - {0xe687, 0x00e8ab9b}, /* U+8ADB */ - {0xe688, 0x00e8ac8c}, /* U+8B0C */ - {0xe689, 0x00e8ac87}, /* U+8B07 */ - {0xe68a, 0x00e8ac9a}, /* U+8B1A */ - {0xe68b, 0x00e8aba1}, /* U+8AE1 */ - {0xe68c, 0x00e8ac96}, /* U+8B16 */ - {0xe68d, 0x00e8ac90}, /* U+8B10 */ - {0xe68e, 0x00e8ac97}, /* U+8B17 */ - {0xe68f, 0x00e8aca0}, /* U+8B20 */ - {0xe690, 0x00e8acb3}, /* U+8B33 */ - {0xe691, 0x00e99eab}, /* U+97AB */ - {0xe692, 0x00e8aca6}, /* U+8B26 */ - {0xe693, 0x00e8acab}, /* U+8B2B */ - {0xe694, 0x00e8acbe}, /* U+8B3E */ - {0xe695, 0x00e8aca8}, /* U+8B28 */ - {0xe696, 0x00e8ad81}, /* U+8B41 */ - {0xe697, 0x00e8ad8c}, /* U+8B4C */ - {0xe698, 0x00e8ad8f}, /* U+8B4F */ - {0xe699, 0x00e8ad8e}, /* U+8B4E */ - {0xe69a, 0x00e8ad89}, /* U+8B49 */ - {0xe69b, 0x00e8ad96}, /* U+8B56 */ - {0xe69c, 0x00e8ad9b}, /* U+8B5B */ - {0xe69d, 0x00e8ad9a}, /* U+8B5A */ - {0xe69e, 0x00e8adab}, /* U+8B6B */ - {0xe69f, 0x00e8ad9f}, /* U+8B5F */ - {0xe6a0, 0x00e8adac}, /* U+8B6C */ - {0xe6a1, 0x00e8adaf}, /* U+8B6F */ - {0xe6a2, 0x00e8adb4}, /* U+8B74 */ - {0xe6a3, 0x00e8adbd}, /* U+8B7D */ - {0xe6a4, 0x00e8ae80}, /* U+8B80 */ - {0xe6a5, 0x00e8ae8c}, /* U+8B8C */ - {0xe6a6, 0x00e8ae8e}, /* U+8B8E */ - {0xe6a7, 0x00e8ae92}, /* U+8B92 */ - {0xe6a8, 0x00e8ae93}, /* U+8B93 */ - {0xe6a9, 0x00e8ae96}, /* U+8B96 */ - {0xe6aa, 0x00e8ae99}, /* U+8B99 */ - {0xe6ab, 0x00e8ae9a}, /* U+8B9A */ - {0xe6ac, 0x00e8b0ba}, /* U+8C3A */ - {0xe6ad, 0x00e8b181}, /* U+8C41 */ - {0xe6ae, 0x00e8b0bf}, /* U+8C3F */ - {0xe6af, 0x00e8b188}, /* U+8C48 */ - {0xe6b0, 0x00e8b18c}, /* U+8C4C */ - {0xe6b1, 0x00e8b18e}, /* U+8C4E */ - {0xe6b2, 0x00e8b190}, /* U+8C50 */ - {0xe6b3, 0x00e8b195}, /* U+8C55 */ - {0xe6b4, 0x00e8b1a2}, /* U+8C62 */ - {0xe6b5, 0x00e8b1ac}, /* U+8C6C */ - {0xe6b6, 0x00e8b1b8}, /* U+8C78 */ - {0xe6b7, 0x00e8b1ba}, /* U+8C7A */ - {0xe6b8, 0x00e8b282}, /* U+8C82 */ - {0xe6b9, 0x00e8b289}, /* U+8C89 */ - {0xe6ba, 0x00e8b285}, /* U+8C85 */ - {0xe6bb, 0x00e8b28a}, /* U+8C8A */ - {0xe6bc, 0x00e8b28d}, /* U+8C8D */ - {0xe6bd, 0x00e8b28e}, /* U+8C8E */ - {0xe6be, 0x00e8b294}, /* U+8C94 */ - {0xe6bf, 0x00e8b1bc}, /* U+8C7C */ - {0xe6c0, 0x00e8b298}, /* U+8C98 */ - {0xe6c1, 0x00e6889d}, /* U+621D */ - {0xe6c2, 0x00e8b2ad}, /* U+8CAD */ - {0xe6c3, 0x00e8b2aa}, /* U+8CAA */ - {0xe6c4, 0x00e8b2bd}, /* U+8CBD */ - {0xe6c5, 0x00e8b2b2}, /* U+8CB2 */ - {0xe6c6, 0x00e8b2b3}, /* U+8CB3 */ - {0xe6c7, 0x00e8b2ae}, /* U+8CAE */ - {0xe6c8, 0x00e8b2b6}, /* U+8CB6 */ - {0xe6c9, 0x00e8b388}, /* U+8CC8 */ - {0xe6ca, 0x00e8b381}, /* U+8CC1 */ - {0xe6cb, 0x00e8b3a4}, /* U+8CE4 */ - {0xe6cc, 0x00e8b3a3}, /* U+8CE3 */ - {0xe6cd, 0x00e8b39a}, /* U+8CDA */ - {0xe6ce, 0x00e8b3bd}, /* U+8CFD */ - {0xe6cf, 0x00e8b3ba}, /* U+8CFA */ - {0xe6d0, 0x00e8b3bb}, /* U+8CFB */ - {0xe6d1, 0x00e8b484}, /* U+8D04 */ - {0xe6d2, 0x00e8b485}, /* U+8D05 */ - {0xe6d3, 0x00e8b48a}, /* U+8D0A */ - {0xe6d4, 0x00e8b487}, /* U+8D07 */ - {0xe6d5, 0x00e8b48f}, /* U+8D0F */ - {0xe6d6, 0x00e8b48d}, /* U+8D0D */ - {0xe6d7, 0x00e8b490}, /* U+8D10 */ - {0xe6d8, 0x00e9bd8e}, /* U+9F4E */ - {0xe6d9, 0x00e8b493}, /* U+8D13 */ - {0xe6da, 0x00e8b38d}, /* U+8CCD */ - {0xe6db, 0x00e8b494}, /* U+8D14 */ - {0xe6dc, 0x00e8b496}, /* U+8D16 */ - {0xe6dd, 0x00e8b5a7}, /* U+8D67 */ - {0xe6de, 0x00e8b5ad}, /* U+8D6D */ - {0xe6df, 0x00e8b5b1}, /* U+8D71 */ - {0xe6e0, 0x00e8b5b3}, /* U+8D73 */ - {0xe6e1, 0x00e8b681}, /* U+8D81 */ - {0xe6e2, 0x00e8b699}, /* U+8D99 */ - {0xe6e3, 0x00e8b782}, /* U+8DC2 */ - {0xe6e4, 0x00e8b6be}, /* U+8DBE */ - {0xe6e5, 0x00e8b6ba}, /* U+8DBA */ - {0xe6e6, 0x00e8b78f}, /* U+8DCF */ - {0xe6e7, 0x00e8b79a}, /* U+8DDA */ - {0xe6e8, 0x00e8b796}, /* U+8DD6 */ - {0xe6e9, 0x00e8b78c}, /* U+8DCC */ - {0xe6ea, 0x00e8b79b}, /* U+8DDB */ - {0xe6eb, 0x00e8b78b}, /* U+8DCB */ - {0xe6ec, 0x00e8b7aa}, /* U+8DEA */ - {0xe6ed, 0x00e8b7ab}, /* U+8DEB */ - {0xe6ee, 0x00e8b79f}, /* U+8DDF */ - {0xe6ef, 0x00e8b7a3}, /* U+8DE3 */ - {0xe6f0, 0x00e8b7bc}, /* U+8DFC */ - {0xe6f1, 0x00e8b888}, /* U+8E08 */ - {0xe6f2, 0x00e8b889}, /* U+8E09 */ - {0xe6f3, 0x00e8b7bf}, /* U+8DFF */ - {0xe6f4, 0x00e8b89d}, /* U+8E1D */ - {0xe6f5, 0x00e8b89e}, /* U+8E1E */ - {0xe6f6, 0x00e8b890}, /* U+8E10 */ - {0xe6f7, 0x00e8b89f}, /* U+8E1F */ - {0xe6f8, 0x00e8b982}, /* U+8E42 */ - {0xe6f9, 0x00e8b8b5}, /* U+8E35 */ - {0xe6fa, 0x00e8b8b0}, /* U+8E30 */ - {0xe6fb, 0x00e8b8b4}, /* U+8E34 */ - {0xe6fc, 0x00e8b98a}, /* U+8E4A */ - {0xe740, 0x00e8b987}, /* U+8E47 */ - {0xe741, 0x00e8b989}, /* U+8E49 */ - {0xe742, 0x00e8b98c}, /* U+8E4C */ - {0xe743, 0x00e8b990}, /* U+8E50 */ - {0xe744, 0x00e8b988}, /* U+8E48 */ - {0xe745, 0x00e8b999}, /* U+8E59 */ - {0xe746, 0x00e8b9a4}, /* U+8E64 */ - {0xe747, 0x00e8b9a0}, /* U+8E60 */ - {0xe748, 0x00e8b8aa}, /* U+8E2A */ - {0xe749, 0x00e8b9a3}, /* U+8E63 */ - {0xe74a, 0x00e8b995}, /* U+8E55 */ - {0xe74b, 0x00e8b9b6}, /* U+8E76 */ - {0xe74c, 0x00e8b9b2}, /* U+8E72 */ - {0xe74d, 0x00e8b9bc}, /* U+8E7C */ - {0xe74e, 0x00e8ba81}, /* U+8E81 */ - {0xe74f, 0x00e8ba87}, /* U+8E87 */ - {0xe750, 0x00e8ba85}, /* U+8E85 */ - {0xe751, 0x00e8ba84}, /* U+8E84 */ - {0xe752, 0x00e8ba8b}, /* U+8E8B */ - {0xe753, 0x00e8ba8a}, /* U+8E8A */ - {0xe754, 0x00e8ba93}, /* U+8E93 */ - {0xe755, 0x00e8ba91}, /* U+8E91 */ - {0xe756, 0x00e8ba94}, /* U+8E94 */ - {0xe757, 0x00e8ba99}, /* U+8E99 */ - {0xe758, 0x00e8baaa}, /* U+8EAA */ - {0xe759, 0x00e8baa1}, /* U+8EA1 */ - {0xe75a, 0x00e8baac}, /* U+8EAC */ - {0xe75b, 0x00e8bab0}, /* U+8EB0 */ - {0xe75c, 0x00e8bb86}, /* U+8EC6 */ - {0xe75d, 0x00e8bab1}, /* U+8EB1 */ - {0xe75e, 0x00e8babe}, /* U+8EBE */ - {0xe75f, 0x00e8bb85}, /* U+8EC5 */ - {0xe760, 0x00e8bb88}, /* U+8EC8 */ - {0xe761, 0x00e8bb8b}, /* U+8ECB */ - {0xe762, 0x00e8bb9b}, /* U+8EDB */ - {0xe763, 0x00e8bba3}, /* U+8EE3 */ - {0xe764, 0x00e8bbbc}, /* U+8EFC */ - {0xe765, 0x00e8bbbb}, /* U+8EFB */ - {0xe766, 0x00e8bbab}, /* U+8EEB */ - {0xe767, 0x00e8bbbe}, /* U+8EFE */ - {0xe768, 0x00e8bc8a}, /* U+8F0A */ - {0xe769, 0x00e8bc85}, /* U+8F05 */ - {0xe76a, 0x00e8bc95}, /* U+8F15 */ - {0xe76b, 0x00e8bc92}, /* U+8F12 */ - {0xe76c, 0x00e8bc99}, /* U+8F19 */ - {0xe76d, 0x00e8bc93}, /* U+8F13 */ - {0xe76e, 0x00e8bc9c}, /* U+8F1C */ - {0xe76f, 0x00e8bc9f}, /* U+8F1F */ - {0xe770, 0x00e8bc9b}, /* U+8F1B */ - {0xe771, 0x00e8bc8c}, /* U+8F0C */ - {0xe772, 0x00e8bca6}, /* U+8F26 */ - {0xe773, 0x00e8bcb3}, /* U+8F33 */ - {0xe774, 0x00e8bcbb}, /* U+8F3B */ - {0xe775, 0x00e8bcb9}, /* U+8F39 */ - {0xe776, 0x00e8bd85}, /* U+8F45 */ - {0xe777, 0x00e8bd82}, /* U+8F42 */ - {0xe778, 0x00e8bcbe}, /* U+8F3E */ - {0xe779, 0x00e8bd8c}, /* U+8F4C */ - {0xe77a, 0x00e8bd89}, /* U+8F49 */ - {0xe77b, 0x00e8bd86}, /* U+8F46 */ - {0xe77c, 0x00e8bd8e}, /* U+8F4E */ - {0xe77d, 0x00e8bd97}, /* U+8F57 */ - {0xe77e, 0x00e8bd9c}, /* U+8F5C */ - {0xe780, 0x00e8bda2}, /* U+8F62 */ - {0xe781, 0x00e8bda3}, /* U+8F63 */ - {0xe782, 0x00e8bda4}, /* U+8F64 */ - {0xe783, 0x00e8be9c}, /* U+8F9C */ - {0xe784, 0x00e8be9f}, /* U+8F9F */ - {0xe785, 0x00e8bea3}, /* U+8FA3 */ - {0xe786, 0x00e8bead}, /* U+8FAD */ - {0xe787, 0x00e8beaf}, /* U+8FAF */ - {0xe788, 0x00e8beb7}, /* U+8FB7 */ - {0xe789, 0x00e8bf9a}, /* U+8FDA */ - {0xe78a, 0x00e8bfa5}, /* U+8FE5 */ - {0xe78b, 0x00e8bfa2}, /* U+8FE2 */ - {0xe78c, 0x00e8bfaa}, /* U+8FEA */ - {0xe78d, 0x00e8bfaf}, /* U+8FEF */ - {0xe78e, 0x00e98287}, /* U+9087 */ - {0xe78f, 0x00e8bfb4}, /* U+8FF4 */ - {0xe790, 0x00e98085}, /* U+9005 */ - {0xe791, 0x00e8bfb9}, /* U+8FF9 */ - {0xe792, 0x00e8bfba}, /* U+8FFA */ - {0xe793, 0x00e98091}, /* U+9011 */ - {0xe794, 0x00e98095}, /* U+9015 */ - {0xe795, 0x00e980a1}, /* U+9021 */ - {0xe796, 0x00e9808d}, /* U+900D */ - {0xe797, 0x00e9809e}, /* U+901E */ - {0xe798, 0x00e98096}, /* U+9016 */ - {0xe799, 0x00e9808b}, /* U+900B */ - {0xe79a, 0x00e980a7}, /* U+9027 */ - {0xe79b, 0x00e980b6}, /* U+9036 */ - {0xe79c, 0x00e980b5}, /* U+9035 */ - {0xe79d, 0x00e980b9}, /* U+9039 */ - {0xe79e, 0x00e8bfb8}, /* U+8FF8 */ - {0xe79f, 0x00e9818f}, /* U+904F */ - {0xe7a0, 0x00e98190}, /* U+9050 */ - {0xe7a1, 0x00e98191}, /* U+9051 */ - {0xe7a2, 0x00e98192}, /* U+9052 */ - {0xe7a3, 0x00e9808e}, /* U+900E */ - {0xe7a4, 0x00e98189}, /* U+9049 */ - {0xe7a5, 0x00e980be}, /* U+903E */ - {0xe7a6, 0x00e98196}, /* U+9056 */ - {0xe7a7, 0x00e98198}, /* U+9058 */ - {0xe7a8, 0x00e9819e}, /* U+905E */ - {0xe7a9, 0x00e981a8}, /* U+9068 */ - {0xe7aa, 0x00e981af}, /* U+906F */ - {0xe7ab, 0x00e981b6}, /* U+9076 */ - {0xe7ac, 0x00e99aa8}, /* U+96A8 */ - {0xe7ad, 0x00e981b2}, /* U+9072 */ - {0xe7ae, 0x00e98282}, /* U+9082 */ - {0xe7af, 0x00e981bd}, /* U+907D */ - {0xe7b0, 0x00e98281}, /* U+9081 */ - {0xe7b1, 0x00e98280}, /* U+9080 */ - {0xe7b2, 0x00e9828a}, /* U+908A */ - {0xe7b3, 0x00e98289}, /* U+9089 */ - {0xe7b4, 0x00e9828f}, /* U+908F */ - {0xe7b5, 0x00e982a8}, /* U+90A8 */ - {0xe7b6, 0x00e982af}, /* U+90AF */ - {0xe7b7, 0x00e982b1}, /* U+90B1 */ - {0xe7b8, 0x00e982b5}, /* U+90B5 */ - {0xe7b9, 0x00e983a2}, /* U+90E2 */ - {0xe7ba, 0x00e983a4}, /* U+90E4 */ - {0xe7bb, 0x00e68988}, /* U+6248 */ - {0xe7bc, 0x00e9839b}, /* U+90DB */ - {0xe7bd, 0x00e98482}, /* U+9102 */ - {0xe7be, 0x00e98492}, /* U+9112 */ - {0xe7bf, 0x00e98499}, /* U+9119 */ - {0xe7c0, 0x00e984b2}, /* U+9132 */ - {0xe7c1, 0x00e984b0}, /* U+9130 */ - {0xe7c2, 0x00e9858a}, /* U+914A */ - {0xe7c3, 0x00e98596}, /* U+9156 */ - {0xe7c4, 0x00e98598}, /* U+9158 */ - {0xe7c5, 0x00e985a3}, /* U+9163 */ - {0xe7c6, 0x00e985a5}, /* U+9165 */ - {0xe7c7, 0x00e985a9}, /* U+9169 */ - {0xe7c8, 0x00e985b3}, /* U+9173 */ - {0xe7c9, 0x00e985b2}, /* U+9172 */ - {0xe7ca, 0x00e9868b}, /* U+918B */ - {0xe7cb, 0x00e98689}, /* U+9189 */ - {0xe7cc, 0x00e98682}, /* U+9182 */ - {0xe7cd, 0x00e986a2}, /* U+91A2 */ - {0xe7ce, 0x00e986ab}, /* U+91AB */ - {0xe7cf, 0x00e986af}, /* U+91AF */ - {0xe7d0, 0x00e986aa}, /* U+91AA */ - {0xe7d1, 0x00e986b5}, /* U+91B5 */ - {0xe7d2, 0x00e986b4}, /* U+91B4 */ - {0xe7d3, 0x00e986ba}, /* U+91BA */ - {0xe7d4, 0x00e98780}, /* U+91C0 */ - {0xe7d5, 0x00e98781}, /* U+91C1 */ - {0xe7d6, 0x00e98789}, /* U+91C9 */ - {0xe7d7, 0x00e9878b}, /* U+91CB */ - {0xe7d8, 0x00e98790}, /* U+91D0 */ - {0xe7d9, 0x00e98796}, /* U+91D6 */ - {0xe7da, 0x00e9879f}, /* U+91DF */ - {0xe7db, 0x00e987a1}, /* U+91E1 */ - {0xe7dc, 0x00e9879b}, /* U+91DB */ - {0xe7dd, 0x00e987bc}, /* U+91FC */ - {0xe7de, 0x00e987b5}, /* U+91F5 */ - {0xe7df, 0x00e987b6}, /* U+91F6 */ - {0xe7e0, 0x00e9889e}, /* U+921E */ - {0xe7e1, 0x00e987bf}, /* U+91FF */ - {0xe7e2, 0x00e98894}, /* U+9214 */ - {0xe7e3, 0x00e988ac}, /* U+922C */ - {0xe7e4, 0x00e98895}, /* U+9215 */ - {0xe7e5, 0x00e98891}, /* U+9211 */ - {0xe7e6, 0x00e9899e}, /* U+925E */ - {0xe7e7, 0x00e98997}, /* U+9257 */ - {0xe7e8, 0x00e98985}, /* U+9245 */ - {0xe7e9, 0x00e98989}, /* U+9249 */ - {0xe7ea, 0x00e989a4}, /* U+9264 */ - {0xe7eb, 0x00e98988}, /* U+9248 */ - {0xe7ec, 0x00e98a95}, /* U+9295 */ - {0xe7ed, 0x00e988bf}, /* U+923F */ - {0xe7ee, 0x00e9898b}, /* U+924B */ - {0xe7ef, 0x00e98990}, /* U+9250 */ - {0xe7f0, 0x00e98a9c}, /* U+929C */ - {0xe7f1, 0x00e98a96}, /* U+9296 */ - {0xe7f2, 0x00e98a93}, /* U+9293 */ - {0xe7f3, 0x00e98a9b}, /* U+929B */ - {0xe7f4, 0x00e9899a}, /* U+925A */ - {0xe7f5, 0x00e98b8f}, /* U+92CF */ - {0xe7f6, 0x00e98ab9}, /* U+92B9 */ - {0xe7f7, 0x00e98ab7}, /* U+92B7 */ - {0xe7f8, 0x00e98ba9}, /* U+92E9 */ - {0xe7f9, 0x00e98c8f}, /* U+930F */ - {0xe7fa, 0x00e98bba}, /* U+92FA */ - {0xe7fb, 0x00e98d84}, /* U+9344 */ - {0xe7fc, 0x00e98cae}, /* U+932E */ - {0xe840, 0x00e98c99}, /* U+9319 */ - {0xe841, 0x00e98ca2}, /* U+9322 */ - {0xe842, 0x00e98c9a}, /* U+931A */ - {0xe843, 0x00e98ca3}, /* U+9323 */ - {0xe844, 0x00e98cba}, /* U+933A */ - {0xe845, 0x00e98cb5}, /* U+9335 */ - {0xe846, 0x00e98cbb}, /* U+933B */ - {0xe847, 0x00e98d9c}, /* U+935C */ - {0xe848, 0x00e98da0}, /* U+9360 */ - {0xe849, 0x00e98dbc}, /* U+937C */ - {0xe84a, 0x00e98dae}, /* U+936E */ - {0xe84b, 0x00e98d96}, /* U+9356 */ - {0xe84c, 0x00e98eb0}, /* U+93B0 */ - {0xe84d, 0x00e98eac}, /* U+93AC */ - {0xe84e, 0x00e98ead}, /* U+93AD */ - {0xe84f, 0x00e98e94}, /* U+9394 */ - {0xe850, 0x00e98eb9}, /* U+93B9 */ - {0xe851, 0x00e98f96}, /* U+93D6 */ - {0xe852, 0x00e98f97}, /* U+93D7 */ - {0xe853, 0x00e98fa8}, /* U+93E8 */ - {0xe854, 0x00e98fa5}, /* U+93E5 */ - {0xe855, 0x00e98f98}, /* U+93D8 */ - {0xe856, 0x00e98f83}, /* U+93C3 */ - {0xe857, 0x00e98f9d}, /* U+93DD */ - {0xe858, 0x00e98f90}, /* U+93D0 */ - {0xe859, 0x00e98f88}, /* U+93C8 */ - {0xe85a, 0x00e98fa4}, /* U+93E4 */ - {0xe85b, 0x00e9909a}, /* U+941A */ - {0xe85c, 0x00e99094}, /* U+9414 */ - {0xe85d, 0x00e99093}, /* U+9413 */ - {0xe85e, 0x00e99083}, /* U+9403 */ - {0xe85f, 0x00e99087}, /* U+9407 */ - {0xe860, 0x00e99090}, /* U+9410 */ - {0xe861, 0x00e990b6}, /* U+9436 */ - {0xe862, 0x00e990ab}, /* U+942B */ - {0xe863, 0x00e990b5}, /* U+9435 */ - {0xe864, 0x00e990a1}, /* U+9421 */ - {0xe865, 0x00e990ba}, /* U+943A */ - {0xe866, 0x00e99181}, /* U+9441 */ - {0xe867, 0x00e99192}, /* U+9452 */ - {0xe868, 0x00e99184}, /* U+9444 */ - {0xe869, 0x00e9919b}, /* U+945B */ - {0xe86a, 0x00e991a0}, /* U+9460 */ - {0xe86b, 0x00e991a2}, /* U+9462 */ - {0xe86c, 0x00e9919e}, /* U+945E */ - {0xe86d, 0x00e991aa}, /* U+946A */ - {0xe86e, 0x00e988a9}, /* U+9229 */ - {0xe86f, 0x00e991b0}, /* U+9470 */ - {0xe870, 0x00e991b5}, /* U+9475 */ - {0xe871, 0x00e991b7}, /* U+9477 */ - {0xe872, 0x00e991bd}, /* U+947D */ - {0xe873, 0x00e9919a}, /* U+945A */ - {0xe874, 0x00e991bc}, /* U+947C */ - {0xe875, 0x00e991be}, /* U+947E */ - {0xe876, 0x00e99281}, /* U+9481 */ - {0xe877, 0x00e991bf}, /* U+947F */ - {0xe878, 0x00e99682}, /* U+9582 */ - {0xe879, 0x00e99687}, /* U+9587 */ - {0xe87a, 0x00e9968a}, /* U+958A */ - {0xe87b, 0x00e99694}, /* U+9594 */ - {0xe87c, 0x00e99696}, /* U+9596 */ - {0xe87d, 0x00e99698}, /* U+9598 */ - {0xe87e, 0x00e99699}, /* U+9599 */ - {0xe880, 0x00e996a0}, /* U+95A0 */ - {0xe881, 0x00e996a8}, /* U+95A8 */ - {0xe882, 0x00e996a7}, /* U+95A7 */ - {0xe883, 0x00e996ad}, /* U+95AD */ - {0xe884, 0x00e996bc}, /* U+95BC */ - {0xe885, 0x00e996bb}, /* U+95BB */ - {0xe886, 0x00e996b9}, /* U+95B9 */ - {0xe887, 0x00e996be}, /* U+95BE */ - {0xe888, 0x00e9978a}, /* U+95CA */ - {0xe889, 0x00e6bfb6}, /* U+6FF6 */ - {0xe88a, 0x00e99783}, /* U+95C3 */ - {0xe88b, 0x00e9978d}, /* U+95CD */ - {0xe88c, 0x00e9978c}, /* U+95CC */ - {0xe88d, 0x00e99795}, /* U+95D5 */ - {0xe88e, 0x00e99794}, /* U+95D4 */ - {0xe88f, 0x00e99796}, /* U+95D6 */ - {0xe890, 0x00e9979c}, /* U+95DC */ - {0xe891, 0x00e997a1}, /* U+95E1 */ - {0xe892, 0x00e997a5}, /* U+95E5 */ - {0xe893, 0x00e997a2}, /* U+95E2 */ - {0xe894, 0x00e998a1}, /* U+9621 */ - {0xe895, 0x00e998a8}, /* U+9628 */ - {0xe896, 0x00e998ae}, /* U+962E */ - {0xe897, 0x00e998af}, /* U+962F */ - {0xe898, 0x00e99982}, /* U+9642 */ - {0xe899, 0x00e9998c}, /* U+964C */ - {0xe89a, 0x00e9998f}, /* U+964F */ - {0xe89b, 0x00e9998b}, /* U+964B */ - {0xe89c, 0x00e999b7}, /* U+9677 */ - {0xe89d, 0x00e9999c}, /* U+965C */ - {0xe89e, 0x00e9999e}, /* U+965E */ - {0xe89f, 0x00e9999d}, /* U+965D */ - {0xe8a0, 0x00e9999f}, /* U+965F */ - {0xe8a1, 0x00e999a6}, /* U+9666 */ - {0xe8a2, 0x00e999b2}, /* U+9672 */ - {0xe8a3, 0x00e999ac}, /* U+966C */ - {0xe8a4, 0x00e99a8d}, /* U+968D */ - {0xe8a5, 0x00e99a98}, /* U+9698 */ - {0xe8a6, 0x00e99a95}, /* U+9695 */ - {0xe8a7, 0x00e99a97}, /* U+9697 */ - {0xe8a8, 0x00e99aaa}, /* U+96AA */ - {0xe8a9, 0x00e99aa7}, /* U+96A7 */ - {0xe8aa, 0x00e99ab1}, /* U+96B1 */ - {0xe8ab, 0x00e99ab2}, /* U+96B2 */ - {0xe8ac, 0x00e99ab0}, /* U+96B0 */ - {0xe8ad, 0x00e99ab4}, /* U+96B4 */ - {0xe8ae, 0x00e99ab6}, /* U+96B6 */ - {0xe8af, 0x00e99ab8}, /* U+96B8 */ - {0xe8b0, 0x00e99ab9}, /* U+96B9 */ - {0xe8b1, 0x00e99b8e}, /* U+96CE */ - {0xe8b2, 0x00e99b8b}, /* U+96CB */ - {0xe8b3, 0x00e99b89}, /* U+96C9 */ - {0xe8b4, 0x00e99b8d}, /* U+96CD */ - {0xe8b5, 0x00e8a58d}, /* U+894D */ - {0xe8b6, 0x00e99b9c}, /* U+96DC */ - {0xe8b7, 0x00e99c8d}, /* U+970D */ - {0xe8b8, 0x00e99b95}, /* U+96D5 */ - {0xe8b9, 0x00e99bb9}, /* U+96F9 */ - {0xe8ba, 0x00e99c84}, /* U+9704 */ - {0xe8bb, 0x00e99c86}, /* U+9706 */ - {0xe8bc, 0x00e99c88}, /* U+9708 */ - {0xe8bd, 0x00e99c93}, /* U+9713 */ - {0xe8be, 0x00e99c8e}, /* U+970E */ - {0xe8bf, 0x00e99c91}, /* U+9711 */ - {0xe8c0, 0x00e99c8f}, /* U+970F */ - {0xe8c1, 0x00e99c96}, /* U+9716 */ - {0xe8c2, 0x00e99c99}, /* U+9719 */ - {0xe8c3, 0x00e99ca4}, /* U+9724 */ - {0xe8c4, 0x00e99caa}, /* U+972A */ - {0xe8c5, 0x00e99cb0}, /* U+9730 */ - {0xe8c6, 0x00e99cb9}, /* U+9739 */ - {0xe8c7, 0x00e99cbd}, /* U+973D */ - {0xe8c8, 0x00e99cbe}, /* U+973E */ - {0xe8c9, 0x00e99d84}, /* U+9744 */ - {0xe8ca, 0x00e99d86}, /* U+9746 */ - {0xe8cb, 0x00e99d88}, /* U+9748 */ - {0xe8cc, 0x00e99d82}, /* U+9742 */ - {0xe8cd, 0x00e99d89}, /* U+9749 */ - {0xe8ce, 0x00e99d9c}, /* U+975C */ - {0xe8cf, 0x00e99da0}, /* U+9760 */ - {0xe8d0, 0x00e99da4}, /* U+9764 */ - {0xe8d1, 0x00e99da6}, /* U+9766 */ - {0xe8d2, 0x00e99da8}, /* U+9768 */ - {0xe8d3, 0x00e58b92}, /* U+52D2 */ - {0xe8d4, 0x00e99dab}, /* U+976B */ - {0xe8d5, 0x00e99db1}, /* U+9771 */ - {0xe8d6, 0x00e99db9}, /* U+9779 */ - {0xe8d7, 0x00e99e85}, /* U+9785 */ - {0xe8d8, 0x00e99dbc}, /* U+977C */ - {0xe8d9, 0x00e99e81}, /* U+9781 */ - {0xe8da, 0x00e99dba}, /* U+977A */ - {0xe8db, 0x00e99e86}, /* U+9786 */ - {0xe8dc, 0x00e99e8b}, /* U+978B */ - {0xe8dd, 0x00e99e8f}, /* U+978F */ - {0xe8de, 0x00e99e90}, /* U+9790 */ - {0xe8df, 0x00e99e9c}, /* U+979C */ - {0xe8e0, 0x00e99ea8}, /* U+97A8 */ - {0xe8e1, 0x00e99ea6}, /* U+97A6 */ - {0xe8e2, 0x00e99ea3}, /* U+97A3 */ - {0xe8e3, 0x00e99eb3}, /* U+97B3 */ - {0xe8e4, 0x00e99eb4}, /* U+97B4 */ - {0xe8e5, 0x00e99f83}, /* U+97C3 */ - {0xe8e6, 0x00e99f86}, /* U+97C6 */ - {0xe8e7, 0x00e99f88}, /* U+97C8 */ - {0xe8e8, 0x00e99f8b}, /* U+97CB */ - {0xe8e9, 0x00e99f9c}, /* U+97DC */ - {0xe8ea, 0x00e99fad}, /* U+97ED */ - {0xe8eb, 0x00e9bd8f}, /* U+9F4F */ - {0xe8ec, 0x00e99fb2}, /* U+97F2 */ - {0xe8ed, 0x00e7ab9f}, /* U+7ADF */ - {0xe8ee, 0x00e99fb6}, /* U+97F6 */ - {0xe8ef, 0x00e99fb5}, /* U+97F5 */ - {0xe8f0, 0x00e9a08f}, /* U+980F */ - {0xe8f1, 0x00e9a08c}, /* U+980C */ - {0xe8f2, 0x00e9a0b8}, /* U+9838 */ - {0xe8f3, 0x00e9a0a4}, /* U+9824 */ - {0xe8f4, 0x00e9a0a1}, /* U+9821 */ - {0xe8f5, 0x00e9a0b7}, /* U+9837 */ - {0xe8f6, 0x00e9a0bd}, /* U+983D */ - {0xe8f7, 0x00e9a186}, /* U+9846 */ - {0xe8f8, 0x00e9a18f}, /* U+984F */ - {0xe8f9, 0x00e9a18b}, /* U+984B */ - {0xe8fa, 0x00e9a1ab}, /* U+986B */ - {0xe8fb, 0x00e9a1af}, /* U+986F */ - {0xe8fc, 0x00e9a1b0}, /* U+9870 */ - {0xe940, 0x00e9a1b1}, /* U+9871 */ - {0xe941, 0x00e9a1b4}, /* U+9874 */ - {0xe942, 0x00e9a1b3}, /* U+9873 */ - {0xe943, 0x00e9a2aa}, /* U+98AA */ - {0xe944, 0x00e9a2af}, /* U+98AF */ - {0xe945, 0x00e9a2b1}, /* U+98B1 */ - {0xe946, 0x00e9a2b6}, /* U+98B6 */ - {0xe947, 0x00e9a384}, /* U+98C4 */ - {0xe948, 0x00e9a383}, /* U+98C3 */ - {0xe949, 0x00e9a386}, /* U+98C6 */ - {0xe94a, 0x00e9a3a9}, /* U+98E9 */ - {0xe94b, 0x00e9a3ab}, /* U+98EB */ - {0xe94c, 0x00e9a483}, /* U+9903 */ - {0xe94d, 0x00e9a489}, /* U+9909 */ - {0xe94e, 0x00e9a492}, /* U+9912 */ - {0xe94f, 0x00e9a494}, /* U+9914 */ - {0xe950, 0x00e9a498}, /* U+9918 */ - {0xe951, 0x00e9a4a1}, /* U+9921 */ - {0xe952, 0x00e9a49d}, /* U+991D */ - {0xe953, 0x00e9a49e}, /* U+991E */ - {0xe954, 0x00e9a4a4}, /* U+9924 */ - {0xe955, 0x00e9a4a0}, /* U+9920 */ - {0xe956, 0x00e9a4ac}, /* U+992C */ - {0xe957, 0x00e9a4ae}, /* U+992E */ - {0xe958, 0x00e9a4bd}, /* U+993D */ - {0xe959, 0x00e9a4be}, /* U+993E */ - {0xe95a, 0x00e9a582}, /* U+9942 */ - {0xe95b, 0x00e9a589}, /* U+9949 */ - {0xe95c, 0x00e9a585}, /* U+9945 */ - {0xe95d, 0x00e9a590}, /* U+9950 */ - {0xe95e, 0x00e9a58b}, /* U+994B */ - {0xe95f, 0x00e9a591}, /* U+9951 */ - {0xe960, 0x00e9a592}, /* U+9952 */ - {0xe961, 0x00e9a58c}, /* U+994C */ - {0xe962, 0x00e9a595}, /* U+9955 */ - {0xe963, 0x00e9a697}, /* U+9997 */ - {0xe964, 0x00e9a698}, /* U+9998 */ - {0xe965, 0x00e9a6a5}, /* U+99A5 */ - {0xe966, 0x00e9a6ad}, /* U+99AD */ - {0xe967, 0x00e9a6ae}, /* U+99AE */ - {0xe968, 0x00e9a6bc}, /* U+99BC */ - {0xe969, 0x00e9a79f}, /* U+99DF */ - {0xe96a, 0x00e9a79b}, /* U+99DB */ - {0xe96b, 0x00e9a79d}, /* U+99DD */ - {0xe96c, 0x00e9a798}, /* U+99D8 */ - {0xe96d, 0x00e9a791}, /* U+99D1 */ - {0xe96e, 0x00e9a7ad}, /* U+99ED */ - {0xe96f, 0x00e9a7ae}, /* U+99EE */ - {0xe970, 0x00e9a7b1}, /* U+99F1 */ - {0xe971, 0x00e9a7b2}, /* U+99F2 */ - {0xe972, 0x00e9a7bb}, /* U+99FB */ - {0xe973, 0x00e9a7b8}, /* U+99F8 */ - {0xe974, 0x00e9a881}, /* U+9A01 */ - {0xe975, 0x00e9a88f}, /* U+9A0F */ - {0xe976, 0x00e9a885}, /* U+9A05 */ - {0xe977, 0x00e9a7a2}, /* U+99E2 */ - {0xe978, 0x00e9a899}, /* U+9A19 */ - {0xe979, 0x00e9a8ab}, /* U+9A2B */ - {0xe97a, 0x00e9a8b7}, /* U+9A37 */ - {0xe97b, 0x00e9a985}, /* U+9A45 */ - {0xe97c, 0x00e9a982}, /* U+9A42 */ - {0xe97d, 0x00e9a980}, /* U+9A40 */ - {0xe97e, 0x00e9a983}, /* U+9A43 */ - {0xe980, 0x00e9a8be}, /* U+9A3E */ - {0xe981, 0x00e9a995}, /* U+9A55 */ - {0xe982, 0x00e9a98d}, /* U+9A4D */ - {0xe983, 0x00e9a99b}, /* U+9A5B */ - {0xe984, 0x00e9a997}, /* U+9A57 */ - {0xe985, 0x00e9a99f}, /* U+9A5F */ - {0xe986, 0x00e9a9a2}, /* U+9A62 */ - {0xe987, 0x00e9a9a5}, /* U+9A65 */ - {0xe988, 0x00e9a9a4}, /* U+9A64 */ - {0xe989, 0x00e9a9a9}, /* U+9A69 */ - {0xe98a, 0x00e9a9ab}, /* U+9A6B */ - {0xe98b, 0x00e9a9aa}, /* U+9A6A */ - {0xe98c, 0x00e9aaad}, /* U+9AAD */ - {0xe98d, 0x00e9aab0}, /* U+9AB0 */ - {0xe98e, 0x00e9aabc}, /* U+9ABC */ - {0xe98f, 0x00e9ab80}, /* U+9AC0 */ - {0xe990, 0x00e9ab8f}, /* U+9ACF */ - {0xe991, 0x00e9ab91}, /* U+9AD1 */ - {0xe992, 0x00e9ab93}, /* U+9AD3 */ - {0xe993, 0x00e9ab94}, /* U+9AD4 */ - {0xe994, 0x00e9ab9e}, /* U+9ADE */ - {0xe995, 0x00e9ab9f}, /* U+9ADF */ - {0xe996, 0x00e9aba2}, /* U+9AE2 */ - {0xe997, 0x00e9aba3}, /* U+9AE3 */ - {0xe998, 0x00e9aba6}, /* U+9AE6 */ - {0xe999, 0x00e9abaf}, /* U+9AEF */ - {0xe99a, 0x00e9abab}, /* U+9AEB */ - {0xe99b, 0x00e9abae}, /* U+9AEE */ - {0xe99c, 0x00e9abb4}, /* U+9AF4 */ - {0xe99d, 0x00e9abb1}, /* U+9AF1 */ - {0xe99e, 0x00e9abb7}, /* U+9AF7 */ - {0xe99f, 0x00e9abbb}, /* U+9AFB */ - {0xe9a0, 0x00e9ac86}, /* U+9B06 */ - {0xe9a1, 0x00e9ac98}, /* U+9B18 */ - {0xe9a2, 0x00e9ac9a}, /* U+9B1A */ - {0xe9a3, 0x00e9ac9f}, /* U+9B1F */ - {0xe9a4, 0x00e9aca2}, /* U+9B22 */ - {0xe9a5, 0x00e9aca3}, /* U+9B23 */ - {0xe9a6, 0x00e9aca5}, /* U+9B25 */ - {0xe9a7, 0x00e9aca7}, /* U+9B27 */ - {0xe9a8, 0x00e9aca8}, /* U+9B28 */ - {0xe9a9, 0x00e9aca9}, /* U+9B29 */ - {0xe9aa, 0x00e9acaa}, /* U+9B2A */ - {0xe9ab, 0x00e9acae}, /* U+9B2E */ - {0xe9ac, 0x00e9acaf}, /* U+9B2F */ - {0xe9ad, 0x00e9acb2}, /* U+9B32 */ - {0xe9ae, 0x00e9ad84}, /* U+9B44 */ - {0xe9af, 0x00e9ad83}, /* U+9B43 */ - {0xe9b0, 0x00e9ad8f}, /* U+9B4F */ - {0xe9b1, 0x00e9ad8d}, /* U+9B4D */ - {0xe9b2, 0x00e9ad8e}, /* U+9B4E */ - {0xe9b3, 0x00e9ad91}, /* U+9B51 */ - {0xe9b4, 0x00e9ad98}, /* U+9B58 */ - {0xe9b5, 0x00e9adb4}, /* U+9B74 */ - {0xe9b6, 0x00e9ae93}, /* U+9B93 */ - {0xe9b7, 0x00e9ae83}, /* U+9B83 */ - {0xe9b8, 0x00e9ae91}, /* U+9B91 */ - {0xe9b9, 0x00e9ae96}, /* U+9B96 */ - {0xe9ba, 0x00e9ae97}, /* U+9B97 */ - {0xe9bb, 0x00e9ae9f}, /* U+9B9F */ - {0xe9bc, 0x00e9aea0}, /* U+9BA0 */ - {0xe9bd, 0x00e9aea8}, /* U+9BA8 */ - {0xe9be, 0x00e9aeb4}, /* U+9BB4 */ - {0xe9bf, 0x00e9af80}, /* U+9BC0 */ - {0xe9c0, 0x00e9af8a}, /* U+9BCA */ - {0xe9c1, 0x00e9aeb9}, /* U+9BB9 */ - {0xe9c2, 0x00e9af86}, /* U+9BC6 */ - {0xe9c3, 0x00e9af8f}, /* U+9BCF */ - {0xe9c4, 0x00e9af91}, /* U+9BD1 */ - {0xe9c5, 0x00e9af92}, /* U+9BD2 */ - {0xe9c6, 0x00e9afa3}, /* U+9BE3 */ - {0xe9c7, 0x00e9afa2}, /* U+9BE2 */ - {0xe9c8, 0x00e9afa4}, /* U+9BE4 */ - {0xe9c9, 0x00e9af94}, /* U+9BD4 */ - {0xe9ca, 0x00e9afa1}, /* U+9BE1 */ - {0xe9cb, 0x00e9b0ba}, /* U+9C3A */ - {0xe9cc, 0x00e9afb2}, /* U+9BF2 */ - {0xe9cd, 0x00e9afb1}, /* U+9BF1 */ - {0xe9ce, 0x00e9afb0}, /* U+9BF0 */ - {0xe9cf, 0x00e9b095}, /* U+9C15 */ - {0xe9d0, 0x00e9b094}, /* U+9C14 */ - {0xe9d1, 0x00e9b089}, /* U+9C09 */ - {0xe9d2, 0x00e9b093}, /* U+9C13 */ - {0xe9d3, 0x00e9b08c}, /* U+9C0C */ - {0xe9d4, 0x00e9b086}, /* U+9C06 */ - {0xe9d5, 0x00e9b088}, /* U+9C08 */ - {0xe9d6, 0x00e9b092}, /* U+9C12 */ - {0xe9d7, 0x00e9b08a}, /* U+9C0A */ - {0xe9d8, 0x00e9b084}, /* U+9C04 */ - {0xe9d9, 0x00e9b0ae}, /* U+9C2E */ - {0xe9da, 0x00e9b09b}, /* U+9C1B */ - {0xe9db, 0x00e9b0a5}, /* U+9C25 */ - {0xe9dc, 0x00e9b0a4}, /* U+9C24 */ - {0xe9dd, 0x00e9b0a1}, /* U+9C21 */ - {0xe9de, 0x00e9b0b0}, /* U+9C30 */ - {0xe9df, 0x00e9b187}, /* U+9C47 */ - {0xe9e0, 0x00e9b0b2}, /* U+9C32 */ - {0xe9e1, 0x00e9b186}, /* U+9C46 */ - {0xe9e2, 0x00e9b0be}, /* U+9C3E */ - {0xe9e3, 0x00e9b19a}, /* U+9C5A */ - {0xe9e4, 0x00e9b1a0}, /* U+9C60 */ - {0xe9e5, 0x00e9b1a7}, /* U+9C67 */ - {0xe9e6, 0x00e9b1b6}, /* U+9C76 */ - {0xe9e7, 0x00e9b1b8}, /* U+9C78 */ - {0xe9e8, 0x00e9b3a7}, /* U+9CE7 */ - {0xe9e9, 0x00e9b3ac}, /* U+9CEC */ - {0xe9ea, 0x00e9b3b0}, /* U+9CF0 */ - {0xe9eb, 0x00e9b489}, /* U+9D09 */ - {0xe9ec, 0x00e9b488}, /* U+9D08 */ - {0xe9ed, 0x00e9b3ab}, /* U+9CEB */ - {0xe9ee, 0x00e9b483}, /* U+9D03 */ - {0xe9ef, 0x00e9b486}, /* U+9D06 */ - {0xe9f0, 0x00e9b4aa}, /* U+9D2A */ - {0xe9f1, 0x00e9b4a6}, /* U+9D26 */ - {0xe9f2, 0x00e9b6af}, /* U+9DAF */ - {0xe9f3, 0x00e9b4a3}, /* U+9D23 */ - {0xe9f4, 0x00e9b49f}, /* U+9D1F */ - {0xe9f5, 0x00e9b584}, /* U+9D44 */ - {0xe9f6, 0x00e9b495}, /* U+9D15 */ - {0xe9f7, 0x00e9b492}, /* U+9D12 */ - {0xe9f8, 0x00e9b581}, /* U+9D41 */ - {0xe9f9, 0x00e9b4bf}, /* U+9D3F */ - {0xe9fa, 0x00e9b4be}, /* U+9D3E */ - {0xe9fb, 0x00e9b586}, /* U+9D46 */ - {0xe9fc, 0x00e9b588}, /* U+9D48 */ - {0xea40, 0x00e9b59d}, /* U+9D5D */ - {0xea41, 0x00e9b59e}, /* U+9D5E */ - {0xea42, 0x00e9b5a4}, /* U+9D64 */ - {0xea43, 0x00e9b591}, /* U+9D51 */ - {0xea44, 0x00e9b590}, /* U+9D50 */ - {0xea45, 0x00e9b599}, /* U+9D59 */ - {0xea46, 0x00e9b5b2}, /* U+9D72 */ - {0xea47, 0x00e9b689}, /* U+9D89 */ - {0xea48, 0x00e9b687}, /* U+9D87 */ - {0xea49, 0x00e9b6ab}, /* U+9DAB */ - {0xea4a, 0x00e9b5af}, /* U+9D6F */ - {0xea4b, 0x00e9b5ba}, /* U+9D7A */ - {0xea4c, 0x00e9b69a}, /* U+9D9A */ - {0xea4d, 0x00e9b6a4}, /* U+9DA4 */ - {0xea4e, 0x00e9b6a9}, /* U+9DA9 */ - {0xea4f, 0x00e9b6b2}, /* U+9DB2 */ - {0xea50, 0x00e9b784}, /* U+9DC4 */ - {0xea51, 0x00e9b781}, /* U+9DC1 */ - {0xea52, 0x00e9b6bb}, /* U+9DBB */ - {0xea53, 0x00e9b6b8}, /* U+9DB8 */ - {0xea54, 0x00e9b6ba}, /* U+9DBA */ - {0xea55, 0x00e9b786}, /* U+9DC6 */ - {0xea56, 0x00e9b78f}, /* U+9DCF */ - {0xea57, 0x00e9b782}, /* U+9DC2 */ - {0xea58, 0x00e9b799}, /* U+9DD9 */ - {0xea59, 0x00e9b793}, /* U+9DD3 */ - {0xea5a, 0x00e9b7b8}, /* U+9DF8 */ - {0xea5b, 0x00e9b7a6}, /* U+9DE6 */ - {0xea5c, 0x00e9b7ad}, /* U+9DED */ - {0xea5d, 0x00e9b7af}, /* U+9DEF */ - {0xea5e, 0x00e9b7bd}, /* U+9DFD */ - {0xea5f, 0x00e9b89a}, /* U+9E1A */ - {0xea60, 0x00e9b89b}, /* U+9E1B */ - {0xea61, 0x00e9b89e}, /* U+9E1E */ - {0xea62, 0x00e9b9b5}, /* U+9E75 */ - {0xea63, 0x00e9b9b9}, /* U+9E79 */ - {0xea64, 0x00e9b9bd}, /* U+9E7D */ - {0xea65, 0x00e9ba81}, /* U+9E81 */ - {0xea66, 0x00e9ba88}, /* U+9E88 */ - {0xea67, 0x00e9ba8b}, /* U+9E8B */ - {0xea68, 0x00e9ba8c}, /* U+9E8C */ - {0xea69, 0x00e9ba92}, /* U+9E92 */ - {0xea6a, 0x00e9ba95}, /* U+9E95 */ - {0xea6b, 0x00e9ba91}, /* U+9E91 */ - {0xea6c, 0x00e9ba9d}, /* U+9E9D */ - {0xea6d, 0x00e9baa5}, /* U+9EA5 */ - {0xea6e, 0x00e9baa9}, /* U+9EA9 */ - {0xea6f, 0x00e9bab8}, /* U+9EB8 */ - {0xea70, 0x00e9baaa}, /* U+9EAA */ - {0xea71, 0x00e9baad}, /* U+9EAD */ - {0xea72, 0x00e99da1}, /* U+9761 */ - {0xea73, 0x00e9bb8c}, /* U+9ECC */ - {0xea74, 0x00e9bb8e}, /* U+9ECE */ - {0xea75, 0x00e9bb8f}, /* U+9ECF */ - {0xea76, 0x00e9bb90}, /* U+9ED0 */ - {0xea77, 0x00e9bb94}, /* U+9ED4 */ - {0xea78, 0x00e9bb9c}, /* U+9EDC */ - {0xea79, 0x00e9bb9e}, /* U+9EDE */ - {0xea7a, 0x00e9bb9d}, /* U+9EDD */ - {0xea7b, 0x00e9bba0}, /* U+9EE0 */ - {0xea7c, 0x00e9bba5}, /* U+9EE5 */ - {0xea7d, 0x00e9bba8}, /* U+9EE8 */ - {0xea7e, 0x00e9bbaf}, /* U+9EEF */ - {0xea80, 0x00e9bbb4}, /* U+9EF4 */ - {0xea81, 0x00e9bbb6}, /* U+9EF6 */ - {0xea82, 0x00e9bbb7}, /* U+9EF7 */ - {0xea83, 0x00e9bbb9}, /* U+9EF9 */ - {0xea84, 0x00e9bbbb}, /* U+9EFB */ - {0xea85, 0x00e9bbbc}, /* U+9EFC */ - {0xea86, 0x00e9bbbd}, /* U+9EFD */ - {0xea87, 0x00e9bc87}, /* U+9F07 */ - {0xea88, 0x00e9bc88}, /* U+9F08 */ - {0xea89, 0x00e79ab7}, /* U+76B7 */ - {0xea8a, 0x00e9bc95}, /* U+9F15 */ - {0xea8b, 0x00e9bca1}, /* U+9F21 */ - {0xea8c, 0x00e9bcac}, /* U+9F2C */ - {0xea8d, 0x00e9bcbe}, /* U+9F3E */ - {0xea8e, 0x00e9bd8a}, /* U+9F4A */ - {0xea8f, 0x00e9bd92}, /* U+9F52 */ - {0xea90, 0x00e9bd94}, /* U+9F54 */ - {0xea91, 0x00e9bda3}, /* U+9F63 */ - {0xea92, 0x00e9bd9f}, /* U+9F5F */ - {0xea93, 0x00e9bda0}, /* U+9F60 */ - {0xea94, 0x00e9bda1}, /* U+9F61 */ - {0xea95, 0x00e9bda6}, /* U+9F66 */ - {0xea96, 0x00e9bda7}, /* U+9F67 */ - {0xea97, 0x00e9bdac}, /* U+9F6C */ - {0xea98, 0x00e9bdaa}, /* U+9F6A */ - {0xea99, 0x00e9bdb7}, /* U+9F77 */ - {0xea9a, 0x00e9bdb2}, /* U+9F72 */ - {0xea9b, 0x00e9bdb6}, /* U+9F76 */ - {0xea9c, 0x00e9be95}, /* U+9F95 */ - {0xea9d, 0x00e9be9c}, /* U+9F9C */ - {0xea9e, 0x00e9bea0}, /* U+9FA0 */ - {0xea9f, 0x00e5a0af}, /* U+582F [1983] */ - {0xeaa0, 0x00e6a787}, /* U+69C7 [1983] */ - {0xeaa1, 0x00e98199}, /* U+9059 [1983] */ - {0xeaa2, 0x00e791a4}, /* U+7464 [1983] */ - {0xeaa3, 0x00e5879c}, /* U+51DC [1990] */ - {0xeaa4, 0x00e78699}, /* U+7199 [1990] */ - {0xeaa5, 0x00e59993}, /* U+5653 [2004] */ - {0xeaa6, 0x00e5b7a2}, /* U+5DE2 [2000] */ - {0xeaa7, 0x00e5b894}, /* U+5E14 [2000] */ - {0xeaa8, 0x00e5b898}, /* U+5E18 [2000] */ - {0xeaa9, 0x00e5b998}, /* U+5E58 [2000] */ - {0xeaaa, 0x00e5b99e}, /* U+5E5E [2000] */ - {0xeaab, 0x00e5babe}, /* U+5EBE [2000] */ - {0xeaac, 0x00efa4a8}, /* U+F928 CJK COMPATIBILITY IDEOGRAPH-F928 [2000] */ - {0xeaad, 0x00e5bb8b}, /* U+5ECB [2000] */ - {0xeaae, 0x00e5bbb9}, /* U+5EF9 [2000] */ - {0xeaaf, 0x00e5bc80}, /* U+5F00 [2000] */ - {0xeab0, 0x00e5bc82}, /* U+5F02 [2000] */ - {0xeab1, 0x00e5bc87}, /* U+5F07 [2000] */ - {0xeab2, 0x00e5bc9d}, /* U+5F1D [2000] */ - {0xeab3, 0x00e5bca3}, /* U+5F23 [2000] */ - {0xeab4, 0x00e5bcb4}, /* U+5F34 [2000] */ - {0xeab5, 0x00e5bcb6}, /* U+5F36 [2000] */ - {0xeab6, 0x00e5bcbd}, /* U+5F3D [2000] */ - {0xeab7, 0x00e5bd80}, /* U+5F40 [2000] */ - {0xeab8, 0x00e5bd85}, /* U+5F45 [2000] */ - {0xeab9, 0x00e5bd94}, /* U+5F54 [2000] */ - {0xeaba, 0x00e5bd98}, /* U+5F58 [2000] */ - {0xeabb, 0x00e5bda4}, /* U+5F64 [2000] */ - {0xeabc, 0x00e5bda7}, /* U+5F67 [2000] */ - {0xeabd, 0x00e5bdbd}, /* U+5F7D [2000] */ - {0xeabe, 0x00e5be89}, /* U+5F89 [2000] */ - {0xeabf, 0x00e5be9c}, /* U+5F9C [2000] */ - {0xeac0, 0x00e5bea7}, /* U+5FA7 [2000] */ - {0xeac1, 0x00e5beaf}, /* U+5FAF [2000] */ - {0xeac2, 0x00e5beb5}, /* U+5FB5 [2000] */ - {0xeac3, 0x00e5beb7}, /* U+5FB7 [2000] */ - {0xeac4, 0x00e5bf89}, /* U+5FC9 [2000] */ - {0xeac5, 0x00e5bf9e}, /* U+5FDE [2000] */ - {0xeac6, 0x00e5bfa1}, /* U+5FE1 [2000] */ - {0xeac7, 0x00e5bfa9}, /* U+5FE9 [2000] */ - {0xeac8, 0x00e6808d}, /* U+600D [2000] */ - {0xeac9, 0x00e68094}, /* U+6014 [2000] */ - {0xeaca, 0x00e68098}, /* U+6018 [2000] */ - {0xeacb, 0x00e680b3}, /* U+6033 [2000] */ - {0xeacc, 0x00e680b5}, /* U+6035 [2000] */ - {0xeacd, 0x00e68187}, /* U+6047 [2000] */ - {0xeace, 0x00efa8bd}, /* U+FA3D CJK COMPATIBILITY IDEOGRAPH-FA3D [2000] [Unicode3.2] */ - {0xeacf, 0x00e6829d}, /* U+609D [2000] */ - {0xead0, 0x00e6829e}, /* U+609E [2000] */ - {0xead1, 0x00e6838b}, /* U+60CB [2000] */ - {0xead2, 0x00e68394}, /* U+60D4 [2000] */ - {0xead3, 0x00e68395}, /* U+60D5 [2000] */ - {0xead4, 0x00e6839d}, /* U+60DD [2000] */ - {0xead5, 0x00e683b8}, /* U+60F8 [2000] */ - {0xead6, 0x00e6849c}, /* U+611C [2000] */ - {0xead7, 0x00e684ab}, /* U+612B [2000] */ - {0xead8, 0x00e684b0}, /* U+6130 [2000] */ - {0xead9, 0x00e684b7}, /* U+6137 [2000] */ - {0xeada, 0x00efa8be}, /* U+FA3E CJK COMPATIBILITY IDEOGRAPH-FA3E [2000] [Unicode3.2] */ - {0xeadb, 0x00e6868d}, /* U+618D [2000] */ - {0xeadc, 0x00efa8bf}, /* U+FA3F CJK COMPATIBILITY IDEOGRAPH-FA3F [2000] [Unicode3.2] */ - {0xeadd, 0x00e686bc}, /* U+61BC [2000] */ - {0xeade, 0x00e686b9}, /* U+61B9 [2000] */ - {0xeadf, 0x00efa980}, /* U+FA40 CJK COMPATIBILITY IDEOGRAPH-FA40 [2000] [Unicode3.2] */ - {0xeae0, 0x00e688a2}, /* U+6222 [2000] */ - {0xeae1, 0x00e688be}, /* U+623E [2000] */ - {0xeae2, 0x00e68983}, /* U+6243 [2000] */ - {0xeae3, 0x00e68996}, /* U+6256 [2000] */ - {0xeae4, 0x00e6899a}, /* U+625A [2000] */ - {0xeae5, 0x00e689af}, /* U+626F [2000] */ - {0xeae6, 0x00e68a85}, /* U+6285 [2000] */ - {0xeae7, 0x00e68b84}, /* U+62C4 [2000] */ - {0xeae8, 0x00e68b96}, /* U+62D6 [2000] */ - {0xeae9, 0x00e68bbc}, /* U+62FC [2000] */ - {0xeaea, 0x00e68c8a}, /* U+630A [2000] */ - {0xeaeb, 0x00e68c98}, /* U+6318 [2000] */ - {0xeaec, 0x00e68cb9}, /* U+6339 [2000] */ - {0xeaed, 0x00e68d83}, /* U+6343 [2000] */ - {0xeaee, 0x00e68da5}, /* U+6365 [2000] */ - {0xeaef, 0x00e68dbc}, /* U+637C [2000] */ - {0xeaf0, 0x00e68fa5}, /* U+63E5 [2000] */ - {0xeaf1, 0x00e68fad}, /* U+63ED [2000] */ - {0xeaf2, 0x00e68fb5}, /* U+63F5 [2000] */ - {0xeaf3, 0x00e69090}, /* U+6410 [2000] */ - {0xeaf4, 0x00e69094}, /* U+6414 [2000] */ - {0xeaf5, 0x00e690a2}, /* U+6422 [2000] */ - {0xeaf6, 0x00e691b9}, /* U+6479 [2000] */ - {0xeaf7, 0x00e69191}, /* U+6451 [2000] */ - {0xeaf8, 0x00e691a0}, /* U+6460 [2000] */ - {0xeaf9, 0x00e691ad}, /* U+646D [2000] */ - {0xeafa, 0x00e6938e}, /* U+64CE [2000] */ - {0xeafb, 0x00e692be}, /* U+64BE [2000] */ - {0xeafc, 0x00e692bf}, /* U+64BF [2000] */ - {0xeb40, 0x00e69384}, /* U+64C4 [2000] */ - {0xeb41, 0x00e6938a}, /* U+64CA [2000] */ - {0xeb42, 0x00e69390}, /* U+64D0 [2000] */ - {0xeb43, 0x00e693b7}, /* U+64F7 [2000] */ - {0xeb44, 0x00e693bb}, /* U+64FB [2000] */ - {0xeb45, 0x00e694a2}, /* U+6522 [2000] */ - {0xeb46, 0x00e694a9}, /* U+6529 [2000] */ - {0xeb47, 0x00efa981}, /* U+FA41 CJK COMPATIBILITY IDEOGRAPH-FA41 [2000] [Unicode3.2] */ - {0xeb48, 0x00e695a7}, /* U+6567 [2000] */ - {0xeb49, 0x00e6969d}, /* U+659D [2000] */ - {0xeb4a, 0x00efa982}, /* U+FA42 CJK COMPATIBILITY IDEOGRAPH-FA42 [2000] [Unicode3.2] */ - {0xeb4b, 0x00e69880}, /* U+6600 [2000] */ - {0xeb4c, 0x00e69889}, /* U+6609 [2000] */ - {0xeb4d, 0x00e69895}, /* U+6615 [2000] */ - {0xeb4e, 0x00e6989e}, /* U+661E [2000] */ - {0xeb4f, 0x00e698ba}, /* U+663A [2000] */ - {0xeb50, 0x00e698a2}, /* U+6622 [2000] */ - {0xeb51, 0x00e698a4}, /* U+6624 [2000] */ - {0xeb52, 0x00e698ab}, /* U+662B [2000] */ - {0xeb53, 0x00e698b0}, /* U+6630 [2000] */ - {0xeb54, 0x00e698b1}, /* U+6631 [2000] */ - {0xeb55, 0x00e698b3}, /* U+6633 [2000] */ - {0xeb56, 0x00e69bbb}, /* U+66FB [2000] */ - {0xeb57, 0x00e69988}, /* U+6648 [2000] */ - {0xeb58, 0x00e6998c}, /* U+664C [2000] */ + {0x988f, 0xe39fa2}, /* U+37E2 [2000] */ + {0x9890, 0xe5b48d}, /* U+5D0D [2000] */ + {0x9891, 0xe5b4a7}, /* U+5D27 [2000] */ + {0x9892, 0xefa891}, /* U+FA11 CJK COMPATIBILITY IDEOGRAPH-FA11 [2000] */ + {0x9893, 0xe5b586}, /* U+5D46 [2000] */ + {0x9894, 0xe5b587}, /* U+5D47 [2000] */ + {0x9895, 0xe5b593}, /* U+5D53 [2000] */ + {0x9896, 0xe5b58a}, /* U+5D4A [2000] */ + {0x9897, 0xe5b5ad}, /* U+5D6D [2000] */ + {0x9898, 0xe5b681}, /* U+5D81 [2000] */ + {0x9899, 0xe5b6a0}, /* U+5DA0 [2000] */ + {0x989a, 0xe5b6a4}, /* U+5DA4 [2000] */ + {0x989b, 0xe5b6a7}, /* U+5DA7 [2000] */ + {0x989c, 0xe5b6b8}, /* U+5DB8 [2000] */ + {0x989d, 0xe5b78b}, /* U+5DCB [2000] */ + {0x989e, 0xe5909e}, /* U+541E [2004] */ + {0x989f, 0xe5bc8c}, /* U+5F0C */ + {0x98a0, 0xe4b890}, /* U+4E10 */ + {0x98a1, 0xe4b895}, /* U+4E15 */ + {0x98a2, 0xe4b8aa}, /* U+4E2A */ + {0x98a3, 0xe4b8b1}, /* U+4E31 */ + {0x98a4, 0xe4b8b6}, /* U+4E36 */ + {0x98a5, 0xe4b8bc}, /* U+4E3C */ + {0x98a6, 0xe4b8bf}, /* U+4E3F */ + {0x98a7, 0xe4b982}, /* U+4E42 */ + {0x98a8, 0xe4b996}, /* U+4E56 */ + {0x98a9, 0xe4b998}, /* U+4E58 */ + {0x98aa, 0xe4ba82}, /* U+4E82 */ + {0x98ab, 0xe4ba85}, /* U+4E85 */ + {0x98ac, 0xe8b1ab}, /* U+8C6B */ + {0x98ad, 0xe4ba8a}, /* U+4E8A */ + {0x98ae, 0xe88892}, /* U+8212 */ + {0x98af, 0xe5bc8d}, /* U+5F0D */ + {0x98b0, 0xe4ba8e}, /* U+4E8E */ + {0x98b1, 0xe4ba9e}, /* U+4E9E */ + {0x98b2, 0xe4ba9f}, /* U+4E9F */ + {0x98b3, 0xe4baa0}, /* U+4EA0 */ + {0x98b4, 0xe4baa2}, /* U+4EA2 */ + {0x98b5, 0xe4bab0}, /* U+4EB0 */ + {0x98b6, 0xe4bab3}, /* U+4EB3 */ + {0x98b7, 0xe4bab6}, /* U+4EB6 */ + {0x98b8, 0xe4bb8e}, /* U+4ECE */ + {0x98b9, 0xe4bb8d}, /* U+4ECD */ + {0x98ba, 0xe4bb84}, /* U+4EC4 */ + {0x98bb, 0xe4bb86}, /* U+4EC6 */ + {0x98bc, 0xe4bb82}, /* U+4EC2 */ + {0x98bd, 0xe4bb97}, /* U+4ED7 */ + {0x98be, 0xe4bb9e}, /* U+4EDE */ + {0x98bf, 0xe4bbad}, /* U+4EED */ + {0x98c0, 0xe4bb9f}, /* U+4EDF */ + {0x98c1, 0xe4bbb7}, /* U+4EF7 */ + {0x98c2, 0xe4bc89}, /* U+4F09 */ + {0x98c3, 0xe4bd9a}, /* U+4F5A */ + {0x98c4, 0xe4bcb0}, /* U+4F30 */ + {0x98c5, 0xe4bd9b}, /* U+4F5B */ + {0x98c6, 0xe4bd9d}, /* U+4F5D */ + {0x98c7, 0xe4bd97}, /* U+4F57 */ + {0x98c8, 0xe4bd87}, /* U+4F47 */ + {0x98c9, 0xe4bdb6}, /* U+4F76 */ + {0x98ca, 0xe4be88}, /* U+4F88 */ + {0x98cb, 0xe4be8f}, /* U+4F8F */ + {0x98cc, 0xe4be98}, /* U+4F98 */ + {0x98cd, 0xe4bdbb}, /* U+4F7B */ + {0x98ce, 0xe4bda9}, /* U+4F69 */ + {0x98cf, 0xe4bdb0}, /* U+4F70 */ + {0x98d0, 0xe4be91}, /* U+4F91 */ + {0x98d1, 0xe4bdaf}, /* U+4F6F */ + {0x98d2, 0xe4be86}, /* U+4F86 */ + {0x98d3, 0xe4be96}, /* U+4F96 */ + {0x98d4, 0xe58498}, /* U+5118 */ + {0x98d5, 0xe4bf94}, /* U+4FD4 */ + {0x98d6, 0xe4bf9f}, /* U+4FDF */ + {0x98d7, 0xe4bf8e}, /* U+4FCE */ + {0x98d8, 0xe4bf98}, /* U+4FD8 */ + {0x98d9, 0xe4bf9b}, /* U+4FDB */ + {0x98da, 0xe4bf91}, /* U+4FD1 */ + {0x98db, 0xe4bf9a}, /* U+4FDA */ + {0x98dc, 0xe4bf90}, /* U+4FD0 */ + {0x98dd, 0xe4bfa4}, /* U+4FE4 */ + {0x98de, 0xe4bfa5}, /* U+4FE5 */ + {0x98df, 0xe5809a}, /* U+501A */ + {0x98e0, 0xe580a8}, /* U+5028 */ + {0x98e1, 0xe58094}, /* U+5014 */ + {0x98e2, 0xe580aa}, /* U+502A */ + {0x98e3, 0xe580a5}, /* U+5025 */ + {0x98e4, 0xe58085}, /* U+5005 */ + {0x98e5, 0xe4bc9c}, /* U+4F1C */ + {0x98e6, 0xe4bfb6}, /* U+4FF6 */ + {0x98e7, 0xe580a1}, /* U+5021 */ + {0x98e8, 0xe580a9}, /* U+5029 */ + {0x98e9, 0xe580ac}, /* U+502C */ + {0x98ea, 0xe4bfbe}, /* U+4FFE */ + {0x98eb, 0xe4bfaf}, /* U+4FEF */ + {0x98ec, 0xe58091}, /* U+5011 */ + {0x98ed, 0xe58086}, /* U+5006 */ + {0x98ee, 0xe58183}, /* U+5043 */ + {0x98ef, 0xe58187}, /* U+5047 */ + {0x98f0, 0xe69c83}, /* U+6703 */ + {0x98f1, 0xe58195}, /* U+5055 */ + {0x98f2, 0xe58190}, /* U+5050 */ + {0x98f3, 0xe58188}, /* U+5048 */ + {0x98f4, 0xe5819a}, /* U+505A */ + {0x98f5, 0xe58196}, /* U+5056 */ + {0x98f6, 0xe581ac}, /* U+506C */ + {0x98f7, 0xe581b8}, /* U+5078 */ + {0x98f8, 0xe58280}, /* U+5080 */ + {0x98f9, 0xe5829a}, /* U+509A */ + {0x98fa, 0xe58285}, /* U+5085 */ + {0x98fb, 0xe582b4}, /* U+50B4 */ + {0x98fc, 0xe582b2}, /* U+50B2 */ + {0x9940, 0xe58389}, /* U+50C9 */ + {0x9941, 0xe5838a}, /* U+50CA */ + {0x9942, 0xe582b3}, /* U+50B3 */ + {0x9943, 0xe58382}, /* U+50C2 */ + {0x9944, 0xe58396}, /* U+50D6 */ + {0x9945, 0xe5839e}, /* U+50DE */ + {0x9946, 0xe583a5}, /* U+50E5 */ + {0x9947, 0xe583ad}, /* U+50ED */ + {0x9948, 0xe583a3}, /* U+50E3 */ + {0x9949, 0xe583ae}, /* U+50EE */ + {0x994a, 0xe583b9}, /* U+50F9 */ + {0x994b, 0xe583b5}, /* U+50F5 */ + {0x994c, 0xe58489}, /* U+5109 */ + {0x994d, 0xe58481}, /* U+5101 */ + {0x994e, 0xe58482}, /* U+5102 */ + {0x994f, 0xe58496}, /* U+5116 */ + {0x9950, 0xe58495}, /* U+5115 */ + {0x9951, 0xe58494}, /* U+5114 */ + {0x9952, 0xe5849a}, /* U+511A */ + {0x9953, 0xe584a1}, /* U+5121 */ + {0x9954, 0xe584ba}, /* U+513A */ + {0x9955, 0xe584b7}, /* U+5137 */ + {0x9956, 0xe584bc}, /* U+513C */ + {0x9957, 0xe584bb}, /* U+513B */ + {0x9958, 0xe584bf}, /* U+513F */ + {0x9959, 0xe58580}, /* U+5140 */ + {0x995a, 0xe58592}, /* U+5152 */ + {0x995b, 0xe5858c}, /* U+514C */ + {0x995c, 0xe58594}, /* U+5154 */ + {0x995d, 0xe585a2}, /* U+5162 */ + {0x995e, 0xe7abb8}, /* U+7AF8 */ + {0x995f, 0xe585a9}, /* U+5169 */ + {0x9960, 0xe585aa}, /* U+516A */ + {0x9961, 0xe585ae}, /* U+516E */ + {0x9962, 0xe58680}, /* U+5180 */ + {0x9963, 0xe58682}, /* U+5182 */ + {0x9964, 0xe59b98}, /* U+56D8 */ + {0x9965, 0xe5868c}, /* U+518C */ + {0x9966, 0xe58689}, /* U+5189 */ + {0x9967, 0xe5868f}, /* U+518F */ + {0x9968, 0xe58691}, /* U+5191 */ + {0x9969, 0xe58693}, /* U+5193 */ + {0x996a, 0xe58695}, /* U+5195 */ + {0x996b, 0xe58696}, /* U+5196 */ + {0x996c, 0xe586a4}, /* U+51A4 */ + {0x996d, 0xe586a6}, /* U+51A6 */ + {0x996e, 0xe586a2}, /* U+51A2 */ + {0x996f, 0xe586a9}, /* U+51A9 */ + {0x9970, 0xe586aa}, /* U+51AA */ + {0x9971, 0xe586ab}, /* U+51AB */ + {0x9972, 0xe586b3}, /* U+51B3 */ + {0x9973, 0xe586b1}, /* U+51B1 */ + {0x9974, 0xe586b2}, /* U+51B2 */ + {0x9975, 0xe586b0}, /* U+51B0 */ + {0x9976, 0xe586b5}, /* U+51B5 */ + {0x9977, 0xe586bd}, /* U+51BD */ + {0x9978, 0xe58785}, /* U+51C5 */ + {0x9979, 0xe58789}, /* U+51C9 */ + {0x997a, 0xe5879b}, /* U+51DB */ + {0x997b, 0xe587a0}, /* U+51E0 */ + {0x997c, 0xe89995}, /* U+8655 */ + {0x997d, 0xe587a9}, /* U+51E9 */ + {0x997e, 0xe587ad}, /* U+51ED */ + {0x9980, 0xe587b0}, /* U+51F0 */ + {0x9981, 0xe587b5}, /* U+51F5 */ + {0x9982, 0xe587be}, /* U+51FE */ + {0x9983, 0xe58884}, /* U+5204 */ + {0x9984, 0xe5888b}, /* U+520B */ + {0x9985, 0xe58894}, /* U+5214 */ + {0x9986, 0xe5888e}, /* U+520E */ + {0x9987, 0xe588a7}, /* U+5227 */ + {0x9988, 0xe588aa}, /* U+522A */ + {0x9989, 0xe588ae}, /* U+522E */ + {0x998a, 0xe588b3}, /* U+5233 */ + {0x998b, 0xe588b9}, /* U+5239 */ + {0x998c, 0xe5898f}, /* U+524F */ + {0x998d, 0xe58984}, /* U+5244 */ + {0x998e, 0xe5898b}, /* U+524B */ + {0x998f, 0xe5898c}, /* U+524C */ + {0x9990, 0xe5899e}, /* U+525E */ + {0x9991, 0xe58994}, /* U+5254 */ + {0x9992, 0xe589aa}, /* U+526A */ + {0x9993, 0xe589b4}, /* U+5274 */ + {0x9994, 0xe589a9}, /* U+5269 */ + {0x9995, 0xe589b3}, /* U+5273 */ + {0x9996, 0xe589bf}, /* U+527F */ + {0x9997, 0xe589bd}, /* U+527D */ + {0x9998, 0xe58a8d}, /* U+528D */ + {0x9999, 0xe58a94}, /* U+5294 */ + {0x999a, 0xe58a92}, /* U+5292 */ + {0x999b, 0xe589b1}, /* U+5271 */ + {0x999c, 0xe58a88}, /* U+5288 */ + {0x999d, 0xe58a91}, /* U+5291 */ + {0x999e, 0xe8bea8}, /* U+8FA8 */ + {0x999f, 0xe8bea7}, /* U+8FA7 */ + {0x99a0, 0xe58aac}, /* U+52AC */ + {0x99a1, 0xe58aad}, /* U+52AD */ + {0x99a2, 0xe58abc}, /* U+52BC */ + {0x99a3, 0xe58ab5}, /* U+52B5 */ + {0x99a4, 0xe58b81}, /* U+52C1 */ + {0x99a5, 0xe58b8d}, /* U+52CD */ + {0x99a6, 0xe58b97}, /* U+52D7 */ + {0x99a7, 0xe58b9e}, /* U+52DE */ + {0x99a8, 0xe58ba3}, /* U+52E3 */ + {0x99a9, 0xe58ba6}, /* U+52E6 */ + {0x99aa, 0xe9a3ad}, /* U+98ED */ + {0x99ab, 0xe58ba0}, /* U+52E0 */ + {0x99ac, 0xe58bb3}, /* U+52F3 */ + {0x99ad, 0xe58bb5}, /* U+52F5 */ + {0x99ae, 0xe58bb8}, /* U+52F8 */ + {0x99af, 0xe58bb9}, /* U+52F9 */ + {0x99b0, 0xe58c86}, /* U+5306 */ + {0x99b1, 0xe58c88}, /* U+5308 */ + {0x99b2, 0xe794b8}, /* U+7538 */ + {0x99b3, 0xe58c8d}, /* U+530D */ + {0x99b4, 0xe58c90}, /* U+5310 */ + {0x99b5, 0xe58c8f}, /* U+530F */ + {0x99b6, 0xe58c95}, /* U+5315 */ + {0x99b7, 0xe58c9a}, /* U+531A */ + {0x99b8, 0xe58ca3}, /* U+5323 */ + {0x99b9, 0xe58caf}, /* U+532F */ + {0x99ba, 0xe58cb1}, /* U+5331 */ + {0x99bb, 0xe58cb3}, /* U+5333 */ + {0x99bc, 0xe58cb8}, /* U+5338 */ + {0x99bd, 0xe58d80}, /* U+5340 */ + {0x99be, 0xe58d86}, /* U+5346 */ + {0x99bf, 0xe58d85}, /* U+5345 */ + {0x99c0, 0xe4b897}, /* U+4E17 */ + {0x99c1, 0xe58d89}, /* U+5349 */ + {0x99c2, 0xe58d8d}, /* U+534D */ + {0x99c3, 0xe58796}, /* U+51D6 */ + {0x99c4, 0xe58d9e}, /* U+535E */ + {0x99c5, 0xe58da9}, /* U+5369 */ + {0x99c6, 0xe58dae}, /* U+536E */ + {0x99c7, 0xe5a498}, /* U+5918 */ + {0x99c8, 0xe58dbb}, /* U+537B */ + {0x99c9, 0xe58db7}, /* U+5377 */ + {0x99ca, 0xe58e82}, /* U+5382 */ + {0x99cb, 0xe58e96}, /* U+5396 */ + {0x99cc, 0xe58ea0}, /* U+53A0 */ + {0x99cd, 0xe58ea6}, /* U+53A6 */ + {0x99ce, 0xe58ea5}, /* U+53A5 */ + {0x99cf, 0xe58eae}, /* U+53AE */ + {0x99d0, 0xe58eb0}, /* U+53B0 */ + {0x99d1, 0xe58eb6}, /* U+53B6 */ + {0x99d2, 0xe58f83}, /* U+53C3 */ + {0x99d3, 0xe7b092}, /* U+7C12 */ + {0x99d4, 0xe99b99}, /* U+96D9 */ + {0x99d5, 0xe58f9f}, /* U+53DF */ + {0x99d6, 0xe69bbc}, /* U+66FC */ + {0x99d7, 0xe787ae}, /* U+71EE */ + {0x99d8, 0xe58fae}, /* U+53EE */ + {0x99d9, 0xe58fa8}, /* U+53E8 */ + {0x99da, 0xe58fad}, /* U+53ED */ + {0x99db, 0xe58fba}, /* U+53FA */ + {0x99dc, 0xe59081}, /* U+5401 */ + {0x99dd, 0xe590bd}, /* U+543D */ + {0x99de, 0xe59180}, /* U+5440 */ + {0x99df, 0xe590ac}, /* U+542C */ + {0x99e0, 0xe590ad}, /* U+542D */ + {0x99e1, 0xe590bc}, /* U+543C */ + {0x99e2, 0xe590ae}, /* U+542E */ + {0x99e3, 0xe590b6}, /* U+5436 */ + {0x99e4, 0xe590a9}, /* U+5429 */ + {0x99e5, 0xe5909d}, /* U+541D */ + {0x99e6, 0xe5918e}, /* U+544E */ + {0x99e7, 0xe5928f}, /* U+548F */ + {0x99e8, 0xe591b5}, /* U+5475 */ + {0x99e9, 0xe5928e}, /* U+548E */ + {0x99ea, 0xe5919f}, /* U+545F */ + {0x99eb, 0xe591b1}, /* U+5471 */ + {0x99ec, 0xe591b7}, /* U+5477 */ + {0x99ed, 0xe591b0}, /* U+5470 */ + {0x99ee, 0xe59292}, /* U+5492 */ + {0x99ef, 0xe591bb}, /* U+547B */ + {0x99f0, 0xe59280}, /* U+5480 */ + {0x99f1, 0xe591b6}, /* U+5476 */ + {0x99f2, 0xe59284}, /* U+5484 */ + {0x99f3, 0xe59290}, /* U+5490 */ + {0x99f4, 0xe59286}, /* U+5486 */ + {0x99f5, 0xe59387}, /* U+54C7 */ + {0x99f6, 0xe592a2}, /* U+54A2 */ + {0x99f7, 0xe592b8}, /* U+54B8 */ + {0x99f8, 0xe592a5}, /* U+54A5 */ + {0x99f9, 0xe592ac}, /* U+54AC */ + {0x99fa, 0xe59384}, /* U+54C4 */ + {0x99fb, 0xe59388}, /* U+54C8 */ + {0x99fc, 0xe592a8}, /* U+54A8 */ + {0x9a40, 0xe592ab}, /* U+54AB */ + {0x9a41, 0xe59382}, /* U+54C2 */ + {0x9a42, 0xe592a4}, /* U+54A4 */ + {0x9a43, 0xe592be}, /* U+54BE */ + {0x9a44, 0xe592bc}, /* U+54BC */ + {0x9a45, 0xe59398}, /* U+54D8 */ + {0x9a46, 0xe593a5}, /* U+54E5 */ + {0x9a47, 0xe593a6}, /* U+54E6 */ + {0x9a48, 0xe5948f}, /* U+550F */ + {0x9a49, 0xe59494}, /* U+5514 */ + {0x9a4a, 0xe593bd}, /* U+54FD */ + {0x9a4b, 0xe593ae}, /* U+54EE */ + {0x9a4c, 0xe593ad}, /* U+54ED */ + {0x9a4d, 0xe593ba}, /* U+54FA */ + {0x9a4e, 0xe593a2}, /* U+54E2 */ + {0x9a4f, 0xe594b9}, /* U+5539 */ + {0x9a50, 0xe59580}, /* U+5540 */ + {0x9a51, 0xe595a3}, /* U+5563 */ + {0x9a52, 0xe5958c}, /* U+554C */ + {0x9a53, 0xe594ae}, /* U+552E */ + {0x9a54, 0xe5959c}, /* U+555C */ + {0x9a55, 0xe59585}, /* U+5545 */ + {0x9a56, 0xe59596}, /* U+5556 */ + {0x9a57, 0xe59597}, /* U+5557 */ + {0x9a58, 0xe594b8}, /* U+5538 */ + {0x9a59, 0xe594b3}, /* U+5533 */ + {0x9a5a, 0xe5959d}, /* U+555D */ + {0x9a5b, 0xe59699}, /* U+5599 */ + {0x9a5c, 0xe59680}, /* U+5580 */ + {0x9a5d, 0xe592af}, /* U+54AF */ + {0x9a5e, 0xe5968a}, /* U+558A */ + {0x9a5f, 0xe5969f}, /* U+559F */ + {0x9a60, 0xe595bb}, /* U+557B */ + {0x9a61, 0xe595be}, /* U+557E */ + {0x9a62, 0xe59698}, /* U+5598 */ + {0x9a63, 0xe5969e}, /* U+559E */ + {0x9a64, 0xe596ae}, /* U+55AE */ + {0x9a65, 0xe595bc}, /* U+557C */ + {0x9a66, 0xe59683}, /* U+5583 */ + {0x9a67, 0xe596a9}, /* U+55A9 */ + {0x9a68, 0xe59687}, /* U+5587 */ + {0x9a69, 0xe596a8}, /* U+55A8 */ + {0x9a6a, 0xe5979a}, /* U+55DA */ + {0x9a6b, 0xe59785}, /* U+55C5 */ + {0x9a6c, 0xe5979f}, /* U+55DF */ + {0x9a6d, 0xe59784}, /* U+55C4 */ + {0x9a6e, 0xe5979c}, /* U+55DC */ + {0x9a6f, 0xe597a4}, /* U+55E4 */ + {0x9a70, 0xe59794}, /* U+55D4 */ + {0x9a71, 0xe59894}, /* U+5614 */ + {0x9a72, 0xe597b7}, /* U+55F7 */ + {0x9a73, 0xe59896}, /* U+5616 */ + {0x9a74, 0xe597be}, /* U+55FE */ + {0x9a75, 0xe597bd}, /* U+55FD */ + {0x9a76, 0xe5989b}, /* U+561B */ + {0x9a77, 0xe597b9}, /* U+55F9 */ + {0x9a78, 0xe5998e}, /* U+564E */ + {0x9a79, 0xe59990}, /* U+5650 */ + {0x9a7a, 0xe7879f}, /* U+71DF */ + {0x9a7b, 0xe598b4}, /* U+5634 */ + {0x9a7c, 0xe598b6}, /* U+5636 */ + {0x9a7d, 0xe598b2}, /* U+5632 */ + {0x9a7e, 0xe598b8}, /* U+5638 */ + {0x9a80, 0xe599ab}, /* U+566B */ + {0x9a81, 0xe599a4}, /* U+5664 */ + {0x9a82, 0xe598af}, /* U+562F */ + {0x9a83, 0xe599ac}, /* U+566C */ + {0x9a84, 0xe599aa}, /* U+566A */ + {0x9a85, 0xe59a86}, /* U+5686 */ + {0x9a86, 0xe59a80}, /* U+5680 */ + {0x9a87, 0xe59a8a}, /* U+568A */ + {0x9a88, 0xe59aa0}, /* U+56A0 */ + {0x9a89, 0xe59a94}, /* U+5694 */ + {0x9a8a, 0xe59a8f}, /* U+568F */ + {0x9a8b, 0xe59aa5}, /* U+56A5 */ + {0x9a8c, 0xe59aae}, /* U+56AE */ + {0x9a8d, 0xe59ab6}, /* U+56B6 */ + {0x9a8e, 0xe59ab4}, /* U+56B4 */ + {0x9a8f, 0xe59b82}, /* U+56C2 */ + {0x9a90, 0xe59abc}, /* U+56BC */ + {0x9a91, 0xe59b81}, /* U+56C1 */ + {0x9a92, 0xe59b83}, /* U+56C3 */ + {0x9a93, 0xe59b80}, /* U+56C0 */ + {0x9a94, 0xe59b88}, /* U+56C8 */ + {0x9a95, 0xe59b8e}, /* U+56CE */ + {0x9a96, 0xe59b91}, /* U+56D1 */ + {0x9a97, 0xe59b93}, /* U+56D3 */ + {0x9a98, 0xe59b97}, /* U+56D7 */ + {0x9a99, 0xe59bae}, /* U+56EE */ + {0x9a9a, 0xe59bb9}, /* U+56F9 */ + {0x9a9b, 0xe59c80}, /* U+5700 */ + {0x9a9c, 0xe59bbf}, /* U+56FF */ + {0x9a9d, 0xe59c84}, /* U+5704 */ + {0x9a9e, 0xe59c89}, /* U+5709 */ + {0x9a9f, 0xe59c88}, /* U+5708 */ + {0x9aa0, 0xe59c8b}, /* U+570B */ + {0x9aa1, 0xe59c8d}, /* U+570D */ + {0x9aa2, 0xe59c93}, /* U+5713 */ + {0x9aa3, 0xe59c98}, /* U+5718 */ + {0x9aa4, 0xe59c96}, /* U+5716 */ + {0x9aa5, 0xe59787}, /* U+55C7 */ + {0x9aa6, 0xe59c9c}, /* U+571C */ + {0x9aa7, 0xe59ca6}, /* U+5726 */ + {0x9aa8, 0xe59cb7}, /* U+5737 */ + {0x9aa9, 0xe59cb8}, /* U+5738 */ + {0x9aaa, 0xe59d8e}, /* U+574E */ + {0x9aab, 0xe59cbb}, /* U+573B */ + {0x9aac, 0xe59d80}, /* U+5740 */ + {0x9aad, 0xe59d8f}, /* U+574F */ + {0x9aae, 0xe59da9}, /* U+5769 */ + {0x9aaf, 0xe59f80}, /* U+57C0 */ + {0x9ab0, 0xe59e88}, /* U+5788 */ + {0x9ab1, 0xe59da1}, /* U+5761 */ + {0x9ab2, 0xe59dbf}, /* U+577F */ + {0x9ab3, 0xe59e89}, /* U+5789 */ + {0x9ab4, 0xe59e93}, /* U+5793 */ + {0x9ab5, 0xe59ea0}, /* U+57A0 */ + {0x9ab6, 0xe59eb3}, /* U+57B3 */ + {0x9ab7, 0xe59ea4}, /* U+57A4 */ + {0x9ab8, 0xe59eaa}, /* U+57AA */ + {0x9ab9, 0xe59eb0}, /* U+57B0 */ + {0x9aba, 0xe59f83}, /* U+57C3 */ + {0x9abb, 0xe59f86}, /* U+57C6 */ + {0x9abc, 0xe59f94}, /* U+57D4 */ + {0x9abd, 0xe59f92}, /* U+57D2 */ + {0x9abe, 0xe59f93}, /* U+57D3 */ + {0x9abf, 0xe5a08a}, /* U+580A */ + {0x9ac0, 0xe59f96}, /* U+57D6 */ + {0x9ac1, 0xe59fa3}, /* U+57E3 */ + {0x9ac2, 0xe5a08b}, /* U+580B */ + {0x9ac3, 0xe5a099}, /* U+5819 */ + {0x9ac4, 0xe5a09d}, /* U+581D */ + {0x9ac5, 0xe5a1b2}, /* U+5872 */ + {0x9ac6, 0xe5a0a1}, /* U+5821 */ + {0x9ac7, 0xe5a1a2}, /* U+5862 */ + {0x9ac8, 0xe5a18b}, /* U+584B */ + {0x9ac9, 0xe5a1b0}, /* U+5870 */ + {0x9aca, 0xe6af80}, /* U+6BC0 */ + {0x9acb, 0xe5a192}, /* U+5852 */ + {0x9acc, 0xe5a0bd}, /* U+583D */ + {0x9acd, 0xe5a1b9}, /* U+5879 */ + {0x9ace, 0xe5a285}, /* U+5885 */ + {0x9acf, 0xe5a2b9}, /* U+58B9 */ + {0x9ad0, 0xe5a29f}, /* U+589F */ + {0x9ad1, 0xe5a2ab}, /* U+58AB */ + {0x9ad2, 0xe5a2ba}, /* U+58BA */ + {0x9ad3, 0xe5a39e}, /* U+58DE */ + {0x9ad4, 0xe5a2bb}, /* U+58BB */ + {0x9ad5, 0xe5a2b8}, /* U+58B8 */ + {0x9ad6, 0xe5a2ae}, /* U+58AE */ + {0x9ad7, 0xe5a385}, /* U+58C5 */ + {0x9ad8, 0xe5a393}, /* U+58D3 */ + {0x9ad9, 0xe5a391}, /* U+58D1 */ + {0x9ada, 0xe5a397}, /* U+58D7 */ + {0x9adb, 0xe5a399}, /* U+58D9 */ + {0x9adc, 0xe5a398}, /* U+58D8 */ + {0x9add, 0xe5a3a5}, /* U+58E5 */ + {0x9ade, 0xe5a39c}, /* U+58DC */ + {0x9adf, 0xe5a3a4}, /* U+58E4 */ + {0x9ae0, 0xe5a39f}, /* U+58DF */ + {0x9ae1, 0xe5a3af}, /* U+58EF */ + {0x9ae2, 0xe5a3ba}, /* U+58FA */ + {0x9ae3, 0xe5a3b9}, /* U+58F9 */ + {0x9ae4, 0xe5a3bb}, /* U+58FB */ + {0x9ae5, 0xe5a3bc}, /* U+58FC */ + {0x9ae6, 0xe5a3bd}, /* U+58FD */ + {0x9ae7, 0xe5a482}, /* U+5902 */ + {0x9ae8, 0xe5a48a}, /* U+590A */ + {0x9ae9, 0xe5a490}, /* U+5910 */ + {0x9aea, 0xe5a49b}, /* U+591B */ + {0x9aeb, 0xe6a2a6}, /* U+68A6 */ + {0x9aec, 0xe5a4a5}, /* U+5925 */ + {0x9aed, 0xe5a4ac}, /* U+592C */ + {0x9aee, 0xe5a4ad}, /* U+592D */ + {0x9aef, 0xe5a4b2}, /* U+5932 */ + {0x9af0, 0xe5a4b8}, /* U+5938 */ + {0x9af1, 0xe5a4be}, /* U+593E */ + {0x9af2, 0xe7ab92}, /* U+7AD2 */ + {0x9af3, 0xe5a595}, /* U+5955 */ + {0x9af4, 0xe5a590}, /* U+5950 */ + {0x9af5, 0xe5a58e}, /* U+594E */ + {0x9af6, 0xe5a59a}, /* U+595A */ + {0x9af7, 0xe5a598}, /* U+5958 */ + {0x9af8, 0xe5a5a2}, /* U+5962 */ + {0x9af9, 0xe5a5a0}, /* U+5960 */ + {0x9afa, 0xe5a5a7}, /* U+5967 */ + {0x9afb, 0xe5a5ac}, /* U+596C */ + {0x9afc, 0xe5a5a9}, /* U+5969 */ + {0x9b40, 0xe5a5b8}, /* U+5978 */ + {0x9b41, 0xe5a681}, /* U+5981 */ + {0x9b42, 0xe5a69d}, /* U+599D */ + {0x9b43, 0xe4bd9e}, /* U+4F5E */ + {0x9b44, 0xe4beab}, /* U+4FAB */ + {0x9b45, 0xe5a6a3}, /* U+59A3 */ + {0x9b46, 0xe5a6b2}, /* U+59B2 */ + {0x9b47, 0xe5a786}, /* U+59C6 */ + {0x9b48, 0xe5a7a8}, /* U+59E8 */ + {0x9b49, 0xe5a79c}, /* U+59DC */ + {0x9b4a, 0xe5a68d}, /* U+598D */ + {0x9b4b, 0xe5a799}, /* U+59D9 */ + {0x9b4c, 0xe5a79a}, /* U+59DA */ + {0x9b4d, 0xe5a8a5}, /* U+5A25 */ + {0x9b4e, 0xe5a89f}, /* U+5A1F */ + {0x9b4f, 0xe5a891}, /* U+5A11 */ + {0x9b50, 0xe5a89c}, /* U+5A1C */ + {0x9b51, 0xe5a889}, /* U+5A09 */ + {0x9b52, 0xe5a89a}, /* U+5A1A */ + {0x9b53, 0xe5a980}, /* U+5A40 */ + {0x9b54, 0xe5a9ac}, /* U+5A6C */ + {0x9b55, 0xe5a989}, /* U+5A49 */ + {0x9b56, 0xe5a8b5}, /* U+5A35 */ + {0x9b57, 0xe5a8b6}, /* U+5A36 */ + {0x9b58, 0xe5a9a2}, /* U+5A62 */ + {0x9b59, 0xe5a9aa}, /* U+5A6A */ + {0x9b5a, 0xe5aa9a}, /* U+5A9A */ + {0x9b5b, 0xe5aabc}, /* U+5ABC */ + {0x9b5c, 0xe5aabe}, /* U+5ABE */ + {0x9b5d, 0xe5ab8b}, /* U+5ACB */ + {0x9b5e, 0xe5ab82}, /* U+5AC2 */ + {0x9b5f, 0xe5aabd}, /* U+5ABD */ + {0x9b60, 0xe5aba3}, /* U+5AE3 */ + {0x9b61, 0xe5ab97}, /* U+5AD7 */ + {0x9b62, 0xe5aba6}, /* U+5AE6 */ + {0x9b63, 0xe5aba9}, /* U+5AE9 */ + {0x9b64, 0xe5ab96}, /* U+5AD6 */ + {0x9b65, 0xe5abba}, /* U+5AFA */ + {0x9b66, 0xe5abbb}, /* U+5AFB */ + {0x9b67, 0xe5ac8c}, /* U+5B0C */ + {0x9b68, 0xe5ac8b}, /* U+5B0B */ + {0x9b69, 0xe5ac96}, /* U+5B16 */ + {0x9b6a, 0xe5acb2}, /* U+5B32 */ + {0x9b6b, 0xe5ab90}, /* U+5AD0 */ + {0x9b6c, 0xe5acaa}, /* U+5B2A */ + {0x9b6d, 0xe5acb6}, /* U+5B36 */ + {0x9b6e, 0xe5acbe}, /* U+5B3E */ + {0x9b6f, 0xe5ad83}, /* U+5B43 */ + {0x9b70, 0xe5ad85}, /* U+5B45 */ + {0x9b71, 0xe5ad80}, /* U+5B40 */ + {0x9b72, 0xe5ad91}, /* U+5B51 */ + {0x9b73, 0xe5ad95}, /* U+5B55 */ + {0x9b74, 0xe5ad9a}, /* U+5B5A */ + {0x9b75, 0xe5ad9b}, /* U+5B5B */ + {0x9b76, 0xe5ada5}, /* U+5B65 */ + {0x9b77, 0xe5ada9}, /* U+5B69 */ + {0x9b78, 0xe5adb0}, /* U+5B70 */ + {0x9b79, 0xe5adb3}, /* U+5B73 */ + {0x9b7a, 0xe5adb5}, /* U+5B75 */ + {0x9b7b, 0xe5adb8}, /* U+5B78 */ + {0x9b7c, 0xe69688}, /* U+6588 */ + {0x9b7d, 0xe5adba}, /* U+5B7A */ + {0x9b7e, 0xe5ae80}, /* U+5B80 */ + {0x9b80, 0xe5ae83}, /* U+5B83 */ + {0x9b81, 0xe5aea6}, /* U+5BA6 */ + {0x9b82, 0xe5aeb8}, /* U+5BB8 */ + {0x9b83, 0xe5af83}, /* U+5BC3 */ + {0x9b84, 0xe5af87}, /* U+5BC7 */ + {0x9b85, 0xe5af89}, /* U+5BC9 */ + {0x9b86, 0xe5af94}, /* U+5BD4 */ + {0x9b87, 0xe5af90}, /* U+5BD0 */ + {0x9b88, 0xe5afa4}, /* U+5BE4 */ + {0x9b89, 0xe5afa6}, /* U+5BE6 */ + {0x9b8a, 0xe5afa2}, /* U+5BE2 */ + {0x9b8b, 0xe5af9e}, /* U+5BDE */ + {0x9b8c, 0xe5afa5}, /* U+5BE5 */ + {0x9b8d, 0xe5afab}, /* U+5BEB */ + {0x9b8e, 0xe5afb0}, /* U+5BF0 */ + {0x9b8f, 0xe5afb6}, /* U+5BF6 */ + {0x9b90, 0xe5afb3}, /* U+5BF3 */ + {0x9b91, 0xe5b085}, /* U+5C05 */ + {0x9b92, 0xe5b087}, /* U+5C07 */ + {0x9b93, 0xe5b088}, /* U+5C08 */ + {0x9b94, 0xe5b08d}, /* U+5C0D */ + {0x9b95, 0xe5b093}, /* U+5C13 */ + {0x9b96, 0xe5b0a0}, /* U+5C20 */ + {0x9b97, 0xe5b0a2}, /* U+5C22 */ + {0x9b98, 0xe5b0a8}, /* U+5C28 */ + {0x9b99, 0xe5b0b8}, /* U+5C38 */ + {0x9b9a, 0xe5b0b9}, /* U+5C39 */ + {0x9b9b, 0xe5b181}, /* U+5C41 */ + {0x9b9c, 0xe5b186}, /* U+5C46 */ + {0x9b9d, 0xe5b18e}, /* U+5C4E */ + {0x9b9e, 0xe5b193}, /* U+5C53 */ + {0x9b9f, 0xe5b190}, /* U+5C50 */ + {0x9ba0, 0xe5b18f}, /* U+5C4F */ + {0x9ba1, 0xe5adb1}, /* U+5B71 */ + {0x9ba2, 0xe5b1ac}, /* U+5C6C */ + {0x9ba3, 0xe5b1ae}, /* U+5C6E */ + {0x9ba4, 0xe4b9a2}, /* U+4E62 */ + {0x9ba5, 0xe5b1b6}, /* U+5C76 */ + {0x9ba6, 0xe5b1b9}, /* U+5C79 */ + {0x9ba7, 0xe5b28c}, /* U+5C8C */ + {0x9ba8, 0xe5b291}, /* U+5C91 */ + {0x9ba9, 0xe5b294}, /* U+5C94 */ + {0x9baa, 0xe5a69b}, /* U+599B */ + {0x9bab, 0xe5b2ab}, /* U+5CAB */ + {0x9bac, 0xe5b2bb}, /* U+5CBB */ + {0x9bad, 0xe5b2b6}, /* U+5CB6 */ + {0x9bae, 0xe5b2bc}, /* U+5CBC */ + {0x9baf, 0xe5b2b7}, /* U+5CB7 */ + {0x9bb0, 0xe5b385}, /* U+5CC5 */ + {0x9bb1, 0xe5b2be}, /* U+5CBE */ + {0x9bb2, 0xe5b387}, /* U+5CC7 */ + {0x9bb3, 0xe5b399}, /* U+5CD9 */ + {0x9bb4, 0xe5b3a9}, /* U+5CE9 */ + {0x9bb5, 0xe5b3bd}, /* U+5CFD */ + {0x9bb6, 0xe5b3ba}, /* U+5CFA */ + {0x9bb7, 0xe5b3ad}, /* U+5CED */ + {0x9bb8, 0xe5b68c}, /* U+5D8C */ + {0x9bb9, 0xe5b3aa}, /* U+5CEA */ + {0x9bba, 0xe5b48b}, /* U+5D0B */ + {0x9bbb, 0xe5b495}, /* U+5D15 */ + {0x9bbc, 0xe5b497}, /* U+5D17 */ + {0x9bbd, 0xe5b59c}, /* U+5D5C */ + {0x9bbe, 0xe5b49f}, /* U+5D1F */ + {0x9bbf, 0xe5b49b}, /* U+5D1B */ + {0x9bc0, 0xe5b491}, /* U+5D11 */ + {0x9bc1, 0xe5b494}, /* U+5D14 */ + {0x9bc2, 0xe5b4a2}, /* U+5D22 */ + {0x9bc3, 0xe5b49a}, /* U+5D1A */ + {0x9bc4, 0xe5b499}, /* U+5D19 */ + {0x9bc5, 0xe5b498}, /* U+5D18 */ + {0x9bc6, 0xe5b58c}, /* U+5D4C */ + {0x9bc7, 0xe5b592}, /* U+5D52 */ + {0x9bc8, 0xe5b58e}, /* U+5D4E */ + {0x9bc9, 0xe5b58b}, /* U+5D4B */ + {0x9bca, 0xe5b5ac}, /* U+5D6C */ + {0x9bcb, 0xe5b5b3}, /* U+5D73 */ + {0x9bcc, 0xe5b5b6}, /* U+5D76 */ + {0x9bcd, 0xe5b687}, /* U+5D87 */ + {0x9bce, 0xe5b684}, /* U+5D84 */ + {0x9bcf, 0xe5b682}, /* U+5D82 */ + {0x9bd0, 0xe5b6a2}, /* U+5DA2 */ + {0x9bd1, 0xe5b69d}, /* U+5D9D */ + {0x9bd2, 0xe5b6ac}, /* U+5DAC */ + {0x9bd3, 0xe5b6ae}, /* U+5DAE */ + {0x9bd4, 0xe5b6bd}, /* U+5DBD */ + {0x9bd5, 0xe5b690}, /* U+5D90 */ + {0x9bd6, 0xe5b6b7}, /* U+5DB7 */ + {0x9bd7, 0xe5b6bc}, /* U+5DBC */ + {0x9bd8, 0xe5b789}, /* U+5DC9 */ + {0x9bd9, 0xe5b78d}, /* U+5DCD */ + {0x9bda, 0xe5b793}, /* U+5DD3 */ + {0x9bdb, 0xe5b792}, /* U+5DD2 */ + {0x9bdc, 0xe5b796}, /* U+5DD6 */ + {0x9bdd, 0xe5b79b}, /* U+5DDB */ + {0x9bde, 0xe5b7ab}, /* U+5DEB */ + {0x9bdf, 0xe5b7b2}, /* U+5DF2 */ + {0x9be0, 0xe5b7b5}, /* U+5DF5 */ + {0x9be1, 0xe5b88b}, /* U+5E0B */ + {0x9be2, 0xe5b89a}, /* U+5E1A */ + {0x9be3, 0xe5b899}, /* U+5E19 */ + {0x9be4, 0xe5b891}, /* U+5E11 */ + {0x9be5, 0xe5b89b}, /* U+5E1B */ + {0x9be6, 0xe5b8b6}, /* U+5E36 */ + {0x9be7, 0xe5b8b7}, /* U+5E37 */ + {0x9be8, 0xe5b984}, /* U+5E44 */ + {0x9be9, 0xe5b983}, /* U+5E43 */ + {0x9bea, 0xe5b980}, /* U+5E40 */ + {0x9beb, 0xe5b98e}, /* U+5E4E */ + {0x9bec, 0xe5b997}, /* U+5E57 */ + {0x9bed, 0xe5b994}, /* U+5E54 */ + {0x9bee, 0xe5b99f}, /* U+5E5F */ + {0x9bef, 0xe5b9a2}, /* U+5E62 */ + {0x9bf0, 0xe5b9a4}, /* U+5E64 */ + {0x9bf1, 0xe5b987}, /* U+5E47 */ + {0x9bf2, 0xe5b9b5}, /* U+5E75 */ + {0x9bf3, 0xe5b9b6}, /* U+5E76 */ + {0x9bf4, 0xe5b9ba}, /* U+5E7A */ + {0x9bf5, 0xe9babc}, /* U+9EBC */ + {0x9bf6, 0xe5b9bf}, /* U+5E7F */ + {0x9bf7, 0xe5baa0}, /* U+5EA0 */ + {0x9bf8, 0xe5bb81}, /* U+5EC1 */ + {0x9bf9, 0xe5bb82}, /* U+5EC2 */ + {0x9bfa, 0xe5bb88}, /* U+5EC8 */ + {0x9bfb, 0xe5bb90}, /* U+5ED0 */ + {0x9bfc, 0xe5bb8f}, /* U+5ECF */ + {0x9c40, 0xe5bb96}, /* U+5ED6 */ + {0x9c41, 0xe5bba3}, /* U+5EE3 */ + {0x9c42, 0xe5bb9d}, /* U+5EDD */ + {0x9c43, 0xe5bb9a}, /* U+5EDA */ + {0x9c44, 0xe5bb9b}, /* U+5EDB */ + {0x9c45, 0xe5bba2}, /* U+5EE2 */ + {0x9c46, 0xe5bba1}, /* U+5EE1 */ + {0x9c47, 0xe5bba8}, /* U+5EE8 */ + {0x9c48, 0xe5bba9}, /* U+5EE9 */ + {0x9c49, 0xe5bbac}, /* U+5EEC */ + {0x9c4a, 0xe5bbb1}, /* U+5EF1 */ + {0x9c4b, 0xe5bbb3}, /* U+5EF3 */ + {0x9c4c, 0xe5bbb0}, /* U+5EF0 */ + {0x9c4d, 0xe5bbb4}, /* U+5EF4 */ + {0x9c4e, 0xe5bbb8}, /* U+5EF8 */ + {0x9c4f, 0xe5bbbe}, /* U+5EFE */ + {0x9c50, 0xe5bc83}, /* U+5F03 */ + {0x9c51, 0xe5bc89}, /* U+5F09 */ + {0x9c52, 0xe5bd9d}, /* U+5F5D */ + {0x9c53, 0xe5bd9c}, /* U+5F5C */ + {0x9c54, 0xe5bc8b}, /* U+5F0B */ + {0x9c55, 0xe5bc91}, /* U+5F11 */ + {0x9c56, 0xe5bc96}, /* U+5F16 */ + {0x9c57, 0xe5bca9}, /* U+5F29 */ + {0x9c58, 0xe5bcad}, /* U+5F2D */ + {0x9c59, 0xe5bcb8}, /* U+5F38 */ + {0x9c5a, 0xe5bd81}, /* U+5F41 */ + {0x9c5b, 0xe5bd88}, /* U+5F48 */ + {0x9c5c, 0xe5bd8c}, /* U+5F4C */ + {0x9c5d, 0xe5bd8e}, /* U+5F4E */ + {0x9c5e, 0xe5bcaf}, /* U+5F2F */ + {0x9c5f, 0xe5bd91}, /* U+5F51 */ + {0x9c60, 0xe5bd96}, /* U+5F56 */ + {0x9c61, 0xe5bd97}, /* U+5F57 */ + {0x9c62, 0xe5bd99}, /* U+5F59 */ + {0x9c63, 0xe5bda1}, /* U+5F61 */ + {0x9c64, 0xe5bdad}, /* U+5F6D */ + {0x9c65, 0xe5bdb3}, /* U+5F73 */ + {0x9c66, 0xe5bdb7}, /* U+5F77 */ + {0x9c67, 0xe5be83}, /* U+5F83 */ + {0x9c68, 0xe5be82}, /* U+5F82 */ + {0x9c69, 0xe5bdbf}, /* U+5F7F */ + {0x9c6a, 0xe5be8a}, /* U+5F8A */ + {0x9c6b, 0xe5be88}, /* U+5F88 */ + {0x9c6c, 0xe5be91}, /* U+5F91 */ + {0x9c6d, 0xe5be87}, /* U+5F87 */ + {0x9c6e, 0xe5be9e}, /* U+5F9E */ + {0x9c6f, 0xe5be99}, /* U+5F99 */ + {0x9c70, 0xe5be98}, /* U+5F98 */ + {0x9c71, 0xe5bea0}, /* U+5FA0 */ + {0x9c72, 0xe5bea8}, /* U+5FA8 */ + {0x9c73, 0xe5bead}, /* U+5FAD */ + {0x9c74, 0xe5bebc}, /* U+5FBC */ + {0x9c75, 0xe5bf96}, /* U+5FD6 */ + {0x9c76, 0xe5bfbb}, /* U+5FFB */ + {0x9c77, 0xe5bfa4}, /* U+5FE4 */ + {0x9c78, 0xe5bfb8}, /* U+5FF8 */ + {0x9c79, 0xe5bfb1}, /* U+5FF1 */ + {0x9c7a, 0xe5bf9d}, /* U+5FDD */ + {0x9c7b, 0xe682b3}, /* U+60B3 */ + {0x9c7c, 0xe5bfbf}, /* U+5FFF */ + {0x9c7d, 0xe680a1}, /* U+6021 */ + {0x9c7e, 0xe681a0}, /* U+6060 */ + {0x9c80, 0xe68099}, /* U+6019 */ + {0x9c81, 0xe68090}, /* U+6010 */ + {0x9c82, 0xe680a9}, /* U+6029 */ + {0x9c83, 0xe6808e}, /* U+600E */ + {0x9c84, 0xe680b1}, /* U+6031 */ + {0x9c85, 0xe6809b}, /* U+601B */ + {0x9c86, 0xe68095}, /* U+6015 */ + {0x9c87, 0xe680ab}, /* U+602B */ + {0x9c88, 0xe680a6}, /* U+6026 */ + {0x9c89, 0xe6808f}, /* U+600F */ + {0x9c8a, 0xe680ba}, /* U+603A */ + {0x9c8b, 0xe6819a}, /* U+605A */ + {0x9c8c, 0xe68181}, /* U+6041 */ + {0x9c8d, 0xe681aa}, /* U+606A */ + {0x9c8e, 0xe681b7}, /* U+6077 */ + {0x9c8f, 0xe6819f}, /* U+605F */ + {0x9c90, 0xe6818a}, /* U+604A */ + {0x9c91, 0xe68186}, /* U+6046 */ + {0x9c92, 0xe6818d}, /* U+604D */ + {0x9c93, 0xe681a3}, /* U+6063 */ + {0x9c94, 0xe68183}, /* U+6043 */ + {0x9c95, 0xe681a4}, /* U+6064 */ + {0x9c96, 0xe68182}, /* U+6042 */ + {0x9c97, 0xe681ac}, /* U+606C */ + {0x9c98, 0xe681ab}, /* U+606B */ + {0x9c99, 0xe68199}, /* U+6059 */ + {0x9c9a, 0xe68281}, /* U+6081 */ + {0x9c9b, 0xe6828d}, /* U+608D */ + {0x9c9c, 0xe683a7}, /* U+60E7 */ + {0x9c9d, 0xe68283}, /* U+6083 */ + {0x9c9e, 0xe6829a}, /* U+609A */ + {0x9c9f, 0xe68284}, /* U+6084 */ + {0x9ca0, 0xe6829b}, /* U+609B */ + {0x9ca1, 0xe68296}, /* U+6096 */ + {0x9ca2, 0xe68297}, /* U+6097 */ + {0x9ca3, 0xe68292}, /* U+6092 */ + {0x9ca4, 0xe682a7}, /* U+60A7 */ + {0x9ca5, 0xe6828b}, /* U+608B */ + {0x9ca6, 0xe683a1}, /* U+60E1 */ + {0x9ca7, 0xe682b8}, /* U+60B8 */ + {0x9ca8, 0xe683a0}, /* U+60E0 */ + {0x9ca9, 0xe68393}, /* U+60D3 */ + {0x9caa, 0xe682b4}, /* U+60B4 */ + {0x9cab, 0xe5bfb0}, /* U+5FF0 */ + {0x9cac, 0xe682bd}, /* U+60BD */ + {0x9cad, 0xe68386}, /* U+60C6 */ + {0x9cae, 0xe682b5}, /* U+60B5 */ + {0x9caf, 0xe68398}, /* U+60D8 */ + {0x9cb0, 0xe6858d}, /* U+614D */ + {0x9cb1, 0xe68495}, /* U+6115 */ + {0x9cb2, 0xe68486}, /* U+6106 */ + {0x9cb3, 0xe683b6}, /* U+60F6 */ + {0x9cb4, 0xe683b7}, /* U+60F7 */ + {0x9cb5, 0xe68480}, /* U+6100 */ + {0x9cb6, 0xe683b4}, /* U+60F4 */ + {0x9cb7, 0xe683ba}, /* U+60FA */ + {0x9cb8, 0xe68483}, /* U+6103 */ + {0x9cb9, 0xe684a1}, /* U+6121 */ + {0x9cba, 0xe683bb}, /* U+60FB */ + {0x9cbb, 0xe683b1}, /* U+60F1 */ + {0x9cbc, 0xe6848d}, /* U+610D */ + {0x9cbd, 0xe6848e}, /* U+610E */ + {0x9cbe, 0xe68587}, /* U+6147 */ + {0x9cbf, 0xe684be}, /* U+613E */ + {0x9cc0, 0xe684a8}, /* U+6128 */ + {0x9cc1, 0xe684a7}, /* U+6127 */ + {0x9cc2, 0xe6858a}, /* U+614A */ + {0x9cc3, 0xe684bf}, /* U+613F */ + {0x9cc4, 0xe684bc}, /* U+613C */ + {0x9cc5, 0xe684ac}, /* U+612C */ + {0x9cc6, 0xe684b4}, /* U+6134 */ + {0x9cc7, 0xe684bd}, /* U+613D */ + {0x9cc8, 0xe68582}, /* U+6142 */ + {0x9cc9, 0xe68584}, /* U+6144 */ + {0x9cca, 0xe685b3}, /* U+6173 */ + {0x9ccb, 0xe685b7}, /* U+6177 */ + {0x9ccc, 0xe68598}, /* U+6158 */ + {0x9ccd, 0xe68599}, /* U+6159 */ + {0x9cce, 0xe6859a}, /* U+615A */ + {0x9ccf, 0xe685ab}, /* U+616B */ + {0x9cd0, 0xe685b4}, /* U+6174 */ + {0x9cd1, 0xe685af}, /* U+616F */ + {0x9cd2, 0xe685a5}, /* U+6165 */ + {0x9cd3, 0xe685b1}, /* U+6171 */ + {0x9cd4, 0xe6859f}, /* U+615F */ + {0x9cd5, 0xe6859d}, /* U+615D */ + {0x9cd6, 0xe68593}, /* U+6153 */ + {0x9cd7, 0xe685b5}, /* U+6175 */ + {0x9cd8, 0xe68699}, /* U+6199 */ + {0x9cd9, 0xe68696}, /* U+6196 */ + {0x9cda, 0xe68687}, /* U+6187 */ + {0x9cdb, 0xe686ac}, /* U+61AC */ + {0x9cdc, 0xe68694}, /* U+6194 */ + {0x9cdd, 0xe6869a}, /* U+619A */ + {0x9cde, 0xe6868a}, /* U+618A */ + {0x9cdf, 0xe68691}, /* U+6191 */ + {0x9ce0, 0xe686ab}, /* U+61AB */ + {0x9ce1, 0xe686ae}, /* U+61AE */ + {0x9ce2, 0xe6878c}, /* U+61CC */ + {0x9ce3, 0xe6878a}, /* U+61CA */ + {0x9ce4, 0xe68789}, /* U+61C9 */ + {0x9ce5, 0xe687b7}, /* U+61F7 */ + {0x9ce6, 0xe68788}, /* U+61C8 */ + {0x9ce7, 0xe68783}, /* U+61C3 */ + {0x9ce8, 0xe68786}, /* U+61C6 */ + {0x9ce9, 0xe686ba}, /* U+61BA */ + {0x9cea, 0xe6878b}, /* U+61CB */ + {0x9ceb, 0xe7bdb9}, /* U+7F79 */ + {0x9cec, 0xe6878d}, /* U+61CD */ + {0x9ced, 0xe687a6}, /* U+61E6 */ + {0x9cee, 0xe687a3}, /* U+61E3 */ + {0x9cef, 0xe687b6}, /* U+61F6 */ + {0x9cf0, 0xe687ba}, /* U+61FA */ + {0x9cf1, 0xe687b4}, /* U+61F4 */ + {0x9cf2, 0xe687bf}, /* U+61FF */ + {0x9cf3, 0xe687bd}, /* U+61FD */ + {0x9cf4, 0xe687bc}, /* U+61FC */ + {0x9cf5, 0xe687be}, /* U+61FE */ + {0x9cf6, 0xe68880}, /* U+6200 */ + {0x9cf7, 0xe68888}, /* U+6208 */ + {0x9cf8, 0xe68889}, /* U+6209 */ + {0x9cf9, 0xe6888d}, /* U+620D */ + {0x9cfa, 0xe6888c}, /* U+620C */ + {0x9cfb, 0xe68894}, /* U+6214 */ + {0x9cfc, 0xe6889b}, /* U+621B */ + {0x9d40, 0xe6889e}, /* U+621E */ + {0x9d41, 0xe688a1}, /* U+6221 */ + {0x9d42, 0xe688aa}, /* U+622A */ + {0x9d43, 0xe688ae}, /* U+622E */ + {0x9d44, 0xe688b0}, /* U+6230 */ + {0x9d45, 0xe688b2}, /* U+6232 */ + {0x9d46, 0xe688b3}, /* U+6233 */ + {0x9d47, 0xe68981}, /* U+6241 */ + {0x9d48, 0xe6898e}, /* U+624E */ + {0x9d49, 0xe6899e}, /* U+625E */ + {0x9d4a, 0xe689a3}, /* U+6263 */ + {0x9d4b, 0xe6899b}, /* U+625B */ + {0x9d4c, 0xe689a0}, /* U+6260 */ + {0x9d4d, 0xe689a8}, /* U+6268 */ + {0x9d4e, 0xe689bc}, /* U+627C */ + {0x9d4f, 0xe68a82}, /* U+6282 */ + {0x9d50, 0xe68a89}, /* U+6289 */ + {0x9d51, 0xe689be}, /* U+627E */ + {0x9d52, 0xe68a92}, /* U+6292 */ + {0x9d53, 0xe68a93}, /* U+6293 */ + {0x9d54, 0xe68a96}, /* U+6296 */ + {0x9d55, 0xe68b94}, /* U+62D4 */ + {0x9d56, 0xe68a83}, /* U+6283 */ + {0x9d57, 0xe68a94}, /* U+6294 */ + {0x9d58, 0xe68b97}, /* U+62D7 */ + {0x9d59, 0xe68b91}, /* U+62D1 */ + {0x9d5a, 0xe68abb}, /* U+62BB */ + {0x9d5b, 0xe68b8f}, /* U+62CF */ + {0x9d5c, 0xe68bbf}, /* U+62FF */ + {0x9d5d, 0xe68b86}, /* U+62C6 */ + {0x9d5e, 0xe69394}, /* U+64D4 */ + {0x9d5f, 0xe68b88}, /* U+62C8 */ + {0x9d60, 0xe68b9c}, /* U+62DC */ + {0x9d61, 0xe68b8c}, /* U+62CC */ + {0x9d62, 0xe68b8a}, /* U+62CA */ + {0x9d63, 0xe68b82}, /* U+62C2 */ + {0x9d64, 0xe68b87}, /* U+62C7 */ + {0x9d65, 0xe68a9b}, /* U+629B */ + {0x9d66, 0xe68b89}, /* U+62C9 */ + {0x9d67, 0xe68c8c}, /* U+630C */ + {0x9d68, 0xe68bae}, /* U+62EE */ + {0x9d69, 0xe68bb1}, /* U+62F1 */ + {0x9d6a, 0xe68ca7}, /* U+6327 */ + {0x9d6b, 0xe68c82}, /* U+6302 */ + {0x9d6c, 0xe68c88}, /* U+6308 */ + {0x9d6d, 0xe68baf}, /* U+62EF */ + {0x9d6e, 0xe68bb5}, /* U+62F5 */ + {0x9d6f, 0xe68d90}, /* U+6350 */ + {0x9d70, 0xe68cbe}, /* U+633E */ + {0x9d71, 0xe68d8d}, /* U+634D */ + {0x9d72, 0xe6909c}, /* U+641C */ + {0x9d73, 0xe68d8f}, /* U+634F */ + {0x9d74, 0xe68e96}, /* U+6396 */ + {0x9d75, 0xe68e8e}, /* U+638E */ + {0x9d76, 0xe68e80}, /* U+6380 */ + {0x9d77, 0xe68eab}, /* U+63AB */ + {0x9d78, 0xe68db6}, /* U+6376 */ + {0x9d79, 0xe68ea3}, /* U+63A3 */ + {0x9d7a, 0xe68e8f}, /* U+638F */ + {0x9d7b, 0xe68e89}, /* U+6389 */ + {0x9d7c, 0xe68e9f}, /* U+639F */ + {0x9d7d, 0xe68eb5}, /* U+63B5 */ + {0x9d7e, 0xe68dab}, /* U+636B */ + {0x9d80, 0xe68da9}, /* U+6369 */ + {0x9d81, 0xe68ebe}, /* U+63BE */ + {0x9d82, 0xe68fa9}, /* U+63E9 */ + {0x9d83, 0xe68f80}, /* U+63C0 */ + {0x9d84, 0xe68f86}, /* U+63C6 */ + {0x9d85, 0xe68fa3}, /* U+63E3 */ + {0x9d86, 0xe68f89}, /* U+63C9 */ + {0x9d87, 0xe68f92}, /* U+63D2 */ + {0x9d88, 0xe68fb6}, /* U+63F6 */ + {0x9d89, 0xe68f84}, /* U+63C4 */ + {0x9d8a, 0xe69096}, /* U+6416 */ + {0x9d8b, 0xe690b4}, /* U+6434 */ + {0x9d8c, 0xe69086}, /* U+6406 */ + {0x9d8d, 0xe69093}, /* U+6413 */ + {0x9d8e, 0xe690a6}, /* U+6426 */ + {0x9d8f, 0xe690b6}, /* U+6436 */ + {0x9d90, 0xe6949d}, /* U+651D */ + {0x9d91, 0xe69097}, /* U+6417 */ + {0x9d92, 0xe690a8}, /* U+6428 */ + {0x9d93, 0xe6908f}, /* U+640F */ + {0x9d94, 0xe691a7}, /* U+6467 */ + {0x9d95, 0xe691af}, /* U+646F */ + {0x9d96, 0xe691b6}, /* U+6476 */ + {0x9d97, 0xe6918e}, /* U+644E */ + {0x9d98, 0xe694aa}, /* U+652A */ + {0x9d99, 0xe69295}, /* U+6495 */ + {0x9d9a, 0xe69293}, /* U+6493 */ + {0x9d9b, 0xe692a5}, /* U+64A5 */ + {0x9d9c, 0xe692a9}, /* U+64A9 */ + {0x9d9d, 0xe69288}, /* U+6488 */ + {0x9d9e, 0xe692bc}, /* U+64BC */ + {0x9d9f, 0xe6939a}, /* U+64DA */ + {0x9da0, 0xe69392}, /* U+64D2 */ + {0x9da1, 0xe69385}, /* U+64C5 */ + {0x9da2, 0xe69387}, /* U+64C7 */ + {0x9da3, 0xe692bb}, /* U+64BB */ + {0x9da4, 0xe69398}, /* U+64D8 */ + {0x9da5, 0xe69382}, /* U+64C2 */ + {0x9da6, 0xe693b1}, /* U+64F1 */ + {0x9da7, 0xe693a7}, /* U+64E7 */ + {0x9da8, 0xe88889}, /* U+8209 */ + {0x9da9, 0xe693a0}, /* U+64E0 */ + {0x9daa, 0xe693a1}, /* U+64E1 */ + {0x9dab, 0xe68aac}, /* U+62AC */ + {0x9dac, 0xe693a3}, /* U+64E3 */ + {0x9dad, 0xe693af}, /* U+64EF */ + {0x9dae, 0xe694ac}, /* U+652C */ + {0x9daf, 0xe693b6}, /* U+64F6 */ + {0x9db0, 0xe693b4}, /* U+64F4 */ + {0x9db1, 0xe693b2}, /* U+64F2 */ + {0x9db2, 0xe693ba}, /* U+64FA */ + {0x9db3, 0xe69480}, /* U+6500 */ + {0x9db4, 0xe693bd}, /* U+64FD */ + {0x9db5, 0xe69498}, /* U+6518 */ + {0x9db6, 0xe6949c}, /* U+651C */ + {0x9db7, 0xe69485}, /* U+6505 */ + {0x9db8, 0xe694a4}, /* U+6524 */ + {0x9db9, 0xe694a3}, /* U+6523 */ + {0x9dba, 0xe694ab}, /* U+652B */ + {0x9dbb, 0xe694b4}, /* U+6534 */ + {0x9dbc, 0xe694b5}, /* U+6535 */ + {0x9dbd, 0xe694b7}, /* U+6537 */ + {0x9dbe, 0xe694b6}, /* U+6536 */ + {0x9dbf, 0xe694b8}, /* U+6538 */ + {0x9dc0, 0xe7958b}, /* U+754B */ + {0x9dc1, 0xe69588}, /* U+6548 */ + {0x9dc2, 0xe69596}, /* U+6556 */ + {0x9dc3, 0xe69595}, /* U+6555 */ + {0x9dc4, 0xe6958d}, /* U+654D */ + {0x9dc5, 0xe69598}, /* U+6558 */ + {0x9dc6, 0xe6959e}, /* U+655E */ + {0x9dc7, 0xe6959d}, /* U+655D */ + {0x9dc8, 0xe695b2}, /* U+6572 */ + {0x9dc9, 0xe695b8}, /* U+6578 */ + {0x9dca, 0xe69682}, /* U+6582 */ + {0x9dcb, 0xe69683}, /* U+6583 */ + {0x9dcc, 0xe8ae8a}, /* U+8B8A */ + {0x9dcd, 0xe6969b}, /* U+659B */ + {0x9dce, 0xe6969f}, /* U+659F */ + {0x9dcf, 0xe696ab}, /* U+65AB */ + {0x9dd0, 0xe696b7}, /* U+65B7 */ + {0x9dd1, 0xe69783}, /* U+65C3 */ + {0x9dd2, 0xe69786}, /* U+65C6 */ + {0x9dd3, 0xe69781}, /* U+65C1 */ + {0x9dd4, 0xe69784}, /* U+65C4 */ + {0x9dd5, 0xe6978c}, /* U+65CC */ + {0x9dd6, 0xe69792}, /* U+65D2 */ + {0x9dd7, 0xe6979b}, /* U+65DB */ + {0x9dd8, 0xe69799}, /* U+65D9 */ + {0x9dd9, 0xe697a0}, /* U+65E0 */ + {0x9dda, 0xe697a1}, /* U+65E1 */ + {0x9ddb, 0xe697b1}, /* U+65F1 */ + {0x9ddc, 0xe69db2}, /* U+6772 */ + {0x9ddd, 0xe6988a}, /* U+660A */ + {0x9dde, 0xe69883}, /* U+6603 */ + {0x9ddf, 0xe697bb}, /* U+65FB */ + {0x9de0, 0xe69db3}, /* U+6773 */ + {0x9de1, 0xe698b5}, /* U+6635 */ + {0x9de2, 0xe698b6}, /* U+6636 */ + {0x9de3, 0xe698b4}, /* U+6634 */ + {0x9de4, 0xe6989c}, /* U+661C */ + {0x9de5, 0xe6998f}, /* U+664F */ + {0x9de6, 0xe69984}, /* U+6644 */ + {0x9de7, 0xe69989}, /* U+6649 */ + {0x9de8, 0xe69981}, /* U+6641 */ + {0x9de9, 0xe6999e}, /* U+665E */ + {0x9dea, 0xe6999d}, /* U+665D */ + {0x9deb, 0xe699a4}, /* U+6664 */ + {0x9dec, 0xe699a7}, /* U+6667 */ + {0x9ded, 0xe699a8}, /* U+6668 */ + {0x9dee, 0xe6999f}, /* U+665F */ + {0x9def, 0xe699a2}, /* U+6662 */ + {0x9df0, 0xe699b0}, /* U+6670 */ + {0x9df1, 0xe69a83}, /* U+6683 */ + {0x9df2, 0xe69a88}, /* U+6688 */ + {0x9df3, 0xe69a8e}, /* U+668E */ + {0x9df4, 0xe69a89}, /* U+6689 */ + {0x9df5, 0xe69a84}, /* U+6684 */ + {0x9df6, 0xe69a98}, /* U+6698 */ + {0x9df7, 0xe69a9d}, /* U+669D */ + {0x9df8, 0xe69b81}, /* U+66C1 */ + {0x9df9, 0xe69ab9}, /* U+66B9 */ + {0x9dfa, 0xe69b89}, /* U+66C9 */ + {0x9dfb, 0xe69abe}, /* U+66BE */ + {0x9dfc, 0xe69abc}, /* U+66BC */ + {0x9e40, 0xe69b84}, /* U+66C4 */ + {0x9e41, 0xe69ab8}, /* U+66B8 */ + {0x9e42, 0xe69b96}, /* U+66D6 */ + {0x9e43, 0xe69b9a}, /* U+66DA */ + {0x9e44, 0xe69ba0}, /* U+66E0 */ + {0x9e45, 0xe698bf}, /* U+663F */ + {0x9e46, 0xe69ba6}, /* U+66E6 */ + {0x9e47, 0xe69ba9}, /* U+66E9 */ + {0x9e48, 0xe69bb0}, /* U+66F0 */ + {0x9e49, 0xe69bb5}, /* U+66F5 */ + {0x9e4a, 0xe69bb7}, /* U+66F7 */ + {0x9e4b, 0xe69c8f}, /* U+670F */ + {0x9e4c, 0xe69c96}, /* U+6716 */ + {0x9e4d, 0xe69c9e}, /* U+671E */ + {0x9e4e, 0xe69ca6}, /* U+6726 */ + {0x9e4f, 0xe69ca7}, /* U+6727 */ + {0x9e50, 0xe99cb8}, /* U+9738 */ + {0x9e51, 0xe69cae}, /* U+672E */ + {0x9e52, 0xe69cbf}, /* U+673F */ + {0x9e53, 0xe69cb6}, /* U+6736 */ + {0x9e54, 0xe69d81}, /* U+6741 */ + {0x9e55, 0xe69cb8}, /* U+6738 */ + {0x9e56, 0xe69cb7}, /* U+6737 */ + {0x9e57, 0xe69d86}, /* U+6746 */ + {0x9e58, 0xe69d9e}, /* U+675E */ + {0x9e59, 0xe69da0}, /* U+6760 */ + {0x9e5a, 0xe69d99}, /* U+6759 */ + {0x9e5b, 0xe69da3}, /* U+6763 */ + {0x9e5c, 0xe69da4}, /* U+6764 */ + {0x9e5d, 0xe69e89}, /* U+6789 */ + {0x9e5e, 0xe69db0}, /* U+6770 */ + {0x9e5f, 0xe69ea9}, /* U+67A9 */ + {0x9e60, 0xe69dbc}, /* U+677C */ + {0x9e61, 0xe69daa}, /* U+676A */ + {0x9e62, 0xe69e8c}, /* U+678C */ + {0x9e63, 0xe69e8b}, /* U+678B */ + {0x9e64, 0xe69ea6}, /* U+67A6 */ + {0x9e65, 0xe69ea1}, /* U+67A1 */ + {0x9e66, 0xe69e85}, /* U+6785 */ + {0x9e67, 0xe69eb7}, /* U+67B7 */ + {0x9e68, 0xe69faf}, /* U+67EF */ + {0x9e69, 0xe69eb4}, /* U+67B4 */ + {0x9e6a, 0xe69fac}, /* U+67EC */ + {0x9e6b, 0xe69eb3}, /* U+67B3 */ + {0x9e6c, 0xe69fa9}, /* U+67E9 */ + {0x9e6d, 0xe69eb8}, /* U+67B8 */ + {0x9e6e, 0xe69fa4}, /* U+67E4 */ + {0x9e6f, 0xe69f9e}, /* U+67DE */ + {0x9e70, 0xe69f9d}, /* U+67DD */ + {0x9e71, 0xe69fa2}, /* U+67E2 */ + {0x9e72, 0xe69fae}, /* U+67EE */ + {0x9e73, 0xe69eb9}, /* U+67B9 */ + {0x9e74, 0xe69f8e}, /* U+67CE */ + {0x9e75, 0xe69f86}, /* U+67C6 */ + {0x9e76, 0xe69fa7}, /* U+67E7 */ + {0x9e77, 0xe6aa9c}, /* U+6A9C */ + {0x9e78, 0xe6a09e}, /* U+681E */ + {0x9e79, 0xe6a186}, /* U+6846 */ + {0x9e7a, 0xe6a0a9}, /* U+6829 */ + {0x9e7b, 0xe6a180}, /* U+6840 */ + {0x9e7c, 0xe6a18d}, /* U+684D */ + {0x9e7d, 0xe6a0b2}, /* U+6832 */ + {0x9e7e, 0xe6a18e}, /* U+684E */ + {0x9e80, 0xe6a2b3}, /* U+68B3 */ + {0x9e81, 0xe6a0ab}, /* U+682B */ + {0x9e82, 0xe6a199}, /* U+6859 */ + {0x9e83, 0xe6a1a3}, /* U+6863 */ + {0x9e84, 0xe6a1b7}, /* U+6877 */ + {0x9e85, 0xe6a1bf}, /* U+687F */ + {0x9e86, 0xe6a29f}, /* U+689F */ + {0x9e87, 0xe6a28f}, /* U+688F */ + {0x9e88, 0xe6a2ad}, /* U+68AD */ + {0x9e89, 0xe6a294}, /* U+6894 */ + {0x9e8a, 0xe6a29d}, /* U+689D */ + {0x9e8b, 0xe6a29b}, /* U+689B */ + {0x9e8c, 0xe6a283}, /* U+6883 */ + {0x9e8d, 0xe6aaae}, /* U+6AAE */ + {0x9e8e, 0xe6a2b9}, /* U+68B9 */ + {0x9e8f, 0xe6a1b4}, /* U+6874 */ + {0x9e90, 0xe6a2b5}, /* U+68B5 */ + {0x9e91, 0xe6a2a0}, /* U+68A0 */ + {0x9e92, 0xe6a2ba}, /* U+68BA */ + {0x9e93, 0xe6a48f}, /* U+690F */ + {0x9e94, 0xe6a28d}, /* U+688D */ + {0x9e95, 0xe6a1be}, /* U+687E */ + {0x9e96, 0xe6a481}, /* U+6901 */ + {0x9e97, 0xe6a38a}, /* U+68CA */ + {0x9e98, 0xe6a488}, /* U+6908 */ + {0x9e99, 0xe6a398}, /* U+68D8 */ + {0x9e9a, 0xe6a4a2}, /* U+6922 */ + {0x9e9b, 0xe6a4a6}, /* U+6926 */ + {0x9e9c, 0xe6a3a1}, /* U+68E1 */ + {0x9e9d, 0xe6a48c}, /* U+690C */ + {0x9e9e, 0xe6a38d}, /* U+68CD */ + {0x9e9f, 0xe6a394}, /* U+68D4 */ + {0x9ea0, 0xe6a3a7}, /* U+68E7 */ + {0x9ea1, 0xe6a395}, /* U+68D5 */ + {0x9ea2, 0xe6a4b6}, /* U+6936 */ + {0x9ea3, 0xe6a492}, /* U+6912 */ + {0x9ea4, 0xe6a484}, /* U+6904 */ + {0x9ea5, 0xe6a397}, /* U+68D7 */ + {0x9ea6, 0xe6a3a3}, /* U+68E3 */ + {0x9ea7, 0xe6a4a5}, /* U+6925 */ + {0x9ea8, 0xe6a3b9}, /* U+68F9 */ + {0x9ea9, 0xe6a3a0}, /* U+68E0 */ + {0x9eaa, 0xe6a3af}, /* U+68EF */ + {0x9eab, 0xe6a4a8}, /* U+6928 */ + {0x9eac, 0xe6a4aa}, /* U+692A */ + {0x9ead, 0xe6a49a}, /* U+691A */ + {0x9eae, 0xe6a4a3}, /* U+6923 */ + {0x9eaf, 0xe6a4a1}, /* U+6921 */ + {0x9eb0, 0xe6a386}, /* U+68C6 */ + {0x9eb1, 0xe6a5b9}, /* U+6979 */ + {0x9eb2, 0xe6a5b7}, /* U+6977 */ + {0x9eb3, 0xe6a59c}, /* U+695C */ + {0x9eb4, 0xe6a5b8}, /* U+6978 */ + {0x9eb5, 0xe6a5ab}, /* U+696B */ + {0x9eb6, 0xe6a594}, /* U+6954 */ + {0x9eb7, 0xe6a5be}, /* U+697E */ + {0x9eb8, 0xe6a5ae}, /* U+696E */ + {0x9eb9, 0xe6a4b9}, /* U+6939 */ + {0x9eba, 0xe6a5b4}, /* U+6974 */ + {0x9ebb, 0xe6a4bd}, /* U+693D */ + {0x9ebc, 0xe6a599}, /* U+6959 */ + {0x9ebd, 0xe6a4b0}, /* U+6930 */ + {0x9ebe, 0xe6a5a1}, /* U+6961 */ + {0x9ebf, 0xe6a59e}, /* U+695E */ + {0x9ec0, 0xe6a59d}, /* U+695D */ + {0x9ec1, 0xe6a681}, /* U+6981 */ + {0x9ec2, 0xe6a5aa}, /* U+696A */ + {0x9ec3, 0xe6a6b2}, /* U+69B2 */ + {0x9ec4, 0xe6a6ae}, /* U+69AE */ + {0x9ec5, 0xe6a790}, /* U+69D0 */ + {0x9ec6, 0xe6a6bf}, /* U+69BF */ + {0x9ec7, 0xe6a781}, /* U+69C1 */ + {0x9ec8, 0xe6a793}, /* U+69D3 */ + {0x9ec9, 0xe6a6be}, /* U+69BE */ + {0x9eca, 0xe6a78e}, /* U+69CE */ + {0x9ecb, 0xe5afa8}, /* U+5BE8 */ + {0x9ecc, 0xe6a78a}, /* U+69CA */ + {0x9ecd, 0xe6a79d}, /* U+69DD */ + {0x9ece, 0xe6a6bb}, /* U+69BB */ + {0x9ecf, 0xe6a783}, /* U+69C3 */ + {0x9ed0, 0xe6a6a7}, /* U+69A7 */ + {0x9ed1, 0xe6a8ae}, /* U+6A2E */ + {0x9ed2, 0xe6a691}, /* U+6991 */ + {0x9ed3, 0xe6a6a0}, /* U+69A0 */ + {0x9ed4, 0xe6a69c}, /* U+699C */ + {0x9ed5, 0xe6a695}, /* U+6995 */ + {0x9ed6, 0xe6a6b4}, /* U+69B4 */ + {0x9ed7, 0xe6a79e}, /* U+69DE */ + {0x9ed8, 0xe6a7a8}, /* U+69E8 */ + {0x9ed9, 0xe6a882}, /* U+6A02 */ + {0x9eda, 0xe6a89b}, /* U+6A1B */ + {0x9edb, 0xe6a7bf}, /* U+69FF */ + {0x9edc, 0xe6ac8a}, /* U+6B0A */ + {0x9edd, 0xe6a7b9}, /* U+69F9 */ + {0x9ede, 0xe6a7b2}, /* U+69F2 */ + {0x9edf, 0xe6a7a7}, /* U+69E7 */ + {0x9ee0, 0xe6a885}, /* U+6A05 */ + {0x9ee1, 0xe6a6b1}, /* U+69B1 */ + {0x9ee2, 0xe6a89e}, /* U+6A1E */ + {0x9ee3, 0xe6a7ad}, /* U+69ED */ + {0x9ee4, 0xe6a894}, /* U+6A14 */ + {0x9ee5, 0xe6a7ab}, /* U+69EB */ + {0x9ee6, 0xe6a88a}, /* U+6A0A */ + {0x9ee7, 0xe6a892}, /* U+6A12 */ + {0x9ee8, 0xe6ab81}, /* U+6AC1 */ + {0x9ee9, 0xe6a8a3}, /* U+6A23 */ + {0x9eea, 0xe6a893}, /* U+6A13 */ + {0x9eeb, 0xe6a984}, /* U+6A44 */ + {0x9eec, 0xe6a88c}, /* U+6A0C */ + {0x9eed, 0xe6a9b2}, /* U+6A72 */ + {0x9eee, 0xe6a8b6}, /* U+6A36 */ + {0x9eef, 0xe6a9b8}, /* U+6A78 */ + {0x9ef0, 0xe6a987}, /* U+6A47 */ + {0x9ef1, 0xe6a9a2}, /* U+6A62 */ + {0x9ef2, 0xe6a999}, /* U+6A59 */ + {0x9ef3, 0xe6a9a6}, /* U+6A66 */ + {0x9ef4, 0xe6a988}, /* U+6A48 */ + {0x9ef5, 0xe6a8b8}, /* U+6A38 */ + {0x9ef6, 0xe6a8a2}, /* U+6A22 */ + {0x9ef7, 0xe6aa90}, /* U+6A90 */ + {0x9ef8, 0xe6aa8d}, /* U+6A8D */ + {0x9ef9, 0xe6aaa0}, /* U+6AA0 */ + {0x9efa, 0xe6aa84}, /* U+6A84 */ + {0x9efb, 0xe6aaa2}, /* U+6AA2 */ + {0x9efc, 0xe6aaa3}, /* U+6AA3 */ + {0x9f40, 0xe6aa97}, /* U+6A97 */ + {0x9f41, 0xe89897}, /* U+8617 */ + {0x9f42, 0xe6aabb}, /* U+6ABB */ + {0x9f43, 0xe6ab83}, /* U+6AC3 */ + {0x9f44, 0xe6ab82}, /* U+6AC2 */ + {0x9f45, 0xe6aab8}, /* U+6AB8 */ + {0x9f46, 0xe6aab3}, /* U+6AB3 */ + {0x9f47, 0xe6aaac}, /* U+6AAC */ + {0x9f48, 0xe6ab9e}, /* U+6ADE */ + {0x9f49, 0xe6ab91}, /* U+6AD1 */ + {0x9f4a, 0xe6ab9f}, /* U+6ADF */ + {0x9f4b, 0xe6aaaa}, /* U+6AAA */ + {0x9f4c, 0xe6ab9a}, /* U+6ADA */ + {0x9f4d, 0xe6abaa}, /* U+6AEA */ + {0x9f4e, 0xe6abbb}, /* U+6AFB */ + {0x9f4f, 0xe6ac85}, /* U+6B05 */ + {0x9f50, 0xe89896}, /* U+8616 */ + {0x9f51, 0xe6abba}, /* U+6AFA */ + {0x9f52, 0xe6ac92}, /* U+6B12 */ + {0x9f53, 0xe6ac96}, /* U+6B16 */ + {0x9f54, 0xe9acb1}, /* U+9B31 */ + {0x9f55, 0xe6ac9f}, /* U+6B1F */ + {0x9f56, 0xe6acb8}, /* U+6B38 */ + {0x9f57, 0xe6acb7}, /* U+6B37 */ + {0x9f58, 0xe79b9c}, /* U+76DC */ + {0x9f59, 0xe6acb9}, /* U+6B39 */ + {0x9f5a, 0xe9a3ae}, /* U+98EE */ + {0x9f5b, 0xe6ad87}, /* U+6B47 */ + {0x9f5c, 0xe6ad83}, /* U+6B43 */ + {0x9f5d, 0xe6ad89}, /* U+6B49 */ + {0x9f5e, 0xe6ad90}, /* U+6B50 */ + {0x9f5f, 0xe6ad99}, /* U+6B59 */ + {0x9f60, 0xe6ad94}, /* U+6B54 */ + {0x9f61, 0xe6ad9b}, /* U+6B5B */ + {0x9f62, 0xe6ad9f}, /* U+6B5F */ + {0x9f63, 0xe6ada1}, /* U+6B61 */ + {0x9f64, 0xe6adb8}, /* U+6B78 */ + {0x9f65, 0xe6adb9}, /* U+6B79 */ + {0x9f66, 0xe6adbf}, /* U+6B7F */ + {0x9f67, 0xe6ae80}, /* U+6B80 */ + {0x9f68, 0xe6ae84}, /* U+6B84 */ + {0x9f69, 0xe6ae83}, /* U+6B83 */ + {0x9f6a, 0xe6ae8d}, /* U+6B8D */ + {0x9f6b, 0xe6ae98}, /* U+6B98 */ + {0x9f6c, 0xe6ae95}, /* U+6B95 */ + {0x9f6d, 0xe6ae9e}, /* U+6B9E */ + {0x9f6e, 0xe6aea4}, /* U+6BA4 */ + {0x9f6f, 0xe6aeaa}, /* U+6BAA */ + {0x9f70, 0xe6aeab}, /* U+6BAB */ + {0x9f71, 0xe6aeaf}, /* U+6BAF */ + {0x9f72, 0xe6aeb2}, /* U+6BB2 */ + {0x9f73, 0xe6aeb1}, /* U+6BB1 */ + {0x9f74, 0xe6aeb3}, /* U+6BB3 */ + {0x9f75, 0xe6aeb7}, /* U+6BB7 */ + {0x9f76, 0xe6aebc}, /* U+6BBC */ + {0x9f77, 0xe6af86}, /* U+6BC6 */ + {0x9f78, 0xe6af8b}, /* U+6BCB */ + {0x9f79, 0xe6af93}, /* U+6BD3 */ + {0x9f7a, 0xe6af9f}, /* U+6BDF */ + {0x9f7b, 0xe6afac}, /* U+6BEC */ + {0x9f7c, 0xe6afab}, /* U+6BEB */ + {0x9f7d, 0xe6afb3}, /* U+6BF3 */ + {0x9f7e, 0xe6afaf}, /* U+6BEF */ + {0x9f80, 0xe9babe}, /* U+9EBE */ + {0x9f81, 0xe6b088}, /* U+6C08 */ + {0x9f82, 0xe6b093}, /* U+6C13 */ + {0x9f83, 0xe6b094}, /* U+6C14 */ + {0x9f84, 0xe6b09b}, /* U+6C1B */ + {0x9f85, 0xe6b0a4}, /* U+6C24 */ + {0x9f86, 0xe6b0a3}, /* U+6C23 */ + {0x9f87, 0xe6b19e}, /* U+6C5E */ + {0x9f88, 0xe6b195}, /* U+6C55 */ + {0x9f89, 0xe6b1a2}, /* U+6C62 */ + {0x9f8a, 0xe6b1aa}, /* U+6C6A */ + {0x9f8b, 0xe6b282}, /* U+6C82 */ + {0x9f8c, 0xe6b28d}, /* U+6C8D */ + {0x9f8d, 0xe6b29a}, /* U+6C9A */ + {0x9f8e, 0xe6b281}, /* U+6C81 */ + {0x9f8f, 0xe6b29b}, /* U+6C9B */ + {0x9f90, 0xe6b1be}, /* U+6C7E */ + {0x9f91, 0xe6b1a8}, /* U+6C68 */ + {0x9f92, 0xe6b1b3}, /* U+6C73 */ + {0x9f93, 0xe6b292}, /* U+6C92 */ + {0x9f94, 0xe6b290}, /* U+6C90 */ + {0x9f95, 0xe6b384}, /* U+6CC4 */ + {0x9f96, 0xe6b3b1}, /* U+6CF1 */ + {0x9f97, 0xe6b393}, /* U+6CD3 */ + {0x9f98, 0xe6b2bd}, /* U+6CBD */ + {0x9f99, 0xe6b397}, /* U+6CD7 */ + {0x9f9a, 0xe6b385}, /* U+6CC5 */ + {0x9f9b, 0xe6b39d}, /* U+6CDD */ + {0x9f9c, 0xe6b2ae}, /* U+6CAE */ + {0x9f9d, 0xe6b2b1}, /* U+6CB1 */ + {0x9f9e, 0xe6b2be}, /* U+6CBE */ + {0x9f9f, 0xe6b2ba}, /* U+6CBA */ + {0x9fa0, 0xe6b39b}, /* U+6CDB */ + {0x9fa1, 0xe6b3af}, /* U+6CEF */ + {0x9fa2, 0xe6b399}, /* U+6CD9 */ + {0x9fa3, 0xe6b3aa}, /* U+6CEA */ + {0x9fa4, 0xe6b49f}, /* U+6D1F */ + {0x9fa5, 0xe8a18d}, /* U+884D */ + {0x9fa6, 0xe6b4b6}, /* U+6D36 */ + {0x9fa7, 0xe6b4ab}, /* U+6D2B */ + {0x9fa8, 0xe6b4bd}, /* U+6D3D */ + {0x9fa9, 0xe6b4b8}, /* U+6D38 */ + {0x9faa, 0xe6b499}, /* U+6D19 */ + {0x9fab, 0xe6b4b5}, /* U+6D35 */ + {0x9fac, 0xe6b4b3}, /* U+6D33 */ + {0x9fad, 0xe6b492}, /* U+6D12 */ + {0x9fae, 0xe6b48c}, /* U+6D0C */ + {0x9faf, 0xe6b5a3}, /* U+6D63 */ + {0x9fb0, 0xe6b693}, /* U+6D93 */ + {0x9fb1, 0xe6b5a4}, /* U+6D64 */ + {0x9fb2, 0xe6b59a}, /* U+6D5A */ + {0x9fb3, 0xe6b5b9}, /* U+6D79 */ + {0x9fb4, 0xe6b599}, /* U+6D59 */ + {0x9fb5, 0xe6b68e}, /* U+6D8E */ + {0x9fb6, 0xe6b695}, /* U+6D95 */ + {0x9fb7, 0xe6bfa4}, /* U+6FE4 */ + {0x9fb8, 0xe6b685}, /* U+6D85 */ + {0x9fb9, 0xe6b7b9}, /* U+6DF9 */ + {0x9fba, 0xe6b895}, /* U+6E15 */ + {0x9fbb, 0xe6b88a}, /* U+6E0A */ + {0x9fbc, 0xe6b6b5}, /* U+6DB5 */ + {0x9fbd, 0xe6b787}, /* U+6DC7 */ + {0x9fbe, 0xe6b7a6}, /* U+6DE6 */ + {0x9fbf, 0xe6b6b8}, /* U+6DB8 */ + {0x9fc0, 0xe6b786}, /* U+6DC6 */ + {0x9fc1, 0xe6b7ac}, /* U+6DEC */ + {0x9fc2, 0xe6b79e}, /* U+6DDE */ + {0x9fc3, 0xe6b78c}, /* U+6DCC */ + {0x9fc4, 0xe6b7a8}, /* U+6DE8 */ + {0x9fc5, 0xe6b792}, /* U+6DD2 */ + {0x9fc6, 0xe6b785}, /* U+6DC5 */ + {0x9fc7, 0xe6b7ba}, /* U+6DFA */ + {0x9fc8, 0xe6b799}, /* U+6DD9 */ + {0x9fc9, 0xe6b7a4}, /* U+6DE4 */ + {0x9fca, 0xe6b795}, /* U+6DD5 */ + {0x9fcb, 0xe6b7aa}, /* U+6DEA */ + {0x9fcc, 0xe6b7ae}, /* U+6DEE */ + {0x9fcd, 0xe6b8ad}, /* U+6E2D */ + {0x9fce, 0xe6b9ae}, /* U+6E6E */ + {0x9fcf, 0xe6b8ae}, /* U+6E2E */ + {0x9fd0, 0xe6b899}, /* U+6E19 */ + {0x9fd1, 0xe6b9b2}, /* U+6E72 */ + {0x9fd2, 0xe6b99f}, /* U+6E5F */ + {0x9fd3, 0xe6b8be}, /* U+6E3E */ + {0x9fd4, 0xe6b8a3}, /* U+6E23 */ + {0x9fd5, 0xe6b9ab}, /* U+6E6B */ + {0x9fd6, 0xe6b8ab}, /* U+6E2B */ + {0x9fd7, 0xe6b9b6}, /* U+6E76 */ + {0x9fd8, 0xe6b98d}, /* U+6E4D */ + {0x9fd9, 0xe6b89f}, /* U+6E1F */ + {0x9fda, 0xe6b983}, /* U+6E43 */ + {0x9fdb, 0xe6b8ba}, /* U+6E3A */ + {0x9fdc, 0xe6b98e}, /* U+6E4E */ + {0x9fdd, 0xe6b8a4}, /* U+6E24 */ + {0x9fde, 0xe6bbbf}, /* U+6EFF */ + {0x9fdf, 0xe6b89d}, /* U+6E1D */ + {0x9fe0, 0xe6b8b8}, /* U+6E38 */ + {0x9fe1, 0xe6ba82}, /* U+6E82 */ + {0x9fe2, 0xe6baaa}, /* U+6EAA */ + {0x9fe3, 0xe6ba98}, /* U+6E98 */ + {0x9fe4, 0xe6bb89}, /* U+6EC9 */ + {0x9fe5, 0xe6bab7}, /* U+6EB7 */ + {0x9fe6, 0xe6bb93}, /* U+6ED3 */ + {0x9fe7, 0xe6babd}, /* U+6EBD */ + {0x9fe8, 0xe6baaf}, /* U+6EAF */ + {0x9fe9, 0xe6bb84}, /* U+6EC4 */ + {0x9fea, 0xe6bab2}, /* U+6EB2 */ + {0x9feb, 0xe6bb94}, /* U+6ED4 */ + {0x9fec, 0xe6bb95}, /* U+6ED5 */ + {0x9fed, 0xe6ba8f}, /* U+6E8F */ + {0x9fee, 0xe6baa5}, /* U+6EA5 */ + {0x9fef, 0xe6bb82}, /* U+6EC2 */ + {0x9ff0, 0xe6ba9f}, /* U+6E9F */ + {0x9ff1, 0xe6bd81}, /* U+6F41 */ + {0x9ff2, 0xe6bc91}, /* U+6F11 */ + {0x9ff3, 0xe7818c}, /* U+704C */ + {0x9ff4, 0xe6bbac}, /* U+6EEC */ + {0x9ff5, 0xe6bbb8}, /* U+6EF8 */ + {0x9ff6, 0xe6bbbe}, /* U+6EFE */ + {0x9ff7, 0xe6bcbf}, /* U+6F3F */ + {0x9ff8, 0xe6bbb2}, /* U+6EF2 */ + {0x9ff9, 0xe6bcb1}, /* U+6F31 */ + {0x9ffa, 0xe6bbaf}, /* U+6EEF */ + {0x9ffb, 0xe6bcb2}, /* U+6F32 */ + {0x9ffc, 0xe6bb8c}, /* U+6ECC */ + {0xe040, 0xe6bcbe}, /* U+6F3E */ + {0xe041, 0xe6bc93}, /* U+6F13 */ + {0xe042, 0xe6bbb7}, /* U+6EF7 */ + {0xe043, 0xe6be86}, /* U+6F86 */ + {0xe044, 0xe6bdba}, /* U+6F7A */ + {0xe045, 0xe6bdb8}, /* U+6F78 */ + {0xe046, 0xe6be81}, /* U+6F81 */ + {0xe047, 0xe6be80}, /* U+6F80 */ + {0xe048, 0xe6bdaf}, /* U+6F6F */ + {0xe049, 0xe6bd9b}, /* U+6F5B */ + {0xe04a, 0xe6bfb3}, /* U+6FF3 */ + {0xe04b, 0xe6bdad}, /* U+6F6D */ + {0xe04c, 0xe6be82}, /* U+6F82 */ + {0xe04d, 0xe6bdbc}, /* U+6F7C */ + {0xe04e, 0xe6bd98}, /* U+6F58 */ + {0xe04f, 0xe6be8e}, /* U+6F8E */ + {0xe050, 0xe6be91}, /* U+6F91 */ + {0xe051, 0xe6bf82}, /* U+6FC2 */ + {0xe052, 0xe6bda6}, /* U+6F66 */ + {0xe053, 0xe6beb3}, /* U+6FB3 */ + {0xe054, 0xe6bea3}, /* U+6FA3 */ + {0xe055, 0xe6bea1}, /* U+6FA1 */ + {0xe056, 0xe6bea4}, /* U+6FA4 */ + {0xe057, 0xe6beb9}, /* U+6FB9 */ + {0xe058, 0xe6bf86}, /* U+6FC6 */ + {0xe059, 0xe6beaa}, /* U+6FAA */ + {0xe05a, 0xe6bf9f}, /* U+6FDF */ + {0xe05b, 0xe6bf95}, /* U+6FD5 */ + {0xe05c, 0xe6bfac}, /* U+6FEC */ + {0xe05d, 0xe6bf94}, /* U+6FD4 */ + {0xe05e, 0xe6bf98}, /* U+6FD8 */ + {0xe05f, 0xe6bfb1}, /* U+6FF1 */ + {0xe060, 0xe6bfae}, /* U+6FEE */ + {0xe061, 0xe6bf9b}, /* U+6FDB */ + {0xe062, 0xe78089}, /* U+7009 */ + {0xe063, 0xe7808b}, /* U+700B */ + {0xe064, 0xe6bfba}, /* U+6FFA */ + {0xe065, 0xe78091}, /* U+7011 */ + {0xe066, 0xe78081}, /* U+7001 */ + {0xe067, 0xe7808f}, /* U+700F */ + {0xe068, 0xe6bfbe}, /* U+6FFE */ + {0xe069, 0xe7809b}, /* U+701B */ + {0xe06a, 0xe7809a}, /* U+701A */ + {0xe06b, 0xe6bdb4}, /* U+6F74 */ + {0xe06c, 0xe7809d}, /* U+701D */ + {0xe06d, 0xe78098}, /* U+7018 */ + {0xe06e, 0xe7809f}, /* U+701F */ + {0xe06f, 0xe780b0}, /* U+7030 */ + {0xe070, 0xe780be}, /* U+703E */ + {0xe071, 0xe780b2}, /* U+7032 */ + {0xe072, 0xe78191}, /* U+7051 */ + {0xe073, 0xe781a3}, /* U+7063 */ + {0xe074, 0xe78299}, /* U+7099 */ + {0xe075, 0xe78292}, /* U+7092 */ + {0xe076, 0xe782af}, /* U+70AF */ + {0xe077, 0xe783b1}, /* U+70F1 */ + {0xe078, 0xe782ac}, /* U+70AC */ + {0xe079, 0xe782b8}, /* U+70B8 */ + {0xe07a, 0xe782b3}, /* U+70B3 */ + {0xe07b, 0xe782ae}, /* U+70AE */ + {0xe07c, 0xe7839f}, /* U+70DF */ + {0xe07d, 0xe7838b}, /* U+70CB */ + {0xe07e, 0xe7839d}, /* U+70DD */ + {0xe080, 0xe78399}, /* U+70D9 */ + {0xe081, 0xe78489}, /* U+7109 */ + {0xe082, 0xe783bd}, /* U+70FD */ + {0xe083, 0xe7849c}, /* U+711C */ + {0xe084, 0xe78499}, /* U+7119 */ + {0xe085, 0xe785a5}, /* U+7165 */ + {0xe086, 0xe78595}, /* U+7155 */ + {0xe087, 0xe78688}, /* U+7188 */ + {0xe088, 0xe785a6}, /* U+7166 */ + {0xe089, 0xe785a2}, /* U+7162 */ + {0xe08a, 0xe7858c}, /* U+714C */ + {0xe08b, 0xe78596}, /* U+7156 */ + {0xe08c, 0xe785ac}, /* U+716C */ + {0xe08d, 0xe7868f}, /* U+718F */ + {0xe08e, 0xe787bb}, /* U+71FB */ + {0xe08f, 0xe78684}, /* U+7184 */ + {0xe090, 0xe78695}, /* U+7195 */ + {0xe091, 0xe786a8}, /* U+71A8 */ + {0xe092, 0xe786ac}, /* U+71AC */ + {0xe093, 0xe78797}, /* U+71D7 */ + {0xe094, 0xe786b9}, /* U+71B9 */ + {0xe095, 0xe786be}, /* U+71BE */ + {0xe096, 0xe78792}, /* U+71D2 */ + {0xe097, 0xe78789}, /* U+71C9 */ + {0xe098, 0xe78794}, /* U+71D4 */ + {0xe099, 0xe7878e}, /* U+71CE */ + {0xe09a, 0xe787a0}, /* U+71E0 */ + {0xe09b, 0xe787ac}, /* U+71EC */ + {0xe09c, 0xe787a7}, /* U+71E7 */ + {0xe09d, 0xe787b5}, /* U+71F5 */ + {0xe09e, 0xe787bc}, /* U+71FC */ + {0xe09f, 0xe787b9}, /* U+71F9 */ + {0xe0a0, 0xe787bf}, /* U+71FF */ + {0xe0a1, 0xe7888d}, /* U+720D */ + {0xe0a2, 0xe78890}, /* U+7210 */ + {0xe0a3, 0xe7889b}, /* U+721B */ + {0xe0a4, 0xe788a8}, /* U+7228 */ + {0xe0a5, 0xe788ad}, /* U+722D */ + {0xe0a6, 0xe788ac}, /* U+722C */ + {0xe0a7, 0xe788b0}, /* U+7230 */ + {0xe0a8, 0xe788b2}, /* U+7232 */ + {0xe0a9, 0xe788bb}, /* U+723B */ + {0xe0aa, 0xe788bc}, /* U+723C */ + {0xe0ab, 0xe788bf}, /* U+723F */ + {0xe0ac, 0xe78980}, /* U+7240 */ + {0xe0ad, 0xe78986}, /* U+7246 */ + {0xe0ae, 0xe7898b}, /* U+724B */ + {0xe0af, 0xe78998}, /* U+7258 */ + {0xe0b0, 0xe789b4}, /* U+7274 */ + {0xe0b1, 0xe789be}, /* U+727E */ + {0xe0b2, 0xe78a82}, /* U+7282 */ + {0xe0b3, 0xe78a81}, /* U+7281 */ + {0xe0b4, 0xe78a87}, /* U+7287 */ + {0xe0b5, 0xe78a92}, /* U+7292 */ + {0xe0b6, 0xe78a96}, /* U+7296 */ + {0xe0b7, 0xe78aa2}, /* U+72A2 */ + {0xe0b8, 0xe78aa7}, /* U+72A7 */ + {0xe0b9, 0xe78ab9}, /* U+72B9 */ + {0xe0ba, 0xe78ab2}, /* U+72B2 */ + {0xe0bb, 0xe78b83}, /* U+72C3 */ + {0xe0bc, 0xe78b86}, /* U+72C6 */ + {0xe0bd, 0xe78b84}, /* U+72C4 */ + {0xe0be, 0xe78b8e}, /* U+72CE */ + {0xe0bf, 0xe78b92}, /* U+72D2 */ + {0xe0c0, 0xe78ba2}, /* U+72E2 */ + {0xe0c1, 0xe78ba0}, /* U+72E0 */ + {0xe0c2, 0xe78ba1}, /* U+72E1 */ + {0xe0c3, 0xe78bb9}, /* U+72F9 */ + {0xe0c4, 0xe78bb7}, /* U+72F7 */ + {0xe0c5, 0xe5808f}, /* U+500F */ + {0xe0c6, 0xe78c97}, /* U+7317 */ + {0xe0c7, 0xe78c8a}, /* U+730A */ + {0xe0c8, 0xe78c9c}, /* U+731C */ + {0xe0c9, 0xe78c96}, /* U+7316 */ + {0xe0ca, 0xe78c9d}, /* U+731D */ + {0xe0cb, 0xe78cb4}, /* U+7334 */ + {0xe0cc, 0xe78caf}, /* U+732F */ + {0xe0cd, 0xe78ca9}, /* U+7329 */ + {0xe0ce, 0xe78ca5}, /* U+7325 */ + {0xe0cf, 0xe78cbe}, /* U+733E */ + {0xe0d0, 0xe78d8e}, /* U+734E */ + {0xe0d1, 0xe78d8f}, /* U+734F */ + {0xe0d2, 0xe9bb98}, /* U+9ED8 */ + {0xe0d3, 0xe78d97}, /* U+7357 */ + {0xe0d4, 0xe78daa}, /* U+736A */ + {0xe0d5, 0xe78da8}, /* U+7368 */ + {0xe0d6, 0xe78db0}, /* U+7370 */ + {0xe0d7, 0xe78db8}, /* U+7378 */ + {0xe0d8, 0xe78db5}, /* U+7375 */ + {0xe0d9, 0xe78dbb}, /* U+737B */ + {0xe0da, 0xe78dba}, /* U+737A */ + {0xe0db, 0xe78f88}, /* U+73C8 */ + {0xe0dc, 0xe78eb3}, /* U+73B3 */ + {0xe0dd, 0xe78f8e}, /* U+73CE */ + {0xe0de, 0xe78ebb}, /* U+73BB */ + {0xe0df, 0xe78f80}, /* U+73C0 */ + {0xe0e0, 0xe78fa5}, /* U+73E5 */ + {0xe0e1, 0xe78fae}, /* U+73EE */ + {0xe0e2, 0xe78f9e}, /* U+73DE */ + {0xe0e3, 0xe792a2}, /* U+74A2 */ + {0xe0e4, 0xe79085}, /* U+7405 */ + {0xe0e5, 0xe791af}, /* U+746F */ + {0xe0e6, 0xe790a5}, /* U+7425 */ + {0xe0e7, 0xe78fb8}, /* U+73F8 */ + {0xe0e8, 0xe790b2}, /* U+7432 */ + {0xe0e9, 0xe790ba}, /* U+743A */ + {0xe0ea, 0xe79195}, /* U+7455 */ + {0xe0eb, 0xe790bf}, /* U+743F */ + {0xe0ec, 0xe7919f}, /* U+745F */ + {0xe0ed, 0xe79199}, /* U+7459 */ + {0xe0ee, 0xe79181}, /* U+7441 */ + {0xe0ef, 0xe7919c}, /* U+745C */ + {0xe0f0, 0xe791a9}, /* U+7469 */ + {0xe0f1, 0xe791b0}, /* U+7470 */ + {0xe0f2, 0xe791a3}, /* U+7463 */ + {0xe0f3, 0xe791aa}, /* U+746A */ + {0xe0f4, 0xe791b6}, /* U+7476 */ + {0xe0f5, 0xe791be}, /* U+747E */ + {0xe0f6, 0xe7928b}, /* U+748B */ + {0xe0f7, 0xe7929e}, /* U+749E */ + {0xe0f8, 0xe792a7}, /* U+74A7 */ + {0xe0f9, 0xe7938a}, /* U+74CA */ + {0xe0fa, 0xe7938f}, /* U+74CF */ + {0xe0fb, 0xe79394}, /* U+74D4 */ + {0xe0fc, 0xe78fb1}, /* U+73F1 */ + {0xe140, 0xe793a0}, /* U+74E0 */ + {0xe141, 0xe793a3}, /* U+74E3 */ + {0xe142, 0xe793a7}, /* U+74E7 */ + {0xe143, 0xe793a9}, /* U+74E9 */ + {0xe144, 0xe793ae}, /* U+74EE */ + {0xe145, 0xe793b2}, /* U+74F2 */ + {0xe146, 0xe793b0}, /* U+74F0 */ + {0xe147, 0xe793b1}, /* U+74F1 */ + {0xe148, 0xe793b8}, /* U+74F8 */ + {0xe149, 0xe793b7}, /* U+74F7 */ + {0xe14a, 0xe79484}, /* U+7504 */ + {0xe14b, 0xe79483}, /* U+7503 */ + {0xe14c, 0xe79485}, /* U+7505 */ + {0xe14d, 0xe7948c}, /* U+750C */ + {0xe14e, 0xe7948e}, /* U+750E */ + {0xe14f, 0xe7948d}, /* U+750D */ + {0xe150, 0xe79495}, /* U+7515 */ + {0xe151, 0xe79493}, /* U+7513 */ + {0xe152, 0xe7949e}, /* U+751E */ + {0xe153, 0xe794a6}, /* U+7526 */ + {0xe154, 0xe794ac}, /* U+752C */ + {0xe155, 0xe794bc}, /* U+753C */ + {0xe156, 0xe79584}, /* U+7544 */ + {0xe157, 0xe7958d}, /* U+754D */ + {0xe158, 0xe7958a}, /* U+754A */ + {0xe159, 0xe79589}, /* U+7549 */ + {0xe15a, 0xe7959b}, /* U+755B */ + {0xe15b, 0xe79586}, /* U+7546 */ + {0xe15c, 0xe7959a}, /* U+755A */ + {0xe15d, 0xe795a9}, /* U+7569 */ + {0xe15e, 0xe795a4}, /* U+7564 */ + {0xe15f, 0xe795a7}, /* U+7567 */ + {0xe160, 0xe795ab}, /* U+756B */ + {0xe161, 0xe795ad}, /* U+756D */ + {0xe162, 0xe795b8}, /* U+7578 */ + {0xe163, 0xe795b6}, /* U+7576 */ + {0xe164, 0xe79686}, /* U+7586 */ + {0xe165, 0xe79687}, /* U+7587 */ + {0xe166, 0xe795b4}, /* U+7574 */ + {0xe167, 0xe7968a}, /* U+758A */ + {0xe168, 0xe79689}, /* U+7589 */ + {0xe169, 0xe79682}, /* U+7582 */ + {0xe16a, 0xe79694}, /* U+7594 */ + {0xe16b, 0xe7969a}, /* U+759A */ + {0xe16c, 0xe7969d}, /* U+759D */ + {0xe16d, 0xe796a5}, /* U+75A5 */ + {0xe16e, 0xe796a3}, /* U+75A3 */ + {0xe16f, 0xe79782}, /* U+75C2 */ + {0xe170, 0xe796b3}, /* U+75B3 */ + {0xe171, 0xe79783}, /* U+75C3 */ + {0xe172, 0xe796b5}, /* U+75B5 */ + {0xe173, 0xe796bd}, /* U+75BD */ + {0xe174, 0xe796b8}, /* U+75B8 */ + {0xe175, 0xe796bc}, /* U+75BC */ + {0xe176, 0xe796b1}, /* U+75B1 */ + {0xe177, 0xe7978d}, /* U+75CD */ + {0xe178, 0xe7978a}, /* U+75CA */ + {0xe179, 0xe79792}, /* U+75D2 */ + {0xe17a, 0xe79799}, /* U+75D9 */ + {0xe17b, 0xe797a3}, /* U+75E3 */ + {0xe17c, 0xe7979e}, /* U+75DE */ + {0xe17d, 0xe797be}, /* U+75FE */ + {0xe17e, 0xe797bf}, /* U+75FF */ + {0xe180, 0xe797bc}, /* U+75FC */ + {0xe181, 0xe79881}, /* U+7601 */ + {0xe182, 0xe797b0}, /* U+75F0 */ + {0xe183, 0xe797ba}, /* U+75FA */ + {0xe184, 0xe797b2}, /* U+75F2 */ + {0xe185, 0xe797b3}, /* U+75F3 */ + {0xe186, 0xe7988b}, /* U+760B */ + {0xe187, 0xe7988d}, /* U+760D */ + {0xe188, 0xe79889}, /* U+7609 */ + {0xe189, 0xe7989f}, /* U+761F */ + {0xe18a, 0xe798a7}, /* U+7627 */ + {0xe18b, 0xe798a0}, /* U+7620 */ + {0xe18c, 0xe798a1}, /* U+7621 */ + {0xe18d, 0xe798a2}, /* U+7622 */ + {0xe18e, 0xe798a4}, /* U+7624 */ + {0xe18f, 0xe798b4}, /* U+7634 */ + {0xe190, 0xe798b0}, /* U+7630 */ + {0xe191, 0xe798bb}, /* U+763B */ + {0xe192, 0xe79987}, /* U+7647 */ + {0xe193, 0xe79988}, /* U+7648 */ + {0xe194, 0xe79986}, /* U+7646 */ + {0xe195, 0xe7999c}, /* U+765C */ + {0xe196, 0xe79998}, /* U+7658 */ + {0xe197, 0xe799a1}, /* U+7661 */ + {0xe198, 0xe799a2}, /* U+7662 */ + {0xe199, 0xe799a8}, /* U+7668 */ + {0xe19a, 0xe799a9}, /* U+7669 */ + {0xe19b, 0xe799aa}, /* U+766A */ + {0xe19c, 0xe799a7}, /* U+7667 */ + {0xe19d, 0xe799ac}, /* U+766C */ + {0xe19e, 0xe799b0}, /* U+7670 */ + {0xe19f, 0xe799b2}, /* U+7672 */ + {0xe1a0, 0xe799b6}, /* U+7676 */ + {0xe1a1, 0xe799b8}, /* U+7678 */ + {0xe1a2, 0xe799bc}, /* U+767C */ + {0xe1a3, 0xe79a80}, /* U+7680 */ + {0xe1a4, 0xe79a83}, /* U+7683 */ + {0xe1a5, 0xe79a88}, /* U+7688 */ + {0xe1a6, 0xe79a8b}, /* U+768B */ + {0xe1a7, 0xe79a8e}, /* U+768E */ + {0xe1a8, 0xe79a96}, /* U+7696 */ + {0xe1a9, 0xe79a93}, /* U+7693 */ + {0xe1aa, 0xe79a99}, /* U+7699 */ + {0xe1ab, 0xe79a9a}, /* U+769A */ + {0xe1ac, 0xe79ab0}, /* U+76B0 */ + {0xe1ad, 0xe79ab4}, /* U+76B4 */ + {0xe1ae, 0xe79ab8}, /* U+76B8 */ + {0xe1af, 0xe79ab9}, /* U+76B9 */ + {0xe1b0, 0xe79aba}, /* U+76BA */ + {0xe1b1, 0xe79b82}, /* U+76C2 */ + {0xe1b2, 0xe79b8d}, /* U+76CD */ + {0xe1b3, 0xe79b96}, /* U+76D6 */ + {0xe1b4, 0xe79b92}, /* U+76D2 */ + {0xe1b5, 0xe79b9e}, /* U+76DE */ + {0xe1b6, 0xe79ba1}, /* U+76E1 */ + {0xe1b7, 0xe79ba5}, /* U+76E5 */ + {0xe1b8, 0xe79ba7}, /* U+76E7 */ + {0xe1b9, 0xe79baa}, /* U+76EA */ + {0xe1ba, 0xe898af}, /* U+862F */ + {0xe1bb, 0xe79bbb}, /* U+76FB */ + {0xe1bc, 0xe79c88}, /* U+7708 */ + {0xe1bd, 0xe79c87}, /* U+7707 */ + {0xe1be, 0xe79c84}, /* U+7704 */ + {0xe1bf, 0xe79ca9}, /* U+7729 */ + {0xe1c0, 0xe79ca4}, /* U+7724 */ + {0xe1c1, 0xe79c9e}, /* U+771E */ + {0xe1c2, 0xe79ca5}, /* U+7725 */ + {0xe1c3, 0xe79ca6}, /* U+7726 */ + {0xe1c4, 0xe79c9b}, /* U+771B */ + {0xe1c5, 0xe79cb7}, /* U+7737 */ + {0xe1c6, 0xe79cb8}, /* U+7738 */ + {0xe1c7, 0xe79d87}, /* U+7747 */ + {0xe1c8, 0xe79d9a}, /* U+775A */ + {0xe1c9, 0xe79da8}, /* U+7768 */ + {0xe1ca, 0xe79dab}, /* U+776B */ + {0xe1cb, 0xe79d9b}, /* U+775B */ + {0xe1cc, 0xe79da5}, /* U+7765 */ + {0xe1cd, 0xe79dbf}, /* U+777F */ + {0xe1ce, 0xe79dbe}, /* U+777E */ + {0xe1cf, 0xe79db9}, /* U+7779 */ + {0xe1d0, 0xe79e8e}, /* U+778E */ + {0xe1d1, 0xe79e8b}, /* U+778B */ + {0xe1d2, 0xe79e91}, /* U+7791 */ + {0xe1d3, 0xe79ea0}, /* U+77A0 */ + {0xe1d4, 0xe79e9e}, /* U+779E */ + {0xe1d5, 0xe79eb0}, /* U+77B0 */ + {0xe1d6, 0xe79eb6}, /* U+77B6 */ + {0xe1d7, 0xe79eb9}, /* U+77B9 */ + {0xe1d8, 0xe79ebf}, /* U+77BF */ + {0xe1d9, 0xe79ebc}, /* U+77BC */ + {0xe1da, 0xe79ebd}, /* U+77BD */ + {0xe1db, 0xe79ebb}, /* U+77BB */ + {0xe1dc, 0xe79f87}, /* U+77C7 */ + {0xe1dd, 0xe79f8d}, /* U+77CD */ + {0xe1de, 0xe79f97}, /* U+77D7 */ + {0xe1df, 0xe79f9a}, /* U+77DA */ + {0xe1e0, 0xe79f9c}, /* U+77DC */ + {0xe1e1, 0xe79fa3}, /* U+77E3 */ + {0xe1e2, 0xe79fae}, /* U+77EE */ + {0xe1e3, 0xe79fbc}, /* U+77FC */ + {0xe1e4, 0xe7a08c}, /* U+780C */ + {0xe1e5, 0xe7a092}, /* U+7812 */ + {0xe1e6, 0xe7a4a6}, /* U+7926 */ + {0xe1e7, 0xe7a0a0}, /* U+7820 */ + {0xe1e8, 0xe7a4aa}, /* U+792A */ + {0xe1e9, 0xe7a185}, /* U+7845 */ + {0xe1ea, 0xe7a28e}, /* U+788E */ + {0xe1eb, 0xe7a1b4}, /* U+7874 */ + {0xe1ec, 0xe7a286}, /* U+7886 */ + {0xe1ed, 0xe7a1bc}, /* U+787C */ + {0xe1ee, 0xe7a29a}, /* U+789A */ + {0xe1ef, 0xe7a28c}, /* U+788C */ + {0xe1f0, 0xe7a2a3}, /* U+78A3 */ + {0xe1f1, 0xe7a2b5}, /* U+78B5 */ + {0xe1f2, 0xe7a2aa}, /* U+78AA */ + {0xe1f3, 0xe7a2af}, /* U+78AF */ + {0xe1f4, 0xe7a391}, /* U+78D1 */ + {0xe1f5, 0xe7a386}, /* U+78C6 */ + {0xe1f6, 0xe7a38b}, /* U+78CB */ + {0xe1f7, 0xe7a394}, /* U+78D4 */ + {0xe1f8, 0xe7a2be}, /* U+78BE */ + {0xe1f9, 0xe7a2bc}, /* U+78BC */ + {0xe1fa, 0xe7a385}, /* U+78C5 */ + {0xe1fb, 0xe7a38a}, /* U+78CA */ + {0xe1fc, 0xe7a3ac}, /* U+78EC */ + {0xe240, 0xe7a3a7}, /* U+78E7 */ + {0xe241, 0xe7a39a}, /* U+78DA */ + {0xe242, 0xe7a3bd}, /* U+78FD */ + {0xe243, 0xe7a3b4}, /* U+78F4 */ + {0xe244, 0xe7a487}, /* U+7907 */ + {0xe245, 0xe7a492}, /* U+7912 */ + {0xe246, 0xe7a491}, /* U+7911 */ + {0xe247, 0xe7a499}, /* U+7919 */ + {0xe248, 0xe7a4ac}, /* U+792C */ + {0xe249, 0xe7a4ab}, /* U+792B */ + {0xe24a, 0xe7a580}, /* U+7940 */ + {0xe24b, 0xe7a5a0}, /* U+7960 */ + {0xe24c, 0xe7a597}, /* U+7957 */ + {0xe24d, 0xe7a59f}, /* U+795F */ + {0xe24e, 0xe7a59a}, /* U+795A */ + {0xe24f, 0xe7a595}, /* U+7955 */ + {0xe250, 0xe7a593}, /* U+7953 */ + {0xe251, 0xe7a5ba}, /* U+797A */ + {0xe252, 0xe7a5bf}, /* U+797F */ + {0xe253, 0xe7a68a}, /* U+798A */ + {0xe254, 0xe7a69d}, /* U+799D */ + {0xe255, 0xe7a6a7}, /* U+79A7 */ + {0xe256, 0xe9bd8b}, /* U+9F4B */ + {0xe257, 0xe7a6aa}, /* U+79AA */ + {0xe258, 0xe7a6ae}, /* U+79AE */ + {0xe259, 0xe7a6b3}, /* U+79B3 */ + {0xe25a, 0xe7a6b9}, /* U+79B9 */ + {0xe25b, 0xe7a6ba}, /* U+79BA */ + {0xe25c, 0xe7a789}, /* U+79C9 */ + {0xe25d, 0xe7a795}, /* U+79D5 */ + {0xe25e, 0xe7a7a7}, /* U+79E7 */ + {0xe25f, 0xe7a7ac}, /* U+79EC */ + {0xe260, 0xe7a7a1}, /* U+79E1 */ + {0xe261, 0xe7a7a3}, /* U+79E3 */ + {0xe262, 0xe7a888}, /* U+7A08 */ + {0xe263, 0xe7a88d}, /* U+7A0D */ + {0xe264, 0xe7a898}, /* U+7A18 */ + {0xe265, 0xe7a899}, /* U+7A19 */ + {0xe266, 0xe7a8a0}, /* U+7A20 */ + {0xe267, 0xe7a89f}, /* U+7A1F */ + {0xe268, 0xe7a680}, /* U+7980 */ + {0xe269, 0xe7a8b1}, /* U+7A31 */ + {0xe26a, 0xe7a8bb}, /* U+7A3B */ + {0xe26b, 0xe7a8be}, /* U+7A3E */ + {0xe26c, 0xe7a8b7}, /* U+7A37 */ + {0xe26d, 0xe7a983}, /* U+7A43 */ + {0xe26e, 0xe7a997}, /* U+7A57 */ + {0xe26f, 0xe7a989}, /* U+7A49 */ + {0xe270, 0xe7a9a1}, /* U+7A61 */ + {0xe271, 0xe7a9a2}, /* U+7A62 */ + {0xe272, 0xe7a9a9}, /* U+7A69 */ + {0xe273, 0xe9be9d}, /* U+9F9D */ + {0xe274, 0xe7a9b0}, /* U+7A70 */ + {0xe275, 0xe7a9b9}, /* U+7A79 */ + {0xe276, 0xe7a9bd}, /* U+7A7D */ + {0xe277, 0xe7aa88}, /* U+7A88 */ + {0xe278, 0xe7aa97}, /* U+7A97 */ + {0xe279, 0xe7aa95}, /* U+7A95 */ + {0xe27a, 0xe7aa98}, /* U+7A98 */ + {0xe27b, 0xe7aa96}, /* U+7A96 */ + {0xe27c, 0xe7aaa9}, /* U+7AA9 */ + {0xe27d, 0xe7ab88}, /* U+7AC8 */ + {0xe27e, 0xe7aab0}, /* U+7AB0 */ + {0xe280, 0xe7aab6}, /* U+7AB6 */ + {0xe281, 0xe7ab85}, /* U+7AC5 */ + {0xe282, 0xe7ab84}, /* U+7AC4 */ + {0xe283, 0xe7aabf}, /* U+7ABF */ + {0xe284, 0xe98283}, /* U+9083 */ + {0xe285, 0xe7ab87}, /* U+7AC7 */ + {0xe286, 0xe7ab8a}, /* U+7ACA */ + {0xe287, 0xe7ab8d}, /* U+7ACD */ + {0xe288, 0xe7ab8f}, /* U+7ACF */ + {0xe289, 0xe7ab95}, /* U+7AD5 */ + {0xe28a, 0xe7ab93}, /* U+7AD3 */ + {0xe28b, 0xe7ab99}, /* U+7AD9 */ + {0xe28c, 0xe7ab9a}, /* U+7ADA */ + {0xe28d, 0xe7ab9d}, /* U+7ADD */ + {0xe28e, 0xe7aba1}, /* U+7AE1 */ + {0xe28f, 0xe7aba2}, /* U+7AE2 */ + {0xe290, 0xe7aba6}, /* U+7AE6 */ + {0xe291, 0xe7abad}, /* U+7AED */ + {0xe292, 0xe7abb0}, /* U+7AF0 */ + {0xe293, 0xe7ac82}, /* U+7B02 */ + {0xe294, 0xe7ac8f}, /* U+7B0F */ + {0xe295, 0xe7ac8a}, /* U+7B0A */ + {0xe296, 0xe7ac86}, /* U+7B06 */ + {0xe297, 0xe7acb3}, /* U+7B33 */ + {0xe298, 0xe7ac98}, /* U+7B18 */ + {0xe299, 0xe7ac99}, /* U+7B19 */ + {0xe29a, 0xe7ac9e}, /* U+7B1E */ + {0xe29b, 0xe7acb5}, /* U+7B35 */ + {0xe29c, 0xe7aca8}, /* U+7B28 */ + {0xe29d, 0xe7acb6}, /* U+7B36 */ + {0xe29e, 0xe7ad90}, /* U+7B50 */ + {0xe29f, 0xe7adba}, /* U+7B7A */ + {0xe2a0, 0xe7ac84}, /* U+7B04 */ + {0xe2a1, 0xe7ad8d}, /* U+7B4D */ + {0xe2a2, 0xe7ac8b}, /* U+7B0B */ + {0xe2a3, 0xe7ad8c}, /* U+7B4C */ + {0xe2a4, 0xe7ad85}, /* U+7B45 */ + {0xe2a5, 0xe7adb5}, /* U+7B75 */ + {0xe2a6, 0xe7ada5}, /* U+7B65 */ + {0xe2a7, 0xe7adb4}, /* U+7B74 */ + {0xe2a8, 0xe7ada7}, /* U+7B67 */ + {0xe2a9, 0xe7adb0}, /* U+7B70 */ + {0xe2aa, 0xe7adb1}, /* U+7B71 */ + {0xe2ab, 0xe7adac}, /* U+7B6C */ + {0xe2ac, 0xe7adae}, /* U+7B6E */ + {0xe2ad, 0xe7ae9d}, /* U+7B9D */ + {0xe2ae, 0xe7ae98}, /* U+7B98 */ + {0xe2af, 0xe7ae9f}, /* U+7B9F */ + {0xe2b0, 0xe7ae8d}, /* U+7B8D */ + {0xe2b1, 0xe7ae9c}, /* U+7B9C */ + {0xe2b2, 0xe7ae9a}, /* U+7B9A */ + {0xe2b3, 0xe7ae8b}, /* U+7B8B */ + {0xe2b4, 0xe7ae92}, /* U+7B92 */ + {0xe2b5, 0xe7ae8f}, /* U+7B8F */ + {0xe2b6, 0xe7ad9d}, /* U+7B5D */ + {0xe2b7, 0xe7ae99}, /* U+7B99 */ + {0xe2b8, 0xe7af8b}, /* U+7BCB */ + {0xe2b9, 0xe7af81}, /* U+7BC1 */ + {0xe2ba, 0xe7af8c}, /* U+7BCC */ + {0xe2bb, 0xe7af8f}, /* U+7BCF */ + {0xe2bc, 0xe7aeb4}, /* U+7BB4 */ + {0xe2bd, 0xe7af86}, /* U+7BC6 */ + {0xe2be, 0xe7af9d}, /* U+7BDD */ + {0xe2bf, 0xe7afa9}, /* U+7BE9 */ + {0xe2c0, 0xe7b091}, /* U+7C11 */ + {0xe2c1, 0xe7b094}, /* U+7C14 */ + {0xe2c2, 0xe7afa6}, /* U+7BE6 */ + {0xe2c3, 0xe7afa5}, /* U+7BE5 */ + {0xe2c4, 0xe7b1a0}, /* U+7C60 */ + {0xe2c5, 0xe7b080}, /* U+7C00 */ + {0xe2c6, 0xe7b087}, /* U+7C07 */ + {0xe2c7, 0xe7b093}, /* U+7C13 */ + {0xe2c8, 0xe7afb3}, /* U+7BF3 */ + {0xe2c9, 0xe7afb7}, /* U+7BF7 */ + {0xe2ca, 0xe7b097}, /* U+7C17 */ + {0xe2cb, 0xe7b08d}, /* U+7C0D */ + {0xe2cc, 0xe7afb6}, /* U+7BF6 */ + {0xe2cd, 0xe7b0a3}, /* U+7C23 */ + {0xe2ce, 0xe7b0a7}, /* U+7C27 */ + {0xe2cf, 0xe7b0aa}, /* U+7C2A */ + {0xe2d0, 0xe7b09f}, /* U+7C1F */ + {0xe2d1, 0xe7b0b7}, /* U+7C37 */ + {0xe2d2, 0xe7b0ab}, /* U+7C2B */ + {0xe2d3, 0xe7b0bd}, /* U+7C3D */ + {0xe2d4, 0xe7b18c}, /* U+7C4C */ + {0xe2d5, 0xe7b183}, /* U+7C43 */ + {0xe2d6, 0xe7b194}, /* U+7C54 */ + {0xe2d7, 0xe7b18f}, /* U+7C4F */ + {0xe2d8, 0xe7b180}, /* U+7C40 */ + {0xe2d9, 0xe7b190}, /* U+7C50 */ + {0xe2da, 0xe7b198}, /* U+7C58 */ + {0xe2db, 0xe7b19f}, /* U+7C5F */ + {0xe2dc, 0xe7b1a4}, /* U+7C64 */ + {0xe2dd, 0xe7b196}, /* U+7C56 */ + {0xe2de, 0xe7b1a5}, /* U+7C65 */ + {0xe2df, 0xe7b1ac}, /* U+7C6C */ + {0xe2e0, 0xe7b1b5}, /* U+7C75 */ + {0xe2e1, 0xe7b283}, /* U+7C83 */ + {0xe2e2, 0xe7b290}, /* U+7C90 */ + {0xe2e3, 0xe7b2a4}, /* U+7CA4 */ + {0xe2e4, 0xe7b2ad}, /* U+7CAD */ + {0xe2e5, 0xe7b2a2}, /* U+7CA2 */ + {0xe2e6, 0xe7b2ab}, /* U+7CAB */ + {0xe2e7, 0xe7b2a1}, /* U+7CA1 */ + {0xe2e8, 0xe7b2a8}, /* U+7CA8 */ + {0xe2e9, 0xe7b2b3}, /* U+7CB3 */ + {0xe2ea, 0xe7b2b2}, /* U+7CB2 */ + {0xe2eb, 0xe7b2b1}, /* U+7CB1 */ + {0xe2ec, 0xe7b2ae}, /* U+7CAE */ + {0xe2ed, 0xe7b2b9}, /* U+7CB9 */ + {0xe2ee, 0xe7b2bd}, /* U+7CBD */ + {0xe2ef, 0xe7b380}, /* U+7CC0 */ + {0xe2f0, 0xe7b385}, /* U+7CC5 */ + {0xe2f1, 0xe7b382}, /* U+7CC2 */ + {0xe2f2, 0xe7b398}, /* U+7CD8 */ + {0xe2f3, 0xe7b392}, /* U+7CD2 */ + {0xe2f4, 0xe7b39c}, /* U+7CDC */ + {0xe2f5, 0xe7b3a2}, /* U+7CE2 */ + {0xe2f6, 0xe9acbb}, /* U+9B3B */ + {0xe2f7, 0xe7b3af}, /* U+7CEF */ + {0xe2f8, 0xe7b3b2}, /* U+7CF2 */ + {0xe2f9, 0xe7b3b4}, /* U+7CF4 */ + {0xe2fa, 0xe7b3b6}, /* U+7CF6 */ + {0xe2fb, 0xe7b3ba}, /* U+7CFA */ + {0xe2fc, 0xe7b486}, /* U+7D06 */ + {0xe340, 0xe7b482}, /* U+7D02 */ + {0xe341, 0xe7b49c}, /* U+7D1C */ + {0xe342, 0xe7b495}, /* U+7D15 */ + {0xe343, 0xe7b48a}, /* U+7D0A */ + {0xe344, 0xe7b585}, /* U+7D45 */ + {0xe345, 0xe7b58b}, /* U+7D4B */ + {0xe346, 0xe7b4ae}, /* U+7D2E */ + {0xe347, 0xe7b4b2}, /* U+7D32 */ + {0xe348, 0xe7b4bf}, /* U+7D3F */ + {0xe349, 0xe7b4b5}, /* U+7D35 */ + {0xe34a, 0xe7b586}, /* U+7D46 */ + {0xe34b, 0xe7b5b3}, /* U+7D73 */ + {0xe34c, 0xe7b596}, /* U+7D56 */ + {0xe34d, 0xe7b58e}, /* U+7D4E */ + {0xe34e, 0xe7b5b2}, /* U+7D72 */ + {0xe34f, 0xe7b5a8}, /* U+7D68 */ + {0xe350, 0xe7b5ae}, /* U+7D6E */ + {0xe351, 0xe7b58f}, /* U+7D4F */ + {0xe352, 0xe7b5a3}, /* U+7D63 */ + {0xe353, 0xe7b693}, /* U+7D93 */ + {0xe354, 0xe7b689}, /* U+7D89 */ + {0xe355, 0xe7b59b}, /* U+7D5B */ + {0xe356, 0xe7b68f}, /* U+7D8F */ + {0xe357, 0xe7b5bd}, /* U+7D7D */ + {0xe358, 0xe7b69b}, /* U+7D9B */ + {0xe359, 0xe7b6ba}, /* U+7DBA */ + {0xe35a, 0xe7b6ae}, /* U+7DAE */ + {0xe35b, 0xe7b6a3}, /* U+7DA3 */ + {0xe35c, 0xe7b6b5}, /* U+7DB5 */ + {0xe35d, 0xe7b787}, /* U+7DC7 */ + {0xe35e, 0xe7b6bd}, /* U+7DBD */ + {0xe35f, 0xe7b6ab}, /* U+7DAB */ + {0xe360, 0xe7b8bd}, /* U+7E3D */ + {0xe361, 0xe7b6a2}, /* U+7DA2 */ + {0xe362, 0xe7b6af}, /* U+7DAF */ + {0xe363, 0xe7b79c}, /* U+7DDC */ + {0xe364, 0xe7b6b8}, /* U+7DB8 */ + {0xe365, 0xe7b69f}, /* U+7D9F */ + {0xe366, 0xe7b6b0}, /* U+7DB0 */ + {0xe367, 0xe7b798}, /* U+7DD8 */ + {0xe368, 0xe7b79d}, /* U+7DDD */ + {0xe369, 0xe7b7a4}, /* U+7DE4 */ + {0xe36a, 0xe7b79e}, /* U+7DDE */ + {0xe36b, 0xe7b7bb}, /* U+7DFB */ + {0xe36c, 0xe7b7b2}, /* U+7DF2 */ + {0xe36d, 0xe7b7a1}, /* U+7DE1 */ + {0xe36e, 0xe7b885}, /* U+7E05 */ + {0xe36f, 0xe7b88a}, /* U+7E0A */ + {0xe370, 0xe7b8a3}, /* U+7E23 */ + {0xe371, 0xe7b8a1}, /* U+7E21 */ + {0xe372, 0xe7b892}, /* U+7E12 */ + {0xe373, 0xe7b8b1}, /* U+7E31 */ + {0xe374, 0xe7b89f}, /* U+7E1F */ + {0xe375, 0xe7b889}, /* U+7E09 */ + {0xe376, 0xe7b88b}, /* U+7E0B */ + {0xe377, 0xe7b8a2}, /* U+7E22 */ + {0xe378, 0xe7b986}, /* U+7E46 */ + {0xe379, 0xe7b9a6}, /* U+7E66 */ + {0xe37a, 0xe7b8bb}, /* U+7E3B */ + {0xe37b, 0xe7b8b5}, /* U+7E35 */ + {0xe37c, 0xe7b8b9}, /* U+7E39 */ + {0xe37d, 0xe7b983}, /* U+7E43 */ + {0xe37e, 0xe7b8b7}, /* U+7E37 */ + {0xe380, 0xe7b8b2}, /* U+7E32 */ + {0xe381, 0xe7b8ba}, /* U+7E3A */ + {0xe382, 0xe7b9a7}, /* U+7E67 */ + {0xe383, 0xe7b99d}, /* U+7E5D */ + {0xe384, 0xe7b996}, /* U+7E56 */ + {0xe385, 0xe7b99e}, /* U+7E5E */ + {0xe386, 0xe7b999}, /* U+7E59 */ + {0xe387, 0xe7b99a}, /* U+7E5A */ + {0xe388, 0xe7b9b9}, /* U+7E79 */ + {0xe389, 0xe7b9aa}, /* U+7E6A */ + {0xe38a, 0xe7b9a9}, /* U+7E69 */ + {0xe38b, 0xe7b9bc}, /* U+7E7C */ + {0xe38c, 0xe7b9bb}, /* U+7E7B */ + {0xe38d, 0xe7ba83}, /* U+7E83 */ + {0xe38e, 0xe7b795}, /* U+7DD5 */ + {0xe38f, 0xe7b9bd}, /* U+7E7D */ + {0xe390, 0xe8beae}, /* U+8FAE */ + {0xe391, 0xe7b9bf}, /* U+7E7F */ + {0xe392, 0xe7ba88}, /* U+7E88 */ + {0xe393, 0xe7ba89}, /* U+7E89 */ + {0xe394, 0xe7ba8c}, /* U+7E8C */ + {0xe395, 0xe7ba92}, /* U+7E92 */ + {0xe396, 0xe7ba90}, /* U+7E90 */ + {0xe397, 0xe7ba93}, /* U+7E93 */ + {0xe398, 0xe7ba94}, /* U+7E94 */ + {0xe399, 0xe7ba96}, /* U+7E96 */ + {0xe39a, 0xe7ba8e}, /* U+7E8E */ + {0xe39b, 0xe7ba9b}, /* U+7E9B */ + {0xe39c, 0xe7ba9c}, /* U+7E9C */ + {0xe39d, 0xe7bcb8}, /* U+7F38 */ + {0xe39e, 0xe7bcba}, /* U+7F3A */ + {0xe39f, 0xe7bd85}, /* U+7F45 */ + {0xe3a0, 0xe7bd8c}, /* U+7F4C */ + {0xe3a1, 0xe7bd8d}, /* U+7F4D */ + {0xe3a2, 0xe7bd8e}, /* U+7F4E */ + {0xe3a3, 0xe7bd90}, /* U+7F50 */ + {0xe3a4, 0xe7bd91}, /* U+7F51 */ + {0xe3a5, 0xe7bd95}, /* U+7F55 */ + {0xe3a6, 0xe7bd94}, /* U+7F54 */ + {0xe3a7, 0xe7bd98}, /* U+7F58 */ + {0xe3a8, 0xe7bd9f}, /* U+7F5F */ + {0xe3a9, 0xe7bda0}, /* U+7F60 */ + {0xe3aa, 0xe7bda8}, /* U+7F68 */ + {0xe3ab, 0xe7bda9}, /* U+7F69 */ + {0xe3ac, 0xe7bda7}, /* U+7F67 */ + {0xe3ad, 0xe7bdb8}, /* U+7F78 */ + {0xe3ae, 0xe7be82}, /* U+7F82 */ + {0xe3af, 0xe7be86}, /* U+7F86 */ + {0xe3b0, 0xe7be83}, /* U+7F83 */ + {0xe3b1, 0xe7be88}, /* U+7F88 */ + {0xe3b2, 0xe7be87}, /* U+7F87 */ + {0xe3b3, 0xe7be8c}, /* U+7F8C */ + {0xe3b4, 0xe7be94}, /* U+7F94 */ + {0xe3b5, 0xe7be9e}, /* U+7F9E */ + {0xe3b6, 0xe7be9d}, /* U+7F9D */ + {0xe3b7, 0xe7be9a}, /* U+7F9A */ + {0xe3b8, 0xe7bea3}, /* U+7FA3 */ + {0xe3b9, 0xe7beaf}, /* U+7FAF */ + {0xe3ba, 0xe7beb2}, /* U+7FB2 */ + {0xe3bb, 0xe7beb9}, /* U+7FB9 */ + {0xe3bc, 0xe7beae}, /* U+7FAE */ + {0xe3bd, 0xe7beb6}, /* U+7FB6 */ + {0xe3be, 0xe7beb8}, /* U+7FB8 */ + {0xe3bf, 0xe8adb1}, /* U+8B71 */ + {0xe3c0, 0xe7bf85}, /* U+7FC5 */ + {0xe3c1, 0xe7bf86}, /* U+7FC6 */ + {0xe3c2, 0xe7bf8a}, /* U+7FCA */ + {0xe3c3, 0xe7bf95}, /* U+7FD5 */ + {0xe3c4, 0xe7bf94}, /* U+7FD4 */ + {0xe3c5, 0xe7bfa1}, /* U+7FE1 */ + {0xe3c6, 0xe7bfa6}, /* U+7FE6 */ + {0xe3c7, 0xe7bfa9}, /* U+7FE9 */ + {0xe3c8, 0xe7bfb3}, /* U+7FF3 */ + {0xe3c9, 0xe7bfb9}, /* U+7FF9 */ + {0xe3ca, 0xe9a39c}, /* U+98DC */ + {0xe3cb, 0xe88086}, /* U+8006 */ + {0xe3cc, 0xe88084}, /* U+8004 */ + {0xe3cd, 0xe8808b}, /* U+800B */ + {0xe3ce, 0xe88092}, /* U+8012 */ + {0xe3cf, 0xe88098}, /* U+8018 */ + {0xe3d0, 0xe88099}, /* U+8019 */ + {0xe3d1, 0xe8809c}, /* U+801C */ + {0xe3d2, 0xe880a1}, /* U+8021 */ + {0xe3d3, 0xe880a8}, /* U+8028 */ + {0xe3d4, 0xe880bf}, /* U+803F */ + {0xe3d5, 0xe880bb}, /* U+803B */ + {0xe3d6, 0xe8818a}, /* U+804A */ + {0xe3d7, 0xe88186}, /* U+8046 */ + {0xe3d8, 0xe88192}, /* U+8052 */ + {0xe3d9, 0xe88198}, /* U+8058 */ + {0xe3da, 0xe8819a}, /* U+805A */ + {0xe3db, 0xe8819f}, /* U+805F */ + {0xe3dc, 0xe881a2}, /* U+8062 */ + {0xe3dd, 0xe881a8}, /* U+8068 */ + {0xe3de, 0xe881b3}, /* U+8073 */ + {0xe3df, 0xe881b2}, /* U+8072 */ + {0xe3e0, 0xe881b0}, /* U+8070 */ + {0xe3e1, 0xe881b6}, /* U+8076 */ + {0xe3e2, 0xe881b9}, /* U+8079 */ + {0xe3e3, 0xe881bd}, /* U+807D */ + {0xe3e4, 0xe881bf}, /* U+807F */ + {0xe3e5, 0xe88284}, /* U+8084 */ + {0xe3e6, 0xe88286}, /* U+8086 */ + {0xe3e7, 0xe88285}, /* U+8085 */ + {0xe3e8, 0xe8829b}, /* U+809B */ + {0xe3e9, 0xe88293}, /* U+8093 */ + {0xe3ea, 0xe8829a}, /* U+809A */ + {0xe3eb, 0xe882ad}, /* U+80AD */ + {0xe3ec, 0xe58690}, /* U+5190 */ + {0xe3ed, 0xe882ac}, /* U+80AC */ + {0xe3ee, 0xe8839b}, /* U+80DB */ + {0xe3ef, 0xe883a5}, /* U+80E5 */ + {0xe3f0, 0xe88399}, /* U+80D9 */ + {0xe3f1, 0xe8839d}, /* U+80DD */ + {0xe3f2, 0xe88384}, /* U+80C4 */ + {0xe3f3, 0xe8839a}, /* U+80DA */ + {0xe3f4, 0xe88396}, /* U+80D6 */ + {0xe3f5, 0xe88489}, /* U+8109 */ + {0xe3f6, 0xe883af}, /* U+80EF */ + {0xe3f7, 0xe883b1}, /* U+80F1 */ + {0xe3f8, 0xe8849b}, /* U+811B */ + {0xe3f9, 0xe884a9}, /* U+8129 */ + {0xe3fa, 0xe884a3}, /* U+8123 */ + {0xe3fb, 0xe884af}, /* U+812F */ + {0xe3fc, 0xe8858b}, /* U+814B */ + {0xe440, 0xe99a8b}, /* U+968B */ + {0xe441, 0xe88586}, /* U+8146 */ + {0xe442, 0xe884be}, /* U+813E */ + {0xe443, 0xe88593}, /* U+8153 */ + {0xe444, 0xe88591}, /* U+8151 */ + {0xe445, 0xe883bc}, /* U+80FC */ + {0xe446, 0xe885b1}, /* U+8171 */ + {0xe447, 0xe885ae}, /* U+816E */ + {0xe448, 0xe885a5}, /* U+8165 */ + {0xe449, 0xe885a6}, /* U+8166 */ + {0xe44a, 0xe885b4}, /* U+8174 */ + {0xe44b, 0xe88683}, /* U+8183 */ + {0xe44c, 0xe88688}, /* U+8188 */ + {0xe44d, 0xe8868a}, /* U+818A */ + {0xe44e, 0xe88680}, /* U+8180 */ + {0xe44f, 0xe88682}, /* U+8182 */ + {0xe450, 0xe886a0}, /* U+81A0 */ + {0xe451, 0xe88695}, /* U+8195 */ + {0xe452, 0xe886a4}, /* U+81A4 */ + {0xe453, 0xe886a3}, /* U+81A3 */ + {0xe454, 0xe8859f}, /* U+815F */ + {0xe455, 0xe88693}, /* U+8193 */ + {0xe456, 0xe886a9}, /* U+81A9 */ + {0xe457, 0xe886b0}, /* U+81B0 */ + {0xe458, 0xe886b5}, /* U+81B5 */ + {0xe459, 0xe886be}, /* U+81BE */ + {0xe45a, 0xe886b8}, /* U+81B8 */ + {0xe45b, 0xe886bd}, /* U+81BD */ + {0xe45c, 0xe88780}, /* U+81C0 */ + {0xe45d, 0xe88782}, /* U+81C2 */ + {0xe45e, 0xe886ba}, /* U+81BA */ + {0xe45f, 0xe88789}, /* U+81C9 */ + {0xe460, 0xe8878d}, /* U+81CD */ + {0xe461, 0xe88791}, /* U+81D1 */ + {0xe462, 0xe88799}, /* U+81D9 */ + {0xe463, 0xe88798}, /* U+81D8 */ + {0xe464, 0xe88788}, /* U+81C8 */ + {0xe465, 0xe8879a}, /* U+81DA */ + {0xe466, 0xe8879f}, /* U+81DF */ + {0xe467, 0xe887a0}, /* U+81E0 */ + {0xe468, 0xe887a7}, /* U+81E7 */ + {0xe469, 0xe887ba}, /* U+81FA */ + {0xe46a, 0xe887bb}, /* U+81FB */ + {0xe46b, 0xe887be}, /* U+81FE */ + {0xe46c, 0xe88881}, /* U+8201 */ + {0xe46d, 0xe88882}, /* U+8202 */ + {0xe46e, 0xe88885}, /* U+8205 */ + {0xe46f, 0xe88887}, /* U+8207 */ + {0xe470, 0xe8888a}, /* U+820A */ + {0xe471, 0xe8888d}, /* U+820D */ + {0xe472, 0xe88890}, /* U+8210 */ + {0xe473, 0xe88896}, /* U+8216 */ + {0xe474, 0xe888a9}, /* U+8229 */ + {0xe475, 0xe888ab}, /* U+822B */ + {0xe476, 0xe888b8}, /* U+8238 */ + {0xe477, 0xe888b3}, /* U+8233 */ + {0xe478, 0xe88980}, /* U+8240 */ + {0xe479, 0xe88999}, /* U+8259 */ + {0xe47a, 0xe88998}, /* U+8258 */ + {0xe47b, 0xe8899d}, /* U+825D */ + {0xe47c, 0xe8899a}, /* U+825A */ + {0xe47d, 0xe8899f}, /* U+825F */ + {0xe47e, 0xe889a4}, /* U+8264 */ + {0xe480, 0xe889a2}, /* U+8262 */ + {0xe481, 0xe889a8}, /* U+8268 */ + {0xe482, 0xe889aa}, /* U+826A */ + {0xe483, 0xe889ab}, /* U+826B */ + {0xe484, 0xe888ae}, /* U+822E */ + {0xe485, 0xe889b1}, /* U+8271 */ + {0xe486, 0xe889b7}, /* U+8277 */ + {0xe487, 0xe889b8}, /* U+8278 */ + {0xe488, 0xe889be}, /* U+827E */ + {0xe489, 0xe88a8d}, /* U+828D */ + {0xe48a, 0xe88a92}, /* U+8292 */ + {0xe48b, 0xe88aab}, /* U+82AB */ + {0xe48c, 0xe88a9f}, /* U+829F */ + {0xe48d, 0xe88abb}, /* U+82BB */ + {0xe48e, 0xe88aac}, /* U+82AC */ + {0xe48f, 0xe88ba1}, /* U+82E1 */ + {0xe490, 0xe88ba3}, /* U+82E3 */ + {0xe491, 0xe88b9f}, /* U+82DF */ + {0xe492, 0xe88b92}, /* U+82D2 */ + {0xe493, 0xe88bb4}, /* U+82F4 */ + {0xe494, 0xe88bb3}, /* U+82F3 */ + {0xe495, 0xe88bba}, /* U+82FA */ + {0xe496, 0xe88e93}, /* U+8393 */ + {0xe497, 0xe88c83}, /* U+8303 */ + {0xe498, 0xe88bbb}, /* U+82FB */ + {0xe499, 0xe88bb9}, /* U+82F9 */ + {0xe49a, 0xe88b9e}, /* U+82DE */ + {0xe49b, 0xe88c86}, /* U+8306 */ + {0xe49c, 0xe88b9c}, /* U+82DC */ + {0xe49d, 0xe88c89}, /* U+8309 */ + {0xe49e, 0xe88b99}, /* U+82D9 */ + {0xe49f, 0xe88cb5}, /* U+8335 */ + {0xe4a0, 0xe88cb4}, /* U+8334 */ + {0xe4a1, 0xe88c96}, /* U+8316 */ + {0xe4a2, 0xe88cb2}, /* U+8332 */ + {0xe4a3, 0xe88cb1}, /* U+8331 */ + {0xe4a4, 0xe88d80}, /* U+8340 */ + {0xe4a5, 0xe88cb9}, /* U+8339 */ + {0xe4a6, 0xe88d90}, /* U+8350 */ + {0xe4a7, 0xe88d85}, /* U+8345 */ + {0xe4a8, 0xe88caf}, /* U+832F */ + {0xe4a9, 0xe88cab}, /* U+832B */ + {0xe4aa, 0xe88c97}, /* U+8317 */ + {0xe4ab, 0xe88c98}, /* U+8318 */ + {0xe4ac, 0xe88e85}, /* U+8385 */ + {0xe4ad, 0xe88e9a}, /* U+839A */ + {0xe4ae, 0xe88eaa}, /* U+83AA */ + {0xe4af, 0xe88e9f}, /* U+839F */ + {0xe4b0, 0xe88ea2}, /* U+83A2 */ + {0xe4b1, 0xe88e96}, /* U+8396 */ + {0xe4b2, 0xe88ca3}, /* U+8323 */ + {0xe4b3, 0xe88e8e}, /* U+838E */ + {0xe4b4, 0xe88e87}, /* U+8387 */ + {0xe4b5, 0xe88e8a}, /* U+838A */ + {0xe4b6, 0xe88dbc}, /* U+837C */ + {0xe4b7, 0xe88eb5}, /* U+83B5 */ + {0xe4b8, 0xe88db3}, /* U+8373 */ + {0xe4b9, 0xe88db5}, /* U+8375 */ + {0xe4ba, 0xe88ea0}, /* U+83A0 */ + {0xe4bb, 0xe88e89}, /* U+8389 */ + {0xe4bc, 0xe88ea8}, /* U+83A8 */ + {0xe4bd, 0xe88fb4}, /* U+83F4 */ + {0xe4be, 0xe89093}, /* U+8413 */ + {0xe4bf, 0xe88fab}, /* U+83EB */ + {0xe4c0, 0xe88f8e}, /* U+83CE */ + {0xe4c1, 0xe88fbd}, /* U+83FD */ + {0xe4c2, 0xe89083}, /* U+8403 */ + {0xe4c3, 0xe88f98}, /* U+83D8 */ + {0xe4c4, 0xe8908b}, /* U+840B */ + {0xe4c5, 0xe88f81}, /* U+83C1 */ + {0xe4c6, 0xe88fb7}, /* U+83F7 */ + {0xe4c7, 0xe89087}, /* U+8407 */ + {0xe4c8, 0xe88fa0}, /* U+83E0 */ + {0xe4c9, 0xe88fb2}, /* U+83F2 */ + {0xe4ca, 0xe8908d}, /* U+840D */ + {0xe4cb, 0xe890a2}, /* U+8422 */ + {0xe4cc, 0xe890a0}, /* U+8420 */ + {0xe4cd, 0xe88ebd}, /* U+83BD */ + {0xe4ce, 0xe890b8}, /* U+8438 */ + {0xe4cf, 0xe89486}, /* U+8506 */ + {0xe4d0, 0xe88fbb}, /* U+83FB */ + {0xe4d1, 0xe891ad}, /* U+846D */ + {0xe4d2, 0xe890aa}, /* U+842A */ + {0xe4d3, 0xe890bc}, /* U+843C */ + {0xe4d4, 0xe8959a}, /* U+855A */ + {0xe4d5, 0xe89284}, /* U+8484 */ + {0xe4d6, 0xe891b7}, /* U+8477 */ + {0xe4d7, 0xe891ab}, /* U+846B */ + {0xe4d8, 0xe892ad}, /* U+84AD */ + {0xe4d9, 0xe891ae}, /* U+846E */ + {0xe4da, 0xe89282}, /* U+8482 */ + {0xe4db, 0xe891a9}, /* U+8469 */ + {0xe4dc, 0xe89186}, /* U+8446 */ + {0xe4dd, 0xe890ac}, /* U+842C */ + {0xe4de, 0xe891af}, /* U+846F */ + {0xe4df, 0xe891b9}, /* U+8479 */ + {0xe4e0, 0xe890b5}, /* U+8435 */ + {0xe4e1, 0xe8938a}, /* U+84CA */ + {0xe4e2, 0xe891a2}, /* U+8462 */ + {0xe4e3, 0xe892b9}, /* U+84B9 */ + {0xe4e4, 0xe892bf}, /* U+84BF */ + {0xe4e5, 0xe8929f}, /* U+849F */ + {0xe4e6, 0xe89399}, /* U+84D9 */ + {0xe4e7, 0xe8938d}, /* U+84CD */ + {0xe4e8, 0xe892bb}, /* U+84BB */ + {0xe4e9, 0xe8939a}, /* U+84DA */ + {0xe4ea, 0xe89390}, /* U+84D0 */ + {0xe4eb, 0xe89381}, /* U+84C1 */ + {0xe4ec, 0xe89386}, /* U+84C6 */ + {0xe4ed, 0xe89396}, /* U+84D6 */ + {0xe4ee, 0xe892a1}, /* U+84A1 */ + {0xe4ef, 0xe894a1}, /* U+8521 */ + {0xe4f0, 0xe893bf}, /* U+84FF */ + {0xe4f1, 0xe893b4}, /* U+84F4 */ + {0xe4f2, 0xe89497}, /* U+8517 */ + {0xe4f3, 0xe89498}, /* U+8518 */ + {0xe4f4, 0xe894ac}, /* U+852C */ + {0xe4f5, 0xe8949f}, /* U+851F */ + {0xe4f6, 0xe89495}, /* U+8515 */ + {0xe4f7, 0xe89494}, /* U+8514 */ + {0xe4f8, 0xe893bc}, /* U+84FC */ + {0xe4f9, 0xe89580}, /* U+8540 */ + {0xe4fa, 0xe895a3}, /* U+8563 */ + {0xe4fb, 0xe89598}, /* U+8558 */ + {0xe4fc, 0xe89588}, /* U+8548 */ + {0xe540, 0xe89581}, /* U+8541 */ + {0xe541, 0xe89882}, /* U+8602 */ + {0xe542, 0xe8958b}, /* U+854B */ + {0xe543, 0xe89595}, /* U+8555 */ + {0xe544, 0xe89680}, /* U+8580 */ + {0xe545, 0xe896a4}, /* U+85A4 */ + {0xe546, 0xe89688}, /* U+8588 */ + {0xe547, 0xe89691}, /* U+8591 */ + {0xe548, 0xe8968a}, /* U+858A */ + {0xe549, 0xe896a8}, /* U+85A8 */ + {0xe54a, 0xe895ad}, /* U+856D */ + {0xe54b, 0xe89694}, /* U+8594 */ + {0xe54c, 0xe8969b}, /* U+859B */ + {0xe54d, 0xe897aa}, /* U+85EA */ + {0xe54e, 0xe89687}, /* U+8587 */ + {0xe54f, 0xe8969c}, /* U+859C */ + {0xe550, 0xe895b7}, /* U+8577 */ + {0xe551, 0xe895be}, /* U+857E */ + {0xe552, 0xe89690}, /* U+8590 */ + {0xe553, 0xe89789}, /* U+85C9 */ + {0xe554, 0xe896ba}, /* U+85BA */ + {0xe555, 0xe8978f}, /* U+85CF */ + {0xe556, 0xe896b9}, /* U+85B9 */ + {0xe557, 0xe89790}, /* U+85D0 */ + {0xe558, 0xe89795}, /* U+85D5 */ + {0xe559, 0xe8979d}, /* U+85DD */ + {0xe55a, 0xe897a5}, /* U+85E5 */ + {0xe55b, 0xe8979c}, /* U+85DC */ + {0xe55c, 0xe897b9}, /* U+85F9 */ + {0xe55d, 0xe8988a}, /* U+860A */ + {0xe55e, 0xe89893}, /* U+8613 */ + {0xe55f, 0xe8988b}, /* U+860B */ + {0xe560, 0xe897be}, /* U+85FE */ + {0xe561, 0xe897ba}, /* U+85FA */ + {0xe562, 0xe89886}, /* U+8606 */ + {0xe563, 0xe898a2}, /* U+8622 */ + {0xe564, 0xe8989a}, /* U+861A */ + {0xe565, 0xe898b0}, /* U+8630 */ + {0xe566, 0xe898bf}, /* U+863F */ + {0xe567, 0xe8998d}, /* U+864D */ + {0xe568, 0xe4b995}, /* U+4E55 */ + {0xe569, 0xe89994}, /* U+8654 */ + {0xe56a, 0xe8999f}, /* U+865F */ + {0xe56b, 0xe899a7}, /* U+8667 */ + {0xe56c, 0xe899b1}, /* U+8671 */ + {0xe56d, 0xe89a93}, /* U+8693 */ + {0xe56e, 0xe89aa3}, /* U+86A3 */ + {0xe56f, 0xe89aa9}, /* U+86A9 */ + {0xe570, 0xe89aaa}, /* U+86AA */ + {0xe571, 0xe89a8b}, /* U+868B */ + {0xe572, 0xe89a8c}, /* U+868C */ + {0xe573, 0xe89ab6}, /* U+86B6 */ + {0xe574, 0xe89aaf}, /* U+86AF */ + {0xe575, 0xe89b84}, /* U+86C4 */ + {0xe576, 0xe89b86}, /* U+86C6 */ + {0xe577, 0xe89ab0}, /* U+86B0 */ + {0xe578, 0xe89b89}, /* U+86C9 */ + {0xe579, 0xe8a0a3}, /* U+8823 */ + {0xe57a, 0xe89aab}, /* U+86AB */ + {0xe57b, 0xe89b94}, /* U+86D4 */ + {0xe57c, 0xe89b9e}, /* U+86DE */ + {0xe57d, 0xe89ba9}, /* U+86E9 */ + {0xe57e, 0xe89bac}, /* U+86EC */ + {0xe580, 0xe89b9f}, /* U+86DF */ + {0xe581, 0xe89b9b}, /* U+86DB */ + {0xe582, 0xe89baf}, /* U+86EF */ + {0xe583, 0xe89c92}, /* U+8712 */ + {0xe584, 0xe89c86}, /* U+8706 */ + {0xe585, 0xe89c88}, /* U+8708 */ + {0xe586, 0xe89c80}, /* U+8700 */ + {0xe587, 0xe89c83}, /* U+8703 */ + {0xe588, 0xe89bbb}, /* U+86FB */ + {0xe589, 0xe89c91}, /* U+8711 */ + {0xe58a, 0xe89c89}, /* U+8709 */ + {0xe58b, 0xe89c8d}, /* U+870D */ + {0xe58c, 0xe89bb9}, /* U+86F9 */ + {0xe58d, 0xe89c8a}, /* U+870A */ + {0xe58e, 0xe89cb4}, /* U+8734 */ + {0xe58f, 0xe89cbf}, /* U+873F */ + {0xe590, 0xe89cb7}, /* U+8737 */ + {0xe591, 0xe89cbb}, /* U+873B */ + {0xe592, 0xe89ca5}, /* U+8725 */ + {0xe593, 0xe89ca9}, /* U+8729 */ + {0xe594, 0xe89c9a}, /* U+871A */ + {0xe595, 0xe89da0}, /* U+8760 */ + {0xe596, 0xe89d9f}, /* U+875F */ + {0xe597, 0xe89db8}, /* U+8778 */ + {0xe598, 0xe89d8c}, /* U+874C */ + {0xe599, 0xe89d8e}, /* U+874E */ + {0xe59a, 0xe89db4}, /* U+8774 */ + {0xe59b, 0xe89d97}, /* U+8757 */ + {0xe59c, 0xe89da8}, /* U+8768 */ + {0xe59d, 0xe89dae}, /* U+876E */ + {0xe59e, 0xe89d99}, /* U+8759 */ + {0xe59f, 0xe89d93}, /* U+8753 */ + {0xe5a0, 0xe89da3}, /* U+8763 */ + {0xe5a1, 0xe89daa}, /* U+876A */ + {0xe5a2, 0xe8a085}, /* U+8805 */ + {0xe5a3, 0xe89ea2}, /* U+87A2 */ + {0xe5a4, 0xe89e9f}, /* U+879F */ + {0xe5a5, 0xe89e82}, /* U+8782 */ + {0xe5a6, 0xe89eaf}, /* U+87AF */ + {0xe5a7, 0xe89f8b}, /* U+87CB */ + {0xe5a8, 0xe89ebd}, /* U+87BD */ + {0xe5a9, 0xe89f80}, /* U+87C0 */ + {0xe5aa, 0xe89f90}, /* U+87D0 */ + {0xe5ab, 0xe99b96}, /* U+96D6 */ + {0xe5ac, 0xe89eab}, /* U+87AB */ + {0xe5ad, 0xe89f84}, /* U+87C4 */ + {0xe5ae, 0xe89eb3}, /* U+87B3 */ + {0xe5af, 0xe89f87}, /* U+87C7 */ + {0xe5b0, 0xe89f86}, /* U+87C6 */ + {0xe5b1, 0xe89ebb}, /* U+87BB */ + {0xe5b2, 0xe89faf}, /* U+87EF */ + {0xe5b3, 0xe89fb2}, /* U+87F2 */ + {0xe5b4, 0xe89fa0}, /* U+87E0 */ + {0xe5b5, 0xe8a08f}, /* U+880F */ + {0xe5b6, 0xe8a08d}, /* U+880D */ + {0xe5b7, 0xe89fbe}, /* U+87FE */ + {0xe5b8, 0xe89fb6}, /* U+87F6 */ + {0xe5b9, 0xe89fb7}, /* U+87F7 */ + {0xe5ba, 0xe8a08e}, /* U+880E */ + {0xe5bb, 0xe89f92}, /* U+87D2 */ + {0xe5bc, 0xe8a091}, /* U+8811 */ + {0xe5bd, 0xe8a096}, /* U+8816 */ + {0xe5be, 0xe8a095}, /* U+8815 */ + {0xe5bf, 0xe8a0a2}, /* U+8822 */ + {0xe5c0, 0xe8a0a1}, /* U+8821 */ + {0xe5c1, 0xe8a0b1}, /* U+8831 */ + {0xe5c2, 0xe8a0b6}, /* U+8836 */ + {0xe5c3, 0xe8a0b9}, /* U+8839 */ + {0xe5c4, 0xe8a0a7}, /* U+8827 */ + {0xe5c5, 0xe8a0bb}, /* U+883B */ + {0xe5c6, 0xe8a184}, /* U+8844 */ + {0xe5c7, 0xe8a182}, /* U+8842 */ + {0xe5c8, 0xe8a192}, /* U+8852 */ + {0xe5c9, 0xe8a199}, /* U+8859 */ + {0xe5ca, 0xe8a19e}, /* U+885E */ + {0xe5cb, 0xe8a1a2}, /* U+8862 */ + {0xe5cc, 0xe8a1ab}, /* U+886B */ + {0xe5cd, 0xe8a281}, /* U+8881 */ + {0xe5ce, 0xe8a1be}, /* U+887E */ + {0xe5cf, 0xe8a29e}, /* U+889E */ + {0xe5d0, 0xe8a1b5}, /* U+8875 */ + {0xe5d1, 0xe8a1bd}, /* U+887D */ + {0xe5d2, 0xe8a2b5}, /* U+88B5 */ + {0xe5d3, 0xe8a1b2}, /* U+8872 */ + {0xe5d4, 0xe8a282}, /* U+8882 */ + {0xe5d5, 0xe8a297}, /* U+8897 */ + {0xe5d6, 0xe8a292}, /* U+8892 */ + {0xe5d7, 0xe8a2ae}, /* U+88AE */ + {0xe5d8, 0xe8a299}, /* U+8899 */ + {0xe5d9, 0xe8a2a2}, /* U+88A2 */ + {0xe5da, 0xe8a28d}, /* U+888D */ + {0xe5db, 0xe8a2a4}, /* U+88A4 */ + {0xe5dc, 0xe8a2b0}, /* U+88B0 */ + {0xe5dd, 0xe8a2bf}, /* U+88BF */ + {0xe5de, 0xe8a2b1}, /* U+88B1 */ + {0xe5df, 0xe8a383}, /* U+88C3 */ + {0xe5e0, 0xe8a384}, /* U+88C4 */ + {0xe5e1, 0xe8a394}, /* U+88D4 */ + {0xe5e2, 0xe8a398}, /* U+88D8 */ + {0xe5e3, 0xe8a399}, /* U+88D9 */ + {0xe5e4, 0xe8a39d}, /* U+88DD */ + {0xe5e5, 0xe8a3b9}, /* U+88F9 */ + {0xe5e6, 0xe8a482}, /* U+8902 */ + {0xe5e7, 0xe8a3bc}, /* U+88FC */ + {0xe5e8, 0xe8a3b4}, /* U+88F4 */ + {0xe5e9, 0xe8a3a8}, /* U+88E8 */ + {0xe5ea, 0xe8a3b2}, /* U+88F2 */ + {0xe5eb, 0xe8a484}, /* U+8904 */ + {0xe5ec, 0xe8a48c}, /* U+890C */ + {0xe5ed, 0xe8a48a}, /* U+890A */ + {0xe5ee, 0xe8a493}, /* U+8913 */ + {0xe5ef, 0xe8a583}, /* U+8943 */ + {0xe5f0, 0xe8a49e}, /* U+891E */ + {0xe5f1, 0xe8a4a5}, /* U+8925 */ + {0xe5f2, 0xe8a4aa}, /* U+892A */ + {0xe5f3, 0xe8a4ab}, /* U+892B */ + {0xe5f4, 0xe8a581}, /* U+8941 */ + {0xe5f5, 0xe8a584}, /* U+8944 */ + {0xe5f6, 0xe8a4bb}, /* U+893B */ + {0xe5f7, 0xe8a4b6}, /* U+8936 */ + {0xe5f8, 0xe8a4b8}, /* U+8938 */ + {0xe5f9, 0xe8a58c}, /* U+894C */ + {0xe5fa, 0xe8a49d}, /* U+891D */ + {0xe5fb, 0xe8a5a0}, /* U+8960 */ + {0xe5fc, 0xe8a59e}, /* U+895E */ + {0xe640, 0xe8a5a6}, /* U+8966 */ + {0xe641, 0xe8a5a4}, /* U+8964 */ + {0xe642, 0xe8a5ad}, /* U+896D */ + {0xe643, 0xe8a5aa}, /* U+896A */ + {0xe644, 0xe8a5af}, /* U+896F */ + {0xe645, 0xe8a5b4}, /* U+8974 */ + {0xe646, 0xe8a5b7}, /* U+8977 */ + {0xe647, 0xe8a5be}, /* U+897E */ + {0xe648, 0xe8a683}, /* U+8983 */ + {0xe649, 0xe8a688}, /* U+8988 */ + {0xe64a, 0xe8a68a}, /* U+898A */ + {0xe64b, 0xe8a693}, /* U+8993 */ + {0xe64c, 0xe8a698}, /* U+8998 */ + {0xe64d, 0xe8a6a1}, /* U+89A1 */ + {0xe64e, 0xe8a6a9}, /* U+89A9 */ + {0xe64f, 0xe8a6a6}, /* U+89A6 */ + {0xe650, 0xe8a6ac}, /* U+89AC */ + {0xe651, 0xe8a6af}, /* U+89AF */ + {0xe652, 0xe8a6b2}, /* U+89B2 */ + {0xe653, 0xe8a6ba}, /* U+89BA */ + {0xe654, 0xe8a6bd}, /* U+89BD */ + {0xe655, 0xe8a6bf}, /* U+89BF */ + {0xe656, 0xe8a780}, /* U+89C0 */ + {0xe657, 0xe8a79a}, /* U+89DA */ + {0xe658, 0xe8a79c}, /* U+89DC */ + {0xe659, 0xe8a79d}, /* U+89DD */ + {0xe65a, 0xe8a7a7}, /* U+89E7 */ + {0xe65b, 0xe8a7b4}, /* U+89F4 */ + {0xe65c, 0xe8a7b8}, /* U+89F8 */ + {0xe65d, 0xe8a883}, /* U+8A03 */ + {0xe65e, 0xe8a896}, /* U+8A16 */ + {0xe65f, 0xe8a890}, /* U+8A10 */ + {0xe660, 0xe8a88c}, /* U+8A0C */ + {0xe661, 0xe8a89b}, /* U+8A1B */ + {0xe662, 0xe8a89d}, /* U+8A1D */ + {0xe663, 0xe8a8a5}, /* U+8A25 */ + {0xe664, 0xe8a8b6}, /* U+8A36 */ + {0xe665, 0xe8a981}, /* U+8A41 */ + {0xe666, 0xe8a99b}, /* U+8A5B */ + {0xe667, 0xe8a992}, /* U+8A52 */ + {0xe668, 0xe8a986}, /* U+8A46 */ + {0xe669, 0xe8a988}, /* U+8A48 */ + {0xe66a, 0xe8a9bc}, /* U+8A7C */ + {0xe66b, 0xe8a9ad}, /* U+8A6D */ + {0xe66c, 0xe8a9ac}, /* U+8A6C */ + {0xe66d, 0xe8a9a2}, /* U+8A62 */ + {0xe66e, 0xe8aa85}, /* U+8A85 */ + {0xe66f, 0xe8aa82}, /* U+8A82 */ + {0xe670, 0xe8aa84}, /* U+8A84 */ + {0xe671, 0xe8aaa8}, /* U+8AA8 */ + {0xe672, 0xe8aaa1}, /* U+8AA1 */ + {0xe673, 0xe8aa91}, /* U+8A91 */ + {0xe674, 0xe8aaa5}, /* U+8AA5 */ + {0xe675, 0xe8aaa6}, /* U+8AA6 */ + {0xe676, 0xe8aa9a}, /* U+8A9A */ + {0xe677, 0xe8aaa3}, /* U+8AA3 */ + {0xe678, 0xe8ab84}, /* U+8AC4 */ + {0xe679, 0xe8ab8d}, /* U+8ACD */ + {0xe67a, 0xe8ab82}, /* U+8AC2 */ + {0xe67b, 0xe8ab9a}, /* U+8ADA */ + {0xe67c, 0xe8abab}, /* U+8AEB */ + {0xe67d, 0xe8abb3}, /* U+8AF3 */ + {0xe67e, 0xe8aba7}, /* U+8AE7 */ + {0xe680, 0xe8aba4}, /* U+8AE4 */ + {0xe681, 0xe8abb1}, /* U+8AF1 */ + {0xe682, 0xe8ac94}, /* U+8B14 */ + {0xe683, 0xe8aba0}, /* U+8AE0 */ + {0xe684, 0xe8aba2}, /* U+8AE2 */ + {0xe685, 0xe8abb7}, /* U+8AF7 */ + {0xe686, 0xe8ab9e}, /* U+8ADE */ + {0xe687, 0xe8ab9b}, /* U+8ADB */ + {0xe688, 0xe8ac8c}, /* U+8B0C */ + {0xe689, 0xe8ac87}, /* U+8B07 */ + {0xe68a, 0xe8ac9a}, /* U+8B1A */ + {0xe68b, 0xe8aba1}, /* U+8AE1 */ + {0xe68c, 0xe8ac96}, /* U+8B16 */ + {0xe68d, 0xe8ac90}, /* U+8B10 */ + {0xe68e, 0xe8ac97}, /* U+8B17 */ + {0xe68f, 0xe8aca0}, /* U+8B20 */ + {0xe690, 0xe8acb3}, /* U+8B33 */ + {0xe691, 0xe99eab}, /* U+97AB */ + {0xe692, 0xe8aca6}, /* U+8B26 */ + {0xe693, 0xe8acab}, /* U+8B2B */ + {0xe694, 0xe8acbe}, /* U+8B3E */ + {0xe695, 0xe8aca8}, /* U+8B28 */ + {0xe696, 0xe8ad81}, /* U+8B41 */ + {0xe697, 0xe8ad8c}, /* U+8B4C */ + {0xe698, 0xe8ad8f}, /* U+8B4F */ + {0xe699, 0xe8ad8e}, /* U+8B4E */ + {0xe69a, 0xe8ad89}, /* U+8B49 */ + {0xe69b, 0xe8ad96}, /* U+8B56 */ + {0xe69c, 0xe8ad9b}, /* U+8B5B */ + {0xe69d, 0xe8ad9a}, /* U+8B5A */ + {0xe69e, 0xe8adab}, /* U+8B6B */ + {0xe69f, 0xe8ad9f}, /* U+8B5F */ + {0xe6a0, 0xe8adac}, /* U+8B6C */ + {0xe6a1, 0xe8adaf}, /* U+8B6F */ + {0xe6a2, 0xe8adb4}, /* U+8B74 */ + {0xe6a3, 0xe8adbd}, /* U+8B7D */ + {0xe6a4, 0xe8ae80}, /* U+8B80 */ + {0xe6a5, 0xe8ae8c}, /* U+8B8C */ + {0xe6a6, 0xe8ae8e}, /* U+8B8E */ + {0xe6a7, 0xe8ae92}, /* U+8B92 */ + {0xe6a8, 0xe8ae93}, /* U+8B93 */ + {0xe6a9, 0xe8ae96}, /* U+8B96 */ + {0xe6aa, 0xe8ae99}, /* U+8B99 */ + {0xe6ab, 0xe8ae9a}, /* U+8B9A */ + {0xe6ac, 0xe8b0ba}, /* U+8C3A */ + {0xe6ad, 0xe8b181}, /* U+8C41 */ + {0xe6ae, 0xe8b0bf}, /* U+8C3F */ + {0xe6af, 0xe8b188}, /* U+8C48 */ + {0xe6b0, 0xe8b18c}, /* U+8C4C */ + {0xe6b1, 0xe8b18e}, /* U+8C4E */ + {0xe6b2, 0xe8b190}, /* U+8C50 */ + {0xe6b3, 0xe8b195}, /* U+8C55 */ + {0xe6b4, 0xe8b1a2}, /* U+8C62 */ + {0xe6b5, 0xe8b1ac}, /* U+8C6C */ + {0xe6b6, 0xe8b1b8}, /* U+8C78 */ + {0xe6b7, 0xe8b1ba}, /* U+8C7A */ + {0xe6b8, 0xe8b282}, /* U+8C82 */ + {0xe6b9, 0xe8b289}, /* U+8C89 */ + {0xe6ba, 0xe8b285}, /* U+8C85 */ + {0xe6bb, 0xe8b28a}, /* U+8C8A */ + {0xe6bc, 0xe8b28d}, /* U+8C8D */ + {0xe6bd, 0xe8b28e}, /* U+8C8E */ + {0xe6be, 0xe8b294}, /* U+8C94 */ + {0xe6bf, 0xe8b1bc}, /* U+8C7C */ + {0xe6c0, 0xe8b298}, /* U+8C98 */ + {0xe6c1, 0xe6889d}, /* U+621D */ + {0xe6c2, 0xe8b2ad}, /* U+8CAD */ + {0xe6c3, 0xe8b2aa}, /* U+8CAA */ + {0xe6c4, 0xe8b2bd}, /* U+8CBD */ + {0xe6c5, 0xe8b2b2}, /* U+8CB2 */ + {0xe6c6, 0xe8b2b3}, /* U+8CB3 */ + {0xe6c7, 0xe8b2ae}, /* U+8CAE */ + {0xe6c8, 0xe8b2b6}, /* U+8CB6 */ + {0xe6c9, 0xe8b388}, /* U+8CC8 */ + {0xe6ca, 0xe8b381}, /* U+8CC1 */ + {0xe6cb, 0xe8b3a4}, /* U+8CE4 */ + {0xe6cc, 0xe8b3a3}, /* U+8CE3 */ + {0xe6cd, 0xe8b39a}, /* U+8CDA */ + {0xe6ce, 0xe8b3bd}, /* U+8CFD */ + {0xe6cf, 0xe8b3ba}, /* U+8CFA */ + {0xe6d0, 0xe8b3bb}, /* U+8CFB */ + {0xe6d1, 0xe8b484}, /* U+8D04 */ + {0xe6d2, 0xe8b485}, /* U+8D05 */ + {0xe6d3, 0xe8b48a}, /* U+8D0A */ + {0xe6d4, 0xe8b487}, /* U+8D07 */ + {0xe6d5, 0xe8b48f}, /* U+8D0F */ + {0xe6d6, 0xe8b48d}, /* U+8D0D */ + {0xe6d7, 0xe8b490}, /* U+8D10 */ + {0xe6d8, 0xe9bd8e}, /* U+9F4E */ + {0xe6d9, 0xe8b493}, /* U+8D13 */ + {0xe6da, 0xe8b38d}, /* U+8CCD */ + {0xe6db, 0xe8b494}, /* U+8D14 */ + {0xe6dc, 0xe8b496}, /* U+8D16 */ + {0xe6dd, 0xe8b5a7}, /* U+8D67 */ + {0xe6de, 0xe8b5ad}, /* U+8D6D */ + {0xe6df, 0xe8b5b1}, /* U+8D71 */ + {0xe6e0, 0xe8b5b3}, /* U+8D73 */ + {0xe6e1, 0xe8b681}, /* U+8D81 */ + {0xe6e2, 0xe8b699}, /* U+8D99 */ + {0xe6e3, 0xe8b782}, /* U+8DC2 */ + {0xe6e4, 0xe8b6be}, /* U+8DBE */ + {0xe6e5, 0xe8b6ba}, /* U+8DBA */ + {0xe6e6, 0xe8b78f}, /* U+8DCF */ + {0xe6e7, 0xe8b79a}, /* U+8DDA */ + {0xe6e8, 0xe8b796}, /* U+8DD6 */ + {0xe6e9, 0xe8b78c}, /* U+8DCC */ + {0xe6ea, 0xe8b79b}, /* U+8DDB */ + {0xe6eb, 0xe8b78b}, /* U+8DCB */ + {0xe6ec, 0xe8b7aa}, /* U+8DEA */ + {0xe6ed, 0xe8b7ab}, /* U+8DEB */ + {0xe6ee, 0xe8b79f}, /* U+8DDF */ + {0xe6ef, 0xe8b7a3}, /* U+8DE3 */ + {0xe6f0, 0xe8b7bc}, /* U+8DFC */ + {0xe6f1, 0xe8b888}, /* U+8E08 */ + {0xe6f2, 0xe8b889}, /* U+8E09 */ + {0xe6f3, 0xe8b7bf}, /* U+8DFF */ + {0xe6f4, 0xe8b89d}, /* U+8E1D */ + {0xe6f5, 0xe8b89e}, /* U+8E1E */ + {0xe6f6, 0xe8b890}, /* U+8E10 */ + {0xe6f7, 0xe8b89f}, /* U+8E1F */ + {0xe6f8, 0xe8b982}, /* U+8E42 */ + {0xe6f9, 0xe8b8b5}, /* U+8E35 */ + {0xe6fa, 0xe8b8b0}, /* U+8E30 */ + {0xe6fb, 0xe8b8b4}, /* U+8E34 */ + {0xe6fc, 0xe8b98a}, /* U+8E4A */ + {0xe740, 0xe8b987}, /* U+8E47 */ + {0xe741, 0xe8b989}, /* U+8E49 */ + {0xe742, 0xe8b98c}, /* U+8E4C */ + {0xe743, 0xe8b990}, /* U+8E50 */ + {0xe744, 0xe8b988}, /* U+8E48 */ + {0xe745, 0xe8b999}, /* U+8E59 */ + {0xe746, 0xe8b9a4}, /* U+8E64 */ + {0xe747, 0xe8b9a0}, /* U+8E60 */ + {0xe748, 0xe8b8aa}, /* U+8E2A */ + {0xe749, 0xe8b9a3}, /* U+8E63 */ + {0xe74a, 0xe8b995}, /* U+8E55 */ + {0xe74b, 0xe8b9b6}, /* U+8E76 */ + {0xe74c, 0xe8b9b2}, /* U+8E72 */ + {0xe74d, 0xe8b9bc}, /* U+8E7C */ + {0xe74e, 0xe8ba81}, /* U+8E81 */ + {0xe74f, 0xe8ba87}, /* U+8E87 */ + {0xe750, 0xe8ba85}, /* U+8E85 */ + {0xe751, 0xe8ba84}, /* U+8E84 */ + {0xe752, 0xe8ba8b}, /* U+8E8B */ + {0xe753, 0xe8ba8a}, /* U+8E8A */ + {0xe754, 0xe8ba93}, /* U+8E93 */ + {0xe755, 0xe8ba91}, /* U+8E91 */ + {0xe756, 0xe8ba94}, /* U+8E94 */ + {0xe757, 0xe8ba99}, /* U+8E99 */ + {0xe758, 0xe8baaa}, /* U+8EAA */ + {0xe759, 0xe8baa1}, /* U+8EA1 */ + {0xe75a, 0xe8baac}, /* U+8EAC */ + {0xe75b, 0xe8bab0}, /* U+8EB0 */ + {0xe75c, 0xe8bb86}, /* U+8EC6 */ + {0xe75d, 0xe8bab1}, /* U+8EB1 */ + {0xe75e, 0xe8babe}, /* U+8EBE */ + {0xe75f, 0xe8bb85}, /* U+8EC5 */ + {0xe760, 0xe8bb88}, /* U+8EC8 */ + {0xe761, 0xe8bb8b}, /* U+8ECB */ + {0xe762, 0xe8bb9b}, /* U+8EDB */ + {0xe763, 0xe8bba3}, /* U+8EE3 */ + {0xe764, 0xe8bbbc}, /* U+8EFC */ + {0xe765, 0xe8bbbb}, /* U+8EFB */ + {0xe766, 0xe8bbab}, /* U+8EEB */ + {0xe767, 0xe8bbbe}, /* U+8EFE */ + {0xe768, 0xe8bc8a}, /* U+8F0A */ + {0xe769, 0xe8bc85}, /* U+8F05 */ + {0xe76a, 0xe8bc95}, /* U+8F15 */ + {0xe76b, 0xe8bc92}, /* U+8F12 */ + {0xe76c, 0xe8bc99}, /* U+8F19 */ + {0xe76d, 0xe8bc93}, /* U+8F13 */ + {0xe76e, 0xe8bc9c}, /* U+8F1C */ + {0xe76f, 0xe8bc9f}, /* U+8F1F */ + {0xe770, 0xe8bc9b}, /* U+8F1B */ + {0xe771, 0xe8bc8c}, /* U+8F0C */ + {0xe772, 0xe8bca6}, /* U+8F26 */ + {0xe773, 0xe8bcb3}, /* U+8F33 */ + {0xe774, 0xe8bcbb}, /* U+8F3B */ + {0xe775, 0xe8bcb9}, /* U+8F39 */ + {0xe776, 0xe8bd85}, /* U+8F45 */ + {0xe777, 0xe8bd82}, /* U+8F42 */ + {0xe778, 0xe8bcbe}, /* U+8F3E */ + {0xe779, 0xe8bd8c}, /* U+8F4C */ + {0xe77a, 0xe8bd89}, /* U+8F49 */ + {0xe77b, 0xe8bd86}, /* U+8F46 */ + {0xe77c, 0xe8bd8e}, /* U+8F4E */ + {0xe77d, 0xe8bd97}, /* U+8F57 */ + {0xe77e, 0xe8bd9c}, /* U+8F5C */ + {0xe780, 0xe8bda2}, /* U+8F62 */ + {0xe781, 0xe8bda3}, /* U+8F63 */ + {0xe782, 0xe8bda4}, /* U+8F64 */ + {0xe783, 0xe8be9c}, /* U+8F9C */ + {0xe784, 0xe8be9f}, /* U+8F9F */ + {0xe785, 0xe8bea3}, /* U+8FA3 */ + {0xe786, 0xe8bead}, /* U+8FAD */ + {0xe787, 0xe8beaf}, /* U+8FAF */ + {0xe788, 0xe8beb7}, /* U+8FB7 */ + {0xe789, 0xe8bf9a}, /* U+8FDA */ + {0xe78a, 0xe8bfa5}, /* U+8FE5 */ + {0xe78b, 0xe8bfa2}, /* U+8FE2 */ + {0xe78c, 0xe8bfaa}, /* U+8FEA */ + {0xe78d, 0xe8bfaf}, /* U+8FEF */ + {0xe78e, 0xe98287}, /* U+9087 */ + {0xe78f, 0xe8bfb4}, /* U+8FF4 */ + {0xe790, 0xe98085}, /* U+9005 */ + {0xe791, 0xe8bfb9}, /* U+8FF9 */ + {0xe792, 0xe8bfba}, /* U+8FFA */ + {0xe793, 0xe98091}, /* U+9011 */ + {0xe794, 0xe98095}, /* U+9015 */ + {0xe795, 0xe980a1}, /* U+9021 */ + {0xe796, 0xe9808d}, /* U+900D */ + {0xe797, 0xe9809e}, /* U+901E */ + {0xe798, 0xe98096}, /* U+9016 */ + {0xe799, 0xe9808b}, /* U+900B */ + {0xe79a, 0xe980a7}, /* U+9027 */ + {0xe79b, 0xe980b6}, /* U+9036 */ + {0xe79c, 0xe980b5}, /* U+9035 */ + {0xe79d, 0xe980b9}, /* U+9039 */ + {0xe79e, 0xe8bfb8}, /* U+8FF8 */ + {0xe79f, 0xe9818f}, /* U+904F */ + {0xe7a0, 0xe98190}, /* U+9050 */ + {0xe7a1, 0xe98191}, /* U+9051 */ + {0xe7a2, 0xe98192}, /* U+9052 */ + {0xe7a3, 0xe9808e}, /* U+900E */ + {0xe7a4, 0xe98189}, /* U+9049 */ + {0xe7a5, 0xe980be}, /* U+903E */ + {0xe7a6, 0xe98196}, /* U+9056 */ + {0xe7a7, 0xe98198}, /* U+9058 */ + {0xe7a8, 0xe9819e}, /* U+905E */ + {0xe7a9, 0xe981a8}, /* U+9068 */ + {0xe7aa, 0xe981af}, /* U+906F */ + {0xe7ab, 0xe981b6}, /* U+9076 */ + {0xe7ac, 0xe99aa8}, /* U+96A8 */ + {0xe7ad, 0xe981b2}, /* U+9072 */ + {0xe7ae, 0xe98282}, /* U+9082 */ + {0xe7af, 0xe981bd}, /* U+907D */ + {0xe7b0, 0xe98281}, /* U+9081 */ + {0xe7b1, 0xe98280}, /* U+9080 */ + {0xe7b2, 0xe9828a}, /* U+908A */ + {0xe7b3, 0xe98289}, /* U+9089 */ + {0xe7b4, 0xe9828f}, /* U+908F */ + {0xe7b5, 0xe982a8}, /* U+90A8 */ + {0xe7b6, 0xe982af}, /* U+90AF */ + {0xe7b7, 0xe982b1}, /* U+90B1 */ + {0xe7b8, 0xe982b5}, /* U+90B5 */ + {0xe7b9, 0xe983a2}, /* U+90E2 */ + {0xe7ba, 0xe983a4}, /* U+90E4 */ + {0xe7bb, 0xe68988}, /* U+6248 */ + {0xe7bc, 0xe9839b}, /* U+90DB */ + {0xe7bd, 0xe98482}, /* U+9102 */ + {0xe7be, 0xe98492}, /* U+9112 */ + {0xe7bf, 0xe98499}, /* U+9119 */ + {0xe7c0, 0xe984b2}, /* U+9132 */ + {0xe7c1, 0xe984b0}, /* U+9130 */ + {0xe7c2, 0xe9858a}, /* U+914A */ + {0xe7c3, 0xe98596}, /* U+9156 */ + {0xe7c4, 0xe98598}, /* U+9158 */ + {0xe7c5, 0xe985a3}, /* U+9163 */ + {0xe7c6, 0xe985a5}, /* U+9165 */ + {0xe7c7, 0xe985a9}, /* U+9169 */ + {0xe7c8, 0xe985b3}, /* U+9173 */ + {0xe7c9, 0xe985b2}, /* U+9172 */ + {0xe7ca, 0xe9868b}, /* U+918B */ + {0xe7cb, 0xe98689}, /* U+9189 */ + {0xe7cc, 0xe98682}, /* U+9182 */ + {0xe7cd, 0xe986a2}, /* U+91A2 */ + {0xe7ce, 0xe986ab}, /* U+91AB */ + {0xe7cf, 0xe986af}, /* U+91AF */ + {0xe7d0, 0xe986aa}, /* U+91AA */ + {0xe7d1, 0xe986b5}, /* U+91B5 */ + {0xe7d2, 0xe986b4}, /* U+91B4 */ + {0xe7d3, 0xe986ba}, /* U+91BA */ + {0xe7d4, 0xe98780}, /* U+91C0 */ + {0xe7d5, 0xe98781}, /* U+91C1 */ + {0xe7d6, 0xe98789}, /* U+91C9 */ + {0xe7d7, 0xe9878b}, /* U+91CB */ + {0xe7d8, 0xe98790}, /* U+91D0 */ + {0xe7d9, 0xe98796}, /* U+91D6 */ + {0xe7da, 0xe9879f}, /* U+91DF */ + {0xe7db, 0xe987a1}, /* U+91E1 */ + {0xe7dc, 0xe9879b}, /* U+91DB */ + {0xe7dd, 0xe987bc}, /* U+91FC */ + {0xe7de, 0xe987b5}, /* U+91F5 */ + {0xe7df, 0xe987b6}, /* U+91F6 */ + {0xe7e0, 0xe9889e}, /* U+921E */ + {0xe7e1, 0xe987bf}, /* U+91FF */ + {0xe7e2, 0xe98894}, /* U+9214 */ + {0xe7e3, 0xe988ac}, /* U+922C */ + {0xe7e4, 0xe98895}, /* U+9215 */ + {0xe7e5, 0xe98891}, /* U+9211 */ + {0xe7e6, 0xe9899e}, /* U+925E */ + {0xe7e7, 0xe98997}, /* U+9257 */ + {0xe7e8, 0xe98985}, /* U+9245 */ + {0xe7e9, 0xe98989}, /* U+9249 */ + {0xe7ea, 0xe989a4}, /* U+9264 */ + {0xe7eb, 0xe98988}, /* U+9248 */ + {0xe7ec, 0xe98a95}, /* U+9295 */ + {0xe7ed, 0xe988bf}, /* U+923F */ + {0xe7ee, 0xe9898b}, /* U+924B */ + {0xe7ef, 0xe98990}, /* U+9250 */ + {0xe7f0, 0xe98a9c}, /* U+929C */ + {0xe7f1, 0xe98a96}, /* U+9296 */ + {0xe7f2, 0xe98a93}, /* U+9293 */ + {0xe7f3, 0xe98a9b}, /* U+929B */ + {0xe7f4, 0xe9899a}, /* U+925A */ + {0xe7f5, 0xe98b8f}, /* U+92CF */ + {0xe7f6, 0xe98ab9}, /* U+92B9 */ + {0xe7f7, 0xe98ab7}, /* U+92B7 */ + {0xe7f8, 0xe98ba9}, /* U+92E9 */ + {0xe7f9, 0xe98c8f}, /* U+930F */ + {0xe7fa, 0xe98bba}, /* U+92FA */ + {0xe7fb, 0xe98d84}, /* U+9344 */ + {0xe7fc, 0xe98cae}, /* U+932E */ + {0xe840, 0xe98c99}, /* U+9319 */ + {0xe841, 0xe98ca2}, /* U+9322 */ + {0xe842, 0xe98c9a}, /* U+931A */ + {0xe843, 0xe98ca3}, /* U+9323 */ + {0xe844, 0xe98cba}, /* U+933A */ + {0xe845, 0xe98cb5}, /* U+9335 */ + {0xe846, 0xe98cbb}, /* U+933B */ + {0xe847, 0xe98d9c}, /* U+935C */ + {0xe848, 0xe98da0}, /* U+9360 */ + {0xe849, 0xe98dbc}, /* U+937C */ + {0xe84a, 0xe98dae}, /* U+936E */ + {0xe84b, 0xe98d96}, /* U+9356 */ + {0xe84c, 0xe98eb0}, /* U+93B0 */ + {0xe84d, 0xe98eac}, /* U+93AC */ + {0xe84e, 0xe98ead}, /* U+93AD */ + {0xe84f, 0xe98e94}, /* U+9394 */ + {0xe850, 0xe98eb9}, /* U+93B9 */ + {0xe851, 0xe98f96}, /* U+93D6 */ + {0xe852, 0xe98f97}, /* U+93D7 */ + {0xe853, 0xe98fa8}, /* U+93E8 */ + {0xe854, 0xe98fa5}, /* U+93E5 */ + {0xe855, 0xe98f98}, /* U+93D8 */ + {0xe856, 0xe98f83}, /* U+93C3 */ + {0xe857, 0xe98f9d}, /* U+93DD */ + {0xe858, 0xe98f90}, /* U+93D0 */ + {0xe859, 0xe98f88}, /* U+93C8 */ + {0xe85a, 0xe98fa4}, /* U+93E4 */ + {0xe85b, 0xe9909a}, /* U+941A */ + {0xe85c, 0xe99094}, /* U+9414 */ + {0xe85d, 0xe99093}, /* U+9413 */ + {0xe85e, 0xe99083}, /* U+9403 */ + {0xe85f, 0xe99087}, /* U+9407 */ + {0xe860, 0xe99090}, /* U+9410 */ + {0xe861, 0xe990b6}, /* U+9436 */ + {0xe862, 0xe990ab}, /* U+942B */ + {0xe863, 0xe990b5}, /* U+9435 */ + {0xe864, 0xe990a1}, /* U+9421 */ + {0xe865, 0xe990ba}, /* U+943A */ + {0xe866, 0xe99181}, /* U+9441 */ + {0xe867, 0xe99192}, /* U+9452 */ + {0xe868, 0xe99184}, /* U+9444 */ + {0xe869, 0xe9919b}, /* U+945B */ + {0xe86a, 0xe991a0}, /* U+9460 */ + {0xe86b, 0xe991a2}, /* U+9462 */ + {0xe86c, 0xe9919e}, /* U+945E */ + {0xe86d, 0xe991aa}, /* U+946A */ + {0xe86e, 0xe988a9}, /* U+9229 */ + {0xe86f, 0xe991b0}, /* U+9470 */ + {0xe870, 0xe991b5}, /* U+9475 */ + {0xe871, 0xe991b7}, /* U+9477 */ + {0xe872, 0xe991bd}, /* U+947D */ + {0xe873, 0xe9919a}, /* U+945A */ + {0xe874, 0xe991bc}, /* U+947C */ + {0xe875, 0xe991be}, /* U+947E */ + {0xe876, 0xe99281}, /* U+9481 */ + {0xe877, 0xe991bf}, /* U+947F */ + {0xe878, 0xe99682}, /* U+9582 */ + {0xe879, 0xe99687}, /* U+9587 */ + {0xe87a, 0xe9968a}, /* U+958A */ + {0xe87b, 0xe99694}, /* U+9594 */ + {0xe87c, 0xe99696}, /* U+9596 */ + {0xe87d, 0xe99698}, /* U+9598 */ + {0xe87e, 0xe99699}, /* U+9599 */ + {0xe880, 0xe996a0}, /* U+95A0 */ + {0xe881, 0xe996a8}, /* U+95A8 */ + {0xe882, 0xe996a7}, /* U+95A7 */ + {0xe883, 0xe996ad}, /* U+95AD */ + {0xe884, 0xe996bc}, /* U+95BC */ + {0xe885, 0xe996bb}, /* U+95BB */ + {0xe886, 0xe996b9}, /* U+95B9 */ + {0xe887, 0xe996be}, /* U+95BE */ + {0xe888, 0xe9978a}, /* U+95CA */ + {0xe889, 0xe6bfb6}, /* U+6FF6 */ + {0xe88a, 0xe99783}, /* U+95C3 */ + {0xe88b, 0xe9978d}, /* U+95CD */ + {0xe88c, 0xe9978c}, /* U+95CC */ + {0xe88d, 0xe99795}, /* U+95D5 */ + {0xe88e, 0xe99794}, /* U+95D4 */ + {0xe88f, 0xe99796}, /* U+95D6 */ + {0xe890, 0xe9979c}, /* U+95DC */ + {0xe891, 0xe997a1}, /* U+95E1 */ + {0xe892, 0xe997a5}, /* U+95E5 */ + {0xe893, 0xe997a2}, /* U+95E2 */ + {0xe894, 0xe998a1}, /* U+9621 */ + {0xe895, 0xe998a8}, /* U+9628 */ + {0xe896, 0xe998ae}, /* U+962E */ + {0xe897, 0xe998af}, /* U+962F */ + {0xe898, 0xe99982}, /* U+9642 */ + {0xe899, 0xe9998c}, /* U+964C */ + {0xe89a, 0xe9998f}, /* U+964F */ + {0xe89b, 0xe9998b}, /* U+964B */ + {0xe89c, 0xe999b7}, /* U+9677 */ + {0xe89d, 0xe9999c}, /* U+965C */ + {0xe89e, 0xe9999e}, /* U+965E */ + {0xe89f, 0xe9999d}, /* U+965D */ + {0xe8a0, 0xe9999f}, /* U+965F */ + {0xe8a1, 0xe999a6}, /* U+9666 */ + {0xe8a2, 0xe999b2}, /* U+9672 */ + {0xe8a3, 0xe999ac}, /* U+966C */ + {0xe8a4, 0xe99a8d}, /* U+968D */ + {0xe8a5, 0xe99a98}, /* U+9698 */ + {0xe8a6, 0xe99a95}, /* U+9695 */ + {0xe8a7, 0xe99a97}, /* U+9697 */ + {0xe8a8, 0xe99aaa}, /* U+96AA */ + {0xe8a9, 0xe99aa7}, /* U+96A7 */ + {0xe8aa, 0xe99ab1}, /* U+96B1 */ + {0xe8ab, 0xe99ab2}, /* U+96B2 */ + {0xe8ac, 0xe99ab0}, /* U+96B0 */ + {0xe8ad, 0xe99ab4}, /* U+96B4 */ + {0xe8ae, 0xe99ab6}, /* U+96B6 */ + {0xe8af, 0xe99ab8}, /* U+96B8 */ + {0xe8b0, 0xe99ab9}, /* U+96B9 */ + {0xe8b1, 0xe99b8e}, /* U+96CE */ + {0xe8b2, 0xe99b8b}, /* U+96CB */ + {0xe8b3, 0xe99b89}, /* U+96C9 */ + {0xe8b4, 0xe99b8d}, /* U+96CD */ + {0xe8b5, 0xe8a58d}, /* U+894D */ + {0xe8b6, 0xe99b9c}, /* U+96DC */ + {0xe8b7, 0xe99c8d}, /* U+970D */ + {0xe8b8, 0xe99b95}, /* U+96D5 */ + {0xe8b9, 0xe99bb9}, /* U+96F9 */ + {0xe8ba, 0xe99c84}, /* U+9704 */ + {0xe8bb, 0xe99c86}, /* U+9706 */ + {0xe8bc, 0xe99c88}, /* U+9708 */ + {0xe8bd, 0xe99c93}, /* U+9713 */ + {0xe8be, 0xe99c8e}, /* U+970E */ + {0xe8bf, 0xe99c91}, /* U+9711 */ + {0xe8c0, 0xe99c8f}, /* U+970F */ + {0xe8c1, 0xe99c96}, /* U+9716 */ + {0xe8c2, 0xe99c99}, /* U+9719 */ + {0xe8c3, 0xe99ca4}, /* U+9724 */ + {0xe8c4, 0xe99caa}, /* U+972A */ + {0xe8c5, 0xe99cb0}, /* U+9730 */ + {0xe8c6, 0xe99cb9}, /* U+9739 */ + {0xe8c7, 0xe99cbd}, /* U+973D */ + {0xe8c8, 0xe99cbe}, /* U+973E */ + {0xe8c9, 0xe99d84}, /* U+9744 */ + {0xe8ca, 0xe99d86}, /* U+9746 */ + {0xe8cb, 0xe99d88}, /* U+9748 */ + {0xe8cc, 0xe99d82}, /* U+9742 */ + {0xe8cd, 0xe99d89}, /* U+9749 */ + {0xe8ce, 0xe99d9c}, /* U+975C */ + {0xe8cf, 0xe99da0}, /* U+9760 */ + {0xe8d0, 0xe99da4}, /* U+9764 */ + {0xe8d1, 0xe99da6}, /* U+9766 */ + {0xe8d2, 0xe99da8}, /* U+9768 */ + {0xe8d3, 0xe58b92}, /* U+52D2 */ + {0xe8d4, 0xe99dab}, /* U+976B */ + {0xe8d5, 0xe99db1}, /* U+9771 */ + {0xe8d6, 0xe99db9}, /* U+9779 */ + {0xe8d7, 0xe99e85}, /* U+9785 */ + {0xe8d8, 0xe99dbc}, /* U+977C */ + {0xe8d9, 0xe99e81}, /* U+9781 */ + {0xe8da, 0xe99dba}, /* U+977A */ + {0xe8db, 0xe99e86}, /* U+9786 */ + {0xe8dc, 0xe99e8b}, /* U+978B */ + {0xe8dd, 0xe99e8f}, /* U+978F */ + {0xe8de, 0xe99e90}, /* U+9790 */ + {0xe8df, 0xe99e9c}, /* U+979C */ + {0xe8e0, 0xe99ea8}, /* U+97A8 */ + {0xe8e1, 0xe99ea6}, /* U+97A6 */ + {0xe8e2, 0xe99ea3}, /* U+97A3 */ + {0xe8e3, 0xe99eb3}, /* U+97B3 */ + {0xe8e4, 0xe99eb4}, /* U+97B4 */ + {0xe8e5, 0xe99f83}, /* U+97C3 */ + {0xe8e6, 0xe99f86}, /* U+97C6 */ + {0xe8e7, 0xe99f88}, /* U+97C8 */ + {0xe8e8, 0xe99f8b}, /* U+97CB */ + {0xe8e9, 0xe99f9c}, /* U+97DC */ + {0xe8ea, 0xe99fad}, /* U+97ED */ + {0xe8eb, 0xe9bd8f}, /* U+9F4F */ + {0xe8ec, 0xe99fb2}, /* U+97F2 */ + {0xe8ed, 0xe7ab9f}, /* U+7ADF */ + {0xe8ee, 0xe99fb6}, /* U+97F6 */ + {0xe8ef, 0xe99fb5}, /* U+97F5 */ + {0xe8f0, 0xe9a08f}, /* U+980F */ + {0xe8f1, 0xe9a08c}, /* U+980C */ + {0xe8f2, 0xe9a0b8}, /* U+9838 */ + {0xe8f3, 0xe9a0a4}, /* U+9824 */ + {0xe8f4, 0xe9a0a1}, /* U+9821 */ + {0xe8f5, 0xe9a0b7}, /* U+9837 */ + {0xe8f6, 0xe9a0bd}, /* U+983D */ + {0xe8f7, 0xe9a186}, /* U+9846 */ + {0xe8f8, 0xe9a18f}, /* U+984F */ + {0xe8f9, 0xe9a18b}, /* U+984B */ + {0xe8fa, 0xe9a1ab}, /* U+986B */ + {0xe8fb, 0xe9a1af}, /* U+986F */ + {0xe8fc, 0xe9a1b0}, /* U+9870 */ + {0xe940, 0xe9a1b1}, /* U+9871 */ + {0xe941, 0xe9a1b4}, /* U+9874 */ + {0xe942, 0xe9a1b3}, /* U+9873 */ + {0xe943, 0xe9a2aa}, /* U+98AA */ + {0xe944, 0xe9a2af}, /* U+98AF */ + {0xe945, 0xe9a2b1}, /* U+98B1 */ + {0xe946, 0xe9a2b6}, /* U+98B6 */ + {0xe947, 0xe9a384}, /* U+98C4 */ + {0xe948, 0xe9a383}, /* U+98C3 */ + {0xe949, 0xe9a386}, /* U+98C6 */ + {0xe94a, 0xe9a3a9}, /* U+98E9 */ + {0xe94b, 0xe9a3ab}, /* U+98EB */ + {0xe94c, 0xe9a483}, /* U+9903 */ + {0xe94d, 0xe9a489}, /* U+9909 */ + {0xe94e, 0xe9a492}, /* U+9912 */ + {0xe94f, 0xe9a494}, /* U+9914 */ + {0xe950, 0xe9a498}, /* U+9918 */ + {0xe951, 0xe9a4a1}, /* U+9921 */ + {0xe952, 0xe9a49d}, /* U+991D */ + {0xe953, 0xe9a49e}, /* U+991E */ + {0xe954, 0xe9a4a4}, /* U+9924 */ + {0xe955, 0xe9a4a0}, /* U+9920 */ + {0xe956, 0xe9a4ac}, /* U+992C */ + {0xe957, 0xe9a4ae}, /* U+992E */ + {0xe958, 0xe9a4bd}, /* U+993D */ + {0xe959, 0xe9a4be}, /* U+993E */ + {0xe95a, 0xe9a582}, /* U+9942 */ + {0xe95b, 0xe9a589}, /* U+9949 */ + {0xe95c, 0xe9a585}, /* U+9945 */ + {0xe95d, 0xe9a590}, /* U+9950 */ + {0xe95e, 0xe9a58b}, /* U+994B */ + {0xe95f, 0xe9a591}, /* U+9951 */ + {0xe960, 0xe9a592}, /* U+9952 */ + {0xe961, 0xe9a58c}, /* U+994C */ + {0xe962, 0xe9a595}, /* U+9955 */ + {0xe963, 0xe9a697}, /* U+9997 */ + {0xe964, 0xe9a698}, /* U+9998 */ + {0xe965, 0xe9a6a5}, /* U+99A5 */ + {0xe966, 0xe9a6ad}, /* U+99AD */ + {0xe967, 0xe9a6ae}, /* U+99AE */ + {0xe968, 0xe9a6bc}, /* U+99BC */ + {0xe969, 0xe9a79f}, /* U+99DF */ + {0xe96a, 0xe9a79b}, /* U+99DB */ + {0xe96b, 0xe9a79d}, /* U+99DD */ + {0xe96c, 0xe9a798}, /* U+99D8 */ + {0xe96d, 0xe9a791}, /* U+99D1 */ + {0xe96e, 0xe9a7ad}, /* U+99ED */ + {0xe96f, 0xe9a7ae}, /* U+99EE */ + {0xe970, 0xe9a7b1}, /* U+99F1 */ + {0xe971, 0xe9a7b2}, /* U+99F2 */ + {0xe972, 0xe9a7bb}, /* U+99FB */ + {0xe973, 0xe9a7b8}, /* U+99F8 */ + {0xe974, 0xe9a881}, /* U+9A01 */ + {0xe975, 0xe9a88f}, /* U+9A0F */ + {0xe976, 0xe9a885}, /* U+9A05 */ + {0xe977, 0xe9a7a2}, /* U+99E2 */ + {0xe978, 0xe9a899}, /* U+9A19 */ + {0xe979, 0xe9a8ab}, /* U+9A2B */ + {0xe97a, 0xe9a8b7}, /* U+9A37 */ + {0xe97b, 0xe9a985}, /* U+9A45 */ + {0xe97c, 0xe9a982}, /* U+9A42 */ + {0xe97d, 0xe9a980}, /* U+9A40 */ + {0xe97e, 0xe9a983}, /* U+9A43 */ + {0xe980, 0xe9a8be}, /* U+9A3E */ + {0xe981, 0xe9a995}, /* U+9A55 */ + {0xe982, 0xe9a98d}, /* U+9A4D */ + {0xe983, 0xe9a99b}, /* U+9A5B */ + {0xe984, 0xe9a997}, /* U+9A57 */ + {0xe985, 0xe9a99f}, /* U+9A5F */ + {0xe986, 0xe9a9a2}, /* U+9A62 */ + {0xe987, 0xe9a9a5}, /* U+9A65 */ + {0xe988, 0xe9a9a4}, /* U+9A64 */ + {0xe989, 0xe9a9a9}, /* U+9A69 */ + {0xe98a, 0xe9a9ab}, /* U+9A6B */ + {0xe98b, 0xe9a9aa}, /* U+9A6A */ + {0xe98c, 0xe9aaad}, /* U+9AAD */ + {0xe98d, 0xe9aab0}, /* U+9AB0 */ + {0xe98e, 0xe9aabc}, /* U+9ABC */ + {0xe98f, 0xe9ab80}, /* U+9AC0 */ + {0xe990, 0xe9ab8f}, /* U+9ACF */ + {0xe991, 0xe9ab91}, /* U+9AD1 */ + {0xe992, 0xe9ab93}, /* U+9AD3 */ + {0xe993, 0xe9ab94}, /* U+9AD4 */ + {0xe994, 0xe9ab9e}, /* U+9ADE */ + {0xe995, 0xe9ab9f}, /* U+9ADF */ + {0xe996, 0xe9aba2}, /* U+9AE2 */ + {0xe997, 0xe9aba3}, /* U+9AE3 */ + {0xe998, 0xe9aba6}, /* U+9AE6 */ + {0xe999, 0xe9abaf}, /* U+9AEF */ + {0xe99a, 0xe9abab}, /* U+9AEB */ + {0xe99b, 0xe9abae}, /* U+9AEE */ + {0xe99c, 0xe9abb4}, /* U+9AF4 */ + {0xe99d, 0xe9abb1}, /* U+9AF1 */ + {0xe99e, 0xe9abb7}, /* U+9AF7 */ + {0xe99f, 0xe9abbb}, /* U+9AFB */ + {0xe9a0, 0xe9ac86}, /* U+9B06 */ + {0xe9a1, 0xe9ac98}, /* U+9B18 */ + {0xe9a2, 0xe9ac9a}, /* U+9B1A */ + {0xe9a3, 0xe9ac9f}, /* U+9B1F */ + {0xe9a4, 0xe9aca2}, /* U+9B22 */ + {0xe9a5, 0xe9aca3}, /* U+9B23 */ + {0xe9a6, 0xe9aca5}, /* U+9B25 */ + {0xe9a7, 0xe9aca7}, /* U+9B27 */ + {0xe9a8, 0xe9aca8}, /* U+9B28 */ + {0xe9a9, 0xe9aca9}, /* U+9B29 */ + {0xe9aa, 0xe9acaa}, /* U+9B2A */ + {0xe9ab, 0xe9acae}, /* U+9B2E */ + {0xe9ac, 0xe9acaf}, /* U+9B2F */ + {0xe9ad, 0xe9acb2}, /* U+9B32 */ + {0xe9ae, 0xe9ad84}, /* U+9B44 */ + {0xe9af, 0xe9ad83}, /* U+9B43 */ + {0xe9b0, 0xe9ad8f}, /* U+9B4F */ + {0xe9b1, 0xe9ad8d}, /* U+9B4D */ + {0xe9b2, 0xe9ad8e}, /* U+9B4E */ + {0xe9b3, 0xe9ad91}, /* U+9B51 */ + {0xe9b4, 0xe9ad98}, /* U+9B58 */ + {0xe9b5, 0xe9adb4}, /* U+9B74 */ + {0xe9b6, 0xe9ae93}, /* U+9B93 */ + {0xe9b7, 0xe9ae83}, /* U+9B83 */ + {0xe9b8, 0xe9ae91}, /* U+9B91 */ + {0xe9b9, 0xe9ae96}, /* U+9B96 */ + {0xe9ba, 0xe9ae97}, /* U+9B97 */ + {0xe9bb, 0xe9ae9f}, /* U+9B9F */ + {0xe9bc, 0xe9aea0}, /* U+9BA0 */ + {0xe9bd, 0xe9aea8}, /* U+9BA8 */ + {0xe9be, 0xe9aeb4}, /* U+9BB4 */ + {0xe9bf, 0xe9af80}, /* U+9BC0 */ + {0xe9c0, 0xe9af8a}, /* U+9BCA */ + {0xe9c1, 0xe9aeb9}, /* U+9BB9 */ + {0xe9c2, 0xe9af86}, /* U+9BC6 */ + {0xe9c3, 0xe9af8f}, /* U+9BCF */ + {0xe9c4, 0xe9af91}, /* U+9BD1 */ + {0xe9c5, 0xe9af92}, /* U+9BD2 */ + {0xe9c6, 0xe9afa3}, /* U+9BE3 */ + {0xe9c7, 0xe9afa2}, /* U+9BE2 */ + {0xe9c8, 0xe9afa4}, /* U+9BE4 */ + {0xe9c9, 0xe9af94}, /* U+9BD4 */ + {0xe9ca, 0xe9afa1}, /* U+9BE1 */ + {0xe9cb, 0xe9b0ba}, /* U+9C3A */ + {0xe9cc, 0xe9afb2}, /* U+9BF2 */ + {0xe9cd, 0xe9afb1}, /* U+9BF1 */ + {0xe9ce, 0xe9afb0}, /* U+9BF0 */ + {0xe9cf, 0xe9b095}, /* U+9C15 */ + {0xe9d0, 0xe9b094}, /* U+9C14 */ + {0xe9d1, 0xe9b089}, /* U+9C09 */ + {0xe9d2, 0xe9b093}, /* U+9C13 */ + {0xe9d3, 0xe9b08c}, /* U+9C0C */ + {0xe9d4, 0xe9b086}, /* U+9C06 */ + {0xe9d5, 0xe9b088}, /* U+9C08 */ + {0xe9d6, 0xe9b092}, /* U+9C12 */ + {0xe9d7, 0xe9b08a}, /* U+9C0A */ + {0xe9d8, 0xe9b084}, /* U+9C04 */ + {0xe9d9, 0xe9b0ae}, /* U+9C2E */ + {0xe9da, 0xe9b09b}, /* U+9C1B */ + {0xe9db, 0xe9b0a5}, /* U+9C25 */ + {0xe9dc, 0xe9b0a4}, /* U+9C24 */ + {0xe9dd, 0xe9b0a1}, /* U+9C21 */ + {0xe9de, 0xe9b0b0}, /* U+9C30 */ + {0xe9df, 0xe9b187}, /* U+9C47 */ + {0xe9e0, 0xe9b0b2}, /* U+9C32 */ + {0xe9e1, 0xe9b186}, /* U+9C46 */ + {0xe9e2, 0xe9b0be}, /* U+9C3E */ + {0xe9e3, 0xe9b19a}, /* U+9C5A */ + {0xe9e4, 0xe9b1a0}, /* U+9C60 */ + {0xe9e5, 0xe9b1a7}, /* U+9C67 */ + {0xe9e6, 0xe9b1b6}, /* U+9C76 */ + {0xe9e7, 0xe9b1b8}, /* U+9C78 */ + {0xe9e8, 0xe9b3a7}, /* U+9CE7 */ + {0xe9e9, 0xe9b3ac}, /* U+9CEC */ + {0xe9ea, 0xe9b3b0}, /* U+9CF0 */ + {0xe9eb, 0xe9b489}, /* U+9D09 */ + {0xe9ec, 0xe9b488}, /* U+9D08 */ + {0xe9ed, 0xe9b3ab}, /* U+9CEB */ + {0xe9ee, 0xe9b483}, /* U+9D03 */ + {0xe9ef, 0xe9b486}, /* U+9D06 */ + {0xe9f0, 0xe9b4aa}, /* U+9D2A */ + {0xe9f1, 0xe9b4a6}, /* U+9D26 */ + {0xe9f2, 0xe9b6af}, /* U+9DAF */ + {0xe9f3, 0xe9b4a3}, /* U+9D23 */ + {0xe9f4, 0xe9b49f}, /* U+9D1F */ + {0xe9f5, 0xe9b584}, /* U+9D44 */ + {0xe9f6, 0xe9b495}, /* U+9D15 */ + {0xe9f7, 0xe9b492}, /* U+9D12 */ + {0xe9f8, 0xe9b581}, /* U+9D41 */ + {0xe9f9, 0xe9b4bf}, /* U+9D3F */ + {0xe9fa, 0xe9b4be}, /* U+9D3E */ + {0xe9fb, 0xe9b586}, /* U+9D46 */ + {0xe9fc, 0xe9b588}, /* U+9D48 */ + {0xea40, 0xe9b59d}, /* U+9D5D */ + {0xea41, 0xe9b59e}, /* U+9D5E */ + {0xea42, 0xe9b5a4}, /* U+9D64 */ + {0xea43, 0xe9b591}, /* U+9D51 */ + {0xea44, 0xe9b590}, /* U+9D50 */ + {0xea45, 0xe9b599}, /* U+9D59 */ + {0xea46, 0xe9b5b2}, /* U+9D72 */ + {0xea47, 0xe9b689}, /* U+9D89 */ + {0xea48, 0xe9b687}, /* U+9D87 */ + {0xea49, 0xe9b6ab}, /* U+9DAB */ + {0xea4a, 0xe9b5af}, /* U+9D6F */ + {0xea4b, 0xe9b5ba}, /* U+9D7A */ + {0xea4c, 0xe9b69a}, /* U+9D9A */ + {0xea4d, 0xe9b6a4}, /* U+9DA4 */ + {0xea4e, 0xe9b6a9}, /* U+9DA9 */ + {0xea4f, 0xe9b6b2}, /* U+9DB2 */ + {0xea50, 0xe9b784}, /* U+9DC4 */ + {0xea51, 0xe9b781}, /* U+9DC1 */ + {0xea52, 0xe9b6bb}, /* U+9DBB */ + {0xea53, 0xe9b6b8}, /* U+9DB8 */ + {0xea54, 0xe9b6ba}, /* U+9DBA */ + {0xea55, 0xe9b786}, /* U+9DC6 */ + {0xea56, 0xe9b78f}, /* U+9DCF */ + {0xea57, 0xe9b782}, /* U+9DC2 */ + {0xea58, 0xe9b799}, /* U+9DD9 */ + {0xea59, 0xe9b793}, /* U+9DD3 */ + {0xea5a, 0xe9b7b8}, /* U+9DF8 */ + {0xea5b, 0xe9b7a6}, /* U+9DE6 */ + {0xea5c, 0xe9b7ad}, /* U+9DED */ + {0xea5d, 0xe9b7af}, /* U+9DEF */ + {0xea5e, 0xe9b7bd}, /* U+9DFD */ + {0xea5f, 0xe9b89a}, /* U+9E1A */ + {0xea60, 0xe9b89b}, /* U+9E1B */ + {0xea61, 0xe9b89e}, /* U+9E1E */ + {0xea62, 0xe9b9b5}, /* U+9E75 */ + {0xea63, 0xe9b9b9}, /* U+9E79 */ + {0xea64, 0xe9b9bd}, /* U+9E7D */ + {0xea65, 0xe9ba81}, /* U+9E81 */ + {0xea66, 0xe9ba88}, /* U+9E88 */ + {0xea67, 0xe9ba8b}, /* U+9E8B */ + {0xea68, 0xe9ba8c}, /* U+9E8C */ + {0xea69, 0xe9ba92}, /* U+9E92 */ + {0xea6a, 0xe9ba95}, /* U+9E95 */ + {0xea6b, 0xe9ba91}, /* U+9E91 */ + {0xea6c, 0xe9ba9d}, /* U+9E9D */ + {0xea6d, 0xe9baa5}, /* U+9EA5 */ + {0xea6e, 0xe9baa9}, /* U+9EA9 */ + {0xea6f, 0xe9bab8}, /* U+9EB8 */ + {0xea70, 0xe9baaa}, /* U+9EAA */ + {0xea71, 0xe9baad}, /* U+9EAD */ + {0xea72, 0xe99da1}, /* U+9761 */ + {0xea73, 0xe9bb8c}, /* U+9ECC */ + {0xea74, 0xe9bb8e}, /* U+9ECE */ + {0xea75, 0xe9bb8f}, /* U+9ECF */ + {0xea76, 0xe9bb90}, /* U+9ED0 */ + {0xea77, 0xe9bb94}, /* U+9ED4 */ + {0xea78, 0xe9bb9c}, /* U+9EDC */ + {0xea79, 0xe9bb9e}, /* U+9EDE */ + {0xea7a, 0xe9bb9d}, /* U+9EDD */ + {0xea7b, 0xe9bba0}, /* U+9EE0 */ + {0xea7c, 0xe9bba5}, /* U+9EE5 */ + {0xea7d, 0xe9bba8}, /* U+9EE8 */ + {0xea7e, 0xe9bbaf}, /* U+9EEF */ + {0xea80, 0xe9bbb4}, /* U+9EF4 */ + {0xea81, 0xe9bbb6}, /* U+9EF6 */ + {0xea82, 0xe9bbb7}, /* U+9EF7 */ + {0xea83, 0xe9bbb9}, /* U+9EF9 */ + {0xea84, 0xe9bbbb}, /* U+9EFB */ + {0xea85, 0xe9bbbc}, /* U+9EFC */ + {0xea86, 0xe9bbbd}, /* U+9EFD */ + {0xea87, 0xe9bc87}, /* U+9F07 */ + {0xea88, 0xe9bc88}, /* U+9F08 */ + {0xea89, 0xe79ab7}, /* U+76B7 */ + {0xea8a, 0xe9bc95}, /* U+9F15 */ + {0xea8b, 0xe9bca1}, /* U+9F21 */ + {0xea8c, 0xe9bcac}, /* U+9F2C */ + {0xea8d, 0xe9bcbe}, /* U+9F3E */ + {0xea8e, 0xe9bd8a}, /* U+9F4A */ + {0xea8f, 0xe9bd92}, /* U+9F52 */ + {0xea90, 0xe9bd94}, /* U+9F54 */ + {0xea91, 0xe9bda3}, /* U+9F63 */ + {0xea92, 0xe9bd9f}, /* U+9F5F */ + {0xea93, 0xe9bda0}, /* U+9F60 */ + {0xea94, 0xe9bda1}, /* U+9F61 */ + {0xea95, 0xe9bda6}, /* U+9F66 */ + {0xea96, 0xe9bda7}, /* U+9F67 */ + {0xea97, 0xe9bdac}, /* U+9F6C */ + {0xea98, 0xe9bdaa}, /* U+9F6A */ + {0xea99, 0xe9bdb7}, /* U+9F77 */ + {0xea9a, 0xe9bdb2}, /* U+9F72 */ + {0xea9b, 0xe9bdb6}, /* U+9F76 */ + {0xea9c, 0xe9be95}, /* U+9F95 */ + {0xea9d, 0xe9be9c}, /* U+9F9C */ + {0xea9e, 0xe9bea0}, /* U+9FA0 */ + {0xea9f, 0xe5a0af}, /* U+582F [1983] */ + {0xeaa0, 0xe6a787}, /* U+69C7 [1983] */ + {0xeaa1, 0xe98199}, /* U+9059 [1983] */ + {0xeaa2, 0xe791a4}, /* U+7464 [1983] */ + {0xeaa3, 0xe5879c}, /* U+51DC [1990] */ + {0xeaa4, 0xe78699}, /* U+7199 [1990] */ + {0xeaa5, 0xe59993}, /* U+5653 [2004] */ + {0xeaa6, 0xe5b7a2}, /* U+5DE2 [2000] */ + {0xeaa7, 0xe5b894}, /* U+5E14 [2000] */ + {0xeaa8, 0xe5b898}, /* U+5E18 [2000] */ + {0xeaa9, 0xe5b998}, /* U+5E58 [2000] */ + {0xeaaa, 0xe5b99e}, /* U+5E5E [2000] */ + {0xeaab, 0xe5babe}, /* U+5EBE [2000] */ + {0xeaac, 0xefa4a8}, /* U+F928 CJK COMPATIBILITY IDEOGRAPH-F928 [2000] */ + {0xeaad, 0xe5bb8b}, /* U+5ECB [2000] */ + {0xeaae, 0xe5bbb9}, /* U+5EF9 [2000] */ + {0xeaaf, 0xe5bc80}, /* U+5F00 [2000] */ + {0xeab0, 0xe5bc82}, /* U+5F02 [2000] */ + {0xeab1, 0xe5bc87}, /* U+5F07 [2000] */ + {0xeab2, 0xe5bc9d}, /* U+5F1D [2000] */ + {0xeab3, 0xe5bca3}, /* U+5F23 [2000] */ + {0xeab4, 0xe5bcb4}, /* U+5F34 [2000] */ + {0xeab5, 0xe5bcb6}, /* U+5F36 [2000] */ + {0xeab6, 0xe5bcbd}, /* U+5F3D [2000] */ + {0xeab7, 0xe5bd80}, /* U+5F40 [2000] */ + {0xeab8, 0xe5bd85}, /* U+5F45 [2000] */ + {0xeab9, 0xe5bd94}, /* U+5F54 [2000] */ + {0xeaba, 0xe5bd98}, /* U+5F58 [2000] */ + {0xeabb, 0xe5bda4}, /* U+5F64 [2000] */ + {0xeabc, 0xe5bda7}, /* U+5F67 [2000] */ + {0xeabd, 0xe5bdbd}, /* U+5F7D [2000] */ + {0xeabe, 0xe5be89}, /* U+5F89 [2000] */ + {0xeabf, 0xe5be9c}, /* U+5F9C [2000] */ + {0xeac0, 0xe5bea7}, /* U+5FA7 [2000] */ + {0xeac1, 0xe5beaf}, /* U+5FAF [2000] */ + {0xeac2, 0xe5beb5}, /* U+5FB5 [2000] */ + {0xeac3, 0xe5beb7}, /* U+5FB7 [2000] */ + {0xeac4, 0xe5bf89}, /* U+5FC9 [2000] */ + {0xeac5, 0xe5bf9e}, /* U+5FDE [2000] */ + {0xeac6, 0xe5bfa1}, /* U+5FE1 [2000] */ + {0xeac7, 0xe5bfa9}, /* U+5FE9 [2000] */ + {0xeac8, 0xe6808d}, /* U+600D [2000] */ + {0xeac9, 0xe68094}, /* U+6014 [2000] */ + {0xeaca, 0xe68098}, /* U+6018 [2000] */ + {0xeacb, 0xe680b3}, /* U+6033 [2000] */ + {0xeacc, 0xe680b5}, /* U+6035 [2000] */ + {0xeacd, 0xe68187}, /* U+6047 [2000] */ + {0xeace, 0xefa8bd}, /* U+FA3D CJK COMPATIBILITY IDEOGRAPH-FA3D [2000] [Unicode3.2] */ + {0xeacf, 0xe6829d}, /* U+609D [2000] */ + {0xead0, 0xe6829e}, /* U+609E [2000] */ + {0xead1, 0xe6838b}, /* U+60CB [2000] */ + {0xead2, 0xe68394}, /* U+60D4 [2000] */ + {0xead3, 0xe68395}, /* U+60D5 [2000] */ + {0xead4, 0xe6839d}, /* U+60DD [2000] */ + {0xead5, 0xe683b8}, /* U+60F8 [2000] */ + {0xead6, 0xe6849c}, /* U+611C [2000] */ + {0xead7, 0xe684ab}, /* U+612B [2000] */ + {0xead8, 0xe684b0}, /* U+6130 [2000] */ + {0xead9, 0xe684b7}, /* U+6137 [2000] */ + {0xeada, 0xefa8be}, /* U+FA3E CJK COMPATIBILITY IDEOGRAPH-FA3E [2000] [Unicode3.2] */ + {0xeadb, 0xe6868d}, /* U+618D [2000] */ + {0xeadc, 0xefa8bf}, /* U+FA3F CJK COMPATIBILITY IDEOGRAPH-FA3F [2000] [Unicode3.2] */ + {0xeadd, 0xe686bc}, /* U+61BC [2000] */ + {0xeade, 0xe686b9}, /* U+61B9 [2000] */ + {0xeadf, 0xefa980}, /* U+FA40 CJK COMPATIBILITY IDEOGRAPH-FA40 [2000] [Unicode3.2] */ + {0xeae0, 0xe688a2}, /* U+6222 [2000] */ + {0xeae1, 0xe688be}, /* U+623E [2000] */ + {0xeae2, 0xe68983}, /* U+6243 [2000] */ + {0xeae3, 0xe68996}, /* U+6256 [2000] */ + {0xeae4, 0xe6899a}, /* U+625A [2000] */ + {0xeae5, 0xe689af}, /* U+626F [2000] */ + {0xeae6, 0xe68a85}, /* U+6285 [2000] */ + {0xeae7, 0xe68b84}, /* U+62C4 [2000] */ + {0xeae8, 0xe68b96}, /* U+62D6 [2000] */ + {0xeae9, 0xe68bbc}, /* U+62FC [2000] */ + {0xeaea, 0xe68c8a}, /* U+630A [2000] */ + {0xeaeb, 0xe68c98}, /* U+6318 [2000] */ + {0xeaec, 0xe68cb9}, /* U+6339 [2000] */ + {0xeaed, 0xe68d83}, /* U+6343 [2000] */ + {0xeaee, 0xe68da5}, /* U+6365 [2000] */ + {0xeaef, 0xe68dbc}, /* U+637C [2000] */ + {0xeaf0, 0xe68fa5}, /* U+63E5 [2000] */ + {0xeaf1, 0xe68fad}, /* U+63ED [2000] */ + {0xeaf2, 0xe68fb5}, /* U+63F5 [2000] */ + {0xeaf3, 0xe69090}, /* U+6410 [2000] */ + {0xeaf4, 0xe69094}, /* U+6414 [2000] */ + {0xeaf5, 0xe690a2}, /* U+6422 [2000] */ + {0xeaf6, 0xe691b9}, /* U+6479 [2000] */ + {0xeaf7, 0xe69191}, /* U+6451 [2000] */ + {0xeaf8, 0xe691a0}, /* U+6460 [2000] */ + {0xeaf9, 0xe691ad}, /* U+646D [2000] */ + {0xeafa, 0xe6938e}, /* U+64CE [2000] */ + {0xeafb, 0xe692be}, /* U+64BE [2000] */ + {0xeafc, 0xe692bf}, /* U+64BF [2000] */ + {0xeb40, 0xe69384}, /* U+64C4 [2000] */ + {0xeb41, 0xe6938a}, /* U+64CA [2000] */ + {0xeb42, 0xe69390}, /* U+64D0 [2000] */ + {0xeb43, 0xe693b7}, /* U+64F7 [2000] */ + {0xeb44, 0xe693bb}, /* U+64FB [2000] */ + {0xeb45, 0xe694a2}, /* U+6522 [2000] */ + {0xeb46, 0xe694a9}, /* U+6529 [2000] */ + {0xeb47, 0xefa981}, /* U+FA41 CJK COMPATIBILITY IDEOGRAPH-FA41 [2000] [Unicode3.2] */ + {0xeb48, 0xe695a7}, /* U+6567 [2000] */ + {0xeb49, 0xe6969d}, /* U+659D [2000] */ + {0xeb4a, 0xefa982}, /* U+FA42 CJK COMPATIBILITY IDEOGRAPH-FA42 [2000] [Unicode3.2] */ + {0xeb4b, 0xe69880}, /* U+6600 [2000] */ + {0xeb4c, 0xe69889}, /* U+6609 [2000] */ + {0xeb4d, 0xe69895}, /* U+6615 [2000] */ + {0xeb4e, 0xe6989e}, /* U+661E [2000] */ + {0xeb4f, 0xe698ba}, /* U+663A [2000] */ + {0xeb50, 0xe698a2}, /* U+6622 [2000] */ + {0xeb51, 0xe698a4}, /* U+6624 [2000] */ + {0xeb52, 0xe698ab}, /* U+662B [2000] */ + {0xeb53, 0xe698b0}, /* U+6630 [2000] */ + {0xeb54, 0xe698b1}, /* U+6631 [2000] */ + {0xeb55, 0xe698b3}, /* U+6633 [2000] */ + {0xeb56, 0xe69bbb}, /* U+66FB [2000] */ + {0xeb57, 0xe69988}, /* U+6648 [2000] */ + {0xeb58, 0xe6998c}, /* U+664C [2000] */ {0xeb59, 0xf0a38784}, /* U+231C4 [2000] [Unicode3.1] */ - {0xeb5a, 0x00e69999}, /* U+6659 [2000] */ - {0xeb5b, 0x00e6999a}, /* U+665A [2000] */ - {0xeb5c, 0x00e699a1}, /* U+6661 [2000] */ - {0xeb5d, 0x00e699a5}, /* U+6665 [2000] */ - {0xeb5e, 0x00e699b3}, /* U+6673 [2000] */ - {0xeb5f, 0x00e699b7}, /* U+6677 [2000] */ - {0xeb60, 0x00e699b8}, /* U+6678 [2000] */ - {0xeb61, 0x00e69a8d}, /* U+668D [2000] */ - {0xeb62, 0x00efa983}, /* U+FA43 CJK COMPATIBILITY IDEOGRAPH-FA43 [2000] [Unicode3.2] */ - {0xeb63, 0x00e69aa0}, /* U+66A0 [2000] */ - {0xeb64, 0x00e69ab2}, /* U+66B2 [2000] */ - {0xeb65, 0x00e69abb}, /* U+66BB [2000] */ - {0xeb66, 0x00e69b86}, /* U+66C6 [2000] */ - {0xeb67, 0x00e69b88}, /* U+66C8 [2000] */ - {0xeb68, 0x00e3aca2}, /* U+3B22 [2000] */ - {0xeb69, 0x00e69b9b}, /* U+66DB [2000] */ - {0xeb6a, 0x00e69ba8}, /* U+66E8 [2000] */ - {0xeb6b, 0x00e69bba}, /* U+66FA [2000] */ - {0xeb6c, 0x00e69c93}, /* U+6713 [2000] */ - {0xeb6d, 0x00efa4a9}, /* U+F929 CJK COMPATIBILITY IDEOGRAPH-F929 [2000] */ - {0xeb6e, 0x00e69cb3}, /* U+6733 [2000] */ - {0xeb6f, 0x00e69da6}, /* U+6766 [2000] */ - {0xeb70, 0x00e69d87}, /* U+6747 [2000] */ - {0xeb71, 0x00e69d88}, /* U+6748 [2000] */ - {0xeb72, 0x00e69dbb}, /* U+677B [2000] */ - {0xeb73, 0x00e69e81}, /* U+6781 [2000] */ - {0xeb74, 0x00e69e93}, /* U+6793 [2000] */ - {0xeb75, 0x00e69e98}, /* U+6798 [2000] */ - {0xeb76, 0x00e69e9b}, /* U+679B [2000] */ - {0xeb77, 0x00e69ebb}, /* U+67BB [2000] */ - {0xeb78, 0x00e69fb9}, /* U+67F9 [2000] */ - {0xeb79, 0x00e69f80}, /* U+67C0 [2000] */ - {0xeb7a, 0x00e69f97}, /* U+67D7 [2000] */ - {0xeb7b, 0x00e69fbc}, /* U+67FC [2000] */ - {0xeb7c, 0x00e6a081}, /* U+6801 [2000] */ - {0xeb7d, 0x00e6a192}, /* U+6852 [2000] */ - {0xeb7e, 0x00e6a09d}, /* U+681D [2000] */ - {0xeb80, 0x00e6a0ac}, /* U+682C [2000] */ - {0xeb81, 0x00e6a0b1}, /* U+6831 [2000] */ - {0xeb82, 0x00e6a19b}, /* U+685B [2000] */ - {0xeb83, 0x00e6a1b2}, /* U+6872 [2000] */ - {0xeb84, 0x00e6a1b5}, /* U+6875 [2000] */ - {0xeb85, 0x00efa984}, /* U+FA44 CJK COMPATIBILITY IDEOGRAPH-FA44 [2000] [Unicode3.2] */ - {0xeb86, 0x00e6a2a3}, /* U+68A3 [2000] */ - {0xeb87, 0x00e6a2a5}, /* U+68A5 [2000] */ - {0xeb88, 0x00e6a2b2}, /* U+68B2 [2000] */ - {0xeb89, 0x00e6a388}, /* U+68C8 [2000] */ - {0xeb8a, 0x00e6a390}, /* U+68D0 [2000] */ - {0xeb8b, 0x00e6a3a8}, /* U+68E8 [2000] */ - {0xeb8c, 0x00e6a3ad}, /* U+68ED [2000] */ - {0xeb8d, 0x00e6a3b0}, /* U+68F0 [2000] */ - {0xeb8e, 0x00e6a3b1}, /* U+68F1 [2000] */ - {0xeb8f, 0x00e6a3bc}, /* U+68FC [2000] */ - {0xeb90, 0x00e6a48a}, /* U+690A [2000] */ - {0xeb91, 0x00e6a589}, /* U+6949 [2000] */ + {0xeb5a, 0xe69999}, /* U+6659 [2000] */ + {0xeb5b, 0xe6999a}, /* U+665A [2000] */ + {0xeb5c, 0xe699a1}, /* U+6661 [2000] */ + {0xeb5d, 0xe699a5}, /* U+6665 [2000] */ + {0xeb5e, 0xe699b3}, /* U+6673 [2000] */ + {0xeb5f, 0xe699b7}, /* U+6677 [2000] */ + {0xeb60, 0xe699b8}, /* U+6678 [2000] */ + {0xeb61, 0xe69a8d}, /* U+668D [2000] */ + {0xeb62, 0xefa983}, /* U+FA43 CJK COMPATIBILITY IDEOGRAPH-FA43 [2000] [Unicode3.2] */ + {0xeb63, 0xe69aa0}, /* U+66A0 [2000] */ + {0xeb64, 0xe69ab2}, /* U+66B2 [2000] */ + {0xeb65, 0xe69abb}, /* U+66BB [2000] */ + {0xeb66, 0xe69b86}, /* U+66C6 [2000] */ + {0xeb67, 0xe69b88}, /* U+66C8 [2000] */ + {0xeb68, 0xe3aca2}, /* U+3B22 [2000] */ + {0xeb69, 0xe69b9b}, /* U+66DB [2000] */ + {0xeb6a, 0xe69ba8}, /* U+66E8 [2000] */ + {0xeb6b, 0xe69bba}, /* U+66FA [2000] */ + {0xeb6c, 0xe69c93}, /* U+6713 [2000] */ + {0xeb6d, 0xefa4a9}, /* U+F929 CJK COMPATIBILITY IDEOGRAPH-F929 [2000] */ + {0xeb6e, 0xe69cb3}, /* U+6733 [2000] */ + {0xeb6f, 0xe69da6}, /* U+6766 [2000] */ + {0xeb70, 0xe69d87}, /* U+6747 [2000] */ + {0xeb71, 0xe69d88}, /* U+6748 [2000] */ + {0xeb72, 0xe69dbb}, /* U+677B [2000] */ + {0xeb73, 0xe69e81}, /* U+6781 [2000] */ + {0xeb74, 0xe69e93}, /* U+6793 [2000] */ + {0xeb75, 0xe69e98}, /* U+6798 [2000] */ + {0xeb76, 0xe69e9b}, /* U+679B [2000] */ + {0xeb77, 0xe69ebb}, /* U+67BB [2000] */ + {0xeb78, 0xe69fb9}, /* U+67F9 [2000] */ + {0xeb79, 0xe69f80}, /* U+67C0 [2000] */ + {0xeb7a, 0xe69f97}, /* U+67D7 [2000] */ + {0xeb7b, 0xe69fbc}, /* U+67FC [2000] */ + {0xeb7c, 0xe6a081}, /* U+6801 [2000] */ + {0xeb7d, 0xe6a192}, /* U+6852 [2000] */ + {0xeb7e, 0xe6a09d}, /* U+681D [2000] */ + {0xeb80, 0xe6a0ac}, /* U+682C [2000] */ + {0xeb81, 0xe6a0b1}, /* U+6831 [2000] */ + {0xeb82, 0xe6a19b}, /* U+685B [2000] */ + {0xeb83, 0xe6a1b2}, /* U+6872 [2000] */ + {0xeb84, 0xe6a1b5}, /* U+6875 [2000] */ + {0xeb85, 0xefa984}, /* U+FA44 CJK COMPATIBILITY IDEOGRAPH-FA44 [2000] [Unicode3.2] */ + {0xeb86, 0xe6a2a3}, /* U+68A3 [2000] */ + {0xeb87, 0xe6a2a5}, /* U+68A5 [2000] */ + {0xeb88, 0xe6a2b2}, /* U+68B2 [2000] */ + {0xeb89, 0xe6a388}, /* U+68C8 [2000] */ + {0xeb8a, 0xe6a390}, /* U+68D0 [2000] */ + {0xeb8b, 0xe6a3a8}, /* U+68E8 [2000] */ + {0xeb8c, 0xe6a3ad}, /* U+68ED [2000] */ + {0xeb8d, 0xe6a3b0}, /* U+68F0 [2000] */ + {0xeb8e, 0xe6a3b1}, /* U+68F1 [2000] */ + {0xeb8f, 0xe6a3bc}, /* U+68FC [2000] */ + {0xeb90, 0xe6a48a}, /* U+690A [2000] */ + {0xeb91, 0xe6a589}, /* U+6949 [2000] */ {0xeb92, 0xf0a39784}, /* U+235C4 [2000] [Unicode3.1] */ - {0xeb93, 0x00e6a4b5}, /* U+6935 [2000] */ - {0xeb94, 0x00e6a582}, /* U+6942 [2000] */ - {0xeb95, 0x00e6a597}, /* U+6957 [2000] */ - {0xeb96, 0x00e6a5a3}, /* U+6963 [2000] */ - {0xeb97, 0x00e6a5a4}, /* U+6964 [2000] */ - {0xeb98, 0x00e6a5a8}, /* U+6968 [2000] */ - {0xeb99, 0x00e6a680}, /* U+6980 [2000] */ - {0xeb9a, 0x00efa894}, /* U+FA14 CJK COMPATIBILITY IDEOGRAPH-FA14 [2000] */ - {0xeb9b, 0x00e6a6a5}, /* U+69A5 [2000] */ - {0xeb9c, 0x00e6a6ad}, /* U+69AD [2000] */ - {0xeb9d, 0x00e6a78f}, /* U+69CF [2000] */ - {0xeb9e, 0x00e3aeb6}, /* U+3BB6 [2000] */ - {0xeb9f, 0x00e3af83}, /* U+3BC3 [2000] */ - {0xeba0, 0x00e6a7a2}, /* U+69E2 [2000] */ - {0xeba1, 0x00e6a7a9}, /* U+69E9 [2000] */ - {0xeba2, 0x00e6a7aa}, /* U+69EA [2000] */ - {0xeba3, 0x00e6a7b5}, /* U+69F5 [2000] */ - {0xeba4, 0x00e6a7b6}, /* U+69F6 [2000] */ - {0xeba5, 0x00e6a88f}, /* U+6A0F [2000] */ - {0xeba6, 0x00e6a895}, /* U+6A15 [2000] */ + {0xeb93, 0xe6a4b5}, /* U+6935 [2000] */ + {0xeb94, 0xe6a582}, /* U+6942 [2000] */ + {0xeb95, 0xe6a597}, /* U+6957 [2000] */ + {0xeb96, 0xe6a5a3}, /* U+6963 [2000] */ + {0xeb97, 0xe6a5a4}, /* U+6964 [2000] */ + {0xeb98, 0xe6a5a8}, /* U+6968 [2000] */ + {0xeb99, 0xe6a680}, /* U+6980 [2000] */ + {0xeb9a, 0xefa894}, /* U+FA14 CJK COMPATIBILITY IDEOGRAPH-FA14 [2000] */ + {0xeb9b, 0xe6a6a5}, /* U+69A5 [2000] */ + {0xeb9c, 0xe6a6ad}, /* U+69AD [2000] */ + {0xeb9d, 0xe6a78f}, /* U+69CF [2000] */ + {0xeb9e, 0xe3aeb6}, /* U+3BB6 [2000] */ + {0xeb9f, 0xe3af83}, /* U+3BC3 [2000] */ + {0xeba0, 0xe6a7a2}, /* U+69E2 [2000] */ + {0xeba1, 0xe6a7a9}, /* U+69E9 [2000] */ + {0xeba2, 0xe6a7aa}, /* U+69EA [2000] */ + {0xeba3, 0xe6a7b5}, /* U+69F5 [2000] */ + {0xeba4, 0xe6a7b6}, /* U+69F6 [2000] */ + {0xeba5, 0xe6a88f}, /* U+6A0F [2000] */ + {0xeba6, 0xe6a895}, /* U+6A15 [2000] */ {0xeba7, 0xf0a39cbf}, /* U+2373F [2000] [Unicode3.1] */ - {0xeba8, 0x00e6a8bb}, /* U+6A3B [2000] */ - {0xeba9, 0x00e6a8be}, /* U+6A3E [2000] */ - {0xebaa, 0x00e6a985}, /* U+6A45 [2000] */ - {0xebab, 0x00e6a990}, /* U+6A50 [2000] */ - {0xebac, 0x00e6a996}, /* U+6A56 [2000] */ - {0xebad, 0x00e6a99b}, /* U+6A5B [2000] */ - {0xebae, 0x00e6a9ab}, /* U+6A6B [2000] */ - {0xebaf, 0x00e6a9b3}, /* U+6A73 [2000] */ + {0xeba8, 0xe6a8bb}, /* U+6A3B [2000] */ + {0xeba9, 0xe6a8be}, /* U+6A3E [2000] */ + {0xebaa, 0xe6a985}, /* U+6A45 [2000] */ + {0xebab, 0xe6a990}, /* U+6A50 [2000] */ + {0xebac, 0xe6a996}, /* U+6A56 [2000] */ + {0xebad, 0xe6a99b}, /* U+6A5B [2000] */ + {0xebae, 0xe6a9ab}, /* U+6A6B [2000] */ + {0xebaf, 0xe6a9b3}, /* U+6A73 [2000] */ {0xebb0, 0xf0a39da3}, /* U+23763 [2000] [Unicode3.1] */ - {0xebb1, 0x00e6aa89}, /* U+6A89 [2000] */ - {0xebb2, 0x00e6aa94}, /* U+6A94 [2000] */ - {0xebb3, 0x00e6aa9d}, /* U+6A9D [2000] */ - {0xebb4, 0x00e6aa9e}, /* U+6A9E [2000] */ - {0xebb5, 0x00e6aaa5}, /* U+6AA5 [2000] */ - {0xebb6, 0x00e6aba4}, /* U+6AE4 [2000] */ - {0xebb7, 0x00e6aba7}, /* U+6AE7 [2000] */ - {0xebb8, 0x00e3b08f}, /* U+3C0F [2000] */ - {0xebb9, 0x00efa49d}, /* U+F91D CJK COMPATIBILITY IDEOGRAPH-F91D [2000] */ - {0xebba, 0x00e6ac9b}, /* U+6B1B [2000] */ - {0xebbb, 0x00e6ac9e}, /* U+6B1E [2000] */ - {0xebbc, 0x00e6acac}, /* U+6B2C [2000] */ - {0xebbd, 0x00e6acb5}, /* U+6B35 [2000] */ - {0xebbe, 0x00e6ad86}, /* U+6B46 [2000] */ - {0xebbf, 0x00e6ad96}, /* U+6B56 [2000] */ - {0xebc0, 0x00e6ada0}, /* U+6B60 [2000] */ - {0xebc1, 0x00e6ada5}, /* U+6B65 [2000] */ - {0xebc2, 0x00e6ada7}, /* U+6B67 [2000] */ - {0xebc3, 0x00e6adb7}, /* U+6B77 [2000] */ - {0xebc4, 0x00e6ae82}, /* U+6B82 [2000] */ - {0xebc5, 0x00e6aea9}, /* U+6BA9 [2000] */ - {0xebc6, 0x00e6aead}, /* U+6BAD [2000] */ - {0xebc7, 0x00efa5b0}, /* U+F970 CJK COMPATIBILITY IDEOGRAPH-F970 [2000] */ - {0xebc8, 0x00e6af8f}, /* U+6BCF [2000] */ - {0xebc9, 0x00e6af96}, /* U+6BD6 [2000] */ - {0xebca, 0x00e6af97}, /* U+6BD7 [2000] */ - {0xebcb, 0x00e6afbf}, /* U+6BFF [2000] */ - {0xebcc, 0x00e6b085}, /* U+6C05 [2000] */ - {0xebcd, 0x00e6b090}, /* U+6C10 [2000] */ - {0xebce, 0x00e6b0b3}, /* U+6C33 [2000] */ - {0xebcf, 0x00e6b199}, /* U+6C59 [2000] */ - {0xebd0, 0x00e6b19c}, /* U+6C5C [2000] */ - {0xebd1, 0x00e6b2aa}, /* U+6CAA [2000] */ - {0xebd2, 0x00e6b1b4}, /* U+6C74 [2000] */ - {0xebd3, 0x00e6b1b6}, /* U+6C76 [2000] */ - {0xebd4, 0x00e6b285}, /* U+6C85 [2000] */ - {0xebd5, 0x00e6b286}, /* U+6C86 [2000] */ - {0xebd6, 0x00e6b298}, /* U+6C98 [2000] */ - {0xebd7, 0x00e6b29c}, /* U+6C9C [2000] */ - {0xebd8, 0x00e6b3bb}, /* U+6CFB [2000] */ - {0xebd9, 0x00e6b386}, /* U+6CC6 [2000] */ - {0xebda, 0x00e6b394}, /* U+6CD4 [2000] */ - {0xebdb, 0x00e6b3a0}, /* U+6CE0 [2000] */ - {0xebdc, 0x00e6b3ab}, /* U+6CEB [2000] */ - {0xebdd, 0x00e6b3ae}, /* U+6CEE [2000] */ + {0xebb1, 0xe6aa89}, /* U+6A89 [2000] */ + {0xebb2, 0xe6aa94}, /* U+6A94 [2000] */ + {0xebb3, 0xe6aa9d}, /* U+6A9D [2000] */ + {0xebb4, 0xe6aa9e}, /* U+6A9E [2000] */ + {0xebb5, 0xe6aaa5}, /* U+6AA5 [2000] */ + {0xebb6, 0xe6aba4}, /* U+6AE4 [2000] */ + {0xebb7, 0xe6aba7}, /* U+6AE7 [2000] */ + {0xebb8, 0xe3b08f}, /* U+3C0F [2000] */ + {0xebb9, 0xefa49d}, /* U+F91D CJK COMPATIBILITY IDEOGRAPH-F91D [2000] */ + {0xebba, 0xe6ac9b}, /* U+6B1B [2000] */ + {0xebbb, 0xe6ac9e}, /* U+6B1E [2000] */ + {0xebbc, 0xe6acac}, /* U+6B2C [2000] */ + {0xebbd, 0xe6acb5}, /* U+6B35 [2000] */ + {0xebbe, 0xe6ad86}, /* U+6B46 [2000] */ + {0xebbf, 0xe6ad96}, /* U+6B56 [2000] */ + {0xebc0, 0xe6ada0}, /* U+6B60 [2000] */ + {0xebc1, 0xe6ada5}, /* U+6B65 [2000] */ + {0xebc2, 0xe6ada7}, /* U+6B67 [2000] */ + {0xebc3, 0xe6adb7}, /* U+6B77 [2000] */ + {0xebc4, 0xe6ae82}, /* U+6B82 [2000] */ + {0xebc5, 0xe6aea9}, /* U+6BA9 [2000] */ + {0xebc6, 0xe6aead}, /* U+6BAD [2000] */ + {0xebc7, 0xefa5b0}, /* U+F970 CJK COMPATIBILITY IDEOGRAPH-F970 [2000] */ + {0xebc8, 0xe6af8f}, /* U+6BCF [2000] */ + {0xebc9, 0xe6af96}, /* U+6BD6 [2000] */ + {0xebca, 0xe6af97}, /* U+6BD7 [2000] */ + {0xebcb, 0xe6afbf}, /* U+6BFF [2000] */ + {0xebcc, 0xe6b085}, /* U+6C05 [2000] */ + {0xebcd, 0xe6b090}, /* U+6C10 [2000] */ + {0xebce, 0xe6b0b3}, /* U+6C33 [2000] */ + {0xebcf, 0xe6b199}, /* U+6C59 [2000] */ + {0xebd0, 0xe6b19c}, /* U+6C5C [2000] */ + {0xebd1, 0xe6b2aa}, /* U+6CAA [2000] */ + {0xebd2, 0xe6b1b4}, /* U+6C74 [2000] */ + {0xebd3, 0xe6b1b6}, /* U+6C76 [2000] */ + {0xebd4, 0xe6b285}, /* U+6C85 [2000] */ + {0xebd5, 0xe6b286}, /* U+6C86 [2000] */ + {0xebd6, 0xe6b298}, /* U+6C98 [2000] */ + {0xebd7, 0xe6b29c}, /* U+6C9C [2000] */ + {0xebd8, 0xe6b3bb}, /* U+6CFB [2000] */ + {0xebd9, 0xe6b386}, /* U+6CC6 [2000] */ + {0xebda, 0xe6b394}, /* U+6CD4 [2000] */ + {0xebdb, 0xe6b3a0}, /* U+6CE0 [2000] */ + {0xebdc, 0xe6b3ab}, /* U+6CEB [2000] */ + {0xebdd, 0xe6b3ae}, /* U+6CEE [2000] */ {0xebde, 0xf0a3b3be}, /* U+23CFE [2000] [Unicode3.1] */ - {0xebdf, 0x00e6b484}, /* U+6D04 [2000] */ - {0xebe0, 0x00e6b48e}, /* U+6D0E [2000] */ - {0xebe1, 0x00e6b4ae}, /* U+6D2E [2000] */ - {0xebe2, 0x00e6b4b1}, /* U+6D31 [2000] */ - {0xebe3, 0x00e6b4b9}, /* U+6D39 [2000] */ - {0xebe4, 0x00e6b4bf}, /* U+6D3F [2000] */ - {0xebe5, 0x00e6b598}, /* U+6D58 [2000] */ - {0xebe6, 0x00e6b5a5}, /* U+6D65 [2000] */ - {0xebe7, 0x00efa985}, /* U+FA45 CJK COMPATIBILITY IDEOGRAPH-FA45 [2000] [Unicode3.2] */ - {0xebe8, 0x00e6b682}, /* U+6D82 [2000] */ - {0xebe9, 0x00e6b687}, /* U+6D87 [2000] */ - {0xebea, 0x00e6b689}, /* U+6D89 [2000] */ - {0xebeb, 0x00e6b694}, /* U+6D94 [2000] */ - {0xebec, 0x00e6b6aa}, /* U+6DAA [2000] */ - {0xebed, 0x00e6b6ac}, /* U+6DAC [2000] */ - {0xebee, 0x00e6b6bf}, /* U+6DBF [2000] */ - {0xebef, 0x00e6b784}, /* U+6DC4 [2000] */ - {0xebf0, 0x00e6b796}, /* U+6DD6 [2000] */ - {0xebf1, 0x00e6b79a}, /* U+6DDA [2000] */ - {0xebf2, 0x00e6b79b}, /* U+6DDB [2000] */ - {0xebf3, 0x00e6b79d}, /* U+6DDD [2000] */ - {0xebf4, 0x00e6b7bc}, /* U+6DFC [2000] */ - {0xebf5, 0x00efa986}, /* U+FA46 CJK COMPATIBILITY IDEOGRAPH-FA46 [2000] [Unicode3.2] */ - {0xebf6, 0x00e6b8b4}, /* U+6E34 [2000] */ - {0xebf7, 0x00e6b984}, /* U+6E44 [2000] */ - {0xebf8, 0x00e6b99c}, /* U+6E5C [2000] */ - {0xebf9, 0x00e6b99e}, /* U+6E5E [2000] */ - {0xebfa, 0x00e6baab}, /* U+6EAB [2000] */ - {0xebfb, 0x00e6bab1}, /* U+6EB1 [2000] */ - {0xebfc, 0x00e6bb81}, /* U+6EC1 [2000] */ - {0xec40, 0x00e6bb87}, /* U+6EC7 [2000] */ - {0xec41, 0x00e6bb8e}, /* U+6ECE [2000] */ - {0xec42, 0x00e6bc90}, /* U+6F10 [2000] */ - {0xec43, 0x00e6bc9a}, /* U+6F1A [2000] */ - {0xec44, 0x00efa987}, /* U+FA47 CJK COMPATIBILITY IDEOGRAPH-FA47 [2000] [Unicode3.2] */ - {0xec45, 0x00e6bcaa}, /* U+6F2A [2000] */ - {0xec46, 0x00e6bcaf}, /* U+6F2F [2000] */ - {0xec47, 0x00e6bcb3}, /* U+6F33 [2000] */ - {0xec48, 0x00e6bd91}, /* U+6F51 [2000] */ - {0xec49, 0x00e6bd99}, /* U+6F59 [2000] */ - {0xec4a, 0x00e6bd9e}, /* U+6F5E [2000] */ - {0xec4b, 0x00e6bda1}, /* U+6F61 [2000] */ - {0xec4c, 0x00e6bda2}, /* U+6F62 [2000] */ - {0xec4d, 0x00e6bdbe}, /* U+6F7E [2000] */ - {0xec4e, 0x00e6be88}, /* U+6F88 [2000] */ - {0xec4f, 0x00e6be8c}, /* U+6F8C [2000] */ - {0xec50, 0x00e6be8d}, /* U+6F8D [2000] */ - {0xec51, 0x00e6be94}, /* U+6F94 [2000] */ - {0xec52, 0x00e6bea0}, /* U+6FA0 [2000] */ - {0xec53, 0x00e6bea7}, /* U+6FA7 [2000] */ - {0xec54, 0x00e6beb6}, /* U+6FB6 [2000] */ - {0xec55, 0x00e6bebc}, /* U+6FBC [2000] */ - {0xec56, 0x00e6bf87}, /* U+6FC7 [2000] */ - {0xec57, 0x00e6bf8a}, /* U+6FCA [2000] */ - {0xec58, 0x00e6bfb9}, /* U+6FF9 [2000] */ - {0xec59, 0x00e6bfb0}, /* U+6FF0 [2000] */ - {0xec5a, 0x00e6bfb5}, /* U+6FF5 [2000] */ - {0xec5b, 0x00e78085}, /* U+7005 [2000] */ - {0xec5c, 0x00e78086}, /* U+7006 [2000] */ - {0xec5d, 0x00e780a8}, /* U+7028 [2000] */ - {0xec5e, 0x00e7818a}, /* U+704A [2000] */ - {0xec5f, 0x00e7819d}, /* U+705D [2000] */ - {0xec60, 0x00e7819e}, /* U+705E [2000] */ - {0xec61, 0x00e7818e}, /* U+704E [2000] */ - {0xec62, 0x00e781a4}, /* U+7064 [2000] */ - {0xec63, 0x00e781b5}, /* U+7075 [2000] */ - {0xec64, 0x00e78285}, /* U+7085 [2000] */ - {0xec65, 0x00e782a4}, /* U+70A4 [2000] */ - {0xec66, 0x00e782ab}, /* U+70AB [2000] */ - {0xec67, 0x00e782b7}, /* U+70B7 [2000] */ - {0xec68, 0x00e78394}, /* U+70D4 [2000] */ - {0xec69, 0x00e78398}, /* U+70D8 [2000] */ - {0xec6a, 0x00e783a4}, /* U+70E4 [2000] */ - {0xec6b, 0x00e7848f}, /* U+710F [2000] */ - {0xec6c, 0x00e784ab}, /* U+712B [2000] */ - {0xec6d, 0x00e7849e}, /* U+711E [2000] */ - {0xec6e, 0x00e784a0}, /* U+7120 [2000] */ - {0xec6f, 0x00e784ae}, /* U+712E [2000] */ - {0xec70, 0x00e784b0}, /* U+7130 [2000] */ - {0xec71, 0x00e78586}, /* U+7146 [2000] */ - {0xec72, 0x00e78587}, /* U+7147 [2000] */ - {0xec73, 0x00e78591}, /* U+7151 [2000] */ - {0xec74, 0x00efa988}, /* U+FA48 CJK COMPATIBILITY IDEOGRAPH-FA48 [2000] [Unicode3.2] */ - {0xec75, 0x00e78592}, /* U+7152 [2000] */ - {0xec76, 0x00e7859c}, /* U+715C [2000] */ - {0xec77, 0x00e785a0}, /* U+7160 [2000] */ - {0xec78, 0x00e785a8}, /* U+7168 [2000] */ - {0xec79, 0x00efa895}, /* U+FA15 CJK COMPATIBILITY IDEOGRAPH-FA15 [2000] */ - {0xec7a, 0x00e78685}, /* U+7185 [2000] */ - {0xec7b, 0x00e78687}, /* U+7187 [2000] */ - {0xec7c, 0x00e78692}, /* U+7192 [2000] */ - {0xec7d, 0x00e78781}, /* U+71C1 [2000] */ - {0xec7e, 0x00e786ba}, /* U+71BA [2000] */ - {0xec80, 0x00e78784}, /* U+71C4 [2000] */ - {0xec81, 0x00e787be}, /* U+71FE [2000] */ - {0xec82, 0x00e78880}, /* U+7200 [2000] */ - {0xec83, 0x00e78895}, /* U+7215 [2000] */ - {0xec84, 0x00e78995}, /* U+7255 [2000] */ - {0xec85, 0x00e78996}, /* U+7256 [2000] */ - {0xec86, 0x00e3b8bf}, /* U+3E3F [2000] */ - {0xec87, 0x00e78a8d}, /* U+728D [2000] */ - {0xec88, 0x00e78a9b}, /* U+729B [2000] */ - {0xec89, 0x00e78abe}, /* U+72BE [2000] */ - {0xec8a, 0x00e78b80}, /* U+72C0 [2000] */ - {0xec8b, 0x00e78bbb}, /* U+72FB [2000] */ + {0xebdf, 0xe6b484}, /* U+6D04 [2000] */ + {0xebe0, 0xe6b48e}, /* U+6D0E [2000] */ + {0xebe1, 0xe6b4ae}, /* U+6D2E [2000] */ + {0xebe2, 0xe6b4b1}, /* U+6D31 [2000] */ + {0xebe3, 0xe6b4b9}, /* U+6D39 [2000] */ + {0xebe4, 0xe6b4bf}, /* U+6D3F [2000] */ + {0xebe5, 0xe6b598}, /* U+6D58 [2000] */ + {0xebe6, 0xe6b5a5}, /* U+6D65 [2000] */ + {0xebe7, 0xefa985}, /* U+FA45 CJK COMPATIBILITY IDEOGRAPH-FA45 [2000] [Unicode3.2] */ + {0xebe8, 0xe6b682}, /* U+6D82 [2000] */ + {0xebe9, 0xe6b687}, /* U+6D87 [2000] */ + {0xebea, 0xe6b689}, /* U+6D89 [2000] */ + {0xebeb, 0xe6b694}, /* U+6D94 [2000] */ + {0xebec, 0xe6b6aa}, /* U+6DAA [2000] */ + {0xebed, 0xe6b6ac}, /* U+6DAC [2000] */ + {0xebee, 0xe6b6bf}, /* U+6DBF [2000] */ + {0xebef, 0xe6b784}, /* U+6DC4 [2000] */ + {0xebf0, 0xe6b796}, /* U+6DD6 [2000] */ + {0xebf1, 0xe6b79a}, /* U+6DDA [2000] */ + {0xebf2, 0xe6b79b}, /* U+6DDB [2000] */ + {0xebf3, 0xe6b79d}, /* U+6DDD [2000] */ + {0xebf4, 0xe6b7bc}, /* U+6DFC [2000] */ + {0xebf5, 0xefa986}, /* U+FA46 CJK COMPATIBILITY IDEOGRAPH-FA46 [2000] [Unicode3.2] */ + {0xebf6, 0xe6b8b4}, /* U+6E34 [2000] */ + {0xebf7, 0xe6b984}, /* U+6E44 [2000] */ + {0xebf8, 0xe6b99c}, /* U+6E5C [2000] */ + {0xebf9, 0xe6b99e}, /* U+6E5E [2000] */ + {0xebfa, 0xe6baab}, /* U+6EAB [2000] */ + {0xebfb, 0xe6bab1}, /* U+6EB1 [2000] */ + {0xebfc, 0xe6bb81}, /* U+6EC1 [2000] */ + {0xec40, 0xe6bb87}, /* U+6EC7 [2000] */ + {0xec41, 0xe6bb8e}, /* U+6ECE [2000] */ + {0xec42, 0xe6bc90}, /* U+6F10 [2000] */ + {0xec43, 0xe6bc9a}, /* U+6F1A [2000] */ + {0xec44, 0xefa987}, /* U+FA47 CJK COMPATIBILITY IDEOGRAPH-FA47 [2000] [Unicode3.2] */ + {0xec45, 0xe6bcaa}, /* U+6F2A [2000] */ + {0xec46, 0xe6bcaf}, /* U+6F2F [2000] */ + {0xec47, 0xe6bcb3}, /* U+6F33 [2000] */ + {0xec48, 0xe6bd91}, /* U+6F51 [2000] */ + {0xec49, 0xe6bd99}, /* U+6F59 [2000] */ + {0xec4a, 0xe6bd9e}, /* U+6F5E [2000] */ + {0xec4b, 0xe6bda1}, /* U+6F61 [2000] */ + {0xec4c, 0xe6bda2}, /* U+6F62 [2000] */ + {0xec4d, 0xe6bdbe}, /* U+6F7E [2000] */ + {0xec4e, 0xe6be88}, /* U+6F88 [2000] */ + {0xec4f, 0xe6be8c}, /* U+6F8C [2000] */ + {0xec50, 0xe6be8d}, /* U+6F8D [2000] */ + {0xec51, 0xe6be94}, /* U+6F94 [2000] */ + {0xec52, 0xe6bea0}, /* U+6FA0 [2000] */ + {0xec53, 0xe6bea7}, /* U+6FA7 [2000] */ + {0xec54, 0xe6beb6}, /* U+6FB6 [2000] */ + {0xec55, 0xe6bebc}, /* U+6FBC [2000] */ + {0xec56, 0xe6bf87}, /* U+6FC7 [2000] */ + {0xec57, 0xe6bf8a}, /* U+6FCA [2000] */ + {0xec58, 0xe6bfb9}, /* U+6FF9 [2000] */ + {0xec59, 0xe6bfb0}, /* U+6FF0 [2000] */ + {0xec5a, 0xe6bfb5}, /* U+6FF5 [2000] */ + {0xec5b, 0xe78085}, /* U+7005 [2000] */ + {0xec5c, 0xe78086}, /* U+7006 [2000] */ + {0xec5d, 0xe780a8}, /* U+7028 [2000] */ + {0xec5e, 0xe7818a}, /* U+704A [2000] */ + {0xec5f, 0xe7819d}, /* U+705D [2000] */ + {0xec60, 0xe7819e}, /* U+705E [2000] */ + {0xec61, 0xe7818e}, /* U+704E [2000] */ + {0xec62, 0xe781a4}, /* U+7064 [2000] */ + {0xec63, 0xe781b5}, /* U+7075 [2000] */ + {0xec64, 0xe78285}, /* U+7085 [2000] */ + {0xec65, 0xe782a4}, /* U+70A4 [2000] */ + {0xec66, 0xe782ab}, /* U+70AB [2000] */ + {0xec67, 0xe782b7}, /* U+70B7 [2000] */ + {0xec68, 0xe78394}, /* U+70D4 [2000] */ + {0xec69, 0xe78398}, /* U+70D8 [2000] */ + {0xec6a, 0xe783a4}, /* U+70E4 [2000] */ + {0xec6b, 0xe7848f}, /* U+710F [2000] */ + {0xec6c, 0xe784ab}, /* U+712B [2000] */ + {0xec6d, 0xe7849e}, /* U+711E [2000] */ + {0xec6e, 0xe784a0}, /* U+7120 [2000] */ + {0xec6f, 0xe784ae}, /* U+712E [2000] */ + {0xec70, 0xe784b0}, /* U+7130 [2000] */ + {0xec71, 0xe78586}, /* U+7146 [2000] */ + {0xec72, 0xe78587}, /* U+7147 [2000] */ + {0xec73, 0xe78591}, /* U+7151 [2000] */ + {0xec74, 0xefa988}, /* U+FA48 CJK COMPATIBILITY IDEOGRAPH-FA48 [2000] [Unicode3.2] */ + {0xec75, 0xe78592}, /* U+7152 [2000] */ + {0xec76, 0xe7859c}, /* U+715C [2000] */ + {0xec77, 0xe785a0}, /* U+7160 [2000] */ + {0xec78, 0xe785a8}, /* U+7168 [2000] */ + {0xec79, 0xefa895}, /* U+FA15 CJK COMPATIBILITY IDEOGRAPH-FA15 [2000] */ + {0xec7a, 0xe78685}, /* U+7185 [2000] */ + {0xec7b, 0xe78687}, /* U+7187 [2000] */ + {0xec7c, 0xe78692}, /* U+7192 [2000] */ + {0xec7d, 0xe78781}, /* U+71C1 [2000] */ + {0xec7e, 0xe786ba}, /* U+71BA [2000] */ + {0xec80, 0xe78784}, /* U+71C4 [2000] */ + {0xec81, 0xe787be}, /* U+71FE [2000] */ + {0xec82, 0xe78880}, /* U+7200 [2000] */ + {0xec83, 0xe78895}, /* U+7215 [2000] */ + {0xec84, 0xe78995}, /* U+7255 [2000] */ + {0xec85, 0xe78996}, /* U+7256 [2000] */ + {0xec86, 0xe3b8bf}, /* U+3E3F [2000] */ + {0xec87, 0xe78a8d}, /* U+728D [2000] */ + {0xec88, 0xe78a9b}, /* U+729B [2000] */ + {0xec89, 0xe78abe}, /* U+72BE [2000] */ + {0xec8a, 0xe78b80}, /* U+72C0 [2000] */ + {0xec8b, 0xe78bbb}, /* U+72FB [2000] */ {0xec8c, 0xf0a49fb1}, /* U+247F1 [2000] [Unicode3.1] */ - {0xec8d, 0x00e78ca7}, /* U+7327 [2000] */ - {0xec8e, 0x00e78ca8}, /* U+7328 [2000] */ - {0xec8f, 0x00efa896}, /* U+FA16 CJK COMPATIBILITY IDEOGRAPH-FA16 [2000] */ - {0xec90, 0x00e78d90}, /* U+7350 [2000] */ - {0xec91, 0x00e78da6}, /* U+7366 [2000] */ - {0xec92, 0x00e78dbc}, /* U+737C [2000] */ - {0xec93, 0x00e78e95}, /* U+7395 [2000] */ - {0xec94, 0x00e78e9f}, /* U+739F [2000] */ - {0xec95, 0x00e78ea0}, /* U+73A0 [2000] */ - {0xec96, 0x00e78ea2}, /* U+73A2 [2000] */ - {0xec97, 0x00e78ea6}, /* U+73A6 [2000] */ - {0xec98, 0x00e78eab}, /* U+73AB [2000] */ - {0xec99, 0x00e78f89}, /* U+73C9 [2000] */ - {0xec9a, 0x00e78f8f}, /* U+73CF [2000] */ - {0xec9b, 0x00e78f96}, /* U+73D6 [2000] */ - {0xec9c, 0x00e78f99}, /* U+73D9 [2000] */ - {0xec9d, 0x00e78fa3}, /* U+73E3 [2000] */ - {0xec9e, 0x00e78fa9}, /* U+73E9 [2000] */ - {0xec9f, 0x00e79087}, /* U+7407 [2000] */ - {0xeca0, 0x00e7908a}, /* U+740A [2000] */ - {0xeca1, 0x00e7909a}, /* U+741A [2000] */ - {0xeca2, 0x00e7909b}, /* U+741B [2000] */ - {0xeca3, 0x00efa98a}, /* U+FA4A CJK COMPATIBILITY IDEOGRAPH-FA4A [2000] [Unicode3.2] */ - {0xeca4, 0x00e790a6}, /* U+7426 [2000] */ - {0xeca5, 0x00e790a8}, /* U+7428 [2000] */ - {0xeca6, 0x00e790aa}, /* U+742A [2000] */ - {0xeca7, 0x00e790ab}, /* U+742B [2000] */ - {0xeca8, 0x00e790ac}, /* U+742C [2000] */ - {0xeca9, 0x00e790ae}, /* U+742E [2000] */ - {0xecaa, 0x00e790af}, /* U+742F [2000] */ - {0xecab, 0x00e790b0}, /* U+7430 [2000] */ - {0xecac, 0x00e79184}, /* U+7444 [2000] */ - {0xecad, 0x00e79186}, /* U+7446 [2000] */ - {0xecae, 0x00e79187}, /* U+7447 [2000] */ - {0xecaf, 0x00e7918b}, /* U+744B [2000] */ - {0xecb0, 0x00e79197}, /* U+7457 [2000] */ - {0xecb1, 0x00e791a2}, /* U+7462 [2000] */ - {0xecb2, 0x00e791ab}, /* U+746B [2000] */ - {0xecb3, 0x00e791ad}, /* U+746D [2000] */ - {0xecb4, 0x00e79286}, /* U+7486 [2000] */ - {0xecb5, 0x00e79287}, /* U+7487 [2000] */ - {0xecb6, 0x00e79289}, /* U+7489 [2000] */ - {0xecb7, 0x00e79298}, /* U+7498 [2000] */ - {0xecb8, 0x00e7929c}, /* U+749C [2000] */ - {0xecb9, 0x00e7929f}, /* U+749F [2000] */ - {0xecba, 0x00e792a3}, /* U+74A3 [2000] */ - {0xecbb, 0x00e79290}, /* U+7490 [2000] */ - {0xecbc, 0x00e792a6}, /* U+74A6 [2000] */ - {0xecbd, 0x00e792a8}, /* U+74A8 [2000] */ - {0xecbe, 0x00e792a9}, /* U+74A9 [2000] */ - {0xecbf, 0x00e792b5}, /* U+74B5 [2000] */ - {0xecc0, 0x00e792bf}, /* U+74BF [2000] */ - {0xecc1, 0x00e79388}, /* U+74C8 [2000] */ - {0xecc2, 0x00e79389}, /* U+74C9 [2000] */ - {0xecc3, 0x00e7939a}, /* U+74DA [2000] */ - {0xecc4, 0x00e793bf}, /* U+74FF [2000] */ - {0xecc5, 0x00e79481}, /* U+7501 [2000] */ - {0xecc6, 0x00e79497}, /* U+7517 [2000] */ - {0xecc7, 0x00e794af}, /* U+752F [2000] */ - {0xecc8, 0x00e795af}, /* U+756F [2000] */ - {0xecc9, 0x00e795b9}, /* U+7579 [2000] */ - {0xecca, 0x00e79692}, /* U+7592 [2000] */ - {0xeccb, 0x00e3bdb2}, /* U+3F72 [2000] */ - {0xeccc, 0x00e7978e}, /* U+75CE [2000] */ - {0xeccd, 0x00e797a4}, /* U+75E4 [2000] */ - {0xecce, 0x00e79880}, /* U+7600 [2000] */ - {0xeccf, 0x00e79882}, /* U+7602 [2000] */ - {0xecd0, 0x00e79888}, /* U+7608 [2000] */ - {0xecd1, 0x00e79895}, /* U+7615 [2000] */ - {0xecd2, 0x00e79896}, /* U+7616 [2000] */ - {0xecd3, 0x00e79899}, /* U+7619 [2000] */ - {0xecd4, 0x00e7989e}, /* U+761E [2000] */ - {0xecd5, 0x00e798ad}, /* U+762D [2000] */ - {0xecd6, 0x00e798b5}, /* U+7635 [2000] */ - {0xecd7, 0x00e79983}, /* U+7643 [2000] */ - {0xecd8, 0x00e7998b}, /* U+764B [2000] */ - {0xecd9, 0x00e799a4}, /* U+7664 [2000] */ - {0xecda, 0x00e799a5}, /* U+7665 [2000] */ - {0xecdb, 0x00e799ad}, /* U+766D [2000] */ - {0xecdc, 0x00e799af}, /* U+766F [2000] */ - {0xecdd, 0x00e799b1}, /* U+7671 [2000] */ - {0xecde, 0x00e79a81}, /* U+7681 [2000] */ - {0xecdf, 0x00e79a9b}, /* U+769B [2000] */ - {0xece0, 0x00e79a9d}, /* U+769D [2000] */ - {0xece1, 0x00e79a9e}, /* U+769E [2000] */ - {0xece2, 0x00e79aa6}, /* U+76A6 [2000] */ - {0xece3, 0x00e79aaa}, /* U+76AA [2000] */ - {0xece4, 0x00e79ab6}, /* U+76B6 [2000] */ - {0xece5, 0x00e79b85}, /* U+76C5 [2000] */ - {0xece6, 0x00e79b8c}, /* U+76CC [2000] */ - {0xece7, 0x00e79b8e}, /* U+76CE [2000] */ - {0xece8, 0x00e79b94}, /* U+76D4 [2000] */ - {0xece9, 0x00e79ba6}, /* U+76E6 [2000] */ - {0xecea, 0x00e79bb1}, /* U+76F1 [2000] */ - {0xeceb, 0x00e79bbc}, /* U+76FC [2000] */ - {0xecec, 0x00e79c8a}, /* U+770A [2000] */ - {0xeced, 0x00e79c99}, /* U+7719 [2000] */ - {0xecee, 0x00e79cb4}, /* U+7734 [2000] */ - {0xecef, 0x00e79cb6}, /* U+7736 [2000] */ - {0xecf0, 0x00e79d86}, /* U+7746 [2000] */ - {0xecf1, 0x00e79d8d}, /* U+774D [2000] */ - {0xecf2, 0x00e79d8e}, /* U+774E [2000] */ - {0xecf3, 0x00e79d9c}, /* U+775C [2000] */ - {0xecf4, 0x00e79d9f}, /* U+775F [2000] */ - {0xecf5, 0x00e79da2}, /* U+7762 [2000] */ - {0xecf6, 0x00e79dba}, /* U+777A [2000] */ - {0xecf7, 0x00e79e80}, /* U+7780 [2000] */ - {0xecf8, 0x00e79e94}, /* U+7794 [2000] */ - {0xecf9, 0x00e79eaa}, /* U+77AA [2000] */ - {0xecfa, 0x00e79fa0}, /* U+77E0 [2000] */ - {0xecfb, 0x00e7a0ad}, /* U+782D [2000] */ + {0xec8d, 0xe78ca7}, /* U+7327 [2000] */ + {0xec8e, 0xe78ca8}, /* U+7328 [2000] */ + {0xec8f, 0xefa896}, /* U+FA16 CJK COMPATIBILITY IDEOGRAPH-FA16 [2000] */ + {0xec90, 0xe78d90}, /* U+7350 [2000] */ + {0xec91, 0xe78da6}, /* U+7366 [2000] */ + {0xec92, 0xe78dbc}, /* U+737C [2000] */ + {0xec93, 0xe78e95}, /* U+7395 [2000] */ + {0xec94, 0xe78e9f}, /* U+739F [2000] */ + {0xec95, 0xe78ea0}, /* U+73A0 [2000] */ + {0xec96, 0xe78ea2}, /* U+73A2 [2000] */ + {0xec97, 0xe78ea6}, /* U+73A6 [2000] */ + {0xec98, 0xe78eab}, /* U+73AB [2000] */ + {0xec99, 0xe78f89}, /* U+73C9 [2000] */ + {0xec9a, 0xe78f8f}, /* U+73CF [2000] */ + {0xec9b, 0xe78f96}, /* U+73D6 [2000] */ + {0xec9c, 0xe78f99}, /* U+73D9 [2000] */ + {0xec9d, 0xe78fa3}, /* U+73E3 [2000] */ + {0xec9e, 0xe78fa9}, /* U+73E9 [2000] */ + {0xec9f, 0xe79087}, /* U+7407 [2000] */ + {0xeca0, 0xe7908a}, /* U+740A [2000] */ + {0xeca1, 0xe7909a}, /* U+741A [2000] */ + {0xeca2, 0xe7909b}, /* U+741B [2000] */ + {0xeca3, 0xefa98a}, /* U+FA4A CJK COMPATIBILITY IDEOGRAPH-FA4A [2000] [Unicode3.2] */ + {0xeca4, 0xe790a6}, /* U+7426 [2000] */ + {0xeca5, 0xe790a8}, /* U+7428 [2000] */ + {0xeca6, 0xe790aa}, /* U+742A [2000] */ + {0xeca7, 0xe790ab}, /* U+742B [2000] */ + {0xeca8, 0xe790ac}, /* U+742C [2000] */ + {0xeca9, 0xe790ae}, /* U+742E [2000] */ + {0xecaa, 0xe790af}, /* U+742F [2000] */ + {0xecab, 0xe790b0}, /* U+7430 [2000] */ + {0xecac, 0xe79184}, /* U+7444 [2000] */ + {0xecad, 0xe79186}, /* U+7446 [2000] */ + {0xecae, 0xe79187}, /* U+7447 [2000] */ + {0xecaf, 0xe7918b}, /* U+744B [2000] */ + {0xecb0, 0xe79197}, /* U+7457 [2000] */ + {0xecb1, 0xe791a2}, /* U+7462 [2000] */ + {0xecb2, 0xe791ab}, /* U+746B [2000] */ + {0xecb3, 0xe791ad}, /* U+746D [2000] */ + {0xecb4, 0xe79286}, /* U+7486 [2000] */ + {0xecb5, 0xe79287}, /* U+7487 [2000] */ + {0xecb6, 0xe79289}, /* U+7489 [2000] */ + {0xecb7, 0xe79298}, /* U+7498 [2000] */ + {0xecb8, 0xe7929c}, /* U+749C [2000] */ + {0xecb9, 0xe7929f}, /* U+749F [2000] */ + {0xecba, 0xe792a3}, /* U+74A3 [2000] */ + {0xecbb, 0xe79290}, /* U+7490 [2000] */ + {0xecbc, 0xe792a6}, /* U+74A6 [2000] */ + {0xecbd, 0xe792a8}, /* U+74A8 [2000] */ + {0xecbe, 0xe792a9}, /* U+74A9 [2000] */ + {0xecbf, 0xe792b5}, /* U+74B5 [2000] */ + {0xecc0, 0xe792bf}, /* U+74BF [2000] */ + {0xecc1, 0xe79388}, /* U+74C8 [2000] */ + {0xecc2, 0xe79389}, /* U+74C9 [2000] */ + {0xecc3, 0xe7939a}, /* U+74DA [2000] */ + {0xecc4, 0xe793bf}, /* U+74FF [2000] */ + {0xecc5, 0xe79481}, /* U+7501 [2000] */ + {0xecc6, 0xe79497}, /* U+7517 [2000] */ + {0xecc7, 0xe794af}, /* U+752F [2000] */ + {0xecc8, 0xe795af}, /* U+756F [2000] */ + {0xecc9, 0xe795b9}, /* U+7579 [2000] */ + {0xecca, 0xe79692}, /* U+7592 [2000] */ + {0xeccb, 0xe3bdb2}, /* U+3F72 [2000] */ + {0xeccc, 0xe7978e}, /* U+75CE [2000] */ + {0xeccd, 0xe797a4}, /* U+75E4 [2000] */ + {0xecce, 0xe79880}, /* U+7600 [2000] */ + {0xeccf, 0xe79882}, /* U+7602 [2000] */ + {0xecd0, 0xe79888}, /* U+7608 [2000] */ + {0xecd1, 0xe79895}, /* U+7615 [2000] */ + {0xecd2, 0xe79896}, /* U+7616 [2000] */ + {0xecd3, 0xe79899}, /* U+7619 [2000] */ + {0xecd4, 0xe7989e}, /* U+761E [2000] */ + {0xecd5, 0xe798ad}, /* U+762D [2000] */ + {0xecd6, 0xe798b5}, /* U+7635 [2000] */ + {0xecd7, 0xe79983}, /* U+7643 [2000] */ + {0xecd8, 0xe7998b}, /* U+764B [2000] */ + {0xecd9, 0xe799a4}, /* U+7664 [2000] */ + {0xecda, 0xe799a5}, /* U+7665 [2000] */ + {0xecdb, 0xe799ad}, /* U+766D [2000] */ + {0xecdc, 0xe799af}, /* U+766F [2000] */ + {0xecdd, 0xe799b1}, /* U+7671 [2000] */ + {0xecde, 0xe79a81}, /* U+7681 [2000] */ + {0xecdf, 0xe79a9b}, /* U+769B [2000] */ + {0xece0, 0xe79a9d}, /* U+769D [2000] */ + {0xece1, 0xe79a9e}, /* U+769E [2000] */ + {0xece2, 0xe79aa6}, /* U+76A6 [2000] */ + {0xece3, 0xe79aaa}, /* U+76AA [2000] */ + {0xece4, 0xe79ab6}, /* U+76B6 [2000] */ + {0xece5, 0xe79b85}, /* U+76C5 [2000] */ + {0xece6, 0xe79b8c}, /* U+76CC [2000] */ + {0xece7, 0xe79b8e}, /* U+76CE [2000] */ + {0xece8, 0xe79b94}, /* U+76D4 [2000] */ + {0xece9, 0xe79ba6}, /* U+76E6 [2000] */ + {0xecea, 0xe79bb1}, /* U+76F1 [2000] */ + {0xeceb, 0xe79bbc}, /* U+76FC [2000] */ + {0xecec, 0xe79c8a}, /* U+770A [2000] */ + {0xeced, 0xe79c99}, /* U+7719 [2000] */ + {0xecee, 0xe79cb4}, /* U+7734 [2000] */ + {0xecef, 0xe79cb6}, /* U+7736 [2000] */ + {0xecf0, 0xe79d86}, /* U+7746 [2000] */ + {0xecf1, 0xe79d8d}, /* U+774D [2000] */ + {0xecf2, 0xe79d8e}, /* U+774E [2000] */ + {0xecf3, 0xe79d9c}, /* U+775C [2000] */ + {0xecf4, 0xe79d9f}, /* U+775F [2000] */ + {0xecf5, 0xe79da2}, /* U+7762 [2000] */ + {0xecf6, 0xe79dba}, /* U+777A [2000] */ + {0xecf7, 0xe79e80}, /* U+7780 [2000] */ + {0xecf8, 0xe79e94}, /* U+7794 [2000] */ + {0xecf9, 0xe79eaa}, /* U+77AA [2000] */ + {0xecfa, 0xe79fa0}, /* U+77E0 [2000] */ + {0xecfb, 0xe7a0ad}, /* U+782D [2000] */ {0xecfc, 0xf0a5928e}, /* U+2548E [2000] [Unicode3.1] */ - {0xed40, 0x00e7a183}, /* U+7843 [2000] */ - {0xed41, 0x00e7a18e}, /* U+784E [2000] */ - {0xed42, 0x00e7a18f}, /* U+784F [2000] */ - {0xed43, 0x00e7a191}, /* U+7851 [2000] */ - {0xed44, 0x00e7a1a8}, /* U+7868 [2000] */ - {0xed45, 0x00e7a1ae}, /* U+786E [2000] */ - {0xed46, 0x00efa98b}, /* U+FA4B CJK COMPATIBILITY IDEOGRAPH-FA4B [2000] [Unicode3.2] */ - {0xed47, 0x00e7a2b0}, /* U+78B0 [2000] */ + {0xed40, 0xe7a183}, /* U+7843 [2000] */ + {0xed41, 0xe7a18e}, /* U+784E [2000] */ + {0xed42, 0xe7a18f}, /* U+784F [2000] */ + {0xed43, 0xe7a191}, /* U+7851 [2000] */ + {0xed44, 0xe7a1a8}, /* U+7868 [2000] */ + {0xed45, 0xe7a1ae}, /* U+786E [2000] */ + {0xed46, 0xefa98b}, /* U+FA4B CJK COMPATIBILITY IDEOGRAPH-FA4B [2000] [Unicode3.2] */ + {0xed47, 0xe7a2b0}, /* U+78B0 [2000] */ {0xed48, 0xf0a5948e}, /* U+2550E [2000] [Unicode3.1] */ - {0xed49, 0x00e7a2ad}, /* U+78AD [2000] */ - {0xed4a, 0x00e7a3a4}, /* U+78E4 [2000] */ - {0xed4b, 0x00e7a3b2}, /* U+78F2 [2000] */ - {0xed4c, 0x00e7a480}, /* U+7900 [2000] */ - {0xed4d, 0x00e7a3b7}, /* U+78F7 [2000] */ - {0xed4e, 0x00e7a49c}, /* U+791C [2000] */ - {0xed4f, 0x00e7a4ae}, /* U+792E [2000] */ - {0xed50, 0x00e7a4b1}, /* U+7931 [2000] */ - {0xed51, 0x00e7a4b4}, /* U+7934 [2000] */ - {0xed52, 0x00efa98c}, /* U+FA4C CJK COMPATIBILITY IDEOGRAPH-FA4C [2000] [Unicode3.2] */ - {0xed53, 0x00efa98d}, /* U+FA4D CJK COMPATIBILITY IDEOGRAPH-FA4D [2000] [Unicode3.2] */ - {0xed54, 0x00e7a585}, /* U+7945 [2000] */ - {0xed55, 0x00e7a586}, /* U+7946 [2000] */ - {0xed56, 0x00efa98e}, /* U+FA4E CJK COMPATIBILITY IDEOGRAPH-FA4E [2000] [Unicode3.2] */ - {0xed57, 0x00efa98f}, /* U+FA4F CJK COMPATIBILITY IDEOGRAPH-FA4F [2000] [Unicode3.2] */ - {0xed58, 0x00efa990}, /* U+FA50 CJK COMPATIBILITY IDEOGRAPH-FA50 [2000] [Unicode3.2] */ - {0xed59, 0x00e7a59c}, /* U+795C [2000] */ - {0xed5a, 0x00efa991}, /* U+FA51 CJK COMPATIBILITY IDEOGRAPH-FA51 [2000] [Unicode3.2] */ - {0xed5b, 0x00efa899}, /* U+FA19 CJK COMPATIBILITY IDEOGRAPH-FA19 [2000] */ - {0xed5c, 0x00efa89a}, /* U+FA1A CJK COMPATIBILITY IDEOGRAPH-FA1A [2000] */ - {0xed5d, 0x00e7a5b9}, /* U+7979 [2000] */ - {0xed5e, 0x00efa992}, /* U+FA52 CJK COMPATIBILITY IDEOGRAPH-FA52 [2000] [Unicode3.2] */ - {0xed5f, 0x00efa993}, /* U+FA53 CJK COMPATIBILITY IDEOGRAPH-FA53 [2000] [Unicode3.2] */ - {0xed60, 0x00efa89b}, /* U+FA1B CJK COMPATIBILITY IDEOGRAPH-FA1B [2000] */ - {0xed61, 0x00e7a698}, /* U+7998 [2000] */ - {0xed62, 0x00e7a6b1}, /* U+79B1 [2000] */ - {0xed63, 0x00e7a6b8}, /* U+79B8 [2000] */ - {0xed64, 0x00e7a788}, /* U+79C8 [2000] */ - {0xed65, 0x00e7a78a}, /* U+79CA [2000] */ + {0xed49, 0xe7a2ad}, /* U+78AD [2000] */ + {0xed4a, 0xe7a3a4}, /* U+78E4 [2000] */ + {0xed4b, 0xe7a3b2}, /* U+78F2 [2000] */ + {0xed4c, 0xe7a480}, /* U+7900 [2000] */ + {0xed4d, 0xe7a3b7}, /* U+78F7 [2000] */ + {0xed4e, 0xe7a49c}, /* U+791C [2000] */ + {0xed4f, 0xe7a4ae}, /* U+792E [2000] */ + {0xed50, 0xe7a4b1}, /* U+7931 [2000] */ + {0xed51, 0xe7a4b4}, /* U+7934 [2000] */ + {0xed52, 0xefa98c}, /* U+FA4C CJK COMPATIBILITY IDEOGRAPH-FA4C [2000] [Unicode3.2] */ + {0xed53, 0xefa98d}, /* U+FA4D CJK COMPATIBILITY IDEOGRAPH-FA4D [2000] [Unicode3.2] */ + {0xed54, 0xe7a585}, /* U+7945 [2000] */ + {0xed55, 0xe7a586}, /* U+7946 [2000] */ + {0xed56, 0xefa98e}, /* U+FA4E CJK COMPATIBILITY IDEOGRAPH-FA4E [2000] [Unicode3.2] */ + {0xed57, 0xefa98f}, /* U+FA4F CJK COMPATIBILITY IDEOGRAPH-FA4F [2000] [Unicode3.2] */ + {0xed58, 0xefa990}, /* U+FA50 CJK COMPATIBILITY IDEOGRAPH-FA50 [2000] [Unicode3.2] */ + {0xed59, 0xe7a59c}, /* U+795C [2000] */ + {0xed5a, 0xefa991}, /* U+FA51 CJK COMPATIBILITY IDEOGRAPH-FA51 [2000] [Unicode3.2] */ + {0xed5b, 0xefa899}, /* U+FA19 CJK COMPATIBILITY IDEOGRAPH-FA19 [2000] */ + {0xed5c, 0xefa89a}, /* U+FA1A CJK COMPATIBILITY IDEOGRAPH-FA1A [2000] */ + {0xed5d, 0xe7a5b9}, /* U+7979 [2000] */ + {0xed5e, 0xefa992}, /* U+FA52 CJK COMPATIBILITY IDEOGRAPH-FA52 [2000] [Unicode3.2] */ + {0xed5f, 0xefa993}, /* U+FA53 CJK COMPATIBILITY IDEOGRAPH-FA53 [2000] [Unicode3.2] */ + {0xed60, 0xefa89b}, /* U+FA1B CJK COMPATIBILITY IDEOGRAPH-FA1B [2000] */ + {0xed61, 0xe7a698}, /* U+7998 [2000] */ + {0xed62, 0xe7a6b1}, /* U+79B1 [2000] */ + {0xed63, 0xe7a6b8}, /* U+79B8 [2000] */ + {0xed64, 0xe7a788}, /* U+79C8 [2000] */ + {0xed65, 0xe7a78a}, /* U+79CA [2000] */ {0xed66, 0xf0a59db1}, /* U+25771 [2000] [Unicode3.1] */ - {0xed67, 0x00e7a794}, /* U+79D4 [2000] */ - {0xed68, 0x00e7a79e}, /* U+79DE [2000] */ - {0xed69, 0x00e7a7ab}, /* U+79EB [2000] */ - {0xed6a, 0x00e7a7ad}, /* U+79ED [2000] */ - {0xed6b, 0x00e7a883}, /* U+7A03 [2000] */ - {0xed6c, 0x00efa994}, /* U+FA54 CJK COMPATIBILITY IDEOGRAPH-FA54 [2000] [Unicode3.2] */ - {0xed6d, 0x00e7a8b9}, /* U+7A39 [2000] */ - {0xed6e, 0x00e7a99d}, /* U+7A5D [2000] */ - {0xed6f, 0x00e7a9ad}, /* U+7A6D [2000] */ - {0xed70, 0x00efa995}, /* U+FA55 CJK COMPATIBILITY IDEOGRAPH-FA55 [2000] [Unicode3.2] */ - {0xed71, 0x00e7aa85}, /* U+7A85 [2000] */ - {0xed72, 0x00e7aaa0}, /* U+7AA0 [2000] */ + {0xed67, 0xe7a794}, /* U+79D4 [2000] */ + {0xed68, 0xe7a79e}, /* U+79DE [2000] */ + {0xed69, 0xe7a7ab}, /* U+79EB [2000] */ + {0xed6a, 0xe7a7ad}, /* U+79ED [2000] */ + {0xed6b, 0xe7a883}, /* U+7A03 [2000] */ + {0xed6c, 0xefa994}, /* U+FA54 CJK COMPATIBILITY IDEOGRAPH-FA54 [2000] [Unicode3.2] */ + {0xed6d, 0xe7a8b9}, /* U+7A39 [2000] */ + {0xed6e, 0xe7a99d}, /* U+7A5D [2000] */ + {0xed6f, 0xe7a9ad}, /* U+7A6D [2000] */ + {0xed70, 0xefa995}, /* U+FA55 CJK COMPATIBILITY IDEOGRAPH-FA55 [2000] [Unicode3.2] */ + {0xed71, 0xe7aa85}, /* U+7A85 [2000] */ + {0xed72, 0xe7aaa0}, /* U+7AA0 [2000] */ {0xed73, 0xf0a5a784}, /* U+259C4 [2000] [Unicode3.1] */ - {0xed74, 0x00e7aab3}, /* U+7AB3 [2000] */ - {0xed75, 0x00e7aabb}, /* U+7ABB [2000] */ - {0xed76, 0x00e7ab8e}, /* U+7ACE [2000] */ - {0xed77, 0x00e7abab}, /* U+7AEB [2000] */ - {0xed78, 0x00e7abbd}, /* U+7AFD [2000] */ - {0xed79, 0x00e7ac92}, /* U+7B12 [2000] */ - {0xed7a, 0x00e7acad}, /* U+7B2D [2000] */ - {0xed7b, 0x00e7acbb}, /* U+7B3B [2000] */ - {0xed7c, 0x00e7ad87}, /* U+7B47 [2000] */ - {0xed7d, 0x00e7ad8e}, /* U+7B4E [2000] */ - {0xed7e, 0x00e7ada0}, /* U+7B60 [2000] */ - {0xed80, 0x00e7adad}, /* U+7B6D [2000] */ - {0xed81, 0x00e7adaf}, /* U+7B6F [2000] */ - {0xed82, 0x00e7adb2}, /* U+7B72 [2000] */ - {0xed83, 0x00e7ae9e}, /* U+7B9E [2000] */ - {0xed84, 0x00efa996}, /* U+FA56 CJK COMPATIBILITY IDEOGRAPH-FA56 [2000] [Unicode3.2] */ - {0xed85, 0x00e7af97}, /* U+7BD7 [2000] */ - {0xed86, 0x00e7af99}, /* U+7BD9 [2000] */ - {0xed87, 0x00e7b081}, /* U+7C01 [2000] */ - {0xed88, 0x00e7b0b1}, /* U+7C31 [2000] */ - {0xed89, 0x00e7b09e}, /* U+7C1E [2000] */ - {0xed8a, 0x00e7b0a0}, /* U+7C20 [2000] */ - {0xed8b, 0x00e7b0b3}, /* U+7C33 [2000] */ - {0xed8c, 0x00e7b0b6}, /* U+7C36 [2000] */ - {0xed8d, 0x00e489a4}, /* U+4264 [2000] */ + {0xed74, 0xe7aab3}, /* U+7AB3 [2000] */ + {0xed75, 0xe7aabb}, /* U+7ABB [2000] */ + {0xed76, 0xe7ab8e}, /* U+7ACE [2000] */ + {0xed77, 0xe7abab}, /* U+7AEB [2000] */ + {0xed78, 0xe7abbd}, /* U+7AFD [2000] */ + {0xed79, 0xe7ac92}, /* U+7B12 [2000] */ + {0xed7a, 0xe7acad}, /* U+7B2D [2000] */ + {0xed7b, 0xe7acbb}, /* U+7B3B [2000] */ + {0xed7c, 0xe7ad87}, /* U+7B47 [2000] */ + {0xed7d, 0xe7ad8e}, /* U+7B4E [2000] */ + {0xed7e, 0xe7ada0}, /* U+7B60 [2000] */ + {0xed80, 0xe7adad}, /* U+7B6D [2000] */ + {0xed81, 0xe7adaf}, /* U+7B6F [2000] */ + {0xed82, 0xe7adb2}, /* U+7B72 [2000] */ + {0xed83, 0xe7ae9e}, /* U+7B9E [2000] */ + {0xed84, 0xefa996}, /* U+FA56 CJK COMPATIBILITY IDEOGRAPH-FA56 [2000] [Unicode3.2] */ + {0xed85, 0xe7af97}, /* U+7BD7 [2000] */ + {0xed86, 0xe7af99}, /* U+7BD9 [2000] */ + {0xed87, 0xe7b081}, /* U+7C01 [2000] */ + {0xed88, 0xe7b0b1}, /* U+7C31 [2000] */ + {0xed89, 0xe7b09e}, /* U+7C1E [2000] */ + {0xed8a, 0xe7b0a0}, /* U+7C20 [2000] */ + {0xed8b, 0xe7b0b3}, /* U+7C33 [2000] */ + {0xed8c, 0xe7b0b6}, /* U+7C36 [2000] */ + {0xed8d, 0xe489a4}, /* U+4264 [2000] */ {0xed8e, 0xf0a5b6a1}, /* U+25DA1 [2000] [Unicode3.1] */ - {0xed8f, 0x00e7b199}, /* U+7C59 [2000] */ - {0xed90, 0x00e7b1ad}, /* U+7C6D [2000] */ - {0xed91, 0x00e7b1b9}, /* U+7C79 [2000] */ - {0xed92, 0x00e7b28f}, /* U+7C8F [2000] */ - {0xed93, 0x00e7b294}, /* U+7C94 [2000] */ - {0xed94, 0x00e7b2a0}, /* U+7CA0 [2000] */ - {0xed95, 0x00e7b2bc}, /* U+7CBC [2000] */ - {0xed96, 0x00e7b395}, /* U+7CD5 [2000] */ - {0xed97, 0x00e7b399}, /* U+7CD9 [2000] */ - {0xed98, 0x00e7b39d}, /* U+7CDD [2000] */ - {0xed99, 0x00e7b487}, /* U+7D07 [2000] */ - {0xed9a, 0x00e7b488}, /* U+7D08 [2000] */ - {0xed9b, 0x00e7b493}, /* U+7D13 [2000] */ - {0xed9c, 0x00e7b49d}, /* U+7D1D [2000] */ - {0xed9d, 0x00e7b4a3}, /* U+7D23 [2000] */ - {0xed9e, 0x00e7b4b1}, /* U+7D31 [2000] */ - {0xed9f, 0x00e7b581}, /* U+7D41 [2000] */ - {0xeda0, 0x00e7b588}, /* U+7D48 [2000] */ - {0xeda1, 0x00e7b593}, /* U+7D53 [2000] */ - {0xeda2, 0x00e7b59c}, /* U+7D5C [2000] */ - {0xeda3, 0x00e7b5ba}, /* U+7D7A [2000] */ - {0xeda4, 0x00e7b683}, /* U+7D83 [2000] */ - {0xeda5, 0x00e7b68b}, /* U+7D8B [2000] */ - {0xeda6, 0x00e7b6a0}, /* U+7DA0 [2000] */ - {0xeda7, 0x00e7b6a6}, /* U+7DA6 [2000] */ - {0xeda8, 0x00e7b782}, /* U+7DC2 [2000] */ - {0xeda9, 0x00e7b78c}, /* U+7DCC [2000] */ - {0xedaa, 0x00e7b796}, /* U+7DD6 [2000] */ - {0xedab, 0x00e7b7a3}, /* U+7DE3 [2000] */ - {0xedac, 0x00efa997}, /* U+FA57 CJK COMPATIBILITY IDEOGRAPH-FA57 [2000] [Unicode3.2] */ - {0xedad, 0x00e7b8a8}, /* U+7E28 [2000] */ - {0xedae, 0x00e7b888}, /* U+7E08 [2000] */ - {0xedaf, 0x00e7b891}, /* U+7E11 [2000] */ - {0xedb0, 0x00e7b895}, /* U+7E15 [2000] */ - {0xedb1, 0x00efa999}, /* U+FA59 CJK COMPATIBILITY IDEOGRAPH-FA59 [2000] [Unicode3.2] */ - {0xedb2, 0x00e7b987}, /* U+7E47 [2000] */ - {0xedb3, 0x00e7b992}, /* U+7E52 [2000] */ - {0xedb4, 0x00e7b9a1}, /* U+7E61 [2000] */ - {0xedb5, 0x00e7ba8a}, /* U+7E8A [2000] */ - {0xedb6, 0x00e7ba8d}, /* U+7E8D [2000] */ - {0xedb7, 0x00e7bd87}, /* U+7F47 [2000] */ - {0xedb8, 0x00efa99a}, /* U+FA5A CJK COMPATIBILITY IDEOGRAPH-FA5A [2000] [Unicode3.2] */ - {0xedb9, 0x00e7be91}, /* U+7F91 [2000] */ - {0xedba, 0x00e7be97}, /* U+7F97 [2000] */ - {0xedbb, 0x00e7bebf}, /* U+7FBF [2000] */ - {0xedbc, 0x00e7bf8e}, /* U+7FCE [2000] */ - {0xedbd, 0x00e7bf9b}, /* U+7FDB [2000] */ - {0xedbe, 0x00e7bf9f}, /* U+7FDF [2000] */ - {0xedbf, 0x00e7bfac}, /* U+7FEC [2000] */ - {0xedc0, 0x00e7bfae}, /* U+7FEE [2000] */ - {0xedc1, 0x00e7bfba}, /* U+7FFA [2000] */ - {0xedc2, 0x00efa99b}, /* U+FA5B CJK COMPATIBILITY IDEOGRAPH-FA5B [2000] [Unicode3.2] */ - {0xedc3, 0x00e88094}, /* U+8014 [2000] */ - {0xedc4, 0x00e880a6}, /* U+8026 [2000] */ - {0xedc5, 0x00e880b5}, /* U+8035 [2000] */ - {0xedc6, 0x00e880b7}, /* U+8037 [2000] */ - {0xedc7, 0x00e880bc}, /* U+803C [2000] */ - {0xedc8, 0x00e8838a}, /* U+80CA [2000] */ - {0xedc9, 0x00e88397}, /* U+80D7 [2000] */ - {0xedca, 0x00e883a0}, /* U+80E0 [2000] */ - {0xedcb, 0x00e883b3}, /* U+80F3 [2000] */ - {0xedcc, 0x00e88498}, /* U+8118 [2000] */ - {0xedcd, 0x00e8858a}, /* U+814A [2000] */ - {0xedce, 0x00e885a0}, /* U+8160 [2000] */ - {0xedcf, 0x00e885a7}, /* U+8167 [2000] */ - {0xedd0, 0x00e885a8}, /* U+8168 [2000] */ - {0xedd1, 0x00e885ad}, /* U+816D [2000] */ - {0xedd2, 0x00e886bb}, /* U+81BB [2000] */ - {0xedd3, 0x00e8878a}, /* U+81CA [2000] */ - {0xedd4, 0x00e8878f}, /* U+81CF [2000] */ - {0xedd5, 0x00e88797}, /* U+81D7 [2000] */ - {0xedd6, 0x00efa99c}, /* U+FA5C CJK COMPATIBILITY IDEOGRAPH-FA5C [2000] [Unicode3.2] */ - {0xedd7, 0x00e49193}, /* U+4453 [2000] */ - {0xedd8, 0x00e4919b}, /* U+445B [2000] */ - {0xedd9, 0x00e889a0}, /* U+8260 [2000] */ - {0xedda, 0x00e889b4}, /* U+8274 [2000] */ + {0xed8f, 0xe7b199}, /* U+7C59 [2000] */ + {0xed90, 0xe7b1ad}, /* U+7C6D [2000] */ + {0xed91, 0xe7b1b9}, /* U+7C79 [2000] */ + {0xed92, 0xe7b28f}, /* U+7C8F [2000] */ + {0xed93, 0xe7b294}, /* U+7C94 [2000] */ + {0xed94, 0xe7b2a0}, /* U+7CA0 [2000] */ + {0xed95, 0xe7b2bc}, /* U+7CBC [2000] */ + {0xed96, 0xe7b395}, /* U+7CD5 [2000] */ + {0xed97, 0xe7b399}, /* U+7CD9 [2000] */ + {0xed98, 0xe7b39d}, /* U+7CDD [2000] */ + {0xed99, 0xe7b487}, /* U+7D07 [2000] */ + {0xed9a, 0xe7b488}, /* U+7D08 [2000] */ + {0xed9b, 0xe7b493}, /* U+7D13 [2000] */ + {0xed9c, 0xe7b49d}, /* U+7D1D [2000] */ + {0xed9d, 0xe7b4a3}, /* U+7D23 [2000] */ + {0xed9e, 0xe7b4b1}, /* U+7D31 [2000] */ + {0xed9f, 0xe7b581}, /* U+7D41 [2000] */ + {0xeda0, 0xe7b588}, /* U+7D48 [2000] */ + {0xeda1, 0xe7b593}, /* U+7D53 [2000] */ + {0xeda2, 0xe7b59c}, /* U+7D5C [2000] */ + {0xeda3, 0xe7b5ba}, /* U+7D7A [2000] */ + {0xeda4, 0xe7b683}, /* U+7D83 [2000] */ + {0xeda5, 0xe7b68b}, /* U+7D8B [2000] */ + {0xeda6, 0xe7b6a0}, /* U+7DA0 [2000] */ + {0xeda7, 0xe7b6a6}, /* U+7DA6 [2000] */ + {0xeda8, 0xe7b782}, /* U+7DC2 [2000] */ + {0xeda9, 0xe7b78c}, /* U+7DCC [2000] */ + {0xedaa, 0xe7b796}, /* U+7DD6 [2000] */ + {0xedab, 0xe7b7a3}, /* U+7DE3 [2000] */ + {0xedac, 0xefa997}, /* U+FA57 CJK COMPATIBILITY IDEOGRAPH-FA57 [2000] [Unicode3.2] */ + {0xedad, 0xe7b8a8}, /* U+7E28 [2000] */ + {0xedae, 0xe7b888}, /* U+7E08 [2000] */ + {0xedaf, 0xe7b891}, /* U+7E11 [2000] */ + {0xedb0, 0xe7b895}, /* U+7E15 [2000] */ + {0xedb1, 0xefa999}, /* U+FA59 CJK COMPATIBILITY IDEOGRAPH-FA59 [2000] [Unicode3.2] */ + {0xedb2, 0xe7b987}, /* U+7E47 [2000] */ + {0xedb3, 0xe7b992}, /* U+7E52 [2000] */ + {0xedb4, 0xe7b9a1}, /* U+7E61 [2000] */ + {0xedb5, 0xe7ba8a}, /* U+7E8A [2000] */ + {0xedb6, 0xe7ba8d}, /* U+7E8D [2000] */ + {0xedb7, 0xe7bd87}, /* U+7F47 [2000] */ + {0xedb8, 0xefa99a}, /* U+FA5A CJK COMPATIBILITY IDEOGRAPH-FA5A [2000] [Unicode3.2] */ + {0xedb9, 0xe7be91}, /* U+7F91 [2000] */ + {0xedba, 0xe7be97}, /* U+7F97 [2000] */ + {0xedbb, 0xe7bebf}, /* U+7FBF [2000] */ + {0xedbc, 0xe7bf8e}, /* U+7FCE [2000] */ + {0xedbd, 0xe7bf9b}, /* U+7FDB [2000] */ + {0xedbe, 0xe7bf9f}, /* U+7FDF [2000] */ + {0xedbf, 0xe7bfac}, /* U+7FEC [2000] */ + {0xedc0, 0xe7bfae}, /* U+7FEE [2000] */ + {0xedc1, 0xe7bfba}, /* U+7FFA [2000] */ + {0xedc2, 0xefa99b}, /* U+FA5B CJK COMPATIBILITY IDEOGRAPH-FA5B [2000] [Unicode3.2] */ + {0xedc3, 0xe88094}, /* U+8014 [2000] */ + {0xedc4, 0xe880a6}, /* U+8026 [2000] */ + {0xedc5, 0xe880b5}, /* U+8035 [2000] */ + {0xedc6, 0xe880b7}, /* U+8037 [2000] */ + {0xedc7, 0xe880bc}, /* U+803C [2000] */ + {0xedc8, 0xe8838a}, /* U+80CA [2000] */ + {0xedc9, 0xe88397}, /* U+80D7 [2000] */ + {0xedca, 0xe883a0}, /* U+80E0 [2000] */ + {0xedcb, 0xe883b3}, /* U+80F3 [2000] */ + {0xedcc, 0xe88498}, /* U+8118 [2000] */ + {0xedcd, 0xe8858a}, /* U+814A [2000] */ + {0xedce, 0xe885a0}, /* U+8160 [2000] */ + {0xedcf, 0xe885a7}, /* U+8167 [2000] */ + {0xedd0, 0xe885a8}, /* U+8168 [2000] */ + {0xedd1, 0xe885ad}, /* U+816D [2000] */ + {0xedd2, 0xe886bb}, /* U+81BB [2000] */ + {0xedd3, 0xe8878a}, /* U+81CA [2000] */ + {0xedd4, 0xe8878f}, /* U+81CF [2000] */ + {0xedd5, 0xe88797}, /* U+81D7 [2000] */ + {0xedd6, 0xefa99c}, /* U+FA5C CJK COMPATIBILITY IDEOGRAPH-FA5C [2000] [Unicode3.2] */ + {0xedd7, 0xe49193}, /* U+4453 [2000] */ + {0xedd8, 0xe4919b}, /* U+445B [2000] */ + {0xedd9, 0xe889a0}, /* U+8260 [2000] */ + {0xedda, 0xe889b4}, /* U+8274 [2000] */ {0xeddb, 0xf0a6abbf}, /* U+26AFF [2000] [Unicode3.1] */ - {0xeddc, 0x00e88a8e}, /* U+828E [2000] */ - {0xeddd, 0x00e88aa1}, /* U+82A1 [2000] */ - {0xedde, 0x00e88aa3}, /* U+82A3 [2000] */ - {0xeddf, 0x00e88aa4}, /* U+82A4 [2000] */ - {0xede0, 0x00e88aa9}, /* U+82A9 [2000] */ - {0xede1, 0x00e88aae}, /* U+82AE [2000] */ - {0xede2, 0x00e88ab7}, /* U+82B7 [2000] */ - {0xede3, 0x00e88abe}, /* U+82BE [2000] */ - {0xede4, 0x00e88abf}, /* U+82BF [2000] */ - {0xede5, 0x00e88b86}, /* U+82C6 [2000] */ - {0xede6, 0x00e88b95}, /* U+82D5 [2000] */ - {0xede7, 0x00e88bbd}, /* U+82FD [2000] */ - {0xede8, 0x00e88bbe}, /* U+82FE [2000] */ - {0xede9, 0x00e88c80}, /* U+8300 [2000] */ - {0xedea, 0x00e88c81}, /* U+8301 [2000] */ - {0xedeb, 0x00e88da2}, /* U+8362 [2000] */ - {0xedec, 0x00e88ca2}, /* U+8322 [2000] */ - {0xeded, 0x00e88cad}, /* U+832D [2000] */ - {0xedee, 0x00e88cba}, /* U+833A [2000] */ - {0xedef, 0x00e88d83}, /* U+8343 [2000] */ - {0xedf0, 0x00e88d87}, /* U+8347 [2000] */ - {0xedf1, 0x00e88d91}, /* U+8351 [2000] */ - {0xedf2, 0x00e88d95}, /* U+8355 [2000] */ - {0xedf3, 0x00e88dbd}, /* U+837D [2000] */ - {0xedf4, 0x00e88e86}, /* U+8386 [2000] */ - {0xedf5, 0x00e88e92}, /* U+8392 [2000] */ - {0xedf6, 0x00e88e98}, /* U+8398 [2000] */ - {0xedf7, 0x00e88ea7}, /* U+83A7 [2000] */ - {0xedf8, 0x00e88ea9}, /* U+83A9 [2000] */ - {0xedf9, 0x00e88ebf}, /* U+83BF [2000] */ - {0xedfa, 0x00e88f80}, /* U+83C0 [2000] */ - {0xedfb, 0x00e88f87}, /* U+83C7 [2000] */ - {0xedfc, 0x00e88f8f}, /* U+83CF [2000] */ - {0xee40, 0x00e88f91}, /* U+83D1 [2000] */ - {0xee41, 0x00e88fa1}, /* U+83E1 [2000] */ - {0xee42, 0x00e88faa}, /* U+83EA [2000] */ - {0xee43, 0x00e89081}, /* U+8401 [2000] */ - {0xee44, 0x00e89086}, /* U+8406 [2000] */ - {0xee45, 0x00e8908a}, /* U+840A [2000] */ - {0xee46, 0x00efa99f}, /* U+FA5F CJK COMPATIBILITY IDEOGRAPH-FA5F [2000] [Unicode3.2] */ - {0xee47, 0x00e89188}, /* U+8448 [2000] */ - {0xee48, 0x00e8919f}, /* U+845F [2000] */ - {0xee49, 0x00e891b0}, /* U+8470 [2000] */ - {0xee4a, 0x00e891b3}, /* U+8473 [2000] */ - {0xee4b, 0x00e89285}, /* U+8485 [2000] */ - {0xee4c, 0x00e8929e}, /* U+849E [2000] */ - {0xee4d, 0x00e892af}, /* U+84AF [2000] */ - {0xee4e, 0x00e892b4}, /* U+84B4 [2000] */ - {0xee4f, 0x00e892ba}, /* U+84BA [2000] */ - {0xee50, 0x00e89380}, /* U+84C0 [2000] */ - {0xee51, 0x00e89382}, /* U+84C2 [2000] */ + {0xeddc, 0xe88a8e}, /* U+828E [2000] */ + {0xeddd, 0xe88aa1}, /* U+82A1 [2000] */ + {0xedde, 0xe88aa3}, /* U+82A3 [2000] */ + {0xeddf, 0xe88aa4}, /* U+82A4 [2000] */ + {0xede0, 0xe88aa9}, /* U+82A9 [2000] */ + {0xede1, 0xe88aae}, /* U+82AE [2000] */ + {0xede2, 0xe88ab7}, /* U+82B7 [2000] */ + {0xede3, 0xe88abe}, /* U+82BE [2000] */ + {0xede4, 0xe88abf}, /* U+82BF [2000] */ + {0xede5, 0xe88b86}, /* U+82C6 [2000] */ + {0xede6, 0xe88b95}, /* U+82D5 [2000] */ + {0xede7, 0xe88bbd}, /* U+82FD [2000] */ + {0xede8, 0xe88bbe}, /* U+82FE [2000] */ + {0xede9, 0xe88c80}, /* U+8300 [2000] */ + {0xedea, 0xe88c81}, /* U+8301 [2000] */ + {0xedeb, 0xe88da2}, /* U+8362 [2000] */ + {0xedec, 0xe88ca2}, /* U+8322 [2000] */ + {0xeded, 0xe88cad}, /* U+832D [2000] */ + {0xedee, 0xe88cba}, /* U+833A [2000] */ + {0xedef, 0xe88d83}, /* U+8343 [2000] */ + {0xedf0, 0xe88d87}, /* U+8347 [2000] */ + {0xedf1, 0xe88d91}, /* U+8351 [2000] */ + {0xedf2, 0xe88d95}, /* U+8355 [2000] */ + {0xedf3, 0xe88dbd}, /* U+837D [2000] */ + {0xedf4, 0xe88e86}, /* U+8386 [2000] */ + {0xedf5, 0xe88e92}, /* U+8392 [2000] */ + {0xedf6, 0xe88e98}, /* U+8398 [2000] */ + {0xedf7, 0xe88ea7}, /* U+83A7 [2000] */ + {0xedf8, 0xe88ea9}, /* U+83A9 [2000] */ + {0xedf9, 0xe88ebf}, /* U+83BF [2000] */ + {0xedfa, 0xe88f80}, /* U+83C0 [2000] */ + {0xedfb, 0xe88f87}, /* U+83C7 [2000] */ + {0xedfc, 0xe88f8f}, /* U+83CF [2000] */ + {0xee40, 0xe88f91}, /* U+83D1 [2000] */ + {0xee41, 0xe88fa1}, /* U+83E1 [2000] */ + {0xee42, 0xe88faa}, /* U+83EA [2000] */ + {0xee43, 0xe89081}, /* U+8401 [2000] */ + {0xee44, 0xe89086}, /* U+8406 [2000] */ + {0xee45, 0xe8908a}, /* U+840A [2000] */ + {0xee46, 0xefa99f}, /* U+FA5F CJK COMPATIBILITY IDEOGRAPH-FA5F [2000] [Unicode3.2] */ + {0xee47, 0xe89188}, /* U+8448 [2000] */ + {0xee48, 0xe8919f}, /* U+845F [2000] */ + {0xee49, 0xe891b0}, /* U+8470 [2000] */ + {0xee4a, 0xe891b3}, /* U+8473 [2000] */ + {0xee4b, 0xe89285}, /* U+8485 [2000] */ + {0xee4c, 0xe8929e}, /* U+849E [2000] */ + {0xee4d, 0xe892af}, /* U+84AF [2000] */ + {0xee4e, 0xe892b4}, /* U+84B4 [2000] */ + {0xee4f, 0xe892ba}, /* U+84BA [2000] */ + {0xee50, 0xe89380}, /* U+84C0 [2000] */ + {0xee51, 0xe89382}, /* U+84C2 [2000] */ {0xee52, 0xf0a6b980}, /* U+26E40 [2000] [Unicode3.1] */ - {0xee53, 0x00e894b2}, /* U+8532 [2000] */ - {0xee54, 0x00e8949e}, /* U+851E [2000] */ - {0xee55, 0x00e894a3}, /* U+8523 [2000] */ - {0xee56, 0x00e894af}, /* U+852F [2000] */ - {0xee57, 0x00e89599}, /* U+8559 [2000] */ - {0xee58, 0x00e895a4}, /* U+8564 [2000] */ - {0xee59, 0x00efa89f}, /* U+FA1F CJK COMPATIBILITY IDEOGRAPH-FA1F [2000] */ - {0xee5a, 0x00e896ad}, /* U+85AD [2000] */ - {0xee5b, 0x00e895ba}, /* U+857A [2000] */ - {0xee5c, 0x00e8968c}, /* U+858C [2000] */ - {0xee5d, 0x00e8968f}, /* U+858F [2000] */ - {0xee5e, 0x00e896a2}, /* U+85A2 [2000] */ - {0xee5f, 0x00e896b0}, /* U+85B0 [2000] */ - {0xee60, 0x00e8978b}, /* U+85CB [2000] */ - {0xee61, 0x00e8978e}, /* U+85CE [2000] */ - {0xee62, 0x00e897ad}, /* U+85ED [2000] */ - {0xee63, 0x00e89892}, /* U+8612 [2000] */ - {0xee64, 0x00e897bf}, /* U+85FF [2000] */ - {0xee65, 0x00e89884}, /* U+8604 [2000] */ - {0xee66, 0x00e89885}, /* U+8605 [2000] */ - {0xee67, 0x00e89890}, /* U+8610 [2000] */ + {0xee53, 0xe894b2}, /* U+8532 [2000] */ + {0xee54, 0xe8949e}, /* U+851E [2000] */ + {0xee55, 0xe894a3}, /* U+8523 [2000] */ + {0xee56, 0xe894af}, /* U+852F [2000] */ + {0xee57, 0xe89599}, /* U+8559 [2000] */ + {0xee58, 0xe895a4}, /* U+8564 [2000] */ + {0xee59, 0xefa89f}, /* U+FA1F CJK COMPATIBILITY IDEOGRAPH-FA1F [2000] */ + {0xee5a, 0xe896ad}, /* U+85AD [2000] */ + {0xee5b, 0xe895ba}, /* U+857A [2000] */ + {0xee5c, 0xe8968c}, /* U+858C [2000] */ + {0xee5d, 0xe8968f}, /* U+858F [2000] */ + {0xee5e, 0xe896a2}, /* U+85A2 [2000] */ + {0xee5f, 0xe896b0}, /* U+85B0 [2000] */ + {0xee60, 0xe8978b}, /* U+85CB [2000] */ + {0xee61, 0xe8978e}, /* U+85CE [2000] */ + {0xee62, 0xe897ad}, /* U+85ED [2000] */ + {0xee63, 0xe89892}, /* U+8612 [2000] */ + {0xee64, 0xe897bf}, /* U+85FF [2000] */ + {0xee65, 0xe89884}, /* U+8604 [2000] */ + {0xee66, 0xe89885}, /* U+8605 [2000] */ + {0xee67, 0xe89890}, /* U+8610 [2000] */ {0xee68, 0xf0a783b4}, /* U+270F4 [2000] [Unicode3.1] */ - {0xee69, 0x00e89898}, /* U+8618 [2000] */ - {0xee6a, 0x00e898a9}, /* U+8629 [2000] */ - {0xee6b, 0x00e898b8}, /* U+8638 [2000] */ - {0xee6c, 0x00e89997}, /* U+8657 [2000] */ - {0xee6d, 0x00e8999b}, /* U+865B [2000] */ - {0xee6e, 0x00efa4b6}, /* U+F936 CJK COMPATIBILITY IDEOGRAPH-F936 [2000] */ - {0xee6f, 0x00e899a2}, /* U+8662 [2000] */ - {0xee70, 0x00e4969d}, /* U+459D [2000] */ - {0xee71, 0x00e899ac}, /* U+866C [2000] */ - {0xee72, 0x00e899b5}, /* U+8675 [2000] */ - {0xee73, 0x00e89a98}, /* U+8698 [2000] */ - {0xee74, 0x00e89ab8}, /* U+86B8 [2000] */ - {0xee75, 0x00e89bba}, /* U+86FA [2000] */ - {0xee76, 0x00e89bbc}, /* U+86FC [2000] */ - {0xee77, 0x00e89bbd}, /* U+86FD [2000] */ - {0xee78, 0x00e89c8b}, /* U+870B [2000] */ - {0xee79, 0x00e89db1}, /* U+8771 [2000] */ - {0xee7a, 0x00e89e87}, /* U+8787 [2000] */ - {0xee7b, 0x00e89e88}, /* U+8788 [2000] */ - {0xee7c, 0x00e89eac}, /* U+87AC [2000] */ - {0xee7d, 0x00e89ead}, /* U+87AD [2000] */ - {0xee7e, 0x00e89eb5}, /* U+87B5 [2000] */ - {0xee80, 0x00e497aa}, /* U+45EA [2000] */ - {0xee81, 0x00e89f96}, /* U+87D6 [2000] */ - {0xee82, 0x00e89fac}, /* U+87EC [2000] */ - {0xee83, 0x00e8a086}, /* U+8806 [2000] */ - {0xee84, 0x00e8a08a}, /* U+880A [2000] */ - {0xee85, 0x00e8a090}, /* U+8810 [2000] */ - {0xee86, 0x00e8a094}, /* U+8814 [2000] */ - {0xee87, 0x00e8a09f}, /* U+881F [2000] */ - {0xee88, 0x00e8a298}, /* U+8898 [2000] */ - {0xee89, 0x00e8a2aa}, /* U+88AA [2000] */ - {0xee8a, 0x00e8a38a}, /* U+88CA [2000] */ - {0xee8b, 0x00e8a38e}, /* U+88CE [2000] */ + {0xee69, 0xe89898}, /* U+8618 [2000] */ + {0xee6a, 0xe898a9}, /* U+8629 [2000] */ + {0xee6b, 0xe898b8}, /* U+8638 [2000] */ + {0xee6c, 0xe89997}, /* U+8657 [2000] */ + {0xee6d, 0xe8999b}, /* U+865B [2000] */ + {0xee6e, 0xefa4b6}, /* U+F936 CJK COMPATIBILITY IDEOGRAPH-F936 [2000] */ + {0xee6f, 0xe899a2}, /* U+8662 [2000] */ + {0xee70, 0xe4969d}, /* U+459D [2000] */ + {0xee71, 0xe899ac}, /* U+866C [2000] */ + {0xee72, 0xe899b5}, /* U+8675 [2000] */ + {0xee73, 0xe89a98}, /* U+8698 [2000] */ + {0xee74, 0xe89ab8}, /* U+86B8 [2000] */ + {0xee75, 0xe89bba}, /* U+86FA [2000] */ + {0xee76, 0xe89bbc}, /* U+86FC [2000] */ + {0xee77, 0xe89bbd}, /* U+86FD [2000] */ + {0xee78, 0xe89c8b}, /* U+870B [2000] */ + {0xee79, 0xe89db1}, /* U+8771 [2000] */ + {0xee7a, 0xe89e87}, /* U+8787 [2000] */ + {0xee7b, 0xe89e88}, /* U+8788 [2000] */ + {0xee7c, 0xe89eac}, /* U+87AC [2000] */ + {0xee7d, 0xe89ead}, /* U+87AD [2000] */ + {0xee7e, 0xe89eb5}, /* U+87B5 [2000] */ + {0xee80, 0xe497aa}, /* U+45EA [2000] */ + {0xee81, 0xe89f96}, /* U+87D6 [2000] */ + {0xee82, 0xe89fac}, /* U+87EC [2000] */ + {0xee83, 0xe8a086}, /* U+8806 [2000] */ + {0xee84, 0xe8a08a}, /* U+880A [2000] */ + {0xee85, 0xe8a090}, /* U+8810 [2000] */ + {0xee86, 0xe8a094}, /* U+8814 [2000] */ + {0xee87, 0xe8a09f}, /* U+881F [2000] */ + {0xee88, 0xe8a298}, /* U+8898 [2000] */ + {0xee89, 0xe8a2aa}, /* U+88AA [2000] */ + {0xee8a, 0xe8a38a}, /* U+88CA [2000] */ + {0xee8b, 0xe8a38e}, /* U+88CE [2000] */ {0xee8c, 0xf0a79a84}, /* U+27684 [2000] [Unicode3.1] */ - {0xee8d, 0x00e8a3b5}, /* U+88F5 [2000] */ - {0xee8e, 0x00e8a49c}, /* U+891C [2000] */ - {0xee8f, 0x00efa9a0}, /* U+FA60 CJK COMPATIBILITY IDEOGRAPH-FA60 [2000] [Unicode3.2] */ - {0xee90, 0x00e8a498}, /* U+8918 [2000] */ - {0xee91, 0x00e8a499}, /* U+8919 [2000] */ - {0xee92, 0x00e8a49a}, /* U+891A [2000] */ - {0xee93, 0x00e8a4a7}, /* U+8927 [2000] */ - {0xee94, 0x00e8a4b0}, /* U+8930 [2000] */ - {0xee95, 0x00e8a4b2}, /* U+8932 [2000] */ - {0xee96, 0x00e8a4b9}, /* U+8939 [2000] */ - {0xee97, 0x00e8a580}, /* U+8940 [2000] */ - {0xee98, 0x00e8a694}, /* U+8994 [2000] */ - {0xee99, 0x00efa9a1}, /* U+FA61 CJK COMPATIBILITY IDEOGRAPH-FA61 [2000] [Unicode3.2] */ - {0xee9a, 0x00e8a794}, /* U+89D4 [2000] */ - {0xee9b, 0x00e8a7a5}, /* U+89E5 [2000] */ - {0xee9c, 0x00e8a7b6}, /* U+89F6 [2000] */ - {0xee9d, 0x00e8a892}, /* U+8A12 [2000] */ - {0xee9e, 0x00e8a895}, /* U+8A15 [2000] */ - {0xee9f, 0x00e8a8a2}, /* U+8A22 [2000] */ - {0xeea0, 0x00e8a8b7}, /* U+8A37 [2000] */ - {0xeea1, 0x00e8a987}, /* U+8A47 [2000] */ - {0xeea2, 0x00e8a98e}, /* U+8A4E [2000] */ - {0xeea3, 0x00e8a99d}, /* U+8A5D [2000] */ - {0xeea4, 0x00e8a9a1}, /* U+8A61 [2000] */ - {0xeea5, 0x00e8a9b5}, /* U+8A75 [2000] */ - {0xeea6, 0x00e8a9b9}, /* U+8A79 [2000] */ - {0xeea7, 0x00e8aaa7}, /* U+8AA7 [2000] */ - {0xeea8, 0x00e8ab90}, /* U+8AD0 [2000] */ - {0xeea9, 0x00e8ab9f}, /* U+8ADF [2000] */ - {0xeeaa, 0x00e8abb4}, /* U+8AF4 [2000] */ - {0xeeab, 0x00e8abb6}, /* U+8AF6 [2000] */ - {0xeeac, 0x00efa8a2}, /* U+FA22 CJK COMPATIBILITY IDEOGRAPH-FA22 [2000] */ - {0xeead, 0x00efa9a2}, /* U+FA62 CJK COMPATIBILITY IDEOGRAPH-FA62 [2000] [Unicode3.2] */ - {0xeeae, 0x00efa9a3}, /* U+FA63 CJK COMPATIBILITY IDEOGRAPH-FA63 [2000] [Unicode3.2] */ - {0xeeaf, 0x00e8ad86}, /* U+8B46 [2000] */ - {0xeeb0, 0x00e8ad94}, /* U+8B54 [2000] */ - {0xeeb1, 0x00e8ad99}, /* U+8B59 [2000] */ - {0xeeb2, 0x00e8ada9}, /* U+8B69 [2000] */ - {0xeeb3, 0x00e8ae9d}, /* U+8B9D [2000] */ - {0xeeb4, 0x00e8b189}, /* U+8C49 [2000] */ - {0xeeb5, 0x00e8b1a8}, /* U+8C68 [2000] */ - {0xeeb6, 0x00efa9a4}, /* U+FA64 CJK COMPATIBILITY IDEOGRAPH-FA64 [2000] [Unicode3.2] */ - {0xeeb7, 0x00e8b3a1}, /* U+8CE1 [2000] */ - {0xeeb8, 0x00e8b3b4}, /* U+8CF4 [2000] */ - {0xeeb9, 0x00e8b3b8}, /* U+8CF8 [2000] */ - {0xeeba, 0x00e8b3be}, /* U+8CFE [2000] */ - {0xeebb, 0x00efa9a5}, /* U+FA65 CJK COMPATIBILITY IDEOGRAPH-FA65 [2000] [Unicode3.2] */ - {0xeebc, 0x00e8b492}, /* U+8D12 [2000] */ - {0xeebd, 0x00e8b49b}, /* U+8D1B [2000] */ - {0xeebe, 0x00e8b6af}, /* U+8DAF [2000] */ - {0xeebf, 0x00e8b78e}, /* U+8DCE [2000] */ - {0xeec0, 0x00e8b791}, /* U+8DD1 [2000] */ - {0xeec1, 0x00e8b797}, /* U+8DD7 [2000] */ - {0xeec2, 0x00e8b8a0}, /* U+8E20 [2000] */ - {0xeec3, 0x00e8b8a3}, /* U+8E23 [2000] */ - {0xeec4, 0x00e8b8bd}, /* U+8E3D [2000] */ - {0xeec5, 0x00e8b9b0}, /* U+8E70 [2000] */ - {0xeec6, 0x00e8b9bb}, /* U+8E7B [2000] */ + {0xee8d, 0xe8a3b5}, /* U+88F5 [2000] */ + {0xee8e, 0xe8a49c}, /* U+891C [2000] */ + {0xee8f, 0xefa9a0}, /* U+FA60 CJK COMPATIBILITY IDEOGRAPH-FA60 [2000] [Unicode3.2] */ + {0xee90, 0xe8a498}, /* U+8918 [2000] */ + {0xee91, 0xe8a499}, /* U+8919 [2000] */ + {0xee92, 0xe8a49a}, /* U+891A [2000] */ + {0xee93, 0xe8a4a7}, /* U+8927 [2000] */ + {0xee94, 0xe8a4b0}, /* U+8930 [2000] */ + {0xee95, 0xe8a4b2}, /* U+8932 [2000] */ + {0xee96, 0xe8a4b9}, /* U+8939 [2000] */ + {0xee97, 0xe8a580}, /* U+8940 [2000] */ + {0xee98, 0xe8a694}, /* U+8994 [2000] */ + {0xee99, 0xefa9a1}, /* U+FA61 CJK COMPATIBILITY IDEOGRAPH-FA61 [2000] [Unicode3.2] */ + {0xee9a, 0xe8a794}, /* U+89D4 [2000] */ + {0xee9b, 0xe8a7a5}, /* U+89E5 [2000] */ + {0xee9c, 0xe8a7b6}, /* U+89F6 [2000] */ + {0xee9d, 0xe8a892}, /* U+8A12 [2000] */ + {0xee9e, 0xe8a895}, /* U+8A15 [2000] */ + {0xee9f, 0xe8a8a2}, /* U+8A22 [2000] */ + {0xeea0, 0xe8a8b7}, /* U+8A37 [2000] */ + {0xeea1, 0xe8a987}, /* U+8A47 [2000] */ + {0xeea2, 0xe8a98e}, /* U+8A4E [2000] */ + {0xeea3, 0xe8a99d}, /* U+8A5D [2000] */ + {0xeea4, 0xe8a9a1}, /* U+8A61 [2000] */ + {0xeea5, 0xe8a9b5}, /* U+8A75 [2000] */ + {0xeea6, 0xe8a9b9}, /* U+8A79 [2000] */ + {0xeea7, 0xe8aaa7}, /* U+8AA7 [2000] */ + {0xeea8, 0xe8ab90}, /* U+8AD0 [2000] */ + {0xeea9, 0xe8ab9f}, /* U+8ADF [2000] */ + {0xeeaa, 0xe8abb4}, /* U+8AF4 [2000] */ + {0xeeab, 0xe8abb6}, /* U+8AF6 [2000] */ + {0xeeac, 0xefa8a2}, /* U+FA22 CJK COMPATIBILITY IDEOGRAPH-FA22 [2000] */ + {0xeead, 0xefa9a2}, /* U+FA62 CJK COMPATIBILITY IDEOGRAPH-FA62 [2000] [Unicode3.2] */ + {0xeeae, 0xefa9a3}, /* U+FA63 CJK COMPATIBILITY IDEOGRAPH-FA63 [2000] [Unicode3.2] */ + {0xeeaf, 0xe8ad86}, /* U+8B46 [2000] */ + {0xeeb0, 0xe8ad94}, /* U+8B54 [2000] */ + {0xeeb1, 0xe8ad99}, /* U+8B59 [2000] */ + {0xeeb2, 0xe8ada9}, /* U+8B69 [2000] */ + {0xeeb3, 0xe8ae9d}, /* U+8B9D [2000] */ + {0xeeb4, 0xe8b189}, /* U+8C49 [2000] */ + {0xeeb5, 0xe8b1a8}, /* U+8C68 [2000] */ + {0xeeb6, 0xefa9a4}, /* U+FA64 CJK COMPATIBILITY IDEOGRAPH-FA64 [2000] [Unicode3.2] */ + {0xeeb7, 0xe8b3a1}, /* U+8CE1 [2000] */ + {0xeeb8, 0xe8b3b4}, /* U+8CF4 [2000] */ + {0xeeb9, 0xe8b3b8}, /* U+8CF8 [2000] */ + {0xeeba, 0xe8b3be}, /* U+8CFE [2000] */ + {0xeebb, 0xefa9a5}, /* U+FA65 CJK COMPATIBILITY IDEOGRAPH-FA65 [2000] [Unicode3.2] */ + {0xeebc, 0xe8b492}, /* U+8D12 [2000] */ + {0xeebd, 0xe8b49b}, /* U+8D1B [2000] */ + {0xeebe, 0xe8b6af}, /* U+8DAF [2000] */ + {0xeebf, 0xe8b78e}, /* U+8DCE [2000] */ + {0xeec0, 0xe8b791}, /* U+8DD1 [2000] */ + {0xeec1, 0xe8b797}, /* U+8DD7 [2000] */ + {0xeec2, 0xe8b8a0}, /* U+8E20 [2000] */ + {0xeec3, 0xe8b8a3}, /* U+8E23 [2000] */ + {0xeec4, 0xe8b8bd}, /* U+8E3D [2000] */ + {0xeec5, 0xe8b9b0}, /* U+8E70 [2000] */ + {0xeec6, 0xe8b9bb}, /* U+8E7B [2000] */ {0xeec7, 0xf0a889b7}, /* U+28277 [2000] [Unicode3.1] */ - {0xeec8, 0x00e8bb80}, /* U+8EC0 [2000] */ - {0xeec9, 0x00e4a184}, /* U+4844 [2000] */ - {0xeeca, 0x00e8bbba}, /* U+8EFA [2000] */ - {0xeecb, 0x00e8bc9e}, /* U+8F1E [2000] */ - {0xeecc, 0x00e8bcad}, /* U+8F2D [2000] */ - {0xeecd, 0x00e8bcb6}, /* U+8F36 [2000] */ - {0xeece, 0x00e8bd94}, /* U+8F54 [2000] */ + {0xeec8, 0xe8bb80}, /* U+8EC0 [2000] */ + {0xeec9, 0xe4a184}, /* U+4844 [2000] */ + {0xeeca, 0xe8bbba}, /* U+8EFA [2000] */ + {0xeecb, 0xe8bc9e}, /* U+8F1E [2000] */ + {0xeecc, 0xe8bcad}, /* U+8F2D [2000] */ + {0xeecd, 0xe8bcb6}, /* U+8F36 [2000] */ + {0xeece, 0xe8bd94}, /* U+8F54 [2000] */ {0xeecf, 0xf0a88f8d}, /* U+283CD [2000] [Unicode3.1] */ - {0xeed0, 0x00e8bea6}, /* U+8FA6 [2000] */ - {0xeed1, 0x00e8beb5}, /* U+8FB5 [2000] */ - {0xeed2, 0x00e8bfa4}, /* U+8FE4 [2000] */ - {0xeed3, 0x00e8bfa8}, /* U+8FE8 [2000] */ - {0xeed4, 0x00e8bfae}, /* U+8FEE [2000] */ - {0xeed5, 0x00e98088}, /* U+9008 [2000] */ - {0xeed6, 0x00e980ad}, /* U+902D [2000] */ - {0xeed7, 0x00efa9a7}, /* U+FA67 CJK COMPATIBILITY IDEOGRAPH-FA67 [2000] [Unicode3.2] */ - {0xeed8, 0x00e98288}, /* U+9088 [2000] */ - {0xeed9, 0x00e98295}, /* U+9095 [2000] */ - {0xeeda, 0x00e98297}, /* U+9097 [2000] */ - {0xeedb, 0x00e98299}, /* U+9099 [2000] */ - {0xeedc, 0x00e9829b}, /* U+909B [2000] */ - {0xeedd, 0x00e982a2}, /* U+90A2 [2000] */ - {0xeede, 0x00e982b3}, /* U+90B3 [2000] */ - {0xeedf, 0x00e982be}, /* U+90BE [2000] */ - {0xeee0, 0x00e98384}, /* U+90C4 [2000] */ - {0xeee1, 0x00e98385}, /* U+90C5 [2000] */ - {0xeee2, 0x00e98387}, /* U+90C7 [2000] */ - {0xeee3, 0x00e98397}, /* U+90D7 [2000] */ - {0xeee4, 0x00e9839d}, /* U+90DD [2000] */ - {0xeee5, 0x00e9839e}, /* U+90DE [2000] */ - {0xeee6, 0x00e983af}, /* U+90EF [2000] */ - {0xeee7, 0x00e983b4}, /* U+90F4 [2000] */ - {0xeee8, 0x00efa8a6}, /* U+FA26 CJK COMPATIBILITY IDEOGRAPH-FA26 [2000] */ - {0xeee9, 0x00e98494}, /* U+9114 [2000] */ - {0xeeea, 0x00e98495}, /* U+9115 [2000] */ - {0xeeeb, 0x00e98496}, /* U+9116 [2000] */ - {0xeeec, 0x00e984a2}, /* U+9122 [2000] */ - {0xeeed, 0x00e984a3}, /* U+9123 [2000] */ - {0xeeee, 0x00e984a7}, /* U+9127 [2000] */ - {0xeeef, 0x00e984af}, /* U+912F [2000] */ - {0xeef0, 0x00e984b1}, /* U+9131 [2000] */ - {0xeef1, 0x00e984b4}, /* U+9134 [2000] */ - {0xeef2, 0x00e984bd}, /* U+913D [2000] */ - {0xeef3, 0x00e98588}, /* U+9148 [2000] */ - {0xeef4, 0x00e9859b}, /* U+915B [2000] */ - {0xeef5, 0x00e98683}, /* U+9183 [2000] */ - {0xeef6, 0x00e9869e}, /* U+919E [2000] */ - {0xeef7, 0x00e986ac}, /* U+91AC [2000] */ - {0xeef8, 0x00e986b1}, /* U+91B1 [2000] */ - {0xeef9, 0x00e986bc}, /* U+91BC [2000] */ - {0xeefa, 0x00e98797}, /* U+91D7 [2000] */ - {0xeefb, 0x00e987bb}, /* U+91FB [2000] */ - {0xeefc, 0x00e987a4}, /* U+91E4 [2000] */ - {0xef40, 0x00e987a5}, /* U+91E5 [2000] */ - {0xef41, 0x00e987ad}, /* U+91ED [2000] */ - {0xef42, 0x00e987b1}, /* U+91F1 [2000] */ - {0xef43, 0x00e98887}, /* U+9207 [2000] */ - {0xef44, 0x00e98890}, /* U+9210 [2000] */ - {0xef45, 0x00e988b8}, /* U+9238 [2000] */ - {0xef46, 0x00e988b9}, /* U+9239 [2000] */ - {0xef47, 0x00e988ba}, /* U+923A [2000] */ - {0xef48, 0x00e988bc}, /* U+923C [2000] */ - {0xef49, 0x00e98980}, /* U+9240 [2000] */ - {0xef4a, 0x00e98983}, /* U+9243 [2000] */ - {0xef4b, 0x00e9898f}, /* U+924F [2000] */ - {0xef4c, 0x00e989b8}, /* U+9278 [2000] */ - {0xef4d, 0x00e98a88}, /* U+9288 [2000] */ - {0xef4e, 0x00e98b82}, /* U+92C2 [2000] */ - {0xef4f, 0x00e98b8b}, /* U+92CB [2000] */ - {0xef50, 0x00e98b8c}, /* U+92CC [2000] */ - {0xef51, 0x00e98b93}, /* U+92D3 [2000] */ - {0xef52, 0x00e98ba0}, /* U+92E0 [2000] */ - {0xef53, 0x00e98bbf}, /* U+92FF [2000] */ - {0xef54, 0x00e98c84}, /* U+9304 [2000] */ - {0xef55, 0x00e98c9f}, /* U+931F [2000] */ - {0xef56, 0x00e98ca1}, /* U+9321 [2000] */ - {0xef57, 0x00e98ca5}, /* U+9325 [2000] */ - {0xef58, 0x00e98d88}, /* U+9348 [2000] */ - {0xef59, 0x00e98d89}, /* U+9349 [2000] */ - {0xef5a, 0x00e98d8a}, /* U+934A [2000] */ - {0xef5b, 0x00e98da4}, /* U+9364 [2000] */ - {0xef5c, 0x00e98da5}, /* U+9365 [2000] */ - {0xef5d, 0x00e98daa}, /* U+936A [2000] */ - {0xef5e, 0x00e98db0}, /* U+9370 [2000] */ - {0xef5f, 0x00e98e9b}, /* U+939B [2000] */ - {0xef60, 0x00e98ea3}, /* U+93A3 [2000] */ - {0xef61, 0x00e98eba}, /* U+93BA [2000] */ - {0xef62, 0x00e98f86}, /* U+93C6 [2000] */ - {0xef63, 0x00e98f9e}, /* U+93DE [2000] */ - {0xef64, 0x00e98f9f}, /* U+93DF [2000] */ - {0xef65, 0x00e99084}, /* U+9404 [2000] */ - {0xef66, 0x00e98fbd}, /* U+93FD [2000] */ - {0xef67, 0x00e990b3}, /* U+9433 [2000] */ - {0xef68, 0x00e9918a}, /* U+944A [2000] */ - {0xef69, 0x00e991a3}, /* U+9463 [2000] */ - {0xef6a, 0x00e991ab}, /* U+946B [2000] */ - {0xef6b, 0x00e991b1}, /* U+9471 [2000] */ - {0xef6c, 0x00e991b2}, /* U+9472 [2000] */ - {0xef6d, 0x00e9968e}, /* U+958E [2000] */ - {0xef6e, 0x00e9969f}, /* U+959F [2000] */ - {0xef6f, 0x00e996a6}, /* U+95A6 [2000] */ - {0xef70, 0x00e996a9}, /* U+95A9 [2000] */ - {0xef71, 0x00e996ac}, /* U+95AC [2000] */ - {0xef72, 0x00e996b6}, /* U+95B6 [2000] */ - {0xef73, 0x00e996bd}, /* U+95BD [2000] */ - {0xef74, 0x00e9978b}, /* U+95CB [2000] */ - {0xef75, 0x00e99790}, /* U+95D0 [2000] */ - {0xef76, 0x00e99793}, /* U+95D3 [2000] */ - {0xef77, 0x00e4a6b0}, /* U+49B0 [2000] */ - {0xef78, 0x00e9979a}, /* U+95DA [2000] */ - {0xef79, 0x00e9979e}, /* U+95DE [2000] */ - {0xef7a, 0x00e99998}, /* U+9658 [2000] */ - {0xef7b, 0x00e99a84}, /* U+9684 [2000] */ - {0xef7c, 0x00efa79c}, /* U+F9DC CJK COMPATIBILITY IDEOGRAPH-F9DC [2000] */ - {0xef7d, 0x00e99a9d}, /* U+969D [2000] */ - {0xef7e, 0x00e99aa4}, /* U+96A4 [2000] */ - {0xef80, 0x00e99aa5}, /* U+96A5 [2000] */ - {0xef81, 0x00e99b92}, /* U+96D2 [2000] */ - {0xef82, 0x00e99b9e}, /* U+96DE [2000] */ - {0xef83, 0x00efa9a8}, /* U+FA68 CJK COMPATIBILITY IDEOGRAPH-FA68 [2000] [Unicode3.2] */ - {0xef84, 0x00e99ba9}, /* U+96E9 [2000] */ - {0xef85, 0x00e99baf}, /* U+96EF [2000] */ - {0xef86, 0x00e99cb3}, /* U+9733 [2000] */ - {0xef87, 0x00e99cbb}, /* U+973B [2000] */ - {0xef88, 0x00e99d8d}, /* U+974D [2000] */ - {0xef89, 0x00e99d8e}, /* U+974E [2000] */ - {0xef8a, 0x00e99d8f}, /* U+974F [2000] */ - {0xef8b, 0x00e99d9a}, /* U+975A [2000] */ - {0xef8c, 0x00e99dae}, /* U+976E [2000] */ - {0xef8d, 0x00e99db3}, /* U+9773 [2000] */ - {0xef8e, 0x00e99e95}, /* U+9795 [2000] */ - {0xef8f, 0x00e99eae}, /* U+97AE [2000] */ - {0xef90, 0x00e99eba}, /* U+97BA [2000] */ - {0xef91, 0x00e99f81}, /* U+97C1 [2000] */ - {0xef92, 0x00e99f89}, /* U+97C9 [2000] */ - {0xef93, 0x00e99f9e}, /* U+97DE [2000] */ - {0xef94, 0x00e99f9b}, /* U+97DB [2000] */ - {0xef95, 0x00e99fb4}, /* U+97F4 [2000] */ - {0xef96, 0x00efa9a9}, /* U+FA69 CJK COMPATIBILITY IDEOGRAPH-FA69 [2000] [Unicode3.2] */ - {0xef97, 0x00e9a08a}, /* U+980A [2000] */ - {0xef98, 0x00e9a09e}, /* U+981E [2000] */ - {0xef99, 0x00e9a0ab}, /* U+982B [2000] */ - {0xef9a, 0x00e9a0b0}, /* U+9830 [2000] */ - {0xef9b, 0x00efa9aa}, /* U+FA6A CJK COMPATIBILITY IDEOGRAPH-FA6A [2000] [Unicode3.2] */ - {0xef9c, 0x00e9a192}, /* U+9852 [2000] */ - {0xef9d, 0x00e9a193}, /* U+9853 [2000] */ - {0xef9e, 0x00e9a196}, /* U+9856 [2000] */ - {0xef9f, 0x00e9a197}, /* U+9857 [2000] */ - {0xefa0, 0x00e9a199}, /* U+9859 [2000] */ - {0xefa1, 0x00e9a19a}, /* U+985A [2000] */ - {0xefa2, 0x00efa790}, /* U+F9D0 CJK COMPATIBILITY IDEOGRAPH-F9D0 [2000] */ - {0xefa3, 0x00e9a1a5}, /* U+9865 [2000] */ - {0xefa4, 0x00e9a1ac}, /* U+986C [2000] */ - {0xefa5, 0x00e9a2ba}, /* U+98BA [2000] */ - {0xefa6, 0x00e9a388}, /* U+98C8 [2000] */ - {0xefa7, 0x00e9a3a7}, /* U+98E7 [2000] */ - {0xefa8, 0x00e9a598}, /* U+9958 [2000] */ - {0xefa9, 0x00e9a69e}, /* U+999E [2000] */ - {0xefaa, 0x00e9a882}, /* U+9A02 [2000] */ - {0xefab, 0x00e9a883}, /* U+9A03 [2000] */ - {0xefac, 0x00e9a8a4}, /* U+9A24 [2000] */ - {0xefad, 0x00e9a8ad}, /* U+9A2D [2000] */ - {0xefae, 0x00e9a8ae}, /* U+9A2E [2000] */ - {0xefaf, 0x00e9a8b8}, /* U+9A38 [2000] */ - {0xefb0, 0x00e9a98a}, /* U+9A4A [2000] */ - {0xefb1, 0x00e9a98e}, /* U+9A4E [2000] */ - {0xefb2, 0x00e9a992}, /* U+9A52 [2000] */ - {0xefb3, 0x00e9aab6}, /* U+9AB6 [2000] */ - {0xefb4, 0x00e9ab81}, /* U+9AC1 [2000] */ - {0xefb5, 0x00e9ab83}, /* U+9AC3 [2000] */ - {0xefb6, 0x00e9ab8e}, /* U+9ACE [2000] */ - {0xefb7, 0x00e9ab96}, /* U+9AD6 [2000] */ - {0xefb8, 0x00e9abb9}, /* U+9AF9 [2000] */ - {0xefb9, 0x00e9ac82}, /* U+9B02 [2000] */ - {0xefba, 0x00e9ac88}, /* U+9B08 [2000] */ - {0xefbb, 0x00e9aca0}, /* U+9B20 [2000] */ - {0xefbc, 0x00e4b097}, /* U+4C17 [2000] */ - {0xefbd, 0x00e9acad}, /* U+9B2D [2000] */ - {0xefbe, 0x00e9ad9e}, /* U+9B5E [2000] */ - {0xefbf, 0x00e9adb9}, /* U+9B79 [2000] */ - {0xefc0, 0x00e9ada6}, /* U+9B66 [2000] */ - {0xefc1, 0x00e9adb2}, /* U+9B72 [2000] */ - {0xefc2, 0x00e9adb5}, /* U+9B75 [2000] */ - {0xefc3, 0x00e9ae84}, /* U+9B84 [2000] */ - {0xefc4, 0x00e9ae8a}, /* U+9B8A [2000] */ - {0xefc5, 0x00e9ae8f}, /* U+9B8F [2000] */ - {0xefc6, 0x00e9ae9e}, /* U+9B9E [2000] */ - {0xefc7, 0x00e9aea7}, /* U+9BA7 [2000] */ - {0xefc8, 0x00e9af81}, /* U+9BC1 [2000] */ - {0xefc9, 0x00e9af8e}, /* U+9BCE [2000] */ - {0xefca, 0x00e9afa5}, /* U+9BE5 [2000] */ - {0xefcb, 0x00e9afb8}, /* U+9BF8 [2000] */ - {0xefcc, 0x00e9afbd}, /* U+9BFD [2000] */ - {0xefcd, 0x00e9b080}, /* U+9C00 [2000] */ - {0xefce, 0x00e9b0a3}, /* U+9C23 [2000] */ - {0xefcf, 0x00e9b181}, /* U+9C41 [2000] */ - {0xefd0, 0x00e9b18f}, /* U+9C4F [2000] */ - {0xefd1, 0x00e9b190}, /* U+9C50 [2000] */ - {0xefd2, 0x00e9b193}, /* U+9C53 [2000] */ - {0xefd3, 0x00e9b1a3}, /* U+9C63 [2000] */ - {0xefd4, 0x00e9b1a5}, /* U+9C65 [2000] */ - {0xefd5, 0x00e9b1b7}, /* U+9C77 [2000] */ - {0xefd6, 0x00e9b49d}, /* U+9D1D [2000] */ - {0xefd7, 0x00e9b49e}, /* U+9D1E [2000] */ - {0xefd8, 0x00e9b583}, /* U+9D43 [2000] */ - {0xefd9, 0x00e9b587}, /* U+9D47 [2000] */ - {0xefda, 0x00e9b592}, /* U+9D52 [2000] */ - {0xefdb, 0x00e9b5a3}, /* U+9D63 [2000] */ - {0xefdc, 0x00e9b5b0}, /* U+9D70 [2000] */ - {0xefdd, 0x00e9b5bc}, /* U+9D7C [2000] */ - {0xefde, 0x00e9b68a}, /* U+9D8A [2000] */ - {0xefdf, 0x00e9b696}, /* U+9D96 [2000] */ - {0xefe0, 0x00e9b780}, /* U+9DC0 [2000] */ - {0xefe1, 0x00e9b6ac}, /* U+9DAC [2000] */ - {0xefe2, 0x00e9b6bc}, /* U+9DBC [2000] */ - {0xefe3, 0x00e9b797}, /* U+9DD7 [2000] */ + {0xeed0, 0xe8bea6}, /* U+8FA6 [2000] */ + {0xeed1, 0xe8beb5}, /* U+8FB5 [2000] */ + {0xeed2, 0xe8bfa4}, /* U+8FE4 [2000] */ + {0xeed3, 0xe8bfa8}, /* U+8FE8 [2000] */ + {0xeed4, 0xe8bfae}, /* U+8FEE [2000] */ + {0xeed5, 0xe98088}, /* U+9008 [2000] */ + {0xeed6, 0xe980ad}, /* U+902D [2000] */ + {0xeed7, 0xefa9a7}, /* U+FA67 CJK COMPATIBILITY IDEOGRAPH-FA67 [2000] [Unicode3.2] */ + {0xeed8, 0xe98288}, /* U+9088 [2000] */ + {0xeed9, 0xe98295}, /* U+9095 [2000] */ + {0xeeda, 0xe98297}, /* U+9097 [2000] */ + {0xeedb, 0xe98299}, /* U+9099 [2000] */ + {0xeedc, 0xe9829b}, /* U+909B [2000] */ + {0xeedd, 0xe982a2}, /* U+90A2 [2000] */ + {0xeede, 0xe982b3}, /* U+90B3 [2000] */ + {0xeedf, 0xe982be}, /* U+90BE [2000] */ + {0xeee0, 0xe98384}, /* U+90C4 [2000] */ + {0xeee1, 0xe98385}, /* U+90C5 [2000] */ + {0xeee2, 0xe98387}, /* U+90C7 [2000] */ + {0xeee3, 0xe98397}, /* U+90D7 [2000] */ + {0xeee4, 0xe9839d}, /* U+90DD [2000] */ + {0xeee5, 0xe9839e}, /* U+90DE [2000] */ + {0xeee6, 0xe983af}, /* U+90EF [2000] */ + {0xeee7, 0xe983b4}, /* U+90F4 [2000] */ + {0xeee8, 0xefa8a6}, /* U+FA26 CJK COMPATIBILITY IDEOGRAPH-FA26 [2000] */ + {0xeee9, 0xe98494}, /* U+9114 [2000] */ + {0xeeea, 0xe98495}, /* U+9115 [2000] */ + {0xeeeb, 0xe98496}, /* U+9116 [2000] */ + {0xeeec, 0xe984a2}, /* U+9122 [2000] */ + {0xeeed, 0xe984a3}, /* U+9123 [2000] */ + {0xeeee, 0xe984a7}, /* U+9127 [2000] */ + {0xeeef, 0xe984af}, /* U+912F [2000] */ + {0xeef0, 0xe984b1}, /* U+9131 [2000] */ + {0xeef1, 0xe984b4}, /* U+9134 [2000] */ + {0xeef2, 0xe984bd}, /* U+913D [2000] */ + {0xeef3, 0xe98588}, /* U+9148 [2000] */ + {0xeef4, 0xe9859b}, /* U+915B [2000] */ + {0xeef5, 0xe98683}, /* U+9183 [2000] */ + {0xeef6, 0xe9869e}, /* U+919E [2000] */ + {0xeef7, 0xe986ac}, /* U+91AC [2000] */ + {0xeef8, 0xe986b1}, /* U+91B1 [2000] */ + {0xeef9, 0xe986bc}, /* U+91BC [2000] */ + {0xeefa, 0xe98797}, /* U+91D7 [2000] */ + {0xeefb, 0xe987bb}, /* U+91FB [2000] */ + {0xeefc, 0xe987a4}, /* U+91E4 [2000] */ + {0xef40, 0xe987a5}, /* U+91E5 [2000] */ + {0xef41, 0xe987ad}, /* U+91ED [2000] */ + {0xef42, 0xe987b1}, /* U+91F1 [2000] */ + {0xef43, 0xe98887}, /* U+9207 [2000] */ + {0xef44, 0xe98890}, /* U+9210 [2000] */ + {0xef45, 0xe988b8}, /* U+9238 [2000] */ + {0xef46, 0xe988b9}, /* U+9239 [2000] */ + {0xef47, 0xe988ba}, /* U+923A [2000] */ + {0xef48, 0xe988bc}, /* U+923C [2000] */ + {0xef49, 0xe98980}, /* U+9240 [2000] */ + {0xef4a, 0xe98983}, /* U+9243 [2000] */ + {0xef4b, 0xe9898f}, /* U+924F [2000] */ + {0xef4c, 0xe989b8}, /* U+9278 [2000] */ + {0xef4d, 0xe98a88}, /* U+9288 [2000] */ + {0xef4e, 0xe98b82}, /* U+92C2 [2000] */ + {0xef4f, 0xe98b8b}, /* U+92CB [2000] */ + {0xef50, 0xe98b8c}, /* U+92CC [2000] */ + {0xef51, 0xe98b93}, /* U+92D3 [2000] */ + {0xef52, 0xe98ba0}, /* U+92E0 [2000] */ + {0xef53, 0xe98bbf}, /* U+92FF [2000] */ + {0xef54, 0xe98c84}, /* U+9304 [2000] */ + {0xef55, 0xe98c9f}, /* U+931F [2000] */ + {0xef56, 0xe98ca1}, /* U+9321 [2000] */ + {0xef57, 0xe98ca5}, /* U+9325 [2000] */ + {0xef58, 0xe98d88}, /* U+9348 [2000] */ + {0xef59, 0xe98d89}, /* U+9349 [2000] */ + {0xef5a, 0xe98d8a}, /* U+934A [2000] */ + {0xef5b, 0xe98da4}, /* U+9364 [2000] */ + {0xef5c, 0xe98da5}, /* U+9365 [2000] */ + {0xef5d, 0xe98daa}, /* U+936A [2000] */ + {0xef5e, 0xe98db0}, /* U+9370 [2000] */ + {0xef5f, 0xe98e9b}, /* U+939B [2000] */ + {0xef60, 0xe98ea3}, /* U+93A3 [2000] */ + {0xef61, 0xe98eba}, /* U+93BA [2000] */ + {0xef62, 0xe98f86}, /* U+93C6 [2000] */ + {0xef63, 0xe98f9e}, /* U+93DE [2000] */ + {0xef64, 0xe98f9f}, /* U+93DF [2000] */ + {0xef65, 0xe99084}, /* U+9404 [2000] */ + {0xef66, 0xe98fbd}, /* U+93FD [2000] */ + {0xef67, 0xe990b3}, /* U+9433 [2000] */ + {0xef68, 0xe9918a}, /* U+944A [2000] */ + {0xef69, 0xe991a3}, /* U+9463 [2000] */ + {0xef6a, 0xe991ab}, /* U+946B [2000] */ + {0xef6b, 0xe991b1}, /* U+9471 [2000] */ + {0xef6c, 0xe991b2}, /* U+9472 [2000] */ + {0xef6d, 0xe9968e}, /* U+958E [2000] */ + {0xef6e, 0xe9969f}, /* U+959F [2000] */ + {0xef6f, 0xe996a6}, /* U+95A6 [2000] */ + {0xef70, 0xe996a9}, /* U+95A9 [2000] */ + {0xef71, 0xe996ac}, /* U+95AC [2000] */ + {0xef72, 0xe996b6}, /* U+95B6 [2000] */ + {0xef73, 0xe996bd}, /* U+95BD [2000] */ + {0xef74, 0xe9978b}, /* U+95CB [2000] */ + {0xef75, 0xe99790}, /* U+95D0 [2000] */ + {0xef76, 0xe99793}, /* U+95D3 [2000] */ + {0xef77, 0xe4a6b0}, /* U+49B0 [2000] */ + {0xef78, 0xe9979a}, /* U+95DA [2000] */ + {0xef79, 0xe9979e}, /* U+95DE [2000] */ + {0xef7a, 0xe99998}, /* U+9658 [2000] */ + {0xef7b, 0xe99a84}, /* U+9684 [2000] */ + {0xef7c, 0xefa79c}, /* U+F9DC CJK COMPATIBILITY IDEOGRAPH-F9DC [2000] */ + {0xef7d, 0xe99a9d}, /* U+969D [2000] */ + {0xef7e, 0xe99aa4}, /* U+96A4 [2000] */ + {0xef80, 0xe99aa5}, /* U+96A5 [2000] */ + {0xef81, 0xe99b92}, /* U+96D2 [2000] */ + {0xef82, 0xe99b9e}, /* U+96DE [2000] */ + {0xef83, 0xefa9a8}, /* U+FA68 CJK COMPATIBILITY IDEOGRAPH-FA68 [2000] [Unicode3.2] */ + {0xef84, 0xe99ba9}, /* U+96E9 [2000] */ + {0xef85, 0xe99baf}, /* U+96EF [2000] */ + {0xef86, 0xe99cb3}, /* U+9733 [2000] */ + {0xef87, 0xe99cbb}, /* U+973B [2000] */ + {0xef88, 0xe99d8d}, /* U+974D [2000] */ + {0xef89, 0xe99d8e}, /* U+974E [2000] */ + {0xef8a, 0xe99d8f}, /* U+974F [2000] */ + {0xef8b, 0xe99d9a}, /* U+975A [2000] */ + {0xef8c, 0xe99dae}, /* U+976E [2000] */ + {0xef8d, 0xe99db3}, /* U+9773 [2000] */ + {0xef8e, 0xe99e95}, /* U+9795 [2000] */ + {0xef8f, 0xe99eae}, /* U+97AE [2000] */ + {0xef90, 0xe99eba}, /* U+97BA [2000] */ + {0xef91, 0xe99f81}, /* U+97C1 [2000] */ + {0xef92, 0xe99f89}, /* U+97C9 [2000] */ + {0xef93, 0xe99f9e}, /* U+97DE [2000] */ + {0xef94, 0xe99f9b}, /* U+97DB [2000] */ + {0xef95, 0xe99fb4}, /* U+97F4 [2000] */ + {0xef96, 0xefa9a9}, /* U+FA69 CJK COMPATIBILITY IDEOGRAPH-FA69 [2000] [Unicode3.2] */ + {0xef97, 0xe9a08a}, /* U+980A [2000] */ + {0xef98, 0xe9a09e}, /* U+981E [2000] */ + {0xef99, 0xe9a0ab}, /* U+982B [2000] */ + {0xef9a, 0xe9a0b0}, /* U+9830 [2000] */ + {0xef9b, 0xefa9aa}, /* U+FA6A CJK COMPATIBILITY IDEOGRAPH-FA6A [2000] [Unicode3.2] */ + {0xef9c, 0xe9a192}, /* U+9852 [2000] */ + {0xef9d, 0xe9a193}, /* U+9853 [2000] */ + {0xef9e, 0xe9a196}, /* U+9856 [2000] */ + {0xef9f, 0xe9a197}, /* U+9857 [2000] */ + {0xefa0, 0xe9a199}, /* U+9859 [2000] */ + {0xefa1, 0xe9a19a}, /* U+985A [2000] */ + {0xefa2, 0xefa790}, /* U+F9D0 CJK COMPATIBILITY IDEOGRAPH-F9D0 [2000] */ + {0xefa3, 0xe9a1a5}, /* U+9865 [2000] */ + {0xefa4, 0xe9a1ac}, /* U+986C [2000] */ + {0xefa5, 0xe9a2ba}, /* U+98BA [2000] */ + {0xefa6, 0xe9a388}, /* U+98C8 [2000] */ + {0xefa7, 0xe9a3a7}, /* U+98E7 [2000] */ + {0xefa8, 0xe9a598}, /* U+9958 [2000] */ + {0xefa9, 0xe9a69e}, /* U+999E [2000] */ + {0xefaa, 0xe9a882}, /* U+9A02 [2000] */ + {0xefab, 0xe9a883}, /* U+9A03 [2000] */ + {0xefac, 0xe9a8a4}, /* U+9A24 [2000] */ + {0xefad, 0xe9a8ad}, /* U+9A2D [2000] */ + {0xefae, 0xe9a8ae}, /* U+9A2E [2000] */ + {0xefaf, 0xe9a8b8}, /* U+9A38 [2000] */ + {0xefb0, 0xe9a98a}, /* U+9A4A [2000] */ + {0xefb1, 0xe9a98e}, /* U+9A4E [2000] */ + {0xefb2, 0xe9a992}, /* U+9A52 [2000] */ + {0xefb3, 0xe9aab6}, /* U+9AB6 [2000] */ + {0xefb4, 0xe9ab81}, /* U+9AC1 [2000] */ + {0xefb5, 0xe9ab83}, /* U+9AC3 [2000] */ + {0xefb6, 0xe9ab8e}, /* U+9ACE [2000] */ + {0xefb7, 0xe9ab96}, /* U+9AD6 [2000] */ + {0xefb8, 0xe9abb9}, /* U+9AF9 [2000] */ + {0xefb9, 0xe9ac82}, /* U+9B02 [2000] */ + {0xefba, 0xe9ac88}, /* U+9B08 [2000] */ + {0xefbb, 0xe9aca0}, /* U+9B20 [2000] */ + {0xefbc, 0xe4b097}, /* U+4C17 [2000] */ + {0xefbd, 0xe9acad}, /* U+9B2D [2000] */ + {0xefbe, 0xe9ad9e}, /* U+9B5E [2000] */ + {0xefbf, 0xe9adb9}, /* U+9B79 [2000] */ + {0xefc0, 0xe9ada6}, /* U+9B66 [2000] */ + {0xefc1, 0xe9adb2}, /* U+9B72 [2000] */ + {0xefc2, 0xe9adb5}, /* U+9B75 [2000] */ + {0xefc3, 0xe9ae84}, /* U+9B84 [2000] */ + {0xefc4, 0xe9ae8a}, /* U+9B8A [2000] */ + {0xefc5, 0xe9ae8f}, /* U+9B8F [2000] */ + {0xefc6, 0xe9ae9e}, /* U+9B9E [2000] */ + {0xefc7, 0xe9aea7}, /* U+9BA7 [2000] */ + {0xefc8, 0xe9af81}, /* U+9BC1 [2000] */ + {0xefc9, 0xe9af8e}, /* U+9BCE [2000] */ + {0xefca, 0xe9afa5}, /* U+9BE5 [2000] */ + {0xefcb, 0xe9afb8}, /* U+9BF8 [2000] */ + {0xefcc, 0xe9afbd}, /* U+9BFD [2000] */ + {0xefcd, 0xe9b080}, /* U+9C00 [2000] */ + {0xefce, 0xe9b0a3}, /* U+9C23 [2000] */ + {0xefcf, 0xe9b181}, /* U+9C41 [2000] */ + {0xefd0, 0xe9b18f}, /* U+9C4F [2000] */ + {0xefd1, 0xe9b190}, /* U+9C50 [2000] */ + {0xefd2, 0xe9b193}, /* U+9C53 [2000] */ + {0xefd3, 0xe9b1a3}, /* U+9C63 [2000] */ + {0xefd4, 0xe9b1a5}, /* U+9C65 [2000] */ + {0xefd5, 0xe9b1b7}, /* U+9C77 [2000] */ + {0xefd6, 0xe9b49d}, /* U+9D1D [2000] */ + {0xefd7, 0xe9b49e}, /* U+9D1E [2000] */ + {0xefd8, 0xe9b583}, /* U+9D43 [2000] */ + {0xefd9, 0xe9b587}, /* U+9D47 [2000] */ + {0xefda, 0xe9b592}, /* U+9D52 [2000] */ + {0xefdb, 0xe9b5a3}, /* U+9D63 [2000] */ + {0xefdc, 0xe9b5b0}, /* U+9D70 [2000] */ + {0xefdd, 0xe9b5bc}, /* U+9D7C [2000] */ + {0xefde, 0xe9b68a}, /* U+9D8A [2000] */ + {0xefdf, 0xe9b696}, /* U+9D96 [2000] */ + {0xefe0, 0xe9b780}, /* U+9DC0 [2000] */ + {0xefe1, 0xe9b6ac}, /* U+9DAC [2000] */ + {0xefe2, 0xe9b6bc}, /* U+9DBC [2000] */ + {0xefe3, 0xe9b797}, /* U+9DD7 [2000] */ {0xefe4, 0xf0aa8690}, /* U+2A190 [2000] [Unicode3.1] */ - {0xefe5, 0x00e9b7a7}, /* U+9DE7 [2000] */ - {0xefe6, 0x00e9b887}, /* U+9E07 [2000] */ - {0xefe7, 0x00e9b895}, /* U+9E15 [2000] */ - {0xefe8, 0x00e9b9bc}, /* U+9E7C [2000] */ - {0xefe9, 0x00e9ba9e}, /* U+9E9E [2000] */ - {0xefea, 0x00e9baa4}, /* U+9EA4 [2000] */ - {0xefeb, 0x00e9baac}, /* U+9EAC [2000] */ - {0xefec, 0x00e9baaf}, /* U+9EAF [2000] */ - {0xefed, 0x00e9bab4}, /* U+9EB4 [2000] */ - {0xefee, 0x00e9bab5}, /* U+9EB5 [2000] */ - {0xefef, 0x00e9bb83}, /* U+9EC3 [2000] */ - {0xeff0, 0x00e9bb91}, /* U+9ED1 [2000] */ - {0xeff1, 0x00e9bc90}, /* U+9F10 [2000] */ - {0xeff2, 0x00e9bcb9}, /* U+9F39 [2000] */ - {0xeff3, 0x00e9bd97}, /* U+9F57 [2000] */ - {0xeff4, 0x00e9be90}, /* U+9F90 [2000] */ - {0xeff5, 0x00e9be94}, /* U+9F94 [2000] */ - {0xeff6, 0x00e9be97}, /* U+9F97 [2000] */ - {0xeff7, 0x00e9bea2}, /* U+9FA2 [2000] */ - {0xeff8, 0x00e5a7b8}, /* U+59F8 [2004] */ - {0xeff9, 0x00e5b19b}, /* U+5C5B [2004] */ - {0xeffa, 0x00e5b9b7}, /* U+5E77 [2004] */ - {0xeffb, 0x00e798a6}, /* U+7626 [2004] */ - {0xeffc, 0x00e7b9ab}, /* U+7E6B [2004] */ + {0xefe5, 0xe9b7a7}, /* U+9DE7 [2000] */ + {0xefe6, 0xe9b887}, /* U+9E07 [2000] */ + {0xefe7, 0xe9b895}, /* U+9E15 [2000] */ + {0xefe8, 0xe9b9bc}, /* U+9E7C [2000] */ + {0xefe9, 0xe9ba9e}, /* U+9E9E [2000] */ + {0xefea, 0xe9baa4}, /* U+9EA4 [2000] */ + {0xefeb, 0xe9baac}, /* U+9EAC [2000] */ + {0xefec, 0xe9baaf}, /* U+9EAF [2000] */ + {0xefed, 0xe9bab4}, /* U+9EB4 [2000] */ + {0xefee, 0xe9bab5}, /* U+9EB5 [2000] */ + {0xefef, 0xe9bb83}, /* U+9EC3 [2000] */ + {0xeff0, 0xe9bb91}, /* U+9ED1 [2000] */ + {0xeff1, 0xe9bc90}, /* U+9F10 [2000] */ + {0xeff2, 0xe9bcb9}, /* U+9F39 [2000] */ + {0xeff3, 0xe9bd97}, /* U+9F57 [2000] */ + {0xeff4, 0xe9be90}, /* U+9F90 [2000] */ + {0xeff5, 0xe9be94}, /* U+9F94 [2000] */ + {0xeff6, 0xe9be97}, /* U+9F97 [2000] */ + {0xeff7, 0xe9bea2}, /* U+9FA2 [2000] */ + {0xeff8, 0xe5a7b8}, /* U+59F8 [2004] */ + {0xeff9, 0xe5b19b}, /* U+5C5B [2004] */ + {0xeffa, 0xe5b9b7}, /* U+5E77 [2004] */ + {0xeffb, 0xe798a6}, /* U+7626 [2004] */ + {0xeffc, 0xe7b9ab}, /* U+7E6B [2004] */ {0xf040, 0xf0a08289}, /* U+20089 [2000] [Unicode3.1] */ - {0xf041, 0x00e4b882}, /* U+4E02 [2000] */ - {0xf042, 0x00e4b88f}, /* U+4E0F [2000] */ - {0xf043, 0x00e4b892}, /* U+4E12 [2000] */ - {0xf044, 0x00e4b8a9}, /* U+4E29 [2000] */ - {0xf045, 0x00e4b8ab}, /* U+4E2B [2000] */ - {0xf046, 0x00e4b8ae}, /* U+4E2E [2000] */ - {0xf047, 0x00e4b980}, /* U+4E40 [2000] */ - {0xf048, 0x00e4b987}, /* U+4E47 [2000] */ - {0xf049, 0x00e4b988}, /* U+4E48 [2000] */ + {0xf041, 0xe4b882}, /* U+4E02 [2000] */ + {0xf042, 0xe4b88f}, /* U+4E0F [2000] */ + {0xf043, 0xe4b892}, /* U+4E12 [2000] */ + {0xf044, 0xe4b8a9}, /* U+4E29 [2000] */ + {0xf045, 0xe4b8ab}, /* U+4E2B [2000] */ + {0xf046, 0xe4b8ae}, /* U+4E2E [2000] */ + {0xf047, 0xe4b980}, /* U+4E40 [2000] */ + {0xf048, 0xe4b987}, /* U+4E47 [2000] */ + {0xf049, 0xe4b988}, /* U+4E48 [2000] */ {0xf04a, 0xf0a082a2}, /* U+200A2 [2000] [Unicode3.1] */ - {0xf04b, 0x00e4b991}, /* U+4E51 [2000] */ - {0xf04c, 0x00e39086}, /* U+3406 [2000] */ + {0xf04b, 0xe4b991}, /* U+4E51 [2000] */ + {0xf04c, 0xe39086}, /* U+3406 [2000] */ {0xf04d, 0xf0a082a4}, /* U+200A4 [2000] [Unicode3.1] */ - {0xf04e, 0x00e4b99a}, /* U+4E5A [2000] */ - {0xf04f, 0x00e4b9a9}, /* U+4E69 [2000] */ - {0xf050, 0x00e4ba9d}, /* U+4E9D [2000] */ - {0xf051, 0x00e390ac}, /* U+342C [2000] */ - {0xf052, 0x00e390ae}, /* U+342E [2000] */ - {0xf053, 0x00e4bab9}, /* U+4EB9 [2000] */ - {0xf054, 0x00e4babb}, /* U+4EBB [2000] */ + {0xf04e, 0xe4b99a}, /* U+4E5A [2000] */ + {0xf04f, 0xe4b9a9}, /* U+4E69 [2000] */ + {0xf050, 0xe4ba9d}, /* U+4E9D [2000] */ + {0xf051, 0xe390ac}, /* U+342C [2000] */ + {0xf052, 0xe390ae}, /* U+342E [2000] */ + {0xf053, 0xe4bab9}, /* U+4EB9 [2000] */ + {0xf054, 0xe4babb}, /* U+4EBB [2000] */ {0xf055, 0xf0a086a2}, /* U+201A2 [2000] [Unicode3.1] */ - {0xf056, 0x00e4babc}, /* U+4EBC [2000] */ - {0xf057, 0x00e4bb83}, /* U+4EC3 [2000] */ - {0xf058, 0x00e4bb88}, /* U+4EC8 [2000] */ - {0xf059, 0x00e4bb90}, /* U+4ED0 [2000] */ - {0xf05a, 0x00e4bbab}, /* U+4EEB [2000] */ - {0xf05b, 0x00e4bb9a}, /* U+4EDA [2000] */ - {0xf05c, 0x00e4bbb1}, /* U+4EF1 [2000] */ - {0xf05d, 0x00e4bbb5}, /* U+4EF5 [2000] */ - {0xf05e, 0x00e4bc80}, /* U+4F00 [2000] */ - {0xf05f, 0x00e4bc96}, /* U+4F16 [2000] */ - {0xf060, 0x00e4bda4}, /* U+4F64 [2000] */ - {0xf061, 0x00e4bcb7}, /* U+4F37 [2000] */ - {0xf062, 0x00e4bcbe}, /* U+4F3E [2000] */ - {0xf063, 0x00e4bd94}, /* U+4F54 [2000] */ - {0xf064, 0x00e4bd98}, /* U+4F58 [2000] */ + {0xf056, 0xe4babc}, /* U+4EBC [2000] */ + {0xf057, 0xe4bb83}, /* U+4EC3 [2000] */ + {0xf058, 0xe4bb88}, /* U+4EC8 [2000] */ + {0xf059, 0xe4bb90}, /* U+4ED0 [2000] */ + {0xf05a, 0xe4bbab}, /* U+4EEB [2000] */ + {0xf05b, 0xe4bb9a}, /* U+4EDA [2000] */ + {0xf05c, 0xe4bbb1}, /* U+4EF1 [2000] */ + {0xf05d, 0xe4bbb5}, /* U+4EF5 [2000] */ + {0xf05e, 0xe4bc80}, /* U+4F00 [2000] */ + {0xf05f, 0xe4bc96}, /* U+4F16 [2000] */ + {0xf060, 0xe4bda4}, /* U+4F64 [2000] */ + {0xf061, 0xe4bcb7}, /* U+4F37 [2000] */ + {0xf062, 0xe4bcbe}, /* U+4F3E [2000] */ + {0xf063, 0xe4bd94}, /* U+4F54 [2000] */ + {0xf064, 0xe4bd98}, /* U+4F58 [2000] */ {0xf065, 0xf0a08893}, /* U+20213 [2000] [Unicode3.1] */ - {0xf066, 0x00e4bdb7}, /* U+4F77 [2000] */ - {0xf067, 0x00e4bdb8}, /* U+4F78 [2000] */ - {0xf068, 0x00e4bdba}, /* U+4F7A [2000] */ - {0xf069, 0x00e4bdbd}, /* U+4F7D [2000] */ - {0xf06a, 0x00e4be82}, /* U+4F82 [2000] */ - {0xf06b, 0x00e4be85}, /* U+4F85 [2000] */ - {0xf06c, 0x00e4be92}, /* U+4F92 [2000] */ - {0xf06d, 0x00e4be9a}, /* U+4F9A [2000] */ - {0xf06e, 0x00e4bfa6}, /* U+4FE6 [2000] */ - {0xf06f, 0x00e4beb2}, /* U+4FB2 [2000] */ - {0xf070, 0x00e4bebe}, /* U+4FBE [2000] */ - {0xf071, 0x00e4bf85}, /* U+4FC5 [2000] */ - {0xf072, 0x00e4bf8b}, /* U+4FCB [2000] */ - {0xf073, 0x00e4bf8f}, /* U+4FCF [2000] */ - {0xf074, 0x00e4bf92}, /* U+4FD2 [2000] */ - {0xf075, 0x00e391aa}, /* U+346A [2000] */ - {0xf076, 0x00e4bfb2}, /* U+4FF2 [2000] */ - {0xf077, 0x00e58080}, /* U+5000 [2000] */ - {0xf078, 0x00e58090}, /* U+5010 [2000] */ - {0xf079, 0x00e58093}, /* U+5013 [2000] */ - {0xf07a, 0x00e5809c}, /* U+501C [2000] */ - {0xf07b, 0x00e5809e}, /* U+501E [2000] */ - {0xf07c, 0x00e580a2}, /* U+5022 [2000] */ - {0xf07d, 0x00e391a8}, /* U+3468 [2000] */ - {0xf07e, 0x00e58182}, /* U+5042 [2000] */ - {0xf080, 0x00e58186}, /* U+5046 [2000] */ - {0xf081, 0x00e5818e}, /* U+504E [2000] */ - {0xf082, 0x00e58193}, /* U+5053 [2000] */ - {0xf083, 0x00e58197}, /* U+5057 [2000] */ - {0xf084, 0x00e581a3}, /* U+5063 [2000] */ - {0xf085, 0x00e581a6}, /* U+5066 [2000] */ - {0xf086, 0x00e581aa}, /* U+506A [2000] */ - {0xf087, 0x00e581b0}, /* U+5070 [2000] */ - {0xf088, 0x00e582a3}, /* U+50A3 [2000] */ - {0xf089, 0x00e58288}, /* U+5088 [2000] */ - {0xf08a, 0x00e58292}, /* U+5092 [2000] */ - {0xf08b, 0x00e58293}, /* U+5093 [2000] */ - {0xf08c, 0x00e58295}, /* U+5095 [2000] */ - {0xf08d, 0x00e58296}, /* U+5096 [2000] */ - {0xf08e, 0x00e5829c}, /* U+509C [2000] */ - {0xf08f, 0x00e582aa}, /* U+50AA [2000] */ + {0xf066, 0xe4bdb7}, /* U+4F77 [2000] */ + {0xf067, 0xe4bdb8}, /* U+4F78 [2000] */ + {0xf068, 0xe4bdba}, /* U+4F7A [2000] */ + {0xf069, 0xe4bdbd}, /* U+4F7D [2000] */ + {0xf06a, 0xe4be82}, /* U+4F82 [2000] */ + {0xf06b, 0xe4be85}, /* U+4F85 [2000] */ + {0xf06c, 0xe4be92}, /* U+4F92 [2000] */ + {0xf06d, 0xe4be9a}, /* U+4F9A [2000] */ + {0xf06e, 0xe4bfa6}, /* U+4FE6 [2000] */ + {0xf06f, 0xe4beb2}, /* U+4FB2 [2000] */ + {0xf070, 0xe4bebe}, /* U+4FBE [2000] */ + {0xf071, 0xe4bf85}, /* U+4FC5 [2000] */ + {0xf072, 0xe4bf8b}, /* U+4FCB [2000] */ + {0xf073, 0xe4bf8f}, /* U+4FCF [2000] */ + {0xf074, 0xe4bf92}, /* U+4FD2 [2000] */ + {0xf075, 0xe391aa}, /* U+346A [2000] */ + {0xf076, 0xe4bfb2}, /* U+4FF2 [2000] */ + {0xf077, 0xe58080}, /* U+5000 [2000] */ + {0xf078, 0xe58090}, /* U+5010 [2000] */ + {0xf079, 0xe58093}, /* U+5013 [2000] */ + {0xf07a, 0xe5809c}, /* U+501C [2000] */ + {0xf07b, 0xe5809e}, /* U+501E [2000] */ + {0xf07c, 0xe580a2}, /* U+5022 [2000] */ + {0xf07d, 0xe391a8}, /* U+3468 [2000] */ + {0xf07e, 0xe58182}, /* U+5042 [2000] */ + {0xf080, 0xe58186}, /* U+5046 [2000] */ + {0xf081, 0xe5818e}, /* U+504E [2000] */ + {0xf082, 0xe58193}, /* U+5053 [2000] */ + {0xf083, 0xe58197}, /* U+5057 [2000] */ + {0xf084, 0xe581a3}, /* U+5063 [2000] */ + {0xf085, 0xe581a6}, /* U+5066 [2000] */ + {0xf086, 0xe581aa}, /* U+506A [2000] */ + {0xf087, 0xe581b0}, /* U+5070 [2000] */ + {0xf088, 0xe582a3}, /* U+50A3 [2000] */ + {0xf089, 0xe58288}, /* U+5088 [2000] */ + {0xf08a, 0xe58292}, /* U+5092 [2000] */ + {0xf08b, 0xe58293}, /* U+5093 [2000] */ + {0xf08c, 0xe58295}, /* U+5095 [2000] */ + {0xf08d, 0xe58296}, /* U+5096 [2000] */ + {0xf08e, 0xe5829c}, /* U+509C [2000] */ + {0xf08f, 0xe582aa}, /* U+50AA [2000] */ {0xf090, 0xf0a08cab}, /* U+2032B [2000] [Unicode3.1] */ - {0xf091, 0x00e582b1}, /* U+50B1 [2000] */ - {0xf092, 0x00e582ba}, /* U+50BA [2000] */ - {0xf093, 0x00e582bb}, /* U+50BB [2000] */ - {0xf094, 0x00e58384}, /* U+50C4 [2000] */ - {0xf095, 0x00e58387}, /* U+50C7 [2000] */ - {0xf096, 0x00e583b3}, /* U+50F3 [2000] */ + {0xf091, 0xe582b1}, /* U+50B1 [2000] */ + {0xf092, 0xe582ba}, /* U+50BA [2000] */ + {0xf093, 0xe582bb}, /* U+50BB [2000] */ + {0xf094, 0xe58384}, /* U+50C4 [2000] */ + {0xf095, 0xe58387}, /* U+50C7 [2000] */ + {0xf096, 0xe583b3}, /* U+50F3 [2000] */ {0xf097, 0xf0a08e81}, /* U+20381 [2000] [Unicode3.1] */ - {0xf098, 0x00e5838e}, /* U+50CE [2000] */ + {0xf098, 0xe5838e}, /* U+50CE [2000] */ {0xf099, 0xf0a08db1}, /* U+20371 [2000] [Unicode3.1] */ - {0xf09a, 0x00e58394}, /* U+50D4 [2000] */ - {0xf09b, 0x00e58399}, /* U+50D9 [2000] */ - {0xf09c, 0x00e583a1}, /* U+50E1 [2000] */ - {0xf09d, 0x00e583a9}, /* U+50E9 [2000] */ - {0xf09e, 0x00e39292}, /* U+3492 [2000] */ - {0xf09f, 0x00e5ae96}, /* U+5B96 [2000] */ - {0xf0a0, 0x00e5aeac}, /* U+5BAC [2000] */ - {0xf0a1, 0x00e39da1}, /* U+3761 [2000] */ - {0xf0a2, 0x00e5af80}, /* U+5BC0 [2000] */ - {0xf0a3, 0x00e39da2}, /* U+3762 [2000] */ - {0xf0a4, 0x00e5af8e}, /* U+5BCE [2000] */ - {0xf0a5, 0x00e5af96}, /* U+5BD6 [2000] */ - {0xf0a6, 0x00e39dac}, /* U+376C [2000] */ - {0xf0a7, 0x00e39dab}, /* U+376B [2000] */ - {0xf0a8, 0x00e5afb1}, /* U+5BF1 [2000] */ - {0xf0a9, 0x00e5afbd}, /* U+5BFD [2000] */ - {0xf0aa, 0x00e39db5}, /* U+3775 [2000] */ - {0xf0ab, 0x00e5b083}, /* U+5C03 [2000] */ - {0xf0ac, 0x00e5b0a9}, /* U+5C29 [2000] */ - {0xf0ad, 0x00e5b0b0}, /* U+5C30 [2000] */ + {0xf09a, 0xe58394}, /* U+50D4 [2000] */ + {0xf09b, 0xe58399}, /* U+50D9 [2000] */ + {0xf09c, 0xe583a1}, /* U+50E1 [2000] */ + {0xf09d, 0xe583a9}, /* U+50E9 [2000] */ + {0xf09e, 0xe39292}, /* U+3492 [2000] */ + {0xf09f, 0xe5ae96}, /* U+5B96 [2000] */ + {0xf0a0, 0xe5aeac}, /* U+5BAC [2000] */ + {0xf0a1, 0xe39da1}, /* U+3761 [2000] */ + {0xf0a2, 0xe5af80}, /* U+5BC0 [2000] */ + {0xf0a3, 0xe39da2}, /* U+3762 [2000] */ + {0xf0a4, 0xe5af8e}, /* U+5BCE [2000] */ + {0xf0a5, 0xe5af96}, /* U+5BD6 [2000] */ + {0xf0a6, 0xe39dac}, /* U+376C [2000] */ + {0xf0a7, 0xe39dab}, /* U+376B [2000] */ + {0xf0a8, 0xe5afb1}, /* U+5BF1 [2000] */ + {0xf0a9, 0xe5afbd}, /* U+5BFD [2000] */ + {0xf0aa, 0xe39db5}, /* U+3775 [2000] */ + {0xf0ab, 0xe5b083}, /* U+5C03 [2000] */ + {0xf0ac, 0xe5b0a9}, /* U+5C29 [2000] */ + {0xf0ad, 0xe5b0b0}, /* U+5C30 [2000] */ {0xf0ae, 0xf0a1b196}, /* U+21C56 [2000] [Unicode3.1] */ - {0xf0af, 0x00e5b19f}, /* U+5C5F [2000] */ - {0xf0b0, 0x00e5b1a3}, /* U+5C63 [2000] */ - {0xf0b1, 0x00e5b1a7}, /* U+5C67 [2000] */ - {0xf0b2, 0x00e5b1a8}, /* U+5C68 [2000] */ - {0xf0b3, 0x00e5b1a9}, /* U+5C69 [2000] */ - {0xf0b4, 0x00e5b1b0}, /* U+5C70 [2000] */ + {0xf0af, 0xe5b19f}, /* U+5C5F [2000] */ + {0xf0b0, 0xe5b1a3}, /* U+5C63 [2000] */ + {0xf0b1, 0xe5b1a7}, /* U+5C67 [2000] */ + {0xf0b2, 0xe5b1a8}, /* U+5C68 [2000] */ + {0xf0b3, 0xe5b1a9}, /* U+5C69 [2000] */ + {0xf0b4, 0xe5b1b0}, /* U+5C70 [2000] */ {0xf0b5, 0xf0a1b4ad}, /* U+21D2D [2000] [Unicode3.1] */ {0xf0b6, 0xf0a1b585}, /* U+21D45 [2000] [Unicode3.1] */ - {0xf0b7, 0x00e5b1bc}, /* U+5C7C [2000] */ + {0xf0b7, 0xe5b1bc}, /* U+5C7C [2000] */ {0xf0b8, 0xf0a1b5b8}, /* U+21D78 [2000] [Unicode3.1] */ {0xf0b9, 0xf0a1b5a2}, /* U+21D62 [2000] [Unicode3.1] */ - {0xf0ba, 0x00e5b288}, /* U+5C88 [2000] */ - {0xf0bb, 0x00e5b28a}, /* U+5C8A [2000] */ - {0xf0bc, 0x00e39f81}, /* U+37C1 [2000] */ + {0xf0ba, 0xe5b288}, /* U+5C88 [2000] */ + {0xf0bb, 0xe5b28a}, /* U+5C8A [2000] */ + {0xf0bc, 0xe39f81}, /* U+37C1 [2000] */ {0xf0bd, 0xf0a1b6a1}, /* U+21DA1 [2000] [Unicode3.1] */ {0xf0be, 0xf0a1b69c}, /* U+21D9C [2000] [Unicode3.1] */ - {0xf0bf, 0x00e5b2a0}, /* U+5CA0 [2000] */ - {0xf0c0, 0x00e5b2a2}, /* U+5CA2 [2000] */ - {0xf0c1, 0x00e5b2a6}, /* U+5CA6 [2000] */ - {0xf0c2, 0x00e5b2a7}, /* U+5CA7 [2000] */ + {0xf0bf, 0xe5b2a0}, /* U+5CA0 [2000] */ + {0xf0c0, 0xe5b2a2}, /* U+5CA2 [2000] */ + {0xf0c1, 0xe5b2a6}, /* U+5CA6 [2000] */ + {0xf0c2, 0xe5b2a7}, /* U+5CA7 [2000] */ {0xf0c3, 0xf0a1b692}, /* U+21D92 [2000] [Unicode3.1] */ - {0xf0c4, 0x00e5b2ad}, /* U+5CAD [2000] */ - {0xf0c5, 0x00e5b2b5}, /* U+5CB5 [2000] */ + {0xf0c4, 0xe5b2ad}, /* U+5CAD [2000] */ + {0xf0c5, 0xe5b2b5}, /* U+5CB5 [2000] */ {0xf0c6, 0xf0a1b6b7}, /* U+21DB7 [2000] [Unicode3.1] */ - {0xf0c7, 0x00e5b389}, /* U+5CC9 [2000] */ + {0xf0c7, 0xe5b389}, /* U+5CC9 [2000] */ {0xf0c8, 0xf0a1b7a0}, /* U+21DE0 [2000] [Unicode3.1] */ {0xf0c9, 0xf0a1b8b3}, /* U+21E33 [2000] [Unicode3.1] */ - {0xf0ca, 0x00e5b486}, /* U+5D06 [2000] */ - {0xf0cb, 0x00e5b490}, /* U+5D10 [2000] */ - {0xf0cc, 0x00e5b4ab}, /* U+5D2B [2000] */ - {0xf0cd, 0x00e5b49d}, /* U+5D1D [2000] */ - {0xf0ce, 0x00e5b4a0}, /* U+5D20 [2000] */ - {0xf0cf, 0x00e5b4a4}, /* U+5D24 [2000] */ - {0xf0d0, 0x00e5b4a6}, /* U+5D26 [2000] */ - {0xf0d1, 0x00e5b4b1}, /* U+5D31 [2000] */ - {0xf0d2, 0x00e5b4b9}, /* U+5D39 [2000] */ - {0xf0d3, 0x00e5b582}, /* U+5D42 [2000] */ - {0xf0d4, 0x00e39fa8}, /* U+37E8 [2000] */ - {0xf0d5, 0x00e5b5a1}, /* U+5D61 [2000] */ - {0xf0d6, 0x00e5b5aa}, /* U+5D6A [2000] */ - {0xf0d7, 0x00e39fb4}, /* U+37F4 [2000] */ - {0xf0d8, 0x00e5b5b0}, /* U+5D70 [2000] */ + {0xf0ca, 0xe5b486}, /* U+5D06 [2000] */ + {0xf0cb, 0xe5b490}, /* U+5D10 [2000] */ + {0xf0cc, 0xe5b4ab}, /* U+5D2B [2000] */ + {0xf0cd, 0xe5b49d}, /* U+5D1D [2000] */ + {0xf0ce, 0xe5b4a0}, /* U+5D20 [2000] */ + {0xf0cf, 0xe5b4a4}, /* U+5D24 [2000] */ + {0xf0d0, 0xe5b4a6}, /* U+5D26 [2000] */ + {0xf0d1, 0xe5b4b1}, /* U+5D31 [2000] */ + {0xf0d2, 0xe5b4b9}, /* U+5D39 [2000] */ + {0xf0d3, 0xe5b582}, /* U+5D42 [2000] */ + {0xf0d4, 0xe39fa8}, /* U+37E8 [2000] */ + {0xf0d5, 0xe5b5a1}, /* U+5D61 [2000] */ + {0xf0d6, 0xe5b5aa}, /* U+5D6A [2000] */ + {0xf0d7, 0xe39fb4}, /* U+37F4 [2000] */ + {0xf0d8, 0xe5b5b0}, /* U+5D70 [2000] */ {0xf0d9, 0xf0a1bc9e}, /* U+21F1E [2000] [Unicode3.1] */ - {0xf0da, 0x00e39fbd}, /* U+37FD [2000] */ - {0xf0db, 0x00e5b688}, /* U+5D88 [2000] */ - {0xf0dc, 0x00e3a080}, /* U+3800 [2000] */ - {0xf0dd, 0x00e5b692}, /* U+5D92 [2000] */ - {0xf0de, 0x00e5b694}, /* U+5D94 [2000] */ - {0xf0df, 0x00e5b697}, /* U+5D97 [2000] */ - {0xf0e0, 0x00e5b699}, /* U+5D99 [2000] */ - {0xf0e1, 0x00e5b6b0}, /* U+5DB0 [2000] */ - {0xf0e2, 0x00e5b6b2}, /* U+5DB2 [2000] */ - {0xf0e3, 0x00e5b6b4}, /* U+5DB4 [2000] */ + {0xf0da, 0xe39fbd}, /* U+37FD [2000] */ + {0xf0db, 0xe5b688}, /* U+5D88 [2000] */ + {0xf0dc, 0xe3a080}, /* U+3800 [2000] */ + {0xf0dd, 0xe5b692}, /* U+5D92 [2000] */ + {0xf0de, 0xe5b694}, /* U+5D94 [2000] */ + {0xf0df, 0xe5b697}, /* U+5D97 [2000] */ + {0xf0e0, 0xe5b699}, /* U+5D99 [2000] */ + {0xf0e1, 0xe5b6b0}, /* U+5DB0 [2000] */ + {0xf0e2, 0xe5b6b2}, /* U+5DB2 [2000] */ + {0xf0e3, 0xe5b6b4}, /* U+5DB4 [2000] */ {0xf0e4, 0xf0a1bdb6}, /* U+21F76 [2000] [Unicode3.1] */ - {0xf0e5, 0x00e5b6b9}, /* U+5DB9 [2000] */ - {0xf0e6, 0x00e5b791}, /* U+5DD1 [2000] */ - {0xf0e7, 0x00e5b797}, /* U+5DD7 [2000] */ - {0xf0e8, 0x00e5b798}, /* U+5DD8 [2000] */ - {0xf0e9, 0x00e5b7a0}, /* U+5DE0 [2000] */ + {0xf0e5, 0xe5b6b9}, /* U+5DB9 [2000] */ + {0xf0e6, 0xe5b791}, /* U+5DD1 [2000] */ + {0xf0e7, 0xe5b797}, /* U+5DD7 [2000] */ + {0xf0e8, 0xe5b798}, /* U+5DD8 [2000] */ + {0xf0e9, 0xe5b7a0}, /* U+5DE0 [2000] */ {0xf0ea, 0xf0a1bfba}, /* U+21FFA [2000] [Unicode3.1] */ - {0xf0eb, 0x00e5b7a4}, /* U+5DE4 [2000] */ - {0xf0ec, 0x00e5b7a9}, /* U+5DE9 [2000] */ - {0xf0ed, 0x00e3a0af}, /* U+382F [2000] */ - {0xf0ee, 0x00e5b880}, /* U+5E00 [2000] */ - {0xf0ef, 0x00e3a0b6}, /* U+3836 [2000] */ - {0xf0f0, 0x00e5b892}, /* U+5E12 [2000] */ - {0xf0f1, 0x00e5b895}, /* U+5E15 [2000] */ - {0xf0f2, 0x00e3a180}, /* U+3840 [2000] */ - {0xf0f3, 0x00e5b89f}, /* U+5E1F [2000] */ - {0xf0f4, 0x00e5b8ae}, /* U+5E2E [2000] */ - {0xf0f5, 0x00e5b8be}, /* U+5E3E [2000] */ - {0xf0f6, 0x00e5b989}, /* U+5E49 [2000] */ - {0xf0f7, 0x00e3a19c}, /* U+385C [2000] */ - {0xf0f8, 0x00e5b996}, /* U+5E56 [2000] */ - {0xf0f9, 0x00e3a1a1}, /* U+3861 [2000] */ - {0xf0fa, 0x00e5b9ab}, /* U+5E6B [2000] */ - {0xf0fb, 0x00e5b9ac}, /* U+5E6C [2000] */ - {0xf0fc, 0x00e5b9ad}, /* U+5E6D [2000] */ - {0xf140, 0x00e58488}, /* U+5108 [2000] */ + {0xf0eb, 0xe5b7a4}, /* U+5DE4 [2000] */ + {0xf0ec, 0xe5b7a9}, /* U+5DE9 [2000] */ + {0xf0ed, 0xe3a0af}, /* U+382F [2000] */ + {0xf0ee, 0xe5b880}, /* U+5E00 [2000] */ + {0xf0ef, 0xe3a0b6}, /* U+3836 [2000] */ + {0xf0f0, 0xe5b892}, /* U+5E12 [2000] */ + {0xf0f1, 0xe5b895}, /* U+5E15 [2000] */ + {0xf0f2, 0xe3a180}, /* U+3840 [2000] */ + {0xf0f3, 0xe5b89f}, /* U+5E1F [2000] */ + {0xf0f4, 0xe5b8ae}, /* U+5E2E [2000] */ + {0xf0f5, 0xe5b8be}, /* U+5E3E [2000] */ + {0xf0f6, 0xe5b989}, /* U+5E49 [2000] */ + {0xf0f7, 0xe3a19c}, /* U+385C [2000] */ + {0xf0f8, 0xe5b996}, /* U+5E56 [2000] */ + {0xf0f9, 0xe3a1a1}, /* U+3861 [2000] */ + {0xf0fa, 0xe5b9ab}, /* U+5E6B [2000] */ + {0xf0fb, 0xe5b9ac}, /* U+5E6C [2000] */ + {0xf0fc, 0xe5b9ad}, /* U+5E6D [2000] */ + {0xf140, 0xe58488}, /* U+5108 [2000] */ {0xf141, 0xf0a08fb9}, /* U+203F9 [2000] [Unicode3.1] */ - {0xf142, 0x00e58497}, /* U+5117 [2000] */ - {0xf143, 0x00e5849b}, /* U+511B [2000] */ + {0xf142, 0xe58497}, /* U+5117 [2000] */ + {0xf143, 0xe5849b}, /* U+511B [2000] */ {0xf144, 0xf0a0918a}, /* U+2044A [2000] [Unicode3.1] */ - {0xf145, 0x00e585a0}, /* U+5160 [2000] */ + {0xf145, 0xe585a0}, /* U+5160 [2000] */ {0xf146, 0xf0a09489}, /* U+20509 [2000] [Unicode3.1] */ - {0xf147, 0x00e585b3}, /* U+5173 [2000] */ - {0xf148, 0x00e58683}, /* U+5183 [2000] */ - {0xf149, 0x00e5868b}, /* U+518B [2000] */ - {0xf14a, 0x00e392bc}, /* U+34BC [2000] */ - {0xf14b, 0x00e58698}, /* U+5198 [2000] */ - {0xf14c, 0x00e586a3}, /* U+51A3 [2000] */ - {0xf14d, 0x00e586ad}, /* U+51AD [2000] */ - {0xf14e, 0x00e39387}, /* U+34C7 [2000] */ - {0xf14f, 0x00e586bc}, /* U+51BC [2000] */ + {0xf147, 0xe585b3}, /* U+5173 [2000] */ + {0xf148, 0xe58683}, /* U+5183 [2000] */ + {0xf149, 0xe5868b}, /* U+518B [2000] */ + {0xf14a, 0xe392bc}, /* U+34BC [2000] */ + {0xf14b, 0xe58698}, /* U+5198 [2000] */ + {0xf14c, 0xe586a3}, /* U+51A3 [2000] */ + {0xf14d, 0xe586ad}, /* U+51AD [2000] */ + {0xf14e, 0xe39387}, /* U+34C7 [2000] */ + {0xf14f, 0xe586bc}, /* U+51BC [2000] */ {0xf150, 0xf0a09796}, /* U+205D6 [2000] [Unicode3.1] */ {0xf151, 0xf0a098a8}, /* U+20628 [2000] [Unicode3.1] */ - {0xf152, 0x00e587b3}, /* U+51F3 [2000] */ - {0xf153, 0x00e587b4}, /* U+51F4 [2000] */ - {0xf154, 0x00e58882}, /* U+5202 [2000] */ - {0xf155, 0x00e58892}, /* U+5212 [2000] */ - {0xf156, 0x00e58896}, /* U+5216 [2000] */ + {0xf152, 0xe587b3}, /* U+51F3 [2000] */ + {0xf153, 0xe587b4}, /* U+51F4 [2000] */ + {0xf154, 0xe58882}, /* U+5202 [2000] */ + {0xf155, 0xe58892}, /* U+5212 [2000] */ + {0xf156, 0xe58896}, /* U+5216 [2000] */ {0xf157, 0xf0a09d8f}, /* U+2074F [2000] [Unicode3.1] */ - {0xf158, 0x00e58995}, /* U+5255 [2000] */ - {0xf159, 0x00e5899c}, /* U+525C [2000] */ - {0xf15a, 0x00e589ac}, /* U+526C [2000] */ - {0xf15b, 0x00e589b7}, /* U+5277 [2000] */ - {0xf15c, 0x00e58a84}, /* U+5284 [2000] */ - {0xf15d, 0x00e58a82}, /* U+5282 [2000] */ + {0xf158, 0xe58995}, /* U+5255 [2000] */ + {0xf159, 0xe5899c}, /* U+525C [2000] */ + {0xf15a, 0xe589ac}, /* U+526C [2000] */ + {0xf15b, 0xe589b7}, /* U+5277 [2000] */ + {0xf15c, 0xe58a84}, /* U+5284 [2000] */ + {0xf15d, 0xe58a82}, /* U+5282 [2000] */ {0xf15e, 0xf0a0a087}, /* U+20807 [2000] [Unicode3.1] */ - {0xf15f, 0x00e58a98}, /* U+5298 [2000] */ + {0xf15f, 0xe58a98}, /* U+5298 [2000] */ {0xf160, 0xf0a0a0ba}, /* U+2083A [2000] [Unicode3.1] */ - {0xf161, 0x00e58aa4}, /* U+52A4 [2000] */ - {0xf162, 0x00e58aa6}, /* U+52A6 [2000] */ - {0xf163, 0x00e58aaf}, /* U+52AF [2000] */ - {0xf164, 0x00e58aba}, /* U+52BA [2000] */ - {0xf165, 0x00e58abb}, /* U+52BB [2000] */ - {0xf166, 0x00e58b8a}, /* U+52CA [2000] */ - {0xf167, 0x00e3949f}, /* U+351F [2000] */ - {0xf168, 0x00e58b91}, /* U+52D1 [2000] */ + {0xf161, 0xe58aa4}, /* U+52A4 [2000] */ + {0xf162, 0xe58aa6}, /* U+52A6 [2000] */ + {0xf163, 0xe58aaf}, /* U+52AF [2000] */ + {0xf164, 0xe58aba}, /* U+52BA [2000] */ + {0xf165, 0xe58abb}, /* U+52BB [2000] */ + {0xf166, 0xe58b8a}, /* U+52CA [2000] */ + {0xf167, 0xe3949f}, /* U+351F [2000] */ + {0xf168, 0xe58b91}, /* U+52D1 [2000] */ {0xf169, 0xf0a0a2b9}, /* U+208B9 [2000] [Unicode3.1] */ - {0xf16a, 0x00e58bb7}, /* U+52F7 [2000] */ - {0xf16b, 0x00e58c8a}, /* U+530A [2000] */ - {0xf16c, 0x00e58c8b}, /* U+530B [2000] */ - {0xf16d, 0x00e58ca4}, /* U+5324 [2000] */ - {0xf16e, 0x00e58cb5}, /* U+5335 [2000] */ - {0xf16f, 0x00e58cbe}, /* U+533E [2000] */ - {0xf170, 0x00e58d82}, /* U+5342 [2000] */ + {0xf16a, 0xe58bb7}, /* U+52F7 [2000] */ + {0xf16b, 0xe58c8a}, /* U+530A [2000] */ + {0xf16c, 0xe58c8b}, /* U+530B [2000] */ + {0xf16d, 0xe58ca4}, /* U+5324 [2000] */ + {0xf16e, 0xe58cb5}, /* U+5335 [2000] */ + {0xf16f, 0xe58cbe}, /* U+533E [2000] */ + {0xf170, 0xe58d82}, /* U+5342 [2000] */ {0xf171, 0xf0a0a5bc}, /* U+2097C [2000] [Unicode3.1] */ {0xf172, 0xf0a0a69d}, /* U+2099D [2000] [Unicode3.1] */ - {0xf173, 0x00e58da7}, /* U+5367 [2000] */ - {0xf174, 0x00e58dac}, /* U+536C [2000] */ - {0xf175, 0x00e58dba}, /* U+537A [2000] */ - {0xf176, 0x00e58ea4}, /* U+53A4 [2000] */ - {0xf177, 0x00e58eb4}, /* U+53B4 [2000] */ + {0xf173, 0xe58da7}, /* U+5367 [2000] */ + {0xf174, 0xe58dac}, /* U+536C [2000] */ + {0xf175, 0xe58dba}, /* U+537A [2000] */ + {0xf176, 0xe58ea4}, /* U+53A4 [2000] */ + {0xf177, 0xe58eb4}, /* U+53B4 [2000] */ {0xf178, 0xf0a0ab93}, /* U+20AD3 [2000] [Unicode3.1] */ - {0xf179, 0x00e58eb7}, /* U+53B7 [2000] */ - {0xf17a, 0x00e58f80}, /* U+53C0 [2000] */ + {0xf179, 0xe58eb7}, /* U+53B7 [2000] */ + {0xf17a, 0xe58f80}, /* U+53C0 [2000] */ {0xf17b, 0xf0a0ac9d}, /* U+20B1D [2000] [Unicode3.1] */ - {0xf17c, 0x00e3959d}, /* U+355D [2000] */ - {0xf17d, 0x00e3959e}, /* U+355E [2000] */ - {0xf17e, 0x00e58f95}, /* U+53D5 [2000] */ - {0xf180, 0x00e58f9a}, /* U+53DA [2000] */ - {0xf181, 0x00e395a3}, /* U+3563 [2000] */ - {0xf182, 0x00e58fb4}, /* U+53F4 [2000] */ - {0xf183, 0x00e58fb5}, /* U+53F5 [2000] */ - {0xf184, 0x00e59195}, /* U+5455 [2000] */ - {0xf185, 0x00e590a4}, /* U+5424 [2000] */ - {0xf186, 0x00e590a8}, /* U+5428 [2000] */ - {0xf187, 0x00e395ae}, /* U+356E [2000] */ - {0xf188, 0x00e59183}, /* U+5443 [2000] */ - {0xf189, 0x00e591a2}, /* U+5462 [2000] */ - {0xf18a, 0x00e591a6}, /* U+5466 [2000] */ - {0xf18b, 0x00e591ac}, /* U+546C [2000] */ - {0xf18c, 0x00e5928a}, /* U+548A [2000] */ - {0xf18d, 0x00e5928d}, /* U+548D [2000] */ - {0xf18e, 0x00e59295}, /* U+5495 [2000] */ - {0xf18f, 0x00e592a0}, /* U+54A0 [2000] */ - {0xf190, 0x00e592a6}, /* U+54A6 [2000] */ - {0xf191, 0x00e592ad}, /* U+54AD [2000] */ - {0xf192, 0x00e592ae}, /* U+54AE [2000] */ - {0xf193, 0x00e592b7}, /* U+54B7 [2000] */ - {0xf194, 0x00e592ba}, /* U+54BA [2000] */ - {0xf195, 0x00e592bf}, /* U+54BF [2000] */ - {0xf196, 0x00e59383}, /* U+54C3 [2000] */ + {0xf17c, 0xe3959d}, /* U+355D [2000] */ + {0xf17d, 0xe3959e}, /* U+355E [2000] */ + {0xf17e, 0xe58f95}, /* U+53D5 [2000] */ + {0xf180, 0xe58f9a}, /* U+53DA [2000] */ + {0xf181, 0xe395a3}, /* U+3563 [2000] */ + {0xf182, 0xe58fb4}, /* U+53F4 [2000] */ + {0xf183, 0xe58fb5}, /* U+53F5 [2000] */ + {0xf184, 0xe59195}, /* U+5455 [2000] */ + {0xf185, 0xe590a4}, /* U+5424 [2000] */ + {0xf186, 0xe590a8}, /* U+5428 [2000] */ + {0xf187, 0xe395ae}, /* U+356E [2000] */ + {0xf188, 0xe59183}, /* U+5443 [2000] */ + {0xf189, 0xe591a2}, /* U+5462 [2000] */ + {0xf18a, 0xe591a6}, /* U+5466 [2000] */ + {0xf18b, 0xe591ac}, /* U+546C [2000] */ + {0xf18c, 0xe5928a}, /* U+548A [2000] */ + {0xf18d, 0xe5928d}, /* U+548D [2000] */ + {0xf18e, 0xe59295}, /* U+5495 [2000] */ + {0xf18f, 0xe592a0}, /* U+54A0 [2000] */ + {0xf190, 0xe592a6}, /* U+54A6 [2000] */ + {0xf191, 0xe592ad}, /* U+54AD [2000] */ + {0xf192, 0xe592ae}, /* U+54AE [2000] */ + {0xf193, 0xe592b7}, /* U+54B7 [2000] */ + {0xf194, 0xe592ba}, /* U+54BA [2000] */ + {0xf195, 0xe592bf}, /* U+54BF [2000] */ + {0xf196, 0xe59383}, /* U+54C3 [2000] */ {0xf197, 0xf0a0b585}, /* U+20D45 [2000] [Unicode3.1] */ - {0xf198, 0x00e593ac}, /* U+54EC [2000] */ - {0xf199, 0x00e593af}, /* U+54EF [2000] */ - {0xf19a, 0x00e593b1}, /* U+54F1 [2000] */ - {0xf19b, 0x00e593b3}, /* U+54F3 [2000] */ - {0xf19c, 0x00e59480}, /* U+5500 [2000] */ - {0xf19d, 0x00e59481}, /* U+5501 [2000] */ - {0xf19e, 0x00e59489}, /* U+5509 [2000] */ - {0xf19f, 0x00e594bc}, /* U+553C [2000] */ - {0xf1a0, 0x00e59581}, /* U+5541 [2000] */ - {0xf1a1, 0x00e396a6}, /* U+35A6 [2000] */ - {0xf1a2, 0x00e59587}, /* U+5547 [2000] */ - {0xf1a3, 0x00e5958a}, /* U+554A [2000] */ - {0xf1a4, 0x00e396a8}, /* U+35A8 [2000] */ - {0xf1a5, 0x00e595a0}, /* U+5560 [2000] */ - {0xf1a6, 0x00e595a1}, /* U+5561 [2000] */ - {0xf1a7, 0x00e595a4}, /* U+5564 [2000] */ + {0xf198, 0xe593ac}, /* U+54EC [2000] */ + {0xf199, 0xe593af}, /* U+54EF [2000] */ + {0xf19a, 0xe593b1}, /* U+54F1 [2000] */ + {0xf19b, 0xe593b3}, /* U+54F3 [2000] */ + {0xf19c, 0xe59480}, /* U+5500 [2000] */ + {0xf19d, 0xe59481}, /* U+5501 [2000] */ + {0xf19e, 0xe59489}, /* U+5509 [2000] */ + {0xf19f, 0xe594bc}, /* U+553C [2000] */ + {0xf1a0, 0xe59581}, /* U+5541 [2000] */ + {0xf1a1, 0xe396a6}, /* U+35A6 [2000] */ + {0xf1a2, 0xe59587}, /* U+5547 [2000] */ + {0xf1a3, 0xe5958a}, /* U+554A [2000] */ + {0xf1a4, 0xe396a8}, /* U+35A8 [2000] */ + {0xf1a5, 0xe595a0}, /* U+5560 [2000] */ + {0xf1a6, 0xe595a1}, /* U+5561 [2000] */ + {0xf1a7, 0xe595a4}, /* U+5564 [2000] */ {0xf1a8, 0xf0a0b7a1}, /* U+20DE1 [2000] [Unicode3.1] */ - {0xf1a9, 0x00e595bd}, /* U+557D [2000] */ - {0xf1aa, 0x00e59682}, /* U+5582 [2000] */ - {0xf1ab, 0x00e59688}, /* U+5588 [2000] */ - {0xf1ac, 0x00e59691}, /* U+5591 [2000] */ - {0xf1ad, 0x00e39785}, /* U+35C5 [2000] */ - {0xf1ae, 0x00e59792}, /* U+55D2 [2000] */ + {0xf1a9, 0xe595bd}, /* U+557D [2000] */ + {0xf1aa, 0xe59682}, /* U+5582 [2000] */ + {0xf1ab, 0xe59688}, /* U+5588 [2000] */ + {0xf1ac, 0xe59691}, /* U+5591 [2000] */ + {0xf1ad, 0xe39785}, /* U+35C5 [2000] */ + {0xf1ae, 0xe59792}, /* U+55D2 [2000] */ {0xf1af, 0xf0a0ba95}, /* U+20E95 [2000] [Unicode3.1] */ {0xf1b0, 0xf0a0b9ad}, /* U+20E6D [2000] [Unicode3.1] */ - {0xf1b1, 0x00e596bf}, /* U+55BF [2000] */ - {0xf1b2, 0x00e59789}, /* U+55C9 [2000] */ - {0xf1b3, 0x00e5978c}, /* U+55CC [2000] */ - {0xf1b4, 0x00e59791}, /* U+55D1 [2000] */ - {0xf1b5, 0x00e5979d}, /* U+55DD [2000] */ - {0xf1b6, 0x00e3979a}, /* U+35DA [2000] */ - {0xf1b7, 0x00e597a2}, /* U+55E2 [2000] */ + {0xf1b1, 0xe596bf}, /* U+55BF [2000] */ + {0xf1b2, 0xe59789}, /* U+55C9 [2000] */ + {0xf1b3, 0xe5978c}, /* U+55CC [2000] */ + {0xf1b4, 0xe59791}, /* U+55D1 [2000] */ + {0xf1b5, 0xe5979d}, /* U+55DD [2000] */ + {0xf1b6, 0xe3979a}, /* U+35DA [2000] */ + {0xf1b7, 0xe597a2}, /* U+55E2 [2000] */ {0xf1b8, 0xf0a0b9a4}, /* U+20E64 [2000] [Unicode3.1] */ - {0xf1b9, 0x00e597a9}, /* U+55E9 [2000] */ - {0xf1ba, 0x00e598a8}, /* U+5628 [2000] */ + {0xf1b9, 0xe597a9}, /* U+55E9 [2000] */ + {0xf1ba, 0xe598a8}, /* U+5628 [2000] */ {0xf1bb, 0xf0a0bd9f}, /* U+20F5F [2000] [Unicode3.1] */ - {0xf1bc, 0x00e59887}, /* U+5607 [2000] */ - {0xf1bd, 0x00e59890}, /* U+5610 [2000] */ - {0xf1be, 0x00e598b0}, /* U+5630 [2000] */ - {0xf1bf, 0x00e598b7}, /* U+5637 [2000] */ - {0xf1c0, 0x00e397b4}, /* U+35F4 [2000] */ - {0xf1c1, 0x00e598bd}, /* U+563D [2000] */ - {0xf1c2, 0x00e598bf}, /* U+563F [2000] */ - {0xf1c3, 0x00e59980}, /* U+5640 [2000] */ - {0xf1c4, 0x00e59987}, /* U+5647 [2000] */ - {0xf1c5, 0x00e5999e}, /* U+565E [2000] */ - {0xf1c6, 0x00e599a0}, /* U+5660 [2000] */ - {0xf1c7, 0x00e599ad}, /* U+566D [2000] */ - {0xf1c8, 0x00e39885}, /* U+3605 [2000] */ - {0xf1c9, 0x00e59a88}, /* U+5688 [2000] */ - {0xf1ca, 0x00e59a8c}, /* U+568C [2000] */ - {0xf1cb, 0x00e59a95}, /* U+5695 [2000] */ - {0xf1cc, 0x00e59a9a}, /* U+569A [2000] */ - {0xf1cd, 0x00e59a9d}, /* U+569D [2000] */ - {0xf1ce, 0x00e59aa8}, /* U+56A8 [2000] */ - {0xf1cf, 0x00e59aad}, /* U+56AD [2000] */ - {0xf1d0, 0x00e59ab2}, /* U+56B2 [2000] */ - {0xf1d1, 0x00e59b85}, /* U+56C5 [2000] */ - {0xf1d2, 0x00e59b8d}, /* U+56CD [2000] */ - {0xf1d3, 0x00e59b9f}, /* U+56DF [2000] */ - {0xf1d4, 0x00e59ba8}, /* U+56E8 [2000] */ - {0xf1d5, 0x00e59bb6}, /* U+56F6 [2000] */ - {0xf1d6, 0x00e59bb7}, /* U+56F7 [2000] */ + {0xf1bc, 0xe59887}, /* U+5607 [2000] */ + {0xf1bd, 0xe59890}, /* U+5610 [2000] */ + {0xf1be, 0xe598b0}, /* U+5630 [2000] */ + {0xf1bf, 0xe598b7}, /* U+5637 [2000] */ + {0xf1c0, 0xe397b4}, /* U+35F4 [2000] */ + {0xf1c1, 0xe598bd}, /* U+563D [2000] */ + {0xf1c2, 0xe598bf}, /* U+563F [2000] */ + {0xf1c3, 0xe59980}, /* U+5640 [2000] */ + {0xf1c4, 0xe59987}, /* U+5647 [2000] */ + {0xf1c5, 0xe5999e}, /* U+565E [2000] */ + {0xf1c6, 0xe599a0}, /* U+5660 [2000] */ + {0xf1c7, 0xe599ad}, /* U+566D [2000] */ + {0xf1c8, 0xe39885}, /* U+3605 [2000] */ + {0xf1c9, 0xe59a88}, /* U+5688 [2000] */ + {0xf1ca, 0xe59a8c}, /* U+568C [2000] */ + {0xf1cb, 0xe59a95}, /* U+5695 [2000] */ + {0xf1cc, 0xe59a9a}, /* U+569A [2000] */ + {0xf1cd, 0xe59a9d}, /* U+569D [2000] */ + {0xf1ce, 0xe59aa8}, /* U+56A8 [2000] */ + {0xf1cf, 0xe59aad}, /* U+56AD [2000] */ + {0xf1d0, 0xe59ab2}, /* U+56B2 [2000] */ + {0xf1d1, 0xe59b85}, /* U+56C5 [2000] */ + {0xf1d2, 0xe59b8d}, /* U+56CD [2000] */ + {0xf1d3, 0xe59b9f}, /* U+56DF [2000] */ + {0xf1d4, 0xe59ba8}, /* U+56E8 [2000] */ + {0xf1d5, 0xe59bb6}, /* U+56F6 [2000] */ + {0xf1d6, 0xe59bb7}, /* U+56F7 [2000] */ {0xf1d7, 0xf0a18881}, /* U+21201 [2000] [Unicode3.1] */ - {0xf1d8, 0x00e59c95}, /* U+5715 [2000] */ - {0xf1d9, 0x00e59ca3}, /* U+5723 [2000] */ + {0xf1d8, 0xe59c95}, /* U+5715 [2000] */ + {0xf1d9, 0xe59ca3}, /* U+5723 [2000] */ {0xf1da, 0xf0a18995}, /* U+21255 [2000] [Unicode3.1] */ - {0xf1db, 0x00e59ca9}, /* U+5729 [2000] */ + {0xf1db, 0xe59ca9}, /* U+5729 [2000] */ {0xf1dc, 0xf0a189bb}, /* U+2127B [2000] [Unicode3.1] */ - {0xf1dd, 0x00e59d85}, /* U+5745 [2000] */ - {0xf1de, 0x00e59d86}, /* U+5746 [2000] */ - {0xf1df, 0x00e59d8c}, /* U+574C [2000] */ - {0xf1e0, 0x00e59d8d}, /* U+574D [2000] */ + {0xf1dd, 0xe59d85}, /* U+5745 [2000] */ + {0xf1de, 0xe59d86}, /* U+5746 [2000] */ + {0xf1df, 0xe59d8c}, /* U+574C [2000] */ + {0xf1e0, 0xe59d8d}, /* U+574D [2000] */ {0xf1e1, 0xf0a189b4}, /* U+21274 [2000] [Unicode3.1] */ - {0xf1e2, 0x00e59da8}, /* U+5768 [2000] */ - {0xf1e3, 0x00e59daf}, /* U+576F [2000] */ - {0xf1e4, 0x00e59db3}, /* U+5773 [2000] */ - {0xf1e5, 0x00e59db4}, /* U+5774 [2000] */ - {0xf1e6, 0x00e59db5}, /* U+5775 [2000] */ - {0xf1e7, 0x00e59dbb}, /* U+577B [2000] */ + {0xf1e2, 0xe59da8}, /* U+5768 [2000] */ + {0xf1e3, 0xe59daf}, /* U+576F [2000] */ + {0xf1e4, 0xe59db3}, /* U+5773 [2000] */ + {0xf1e5, 0xe59db4}, /* U+5774 [2000] */ + {0xf1e6, 0xe59db5}, /* U+5775 [2000] */ + {0xf1e7, 0xe59dbb}, /* U+577B [2000] */ {0xf1e8, 0xf0a18ba4}, /* U+212E4 [2000] [Unicode3.1] */ {0xf1e9, 0xf0a18b97}, /* U+212D7 [2000] [Unicode3.1] */ - {0xf1ea, 0x00e59eac}, /* U+57AC [2000] */ - {0xf1eb, 0x00e59e9a}, /* U+579A [2000] */ - {0xf1ec, 0x00e59e9d}, /* U+579D [2000] */ - {0xf1ed, 0x00e59e9e}, /* U+579E [2000] */ - {0xf1ee, 0x00e59ea8}, /* U+57A8 [2000] */ - {0xf1ef, 0x00e59f97}, /* U+57D7 [2000] */ + {0xf1ea, 0xe59eac}, /* U+57AC [2000] */ + {0xf1eb, 0xe59e9a}, /* U+579A [2000] */ + {0xf1ec, 0xe59e9d}, /* U+579D [2000] */ + {0xf1ed, 0xe59e9e}, /* U+579E [2000] */ + {0xf1ee, 0xe59ea8}, /* U+57A8 [2000] */ + {0xf1ef, 0xe59f97}, /* U+57D7 [2000] */ {0xf1f0, 0xf0a18bbd}, /* U+212FD [2000] [Unicode3.1] */ - {0xf1f1, 0x00e59f8c}, /* U+57CC [2000] */ + {0xf1f1, 0xe59f8c}, /* U+57CC [2000] */ {0xf1f2, 0xf0a18cb6}, /* U+21336 [2000] [Unicode3.1] */ {0xf1f3, 0xf0a18d84}, /* U+21344 [2000] [Unicode3.1] */ - {0xf1f4, 0x00e59f9e}, /* U+57DE [2000] */ - {0xf1f5, 0x00e59fa6}, /* U+57E6 [2000] */ - {0xf1f6, 0x00e59fb0}, /* U+57F0 [2000] */ - {0xf1f7, 0x00e3998a}, /* U+364A [2000] */ - {0xf1f8, 0x00e59fb8}, /* U+57F8 [2000] */ - {0xf1f9, 0x00e59fbb}, /* U+57FB [2000] */ - {0xf1fa, 0x00e59fbd}, /* U+57FD [2000] */ - {0xf1fb, 0x00e5a084}, /* U+5804 [2000] */ - {0xf1fc, 0x00e5a09e}, /* U+581E [2000] */ - {0xf240, 0x00e5a0a0}, /* U+5820 [2000] */ - {0xf241, 0x00e5a0a7}, /* U+5827 [2000] */ - {0xf242, 0x00e5a0b2}, /* U+5832 [2000] */ - {0xf243, 0x00e5a0b9}, /* U+5839 [2000] */ + {0xf1f4, 0xe59f9e}, /* U+57DE [2000] */ + {0xf1f5, 0xe59fa6}, /* U+57E6 [2000] */ + {0xf1f6, 0xe59fb0}, /* U+57F0 [2000] */ + {0xf1f7, 0xe3998a}, /* U+364A [2000] */ + {0xf1f8, 0xe59fb8}, /* U+57F8 [2000] */ + {0xf1f9, 0xe59fbb}, /* U+57FB [2000] */ + {0xf1fa, 0xe59fbd}, /* U+57FD [2000] */ + {0xf1fb, 0xe5a084}, /* U+5804 [2000] */ + {0xf1fc, 0xe5a09e}, /* U+581E [2000] */ + {0xf240, 0xe5a0a0}, /* U+5820 [2000] */ + {0xf241, 0xe5a0a7}, /* U+5827 [2000] */ + {0xf242, 0xe5a0b2}, /* U+5832 [2000] */ + {0xf243, 0xe5a0b9}, /* U+5839 [2000] */ {0xf244, 0xf0a18f84}, /* U+213C4 [2000] [Unicode3.1] */ - {0xf245, 0x00e5a189}, /* U+5849 [2000] */ - {0xf246, 0x00e5a18c}, /* U+584C [2000] */ - {0xf247, 0x00e5a1a7}, /* U+5867 [2000] */ - {0xf248, 0x00e5a28a}, /* U+588A [2000] */ - {0xf249, 0x00e5a28b}, /* U+588B [2000] */ - {0xf24a, 0x00e5a28d}, /* U+588D [2000] */ - {0xf24b, 0x00e5a28f}, /* U+588F [2000] */ - {0xf24c, 0x00e5a290}, /* U+5890 [2000] */ - {0xf24d, 0x00e5a294}, /* U+5894 [2000] */ - {0xf24e, 0x00e5a29d}, /* U+589D [2000] */ - {0xf24f, 0x00e5a2aa}, /* U+58AA [2000] */ - {0xf250, 0x00e5a2b1}, /* U+58B1 [2000] */ + {0xf245, 0xe5a189}, /* U+5849 [2000] */ + {0xf246, 0xe5a18c}, /* U+584C [2000] */ + {0xf247, 0xe5a1a7}, /* U+5867 [2000] */ + {0xf248, 0xe5a28a}, /* U+588A [2000] */ + {0xf249, 0xe5a28b}, /* U+588B [2000] */ + {0xf24a, 0xe5a28d}, /* U+588D [2000] */ + {0xf24b, 0xe5a28f}, /* U+588F [2000] */ + {0xf24c, 0xe5a290}, /* U+5890 [2000] */ + {0xf24d, 0xe5a294}, /* U+5894 [2000] */ + {0xf24e, 0xe5a29d}, /* U+589D [2000] */ + {0xf24f, 0xe5a2aa}, /* U+58AA [2000] */ + {0xf250, 0xe5a2b1}, /* U+58B1 [2000] */ {0xf251, 0xf0a191ad}, /* U+2146D [2000] [Unicode3.1] */ - {0xf252, 0x00e5a383}, /* U+58C3 [2000] */ - {0xf253, 0x00e5a38d}, /* U+58CD [2000] */ - {0xf254, 0x00e5a3a2}, /* U+58E2 [2000] */ - {0xf255, 0x00e5a3b3}, /* U+58F3 [2000] */ - {0xf256, 0x00e5a3b4}, /* U+58F4 [2000] */ - {0xf257, 0x00e5a485}, /* U+5905 [2000] */ - {0xf258, 0x00e5a486}, /* U+5906 [2000] */ - {0xf259, 0x00e5a48b}, /* U+590B [2000] */ - {0xf25a, 0x00e5a48d}, /* U+590D [2000] */ - {0xf25b, 0x00e5a494}, /* U+5914 [2000] */ - {0xf25c, 0x00e5a4a4}, /* U+5924 [2000] */ + {0xf252, 0xe5a383}, /* U+58C3 [2000] */ + {0xf253, 0xe5a38d}, /* U+58CD [2000] */ + {0xf254, 0xe5a3a2}, /* U+58E2 [2000] */ + {0xf255, 0xe5a3b3}, /* U+58F3 [2000] */ + {0xf256, 0xe5a3b4}, /* U+58F4 [2000] */ + {0xf257, 0xe5a485}, /* U+5905 [2000] */ + {0xf258, 0xe5a486}, /* U+5906 [2000] */ + {0xf259, 0xe5a48b}, /* U+590B [2000] */ + {0xf25a, 0xe5a48d}, /* U+590D [2000] */ + {0xf25b, 0xe5a494}, /* U+5914 [2000] */ + {0xf25c, 0xe5a4a4}, /* U+5924 [2000] */ {0xf25d, 0xf0a19797}, /* U+215D7 [2000] [Unicode3.1] */ - {0xf25e, 0x00e39a91}, /* U+3691 [2000] */ - {0xf25f, 0x00e5a4bd}, /* U+593D [2000] */ - {0xf260, 0x00e39a99}, /* U+3699 [2000] */ - {0xf261, 0x00e5a586}, /* U+5946 [2000] */ - {0xf262, 0x00e39a96}, /* U+3696 [2000] */ + {0xf25e, 0xe39a91}, /* U+3691 [2000] */ + {0xf25f, 0xe5a4bd}, /* U+593D [2000] */ + {0xf260, 0xe39a99}, /* U+3699 [2000] */ + {0xf261, 0xe5a586}, /* U+5946 [2000] */ + {0xf262, 0xe39a96}, /* U+3696 [2000] */ {0xf263, 0xf0a6b0a9}, /* U+26C29 [2000] [Unicode3.1] */ - {0xf264, 0x00e5a59b}, /* U+595B [2000] */ - {0xf265, 0x00e5a59f}, /* U+595F [2000] */ + {0xf264, 0xe5a59b}, /* U+595B [2000] */ + {0xf265, 0xe5a59f}, /* U+595F [2000] */ {0xf266, 0xf0a19987}, /* U+21647 [2000] [Unicode3.1] */ - {0xf267, 0x00e5a5b5}, /* U+5975 [2000] */ - {0xf268, 0x00e5a5b6}, /* U+5976 [2000] */ - {0xf269, 0x00e5a5bc}, /* U+597C [2000] */ - {0xf26a, 0x00e5a69f}, /* U+599F [2000] */ - {0xf26b, 0x00e5a6ae}, /* U+59AE [2000] */ - {0xf26c, 0x00e5a6bc}, /* U+59BC [2000] */ - {0xf26d, 0x00e5a788}, /* U+59C8 [2000] */ - {0xf26e, 0x00e5a78d}, /* U+59CD [2000] */ - {0xf26f, 0x00e5a79e}, /* U+59DE [2000] */ - {0xf270, 0x00e5a7a3}, /* U+59E3 [2000] */ - {0xf271, 0x00e5a7a4}, /* U+59E4 [2000] */ - {0xf272, 0x00e5a7a7}, /* U+59E7 [2000] */ - {0xf273, 0x00e5a7ae}, /* U+59EE [2000] */ + {0xf267, 0xe5a5b5}, /* U+5975 [2000] */ + {0xf268, 0xe5a5b6}, /* U+5976 [2000] */ + {0xf269, 0xe5a5bc}, /* U+597C [2000] */ + {0xf26a, 0xe5a69f}, /* U+599F [2000] */ + {0xf26b, 0xe5a6ae}, /* U+59AE [2000] */ + {0xf26c, 0xe5a6bc}, /* U+59BC [2000] */ + {0xf26d, 0xe5a788}, /* U+59C8 [2000] */ + {0xf26e, 0xe5a78d}, /* U+59CD [2000] */ + {0xf26f, 0xe5a79e}, /* U+59DE [2000] */ + {0xf270, 0xe5a7a3}, /* U+59E3 [2000] */ + {0xf271, 0xe5a7a4}, /* U+59E4 [2000] */ + {0xf272, 0xe5a7a7}, /* U+59E7 [2000] */ + {0xf273, 0xe5a7ae}, /* U+59EE [2000] */ {0xf274, 0xf0a19c86}, /* U+21706 [2000] [Unicode3.1] */ {0xf275, 0xf0a19d82}, /* U+21742 [2000] [Unicode3.1] */ - {0xf276, 0x00e39b8f}, /* U+36CF [2000] */ - {0xf277, 0x00e5a88c}, /* U+5A0C [2000] */ - {0xf278, 0x00e5a88d}, /* U+5A0D [2000] */ - {0xf279, 0x00e5a897}, /* U+5A17 [2000] */ - {0xf27a, 0x00e5a8a7}, /* U+5A27 [2000] */ - {0xf27b, 0x00e5a8ad}, /* U+5A2D [2000] */ - {0xf27c, 0x00e5a995}, /* U+5A55 [2000] */ - {0xf27d, 0x00e5a9a5}, /* U+5A65 [2000] */ - {0xf27e, 0x00e5a9ba}, /* U+5A7A [2000] */ - {0xf280, 0x00e5aa8b}, /* U+5A8B [2000] */ - {0xf281, 0x00e5aa9c}, /* U+5A9C [2000] */ - {0xf282, 0x00e5aa9f}, /* U+5A9F [2000] */ - {0xf283, 0x00e5aaa0}, /* U+5AA0 [2000] */ - {0xf284, 0x00e5aaa2}, /* U+5AA2 [2000] */ - {0xf285, 0x00e5aab1}, /* U+5AB1 [2000] */ - {0xf286, 0x00e5aab3}, /* U+5AB3 [2000] */ - {0xf287, 0x00e5aab5}, /* U+5AB5 [2000] */ - {0xf288, 0x00e5aaba}, /* U+5ABA [2000] */ - {0xf289, 0x00e5aabf}, /* U+5ABF [2000] */ - {0xf28a, 0x00e5ab9a}, /* U+5ADA [2000] */ - {0xf28b, 0x00e5ab9c}, /* U+5ADC [2000] */ - {0xf28c, 0x00e5aba0}, /* U+5AE0 [2000] */ - {0xf28d, 0x00e5aba5}, /* U+5AE5 [2000] */ - {0xf28e, 0x00e5abb0}, /* U+5AF0 [2000] */ - {0xf28f, 0x00e5abae}, /* U+5AEE [2000] */ - {0xf290, 0x00e5abb5}, /* U+5AF5 [2000] */ - {0xf291, 0x00e5ac80}, /* U+5B00 [2000] */ - {0xf292, 0x00e5ac88}, /* U+5B08 [2000] */ - {0xf293, 0x00e5ac97}, /* U+5B17 [2000] */ - {0xf294, 0x00e5acb4}, /* U+5B34 [2000] */ - {0xf295, 0x00e5acad}, /* U+5B2D [2000] */ - {0xf296, 0x00e5ad8c}, /* U+5B4C [2000] */ - {0xf297, 0x00e5ad92}, /* U+5B52 [2000] */ - {0xf298, 0x00e5ada8}, /* U+5B68 [2000] */ - {0xf299, 0x00e5adaf}, /* U+5B6F [2000] */ - {0xf29a, 0x00e5adbc}, /* U+5B7C [2000] */ - {0xf29b, 0x00e5adbf}, /* U+5B7F [2000] */ - {0xf29c, 0x00e5ae81}, /* U+5B81 [2000] */ - {0xf29d, 0x00e5ae84}, /* U+5B84 [2000] */ + {0xf276, 0xe39b8f}, /* U+36CF [2000] */ + {0xf277, 0xe5a88c}, /* U+5A0C [2000] */ + {0xf278, 0xe5a88d}, /* U+5A0D [2000] */ + {0xf279, 0xe5a897}, /* U+5A17 [2000] */ + {0xf27a, 0xe5a8a7}, /* U+5A27 [2000] */ + {0xf27b, 0xe5a8ad}, /* U+5A2D [2000] */ + {0xf27c, 0xe5a995}, /* U+5A55 [2000] */ + {0xf27d, 0xe5a9a5}, /* U+5A65 [2000] */ + {0xf27e, 0xe5a9ba}, /* U+5A7A [2000] */ + {0xf280, 0xe5aa8b}, /* U+5A8B [2000] */ + {0xf281, 0xe5aa9c}, /* U+5A9C [2000] */ + {0xf282, 0xe5aa9f}, /* U+5A9F [2000] */ + {0xf283, 0xe5aaa0}, /* U+5AA0 [2000] */ + {0xf284, 0xe5aaa2}, /* U+5AA2 [2000] */ + {0xf285, 0xe5aab1}, /* U+5AB1 [2000] */ + {0xf286, 0xe5aab3}, /* U+5AB3 [2000] */ + {0xf287, 0xe5aab5}, /* U+5AB5 [2000] */ + {0xf288, 0xe5aaba}, /* U+5ABA [2000] */ + {0xf289, 0xe5aabf}, /* U+5ABF [2000] */ + {0xf28a, 0xe5ab9a}, /* U+5ADA [2000] */ + {0xf28b, 0xe5ab9c}, /* U+5ADC [2000] */ + {0xf28c, 0xe5aba0}, /* U+5AE0 [2000] */ + {0xf28d, 0xe5aba5}, /* U+5AE5 [2000] */ + {0xf28e, 0xe5abb0}, /* U+5AF0 [2000] */ + {0xf28f, 0xe5abae}, /* U+5AEE [2000] */ + {0xf290, 0xe5abb5}, /* U+5AF5 [2000] */ + {0xf291, 0xe5ac80}, /* U+5B00 [2000] */ + {0xf292, 0xe5ac88}, /* U+5B08 [2000] */ + {0xf293, 0xe5ac97}, /* U+5B17 [2000] */ + {0xf294, 0xe5acb4}, /* U+5B34 [2000] */ + {0xf295, 0xe5acad}, /* U+5B2D [2000] */ + {0xf296, 0xe5ad8c}, /* U+5B4C [2000] */ + {0xf297, 0xe5ad92}, /* U+5B52 [2000] */ + {0xf298, 0xe5ada8}, /* U+5B68 [2000] */ + {0xf299, 0xe5adaf}, /* U+5B6F [2000] */ + {0xf29a, 0xe5adbc}, /* U+5B7C [2000] */ + {0xf29b, 0xe5adbf}, /* U+5B7F [2000] */ + {0xf29c, 0xe5ae81}, /* U+5B81 [2000] */ + {0xf29d, 0xe5ae84}, /* U+5B84 [2000] */ {0xf29e, 0xf0a1a783}, /* U+219C3 [2000] [Unicode3.1] */ - {0xf29f, 0x00e5b9ae}, /* U+5E6E [2000] */ + {0xf29f, 0xe5b9ae}, /* U+5E6E [2000] */ {0xf2a0, 0xf0a285bb}, /* U+2217B [2000] [Unicode3.1] */ - {0xf2a1, 0x00e5baa5}, /* U+5EA5 [2000] */ - {0xf2a2, 0x00e5baaa}, /* U+5EAA [2000] */ - {0xf2a3, 0x00e5baac}, /* U+5EAC [2000] */ - {0xf2a4, 0x00e5bab9}, /* U+5EB9 [2000] */ - {0xf2a5, 0x00e5babf}, /* U+5EBF [2000] */ - {0xf2a6, 0x00e5bb86}, /* U+5EC6 [2000] */ - {0xf2a7, 0x00e5bb92}, /* U+5ED2 [2000] */ - {0xf2a8, 0x00e5bb99}, /* U+5ED9 [2000] */ + {0xf2a1, 0xe5baa5}, /* U+5EA5 [2000] */ + {0xf2a2, 0xe5baaa}, /* U+5EAA [2000] */ + {0xf2a3, 0xe5baac}, /* U+5EAC [2000] */ + {0xf2a4, 0xe5bab9}, /* U+5EB9 [2000] */ + {0xf2a5, 0xe5babf}, /* U+5EBF [2000] */ + {0xf2a6, 0xe5bb86}, /* U+5EC6 [2000] */ + {0xf2a7, 0xe5bb92}, /* U+5ED2 [2000] */ + {0xf2a8, 0xe5bb99}, /* U+5ED9 [2000] */ {0xf2a9, 0xf0a28c9e}, /* U+2231E [2000] [Unicode3.1] */ - {0xf2aa, 0x00e5bbbd}, /* U+5EFD [2000] */ - {0xf2ab, 0x00e5bc88}, /* U+5F08 [2000] */ - {0xf2ac, 0x00e5bc8e}, /* U+5F0E [2000] */ - {0xf2ad, 0x00e5bc9c}, /* U+5F1C [2000] */ + {0xf2aa, 0xe5bbbd}, /* U+5EFD [2000] */ + {0xf2ab, 0xe5bc88}, /* U+5F08 [2000] */ + {0xf2ac, 0xe5bc8e}, /* U+5F0E [2000] */ + {0xf2ad, 0xe5bc9c}, /* U+5F1C [2000] */ {0xf2ae, 0xf0a28ead}, /* U+223AD [2000] [Unicode3.1] */ - {0xf2af, 0x00e5bc9e}, /* U+5F1E [2000] */ - {0xf2b0, 0x00e5bd87}, /* U+5F47 [2000] */ - {0xf2b1, 0x00e5bda3}, /* U+5F63 [2000] */ - {0xf2b2, 0x00e5bdb2}, /* U+5F72 [2000] */ - {0xf2b3, 0x00e5bdbe}, /* U+5F7E [2000] */ - {0xf2b4, 0x00e5be8f}, /* U+5F8F [2000] */ - {0xf2b5, 0x00e5bea2}, /* U+5FA2 [2000] */ - {0xf2b6, 0x00e5bea4}, /* U+5FA4 [2000] */ - {0xf2b7, 0x00e5beb8}, /* U+5FB8 [2000] */ - {0xf2b8, 0x00e5bf84}, /* U+5FC4 [2000] */ - {0xf2b9, 0x00e3a3ba}, /* U+38FA [2000] */ - {0xf2ba, 0x00e5bf87}, /* U+5FC7 [2000] */ - {0xf2bb, 0x00e5bf8b}, /* U+5FCB [2000] */ - {0xf2bc, 0x00e5bf92}, /* U+5FD2 [2000] */ - {0xf2bd, 0x00e5bf93}, /* U+5FD3 [2000] */ - {0xf2be, 0x00e5bf94}, /* U+5FD4 [2000] */ - {0xf2bf, 0x00e5bfa2}, /* U+5FE2 [2000] */ - {0xf2c0, 0x00e5bfae}, /* U+5FEE [2000] */ - {0xf2c1, 0x00e5bfaf}, /* U+5FEF [2000] */ - {0xf2c2, 0x00e5bfb3}, /* U+5FF3 [2000] */ - {0xf2c3, 0x00e5bfbc}, /* U+5FFC [2000] */ - {0xf2c4, 0x00e3a497}, /* U+3917 [2000] */ - {0xf2c5, 0x00e68097}, /* U+6017 [2000] */ - {0xf2c6, 0x00e680a2}, /* U+6022 [2000] */ - {0xf2c7, 0x00e680a4}, /* U+6024 [2000] */ - {0xf2c8, 0x00e3a49a}, /* U+391A [2000] */ - {0xf2c9, 0x00e6818c}, /* U+604C [2000] */ - {0xf2ca, 0x00e681bf}, /* U+607F [2000] */ - {0xf2cb, 0x00e6828a}, /* U+608A [2000] */ - {0xf2cc, 0x00e68295}, /* U+6095 [2000] */ - {0xf2cd, 0x00e682a8}, /* U+60A8 [2000] */ + {0xf2af, 0xe5bc9e}, /* U+5F1E [2000] */ + {0xf2b0, 0xe5bd87}, /* U+5F47 [2000] */ + {0xf2b1, 0xe5bda3}, /* U+5F63 [2000] */ + {0xf2b2, 0xe5bdb2}, /* U+5F72 [2000] */ + {0xf2b3, 0xe5bdbe}, /* U+5F7E [2000] */ + {0xf2b4, 0xe5be8f}, /* U+5F8F [2000] */ + {0xf2b5, 0xe5bea2}, /* U+5FA2 [2000] */ + {0xf2b6, 0xe5bea4}, /* U+5FA4 [2000] */ + {0xf2b7, 0xe5beb8}, /* U+5FB8 [2000] */ + {0xf2b8, 0xe5bf84}, /* U+5FC4 [2000] */ + {0xf2b9, 0xe3a3ba}, /* U+38FA [2000] */ + {0xf2ba, 0xe5bf87}, /* U+5FC7 [2000] */ + {0xf2bb, 0xe5bf8b}, /* U+5FCB [2000] */ + {0xf2bc, 0xe5bf92}, /* U+5FD2 [2000] */ + {0xf2bd, 0xe5bf93}, /* U+5FD3 [2000] */ + {0xf2be, 0xe5bf94}, /* U+5FD4 [2000] */ + {0xf2bf, 0xe5bfa2}, /* U+5FE2 [2000] */ + {0xf2c0, 0xe5bfae}, /* U+5FEE [2000] */ + {0xf2c1, 0xe5bfaf}, /* U+5FEF [2000] */ + {0xf2c2, 0xe5bfb3}, /* U+5FF3 [2000] */ + {0xf2c3, 0xe5bfbc}, /* U+5FFC [2000] */ + {0xf2c4, 0xe3a497}, /* U+3917 [2000] */ + {0xf2c5, 0xe68097}, /* U+6017 [2000] */ + {0xf2c6, 0xe680a2}, /* U+6022 [2000] */ + {0xf2c7, 0xe680a4}, /* U+6024 [2000] */ + {0xf2c8, 0xe3a49a}, /* U+391A [2000] */ + {0xf2c9, 0xe6818c}, /* U+604C [2000] */ + {0xf2ca, 0xe681bf}, /* U+607F [2000] */ + {0xf2cb, 0xe6828a}, /* U+608A [2000] */ + {0xf2cc, 0xe68295}, /* U+6095 [2000] */ + {0xf2cd, 0xe682a8}, /* U+60A8 [2000] */ {0xf2ce, 0xf0a29bb3}, /* U+226F3 [2000] [Unicode3.1] */ - {0xf2cf, 0x00e682b0}, /* U+60B0 [2000] */ - {0xf2d0, 0x00e682b1}, /* U+60B1 [2000] */ - {0xf2d1, 0x00e682be}, /* U+60BE [2000] */ - {0xf2d2, 0x00e68388}, /* U+60C8 [2000] */ - {0xf2d3, 0x00e68399}, /* U+60D9 [2000] */ - {0xf2d4, 0x00e6839b}, /* U+60DB [2000] */ - {0xf2d5, 0x00e683ae}, /* U+60EE [2000] */ - {0xf2d6, 0x00e683b2}, /* U+60F2 [2000] */ - {0xf2d7, 0x00e683b5}, /* U+60F5 [2000] */ - {0xf2d8, 0x00e68490}, /* U+6110 [2000] */ - {0xf2d9, 0x00e68492}, /* U+6112 [2000] */ - {0xf2da, 0x00e68493}, /* U+6113 [2000] */ - {0xf2db, 0x00e68499}, /* U+6119 [2000] */ - {0xf2dc, 0x00e6849e}, /* U+611E [2000] */ - {0xf2dd, 0x00e684ba}, /* U+613A [2000] */ - {0xf2de, 0x00e3a5af}, /* U+396F [2000] */ - {0xf2df, 0x00e68581}, /* U+6141 [2000] */ - {0xf2e0, 0x00e68586}, /* U+6146 [2000] */ - {0xf2e1, 0x00e685a0}, /* U+6160 [2000] */ - {0xf2e2, 0x00e685bc}, /* U+617C [2000] */ + {0xf2cf, 0xe682b0}, /* U+60B0 [2000] */ + {0xf2d0, 0xe682b1}, /* U+60B1 [2000] */ + {0xf2d1, 0xe682be}, /* U+60BE [2000] */ + {0xf2d2, 0xe68388}, /* U+60C8 [2000] */ + {0xf2d3, 0xe68399}, /* U+60D9 [2000] */ + {0xf2d4, 0xe6839b}, /* U+60DB [2000] */ + {0xf2d5, 0xe683ae}, /* U+60EE [2000] */ + {0xf2d6, 0xe683b2}, /* U+60F2 [2000] */ + {0xf2d7, 0xe683b5}, /* U+60F5 [2000] */ + {0xf2d8, 0xe68490}, /* U+6110 [2000] */ + {0xf2d9, 0xe68492}, /* U+6112 [2000] */ + {0xf2da, 0xe68493}, /* U+6113 [2000] */ + {0xf2db, 0xe68499}, /* U+6119 [2000] */ + {0xf2dc, 0xe6849e}, /* U+611E [2000] */ + {0xf2dd, 0xe684ba}, /* U+613A [2000] */ + {0xf2de, 0xe3a5af}, /* U+396F [2000] */ + {0xf2df, 0xe68581}, /* U+6141 [2000] */ + {0xf2e0, 0xe68586}, /* U+6146 [2000] */ + {0xf2e1, 0xe685a0}, /* U+6160 [2000] */ + {0xf2e2, 0xe685bc}, /* U+617C [2000] */ {0xf2e3, 0xf0a2a19b}, /* U+2285B [2000] [Unicode3.1] */ - {0xf2e4, 0x00e68692}, /* U+6192 [2000] */ - {0xf2e5, 0x00e68693}, /* U+6193 [2000] */ - {0xf2e6, 0x00e68697}, /* U+6197 [2000] */ - {0xf2e7, 0x00e68698}, /* U+6198 [2000] */ - {0xf2e8, 0x00e686a5}, /* U+61A5 [2000] */ - {0xf2e9, 0x00e686a8}, /* U+61A8 [2000] */ - {0xf2ea, 0x00e686ad}, /* U+61AD [2000] */ + {0xf2e4, 0xe68692}, /* U+6192 [2000] */ + {0xf2e5, 0xe68693}, /* U+6193 [2000] */ + {0xf2e6, 0xe68697}, /* U+6197 [2000] */ + {0xf2e7, 0xe68698}, /* U+6198 [2000] */ + {0xf2e8, 0xe686a5}, /* U+61A5 [2000] */ + {0xf2e9, 0xe686a8}, /* U+61A8 [2000] */ + {0xf2ea, 0xe686ad}, /* U+61AD [2000] */ {0xf2eb, 0xf0a2a2ab}, /* U+228AB [2000] [Unicode3.1] */ - {0xf2ec, 0x00e68795}, /* U+61D5 [2000] */ - {0xf2ed, 0x00e6879d}, /* U+61DD [2000] */ - {0xf2ee, 0x00e6879f}, /* U+61DF [2000] */ - {0xf2ef, 0x00e687b5}, /* U+61F5 [2000] */ + {0xf2ec, 0xe68795}, /* U+61D5 [2000] */ + {0xf2ed, 0xe6879d}, /* U+61DD [2000] */ + {0xf2ee, 0xe6879f}, /* U+61DF [2000] */ + {0xf2ef, 0xe687b5}, /* U+61F5 [2000] */ {0xf2f0, 0xf0a2a68f}, /* U+2298F [2000] [Unicode3.1] */ - {0xf2f1, 0x00e68895}, /* U+6215 [2000] */ - {0xf2f2, 0x00e688a3}, /* U+6223 [2000] */ - {0xf2f3, 0x00e688a9}, /* U+6229 [2000] */ - {0xf2f4, 0x00e68986}, /* U+6246 [2000] */ - {0xf2f5, 0x00e6898c}, /* U+624C [2000] */ - {0xf2f6, 0x00e68991}, /* U+6251 [2000] */ - {0xf2f7, 0x00e68992}, /* U+6252 [2000] */ - {0xf2f8, 0x00e689a1}, /* U+6261 [2000] */ - {0xf2f9, 0x00e689a4}, /* U+6264 [2000] */ - {0xf2fa, 0x00e689bb}, /* U+627B [2000] */ - {0xf2fb, 0x00e689ad}, /* U+626D [2000] */ - {0xf2fc, 0x00e689b3}, /* U+6273 [2000] */ - {0xf340, 0x00e68a99}, /* U+6299 [2000] */ - {0xf341, 0x00e68aa6}, /* U+62A6 [2000] */ - {0xf342, 0x00e68b95}, /* U+62D5 [2000] */ + {0xf2f1, 0xe68895}, /* U+6215 [2000] */ + {0xf2f2, 0xe688a3}, /* U+6223 [2000] */ + {0xf2f3, 0xe688a9}, /* U+6229 [2000] */ + {0xf2f4, 0xe68986}, /* U+6246 [2000] */ + {0xf2f5, 0xe6898c}, /* U+624C [2000] */ + {0xf2f6, 0xe68991}, /* U+6251 [2000] */ + {0xf2f7, 0xe68992}, /* U+6252 [2000] */ + {0xf2f8, 0xe689a1}, /* U+6261 [2000] */ + {0xf2f9, 0xe689a4}, /* U+6264 [2000] */ + {0xf2fa, 0xe689bb}, /* U+627B [2000] */ + {0xf2fb, 0xe689ad}, /* U+626D [2000] */ + {0xf2fc, 0xe689b3}, /* U+6273 [2000] */ + {0xf340, 0xe68a99}, /* U+6299 [2000] */ + {0xf341, 0xe68aa6}, /* U+62A6 [2000] */ + {0xf342, 0xe68b95}, /* U+62D5 [2000] */ {0xf343, 0xf0a2aab8}, /* U+22AB8 [2000] [Unicode3.1] */ - {0xf344, 0x00e68bbd}, /* U+62FD [2000] */ - {0xf345, 0x00e68c83}, /* U+6303 [2000] */ - {0xf346, 0x00e68c8d}, /* U+630D [2000] */ - {0xf347, 0x00e68c90}, /* U+6310 [2000] */ + {0xf344, 0xe68bbd}, /* U+62FD [2000] */ + {0xf345, 0xe68c83}, /* U+6303 [2000] */ + {0xf346, 0xe68c8d}, /* U+630D [2000] */ + {0xf347, 0xe68c90}, /* U+6310 [2000] */ {0xf348, 0xf0a2ad8f}, /* U+22B4F [2000] [Unicode3.1] */ {0xf349, 0xf0a2ad90}, /* U+22B50 [2000] [Unicode3.1] */ - {0xf34a, 0x00e68cb2}, /* U+6332 [2000] */ - {0xf34b, 0x00e68cb5}, /* U+6335 [2000] */ - {0xf34c, 0x00e68cbb}, /* U+633B [2000] */ - {0xf34d, 0x00e68cbc}, /* U+633C [2000] */ - {0xf34e, 0x00e68d81}, /* U+6341 [2000] */ - {0xf34f, 0x00e68d84}, /* U+6344 [2000] */ - {0xf350, 0x00e68d8e}, /* U+634E [2000] */ + {0xf34a, 0xe68cb2}, /* U+6332 [2000] */ + {0xf34b, 0xe68cb5}, /* U+6335 [2000] */ + {0xf34c, 0xe68cbb}, /* U+633B [2000] */ + {0xf34d, 0xe68cbc}, /* U+633C [2000] */ + {0xf34e, 0xe68d81}, /* U+6341 [2000] */ + {0xf34f, 0xe68d84}, /* U+6344 [2000] */ + {0xf350, 0xe68d8e}, /* U+634E [2000] */ {0xf351, 0xf0a2ad86}, /* U+22B46 [2000] [Unicode3.1] */ - {0xf352, 0x00e68d99}, /* U+6359 [2000] */ + {0xf352, 0xe68d99}, /* U+6359 [2000] */ {0xf353, 0xf0a2b09d}, /* U+22C1D [2000] [Unicode3.1] */ {0xf354, 0xf0a2aea6}, /* U+22BA6 [2000] [Unicode3.1] */ - {0xf355, 0x00e68dac}, /* U+636C [2000] */ - {0xf356, 0x00e68e84}, /* U+6384 [2000] */ - {0xf357, 0x00e68e99}, /* U+6399 [2000] */ + {0xf355, 0xe68dac}, /* U+636C [2000] */ + {0xf356, 0xe68e84}, /* U+6384 [2000] */ + {0xf357, 0xe68e99}, /* U+6399 [2000] */ {0xf358, 0xf0a2b0a4}, /* U+22C24 [2000] [Unicode3.1] */ - {0xf359, 0x00e68e94}, /* U+6394 [2000] */ - {0xf35a, 0x00e68ebd}, /* U+63BD [2000] */ - {0xf35b, 0x00e68fb7}, /* U+63F7 [2000] */ - {0xf35c, 0x00e68f94}, /* U+63D4 [2000] */ - {0xf35d, 0x00e68f95}, /* U+63D5 [2000] */ - {0xf35e, 0x00e68f9c}, /* U+63DC [2000] */ - {0xf35f, 0x00e68fa0}, /* U+63E0 [2000] */ - {0xf360, 0x00e68fab}, /* U+63EB [2000] */ - {0xf361, 0x00e68fac}, /* U+63EC [2000] */ - {0xf362, 0x00e68fb2}, /* U+63F2 [2000] */ - {0xf363, 0x00e69089}, /* U+6409 [2000] */ - {0xf364, 0x00e6909e}, /* U+641E [2000] */ - {0xf365, 0x00e690a5}, /* U+6425 [2000] */ - {0xf366, 0x00e690a9}, /* U+6429 [2000] */ - {0xf367, 0x00e690af}, /* U+642F [2000] */ - {0xf368, 0x00e6919a}, /* U+645A [2000] */ - {0xf369, 0x00e6919b}, /* U+645B [2000] */ - {0xf36a, 0x00e6919d}, /* U+645D [2000] */ - {0xf36b, 0x00e691b3}, /* U+6473 [2000] */ - {0xf36c, 0x00e691bd}, /* U+647D [2000] */ - {0xf36d, 0x00e69287}, /* U+6487 [2000] */ - {0xf36e, 0x00e69291}, /* U+6491 [2000] */ - {0xf36f, 0x00e6929d}, /* U+649D [2000] */ - {0xf370, 0x00e6929f}, /* U+649F [2000] */ - {0xf371, 0x00e6938b}, /* U+64CB [2000] */ - {0xf372, 0x00e6938c}, /* U+64CC [2000] */ - {0xf373, 0x00e69395}, /* U+64D5 [2000] */ - {0xf374, 0x00e69397}, /* U+64D7 [2000] */ + {0xf359, 0xe68e94}, /* U+6394 [2000] */ + {0xf35a, 0xe68ebd}, /* U+63BD [2000] */ + {0xf35b, 0xe68fb7}, /* U+63F7 [2000] */ + {0xf35c, 0xe68f94}, /* U+63D4 [2000] */ + {0xf35d, 0xe68f95}, /* U+63D5 [2000] */ + {0xf35e, 0xe68f9c}, /* U+63DC [2000] */ + {0xf35f, 0xe68fa0}, /* U+63E0 [2000] */ + {0xf360, 0xe68fab}, /* U+63EB [2000] */ + {0xf361, 0xe68fac}, /* U+63EC [2000] */ + {0xf362, 0xe68fb2}, /* U+63F2 [2000] */ + {0xf363, 0xe69089}, /* U+6409 [2000] */ + {0xf364, 0xe6909e}, /* U+641E [2000] */ + {0xf365, 0xe690a5}, /* U+6425 [2000] */ + {0xf366, 0xe690a9}, /* U+6429 [2000] */ + {0xf367, 0xe690af}, /* U+642F [2000] */ + {0xf368, 0xe6919a}, /* U+645A [2000] */ + {0xf369, 0xe6919b}, /* U+645B [2000] */ + {0xf36a, 0xe6919d}, /* U+645D [2000] */ + {0xf36b, 0xe691b3}, /* U+6473 [2000] */ + {0xf36c, 0xe691bd}, /* U+647D [2000] */ + {0xf36d, 0xe69287}, /* U+6487 [2000] */ + {0xf36e, 0xe69291}, /* U+6491 [2000] */ + {0xf36f, 0xe6929d}, /* U+649D [2000] */ + {0xf370, 0xe6929f}, /* U+649F [2000] */ + {0xf371, 0xe6938b}, /* U+64CB [2000] */ + {0xf372, 0xe6938c}, /* U+64CC [2000] */ + {0xf373, 0xe69395}, /* U+64D5 [2000] */ + {0xf374, 0xe69397}, /* U+64D7 [2000] */ {0xf375, 0xf0a2b7a1}, /* U+22DE1 [2000] [Unicode3.1] */ - {0xf376, 0x00e693a4}, /* U+64E4 [2000] */ - {0xf377, 0x00e693a5}, /* U+64E5 [2000] */ - {0xf378, 0x00e693bf}, /* U+64FF [2000] */ - {0xf379, 0x00e69484}, /* U+6504 [2000] */ - {0xf37a, 0x00e3a9ae}, /* U+3A6E [2000] */ - {0xf37b, 0x00e6948f}, /* U+650F [2000] */ - {0xf37c, 0x00e69494}, /* U+6514 [2000] */ - {0xf37d, 0x00e69496}, /* U+6516 [2000] */ - {0xf37e, 0x00e3a9b3}, /* U+3A73 [2000] */ - {0xf380, 0x00e6949e}, /* U+651E [2000] */ - {0xf381, 0x00e694b2}, /* U+6532 [2000] */ - {0xf382, 0x00e69584}, /* U+6544 [2000] */ - {0xf383, 0x00e69594}, /* U+6554 [2000] */ - {0xf384, 0x00e695ab}, /* U+656B [2000] */ - {0xf385, 0x00e695ba}, /* U+657A [2000] */ - {0xf386, 0x00e69681}, /* U+6581 [2000] */ - {0xf387, 0x00e69684}, /* U+6584 [2000] */ - {0xf388, 0x00e69685}, /* U+6585 [2000] */ - {0xf389, 0x00e6968a}, /* U+658A [2000] */ - {0xf38a, 0x00e696b2}, /* U+65B2 [2000] */ - {0xf38b, 0x00e696b5}, /* U+65B5 [2000] */ - {0xf38c, 0x00e696b8}, /* U+65B8 [2000] */ - {0xf38d, 0x00e696bf}, /* U+65BF [2000] */ - {0xf38e, 0x00e69782}, /* U+65C2 [2000] */ - {0xf38f, 0x00e69789}, /* U+65C9 [2000] */ - {0xf390, 0x00e69794}, /* U+65D4 [2000] */ - {0xf391, 0x00e3ab96}, /* U+3AD6 [2000] */ - {0xf392, 0x00e697b2}, /* U+65F2 [2000] */ - {0xf393, 0x00e697b9}, /* U+65F9 [2000] */ - {0xf394, 0x00e697bc}, /* U+65FC [2000] */ - {0xf395, 0x00e69884}, /* U+6604 [2000] */ - {0xf396, 0x00e69888}, /* U+6608 [2000] */ - {0xf397, 0x00e698a1}, /* U+6621 [2000] */ - {0xf398, 0x00e698aa}, /* U+662A [2000] */ - {0xf399, 0x00e69985}, /* U+6645 [2000] */ - {0xf39a, 0x00e69991}, /* U+6651 [2000] */ - {0xf39b, 0x00e6998e}, /* U+664E [2000] */ - {0xf39c, 0x00e3abaa}, /* U+3AEA [2000] */ + {0xf376, 0xe693a4}, /* U+64E4 [2000] */ + {0xf377, 0xe693a5}, /* U+64E5 [2000] */ + {0xf378, 0xe693bf}, /* U+64FF [2000] */ + {0xf379, 0xe69484}, /* U+6504 [2000] */ + {0xf37a, 0xe3a9ae}, /* U+3A6E [2000] */ + {0xf37b, 0xe6948f}, /* U+650F [2000] */ + {0xf37c, 0xe69494}, /* U+6514 [2000] */ + {0xf37d, 0xe69496}, /* U+6516 [2000] */ + {0xf37e, 0xe3a9b3}, /* U+3A73 [2000] */ + {0xf380, 0xe6949e}, /* U+651E [2000] */ + {0xf381, 0xe694b2}, /* U+6532 [2000] */ + {0xf382, 0xe69584}, /* U+6544 [2000] */ + {0xf383, 0xe69594}, /* U+6554 [2000] */ + {0xf384, 0xe695ab}, /* U+656B [2000] */ + {0xf385, 0xe695ba}, /* U+657A [2000] */ + {0xf386, 0xe69681}, /* U+6581 [2000] */ + {0xf387, 0xe69684}, /* U+6584 [2000] */ + {0xf388, 0xe69685}, /* U+6585 [2000] */ + {0xf389, 0xe6968a}, /* U+658A [2000] */ + {0xf38a, 0xe696b2}, /* U+65B2 [2000] */ + {0xf38b, 0xe696b5}, /* U+65B5 [2000] */ + {0xf38c, 0xe696b8}, /* U+65B8 [2000] */ + {0xf38d, 0xe696bf}, /* U+65BF [2000] */ + {0xf38e, 0xe69782}, /* U+65C2 [2000] */ + {0xf38f, 0xe69789}, /* U+65C9 [2000] */ + {0xf390, 0xe69794}, /* U+65D4 [2000] */ + {0xf391, 0xe3ab96}, /* U+3AD6 [2000] */ + {0xf392, 0xe697b2}, /* U+65F2 [2000] */ + {0xf393, 0xe697b9}, /* U+65F9 [2000] */ + {0xf394, 0xe697bc}, /* U+65FC [2000] */ + {0xf395, 0xe69884}, /* U+6604 [2000] */ + {0xf396, 0xe69888}, /* U+6608 [2000] */ + {0xf397, 0xe698a1}, /* U+6621 [2000] */ + {0xf398, 0xe698aa}, /* U+662A [2000] */ + {0xf399, 0xe69985}, /* U+6645 [2000] */ + {0xf39a, 0xe69991}, /* U+6651 [2000] */ + {0xf39b, 0xe6998e}, /* U+664E [2000] */ + {0xf39c, 0xe3abaa}, /* U+3AEA [2000] */ {0xf39d, 0xf0a38783}, /* U+231C3 [2000] [Unicode3.1] */ - {0xf39e, 0x00e69997}, /* U+6657 [2000] */ - {0xf39f, 0x00e6999b}, /* U+665B [2000] */ - {0xf3a0, 0x00e699a3}, /* U+6663 [2000] */ + {0xf39e, 0xe69997}, /* U+6657 [2000] */ + {0xf39f, 0xe6999b}, /* U+665B [2000] */ + {0xf3a0, 0xe699a3}, /* U+6663 [2000] */ {0xf3a1, 0xf0a387b5}, /* U+231F5 [2000] [Unicode3.1] */ {0xf3a2, 0xf0a386b6}, /* U+231B6 [2000] [Unicode3.1] */ - {0xf3a3, 0x00e699aa}, /* U+666A [2000] */ - {0xf3a4, 0x00e699ab}, /* U+666B [2000] */ - {0xf3a5, 0x00e699ac}, /* U+666C [2000] */ - {0xf3a6, 0x00e699ad}, /* U+666D [2000] */ - {0xf3a7, 0x00e699bb}, /* U+667B [2000] */ - {0xf3a8, 0x00e69a80}, /* U+6680 [2000] */ - {0xf3a9, 0x00e69a90}, /* U+6690 [2000] */ - {0xf3aa, 0x00e69a92}, /* U+6692 [2000] */ - {0xf3ab, 0x00e69a99}, /* U+6699 [2000] */ - {0xf3ac, 0x00e3ac8e}, /* U+3B0E [2000] */ - {0xf3ad, 0x00e69aad}, /* U+66AD [2000] */ - {0xf3ae, 0x00e69ab1}, /* U+66B1 [2000] */ - {0xf3af, 0x00e69ab5}, /* U+66B5 [2000] */ - {0xf3b0, 0x00e3ac9a}, /* U+3B1A [2000] */ - {0xf3b1, 0x00e69abf}, /* U+66BF [2000] */ - {0xf3b2, 0x00e3ac9c}, /* U+3B1C [2000] */ - {0xf3b3, 0x00e69bac}, /* U+66EC [2000] */ - {0xf3b4, 0x00e3ab97}, /* U+3AD7 [2000] */ - {0xf3b5, 0x00e69c81}, /* U+6701 [2000] */ - {0xf3b6, 0x00e69c85}, /* U+6705 [2000] */ - {0xf3b7, 0x00e69c92}, /* U+6712 [2000] */ + {0xf3a3, 0xe699aa}, /* U+666A [2000] */ + {0xf3a4, 0xe699ab}, /* U+666B [2000] */ + {0xf3a5, 0xe699ac}, /* U+666C [2000] */ + {0xf3a6, 0xe699ad}, /* U+666D [2000] */ + {0xf3a7, 0xe699bb}, /* U+667B [2000] */ + {0xf3a8, 0xe69a80}, /* U+6680 [2000] */ + {0xf3a9, 0xe69a90}, /* U+6690 [2000] */ + {0xf3aa, 0xe69a92}, /* U+6692 [2000] */ + {0xf3ab, 0xe69a99}, /* U+6699 [2000] */ + {0xf3ac, 0xe3ac8e}, /* U+3B0E [2000] */ + {0xf3ad, 0xe69aad}, /* U+66AD [2000] */ + {0xf3ae, 0xe69ab1}, /* U+66B1 [2000] */ + {0xf3af, 0xe69ab5}, /* U+66B5 [2000] */ + {0xf3b0, 0xe3ac9a}, /* U+3B1A [2000] */ + {0xf3b1, 0xe69abf}, /* U+66BF [2000] */ + {0xf3b2, 0xe3ac9c}, /* U+3B1C [2000] */ + {0xf3b3, 0xe69bac}, /* U+66EC [2000] */ + {0xf3b4, 0xe3ab97}, /* U+3AD7 [2000] */ + {0xf3b5, 0xe69c81}, /* U+6701 [2000] */ + {0xf3b6, 0xe69c85}, /* U+6705 [2000] */ + {0xf3b7, 0xe69c92}, /* U+6712 [2000] */ {0xf3b8, 0xf0a38db2}, /* U+23372 [2000] [Unicode3.1] */ - {0xf3b9, 0x00e69c99}, /* U+6719 [2000] */ + {0xf3b9, 0xe69c99}, /* U+6719 [2000] */ {0xf3ba, 0xf0a38f93}, /* U+233D3 [2000] [Unicode3.1] */ {0xf3bb, 0xf0a38f92}, /* U+233D2 [2000] [Unicode3.1] */ - {0xf3bc, 0x00e69d8c}, /* U+674C [2000] */ - {0xf3bd, 0x00e69d8d}, /* U+674D [2000] */ - {0xf3be, 0x00e69d94}, /* U+6754 [2000] */ - {0xf3bf, 0x00e69d9d}, /* U+675D [2000] */ + {0xf3bc, 0xe69d8c}, /* U+674C [2000] */ + {0xf3bd, 0xe69d8d}, /* U+674D [2000] */ + {0xf3be, 0xe69d94}, /* U+6754 [2000] */ + {0xf3bf, 0xe69d9d}, /* U+675D [2000] */ {0xf3c0, 0xf0a38f90}, /* U+233D0 [2000] [Unicode3.1] */ {0xf3c1, 0xf0a38fa4}, /* U+233E4 [2000] [Unicode3.1] */ {0xf3c2, 0xf0a38f95}, /* U+233D5 [2000] [Unicode3.1] */ - {0xf3c3, 0x00e69db4}, /* U+6774 [2000] */ - {0xf3c4, 0x00e69db6}, /* U+6776 [2000] */ + {0xf3c3, 0xe69db4}, /* U+6774 [2000] */ + {0xf3c4, 0xe69db6}, /* U+6776 [2000] */ {0xf3c5, 0xf0a38f9a}, /* U+233DA [2000] [Unicode3.1] */ - {0xf3c6, 0x00e69e92}, /* U+6792 [2000] */ + {0xf3c6, 0xe69e92}, /* U+6792 [2000] */ {0xf3c7, 0xf0a38f9f}, /* U+233DF [2000] [Unicode3.1] */ - {0xf3c8, 0x00e88da3}, /* U+8363 [2000] */ - {0xf3c9, 0x00e6a090}, /* U+6810 [2000] */ - {0xf3ca, 0x00e69eb0}, /* U+67B0 [2000] */ - {0xf3cb, 0x00e69eb2}, /* U+67B2 [2000] */ - {0xf3cc, 0x00e69f83}, /* U+67C3 [2000] */ - {0xf3cd, 0x00e69f88}, /* U+67C8 [2000] */ - {0xf3ce, 0x00e69f92}, /* U+67D2 [2000] */ - {0xf3cf, 0x00e69f99}, /* U+67D9 [2000] */ - {0xf3d0, 0x00e69f9b}, /* U+67DB [2000] */ - {0xf3d1, 0x00e69fb0}, /* U+67F0 [2000] */ - {0xf3d2, 0x00e69fb7}, /* U+67F7 [2000] */ + {0xf3c8, 0xe88da3}, /* U+8363 [2000] */ + {0xf3c9, 0xe6a090}, /* U+6810 [2000] */ + {0xf3ca, 0xe69eb0}, /* U+67B0 [2000] */ + {0xf3cb, 0xe69eb2}, /* U+67B2 [2000] */ + {0xf3cc, 0xe69f83}, /* U+67C3 [2000] */ + {0xf3cd, 0xe69f88}, /* U+67C8 [2000] */ + {0xf3ce, 0xe69f92}, /* U+67D2 [2000] */ + {0xf3cf, 0xe69f99}, /* U+67D9 [2000] */ + {0xf3d0, 0xe69f9b}, /* U+67DB [2000] */ + {0xf3d1, 0xe69fb0}, /* U+67F0 [2000] */ + {0xf3d2, 0xe69fb7}, /* U+67F7 [2000] */ {0xf3d3, 0xf0a3918a}, /* U+2344A [2000] [Unicode3.1] */ {0xf3d4, 0xf0a39191}, /* U+23451 [2000] [Unicode3.1] */ {0xf3d5, 0xf0a3918b}, /* U+2344B [2000] [Unicode3.1] */ - {0xf3d6, 0x00e6a098}, /* U+6818 [2000] */ - {0xf3d7, 0x00e6a09f}, /* U+681F [2000] */ - {0xf3d8, 0x00e6a0ad}, /* U+682D [2000] */ + {0xf3d6, 0xe6a098}, /* U+6818 [2000] */ + {0xf3d7, 0xe6a09f}, /* U+681F [2000] */ + {0xf3d8, 0xe6a0ad}, /* U+682D [2000] */ {0xf3d9, 0xf0a391a5}, /* U+23465 [2000] [Unicode3.1] */ - {0xf3da, 0x00e6a0b3}, /* U+6833 [2000] */ - {0xf3db, 0x00e6a0bb}, /* U+683B [2000] */ - {0xf3dc, 0x00e6a0be}, /* U+683E [2000] */ - {0xf3dd, 0x00e6a184}, /* U+6844 [2000] */ - {0xf3de, 0x00e6a185}, /* U+6845 [2000] */ - {0xf3df, 0x00e6a189}, /* U+6849 [2000] */ - {0xf3e0, 0x00e6a18c}, /* U+684C [2000] */ - {0xf3e1, 0x00e6a195}, /* U+6855 [2000] */ - {0xf3e2, 0x00e6a197}, /* U+6857 [2000] */ - {0xf3e3, 0x00e3adb7}, /* U+3B77 [2000] */ - {0xf3e4, 0x00e6a1ab}, /* U+686B [2000] */ - {0xf3e5, 0x00e6a1ae}, /* U+686E [2000] */ - {0xf3e6, 0x00e6a1ba}, /* U+687A [2000] */ - {0xf3e7, 0x00e6a1bc}, /* U+687C [2000] */ - {0xf3e8, 0x00e6a282}, /* U+6882 [2000] */ - {0xf3e9, 0x00e6a290}, /* U+6890 [2000] */ - {0xf3ea, 0x00e6a296}, /* U+6896 [2000] */ - {0xf3eb, 0x00e3adad}, /* U+3B6D [2000] */ - {0xf3ec, 0x00e6a298}, /* U+6898 [2000] */ - {0xf3ed, 0x00e6a299}, /* U+6899 [2000] */ - {0xf3ee, 0x00e6a29a}, /* U+689A [2000] */ - {0xf3ef, 0x00e6a29c}, /* U+689C [2000] */ - {0xf3f0, 0x00e6a2aa}, /* U+68AA [2000] */ - {0xf3f1, 0x00e6a2ab}, /* U+68AB [2000] */ - {0xf3f2, 0x00e6a2b4}, /* U+68B4 [2000] */ - {0xf3f3, 0x00e6a2bb}, /* U+68BB [2000] */ - {0xf3f4, 0x00e6a3bb}, /* U+68FB [2000] */ + {0xf3da, 0xe6a0b3}, /* U+6833 [2000] */ + {0xf3db, 0xe6a0bb}, /* U+683B [2000] */ + {0xf3dc, 0xe6a0be}, /* U+683E [2000] */ + {0xf3dd, 0xe6a184}, /* U+6844 [2000] */ + {0xf3de, 0xe6a185}, /* U+6845 [2000] */ + {0xf3df, 0xe6a189}, /* U+6849 [2000] */ + {0xf3e0, 0xe6a18c}, /* U+684C [2000] */ + {0xf3e1, 0xe6a195}, /* U+6855 [2000] */ + {0xf3e2, 0xe6a197}, /* U+6857 [2000] */ + {0xf3e3, 0xe3adb7}, /* U+3B77 [2000] */ + {0xf3e4, 0xe6a1ab}, /* U+686B [2000] */ + {0xf3e5, 0xe6a1ae}, /* U+686E [2000] */ + {0xf3e6, 0xe6a1ba}, /* U+687A [2000] */ + {0xf3e7, 0xe6a1bc}, /* U+687C [2000] */ + {0xf3e8, 0xe6a282}, /* U+6882 [2000] */ + {0xf3e9, 0xe6a290}, /* U+6890 [2000] */ + {0xf3ea, 0xe6a296}, /* U+6896 [2000] */ + {0xf3eb, 0xe3adad}, /* U+3B6D [2000] */ + {0xf3ec, 0xe6a298}, /* U+6898 [2000] */ + {0xf3ed, 0xe6a299}, /* U+6899 [2000] */ + {0xf3ee, 0xe6a29a}, /* U+689A [2000] */ + {0xf3ef, 0xe6a29c}, /* U+689C [2000] */ + {0xf3f0, 0xe6a2aa}, /* U+68AA [2000] */ + {0xf3f1, 0xe6a2ab}, /* U+68AB [2000] */ + {0xf3f2, 0xe6a2b4}, /* U+68B4 [2000] */ + {0xf3f3, 0xe6a2bb}, /* U+68BB [2000] */ + {0xf3f4, 0xe6a3bb}, /* U+68FB [2000] */ {0xf3f5, 0xf0a393a4}, /* U+234E4 [2000] [Unicode3.1] */ {0xf3f6, 0xf0a3959a}, /* U+2355A [2000] [Unicode3.1] */ - {0xf3f7, 0x00efa893}, /* U+FA13 CJK COMPATIBILITY IDEOGRAPH-FA13 [2000] */ - {0xf3f8, 0x00e6a383}, /* U+68C3 [2000] */ - {0xf3f9, 0x00e6a385}, /* U+68C5 [2000] */ - {0xf3fa, 0x00e6a38c}, /* U+68CC [2000] */ - {0xf3fb, 0x00e6a38f}, /* U+68CF [2000] */ - {0xf3fc, 0x00e6a396}, /* U+68D6 [2000] */ - {0xf440, 0x00e6a399}, /* U+68D9 [2000] */ - {0xf441, 0x00e6a3a4}, /* U+68E4 [2000] */ - {0xf442, 0x00e6a3a5}, /* U+68E5 [2000] */ - {0xf443, 0x00e6a3ac}, /* U+68EC [2000] */ - {0xf444, 0x00e6a3b7}, /* U+68F7 [2000] */ - {0xf445, 0x00e6a483}, /* U+6903 [2000] */ - {0xf446, 0x00e6a487}, /* U+6907 [2000] */ - {0xf447, 0x00e3ae87}, /* U+3B87 [2000] */ - {0xf448, 0x00e3ae88}, /* U+3B88 [2000] */ + {0xf3f7, 0xefa893}, /* U+FA13 CJK COMPATIBILITY IDEOGRAPH-FA13 [2000] */ + {0xf3f8, 0xe6a383}, /* U+68C3 [2000] */ + {0xf3f9, 0xe6a385}, /* U+68C5 [2000] */ + {0xf3fa, 0xe6a38c}, /* U+68CC [2000] */ + {0xf3fb, 0xe6a38f}, /* U+68CF [2000] */ + {0xf3fc, 0xe6a396}, /* U+68D6 [2000] */ + {0xf440, 0xe6a399}, /* U+68D9 [2000] */ + {0xf441, 0xe6a3a4}, /* U+68E4 [2000] */ + {0xf442, 0xe6a3a5}, /* U+68E5 [2000] */ + {0xf443, 0xe6a3ac}, /* U+68EC [2000] */ + {0xf444, 0xe6a3b7}, /* U+68F7 [2000] */ + {0xf445, 0xe6a483}, /* U+6903 [2000] */ + {0xf446, 0xe6a487}, /* U+6907 [2000] */ + {0xf447, 0xe3ae87}, /* U+3B87 [2000] */ + {0xf448, 0xe3ae88}, /* U+3B88 [2000] */ {0xf449, 0xf0a39694}, /* U+23594 [2000] [Unicode3.1] */ - {0xf44a, 0x00e6a4bb}, /* U+693B [2000] */ - {0xf44b, 0x00e3ae8d}, /* U+3B8D [2000] */ - {0xf44c, 0x00e6a586}, /* U+6946 [2000] */ - {0xf44d, 0x00e6a5a9}, /* U+6969 [2000] */ - {0xf44e, 0x00e6a5ac}, /* U+696C [2000] */ - {0xf44f, 0x00e6a5b2}, /* U+6972 [2000] */ - {0xf450, 0x00e6a5ba}, /* U+697A [2000] */ - {0xf451, 0x00e6a5bf}, /* U+697F [2000] */ - {0xf452, 0x00e6a692}, /* U+6992 [2000] */ - {0xf453, 0x00e3aea4}, /* U+3BA4 [2000] */ - {0xf454, 0x00e6a696}, /* U+6996 [2000] */ - {0xf455, 0x00e6a698}, /* U+6998 [2000] */ - {0xf456, 0x00e6a6a6}, /* U+69A6 [2000] */ - {0xf457, 0x00e6a6b0}, /* U+69B0 [2000] */ - {0xf458, 0x00e6a6b7}, /* U+69B7 [2000] */ - {0xf459, 0x00e6a6ba}, /* U+69BA [2000] */ - {0xf45a, 0x00e6a6bc}, /* U+69BC [2000] */ - {0xf45b, 0x00e6a780}, /* U+69C0 [2000] */ - {0xf45c, 0x00e6a791}, /* U+69D1 [2000] */ - {0xf45d, 0x00e6a796}, /* U+69D6 [2000] */ + {0xf44a, 0xe6a4bb}, /* U+693B [2000] */ + {0xf44b, 0xe3ae8d}, /* U+3B8D [2000] */ + {0xf44c, 0xe6a586}, /* U+6946 [2000] */ + {0xf44d, 0xe6a5a9}, /* U+6969 [2000] */ + {0xf44e, 0xe6a5ac}, /* U+696C [2000] */ + {0xf44f, 0xe6a5b2}, /* U+6972 [2000] */ + {0xf450, 0xe6a5ba}, /* U+697A [2000] */ + {0xf451, 0xe6a5bf}, /* U+697F [2000] */ + {0xf452, 0xe6a692}, /* U+6992 [2000] */ + {0xf453, 0xe3aea4}, /* U+3BA4 [2000] */ + {0xf454, 0xe6a696}, /* U+6996 [2000] */ + {0xf455, 0xe6a698}, /* U+6998 [2000] */ + {0xf456, 0xe6a6a6}, /* U+69A6 [2000] */ + {0xf457, 0xe6a6b0}, /* U+69B0 [2000] */ + {0xf458, 0xe6a6b7}, /* U+69B7 [2000] */ + {0xf459, 0xe6a6ba}, /* U+69BA [2000] */ + {0xf45a, 0xe6a6bc}, /* U+69BC [2000] */ + {0xf45b, 0xe6a780}, /* U+69C0 [2000] */ + {0xf45c, 0xe6a791}, /* U+69D1 [2000] */ + {0xf45d, 0xe6a796}, /* U+69D6 [2000] */ {0xf45e, 0xf0a398b9}, /* U+23639 [2000] [Unicode3.1] */ {0xf45f, 0xf0a39987}, /* U+23647 [2000] [Unicode3.1] */ - {0xf460, 0x00e6a8b0}, /* U+6A30 [2000] */ + {0xf460, 0xe6a8b0}, /* U+6A30 [2000] */ {0xf461, 0xf0a398b8}, /* U+23638 [2000] [Unicode3.1] */ {0xf462, 0xf0a398ba}, /* U+2363A [2000] [Unicode3.1] */ - {0xf463, 0x00e6a7a3}, /* U+69E3 [2000] */ - {0xf464, 0x00e6a7ae}, /* U+69EE [2000] */ - {0xf465, 0x00e6a7af}, /* U+69EF [2000] */ - {0xf466, 0x00e6a7b3}, /* U+69F3 [2000] */ - {0xf467, 0x00e3af8d}, /* U+3BCD [2000] */ - {0xf468, 0x00e6a7b4}, /* U+69F4 [2000] */ - {0xf469, 0x00e6a7be}, /* U+69FE [2000] */ - {0xf46a, 0x00e6a891}, /* U+6A11 [2000] */ - {0xf46b, 0x00e6a89a}, /* U+6A1A [2000] */ - {0xf46c, 0x00e6a89d}, /* U+6A1D [2000] */ + {0xf463, 0xe6a7a3}, /* U+69E3 [2000] */ + {0xf464, 0xe6a7ae}, /* U+69EE [2000] */ + {0xf465, 0xe6a7af}, /* U+69EF [2000] */ + {0xf466, 0xe6a7b3}, /* U+69F3 [2000] */ + {0xf467, 0xe3af8d}, /* U+3BCD [2000] */ + {0xf468, 0xe6a7b4}, /* U+69F4 [2000] */ + {0xf469, 0xe6a7be}, /* U+69FE [2000] */ + {0xf46a, 0xe6a891}, /* U+6A11 [2000] */ + {0xf46b, 0xe6a89a}, /* U+6A1A [2000] */ + {0xf46c, 0xe6a89d}, /* U+6A1D [2000] */ {0xf46d, 0xf0a39c9c}, /* U+2371C [2000] [Unicode3.1] */ - {0xf46e, 0x00e6a8b2}, /* U+6A32 [2000] */ - {0xf46f, 0x00e6a8b3}, /* U+6A33 [2000] */ - {0xf470, 0x00e6a8b4}, /* U+6A34 [2000] */ - {0xf471, 0x00e6a8bf}, /* U+6A3F [2000] */ - {0xf472, 0x00e6a986}, /* U+6A46 [2000] */ - {0xf473, 0x00e6a989}, /* U+6A49 [2000] */ - {0xf474, 0x00e6a9ba}, /* U+6A7A [2000] */ - {0xf475, 0x00e6a98e}, /* U+6A4E [2000] */ - {0xf476, 0x00e6a992}, /* U+6A52 [2000] */ - {0xf477, 0x00e6a9a4}, /* U+6A64 [2000] */ + {0xf46e, 0xe6a8b2}, /* U+6A32 [2000] */ + {0xf46f, 0xe6a8b3}, /* U+6A33 [2000] */ + {0xf470, 0xe6a8b4}, /* U+6A34 [2000] */ + {0xf471, 0xe6a8bf}, /* U+6A3F [2000] */ + {0xf472, 0xe6a986}, /* U+6A46 [2000] */ + {0xf473, 0xe6a989}, /* U+6A49 [2000] */ + {0xf474, 0xe6a9ba}, /* U+6A7A [2000] */ + {0xf475, 0xe6a98e}, /* U+6A4E [2000] */ + {0xf476, 0xe6a992}, /* U+6A52 [2000] */ + {0xf477, 0xe6a9a4}, /* U+6A64 [2000] */ {0xf478, 0xf0a39c8c}, /* U+2370C [2000] [Unicode3.1] */ - {0xf479, 0x00e6a9be}, /* U+6A7E [2000] */ - {0xf47a, 0x00e6aa83}, /* U+6A83 [2000] */ - {0xf47b, 0x00e6aa8b}, /* U+6A8B [2000] */ - {0xf47c, 0x00e3afb0}, /* U+3BF0 [2000] */ - {0xf47d, 0x00e6aa91}, /* U+6A91 [2000] */ - {0xf47e, 0x00e6aa9f}, /* U+6A9F [2000] */ - {0xf480, 0x00e6aaa1}, /* U+6AA1 [2000] */ + {0xf479, 0xe6a9be}, /* U+6A7E [2000] */ + {0xf47a, 0xe6aa83}, /* U+6A83 [2000] */ + {0xf47b, 0xe6aa8b}, /* U+6A8B [2000] */ + {0xf47c, 0xe3afb0}, /* U+3BF0 [2000] */ + {0xf47d, 0xe6aa91}, /* U+6A91 [2000] */ + {0xf47e, 0xe6aa9f}, /* U+6A9F [2000] */ + {0xf480, 0xe6aaa1}, /* U+6AA1 [2000] */ {0xf481, 0xf0a39da4}, /* U+23764 [2000] [Unicode3.1] */ - {0xf482, 0x00e6aaab}, /* U+6AAB [2000] */ - {0xf483, 0x00e6aabd}, /* U+6ABD [2000] */ - {0xf484, 0x00e6ab86}, /* U+6AC6 [2000] */ - {0xf485, 0x00e6ab94}, /* U+6AD4 [2000] */ - {0xf486, 0x00e6ab90}, /* U+6AD0 [2000] */ - {0xf487, 0x00e6ab9c}, /* U+6ADC [2000] */ - {0xf488, 0x00e6ab9d}, /* U+6ADD [2000] */ + {0xf482, 0xe6aaab}, /* U+6AAB [2000] */ + {0xf483, 0xe6aabd}, /* U+6ABD [2000] */ + {0xf484, 0xe6ab86}, /* U+6AC6 [2000] */ + {0xf485, 0xe6ab94}, /* U+6AD4 [2000] */ + {0xf486, 0xe6ab90}, /* U+6AD0 [2000] */ + {0xf487, 0xe6ab9c}, /* U+6ADC [2000] */ + {0xf488, 0xe6ab9d}, /* U+6ADD [2000] */ {0xf489, 0xf0a39fbf}, /* U+237FF [2000] [Unicode3.1] */ {0xf48a, 0xf0a39fa7}, /* U+237E7 [2000] [Unicode3.1] */ - {0xf48b, 0x00e6abac}, /* U+6AEC [2000] */ - {0xf48c, 0x00e6abb1}, /* U+6AF1 [2000] */ - {0xf48d, 0x00e6abb2}, /* U+6AF2 [2000] */ - {0xf48e, 0x00e6abb3}, /* U+6AF3 [2000] */ - {0xf48f, 0x00e6abbd}, /* U+6AFD [2000] */ + {0xf48b, 0xe6abac}, /* U+6AEC [2000] */ + {0xf48c, 0xe6abb1}, /* U+6AF1 [2000] */ + {0xf48d, 0xe6abb2}, /* U+6AF2 [2000] */ + {0xf48e, 0xe6abb3}, /* U+6AF3 [2000] */ + {0xf48f, 0xe6abbd}, /* U+6AFD [2000] */ {0xf490, 0xf0a3a0a4}, /* U+23824 [2000] [Unicode3.1] */ - {0xf491, 0x00e6ac8b}, /* U+6B0B [2000] */ - {0xf492, 0x00e6ac8f}, /* U+6B0F [2000] */ - {0xf493, 0x00e6ac90}, /* U+6B10 [2000] */ - {0xf494, 0x00e6ac91}, /* U+6B11 [2000] */ + {0xf491, 0xe6ac8b}, /* U+6B0B [2000] */ + {0xf492, 0xe6ac8f}, /* U+6B0F [2000] */ + {0xf493, 0xe6ac90}, /* U+6B10 [2000] */ + {0xf494, 0xe6ac91}, /* U+6B11 [2000] */ {0xf495, 0xf0a3a0bd}, /* U+2383D [2000] [Unicode3.1] */ - {0xf496, 0x00e6ac97}, /* U+6B17 [2000] */ - {0xf497, 0x00e3b0a6}, /* U+3C26 [2000] */ - {0xf498, 0x00e6acaf}, /* U+6B2F [2000] */ - {0xf499, 0x00e6ad8a}, /* U+6B4A [2000] */ - {0xf49a, 0x00e6ad98}, /* U+6B58 [2000] */ - {0xf49b, 0x00e6adac}, /* U+6B6C [2000] */ - {0xf49c, 0x00e6adb5}, /* U+6B75 [2000] */ - {0xf49d, 0x00e6adba}, /* U+6B7A [2000] */ - {0xf49e, 0x00e6ae81}, /* U+6B81 [2000] */ - {0xf49f, 0x00e6ae9b}, /* U+6B9B [2000] */ - {0xf4a0, 0x00e6aeae}, /* U+6BAE [2000] */ + {0xf496, 0xe6ac97}, /* U+6B17 [2000] */ + {0xf497, 0xe3b0a6}, /* U+3C26 [2000] */ + {0xf498, 0xe6acaf}, /* U+6B2F [2000] */ + {0xf499, 0xe6ad8a}, /* U+6B4A [2000] */ + {0xf49a, 0xe6ad98}, /* U+6B58 [2000] */ + {0xf49b, 0xe6adac}, /* U+6B6C [2000] */ + {0xf49c, 0xe6adb5}, /* U+6B75 [2000] */ + {0xf49d, 0xe6adba}, /* U+6B7A [2000] */ + {0xf49e, 0xe6ae81}, /* U+6B81 [2000] */ + {0xf49f, 0xe6ae9b}, /* U+6B9B [2000] */ + {0xf4a0, 0xe6aeae}, /* U+6BAE [2000] */ {0xf4a1, 0xf0a3aa98}, /* U+23A98 [2000] [Unicode3.1] */ - {0xf4a2, 0x00e6aebd}, /* U+6BBD [2000] */ - {0xf4a3, 0x00e6aebe}, /* U+6BBE [2000] */ - {0xf4a4, 0x00e6af87}, /* U+6BC7 [2000] */ - {0xf4a5, 0x00e6af88}, /* U+6BC8 [2000] */ - {0xf4a6, 0x00e6af89}, /* U+6BC9 [2000] */ - {0xf4a7, 0x00e6af9a}, /* U+6BDA [2000] */ - {0xf4a8, 0x00e6afa6}, /* U+6BE6 [2000] */ - {0xf4a9, 0x00e6afa7}, /* U+6BE7 [2000] */ - {0xf4aa, 0x00e6afae}, /* U+6BEE [2000] */ - {0xf4ab, 0x00e6afb1}, /* U+6BF1 [2000] */ - {0xf4ac, 0x00e6b082}, /* U+6C02 [2000] */ - {0xf4ad, 0x00e6b08a}, /* U+6C0A [2000] */ - {0xf4ae, 0x00e6b08e}, /* U+6C0E [2000] */ - {0xf4af, 0x00e6b0b5}, /* U+6C35 [2000] */ - {0xf4b0, 0x00e6b0b6}, /* U+6C36 [2000] */ - {0xf4b1, 0x00e6b0ba}, /* U+6C3A [2000] */ + {0xf4a2, 0xe6aebd}, /* U+6BBD [2000] */ + {0xf4a3, 0xe6aebe}, /* U+6BBE [2000] */ + {0xf4a4, 0xe6af87}, /* U+6BC7 [2000] */ + {0xf4a5, 0xe6af88}, /* U+6BC8 [2000] */ + {0xf4a6, 0xe6af89}, /* U+6BC9 [2000] */ + {0xf4a7, 0xe6af9a}, /* U+6BDA [2000] */ + {0xf4a8, 0xe6afa6}, /* U+6BE6 [2000] */ + {0xf4a9, 0xe6afa7}, /* U+6BE7 [2000] */ + {0xf4aa, 0xe6afae}, /* U+6BEE [2000] */ + {0xf4ab, 0xe6afb1}, /* U+6BF1 [2000] */ + {0xf4ac, 0xe6b082}, /* U+6C02 [2000] */ + {0xf4ad, 0xe6b08a}, /* U+6C0A [2000] */ + {0xf4ae, 0xe6b08e}, /* U+6C0E [2000] */ + {0xf4af, 0xe6b0b5}, /* U+6C35 [2000] */ + {0xf4b0, 0xe6b0b6}, /* U+6C36 [2000] */ + {0xf4b1, 0xe6b0ba}, /* U+6C3A [2000] */ {0xf4b2, 0xf0a3b1bf}, /* U+23C7F [2000] [Unicode3.1] */ - {0xf4b3, 0x00e6b0bf}, /* U+6C3F [2000] */ - {0xf4b4, 0x00e6b18d}, /* U+6C4D [2000] */ - {0xf4b5, 0x00e6b19b}, /* U+6C5B [2000] */ - {0xf4b6, 0x00e6b1ad}, /* U+6C6D [2000] */ - {0xf4b7, 0x00e6b284}, /* U+6C84 [2000] */ - {0xf4b8, 0x00e6b289}, /* U+6C89 [2000] */ - {0xf4b9, 0x00e3b383}, /* U+3CC3 [2000] */ - {0xf4ba, 0x00e6b294}, /* U+6C94 [2000] */ - {0xf4bb, 0x00e6b295}, /* U+6C95 [2000] */ - {0xf4bc, 0x00e6b297}, /* U+6C97 [2000] */ - {0xf4bd, 0x00e6b2ad}, /* U+6CAD [2000] */ - {0xf4be, 0x00e6b382}, /* U+6CC2 [2000] */ - {0xf4bf, 0x00e6b390}, /* U+6CD0 [2000] */ - {0xf4c0, 0x00e3b392}, /* U+3CD2 [2000] */ - {0xf4c1, 0x00e6b396}, /* U+6CD6 [2000] */ - {0xf4c2, 0x00e6b39a}, /* U+6CDA [2000] */ - {0xf4c3, 0x00e6b39c}, /* U+6CDC [2000] */ - {0xf4c4, 0x00e6b3a9}, /* U+6CE9 [2000] */ - {0xf4c5, 0x00e6b3ac}, /* U+6CEC [2000] */ - {0xf4c6, 0x00e6b3ad}, /* U+6CED [2000] */ + {0xf4b3, 0xe6b0bf}, /* U+6C3F [2000] */ + {0xf4b4, 0xe6b18d}, /* U+6C4D [2000] */ + {0xf4b5, 0xe6b19b}, /* U+6C5B [2000] */ + {0xf4b6, 0xe6b1ad}, /* U+6C6D [2000] */ + {0xf4b7, 0xe6b284}, /* U+6C84 [2000] */ + {0xf4b8, 0xe6b289}, /* U+6C89 [2000] */ + {0xf4b9, 0xe3b383}, /* U+3CC3 [2000] */ + {0xf4ba, 0xe6b294}, /* U+6C94 [2000] */ + {0xf4bb, 0xe6b295}, /* U+6C95 [2000] */ + {0xf4bc, 0xe6b297}, /* U+6C97 [2000] */ + {0xf4bd, 0xe6b2ad}, /* U+6CAD [2000] */ + {0xf4be, 0xe6b382}, /* U+6CC2 [2000] */ + {0xf4bf, 0xe6b390}, /* U+6CD0 [2000] */ + {0xf4c0, 0xe3b392}, /* U+3CD2 [2000] */ + {0xf4c1, 0xe6b396}, /* U+6CD6 [2000] */ + {0xf4c2, 0xe6b39a}, /* U+6CDA [2000] */ + {0xf4c3, 0xe6b39c}, /* U+6CDC [2000] */ + {0xf4c4, 0xe6b3a9}, /* U+6CE9 [2000] */ + {0xf4c5, 0xe6b3ac}, /* U+6CEC [2000] */ + {0xf4c6, 0xe6b3ad}, /* U+6CED [2000] */ {0xf4c7, 0xf0a3b480}, /* U+23D00 [2000] [Unicode3.1] */ - {0xf4c8, 0x00e6b480}, /* U+6D00 [2000] */ - {0xf4c9, 0x00e6b48a}, /* U+6D0A [2000] */ - {0xf4ca, 0x00e6b4a4}, /* U+6D24 [2000] */ - {0xf4cb, 0x00e6b4a6}, /* U+6D26 [2000] */ - {0xf4cc, 0x00e6b4a7}, /* U+6D27 [2000] */ - {0xf4cd, 0x00e6b1a7}, /* U+6C67 [2000] */ - {0xf4ce, 0x00e6b4af}, /* U+6D2F [2000] */ - {0xf4cf, 0x00e6b4bc}, /* U+6D3C [2000] */ - {0xf4d0, 0x00e6b59b}, /* U+6D5B [2000] */ - {0xf4d1, 0x00e6b59e}, /* U+6D5E [2000] */ - {0xf4d2, 0x00e6b5a0}, /* U+6D60 [2000] */ - {0xf4d3, 0x00e6b5b0}, /* U+6D70 [2000] */ - {0xf4d4, 0x00e6b680}, /* U+6D80 [2000] */ - {0xf4d5, 0x00e6b681}, /* U+6D81 [2000] */ - {0xf4d6, 0x00e6b68a}, /* U+6D8A [2000] */ - {0xf4d7, 0x00e6b68d}, /* U+6D8D [2000] */ - {0xf4d8, 0x00e6b691}, /* U+6D91 [2000] */ - {0xf4d9, 0x00e6b698}, /* U+6D98 [2000] */ + {0xf4c8, 0xe6b480}, /* U+6D00 [2000] */ + {0xf4c9, 0xe6b48a}, /* U+6D0A [2000] */ + {0xf4ca, 0xe6b4a4}, /* U+6D24 [2000] */ + {0xf4cb, 0xe6b4a6}, /* U+6D26 [2000] */ + {0xf4cc, 0xe6b4a7}, /* U+6D27 [2000] */ + {0xf4cd, 0xe6b1a7}, /* U+6C67 [2000] */ + {0xf4ce, 0xe6b4af}, /* U+6D2F [2000] */ + {0xf4cf, 0xe6b4bc}, /* U+6D3C [2000] */ + {0xf4d0, 0xe6b59b}, /* U+6D5B [2000] */ + {0xf4d1, 0xe6b59e}, /* U+6D5E [2000] */ + {0xf4d2, 0xe6b5a0}, /* U+6D60 [2000] */ + {0xf4d3, 0xe6b5b0}, /* U+6D70 [2000] */ + {0xf4d4, 0xe6b680}, /* U+6D80 [2000] */ + {0xf4d5, 0xe6b681}, /* U+6D81 [2000] */ + {0xf4d6, 0xe6b68a}, /* U+6D8A [2000] */ + {0xf4d7, 0xe6b68d}, /* U+6D8D [2000] */ + {0xf4d8, 0xe6b691}, /* U+6D91 [2000] */ + {0xf4d9, 0xe6b698}, /* U+6D98 [2000] */ {0xf4da, 0xf0a3b580}, /* U+23D40 [2000] [Unicode3.1] */ - {0xf4db, 0x00e6b897}, /* U+6E17 [2000] */ + {0xf4db, 0xe6b897}, /* U+6E17 [2000] */ {0xf4dc, 0xf0a3b7ba}, /* U+23DFA [2000] [Unicode3.1] */ {0xf4dd, 0xf0a3b7b9}, /* U+23DF9 [2000] [Unicode3.1] */ {0xf4de, 0xf0a3b793}, /* U+23DD3 [2000] [Unicode3.1] */ - {0xf4df, 0x00e6b6ab}, /* U+6DAB [2000] */ - {0xf4e0, 0x00e6b6ae}, /* U+6DAE [2000] */ - {0xf4e1, 0x00e6b6b4}, /* U+6DB4 [2000] */ - {0xf4e2, 0x00e6b782}, /* U+6DC2 [2000] */ - {0xf4e3, 0x00e6b4b4}, /* U+6D34 [2000] */ - {0xf4e4, 0x00e6b788}, /* U+6DC8 [2000] */ - {0xf4e5, 0x00e6b78e}, /* U+6DCE [2000] */ - {0xf4e6, 0x00e6b78f}, /* U+6DCF [2000] */ - {0xf4e7, 0x00e6b790}, /* U+6DD0 [2000] */ - {0xf4e8, 0x00e6b79f}, /* U+6DDF [2000] */ - {0xf4e9, 0x00e6b7a9}, /* U+6DE9 [2000] */ - {0xf4ea, 0x00e6b7b6}, /* U+6DF6 [2000] */ - {0xf4eb, 0x00e6b8b6}, /* U+6E36 [2000] */ - {0xf4ec, 0x00e6b89e}, /* U+6E1E [2000] */ - {0xf4ed, 0x00e6b8a2}, /* U+6E22 [2000] */ - {0xf4ee, 0x00e6b8a7}, /* U+6E27 [2000] */ - {0xf4ef, 0x00e3b491}, /* U+3D11 [2000] */ - {0xf4f0, 0x00e6b8b2}, /* U+6E32 [2000] */ - {0xf4f1, 0x00e6b8bc}, /* U+6E3C [2000] */ - {0xf4f2, 0x00e6b988}, /* U+6E48 [2000] */ - {0xf4f3, 0x00e6b989}, /* U+6E49 [2000] */ - {0xf4f4, 0x00e6b98b}, /* U+6E4B [2000] */ - {0xf4f5, 0x00e6b98c}, /* U+6E4C [2000] */ - {0xf4f6, 0x00e6b98f}, /* U+6E4F [2000] */ - {0xf4f7, 0x00e6b991}, /* U+6E51 [2000] */ - {0xf4f8, 0x00e6b993}, /* U+6E53 [2000] */ - {0xf4f9, 0x00e6b994}, /* U+6E54 [2000] */ - {0xf4fa, 0x00e6b997}, /* U+6E57 [2000] */ - {0xf4fb, 0x00e6b9a3}, /* U+6E63 [2000] */ - {0xf4fc, 0x00e3b49e}, /* U+3D1E [2000] */ - {0xf540, 0x00e6ba93}, /* U+6E93 [2000] */ - {0xf541, 0x00e6baa7}, /* U+6EA7 [2000] */ - {0xf542, 0x00e6bab4}, /* U+6EB4 [2000] */ - {0xf543, 0x00e6babf}, /* U+6EBF [2000] */ - {0xf544, 0x00e6bb83}, /* U+6EC3 [2000] */ - {0xf545, 0x00e6bb8a}, /* U+6ECA [2000] */ - {0xf546, 0x00e6bb99}, /* U+6ED9 [2000] */ - {0xf547, 0x00e6bcb5}, /* U+6F35 [2000] */ - {0xf548, 0x00e6bbab}, /* U+6EEB [2000] */ - {0xf549, 0x00e6bbb9}, /* U+6EF9 [2000] */ - {0xf54a, 0x00e6bbbb}, /* U+6EFB [2000] */ - {0xf54b, 0x00e6bc8a}, /* U+6F0A [2000] */ - {0xf54c, 0x00e6bc8c}, /* U+6F0C [2000] */ - {0xf54d, 0x00e6bc98}, /* U+6F18 [2000] */ - {0xf54e, 0x00e6bca5}, /* U+6F25 [2000] */ - {0xf54f, 0x00e6bcb6}, /* U+6F36 [2000] */ - {0xf550, 0x00e6bcbc}, /* U+6F3C [2000] */ + {0xf4df, 0xe6b6ab}, /* U+6DAB [2000] */ + {0xf4e0, 0xe6b6ae}, /* U+6DAE [2000] */ + {0xf4e1, 0xe6b6b4}, /* U+6DB4 [2000] */ + {0xf4e2, 0xe6b782}, /* U+6DC2 [2000] */ + {0xf4e3, 0xe6b4b4}, /* U+6D34 [2000] */ + {0xf4e4, 0xe6b788}, /* U+6DC8 [2000] */ + {0xf4e5, 0xe6b78e}, /* U+6DCE [2000] */ + {0xf4e6, 0xe6b78f}, /* U+6DCF [2000] */ + {0xf4e7, 0xe6b790}, /* U+6DD0 [2000] */ + {0xf4e8, 0xe6b79f}, /* U+6DDF [2000] */ + {0xf4e9, 0xe6b7a9}, /* U+6DE9 [2000] */ + {0xf4ea, 0xe6b7b6}, /* U+6DF6 [2000] */ + {0xf4eb, 0xe6b8b6}, /* U+6E36 [2000] */ + {0xf4ec, 0xe6b89e}, /* U+6E1E [2000] */ + {0xf4ed, 0xe6b8a2}, /* U+6E22 [2000] */ + {0xf4ee, 0xe6b8a7}, /* U+6E27 [2000] */ + {0xf4ef, 0xe3b491}, /* U+3D11 [2000] */ + {0xf4f0, 0xe6b8b2}, /* U+6E32 [2000] */ + {0xf4f1, 0xe6b8bc}, /* U+6E3C [2000] */ + {0xf4f2, 0xe6b988}, /* U+6E48 [2000] */ + {0xf4f3, 0xe6b989}, /* U+6E49 [2000] */ + {0xf4f4, 0xe6b98b}, /* U+6E4B [2000] */ + {0xf4f5, 0xe6b98c}, /* U+6E4C [2000] */ + {0xf4f6, 0xe6b98f}, /* U+6E4F [2000] */ + {0xf4f7, 0xe6b991}, /* U+6E51 [2000] */ + {0xf4f8, 0xe6b993}, /* U+6E53 [2000] */ + {0xf4f9, 0xe6b994}, /* U+6E54 [2000] */ + {0xf4fa, 0xe6b997}, /* U+6E57 [2000] */ + {0xf4fb, 0xe6b9a3}, /* U+6E63 [2000] */ + {0xf4fc, 0xe3b49e}, /* U+3D1E [2000] */ + {0xf540, 0xe6ba93}, /* U+6E93 [2000] */ + {0xf541, 0xe6baa7}, /* U+6EA7 [2000] */ + {0xf542, 0xe6bab4}, /* U+6EB4 [2000] */ + {0xf543, 0xe6babf}, /* U+6EBF [2000] */ + {0xf544, 0xe6bb83}, /* U+6EC3 [2000] */ + {0xf545, 0xe6bb8a}, /* U+6ECA [2000] */ + {0xf546, 0xe6bb99}, /* U+6ED9 [2000] */ + {0xf547, 0xe6bcb5}, /* U+6F35 [2000] */ + {0xf548, 0xe6bbab}, /* U+6EEB [2000] */ + {0xf549, 0xe6bbb9}, /* U+6EF9 [2000] */ + {0xf54a, 0xe6bbbb}, /* U+6EFB [2000] */ + {0xf54b, 0xe6bc8a}, /* U+6F0A [2000] */ + {0xf54c, 0xe6bc8c}, /* U+6F0C [2000] */ + {0xf54d, 0xe6bc98}, /* U+6F18 [2000] */ + {0xf54e, 0xe6bca5}, /* U+6F25 [2000] */ + {0xf54f, 0xe6bcb6}, /* U+6F36 [2000] */ + {0xf550, 0xe6bcbc}, /* U+6F3C [2000] */ {0xf551, 0xf0a3bdbe}, /* U+23F7E [2000] [Unicode3.1] */ - {0xf552, 0x00e6bd92}, /* U+6F52 [2000] */ - {0xf553, 0x00e6bd97}, /* U+6F57 [2000] */ - {0xf554, 0x00e6bd9a}, /* U+6F5A [2000] */ - {0xf555, 0x00e6bda0}, /* U+6F60 [2000] */ - {0xf556, 0x00e6bda8}, /* U+6F68 [2000] */ - {0xf557, 0x00e6be98}, /* U+6F98 [2000] */ - {0xf558, 0x00e6bdbd}, /* U+6F7D [2000] */ - {0xf559, 0x00e6be90}, /* U+6F90 [2000] */ - {0xf55a, 0x00e6be96}, /* U+6F96 [2000] */ - {0xf55b, 0x00e6bebe}, /* U+6FBE [2000] */ - {0xf55c, 0x00e6be9f}, /* U+6F9F [2000] */ - {0xf55d, 0x00e6bea5}, /* U+6FA5 [2000] */ - {0xf55e, 0x00e6beaf}, /* U+6FAF [2000] */ - {0xf55f, 0x00e3b5a4}, /* U+3D64 [2000] */ - {0xf560, 0x00e6beb5}, /* U+6FB5 [2000] */ - {0xf561, 0x00e6bf88}, /* U+6FC8 [2000] */ - {0xf562, 0x00e6bf89}, /* U+6FC9 [2000] */ - {0xf563, 0x00e6bf9a}, /* U+6FDA [2000] */ - {0xf564, 0x00e6bf9e}, /* U+6FDE [2000] */ - {0xf565, 0x00e6bfa9}, /* U+6FE9 [2000] */ + {0xf552, 0xe6bd92}, /* U+6F52 [2000] */ + {0xf553, 0xe6bd97}, /* U+6F57 [2000] */ + {0xf554, 0xe6bd9a}, /* U+6F5A [2000] */ + {0xf555, 0xe6bda0}, /* U+6F60 [2000] */ + {0xf556, 0xe6bda8}, /* U+6F68 [2000] */ + {0xf557, 0xe6be98}, /* U+6F98 [2000] */ + {0xf558, 0xe6bdbd}, /* U+6F7D [2000] */ + {0xf559, 0xe6be90}, /* U+6F90 [2000] */ + {0xf55a, 0xe6be96}, /* U+6F96 [2000] */ + {0xf55b, 0xe6bebe}, /* U+6FBE [2000] */ + {0xf55c, 0xe6be9f}, /* U+6F9F [2000] */ + {0xf55d, 0xe6bea5}, /* U+6FA5 [2000] */ + {0xf55e, 0xe6beaf}, /* U+6FAF [2000] */ + {0xf55f, 0xe3b5a4}, /* U+3D64 [2000] */ + {0xf560, 0xe6beb5}, /* U+6FB5 [2000] */ + {0xf561, 0xe6bf88}, /* U+6FC8 [2000] */ + {0xf562, 0xe6bf89}, /* U+6FC9 [2000] */ + {0xf563, 0xe6bf9a}, /* U+6FDA [2000] */ + {0xf564, 0xe6bf9e}, /* U+6FDE [2000] */ + {0xf565, 0xe6bfa9}, /* U+6FE9 [2000] */ {0xf566, 0xf0a48296}, /* U+24096 [2000] [Unicode3.1] */ - {0xf567, 0x00e6bfbc}, /* U+6FFC [2000] */ - {0xf568, 0x00e78080}, /* U+7000 [2000] */ - {0xf569, 0x00e78087}, /* U+7007 [2000] */ - {0xf56a, 0x00e7808a}, /* U+700A [2000] */ - {0xf56b, 0x00e780a3}, /* U+7023 [2000] */ + {0xf567, 0xe6bfbc}, /* U+6FFC [2000] */ + {0xf568, 0xe78080}, /* U+7000 [2000] */ + {0xf569, 0xe78087}, /* U+7007 [2000] */ + {0xf56a, 0xe7808a}, /* U+700A [2000] */ + {0xf56b, 0xe780a3}, /* U+7023 [2000] */ {0xf56c, 0xf0a48483}, /* U+24103 [2000] [Unicode3.1] */ - {0xf56d, 0x00e780b9}, /* U+7039 [2000] */ - {0xf56e, 0x00e780ba}, /* U+703A [2000] */ - {0xf56f, 0x00e780bc}, /* U+703C [2000] */ - {0xf570, 0x00e78183}, /* U+7043 [2000] */ - {0xf571, 0x00e78187}, /* U+7047 [2000] */ - {0xf572, 0x00e7818b}, /* U+704B [2000] */ - {0xf573, 0x00e3b69a}, /* U+3D9A [2000] */ - {0xf574, 0x00e78194}, /* U+7054 [2000] */ - {0xf575, 0x00e781a5}, /* U+7065 [2000] */ - {0xf576, 0x00e781a9}, /* U+7069 [2000] */ - {0xf577, 0x00e781ac}, /* U+706C [2000] */ - {0xf578, 0x00e781ae}, /* U+706E [2000] */ - {0xf579, 0x00e781b6}, /* U+7076 [2000] */ - {0xf57a, 0x00e781be}, /* U+707E [2000] */ - {0xf57b, 0x00e78281}, /* U+7081 [2000] */ - {0xf57c, 0x00e78286}, /* U+7086 [2000] */ - {0xf57d, 0x00e78295}, /* U+7095 [2000] */ - {0xf57e, 0x00e78297}, /* U+7097 [2000] */ - {0xf580, 0x00e782bb}, /* U+70BB [2000] */ + {0xf56d, 0xe780b9}, /* U+7039 [2000] */ + {0xf56e, 0xe780ba}, /* U+703A [2000] */ + {0xf56f, 0xe780bc}, /* U+703C [2000] */ + {0xf570, 0xe78183}, /* U+7043 [2000] */ + {0xf571, 0xe78187}, /* U+7047 [2000] */ + {0xf572, 0xe7818b}, /* U+704B [2000] */ + {0xf573, 0xe3b69a}, /* U+3D9A [2000] */ + {0xf574, 0xe78194}, /* U+7054 [2000] */ + {0xf575, 0xe781a5}, /* U+7065 [2000] */ + {0xf576, 0xe781a9}, /* U+7069 [2000] */ + {0xf577, 0xe781ac}, /* U+706C [2000] */ + {0xf578, 0xe781ae}, /* U+706E [2000] */ + {0xf579, 0xe781b6}, /* U+7076 [2000] */ + {0xf57a, 0xe781be}, /* U+707E [2000] */ + {0xf57b, 0xe78281}, /* U+7081 [2000] */ + {0xf57c, 0xe78286}, /* U+7086 [2000] */ + {0xf57d, 0xe78295}, /* U+7095 [2000] */ + {0xf57e, 0xe78297}, /* U+7097 [2000] */ + {0xf580, 0xe782bb}, /* U+70BB [2000] */ {0xf581, 0xf0a48786}, /* U+241C6 [2000] [Unicode3.1] */ - {0xf582, 0x00e7829f}, /* U+709F [2000] */ - {0xf583, 0x00e782b1}, /* U+70B1 [2000] */ + {0xf582, 0xe7829f}, /* U+709F [2000] */ + {0xf583, 0xe782b1}, /* U+70B1 [2000] */ {0xf584, 0xf0a487be}, /* U+241FE [2000] [Unicode3.1] */ - {0xf585, 0x00e783ac}, /* U+70EC [2000] */ - {0xf586, 0x00e7838a}, /* U+70CA [2000] */ - {0xf587, 0x00e78391}, /* U+70D1 [2000] */ - {0xf588, 0x00e78393}, /* U+70D3 [2000] */ - {0xf589, 0x00e7839c}, /* U+70DC [2000] */ - {0xf58a, 0x00e78483}, /* U+7103 [2000] */ - {0xf58b, 0x00e78484}, /* U+7104 [2000] */ - {0xf58c, 0x00e78486}, /* U+7106 [2000] */ - {0xf58d, 0x00e78487}, /* U+7107 [2000] */ - {0xf58e, 0x00e78488}, /* U+7108 [2000] */ - {0xf58f, 0x00e7848c}, /* U+710C [2000] */ - {0xf590, 0x00e3b780}, /* U+3DC0 [2000] */ - {0xf591, 0x00e784af}, /* U+712F [2000] */ - {0xf592, 0x00e784b1}, /* U+7131 [2000] */ - {0xf593, 0x00e78590}, /* U+7150 [2000] */ - {0xf594, 0x00e7858a}, /* U+714A [2000] */ - {0xf595, 0x00e78593}, /* U+7153 [2000] */ - {0xf596, 0x00e7859e}, /* U+715E [2000] */ - {0xf597, 0x00e3b794}, /* U+3DD4 [2000] */ - {0xf598, 0x00e78696}, /* U+7196 [2000] */ - {0xf599, 0x00e78680}, /* U+7180 [2000] */ - {0xf59a, 0x00e7869b}, /* U+719B [2000] */ - {0xf59b, 0x00e786a0}, /* U+71A0 [2000] */ - {0xf59c, 0x00e786a2}, /* U+71A2 [2000] */ - {0xf59d, 0x00e786ae}, /* U+71AE [2000] */ - {0xf59e, 0x00e786af}, /* U+71AF [2000] */ - {0xf59f, 0x00e786b3}, /* U+71B3 [2000] */ + {0xf585, 0xe783ac}, /* U+70EC [2000] */ + {0xf586, 0xe7838a}, /* U+70CA [2000] */ + {0xf587, 0xe78391}, /* U+70D1 [2000] */ + {0xf588, 0xe78393}, /* U+70D3 [2000] */ + {0xf589, 0xe7839c}, /* U+70DC [2000] */ + {0xf58a, 0xe78483}, /* U+7103 [2000] */ + {0xf58b, 0xe78484}, /* U+7104 [2000] */ + {0xf58c, 0xe78486}, /* U+7106 [2000] */ + {0xf58d, 0xe78487}, /* U+7107 [2000] */ + {0xf58e, 0xe78488}, /* U+7108 [2000] */ + {0xf58f, 0xe7848c}, /* U+710C [2000] */ + {0xf590, 0xe3b780}, /* U+3DC0 [2000] */ + {0xf591, 0xe784af}, /* U+712F [2000] */ + {0xf592, 0xe784b1}, /* U+7131 [2000] */ + {0xf593, 0xe78590}, /* U+7150 [2000] */ + {0xf594, 0xe7858a}, /* U+714A [2000] */ + {0xf595, 0xe78593}, /* U+7153 [2000] */ + {0xf596, 0xe7859e}, /* U+715E [2000] */ + {0xf597, 0xe3b794}, /* U+3DD4 [2000] */ + {0xf598, 0xe78696}, /* U+7196 [2000] */ + {0xf599, 0xe78680}, /* U+7180 [2000] */ + {0xf59a, 0xe7869b}, /* U+719B [2000] */ + {0xf59b, 0xe786a0}, /* U+71A0 [2000] */ + {0xf59c, 0xe786a2}, /* U+71A2 [2000] */ + {0xf59d, 0xe786ae}, /* U+71AE [2000] */ + {0xf59e, 0xe786af}, /* U+71AF [2000] */ + {0xf59f, 0xe786b3}, /* U+71B3 [2000] */ {0xf5a0, 0xf0a48ebc}, /* U+243BC [2000] [Unicode3.1] */ - {0xf5a1, 0x00e7878b}, /* U+71CB [2000] */ - {0xf5a2, 0x00e78793}, /* U+71D3 [2000] */ - {0xf5a3, 0x00e78799}, /* U+71D9 [2000] */ - {0xf5a4, 0x00e7879c}, /* U+71DC [2000] */ - {0xf5a5, 0x00e78887}, /* U+7207 [2000] */ - {0xf5a6, 0x00e3b885}, /* U+3E05 [2000] */ - {0xf5a7, 0x00efa989}, /* U+FA49 CJK COMPATIBILITY IDEOGRAPH-FA49 [2000] [Unicode3.2] */ - {0xf5a8, 0x00e788ab}, /* U+722B [2000] */ - {0xf5a9, 0x00e788b4}, /* U+7234 [2000] */ - {0xf5aa, 0x00e788b8}, /* U+7238 [2000] */ - {0xf5ab, 0x00e788b9}, /* U+7239 [2000] */ - {0xf5ac, 0x00e4b8ac}, /* U+4E2C [2000] */ - {0xf5ad, 0x00e78982}, /* U+7242 [2000] */ - {0xf5ae, 0x00e78993}, /* U+7253 [2000] */ - {0xf5af, 0x00e78997}, /* U+7257 [2000] */ - {0xf5b0, 0x00e789a3}, /* U+7263 [2000] */ + {0xf5a1, 0xe7878b}, /* U+71CB [2000] */ + {0xf5a2, 0xe78793}, /* U+71D3 [2000] */ + {0xf5a3, 0xe78799}, /* U+71D9 [2000] */ + {0xf5a4, 0xe7879c}, /* U+71DC [2000] */ + {0xf5a5, 0xe78887}, /* U+7207 [2000] */ + {0xf5a6, 0xe3b885}, /* U+3E05 [2000] */ + {0xf5a7, 0xefa989}, /* U+FA49 CJK COMPATIBILITY IDEOGRAPH-FA49 [2000] [Unicode3.2] */ + {0xf5a8, 0xe788ab}, /* U+722B [2000] */ + {0xf5a9, 0xe788b4}, /* U+7234 [2000] */ + {0xf5aa, 0xe788b8}, /* U+7238 [2000] */ + {0xf5ab, 0xe788b9}, /* U+7239 [2000] */ + {0xf5ac, 0xe4b8ac}, /* U+4E2C [2000] */ + {0xf5ad, 0xe78982}, /* U+7242 [2000] */ + {0xf5ae, 0xe78993}, /* U+7253 [2000] */ + {0xf5af, 0xe78997}, /* U+7257 [2000] */ + {0xf5b0, 0xe789a3}, /* U+7263 [2000] */ {0xf5b1, 0xf0a498a9}, /* U+24629 [2000] [Unicode3.1] */ - {0xf5b2, 0x00e789ae}, /* U+726E [2000] */ - {0xf5b3, 0x00e789af}, /* U+726F [2000] */ - {0xf5b4, 0x00e789b8}, /* U+7278 [2000] */ - {0xf5b5, 0x00e789bf}, /* U+727F [2000] */ - {0xf5b6, 0x00e78a8e}, /* U+728E [2000] */ + {0xf5b2, 0xe789ae}, /* U+726E [2000] */ + {0xf5b3, 0xe789af}, /* U+726F [2000] */ + {0xf5b4, 0xe789b8}, /* U+7278 [2000] */ + {0xf5b5, 0xe789bf}, /* U+727F [2000] */ + {0xf5b6, 0xe78a8e}, /* U+728E [2000] */ {0xf5b7, 0xf0a49aa5}, /* U+246A5 [2000] [Unicode3.1] */ - {0xf5b8, 0x00e78aad}, /* U+72AD [2000] */ - {0xf5b9, 0x00e78aae}, /* U+72AE [2000] */ - {0xf5ba, 0x00e78ab0}, /* U+72B0 [2000] */ - {0xf5bb, 0x00e78ab1}, /* U+72B1 [2000] */ - {0xf5bc, 0x00e78b81}, /* U+72C1 [2000] */ - {0xf5bd, 0x00e3b9a0}, /* U+3E60 [2000] */ - {0xf5be, 0x00e78b8c}, /* U+72CC [2000] */ - {0xf5bf, 0x00e3b9a6}, /* U+3E66 [2000] */ - {0xf5c0, 0x00e3b9a8}, /* U+3E68 [2000] */ - {0xf5c1, 0x00e78bb3}, /* U+72F3 [2000] */ - {0xf5c2, 0x00e78bba}, /* U+72FA [2000] */ - {0xf5c3, 0x00e78c87}, /* U+7307 [2000] */ - {0xf5c4, 0x00e78c92}, /* U+7312 [2000] */ - {0xf5c5, 0x00e78c98}, /* U+7318 [2000] */ - {0xf5c6, 0x00e78c99}, /* U+7319 [2000] */ - {0xf5c7, 0x00e3ba83}, /* U+3E83 [2000] */ - {0xf5c8, 0x00e78cb9}, /* U+7339 [2000] */ - {0xf5c9, 0x00e78cac}, /* U+732C [2000] */ - {0xf5ca, 0x00e78cb1}, /* U+7331 [2000] */ - {0xf5cb, 0x00e78cb3}, /* U+7333 [2000] */ - {0xf5cc, 0x00e78cbd}, /* U+733D [2000] */ - {0xf5cd, 0x00e78d92}, /* U+7352 [2000] */ - {0xf5ce, 0x00e3ba94}, /* U+3E94 [2000] */ - {0xf5cf, 0x00e78dab}, /* U+736B [2000] */ - {0xf5d0, 0x00e78dac}, /* U+736C [2000] */ + {0xf5b8, 0xe78aad}, /* U+72AD [2000] */ + {0xf5b9, 0xe78aae}, /* U+72AE [2000] */ + {0xf5ba, 0xe78ab0}, /* U+72B0 [2000] */ + {0xf5bb, 0xe78ab1}, /* U+72B1 [2000] */ + {0xf5bc, 0xe78b81}, /* U+72C1 [2000] */ + {0xf5bd, 0xe3b9a0}, /* U+3E60 [2000] */ + {0xf5be, 0xe78b8c}, /* U+72CC [2000] */ + {0xf5bf, 0xe3b9a6}, /* U+3E66 [2000] */ + {0xf5c0, 0xe3b9a8}, /* U+3E68 [2000] */ + {0xf5c1, 0xe78bb3}, /* U+72F3 [2000] */ + {0xf5c2, 0xe78bba}, /* U+72FA [2000] */ + {0xf5c3, 0xe78c87}, /* U+7307 [2000] */ + {0xf5c4, 0xe78c92}, /* U+7312 [2000] */ + {0xf5c5, 0xe78c98}, /* U+7318 [2000] */ + {0xf5c6, 0xe78c99}, /* U+7319 [2000] */ + {0xf5c7, 0xe3ba83}, /* U+3E83 [2000] */ + {0xf5c8, 0xe78cb9}, /* U+7339 [2000] */ + {0xf5c9, 0xe78cac}, /* U+732C [2000] */ + {0xf5ca, 0xe78cb1}, /* U+7331 [2000] */ + {0xf5cb, 0xe78cb3}, /* U+7333 [2000] */ + {0xf5cc, 0xe78cbd}, /* U+733D [2000] */ + {0xf5cd, 0xe78d92}, /* U+7352 [2000] */ + {0xf5ce, 0xe3ba94}, /* U+3E94 [2000] */ + {0xf5cf, 0xe78dab}, /* U+736B [2000] */ + {0xf5d0, 0xe78dac}, /* U+736C [2000] */ {0xf5d1, 0xf0a4a296}, /* U+24896 [2000] [Unicode3.1] */ - {0xf5d2, 0x00e78dae}, /* U+736E [2000] */ - {0xf5d3, 0x00e78daf}, /* U+736F [2000] */ - {0xf5d4, 0x00e78db1}, /* U+7371 [2000] */ - {0xf5d5, 0x00e78db7}, /* U+7377 [2000] */ - {0xf5d6, 0x00e78e81}, /* U+7381 [2000] */ - {0xf5d7, 0x00e78e85}, /* U+7385 [2000] */ - {0xf5d8, 0x00e78e8a}, /* U+738A [2000] */ - {0xf5d9, 0x00e78e94}, /* U+7394 [2000] */ - {0xf5da, 0x00e78e98}, /* U+7398 [2000] */ - {0xf5db, 0x00e78e9c}, /* U+739C [2000] */ - {0xf5dc, 0x00e78e9e}, /* U+739E [2000] */ - {0xf5dd, 0x00e78ea5}, /* U+73A5 [2000] */ - {0xf5de, 0x00e78ea8}, /* U+73A8 [2000] */ - {0xf5df, 0x00e78eb5}, /* U+73B5 [2000] */ - {0xf5e0, 0x00e78eb7}, /* U+73B7 [2000] */ - {0xf5e1, 0x00e78eb9}, /* U+73B9 [2000] */ - {0xf5e2, 0x00e78ebc}, /* U+73BC [2000] */ - {0xf5e3, 0x00e78ebf}, /* U+73BF [2000] */ - {0xf5e4, 0x00e78f85}, /* U+73C5 [2000] */ - {0xf5e5, 0x00e78f8b}, /* U+73CB [2000] */ - {0xf5e6, 0x00e78fa1}, /* U+73E1 [2000] */ - {0xf5e7, 0x00e78fa7}, /* U+73E7 [2000] */ - {0xf5e8, 0x00e78fb9}, /* U+73F9 [2000] */ - {0xf5e9, 0x00e79093}, /* U+7413 [2000] */ - {0xf5ea, 0x00e78fba}, /* U+73FA [2000] */ - {0xf5eb, 0x00e79081}, /* U+7401 [2000] */ - {0xf5ec, 0x00e790a4}, /* U+7424 [2000] */ - {0xf5ed, 0x00e790b1}, /* U+7431 [2000] */ - {0xf5ee, 0x00e790b9}, /* U+7439 [2000] */ - {0xf5ef, 0x00e79193}, /* U+7453 [2000] */ - {0xf5f0, 0x00e79180}, /* U+7440 [2000] */ - {0xf5f1, 0x00e79183}, /* U+7443 [2000] */ - {0xf5f2, 0x00e7918d}, /* U+744D [2000] */ - {0xf5f3, 0x00e79192}, /* U+7452 [2000] */ - {0xf5f4, 0x00e7919d}, /* U+745D [2000] */ - {0xf5f5, 0x00e791b1}, /* U+7471 [2000] */ - {0xf5f6, 0x00e79281}, /* U+7481 [2000] */ - {0xf5f7, 0x00e79285}, /* U+7485 [2000] */ - {0xf5f8, 0x00e79288}, /* U+7488 [2000] */ + {0xf5d2, 0xe78dae}, /* U+736E [2000] */ + {0xf5d3, 0xe78daf}, /* U+736F [2000] */ + {0xf5d4, 0xe78db1}, /* U+7371 [2000] */ + {0xf5d5, 0xe78db7}, /* U+7377 [2000] */ + {0xf5d6, 0xe78e81}, /* U+7381 [2000] */ + {0xf5d7, 0xe78e85}, /* U+7385 [2000] */ + {0xf5d8, 0xe78e8a}, /* U+738A [2000] */ + {0xf5d9, 0xe78e94}, /* U+7394 [2000] */ + {0xf5da, 0xe78e98}, /* U+7398 [2000] */ + {0xf5db, 0xe78e9c}, /* U+739C [2000] */ + {0xf5dc, 0xe78e9e}, /* U+739E [2000] */ + {0xf5dd, 0xe78ea5}, /* U+73A5 [2000] */ + {0xf5de, 0xe78ea8}, /* U+73A8 [2000] */ + {0xf5df, 0xe78eb5}, /* U+73B5 [2000] */ + {0xf5e0, 0xe78eb7}, /* U+73B7 [2000] */ + {0xf5e1, 0xe78eb9}, /* U+73B9 [2000] */ + {0xf5e2, 0xe78ebc}, /* U+73BC [2000] */ + {0xf5e3, 0xe78ebf}, /* U+73BF [2000] */ + {0xf5e4, 0xe78f85}, /* U+73C5 [2000] */ + {0xf5e5, 0xe78f8b}, /* U+73CB [2000] */ + {0xf5e6, 0xe78fa1}, /* U+73E1 [2000] */ + {0xf5e7, 0xe78fa7}, /* U+73E7 [2000] */ + {0xf5e8, 0xe78fb9}, /* U+73F9 [2000] */ + {0xf5e9, 0xe79093}, /* U+7413 [2000] */ + {0xf5ea, 0xe78fba}, /* U+73FA [2000] */ + {0xf5eb, 0xe79081}, /* U+7401 [2000] */ + {0xf5ec, 0xe790a4}, /* U+7424 [2000] */ + {0xf5ed, 0xe790b1}, /* U+7431 [2000] */ + {0xf5ee, 0xe790b9}, /* U+7439 [2000] */ + {0xf5ef, 0xe79193}, /* U+7453 [2000] */ + {0xf5f0, 0xe79180}, /* U+7440 [2000] */ + {0xf5f1, 0xe79183}, /* U+7443 [2000] */ + {0xf5f2, 0xe7918d}, /* U+744D [2000] */ + {0xf5f3, 0xe79192}, /* U+7452 [2000] */ + {0xf5f4, 0xe7919d}, /* U+745D [2000] */ + {0xf5f5, 0xe791b1}, /* U+7471 [2000] */ + {0xf5f6, 0xe79281}, /* U+7481 [2000] */ + {0xf5f7, 0xe79285}, /* U+7485 [2000] */ + {0xf5f8, 0xe79288}, /* U+7488 [2000] */ {0xf5f9, 0xf0a4a98d}, /* U+24A4D [2000] [Unicode3.1] */ - {0xf5fa, 0x00e79292}, /* U+7492 [2000] */ - {0xf5fb, 0x00e79297}, /* U+7497 [2000] */ - {0xf5fc, 0x00e79299}, /* U+7499 [2000] */ - {0xf640, 0x00e792a0}, /* U+74A0 [2000] */ - {0xf641, 0x00e792a1}, /* U+74A1 [2000] */ - {0xf642, 0x00e792a5}, /* U+74A5 [2000] */ - {0xf643, 0x00e792aa}, /* U+74AA [2000] */ - {0xf644, 0x00e792ab}, /* U+74AB [2000] */ - {0xf645, 0x00e792b9}, /* U+74B9 [2000] */ - {0xf646, 0x00e792bb}, /* U+74BB [2000] */ - {0xf647, 0x00e792ba}, /* U+74BA [2000] */ - {0xf648, 0x00e79396}, /* U+74D6 [2000] */ - {0xf649, 0x00e79398}, /* U+74D8 [2000] */ - {0xf64a, 0x00e7939e}, /* U+74DE [2000] */ - {0xf64b, 0x00e793af}, /* U+74EF [2000] */ - {0xf64c, 0x00e793ab}, /* U+74EB [2000] */ + {0xf5fa, 0xe79292}, /* U+7492 [2000] */ + {0xf5fb, 0xe79297}, /* U+7497 [2000] */ + {0xf5fc, 0xe79299}, /* U+7499 [2000] */ + {0xf640, 0xe792a0}, /* U+74A0 [2000] */ + {0xf641, 0xe792a1}, /* U+74A1 [2000] */ + {0xf642, 0xe792a5}, /* U+74A5 [2000] */ + {0xf643, 0xe792aa}, /* U+74AA [2000] */ + {0xf644, 0xe792ab}, /* U+74AB [2000] */ + {0xf645, 0xe792b9}, /* U+74B9 [2000] */ + {0xf646, 0xe792bb}, /* U+74BB [2000] */ + {0xf647, 0xe792ba}, /* U+74BA [2000] */ + {0xf648, 0xe79396}, /* U+74D6 [2000] */ + {0xf649, 0xe79398}, /* U+74D8 [2000] */ + {0xf64a, 0xe7939e}, /* U+74DE [2000] */ + {0xf64b, 0xe793af}, /* U+74EF [2000] */ + {0xf64c, 0xe793ab}, /* U+74EB [2000] */ {0xf64d, 0xf0a4ad96}, /* U+24B56 [2000] [Unicode3.1] */ - {0xf64e, 0x00e793ba}, /* U+74FA [2000] */ + {0xf64e, 0xe793ba}, /* U+74FA [2000] */ {0xf64f, 0xf0a4adaf}, /* U+24B6F [2000] [Unicode3.1] */ - {0xf650, 0x00e794a0}, /* U+7520 [2000] */ - {0xf651, 0x00e794a4}, /* U+7524 [2000] */ - {0xf652, 0x00e794aa}, /* U+752A [2000] */ - {0xf653, 0x00e3bd97}, /* U+3F57 [2000] */ + {0xf650, 0xe794a0}, /* U+7520 [2000] */ + {0xf651, 0xe794a4}, /* U+7524 [2000] */ + {0xf652, 0xe794aa}, /* U+752A [2000] */ + {0xf653, 0xe3bd97}, /* U+3F57 [2000] */ {0xf654, 0xf0a4b096}, /* U+24C16 [2000] [Unicode3.1] */ - {0xf655, 0x00e794bd}, /* U+753D [2000] */ - {0xf656, 0x00e794be}, /* U+753E [2000] */ - {0xf657, 0x00e79580}, /* U+7540 [2000] */ - {0xf658, 0x00e79588}, /* U+7548 [2000] */ - {0xf659, 0x00e7958e}, /* U+754E [2000] */ - {0xf65a, 0x00e79590}, /* U+7550 [2000] */ - {0xf65b, 0x00e79592}, /* U+7552 [2000] */ - {0xf65c, 0x00e795ac}, /* U+756C [2000] */ - {0xf65d, 0x00e795b2}, /* U+7572 [2000] */ - {0xf65e, 0x00e795b1}, /* U+7571 [2000] */ - {0xf65f, 0x00e795ba}, /* U+757A [2000] */ - {0xf660, 0x00e795bd}, /* U+757D [2000] */ - {0xf661, 0x00e795be}, /* U+757E [2000] */ - {0xf662, 0x00e79681}, /* U+7581 [2000] */ + {0xf655, 0xe794bd}, /* U+753D [2000] */ + {0xf656, 0xe794be}, /* U+753E [2000] */ + {0xf657, 0xe79580}, /* U+7540 [2000] */ + {0xf658, 0xe79588}, /* U+7548 [2000] */ + {0xf659, 0xe7958e}, /* U+754E [2000] */ + {0xf65a, 0xe79590}, /* U+7550 [2000] */ + {0xf65b, 0xe79592}, /* U+7552 [2000] */ + {0xf65c, 0xe795ac}, /* U+756C [2000] */ + {0xf65d, 0xe795b2}, /* U+7572 [2000] */ + {0xf65e, 0xe795b1}, /* U+7571 [2000] */ + {0xf65f, 0xe795ba}, /* U+757A [2000] */ + {0xf660, 0xe795bd}, /* U+757D [2000] */ + {0xf661, 0xe795be}, /* U+757E [2000] */ + {0xf662, 0xe79681}, /* U+7581 [2000] */ {0xf663, 0xf0a4b494}, /* U+24D14 [2000] [Unicode3.1] */ - {0xf664, 0x00e7968c}, /* U+758C [2000] */ - {0xf665, 0x00e3bdb5}, /* U+3F75 [2000] */ - {0xf666, 0x00e796a2}, /* U+75A2 [2000] */ - {0xf667, 0x00e3bdb7}, /* U+3F77 [2000] */ - {0xf668, 0x00e796b0}, /* U+75B0 [2000] */ - {0xf669, 0x00e796b7}, /* U+75B7 [2000] */ - {0xf66a, 0x00e796bf}, /* U+75BF [2000] */ - {0xf66b, 0x00e79780}, /* U+75C0 [2000] */ - {0xf66c, 0x00e79786}, /* U+75C6 [2000] */ - {0xf66d, 0x00e7978f}, /* U+75CF [2000] */ - {0xf66e, 0x00e79793}, /* U+75D3 [2000] */ - {0xf66f, 0x00e7979d}, /* U+75DD [2000] */ - {0xf670, 0x00e7979f}, /* U+75DF [2000] */ - {0xf671, 0x00e797a0}, /* U+75E0 [2000] */ - {0xf672, 0x00e797a7}, /* U+75E7 [2000] */ - {0xf673, 0x00e797ac}, /* U+75EC [2000] */ - {0xf674, 0x00e797ae}, /* U+75EE [2000] */ - {0xf675, 0x00e797b1}, /* U+75F1 [2000] */ - {0xf676, 0x00e797b9}, /* U+75F9 [2000] */ - {0xf677, 0x00e79883}, /* U+7603 [2000] */ - {0xf678, 0x00e79898}, /* U+7618 [2000] */ - {0xf679, 0x00e79887}, /* U+7607 [2000] */ - {0xf67a, 0x00e7988f}, /* U+760F [2000] */ - {0xf67b, 0x00e3beae}, /* U+3FAE [2000] */ + {0xf664, 0xe7968c}, /* U+758C [2000] */ + {0xf665, 0xe3bdb5}, /* U+3F75 [2000] */ + {0xf666, 0xe796a2}, /* U+75A2 [2000] */ + {0xf667, 0xe3bdb7}, /* U+3F77 [2000] */ + {0xf668, 0xe796b0}, /* U+75B0 [2000] */ + {0xf669, 0xe796b7}, /* U+75B7 [2000] */ + {0xf66a, 0xe796bf}, /* U+75BF [2000] */ + {0xf66b, 0xe79780}, /* U+75C0 [2000] */ + {0xf66c, 0xe79786}, /* U+75C6 [2000] */ + {0xf66d, 0xe7978f}, /* U+75CF [2000] */ + {0xf66e, 0xe79793}, /* U+75D3 [2000] */ + {0xf66f, 0xe7979d}, /* U+75DD [2000] */ + {0xf670, 0xe7979f}, /* U+75DF [2000] */ + {0xf671, 0xe797a0}, /* U+75E0 [2000] */ + {0xf672, 0xe797a7}, /* U+75E7 [2000] */ + {0xf673, 0xe797ac}, /* U+75EC [2000] */ + {0xf674, 0xe797ae}, /* U+75EE [2000] */ + {0xf675, 0xe797b1}, /* U+75F1 [2000] */ + {0xf676, 0xe797b9}, /* U+75F9 [2000] */ + {0xf677, 0xe79883}, /* U+7603 [2000] */ + {0xf678, 0xe79898}, /* U+7618 [2000] */ + {0xf679, 0xe79887}, /* U+7607 [2000] */ + {0xf67a, 0xe7988f}, /* U+760F [2000] */ + {0xf67b, 0xe3beae}, /* U+3FAE [2000] */ {0xf67c, 0xf0a4b88e}, /* U+24E0E [2000] [Unicode3.1] */ - {0xf67d, 0x00e79893}, /* U+7613 [2000] */ - {0xf67e, 0x00e7989b}, /* U+761B [2000] */ - {0xf680, 0x00e7989c}, /* U+761C [2000] */ + {0xf67d, 0xe79893}, /* U+7613 [2000] */ + {0xf67e, 0xe7989b}, /* U+761B [2000] */ + {0xf680, 0xe7989c}, /* U+761C [2000] */ {0xf681, 0xf0a4b8b7}, /* U+24E37 [2000] [Unicode3.1] */ - {0xf682, 0x00e798a5}, /* U+7625 [2000] */ - {0xf683, 0x00e798a8}, /* U+7628 [2000] */ - {0xf684, 0x00e798bc}, /* U+763C [2000] */ - {0xf685, 0x00e798b3}, /* U+7633 [2000] */ + {0xf682, 0xe798a5}, /* U+7625 [2000] */ + {0xf683, 0xe798a8}, /* U+7628 [2000] */ + {0xf684, 0xe798bc}, /* U+763C [2000] */ + {0xf685, 0xe798b3}, /* U+7633 [2000] */ {0xf686, 0xf0a4b9aa}, /* U+24E6A [2000] [Unicode3.1] */ - {0xf687, 0x00e3bf89}, /* U+3FC9 [2000] */ - {0xf688, 0x00e79981}, /* U+7641 [2000] */ + {0xf687, 0xe3bf89}, /* U+3FC9 [2000] */ + {0xf688, 0xe79981}, /* U+7641 [2000] */ {0xf689, 0xf0a4ba8b}, /* U+24E8B [2000] [Unicode3.1] */ - {0xf68a, 0x00e79989}, /* U+7649 [2000] */ - {0xf68b, 0x00e79995}, /* U+7655 [2000] */ - {0xf68c, 0x00e3bf97}, /* U+3FD7 [2000] */ - {0xf68d, 0x00e799ae}, /* U+766E [2000] */ - {0xf68e, 0x00e79a95}, /* U+7695 [2000] */ - {0xf68f, 0x00e79a9c}, /* U+769C [2000] */ - {0xf690, 0x00e79aa1}, /* U+76A1 [2000] */ - {0xf691, 0x00e79aa0}, /* U+76A0 [2000] */ - {0xf692, 0x00e79aa7}, /* U+76A7 [2000] */ - {0xf693, 0x00e79aa8}, /* U+76A8 [2000] */ - {0xf694, 0x00e79aaf}, /* U+76AF [2000] */ + {0xf68a, 0xe79989}, /* U+7649 [2000] */ + {0xf68b, 0xe79995}, /* U+7655 [2000] */ + {0xf68c, 0xe3bf97}, /* U+3FD7 [2000] */ + {0xf68d, 0xe799ae}, /* U+766E [2000] */ + {0xf68e, 0xe79a95}, /* U+7695 [2000] */ + {0xf68f, 0xe79a9c}, /* U+769C [2000] */ + {0xf690, 0xe79aa1}, /* U+76A1 [2000] */ + {0xf691, 0xe79aa0}, /* U+76A0 [2000] */ + {0xf692, 0xe79aa7}, /* U+76A7 [2000] */ + {0xf693, 0xe79aa8}, /* U+76A8 [2000] */ + {0xf694, 0xe79aaf}, /* U+76AF [2000] */ {0xf695, 0xf0a5818a}, /* U+2504A [2000] [Unicode3.1] */ - {0xf696, 0x00e79b89}, /* U+76C9 [2000] */ + {0xf696, 0xe79b89}, /* U+76C9 [2000] */ {0xf697, 0xf0a58195}, /* U+25055 [2000] [Unicode3.1] */ - {0xf698, 0x00e79ba8}, /* U+76E8 [2000] */ - {0xf699, 0x00e79bac}, /* U+76EC [2000] */ + {0xf698, 0xe79ba8}, /* U+76E8 [2000] */ + {0xf699, 0xe79bac}, /* U+76EC [2000] */ {0xf69a, 0xf0a584a2}, /* U+25122 [2000] [Unicode3.1] */ - {0xf69b, 0x00e79c97}, /* U+7717 [2000] */ - {0xf69c, 0x00e79c9a}, /* U+771A [2000] */ - {0xf69d, 0x00e79cad}, /* U+772D [2000] */ - {0xf69e, 0x00e79cb5}, /* U+7735 [2000] */ + {0xf69b, 0xe79c97}, /* U+7717 [2000] */ + {0xf69c, 0xe79c9a}, /* U+771A [2000] */ + {0xf69d, 0xe79cad}, /* U+772D [2000] */ + {0xf69e, 0xe79cb5}, /* U+7735 [2000] */ {0xf69f, 0xf0a586a9}, /* U+251A9 [2000] [Unicode3.1] */ - {0xf6a0, 0x00e480b9}, /* U+4039 [2000] */ + {0xf6a0, 0xe480b9}, /* U+4039 [2000] */ {0xf6a1, 0xf0a587a5}, /* U+251E5 [2000] [Unicode3.1] */ {0xf6a2, 0xf0a5878d}, /* U+251CD [2000] [Unicode3.1] */ - {0xf6a3, 0x00e79d98}, /* U+7758 [2000] */ - {0xf6a4, 0x00e79da0}, /* U+7760 [2000] */ - {0xf6a5, 0x00e79daa}, /* U+776A [2000] */ + {0xf6a3, 0xe79d98}, /* U+7758 [2000] */ + {0xf6a4, 0xe79da0}, /* U+7760 [2000] */ + {0xf6a5, 0xe79daa}, /* U+776A [2000] */ {0xf6a6, 0xf0a5889e}, /* U+2521E [2000] [Unicode3.1] */ - {0xf6a7, 0x00e79db2}, /* U+7772 [2000] */ - {0xf6a8, 0x00e79dbc}, /* U+777C [2000] */ - {0xf6a9, 0x00e79dbd}, /* U+777D [2000] */ + {0xf6a7, 0xe79db2}, /* U+7772 [2000] */ + {0xf6a8, 0xe79dbc}, /* U+777C [2000] */ + {0xf6a9, 0xe79dbd}, /* U+777D [2000] */ {0xf6aa, 0xf0a5898c}, /* U+2524C [2000] [Unicode3.1] */ - {0xf6ab, 0x00e48198}, /* U+4058 [2000] */ - {0xf6ac, 0x00e79e9a}, /* U+779A [2000] */ - {0xf6ad, 0x00e79e9f}, /* U+779F [2000] */ - {0xf6ae, 0x00e79ea2}, /* U+77A2 [2000] */ - {0xf6af, 0x00e79ea4}, /* U+77A4 [2000] */ - {0xf6b0, 0x00e79ea9}, /* U+77A9 [2000] */ - {0xf6b1, 0x00e79f9e}, /* U+77DE [2000] */ - {0xf6b2, 0x00e79f9f}, /* U+77DF [2000] */ - {0xf6b3, 0x00e79fa4}, /* U+77E4 [2000] */ - {0xf6b4, 0x00e79fa6}, /* U+77E6 [2000] */ - {0xf6b5, 0x00e79faa}, /* U+77EA [2000] */ - {0xf6b6, 0x00e79fac}, /* U+77EC [2000] */ - {0xf6b7, 0x00e48293}, /* U+4093 [2000] */ - {0xf6b8, 0x00e79fb0}, /* U+77F0 [2000] */ - {0xf6b9, 0x00e79fb4}, /* U+77F4 [2000] */ - {0xf6ba, 0x00e79fbb}, /* U+77FB [2000] */ + {0xf6ab, 0xe48198}, /* U+4058 [2000] */ + {0xf6ac, 0xe79e9a}, /* U+779A [2000] */ + {0xf6ad, 0xe79e9f}, /* U+779F [2000] */ + {0xf6ae, 0xe79ea2}, /* U+77A2 [2000] */ + {0xf6af, 0xe79ea4}, /* U+77A4 [2000] */ + {0xf6b0, 0xe79ea9}, /* U+77A9 [2000] */ + {0xf6b1, 0xe79f9e}, /* U+77DE [2000] */ + {0xf6b2, 0xe79f9f}, /* U+77DF [2000] */ + {0xf6b3, 0xe79fa4}, /* U+77E4 [2000] */ + {0xf6b4, 0xe79fa6}, /* U+77E6 [2000] */ + {0xf6b5, 0xe79faa}, /* U+77EA [2000] */ + {0xf6b6, 0xe79fac}, /* U+77EC [2000] */ + {0xf6b7, 0xe48293}, /* U+4093 [2000] */ + {0xf6b8, 0xe79fb0}, /* U+77F0 [2000] */ + {0xf6b9, 0xe79fb4}, /* U+77F4 [2000] */ + {0xf6ba, 0xe79fbb}, /* U+77FB [2000] */ {0xf6bb, 0xf0a590ae}, /* U+2542E [2000] [Unicode3.1] */ - {0xf6bc, 0x00e7a085}, /* U+7805 [2000] */ - {0xf6bd, 0x00e7a086}, /* U+7806 [2000] */ - {0xf6be, 0x00e7a089}, /* U+7809 [2000] */ - {0xf6bf, 0x00e7a08d}, /* U+780D [2000] */ - {0xf6c0, 0x00e7a099}, /* U+7819 [2000] */ - {0xf6c1, 0x00e7a0a1}, /* U+7821 [2000] */ - {0xf6c2, 0x00e7a0ac}, /* U+782C [2000] */ - {0xf6c3, 0x00e7a187}, /* U+7847 [2000] */ - {0xf6c4, 0x00e7a1a4}, /* U+7864 [2000] */ - {0xf6c5, 0x00e7a1aa}, /* U+786A [2000] */ + {0xf6bc, 0xe7a085}, /* U+7805 [2000] */ + {0xf6bd, 0xe7a086}, /* U+7806 [2000] */ + {0xf6be, 0xe7a089}, /* U+7809 [2000] */ + {0xf6bf, 0xe7a08d}, /* U+780D [2000] */ + {0xf6c0, 0xe7a099}, /* U+7819 [2000] */ + {0xf6c1, 0xe7a0a1}, /* U+7821 [2000] */ + {0xf6c2, 0xe7a0ac}, /* U+782C [2000] */ + {0xf6c3, 0xe7a187}, /* U+7847 [2000] */ + {0xf6c4, 0xe7a1a4}, /* U+7864 [2000] */ + {0xf6c5, 0xe7a1aa}, /* U+786A [2000] */ {0xf6c6, 0xf0a59399}, /* U+254D9 [2000] [Unicode3.1] */ - {0xf6c7, 0x00e7a28a}, /* U+788A [2000] */ - {0xf6c8, 0x00e7a294}, /* U+7894 [2000] */ - {0xf6c9, 0x00e7a2a4}, /* U+78A4 [2000] */ - {0xf6ca, 0x00e7a29d}, /* U+789D [2000] */ - {0xf6cb, 0x00e7a29e}, /* U+789E [2000] */ - {0xf6cc, 0x00e7a29f}, /* U+789F [2000] */ - {0xf6cd, 0x00e7a2bb}, /* U+78BB [2000] */ - {0xf6ce, 0x00e7a388}, /* U+78C8 [2000] */ - {0xf6cf, 0x00e7a38c}, /* U+78CC [2000] */ - {0xf6d0, 0x00e7a38e}, /* U+78CE [2000] */ - {0xf6d1, 0x00e7a395}, /* U+78D5 [2000] */ - {0xf6d2, 0x00e7a3a0}, /* U+78E0 [2000] */ - {0xf6d3, 0x00e7a3a1}, /* U+78E1 [2000] */ - {0xf6d4, 0x00e7a3a6}, /* U+78E6 [2000] */ - {0xf6d5, 0x00e7a3b9}, /* U+78F9 [2000] */ - {0xf6d6, 0x00e7a3ba}, /* U+78FA [2000] */ - {0xf6d7, 0x00e7a3bb}, /* U+78FB [2000] */ - {0xf6d8, 0x00e7a3be}, /* U+78FE [2000] */ + {0xf6c7, 0xe7a28a}, /* U+788A [2000] */ + {0xf6c8, 0xe7a294}, /* U+7894 [2000] */ + {0xf6c9, 0xe7a2a4}, /* U+78A4 [2000] */ + {0xf6ca, 0xe7a29d}, /* U+789D [2000] */ + {0xf6cb, 0xe7a29e}, /* U+789E [2000] */ + {0xf6cc, 0xe7a29f}, /* U+789F [2000] */ + {0xf6cd, 0xe7a2bb}, /* U+78BB [2000] */ + {0xf6ce, 0xe7a388}, /* U+78C8 [2000] */ + {0xf6cf, 0xe7a38c}, /* U+78CC [2000] */ + {0xf6d0, 0xe7a38e}, /* U+78CE [2000] */ + {0xf6d1, 0xe7a395}, /* U+78D5 [2000] */ + {0xf6d2, 0xe7a3a0}, /* U+78E0 [2000] */ + {0xf6d3, 0xe7a3a1}, /* U+78E1 [2000] */ + {0xf6d4, 0xe7a3a6}, /* U+78E6 [2000] */ + {0xf6d5, 0xe7a3b9}, /* U+78F9 [2000] */ + {0xf6d6, 0xe7a3ba}, /* U+78FA [2000] */ + {0xf6d7, 0xe7a3bb}, /* U+78FB [2000] */ + {0xf6d8, 0xe7a3be}, /* U+78FE [2000] */ {0xf6d9, 0xf0a596a7}, /* U+255A7 [2000] [Unicode3.1] */ - {0xf6da, 0x00e7a490}, /* U+7910 [2000] */ - {0xf6db, 0x00e7a49b}, /* U+791B [2000] */ - {0xf6dc, 0x00e7a4b0}, /* U+7930 [2000] */ - {0xf6dd, 0x00e7a4a5}, /* U+7925 [2000] */ - {0xf6de, 0x00e7a4bb}, /* U+793B [2000] */ - {0xf6df, 0x00e7a58a}, /* U+794A [2000] */ - {0xf6e0, 0x00e7a598}, /* U+7958 [2000] */ - {0xf6e1, 0x00e7a59b}, /* U+795B [2000] */ - {0xf6e2, 0x00e48485}, /* U+4105 [2000] */ - {0xf6e3, 0x00e7a5a7}, /* U+7967 [2000] */ - {0xf6e4, 0x00e7a5b2}, /* U+7972 [2000] */ - {0xf6e5, 0x00e7a694}, /* U+7994 [2000] */ - {0xf6e6, 0x00e7a695}, /* U+7995 [2000] */ - {0xf6e7, 0x00e7a696}, /* U+7996 [2000] */ - {0xf6e8, 0x00e7a69b}, /* U+799B [2000] */ - {0xf6e9, 0x00e7a6a1}, /* U+79A1 [2000] */ - {0xf6ea, 0x00e7a6a9}, /* U+79A9 [2000] */ - {0xf6eb, 0x00e7a6b4}, /* U+79B4 [2000] */ - {0xf6ec, 0x00e7a6bb}, /* U+79BB [2000] */ - {0xf6ed, 0x00e7a782}, /* U+79C2 [2000] */ - {0xf6ee, 0x00e7a787}, /* U+79C7 [2000] */ - {0xf6ef, 0x00e7a78c}, /* U+79CC [2000] */ - {0xf6f0, 0x00e7a78d}, /* U+79CD [2000] */ - {0xf6f1, 0x00e7a796}, /* U+79D6 [2000] */ - {0xf6f2, 0x00e48588}, /* U+4148 [2000] */ + {0xf6da, 0xe7a490}, /* U+7910 [2000] */ + {0xf6db, 0xe7a49b}, /* U+791B [2000] */ + {0xf6dc, 0xe7a4b0}, /* U+7930 [2000] */ + {0xf6dd, 0xe7a4a5}, /* U+7925 [2000] */ + {0xf6de, 0xe7a4bb}, /* U+793B [2000] */ + {0xf6df, 0xe7a58a}, /* U+794A [2000] */ + {0xf6e0, 0xe7a598}, /* U+7958 [2000] */ + {0xf6e1, 0xe7a59b}, /* U+795B [2000] */ + {0xf6e2, 0xe48485}, /* U+4105 [2000] */ + {0xf6e3, 0xe7a5a7}, /* U+7967 [2000] */ + {0xf6e4, 0xe7a5b2}, /* U+7972 [2000] */ + {0xf6e5, 0xe7a694}, /* U+7994 [2000] */ + {0xf6e6, 0xe7a695}, /* U+7995 [2000] */ + {0xf6e7, 0xe7a696}, /* U+7996 [2000] */ + {0xf6e8, 0xe7a69b}, /* U+799B [2000] */ + {0xf6e9, 0xe7a6a1}, /* U+79A1 [2000] */ + {0xf6ea, 0xe7a6a9}, /* U+79A9 [2000] */ + {0xf6eb, 0xe7a6b4}, /* U+79B4 [2000] */ + {0xf6ec, 0xe7a6bb}, /* U+79BB [2000] */ + {0xf6ed, 0xe7a782}, /* U+79C2 [2000] */ + {0xf6ee, 0xe7a787}, /* U+79C7 [2000] */ + {0xf6ef, 0xe7a78c}, /* U+79CC [2000] */ + {0xf6f0, 0xe7a78d}, /* U+79CD [2000] */ + {0xf6f1, 0xe7a796}, /* U+79D6 [2000] */ + {0xf6f2, 0xe48588}, /* U+4148 [2000] */ {0xf6f3, 0xf0a59ea9}, /* U+257A9 [2000] [Unicode3.1] */ {0xf6f4, 0xf0a59eb4}, /* U+257B4 [2000] [Unicode3.1] */ - {0xf6f5, 0x00e4858f}, /* U+414F [2000] */ - {0xf6f6, 0x00e7a88a}, /* U+7A0A [2000] */ - {0xf6f7, 0x00e7a891}, /* U+7A11 [2000] */ - {0xf6f8, 0x00e7a895}, /* U+7A15 [2000] */ - {0xf6f9, 0x00e7a89b}, /* U+7A1B [2000] */ - {0xf6fa, 0x00e7a89e}, /* U+7A1E [2000] */ - {0xf6fb, 0x00e485a3}, /* U+4163 [2000] */ - {0xf6fc, 0x00e7a8ad}, /* U+7A2D [2000] */ - {0xf740, 0x00e7a8b8}, /* U+7A38 [2000] */ - {0xf741, 0x00e7a987}, /* U+7A47 [2000] */ - {0xf742, 0x00e7a98c}, /* U+7A4C [2000] */ - {0xf743, 0x00e7a996}, /* U+7A56 [2000] */ - {0xf744, 0x00e7a999}, /* U+7A59 [2000] */ - {0xf745, 0x00e7a99c}, /* U+7A5C [2000] */ - {0xf746, 0x00e7a99f}, /* U+7A5F [2000] */ - {0xf747, 0x00e7a9a0}, /* U+7A60 [2000] */ - {0xf748, 0x00e7a9a7}, /* U+7A67 [2000] */ - {0xf749, 0x00e7a9aa}, /* U+7A6A [2000] */ - {0xf74a, 0x00e7a9b5}, /* U+7A75 [2000] */ - {0xf74b, 0x00e7a9b8}, /* U+7A78 [2000] */ - {0xf74c, 0x00e7aa82}, /* U+7A82 [2000] */ - {0xf74d, 0x00e7aa8a}, /* U+7A8A [2000] */ - {0xf74e, 0x00e7aa90}, /* U+7A90 [2000] */ - {0xf74f, 0x00e7aaa3}, /* U+7AA3 [2000] */ - {0xf750, 0x00e7aaac}, /* U+7AAC [2000] */ + {0xf6f5, 0xe4858f}, /* U+414F [2000] */ + {0xf6f6, 0xe7a88a}, /* U+7A0A [2000] */ + {0xf6f7, 0xe7a891}, /* U+7A11 [2000] */ + {0xf6f8, 0xe7a895}, /* U+7A15 [2000] */ + {0xf6f9, 0xe7a89b}, /* U+7A1B [2000] */ + {0xf6fa, 0xe7a89e}, /* U+7A1E [2000] */ + {0xf6fb, 0xe485a3}, /* U+4163 [2000] */ + {0xf6fc, 0xe7a8ad}, /* U+7A2D [2000] */ + {0xf740, 0xe7a8b8}, /* U+7A38 [2000] */ + {0xf741, 0xe7a987}, /* U+7A47 [2000] */ + {0xf742, 0xe7a98c}, /* U+7A4C [2000] */ + {0xf743, 0xe7a996}, /* U+7A56 [2000] */ + {0xf744, 0xe7a999}, /* U+7A59 [2000] */ + {0xf745, 0xe7a99c}, /* U+7A5C [2000] */ + {0xf746, 0xe7a99f}, /* U+7A5F [2000] */ + {0xf747, 0xe7a9a0}, /* U+7A60 [2000] */ + {0xf748, 0xe7a9a7}, /* U+7A67 [2000] */ + {0xf749, 0xe7a9aa}, /* U+7A6A [2000] */ + {0xf74a, 0xe7a9b5}, /* U+7A75 [2000] */ + {0xf74b, 0xe7a9b8}, /* U+7A78 [2000] */ + {0xf74c, 0xe7aa82}, /* U+7A82 [2000] */ + {0xf74d, 0xe7aa8a}, /* U+7A8A [2000] */ + {0xf74e, 0xe7aa90}, /* U+7A90 [2000] */ + {0xf74f, 0xe7aaa3}, /* U+7AA3 [2000] */ + {0xf750, 0xe7aaac}, /* U+7AAC [2000] */ {0xf751, 0xf0a5a794}, /* U+259D4 [2000] [Unicode3.1] */ - {0xf752, 0x00e486b4}, /* U+41B4 [2000] */ - {0xf753, 0x00e7aab9}, /* U+7AB9 [2000] */ - {0xf754, 0x00e7aabc}, /* U+7ABC [2000] */ - {0xf755, 0x00e7aabe}, /* U+7ABE [2000] */ - {0xf756, 0x00e486bf}, /* U+41BF [2000] */ - {0xf757, 0x00e7ab8c}, /* U+7ACC [2000] */ - {0xf758, 0x00e7ab91}, /* U+7AD1 [2000] */ - {0xf759, 0x00e7aba7}, /* U+7AE7 [2000] */ - {0xf75a, 0x00e7aba8}, /* U+7AE8 [2000] */ - {0xf75b, 0x00e7abb4}, /* U+7AF4 [2000] */ + {0xf752, 0xe486b4}, /* U+41B4 [2000] */ + {0xf753, 0xe7aab9}, /* U+7AB9 [2000] */ + {0xf754, 0xe7aabc}, /* U+7ABC [2000] */ + {0xf755, 0xe7aabe}, /* U+7ABE [2000] */ + {0xf756, 0xe486bf}, /* U+41BF [2000] */ + {0xf757, 0xe7ab8c}, /* U+7ACC [2000] */ + {0xf758, 0xe7ab91}, /* U+7AD1 [2000] */ + {0xf759, 0xe7aba7}, /* U+7AE7 [2000] */ + {0xf75a, 0xe7aba8}, /* U+7AE8 [2000] */ + {0xf75b, 0xe7abb4}, /* U+7AF4 [2000] */ {0xf75c, 0xf0a5aba4}, /* U+25AE4 [2000] [Unicode3.1] */ {0xf75d, 0xf0a5aba3}, /* U+25AE3 [2000] [Unicode3.1] */ - {0xf75e, 0x00e7ac87}, /* U+7B07 [2000] */ + {0xf75e, 0xe7ac87}, /* U+7B07 [2000] */ {0xf75f, 0xf0a5abb1}, /* U+25AF1 [2000] [Unicode3.1] */ - {0xf760, 0x00e7acbd}, /* U+7B3D [2000] */ - {0xf761, 0x00e7aca7}, /* U+7B27 [2000] */ - {0xf762, 0x00e7acaa}, /* U+7B2A [2000] */ - {0xf763, 0x00e7acae}, /* U+7B2E [2000] */ - {0xf764, 0x00e7acaf}, /* U+7B2F [2000] */ - {0xf765, 0x00e7acb1}, /* U+7B31 [2000] */ - {0xf766, 0x00e487a6}, /* U+41E6 [2000] */ - {0xf767, 0x00e487b3}, /* U+41F3 [2000] */ - {0xf768, 0x00e7adbf}, /* U+7B7F [2000] */ - {0xf769, 0x00e7ad81}, /* U+7B41 [2000] */ - {0xf76a, 0x00e487ae}, /* U+41EE [2000] */ - {0xf76b, 0x00e7ad95}, /* U+7B55 [2000] */ - {0xf76c, 0x00e7adb9}, /* U+7B79 [2000] */ - {0xf76d, 0x00e7ada4}, /* U+7B64 [2000] */ - {0xf76e, 0x00e7ada6}, /* U+7B66 [2000] */ - {0xf76f, 0x00e7ada9}, /* U+7B69 [2000] */ - {0xf770, 0x00e7adb3}, /* U+7B73 [2000] */ + {0xf760, 0xe7acbd}, /* U+7B3D [2000] */ + {0xf761, 0xe7aca7}, /* U+7B27 [2000] */ + {0xf762, 0xe7acaa}, /* U+7B2A [2000] */ + {0xf763, 0xe7acae}, /* U+7B2E [2000] */ + {0xf764, 0xe7acaf}, /* U+7B2F [2000] */ + {0xf765, 0xe7acb1}, /* U+7B31 [2000] */ + {0xf766, 0xe487a6}, /* U+41E6 [2000] */ + {0xf767, 0xe487b3}, /* U+41F3 [2000] */ + {0xf768, 0xe7adbf}, /* U+7B7F [2000] */ + {0xf769, 0xe7ad81}, /* U+7B41 [2000] */ + {0xf76a, 0xe487ae}, /* U+41EE [2000] */ + {0xf76b, 0xe7ad95}, /* U+7B55 [2000] */ + {0xf76c, 0xe7adb9}, /* U+7B79 [2000] */ + {0xf76d, 0xe7ada4}, /* U+7B64 [2000] */ + {0xf76e, 0xe7ada6}, /* U+7B66 [2000] */ + {0xf76f, 0xe7ada9}, /* U+7B69 [2000] */ + {0xf770, 0xe7adb3}, /* U+7B73 [2000] */ {0xf771, 0xf0a5aeb2}, /* U+25BB2 [2000] [Unicode3.1] */ - {0xf772, 0x00e48887}, /* U+4207 [2000] */ - {0xf773, 0x00e7ae90}, /* U+7B90 [2000] */ - {0xf774, 0x00e7ae91}, /* U+7B91 [2000] */ - {0xf775, 0x00e7ae9b}, /* U+7B9B [2000] */ - {0xf776, 0x00e4888e}, /* U+420E [2000] */ - {0xf777, 0x00e7aeaf}, /* U+7BAF [2000] */ - {0xf778, 0x00e7aeb5}, /* U+7BB5 [2000] */ - {0xf779, 0x00e7aebc}, /* U+7BBC [2000] */ - {0xf77a, 0x00e7af85}, /* U+7BC5 [2000] */ - {0xf77b, 0x00e7af8a}, /* U+7BCA [2000] */ + {0xf772, 0xe48887}, /* U+4207 [2000] */ + {0xf773, 0xe7ae90}, /* U+7B90 [2000] */ + {0xf774, 0xe7ae91}, /* U+7B91 [2000] */ + {0xf775, 0xe7ae9b}, /* U+7B9B [2000] */ + {0xf776, 0xe4888e}, /* U+420E [2000] */ + {0xf777, 0xe7aeaf}, /* U+7BAF [2000] */ + {0xf778, 0xe7aeb5}, /* U+7BB5 [2000] */ + {0xf779, 0xe7aebc}, /* U+7BBC [2000] */ + {0xf77a, 0xe7af85}, /* U+7BC5 [2000] */ + {0xf77b, 0xe7af8a}, /* U+7BCA [2000] */ {0xf77c, 0xf0a5b18b}, /* U+25C4B [2000] [Unicode3.1] */ {0xf77d, 0xf0a5b1a4}, /* U+25C64 [2000] [Unicode3.1] */ - {0xf77e, 0x00e7af94}, /* U+7BD4 [2000] */ - {0xf780, 0x00e7af96}, /* U+7BD6 [2000] */ - {0xf781, 0x00e7af9a}, /* U+7BDA [2000] */ - {0xf782, 0x00e7afaa}, /* U+7BEA [2000] */ - {0xf783, 0x00e7afb0}, /* U+7BF0 [2000] */ - {0xf784, 0x00e7b083}, /* U+7C03 [2000] */ - {0xf785, 0x00e7b08b}, /* U+7C0B [2000] */ - {0xf786, 0x00e7b08e}, /* U+7C0E [2000] */ - {0xf787, 0x00e7b08f}, /* U+7C0F [2000] */ - {0xf788, 0x00e7b0a6}, /* U+7C26 [2000] */ - {0xf789, 0x00e7b185}, /* U+7C45 [2000] */ - {0xf78a, 0x00e7b18a}, /* U+7C4A [2000] */ - {0xf78b, 0x00e7b191}, /* U+7C51 [2000] */ - {0xf78c, 0x00e7b197}, /* U+7C57 [2000] */ - {0xf78d, 0x00e7b19e}, /* U+7C5E [2000] */ - {0xf78e, 0x00e7b1a1}, /* U+7C61 [2000] */ - {0xf78f, 0x00e7b1a9}, /* U+7C69 [2000] */ - {0xf790, 0x00e7b1ae}, /* U+7C6E [2000] */ - {0xf791, 0x00e7b1af}, /* U+7C6F [2000] */ - {0xf792, 0x00e7b1b0}, /* U+7C70 [2000] */ + {0xf77e, 0xe7af94}, /* U+7BD4 [2000] */ + {0xf780, 0xe7af96}, /* U+7BD6 [2000] */ + {0xf781, 0xe7af9a}, /* U+7BDA [2000] */ + {0xf782, 0xe7afaa}, /* U+7BEA [2000] */ + {0xf783, 0xe7afb0}, /* U+7BF0 [2000] */ + {0xf784, 0xe7b083}, /* U+7C03 [2000] */ + {0xf785, 0xe7b08b}, /* U+7C0B [2000] */ + {0xf786, 0xe7b08e}, /* U+7C0E [2000] */ + {0xf787, 0xe7b08f}, /* U+7C0F [2000] */ + {0xf788, 0xe7b0a6}, /* U+7C26 [2000] */ + {0xf789, 0xe7b185}, /* U+7C45 [2000] */ + {0xf78a, 0xe7b18a}, /* U+7C4A [2000] */ + {0xf78b, 0xe7b191}, /* U+7C51 [2000] */ + {0xf78c, 0xe7b197}, /* U+7C57 [2000] */ + {0xf78d, 0xe7b19e}, /* U+7C5E [2000] */ + {0xf78e, 0xe7b1a1}, /* U+7C61 [2000] */ + {0xf78f, 0xe7b1a9}, /* U+7C69 [2000] */ + {0xf790, 0xe7b1ae}, /* U+7C6E [2000] */ + {0xf791, 0xe7b1af}, /* U+7C6F [2000] */ + {0xf792, 0xe7b1b0}, /* U+7C70 [2000] */ {0xf793, 0xf0a5b8ae}, /* U+25E2E [2000] [Unicode3.1] */ {0xf794, 0xf0a5b996}, /* U+25E56 [2000] [Unicode3.1] */ {0xf795, 0xf0a5b9a5}, /* U+25E65 [2000] [Unicode3.1] */ - {0xf796, 0x00e7b2a6}, /* U+7CA6 [2000] */ + {0xf796, 0xe7b2a6}, /* U+7CA6 [2000] */ {0xf797, 0xf0a5b9a2}, /* U+25E62 [2000] [Unicode3.1] */ - {0xf798, 0x00e7b2b6}, /* U+7CB6 [2000] */ - {0xf799, 0x00e7b2b7}, /* U+7CB7 [2000] */ - {0xf79a, 0x00e7b2bf}, /* U+7CBF [2000] */ + {0xf798, 0xe7b2b6}, /* U+7CB6 [2000] */ + {0xf799, 0xe7b2b7}, /* U+7CB7 [2000] */ + {0xf79a, 0xe7b2bf}, /* U+7CBF [2000] */ {0xf79b, 0xf0a5bb98}, /* U+25ED8 [2000] [Unicode3.1] */ - {0xf79c, 0x00e7b384}, /* U+7CC4 [2000] */ + {0xf79c, 0xe7b384}, /* U+7CC4 [2000] */ {0xf79d, 0xf0a5bb82}, /* U+25EC2 [2000] [Unicode3.1] */ - {0xf79e, 0x00e7b388}, /* U+7CC8 [2000] */ - {0xf79f, 0x00e7b38d}, /* U+7CCD [2000] */ + {0xf79e, 0xe7b388}, /* U+7CC8 [2000] */ + {0xf79f, 0xe7b38d}, /* U+7CCD [2000] */ {0xf7a0, 0xf0a5bba8}, /* U+25EE8 [2000] [Unicode3.1] */ - {0xf7a1, 0x00e7b397}, /* U+7CD7 [2000] */ + {0xf7a1, 0xe7b397}, /* U+7CD7 [2000] */ {0xf7a2, 0xf0a5bca3}, /* U+25F23 [2000] [Unicode3.1] */ - {0xf7a3, 0x00e7b3a6}, /* U+7CE6 [2000] */ - {0xf7a4, 0x00e7b3ab}, /* U+7CEB [2000] */ + {0xf7a3, 0xe7b3a6}, /* U+7CE6 [2000] */ + {0xf7a4, 0xe7b3ab}, /* U+7CEB [2000] */ {0xf7a5, 0xf0a5bd9c}, /* U+25F5C [2000] [Unicode3.1] */ - {0xf7a6, 0x00e7b3b5}, /* U+7CF5 [2000] */ - {0xf7a7, 0x00e7b483}, /* U+7D03 [2000] */ - {0xf7a8, 0x00e7b489}, /* U+7D09 [2000] */ - {0xf7a9, 0x00e48b86}, /* U+42C6 [2000] */ - {0xf7aa, 0x00e7b492}, /* U+7D12 [2000] */ - {0xf7ab, 0x00e7b49e}, /* U+7D1E [2000] */ + {0xf7a6, 0xe7b3b5}, /* U+7CF5 [2000] */ + {0xf7a7, 0xe7b483}, /* U+7D03 [2000] */ + {0xf7a8, 0xe7b489}, /* U+7D09 [2000] */ + {0xf7a9, 0xe48b86}, /* U+42C6 [2000] */ + {0xf7aa, 0xe7b492}, /* U+7D12 [2000] */ + {0xf7ab, 0xe7b49e}, /* U+7D1E [2000] */ {0xf7ac, 0xf0a5bfa0}, /* U+25FE0 [2000] [Unicode3.1] */ {0xf7ad, 0xf0a5bf94}, /* U+25FD4 [2000] [Unicode3.1] */ - {0xf7ae, 0x00e7b4bd}, /* U+7D3D [2000] */ - {0xf7af, 0x00e7b4be}, /* U+7D3E [2000] */ - {0xf7b0, 0x00e7b580}, /* U+7D40 [2000] */ - {0xf7b1, 0x00e7b587}, /* U+7D47 [2000] */ + {0xf7ae, 0xe7b4bd}, /* U+7D3D [2000] */ + {0xf7af, 0xe7b4be}, /* U+7D3E [2000] */ + {0xf7b0, 0xe7b580}, /* U+7D40 [2000] */ + {0xf7b1, 0xe7b587}, /* U+7D47 [2000] */ {0xf7b2, 0xf0a6808c}, /* U+2600C [2000] [Unicode3.1] */ {0xf7b3, 0xf0a5bfbb}, /* U+25FFB [2000] [Unicode3.1] */ - {0xf7b4, 0x00e48b96}, /* U+42D6 [2000] */ - {0xf7b5, 0x00e7b599}, /* U+7D59 [2000] */ - {0xf7b6, 0x00e7b59a}, /* U+7D5A [2000] */ - {0xf7b7, 0x00e7b5aa}, /* U+7D6A [2000] */ - {0xf7b8, 0x00e7b5b0}, /* U+7D70 [2000] */ - {0xf7b9, 0x00e48b9d}, /* U+42DD [2000] */ - {0xf7ba, 0x00e7b5bf}, /* U+7D7F [2000] */ + {0xf7b4, 0xe48b96}, /* U+42D6 [2000] */ + {0xf7b5, 0xe7b599}, /* U+7D59 [2000] */ + {0xf7b6, 0xe7b59a}, /* U+7D5A [2000] */ + {0xf7b7, 0xe7b5aa}, /* U+7D6A [2000] */ + {0xf7b8, 0xe7b5b0}, /* U+7D70 [2000] */ + {0xf7b9, 0xe48b9d}, /* U+42DD [2000] */ + {0xf7ba, 0xe7b5bf}, /* U+7D7F [2000] */ {0xf7bb, 0xf0a68097}, /* U+26017 [2000] [Unicode3.1] */ - {0xf7bc, 0x00e7b686}, /* U+7D86 [2000] */ - {0xf7bd, 0x00e7b688}, /* U+7D88 [2000] */ - {0xf7be, 0x00e7b68c}, /* U+7D8C [2000] */ - {0xf7bf, 0x00e7b697}, /* U+7D97 [2000] */ + {0xf7bc, 0xe7b686}, /* U+7D86 [2000] */ + {0xf7bd, 0xe7b688}, /* U+7D88 [2000] */ + {0xf7be, 0xe7b68c}, /* U+7D8C [2000] */ + {0xf7bf, 0xe7b697}, /* U+7D97 [2000] */ {0xf7c0, 0xf0a681a0}, /* U+26060 [2000] [Unicode3.1] */ - {0xf7c1, 0x00e7b69d}, /* U+7D9D [2000] */ - {0xf7c2, 0x00e7b6a7}, /* U+7DA7 [2000] */ - {0xf7c3, 0x00e7b6aa}, /* U+7DAA [2000] */ - {0xf7c4, 0x00e7b6b6}, /* U+7DB6 [2000] */ - {0xf7c5, 0x00e7b6b7}, /* U+7DB7 [2000] */ - {0xf7c6, 0x00e7b780}, /* U+7DC0 [2000] */ - {0xf7c7, 0x00e7b797}, /* U+7DD7 [2000] */ - {0xf7c8, 0x00e7b799}, /* U+7DD9 [2000] */ - {0xf7c9, 0x00e7b7a6}, /* U+7DE6 [2000] */ - {0xf7ca, 0x00e7b7b1}, /* U+7DF1 [2000] */ - {0xf7cb, 0x00e7b7b9}, /* U+7DF9 [2000] */ - {0xf7cc, 0x00e48c82}, /* U+4302 [2000] */ + {0xf7c1, 0xe7b69d}, /* U+7D9D [2000] */ + {0xf7c2, 0xe7b6a7}, /* U+7DA7 [2000] */ + {0xf7c3, 0xe7b6aa}, /* U+7DAA [2000] */ + {0xf7c4, 0xe7b6b6}, /* U+7DB6 [2000] */ + {0xf7c5, 0xe7b6b7}, /* U+7DB7 [2000] */ + {0xf7c6, 0xe7b780}, /* U+7DC0 [2000] */ + {0xf7c7, 0xe7b797}, /* U+7DD7 [2000] */ + {0xf7c8, 0xe7b799}, /* U+7DD9 [2000] */ + {0xf7c9, 0xe7b7a6}, /* U+7DE6 [2000] */ + {0xf7ca, 0xe7b7b1}, /* U+7DF1 [2000] */ + {0xf7cb, 0xe7b7b9}, /* U+7DF9 [2000] */ + {0xf7cc, 0xe48c82}, /* U+4302 [2000] */ {0xf7cd, 0xf0a683ad}, /* U+260ED [2000] [Unicode3.1] */ - {0xf7ce, 0x00efa998}, /* U+FA58 CJK COMPATIBILITY IDEOGRAPH-FA58 [2000] [Unicode3.2] */ - {0xf7cf, 0x00e7b890}, /* U+7E10 [2000] */ - {0xf7d0, 0x00e7b897}, /* U+7E17 [2000] */ - {0xf7d1, 0x00e7b89d}, /* U+7E1D [2000] */ - {0xf7d2, 0x00e7b8a0}, /* U+7E20 [2000] */ - {0xf7d3, 0x00e7b8a7}, /* U+7E27 [2000] */ - {0xf7d4, 0x00e7b8ac}, /* U+7E2C [2000] */ - {0xf7d5, 0x00e7b985}, /* U+7E45 [2000] */ - {0xf7d6, 0x00e7b9b3}, /* U+7E73 [2000] */ - {0xf7d7, 0x00e7b9b5}, /* U+7E75 [2000] */ - {0xf7d8, 0x00e7b9be}, /* U+7E7E [2000] */ - {0xf7d9, 0x00e7ba86}, /* U+7E86 [2000] */ - {0xf7da, 0x00e7ba87}, /* U+7E87 [2000] */ - {0xf7db, 0x00e48cab}, /* U+432B [2000] */ - {0xf7dc, 0x00e7ba91}, /* U+7E91 [2000] */ - {0xf7dd, 0x00e7ba98}, /* U+7E98 [2000] */ - {0xf7de, 0x00e7ba9a}, /* U+7E9A [2000] */ - {0xf7df, 0x00e48d83}, /* U+4343 [2000] */ - {0xf7e0, 0x00e7bcbc}, /* U+7F3C [2000] */ - {0xf7e1, 0x00e7bcbb}, /* U+7F3B [2000] */ - {0xf7e2, 0x00e7bcbe}, /* U+7F3E [2000] */ - {0xf7e3, 0x00e7bd83}, /* U+7F43 [2000] */ - {0xf7e4, 0x00e7bd84}, /* U+7F44 [2000] */ - {0xf7e5, 0x00e7bd8f}, /* U+7F4F [2000] */ - {0xf7e6, 0x00e39381}, /* U+34C1 [2000] */ + {0xf7ce, 0xefa998}, /* U+FA58 CJK COMPATIBILITY IDEOGRAPH-FA58 [2000] [Unicode3.2] */ + {0xf7cf, 0xe7b890}, /* U+7E10 [2000] */ + {0xf7d0, 0xe7b897}, /* U+7E17 [2000] */ + {0xf7d1, 0xe7b89d}, /* U+7E1D [2000] */ + {0xf7d2, 0xe7b8a0}, /* U+7E20 [2000] */ + {0xf7d3, 0xe7b8a7}, /* U+7E27 [2000] */ + {0xf7d4, 0xe7b8ac}, /* U+7E2C [2000] */ + {0xf7d5, 0xe7b985}, /* U+7E45 [2000] */ + {0xf7d6, 0xe7b9b3}, /* U+7E73 [2000] */ + {0xf7d7, 0xe7b9b5}, /* U+7E75 [2000] */ + {0xf7d8, 0xe7b9be}, /* U+7E7E [2000] */ + {0xf7d9, 0xe7ba86}, /* U+7E86 [2000] */ + {0xf7da, 0xe7ba87}, /* U+7E87 [2000] */ + {0xf7db, 0xe48cab}, /* U+432B [2000] */ + {0xf7dc, 0xe7ba91}, /* U+7E91 [2000] */ + {0xf7dd, 0xe7ba98}, /* U+7E98 [2000] */ + {0xf7de, 0xe7ba9a}, /* U+7E9A [2000] */ + {0xf7df, 0xe48d83}, /* U+4343 [2000] */ + {0xf7e0, 0xe7bcbc}, /* U+7F3C [2000] */ + {0xf7e1, 0xe7bcbb}, /* U+7F3B [2000] */ + {0xf7e2, 0xe7bcbe}, /* U+7F3E [2000] */ + {0xf7e3, 0xe7bd83}, /* U+7F43 [2000] */ + {0xf7e4, 0xe7bd84}, /* U+7F44 [2000] */ + {0xf7e5, 0xe7bd8f}, /* U+7F4F [2000] */ + {0xf7e6, 0xe39381}, /* U+34C1 [2000] */ {0xf7e7, 0xf0a689b0}, /* U+26270 [2000] [Unicode3.1] */ - {0xf7e8, 0x00e7bd92}, /* U+7F52 [2000] */ + {0xf7e8, 0xe7bd92}, /* U+7F52 [2000] */ {0xf7e9, 0xf0a68a86}, /* U+26286 [2000] [Unicode3.1] */ - {0xf7ea, 0x00e7bda1}, /* U+7F61 [2000] */ - {0xf7eb, 0x00e7bda3}, /* U+7F63 [2000] */ - {0xf7ec, 0x00e7bda4}, /* U+7F64 [2000] */ - {0xf7ed, 0x00e7bdad}, /* U+7F6D [2000] */ - {0xf7ee, 0x00e7bdbd}, /* U+7F7D [2000] */ - {0xf7ef, 0x00e7bdbe}, /* U+7F7E [2000] */ + {0xf7ea, 0xe7bda1}, /* U+7F61 [2000] */ + {0xf7eb, 0xe7bda3}, /* U+7F63 [2000] */ + {0xf7ec, 0xe7bda4}, /* U+7F64 [2000] */ + {0xf7ed, 0xe7bdad}, /* U+7F6D [2000] */ + {0xf7ee, 0xe7bdbd}, /* U+7F7D [2000] */ + {0xf7ef, 0xe7bdbe}, /* U+7F7E [2000] */ {0xf7f0, 0xf0a68d8c}, /* U+2634C [2000] [Unicode3.1] */ - {0xf7f1, 0x00e7be90}, /* U+7F90 [2000] */ - {0xf7f2, 0x00e585bb}, /* U+517B [2000] */ + {0xf7f1, 0xe7be90}, /* U+7F90 [2000] */ + {0xf7f2, 0xe585bb}, /* U+517B [2000] */ {0xf7f3, 0xf0a3b48e}, /* U+23D0E [2000] [Unicode3.1] */ - {0xf7f4, 0x00e7be96}, /* U+7F96 [2000] */ - {0xf7f5, 0x00e7be9c}, /* U+7F9C [2000] */ - {0xf7f6, 0x00e7bead}, /* U+7FAD [2000] */ + {0xf7f4, 0xe7be96}, /* U+7F96 [2000] */ + {0xf7f5, 0xe7be9c}, /* U+7F9C [2000] */ + {0xf7f6, 0xe7bead}, /* U+7FAD [2000] */ {0xf7f7, 0xf0a69082}, /* U+26402 [2000] [Unicode3.1] */ - {0xf7f8, 0x00e7bf83}, /* U+7FC3 [2000] */ - {0xf7f9, 0x00e7bf8f}, /* U+7FCF [2000] */ - {0xf7fa, 0x00e7bfa3}, /* U+7FE3 [2000] */ - {0xf7fb, 0x00e7bfa5}, /* U+7FE5 [2000] */ - {0xf7fc, 0x00e7bfaf}, /* U+7FEF [2000] */ - {0xf840, 0x00e7bfb2}, /* U+7FF2 [2000] */ - {0xf841, 0x00e88082}, /* U+8002 [2000] */ - {0xf842, 0x00e8808a}, /* U+800A [2000] */ - {0xf843, 0x00e88088}, /* U+8008 [2000] */ - {0xf844, 0x00e8808e}, /* U+800E [2000] */ - {0xf845, 0x00e88091}, /* U+8011 [2000] */ - {0xf846, 0x00e88096}, /* U+8016 [2000] */ - {0xf847, 0x00e880a4}, /* U+8024 [2000] */ - {0xf848, 0x00e880ac}, /* U+802C [2000] */ - {0xf849, 0x00e880b0}, /* U+8030 [2000] */ - {0xf84a, 0x00e88183}, /* U+8043 [2000] */ - {0xf84b, 0x00e881a6}, /* U+8066 [2000] */ - {0xf84c, 0x00e881b1}, /* U+8071 [2000] */ - {0xf84d, 0x00e881b5}, /* U+8075 [2000] */ - {0xf84e, 0x00e881bb}, /* U+807B [2000] */ - {0xf84f, 0x00e88299}, /* U+8099 [2000] */ - {0xf850, 0x00e8829c}, /* U+809C [2000] */ - {0xf851, 0x00e882a4}, /* U+80A4 [2000] */ - {0xf852, 0x00e882a7}, /* U+80A7 [2000] */ - {0xf853, 0x00e882b8}, /* U+80B8 [2000] */ + {0xf7f8, 0xe7bf83}, /* U+7FC3 [2000] */ + {0xf7f9, 0xe7bf8f}, /* U+7FCF [2000] */ + {0xf7fa, 0xe7bfa3}, /* U+7FE3 [2000] */ + {0xf7fb, 0xe7bfa5}, /* U+7FE5 [2000] */ + {0xf7fc, 0xe7bfaf}, /* U+7FEF [2000] */ + {0xf840, 0xe7bfb2}, /* U+7FF2 [2000] */ + {0xf841, 0xe88082}, /* U+8002 [2000] */ + {0xf842, 0xe8808a}, /* U+800A [2000] */ + {0xf843, 0xe88088}, /* U+8008 [2000] */ + {0xf844, 0xe8808e}, /* U+800E [2000] */ + {0xf845, 0xe88091}, /* U+8011 [2000] */ + {0xf846, 0xe88096}, /* U+8016 [2000] */ + {0xf847, 0xe880a4}, /* U+8024 [2000] */ + {0xf848, 0xe880ac}, /* U+802C [2000] */ + {0xf849, 0xe880b0}, /* U+8030 [2000] */ + {0xf84a, 0xe88183}, /* U+8043 [2000] */ + {0xf84b, 0xe881a6}, /* U+8066 [2000] */ + {0xf84c, 0xe881b1}, /* U+8071 [2000] */ + {0xf84d, 0xe881b5}, /* U+8075 [2000] */ + {0xf84e, 0xe881bb}, /* U+807B [2000] */ + {0xf84f, 0xe88299}, /* U+8099 [2000] */ + {0xf850, 0xe8829c}, /* U+809C [2000] */ + {0xf851, 0xe882a4}, /* U+80A4 [2000] */ + {0xf852, 0xe882a7}, /* U+80A7 [2000] */ + {0xf853, 0xe882b8}, /* U+80B8 [2000] */ {0xf854, 0xf0a699be}, /* U+2667E [2000] [Unicode3.1] */ - {0xf855, 0x00e88385}, /* U+80C5 [2000] */ - {0xf856, 0x00e88395}, /* U+80D5 [2000] */ - {0xf857, 0x00e88398}, /* U+80D8 [2000] */ - {0xf858, 0x00e883a6}, /* U+80E6 [2000] */ + {0xf855, 0xe88385}, /* U+80C5 [2000] */ + {0xf856, 0xe88395}, /* U+80D5 [2000] */ + {0xf857, 0xe88398}, /* U+80D8 [2000] */ + {0xf858, 0xe883a6}, /* U+80E6 [2000] */ {0xf859, 0xf0a69ab0}, /* U+266B0 [2000] [Unicode3.1] */ - {0xf85a, 0x00e8848d}, /* U+810D [2000] */ - {0xf85b, 0x00e883b5}, /* U+80F5 [2000] */ - {0xf85c, 0x00e883bb}, /* U+80FB [2000] */ - {0xf85d, 0x00e48fae}, /* U+43EE [2000] */ - {0xf85e, 0x00e884b5}, /* U+8135 [2000] */ - {0xf85f, 0x00e88496}, /* U+8116 [2000] */ - {0xf860, 0x00e8849e}, /* U+811E [2000] */ - {0xf861, 0x00e48fb0}, /* U+43F0 [2000] */ - {0xf862, 0x00e884a4}, /* U+8124 [2000] */ - {0xf863, 0x00e884a7}, /* U+8127 [2000] */ - {0xf864, 0x00e884ac}, /* U+812C [2000] */ + {0xf85a, 0xe8848d}, /* U+810D [2000] */ + {0xf85b, 0xe883b5}, /* U+80F5 [2000] */ + {0xf85c, 0xe883bb}, /* U+80FB [2000] */ + {0xf85d, 0xe48fae}, /* U+43EE [2000] */ + {0xf85e, 0xe884b5}, /* U+8135 [2000] */ + {0xf85f, 0xe88496}, /* U+8116 [2000] */ + {0xf860, 0xe8849e}, /* U+811E [2000] */ + {0xf861, 0xe48fb0}, /* U+43F0 [2000] */ + {0xf862, 0xe884a4}, /* U+8124 [2000] */ + {0xf863, 0xe884a7}, /* U+8127 [2000] */ + {0xf864, 0xe884ac}, /* U+812C [2000] */ {0xf865, 0xf0a69c9d}, /* U+2671D [2000] [Unicode3.1] */ - {0xf866, 0x00e884bd}, /* U+813D [2000] */ - {0xf867, 0x00e49088}, /* U+4408 [2000] */ - {0xf868, 0x00e885a9}, /* U+8169 [2000] */ - {0xf869, 0x00e49097}, /* U+4417 [2000] */ - {0xf86a, 0x00e88681}, /* U+8181 [2000] */ - {0xf86b, 0x00e4909c}, /* U+441C [2000] */ - {0xf86c, 0x00e88684}, /* U+8184 [2000] */ - {0xf86d, 0x00e88685}, /* U+8185 [2000] */ - {0xf86e, 0x00e490a2}, /* U+4422 [2000] */ - {0xf86f, 0x00e88698}, /* U+8198 [2000] */ - {0xf870, 0x00e886b2}, /* U+81B2 [2000] */ - {0xf871, 0x00e88781}, /* U+81C1 [2000] */ - {0xf872, 0x00e88783}, /* U+81C3 [2000] */ - {0xf873, 0x00e88796}, /* U+81D6 [2000] */ - {0xf874, 0x00e8879b}, /* U+81DB [2000] */ + {0xf866, 0xe884bd}, /* U+813D [2000] */ + {0xf867, 0xe49088}, /* U+4408 [2000] */ + {0xf868, 0xe885a9}, /* U+8169 [2000] */ + {0xf869, 0xe49097}, /* U+4417 [2000] */ + {0xf86a, 0xe88681}, /* U+8181 [2000] */ + {0xf86b, 0xe4909c}, /* U+441C [2000] */ + {0xf86c, 0xe88684}, /* U+8184 [2000] */ + {0xf86d, 0xe88685}, /* U+8185 [2000] */ + {0xf86e, 0xe490a2}, /* U+4422 [2000] */ + {0xf86f, 0xe88698}, /* U+8198 [2000] */ + {0xf870, 0xe886b2}, /* U+81B2 [2000] */ + {0xf871, 0xe88781}, /* U+81C1 [2000] */ + {0xf872, 0xe88783}, /* U+81C3 [2000] */ + {0xf873, 0xe88796}, /* U+81D6 [2000] */ + {0xf874, 0xe8879b}, /* U+81DB [2000] */ {0xf875, 0xf0a6a39d}, /* U+268DD [2000] [Unicode3.1] */ - {0xf876, 0x00e887a4}, /* U+81E4 [2000] */ + {0xf876, 0xe887a4}, /* U+81E4 [2000] */ {0xf877, 0xf0a6a3aa}, /* U+268EA [2000] [Unicode3.1] */ - {0xf878, 0x00e887ac}, /* U+81EC [2000] */ + {0xf878, 0xe887ac}, /* U+81EC [2000] */ {0xf879, 0xf0a6a591}, /* U+26951 [2000] [Unicode3.1] */ - {0xf87a, 0x00e887bd}, /* U+81FD [2000] */ - {0xf87b, 0x00e887bf}, /* U+81FF [2000] */ + {0xf87a, 0xe887bd}, /* U+81FD [2000] */ + {0xf87b, 0xe887bf}, /* U+81FF [2000] */ {0xf87c, 0xf0a6a5af}, /* U+2696F [2000] [Unicode3.1] */ - {0xf87d, 0x00e88884}, /* U+8204 [2000] */ + {0xf87d, 0xe88884}, /* U+8204 [2000] */ {0xf87e, 0xf0a6a79d}, /* U+269DD [2000] [Unicode3.1] */ - {0xf880, 0x00e88899}, /* U+8219 [2000] */ - {0xf881, 0x00e888a1}, /* U+8221 [2000] */ - {0xf882, 0x00e888a2}, /* U+8222 [2000] */ + {0xf880, 0xe88899}, /* U+8219 [2000] */ + {0xf881, 0xe888a1}, /* U+8221 [2000] */ + {0xf882, 0xe888a2}, /* U+8222 [2000] */ {0xf883, 0xf0a6a89e}, /* U+26A1E [2000] [Unicode3.1] */ - {0xf884, 0x00e888b2}, /* U+8232 [2000] */ - {0xf885, 0x00e888b4}, /* U+8234 [2000] */ - {0xf886, 0x00e888bc}, /* U+823C [2000] */ - {0xf887, 0x00e88986}, /* U+8246 [2000] */ - {0xf888, 0x00e88989}, /* U+8249 [2000] */ - {0xf889, 0x00e88985}, /* U+8245 [2000] */ + {0xf884, 0xe888b2}, /* U+8232 [2000] */ + {0xf885, 0xe888b4}, /* U+8234 [2000] */ + {0xf886, 0xe888bc}, /* U+823C [2000] */ + {0xf887, 0xe88986}, /* U+8246 [2000] */ + {0xf888, 0xe88989}, /* U+8249 [2000] */ + {0xf889, 0xe88985}, /* U+8245 [2000] */ {0xf88a, 0xf0a6a998}, /* U+26A58 [2000] [Unicode3.1] */ - {0xf88b, 0x00e8898b}, /* U+824B [2000] */ - {0xf88c, 0x00e491b6}, /* U+4476 [2000] */ - {0xf88d, 0x00e8898f}, /* U+824F [2000] */ - {0xf88e, 0x00e491ba}, /* U+447A [2000] */ - {0xf88f, 0x00e88997}, /* U+8257 [2000] */ + {0xf88b, 0xe8898b}, /* U+824B [2000] */ + {0xf88c, 0xe491b6}, /* U+4476 [2000] */ + {0xf88d, 0xe8898f}, /* U+824F [2000] */ + {0xf88e, 0xe491ba}, /* U+447A [2000] */ + {0xf88f, 0xe88997}, /* U+8257 [2000] */ {0xf890, 0xf0a6aa8c}, /* U+26A8C [2000] [Unicode3.1] */ - {0xf891, 0x00e8899c}, /* U+825C [2000] */ - {0xf892, 0x00e889a3}, /* U+8263 [2000] */ + {0xf891, 0xe8899c}, /* U+825C [2000] */ + {0xf892, 0xe889a3}, /* U+8263 [2000] */ {0xf893, 0xf0a6aab7}, /* U+26AB7 [2000] [Unicode3.1] */ - {0xf894, 0x00efa99d}, /* U+FA5D CJK COMPATIBILITY IDEOGRAPH-FA5D [2000] [Unicode3.2] */ - {0xf895, 0x00efa99e}, /* U+FA5E CJK COMPATIBILITY IDEOGRAPH-FA5E [2000] [Unicode3.2] */ - {0xf896, 0x00e889b9}, /* U+8279 [2000] */ - {0xf897, 0x00e49291}, /* U+4491 [2000] */ - {0xf898, 0x00e889bd}, /* U+827D [2000] */ - {0xf899, 0x00e889bf}, /* U+827F [2000] */ - {0xf89a, 0x00e88a83}, /* U+8283 [2000] */ - {0xf89b, 0x00e88a8a}, /* U+828A [2000] */ - {0xf89c, 0x00e88a93}, /* U+8293 [2000] */ - {0xf89d, 0x00e88aa7}, /* U+82A7 [2000] */ - {0xf89e, 0x00e88aa8}, /* U+82A8 [2000] */ - {0xf89f, 0x00e88ab2}, /* U+82B2 [2000] */ - {0xf8a0, 0x00e88ab4}, /* U+82B4 [2000] */ - {0xf8a1, 0x00e88aba}, /* U+82BA [2000] */ - {0xf8a2, 0x00e88abc}, /* U+82BC [2000] */ - {0xf8a3, 0x00e88ba2}, /* U+82E2 [2000] */ - {0xf8a4, 0x00e88ba8}, /* U+82E8 [2000] */ - {0xf8a5, 0x00e88bb7}, /* U+82F7 [2000] */ - {0xf8a6, 0x00e88c87}, /* U+8307 [2000] */ - {0xf8a7, 0x00e88c88}, /* U+8308 [2000] */ - {0xf8a8, 0x00e88c8c}, /* U+830C [2000] */ - {0xf8a9, 0x00e88d94}, /* U+8354 [2000] */ - {0xf8aa, 0x00e88c9b}, /* U+831B [2000] */ - {0xf8ab, 0x00e88c9d}, /* U+831D [2000] */ - {0xf8ac, 0x00e88cb0}, /* U+8330 [2000] */ - {0xf8ad, 0x00e88cbc}, /* U+833C [2000] */ - {0xf8ae, 0x00e88d84}, /* U+8344 [2000] */ - {0xf8af, 0x00e88d97}, /* U+8357 [2000] */ - {0xf8b0, 0x00e492be}, /* U+44BE [2000] */ - {0xf8b1, 0x00e88dbf}, /* U+837F [2000] */ - {0xf8b2, 0x00e49394}, /* U+44D4 [2000] */ - {0xf8b3, 0x00e492b3}, /* U+44B3 [2000] */ - {0xf8b4, 0x00e88e8d}, /* U+838D [2000] */ - {0xf8b5, 0x00e88e94}, /* U+8394 [2000] */ - {0xf8b6, 0x00e88e95}, /* U+8395 [2000] */ - {0xf8b7, 0x00e88e9b}, /* U+839B [2000] */ - {0xf8b8, 0x00e88e9d}, /* U+839D [2000] */ - {0xf8b9, 0x00e88f89}, /* U+83C9 [2000] */ - {0xf8ba, 0x00e88f90}, /* U+83D0 [2000] */ - {0xf8bb, 0x00e88f94}, /* U+83D4 [2000] */ - {0xf8bc, 0x00e88f9d}, /* U+83DD [2000] */ - {0xf8bd, 0x00e88fa5}, /* U+83E5 [2000] */ - {0xf8be, 0x00e88fb9}, /* U+83F9 [2000] */ - {0xf8bf, 0x00e8908f}, /* U+840F [2000] */ - {0xf8c0, 0x00e89091}, /* U+8411 [2000] */ - {0xf8c1, 0x00e89095}, /* U+8415 [2000] */ + {0xf894, 0xefa99d}, /* U+FA5D CJK COMPATIBILITY IDEOGRAPH-FA5D [2000] [Unicode3.2] */ + {0xf895, 0xefa99e}, /* U+FA5E CJK COMPATIBILITY IDEOGRAPH-FA5E [2000] [Unicode3.2] */ + {0xf896, 0xe889b9}, /* U+8279 [2000] */ + {0xf897, 0xe49291}, /* U+4491 [2000] */ + {0xf898, 0xe889bd}, /* U+827D [2000] */ + {0xf899, 0xe889bf}, /* U+827F [2000] */ + {0xf89a, 0xe88a83}, /* U+8283 [2000] */ + {0xf89b, 0xe88a8a}, /* U+828A [2000] */ + {0xf89c, 0xe88a93}, /* U+8293 [2000] */ + {0xf89d, 0xe88aa7}, /* U+82A7 [2000] */ + {0xf89e, 0xe88aa8}, /* U+82A8 [2000] */ + {0xf89f, 0xe88ab2}, /* U+82B2 [2000] */ + {0xf8a0, 0xe88ab4}, /* U+82B4 [2000] */ + {0xf8a1, 0xe88aba}, /* U+82BA [2000] */ + {0xf8a2, 0xe88abc}, /* U+82BC [2000] */ + {0xf8a3, 0xe88ba2}, /* U+82E2 [2000] */ + {0xf8a4, 0xe88ba8}, /* U+82E8 [2000] */ + {0xf8a5, 0xe88bb7}, /* U+82F7 [2000] */ + {0xf8a6, 0xe88c87}, /* U+8307 [2000] */ + {0xf8a7, 0xe88c88}, /* U+8308 [2000] */ + {0xf8a8, 0xe88c8c}, /* U+830C [2000] */ + {0xf8a9, 0xe88d94}, /* U+8354 [2000] */ + {0xf8aa, 0xe88c9b}, /* U+831B [2000] */ + {0xf8ab, 0xe88c9d}, /* U+831D [2000] */ + {0xf8ac, 0xe88cb0}, /* U+8330 [2000] */ + {0xf8ad, 0xe88cbc}, /* U+833C [2000] */ + {0xf8ae, 0xe88d84}, /* U+8344 [2000] */ + {0xf8af, 0xe88d97}, /* U+8357 [2000] */ + {0xf8b0, 0xe492be}, /* U+44BE [2000] */ + {0xf8b1, 0xe88dbf}, /* U+837F [2000] */ + {0xf8b2, 0xe49394}, /* U+44D4 [2000] */ + {0xf8b3, 0xe492b3}, /* U+44B3 [2000] */ + {0xf8b4, 0xe88e8d}, /* U+838D [2000] */ + {0xf8b5, 0xe88e94}, /* U+8394 [2000] */ + {0xf8b6, 0xe88e95}, /* U+8395 [2000] */ + {0xf8b7, 0xe88e9b}, /* U+839B [2000] */ + {0xf8b8, 0xe88e9d}, /* U+839D [2000] */ + {0xf8b9, 0xe88f89}, /* U+83C9 [2000] */ + {0xf8ba, 0xe88f90}, /* U+83D0 [2000] */ + {0xf8bb, 0xe88f94}, /* U+83D4 [2000] */ + {0xf8bc, 0xe88f9d}, /* U+83DD [2000] */ + {0xf8bd, 0xe88fa5}, /* U+83E5 [2000] */ + {0xf8be, 0xe88fb9}, /* U+83F9 [2000] */ + {0xf8bf, 0xe8908f}, /* U+840F [2000] */ + {0xf8c0, 0xe89091}, /* U+8411 [2000] */ + {0xf8c1, 0xe89095}, /* U+8415 [2000] */ {0xf8c2, 0xf0a6b1b3}, /* U+26C73 [2000] [Unicode3.1] */ - {0xf8c3, 0x00e89097}, /* U+8417 [2000] */ - {0xf8c4, 0x00e890b9}, /* U+8439 [2000] */ - {0xf8c5, 0x00e8918a}, /* U+844A [2000] */ - {0xf8c6, 0x00e8918f}, /* U+844F [2000] */ - {0xf8c7, 0x00e89191}, /* U+8451 [2000] */ - {0xf8c8, 0x00e89192}, /* U+8452 [2000] */ - {0xf8c9, 0x00e89199}, /* U+8459 [2000] */ - {0xf8ca, 0x00e8919a}, /* U+845A [2000] */ - {0xf8cb, 0x00e8919c}, /* U+845C [2000] */ + {0xf8c3, 0xe89097}, /* U+8417 [2000] */ + {0xf8c4, 0xe890b9}, /* U+8439 [2000] */ + {0xf8c5, 0xe8918a}, /* U+844A [2000] */ + {0xf8c6, 0xe8918f}, /* U+844F [2000] */ + {0xf8c7, 0xe89191}, /* U+8451 [2000] */ + {0xf8c8, 0xe89192}, /* U+8452 [2000] */ + {0xf8c9, 0xe89199}, /* U+8459 [2000] */ + {0xf8ca, 0xe8919a}, /* U+845A [2000] */ + {0xf8cb, 0xe8919c}, /* U+845C [2000] */ {0xf8cc, 0xf0a6b39d}, /* U+26CDD [2000] [Unicode3.1] */ - {0xf8cd, 0x00e891a5}, /* U+8465 [2000] */ - {0xf8ce, 0x00e891b6}, /* U+8476 [2000] */ - {0xf8cf, 0x00e891b8}, /* U+8478 [2000] */ - {0xf8d0, 0x00e891bc}, /* U+847C [2000] */ - {0xf8d1, 0x00e89281}, /* U+8481 [2000] */ - {0xf8d2, 0x00e4948d}, /* U+450D [2000] */ - {0xf8d3, 0x00e8939c}, /* U+84DC [2000] */ - {0xf8d4, 0x00e89297}, /* U+8497 [2000] */ - {0xf8d5, 0x00e892a6}, /* U+84A6 [2000] */ - {0xf8d6, 0x00e892be}, /* U+84BE [2000] */ - {0xf8d7, 0x00e49488}, /* U+4508 [2000] */ - {0xf8d8, 0x00e8938e}, /* U+84CE [2000] */ - {0xf8d9, 0x00e8938f}, /* U+84CF [2000] */ - {0xf8da, 0x00e89393}, /* U+84D3 [2000] */ + {0xf8cd, 0xe891a5}, /* U+8465 [2000] */ + {0xf8ce, 0xe891b6}, /* U+8476 [2000] */ + {0xf8cf, 0xe891b8}, /* U+8478 [2000] */ + {0xf8d0, 0xe891bc}, /* U+847C [2000] */ + {0xf8d1, 0xe89281}, /* U+8481 [2000] */ + {0xf8d2, 0xe4948d}, /* U+450D [2000] */ + {0xf8d3, 0xe8939c}, /* U+84DC [2000] */ + {0xf8d4, 0xe89297}, /* U+8497 [2000] */ + {0xf8d5, 0xe892a6}, /* U+84A6 [2000] */ + {0xf8d6, 0xe892be}, /* U+84BE [2000] */ + {0xf8d7, 0xe49488}, /* U+4508 [2000] */ + {0xf8d8, 0xe8938e}, /* U+84CE [2000] */ + {0xf8d9, 0xe8938f}, /* U+84CF [2000] */ + {0xf8da, 0xe89393}, /* U+84D3 [2000] */ {0xf8db, 0xf0a6b9a5}, /* U+26E65 [2000] [Unicode3.1] */ - {0xf8dc, 0x00e893a7}, /* U+84E7 [2000] */ - {0xf8dd, 0x00e893aa}, /* U+84EA [2000] */ - {0xf8de, 0x00e893af}, /* U+84EF [2000] */ - {0xf8df, 0x00e893b0}, /* U+84F0 [2000] */ - {0xf8e0, 0x00e893b1}, /* U+84F1 [2000] */ - {0xf8e1, 0x00e893ba}, /* U+84FA [2000] */ - {0xf8e2, 0x00e893bd}, /* U+84FD [2000] */ - {0xf8e3, 0x00e8948c}, /* U+850C [2000] */ - {0xf8e4, 0x00e8949b}, /* U+851B [2000] */ - {0xf8e5, 0x00e894a4}, /* U+8524 [2000] */ - {0xf8e6, 0x00e894a5}, /* U+8525 [2000] */ - {0xf8e7, 0x00e894ab}, /* U+852B [2000] */ - {0xf8e8, 0x00e894b4}, /* U+8534 [2000] */ - {0xf8e9, 0x00e8958f}, /* U+854F [2000] */ - {0xf8ea, 0x00e895af}, /* U+856F [2000] */ - {0xf8eb, 0x00e494a5}, /* U+4525 [2000] */ - {0xf8ec, 0x00e49583}, /* U+4543 [2000] */ - {0xf8ed, 0x00e894be}, /* U+853E [2000] */ - {0xf8ee, 0x00e89591}, /* U+8551 [2000] */ - {0xf8ef, 0x00e89593}, /* U+8553 [2000] */ - {0xf8f0, 0x00e8959e}, /* U+855E [2000] */ - {0xf8f1, 0x00e895a1}, /* U+8561 [2000] */ - {0xf8f2, 0x00e895a2}, /* U+8562 [2000] */ + {0xf8dc, 0xe893a7}, /* U+84E7 [2000] */ + {0xf8dd, 0xe893aa}, /* U+84EA [2000] */ + {0xf8de, 0xe893af}, /* U+84EF [2000] */ + {0xf8df, 0xe893b0}, /* U+84F0 [2000] */ + {0xf8e0, 0xe893b1}, /* U+84F1 [2000] */ + {0xf8e1, 0xe893ba}, /* U+84FA [2000] */ + {0xf8e2, 0xe893bd}, /* U+84FD [2000] */ + {0xf8e3, 0xe8948c}, /* U+850C [2000] */ + {0xf8e4, 0xe8949b}, /* U+851B [2000] */ + {0xf8e5, 0xe894a4}, /* U+8524 [2000] */ + {0xf8e6, 0xe894a5}, /* U+8525 [2000] */ + {0xf8e7, 0xe894ab}, /* U+852B [2000] */ + {0xf8e8, 0xe894b4}, /* U+8534 [2000] */ + {0xf8e9, 0xe8958f}, /* U+854F [2000] */ + {0xf8ea, 0xe895af}, /* U+856F [2000] */ + {0xf8eb, 0xe494a5}, /* U+4525 [2000] */ + {0xf8ec, 0xe49583}, /* U+4543 [2000] */ + {0xf8ed, 0xe894be}, /* U+853E [2000] */ + {0xf8ee, 0xe89591}, /* U+8551 [2000] */ + {0xf8ef, 0xe89593}, /* U+8553 [2000] */ + {0xf8f0, 0xe8959e}, /* U+855E [2000] */ + {0xf8f1, 0xe895a1}, /* U+8561 [2000] */ + {0xf8f2, 0xe895a2}, /* U+8562 [2000] */ {0xf8f3, 0xf0a6be94}, /* U+26F94 [2000] [Unicode3.1] */ - {0xf8f4, 0x00e895bb}, /* U+857B [2000] */ - {0xf8f5, 0x00e895bd}, /* U+857D [2000] */ - {0xf8f6, 0x00e895bf}, /* U+857F [2000] */ - {0xf8f7, 0x00e89681}, /* U+8581 [2000] */ - {0xf8f8, 0x00e89686}, /* U+8586 [2000] */ - {0xf8f9, 0x00e89693}, /* U+8593 [2000] */ - {0xf8fa, 0x00e8969d}, /* U+859D [2000] */ - {0xf8fb, 0x00e8969f}, /* U+859F [2000] */ + {0xf8f4, 0xe895bb}, /* U+857B [2000] */ + {0xf8f5, 0xe895bd}, /* U+857D [2000] */ + {0xf8f6, 0xe895bf}, /* U+857F [2000] */ + {0xf8f7, 0xe89681}, /* U+8581 [2000] */ + {0xf8f8, 0xe89686}, /* U+8586 [2000] */ + {0xf8f9, 0xe89693}, /* U+8593 [2000] */ + {0xf8fa, 0xe8969d}, /* U+859D [2000] */ + {0xf8fb, 0xe8969f}, /* U+859F [2000] */ {0xf8fc, 0xf0a6bfb8}, /* U+26FF8 [2000] [Unicode3.1] */ {0xf940, 0xf0a6bfb6}, /* U+26FF6 [2000] [Unicode3.1] */ {0xf941, 0xf0a6bfb7}, /* U+26FF7 [2000] [Unicode3.1] */ - {0xf942, 0x00e896b7}, /* U+85B7 [2000] */ - {0xf943, 0x00e896bc}, /* U+85BC [2000] */ - {0xf944, 0x00e89787}, /* U+85C7 [2000] */ - {0xf945, 0x00e8978a}, /* U+85CA [2000] */ - {0xf946, 0x00e89798}, /* U+85D8 [2000] */ - {0xf947, 0x00e89799}, /* U+85D9 [2000] */ - {0xf948, 0x00e8979f}, /* U+85DF [2000] */ - {0xf949, 0x00e897a1}, /* U+85E1 [2000] */ - {0xf94a, 0x00e897a6}, /* U+85E6 [2000] */ - {0xf94b, 0x00e897b6}, /* U+85F6 [2000] */ - {0xf94c, 0x00e89880}, /* U+8600 [2000] */ - {0xf94d, 0x00e89891}, /* U+8611 [2000] */ - {0xf94e, 0x00e8989e}, /* U+861E [2000] */ - {0xf94f, 0x00e898a1}, /* U+8621 [2000] */ - {0xf950, 0x00e898a4}, /* U+8624 [2000] */ - {0xf951, 0x00e898a7}, /* U+8627 [2000] */ + {0xf942, 0xe896b7}, /* U+85B7 [2000] */ + {0xf943, 0xe896bc}, /* U+85BC [2000] */ + {0xf944, 0xe89787}, /* U+85C7 [2000] */ + {0xf945, 0xe8978a}, /* U+85CA [2000] */ + {0xf946, 0xe89798}, /* U+85D8 [2000] */ + {0xf947, 0xe89799}, /* U+85D9 [2000] */ + {0xf948, 0xe8979f}, /* U+85DF [2000] */ + {0xf949, 0xe897a1}, /* U+85E1 [2000] */ + {0xf94a, 0xe897a6}, /* U+85E6 [2000] */ + {0xf94b, 0xe897b6}, /* U+85F6 [2000] */ + {0xf94c, 0xe89880}, /* U+8600 [2000] */ + {0xf94d, 0xe89891}, /* U+8611 [2000] */ + {0xf94e, 0xe8989e}, /* U+861E [2000] */ + {0xf94f, 0xe898a1}, /* U+8621 [2000] */ + {0xf950, 0xe898a4}, /* U+8624 [2000] */ + {0xf951, 0xe898a7}, /* U+8627 [2000] */ {0xf952, 0xf0a7848d}, /* U+2710D [2000] [Unicode3.1] */ - {0xf953, 0x00e898b9}, /* U+8639 [2000] */ - {0xf954, 0x00e898bc}, /* U+863C [2000] */ + {0xf953, 0xe898b9}, /* U+8639 [2000] */ + {0xf954, 0xe898bc}, /* U+863C [2000] */ {0xf955, 0xf0a784b9}, /* U+27139 [2000] [Unicode3.1] */ - {0xf956, 0x00e89980}, /* U+8640 [2000] */ - {0xf957, 0x00efa8a0}, /* U+FA20 CJK COMPATIBILITY IDEOGRAPH-FA20 [2000] */ - {0xf958, 0x00e89993}, /* U+8653 [2000] */ - {0xf959, 0x00e89996}, /* U+8656 [2000] */ - {0xf95a, 0x00e899af}, /* U+866F [2000] */ - {0xf95b, 0x00e899b7}, /* U+8677 [2000] */ - {0xf95c, 0x00e899ba}, /* U+867A [2000] */ - {0xf95d, 0x00e89a87}, /* U+8687 [2000] */ - {0xf95e, 0x00e89a89}, /* U+8689 [2000] */ - {0xf95f, 0x00e89a8d}, /* U+868D [2000] */ - {0xf960, 0x00e89a91}, /* U+8691 [2000] */ - {0xf961, 0x00e89a9c}, /* U+869C [2000] */ - {0xf962, 0x00e89a9d}, /* U+869D [2000] */ - {0xf963, 0x00e89aa8}, /* U+86A8 [2000] */ - {0xf964, 0x00efa8a1}, /* U+FA21 CJK COMPATIBILITY IDEOGRAPH-FA21 [2000] */ - {0xf965, 0x00e89ab1}, /* U+86B1 [2000] */ - {0xf966, 0x00e89ab3}, /* U+86B3 [2000] */ - {0xf967, 0x00e89b81}, /* U+86C1 [2000] */ - {0xf968, 0x00e89b83}, /* U+86C3 [2000] */ - {0xf969, 0x00e89b91}, /* U+86D1 [2000] */ - {0xf96a, 0x00e89b95}, /* U+86D5 [2000] */ - {0xf96b, 0x00e89b97}, /* U+86D7 [2000] */ - {0xf96c, 0x00e89ba3}, /* U+86E3 [2000] */ - {0xf96d, 0x00e89ba6}, /* U+86E6 [2000] */ - {0xf96e, 0x00e496b8}, /* U+45B8 [2000] */ - {0xf96f, 0x00e89c85}, /* U+8705 [2000] */ - {0xf970, 0x00e89c87}, /* U+8707 [2000] */ - {0xf971, 0x00e89c8e}, /* U+870E [2000] */ - {0xf972, 0x00e89c90}, /* U+8710 [2000] */ - {0xf973, 0x00e89c93}, /* U+8713 [2000] */ - {0xf974, 0x00e89c99}, /* U+8719 [2000] */ - {0xf975, 0x00e89c9f}, /* U+871F [2000] */ - {0xf976, 0x00e89ca1}, /* U+8721 [2000] */ - {0xf977, 0x00e89ca3}, /* U+8723 [2000] */ - {0xf978, 0x00e89cb1}, /* U+8731 [2000] */ - {0xf979, 0x00e89cba}, /* U+873A [2000] */ - {0xf97a, 0x00e89cbe}, /* U+873E [2000] */ - {0xf97b, 0x00e89d80}, /* U+8740 [2000] */ - {0xf97c, 0x00e89d83}, /* U+8743 [2000] */ - {0xf97d, 0x00e89d91}, /* U+8751 [2000] */ - {0xf97e, 0x00e89d98}, /* U+8758 [2000] */ - {0xf980, 0x00e89da4}, /* U+8764 [2000] */ - {0xf981, 0x00e89da5}, /* U+8765 [2000] */ - {0xf982, 0x00e89db2}, /* U+8772 [2000] */ - {0xf983, 0x00e89dbc}, /* U+877C [2000] */ + {0xf956, 0xe89980}, /* U+8640 [2000] */ + {0xf957, 0xefa8a0}, /* U+FA20 CJK COMPATIBILITY IDEOGRAPH-FA20 [2000] */ + {0xf958, 0xe89993}, /* U+8653 [2000] */ + {0xf959, 0xe89996}, /* U+8656 [2000] */ + {0xf95a, 0xe899af}, /* U+866F [2000] */ + {0xf95b, 0xe899b7}, /* U+8677 [2000] */ + {0xf95c, 0xe899ba}, /* U+867A [2000] */ + {0xf95d, 0xe89a87}, /* U+8687 [2000] */ + {0xf95e, 0xe89a89}, /* U+8689 [2000] */ + {0xf95f, 0xe89a8d}, /* U+868D [2000] */ + {0xf960, 0xe89a91}, /* U+8691 [2000] */ + {0xf961, 0xe89a9c}, /* U+869C [2000] */ + {0xf962, 0xe89a9d}, /* U+869D [2000] */ + {0xf963, 0xe89aa8}, /* U+86A8 [2000] */ + {0xf964, 0xefa8a1}, /* U+FA21 CJK COMPATIBILITY IDEOGRAPH-FA21 [2000] */ + {0xf965, 0xe89ab1}, /* U+86B1 [2000] */ + {0xf966, 0xe89ab3}, /* U+86B3 [2000] */ + {0xf967, 0xe89b81}, /* U+86C1 [2000] */ + {0xf968, 0xe89b83}, /* U+86C3 [2000] */ + {0xf969, 0xe89b91}, /* U+86D1 [2000] */ + {0xf96a, 0xe89b95}, /* U+86D5 [2000] */ + {0xf96b, 0xe89b97}, /* U+86D7 [2000] */ + {0xf96c, 0xe89ba3}, /* U+86E3 [2000] */ + {0xf96d, 0xe89ba6}, /* U+86E6 [2000] */ + {0xf96e, 0xe496b8}, /* U+45B8 [2000] */ + {0xf96f, 0xe89c85}, /* U+8705 [2000] */ + {0xf970, 0xe89c87}, /* U+8707 [2000] */ + {0xf971, 0xe89c8e}, /* U+870E [2000] */ + {0xf972, 0xe89c90}, /* U+8710 [2000] */ + {0xf973, 0xe89c93}, /* U+8713 [2000] */ + {0xf974, 0xe89c99}, /* U+8719 [2000] */ + {0xf975, 0xe89c9f}, /* U+871F [2000] */ + {0xf976, 0xe89ca1}, /* U+8721 [2000] */ + {0xf977, 0xe89ca3}, /* U+8723 [2000] */ + {0xf978, 0xe89cb1}, /* U+8731 [2000] */ + {0xf979, 0xe89cba}, /* U+873A [2000] */ + {0xf97a, 0xe89cbe}, /* U+873E [2000] */ + {0xf97b, 0xe89d80}, /* U+8740 [2000] */ + {0xf97c, 0xe89d83}, /* U+8743 [2000] */ + {0xf97d, 0xe89d91}, /* U+8751 [2000] */ + {0xf97e, 0xe89d98}, /* U+8758 [2000] */ + {0xf980, 0xe89da4}, /* U+8764 [2000] */ + {0xf981, 0xe89da5}, /* U+8765 [2000] */ + {0xf982, 0xe89db2}, /* U+8772 [2000] */ + {0xf983, 0xe89dbc}, /* U+877C [2000] */ {0xf984, 0xf0a78f9b}, /* U+273DB [2000] [Unicode3.1] */ {0xf985, 0xf0a78f9a}, /* U+273DA [2000] [Unicode3.1] */ - {0xf986, 0x00e89ea7}, /* U+87A7 [2000] */ - {0xf987, 0x00e89e89}, /* U+8789 [2000] */ - {0xf988, 0x00e89e8b}, /* U+878B [2000] */ - {0xf989, 0x00e89e93}, /* U+8793 [2000] */ - {0xf98a, 0x00e89ea0}, /* U+87A0 [2000] */ + {0xf986, 0xe89ea7}, /* U+87A7 [2000] */ + {0xf987, 0xe89e89}, /* U+8789 [2000] */ + {0xf988, 0xe89e8b}, /* U+878B [2000] */ + {0xf989, 0xe89e93}, /* U+8793 [2000] */ + {0xf98a, 0xe89ea0}, /* U+87A0 [2000] */ {0xf98b, 0xf0a78fbe}, /* U+273FE [2000] [Unicode3.1] */ - {0xf98c, 0x00e497a5}, /* U+45E5 [2000] */ - {0xf98d, 0x00e89ebe}, /* U+87BE [2000] */ + {0xf98c, 0xe497a5}, /* U+45E5 [2000] */ + {0xf98d, 0xe89ebe}, /* U+87BE [2000] */ {0xf98e, 0xf0a79090}, /* U+27410 [2000] [Unicode3.1] */ - {0xf98f, 0x00e89f81}, /* U+87C1 [2000] */ - {0xf990, 0x00e89f8e}, /* U+87CE [2000] */ - {0xf991, 0x00e89fb5}, /* U+87F5 [2000] */ - {0xf992, 0x00e89f9f}, /* U+87DF [2000] */ + {0xf98f, 0xe89f81}, /* U+87C1 [2000] */ + {0xf990, 0xe89f8e}, /* U+87CE [2000] */ + {0xf991, 0xe89fb5}, /* U+87F5 [2000] */ + {0xf992, 0xe89f9f}, /* U+87DF [2000] */ {0xf993, 0xf0a79189}, /* U+27449 [2000] [Unicode3.1] */ - {0xf994, 0x00e89fa3}, /* U+87E3 [2000] */ - {0xf995, 0x00e89fa5}, /* U+87E5 [2000] */ - {0xf996, 0x00e89fa6}, /* U+87E6 [2000] */ - {0xf997, 0x00e89faa}, /* U+87EA [2000] */ - {0xf998, 0x00e89fab}, /* U+87EB [2000] */ - {0xf999, 0x00e89fad}, /* U+87ED [2000] */ - {0xf99a, 0x00e8a081}, /* U+8801 [2000] */ - {0xf99b, 0x00e8a083}, /* U+8803 [2000] */ - {0xf99c, 0x00e8a08b}, /* U+880B [2000] */ - {0xf99d, 0x00e8a093}, /* U+8813 [2000] */ - {0xf99e, 0x00e8a0a8}, /* U+8828 [2000] */ - {0xf99f, 0x00e8a0ae}, /* U+882E [2000] */ - {0xf9a0, 0x00e8a0b2}, /* U+8832 [2000] */ - {0xf9a1, 0x00e8a0bc}, /* U+883C [2000] */ - {0xf9a2, 0x00e4988f}, /* U+460F [2000] */ - {0xf9a3, 0x00e8a18a}, /* U+884A [2000] */ - {0xf9a4, 0x00e8a198}, /* U+8858 [2000] */ - {0xf9a5, 0x00e8a19f}, /* U+885F [2000] */ - {0xf9a6, 0x00e8a1a4}, /* U+8864 [2000] */ + {0xf994, 0xe89fa3}, /* U+87E3 [2000] */ + {0xf995, 0xe89fa5}, /* U+87E5 [2000] */ + {0xf996, 0xe89fa6}, /* U+87E6 [2000] */ + {0xf997, 0xe89faa}, /* U+87EA [2000] */ + {0xf998, 0xe89fab}, /* U+87EB [2000] */ + {0xf999, 0xe89fad}, /* U+87ED [2000] */ + {0xf99a, 0xe8a081}, /* U+8801 [2000] */ + {0xf99b, 0xe8a083}, /* U+8803 [2000] */ + {0xf99c, 0xe8a08b}, /* U+880B [2000] */ + {0xf99d, 0xe8a093}, /* U+8813 [2000] */ + {0xf99e, 0xe8a0a8}, /* U+8828 [2000] */ + {0xf99f, 0xe8a0ae}, /* U+882E [2000] */ + {0xf9a0, 0xe8a0b2}, /* U+8832 [2000] */ + {0xf9a1, 0xe8a0bc}, /* U+883C [2000] */ + {0xf9a2, 0xe4988f}, /* U+460F [2000] */ + {0xf9a3, 0xe8a18a}, /* U+884A [2000] */ + {0xf9a4, 0xe8a198}, /* U+8858 [2000] */ + {0xf9a5, 0xe8a19f}, /* U+885F [2000] */ + {0xf9a6, 0xe8a1a4}, /* U+8864 [2000] */ {0xf9a7, 0xf0a79895}, /* U+27615 [2000] [Unicode3.1] */ {0xf9a8, 0xf0a79894}, /* U+27614 [2000] [Unicode3.1] */ - {0xf9a9, 0x00e8a1a9}, /* U+8869 [2000] */ + {0xf9a9, 0xe8a1a9}, /* U+8869 [2000] */ {0xf9aa, 0xf0a798b1}, /* U+27631 [2000] [Unicode3.1] */ - {0xf9ab, 0x00e8a1af}, /* U+886F [2000] */ - {0xf9ac, 0x00e8a2a0}, /* U+88A0 [2000] */ - {0xf9ad, 0x00e8a2bc}, /* U+88BC [2000] */ - {0xf9ae, 0x00e8a2bd}, /* U+88BD [2000] */ - {0xf9af, 0x00e8a2be}, /* U+88BE [2000] */ - {0xf9b0, 0x00e8a380}, /* U+88C0 [2000] */ - {0xf9b1, 0x00e8a392}, /* U+88D2 [2000] */ + {0xf9ab, 0xe8a1af}, /* U+886F [2000] */ + {0xf9ac, 0xe8a2a0}, /* U+88A0 [2000] */ + {0xf9ad, 0xe8a2bc}, /* U+88BC [2000] */ + {0xf9ae, 0xe8a2bd}, /* U+88BD [2000] */ + {0xf9af, 0xe8a2be}, /* U+88BE [2000] */ + {0xf9b0, 0xe8a380}, /* U+88C0 [2000] */ + {0xf9b1, 0xe8a392}, /* U+88D2 [2000] */ {0xf9b2, 0xf0a79a93}, /* U+27693 [2000] [Unicode3.1] */ - {0xf9b3, 0x00e8a391}, /* U+88D1 [2000] */ - {0xf9b4, 0x00e8a393}, /* U+88D3 [2000] */ - {0xf9b5, 0x00e8a39b}, /* U+88DB [2000] */ - {0xf9b6, 0x00e8a3b0}, /* U+88F0 [2000] */ - {0xf9b7, 0x00e8a3b1}, /* U+88F1 [2000] */ - {0xf9b8, 0x00e49981}, /* U+4641 [2000] */ - {0xf9b9, 0x00e8a481}, /* U+8901 [2000] */ + {0xf9b3, 0xe8a391}, /* U+88D1 [2000] */ + {0xf9b4, 0xe8a393}, /* U+88D3 [2000] */ + {0xf9b5, 0xe8a39b}, /* U+88DB [2000] */ + {0xf9b6, 0xe8a3b0}, /* U+88F0 [2000] */ + {0xf9b7, 0xe8a3b1}, /* U+88F1 [2000] */ + {0xf9b8, 0xe49981}, /* U+4641 [2000] */ + {0xf9b9, 0xe8a481}, /* U+8901 [2000] */ {0xf9ba, 0xf0a79c8e}, /* U+2770E [2000] [Unicode3.1] */ - {0xf9bb, 0x00e8a4b7}, /* U+8937 [2000] */ + {0xf9bb, 0xe8a4b7}, /* U+8937 [2000] */ {0xf9bc, 0xf0a79ca3}, /* U+27723 [2000] [Unicode3.1] */ - {0xf9bd, 0x00e8a582}, /* U+8942 [2000] */ - {0xf9be, 0x00e8a585}, /* U+8945 [2000] */ - {0xf9bf, 0x00e8a589}, /* U+8949 [2000] */ + {0xf9bd, 0xe8a582}, /* U+8942 [2000] */ + {0xf9be, 0xe8a585}, /* U+8945 [2000] */ + {0xf9bf, 0xe8a589}, /* U+8949 [2000] */ {0xf9c0, 0xf0a79d92}, /* U+27752 [2000] [Unicode3.1] */ - {0xf9c1, 0x00e499a5}, /* U+4665 [2000] */ - {0xf9c2, 0x00e8a5a2}, /* U+8962 [2000] */ - {0xf9c3, 0x00e8a680}, /* U+8980 [2000] */ - {0xf9c4, 0x00e8a689}, /* U+8989 [2000] */ - {0xf9c5, 0x00e8a690}, /* U+8990 [2000] */ - {0xf9c6, 0x00e8a69f}, /* U+899F [2000] */ - {0xf9c7, 0x00e8a6b0}, /* U+89B0 [2000] */ - {0xf9c8, 0x00e8a6b7}, /* U+89B7 [2000] */ - {0xf9c9, 0x00e8a796}, /* U+89D6 [2000] */ - {0xf9ca, 0x00e8a798}, /* U+89D8 [2000] */ - {0xf9cb, 0x00e8a7ab}, /* U+89EB [2000] */ - {0xf9cc, 0x00e49aa1}, /* U+46A1 [2000] */ - {0xf9cd, 0x00e8a7b1}, /* U+89F1 [2000] */ - {0xf9ce, 0x00e8a7b3}, /* U+89F3 [2000] */ - {0xf9cf, 0x00e8a7bd}, /* U+89FD [2000] */ - {0xf9d0, 0x00e8a7bf}, /* U+89FF [2000] */ - {0xf9d1, 0x00e49aaf}, /* U+46AF [2000] */ - {0xf9d2, 0x00e8a891}, /* U+8A11 [2000] */ - {0xf9d3, 0x00e8a894}, /* U+8A14 [2000] */ + {0xf9c1, 0xe499a5}, /* U+4665 [2000] */ + {0xf9c2, 0xe8a5a2}, /* U+8962 [2000] */ + {0xf9c3, 0xe8a680}, /* U+8980 [2000] */ + {0xf9c4, 0xe8a689}, /* U+8989 [2000] */ + {0xf9c5, 0xe8a690}, /* U+8990 [2000] */ + {0xf9c6, 0xe8a69f}, /* U+899F [2000] */ + {0xf9c7, 0xe8a6b0}, /* U+89B0 [2000] */ + {0xf9c8, 0xe8a6b7}, /* U+89B7 [2000] */ + {0xf9c9, 0xe8a796}, /* U+89D6 [2000] */ + {0xf9ca, 0xe8a798}, /* U+89D8 [2000] */ + {0xf9cb, 0xe8a7ab}, /* U+89EB [2000] */ + {0xf9cc, 0xe49aa1}, /* U+46A1 [2000] */ + {0xf9cd, 0xe8a7b1}, /* U+89F1 [2000] */ + {0xf9ce, 0xe8a7b3}, /* U+89F3 [2000] */ + {0xf9cf, 0xe8a7bd}, /* U+89FD [2000] */ + {0xf9d0, 0xe8a7bf}, /* U+89FF [2000] */ + {0xf9d1, 0xe49aaf}, /* U+46AF [2000] */ + {0xf9d2, 0xe8a891}, /* U+8A11 [2000] */ + {0xf9d3, 0xe8a894}, /* U+8A14 [2000] */ {0xf9d4, 0xf0a7a685}, /* U+27985 [2000] [Unicode3.1] */ - {0xf9d5, 0x00e8a8a1}, /* U+8A21 [2000] */ - {0xf9d6, 0x00e8a8b5}, /* U+8A35 [2000] */ - {0xf9d7, 0x00e8a8be}, /* U+8A3E [2000] */ - {0xf9d8, 0x00e8a985}, /* U+8A45 [2000] */ - {0xf9d9, 0x00e8a98d}, /* U+8A4D [2000] */ - {0xf9da, 0x00e8a998}, /* U+8A58 [2000] */ - {0xf9db, 0x00e8aaae}, /* U+8AAE [2000] */ - {0xf9dc, 0x00e8aa90}, /* U+8A90 [2000] */ - {0xf9dd, 0x00e8aab7}, /* U+8AB7 [2000] */ - {0xf9de, 0x00e8aabe}, /* U+8ABE [2000] */ - {0xf9df, 0x00e8ab97}, /* U+8AD7 [2000] */ - {0xf9e0, 0x00e8abbc}, /* U+8AFC [2000] */ + {0xf9d5, 0xe8a8a1}, /* U+8A21 [2000] */ + {0xf9d6, 0xe8a8b5}, /* U+8A35 [2000] */ + {0xf9d7, 0xe8a8be}, /* U+8A3E [2000] */ + {0xf9d8, 0xe8a985}, /* U+8A45 [2000] */ + {0xf9d9, 0xe8a98d}, /* U+8A4D [2000] */ + {0xf9da, 0xe8a998}, /* U+8A58 [2000] */ + {0xf9db, 0xe8aaae}, /* U+8AAE [2000] */ + {0xf9dc, 0xe8aa90}, /* U+8A90 [2000] */ + {0xf9dd, 0xe8aab7}, /* U+8AB7 [2000] */ + {0xf9de, 0xe8aabe}, /* U+8ABE [2000] */ + {0xf9df, 0xe8ab97}, /* U+8AD7 [2000] */ + {0xf9e0, 0xe8abbc}, /* U+8AFC [2000] */ {0xf9e1, 0xf0a7aa84}, /* U+27A84 [2000] [Unicode3.1] */ - {0xf9e2, 0x00e8ac8a}, /* U+8B0A [2000] */ - {0xf9e3, 0x00e8ac85}, /* U+8B05 [2000] */ - {0xf9e4, 0x00e8ac8d}, /* U+8B0D [2000] */ - {0xf9e5, 0x00e8ac9c}, /* U+8B1C [2000] */ - {0xf9e6, 0x00e8ac9f}, /* U+8B1F [2000] */ - {0xf9e7, 0x00e8acad}, /* U+8B2D [2000] */ - {0xf9e8, 0x00e8ad83}, /* U+8B43 [2000] */ - {0xf9e9, 0x00e49c8c}, /* U+470C [2000] */ - {0xf9ea, 0x00e8ad91}, /* U+8B51 [2000] */ - {0xf9eb, 0x00e8ad9e}, /* U+8B5E [2000] */ - {0xf9ec, 0x00e8adb6}, /* U+8B76 [2000] */ - {0xf9ed, 0x00e8adbf}, /* U+8B7F [2000] */ - {0xf9ee, 0x00e8ae81}, /* U+8B81 [2000] */ - {0xf9ef, 0x00e8ae8b}, /* U+8B8B [2000] */ - {0xf9f0, 0x00e8ae94}, /* U+8B94 [2000] */ - {0xf9f1, 0x00e8ae95}, /* U+8B95 [2000] */ - {0xf9f2, 0x00e8ae9c}, /* U+8B9C [2000] */ - {0xf9f3, 0x00e8ae9e}, /* U+8B9E [2000] */ - {0xf9f4, 0x00e8b0b9}, /* U+8C39 [2000] */ + {0xf9e2, 0xe8ac8a}, /* U+8B0A [2000] */ + {0xf9e3, 0xe8ac85}, /* U+8B05 [2000] */ + {0xf9e4, 0xe8ac8d}, /* U+8B0D [2000] */ + {0xf9e5, 0xe8ac9c}, /* U+8B1C [2000] */ + {0xf9e6, 0xe8ac9f}, /* U+8B1F [2000] */ + {0xf9e7, 0xe8acad}, /* U+8B2D [2000] */ + {0xf9e8, 0xe8ad83}, /* U+8B43 [2000] */ + {0xf9e9, 0xe49c8c}, /* U+470C [2000] */ + {0xf9ea, 0xe8ad91}, /* U+8B51 [2000] */ + {0xf9eb, 0xe8ad9e}, /* U+8B5E [2000] */ + {0xf9ec, 0xe8adb6}, /* U+8B76 [2000] */ + {0xf9ed, 0xe8adbf}, /* U+8B7F [2000] */ + {0xf9ee, 0xe8ae81}, /* U+8B81 [2000] */ + {0xf9ef, 0xe8ae8b}, /* U+8B8B [2000] */ + {0xf9f0, 0xe8ae94}, /* U+8B94 [2000] */ + {0xf9f1, 0xe8ae95}, /* U+8B95 [2000] */ + {0xf9f2, 0xe8ae9c}, /* U+8B9C [2000] */ + {0xf9f3, 0xe8ae9e}, /* U+8B9E [2000] */ + {0xf9f4, 0xe8b0b9}, /* U+8C39 [2000] */ {0xf9f5, 0xf0a7aeb3}, /* U+27BB3 [2000] [Unicode3.1] */ - {0xf9f6, 0x00e8b0bd}, /* U+8C3D [2000] */ + {0xf9f6, 0xe8b0bd}, /* U+8C3D [2000] */ {0xf9f7, 0xf0a7aebe}, /* U+27BBE [2000] [Unicode3.1] */ {0xf9f8, 0xf0a7af87}, /* U+27BC7 [2000] [Unicode3.1] */ - {0xf9f9, 0x00e8b185}, /* U+8C45 [2000] */ - {0xf9fa, 0x00e8b187}, /* U+8C47 [2000] */ - {0xf9fb, 0x00e8b18f}, /* U+8C4F [2000] */ - {0xf9fc, 0x00e8b194}, /* U+8C54 [2000] */ - {0xfa40, 0x00e8b197}, /* U+8C57 [2000] */ - {0xfa41, 0x00e8b1a9}, /* U+8C69 [2000] */ - {0xfa42, 0x00e8b1ad}, /* U+8C6D [2000] */ - {0xfa43, 0x00e8b1b3}, /* U+8C73 [2000] */ + {0xf9f9, 0xe8b185}, /* U+8C45 [2000] */ + {0xf9fa, 0xe8b187}, /* U+8C47 [2000] */ + {0xf9fb, 0xe8b18f}, /* U+8C4F [2000] */ + {0xf9fc, 0xe8b194}, /* U+8C54 [2000] */ + {0xfa40, 0xe8b197}, /* U+8C57 [2000] */ + {0xfa41, 0xe8b1a9}, /* U+8C69 [2000] */ + {0xfa42, 0xe8b1ad}, /* U+8C6D [2000] */ + {0xfa43, 0xe8b1b3}, /* U+8C73 [2000] */ {0xfa44, 0xf0a7b2b8}, /* U+27CB8 [2000] [Unicode3.1] */ - {0xfa45, 0x00e8b293}, /* U+8C93 [2000] */ - {0xfa46, 0x00e8b292}, /* U+8C92 [2000] */ - {0xfa47, 0x00e8b299}, /* U+8C99 [2000] */ - {0xfa48, 0x00e49da4}, /* U+4764 [2000] */ - {0xfa49, 0x00e8b29b}, /* U+8C9B [2000] */ - {0xfa4a, 0x00e8b2a4}, /* U+8CA4 [2000] */ - {0xfa4b, 0x00e8b396}, /* U+8CD6 [2000] */ - {0xfa4c, 0x00e8b395}, /* U+8CD5 [2000] */ - {0xfa4d, 0x00e8b399}, /* U+8CD9 [2000] */ + {0xfa45, 0xe8b293}, /* U+8C93 [2000] */ + {0xfa46, 0xe8b292}, /* U+8C92 [2000] */ + {0xfa47, 0xe8b299}, /* U+8C99 [2000] */ + {0xfa48, 0xe49da4}, /* U+4764 [2000] */ + {0xfa49, 0xe8b29b}, /* U+8C9B [2000] */ + {0xfa4a, 0xe8b2a4}, /* U+8CA4 [2000] */ + {0xfa4b, 0xe8b396}, /* U+8CD6 [2000] */ + {0xfa4c, 0xe8b395}, /* U+8CD5 [2000] */ + {0xfa4d, 0xe8b399}, /* U+8CD9 [2000] */ {0xfa4e, 0xf0a7b6a0}, /* U+27DA0 [2000] [Unicode3.1] */ - {0xfa4f, 0x00e8b3b0}, /* U+8CF0 [2000] */ - {0xfa50, 0x00e8b3b1}, /* U+8CF1 [2000] */ + {0xfa4f, 0xe8b3b0}, /* U+8CF0 [2000] */ + {0xfa50, 0xe8b3b1}, /* U+8CF1 [2000] */ {0xfa51, 0xf0a7b890}, /* U+27E10 [2000] [Unicode3.1] */ - {0xfa52, 0x00e8b489}, /* U+8D09 [2000] */ - {0xfa53, 0x00e8b48e}, /* U+8D0E [2000] */ - {0xfa54, 0x00e8b5ac}, /* U+8D6C [2000] */ - {0xfa55, 0x00e8b684}, /* U+8D84 [2000] */ - {0xfa56, 0x00e8b695}, /* U+8D95 [2000] */ - {0xfa57, 0x00e8b6a6}, /* U+8DA6 [2000] */ + {0xfa52, 0xe8b489}, /* U+8D09 [2000] */ + {0xfa53, 0xe8b48e}, /* U+8D0E [2000] */ + {0xfa54, 0xe8b5ac}, /* U+8D6C [2000] */ + {0xfa55, 0xe8b684}, /* U+8D84 [2000] */ + {0xfa56, 0xe8b695}, /* U+8D95 [2000] */ + {0xfa57, 0xe8b6a6}, /* U+8DA6 [2000] */ {0xfa58, 0xf0a7beb7}, /* U+27FB7 [2000] [Unicode3.1] */ - {0xfa59, 0x00e8b786}, /* U+8DC6 [2000] */ - {0xfa5a, 0x00e8b788}, /* U+8DC8 [2000] */ - {0xfa5b, 0x00e8b799}, /* U+8DD9 [2000] */ - {0xfa5c, 0x00e8b7ac}, /* U+8DEC [2000] */ - {0xfa5d, 0x00e8b88c}, /* U+8E0C [2000] */ - {0xfa5e, 0x00e49fbd}, /* U+47FD [2000] */ - {0xfa5f, 0x00e8b7bd}, /* U+8DFD [2000] */ - {0xfa60, 0x00e8b886}, /* U+8E06 [2000] */ + {0xfa59, 0xe8b786}, /* U+8DC6 [2000] */ + {0xfa5a, 0xe8b788}, /* U+8DC8 [2000] */ + {0xfa5b, 0xe8b799}, /* U+8DD9 [2000] */ + {0xfa5c, 0xe8b7ac}, /* U+8DEC [2000] */ + {0xfa5d, 0xe8b88c}, /* U+8E0C [2000] */ + {0xfa5e, 0xe49fbd}, /* U+47FD [2000] */ + {0xfa5f, 0xe8b7bd}, /* U+8DFD [2000] */ + {0xfa60, 0xe8b886}, /* U+8E06 [2000] */ {0xfa61, 0xf0a8828a}, /* U+2808A [2000] [Unicode3.1] */ - {0xfa62, 0x00e8b894}, /* U+8E14 [2000] */ - {0xfa63, 0x00e8b896}, /* U+8E16 [2000] */ - {0xfa64, 0x00e8b8a1}, /* U+8E21 [2000] */ - {0xfa65, 0x00e8b8a2}, /* U+8E22 [2000] */ - {0xfa66, 0x00e8b8a7}, /* U+8E27 [2000] */ + {0xfa62, 0xe8b894}, /* U+8E14 [2000] */ + {0xfa63, 0xe8b896}, /* U+8E16 [2000] */ + {0xfa64, 0xe8b8a1}, /* U+8E21 [2000] */ + {0xfa65, 0xe8b8a2}, /* U+8E22 [2000] */ + {0xfa66, 0xe8b8a7}, /* U+8E27 [2000] */ {0xfa67, 0xf0a882bb}, /* U+280BB [2000] [Unicode3.1] */ - {0xfa68, 0x00e4a096}, /* U+4816 [2000] */ - {0xfa69, 0x00e8b8b6}, /* U+8E36 [2000] */ - {0xfa6a, 0x00e8b8b9}, /* U+8E39 [2000] */ - {0xfa6b, 0x00e8b98b}, /* U+8E4B [2000] */ - {0xfa6c, 0x00e8b994}, /* U+8E54 [2000] */ - {0xfa6d, 0x00e8b9a2}, /* U+8E62 [2000] */ - {0xfa6e, 0x00e8b9ac}, /* U+8E6C [2000] */ - {0xfa6f, 0x00e8b9ad}, /* U+8E6D [2000] */ - {0xfa70, 0x00e8b9af}, /* U+8E6F [2000] */ - {0xfa71, 0x00e8ba98}, /* U+8E98 [2000] */ - {0xfa72, 0x00e8ba9e}, /* U+8E9E [2000] */ - {0xfa73, 0x00e8baae}, /* U+8EAE [2000] */ - {0xfa74, 0x00e8bab3}, /* U+8EB3 [2000] */ - {0xfa75, 0x00e8bab5}, /* U+8EB5 [2000] */ - {0xfa76, 0x00e8bab6}, /* U+8EB6 [2000] */ - {0xfa77, 0x00e8babb}, /* U+8EBB [2000] */ + {0xfa68, 0xe4a096}, /* U+4816 [2000] */ + {0xfa69, 0xe8b8b6}, /* U+8E36 [2000] */ + {0xfa6a, 0xe8b8b9}, /* U+8E39 [2000] */ + {0xfa6b, 0xe8b98b}, /* U+8E4B [2000] */ + {0xfa6c, 0xe8b994}, /* U+8E54 [2000] */ + {0xfa6d, 0xe8b9a2}, /* U+8E62 [2000] */ + {0xfa6e, 0xe8b9ac}, /* U+8E6C [2000] */ + {0xfa6f, 0xe8b9ad}, /* U+8E6D [2000] */ + {0xfa70, 0xe8b9af}, /* U+8E6F [2000] */ + {0xfa71, 0xe8ba98}, /* U+8E98 [2000] */ + {0xfa72, 0xe8ba9e}, /* U+8E9E [2000] */ + {0xfa73, 0xe8baae}, /* U+8EAE [2000] */ + {0xfa74, 0xe8bab3}, /* U+8EB3 [2000] */ + {0xfa75, 0xe8bab5}, /* U+8EB5 [2000] */ + {0xfa76, 0xe8bab6}, /* U+8EB6 [2000] */ + {0xfa77, 0xe8babb}, /* U+8EBB [2000] */ {0xfa78, 0xf0a88a82}, /* U+28282 [2000] [Unicode3.1] */ - {0xfa79, 0x00e8bb91}, /* U+8ED1 [2000] */ - {0xfa7a, 0x00e8bb94}, /* U+8ED4 [2000] */ - {0xfa7b, 0x00e4a18e}, /* U+484E [2000] */ - {0xfa7c, 0x00e8bbb9}, /* U+8EF9 [2000] */ + {0xfa79, 0xe8bb91}, /* U+8ED1 [2000] */ + {0xfa7a, 0xe8bb94}, /* U+8ED4 [2000] */ + {0xfa7b, 0xe4a18e}, /* U+484E [2000] */ + {0xfa7c, 0xe8bbb9}, /* U+8EF9 [2000] */ {0xfa7d, 0xf0a88bb3}, /* U+282F3 [2000] [Unicode3.1] */ - {0xfa7e, 0x00e8bc80}, /* U+8F00 [2000] */ - {0xfa80, 0x00e8bc88}, /* U+8F08 [2000] */ - {0xfa81, 0x00e8bc97}, /* U+8F17 [2000] */ - {0xfa82, 0x00e8bcab}, /* U+8F2B [2000] */ - {0xfa83, 0x00e8bd80}, /* U+8F40 [2000] */ - {0xfa84, 0x00e8bd8a}, /* U+8F4A [2000] */ - {0xfa85, 0x00e8bd98}, /* U+8F58 [2000] */ + {0xfa7e, 0xe8bc80}, /* U+8F00 [2000] */ + {0xfa80, 0xe8bc88}, /* U+8F08 [2000] */ + {0xfa81, 0xe8bc97}, /* U+8F17 [2000] */ + {0xfa82, 0xe8bcab}, /* U+8F2B [2000] */ + {0xfa83, 0xe8bd80}, /* U+8F40 [2000] */ + {0xfa84, 0xe8bd8a}, /* U+8F4A [2000] */ + {0xfa85, 0xe8bd98}, /* U+8F58 [2000] */ {0xfa86, 0xf0a8908c}, /* U+2840C [2000] [Unicode3.1] */ - {0xfa87, 0x00e8bea4}, /* U+8FA4 [2000] */ - {0xfa88, 0x00e8beb4}, /* U+8FB4 [2000] */ - {0xfa89, 0x00efa9a6}, /* U+FA66 CJK COMPATIBILITY IDEOGRAPH-FA66 [2000] [Unicode3.2] */ - {0xfa8a, 0x00e8beb6}, /* U+8FB6 [2000] */ + {0xfa87, 0xe8bea4}, /* U+8FA4 [2000] */ + {0xfa88, 0xe8beb4}, /* U+8FB4 [2000] */ + {0xfa89, 0xefa9a6}, /* U+FA66 CJK COMPATIBILITY IDEOGRAPH-FA66 [2000] [Unicode3.2] */ + {0xfa8a, 0xe8beb6}, /* U+8FB6 [2000] */ {0xfa8b, 0xf0a89195}, /* U+28455 [2000] [Unicode3.1] */ - {0xfa8c, 0x00e8bf81}, /* U+8FC1 [2000] */ - {0xfa8d, 0x00e8bf86}, /* U+8FC6 [2000] */ - {0xfa8e, 0x00efa8a4}, /* U+FA24 CJK COMPATIBILITY IDEOGRAPH-FA24 [2000] */ - {0xfa8f, 0x00e8bf8a}, /* U+8FCA [2000] */ - {0xfa90, 0x00e8bf8d}, /* U+8FCD [2000] */ - {0xfa91, 0x00e8bf93}, /* U+8FD3 [2000] */ - {0xfa92, 0x00e8bf95}, /* U+8FD5 [2000] */ - {0xfa93, 0x00e8bfa0}, /* U+8FE0 [2000] */ - {0xfa94, 0x00e8bfb1}, /* U+8FF1 [2000] */ - {0xfa95, 0x00e8bfb5}, /* U+8FF5 [2000] */ - {0xfa96, 0x00e8bfbb}, /* U+8FFB [2000] */ - {0xfa97, 0x00e98082}, /* U+9002 [2000] */ - {0xfa98, 0x00e9808c}, /* U+900C [2000] */ - {0xfa99, 0x00e980b7}, /* U+9037 [2000] */ + {0xfa8c, 0xe8bf81}, /* U+8FC1 [2000] */ + {0xfa8d, 0xe8bf86}, /* U+8FC6 [2000] */ + {0xfa8e, 0xefa8a4}, /* U+FA24 CJK COMPATIBILITY IDEOGRAPH-FA24 [2000] */ + {0xfa8f, 0xe8bf8a}, /* U+8FCA [2000] */ + {0xfa90, 0xe8bf8d}, /* U+8FCD [2000] */ + {0xfa91, 0xe8bf93}, /* U+8FD3 [2000] */ + {0xfa92, 0xe8bf95}, /* U+8FD5 [2000] */ + {0xfa93, 0xe8bfa0}, /* U+8FE0 [2000] */ + {0xfa94, 0xe8bfb1}, /* U+8FF1 [2000] */ + {0xfa95, 0xe8bfb5}, /* U+8FF5 [2000] */ + {0xfa96, 0xe8bfbb}, /* U+8FFB [2000] */ + {0xfa97, 0xe98082}, /* U+9002 [2000] */ + {0xfa98, 0xe9808c}, /* U+900C [2000] */ + {0xfa99, 0xe980b7}, /* U+9037 [2000] */ {0xfa9a, 0xf0a895ab}, /* U+2856B [2000] [Unicode3.1] */ - {0xfa9b, 0x00e98183}, /* U+9043 [2000] */ - {0xfa9c, 0x00e98184}, /* U+9044 [2000] */ - {0xfa9d, 0x00e9819d}, /* U+905D [2000] */ + {0xfa9b, 0xe98183}, /* U+9043 [2000] */ + {0xfa9c, 0xe98184}, /* U+9044 [2000] */ + {0xfa9d, 0xe9819d}, /* U+905D [2000] */ {0xfa9e, 0xf0a89788}, /* U+285C8 [2000] [Unicode3.1] */ {0xfa9f, 0xf0a89789}, /* U+285C9 [2000] [Unicode3.1] */ - {0xfaa0, 0x00e98285}, /* U+9085 [2000] */ - {0xfaa1, 0x00e9828c}, /* U+908C [2000] */ - {0xfaa2, 0x00e98290}, /* U+9090 [2000] */ - {0xfaa3, 0x00e9989d}, /* U+961D [2000] */ - {0xfaa4, 0x00e982a1}, /* U+90A1 [2000] */ - {0xfaa5, 0x00e4a2b5}, /* U+48B5 [2000] */ - {0xfaa6, 0x00e982b0}, /* U+90B0 [2000] */ - {0xfaa7, 0x00e982b6}, /* U+90B6 [2000] */ - {0xfaa8, 0x00e98383}, /* U+90C3 [2000] */ - {0xfaa9, 0x00e98388}, /* U+90C8 [2000] */ + {0xfaa0, 0xe98285}, /* U+9085 [2000] */ + {0xfaa1, 0xe9828c}, /* U+908C [2000] */ + {0xfaa2, 0xe98290}, /* U+9090 [2000] */ + {0xfaa3, 0xe9989d}, /* U+961D [2000] */ + {0xfaa4, 0xe982a1}, /* U+90A1 [2000] */ + {0xfaa5, 0xe4a2b5}, /* U+48B5 [2000] */ + {0xfaa6, 0xe982b0}, /* U+90B0 [2000] */ + {0xfaa7, 0xe982b6}, /* U+90B6 [2000] */ + {0xfaa8, 0xe98383}, /* U+90C3 [2000] */ + {0xfaa9, 0xe98388}, /* U+90C8 [2000] */ {0xfaaa, 0xf0a89b97}, /* U+286D7 [2000] [Unicode3.1] */ - {0xfaab, 0x00e9839c}, /* U+90DC [2000] */ - {0xfaac, 0x00e9839f}, /* U+90DF [2000] */ + {0xfaab, 0xe9839c}, /* U+90DC [2000] */ + {0xfaac, 0xe9839f}, /* U+90DF [2000] */ {0xfaad, 0xf0a89bba}, /* U+286FA [2000] [Unicode3.1] */ - {0xfaae, 0x00e983b6}, /* U+90F6 [2000] */ - {0xfaaf, 0x00e983b2}, /* U+90F2 [2000] */ - {0xfab0, 0x00e98480}, /* U+9100 [2000] */ - {0xfab1, 0x00e983ab}, /* U+90EB [2000] */ - {0xfab2, 0x00e983be}, /* U+90FE [2000] */ - {0xfab3, 0x00e983bf}, /* U+90FF [2000] */ - {0xfab4, 0x00e98484}, /* U+9104 [2000] */ - {0xfab5, 0x00e98486}, /* U+9106 [2000] */ - {0xfab6, 0x00e98498}, /* U+9118 [2000] */ - {0xfab7, 0x00e9849c}, /* U+911C [2000] */ - {0xfab8, 0x00e9849e}, /* U+911E [2000] */ - {0xfab9, 0x00e984b7}, /* U+9137 [2000] */ - {0xfaba, 0x00e984b9}, /* U+9139 [2000] */ - {0xfabb, 0x00e984ba}, /* U+913A [2000] */ - {0xfabc, 0x00e98586}, /* U+9146 [2000] */ - {0xfabd, 0x00e98587}, /* U+9147 [2000] */ - {0xfabe, 0x00e98597}, /* U+9157 [2000] */ - {0xfabf, 0x00e98599}, /* U+9159 [2000] */ - {0xfac0, 0x00e985a1}, /* U+9161 [2000] */ - {0xfac1, 0x00e985a4}, /* U+9164 [2000] */ - {0xfac2, 0x00e985b4}, /* U+9174 [2000] */ - {0xfac3, 0x00e985b9}, /* U+9179 [2000] */ - {0xfac4, 0x00e98685}, /* U+9185 [2000] */ - {0xfac5, 0x00e9868e}, /* U+918E [2000] */ - {0xfac6, 0x00e986a8}, /* U+91A8 [2000] */ - {0xfac7, 0x00e986ae}, /* U+91AE [2000] */ - {0xfac8, 0x00e986b3}, /* U+91B3 [2000] */ - {0xfac9, 0x00e986b6}, /* U+91B6 [2000] */ - {0xfaca, 0x00e98783}, /* U+91C3 [2000] */ - {0xfacb, 0x00e98784}, /* U+91C4 [2000] */ - {0xfacc, 0x00e9879a}, /* U+91DA [2000] */ + {0xfaae, 0xe983b6}, /* U+90F6 [2000] */ + {0xfaaf, 0xe983b2}, /* U+90F2 [2000] */ + {0xfab0, 0xe98480}, /* U+9100 [2000] */ + {0xfab1, 0xe983ab}, /* U+90EB [2000] */ + {0xfab2, 0xe983be}, /* U+90FE [2000] */ + {0xfab3, 0xe983bf}, /* U+90FF [2000] */ + {0xfab4, 0xe98484}, /* U+9104 [2000] */ + {0xfab5, 0xe98486}, /* U+9106 [2000] */ + {0xfab6, 0xe98498}, /* U+9118 [2000] */ + {0xfab7, 0xe9849c}, /* U+911C [2000] */ + {0xfab8, 0xe9849e}, /* U+911E [2000] */ + {0xfab9, 0xe984b7}, /* U+9137 [2000] */ + {0xfaba, 0xe984b9}, /* U+9139 [2000] */ + {0xfabb, 0xe984ba}, /* U+913A [2000] */ + {0xfabc, 0xe98586}, /* U+9146 [2000] */ + {0xfabd, 0xe98587}, /* U+9147 [2000] */ + {0xfabe, 0xe98597}, /* U+9157 [2000] */ + {0xfabf, 0xe98599}, /* U+9159 [2000] */ + {0xfac0, 0xe985a1}, /* U+9161 [2000] */ + {0xfac1, 0xe985a4}, /* U+9164 [2000] */ + {0xfac2, 0xe985b4}, /* U+9174 [2000] */ + {0xfac3, 0xe985b9}, /* U+9179 [2000] */ + {0xfac4, 0xe98685}, /* U+9185 [2000] */ + {0xfac5, 0xe9868e}, /* U+918E [2000] */ + {0xfac6, 0xe986a8}, /* U+91A8 [2000] */ + {0xfac7, 0xe986ae}, /* U+91AE [2000] */ + {0xfac8, 0xe986b3}, /* U+91B3 [2000] */ + {0xfac9, 0xe986b6}, /* U+91B6 [2000] */ + {0xfaca, 0xe98783}, /* U+91C3 [2000] */ + {0xfacb, 0xe98784}, /* U+91C4 [2000] */ + {0xfacc, 0xe9879a}, /* U+91DA [2000] */ {0xfacd, 0xf0a8a589}, /* U+28949 [2000] [Unicode3.1] */ {0xface, 0xf0a8a586}, /* U+28946 [2000] [Unicode3.1] */ - {0xfacf, 0x00e987ac}, /* U+91EC [2000] */ - {0xfad0, 0x00e987ae}, /* U+91EE [2000] */ - {0xfad1, 0x00e98881}, /* U+9201 [2000] */ - {0xfad2, 0x00e9888a}, /* U+920A [2000] */ - {0xfad3, 0x00e98896}, /* U+9216 [2000] */ - {0xfad4, 0x00e98897}, /* U+9217 [2000] */ + {0xfacf, 0xe987ac}, /* U+91EC [2000] */ + {0xfad0, 0xe987ae}, /* U+91EE [2000] */ + {0xfad1, 0xe98881}, /* U+9201 [2000] */ + {0xfad2, 0xe9888a}, /* U+920A [2000] */ + {0xfad3, 0xe98896}, /* U+9216 [2000] */ + {0xfad4, 0xe98897}, /* U+9217 [2000] */ {0xfad5, 0xf0a8a5ab}, /* U+2896B [2000] [Unicode3.1] */ - {0xfad6, 0x00e988b3}, /* U+9233 [2000] */ - {0xfad7, 0x00e98982}, /* U+9242 [2000] */ - {0xfad8, 0x00e98987}, /* U+9247 [2000] */ - {0xfad9, 0x00e9898a}, /* U+924A [2000] */ - {0xfada, 0x00e9898e}, /* U+924E [2000] */ - {0xfadb, 0x00e98991}, /* U+9251 [2000] */ - {0xfadc, 0x00e98996}, /* U+9256 [2000] */ - {0xfadd, 0x00e98999}, /* U+9259 [2000] */ - {0xfade, 0x00e989a0}, /* U+9260 [2000] */ - {0xfadf, 0x00e989a1}, /* U+9261 [2000] */ - {0xfae0, 0x00e989a5}, /* U+9265 [2000] */ - {0xfae1, 0x00e989a7}, /* U+9267 [2000] */ - {0xfae2, 0x00e989a8}, /* U+9268 [2000] */ + {0xfad6, 0xe988b3}, /* U+9233 [2000] */ + {0xfad7, 0xe98982}, /* U+9242 [2000] */ + {0xfad8, 0xe98987}, /* U+9247 [2000] */ + {0xfad9, 0xe9898a}, /* U+924A [2000] */ + {0xfada, 0xe9898e}, /* U+924E [2000] */ + {0xfadb, 0xe98991}, /* U+9251 [2000] */ + {0xfadc, 0xe98996}, /* U+9256 [2000] */ + {0xfadd, 0xe98999}, /* U+9259 [2000] */ + {0xfade, 0xe989a0}, /* U+9260 [2000] */ + {0xfadf, 0xe989a1}, /* U+9261 [2000] */ + {0xfae0, 0xe989a5}, /* U+9265 [2000] */ + {0xfae1, 0xe989a7}, /* U+9267 [2000] */ + {0xfae2, 0xe989a8}, /* U+9268 [2000] */ {0xfae3, 0xf0a8a687}, /* U+28987 [2000] [Unicode3.1] */ {0xfae4, 0xf0a8a688}, /* U+28988 [2000] [Unicode3.1] */ - {0xfae5, 0x00e989bc}, /* U+927C [2000] */ - {0xfae6, 0x00e989bd}, /* U+927D [2000] */ - {0xfae7, 0x00e989bf}, /* U+927F [2000] */ - {0xfae8, 0x00e98a89}, /* U+9289 [2000] */ - {0xfae9, 0x00e98a8d}, /* U+928D [2000] */ - {0xfaea, 0x00e98a97}, /* U+9297 [2000] */ - {0xfaeb, 0x00e98a99}, /* U+9299 [2000] */ - {0xfaec, 0x00e98a9f}, /* U+929F [2000] */ - {0xfaed, 0x00e98aa7}, /* U+92A7 [2000] */ - {0xfaee, 0x00e98aab}, /* U+92AB [2000] */ + {0xfae5, 0xe989bc}, /* U+927C [2000] */ + {0xfae6, 0xe989bd}, /* U+927D [2000] */ + {0xfae7, 0xe989bf}, /* U+927F [2000] */ + {0xfae8, 0xe98a89}, /* U+9289 [2000] */ + {0xfae9, 0xe98a8d}, /* U+928D [2000] */ + {0xfaea, 0xe98a97}, /* U+9297 [2000] */ + {0xfaeb, 0xe98a99}, /* U+9299 [2000] */ + {0xfaec, 0xe98a9f}, /* U+929F [2000] */ + {0xfaed, 0xe98aa7}, /* U+92A7 [2000] */ + {0xfaee, 0xe98aab}, /* U+92AB [2000] */ {0xfaef, 0xf0a8a6ba}, /* U+289BA [2000] [Unicode3.1] */ {0xfaf0, 0xf0a8a6bb}, /* U+289BB [2000] [Unicode3.1] */ - {0xfaf1, 0x00e98ab2}, /* U+92B2 [2000] */ - {0xfaf2, 0x00e98abf}, /* U+92BF [2000] */ - {0xfaf3, 0x00e98b80}, /* U+92C0 [2000] */ - {0xfaf4, 0x00e98b86}, /* U+92C6 [2000] */ - {0xfaf5, 0x00e98b8e}, /* U+92CE [2000] */ - {0xfaf6, 0x00e98b90}, /* U+92D0 [2000] */ - {0xfaf7, 0x00e98b97}, /* U+92D7 [2000] */ - {0xfaf8, 0x00e98b99}, /* U+92D9 [2000] */ - {0xfaf9, 0x00e98ba5}, /* U+92E5 [2000] */ - {0xfafa, 0x00e98ba7}, /* U+92E7 [2000] */ - {0xfafb, 0x00e98c91}, /* U+9311 [2000] */ + {0xfaf1, 0xe98ab2}, /* U+92B2 [2000] */ + {0xfaf2, 0xe98abf}, /* U+92BF [2000] */ + {0xfaf3, 0xe98b80}, /* U+92C0 [2000] */ + {0xfaf4, 0xe98b86}, /* U+92C6 [2000] */ + {0xfaf5, 0xe98b8e}, /* U+92CE [2000] */ + {0xfaf6, 0xe98b90}, /* U+92D0 [2000] */ + {0xfaf7, 0xe98b97}, /* U+92D7 [2000] */ + {0xfaf8, 0xe98b99}, /* U+92D9 [2000] */ + {0xfaf9, 0xe98ba5}, /* U+92E5 [2000] */ + {0xfafa, 0xe98ba7}, /* U+92E7 [2000] */ + {0xfafb, 0xe98c91}, /* U+9311 [2000] */ {0xfafc, 0xf0a8a89e}, /* U+28A1E [2000] [Unicode3.1] */ {0xfb40, 0xf0a8a8a9}, /* U+28A29 [2000] [Unicode3.1] */ - {0xfb41, 0x00e98bb7}, /* U+92F7 [2000] */ - {0xfb42, 0x00e98bb9}, /* U+92F9 [2000] */ - {0xfb43, 0x00e98bbb}, /* U+92FB [2000] */ - {0xfb44, 0x00e98c82}, /* U+9302 [2000] */ - {0xfb45, 0x00e98c8d}, /* U+930D [2000] */ - {0xfb46, 0x00e98c95}, /* U+9315 [2000] */ - {0xfb47, 0x00e98c9d}, /* U+931D [2000] */ - {0xfb48, 0x00e98c9e}, /* U+931E [2000] */ - {0xfb49, 0x00e98ca7}, /* U+9327 [2000] */ - {0xfb4a, 0x00e98ca9}, /* U+9329 [2000] */ + {0xfb41, 0xe98bb7}, /* U+92F7 [2000] */ + {0xfb42, 0xe98bb9}, /* U+92F9 [2000] */ + {0xfb43, 0xe98bbb}, /* U+92FB [2000] */ + {0xfb44, 0xe98c82}, /* U+9302 [2000] */ + {0xfb45, 0xe98c8d}, /* U+930D [2000] */ + {0xfb46, 0xe98c95}, /* U+9315 [2000] */ + {0xfb47, 0xe98c9d}, /* U+931D [2000] */ + {0xfb48, 0xe98c9e}, /* U+931E [2000] */ + {0xfb49, 0xe98ca7}, /* U+9327 [2000] */ + {0xfb4a, 0xe98ca9}, /* U+9329 [2000] */ {0xfb4b, 0xf0a8a9b1}, /* U+28A71 [2000] [Unicode3.1] */ {0xfb4c, 0xf0a8a983}, /* U+28A43 [2000] [Unicode3.1] */ - {0xfb4d, 0x00e98d87}, /* U+9347 [2000] */ - {0xfb4e, 0x00e98d91}, /* U+9351 [2000] */ - {0xfb4f, 0x00e98d97}, /* U+9357 [2000] */ - {0xfb50, 0x00e98d9a}, /* U+935A [2000] */ - {0xfb51, 0x00e98dab}, /* U+936B [2000] */ - {0xfb52, 0x00e98db1}, /* U+9371 [2000] */ - {0xfb53, 0x00e98db3}, /* U+9373 [2000] */ - {0xfb54, 0x00e98ea1}, /* U+93A1 [2000] */ + {0xfb4d, 0xe98d87}, /* U+9347 [2000] */ + {0xfb4e, 0xe98d91}, /* U+9351 [2000] */ + {0xfb4f, 0xe98d97}, /* U+9357 [2000] */ + {0xfb50, 0xe98d9a}, /* U+935A [2000] */ + {0xfb51, 0xe98dab}, /* U+936B [2000] */ + {0xfb52, 0xe98db1}, /* U+9371 [2000] */ + {0xfb53, 0xe98db3}, /* U+9373 [2000] */ + {0xfb54, 0xe98ea1}, /* U+93A1 [2000] */ {0xfb55, 0xf0a8aa99}, /* U+28A99 [2000] [Unicode3.1] */ {0xfb56, 0xf0a8ab8d}, /* U+28ACD [2000] [Unicode3.1] */ - {0xfb57, 0x00e98e88}, /* U+9388 [2000] */ - {0xfb58, 0x00e98e8b}, /* U+938B [2000] */ - {0xfb59, 0x00e98e8f}, /* U+938F [2000] */ - {0xfb5a, 0x00e98e9e}, /* U+939E [2000] */ - {0xfb5b, 0x00e98fb5}, /* U+93F5 [2000] */ + {0xfb57, 0xe98e88}, /* U+9388 [2000] */ + {0xfb58, 0xe98e8b}, /* U+938B [2000] */ + {0xfb59, 0xe98e8f}, /* U+938F [2000] */ + {0xfb5a, 0xe98e9e}, /* U+939E [2000] */ + {0xfb5b, 0xe98fb5}, /* U+93F5 [2000] */ {0xfb5c, 0xf0a8aba4}, /* U+28AE4 [2000] [Unicode3.1] */ {0xfb5d, 0xf0a8ab9d}, /* U+28ADD [2000] [Unicode3.1] */ - {0xfb5e, 0x00e98fb1}, /* U+93F1 [2000] */ - {0xfb5f, 0x00e98f81}, /* U+93C1 [2000] */ - {0xfb60, 0x00e98f87}, /* U+93C7 [2000] */ - {0xfb61, 0x00e98f9c}, /* U+93DC [2000] */ - {0xfb62, 0x00e98fa2}, /* U+93E2 [2000] */ - {0xfb63, 0x00e98fa7}, /* U+93E7 [2000] */ - {0xfb64, 0x00e99089}, /* U+9409 [2000] */ - {0xfb65, 0x00e9908f}, /* U+940F [2000] */ - {0xfb66, 0x00e99096}, /* U+9416 [2000] */ - {0xfb67, 0x00e99097}, /* U+9417 [2000] */ - {0xfb68, 0x00e98fbb}, /* U+93FB [2000] */ - {0xfb69, 0x00e990b2}, /* U+9432 [2000] */ - {0xfb6a, 0x00e990b4}, /* U+9434 [2000] */ - {0xfb6b, 0x00e990bb}, /* U+943B [2000] */ - {0xfb6c, 0x00e99185}, /* U+9445 [2000] */ + {0xfb5e, 0xe98fb1}, /* U+93F1 [2000] */ + {0xfb5f, 0xe98f81}, /* U+93C1 [2000] */ + {0xfb60, 0xe98f87}, /* U+93C7 [2000] */ + {0xfb61, 0xe98f9c}, /* U+93DC [2000] */ + {0xfb62, 0xe98fa2}, /* U+93E2 [2000] */ + {0xfb63, 0xe98fa7}, /* U+93E7 [2000] */ + {0xfb64, 0xe99089}, /* U+9409 [2000] */ + {0xfb65, 0xe9908f}, /* U+940F [2000] */ + {0xfb66, 0xe99096}, /* U+9416 [2000] */ + {0xfb67, 0xe99097}, /* U+9417 [2000] */ + {0xfb68, 0xe98fbb}, /* U+93FB [2000] */ + {0xfb69, 0xe990b2}, /* U+9432 [2000] */ + {0xfb6a, 0xe990b4}, /* U+9434 [2000] */ + {0xfb6b, 0xe990bb}, /* U+943B [2000] */ + {0xfb6c, 0xe99185}, /* U+9445 [2000] */ {0xfb6d, 0xf0a8af81}, /* U+28BC1 [2000] [Unicode3.1] */ {0xfb6e, 0xf0a8afaf}, /* U+28BEF [2000] [Unicode3.1] */ - {0xfb6f, 0x00e991ad}, /* U+946D [2000] */ - {0xfb70, 0x00e991af}, /* U+946F [2000] */ - {0xfb71, 0x00e995b8}, /* U+9578 [2000] */ - {0xfb72, 0x00e995b9}, /* U+9579 [2000] */ - {0xfb73, 0x00e99686}, /* U+9586 [2000] */ - {0xfb74, 0x00e9968c}, /* U+958C [2000] */ - {0xfb75, 0x00e9968d}, /* U+958D [2000] */ + {0xfb6f, 0xe991ad}, /* U+946D [2000] */ + {0xfb70, 0xe991af}, /* U+946F [2000] */ + {0xfb71, 0xe995b8}, /* U+9578 [2000] */ + {0xfb72, 0xe995b9}, /* U+9579 [2000] */ + {0xfb73, 0xe99686}, /* U+9586 [2000] */ + {0xfb74, 0xe9968c}, /* U+958C [2000] */ + {0xfb75, 0xe9968d}, /* U+958D [2000] */ {0xfb76, 0xf0a8b490}, /* U+28D10 [2000] [Unicode3.1] */ - {0xfb77, 0x00e996ab}, /* U+95AB [2000] */ - {0xfb78, 0x00e996b4}, /* U+95B4 [2000] */ + {0xfb77, 0xe996ab}, /* U+95AB [2000] */ + {0xfb78, 0xe996b4}, /* U+95B4 [2000] */ {0xfb79, 0xf0a8b5b1}, /* U+28D71 [2000] [Unicode3.1] */ - {0xfb7a, 0x00e99788}, /* U+95C8 [2000] */ + {0xfb7a, 0xe99788}, /* U+95C8 [2000] */ {0xfb7b, 0xf0a8b7bb}, /* U+28DFB [2000] [Unicode3.1] */ {0xfb7c, 0xf0a8b89f}, /* U+28E1F [2000] [Unicode3.1] */ - {0xfb7d, 0x00e998ac}, /* U+962C [2000] */ - {0xfb7e, 0x00e998b3}, /* U+9633 [2000] */ - {0xfb80, 0x00e998b4}, /* U+9634 [2000] */ + {0xfb7d, 0xe998ac}, /* U+962C [2000] */ + {0xfb7e, 0xe998b3}, /* U+9633 [2000] */ + {0xfb80, 0xe998b4}, /* U+9634 [2000] */ {0xfb81, 0xf0a8b8b6}, /* U+28E36 [2000] [Unicode3.1] */ - {0xfb82, 0x00e998bc}, /* U+963C [2000] */ - {0xfb83, 0x00e99981}, /* U+9641 [2000] */ - {0xfb84, 0x00e999a1}, /* U+9661 [2000] */ + {0xfb82, 0xe998bc}, /* U+963C [2000] */ + {0xfb83, 0xe99981}, /* U+9641 [2000] */ + {0xfb84, 0xe999a1}, /* U+9661 [2000] */ {0xfb85, 0xf0a8ba89}, /* U+28E89 [2000] [Unicode3.1] */ - {0xfb86, 0x00e99a82}, /* U+9682 [2000] */ + {0xfb86, 0xe99a82}, /* U+9682 [2000] */ {0xfb87, 0xf0a8bbab}, /* U+28EEB [2000] [Unicode3.1] */ - {0xfb88, 0x00e99a9a}, /* U+969A [2000] */ + {0xfb88, 0xe99a9a}, /* U+969A [2000] */ {0xfb89, 0xf0a8bcb2}, /* U+28F32 [2000] [Unicode3.1] */ - {0xfb8a, 0x00e4a7a7}, /* U+49E7 [2000] */ - {0xfb8b, 0x00e99aa9}, /* U+96A9 [2000] */ - {0xfb8c, 0x00e99aaf}, /* U+96AF [2000] */ - {0xfb8d, 0x00e99ab3}, /* U+96B3 [2000] */ - {0xfb8e, 0x00e99aba}, /* U+96BA [2000] */ - {0xfb8f, 0x00e99abd}, /* U+96BD [2000] */ - {0xfb90, 0x00e4a7ba}, /* U+49FA [2000] */ + {0xfb8a, 0xe4a7a7}, /* U+49E7 [2000] */ + {0xfb8b, 0xe99aa9}, /* U+96A9 [2000] */ + {0xfb8c, 0xe99aaf}, /* U+96AF [2000] */ + {0xfb8d, 0xe99ab3}, /* U+96B3 [2000] */ + {0xfb8e, 0xe99aba}, /* U+96BA [2000] */ + {0xfb8f, 0xe99abd}, /* U+96BD [2000] */ + {0xfb90, 0xe4a7ba}, /* U+49FA [2000] */ {0xfb91, 0xf0a8bfb8}, /* U+28FF8 [2000] [Unicode3.1] */ - {0xfb92, 0x00e99b98}, /* U+96D8 [2000] */ - {0xfb93, 0x00e99b9a}, /* U+96DA [2000] */ - {0xfb94, 0x00e99b9d}, /* U+96DD [2000] */ - {0xfb95, 0x00e4a884}, /* U+4A04 [2000] */ - {0xfb96, 0x00e99c94}, /* U+9714 [2000] */ - {0xfb97, 0x00e99ca3}, /* U+9723 [2000] */ - {0xfb98, 0x00e4a8a9}, /* U+4A29 [2000] */ - {0xfb99, 0x00e99cb6}, /* U+9736 [2000] */ - {0xfb9a, 0x00e99d81}, /* U+9741 [2000] */ - {0xfb9b, 0x00e99d87}, /* U+9747 [2000] */ - {0xfb9c, 0x00e99d95}, /* U+9755 [2000] */ - {0xfb9d, 0x00e99d97}, /* U+9757 [2000] */ - {0xfb9e, 0x00e99d9b}, /* U+975B [2000] */ - {0xfb9f, 0x00e99daa}, /* U+976A [2000] */ + {0xfb92, 0xe99b98}, /* U+96D8 [2000] */ + {0xfb93, 0xe99b9a}, /* U+96DA [2000] */ + {0xfb94, 0xe99b9d}, /* U+96DD [2000] */ + {0xfb95, 0xe4a884}, /* U+4A04 [2000] */ + {0xfb96, 0xe99c94}, /* U+9714 [2000] */ + {0xfb97, 0xe99ca3}, /* U+9723 [2000] */ + {0xfb98, 0xe4a8a9}, /* U+4A29 [2000] */ + {0xfb99, 0xe99cb6}, /* U+9736 [2000] */ + {0xfb9a, 0xe99d81}, /* U+9741 [2000] */ + {0xfb9b, 0xe99d87}, /* U+9747 [2000] */ + {0xfb9c, 0xe99d95}, /* U+9755 [2000] */ + {0xfb9d, 0xe99d97}, /* U+9757 [2000] */ + {0xfb9e, 0xe99d9b}, /* U+975B [2000] */ + {0xfb9f, 0xe99daa}, /* U+976A [2000] */ {0xfba0, 0xf0a98aa0}, /* U+292A0 [2000] [Unicode3.1] */ {0xfba1, 0xf0a98ab1}, /* U+292B1 [2000] [Unicode3.1] */ - {0xfba2, 0x00e99e96}, /* U+9796 [2000] */ - {0xfba3, 0x00e99e9a}, /* U+979A [2000] */ - {0xfba4, 0x00e99e9e}, /* U+979E [2000] */ - {0xfba5, 0x00e99ea2}, /* U+97A2 [2000] */ - {0xfba6, 0x00e99eb1}, /* U+97B1 [2000] */ - {0xfba7, 0x00e99eb2}, /* U+97B2 [2000] */ - {0xfba8, 0x00e99ebe}, /* U+97BE [2000] */ - {0xfba9, 0x00e99f8c}, /* U+97CC [2000] */ - {0xfbaa, 0x00e99f91}, /* U+97D1 [2000] */ - {0xfbab, 0x00e99f94}, /* U+97D4 [2000] */ - {0xfbac, 0x00e99f98}, /* U+97D8 [2000] */ - {0xfbad, 0x00e99f99}, /* U+97D9 [2000] */ - {0xfbae, 0x00e99fa1}, /* U+97E1 [2000] */ - {0xfbaf, 0x00e99fb1}, /* U+97F1 [2000] */ - {0xfbb0, 0x00e9a084}, /* U+9804 [2000] */ - {0xfbb1, 0x00e9a08d}, /* U+980D [2000] */ - {0xfbb2, 0x00e9a08e}, /* U+980E [2000] */ - {0xfbb3, 0x00e9a094}, /* U+9814 [2000] */ - {0xfbb4, 0x00e9a096}, /* U+9816 [2000] */ - {0xfbb5, 0x00e4aabc}, /* U+4ABC [2000] */ + {0xfba2, 0xe99e96}, /* U+9796 [2000] */ + {0xfba3, 0xe99e9a}, /* U+979A [2000] */ + {0xfba4, 0xe99e9e}, /* U+979E [2000] */ + {0xfba5, 0xe99ea2}, /* U+97A2 [2000] */ + {0xfba6, 0xe99eb1}, /* U+97B1 [2000] */ + {0xfba7, 0xe99eb2}, /* U+97B2 [2000] */ + {0xfba8, 0xe99ebe}, /* U+97BE [2000] */ + {0xfba9, 0xe99f8c}, /* U+97CC [2000] */ + {0xfbaa, 0xe99f91}, /* U+97D1 [2000] */ + {0xfbab, 0xe99f94}, /* U+97D4 [2000] */ + {0xfbac, 0xe99f98}, /* U+97D8 [2000] */ + {0xfbad, 0xe99f99}, /* U+97D9 [2000] */ + {0xfbae, 0xe99fa1}, /* U+97E1 [2000] */ + {0xfbaf, 0xe99fb1}, /* U+97F1 [2000] */ + {0xfbb0, 0xe9a084}, /* U+9804 [2000] */ + {0xfbb1, 0xe9a08d}, /* U+980D [2000] */ + {0xfbb2, 0xe9a08e}, /* U+980E [2000] */ + {0xfbb3, 0xe9a094}, /* U+9814 [2000] */ + {0xfbb4, 0xe9a096}, /* U+9816 [2000] */ + {0xfbb5, 0xe4aabc}, /* U+4ABC [2000] */ {0xfbb6, 0xf0a99290}, /* U+29490 [2000] [Unicode3.1] */ - {0xfbb7, 0x00e9a0a3}, /* U+9823 [2000] */ - {0xfbb8, 0x00e9a0b2}, /* U+9832 [2000] */ - {0xfbb9, 0x00e9a0b3}, /* U+9833 [2000] */ - {0xfbba, 0x00e9a0a5}, /* U+9825 [2000] */ - {0xfbbb, 0x00e9a187}, /* U+9847 [2000] */ - {0xfbbc, 0x00e9a1a6}, /* U+9866 [2000] */ - {0xfbbd, 0x00e9a2ab}, /* U+98AB [2000] */ - {0xfbbe, 0x00e9a2ad}, /* U+98AD [2000] */ - {0xfbbf, 0x00e9a2b0}, /* U+98B0 [2000] */ + {0xfbb7, 0xe9a0a3}, /* U+9823 [2000] */ + {0xfbb8, 0xe9a0b2}, /* U+9832 [2000] */ + {0xfbb9, 0xe9a0b3}, /* U+9833 [2000] */ + {0xfbba, 0xe9a0a5}, /* U+9825 [2000] */ + {0xfbbb, 0xe9a187}, /* U+9847 [2000] */ + {0xfbbc, 0xe9a1a6}, /* U+9866 [2000] */ + {0xfbbd, 0xe9a2ab}, /* U+98AB [2000] */ + {0xfbbe, 0xe9a2ad}, /* U+98AD [2000] */ + {0xfbbf, 0xe9a2b0}, /* U+98B0 [2000] */ {0xfbc0, 0xf0a9978f}, /* U+295CF [2000] [Unicode3.1] */ - {0xfbc1, 0x00e9a2b7}, /* U+98B7 [2000] */ - {0xfbc2, 0x00e9a2b8}, /* U+98B8 [2000] */ - {0xfbc3, 0x00e9a2bb}, /* U+98BB [2000] */ - {0xfbc4, 0x00e9a2bc}, /* U+98BC [2000] */ - {0xfbc5, 0x00e9a2bf}, /* U+98BF [2000] */ - {0xfbc6, 0x00e9a382}, /* U+98C2 [2000] */ - {0xfbc7, 0x00e9a387}, /* U+98C7 [2000] */ - {0xfbc8, 0x00e9a38b}, /* U+98CB [2000] */ - {0xfbc9, 0x00e9a3a0}, /* U+98E0 [2000] */ + {0xfbc1, 0xe9a2b7}, /* U+98B7 [2000] */ + {0xfbc2, 0xe9a2b8}, /* U+98B8 [2000] */ + {0xfbc3, 0xe9a2bb}, /* U+98BB [2000] */ + {0xfbc4, 0xe9a2bc}, /* U+98BC [2000] */ + {0xfbc5, 0xe9a2bf}, /* U+98BF [2000] */ + {0xfbc6, 0xe9a382}, /* U+98C2 [2000] */ + {0xfbc7, 0xe9a387}, /* U+98C7 [2000] */ + {0xfbc8, 0xe9a38b}, /* U+98CB [2000] */ + {0xfbc9, 0xe9a3a0}, /* U+98E0 [2000] */ {0xfbca, 0xf0a999bf}, /* U+2967F [2000] [Unicode3.1] */ - {0xfbcb, 0x00e9a3a1}, /* U+98E1 [2000] */ - {0xfbcc, 0x00e9a3a3}, /* U+98E3 [2000] */ - {0xfbcd, 0x00e9a3a5}, /* U+98E5 [2000] */ - {0xfbce, 0x00e9a3aa}, /* U+98EA [2000] */ - {0xfbcf, 0x00e9a3b0}, /* U+98F0 [2000] */ - {0xfbd0, 0x00e9a3b1}, /* U+98F1 [2000] */ - {0xfbd1, 0x00e9a3b3}, /* U+98F3 [2000] */ - {0xfbd2, 0x00e9a488}, /* U+9908 [2000] */ - {0xfbd3, 0x00e4acbb}, /* U+4B3B [2000] */ + {0xfbcb, 0xe9a3a1}, /* U+98E1 [2000] */ + {0xfbcc, 0xe9a3a3}, /* U+98E3 [2000] */ + {0xfbcd, 0xe9a3a5}, /* U+98E5 [2000] */ + {0xfbce, 0xe9a3aa}, /* U+98EA [2000] */ + {0xfbcf, 0xe9a3b0}, /* U+98F0 [2000] */ + {0xfbd0, 0xe9a3b1}, /* U+98F1 [2000] */ + {0xfbd1, 0xe9a3b3}, /* U+98F3 [2000] */ + {0xfbd2, 0xe9a488}, /* U+9908 [2000] */ + {0xfbd3, 0xe4acbb}, /* U+4B3B [2000] */ {0xfbd4, 0xf0a99bb0}, /* U+296F0 [2000] [Unicode3.1] */ - {0xfbd5, 0x00e9a496}, /* U+9916 [2000] */ - {0xfbd6, 0x00e9a497}, /* U+9917 [2000] */ + {0xfbd5, 0xe9a496}, /* U+9916 [2000] */ + {0xfbd6, 0xe9a497}, /* U+9917 [2000] */ {0xfbd7, 0xf0a99c99}, /* U+29719 [2000] [Unicode3.1] */ - {0xfbd8, 0x00e9a49a}, /* U+991A [2000] */ - {0xfbd9, 0x00e9a49b}, /* U+991B [2000] */ - {0xfbda, 0x00e9a49c}, /* U+991C [2000] */ + {0xfbd8, 0xe9a49a}, /* U+991A [2000] */ + {0xfbd9, 0xe9a49b}, /* U+991B [2000] */ + {0xfbda, 0xe9a49c}, /* U+991C [2000] */ {0xfbdb, 0xf0a99d90}, /* U+29750 [2000] [Unicode3.1] */ - {0xfbdc, 0x00e9a4b1}, /* U+9931 [2000] */ - {0xfbdd, 0x00e9a4b2}, /* U+9932 [2000] */ - {0xfbde, 0x00e9a4b3}, /* U+9933 [2000] */ - {0xfbdf, 0x00e9a4ba}, /* U+993A [2000] */ - {0xfbe0, 0x00e9a4bb}, /* U+993B [2000] */ - {0xfbe1, 0x00e9a4bc}, /* U+993C [2000] */ - {0xfbe2, 0x00e9a580}, /* U+9940 [2000] */ - {0xfbe3, 0x00e9a581}, /* U+9941 [2000] */ - {0xfbe4, 0x00e9a586}, /* U+9946 [2000] */ - {0xfbe5, 0x00e9a58d}, /* U+994D [2000] */ - {0xfbe6, 0x00e9a58e}, /* U+994E [2000] */ - {0xfbe7, 0x00e9a59c}, /* U+995C [2000] */ - {0xfbe8, 0x00e9a59f}, /* U+995F [2000] */ - {0xfbe9, 0x00e9a5a0}, /* U+9960 [2000] */ - {0xfbea, 0x00e9a6a3}, /* U+99A3 [2000] */ - {0xfbeb, 0x00e9a6a6}, /* U+99A6 [2000] */ - {0xfbec, 0x00e9a6b9}, /* U+99B9 [2000] */ - {0xfbed, 0x00e9a6bd}, /* U+99BD [2000] */ - {0xfbee, 0x00e9a6bf}, /* U+99BF [2000] */ - {0xfbef, 0x00e9a783}, /* U+99C3 [2000] */ - {0xfbf0, 0x00e9a789}, /* U+99C9 [2000] */ - {0xfbf1, 0x00e9a794}, /* U+99D4 [2000] */ - {0xfbf2, 0x00e9a799}, /* U+99D9 [2000] */ - {0xfbf3, 0x00e9a79e}, /* U+99DE [2000] */ + {0xfbdc, 0xe9a4b1}, /* U+9931 [2000] */ + {0xfbdd, 0xe9a4b2}, /* U+9932 [2000] */ + {0xfbde, 0xe9a4b3}, /* U+9933 [2000] */ + {0xfbdf, 0xe9a4ba}, /* U+993A [2000] */ + {0xfbe0, 0xe9a4bb}, /* U+993B [2000] */ + {0xfbe1, 0xe9a4bc}, /* U+993C [2000] */ + {0xfbe2, 0xe9a580}, /* U+9940 [2000] */ + {0xfbe3, 0xe9a581}, /* U+9941 [2000] */ + {0xfbe4, 0xe9a586}, /* U+9946 [2000] */ + {0xfbe5, 0xe9a58d}, /* U+994D [2000] */ + {0xfbe6, 0xe9a58e}, /* U+994E [2000] */ + {0xfbe7, 0xe9a59c}, /* U+995C [2000] */ + {0xfbe8, 0xe9a59f}, /* U+995F [2000] */ + {0xfbe9, 0xe9a5a0}, /* U+9960 [2000] */ + {0xfbea, 0xe9a6a3}, /* U+99A3 [2000] */ + {0xfbeb, 0xe9a6a6}, /* U+99A6 [2000] */ + {0xfbec, 0xe9a6b9}, /* U+99B9 [2000] */ + {0xfbed, 0xe9a6bd}, /* U+99BD [2000] */ + {0xfbee, 0xe9a6bf}, /* U+99BF [2000] */ + {0xfbef, 0xe9a783}, /* U+99C3 [2000] */ + {0xfbf0, 0xe9a789}, /* U+99C9 [2000] */ + {0xfbf1, 0xe9a794}, /* U+99D4 [2000] */ + {0xfbf2, 0xe9a799}, /* U+99D9 [2000] */ + {0xfbf3, 0xe9a79e}, /* U+99DE [2000] */ {0xfbf4, 0xf0a9a386}, /* U+298C6 [2000] [Unicode3.1] */ - {0xfbf5, 0x00e9a7b0}, /* U+99F0 [2000] */ - {0xfbf6, 0x00e9a7b9}, /* U+99F9 [2000] */ - {0xfbf7, 0x00e9a7bc}, /* U+99FC [2000] */ - {0xfbf8, 0x00e9a88a}, /* U+9A0A [2000] */ - {0xfbf9, 0x00e9a891}, /* U+9A11 [2000] */ - {0xfbfa, 0x00e9a896}, /* U+9A16 [2000] */ - {0xfbfb, 0x00e9a89a}, /* U+9A1A [2000] */ - {0xfbfc, 0x00e9a8a0}, /* U+9A20 [2000] */ - {0xfc40, 0x00e9a8b1}, /* U+9A31 [2000] */ - {0xfc41, 0x00e9a8b6}, /* U+9A36 [2000] */ - {0xfc42, 0x00e9a984}, /* U+9A44 [2000] */ - {0xfc43, 0x00e9a98c}, /* U+9A4C [2000] */ - {0xfc44, 0x00e9a998}, /* U+9A58 [2000] */ - {0xfc45, 0x00e4af82}, /* U+4BC2 [2000] */ - {0xfc46, 0x00e9aaaf}, /* U+9AAF [2000] */ - {0xfc47, 0x00e4af8a}, /* U+4BCA [2000] */ - {0xfc48, 0x00e9aab7}, /* U+9AB7 [2000] */ - {0xfc49, 0x00e4af92}, /* U+4BD2 [2000] */ - {0xfc4a, 0x00e9aab9}, /* U+9AB9 [2000] */ + {0xfbf5, 0xe9a7b0}, /* U+99F0 [2000] */ + {0xfbf6, 0xe9a7b9}, /* U+99F9 [2000] */ + {0xfbf7, 0xe9a7bc}, /* U+99FC [2000] */ + {0xfbf8, 0xe9a88a}, /* U+9A0A [2000] */ + {0xfbf9, 0xe9a891}, /* U+9A11 [2000] */ + {0xfbfa, 0xe9a896}, /* U+9A16 [2000] */ + {0xfbfb, 0xe9a89a}, /* U+9A1A [2000] */ + {0xfbfc, 0xe9a8a0}, /* U+9A20 [2000] */ + {0xfc40, 0xe9a8b1}, /* U+9A31 [2000] */ + {0xfc41, 0xe9a8b6}, /* U+9A36 [2000] */ + {0xfc42, 0xe9a984}, /* U+9A44 [2000] */ + {0xfc43, 0xe9a98c}, /* U+9A4C [2000] */ + {0xfc44, 0xe9a998}, /* U+9A58 [2000] */ + {0xfc45, 0xe4af82}, /* U+4BC2 [2000] */ + {0xfc46, 0xe9aaaf}, /* U+9AAF [2000] */ + {0xfc47, 0xe4af8a}, /* U+4BCA [2000] */ + {0xfc48, 0xe9aab7}, /* U+9AB7 [2000] */ + {0xfc49, 0xe4af92}, /* U+4BD2 [2000] */ + {0xfc4a, 0xe9aab9}, /* U+9AB9 [2000] */ {0xfc4b, 0xf0a9a9b2}, /* U+29A72 [2000] [Unicode3.1] */ - {0xfc4c, 0x00e9ab86}, /* U+9AC6 [2000] */ - {0xfc4d, 0x00e9ab90}, /* U+9AD0 [2000] */ - {0xfc4e, 0x00e9ab92}, /* U+9AD2 [2000] */ - {0xfc4f, 0x00e9ab95}, /* U+9AD5 [2000] */ - {0xfc50, 0x00e4afa8}, /* U+4BE8 [2000] */ - {0xfc51, 0x00e9ab9c}, /* U+9ADC [2000] */ - {0xfc52, 0x00e9aba0}, /* U+9AE0 [2000] */ - {0xfc53, 0x00e9aba5}, /* U+9AE5 [2000] */ - {0xfc54, 0x00e9aba9}, /* U+9AE9 [2000] */ - {0xfc55, 0x00e9ac83}, /* U+9B03 [2000] */ - {0xfc56, 0x00e9ac8c}, /* U+9B0C [2000] */ - {0xfc57, 0x00e9ac90}, /* U+9B10 [2000] */ - {0xfc58, 0x00e9ac92}, /* U+9B12 [2000] */ - {0xfc59, 0x00e9ac96}, /* U+9B16 [2000] */ - {0xfc5a, 0x00e9ac9c}, /* U+9B1C [2000] */ - {0xfc5b, 0x00e9acab}, /* U+9B2B [2000] */ - {0xfc5c, 0x00e9acb3}, /* U+9B33 [2000] */ - {0xfc5d, 0x00e9acbd}, /* U+9B3D [2000] */ - {0xfc5e, 0x00e4b0a0}, /* U+4C20 [2000] */ - {0xfc5f, 0x00e9ad8b}, /* U+9B4B [2000] */ - {0xfc60, 0x00e9ada3}, /* U+9B63 [2000] */ - {0xfc61, 0x00e9ada5}, /* U+9B65 [2000] */ - {0xfc62, 0x00e9adab}, /* U+9B6B [2000] */ - {0xfc63, 0x00e9adac}, /* U+9B6C [2000] */ - {0xfc64, 0x00e9adb3}, /* U+9B73 [2000] */ - {0xfc65, 0x00e9adb6}, /* U+9B76 [2000] */ - {0xfc66, 0x00e9adb7}, /* U+9B77 [2000] */ - {0xfc67, 0x00e9aea6}, /* U+9BA6 [2000] */ - {0xfc68, 0x00e9aeac}, /* U+9BAC [2000] */ - {0xfc69, 0x00e9aeb1}, /* U+9BB1 [2000] */ + {0xfc4c, 0xe9ab86}, /* U+9AC6 [2000] */ + {0xfc4d, 0xe9ab90}, /* U+9AD0 [2000] */ + {0xfc4e, 0xe9ab92}, /* U+9AD2 [2000] */ + {0xfc4f, 0xe9ab95}, /* U+9AD5 [2000] */ + {0xfc50, 0xe4afa8}, /* U+4BE8 [2000] */ + {0xfc51, 0xe9ab9c}, /* U+9ADC [2000] */ + {0xfc52, 0xe9aba0}, /* U+9AE0 [2000] */ + {0xfc53, 0xe9aba5}, /* U+9AE5 [2000] */ + {0xfc54, 0xe9aba9}, /* U+9AE9 [2000] */ + {0xfc55, 0xe9ac83}, /* U+9B03 [2000] */ + {0xfc56, 0xe9ac8c}, /* U+9B0C [2000] */ + {0xfc57, 0xe9ac90}, /* U+9B10 [2000] */ + {0xfc58, 0xe9ac92}, /* U+9B12 [2000] */ + {0xfc59, 0xe9ac96}, /* U+9B16 [2000] */ + {0xfc5a, 0xe9ac9c}, /* U+9B1C [2000] */ + {0xfc5b, 0xe9acab}, /* U+9B2B [2000] */ + {0xfc5c, 0xe9acb3}, /* U+9B33 [2000] */ + {0xfc5d, 0xe9acbd}, /* U+9B3D [2000] */ + {0xfc5e, 0xe4b0a0}, /* U+4C20 [2000] */ + {0xfc5f, 0xe9ad8b}, /* U+9B4B [2000] */ + {0xfc60, 0xe9ada3}, /* U+9B63 [2000] */ + {0xfc61, 0xe9ada5}, /* U+9B65 [2000] */ + {0xfc62, 0xe9adab}, /* U+9B6B [2000] */ + {0xfc63, 0xe9adac}, /* U+9B6C [2000] */ + {0xfc64, 0xe9adb3}, /* U+9B73 [2000] */ + {0xfc65, 0xe9adb6}, /* U+9B76 [2000] */ + {0xfc66, 0xe9adb7}, /* U+9B77 [2000] */ + {0xfc67, 0xe9aea6}, /* U+9BA6 [2000] */ + {0xfc68, 0xe9aeac}, /* U+9BAC [2000] */ + {0xfc69, 0xe9aeb1}, /* U+9BB1 [2000] */ {0xfc6a, 0xf0a9b79b}, /* U+29DDB [2000] [Unicode3.1] */ {0xfc6b, 0xf0a9b8bd}, /* U+29E3D [2000] [Unicode3.1] */ - {0xfc6c, 0x00e9aeb2}, /* U+9BB2 [2000] */ - {0xfc6d, 0x00e9aeb8}, /* U+9BB8 [2000] */ - {0xfc6e, 0x00e9aebe}, /* U+9BBE [2000] */ - {0xfc6f, 0x00e9af87}, /* U+9BC7 [2000] */ - {0xfc70, 0x00e9afb3}, /* U+9BF3 [2000] */ - {0xfc71, 0x00e9af98}, /* U+9BD8 [2000] */ - {0xfc72, 0x00e9af9d}, /* U+9BDD [2000] */ - {0xfc73, 0x00e9afa7}, /* U+9BE7 [2000] */ - {0xfc74, 0x00e9afaa}, /* U+9BEA [2000] */ - {0xfc75, 0x00e9afab}, /* U+9BEB [2000] */ - {0xfc76, 0x00e9afaf}, /* U+9BEF [2000] */ - {0xfc77, 0x00e9afae}, /* U+9BEE [2000] */ + {0xfc6c, 0xe9aeb2}, /* U+9BB2 [2000] */ + {0xfc6d, 0xe9aeb8}, /* U+9BB8 [2000] */ + {0xfc6e, 0xe9aebe}, /* U+9BBE [2000] */ + {0xfc6f, 0xe9af87}, /* U+9BC7 [2000] */ + {0xfc70, 0xe9afb3}, /* U+9BF3 [2000] */ + {0xfc71, 0xe9af98}, /* U+9BD8 [2000] */ + {0xfc72, 0xe9af9d}, /* U+9BDD [2000] */ + {0xfc73, 0xe9afa7}, /* U+9BE7 [2000] */ + {0xfc74, 0xe9afaa}, /* U+9BEA [2000] */ + {0xfc75, 0xe9afab}, /* U+9BEB [2000] */ + {0xfc76, 0xe9afaf}, /* U+9BEF [2000] */ + {0xfc77, 0xe9afae}, /* U+9BEE [2000] */ {0xfc78, 0xf0a9b895}, /* U+29E15 [2000] [Unicode3.1] */ - {0xfc79, 0x00e9afba}, /* U+9BFA [2000] */ + {0xfc79, 0xe9afba}, /* U+9BFA [2000] */ {0xfc7a, 0xf0a9ba8a}, /* U+29E8A [2000] [Unicode3.1] */ - {0xfc7b, 0x00e9afb7}, /* U+9BF7 [2000] */ + {0xfc7b, 0xe9afb7}, /* U+9BF7 [2000] */ {0xfc7c, 0xf0a9b989}, /* U+29E49 [2000] [Unicode3.1] */ - {0xfc7d, 0x00e9b096}, /* U+9C16 [2000] */ - {0xfc7e, 0x00e9b098}, /* U+9C18 [2000] */ - {0xfc80, 0x00e9b099}, /* U+9C19 [2000] */ - {0xfc81, 0x00e9b09a}, /* U+9C1A [2000] */ - {0xfc82, 0x00e9b09d}, /* U+9C1D [2000] */ - {0xfc83, 0x00e9b0a2}, /* U+9C22 [2000] */ - {0xfc84, 0x00e9b0a7}, /* U+9C27 [2000] */ - {0xfc85, 0x00e9b0a9}, /* U+9C29 [2000] */ - {0xfc86, 0x00e9b0aa}, /* U+9C2A [2000] */ + {0xfc7d, 0xe9b096}, /* U+9C16 [2000] */ + {0xfc7e, 0xe9b098}, /* U+9C18 [2000] */ + {0xfc80, 0xe9b099}, /* U+9C19 [2000] */ + {0xfc81, 0xe9b09a}, /* U+9C1A [2000] */ + {0xfc82, 0xe9b09d}, /* U+9C1D [2000] */ + {0xfc83, 0xe9b0a2}, /* U+9C22 [2000] */ + {0xfc84, 0xe9b0a7}, /* U+9C27 [2000] */ + {0xfc85, 0xe9b0a9}, /* U+9C29 [2000] */ + {0xfc86, 0xe9b0aa}, /* U+9C2A [2000] */ {0xfc87, 0xf0a9bb84}, /* U+29EC4 [2000] [Unicode3.1] */ - {0xfc88, 0x00e9b0b1}, /* U+9C31 [2000] */ - {0xfc89, 0x00e9b0b6}, /* U+9C36 [2000] */ - {0xfc8a, 0x00e9b0b7}, /* U+9C37 [2000] */ - {0xfc8b, 0x00e9b185}, /* U+9C45 [2000] */ - {0xfc8c, 0x00e9b19c}, /* U+9C5C [2000] */ + {0xfc88, 0xe9b0b1}, /* U+9C31 [2000] */ + {0xfc89, 0xe9b0b6}, /* U+9C36 [2000] */ + {0xfc8a, 0xe9b0b7}, /* U+9C37 [2000] */ + {0xfc8b, 0xe9b185}, /* U+9C45 [2000] */ + {0xfc8c, 0xe9b19c}, /* U+9C5C [2000] */ {0xfc8d, 0xf0a9bba9}, /* U+29EE9 [2000] [Unicode3.1] */ - {0xfc8e, 0x00e9b189}, /* U+9C49 [2000] */ - {0xfc8f, 0x00e9b18a}, /* U+9C4A [2000] */ + {0xfc8e, 0xe9b189}, /* U+9C49 [2000] */ + {0xfc8f, 0xe9b18a}, /* U+9C4A [2000] */ {0xfc90, 0xf0a9bb9b}, /* U+29EDB [2000] [Unicode3.1] */ - {0xfc91, 0x00e9b194}, /* U+9C54 [2000] */ - {0xfc92, 0x00e9b198}, /* U+9C58 [2000] */ - {0xfc93, 0x00e9b19b}, /* U+9C5B [2000] */ - {0xfc94, 0x00e9b19d}, /* U+9C5D [2000] */ - {0xfc95, 0x00e9b19f}, /* U+9C5F [2000] */ - {0xfc96, 0x00e9b1a9}, /* U+9C69 [2000] */ - {0xfc97, 0x00e9b1aa}, /* U+9C6A [2000] */ - {0xfc98, 0x00e9b1ab}, /* U+9C6B [2000] */ - {0xfc99, 0x00e9b1ad}, /* U+9C6D [2000] */ - {0xfc9a, 0x00e9b1ae}, /* U+9C6E [2000] */ - {0xfc9b, 0x00e9b1b0}, /* U+9C70 [2000] */ - {0xfc9c, 0x00e9b1b2}, /* U+9C72 [2000] */ - {0xfc9d, 0x00e9b1b5}, /* U+9C75 [2000] */ - {0xfc9e, 0x00e9b1ba}, /* U+9C7A [2000] */ - {0xfc9f, 0x00e9b3a6}, /* U+9CE6 [2000] */ - {0xfca0, 0x00e9b3b2}, /* U+9CF2 [2000] */ - {0xfca1, 0x00e9b48b}, /* U+9D0B [2000] */ - {0xfca2, 0x00e9b482}, /* U+9D02 [2000] */ + {0xfc91, 0xe9b194}, /* U+9C54 [2000] */ + {0xfc92, 0xe9b198}, /* U+9C58 [2000] */ + {0xfc93, 0xe9b19b}, /* U+9C5B [2000] */ + {0xfc94, 0xe9b19d}, /* U+9C5D [2000] */ + {0xfc95, 0xe9b19f}, /* U+9C5F [2000] */ + {0xfc96, 0xe9b1a9}, /* U+9C69 [2000] */ + {0xfc97, 0xe9b1aa}, /* U+9C6A [2000] */ + {0xfc98, 0xe9b1ab}, /* U+9C6B [2000] */ + {0xfc99, 0xe9b1ad}, /* U+9C6D [2000] */ + {0xfc9a, 0xe9b1ae}, /* U+9C6E [2000] */ + {0xfc9b, 0xe9b1b0}, /* U+9C70 [2000] */ + {0xfc9c, 0xe9b1b2}, /* U+9C72 [2000] */ + {0xfc9d, 0xe9b1b5}, /* U+9C75 [2000] */ + {0xfc9e, 0xe9b1ba}, /* U+9C7A [2000] */ + {0xfc9f, 0xe9b3a6}, /* U+9CE6 [2000] */ + {0xfca0, 0xe9b3b2}, /* U+9CF2 [2000] */ + {0xfca1, 0xe9b48b}, /* U+9D0B [2000] */ + {0xfca2, 0xe9b482}, /* U+9D02 [2000] */ {0xfca3, 0xf0a9bf8e}, /* U+29FCE [2000] [Unicode3.1] */ - {0xfca4, 0x00e9b491}, /* U+9D11 [2000] */ - {0xfca5, 0x00e9b497}, /* U+9D17 [2000] */ - {0xfca6, 0x00e9b498}, /* U+9D18 [2000] */ + {0xfca4, 0xe9b491}, /* U+9D11 [2000] */ + {0xfca5, 0xe9b497}, /* U+9D17 [2000] */ + {0xfca6, 0xe9b498}, /* U+9D18 [2000] */ {0xfca7, 0xf0aa80af}, /* U+2A02F [2000] [Unicode3.1] */ - {0xfca8, 0x00e4b384}, /* U+4CC4 [2000] */ + {0xfca8, 0xe4b384}, /* U+4CC4 [2000] */ {0xfca9, 0xf0aa809a}, /* U+2A01A [2000] [Unicode3.1] */ - {0xfcaa, 0x00e9b4b2}, /* U+9D32 [2000] */ - {0xfcab, 0x00e4b391}, /* U+4CD1 [2000] */ - {0xfcac, 0x00e9b582}, /* U+9D42 [2000] */ - {0xfcad, 0x00e9b58a}, /* U+9D4A [2000] */ - {0xfcae, 0x00e9b59f}, /* U+9D5F [2000] */ - {0xfcaf, 0x00e9b5a2}, /* U+9D62 [2000] */ + {0xfcaa, 0xe9b4b2}, /* U+9D32 [2000] */ + {0xfcab, 0xe4b391}, /* U+4CD1 [2000] */ + {0xfcac, 0xe9b582}, /* U+9D42 [2000] */ + {0xfcad, 0xe9b58a}, /* U+9D4A [2000] */ + {0xfcae, 0xe9b59f}, /* U+9D5F [2000] */ + {0xfcaf, 0xe9b5a2}, /* U+9D62 [2000] */ {0xfcb0, 0xf0aa83b9}, /* U+2A0F9 [2000] [Unicode3.1] */ - {0xfcb1, 0x00e9b5a9}, /* U+9D69 [2000] */ - {0xfcb2, 0x00e9b5ab}, /* U+9D6B [2000] */ + {0xfcb1, 0xe9b5a9}, /* U+9D69 [2000] */ + {0xfcb2, 0xe9b5ab}, /* U+9D6B [2000] */ {0xfcb3, 0xf0aa8282}, /* U+2A082 [2000] [Unicode3.1] */ - {0xfcb4, 0x00e9b5b3}, /* U+9D73 [2000] */ - {0xfcb5, 0x00e9b5b6}, /* U+9D76 [2000] */ - {0xfcb6, 0x00e9b5b7}, /* U+9D77 [2000] */ - {0xfcb7, 0x00e9b5be}, /* U+9D7E [2000] */ - {0xfcb8, 0x00e9b684}, /* U+9D84 [2000] */ - {0xfcb9, 0x00e9b68d}, /* U+9D8D [2000] */ - {0xfcba, 0x00e9b699}, /* U+9D99 [2000] */ - {0xfcbb, 0x00e9b6a1}, /* U+9DA1 [2000] */ - {0xfcbc, 0x00e9b6bf}, /* U+9DBF [2000] */ - {0xfcbd, 0x00e9b6b5}, /* U+9DB5 [2000] */ - {0xfcbe, 0x00e9b6b9}, /* U+9DB9 [2000] */ - {0xfcbf, 0x00e9b6bd}, /* U+9DBD [2000] */ - {0xfcc0, 0x00e9b783}, /* U+9DC3 [2000] */ - {0xfcc1, 0x00e9b787}, /* U+9DC7 [2000] */ - {0xfcc2, 0x00e9b789}, /* U+9DC9 [2000] */ - {0xfcc3, 0x00e9b796}, /* U+9DD6 [2000] */ - {0xfcc4, 0x00e9b79a}, /* U+9DDA [2000] */ - {0xfcc5, 0x00e9b79f}, /* U+9DDF [2000] */ - {0xfcc6, 0x00e9b7a0}, /* U+9DE0 [2000] */ - {0xfcc7, 0x00e9b7a3}, /* U+9DE3 [2000] */ - {0xfcc8, 0x00e9b7b4}, /* U+9DF4 [2000] */ - {0xfcc9, 0x00e4b487}, /* U+4D07 [2000] */ - {0xfcca, 0x00e9b88a}, /* U+9E0A [2000] */ - {0xfccb, 0x00e9b882}, /* U+9E02 [2000] */ - {0xfccc, 0x00e9b88d}, /* U+9E0D [2000] */ - {0xfccd, 0x00e9b899}, /* U+9E19 [2000] */ - {0xfcce, 0x00e9b89c}, /* U+9E1C [2000] */ - {0xfccf, 0x00e9b89d}, /* U+9E1D [2000] */ - {0xfcd0, 0x00e9b9bb}, /* U+9E7B [2000] */ + {0xfcb4, 0xe9b5b3}, /* U+9D73 [2000] */ + {0xfcb5, 0xe9b5b6}, /* U+9D76 [2000] */ + {0xfcb6, 0xe9b5b7}, /* U+9D77 [2000] */ + {0xfcb7, 0xe9b5be}, /* U+9D7E [2000] */ + {0xfcb8, 0xe9b684}, /* U+9D84 [2000] */ + {0xfcb9, 0xe9b68d}, /* U+9D8D [2000] */ + {0xfcba, 0xe9b699}, /* U+9D99 [2000] */ + {0xfcbb, 0xe9b6a1}, /* U+9DA1 [2000] */ + {0xfcbc, 0xe9b6bf}, /* U+9DBF [2000] */ + {0xfcbd, 0xe9b6b5}, /* U+9DB5 [2000] */ + {0xfcbe, 0xe9b6b9}, /* U+9DB9 [2000] */ + {0xfcbf, 0xe9b6bd}, /* U+9DBD [2000] */ + {0xfcc0, 0xe9b783}, /* U+9DC3 [2000] */ + {0xfcc1, 0xe9b787}, /* U+9DC7 [2000] */ + {0xfcc2, 0xe9b789}, /* U+9DC9 [2000] */ + {0xfcc3, 0xe9b796}, /* U+9DD6 [2000] */ + {0xfcc4, 0xe9b79a}, /* U+9DDA [2000] */ + {0xfcc5, 0xe9b79f}, /* U+9DDF [2000] */ + {0xfcc6, 0xe9b7a0}, /* U+9DE0 [2000] */ + {0xfcc7, 0xe9b7a3}, /* U+9DE3 [2000] */ + {0xfcc8, 0xe9b7b4}, /* U+9DF4 [2000] */ + {0xfcc9, 0xe4b487}, /* U+4D07 [2000] */ + {0xfcca, 0xe9b88a}, /* U+9E0A [2000] */ + {0xfccb, 0xe9b882}, /* U+9E02 [2000] */ + {0xfccc, 0xe9b88d}, /* U+9E0D [2000] */ + {0xfccd, 0xe9b899}, /* U+9E19 [2000] */ + {0xfcce, 0xe9b89c}, /* U+9E1C [2000] */ + {0xfccf, 0xe9b89d}, /* U+9E1D [2000] */ + {0xfcd0, 0xe9b9bb}, /* U+9E7B [2000] */ {0xfcd1, 0xf0a28898}, /* U+22218 [2000] [Unicode3.1] */ - {0xfcd2, 0x00e9ba80}, /* U+9E80 [2000] */ - {0xfcd3, 0x00e9ba85}, /* U+9E85 [2000] */ - {0xfcd4, 0x00e9ba9b}, /* U+9E9B [2000] */ - {0xfcd5, 0x00e9baa8}, /* U+9EA8 [2000] */ + {0xfcd2, 0xe9ba80}, /* U+9E80 [2000] */ + {0xfcd3, 0xe9ba85}, /* U+9E85 [2000] */ + {0xfcd4, 0xe9ba9b}, /* U+9E9B [2000] */ + {0xfcd5, 0xe9baa8}, /* U+9EA8 [2000] */ {0xfcd6, 0xf0aa8e8c}, /* U+2A38C [2000] [Unicode3.1] */ - {0xfcd7, 0x00e9babd}, /* U+9EBD [2000] */ + {0xfcd7, 0xe9babd}, /* U+9EBD [2000] */ {0xfcd8, 0xf0aa90b7}, /* U+2A437 [2000] [Unicode3.1] */ - {0xfcd9, 0x00e9bb9f}, /* U+9EDF [2000] */ - {0xfcda, 0x00e9bba7}, /* U+9EE7 [2000] */ - {0xfcdb, 0x00e9bbae}, /* U+9EEE [2000] */ - {0xfcdc, 0x00e9bbbf}, /* U+9EFF [2000] */ - {0xfcdd, 0x00e9bc82}, /* U+9F02 [2000] */ - {0xfcde, 0x00e4b5b7}, /* U+4D77 [2000] */ - {0xfcdf, 0x00e9bc83}, /* U+9F03 [2000] */ - {0xfce0, 0x00e9bc97}, /* U+9F17 [2000] */ - {0xfce1, 0x00e9bc99}, /* U+9F19 [2000] */ - {0xfce2, 0x00e9bcaf}, /* U+9F2F [2000] */ - {0xfce3, 0x00e9bcb7}, /* U+9F37 [2000] */ - {0xfce4, 0x00e9bcba}, /* U+9F3A [2000] */ - {0xfce5, 0x00e9bcbd}, /* U+9F3D [2000] */ - {0xfce6, 0x00e9bd81}, /* U+9F41 [2000] */ - {0xfce7, 0x00e9bd85}, /* U+9F45 [2000] */ - {0xfce8, 0x00e9bd86}, /* U+9F46 [2000] */ - {0xfce9, 0x00e9bd93}, /* U+9F53 [2000] */ - {0xfcea, 0x00e9bd95}, /* U+9F55 [2000] */ - {0xfceb, 0x00e9bd98}, /* U+9F58 [2000] */ + {0xfcd9, 0xe9bb9f}, /* U+9EDF [2000] */ + {0xfcda, 0xe9bba7}, /* U+9EE7 [2000] */ + {0xfcdb, 0xe9bbae}, /* U+9EEE [2000] */ + {0xfcdc, 0xe9bbbf}, /* U+9EFF [2000] */ + {0xfcdd, 0xe9bc82}, /* U+9F02 [2000] */ + {0xfcde, 0xe4b5b7}, /* U+4D77 [2000] */ + {0xfcdf, 0xe9bc83}, /* U+9F03 [2000] */ + {0xfce0, 0xe9bc97}, /* U+9F17 [2000] */ + {0xfce1, 0xe9bc99}, /* U+9F19 [2000] */ + {0xfce2, 0xe9bcaf}, /* U+9F2F [2000] */ + {0xfce3, 0xe9bcb7}, /* U+9F37 [2000] */ + {0xfce4, 0xe9bcba}, /* U+9F3A [2000] */ + {0xfce5, 0xe9bcbd}, /* U+9F3D [2000] */ + {0xfce6, 0xe9bd81}, /* U+9F41 [2000] */ + {0xfce7, 0xe9bd85}, /* U+9F45 [2000] */ + {0xfce8, 0xe9bd86}, /* U+9F46 [2000] */ + {0xfce9, 0xe9bd93}, /* U+9F53 [2000] */ + {0xfcea, 0xe9bd95}, /* U+9F55 [2000] */ + {0xfceb, 0xe9bd98}, /* U+9F58 [2000] */ {0xfcec, 0xf0aa97b1}, /* U+2A5F1 [2000] [Unicode3.1] */ - {0xfced, 0x00e9bd9d}, /* U+9F5D [2000] */ + {0xfced, 0xe9bd9d}, /* U+9F5D [2000] */ {0xfcee, 0xf0aa9882}, /* U+2A602 [2000] [Unicode3.1] */ - {0xfcef, 0x00e9bda9}, /* U+9F69 [2000] */ + {0xfcef, 0xe9bda9}, /* U+9F69 [2000] */ {0xfcf0, 0xf0aa989a}, /* U+2A61A [2000] [Unicode3.1] */ - {0xfcf1, 0x00e9bdad}, /* U+9F6D [2000] */ - {0xfcf2, 0x00e9bdb0}, /* U+9F70 [2000] */ - {0xfcf3, 0x00e9bdb5}, /* U+9F75 [2000] */ + {0xfcf1, 0xe9bdad}, /* U+9F6D [2000] */ + {0xfcf2, 0xe9bdb0}, /* U+9F70 [2000] */ + {0xfcf3, 0xe9bdb5}, /* U+9F75 [2000] */ {0xfcf4, 0xf0aa9ab2} /* U+2A6B2 [2000] [Unicode3.1] */ }; diff --git a/src/backend/utils/mb/Unicode/shift_jis_2004_to_utf8_combined.map b/src/backend/utils/mb/Unicode/shift_jis_2004_to_utf8_combined.map index b1c7bced5f..414e59dc40 100644 --- a/src/backend/utils/mb/Unicode/shift_jis_2004_to_utf8_combined.map +++ b/src/backend/utils/mb/Unicode/shift_jis_2004_to_utf8_combined.map @@ -1,7 +1,6 @@ -/* - * This file was generated by UCS_to_SHIFT_JIS_2004.pl - */ -static const pg_local_to_utf_combined LUmapSHIFT_JIS_2004_combined[] = { +/* src/backend/utils/mb/Unicode/shift_jis_2004_to_utf8_combined.map */ + +static const pg_local_to_utf_combined LUmapSHIFT_JIS_2004_combined[ 25 ] = { /* */ {0x82f5, 0x00e3818b, 0x00e3829a}, /* U+304B+309A [2000] */ {0x82f6, 0x00e3818d, 0x00e3829a}, /* U+304D+309A [2000] */ {0x82f7, 0x00e3818f, 0x00e3829a}, /* U+304F+309A [2000] */ diff --git a/src/backend/utils/mb/Unicode/ucs2utf.pl b/src/backend/utils/mb/Unicode/ucs2utf.pl deleted file mode 100644 index e0f1fb226f..0000000000 --- a/src/backend/utils/mb/Unicode/ucs2utf.pl +++ /dev/null @@ -1,35 +0,0 @@ -# -# Copyright (c) 2001-2016, PostgreSQL Global Development Group -# -# src/backend/utils/mb/Unicode/ucs2utf.pl -# convert UCS-4 to UTF-8 -# -sub ucs2utf -{ - local ($ucs) = @_; - local $utf; - - if ($ucs <= 0x007f) - { - $utf = $ucs; - } - elsif ($ucs > 0x007f && $ucs <= 0x07ff) - { - $utf = (($ucs & 0x003f) | 0x80) | ((($ucs >> 6) | 0xc0) << 8); - } - elsif ($ucs > 0x07ff && $ucs <= 0xffff) - { - $utf = - ((($ucs >> 12) | 0xe0) << 16) | - (((($ucs & 0x0fc0) >> 6) | 0x80) << 8) | (($ucs & 0x003f) | 0x80); - } - else - { - $utf = - ((($ucs >> 18) | 0xf0) << 24) | - (((($ucs & 0x3ffff) >> 12) | 0x80) << 16) | - (((($ucs & 0x0fc0) >> 6) | 0x80) << 8) | (($ucs & 0x003f) | 0x80); - } - return ($utf); -} -1; diff --git a/src/backend/utils/mb/Unicode/uhc_to_utf8.map b/src/backend/utils/mb/Unicode/uhc_to_utf8.map index 26a7b18f65..65c7e114a3 100644 --- a/src/backend/utils/mb/Unicode/uhc_to_utf8.map +++ b/src/backend/utils/mb/Unicode/uhc_to_utf8.map @@ -1,3 +1,5 @@ +/* src/backend/utils/mb/Unicode/uhc_to_utf8.map */ + static const pg_local_to_utf LUmapUHC[ 17237 ] = { {0x8141, 0xeab082}, {0x8142, 0xeab083}, diff --git a/src/backend/utils/mb/Unicode/utf8_to_euc_cn.map b/src/backend/utils/mb/Unicode/utf8_to_euc_cn.map index b28eb9cc0c..3d64cd1a60 100644 --- a/src/backend/utils/mb/Unicode/utf8_to_euc_cn.map +++ b/src/backend/utils/mb/Unicode/utf8_to_euc_cn.map @@ -1,3 +1,5 @@ +/* src/backend/utils/mb/Unicode/utf8_to_euc_cn.map */ + static const pg_utf_to_local ULmapEUC_CN[ 7445 ] = { {0xc2a4, 0xa1e8}, {0xc2a7, 0xa1ec}, diff --git a/src/backend/utils/mb/Unicode/utf8_to_euc_jis_2004.map b/src/backend/utils/mb/Unicode/utf8_to_euc_jis_2004.map index bae26f2d86..b50e232b6c 100644 --- a/src/backend/utils/mb/Unicode/utf8_to_euc_jis_2004.map +++ b/src/backend/utils/mb/Unicode/utf8_to_euc_jis_2004.map @@ -1,11136 +1,11007 @@ -/* - * This file was generated by UCS_to_EUC_JIS_2004.pl - */ -static const pg_utf_to_local ULmapEUC_JIS_2004[] = { - {0x00000000, 0x000000}, /* U+0000 */ - {0x00000001, 0x000001}, /* U+0001 */ - {0x00000002, 0x000002}, /* U+0002 */ - {0x00000003, 0x000003}, /* U+0003 */ - {0x00000004, 0x000004}, /* U+0004 */ - {0x00000005, 0x000005}, /* U+0005 */ - {0x00000006, 0x000006}, /* U+0006 */ - {0x00000007, 0x000007}, /* U+0007 */ - {0x00000008, 0x000008}, /* U+0008 */ - {0x00000009, 0x000009}, /* U+0009 */ - {0x0000000a, 0x00000a}, /* U+000A */ - {0x0000000b, 0x00000b}, /* U+000B */ - {0x0000000c, 0x00000c}, /* U+000C */ - {0x0000000d, 0x00000d}, /* U+000D */ - {0x0000000e, 0x00000e}, /* U+000E */ - {0x0000000f, 0x00000f}, /* U+000F */ - {0x00000010, 0x000010}, /* U+0010 */ - {0x00000011, 0x000011}, /* U+0011 */ - {0x00000012, 0x000012}, /* U+0012 */ - {0x00000013, 0x000013}, /* U+0013 */ - {0x00000014, 0x000014}, /* U+0014 */ - {0x00000015, 0x000015}, /* U+0015 */ - {0x00000016, 0x000016}, /* U+0016 */ - {0x00000017, 0x000017}, /* U+0017 */ - {0x00000018, 0x000018}, /* U+0018 */ - {0x00000019, 0x000019}, /* U+0019 */ - {0x0000001a, 0x00001a}, /* U+001A */ - {0x0000001b, 0x00001b}, /* U+001B */ - {0x0000001c, 0x00001c}, /* U+001C */ - {0x0000001d, 0x00001d}, /* U+001D */ - {0x0000001e, 0x00001e}, /* U+001E */ - {0x0000001f, 0x00001f}, /* U+001F */ - {0x00000020, 0x000020}, /* U+0020 SPACE */ - {0x00000021, 0x000021}, /* U+0021 EXCLAMATION MARK */ - {0x00000022, 0x000022}, /* U+0022 QUOTATION MARK */ - {0x00000023, 0x000023}, /* U+0023 NUMBER SIGN */ - {0x00000024, 0x000024}, /* U+0024 DOLLAR SIGN */ - {0x00000025, 0x000025}, /* U+0025 PERCENT SIGN */ - {0x00000026, 0x000026}, /* U+0026 AMPERSAND */ - {0x00000027, 0x000027}, /* U+0027 APOSTROPHE */ - {0x00000028, 0x000028}, /* U+0028 LEFT PARENTHESIS */ - {0x00000029, 0x000029}, /* U+0029 RIGHT PARENTHESIS */ - {0x0000002a, 0x00002a}, /* U+002A ASTERISK */ - {0x0000002b, 0x00002b}, /* U+002B PLUS SIGN */ - {0x0000002c, 0x00002c}, /* U+002C COMMA */ - {0x0000002d, 0x00002d}, /* U+002D HYPHEN-MINUS */ - {0x0000002e, 0x00002e}, /* U+002E FULL STOP */ - {0x0000002f, 0x00002f}, /* U+002F SOLIDUS */ - {0x00000030, 0x000030}, /* U+0030 DIGIT ZERO */ - {0x00000031, 0x000031}, /* U+0031 DIGIT ONE */ - {0x00000032, 0x000032}, /* U+0032 DIGIT TWO */ - {0x00000033, 0x000033}, /* U+0033 DIGIT THREE */ - {0x00000034, 0x000034}, /* U+0034 DIGIT FOUR */ - {0x00000035, 0x000035}, /* U+0035 DIGIT FIVE */ - {0x00000036, 0x000036}, /* U+0036 DIGIT SIX */ - {0x00000037, 0x000037}, /* U+0037 DIGIT SEVEN */ - {0x00000038, 0x000038}, /* U+0038 DIGIT EIGHT */ - {0x00000039, 0x000039}, /* U+0039 DIGIT NINE */ - {0x0000003a, 0x00003a}, /* U+003A COLON */ - {0x0000003b, 0x00003b}, /* U+003B SEMICOLON */ - {0x0000003c, 0x00003c}, /* U+003C LESS-THAN SIGN */ - {0x0000003d, 0x00003d}, /* U+003D EQUALS SIGN */ - {0x0000003e, 0x00003e}, /* U+003E GREATER-THAN SIGN */ - {0x0000003f, 0x00003f}, /* U+003F QUESTION MARK */ - {0x00000040, 0x000040}, /* U+0040 COMMERCIAL AT */ - {0x00000041, 0x000041}, /* U+0041 LATIN CAPITAL LETTER A */ - {0x00000042, 0x000042}, /* U+0042 LATIN CAPITAL LETTER B */ - {0x00000043, 0x000043}, /* U+0043 LATIN CAPITAL LETTER C */ - {0x00000044, 0x000044}, /* U+0044 LATIN CAPITAL LETTER D */ - {0x00000045, 0x000045}, /* U+0045 LATIN CAPITAL LETTER E */ - {0x00000046, 0x000046}, /* U+0046 LATIN CAPITAL LETTER F */ - {0x00000047, 0x000047}, /* U+0047 LATIN CAPITAL LETTER G */ - {0x00000048, 0x000048}, /* U+0048 LATIN CAPITAL LETTER H */ - {0x00000049, 0x000049}, /* U+0049 LATIN CAPITAL LETTER I */ - {0x0000004a, 0x00004a}, /* U+004A LATIN CAPITAL LETTER J */ - {0x0000004b, 0x00004b}, /* U+004B LATIN CAPITAL LETTER K */ - {0x0000004c, 0x00004c}, /* U+004C LATIN CAPITAL LETTER L */ - {0x0000004d, 0x00004d}, /* U+004D LATIN CAPITAL LETTER M */ - {0x0000004e, 0x00004e}, /* U+004E LATIN CAPITAL LETTER N */ - {0x0000004f, 0x00004f}, /* U+004F LATIN CAPITAL LETTER O */ - {0x00000050, 0x000050}, /* U+0050 LATIN CAPITAL LETTER P */ - {0x00000051, 0x000051}, /* U+0051 LATIN CAPITAL LETTER Q */ - {0x00000052, 0x000052}, /* U+0052 LATIN CAPITAL LETTER R */ - {0x00000053, 0x000053}, /* U+0053 LATIN CAPITAL LETTER S */ - {0x00000054, 0x000054}, /* U+0054 LATIN CAPITAL LETTER T */ - {0x00000055, 0x000055}, /* U+0055 LATIN CAPITAL LETTER U */ - {0x00000056, 0x000056}, /* U+0056 LATIN CAPITAL LETTER V */ - {0x00000057, 0x000057}, /* U+0057 LATIN CAPITAL LETTER W */ - {0x00000058, 0x000058}, /* U+0058 LATIN CAPITAL LETTER X */ - {0x00000059, 0x000059}, /* U+0059 LATIN CAPITAL LETTER Y */ - {0x0000005a, 0x00005a}, /* U+005A LATIN CAPITAL LETTER Z */ - {0x0000005b, 0x00005b}, /* U+005B LEFT SQUARE BRACKET */ - {0x0000005c, 0x00005c}, /* U+005C REVERSE SOLIDUS */ - {0x0000005d, 0x00005d}, /* U+005D RIGHT SQUARE BRACKET */ - {0x0000005e, 0x00005e}, /* U+005E CIRCUMFLEX ACCENT */ - {0x0000005f, 0x00005f}, /* U+005F LOW LINE */ - {0x00000060, 0x000060}, /* U+0060 GRAVE ACCENT */ - {0x00000061, 0x000061}, /* U+0061 LATIN SMALL LETTER A */ - {0x00000062, 0x000062}, /* U+0062 LATIN SMALL LETTER B */ - {0x00000063, 0x000063}, /* U+0063 LATIN SMALL LETTER C */ - {0x00000064, 0x000064}, /* U+0064 LATIN SMALL LETTER D */ - {0x00000065, 0x000065}, /* U+0065 LATIN SMALL LETTER E */ - {0x00000066, 0x000066}, /* U+0066 LATIN SMALL LETTER F */ - {0x00000067, 0x000067}, /* U+0067 LATIN SMALL LETTER G */ - {0x00000068, 0x000068}, /* U+0068 LATIN SMALL LETTER H */ - {0x00000069, 0x000069}, /* U+0069 LATIN SMALL LETTER I */ - {0x0000006a, 0x00006a}, /* U+006A LATIN SMALL LETTER J */ - {0x0000006b, 0x00006b}, /* U+006B LATIN SMALL LETTER K */ - {0x0000006c, 0x00006c}, /* U+006C LATIN SMALL LETTER L */ - {0x0000006d, 0x00006d}, /* U+006D LATIN SMALL LETTER M */ - {0x0000006e, 0x00006e}, /* U+006E LATIN SMALL LETTER N */ - {0x0000006f, 0x00006f}, /* U+006F LATIN SMALL LETTER O */ - {0x00000070, 0x000070}, /* U+0070 LATIN SMALL LETTER P */ - {0x00000071, 0x000071}, /* U+0071 LATIN SMALL LETTER Q */ - {0x00000072, 0x000072}, /* U+0072 LATIN SMALL LETTER R */ - {0x00000073, 0x000073}, /* U+0073 LATIN SMALL LETTER S */ - {0x00000074, 0x000074}, /* U+0074 LATIN SMALL LETTER T */ - {0x00000075, 0x000075}, /* U+0075 LATIN SMALL LETTER U */ - {0x00000076, 0x000076}, /* U+0076 LATIN SMALL LETTER V */ - {0x00000077, 0x000077}, /* U+0077 LATIN SMALL LETTER W */ - {0x00000078, 0x000078}, /* U+0078 LATIN SMALL LETTER X */ - {0x00000079, 0x000079}, /* U+0079 LATIN SMALL LETTER Y */ - {0x0000007a, 0x00007a}, /* U+007A LATIN SMALL LETTER Z */ - {0x0000007b, 0x00007b}, /* U+007B LEFT CURLY BRACKET */ - {0x0000007c, 0x00007c}, /* U+007C VERTICAL LINE */ - {0x0000007d, 0x00007d}, /* U+007D RIGHT CURLY BRACKET */ - {0x0000007e, 0x00007e}, /* U+007E TILDE */ - {0x0000007f, 0x00007f}, /* U+007F */ - {0x0000c280, 0x000080}, /* U+0080 */ - {0x0000c281, 0x000081}, /* U+0081 */ - {0x0000c282, 0x000082}, /* U+0082 */ - {0x0000c283, 0x000083}, /* U+0083 */ - {0x0000c284, 0x000084}, /* U+0084 */ - {0x0000c285, 0x000085}, /* U+0085 */ - {0x0000c286, 0x000086}, /* U+0086 */ - {0x0000c287, 0x000087}, /* U+0087 */ - {0x0000c288, 0x000088}, /* U+0088 */ - {0x0000c289, 0x000089}, /* U+0089 */ - {0x0000c28a, 0x00008a}, /* U+008A */ - {0x0000c28b, 0x00008b}, /* U+008B */ - {0x0000c28c, 0x00008c}, /* U+008C */ - {0x0000c28d, 0x00008d}, /* U+008D */ - {0x0000c28e, 0x00008e}, /* U+008E */ - {0x0000c28f, 0x00008f}, /* U+008F */ - {0x0000c290, 0x000090}, /* U+0090 */ - {0x0000c291, 0x000091}, /* U+0091 */ - {0x0000c292, 0x000092}, /* U+0092 */ - {0x0000c293, 0x000093}, /* U+0093 */ - {0x0000c294, 0x000094}, /* U+0094 */ - {0x0000c295, 0x000095}, /* U+0095 */ - {0x0000c296, 0x000096}, /* U+0096 */ - {0x0000c297, 0x000097}, /* U+0097 */ - {0x0000c298, 0x000098}, /* U+0098 */ - {0x0000c299, 0x000099}, /* U+0099 */ - {0x0000c29a, 0x00009a}, /* U+009A */ - {0x0000c29b, 0x00009b}, /* U+009B */ - {0x0000c29c, 0x00009c}, /* U+009C */ - {0x0000c29d, 0x00009d}, /* U+009D */ - {0x0000c29e, 0x00009e}, /* U+009E */ - {0x0000c29f, 0x00009f}, /* U+009F */ - {0x0000c2a0, 0x00a9a2}, /* U+00A0 NO-BREAK SPACE [2000] */ - {0x0000c2a1, 0x00a9a3}, /* U+00A1 INVERTED EXCLAMATION MARK [2000] */ - {0x0000c2a2, 0x00a1f1}, /* U+00A2 CENT SIGN Windows: U+FFE0 */ - {0x0000c2a3, 0x00a1f2}, /* U+00A3 POUND SIGN Windows: U+FFE1 */ - {0x0000c2a4, 0x00a9a4}, /* U+00A4 CURRENCY SIGN [2000] */ - {0x0000c2a5, 0x00a1ef}, /* U+00A5 YEN SIGN Windows: U+FFE5 */ - {0x0000c2a6, 0x00a9a5}, /* U+00A6 BROKEN BAR [2000] */ - {0x0000c2a7, 0x00a1f8}, /* U+00A7 SECTION SIGN */ - {0x0000c2a8, 0x00a1af}, /* U+00A8 DIAERESIS */ - {0x0000c2a9, 0x00a9a6}, /* U+00A9 COPYRIGHT SIGN [2000] */ - {0x0000c2aa, 0x00a9a7}, /* U+00AA FEMININE ORDINAL INDICATOR [2000] */ - {0x0000c2ab, 0x00a9a8}, /* U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK [2000] */ - {0x0000c2ac, 0x00a2cc}, /* U+00AC NOT SIGN [1983] Windows: U+FFE2 */ - {0x0000c2ad, 0x00a9a9}, /* U+00AD SOFT HYPHEN [2000] */ - {0x0000c2ae, 0x00a9aa}, /* U+00AE REGISTERED SIGN [2000] */ - {0x0000c2af, 0x00a9ab}, /* U+00AF MACRON [2000] */ - {0x0000c2b0, 0x00a1eb}, /* U+00B0 DEGREE SIGN */ - {0x0000c2b1, 0x00a1de}, /* U+00B1 PLUS-MINUS SIGN */ - {0x0000c2b2, 0x00a9ac}, /* U+00B2 SUPERSCRIPT TWO [2000] */ - {0x0000c2b3, 0x00a9ad}, /* U+00B3 SUPERSCRIPT THREE [2000] */ - {0x0000c2b4, 0x00a1ad}, /* U+00B4 ACUTE ACCENT */ - {0x0000c2b6, 0x00a2f9}, /* U+00B6 PILCROW SIGN [1983] */ - {0x0000c2b7, 0x00a9ae}, /* U+00B7 MIDDLE DOT [2000] */ - {0x0000c2b8, 0x00a9af}, /* U+00B8 CEDILLA [2000] */ - {0x0000c2b9, 0x00a9b0}, /* U+00B9 SUPERSCRIPT ONE [2000] */ - {0x0000c2ba, 0x00a9b1}, /* U+00BA MASCULINE ORDINAL INDICATOR [2000] */ - {0x0000c2bb, 0x00a9b2}, /* U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK [2000] */ - {0x0000c2bc, 0x00a9b3}, /* U+00BC VULGAR FRACTION ONE QUARTER [2000] */ - {0x0000c2bd, 0x00a9b4}, /* U+00BD VULGAR FRACTION ONE HALF [2000] */ - {0x0000c2be, 0x00a9b5}, /* U+00BE VULGAR FRACTION THREE QUARTERS [2000] */ - {0x0000c2bf, 0x00a9b6}, /* U+00BF INVERTED QUESTION MARK [2000] */ - {0x0000c380, 0x00a9b7}, /* U+00C0 LATIN CAPITAL LETTER A WITH GRAVE [2000] */ - {0x0000c381, 0x00a9b8}, /* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE [2000] */ - {0x0000c382, 0x00a9b9}, /* U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX [2000] */ - {0x0000c383, 0x00a9ba}, /* U+00C3 LATIN CAPITAL LETTER A WITH TILDE [2000] */ - {0x0000c384, 0x00a9bb}, /* U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS [2000] */ - {0x0000c385, 0x00a9bc}, /* U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE [2000] */ - {0x0000c386, 0x00a9bd}, /* U+00C6 LATIN CAPITAL LETTER AE [2000] */ - {0x0000c387, 0x00a9be}, /* U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA [2000] */ - {0x0000c388, 0x00a9bf}, /* U+00C8 LATIN CAPITAL LETTER E WITH GRAVE [2000] */ - {0x0000c389, 0x00a9c0}, /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE [2000] */ - {0x0000c38a, 0x00a9c1}, /* U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX [2000] */ - {0x0000c38b, 0x00a9c2}, /* U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS [2000] */ - {0x0000c38c, 0x00a9c3}, /* U+00CC LATIN CAPITAL LETTER I WITH GRAVE [2000] */ - {0x0000c38d, 0x00a9c4}, /* U+00CD LATIN CAPITAL LETTER I WITH ACUTE [2000] */ - {0x0000c38e, 0x00a9c5}, /* U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX [2000] */ - {0x0000c38f, 0x00a9c6}, /* U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS [2000] */ - {0x0000c390, 0x00a9c7}, /* U+00D0 LATIN CAPITAL LETTER ETH [2000] */ - {0x0000c391, 0x00a9c8}, /* U+00D1 LATIN CAPITAL LETTER N WITH TILDE [2000] */ - {0x0000c392, 0x00a9c9}, /* U+00D2 LATIN CAPITAL LETTER O WITH GRAVE [2000] */ - {0x0000c393, 0x00a9ca}, /* U+00D3 LATIN CAPITAL LETTER O WITH ACUTE [2000] */ - {0x0000c394, 0x00a9cb}, /* U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX [2000] */ - {0x0000c395, 0x00a9cc}, /* U+00D5 LATIN CAPITAL LETTER O WITH TILDE [2000] */ - {0x0000c396, 0x00a9cd}, /* U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS [2000] */ - {0x0000c397, 0x00a1df}, /* U+00D7 MULTIPLICATION SIGN */ - {0x0000c398, 0x00a9ce}, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE [2000] */ - {0x0000c399, 0x00a9cf}, /* U+00D9 LATIN CAPITAL LETTER U WITH GRAVE [2000] */ - {0x0000c39a, 0x00a9d0}, /* U+00DA LATIN CAPITAL LETTER U WITH ACUTE [2000] */ - {0x0000c39b, 0x00a9d1}, /* U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX [2000] */ - {0x0000c39c, 0x00a9d2}, /* U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS [2000] */ - {0x0000c39d, 0x00a9d3}, /* U+00DD LATIN CAPITAL LETTER Y WITH ACUTE [2000] */ - {0x0000c39e, 0x00a9d4}, /* U+00DE LATIN CAPITAL LETTER THORN [2000] */ - {0x0000c39f, 0x00a9d5}, /* U+00DF LATIN SMALL LETTER SHARP S [2000] */ - {0x0000c3a0, 0x00a9d6}, /* U+00E0 LATIN SMALL LETTER A WITH GRAVE [2000] */ - {0x0000c3a1, 0x00a9d7}, /* U+00E1 LATIN SMALL LETTER A WITH ACUTE [2000] */ - {0x0000c3a2, 0x00a9d8}, /* U+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX [2000] */ - {0x0000c3a3, 0x00a9d9}, /* U+00E3 LATIN SMALL LETTER A WITH TILDE [2000] */ - {0x0000c3a4, 0x00a9da}, /* U+00E4 LATIN SMALL LETTER A WITH DIAERESIS [2000] */ - {0x0000c3a5, 0x00a9db}, /* U+00E5 LATIN SMALL LETTER A WITH RING ABOVE [2000] */ - {0x0000c3a6, 0x00a9dc}, /* U+00E6 LATIN SMALL LETTER AE [2000] */ - {0x0000c3a7, 0x00a9dd}, /* U+00E7 LATIN SMALL LETTER C WITH CEDILLA [2000] */ - {0x0000c3a8, 0x00a9de}, /* U+00E8 LATIN SMALL LETTER E WITH GRAVE [2000] */ - {0x0000c3a9, 0x00a9df}, /* U+00E9 LATIN SMALL LETTER E WITH ACUTE [2000] */ - {0x0000c3aa, 0x00a9e0}, /* U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX [2000] */ - {0x0000c3ab, 0x00a9e1}, /* U+00EB LATIN SMALL LETTER E WITH DIAERESIS [2000] */ - {0x0000c3ac, 0x00a9e2}, /* U+00EC LATIN SMALL LETTER I WITH GRAVE [2000] */ - {0x0000c3ad, 0x00a9e3}, /* U+00ED LATIN SMALL LETTER I WITH ACUTE [2000] */ - {0x0000c3ae, 0x00a9e4}, /* U+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX [2000] */ - {0x0000c3af, 0x00a9e5}, /* U+00EF LATIN SMALL LETTER I WITH DIAERESIS [2000] */ - {0x0000c3b0, 0x00a9e6}, /* U+00F0 LATIN SMALL LETTER ETH [2000] */ - {0x0000c3b1, 0x00a9e7}, /* U+00F1 LATIN SMALL LETTER N WITH TILDE [2000] */ - {0x0000c3b2, 0x00a9e8}, /* U+00F2 LATIN SMALL LETTER O WITH GRAVE [2000] */ - {0x0000c3b3, 0x00a9e9}, /* U+00F3 LATIN SMALL LETTER O WITH ACUTE [2000] */ - {0x0000c3b4, 0x00a9ea}, /* U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX [2000] */ - {0x0000c3b5, 0x00a9eb}, /* U+00F5 LATIN SMALL LETTER O WITH TILDE [2000] */ - {0x0000c3b6, 0x00a9ec}, /* U+00F6 LATIN SMALL LETTER O WITH DIAERESIS [2000] */ - {0x0000c3b7, 0x00a1e0}, /* U+00F7 DIVISION SIGN */ - {0x0000c3b8, 0x00a9ed}, /* U+00F8 LATIN SMALL LETTER O WITH STROKE [2000] */ - {0x0000c3b9, 0x00a9ee}, /* U+00F9 LATIN SMALL LETTER U WITH GRAVE [2000] */ - {0x0000c3ba, 0x00a9ef}, /* U+00FA LATIN SMALL LETTER U WITH ACUTE [2000] */ - {0x0000c3bb, 0x00a9f0}, /* U+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX [2000] */ - {0x0000c3bc, 0x00a9f1}, /* U+00FC LATIN SMALL LETTER U WITH DIAERESIS [2000] */ - {0x0000c3bd, 0x00a9f2}, /* U+00FD LATIN SMALL LETTER Y WITH ACUTE [2000] */ - {0x0000c3be, 0x00a9f3}, /* U+00FE LATIN SMALL LETTER THORN [2000] */ - {0x0000c3bf, 0x00a9f4}, /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS [2000] */ - {0x0000c480, 0x00a9f5}, /* U+0100 LATIN CAPITAL LETTER A WITH MACRON [2000] */ - {0x0000c481, 0x00a9fa}, /* U+0101 LATIN SMALL LETTER A WITH MACRON [2000] */ - {0x0000c482, 0x00aaba}, /* U+0102 LATIN CAPITAL LETTER A WITH BREVE [2000] */ - {0x0000c483, 0x00aac9}, /* U+0103 LATIN SMALL LETTER A WITH BREVE [2000] */ - {0x0000c484, 0x00aaa1}, /* U+0104 LATIN CAPITAL LETTER A WITH OGONEK [2000] */ - {0x0000c485, 0x00aaac}, /* U+0105 LATIN SMALL LETTER A WITH OGONEK [2000] */ - {0x0000c486, 0x00aabc}, /* U+0106 LATIN CAPITAL LETTER C WITH ACUTE [2000] */ - {0x0000c487, 0x00aacb}, /* U+0107 LATIN SMALL LETTER C WITH ACUTE [2000] */ - {0x0000c488, 0x00aad9}, /* U+0108 LATIN CAPITAL LETTER C WITH CIRCUMFLEX [2000] */ - {0x0000c489, 0x00aadf}, /* U+0109 LATIN SMALL LETTER C WITH CIRCUMFLEX [2000] */ - {0x0000c48c, 0x00aabd}, /* U+010C LATIN CAPITAL LETTER C WITH CARON [2000] */ - {0x0000c48d, 0x00aacc}, /* U+010D LATIN SMALL LETTER C WITH CARON [2000] */ - {0x0000c48e, 0x00aac0}, /* U+010E LATIN CAPITAL LETTER D WITH CARON [2000] */ - {0x0000c48f, 0x00aacf}, /* U+010F LATIN SMALL LETTER D WITH CARON [2000] */ - {0x0000c491, 0x00aad0}, /* U+0111 LATIN SMALL LETTER D WITH STROKE [2000] */ - {0x0000c492, 0x00a9f8}, /* U+0112 LATIN CAPITAL LETTER E WITH MACRON [2000] */ - {0x0000c493, 0x00a9fd}, /* U+0113 LATIN SMALL LETTER E WITH MACRON [2000] */ - {0x0000c498, 0x00aabe}, /* U+0118 LATIN CAPITAL LETTER E WITH OGONEK [2000] */ - {0x0000c499, 0x00aacd}, /* U+0119 LATIN SMALL LETTER E WITH OGONEK [2000] */ - {0x0000c49a, 0x00aabf}, /* U+011A LATIN CAPITAL LETTER E WITH CARON [2000] */ - {0x0000c49b, 0x00aace}, /* U+011B LATIN SMALL LETTER E WITH CARON [2000] */ - {0x0000c49c, 0x00aada}, /* U+011C LATIN CAPITAL LETTER G WITH CIRCUMFLEX [2000] */ - {0x0000c49d, 0x00aae0}, /* U+011D LATIN SMALL LETTER G WITH CIRCUMFLEX [2000] */ - {0x0000c4a4, 0x00aadb}, /* U+0124 LATIN CAPITAL LETTER H WITH CIRCUMFLEX [2000] */ - {0x0000c4a5, 0x00aae1}, /* U+0125 LATIN SMALL LETTER H WITH CIRCUMFLEX [2000] */ - {0x0000c4a7, 0x00aafd}, /* U+0127 LATIN SMALL LETTER H WITH STROKE [2000] */ - {0x0000c4aa, 0x00a9f6}, /* U+012A LATIN CAPITAL LETTER I WITH MACRON [2000] */ - {0x0000c4ab, 0x00a9fb}, /* U+012B LATIN SMALL LETTER I WITH MACRON [2000] */ - {0x0000c4b4, 0x00aadc}, /* U+0134 LATIN CAPITAL LETTER J WITH CIRCUMFLEX [2000] */ - {0x0000c4b5, 0x00aae2}, /* U+0135 LATIN SMALL LETTER J WITH CIRCUMFLEX [2000] */ - {0x0000c4b9, 0x00aabb}, /* U+0139 LATIN CAPITAL LETTER L WITH ACUTE [2000] */ - {0x0000c4ba, 0x00aaca}, /* U+013A LATIN SMALL LETTER L WITH ACUTE [2000] */ - {0x0000c4bd, 0x00aaa4}, /* U+013D LATIN CAPITAL LETTER L WITH CARON [2000] */ - {0x0000c4be, 0x00aaaf}, /* U+013E LATIN SMALL LETTER L WITH CARON [2000] */ - {0x0000c581, 0x00aaa3}, /* U+0141 LATIN CAPITAL LETTER L WITH STROKE [2000] */ - {0x0000c582, 0x00aaae}, /* U+0142 LATIN SMALL LETTER L WITH STROKE [2000] */ - {0x0000c583, 0x00aac1}, /* U+0143 LATIN CAPITAL LETTER N WITH ACUTE [2000] */ - {0x0000c584, 0x00aad1}, /* U+0144 LATIN SMALL LETTER N WITH ACUTE [2000] */ - {0x0000c587, 0x00aac2}, /* U+0147 LATIN CAPITAL LETTER N WITH CARON [2000] */ - {0x0000c588, 0x00aad2}, /* U+0148 LATIN SMALL LETTER N WITH CARON [2000] */ - {0x0000c58b, 0x00aafa}, /* U+014B LATIN SMALL LETTER ENG [2000] */ - {0x0000c58c, 0x00a9f9}, /* U+014C LATIN CAPITAL LETTER O WITH MACRON [2000] */ - {0x0000c58d, 0x00a9fe}, /* U+014D LATIN SMALL LETTER O WITH MACRON [2000] */ - {0x0000c590, 0x00aac3}, /* U+0150 LATIN CAPITAL LETTER O WITH DOUBLE ACUTE [2000] */ - {0x0000c591, 0x00aad3}, /* U+0151 LATIN SMALL LETTER O WITH DOUBLE ACUTE [2000] */ - {0x0000c592, 0x00abab}, /* U+0152 LATIN CAPITAL LIGATURE OE [2000] */ - {0x0000c593, 0x00abaa}, /* U+0153 LATIN SMALL LIGATURE OE [2000] */ - {0x0000c594, 0x00aab9}, /* U+0154 LATIN CAPITAL LETTER R WITH ACUTE [2000] */ - {0x0000c595, 0x00aac8}, /* U+0155 LATIN SMALL LETTER R WITH ACUTE [2000] */ - {0x0000c598, 0x00aac4}, /* U+0158 LATIN CAPITAL LETTER R WITH CARON [2000] */ - {0x0000c599, 0x00aad4}, /* U+0159 LATIN SMALL LETTER R WITH CARON [2000] */ - {0x0000c59a, 0x00aaa5}, /* U+015A LATIN CAPITAL LETTER S WITH ACUTE [2000] */ - {0x0000c59b, 0x00aab0}, /* U+015B LATIN SMALL LETTER S WITH ACUTE [2000] */ - {0x0000c59c, 0x00aadd}, /* U+015C LATIN CAPITAL LETTER S WITH CIRCUMFLEX [2000] */ - {0x0000c59d, 0x00aae3}, /* U+015D LATIN SMALL LETTER S WITH CIRCUMFLEX [2000] */ - {0x0000c59e, 0x00aaa7}, /* U+015E LATIN CAPITAL LETTER S WITH CEDILLA [2000] */ - {0x0000c59f, 0x00aab3}, /* U+015F LATIN SMALL LETTER S WITH CEDILLA [2000] */ - {0x0000c5a0, 0x00aaa6}, /* U+0160 LATIN CAPITAL LETTER S WITH CARON [2000] */ - {0x0000c5a1, 0x00aab2}, /* U+0161 LATIN SMALL LETTER S WITH CARON [2000] */ - {0x0000c5a2, 0x00aac7}, /* U+0162 LATIN CAPITAL LETTER T WITH CEDILLA [2000] */ - {0x0000c5a3, 0x00aad7}, /* U+0163 LATIN SMALL LETTER T WITH CEDILLA [2000] */ - {0x0000c5a4, 0x00aaa8}, /* U+0164 LATIN CAPITAL LETTER T WITH CARON [2000] */ - {0x0000c5a5, 0x00aab4}, /* U+0165 LATIN SMALL LETTER T WITH CARON [2000] */ - {0x0000c5aa, 0x00a9f7}, /* U+016A LATIN CAPITAL LETTER U WITH MACRON [2000] */ - {0x0000c5ab, 0x00a9fc}, /* U+016B LATIN SMALL LETTER U WITH MACRON [2000] */ - {0x0000c5ac, 0x00aade}, /* U+016C LATIN CAPITAL LETTER U WITH BREVE [2000] */ - {0x0000c5ad, 0x00aae4}, /* U+016D LATIN SMALL LETTER U WITH BREVE [2000] */ - {0x0000c5ae, 0x00aac5}, /* U+016E LATIN CAPITAL LETTER U WITH RING ABOVE [2000] */ - {0x0000c5af, 0x00aad5}, /* U+016F LATIN SMALL LETTER U WITH RING ABOVE [2000] */ - {0x0000c5b0, 0x00aac6}, /* U+0170 LATIN CAPITAL LETTER U WITH DOUBLE ACUTE [2000] */ - {0x0000c5b1, 0x00aad6}, /* U+0171 LATIN SMALL LETTER U WITH DOUBLE ACUTE [2000] */ - {0x0000c5b9, 0x00aaa9}, /* U+0179 LATIN CAPITAL LETTER Z WITH ACUTE [2000] */ - {0x0000c5ba, 0x00aab5}, /* U+017A LATIN SMALL LETTER Z WITH ACUTE [2000] */ - {0x0000c5bb, 0x00aaab}, /* U+017B LATIN CAPITAL LETTER Z WITH DOT ABOVE [2000] */ - {0x0000c5bc, 0x00aab8}, /* U+017C LATIN SMALL LETTER Z WITH DOT ABOVE [2000] */ - {0x0000c5bd, 0x00aaaa}, /* U+017D LATIN CAPITAL LETTER Z WITH CARON [2000] */ - {0x0000c5be, 0x00aab7}, /* U+017E LATIN SMALL LETTER Z WITH CARON [2000] */ - {0x0000c693, 0x00aba9}, /* U+0193 LATIN CAPITAL LETTER G WITH HOOK [2000] */ - {0x0000c782, 0x00aba4}, /* U+01C2 LATIN LETTER ALVEOLAR CLICK [2000] */ - {0x0000c78d, 0x00a8ef}, /* U+01CD LATIN CAPITAL LETTER A WITH CARON [2000] */ - {0x0000c78e, 0x00a8f0}, /* U+01CE LATIN SMALL LETTER A WITH CARON [2000] */ - {0x0000c790, 0x00a8f1}, /* U+01D0 LATIN SMALL LETTER I WITH CARON [2000] */ - {0x0000c791, 0x00a8f6}, /* U+01D1 LATIN CAPITAL LETTER O WITH CARON [2000] */ - {0x0000c792, 0x00a8f7}, /* U+01D2 LATIN SMALL LETTER O WITH CARON [2000] */ - {0x0000c794, 0x00a8f8}, /* U+01D4 LATIN SMALL LETTER U WITH CARON [2000] */ - {0x0000c796, 0x00a8f9}, /* U+01D6 LATIN SMALL LETTER U WITH DIAERESIS AND MACRON [2000] */ - {0x0000c798, 0x00a8fa}, /* U+01D8 LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE [2000] */ - {0x0000c79a, 0x00a8fb}, /* U+01DA LATIN SMALL LETTER U WITH DIAERESIS AND CARON [2000] */ - {0x0000c79c, 0x00a8fc}, /* U+01DC LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE [2000] */ - {0x0000c7b8, 0x00a8f4}, /* U+01F8 LATIN CAPITAL LETTER N WITH GRAVE [2000] */ - {0x0000c7b9, 0x00a8f5}, /* U+01F9 LATIN SMALL LETTER N WITH GRAVE [2000] */ - {0x0000c7bd, 0x00abc5}, /* U+01FD LATIN SMALL LETTER AE WITH ACUTE [2000] */ - {0x0000c990, 0x00abb3}, /* U+0250 LATIN SMALL LETTER TURNED A [2000] */ - {0x0000c991, 0x00abb9}, /* U+0251 LATIN SMALL LETTER ALPHA [2000] */ - {0x0000c992, 0x00abba}, /* U+0252 LATIN SMALL LETTER TURNED ALPHA [2000] */ - {0x0000c993, 0x00aba5}, /* U+0253 LATIN SMALL LETTER B WITH HOOK [2000] */ - {0x0000c994, 0x00abb8}, /* U+0254 LATIN SMALL LETTER OPEN O [2000] */ - {0x0000c995, 0x00abbf}, /* U+0255 LATIN SMALL LETTER C WITH CURL [2000] */ - {0x0000c996, 0x00aaee}, /* U+0256 LATIN SMALL LETTER D WITH TAIL [2000] */ - {0x0000c997, 0x00aba6}, /* U+0257 LATIN SMALL LETTER D WITH HOOK [2000] */ - {0x0000c998, 0x00abae}, /* U+0258 LATIN SMALL LETTER REVERSED E [2000] */ - {0x0000c999, 0x00abb0}, /* U+0259 LATIN SMALL LETTER SCHWA [2000] */ - {0x0000c99a, 0x00abc3}, /* U+025A LATIN SMALL LETTER SCHWA WITH HOOK [2000] */ - {0x0000c99c, 0x00abb1}, /* U+025C LATIN SMALL LETTER REVERSED OPEN E [2000] */ - {0x0000c99e, 0x00abb2}, /* U+025E LATIN SMALL LETTER CLOSED REVERSED OPEN E [2000] */ - {0x0000c99f, 0x00aaf5}, /* U+025F LATIN SMALL LETTER DOTLESS J WITH STROKE [2000] */ - {0x0000c9a0, 0x00aba8}, /* U+0260 LATIN SMALL LETTER G WITH HOOK [2000] */ - {0x0000c9a1, 0x00aaf9}, /* U+0261 LATIN SMALL LETTER SCRIPT G [2000] */ - {0x0000c9a4, 0x00abb6}, /* U+0264 LATIN SMALL LETTER RAMS HORN [2000] */ - {0x0000c9a5, 0x00abbc}, /* U+0265 LATIN SMALL LETTER TURNED H [2000] */ - {0x0000c9a6, 0x00aba2}, /* U+0266 LATIN SMALL LETTER H WITH HOOK [2000] */ - {0x0000c9a7, 0x00abc2}, /* U+0267 LATIN SMALL LETTER HENG WITH HOOK [2000] */ - {0x0000c9a8, 0x00abac}, /* U+0268 LATIN SMALL LETTER I WITH STROKE [2000] */ - {0x0000c9ac, 0x00aaea}, /* U+026C LATIN SMALL LETTER L WITH BELT [2000] */ - {0x0000c9ad, 0x00aaf4}, /* U+026D LATIN SMALL LETTER L WITH RETROFLEX HOOK [2000] */ - {0x0000c9ae, 0x00aaeb}, /* U+026E LATIN SMALL LETTER LEZH [2000] */ - {0x0000c9af, 0x00abb4}, /* U+026F LATIN SMALL LETTER TURNED M [2000] */ - {0x0000c9b0, 0x00aafb}, /* U+0270 LATIN SMALL LETTER TURNED M WITH LONG LEG [2000] */ - {0x0000c9b1, 0x00aae5}, /* U+0271 LATIN SMALL LETTER M WITH HOOK [2000] */ - {0x0000c9b2, 0x00aaf6}, /* U+0272 LATIN SMALL LETTER N WITH LEFT HOOK [2000] */ - {0x0000c9b3, 0x00aaef}, /* U+0273 LATIN SMALL LETTER N WITH RETROFLEX HOOK [2000] */ - {0x0000c9b5, 0x00abaf}, /* U+0275 LATIN SMALL LETTER BARRED O [2000] */ - {0x0000c9b9, 0x00aaec}, /* U+0279 LATIN SMALL LETTER TURNED R [2000] */ - {0x0000c9ba, 0x00abc1}, /* U+027A LATIN SMALL LETTER TURNED R WITH LONG LEG [2000] */ - {0x0000c9bb, 0x00aaf3}, /* U+027B LATIN SMALL LETTER TURNED R WITH HOOK [2000] */ - {0x0000c9bd, 0x00aaf0}, /* U+027D LATIN SMALL LETTER R WITH TAIL [2000] */ - {0x0000c9be, 0x00aae7}, /* U+027E LATIN SMALL LETTER R WITH FISHHOOK [2000] */ - {0x0000ca81, 0x00aafc}, /* U+0281 LATIN LETTER SMALL CAPITAL INVERTED R [2000] */ - {0x0000ca82, 0x00aaf1}, /* U+0282 LATIN SMALL LETTER S WITH HOOK [2000] */ - {0x0000ca83, 0x00aae8}, /* U+0283 LATIN SMALL LETTER ESH [2000] */ - {0x0000ca84, 0x00aba7}, /* U+0284 LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK [2000] */ - {0x0000ca88, 0x00aaed}, /* U+0288 LATIN SMALL LETTER T WITH RETROFLEX HOOK [2000] */ - {0x0000ca89, 0x00abad}, /* U+0289 LATIN SMALL LETTER U BAR [2000] */ - {0x0000ca8a, 0x00abb5}, /* U+028A LATIN SMALL LETTER UPSILON [2000] */ - {0x0000ca8b, 0x00aae6}, /* U+028B LATIN SMALL LETTER V WITH HOOK [2000] */ - {0x0000ca8c, 0x00abb7}, /* U+028C LATIN SMALL LETTER TURNED V [2000] */ - {0x0000ca8d, 0x00abbb}, /* U+028D LATIN SMALL LETTER TURNED W [2000] */ - {0x0000ca8e, 0x00aaf8}, /* U+028E LATIN SMALL LETTER TURNED Y [2000] */ - {0x0000ca90, 0x00aaf2}, /* U+0290 LATIN SMALL LETTER Z WITH RETROFLEX HOOK [2000] */ - {0x0000ca91, 0x00abc0}, /* U+0291 LATIN SMALL LETTER Z WITH CURL [2000] */ - {0x0000ca92, 0x00aae9}, /* U+0292 LATIN SMALL LETTER EZH [2000] */ - {0x0000ca94, 0x00aba1}, /* U+0294 LATIN LETTER GLOTTAL STOP [2000] */ - {0x0000ca95, 0x00aafe}, /* U+0295 LATIN LETTER PHARYNGEAL VOICED FRICATIVE [2000] */ - {0x0000ca98, 0x00aba3}, /* U+0298 LATIN LETTER BILABIAL CLICK [2000] */ - {0x0000ca9d, 0x00aaf7}, /* U+029D LATIN SMALL LETTER J WITH CROSSED-TAIL [2000] */ - {0x0000caa1, 0x00abbe}, /* U+02A1 LATIN LETTER GLOTTAL STOP WITH STROKE [2000] */ - {0x0000caa2, 0x00abbd}, /* U+02A2 LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE [2000] */ - {0x0000cb87, 0x00aab1}, /* U+02C7 CARON [2000] */ - {0x0000cb88, 0x00abd3}, /* U+02C8 MODIFIER LETTER VERTICAL LINE [2000] */ - {0x0000cb8c, 0x00abd4}, /* U+02CC MODIFIER LETTER LOW VERTICAL LINE [2000] */ - {0x0000cb90, 0x00abd5}, /* U+02D0 MODIFIER LETTER TRIANGULAR COLON [2000] */ - {0x0000cb91, 0x00abd6}, /* U+02D1 MODIFIER LETTER HALF TRIANGULAR COLON [2000] */ - {0x0000cb98, 0x00aaa2}, /* U+02D8 BREVE [2000] */ - {0x0000cb99, 0x00aad8}, /* U+02D9 DOT ABOVE [2000] */ - {0x0000cb9b, 0x00aaad}, /* U+02DB OGONEK [2000] */ - {0x0000cb9d, 0x00aab6}, /* U+02DD DOUBLE ACUTE ACCENT [2000] */ - {0x0000cb9e, 0x00abf1}, /* U+02DE MODIFIER LETTER RHOTIC HOOK [2000] */ - {0x0000cba5, 0x00abe0}, /* U+02E5 MODIFIER LETTER EXTRA-HIGH TONE BAR [2000] */ - {0x0000cba6, 0x00abe1}, /* U+02E6 MODIFIER LETTER HIGH TONE BAR [2000] */ - {0x0000cba7, 0x00abe2}, /* U+02E7 MODIFIER LETTER MID TONE BAR [2000] */ - {0x0000cba8, 0x00abe3}, /* U+02E8 MODIFIER LETTER LOW TONE BAR [2000] */ - {0x0000cba9, 0x00abe4}, /* U+02E9 MODIFIER LETTER EXTRA-LOW TONE BAR [2000] */ - {0x0000cc80, 0x00abdc}, /* U+0300 COMBINING GRAVE ACCENT [2000] */ - {0x0000cc81, 0x00abda}, /* U+0301 COMBINING ACUTE ACCENT [2000] */ - {0x0000cc82, 0x00abdf}, /* U+0302 COMBINING CIRCUMFLEX ACCENT [2000] */ - {0x0000cc83, 0x00abfd}, /* U+0303 COMBINING TILDE [2000] */ - {0x0000cc84, 0x00abdb}, /* U+0304 COMBINING MACRON [2000] */ - {0x0000cc86, 0x00abd7}, /* U+0306 COMBINING BREVE [2000] */ - {0x0000cc88, 0x00abed}, /* U+0308 COMBINING DIAERESIS [2000] */ - {0x0000cc8b, 0x00abd9}, /* U+030B COMBINING DOUBLE ACUTE ACCENT [2000] */ - {0x0000cc8c, 0x00abde}, /* U+030C COMBINING CARON [2000] */ - {0x0000cc8f, 0x00abdd}, /* U+030F COMBINING DOUBLE GRAVE ACCENT [2000] */ - {0x0000cc98, 0x00abf8}, /* U+0318 COMBINING LEFT TACK BELOW [2000] */ - {0x0000cc99, 0x00abf9}, /* U+0319 COMBINING RIGHT TACK BELOW [2000] */ - {0x0000cc9a, 0x00abfe}, /* U+031A COMBINING LEFT ANGLE ABOVE [2000] */ - {0x0000cc9c, 0x00abea}, /* U+031C COMBINING LEFT HALF RING BELOW [2000] */ - {0x0000cc9d, 0x00abf6}, /* U+031D COMBINING UP TACK BELOW [2000] */ - {0x0000cc9e, 0x00abf7}, /* U+031E COMBINING DOWN TACK BELOW [2000] */ - {0x0000cc9f, 0x00abeb}, /* U+031F COMBINING PLUS SIGN BELOW [2000] */ - {0x0000cca0, 0x00abec}, /* U+0320 COMBINING MINUS SIGN BELOW [2000] */ - {0x0000cca4, 0x00abf2}, /* U+0324 COMBINING DIAERESIS BELOW [2000] */ - {0x0000cca5, 0x00abe7}, /* U+0325 COMBINING RING BELOW [2000] */ - {0x0000cca9, 0x00abef}, /* U+0329 COMBINING VERTICAL LINE BELOW [2000] */ - {0x0000ccaa, 0x00abfa}, /* U+032A COMBINING BRIDGE BELOW [2000] */ - {0x0000ccac, 0x00abe8}, /* U+032C COMBINING CARON BELOW [2000] */ - {0x0000ccaf, 0x00abf0}, /* U+032F COMBINING INVERTED BREVE BELOW [2000] */ - {0x0000ccb0, 0x00abf3}, /* U+0330 COMBINING TILDE BELOW [2000] */ - {0x0000ccb4, 0x00abf5}, /* U+0334 COMBINING TILDE OVERLAY [2000] */ - {0x0000ccb9, 0x00abe9}, /* U+0339 COMBINING RIGHT HALF RING BELOW [2000] */ - {0x0000ccba, 0x00abfb}, /* U+033A COMBINING INVERTED BRIDGE BELOW [2000] */ - {0x0000ccbb, 0x00abfc}, /* U+033B COMBINING SQUARE BELOW [2000] */ - {0x0000ccbc, 0x00abf4}, /* U+033C COMBINING SEAGULL BELOW [2000] */ - {0x0000ccbd, 0x00abee}, /* U+033D COMBINING X ABOVE [2000] */ - {0x0000cda1, 0x00abd2}, /* U+0361 COMBINING DOUBLE INVERTED BREVE [2000] */ - {0x0000ce91, 0x00a6a1}, /* U+0391 GREEK CAPITAL LETTER ALPHA */ - {0x0000ce92, 0x00a6a2}, /* U+0392 GREEK CAPITAL LETTER BETA */ - {0x0000ce93, 0x00a6a3}, /* U+0393 GREEK CAPITAL LETTER GAMMA */ - {0x0000ce94, 0x00a6a4}, /* U+0394 GREEK CAPITAL LETTER DELTA */ - {0x0000ce95, 0x00a6a5}, /* U+0395 GREEK CAPITAL LETTER EPSILON */ - {0x0000ce96, 0x00a6a6}, /* U+0396 GREEK CAPITAL LETTER ZETA */ - {0x0000ce97, 0x00a6a7}, /* U+0397 GREEK CAPITAL LETTER ETA */ - {0x0000ce98, 0x00a6a8}, /* U+0398 GREEK CAPITAL LETTER THETA */ - {0x0000ce99, 0x00a6a9}, /* U+0399 GREEK CAPITAL LETTER IOTA */ - {0x0000ce9a, 0x00a6aa}, /* U+039A GREEK CAPITAL LETTER KAPPA */ - {0x0000ce9b, 0x00a6ab}, /* U+039B GREEK CAPITAL LETTER LAMDA */ - {0x0000ce9c, 0x00a6ac}, /* U+039C GREEK CAPITAL LETTER MU */ - {0x0000ce9d, 0x00a6ad}, /* U+039D GREEK CAPITAL LETTER NU */ - {0x0000ce9e, 0x00a6ae}, /* U+039E GREEK CAPITAL LETTER XI */ - {0x0000ce9f, 0x00a6af}, /* U+039F GREEK CAPITAL LETTER OMICRON */ - {0x0000cea0, 0x00a6b0}, /* U+03A0 GREEK CAPITAL LETTER PI */ - {0x0000cea1, 0x00a6b1}, /* U+03A1 GREEK CAPITAL LETTER RHO */ - {0x0000cea3, 0x00a6b2}, /* U+03A3 GREEK CAPITAL LETTER SIGMA */ - {0x0000cea4, 0x00a6b3}, /* U+03A4 GREEK CAPITAL LETTER TAU */ - {0x0000cea5, 0x00a6b4}, /* U+03A5 GREEK CAPITAL LETTER UPSILON */ - {0x0000cea6, 0x00a6b5}, /* U+03A6 GREEK CAPITAL LETTER PHI */ - {0x0000cea7, 0x00a6b6}, /* U+03A7 GREEK CAPITAL LETTER CHI */ - {0x0000cea8, 0x00a6b7}, /* U+03A8 GREEK CAPITAL LETTER PSI */ - {0x0000cea9, 0x00a6b8}, /* U+03A9 GREEK CAPITAL LETTER OMEGA */ - {0x0000ceb1, 0x00a6c1}, /* U+03B1 GREEK SMALL LETTER ALPHA */ - {0x0000ceb2, 0x00a6c2}, /* U+03B2 GREEK SMALL LETTER BETA */ - {0x0000ceb3, 0x00a6c3}, /* U+03B3 GREEK SMALL LETTER GAMMA */ - {0x0000ceb4, 0x00a6c4}, /* U+03B4 GREEK SMALL LETTER DELTA */ - {0x0000ceb5, 0x00a6c5}, /* U+03B5 GREEK SMALL LETTER EPSILON */ - {0x0000ceb6, 0x00a6c6}, /* U+03B6 GREEK SMALL LETTER ZETA */ - {0x0000ceb7, 0x00a6c7}, /* U+03B7 GREEK SMALL LETTER ETA */ - {0x0000ceb8, 0x00a6c8}, /* U+03B8 GREEK SMALL LETTER THETA */ - {0x0000ceb9, 0x00a6c9}, /* U+03B9 GREEK SMALL LETTER IOTA */ - {0x0000ceba, 0x00a6ca}, /* U+03BA GREEK SMALL LETTER KAPPA */ - {0x0000cebb, 0x00a6cb}, /* U+03BB GREEK SMALL LETTER LAMDA */ - {0x0000cebc, 0x00a6cc}, /* U+03BC GREEK SMALL LETTER MU */ - {0x0000cebd, 0x00a6cd}, /* U+03BD GREEK SMALL LETTER NU */ - {0x0000cebe, 0x00a6ce}, /* U+03BE GREEK SMALL LETTER XI */ - {0x0000cebf, 0x00a6cf}, /* U+03BF GREEK SMALL LETTER OMICRON */ - {0x0000cf80, 0x00a6d0}, /* U+03C0 GREEK SMALL LETTER PI */ - {0x0000cf81, 0x00a6d1}, /* U+03C1 GREEK SMALL LETTER RHO */ - {0x0000cf82, 0x00a6d9}, /* U+03C2 GREEK SMALL LETTER FINAL SIGMA [2000] */ - {0x0000cf83, 0x00a6d2}, /* U+03C3 GREEK SMALL LETTER SIGMA */ - {0x0000cf84, 0x00a6d3}, /* U+03C4 GREEK SMALL LETTER TAU */ - {0x0000cf85, 0x00a6d4}, /* U+03C5 GREEK SMALL LETTER UPSILON */ - {0x0000cf86, 0x00a6d5}, /* U+03C6 GREEK SMALL LETTER PHI */ - {0x0000cf87, 0x00a6d6}, /* U+03C7 GREEK SMALL LETTER CHI */ - {0x0000cf88, 0x00a6d7}, /* U+03C8 GREEK SMALL LETTER PSI */ - {0x0000cf89, 0x00a6d8}, /* U+03C9 GREEK SMALL LETTER OMEGA */ - {0x0000d081, 0x00a7a7}, /* U+0401 CYRILLIC CAPITAL LETTER IO */ - {0x0000d090, 0x00a7a1}, /* U+0410 CYRILLIC CAPITAL LETTER A */ - {0x0000d091, 0x00a7a2}, /* U+0411 CYRILLIC CAPITAL LETTER BE */ - {0x0000d092, 0x00a7a3}, /* U+0412 CYRILLIC CAPITAL LETTER VE */ - {0x0000d093, 0x00a7a4}, /* U+0413 CYRILLIC CAPITAL LETTER GHE */ - {0x0000d094, 0x00a7a5}, /* U+0414 CYRILLIC CAPITAL LETTER DE */ - {0x0000d095, 0x00a7a6}, /* U+0415 CYRILLIC CAPITAL LETTER IE */ - {0x0000d096, 0x00a7a8}, /* U+0416 CYRILLIC CAPITAL LETTER ZHE */ - {0x0000d097, 0x00a7a9}, /* U+0417 CYRILLIC CAPITAL LETTER ZE */ - {0x0000d098, 0x00a7aa}, /* U+0418 CYRILLIC CAPITAL LETTER I */ - {0x0000d099, 0x00a7ab}, /* U+0419 CYRILLIC CAPITAL LETTER SHORT I */ - {0x0000d09a, 0x00a7ac}, /* U+041A CYRILLIC CAPITAL LETTER KA */ - {0x0000d09b, 0x00a7ad}, /* U+041B CYRILLIC CAPITAL LETTER EL */ - {0x0000d09c, 0x00a7ae}, /* U+041C CYRILLIC CAPITAL LETTER EM */ - {0x0000d09d, 0x00a7af}, /* U+041D CYRILLIC CAPITAL LETTER EN */ - {0x0000d09e, 0x00a7b0}, /* U+041E CYRILLIC CAPITAL LETTER O */ - {0x0000d09f, 0x00a7b1}, /* U+041F CYRILLIC CAPITAL LETTER PE */ - {0x0000d0a0, 0x00a7b2}, /* U+0420 CYRILLIC CAPITAL LETTER ER */ - {0x0000d0a1, 0x00a7b3}, /* U+0421 CYRILLIC CAPITAL LETTER ES */ - {0x0000d0a2, 0x00a7b4}, /* U+0422 CYRILLIC CAPITAL LETTER TE */ - {0x0000d0a3, 0x00a7b5}, /* U+0423 CYRILLIC CAPITAL LETTER U */ - {0x0000d0a4, 0x00a7b6}, /* U+0424 CYRILLIC CAPITAL LETTER EF */ - {0x0000d0a5, 0x00a7b7}, /* U+0425 CYRILLIC CAPITAL LETTER HA */ - {0x0000d0a6, 0x00a7b8}, /* U+0426 CYRILLIC CAPITAL LETTER TSE */ - {0x0000d0a7, 0x00a7b9}, /* U+0427 CYRILLIC CAPITAL LETTER CHE */ - {0x0000d0a8, 0x00a7ba}, /* U+0428 CYRILLIC CAPITAL LETTER SHA */ - {0x0000d0a9, 0x00a7bb}, /* U+0429 CYRILLIC CAPITAL LETTER SHCHA */ - {0x0000d0aa, 0x00a7bc}, /* U+042A CYRILLIC CAPITAL LETTER HARD SIGN */ - {0x0000d0ab, 0x00a7bd}, /* U+042B CYRILLIC CAPITAL LETTER YERU */ - {0x0000d0ac, 0x00a7be}, /* U+042C CYRILLIC CAPITAL LETTER SOFT SIGN */ - {0x0000d0ad, 0x00a7bf}, /* U+042D CYRILLIC CAPITAL LETTER E */ - {0x0000d0ae, 0x00a7c0}, /* U+042E CYRILLIC CAPITAL LETTER YU */ - {0x0000d0af, 0x00a7c1}, /* U+042F CYRILLIC CAPITAL LETTER YA */ - {0x0000d0b0, 0x00a7d1}, /* U+0430 CYRILLIC SMALL LETTER A */ - {0x0000d0b1, 0x00a7d2}, /* U+0431 CYRILLIC SMALL LETTER BE */ - {0x0000d0b2, 0x00a7d3}, /* U+0432 CYRILLIC SMALL LETTER VE */ - {0x0000d0b3, 0x00a7d4}, /* U+0433 CYRILLIC SMALL LETTER GHE */ - {0x0000d0b4, 0x00a7d5}, /* U+0434 CYRILLIC SMALL LETTER DE */ - {0x0000d0b5, 0x00a7d6}, /* U+0435 CYRILLIC SMALL LETTER IE */ - {0x0000d0b6, 0x00a7d8}, /* U+0436 CYRILLIC SMALL LETTER ZHE */ - {0x0000d0b7, 0x00a7d9}, /* U+0437 CYRILLIC SMALL LETTER ZE */ - {0x0000d0b8, 0x00a7da}, /* U+0438 CYRILLIC SMALL LETTER I */ - {0x0000d0b9, 0x00a7db}, /* U+0439 CYRILLIC SMALL LETTER SHORT I */ - {0x0000d0ba, 0x00a7dc}, /* U+043A CYRILLIC SMALL LETTER KA */ - {0x0000d0bb, 0x00a7dd}, /* U+043B CYRILLIC SMALL LETTER EL */ - {0x0000d0bc, 0x00a7de}, /* U+043C CYRILLIC SMALL LETTER EM */ - {0x0000d0bd, 0x00a7df}, /* U+043D CYRILLIC SMALL LETTER EN */ - {0x0000d0be, 0x00a7e0}, /* U+043E CYRILLIC SMALL LETTER O */ - {0x0000d0bf, 0x00a7e1}, /* U+043F CYRILLIC SMALL LETTER PE */ - {0x0000d180, 0x00a7e2}, /* U+0440 CYRILLIC SMALL LETTER ER */ - {0x0000d181, 0x00a7e3}, /* U+0441 CYRILLIC SMALL LETTER ES */ - {0x0000d182, 0x00a7e4}, /* U+0442 CYRILLIC SMALL LETTER TE */ - {0x0000d183, 0x00a7e5}, /* U+0443 CYRILLIC SMALL LETTER U */ - {0x0000d184, 0x00a7e6}, /* U+0444 CYRILLIC SMALL LETTER EF */ - {0x0000d185, 0x00a7e7}, /* U+0445 CYRILLIC SMALL LETTER HA */ - {0x0000d186, 0x00a7e8}, /* U+0446 CYRILLIC SMALL LETTER TSE */ - {0x0000d187, 0x00a7e9}, /* U+0447 CYRILLIC SMALL LETTER CHE */ - {0x0000d188, 0x00a7ea}, /* U+0448 CYRILLIC SMALL LETTER SHA */ - {0x0000d189, 0x00a7eb}, /* U+0449 CYRILLIC SMALL LETTER SHCHA */ - {0x0000d18a, 0x00a7ec}, /* U+044A CYRILLIC SMALL LETTER HARD SIGN */ - {0x0000d18b, 0x00a7ed}, /* U+044B CYRILLIC SMALL LETTER YERU */ - {0x0000d18c, 0x00a7ee}, /* U+044C CYRILLIC SMALL LETTER SOFT SIGN */ - {0x0000d18d, 0x00a7ef}, /* U+044D CYRILLIC SMALL LETTER E */ - {0x0000d18e, 0x00a7f0}, /* U+044E CYRILLIC SMALL LETTER YU */ - {0x0000d18f, 0x00a7f1}, /* U+044F CYRILLIC SMALL LETTER YA */ - {0x0000d191, 0x00a7d7}, /* U+0451 CYRILLIC SMALL LETTER IO */ - {0x00e1b8be, 0x00a8f2}, /* U+1E3E LATIN CAPITAL LETTER M WITH ACUTE [2000] */ - {0x00e1b8bf, 0x00a8f3}, /* U+1E3F LATIN SMALL LETTER M WITH ACUTE [2000] */ - {0x00e1bdb0, 0x00abc6}, /* U+1F70 GREEK SMALL LETTER ALPHA WITH VARIA [2000] */ - {0x00e1bdb1, 0x00abc7}, /* U+1F71 GREEK SMALL LETTER ALPHA WITH OXIA [2000] */ - {0x00e1bdb2, 0x00abd0}, /* U+1F72 GREEK SMALL LETTER EPSILON WITH VARIA [2000] */ - {0x00e1bdb3, 0x00abd1}, /* U+1F73 GREEK SMALL LETTER EPSILON WITH OXIA [2000] */ - {0x00e28090, 0x00a1be}, /* U+2010 HYPHEN */ - {0x00e28093, 0x00a3fc}, /* U+2013 EN DASH [2000] */ - {0x00e28094, 0x00a1bd}, /* U+2014 EM DASH Windows: U+2015 */ - {0x00e28096, 0x00a1c2}, /* U+2016 DOUBLE VERTICAL LINE Windows: U+2225 */ - {0x00e28098, 0x00a1c6}, /* U+2018 LEFT SINGLE QUOTATION MARK */ - {0x00e28099, 0x00a1c7}, /* U+2019 RIGHT SINGLE QUOTATION MARK */ - {0x00e2809c, 0x00a1c8}, /* U+201C LEFT DOUBLE QUOTATION MARK */ - {0x00e2809d, 0x00a1c9}, /* U+201D RIGHT DOUBLE QUOTATION MARK */ - {0x00e280a0, 0x00a2f7}, /* U+2020 DAGGER [1983] */ - {0x00e280a1, 0x00a2f8}, /* U+2021 DOUBLE DAGGER [1983] */ - {0x00e280a2, 0x00a3c0}, /* U+2022 BULLET [2000] */ - {0x00e280a5, 0x00a1c5}, /* U+2025 TWO DOT LEADER */ - {0x00e280a6, 0x00a1c4}, /* U+2026 HORIZONTAL ELLIPSIS */ - {0x00e280b0, 0x00a2f3}, /* U+2030 PER MILLE SIGN [1983] */ - {0x00e280b2, 0x00a1ec}, /* U+2032 PRIME */ - {0x00e280b3, 0x00a1ed}, /* U+2033 DOUBLE PRIME */ - {0x00e280bb, 0x00a2a8}, /* U+203B REFERENCE MARK */ - {0x00e280bc, 0x00a8eb}, /* U+203C DOUBLE EXCLAMATION MARK [2000] */ - {0x00e280be, 0x00a1b1}, /* U+203E OVERLINE Windows: U+FFE3 */ - {0x00e280bf, 0x00abd8}, /* U+203F UNDERTIE [2000] */ - {0x00e28182, 0x00acfe}, /* U+2042 ASTERISM [2000] */ - {0x00e28187, 0x00a8ec}, /* U+2047 DOUBLE QUESTION MARK [2000] [Unicode3.2] */ - {0x00e28188, 0x00a8ed}, /* U+2048 QUESTION EXCLAMATION MARK [2000] */ - {0x00e28189, 0x00a8ee}, /* U+2049 EXCLAMATION QUESTION MARK [2000] */ - {0x00e28191, 0x00acfd}, /* U+2051 TWO ASTERISKS ALIGNED VERTICALLY [2000] [Unicode3.2] */ - {0x00e282ac, 0x00a9a1}, /* U+20AC EURO SIGN [2000] */ - {0x00e28483, 0x00a1ee}, /* U+2103 DEGREE CELSIUS */ - {0x00e2848f, 0x00a3dd}, /* U+210F PLANCK CONSTANT OVER TWO PI [2000] */ - {0x00e28493, 0x00a3df}, /* U+2113 SCRIPT SMALL L [2000] */ - {0x00e28496, 0x00ade2}, /* U+2116 NUMERO SIGN [2000] */ - {0x00e284a1, 0x00ade4}, /* U+2121 TELEPHONE SIGN [2000] */ - {0x00e284a7, 0x00a3e0}, /* U+2127 INVERTED OHM SIGN [2000] */ - {0x00e284ab, 0x00a2f2}, /* U+212B ANGSTROM SIGN [1983] */ - {0x00e284b5, 0x00a3dc}, /* U+2135 ALEF SYMBOL [2000] */ - {0x00e28593, 0x00a7f8}, /* U+2153 VULGAR FRACTION ONE THIRD [2000] */ - {0x00e28594, 0x00a7f9}, /* U+2154 VULGAR FRACTION TWO THIRDS [2000] */ - {0x00e28595, 0x00a7fa}, /* U+2155 VULGAR FRACTION ONE FIFTH [2000] */ - {0x00e285a0, 0x00adb5}, /* U+2160 ROMAN NUMERAL ONE [2000] */ - {0x00e285a1, 0x00adb6}, /* U+2161 ROMAN NUMERAL TWO [2000] */ - {0x00e285a2, 0x00adb7}, /* U+2162 ROMAN NUMERAL THREE [2000] */ - {0x00e285a3, 0x00adb8}, /* U+2163 ROMAN NUMERAL FOUR [2000] */ - {0x00e285a4, 0x00adb9}, /* U+2164 ROMAN NUMERAL FIVE [2000] */ - {0x00e285a5, 0x00adba}, /* U+2165 ROMAN NUMERAL SIX [2000] */ - {0x00e285a6, 0x00adbb}, /* U+2166 ROMAN NUMERAL SEVEN [2000] */ - {0x00e285a7, 0x00adbc}, /* U+2167 ROMAN NUMERAL EIGHT [2000] */ - {0x00e285a8, 0x00adbd}, /* U+2168 ROMAN NUMERAL NINE [2000] */ - {0x00e285a9, 0x00adbe}, /* U+2169 ROMAN NUMERAL TEN [2000] */ - {0x00e285aa, 0x00adbf}, /* U+216A ROMAN NUMERAL ELEVEN [2000] */ - {0x00e285ab, 0x00add7}, /* U+216B ROMAN NUMERAL TWELVE [2000] */ - {0x00e285b0, 0x00acb5}, /* U+2170 SMALL ROMAN NUMERAL ONE [2000] */ - {0x00e285b1, 0x00acb6}, /* U+2171 SMALL ROMAN NUMERAL TWO [2000] */ - {0x00e285b2, 0x00acb7}, /* U+2172 SMALL ROMAN NUMERAL THREE [2000] */ - {0x00e285b3, 0x00acb8}, /* U+2173 SMALL ROMAN NUMERAL FOUR [2000] */ - {0x00e285b4, 0x00acb9}, /* U+2174 SMALL ROMAN NUMERAL FIVE [2000] */ - {0x00e285b5, 0x00acba}, /* U+2175 SMALL ROMAN NUMERAL SIX [2000] */ - {0x00e285b6, 0x00acbb}, /* U+2176 SMALL ROMAN NUMERAL SEVEN [2000] */ - {0x00e285b7, 0x00acbc}, /* U+2177 SMALL ROMAN NUMERAL EIGHT [2000] */ - {0x00e285b8, 0x00acbd}, /* U+2178 SMALL ROMAN NUMERAL NINE [2000] */ - {0x00e285b9, 0x00acbe}, /* U+2179 SMALL ROMAN NUMERAL TEN [2000] */ - {0x00e285ba, 0x00acbf}, /* U+217A SMALL ROMAN NUMERAL ELEVEN [2000] */ - {0x00e285bb, 0x00acc0}, /* U+217B SMALL ROMAN NUMERAL TWELVE [2000] */ - {0x00e28690, 0x00a2ab}, /* U+2190 LEFTWARDS ARROW */ - {0x00e28691, 0x00a2ac}, /* U+2191 UPWARDS ARROW */ - {0x00e28692, 0x00a2aa}, /* U+2192 RIGHTWARDS ARROW */ - {0x00e28693, 0x00a2ad}, /* U+2193 DOWNWARDS ARROW */ - {0x00e28694, 0x00a2f1}, /* U+2194 LEFT RIGHT ARROW [2000] */ - {0x00e28696, 0x00a3a7}, /* U+2196 NORTH WEST ARROW [2000] */ - {0x00e28697, 0x00a3a5}, /* U+2197 NORTH EAST ARROW [2000] */ - {0x00e28698, 0x00a3a6}, /* U+2198 SOUTH EAST ARROW [2000] */ - {0x00e28699, 0x00a3a8}, /* U+2199 SOUTH WEST ARROW [2000] */ - {0x00e28784, 0x00a3a9}, /* U+21C4 RIGHTWARDS ARROW OVER LEFTWARDS ARROW [2000] */ - {0x00e28792, 0x00a2cd}, /* U+21D2 RIGHTWARDS DOUBLE ARROW [1983] */ - {0x00e28794, 0x00a2ce}, /* U+21D4 LEFT RIGHT DOUBLE ARROW [1983] */ - {0x00e287a6, 0x00a3ab}, /* U+21E6 LEFTWARDS WHITE ARROW [2000] */ - {0x00e287a7, 0x00a3ac}, /* U+21E7 UPWARDS WHITE ARROW [2000] */ - {0x00e287a8, 0x00a3aa}, /* U+21E8 RIGHTWARDS WHITE ARROW [2000] */ - {0x00e287a9, 0x00a3ad}, /* U+21E9 DOWNWARDS WHITE ARROW [2000] */ - {0x00e28880, 0x00a2cf}, /* U+2200 FOR ALL [1983] */ - {0x00e28882, 0x00a2df}, /* U+2202 PARTIAL DIFFERENTIAL [1983] */ - {0x00e28883, 0x00a2d0}, /* U+2203 THERE EXISTS [1983] */ - {0x00e28885, 0x00a2c7}, /* U+2205 EMPTY SET [2000] */ - {0x00e28887, 0x00a2e0}, /* U+2207 NABLA [1983] */ - {0x00e28888, 0x00a2ba}, /* U+2208 ELEMENT OF [1983] */ - {0x00e28889, 0x00a2c6}, /* U+2209 NOT AN ELEMENT OF [2000] */ - {0x00e2888b, 0x00a2bb}, /* U+220B CONTAINS AS MEMBER [1983] */ - {0x00e28892, 0x00a1dd}, /* U+2212 MINUS SIGN Windows: U+FF0D */ - {0x00e28893, 0x00a3db}, /* U+2213 MINUS-OR-PLUS SIGN [2000] */ - {0x00e2889a, 0x00a2e5}, /* U+221A SQUARE ROOT [1983] */ - {0x00e2889d, 0x00a2e7}, /* U+221D PROPORTIONAL TO [1983] */ - {0x00e2889e, 0x00a1e7}, /* U+221E INFINITY */ - {0x00e2889f, 0x00adf8}, /* U+221F RIGHT ANGLE [2000] */ - {0x00e288a0, 0x00a2dc}, /* U+2220 ANGLE [1983] */ - {0x00e288a5, 0x00a2d4}, /* U+2225 PARALLEL TO [2000] */ - {0x00e288a6, 0x00a2d5}, /* U+2226 NOT PARALLEL TO [2000] */ - {0x00e288a7, 0x00a2ca}, /* U+2227 LOGICAL AND [1983] */ - {0x00e288a8, 0x00a2cb}, /* U+2228 LOGICAL OR [1983] */ - {0x00e288a9, 0x00a2c1}, /* U+2229 INTERSECTION [1983] */ - {0x00e288aa, 0x00a2c0}, /* U+222A UNION [1983] */ - {0x00e288ab, 0x00a2e9}, /* U+222B INTEGRAL [1983] */ - {0x00e288ac, 0x00a2ea}, /* U+222C DOUBLE INTEGRAL [1983] */ - {0x00e288ae, 0x00adf3}, /* U+222E CONTOUR INTEGRAL [2000] */ - {0x00e288b4, 0x00a1e8}, /* U+2234 THEREFORE */ - {0x00e288b5, 0x00a2e8}, /* U+2235 BECAUSE [1983] */ - {0x00e288bd, 0x00a2e6}, /* U+223D REVERSED TILDE [1983] */ - {0x00e28983, 0x00a2ec}, /* U+2243 ASYMPTOTICALLY EQUAL TO [2000] */ - {0x00e28985, 0x00a2ed}, /* U+2245 APPROXIMATELY EQUAL TO [2000] */ - {0x00e28988, 0x00a2ee}, /* U+2248 ALMOST EQUAL TO [2000] */ - {0x00e28992, 0x00a2e2}, /* U+2252 APPROXIMATELY EQUAL TO OR THE IMAGE OF [1983] */ - {0x00e289a0, 0x00a1e2}, /* U+2260 NOT EQUAL TO */ - {0x00e289a1, 0x00a2e1}, /* U+2261 IDENTICAL TO [1983] */ - {0x00e289a2, 0x00a2eb}, /* U+2262 NOT IDENTICAL TO [2000] */ - {0x00e289a6, 0x00a1e5}, /* U+2266 LESS-THAN OVER EQUAL TO */ - {0x00e289a7, 0x00a1e6}, /* U+2267 GREATER-THAN OVER EQUAL TO */ - {0x00e289aa, 0x00a2e3}, /* U+226A MUCH LESS-THAN [1983] */ - {0x00e289ab, 0x00a2e4}, /* U+226B MUCH GREATER-THAN [1983] */ - {0x00e289b6, 0x00a2ef}, /* U+2276 LESS-THAN OR GREATER-THAN [2000] */ - {0x00e289b7, 0x00a2f0}, /* U+2277 GREATER-THAN OR LESS-THAN [2000] */ - {0x00e28a82, 0x00a2be}, /* U+2282 SUBSET OF [1983] */ - {0x00e28a83, 0x00a2bf}, /* U+2283 SUPERSET OF [1983] */ - {0x00e28a84, 0x00a2c2}, /* U+2284 NOT A SUBSET OF [2000] */ - {0x00e28a85, 0x00a2c3}, /* U+2285 NOT A SUPERSET OF [2000] */ - {0x00e28a86, 0x00a2bc}, /* U+2286 SUBSET OF OR EQUAL TO [1983] */ - {0x00e28a87, 0x00a2bd}, /* U+2287 SUPERSET OF OR EQUAL TO [1983] */ - {0x00e28a8a, 0x00a2c4}, /* U+228A SUBSET OF WITH NOT EQUAL TO [2000] */ - {0x00e28a8b, 0x00a2c5}, /* U+228B SUPERSET OF WITH NOT EQUAL TO [2000] */ - {0x00e28a95, 0x00a2d1}, /* U+2295 CIRCLED PLUS [2000] */ - {0x00e28a96, 0x00a2d2}, /* U+2296 CIRCLED MINUS [2000] */ - {0x00e28a97, 0x00a2d3}, /* U+2297 CIRCLED TIMES [2000] */ - {0x00e28aa5, 0x00a2dd}, /* U+22A5 UP TACK [1983] */ - {0x00e28abf, 0x00adf9}, /* U+22BF RIGHT TRIANGLE [2000] */ - {0x00e28b9a, 0x00a7f6}, /* U+22DA LESS-THAN EQUAL TO OR GREATER-THAN [2000] */ - {0x00e28b9b, 0x00a7f7}, /* U+22DB GREATER-THAN EQUAL TO OR LESS-THAN [2000] */ - {0x00e28c85, 0x00a2c8}, /* U+2305 PROJECTIVE [2000] */ - {0x00e28c86, 0x00a2c9}, /* U+2306 PERSPECTIVE [2000] */ - {0x00e28c92, 0x00a2de}, /* U+2312 ARC [1983] */ - {0x00e28c98, 0x00a7fc}, /* U+2318 PLACE OF INTEREST SIGN [2000] */ - {0x00e28ebe, 0x00a7c2}, /* U+23BE DENTISTRY SYMBOL LIGHT VERTICAL AND TOP RIGHT [2000] [Unicode3.2] */ - {0x00e28ebf, 0x00a7c3}, /* U+23BF DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM RIGHT [2000] [Unicode3.2] */ - {0x00e28f80, 0x00a7c4}, /* U+23C0 DENTISTRY SYMBOL LIGHT VERTICAL WITH CIRCLE [2000] [Unicode3.2] */ - {0x00e28f81, 0x00a7c5}, /* U+23C1 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH CIRCLE [2000] [Unicode3.2] */ - {0x00e28f82, 0x00a7c6}, /* U+23C2 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLE [2000] [Unicode3.2] */ - {0x00e28f83, 0x00a7c7}, /* U+23C3 DENTISTRY SYMBOL LIGHT VERTICAL WITH TRIANGLE [2000] [Unicode3.2] */ - {0x00e28f84, 0x00a7c8}, /* U+23C4 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH TRIANGLE [2000] [Unicode3.2] */ - {0x00e28f85, 0x00a7c9}, /* U+23C5 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH TRIANGLE [2000] [Unicode3.2] */ - {0x00e28f86, 0x00a7ca}, /* U+23C6 DENTISTRY SYMBOL LIGHT VERTICAL AND WAVE [2000] [Unicode3.2] */ - {0x00e28f87, 0x00a7cb}, /* U+23C7 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH WAVE [2000] [Unicode3.2] */ - {0x00e28f88, 0x00a7cc}, /* U+23C8 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH WAVE [2000] [Unicode3.2] */ - {0x00e28f89, 0x00a7cd}, /* U+23C9 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL [2000] [Unicode3.2] */ - {0x00e28f8a, 0x00a7ce}, /* U+23CA DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL [2000] [Unicode3.2] */ - {0x00e28f8b, 0x00a7cf}, /* U+23CB DENTISTRY SYMBOL LIGHT VERTICAL AND TOP LEFT [2000] [Unicode3.2] */ - {0x00e28f8c, 0x00a7d0}, /* U+23CC DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM LEFT [2000] [Unicode3.2] */ - {0x00e28f8e, 0x00a7fe}, /* U+23CE RETURN SYMBOL [2000] [Unicode3.2] */ - {0x00e290a3, 0x00a7fd}, /* U+2423 OPEN BOX [2000] */ - {0x00e291a0, 0x00ada1}, /* U+2460 CIRCLED DIGIT ONE [2000] */ - {0x00e291a1, 0x00ada2}, /* U+2461 CIRCLED DIGIT TWO [2000] */ - {0x00e291a2, 0x00ada3}, /* U+2462 CIRCLED DIGIT THREE [2000] */ - {0x00e291a3, 0x00ada4}, /* U+2463 CIRCLED DIGIT FOUR [2000] */ - {0x00e291a4, 0x00ada5}, /* U+2464 CIRCLED DIGIT FIVE [2000] */ - {0x00e291a5, 0x00ada6}, /* U+2465 CIRCLED DIGIT SIX [2000] */ - {0x00e291a6, 0x00ada7}, /* U+2466 CIRCLED DIGIT SEVEN [2000] */ - {0x00e291a7, 0x00ada8}, /* U+2467 CIRCLED DIGIT EIGHT [2000] */ - {0x00e291a8, 0x00ada9}, /* U+2468 CIRCLED DIGIT NINE [2000] */ - {0x00e291a9, 0x00adaa}, /* U+2469 CIRCLED NUMBER TEN [2000] */ - {0x00e291aa, 0x00adab}, /* U+246A CIRCLED NUMBER ELEVEN [2000] */ - {0x00e291ab, 0x00adac}, /* U+246B CIRCLED NUMBER TWELVE [2000] */ - {0x00e291ac, 0x00adad}, /* U+246C CIRCLED NUMBER THIRTEEN [2000] */ - {0x00e291ad, 0x00adae}, /* U+246D CIRCLED NUMBER FOURTEEN [2000] */ - {0x00e291ae, 0x00adaf}, /* U+246E CIRCLED NUMBER FIFTEEN [2000] */ - {0x00e291af, 0x00adb0}, /* U+246F CIRCLED NUMBER SIXTEEN [2000] */ - {0x00e291b0, 0x00adb1}, /* U+2470 CIRCLED NUMBER SEVENTEEN [2000] */ - {0x00e291b1, 0x00adb2}, /* U+2471 CIRCLED NUMBER EIGHTEEN [2000] */ - {0x00e291b2, 0x00adb3}, /* U+2472 CIRCLED NUMBER NINETEEN [2000] */ - {0x00e291b3, 0x00adb4}, /* U+2473 CIRCLED NUMBER TWENTY [2000] */ - {0x00e29390, 0x00acc1}, /* U+24D0 CIRCLED LATIN SMALL LETTER A [2000] */ - {0x00e29391, 0x00acc2}, /* U+24D1 CIRCLED LATIN SMALL LETTER B [2000] */ - {0x00e29392, 0x00acc3}, /* U+24D2 CIRCLED LATIN SMALL LETTER C [2000] */ - {0x00e29393, 0x00acc4}, /* U+24D3 CIRCLED LATIN SMALL LETTER D [2000] */ - {0x00e29394, 0x00acc5}, /* U+24D4 CIRCLED LATIN SMALL LETTER E [2000] */ - {0x00e29395, 0x00acc6}, /* U+24D5 CIRCLED LATIN SMALL LETTER F [2000] */ - {0x00e29396, 0x00acc7}, /* U+24D6 CIRCLED LATIN SMALL LETTER G [2000] */ - {0x00e29397, 0x00acc8}, /* U+24D7 CIRCLED LATIN SMALL LETTER H [2000] */ - {0x00e29398, 0x00acc9}, /* U+24D8 CIRCLED LATIN SMALL LETTER I [2000] */ - {0x00e29399, 0x00acca}, /* U+24D9 CIRCLED LATIN SMALL LETTER J [2000] */ - {0x00e2939a, 0x00accb}, /* U+24DA CIRCLED LATIN SMALL LETTER K [2000] */ - {0x00e2939b, 0x00accc}, /* U+24DB CIRCLED LATIN SMALL LETTER L [2000] */ - {0x00e2939c, 0x00accd}, /* U+24DC CIRCLED LATIN SMALL LETTER M [2000] */ - {0x00e2939d, 0x00acce}, /* U+24DD CIRCLED LATIN SMALL LETTER N [2000] */ - {0x00e2939e, 0x00accf}, /* U+24DE CIRCLED LATIN SMALL LETTER O [2000] */ - {0x00e2939f, 0x00acd0}, /* U+24DF CIRCLED LATIN SMALL LETTER P [2000] */ - {0x00e293a0, 0x00acd1}, /* U+24E0 CIRCLED LATIN SMALL LETTER Q [2000] */ - {0x00e293a1, 0x00acd2}, /* U+24E1 CIRCLED LATIN SMALL LETTER R [2000] */ - {0x00e293a2, 0x00acd3}, /* U+24E2 CIRCLED LATIN SMALL LETTER S [2000] */ - {0x00e293a3, 0x00acd4}, /* U+24E3 CIRCLED LATIN SMALL LETTER T [2000] */ - {0x00e293a4, 0x00acd5}, /* U+24E4 CIRCLED LATIN SMALL LETTER U [2000] */ - {0x00e293a5, 0x00acd6}, /* U+24E5 CIRCLED LATIN SMALL LETTER V [2000] */ - {0x00e293a6, 0x00acd7}, /* U+24E6 CIRCLED LATIN SMALL LETTER W [2000] */ - {0x00e293a7, 0x00acd8}, /* U+24E7 CIRCLED LATIN SMALL LETTER X [2000] */ - {0x00e293a8, 0x00acd9}, /* U+24E8 CIRCLED LATIN SMALL LETTER Y [2000] */ - {0x00e293a9, 0x00acda}, /* U+24E9 CIRCLED LATIN SMALL LETTER Z [2000] */ - {0x00e293ab, 0x00acab}, /* U+24EB NEGATIVE CIRCLED NUMBER ELEVEN [2000] [Unicode3.2] */ - {0x00e293ac, 0x00acac}, /* U+24EC NEGATIVE CIRCLED NUMBER TWELVE [2000] [Unicode3.2] */ - {0x00e293ad, 0x00acad}, /* U+24ED NEGATIVE CIRCLED NUMBER THIRTEEN [2000] [Unicode3.2] */ - {0x00e293ae, 0x00acae}, /* U+24EE NEGATIVE CIRCLED NUMBER FOURTEEN [2000] [Unicode3.2] */ - {0x00e293af, 0x00acaf}, /* U+24EF NEGATIVE CIRCLED NUMBER FIFTEEN [2000] [Unicode3.2] */ - {0x00e293b0, 0x00acb0}, /* U+24F0 NEGATIVE CIRCLED NUMBER SIXTEEN [2000] [Unicode3.2] */ - {0x00e293b1, 0x00acb1}, /* U+24F1 NEGATIVE CIRCLED NUMBER SEVENTEEN [2000] [Unicode3.2] */ - {0x00e293b2, 0x00acb2}, /* U+24F2 NEGATIVE CIRCLED NUMBER EIGHTEEN [2000] [Unicode3.2] */ - {0x00e293b3, 0x00acb3}, /* U+24F3 NEGATIVE CIRCLED NUMBER NINETEEN [2000] [Unicode3.2] */ - {0x00e293b4, 0x00acb4}, /* U+24F4 NEGATIVE CIRCLED NUMBER TWENTY [2000] [Unicode3.2] */ - {0x00e293b5, 0x00a6da}, /* U+24F5 DOUBLE CIRCLED DIGIT ONE [2000] [Unicode3.2] */ - {0x00e293b6, 0x00a6db}, /* U+24F6 DOUBLE CIRCLED DIGIT TWO [2000] [Unicode3.2] */ - {0x00e293b7, 0x00a6dc}, /* U+24F7 DOUBLE CIRCLED DIGIT THREE [2000] [Unicode3.2] */ - {0x00e293b8, 0x00a6dd}, /* U+24F8 DOUBLE CIRCLED DIGIT FOUR [2000] [Unicode3.2] */ - {0x00e293b9, 0x00a6de}, /* U+24F9 DOUBLE CIRCLED DIGIT FIVE [2000] [Unicode3.2] */ - {0x00e293ba, 0x00a6df}, /* U+24FA DOUBLE CIRCLED DIGIT SIX [2000] [Unicode3.2] */ - {0x00e293bb, 0x00a6e0}, /* U+24FB DOUBLE CIRCLED DIGIT SEVEN [2000] [Unicode3.2] */ - {0x00e293bc, 0x00a6e1}, /* U+24FC DOUBLE CIRCLED DIGIT EIGHT [2000] [Unicode3.2] */ - {0x00e293bd, 0x00a6e2}, /* U+24FD DOUBLE CIRCLED DIGIT NINE [2000] [Unicode3.2] */ - {0x00e293be, 0x00a6e3}, /* U+24FE DOUBLE CIRCLED NUMBER TEN [2000] [Unicode3.2] */ - {0x00e29480, 0x00a8a1}, /* U+2500 BOX DRAWINGS LIGHT HORIZONTAL [1983] */ - {0x00e29481, 0x00a8ac}, /* U+2501 BOX DRAWINGS HEAVY HORIZONTAL [1983] */ - {0x00e29482, 0x00a8a2}, /* U+2502 BOX DRAWINGS LIGHT VERTICAL [1983] */ - {0x00e29483, 0x00a8ad}, /* U+2503 BOX DRAWINGS HEAVY VERTICAL [1983] */ - {0x00e2948c, 0x00a8a3}, /* U+250C BOX DRAWINGS LIGHT DOWN AND RIGHT [1983] */ - {0x00e2948f, 0x00a8ae}, /* U+250F BOX DRAWINGS HEAVY DOWN AND RIGHT [1983] */ - {0x00e29490, 0x00a8a4}, /* U+2510 BOX DRAWINGS LIGHT DOWN AND LEFT [1983] */ - {0x00e29493, 0x00a8af}, /* U+2513 BOX DRAWINGS HEAVY DOWN AND LEFT [1983] */ - {0x00e29494, 0x00a8a6}, /* U+2514 BOX DRAWINGS LIGHT UP AND RIGHT [1983] */ - {0x00e29497, 0x00a8b1}, /* U+2517 BOX DRAWINGS HEAVY UP AND RIGHT [1983] */ - {0x00e29498, 0x00a8a5}, /* U+2518 BOX DRAWINGS LIGHT UP AND LEFT [1983] */ - {0x00e2949b, 0x00a8b0}, /* U+251B BOX DRAWINGS HEAVY UP AND LEFT [1983] */ - {0x00e2949c, 0x00a8a7}, /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT [1983] */ - {0x00e2949d, 0x00a8bc}, /* U+251D BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY [1983] */ - {0x00e294a0, 0x00a8b7}, /* U+2520 BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT [1983] */ - {0x00e294a3, 0x00a8b2}, /* U+2523 BOX DRAWINGS HEAVY VERTICAL AND RIGHT [1983] */ - {0x00e294a4, 0x00a8a9}, /* U+2524 BOX DRAWINGS LIGHT VERTICAL AND LEFT [1983] */ - {0x00e294a5, 0x00a8be}, /* U+2525 BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY [1983] */ - {0x00e294a8, 0x00a8b9}, /* U+2528 BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT [1983] */ - {0x00e294ab, 0x00a8b4}, /* U+252B BOX DRAWINGS HEAVY VERTICAL AND LEFT [1983] */ - {0x00e294ac, 0x00a8a8}, /* U+252C BOX DRAWINGS LIGHT DOWN AND HORIZONTAL [1983] */ - {0x00e294af, 0x00a8b8}, /* U+252F BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY [1983] */ - {0x00e294b0, 0x00a8bd}, /* U+2530 BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT [1983] */ - {0x00e294b3, 0x00a8b3}, /* U+2533 BOX DRAWINGS HEAVY DOWN AND HORIZONTAL [1983] */ - {0x00e294b4, 0x00a8aa}, /* U+2534 BOX DRAWINGS LIGHT UP AND HORIZONTAL [1983] */ - {0x00e294b7, 0x00a8ba}, /* U+2537 BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY [1983] */ - {0x00e294b8, 0x00a8bf}, /* U+2538 BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT [1983] */ - {0x00e294bb, 0x00a8b5}, /* U+253B BOX DRAWINGS HEAVY UP AND HORIZONTAL [1983] */ - {0x00e294bc, 0x00a8ab}, /* U+253C BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL [1983] */ - {0x00e294bf, 0x00a8bb}, /* U+253F BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY [1983] */ - {0x00e29582, 0x00a8c0}, /* U+2542 BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT [1983] */ - {0x00e2958b, 0x00a8b6}, /* U+254B BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL [1983] */ - {0x00e296a0, 0x00a2a3}, /* U+25A0 BLACK SQUARE */ - {0x00e296a1, 0x00a2a2}, /* U+25A1 WHITE SQUARE */ - {0x00e296b1, 0x00a6ed}, /* U+25B1 WHITE PARALLELOGRAM [2000] */ - {0x00e296b2, 0x00a2a5}, /* U+25B2 BLACK UP-POINTING TRIANGLE */ - {0x00e296b3, 0x00a2a4}, /* U+25B3 WHITE UP-POINTING TRIANGLE */ - {0x00e296b6, 0x00a3a2}, /* U+25B6 BLACK RIGHT-POINTING TRIANGLE [2000] */ - {0x00e296b7, 0x00a3a1}, /* U+25B7 WHITE RIGHT-POINTING TRIANGLE [2000] */ - {0x00e296bc, 0x00a2a7}, /* U+25BC BLACK DOWN-POINTING TRIANGLE */ - {0x00e296bd, 0x00a2a6}, /* U+25BD WHITE DOWN-POINTING TRIANGLE */ - {0x00e29780, 0x00a3a4}, /* U+25C0 BLACK LEFT-POINTING TRIANGLE [2000] */ - {0x00e29781, 0x00a3a3}, /* U+25C1 WHITE LEFT-POINTING TRIANGLE [2000] */ - {0x00e29786, 0x00a2a1}, /* U+25C6 BLACK DIAMOND */ - {0x00e29787, 0x00a1fe}, /* U+25C7 WHITE DIAMOND */ - {0x00e29789, 0x00a3bb}, /* U+25C9 FISHEYE [2000] */ - {0x00e2978b, 0x00a1fb}, /* U+25CB WHITE CIRCLE */ - {0x00e2978e, 0x00a1fd}, /* U+25CE BULLSEYE */ - {0x00e2978f, 0x00a1fc}, /* U+25CF BLACK CIRCLE */ - {0x00e29790, 0x00a8e7}, /* U+25D0 CIRCLE WITH LEFT HALF BLACK [2000] */ - {0x00e29791, 0x00a8e8}, /* U+25D1 CIRCLE WITH RIGHT HALF BLACK [2000] */ - {0x00e29792, 0x00a8e9}, /* U+25D2 CIRCLE WITH LOWER HALF BLACK [2000] */ - {0x00e29793, 0x00a8ea}, /* U+25D3 CIRCLE WITH UPPER HALF BLACK [2000] */ - {0x00e297a6, 0x00a3bf}, /* U+25E6 WHITE BULLET [2000] */ - {0x00e297af, 0x00a2fe}, /* U+25EF LARGE CIRCLE [1983] */ - {0x00e29880, 0x00a6e8}, /* U+2600 BLACK SUN WITH RAYS [2000] */ - {0x00e29881, 0x00a6e9}, /* U+2601 CLOUD [2000] */ - {0x00e29882, 0x00a6ea}, /* U+2602 UMBRELLA [2000] */ - {0x00e29883, 0x00a6eb}, /* U+2603 SNOWMAN [2000] */ - {0x00e29885, 0x00a1fa}, /* U+2605 BLACK STAR */ - {0x00e29886, 0x00a1f9}, /* U+2606 WHITE STAR */ - {0x00e2988e, 0x00a6e7}, /* U+260E BLACK TELEPHONE [2000] */ - {0x00e29896, 0x00a6e4}, /* U+2616 WHITE SHOGI PIECE [2000] [Unicode3.2] */ - {0x00e29897, 0x00a6e5}, /* U+2617 BLACK SHOGI PIECE [2000] [Unicode3.2] */ - {0x00e2989e, 0x00adfe}, /* U+261E WHITE RIGHT POINTING INDEX [2000] */ - {0x00e29980, 0x00a1ea}, /* U+2640 FEMALE SIGN */ - {0x00e29982, 0x00a1e9}, /* U+2642 MALE SIGN */ - {0x00e299a0, 0x00a6ba}, /* U+2660 BLACK SPADE SUIT [2000] */ - {0x00e299a1, 0x00a6bd}, /* U+2661 WHITE HEART SUIT [2000] */ - {0x00e299a2, 0x00a6bb}, /* U+2662 WHITE DIAMOND SUIT [2000] */ - {0x00e299a3, 0x00a6c0}, /* U+2663 BLACK CLUB SUIT [2000] */ - {0x00e299a4, 0x00a6b9}, /* U+2664 WHITE SPADE SUIT [2000] */ - {0x00e299a5, 0x00a6be}, /* U+2665 BLACK HEART SUIT [2000] */ - {0x00e299a6, 0x00a6bc}, /* U+2666 BLACK DIAMOND SUIT [2000] */ - {0x00e299a7, 0x00a6bf}, /* U+2667 WHITE CLUB SUIT [2000] */ - {0x00e299a8, 0x00a6ec}, /* U+2668 HOT SPRINGS [2000] */ - {0x00e299a9, 0x00a2fd}, /* U+2669 QUARTER NOTE [2000] */ - {0x00e299aa, 0x00a2f6}, /* U+266A EIGHTH NOTE [1983] */ - {0x00e299ab, 0x00a2fb}, /* U+266B BEAMED EIGHTH NOTES [2000] */ - {0x00e299ac, 0x00a2fc}, /* U+266C BEAMED SIXTEENTH NOTES [2000] */ - {0x00e299ad, 0x00a2f5}, /* U+266D MUSIC FLAT SIGN [1983] */ - {0x00e299ae, 0x00a2fa}, /* U+266E MUSIC NATURAL SIGN [2000] */ - {0x00e299af, 0x00a2f4}, /* U+266F MUSIC SHARP SIGN [1983] */ - {0x00e29c93, 0x00a7fb}, /* U+2713 CHECK MARK [2000] */ - {0x00e29d96, 0x00adfd}, /* U+2756 BLACK DIAMOND MINUS WHITE X [2000] */ - {0x00e29db6, 0x00aca1}, /* U+2776 DINGBAT NEGATIVE CIRCLED DIGIT ONE [2000] */ - {0x00e29db7, 0x00aca2}, /* U+2777 DINGBAT NEGATIVE CIRCLED DIGIT TWO [2000] */ - {0x00e29db8, 0x00aca3}, /* U+2778 DINGBAT NEGATIVE CIRCLED DIGIT THREE [2000] */ - {0x00e29db9, 0x00aca4}, /* U+2779 DINGBAT NEGATIVE CIRCLED DIGIT FOUR [2000] */ - {0x00e29dba, 0x00aca5}, /* U+277A DINGBAT NEGATIVE CIRCLED DIGIT FIVE [2000] */ - {0x00e29dbb, 0x00aca6}, /* U+277B DINGBAT NEGATIVE CIRCLED DIGIT SIX [2000] */ - {0x00e29dbc, 0x00aca7}, /* U+277C DINGBAT NEGATIVE CIRCLED DIGIT SEVEN [2000] */ - {0x00e29dbd, 0x00aca8}, /* U+277D DINGBAT NEGATIVE CIRCLED DIGIT EIGHT [2000] */ - {0x00e29dbe, 0x00aca9}, /* U+277E DINGBAT NEGATIVE CIRCLED DIGIT NINE [2000] */ - {0x00e29dbf, 0x00acaa}, /* U+277F DINGBAT NEGATIVE CIRCLED NUMBER TEN [2000] */ - {0x00e2a4b4, 0x00a3ae}, /* U+2934 ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS [2000] [Unicode3.2] */ - {0x00e2a4b5, 0x00a3af}, /* U+2935 ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS [2000] [Unicode3.2] */ - {0x00e2a6bf, 0x00a3ba}, /* U+29BF CIRCLED BULLET [2000] [Unicode3.2] */ - {0x00e2a7ba, 0x00a3fd}, /* U+29FA DOUBLE PLUS [2000] [Unicode3.2] */ - {0x00e2a7bb, 0x00a3fe}, /* U+29FB TRIPLE PLUS [2000] [Unicode3.2] */ - {0x00e38080, 0x00a1a1}, /* U+3000 IDEOGRAPHIC SPACE */ - {0x00e38081, 0x00a1a2}, /* U+3001 IDEOGRAPHIC COMMA */ - {0x00e38082, 0x00a1a3}, /* U+3002 IDEOGRAPHIC FULL STOP */ - {0x00e38083, 0x00a1b7}, /* U+3003 DITTO MARK */ - {0x00e38085, 0x00a1b9}, /* U+3005 IDEOGRAPHIC ITERATION MARK */ - {0x00e38086, 0x00a1ba}, /* U+3006 IDEOGRAPHIC CLOSING MARK */ - {0x00e38087, 0x00a1bb}, /* U+3007 IDEOGRAPHIC NUMBER ZERO */ - {0x00e38088, 0x00a1d2}, /* U+3008 LEFT ANGLE BRACKET */ - {0x00e38089, 0x00a1d3}, /* U+3009 RIGHT ANGLE BRACKET */ - {0x00e3808a, 0x00a1d4}, /* U+300A LEFT DOUBLE ANGLE BRACKET */ - {0x00e3808b, 0x00a1d5}, /* U+300B RIGHT DOUBLE ANGLE BRACKET */ - {0x00e3808c, 0x00a1d6}, /* U+300C LEFT CORNER BRACKET */ - {0x00e3808d, 0x00a1d7}, /* U+300D RIGHT CORNER BRACKET */ - {0x00e3808e, 0x00a1d8}, /* U+300E LEFT WHITE CORNER BRACKET */ - {0x00e3808f, 0x00a1d9}, /* U+300F RIGHT WHITE CORNER BRACKET */ - {0x00e38090, 0x00a1da}, /* U+3010 LEFT BLACK LENTICULAR BRACKET */ - {0x00e38091, 0x00a1db}, /* U+3011 RIGHT BLACK LENTICULAR BRACKET */ - {0x00e38092, 0x00a2a9}, /* U+3012 POSTAL MARK */ - {0x00e38093, 0x00a2ae}, /* U+3013 GETA MARK */ - {0x00e38094, 0x00a1cc}, /* U+3014 LEFT TORTOISE SHELL BRACKET */ - {0x00e38095, 0x00a1cd}, /* U+3015 RIGHT TORTOISE SHELL BRACKET */ - {0x00e38096, 0x00a2da}, /* U+3016 LEFT WHITE LENTICULAR BRACKET [2000] */ - {0x00e38097, 0x00a2db}, /* U+3017 RIGHT WHITE LENTICULAR BRACKET [2000] */ - {0x00e38098, 0x00a2d8}, /* U+3018 LEFT WHITE TORTOISE SHELL BRACKET [2000] */ - {0x00e38099, 0x00a2d9}, /* U+3019 RIGHT WHITE TORTOISE SHELL BRACKET [2000] */ - {0x00e3809c, 0x00a1c1}, /* U+301C WAVE DASH Windows: U+FF5E */ - {0x00e3809d, 0x00ade0}, /* U+301D REVERSED DOUBLE PRIME QUOTATION MARK [2000] */ - {0x00e3809f, 0x00ade1}, /* U+301F LOW DOUBLE PRIME QUOTATION MARK [2000] */ - {0x00e380a0, 0x00a6e6}, /* U+3020 POSTAL MARK FACE [2000] */ - {0x00e380b3, 0x00a2b3}, /* U+3033 VERTICAL KANA REPEAT MARK UPPER HALF [2000] */ - {0x00e380b4, 0x00a2b4}, /* U+3034 VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF [2000] */ - {0x00e380b5, 0x00a2b5}, /* U+3035 VERTICAL KANA REPEAT MARK LOWER HALF [2000] */ - {0x00e380bb, 0x00a2b6}, /* U+303B VERTICAL IDEOGRAPHIC ITERATION MARK [2000] [Unicode3.2] */ - {0x00e380bc, 0x00a2b7}, /* U+303C MASU MARK [2000] [Unicode3.2] */ - {0x00e380bd, 0x00a3bc}, /* U+303D PART ALTERNATION MARK [2000] [Unicode3.2] */ - {0x00e38181, 0x00a4a1}, /* U+3041 HIRAGANA LETTER SMALL A */ - {0x00e38182, 0x00a4a2}, /* U+3042 HIRAGANA LETTER A */ - {0x00e38183, 0x00a4a3}, /* U+3043 HIRAGANA LETTER SMALL I */ - {0x00e38184, 0x00a4a4}, /* U+3044 HIRAGANA LETTER I */ - {0x00e38185, 0x00a4a5}, /* U+3045 HIRAGANA LETTER SMALL U */ - {0x00e38186, 0x00a4a6}, /* U+3046 HIRAGANA LETTER U */ - {0x00e38187, 0x00a4a7}, /* U+3047 HIRAGANA LETTER SMALL E */ - {0x00e38188, 0x00a4a8}, /* U+3048 HIRAGANA LETTER E */ - {0x00e38189, 0x00a4a9}, /* U+3049 HIRAGANA LETTER SMALL O */ - {0x00e3818a, 0x00a4aa}, /* U+304A HIRAGANA LETTER O */ - {0x00e3818b, 0x00a4ab}, /* U+304B HIRAGANA LETTER KA */ - {0x00e3818c, 0x00a4ac}, /* U+304C HIRAGANA LETTER GA */ - {0x00e3818d, 0x00a4ad}, /* U+304D HIRAGANA LETTER KI */ - {0x00e3818e, 0x00a4ae}, /* U+304E HIRAGANA LETTER GI */ - {0x00e3818f, 0x00a4af}, /* U+304F HIRAGANA LETTER KU */ - {0x00e38190, 0x00a4b0}, /* U+3050 HIRAGANA LETTER GU */ - {0x00e38191, 0x00a4b1}, /* U+3051 HIRAGANA LETTER KE */ - {0x00e38192, 0x00a4b2}, /* U+3052 HIRAGANA LETTER GE */ - {0x00e38193, 0x00a4b3}, /* U+3053 HIRAGANA LETTER KO */ - {0x00e38194, 0x00a4b4}, /* U+3054 HIRAGANA LETTER GO */ - {0x00e38195, 0x00a4b5}, /* U+3055 HIRAGANA LETTER SA */ - {0x00e38196, 0x00a4b6}, /* U+3056 HIRAGANA LETTER ZA */ - {0x00e38197, 0x00a4b7}, /* U+3057 HIRAGANA LETTER SI */ - {0x00e38198, 0x00a4b8}, /* U+3058 HIRAGANA LETTER ZI */ - {0x00e38199, 0x00a4b9}, /* U+3059 HIRAGANA LETTER SU */ - {0x00e3819a, 0x00a4ba}, /* U+305A HIRAGANA LETTER ZU */ - {0x00e3819b, 0x00a4bb}, /* U+305B HIRAGANA LETTER SE */ - {0x00e3819c, 0x00a4bc}, /* U+305C HIRAGANA LETTER ZE */ - {0x00e3819d, 0x00a4bd}, /* U+305D HIRAGANA LETTER SO */ - {0x00e3819e, 0x00a4be}, /* U+305E HIRAGANA LETTER ZO */ - {0x00e3819f, 0x00a4bf}, /* U+305F HIRAGANA LETTER TA */ - {0x00e381a0, 0x00a4c0}, /* U+3060 HIRAGANA LETTER DA */ - {0x00e381a1, 0x00a4c1}, /* U+3061 HIRAGANA LETTER TI */ - {0x00e381a2, 0x00a4c2}, /* U+3062 HIRAGANA LETTER DI */ - {0x00e381a3, 0x00a4c3}, /* U+3063 HIRAGANA LETTER SMALL TU */ - {0x00e381a4, 0x00a4c4}, /* U+3064 HIRAGANA LETTER TU */ - {0x00e381a5, 0x00a4c5}, /* U+3065 HIRAGANA LETTER DU */ - {0x00e381a6, 0x00a4c6}, /* U+3066 HIRAGANA LETTER TE */ - {0x00e381a7, 0x00a4c7}, /* U+3067 HIRAGANA LETTER DE */ - {0x00e381a8, 0x00a4c8}, /* U+3068 HIRAGANA LETTER TO */ - {0x00e381a9, 0x00a4c9}, /* U+3069 HIRAGANA LETTER DO */ - {0x00e381aa, 0x00a4ca}, /* U+306A HIRAGANA LETTER NA */ - {0x00e381ab, 0x00a4cb}, /* U+306B HIRAGANA LETTER NI */ - {0x00e381ac, 0x00a4cc}, /* U+306C HIRAGANA LETTER NU */ - {0x00e381ad, 0x00a4cd}, /* U+306D HIRAGANA LETTER NE */ - {0x00e381ae, 0x00a4ce}, /* U+306E HIRAGANA LETTER NO */ - {0x00e381af, 0x00a4cf}, /* U+306F HIRAGANA LETTER HA */ - {0x00e381b0, 0x00a4d0}, /* U+3070 HIRAGANA LETTER BA */ - {0x00e381b1, 0x00a4d1}, /* U+3071 HIRAGANA LETTER PA */ - {0x00e381b2, 0x00a4d2}, /* U+3072 HIRAGANA LETTER HI */ - {0x00e381b3, 0x00a4d3}, /* U+3073 HIRAGANA LETTER BI */ - {0x00e381b4, 0x00a4d4}, /* U+3074 HIRAGANA LETTER PI */ - {0x00e381b5, 0x00a4d5}, /* U+3075 HIRAGANA LETTER HU */ - {0x00e381b6, 0x00a4d6}, /* U+3076 HIRAGANA LETTER BU */ - {0x00e381b7, 0x00a4d7}, /* U+3077 HIRAGANA LETTER PU */ - {0x00e381b8, 0x00a4d8}, /* U+3078 HIRAGANA LETTER HE */ - {0x00e381b9, 0x00a4d9}, /* U+3079 HIRAGANA LETTER BE */ - {0x00e381ba, 0x00a4da}, /* U+307A HIRAGANA LETTER PE */ - {0x00e381bb, 0x00a4db}, /* U+307B HIRAGANA LETTER HO */ - {0x00e381bc, 0x00a4dc}, /* U+307C HIRAGANA LETTER BO */ - {0x00e381bd, 0x00a4dd}, /* U+307D HIRAGANA LETTER PO */ - {0x00e381be, 0x00a4de}, /* U+307E HIRAGANA LETTER MA */ - {0x00e381bf, 0x00a4df}, /* U+307F HIRAGANA LETTER MI */ - {0x00e38280, 0x00a4e0}, /* U+3080 HIRAGANA LETTER MU */ - {0x00e38281, 0x00a4e1}, /* U+3081 HIRAGANA LETTER ME */ - {0x00e38282, 0x00a4e2}, /* U+3082 HIRAGANA LETTER MO */ - {0x00e38283, 0x00a4e3}, /* U+3083 HIRAGANA LETTER SMALL YA */ - {0x00e38284, 0x00a4e4}, /* U+3084 HIRAGANA LETTER YA */ - {0x00e38285, 0x00a4e5}, /* U+3085 HIRAGANA LETTER SMALL YU */ - {0x00e38286, 0x00a4e6}, /* U+3086 HIRAGANA LETTER YU */ - {0x00e38287, 0x00a4e7}, /* U+3087 HIRAGANA LETTER SMALL YO */ - {0x00e38288, 0x00a4e8}, /* U+3088 HIRAGANA LETTER YO */ - {0x00e38289, 0x00a4e9}, /* U+3089 HIRAGANA LETTER RA */ - {0x00e3828a, 0x00a4ea}, /* U+308A HIRAGANA LETTER RI */ - {0x00e3828b, 0x00a4eb}, /* U+308B HIRAGANA LETTER RU */ - {0x00e3828c, 0x00a4ec}, /* U+308C HIRAGANA LETTER RE */ - {0x00e3828d, 0x00a4ed}, /* U+308D HIRAGANA LETTER RO */ - {0x00e3828e, 0x00a4ee}, /* U+308E HIRAGANA LETTER SMALL WA */ - {0x00e3828f, 0x00a4ef}, /* U+308F HIRAGANA LETTER WA */ - {0x00e38290, 0x00a4f0}, /* U+3090 HIRAGANA LETTER WI */ - {0x00e38291, 0x00a4f1}, /* U+3091 HIRAGANA LETTER WE */ - {0x00e38292, 0x00a4f2}, /* U+3092 HIRAGANA LETTER WO */ - {0x00e38293, 0x00a4f3}, /* U+3093 HIRAGANA LETTER N */ - {0x00e38294, 0x00a4f4}, /* U+3094 HIRAGANA LETTER VU [2000] */ - {0x00e38295, 0x00a4f5}, /* U+3095 HIRAGANA LETTER SMALL KA [2000] [Unicode3.2] */ - {0x00e38296, 0x00a4f6}, /* U+3096 HIRAGANA LETTER SMALL KE [2000] [Unicode3.2] */ - {0x00e3829b, 0x00a1ab}, /* U+309B KATAKANA-HIRAGANA VOICED SOUND MARK */ - {0x00e3829c, 0x00a1ac}, /* U+309C KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ - {0x00e3829d, 0x00a1b5}, /* U+309D HIRAGANA ITERATION MARK */ - {0x00e3829e, 0x00a1b6}, /* U+309E HIRAGANA VOICED ITERATION MARK */ - {0x00e3829f, 0x00a2b9}, /* U+309F HIRAGANA DIGRAPH YORI [2000] [Unicode3.2] */ - {0x00e382a0, 0x00a3fb}, /* U+30A0 KATAKANA-HIRAGANA DOUBLE HYPHEN [2000] [Unicode3.2] */ - {0x00e382a1, 0x00a5a1}, /* U+30A1 KATAKANA LETTER SMALL A */ - {0x00e382a2, 0x00a5a2}, /* U+30A2 KATAKANA LETTER A */ - {0x00e382a3, 0x00a5a3}, /* U+30A3 KATAKANA LETTER SMALL I */ - {0x00e382a4, 0x00a5a4}, /* U+30A4 KATAKANA LETTER I */ - {0x00e382a5, 0x00a5a5}, /* U+30A5 KATAKANA LETTER SMALL U */ - {0x00e382a6, 0x00a5a6}, /* U+30A6 KATAKANA LETTER U */ - {0x00e382a7, 0x00a5a7}, /* U+30A7 KATAKANA LETTER SMALL E */ - {0x00e382a8, 0x00a5a8}, /* U+30A8 KATAKANA LETTER E */ - {0x00e382a9, 0x00a5a9}, /* U+30A9 KATAKANA LETTER SMALL O */ - {0x00e382aa, 0x00a5aa}, /* U+30AA KATAKANA LETTER O */ - {0x00e382ab, 0x00a5ab}, /* U+30AB KATAKANA LETTER KA */ - {0x00e382ac, 0x00a5ac}, /* U+30AC KATAKANA LETTER GA */ - {0x00e382ad, 0x00a5ad}, /* U+30AD KATAKANA LETTER KI */ - {0x00e382ae, 0x00a5ae}, /* U+30AE KATAKANA LETTER GI */ - {0x00e382af, 0x00a5af}, /* U+30AF KATAKANA LETTER KU */ - {0x00e382b0, 0x00a5b0}, /* U+30B0 KATAKANA LETTER GU */ - {0x00e382b1, 0x00a5b1}, /* U+30B1 KATAKANA LETTER KE */ - {0x00e382b2, 0x00a5b2}, /* U+30B2 KATAKANA LETTER GE */ - {0x00e382b3, 0x00a5b3}, /* U+30B3 KATAKANA LETTER KO */ - {0x00e382b4, 0x00a5b4}, /* U+30B4 KATAKANA LETTER GO */ - {0x00e382b5, 0x00a5b5}, /* U+30B5 KATAKANA LETTER SA */ - {0x00e382b6, 0x00a5b6}, /* U+30B6 KATAKANA LETTER ZA */ - {0x00e382b7, 0x00a5b7}, /* U+30B7 KATAKANA LETTER SI */ - {0x00e382b8, 0x00a5b8}, /* U+30B8 KATAKANA LETTER ZI */ - {0x00e382b9, 0x00a5b9}, /* U+30B9 KATAKANA LETTER SU */ - {0x00e382ba, 0x00a5ba}, /* U+30BA KATAKANA LETTER ZU */ - {0x00e382bb, 0x00a5bb}, /* U+30BB KATAKANA LETTER SE */ - {0x00e382bc, 0x00a5bc}, /* U+30BC KATAKANA LETTER ZE */ - {0x00e382bd, 0x00a5bd}, /* U+30BD KATAKANA LETTER SO */ - {0x00e382be, 0x00a5be}, /* U+30BE KATAKANA LETTER ZO */ - {0x00e382bf, 0x00a5bf}, /* U+30BF KATAKANA LETTER TA */ - {0x00e38380, 0x00a5c0}, /* U+30C0 KATAKANA LETTER DA */ - {0x00e38381, 0x00a5c1}, /* U+30C1 KATAKANA LETTER TI */ - {0x00e38382, 0x00a5c2}, /* U+30C2 KATAKANA LETTER DI */ - {0x00e38383, 0x00a5c3}, /* U+30C3 KATAKANA LETTER SMALL TU */ - {0x00e38384, 0x00a5c4}, /* U+30C4 KATAKANA LETTER TU */ - {0x00e38385, 0x00a5c5}, /* U+30C5 KATAKANA LETTER DU */ - {0x00e38386, 0x00a5c6}, /* U+30C6 KATAKANA LETTER TE */ - {0x00e38387, 0x00a5c7}, /* U+30C7 KATAKANA LETTER DE */ - {0x00e38388, 0x00a5c8}, /* U+30C8 KATAKANA LETTER TO */ - {0x00e38389, 0x00a5c9}, /* U+30C9 KATAKANA LETTER DO */ - {0x00e3838a, 0x00a5ca}, /* U+30CA KATAKANA LETTER NA */ - {0x00e3838b, 0x00a5cb}, /* U+30CB KATAKANA LETTER NI */ - {0x00e3838c, 0x00a5cc}, /* U+30CC KATAKANA LETTER NU */ - {0x00e3838d, 0x00a5cd}, /* U+30CD KATAKANA LETTER NE */ - {0x00e3838e, 0x00a5ce}, /* U+30CE KATAKANA LETTER NO */ - {0x00e3838f, 0x00a5cf}, /* U+30CF KATAKANA LETTER HA */ - {0x00e38390, 0x00a5d0}, /* U+30D0 KATAKANA LETTER BA */ - {0x00e38391, 0x00a5d1}, /* U+30D1 KATAKANA LETTER PA */ - {0x00e38392, 0x00a5d2}, /* U+30D2 KATAKANA LETTER HI */ - {0x00e38393, 0x00a5d3}, /* U+30D3 KATAKANA LETTER BI */ - {0x00e38394, 0x00a5d4}, /* U+30D4 KATAKANA LETTER PI */ - {0x00e38395, 0x00a5d5}, /* U+30D5 KATAKANA LETTER HU */ - {0x00e38396, 0x00a5d6}, /* U+30D6 KATAKANA LETTER BU */ - {0x00e38397, 0x00a5d7}, /* U+30D7 KATAKANA LETTER PU */ - {0x00e38398, 0x00a5d8}, /* U+30D8 KATAKANA LETTER HE */ - {0x00e38399, 0x00a5d9}, /* U+30D9 KATAKANA LETTER BE */ - {0x00e3839a, 0x00a5da}, /* U+30DA KATAKANA LETTER PE */ - {0x00e3839b, 0x00a5db}, /* U+30DB KATAKANA LETTER HO */ - {0x00e3839c, 0x00a5dc}, /* U+30DC KATAKANA LETTER BO */ - {0x00e3839d, 0x00a5dd}, /* U+30DD KATAKANA LETTER PO */ - {0x00e3839e, 0x00a5de}, /* U+30DE KATAKANA LETTER MA */ - {0x00e3839f, 0x00a5df}, /* U+30DF KATAKANA LETTER MI */ - {0x00e383a0, 0x00a5e0}, /* U+30E0 KATAKANA LETTER MU */ - {0x00e383a1, 0x00a5e1}, /* U+30E1 KATAKANA LETTER ME */ - {0x00e383a2, 0x00a5e2}, /* U+30E2 KATAKANA LETTER MO */ - {0x00e383a3, 0x00a5e3}, /* U+30E3 KATAKANA LETTER SMALL YA */ - {0x00e383a4, 0x00a5e4}, /* U+30E4 KATAKANA LETTER YA */ - {0x00e383a5, 0x00a5e5}, /* U+30E5 KATAKANA LETTER SMALL YU */ - {0x00e383a6, 0x00a5e6}, /* U+30E6 KATAKANA LETTER YU */ - {0x00e383a7, 0x00a5e7}, /* U+30E7 KATAKANA LETTER SMALL YO */ - {0x00e383a8, 0x00a5e8}, /* U+30E8 KATAKANA LETTER YO */ - {0x00e383a9, 0x00a5e9}, /* U+30E9 KATAKANA LETTER RA */ - {0x00e383aa, 0x00a5ea}, /* U+30EA KATAKANA LETTER RI */ - {0x00e383ab, 0x00a5eb}, /* U+30EB KATAKANA LETTER RU */ - {0x00e383ac, 0x00a5ec}, /* U+30EC KATAKANA LETTER RE */ - {0x00e383ad, 0x00a5ed}, /* U+30ED KATAKANA LETTER RO */ - {0x00e383ae, 0x00a5ee}, /* U+30EE KATAKANA LETTER SMALL WA */ - {0x00e383af, 0x00a5ef}, /* U+30EF KATAKANA LETTER WA */ - {0x00e383b0, 0x00a5f0}, /* U+30F0 KATAKANA LETTER WI */ - {0x00e383b1, 0x00a5f1}, /* U+30F1 KATAKANA LETTER WE */ - {0x00e383b2, 0x00a5f2}, /* U+30F2 KATAKANA LETTER WO */ - {0x00e383b3, 0x00a5f3}, /* U+30F3 KATAKANA LETTER N */ - {0x00e383b4, 0x00a5f4}, /* U+30F4 KATAKANA LETTER VU */ - {0x00e383b5, 0x00a5f5}, /* U+30F5 KATAKANA LETTER SMALL KA */ - {0x00e383b6, 0x00a5f6}, /* U+30F6 KATAKANA LETTER SMALL KE */ - {0x00e383b7, 0x00a7f2}, /* U+30F7 KATAKANA LETTER VA [2000] */ - {0x00e383b8, 0x00a7f3}, /* U+30F8 KATAKANA LETTER VI [2000] */ - {0x00e383b9, 0x00a7f4}, /* U+30F9 KATAKANA LETTER VE [2000] */ - {0x00e383ba, 0x00a7f5}, /* U+30FA KATAKANA LETTER VO [2000] */ - {0x00e383bb, 0x00a1a6}, /* U+30FB KATAKANA MIDDLE DOT */ - {0x00e383bc, 0x00a1bc}, /* U+30FC KATAKANA-HIRAGANA PROLONGED SOUND MARK */ - {0x00e383bd, 0x00a1b3}, /* U+30FD KATAKANA ITERATION MARK */ - {0x00e383be, 0x00a1b4}, /* U+30FE KATAKANA VOICED ITERATION MARK */ - {0x00e383bf, 0x00a2b8}, /* U+30FF KATAKANA DIGRAPH KOTO [2000] [Unicode3.2] */ - {0x00e387b0, 0x00a6ee}, /* U+31F0 KATAKANA LETTER SMALL KU [2000] [Unicode3.2] */ - {0x00e387b1, 0x00a6ef}, /* U+31F1 KATAKANA LETTER SMALL SI [2000] [Unicode3.2] */ - {0x00e387b2, 0x00a6f0}, /* U+31F2 KATAKANA LETTER SMALL SU [2000] [Unicode3.2] */ - {0x00e387b3, 0x00a6f1}, /* U+31F3 KATAKANA LETTER SMALL TO [2000] [Unicode3.2] */ - {0x00e387b4, 0x00a6f2}, /* U+31F4 KATAKANA LETTER SMALL NU [2000] [Unicode3.2] */ - {0x00e387b5, 0x00a6f3}, /* U+31F5 KATAKANA LETTER SMALL HA [2000] [Unicode3.2] */ - {0x00e387b6, 0x00a6f4}, /* U+31F6 KATAKANA LETTER SMALL HI [2000] [Unicode3.2] */ - {0x00e387b7, 0x00a6f5}, /* U+31F7 KATAKANA LETTER SMALL HU [2000] [Unicode3.2] */ - {0x00e387b8, 0x00a6f6}, /* U+31F8 KATAKANA LETTER SMALL HE [2000] [Unicode3.2] */ - {0x00e387b9, 0x00a6f7}, /* U+31F9 KATAKANA LETTER SMALL HO [2000] [Unicode3.2] */ - {0x00e387ba, 0x00a6f9}, /* U+31FA KATAKANA LETTER SMALL MU [2000] [Unicode3.2] */ - {0x00e387bb, 0x00a6fa}, /* U+31FB KATAKANA LETTER SMALL RA [2000] [Unicode3.2] */ - {0x00e387bc, 0x00a6fb}, /* U+31FC KATAKANA LETTER SMALL RI [2000] [Unicode3.2] */ - {0x00e387bd, 0x00a6fc}, /* U+31FD KATAKANA LETTER SMALL RU [2000] [Unicode3.2] */ - {0x00e387be, 0x00a6fd}, /* U+31FE KATAKANA LETTER SMALL RE [2000] [Unicode3.2] */ - {0x00e387bf, 0x00a6fe}, /* U+31FF KATAKANA LETTER SMALL RO [2000] [Unicode3.2] */ - {0x00e388b1, 0x00adea}, /* U+3231 PARENTHESIZED IDEOGRAPH STOCK [2000] */ - {0x00e388b2, 0x00adeb}, /* U+3232 PARENTHESIZED IDEOGRAPH HAVE [2000] */ - {0x00e388b9, 0x00adec}, /* U+3239 PARENTHESIZED IDEOGRAPH REPRESENT [2000] */ - {0x00e38991, 0x00a8c1}, /* U+3251 CIRCLED NUMBER TWENTY ONE [2000] [Unicode3.2] */ - {0x00e38992, 0x00a8c2}, /* U+3252 CIRCLED NUMBER TWENTY TWO [2000] [Unicode3.2] */ - {0x00e38993, 0x00a8c3}, /* U+3253 CIRCLED NUMBER TWENTY THREE [2000] [Unicode3.2] */ - {0x00e38994, 0x00a8c4}, /* U+3254 CIRCLED NUMBER TWENTY FOUR [2000] [Unicode3.2] */ - {0x00e38995, 0x00a8c5}, /* U+3255 CIRCLED NUMBER TWENTY FIVE [2000] [Unicode3.2] */ - {0x00e38996, 0x00a8c6}, /* U+3256 CIRCLED NUMBER TWENTY SIX [2000] [Unicode3.2] */ - {0x00e38997, 0x00a8c7}, /* U+3257 CIRCLED NUMBER TWENTY SEVEN [2000] [Unicode3.2] */ - {0x00e38998, 0x00a8c8}, /* U+3258 CIRCLED NUMBER TWENTY EIGHT [2000] [Unicode3.2] */ - {0x00e38999, 0x00a8c9}, /* U+3259 CIRCLED NUMBER TWENTY NINE [2000] [Unicode3.2] */ - {0x00e3899a, 0x00a8ca}, /* U+325A CIRCLED NUMBER THIRTY [2000] [Unicode3.2] */ - {0x00e3899b, 0x00a8cb}, /* U+325B CIRCLED NUMBER THIRTY ONE [2000] [Unicode3.2] */ - {0x00e3899c, 0x00a8cc}, /* U+325C CIRCLED NUMBER THIRTY TWO [2000] [Unicode3.2] */ - {0x00e3899d, 0x00a8cd}, /* U+325D CIRCLED NUMBER THIRTY THREE [2000] [Unicode3.2] */ - {0x00e3899e, 0x00a8ce}, /* U+325E CIRCLED NUMBER THIRTY FOUR [2000] [Unicode3.2] */ - {0x00e3899f, 0x00a8cf}, /* U+325F CIRCLED NUMBER THIRTY FIVE [2000] [Unicode3.2] */ - {0x00e38aa4, 0x00ade5}, /* U+32A4 CIRCLED IDEOGRAPH HIGH [2000] */ - {0x00e38aa5, 0x00ade6}, /* U+32A5 CIRCLED IDEOGRAPH CENTRE [2000] */ - {0x00e38aa6, 0x00ade7}, /* U+32A6 CIRCLED IDEOGRAPH LOW [2000] */ - {0x00e38aa7, 0x00ade8}, /* U+32A7 CIRCLED IDEOGRAPH LEFT [2000] */ - {0x00e38aa8, 0x00ade9}, /* U+32A8 CIRCLED IDEOGRAPH RIGHT [2000] */ - {0x00e38ab1, 0x00a8d0}, /* U+32B1 CIRCLED NUMBER THIRTY SIX [2000] [Unicode3.2] */ - {0x00e38ab2, 0x00a8d1}, /* U+32B2 CIRCLED NUMBER THIRTY SEVEN [2000] [Unicode3.2] */ - {0x00e38ab3, 0x00a8d2}, /* U+32B3 CIRCLED NUMBER THIRTY EIGHT [2000] [Unicode3.2] */ - {0x00e38ab4, 0x00a8d3}, /* U+32B4 CIRCLED NUMBER THIRTY NINE [2000] [Unicode3.2] */ - {0x00e38ab5, 0x00a8d4}, /* U+32B5 CIRCLED NUMBER FORTY [2000] [Unicode3.2] */ - {0x00e38ab6, 0x00a8d5}, /* U+32B6 CIRCLED NUMBER FORTY ONE [2000] [Unicode3.2] */ - {0x00e38ab7, 0x00a8d6}, /* U+32B7 CIRCLED NUMBER FORTY TWO [2000] [Unicode3.2] */ - {0x00e38ab8, 0x00a8d7}, /* U+32B8 CIRCLED NUMBER FORTY THREE [2000] [Unicode3.2] */ - {0x00e38ab9, 0x00a8d8}, /* U+32B9 CIRCLED NUMBER FORTY FOUR [2000] [Unicode3.2] */ - {0x00e38aba, 0x00a8d9}, /* U+32BA CIRCLED NUMBER FORTY FIVE [2000] [Unicode3.2] */ - {0x00e38abb, 0x00a8da}, /* U+32BB CIRCLED NUMBER FORTY SIX [2000] [Unicode3.2] */ - {0x00e38abc, 0x00a8db}, /* U+32BC CIRCLED NUMBER FORTY SEVEN [2000] [Unicode3.2] */ - {0x00e38abd, 0x00a8dc}, /* U+32BD CIRCLED NUMBER FORTY EIGHT [2000] [Unicode3.2] */ - {0x00e38abe, 0x00a8dd}, /* U+32BE CIRCLED NUMBER FORTY NINE [2000] [Unicode3.2] */ - {0x00e38abf, 0x00a8de}, /* U+32BF CIRCLED NUMBER FIFTY [2000] [Unicode3.2] */ - {0x00e38b90, 0x00acdb}, /* U+32D0 CIRCLED KATAKANA A [2000] */ - {0x00e38b91, 0x00acdc}, /* U+32D1 CIRCLED KATAKANA I [2000] */ - {0x00e38b92, 0x00acdd}, /* U+32D2 CIRCLED KATAKANA U [2000] */ - {0x00e38b93, 0x00acde}, /* U+32D3 CIRCLED KATAKANA E [2000] */ - {0x00e38b94, 0x00acdf}, /* U+32D4 CIRCLED KATAKANA O [2000] */ - {0x00e38b95, 0x00ace0}, /* U+32D5 CIRCLED KATAKANA KA [2000] */ - {0x00e38b96, 0x00ace1}, /* U+32D6 CIRCLED KATAKANA KI [2000] */ - {0x00e38b97, 0x00ace2}, /* U+32D7 CIRCLED KATAKANA KU [2000] */ - {0x00e38b98, 0x00ace3}, /* U+32D8 CIRCLED KATAKANA KE [2000] */ - {0x00e38b99, 0x00ace4}, /* U+32D9 CIRCLED KATAKANA KO [2000] */ - {0x00e38b9a, 0x00ace5}, /* U+32DA CIRCLED KATAKANA SA [2000] */ - {0x00e38b9b, 0x00ace6}, /* U+32DB CIRCLED KATAKANA SI [2000] */ - {0x00e38b9c, 0x00ace7}, /* U+32DC CIRCLED KATAKANA SU [2000] */ - {0x00e38b9d, 0x00ace8}, /* U+32DD CIRCLED KATAKANA SE [2000] */ - {0x00e38b9e, 0x00ace9}, /* U+32DE CIRCLED KATAKANA SO [2000] */ - {0x00e38b9f, 0x00acea}, /* U+32DF CIRCLED KATAKANA TA [2000] */ - {0x00e38ba0, 0x00aceb}, /* U+32E0 CIRCLED KATAKANA TI [2000] */ - {0x00e38ba1, 0x00acec}, /* U+32E1 CIRCLED KATAKANA TU [2000] */ - {0x00e38ba2, 0x00aced}, /* U+32E2 CIRCLED KATAKANA TE [2000] */ - {0x00e38ba3, 0x00acee}, /* U+32E3 CIRCLED KATAKANA TO [2000] */ - {0x00e38ba5, 0x00acf1}, /* U+32E5 CIRCLED KATAKANA NI [2000] */ - {0x00e38ba9, 0x00acf0}, /* U+32E9 CIRCLED KATAKANA HA [2000] */ - {0x00e38bac, 0x00acf3}, /* U+32EC CIRCLED KATAKANA HE [2000] */ - {0x00e38bad, 0x00acf2}, /* U+32ED CIRCLED KATAKANA HO [2000] */ - {0x00e38bba, 0x00acef}, /* U+32FA CIRCLED KATAKANA RO [2000] */ - {0x00e38c83, 0x00adc6}, /* U+3303 SQUARE AARU [2000] */ - {0x00e38c8d, 0x00adca}, /* U+330D SQUARE KARORII [2000] */ - {0x00e38c94, 0x00adc1}, /* U+3314 SQUARE KIRO [2000] */ - {0x00e38c98, 0x00adc4}, /* U+3318 SQUARE GURAMU [2000] */ - {0x00e38ca2, 0x00adc2}, /* U+3322 SQUARE SENTI [2000] */ - {0x00e38ca3, 0x00adcc}, /* U+3323 SQUARE SENTO [2000] */ - {0x00e38ca6, 0x00adcb}, /* U+3326 SQUARE DORU [2000] */ - {0x00e38ca7, 0x00adc5}, /* U+3327 SQUARE TON [2000] */ - {0x00e38cab, 0x00adcd}, /* U+332B SQUARE PAASENTO [2000] */ - {0x00e38cb6, 0x00adc7}, /* U+3336 SQUARE HEKUTAARU [2000] */ - {0x00e38cbb, 0x00adcf}, /* U+333B SQUARE PEEZI [2000] */ - {0x00e38d89, 0x00adc0}, /* U+3349 SQUARE MIRI [2000] */ - {0x00e38d8a, 0x00adce}, /* U+334A SQUARE MIRIBAARU [2000] */ - {0x00e38d8d, 0x00adc3}, /* U+334D SQUARE MEETORU [2000] */ - {0x00e38d91, 0x00adc8}, /* U+3351 SQUARE RITTORU [2000] */ - {0x00e38d97, 0x00adc9}, /* U+3357 SQUARE WATTO [2000] */ - {0x00e38dbb, 0x00addf}, /* U+337B SQUARE ERA NAME HEISEI [2000] */ - {0x00e38dbc, 0x00adef}, /* U+337C SQUARE ERA NAME SYOUWA [2000] */ - {0x00e38dbd, 0x00adee}, /* U+337D SQUARE ERA NAME TAISYOU [2000] */ - {0x00e38dbe, 0x00aded}, /* U+337E SQUARE ERA NAME MEIZI [2000] */ - {0x00e38e8e, 0x00add3}, /* U+338E SQUARE MG [2000] */ - {0x00e38e8f, 0x00add4}, /* U+338F SQUARE KG [2000] */ - {0x00e38e9c, 0x00add0}, /* U+339C SQUARE MM [2000] */ - {0x00e38e9d, 0x00add1}, /* U+339D SQUARE CM [2000] */ - {0x00e38e9e, 0x00add2}, /* U+339E SQUARE KM [2000] */ - {0x00e38ea1, 0x00add6}, /* U+33A1 SQUARE M SQUARED [2000] */ - {0x00e38f84, 0x00add5}, /* U+33C4 SQUARE CC [2000] */ - {0x00e38f8b, 0x00a3de}, /* U+33CB SQUARE HP [2000] */ - {0x00e38f8d, 0x00ade3}, /* U+33CD SQUARE KK [2000] */ - {0x00e39082, 0x00aea3}, /* U+3402 [2000] */ - {0x00e39086, 0x8fa1ad}, /* U+3406 [2000] */ - {0x00e390ac, 0x8fa1b2}, /* U+342C [2000] */ - {0x00e390ae, 0x8fa1b3}, /* U+342E [2000] */ - {0x00e391a8, 0x8fa1de}, /* U+3468 [2000] */ - {0x00e391aa, 0x8fa1d6}, /* U+346A [2000] */ - {0x00e39292, 0x8fa1fe}, /* U+3492 [2000] */ - {0x00e392b5, 0x00aed3}, /* U+34B5 [2000] */ - {0x00e392bc, 0x8fa3ab}, /* U+34BC [2000] */ - {0x00e39381, 0x8ff4e8}, /* U+34C1 [2000] */ - {0x00e39387, 0x8fa3af}, /* U+34C7 [2000] */ - {0x00e3939b, 0x00aedb}, /* U+34DB [2000] */ - {0x00e3949f, 0x8fa3c8}, /* U+351F [2000] */ - {0x00e3959d, 0x8fa3dd}, /* U+355D [2000] */ - {0x00e3959e, 0x8fa3de}, /* U+355E [2000] */ - {0x00e395a3, 0x8fa3e1}, /* U+3563 [2000] */ - {0x00e395ae, 0x8fa3e7}, /* U+356E [2000] */ - {0x00e396a6, 0x8fa4a3}, /* U+35A6 [2000] */ - {0x00e396a8, 0x8fa4a6}, /* U+35A8 [2000] */ - {0x00e39785, 0x8fa4af}, /* U+35C5 [2000] */ - {0x00e3979a, 0x8fa4b8}, /* U+35DA [2000] */ - {0x00e397b4, 0x8fa4c2}, /* U+35F4 [2000] */ - {0x00e39885, 0x8fa4ca}, /* U+3605 [2000] */ - {0x00e3998a, 0x8fa4f9}, /* U+364A [2000] */ - {0x00e39a91, 0x8fa5bf}, /* U+3691 [2000] */ - {0x00e39a96, 0x8fa5c3}, /* U+3696 [2000] */ - {0x00e39a99, 0x8fa5c1}, /* U+3699 [2000] */ - {0x00e39b8f, 0x8fa5d7}, /* U+36CF [2000] */ - {0x00e39da1, 0x8fa8a3}, /* U+3761 [2000] */ - {0x00e39da2, 0x8fa8a5}, /* U+3762 [2000] */ - {0x00e39dab, 0x8fa8a9}, /* U+376B [2000] */ - {0x00e39dac, 0x8fa8a8}, /* U+376C [2000] */ - {0x00e39db5, 0x8fa8ac}, /* U+3775 [2000] */ - {0x00e39e8d, 0x00cfdf}, /* U+378D [2000] */ - {0x00e39f81, 0x8fa8be}, /* U+37C1 [2000] */ - {0x00e39fa2, 0x00cfef}, /* U+37E2 [2000] */ - {0x00e39fa8, 0x8fa8d6}, /* U+37E8 [2000] */ - {0x00e39fb4, 0x8fa8d9}, /* U+37F4 [2000] */ - {0x00e39fbd, 0x8fa8dc}, /* U+37FD [2000] */ - {0x00e3a080, 0x8fa8de}, /* U+3800 [2000] */ - {0x00e3a0af, 0x8fa8ef}, /* U+382F [2000] */ - {0x00e3a0b6, 0x8fa8f1}, /* U+3836 [2000] */ - {0x00e3a180, 0x8fa8f4}, /* U+3840 [2000] */ - {0x00e3a19c, 0x8fa8f9}, /* U+385C [2000] */ - {0x00e3a1a1, 0x8fa8fb}, /* U+3861 [2000] */ - {0x00e3a3ba, 0x8facbb}, /* U+38FA [2000] */ - {0x00e3a497, 0x8facc6}, /* U+3917 [2000] */ - {0x00e3a49a, 0x8facca}, /* U+391A [2000] */ - {0x00e3a5af, 0x8face0}, /* U+396F [2000] */ - {0x00e3a9ae, 0x8faddb}, /* U+3A6E [2000] */ - {0x00e3a9b3, 0x8faddf}, /* U+3A73 [2000] */ - {0x00e3ab96, 0x8fadf1}, /* U+3AD6 [2000] */ - {0x00e3ab97, 0x8faeb6}, /* U+3AD7 [2000] */ - {0x00e3abaa, 0x8fadfc}, /* U+3AEA [2000] */ - {0x00e3ac8e, 0x8faeae}, /* U+3B0E [2000] */ - {0x00e3ac9a, 0x8faeb2}, /* U+3B1A [2000] */ - {0x00e3ac9c, 0x8faeb4}, /* U+3B1C [2000] */ - {0x00e3aca2, 0x00f5c9}, /* U+3B22 [2000] */ - {0x00e3adad, 0x8faeed}, /* U+3B6D [2000] */ - {0x00e3adb7, 0x8faee5}, /* U+3B77 [2000] */ - {0x00e3ae87, 0x8fafa8}, /* U+3B87 [2000] */ - {0x00e3ae88, 0x8fafa9}, /* U+3B88 [2000] */ - {0x00e3ae8d, 0x8fafac}, /* U+3B8D [2000] */ - {0x00e3aea4, 0x8fafb4}, /* U+3BA4 [2000] */ - {0x00e3aeb6, 0x00f5fe}, /* U+3BB6 [2000] */ - {0x00e3af83, 0x00f6a1}, /* U+3BC3 [2000] */ - {0x00e3af8d, 0x8fafc8}, /* U+3BCD [2000] */ - {0x00e3afb0, 0x8fafdd}, /* U+3BF0 [2000] */ - {0x00e3b08f, 0x00f6ba}, /* U+3C0F [2000] */ - {0x00e3b0a6, 0x8faff7}, /* U+3C26 [2000] */ - {0x00e3b383, 0x8feebb}, /* U+3CC3 [2000] */ - {0x00e3b392, 0x8feec2}, /* U+3CD2 [2000] */ - {0x00e3b491, 0x8feef1}, /* U+3D11 [2000] */ - {0x00e3b49e, 0x8feefe}, /* U+3D1E [2000] */ - {0x00e3b5a4, 0x8fefc0}, /* U+3D64 [2000] */ - {0x00e3b69a, 0x8fefd4}, /* U+3D9A [2000] */ - {0x00e3b780, 0x8feff0}, /* U+3DC0 [2000] */ - {0x00e3b794, 0x8feff7}, /* U+3DD4 [2000] */ - {0x00e3b885, 0x8ff0a8}, /* U+3E05 [2000] */ - {0x00e3b8bf, 0x00f7e6}, /* U+3E3F [2000] */ - {0x00e3b9a0, 0x8ff0bf}, /* U+3E60 [2000] */ - {0x00e3b9a6, 0x8ff0c1}, /* U+3E66 [2000] */ - {0x00e3b9a8, 0x8ff0c2}, /* U+3E68 [2000] */ - {0x00e3ba83, 0x8ff0c9}, /* U+3E83 [2000] */ - {0x00e3ba94, 0x8ff0d0}, /* U+3E94 [2000] */ - {0x00e3bd97, 0x8ff1b4}, /* U+3F57 [2000] */ - {0x00e3bdb2, 0x00f8cd}, /* U+3F72 [2000] */ - {0x00e3bdb5, 0x8ff1c6}, /* U+3F75 [2000] */ - {0x00e3bdb7, 0x8ff1c8}, /* U+3F77 [2000] */ - {0x00e3beae, 0x8ff1dc}, /* U+3FAE [2000] */ - {0x00e3bf89, 0x8ff1e7}, /* U+3FC9 [2000] */ - {0x00e3bf97, 0x8ff1ec}, /* U+3FD7 [2000] */ - {0x00e480b9, 0x8ff2a2}, /* U+4039 [2000] */ - {0x00e48198, 0x8ff2ad}, /* U+4058 [2000] */ - {0x00e48293, 0x8ff2b9}, /* U+4093 [2000] */ - {0x00e48485, 0x8ff2e4}, /* U+4105 [2000] */ - {0x00e48588, 0x8ff2f4}, /* U+4148 [2000] */ - {0x00e4858f, 0x8ff2f7}, /* U+414F [2000] */ - {0x00e485a3, 0x8ff2fd}, /* U+4163 [2000] */ - {0x00e486b4, 0x8ff3b3}, /* U+41B4 [2000] */ - {0x00e486bf, 0x8ff3b7}, /* U+41BF [2000] */ - {0x00e487a6, 0x8ff3c7}, /* U+41E6 [2000] */ - {0x00e487ae, 0x8ff3cb}, /* U+41EE [2000] */ - {0x00e487b3, 0x8ff3c8}, /* U+41F3 [2000] */ - {0x00e48887, 0x8ff3d3}, /* U+4207 [2000] */ - {0x00e4888e, 0x8ff3d7}, /* U+420E [2000] */ - {0x00e489a4, 0x00f9ed}, /* U+4264 [2000] */ - {0x00e48b86, 0x8ff4ab}, /* U+42C6 [2000] */ - {0x00e48b96, 0x8ff4b6}, /* U+42D6 [2000] */ - {0x00e48b9d, 0x8ff4bb}, /* U+42DD [2000] */ - {0x00e48c82, 0x8ff4ce}, /* U+4302 [2000] */ - {0x00e48cab, 0x8ff4dd}, /* U+432B [2000] */ - {0x00e48d83, 0x8ff4e1}, /* U+4343 [2000] */ - {0x00e48fae, 0x8ff5be}, /* U+43EE [2000] */ - {0x00e48fb0, 0x8ff5c2}, /* U+43F0 [2000] */ - {0x00e49088, 0x8ff5c8}, /* U+4408 [2000] */ - {0x00e49097, 0x8ff5ca}, /* U+4417 [2000] */ - {0x00e4909c, 0x8ff5cc}, /* U+441C [2000] */ - {0x00e490a2, 0x8ff5cf}, /* U+4422 [2000] */ - {0x00e49193, 0x00fad9}, /* U+4453 [2000] */ - {0x00e4919b, 0x00fada}, /* U+445B [2000] */ - {0x00e491b6, 0x8ff5ec}, /* U+4476 [2000] */ - {0x00e491ba, 0x8ff5ee}, /* U+447A [2000] */ - {0x00e49291, 0x8ff5f7}, /* U+4491 [2000] */ - {0x00e492b3, 0x8ff6b5}, /* U+44B3 [2000] */ - {0x00e492be, 0x8ff6b2}, /* U+44BE [2000] */ - {0x00e49394, 0x8ff6b4}, /* U+44D4 [2000] */ - {0x00e49488, 0x8ff6d9}, /* U+4508 [2000] */ - {0x00e4948d, 0x8ff6d4}, /* U+450D [2000] */ - {0x00e494a5, 0x8ff6ed}, /* U+4525 [2000] */ - {0x00e49583, 0x8ff6ee}, /* U+4543 [2000] */ - {0x00e4969d, 0x00fbd1}, /* U+459D [2000] */ - {0x00e496b8, 0x8ff7cf}, /* U+45B8 [2000] */ - {0x00e497a5, 0x8ff7ec}, /* U+45E5 [2000] */ - {0x00e497aa, 0x00fbe0}, /* U+45EA [2000] */ - {0x00e4988f, 0x8ff8a4}, /* U+460F [2000] */ - {0x00e49981, 0x8ff8ba}, /* U+4641 [2000] */ - {0x00e499a5, 0x8ff8c3}, /* U+4665 [2000] */ - {0x00e49aa1, 0x8ff8ce}, /* U+46A1 [2000] */ - {0x00e49aaf, 0x8ff8d3}, /* U+46AF [2000] */ - {0x00e49c8c, 0x8ff8eb}, /* U+470C [2000] */ - {0x00e49da4, 0x8ff9a9}, /* U+4764 [2000] */ - {0x00e49fbd, 0x8ff9bf}, /* U+47FD [2000] */ - {0x00e4a096, 0x8ff9c9}, /* U+4816 [2000] */ - {0x00e4a184, 0x00fccb}, /* U+4844 [2000] */ - {0x00e4a18e, 0x8ff9dc}, /* U+484E [2000] */ - {0x00e4a2b5, 0x8ffaa7}, /* U+48B5 [2000] */ - {0x00e4a6b0, 0x00fdd8}, /* U+49B0 [2000] */ - {0x00e4a7a7, 0x8ffbea}, /* U+49E7 [2000] */ - {0x00e4a7ba, 0x8ffbf0}, /* U+49FA [2000] */ - {0x00e4a884, 0x8ffbf5}, /* U+4A04 [2000] */ - {0x00e4a8a9, 0x8ffbf8}, /* U+4A29 [2000] */ - {0x00e4aabc, 0x8ffcb7}, /* U+4ABC [2000] */ - {0x00e4acbb, 0x8ffcd5}, /* U+4B3B [2000] */ - {0x00e4af82, 0x8ffda6}, /* U+4BC2 [2000] */ - {0x00e4af8a, 0x8ffda8}, /* U+4BCA [2000] */ - {0x00e4af92, 0x8ffdaa}, /* U+4BD2 [2000] */ - {0x00e4afa8, 0x8ffdb1}, /* U+4BE8 [2000] */ - {0x00e4b097, 0x00febe}, /* U+4C17 [2000] */ - {0x00e4b0a0, 0x8ffdbf}, /* U+4C20 [2000] */ - {0x00e4b384, 0x8ffeaa}, /* U+4CC4 [2000] */ - {0x00e4b391, 0x8ffead}, /* U+4CD1 [2000] */ - {0x00e4b487, 0x8ffecb}, /* U+4D07 [2000] */ - {0x00e4b5b7, 0x8ffee0}, /* U+4D77 [2000] */ - {0x00e4b880, 0x00b0ec}, /* U+4E00 */ - {0x00e4b881, 0x00c3fa}, /* U+4E01 */ - {0x00e4b882, 0x8fa1a2}, /* U+4E02 [2000] */ - {0x00e4b883, 0x00bcb7}, /* U+4E03 */ - {0x00e4b887, 0x00cbfc}, /* U+4E07 */ - {0x00e4b888, 0x00bee6}, /* U+4E08 */ - {0x00e4b889, 0x00bbb0}, /* U+4E09 */ - {0x00e4b88a, 0x00bee5}, /* U+4E0A */ - {0x00e4b88b, 0x00b2bc}, /* U+4E0B */ - {0x00e4b88d, 0x00c9d4}, /* U+4E0D */ - {0x00e4b88e, 0x00cdbf}, /* U+4E0E */ - {0x00e4b88f, 0x8fa1a3}, /* U+4E0F [2000] */ - {0x00e4b890, 0x00d0a2}, /* U+4E10 */ - {0x00e4b891, 0x00b1af}, /* U+4E11 */ - {0x00e4b892, 0x8fa1a4}, /* U+4E12 [2000] */ - {0x00e4b894, 0x00b3ee}, /* U+4E14 */ - {0x00e4b895, 0x00d0a3}, /* U+4E15 */ - {0x00e4b896, 0x00c0a4}, /* U+4E16 */ - {0x00e4b897, 0x00d2c2}, /* U+4E17 */ - {0x00e4b898, 0x00b5d6}, /* U+4E18 */ - {0x00e4b899, 0x00caba}, /* U+4E19 */ - {0x00e4b89e, 0x00bee7}, /* U+4E1E */ - {0x00e4b8a1, 0x00cebe}, /* U+4E21 */ - {0x00e4b8a6, 0x00cac2}, /* U+4E26 */ - {0x00e4b8a8, 0x00aea4}, /* U+4E28 [2000] */ - {0x00e4b8a9, 0x8fa1a5}, /* U+4E29 [2000] */ - {0x00e4b8aa, 0x00d0a4}, /* U+4E2A */ - {0x00e4b8ab, 0x8fa1a6}, /* U+4E2B [2000] */ - {0x00e4b8ac, 0x8ff0ae}, /* U+4E2C [2000] */ - {0x00e4b8ad, 0x00c3e6}, /* U+4E2D */ - {0x00e4b8ae, 0x8fa1a7}, /* U+4E2E [2000] */ - {0x00e4b8af, 0x00aea5}, /* U+4E2F [2000] */ - {0x00e4b8b0, 0x00aea6}, /* U+4E30 [2000] */ - {0x00e4b8b1, 0x00d0a5}, /* U+4E31 */ - {0x00e4b8b2, 0x00b6fa}, /* U+4E32 */ - {0x00e4b8b6, 0x00d0a6}, /* U+4E36 */ - {0x00e4b8b8, 0x00b4dd}, /* U+4E38 */ - {0x00e4b8b9, 0x00c3b0}, /* U+4E39 */ - {0x00e4b8bb, 0x00bce7}, /* U+4E3B */ - {0x00e4b8bc, 0x00d0a7}, /* U+4E3C */ - {0x00e4b8bf, 0x00d0a8}, /* U+4E3F */ - {0x00e4b980, 0x8fa1a8}, /* U+4E40 [2000] */ - {0x00e4b982, 0x00d0a9}, /* U+4E42 */ - {0x00e4b983, 0x00c7b5}, /* U+4E43 */ - {0x00e4b985, 0x00b5d7}, /* U+4E45 */ - {0x00e4b987, 0x8fa1a9}, /* U+4E47 [2000] */ - {0x00e4b988, 0x8fa1aa}, /* U+4E48 [2000] */ - {0x00e4b98b, 0x00c7b7}, /* U+4E4B */ - {0x00e4b98d, 0x00c6e3}, /* U+4E4D */ - {0x00e4b98e, 0x00b8c3}, /* U+4E4E */ - {0x00e4b98f, 0x00cbb3}, /* U+4E4F */ - {0x00e4b991, 0x8fa1ac}, /* U+4E51 [2000] */ - {0x00e4b995, 0x00e9c9}, /* U+4E55 */ - {0x00e4b996, 0x00d0aa}, /* U+4E56 */ - {0x00e4b997, 0x00bee8}, /* U+4E57 */ - {0x00e4b998, 0x00d0ab}, /* U+4E58 */ - {0x00e4b999, 0x00b2b5}, /* U+4E59 */ - {0x00e4b99a, 0x8fa1af}, /* U+4E5A [2000] */ - {0x00e4b99d, 0x00b6e5}, /* U+4E5D */ - {0x00e4b99e, 0x00b8f0}, /* U+4E5E */ - {0x00e4b99f, 0x00cce9}, /* U+4E5F */ - {0x00e4b9a2, 0x00d6a6}, /* U+4E62 */ - {0x00e4b9a9, 0x8fa1b0}, /* U+4E69 [2000] */ - {0x00e4b9b1, 0x00cdf0}, /* U+4E71 */ - {0x00e4b9b3, 0x00c6fd}, /* U+4E73 */ - {0x00e4b9be, 0x00b4a5}, /* U+4E7E */ - {0x00e4ba80, 0x00b5b5}, /* U+4E80 */ - {0x00e4ba82, 0x00d0ac}, /* U+4E82 */ - {0x00e4ba85, 0x00d0ad}, /* U+4E85 */ - {0x00e4ba86, 0x00cebb}, /* U+4E86 */ - {0x00e4ba88, 0x00cdbd}, /* U+4E88 */ - {0x00e4ba89, 0x00c1e8}, /* U+4E89 */ - {0x00e4ba8a, 0x00d0af}, /* U+4E8A */ - {0x00e4ba8b, 0x00bbf6}, /* U+4E8B */ - {0x00e4ba8c, 0x00c6f3}, /* U+4E8C */ - {0x00e4ba8d, 0x00aea7}, /* U+4E8D [2000] */ - {0x00e4ba8e, 0x00d0b2}, /* U+4E8E */ - {0x00e4ba91, 0x00b1be}, /* U+4E91 */ - {0x00e4ba92, 0x00b8df}, /* U+4E92 */ - {0x00e4ba94, 0x00b8de}, /* U+4E94 */ - {0x00e4ba95, 0x00b0e6}, /* U+4E95 */ - {0x00e4ba98, 0x00cfcb}, /* U+4E98 */ - {0x00e4ba99, 0x00cfca}, /* U+4E99 */ - {0x00e4ba9b, 0x00bab3}, /* U+4E9B */ - {0x00e4ba9c, 0x00b0a1}, /* U+4E9C */ - {0x00e4ba9d, 0x8fa1b1}, /* U+4E9D [2000] */ - {0x00e4ba9e, 0x00d0b3}, /* U+4E9E */ - {0x00e4ba9f, 0x00d0b4}, /* U+4E9F */ - {0x00e4baa0, 0x00d0b5}, /* U+4EA0 */ - {0x00e4baa1, 0x00cbb4}, /* U+4EA1 */ - {0x00e4baa2, 0x00d0b6}, /* U+4EA2 */ - {0x00e4baa4, 0x00b8f2}, /* U+4EA4 */ - {0x00e4baa5, 0x00b0e7}, /* U+4EA5 */ - {0x00e4baa6, 0x00cbf2}, /* U+4EA6 */ - {0x00e4baa8, 0x00b5fc}, /* U+4EA8 */ - {0x00e4baab, 0x00b5fd}, /* U+4EAB */ - {0x00e4baac, 0x00b5fe}, /* U+4EAC */ - {0x00e4baad, 0x00c4e2}, /* U+4EAD */ - {0x00e4baae, 0x00cebc}, /* U+4EAE */ - {0x00e4bab0, 0x00d0b7}, /* U+4EB0 */ - {0x00e4bab3, 0x00d0b8}, /* U+4EB3 */ - {0x00e4bab6, 0x00d0b9}, /* U+4EB6 */ - {0x00e4bab9, 0x8fa1b4}, /* U+4EB9 [2000] */ - {0x00e4baba, 0x00bfcd}, /* U+4EBA */ - {0x00e4babb, 0x8fa1b5}, /* U+4EBB [2000] */ - {0x00e4babc, 0x8fa1b7}, /* U+4EBC [2000] */ - {0x00e4bb80, 0x00bdba}, /* U+4EC0 */ - {0x00e4bb81, 0x00bfce}, /* U+4EC1 */ - {0x00e4bb82, 0x00d0be}, /* U+4EC2 */ - {0x00e4bb83, 0x8fa1b8}, /* U+4EC3 [2000] */ - {0x00e4bb84, 0x00d0bc}, /* U+4EC4 */ - {0x00e4bb86, 0x00d0bd}, /* U+4EC6 */ - {0x00e4bb87, 0x00b5d8}, /* U+4EC7 */ - {0x00e4bb88, 0x8fa1b9}, /* U+4EC8 [2000] */ - {0x00e4bb8a, 0x00baa3}, /* U+4ECA */ - {0x00e4bb8b, 0x00b2f0}, /* U+4ECB */ - {0x00e4bb8d, 0x00d0bb}, /* U+4ECD */ - {0x00e4bb8e, 0x00d0ba}, /* U+4ECE */ - {0x00e4bb8f, 0x00caa9}, /* U+4ECF */ - {0x00e4bb90, 0x8fa1ba}, /* U+4ED0 [2000] */ - {0x00e4bb94, 0x00bbc6}, /* U+4ED4 */ - {0x00e4bb95, 0x00bbc5}, /* U+4ED5 */ - {0x00e4bb96, 0x00c2be}, /* U+4ED6 */ - {0x00e4bb97, 0x00d0bf}, /* U+4ED7 */ - {0x00e4bb98, 0x00c9d5}, /* U+4ED8 */ - {0x00e4bb99, 0x00c0e7}, /* U+4ED9 */ - {0x00e4bb9a, 0x8fa1bc}, /* U+4EDA [2000] */ - {0x00e4bb9d, 0x00a1b8}, /* U+4EDD */ - {0x00e4bb9e, 0x00d0c0}, /* U+4EDE */ - {0x00e4bb9f, 0x00d0c2}, /* U+4EDF */ - {0x00e4bba1, 0x00aea8}, /* U+4EE1 [2000] */ - {0x00e4bba3, 0x00c2e5}, /* U+4EE3 */ - {0x00e4bba4, 0x00cee1}, /* U+4EE4 */ - {0x00e4bba5, 0x00b0ca}, /* U+4EE5 */ - {0x00e4bbab, 0x8fa1bb}, /* U+4EEB [2000] */ - {0x00e4bbad, 0x00d0c1}, /* U+4EED */ - {0x00e4bbae, 0x00b2be}, /* U+4EEE */ - {0x00e4bbb0, 0x00b6c4}, /* U+4EF0 */ - {0x00e4bbb1, 0x8fa1bd}, /* U+4EF1 [2000] */ - {0x00e4bbb2, 0x00c3e7}, /* U+4EF2 */ - {0x00e4bbb5, 0x8fa1be}, /* U+4EF5 [2000] */ - {0x00e4bbb6, 0x00b7ef}, /* U+4EF6 */ - {0x00e4bbb7, 0x00d0c3}, /* U+4EF7 */ - {0x00e4bbbb, 0x00c7a4}, /* U+4EFB */ - {0x00e4bbbd, 0x00aea9}, /* U+4EFD [2000] */ - {0x00e4bbbf, 0x00aeaa}, /* U+4EFF [2000] */ - {0x00e4bc80, 0x8fa1bf}, /* U+4F00 [2000] */ - {0x00e4bc81, 0x00b4eb}, /* U+4F01 */ - {0x00e4bc83, 0x00aeab}, /* U+4F03 [2000] */ - {0x00e4bc89, 0x00d0c4}, /* U+4F09 */ - {0x00e4bc8a, 0x00b0cb}, /* U+4F0A */ - {0x00e4bc8b, 0x00aeac}, /* U+4F0B [2000] */ - {0x00e4bc8d, 0x00b8e0}, /* U+4F0D */ - {0x00e4bc8e, 0x00b4ec}, /* U+4F0E */ - {0x00e4bc8f, 0x00c9fa}, /* U+4F0F */ - {0x00e4bc90, 0x00c8b2}, /* U+4F10 */ - {0x00e4bc91, 0x00b5d9}, /* U+4F11 */ - {0x00e4bc96, 0x8fa1c0}, /* U+4F16 [2000] */ - {0x00e4bc9a, 0x00b2f1}, /* U+4F1A */ - {0x00e4bc9c, 0x00d0e7}, /* U+4F1C */ - {0x00e4bc9d, 0x00c5c1}, /* U+4F1D */ - {0x00e4bcaf, 0x00c7ec}, /* U+4F2F */ - {0x00e4bcb0, 0x00d0c6}, /* U+4F30 */ - {0x00e4bcb4, 0x00c8bc}, /* U+4F34 */ - {0x00e4bcb6, 0x00cee2}, /* U+4F36 */ - {0x00e4bcb7, 0x8fa1c2}, /* U+4F37 [2000] */ - {0x00e4bcb8, 0x00bfad}, /* U+4F38 */ - {0x00e4bcba, 0x00bbc7}, /* U+4F3A */ - {0x00e4bcbc, 0x00bbf7}, /* U+4F3C */ - {0x00e4bcbd, 0x00b2c0}, /* U+4F3D */ - {0x00e4bcbe, 0x8fa1c3}, /* U+4F3E [2000] */ - {0x00e4bd83, 0x00c4d1}, /* U+4F43 */ - {0x00e4bd86, 0x00c3a2}, /* U+4F46 */ - {0x00e4bd87, 0x00d0ca}, /* U+4F47 */ - {0x00e4bd88, 0x00aeae}, /* U+4F48 [2000] */ - {0x00e4bd89, 0x00aeaf}, /* U+4F49 [2000] */ - {0x00e4bd8d, 0x00b0cc}, /* U+4F4D */ - {0x00e4bd8e, 0x00c4e3}, /* U+4F4E */ - {0x00e4bd8f, 0x00bdbb}, /* U+4F4F */ - {0x00e4bd90, 0x00bab4}, /* U+4F50 */ - {0x00e4bd91, 0x00cda4}, /* U+4F51 */ - {0x00e4bd93, 0x00c2ce}, /* U+4F53 */ - {0x00e4bd94, 0x8fa1c4}, /* U+4F54 [2000] */ - {0x00e4bd95, 0x00b2bf}, /* U+4F55 */ - {0x00e4bd96, 0x00aeb0}, /* U+4F56 [2000] */ - {0x00e4bd97, 0x00d0c9}, /* U+4F57 */ - {0x00e4bd98, 0x8fa1c5}, /* U+4F58 [2000] */ - {0x00e4bd99, 0x00cdbe}, /* U+4F59 */ - {0x00e4bd9a, 0x00d0c5}, /* U+4F5A */ - {0x00e4bd9b, 0x00d0c7}, /* U+4F5B */ - {0x00e4bd9c, 0x00baee}, /* U+4F5C */ - {0x00e4bd9d, 0x00d0c8}, /* U+4F5D */ - {0x00e4bd9e, 0x00d5a4}, /* U+4F5E */ - {0x00e4bd9f, 0x00aeb1}, /* U+4F5F [2000] */ - {0x00e4bda0, 0x00aead}, /* U+4F60 [2000] */ - {0x00e4bda4, 0x8fa1c1}, /* U+4F64 [2000] */ - {0x00e4bda9, 0x00d0d0}, /* U+4F69 */ - {0x00e4bdaa, 0x00aeb2}, /* U+4F6A [2000] */ - {0x00e4bdac, 0x00aeb3}, /* U+4F6C [2000] */ - {0x00e4bdaf, 0x00d0d3}, /* U+4F6F */ - {0x00e4bdb0, 0x00d0d1}, /* U+4F70 */ - {0x00e4bdb3, 0x00b2c2}, /* U+4F73 */ - {0x00e4bdb5, 0x00cabb}, /* U+4F75 */ - {0x00e4bdb6, 0x00d0cb}, /* U+4F76 */ - {0x00e4bdb7, 0x8fa1c7}, /* U+4F77 [2000] */ - {0x00e4bdb8, 0x8fa1c8}, /* U+4F78 [2000] */ - {0x00e4bdba, 0x8fa1c9}, /* U+4F7A [2000] */ - {0x00e4bdbb, 0x00d0cf}, /* U+4F7B */ - {0x00e4bdbc, 0x00b8f3}, /* U+4F7C */ - {0x00e4bdbd, 0x8fa1ca}, /* U+4F7D [2000] */ - {0x00e4bdbe, 0x00aeb4}, /* U+4F7E [2000] */ - {0x00e4bdbf, 0x00bbc8}, /* U+4F7F */ - {0x00e4be82, 0x8fa1cb}, /* U+4F82 [2000] */ - {0x00e4be83, 0x00b4a6}, /* U+4F83 */ - {0x00e4be85, 0x8fa1cc}, /* U+4F85 [2000] */ - {0x00e4be86, 0x00d0d4}, /* U+4F86 */ - {0x00e4be88, 0x00d0cc}, /* U+4F88 */ - {0x00e4be8a, 0x00aeb5}, /* U+4F8A [2000] */ - {0x00e4be8b, 0x00cee3}, /* U+4F8B */ - {0x00e4be8d, 0x00bbf8}, /* U+4F8D */ - {0x00e4be8f, 0x00d0cd}, /* U+4F8F */ - {0x00e4be91, 0x00d0d2}, /* U+4F91 */ - {0x00e4be92, 0x8fa1cd}, /* U+4F92 [2000] */ - {0x00e4be94, 0x00aeb6}, /* U+4F94 [2000] */ - {0x00e4be96, 0x00d0d5}, /* U+4F96 */ - {0x00e4be97, 0x00aeb7}, /* U+4F97 [2000] */ - {0x00e4be98, 0x00d0ce}, /* U+4F98 */ - {0x00e4be9a, 0x8fa1ce}, /* U+4F9A [2000] */ - {0x00e4be9b, 0x00b6a1}, /* U+4F9B */ - {0x00e4be9d, 0x00b0cd}, /* U+4F9D */ - {0x00e4bea0, 0x00b6a2}, /* U+4FA0 */ - {0x00e4bea1, 0x00b2c1}, /* U+4FA1 */ - {0x00e4beab, 0x00d5a5}, /* U+4FAB */ - {0x00e4bead, 0x00cbf9}, /* U+4FAD */ - {0x00e4beae, 0x00c9ee}, /* U+4FAE */ - {0x00e4beaf, 0x00b8f4}, /* U+4FAF */ - {0x00e4beb2, 0x8fa1d0}, /* U+4FB2 [2000] */ - {0x00e4beb5, 0x00bfaf}, /* U+4FB5 */ - {0x00e4beb6, 0x00ceb7}, /* U+4FB6 */ - {0x00e4bebe, 0x8fa1d1}, /* U+4FBE [2000] */ - {0x00e4bebf, 0x00cad8}, /* U+4FBF */ - {0x00e4bf82, 0x00b7b8}, /* U+4FC2 */ - {0x00e4bf83, 0x00c2a5}, /* U+4FC3 */ - {0x00e4bf84, 0x00b2e4}, /* U+4FC4 */ - {0x00e4bf85, 0x8fa1d2}, /* U+4FC5 [2000] */ - {0x00e4bf89, 0x00aeb9}, /* U+4FC9 [2000] */ - {0x00e4bf8a, 0x00bdd3}, /* U+4FCA */ - {0x00e4bf8b, 0x8fa1d3}, /* U+4FCB [2000] */ - {0x00e4bf8e, 0x00d0d9}, /* U+4FCE */ - {0x00e4bf8f, 0x8fa1d4}, /* U+4FCF [2000] */ - {0x00e4bf90, 0x00d0de}, /* U+4FD0 */ - {0x00e4bf91, 0x00d0dc}, /* U+4FD1 */ - {0x00e4bf92, 0x8fa1d5}, /* U+4FD2 [2000] */ - {0x00e4bf94, 0x00d0d7}, /* U+4FD4 */ - {0x00e4bf97, 0x00c2af}, /* U+4FD7 */ - {0x00e4bf98, 0x00d0da}, /* U+4FD8 */ - {0x00e4bf9a, 0x00d0dd}, /* U+4FDA */ - {0x00e4bf9b, 0x00d0db}, /* U+4FDB */ - {0x00e4bf9d, 0x00cadd}, /* U+4FDD */ - {0x00e4bf9f, 0x00d0d8}, /* U+4FDF */ - {0x00e4bfa0, 0x00aeba}, /* U+4FE0 [2000] */ - {0x00e4bfa1, 0x00bfae}, /* U+4FE1 */ - {0x00e4bfa3, 0x00cbf3}, /* U+4FE3 */ - {0x00e4bfa4, 0x00d0df}, /* U+4FE4 */ - {0x00e4bfa5, 0x00d0e0}, /* U+4FE5 */ - {0x00e4bfa6, 0x8fa1cf}, /* U+4FE6 [2000] */ - {0x00e4bfae, 0x00bda4}, /* U+4FEE */ - {0x00e4bfaf, 0x00d0ed}, /* U+4FEF */ - {0x00e4bfb1, 0x00aea1}, /* U+4FF1 [2004] */ - {0x00e4bfb2, 0x8fa1d7}, /* U+4FF2 [2000] */ - {0x00e4bfb3, 0x00c7d0}, /* U+4FF3 */ - {0x00e4bfb5, 0x00c9b6}, /* U+4FF5 */ - {0x00e4bfb6, 0x00d0e8}, /* U+4FF6 */ - {0x00e4bfb8, 0x00caf0}, /* U+4FF8 */ - {0x00e4bfba, 0x00b2b6}, /* U+4FFA */ - {0x00e4bfbe, 0x00d0ec}, /* U+4FFE */ - {0x00e58080, 0x8fa1d8}, /* U+5000 [2000] */ - {0x00e58081, 0x00aebb}, /* U+5001 [2000] */ - {0x00e58082, 0x00aebc}, /* U+5002 [2000] */ - {0x00e58085, 0x00d0e6}, /* U+5005 */ - {0x00e58086, 0x00d0ef}, /* U+5006 */ - {0x00e58089, 0x00c1d2}, /* U+5009 */ - {0x00e5808b, 0x00b8c4}, /* U+500B */ - {0x00e5808d, 0x00c7dc}, /* U+500D */ - {0x00e5808e, 0x00aebd}, /* U+500E [2000] */ - {0x00e5808f, 0x00e0c7}, /* U+500F */ - {0x00e58090, 0x8fa1d9}, /* U+5010 [2000] */ - {0x00e58091, 0x00d0ee}, /* U+5011 */ - {0x00e58092, 0x00c5dd}, /* U+5012 */ - {0x00e58093, 0x8fa1da}, /* U+5013 [2000] */ - {0x00e58094, 0x00d0e3}, /* U+5014 */ - {0x00e58096, 0x00b8f6}, /* U+5016 */ - {0x00e58098, 0x00aebe}, /* U+5018 [2000] */ - {0x00e58099, 0x00b8f5}, /* U+5019 */ - {0x00e5809a, 0x00d0e1}, /* U+501A */ - {0x00e5809c, 0x8fa1db}, /* U+501C [2000] */ - {0x00e5809e, 0x8fa1dc}, /* U+501E [2000] */ - {0x00e5809f, 0x00bcda}, /* U+501F */ - {0x00e580a1, 0x00d0e9}, /* U+5021 */ - {0x00e580a2, 0x8fa1dd}, /* U+5022 [2000] */ - {0x00e580a3, 0x00caef}, /* U+5023 */ - {0x00e580a4, 0x00c3cd}, /* U+5024 */ - {0x00e580a5, 0x00d0e5}, /* U+5025 */ - {0x00e580a6, 0x00b7f1}, /* U+5026 */ - {0x00e580a7, 0x00aebf}, /* U+5027 [2000] */ - {0x00e580a8, 0x00d0e2}, /* U+5028 */ - {0x00e580a9, 0x00d0ea}, /* U+5029 */ - {0x00e580aa, 0x00d0e4}, /* U+502A */ - {0x00e580ab, 0x00ced1}, /* U+502B */ - {0x00e580ac, 0x00d0eb}, /* U+502C */ - {0x00e580ad, 0x00cfc1}, /* U+502D */ - {0x00e580ae, 0x00aec0}, /* U+502E [2000] */ - {0x00e580b6, 0x00b6e6}, /* U+5036 */ - {0x00e580b9, 0x00b7f0}, /* U+5039 */ - {0x00e580bb, 0x00aec2}, /* U+503B [2000] */ - {0x00e58180, 0x00aec1}, /* U+5040 [2000] */ - {0x00e58181, 0x00aec3}, /* U+5041 [2000] */ - {0x00e58182, 0x8fa1df}, /* U+5042 [2000] */ - {0x00e58183, 0x00d0f0}, /* U+5043 */ - {0x00e58186, 0x8fa1e0}, /* U+5046 [2000] */ - {0x00e58187, 0x00d0f1}, /* U+5047 */ - {0x00e58188, 0x00d0f5}, /* U+5048 */ - {0x00e58189, 0x00b0ce}, /* U+5049 */ - {0x00e5818e, 0x8fa1e1}, /* U+504E [2000] */ - {0x00e5818f, 0x00cad0}, /* U+504F */ - {0x00e58190, 0x00d0f4}, /* U+5050 */ - {0x00e58193, 0x8fa1e2}, /* U+5053 [2000] */ - {0x00e58195, 0x00d0f3}, /* U+5055 */ - {0x00e58196, 0x00d0f7}, /* U+5056 */ - {0x00e58197, 0x8fa1e3}, /* U+5057 [2000] */ - {0x00e5819a, 0x00d0f6}, /* U+505A */ - {0x00e5819c, 0x00c4e4}, /* U+505C */ - {0x00e581a3, 0x8fa1e4}, /* U+5063 [2000] */ - {0x00e581a5, 0x00b7f2}, /* U+5065 */ - {0x00e581a6, 0x8fa1e5}, /* U+5066 [2000] */ - {0x00e581aa, 0x8fa1e6}, /* U+506A [2000] */ - {0x00e581ac, 0x00d0f8}, /* U+506C */ - {0x00e581b0, 0x8fa1e7}, /* U+5070 [2000] */ - {0x00e581b2, 0x00bcc5}, /* U+5072 */ - {0x00e581b4, 0x00c2a6}, /* U+5074 */ - {0x00e581b5, 0x00c4e5}, /* U+5075 */ - {0x00e581b6, 0x00b6f6}, /* U+5076 */ - {0x00e581b8, 0x00d0f9}, /* U+5078 */ - {0x00e581bd, 0x00b5b6}, /* U+507D */ - {0x00e58280, 0x00d0fa}, /* U+5080 */ - {0x00e58285, 0x00d0fc}, /* U+5085 */ - {0x00e58288, 0x8fa1e9}, /* U+5088 [2000] */ - {0x00e5828d, 0x00cbb5}, /* U+508D */ - {0x00e58291, 0x00b7e6}, /* U+5091 */ - {0x00e58292, 0x8fa1ea}, /* U+5092 [2000] */ - {0x00e58293, 0x8fa1eb}, /* U+5093 [2000] */ - {0x00e58294, 0x00aec4}, /* U+5094 [2000] */ - {0x00e58295, 0x8fa1ec}, /* U+5095 [2000] */ - {0x00e58296, 0x8fa1ed}, /* U+5096 [2000] */ - {0x00e58298, 0x00bbb1}, /* U+5098 */ - {0x00e58299, 0x00c8f7}, /* U+5099 */ - {0x00e5829a, 0x00d0fb}, /* U+509A */ - {0x00e5829c, 0x8fa1ee}, /* U+509C [2000] */ - {0x00e582a3, 0x8fa1e8}, /* U+50A3 [2000] */ - {0x00e582aa, 0x8fa1ef}, /* U+50AA [2000] */ - {0x00e582ac, 0x00bac5}, /* U+50AC */ - {0x00e582ad, 0x00cdc3}, /* U+50AD */ - {0x00e582b1, 0x8fa1f1}, /* U+50B1 [2000] */ - {0x00e582b2, 0x00d0fe}, /* U+50B2 */ - {0x00e582b3, 0x00d1a3}, /* U+50B3 */ - {0x00e582b4, 0x00d0fd}, /* U+50B4 */ - {0x00e582b5, 0x00bac4}, /* U+50B5 */ - {0x00e582b7, 0x00bdfd}, /* U+50B7 */ - {0x00e582ba, 0x8fa1f2}, /* U+50BA [2000] */ - {0x00e582bb, 0x8fa1f3}, /* U+50BB [2000] */ - {0x00e582be, 0x00b7b9}, /* U+50BE */ - {0x00e58382, 0x00d1a4}, /* U+50C2 */ - {0x00e58384, 0x8fa1f4}, /* U+50C4 [2000] */ - {0x00e58385, 0x00b6cf}, /* U+50C5 */ - {0x00e58387, 0x8fa1f5}, /* U+50C7 [2000] */ - {0x00e58389, 0x00d1a1}, /* U+50C9 */ - {0x00e5838a, 0x00d1a2}, /* U+50CA */ - {0x00e5838c, 0x00aec5}, /* U+50CC [2000] */ - {0x00e5838d, 0x00c6af}, /* U+50CD */ - {0x00e5838e, 0x8fa1f8}, /* U+50CE [2000] */ - {0x00e5838f, 0x00c1fc}, /* U+50CF */ - {0x00e58390, 0x00aec7}, /* U+50D0 [2000] */ - {0x00e58391, 0x00b6a3}, /* U+50D1 */ - {0x00e58394, 0x8fa1fa}, /* U+50D4 [2000] */ - {0x00e58395, 0x00cbcd}, /* U+50D5 */ - {0x00e58396, 0x00d1a5}, /* U+50D6 */ - {0x00e58399, 0x8fa1fb}, /* U+50D9 [2000] */ - {0x00e5839a, 0x00cebd}, /* U+50DA */ - {0x00e5839e, 0x00d1a6}, /* U+50DE */ - {0x00e583a1, 0x8fa1fc}, /* U+50E1 [2000] */ - {0x00e583a3, 0x00d1a9}, /* U+50E3 */ - {0x00e583a5, 0x00d1a7}, /* U+50E5 */ - {0x00e583a6, 0x00aec8}, /* U+50E6 [2000] */ - {0x00e583a7, 0x00c1ce}, /* U+50E7 */ - {0x00e583a9, 0x8fa1fd}, /* U+50E9 [2000] */ - {0x00e583ad, 0x00d1a8}, /* U+50ED */ - {0x00e583ae, 0x00d1aa}, /* U+50EE */ - {0x00e583b2, 0x00aec6}, /* U+50F2 [2000] */ - {0x00e583b3, 0x8fa1f6}, /* U+50F3 [2000] */ - {0x00e583b5, 0x00d1ac}, /* U+50F5 */ - {0x00e583b9, 0x00d1ab}, /* U+50F9 */ - {0x00e583bb, 0x00cac8}, /* U+50FB */ - {0x00e58480, 0x00b5b7}, /* U+5100 */ - {0x00e58481, 0x00d1ae}, /* U+5101 */ - {0x00e58482, 0x00d1af}, /* U+5102 */ - {0x00e58483, 0x00aecb}, /* U+5103 [2000] */ - {0x00e58484, 0x00b2af}, /* U+5104 */ - {0x00e58486, 0x00aeca}, /* U+5106 [2000] */ - {0x00e58488, 0x8fa3a1}, /* U+5108 [2000] */ - {0x00e58489, 0x00d1ad}, /* U+5109 */ - {0x00e5848b, 0x00aecc}, /* U+510B [2000] */ - {0x00e58492, 0x00bcf4}, /* U+5112 */ - {0x00e58494, 0x00d1b2}, /* U+5114 */ - {0x00e58495, 0x00d1b1}, /* U+5115 */ - {0x00e58496, 0x00d1b0}, /* U+5116 */ - {0x00e58497, 0x8fa3a3}, /* U+5117 [2000] */ - {0x00e58498, 0x00d0d6}, /* U+5118 */ - {0x00e5849a, 0x00d1b3}, /* U+511A */ - {0x00e5849b, 0x8fa3a4}, /* U+511B [2000] */ - {0x00e5849e, 0x00aecd}, /* U+511E [2000] */ - {0x00e5849f, 0x00bdfe}, /* U+511F */ - {0x00e584a1, 0x00d1b4}, /* U+5121 */ - {0x00e584aa, 0x00cda5}, /* U+512A */ - {0x00e584b2, 0x00ccd9}, /* U+5132 */ - {0x00e584b5, 0x00aece}, /* U+5135 [2000] */ - {0x00e584b7, 0x00d1b6}, /* U+5137 */ - {0x00e584ba, 0x00d1b5}, /* U+513A */ - {0x00e584bb, 0x00d1b8}, /* U+513B */ - {0x00e584bc, 0x00d1b7}, /* U+513C */ - {0x00e584bf, 0x00d1b9}, /* U+513F */ - {0x00e58580, 0x00d1ba}, /* U+5140 */ - {0x00e58581, 0x00b0f4}, /* U+5141 */ - {0x00e58583, 0x00b8b5}, /* U+5143 */ - {0x00e58584, 0x00b7bb}, /* U+5144 */ - {0x00e58585, 0x00bdbc}, /* U+5145 */ - {0x00e58586, 0x00c3fb}, /* U+5146 */ - {0x00e58587, 0x00b6a4}, /* U+5147 */ - {0x00e58588, 0x00c0e8}, /* U+5148 */ - {0x00e58589, 0x00b8f7}, /* U+5149 */ - {0x00e5858a, 0x00aecf}, /* U+514A [2000] */ - {0x00e5858b, 0x00b9ee}, /* U+514B */ - {0x00e5858c, 0x00d1bc}, /* U+514C */ - {0x00e5858d, 0x00ccc8}, /* U+514D */ - {0x00e5858e, 0x00c5c6}, /* U+514E */ - {0x00e58590, 0x00bbf9}, /* U+5150 */ - {0x00e58592, 0x00d1bb}, /* U+5152 */ - {0x00e58594, 0x00d1bd}, /* U+5154 */ - {0x00e58595, 0x00aed1}, /* U+5155 [2000] */ - {0x00e58597, 0x00aed2}, /* U+5157 [2000] */ - {0x00e5859a, 0x00c5de}, /* U+515A */ - {0x00e5859c, 0x00b3f5}, /* U+515C */ - {0x00e585a0, 0x8fa3a6}, /* U+5160 [2000] */ - {0x00e585a2, 0x00d1be}, /* U+5162 */ - {0x00e585a5, 0x00c6fe}, /* U+5165 */ - {0x00e585a8, 0x00c1b4}, /* U+5168 */ - {0x00e585a9, 0x00d1c0}, /* U+5169 */ - {0x00e585aa, 0x00d1c1}, /* U+516A */ - {0x00e585ab, 0x00c8ac}, /* U+516B */ - {0x00e585ac, 0x00b8f8}, /* U+516C */ - {0x00e585ad, 0x00cfbb}, /* U+516D */ - {0x00e585ae, 0x00d1c2}, /* U+516E */ - {0x00e585b1, 0x00b6a6}, /* U+5171 */ - {0x00e585b3, 0x8fa3a8}, /* U+5173 [2000] */ - {0x00e585b5, 0x00cabc}, /* U+5175 */ - {0x00e585b6, 0x00c2b6}, /* U+5176 */ - {0x00e585b7, 0x00b6f1}, /* U+5177 */ - {0x00e585b8, 0x00c5b5}, /* U+5178 */ - {0x00e585bb, 0x8ff4f4}, /* U+517B [2000] */ - {0x00e585bc, 0x00b7f3}, /* U+517C */ - {0x00e58680, 0x00d1c3}, /* U+5180 */ - {0x00e58682, 0x00d1c4}, /* U+5182 */ - {0x00e58683, 0x8fa3a9}, /* U+5183 [2000] */ - {0x00e58685, 0x00c6e2}, /* U+5185 */ - {0x00e58686, 0x00b1df}, /* U+5186 */ - {0x00e58689, 0x00d1c7}, /* U+5189 */ - {0x00e5868a, 0x00bafd}, /* U+518A */ - {0x00e5868b, 0x8fa3aa}, /* U+518B [2000] */ - {0x00e5868c, 0x00d1c6}, /* U+518C */ - {0x00e5868d, 0x00bac6}, /* U+518D */ - {0x00e5868f, 0x00d1c8}, /* U+518F */ - {0x00e58690, 0x00e6ee}, /* U+5190 */ - {0x00e58691, 0x00d1c9}, /* U+5191 */ - {0x00e58692, 0x00cbc1}, /* U+5192 */ - {0x00e58693, 0x00d1ca}, /* U+5193 */ - {0x00e58695, 0x00d1cb}, /* U+5195 */ - {0x00e58696, 0x00d1cc}, /* U+5196 */ - {0x00e58697, 0x00bee9}, /* U+5197 */ - {0x00e58698, 0x8fa3ac}, /* U+5198 [2000] */ - {0x00e58699, 0x00bccc}, /* U+5199 */ - {0x00e5869d, 0x00aed4}, /* U+519D [2000] */ - {0x00e586a0, 0x00b4a7}, /* U+51A0 */ - {0x00e586a2, 0x00d1cf}, /* U+51A2 */ - {0x00e586a3, 0x8fa3ad}, /* U+51A3 [2000] */ - {0x00e586a4, 0x00d1cd}, /* U+51A4 */ - {0x00e586a5, 0x00ccbd}, /* U+51A5 */ - {0x00e586a6, 0x00d1ce}, /* U+51A6 */ - {0x00e586a8, 0x00c9da}, /* U+51A8 */ - {0x00e586a9, 0x00d1d0}, /* U+51A9 */ - {0x00e586aa, 0x00d1d1}, /* U+51AA */ - {0x00e586ab, 0x00d1d2}, /* U+51AB */ - {0x00e586ac, 0x00c5df}, /* U+51AC */ - {0x00e586ad, 0x8fa3ae}, /* U+51AD [2000] */ - {0x00e586b0, 0x00d1d6}, /* U+51B0 */ - {0x00e586b1, 0x00d1d4}, /* U+51B1 */ - {0x00e586b2, 0x00d1d5}, /* U+51B2 */ - {0x00e586b3, 0x00d1d3}, /* U+51B3 */ - {0x00e586b4, 0x00bae3}, /* U+51B4 */ - {0x00e586b5, 0x00d1d7}, /* U+51B5 */ - {0x00e586b6, 0x00ccea}, /* U+51B6 */ - {0x00e586b7, 0x00cee4}, /* U+51B7 */ - {0x00e586bc, 0x8fa3b0}, /* U+51BC [2000] */ - {0x00e586bd, 0x00d1d8}, /* U+51BD */ - {0x00e58783, 0x00aed5}, /* U+51C3 [2000] */ - {0x00e58784, 0x00c0a8}, /* U+51C4 */ - {0x00e58785, 0x00d1d9}, /* U+51C5 */ - {0x00e58786, 0x00bdda}, /* U+51C6 */ - {0x00e58789, 0x00d1da}, /* U+51C9 */ - {0x00e5878a, 0x00aed6}, /* U+51CA [2000] */ - {0x00e5878b, 0x00c3fc}, /* U+51CB */ - {0x00e5878c, 0x00cebf}, /* U+51CC */ - {0x00e5878d, 0x00c5e0}, /* U+51CD */ - {0x00e58796, 0x00d2c5}, /* U+51D6 */ - {0x00e5879b, 0x00d1db}, /* U+51DB */ - {0x00e5879c, 0x00f4a5}, /* U+51DC [1990] */ - {0x00e5879d, 0x00b6c5}, /* U+51DD */ - {0x00e5879e, 0x00aed7}, /* U+51DE [2000] */ - {0x00e587a0, 0x00d1dc}, /* U+51E0 */ - {0x00e587a1, 0x00cbde}, /* U+51E1 */ - {0x00e587a2, 0x00aed8}, /* U+51E2 [2000] */ - {0x00e587a6, 0x00bde8}, /* U+51E6 */ - {0x00e587a7, 0x00c2fc}, /* U+51E7 */ - {0x00e587a9, 0x00d1de}, /* U+51E9 */ - {0x00e587aa, 0x00c6e4}, /* U+51EA */ - {0x00e587ad, 0x00d1df}, /* U+51ED */ - {0x00e587ae, 0x00aed9}, /* U+51EE [2000] */ - {0x00e587b0, 0x00d1e0}, /* U+51F0 */ - {0x00e587b1, 0x00b3ae}, /* U+51F1 */ - {0x00e587b3, 0x8fa3b3}, /* U+51F3 [2000] */ - {0x00e587b4, 0x8fa3b4}, /* U+51F4 [2000] */ - {0x00e587b5, 0x00d1e1}, /* U+51F5 */ - {0x00e587b6, 0x00b6a7}, /* U+51F6 */ - {0x00e587b8, 0x00c6cc}, /* U+51F8 */ - {0x00e587b9, 0x00b1fa}, /* U+51F9 */ - {0x00e587ba, 0x00bdd0}, /* U+51FA */ - {0x00e587bd, 0x00c8a1}, /* U+51FD */ - {0x00e587be, 0x00d1e2}, /* U+51FE */ - {0x00e58880, 0x00c5e1}, /* U+5200 */ - {0x00e58881, 0x00aeda}, /* U+5201 [2000] */ - {0x00e58882, 0x8fa3b5}, /* U+5202 [2000] */ - {0x00e58883, 0x00bfcf}, /* U+5203 */ - {0x00e58884, 0x00d1e3}, /* U+5204 */ - {0x00e58886, 0x00caac}, /* U+5206 */ - {0x00e58887, 0x00c0da}, /* U+5207 */ - {0x00e58888, 0x00b4a2}, /* U+5208 */ - {0x00e5888a, 0x00b4a9}, /* U+520A */ - {0x00e5888b, 0x00d1e4}, /* U+520B */ - {0x00e5888e, 0x00d1e6}, /* U+520E */ - {0x00e58891, 0x00b7ba}, /* U+5211 */ - {0x00e58892, 0x8fa3b6}, /* U+5212 [2000] */ - {0x00e58893, 0x00aedc}, /* U+5213 [2000] */ - {0x00e58894, 0x00d1e5}, /* U+5214 */ - {0x00e58895, 0x00aedd}, /* U+5215 [2000] */ - {0x00e58896, 0x8fa3b7}, /* U+5216 [2000] */ - {0x00e58897, 0x00cef3}, /* U+5217 */ - {0x00e5889d, 0x00bde9}, /* U+521D */ - {0x00e588a4, 0x00c8bd}, /* U+5224 */ - {0x00e588a5, 0x00cacc}, /* U+5225 */ - {0x00e588a7, 0x00d1e7}, /* U+5227 */ - {0x00e588a9, 0x00cdf8}, /* U+5229 */ - {0x00e588aa, 0x00d1e8}, /* U+522A */ - {0x00e588ae, 0x00d1e9}, /* U+522E */ - {0x00e588b0, 0x00c5fe}, /* U+5230 */ - {0x00e588b3, 0x00d1ea}, /* U+5233 */ - {0x00e588b6, 0x00c0a9}, /* U+5236 */ - {0x00e588b7, 0x00bafe}, /* U+5237 */ - {0x00e588b8, 0x00b7f4}, /* U+5238 */ - {0x00e588b9, 0x00d1eb}, /* U+5239 */ - {0x00e588ba, 0x00bbc9}, /* U+523A */ - {0x00e588bb, 0x00b9ef}, /* U+523B */ - {0x00e58983, 0x00c4e6}, /* U+5243 */ - {0x00e58984, 0x00d1ed}, /* U+5244 */ - {0x00e58987, 0x00c2a7}, /* U+5247 */ - {0x00e58989, 0x00aede}, /* U+5249 [2000] */ - {0x00e5898a, 0x00baef}, /* U+524A */ - {0x00e5898b, 0x00d1ee}, /* U+524B */ - {0x00e5898c, 0x00d1ef}, /* U+524C */ - {0x00e5898d, 0x00c1b0}, /* U+524D */ - {0x00e5898f, 0x00d1ec}, /* U+524F */ - {0x00e58994, 0x00d1f1}, /* U+5254 */ - {0x00e58995, 0x8fa3b9}, /* U+5255 [2000] */ - {0x00e58996, 0x00cbb6}, /* U+5256 */ - {0x00e58997, 0x00aedf}, /* U+5257 [2000] */ - {0x00e5899b, 0x00b9e4}, /* U+525B */ - {0x00e5899c, 0x8fa3ba}, /* U+525C [2000] */ - {0x00e5899d, 0x00affe}, /* U+525D [2004] */ - {0x00e5899e, 0x00d1f0}, /* U+525E */ - {0x00e589a1, 0x00aee0}, /* U+5261 [2000] */ - {0x00e589a3, 0x00b7f5}, /* U+5263 */ - {0x00e589a4, 0x00bade}, /* U+5264 */ - {0x00e589a5, 0x00c7ed}, /* U+5265 */ - {0x00e589a9, 0x00d1f4}, /* U+5269 */ - {0x00e589aa, 0x00d1f2}, /* U+526A */ - {0x00e589ac, 0x8fa3bb}, /* U+526C [2000] */ - {0x00e589af, 0x00c9fb}, /* U+526F */ - {0x00e589b0, 0x00beea}, /* U+5270 */ - {0x00e589b1, 0x00d1fb}, /* U+5271 */ - {0x00e589b2, 0x00b3e4}, /* U+5272 */ - {0x00e589b3, 0x00d1f5}, /* U+5273 */ - {0x00e589b4, 0x00d1f3}, /* U+5274 */ - {0x00e589b5, 0x00c1cf}, /* U+5275 */ - {0x00e589b7, 0x8fa3bc}, /* U+5277 [2000] */ - {0x00e589bd, 0x00d1f7}, /* U+527D */ - {0x00e589bf, 0x00d1f6}, /* U+527F */ - {0x00e58a82, 0x8fa3be}, /* U+5282 [2000] */ - {0x00e58a83, 0x00b3c4}, /* U+5283 */ - {0x00e58a84, 0x8fa3bd}, /* U+5284 [2000] */ - {0x00e58a87, 0x00b7e0}, /* U+5287 */ - {0x00e58a88, 0x00d1fc}, /* U+5288 */ - {0x00e58a89, 0x00cead}, /* U+5289 */ - {0x00e58a8d, 0x00d1f8}, /* U+528D */ - {0x00e58a91, 0x00d1fd}, /* U+5291 */ - {0x00e58a92, 0x00d1fa}, /* U+5292 */ - {0x00e58a93, 0x00aee1}, /* U+5293 [2000] */ - {0x00e58a94, 0x00d1f9}, /* U+5294 */ - {0x00e58a98, 0x8fa3c0}, /* U+5298 [2000] */ - {0x00e58a9b, 0x00cecf}, /* U+529B */ - {0x00e58a9f, 0x00b8f9}, /* U+529F */ - {0x00e58aa0, 0x00b2c3}, /* U+52A0 */ - {0x00e58aa3, 0x00cef4}, /* U+52A3 */ - {0x00e58aa4, 0x8fa3c2}, /* U+52A4 [2000] */ - {0x00e58aa6, 0x8fa3c3}, /* U+52A6 [2000] */ - {0x00e58aa9, 0x00bdf5}, /* U+52A9 */ - {0x00e58aaa, 0x00c5d8}, /* U+52AA */ - {0x00e58aab, 0x00b9e5}, /* U+52AB */ - {0x00e58aac, 0x00d2a2}, /* U+52AC */ - {0x00e58aad, 0x00d2a3}, /* U+52AD */ - {0x00e58aaf, 0x8fa3c4}, /* U+52AF [2000] */ - {0x00e58ab1, 0x00cee5}, /* U+52B1 */ - {0x00e58ab4, 0x00cfab}, /* U+52B4 */ - {0x00e58ab5, 0x00d2a5}, /* U+52B5 */ - {0x00e58ab9, 0x00b8fa}, /* U+52B9 */ - {0x00e58aba, 0x8fa3c5}, /* U+52BA [2000] */ - {0x00e58abb, 0x8fa3c6}, /* U+52BB [2000] */ - {0x00e58abc, 0x00d2a4}, /* U+52BC */ - {0x00e58abe, 0x00b3af}, /* U+52BE */ - {0x00e58b81, 0x00d2a6}, /* U+52C1 */ - {0x00e58b83, 0x00cbd6}, /* U+52C3 */ - {0x00e58b85, 0x00c4bc}, /* U+52C5 */ - {0x00e58b87, 0x00cda6}, /* U+52C7 */ - {0x00e58b88, 0x00aee2}, /* U+52C8 [2000] */ - {0x00e58b89, 0x00cad9}, /* U+52C9 */ - {0x00e58b8a, 0x8fa3c7}, /* U+52CA [2000] */ - {0x00e58b8c, 0x00aee4}, /* U+52CC [2000] */ - {0x00e58b8d, 0x00d2a7}, /* U+52CD */ - {0x00e58b90, 0x00aee5}, /* U+52D0 [2000] */ - {0x00e58b91, 0x8fa3c9}, /* U+52D1 [2000] */ - {0x00e58b92, 0x00f0d5}, /* U+52D2 */ - {0x00e58b95, 0x00c6b0}, /* U+52D5 */ - {0x00e58b96, 0x00aee6}, /* U+52D6 [2000] */ - {0x00e58b97, 0x00d2a8}, /* U+52D7 */ - {0x00e58b98, 0x00b4aa}, /* U+52D8 */ - {0x00e58b99, 0x00ccb3}, /* U+52D9 */ - {0x00e58b9b, 0x00aee7}, /* U+52DB [2000] */ - {0x00e58b9d, 0x00bea1}, /* U+52DD */ - {0x00e58b9e, 0x00d2a9}, /* U+52DE */ - {0x00e58b9f, 0x00cae7}, /* U+52DF */ - {0x00e58ba0, 0x00d2ad}, /* U+52E0 */ - {0x00e58ba2, 0x00c0aa}, /* U+52E2 */ - {0x00e58ba3, 0x00d2aa}, /* U+52E3 */ - {0x00e58ba4, 0x00b6d0}, /* U+52E4 */ - {0x00e58ba6, 0x00d2ab}, /* U+52E6 */ - {0x00e58ba7, 0x00b4ab}, /* U+52E7 */ - {0x00e58bb0, 0x00aee9}, /* U+52F0 [2000] */ - {0x00e58bb2, 0x00b7ae}, /* U+52F2 */ - {0x00e58bb3, 0x00d2ae}, /* U+52F3 */ - {0x00e58bb5, 0x00d2af}, /* U+52F5 */ - {0x00e58bb7, 0x8fa3cb}, /* U+52F7 [2000] */ - {0x00e58bb8, 0x00d2b0}, /* U+52F8 */ - {0x00e58bb9, 0x00d2b1}, /* U+52F9 */ - {0x00e58bba, 0x00bcdb}, /* U+52FA */ - {0x00e58bbb, 0x00aeea}, /* U+52FB [2000] */ - {0x00e58bbe, 0x00b8fb}, /* U+52FE */ - {0x00e58bbf, 0x00ccde}, /* U+52FF */ - {0x00e58c80, 0x00aeeb}, /* U+5300 [2000] */ - {0x00e58c81, 0x00cce8}, /* U+5301 */ - {0x00e58c82, 0x00c6f7}, /* U+5302 */ - {0x00e58c85, 0x00caf1}, /* U+5305 */ - {0x00e58c86, 0x00d2b2}, /* U+5306 */ - {0x00e58c87, 0x00aeec}, /* U+5307 [2000] */ - {0x00e58c88, 0x00d2b3}, /* U+5308 */ - {0x00e58c8a, 0x8fa3cc}, /* U+530A [2000] */ - {0x00e58c8b, 0x8fa3cd}, /* U+530B [2000] */ - {0x00e58c8d, 0x00d2b5}, /* U+530D */ - {0x00e58c8f, 0x00d2b7}, /* U+530F */ - {0x00e58c90, 0x00d2b6}, /* U+5310 */ - {0x00e58c95, 0x00d2b8}, /* U+5315 */ - {0x00e58c96, 0x00b2bd}, /* U+5316 */ - {0x00e58c97, 0x00cbcc}, /* U+5317 */ - {0x00e58c99, 0x00bafc}, /* U+5319 */ - {0x00e58c9a, 0x00d2b9}, /* U+531A */ - {0x00e58c9c, 0x00aeed}, /* U+531C [2000] */ - {0x00e58c9d, 0x00c1d9}, /* U+531D */ - {0x00e58ca0, 0x00bea2}, /* U+5320 */ - {0x00e58ca1, 0x00b6a9}, /* U+5321 */ - {0x00e58ca3, 0x00d2ba}, /* U+5323 */ - {0x00e58ca4, 0x8fa3ce}, /* U+5324 [2000] */ - {0x00e58caa, 0x00c8db}, /* U+532A */ - {0x00e58caf, 0x00d2bb}, /* U+532F */ - {0x00e58cb1, 0x00d2bc}, /* U+5331 */ - {0x00e58cb3, 0x00d2bd}, /* U+5333 */ - {0x00e58cb5, 0x8fa3cf}, /* U+5335 [2000] */ - {0x00e58cb8, 0x00d2be}, /* U+5338 */ - {0x00e58cb9, 0x00c9a4}, /* U+5339 */ - {0x00e58cba, 0x00b6e8}, /* U+533A */ - {0x00e58cbb, 0x00b0e5}, /* U+533B */ - {0x00e58cbe, 0x8fa3d0}, /* U+533E [2000] */ - {0x00e58cbf, 0x00c6bf}, /* U+533F */ - {0x00e58d80, 0x00d2bf}, /* U+5340 */ - {0x00e58d81, 0x00bdbd}, /* U+5341 */ - {0x00e58d82, 0x8fa3d1}, /* U+5342 [2000] */ - {0x00e58d83, 0x00c0e9}, /* U+5343 */ - {0x00e58d85, 0x00d2c1}, /* U+5345 */ - {0x00e58d86, 0x00d2c0}, /* U+5346 */ - {0x00e58d87, 0x00bea3}, /* U+5347 */ - {0x00e58d88, 0x00b8e1}, /* U+5348 */ - {0x00e58d89, 0x00d2c3}, /* U+5349 */ - {0x00e58d8a, 0x00c8be}, /* U+534A */ - {0x00e58d8d, 0x00d2c4}, /* U+534D */ - {0x00e58d91, 0x00c8dc}, /* U+5351 */ - {0x00e58d92, 0x00c2b4}, /* U+5352 */ - {0x00e58d93, 0x00c2ee}, /* U+5353 */ - {0x00e58d94, 0x00b6a8}, /* U+5354 */ - {0x00e58d97, 0x00c6ee}, /* U+5357 */ - {0x00e58d98, 0x00c3b1}, /* U+5358 */ - {0x00e58d9a, 0x00c7ee}, /* U+535A */ - {0x00e58d9c, 0x00cbce}, /* U+535C */ - {0x00e58d9e, 0x00d2c6}, /* U+535E */ - {0x00e58da0, 0x00c0ea}, /* U+5360 */ - {0x00e58da1, 0x00aeef}, /* U+5361 [2000] */ - {0x00e58da3, 0x00aef0}, /* U+5363 [2000] */ - {0x00e58da6, 0x00b7b5}, /* U+5366 */ - {0x00e58da7, 0x8fa3d4}, /* U+5367 [2000] */ - {0x00e58da9, 0x00d2c7}, /* U+5369 */ - {0x00e58dac, 0x8fa3d5}, /* U+536C [2000] */ - {0x00e58dae, 0x00d2c8}, /* U+536E */ - {0x00e58daf, 0x00b1ac}, /* U+536F */ - {0x00e58db0, 0x00b0f5}, /* U+5370 */ - {0x00e58db1, 0x00b4ed}, /* U+5371 */ - {0x00e58db3, 0x00c2a8}, /* U+5373 */ - {0x00e58db4, 0x00b5d1}, /* U+5374 */ - {0x00e58db5, 0x00cdf1}, /* U+5375 */ - {0x00e58db7, 0x00d2cb}, /* U+5377 */ - {0x00e58db8, 0x00b2b7}, /* U+5378 */ - {0x00e58dba, 0x8fa3d6}, /* U+537A [2000] */ - {0x00e58dbb, 0x00d2ca}, /* U+537B */ - {0x00e58dbd, 0x00aef1}, /* U+537D [2000] */ - {0x00e58dbf, 0x00b6aa}, /* U+537F */ - {0x00e58e82, 0x00d2cc}, /* U+5382 */ - {0x00e58e84, 0x00ccf1}, /* U+5384 */ - {0x00e58e93, 0x00aef2}, /* U+5393 [2000] */ - {0x00e58e96, 0x00d2cd}, /* U+5396 */ - {0x00e58e98, 0x00ced2}, /* U+5398 */ - {0x00e58e9a, 0x00b8fc}, /* U+539A */ - {0x00e58e9d, 0x00aef3}, /* U+539D [2000] */ - {0x00e58e9f, 0x00b8b6}, /* U+539F */ - {0x00e58ea0, 0x00d2ce}, /* U+53A0 */ - {0x00e58ea4, 0x8fa3d7}, /* U+53A4 [2000] */ - {0x00e58ea5, 0x00d2d0}, /* U+53A5 */ - {0x00e58ea6, 0x00d2cf}, /* U+53A6 */ - {0x00e58ea8, 0x00bfdf}, /* U+53A8 */ - {0x00e58ea9, 0x00b1b9}, /* U+53A9 */ - {0x00e58ead, 0x00b1de}, /* U+53AD */ - {0x00e58eae, 0x00d2d1}, /* U+53AE */ - {0x00e58eb0, 0x00d2d2}, /* U+53B0 */ - {0x00e58eb2, 0x00aef4}, /* U+53B2 [2000] */ - {0x00e58eb3, 0x00b8b7}, /* U+53B3 */ - {0x00e58eb4, 0x8fa3d8}, /* U+53B4 [2000] */ - {0x00e58eb6, 0x00d2d3}, /* U+53B6 */ - {0x00e58eb7, 0x8fa3da}, /* U+53B7 [2000] */ - {0x00e58ebb, 0x00b5ee}, /* U+53BB */ - {0x00e58f80, 0x8fa3db}, /* U+53C0 [2000] */ - {0x00e58f82, 0x00bbb2}, /* U+53C2 */ - {0x00e58f83, 0x00d2d4}, /* U+53C3 */ - {0x00e58f88, 0x00cbf4}, /* U+53C8 */ - {0x00e58f89, 0x00bab5}, /* U+53C9 */ - {0x00e58f8a, 0x00b5da}, /* U+53CA */ - {0x00e58f8b, 0x00cda7}, /* U+53CB */ - {0x00e58f8c, 0x00c1d0}, /* U+53CC */ - {0x00e58f8d, 0x00c8bf}, /* U+53CD */ - {0x00e58f8e, 0x00bcfd}, /* U+53CE */ - {0x00e58f94, 0x00bdc7}, /* U+53D4 */ - {0x00e58f95, 0x8fa3df}, /* U+53D5 [2000] */ - {0x00e58f96, 0x00bce8}, /* U+53D6 */ - {0x00e58f97, 0x00bcf5}, /* U+53D7 */ - {0x00e58f99, 0x00bdf6}, /* U+53D9 */ - {0x00e58f9a, 0x8fa3e0}, /* U+53DA [2000] */ - {0x00e58f9b, 0x00c8c0}, /* U+53DB */ - {0x00e58f9f, 0x00d2d7}, /* U+53DF */ - {0x00e58fa1, 0x00b1c3}, /* U+53E1 */ - {0x00e58fa2, 0x00c1d1}, /* U+53E2 */ - {0x00e58fa3, 0x00b8fd}, /* U+53E3 */ - {0x00e58fa4, 0x00b8c5}, /* U+53E4 */ - {0x00e58fa5, 0x00b6e7}, /* U+53E5 */ - {0x00e58fa8, 0x00d2db}, /* U+53E8 */ - {0x00e58fa9, 0x00c3a1}, /* U+53E9 */ - {0x00e58faa, 0x00c2fe}, /* U+53EA */ - {0x00e58fab, 0x00b6ab}, /* U+53EB */ - {0x00e58fac, 0x00bea4}, /* U+53EC */ - {0x00e58fad, 0x00d2dc}, /* U+53ED */ - {0x00e58fae, 0x00d2da}, /* U+53EE */ - {0x00e58faf, 0x00b2c4}, /* U+53EF */ - {0x00e58fb0, 0x00c2e6}, /* U+53F0 */ - {0x00e58fb1, 0x00bcb8}, /* U+53F1 */ - {0x00e58fb2, 0x00bbcb}, /* U+53F2 */ - {0x00e58fb3, 0x00b1a6}, /* U+53F3 */ - {0x00e58fb4, 0x8fa3e2}, /* U+53F4 [2000] */ - {0x00e58fb5, 0x8fa3e3}, /* U+53F5 [2000] */ - {0x00e58fb6, 0x00b3f0}, /* U+53F6 */ - {0x00e58fb7, 0x00b9e6}, /* U+53F7 */ - {0x00e58fb8, 0x00bbca}, /* U+53F8 */ - {0x00e58fba, 0x00d2dd}, /* U+53FA */ - {0x00e59081, 0x00d2de}, /* U+5401 */ - {0x00e59083, 0x00b5c9}, /* U+5403 */ - {0x00e59084, 0x00b3c6}, /* U+5404 */ - {0x00e59088, 0x00b9e7}, /* U+5408 */ - {0x00e59089, 0x00b5c8}, /* U+5409 */ - {0x00e5908a, 0x00c4df}, /* U+540A */ - {0x00e5908b, 0x00b1a5}, /* U+540B */ - {0x00e5908c, 0x00c6b1}, /* U+540C */ - {0x00e5908d, 0x00ccbe}, /* U+540D */ - {0x00e5908e, 0x00b9a1}, /* U+540E */ - {0x00e5908f, 0x00cdf9}, /* U+540F */ - {0x00e59090, 0x00c5c7}, /* U+5410 */ - {0x00e59091, 0x00b8fe}, /* U+5411 */ - {0x00e59092, 0x00aef5}, /* U+5412 [2000] */ - {0x00e5909b, 0x00b7af}, /* U+541B */ - {0x00e5909d, 0x00d2e7}, /* U+541D */ - {0x00e5909e, 0x00cffe}, /* U+541E [2004] */ - {0x00e5909f, 0x00b6e3}, /* U+541F */ - {0x00e590a0, 0x00cbca}, /* U+5420 */ - {0x00e590a4, 0x8fa3e5}, /* U+5424 [2000] */ - {0x00e590a6, 0x00c8dd}, /* U+5426 */ - {0x00e590a7, 0x00aef6}, /* U+5427 [2000] */ - {0x00e590a8, 0x8fa3e6}, /* U+5428 [2000] */ - {0x00e590a9, 0x00d2e6}, /* U+5429 */ - {0x00e590ab, 0x00b4de}, /* U+542B */ - {0x00e590ac, 0x00d2e1}, /* U+542C */ - {0x00e590ad, 0x00d2e2}, /* U+542D */ - {0x00e590ae, 0x00d2e4}, /* U+542E */ - {0x00e590b6, 0x00d2e5}, /* U+5436 */ - {0x00e590b8, 0x00b5db}, /* U+5438 */ - {0x00e590b9, 0x00bfe1}, /* U+5439 */ - {0x00e590bb, 0x00caad}, /* U+543B */ - {0x00e590bc, 0x00d2e3}, /* U+543C */ - {0x00e590bd, 0x00d2df}, /* U+543D */ - {0x00e590be, 0x00b8e3}, /* U+543E */ - {0x00e59180, 0x00d2e0}, /* U+5440 */ - {0x00e59182, 0x00cfa4}, /* U+5442 */ - {0x00e59183, 0x8fa3e8}, /* U+5443 [2000] */ - {0x00e59186, 0x00caf2}, /* U+5446 */ - {0x00e59188, 0x00c4e8}, /* U+5448 */ - {0x00e59189, 0x00b8e2}, /* U+5449 */ - {0x00e5918a, 0x00b9f0}, /* U+544A */ - {0x00e5918d, 0x00aef7}, /* U+544D [2000] */ - {0x00e5918e, 0x00d2e8}, /* U+544E */ - {0x00e59191, 0x00c6dd}, /* U+5451 */ - {0x00e59195, 0x8fa3e4}, /* U+5455 [2000] */ - {0x00e5919f, 0x00d2ec}, /* U+545F */ - {0x00e591a2, 0x8fa3e9}, /* U+5462 [2000] */ - {0x00e591a6, 0x8fa3ea}, /* U+5466 [2000] */ - {0x00e591a8, 0x00bcfe}, /* U+5468 */ - {0x00e591aa, 0x00bcf6}, /* U+546A */ - {0x00e591ab, 0x00aef9}, /* U+546B [2000] */ - {0x00e591ac, 0x8fa3eb}, /* U+546C [2000] */ - {0x00e591b0, 0x00d2ef}, /* U+5470 */ - {0x00e591b1, 0x00d2ed}, /* U+5471 */ - {0x00e591b3, 0x00cca3}, /* U+5473 */ - {0x00e591b4, 0x00aefa}, /* U+5474 [2000] */ - {0x00e591b5, 0x00d2ea}, /* U+5475 */ - {0x00e591b6, 0x00d2f3}, /* U+5476 */ - {0x00e591b7, 0x00d2ee}, /* U+5477 */ - {0x00e591bb, 0x00d2f1}, /* U+547B */ - {0x00e591bc, 0x00b8c6}, /* U+547C */ - {0x00e591bd, 0x00ccbf}, /* U+547D */ - {0x00e591bf, 0x00aefb}, /* U+547F [2000] */ - {0x00e59280, 0x00d2f2}, /* U+5480 */ - {0x00e59284, 0x00d2f4}, /* U+5484 */ - {0x00e59286, 0x00d2f6}, /* U+5486 */ - {0x00e59288, 0x00aefc}, /* U+5488 [2000] */ - {0x00e5928a, 0x8fa3ec}, /* U+548A [2000] */ - {0x00e5928b, 0x00baf0}, /* U+548B */ - {0x00e5928c, 0x00cfc2}, /* U+548C */ - {0x00e5928d, 0x8fa3ed}, /* U+548D [2000] */ - {0x00e5928e, 0x00d2eb}, /* U+548E */ - {0x00e5928f, 0x00d2e9}, /* U+548F */ - {0x00e59290, 0x00d2f5}, /* U+5490 */ - {0x00e59292, 0x00d2f0}, /* U+5492 */ - {0x00e59295, 0x8fa3ee}, /* U+5495 [2000] */ - {0x00e59296, 0x00aefd}, /* U+5496 [2000] */ - {0x00e5929c, 0x00aef8}, /* U+549C [2000] */ - {0x00e592a0, 0x8fa3ef}, /* U+54A0 [2000] */ - {0x00e592a1, 0x00aefe}, /* U+54A1 [2000] */ - {0x00e592a2, 0x00d2f8}, /* U+54A2 */ - {0x00e592a4, 0x00d3a3}, /* U+54A4 */ - {0x00e592a5, 0x00d2fa}, /* U+54A5 */ - {0x00e592a6, 0x8fa3f0}, /* U+54A6 [2000] */ - {0x00e592a8, 0x00d2fe}, /* U+54A8 */ - {0x00e592a9, 0x00afa1}, /* U+54A9 [2000] */ - {0x00e592ab, 0x00d3a1}, /* U+54AB */ - {0x00e592ac, 0x00d2fb}, /* U+54AC */ - {0x00e592ad, 0x8fa3f1}, /* U+54AD [2000] */ - {0x00e592ae, 0x8fa3f2}, /* U+54AE [2000] */ - {0x00e592af, 0x00d3be}, /* U+54AF */ - {0x00e592b2, 0x00bae9}, /* U+54B2 */ - {0x00e592b3, 0x00b3b1}, /* U+54B3 */ - {0x00e592b7, 0x8fa3f3}, /* U+54B7 [2000] */ - {0x00e592b8, 0x00d2f9}, /* U+54B8 */ - {0x00e592ba, 0x8fa3f4}, /* U+54BA [2000] */ - {0x00e592bc, 0x00d3a5}, /* U+54BC */ - {0x00e592bd, 0x00b0f6}, /* U+54BD */ - {0x00e592be, 0x00d3a4}, /* U+54BE */ - {0x00e592bf, 0x8fa3f5}, /* U+54BF [2000] */ - {0x00e59380, 0x00b0a5}, /* U+54C0 */ - {0x00e59381, 0x00c9ca}, /* U+54C1 */ - {0x00e59382, 0x00d3a2}, /* U+54C2 */ - {0x00e59383, 0x8fa3f6}, /* U+54C3 [2000] */ - {0x00e59384, 0x00d2fc}, /* U+54C4 */ - {0x00e59386, 0x00afa2}, /* U+54C6 [2000] */ - {0x00e59387, 0x00d2f7}, /* U+54C7 */ - {0x00e59388, 0x00d2fd}, /* U+54C8 */ - {0x00e59389, 0x00bac8}, /* U+54C9 */ - {0x00e59398, 0x00d3a6}, /* U+54D8 */ - {0x00e593a1, 0x00b0f7}, /* U+54E1 */ - {0x00e593a2, 0x00d3af}, /* U+54E2 */ - {0x00e593a5, 0x00d3a7}, /* U+54E5 */ - {0x00e593a6, 0x00d3a8}, /* U+54E6 */ - {0x00e593a8, 0x00bea5}, /* U+54E8 */ - {0x00e593a9, 0x00cbe9}, /* U+54E9 */ - {0x00e593ac, 0x8fa3f8}, /* U+54EC [2000] */ - {0x00e593ad, 0x00d3ad}, /* U+54ED */ - {0x00e593ae, 0x00d3ac}, /* U+54EE */ - {0x00e593af, 0x8fa3f9}, /* U+54EF [2000] */ - {0x00e593b1, 0x8fa3fa}, /* U+54F1 [2000] */ - {0x00e593b2, 0x00c5af}, /* U+54F2 */ - {0x00e593b3, 0x8fa3fb}, /* U+54F3 [2000] */ - {0x00e593ba, 0x00d3ae}, /* U+54FA */ - {0x00e593bd, 0x00d3ab}, /* U+54FD */ - {0x00e593bf, 0x00afa3}, /* U+54FF [2000] */ - {0x00e59480, 0x8fa3fc}, /* U+5500 [2000] */ - {0x00e59481, 0x8fa3fd}, /* U+5501 [2000] */ - {0x00e59484, 0x00b1b4}, /* U+5504 */ - {0x00e59486, 0x00bab6}, /* U+5506 */ - {0x00e59487, 0x00bfb0}, /* U+5507 */ - {0x00e59489, 0x8fa3fe}, /* U+5509 [2000] */ - {0x00e5948e, 0x00afa4}, /* U+550E [2000] */ - {0x00e5948f, 0x00d3a9}, /* U+550F */ - {0x00e59490, 0x00c5e2}, /* U+5510 */ - {0x00e59494, 0x00d3aa}, /* U+5514 */ - {0x00e59496, 0x00b0a2}, /* U+5516 */ - {0x00e594ab, 0x00afa5}, /* U+552B [2000] */ - {0x00e594ae, 0x00d3b4}, /* U+552E */ - {0x00e594af, 0x00cda3}, /* U+552F */ - {0x00e594b1, 0x00bea7}, /* U+5531 */ - {0x00e594b3, 0x00d3ba}, /* U+5533 */ - {0x00e594b5, 0x00afa6}, /* U+5535 [2000] */ - {0x00e594b8, 0x00d3b9}, /* U+5538 */ - {0x00e594b9, 0x00d3b0}, /* U+5539 */ - {0x00e594bc, 0x8fa4a1}, /* U+553C [2000] */ - {0x00e594be, 0x00c2c3}, /* U+553E */ - {0x00e59580, 0x00d3b1}, /* U+5540 */ - {0x00e59581, 0x8fa4a2}, /* U+5541 [2000] */ - {0x00e59584, 0x00c2ef}, /* U+5544 */ - {0x00e59585, 0x00d3b6}, /* U+5545 */ - {0x00e59586, 0x00bea6}, /* U+5546 */ - {0x00e59587, 0x8fa4a4}, /* U+5547 [2000] */ - {0x00e5958a, 0x8fa4a5}, /* U+554A [2000] */ - {0x00e5958c, 0x00d3b3}, /* U+554C */ - {0x00e5958f, 0x00cce4}, /* U+554F */ - {0x00e59590, 0x00afa7}, /* U+5550 [2000] */ - {0x00e59593, 0x00b7bc}, /* U+5553 */ - {0x00e59596, 0x00d3b7}, /* U+5556 */ - {0x00e59597, 0x00d3b8}, /* U+5557 */ - {0x00e5959c, 0x00d3b5}, /* U+555C */ - {0x00e5959d, 0x00d3bb}, /* U+555D */ - {0x00e5959e, 0x00afa8}, /* U+555E [2000] */ - {0x00e595a0, 0x8fa4a7}, /* U+5560 [2000] */ - {0x00e595a1, 0x8fa4a8}, /* U+5561 [2000] */ - {0x00e595a3, 0x00d3b2}, /* U+5563 */ - {0x00e595a4, 0x8fa4a9}, /* U+5564 [2000] */ - {0x00e595bb, 0x00d3c1}, /* U+557B */ - {0x00e595bc, 0x00d3c6}, /* U+557C */ - {0x00e595bd, 0x8fa4ab}, /* U+557D [2000] */ - {0x00e595be, 0x00d3c2}, /* U+557E */ - {0x00e59680, 0x00d3bd}, /* U+5580 */ - {0x00e59681, 0x00afa9}, /* U+5581 [2000] */ - {0x00e59682, 0x8fa4ac}, /* U+5582 [2000] */ - {0x00e59683, 0x00d3c7}, /* U+5583 */ - {0x00e59684, 0x00c1b1}, /* U+5584 */ - {0x00e59686, 0x00afaa}, /* U+5586 [2000] */ - {0x00e59687, 0x00d3c9}, /* U+5587 */ - {0x00e59688, 0x8fa4ad}, /* U+5588 [2000] */ - {0x00e59689, 0x00b9a2}, /* U+5589 */ - {0x00e5968a, 0x00d3bf}, /* U+558A */ - {0x00e5968b, 0x00c3fd}, /* U+558B */ - {0x00e5968e, 0x00afab}, /* U+558E [2000] */ - {0x00e59691, 0x8fa4ae}, /* U+5591 [2000] */ - {0x00e59698, 0x00d3c3}, /* U+5598 */ - {0x00e59699, 0x00d3bc}, /* U+5599 */ - {0x00e5969a, 0x00b4ad}, /* U+559A */ - {0x00e5969c, 0x00b4ee}, /* U+559C */ - {0x00e5969d, 0x00b3e5}, /* U+559D */ - {0x00e5969e, 0x00d3c4}, /* U+559E */ - {0x00e5969f, 0x00d3c0}, /* U+559F */ - {0x00e596a7, 0x00b7f6}, /* U+55A7 */ - {0x00e596a8, 0x00d3ca}, /* U+55A8 */ - {0x00e596a9, 0x00d3c8}, /* U+55A9 */ - {0x00e596aa, 0x00c1d3}, /* U+55AA */ - {0x00e596ab, 0x00b5ca}, /* U+55AB */ - {0x00e596ac, 0x00b6ac}, /* U+55AC */ - {0x00e596ad, 0x00afad}, /* U+55AD [2000] */ - {0x00e596ae, 0x00d3c5}, /* U+55AE */ - {0x00e596b0, 0x00b6f4}, /* U+55B0 */ - {0x00e596b6, 0x00b1c4}, /* U+55B6 */ - {0x00e596bf, 0x8fa4b3}, /* U+55BF [2000] */ - {0x00e59784, 0x00d3ce}, /* U+55C4 */ - {0x00e59785, 0x00d3cc}, /* U+55C5 */ - {0x00e59787, 0x00d4a7}, /* U+55C7 */ - {0x00e59789, 0x8fa4b4}, /* U+55C9 [2000] */ - {0x00e5978c, 0x8fa4b5}, /* U+55CC [2000] */ - {0x00e5978e, 0x00afae}, /* U+55CE [2000] */ - {0x00e59791, 0x8fa4b6}, /* U+55D1 [2000] */ - {0x00e59792, 0x8fa4b0}, /* U+55D2 [2000] */ - {0x00e59794, 0x00d3d1}, /* U+55D4 */ - {0x00e5979a, 0x00d3cb}, /* U+55DA */ - {0x00e5979c, 0x00d3cf}, /* U+55DC */ - {0x00e5979d, 0x8fa4b7}, /* U+55DD [2000] */ - {0x00e5979f, 0x00d3cd}, /* U+55DF */ - {0x00e597a2, 0x8fa4b9}, /* U+55E2 [2000] */ - {0x00e597a3, 0x00bbcc}, /* U+55E3 */ - {0x00e597a4, 0x00d3d0}, /* U+55E4 */ - {0x00e597a9, 0x8fa4bb}, /* U+55E9 [2000] */ - {0x00e597b7, 0x00d3d3}, /* U+55F7 */ - {0x00e597b9, 0x00d3d8}, /* U+55F9 */ - {0x00e597bd, 0x00d3d6}, /* U+55FD */ - {0x00e597be, 0x00d3d5}, /* U+55FE */ - {0x00e59886, 0x00c3b2}, /* U+5606 */ - {0x00e59887, 0x8fa4be}, /* U+5607 [2000] */ - {0x00e59888, 0x00afb0}, /* U+5608 [2000] */ - {0x00e59889, 0x00b2c5}, /* U+5609 */ - {0x00e5988e, 0x00afb1}, /* U+560E [2000] */ - {0x00e59890, 0x8fa4bf}, /* U+5610 [2000] */ - {0x00e59894, 0x00d3d2}, /* U+5614 */ - {0x00e59896, 0x00d3d4}, /* U+5616 */ - {0x00e59897, 0x00bea8}, /* U+5617 */ - {0x00e59898, 0x00b1b3}, /* U+5618 */ - {0x00e5989b, 0x00d3d7}, /* U+561B */ - {0x00e598a8, 0x8fa4bc}, /* U+5628 [2000] */ - {0x00e598a9, 0x00b2de}, /* U+5629 */ - {0x00e598af, 0x00d3e2}, /* U+562F */ - {0x00e598b0, 0x8fa4c0}, /* U+5630 [2000] */ - {0x00e598b1, 0x00befc}, /* U+5631 */ - {0x00e598b2, 0x00d3de}, /* U+5632 */ - {0x00e598b4, 0x00d3dc}, /* U+5634 */ - {0x00e598b6, 0x00d3dd}, /* U+5636 */ - {0x00e598b7, 0x8fa4c1}, /* U+5637 [2000] */ - {0x00e598b8, 0x00d3df}, /* U+5638 */ - {0x00e598bb, 0x00afb2}, /* U+563B [2000] */ - {0x00e598bd, 0x8fa4c3}, /* U+563D [2000] */ - {0x00e598bf, 0x8fa4c4}, /* U+563F [2000] */ - {0x00e59980, 0x8fa4c5}, /* U+5640 [2000] */ - {0x00e59982, 0x00b1bd}, /* U+5642 */ - {0x00e59987, 0x8fa4c6}, /* U+5647 [2000] */ - {0x00e59989, 0x00afb3}, /* U+5649 [2000] */ - {0x00e5998c, 0x00c1b9}, /* U+564C */ - {0x00e5998e, 0x00d3d9}, /* U+564E */ - {0x00e59990, 0x00d3da}, /* U+5650 */ - {0x00e59993, 0x00f4a7}, /* U+5653 [2004] */ - {0x00e5999b, 0x00b3fa}, /* U+565B */ - {0x00e5999e, 0x8fa4c7}, /* U+565E [2000] */ - {0x00e599a0, 0x8fa4c8}, /* U+5660 [2000] */ - {0x00e599a4, 0x00d3e1}, /* U+5664 */ - {0x00e599a6, 0x00afb5}, /* U+5666 [2000] */ - {0x00e599a8, 0x00b4ef}, /* U+5668 */ - {0x00e599aa, 0x00d3e4}, /* U+566A */ - {0x00e599ab, 0x00d3e0}, /* U+566B */ - {0x00e599ac, 0x00d3e3}, /* U+566C */ - {0x00e599ad, 0x8fa4c9}, /* U+566D [2000] */ - {0x00e599af, 0x00afb7}, /* U+566F [2000] */ - {0x00e599b1, 0x00afb8}, /* U+5671 [2000] */ - {0x00e599b2, 0x00afb9}, /* U+5672 [2000] */ - {0x00e599b4, 0x00caae}, /* U+5674 */ - {0x00e599b6, 0x00afb4}, /* U+5676 [2000] */ - {0x00e599b8, 0x00c6d5}, /* U+5678 */ - {0x00e599ba, 0x00c8b8}, /* U+567A */ - {0x00e59a80, 0x00d3e6}, /* U+5680 */ - {0x00e59a86, 0x00d3e5}, /* U+5686 */ - {0x00e59a87, 0x00b3c5}, /* U+5687 */ - {0x00e59a88, 0x8fa4cb}, /* U+5688 [2000] */ - {0x00e59a8a, 0x00d3e7}, /* U+568A */ - {0x00e59a8c, 0x8fa4cc}, /* U+568C [2000] */ - {0x00e59a8f, 0x00d3ea}, /* U+568F */ - {0x00e59a94, 0x00d3e9}, /* U+5694 */ - {0x00e59a95, 0x8fa4cd}, /* U+5695 [2000] */ - {0x00e59a99, 0x00afba}, /* U+5699 [2000] */ - {0x00e59a9a, 0x8fa4ce}, /* U+569A [2000] */ - {0x00e59a9d, 0x8fa4cf}, /* U+569D [2000] */ - {0x00e59a9e, 0x00afbb}, /* U+569E [2000] */ - {0x00e59aa0, 0x00d3e8}, /* U+56A0 */ - {0x00e59aa2, 0x00c7b9}, /* U+56A2 */ - {0x00e59aa5, 0x00d3eb}, /* U+56A5 */ - {0x00e59aa8, 0x8fa4d0}, /* U+56A8 [2000] */ - {0x00e59aa9, 0x00afbc}, /* U+56A9 [2000] */ - {0x00e59aac, 0x00afbd}, /* U+56AC [2000] */ - {0x00e59aad, 0x8fa4d1}, /* U+56AD [2000] */ - {0x00e59aae, 0x00d3ec}, /* U+56AE */ - {0x00e59ab2, 0x8fa4d2}, /* U+56B2 [2000] */ - {0x00e59ab3, 0x00afbe}, /* U+56B3 [2000] */ - {0x00e59ab4, 0x00d3ee}, /* U+56B4 */ - {0x00e59ab6, 0x00d3ed}, /* U+56B6 */ - {0x00e59abc, 0x00d3f0}, /* U+56BC */ - {0x00e59b80, 0x00d3f3}, /* U+56C0 */ - {0x00e59b81, 0x00d3f1}, /* U+56C1 */ - {0x00e59b82, 0x00d3ef}, /* U+56C2 */ - {0x00e59b83, 0x00d3f2}, /* U+56C3 */ - {0x00e59b85, 0x8fa4d3}, /* U+56C5 [2000] */ - {0x00e59b88, 0x00d3f4}, /* U+56C8 */ - {0x00e59b89, 0x00afbf}, /* U+56C9 [2000] */ - {0x00e59b8a, 0x00afc0}, /* U+56CA [2000] */ - {0x00e59b8d, 0x8fa4d4}, /* U+56CD [2000] */ - {0x00e59b8e, 0x00d3f5}, /* U+56CE */ - {0x00e59b91, 0x00d3f6}, /* U+56D1 */ - {0x00e59b93, 0x00d3f7}, /* U+56D3 */ - {0x00e59b97, 0x00d3f8}, /* U+56D7 */ - {0x00e59b98, 0x00d1c5}, /* U+56D8 */ - {0x00e59b9a, 0x00bcfc}, /* U+56DA */ - {0x00e59b9b, 0x00bbcd}, /* U+56DB */ - {0x00e59b9e, 0x00b2f3}, /* U+56DE */ - {0x00e59b9f, 0x8fa4d5}, /* U+56DF [2000] */ - {0x00e59ba0, 0x00b0f8}, /* U+56E0 */ - {0x00e59ba3, 0x00c3c4}, /* U+56E3 */ - {0x00e59ba8, 0x8fa4d6}, /* U+56E8 [2000] */ - {0x00e59bae, 0x00d3f9}, /* U+56EE */ - {0x00e59bb0, 0x00baa4}, /* U+56F0 */ - {0x00e59bb2, 0x00b0cf}, /* U+56F2 */ - {0x00e59bb3, 0x00bfde}, /* U+56F3 */ - {0x00e59bb6, 0x8fa4d7}, /* U+56F6 [2000] */ - {0x00e59bb7, 0x8fa4d8}, /* U+56F7 [2000] */ - {0x00e59bb9, 0x00d3fa}, /* U+56F9 */ - {0x00e59bba, 0x00b8c7}, /* U+56FA */ - {0x00e59bbd, 0x00b9f1}, /* U+56FD */ - {0x00e59bbf, 0x00d3fc}, /* U+56FF */ - {0x00e59c80, 0x00d3fb}, /* U+5700 */ - {0x00e59c83, 0x00cae0}, /* U+5703 */ - {0x00e59c84, 0x00d3fd}, /* U+5704 */ - {0x00e59c88, 0x00d4a1}, /* U+5708 */ - {0x00e59c89, 0x00d3fe}, /* U+5709 */ - {0x00e59c8a, 0x00afc1}, /* U+570A [2000] */ - {0x00e59c8b, 0x00d4a2}, /* U+570B */ - {0x00e59c8d, 0x00d4a3}, /* U+570D */ - {0x00e59c8f, 0x00b7f7}, /* U+570F */ - {0x00e59c92, 0x00b1e0}, /* U+5712 */ - {0x00e59c93, 0x00d4a4}, /* U+5713 */ - {0x00e59c95, 0x8fa4da}, /* U+5715 [2000] */ - {0x00e59c96, 0x00d4a6}, /* U+5716 */ - {0x00e59c98, 0x00d4a5}, /* U+5718 */ - {0x00e59c9c, 0x00d4a8}, /* U+571C */ - {0x00e59c9f, 0x00c5da}, /* U+571F */ - {0x00e59ca1, 0x00afc3}, /* U+5721 [2000] */ - {0x00e59ca3, 0x8fa4db}, /* U+5723 [2000] */ - {0x00e59ca6, 0x00d4a9}, /* U+5726 */ - {0x00e59ca7, 0x00b0b5}, /* U+5727 */ - {0x00e59ca8, 0x00badf}, /* U+5728 */ - {0x00e59ca9, 0x8fa4dd}, /* U+5729 [2000] */ - {0x00e59cad, 0x00b7bd}, /* U+572D */ - {0x00e59caf, 0x00afc4}, /* U+572F [2000] */ - {0x00e59cb0, 0x00c3cf}, /* U+5730 */ - {0x00e59cb3, 0x00afc5}, /* U+5733 [2000] */ - {0x00e59cb4, 0x00afc6}, /* U+5734 [2000] */ - {0x00e59cb7, 0x00d4aa}, /* U+5737 */ - {0x00e59cb8, 0x00d4ab}, /* U+5738 */ - {0x00e59cbb, 0x00d4ad}, /* U+573B */ - {0x00e59d80, 0x00d4ae}, /* U+5740 */ - {0x00e59d82, 0x00bae4}, /* U+5742 */ - {0x00e59d85, 0x8fa4df}, /* U+5745 [2000] */ - {0x00e59d86, 0x8fa4e0}, /* U+5746 [2000] */ - {0x00e59d87, 0x00b6d1}, /* U+5747 */ - {0x00e59d8a, 0x00cbb7}, /* U+574A */ - {0x00e59d8c, 0x8fa4e1}, /* U+574C [2000] */ - {0x00e59d8d, 0x8fa4e2}, /* U+574D [2000] */ - {0x00e59d8e, 0x00d4ac}, /* U+574E */ - {0x00e59d8f, 0x00d4af}, /* U+574F */ - {0x00e59d90, 0x00bac1}, /* U+5750 */ - {0x00e59d91, 0x00b9a3}, /* U+5751 */ - {0x00e59da1, 0x00d4b3}, /* U+5761 */ - {0x00e59da4, 0x00baa5}, /* U+5764 */ - {0x00e59da6, 0x00c3b3}, /* U+5766 */ - {0x00e59da8, 0x8fa4e4}, /* U+5768 [2000] */ - {0x00e59da9, 0x00d4b0}, /* U+5769 */ - {0x00e59daa, 0x00c4da}, /* U+576A */ - {0x00e59daf, 0x8fa4e5}, /* U+576F [2000] */ - {0x00e59db0, 0x00afc7}, /* U+5770 [2000] */ - {0x00e59db3, 0x8fa4e6}, /* U+5773 [2000] */ - {0x00e59db4, 0x8fa4e7}, /* U+5774 [2000] */ - {0x00e59db5, 0x8fa4e8}, /* U+5775 [2000] */ - {0x00e59db7, 0x00afc8}, /* U+5777 [2000] */ - {0x00e59dbb, 0x8fa4e9}, /* U+577B [2000] */ - {0x00e59dbc, 0x00afc9}, /* U+577C [2000] */ - {0x00e59dbf, 0x00d4b4}, /* U+577F */ - {0x00e59e82, 0x00bfe2}, /* U+5782 */ - {0x00e59e88, 0x00d4b2}, /* U+5788 */ - {0x00e59e89, 0x00d4b5}, /* U+5789 */ - {0x00e59e8b, 0x00b7bf}, /* U+578B */ - {0x00e59e93, 0x00d4b6}, /* U+5793 */ - {0x00e59e9a, 0x8fa4ed}, /* U+579A [2000] */ - {0x00e59e9c, 0x00afca}, /* U+579C [2000] */ - {0x00e59e9d, 0x8fa4ee}, /* U+579D [2000] */ - {0x00e59e9e, 0x8fa4ef}, /* U+579E [2000] */ - {0x00e59ea0, 0x00d4b7}, /* U+57A0 */ - {0x00e59ea2, 0x00b9a4}, /* U+57A2 */ - {0x00e59ea3, 0x00b3c0}, /* U+57A3 */ - {0x00e59ea4, 0x00d4b9}, /* U+57A4 */ - {0x00e59ea8, 0x8fa4f0}, /* U+57A8 [2000] */ - {0x00e59eaa, 0x00d4ba}, /* U+57AA */ - {0x00e59eac, 0x8fa4ec}, /* U+57AC [2000] */ - {0x00e59eb0, 0x00d4bb}, /* U+57B0 */ - {0x00e59eb3, 0x00d4b8}, /* U+57B3 */ - {0x00e59eb8, 0x00afcd}, /* U+57B8 [2000] */ - {0x00e59f80, 0x00d4b1}, /* U+57C0 */ - {0x00e59f83, 0x00d4bc}, /* U+57C3 */ - {0x00e59f86, 0x00d4bd}, /* U+57C6 */ - {0x00e59f87, 0x00afce}, /* U+57C7 [2000] */ - {0x00e59f88, 0x00afcf}, /* U+57C8 [2000] */ - {0x00e59f8b, 0x00cbe4}, /* U+57CB */ - {0x00e59f8c, 0x8fa4f3}, /* U+57CC [2000] */ - {0x00e59f8e, 0x00beeb}, /* U+57CE */ - {0x00e59f8f, 0x00afd0}, /* U+57CF [2000] */ - {0x00e59f92, 0x00d4bf}, /* U+57D2 */ - {0x00e59f93, 0x00d4c0}, /* U+57D3 */ - {0x00e59f94, 0x00d4be}, /* U+57D4 */ - {0x00e59f96, 0x00d4c2}, /* U+57D6 */ - {0x00e59f97, 0x8fa4f1}, /* U+57D7 [2000] */ - {0x00e59f9c, 0x00c7b8}, /* U+57DC */ - {0x00e59f9e, 0x8fa4f6}, /* U+57DE [2000] */ - {0x00e59f9f, 0x00b0e8}, /* U+57DF */ - {0x00e59fa0, 0x00c9d6}, /* U+57E0 */ - {0x00e59fa3, 0x00d4c3}, /* U+57E3 */ - {0x00e59fa4, 0x00afd1}, /* U+57E4 [2000] */ - {0x00e59fa6, 0x8fa4f7}, /* U+57E6 [2000] */ - {0x00e59fad, 0x00afd2}, /* U+57ED [2000] */ - {0x00e59fb0, 0x8fa4f8}, /* U+57F0 [2000] */ - {0x00e59fb4, 0x00befd}, /* U+57F4 */ - {0x00e59fb5, 0x00afd3}, /* U+57F5 [2000] */ - {0x00e59fb6, 0x00afd4}, /* U+57F6 [2000] */ - {0x00e59fb7, 0x00bcb9}, /* U+57F7 */ - {0x00e59fb8, 0x8fa4fa}, /* U+57F8 [2000] */ - {0x00e59fb9, 0x00c7dd}, /* U+57F9 */ - {0x00e59fba, 0x00b4f0}, /* U+57FA */ - {0x00e59fbb, 0x8fa4fb}, /* U+57FB [2000] */ - {0x00e59fbc, 0x00baeb}, /* U+57FC */ - {0x00e59fbd, 0x8fa4fc}, /* U+57FD [2000] */ - {0x00e59fbf, 0x00afd5}, /* U+57FF [2000] */ - {0x00e5a080, 0x00cbd9}, /* U+5800 */ - {0x00e5a082, 0x00c6b2}, /* U+5802 */ - {0x00e5a084, 0x8fa4fd}, /* U+5804 [2000] */ - {0x00e5a085, 0x00b7f8}, /* U+5805 */ - {0x00e5a086, 0x00c2cf}, /* U+5806 */ - {0x00e5a089, 0x00afd6}, /* U+5809 [2000] */ - {0x00e5a08a, 0x00d4c1}, /* U+580A */ - {0x00e5a08b, 0x00d4c4}, /* U+580B */ - {0x00e5a095, 0x00c2c4}, /* U+5815 */ - {0x00e5a099, 0x00d4c5}, /* U+5819 */ - {0x00e5a09d, 0x00d4c6}, /* U+581D */ - {0x00e5a09e, 0x8fa4fe}, /* U+581E [2000] */ - {0x00e5a0a0, 0x8fa5a1}, /* U+5820 [2000] */ - {0x00e5a0a1, 0x00d4c8}, /* U+5821 */ - {0x00e5a0a4, 0x00c4e9}, /* U+5824 */ - {0x00e5a0a7, 0x8fa5a2}, /* U+5827 [2000] */ - {0x00e5a0aa, 0x00b4ae}, /* U+582A */ - {0x00e5a0af, 0x00f4a1}, /* U+582F [1983] */ - {0x00e5a0b0, 0x00b1e1}, /* U+5830 */ - {0x00e5a0b1, 0x00caf3}, /* U+5831 */ - {0x00e5a0b2, 0x8fa5a3}, /* U+5832 [2000] */ - {0x00e5a0b4, 0x00beec}, /* U+5834 */ - {0x00e5a0b5, 0x00c5c8}, /* U+5835 */ - {0x00e5a0b9, 0x8fa5a4}, /* U+5839 [2000] */ - {0x00e5a0ba, 0x00bae6}, /* U+583A */ - {0x00e5a0bd, 0x00d4ce}, /* U+583D */ - {0x00e5a180, 0x00cabd}, /* U+5840 */ - {0x00e5a181, 0x00cedd}, /* U+5841 */ - {0x00e5a189, 0x8fa5a6}, /* U+5849 [2000] */ - {0x00e5a18a, 0x00b2f4}, /* U+584A */ - {0x00e5a18b, 0x00d4ca}, /* U+584B */ - {0x00e5a18c, 0x8fa5a7}, /* U+584C [2000] */ - {0x00e5a191, 0x00c1ba}, /* U+5851 */ - {0x00e5a192, 0x00d4cd}, /* U+5852 */ - {0x00e5a194, 0x00c5e3}, /* U+5854 */ - {0x00e5a197, 0x00c5c9}, /* U+5857 */ - {0x00e5a198, 0x00c5e4}, /* U+5858 */ - {0x00e5a199, 0x00c8b9}, /* U+5859 */ - {0x00e5a19a, 0x00c4cd}, /* U+585A */ - {0x00e5a19e, 0x00bac9}, /* U+585E */ - {0x00e5a1a1, 0x00afd8}, /* U+5861 [2000] */ - {0x00e5a1a2, 0x00d4c9}, /* U+5862 */ - {0x00e5a1a4, 0x00afd9}, /* U+5864 [2000] */ - {0x00e5a1a7, 0x8fa5a8}, /* U+5867 [2000] */ - {0x00e5a1a9, 0x00b1f6}, /* U+5869 */ - {0x00e5a1ab, 0x00c5b6}, /* U+586B */ - {0x00e5a1b0, 0x00d4cb}, /* U+5870 */ - {0x00e5a1b2, 0x00d4c7}, /* U+5872 */ - {0x00e5a1b5, 0x00bfd0}, /* U+5875 */ - {0x00e5a1b9, 0x00d4cf}, /* U+5879 */ - {0x00e5a1bc, 0x00afdb}, /* U+587C [2000] */ - {0x00e5a1be, 0x00bdce}, /* U+587E */ - {0x00e5a283, 0x00b6ad}, /* U+5883 */ - {0x00e5a285, 0x00d4d0}, /* U+5885 */ - {0x00e5a289, 0x00afdc}, /* U+5889 [2000] */ - {0x00e5a28a, 0x8fa5a9}, /* U+588A [2000] */ - {0x00e5a28b, 0x8fa5aa}, /* U+588B [2000] */ - {0x00e5a28d, 0x8fa5ab}, /* U+588D [2000] */ - {0x00e5a28f, 0x8fa5ac}, /* U+588F [2000] */ - {0x00e5a290, 0x8fa5ad}, /* U+5890 [2000] */ - {0x00e5a293, 0x00cae8}, /* U+5893 */ - {0x00e5a294, 0x8fa5ae}, /* U+5894 [2000] */ - {0x00e5a297, 0x00c1fd}, /* U+5897 */ - {0x00e5a29c, 0x00c4c6}, /* U+589C */ - {0x00e5a29d, 0x8fa5af}, /* U+589D [2000] */ - {0x00e5a29e, 0x00afdd}, /* U+589E [2000] */ - {0x00e5a29f, 0x00d4d2}, /* U+589F */ - {0x00e5a2a8, 0x00cbcf}, /* U+58A8 */ - {0x00e5a2a9, 0x00afdf}, /* U+58A9 [2000] */ - {0x00e5a2aa, 0x8fa5b0}, /* U+58AA [2000] */ - {0x00e5a2ab, 0x00d4d3}, /* U+58AB */ - {0x00e5a2ae, 0x00d4d8}, /* U+58AE */ - {0x00e5a2b1, 0x8fa5b1}, /* U+58B1 [2000] */ - {0x00e5a2b3, 0x00caaf}, /* U+58B3 */ - {0x00e5a2b8, 0x00d4d7}, /* U+58B8 */ - {0x00e5a2b9, 0x00d4d1}, /* U+58B9 */ - {0x00e5a2ba, 0x00d4d4}, /* U+58BA */ - {0x00e5a2bb, 0x00d4d6}, /* U+58BB */ - {0x00e5a2be, 0x00baa6}, /* U+58BE */ - {0x00e5a381, 0x00cac9}, /* U+58C1 */ - {0x00e5a383, 0x8fa5b3}, /* U+58C3 [2000] */ - {0x00e5a385, 0x00d4d9}, /* U+58C5 */ - {0x00e5a387, 0x00c3c5}, /* U+58C7 */ - {0x00e5a38a, 0x00b2f5}, /* U+58CA */ - {0x00e5a38c, 0x00beed}, /* U+58CC */ - {0x00e5a38d, 0x8fa5b4}, /* U+58CD [2000] */ - {0x00e5a38e, 0x00afe2}, /* U+58CE [2000] */ - {0x00e5a391, 0x00d4db}, /* U+58D1 */ - {0x00e5a392, 0x00afe1}, /* U+58D2 [2000] */ - {0x00e5a393, 0x00d4da}, /* U+58D3 */ - {0x00e5a394, 0x00afe3}, /* U+58D4 [2000] */ - {0x00e5a395, 0x00b9e8}, /* U+58D5 */ - {0x00e5a397, 0x00d4dc}, /* U+58D7 */ - {0x00e5a398, 0x00d4de}, /* U+58D8 */ - {0x00e5a399, 0x00d4dd}, /* U+58D9 */ - {0x00e5a39a, 0x00afe4}, /* U+58DA [2000] */ - {0x00e5a39c, 0x00d4e0}, /* U+58DC */ - {0x00e5a39e, 0x00d4d5}, /* U+58DE */ - {0x00e5a39f, 0x00d4e2}, /* U+58DF */ - {0x00e5a3a0, 0x00afe5}, /* U+58E0 [2000] */ - {0x00e5a3a2, 0x8fa5b5}, /* U+58E2 [2000] */ - {0x00e5a3a4, 0x00d4e1}, /* U+58E4 */ - {0x00e5a3a5, 0x00d4df}, /* U+58E5 */ - {0x00e5a3a9, 0x00afe6}, /* U+58E9 [2000] */ - {0x00e5a3ab, 0x00bbce}, /* U+58EB */ - {0x00e5a3ac, 0x00bfd1}, /* U+58EC */ - {0x00e5a3ae, 0x00c1d4}, /* U+58EE */ - {0x00e5a3af, 0x00d4e3}, /* U+58EF */ - {0x00e5a3b0, 0x00c0bc}, /* U+58F0 */ - {0x00e5a3b1, 0x00b0ed}, /* U+58F1 */ - {0x00e5a3b2, 0x00c7e4}, /* U+58F2 */ - {0x00e5a3b3, 0x8fa5b6}, /* U+58F3 [2000] */ - {0x00e5a3b4, 0x8fa5b7}, /* U+58F4 [2000] */ - {0x00e5a3b7, 0x00c4db}, /* U+58F7 */ - {0x00e5a3b9, 0x00d4e5}, /* U+58F9 */ - {0x00e5a3ba, 0x00d4e4}, /* U+58FA */ - {0x00e5a3bb, 0x00d4e6}, /* U+58FB */ - {0x00e5a3bc, 0x00d4e7}, /* U+58FC */ - {0x00e5a3bd, 0x00d4e8}, /* U+58FD */ - {0x00e5a482, 0x00d4e9}, /* U+5902 */ - {0x00e5a485, 0x8fa5b8}, /* U+5905 [2000] */ - {0x00e5a486, 0x8fa5b9}, /* U+5906 [2000] */ - {0x00e5a489, 0x00cad1}, /* U+5909 */ - {0x00e5a48a, 0x00d4ea}, /* U+590A */ - {0x00e5a48b, 0x8fa5ba}, /* U+590B [2000] */ - {0x00e5a48c, 0x00afe7}, /* U+590C [2000] */ - {0x00e5a48d, 0x8fa5bb}, /* U+590D [2000] */ - {0x00e5a48f, 0x00b2c6}, /* U+590F */ - {0x00e5a490, 0x00d4eb}, /* U+5910 */ - {0x00e5a494, 0x8fa5bc}, /* U+5914 [2000] */ - {0x00e5a495, 0x00cdbc}, /* U+5915 */ - {0x00e5a496, 0x00b3b0}, /* U+5916 */ - {0x00e5a498, 0x00d2c9}, /* U+5918 */ - {0x00e5a499, 0x00bdc8}, /* U+5919 */ - {0x00e5a49a, 0x00c2bf}, /* U+591A */ - {0x00e5a49b, 0x00d4ec}, /* U+591B */ - {0x00e5a49c, 0x00cceb}, /* U+591C */ - {0x00e5a4a2, 0x00ccb4}, /* U+5922 */ - {0x00e5a4a4, 0x8fa5bd}, /* U+5924 [2000] */ - {0x00e5a4a5, 0x00d4ee}, /* U+5925 */ - {0x00e5a4a7, 0x00c2e7}, /* U+5927 */ - {0x00e5a4a9, 0x00c5b7}, /* U+5929 */ - {0x00e5a4aa, 0x00c2c0}, /* U+592A */ - {0x00e5a4ab, 0x00c9d7}, /* U+592B */ - {0x00e5a4ac, 0x00d4ef}, /* U+592C */ - {0x00e5a4ad, 0x00d4f0}, /* U+592D */ - {0x00e5a4ae, 0x00b1fb}, /* U+592E */ - {0x00e5a4b1, 0x00bcba}, /* U+5931 */ - {0x00e5a4b2, 0x00d4f1}, /* U+5932 */ - {0x00e5a4b7, 0x00b0d0}, /* U+5937 */ - {0x00e5a4b8, 0x00d4f2}, /* U+5938 */ - {0x00e5a4bd, 0x8fa5c0}, /* U+593D [2000] */ - {0x00e5a4be, 0x00d4f3}, /* U+593E */ - {0x00e5a584, 0x00b1e2}, /* U+5944 */ - {0x00e5a586, 0x8fa5c2}, /* U+5946 [2000] */ - {0x00e5a587, 0x00b4f1}, /* U+5947 */ - {0x00e5a588, 0x00c6e0}, /* U+5948 */ - {0x00e5a589, 0x00caf4}, /* U+5949 */ - {0x00e5a58e, 0x00d4f7}, /* U+594E */ - {0x00e5a58f, 0x00c1d5}, /* U+594F */ - {0x00e5a590, 0x00d4f6}, /* U+5950 */ - {0x00e5a591, 0x00b7c0}, /* U+5951 */ - {0x00e5a594, 0x00cbdb}, /* U+5954 */ - {0x00e5a595, 0x00d4f5}, /* U+5955 */ - {0x00e5a597, 0x00c5e5}, /* U+5957 */ - {0x00e5a598, 0x00d4f9}, /* U+5958 */ - {0x00e5a59a, 0x00d4f8}, /* U+595A */ - {0x00e5a59b, 0x8fa5c5}, /* U+595B [2000] */ - {0x00e5a59d, 0x00afe9}, /* U+595D [2000] */ - {0x00e5a59f, 0x8fa5c6}, /* U+595F [2000] */ - {0x00e5a5a0, 0x00d4fb}, /* U+5960 */ - {0x00e5a5a2, 0x00d4fa}, /* U+5962 */ - {0x00e5a5a5, 0x00b1fc}, /* U+5965 */ - {0x00e5a5a7, 0x00d4fc}, /* U+5967 */ - {0x00e5a5a8, 0x00bea9}, /* U+5968 */ - {0x00e5a5a9, 0x00d4fe}, /* U+5969 */ - {0x00e5a5aa, 0x00c3a5}, /* U+596A */ - {0x00e5a5ac, 0x00d4fd}, /* U+596C */ - {0x00e5a5ad, 0x00afea}, /* U+596D [2000] */ - {0x00e5a5ae, 0x00cab3}, /* U+596E */ - {0x00e5a5b3, 0x00bdf7}, /* U+5973 */ - {0x00e5a5b4, 0x00c5db}, /* U+5974 */ - {0x00e5a5b5, 0x8fa5c8}, /* U+5975 [2000] */ - {0x00e5a5b6, 0x8fa5c9}, /* U+5976 [2000] */ - {0x00e5a5b8, 0x00d5a1}, /* U+5978 */ - {0x00e5a5bc, 0x8fa5ca}, /* U+597C [2000] */ - {0x00e5a5bd, 0x00b9a5}, /* U+597D */ - {0x00e5a681, 0x00d5a2}, /* U+5981 */ - {0x00e5a682, 0x00c7a1}, /* U+5982 */ - {0x00e5a683, 0x00c8de}, /* U+5983 */ - {0x00e5a684, 0x00ccd1}, /* U+5984 */ - {0x00e5a68a, 0x00c7a5}, /* U+598A */ - {0x00e5a68b, 0x00afeb}, /* U+598B [2000] */ - {0x00e5a68d, 0x00d5ab}, /* U+598D */ - {0x00e5a692, 0x00afec}, /* U+5992 [2000] */ - {0x00e5a693, 0x00b5b8}, /* U+5993 */ - {0x00e5a696, 0x00cdc5}, /* U+5996 */ - {0x00e5a699, 0x00ccaf}, /* U+5999 */ - {0x00e5a69b, 0x00d6ac}, /* U+599B */ - {0x00e5a69d, 0x00d5a3}, /* U+599D */ - {0x00e5a69f, 0x8fa5cb}, /* U+599F [2000] */ - {0x00e5a6a3, 0x00d5a6}, /* U+59A3 */ - {0x00e5a6a4, 0x00afed}, /* U+59A4 [2000] */ - {0x00e5a6a5, 0x00c2c5}, /* U+59A5 */ - {0x00e5a6a8, 0x00cbb8}, /* U+59A8 */ - {0x00e5a6ac, 0x00c5ca}, /* U+59AC */ - {0x00e5a6ae, 0x8fa5cc}, /* U+59AE [2000] */ - {0x00e5a6b2, 0x00d5a7}, /* U+59B2 */ - {0x00e5a6b9, 0x00cbe5}, /* U+59B9 */ - {0x00e5a6bb, 0x00baca}, /* U+59BB */ - {0x00e5a6bc, 0x8fa5cd}, /* U+59BC [2000] */ - {0x00e5a6be, 0x00beaa}, /* U+59BE */ - {0x00e5a783, 0x00afee}, /* U+59C3 [2000] */ - {0x00e5a786, 0x00d5a8}, /* U+59C6 */ - {0x00e5a788, 0x8fa5ce}, /* U+59C8 [2000] */ - {0x00e5a789, 0x00bbd0}, /* U+59C9 */ - {0x00e5a78b, 0x00bbcf}, /* U+59CB */ - {0x00e5a78d, 0x8fa5cf}, /* U+59CD [2000] */ - {0x00e5a790, 0x00b0b9}, /* U+59D0 */ - {0x00e5a791, 0x00b8c8}, /* U+59D1 */ - {0x00e5a792, 0x00afef}, /* U+59D2 [2000] */ - {0x00e5a793, 0x00c0ab}, /* U+59D3 */ - {0x00e5a794, 0x00b0d1}, /* U+59D4 */ - {0x00e5a799, 0x00d5ac}, /* U+59D9 */ - {0x00e5a79a, 0x00d5ad}, /* U+59DA */ - {0x00e5a79c, 0x00d5aa}, /* U+59DC */ - {0x00e5a79d, 0x00aff0}, /* U+59DD [2000] */ - {0x00e5a79e, 0x8fa5d0}, /* U+59DE [2000] */ - {0x00e5a7a3, 0x8fa5d1}, /* U+59E3 [2000] */ - {0x00e5a7a4, 0x8fa5d2}, /* U+59E4 [2000] */ - {0x00e5a7a5, 0x00b1b8}, /* U+59E5 */ - {0x00e5a7a6, 0x00b4af}, /* U+59E6 */ - {0x00e5a7a7, 0x8fa5d3}, /* U+59E7 [2000] */ - {0x00e5a7a8, 0x00d5a9}, /* U+59E8 */ - {0x00e5a7aa, 0x00ccc5}, /* U+59EA */ - {0x00e5a7ab, 0x00c9b1}, /* U+59EB */ - {0x00e5a7ae, 0x8fa5d4}, /* U+59EE [2000] */ - {0x00e5a7b6, 0x00b0a8}, /* U+59F6 */ - {0x00e5a7b8, 0x00fefa}, /* U+59F8 [2004] */ - {0x00e5a7bb, 0x00b0f9}, /* U+59FB */ - {0x00e5a7bf, 0x00bbd1}, /* U+59FF */ - {0x00e5a881, 0x00b0d2}, /* U+5A01 */ - {0x00e5a883, 0x00b0a3}, /* U+5A03 */ - {0x00e5a889, 0x00d5b2}, /* U+5A09 */ - {0x00e5a88c, 0x8fa5d8}, /* U+5A0C [2000] */ - {0x00e5a88d, 0x8fa5d9}, /* U+5A0D [2000] */ - {0x00e5a891, 0x00d5b0}, /* U+5A11 */ - {0x00e5a893, 0x00aff1}, /* U+5A13 [2000] */ - {0x00e5a897, 0x8fa5da}, /* U+5A17 [2000] */ - {0x00e5a898, 0x00ccbc}, /* U+5A18 */ - {0x00e5a89a, 0x00d5b3}, /* U+5A1A */ - {0x00e5a89c, 0x00d5b1}, /* U+5A1C */ - {0x00e5a89f, 0x00d5af}, /* U+5A1F */ - {0x00e5a8a0, 0x00bfb1}, /* U+5A20 */ - {0x00e5a8a3, 0x00aff2}, /* U+5A23 [2000] */ - {0x00e5a8a5, 0x00d5ae}, /* U+5A25 */ - {0x00e5a8a7, 0x8fa5db}, /* U+5A27 [2000] */ - {0x00e5a8a9, 0x00cada}, /* U+5A29 */ - {0x00e5a8ad, 0x8fa5dc}, /* U+5A2D [2000] */ - {0x00e5a8af, 0x00b8e4}, /* U+5A2F */ - {0x00e5a8b5, 0x00d5b7}, /* U+5A35 */ - {0x00e5a8b6, 0x00d5b8}, /* U+5A36 */ - {0x00e5a8bc, 0x00beab}, /* U+5A3C */ - {0x00e5a980, 0x00d5b4}, /* U+5A40 */ - {0x00e5a981, 0x00cfac}, /* U+5A41 */ - {0x00e5a986, 0x00c7cc}, /* U+5A46 */ - {0x00e5a989, 0x00d5b6}, /* U+5A49 */ - {0x00e5a995, 0x8fa5dd}, /* U+5A55 [2000] */ - {0x00e5a99a, 0x00baa7}, /* U+5A5A */ - {0x00e5a9a2, 0x00d5b9}, /* U+5A62 */ - {0x00e5a9a5, 0x8fa5de}, /* U+5A65 [2000] */ - {0x00e5a9a6, 0x00c9d8}, /* U+5A66 */ - {0x00e5a9a7, 0x00aff3}, /* U+5A67 [2000] */ - {0x00e5a9aa, 0x00d5ba}, /* U+5A6A */ - {0x00e5a9ac, 0x00d5b5}, /* U+5A6C */ - {0x00e5a9ad, 0x00aff4}, /* U+5A6D [2000] */ - {0x00e5a9b7, 0x00aff5}, /* U+5A77 [2000] */ - {0x00e5a9ba, 0x8fa5df}, /* U+5A7A [2000] */ - {0x00e5a9be, 0x00aff6}, /* U+5A7E [2000] */ - {0x00e5a9bf, 0x00ccbb}, /* U+5A7F */ - {0x00e5aa84, 0x00aff7}, /* U+5A84 [2000] */ - {0x00e5aa8b, 0x8fa5e0}, /* U+5A8B [2000] */ - {0x00e5aa92, 0x00c7de}, /* U+5A92 */ - {0x00e5aa9a, 0x00d5bb}, /* U+5A9A */ - {0x00e5aa9b, 0x00c9b2}, /* U+5A9B */ - {0x00e5aa9c, 0x8fa5e1}, /* U+5A9C [2000] */ - {0x00e5aa9e, 0x00aff8}, /* U+5A9E [2000] */ - {0x00e5aa9f, 0x8fa5e2}, /* U+5A9F [2000] */ - {0x00e5aaa0, 0x8fa5e3}, /* U+5AA0 [2000] */ - {0x00e5aaa2, 0x8fa5e4}, /* U+5AA2 [2000] */ - {0x00e5aaa7, 0x00aff9}, /* U+5AA7 [2000] */ - {0x00e5aab1, 0x8fa5e5}, /* U+5AB1 [2000] */ - {0x00e5aab3, 0x8fa5e6}, /* U+5AB3 [2000] */ - {0x00e5aab5, 0x8fa5e7}, /* U+5AB5 [2000] */ - {0x00e5aaba, 0x8fa5e8}, /* U+5ABA [2000] */ - {0x00e5aabc, 0x00d5bc}, /* U+5ABC */ - {0x00e5aabd, 0x00d5c0}, /* U+5ABD */ - {0x00e5aabe, 0x00d5bd}, /* U+5ABE */ - {0x00e5aabf, 0x8fa5e9}, /* U+5ABF [2000] */ - {0x00e5ab81, 0x00b2c7}, /* U+5AC1 */ - {0x00e5ab82, 0x00d5bf}, /* U+5AC2 */ - {0x00e5ab84, 0x00affa}, /* U+5AC4 [2000] */ - {0x00e5ab89, 0x00bcbb}, /* U+5AC9 */ - {0x00e5ab8b, 0x00d5be}, /* U+5ACB */ - {0x00e5ab8c, 0x00b7f9}, /* U+5ACC */ - {0x00e5ab90, 0x00d5cc}, /* U+5AD0 */ - {0x00e5ab96, 0x00d5c5}, /* U+5AD6 */ - {0x00e5ab97, 0x00d5c2}, /* U+5AD7 */ - {0x00e5ab9a, 0x8fa5ea}, /* U+5ADA [2000] */ - {0x00e5ab9c, 0x8fa5eb}, /* U+5ADC [2000] */ - {0x00e5aba0, 0x8fa5ec}, /* U+5AE0 [2000] */ - {0x00e5aba1, 0x00c3e4}, /* U+5AE1 */ - {0x00e5aba3, 0x00d5c1}, /* U+5AE3 */ - {0x00e5aba5, 0x8fa5ed}, /* U+5AE5 [2000] */ - {0x00e5aba6, 0x00d5c3}, /* U+5AE6 */ - {0x00e5aba9, 0x00d5c4}, /* U+5AE9 */ - {0x00e5abae, 0x8fa5ef}, /* U+5AEE [2000] */ - {0x00e5abb0, 0x8fa5ee}, /* U+5AF0 [2000] */ - {0x00e5abb5, 0x8fa5f0}, /* U+5AF5 [2000] */ - {0x00e5abba, 0x00d5c6}, /* U+5AFA */ - {0x00e5abbb, 0x00d5c7}, /* U+5AFB */ - {0x00e5ac80, 0x8fa5f1}, /* U+5B00 [2000] */ - {0x00e5ac88, 0x8fa5f2}, /* U+5B08 [2000] */ - {0x00e5ac89, 0x00b4f2}, /* U+5B09 */ - {0x00e5ac8b, 0x00d5c9}, /* U+5B0B */ - {0x00e5ac8c, 0x00d5c8}, /* U+5B0C */ - {0x00e5ac96, 0x00d5ca}, /* U+5B16 */ - {0x00e5ac97, 0x8fa5f3}, /* U+5B17 [2000] */ - {0x00e5ac99, 0x00affc}, /* U+5B19 [2000] */ - {0x00e5aca2, 0x00beee}, /* U+5B22 */ - {0x00e5aca5, 0x00affd}, /* U+5B25 [2000] */ - {0x00e5acaa, 0x00d5cd}, /* U+5B2A */ - {0x00e5acac, 0x00c4dc}, /* U+5B2C */ - {0x00e5acad, 0x8fa5f5}, /* U+5B2D [2000] */ - {0x00e5acb0, 0x00b1c5}, /* U+5B30 */ - {0x00e5acb2, 0x00d5cb}, /* U+5B32 */ - {0x00e5acb4, 0x8fa5f4}, /* U+5B34 [2000] */ - {0x00e5acb6, 0x00d5ce}, /* U+5B36 */ - {0x00e5acbe, 0x00d5cf}, /* U+5B3E */ - {0x00e5ad80, 0x00d5d2}, /* U+5B40 */ - {0x00e5ad81, 0x00cfd5}, /* U+5B41 [2000] */ - {0x00e5ad83, 0x00d5d0}, /* U+5B43 */ - {0x00e5ad85, 0x00d5d1}, /* U+5B45 */ - {0x00e5ad8c, 0x8fa5f6}, /* U+5B4C [2000] */ - {0x00e5ad90, 0x00bbd2}, /* U+5B50 */ - {0x00e5ad91, 0x00d5d3}, /* U+5B51 */ - {0x00e5ad92, 0x8fa5f7}, /* U+5B52 [2000] */ - {0x00e5ad94, 0x00b9a6}, /* U+5B54 */ - {0x00e5ad95, 0x00d5d4}, /* U+5B55 */ - {0x00e5ad96, 0x00cfd6}, /* U+5B56 [2000] */ - {0x00e5ad97, 0x00bbfa}, /* U+5B57 */ - {0x00e5ad98, 0x00c2b8}, /* U+5B58 */ - {0x00e5ad9a, 0x00d5d5}, /* U+5B5A */ - {0x00e5ad9b, 0x00d5d6}, /* U+5B5B */ - {0x00e5ad9c, 0x00bbda}, /* U+5B5C */ - {0x00e5ad9d, 0x00b9a7}, /* U+5B5D */ - {0x00e5ad9f, 0x00ccd2}, /* U+5B5F */ - {0x00e5ada3, 0x00b5a8}, /* U+5B63 */ - {0x00e5ada4, 0x00b8c9}, /* U+5B64 */ - {0x00e5ada5, 0x00d5d7}, /* U+5B65 */ - {0x00e5ada6, 0x00b3d8}, /* U+5B66 */ - {0x00e5ada8, 0x8fa5f8}, /* U+5B68 [2000] */ - {0x00e5ada9, 0x00d5d8}, /* U+5B69 */ - {0x00e5adab, 0x00c2b9}, /* U+5B6B */ - {0x00e5adaf, 0x8fa5f9}, /* U+5B6F [2000] */ - {0x00e5adb0, 0x00d5d9}, /* U+5B70 */ - {0x00e5adb1, 0x00d6a3}, /* U+5B71 */ - {0x00e5adb3, 0x00d5da}, /* U+5B73 */ - {0x00e5adb5, 0x00d5db}, /* U+5B75 */ - {0x00e5adb8, 0x00d5dc}, /* U+5B78 */ - {0x00e5adba, 0x00d5de}, /* U+5B7A */ - {0x00e5adbc, 0x8fa5fa}, /* U+5B7C [2000] */ - {0x00e5adbd, 0x00cfd7}, /* U+5B7D [2000] */ - {0x00e5adbf, 0x8fa5fb}, /* U+5B7F [2000] */ - {0x00e5ae80, 0x00d5df}, /* U+5B80 */ - {0x00e5ae81, 0x8fa5fc}, /* U+5B81 [2000] */ - {0x00e5ae83, 0x00d5e0}, /* U+5B83 */ - {0x00e5ae84, 0x8fa5fd}, /* U+5B84 [2000] */ - {0x00e5ae85, 0x00c2f0}, /* U+5B85 */ - {0x00e5ae87, 0x00b1a7}, /* U+5B87 */ - {0x00e5ae88, 0x00bce9}, /* U+5B88 */ - {0x00e5ae89, 0x00b0c2}, /* U+5B89 */ - {0x00e5ae8b, 0x00c1d7}, /* U+5B8B */ - {0x00e5ae8c, 0x00b4b0}, /* U+5B8C */ - {0x00e5ae8d, 0x00bcb5}, /* U+5B8D */ - {0x00e5ae8f, 0x00b9a8}, /* U+5B8F */ - {0x00e5ae93, 0x00cfd8}, /* U+5B93 [2000] */ - {0x00e5ae95, 0x00c5e6}, /* U+5B95 */ - {0x00e5ae96, 0x8fa8a1}, /* U+5B96 [2000] */ - {0x00e5ae97, 0x00bda1}, /* U+5B97 */ - {0x00e5ae98, 0x00b4b1}, /* U+5B98 */ - {0x00e5ae99, 0x00c3e8}, /* U+5B99 */ - {0x00e5ae9a, 0x00c4ea}, /* U+5B9A */ - {0x00e5ae9b, 0x00b0b8}, /* U+5B9B */ - {0x00e5ae9c, 0x00b5b9}, /* U+5B9C */ - {0x00e5ae9d, 0x00caf5}, /* U+5B9D */ - {0x00e5ae9f, 0x00bcc2}, /* U+5B9F */ - {0x00e5aea2, 0x00b5d2}, /* U+5BA2 */ - {0x00e5aea3, 0x00c0eb}, /* U+5BA3 */ - {0x00e5aea4, 0x00bcbc}, /* U+5BA4 */ - {0x00e5aea5, 0x00cda8}, /* U+5BA5 */ - {0x00e5aea6, 0x00d5e1}, /* U+5BA6 */ - {0x00e5aeac, 0x8fa8a2}, /* U+5BAC [2000] */ - {0x00e5aeae, 0x00b5dc}, /* U+5BAE */ - {0x00e5aeb0, 0x00bacb}, /* U+5BB0 */ - {0x00e5aeb3, 0x00b3b2}, /* U+5BB3 */ - {0x00e5aeb4, 0x00b1e3}, /* U+5BB4 */ - {0x00e5aeb5, 0x00beac}, /* U+5BB5 */ - {0x00e5aeb6, 0x00b2c8}, /* U+5BB6 */ - {0x00e5aeb8, 0x00d5e2}, /* U+5BB8 */ - {0x00e5aeb9, 0x00cdc6}, /* U+5BB9 */ - {0x00e5aebf, 0x00bdc9}, /* U+5BBF */ - {0x00e5af80, 0x8fa8a4}, /* U+5BC0 [2000] */ - {0x00e5af82, 0x00bce4}, /* U+5BC2 */ - {0x00e5af83, 0x00d5e3}, /* U+5BC3 */ - {0x00e5af84, 0x00b4f3}, /* U+5BC4 */ - {0x00e5af85, 0x00c6d2}, /* U+5BC5 */ - {0x00e5af86, 0x00cca9}, /* U+5BC6 */ - {0x00e5af87, 0x00d5e4}, /* U+5BC7 */ - {0x00e5af89, 0x00d5e5}, /* U+5BC9 */ - {0x00e5af8c, 0x00c9d9}, /* U+5BCC */ - {0x00e5af8e, 0x8fa8a6}, /* U+5BCE [2000] */ - {0x00e5af90, 0x00d5e7}, /* U+5BD0 */ - {0x00e5af92, 0x00b4a8}, /* U+5BD2 */ - {0x00e5af93, 0x00b6f7}, /* U+5BD3 */ - {0x00e5af94, 0x00d5e6}, /* U+5BD4 */ - {0x00e5af96, 0x8fa8a7}, /* U+5BD6 [2000] */ - {0x00e5af98, 0x00cfd9}, /* U+5BD8 [2000] */ - {0x00e5af9b, 0x00b4b2}, /* U+5BDB */ - {0x00e5af9d, 0x00bfb2}, /* U+5BDD */ - {0x00e5af9e, 0x00d5eb}, /* U+5BDE */ - {0x00e5af9f, 0x00bba1}, /* U+5BDF */ - {0x00e5afa1, 0x00b2c9}, /* U+5BE1 */ - {0x00e5afa2, 0x00d5ea}, /* U+5BE2 */ - {0x00e5afa4, 0x00d5e8}, /* U+5BE4 */ - {0x00e5afa5, 0x00d5ec}, /* U+5BE5 */ - {0x00e5afa6, 0x00d5e9}, /* U+5BE6 */ - {0x00e5afa7, 0x00c7ab}, /* U+5BE7 */ - {0x00e5afa8, 0x00dccd}, /* U+5BE8 */ - {0x00e5afa9, 0x00bfb3}, /* U+5BE9 */ - {0x00e5afab, 0x00d5ed}, /* U+5BEB */ - {0x00e5afac, 0x00cfda}, /* U+5BEC [2000] */ - {0x00e5afae, 0x00cec0}, /* U+5BEE */ - {0x00e5afb0, 0x00d5ee}, /* U+5BF0 */ - {0x00e5afb1, 0x8fa8aa}, /* U+5BF1 [2000] */ - {0x00e5afb3, 0x00d5f0}, /* U+5BF3 */ - {0x00e5afb5, 0x00c3fe}, /* U+5BF5 */ - {0x00e5afb6, 0x00d5ef}, /* U+5BF6 */ - {0x00e5afb8, 0x00c0a3}, /* U+5BF8 */ - {0x00e5afba, 0x00bbfb}, /* U+5BFA */ - {0x00e5afbd, 0x8fa8ab}, /* U+5BFD [2000] */ - {0x00e5afbe, 0x00c2d0}, /* U+5BFE */ - {0x00e5afbf, 0x00bcf7}, /* U+5BFF */ - {0x00e5b081, 0x00c9f5}, /* U+5C01 */ - {0x00e5b082, 0x00c0ec}, /* U+5C02 */ - {0x00e5b083, 0x8fa8ad}, /* U+5C03 [2000] */ - {0x00e5b084, 0x00bccd}, /* U+5C04 */ - {0x00e5b085, 0x00d5f1}, /* U+5C05 */ - {0x00e5b086, 0x00bead}, /* U+5C06 */ - {0x00e5b087, 0x00d5f2}, /* U+5C07 */ - {0x00e5b088, 0x00d5f3}, /* U+5C08 */ - {0x00e5b089, 0x00b0d3}, /* U+5C09 */ - {0x00e5b08a, 0x00c2ba}, /* U+5C0A */ - {0x00e5b08b, 0x00bfd2}, /* U+5C0B */ - {0x00e5b08d, 0x00d5f4}, /* U+5C0D */ - {0x00e5b08e, 0x00c6b3}, /* U+5C0E */ - {0x00e5b08f, 0x00beae}, /* U+5C0F */ - {0x00e5b091, 0x00beaf}, /* U+5C11 */ - {0x00e5b092, 0x00cfdb}, /* U+5C12 [2000] */ - {0x00e5b093, 0x00d5f5}, /* U+5C13 */ - {0x00e5b096, 0x00c0ed}, /* U+5C16 */ - {0x00e5b09a, 0x00beb0}, /* U+5C1A */ - {0x00e5b09e, 0x00cfdc}, /* U+5C1E [2000] */ - {0x00e5b0a0, 0x00d5f6}, /* U+5C20 */ - {0x00e5b0a2, 0x00d5f7}, /* U+5C22 */ - {0x00e5b0a3, 0x00cfdd}, /* U+5C23 [2000] */ - {0x00e5b0a4, 0x00cce0}, /* U+5C24 */ - {0x00e5b0a8, 0x00d5f8}, /* U+5C28 */ - {0x00e5b0a9, 0x8fa8ae}, /* U+5C29 [2000] */ - {0x00e5b0ab, 0x00cfde}, /* U+5C2B [2000] */ - {0x00e5b0ad, 0x00b6c6}, /* U+5C2D */ - {0x00e5b0b0, 0x8fa8af}, /* U+5C30 [2000] */ - {0x00e5b0b1, 0x00bda2}, /* U+5C31 */ - {0x00e5b0b8, 0x00d5f9}, /* U+5C38 */ - {0x00e5b0b9, 0x00d5fa}, /* U+5C39 */ - {0x00e5b0ba, 0x00bcdc}, /* U+5C3A */ - {0x00e5b0bb, 0x00bfac}, /* U+5C3B */ - {0x00e5b0bc, 0x00c6f4}, /* U+5C3C */ - {0x00e5b0bd, 0x00bfd4}, /* U+5C3D */ - {0x00e5b0be, 0x00c8f8}, /* U+5C3E */ - {0x00e5b0bf, 0x00c7a2}, /* U+5C3F */ - {0x00e5b180, 0x00b6c9}, /* U+5C40 */ - {0x00e5b181, 0x00d5fb}, /* U+5C41 */ - {0x00e5b185, 0x00b5ef}, /* U+5C45 */ - {0x00e5b186, 0x00d5fc}, /* U+5C46 */ - {0x00e5b188, 0x00b6fe}, /* U+5C48 */ - {0x00e5b18a, 0x00c6cf}, /* U+5C4A */ - {0x00e5b18b, 0x00b2b0}, /* U+5C4B */ - {0x00e5b18d, 0x00bbd3}, /* U+5C4D */ - {0x00e5b18e, 0x00d5fd}, /* U+5C4E */ - {0x00e5b18f, 0x00d6a2}, /* U+5C4F */ - {0x00e5b190, 0x00d6a1}, /* U+5C50 */ - {0x00e5b191, 0x00b6fd}, /* U+5C51 */ - {0x00e5b193, 0x00d5fe}, /* U+5C53 */ - {0x00e5b195, 0x00c5b8}, /* U+5C55 */ - {0x00e5b19b, 0x00fefb}, /* U+5C5B [2004] */ - {0x00e5b19e, 0x00c2b0}, /* U+5C5E */ - {0x00e5b19f, 0x8fa8b1}, /* U+5C5F [2000] */ - {0x00e5b1a0, 0x00c5cb}, /* U+5C60 */ - {0x00e5b1a1, 0x00bcc8}, /* U+5C61 */ - {0x00e5b1a2, 0x00cfe0}, /* U+5C62 [2000] */ - {0x00e5b1a3, 0x8fa8b2}, /* U+5C63 [2000] */ - {0x00e5b1a4, 0x00c1d8}, /* U+5C64 */ - {0x00e5b1a5, 0x00cdfa}, /* U+5C65 */ - {0x00e5b1a7, 0x8fa8b3}, /* U+5C67 [2000] */ - {0x00e5b1a8, 0x8fa8b4}, /* U+5C68 [2000] */ - {0x00e5b1a9, 0x8fa8b5}, /* U+5C69 [2000] */ - {0x00e5b1ac, 0x00d6a4}, /* U+5C6C */ - {0x00e5b1ae, 0x00d6a5}, /* U+5C6E */ - {0x00e5b1af, 0x00c6d6}, /* U+5C6F */ - {0x00e5b1b0, 0x8fa8b6}, /* U+5C70 [2000] */ - {0x00e5b1b1, 0x00bbb3}, /* U+5C71 */ - {0x00e5b1b6, 0x00d6a7}, /* U+5C76 */ - {0x00e5b1b9, 0x00d6a8}, /* U+5C79 */ - {0x00e5b1ba, 0x00cfe4}, /* U+5C7A [2000] */ - {0x00e5b1bc, 0x8fa8b9}, /* U+5C7C [2000] */ - {0x00e5b288, 0x8fa8bc}, /* U+5C88 [2000] */ - {0x00e5b28a, 0x8fa8bd}, /* U+5C8A [2000] */ - {0x00e5b28c, 0x00d6a9}, /* U+5C8C */ - {0x00e5b28f, 0x00cfe5}, /* U+5C8F [2000] */ - {0x00e5b290, 0x00b4f4}, /* U+5C90 */ - {0x00e5b291, 0x00d6aa}, /* U+5C91 */ - {0x00e5b294, 0x00d6ab}, /* U+5C94 */ - {0x00e5b29f, 0x00cfe6}, /* U+5C9F [2000] */ - {0x00e5b2a0, 0x8fa8c1}, /* U+5CA0 [2000] */ - {0x00e5b2a1, 0x00b2ac}, /* U+5CA1 */ - {0x00e5b2a2, 0x8fa8c2}, /* U+5CA2 [2000] */ - {0x00e5b2a3, 0x00cfe7}, /* U+5CA3 [2000] */ - {0x00e5b2a6, 0x8fa8c3}, /* U+5CA6 [2000] */ - {0x00e5b2a7, 0x8fa8c4}, /* U+5CA7 [2000] */ - {0x00e5b2a8, 0x00c1bb}, /* U+5CA8 */ - {0x00e5b2a9, 0x00b4e4}, /* U+5CA9 */ - {0x00e5b2aa, 0x00cfe8}, /* U+5CAA [2000] */ - {0x00e5b2ab, 0x00d6ad}, /* U+5CAB */ - {0x00e5b2ac, 0x00cca8}, /* U+5CAC */ - {0x00e5b2ad, 0x8fa8c6}, /* U+5CAD [2000] */ - {0x00e5b2b1, 0x00c2d2}, /* U+5CB1 */ - {0x00e5b2b3, 0x00b3d9}, /* U+5CB3 */ - {0x00e5b2b5, 0x8fa8c7}, /* U+5CB5 [2000] */ - {0x00e5b2b6, 0x00d6af}, /* U+5CB6 */ - {0x00e5b2b7, 0x00d6b1}, /* U+5CB7 */ - {0x00e5b2b8, 0x00b4df}, /* U+5CB8 */ - {0x00e5b2ba, 0x00cfe9}, /* U+5CBA [2000] */ - {0x00e5b2bb, 0x00d6ae}, /* U+5CBB */ - {0x00e5b2bc, 0x00d6b0}, /* U+5CBC */ - {0x00e5b2be, 0x00d6b3}, /* U+5CBE */ - {0x00e5b385, 0x00d6b2}, /* U+5CC5 */ - {0x00e5b387, 0x00d6b4}, /* U+5CC7 */ - {0x00e5b389, 0x8fa8c9}, /* U+5CC9 [2000] */ - {0x00e5b38b, 0x00cfea}, /* U+5CCB [2000] */ - {0x00e5b390, 0x00cfeb}, /* U+5CD0 [2000] */ - {0x00e5b392, 0x00cfec}, /* U+5CD2 [2000] */ - {0x00e5b399, 0x00d6b5}, /* U+5CD9 */ - {0x00e5b3a0, 0x00c6bd}, /* U+5CE0 */ - {0x00e5b3a1, 0x00b6ae}, /* U+5CE1 */ - {0x00e5b3a8, 0x00b2e5}, /* U+5CE8 */ - {0x00e5b3a9, 0x00d6b6}, /* U+5CE9 */ - {0x00e5b3aa, 0x00d6bb}, /* U+5CEA */ - {0x00e5b3ad, 0x00d6b9}, /* U+5CED */ - {0x00e5b3af, 0x00caf7}, /* U+5CEF */ - {0x00e5b3b0, 0x00caf6}, /* U+5CF0 */ - {0x00e5b3b4, 0x00cfed}, /* U+5CF4 [2000] */ - {0x00e5b3b6, 0x00c5e7}, /* U+5CF6 */ - {0x00e5b3ba, 0x00d6b8}, /* U+5CFA */ - {0x00e5b3bb, 0x00bdd4}, /* U+5CFB */ - {0x00e5b3bd, 0x00d6b7}, /* U+5CFD */ - {0x00e5b486, 0x8fa8cc}, /* U+5D06 [2000] */ - {0x00e5b487, 0x00bff2}, /* U+5D07 */ - {0x00e5b48b, 0x00d6bc}, /* U+5D0B */ - {0x00e5b48d, 0x00cff0}, /* U+5D0D [2000] */ - {0x00e5b48e, 0x00baea}, /* U+5D0E */ - {0x00e5b490, 0x8fa8cd}, /* U+5D10 [2000] */ - {0x00e5b491, 0x00d6c2}, /* U+5D11 */ - {0x00e5b494, 0x00d6c3}, /* U+5D14 */ - {0x00e5b495, 0x00d6bd}, /* U+5D15 */ - {0x00e5b496, 0x00b3b3}, /* U+5D16 */ - {0x00e5b497, 0x00d6be}, /* U+5D17 */ - {0x00e5b498, 0x00d6c7}, /* U+5D18 */ - {0x00e5b499, 0x00d6c6}, /* U+5D19 */ - {0x00e5b49a, 0x00d6c5}, /* U+5D1A */ - {0x00e5b49b, 0x00d6c1}, /* U+5D1B */ - {0x00e5b49d, 0x8fa8cf}, /* U+5D1D [2000] */ - {0x00e5b49f, 0x00d6c0}, /* U+5D1F */ - {0x00e5b4a0, 0x8fa8d0}, /* U+5D20 [2000] */ - {0x00e5b4a2, 0x00d6c4}, /* U+5D22 */ - {0x00e5b4a4, 0x8fa8d1}, /* U+5D24 [2000] */ - {0x00e5b4a6, 0x8fa8d2}, /* U+5D26 [2000] */ - {0x00e5b4a7, 0x00cff1}, /* U+5D27 [2000] */ - {0x00e5b4a9, 0x00caf8}, /* U+5D29 */ - {0x00e5b4ab, 0x8fa8ce}, /* U+5D2B [2000] */ - {0x00e5b4b1, 0x8fa8d3}, /* U+5D31 [2000] */ - {0x00e5b4b9, 0x8fa8d4}, /* U+5D39 [2000] */ - {0x00e5b582, 0x8fa8d5}, /* U+5D42 [2000] */ - {0x00e5b586, 0x00cff3}, /* U+5D46 [2000] */ - {0x00e5b587, 0x00cff4}, /* U+5D47 [2000] */ - {0x00e5b58a, 0x00cff6}, /* U+5D4A [2000] */ - {0x00e5b58b, 0x00d6cb}, /* U+5D4B */ - {0x00e5b58c, 0x00d6c8}, /* U+5D4C */ - {0x00e5b58e, 0x00d6ca}, /* U+5D4E */ - {0x00e5b590, 0x00cdf2}, /* U+5D50 */ - {0x00e5b592, 0x00d6c9}, /* U+5D52 */ - {0x00e5b593, 0x00cff5}, /* U+5D53 [2000] */ - {0x00e5b59c, 0x00d6bf}, /* U+5D5C */ - {0x00e5b5a1, 0x8fa8d7}, /* U+5D61 [2000] */ - {0x00e5b5a9, 0x00bff3}, /* U+5D69 */ - {0x00e5b5aa, 0x8fa8d8}, /* U+5D6A [2000] */ - {0x00e5b5ac, 0x00d6cc}, /* U+5D6C */ - {0x00e5b5ad, 0x00cff7}, /* U+5D6D [2000] */ - {0x00e5b5af, 0x00bab7}, /* U+5D6F */ - {0x00e5b5b0, 0x8fa8da}, /* U+5D70 [2000] */ - {0x00e5b5b3, 0x00d6cd}, /* U+5D73 */ - {0x00e5b5b6, 0x00d6ce}, /* U+5D76 */ - {0x00e5b681, 0x00cff8}, /* U+5D81 [2000] */ - {0x00e5b682, 0x00d6d1}, /* U+5D82 */ - {0x00e5b684, 0x00d6d0}, /* U+5D84 */ - {0x00e5b687, 0x00d6cf}, /* U+5D87 */ - {0x00e5b688, 0x8fa8dd}, /* U+5D88 [2000] */ - {0x00e5b68b, 0x00c5e8}, /* U+5D8B */ - {0x00e5b68c, 0x00d6ba}, /* U+5D8C */ - {0x00e5b690, 0x00d6d7}, /* U+5D90 */ - {0x00e5b692, 0x8fa8df}, /* U+5D92 [2000] */ - {0x00e5b694, 0x8fa8e0}, /* U+5D94 [2000] */ - {0x00e5b697, 0x8fa8e1}, /* U+5D97 [2000] */ - {0x00e5b699, 0x8fa8e2}, /* U+5D99 [2000] */ - {0x00e5b69d, 0x00d6d3}, /* U+5D9D */ - {0x00e5b6a0, 0x00cff9}, /* U+5DA0 [2000] */ - {0x00e5b6a2, 0x00d6d2}, /* U+5DA2 */ - {0x00e5b6a4, 0x00cffa}, /* U+5DA4 [2000] */ - {0x00e5b6a7, 0x00cffb}, /* U+5DA7 [2000] */ - {0x00e5b6ac, 0x00d6d4}, /* U+5DAC */ - {0x00e5b6ae, 0x00d6d5}, /* U+5DAE */ - {0x00e5b6b0, 0x8fa8e3}, /* U+5DB0 [2000] */ - {0x00e5b6b2, 0x8fa8e4}, /* U+5DB2 [2000] */ - {0x00e5b6b4, 0x8fa8e5}, /* U+5DB4 [2000] */ - {0x00e5b6b7, 0x00d6d8}, /* U+5DB7 */ - {0x00e5b6b8, 0x00cffc}, /* U+5DB8 [2000] */ - {0x00e5b6b9, 0x8fa8e7}, /* U+5DB9 [2000] */ - {0x00e5b6ba, 0x00cee6}, /* U+5DBA */ - {0x00e5b6bc, 0x00d6d9}, /* U+5DBC */ - {0x00e5b6bd, 0x00d6d6}, /* U+5DBD */ - {0x00e5b789, 0x00d6da}, /* U+5DC9 */ - {0x00e5b78b, 0x00cffd}, /* U+5DCB [2000] */ - {0x00e5b78c, 0x00b4e0}, /* U+5DCC */ - {0x00e5b78d, 0x00d6db}, /* U+5DCD */ - {0x00e5b791, 0x8fa8e8}, /* U+5DD1 [2000] */ - {0x00e5b792, 0x00d6dd}, /* U+5DD2 */ - {0x00e5b793, 0x00d6dc}, /* U+5DD3 */ - {0x00e5b796, 0x00d6de}, /* U+5DD6 */ - {0x00e5b797, 0x8fa8e9}, /* U+5DD7 [2000] */ - {0x00e5b798, 0x8fa8ea}, /* U+5DD8 [2000] */ - {0x00e5b79b, 0x00d6df}, /* U+5DDB */ - {0x00e5b79d, 0x00c0ee}, /* U+5DDD */ - {0x00e5b79e, 0x00bda3}, /* U+5DDE */ - {0x00e5b7a0, 0x8fa8eb}, /* U+5DE0 [2000] */ - {0x00e5b7a1, 0x00bde4}, /* U+5DE1 */ - {0x00e5b7a2, 0x00f4a8}, /* U+5DE2 [2000] */ - {0x00e5b7a3, 0x00c1e3}, /* U+5DE3 */ - {0x00e5b7a4, 0x8fa8ed}, /* U+5DE4 [2000] */ - {0x00e5b7a5, 0x00b9a9}, /* U+5DE5 */ - {0x00e5b7a6, 0x00bab8}, /* U+5DE6 */ - {0x00e5b7a7, 0x00b9aa}, /* U+5DE7 */ - {0x00e5b7a8, 0x00b5f0}, /* U+5DE8 */ - {0x00e5b7a9, 0x8fa8ee}, /* U+5DE9 [2000] */ - {0x00e5b7ab, 0x00d6e0}, /* U+5DEB */ - {0x00e5b7ae, 0x00bab9}, /* U+5DEE */ - {0x00e5b7b1, 0x00b8ca}, /* U+5DF1 */ - {0x00e5b7b2, 0x00d6e1}, /* U+5DF2 */ - {0x00e5b7b3, 0x00cca6}, /* U+5DF3 */ - {0x00e5b7b4, 0x00c7c3}, /* U+5DF4 */ - {0x00e5b7b5, 0x00d6e2}, /* U+5DF5 */ - {0x00e5b7b7, 0x00b9ab}, /* U+5DF7 */ - {0x00e5b7bb, 0x00b4ac}, /* U+5DFB */ - {0x00e5b7bd, 0x00c3a7}, /* U+5DFD */ - {0x00e5b7be, 0x00b6d2}, /* U+5DFE */ - {0x00e5b880, 0x8fa8f0}, /* U+5E00 [2000] */ - {0x00e5b882, 0x00bbd4}, /* U+5E02 */ - {0x00e5b883, 0x00c9db}, /* U+5E03 */ - {0x00e5b886, 0x00c8c1}, /* U+5E06 */ - {0x00e5b88b, 0x00d6e3}, /* U+5E0B */ - {0x00e5b88c, 0x00b4f5}, /* U+5E0C */ - {0x00e5b891, 0x00d6e6}, /* U+5E11 */ - {0x00e5b892, 0x8fa8f2}, /* U+5E12 [2000] */ - {0x00e5b894, 0x00f4a9}, /* U+5E14 [2000] */ - {0x00e5b895, 0x8fa8f3}, /* U+5E15 [2000] */ - {0x00e5b896, 0x00c4a1}, /* U+5E16 */ - {0x00e5b898, 0x00f4aa}, /* U+5E18 [2000] */ - {0x00e5b899, 0x00d6e5}, /* U+5E19 */ - {0x00e5b89a, 0x00d6e4}, /* U+5E1A */ - {0x00e5b89b, 0x00d6e7}, /* U+5E1B */ - {0x00e5b89d, 0x00c4eb}, /* U+5E1D */ - {0x00e5b89f, 0x8fa8f5}, /* U+5E1F [2000] */ - {0x00e5b8a5, 0x00bfe3}, /* U+5E25 */ - {0x00e5b8ab, 0x00bbd5}, /* U+5E2B */ - {0x00e5b8ad, 0x00c0ca}, /* U+5E2D */ - {0x00e5b8ae, 0x8fa8f6}, /* U+5E2E [2000] */ - {0x00e5b8af, 0x00c2d3}, /* U+5E2F */ - {0x00e5b8b0, 0x00b5a2}, /* U+5E30 */ - {0x00e5b8b3, 0x00c4a2}, /* U+5E33 */ - {0x00e5b8b6, 0x00d6e8}, /* U+5E36 */ - {0x00e5b8b7, 0x00d6e9}, /* U+5E37 */ - {0x00e5b8b8, 0x00beef}, /* U+5E38 */ - {0x00e5b8bd, 0x00cbb9}, /* U+5E3D */ - {0x00e5b8be, 0x8fa8f7}, /* U+5E3E [2000] */ - {0x00e5b980, 0x00d6ec}, /* U+5E40 */ - {0x00e5b983, 0x00d6eb}, /* U+5E43 */ - {0x00e5b984, 0x00d6ea}, /* U+5E44 */ - {0x00e5b985, 0x00c9fd}, /* U+5E45 */ - {0x00e5b987, 0x00d6f3}, /* U+5E47 */ - {0x00e5b989, 0x8fa8f8}, /* U+5E49 [2000] */ - {0x00e5b98c, 0x00cbda}, /* U+5E4C */ - {0x00e5b98e, 0x00d6ed}, /* U+5E4E */ - {0x00e5b994, 0x00d6ef}, /* U+5E54 */ - {0x00e5b995, 0x00cbeb}, /* U+5E55 */ - {0x00e5b996, 0x8fa8fa}, /* U+5E56 [2000] */ - {0x00e5b997, 0x00d6ee}, /* U+5E57 */ - {0x00e5b998, 0x00f4ab}, /* U+5E58 [2000] */ - {0x00e5b99e, 0x00f4ac}, /* U+5E5E [2000] */ - {0x00e5b99f, 0x00d6f0}, /* U+5E5F */ - {0x00e5b9a1, 0x00c8a8}, /* U+5E61 */ - {0x00e5b9a2, 0x00d6f1}, /* U+5E62 */ - {0x00e5b9a3, 0x00cabe}, /* U+5E63 */ - {0x00e5b9a4, 0x00d6f2}, /* U+5E64 */ - {0x00e5b9ab, 0x8fa8fc}, /* U+5E6B [2000] */ - {0x00e5b9ac, 0x8fa8fd}, /* U+5E6C [2000] */ - {0x00e5b9ad, 0x8fa8fe}, /* U+5E6D [2000] */ - {0x00e5b9ae, 0x8faca1}, /* U+5E6E [2000] */ - {0x00e5b9b2, 0x00b4b3}, /* U+5E72 */ - {0x00e5b9b3, 0x00cabf}, /* U+5E73 */ - {0x00e5b9b4, 0x00c7af}, /* U+5E74 */ - {0x00e5b9b5, 0x00d6f4}, /* U+5E75 */ - {0x00e5b9b6, 0x00d6f5}, /* U+5E76 */ - {0x00e5b9b7, 0x00fefc}, /* U+5E77 [2004] */ - {0x00e5b9b8, 0x00b9ac}, /* U+5E78 */ - {0x00e5b9b9, 0x00b4b4}, /* U+5E79 */ - {0x00e5b9ba, 0x00d6f6}, /* U+5E7A */ - {0x00e5b9bb, 0x00b8b8}, /* U+5E7B */ - {0x00e5b9bc, 0x00cdc4}, /* U+5E7C */ - {0x00e5b9bd, 0x00cda9}, /* U+5E7D */ - {0x00e5b9be, 0x00b4f6}, /* U+5E7E */ - {0x00e5b9bf, 0x00d6f8}, /* U+5E7F */ - {0x00e5ba81, 0x00c4a3}, /* U+5E81 */ - {0x00e5ba83, 0x00b9ad}, /* U+5E83 */ - {0x00e5ba84, 0x00beb1}, /* U+5E84 */ - {0x00e5ba87, 0x00c8df}, /* U+5E87 */ - {0x00e5ba8a, 0x00beb2}, /* U+5E8A */ - {0x00e5ba8f, 0x00bdf8}, /* U+5E8F */ - {0x00e5ba95, 0x00c4ec}, /* U+5E95 */ - {0x00e5ba96, 0x00caf9}, /* U+5E96 */ - {0x00e5ba97, 0x00c5b9}, /* U+5E97 */ - {0x00e5ba9a, 0x00b9ae}, /* U+5E9A */ - {0x00e5ba9c, 0x00c9dc}, /* U+5E9C */ - {0x00e5baa0, 0x00d6f9}, /* U+5EA0 */ - {0x00e5baa5, 0x8faca3}, /* U+5EA5 [2000] */ - {0x00e5baa6, 0x00c5d9}, /* U+5EA6 */ - {0x00e5baa7, 0x00bac2}, /* U+5EA7 */ - {0x00e5baaa, 0x8faca4}, /* U+5EAA [2000] */ - {0x00e5baab, 0x00b8cb}, /* U+5EAB */ - {0x00e5baac, 0x8faca5}, /* U+5EAC [2000] */ - {0x00e5baad, 0x00c4ed}, /* U+5EAD */ - {0x00e5bab5, 0x00b0c3}, /* U+5EB5 */ - {0x00e5bab6, 0x00bdee}, /* U+5EB6 */ - {0x00e5bab7, 0x00b9af}, /* U+5EB7 */ - {0x00e5bab8, 0x00cdc7}, /* U+5EB8 */ - {0x00e5bab9, 0x8faca6}, /* U+5EB9 [2000] */ - {0x00e5babe, 0x00f4ad}, /* U+5EBE [2000] */ - {0x00e5babf, 0x8faca7}, /* U+5EBF [2000] */ - {0x00e5bb81, 0x00d6fa}, /* U+5EC1 */ - {0x00e5bb82, 0x00d6fb}, /* U+5EC2 */ - {0x00e5bb83, 0x00c7d1}, /* U+5EC3 */ - {0x00e5bb86, 0x8faca8}, /* U+5EC6 [2000] */ - {0x00e5bb88, 0x00d6fc}, /* U+5EC8 */ - {0x00e5bb89, 0x00cef7}, /* U+5EC9 */ - {0x00e5bb8a, 0x00cfad}, /* U+5ECA */ - {0x00e5bb8b, 0x00f4af}, /* U+5ECB [2000] */ - {0x00e5bb8f, 0x00d6fe}, /* U+5ECF */ - {0x00e5bb90, 0x00d6fd}, /* U+5ED0 */ - {0x00e5bb92, 0x8faca9}, /* U+5ED2 [2000] */ - {0x00e5bb93, 0x00b3c7}, /* U+5ED3 */ - {0x00e5bb96, 0x00d7a1}, /* U+5ED6 */ - {0x00e5bb99, 0x8facaa}, /* U+5ED9 [2000] */ - {0x00e5bb9a, 0x00d7a4}, /* U+5EDA */ - {0x00e5bb9b, 0x00d7a5}, /* U+5EDB */ - {0x00e5bb9d, 0x00d7a3}, /* U+5EDD */ - {0x00e5bb9f, 0x00c9c0}, /* U+5EDF */ - {0x00e5bba0, 0x00beb3}, /* U+5EE0 */ - {0x00e5bba1, 0x00d7a7}, /* U+5EE1 */ - {0x00e5bba2, 0x00d7a6}, /* U+5EE2 */ - {0x00e5bba3, 0x00d7a2}, /* U+5EE3 */ - {0x00e5bba8, 0x00d7a8}, /* U+5EE8 */ - {0x00e5bba9, 0x00d7a9}, /* U+5EE9 */ - {0x00e5bbac, 0x00d7aa}, /* U+5EEC */ - {0x00e5bbb0, 0x00d7ad}, /* U+5EF0 */ - {0x00e5bbb1, 0x00d7ab}, /* U+5EF1 */ - {0x00e5bbb3, 0x00d7ac}, /* U+5EF3 */ - {0x00e5bbb4, 0x00d7ae}, /* U+5EF4 */ - {0x00e5bbb6, 0x00b1e4}, /* U+5EF6 */ - {0x00e5bbb7, 0x00c4ee}, /* U+5EF7 */ - {0x00e5bbb8, 0x00d7af}, /* U+5EF8 */ - {0x00e5bbb9, 0x00f4b0}, /* U+5EF9 [2000] */ - {0x00e5bbba, 0x00b7fa}, /* U+5EFA */ - {0x00e5bbbb, 0x00b2f6}, /* U+5EFB */ - {0x00e5bbbc, 0x00c7b6}, /* U+5EFC */ - {0x00e5bbbd, 0x8facac}, /* U+5EFD [2000] */ - {0x00e5bbbe, 0x00d7b0}, /* U+5EFE */ - {0x00e5bbbf, 0x00c6fb}, /* U+5EFF */ - {0x00e5bc80, 0x00f4b1}, /* U+5F00 [2000] */ - {0x00e5bc81, 0x00cadb}, /* U+5F01 */ - {0x00e5bc82, 0x00f4b2}, /* U+5F02 [2000] */ - {0x00e5bc83, 0x00d7b1}, /* U+5F03 */ - {0x00e5bc84, 0x00cfae}, /* U+5F04 */ - {0x00e5bc87, 0x00f4b3}, /* U+5F07 [2000] */ - {0x00e5bc88, 0x8facad}, /* U+5F08 [2000] */ - {0x00e5bc89, 0x00d7b2}, /* U+5F09 */ - {0x00e5bc8a, 0x00cac0}, /* U+5F0A */ - {0x00e5bc8b, 0x00d7b5}, /* U+5F0B */ - {0x00e5bc8c, 0x00d0a1}, /* U+5F0C */ - {0x00e5bc8d, 0x00d0b1}, /* U+5F0D */ - {0x00e5bc8e, 0x8facae}, /* U+5F0E [2000] */ - {0x00e5bc8f, 0x00bcb0}, /* U+5F0F */ - {0x00e5bc90, 0x00c6f5}, /* U+5F10 */ - {0x00e5bc91, 0x00d7b6}, /* U+5F11 */ - {0x00e5bc93, 0x00b5dd}, /* U+5F13 */ - {0x00e5bc94, 0x00c4a4}, /* U+5F14 */ - {0x00e5bc95, 0x00b0fa}, /* U+5F15 */ - {0x00e5bc96, 0x00d7b7}, /* U+5F16 */ - {0x00e5bc97, 0x00caa6}, /* U+5F17 */ - {0x00e5bc98, 0x00b9b0}, /* U+5F18 */ - {0x00e5bc9b, 0x00c3d0}, /* U+5F1B */ - {0x00e5bc9c, 0x8facaf}, /* U+5F1C [2000] */ - {0x00e5bc9d, 0x00f4b4}, /* U+5F1D [2000] */ - {0x00e5bc9e, 0x8facb1}, /* U+5F1E [2000] */ - {0x00e5bc9f, 0x00c4ef}, /* U+5F1F */ - {0x00e5bca3, 0x00f4b5}, /* U+5F23 [2000] */ - {0x00e5bca5, 0x00ccef}, /* U+5F25 */ - {0x00e5bca6, 0x00b8b9}, /* U+5F26 */ - {0x00e5bca7, 0x00b8cc}, /* U+5F27 */ - {0x00e5bca9, 0x00d7b8}, /* U+5F29 */ - {0x00e5bcad, 0x00d7b9}, /* U+5F2D */ - {0x00e5bcaf, 0x00d7bf}, /* U+5F2F */ - {0x00e5bcb1, 0x00bce5}, /* U+5F31 */ - {0x00e5bcb4, 0x00f4b6}, /* U+5F34 [2000] */ - {0x00e5bcb5, 0x00c4a5}, /* U+5F35 */ - {0x00e5bcb6, 0x00f4b7}, /* U+5F36 [2000] */ - {0x00e5bcb7, 0x00b6af}, /* U+5F37 */ - {0x00e5bcb8, 0x00d7ba}, /* U+5F38 */ - {0x00e5bcbc, 0x00c9ab}, /* U+5F3C */ - {0x00e5bcbd, 0x00f4b8}, /* U+5F3D [2000] */ - {0x00e5bcbe, 0x00c3c6}, /* U+5F3E */ - {0x00e5bd80, 0x00f4b9}, /* U+5F40 [2000] */ - {0x00e5bd81, 0x00d7bb}, /* U+5F41 */ - {0x00e5bd85, 0x00f4ba}, /* U+5F45 [2000] */ - {0x00e5bd87, 0x8facb2}, /* U+5F47 [2000] */ - {0x00e5bd88, 0x00d7bc}, /* U+5F48 */ - {0x00e5bd8a, 0x00b6b0}, /* U+5F4A */ - {0x00e5bd8c, 0x00d7bd}, /* U+5F4C */ - {0x00e5bd8e, 0x00d7be}, /* U+5F4E */ - {0x00e5bd91, 0x00d7c0}, /* U+5F51 */ - {0x00e5bd93, 0x00c5f6}, /* U+5F53 */ - {0x00e5bd94, 0x00f4bb}, /* U+5F54 [2000] */ - {0x00e5bd96, 0x00d7c1}, /* U+5F56 */ - {0x00e5bd97, 0x00d7c2}, /* U+5F57 */ - {0x00e5bd98, 0x00f4bc}, /* U+5F58 [2000] */ - {0x00e5bd99, 0x00d7c3}, /* U+5F59 */ - {0x00e5bd9c, 0x00d7b4}, /* U+5F5C */ - {0x00e5bd9d, 0x00d7b3}, /* U+5F5D */ - {0x00e5bda1, 0x00d7c4}, /* U+5F61 */ - {0x00e5bda2, 0x00b7c1}, /* U+5F62 */ - {0x00e5bda3, 0x8facb3}, /* U+5F63 [2000] */ - {0x00e5bda4, 0x00f4bd}, /* U+5F64 [2000] */ - {0x00e5bda6, 0x00c9a7}, /* U+5F66 */ - {0x00e5bda7, 0x00f4be}, /* U+5F67 [2000] */ - {0x00e5bda9, 0x00bacc}, /* U+5F69 */ - {0x00e5bdaa, 0x00c9b7}, /* U+5F6A */ - {0x00e5bdab, 0x00c4a6}, /* U+5F6B */ - {0x00e5bdac, 0x00c9cb}, /* U+5F6C */ - {0x00e5bdad, 0x00d7c5}, /* U+5F6D */ - {0x00e5bdb0, 0x00beb4}, /* U+5F70 */ - {0x00e5bdb1, 0x00b1c6}, /* U+5F71 */ - {0x00e5bdb2, 0x8facb4}, /* U+5F72 [2000] */ - {0x00e5bdb3, 0x00d7c6}, /* U+5F73 */ - {0x00e5bdb7, 0x00d7c7}, /* U+5F77 */ - {0x00e5bdb9, 0x00ccf2}, /* U+5F79 */ - {0x00e5bdbc, 0x00c8e0}, /* U+5F7C */ - {0x00e5bdbd, 0x00f4bf}, /* U+5F7D [2000] */ - {0x00e5bdbe, 0x8facb5}, /* U+5F7E [2000] */ - {0x00e5bdbf, 0x00d7ca}, /* U+5F7F */ - {0x00e5be80, 0x00b1fd}, /* U+5F80 */ - {0x00e5be81, 0x00c0ac}, /* U+5F81 */ - {0x00e5be82, 0x00d7c9}, /* U+5F82 */ - {0x00e5be83, 0x00d7c8}, /* U+5F83 */ - {0x00e5be84, 0x00b7c2}, /* U+5F84 */ - {0x00e5be85, 0x00c2d4}, /* U+5F85 */ - {0x00e5be87, 0x00d7ce}, /* U+5F87 */ - {0x00e5be88, 0x00d7cc}, /* U+5F88 */ - {0x00e5be89, 0x00f4c0}, /* U+5F89 [2000] */ - {0x00e5be8a, 0x00d7cb}, /* U+5F8A */ - {0x00e5be8b, 0x00cea7}, /* U+5F8B */ - {0x00e5be8c, 0x00b8e5}, /* U+5F8C */ - {0x00e5be8f, 0x8facb6}, /* U+5F8F [2000] */ - {0x00e5be90, 0x00bdf9}, /* U+5F90 */ - {0x00e5be91, 0x00d7cd}, /* U+5F91 */ - {0x00e5be92, 0x00c5cc}, /* U+5F92 */ - {0x00e5be93, 0x00bdbe}, /* U+5F93 */ - {0x00e5be97, 0x00c6c0}, /* U+5F97 */ - {0x00e5be98, 0x00d7d1}, /* U+5F98 */ - {0x00e5be99, 0x00d7d0}, /* U+5F99 */ - {0x00e5be9c, 0x00f4c1}, /* U+5F9C [2000] */ - {0x00e5be9e, 0x00d7cf}, /* U+5F9E */ - {0x00e5bea0, 0x00d7d2}, /* U+5FA0 */ - {0x00e5bea1, 0x00b8e6}, /* U+5FA1 */ - {0x00e5bea2, 0x8facb7}, /* U+5FA2 [2000] */ - {0x00e5bea4, 0x8facb8}, /* U+5FA4 [2000] */ - {0x00e5bea7, 0x00f4c2}, /* U+5FA7 [2000] */ - {0x00e5bea8, 0x00d7d3}, /* U+5FA8 */ - {0x00e5bea9, 0x00c9fc}, /* U+5FA9 */ - {0x00e5beaa, 0x00bddb}, /* U+5FAA */ - {0x00e5bead, 0x00d7d4}, /* U+5FAD */ - {0x00e5beae, 0x00c8f9}, /* U+5FAE */ - {0x00e5beaf, 0x00f4c3}, /* U+5FAF [2000] */ - {0x00e5beb3, 0x00c6c1}, /* U+5FB3 */ - {0x00e5beb4, 0x00c4a7}, /* U+5FB4 */ - {0x00e5beb5, 0x00f4c4}, /* U+5FB5 [2000] */ - {0x00e5beb7, 0x00f4c5}, /* U+5FB7 [2000] */ - {0x00e5beb8, 0x8facb9}, /* U+5FB8 [2000] */ - {0x00e5beb9, 0x00c5b0}, /* U+5FB9 */ - {0x00e5bebc, 0x00d7d5}, /* U+5FBC */ - {0x00e5bebd, 0x00b5ab}, /* U+5FBD */ - {0x00e5bf83, 0x00bfb4}, /* U+5FC3 */ - {0x00e5bf84, 0x8facba}, /* U+5FC4 [2000] */ - {0x00e5bf85, 0x00c9ac}, /* U+5FC5 */ - {0x00e5bf87, 0x8facbc}, /* U+5FC7 [2000] */ - {0x00e5bf89, 0x00f4c6}, /* U+5FC9 [2000] */ - {0x00e5bf8b, 0x8facbd}, /* U+5FCB [2000] */ - {0x00e5bf8c, 0x00b4f7}, /* U+5FCC */ - {0x00e5bf8d, 0x00c7a6}, /* U+5FCD */ - {0x00e5bf92, 0x8facbe}, /* U+5FD2 [2000] */ - {0x00e5bf93, 0x8facbf}, /* U+5FD3 [2000] */ - {0x00e5bf94, 0x8facc0}, /* U+5FD4 [2000] */ - {0x00e5bf96, 0x00d7d6}, /* U+5FD6 */ - {0x00e5bf97, 0x00bbd6}, /* U+5FD7 */ - {0x00e5bf98, 0x00cbba}, /* U+5FD8 */ - {0x00e5bf99, 0x00cbbb}, /* U+5FD9 */ - {0x00e5bf9c, 0x00b1fe}, /* U+5FDC */ - {0x00e5bf9d, 0x00d7db}, /* U+5FDD */ - {0x00e5bf9e, 0x00f4c7}, /* U+5FDE [2000] */ - {0x00e5bfa0, 0x00c3e9}, /* U+5FE0 */ - {0x00e5bfa1, 0x00f4c8}, /* U+5FE1 [2000] */ - {0x00e5bfa2, 0x8facc1}, /* U+5FE2 [2000] */ - {0x00e5bfa4, 0x00d7d8}, /* U+5FE4 */ - {0x00e5bfa9, 0x00f4c9}, /* U+5FE9 [2000] */ - {0x00e5bfab, 0x00b2f7}, /* U+5FEB */ - {0x00e5bfae, 0x8facc2}, /* U+5FEE [2000] */ - {0x00e5bfaf, 0x8facc3}, /* U+5FEF [2000] */ - {0x00e5bfb0, 0x00d8ad}, /* U+5FF0 */ - {0x00e5bfb1, 0x00d7da}, /* U+5FF1 */ - {0x00e5bfb3, 0x8facc4}, /* U+5FF3 [2000] */ - {0x00e5bfb5, 0x00c7b0}, /* U+5FF5 */ - {0x00e5bfb8, 0x00d7d9}, /* U+5FF8 */ - {0x00e5bfbb, 0x00d7d7}, /* U+5FFB */ - {0x00e5bfbc, 0x8facc5}, /* U+5FFC [2000] */ - {0x00e5bfbd, 0x00b9fa}, /* U+5FFD */ - {0x00e5bfbf, 0x00d7dd}, /* U+5FFF */ - {0x00e6808d, 0x00f4ca}, /* U+600D [2000] */ - {0x00e6808e, 0x00d7e3}, /* U+600E */ - {0x00e6808f, 0x00d7e9}, /* U+600F */ - {0x00e68090, 0x00d7e1}, /* U+6010 */ - {0x00e68092, 0x00c5dc}, /* U+6012 */ - {0x00e68094, 0x00f4cb}, /* U+6014 [2000] */ - {0x00e68095, 0x00d7e6}, /* U+6015 */ - {0x00e68096, 0x00c9dd}, /* U+6016 */ - {0x00e68097, 0x8facc7}, /* U+6017 [2000] */ - {0x00e68098, 0x00f4cc}, /* U+6018 [2000] */ - {0x00e68099, 0x00d7e0}, /* U+6019 */ - {0x00e6809b, 0x00d7e5}, /* U+601B */ - {0x00e6809c, 0x00cee7}, /* U+601C */ - {0x00e6809d, 0x00bbd7}, /* U+601D */ - {0x00e680a0, 0x00c2d5}, /* U+6020 */ - {0x00e680a1, 0x00d7de}, /* U+6021 */ - {0x00e680a2, 0x8facc8}, /* U+6022 [2000] */ - {0x00e680a4, 0x8facc9}, /* U+6024 [2000] */ - {0x00e680a5, 0x00b5de}, /* U+6025 */ - {0x00e680a6, 0x00d7e8}, /* U+6026 */ - {0x00e680a7, 0x00c0ad}, /* U+6027 */ - {0x00e680a8, 0x00b1e5}, /* U+6028 */ - {0x00e680a9, 0x00d7e2}, /* U+6029 */ - {0x00e680aa, 0x00b2f8}, /* U+602A */ - {0x00e680ab, 0x00d7e7}, /* U+602B */ - {0x00e680af, 0x00b6b1}, /* U+602F */ - {0x00e680b1, 0x00d7e4}, /* U+6031 */ - {0x00e680b3, 0x00f4cd}, /* U+6033 [2000] */ - {0x00e680b5, 0x00f4ce}, /* U+6035 [2000] */ - {0x00e680ba, 0x00d7ea}, /* U+603A */ - {0x00e68181, 0x00d7ec}, /* U+6041 */ - {0x00e68182, 0x00d7f6}, /* U+6042 */ - {0x00e68183, 0x00d7f4}, /* U+6043 */ - {0x00e68186, 0x00d7f1}, /* U+6046 */ - {0x00e68187, 0x00f4cf}, /* U+6047 [2000] */ - {0x00e6818a, 0x00d7f0}, /* U+604A */ - {0x00e6818b, 0x00cef8}, /* U+604B */ - {0x00e6818c, 0x8faccb}, /* U+604C [2000] */ - {0x00e6818d, 0x00d7f2}, /* U+604D */ - {0x00e68190, 0x00b6b2}, /* U+6050 */ - {0x00e68192, 0x00b9b1}, /* U+6052 */ - {0x00e68195, 0x00bdfa}, /* U+6055 */ - {0x00e68199, 0x00d7f9}, /* U+6059 */ - {0x00e6819a, 0x00d7eb}, /* U+605A */ - {0x00e6819f, 0x00d7ef}, /* U+605F */ - {0x00e681a0, 0x00d7df}, /* U+6060 */ - {0x00e681a2, 0x00b2fa}, /* U+6062 */ - {0x00e681a3, 0x00d7f3}, /* U+6063 */ - {0x00e681a4, 0x00d7f5}, /* U+6064 */ - {0x00e681a5, 0x00c3d1}, /* U+6065 */ - {0x00e681a8, 0x00baa8}, /* U+6068 */ - {0x00e681a9, 0x00b2b8}, /* U+6069 */ - {0x00e681aa, 0x00d7ed}, /* U+606A */ - {0x00e681ab, 0x00d7f8}, /* U+606B */ - {0x00e681ac, 0x00d7f7}, /* U+606C */ - {0x00e681ad, 0x00b6b3}, /* U+606D */ - {0x00e681af, 0x00c2a9}, /* U+606F */ - {0x00e681b0, 0x00b3e6}, /* U+6070 */ - {0x00e681b5, 0x00b7c3}, /* U+6075 */ - {0x00e681b7, 0x00d7ee}, /* U+6077 */ - {0x00e681bf, 0x8faccc}, /* U+607F [2000] */ - {0x00e68281, 0x00d7fa}, /* U+6081 */ - {0x00e68283, 0x00d7fd}, /* U+6083 */ - {0x00e68284, 0x00d8a1}, /* U+6084 */ - {0x00e68289, 0x00bcbd}, /* U+6089 */ - {0x00e6828a, 0x8faccd}, /* U+608A [2000] */ - {0x00e6828b, 0x00d8a7}, /* U+608B */ - {0x00e6828c, 0x00c4f0}, /* U+608C */ - {0x00e6828d, 0x00d7fb}, /* U+608D */ - {0x00e68292, 0x00d8a5}, /* U+6092 */ - {0x00e68294, 0x00b2f9}, /* U+6094 */ - {0x00e68295, 0x8facce}, /* U+6095 [2000] */ - {0x00e68296, 0x00d8a3}, /* U+6096 */ - {0x00e68297, 0x00d8a4}, /* U+6097 */ - {0x00e6829a, 0x00d7fe}, /* U+609A */ - {0x00e6829b, 0x00d8a2}, /* U+609B */ - {0x00e6829d, 0x00f4d1}, /* U+609D [2000] */ - {0x00e6829e, 0x00f4d2}, /* U+609E [2000] */ - {0x00e6829f, 0x00b8e7}, /* U+609F */ - {0x00e682a0, 0x00cdaa}, /* U+60A0 */ - {0x00e682a3, 0x00b4b5}, /* U+60A3 */ - {0x00e682a6, 0x00b1d9}, /* U+60A6 */ - {0x00e682a7, 0x00d8a6}, /* U+60A7 */ - {0x00e682a8, 0x8faccf}, /* U+60A8 [2000] */ - {0x00e682a9, 0x00c7ba}, /* U+60A9 */ - {0x00e682aa, 0x00b0ad}, /* U+60AA */ - {0x00e682b0, 0x8facd1}, /* U+60B0 [2000] */ - {0x00e682b1, 0x8facd2}, /* U+60B1 [2000] */ - {0x00e682b2, 0x00c8e1}, /* U+60B2 */ - {0x00e682b3, 0x00d7dc}, /* U+60B3 */ - {0x00e682b4, 0x00d8ac}, /* U+60B4 */ - {0x00e682b5, 0x00d8b0}, /* U+60B5 */ - {0x00e682b6, 0x00cce5}, /* U+60B6 */ - {0x00e682b8, 0x00d8a9}, /* U+60B8 */ - {0x00e682bc, 0x00c5e9}, /* U+60BC */ - {0x00e682bd, 0x00d8ae}, /* U+60BD */ - {0x00e682be, 0x8facd3}, /* U+60BE [2000] */ - {0x00e68385, 0x00bef0}, /* U+60C5 */ - {0x00e68386, 0x00d8af}, /* U+60C6 */ - {0x00e68387, 0x00c6d7}, /* U+60C7 */ - {0x00e68388, 0x8facd4}, /* U+60C8 [2000] */ - {0x00e6838b, 0x00f4d3}, /* U+60CB [2000] */ - {0x00e68391, 0x00cfc7}, /* U+60D1 */ - {0x00e68393, 0x00d8ab}, /* U+60D3 */ - {0x00e68394, 0x00f4d4}, /* U+60D4 [2000] */ - {0x00e68395, 0x00f4d5}, /* U+60D5 [2000] */ - {0x00e68398, 0x00d8b1}, /* U+60D8 */ - {0x00e68399, 0x8facd5}, /* U+60D9 [2000] */ - {0x00e6839a, 0x00b9fb}, /* U+60DA */ - {0x00e6839b, 0x8facd6}, /* U+60DB [2000] */ - {0x00e6839c, 0x00c0cb}, /* U+60DC */ - {0x00e6839d, 0x00f4d6}, /* U+60DD [2000] */ - {0x00e6839f, 0x00b0d4}, /* U+60DF */ - {0x00e683a0, 0x00d8aa}, /* U+60E0 */ - {0x00e683a1, 0x00d8a8}, /* U+60E1 */ - {0x00e683a3, 0x00c1da}, /* U+60E3 */ - {0x00e683a7, 0x00d7fc}, /* U+60E7 */ - {0x00e683a8, 0x00bbb4}, /* U+60E8 */ - {0x00e683ae, 0x8facd7}, /* U+60EE [2000] */ - {0x00e683b0, 0x00c2c6}, /* U+60F0 */ - {0x00e683b1, 0x00d8bd}, /* U+60F1 */ - {0x00e683b2, 0x8facd8}, /* U+60F2 [2000] */ - {0x00e683b3, 0x00c1db}, /* U+60F3 */ - {0x00e683b4, 0x00d8b8}, /* U+60F4 */ - {0x00e683b5, 0x8facd9}, /* U+60F5 [2000] */ - {0x00e683b6, 0x00d8b5}, /* U+60F6 */ - {0x00e683b7, 0x00d8b6}, /* U+60F7 */ - {0x00e683b8, 0x00f4d7}, /* U+60F8 [2000] */ - {0x00e683b9, 0x00bce6}, /* U+60F9 */ - {0x00e683ba, 0x00d8b9}, /* U+60FA */ - {0x00e683bb, 0x00d8bc}, /* U+60FB */ - {0x00e68480, 0x00d8b7}, /* U+6100 */ - {0x00e68481, 0x00bda5}, /* U+6101 */ - {0x00e68483, 0x00d8ba}, /* U+6103 */ - {0x00e68486, 0x00d8b4}, /* U+6106 */ - {0x00e68488, 0x00ccfc}, /* U+6108 */ - {0x00e68489, 0x00ccfb}, /* U+6109 */ - {0x00e6848d, 0x00d8be}, /* U+610D */ - {0x00e6848e, 0x00d8bf}, /* U+610E */ - {0x00e6848f, 0x00b0d5}, /* U+610F */ - {0x00e68490, 0x8facda}, /* U+6110 [2000] */ - {0x00e68492, 0x8facdb}, /* U+6112 [2000] */ - {0x00e68493, 0x8facdc}, /* U+6113 [2000] */ - {0x00e68495, 0x00d8b3}, /* U+6115 */ - {0x00e68499, 0x8facdd}, /* U+6119 [2000] */ - {0x00e6849a, 0x00b6f2}, /* U+611A */ - {0x00e6849b, 0x00b0a6}, /* U+611B */ - {0x00e6849c, 0x00f4d8}, /* U+611C [2000] */ - {0x00e6849e, 0x8facde}, /* U+611E [2000] */ - {0x00e6849f, 0x00b4b6}, /* U+611F */ - {0x00e684a1, 0x00d8bb}, /* U+6121 */ - {0x00e684a7, 0x00d8c3}, /* U+6127 */ - {0x00e684a8, 0x00d8c2}, /* U+6128 */ - {0x00e684ab, 0x00f4d9}, /* U+612B [2000] */ - {0x00e684ac, 0x00d8c7}, /* U+612C */ - {0x00e684b0, 0x00f4da}, /* U+6130 [2000] */ - {0x00e684b4, 0x00d8c8}, /* U+6134 */ - {0x00e684b7, 0x00f4db}, /* U+6137 [2000] */ - {0x00e684ba, 0x8facdf}, /* U+613A [2000] */ - {0x00e684bc, 0x00d8c6}, /* U+613C */ - {0x00e684bd, 0x00d8c9}, /* U+613D */ - {0x00e684be, 0x00d8c1}, /* U+613E */ - {0x00e684bf, 0x00d8c5}, /* U+613F */ - {0x00e68581, 0x8face1}, /* U+6141 [2000] */ - {0x00e68582, 0x00d8ca}, /* U+6142 */ - {0x00e68584, 0x00d8cb}, /* U+6144 */ - {0x00e68586, 0x8face2}, /* U+6146 [2000] */ - {0x00e68587, 0x00d8c0}, /* U+6147 */ - {0x00e68588, 0x00bbfc}, /* U+6148 */ - {0x00e6858a, 0x00d8c4}, /* U+614A */ - {0x00e6858b, 0x00c2d6}, /* U+614B */ - {0x00e6858c, 0x00b9b2}, /* U+614C */ - {0x00e6858d, 0x00d8b2}, /* U+614D */ - {0x00e6858e, 0x00bfb5}, /* U+614E */ - {0x00e68593, 0x00d8d8}, /* U+6153 */ - {0x00e68595, 0x00cae9}, /* U+6155 */ - {0x00e68598, 0x00d8ce}, /* U+6158 */ - {0x00e68599, 0x00d8cf}, /* U+6159 */ - {0x00e6859a, 0x00d8d0}, /* U+615A */ - {0x00e6859d, 0x00d8d7}, /* U+615D */ - {0x00e6859f, 0x00d8d6}, /* U+615F */ - {0x00e685a0, 0x8face3}, /* U+6160 [2000] */ - {0x00e685a2, 0x00cbfd}, /* U+6162 */ - {0x00e685a3, 0x00b4b7}, /* U+6163 */ - {0x00e685a5, 0x00d8d4}, /* U+6165 */ - {0x00e685a7, 0x00b7c5}, /* U+6167 */ - {0x00e685a8, 0x00b3b4}, /* U+6168 */ - {0x00e685ab, 0x00d8d1}, /* U+616B */ - {0x00e685ae, 0x00ceb8}, /* U+616E */ - {0x00e685af, 0x00d8d3}, /* U+616F */ - {0x00e685b0, 0x00b0d6}, /* U+6170 */ - {0x00e685b1, 0x00d8d5}, /* U+6171 */ - {0x00e685b3, 0x00d8cc}, /* U+6173 */ - {0x00e685b4, 0x00d8d2}, /* U+6174 */ - {0x00e685b5, 0x00d8d9}, /* U+6175 */ - {0x00e685b6, 0x00b7c4}, /* U+6176 */ - {0x00e685b7, 0x00d8cd}, /* U+6177 */ - {0x00e685bc, 0x8face4}, /* U+617C [2000] */ - {0x00e685be, 0x00cddd}, /* U+617E */ - {0x00e68682, 0x00cdab}, /* U+6182 */ - {0x00e68687, 0x00d8dc}, /* U+6187 */ - {0x00e6868a, 0x00d8e0}, /* U+618A */ - {0x00e6868d, 0x00f4dd}, /* U+618D [2000] */ - {0x00e6868e, 0x00c1fe}, /* U+618E */ - {0x00e68690, 0x00cef9}, /* U+6190 */ - {0x00e68691, 0x00d8e1}, /* U+6191 */ - {0x00e68692, 0x8face6}, /* U+6192 [2000] */ - {0x00e68693, 0x8face7}, /* U+6193 [2000] */ - {0x00e68694, 0x00d8de}, /* U+6194 */ - {0x00e68696, 0x00d8db}, /* U+6196 */ - {0x00e68697, 0x8face8}, /* U+6197 [2000] */ - {0x00e68698, 0x8face9}, /* U+6198 [2000] */ - {0x00e68699, 0x00d8da}, /* U+6199 */ - {0x00e6869a, 0x00d8df}, /* U+619A */ - {0x00e686a4, 0x00cab0}, /* U+61A4 */ - {0x00e686a5, 0x8facea}, /* U+61A5 [2000] */ - {0x00e686a7, 0x00c6b4}, /* U+61A7 */ - {0x00e686a8, 0x8faceb}, /* U+61A8 [2000] */ - {0x00e686a9, 0x00b7c6}, /* U+61A9 */ - {0x00e686ab, 0x00d8e2}, /* U+61AB */ - {0x00e686ac, 0x00d8dd}, /* U+61AC */ - {0x00e686ad, 0x8facec}, /* U+61AD [2000] */ - {0x00e686ae, 0x00d8e3}, /* U+61AE */ - {0x00e686b2, 0x00b7fb}, /* U+61B2 */ - {0x00e686b6, 0x00b2b1}, /* U+61B6 */ - {0x00e686b9, 0x00f4e0}, /* U+61B9 [2000] */ - {0x00e686ba, 0x00d8eb}, /* U+61BA */ - {0x00e686bc, 0x00f4df}, /* U+61BC [2000] */ - {0x00e686be, 0x00b4b8}, /* U+61BE */ - {0x00e68783, 0x00d8e9}, /* U+61C3 */ - {0x00e68786, 0x00d8ea}, /* U+61C6 */ - {0x00e68787, 0x00baa9}, /* U+61C7 */ - {0x00e68788, 0x00d8e8}, /* U+61C8 */ - {0x00e68789, 0x00d8e6}, /* U+61C9 */ - {0x00e6878a, 0x00d8e5}, /* U+61CA */ - {0x00e6878b, 0x00d8ec}, /* U+61CB */ - {0x00e6878c, 0x00d8e4}, /* U+61CC */ - {0x00e6878d, 0x00d8ee}, /* U+61CD */ - {0x00e68790, 0x00b2fb}, /* U+61D0 */ - {0x00e68795, 0x8facee}, /* U+61D5 [2000] */ - {0x00e6879d, 0x8facef}, /* U+61DD [2000] */ - {0x00e6879f, 0x8facf0}, /* U+61DF [2000] */ - {0x00e687a3, 0x00d8f0}, /* U+61E3 */ - {0x00e687a6, 0x00d8ef}, /* U+61E6 */ - {0x00e687b2, 0x00c4a8}, /* U+61F2 */ - {0x00e687b4, 0x00d8f3}, /* U+61F4 */ - {0x00e687b5, 0x8facf1}, /* U+61F5 [2000] */ - {0x00e687b6, 0x00d8f1}, /* U+61F6 */ - {0x00e687b7, 0x00d8e7}, /* U+61F7 */ - {0x00e687b8, 0x00b7fc}, /* U+61F8 */ - {0x00e687ba, 0x00d8f2}, /* U+61FA */ - {0x00e687bc, 0x00d8f6}, /* U+61FC */ - {0x00e687bd, 0x00d8f5}, /* U+61FD */ - {0x00e687be, 0x00d8f7}, /* U+61FE */ - {0x00e687bf, 0x00d8f4}, /* U+61FF */ - {0x00e68880, 0x00d8f8}, /* U+6200 */ - {0x00e68888, 0x00d8f9}, /* U+6208 */ - {0x00e68889, 0x00d8fa}, /* U+6209 */ - {0x00e6888a, 0x00caea}, /* U+620A */ - {0x00e6888c, 0x00d8fc}, /* U+620C */ - {0x00e6888d, 0x00d8fb}, /* U+620D */ - {0x00e6888e, 0x00bdbf}, /* U+620E */ - {0x00e68890, 0x00c0ae}, /* U+6210 */ - {0x00e68891, 0x00b2e6}, /* U+6211 */ - {0x00e68892, 0x00b2fc}, /* U+6212 */ - {0x00e68894, 0x00d8fd}, /* U+6214 */ - {0x00e68895, 0x8facf3}, /* U+6215 [2000] */ - {0x00e68896, 0x00b0bf}, /* U+6216 */ - {0x00e6889a, 0x00c0cc}, /* U+621A */ - {0x00e6889b, 0x00d8fe}, /* U+621B */ - {0x00e6889d, 0x00ecc3}, /* U+621D */ - {0x00e6889e, 0x00d9a1}, /* U+621E */ - {0x00e6889f, 0x00b7e1}, /* U+621F */ - {0x00e688a1, 0x00d9a2}, /* U+6221 */ - {0x00e688a2, 0x00f4e2}, /* U+6222 [2000] */ - {0x00e688a3, 0x8facf4}, /* U+6223 [2000] */ - {0x00e688a6, 0x00c0ef}, /* U+6226 */ - {0x00e688a9, 0x8facf5}, /* U+6229 [2000] */ - {0x00e688aa, 0x00d9a3}, /* U+622A */ - {0x00e688ae, 0x00d9a4}, /* U+622E */ - {0x00e688af, 0x00b5ba}, /* U+622F */ - {0x00e688b0, 0x00d9a5}, /* U+6230 */ - {0x00e688b2, 0x00d9a6}, /* U+6232 */ - {0x00e688b3, 0x00d9a7}, /* U+6233 */ - {0x00e688b4, 0x00c2d7}, /* U+6234 */ - {0x00e688b8, 0x00b8cd}, /* U+6238 */ - {0x00e688bb, 0x00cce1}, /* U+623B */ - {0x00e688be, 0x00f4e3}, /* U+623E [2000] */ - {0x00e688bf, 0x00cbbc}, /* U+623F */ - {0x00e68980, 0x00bdea}, /* U+6240 */ - {0x00e68981, 0x00d9a8}, /* U+6241 */ - {0x00e68983, 0x00f4e4}, /* U+6243 [2000] */ - {0x00e68986, 0x8facf6}, /* U+6246 [2000] */ - {0x00e68987, 0x00c0f0}, /* U+6247 */ - {0x00e68988, 0x00eebd}, /* U+6248 */ - {0x00e68989, 0x00c8e2}, /* U+6249 */ - {0x00e6898b, 0x00bcea}, /* U+624B */ - {0x00e6898c, 0x8facf7}, /* U+624C [2000] */ - {0x00e6898d, 0x00bacd}, /* U+624D */ - {0x00e6898e, 0x00d9a9}, /* U+624E */ - {0x00e68991, 0x8facf8}, /* U+6251 [2000] */ - {0x00e68992, 0x8facf9}, /* U+6252 [2000] */ - {0x00e68993, 0x00c2c7}, /* U+6253 */ - {0x00e68995, 0x00caa7}, /* U+6255 */ - {0x00e68996, 0x00f4e5}, /* U+6256 [2000] */ - {0x00e68998, 0x00c2f1}, /* U+6258 */ - {0x00e6899a, 0x00f4e6}, /* U+625A [2000] */ - {0x00e6899b, 0x00d9ac}, /* U+625B */ - {0x00e6899e, 0x00d9aa}, /* U+625E */ - {0x00e689a0, 0x00d9ad}, /* U+6260 */ - {0x00e689a1, 0x8facfa}, /* U+6261 [2000] */ - {0x00e689a3, 0x00d9ab}, /* U+6263 */ - {0x00e689a4, 0x8facfb}, /* U+6264 [2000] */ - {0x00e689a8, 0x00d9ae}, /* U+6268 */ - {0x00e689ad, 0x8facfd}, /* U+626D [2000] */ - {0x00e689ae, 0x00cab1}, /* U+626E */ - {0x00e689af, 0x00f4e7}, /* U+626F [2000] */ - {0x00e689b1, 0x00b0b7}, /* U+6271 */ - {0x00e689b3, 0x8facfe}, /* U+6273 [2000] */ - {0x00e689b6, 0x00c9de}, /* U+6276 */ - {0x00e689b9, 0x00c8e3}, /* U+6279 */ - {0x00e689bb, 0x8facfc}, /* U+627B [2000] */ - {0x00e689bc, 0x00d9af}, /* U+627C */ - {0x00e689be, 0x00d9b2}, /* U+627E */ - {0x00e689bf, 0x00beb5}, /* U+627F */ - {0x00e68a80, 0x00b5bb}, /* U+6280 */ - {0x00e68a82, 0x00d9b0}, /* U+6282 */ - {0x00e68a83, 0x00d9b7}, /* U+6283 */ - {0x00e68a84, 0x00beb6}, /* U+6284 */ - {0x00e68a85, 0x00f4e8}, /* U+6285 [2000] */ - {0x00e68a89, 0x00d9b1}, /* U+6289 */ - {0x00e68a8a, 0x00c7c4}, /* U+628A */ - {0x00e68a91, 0x00cdde}, /* U+6291 */ - {0x00e68a92, 0x00d9b3}, /* U+6292 */ - {0x00e68a93, 0x00d9b4}, /* U+6293 */ - {0x00e68a94, 0x00d9b8}, /* U+6294 */ - {0x00e68a95, 0x00c5ea}, /* U+6295 */ - {0x00e68a96, 0x00d9b5}, /* U+6296 */ - {0x00e68a97, 0x00b9b3}, /* U+6297 */ - {0x00e68a98, 0x00c0de}, /* U+6298 */ - {0x00e68a99, 0x8fada1}, /* U+6299 [2000] */ - {0x00e68a9b, 0x00d9c6}, /* U+629B */ - {0x00e68a9c, 0x00c8b4}, /* U+629C */ - {0x00e68a9e, 0x00c2f2}, /* U+629E */ - {0x00e68aa6, 0x8fada2}, /* U+62A6 [2000] */ - {0x00e68aab, 0x00c8e4}, /* U+62AB */ - {0x00e68aac, 0x00daad}, /* U+62AC */ - {0x00e68ab1, 0x00cafa}, /* U+62B1 */ - {0x00e68ab5, 0x00c4f1}, /* U+62B5 */ - {0x00e68ab9, 0x00cbf5}, /* U+62B9 */ - {0x00e68abb, 0x00d9bb}, /* U+62BB */ - {0x00e68abc, 0x00b2a1}, /* U+62BC */ - {0x00e68abd, 0x00c3ea}, /* U+62BD */ - {0x00e68b82, 0x00d9c4}, /* U+62C2 */ - {0x00e68b84, 0x00f4e9}, /* U+62C4 [2000] */ - {0x00e68b85, 0x00c3b4}, /* U+62C5 */ - {0x00e68b86, 0x00d9be}, /* U+62C6 */ - {0x00e68b87, 0x00d9c5}, /* U+62C7 */ - {0x00e68b88, 0x00d9c0}, /* U+62C8 */ - {0x00e68b89, 0x00d9c7}, /* U+62C9 */ - {0x00e68b8a, 0x00d9c3}, /* U+62CA */ - {0x00e68b8c, 0x00d9c2}, /* U+62CC */ - {0x00e68b8d, 0x00c7ef}, /* U+62CD */ - {0x00e68b8f, 0x00d9bc}, /* U+62CF */ - {0x00e68b90, 0x00b2fd}, /* U+62D0 */ - {0x00e68b91, 0x00d9ba}, /* U+62D1 */ - {0x00e68b92, 0x00b5f1}, /* U+62D2 */ - {0x00e68b93, 0x00c2f3}, /* U+62D3 */ - {0x00e68b94, 0x00d9b6}, /* U+62D4 */ - {0x00e68b95, 0x8fada3}, /* U+62D5 [2000] */ - {0x00e68b96, 0x00f4ea}, /* U+62D6 [2000] */ - {0x00e68b97, 0x00d9b9}, /* U+62D7 */ - {0x00e68b98, 0x00b9b4}, /* U+62D8 */ - {0x00e68b99, 0x00c0db}, /* U+62D9 */ - {0x00e68b9b, 0x00beb7}, /* U+62DB */ - {0x00e68b9c, 0x00d9c1}, /* U+62DC */ - {0x00e68b9d, 0x00c7d2}, /* U+62DD */ - {0x00e68ba0, 0x00b5f2}, /* U+62E0 */ - {0x00e68ba1, 0x00b3c8}, /* U+62E1 */ - {0x00e68bac, 0x00b3e7}, /* U+62EC */ - {0x00e68bad, 0x00bfa1}, /* U+62ED */ - {0x00e68bae, 0x00d9c9}, /* U+62EE */ - {0x00e68baf, 0x00d9ce}, /* U+62EF */ - {0x00e68bb1, 0x00d9ca}, /* U+62F1 */ - {0x00e68bb3, 0x00b7fd}, /* U+62F3 */ - {0x00e68bb5, 0x00d9cf}, /* U+62F5 */ - {0x00e68bb6, 0x00bba2}, /* U+62F6 */ - {0x00e68bb7, 0x00b9e9}, /* U+62F7 */ - {0x00e68bbc, 0x00f4eb}, /* U+62FC [2000] */ - {0x00e68bbd, 0x8fada5}, /* U+62FD [2000] */ - {0x00e68bbe, 0x00bda6}, /* U+62FE */ - {0x00e68bbf, 0x00d9bd}, /* U+62FF */ - {0x00e68c81, 0x00bbfd}, /* U+6301 */ - {0x00e68c82, 0x00d9cc}, /* U+6302 */ - {0x00e68c83, 0x8fada6}, /* U+6303 [2000] */ - {0x00e68c87, 0x00bbd8}, /* U+6307 */ - {0x00e68c88, 0x00d9cd}, /* U+6308 */ - {0x00e68c89, 0x00b0c4}, /* U+6309 */ - {0x00e68c8a, 0x00f4ec}, /* U+630A [2000] */ - {0x00e68c8c, 0x00d9c8}, /* U+630C */ - {0x00e68c8d, 0x8fada7}, /* U+630D [2000] */ - {0x00e68c90, 0x8fada8}, /* U+6310 [2000] */ - {0x00e68c91, 0x00c4a9}, /* U+6311 */ - {0x00e68c98, 0x00f4ed}, /* U+6318 [2000] */ - {0x00e68c99, 0x00b5f3}, /* U+6319 */ - {0x00e68c9f, 0x00b6b4}, /* U+631F */ - {0x00e68ca7, 0x00d9cb}, /* U+6327 */ - {0x00e68ca8, 0x00b0a7}, /* U+6328 */ - {0x00e68cab, 0x00bac3}, /* U+632B */ - {0x00e68caf, 0x00bfb6}, /* U+632F */ - {0x00e68cb2, 0x8fadab}, /* U+6332 [2000] */ - {0x00e68cb5, 0x8fadac}, /* U+6335 [2000] */ - {0x00e68cb9, 0x00f4ee}, /* U+6339 [2000] */ - {0x00e68cba, 0x00c4f2}, /* U+633A */ - {0x00e68cbb, 0x8fadad}, /* U+633B [2000] */ - {0x00e68cbc, 0x8fadae}, /* U+633C [2000] */ - {0x00e68cbd, 0x00c8d4}, /* U+633D */ - {0x00e68cbe, 0x00d9d1}, /* U+633E */ - {0x00e68cbf, 0x00c1de}, /* U+633F */ - {0x00e68d81, 0x8fadaf}, /* U+6341 [2000] */ - {0x00e68d83, 0x00f4ef}, /* U+6343 [2000] */ - {0x00e68d84, 0x8fadb0}, /* U+6344 [2000] */ - {0x00e68d89, 0x00c2aa}, /* U+6349 */ - {0x00e68d8c, 0x00bbab}, /* U+634C */ - {0x00e68d8d, 0x00d9d2}, /* U+634D */ - {0x00e68d8e, 0x8fadb1}, /* U+634E [2000] */ - {0x00e68d8f, 0x00d9d4}, /* U+634F */ - {0x00e68d90, 0x00d9d0}, /* U+6350 */ - {0x00e68d95, 0x00cae1}, /* U+6355 */ - {0x00e68d97, 0x00c4bd}, /* U+6357 */ - {0x00e68d99, 0x8fadb3}, /* U+6359 [2000] */ - {0x00e68d9c, 0x00c1dc}, /* U+635C */ - {0x00e68da5, 0x00f4f0}, /* U+6365 [2000] */ - {0x00e68da7, 0x00cafb}, /* U+6367 */ - {0x00e68da8, 0x00bcce}, /* U+6368 */ - {0x00e68da9, 0x00d9e0}, /* U+6369 */ - {0x00e68dab, 0x00d9df}, /* U+636B */ - {0x00e68dac, 0x8fadb6}, /* U+636C [2000] */ - {0x00e68dae, 0x00bff8}, /* U+636E */ - {0x00e68db2, 0x00b7fe}, /* U+6372 */ - {0x00e68db6, 0x00d9d9}, /* U+6376 */ - {0x00e68db7, 0x00beb9}, /* U+6377 */ - {0x00e68dba, 0x00c6e8}, /* U+637A */ - {0x00e68dbb, 0x00c7b1}, /* U+637B */ - {0x00e68dbc, 0x00f4f1}, /* U+637C [2000] */ - {0x00e68e80, 0x00d9d7}, /* U+6380 */ - {0x00e68e83, 0x00c1dd}, /* U+6383 */ - {0x00e68e84, 0x8fadb7}, /* U+6384 [2000] */ - {0x00e68e88, 0x00bcf8}, /* U+6388 */ - {0x00e68e89, 0x00d9dc}, /* U+6389 */ - {0x00e68e8c, 0x00beb8}, /* U+638C */ - {0x00e68e8e, 0x00d9d6}, /* U+638E */ - {0x00e68e8f, 0x00d9db}, /* U+638F */ - {0x00e68e92, 0x00c7d3}, /* U+6392 */ - {0x00e68e94, 0x8fadba}, /* U+6394 [2000] */ - {0x00e68e96, 0x00d9d5}, /* U+6396 */ - {0x00e68e98, 0x00b7a1}, /* U+6398 */ - {0x00e68e99, 0x8fadb8}, /* U+6399 [2000] */ - {0x00e68e9b, 0x00b3dd}, /* U+639B */ - {0x00e68e9f, 0x00d9dd}, /* U+639F */ - {0x00e68ea0, 0x00ceab}, /* U+63A0 */ - {0x00e68ea1, 0x00bace}, /* U+63A1 */ - {0x00e68ea2, 0x00c3b5}, /* U+63A2 */ - {0x00e68ea3, 0x00d9da}, /* U+63A3 */ - {0x00e68ea5, 0x00c0dc}, /* U+63A5 */ - {0x00e68ea7, 0x00b9b5}, /* U+63A7 */ - {0x00e68ea8, 0x00bfe4}, /* U+63A8 */ - {0x00e68ea9, 0x00b1e6}, /* U+63A9 */ - {0x00e68eaa, 0x00c1bc}, /* U+63AA */ - {0x00e68eab, 0x00d9d8}, /* U+63AB */ - {0x00e68eac, 0x00b5c5}, /* U+63AC */ - {0x00e68eb2, 0x00b7c7}, /* U+63B2 */ - {0x00e68eb4, 0x00c4cf}, /* U+63B4 */ - {0x00e68eb5, 0x00d9de}, /* U+63B5 */ - {0x00e68ebb, 0x00c1df}, /* U+63BB */ - {0x00e68ebd, 0x8fadbb}, /* U+63BD [2000] */ - {0x00e68ebe, 0x00d9e1}, /* U+63BE */ - {0x00e68f80, 0x00d9e3}, /* U+63C0 */ - {0x00e68f83, 0x00c2b7}, /* U+63C3 */ - {0x00e68f84, 0x00d9e9}, /* U+63C4 */ - {0x00e68f86, 0x00d9e4}, /* U+63C6 */ - {0x00e68f89, 0x00d9e6}, /* U+63C9 */ - {0x00e68f8f, 0x00c9c1}, /* U+63CF */ - {0x00e68f90, 0x00c4f3}, /* U+63D0 */ - {0x00e68f92, 0x00d9e7}, /* U+63D2 */ - {0x00e68f94, 0x8fadbd}, /* U+63D4 [2000] */ - {0x00e68f95, 0x8fadbe}, /* U+63D5 [2000] */ - {0x00e68f96, 0x00cdac}, /* U+63D6 */ - {0x00e68f9a, 0x00cdc8}, /* U+63DA */ - {0x00e68f9b, 0x00b4b9}, /* U+63DB */ - {0x00e68f9c, 0x8fadbf}, /* U+63DC [2000] */ - {0x00e68fa0, 0x8fadc0}, /* U+63E0 [2000] */ - {0x00e68fa1, 0x00b0ae}, /* U+63E1 */ - {0x00e68fa3, 0x00d9e5}, /* U+63E3 */ - {0x00e68fa5, 0x00f4f2}, /* U+63E5 [2000] */ - {0x00e68fa9, 0x00d9e2}, /* U+63E9 */ - {0x00e68fab, 0x8fadc1}, /* U+63EB [2000] */ - {0x00e68fac, 0x8fadc2}, /* U+63EC [2000] */ - {0x00e68fad, 0x00f4f3}, /* U+63ED [2000] */ - {0x00e68fae, 0x00b4f8}, /* U+63EE */ - {0x00e68fb2, 0x8fadc3}, /* U+63F2 [2000] */ - {0x00e68fb4, 0x00b1e7}, /* U+63F4 */ - {0x00e68fb5, 0x00f4f4}, /* U+63F5 [2000] */ - {0x00e68fb6, 0x00d9e8}, /* U+63F6 */ - {0x00e68fb7, 0x8fadbc}, /* U+63F7 [2000] */ - {0x00e68fba, 0x00cdc9}, /* U+63FA */ - {0x00e69086, 0x00d9ec}, /* U+6406 */ - {0x00e69089, 0x8fadc4}, /* U+6409 [2000] */ - {0x00e6908d, 0x00c2bb}, /* U+640D */ - {0x00e6908f, 0x00d9f3}, /* U+640F */ - {0x00e69090, 0x00f4f5}, /* U+6410 [2000] */ - {0x00e69093, 0x00d9ed}, /* U+6413 */ - {0x00e69094, 0x00f4f6}, /* U+6414 [2000] */ - {0x00e69096, 0x00d9ea}, /* U+6416 */ - {0x00e69097, 0x00d9f1}, /* U+6417 */ - {0x00e6909c, 0x00d9d3}, /* U+641C */ - {0x00e6909e, 0x8fadc5}, /* U+641E [2000] */ - {0x00e690a2, 0x00f4f7}, /* U+6422 [2000] */ - {0x00e690a5, 0x8fadc6}, /* U+6425 [2000] */ - {0x00e690a6, 0x00d9ee}, /* U+6426 */ - {0x00e690a8, 0x00d9f2}, /* U+6428 */ - {0x00e690a9, 0x8fadc7}, /* U+6429 [2000] */ - {0x00e690ac, 0x00c8c2}, /* U+642C */ - {0x00e690ad, 0x00c5eb}, /* U+642D */ - {0x00e690af, 0x8fadc8}, /* U+642F [2000] */ - {0x00e690b4, 0x00d9eb}, /* U+6434 */ - {0x00e690b6, 0x00d9ef}, /* U+6436 */ - {0x00e690ba, 0x00b7c8}, /* U+643A */ - {0x00e690be, 0x00baf1}, /* U+643E */ - {0x00e69182, 0x00c0dd}, /* U+6442 */ - {0x00e6918e, 0x00d9f7}, /* U+644E */ - {0x00e69191, 0x00f4f9}, /* U+6451 [2000] */ - {0x00e69198, 0x00c5a6}, /* U+6458 */ - {0x00e6919a, 0x8fadc9}, /* U+645A [2000] */ - {0x00e6919b, 0x8fadca}, /* U+645B [2000] */ - {0x00e6919d, 0x8fadcb}, /* U+645D [2000] */ - {0x00e691a0, 0x00f4fa}, /* U+6460 [2000] */ - {0x00e691a7, 0x00d9f4}, /* U+6467 */ - {0x00e691a9, 0x00cbe0}, /* U+6469 */ - {0x00e691ad, 0x00f4fb}, /* U+646D [2000] */ - {0x00e691af, 0x00d9f5}, /* U+646F */ - {0x00e691b3, 0x8fadcc}, /* U+6473 [2000] */ - {0x00e691b6, 0x00d9f6}, /* U+6476 */ - {0x00e691b8, 0x00ccce}, /* U+6478 */ - {0x00e691b9, 0x00f4f8}, /* U+6479 [2000] */ - {0x00e691ba, 0x00c0a2}, /* U+647A */ - {0x00e691bd, 0x8fadcd}, /* U+647D [2000] */ - {0x00e69283, 0x00b7e2}, /* U+6483 */ - {0x00e69287, 0x8fadce}, /* U+6487 [2000] */ - {0x00e69288, 0x00d9fd}, /* U+6488 */ - {0x00e69291, 0x8fadcf}, /* U+6491 [2000] */ - {0x00e69292, 0x00bbb5}, /* U+6492 */ - {0x00e69293, 0x00d9fa}, /* U+6493 */ - {0x00e69295, 0x00d9f9}, /* U+6495 */ - {0x00e6929a, 0x00c7b2}, /* U+649A */ - {0x00e6929d, 0x8fadd0}, /* U+649D [2000] */ - {0x00e6929e, 0x00c6b5}, /* U+649E */ - {0x00e6929f, 0x8fadd1}, /* U+649F [2000] */ - {0x00e692a4, 0x00c5b1}, /* U+64A4 */ - {0x00e692a5, 0x00d9fb}, /* U+64A5 */ - {0x00e692a9, 0x00d9fc}, /* U+64A9 */ - {0x00e692ab, 0x00c9ef}, /* U+64AB */ - {0x00e692ad, 0x00c7c5}, /* U+64AD */ - {0x00e692ae, 0x00bba3}, /* U+64AE */ - {0x00e692b0, 0x00c0f1}, /* U+64B0 */ - {0x00e692b2, 0x00cbd0}, /* U+64B2 */ - {0x00e692b9, 0x00b3c9}, /* U+64B9 */ - {0x00e692bb, 0x00daa5}, /* U+64BB */ - {0x00e692bc, 0x00d9fe}, /* U+64BC */ - {0x00e692be, 0x00f4fd}, /* U+64BE [2000] */ - {0x00e692bf, 0x00f4fe}, /* U+64BF [2000] */ - {0x00e69381, 0x00cdca}, /* U+64C1 */ - {0x00e69382, 0x00daa7}, /* U+64C2 */ - {0x00e69384, 0x00f5a1}, /* U+64C4 [2000] */ - {0x00e69385, 0x00daa3}, /* U+64C5 */ - {0x00e69387, 0x00daa4}, /* U+64C7 */ - {0x00e6938a, 0x00f5a2}, /* U+64CA [2000] */ - {0x00e6938b, 0x8fadd2}, /* U+64CB [2000] */ - {0x00e6938c, 0x8fadd3}, /* U+64CC [2000] */ - {0x00e6938d, 0x00c1e0}, /* U+64CD */ - {0x00e6938e, 0x00f4fc}, /* U+64CE [2000] */ - {0x00e69390, 0x00f5a3}, /* U+64D0 [2000] */ - {0x00e69392, 0x00daa2}, /* U+64D2 */ - {0x00e69394, 0x00d9bf}, /* U+64D4 */ - {0x00e69395, 0x8fadd4}, /* U+64D5 [2000] */ - {0x00e69397, 0x8fadd5}, /* U+64D7 [2000] */ - {0x00e69398, 0x00daa6}, /* U+64D8 */ - {0x00e6939a, 0x00daa1}, /* U+64DA */ - {0x00e693a0, 0x00daab}, /* U+64E0 */ - {0x00e693a1, 0x00daac}, /* U+64E1 */ - {0x00e693a2, 0x00c5a7}, /* U+64E2 */ - {0x00e693a3, 0x00daae}, /* U+64E3 */ - {0x00e693a4, 0x8fadd7}, /* U+64E4 [2000] */ - {0x00e693a5, 0x8fadd8}, /* U+64E5 [2000] */ - {0x00e693a6, 0x00bba4}, /* U+64E6 */ - {0x00e693a7, 0x00daa9}, /* U+64E7 */ - {0x00e693ac, 0x00b5bc}, /* U+64EC */ - {0x00e693af, 0x00daaf}, /* U+64EF */ - {0x00e693b1, 0x00daa8}, /* U+64F1 */ - {0x00e693b2, 0x00dab3}, /* U+64F2 */ - {0x00e693b4, 0x00dab2}, /* U+64F4 */ - {0x00e693b6, 0x00dab1}, /* U+64F6 */ - {0x00e693b7, 0x00f5a4}, /* U+64F7 [2000] */ - {0x00e693ba, 0x00dab4}, /* U+64FA */ - {0x00e693bb, 0x00f5a5}, /* U+64FB [2000] */ - {0x00e693bd, 0x00dab6}, /* U+64FD */ - {0x00e693be, 0x00bef1}, /* U+64FE */ - {0x00e693bf, 0x8fadd9}, /* U+64FF [2000] */ - {0x00e69480, 0x00dab5}, /* U+6500 */ - {0x00e69484, 0x8fadda}, /* U+6504 [2000] */ - {0x00e69485, 0x00dab9}, /* U+6505 */ - {0x00e6948f, 0x8faddc}, /* U+650F [2000] */ - {0x00e69494, 0x8faddd}, /* U+6514 [2000] */ - {0x00e69496, 0x8fadde}, /* U+6516 [2000] */ - {0x00e69498, 0x00dab7}, /* U+6518 */ - {0x00e6949c, 0x00dab8}, /* U+651C */ - {0x00e6949d, 0x00d9f0}, /* U+651D */ - {0x00e6949e, 0x8fade0}, /* U+651E [2000] */ - {0x00e694a2, 0x00f5a6}, /* U+6522 [2000] */ - {0x00e694a3, 0x00dabb}, /* U+6523 */ - {0x00e694a4, 0x00daba}, /* U+6524 */ - {0x00e694a9, 0x00f5a7}, /* U+6529 [2000] */ - {0x00e694aa, 0x00d9f8}, /* U+652A */ - {0x00e694ab, 0x00dabc}, /* U+652B */ - {0x00e694ac, 0x00dab0}, /* U+652C */ - {0x00e694af, 0x00bbd9}, /* U+652F */ - {0x00e694b2, 0x8fade1}, /* U+6532 [2000] */ - {0x00e694b4, 0x00dabd}, /* U+6534 */ - {0x00e694b5, 0x00dabe}, /* U+6535 */ - {0x00e694b6, 0x00dac0}, /* U+6536 */ - {0x00e694b7, 0x00dabf}, /* U+6537 */ - {0x00e694b8, 0x00dac1}, /* U+6538 */ - {0x00e694b9, 0x00b2fe}, /* U+6539 */ - {0x00e694bb, 0x00b9b6}, /* U+653B */ - {0x00e694be, 0x00cafc}, /* U+653E */ - {0x00e694bf, 0x00c0af}, /* U+653F */ - {0x00e69584, 0x8fade2}, /* U+6544 [2000] */ - {0x00e69585, 0x00b8ce}, /* U+6545 */ - {0x00e69588, 0x00dac3}, /* U+6548 */ - {0x00e6958d, 0x00dac6}, /* U+654D */ - {0x00e6958f, 0x00c9d2}, /* U+654F */ - {0x00e69591, 0x00b5df}, /* U+6551 */ - {0x00e69594, 0x8fade3}, /* U+6554 [2000] */ - {0x00e69595, 0x00dac5}, /* U+6555 */ - {0x00e69596, 0x00dac4}, /* U+6556 */ - {0x00e69597, 0x00c7d4}, /* U+6557 */ - {0x00e69598, 0x00dac7}, /* U+6558 */ - {0x00e69599, 0x00b6b5}, /* U+6559 */ - {0x00e6959d, 0x00dac9}, /* U+655D */ - {0x00e6959e, 0x00dac8}, /* U+655E */ - {0x00e695a2, 0x00b4ba}, /* U+6562 */ - {0x00e695a3, 0x00bbb6}, /* U+6563 */ - {0x00e695a6, 0x00c6d8}, /* U+6566 */ - {0x00e695a7, 0x00f5a9}, /* U+6567 [2000] */ - {0x00e695ab, 0x8fade4}, /* U+656B [2000] */ - {0x00e695ac, 0x00b7c9}, /* U+656C */ - {0x00e695b0, 0x00bff4}, /* U+6570 */ - {0x00e695b2, 0x00daca}, /* U+6572 */ - {0x00e695b4, 0x00c0b0}, /* U+6574 */ - {0x00e695b5, 0x00c5a8}, /* U+6575 */ - {0x00e695b7, 0x00c9df}, /* U+6577 */ - {0x00e695b8, 0x00dacb}, /* U+6578 */ - {0x00e695ba, 0x8fade5}, /* U+657A [2000] */ - {0x00e69681, 0x8fade6}, /* U+6581 [2000] */ - {0x00e69682, 0x00dacc}, /* U+6582 */ - {0x00e69683, 0x00dacd}, /* U+6583 */ - {0x00e69684, 0x8fade7}, /* U+6584 [2000] */ - {0x00e69685, 0x8fade8}, /* U+6585 [2000] */ - {0x00e69687, 0x00cab8}, /* U+6587 */ - {0x00e69688, 0x00d5dd}, /* U+6588 */ - {0x00e69689, 0x00c0c6}, /* U+6589 */ - {0x00e6968a, 0x8fade9}, /* U+658A [2000] */ - {0x00e6968c, 0x00c9cc}, /* U+658C */ - {0x00e6968e, 0x00bad8}, /* U+658E */ - {0x00e69690, 0x00c8e5}, /* U+6590 */ - {0x00e69691, 0x00c8c3}, /* U+6591 */ - {0x00e69697, 0x00c5cd}, /* U+6597 */ - {0x00e69699, 0x00cec1}, /* U+6599 */ - {0x00e6969b, 0x00dacf}, /* U+659B */ - {0x00e6969c, 0x00bcd0}, /* U+659C */ - {0x00e6969d, 0x00f5aa}, /* U+659D [2000] */ - {0x00e6969f, 0x00dad0}, /* U+659F */ - {0x00e696a1, 0x00b0b6}, /* U+65A1 */ - {0x00e696a4, 0x00b6d4}, /* U+65A4 */ - {0x00e696a5, 0x00c0cd}, /* U+65A5 */ - {0x00e696a7, 0x00c9e0}, /* U+65A7 */ - {0x00e696ab, 0x00dad1}, /* U+65AB */ - {0x00e696ac, 0x00bbc2}, /* U+65AC */ - {0x00e696ad, 0x00c3c7}, /* U+65AD */ - {0x00e696af, 0x00bbdb}, /* U+65AF */ - {0x00e696b0, 0x00bfb7}, /* U+65B0 */ - {0x00e696b2, 0x8fadea}, /* U+65B2 [2000] */ - {0x00e696b5, 0x8fadeb}, /* U+65B5 [2000] */ - {0x00e696b7, 0x00dad2}, /* U+65B7 */ - {0x00e696b8, 0x8fadec}, /* U+65B8 [2000] */ - {0x00e696b9, 0x00cafd}, /* U+65B9 */ - {0x00e696bc, 0x00b1f7}, /* U+65BC */ - {0x00e696bd, 0x00bbdc}, /* U+65BD */ - {0x00e696bf, 0x8faded}, /* U+65BF [2000] */ - {0x00e69781, 0x00dad5}, /* U+65C1 */ - {0x00e69782, 0x8fadee}, /* U+65C2 [2000] */ - {0x00e69783, 0x00dad3}, /* U+65C3 */ - {0x00e69784, 0x00dad6}, /* U+65C4 */ - {0x00e69785, 0x00ceb9}, /* U+65C5 */ - {0x00e69786, 0x00dad4}, /* U+65C6 */ - {0x00e69789, 0x8fadef}, /* U+65C9 [2000] */ - {0x00e6978b, 0x00c0fb}, /* U+65CB */ - {0x00e6978c, 0x00dad7}, /* U+65CC */ - {0x00e6978f, 0x00c2b2}, /* U+65CF */ - {0x00e69792, 0x00dad8}, /* U+65D2 */ - {0x00e69794, 0x8fadf0}, /* U+65D4 [2000] */ - {0x00e69797, 0x00b4fa}, /* U+65D7 */ - {0x00e69799, 0x00dada}, /* U+65D9 */ - {0x00e6979b, 0x00dad9}, /* U+65DB */ - {0x00e697a0, 0x00dadb}, /* U+65E0 */ - {0x00e697a1, 0x00dadc}, /* U+65E1 */ - {0x00e697a2, 0x00b4fb}, /* U+65E2 */ - {0x00e697a5, 0x00c6fc}, /* U+65E5 */ - {0x00e697a6, 0x00c3b6}, /* U+65E6 */ - {0x00e697a7, 0x00b5ec}, /* U+65E7 */ - {0x00e697a8, 0x00bbdd}, /* U+65E8 */ - {0x00e697a9, 0x00c1e1}, /* U+65E9 */ - {0x00e697ac, 0x00bddc}, /* U+65EC */ - {0x00e697ad, 0x00b0b0}, /* U+65ED */ - {0x00e697b1, 0x00dadd}, /* U+65F1 */ - {0x00e697b2, 0x8fadf2}, /* U+65F2 [2000] */ - {0x00e697b9, 0x8fadf3}, /* U+65F9 [2000] */ - {0x00e697ba, 0x00b2a2}, /* U+65FA */ - {0x00e697bb, 0x00dae1}, /* U+65FB */ - {0x00e697bc, 0x8fadf4}, /* U+65FC [2000] */ - {0x00e69880, 0x00f5ac}, /* U+6600 [2000] */ - {0x00e69882, 0x00b9b7}, /* U+6602 */ - {0x00e69883, 0x00dae0}, /* U+6603 */ - {0x00e69884, 0x8fadf5}, /* U+6604 [2000] */ - {0x00e69886, 0x00baab}, /* U+6606 */ - {0x00e69887, 0x00beba}, /* U+6607 */ - {0x00e69888, 0x8fadf6}, /* U+6608 [2000] */ - {0x00e69889, 0x00f5ad}, /* U+6609 [2000] */ - {0x00e6988a, 0x00dadf}, /* U+660A */ - {0x00e6988c, 0x00bebb}, /* U+660C */ - {0x00e6988e, 0x00ccc0}, /* U+660E */ - {0x00e6988f, 0x00baaa}, /* U+660F */ - {0x00e69893, 0x00b0d7}, /* U+6613 */ - {0x00e69894, 0x00c0ce}, /* U+6614 */ - {0x00e69895, 0x00f5ae}, /* U+6615 [2000] */ - {0x00e6989c, 0x00dae6}, /* U+661C */ - {0x00e6989e, 0x00f5af}, /* U+661E [2000] */ - {0x00e6989f, 0x00c0b1}, /* U+661F */ - {0x00e698a0, 0x00b1c7}, /* U+6620 */ - {0x00e698a1, 0x8fadf7}, /* U+6621 [2000] */ - {0x00e698a2, 0x00f5b1}, /* U+6622 [2000] */ - {0x00e698a4, 0x00f5b2}, /* U+6624 [2000] */ - {0x00e698a5, 0x00bdd5}, /* U+6625 */ - {0x00e698a7, 0x00cbe6}, /* U+6627 */ - {0x00e698a8, 0x00baf2}, /* U+6628 */ - {0x00e698aa, 0x8fadf8}, /* U+662A [2000] */ - {0x00e698ab, 0x00f5b3}, /* U+662B [2000] */ - {0x00e698ad, 0x00bebc}, /* U+662D */ - {0x00e698af, 0x00c0a7}, /* U+662F */ - {0x00e698b0, 0x00f5b4}, /* U+6630 [2000] */ - {0x00e698b1, 0x00f5b5}, /* U+6631 [2000] */ - {0x00e698b3, 0x00f5b6}, /* U+6633 [2000] */ - {0x00e698b4, 0x00dae5}, /* U+6634 */ - {0x00e698b5, 0x00dae3}, /* U+6635 */ - {0x00e698b6, 0x00dae4}, /* U+6636 */ - {0x00e698ba, 0x00f5b0}, /* U+663A [2000] */ - {0x00e698bc, 0x00c3eb}, /* U+663C */ - {0x00e698bf, 0x00dba6}, /* U+663F */ - {0x00e69981, 0x00daea}, /* U+6641 */ - {0x00e69982, 0x00bbfe}, /* U+6642 */ - {0x00e69983, 0x00b9b8}, /* U+6643 */ - {0x00e69984, 0x00dae8}, /* U+6644 */ - {0x00e69985, 0x8fadf9}, /* U+6645 [2000] */ - {0x00e69988, 0x00f5b8}, /* U+6648 [2000] */ - {0x00e69989, 0x00dae9}, /* U+6649 */ - {0x00e6998b, 0x00bfb8}, /* U+664B */ - {0x00e6998c, 0x00f5b9}, /* U+664C [2000] */ - {0x00e6998e, 0x8fadfb}, /* U+664E [2000] */ - {0x00e6998f, 0x00dae7}, /* U+664F */ - {0x00e69991, 0x8fadfa}, /* U+6651 [2000] */ - {0x00e69992, 0x00bbaf}, /* U+6652 */ - {0x00e69997, 0x8fadfe}, /* U+6657 [2000] */ - {0x00e69999, 0x00f5bb}, /* U+6659 [2000] */ - {0x00e6999a, 0x00f5bc}, /* U+665A [2000] */ - {0x00e6999b, 0x8faea1}, /* U+665B [2000] */ - {0x00e6999d, 0x00daec}, /* U+665D */ - {0x00e6999e, 0x00daeb}, /* U+665E */ - {0x00e6999f, 0x00daf0}, /* U+665F */ - {0x00e699a1, 0x00f5bd}, /* U+6661 [2000] */ - {0x00e699a2, 0x00daf1}, /* U+6662 */ - {0x00e699a3, 0x8faea2}, /* U+6663 [2000] */ - {0x00e699a4, 0x00daed}, /* U+6664 */ - {0x00e699a5, 0x00f5be}, /* U+6665 [2000] */ - {0x00e699a6, 0x00b3a2}, /* U+6666 */ - {0x00e699a7, 0x00daee}, /* U+6667 */ - {0x00e699a8, 0x00daef}, /* U+6668 */ - {0x00e699a9, 0x00c8d5}, /* U+6669 */ - {0x00e699aa, 0x8faea5}, /* U+666A [2000] */ - {0x00e699ab, 0x8faea6}, /* U+666B [2000] */ - {0x00e699ac, 0x8faea7}, /* U+666C [2000] */ - {0x00e699ad, 0x8faea8}, /* U+666D [2000] */ - {0x00e699ae, 0x00c9e1}, /* U+666E */ - {0x00e699af, 0x00b7ca}, /* U+666F */ - {0x00e699b0, 0x00daf2}, /* U+6670 */ - {0x00e699b3, 0x00f5bf}, /* U+6673 [2000] */ - {0x00e699b4, 0x00c0b2}, /* U+6674 */ - {0x00e699b6, 0x00bebd}, /* U+6676 */ - {0x00e699b7, 0x00f5c0}, /* U+6677 [2000] */ - {0x00e699b8, 0x00f5c1}, /* U+6678 [2000] */ - {0x00e699ba, 0x00c3d2}, /* U+667A */ - {0x00e699bb, 0x8faea9}, /* U+667B [2000] */ - {0x00e69a80, 0x8faeaa}, /* U+6680 [2000] */ - {0x00e69a81, 0x00b6c7}, /* U+6681 */ - {0x00e69a83, 0x00daf3}, /* U+6683 */ - {0x00e69a84, 0x00daf7}, /* U+6684 */ - {0x00e69a87, 0x00b2cb}, /* U+6687 */ - {0x00e69a88, 0x00daf4}, /* U+6688 */ - {0x00e69a89, 0x00daf6}, /* U+6689 */ - {0x00e69a8d, 0x00f5c2}, /* U+668D [2000] */ - {0x00e69a8e, 0x00daf5}, /* U+668E */ - {0x00e69a90, 0x8faeab}, /* U+6690 [2000] */ - {0x00e69a91, 0x00bdeb}, /* U+6691 */ - {0x00e69a92, 0x8faeac}, /* U+6692 [2000] */ - {0x00e69a96, 0x00c3c8}, /* U+6696 */ - {0x00e69a97, 0x00b0c5}, /* U+6697 */ - {0x00e69a98, 0x00daf8}, /* U+6698 */ - {0x00e69a99, 0x8faead}, /* U+6699 [2000] */ - {0x00e69a9d, 0x00daf9}, /* U+669D */ - {0x00e69aa0, 0x00f5c4}, /* U+66A0 [2000] */ - {0x00e69aa2, 0x00c4aa}, /* U+66A2 */ - {0x00e69aa6, 0x00cef1}, /* U+66A6 */ - {0x00e69aab, 0x00bbc3}, /* U+66AB */ - {0x00e69aad, 0x8faeaf}, /* U+66AD [2000] */ - {0x00e69aae, 0x00caeb}, /* U+66AE */ - {0x00e69ab1, 0x8faeb0}, /* U+66B1 [2000] */ - {0x00e69ab2, 0x00f5c5}, /* U+66B2 [2000] */ - {0x00e69ab4, 0x00cbbd}, /* U+66B4 */ - {0x00e69ab5, 0x8faeb1}, /* U+66B5 [2000] */ - {0x00e69ab8, 0x00dba2}, /* U+66B8 */ - {0x00e69ab9, 0x00dafb}, /* U+66B9 */ - {0x00e69abb, 0x00f5c6}, /* U+66BB [2000] */ - {0x00e69abc, 0x00dafe}, /* U+66BC */ - {0x00e69abe, 0x00dafd}, /* U+66BE */ - {0x00e69abf, 0x8faeb3}, /* U+66BF [2000] */ - {0x00e69b81, 0x00dafa}, /* U+66C1 */ - {0x00e69b84, 0x00dba1}, /* U+66C4 */ - {0x00e69b86, 0x00f5c7}, /* U+66C6 [2000] */ - {0x00e69b87, 0x00c6de}, /* U+66C7 */ - {0x00e69b88, 0x00f5c8}, /* U+66C8 [2000] */ - {0x00e69b89, 0x00dafc}, /* U+66C9 */ - {0x00e69b96, 0x00dba3}, /* U+66D6 */ - {0x00e69b99, 0x00bdec}, /* U+66D9 */ - {0x00e69b9a, 0x00dba4}, /* U+66DA */ - {0x00e69b9b, 0x00f5ca}, /* U+66DB [2000] */ - {0x00e69b9c, 0x00cdcb}, /* U+66DC */ - {0x00e69b9d, 0x00c7f8}, /* U+66DD */ - {0x00e69ba0, 0x00dba5}, /* U+66E0 */ - {0x00e69ba6, 0x00dba7}, /* U+66E6 */ - {0x00e69ba8, 0x00f5cb}, /* U+66E8 [2000] */ - {0x00e69ba9, 0x00dba8}, /* U+66E9 */ - {0x00e69bac, 0x8faeb5}, /* U+66EC [2000] */ - {0x00e69bb0, 0x00dba9}, /* U+66F0 */ - {0x00e69bb2, 0x00b6ca}, /* U+66F2 */ - {0x00e69bb3, 0x00b1c8}, /* U+66F3 */ - {0x00e69bb4, 0x00b9b9}, /* U+66F4 */ - {0x00e69bb5, 0x00dbaa}, /* U+66F5 */ - {0x00e69bb7, 0x00dbab}, /* U+66F7 */ - {0x00e69bb8, 0x00bdf1}, /* U+66F8 */ - {0x00e69bb9, 0x00c1e2}, /* U+66F9 */ - {0x00e69bba, 0x00f5cc}, /* U+66FA [2000] */ - {0x00e69bbb, 0x00f5b7}, /* U+66FB [2000] */ - {0x00e69bbc, 0x00d2d8}, /* U+66FC */ - {0x00e69bbd, 0x00c1be}, /* U+66FD */ - {0x00e69bbe, 0x00c1bd}, /* U+66FE */ - {0x00e69bbf, 0x00c2d8}, /* U+66FF */ - {0x00e69c80, 0x00bac7}, /* U+6700 */ - {0x00e69c81, 0x8faeb7}, /* U+6701 [2000] */ - {0x00e69c83, 0x00d0f2}, /* U+6703 */ - {0x00e69c85, 0x8faeb8}, /* U+6705 [2000] */ - {0x00e69c88, 0x00b7ee}, /* U+6708 */ - {0x00e69c89, 0x00cdad}, /* U+6709 */ - {0x00e69c8b, 0x00cafe}, /* U+670B */ - {0x00e69c8d, 0x00c9fe}, /* U+670D */ - {0x00e69c8f, 0x00dbac}, /* U+670F */ - {0x00e69c92, 0x8faeb9}, /* U+6712 [2000] */ - {0x00e69c93, 0x00f5cd}, /* U+6713 [2000] */ - {0x00e69c94, 0x00baf3}, /* U+6714 */ - {0x00e69c95, 0x00c4bf}, /* U+6715 */ - {0x00e69c96, 0x00dbad}, /* U+6716 */ - {0x00e69c97, 0x00cfaf}, /* U+6717 */ - {0x00e69c99, 0x8faebb}, /* U+6719 [2000] */ - {0x00e69c9b, 0x00cbbe}, /* U+671B */ - {0x00e69c9d, 0x00c4ab}, /* U+671D */ - {0x00e69c9e, 0x00dbae}, /* U+671E */ - {0x00e69c9f, 0x00b4fc}, /* U+671F */ - {0x00e69ca6, 0x00dbaf}, /* U+6726 */ - {0x00e69ca7, 0x00dbb0}, /* U+6727 */ - {0x00e69ca8, 0x00ccda}, /* U+6728 */ - {0x00e69caa, 0x00cca4}, /* U+672A */ - {0x00e69cab, 0x00cbf6}, /* U+672B */ - {0x00e69cac, 0x00cbdc}, /* U+672C */ - {0x00e69cad, 0x00bba5}, /* U+672D */ - {0x00e69cae, 0x00dbb2}, /* U+672E */ - {0x00e69cb1, 0x00bceb}, /* U+6731 */ - {0x00e69cb3, 0x00f5cf}, /* U+6733 [2000] */ - {0x00e69cb4, 0x00cbd1}, /* U+6734 */ - {0x00e69cb6, 0x00dbb4}, /* U+6736 */ - {0x00e69cb7, 0x00dbb7}, /* U+6737 */ - {0x00e69cb8, 0x00dbb6}, /* U+6738 */ - {0x00e69cba, 0x00b4f9}, /* U+673A */ - {0x00e69cbd, 0x00b5e0}, /* U+673D */ - {0x00e69cbf, 0x00dbb3}, /* U+673F */ - {0x00e69d81, 0x00dbb5}, /* U+6741 */ - {0x00e69d86, 0x00dbb8}, /* U+6746 */ - {0x00e69d87, 0x00f5d1}, /* U+6747 [2000] */ - {0x00e69d88, 0x00f5d2}, /* U+6748 [2000] */ - {0x00e69d89, 0x00bff9}, /* U+6749 */ - {0x00e69d8c, 0x8faebe}, /* U+674C [2000] */ - {0x00e69d8d, 0x8faebf}, /* U+674D [2000] */ - {0x00e69d8e, 0x00cdfb}, /* U+674E */ - {0x00e69d8f, 0x00b0c9}, /* U+674F */ - {0x00e69d90, 0x00bae0}, /* U+6750 */ - {0x00e69d91, 0x00c2bc}, /* U+6751 */ - {0x00e69d93, 0x00bcdd}, /* U+6753 */ - {0x00e69d94, 0x8faec0}, /* U+6754 [2000] */ - {0x00e69d96, 0x00bef3}, /* U+6756 */ - {0x00e69d99, 0x00dbbb}, /* U+6759 */ - {0x00e69d9c, 0x00c5ce}, /* U+675C */ - {0x00e69d9d, 0x8faec1}, /* U+675D [2000] */ - {0x00e69d9e, 0x00dbb9}, /* U+675E */ - {0x00e69d9f, 0x00c2ab}, /* U+675F */ - {0x00e69da0, 0x00dbba}, /* U+6760 */ - {0x00e69da1, 0x00bef2}, /* U+6761 */ - {0x00e69da2, 0x00ccdd}, /* U+6762 */ - {0x00e69da3, 0x00dbbc}, /* U+6763 */ - {0x00e69da4, 0x00dbbd}, /* U+6764 */ - {0x00e69da5, 0x00cde8}, /* U+6765 */ - {0x00e69da6, 0x00f5d0}, /* U+6766 [2000] */ - {0x00e69daa, 0x00dbc2}, /* U+676A */ - {0x00e69dad, 0x00b9ba}, /* U+676D */ - {0x00e69daf, 0x00c7d5}, /* U+676F */ - {0x00e69db0, 0x00dbbf}, /* U+6770 */ - {0x00e69db1, 0x00c5ec}, /* U+6771 */ - {0x00e69db2, 0x00dade}, /* U+6772 */ - {0x00e69db3, 0x00dae2}, /* U+6773 */ - {0x00e69db4, 0x8faec5}, /* U+6774 [2000] */ - {0x00e69db5, 0x00b5cf}, /* U+6775 */ - {0x00e69db6, 0x8faec6}, /* U+6776 [2000] */ - {0x00e69db7, 0x00c7c7}, /* U+6777 */ - {0x00e69dbb, 0x00f5d3}, /* U+677B [2000] */ - {0x00e69dbc, 0x00dbc1}, /* U+677C */ - {0x00e69dbe, 0x00bebe}, /* U+677E */ - {0x00e69dbf, 0x00c8c4}, /* U+677F */ - {0x00e69e81, 0x00f5d4}, /* U+6781 [2000] */ - {0x00e69e85, 0x00dbc7}, /* U+6785 */ - {0x00e69e87, 0x00c8fa}, /* U+6787 */ - {0x00e69e89, 0x00dbbe}, /* U+6789 */ - {0x00e69e8b, 0x00dbc4}, /* U+678B */ - {0x00e69e8c, 0x00dbc3}, /* U+678C */ - {0x00e69e90, 0x00c0cf}, /* U+6790 */ - {0x00e69e92, 0x8faec8}, /* U+6792 [2000] */ - {0x00e69e93, 0x00f5d5}, /* U+6793 [2000] */ - {0x00e69e95, 0x00cbed}, /* U+6795 */ - {0x00e69e97, 0x00ced3}, /* U+6797 */ - {0x00e69e98, 0x00f5d6}, /* U+6798 [2000] */ - {0x00e69e9a, 0x00cbe7}, /* U+679A */ - {0x00e69e9b, 0x00f5d7}, /* U+679B [2000] */ - {0x00e69e9c, 0x00b2cc}, /* U+679C */ - {0x00e69e9d, 0x00bbde}, /* U+679D */ - {0x00e69ea0, 0x00cfc8}, /* U+67A0 */ - {0x00e69ea1, 0x00dbc6}, /* U+67A1 */ - {0x00e69ea2, 0x00bff5}, /* U+67A2 */ - {0x00e69ea6, 0x00dbc5}, /* U+67A6 */ - {0x00e69ea9, 0x00dbc0}, /* U+67A9 */ - {0x00e69eaf, 0x00b8cf}, /* U+67AF */ - {0x00e69eb0, 0x8faecc}, /* U+67B0 [2000] */ - {0x00e69eb2, 0x8faecd}, /* U+67B2 [2000] */ - {0x00e69eb3, 0x00dbcc}, /* U+67B3 */ - {0x00e69eb4, 0x00dbca}, /* U+67B4 */ - {0x00e69eb6, 0x00b2cd}, /* U+67B6 */ - {0x00e69eb7, 0x00dbc8}, /* U+67B7 */ - {0x00e69eb8, 0x00dbce}, /* U+67B8 */ - {0x00e69eb9, 0x00dbd4}, /* U+67B9 */ - {0x00e69ebb, 0x00f5d8}, /* U+67BB [2000] */ - {0x00e69f80, 0x00f5da}, /* U+67C0 [2000] */ - {0x00e69f81, 0x00c2c8}, /* U+67C1 */ - {0x00e69f83, 0x8faece}, /* U+67C3 [2000] */ - {0x00e69f84, 0x00cac1}, /* U+67C4 */ - {0x00e69f86, 0x00dbd6}, /* U+67C6 */ - {0x00e69f88, 0x8faecf}, /* U+67C8 [2000] */ - {0x00e69f8a, 0x00c9a2}, /* U+67CA */ - {0x00e69f8e, 0x00dbd5}, /* U+67CE */ - {0x00e69f8f, 0x00c7f0}, /* U+67CF */ - {0x00e69f90, 0x00cbbf}, /* U+67D0 */ - {0x00e69f91, 0x00b4bb}, /* U+67D1 */ - {0x00e69f92, 0x8faed0}, /* U+67D2 [2000] */ - {0x00e69f93, 0x00c0f7}, /* U+67D3 */ - {0x00e69f94, 0x00bdc0}, /* U+67D4 */ - {0x00e69f97, 0x00f5db}, /* U+67D7 [2000] */ - {0x00e69f98, 0x00c4d3}, /* U+67D8 */ - {0x00e69f99, 0x8faed1}, /* U+67D9 [2000] */ - {0x00e69f9a, 0x00cdae}, /* U+67DA */ - {0x00e69f9b, 0x8faed2}, /* U+67DB [2000] */ - {0x00e69f9d, 0x00dbd1}, /* U+67DD */ - {0x00e69f9e, 0x00dbd0}, /* U+67DE */ - {0x00e69fa2, 0x00dbd2}, /* U+67E2 */ - {0x00e69fa4, 0x00dbcf}, /* U+67E4 */ - {0x00e69fa7, 0x00dbd7}, /* U+67E7 */ - {0x00e69fa9, 0x00dbcd}, /* U+67E9 */ - {0x00e69fac, 0x00dbcb}, /* U+67EC */ - {0x00e69fae, 0x00dbd3}, /* U+67EE */ - {0x00e69faf, 0x00dbc9}, /* U+67EF */ - {0x00e69fb0, 0x8faed3}, /* U+67F0 [2000] */ - {0x00e69fb1, 0x00c3ec}, /* U+67F1 */ - {0x00e69fb3, 0x00ccf8}, /* U+67F3 */ - {0x00e69fb4, 0x00bcc6}, /* U+67F4 */ - {0x00e69fb5, 0x00baf4}, /* U+67F5 */ - {0x00e69fb7, 0x8faed4}, /* U+67F7 [2000] */ - {0x00e69fb9, 0x00f5d9}, /* U+67F9 [2000] */ - {0x00e69fbb, 0x00baba}, /* U+67FB */ - {0x00e69fbc, 0x00f5dc}, /* U+67FC [2000] */ - {0x00e69fbe, 0x00cbef}, /* U+67FE */ - {0x00e69fbf, 0x00b3c1}, /* U+67FF */ - {0x00e6a081, 0x00f5dd}, /* U+6801 [2000] */ - {0x00e6a082, 0x00c4ce}, /* U+6802 */ - {0x00e6a083, 0x00c6ca}, /* U+6803 */ - {0x00e6a084, 0x00b1c9}, /* U+6804 */ - {0x00e6a090, 0x8faecb}, /* U+6810 [2000] */ - {0x00e6a093, 0x00c0f2}, /* U+6813 */ - {0x00e6a096, 0x00c0b4}, /* U+6816 */ - {0x00e6a097, 0x00b7aa}, /* U+6817 */ - {0x00e6a098, 0x8faed8}, /* U+6818 [2000] */ - {0x00e6a09d, 0x00f5df}, /* U+681D [2000] */ - {0x00e6a09e, 0x00dbd9}, /* U+681E */ - {0x00e6a09f, 0x8faed9}, /* U+681F [2000] */ - {0x00e6a0a1, 0x00b9bb}, /* U+6821 */ - {0x00e6a0a2, 0x00b3fc}, /* U+6822 */ - {0x00e6a0a9, 0x00dbdb}, /* U+6829 */ - {0x00e6a0aa, 0x00b3f4}, /* U+682A */ - {0x00e6a0ab, 0x00dbe1}, /* U+682B */ - {0x00e6a0ac, 0x00f5e0}, /* U+682C [2000] */ - {0x00e6a0ad, 0x8faeda}, /* U+682D [2000] */ - {0x00e6a0b1, 0x00f5e1}, /* U+6831 [2000] */ - {0x00e6a0b2, 0x00dbde}, /* U+6832 */ - {0x00e6a0b3, 0x8faedc}, /* U+6833 [2000] */ - {0x00e6a0b4, 0x00c0f3}, /* U+6834 */ - {0x00e6a0b8, 0x00b3cb}, /* U+6838 */ - {0x00e6a0b9, 0x00baac}, /* U+6839 */ - {0x00e6a0bb, 0x8faedd}, /* U+683B [2000] */ - {0x00e6a0bc, 0x00b3ca}, /* U+683C */ - {0x00e6a0bd, 0x00bacf}, /* U+683D */ - {0x00e6a0be, 0x8faede}, /* U+683E [2000] */ - {0x00e6a180, 0x00dbdc}, /* U+6840 */ - {0x00e6a181, 0x00b7e5}, /* U+6841 */ - {0x00e6a182, 0x00b7cb}, /* U+6842 */ - {0x00e6a183, 0x00c5ed}, /* U+6843 */ - {0x00e6a184, 0x8faedf}, /* U+6844 [2000] */ - {0x00e6a185, 0x8faee0}, /* U+6845 [2000] */ - {0x00e6a186, 0x00dbda}, /* U+6846 */ - {0x00e6a188, 0x00b0c6}, /* U+6848 */ - {0x00e6a189, 0x8faee1}, /* U+6849 [2000] */ - {0x00e6a18c, 0x8faee2}, /* U+684C [2000] */ - {0x00e6a18d, 0x00dbdd}, /* U+684D */ - {0x00e6a18e, 0x00dbdf}, /* U+684E */ - {0x00e6a190, 0x00b6cd}, /* U+6850 */ - {0x00e6a191, 0x00b7ac}, /* U+6851 */ - {0x00e6a192, 0x00f5de}, /* U+6852 [2000] */ - {0x00e6a193, 0x00b4bc}, /* U+6853 */ - {0x00e6a194, 0x00b5cb}, /* U+6854 */ - {0x00e6a195, 0x8faee3}, /* U+6855 [2000] */ - {0x00e6a197, 0x8faee4}, /* U+6857 [2000] */ - {0x00e6a199, 0x00dbe2}, /* U+6859 */ - {0x00e6a19b, 0x00f5e2}, /* U+685B [2000] */ - {0x00e6a19c, 0x00baf9}, /* U+685C */ - {0x00e6a19d, 0x00cbf1}, /* U+685D */ - {0x00e6a19f, 0x00bbb7}, /* U+685F */ - {0x00e6a1a3, 0x00dbe3}, /* U+6863 */ - {0x00e6a1a7, 0x00c9b0}, /* U+6867 */ - {0x00e6a1ab, 0x8faee6}, /* U+686B [2000] */ - {0x00e6a1ae, 0x8faee7}, /* U+686E [2000] */ - {0x00e6a1b2, 0x00f5e3}, /* U+6872 [2000] */ - {0x00e6a1b4, 0x00dbef}, /* U+6874 */ - {0x00e6a1b5, 0x00f5e4}, /* U+6875 [2000] */ - {0x00e6a1b6, 0x00b2b3}, /* U+6876 */ - {0x00e6a1b7, 0x00dbe4}, /* U+6877 */ - {0x00e6a1ba, 0x8faee8}, /* U+687A [2000] */ - {0x00e6a1bc, 0x8faee9}, /* U+687C [2000] */ - {0x00e6a1be, 0x00dbf5}, /* U+687E */ - {0x00e6a1bf, 0x00dbe5}, /* U+687F */ - {0x00e6a281, 0x00cec2}, /* U+6881 */ - {0x00e6a282, 0x8faeea}, /* U+6882 [2000] */ - {0x00e6a283, 0x00dbec}, /* U+6883 */ - {0x00e6a285, 0x00c7df}, /* U+6885 */ - {0x00e6a28d, 0x00dbf4}, /* U+688D */ - {0x00e6a28f, 0x00dbe7}, /* U+688F */ - {0x00e6a290, 0x8faeeb}, /* U+6890 [2000] */ - {0x00e6a293, 0x00b0b4}, /* U+6893 */ - {0x00e6a294, 0x00dbe9}, /* U+6894 */ - {0x00e6a296, 0x8faeec}, /* U+6896 [2000] */ - {0x00e6a297, 0x00b9bc}, /* U+6897 */ - {0x00e6a298, 0x8faeee}, /* U+6898 [2000] */ - {0x00e6a299, 0x8faeef}, /* U+6899 [2000] */ - {0x00e6a29a, 0x8faef0}, /* U+689A [2000] */ - {0x00e6a29b, 0x00dbeb}, /* U+689B */ - {0x00e6a29c, 0x8faef1}, /* U+689C [2000] */ - {0x00e6a29d, 0x00dbea}, /* U+689D */ - {0x00e6a29f, 0x00dbe6}, /* U+689F */ - {0x00e6a2a0, 0x00dbf1}, /* U+68A0 */ - {0x00e6a2a2, 0x00bebf}, /* U+68A2 */ - {0x00e6a2a3, 0x00f5e6}, /* U+68A3 [2000] */ - {0x00e6a2a5, 0x00f5e7}, /* U+68A5 [2000] */ - {0x00e6a2a6, 0x00d4ed}, /* U+68A6 */ - {0x00e6a2a7, 0x00b8e8}, /* U+68A7 */ - {0x00e6a2a8, 0x00cdfc}, /* U+68A8 */ - {0x00e6a2aa, 0x8faef2}, /* U+68AA [2000] */ - {0x00e6a2ab, 0x8faef3}, /* U+68AB [2000] */ - {0x00e6a2ad, 0x00dbe8}, /* U+68AD */ - {0x00e6a2af, 0x00c4f4}, /* U+68AF */ - {0x00e6a2b0, 0x00b3a3}, /* U+68B0 */ - {0x00e6a2b1, 0x00baad}, /* U+68B1 */ - {0x00e6a2b2, 0x00f5e8}, /* U+68B2 [2000] */ - {0x00e6a2b3, 0x00dbe0}, /* U+68B3 */ - {0x00e6a2b4, 0x8faef4}, /* U+68B4 [2000] */ - {0x00e6a2b5, 0x00dbf0}, /* U+68B5 */ - {0x00e6a2b6, 0x00b3e1}, /* U+68B6 */ - {0x00e6a2b9, 0x00dbee}, /* U+68B9 */ - {0x00e6a2ba, 0x00dbf2}, /* U+68BA */ - {0x00e6a2bb, 0x8faef5}, /* U+68BB [2000] */ - {0x00e6a2bc, 0x00c5ee}, /* U+68BC */ - {0x00e6a383, 0x8faefa}, /* U+68C3 [2000] */ - {0x00e6a384, 0x00b4fe}, /* U+68C4 */ - {0x00e6a385, 0x8faefb}, /* U+68C5 [2000] */ - {0x00e6a386, 0x00dcb2}, /* U+68C6 */ - {0x00e6a388, 0x00f5e9}, /* U+68C8 [2000] */ - {0x00e6a389, 0x00ccc9}, /* U+68C9 */ - {0x00e6a38a, 0x00dbf7}, /* U+68CA */ - {0x00e6a38b, 0x00b4fd}, /* U+68CB */ - {0x00e6a38c, 0x8faefc}, /* U+68CC [2000] */ - {0x00e6a38d, 0x00dbfe}, /* U+68CD */ - {0x00e6a38f, 0x8faefd}, /* U+68CF [2000] */ - {0x00e6a390, 0x00f5ea}, /* U+68D0 [2000] */ - {0x00e6a392, 0x00cbc0}, /* U+68D2 */ - {0x00e6a394, 0x00dca1}, /* U+68D4 */ - {0x00e6a395, 0x00dca3}, /* U+68D5 */ - {0x00e6a396, 0x8faefe}, /* U+68D6 [2000] */ - {0x00e6a397, 0x00dca7}, /* U+68D7 */ - {0x00e6a398, 0x00dbf9}, /* U+68D8 */ - {0x00e6a399, 0x8fafa1}, /* U+68D9 [2000] */ - {0x00e6a39a, 0x00c3aa}, /* U+68DA */ - {0x00e6a39f, 0x00c5ef}, /* U+68DF */ - {0x00e6a3a0, 0x00dcab}, /* U+68E0 */ - {0x00e6a3a1, 0x00dbfc}, /* U+68E1 */ - {0x00e6a3a3, 0x00dca8}, /* U+68E3 */ - {0x00e6a3a4, 0x8fafa2}, /* U+68E4 [2000] */ - {0x00e6a3a5, 0x8fafa3}, /* U+68E5 [2000] */ - {0x00e6a3a7, 0x00dca2}, /* U+68E7 */ - {0x00e6a3a8, 0x00f5eb}, /* U+68E8 [2000] */ - {0x00e6a3ac, 0x8fafa4}, /* U+68EC [2000] */ - {0x00e6a3ad, 0x00f5ec}, /* U+68ED [2000] */ - {0x00e6a3ae, 0x00bfb9}, /* U+68EE */ - {0x00e6a3af, 0x00dcac}, /* U+68EF */ - {0x00e6a3b0, 0x00f5ed}, /* U+68F0 [2000] */ - {0x00e6a3b1, 0x00f5ee}, /* U+68F1 [2000] */ - {0x00e6a3b2, 0x00c0b3}, /* U+68F2 */ - {0x00e6a3b7, 0x8fafa5}, /* U+68F7 [2000] */ - {0x00e6a3b9, 0x00dcaa}, /* U+68F9 */ - {0x00e6a3ba, 0x00b4bd}, /* U+68FA */ - {0x00e6a3bb, 0x8faef6}, /* U+68FB [2000] */ - {0x00e6a3bc, 0x00f5ef}, /* U+68FC [2000] */ - {0x00e6a480, 0x00cfd0}, /* U+6900 */ - {0x00e6a481, 0x00dbf6}, /* U+6901 */ - {0x00e6a483, 0x8fafa6}, /* U+6903 [2000] */ - {0x00e6a484, 0x00dca6}, /* U+6904 */ - {0x00e6a485, 0x00b0d8}, /* U+6905 */ - {0x00e6a487, 0x8fafa7}, /* U+6907 [2000] */ - {0x00e6a488, 0x00dbf8}, /* U+6908 */ - {0x00e6a48a, 0x00f5f0}, /* U+690A [2000] */ - {0x00e6a48b, 0x00ccba}, /* U+690B */ - {0x00e6a48c, 0x00dbfd}, /* U+690C */ - {0x00e6a48d, 0x00bfa2}, /* U+690D */ - {0x00e6a48e, 0x00c4c7}, /* U+690E */ - {0x00e6a48f, 0x00dbf3}, /* U+690F */ - {0x00e6a492, 0x00dca5}, /* U+6912 */ - {0x00e6a499, 0x00bffa}, /* U+6919 */ - {0x00e6a49a, 0x00dcaf}, /* U+691A */ - {0x00e6a49b, 0x00b3f1}, /* U+691B */ - {0x00e6a49c, 0x00b8a1}, /* U+691C */ - {0x00e6a4a1, 0x00dcb1}, /* U+6921 */ - {0x00e6a4a2, 0x00dbfa}, /* U+6922 */ - {0x00e6a4a3, 0x00dcb0}, /* U+6923 */ - {0x00e6a4a5, 0x00dca9}, /* U+6925 */ - {0x00e6a4a6, 0x00dbfb}, /* U+6926 */ - {0x00e6a4a8, 0x00dcad}, /* U+6928 */ - {0x00e6a4aa, 0x00dcae}, /* U+692A */ - {0x00e6a4b0, 0x00dcbf}, /* U+6930 */ - {0x00e6a4b4, 0x00c6ce}, /* U+6934 */ - {0x00e6a4b5, 0x00f5f3}, /* U+6935 [2000] */ - {0x00e6a4b6, 0x00dca4}, /* U+6936 */ - {0x00e6a4b9, 0x00dcbb}, /* U+6939 */ - {0x00e6a4bb, 0x8fafab}, /* U+693B [2000] */ - {0x00e6a4bd, 0x00dcbd}, /* U+693D */ - {0x00e6a4bf, 0x00c4d8}, /* U+693F */ - {0x00e6a582, 0x00f5f4}, /* U+6942 [2000] */ - {0x00e6a586, 0x8fafad}, /* U+6946 [2000] */ - {0x00e6a589, 0x00f5f1}, /* U+6949 [2000] */ - {0x00e6a58a, 0x00cdcc}, /* U+694A */ - {0x00e6a593, 0x00c9f6}, /* U+6953 */ - {0x00e6a594, 0x00dcb8}, /* U+6954 */ - {0x00e6a595, 0x00c2ca}, /* U+6955 */ - {0x00e6a597, 0x00f5f5}, /* U+6957 [2000] */ - {0x00e6a599, 0x00dcbe}, /* U+6959 */ - {0x00e6a59a, 0x00c1bf}, /* U+695A */ - {0x00e6a59c, 0x00dcb5}, /* U+695C */ - {0x00e6a59d, 0x00dcc2}, /* U+695D */ - {0x00e6a59e, 0x00dcc1}, /* U+695E */ - {0x00e6a5a0, 0x00c6ef}, /* U+6960 */ - {0x00e6a5a1, 0x00dcc0}, /* U+6961 */ - {0x00e6a5a2, 0x00c6ea}, /* U+6962 */ - {0x00e6a5a3, 0x00f5f6}, /* U+6963 [2000] */ - {0x00e6a5a4, 0x00f5f7}, /* U+6964 [2000] */ - {0x00e6a5a8, 0x00f5f8}, /* U+6968 [2000] */ - {0x00e6a5a9, 0x8fafae}, /* U+6969 [2000] */ - {0x00e6a5aa, 0x00dcc4}, /* U+696A */ - {0x00e6a5ab, 0x00dcb7}, /* U+696B */ - {0x00e6a5ac, 0x8fafaf}, /* U+696C [2000] */ - {0x00e6a5ad, 0x00b6c8}, /* U+696D */ - {0x00e6a5ae, 0x00dcba}, /* U+696E */ - {0x00e6a5af, 0x00bddd}, /* U+696F */ - {0x00e6a5b2, 0x8fafb0}, /* U+6972 [2000] */ - {0x00e6a5b3, 0x00c7e0}, /* U+6973 */ - {0x00e6a5b4, 0x00dcbc}, /* U+6974 */ - {0x00e6a5b5, 0x00b6cb}, /* U+6975 */ - {0x00e6a5b7, 0x00dcb4}, /* U+6977 */ - {0x00e6a5b8, 0x00dcb6}, /* U+6978 */ - {0x00e6a5b9, 0x00dcb3}, /* U+6979 */ - {0x00e6a5ba, 0x8fafb1}, /* U+697A [2000] */ - {0x00e6a5bc, 0x00cfb0}, /* U+697C */ - {0x00e6a5bd, 0x00b3da}, /* U+697D */ - {0x00e6a5be, 0x00dcb9}, /* U+697E */ - {0x00e6a5bf, 0x8fafb2}, /* U+697F [2000] */ - {0x00e6a680, 0x00f5f9}, /* U+6980 [2000] */ - {0x00e6a681, 0x00dcc3}, /* U+6981 */ - {0x00e6a682, 0x00b3b5}, /* U+6982 */ - {0x00e6a68a, 0x00bae7}, /* U+698A */ - {0x00e6a68e, 0x00b1dd}, /* U+698E */ - {0x00e6a691, 0x00dcd4}, /* U+6991 */ - {0x00e6a692, 0x8fafb3}, /* U+6992 [2000] */ - {0x00e6a694, 0x00cfb1}, /* U+6994 */ - {0x00e6a695, 0x00dcd7}, /* U+6995 */ - {0x00e6a696, 0x8fafb5}, /* U+6996 [2000] */ - {0x00e6a698, 0x8fafb6}, /* U+6998 [2000] */ - {0x00e6a69b, 0x00bfba}, /* U+699B */ - {0x00e6a69c, 0x00dcd6}, /* U+699C */ - {0x00e6a6a0, 0x00dcd5}, /* U+69A0 */ - {0x00e6a6a5, 0x00f5fb}, /* U+69A5 [2000] */ - {0x00e6a6a6, 0x8fafb7}, /* U+69A6 [2000] */ - {0x00e6a6a7, 0x00dcd2}, /* U+69A7 */ - {0x00e6a6ad, 0x00f5fc}, /* U+69AD [2000] */ - {0x00e6a6ae, 0x00dcc6}, /* U+69AE */ - {0x00e6a6b0, 0x8fafb8}, /* U+69B0 [2000] */ - {0x00e6a6b1, 0x00dce3}, /* U+69B1 */ - {0x00e6a6b2, 0x00dcc5}, /* U+69B2 */ - {0x00e6a6b4, 0x00dcd8}, /* U+69B4 */ - {0x00e6a6b7, 0x8fafb9}, /* U+69B7 [2000] */ - {0x00e6a6ba, 0x8fafba}, /* U+69BA [2000] */ - {0x00e6a6bb, 0x00dcd0}, /* U+69BB */ - {0x00e6a6bc, 0x8fafbb}, /* U+69BC [2000] */ - {0x00e6a6be, 0x00dccb}, /* U+69BE */ - {0x00e6a6bf, 0x00dcc8}, /* U+69BF */ - {0x00e6a780, 0x8fafbc}, /* U+69C0 [2000] */ - {0x00e6a781, 0x00dcc9}, /* U+69C1 */ - {0x00e6a783, 0x00dcd1}, /* U+69C3 */ - {0x00e6a787, 0x00f4a2}, /* U+69C7 [1983] */ - {0x00e6a78a, 0x00dcce}, /* U+69CA */ - {0x00e6a78b, 0x00b9bd}, /* U+69CB */ - {0x00e6a78c, 0x00c4c8}, /* U+69CC */ - {0x00e6a78d, 0x00c1e4}, /* U+69CD */ - {0x00e6a78e, 0x00dccc}, /* U+69CE */ - {0x00e6a78f, 0x00f5fd}, /* U+69CF [2000] */ - {0x00e6a790, 0x00dcc7}, /* U+69D0 */ - {0x00e6a791, 0x8fafbd}, /* U+69D1 [2000] */ - {0x00e6a793, 0x00dcca}, /* U+69D3 */ - {0x00e6a796, 0x8fafbe}, /* U+69D6 [2000] */ - {0x00e6a798, 0x00cdcd}, /* U+69D8 */ - {0x00e6a799, 0x00cbea}, /* U+69D9 */ - {0x00e6a79d, 0x00dccf}, /* U+69DD */ - {0x00e6a79e, 0x00dcd9}, /* U+69DE */ - {0x00e6a7a2, 0x00f6a2}, /* U+69E2 [2000] */ - {0x00e6a7a3, 0x8fafc4}, /* U+69E3 [2000] */ - {0x00e6a7a7, 0x00dce1}, /* U+69E7 */ - {0x00e6a7a8, 0x00dcda}, /* U+69E8 */ - {0x00e6a7a9, 0x00f6a3}, /* U+69E9 [2000] */ - {0x00e6a7aa, 0x00f6a4}, /* U+69EA [2000] */ - {0x00e6a7ab, 0x00dce7}, /* U+69EB */ - {0x00e6a7ad, 0x00dce5}, /* U+69ED */ - {0x00e6a7ae, 0x8fafc5}, /* U+69EE [2000] */ - {0x00e6a7af, 0x8fafc6}, /* U+69EF [2000] */ - {0x00e6a7b2, 0x00dce0}, /* U+69F2 */ - {0x00e6a7b3, 0x8fafc7}, /* U+69F3 [2000] */ - {0x00e6a7b4, 0x8fafc9}, /* U+69F4 [2000] */ - {0x00e6a7b5, 0x00f6a5}, /* U+69F5 [2000] */ - {0x00e6a7b6, 0x00f6a6}, /* U+69F6 [2000] */ - {0x00e6a7b9, 0x00dcdf}, /* U+69F9 */ - {0x00e6a7bb, 0x00c4d0}, /* U+69FB */ - {0x00e6a7bd, 0x00c1e5}, /* U+69FD */ - {0x00e6a7be, 0x8fafca}, /* U+69FE [2000] */ - {0x00e6a7bf, 0x00dcdd}, /* U+69FF */ - {0x00e6a882, 0x00dcdb}, /* U+6A02 */ - {0x00e6a885, 0x00dce2}, /* U+6A05 */ - {0x00e6a88a, 0x00dce8}, /* U+6A0A */ - {0x00e6a88b, 0x00c8f5}, /* U+6A0B */ - {0x00e6a88c, 0x00dcee}, /* U+6A0C */ - {0x00e6a88f, 0x00f6a7}, /* U+6A0F [2000] */ - {0x00e6a891, 0x8fafcb}, /* U+6A11 [2000] */ - {0x00e6a892, 0x00dce9}, /* U+6A12 */ - {0x00e6a893, 0x00dcec}, /* U+6A13 */ - {0x00e6a894, 0x00dce6}, /* U+6A14 */ - {0x00e6a895, 0x00f6a8}, /* U+6A15 [2000] */ - {0x00e6a897, 0x00c3f4}, /* U+6A17 */ - {0x00e6a899, 0x00c9b8}, /* U+6A19 */ - {0x00e6a89a, 0x8fafcc}, /* U+6A1A [2000] */ - {0x00e6a89b, 0x00dcdc}, /* U+6A1B */ - {0x00e6a89d, 0x8fafcd}, /* U+6A1D [2000] */ - {0x00e6a89e, 0x00dce4}, /* U+6A1E */ - {0x00e6a89f, 0x00bec0}, /* U+6A1F */ - {0x00e6a8a1, 0x00cccf}, /* U+6A21 */ - {0x00e6a8a2, 0x00dcf8}, /* U+6A22 */ - {0x00e6a8a3, 0x00dceb}, /* U+6A23 */ - {0x00e6a8a9, 0x00b8a2}, /* U+6A29 */ - {0x00e6a8aa, 0x00b2a3}, /* U+6A2A */ - {0x00e6a8ab, 0x00b3df}, /* U+6A2B */ - {0x00e6a8ae, 0x00dcd3}, /* U+6A2E */ - {0x00e6a8b0, 0x8fafc1}, /* U+6A30 [2000] */ - {0x00e6a8b2, 0x8fafcf}, /* U+6A32 [2000] */ - {0x00e6a8b3, 0x8fafd0}, /* U+6A33 [2000] */ - {0x00e6a8b4, 0x8fafd1}, /* U+6A34 [2000] */ - {0x00e6a8b5, 0x00bec1}, /* U+6A35 */ - {0x00e6a8b6, 0x00dcf0}, /* U+6A36 */ - {0x00e6a8b8, 0x00dcf7}, /* U+6A38 */ - {0x00e6a8b9, 0x00bcf9}, /* U+6A39 */ - {0x00e6a8ba, 0x00b3f2}, /* U+6A3A */ - {0x00e6a8bb, 0x00f6aa}, /* U+6A3B [2000] */ - {0x00e6a8bd, 0x00c3ae}, /* U+6A3D */ - {0x00e6a8be, 0x00f6ab}, /* U+6A3E [2000] */ - {0x00e6a8bf, 0x8fafd2}, /* U+6A3F [2000] */ - {0x00e6a984, 0x00dced}, /* U+6A44 */ - {0x00e6a985, 0x00f6ac}, /* U+6A45 [2000] */ - {0x00e6a986, 0x8fafd3}, /* U+6A46 [2000] */ - {0x00e6a987, 0x00dcf2}, /* U+6A47 */ - {0x00e6a988, 0x00dcf6}, /* U+6A48 */ - {0x00e6a989, 0x8fafd4}, /* U+6A49 [2000] */ - {0x00e6a98b, 0x00b6b6}, /* U+6A4B */ - {0x00e6a98e, 0x8fafd6}, /* U+6A4E [2000] */ - {0x00e6a990, 0x00f6ad}, /* U+6A50 [2000] */ - {0x00e6a992, 0x8fafd7}, /* U+6A52 [2000] */ - {0x00e6a996, 0x00f6ae}, /* U+6A56 [2000] */ - {0x00e6a998, 0x00b5cc}, /* U+6A58 */ - {0x00e6a999, 0x00dcf4}, /* U+6A59 */ - {0x00e6a99b, 0x00f6af}, /* U+6A5B [2000] */ - {0x00e6a99f, 0x00b5a1}, /* U+6A5F */ - {0x00e6a9a1, 0x00c6cb}, /* U+6A61 */ - {0x00e6a9a2, 0x00dcf3}, /* U+6A62 */ - {0x00e6a9a4, 0x8fafd8}, /* U+6A64 [2000] */ - {0x00e6a9a6, 0x00dcf5}, /* U+6A66 */ - {0x00e6a9ab, 0x00f6b0}, /* U+6A6B [2000] */ - {0x00e6a9b2, 0x00dcef}, /* U+6A72 */ - {0x00e6a9b3, 0x00f6b1}, /* U+6A73 [2000] */ - {0x00e6a9b8, 0x00dcf1}, /* U+6A78 */ - {0x00e6a9ba, 0x8fafd5}, /* U+6A7A [2000] */ - {0x00e6a9be, 0x8fafda}, /* U+6A7E [2000] */ - {0x00e6a9bf, 0x00b3e0}, /* U+6A7F */ - {0x00e6aa80, 0x00c3c9}, /* U+6A80 */ - {0x00e6aa83, 0x8fafdb}, /* U+6A83 [2000] */ - {0x00e6aa84, 0x00dcfc}, /* U+6A84 */ - {0x00e6aa89, 0x00f6b3}, /* U+6A89 [2000] */ - {0x00e6aa8b, 0x8fafdc}, /* U+6A8B [2000] */ - {0x00e6aa8d, 0x00dcfa}, /* U+6A8D */ - {0x00e6aa8e, 0x00b8e9}, /* U+6A8E */ - {0x00e6aa90, 0x00dcf9}, /* U+6A90 */ - {0x00e6aa91, 0x8fafde}, /* U+6A91 [2000] */ - {0x00e6aa94, 0x00f6b4}, /* U+6A94 [2000] */ - {0x00e6aa97, 0x00dda1}, /* U+6A97 */ - {0x00e6aa9c, 0x00dbd8}, /* U+6A9C */ - {0x00e6aa9d, 0x00f6b5}, /* U+6A9D [2000] */ - {0x00e6aa9e, 0x00f6b6}, /* U+6A9E [2000] */ - {0x00e6aa9f, 0x8fafdf}, /* U+6A9F [2000] */ - {0x00e6aaa0, 0x00dcfb}, /* U+6AA0 */ - {0x00e6aaa1, 0x8fafe0}, /* U+6AA1 [2000] */ - {0x00e6aaa2, 0x00dcfd}, /* U+6AA2 */ - {0x00e6aaa3, 0x00dcfe}, /* U+6AA3 */ - {0x00e6aaa5, 0x00f6b7}, /* U+6AA5 [2000] */ - {0x00e6aaaa, 0x00ddac}, /* U+6AAA */ - {0x00e6aaab, 0x8fafe2}, /* U+6AAB [2000] */ - {0x00e6aaac, 0x00dda8}, /* U+6AAC */ - {0x00e6aaae, 0x00dbed}, /* U+6AAE */ - {0x00e6aab3, 0x00dda7}, /* U+6AB3 */ - {0x00e6aab8, 0x00dda6}, /* U+6AB8 */ - {0x00e6aabb, 0x00dda3}, /* U+6ABB */ - {0x00e6aabd, 0x8fafe3}, /* U+6ABD [2000] */ - {0x00e6ab81, 0x00dcea}, /* U+6AC1 */ - {0x00e6ab82, 0x00dda5}, /* U+6AC2 */ - {0x00e6ab83, 0x00dda4}, /* U+6AC3 */ - {0x00e6ab86, 0x8fafe4}, /* U+6AC6 [2000] */ - {0x00e6ab90, 0x8fafe6}, /* U+6AD0 [2000] */ - {0x00e6ab91, 0x00ddaa}, /* U+6AD1 */ - {0x00e6ab93, 0x00cfa6}, /* U+6AD3 */ - {0x00e6ab94, 0x8fafe5}, /* U+6AD4 [2000] */ - {0x00e6ab9a, 0x00ddad}, /* U+6ADA */ - {0x00e6ab9b, 0x00b6fb}, /* U+6ADB */ - {0x00e6ab9c, 0x8fafe7}, /* U+6ADC [2000] */ - {0x00e6ab9d, 0x8fafe8}, /* U+6ADD [2000] */ - {0x00e6ab9e, 0x00dda9}, /* U+6ADE */ - {0x00e6ab9f, 0x00ddab}, /* U+6ADF */ - {0x00e6aba4, 0x00f6b8}, /* U+6AE4 [2000] */ - {0x00e6aba7, 0x00f6b9}, /* U+6AE7 [2000] */ - {0x00e6aba8, 0x00c8a7}, /* U+6AE8 */ - {0x00e6abaa, 0x00ddae}, /* U+6AEA */ - {0x00e6abac, 0x8fafeb}, /* U+6AEC [2000] */ - {0x00e6abb1, 0x8fafec}, /* U+6AF1 [2000] */ - {0x00e6abb2, 0x8fafed}, /* U+6AF2 [2000] */ - {0x00e6abb3, 0x8fafee}, /* U+6AF3 [2000] */ - {0x00e6abba, 0x00ddb2}, /* U+6AFA */ - {0x00e6abbb, 0x00ddaf}, /* U+6AFB */ - {0x00e6abbd, 0x8fafef}, /* U+6AFD [2000] */ - {0x00e6ac84, 0x00cdf3}, /* U+6B04 */ - {0x00e6ac85, 0x00ddb0}, /* U+6B05 */ - {0x00e6ac8a, 0x00dcde}, /* U+6B0A */ - {0x00e6ac8b, 0x8faff1}, /* U+6B0B [2000] */ - {0x00e6ac8f, 0x8faff2}, /* U+6B0F [2000] */ - {0x00e6ac90, 0x8faff3}, /* U+6B10 [2000] */ - {0x00e6ac91, 0x8faff4}, /* U+6B11 [2000] */ - {0x00e6ac92, 0x00ddb3}, /* U+6B12 */ - {0x00e6ac96, 0x00ddb4}, /* U+6B16 */ - {0x00e6ac97, 0x8faff6}, /* U+6B17 [2000] */ - {0x00e6ac9b, 0x00f6bc}, /* U+6B1B [2000] */ - {0x00e6ac9d, 0x00b1b5}, /* U+6B1D */ - {0x00e6ac9e, 0x00f6bd}, /* U+6B1E [2000] */ - {0x00e6ac9f, 0x00ddb6}, /* U+6B1F */ - {0x00e6aca0, 0x00b7e7}, /* U+6B20 */ - {0x00e6aca1, 0x00bca1}, /* U+6B21 */ - {0x00e6aca3, 0x00b6d5}, /* U+6B23 */ - {0x00e6aca7, 0x00b2a4}, /* U+6B27 */ - {0x00e6acac, 0x00f6be}, /* U+6B2C [2000] */ - {0x00e6acaf, 0x8faff8}, /* U+6B2F [2000] */ - {0x00e6acb2, 0x00cddf}, /* U+6B32 */ - {0x00e6acb5, 0x00f6bf}, /* U+6B35 [2000] */ - {0x00e6acb7, 0x00ddb8}, /* U+6B37 */ - {0x00e6acb8, 0x00ddb7}, /* U+6B38 */ - {0x00e6acb9, 0x00ddba}, /* U+6B39 */ - {0x00e6acba, 0x00b5bd}, /* U+6B3A */ - {0x00e6acbd, 0x00b6d6}, /* U+6B3D */ - {0x00e6acbe, 0x00b4be}, /* U+6B3E */ - {0x00e6ad83, 0x00ddbd}, /* U+6B43 */ - {0x00e6ad86, 0x00f6c0}, /* U+6B46 [2000] */ - {0x00e6ad87, 0x00ddbc}, /* U+6B47 */ - {0x00e6ad89, 0x00ddbe}, /* U+6B49 */ - {0x00e6ad8a, 0x8faff9}, /* U+6B4A [2000] */ - {0x00e6ad8c, 0x00b2ce}, /* U+6B4C */ - {0x00e6ad8e, 0x00c3b7}, /* U+6B4E */ - {0x00e6ad90, 0x00ddbf}, /* U+6B50 */ - {0x00e6ad93, 0x00b4bf}, /* U+6B53 */ - {0x00e6ad94, 0x00ddc1}, /* U+6B54 */ - {0x00e6ad96, 0x00f6c1}, /* U+6B56 [2000] */ - {0x00e6ad98, 0x8faffa}, /* U+6B58 [2000] */ - {0x00e6ad99, 0x00ddc0}, /* U+6B59 */ - {0x00e6ad9b, 0x00ddc2}, /* U+6B5B */ - {0x00e6ad9f, 0x00ddc3}, /* U+6B5F */ - {0x00e6ada0, 0x00f6c2}, /* U+6B60 [2000] */ - {0x00e6ada1, 0x00ddc4}, /* U+6B61 */ - {0x00e6ada2, 0x00bbdf}, /* U+6B62 */ - {0x00e6ada3, 0x00c0b5}, /* U+6B63 */ - {0x00e6ada4, 0x00baa1}, /* U+6B64 */ - {0x00e6ada5, 0x00f6c3}, /* U+6B65 [2000] */ - {0x00e6ada6, 0x00c9f0}, /* U+6B66 */ - {0x00e6ada7, 0x00f6c4}, /* U+6B67 [2000] */ - {0x00e6ada9, 0x00cae2}, /* U+6B69 */ - {0x00e6adaa, 0x00cfc4}, /* U+6B6A */ - {0x00e6adac, 0x8faffb}, /* U+6B6C [2000] */ - {0x00e6adaf, 0x00bbf5}, /* U+6B6F */ - {0x00e6adb3, 0x00bad0}, /* U+6B73 */ - {0x00e6adb4, 0x00cef2}, /* U+6B74 */ - {0x00e6adb5, 0x8faffc}, /* U+6B75 [2000] */ - {0x00e6adb7, 0x00f6c5}, /* U+6B77 [2000] */ - {0x00e6adb8, 0x00ddc5}, /* U+6B78 */ - {0x00e6adb9, 0x00ddc6}, /* U+6B79 */ - {0x00e6adba, 0x8faffd}, /* U+6B7A [2000] */ - {0x00e6adbb, 0x00bbe0}, /* U+6B7B */ - {0x00e6adbf, 0x00ddc7}, /* U+6B7F */ - {0x00e6ae80, 0x00ddc8}, /* U+6B80 */ - {0x00e6ae81, 0x8faffe}, /* U+6B81 [2000] */ - {0x00e6ae82, 0x00f6c6}, /* U+6B82 [2000] */ - {0x00e6ae83, 0x00ddca}, /* U+6B83 */ - {0x00e6ae84, 0x00ddc9}, /* U+6B84 */ - {0x00e6ae86, 0x00cbd8}, /* U+6B86 */ - {0x00e6ae89, 0x00bdde}, /* U+6B89 */ - {0x00e6ae8a, 0x00bcec}, /* U+6B8A */ - {0x00e6ae8b, 0x00bbc4}, /* U+6B8B */ - {0x00e6ae8d, 0x00ddcb}, /* U+6B8D */ - {0x00e6ae95, 0x00ddcd}, /* U+6B95 */ - {0x00e6ae96, 0x00bfa3}, /* U+6B96 */ - {0x00e6ae98, 0x00ddcc}, /* U+6B98 */ - {0x00e6ae9b, 0x8feea1}, /* U+6B9B [2000] */ - {0x00e6ae9e, 0x00ddce}, /* U+6B9E */ - {0x00e6aea4, 0x00ddcf}, /* U+6BA4 */ - {0x00e6aea9, 0x00f6c7}, /* U+6BA9 [2000] */ - {0x00e6aeaa, 0x00ddd0}, /* U+6BAA */ - {0x00e6aeab, 0x00ddd1}, /* U+6BAB */ - {0x00e6aead, 0x00f6c8}, /* U+6BAD [2000] */ - {0x00e6aeae, 0x8feea2}, /* U+6BAE [2000] */ - {0x00e6aeaf, 0x00ddd2}, /* U+6BAF */ - {0x00e6aeb1, 0x00ddd4}, /* U+6BB1 */ - {0x00e6aeb2, 0x00ddd3}, /* U+6BB2 */ - {0x00e6aeb3, 0x00ddd5}, /* U+6BB3 */ - {0x00e6aeb4, 0x00b2a5}, /* U+6BB4 */ - {0x00e6aeb5, 0x00c3ca}, /* U+6BB5 */ - {0x00e6aeb7, 0x00ddd6}, /* U+6BB7 */ - {0x00e6aeba, 0x00bba6}, /* U+6BBA */ - {0x00e6aebb, 0x00b3cc}, /* U+6BBB */ - {0x00e6aebc, 0x00ddd7}, /* U+6BBC */ - {0x00e6aebd, 0x8feea4}, /* U+6BBD [2000] */ - {0x00e6aebe, 0x8feea5}, /* U+6BBE [2000] */ - {0x00e6aebf, 0x00c5c2}, /* U+6BBF */ - {0x00e6af80, 0x00d4cc}, /* U+6BC0 */ - {0x00e6af85, 0x00b5a3}, /* U+6BC5 */ - {0x00e6af86, 0x00ddd8}, /* U+6BC6 */ - {0x00e6af87, 0x8feea6}, /* U+6BC7 [2000] */ - {0x00e6af88, 0x8feea7}, /* U+6BC8 [2000] */ - {0x00e6af89, 0x8feea8}, /* U+6BC9 [2000] */ - {0x00e6af8b, 0x00ddd9}, /* U+6BCB */ - {0x00e6af8d, 0x00caec}, /* U+6BCD */ - {0x00e6af8e, 0x00cbe8}, /* U+6BCE */ - {0x00e6af8f, 0x00f6ca}, /* U+6BCF [2000] */ - {0x00e6af92, 0x00c6c7}, /* U+6BD2 */ - {0x00e6af93, 0x00ddda}, /* U+6BD3 */ - {0x00e6af94, 0x00c8e6}, /* U+6BD4 */ - {0x00e6af96, 0x00f6cb}, /* U+6BD6 [2000] */ - {0x00e6af97, 0x00f6cc}, /* U+6BD7 [2000] */ - {0x00e6af98, 0x00c8fb}, /* U+6BD8 */ - {0x00e6af9a, 0x8feea9}, /* U+6BDA [2000] */ - {0x00e6af9b, 0x00ccd3}, /* U+6BDB */ - {0x00e6af9f, 0x00dddb}, /* U+6BDF */ - {0x00e6afa6, 0x8feeaa}, /* U+6BE6 [2000] */ - {0x00e6afa7, 0x8feeab}, /* U+6BE7 [2000] */ - {0x00e6afab, 0x00dddd}, /* U+6BEB */ - {0x00e6afac, 0x00dddc}, /* U+6BEC */ - {0x00e6afae, 0x8feeac}, /* U+6BEE [2000] */ - {0x00e6afaf, 0x00dddf}, /* U+6BEF */ - {0x00e6afb1, 0x8feead}, /* U+6BF1 [2000] */ - {0x00e6afb3, 0x00ddde}, /* U+6BF3 */ - {0x00e6afbf, 0x00f6cd}, /* U+6BFF [2000] */ - {0x00e6b082, 0x8feeae}, /* U+6C02 [2000] */ - {0x00e6b085, 0x00f6ce}, /* U+6C05 [2000] */ - {0x00e6b088, 0x00dde1}, /* U+6C08 */ - {0x00e6b08a, 0x8feeaf}, /* U+6C0A [2000] */ - {0x00e6b08e, 0x8feeb0}, /* U+6C0E [2000] */ - {0x00e6b08f, 0x00bbe1}, /* U+6C0F */ - {0x00e6b090, 0x00f6cf}, /* U+6C10 [2000] */ - {0x00e6b091, 0x00ccb1}, /* U+6C11 */ - {0x00e6b093, 0x00dde2}, /* U+6C13 */ - {0x00e6b094, 0x00dde3}, /* U+6C14 */ - {0x00e6b097, 0x00b5a4}, /* U+6C17 */ - {0x00e6b09b, 0x00dde4}, /* U+6C1B */ - {0x00e6b0a3, 0x00dde6}, /* U+6C23 */ - {0x00e6b0a4, 0x00dde5}, /* U+6C24 */ - {0x00e6b0b3, 0x00f6d0}, /* U+6C33 [2000] */ - {0x00e6b0b4, 0x00bfe5}, /* U+6C34 */ - {0x00e6b0b5, 0x8feeb1}, /* U+6C35 [2000] */ - {0x00e6b0b6, 0x8feeb2}, /* U+6C36 [2000] */ - {0x00e6b0b7, 0x00c9b9}, /* U+6C37 */ - {0x00e6b0b8, 0x00b1ca}, /* U+6C38 */ - {0x00e6b0ba, 0x8feeb3}, /* U+6C3A [2000] */ - {0x00e6b0be, 0x00c8c5}, /* U+6C3E */ - {0x00e6b0bf, 0x8feeb5}, /* U+6C3F [2000] */ - {0x00e6b180, 0x00c4f5}, /* U+6C40 */ - {0x00e6b181, 0x00bdc1}, /* U+6C41 */ - {0x00e6b182, 0x00b5e1}, /* U+6C42 */ - {0x00e6b18d, 0x8feeb6}, /* U+6C4D [2000] */ - {0x00e6b18e, 0x00c8c6}, /* U+6C4E */ - {0x00e6b190, 0x00bcae}, /* U+6C50 */ - {0x00e6b195, 0x00dde8}, /* U+6C55 */ - {0x00e6b197, 0x00b4c0}, /* U+6C57 */ - {0x00e6b199, 0x00f6d1}, /* U+6C59 [2000] */ - {0x00e6b19a, 0x00b1f8}, /* U+6C5A */ - {0x00e6b19b, 0x8feeb7}, /* U+6C5B [2000] */ - {0x00e6b19c, 0x00f6d2}, /* U+6C5C [2000] */ - {0x00e6b19d, 0x00c6f2}, /* U+6C5D */ - {0x00e6b19e, 0x00dde7}, /* U+6C5E */ - {0x00e6b19f, 0x00b9be}, /* U+6C5F */ - {0x00e6b1a0, 0x00c3d3}, /* U+6C60 */ - {0x00e6b1a2, 0x00dde9}, /* U+6C62 */ - {0x00e6b1a7, 0x8feecf}, /* U+6C67 [2000] */ - {0x00e6b1a8, 0x00ddf1}, /* U+6C68 */ - {0x00e6b1aa, 0x00ddea}, /* U+6C6A */ - {0x00e6b1ad, 0x8feeb8}, /* U+6C6D [2000] */ - {0x00e6b1b0, 0x00c2c1}, /* U+6C70 */ - {0x00e6b1b2, 0x00b5e2}, /* U+6C72 */ - {0x00e6b1b3, 0x00ddf2}, /* U+6C73 */ - {0x00e6b1b4, 0x00f6d4}, /* U+6C74 [2000] */ - {0x00e6b1b6, 0x00f6d5}, /* U+6C76 [2000] */ - {0x00e6b1ba, 0x00b7e8}, /* U+6C7A */ - {0x00e6b1bd, 0x00b5a5}, /* U+6C7D */ - {0x00e6b1be, 0x00ddf0}, /* U+6C7E */ - {0x00e6b281, 0x00ddee}, /* U+6C81 */ - {0x00e6b282, 0x00ddeb}, /* U+6C82 */ - {0x00e6b283, 0x00cde0}, /* U+6C83 */ - {0x00e6b284, 0x8feeb9}, /* U+6C84 [2000] */ - {0x00e6b285, 0x00f6d6}, /* U+6C85 [2000] */ - {0x00e6b286, 0x00f6d7}, /* U+6C86 [2000] */ - {0x00e6b288, 0x00c4c0}, /* U+6C88 */ - {0x00e6b289, 0x8feeba}, /* U+6C89 [2000] */ - {0x00e6b28c, 0x00c6d9}, /* U+6C8C */ - {0x00e6b28d, 0x00ddec}, /* U+6C8D */ - {0x00e6b290, 0x00ddf4}, /* U+6C90 */ - {0x00e6b292, 0x00ddf3}, /* U+6C92 */ - {0x00e6b293, 0x00b7a3}, /* U+6C93 */ - {0x00e6b294, 0x8feebc}, /* U+6C94 [2000] */ - {0x00e6b295, 0x8feebd}, /* U+6C95 [2000] */ - {0x00e6b296, 0x00b2ad}, /* U+6C96 */ - {0x00e6b297, 0x8feebe}, /* U+6C97 [2000] */ - {0x00e6b298, 0x00f6d8}, /* U+6C98 [2000] */ - {0x00e6b299, 0x00babb}, /* U+6C99 */ - {0x00e6b29a, 0x00dded}, /* U+6C9A */ - {0x00e6b29b, 0x00ddef}, /* U+6C9B */ - {0x00e6b29c, 0x00f6d9}, /* U+6C9C [2000] */ - {0x00e6b2a1, 0x00cbd7}, /* U+6CA1 */ - {0x00e6b2a2, 0x00c2f4}, /* U+6CA2 */ - {0x00e6b2aa, 0x00f6d3}, /* U+6CAA [2000] */ - {0x00e6b2ab, 0x00cbf7}, /* U+6CAB */ - {0x00e6b2ad, 0x8feebf}, /* U+6CAD [2000] */ - {0x00e6b2ae, 0x00ddfc}, /* U+6CAE */ - {0x00e6b2b1, 0x00ddfd}, /* U+6CB1 */ - {0x00e6b2b3, 0x00b2cf}, /* U+6CB3 */ - {0x00e6b2b8, 0x00caa8}, /* U+6CB8 */ - {0x00e6b2b9, 0x00ccfd}, /* U+6CB9 */ - {0x00e6b2ba, 0x00dea1}, /* U+6CBA */ - {0x00e6b2bb, 0x00bca3}, /* U+6CBB */ - {0x00e6b2bc, 0x00bec2}, /* U+6CBC */ - {0x00e6b2bd, 0x00ddf8}, /* U+6CBD */ - {0x00e6b2be, 0x00ddfe}, /* U+6CBE */ - {0x00e6b2bf, 0x00b1e8}, /* U+6CBF */ - {0x00e6b381, 0x00b6b7}, /* U+6CC1 */ - {0x00e6b382, 0x8feec0}, /* U+6CC2 [2000] */ - {0x00e6b384, 0x00ddf5}, /* U+6CC4 */ - {0x00e6b385, 0x00ddfa}, /* U+6CC5 */ - {0x00e6b386, 0x00f6db}, /* U+6CC6 [2000] */ - {0x00e6b389, 0x00c0f4}, /* U+6CC9 */ - {0x00e6b38a, 0x00c7f1}, /* U+6CCA */ - {0x00e6b38c, 0x00c8e7}, /* U+6CCC */ - {0x00e6b390, 0x8feec1}, /* U+6CD0 [2000] */ - {0x00e6b393, 0x00ddf7}, /* U+6CD3 */ - {0x00e6b394, 0x00f6dc}, /* U+6CD4 [2000] */ - {0x00e6b395, 0x00cba1}, /* U+6CD5 */ - {0x00e6b396, 0x8feec3}, /* U+6CD6 [2000] */ - {0x00e6b397, 0x00ddf9}, /* U+6CD7 */ - {0x00e6b399, 0x00dea4}, /* U+6CD9 */ - {0x00e6b39a, 0x8feec4}, /* U+6CDA [2000] */ - {0x00e6b39b, 0x00dea2}, /* U+6CDB */ - {0x00e6b39c, 0x8feec5}, /* U+6CDC [2000] */ - {0x00e6b39d, 0x00ddfb}, /* U+6CDD */ - {0x00e6b3a0, 0x00f6dd}, /* U+6CE0 [2000] */ - {0x00e6b3a1, 0x00cba2}, /* U+6CE1 */ - {0x00e6b3a2, 0x00c7c8}, /* U+6CE2 */ - {0x00e6b3a3, 0x00b5e3}, /* U+6CE3 */ - {0x00e6b3a5, 0x00c5a5}, /* U+6CE5 */ - {0x00e6b3a8, 0x00c3ed}, /* U+6CE8 */ - {0x00e6b3a9, 0x8feec6}, /* U+6CE9 [2000] */ - {0x00e6b3aa, 0x00dea5}, /* U+6CEA */ - {0x00e6b3ab, 0x00f6de}, /* U+6CEB [2000] */ - {0x00e6b3ac, 0x8feec7}, /* U+6CEC [2000] */ - {0x00e6b3ad, 0x8feec8}, /* U+6CED [2000] */ - {0x00e6b3ae, 0x00f6df}, /* U+6CEE [2000] */ - {0x00e6b3af, 0x00dea3}, /* U+6CEF */ - {0x00e6b3b0, 0x00c2d9}, /* U+6CF0 */ - {0x00e6b3b1, 0x00ddf6}, /* U+6CF1 */ - {0x00e6b3b3, 0x00b1cb}, /* U+6CF3 */ - {0x00e6b3bb, 0x00f6da}, /* U+6CFB [2000] */ - {0x00e6b480, 0x8feeca}, /* U+6D00 [2000] */ - {0x00e6b484, 0x00f6e1}, /* U+6D04 [2000] */ - {0x00e6b48a, 0x8feecb}, /* U+6D0A [2000] */ - {0x00e6b48b, 0x00cdce}, /* U+6D0B */ - {0x00e6b48c, 0x00deb0}, /* U+6D0C */ - {0x00e6b48e, 0x00f6e2}, /* U+6D0E [2000] */ - {0x00e6b492, 0x00deaf}, /* U+6D12 */ - {0x00e6b497, 0x00c0f6}, /* U+6D17 */ - {0x00e6b499, 0x00deac}, /* U+6D19 */ - {0x00e6b49b, 0x00cdec}, /* U+6D1B */ - {0x00e6b49e, 0x00c6b6}, /* U+6D1E */ - {0x00e6b49f, 0x00dea6}, /* U+6D1F */ - {0x00e6b4a4, 0x8feecc}, /* U+6D24 [2000] */ - {0x00e6b4a5, 0x00c4c5}, /* U+6D25 */ - {0x00e6b4a6, 0x8feecd}, /* U+6D26 [2000] */ - {0x00e6b4a7, 0x8feece}, /* U+6D27 [2000] */ - {0x00e6b4a9, 0x00b1cc}, /* U+6D29 */ - {0x00e6b4aa, 0x00b9bf}, /* U+6D2A */ - {0x00e6b4ab, 0x00dea9}, /* U+6D2B */ - {0x00e6b4ae, 0x00f6e3}, /* U+6D2E [2000] */ - {0x00e6b4af, 0x8feed0}, /* U+6D2F [2000] */ - {0x00e6b4b1, 0x00f6e4}, /* U+6D31 [2000] */ - {0x00e6b4b2, 0x00bda7}, /* U+6D32 */ - {0x00e6b4b3, 0x00deae}, /* U+6D33 */ - {0x00e6b4b4, 0x8feee5}, /* U+6D34 [2000] */ - {0x00e6b4b5, 0x00dead}, /* U+6D35 */ - {0x00e6b4b6, 0x00dea8}, /* U+6D36 */ - {0x00e6b4b8, 0x00deab}, /* U+6D38 */ - {0x00e6b4b9, 0x00f6e5}, /* U+6D39 [2000] */ - {0x00e6b4bb, 0x00b3e8}, /* U+6D3B */ - {0x00e6b4bc, 0x8feed1}, /* U+6D3C [2000] */ - {0x00e6b4bd, 0x00deaa}, /* U+6D3D */ - {0x00e6b4be, 0x00c7c9}, /* U+6D3E */ - {0x00e6b4bf, 0x00f6e6}, /* U+6D3F [2000] */ - {0x00e6b581, 0x00ceae}, /* U+6D41 */ - {0x00e6b584, 0x00bef4}, /* U+6D44 */ - {0x00e6b585, 0x00c0f5}, /* U+6D45 */ - {0x00e6b598, 0x00f6e7}, /* U+6D58 [2000] */ - {0x00e6b599, 0x00deb6}, /* U+6D59 */ - {0x00e6b59a, 0x00deb4}, /* U+6D5A */ - {0x00e6b59b, 0x8feed2}, /* U+6D5B [2000] */ - {0x00e6b59c, 0x00c9cd}, /* U+6D5C */ - {0x00e6b59e, 0x8feed3}, /* U+6D5E [2000] */ - {0x00e6b5a0, 0x8feed4}, /* U+6D60 [2000] */ - {0x00e6b5a3, 0x00deb1}, /* U+6D63 */ - {0x00e6b5a4, 0x00deb3}, /* U+6D64 */ - {0x00e6b5a5, 0x00f6e8}, /* U+6D65 [2000] */ - {0x00e6b5a6, 0x00b1ba}, /* U+6D66 */ - {0x00e6b5a9, 0x00b9c0}, /* U+6D69 */ - {0x00e6b5aa, 0x00cfb2}, /* U+6D6A */ - {0x00e6b5ac, 0x00b3bd}, /* U+6D6C */ - {0x00e6b5ae, 0x00c9e2}, /* U+6D6E */ - {0x00e6b5b0, 0x8feed5}, /* U+6D70 [2000] */ - {0x00e6b5b4, 0x00cde1}, /* U+6D74 */ - {0x00e6b5b7, 0x00b3a4}, /* U+6D77 */ - {0x00e6b5b8, 0x00bfbb}, /* U+6D78 */ - {0x00e6b5b9, 0x00deb5}, /* U+6D79 */ - {0x00e6b680, 0x8feed6}, /* U+6D80 [2000] */ - {0x00e6b681, 0x8feed7}, /* U+6D81 [2000] */ - {0x00e6b682, 0x00f6ea}, /* U+6D82 [2000] */ - {0x00e6b685, 0x00deba}, /* U+6D85 */ - {0x00e6b687, 0x00f6eb}, /* U+6D87 [2000] */ - {0x00e6b688, 0x00bec3}, /* U+6D88 */ - {0x00e6b689, 0x00f6ec}, /* U+6D89 [2000] */ - {0x00e6b68a, 0x8feed8}, /* U+6D8A [2000] */ - {0x00e6b68c, 0x00cdb0}, /* U+6D8C */ - {0x00e6b68d, 0x8feed9}, /* U+6D8D [2000] */ - {0x00e6b68e, 0x00deb7}, /* U+6D8E */ - {0x00e6b691, 0x8feeda}, /* U+6D91 [2000] */ - {0x00e6b693, 0x00deb2}, /* U+6D93 */ - {0x00e6b694, 0x00f6ed}, /* U+6D94 [2000] */ - {0x00e6b695, 0x00deb8}, /* U+6D95 */ - {0x00e6b698, 0x8feedb}, /* U+6D98 [2000] */ - {0x00e6b699, 0x00cede}, /* U+6D99 */ - {0x00e6b69b, 0x00c5f3}, /* U+6D9B */ - {0x00e6b69c, 0x00c6c2}, /* U+6D9C */ - {0x00e6b6aa, 0x00f6ee}, /* U+6DAA [2000] */ - {0x00e6b6ab, 0x8feee1}, /* U+6DAB [2000] */ - {0x00e6b6ac, 0x00f6ef}, /* U+6DAC [2000] */ - {0x00e6b6ae, 0x8feee2}, /* U+6DAE [2000] */ - {0x00e6b6af, 0x00b3b6}, /* U+6DAF */ - {0x00e6b6b2, 0x00b1d5}, /* U+6DB2 */ - {0x00e6b6b4, 0x8feee3}, /* U+6DB4 [2000] */ - {0x00e6b6b5, 0x00debe}, /* U+6DB5 */ - {0x00e6b6b8, 0x00dec1}, /* U+6DB8 */ - {0x00e6b6bc, 0x00cec3}, /* U+6DBC */ - {0x00e6b6bf, 0x00f6f0}, /* U+6DBF [2000] */ - {0x00e6b780, 0x00cde4}, /* U+6DC0 */ - {0x00e6b782, 0x8feee4}, /* U+6DC2 [2000] */ - {0x00e6b784, 0x00f6f1}, /* U+6DC4 [2000] */ - {0x00e6b785, 0x00dec8}, /* U+6DC5 */ - {0x00e6b786, 0x00dec2}, /* U+6DC6 */ - {0x00e6b787, 0x00debf}, /* U+6DC7 */ - {0x00e6b788, 0x8feee6}, /* U+6DC8 [2000] */ - {0x00e6b78b, 0x00ced4}, /* U+6DCB */ - {0x00e6b78c, 0x00dec5}, /* U+6DCC */ - {0x00e6b78e, 0x8feee7}, /* U+6DCE [2000] */ - {0x00e6b78f, 0x8feee8}, /* U+6DCF [2000] */ - {0x00e6b790, 0x8feee9}, /* U+6DD0 [2000] */ - {0x00e6b791, 0x00bdca}, /* U+6DD1 */ - {0x00e6b792, 0x00dec7}, /* U+6DD2 */ - {0x00e6b795, 0x00decc}, /* U+6DD5 */ - {0x00e6b796, 0x00f6f2}, /* U+6DD6 [2000] */ - {0x00e6b798, 0x00c5f1}, /* U+6DD8 */ - {0x00e6b799, 0x00deca}, /* U+6DD9 */ - {0x00e6b79a, 0x00f6f3}, /* U+6DDA [2000] */ - {0x00e6b79b, 0x00f6f4}, /* U+6DDB [2000] */ - {0x00e6b79d, 0x00f6f5}, /* U+6DDD [2000] */ - {0x00e6b79e, 0x00dec4}, /* U+6DDE */ - {0x00e6b79f, 0x8feeea}, /* U+6DDF [2000] */ - {0x00e6b7a1, 0x00c3b8}, /* U+6DE1 */ - {0x00e6b7a4, 0x00decb}, /* U+6DE4 */ - {0x00e6b7a6, 0x00dec0}, /* U+6DE6 */ - {0x00e6b7a8, 0x00dec6}, /* U+6DE8 */ - {0x00e6b7a9, 0x8feeeb}, /* U+6DE9 [2000] */ - {0x00e6b7aa, 0x00decd}, /* U+6DEA */ - {0x00e6b7ab, 0x00b0fc}, /* U+6DEB */ - {0x00e6b7ac, 0x00dec3}, /* U+6DEC */ - {0x00e6b7ae, 0x00dece}, /* U+6DEE */ - {0x00e6b7b1, 0x00bfbc}, /* U+6DF1 */ - {0x00e6b7b3, 0x00bddf}, /* U+6DF3 */ - {0x00e6b7b5, 0x00caa5}, /* U+6DF5 */ - {0x00e6b7b6, 0x8feeec}, /* U+6DF6 [2000] */ - {0x00e6b7b7, 0x00baae}, /* U+6DF7 */ - {0x00e6b7b9, 0x00debb}, /* U+6DF9 */ - {0x00e6b7ba, 0x00dec9}, /* U+6DFA */ - {0x00e6b7bb, 0x00c5ba}, /* U+6DFB */ - {0x00e6b7bc, 0x00f6f6}, /* U+6DFC [2000] */ - {0x00e6b885, 0x00c0b6}, /* U+6E05 */ - {0x00e6b887, 0x00b3e9}, /* U+6E07 */ - {0x00e6b888, 0x00bad1}, /* U+6E08 */ - {0x00e6b889, 0x00bec4}, /* U+6E09 */ - {0x00e6b88a, 0x00debd}, /* U+6E0A */ - {0x00e6b88b, 0x00bdc2}, /* U+6E0B */ - {0x00e6b893, 0x00b7cc}, /* U+6E13 */ - {0x00e6b895, 0x00debc}, /* U+6E15 */ - {0x00e6b897, 0x8feedd}, /* U+6E17 [2000] */ - {0x00e6b899, 0x00ded2}, /* U+6E19 */ - {0x00e6b89a, 0x00bded}, /* U+6E1A */ - {0x00e6b89b, 0x00b8ba}, /* U+6E1B */ - {0x00e6b89d, 0x00dee1}, /* U+6E1D */ - {0x00e6b89e, 0x8feeee}, /* U+6E1E [2000] */ - {0x00e6b89f, 0x00dedb}, /* U+6E1F */ - {0x00e6b8a0, 0x00b5f4}, /* U+6E20 */ - {0x00e6b8a1, 0x00c5cf}, /* U+6E21 */ - {0x00e6b8a2, 0x8feeef}, /* U+6E22 [2000] */ - {0x00e6b8a3, 0x00ded6}, /* U+6E23 */ - {0x00e6b8a4, 0x00dedf}, /* U+6E24 */ - {0x00e6b8a5, 0x00b0af}, /* U+6E25 */ - {0x00e6b8a6, 0x00b1b2}, /* U+6E26 */ - {0x00e6b8a7, 0x8feef0}, /* U+6E27 [2000] */ - {0x00e6b8a9, 0x00b2b9}, /* U+6E29 */ - {0x00e6b8ab, 0x00ded8}, /* U+6E2B */ - {0x00e6b8ac, 0x00c2ac}, /* U+6E2C */ - {0x00e6b8ad, 0x00decf}, /* U+6E2D */ - {0x00e6b8ae, 0x00ded1}, /* U+6E2E */ - {0x00e6b8af, 0x00b9c1}, /* U+6E2F */ - {0x00e6b8b2, 0x8feef2}, /* U+6E32 [2000] */ - {0x00e6b8b4, 0x00f6f8}, /* U+6E34 [2000] */ - {0x00e6b8b6, 0x8feeed}, /* U+6E36 [2000] */ - {0x00e6b8b8, 0x00dee2}, /* U+6E38 */ - {0x00e6b8ba, 0x00dedd}, /* U+6E3A */ - {0x00e6b8bc, 0x8feef3}, /* U+6E3C [2000] */ - {0x00e6b8be, 0x00ded5}, /* U+6E3E */ - {0x00e6b983, 0x00dedc}, /* U+6E43 */ - {0x00e6b984, 0x00f6f9}, /* U+6E44 [2000] */ - {0x00e6b988, 0x8feef4}, /* U+6E48 [2000] */ - {0x00e6b989, 0x8feef5}, /* U+6E49 [2000] */ - {0x00e6b98a, 0x00ccab}, /* U+6E4A */ - {0x00e6b98b, 0x8feef6}, /* U+6E4B [2000] */ - {0x00e6b98c, 0x8feef7}, /* U+6E4C [2000] */ - {0x00e6b98d, 0x00deda}, /* U+6E4D */ - {0x00e6b98e, 0x00dede}, /* U+6E4E */ - {0x00e6b98f, 0x8feef8}, /* U+6E4F [2000] */ - {0x00e6b991, 0x8feef9}, /* U+6E51 [2000] */ - {0x00e6b993, 0x8feefa}, /* U+6E53 [2000] */ - {0x00e6b994, 0x8feefb}, /* U+6E54 [2000] */ - {0x00e6b996, 0x00b8d0}, /* U+6E56 */ - {0x00e6b997, 0x8feefc}, /* U+6E57 [2000] */ - {0x00e6b998, 0x00bec5}, /* U+6E58 */ - {0x00e6b99b, 0x00c3b9}, /* U+6E5B */ - {0x00e6b99c, 0x00f6fa}, /* U+6E5C [2000] */ - {0x00e6b99e, 0x00f6fb}, /* U+6E5E [2000] */ - {0x00e6b99f, 0x00ded4}, /* U+6E5F */ - {0x00e6b9a3, 0x8feefd}, /* U+6E63 [2000] */ - {0x00e6b9a7, 0x00cdaf}, /* U+6E67 */ - {0x00e6b9ab, 0x00ded7}, /* U+6E6B */ - {0x00e6b9ae, 0x00ded0}, /* U+6E6E */ - {0x00e6b9af, 0x00c5f2}, /* U+6E6F */ - {0x00e6b9b2, 0x00ded3}, /* U+6E72 */ - {0x00e6b9b6, 0x00ded9}, /* U+6E76 */ - {0x00e6b9be, 0x00cfd1}, /* U+6E7E */ - {0x00e6b9bf, 0x00bcbe}, /* U+6E7F */ - {0x00e6ba80, 0x00cbfe}, /* U+6E80 */ - {0x00e6ba82, 0x00dee3}, /* U+6E82 */ - {0x00e6ba8c, 0x00c8ae}, /* U+6E8C */ - {0x00e6ba8f, 0x00deef}, /* U+6E8F */ - {0x00e6ba90, 0x00b8bb}, /* U+6E90 */ - {0x00e6ba93, 0x8fefa1}, /* U+6E93 [2000] */ - {0x00e6ba96, 0x00bde0}, /* U+6E96 */ - {0x00e6ba98, 0x00dee5}, /* U+6E98 */ - {0x00e6ba9c, 0x00ceaf}, /* U+6E9C */ - {0x00e6ba9d, 0x00b9c2}, /* U+6E9D */ - {0x00e6ba9f, 0x00def2}, /* U+6E9F */ - {0x00e6baa2, 0x00b0ee}, /* U+6EA2 */ - {0x00e6baa5, 0x00def0}, /* U+6EA5 */ - {0x00e6baa7, 0x8fefa2}, /* U+6EA7 [2000] */ - {0x00e6baaa, 0x00dee4}, /* U+6EAA */ - {0x00e6baab, 0x00f6fc}, /* U+6EAB [2000] */ - {0x00e6baaf, 0x00deea}, /* U+6EAF */ - {0x00e6bab1, 0x00f6fd}, /* U+6EB1 [2000] */ - {0x00e6bab2, 0x00deec}, /* U+6EB2 */ - {0x00e6bab4, 0x8fefa3}, /* U+6EB4 [2000] */ - {0x00e6bab6, 0x00cdcf}, /* U+6EB6 */ - {0x00e6bab7, 0x00dee7}, /* U+6EB7 */ - {0x00e6baba, 0x00c5ae}, /* U+6EBA */ - {0x00e6babd, 0x00dee9}, /* U+6EBD */ - {0x00e6babf, 0x8fefa4}, /* U+6EBF [2000] */ - {0x00e6bb81, 0x00f6fe}, /* U+6EC1 [2000] */ - {0x00e6bb82, 0x00def1}, /* U+6EC2 */ - {0x00e6bb83, 0x8fefa5}, /* U+6EC3 [2000] */ - {0x00e6bb84, 0x00deeb}, /* U+6EC4 */ - {0x00e6bb85, 0x00ccc7}, /* U+6EC5 */ - {0x00e6bb87, 0x00f7a1}, /* U+6EC7 [2000] */ - {0x00e6bb89, 0x00dee6}, /* U+6EC9 */ - {0x00e6bb8a, 0x8fefa6}, /* U+6ECA [2000] */ - {0x00e6bb8b, 0x00bca2}, /* U+6ECB */ - {0x00e6bb8c, 0x00defe}, /* U+6ECC */ - {0x00e6bb8e, 0x00f7a2}, /* U+6ECE [2000] */ - {0x00e6bb91, 0x00b3ea}, /* U+6ED1 */ - {0x00e6bb93, 0x00dee8}, /* U+6ED3 */ - {0x00e6bb94, 0x00deed}, /* U+6ED4 */ - {0x00e6bb95, 0x00deee}, /* U+6ED5 */ - {0x00e6bb99, 0x8fefa7}, /* U+6ED9 [2000] */ - {0x00e6bb9d, 0x00c2ec}, /* U+6EDD */ - {0x00e6bb9e, 0x00c2da}, /* U+6EDE */ - {0x00e6bbab, 0x8fefa9}, /* U+6EEB [2000] */ - {0x00e6bbac, 0x00def6}, /* U+6EEC */ - {0x00e6bbaf, 0x00defc}, /* U+6EEF */ - {0x00e6bbb2, 0x00defa}, /* U+6EF2 */ - {0x00e6bbb4, 0x00c5a9}, /* U+6EF4 */ - {0x00e6bbb7, 0x00dfa3}, /* U+6EF7 */ - {0x00e6bbb8, 0x00def7}, /* U+6EF8 */ - {0x00e6bbb9, 0x8fefaa}, /* U+6EF9 [2000] */ - {0x00e6bbbb, 0x8fefab}, /* U+6EFB [2000] */ - {0x00e6bbbe, 0x00def8}, /* U+6EFE */ - {0x00e6bbbf, 0x00dee0}, /* U+6EFF */ - {0x00e6bc81, 0x00b5f9}, /* U+6F01 */ - {0x00e6bc82, 0x00c9ba}, /* U+6F02 */ - {0x00e6bc86, 0x00bcbf}, /* U+6F06 */ - {0x00e6bc89, 0x00b9f7}, /* U+6F09 */ - {0x00e6bc8a, 0x8fefac}, /* U+6F0A [2000] */ - {0x00e6bc8c, 0x8fefad}, /* U+6F0C [2000] */ - {0x00e6bc8f, 0x00cfb3}, /* U+6F0F */ - {0x00e6bc90, 0x00f7a3}, /* U+6F10 [2000] */ - {0x00e6bc91, 0x00def4}, /* U+6F11 */ - {0x00e6bc93, 0x00dfa2}, /* U+6F13 */ - {0x00e6bc94, 0x00b1e9}, /* U+6F14 */ - {0x00e6bc95, 0x00c1e6}, /* U+6F15 */ - {0x00e6bc98, 0x8fefae}, /* U+6F18 [2000] */ - {0x00e6bc9a, 0x00f7a4}, /* U+6F1A [2000] */ - {0x00e6bca0, 0x00c7f9}, /* U+6F20 */ - {0x00e6bca2, 0x00b4c1}, /* U+6F22 */ - {0x00e6bca3, 0x00cefa}, /* U+6F23 */ - {0x00e6bca5, 0x8fefaf}, /* U+6F25 [2000] */ - {0x00e6bcaa, 0x00f7a6}, /* U+6F2A [2000] */ - {0x00e6bcab, 0x00cca1}, /* U+6F2B */ - {0x00e6bcac, 0x00c4d2}, /* U+6F2C */ - {0x00e6bcaf, 0x00f7a7}, /* U+6F2F [2000] */ - {0x00e6bcb1, 0x00defb}, /* U+6F31 */ - {0x00e6bcb2, 0x00defd}, /* U+6F32 */ - {0x00e6bcb3, 0x00f7a8}, /* U+6F33 [2000] */ - {0x00e6bcb5, 0x8fefa8}, /* U+6F35 [2000] */ - {0x00e6bcb6, 0x8fefb0}, /* U+6F36 [2000] */ - {0x00e6bcb8, 0x00c1b2}, /* U+6F38 */ - {0x00e6bcbc, 0x8fefb1}, /* U+6F3C [2000] */ - {0x00e6bcbe, 0x00dfa1}, /* U+6F3E */ - {0x00e6bcbf, 0x00def9}, /* U+6F3F */ - {0x00e6bd81, 0x00def3}, /* U+6F41 */ - {0x00e6bd85, 0x00b4c3}, /* U+6F45 */ - {0x00e6bd91, 0x00f7a9}, /* U+6F51 [2000] */ - {0x00e6bd92, 0x8fefb3}, /* U+6F52 [2000] */ - {0x00e6bd94, 0x00b7e9}, /* U+6F54 */ - {0x00e6bd97, 0x8fefb4}, /* U+6F57 [2000] */ - {0x00e6bd98, 0x00dfaf}, /* U+6F58 */ - {0x00e6bd99, 0x00f7aa}, /* U+6F59 [2000] */ - {0x00e6bd9a, 0x8fefb5}, /* U+6F5A [2000] */ - {0x00e6bd9b, 0x00dfaa}, /* U+6F5B */ - {0x00e6bd9c, 0x00c0f8}, /* U+6F5C */ - {0x00e6bd9e, 0x00f7ab}, /* U+6F5E [2000] */ - {0x00e6bd9f, 0x00b3e3}, /* U+6F5F */ - {0x00e6bda0, 0x8fefb6}, /* U+6F60 [2000] */ - {0x00e6bda1, 0x00f7ac}, /* U+6F61 [2000] */ - {0x00e6bda2, 0x00f7ad}, /* U+6F62 [2000] */ - {0x00e6bda4, 0x00bde1}, /* U+6F64 */ - {0x00e6bda6, 0x00dfb3}, /* U+6F66 */ - {0x00e6bda8, 0x8fefb7}, /* U+6F68 [2000] */ - {0x00e6bdad, 0x00dfac}, /* U+6F6D */ - {0x00e6bdae, 0x00c4ac}, /* U+6F6E */ - {0x00e6bdaf, 0x00dfa9}, /* U+6F6F */ - {0x00e6bdb0, 0x00c4d9}, /* U+6F70 */ - {0x00e6bdb4, 0x00dfcc}, /* U+6F74 */ - {0x00e6bdb8, 0x00dfa6}, /* U+6F78 */ - {0x00e6bdba, 0x00dfa5}, /* U+6F7A */ - {0x00e6bdbc, 0x00dfae}, /* U+6F7C */ - {0x00e6bdbd, 0x8fefb9}, /* U+6F7D [2000] */ - {0x00e6bdbe, 0x00f7ae}, /* U+6F7E [2000] */ - {0x00e6be80, 0x00dfa8}, /* U+6F80 */ - {0x00e6be81, 0x00dfa7}, /* U+6F81 */ - {0x00e6be82, 0x00dfad}, /* U+6F82 */ - {0x00e6be84, 0x00c0a1}, /* U+6F84 */ - {0x00e6be86, 0x00dfa4}, /* U+6F86 */ - {0x00e6be88, 0x00f7af}, /* U+6F88 [2000] */ - {0x00e6be8c, 0x00f7b0}, /* U+6F8C [2000] */ - {0x00e6be8d, 0x00f7b1}, /* U+6F8D [2000] */ - {0x00e6be8e, 0x00dfb0}, /* U+6F8E */ - {0x00e6be90, 0x8fefba}, /* U+6F90 [2000] */ - {0x00e6be91, 0x00dfb1}, /* U+6F91 */ - {0x00e6be94, 0x00f7b2}, /* U+6F94 [2000] */ - {0x00e6be96, 0x8fefbb}, /* U+6F96 [2000] */ - {0x00e6be97, 0x00b4c2}, /* U+6F97 */ - {0x00e6be98, 0x8fefb8}, /* U+6F98 [2000] */ - {0x00e6be9f, 0x8fefbd}, /* U+6F9F [2000] */ - {0x00e6bea0, 0x00f7b3}, /* U+6FA0 [2000] */ - {0x00e6bea1, 0x00dfb6}, /* U+6FA1 */ - {0x00e6bea3, 0x00dfb5}, /* U+6FA3 */ - {0x00e6bea4, 0x00dfb7}, /* U+6FA4 */ - {0x00e6bea5, 0x8fefbe}, /* U+6FA5 [2000] */ - {0x00e6bea7, 0x00f7b4}, /* U+6FA7 [2000] */ - {0x00e6beaa, 0x00dfba}, /* U+6FAA */ - {0x00e6beaf, 0x8fefbf}, /* U+6FAF [2000] */ - {0x00e6beb1, 0x00c5c3}, /* U+6FB1 */ - {0x00e6beb3, 0x00dfb4}, /* U+6FB3 */ - {0x00e6beb5, 0x8fefc1}, /* U+6FB5 [2000] */ - {0x00e6beb6, 0x00f7b5}, /* U+6FB6 [2000] */ - {0x00e6beb9, 0x00dfb8}, /* U+6FB9 */ - {0x00e6bebc, 0x00f7b6}, /* U+6FBC [2000] */ - {0x00e6bebe, 0x8fefbc}, /* U+6FBE [2000] */ - {0x00e6bf80, 0x00b7e3}, /* U+6FC0 */ - {0x00e6bf81, 0x00c2f9}, /* U+6FC1 */ - {0x00e6bf82, 0x00dfb2}, /* U+6FC2 */ - {0x00e6bf83, 0x00c7bb}, /* U+6FC3 */ - {0x00e6bf86, 0x00dfb9}, /* U+6FC6 */ - {0x00e6bf87, 0x00f7b7}, /* U+6FC7 [2000] */ - {0x00e6bf88, 0x8fefc2}, /* U+6FC8 [2000] */ - {0x00e6bf89, 0x8fefc3}, /* U+6FC9 [2000] */ - {0x00e6bf8a, 0x00f7b8}, /* U+6FCA [2000] */ - {0x00e6bf94, 0x00dfbe}, /* U+6FD4 */ - {0x00e6bf95, 0x00dfbc}, /* U+6FD5 */ - {0x00e6bf98, 0x00dfbf}, /* U+6FD8 */ - {0x00e6bf9a, 0x8fefc4}, /* U+6FDA [2000] */ - {0x00e6bf9b, 0x00dfc2}, /* U+6FDB */ - {0x00e6bf9e, 0x8fefc5}, /* U+6FDE [2000] */ - {0x00e6bf9f, 0x00dfbb}, /* U+6FDF */ - {0x00e6bfa0, 0x00b9ea}, /* U+6FE0 */ - {0x00e6bfa1, 0x00c7a8}, /* U+6FE1 */ - {0x00e6bfa4, 0x00deb9}, /* U+6FE4 */ - {0x00e6bfa9, 0x8fefc6}, /* U+6FE9 [2000] */ - {0x00e6bfab, 0x00cdf4}, /* U+6FEB */ - {0x00e6bfac, 0x00dfbd}, /* U+6FEC */ - {0x00e6bfae, 0x00dfc1}, /* U+6FEE */ - {0x00e6bfaf, 0x00c2f5}, /* U+6FEF */ - {0x00e6bfb0, 0x00f7ba}, /* U+6FF0 [2000] */ - {0x00e6bfb1, 0x00dfc0}, /* U+6FF1 */ - {0x00e6bfb3, 0x00dfab}, /* U+6FF3 */ - {0x00e6bfb5, 0x00f7bb}, /* U+6FF5 [2000] */ - {0x00e6bfb6, 0x00efe9}, /* U+6FF6 */ - {0x00e6bfb9, 0x00f7b9}, /* U+6FF9 [2000] */ - {0x00e6bfba, 0x00dfc5}, /* U+6FFA */ - {0x00e6bfbc, 0x8fefc8}, /* U+6FFC [2000] */ - {0x00e6bfbe, 0x00dfc9}, /* U+6FFE */ - {0x00e78080, 0x8fefc9}, /* U+7000 [2000] */ - {0x00e78081, 0x00dfc7}, /* U+7001 */ - {0x00e78085, 0x00f7bc}, /* U+7005 [2000] */ - {0x00e78086, 0x00f7bd}, /* U+7006 [2000] */ - {0x00e78087, 0x8fefca}, /* U+7007 [2000] */ - {0x00e78089, 0x00dfc3}, /* U+7009 */ - {0x00e7808a, 0x8fefcb}, /* U+700A [2000] */ - {0x00e7808b, 0x00dfc4}, /* U+700B */ - {0x00e7808f, 0x00dfc8}, /* U+700F */ - {0x00e78091, 0x00dfc6}, /* U+7011 */ - {0x00e78095, 0x00c9ce}, /* U+7015 */ - {0x00e78098, 0x00dfce}, /* U+7018 */ - {0x00e7809a, 0x00dfcb}, /* U+701A */ - {0x00e7809b, 0x00dfca}, /* U+701B */ - {0x00e7809d, 0x00dfcd}, /* U+701D */ - {0x00e7809e, 0x00c6d4}, /* U+701E */ - {0x00e7809f, 0x00dfcf}, /* U+701F */ - {0x00e780a3, 0x8fefcc}, /* U+7023 [2000] */ - {0x00e780a6, 0x00c3f5}, /* U+7026 */ - {0x00e780a7, 0x00c2ed}, /* U+7027 */ - {0x00e780a8, 0x00f7be}, /* U+7028 [2000] */ - {0x00e780ac, 0x00c0a5}, /* U+702C */ - {0x00e780b0, 0x00dfd0}, /* U+7030 */ - {0x00e780b2, 0x00dfd2}, /* U+7032 */ - {0x00e780b9, 0x8fefce}, /* U+7039 [2000] */ - {0x00e780ba, 0x8fefcf}, /* U+703A [2000] */ - {0x00e780bc, 0x8fefd0}, /* U+703C [2000] */ - {0x00e780be, 0x00dfd1}, /* U+703E */ - {0x00e78183, 0x8fefd1}, /* U+7043 [2000] */ - {0x00e78187, 0x8fefd2}, /* U+7047 [2000] */ - {0x00e7818a, 0x00f7bf}, /* U+704A [2000] */ - {0x00e7818b, 0x8fefd3}, /* U+704B [2000] */ - {0x00e7818c, 0x00def5}, /* U+704C */ - {0x00e7818e, 0x00f7c2}, /* U+704E [2000] */ - {0x00e78191, 0x00dfd3}, /* U+7051 */ - {0x00e78194, 0x8fefd5}, /* U+7054 [2000] */ - {0x00e78198, 0x00c6e7}, /* U+7058 */ - {0x00e7819d, 0x00f7c0}, /* U+705D [2000] */ - {0x00e7819e, 0x00f7c1}, /* U+705E [2000] */ - {0x00e781a3, 0x00dfd4}, /* U+7063 */ - {0x00e781a4, 0x00f7c3}, /* U+7064 [2000] */ - {0x00e781a5, 0x8fefd6}, /* U+7065 [2000] */ - {0x00e781a9, 0x8fefd7}, /* U+7069 [2000] */ - {0x00e781ab, 0x00b2d0}, /* U+706B */ - {0x00e781ac, 0x8fefd8}, /* U+706C [2000] */ - {0x00e781ae, 0x8fefd9}, /* U+706E [2000] */ - {0x00e781af, 0x00c5f4}, /* U+706F */ - {0x00e781b0, 0x00b3a5}, /* U+7070 */ - {0x00e781b5, 0x00f7c4}, /* U+7075 [2000] */ - {0x00e781b6, 0x8fefda}, /* U+7076 [2000] */ - {0x00e781b8, 0x00b5e4}, /* U+7078 */ - {0x00e781bc, 0x00bcde}, /* U+707C */ - {0x00e781bd, 0x00bad2}, /* U+707D */ - {0x00e781be, 0x8fefdb}, /* U+707E [2000] */ - {0x00e78281, 0x8fefdc}, /* U+7081 [2000] */ - {0x00e78285, 0x00f7c5}, /* U+7085 [2000] */ - {0x00e78286, 0x8fefdd}, /* U+7086 [2000] */ - {0x00e78289, 0x00cfa7}, /* U+7089 */ - {0x00e7828a, 0x00bfe6}, /* U+708A */ - {0x00e7828e, 0x00b1ea}, /* U+708E */ - {0x00e78292, 0x00dfd6}, /* U+7092 */ - {0x00e78295, 0x8fefde}, /* U+7095 [2000] */ - {0x00e78297, 0x8fefdf}, /* U+7097 [2000] */ - {0x00e78299, 0x00dfd5}, /* U+7099 */ - {0x00e7829f, 0x8fefe2}, /* U+709F [2000] */ - {0x00e782a4, 0x00f7c6}, /* U+70A4 [2000] */ - {0x00e782ab, 0x00f7c7}, /* U+70AB [2000] */ - {0x00e782ac, 0x00dfd9}, /* U+70AC */ - {0x00e782ad, 0x00c3ba}, /* U+70AD */ - {0x00e782ae, 0x00dfdc}, /* U+70AE */ - {0x00e782af, 0x00dfd7}, /* U+70AF */ - {0x00e782b1, 0x8fefe3}, /* U+70B1 [2000] */ - {0x00e782b3, 0x00dfdb}, /* U+70B3 */ - {0x00e782b7, 0x00f7c8}, /* U+70B7 [2000] */ - {0x00e782b8, 0x00dfda}, /* U+70B8 */ - {0x00e782b9, 0x00c5c0}, /* U+70B9 */ - {0x00e782ba, 0x00b0d9}, /* U+70BA */ - {0x00e782bb, 0x8fefe0}, /* U+70BB [2000] */ - {0x00e78388, 0x00cef5}, /* U+70C8 */ - {0x00e7838a, 0x8fefe6}, /* U+70CA [2000] */ - {0x00e7838b, 0x00dfde}, /* U+70CB */ - {0x00e7838f, 0x00b1a8}, /* U+70CF */ - {0x00e78391, 0x8fefe7}, /* U+70D1 [2000] */ - {0x00e78393, 0x8fefe8}, /* U+70D3 [2000] */ - {0x00e78394, 0x00f7c9}, /* U+70D4 [2000] */ - {0x00e78398, 0x00f7ca}, /* U+70D8 [2000] */ - {0x00e78399, 0x00dfe0}, /* U+70D9 */ - {0x00e7839c, 0x8fefe9}, /* U+70DC [2000] */ - {0x00e7839d, 0x00dfdf}, /* U+70DD */ - {0x00e7839f, 0x00dfdd}, /* U+70DF */ - {0x00e783a4, 0x00f7cb}, /* U+70E4 [2000] */ - {0x00e783ac, 0x8fefe5}, /* U+70EC [2000] */ - {0x00e783b1, 0x00dfd8}, /* U+70F1 */ - {0x00e783b9, 0x00cba3}, /* U+70F9 */ - {0x00e783bd, 0x00dfe2}, /* U+70FD */ - {0x00e78483, 0x8fefea}, /* U+7103 [2000] */ - {0x00e78484, 0x8fefeb}, /* U+7104 [2000] */ - {0x00e78486, 0x8fefec}, /* U+7106 [2000] */ - {0x00e78487, 0x8fefed}, /* U+7107 [2000] */ - {0x00e78488, 0x8fefee}, /* U+7108 [2000] */ - {0x00e78489, 0x00dfe1}, /* U+7109 */ - {0x00e7848c, 0x8fefef}, /* U+710C [2000] */ - {0x00e7848f, 0x00f7cc}, /* U+710F [2000] */ - {0x00e78494, 0x00b1eb}, /* U+7114 */ - {0x00e78499, 0x00dfe4}, /* U+7119 */ - {0x00e7849a, 0x00cab2}, /* U+711A */ - {0x00e7849c, 0x00dfe3}, /* U+711C */ - {0x00e7849e, 0x00f7ce}, /* U+711E [2000] */ - {0x00e784a0, 0x00f7cf}, /* U+7120 [2000] */ - {0x00e784a1, 0x00ccb5}, /* U+7121 */ - {0x00e784a6, 0x00bec7}, /* U+7126 */ - {0x00e784ab, 0x00f7cd}, /* U+712B [2000] */ - {0x00e784ae, 0x00f7d0}, /* U+712E [2000] */ - {0x00e784af, 0x8feff1}, /* U+712F [2000] */ - {0x00e784b0, 0x00f7d1}, /* U+7130 [2000] */ - {0x00e784b1, 0x8feff2}, /* U+7131 [2000] */ - {0x00e784b6, 0x00c1b3}, /* U+7136 */ - {0x00e784bc, 0x00bec6}, /* U+713C */ - {0x00e78586, 0x00f7d2}, /* U+7146 [2000] */ - {0x00e78587, 0x00f7d3}, /* U+7147 [2000] */ - {0x00e78589, 0x00cefb}, /* U+7149 */ - {0x00e7858a, 0x8feff4}, /* U+714A [2000] */ - {0x00e7858c, 0x00dfea}, /* U+714C */ - {0x00e7858e, 0x00c0f9}, /* U+714E */ - {0x00e78590, 0x8feff3}, /* U+7150 [2000] */ - {0x00e78591, 0x00f7d4}, /* U+7151 [2000] */ - {0x00e78592, 0x00f7d6}, /* U+7152 [2000] */ - {0x00e78593, 0x8feff5}, /* U+7153 [2000] */ - {0x00e78595, 0x00dfe6}, /* U+7155 */ - {0x00e78596, 0x00dfeb}, /* U+7156 */ - {0x00e78599, 0x00b1ec}, /* U+7159 */ - {0x00e7859c, 0x00f7d7}, /* U+715C [2000] */ - {0x00e7859e, 0x8feff6}, /* U+715E [2000] */ - {0x00e785a0, 0x00f7d8}, /* U+7160 [2000] */ - {0x00e785a2, 0x00dfe9}, /* U+7162 */ - {0x00e785a4, 0x00c7e1}, /* U+7164 */ - {0x00e785a5, 0x00dfe5}, /* U+7165 */ - {0x00e785a6, 0x00dfe8}, /* U+7166 */ - {0x00e785a7, 0x00bec8}, /* U+7167 */ - {0x00e785a8, 0x00f7d9}, /* U+7168 [2000] */ - {0x00e785a9, 0x00c8d1}, /* U+7169 */ - {0x00e785ac, 0x00dfec}, /* U+716C */ - {0x00e785ae, 0x00bcd1}, /* U+716E */ - {0x00e785bd, 0x00c0fa}, /* U+717D */ - {0x00e78680, 0x8feff9}, /* U+7180 [2000] */ - {0x00e78684, 0x00dfef}, /* U+7184 */ - {0x00e78685, 0x00f7db}, /* U+7185 [2000] */ - {0x00e78687, 0x00f7dc}, /* U+7187 [2000] */ - {0x00e78688, 0x00dfe7}, /* U+7188 */ - {0x00e7868a, 0x00b7a7}, /* U+718A */ - {0x00e7868f, 0x00dfed}, /* U+718F */ - {0x00e78692, 0x00f7dd}, /* U+7192 [2000] */ - {0x00e78694, 0x00cdd0}, /* U+7194 */ - {0x00e78695, 0x00dff0}, /* U+7195 */ - {0x00e78696, 0x8feff8}, /* U+7196 [2000] */ - {0x00e78699, 0x00f4a6}, /* U+7199 [1990] */ - {0x00e7869b, 0x8feffa}, /* U+719B [2000] */ - {0x00e7869f, 0x00bdcf}, /* U+719F */ - {0x00e786a0, 0x8feffb}, /* U+71A0 [2000] */ - {0x00e786a2, 0x8feffc}, /* U+71A2 [2000] */ - {0x00e786a8, 0x00dff1}, /* U+71A8 */ - {0x00e786ac, 0x00dff2}, /* U+71AC */ - {0x00e786ae, 0x8feffd}, /* U+71AE [2000] */ - {0x00e786af, 0x8feffe}, /* U+71AF [2000] */ - {0x00e786b1, 0x00c7ae}, /* U+71B1 */ - {0x00e786b3, 0x8ff0a1}, /* U+71B3 [2000] */ - {0x00e786b9, 0x00dff4}, /* U+71B9 */ - {0x00e786ba, 0x00f7df}, /* U+71BA [2000] */ - {0x00e786be, 0x00dff5}, /* U+71BE */ - {0x00e78781, 0x00f7de}, /* U+71C1 [2000] */ - {0x00e78783, 0x00c7b3}, /* U+71C3 */ - {0x00e78784, 0x00f7e0}, /* U+71C4 [2000] */ - {0x00e78788, 0x00c5f5}, /* U+71C8 */ - {0x00e78789, 0x00dff7}, /* U+71C9 */ - {0x00e7878b, 0x8ff0a3}, /* U+71CB [2000] */ - {0x00e7878e, 0x00dff9}, /* U+71CE */ - {0x00e78790, 0x00ced5}, /* U+71D0 */ - {0x00e78792, 0x00dff6}, /* U+71D2 */ - {0x00e78793, 0x8ff0a4}, /* U+71D3 [2000] */ - {0x00e78794, 0x00dff8}, /* U+71D4 */ - {0x00e78795, 0x00b1ed}, /* U+71D5 */ - {0x00e78797, 0x00dff3}, /* U+71D7 */ - {0x00e78799, 0x8ff0a5}, /* U+71D9 [2000] */ - {0x00e7879c, 0x8ff0a6}, /* U+71DC [2000] */ - {0x00e7879f, 0x00d3db}, /* U+71DF */ - {0x00e787a0, 0x00dffa}, /* U+71E0 */ - {0x00e787a5, 0x00c1e7}, /* U+71E5 */ - {0x00e787a6, 0x00bbb8}, /* U+71E6 */ - {0x00e787a7, 0x00dffc}, /* U+71E7 */ - {0x00e787ac, 0x00dffb}, /* U+71EC */ - {0x00e787ad, 0x00bfa4}, /* U+71ED */ - {0x00e787ae, 0x00d2d9}, /* U+71EE */ - {0x00e787b5, 0x00dffd}, /* U+71F5 */ - {0x00e787b9, 0x00e0a1}, /* U+71F9 */ - {0x00e787bb, 0x00dfee}, /* U+71FB */ - {0x00e787bc, 0x00dffe}, /* U+71FC */ - {0x00e787be, 0x00f7e1}, /* U+71FE [2000] */ - {0x00e787bf, 0x00e0a2}, /* U+71FF */ - {0x00e78880, 0x00f7e2}, /* U+7200 [2000] */ - {0x00e78886, 0x00c7fa}, /* U+7206 */ - {0x00e78887, 0x8ff0a7}, /* U+7207 [2000] */ - {0x00e7888d, 0x00e0a3}, /* U+720D */ - {0x00e78890, 0x00e0a4}, /* U+7210 */ - {0x00e78895, 0x00f7e3}, /* U+7215 [2000] */ - {0x00e7889b, 0x00e0a5}, /* U+721B */ - {0x00e788a8, 0x00e0a6}, /* U+7228 */ - {0x00e788aa, 0x00c4de}, /* U+722A */ - {0x00e788ab, 0x8ff0aa}, /* U+722B [2000] */ - {0x00e788ac, 0x00e0a8}, /* U+722C */ - {0x00e788ad, 0x00e0a7}, /* U+722D */ - {0x00e788b0, 0x00e0a9}, /* U+7230 */ - {0x00e788b2, 0x00e0aa}, /* U+7232 */ - {0x00e788b4, 0x8ff0ab}, /* U+7234 [2000] */ - {0x00e788b5, 0x00bcdf}, /* U+7235 */ - {0x00e788b6, 0x00c9e3}, /* U+7236 */ - {0x00e788b8, 0x8ff0ac}, /* U+7238 [2000] */ - {0x00e788b9, 0x8ff0ad}, /* U+7239 [2000] */ - {0x00e788ba, 0x00ccec}, /* U+723A */ - {0x00e788bb, 0x00e0ab}, /* U+723B */ - {0x00e788bc, 0x00e0ac}, /* U+723C */ - {0x00e788bd, 0x00c1d6}, /* U+723D */ - {0x00e788be, 0x00bca4}, /* U+723E */ - {0x00e788bf, 0x00e0ad}, /* U+723F */ - {0x00e78980, 0x00e0ae}, /* U+7240 */ - {0x00e78982, 0x8ff0af}, /* U+7242 [2000] */ - {0x00e78986, 0x00e0af}, /* U+7246 */ - {0x00e78987, 0x00cad2}, /* U+7247 */ - {0x00e78988, 0x00c8c7}, /* U+7248 */ - {0x00e7898b, 0x00e0b0}, /* U+724B */ - {0x00e7898c, 0x00c7d7}, /* U+724C */ - {0x00e78992, 0x00c4ad}, /* U+7252 */ - {0x00e78993, 0x8ff0b0}, /* U+7253 [2000] */ - {0x00e78995, 0x00f7e4}, /* U+7255 [2000] */ - {0x00e78996, 0x00f7e5}, /* U+7256 [2000] */ - {0x00e78997, 0x8ff0b1}, /* U+7257 [2000] */ - {0x00e78998, 0x00e0b1}, /* U+7258 */ - {0x00e78999, 0x00b2e7}, /* U+7259 */ - {0x00e7899b, 0x00b5ed}, /* U+725B */ - {0x00e7899d, 0x00ccc6}, /* U+725D */ - {0x00e7899f, 0x00ccb6}, /* U+725F */ - {0x00e789a1, 0x00b2b4}, /* U+7261 */ - {0x00e789a2, 0x00cfb4}, /* U+7262 */ - {0x00e789a3, 0x8ff0b2}, /* U+7263 [2000] */ - {0x00e789a7, 0x00cbd2}, /* U+7267 */ - {0x00e789a9, 0x00caaa}, /* U+7269 */ - {0x00e789ae, 0x8ff0b4}, /* U+726E [2000] */ - {0x00e789af, 0x8ff0b5}, /* U+726F [2000] */ - {0x00e789b2, 0x00c0b7}, /* U+7272 */ - {0x00e789b4, 0x00e0b2}, /* U+7274 */ - {0x00e789b8, 0x8ff0b6}, /* U+7278 [2000] */ - {0x00e789b9, 0x00c6c3}, /* U+7279 */ - {0x00e789bd, 0x00b8a3}, /* U+727D */ - {0x00e789be, 0x00e0b3}, /* U+727E */ - {0x00e789bf, 0x8ff0b7}, /* U+727F [2000] */ - {0x00e78a80, 0x00bad4}, /* U+7280 */ - {0x00e78a81, 0x00e0b5}, /* U+7281 */ - {0x00e78a82, 0x00e0b4}, /* U+7282 */ - {0x00e78a87, 0x00e0b6}, /* U+7287 */ - {0x00e78a8d, 0x00f7e7}, /* U+728D [2000] */ - {0x00e78a8e, 0x8ff0b8}, /* U+728E [2000] */ - {0x00e78a92, 0x00e0b7}, /* U+7292 */ - {0x00e78a96, 0x00e0b8}, /* U+7296 */ - {0x00e78a9b, 0x00f7e8}, /* U+729B [2000] */ - {0x00e78aa0, 0x00b5be}, /* U+72A0 */ - {0x00e78aa2, 0x00e0b9}, /* U+72A2 */ - {0x00e78aa7, 0x00e0ba}, /* U+72A7 */ - {0x00e78aac, 0x00b8a4}, /* U+72AC */ - {0x00e78aad, 0x8ff0ba}, /* U+72AD [2000] */ - {0x00e78aae, 0x8ff0bb}, /* U+72AE [2000] */ - {0x00e78aaf, 0x00c8c8}, /* U+72AF */ - {0x00e78ab0, 0x8ff0bc}, /* U+72B0 [2000] */ - {0x00e78ab1, 0x8ff0bd}, /* U+72B1 [2000] */ - {0x00e78ab2, 0x00e0bc}, /* U+72B2 */ - {0x00e78ab6, 0x00bef5}, /* U+72B6 */ - {0x00e78ab9, 0x00e0bb}, /* U+72B9 */ - {0x00e78abe, 0x00f7e9}, /* U+72BE [2000] */ - {0x00e78b80, 0x00f7ea}, /* U+72C0 [2000] */ - {0x00e78b81, 0x8ff0be}, /* U+72C1 [2000] */ - {0x00e78b82, 0x00b6b8}, /* U+72C2 */ - {0x00e78b83, 0x00e0bd}, /* U+72C3 */ - {0x00e78b84, 0x00e0bf}, /* U+72C4 */ - {0x00e78b86, 0x00e0be}, /* U+72C6 */ - {0x00e78b8c, 0x8ff0c0}, /* U+72CC [2000] */ - {0x00e78b8e, 0x00e0c0}, /* U+72CE */ - {0x00e78b90, 0x00b8d1}, /* U+72D0 */ - {0x00e78b92, 0x00e0c1}, /* U+72D2 */ - {0x00e78b97, 0x00b6e9}, /* U+72D7 */ - {0x00e78b99, 0x00c1c0}, /* U+72D9 */ - {0x00e78b9b, 0x00b9fd}, /* U+72DB */ - {0x00e78ba0, 0x00e0c3}, /* U+72E0 */ - {0x00e78ba1, 0x00e0c4}, /* U+72E1 */ - {0x00e78ba2, 0x00e0c2}, /* U+72E2 */ - {0x00e78ba9, 0x00bced}, /* U+72E9 */ - {0x00e78bac, 0x00c6c8}, /* U+72EC */ - {0x00e78bad, 0x00b6b9}, /* U+72ED */ - {0x00e78bb3, 0x8ff0c3}, /* U+72F3 [2000] */ - {0x00e78bb7, 0x00e0c6}, /* U+72F7 */ - {0x00e78bb8, 0x00c3ac}, /* U+72F8 */ - {0x00e78bb9, 0x00e0c5}, /* U+72F9 */ - {0x00e78bba, 0x8ff0c4}, /* U+72FA [2000] */ - {0x00e78bbb, 0x00f7eb}, /* U+72FB [2000] */ - {0x00e78bbc, 0x00cfb5}, /* U+72FC */ - {0x00e78bbd, 0x00c7e2}, /* U+72FD */ - {0x00e78c87, 0x8ff0c5}, /* U+7307 [2000] */ - {0x00e78c8a, 0x00e0c9}, /* U+730A */ - {0x00e78c92, 0x8ff0c6}, /* U+7312 [2000] */ - {0x00e78c96, 0x00e0cb}, /* U+7316 */ - {0x00e78c97, 0x00e0c8}, /* U+7317 */ - {0x00e78c98, 0x8ff0c7}, /* U+7318 [2000] */ - {0x00e78c99, 0x8ff0c8}, /* U+7319 [2000] */ - {0x00e78c9b, 0x00ccd4}, /* U+731B */ - {0x00e78c9c, 0x00e0ca}, /* U+731C */ - {0x00e78c9d, 0x00e0cc}, /* U+731D */ - {0x00e78c9f, 0x00cec4}, /* U+731F */ - {0x00e78ca5, 0x00e0d0}, /* U+7325 */ - {0x00e78ca7, 0x00f7ed}, /* U+7327 [2000] */ - {0x00e78ca8, 0x00f7ee}, /* U+7328 [2000] */ - {0x00e78ca9, 0x00e0cf}, /* U+7329 */ - {0x00e78caa, 0x00c3f6}, /* U+732A */ - {0x00e78cab, 0x00c7ad}, /* U+732B */ - {0x00e78cac, 0x8ff0cb}, /* U+732C [2000] */ - {0x00e78cae, 0x00b8a5}, /* U+732E */ - {0x00e78caf, 0x00e0ce}, /* U+732F */ - {0x00e78cb1, 0x8ff0cc}, /* U+7331 [2000] */ - {0x00e78cb3, 0x8ff0cd}, /* U+7333 [2000] */ - {0x00e78cb4, 0x00e0cd}, /* U+7334 */ - {0x00e78cb6, 0x00cdb1}, /* U+7336 */ - {0x00e78cb7, 0x00cdb2}, /* U+7337 */ - {0x00e78cb9, 0x8ff0ca}, /* U+7339 [2000] */ - {0x00e78cbd, 0x8ff0ce}, /* U+733D [2000] */ - {0x00e78cbe, 0x00e0d1}, /* U+733E */ - {0x00e78cbf, 0x00b1ee}, /* U+733F */ - {0x00e78d84, 0x00b9f6}, /* U+7344 */ - {0x00e78d85, 0x00bbe2}, /* U+7345 */ - {0x00e78d8e, 0x00e0d2}, /* U+734E */ - {0x00e78d8f, 0x00e0d3}, /* U+734F */ - {0x00e78d90, 0x00f7f0}, /* U+7350 [2000] */ - {0x00e78d92, 0x8ff0cf}, /* U+7352 [2000] */ - {0x00e78d97, 0x00e0d5}, /* U+7357 */ - {0x00e78da3, 0x00bdc3}, /* U+7363 */ - {0x00e78da6, 0x00f7f1}, /* U+7366 [2000] */ - {0x00e78da8, 0x00e0d7}, /* U+7368 */ - {0x00e78daa, 0x00e0d6}, /* U+736A */ - {0x00e78dab, 0x8ff0d1}, /* U+736B [2000] */ - {0x00e78dac, 0x8ff0d2}, /* U+736C [2000] */ - {0x00e78dae, 0x8ff0d4}, /* U+736E [2000] */ - {0x00e78daf, 0x8ff0d5}, /* U+736F [2000] */ - {0x00e78db0, 0x00e0d8}, /* U+7370 */ - {0x00e78db1, 0x8ff0d6}, /* U+7371 [2000] */ - {0x00e78db2, 0x00b3cd}, /* U+7372 */ - {0x00e78db5, 0x00e0da}, /* U+7375 */ - {0x00e78db7, 0x8ff0d7}, /* U+7377 [2000] */ - {0x00e78db8, 0x00e0d9}, /* U+7378 */ - {0x00e78dba, 0x00e0dc}, /* U+737A */ - {0x00e78dbb, 0x00e0db}, /* U+737B */ - {0x00e78dbc, 0x00f7f2}, /* U+737C [2000] */ - {0x00e78e81, 0x8ff0d8}, /* U+7381 [2000] */ - {0x00e78e84, 0x00b8bc}, /* U+7384 */ - {0x00e78e85, 0x8ff0d9}, /* U+7385 [2000] */ - {0x00e78e87, 0x00cea8}, /* U+7387 */ - {0x00e78e89, 0x00b6cc}, /* U+7389 */ - {0x00e78e8a, 0x8ff0da}, /* U+738A [2000] */ - {0x00e78e8b, 0x00b2a6}, /* U+738B */ - {0x00e78e94, 0x8ff0db}, /* U+7394 [2000] */ - {0x00e78e95, 0x00f7f3}, /* U+7395 [2000] */ - {0x00e78e96, 0x00b6ea}, /* U+7396 */ - {0x00e78e98, 0x8ff0dc}, /* U+7398 [2000] */ - {0x00e78e9c, 0x8ff0dd}, /* U+739C [2000] */ - {0x00e78e9e, 0x8ff0de}, /* U+739E [2000] */ - {0x00e78e9f, 0x00f7f4}, /* U+739F [2000] */ - {0x00e78ea0, 0x00f7f5}, /* U+73A0 [2000] */ - {0x00e78ea2, 0x00f7f6}, /* U+73A2 [2000] */ - {0x00e78ea5, 0x8ff0df}, /* U+73A5 [2000] */ - {0x00e78ea6, 0x00f7f7}, /* U+73A6 [2000] */ - {0x00e78ea8, 0x8ff0e0}, /* U+73A8 [2000] */ - {0x00e78ea9, 0x00b4e1}, /* U+73A9 */ - {0x00e78eab, 0x00f7f8}, /* U+73AB [2000] */ - {0x00e78eb2, 0x00cee8}, /* U+73B2 */ - {0x00e78eb3, 0x00e0de}, /* U+73B3 */ - {0x00e78eb5, 0x8ff0e1}, /* U+73B5 [2000] */ - {0x00e78eb7, 0x8ff0e2}, /* U+73B7 [2000] */ - {0x00e78eb9, 0x8ff0e3}, /* U+73B9 [2000] */ - {0x00e78ebb, 0x00e0e0}, /* U+73BB */ - {0x00e78ebc, 0x8ff0e4}, /* U+73BC [2000] */ - {0x00e78ebf, 0x8ff0e5}, /* U+73BF [2000] */ - {0x00e78f80, 0x00e0e1}, /* U+73C0 */ - {0x00e78f82, 0x00b2d1}, /* U+73C2 */ - {0x00e78f85, 0x8ff0e6}, /* U+73C5 [2000] */ - {0x00e78f88, 0x00e0dd}, /* U+73C8 */ - {0x00e78f89, 0x00f7f9}, /* U+73C9 [2000] */ - {0x00e78f8a, 0x00bbb9}, /* U+73CA */ - {0x00e78f8b, 0x8ff0e7}, /* U+73CB [2000] */ - {0x00e78f8d, 0x00c4c1}, /* U+73CD */ - {0x00e78f8e, 0x00e0df}, /* U+73CE */ - {0x00e78f8f, 0x00f7fa}, /* U+73CF [2000] */ - {0x00e78f96, 0x00f7fb}, /* U+73D6 [2000] */ - {0x00e78f99, 0x00f7fc}, /* U+73D9 [2000] */ - {0x00e78f9e, 0x00e0e4}, /* U+73DE */ - {0x00e78fa0, 0x00bcee}, /* U+73E0 */ - {0x00e78fa1, 0x8ff0e8}, /* U+73E1 [2000] */ - {0x00e78fa3, 0x00f7fd}, /* U+73E3 [2000] */ - {0x00e78fa5, 0x00e0e2}, /* U+73E5 */ - {0x00e78fa7, 0x8ff0e9}, /* U+73E7 [2000] */ - {0x00e78fa9, 0x00f7fe}, /* U+73E9 [2000] */ - {0x00e78faa, 0x00b7be}, /* U+73EA */ - {0x00e78fad, 0x00c8c9}, /* U+73ED */ - {0x00e78fae, 0x00e0e3}, /* U+73EE */ - {0x00e78fb1, 0x00e0fe}, /* U+73F1 */ - {0x00e78fb8, 0x00e0e9}, /* U+73F8 */ - {0x00e78fb9, 0x8ff0ea}, /* U+73F9 [2000] */ - {0x00e78fba, 0x8ff0ec}, /* U+73FA [2000] */ - {0x00e78fbe, 0x00b8bd}, /* U+73FE */ - {0x00e79081, 0x8ff0ed}, /* U+7401 [2000] */ - {0x00e79083, 0x00b5e5}, /* U+7403 */ - {0x00e79085, 0x00e0e6}, /* U+7405 */ - {0x00e79086, 0x00cdfd}, /* U+7406 */ - {0x00e79087, 0x00f8a1}, /* U+7407 [2000] */ - {0x00e79089, 0x00ceb0}, /* U+7409 */ - {0x00e7908a, 0x00f8a2}, /* U+740A [2000] */ - {0x00e79093, 0x8ff0eb}, /* U+7413 [2000] */ - {0x00e7909a, 0x00f8a3}, /* U+741A [2000] */ - {0x00e7909b, 0x00f8a4}, /* U+741B [2000] */ - {0x00e790a2, 0x00c2f6}, /* U+7422 */ - {0x00e790a4, 0x8ff0ee}, /* U+7424 [2000] */ - {0x00e790a5, 0x00e0e8}, /* U+7425 */ - {0x00e790a6, 0x00f8a6}, /* U+7426 [2000] */ - {0x00e790a8, 0x00f8a7}, /* U+7428 [2000] */ - {0x00e790aa, 0x00f8a8}, /* U+742A [2000] */ - {0x00e790ab, 0x00f8a9}, /* U+742B [2000] */ - {0x00e790ac, 0x00f8aa}, /* U+742C [2000] */ - {0x00e790ae, 0x00f8ab}, /* U+742E [2000] */ - {0x00e790af, 0x00f8ac}, /* U+742F [2000] */ - {0x00e790b0, 0x00f8ad}, /* U+7430 [2000] */ - {0x00e790b1, 0x8ff0ef}, /* U+7431 [2000] */ - {0x00e790b2, 0x00e0ea}, /* U+7432 */ - {0x00e790b3, 0x00ced6}, /* U+7433 */ - {0x00e790b4, 0x00b6d7}, /* U+7434 */ - {0x00e790b5, 0x00c8fc}, /* U+7435 */ - {0x00e790b6, 0x00c7ca}, /* U+7436 */ - {0x00e790b9, 0x8ff0f0}, /* U+7439 [2000] */ - {0x00e790ba, 0x00e0eb}, /* U+743A */ - {0x00e790bf, 0x00e0ed}, /* U+743F */ - {0x00e79180, 0x8ff0f2}, /* U+7440 [2000] */ - {0x00e79181, 0x00e0f0}, /* U+7441 */ - {0x00e79183, 0x8ff0f3}, /* U+7443 [2000] */ - {0x00e79184, 0x00f8ae}, /* U+7444 [2000] */ - {0x00e79186, 0x00f8af}, /* U+7446 [2000] */ - {0x00e79187, 0x00f8b0}, /* U+7447 [2000] */ - {0x00e7918b, 0x00f8b1}, /* U+744B [2000] */ - {0x00e7918d, 0x8ff0f4}, /* U+744D [2000] */ - {0x00e79192, 0x8ff0f5}, /* U+7452 [2000] */ - {0x00e79193, 0x8ff0f1}, /* U+7453 [2000] */ - {0x00e79195, 0x00e0ec}, /* U+7455 */ - {0x00e79197, 0x00f8b2}, /* U+7457 [2000] */ - {0x00e79199, 0x00e0ef}, /* U+7459 */ - {0x00e7919a, 0x00b8ea}, /* U+745A */ - {0x00e7919b, 0x00b1cd}, /* U+745B */ - {0x00e7919c, 0x00e0f1}, /* U+745C */ - {0x00e7919d, 0x8ff0f6}, /* U+745D [2000] */ - {0x00e7919e, 0x00bff0}, /* U+745E */ - {0x00e7919f, 0x00e0ee}, /* U+745F */ - {0x00e791a0, 0x00cedc}, /* U+7460 */ - {0x00e791a2, 0x00f8b3}, /* U+7462 [2000] */ - {0x00e791a3, 0x00e0f4}, /* U+7463 */ - {0x00e791a4, 0x00f4a4}, /* U+7464 [1983] */ - {0x00e791a9, 0x00e0f2}, /* U+7469 */ - {0x00e791aa, 0x00e0f5}, /* U+746A */ - {0x00e791ab, 0x00f8b4}, /* U+746B [2000] */ - {0x00e791ad, 0x00f8b5}, /* U+746D [2000] */ - {0x00e791af, 0x00e0e7}, /* U+746F */ - {0x00e791b0, 0x00e0f3}, /* U+7470 */ - {0x00e791b1, 0x8ff0f7}, /* U+7471 [2000] */ - {0x00e791b3, 0x00babc}, /* U+7473 */ - {0x00e791b6, 0x00e0f6}, /* U+7476 */ - {0x00e791be, 0x00e0f7}, /* U+747E */ - {0x00e79281, 0x8ff0f8}, /* U+7481 [2000] */ - {0x00e79283, 0x00cdfe}, /* U+7483 */ - {0x00e79285, 0x8ff0f9}, /* U+7485 [2000] */ - {0x00e79286, 0x00f8b6}, /* U+7486 [2000] */ - {0x00e79287, 0x00f8b7}, /* U+7487 [2000] */ - {0x00e79288, 0x8ff0fa}, /* U+7488 [2000] */ - {0x00e79289, 0x00f8b8}, /* U+7489 [2000] */ - {0x00e7928b, 0x00e0f8}, /* U+748B */ - {0x00e79290, 0x00f8bd}, /* U+7490 [2000] */ - {0x00e79292, 0x8ff0fc}, /* U+7492 [2000] */ - {0x00e79297, 0x8ff0fd}, /* U+7497 [2000] */ - {0x00e79298, 0x00f8b9}, /* U+7498 [2000] */ - {0x00e79299, 0x8ff0fe}, /* U+7499 [2000] */ - {0x00e7929c, 0x00f8ba}, /* U+749C [2000] */ - {0x00e7929e, 0x00e0f9}, /* U+749E */ - {0x00e7929f, 0x00f8bb}, /* U+749F [2000] */ - {0x00e792a0, 0x8ff1a1}, /* U+74A0 [2000] */ - {0x00e792a1, 0x8ff1a2}, /* U+74A1 [2000] */ - {0x00e792a2, 0x00e0e5}, /* U+74A2 */ - {0x00e792a3, 0x00f8bc}, /* U+74A3 [2000] */ - {0x00e792a5, 0x8ff1a3}, /* U+74A5 [2000] */ - {0x00e792a6, 0x00f8be}, /* U+74A6 [2000] */ - {0x00e792a7, 0x00e0fa}, /* U+74A7 */ - {0x00e792a8, 0x00f8bf}, /* U+74A8 [2000] */ - {0x00e792a9, 0x00f8c0}, /* U+74A9 [2000] */ - {0x00e792aa, 0x8ff1a4}, /* U+74AA [2000] */ - {0x00e792ab, 0x8ff1a5}, /* U+74AB [2000] */ - {0x00e792b0, 0x00b4c4}, /* U+74B0 */ - {0x00e792b5, 0x00f8c1}, /* U+74B5 [2000] */ - {0x00e792b9, 0x8ff1a6}, /* U+74B9 [2000] */ - {0x00e792ba, 0x8ff1a8}, /* U+74BA [2000] */ - {0x00e792bb, 0x8ff1a7}, /* U+74BB [2000] */ - {0x00e792bd, 0x00bca5}, /* U+74BD */ - {0x00e792bf, 0x00f8c2}, /* U+74BF [2000] */ - {0x00e79388, 0x00f8c3}, /* U+74C8 [2000] */ - {0x00e79389, 0x00f8c4}, /* U+74C9 [2000] */ - {0x00e7938a, 0x00e0fb}, /* U+74CA */ - {0x00e7938f, 0x00e0fc}, /* U+74CF */ - {0x00e79394, 0x00e0fd}, /* U+74D4 */ - {0x00e79396, 0x8ff1a9}, /* U+74D6 [2000] */ - {0x00e79398, 0x8ff1aa}, /* U+74D8 [2000] */ - {0x00e7939a, 0x00f8c5}, /* U+74DA [2000] */ - {0x00e7939c, 0x00b1bb}, /* U+74DC */ - {0x00e7939e, 0x8ff1ab}, /* U+74DE [2000] */ - {0x00e793a0, 0x00e1a1}, /* U+74E0 */ - {0x00e793a2, 0x00c9bb}, /* U+74E2 */ - {0x00e793a3, 0x00e1a2}, /* U+74E3 */ - {0x00e793a6, 0x00b4a4}, /* U+74E6 */ - {0x00e793a7, 0x00e1a3}, /* U+74E7 */ - {0x00e793a9, 0x00e1a4}, /* U+74E9 */ - {0x00e793ab, 0x8ff1ad}, /* U+74EB [2000] */ - {0x00e793ae, 0x00e1a5}, /* U+74EE */ - {0x00e793af, 0x8ff1ac}, /* U+74EF [2000] */ - {0x00e793b0, 0x00e1a7}, /* U+74F0 */ - {0x00e793b1, 0x00e1a8}, /* U+74F1 */ - {0x00e793b2, 0x00e1a6}, /* U+74F2 */ - {0x00e793b6, 0x00c9d3}, /* U+74F6 */ - {0x00e793b7, 0x00e1aa}, /* U+74F7 */ - {0x00e793b8, 0x00e1a9}, /* U+74F8 */ - {0x00e793ba, 0x8ff1af}, /* U+74FA [2000] */ - {0x00e793bf, 0x00f8c6}, /* U+74FF [2000] */ - {0x00e79481, 0x00f8c7}, /* U+7501 [2000] */ - {0x00e79483, 0x00e1ac}, /* U+7503 */ - {0x00e79484, 0x00e1ab}, /* U+7504 */ - {0x00e79485, 0x00e1ad}, /* U+7505 */ - {0x00e7948c, 0x00e1ae}, /* U+750C */ - {0x00e7948d, 0x00e1b0}, /* U+750D */ - {0x00e7948e, 0x00e1af}, /* U+750E */ - {0x00e79491, 0x00b9f9}, /* U+7511 */ - {0x00e79493, 0x00e1b2}, /* U+7513 */ - {0x00e79495, 0x00e1b1}, /* U+7515 */ - {0x00e79497, 0x00f8c8}, /* U+7517 [2000] */ - {0x00e79498, 0x00b4c5}, /* U+7518 */ - {0x00e7949a, 0x00bfd3}, /* U+751A */ - {0x00e7949c, 0x00c5bc}, /* U+751C */ - {0x00e7949e, 0x00e1b3}, /* U+751E */ - {0x00e7949f, 0x00c0b8}, /* U+751F */ - {0x00e794a0, 0x8ff1b1}, /* U+7520 [2000] */ - {0x00e794a3, 0x00bbba}, /* U+7523 */ - {0x00e794a4, 0x8ff1b2}, /* U+7524 [2000] */ - {0x00e794a5, 0x00b1f9}, /* U+7525 */ - {0x00e794a6, 0x00e1b4}, /* U+7526 */ - {0x00e794a8, 0x00cdd1}, /* U+7528 */ - {0x00e794aa, 0x8ff1b3}, /* U+752A [2000] */ - {0x00e794ab, 0x00cae3}, /* U+752B */ - {0x00e794ac, 0x00e1b5}, /* U+752C */ - {0x00e794af, 0x00f8c9}, /* U+752F [2000] */ - {0x00e794b0, 0x00c5c4}, /* U+7530 */ - {0x00e794b1, 0x00cdb3}, /* U+7531 */ - {0x00e794b2, 0x00b9c3}, /* U+7532 */ - {0x00e794b3, 0x00bfbd}, /* U+7533 */ - {0x00e794b7, 0x00c3cb}, /* U+7537 */ - {0x00e794b8, 0x00d2b4}, /* U+7538 */ - {0x00e794ba, 0x00c4ae}, /* U+753A */ - {0x00e794bb, 0x00b2e8}, /* U+753B */ - {0x00e794bc, 0x00e1b6}, /* U+753C */ - {0x00e794bd, 0x8ff1b6}, /* U+753D [2000] */ - {0x00e794be, 0x8ff1b7}, /* U+753E [2000] */ - {0x00e79580, 0x8ff1b8}, /* U+7540 [2000] */ - {0x00e79584, 0x00e1b7}, /* U+7544 */ - {0x00e79586, 0x00e1bc}, /* U+7546 */ - {0x00e79588, 0x8ff1b9}, /* U+7548 [2000] */ - {0x00e79589, 0x00e1ba}, /* U+7549 */ - {0x00e7958a, 0x00e1b9}, /* U+754A */ - {0x00e7958b, 0x00dac2}, /* U+754B */ - {0x00e7958c, 0x00b3a6}, /* U+754C */ - {0x00e7958d, 0x00e1b8}, /* U+754D */ - {0x00e7958e, 0x8ff1ba}, /* U+754E [2000] */ - {0x00e7958f, 0x00b0da}, /* U+754F */ - {0x00e79590, 0x8ff1bb}, /* U+7550 [2000] */ - {0x00e79591, 0x00c8aa}, /* U+7551 */ - {0x00e79592, 0x8ff1bc}, /* U+7552 [2000] */ - {0x00e79594, 0x00c8ca}, /* U+7554 */ - {0x00e79599, 0x00ceb1}, /* U+7559 */ - {0x00e7959a, 0x00e1bd}, /* U+755A */ - {0x00e7959b, 0x00e1bb}, /* U+755B */ - {0x00e7959c, 0x00c3dc}, /* U+755C */ - {0x00e7959d, 0x00c0a6}, /* U+755D */ - {0x00e795a0, 0x00c8ab}, /* U+7560 */ - {0x00e795a2, 0x00c9ad}, /* U+7562 */ - {0x00e795a4, 0x00e1bf}, /* U+7564 */ - {0x00e795a5, 0x00ceac}, /* U+7565 */ - {0x00e795a6, 0x00b7cd}, /* U+7566 */ - {0x00e795a7, 0x00e1c0}, /* U+7567 */ - {0x00e795a9, 0x00e1be}, /* U+7569 */ - {0x00e795aa, 0x00c8d6}, /* U+756A */ - {0x00e795ab, 0x00e1c1}, /* U+756B */ - {0x00e795ac, 0x8ff1bd}, /* U+756C [2000] */ - {0x00e795ad, 0x00e1c2}, /* U+756D */ - {0x00e795af, 0x00f8ca}, /* U+756F [2000] */ - {0x00e795b0, 0x00b0db}, /* U+7570 */ - {0x00e795b1, 0x8ff1bf}, /* U+7571 [2000] */ - {0x00e795b2, 0x8ff1be}, /* U+7572 [2000] */ - {0x00e795b3, 0x00bef6}, /* U+7573 */ - {0x00e795b4, 0x00e1c7}, /* U+7574 */ - {0x00e795b6, 0x00e1c4}, /* U+7576 */ - {0x00e795b7, 0x00c6ed}, /* U+7577 */ - {0x00e795b8, 0x00e1c3}, /* U+7578 */ - {0x00e795b9, 0x00f8cb}, /* U+7579 [2000] */ - {0x00e795ba, 0x8ff1c0}, /* U+757A [2000] */ - {0x00e795bd, 0x8ff1c1}, /* U+757D [2000] */ - {0x00e795be, 0x8ff1c2}, /* U+757E [2000] */ - {0x00e795bf, 0x00b5a6}, /* U+757F */ - {0x00e79681, 0x8ff1c3}, /* U+7581 [2000] */ - {0x00e79682, 0x00e1ca}, /* U+7582 */ - {0x00e79686, 0x00e1c5}, /* U+7586 */ - {0x00e79687, 0x00e1c6}, /* U+7587 */ - {0x00e79689, 0x00e1c9}, /* U+7589 */ - {0x00e7968a, 0x00e1c8}, /* U+758A */ - {0x00e7968b, 0x00c9a5}, /* U+758B */ - {0x00e7968c, 0x8ff1c5}, /* U+758C [2000] */ - {0x00e7968e, 0x00c1c2}, /* U+758E */ - {0x00e7968f, 0x00c1c1}, /* U+758F */ - {0x00e79691, 0x00b5bf}, /* U+7591 */ - {0x00e79692, 0x00f8cc}, /* U+7592 [2000] */ - {0x00e79694, 0x00e1cb}, /* U+7594 */ - {0x00e7969a, 0x00e1cc}, /* U+759A */ - {0x00e7969d, 0x00e1cd}, /* U+759D */ - {0x00e796a2, 0x8ff1c7}, /* U+75A2 [2000] */ - {0x00e796a3, 0x00e1cf}, /* U+75A3 */ - {0x00e796a5, 0x00e1ce}, /* U+75A5 */ - {0x00e796ab, 0x00b1d6}, /* U+75AB */ - {0x00e796b0, 0x8ff1c9}, /* U+75B0 [2000] */ - {0x00e796b1, 0x00e1d7}, /* U+75B1 */ - {0x00e796b2, 0x00c8e8}, /* U+75B2 */ - {0x00e796b3, 0x00e1d1}, /* U+75B3 */ - {0x00e796b5, 0x00e1d3}, /* U+75B5 */ - {0x00e796b7, 0x8ff1ca}, /* U+75B7 [2000] */ - {0x00e796b8, 0x00e1d5}, /* U+75B8 */ - {0x00e796b9, 0x00bfbe}, /* U+75B9 */ - {0x00e796bc, 0x00e1d6}, /* U+75BC */ - {0x00e796bd, 0x00e1d4}, /* U+75BD */ - {0x00e796be, 0x00bcc0}, /* U+75BE */ - {0x00e796bf, 0x8ff1cb}, /* U+75BF [2000] */ - {0x00e79780, 0x8ff1cc}, /* U+75C0 [2000] */ - {0x00e79782, 0x00e1d0}, /* U+75C2 */ - {0x00e79783, 0x00e1d2}, /* U+75C3 */ - {0x00e79785, 0x00c9c2}, /* U+75C5 */ - {0x00e79786, 0x8ff1cd}, /* U+75C6 [2000] */ - {0x00e79787, 0x00bec9}, /* U+75C7 */ - {0x00e7978a, 0x00e1d9}, /* U+75CA */ - {0x00e7978d, 0x00e1d8}, /* U+75CD */ - {0x00e7978e, 0x00f8ce}, /* U+75CE [2000] */ - {0x00e7978f, 0x8ff1ce}, /* U+75CF [2000] */ - {0x00e79792, 0x00e1da}, /* U+75D2 */ - {0x00e79793, 0x8ff1cf}, /* U+75D3 [2000] */ - {0x00e79794, 0x00bca6}, /* U+75D4 */ - {0x00e79795, 0x00baaf}, /* U+75D5 */ - {0x00e79798, 0x00c5f7}, /* U+75D8 */ - {0x00e79799, 0x00e1db}, /* U+75D9 */ - {0x00e7979b, 0x00c4cb}, /* U+75DB */ - {0x00e7979d, 0x8ff1d0}, /* U+75DD [2000] */ - {0x00e7979e, 0x00e1dd}, /* U+75DE */ - {0x00e7979f, 0x8ff1d1}, /* U+75DF [2000] */ - {0x00e797a0, 0x8ff1d2}, /* U+75E0 [2000] */ - {0x00e797a2, 0x00cea1}, /* U+75E2 */ - {0x00e797a3, 0x00e1dc}, /* U+75E3 */ - {0x00e797a4, 0x00f8cf}, /* U+75E4 [2000] */ - {0x00e797a7, 0x8ff1d3}, /* U+75E7 [2000] */ - {0x00e797a9, 0x00c1e9}, /* U+75E9 */ - {0x00e797ac, 0x8ff1d4}, /* U+75EC [2000] */ - {0x00e797ae, 0x8ff1d5}, /* U+75EE [2000] */ - {0x00e797b0, 0x00e1e2}, /* U+75F0 */ - {0x00e797b1, 0x8ff1d6}, /* U+75F1 [2000] */ - {0x00e797b2, 0x00e1e4}, /* U+75F2 */ - {0x00e797b3, 0x00e1e5}, /* U+75F3 */ - {0x00e797b4, 0x00c3d4}, /* U+75F4 */ - {0x00e797b9, 0x8ff1d7}, /* U+75F9 [2000] */ - {0x00e797ba, 0x00e1e3}, /* U+75FA */ - {0x00e797bc, 0x00e1e0}, /* U+75FC */ - {0x00e797be, 0x00e1de}, /* U+75FE */ - {0x00e797bf, 0x00e1df}, /* U+75FF */ - {0x00e79880, 0x00f8d0}, /* U+7600 [2000] */ - {0x00e79881, 0x00e1e1}, /* U+7601 */ - {0x00e79882, 0x00f8d1}, /* U+7602 [2000] */ - {0x00e79883, 0x8ff1d8}, /* U+7603 [2000] */ - {0x00e79887, 0x8ff1da}, /* U+7607 [2000] */ - {0x00e79888, 0x00f8d2}, /* U+7608 [2000] */ - {0x00e79889, 0x00e1e8}, /* U+7609 */ - {0x00e7988b, 0x00e1e6}, /* U+760B */ - {0x00e7988d, 0x00e1e7}, /* U+760D */ - {0x00e7988f, 0x8ff1db}, /* U+760F [2000] */ - {0x00e79893, 0x8ff1de}, /* U+7613 [2000] */ - {0x00e79895, 0x00f8d3}, /* U+7615 [2000] */ - {0x00e79896, 0x00f8d4}, /* U+7616 [2000] */ - {0x00e79898, 0x8ff1d9}, /* U+7618 [2000] */ - {0x00e79899, 0x00f8d5}, /* U+7619 [2000] */ - {0x00e7989b, 0x8ff1df}, /* U+761B [2000] */ - {0x00e7989c, 0x8ff1e0}, /* U+761C [2000] */ - {0x00e7989e, 0x00f8d6}, /* U+761E [2000] */ - {0x00e7989f, 0x00e1e9}, /* U+761F */ - {0x00e798a0, 0x00e1eb}, /* U+7620 */ - {0x00e798a1, 0x00e1ec}, /* U+7621 */ - {0x00e798a2, 0x00e1ed}, /* U+7622 */ - {0x00e798a4, 0x00e1ee}, /* U+7624 */ - {0x00e798a5, 0x8ff1e2}, /* U+7625 [2000] */ - {0x00e798a6, 0x00fefd}, /* U+7626 [2004] */ - {0x00e798a7, 0x00e1ea}, /* U+7627 */ - {0x00e798a8, 0x8ff1e3}, /* U+7628 [2000] */ - {0x00e798ad, 0x00f8d7}, /* U+762D [2000] */ - {0x00e798b0, 0x00e1f0}, /* U+7630 */ - {0x00e798b3, 0x8ff1e5}, /* U+7633 [2000] */ - {0x00e798b4, 0x00e1ef}, /* U+7634 */ - {0x00e798b5, 0x00f8d8}, /* U+7635 [2000] */ - {0x00e798bb, 0x00e1f1}, /* U+763B */ - {0x00e798bc, 0x8ff1e4}, /* U+763C [2000] */ - {0x00e79981, 0x8ff1e8}, /* U+7641 [2000] */ - {0x00e79982, 0x00cec5}, /* U+7642 */ - {0x00e79983, 0x00f8d9}, /* U+7643 [2000] */ - {0x00e79986, 0x00e1f4}, /* U+7646 */ - {0x00e79987, 0x00e1f2}, /* U+7647 */ - {0x00e79988, 0x00e1f3}, /* U+7648 */ - {0x00e79989, 0x8ff1ea}, /* U+7649 [2000] */ - {0x00e7998b, 0x00f8da}, /* U+764B [2000] */ - {0x00e7998c, 0x00b4e2}, /* U+764C */ - {0x00e79992, 0x00ccfe}, /* U+7652 */ - {0x00e79995, 0x8ff1eb}, /* U+7655 [2000] */ - {0x00e79996, 0x00caca}, /* U+7656 */ - {0x00e79998, 0x00e1f6}, /* U+7658 */ - {0x00e7999c, 0x00e1f5}, /* U+765C */ - {0x00e799a1, 0x00e1f7}, /* U+7661 */ - {0x00e799a2, 0x00e1f8}, /* U+7662 */ - {0x00e799a4, 0x00f8db}, /* U+7664 [2000] */ - {0x00e799a5, 0x00f8dc}, /* U+7665 [2000] */ - {0x00e799a7, 0x00e1fc}, /* U+7667 */ - {0x00e799a8, 0x00e1f9}, /* U+7668 */ - {0x00e799a9, 0x00e1fa}, /* U+7669 */ - {0x00e799aa, 0x00e1fb}, /* U+766A */ - {0x00e799ac, 0x00e1fd}, /* U+766C */ - {0x00e799ad, 0x00f8dd}, /* U+766D [2000] */ - {0x00e799ae, 0x8ff1ed}, /* U+766E [2000] */ - {0x00e799af, 0x00f8de}, /* U+766F [2000] */ - {0x00e799b0, 0x00e1fe}, /* U+7670 */ - {0x00e799b1, 0x00f8df}, /* U+7671 [2000] */ - {0x00e799b2, 0x00e2a1}, /* U+7672 */ - {0x00e799b6, 0x00e2a2}, /* U+7676 */ - {0x00e799b8, 0x00e2a3}, /* U+7678 */ - {0x00e799ba, 0x00c8af}, /* U+767A */ - {0x00e799bb, 0x00c5d0}, /* U+767B */ - {0x00e799bc, 0x00e2a4}, /* U+767C */ - {0x00e799bd, 0x00c7f2}, /* U+767D */ - {0x00e799be, 0x00c9b4}, /* U+767E */ - {0x00e79a80, 0x00e2a5}, /* U+7680 */ - {0x00e79a81, 0x00f8e0}, /* U+7681 [2000] */ - {0x00e79a83, 0x00e2a6}, /* U+7683 */ - {0x00e79a84, 0x00c5aa}, /* U+7684 */ - {0x00e79a86, 0x00b3a7}, /* U+7686 */ - {0x00e79a87, 0x00b9c4}, /* U+7687 */ - {0x00e79a88, 0x00e2a7}, /* U+7688 */ - {0x00e79a8b, 0x00e2a8}, /* U+768B */ - {0x00e79a8e, 0x00e2a9}, /* U+768E */ - {0x00e79a90, 0x00bba9}, /* U+7690 */ - {0x00e79a93, 0x00e2ab}, /* U+7693 */ - {0x00e79a95, 0x8ff1ee}, /* U+7695 [2000] */ - {0x00e79a96, 0x00e2aa}, /* U+7696 */ - {0x00e79a99, 0x00e2ac}, /* U+7699 */ - {0x00e79a9a, 0x00e2ad}, /* U+769A */ - {0x00e79a9b, 0x00f8e1}, /* U+769B [2000] */ - {0x00e79a9c, 0x8ff1ef}, /* U+769C [2000] */ - {0x00e79a9d, 0x00f8e2}, /* U+769D [2000] */ - {0x00e79a9e, 0x00f8e3}, /* U+769E [2000] */ - {0x00e79aa0, 0x8ff1f1}, /* U+76A0 [2000] */ - {0x00e79aa1, 0x8ff1f0}, /* U+76A1 [2000] */ - {0x00e79aa6, 0x00f8e4}, /* U+76A6 [2000] */ - {0x00e79aa7, 0x8ff1f2}, /* U+76A7 [2000] */ - {0x00e79aa8, 0x8ff1f3}, /* U+76A8 [2000] */ - {0x00e79aaa, 0x00f8e5}, /* U+76AA [2000] */ - {0x00e79aae, 0x00c8e9}, /* U+76AE */ - {0x00e79aaf, 0x8ff1f4}, /* U+76AF [2000] */ - {0x00e79ab0, 0x00e2ae}, /* U+76B0 */ - {0x00e79ab4, 0x00e2af}, /* U+76B4 */ - {0x00e79ab6, 0x00f8e6}, /* U+76B6 [2000] */ - {0x00e79ab7, 0x00f3e9}, /* U+76B7 */ - {0x00e79ab8, 0x00e2b0}, /* U+76B8 */ - {0x00e79ab9, 0x00e2b1}, /* U+76B9 */ - {0x00e79aba, 0x00e2b2}, /* U+76BA */ - {0x00e79abf, 0x00bbae}, /* U+76BF */ - {0x00e79b82, 0x00e2b3}, /* U+76C2 */ - {0x00e79b83, 0x00c7d6}, /* U+76C3 */ - {0x00e79b85, 0x00f8e7}, /* U+76C5 [2000] */ - {0x00e79b86, 0x00cbdf}, /* U+76C6 */ - {0x00e79b88, 0x00b1ce}, /* U+76C8 */ - {0x00e79b89, 0x8ff1f6}, /* U+76C9 [2000] */ - {0x00e79b8a, 0x00b1d7}, /* U+76CA */ - {0x00e79b8c, 0x00f8e8}, /* U+76CC [2000] */ - {0x00e79b8d, 0x00e2b4}, /* U+76CD */ - {0x00e79b8e, 0x00f8e9}, /* U+76CE [2000] */ - {0x00e79b92, 0x00e2b6}, /* U+76D2 */ - {0x00e79b94, 0x00f8ea}, /* U+76D4 [2000] */ - {0x00e79b96, 0x00e2b5}, /* U+76D6 */ - {0x00e79b97, 0x00c5f0}, /* U+76D7 */ - {0x00e79b9b, 0x00c0b9}, /* U+76DB */ - {0x00e79b9c, 0x00ddb9}, /* U+76DC */ - {0x00e79b9e, 0x00e2b7}, /* U+76DE */ - {0x00e79b9f, 0x00ccc1}, /* U+76DF */ - {0x00e79ba1, 0x00e2b8}, /* U+76E1 */ - {0x00e79ba3, 0x00b4c6}, /* U+76E3 */ - {0x00e79ba4, 0x00c8d7}, /* U+76E4 */ - {0x00e79ba5, 0x00e2b9}, /* U+76E5 */ - {0x00e79ba6, 0x00f8eb}, /* U+76E6 [2000] */ - {0x00e79ba7, 0x00e2ba}, /* U+76E7 */ - {0x00e79ba8, 0x8ff1f8}, /* U+76E8 [2000] */ - {0x00e79baa, 0x00e2bb}, /* U+76EA */ - {0x00e79bac, 0x8ff1f9}, /* U+76EC [2000] */ - {0x00e79bae, 0x00ccdc}, /* U+76EE */ - {0x00e79bb1, 0x00f8ec}, /* U+76F1 [2000] */ - {0x00e79bb2, 0x00ccd5}, /* U+76F2 */ - {0x00e79bb4, 0x00c4be}, /* U+76F4 */ - {0x00e79bb8, 0x00c1ea}, /* U+76F8 */ - {0x00e79bbb, 0x00e2bd}, /* U+76FB */ - {0x00e79bbc, 0x00f8ed}, /* U+76FC [2000] */ - {0x00e79bbe, 0x00bde2}, /* U+76FE */ - {0x00e79c81, 0x00beca}, /* U+7701 */ - {0x00e79c84, 0x00e2c0}, /* U+7704 */ - {0x00e79c87, 0x00e2bf}, /* U+7707 */ - {0x00e79c88, 0x00e2be}, /* U+7708 */ - {0x00e79c89, 0x00c8fd}, /* U+7709 */ - {0x00e79c8a, 0x00f8ee}, /* U+770A [2000] */ - {0x00e79c8b, 0x00b4c7}, /* U+770B */ - {0x00e79c8c, 0x00b8a9}, /* U+770C */ - {0x00e79c97, 0x8ff1fb}, /* U+7717 [2000] */ - {0x00e79c99, 0x00f8ef}, /* U+7719 [2000] */ - {0x00e79c9a, 0x8ff1fc}, /* U+771A [2000] */ - {0x00e79c9b, 0x00e2c6}, /* U+771B */ - {0x00e79c9e, 0x00e2c3}, /* U+771E */ - {0x00e79c9f, 0x00bfbf}, /* U+771F */ - {0x00e79ca0, 0x00ccb2}, /* U+7720 */ - {0x00e79ca4, 0x00e2c2}, /* U+7724 */ - {0x00e79ca5, 0x00e2c4}, /* U+7725 */ - {0x00e79ca6, 0x00e2c5}, /* U+7726 */ - {0x00e79ca9, 0x00e2c1}, /* U+7729 */ - {0x00e79cad, 0x8ff1fd}, /* U+772D [2000] */ - {0x00e79cb4, 0x00f8f0}, /* U+7734 [2000] */ - {0x00e79cb5, 0x8ff1fe}, /* U+7735 [2000] */ - {0x00e79cb6, 0x00f8f1}, /* U+7736 [2000] */ - {0x00e79cb7, 0x00e2c7}, /* U+7737 */ - {0x00e79cb8, 0x00e2c8}, /* U+7738 */ - {0x00e79cba, 0x00c4af}, /* U+773A */ - {0x00e79cbc, 0x00b4e3}, /* U+773C */ - {0x00e79d80, 0x00c3e5}, /* U+7740 */ - {0x00e79d86, 0x00f8f2}, /* U+7746 [2000] */ - {0x00e79d87, 0x00e2c9}, /* U+7747 */ - {0x00e79d8d, 0x00f8f3}, /* U+774D [2000] */ - {0x00e79d8e, 0x00f8f4}, /* U+774E [2000] */ - {0x00e79d98, 0x8ff2a5}, /* U+7758 [2000] */ - {0x00e79d9a, 0x00e2ca}, /* U+775A */ - {0x00e79d9b, 0x00e2cd}, /* U+775B */ - {0x00e79d9c, 0x00f8f5}, /* U+775C [2000] */ - {0x00e79d9f, 0x00f8f6}, /* U+775F [2000] */ - {0x00e79da0, 0x8ff2a6}, /* U+7760 [2000] */ - {0x00e79da1, 0x00bfe7}, /* U+7761 */ - {0x00e79da2, 0x00f8f7}, /* U+7762 [2000] */ - {0x00e79da3, 0x00c6c4}, /* U+7763 */ - {0x00e79da5, 0x00e2ce}, /* U+7765 */ - {0x00e79da6, 0x00cbd3}, /* U+7766 */ - {0x00e79da8, 0x00e2cb}, /* U+7768 */ - {0x00e79daa, 0x8ff2a7}, /* U+776A [2000] */ - {0x00e79dab, 0x00e2cc}, /* U+776B */ - {0x00e79db2, 0x8ff2a9}, /* U+7772 [2000] */ - {0x00e79db9, 0x00e2d1}, /* U+7779 */ - {0x00e79dba, 0x00f8f8}, /* U+777A [2000] */ - {0x00e79dbc, 0x8ff2aa}, /* U+777C [2000] */ - {0x00e79dbd, 0x8ff2ab}, /* U+777D [2000] */ - {0x00e79dbe, 0x00e2d0}, /* U+777E */ - {0x00e79dbf, 0x00e2cf}, /* U+777F */ - {0x00e79e80, 0x00f8f9}, /* U+7780 [2000] */ - {0x00e79e8b, 0x00e2d3}, /* U+778B */ - {0x00e79e8e, 0x00e2d2}, /* U+778E */ - {0x00e79e91, 0x00e2d4}, /* U+7791 */ - {0x00e79e94, 0x00f8fa}, /* U+7794 [2000] */ - {0x00e79e9a, 0x8ff2ae}, /* U+779A [2000] */ - {0x00e79e9e, 0x00e2d6}, /* U+779E */ - {0x00e79e9f, 0x8ff2af}, /* U+779F [2000] */ - {0x00e79ea0, 0x00e2d5}, /* U+77A0 */ - {0x00e79ea2, 0x8ff2b0}, /* U+77A2 [2000] */ - {0x00e79ea4, 0x8ff2b1}, /* U+77A4 [2000] */ - {0x00e79ea5, 0x00cacd}, /* U+77A5 */ - {0x00e79ea9, 0x8ff2b2}, /* U+77A9 [2000] */ - {0x00e79eaa, 0x00f8fb}, /* U+77AA [2000] */ - {0x00e79eac, 0x00bdd6}, /* U+77AC */ - {0x00e79ead, 0x00cec6}, /* U+77AD */ - {0x00e79eb0, 0x00e2d7}, /* U+77B0 */ - {0x00e79eb3, 0x00c6b7}, /* U+77B3 */ - {0x00e79eb6, 0x00e2d8}, /* U+77B6 */ - {0x00e79eb9, 0x00e2d9}, /* U+77B9 */ - {0x00e79ebb, 0x00e2dd}, /* U+77BB */ - {0x00e79ebc, 0x00e2db}, /* U+77BC */ - {0x00e79ebd, 0x00e2dc}, /* U+77BD */ - {0x00e79ebf, 0x00e2da}, /* U+77BF */ - {0x00e79f87, 0x00e2de}, /* U+77C7 */ - {0x00e79f8d, 0x00e2df}, /* U+77CD */ - {0x00e79f97, 0x00e2e0}, /* U+77D7 */ - {0x00e79f9a, 0x00e2e1}, /* U+77DA */ - {0x00e79f9b, 0x00ccb7}, /* U+77DB */ - {0x00e79f9c, 0x00e2e2}, /* U+77DC */ - {0x00e79f9e, 0x8ff2b3}, /* U+77DE [2000] */ - {0x00e79f9f, 0x8ff2b4}, /* U+77DF [2000] */ - {0x00e79fa0, 0x00f8fc}, /* U+77E0 [2000] */ - {0x00e79fa2, 0x00ccf0}, /* U+77E2 */ - {0x00e79fa3, 0x00e2e3}, /* U+77E3 */ - {0x00e79fa4, 0x8ff2b5}, /* U+77E4 [2000] */ - {0x00e79fa5, 0x00c3ce}, /* U+77E5 */ - {0x00e79fa6, 0x8ff2b6}, /* U+77E6 [2000] */ - {0x00e79fa7, 0x00c7ea}, /* U+77E7 */ - {0x00e79fa9, 0x00b6eb}, /* U+77E9 */ - {0x00e79faa, 0x8ff2b7}, /* U+77EA [2000] */ - {0x00e79fac, 0x8ff2b8}, /* U+77EC [2000] */ - {0x00e79fad, 0x00c3bb}, /* U+77ED */ - {0x00e79fae, 0x00e2e4}, /* U+77EE */ - {0x00e79faf, 0x00b6ba}, /* U+77EF */ - {0x00e79fb0, 0x8ff2ba}, /* U+77F0 [2000] */ - {0x00e79fb3, 0x00c0d0}, /* U+77F3 */ - {0x00e79fb4, 0x8ff2bb}, /* U+77F4 [2000] */ - {0x00e79fbb, 0x8ff2bc}, /* U+77FB [2000] */ - {0x00e79fbc, 0x00e2e5}, /* U+77FC */ - {0x00e7a082, 0x00babd}, /* U+7802 */ - {0x00e7a085, 0x8ff2be}, /* U+7805 [2000] */ - {0x00e7a086, 0x8ff2bf}, /* U+7806 [2000] */ - {0x00e7a089, 0x8ff2c0}, /* U+7809 [2000] */ - {0x00e7a08c, 0x00e2e6}, /* U+780C */ - {0x00e7a08d, 0x8ff2c1}, /* U+780D [2000] */ - {0x00e7a092, 0x00e2e7}, /* U+7812 */ - {0x00e7a094, 0x00b8a6}, /* U+7814 */ - {0x00e7a095, 0x00bad5}, /* U+7815 */ - {0x00e7a099, 0x8ff2c2}, /* U+7819 [2000] */ - {0x00e7a0a0, 0x00e2e9}, /* U+7820 */ - {0x00e7a0a1, 0x8ff2c3}, /* U+7821 [2000] */ - {0x00e7a0a5, 0x00c5d6}, /* U+7825 */ - {0x00e7a0a6, 0x00bad6}, /* U+7826 */ - {0x00e7a0a7, 0x00b5ce}, /* U+7827 */ - {0x00e7a0ac, 0x8ff2c4}, /* U+782C [2000] */ - {0x00e7a0ad, 0x00f8fd}, /* U+782D [2000] */ - {0x00e7a0b2, 0x00cba4}, /* U+7832 */ - {0x00e7a0b4, 0x00c7cb}, /* U+7834 */ - {0x00e7a0ba, 0x00c5d7}, /* U+783A */ - {0x00e7a0bf, 0x00b9dc}, /* U+783F */ - {0x00e7a183, 0x00f9a1}, /* U+7843 [2000] */ - {0x00e7a185, 0x00e2eb}, /* U+7845 */ - {0x00e7a187, 0x8ff2c5}, /* U+7847 [2000] */ - {0x00e7a18e, 0x00f9a2}, /* U+784E [2000] */ - {0x00e7a18f, 0x00f9a3}, /* U+784F [2000] */ - {0x00e7a191, 0x00f9a4}, /* U+7851 [2000] */ - {0x00e7a19d, 0x00becb}, /* U+785D */ - {0x00e7a1a4, 0x8ff2c6}, /* U+7864 [2000] */ - {0x00e7a1a8, 0x00f9a5}, /* U+7868 [2000] */ - {0x00e7a1aa, 0x8ff2c7}, /* U+786A [2000] */ - {0x00e7a1ab, 0x00ceb2}, /* U+786B */ - {0x00e7a1ac, 0x00b9c5}, /* U+786C */ - {0x00e7a1ae, 0x00f9a6}, /* U+786E [2000] */ - {0x00e7a1af, 0x00b8a7}, /* U+786F */ - {0x00e7a1b2, 0x00c8a3}, /* U+7872 */ - {0x00e7a1b4, 0x00e2ed}, /* U+7874 */ - {0x00e7a1bc, 0x00e2ef}, /* U+787C */ - {0x00e7a281, 0x00b8eb}, /* U+7881 */ - {0x00e7a286, 0x00e2ee}, /* U+7886 */ - {0x00e7a287, 0x00c4f6}, /* U+7887 */ - {0x00e7a28a, 0x8ff2c9}, /* U+788A [2000] */ - {0x00e7a28c, 0x00e2f1}, /* U+788C */ - {0x00e7a28d, 0x00b3b7}, /* U+788D */ - {0x00e7a28e, 0x00e2ec}, /* U+788E */ - {0x00e7a291, 0x00c8ea}, /* U+7891 */ - {0x00e7a293, 0x00b1b0}, /* U+7893 */ - {0x00e7a294, 0x8ff2ca}, /* U+7894 [2000] */ - {0x00e7a295, 0x00baec}, /* U+7895 */ - {0x00e7a297, 0x00cfd2}, /* U+7897 */ - {0x00e7a29a, 0x00e2f0}, /* U+789A */ - {0x00e7a29d, 0x8ff2cc}, /* U+789D [2000] */ - {0x00e7a29e, 0x8ff2cd}, /* U+789E [2000] */ - {0x00e7a29f, 0x8ff2ce}, /* U+789F [2000] */ - {0x00e7a2a3, 0x00e2f2}, /* U+78A3 */ - {0x00e7a2a4, 0x8ff2cb}, /* U+78A4 [2000] */ - {0x00e7a2a7, 0x00cacb}, /* U+78A7 */ - {0x00e7a2a9, 0x00c0d9}, /* U+78A9 */ - {0x00e7a2aa, 0x00e2f4}, /* U+78AA */ - {0x00e7a2ad, 0x00f9aa}, /* U+78AD [2000] */ - {0x00e7a2af, 0x00e2f5}, /* U+78AF */ - {0x00e7a2b0, 0x00f9a8}, /* U+78B0 [2000] */ - {0x00e7a2b5, 0x00e2f3}, /* U+78B5 */ - {0x00e7a2ba, 0x00b3ce}, /* U+78BA */ - {0x00e7a2bb, 0x8ff2cf}, /* U+78BB [2000] */ - {0x00e7a2bc, 0x00e2fb}, /* U+78BC */ - {0x00e7a2be, 0x00e2fa}, /* U+78BE */ - {0x00e7a381, 0x00bca7}, /* U+78C1 */ - {0x00e7a385, 0x00e2fc}, /* U+78C5 */ - {0x00e7a386, 0x00e2f7}, /* U+78C6 */ - {0x00e7a388, 0x8ff2d0}, /* U+78C8 [2000] */ - {0x00e7a38a, 0x00e2fd}, /* U+78CA */ - {0x00e7a38b, 0x00e2f8}, /* U+78CB */ - {0x00e7a38c, 0x8ff2d1}, /* U+78CC [2000] */ - {0x00e7a38e, 0x8ff2d2}, /* U+78CE [2000] */ - {0x00e7a390, 0x00c8d8}, /* U+78D0 */ - {0x00e7a391, 0x00e2f6}, /* U+78D1 */ - {0x00e7a394, 0x00e2f9}, /* U+78D4 */ - {0x00e7a395, 0x8ff2d3}, /* U+78D5 [2000] */ - {0x00e7a39a, 0x00e3a2}, /* U+78DA */ - {0x00e7a3a0, 0x8ff2d4}, /* U+78E0 [2000] */ - {0x00e7a3a1, 0x8ff2d5}, /* U+78E1 [2000] */ - {0x00e7a3a4, 0x00f9ab}, /* U+78E4 [2000] */ - {0x00e7a3a6, 0x8ff2d6}, /* U+78E6 [2000] */ - {0x00e7a3a7, 0x00e3a1}, /* U+78E7 */ - {0x00e7a3a8, 0x00cbe1}, /* U+78E8 */ - {0x00e7a3ac, 0x00e2fe}, /* U+78EC */ - {0x00e7a3af, 0x00b0eb}, /* U+78EF */ - {0x00e7a3b2, 0x00f9ac}, /* U+78F2 [2000] */ - {0x00e7a3b4, 0x00e3a4}, /* U+78F4 */ - {0x00e7a3b7, 0x00f9ae}, /* U+78F7 [2000] */ - {0x00e7a3b9, 0x8ff2d7}, /* U+78F9 [2000] */ - {0x00e7a3ba, 0x8ff2d8}, /* U+78FA [2000] */ - {0x00e7a3bb, 0x8ff2d9}, /* U+78FB [2000] */ - {0x00e7a3bd, 0x00e3a3}, /* U+78FD */ - {0x00e7a3be, 0x8ff2da}, /* U+78FE [2000] */ - {0x00e7a480, 0x00f9ad}, /* U+7900 [2000] */ - {0x00e7a481, 0x00becc}, /* U+7901 */ - {0x00e7a487, 0x00e3a5}, /* U+7907 */ - {0x00e7a48e, 0x00c1c3}, /* U+790E */ - {0x00e7a490, 0x8ff2dc}, /* U+7910 [2000] */ - {0x00e7a491, 0x00e3a7}, /* U+7911 */ - {0x00e7a492, 0x00e3a6}, /* U+7912 */ - {0x00e7a499, 0x00e3a8}, /* U+7919 */ - {0x00e7a49b, 0x8ff2dd}, /* U+791B [2000] */ - {0x00e7a49c, 0x00f9af}, /* U+791C [2000] */ - {0x00e7a4a5, 0x8ff2df}, /* U+7925 [2000] */ - {0x00e7a4a6, 0x00e2e8}, /* U+7926 */ - {0x00e7a4aa, 0x00e2ea}, /* U+792A */ - {0x00e7a4ab, 0x00e3aa}, /* U+792B */ - {0x00e7a4ac, 0x00e3a9}, /* U+792C */ - {0x00e7a4ae, 0x00f9b0}, /* U+792E [2000] */ - {0x00e7a4b0, 0x8ff2de}, /* U+7930 [2000] */ - {0x00e7a4b1, 0x00f9b1}, /* U+7931 [2000] */ - {0x00e7a4b4, 0x00f9b2}, /* U+7934 [2000] */ - {0x00e7a4ba, 0x00bca8}, /* U+793A */ - {0x00e7a4bb, 0x8ff2e0}, /* U+793B [2000] */ - {0x00e7a4bc, 0x00cee9}, /* U+793C */ - {0x00e7a4be, 0x00bcd2}, /* U+793E */ - {0x00e7a580, 0x00e3ab}, /* U+7940 */ - {0x00e7a581, 0x00b7b7}, /* U+7941 */ - {0x00e7a585, 0x00f9b5}, /* U+7945 [2000] */ - {0x00e7a586, 0x00f9b6}, /* U+7946 [2000] */ - {0x00e7a587, 0x00b5c0}, /* U+7947 */ - {0x00e7a588, 0x00b5a7}, /* U+7948 */ - {0x00e7a589, 0x00bbe3}, /* U+7949 */ - {0x00e7a58a, 0x8ff2e1}, /* U+794A [2000] */ - {0x00e7a590, 0x00cdb4}, /* U+7950 */ - {0x00e7a593, 0x00e3b1}, /* U+7953 */ - {0x00e7a595, 0x00e3b0}, /* U+7955 */ - {0x00e7a596, 0x00c1c4}, /* U+7956 */ - {0x00e7a597, 0x00e3ad}, /* U+7957 */ - {0x00e7a598, 0x8ff2e2}, /* U+7958 [2000] */ - {0x00e7a59a, 0x00e3af}, /* U+795A */ - {0x00e7a59b, 0x8ff2e3}, /* U+795B [2000] */ - {0x00e7a59c, 0x00f9ba}, /* U+795C [2000] */ - {0x00e7a59d, 0x00bdcb}, /* U+795D */ - {0x00e7a59e, 0x00bfc0}, /* U+795E */ - {0x00e7a59f, 0x00e3ae}, /* U+795F */ - {0x00e7a5a0, 0x00e3ac}, /* U+7960 */ - {0x00e7a5a2, 0x00c7aa}, /* U+7962 */ - {0x00e7a5a5, 0x00becd}, /* U+7965 */ - {0x00e7a5a7, 0x8ff2e5}, /* U+7967 [2000] */ - {0x00e7a5a8, 0x00c9bc}, /* U+7968 */ - {0x00e7a5ad, 0x00bad7}, /* U+796D */ - {0x00e7a5b2, 0x8ff2e6}, /* U+7972 [2000] */ - {0x00e7a5b7, 0x00c5f8}, /* U+7977 */ - {0x00e7a5b9, 0x00f9be}, /* U+7979 [2000] */ - {0x00e7a5ba, 0x00e3b2}, /* U+797A */ - {0x00e7a5bf, 0x00e3b3}, /* U+797F */ - {0x00e7a680, 0x00e3c9}, /* U+7980 */ - {0x00e7a681, 0x00b6d8}, /* U+7981 */ - {0x00e7a684, 0x00cfbd}, /* U+7984 */ - {0x00e7a685, 0x00c1b5}, /* U+7985 */ - {0x00e7a68a, 0x00e3b4}, /* U+798A */ - {0x00e7a68d, 0x00b2d2}, /* U+798D */ - {0x00e7a68e, 0x00c4f7}, /* U+798E */ - {0x00e7a68f, 0x00caa1}, /* U+798F */ - {0x00e7a694, 0x8ff2e7}, /* U+7994 [2000] */ - {0x00e7a695, 0x8ff2e8}, /* U+7995 [2000] */ - {0x00e7a696, 0x8ff2e9}, /* U+7996 [2000] */ - {0x00e7a698, 0x00f9c2}, /* U+7998 [2000] */ - {0x00e7a69b, 0x8ff2ea}, /* U+799B [2000] */ - {0x00e7a69d, 0x00e3b5}, /* U+799D */ - {0x00e7a6a1, 0x8ff2eb}, /* U+79A1 [2000] */ - {0x00e7a6a6, 0x00b5fa}, /* U+79A6 */ - {0x00e7a6a7, 0x00e3b6}, /* U+79A7 */ - {0x00e7a6a9, 0x8ff2ec}, /* U+79A9 [2000] */ - {0x00e7a6aa, 0x00e3b8}, /* U+79AA */ - {0x00e7a6ae, 0x00e3b9}, /* U+79AE */ - {0x00e7a6b0, 0x00c7a9}, /* U+79B0 */ - {0x00e7a6b1, 0x00f9c3}, /* U+79B1 [2000] */ - {0x00e7a6b3, 0x00e3ba}, /* U+79B3 */ - {0x00e7a6b4, 0x8ff2ed}, /* U+79B4 [2000] */ - {0x00e7a6b8, 0x00f9c4}, /* U+79B8 [2000] */ - {0x00e7a6b9, 0x00e3bb}, /* U+79B9 */ - {0x00e7a6ba, 0x00e3bc}, /* U+79BA */ - {0x00e7a6bb, 0x8ff2ee}, /* U+79BB [2000] */ - {0x00e7a6bd, 0x00b6d9}, /* U+79BD */ - {0x00e7a6be, 0x00b2d3}, /* U+79BE */ - {0x00e7a6bf, 0x00c6c5}, /* U+79BF */ - {0x00e7a780, 0x00bda8}, /* U+79C0 */ - {0x00e7a781, 0x00bbe4}, /* U+79C1 */ - {0x00e7a782, 0x8ff2ef}, /* U+79C2 [2000] */ - {0x00e7a787, 0x8ff2f0}, /* U+79C7 [2000] */ - {0x00e7a788, 0x00f9c5}, /* U+79C8 [2000] */ - {0x00e7a789, 0x00e3bd}, /* U+79C9 */ - {0x00e7a78a, 0x00f9c6}, /* U+79CA [2000] */ - {0x00e7a78b, 0x00bda9}, /* U+79CB */ - {0x00e7a78c, 0x8ff2f1}, /* U+79CC [2000] */ - {0x00e7a78d, 0x8ff2f2}, /* U+79CD [2000] */ - {0x00e7a791, 0x00b2ca}, /* U+79D1 */ - {0x00e7a792, 0x00c9c3}, /* U+79D2 */ - {0x00e7a794, 0x00f9c8}, /* U+79D4 [2000] */ - {0x00e7a795, 0x00e3be}, /* U+79D5 */ - {0x00e7a796, 0x8ff2f3}, /* U+79D6 [2000] */ - {0x00e7a798, 0x00c8eb}, /* U+79D8 */ - {0x00e7a79e, 0x00f9c9}, /* U+79DE [2000] */ - {0x00e7a79f, 0x00c1c5}, /* U+79DF */ - {0x00e7a7a1, 0x00e3c1}, /* U+79E1 */ - {0x00e7a7a3, 0x00e3c2}, /* U+79E3 */ - {0x00e7a7a4, 0x00c7e9}, /* U+79E4 */ - {0x00e7a7a6, 0x00bfc1}, /* U+79E6 */ - {0x00e7a7a7, 0x00e3bf}, /* U+79E7 */ - {0x00e7a7a9, 0x00c3e1}, /* U+79E9 */ - {0x00e7a7ab, 0x00f9ca}, /* U+79EB [2000] */ - {0x00e7a7ac, 0x00e3c0}, /* U+79EC */ - {0x00e7a7ad, 0x00f9cb}, /* U+79ED [2000] */ - {0x00e7a7b0, 0x00bece}, /* U+79F0 */ - {0x00e7a7bb, 0x00b0dc}, /* U+79FB */ - {0x00e7a880, 0x00b5a9}, /* U+7A00 */ - {0x00e7a883, 0x00f9cc}, /* U+7A03 [2000] */ - {0x00e7a888, 0x00e3c3}, /* U+7A08 */ - {0x00e7a88a, 0x8ff2f8}, /* U+7A0A [2000] */ - {0x00e7a88b, 0x00c4f8}, /* U+7A0B */ - {0x00e7a88d, 0x00e3c4}, /* U+7A0D */ - {0x00e7a88e, 0x00c0c7}, /* U+7A0E */ - {0x00e7a891, 0x8ff2f9}, /* U+7A11 [2000] */ - {0x00e7a894, 0x00ccad}, /* U+7A14 */ - {0x00e7a895, 0x8ff2fa}, /* U+7A15 [2000] */ - {0x00e7a897, 0x00c9a3}, /* U+7A17 */ - {0x00e7a898, 0x00e3c5}, /* U+7A18 */ - {0x00e7a899, 0x00e3c6}, /* U+7A19 */ - {0x00e7a89a, 0x00c3d5}, /* U+7A1A */ - {0x00e7a89b, 0x8ff2fb}, /* U+7A1B [2000] */ - {0x00e7a89c, 0x00cec7}, /* U+7A1C */ - {0x00e7a89e, 0x8ff2fc}, /* U+7A1E [2000] */ - {0x00e7a89f, 0x00e3c8}, /* U+7A1F */ - {0x00e7a8a0, 0x00e3c7}, /* U+7A20 */ - {0x00e7a8ad, 0x8ff2fe}, /* U+7A2D [2000] */ - {0x00e7a8ae, 0x00bcef}, /* U+7A2E */ - {0x00e7a8b1, 0x00e3ca}, /* U+7A31 */ - {0x00e7a8b2, 0x00b0f0}, /* U+7A32 */ - {0x00e7a8b7, 0x00e3cd}, /* U+7A37 */ - {0x00e7a8b8, 0x8ff3a1}, /* U+7A38 [2000] */ - {0x00e7a8b9, 0x00f9ce}, /* U+7A39 [2000] */ - {0x00e7a8bb, 0x00e3cb}, /* U+7A3B */ - {0x00e7a8bc, 0x00b2d4}, /* U+7A3C */ - {0x00e7a8bd, 0x00b7ce}, /* U+7A3D */ - {0x00e7a8be, 0x00e3cc}, /* U+7A3E */ - {0x00e7a8bf, 0x00b9c6}, /* U+7A3F */ - {0x00e7a980, 0x00b9f2}, /* U+7A40 */ - {0x00e7a982, 0x00cae6}, /* U+7A42 */ - {0x00e7a983, 0x00e3ce}, /* U+7A43 */ - {0x00e7a986, 0x00cbd4}, /* U+7A46 */ - {0x00e7a987, 0x8ff3a2}, /* U+7A47 [2000] */ - {0x00e7a989, 0x00e3d0}, /* U+7A49 */ - {0x00e7a98c, 0x8ff3a3}, /* U+7A4C [2000] */ - {0x00e7a98d, 0x00c0d1}, /* U+7A4D */ - {0x00e7a98e, 0x00b1cf}, /* U+7A4E */ - {0x00e7a98f, 0x00b2ba}, /* U+7A4F */ - {0x00e7a990, 0x00b0ac}, /* U+7A50 */ - {0x00e7a996, 0x8ff3a4}, /* U+7A56 [2000] */ - {0x00e7a997, 0x00e3cf}, /* U+7A57 */ - {0x00e7a999, 0x8ff3a5}, /* U+7A59 [2000] */ - {0x00e7a99c, 0x8ff3a6}, /* U+7A5C [2000] */ - {0x00e7a99d, 0x00f9cf}, /* U+7A5D [2000] */ - {0x00e7a99f, 0x8ff3a7}, /* U+7A5F [2000] */ - {0x00e7a9a0, 0x8ff3a8}, /* U+7A60 [2000] */ - {0x00e7a9a1, 0x00e3d1}, /* U+7A61 */ - {0x00e7a9a2, 0x00e3d2}, /* U+7A62 */ - {0x00e7a9a3, 0x00bef7}, /* U+7A63 */ - {0x00e7a9a7, 0x8ff3a9}, /* U+7A67 [2000] */ - {0x00e7a9a9, 0x00e3d3}, /* U+7A69 */ - {0x00e7a9aa, 0x8ff3aa}, /* U+7A6A [2000] */ - {0x00e7a9ab, 0x00b3cf}, /* U+7A6B */ - {0x00e7a9ad, 0x00f9d0}, /* U+7A6D [2000] */ - {0x00e7a9b0, 0x00e3d5}, /* U+7A70 */ - {0x00e7a9b4, 0x00b7ea}, /* U+7A74 */ - {0x00e7a9b5, 0x8ff3ab}, /* U+7A75 [2000] */ - {0x00e7a9b6, 0x00b5e6}, /* U+7A76 */ - {0x00e7a9b8, 0x8ff3ac}, /* U+7A78 [2000] */ - {0x00e7a9b9, 0x00e3d6}, /* U+7A79 */ - {0x00e7a9ba, 0x00b6f5}, /* U+7A7A */ - {0x00e7a9bd, 0x00e3d7}, /* U+7A7D */ - {0x00e7a9bf, 0x00c0fc}, /* U+7A7F */ - {0x00e7aa81, 0x00c6cd}, /* U+7A81 */ - {0x00e7aa82, 0x8ff3ad}, /* U+7A82 [2000] */ - {0x00e7aa83, 0x00c0e0}, /* U+7A83 */ - {0x00e7aa84, 0x00baf5}, /* U+7A84 */ - {0x00e7aa85, 0x00f9d2}, /* U+7A85 [2000] */ - {0x00e7aa88, 0x00e3d8}, /* U+7A88 */ - {0x00e7aa8a, 0x8ff3ae}, /* U+7A8A [2000] */ - {0x00e7aa90, 0x8ff3af}, /* U+7A90 [2000] */ - {0x00e7aa92, 0x00c3e2}, /* U+7A92 */ - {0x00e7aa93, 0x00c1eb}, /* U+7A93 */ - {0x00e7aa95, 0x00e3da}, /* U+7A95 */ - {0x00e7aa96, 0x00e3dc}, /* U+7A96 */ - {0x00e7aa97, 0x00e3d9}, /* U+7A97 */ - {0x00e7aa98, 0x00e3db}, /* U+7A98 */ - {0x00e7aa9f, 0x00b7a2}, /* U+7A9F */ - {0x00e7aaa0, 0x00f9d3}, /* U+7AA0 [2000] */ - {0x00e7aaa3, 0x8ff3b0}, /* U+7AA3 [2000] */ - {0x00e7aaa9, 0x00e3dd}, /* U+7AA9 */ - {0x00e7aaaa, 0x00b7a6}, /* U+7AAA */ - {0x00e7aaac, 0x8ff3b1}, /* U+7AAC [2000] */ - {0x00e7aaae, 0x00b5e7}, /* U+7AAE */ - {0x00e7aaaf, 0x00cdd2}, /* U+7AAF */ - {0x00e7aab0, 0x00e3df}, /* U+7AB0 */ - {0x00e7aab3, 0x00f9d5}, /* U+7AB3 [2000] */ - {0x00e7aab6, 0x00e3e0}, /* U+7AB6 */ - {0x00e7aab9, 0x8ff3b4}, /* U+7AB9 [2000] */ - {0x00e7aaba, 0x00b1ae}, /* U+7ABA */ - {0x00e7aabb, 0x00f9d6}, /* U+7ABB [2000] */ - {0x00e7aabc, 0x8ff3b5}, /* U+7ABC [2000] */ - {0x00e7aabe, 0x8ff3b6}, /* U+7ABE [2000] */ - {0x00e7aabf, 0x00e3e3}, /* U+7ABF */ - {0x00e7ab83, 0x00b3f6}, /* U+7AC3 */ - {0x00e7ab84, 0x00e3e2}, /* U+7AC4 */ - {0x00e7ab85, 0x00e3e1}, /* U+7AC5 */ - {0x00e7ab87, 0x00e3e5}, /* U+7AC7 */ - {0x00e7ab88, 0x00e3de}, /* U+7AC8 */ - {0x00e7ab8a, 0x00e3e6}, /* U+7ACA */ - {0x00e7ab8b, 0x00cea9}, /* U+7ACB */ - {0x00e7ab8c, 0x8ff3b8}, /* U+7ACC [2000] */ - {0x00e7ab8d, 0x00e3e7}, /* U+7ACD */ - {0x00e7ab8e, 0x00f9d7}, /* U+7ACE [2000] */ - {0x00e7ab8f, 0x00e3e8}, /* U+7ACF */ - {0x00e7ab91, 0x8ff3b9}, /* U+7AD1 [2000] */ - {0x00e7ab92, 0x00d4f4}, /* U+7AD2 */ - {0x00e7ab93, 0x00e3ea}, /* U+7AD3 */ - {0x00e7ab95, 0x00e3e9}, /* U+7AD5 */ - {0x00e7ab99, 0x00e3eb}, /* U+7AD9 */ - {0x00e7ab9a, 0x00e3ec}, /* U+7ADA */ - {0x00e7ab9c, 0x00ceb5}, /* U+7ADC */ - {0x00e7ab9d, 0x00e3ed}, /* U+7ADD */ - {0x00e7ab9f, 0x00f0ef}, /* U+7ADF */ - {0x00e7aba0, 0x00becf}, /* U+7AE0 */ - {0x00e7aba1, 0x00e3ee}, /* U+7AE1 */ - {0x00e7aba2, 0x00e3ef}, /* U+7AE2 */ - {0x00e7aba3, 0x00bdd7}, /* U+7AE3 */ - {0x00e7aba5, 0x00c6b8}, /* U+7AE5 */ - {0x00e7aba6, 0x00e3f0}, /* U+7AE6 */ - {0x00e7aba7, 0x8ff3ba}, /* U+7AE7 [2000] */ - {0x00e7aba8, 0x8ff3bb}, /* U+7AE8 [2000] */ - {0x00e7abaa, 0x00c3a8}, /* U+7AEA */ - {0x00e7abab, 0x00f9d8}, /* U+7AEB [2000] */ - {0x00e7abad, 0x00e3f1}, /* U+7AED */ - {0x00e7abaf, 0x00c3bc}, /* U+7AEF */ - {0x00e7abb0, 0x00e3f2}, /* U+7AF0 */ - {0x00e7abb4, 0x8ff3bc}, /* U+7AF4 [2000] */ - {0x00e7abb6, 0x00b6a5}, /* U+7AF6 */ - {0x00e7abb8, 0x00d1bf}, /* U+7AF8 */ - {0x00e7abb9, 0x00c3dd}, /* U+7AF9 */ - {0x00e7abba, 0x00bcb3}, /* U+7AFA */ - {0x00e7abbd, 0x00f9d9}, /* U+7AFD [2000] */ - {0x00e7abbf, 0x00b4c8}, /* U+7AFF */ - {0x00e7ac82, 0x00e3f3}, /* U+7B02 */ - {0x00e7ac84, 0x00e4a2}, /* U+7B04 */ - {0x00e7ac86, 0x00e3f6}, /* U+7B06 */ - {0x00e7ac87, 0x8ff3bf}, /* U+7B07 [2000] */ - {0x00e7ac88, 0x00b5e8}, /* U+7B08 */ - {0x00e7ac8a, 0x00e3f5}, /* U+7B0A */ - {0x00e7ac8b, 0x00e4a4}, /* U+7B0B */ - {0x00e7ac8f, 0x00e3f4}, /* U+7B0F */ - {0x00e7ac91, 0x00bed0}, /* U+7B11 */ - {0x00e7ac92, 0x00f9da}, /* U+7B12 [2000] */ - {0x00e7ac98, 0x00e3f8}, /* U+7B18 */ - {0x00e7ac99, 0x00e3f9}, /* U+7B19 */ - {0x00e7ac9b, 0x00c5ab}, /* U+7B1B */ - {0x00e7ac9e, 0x00e3fa}, /* U+7B1E */ - {0x00e7aca0, 0x00b3de}, /* U+7B20 */ - {0x00e7aca5, 0x00bfda}, /* U+7B25 */ - {0x00e7aca6, 0x00c9e4}, /* U+7B26 */ - {0x00e7aca7, 0x8ff3c2}, /* U+7B27 [2000] */ - {0x00e7aca8, 0x00e3fc}, /* U+7B28 */ - {0x00e7acaa, 0x8ff3c3}, /* U+7B2A [2000] */ - {0x00e7acac, 0x00c2e8}, /* U+7B2C */ - {0x00e7acad, 0x00f9db}, /* U+7B2D [2000] */ - {0x00e7acae, 0x8ff3c4}, /* U+7B2E [2000] */ - {0x00e7acaf, 0x8ff3c5}, /* U+7B2F [2000] */ - {0x00e7acb1, 0x8ff3c6}, /* U+7B31 [2000] */ - {0x00e7acb3, 0x00e3f7}, /* U+7B33 */ - {0x00e7acb5, 0x00e3fb}, /* U+7B35 */ - {0x00e7acb6, 0x00e3fd}, /* U+7B36 */ - {0x00e7acb9, 0x00bafb}, /* U+7B39 */ - {0x00e7acbb, 0x00f9dc}, /* U+7B3B [2000] */ - {0x00e7acbd, 0x8ff3c1}, /* U+7B3D [2000] */ - {0x00e7ad81, 0x8ff3ca}, /* U+7B41 [2000] */ - {0x00e7ad85, 0x00e4a6}, /* U+7B45 */ - {0x00e7ad86, 0x00c9ae}, /* U+7B46 */ - {0x00e7ad87, 0x00f9dd}, /* U+7B47 [2000] */ - {0x00e7ad88, 0x00c8a6}, /* U+7B48 */ - {0x00e7ad89, 0x00c5f9}, /* U+7B49 */ - {0x00e7ad8b, 0x00b6da}, /* U+7B4B */ - {0x00e7ad8c, 0x00e4a5}, /* U+7B4C */ - {0x00e7ad8d, 0x00e4a3}, /* U+7B4D */ - {0x00e7ad8e, 0x00f9de}, /* U+7B4E [2000] */ - {0x00e7ad8f, 0x00c8b5}, /* U+7B4F */ - {0x00e7ad90, 0x00e3fe}, /* U+7B50 */ - {0x00e7ad91, 0x00c3de}, /* U+7B51 */ - {0x00e7ad92, 0x00c5fb}, /* U+7B52 */ - {0x00e7ad94, 0x00c5fa}, /* U+7B54 */ - {0x00e7ad95, 0x8ff3cc}, /* U+7B55 [2000] */ - {0x00e7ad96, 0x00baf6}, /* U+7B56 */ - {0x00e7ad9d, 0x00e4b8}, /* U+7B5D */ - {0x00e7ada0, 0x00f9df}, /* U+7B60 [2000] */ - {0x00e7ada4, 0x8ff3ce}, /* U+7B64 [2000] */ - {0x00e7ada5, 0x00e4a8}, /* U+7B65 */ - {0x00e7ada6, 0x8ff3cf}, /* U+7B66 [2000] */ - {0x00e7ada7, 0x00e4aa}, /* U+7B67 */ - {0x00e7ada9, 0x8ff3d0}, /* U+7B69 [2000] */ - {0x00e7adac, 0x00e4ad}, /* U+7B6C */ - {0x00e7adad, 0x00f9e0}, /* U+7B6D [2000] */ - {0x00e7adae, 0x00e4ae}, /* U+7B6E */ - {0x00e7adaf, 0x00f9e1}, /* U+7B6F [2000] */ - {0x00e7adb0, 0x00e4ab}, /* U+7B70 */ - {0x00e7adb1, 0x00e4ac}, /* U+7B71 */ - {0x00e7adb2, 0x00f9e2}, /* U+7B72 [2000] */ - {0x00e7adb3, 0x8ff3d1}, /* U+7B73 [2000] */ - {0x00e7adb4, 0x00e4a9}, /* U+7B74 */ - {0x00e7adb5, 0x00e4a7}, /* U+7B75 */ - {0x00e7adb9, 0x8ff3cd}, /* U+7B79 [2000] */ - {0x00e7adba, 0x00e4a1}, /* U+7B7A */ - {0x00e7adbf, 0x8ff3c9}, /* U+7B7F [2000] */ - {0x00e7ae86, 0x00cacf}, /* U+7B86 */ - {0x00e7ae87, 0x00b2d5}, /* U+7B87 */ - {0x00e7ae8b, 0x00e4b5}, /* U+7B8B */ - {0x00e7ae8d, 0x00e4b2}, /* U+7B8D */ - {0x00e7ae8f, 0x00e4b7}, /* U+7B8F */ - {0x00e7ae90, 0x8ff3d4}, /* U+7B90 [2000] */ - {0x00e7ae91, 0x8ff3d5}, /* U+7B91 [2000] */ - {0x00e7ae92, 0x00e4b6}, /* U+7B92 */ - {0x00e7ae94, 0x00c7f3}, /* U+7B94 */ - {0x00e7ae95, 0x00cca7}, /* U+7B95 */ - {0x00e7ae97, 0x00bbbb}, /* U+7B97 */ - {0x00e7ae98, 0x00e4b0}, /* U+7B98 */ - {0x00e7ae99, 0x00e4b9}, /* U+7B99 */ - {0x00e7ae9a, 0x00e4b4}, /* U+7B9A */ - {0x00e7ae9b, 0x8ff3d6}, /* U+7B9B [2000] */ - {0x00e7ae9c, 0x00e4b3}, /* U+7B9C */ - {0x00e7ae9d, 0x00e4af}, /* U+7B9D */ - {0x00e7ae9e, 0x00f9e3}, /* U+7B9E [2000] */ - {0x00e7ae9f, 0x00e4b1}, /* U+7B9F */ - {0x00e7aea1, 0x00b4c9}, /* U+7BA1 */ - {0x00e7aeaa, 0x00c3bd}, /* U+7BAA */ - {0x00e7aead, 0x00c0fd}, /* U+7BAD */ - {0x00e7aeaf, 0x8ff3d8}, /* U+7BAF [2000] */ - {0x00e7aeb1, 0x00c8a2}, /* U+7BB1 */ - {0x00e7aeb4, 0x00e4be}, /* U+7BB4 */ - {0x00e7aeb5, 0x8ff3d9}, /* U+7BB5 [2000] */ - {0x00e7aeb8, 0x00c8a4}, /* U+7BB8 */ - {0x00e7aebc, 0x8ff3da}, /* U+7BBC [2000] */ - {0x00e7af80, 0x00c0e1}, /* U+7BC0 */ - {0x00e7af81, 0x00e4bb}, /* U+7BC1 */ - {0x00e7af84, 0x00c8cf}, /* U+7BC4 */ - {0x00e7af85, 0x8ff3db}, /* U+7BC5 [2000] */ - {0x00e7af86, 0x00e4bf}, /* U+7BC6 */ - {0x00e7af87, 0x00cad3}, /* U+7BC7 */ - {0x00e7af89, 0x00c3db}, /* U+7BC9 */ - {0x00e7af8a, 0x8ff3dc}, /* U+7BCA [2000] */ - {0x00e7af8b, 0x00e4ba}, /* U+7BCB */ - {0x00e7af8c, 0x00e4bc}, /* U+7BCC */ - {0x00e7af8f, 0x00e4bd}, /* U+7BCF */ - {0x00e7af94, 0x8ff3df}, /* U+7BD4 [2000] */ - {0x00e7af96, 0x8ff3e0}, /* U+7BD6 [2000] */ - {0x00e7af97, 0x00f9e5}, /* U+7BD7 [2000] */ - {0x00e7af99, 0x00f9e6}, /* U+7BD9 [2000] */ - {0x00e7af9a, 0x8ff3e1}, /* U+7BDA [2000] */ - {0x00e7af9d, 0x00e4c0}, /* U+7BDD */ - {0x00e7afa0, 0x00bcc4}, /* U+7BE0 */ - {0x00e7afa4, 0x00c6c6}, /* U+7BE4 */ - {0x00e7afa5, 0x00e4c5}, /* U+7BE5 */ - {0x00e7afa6, 0x00e4c4}, /* U+7BE6 */ - {0x00e7afa9, 0x00e4c1}, /* U+7BE9 */ - {0x00e7afaa, 0x8ff3e2}, /* U+7BEA [2000] */ - {0x00e7afad, 0x00cfb6}, /* U+7BED */ - {0x00e7afb0, 0x8ff3e3}, /* U+7BF0 [2000] */ - {0x00e7afb3, 0x00e4ca}, /* U+7BF3 */ - {0x00e7afb6, 0x00e4ce}, /* U+7BF6 */ - {0x00e7afb7, 0x00e4cb}, /* U+7BF7 */ - {0x00e7b080, 0x00e4c7}, /* U+7C00 */ - {0x00e7b081, 0x00f9e7}, /* U+7C01 [2000] */ - {0x00e7b083, 0x8ff3e4}, /* U+7C03 [2000] */ - {0x00e7b087, 0x00e4c8}, /* U+7C07 */ - {0x00e7b08b, 0x8ff3e5}, /* U+7C0B [2000] */ - {0x00e7b08d, 0x00e4cd}, /* U+7C0D */ - {0x00e7b08e, 0x8ff3e6}, /* U+7C0E [2000] */ - {0x00e7b08f, 0x8ff3e7}, /* U+7C0F [2000] */ - {0x00e7b091, 0x00e4c2}, /* U+7C11 */ - {0x00e7b092, 0x00d2d5}, /* U+7C12 */ - {0x00e7b093, 0x00e4c9}, /* U+7C13 */ - {0x00e7b094, 0x00e4c3}, /* U+7C14 */ - {0x00e7b097, 0x00e4cc}, /* U+7C17 */ - {0x00e7b09e, 0x00f9e9}, /* U+7C1E [2000] */ - {0x00e7b09f, 0x00e4d2}, /* U+7C1F */ - {0x00e7b0a0, 0x00f9ea}, /* U+7C20 [2000] */ - {0x00e7b0a1, 0x00b4ca}, /* U+7C21 */ - {0x00e7b0a3, 0x00e4cf}, /* U+7C23 */ - {0x00e7b0a6, 0x8ff3e8}, /* U+7C26 [2000] */ - {0x00e7b0a7, 0x00e4d0}, /* U+7C27 */ - {0x00e7b0aa, 0x00e4d1}, /* U+7C2A */ - {0x00e7b0ab, 0x00e4d4}, /* U+7C2B */ - {0x00e7b0b1, 0x00f9e8}, /* U+7C31 [2000] */ - {0x00e7b0b3, 0x00f9eb}, /* U+7C33 [2000] */ - {0x00e7b0b6, 0x00f9ec}, /* U+7C36 [2000] */ - {0x00e7b0b7, 0x00e4d3}, /* U+7C37 */ - {0x00e7b0b8, 0x00c8f6}, /* U+7C38 */ - {0x00e7b0bd, 0x00e4d5}, /* U+7C3D */ - {0x00e7b0be, 0x00cefc}, /* U+7C3E */ - {0x00e7b0bf, 0x00caed}, /* U+7C3F */ - {0x00e7b180, 0x00e4da}, /* U+7C40 */ - {0x00e7b183, 0x00e4d7}, /* U+7C43 */ - {0x00e7b185, 0x8ff3e9}, /* U+7C45 [2000] */ - {0x00e7b18a, 0x8ff3ea}, /* U+7C4A [2000] */ - {0x00e7b18c, 0x00e4d6}, /* U+7C4C */ - {0x00e7b18d, 0x00c0d2}, /* U+7C4D */ - {0x00e7b18f, 0x00e4d9}, /* U+7C4F */ - {0x00e7b190, 0x00e4db}, /* U+7C50 */ - {0x00e7b191, 0x8ff3eb}, /* U+7C51 [2000] */ - {0x00e7b194, 0x00e4d8}, /* U+7C54 */ - {0x00e7b196, 0x00e4df}, /* U+7C56 */ - {0x00e7b197, 0x8ff3ec}, /* U+7C57 [2000] */ - {0x00e7b198, 0x00e4dc}, /* U+7C58 */ - {0x00e7b199, 0x00f9ef}, /* U+7C59 [2000] */ - {0x00e7b19e, 0x8ff3ed}, /* U+7C5E [2000] */ - {0x00e7b19f, 0x00e4dd}, /* U+7C5F */ - {0x00e7b1a0, 0x00e4c6}, /* U+7C60 */ - {0x00e7b1a1, 0x8ff3ee}, /* U+7C61 [2000] */ - {0x00e7b1a4, 0x00e4de}, /* U+7C64 */ - {0x00e7b1a5, 0x00e4e0}, /* U+7C65 */ - {0x00e7b1a9, 0x8ff3ef}, /* U+7C69 [2000] */ - {0x00e7b1ac, 0x00e4e1}, /* U+7C6C */ - {0x00e7b1ad, 0x00f9f0}, /* U+7C6D [2000] */ - {0x00e7b1ae, 0x8ff3f0}, /* U+7C6E [2000] */ - {0x00e7b1af, 0x8ff3f1}, /* U+7C6F [2000] */ - {0x00e7b1b0, 0x8ff3f2}, /* U+7C70 [2000] */ - {0x00e7b1b3, 0x00cac6}, /* U+7C73 */ - {0x00e7b1b5, 0x00e4e2}, /* U+7C75 */ - {0x00e7b1b9, 0x00f9f1}, /* U+7C79 [2000] */ - {0x00e7b1be, 0x00cce2}, /* U+7C7E */ - {0x00e7b281, 0x00b6ce}, /* U+7C81 */ - {0x00e7b282, 0x00b7a9}, /* U+7C82 */ - {0x00e7b283, 0x00e4e3}, /* U+7C83 */ - {0x00e7b289, 0x00cab4}, /* U+7C89 */ - {0x00e7b28b, 0x00bfe8}, /* U+7C8B */ - {0x00e7b28d, 0x00ccb0}, /* U+7C8D */ - {0x00e7b28f, 0x00f9f2}, /* U+7C8F [2000] */ - {0x00e7b290, 0x00e4e4}, /* U+7C90 */ - {0x00e7b292, 0x00ceb3}, /* U+7C92 */ - {0x00e7b294, 0x00f9f3}, /* U+7C94 [2000] */ - {0x00e7b295, 0x00c7f4}, /* U+7C95 */ - {0x00e7b297, 0x00c1c6}, /* U+7C97 */ - {0x00e7b298, 0x00c7b4}, /* U+7C98 */ - {0x00e7b29b, 0x00bdcd}, /* U+7C9B */ - {0x00e7b29f, 0x00b0c0}, /* U+7C9F */ - {0x00e7b2a0, 0x00f9f4}, /* U+7CA0 [2000] */ - {0x00e7b2a1, 0x00e4e9}, /* U+7CA1 */ - {0x00e7b2a2, 0x00e4e7}, /* U+7CA2 */ - {0x00e7b2a4, 0x00e4e5}, /* U+7CA4 */ - {0x00e7b2a5, 0x00b4a1}, /* U+7CA5 */ - {0x00e7b2a6, 0x8ff3f6}, /* U+7CA6 [2000] */ - {0x00e7b2a7, 0x00bed1}, /* U+7CA7 */ - {0x00e7b2a8, 0x00e4ea}, /* U+7CA8 */ - {0x00e7b2ab, 0x00e4e8}, /* U+7CAB */ - {0x00e7b2ad, 0x00e4e6}, /* U+7CAD */ - {0x00e7b2ae, 0x00e4ee}, /* U+7CAE */ - {0x00e7b2b1, 0x00e4ed}, /* U+7CB1 */ - {0x00e7b2b2, 0x00e4ec}, /* U+7CB2 */ - {0x00e7b2b3, 0x00e4eb}, /* U+7CB3 */ - {0x00e7b2b6, 0x8ff3f8}, /* U+7CB6 [2000] */ - {0x00e7b2b7, 0x8ff3f9}, /* U+7CB7 [2000] */ - {0x00e7b2b9, 0x00e4ef}, /* U+7CB9 */ - {0x00e7b2bc, 0x00f9f5}, /* U+7CBC [2000] */ - {0x00e7b2bd, 0x00e4f0}, /* U+7CBD */ - {0x00e7b2be, 0x00c0ba}, /* U+7CBE */ - {0x00e7b2bf, 0x8ff3fa}, /* U+7CBF [2000] */ - {0x00e7b380, 0x00e4f1}, /* U+7CC0 */ - {0x00e7b382, 0x00e4f3}, /* U+7CC2 */ - {0x00e7b384, 0x8ff3fc}, /* U+7CC4 [2000] */ - {0x00e7b385, 0x00e4f2}, /* U+7CC5 */ - {0x00e7b388, 0x8ff3fe}, /* U+7CC8 [2000] */ - {0x00e7b38a, 0x00b8d2}, /* U+7CCA */ - {0x00e7b38d, 0x8ff4a1}, /* U+7CCD [2000] */ - {0x00e7b38e, 0x00c1b8}, /* U+7CCE */ - {0x00e7b392, 0x00e4f5}, /* U+7CD2 */ - {0x00e7b395, 0x00f9f6}, /* U+7CD5 [2000] */ - {0x00e7b396, 0x00c5fc}, /* U+7CD6 */ - {0x00e7b397, 0x8ff4a3}, /* U+7CD7 [2000] */ - {0x00e7b398, 0x00e4f4}, /* U+7CD8 */ - {0x00e7b399, 0x00f9f7}, /* U+7CD9 [2000] */ - {0x00e7b39c, 0x00e4f6}, /* U+7CDC */ - {0x00e7b39d, 0x00f9f8}, /* U+7CDD [2000] */ - {0x00e7b39e, 0x00cab5}, /* U+7CDE */ - {0x00e7b39f, 0x00c1ec}, /* U+7CDF */ - {0x00e7b3a0, 0x00b9c7}, /* U+7CE0 */ - {0x00e7b3a2, 0x00e4f7}, /* U+7CE2 */ - {0x00e7b3a6, 0x8ff4a5}, /* U+7CE6 [2000] */ - {0x00e7b3a7, 0x00cec8}, /* U+7CE7 */ - {0x00e7b3ab, 0x8ff4a6}, /* U+7CEB [2000] */ - {0x00e7b3af, 0x00e4f9}, /* U+7CEF */ - {0x00e7b3b2, 0x00e4fa}, /* U+7CF2 */ - {0x00e7b3b4, 0x00e4fb}, /* U+7CF4 */ - {0x00e7b3b5, 0x8ff4a8}, /* U+7CF5 [2000] */ - {0x00e7b3b6, 0x00e4fc}, /* U+7CF6 */ - {0x00e7b3b8, 0x00bbe5}, /* U+7CF8 */ - {0x00e7b3ba, 0x00e4fd}, /* U+7CFA */ - {0x00e7b3bb, 0x00b7cf}, /* U+7CFB */ - {0x00e7b3be, 0x00b5ea}, /* U+7CFE */ - {0x00e7b480, 0x00b5aa}, /* U+7D00 */ - {0x00e7b482, 0x00e5a1}, /* U+7D02 */ - {0x00e7b483, 0x8ff4a9}, /* U+7D03 [2000] */ - {0x00e7b484, 0x00ccf3}, /* U+7D04 */ - {0x00e7b485, 0x00b9c8}, /* U+7D05 */ - {0x00e7b486, 0x00e4fe}, /* U+7D06 */ - {0x00e7b487, 0x00f9f9}, /* U+7D07 [2000] */ - {0x00e7b488, 0x00f9fa}, /* U+7D08 [2000] */ - {0x00e7b489, 0x8ff4aa}, /* U+7D09 [2000] */ - {0x00e7b48a, 0x00e5a4}, /* U+7D0A */ - {0x00e7b48b, 0x00cce6}, /* U+7D0B */ - {0x00e7b48d, 0x00c7bc}, /* U+7D0D */ - {0x00e7b490, 0x00c9b3}, /* U+7D10 */ - {0x00e7b492, 0x8ff4ac}, /* U+7D12 [2000] */ - {0x00e7b493, 0x00f9fb}, /* U+7D13 [2000] */ - {0x00e7b494, 0x00bde3}, /* U+7D14 */ - {0x00e7b495, 0x00e5a3}, /* U+7D15 */ - {0x00e7b497, 0x00bcd3}, /* U+7D17 */ - {0x00e7b498, 0x00b9c9}, /* U+7D18 */ - {0x00e7b499, 0x00bbe6}, /* U+7D19 */ - {0x00e7b49a, 0x00b5e9}, /* U+7D1A */ - {0x00e7b49b, 0x00cab6}, /* U+7D1B */ - {0x00e7b49c, 0x00e5a2}, /* U+7D1C */ - {0x00e7b49d, 0x00f9fc}, /* U+7D1D [2000] */ - {0x00e7b49e, 0x8ff4ad}, /* U+7D1E [2000] */ - {0x00e7b4a0, 0x00c1c7}, /* U+7D20 */ - {0x00e7b4a1, 0x00cbc2}, /* U+7D21 */ - {0x00e7b4a2, 0x00baf7}, /* U+7D22 */ - {0x00e7b4a3, 0x00f9fd}, /* U+7D23 [2000] */ - {0x00e7b4ab, 0x00bbe7}, /* U+7D2B */ - {0x00e7b4ac, 0x00c4dd}, /* U+7D2C */ - {0x00e7b4ae, 0x00e5a7}, /* U+7D2E */ - {0x00e7b4af, 0x00cedf}, /* U+7D2F */ - {0x00e7b4b0, 0x00bad9}, /* U+7D30 */ - {0x00e7b4b1, 0x00f9fe}, /* U+7D31 [2000] */ - {0x00e7b4b2, 0x00e5a8}, /* U+7D32 */ - {0x00e7b4b3, 0x00bfc2}, /* U+7D33 */ - {0x00e7b4b5, 0x00e5aa}, /* U+7D35 */ - {0x00e7b4b9, 0x00bed2}, /* U+7D39 */ - {0x00e7b4ba, 0x00bab0}, /* U+7D3A */ - {0x00e7b4bd, 0x8ff4b0}, /* U+7D3D [2000] */ - {0x00e7b4be, 0x8ff4b1}, /* U+7D3E [2000] */ - {0x00e7b4bf, 0x00e5a9}, /* U+7D3F */ - {0x00e7b580, 0x8ff4b2}, /* U+7D40 [2000] */ - {0x00e7b581, 0x00faa1}, /* U+7D41 [2000] */ - {0x00e7b582, 0x00bdaa}, /* U+7D42 */ - {0x00e7b583, 0x00b8be}, /* U+7D43 */ - {0x00e7b584, 0x00c1c8}, /* U+7D44 */ - {0x00e7b585, 0x00e5a5}, /* U+7D45 */ - {0x00e7b586, 0x00e5ab}, /* U+7D46 */ - {0x00e7b587, 0x8ff4b3}, /* U+7D47 [2000] */ - {0x00e7b588, 0x00faa2}, /* U+7D48 [2000] */ - {0x00e7b58b, 0x00e5a6}, /* U+7D4B */ - {0x00e7b58c, 0x00b7d0}, /* U+7D4C */ - {0x00e7b58e, 0x00e5ae}, /* U+7D4E */ - {0x00e7b58f, 0x00e5b2}, /* U+7D4F */ - {0x00e7b590, 0x00b7eb}, /* U+7D50 */ - {0x00e7b593, 0x00faa3}, /* U+7D53 [2000] */ - {0x00e7b596, 0x00e5ad}, /* U+7D56 */ - {0x00e7b599, 0x8ff4b7}, /* U+7D59 [2000] */ - {0x00e7b59a, 0x8ff4b8}, /* U+7D5A [2000] */ - {0x00e7b59b, 0x00e5b6}, /* U+7D5B */ - {0x00e7b59c, 0x00faa4}, /* U+7D5C [2000] */ - {0x00e7b59e, 0x00b9ca}, /* U+7D5E */ - {0x00e7b5a1, 0x00cded}, /* U+7D61 */ - {0x00e7b5a2, 0x00b0bc}, /* U+7D62 */ - {0x00e7b5a3, 0x00e5b3}, /* U+7D63 */ - {0x00e7b5a6, 0x00b5eb}, /* U+7D66 */ - {0x00e7b5a8, 0x00e5b0}, /* U+7D68 */ - {0x00e7b5aa, 0x8ff4b9}, /* U+7D6A [2000] */ - {0x00e7b5ae, 0x00e5b1}, /* U+7D6E */ - {0x00e7b5b0, 0x8ff4ba}, /* U+7D70 [2000] */ - {0x00e7b5b1, 0x00c5fd}, /* U+7D71 */ - {0x00e7b5b2, 0x00e5af}, /* U+7D72 */ - {0x00e7b5b3, 0x00e5ac}, /* U+7D73 */ - {0x00e7b5b5, 0x00b3a8}, /* U+7D75 */ - {0x00e7b5b6, 0x00c0e4}, /* U+7D76 */ - {0x00e7b5b9, 0x00b8a8}, /* U+7D79 */ - {0x00e7b5ba, 0x00faa5}, /* U+7D7A [2000] */ - {0x00e7b5bd, 0x00e5b8}, /* U+7D7D */ - {0x00e7b5bf, 0x8ff4bc}, /* U+7D7F [2000] */ - {0x00e7b683, 0x00faa6}, /* U+7D83 [2000] */ - {0x00e7b686, 0x8ff4be}, /* U+7D86 [2000] */ - {0x00e7b688, 0x8ff4bf}, /* U+7D88 [2000] */ - {0x00e7b689, 0x00e5b5}, /* U+7D89 */ - {0x00e7b68b, 0x00faa7}, /* U+7D8B [2000] */ - {0x00e7b68c, 0x8ff4c0}, /* U+7D8C [2000] */ - {0x00e7b68f, 0x00e5b7}, /* U+7D8F */ - {0x00e7b693, 0x00e5b4}, /* U+7D93 */ - {0x00e7b697, 0x8ff4c1}, /* U+7D97 [2000] */ - {0x00e7b699, 0x00b7d1}, /* U+7D99 */ - {0x00e7b69a, 0x00c2b3}, /* U+7D9A */ - {0x00e7b69b, 0x00e5b9}, /* U+7D9B */ - {0x00e7b69c, 0x00c1ee}, /* U+7D9C */ - {0x00e7b69d, 0x8ff4c3}, /* U+7D9D [2000] */ - {0x00e7b69f, 0x00e5c6}, /* U+7D9F */ - {0x00e7b6a0, 0x00faa8}, /* U+7DA0 [2000] */ - {0x00e7b6a2, 0x00e5c2}, /* U+7DA2 */ - {0x00e7b6a3, 0x00e5bc}, /* U+7DA3 */ - {0x00e7b6a6, 0x00faa9}, /* U+7DA6 [2000] */ - {0x00e7b6a7, 0x8ff4c4}, /* U+7DA7 [2000] */ - {0x00e7b6aa, 0x8ff4c5}, /* U+7DAA [2000] */ - {0x00e7b6ab, 0x00e5c0}, /* U+7DAB */ - {0x00e7b6ac, 0x00bcfa}, /* U+7DAC */ - {0x00e7b6ad, 0x00b0dd}, /* U+7DAD */ - {0x00e7b6ae, 0x00e5bb}, /* U+7DAE */ - {0x00e7b6af, 0x00e5c3}, /* U+7DAF */ - {0x00e7b6b0, 0x00e5c7}, /* U+7DB0 */ - {0x00e7b6b1, 0x00b9cb}, /* U+7DB1 */ - {0x00e7b6b2, 0x00ccd6}, /* U+7DB2 */ - {0x00e7b6b4, 0x00c4d6}, /* U+7DB4 */ - {0x00e7b6b5, 0x00e5bd}, /* U+7DB5 */ - {0x00e7b6b6, 0x8ff4c6}, /* U+7DB6 [2000] */ - {0x00e7b6b7, 0x8ff4c7}, /* U+7DB7 [2000] */ - {0x00e7b6b8, 0x00e5c5}, /* U+7DB8 */ - {0x00e7b6ba, 0x00e5ba}, /* U+7DBA */ - {0x00e7b6bb, 0x00c3be}, /* U+7DBB */ - {0x00e7b6bd, 0x00e5bf}, /* U+7DBD */ - {0x00e7b6be, 0x00b0bd}, /* U+7DBE */ - {0x00e7b6bf, 0x00ccca}, /* U+7DBF */ - {0x00e7b780, 0x8ff4c8}, /* U+7DC0 [2000] */ - {0x00e7b782, 0x00faaa}, /* U+7DC2 [2000] */ - {0x00e7b787, 0x00e5be}, /* U+7DC7 */ - {0x00e7b78a, 0x00b6db}, /* U+7DCA */ - {0x00e7b78b, 0x00c8ec}, /* U+7DCB */ - {0x00e7b78c, 0x00faab}, /* U+7DCC [2000] */ - {0x00e7b78f, 0x00c1ed}, /* U+7DCF */ - {0x00e7b791, 0x00ced0}, /* U+7DD1 */ - {0x00e7b792, 0x00bdef}, /* U+7DD2 */ - {0x00e7b795, 0x00e5ee}, /* U+7DD5 */ - {0x00e7b796, 0x00faac}, /* U+7DD6 [2000] */ - {0x00e7b797, 0x8ff4c9}, /* U+7DD7 [2000] */ - {0x00e7b798, 0x00e5c8}, /* U+7DD8 */ - {0x00e7b799, 0x8ff4ca}, /* U+7DD9 [2000] */ - {0x00e7b79a, 0x00c0fe}, /* U+7DDA */ - {0x00e7b79c, 0x00e5c4}, /* U+7DDC */ - {0x00e7b79d, 0x00e5c9}, /* U+7DDD */ - {0x00e7b79e, 0x00e5cb}, /* U+7DDE */ - {0x00e7b7a0, 0x00c4f9}, /* U+7DE0 */ - {0x00e7b7a1, 0x00e5ce}, /* U+7DE1 */ - {0x00e7b7a3, 0x00faad}, /* U+7DE3 [2000] */ - {0x00e7b7a4, 0x00e5ca}, /* U+7DE4 */ - {0x00e7b7a6, 0x8ff4cb}, /* U+7DE6 [2000] */ - {0x00e7b7a8, 0x00cad4}, /* U+7DE8 */ - {0x00e7b7a9, 0x00b4cb}, /* U+7DE9 */ - {0x00e7b7ac, 0x00cccb}, /* U+7DEC */ - {0x00e7b7af, 0x00b0de}, /* U+7DEF */ - {0x00e7b7b1, 0x8ff4cc}, /* U+7DF1 [2000] */ - {0x00e7b7b2, 0x00e5cd}, /* U+7DF2 */ - {0x00e7b7b4, 0x00cefd}, /* U+7DF4 */ - {0x00e7b7b9, 0x8ff4cd}, /* U+7DF9 [2000] */ - {0x00e7b7bb, 0x00e5cc}, /* U+7DFB */ - {0x00e7b881, 0x00b1ef}, /* U+7E01 */ - {0x00e7b884, 0x00c6ec}, /* U+7E04 */ - {0x00e7b885, 0x00e5cf}, /* U+7E05 */ - {0x00e7b888, 0x00fab0}, /* U+7E08 [2000] */ - {0x00e7b889, 0x00e5d6}, /* U+7E09 */ - {0x00e7b88a, 0x00e5d0}, /* U+7E0A */ - {0x00e7b88b, 0x00e5d7}, /* U+7E0B */ - {0x00e7b890, 0x8ff4d1}, /* U+7E10 [2000] */ - {0x00e7b891, 0x00fab1}, /* U+7E11 [2000] */ - {0x00e7b892, 0x00e5d3}, /* U+7E12 */ - {0x00e7b895, 0x00fab2}, /* U+7E15 [2000] */ - {0x00e7b897, 0x8ff4d2}, /* U+7E17 [2000] */ - {0x00e7b89b, 0x00c7fb}, /* U+7E1B */ - {0x00e7b89d, 0x8ff4d3}, /* U+7E1D [2000] */ - {0x00e7b89e, 0x00bcca}, /* U+7E1E */ - {0x00e7b89f, 0x00e5d5}, /* U+7E1F */ - {0x00e7b8a0, 0x8ff4d4}, /* U+7E20 [2000] */ - {0x00e7b8a1, 0x00e5d2}, /* U+7E21 */ - {0x00e7b8a2, 0x00e5d8}, /* U+7E22 */ - {0x00e7b8a3, 0x00e5d1}, /* U+7E23 */ - {0x00e7b8a6, 0x00bdc4}, /* U+7E26 */ - {0x00e7b8a7, 0x8ff4d5}, /* U+7E27 [2000] */ - {0x00e7b8a8, 0x00faaf}, /* U+7E28 [2000] */ - {0x00e7b8ab, 0x00cba5}, /* U+7E2B */ - {0x00e7b8ac, 0x8ff4d6}, /* U+7E2C [2000] */ - {0x00e7b8ae, 0x00bdcc}, /* U+7E2E */ - {0x00e7b8b1, 0x00e5d4}, /* U+7E31 */ - {0x00e7b8b2, 0x00e5e0}, /* U+7E32 */ - {0x00e7b8b5, 0x00e5dc}, /* U+7E35 */ - {0x00e7b8b7, 0x00e5df}, /* U+7E37 */ - {0x00e7b8b9, 0x00e5dd}, /* U+7E39 */ - {0x00e7b8ba, 0x00e5e1}, /* U+7E3A */ - {0x00e7b8bb, 0x00e5db}, /* U+7E3B */ - {0x00e7b8bd, 0x00e5c1}, /* U+7E3D */ - {0x00e7b8be, 0x00c0d3}, /* U+7E3E */ - {0x00e7b981, 0x00c8cb}, /* U+7E41 */ - {0x00e7b983, 0x00e5de}, /* U+7E43 */ - {0x00e7b985, 0x8ff4d7}, /* U+7E45 [2000] */ - {0x00e7b986, 0x00e5d9}, /* U+7E46 */ - {0x00e7b987, 0x00fab4}, /* U+7E47 [2000] */ - {0x00e7b98a, 0x00c1a1}, /* U+7E4A */ - {0x00e7b98b, 0x00b7d2}, /* U+7E4B */ - {0x00e7b98d, 0x00bdab}, /* U+7E4D */ - {0x00e7b992, 0x00fab5}, /* U+7E52 [2000] */ - {0x00e7b994, 0x00bfa5}, /* U+7E54 */ - {0x00e7b995, 0x00c1b6}, /* U+7E55 */ - {0x00e7b996, 0x00e5e4}, /* U+7E56 */ - {0x00e7b999, 0x00e5e6}, /* U+7E59 */ - {0x00e7b99a, 0x00e5e7}, /* U+7E5A */ - {0x00e7b99d, 0x00e5e3}, /* U+7E5D */ - {0x00e7b99e, 0x00e5e5}, /* U+7E5E */ - {0x00e7b9a1, 0x00fab6}, /* U+7E61 [2000] */ - {0x00e7b9a6, 0x00e5da}, /* U+7E66 */ - {0x00e7b9a7, 0x00e5e2}, /* U+7E67 */ - {0x00e7b9a9, 0x00e5ea}, /* U+7E69 */ - {0x00e7b9aa, 0x00e5e9}, /* U+7E6A */ - {0x00e7b9ab, 0x00fefe}, /* U+7E6B [2004] */ - {0x00e7b9ad, 0x00cbfa}, /* U+7E6D */ - {0x00e7b9b0, 0x00b7ab}, /* U+7E70 */ - {0x00e7b9b3, 0x8ff4d8}, /* U+7E73 [2000] */ - {0x00e7b9b5, 0x8ff4d9}, /* U+7E75 [2000] */ - {0x00e7b9b9, 0x00e5e8}, /* U+7E79 */ - {0x00e7b9bb, 0x00e5ec}, /* U+7E7B */ - {0x00e7b9bc, 0x00e5eb}, /* U+7E7C */ - {0x00e7b9bd, 0x00e5ef}, /* U+7E7D */ - {0x00e7b9be, 0x8ff4da}, /* U+7E7E [2000] */ - {0x00e7b9bf, 0x00e5f1}, /* U+7E7F */ - {0x00e7ba82, 0x00bbbc}, /* U+7E82 */ - {0x00e7ba83, 0x00e5ed}, /* U+7E83 */ - {0x00e7ba86, 0x8ff4db}, /* U+7E86 [2000] */ - {0x00e7ba87, 0x8ff4dc}, /* U+7E87 [2000] */ - {0x00e7ba88, 0x00e5f2}, /* U+7E88 */ - {0x00e7ba89, 0x00e5f3}, /* U+7E89 */ - {0x00e7ba8a, 0x00fab7}, /* U+7E8A [2000] */ - {0x00e7ba8c, 0x00e5f4}, /* U+7E8C */ - {0x00e7ba8d, 0x00fab8}, /* U+7E8D [2000] */ - {0x00e7ba8e, 0x00e5fa}, /* U+7E8E */ - {0x00e7ba8f, 0x00c5bb}, /* U+7E8F */ - {0x00e7ba90, 0x00e5f6}, /* U+7E90 */ - {0x00e7ba91, 0x8ff4de}, /* U+7E91 [2000] */ - {0x00e7ba92, 0x00e5f5}, /* U+7E92 */ - {0x00e7ba93, 0x00e5f7}, /* U+7E93 */ - {0x00e7ba94, 0x00e5f8}, /* U+7E94 */ - {0x00e7ba96, 0x00e5f9}, /* U+7E96 */ - {0x00e7ba98, 0x8ff4df}, /* U+7E98 [2000] */ - {0x00e7ba9a, 0x8ff4e0}, /* U+7E9A [2000] */ - {0x00e7ba9b, 0x00e5fb}, /* U+7E9B */ - {0x00e7ba9c, 0x00e5fc}, /* U+7E9C */ - {0x00e7bcb6, 0x00b4cc}, /* U+7F36 */ - {0x00e7bcb8, 0x00e5fd}, /* U+7F38 */ - {0x00e7bcba, 0x00e5fe}, /* U+7F3A */ - {0x00e7bcbb, 0x8ff4e3}, /* U+7F3B [2000] */ - {0x00e7bcbc, 0x8ff4e2}, /* U+7F3C [2000] */ - {0x00e7bcbe, 0x8ff4e4}, /* U+7F3E [2000] */ - {0x00e7bd83, 0x8ff4e5}, /* U+7F43 [2000] */ - {0x00e7bd84, 0x8ff4e6}, /* U+7F44 [2000] */ - {0x00e7bd85, 0x00e6a1}, /* U+7F45 */ - {0x00e7bd87, 0x00fab9}, /* U+7F47 [2000] */ - {0x00e7bd8c, 0x00e6a2}, /* U+7F4C */ - {0x00e7bd8d, 0x00e6a3}, /* U+7F4D */ - {0x00e7bd8e, 0x00e6a4}, /* U+7F4E */ - {0x00e7bd8f, 0x8ff4e7}, /* U+7F4F [2000] */ - {0x00e7bd90, 0x00e6a5}, /* U+7F50 */ - {0x00e7bd91, 0x00e6a6}, /* U+7F51 */ - {0x00e7bd92, 0x8ff4ea}, /* U+7F52 [2000] */ - {0x00e7bd94, 0x00e6a8}, /* U+7F54 */ - {0x00e7bd95, 0x00e6a7}, /* U+7F55 */ - {0x00e7bd98, 0x00e6a9}, /* U+7F58 */ - {0x00e7bd9f, 0x00e6aa}, /* U+7F5F */ - {0x00e7bda0, 0x00e6ab}, /* U+7F60 */ - {0x00e7bda1, 0x8ff4ec}, /* U+7F61 [2000] */ - {0x00e7bda3, 0x8ff4ed}, /* U+7F63 [2000] */ - {0x00e7bda4, 0x8ff4ee}, /* U+7F64 [2000] */ - {0x00e7bda7, 0x00e6ae}, /* U+7F67 */ - {0x00e7bda8, 0x00e6ac}, /* U+7F68 */ - {0x00e7bda9, 0x00e6ad}, /* U+7F69 */ - {0x00e7bdaa, 0x00bae1}, /* U+7F6A */ - {0x00e7bdab, 0x00b7d3}, /* U+7F6B */ - {0x00e7bdad, 0x8ff4ef}, /* U+7F6D [2000] */ - {0x00e7bdae, 0x00c3d6}, /* U+7F6E */ - {0x00e7bdb0, 0x00c8b3}, /* U+7F70 */ - {0x00e7bdb2, 0x00bdf0}, /* U+7F72 */ - {0x00e7bdb5, 0x00c7cd}, /* U+7F75 */ - {0x00e7bdb7, 0x00c8ed}, /* U+7F77 */ - {0x00e7bdb8, 0x00e6af}, /* U+7F78 */ - {0x00e7bdb9, 0x00d8ed}, /* U+7F79 */ - {0x00e7bdbd, 0x8ff4f0}, /* U+7F7D [2000] */ - {0x00e7bdbe, 0x8ff4f1}, /* U+7F7E [2000] */ - {0x00e7be82, 0x00e6b0}, /* U+7F82 */ - {0x00e7be83, 0x00e6b2}, /* U+7F83 */ - {0x00e7be85, 0x00cde5}, /* U+7F85 */ - {0x00e7be86, 0x00e6b1}, /* U+7F86 */ - {0x00e7be87, 0x00e6b4}, /* U+7F87 */ - {0x00e7be88, 0x00e6b3}, /* U+7F88 */ - {0x00e7be8a, 0x00cdd3}, /* U+7F8A */ - {0x00e7be8c, 0x00e6b5}, /* U+7F8C */ - {0x00e7be8e, 0x00c8fe}, /* U+7F8E */ - {0x00e7be90, 0x8ff4f3}, /* U+7F90 [2000] */ - {0x00e7be91, 0x00fabb}, /* U+7F91 [2000] */ - {0x00e7be94, 0x00e6b6}, /* U+7F94 */ - {0x00e7be96, 0x8ff4f6}, /* U+7F96 [2000] */ - {0x00e7be97, 0x00fabc}, /* U+7F97 [2000] */ - {0x00e7be9a, 0x00e6b9}, /* U+7F9A */ - {0x00e7be9c, 0x8ff4f7}, /* U+7F9C [2000] */ - {0x00e7be9d, 0x00e6b8}, /* U+7F9D */ - {0x00e7be9e, 0x00e6b7}, /* U+7F9E */ - {0x00e7bea3, 0x00e6ba}, /* U+7FA3 */ - {0x00e7bea4, 0x00b7b2}, /* U+7FA4 */ - {0x00e7bea8, 0x00c1a2}, /* U+7FA8 */ - {0x00e7bea9, 0x00b5c1}, /* U+7FA9 */ - {0x00e7bead, 0x8ff4f8}, /* U+7FAD [2000] */ - {0x00e7beae, 0x00e6be}, /* U+7FAE */ - {0x00e7beaf, 0x00e6bb}, /* U+7FAF */ - {0x00e7beb2, 0x00e6bc}, /* U+7FB2 */ - {0x00e7beb6, 0x00e6bf}, /* U+7FB6 */ - {0x00e7beb8, 0x00e6c0}, /* U+7FB8 */ - {0x00e7beb9, 0x00e6bd}, /* U+7FB9 */ - {0x00e7bebd, 0x00b1a9}, /* U+7FBD */ - {0x00e7bebf, 0x00fabd}, /* U+7FBF [2000] */ - {0x00e7bf81, 0x00b2a7}, /* U+7FC1 */ - {0x00e7bf83, 0x8ff4fa}, /* U+7FC3 [2000] */ - {0x00e7bf85, 0x00e6c2}, /* U+7FC5 */ - {0x00e7bf86, 0x00e6c3}, /* U+7FC6 */ - {0x00e7bf8a, 0x00e6c4}, /* U+7FCA */ - {0x00e7bf8c, 0x00cde2}, /* U+7FCC */ - {0x00e7bf8e, 0x00fabe}, /* U+7FCE [2000] */ - {0x00e7bf8f, 0x8ff4fb}, /* U+7FCF [2000] */ - {0x00e7bf92, 0x00bdac}, /* U+7FD2 */ - {0x00e7bf94, 0x00e6c6}, /* U+7FD4 */ - {0x00e7bf95, 0x00e6c5}, /* U+7FD5 */ - {0x00e7bf9b, 0x00fabf}, /* U+7FDB [2000] */ - {0x00e7bf9f, 0x00fac0}, /* U+7FDF [2000] */ - {0x00e7bfa0, 0x00bfe9}, /* U+7FE0 */ - {0x00e7bfa1, 0x00e6c7}, /* U+7FE1 */ - {0x00e7bfa3, 0x8ff4fc}, /* U+7FE3 [2000] */ - {0x00e7bfa5, 0x8ff4fd}, /* U+7FE5 [2000] */ - {0x00e7bfa6, 0x00e6c8}, /* U+7FE6 */ - {0x00e7bfa9, 0x00e6c9}, /* U+7FE9 */ - {0x00e7bfab, 0x00b4e5}, /* U+7FEB */ - {0x00e7bfac, 0x00fac1}, /* U+7FEC [2000] */ - {0x00e7bfae, 0x00fac2}, /* U+7FEE [2000] */ - {0x00e7bfaf, 0x8ff4fe}, /* U+7FEF [2000] */ - {0x00e7bfb0, 0x00b4cd}, /* U+7FF0 */ - {0x00e7bfb2, 0x8ff5a1}, /* U+7FF2 [2000] */ - {0x00e7bfb3, 0x00e6ca}, /* U+7FF3 */ - {0x00e7bfb9, 0x00e6cb}, /* U+7FF9 */ - {0x00e7bfba, 0x00fac3}, /* U+7FFA [2000] */ - {0x00e7bfbb, 0x00cbdd}, /* U+7FFB */ - {0x00e7bfbc, 0x00cde3}, /* U+7FFC */ - {0x00e88080, 0x00cdd4}, /* U+8000 */ - {0x00e88081, 0x00cfb7}, /* U+8001 */ - {0x00e88082, 0x8ff5a2}, /* U+8002 [2000] */ - {0x00e88083, 0x00b9cd}, /* U+8003 */ - {0x00e88084, 0x00e6ce}, /* U+8004 */ - {0x00e88085, 0x00bcd4}, /* U+8005 */ - {0x00e88086, 0x00e6cd}, /* U+8006 */ - {0x00e88088, 0x8ff5a4}, /* U+8008 [2000] */ - {0x00e8808a, 0x8ff5a3}, /* U+800A [2000] */ - {0x00e8808b, 0x00e6cf}, /* U+800B */ - {0x00e8808c, 0x00bca9}, /* U+800C */ - {0x00e8808e, 0x8ff5a5}, /* U+800E [2000] */ - {0x00e88090, 0x00c2d1}, /* U+8010 */ - {0x00e88091, 0x8ff5a6}, /* U+8011 [2000] */ - {0x00e88092, 0x00e6d0}, /* U+8012 */ - {0x00e88094, 0x00fac5}, /* U+8014 [2000] */ - {0x00e88095, 0x00b9cc}, /* U+8015 */ - {0x00e88096, 0x8ff5a7}, /* U+8016 [2000] */ - {0x00e88097, 0x00ccd7}, /* U+8017 */ - {0x00e88098, 0x00e6d1}, /* U+8018 */ - {0x00e88099, 0x00e6d2}, /* U+8019 */ - {0x00e8809c, 0x00e6d3}, /* U+801C */ - {0x00e880a1, 0x00e6d4}, /* U+8021 */ - {0x00e880a4, 0x8ff5a8}, /* U+8024 [2000] */ - {0x00e880a6, 0x00fac6}, /* U+8026 [2000] */ - {0x00e880a8, 0x00e6d5}, /* U+8028 */ - {0x00e880ac, 0x8ff5a9}, /* U+802C [2000] */ - {0x00e880b0, 0x8ff5aa}, /* U+8030 [2000] */ - {0x00e880b3, 0x00bcaa}, /* U+8033 */ - {0x00e880b5, 0x00fac7}, /* U+8035 [2000] */ - {0x00e880b6, 0x00cced}, /* U+8036 */ - {0x00e880b7, 0x00fac8}, /* U+8037 [2000] */ - {0x00e880bb, 0x00e6d7}, /* U+803B */ - {0x00e880bc, 0x00fac9}, /* U+803C [2000] */ - {0x00e880bd, 0x00c3bf}, /* U+803D */ - {0x00e880bf, 0x00e6d6}, /* U+803F */ - {0x00e88183, 0x8ff5ab}, /* U+8043 [2000] */ - {0x00e88186, 0x00e6d9}, /* U+8046 */ - {0x00e8818a, 0x00e6d8}, /* U+804A */ - {0x00e88192, 0x00e6da}, /* U+8052 */ - {0x00e88196, 0x00c0bb}, /* U+8056 */ - {0x00e88198, 0x00e6db}, /* U+8058 */ - {0x00e8819a, 0x00e6dc}, /* U+805A */ - {0x00e8819e, 0x00cab9}, /* U+805E */ - {0x00e8819f, 0x00e6dd}, /* U+805F */ - {0x00e881a1, 0x00c1ef}, /* U+8061 */ - {0x00e881a2, 0x00e6de}, /* U+8062 */ - {0x00e881a6, 0x8ff5ac}, /* U+8066 [2000] */ - {0x00e881a8, 0x00e6df}, /* U+8068 */ - {0x00e881af, 0x00cefe}, /* U+806F */ - {0x00e881b0, 0x00e6e2}, /* U+8070 */ - {0x00e881b1, 0x8ff5ad}, /* U+8071 [2000] */ - {0x00e881b2, 0x00e6e1}, /* U+8072 */ - {0x00e881b3, 0x00e6e0}, /* U+8073 */ - {0x00e881b4, 0x00c4b0}, /* U+8074 */ - {0x00e881b5, 0x8ff5ae}, /* U+8075 [2000] */ - {0x00e881b6, 0x00e6e3}, /* U+8076 */ - {0x00e881b7, 0x00bfa6}, /* U+8077 */ - {0x00e881b9, 0x00e6e4}, /* U+8079 */ - {0x00e881bb, 0x8ff5af}, /* U+807B [2000] */ - {0x00e881bd, 0x00e6e5}, /* U+807D */ - {0x00e881be, 0x00cfb8}, /* U+807E */ - {0x00e881bf, 0x00e6e6}, /* U+807F */ - {0x00e88284, 0x00e6e7}, /* U+8084 */ - {0x00e88285, 0x00e6e9}, /* U+8085 */ - {0x00e88286, 0x00e6e8}, /* U+8086 */ - {0x00e88287, 0x00c8a5}, /* U+8087 */ - {0x00e88289, 0x00c6f9}, /* U+8089 */ - {0x00e8828b, 0x00cfbe}, /* U+808B */ - {0x00e8828c, 0x00c8a9}, /* U+808C */ - {0x00e88293, 0x00e6eb}, /* U+8093 */ - {0x00e88296, 0x00bed3}, /* U+8096 */ - {0x00e88298, 0x00c9aa}, /* U+8098 */ - {0x00e88299, 0x8ff5b0}, /* U+8099 [2000] */ - {0x00e8829a, 0x00e6ec}, /* U+809A */ - {0x00e8829b, 0x00e6ea}, /* U+809B */ - {0x00e8829c, 0x8ff5b1}, /* U+809C [2000] */ - {0x00e8829d, 0x00b4ce}, /* U+809D */ - {0x00e882a1, 0x00b8d4}, /* U+80A1 */ - {0x00e882a2, 0x00bbe8}, /* U+80A2 */ - {0x00e882a4, 0x8ff5b2}, /* U+80A4 [2000] */ - {0x00e882a5, 0x00c8ee}, /* U+80A5 */ - {0x00e882a7, 0x8ff5b3}, /* U+80A7 [2000] */ - {0x00e882a9, 0x00b8aa}, /* U+80A9 */ - {0x00e882aa, 0x00cbc3}, /* U+80AA */ - {0x00e882ac, 0x00e6ef}, /* U+80AC */ - {0x00e882ad, 0x00e6ed}, /* U+80AD */ - {0x00e882af, 0x00b9ce}, /* U+80AF */ - {0x00e882b1, 0x00b9cf}, /* U+80B1 */ - {0x00e882b2, 0x00b0e9}, /* U+80B2 */ - {0x00e882b4, 0x00bae8}, /* U+80B4 */ - {0x00e882b8, 0x8ff5b4}, /* U+80B8 [2000] */ - {0x00e882ba, 0x00c7d9}, /* U+80BA */ - {0x00e88383, 0x00b0df}, /* U+80C3 */ - {0x00e88384, 0x00e6f4}, /* U+80C4 */ - {0x00e88385, 0x8ff5b6}, /* U+80C5 [2000] */ - {0x00e88386, 0x00c3c0}, /* U+80C6 */ - {0x00e8838a, 0x00faca}, /* U+80CA [2000] */ - {0x00e8838c, 0x00c7d8}, /* U+80CC */ - {0x00e8838e, 0x00c2db}, /* U+80CE */ - {0x00e88395, 0x8ff5b7}, /* U+80D5 [2000] */ - {0x00e88396, 0x00e6f6}, /* U+80D6 */ - {0x00e88397, 0x00facb}, /* U+80D7 [2000] */ - {0x00e88398, 0x8ff5b8}, /* U+80D8 [2000] */ - {0x00e88399, 0x00e6f2}, /* U+80D9 */ - {0x00e8839a, 0x00e6f5}, /* U+80DA */ - {0x00e8839b, 0x00e6f0}, /* U+80DB */ - {0x00e8839d, 0x00e6f3}, /* U+80DD */ - {0x00e8839e, 0x00cba6}, /* U+80DE */ - {0x00e883a0, 0x00facc}, /* U+80E0 [2000] */ - {0x00e883a1, 0x00b8d5}, /* U+80E1 */ - {0x00e883a4, 0x00b0fd}, /* U+80E4 */ - {0x00e883a5, 0x00e6f1}, /* U+80E5 */ - {0x00e883a6, 0x8ff5b9}, /* U+80E6 [2000] */ - {0x00e883af, 0x00e6f8}, /* U+80EF */ - {0x00e883b1, 0x00e6f9}, /* U+80F1 */ - {0x00e883b3, 0x00facd}, /* U+80F3 [2000] */ - {0x00e883b4, 0x00c6b9}, /* U+80F4 */ - {0x00e883b5, 0x8ff5bc}, /* U+80F5 [2000] */ - {0x00e883b8, 0x00b6bb}, /* U+80F8 */ - {0x00e883bb, 0x8ff5bd}, /* U+80FB [2000] */ - {0x00e883bc, 0x00e7a6}, /* U+80FC */ - {0x00e883bd, 0x00c7bd}, /* U+80FD */ - {0x00e88482, 0x00bbe9}, /* U+8102 */ - {0x00e88485, 0x00b6bc}, /* U+8105 */ - {0x00e88486, 0x00c0c8}, /* U+8106 */ - {0x00e88487, 0x00cfc6}, /* U+8107 */ - {0x00e88488, 0x00ccae}, /* U+8108 */ - {0x00e88489, 0x00e6f7}, /* U+8109 */ - {0x00e8848a, 0x00c0d4}, /* U+810A */ - {0x00e8848d, 0x8ff5bb}, /* U+810D [2000] */ - {0x00e88496, 0x8ff5c0}, /* U+8116 [2000] */ - {0x00e88498, 0x00face}, /* U+8118 [2000] */ - {0x00e8849a, 0x00b5d3}, /* U+811A */ - {0x00e8849b, 0x00e6fa}, /* U+811B */ - {0x00e8849e, 0x8ff5c1}, /* U+811E [2000] */ - {0x00e884a3, 0x00e6fc}, /* U+8123 */ - {0x00e884a4, 0x8ff5c3}, /* U+8124 [2000] */ - {0x00e884a7, 0x8ff5c4}, /* U+8127 [2000] */ - {0x00e884a9, 0x00e6fb}, /* U+8129 */ - {0x00e884ac, 0x8ff5c5}, /* U+812C [2000] */ - {0x00e884af, 0x00e6fd}, /* U+812F */ - {0x00e884b1, 0x00c3a6}, /* U+8131 */ - {0x00e884b3, 0x00c7be}, /* U+8133 */ - {0x00e884b5, 0x8ff5bf}, /* U+8135 [2000] */ - {0x00e884b9, 0x00c4b1}, /* U+8139 */ - {0x00e884bd, 0x8ff5c7}, /* U+813D [2000] */ - {0x00e884be, 0x00e7a3}, /* U+813E */ - {0x00e88586, 0x00e7a2}, /* U+8146 */ - {0x00e8858a, 0x00facf}, /* U+814A [2000] */ - {0x00e8858b, 0x00e6fe}, /* U+814B */ - {0x00e8858e, 0x00bfd5}, /* U+814E */ - {0x00e88590, 0x00c9e5}, /* U+8150 */ - {0x00e88591, 0x00e7a5}, /* U+8151 */ - {0x00e88593, 0x00e7a4}, /* U+8153 */ - {0x00e88594, 0x00b9d0}, /* U+8154 */ - {0x00e88595, 0x00cfd3}, /* U+8155 */ - {0x00e8859f, 0x00e7b5}, /* U+815F */ - {0x00e885a0, 0x00fad0}, /* U+8160 [2000] */ - {0x00e885a5, 0x00e7a9}, /* U+8165 */ - {0x00e885a6, 0x00e7aa}, /* U+8166 */ - {0x00e885a7, 0x00fad1}, /* U+8167 [2000] */ - {0x00e885a8, 0x00fad2}, /* U+8168 [2000] */ - {0x00e885a9, 0x8ff5c9}, /* U+8169 [2000] */ - {0x00e885ab, 0x00bcf0}, /* U+816B */ - {0x00e885ad, 0x00fad3}, /* U+816D [2000] */ - {0x00e885ae, 0x00e7a8}, /* U+816E */ - {0x00e885b0, 0x00b9f8}, /* U+8170 */ - {0x00e885b1, 0x00e7a7}, /* U+8171 */ - {0x00e885b4, 0x00e7ab}, /* U+8174 */ - {0x00e885b8, 0x00c4b2}, /* U+8178 */ - {0x00e885b9, 0x00caa2}, /* U+8179 */ - {0x00e885ba, 0x00c1a3}, /* U+817A */ - {0x00e885bf, 0x00c2dc}, /* U+817F */ - {0x00e88680, 0x00e7af}, /* U+8180 */ - {0x00e88681, 0x8ff5cb}, /* U+8181 [2000] */ - {0x00e88682, 0x00e7b0}, /* U+8182 */ - {0x00e88683, 0x00e7ac}, /* U+8183 */ - {0x00e88684, 0x8ff5cd}, /* U+8184 [2000] */ - {0x00e88685, 0x8ff5ce}, /* U+8185 [2000] */ - {0x00e88688, 0x00e7ad}, /* U+8188 */ - {0x00e8868a, 0x00e7ae}, /* U+818A */ - {0x00e8868f, 0x00b9d1}, /* U+818F */ - {0x00e88693, 0x00e7b6}, /* U+8193 */ - {0x00e88695, 0x00e7b2}, /* U+8195 */ - {0x00e88698, 0x8ff5d0}, /* U+8198 [2000] */ - {0x00e8869a, 0x00c9e6}, /* U+819A */ - {0x00e8869c, 0x00cbec}, /* U+819C */ - {0x00e8869d, 0x00c9a8}, /* U+819D */ - {0x00e886a0, 0x00e7b1}, /* U+81A0 */ - {0x00e886a3, 0x00e7b4}, /* U+81A3 */ - {0x00e886a4, 0x00e7b3}, /* U+81A4 */ - {0x00e886a8, 0x00cbc4}, /* U+81A8 */ - {0x00e886a9, 0x00e7b7}, /* U+81A9 */ - {0x00e886b0, 0x00e7b8}, /* U+81B0 */ - {0x00e886b2, 0x8ff5d1}, /* U+81B2 [2000] */ - {0x00e886b3, 0x00c1b7}, /* U+81B3 */ - {0x00e886b5, 0x00e7b9}, /* U+81B5 */ - {0x00e886b8, 0x00e7bb}, /* U+81B8 */ - {0x00e886ba, 0x00e7bf}, /* U+81BA */ - {0x00e886bb, 0x00fad4}, /* U+81BB [2000] */ - {0x00e886bd, 0x00e7bc}, /* U+81BD */ - {0x00e886be, 0x00e7ba}, /* U+81BE */ - {0x00e886bf, 0x00c7bf}, /* U+81BF */ - {0x00e88780, 0x00e7bd}, /* U+81C0 */ - {0x00e88781, 0x8ff5d2}, /* U+81C1 [2000] */ - {0x00e88782, 0x00e7be}, /* U+81C2 */ - {0x00e88783, 0x8ff5d3}, /* U+81C3 [2000] */ - {0x00e88786, 0x00b2b2}, /* U+81C6 */ - {0x00e88788, 0x00e7c5}, /* U+81C8 */ - {0x00e88789, 0x00e7c0}, /* U+81C9 */ - {0x00e8878a, 0x00fad5}, /* U+81CA [2000] */ - {0x00e8878d, 0x00e7c1}, /* U+81CD */ - {0x00e8878f, 0x00fad6}, /* U+81CF [2000] */ - {0x00e88791, 0x00e7c2}, /* U+81D1 */ - {0x00e88793, 0x00c2a1}, /* U+81D3 */ - {0x00e88796, 0x8ff5d4}, /* U+81D6 [2000] */ - {0x00e88797, 0x00fad7}, /* U+81D7 [2000] */ - {0x00e88798, 0x00e7c4}, /* U+81D8 */ - {0x00e88799, 0x00e7c3}, /* U+81D9 */ - {0x00e8879a, 0x00e7c6}, /* U+81DA */ - {0x00e8879b, 0x8ff5d5}, /* U+81DB [2000] */ - {0x00e8879f, 0x00e7c7}, /* U+81DF */ - {0x00e887a0, 0x00e7c8}, /* U+81E0 */ - {0x00e887a3, 0x00bfc3}, /* U+81E3 */ - {0x00e887a4, 0x8ff5d7}, /* U+81E4 [2000] */ - {0x00e887a5, 0x00b2e9}, /* U+81E5 */ - {0x00e887a7, 0x00e7c9}, /* U+81E7 */ - {0x00e887a8, 0x00ced7}, /* U+81E8 */ - {0x00e887aa, 0x00bcab}, /* U+81EA */ - {0x00e887ac, 0x8ff5d9}, /* U+81EC [2000] */ - {0x00e887ad, 0x00bdad}, /* U+81ED */ - {0x00e887b3, 0x00bbea}, /* U+81F3 */ - {0x00e887b4, 0x00c3d7}, /* U+81F4 */ - {0x00e887ba, 0x00e7ca}, /* U+81FA */ - {0x00e887bb, 0x00e7cb}, /* U+81FB */ - {0x00e887bc, 0x00b1b1}, /* U+81FC */ - {0x00e887bd, 0x8ff5db}, /* U+81FD [2000] */ - {0x00e887be, 0x00e7cc}, /* U+81FE */ - {0x00e887bf, 0x8ff5dc}, /* U+81FF [2000] */ - {0x00e88881, 0x00e7cd}, /* U+8201 */ - {0x00e88882, 0x00e7ce}, /* U+8202 */ - {0x00e88884, 0x8ff5de}, /* U+8204 [2000] */ - {0x00e88885, 0x00e7cf}, /* U+8205 */ - {0x00e88887, 0x00e7d0}, /* U+8207 */ - {0x00e88888, 0x00b6bd}, /* U+8208 */ - {0x00e88889, 0x00daaa}, /* U+8209 */ - {0x00e8888a, 0x00e7d1}, /* U+820A */ - {0x00e8888c, 0x00c0e5}, /* U+820C */ - {0x00e8888d, 0x00e7d2}, /* U+820D */ - {0x00e8888e, 0x00bccb}, /* U+820E */ - {0x00e88890, 0x00e7d3}, /* U+8210 */ - {0x00e88892, 0x00d0b0}, /* U+8212 */ - {0x00e88896, 0x00e7d4}, /* U+8216 */ - {0x00e88897, 0x00cade}, /* U+8217 */ - {0x00e88898, 0x00b4dc}, /* U+8218 */ - {0x00e88899, 0x8ff5e0}, /* U+8219 [2000] */ - {0x00e8889b, 0x00c1a4}, /* U+821B */ - {0x00e8889c, 0x00bdd8}, /* U+821C */ - {0x00e8889e, 0x00c9f1}, /* U+821E */ - {0x00e8889f, 0x00bdae}, /* U+821F */ - {0x00e888a1, 0x8ff5e1}, /* U+8221 [2000] */ - {0x00e888a2, 0x8ff5e2}, /* U+8222 [2000] */ - {0x00e888a9, 0x00e7d5}, /* U+8229 */ - {0x00e888aa, 0x00b9d2}, /* U+822A */ - {0x00e888ab, 0x00e7d6}, /* U+822B */ - {0x00e888ac, 0x00c8cc}, /* U+822C */ - {0x00e888ae, 0x00e7e4}, /* U+822E */ - {0x00e888b2, 0x8ff5e4}, /* U+8232 [2000] */ - {0x00e888b3, 0x00e7d8}, /* U+8233 */ - {0x00e888b4, 0x8ff5e5}, /* U+8234 [2000] */ - {0x00e888b5, 0x00c2c9}, /* U+8235 */ - {0x00e888b6, 0x00c7f5}, /* U+8236 */ - {0x00e888b7, 0x00b8bf}, /* U+8237 */ - {0x00e888b8, 0x00e7d7}, /* U+8238 */ - {0x00e888b9, 0x00c1a5}, /* U+8239 */ - {0x00e888bc, 0x8ff5e6}, /* U+823C [2000] */ - {0x00e88980, 0x00e7d9}, /* U+8240 */ - {0x00e88985, 0x8ff5e9}, /* U+8245 [2000] */ - {0x00e88986, 0x8ff5e7}, /* U+8246 [2000] */ - {0x00e88987, 0x00c4fa}, /* U+8247 */ - {0x00e88989, 0x8ff5e8}, /* U+8249 [2000] */ - {0x00e8898b, 0x8ff5eb}, /* U+824B [2000] */ - {0x00e8898f, 0x8ff5ed}, /* U+824F [2000] */ - {0x00e88997, 0x8ff5ef}, /* U+8257 [2000] */ - {0x00e88998, 0x00e7db}, /* U+8258 */ - {0x00e88999, 0x00e7da}, /* U+8259 */ - {0x00e8899a, 0x00e7dd}, /* U+825A */ - {0x00e8899c, 0x8ff5f1}, /* U+825C [2000] */ - {0x00e8899d, 0x00e7dc}, /* U+825D */ - {0x00e8899f, 0x00e7de}, /* U+825F */ - {0x00e889a0, 0x00fadb}, /* U+8260 [2000] */ - {0x00e889a2, 0x00e7e0}, /* U+8262 */ - {0x00e889a3, 0x8ff5f2}, /* U+8263 [2000] */ - {0x00e889a4, 0x00e7df}, /* U+8264 */ - {0x00e889a6, 0x00b4cf}, /* U+8266 */ - {0x00e889a8, 0x00e7e1}, /* U+8268 */ - {0x00e889aa, 0x00e7e2}, /* U+826A */ - {0x00e889ab, 0x00e7e3}, /* U+826B */ - {0x00e889ae, 0x00bab1}, /* U+826E */ - {0x00e889af, 0x00cec9}, /* U+826F */ - {0x00e889b1, 0x00e7e5}, /* U+8271 */ - {0x00e889b2, 0x00bfa7}, /* U+8272 */ - {0x00e889b4, 0x00fadc}, /* U+8274 [2000] */ - {0x00e889b6, 0x00b1f0}, /* U+8276 */ - {0x00e889b7, 0x00e7e6}, /* U+8277 */ - {0x00e889b8, 0x00e7e7}, /* U+8278 */ - {0x00e889b9, 0x8ff5f6}, /* U+8279 [2000] */ - {0x00e889bd, 0x8ff5f8}, /* U+827D [2000] */ - {0x00e889be, 0x00e7e8}, /* U+827E */ - {0x00e889bf, 0x8ff5f9}, /* U+827F [2000] */ - {0x00e88a83, 0x8ff5fa}, /* U+8283 [2000] */ - {0x00e88a8a, 0x8ff5fb}, /* U+828A [2000] */ - {0x00e88a8b, 0x00b0f2}, /* U+828B */ - {0x00e88a8d, 0x00e7e9}, /* U+828D */ - {0x00e88a8e, 0x00fade}, /* U+828E [2000] */ - {0x00e88a92, 0x00e7ea}, /* U+8292 */ - {0x00e88a93, 0x8ff5fc}, /* U+8293 [2000] */ - {0x00e88a99, 0x00c9e7}, /* U+8299 */ - {0x00e88a9d, 0x00bcc7}, /* U+829D */ - {0x00e88a9f, 0x00e7ec}, /* U+829F */ - {0x00e88aa1, 0x00fadf}, /* U+82A1 [2000] */ - {0x00e88aa3, 0x00fae0}, /* U+82A3 [2000] */ - {0x00e88aa4, 0x00fae1}, /* U+82A4 [2000] */ - {0x00e88aa5, 0x00b3a9}, /* U+82A5 */ - {0x00e88aa6, 0x00b0b2}, /* U+82A6 */ - {0x00e88aa7, 0x8ff5fd}, /* U+82A7 [2000] */ - {0x00e88aa8, 0x8ff5fe}, /* U+82A8 [2000] */ - {0x00e88aa9, 0x00fae2}, /* U+82A9 [2000] */ - {0x00e88aab, 0x00e7eb}, /* U+82AB */ - {0x00e88aac, 0x00e7ee}, /* U+82AC */ - {0x00e88aad, 0x00c7ce}, /* U+82AD */ - {0x00e88aae, 0x00fae3}, /* U+82AE [2000] */ - {0x00e88aaf, 0x00bfc4}, /* U+82AF */ - {0x00e88ab1, 0x00b2d6}, /* U+82B1 */ - {0x00e88ab2, 0x8ff6a1}, /* U+82B2 [2000] */ - {0x00e88ab3, 0x00cba7}, /* U+82B3 */ - {0x00e88ab4, 0x8ff6a2}, /* U+82B4 [2000] */ - {0x00e88ab7, 0x00fae4}, /* U+82B7 [2000] */ - {0x00e88ab8, 0x00b7dd}, /* U+82B8 */ - {0x00e88ab9, 0x00b6dc}, /* U+82B9 */ - {0x00e88aba, 0x8ff6a3}, /* U+82BA [2000] */ - {0x00e88abb, 0x00e7ed}, /* U+82BB */ - {0x00e88abc, 0x8ff6a4}, /* U+82BC [2000] */ - {0x00e88abd, 0x00b2ea}, /* U+82BD */ - {0x00e88abe, 0x00fae5}, /* U+82BE [2000] */ - {0x00e88abf, 0x00fae6}, /* U+82BF [2000] */ - {0x00e88b85, 0x00b4a3}, /* U+82C5 */ - {0x00e88b86, 0x00fae7}, /* U+82C6 [2000] */ - {0x00e88b91, 0x00b1f1}, /* U+82D1 */ - {0x00e88b92, 0x00e7f2}, /* U+82D2 */ - {0x00e88b93, 0x00ceea}, /* U+82D3 */ - {0x00e88b94, 0x00c2dd}, /* U+82D4 */ - {0x00e88b95, 0x00fae8}, /* U+82D5 [2000] */ - {0x00e88b97, 0x00c9c4}, /* U+82D7 */ - {0x00e88b99, 0x00e7fe}, /* U+82D9 */ - {0x00e88b9b, 0x00b2d7}, /* U+82DB */ - {0x00e88b9c, 0x00e7fc}, /* U+82DC */ - {0x00e88b9e, 0x00e7fa}, /* U+82DE */ - {0x00e88b9f, 0x00e7f1}, /* U+82DF */ - {0x00e88ba1, 0x00e7ef}, /* U+82E1 */ - {0x00e88ba2, 0x8ff6a5}, /* U+82E2 [2000] */ - {0x00e88ba3, 0x00e7f0}, /* U+82E3 */ - {0x00e88ba5, 0x00bce3}, /* U+82E5 */ - {0x00e88ba6, 0x00b6ec}, /* U+82E6 */ - {0x00e88ba7, 0x00c3f7}, /* U+82E7 */ - {0x00e88ba8, 0x8ff6a6}, /* U+82E8 [2000] */ - {0x00e88bab, 0x00c6d1}, /* U+82EB */ - {0x00e88bb1, 0x00b1d1}, /* U+82F1 */ - {0x00e88bb3, 0x00e7f4}, /* U+82F3 */ - {0x00e88bb4, 0x00e7f3}, /* U+82F4 */ - {0x00e88bb7, 0x8ff6a7}, /* U+82F7 [2000] */ - {0x00e88bb9, 0x00e7f9}, /* U+82F9 */ - {0x00e88bba, 0x00e7f5}, /* U+82FA */ - {0x00e88bbb, 0x00e7f8}, /* U+82FB */ - {0x00e88bbd, 0x00fae9}, /* U+82FD [2000] */ - {0x00e88bbe, 0x00faea}, /* U+82FE [2000] */ - {0x00e88c80, 0x00faeb}, /* U+8300 [2000] */ - {0x00e88c81, 0x00faec}, /* U+8301 [2000] */ - {0x00e88c82, 0x00ccd0}, /* U+8302 */ - {0x00e88c83, 0x00e7f7}, /* U+8303 */ - {0x00e88c84, 0x00b2d8}, /* U+8304 */ - {0x00e88c85, 0x00b3fd}, /* U+8305 */ - {0x00e88c86, 0x00e7fb}, /* U+8306 */ - {0x00e88c87, 0x8ff6a8}, /* U+8307 [2000] */ - {0x00e88c88, 0x8ff6a9}, /* U+8308 [2000] */ - {0x00e88c89, 0x00e7fd}, /* U+8309 */ - {0x00e88c8c, 0x8ff6aa}, /* U+830C [2000] */ - {0x00e88c8e, 0x00b7d4}, /* U+830E */ - {0x00e88c96, 0x00e8a3}, /* U+8316 */ - {0x00e88c97, 0x00e8ac}, /* U+8317 */ - {0x00e88c98, 0x00e8ad}, /* U+8318 */ - {0x00e88c9b, 0x8ff6ac}, /* U+831B [2000] */ - {0x00e88c9c, 0x00b0ab}, /* U+831C */ - {0x00e88c9d, 0x8ff6ad}, /* U+831D [2000] */ - {0x00e88ca2, 0x00faee}, /* U+8322 [2000] */ - {0x00e88ca3, 0x00e8b4}, /* U+8323 */ - {0x00e88ca8, 0x00b0f1}, /* U+8328 */ - {0x00e88cab, 0x00e8ab}, /* U+832B */ - {0x00e88cad, 0x00faef}, /* U+832D [2000] */ - {0x00e88caf, 0x00e8aa}, /* U+832F */ - {0x00e88cb0, 0x8ff6ae}, /* U+8330 [2000] */ - {0x00e88cb1, 0x00e8a5}, /* U+8331 */ - {0x00e88cb2, 0x00e8a4}, /* U+8332 */ - {0x00e88cb4, 0x00e8a2}, /* U+8334 */ - {0x00e88cb5, 0x00e8a1}, /* U+8335 */ - {0x00e88cb6, 0x00c3e3}, /* U+8336 */ - {0x00e88cb8, 0x00c2fb}, /* U+8338 */ - {0x00e88cb9, 0x00e8a7}, /* U+8339 */ - {0x00e88cba, 0x00faf0}, /* U+833A [2000] */ - {0x00e88cbc, 0x8ff6af}, /* U+833C [2000] */ - {0x00e88d80, 0x00e8a6}, /* U+8340 */ - {0x00e88d83, 0x00faf1}, /* U+8343 [2000] */ - {0x00e88d84, 0x8ff6b0}, /* U+8344 [2000] */ - {0x00e88d85, 0x00e8a9}, /* U+8345 */ - {0x00e88d87, 0x00faf2}, /* U+8347 [2000] */ - {0x00e88d89, 0x00c1f0}, /* U+8349 */ - {0x00e88d8a, 0x00b7d5}, /* U+834A */ - {0x00e88d8f, 0x00b1c1}, /* U+834F */ - {0x00e88d90, 0x00e8a8}, /* U+8350 */ - {0x00e88d91, 0x00faf3}, /* U+8351 [2000] */ - {0x00e88d92, 0x00b9d3}, /* U+8352 */ - {0x00e88d94, 0x8ff6ab}, /* U+8354 [2000] */ - {0x00e88d95, 0x00faf4}, /* U+8355 [2000] */ - {0x00e88d97, 0x8ff6b1}, /* U+8357 [2000] */ - {0x00e88d98, 0x00c1f1}, /* U+8358 */ - {0x00e88da2, 0x00faed}, /* U+8362 [2000] */ - {0x00e88da3, 0x8faeca}, /* U+8363 [2000] */ - {0x00e88db3, 0x00e8ba}, /* U+8373 */ - {0x00e88db5, 0x00e8bb}, /* U+8375 */ - {0x00e88db7, 0x00b2d9}, /* U+8377 */ - {0x00e88dbb, 0x00b2ae}, /* U+837B */ - {0x00e88dbc, 0x00e8b8}, /* U+837C */ - {0x00e88dbd, 0x00faf5}, /* U+837D [2000] */ - {0x00e88dbf, 0x8ff6b3}, /* U+837F [2000] */ - {0x00e88e85, 0x00e8ae}, /* U+8385 */ - {0x00e88e86, 0x00faf6}, /* U+8386 [2000] */ - {0x00e88e87, 0x00e8b6}, /* U+8387 */ - {0x00e88e89, 0x00e8bd}, /* U+8389 */ - {0x00e88e8a, 0x00e8b7}, /* U+838A */ - {0x00e88e8d, 0x8ff6b6}, /* U+838D [2000] */ - {0x00e88e8e, 0x00e8b5}, /* U+838E */ - {0x00e88e92, 0x00faf7}, /* U+8392 [2000] */ - {0x00e88e93, 0x00e7f6}, /* U+8393 */ - {0x00e88e94, 0x8ff6b7}, /* U+8394 [2000] */ - {0x00e88e95, 0x8ff6b8}, /* U+8395 [2000] */ - {0x00e88e96, 0x00e8b3}, /* U+8396 */ - {0x00e88e98, 0x00faf8}, /* U+8398 [2000] */ - {0x00e88e9a, 0x00e8af}, /* U+839A */ - {0x00e88e9b, 0x8ff6b9}, /* U+839B [2000] */ - {0x00e88e9d, 0x8ff6ba}, /* U+839D [2000] */ - {0x00e88e9e, 0x00b4d0}, /* U+839E */ - {0x00e88e9f, 0x00e8b1}, /* U+839F */ - {0x00e88ea0, 0x00e8bc}, /* U+83A0 */ - {0x00e88ea2, 0x00e8b2}, /* U+83A2 */ - {0x00e88ea7, 0x00faf9}, /* U+83A7 [2000] */ - {0x00e88ea8, 0x00e8be}, /* U+83A8 */ - {0x00e88ea9, 0x00fafa}, /* U+83A9 [2000] */ - {0x00e88eaa, 0x00e8b0}, /* U+83AA */ - {0x00e88eab, 0x00c7fc}, /* U+83AB */ - {0x00e88eb1, 0x00cde9}, /* U+83B1 */ - {0x00e88eb5, 0x00e8b9}, /* U+83B5 */ - {0x00e88ebd, 0x00e8cf}, /* U+83BD */ - {0x00e88ebf, 0x00fafb}, /* U+83BF [2000] */ - {0x00e88f80, 0x00fafc}, /* U+83C0 [2000] */ - {0x00e88f81, 0x00e8c7}, /* U+83C1 */ - {0x00e88f85, 0x00bffb}, /* U+83C5 */ - {0x00e88f87, 0x00fafd}, /* U+83C7 [2000] */ - {0x00e88f89, 0x8ff6bb}, /* U+83C9 [2000] */ - {0x00e88f8a, 0x00b5c6}, /* U+83CA */ - {0x00e88f8c, 0x00b6dd}, /* U+83CC */ - {0x00e88f8e, 0x00e8c2}, /* U+83CE */ - {0x00e88f8f, 0x00fafe}, /* U+83CF [2000] */ - {0x00e88f90, 0x8ff6bc}, /* U+83D0 [2000] */ - {0x00e88f91, 0x00fba1}, /* U+83D1 [2000] */ - {0x00e88f93, 0x00b2db}, /* U+83D3 */ - {0x00e88f94, 0x8ff6bd}, /* U+83D4 [2000] */ - {0x00e88f96, 0x00bed4}, /* U+83D6 */ - {0x00e88f98, 0x00e8c5}, /* U+83D8 */ - {0x00e88f9c, 0x00bada}, /* U+83DC */ - {0x00e88f9d, 0x8ff6be}, /* U+83DD [2000] */ - {0x00e88f9f, 0x00c5d1}, /* U+83DF */ - {0x00e88fa0, 0x00e8ca}, /* U+83E0 */ - {0x00e88fa1, 0x00fba2}, /* U+83E1 [2000] */ - {0x00e88fa5, 0x8ff6bf}, /* U+83E5 [2000] */ - {0x00e88fa9, 0x00caee}, /* U+83E9 */ - {0x00e88faa, 0x00fba3}, /* U+83EA [2000] */ - {0x00e88fab, 0x00e8c1}, /* U+83EB */ - {0x00e88faf, 0x00b2da}, /* U+83EF */ - {0x00e88fb0, 0x00b8d6}, /* U+83F0 */ - {0x00e88fb1, 0x00c9a9}, /* U+83F1 */ - {0x00e88fb2, 0x00e8cb}, /* U+83F2 */ - {0x00e88fb4, 0x00e8bf}, /* U+83F4 */ - {0x00e88fb7, 0x00e8c8}, /* U+83F7 */ - {0x00e88fb9, 0x8ff6c0}, /* U+83F9 [2000] */ - {0x00e88fbb, 0x00e8d2}, /* U+83FB */ - {0x00e88fbd, 0x00e8c3}, /* U+83FD */ - {0x00e89081, 0x00fba4}, /* U+8401 [2000] */ - {0x00e89083, 0x00e8c4}, /* U+8403 */ - {0x00e89084, 0x00c6ba}, /* U+8404 */ - {0x00e89086, 0x00fba5}, /* U+8406 [2000] */ - {0x00e89087, 0x00e8c9}, /* U+8407 */ - {0x00e8908a, 0x00fba6}, /* U+840A [2000] */ - {0x00e8908b, 0x00e8c6}, /* U+840B */ - {0x00e8908c, 0x00cba8}, /* U+840C */ - {0x00e8908d, 0x00e8cc}, /* U+840D */ - {0x00e8908e, 0x00b0e0}, /* U+840E */ - {0x00e8908f, 0x8ff6c1}, /* U+840F [2000] */ - {0x00e89091, 0x8ff6c2}, /* U+8411 [2000] */ - {0x00e89093, 0x00e8c0}, /* U+8413 */ - {0x00e89095, 0x8ff6c3}, /* U+8415 [2000] */ - {0x00e89097, 0x8ff6c5}, /* U+8417 [2000] */ - {0x00e890a0, 0x00e8ce}, /* U+8420 */ - {0x00e890a2, 0x00e8cd}, /* U+8422 */ - {0x00e890a9, 0x00c7eb}, /* U+8429 */ - {0x00e890aa, 0x00e8d4}, /* U+842A */ - {0x00e890ac, 0x00e8df}, /* U+842C */ - {0x00e890b1, 0x00b3fe}, /* U+8431 */ - {0x00e890b5, 0x00e8e2}, /* U+8435 */ - {0x00e890b8, 0x00e8d0}, /* U+8438 */ - {0x00e890b9, 0x8ff6c6}, /* U+8439 [2000] */ - {0x00e890bc, 0x00e8d5}, /* U+843C */ - {0x00e890bd, 0x00cdee}, /* U+843D */ - {0x00e89186, 0x00e8de}, /* U+8446 */ - {0x00e89188, 0x00fba8}, /* U+8448 [2000] */ - {0x00e89189, 0x00cdd5}, /* U+8449 */ - {0x00e8918a, 0x8ff6c7}, /* U+844A [2000] */ - {0x00e8918e, 0x00ceaa}, /* U+844E */ - {0x00e8918f, 0x8ff6c8}, /* U+844F [2000] */ - {0x00e89191, 0x8ff6c9}, /* U+8451 [2000] */ - {0x00e89192, 0x8ff6ca}, /* U+8452 [2000] */ - {0x00e89197, 0x00c3f8}, /* U+8457 */ - {0x00e89199, 0x8ff6cb}, /* U+8459 [2000] */ - {0x00e8919a, 0x8ff6cc}, /* U+845A [2000] */ - {0x00e8919b, 0x00b3eb}, /* U+845B */ - {0x00e8919c, 0x8ff6cd}, /* U+845C [2000] */ - {0x00e8919f, 0x00fba9}, /* U+845F [2000] */ - {0x00e891a1, 0x00c9f2}, /* U+8461 */ - {0x00e891a2, 0x00e8e4}, /* U+8462 */ - {0x00e891a3, 0x00c6a1}, /* U+8463 */ - {0x00e891a5, 0x8ff6cf}, /* U+8465 [2000] */ - {0x00e891a6, 0x00b0b1}, /* U+8466 */ - {0x00e891a9, 0x00e8dd}, /* U+8469 */ - {0x00e891ab, 0x00e8d9}, /* U+846B */ - {0x00e891ac, 0x00c1f2}, /* U+846C */ - {0x00e891ad, 0x00e8d3}, /* U+846D */ - {0x00e891ae, 0x00e8db}, /* U+846E */ - {0x00e891af, 0x00e8e0}, /* U+846F */ - {0x00e891b0, 0x00fbaa}, /* U+8470 [2000] */ - {0x00e891b1, 0x00c7ac}, /* U+8471 */ - {0x00e891b3, 0x00fbab}, /* U+8473 [2000] */ - {0x00e891b5, 0x00b0aa}, /* U+8475 */ - {0x00e891b6, 0x8ff6d0}, /* U+8476 [2000] */ - {0x00e891b7, 0x00e8d8}, /* U+8477 */ - {0x00e891b8, 0x8ff6d1}, /* U+8478 [2000] */ - {0x00e891b9, 0x00e8e1}, /* U+8479 */ - {0x00e891ba, 0x00c9f8}, /* U+847A */ - {0x00e891bc, 0x8ff6d2}, /* U+847C [2000] */ - {0x00e89281, 0x8ff6d3}, /* U+8481 [2000] */ - {0x00e89282, 0x00e8dc}, /* U+8482 */ - {0x00e89284, 0x00e8d7}, /* U+8484 */ - {0x00e89285, 0x00fbac}, /* U+8485 [2000] */ - {0x00e8928b, 0x00bed5}, /* U+848B */ - {0x00e89290, 0x00bdaf}, /* U+8490 */ - {0x00e89294, 0x00bcac}, /* U+8494 */ - {0x00e89297, 0x8ff6d6}, /* U+8497 [2000] */ - {0x00e89299, 0x00ccd8}, /* U+8499 */ - {0x00e8929c, 0x00c9c7}, /* U+849C */ - {0x00e8929e, 0x00fbad}, /* U+849E [2000] */ - {0x00e8929f, 0x00e8e7}, /* U+849F */ - {0x00e892a1, 0x00e8f0}, /* U+84A1 */ - {0x00e892a6, 0x8ff6d7}, /* U+84A6 [2000] */ - {0x00e892ad, 0x00e8da}, /* U+84AD */ - {0x00e892af, 0x00fbae}, /* U+84AF [2000] */ - {0x00e892b2, 0x00b3f7}, /* U+84B2 */ - {0x00e892b4, 0x00fbaf}, /* U+84B4 [2000] */ - {0x00e892b8, 0x00bef8}, /* U+84B8 */ - {0x00e892b9, 0x00e8e5}, /* U+84B9 */ - {0x00e892ba, 0x00fbb0}, /* U+84BA [2000] */ - {0x00e892bb, 0x00e8ea}, /* U+84BB */ - {0x00e892bc, 0x00c1f3}, /* U+84BC */ - {0x00e892be, 0x8ff6d8}, /* U+84BE [2000] */ - {0x00e892bf, 0x00e8e6}, /* U+84BF */ - {0x00e89380, 0x00fbb1}, /* U+84C0 [2000] */ - {0x00e89381, 0x00e8ed}, /* U+84C1 */ - {0x00e89382, 0x00fbb2}, /* U+84C2 [2000] */ - {0x00e89384, 0x00c3df}, /* U+84C4 */ - {0x00e89386, 0x00e8ee}, /* U+84C6 */ - {0x00e89389, 0x00cdd6}, /* U+84C9 */ - {0x00e8938a, 0x00e8e3}, /* U+84CA */ - {0x00e8938b, 0x00b3b8}, /* U+84CB */ - {0x00e8938d, 0x00e8e9}, /* U+84CD */ - {0x00e8938e, 0x8ff6da}, /* U+84CE [2000] */ - {0x00e8938f, 0x8ff6db}, /* U+84CF [2000] */ - {0x00e89390, 0x00e8ec}, /* U+84D0 */ - {0x00e89391, 0x00ccac}, /* U+84D1 */ - {0x00e89393, 0x8ff6dc}, /* U+84D3 [2000] */ - {0x00e89396, 0x00e8ef}, /* U+84D6 */ - {0x00e89399, 0x00e8e8}, /* U+84D9 */ - {0x00e8939a, 0x00e8eb}, /* U+84DA */ - {0x00e8939c, 0x8ff6d5}, /* U+84DC [2000] */ - {0x00e893a7, 0x8ff6de}, /* U+84E7 [2000] */ - {0x00e893aa, 0x8ff6df}, /* U+84EA [2000] */ - {0x00e893ac, 0x00cba9}, /* U+84EC */ - {0x00e893ae, 0x00cfa1}, /* U+84EE */ - {0x00e893af, 0x8ff6e0}, /* U+84EF [2000] */ - {0x00e893b0, 0x8ff6e1}, /* U+84F0 [2000] */ - {0x00e893b1, 0x8ff6e2}, /* U+84F1 [2000] */ - {0x00e893b4, 0x00e8f3}, /* U+84F4 */ - {0x00e893ba, 0x8ff6e3}, /* U+84FA [2000] */ - {0x00e893bc, 0x00e8fa}, /* U+84FC */ - {0x00e893bd, 0x8ff6e4}, /* U+84FD [2000] */ - {0x00e893bf, 0x00e8f2}, /* U+84FF */ - {0x00e89480, 0x00bcc3}, /* U+8500 */ - {0x00e89486, 0x00e8d1}, /* U+8506 */ - {0x00e8948c, 0x8ff6e5}, /* U+850C [2000] */ - {0x00e89491, 0x00cace}, /* U+8511 */ - {0x00e89493, 0x00cca2}, /* U+8513 */ - {0x00e89494, 0x00e8f9}, /* U+8514 */ - {0x00e89495, 0x00e8f8}, /* U+8515 */ - {0x00e89497, 0x00e8f4}, /* U+8517 */ - {0x00e89498, 0x00e8f5}, /* U+8518 */ - {0x00e8949a, 0x00b1b6}, /* U+851A */ - {0x00e8949b, 0x8ff6e6}, /* U+851B [2000] */ - {0x00e8949e, 0x00fbb5}, /* U+851E [2000] */ - {0x00e8949f, 0x00e8f7}, /* U+851F */ - {0x00e894a1, 0x00e8f1}, /* U+8521 */ - {0x00e894a3, 0x00fbb6}, /* U+8523 [2000] */ - {0x00e894a4, 0x8ff6e7}, /* U+8524 [2000] */ - {0x00e894a5, 0x8ff6e8}, /* U+8525 [2000] */ - {0x00e894a6, 0x00c4d5}, /* U+8526 */ - {0x00e894ab, 0x8ff6e9}, /* U+852B [2000] */ - {0x00e894ac, 0x00e8f6}, /* U+852C */ - {0x00e894ad, 0x00b0fe}, /* U+852D */ - {0x00e894af, 0x00fbb7}, /* U+852F [2000] */ - {0x00e894b2, 0x00fbb4}, /* U+8532 [2000] */ - {0x00e894b4, 0x8ff6ea}, /* U+8534 [2000] */ - {0x00e894b5, 0x00c2a2}, /* U+8535 */ - {0x00e894bd, 0x00cac3}, /* U+853D */ - {0x00e894be, 0x8ff6ef}, /* U+853E [2000] */ - {0x00e89580, 0x00e8fb}, /* U+8540 */ - {0x00e89581, 0x00e9a1}, /* U+8541 */ - {0x00e89583, 0x00c8d9}, /* U+8543 */ - {0x00e89588, 0x00e8fe}, /* U+8548 */ - {0x00e89589, 0x00bed6}, /* U+8549 */ - {0x00e8958a, 0x00bcc9}, /* U+854A */ - {0x00e8958b, 0x00e9a3}, /* U+854B */ - {0x00e8958e, 0x00b6be}, /* U+854E */ - {0x00e8958f, 0x8ff6eb}, /* U+854F [2000] */ - {0x00e89591, 0x8ff6f0}, /* U+8551 [2000] */ - {0x00e89593, 0x8ff6f1}, /* U+8553 [2000] */ - {0x00e89595, 0x00e9a4}, /* U+8555 */ - {0x00e89597, 0x00c9f9}, /* U+8557 */ - {0x00e89598, 0x00e8fd}, /* U+8558 */ - {0x00e89599, 0x00fbb8}, /* U+8559 [2000] */ - {0x00e8959a, 0x00e8d6}, /* U+855A */ - {0x00e8959e, 0x8ff6f2}, /* U+855E [2000] */ - {0x00e895a1, 0x8ff6f3}, /* U+8561 [2000] */ - {0x00e895a2, 0x8ff6f4}, /* U+8562 [2000] */ - {0x00e895a3, 0x00e8fc}, /* U+8563 */ - {0x00e895a4, 0x00fbb9}, /* U+8564 [2000] */ - {0x00e895a8, 0x00cfcf}, /* U+8568 */ - {0x00e895a9, 0x00c6a2}, /* U+8569 */ - {0x00e895aa, 0x00c9f3}, /* U+856A */ - {0x00e895ad, 0x00e9ab}, /* U+856D */ - {0x00e895af, 0x8ff6ec}, /* U+856F [2000] */ - {0x00e895b7, 0x00e9b1}, /* U+8577 */ - {0x00e895ba, 0x00fbbc}, /* U+857A [2000] */ - {0x00e895bb, 0x8ff6f6}, /* U+857B [2000] */ - {0x00e895bd, 0x8ff6f7}, /* U+857D [2000] */ - {0x00e895be, 0x00e9b2}, /* U+857E */ - {0x00e895bf, 0x8ff6f8}, /* U+857F [2000] */ - {0x00e89680, 0x00e9a5}, /* U+8580 */ - {0x00e89681, 0x8ff6f9}, /* U+8581 [2000] */ - {0x00e89684, 0x00c7f6}, /* U+8584 */ - {0x00e89686, 0x8ff6fa}, /* U+8586 [2000] */ - {0x00e89687, 0x00e9af}, /* U+8587 */ - {0x00e89688, 0x00e9a7}, /* U+8588 */ - {0x00e8968a, 0x00e9a9}, /* U+858A */ - {0x00e8968c, 0x00fbbd}, /* U+858C [2000] */ - {0x00e8968f, 0x00fbbe}, /* U+858F [2000] */ - {0x00e89690, 0x00e9b3}, /* U+8590 */ - {0x00e89691, 0x00e9a8}, /* U+8591 */ - {0x00e89693, 0x8ff6fb}, /* U+8593 [2000] */ - {0x00e89694, 0x00e9ac}, /* U+8594 */ - {0x00e89697, 0x00b1f2}, /* U+8597 */ - {0x00e89699, 0x00c6e5}, /* U+8599 */ - {0x00e8969b, 0x00e9ad}, /* U+859B */ - {0x00e8969c, 0x00e9b0}, /* U+859C */ - {0x00e8969d, 0x8ff6fc}, /* U+859D [2000] */ - {0x00e8969f, 0x8ff6fd}, /* U+859F [2000] */ - {0x00e896a2, 0x00fbbf}, /* U+85A2 [2000] */ - {0x00e896a4, 0x00e9a6}, /* U+85A4 */ - {0x00e896a6, 0x00c1a6}, /* U+85A6 */ - {0x00e896a8, 0x00e9aa}, /* U+85A8 */ - {0x00e896a9, 0x00bba7}, /* U+85A9 */ - {0x00e896aa, 0x00bfc5}, /* U+85AA */ - {0x00e896ab, 0x00b7b0}, /* U+85AB */ - {0x00e896ac, 0x00ccf4}, /* U+85AC */ - {0x00e896ad, 0x00fbbb}, /* U+85AD [2000] */ - {0x00e896ae, 0x00ccf9}, /* U+85AE */ - {0x00e896af, 0x00bdf2}, /* U+85AF */ - {0x00e896b0, 0x00fbc0}, /* U+85B0 [2000] */ - {0x00e896b7, 0x8ff7a3}, /* U+85B7 [2000] */ - {0x00e896b9, 0x00e9b7}, /* U+85B9 */ - {0x00e896ba, 0x00e9b5}, /* U+85BA */ - {0x00e896bc, 0x8ff7a4}, /* U+85BC [2000] */ - {0x00e89781, 0x00cfce}, /* U+85C1 */ - {0x00e89787, 0x8ff7a5}, /* U+85C7 [2000] */ - {0x00e89789, 0x00e9b4}, /* U+85C9 */ - {0x00e8978a, 0x8ff7a6}, /* U+85CA [2000] */ - {0x00e8978b, 0x00fbc1}, /* U+85CB [2000] */ - {0x00e8978d, 0x00cdf5}, /* U+85CD */ - {0x00e8978e, 0x00fbc2}, /* U+85CE [2000] */ - {0x00e8978f, 0x00e9b6}, /* U+85CF */ - {0x00e89790, 0x00e9b8}, /* U+85D0 */ - {0x00e89795, 0x00e9b9}, /* U+85D5 */ - {0x00e89798, 0x8ff7a7}, /* U+85D8 [2000] */ - {0x00e89799, 0x8ff7a8}, /* U+85D9 [2000] */ - {0x00e8979c, 0x00e9bc}, /* U+85DC */ - {0x00e8979d, 0x00e9ba}, /* U+85DD */ - {0x00e8979f, 0x8ff7a9}, /* U+85DF [2000] */ - {0x00e897a1, 0x8ff7aa}, /* U+85E1 [2000] */ - {0x00e897a4, 0x00c6a3}, /* U+85E4 */ - {0x00e897a5, 0x00e9bb}, /* U+85E5 */ - {0x00e897a6, 0x8ff7ab}, /* U+85E6 [2000] */ - {0x00e897a9, 0x00c8cd}, /* U+85E9 */ - {0x00e897aa, 0x00e9ae}, /* U+85EA */ - {0x00e897ad, 0x00fbc3}, /* U+85ED [2000] */ - {0x00e897b6, 0x8ff7ac}, /* U+85F6 [2000] */ - {0x00e897b7, 0x00bdf3}, /* U+85F7 */ - {0x00e897b9, 0x00e9bd}, /* U+85F9 */ - {0x00e897ba, 0x00e9c2}, /* U+85FA */ - {0x00e897bb, 0x00c1f4}, /* U+85FB */ - {0x00e897be, 0x00e9c1}, /* U+85FE */ - {0x00e897bf, 0x00fbc5}, /* U+85FF [2000] */ - {0x00e89880, 0x8ff7ad}, /* U+8600 [2000] */ - {0x00e89882, 0x00e9a2}, /* U+8602 */ - {0x00e89884, 0x00fbc6}, /* U+8604 [2000] */ - {0x00e89885, 0x00fbc7}, /* U+8605 [2000] */ - {0x00e89886, 0x00e9c3}, /* U+8606 */ - {0x00e89887, 0x00c1c9}, /* U+8607 */ - {0x00e8988a, 0x00e9be}, /* U+860A */ - {0x00e8988b, 0x00e9c0}, /* U+860B */ - {0x00e89890, 0x00fbc8}, /* U+8610 [2000] */ - {0x00e89891, 0x8ff7ae}, /* U+8611 [2000] */ - {0x00e89892, 0x00fbc4}, /* U+8612 [2000] */ - {0x00e89893, 0x00e9bf}, /* U+8613 */ - {0x00e89896, 0x00ddb1}, /* U+8616 */ - {0x00e89897, 0x00dda2}, /* U+8617 */ - {0x00e89898, 0x00fbca}, /* U+8618 [2000] */ - {0x00e8989a, 0x00e9c5}, /* U+861A */ - {0x00e8989e, 0x8ff7af}, /* U+861E [2000] */ - {0x00e898a1, 0x8ff7b0}, /* U+8621 [2000] */ - {0x00e898a2, 0x00e9c4}, /* U+8622 */ - {0x00e898a4, 0x8ff7b1}, /* U+8624 [2000] */ - {0x00e898a7, 0x8ff7b2}, /* U+8627 [2000] */ - {0x00e898a9, 0x00fbcb}, /* U+8629 [2000] */ - {0x00e898ad, 0x00cdf6}, /* U+862D */ - {0x00e898af, 0x00e2bc}, /* U+862F */ - {0x00e898b0, 0x00e9c6}, /* U+8630 */ - {0x00e898b8, 0x00fbcc}, /* U+8638 [2000] */ - {0x00e898b9, 0x8ff7b4}, /* U+8639 [2000] */ - {0x00e898bc, 0x8ff7b5}, /* U+863C [2000] */ - {0x00e898bf, 0x00e9c7}, /* U+863F */ - {0x00e89980, 0x8ff7b7}, /* U+8640 [2000] */ - {0x00e89981, 0x00afe8}, /* U+8641 [2000] */ - {0x00e8998d, 0x00e9c8}, /* U+864D */ - {0x00e8998e, 0x00b8d7}, /* U+864E */ - {0x00e89990, 0x00b5d4}, /* U+8650 */ - {0x00e89993, 0x8ff7b9}, /* U+8653 [2000] */ - {0x00e89994, 0x00e9ca}, /* U+8654 */ - {0x00e89995, 0x00d1dd}, /* U+8655 */ - {0x00e89996, 0x8ff7ba}, /* U+8656 [2000] */ - {0x00e89997, 0x00fbcd}, /* U+8657 [2000] */ - {0x00e8999a, 0x00b5f5}, /* U+865A */ - {0x00e8999b, 0x00fbce}, /* U+865B [2000] */ - {0x00e8999c, 0x00ceba}, /* U+865C */ - {0x00e8999e, 0x00b6f3}, /* U+865E */ - {0x00e8999f, 0x00e9cb}, /* U+865F */ - {0x00e899a2, 0x00fbd0}, /* U+8662 [2000] */ - {0x00e899a7, 0x00e9cc}, /* U+8667 */ - {0x00e899ab, 0x00c3ee}, /* U+866B */ - {0x00e899ac, 0x00fbd2}, /* U+866C [2000] */ - {0x00e899af, 0x8ff7bb}, /* U+866F [2000] */ - {0x00e899b1, 0x00e9cd}, /* U+8671 */ - {0x00e899b5, 0x00fbd3}, /* U+8675 [2000] */ - {0x00e899b7, 0x8ff7bc}, /* U+8677 [2000] */ - {0x00e899b9, 0x00c6fa}, /* U+8679 */ - {0x00e899ba, 0x8ff7bd}, /* U+867A [2000] */ - {0x00e899bb, 0x00b0ba}, /* U+867B */ - {0x00e89a87, 0x8ff7be}, /* U+8687 [2000] */ - {0x00e89a89, 0x8ff7bf}, /* U+8689 [2000] */ - {0x00e89a8a, 0x00b2e3}, /* U+868A */ - {0x00e89a8b, 0x00e9d2}, /* U+868B */ - {0x00e89a8c, 0x00e9d3}, /* U+868C */ - {0x00e89a8d, 0x8ff7c0}, /* U+868D [2000] */ - {0x00e89a91, 0x8ff7c1}, /* U+8691 [2000] */ - {0x00e89a93, 0x00e9ce}, /* U+8693 */ - {0x00e89a95, 0x00bbbd}, /* U+8695 */ - {0x00e89a98, 0x00fbd4}, /* U+8698 [2000] */ - {0x00e89a9c, 0x8ff7c2}, /* U+869C [2000] */ - {0x00e89a9d, 0x8ff7c3}, /* U+869D [2000] */ - {0x00e89aa3, 0x00e9cf}, /* U+86A3 */ - {0x00e89aa4, 0x00c7c2}, /* U+86A4 */ - {0x00e89aa8, 0x8ff7c4}, /* U+86A8 [2000] */ - {0x00e89aa9, 0x00e9d0}, /* U+86A9 */ - {0x00e89aaa, 0x00e9d1}, /* U+86AA */ - {0x00e89aab, 0x00e9db}, /* U+86AB */ - {0x00e89aaf, 0x00e9d5}, /* U+86AF */ - {0x00e89ab0, 0x00e9d8}, /* U+86B0 */ - {0x00e89ab1, 0x8ff7c6}, /* U+86B1 [2000] */ - {0x00e89ab3, 0x8ff7c7}, /* U+86B3 [2000] */ - {0x00e89ab6, 0x00e9d4}, /* U+86B6 */ - {0x00e89ab8, 0x00fbd5}, /* U+86B8 [2000] */ - {0x00e89b81, 0x8ff7c8}, /* U+86C1 [2000] */ - {0x00e89b83, 0x8ff7c9}, /* U+86C3 [2000] */ - {0x00e89b84, 0x00e9d6}, /* U+86C4 */ - {0x00e89b86, 0x00e9d7}, /* U+86C6 */ - {0x00e89b87, 0x00bcd8}, /* U+86C7 */ - {0x00e89b89, 0x00e9d9}, /* U+86C9 */ - {0x00e89b8b, 0x00c3c1}, /* U+86CB */ - {0x00e89b8d, 0x00b7d6}, /* U+86CD */ - {0x00e89b8e, 0x00b3c2}, /* U+86CE */ - {0x00e89b91, 0x8ff7ca}, /* U+86D1 [2000] */ - {0x00e89b94, 0x00e9dc}, /* U+86D4 */ - {0x00e89b95, 0x8ff7cb}, /* U+86D5 [2000] */ - {0x00e89b97, 0x8ff7cc}, /* U+86D7 [2000] */ - {0x00e89b99, 0x00b3bf}, /* U+86D9 */ - {0x00e89b9b, 0x00e9e1}, /* U+86DB */ - {0x00e89b9e, 0x00e9dd}, /* U+86DE */ - {0x00e89b9f, 0x00e9e0}, /* U+86DF */ - {0x00e89ba3, 0x8ff7cd}, /* U+86E3 [2000] */ - {0x00e89ba4, 0x00c8ba}, /* U+86E4 */ - {0x00e89ba6, 0x8ff7ce}, /* U+86E6 [2000] */ - {0x00e89ba9, 0x00e9de}, /* U+86E9 */ - {0x00e89bac, 0x00e9df}, /* U+86EC */ - {0x00e89bad, 0x00c9c8}, /* U+86ED */ - {0x00e89bae, 0x00c8da}, /* U+86EE */ - {0x00e89baf, 0x00e9e2}, /* U+86EF */ - {0x00e89bb8, 0x00c2fd}, /* U+86F8 */ - {0x00e89bb9, 0x00e9ec}, /* U+86F9 */ - {0x00e89bba, 0x00fbd6}, /* U+86FA [2000] */ - {0x00e89bbb, 0x00e9e8}, /* U+86FB */ - {0x00e89bbc, 0x00fbd7}, /* U+86FC [2000] */ - {0x00e89bbd, 0x00fbd8}, /* U+86FD [2000] */ - {0x00e89bbe, 0x00b2eb}, /* U+86FE */ - {0x00e89c80, 0x00e9e6}, /* U+8700 */ - {0x00e89c82, 0x00cbaa}, /* U+8702 */ - {0x00e89c83, 0x00e9e7}, /* U+8703 */ - {0x00e89c85, 0x8ff7d0}, /* U+8705 [2000] */ - {0x00e89c86, 0x00e9e4}, /* U+8706 */ - {0x00e89c87, 0x8ff7d1}, /* U+8707 [2000] */ - {0x00e89c88, 0x00e9e5}, /* U+8708 */ - {0x00e89c89, 0x00e9ea}, /* U+8709 */ - {0x00e89c8a, 0x00e9ed}, /* U+870A */ - {0x00e89c8b, 0x00fbd9}, /* U+870B [2000] */ - {0x00e89c8d, 0x00e9eb}, /* U+870D */ - {0x00e89c8e, 0x8ff7d2}, /* U+870E [2000] */ - {0x00e89c90, 0x8ff7d3}, /* U+8710 [2000] */ - {0x00e89c91, 0x00e9e9}, /* U+8711 */ - {0x00e89c92, 0x00e9e3}, /* U+8712 */ - {0x00e89c93, 0x8ff7d4}, /* U+8713 [2000] */ - {0x00e89c98, 0x00c3d8}, /* U+8718 */ - {0x00e89c99, 0x8ff7d5}, /* U+8719 [2000] */ - {0x00e89c9a, 0x00e9f4}, /* U+871A */ - {0x00e89c9c, 0x00ccaa}, /* U+871C */ - {0x00e89c9f, 0x8ff7d6}, /* U+871F [2000] */ - {0x00e89ca1, 0x8ff7d7}, /* U+8721 [2000] */ - {0x00e89ca3, 0x8ff7d8}, /* U+8723 [2000] */ - {0x00e89ca5, 0x00e9f2}, /* U+8725 */ - {0x00e89ca9, 0x00e9f3}, /* U+8729 */ - {0x00e89cb1, 0x8ff7d9}, /* U+8731 [2000] */ - {0x00e89cb4, 0x00e9ee}, /* U+8734 */ - {0x00e89cb7, 0x00e9f0}, /* U+8737 */ - {0x00e89cba, 0x8ff7da}, /* U+873A [2000] */ - {0x00e89cbb, 0x00e9f1}, /* U+873B */ - {0x00e89cbe, 0x8ff7db}, /* U+873E [2000] */ - {0x00e89cbf, 0x00e9ef}, /* U+873F */ - {0x00e89d80, 0x8ff7dc}, /* U+8740 [2000] */ - {0x00e89d83, 0x8ff7dd}, /* U+8743 [2000] */ - {0x00e89d89, 0x00c0e6}, /* U+8749 */ - {0x00e89d8b, 0x00cfb9}, /* U+874B */ - {0x00e89d8c, 0x00e9f8}, /* U+874C */ - {0x00e89d8e, 0x00e9f9}, /* U+874E */ - {0x00e89d91, 0x8ff7de}, /* U+8751 [2000] */ - {0x00e89d93, 0x00eaa1}, /* U+8753 */ - {0x00e89d95, 0x00bfaa}, /* U+8755 */ - {0x00e89d97, 0x00e9fb}, /* U+8757 */ - {0x00e89d98, 0x8ff7df}, /* U+8758 [2000] */ - {0x00e89d99, 0x00e9fe}, /* U+8759 */ - {0x00e89d9f, 0x00e9f6}, /* U+875F */ - {0x00e89da0, 0x00e9f5}, /* U+8760 */ - {0x00e89da3, 0x00eaa2}, /* U+8763 */ - {0x00e89da4, 0x8ff7e0}, /* U+8764 [2000] */ - {0x00e89da5, 0x8ff7e1}, /* U+8765 [2000] */ - {0x00e89da6, 0x00b2dc}, /* U+8766 */ - {0x00e89da8, 0x00e9fc}, /* U+8768 */ - {0x00e89daa, 0x00eaa3}, /* U+876A */ - {0x00e89dae, 0x00e9fd}, /* U+876E */ - {0x00e89db1, 0x00fbda}, /* U+8771 [2000] */ - {0x00e89db2, 0x8ff7e2}, /* U+8772 [2000] */ - {0x00e89db4, 0x00e9fa}, /* U+8774 */ - {0x00e89db6, 0x00c4b3}, /* U+8776 */ - {0x00e89db8, 0x00e9f7}, /* U+8778 */ - {0x00e89dbc, 0x8ff7e3}, /* U+877C [2000] */ - {0x00e89dbf, 0x00c7e8}, /* U+877F */ - {0x00e89e82, 0x00eaa7}, /* U+8782 */ - {0x00e89e87, 0x00fbdb}, /* U+8787 [2000] */ - {0x00e89e88, 0x00fbdc}, /* U+8788 [2000] */ - {0x00e89e89, 0x8ff7e7}, /* U+8789 [2000] */ - {0x00e89e8b, 0x8ff7e8}, /* U+878B [2000] */ - {0x00e89e8d, 0x00cdbb}, /* U+878D */ - {0x00e89e93, 0x8ff7e9}, /* U+8793 [2000] */ - {0x00e89e9f, 0x00eaa6}, /* U+879F */ - {0x00e89ea0, 0x8ff7ea}, /* U+87A0 [2000] */ - {0x00e89ea2, 0x00eaa5}, /* U+87A2 */ - {0x00e89ea7, 0x8ff7e6}, /* U+87A7 [2000] */ - {0x00e89eab, 0x00eaae}, /* U+87AB */ - {0x00e89eac, 0x00fbdd}, /* U+87AC [2000] */ - {0x00e89ead, 0x00fbde}, /* U+87AD [2000] */ - {0x00e89eaf, 0x00eaa8}, /* U+87AF */ - {0x00e89eb3, 0x00eab0}, /* U+87B3 */ - {0x00e89eb5, 0x00fbdf}, /* U+87B5 [2000] */ - {0x00e89eba, 0x00cde6}, /* U+87BA */ - {0x00e89ebb, 0x00eab3}, /* U+87BB */ - {0x00e89ebd, 0x00eaaa}, /* U+87BD */ - {0x00e89ebe, 0x8ff7ed}, /* U+87BE [2000] */ - {0x00e89f80, 0x00eaab}, /* U+87C0 */ - {0x00e89f81, 0x8ff7ef}, /* U+87C1 [2000] */ - {0x00e89f84, 0x00eaaf}, /* U+87C4 */ - {0x00e89f86, 0x00eab2}, /* U+87C6 */ - {0x00e89f87, 0x00eab1}, /* U+87C7 */ - {0x00e89f8b, 0x00eaa9}, /* U+87CB */ - {0x00e89f8e, 0x8ff7f0}, /* U+87CE [2000] */ - {0x00e89f90, 0x00eaac}, /* U+87D0 */ - {0x00e89f92, 0x00eabd}, /* U+87D2 */ - {0x00e89f96, 0x00fbe1}, /* U+87D6 [2000] */ - {0x00e89f9f, 0x8ff7f2}, /* U+87DF [2000] */ - {0x00e89fa0, 0x00eab6}, /* U+87E0 */ - {0x00e89fa3, 0x8ff7f4}, /* U+87E3 [2000] */ - {0x00e89fa5, 0x8ff7f5}, /* U+87E5 [2000] */ - {0x00e89fa6, 0x8ff7f6}, /* U+87E6 [2000] */ - {0x00e89faa, 0x8ff7f7}, /* U+87EA [2000] */ - {0x00e89fab, 0x8ff7f8}, /* U+87EB [2000] */ - {0x00e89fac, 0x00fbe2}, /* U+87EC [2000] */ - {0x00e89fad, 0x8ff7f9}, /* U+87ED [2000] */ - {0x00e89faf, 0x00eab4}, /* U+87EF */ - {0x00e89fb2, 0x00eab5}, /* U+87F2 */ - {0x00e89fb5, 0x8ff7f1}, /* U+87F5 [2000] */ - {0x00e89fb6, 0x00eaba}, /* U+87F6 */ - {0x00e89fb7, 0x00eabb}, /* U+87F7 */ - {0x00e89fb9, 0x00b3aa}, /* U+87F9 */ - {0x00e89fbb, 0x00b5c2}, /* U+87FB */ - {0x00e89fbe, 0x00eab9}, /* U+87FE */ - {0x00e8a081, 0x8ff7fa}, /* U+8801 [2000] */ - {0x00e8a083, 0x8ff7fb}, /* U+8803 [2000] */ - {0x00e8a085, 0x00eaa4}, /* U+8805 */ - {0x00e8a086, 0x00fbe3}, /* U+8806 [2000] */ - {0x00e8a08a, 0x00fbe4}, /* U+880A [2000] */ - {0x00e8a08b, 0x8ff7fc}, /* U+880B [2000] */ - {0x00e8a08d, 0x00eab8}, /* U+880D */ - {0x00e8a08e, 0x00eabc}, /* U+880E */ - {0x00e8a08f, 0x00eab7}, /* U+880F */ - {0x00e8a090, 0x00fbe5}, /* U+8810 [2000] */ - {0x00e8a091, 0x00eabe}, /* U+8811 */ - {0x00e8a093, 0x8ff7fd}, /* U+8813 [2000] */ - {0x00e8a094, 0x00fbe6}, /* U+8814 [2000] */ - {0x00e8a095, 0x00eac0}, /* U+8815 */ - {0x00e8a096, 0x00eabf}, /* U+8816 */ - {0x00e8a09f, 0x00fbe7}, /* U+881F [2000] */ - {0x00e8a0a1, 0x00eac2}, /* U+8821 */ - {0x00e8a0a2, 0x00eac1}, /* U+8822 */ - {0x00e8a0a3, 0x00e9da}, /* U+8823 */ - {0x00e8a0a7, 0x00eac6}, /* U+8827 */ - {0x00e8a0a8, 0x8ff7fe}, /* U+8828 [2000] */ - {0x00e8a0ae, 0x8ff8a1}, /* U+882E [2000] */ - {0x00e8a0b1, 0x00eac3}, /* U+8831 */ - {0x00e8a0b2, 0x8ff8a2}, /* U+8832 [2000] */ - {0x00e8a0b6, 0x00eac4}, /* U+8836 */ - {0x00e8a0b9, 0x00eac5}, /* U+8839 */ - {0x00e8a0bb, 0x00eac7}, /* U+883B */ - {0x00e8a0bc, 0x8ff8a3}, /* U+883C [2000] */ - {0x00e8a180, 0x00b7ec}, /* U+8840 */ - {0x00e8a182, 0x00eac9}, /* U+8842 */ - {0x00e8a184, 0x00eac8}, /* U+8844 */ - {0x00e8a186, 0x00bdb0}, /* U+8846 */ - {0x00e8a18a, 0x8ff8a5}, /* U+884A [2000] */ - {0x00e8a18c, 0x00b9d4}, /* U+884C */ - {0x00e8a18d, 0x00dea7}, /* U+884D */ - {0x00e8a192, 0x00eaca}, /* U+8852 */ - {0x00e8a193, 0x00bdd1}, /* U+8853 */ - {0x00e8a197, 0x00b3b9}, /* U+8857 */ - {0x00e8a198, 0x8ff8a6}, /* U+8858 [2000] */ - {0x00e8a199, 0x00eacb}, /* U+8859 */ - {0x00e8a19b, 0x00b1d2}, /* U+885B */ - {0x00e8a19d, 0x00bed7}, /* U+885D */ - {0x00e8a19e, 0x00eacc}, /* U+885E */ - {0x00e8a19f, 0x8ff8a7}, /* U+885F [2000] */ - {0x00e8a1a1, 0x00b9d5}, /* U+8861 */ - {0x00e8a1a2, 0x00eacd}, /* U+8862 */ - {0x00e8a1a3, 0x00b0e1}, /* U+8863 */ - {0x00e8a1a4, 0x8ff8a8}, /* U+8864 [2000] */ - {0x00e8a1a8, 0x00c9bd}, /* U+8868 */ - {0x00e8a1a9, 0x8ff8ab}, /* U+8869 [2000] */ - {0x00e8a1ab, 0x00eace}, /* U+886B */ - {0x00e8a1af, 0x8ff8ad}, /* U+886F [2000] */ - {0x00e8a1b0, 0x00bfea}, /* U+8870 */ - {0x00e8a1b2, 0x00ead5}, /* U+8872 */ - {0x00e8a1b5, 0x00ead2}, /* U+8875 */ - {0x00e8a1b7, 0x00c3ef}, /* U+8877 */ - {0x00e8a1bd, 0x00ead3}, /* U+887D */ - {0x00e8a1be, 0x00ead0}, /* U+887E */ - {0x00e8a1bf, 0x00b6de}, /* U+887F */ - {0x00e8a281, 0x00eacf}, /* U+8881 */ - {0x00e8a282, 0x00ead6}, /* U+8882 */ - {0x00e8a288, 0x00b7b6}, /* U+8888 */ - {0x00e8a28b, 0x00c2de}, /* U+888B */ - {0x00e8a28d, 0x00eadc}, /* U+888D */ - {0x00e8a292, 0x00ead8}, /* U+8892 */ - {0x00e8a296, 0x00c2b5}, /* U+8896 */ - {0x00e8a297, 0x00ead7}, /* U+8897 */ - {0x00e8a298, 0x00fbe8}, /* U+8898 [2000] */ - {0x00e8a299, 0x00eada}, /* U+8899 */ - {0x00e8a29e, 0x00ead1}, /* U+889E */ - {0x00e8a2a0, 0x8ff8ae}, /* U+88A0 [2000] */ - {0x00e8a2a2, 0x00eadb}, /* U+88A2 */ - {0x00e8a2a4, 0x00eadd}, /* U+88A4 */ - {0x00e8a2aa, 0x00fbe9}, /* U+88AA [2000] */ - {0x00e8a2ab, 0x00c8ef}, /* U+88AB */ - {0x00e8a2ae, 0x00ead9}, /* U+88AE */ - {0x00e8a2b0, 0x00eade}, /* U+88B0 */ - {0x00e8a2b1, 0x00eae0}, /* U+88B1 */ - {0x00e8a2b4, 0x00b8d3}, /* U+88B4 */ - {0x00e8a2b5, 0x00ead4}, /* U+88B5 */ - {0x00e8a2b7, 0x00b0c1}, /* U+88B7 */ - {0x00e8a2bc, 0x8ff8af}, /* U+88BC [2000] */ - {0x00e8a2bd, 0x8ff8b0}, /* U+88BD [2000] */ - {0x00e8a2be, 0x8ff8b1}, /* U+88BE [2000] */ - {0x00e8a2bf, 0x00eadf}, /* U+88BF */ - {0x00e8a380, 0x8ff8b2}, /* U+88C0 [2000] */ - {0x00e8a381, 0x00badb}, /* U+88C1 */ - {0x00e8a382, 0x00cef6}, /* U+88C2 */ - {0x00e8a383, 0x00eae1}, /* U+88C3 */ - {0x00e8a384, 0x00eae2}, /* U+88C4 */ - {0x00e8a385, 0x00c1f5}, /* U+88C5 */ - {0x00e8a38a, 0x00fbea}, /* U+88CA [2000] */ - {0x00e8a38e, 0x00fbeb}, /* U+88CE [2000] */ - {0x00e8a38f, 0x00cea2}, /* U+88CF */ - {0x00e8a391, 0x8ff8b5}, /* U+88D1 [2000] */ - {0x00e8a392, 0x8ff8b3}, /* U+88D2 [2000] */ - {0x00e8a393, 0x8ff8b6}, /* U+88D3 [2000] */ - {0x00e8a394, 0x00eae3}, /* U+88D4 */ - {0x00e8a395, 0x00cdb5}, /* U+88D5 */ - {0x00e8a398, 0x00eae4}, /* U+88D8 */ - {0x00e8a399, 0x00eae5}, /* U+88D9 */ - {0x00e8a39b, 0x8ff8b7}, /* U+88DB [2000] */ - {0x00e8a39c, 0x00cae4}, /* U+88DC */ - {0x00e8a39d, 0x00eae6}, /* U+88DD */ - {0x00e8a39f, 0x00bac0}, /* U+88DF */ - {0x00e8a3a1, 0x00cea3}, /* U+88E1 */ - {0x00e8a3a8, 0x00eaeb}, /* U+88E8 */ - {0x00e8a3b0, 0x8ff8b8}, /* U+88F0 [2000] */ - {0x00e8a3b1, 0x8ff8b9}, /* U+88F1 [2000] */ - {0x00e8a3b2, 0x00eaec}, /* U+88F2 */ - {0x00e8a3b3, 0x00bed8}, /* U+88F3 */ - {0x00e8a3b4, 0x00eaea}, /* U+88F4 */ - {0x00e8a3b5, 0x00fbed}, /* U+88F5 [2000] */ - {0x00e8a3b8, 0x00cde7}, /* U+88F8 */ - {0x00e8a3b9, 0x00eae7}, /* U+88F9 */ - {0x00e8a3bc, 0x00eae9}, /* U+88FC */ - {0x00e8a3bd, 0x00c0bd}, /* U+88FD */ - {0x00e8a3be, 0x00bffe}, /* U+88FE */ - {0x00e8a481, 0x8ff8bb}, /* U+8901 [2000] */ - {0x00e8a482, 0x00eae8}, /* U+8902 */ - {0x00e8a484, 0x00eaed}, /* U+8904 */ - {0x00e8a487, 0x00caa3}, /* U+8907 */ - {0x00e8a48a, 0x00eaef}, /* U+890A */ - {0x00e8a48c, 0x00eaee}, /* U+890C */ - {0x00e8a490, 0x00b3ec}, /* U+8910 */ - {0x00e8a492, 0x00cbab}, /* U+8912 */ - {0x00e8a493, 0x00eaf0}, /* U+8913 */ - {0x00e8a498, 0x00fbf0}, /* U+8918 [2000] */ - {0x00e8a499, 0x00fbf1}, /* U+8919 [2000] */ - {0x00e8a49a, 0x00fbf2}, /* U+891A [2000] */ - {0x00e8a49c, 0x00fbee}, /* U+891C [2000] */ - {0x00e8a49d, 0x00eafc}, /* U+891D */ - {0x00e8a49e, 0x00eaf2}, /* U+891E */ - {0x00e8a4a5, 0x00eaf3}, /* U+8925 */ - {0x00e8a4a7, 0x00fbf3}, /* U+8927 [2000] */ - {0x00e8a4aa, 0x00eaf4}, /* U+892A */ - {0x00e8a4ab, 0x00eaf5}, /* U+892B */ - {0x00e8a4b0, 0x00fbf4}, /* U+8930 [2000] */ - {0x00e8a4b2, 0x00fbf5}, /* U+8932 [2000] */ - {0x00e8a4b6, 0x00eaf9}, /* U+8936 */ - {0x00e8a4b7, 0x8ff8bd}, /* U+8937 [2000] */ - {0x00e8a4b8, 0x00eafa}, /* U+8938 */ - {0x00e8a4b9, 0x00fbf6}, /* U+8939 [2000] */ - {0x00e8a4bb, 0x00eaf8}, /* U+893B */ - {0x00e8a580, 0x00fbf7}, /* U+8940 [2000] */ - {0x00e8a581, 0x00eaf6}, /* U+8941 */ - {0x00e8a582, 0x8ff8bf}, /* U+8942 [2000] */ - {0x00e8a583, 0x00eaf1}, /* U+8943 */ - {0x00e8a584, 0x00eaf7}, /* U+8944 */ - {0x00e8a585, 0x8ff8c0}, /* U+8945 [2000] */ - {0x00e8a589, 0x8ff8c1}, /* U+8949 [2000] */ - {0x00e8a58c, 0x00eafb}, /* U+894C */ - {0x00e8a58d, 0x00f0b7}, /* U+894D */ - {0x00e8a596, 0x00b2a8}, /* U+8956 */ - {0x00e8a59e, 0x00eafe}, /* U+895E */ - {0x00e8a59f, 0x00b6df}, /* U+895F */ - {0x00e8a5a0, 0x00eafd}, /* U+8960 */ - {0x00e8a5a2, 0x8ff8c4}, /* U+8962 [2000] */ - {0x00e8a5a4, 0x00eba2}, /* U+8964 */ - {0x00e8a5a6, 0x00eba1}, /* U+8966 */ - {0x00e8a5aa, 0x00eba4}, /* U+896A */ - {0x00e8a5ad, 0x00eba3}, /* U+896D */ - {0x00e8a5af, 0x00eba5}, /* U+896F */ - {0x00e8a5b2, 0x00bdb1}, /* U+8972 */ - {0x00e8a5b4, 0x00eba6}, /* U+8974 */ - {0x00e8a5b7, 0x00eba7}, /* U+8977 */ - {0x00e8a5be, 0x00eba8}, /* U+897E */ - {0x00e8a5bf, 0x00c0be}, /* U+897F */ - {0x00e8a680, 0x8ff8c5}, /* U+8980 [2000] */ - {0x00e8a681, 0x00cdd7}, /* U+8981 */ - {0x00e8a683, 0x00eba9}, /* U+8983 */ - {0x00e8a686, 0x00caa4}, /* U+8986 */ - {0x00e8a687, 0x00c7c6}, /* U+8987 */ - {0x00e8a688, 0x00ebaa}, /* U+8988 */ - {0x00e8a689, 0x8ff8c6}, /* U+8989 [2000] */ - {0x00e8a68a, 0x00ebab}, /* U+898A */ - {0x00e8a68b, 0x00b8ab}, /* U+898B */ - {0x00e8a68f, 0x00b5ac}, /* U+898F */ - {0x00e8a690, 0x8ff8c7}, /* U+8990 [2000] */ - {0x00e8a693, 0x00ebac}, /* U+8993 */ - {0x00e8a694, 0x00fbf8}, /* U+8994 [2000] */ - {0x00e8a696, 0x00bbeb}, /* U+8996 */ - {0x00e8a697, 0x00c7c1}, /* U+8997 */ - {0x00e8a698, 0x00ebad}, /* U+8998 */ - {0x00e8a69a, 0x00b3d0}, /* U+899A */ - {0x00e8a69f, 0x8ff8c8}, /* U+899F [2000] */ - {0x00e8a6a1, 0x00ebae}, /* U+89A1 */ - {0x00e8a6a6, 0x00ebb0}, /* U+89A6 */ - {0x00e8a6a7, 0x00cdf7}, /* U+89A7 */ - {0x00e8a6a9, 0x00ebaf}, /* U+89A9 */ - {0x00e8a6aa, 0x00bfc6}, /* U+89AA */ - {0x00e8a6ac, 0x00ebb1}, /* U+89AC */ - {0x00e8a6af, 0x00ebb2}, /* U+89AF */ - {0x00e8a6b0, 0x8ff8c9}, /* U+89B0 [2000] */ - {0x00e8a6b2, 0x00ebb3}, /* U+89B2 */ - {0x00e8a6b3, 0x00b4d1}, /* U+89B3 */ - {0x00e8a6b7, 0x8ff8ca}, /* U+89B7 [2000] */ - {0x00e8a6ba, 0x00ebb4}, /* U+89BA */ - {0x00e8a6bd, 0x00ebb5}, /* U+89BD */ - {0x00e8a6bf, 0x00ebb6}, /* U+89BF */ - {0x00e8a780, 0x00ebb7}, /* U+89C0 */ - {0x00e8a792, 0x00b3d1}, /* U+89D2 */ - {0x00e8a794, 0x00fbfa}, /* U+89D4 [2000] */ - {0x00e8a796, 0x8ff8cb}, /* U+89D6 [2000] */ - {0x00e8a798, 0x8ff8cc}, /* U+89D8 [2000] */ - {0x00e8a79a, 0x00ebb8}, /* U+89DA */ - {0x00e8a79c, 0x00ebb9}, /* U+89DC */ - {0x00e8a79d, 0x00ebba}, /* U+89DD */ - {0x00e8a7a3, 0x00b2f2}, /* U+89E3 */ - {0x00e8a7a5, 0x00fbfb}, /* U+89E5 [2000] */ - {0x00e8a7a6, 0x00bfa8}, /* U+89E6 */ - {0x00e8a7a7, 0x00ebbb}, /* U+89E7 */ - {0x00e8a7ab, 0x8ff8cd}, /* U+89EB [2000] */ - {0x00e8a7b1, 0x8ff8cf}, /* U+89F1 [2000] */ - {0x00e8a7b3, 0x8ff8d0}, /* U+89F3 [2000] */ - {0x00e8a7b4, 0x00ebbc}, /* U+89F4 */ - {0x00e8a7b6, 0x00fbfc}, /* U+89F6 [2000] */ - {0x00e8a7b8, 0x00ebbd}, /* U+89F8 */ - {0x00e8a7bd, 0x8ff8d1}, /* U+89FD [2000] */ - {0x00e8a7bf, 0x8ff8d2}, /* U+89FF [2000] */ - {0x00e8a880, 0x00b8c0}, /* U+8A00 */ - {0x00e8a882, 0x00c4fb}, /* U+8A02 */ - {0x00e8a883, 0x00ebbe}, /* U+8A03 */ - {0x00e8a888, 0x00b7d7}, /* U+8A08 */ - {0x00e8a88a, 0x00bfd6}, /* U+8A0A */ - {0x00e8a88c, 0x00ebc1}, /* U+8A0C */ - {0x00e8a88e, 0x00c6a4}, /* U+8A0E */ - {0x00e8a890, 0x00ebc0}, /* U+8A10 */ - {0x00e8a891, 0x8ff8d4}, /* U+8A11 [2000] */ - {0x00e8a892, 0x00fbfd}, /* U+8A12 [2000] */ - {0x00e8a893, 0x00b7b1}, /* U+8A13 */ - {0x00e8a894, 0x8ff8d5}, /* U+8A14 [2000] */ - {0x00e8a895, 0x00fbfe}, /* U+8A15 [2000] */ - {0x00e8a896, 0x00ebbf}, /* U+8A16 */ - {0x00e8a897, 0x00c2f7}, /* U+8A17 */ - {0x00e8a898, 0x00b5ad}, /* U+8A18 */ - {0x00e8a89b, 0x00ebc2}, /* U+8A1B */ - {0x00e8a89d, 0x00ebc3}, /* U+8A1D */ - {0x00e8a89f, 0x00bed9}, /* U+8A1F */ - {0x00e8a8a1, 0x8ff8d7}, /* U+8A21 [2000] */ - {0x00e8a8a2, 0x00fca1}, /* U+8A22 [2000] */ - {0x00e8a8a3, 0x00b7ed}, /* U+8A23 */ - {0x00e8a8a5, 0x00ebc4}, /* U+8A25 */ - {0x00e8a8aa, 0x00cbac}, /* U+8A2A */ - {0x00e8a8ad, 0x00c0df}, /* U+8A2D */ - {0x00e8a8b1, 0x00b5f6}, /* U+8A31 */ - {0x00e8a8b3, 0x00ccf5}, /* U+8A33 */ - {0x00e8a8b4, 0x00c1ca}, /* U+8A34 */ - {0x00e8a8b5, 0x8ff8d8}, /* U+8A35 [2000] */ - {0x00e8a8b6, 0x00ebc5}, /* U+8A36 */ - {0x00e8a8b7, 0x00fca2}, /* U+8A37 [2000] */ - {0x00e8a8ba, 0x00bfc7}, /* U+8A3A */ - {0x00e8a8bb, 0x00c3f0}, /* U+8A3B */ - {0x00e8a8bc, 0x00beda}, /* U+8A3C */ - {0x00e8a8be, 0x8ff8d9}, /* U+8A3E [2000] */ - {0x00e8a981, 0x00ebc6}, /* U+8A41 */ - {0x00e8a985, 0x8ff8da}, /* U+8A45 [2000] */ - {0x00e8a986, 0x00ebc9}, /* U+8A46 */ - {0x00e8a987, 0x00fca3}, /* U+8A47 [2000] */ - {0x00e8a988, 0x00ebca}, /* U+8A48 */ - {0x00e8a98d, 0x8ff8db}, /* U+8A4D [2000] */ - {0x00e8a98e, 0x00fca4}, /* U+8A4E [2000] */ - {0x00e8a990, 0x00babe}, /* U+8A50 */ - {0x00e8a991, 0x00c2c2}, /* U+8A51 */ - {0x00e8a992, 0x00ebc8}, /* U+8A52 */ - {0x00e8a994, 0x00bedb}, /* U+8A54 */ - {0x00e8a995, 0x00c9be}, /* U+8A55 */ - {0x00e8a998, 0x8ff8dc}, /* U+8A58 [2000] */ - {0x00e8a99b, 0x00ebc7}, /* U+8A5B */ - {0x00e8a99d, 0x00fca5}, /* U+8A5D [2000] */ - {0x00e8a99e, 0x00bbec}, /* U+8A5E */ - {0x00e8a9a0, 0x00b1d3}, /* U+8A60 */ - {0x00e8a9a1, 0x00fca6}, /* U+8A61 [2000] */ - {0x00e8a9a2, 0x00ebce}, /* U+8A62 */ - {0x00e8a9a3, 0x00b7d8}, /* U+8A63 */ - {0x00e8a9a6, 0x00bbee}, /* U+8A66 */ - {0x00e8a9a9, 0x00bbed}, /* U+8A69 */ - {0x00e8a9ab, 0x00cfcd}, /* U+8A6B */ - {0x00e8a9ac, 0x00ebcd}, /* U+8A6C */ - {0x00e8a9ad, 0x00ebcc}, /* U+8A6D */ - {0x00e8a9ae, 0x00c1a7}, /* U+8A6E */ - {0x00e8a9b0, 0x00b5cd}, /* U+8A70 */ - {0x00e8a9b1, 0x00cfc3}, /* U+8A71 */ - {0x00e8a9b2, 0x00b3ba}, /* U+8A72 */ - {0x00e8a9b3, 0x00bedc}, /* U+8A73 */ - {0x00e8a9b5, 0x00fca7}, /* U+8A75 [2000] */ - {0x00e8a9b9, 0x00fca8}, /* U+8A79 [2000] */ - {0x00e8a9bc, 0x00ebcb}, /* U+8A7C */ - {0x00e8aa82, 0x00ebd0}, /* U+8A82 */ - {0x00e8aa84, 0x00ebd1}, /* U+8A84 */ - {0x00e8aa85, 0x00ebcf}, /* U+8A85 */ - {0x00e8aa87, 0x00b8d8}, /* U+8A87 */ - {0x00e8aa89, 0x00cdc0}, /* U+8A89 */ - {0x00e8aa8c, 0x00bbef}, /* U+8A8C */ - {0x00e8aa8d, 0x00c7a7}, /* U+8A8D */ - {0x00e8aa90, 0x8ff8de}, /* U+8A90 [2000] */ - {0x00e8aa91, 0x00ebd4}, /* U+8A91 */ - {0x00e8aa93, 0x00c0c0}, /* U+8A93 */ - {0x00e8aa95, 0x00c3c2}, /* U+8A95 */ - {0x00e8aa98, 0x00cdb6}, /* U+8A98 */ - {0x00e8aa9a, 0x00ebd7}, /* U+8A9A */ - {0x00e8aa9e, 0x00b8ec}, /* U+8A9E */ - {0x00e8aaa0, 0x00c0bf}, /* U+8AA0 */ - {0x00e8aaa1, 0x00ebd3}, /* U+8AA1 */ - {0x00e8aaa3, 0x00ebd8}, /* U+8AA3 */ - {0x00e8aaa4, 0x00b8ed}, /* U+8AA4 */ - {0x00e8aaa5, 0x00ebd5}, /* U+8AA5 */ - {0x00e8aaa6, 0x00ebd6}, /* U+8AA6 */ - {0x00e8aaa7, 0x00fca9}, /* U+8AA7 [2000] */ - {0x00e8aaa8, 0x00ebd2}, /* U+8AA8 */ - {0x00e8aaac, 0x00c0e2}, /* U+8AAC */ - {0x00e8aaad, 0x00c6c9}, /* U+8AAD */ - {0x00e8aaae, 0x8ff8dd}, /* U+8AAE [2000] */ - {0x00e8aab0, 0x00c3af}, /* U+8AB0 */ - {0x00e8aab2, 0x00b2dd}, /* U+8AB2 */ - {0x00e8aab7, 0x8ff8df}, /* U+8AB7 [2000] */ - {0x00e8aab9, 0x00c8f0}, /* U+8AB9 */ - {0x00e8aabc, 0x00b5c3}, /* U+8ABC */ - {0x00e8aabe, 0x8ff8e0}, /* U+8ABE [2000] */ - {0x00e8aabf, 0x00c4b4}, /* U+8ABF */ - {0x00e8ab82, 0x00ebdb}, /* U+8AC2 */ - {0x00e8ab84, 0x00ebd9}, /* U+8AC4 */ - {0x00e8ab87, 0x00c3cc}, /* U+8AC7 */ - {0x00e8ab8b, 0x00c0c1}, /* U+8ACB */ - {0x00e8ab8c, 0x00b4d2}, /* U+8ACC */ - {0x00e8ab8d, 0x00ebda}, /* U+8ACD */ - {0x00e8ab8f, 0x00bfdb}, /* U+8ACF */ - {0x00e8ab90, 0x00fcaa}, /* U+8AD0 [2000] */ - {0x00e8ab92, 0x00ceca}, /* U+8AD2 */ - {0x00e8ab96, 0x00cfc0}, /* U+8AD6 */ - {0x00e8ab97, 0x8ff8e1}, /* U+8AD7 [2000] */ - {0x00e8ab9a, 0x00ebdc}, /* U+8ADA */ - {0x00e8ab9b, 0x00ebe7}, /* U+8ADB */ - {0x00e8ab9c, 0x00c4b5}, /* U+8ADC */ - {0x00e8ab9e, 0x00ebe6}, /* U+8ADE */ - {0x00e8ab9f, 0x00fcab}, /* U+8ADF [2000] */ - {0x00e8aba0, 0x00ebe3}, /* U+8AE0 */ - {0x00e8aba1, 0x00ebeb}, /* U+8AE1 */ - {0x00e8aba2, 0x00ebe4}, /* U+8AE2 */ - {0x00e8aba4, 0x00ebe0}, /* U+8AE4 */ - {0x00e8aba6, 0x00c4fc}, /* U+8AE6 */ - {0x00e8aba7, 0x00ebdf}, /* U+8AE7 */ - {0x00e8abab, 0x00ebdd}, /* U+8AEB */ - {0x00e8abad, 0x00cda1}, /* U+8AED */ - {0x00e8abae, 0x00bbf0}, /* U+8AEE */ - {0x00e8abb1, 0x00ebe1}, /* U+8AF1 */ - {0x00e8abb3, 0x00ebde}, /* U+8AF3 */ - {0x00e8abb4, 0x00fcac}, /* U+8AF4 [2000] */ - {0x00e8abb6, 0x00fcad}, /* U+8AF6 [2000] */ - {0x00e8abb7, 0x00ebe5}, /* U+8AF7 */ - {0x00e8abb8, 0x00bdf4}, /* U+8AF8 */ - {0x00e8abba, 0x00b8c1}, /* U+8AFA */ - {0x00e8abbc, 0x8ff8e2}, /* U+8AFC [2000] */ - {0x00e8abbe, 0x00c2fa}, /* U+8AFE */ - {0x00e8ac80, 0x00cbc5}, /* U+8B00 */ - {0x00e8ac81, 0x00b1da}, /* U+8B01 */ - {0x00e8ac82, 0x00b0e2}, /* U+8B02 */ - {0x00e8ac84, 0x00c6a5}, /* U+8B04 */ - {0x00e8ac85, 0x8ff8e5}, /* U+8B05 [2000] */ - {0x00e8ac87, 0x00ebe9}, /* U+8B07 */ - {0x00e8ac8a, 0x8ff8e4}, /* U+8B0A [2000] */ - {0x00e8ac8c, 0x00ebe8}, /* U+8B0C */ - {0x00e8ac8d, 0x8ff8e6}, /* U+8B0D [2000] */ - {0x00e8ac8e, 0x00c6e6}, /* U+8B0E */ - {0x00e8ac90, 0x00ebed}, /* U+8B10 */ - {0x00e8ac94, 0x00ebe2}, /* U+8B14 */ - {0x00e8ac96, 0x00ebec}, /* U+8B16 */ - {0x00e8ac97, 0x00ebee}, /* U+8B17 */ - {0x00e8ac99, 0x00b8ac}, /* U+8B19 */ - {0x00e8ac9a, 0x00ebea}, /* U+8B1A */ - {0x00e8ac9b, 0x00b9d6}, /* U+8B1B */ - {0x00e8ac9c, 0x8ff8e7}, /* U+8B1C [2000] */ - {0x00e8ac9d, 0x00bcd5}, /* U+8B1D */ - {0x00e8ac9f, 0x8ff8e8}, /* U+8B1F [2000] */ - {0x00e8aca0, 0x00ebef}, /* U+8B20 */ - {0x00e8aca1, 0x00cdd8}, /* U+8B21 */ - {0x00e8aca6, 0x00ebf2}, /* U+8B26 */ - {0x00e8aca8, 0x00ebf5}, /* U+8B28 */ - {0x00e8acab, 0x00ebf3}, /* U+8B2B */ - {0x00e8acac, 0x00c9b5}, /* U+8B2C */ - {0x00e8acad, 0x8ff8e9}, /* U+8B2D [2000] */ - {0x00e8acb3, 0x00ebf0}, /* U+8B33 */ - {0x00e8acb9, 0x00b6e0}, /* U+8B39 */ - {0x00e8acbe, 0x00ebf4}, /* U+8B3E */ - {0x00e8ad81, 0x00ebf6}, /* U+8B41 */ - {0x00e8ad83, 0x8ff8ea}, /* U+8B43 [2000] */ - {0x00e8ad86, 0x00fcb1}, /* U+8B46 [2000] */ - {0x00e8ad89, 0x00ebfa}, /* U+8B49 */ - {0x00e8ad8c, 0x00ebf7}, /* U+8B4C */ - {0x00e8ad8e, 0x00ebf9}, /* U+8B4E */ - {0x00e8ad8f, 0x00ebf8}, /* U+8B4F */ - {0x00e8ad91, 0x8ff8ec}, /* U+8B51 [2000] */ - {0x00e8ad94, 0x00fcb2}, /* U+8B54 [2000] */ - {0x00e8ad96, 0x00ebfb}, /* U+8B56 */ - {0x00e8ad98, 0x00bcb1}, /* U+8B58 */ - {0x00e8ad99, 0x00fcb3}, /* U+8B59 [2000] */ - {0x00e8ad9a, 0x00ebfd}, /* U+8B5A */ - {0x00e8ad9b, 0x00ebfc}, /* U+8B5B */ - {0x00e8ad9c, 0x00c9e8}, /* U+8B5C */ - {0x00e8ad9e, 0x8ff8ed}, /* U+8B5E [2000] */ - {0x00e8ad9f, 0x00eca1}, /* U+8B5F */ - {0x00e8ada6, 0x00b7d9}, /* U+8B66 */ - {0x00e8ada9, 0x00fcb4}, /* U+8B69 [2000] */ - {0x00e8adab, 0x00ebfe}, /* U+8B6B */ - {0x00e8adac, 0x00eca2}, /* U+8B6C */ - {0x00e8adaf, 0x00eca3}, /* U+8B6F */ - {0x00e8adb0, 0x00b5c4}, /* U+8B70 */ - {0x00e8adb1, 0x00e6c1}, /* U+8B71 */ - {0x00e8adb2, 0x00bef9}, /* U+8B72 */ - {0x00e8adb4, 0x00eca4}, /* U+8B74 */ - {0x00e8adb6, 0x8ff8ee}, /* U+8B76 [2000] */ - {0x00e8adb7, 0x00b8ee}, /* U+8B77 */ - {0x00e8adbd, 0x00eca5}, /* U+8B7D */ - {0x00e8adbf, 0x8ff8ef}, /* U+8B7F [2000] */ - {0x00e8ae80, 0x00eca6}, /* U+8B80 */ - {0x00e8ae81, 0x8ff8f0}, /* U+8B81 [2000] */ - {0x00e8ae83, 0x00bbbe}, /* U+8B83 */ - {0x00e8ae8a, 0x00dace}, /* U+8B8A */ - {0x00e8ae8b, 0x8ff8f1}, /* U+8B8B [2000] */ - {0x00e8ae8c, 0x00eca7}, /* U+8B8C */ - {0x00e8ae8e, 0x00eca8}, /* U+8B8E */ - {0x00e8ae90, 0x00bdb2}, /* U+8B90 */ - {0x00e8ae92, 0x00eca9}, /* U+8B92 */ - {0x00e8ae93, 0x00ecaa}, /* U+8B93 */ - {0x00e8ae94, 0x8ff8f2}, /* U+8B94 [2000] */ - {0x00e8ae95, 0x8ff8f3}, /* U+8B95 [2000] */ - {0x00e8ae96, 0x00ecab}, /* U+8B96 */ - {0x00e8ae99, 0x00ecac}, /* U+8B99 */ - {0x00e8ae9a, 0x00ecad}, /* U+8B9A */ - {0x00e8ae9c, 0x8ff8f4}, /* U+8B9C [2000] */ - {0x00e8ae9d, 0x00fcb5}, /* U+8B9D [2000] */ - {0x00e8ae9e, 0x8ff8f5}, /* U+8B9E [2000] */ - {0x00e8b0b7, 0x00c3ab}, /* U+8C37 */ - {0x00e8b0b9, 0x8ff8f6}, /* U+8C39 [2000] */ - {0x00e8b0ba, 0x00ecae}, /* U+8C3A */ - {0x00e8b0bd, 0x8ff8f8}, /* U+8C3D [2000] */ - {0x00e8b0bf, 0x00ecb0}, /* U+8C3F */ - {0x00e8b181, 0x00ecaf}, /* U+8C41 */ - {0x00e8b185, 0x8ff8fb}, /* U+8C45 [2000] */ - {0x00e8b186, 0x00c6a6}, /* U+8C46 */ - {0x00e8b187, 0x8ff8fc}, /* U+8C47 [2000] */ - {0x00e8b188, 0x00ecb1}, /* U+8C48 */ - {0x00e8b189, 0x00fcb6}, /* U+8C49 [2000] */ - {0x00e8b18a, 0x00cbad}, /* U+8C4A */ - {0x00e8b18c, 0x00ecb2}, /* U+8C4C */ - {0x00e8b18e, 0x00ecb3}, /* U+8C4E */ - {0x00e8b18f, 0x8ff8fd}, /* U+8C4F [2000] */ - {0x00e8b190, 0x00ecb4}, /* U+8C50 */ - {0x00e8b194, 0x8ff8fe}, /* U+8C54 [2000] */ - {0x00e8b195, 0x00ecb5}, /* U+8C55 */ - {0x00e8b197, 0x8ff9a1}, /* U+8C57 [2000] */ - {0x00e8b19a, 0x00c6da}, /* U+8C5A */ - {0x00e8b1a1, 0x00bedd}, /* U+8C61 */ - {0x00e8b1a2, 0x00ecb6}, /* U+8C62 */ - {0x00e8b1a8, 0x00fcb7}, /* U+8C68 [2000] */ - {0x00e8b1a9, 0x8ff9a2}, /* U+8C69 [2000] */ - {0x00e8b1aa, 0x00b9eb}, /* U+8C6A */ - {0x00e8b1ab, 0x00d0ae}, /* U+8C6B */ - {0x00e8b1ac, 0x00ecb7}, /* U+8C6C */ - {0x00e8b1ad, 0x8ff9a3}, /* U+8C6D [2000] */ - {0x00e8b1b3, 0x8ff9a4}, /* U+8C73 [2000] */ - {0x00e8b1b8, 0x00ecb8}, /* U+8C78 */ - {0x00e8b1b9, 0x00c9bf}, /* U+8C79 */ - {0x00e8b1ba, 0x00ecb9}, /* U+8C7A */ - {0x00e8b1bc, 0x00ecc1}, /* U+8C7C */ - {0x00e8b282, 0x00ecba}, /* U+8C82 */ - {0x00e8b285, 0x00ecbc}, /* U+8C85 */ - {0x00e8b289, 0x00ecbb}, /* U+8C89 */ - {0x00e8b28a, 0x00ecbd}, /* U+8C8A */ - {0x00e8b28c, 0x00cbc6}, /* U+8C8C */ - {0x00e8b28d, 0x00ecbe}, /* U+8C8D */ - {0x00e8b28e, 0x00ecbf}, /* U+8C8E */ - {0x00e8b292, 0x8ff9a7}, /* U+8C92 [2000] */ - {0x00e8b293, 0x8ff9a6}, /* U+8C93 [2000] */ - {0x00e8b294, 0x00ecc0}, /* U+8C94 */ - {0x00e8b298, 0x00ecc2}, /* U+8C98 */ - {0x00e8b299, 0x8ff9a8}, /* U+8C99 [2000] */ - {0x00e8b29b, 0x8ff9aa}, /* U+8C9B [2000] */ - {0x00e8b29d, 0x00b3ad}, /* U+8C9D */ - {0x00e8b29e, 0x00c4e7}, /* U+8C9E */ - {0x00e8b2a0, 0x00c9e9}, /* U+8CA0 */ - {0x00e8b2a1, 0x00bae2}, /* U+8CA1 */ - {0x00e8b2a2, 0x00b9d7}, /* U+8CA2 */ - {0x00e8b2a4, 0x8ff9ab}, /* U+8CA4 [2000] */ - {0x00e8b2a7, 0x00c9cf}, /* U+8CA7 */ - {0x00e8b2a8, 0x00b2df}, /* U+8CA8 */ - {0x00e8b2a9, 0x00c8ce}, /* U+8CA9 */ - {0x00e8b2aa, 0x00ecc5}, /* U+8CAA */ - {0x00e8b2ab, 0x00b4d3}, /* U+8CAB */ - {0x00e8b2ac, 0x00c0d5}, /* U+8CAC */ - {0x00e8b2ad, 0x00ecc4}, /* U+8CAD */ - {0x00e8b2ae, 0x00ecc9}, /* U+8CAE */ - {0x00e8b2af, 0x00c3f9}, /* U+8CAF */ - {0x00e8b2b0, 0x00cce3}, /* U+8CB0 */ - {0x00e8b2b2, 0x00ecc7}, /* U+8CB2 */ - {0x00e8b2b3, 0x00ecc8}, /* U+8CB3 */ - {0x00e8b2b4, 0x00b5ae}, /* U+8CB4 */ - {0x00e8b2b6, 0x00ecca}, /* U+8CB6 */ - {0x00e8b2b7, 0x00c7e3}, /* U+8CB7 */ - {0x00e8b2b8, 0x00c2df}, /* U+8CB8 */ - {0x00e8b2bb, 0x00c8f1}, /* U+8CBB */ - {0x00e8b2bc, 0x00c5bd}, /* U+8CBC */ - {0x00e8b2bd, 0x00ecc6}, /* U+8CBD */ - {0x00e8b2bf, 0x00cbc7}, /* U+8CBF */ - {0x00e8b380, 0x00b2ec}, /* U+8CC0 */ - {0x00e8b381, 0x00eccc}, /* U+8CC1 */ - {0x00e8b382, 0x00cfa8}, /* U+8CC2 */ - {0x00e8b383, 0x00c4c2}, /* U+8CC3 */ - {0x00e8b384, 0x00cfc5}, /* U+8CC4 */ - {0x00e8b387, 0x00bbf1}, /* U+8CC7 */ - {0x00e8b388, 0x00eccb}, /* U+8CC8 */ - {0x00e8b38a, 0x00c2b1}, /* U+8CCA */ - {0x00e8b38d, 0x00ecdc}, /* U+8CCD */ - {0x00e8b38e, 0x00c1a8}, /* U+8CCE */ - {0x00e8b391, 0x00c6f8}, /* U+8CD1 */ - {0x00e8b393, 0x00c9d0}, /* U+8CD3 */ - {0x00e8b395, 0x8ff9ad}, /* U+8CD5 [2000] */ - {0x00e8b396, 0x8ff9ac}, /* U+8CD6 [2000] */ - {0x00e8b399, 0x8ff9ae}, /* U+8CD9 [2000] */ - {0x00e8b39a, 0x00eccf}, /* U+8CDA */ - {0x00e8b39b, 0x00bbbf}, /* U+8CDB */ - {0x00e8b39c, 0x00bbf2}, /* U+8CDC */ - {0x00e8b39e, 0x00bede}, /* U+8CDE */ - {0x00e8b3a0, 0x00c7e5}, /* U+8CE0 */ - {0x00e8b3a1, 0x00fcb9}, /* U+8CE1 [2000] */ - {0x00e8b3a2, 0x00b8ad}, /* U+8CE2 */ - {0x00e8b3a3, 0x00ecce}, /* U+8CE3 */ - {0x00e8b3a4, 0x00eccd}, /* U+8CE4 */ - {0x00e8b3a6, 0x00c9ea}, /* U+8CE6 */ - {0x00e8b3aa, 0x00bcc1}, /* U+8CEA */ - {0x00e8b3ad, 0x00c5d2}, /* U+8CED */ - {0x00e8b3b0, 0x8ff9b0}, /* U+8CF0 [2000] */ - {0x00e8b3b1, 0x8ff9b1}, /* U+8CF1 [2000] */ - {0x00e8b3b4, 0x00fcba}, /* U+8CF4 [2000] */ - {0x00e8b3b8, 0x00fcbb}, /* U+8CF8 [2000] */ - {0x00e8b3ba, 0x00ecd1}, /* U+8CFA */ - {0x00e8b3bb, 0x00ecd2}, /* U+8CFB */ - {0x00e8b3bc, 0x00b9d8}, /* U+8CFC */ - {0x00e8b3bd, 0x00ecd0}, /* U+8CFD */ - {0x00e8b3be, 0x00fcbc}, /* U+8CFE [2000] */ - {0x00e8b484, 0x00ecd3}, /* U+8D04 */ - {0x00e8b485, 0x00ecd4}, /* U+8D05 */ - {0x00e8b487, 0x00ecd6}, /* U+8D07 */ - {0x00e8b488, 0x00c2a3}, /* U+8D08 */ - {0x00e8b489, 0x8ff9b3}, /* U+8D09 [2000] */ - {0x00e8b48a, 0x00ecd5}, /* U+8D0A */ - {0x00e8b48b, 0x00b4e6}, /* U+8D0B */ - {0x00e8b48d, 0x00ecd8}, /* U+8D0D */ - {0x00e8b48e, 0x8ff9b4}, /* U+8D0E [2000] */ - {0x00e8b48f, 0x00ecd7}, /* U+8D0F */ - {0x00e8b490, 0x00ecd9}, /* U+8D10 */ - {0x00e8b492, 0x00fcbe}, /* U+8D12 [2000] */ - {0x00e8b493, 0x00ecdb}, /* U+8D13 */ - {0x00e8b494, 0x00ecdd}, /* U+8D14 */ - {0x00e8b496, 0x00ecde}, /* U+8D16 */ - {0x00e8b49b, 0x00fcbf}, /* U+8D1B [2000] */ - {0x00e8b5a4, 0x00c0d6}, /* U+8D64 */ - {0x00e8b5a6, 0x00bccf}, /* U+8D66 */ - {0x00e8b5a7, 0x00ecdf}, /* U+8D67 */ - {0x00e8b5ab, 0x00b3d2}, /* U+8D6B */ - {0x00e8b5ac, 0x8ff9b5}, /* U+8D6C [2000] */ - {0x00e8b5ad, 0x00ece0}, /* U+8D6D */ - {0x00e8b5b0, 0x00c1f6}, /* U+8D70 */ - {0x00e8b5b1, 0x00ece1}, /* U+8D71 */ - {0x00e8b5b3, 0x00ece2}, /* U+8D73 */ - {0x00e8b5b4, 0x00c9eb}, /* U+8D74 */ - {0x00e8b5b7, 0x00b5af}, /* U+8D77 */ - {0x00e8b681, 0x00ece3}, /* U+8D81 */ - {0x00e8b684, 0x8ff9b6}, /* U+8D84 [2000] */ - {0x00e8b685, 0x00c4b6}, /* U+8D85 */ - {0x00e8b68a, 0x00b1db}, /* U+8D8A */ - {0x00e8b695, 0x8ff9b7}, /* U+8D95 [2000] */ - {0x00e8b699, 0x00ece4}, /* U+8D99 */ - {0x00e8b6a3, 0x00bcf1}, /* U+8DA3 */ - {0x00e8b6a6, 0x8ff9b8}, /* U+8DA6 [2000] */ - {0x00e8b6a8, 0x00bff6}, /* U+8DA8 */ - {0x00e8b6af, 0x00fcc0}, /* U+8DAF [2000] */ - {0x00e8b6b3, 0x00c2ad}, /* U+8DB3 */ - {0x00e8b6ba, 0x00ece7}, /* U+8DBA */ - {0x00e8b6be, 0x00ece6}, /* U+8DBE */ - {0x00e8b782, 0x00ece5}, /* U+8DC2 */ - {0x00e8b786, 0x8ff9ba}, /* U+8DC6 [2000] */ - {0x00e8b788, 0x8ff9bb}, /* U+8DC8 [2000] */ - {0x00e8b78b, 0x00eced}, /* U+8DCB */ - {0x00e8b78c, 0x00eceb}, /* U+8DCC */ - {0x00e8b78e, 0x00fcc1}, /* U+8DCE [2000] */ - {0x00e8b78f, 0x00ece8}, /* U+8DCF */ - {0x00e8b791, 0x00fcc2}, /* U+8DD1 [2000] */ - {0x00e8b796, 0x00ecea}, /* U+8DD6 */ - {0x00e8b797, 0x00fcc3}, /* U+8DD7 [2000] */ - {0x00e8b799, 0x8ff9bc}, /* U+8DD9 [2000] */ - {0x00e8b79a, 0x00ece9}, /* U+8DDA */ - {0x00e8b79b, 0x00ecec}, /* U+8DDB */ - {0x00e8b79d, 0x00b5f7}, /* U+8DDD */ - {0x00e8b79f, 0x00ecf0}, /* U+8DDF */ - {0x00e8b7a1, 0x00c0d7}, /* U+8DE1 */ - {0x00e8b7a3, 0x00ecf1}, /* U+8DE3 */ - {0x00e8b7a8, 0x00b8d9}, /* U+8DE8 */ - {0x00e8b7aa, 0x00ecee}, /* U+8DEA */ - {0x00e8b7ab, 0x00ecef}, /* U+8DEB */ - {0x00e8b7ac, 0x8ff9bd}, /* U+8DEC [2000] */ - {0x00e8b7af, 0x00cfa9}, /* U+8DEF */ - {0x00e8b7b3, 0x00c4b7}, /* U+8DF3 */ - {0x00e8b7b5, 0x00c1a9}, /* U+8DF5 */ - {0x00e8b7bc, 0x00ecf2}, /* U+8DFC */ - {0x00e8b7bd, 0x8ff9c0}, /* U+8DFD [2000] */ - {0x00e8b7bf, 0x00ecf5}, /* U+8DFF */ - {0x00e8b886, 0x8ff9c1}, /* U+8E06 [2000] */ - {0x00e8b888, 0x00ecf3}, /* U+8E08 */ - {0x00e8b889, 0x00ecf4}, /* U+8E09 */ - {0x00e8b88a, 0x00cdd9}, /* U+8E0A */ - {0x00e8b88c, 0x8ff9be}, /* U+8E0C [2000] */ - {0x00e8b88f, 0x00c6a7}, /* U+8E0F */ - {0x00e8b890, 0x00ecf8}, /* U+8E10 */ - {0x00e8b894, 0x8ff9c3}, /* U+8E14 [2000] */ - {0x00e8b896, 0x8ff9c4}, /* U+8E16 [2000] */ - {0x00e8b89d, 0x00ecf6}, /* U+8E1D */ - {0x00e8b89e, 0x00ecf7}, /* U+8E1E */ - {0x00e8b89f, 0x00ecf9}, /* U+8E1F */ - {0x00e8b8a0, 0x00fcc4}, /* U+8E20 [2000] */ - {0x00e8b8a1, 0x8ff9c5}, /* U+8E21 [2000] */ - {0x00e8b8a2, 0x8ff9c6}, /* U+8E22 [2000] */ - {0x00e8b8a3, 0x00fcc5}, /* U+8E23 [2000] */ - {0x00e8b8a7, 0x8ff9c7}, /* U+8E27 [2000] */ - {0x00e8b8aa, 0x00eda9}, /* U+8E2A */ - {0x00e8b8b0, 0x00ecfc}, /* U+8E30 */ - {0x00e8b8b4, 0x00ecfd}, /* U+8E34 */ - {0x00e8b8b5, 0x00ecfb}, /* U+8E35 */ - {0x00e8b8b6, 0x8ff9ca}, /* U+8E36 [2000] */ - {0x00e8b8b9, 0x8ff9cb}, /* U+8E39 [2000] */ - {0x00e8b8bd, 0x00fcc6}, /* U+8E3D [2000] */ - {0x00e8b982, 0x00ecfa}, /* U+8E42 */ - {0x00e8b984, 0x00c4fd}, /* U+8E44 */ - {0x00e8b987, 0x00eda1}, /* U+8E47 */ - {0x00e8b988, 0x00eda5}, /* U+8E48 */ - {0x00e8b989, 0x00eda2}, /* U+8E49 */ - {0x00e8b98a, 0x00ecfe}, /* U+8E4A */ - {0x00e8b98b, 0x8ff9cc}, /* U+8E4B [2000] */ - {0x00e8b98c, 0x00eda3}, /* U+8E4C */ - {0x00e8b990, 0x00eda4}, /* U+8E50 */ - {0x00e8b994, 0x8ff9cd}, /* U+8E54 [2000] */ - {0x00e8b995, 0x00edab}, /* U+8E55 */ - {0x00e8b999, 0x00eda6}, /* U+8E59 */ - {0x00e8b99f, 0x00c0d8}, /* U+8E5F */ - {0x00e8b9a0, 0x00eda8}, /* U+8E60 */ - {0x00e8b9a2, 0x8ff9ce}, /* U+8E62 [2000] */ - {0x00e8b9a3, 0x00edaa}, /* U+8E63 */ - {0x00e8b9a4, 0x00eda7}, /* U+8E64 */ - {0x00e8b9ac, 0x8ff9cf}, /* U+8E6C [2000] */ - {0x00e8b9ad, 0x8ff9d0}, /* U+8E6D [2000] */ - {0x00e8b9af, 0x8ff9d1}, /* U+8E6F [2000] */ - {0x00e8b9b0, 0x00fcc7}, /* U+8E70 [2000] */ - {0x00e8b9b2, 0x00edad}, /* U+8E72 */ - {0x00e8b9b4, 0x00bdb3}, /* U+8E74 */ - {0x00e8b9b6, 0x00edac}, /* U+8E76 */ - {0x00e8b9bb, 0x00fcc8}, /* U+8E7B [2000] */ - {0x00e8b9bc, 0x00edae}, /* U+8E7C */ - {0x00e8ba81, 0x00edaf}, /* U+8E81 */ - {0x00e8ba84, 0x00edb2}, /* U+8E84 */ - {0x00e8ba85, 0x00edb1}, /* U+8E85 */ - {0x00e8ba87, 0x00edb0}, /* U+8E87 */ - {0x00e8ba8a, 0x00edb4}, /* U+8E8A */ - {0x00e8ba8b, 0x00edb3}, /* U+8E8B */ - {0x00e8ba8d, 0x00ccf6}, /* U+8E8D */ - {0x00e8ba91, 0x00edb6}, /* U+8E91 */ - {0x00e8ba93, 0x00edb5}, /* U+8E93 */ - {0x00e8ba94, 0x00edb7}, /* U+8E94 */ - {0x00e8ba98, 0x8ff9d2}, /* U+8E98 [2000] */ - {0x00e8ba99, 0x00edb8}, /* U+8E99 */ - {0x00e8ba9e, 0x8ff9d3}, /* U+8E9E [2000] */ - {0x00e8baa1, 0x00edba}, /* U+8EA1 */ - {0x00e8baaa, 0x00edb9}, /* U+8EAA */ - {0x00e8baab, 0x00bfc8}, /* U+8EAB */ - {0x00e8baac, 0x00edbb}, /* U+8EAC */ - {0x00e8baae, 0x8ff9d4}, /* U+8EAE [2000] */ - {0x00e8baaf, 0x00b6ed}, /* U+8EAF */ - {0x00e8bab0, 0x00edbc}, /* U+8EB0 */ - {0x00e8bab1, 0x00edbe}, /* U+8EB1 */ - {0x00e8bab3, 0x8ff9d5}, /* U+8EB3 [2000] */ - {0x00e8bab5, 0x8ff9d6}, /* U+8EB5 [2000] */ - {0x00e8bab6, 0x8ff9d7}, /* U+8EB6 [2000] */ - {0x00e8babb, 0x8ff9d8}, /* U+8EBB [2000] */ - {0x00e8babe, 0x00edbf}, /* U+8EBE */ - {0x00e8bb80, 0x00fcca}, /* U+8EC0 [2000] */ - {0x00e8bb85, 0x00edc0}, /* U+8EC5 */ - {0x00e8bb86, 0x00edbd}, /* U+8EC6 */ - {0x00e8bb88, 0x00edc1}, /* U+8EC8 */ - {0x00e8bb8a, 0x00bcd6}, /* U+8ECA */ - {0x00e8bb8b, 0x00edc2}, /* U+8ECB */ - {0x00e8bb8c, 0x00b5b0}, /* U+8ECC */ - {0x00e8bb8d, 0x00b7b3}, /* U+8ECD */ - {0x00e8bb91, 0x8ff9da}, /* U+8ED1 [2000] */ - {0x00e8bb92, 0x00b8ae}, /* U+8ED2 */ - {0x00e8bb94, 0x8ff9db}, /* U+8ED4 [2000] */ - {0x00e8bb9b, 0x00edc3}, /* U+8EDB */ - {0x00e8bb9f, 0x00c6f0}, /* U+8EDF */ - {0x00e8bba2, 0x00c5be}, /* U+8EE2 */ - {0x00e8bba3, 0x00edc4}, /* U+8EE3 */ - {0x00e8bbab, 0x00edc7}, /* U+8EEB */ - {0x00e8bbb8, 0x00bcb4}, /* U+8EF8 */ - {0x00e8bbb9, 0x8ff9dd}, /* U+8EF9 [2000] */ - {0x00e8bbba, 0x00fccc}, /* U+8EFA [2000] */ - {0x00e8bbbb, 0x00edc6}, /* U+8EFB */ - {0x00e8bbbc, 0x00edc5}, /* U+8EFC */ - {0x00e8bbbd, 0x00b7da}, /* U+8EFD */ - {0x00e8bbbe, 0x00edc8}, /* U+8EFE */ - {0x00e8bc80, 0x8ff9df}, /* U+8F00 [2000] */ - {0x00e8bc83, 0x00b3d3}, /* U+8F03 */ - {0x00e8bc85, 0x00edca}, /* U+8F05 */ - {0x00e8bc88, 0x8ff9e0}, /* U+8F08 [2000] */ - {0x00e8bc89, 0x00badc}, /* U+8F09 */ - {0x00e8bc8a, 0x00edc9}, /* U+8F0A */ - {0x00e8bc8c, 0x00edd2}, /* U+8F0C */ - {0x00e8bc92, 0x00edcc}, /* U+8F12 */ - {0x00e8bc93, 0x00edce}, /* U+8F13 */ - {0x00e8bc94, 0x00cae5}, /* U+8F14 */ - {0x00e8bc95, 0x00edcb}, /* U+8F15 */ - {0x00e8bc97, 0x8ff9e1}, /* U+8F17 [2000] */ - {0x00e8bc99, 0x00edcd}, /* U+8F19 */ - {0x00e8bc9b, 0x00edd1}, /* U+8F1B */ - {0x00e8bc9c, 0x00edcf}, /* U+8F1C */ - {0x00e8bc9d, 0x00b5b1}, /* U+8F1D */ - {0x00e8bc9e, 0x00fccd}, /* U+8F1E [2000] */ - {0x00e8bc9f, 0x00edd0}, /* U+8F1F */ - {0x00e8bca6, 0x00edd3}, /* U+8F26 */ - {0x00e8bca9, 0x00c7da}, /* U+8F29 */ - {0x00e8bcaa, 0x00ced8}, /* U+8F2A */ - {0x00e8bcab, 0x8ff9e2}, /* U+8F2B [2000] */ - {0x00e8bcad, 0x00fcce}, /* U+8F2D [2000] */ - {0x00e8bcaf, 0x00bdb4}, /* U+8F2F */ - {0x00e8bcb3, 0x00edd4}, /* U+8F33 */ - {0x00e8bcb6, 0x00fccf}, /* U+8F36 [2000] */ - {0x00e8bcb8, 0x00cda2}, /* U+8F38 */ - {0x00e8bcb9, 0x00edd6}, /* U+8F39 */ - {0x00e8bcbb, 0x00edd5}, /* U+8F3B */ - {0x00e8bcbe, 0x00edd9}, /* U+8F3E */ - {0x00e8bcbf, 0x00cdc1}, /* U+8F3F */ - {0x00e8bd80, 0x8ff9e3}, /* U+8F40 [2000] */ - {0x00e8bd82, 0x00edd8}, /* U+8F42 */ - {0x00e8bd84, 0x00b3ed}, /* U+8F44 */ - {0x00e8bd85, 0x00edd7}, /* U+8F45 */ - {0x00e8bd86, 0x00eddc}, /* U+8F46 */ - {0x00e8bd89, 0x00eddb}, /* U+8F49 */ - {0x00e8bd8a, 0x8ff9e4}, /* U+8F4A [2000] */ - {0x00e8bd8c, 0x00edda}, /* U+8F4C */ - {0x00e8bd8d, 0x00c5b2}, /* U+8F4D */ - {0x00e8bd8e, 0x00eddd}, /* U+8F4E */ - {0x00e8bd94, 0x00fcd0}, /* U+8F54 [2000] */ - {0x00e8bd97, 0x00edde}, /* U+8F57 */ - {0x00e8bd98, 0x8ff9e5}, /* U+8F58 [2000] */ - {0x00e8bd9c, 0x00eddf}, /* U+8F5C */ - {0x00e8bd9f, 0x00b9ec}, /* U+8F5F */ - {0x00e8bda1, 0x00b7a5}, /* U+8F61 */ - {0x00e8bda2, 0x00ede0}, /* U+8F62 */ - {0x00e8bda3, 0x00ede1}, /* U+8F63 */ - {0x00e8bda4, 0x00ede2}, /* U+8F64 */ - {0x00e8be9b, 0x00bfc9}, /* U+8F9B */ - {0x00e8be9c, 0x00ede3}, /* U+8F9C */ - {0x00e8be9e, 0x00bcad}, /* U+8F9E */ - {0x00e8be9f, 0x00ede4}, /* U+8F9F */ - {0x00e8bea3, 0x00ede5}, /* U+8FA3 */ - {0x00e8bea4, 0x8ff9e7}, /* U+8FA4 [2000] */ - {0x00e8bea6, 0x00fcd2}, /* U+8FA6 [2000] */ - {0x00e8bea7, 0x00d2a1}, /* U+8FA7 */ - {0x00e8bea8, 0x00d1fe}, /* U+8FA8 */ - {0x00e8bead, 0x00ede6}, /* U+8FAD */ - {0x00e8beae, 0x00e5f0}, /* U+8FAE */ - {0x00e8beaf, 0x00ede7}, /* U+8FAF */ - {0x00e8beb0, 0x00c3a4}, /* U+8FB0 */ - {0x00e8beb1, 0x00bfab}, /* U+8FB1 */ - {0x00e8beb2, 0x00c7c0}, /* U+8FB2 */ - {0x00e8beb4, 0x8ff9e8}, /* U+8FB4 [2000] */ - {0x00e8beb5, 0x00fcd3}, /* U+8FB5 [2000] */ - {0x00e8beb6, 0x8ff9ea}, /* U+8FB6 [2000] */ - {0x00e8beb7, 0x00ede8}, /* U+8FB7 */ - {0x00e8beba, 0x00cad5}, /* U+8FBA */ - {0x00e8bebb, 0x00c4d4}, /* U+8FBB */ - {0x00e8bebc, 0x00b9fe}, /* U+8FBC */ - {0x00e8bebf, 0x00c3a9}, /* U+8FBF */ - {0x00e8bf81, 0x8ff9ec}, /* U+8FC1 [2000] */ - {0x00e8bf82, 0x00b1aa}, /* U+8FC2 */ - {0x00e8bf84, 0x00cbf8}, /* U+8FC4 */ - {0x00e8bf85, 0x00bfd7}, /* U+8FC5 */ - {0x00e8bf86, 0x8ff9ed}, /* U+8FC6 [2000] */ - {0x00e8bf8a, 0x8ff9ef}, /* U+8FCA [2000] */ - {0x00e8bf8d, 0x8ff9f0}, /* U+8FCD [2000] */ - {0x00e8bf8e, 0x00b7de}, /* U+8FCE */ - {0x00e8bf91, 0x00b6e1}, /* U+8FD1 */ - {0x00e8bf93, 0x8ff9f1}, /* U+8FD3 [2000] */ - {0x00e8bf94, 0x00cad6}, /* U+8FD4 */ - {0x00e8bf95, 0x8ff9f2}, /* U+8FD5 [2000] */ - {0x00e8bf9a, 0x00ede9}, /* U+8FDA */ - {0x00e8bfa0, 0x8ff9f3}, /* U+8FE0 [2000] */ - {0x00e8bfa2, 0x00edeb}, /* U+8FE2 */ - {0x00e8bfa4, 0x00fcd4}, /* U+8FE4 [2000] */ - {0x00e8bfa5, 0x00edea}, /* U+8FE5 */ - {0x00e8bfa6, 0x00b2e0}, /* U+8FE6 */ - {0x00e8bfa8, 0x00fcd5}, /* U+8FE8 [2000] */ - {0x00e8bfa9, 0x00c6f6}, /* U+8FE9 */ - {0x00e8bfaa, 0x00edec}, /* U+8FEA */ - {0x00e8bfab, 0x00c7f7}, /* U+8FEB */ - {0x00e8bfad, 0x00c5b3}, /* U+8FED */ - {0x00e8bfae, 0x00fcd6}, /* U+8FEE [2000] */ - {0x00e8bfaf, 0x00eded}, /* U+8FEF */ - {0x00e8bfb0, 0x00bdd2}, /* U+8FF0 */ - {0x00e8bfb1, 0x8ff9f4}, /* U+8FF1 [2000] */ - {0x00e8bfb4, 0x00edef}, /* U+8FF4 */ - {0x00e8bfb5, 0x8ff9f5}, /* U+8FF5 [2000] */ - {0x00e8bfb7, 0x00ccc2}, /* U+8FF7 */ - {0x00e8bfb8, 0x00edfe}, /* U+8FF8 */ - {0x00e8bfb9, 0x00edf1}, /* U+8FF9 */ - {0x00e8bfba, 0x00edf2}, /* U+8FFA */ - {0x00e8bfbb, 0x8ff9f6}, /* U+8FFB [2000] */ - {0x00e8bfbd, 0x00c4c9}, /* U+8FFD */ - {0x00e98080, 0x00c2e0}, /* U+9000 */ - {0x00e98081, 0x00c1f7}, /* U+9001 */ - {0x00e98082, 0x8ff9f7}, /* U+9002 [2000] */ - {0x00e98083, 0x00c6a8}, /* U+9003 */ - {0x00e98085, 0x00edf0}, /* U+9005 */ - {0x00e98086, 0x00b5d5}, /* U+9006 */ - {0x00e98088, 0x00fcd7}, /* U+9008 [2000] */ - {0x00e9808b, 0x00edf9}, /* U+900B */ - {0x00e9808c, 0x8ff9f8}, /* U+900C [2000] */ - {0x00e9808d, 0x00edf6}, /* U+900D */ - {0x00e9808e, 0x00eea5}, /* U+900E */ - {0x00e9808f, 0x00c6a9}, /* U+900F */ - {0x00e98090, 0x00c3e0}, /* U+9010 */ - {0x00e98091, 0x00edf3}, /* U+9011 */ - {0x00e98093, 0x00c4fe}, /* U+9013 */ - {0x00e98094, 0x00c5d3}, /* U+9014 */ - {0x00e98095, 0x00edf4}, /* U+9015 */ - {0x00e98096, 0x00edf8}, /* U+9016 */ - {0x00e98097, 0x00bfe0}, /* U+9017 */ - {0x00e98099, 0x00c7e7}, /* U+9019 */ - {0x00e9809a, 0x00c4cc}, /* U+901A */ - {0x00e9809d, 0x00c0c2}, /* U+901D */ - {0x00e9809e, 0x00edf7}, /* U+901E */ - {0x00e9809f, 0x00c2ae}, /* U+901F */ - {0x00e980a0, 0x00c2a4}, /* U+9020 */ - {0x00e980a1, 0x00edf5}, /* U+9021 */ - {0x00e980a2, 0x00b0a9}, /* U+9022 */ - {0x00e980a3, 0x00cfa2}, /* U+9023 */ - {0x00e980a7, 0x00edfa}, /* U+9027 */ - {0x00e980ad, 0x00fcd8}, /* U+902D [2000] */ - {0x00e980ae, 0x00c2e1}, /* U+902E */ - {0x00e980b1, 0x00bdb5}, /* U+9031 */ - {0x00e980b2, 0x00bfca}, /* U+9032 */ - {0x00e980b5, 0x00edfc}, /* U+9035 */ - {0x00e980b6, 0x00edfb}, /* U+9036 */ - {0x00e980b7, 0x8ff9f9}, /* U+9037 [2000] */ - {0x00e980b8, 0x00b0ef}, /* U+9038 */ - {0x00e980b9, 0x00edfd}, /* U+9039 */ - {0x00e980bc, 0x00c9af}, /* U+903C */ - {0x00e980be, 0x00eea7}, /* U+903E */ - {0x00e98181, 0x00c6db}, /* U+9041 */ - {0x00e98182, 0x00bfeb}, /* U+9042 */ - {0x00e98183, 0x8ff9fb}, /* U+9043 [2000] */ - {0x00e98184, 0x8ff9fc}, /* U+9044 [2000] */ - {0x00e98185, 0x00c3d9}, /* U+9045 */ - {0x00e98187, 0x00b6f8}, /* U+9047 */ - {0x00e98189, 0x00eea6}, /* U+9049 */ - {0x00e9818a, 0x00cdb7}, /* U+904A */ - {0x00e9818b, 0x00b1bf}, /* U+904B */ - {0x00e9818d, 0x00cad7}, /* U+904D */ - {0x00e9818e, 0x00b2e1}, /* U+904E */ - {0x00e9818f, 0x00eea1}, /* U+904F */ - {0x00e98190, 0x00eea2}, /* U+9050 */ - {0x00e98191, 0x00eea3}, /* U+9051 */ - {0x00e98192, 0x00eea4}, /* U+9052 */ - {0x00e98193, 0x00c6bb}, /* U+9053 */ - {0x00e98194, 0x00c3a3}, /* U+9054 */ - {0x00e98195, 0x00b0e3}, /* U+9055 */ - {0x00e98196, 0x00eea8}, /* U+9056 */ - {0x00e98198, 0x00eea9}, /* U+9058 */ - {0x00e98199, 0x00f4a3}, /* U+9059 [1983] */ - {0x00e9819c, 0x00c2bd}, /* U+905C */ - {0x00e9819d, 0x8ff9fd}, /* U+905D [2000] */ - {0x00e9819e, 0x00eeaa}, /* U+905E */ - {0x00e981a0, 0x00b1f3}, /* U+9060 */ - {0x00e981a1, 0x00c1cc}, /* U+9061 */ - {0x00e981a3, 0x00b8af}, /* U+9063 */ - {0x00e981a5, 0x00cdda}, /* U+9065 */ - {0x00e981a8, 0x00eeab}, /* U+9068 */ - {0x00e981a9, 0x00c5ac}, /* U+9069 */ - {0x00e981ad, 0x00c1f8}, /* U+906D */ - {0x00e981ae, 0x00bcd7}, /* U+906E */ - {0x00e981af, 0x00eeac}, /* U+906F */ - {0x00e981b2, 0x00eeaf}, /* U+9072 */ - {0x00e981b5, 0x00bde5}, /* U+9075 */ - {0x00e981b6, 0x00eead}, /* U+9076 */ - {0x00e981b7, 0x00c1ab}, /* U+9077 */ - {0x00e981b8, 0x00c1aa}, /* U+9078 */ - {0x00e981ba, 0x00b0e4}, /* U+907A */ - {0x00e981bc, 0x00cecb}, /* U+907C */ - {0x00e981bd, 0x00eeb1}, /* U+907D */ - {0x00e981bf, 0x00c8f2}, /* U+907F */ - {0x00e98280, 0x00eeb3}, /* U+9080 */ - {0x00e98281, 0x00eeb2}, /* U+9081 */ - {0x00e98282, 0x00eeb0}, /* U+9082 */ - {0x00e98283, 0x00e3e4}, /* U+9083 */ - {0x00e98284, 0x00b4d4}, /* U+9084 */ - {0x00e98285, 0x8ffaa2}, /* U+9085 [2000] */ - {0x00e98287, 0x00edee}, /* U+9087 */ - {0x00e98288, 0x00fcda}, /* U+9088 [2000] */ - {0x00e98289, 0x00eeb5}, /* U+9089 */ - {0x00e9828a, 0x00eeb4}, /* U+908A */ - {0x00e9828c, 0x8ffaa3}, /* U+908C [2000] */ - {0x00e9828f, 0x00eeb6}, /* U+908F */ - {0x00e98290, 0x8ffaa4}, /* U+9090 [2000] */ - {0x00e98291, 0x00cdb8}, /* U+9091 */ - {0x00e98295, 0x00fcdb}, /* U+9095 [2000] */ - {0x00e98297, 0x00fcdc}, /* U+9097 [2000] */ - {0x00e98299, 0x00fcdd}, /* U+9099 [2000] */ - {0x00e9829b, 0x00fcde}, /* U+909B [2000] */ - {0x00e982a1, 0x8ffaa6}, /* U+90A1 [2000] */ - {0x00e982a2, 0x00fcdf}, /* U+90A2 [2000] */ - {0x00e982a3, 0x00c6e1}, /* U+90A3 */ - {0x00e982a6, 0x00cbae}, /* U+90A6 */ - {0x00e982a8, 0x00eeb7}, /* U+90A8 */ - {0x00e982aa, 0x00bcd9}, /* U+90AA */ - {0x00e982af, 0x00eeb8}, /* U+90AF */ - {0x00e982b0, 0x8ffaa8}, /* U+90B0 [2000] */ - {0x00e982b1, 0x00eeb9}, /* U+90B1 */ - {0x00e982b3, 0x00fce0}, /* U+90B3 [2000] */ - {0x00e982b5, 0x00eeba}, /* U+90B5 */ - {0x00e982b6, 0x8ffaa9}, /* U+90B6 [2000] */ - {0x00e982b8, 0x00c5a1}, /* U+90B8 */ - {0x00e982be, 0x00fce1}, /* U+90BE [2000] */ - {0x00e98381, 0x00b0ea}, /* U+90C1 */ - {0x00e98383, 0x8ffaaa}, /* U+90C3 [2000] */ - {0x00e98384, 0x00fce2}, /* U+90C4 [2000] */ - {0x00e98385, 0x00fce3}, /* U+90C5 [2000] */ - {0x00e98387, 0x00fce4}, /* U+90C7 [2000] */ - {0x00e98388, 0x8ffaab}, /* U+90C8 [2000] */ - {0x00e9838a, 0x00b9d9}, /* U+90CA */ - {0x00e9838e, 0x00cfba}, /* U+90CE */ - {0x00e98397, 0x00fce5}, /* U+90D7 [2000] */ - {0x00e9839b, 0x00eebe}, /* U+90DB */ - {0x00e9839c, 0x8ffaad}, /* U+90DC [2000] */ - {0x00e9839d, 0x00fce6}, /* U+90DD [2000] */ - {0x00e9839e, 0x00fce7}, /* U+90DE [2000] */ - {0x00e9839f, 0x8ffaae}, /* U+90DF [2000] */ - {0x00e983a1, 0x00b7b4}, /* U+90E1 */ - {0x00e983a2, 0x00eebb}, /* U+90E2 */ - {0x00e983a4, 0x00eebc}, /* U+90E4 */ - {0x00e983a8, 0x00c9f4}, /* U+90E8 */ - {0x00e983ab, 0x8ffab3}, /* U+90EB [2000] */ - {0x00e983ad, 0x00b3d4}, /* U+90ED */ - {0x00e983af, 0x00fce8}, /* U+90EF [2000] */ - {0x00e983b2, 0x8ffab1}, /* U+90F2 [2000] */ - {0x00e983b4, 0x00fce9}, /* U+90F4 [2000] */ - {0x00e983b5, 0x00cdb9}, /* U+90F5 */ - {0x00e983b6, 0x8ffab0}, /* U+90F6 [2000] */ - {0x00e983b7, 0x00b6bf}, /* U+90F7 */ - {0x00e983bd, 0x00c5d4}, /* U+90FD */ - {0x00e983be, 0x8ffab4}, /* U+90FE [2000] */ - {0x00e983bf, 0x8ffab5}, /* U+90FF [2000] */ - {0x00e98480, 0x8ffab2}, /* U+9100 [2000] */ - {0x00e98482, 0x00eebf}, /* U+9102 */ - {0x00e98484, 0x8ffab6}, /* U+9104 [2000] */ - {0x00e98486, 0x8ffab7}, /* U+9106 [2000] */ - {0x00e98492, 0x00eec0}, /* U+9112 */ - {0x00e98494, 0x00fceb}, /* U+9114 [2000] */ - {0x00e98495, 0x00fcec}, /* U+9115 [2000] */ - {0x00e98496, 0x00fced}, /* U+9116 [2000] */ - {0x00e98498, 0x8ffab8}, /* U+9118 [2000] */ - {0x00e98499, 0x00eec1}, /* U+9119 */ - {0x00e9849c, 0x8ffab9}, /* U+911C [2000] */ - {0x00e9849e, 0x8ffaba}, /* U+911E [2000] */ - {0x00e984a2, 0x00fcee}, /* U+9122 [2000] */ - {0x00e984a3, 0x00fcef}, /* U+9123 [2000] */ - {0x00e984a7, 0x00fcf0}, /* U+9127 [2000] */ - {0x00e984ad, 0x00c5a2}, /* U+912D */ - {0x00e984af, 0x00fcf1}, /* U+912F [2000] */ - {0x00e984b0, 0x00eec3}, /* U+9130 */ - {0x00e984b1, 0x00fcf2}, /* U+9131 [2000] */ - {0x00e984b2, 0x00eec2}, /* U+9132 */ - {0x00e984b4, 0x00fcf3}, /* U+9134 [2000] */ - {0x00e984b7, 0x8ffabb}, /* U+9137 [2000] */ - {0x00e984b9, 0x8ffabc}, /* U+9139 [2000] */ - {0x00e984ba, 0x8ffabd}, /* U+913A [2000] */ - {0x00e984bd, 0x00fcf4}, /* U+913D [2000] */ - {0x00e98586, 0x8ffabe}, /* U+9146 [2000] */ - {0x00e98587, 0x8ffabf}, /* U+9147 [2000] */ - {0x00e98588, 0x00fcf5}, /* U+9148 [2000] */ - {0x00e98589, 0x00c6d3}, /* U+9149 */ - {0x00e9858a, 0x00eec4}, /* U+914A */ - {0x00e9858b, 0x00bdb6}, /* U+914B */ - {0x00e9858c, 0x00bce0}, /* U+914C */ - {0x00e9858d, 0x00c7db}, /* U+914D */ - {0x00e9858e, 0x00c3f1}, /* U+914E */ - {0x00e98592, 0x00bcf2}, /* U+9152 */ - {0x00e98594, 0x00bfec}, /* U+9154 */ - {0x00e98596, 0x00eec5}, /* U+9156 */ - {0x00e98597, 0x8ffac0}, /* U+9157 [2000] */ - {0x00e98598, 0x00eec6}, /* U+9158 */ - {0x00e98599, 0x8ffac1}, /* U+9159 [2000] */ - {0x00e9859b, 0x00fcf6}, /* U+915B [2000] */ - {0x00e985a1, 0x8ffac2}, /* U+9161 [2000] */ - {0x00e985a2, 0x00bfdd}, /* U+9162 */ - {0x00e985a3, 0x00eec7}, /* U+9163 */ - {0x00e985a4, 0x8ffac3}, /* U+9164 [2000] */ - {0x00e985a5, 0x00eec8}, /* U+9165 */ - {0x00e985a9, 0x00eec9}, /* U+9169 */ - {0x00e985aa, 0x00cdef}, /* U+916A */ - {0x00e985ac, 0x00bdb7}, /* U+916C */ - {0x00e985b2, 0x00eecb}, /* U+9172 */ - {0x00e985b3, 0x00eeca}, /* U+9173 */ - {0x00e985b4, 0x8ffac4}, /* U+9174 [2000] */ - {0x00e985b5, 0x00b9da}, /* U+9175 */ - {0x00e985b7, 0x00b9f3}, /* U+9177 */ - {0x00e985b8, 0x00bbc0}, /* U+9178 */ - {0x00e985b9, 0x8ffac5}, /* U+9179 [2000] */ - {0x00e98682, 0x00eece}, /* U+9182 */ - {0x00e98683, 0x00fcf7}, /* U+9183 [2000] */ - {0x00e98685, 0x8ffac6}, /* U+9185 [2000] */ - {0x00e98687, 0x00bde6}, /* U+9187 */ - {0x00e98689, 0x00eecd}, /* U+9189 */ - {0x00e9868b, 0x00eecc}, /* U+918B */ - {0x00e9868d, 0x00c2e9}, /* U+918D */ - {0x00e9868e, 0x8ffac7}, /* U+918E [2000] */ - {0x00e98690, 0x00b8ef}, /* U+9190 */ - {0x00e98692, 0x00c0c3}, /* U+9192 */ - {0x00e98697, 0x00c8b0}, /* U+9197 */ - {0x00e9869c, 0x00bdb9}, /* U+919C */ - {0x00e9869e, 0x00fcf8}, /* U+919E [2000] */ - {0x00e986a2, 0x00eecf}, /* U+91A2 */ - {0x00e986a4, 0x00bedf}, /* U+91A4 */ - {0x00e986a8, 0x8ffac8}, /* U+91A8 [2000] */ - {0x00e986aa, 0x00eed2}, /* U+91AA */ - {0x00e986ab, 0x00eed0}, /* U+91AB */ - {0x00e986ac, 0x00fcf9}, /* U+91AC [2000] */ - {0x00e986ae, 0x8ffac9}, /* U+91AE [2000] */ - {0x00e986af, 0x00eed1}, /* U+91AF */ - {0x00e986b1, 0x00fcfa}, /* U+91B1 [2000] */ - {0x00e986b3, 0x8ffaca}, /* U+91B3 [2000] */ - {0x00e986b4, 0x00eed4}, /* U+91B4 */ - {0x00e986b5, 0x00eed3}, /* U+91B5 */ - {0x00e986b6, 0x8ffacb}, /* U+91B6 [2000] */ - {0x00e986b8, 0x00befa}, /* U+91B8 */ - {0x00e986ba, 0x00eed5}, /* U+91BA */ - {0x00e986bc, 0x00fcfb}, /* U+91BC [2000] */ - {0x00e98780, 0x00eed6}, /* U+91C0 */ - {0x00e98781, 0x00eed7}, /* U+91C1 */ - {0x00e98783, 0x8ffacc}, /* U+91C3 [2000] */ - {0x00e98784, 0x8ffacd}, /* U+91C4 [2000] */ - {0x00e98786, 0x00c8d0}, /* U+91C6 */ - {0x00e98787, 0x00bad3}, /* U+91C7 */ - {0x00e98788, 0x00bce1}, /* U+91C8 */ - {0x00e98789, 0x00eed8}, /* U+91C9 */ - {0x00e9878b, 0x00eed9}, /* U+91CB */ - {0x00e9878c, 0x00cea4}, /* U+91CC */ - {0x00e9878d, 0x00bdc5}, /* U+91CD */ - {0x00e9878e, 0x00ccee}, /* U+91CE */ - {0x00e9878f, 0x00cecc}, /* U+91CF */ - {0x00e98790, 0x00eeda}, /* U+91D0 */ - {0x00e98791, 0x00b6e2}, /* U+91D1 */ - {0x00e98796, 0x00eedb}, /* U+91D6 */ - {0x00e98797, 0x00fcfc}, /* U+91D7 [2000] */ - {0x00e98798, 0x00c5a3}, /* U+91D8 */ - {0x00e9879a, 0x8fface}, /* U+91DA [2000] */ - {0x00e9879b, 0x00eede}, /* U+91DB */ - {0x00e9879c, 0x00b3f8}, /* U+91DC */ - {0x00e9879d, 0x00bfcb}, /* U+91DD */ - {0x00e9879f, 0x00eedc}, /* U+91DF */ - {0x00e987a1, 0x00eedd}, /* U+91E1 */ - {0x00e987a3, 0x00c4e0}, /* U+91E3 */ - {0x00e987a4, 0x00fcfe}, /* U+91E4 [2000] */ - {0x00e987a5, 0x00fda1}, /* U+91E5 [2000] */ - {0x00e987a6, 0x00cbd5}, /* U+91E6 */ - {0x00e987a7, 0x00b6fc}, /* U+91E7 */ - {0x00e987ac, 0x8ffad1}, /* U+91EC [2000] */ - {0x00e987ad, 0x00fda2}, /* U+91ED [2000] */ - {0x00e987ae, 0x8ffad2}, /* U+91EE [2000] */ - {0x00e987b1, 0x00fda3}, /* U+91F1 [2000] */ - {0x00e987b5, 0x00eee0}, /* U+91F5 */ - {0x00e987b6, 0x00eee1}, /* U+91F6 */ - {0x00e987bb, 0x00fcfd}, /* U+91FB [2000] */ - {0x00e987bc, 0x00eedf}, /* U+91FC */ - {0x00e987bf, 0x00eee3}, /* U+91FF */ - {0x00e98881, 0x8ffad3}, /* U+9201 [2000] */ - {0x00e98887, 0x00fda4}, /* U+9207 [2000] */ - {0x00e9888a, 0x8ffad4}, /* U+920A [2000] */ - {0x00e9888d, 0x00c6df}, /* U+920D */ - {0x00e9888e, 0x00b3c3}, /* U+920E */ - {0x00e98890, 0x00fda5}, /* U+9210 [2000] */ - {0x00e98891, 0x00eee7}, /* U+9211 */ - {0x00e98894, 0x00eee4}, /* U+9214 */ - {0x00e98895, 0x00eee6}, /* U+9215 */ - {0x00e98896, 0x8ffad5}, /* U+9216 [2000] */ - {0x00e98897, 0x8ffad6}, /* U+9217 [2000] */ - {0x00e9889e, 0x00eee2}, /* U+921E */ - {0x00e988a9, 0x00efcf}, /* U+9229 */ - {0x00e988ac, 0x00eee5}, /* U+922C */ - {0x00e988b3, 0x8ffad8}, /* U+9233 [2000] */ - {0x00e988b4, 0x00ceeb}, /* U+9234 */ - {0x00e988b7, 0x00b8da}, /* U+9237 */ - {0x00e988b8, 0x00fda6}, /* U+9238 [2000] */ - {0x00e988b9, 0x00fda7}, /* U+9239 [2000] */ - {0x00e988ba, 0x00fda8}, /* U+923A [2000] */ - {0x00e988bc, 0x00fda9}, /* U+923C [2000] */ - {0x00e988bf, 0x00eeef}, /* U+923F */ - {0x00e98980, 0x00fdaa}, /* U+9240 [2000] */ - {0x00e98982, 0x8ffad9}, /* U+9242 [2000] */ - {0x00e98983, 0x00fdab}, /* U+9243 [2000] */ - {0x00e98984, 0x00c5b4}, /* U+9244 */ - {0x00e98985, 0x00eeea}, /* U+9245 */ - {0x00e98987, 0x8ffada}, /* U+9247 [2000] */ - {0x00e98988, 0x00eeed}, /* U+9248 */ - {0x00e98989, 0x00eeeb}, /* U+9249 */ - {0x00e9898a, 0x8ffadb}, /* U+924A [2000] */ - {0x00e9898b, 0x00eef0}, /* U+924B */ - {0x00e9898e, 0x8ffadc}, /* U+924E [2000] */ - {0x00e9898f, 0x00fdac}, /* U+924F [2000] */ - {0x00e98990, 0x00eef1}, /* U+9250 */ - {0x00e98991, 0x8ffadd}, /* U+9251 [2000] */ - {0x00e98996, 0x8ffade}, /* U+9256 [2000] */ - {0x00e98997, 0x00eee9}, /* U+9257 */ - {0x00e98999, 0x8ffadf}, /* U+9259 [2000] */ - {0x00e9899a, 0x00eef6}, /* U+925A */ - {0x00e9899b, 0x00b1f4}, /* U+925B */ - {0x00e9899e, 0x00eee8}, /* U+925E */ - {0x00e989a0, 0x8ffae0}, /* U+9260 [2000] */ - {0x00e989a1, 0x8ffae1}, /* U+9261 [2000] */ - {0x00e989a2, 0x00c8ad}, /* U+9262 */ - {0x00e989a4, 0x00eeec}, /* U+9264 */ - {0x00e989a5, 0x8ffae2}, /* U+9265 [2000] */ - {0x00e989a6, 0x00bee0}, /* U+9266 */ - {0x00e989a7, 0x8ffae3}, /* U+9267 [2000] */ - {0x00e989a8, 0x8ffae4}, /* U+9268 [2000] */ - {0x00e989b1, 0x00b9db}, /* U+9271 */ - {0x00e989b8, 0x00fdad}, /* U+9278 [2000] */ - {0x00e989bc, 0x8ffae7}, /* U+927C [2000] */ - {0x00e989bd, 0x8ffae8}, /* U+927D [2000] */ - {0x00e989be, 0x00cbc8}, /* U+927E */ - {0x00e989bf, 0x8ffae9}, /* U+927F [2000] */ - {0x00e98a80, 0x00b6e4}, /* U+9280 */ - {0x00e98a83, 0x00bdc6}, /* U+9283 */ - {0x00e98a85, 0x00c6bc}, /* U+9285 */ - {0x00e98a88, 0x00fdae}, /* U+9288 [2000] */ - {0x00e98a89, 0x8ffaea}, /* U+9289 [2000] */ - {0x00e98a8d, 0x8ffaeb}, /* U+928D [2000] */ - {0x00e98a91, 0x00c1ad}, /* U+9291 */ - {0x00e98a93, 0x00eef4}, /* U+9293 */ - {0x00e98a95, 0x00eeee}, /* U+9295 */ - {0x00e98a96, 0x00eef3}, /* U+9296 */ - {0x00e98a97, 0x8ffaec}, /* U+9297 [2000] */ - {0x00e98a98, 0x00ccc3}, /* U+9298 */ - {0x00e98a99, 0x8ffaed}, /* U+9299 [2000] */ - {0x00e98a9a, 0x00c4b8}, /* U+929A */ - {0x00e98a9b, 0x00eef5}, /* U+929B */ - {0x00e98a9c, 0x00eef2}, /* U+929C */ - {0x00e98a9f, 0x8ffaee}, /* U+929F [2000] */ - {0x00e98aa7, 0x8ffaef}, /* U+92A7 [2000] */ - {0x00e98aab, 0x8ffaf0}, /* U+92AB [2000] */ - {0x00e98aad, 0x00c1ac}, /* U+92AD */ - {0x00e98ab2, 0x8ffaf3}, /* U+92B2 [2000] */ - {0x00e98ab7, 0x00eef9}, /* U+92B7 */ - {0x00e98ab9, 0x00eef8}, /* U+92B9 */ - {0x00e98abf, 0x8ffaf4}, /* U+92BF [2000] */ - {0x00e98b80, 0x8ffaf5}, /* U+92C0 [2000] */ - {0x00e98b82, 0x00fdaf}, /* U+92C2 [2000] */ - {0x00e98b86, 0x8ffaf6}, /* U+92C6 [2000] */ - {0x00e98b8b, 0x00fdb0}, /* U+92CB [2000] */ - {0x00e98b8c, 0x00fdb1}, /* U+92CC [2000] */ - {0x00e98b8e, 0x8ffaf7}, /* U+92CE [2000] */ - {0x00e98b8f, 0x00eef7}, /* U+92CF */ - {0x00e98b90, 0x8ffaf8}, /* U+92D0 [2000] */ - {0x00e98b92, 0x00cbaf}, /* U+92D2 */ - {0x00e98b93, 0x00fdb2}, /* U+92D3 [2000] */ - {0x00e98b97, 0x8ffaf9}, /* U+92D7 [2000] */ - {0x00e98b99, 0x8ffafa}, /* U+92D9 [2000] */ - {0x00e98ba0, 0x00fdb3}, /* U+92E0 [2000] */ - {0x00e98ba4, 0x00bdfb}, /* U+92E4 */ - {0x00e98ba5, 0x8ffafb}, /* U+92E5 [2000] */ - {0x00e98ba7, 0x8ffafc}, /* U+92E7 [2000] */ - {0x00e98ba9, 0x00eefa}, /* U+92E9 */ - {0x00e98baa, 0x00cadf}, /* U+92EA */ - {0x00e98bad, 0x00b1d4}, /* U+92ED */ - {0x00e98bb2, 0x00c9c6}, /* U+92F2 */ - {0x00e98bb3, 0x00c3f2}, /* U+92F3 */ - {0x00e98bb7, 0x8ffba2}, /* U+92F7 [2000] */ - {0x00e98bb8, 0x00b5f8}, /* U+92F8 */ - {0x00e98bb9, 0x8ffba3}, /* U+92F9 [2000] */ - {0x00e98bba, 0x00eefc}, /* U+92FA */ - {0x00e98bbb, 0x8ffba4}, /* U+92FB [2000] */ - {0x00e98bbc, 0x00b9dd}, /* U+92FC */ - {0x00e98bbf, 0x00fdb4}, /* U+92FF [2000] */ - {0x00e98c82, 0x8ffba5}, /* U+9302 [2000] */ - {0x00e98c84, 0x00fdb5}, /* U+9304 [2000] */ - {0x00e98c86, 0x00bbac}, /* U+9306 */ - {0x00e98c8d, 0x8ffba6}, /* U+930D [2000] */ - {0x00e98c8f, 0x00eefb}, /* U+930F */ - {0x00e98c90, 0x00bfed}, /* U+9310 */ - {0x00e98c91, 0x8ffafd}, /* U+9311 [2000] */ - {0x00e98c95, 0x8ffba7}, /* U+9315 [2000] */ - {0x00e98c98, 0x00bfee}, /* U+9318 */ - {0x00e98c99, 0x00efa1}, /* U+9319 */ - {0x00e98c9a, 0x00efa3}, /* U+931A */ - {0x00e98c9d, 0x8ffba8}, /* U+931D [2000] */ - {0x00e98c9e, 0x8ffba9}, /* U+931E [2000] */ - {0x00e98c9f, 0x00fdb6}, /* U+931F [2000] */ - {0x00e98ca0, 0x00befb}, /* U+9320 */ - {0x00e98ca1, 0x00fdb7}, /* U+9321 [2000] */ - {0x00e98ca2, 0x00efa2}, /* U+9322 */ - {0x00e98ca3, 0x00efa4}, /* U+9323 */ - {0x00e98ca5, 0x00fdb8}, /* U+9325 [2000] */ - {0x00e98ca6, 0x00b6d3}, /* U+9326 */ - {0x00e98ca7, 0x8ffbaa}, /* U+9327 [2000] */ - {0x00e98ca8, 0x00c9c5}, /* U+9328 */ - {0x00e98ca9, 0x8ffbab}, /* U+9329 [2000] */ - {0x00e98cab, 0x00bce2}, /* U+932B */ - {0x00e98cac, 0x00cfa3}, /* U+932C */ - {0x00e98cae, 0x00eefe}, /* U+932E */ - {0x00e98caf, 0x00baf8}, /* U+932F */ - {0x00e98cb2, 0x00cfbf}, /* U+9332 */ - {0x00e98cb5, 0x00efa6}, /* U+9335 */ - {0x00e98cba, 0x00efa5}, /* U+933A */ - {0x00e98cbb, 0x00efa7}, /* U+933B */ - {0x00e98d84, 0x00eefd}, /* U+9344 */ - {0x00e98d87, 0x8ffbae}, /* U+9347 [2000] */ - {0x00e98d88, 0x00fdb9}, /* U+9348 [2000] */ - {0x00e98d89, 0x00fdba}, /* U+9349 [2000] */ - {0x00e98d8a, 0x00fdbb}, /* U+934A [2000] */ - {0x00e98d8b, 0x00c6e9}, /* U+934B */ - {0x00e98d8d, 0x00c5d5}, /* U+934D */ - {0x00e98d91, 0x8ffbaf}, /* U+9351 [2000] */ - {0x00e98d94, 0x00c4d7}, /* U+9354 */ - {0x00e98d96, 0x00efac}, /* U+9356 */ - {0x00e98d97, 0x8ffbb0}, /* U+9357 [2000] */ - {0x00e98d9a, 0x8ffbb1}, /* U+935A [2000] */ - {0x00e98d9b, 0x00c3c3}, /* U+935B */ - {0x00e98d9c, 0x00efa8}, /* U+935C */ - {0x00e98da0, 0x00efa9}, /* U+9360 */ - {0x00e98da4, 0x00fdbc}, /* U+9364 [2000] */ - {0x00e98da5, 0x00fdbd}, /* U+9365 [2000] */ - {0x00e98daa, 0x00fdbe}, /* U+936A [2000] */ - {0x00e98dab, 0x8ffbb2}, /* U+936B [2000] */ - {0x00e98dac, 0x00b7ad}, /* U+936C */ - {0x00e98dae, 0x00efab}, /* U+936E */ - {0x00e98db0, 0x00fdbf}, /* U+9370 [2000] */ - {0x00e98db1, 0x8ffbb3}, /* U+9371 [2000] */ - {0x00e98db3, 0x8ffbb4}, /* U+9373 [2000] */ - {0x00e98db5, 0x00b8b0}, /* U+9375 */ - {0x00e98dbc, 0x00efaa}, /* U+937C */ - {0x00e98dbe, 0x00bee1}, /* U+937E */ - {0x00e98e88, 0x8ffbb8}, /* U+9388 [2000] */ - {0x00e98e8b, 0x8ffbb9}, /* U+938B [2000] */ - {0x00e98e8c, 0x00b3f9}, /* U+938C */ - {0x00e98e8f, 0x8ffbba}, /* U+938F [2000] */ - {0x00e98e94, 0x00efb0}, /* U+9394 */ - {0x00e98e96, 0x00babf}, /* U+9396 */ - {0x00e98e97, 0x00c1f9}, /* U+9397 */ - {0x00e98e9a, 0x00c4ca}, /* U+939A */ - {0x00e98e9b, 0x00fdc0}, /* U+939B [2000] */ - {0x00e98e9e, 0x8ffbbb}, /* U+939E [2000] */ - {0x00e98ea1, 0x8ffbb5}, /* U+93A1 [2000] */ - {0x00e98ea3, 0x00fdc1}, /* U+93A3 [2000] */ - {0x00e98ea7, 0x00b3bb}, /* U+93A7 */ - {0x00e98eac, 0x00efae}, /* U+93AC */ - {0x00e98ead, 0x00efaf}, /* U+93AD */ - {0x00e98eae, 0x00c4c3}, /* U+93AE */ - {0x00e98eb0, 0x00efad}, /* U+93B0 */ - {0x00e98eb9, 0x00efb1}, /* U+93B9 */ - {0x00e98eba, 0x00fdc2}, /* U+93BA [2000] */ - {0x00e98f81, 0x8ffbc0}, /* U+93C1 [2000] */ - {0x00e98f83, 0x00efb7}, /* U+93C3 */ - {0x00e98f86, 0x00fdc3}, /* U+93C6 [2000] */ - {0x00e98f87, 0x8ffbc1}, /* U+93C7 [2000] */ - {0x00e98f88, 0x00efba}, /* U+93C8 */ - {0x00e98f90, 0x00efb9}, /* U+93D0 */ - {0x00e98f91, 0x00c5ad}, /* U+93D1 */ - {0x00e98f96, 0x00efb2}, /* U+93D6 */ - {0x00e98f97, 0x00efb3}, /* U+93D7 */ - {0x00e98f98, 0x00efb6}, /* U+93D8 */ - {0x00e98f9c, 0x8ffbc2}, /* U+93DC [2000] */ - {0x00e98f9d, 0x00efb8}, /* U+93DD */ - {0x00e98f9e, 0x00fdc4}, /* U+93DE [2000] */ - {0x00e98f9f, 0x00fdc5}, /* U+93DF [2000] */ - {0x00e98fa1, 0x00b6c0}, /* U+93E1 */ - {0x00e98fa2, 0x8ffbc3}, /* U+93E2 [2000] */ - {0x00e98fa4, 0x00efbb}, /* U+93E4 */ - {0x00e98fa5, 0x00efb5}, /* U+93E5 */ - {0x00e98fa7, 0x8ffbc4}, /* U+93E7 [2000] */ - {0x00e98fa8, 0x00efb4}, /* U+93E8 */ - {0x00e98fb1, 0x8ffbbf}, /* U+93F1 [2000] */ - {0x00e98fb5, 0x8ffbbc}, /* U+93F5 [2000] */ - {0x00e98fbb, 0x8ffbc9}, /* U+93FB [2000] */ - {0x00e98fbd, 0x00fdc7}, /* U+93FD [2000] */ - {0x00e99083, 0x00efbf}, /* U+9403 */ - {0x00e99084, 0x00fdc6}, /* U+9404 [2000] */ - {0x00e99087, 0x00efc0}, /* U+9407 */ - {0x00e99089, 0x8ffbc5}, /* U+9409 [2000] */ - {0x00e9908f, 0x8ffbc6}, /* U+940F [2000] */ - {0x00e99090, 0x00efc1}, /* U+9410 */ - {0x00e99093, 0x00efbe}, /* U+9413 */ - {0x00e99094, 0x00efbd}, /* U+9414 */ - {0x00e99096, 0x8ffbc7}, /* U+9416 [2000] */ - {0x00e99097, 0x8ffbc8}, /* U+9417 [2000] */ - {0x00e99098, 0x00bee2}, /* U+9418 */ - {0x00e99099, 0x00c6aa}, /* U+9419 */ - {0x00e9909a, 0x00efbc}, /* U+941A */ - {0x00e990a1, 0x00efc5}, /* U+9421 */ - {0x00e990ab, 0x00efc3}, /* U+942B */ - {0x00e990b2, 0x8ffbca}, /* U+9432 [2000] */ - {0x00e990b3, 0x00fdc8}, /* U+9433 [2000] */ - {0x00e990b4, 0x8ffbcb}, /* U+9434 [2000] */ - {0x00e990b5, 0x00efc4}, /* U+9435 */ - {0x00e990b6, 0x00efc2}, /* U+9436 */ - {0x00e990b8, 0x00c2f8}, /* U+9438 */ - {0x00e990ba, 0x00efc6}, /* U+943A */ - {0x00e990bb, 0x8ffbcc}, /* U+943B [2000] */ - {0x00e99181, 0x00efc7}, /* U+9441 */ - {0x00e99184, 0x00efc9}, /* U+9444 */ - {0x00e99185, 0x8ffbcd}, /* U+9445 [2000] */ - {0x00e9918a, 0x00fdc9}, /* U+944A [2000] */ - {0x00e99191, 0x00b4d5}, /* U+9451 */ - {0x00e99192, 0x00efc8}, /* U+9452 */ - {0x00e99193, 0x00ccfa}, /* U+9453 */ - {0x00e9919a, 0x00efd4}, /* U+945A */ - {0x00e9919b, 0x00efca}, /* U+945B */ - {0x00e9919e, 0x00efcd}, /* U+945E */ - {0x00e991a0, 0x00efcb}, /* U+9460 */ - {0x00e991a2, 0x00efcc}, /* U+9462 */ - {0x00e991a3, 0x00fdca}, /* U+9463 [2000] */ - {0x00e991aa, 0x00efce}, /* U+946A */ - {0x00e991ab, 0x00fdcb}, /* U+946B [2000] */ - {0x00e991ad, 0x8ffbd0}, /* U+946D [2000] */ - {0x00e991af, 0x8ffbd1}, /* U+946F [2000] */ - {0x00e991b0, 0x00efd0}, /* U+9470 */ - {0x00e991b1, 0x00fdcc}, /* U+9471 [2000] */ - {0x00e991b2, 0x00fdcd}, /* U+9472 [2000] */ - {0x00e991b5, 0x00efd1}, /* U+9475 */ - {0x00e991b7, 0x00efd2}, /* U+9477 */ - {0x00e991bc, 0x00efd5}, /* U+947C */ - {0x00e991bd, 0x00efd3}, /* U+947D */ - {0x00e991be, 0x00efd6}, /* U+947E */ - {0x00e991bf, 0x00efd8}, /* U+947F */ - {0x00e99281, 0x00efd7}, /* U+9481 */ - {0x00e995b7, 0x00c4b9}, /* U+9577 */ - {0x00e995b8, 0x8ffbd2}, /* U+9578 [2000] */ - {0x00e995b9, 0x8ffbd3}, /* U+9579 [2000] */ - {0x00e99680, 0x00cce7}, /* U+9580 */ - {0x00e99682, 0x00efd9}, /* U+9582 */ - {0x00e99683, 0x00c1ae}, /* U+9583 */ - {0x00e99686, 0x8ffbd4}, /* U+9586 [2000] */ - {0x00e99687, 0x00efda}, /* U+9587 */ - {0x00e99689, 0x00cac4}, /* U+9589 */ - {0x00e9968a, 0x00efdb}, /* U+958A */ - {0x00e9968b, 0x00b3ab}, /* U+958B */ - {0x00e9968c, 0x8ffbd5}, /* U+958C [2000] */ - {0x00e9968d, 0x8ffbd6}, /* U+958D [2000] */ - {0x00e9968e, 0x00fdce}, /* U+958E [2000] */ - {0x00e9968f, 0x00b1bc}, /* U+958F */ - {0x00e99691, 0x00b4d7}, /* U+9591 */ - {0x00e99693, 0x00b4d6}, /* U+9593 */ - {0x00e99694, 0x00efdc}, /* U+9594 */ - {0x00e99696, 0x00efdd}, /* U+9596 */ - {0x00e99698, 0x00efde}, /* U+9598 */ - {0x00e99699, 0x00efdf}, /* U+9599 */ - {0x00e9969f, 0x00fdcf}, /* U+959F [2000] */ - {0x00e996a0, 0x00efe0}, /* U+95A0 */ - {0x00e996a2, 0x00b4d8}, /* U+95A2 */ - {0x00e996a3, 0x00b3d5}, /* U+95A3 */ - {0x00e996a4, 0x00b9de}, /* U+95A4 */ - {0x00e996a5, 0x00c8b6}, /* U+95A5 */ - {0x00e996a6, 0x00fdd0}, /* U+95A6 [2000] */ - {0x00e996a7, 0x00efe2}, /* U+95A7 */ - {0x00e996a8, 0x00efe1}, /* U+95A8 */ - {0x00e996a9, 0x00fdd1}, /* U+95A9 [2000] */ - {0x00e996ab, 0x8ffbd8}, /* U+95AB [2000] */ - {0x00e996ac, 0x00fdd2}, /* U+95AC [2000] */ - {0x00e996ad, 0x00efe3}, /* U+95AD */ - {0x00e996b2, 0x00b1dc}, /* U+95B2 */ - {0x00e996b4, 0x8ffbd9}, /* U+95B4 [2000] */ - {0x00e996b6, 0x00fdd3}, /* U+95B6 [2000] */ - {0x00e996b9, 0x00efe6}, /* U+95B9 */ - {0x00e996bb, 0x00efe5}, /* U+95BB */ - {0x00e996bc, 0x00efe4}, /* U+95BC */ - {0x00e996bd, 0x00fdd4}, /* U+95BD [2000] */ - {0x00e996be, 0x00efe7}, /* U+95BE */ - {0x00e99783, 0x00efea}, /* U+95C3 */ - {0x00e99787, 0x00b0c7}, /* U+95C7 */ - {0x00e99788, 0x8ffbdb}, /* U+95C8 [2000] */ - {0x00e9978a, 0x00efe8}, /* U+95CA */ - {0x00e9978b, 0x00fdd5}, /* U+95CB [2000] */ - {0x00e9978c, 0x00efec}, /* U+95CC */ - {0x00e9978d, 0x00efeb}, /* U+95CD */ - {0x00e99790, 0x00fdd6}, /* U+95D0 [2000] */ - {0x00e99793, 0x00fdd7}, /* U+95D3 [2000] */ - {0x00e99794, 0x00efee}, /* U+95D4 */ - {0x00e99795, 0x00efed}, /* U+95D5 */ - {0x00e99796, 0x00efef}, /* U+95D6 */ - {0x00e99798, 0x00c6ae}, /* U+95D8 */ - {0x00e9979a, 0x00fdd9}, /* U+95DA [2000] */ - {0x00e9979c, 0x00eff0}, /* U+95DC */ - {0x00e9979e, 0x00fdda}, /* U+95DE [2000] */ - {0x00e997a1, 0x00eff1}, /* U+95E1 */ - {0x00e997a2, 0x00eff3}, /* U+95E2 */ - {0x00e997a5, 0x00eff2}, /* U+95E5 */ - {0x00e9989c, 0x00c9ec}, /* U+961C */ - {0x00e9989d, 0x8ffaa5}, /* U+961D [2000] */ - {0x00e998a1, 0x00eff4}, /* U+9621 */ - {0x00e998a8, 0x00eff5}, /* U+9628 */ - {0x00e998aa, 0x00bae5}, /* U+962A */ - {0x00e998ac, 0x8ffbde}, /* U+962C [2000] */ - {0x00e998ae, 0x00eff6}, /* U+962E */ - {0x00e998af, 0x00eff7}, /* U+962F */ - {0x00e998b2, 0x00cbc9}, /* U+9632 */ - {0x00e998b3, 0x8ffbdf}, /* U+9633 [2000] */ - {0x00e998b4, 0x8ffbe0}, /* U+9634 [2000] */ - {0x00e998bb, 0x00c1cb}, /* U+963B */ - {0x00e998bc, 0x8ffbe2}, /* U+963C [2000] */ - {0x00e998bf, 0x00b0a4}, /* U+963F */ - {0x00e99980, 0x00c2cb}, /* U+9640 */ - {0x00e99981, 0x8ffbe3}, /* U+9641 [2000] */ - {0x00e99982, 0x00eff8}, /* U+9642 */ - {0x00e99984, 0x00c9ed}, /* U+9644 */ - {0x00e9998b, 0x00effb}, /* U+964B */ - {0x00e9998c, 0x00eff9}, /* U+964C */ - {0x00e9998d, 0x00b9df}, /* U+964D */ - {0x00e9998f, 0x00effa}, /* U+964F */ - {0x00e99990, 0x00b8c2}, /* U+9650 */ - {0x00e99998, 0x00fddb}, /* U+9658 [2000] */ - {0x00e9999b, 0x00cac5}, /* U+965B */ - {0x00e9999c, 0x00effd}, /* U+965C */ - {0x00e9999d, 0x00f0a1}, /* U+965D */ - {0x00e9999e, 0x00effe}, /* U+965E */ - {0x00e9999f, 0x00f0a2}, /* U+965F */ - {0x00e999a1, 0x8ffbe4}, /* U+9661 [2000] */ - {0x00e999a2, 0x00b1a1}, /* U+9662 */ - {0x00e999a3, 0x00bfd8}, /* U+9663 */ - {0x00e999a4, 0x00bdfc}, /* U+9664 */ - {0x00e999a5, 0x00b4d9}, /* U+9665 */ - {0x00e999a6, 0x00f0a3}, /* U+9666 */ - {0x00e999aa, 0x00c7e6}, /* U+966A */ - {0x00e999ac, 0x00f0a5}, /* U+966C */ - {0x00e999b0, 0x00b1a2}, /* U+9670 */ - {0x00e999b2, 0x00f0a4}, /* U+9672 */ - {0x00e999b3, 0x00c4c4}, /* U+9673 */ - {0x00e999b5, 0x00cecd}, /* U+9675 */ - {0x00e999b6, 0x00c6ab}, /* U+9676 */ - {0x00e999b7, 0x00effc}, /* U+9677 */ - {0x00e999b8, 0x00cea6}, /* U+9678 */ - {0x00e999ba, 0x00b8b1}, /* U+967A */ - {0x00e999bd, 0x00cddb}, /* U+967D */ - {0x00e99a82, 0x8ffbe6}, /* U+9682 [2000] */ - {0x00e99a84, 0x00fddc}, /* U+9684 [2000] */ - {0x00e99a85, 0x00b6f9}, /* U+9685 */ - {0x00e99a86, 0x00ceb4}, /* U+9686 */ - {0x00e99a88, 0x00b7a8}, /* U+9688 */ - {0x00e99a8a, 0x00c2e2}, /* U+968A */ - {0x00e99a8b, 0x00e7a1}, /* U+968B */ - {0x00e99a8d, 0x00f0a6}, /* U+968D */ - {0x00e99a8e, 0x00b3ac}, /* U+968E */ - {0x00e99a8f, 0x00bfef}, /* U+968F */ - {0x00e99a94, 0x00b3d6}, /* U+9694 */ - {0x00e99a95, 0x00f0a8}, /* U+9695 */ - {0x00e99a97, 0x00f0a9}, /* U+9697 */ - {0x00e99a98, 0x00f0a7}, /* U+9698 */ - {0x00e99a99, 0x00b7e4}, /* U+9699 */ - {0x00e99a9a, 0x8ffbe8}, /* U+969A [2000] */ - {0x00e99a9b, 0x00badd}, /* U+969B */ - {0x00e99a9c, 0x00bee3}, /* U+969C */ - {0x00e99a9d, 0x00fdde}, /* U+969D [2000] */ - {0x00e99aa0, 0x00b1a3}, /* U+96A0 */ - {0x00e99aa3, 0x00ced9}, /* U+96A3 */ - {0x00e99aa4, 0x00fddf}, /* U+96A4 [2000] */ - {0x00e99aa5, 0x00fde0}, /* U+96A5 [2000] */ - {0x00e99aa7, 0x00f0ab}, /* U+96A7 */ - {0x00e99aa8, 0x00eeae}, /* U+96A8 */ - {0x00e99aa9, 0x8ffbeb}, /* U+96A9 [2000] */ - {0x00e99aaa, 0x00f0aa}, /* U+96AA */ - {0x00e99aaf, 0x8ffbec}, /* U+96AF [2000] */ - {0x00e99ab0, 0x00f0ae}, /* U+96B0 */ - {0x00e99ab1, 0x00f0ac}, /* U+96B1 */ - {0x00e99ab2, 0x00f0ad}, /* U+96B2 */ - {0x00e99ab3, 0x8ffbed}, /* U+96B3 [2000] */ - {0x00e99ab4, 0x00f0af}, /* U+96B4 */ - {0x00e99ab6, 0x00f0b0}, /* U+96B6 */ - {0x00e99ab7, 0x00ceec}, /* U+96B7 */ - {0x00e99ab8, 0x00f0b1}, /* U+96B8 */ - {0x00e99ab9, 0x00f0b2}, /* U+96B9 */ - {0x00e99aba, 0x8ffbee}, /* U+96BA [2000] */ - {0x00e99abb, 0x00c0c9}, /* U+96BB */ - {0x00e99abc, 0x00c8bb}, /* U+96BC */ - {0x00e99abd, 0x8ffbef}, /* U+96BD [2000] */ - {0x00e99b80, 0x00bffd}, /* U+96C0 */ - {0x00e99b81, 0x00b4e7}, /* U+96C1 */ - {0x00e99b84, 0x00cdba}, /* U+96C4 */ - {0x00e99b85, 0x00b2ed}, /* U+96C5 */ - {0x00e99b86, 0x00bdb8}, /* U+96C6 */ - {0x00e99b87, 0x00b8db}, /* U+96C7 */ - {0x00e99b89, 0x00f0b5}, /* U+96C9 */ - {0x00e99b8b, 0x00f0b4}, /* U+96CB */ - {0x00e99b8c, 0x00bbf3}, /* U+96CC */ - {0x00e99b8d, 0x00f0b6}, /* U+96CD */ - {0x00e99b8e, 0x00f0b3}, /* U+96CE */ - {0x00e99b91, 0x00bba8}, /* U+96D1 */ - {0x00e99b92, 0x00fde1}, /* U+96D2 [2000] */ - {0x00e99b95, 0x00f0ba}, /* U+96D5 */ - {0x00e99b96, 0x00eaad}, /* U+96D6 */ - {0x00e99b98, 0x8ffbf2}, /* U+96D8 [2000] */ - {0x00e99b99, 0x00d2d6}, /* U+96D9 */ - {0x00e99b9a, 0x8ffbf3}, /* U+96DA [2000] */ - {0x00e99b9b, 0x00bff7}, /* U+96DB */ - {0x00e99b9c, 0x00f0b8}, /* U+96DC */ - {0x00e99b9d, 0x8ffbf4}, /* U+96DD [2000] */ - {0x00e99b9e, 0x00fde2}, /* U+96DE [2000] */ - {0x00e99ba2, 0x00cea5}, /* U+96E2 */ - {0x00e99ba3, 0x00c6f1}, /* U+96E3 */ - {0x00e99ba8, 0x00b1ab}, /* U+96E8 */ - {0x00e99ba9, 0x00fde4}, /* U+96E9 [2000] */ - {0x00e99baa, 0x00c0e3}, /* U+96EA */ - {0x00e99bab, 0x00bcb6}, /* U+96EB */ - {0x00e99baf, 0x00fde5}, /* U+96EF [2000] */ - {0x00e99bb0, 0x00cab7}, /* U+96F0 */ - {0x00e99bb2, 0x00b1c0}, /* U+96F2 */ - {0x00e99bb6, 0x00ceed}, /* U+96F6 */ - {0x00e99bb7, 0x00cdeb}, /* U+96F7 */ - {0x00e99bb9, 0x00f0bb}, /* U+96F9 */ - {0x00e99bbb, 0x00c5c5}, /* U+96FB */ - {0x00e99c80, 0x00bcfb}, /* U+9700 */ - {0x00e99c84, 0x00f0bc}, /* U+9704 */ - {0x00e99c86, 0x00f0bd}, /* U+9706 */ - {0x00e99c87, 0x00bfcc}, /* U+9707 */ - {0x00e99c88, 0x00f0be}, /* U+9708 */ - {0x00e99c8a, 0x00ceee}, /* U+970A */ - {0x00e99c8d, 0x00f0b9}, /* U+970D */ - {0x00e99c8e, 0x00f0c0}, /* U+970E */ - {0x00e99c8f, 0x00f0c2}, /* U+970F */ - {0x00e99c91, 0x00f0c1}, /* U+9711 */ - {0x00e99c93, 0x00f0bf}, /* U+9713 */ - {0x00e99c94, 0x8ffbf6}, /* U+9714 [2000] */ - {0x00e99c96, 0x00f0c3}, /* U+9716 */ - {0x00e99c99, 0x00f0c4}, /* U+9719 */ - {0x00e99c9c, 0x00c1fa}, /* U+971C */ - {0x00e99c9e, 0x00b2e2}, /* U+971E */ - {0x00e99ca3, 0x8ffbf7}, /* U+9723 [2000] */ - {0x00e99ca4, 0x00f0c5}, /* U+9724 */ - {0x00e99ca7, 0x00ccb8}, /* U+9727 */ - {0x00e99caa, 0x00f0c6}, /* U+972A */ - {0x00e99cb0, 0x00f0c7}, /* U+9730 */ - {0x00e99cb2, 0x00cfaa}, /* U+9732 */ - {0x00e99cb3, 0x00fde6}, /* U+9733 [2000] */ - {0x00e99cb6, 0x8ffbf9}, /* U+9736 [2000] */ - {0x00e99cb8, 0x00dbb1}, /* U+9738 */ - {0x00e99cb9, 0x00f0c8}, /* U+9739 */ - {0x00e99cbb, 0x00fde7}, /* U+973B [2000] */ - {0x00e99cbd, 0x00f0c9}, /* U+973D */ - {0x00e99cbe, 0x00f0ca}, /* U+973E */ - {0x00e99d81, 0x8ffbfa}, /* U+9741 [2000] */ - {0x00e99d82, 0x00f0ce}, /* U+9742 */ - {0x00e99d84, 0x00f0cb}, /* U+9744 */ - {0x00e99d86, 0x00f0cc}, /* U+9746 */ - {0x00e99d87, 0x8ffbfb}, /* U+9747 [2000] */ - {0x00e99d88, 0x00f0cd}, /* U+9748 */ - {0x00e99d89, 0x00f0cf}, /* U+9749 */ - {0x00e99d8d, 0x00fde8}, /* U+974D [2000] */ - {0x00e99d8e, 0x00fde9}, /* U+974E [2000] */ - {0x00e99d8f, 0x00fdea}, /* U+974F [2000] */ - {0x00e99d92, 0x00c0c4}, /* U+9752 */ - {0x00e99d95, 0x8ffbfc}, /* U+9755 [2000] */ - {0x00e99d96, 0x00ccf7}, /* U+9756 */ - {0x00e99d97, 0x8ffbfd}, /* U+9757 [2000] */ - {0x00e99d99, 0x00c0c5}, /* U+9759 */ - {0x00e99d9a, 0x00fdeb}, /* U+975A [2000] */ - {0x00e99d9b, 0x8ffbfe}, /* U+975B [2000] */ - {0x00e99d9c, 0x00f0d0}, /* U+975C */ - {0x00e99d9e, 0x00c8f3}, /* U+975E */ - {0x00e99da0, 0x00f0d1}, /* U+9760 */ - {0x00e99da1, 0x00f3d3}, /* U+9761 */ - {0x00e99da2, 0x00cccc}, /* U+9762 */ - {0x00e99da4, 0x00f0d2}, /* U+9764 */ - {0x00e99da6, 0x00f0d3}, /* U+9766 */ - {0x00e99da8, 0x00f0d4}, /* U+9768 */ - {0x00e99da9, 0x00b3d7}, /* U+9769 */ - {0x00e99daa, 0x8ffca1}, /* U+976A [2000] */ - {0x00e99dab, 0x00f0d6}, /* U+976B */ - {0x00e99dad, 0x00bfd9}, /* U+976D */ - {0x00e99dae, 0x00fdec}, /* U+976E [2000] */ - {0x00e99db1, 0x00f0d7}, /* U+9771 */ - {0x00e99db3, 0x00fded}, /* U+9773 [2000] */ - {0x00e99db4, 0x00b7a4}, /* U+9774 */ - {0x00e99db9, 0x00f0d8}, /* U+9779 */ - {0x00e99dba, 0x00f0dc}, /* U+977A */ - {0x00e99dbc, 0x00f0da}, /* U+977C */ - {0x00e99e81, 0x00f0db}, /* U+9781 */ - {0x00e99e84, 0x00b3f3}, /* U+9784 */ - {0x00e99e85, 0x00f0d9}, /* U+9785 */ - {0x00e99e86, 0x00f0dd}, /* U+9786 */ - {0x00e99e8b, 0x00f0de}, /* U+978B */ - {0x00e99e8d, 0x00b0c8}, /* U+978D */ - {0x00e99e8f, 0x00f0df}, /* U+978F */ - {0x00e99e90, 0x00f0e0}, /* U+9790 */ - {0x00e99e95, 0x00fdee}, /* U+9795 [2000] */ - {0x00e99e96, 0x8ffca4}, /* U+9796 [2000] */ - {0x00e99e98, 0x00bee4}, /* U+9798 */ - {0x00e99e9a, 0x8ffca5}, /* U+979A [2000] */ - {0x00e99e9c, 0x00f0e1}, /* U+979C */ - {0x00e99e9e, 0x8ffca6}, /* U+979E [2000] */ - {0x00e99ea0, 0x00b5c7}, /* U+97A0 */ - {0x00e99ea2, 0x8ffca7}, /* U+97A2 [2000] */ - {0x00e99ea3, 0x00f0e4}, /* U+97A3 */ - {0x00e99ea6, 0x00f0e3}, /* U+97A6 */ - {0x00e99ea8, 0x00f0e2}, /* U+97A8 */ - {0x00e99eab, 0x00ebf1}, /* U+97AB */ - {0x00e99ead, 0x00cadc}, /* U+97AD */ - {0x00e99eae, 0x00fdef}, /* U+97AE [2000] */ - {0x00e99eb1, 0x8ffca8}, /* U+97B1 [2000] */ - {0x00e99eb2, 0x8ffca9}, /* U+97B2 [2000] */ - {0x00e99eb3, 0x00f0e5}, /* U+97B3 */ - {0x00e99eb4, 0x00f0e6}, /* U+97B4 */ - {0x00e99eba, 0x00fdf0}, /* U+97BA [2000] */ - {0x00e99ebe, 0x8ffcaa}, /* U+97BE [2000] */ - {0x00e99f81, 0x00fdf1}, /* U+97C1 [2000] */ - {0x00e99f83, 0x00f0e7}, /* U+97C3 */ - {0x00e99f86, 0x00f0e8}, /* U+97C6 */ - {0x00e99f88, 0x00f0e9}, /* U+97C8 */ - {0x00e99f89, 0x00fdf2}, /* U+97C9 [2000] */ - {0x00e99f8b, 0x00f0ea}, /* U+97CB */ - {0x00e99f8c, 0x8ffcab}, /* U+97CC [2000] */ - {0x00e99f91, 0x8ffcac}, /* U+97D1 [2000] */ - {0x00e99f93, 0x00b4da}, /* U+97D3 */ - {0x00e99f94, 0x8ffcad}, /* U+97D4 [2000] */ - {0x00e99f98, 0x8ffcae}, /* U+97D8 [2000] */ - {0x00e99f99, 0x8ffcaf}, /* U+97D9 [2000] */ - {0x00e99f9b, 0x00fdf4}, /* U+97DB [2000] */ - {0x00e99f9c, 0x00f0eb}, /* U+97DC */ - {0x00e99f9e, 0x00fdf3}, /* U+97DE [2000] */ - {0x00e99fa1, 0x8ffcb0}, /* U+97E1 [2000] */ - {0x00e99fad, 0x00f0ec}, /* U+97ED */ - {0x00e99fae, 0x00c7a3}, /* U+97EE */ - {0x00e99fb1, 0x8ffcb1}, /* U+97F1 [2000] */ - {0x00e99fb2, 0x00f0ee}, /* U+97F2 */ - {0x00e99fb3, 0x00b2bb}, /* U+97F3 */ - {0x00e99fb4, 0x00fdf5}, /* U+97F4 [2000] */ - {0x00e99fb5, 0x00f0f1}, /* U+97F5 */ - {0x00e99fb6, 0x00f0f0}, /* U+97F6 */ - {0x00e99fbb, 0x00b1a4}, /* U+97FB */ - {0x00e99fbf, 0x00b6c1}, /* U+97FF */ - {0x00e9a081, 0x00cac7}, /* U+9801 */ - {0x00e9a082, 0x00c4ba}, /* U+9802 */ - {0x00e9a083, 0x00baa2}, /* U+9803 */ - {0x00e9a084, 0x8ffcb2}, /* U+9804 [2000] */ - {0x00e9a085, 0x00b9e0}, /* U+9805 */ - {0x00e9a086, 0x00bde7}, /* U+9806 */ - {0x00e9a088, 0x00bfdc}, /* U+9808 */ - {0x00e9a08a, 0x00fdf7}, /* U+980A [2000] */ - {0x00e9a08c, 0x00f0f3}, /* U+980C */ - {0x00e9a08d, 0x8ffcb3}, /* U+980D [2000] */ - {0x00e9a08e, 0x8ffcb4}, /* U+980E [2000] */ - {0x00e9a08f, 0x00f0f2}, /* U+980F */ - {0x00e9a090, 0x00cdc2}, /* U+9810 */ - {0x00e9a091, 0x00b4e8}, /* U+9811 */ - {0x00e9a092, 0x00c8d2}, /* U+9812 */ - {0x00e9a093, 0x00c6dc}, /* U+9813 */ - {0x00e9a094, 0x8ffcb5}, /* U+9814 [2000] */ - {0x00e9a096, 0x8ffcb6}, /* U+9816 [2000] */ - {0x00e9a097, 0x00bffc}, /* U+9817 */ - {0x00e9a098, 0x00cece}, /* U+9818 */ - {0x00e9a09a, 0x00b7db}, /* U+981A */ - {0x00e9a09e, 0x00fdf8}, /* U+981E [2000] */ - {0x00e9a0a1, 0x00f0f6}, /* U+9821 */ - {0x00e9a0a3, 0x8ffcb9}, /* U+9823 [2000] */ - {0x00e9a0a4, 0x00f0f5}, /* U+9824 */ - {0x00e9a0a5, 0x8ffcbc}, /* U+9825 [2000] */ - {0x00e9a0ab, 0x00fdf9}, /* U+982B [2000] */ - {0x00e9a0ac, 0x00cbcb}, /* U+982C */ - {0x00e9a0ad, 0x00c6ac}, /* U+982D */ - {0x00e9a0b0, 0x00fdfa}, /* U+9830 [2000] */ - {0x00e9a0b2, 0x8ffcba}, /* U+9832 [2000] */ - {0x00e9a0b3, 0x8ffcbb}, /* U+9833 [2000] */ - {0x00e9a0b4, 0x00b1d0}, /* U+9834 */ - {0x00e9a0b7, 0x00f0f7}, /* U+9837 */ - {0x00e9a0b8, 0x00f0f4}, /* U+9838 */ - {0x00e9a0bb, 0x00c9d1}, /* U+983B */ - {0x00e9a0bc, 0x00cdea}, /* U+983C */ - {0x00e9a0bd, 0x00f0f8}, /* U+983D */ - {0x00e9a186, 0x00f0f9}, /* U+9846 */ - {0x00e9a187, 0x8ffcbd}, /* U+9847 [2000] */ - {0x00e9a18b, 0x00f0fb}, /* U+984B */ - {0x00e9a18c, 0x00c2ea}, /* U+984C */ - {0x00e9a18d, 0x00b3db}, /* U+984D */ - {0x00e9a18e, 0x00b3dc}, /* U+984E */ - {0x00e9a18f, 0x00f0fa}, /* U+984F */ - {0x00e9a192, 0x00fdfc}, /* U+9852 [2000] */ - {0x00e9a193, 0x00fdfd}, /* U+9853 [2000] */ - {0x00e9a194, 0x00b4e9}, /* U+9854 */ - {0x00e9a195, 0x00b8b2}, /* U+9855 */ - {0x00e9a196, 0x00fdfe}, /* U+9856 [2000] */ - {0x00e9a197, 0x00fea1}, /* U+9857 [2000] */ - {0x00e9a198, 0x00b4ea}, /* U+9858 */ - {0x00e9a199, 0x00fea2}, /* U+9859 [2000] */ - {0x00e9a19a, 0x00fea3}, /* U+985A [2000] */ - {0x00e9a19b, 0x00c5bf}, /* U+985B */ - {0x00e9a19e, 0x00cee0}, /* U+985E */ - {0x00e9a1a5, 0x00fea5}, /* U+9865 [2000] */ - {0x00e9a1a6, 0x8ffcbe}, /* U+9866 [2000] */ - {0x00e9a1a7, 0x00b8dc}, /* U+9867 */ - {0x00e9a1ab, 0x00f0fc}, /* U+986B */ - {0x00e9a1ac, 0x00fea6}, /* U+986C [2000] */ - {0x00e9a1af, 0x00f0fd}, /* U+986F */ - {0x00e9a1b0, 0x00f0fe}, /* U+9870 */ - {0x00e9a1b1, 0x00f1a1}, /* U+9871 */ - {0x00e9a1b3, 0x00f1a3}, /* U+9873 */ - {0x00e9a1b4, 0x00f1a2}, /* U+9874 */ - {0x00e9a2a8, 0x00c9f7}, /* U+98A8 */ - {0x00e9a2aa, 0x00f1a4}, /* U+98AA */ - {0x00e9a2ab, 0x8ffcbf}, /* U+98AB [2000] */ - {0x00e9a2ad, 0x8ffcc0}, /* U+98AD [2000] */ - {0x00e9a2af, 0x00f1a5}, /* U+98AF */ - {0x00e9a2b0, 0x8ffcc1}, /* U+98B0 [2000] */ - {0x00e9a2b1, 0x00f1a6}, /* U+98B1 */ - {0x00e9a2b6, 0x00f1a7}, /* U+98B6 */ - {0x00e9a2b7, 0x8ffcc3}, /* U+98B7 [2000] */ - {0x00e9a2b8, 0x8ffcc4}, /* U+98B8 [2000] */ - {0x00e9a2ba, 0x00fea7}, /* U+98BA [2000] */ - {0x00e9a2bb, 0x8ffcc5}, /* U+98BB [2000] */ - {0x00e9a2bc, 0x8ffcc6}, /* U+98BC [2000] */ - {0x00e9a2bf, 0x8ffcc7}, /* U+98BF [2000] */ - {0x00e9a382, 0x8ffcc8}, /* U+98C2 [2000] */ - {0x00e9a383, 0x00f1a9}, /* U+98C3 */ - {0x00e9a384, 0x00f1a8}, /* U+98C4 */ - {0x00e9a386, 0x00f1aa}, /* U+98C6 */ - {0x00e9a387, 0x8ffcc9}, /* U+98C7 [2000] */ - {0x00e9a388, 0x00fea8}, /* U+98C8 [2000] */ - {0x00e9a38b, 0x8ffcca}, /* U+98CB [2000] */ - {0x00e9a39b, 0x00c8f4}, /* U+98DB */ - {0x00e9a39c, 0x00e6cc}, /* U+98DC */ - {0x00e9a39f, 0x00bfa9}, /* U+98DF */ - {0x00e9a3a0, 0x8ffccb}, /* U+98E0 [2000] */ - {0x00e9a3a1, 0x8ffccd}, /* U+98E1 [2000] */ - {0x00e9a3a2, 0x00b5b2}, /* U+98E2 */ - {0x00e9a3a3, 0x8ffcce}, /* U+98E3 [2000] */ - {0x00e9a3a5, 0x8ffccf}, /* U+98E5 [2000] */ - {0x00e9a3a7, 0x00fea9}, /* U+98E7 [2000] */ - {0x00e9a3a9, 0x00f1ab}, /* U+98E9 */ - {0x00e9a3aa, 0x8ffcd0}, /* U+98EA [2000] */ - {0x00e9a3ab, 0x00f1ac}, /* U+98EB */ - {0x00e9a3ad, 0x00d2ac}, /* U+98ED */ - {0x00e9a3ae, 0x00ddbb}, /* U+98EE */ - {0x00e9a3af, 0x00c8d3}, /* U+98EF */ - {0x00e9a3b0, 0x8ffcd1}, /* U+98F0 [2000] */ - {0x00e9a3b1, 0x8ffcd2}, /* U+98F1 [2000] */ - {0x00e9a3b2, 0x00b0fb}, /* U+98F2 */ - {0x00e9a3b3, 0x8ffcd3}, /* U+98F3 [2000] */ - {0x00e9a3b4, 0x00b0bb}, /* U+98F4 */ - {0x00e9a3bc, 0x00bbf4}, /* U+98FC */ - {0x00e9a3bd, 0x00cbb0}, /* U+98FD */ - {0x00e9a3be, 0x00befe}, /* U+98FE */ - {0x00e9a483, 0x00f1ad}, /* U+9903 */ - {0x00e9a485, 0x00ccdf}, /* U+9905 */ - {0x00e9a488, 0x8ffcd4}, /* U+9908 [2000] */ - {0x00e9a489, 0x00f1ae}, /* U+9909 */ - {0x00e9a48a, 0x00cddc}, /* U+990A */ - {0x00e9a48c, 0x00b1c2}, /* U+990C */ - {0x00e9a490, 0x00bbc1}, /* U+9910 */ - {0x00e9a492, 0x00f1af}, /* U+9912 */ - {0x00e9a493, 0x00b2ee}, /* U+9913 */ - {0x00e9a494, 0x00f1b0}, /* U+9914 */ - {0x00e9a496, 0x8ffcd7}, /* U+9916 [2000] */ - {0x00e9a497, 0x8ffcd8}, /* U+9917 [2000] */ - {0x00e9a498, 0x00f1b1}, /* U+9918 */ - {0x00e9a49a, 0x8ffcda}, /* U+991A [2000] */ - {0x00e9a49b, 0x8ffcdb}, /* U+991B [2000] */ - {0x00e9a49c, 0x8ffcdc}, /* U+991C [2000] */ - {0x00e9a49d, 0x00f1b3}, /* U+991D */ - {0x00e9a49e, 0x00f1b4}, /* U+991E */ - {0x00e9a4a0, 0x00f1b6}, /* U+9920 */ - {0x00e9a4a1, 0x00f1b2}, /* U+9921 */ - {0x00e9a4a4, 0x00f1b5}, /* U+9924 */ - {0x00e9a4a8, 0x00b4db}, /* U+9928 */ - {0x00e9a4ac, 0x00f1b7}, /* U+992C */ - {0x00e9a4ae, 0x00f1b8}, /* U+992E */ - {0x00e9a4b1, 0x8ffcde}, /* U+9931 [2000] */ - {0x00e9a4b2, 0x8ffcdf}, /* U+9932 [2000] */ - {0x00e9a4b3, 0x8ffce0}, /* U+9933 [2000] */ - {0x00e9a4ba, 0x8ffce1}, /* U+993A [2000] */ - {0x00e9a4bb, 0x8ffce2}, /* U+993B [2000] */ - {0x00e9a4bc, 0x8ffce3}, /* U+993C [2000] */ - {0x00e9a4bd, 0x00f1b9}, /* U+993D */ - {0x00e9a4be, 0x00f1ba}, /* U+993E */ - {0x00e9a580, 0x8ffce4}, /* U+9940 [2000] */ - {0x00e9a581, 0x8ffce5}, /* U+9941 [2000] */ - {0x00e9a582, 0x00f1bb}, /* U+9942 */ - {0x00e9a585, 0x00f1bd}, /* U+9945 */ - {0x00e9a586, 0x8ffce6}, /* U+9946 [2000] */ - {0x00e9a589, 0x00f1bc}, /* U+9949 */ - {0x00e9a58b, 0x00f1bf}, /* U+994B */ - {0x00e9a58c, 0x00f1c2}, /* U+994C */ - {0x00e9a58d, 0x8ffce7}, /* U+994D [2000] */ - {0x00e9a58e, 0x8ffce8}, /* U+994E [2000] */ - {0x00e9a590, 0x00f1be}, /* U+9950 */ - {0x00e9a591, 0x00f1c0}, /* U+9951 */ - {0x00e9a592, 0x00f1c1}, /* U+9952 */ - {0x00e9a595, 0x00f1c3}, /* U+9955 */ - {0x00e9a597, 0x00b6c2}, /* U+9957 */ - {0x00e9a598, 0x00feaa}, /* U+9958 [2000] */ - {0x00e9a59c, 0x8ffce9}, /* U+995C [2000] */ - {0x00e9a59f, 0x8ffcea}, /* U+995F [2000] */ - {0x00e9a5a0, 0x8ffceb}, /* U+9960 [2000] */ - {0x00e9a696, 0x00bcf3}, /* U+9996 */ - {0x00e9a697, 0x00f1c4}, /* U+9997 */ - {0x00e9a698, 0x00f1c5}, /* U+9998 */ - {0x00e9a699, 0x00b9e1}, /* U+9999 */ - {0x00e9a69e, 0x00feab}, /* U+999E [2000] */ - {0x00e9a6a3, 0x8ffcec}, /* U+99A3 [2000] */ - {0x00e9a6a5, 0x00f1c6}, /* U+99A5 */ - {0x00e9a6a6, 0x8ffced}, /* U+99A6 [2000] */ - {0x00e9a6a8, 0x00b3be}, /* U+99A8 */ - {0x00e9a6ac, 0x00c7cf}, /* U+99AC */ - {0x00e9a6ad, 0x00f1c7}, /* U+99AD */ - {0x00e9a6ae, 0x00f1c8}, /* U+99AE */ - {0x00e9a6b3, 0x00c3da}, /* U+99B3 */ - {0x00e9a6b4, 0x00c6eb}, /* U+99B4 */ - {0x00e9a6b9, 0x8ffcee}, /* U+99B9 [2000] */ - {0x00e9a6bc, 0x00f1c9}, /* U+99BC */ - {0x00e9a6bd, 0x8ffcef}, /* U+99BD [2000] */ - {0x00e9a6bf, 0x8ffcf0}, /* U+99BF [2000] */ - {0x00e9a781, 0x00c7fd}, /* U+99C1 */ - {0x00e9a783, 0x8ffcf1}, /* U+99C3 [2000] */ - {0x00e9a784, 0x00c2cc}, /* U+99C4 */ - {0x00e9a785, 0x00b1d8}, /* U+99C5 */ - {0x00e9a786, 0x00b6ee}, /* U+99C6 */ - {0x00e9a788, 0x00b6ef}, /* U+99C8 */ - {0x00e9a789, 0x8ffcf2}, /* U+99C9 [2000] */ - {0x00e9a790, 0x00c3f3}, /* U+99D0 */ - {0x00e9a791, 0x00f1ce}, /* U+99D1 */ - {0x00e9a792, 0x00b6f0}, /* U+99D2 */ - {0x00e9a794, 0x8ffcf3}, /* U+99D4 [2000] */ - {0x00e9a795, 0x00b2ef}, /* U+99D5 */ - {0x00e9a798, 0x00f1cd}, /* U+99D8 */ - {0x00e9a799, 0x8ffcf4}, /* U+99D9 [2000] */ - {0x00e9a79b, 0x00f1cb}, /* U+99DB */ - {0x00e9a79d, 0x00f1cc}, /* U+99DD */ - {0x00e9a79e, 0x8ffcf5}, /* U+99DE [2000] */ - {0x00e9a79f, 0x00f1ca}, /* U+99DF */ - {0x00e9a7a2, 0x00f1d8}, /* U+99E2 */ - {0x00e9a7ad, 0x00f1cf}, /* U+99ED */ - {0x00e9a7ae, 0x00f1d0}, /* U+99EE */ - {0x00e9a7b0, 0x8ffcf7}, /* U+99F0 [2000] */ - {0x00e9a7b1, 0x00f1d1}, /* U+99F1 */ - {0x00e9a7b2, 0x00f1d2}, /* U+99F2 */ - {0x00e9a7b8, 0x00f1d4}, /* U+99F8 */ - {0x00e9a7b9, 0x8ffcf8}, /* U+99F9 [2000] */ - {0x00e9a7bb, 0x00f1d3}, /* U+99FB */ - {0x00e9a7bc, 0x8ffcf9}, /* U+99FC [2000] */ - {0x00e9a7bf, 0x00bdd9}, /* U+99FF */ - {0x00e9a881, 0x00f1d5}, /* U+9A01 */ - {0x00e9a882, 0x00feac}, /* U+9A02 [2000] */ - {0x00e9a883, 0x00fead}, /* U+9A03 [2000] */ - {0x00e9a885, 0x00f1d7}, /* U+9A05 */ - {0x00e9a88a, 0x8ffcfa}, /* U+9A0A [2000] */ - {0x00e9a88e, 0x00b5b3}, /* U+9A0E */ - {0x00e9a88f, 0x00f1d6}, /* U+9A0F */ - {0x00e9a891, 0x8ffcfb}, /* U+9A11 [2000] */ - {0x00e9a892, 0x00c1fb}, /* U+9A12 */ - {0x00e9a893, 0x00b8b3}, /* U+9A13 */ - {0x00e9a896, 0x8ffcfc}, /* U+9A16 [2000] */ - {0x00e9a899, 0x00f1d9}, /* U+9A19 */ - {0x00e9a89a, 0x8ffcfd}, /* U+9A1A [2000] */ - {0x00e9a8a0, 0x8ffcfe}, /* U+9A20 [2000] */ - {0x00e9a8a4, 0x00feae}, /* U+9A24 [2000] */ - {0x00e9a8a8, 0x00c2cd}, /* U+9A28 */ - {0x00e9a8ab, 0x00f1da}, /* U+9A2B */ - {0x00e9a8ad, 0x00feaf}, /* U+9A2D [2000] */ - {0x00e9a8ae, 0x00feb0}, /* U+9A2E [2000] */ - {0x00e9a8b0, 0x00c6ad}, /* U+9A30 */ - {0x00e9a8b1, 0x8ffda1}, /* U+9A31 [2000] */ - {0x00e9a8b6, 0x8ffda2}, /* U+9A36 [2000] */ - {0x00e9a8b7, 0x00f1db}, /* U+9A37 */ - {0x00e9a8b8, 0x00feb1}, /* U+9A38 [2000] */ - {0x00e9a8be, 0x00f1e0}, /* U+9A3E */ - {0x00e9a980, 0x00f1de}, /* U+9A40 */ - {0x00e9a982, 0x00f1dd}, /* U+9A42 */ - {0x00e9a983, 0x00f1df}, /* U+9A43 */ - {0x00e9a984, 0x8ffda3}, /* U+9A44 [2000] */ - {0x00e9a985, 0x00f1dc}, /* U+9A45 */ - {0x00e9a98a, 0x00feb2}, /* U+9A4A [2000] */ - {0x00e9a98c, 0x8ffda4}, /* U+9A4C [2000] */ - {0x00e9a98d, 0x00f1e2}, /* U+9A4D */ - {0x00e9a98e, 0x00feb3}, /* U+9A4E [2000] */ - {0x00e9a992, 0x00feb4}, /* U+9A52 [2000] */ - {0x00e9a995, 0x00f1e1}, /* U+9A55 */ - {0x00e9a997, 0x00f1e4}, /* U+9A57 */ - {0x00e9a998, 0x8ffda5}, /* U+9A58 [2000] */ - {0x00e9a99a, 0x00b6c3}, /* U+9A5A */ - {0x00e9a99b, 0x00f1e3}, /* U+9A5B */ - {0x00e9a99f, 0x00f1e5}, /* U+9A5F */ - {0x00e9a9a2, 0x00f1e6}, /* U+9A62 */ - {0x00e9a9a4, 0x00f1e8}, /* U+9A64 */ - {0x00e9a9a5, 0x00f1e7}, /* U+9A65 */ - {0x00e9a9a9, 0x00f1e9}, /* U+9A69 */ - {0x00e9a9aa, 0x00f1eb}, /* U+9A6A */ - {0x00e9a9ab, 0x00f1ea}, /* U+9A6B */ - {0x00e9aaa8, 0x00b9fc}, /* U+9AA8 */ - {0x00e9aaad, 0x00f1ec}, /* U+9AAD */ - {0x00e9aaaf, 0x8ffda7}, /* U+9AAF [2000] */ - {0x00e9aab0, 0x00f1ed}, /* U+9AB0 */ - {0x00e9aab6, 0x00feb5}, /* U+9AB6 [2000] */ - {0x00e9aab7, 0x8ffda9}, /* U+9AB7 [2000] */ - {0x00e9aab8, 0x00b3bc}, /* U+9AB8 */ - {0x00e9aab9, 0x8ffdab}, /* U+9AB9 [2000] */ - {0x00e9aabc, 0x00f1ee}, /* U+9ABC */ - {0x00e9ab80, 0x00f1ef}, /* U+9AC0 */ - {0x00e9ab81, 0x00feb6}, /* U+9AC1 [2000] */ - {0x00e9ab83, 0x00feb7}, /* U+9AC3 [2000] */ - {0x00e9ab84, 0x00bff1}, /* U+9AC4 */ - {0x00e9ab86, 0x8ffdad}, /* U+9AC6 [2000] */ - {0x00e9ab8e, 0x00feb8}, /* U+9ACE [2000] */ - {0x00e9ab8f, 0x00f1f0}, /* U+9ACF */ - {0x00e9ab90, 0x8ffdae}, /* U+9AD0 [2000] */ - {0x00e9ab91, 0x00f1f1}, /* U+9AD1 */ - {0x00e9ab92, 0x8ffdaf}, /* U+9AD2 [2000] */ - {0x00e9ab93, 0x00f1f2}, /* U+9AD3 */ - {0x00e9ab94, 0x00f1f3}, /* U+9AD4 */ - {0x00e9ab95, 0x8ffdb0}, /* U+9AD5 [2000] */ - {0x00e9ab96, 0x00feb9}, /* U+9AD6 [2000] */ - {0x00e9ab98, 0x00b9e2}, /* U+9AD8 */ - {0x00e9ab9c, 0x8ffdb2}, /* U+9ADC [2000] */ - {0x00e9ab9e, 0x00f1f4}, /* U+9ADE */ - {0x00e9ab9f, 0x00f1f5}, /* U+9ADF */ - {0x00e9aba0, 0x8ffdb3}, /* U+9AE0 [2000] */ - {0x00e9aba2, 0x00f1f6}, /* U+9AE2 */ - {0x00e9aba3, 0x00f1f7}, /* U+9AE3 */ - {0x00e9aba5, 0x8ffdb4}, /* U+9AE5 [2000] */ - {0x00e9aba6, 0x00f1f8}, /* U+9AE6 */ - {0x00e9aba9, 0x8ffdb5}, /* U+9AE9 [2000] */ - {0x00e9abaa, 0x00c8b1}, /* U+9AEA */ - {0x00e9abab, 0x00f1fa}, /* U+9AEB */ - {0x00e9abad, 0x00c9a6}, /* U+9AED */ - {0x00e9abae, 0x00f1fb}, /* U+9AEE */ - {0x00e9abaf, 0x00f1f9}, /* U+9AEF */ - {0x00e9abb1, 0x00f1fd}, /* U+9AF1 */ - {0x00e9abb4, 0x00f1fc}, /* U+9AF4 */ - {0x00e9abb7, 0x00f1fe}, /* U+9AF7 */ - {0x00e9abb9, 0x00feba}, /* U+9AF9 [2000] */ - {0x00e9abbb, 0x00f2a1}, /* U+9AFB */ - {0x00e9ac82, 0x00febb}, /* U+9B02 [2000] */ - {0x00e9ac83, 0x8ffdb6}, /* U+9B03 [2000] */ - {0x00e9ac86, 0x00f2a2}, /* U+9B06 */ - {0x00e9ac88, 0x00febc}, /* U+9B08 [2000] */ - {0x00e9ac8c, 0x8ffdb7}, /* U+9B0C [2000] */ - {0x00e9ac90, 0x8ffdb8}, /* U+9B10 [2000] */ - {0x00e9ac92, 0x8ffdb9}, /* U+9B12 [2000] */ - {0x00e9ac96, 0x8ffdba}, /* U+9B16 [2000] */ - {0x00e9ac98, 0x00f2a3}, /* U+9B18 */ - {0x00e9ac9a, 0x00f2a4}, /* U+9B1A */ - {0x00e9ac9c, 0x8ffdbb}, /* U+9B1C [2000] */ - {0x00e9ac9f, 0x00f2a5}, /* U+9B1F */ - {0x00e9aca0, 0x00febd}, /* U+9B20 [2000] */ - {0x00e9aca2, 0x00f2a6}, /* U+9B22 */ - {0x00e9aca3, 0x00f2a7}, /* U+9B23 */ - {0x00e9aca5, 0x00f2a8}, /* U+9B25 */ - {0x00e9aca7, 0x00f2a9}, /* U+9B27 */ - {0x00e9aca8, 0x00f2aa}, /* U+9B28 */ - {0x00e9aca9, 0x00f2ab}, /* U+9B29 */ - {0x00e9acaa, 0x00f2ac}, /* U+9B2A */ - {0x00e9acab, 0x8ffdbc}, /* U+9B2B [2000] */ - {0x00e9acad, 0x00febf}, /* U+9B2D [2000] */ - {0x00e9acae, 0x00f2ad}, /* U+9B2E */ - {0x00e9acaf, 0x00f2ae}, /* U+9B2F */ - {0x00e9acb1, 0x00ddb5}, /* U+9B31 */ - {0x00e9acb2, 0x00f2af}, /* U+9B32 */ - {0x00e9acb3, 0x8ffdbd}, /* U+9B33 [2000] */ - {0x00e9acbb, 0x00e4f8}, /* U+9B3B */ - {0x00e9acbc, 0x00b5b4}, /* U+9B3C */ - {0x00e9acbd, 0x8ffdbe}, /* U+9B3D [2000] */ - {0x00e9ad81, 0x00b3a1}, /* U+9B41 */ - {0x00e9ad82, 0x00bab2}, /* U+9B42 */ - {0x00e9ad83, 0x00f2b1}, /* U+9B43 */ - {0x00e9ad84, 0x00f2b0}, /* U+9B44 */ - {0x00e9ad85, 0x00cca5}, /* U+9B45 */ - {0x00e9ad8b, 0x8ffdc0}, /* U+9B4B [2000] */ - {0x00e9ad8d, 0x00f2b3}, /* U+9B4D */ - {0x00e9ad8e, 0x00f2b4}, /* U+9B4E */ - {0x00e9ad8f, 0x00f2b2}, /* U+9B4F */ - {0x00e9ad91, 0x00f2b5}, /* U+9B51 */ - {0x00e9ad94, 0x00cbe2}, /* U+9B54 */ - {0x00e9ad98, 0x00f2b6}, /* U+9B58 */ - {0x00e9ad9a, 0x00b5fb}, /* U+9B5A */ - {0x00e9ad9e, 0x00fec0}, /* U+9B5E [2000] */ - {0x00e9ada3, 0x8ffdc1}, /* U+9B63 [2000] */ - {0x00e9ada5, 0x8ffdc2}, /* U+9B65 [2000] */ - {0x00e9ada6, 0x00fec2}, /* U+9B66 [2000] */ - {0x00e9adab, 0x8ffdc3}, /* U+9B6B [2000] */ - {0x00e9adac, 0x8ffdc4}, /* U+9B6C [2000] */ - {0x00e9adaf, 0x00cfa5}, /* U+9B6F */ - {0x00e9adb2, 0x00fec3}, /* U+9B72 [2000] */ - {0x00e9adb3, 0x8ffdc5}, /* U+9B73 [2000] */ - {0x00e9adb4, 0x00f2b7}, /* U+9B74 */ - {0x00e9adb5, 0x00fec4}, /* U+9B75 [2000] */ - {0x00e9adb6, 0x8ffdc6}, /* U+9B76 [2000] */ - {0x00e9adb7, 0x8ffdc7}, /* U+9B77 [2000] */ - {0x00e9adb9, 0x00fec1}, /* U+9B79 [2000] */ - {0x00e9ae83, 0x00f2b9}, /* U+9B83 */ - {0x00e9ae84, 0x00fec5}, /* U+9B84 [2000] */ - {0x00e9ae8a, 0x00fec6}, /* U+9B8A [2000] */ - {0x00e9ae8e, 0x00b0be}, /* U+9B8E */ - {0x00e9ae8f, 0x00fec7}, /* U+9B8F [2000] */ - {0x00e9ae91, 0x00f2ba}, /* U+9B91 */ - {0x00e9ae92, 0x00caab}, /* U+9B92 */ - {0x00e9ae93, 0x00f2b8}, /* U+9B93 */ - {0x00e9ae96, 0x00f2bb}, /* U+9B96 */ - {0x00e9ae97, 0x00f2bc}, /* U+9B97 */ - {0x00e9ae9e, 0x00fec8}, /* U+9B9E [2000] */ - {0x00e9ae9f, 0x00f2bd}, /* U+9B9F */ - {0x00e9aea0, 0x00f2be}, /* U+9BA0 */ - {0x00e9aea6, 0x8ffdc8}, /* U+9BA6 [2000] */ - {0x00e9aea7, 0x00fec9}, /* U+9BA7 [2000] */ - {0x00e9aea8, 0x00f2bf}, /* U+9BA8 */ - {0x00e9aeaa, 0x00cbee}, /* U+9BAA */ - {0x00e9aeab, 0x00bbad}, /* U+9BAB */ - {0x00e9aeac, 0x8ffdc9}, /* U+9BAC [2000] */ - {0x00e9aead, 0x00bafa}, /* U+9BAD */ - {0x00e9aeae, 0x00c1af}, /* U+9BAE */ - {0x00e9aeb1, 0x8ffdca}, /* U+9BB1 [2000] */ - {0x00e9aeb2, 0x8ffdcd}, /* U+9BB2 [2000] */ - {0x00e9aeb4, 0x00f2c0}, /* U+9BB4 */ - {0x00e9aeb8, 0x8ffdce}, /* U+9BB8 [2000] */ - {0x00e9aeb9, 0x00f2c3}, /* U+9BB9 */ - {0x00e9aebe, 0x8ffdcf}, /* U+9BBE [2000] */ - {0x00e9af80, 0x00f2c1}, /* U+9BC0 */ - {0x00e9af81, 0x00feca}, /* U+9BC1 [2000] */ - {0x00e9af86, 0x00f2c4}, /* U+9BC6 */ - {0x00e9af87, 0x8ffdd0}, /* U+9BC7 [2000] */ - {0x00e9af89, 0x00b8f1}, /* U+9BC9 */ - {0x00e9af8a, 0x00f2c2}, /* U+9BCA */ - {0x00e9af8e, 0x00fecb}, /* U+9BCE [2000] */ - {0x00e9af8f, 0x00f2c5}, /* U+9BCF */ - {0x00e9af91, 0x00f2c6}, /* U+9BD1 */ - {0x00e9af92, 0x00f2c7}, /* U+9BD2 */ - {0x00e9af94, 0x00f2cb}, /* U+9BD4 */ - {0x00e9af96, 0x00bbaa}, /* U+9BD6 */ - {0x00e9af98, 0x8ffdd2}, /* U+9BD8 [2000] */ - {0x00e9af9b, 0x00c2e4}, /* U+9BDB */ - {0x00e9af9d, 0x8ffdd3}, /* U+9BDD [2000] */ - {0x00e9afa1, 0x00f2cc}, /* U+9BE1 */ - {0x00e9afa2, 0x00f2c9}, /* U+9BE2 */ - {0x00e9afa3, 0x00f2c8}, /* U+9BE3 */ - {0x00e9afa4, 0x00f2ca}, /* U+9BE4 */ - {0x00e9afa5, 0x00fecc}, /* U+9BE5 [2000] */ - {0x00e9afa7, 0x8ffdd4}, /* U+9BE7 [2000] */ - {0x00e9afa8, 0x00b7df}, /* U+9BE8 */ - {0x00e9afaa, 0x8ffdd5}, /* U+9BEA [2000] */ - {0x00e9afab, 0x8ffdd6}, /* U+9BEB [2000] */ - {0x00e9afae, 0x8ffdd8}, /* U+9BEE [2000] */ - {0x00e9afaf, 0x8ffdd7}, /* U+9BEF [2000] */ - {0x00e9afb0, 0x00f2d0}, /* U+9BF0 */ - {0x00e9afb1, 0x00f2cf}, /* U+9BF1 */ - {0x00e9afb2, 0x00f2ce}, /* U+9BF2 */ - {0x00e9afb3, 0x8ffdd1}, /* U+9BF3 [2000] */ - {0x00e9afb5, 0x00b0b3}, /* U+9BF5 */ - {0x00e9afb7, 0x8ffddc}, /* U+9BF7 [2000] */ - {0x00e9afb8, 0x00fecd}, /* U+9BF8 [2000] */ - {0x00e9afba, 0x8ffdda}, /* U+9BFA [2000] */ - {0x00e9afbd, 0x00fece}, /* U+9BFD [2000] */ - {0x00e9b080, 0x00fecf}, /* U+9C00 [2000] */ - {0x00e9b084, 0x00f2da}, /* U+9C04 */ - {0x00e9b086, 0x00f2d6}, /* U+9C06 */ - {0x00e9b088, 0x00f2d7}, /* U+9C08 */ - {0x00e9b089, 0x00f2d3}, /* U+9C09 */ - {0x00e9b08a, 0x00f2d9}, /* U+9C0A */ - {0x00e9b08c, 0x00f2d5}, /* U+9C0C */ - {0x00e9b08d, 0x00b3e2}, /* U+9C0D */ - {0x00e9b090, 0x00cfcc}, /* U+9C10 */ - {0x00e9b092, 0x00f2d8}, /* U+9C12 */ - {0x00e9b093, 0x00f2d4}, /* U+9C13 */ - {0x00e9b094, 0x00f2d2}, /* U+9C14 */ - {0x00e9b095, 0x00f2d1}, /* U+9C15 */ - {0x00e9b096, 0x8ffdde}, /* U+9C16 [2000] */ - {0x00e9b098, 0x8ffddf}, /* U+9C18 [2000] */ - {0x00e9b099, 0x8ffde0}, /* U+9C19 [2000] */ - {0x00e9b09a, 0x8ffde1}, /* U+9C1A [2000] */ - {0x00e9b09b, 0x00f2dc}, /* U+9C1B */ - {0x00e9b09d, 0x8ffde2}, /* U+9C1D [2000] */ - {0x00e9b0a1, 0x00f2df}, /* U+9C21 */ - {0x00e9b0a2, 0x8ffde3}, /* U+9C22 [2000] */ - {0x00e9b0a3, 0x00fed0}, /* U+9C23 [2000] */ - {0x00e9b0a4, 0x00f2de}, /* U+9C24 */ - {0x00e9b0a5, 0x00f2dd}, /* U+9C25 */ - {0x00e9b0a7, 0x8ffde4}, /* U+9C27 [2000] */ - {0x00e9b0a9, 0x8ffde5}, /* U+9C29 [2000] */ - {0x00e9b0aa, 0x8ffde6}, /* U+9C2A [2000] */ - {0x00e9b0ad, 0x00c9c9}, /* U+9C2D */ - {0x00e9b0ae, 0x00f2db}, /* U+9C2E */ - {0x00e9b0af, 0x00b0f3}, /* U+9C2F */ - {0x00e9b0b0, 0x00f2e0}, /* U+9C30 */ - {0x00e9b0b1, 0x8ffde8}, /* U+9C31 [2000] */ - {0x00e9b0b2, 0x00f2e2}, /* U+9C32 */ - {0x00e9b0b6, 0x8ffde9}, /* U+9C36 [2000] */ - {0x00e9b0b7, 0x8ffdea}, /* U+9C37 [2000] */ - {0x00e9b0b9, 0x00b3ef}, /* U+9C39 */ - {0x00e9b0ba, 0x00f2cd}, /* U+9C3A */ - {0x00e9b0bb, 0x00b1b7}, /* U+9C3B */ - {0x00e9b0be, 0x00f2e4}, /* U+9C3E */ - {0x00e9b181, 0x00fed1}, /* U+9C41 [2000] */ - {0x00e9b185, 0x8ffdeb}, /* U+9C45 [2000] */ - {0x00e9b186, 0x00f2e3}, /* U+9C46 */ - {0x00e9b187, 0x00f2e1}, /* U+9C47 */ - {0x00e9b188, 0x00c3ad}, /* U+9C48 */ - {0x00e9b189, 0x8ffdee}, /* U+9C49 [2000] */ - {0x00e9b18a, 0x8ffdef}, /* U+9C4A [2000] */ - {0x00e9b18f, 0x00fed2}, /* U+9C4F [2000] */ - {0x00e9b190, 0x00fed3}, /* U+9C50 [2000] */ - {0x00e9b192, 0x00cbf0}, /* U+9C52 */ - {0x00e9b193, 0x00fed4}, /* U+9C53 [2000] */ - {0x00e9b194, 0x8ffdf1}, /* U+9C54 [2000] */ - {0x00e9b197, 0x00ceda}, /* U+9C57 */ - {0x00e9b198, 0x8ffdf2}, /* U+9C58 [2000] */ - {0x00e9b19a, 0x00f2e5}, /* U+9C5A */ - {0x00e9b19b, 0x8ffdf3}, /* U+9C5B [2000] */ - {0x00e9b19c, 0x8ffdec}, /* U+9C5C [2000] */ - {0x00e9b19d, 0x8ffdf4}, /* U+9C5D [2000] */ - {0x00e9b19f, 0x8ffdf5}, /* U+9C5F [2000] */ - {0x00e9b1a0, 0x00f2e6}, /* U+9C60 */ - {0x00e9b1a3, 0x00fed5}, /* U+9C63 [2000] */ - {0x00e9b1a5, 0x00fed6}, /* U+9C65 [2000] */ - {0x00e9b1a7, 0x00f2e7}, /* U+9C67 */ - {0x00e9b1a9, 0x8ffdf6}, /* U+9C69 [2000] */ - {0x00e9b1aa, 0x8ffdf7}, /* U+9C6A [2000] */ - {0x00e9b1ab, 0x8ffdf8}, /* U+9C6B [2000] */ - {0x00e9b1ad, 0x8ffdf9}, /* U+9C6D [2000] */ - {0x00e9b1ae, 0x8ffdfa}, /* U+9C6E [2000] */ - {0x00e9b1b0, 0x8ffdfb}, /* U+9C70 [2000] */ - {0x00e9b1b2, 0x8ffdfc}, /* U+9C72 [2000] */ - {0x00e9b1b5, 0x8ffdfd}, /* U+9C75 [2000] */ - {0x00e9b1b6, 0x00f2e8}, /* U+9C76 */ - {0x00e9b1b7, 0x00fed7}, /* U+9C77 [2000] */ - {0x00e9b1b8, 0x00f2e9}, /* U+9C78 */ - {0x00e9b1ba, 0x8ffdfe}, /* U+9C7A [2000] */ - {0x00e9b3a5, 0x00c4bb}, /* U+9CE5 */ - {0x00e9b3a6, 0x8ffea1}, /* U+9CE6 [2000] */ - {0x00e9b3a7, 0x00f2ea}, /* U+9CE7 */ - {0x00e9b3a9, 0x00c8b7}, /* U+9CE9 */ - {0x00e9b3ab, 0x00f2ef}, /* U+9CEB */ - {0x00e9b3ac, 0x00f2eb}, /* U+9CEC */ - {0x00e9b3b0, 0x00f2ec}, /* U+9CF0 */ - {0x00e9b3b2, 0x8ffea2}, /* U+9CF2 [2000] */ - {0x00e9b3b3, 0x00cbb1}, /* U+9CF3 */ - {0x00e9b3b4, 0x00ccc4}, /* U+9CF4 */ - {0x00e9b3b6, 0x00c6d0}, /* U+9CF6 */ - {0x00e9b482, 0x8ffea4}, /* U+9D02 [2000] */ - {0x00e9b483, 0x00f2f0}, /* U+9D03 */ - {0x00e9b486, 0x00f2f1}, /* U+9D06 */ - {0x00e9b487, 0x00c6be}, /* U+9D07 */ - {0x00e9b488, 0x00f2ee}, /* U+9D08 */ - {0x00e9b489, 0x00f2ed}, /* U+9D09 */ - {0x00e9b48b, 0x8ffea3}, /* U+9D0B [2000] */ - {0x00e9b48e, 0x00b2aa}, /* U+9D0E */ - {0x00e9b491, 0x8ffea6}, /* U+9D11 [2000] */ - {0x00e9b492, 0x00f2f9}, /* U+9D12 */ - {0x00e9b495, 0x00f2f8}, /* U+9D15 */ - {0x00e9b497, 0x8ffea7}, /* U+9D17 [2000] */ - {0x00e9b498, 0x8ffea8}, /* U+9D18 [2000] */ - {0x00e9b49b, 0x00b1f5}, /* U+9D1B */ - {0x00e9b49d, 0x00fed8}, /* U+9D1D [2000] */ - {0x00e9b49e, 0x00fed9}, /* U+9D1E [2000] */ - {0x00e9b49f, 0x00f2f6}, /* U+9D1F */ - {0x00e9b4a3, 0x00f2f5}, /* U+9D23 */ - {0x00e9b4a6, 0x00f2f3}, /* U+9D26 */ - {0x00e9b4a8, 0x00b3fb}, /* U+9D28 */ - {0x00e9b4aa, 0x00f2f2}, /* U+9D2A */ - {0x00e9b4ab, 0x00bcb2}, /* U+9D2B */ - {0x00e9b4ac, 0x00b2a9}, /* U+9D2C */ - {0x00e9b4b2, 0x8ffeac}, /* U+9D32 [2000] */ - {0x00e9b4bb, 0x00b9e3}, /* U+9D3B */ - {0x00e9b4be, 0x00f2fc}, /* U+9D3E */ - {0x00e9b4bf, 0x00f2fb}, /* U+9D3F */ - {0x00e9b581, 0x00f2fa}, /* U+9D41 */ - {0x00e9b582, 0x8ffeae}, /* U+9D42 [2000] */ - {0x00e9b583, 0x00feda}, /* U+9D43 [2000] */ - {0x00e9b584, 0x00f2f7}, /* U+9D44 */ - {0x00e9b586, 0x00f2fd}, /* U+9D46 */ - {0x00e9b587, 0x00fedb}, /* U+9D47 [2000] */ - {0x00e9b588, 0x00f2fe}, /* U+9D48 */ - {0x00e9b58a, 0x8ffeaf}, /* U+9D4A [2000] */ - {0x00e9b590, 0x00f3a5}, /* U+9D50 */ - {0x00e9b591, 0x00f3a4}, /* U+9D51 */ - {0x00e9b592, 0x00fedc}, /* U+9D52 [2000] */ - {0x00e9b599, 0x00f3a6}, /* U+9D59 */ - {0x00e9b59c, 0x00b1ad}, /* U+9D5C */ - {0x00e9b59d, 0x00f3a1}, /* U+9D5D */ - {0x00e9b59e, 0x00f3a2}, /* U+9D5E */ - {0x00e9b59f, 0x8ffeb0}, /* U+9D5F [2000] */ - {0x00e9b5a0, 0x00b9f4}, /* U+9D60 */ - {0x00e9b5a1, 0x00ccb9}, /* U+9D61 */ - {0x00e9b5a2, 0x8ffeb1}, /* U+9D62 [2000] */ - {0x00e9b5a3, 0x00fedd}, /* U+9D63 [2000] */ - {0x00e9b5a4, 0x00f3a3}, /* U+9D64 */ - {0x00e9b5a9, 0x8ffeb3}, /* U+9D69 [2000] */ - {0x00e9b5ab, 0x8ffeb4}, /* U+9D6B [2000] */ - {0x00e9b5ac, 0x00cbb2}, /* U+9D6C */ - {0x00e9b5af, 0x00f3ab}, /* U+9D6F */ - {0x00e9b5b0, 0x00fede}, /* U+9D70 [2000] */ - {0x00e9b5b2, 0x00f3a7}, /* U+9D72 */ - {0x00e9b5b3, 0x8ffeb6}, /* U+9D73 [2000] */ - {0x00e9b5b6, 0x8ffeb7}, /* U+9D76 [2000] */ - {0x00e9b5b7, 0x8ffeb8}, /* U+9D77 [2000] */ - {0x00e9b5ba, 0x00f3ac}, /* U+9D7A */ - {0x00e9b5bc, 0x00fedf}, /* U+9D7C [2000] */ - {0x00e9b5be, 0x8ffeb9}, /* U+9D7E [2000] */ - {0x00e9b684, 0x8ffeba}, /* U+9D84 [2000] */ - {0x00e9b687, 0x00f3a9}, /* U+9D87 */ - {0x00e9b689, 0x00f3a8}, /* U+9D89 */ - {0x00e9b68a, 0x00fee0}, /* U+9D8A [2000] */ - {0x00e9b68d, 0x8ffebb}, /* U+9D8D [2000] */ - {0x00e9b68f, 0x00b7dc}, /* U+9D8F */ - {0x00e9b696, 0x00fee1}, /* U+9D96 [2000] */ - {0x00e9b699, 0x8ffebc}, /* U+9D99 [2000] */ - {0x00e9b69a, 0x00f3ad}, /* U+9D9A */ - {0x00e9b6a1, 0x8ffebd}, /* U+9DA1 [2000] */ - {0x00e9b6a4, 0x00f3ae}, /* U+9DA4 */ - {0x00e9b6a9, 0x00f3af}, /* U+9DA9 */ - {0x00e9b6ab, 0x00f3aa}, /* U+9DAB */ - {0x00e9b6ac, 0x00fee3}, /* U+9DAC [2000] */ - {0x00e9b6af, 0x00f2f4}, /* U+9DAF */ - {0x00e9b6b2, 0x00f3b0}, /* U+9DB2 */ - {0x00e9b6b4, 0x00c4e1}, /* U+9DB4 */ - {0x00e9b6b5, 0x8ffebf}, /* U+9DB5 [2000] */ - {0x00e9b6b8, 0x00f3b4}, /* U+9DB8 */ - {0x00e9b6b9, 0x8ffec0}, /* U+9DB9 [2000] */ - {0x00e9b6ba, 0x00f3b5}, /* U+9DBA */ - {0x00e9b6bb, 0x00f3b3}, /* U+9DBB */ - {0x00e9b6bc, 0x00fee4}, /* U+9DBC [2000] */ - {0x00e9b6bd, 0x8ffec1}, /* U+9DBD [2000] */ - {0x00e9b6bf, 0x8ffebe}, /* U+9DBF [2000] */ - {0x00e9b780, 0x00fee2}, /* U+9DC0 [2000] */ - {0x00e9b781, 0x00f3b2}, /* U+9DC1 */ - {0x00e9b782, 0x00f3b8}, /* U+9DC2 */ - {0x00e9b783, 0x8ffec2}, /* U+9DC3 [2000] */ - {0x00e9b784, 0x00f3b1}, /* U+9DC4 */ - {0x00e9b786, 0x00f3b6}, /* U+9DC6 */ - {0x00e9b787, 0x8ffec3}, /* U+9DC7 [2000] */ - {0x00e9b789, 0x8ffec4}, /* U+9DC9 [2000] */ - {0x00e9b78f, 0x00f3b7}, /* U+9DCF */ - {0x00e9b793, 0x00f3ba}, /* U+9DD3 */ - {0x00e9b796, 0x8ffec5}, /* U+9DD6 [2000] */ - {0x00e9b797, 0x00fee5}, /* U+9DD7 [2000] */ - {0x00e9b799, 0x00f3b9}, /* U+9DD9 */ - {0x00e9b79a, 0x8ffec6}, /* U+9DDA [2000] */ - {0x00e9b79f, 0x8ffec7}, /* U+9DDF [2000] */ - {0x00e9b7a0, 0x8ffec8}, /* U+9DE0 [2000] */ - {0x00e9b7a3, 0x8ffec9}, /* U+9DE3 [2000] */ - {0x00e9b7a6, 0x00f3bc}, /* U+9DE6 */ - {0x00e9b7a7, 0x00fee7}, /* U+9DE7 [2000] */ - {0x00e9b7ad, 0x00f3bd}, /* U+9DED */ - {0x00e9b7af, 0x00f3be}, /* U+9DEF */ - {0x00e9b7b2, 0x00cfc9}, /* U+9DF2 */ - {0x00e9b7b4, 0x8ffeca}, /* U+9DF4 [2000] */ - {0x00e9b7b8, 0x00f3bb}, /* U+9DF8 */ - {0x00e9b7b9, 0x00c2eb}, /* U+9DF9 */ - {0x00e9b7ba, 0x00baed}, /* U+9DFA */ - {0x00e9b7bd, 0x00f3bf}, /* U+9DFD */ - {0x00e9b882, 0x8ffecd}, /* U+9E02 [2000] */ - {0x00e9b887, 0x00fee8}, /* U+9E07 [2000] */ - {0x00e9b88a, 0x8ffecc}, /* U+9E0A [2000] */ - {0x00e9b88d, 0x8ffece}, /* U+9E0D [2000] */ - {0x00e9b895, 0x00fee9}, /* U+9E15 [2000] */ - {0x00e9b899, 0x8ffecf}, /* U+9E19 [2000] */ - {0x00e9b89a, 0x00f3c0}, /* U+9E1A */ - {0x00e9b89b, 0x00f3c1}, /* U+9E1B */ - {0x00e9b89c, 0x8ffed0}, /* U+9E1C [2000] */ - {0x00e9b89d, 0x8ffed1}, /* U+9E1D [2000] */ - {0x00e9b89e, 0x00f3c2}, /* U+9E1E */ - {0x00e9b9b5, 0x00f3c3}, /* U+9E75 */ - {0x00e9b9b8, 0x00b8b4}, /* U+9E78 */ - {0x00e9b9b9, 0x00f3c4}, /* U+9E79 */ - {0x00e9b9bb, 0x8ffed2}, /* U+9E7B [2000] */ - {0x00e9b9bc, 0x00feea}, /* U+9E7C [2000] */ - {0x00e9b9bd, 0x00f3c5}, /* U+9E7D */ - {0x00e9b9bf, 0x00bcaf}, /* U+9E7F */ - {0x00e9ba80, 0x8ffed4}, /* U+9E80 [2000] */ - {0x00e9ba81, 0x00f3c6}, /* U+9E81 */ - {0x00e9ba85, 0x8ffed5}, /* U+9E85 [2000] */ - {0x00e9ba88, 0x00f3c7}, /* U+9E88 */ - {0x00e9ba8b, 0x00f3c8}, /* U+9E8B */ - {0x00e9ba8c, 0x00f3c9}, /* U+9E8C */ - {0x00e9ba91, 0x00f3cc}, /* U+9E91 */ - {0x00e9ba92, 0x00f3ca}, /* U+9E92 */ - {0x00e9ba93, 0x00cfbc}, /* U+9E93 */ - {0x00e9ba95, 0x00f3cb}, /* U+9E95 */ - {0x00e9ba97, 0x00ceef}, /* U+9E97 */ - {0x00e9ba9b, 0x8ffed6}, /* U+9E9B [2000] */ - {0x00e9ba9d, 0x00f3cd}, /* U+9E9D */ - {0x00e9ba9e, 0x00feeb}, /* U+9E9E [2000] */ - {0x00e9ba9f, 0x00cedb}, /* U+9E9F */ - {0x00e9baa4, 0x00feec}, /* U+9EA4 [2000] */ - {0x00e9baa5, 0x00f3ce}, /* U+9EA5 */ - {0x00e9baa6, 0x00c7fe}, /* U+9EA6 */ - {0x00e9baa8, 0x8ffed7}, /* U+9EA8 [2000] */ - {0x00e9baa9, 0x00f3cf}, /* U+9EA9 */ - {0x00e9baaa, 0x00f3d1}, /* U+9EAA */ - {0x00e9baac, 0x00feed}, /* U+9EAC [2000] */ - {0x00e9baad, 0x00f3d2}, /* U+9EAD */ - {0x00e9baaf, 0x00feee}, /* U+9EAF [2000] */ - {0x00e9bab4, 0x00feef}, /* U+9EB4 [2000] */ - {0x00e9bab5, 0x00fef0}, /* U+9EB5 [2000] */ - {0x00e9bab8, 0x00f3d0}, /* U+9EB8 */ - {0x00e9bab9, 0x00b9ed}, /* U+9EB9 */ - {0x00e9baba, 0x00cccd}, /* U+9EBA */ - {0x00e9babb, 0x00cbe3}, /* U+9EBB */ - {0x00e9babc, 0x00d6f7}, /* U+9EBC */ - {0x00e9babd, 0x8ffed9}, /* U+9EBD [2000] */ - {0x00e9babe, 0x00dde0}, /* U+9EBE */ - {0x00e9babf, 0x00cbfb}, /* U+9EBF */ - {0x00e9bb83, 0x00fef1}, /* U+9EC3 [2000] */ - {0x00e9bb84, 0x00b2ab}, /* U+9EC4 */ - {0x00e9bb8c, 0x00f3d4}, /* U+9ECC */ - {0x00e9bb8d, 0x00b5d0}, /* U+9ECD */ - {0x00e9bb8e, 0x00f3d5}, /* U+9ECE */ - {0x00e9bb8f, 0x00f3d6}, /* U+9ECF */ - {0x00e9bb90, 0x00f3d7}, /* U+9ED0 */ - {0x00e9bb91, 0x00fef2}, /* U+9ED1 [2000] */ - {0x00e9bb92, 0x00b9f5}, /* U+9ED2 */ - {0x00e9bb94, 0x00f3d8}, /* U+9ED4 */ - {0x00e9bb98, 0x00e0d4}, /* U+9ED8 */ - {0x00e9bb99, 0x00ccdb}, /* U+9ED9 */ - {0x00e9bb9b, 0x00c2e3}, /* U+9EDB */ - {0x00e9bb9c, 0x00f3d9}, /* U+9EDC */ - {0x00e9bb9d, 0x00f3db}, /* U+9EDD */ - {0x00e9bb9e, 0x00f3da}, /* U+9EDE */ - {0x00e9bb9f, 0x8ffedb}, /* U+9EDF [2000] */ - {0x00e9bba0, 0x00f3dc}, /* U+9EE0 */ - {0x00e9bba5, 0x00f3dd}, /* U+9EE5 */ - {0x00e9bba7, 0x8ffedc}, /* U+9EE7 [2000] */ - {0x00e9bba8, 0x00f3de}, /* U+9EE8 */ - {0x00e9bbae, 0x8ffedd}, /* U+9EEE [2000] */ - {0x00e9bbaf, 0x00f3df}, /* U+9EEF */ - {0x00e9bbb4, 0x00f3e0}, /* U+9EF4 */ - {0x00e9bbb6, 0x00f3e1}, /* U+9EF6 */ - {0x00e9bbb7, 0x00f3e2}, /* U+9EF7 */ - {0x00e9bbb9, 0x00f3e3}, /* U+9EF9 */ - {0x00e9bbbb, 0x00f3e4}, /* U+9EFB */ - {0x00e9bbbc, 0x00f3e5}, /* U+9EFC */ - {0x00e9bbbd, 0x00f3e6}, /* U+9EFD */ - {0x00e9bbbf, 0x8ffede}, /* U+9EFF [2000] */ - {0x00e9bc82, 0x8ffedf}, /* U+9F02 [2000] */ - {0x00e9bc83, 0x8ffee1}, /* U+9F03 [2000] */ - {0x00e9bc87, 0x00f3e7}, /* U+9F07 */ - {0x00e9bc88, 0x00f3e8}, /* U+9F08 */ - {0x00e9bc8e, 0x00c5a4}, /* U+9F0E */ - {0x00e9bc90, 0x00fef3}, /* U+9F10 [2000] */ - {0x00e9bc93, 0x00b8dd}, /* U+9F13 */ - {0x00e9bc95, 0x00f3ea}, /* U+9F15 */ - {0x00e9bc97, 0x8ffee2}, /* U+9F17 [2000] */ - {0x00e9bc99, 0x8ffee3}, /* U+9F19 [2000] */ - {0x00e9bca0, 0x00c1cd}, /* U+9F20 */ - {0x00e9bca1, 0x00f3eb}, /* U+9F21 */ - {0x00e9bcac, 0x00f3ec}, /* U+9F2C */ - {0x00e9bcaf, 0x8ffee4}, /* U+9F2F [2000] */ - {0x00e9bcb7, 0x8ffee5}, /* U+9F37 [2000] */ - {0x00e9bcb9, 0x00fef4}, /* U+9F39 [2000] */ - {0x00e9bcba, 0x8ffee6}, /* U+9F3A [2000] */ - {0x00e9bcbb, 0x00c9a1}, /* U+9F3B */ - {0x00e9bcbd, 0x8ffee7}, /* U+9F3D [2000] */ - {0x00e9bcbe, 0x00f3ed}, /* U+9F3E */ - {0x00e9bd81, 0x8ffee8}, /* U+9F41 [2000] */ - {0x00e9bd85, 0x8ffee9}, /* U+9F45 [2000] */ - {0x00e9bd86, 0x8ffeea}, /* U+9F46 [2000] */ - {0x00e9bd8a, 0x00f3ee}, /* U+9F4A */ - {0x00e9bd8b, 0x00e3b7}, /* U+9F4B */ - {0x00e9bd8e, 0x00ecda}, /* U+9F4E */ - {0x00e9bd8f, 0x00f0ed}, /* U+9F4F */ - {0x00e9bd92, 0x00f3ef}, /* U+9F52 */ - {0x00e9bd93, 0x8ffeeb}, /* U+9F53 [2000] */ - {0x00e9bd94, 0x00f3f0}, /* U+9F54 */ - {0x00e9bd95, 0x8ffeec}, /* U+9F55 [2000] */ - {0x00e9bd97, 0x00fef5}, /* U+9F57 [2000] */ - {0x00e9bd98, 0x8ffeed}, /* U+9F58 [2000] */ - {0x00e9bd9d, 0x8ffeef}, /* U+9F5D [2000] */ - {0x00e9bd9f, 0x00f3f2}, /* U+9F5F */ - {0x00e9bda0, 0x00f3f3}, /* U+9F60 */ - {0x00e9bda1, 0x00f3f4}, /* U+9F61 */ - {0x00e9bda2, 0x00cef0}, /* U+9F62 */ - {0x00e9bda3, 0x00f3f1}, /* U+9F63 */ - {0x00e9bda6, 0x00f3f5}, /* U+9F66 */ - {0x00e9bda7, 0x00f3f6}, /* U+9F67 */ - {0x00e9bda9, 0x8ffef1}, /* U+9F69 [2000] */ - {0x00e9bdaa, 0x00f3f8}, /* U+9F6A */ - {0x00e9bdac, 0x00f3f7}, /* U+9F6C */ - {0x00e9bdad, 0x8ffef3}, /* U+9F6D [2000] */ - {0x00e9bdb0, 0x8ffef4}, /* U+9F70 [2000] */ - {0x00e9bdb2, 0x00f3fa}, /* U+9F72 */ - {0x00e9bdb5, 0x8ffef5}, /* U+9F75 [2000] */ - {0x00e9bdb6, 0x00f3fb}, /* U+9F76 */ - {0x00e9bdb7, 0x00f3f9}, /* U+9F77 */ - {0x00e9be8d, 0x00ceb6}, /* U+9F8D */ - {0x00e9be90, 0x00fef6}, /* U+9F90 [2000] */ - {0x00e9be94, 0x00fef7}, /* U+9F94 [2000] */ - {0x00e9be95, 0x00f3fc}, /* U+9F95 */ - {0x00e9be97, 0x00fef8}, /* U+9F97 [2000] */ - {0x00e9be9c, 0x00f3fd}, /* U+9F9C */ - {0x00e9be9d, 0x00e3d4}, /* U+9F9D */ - {0x00e9bea0, 0x00f3fe}, /* U+9FA0 */ - {0x00e9bea2, 0x00fef9}, /* U+9FA2 [2000] */ - {0x00efa49d, 0x00f6bb}, /* U+F91D CJK COMPATIBILITY IDEOGRAPH-F91D [2000] */ - {0x00efa4a8, 0x00f4ae}, /* U+F928 CJK COMPATIBILITY IDEOGRAPH-F928 [2000] */ - {0x00efa4a9, 0x00f5ce}, /* U+F929 CJK COMPATIBILITY IDEOGRAPH-F929 [2000] */ - {0x00efa4b6, 0x00fbcf}, /* U+F936 CJK COMPATIBILITY IDEOGRAPH-F936 [2000] */ - {0x00efa5b0, 0x00f6c9}, /* U+F970 CJK COMPATIBILITY IDEOGRAPH-F970 [2000] */ - {0x00efa790, 0x00fea4}, /* U+F9D0 CJK COMPATIBILITY IDEOGRAPH-F9D0 [2000] */ - {0x00efa79c, 0x00fddd}, /* U+F9DC CJK COMPATIBILITY IDEOGRAPH-F9DC [2000] */ - {0x00efa88f, 0x00afcb}, /* U+FA0F CJK COMPATIBILITY IDEOGRAPH-FA0F [2000] */ - {0x00efa890, 0x00afd7}, /* U+FA10 CJK COMPATIBILITY IDEOGRAPH-FA10 [2000] */ - {0x00efa891, 0x00cff2}, /* U+FA11 CJK COMPATIBILITY IDEOGRAPH-FA11 [2000] */ - {0x00efa893, 0x8faef9}, /* U+FA13 CJK COMPATIBILITY IDEOGRAPH-FA13 [2000] */ - {0x00efa894, 0x00f5fa}, /* U+FA14 CJK COMPATIBILITY IDEOGRAPH-FA14 [2000] */ - {0x00efa895, 0x00f7da}, /* U+FA15 CJK COMPATIBILITY IDEOGRAPH-FA15 [2000] */ - {0x00efa896, 0x00f7ef}, /* U+FA16 CJK COMPATIBILITY IDEOGRAPH-FA16 [2000] */ - {0x00efa899, 0x00f9bc}, /* U+FA19 CJK COMPATIBILITY IDEOGRAPH-FA19 [2000] */ - {0x00efa89a, 0x00f9bd}, /* U+FA1A CJK COMPATIBILITY IDEOGRAPH-FA1A [2000] */ - {0x00efa89b, 0x00f9c1}, /* U+FA1B CJK COMPATIBILITY IDEOGRAPH-FA1B [2000] */ - {0x00efa89f, 0x00fbba}, /* U+FA1F CJK COMPATIBILITY IDEOGRAPH-FA1F [2000] */ - {0x00efa8a0, 0x8ff7b8}, /* U+FA20 CJK COMPATIBILITY IDEOGRAPH-FA20 [2000] */ - {0x00efa8a1, 0x8ff7c5}, /* U+FA21 CJK COMPATIBILITY IDEOGRAPH-FA21 [2000] */ - {0x00efa8a2, 0x00fcae}, /* U+FA22 CJK COMPATIBILITY IDEOGRAPH-FA22 [2000] */ - {0x00efa8a4, 0x8ff9ee}, /* U+FA24 CJK COMPATIBILITY IDEOGRAPH-FA24 [2000] */ - {0x00efa8a6, 0x00fcea}, /* U+FA26 CJK COMPATIBILITY IDEOGRAPH-FA26 [2000] */ - {0x00efa8b0, 0x00aeb8}, /* U+FA30 CJK COMPATIBILITY IDEOGRAPH-FA30 [2000] [Unicode3.2] */ - {0x00efa8b1, 0x00aec9}, /* U+FA31 CJK COMPATIBILITY IDEOGRAPH-FA31 [2000] [Unicode3.2] */ - {0x00efa8b2, 0x00aed0}, /* U+FA32 CJK COMPATIBILITY IDEOGRAPH-FA32 [2000] [Unicode3.2] */ - {0x00efa8b3, 0x00aee3}, /* U+FA33 CJK COMPATIBILITY IDEOGRAPH-FA33 [2000] [Unicode3.2] */ - {0x00efa8b4, 0x00aee8}, /* U+FA34 CJK COMPATIBILITY IDEOGRAPH-FA34 [2000] [Unicode3.2] */ - {0x00efa8b5, 0x00aeee}, /* U+FA35 CJK COMPATIBILITY IDEOGRAPH-FA35 [2000] [Unicode3.2] */ - {0x00efa8b6, 0x00afac}, /* U+FA36 CJK COMPATIBILITY IDEOGRAPH-FA36 [2000] [Unicode3.2] */ - {0x00efa8b7, 0x00afaf}, /* U+FA37 CJK COMPATIBILITY IDEOGRAPH-FA37 [2000] [Unicode3.2] */ - {0x00efa8b8, 0x00afb6}, /* U+FA38 CJK COMPATIBILITY IDEOGRAPH-FA38 [2000] [Unicode3.2] */ - {0x00efa8b9, 0x00afda}, /* U+FA39 CJK COMPATIBILITY IDEOGRAPH-FA39 [2000] [Unicode3.2] */ - {0x00efa8ba, 0x00afde}, /* U+FA3A CJK COMPATIBILITY IDEOGRAPH-FA3A [2000] [Unicode3.2] */ - {0x00efa8bb, 0x00cfe1}, /* U+FA3B CJK COMPATIBILITY IDEOGRAPH-FA3B [2000] [Unicode3.2] */ - {0x00efa8bc, 0x00cfe2}, /* U+FA3C CJK COMPATIBILITY IDEOGRAPH-FA3C [2000] [Unicode3.2] */ - {0x00efa8bd, 0x00f4d0}, /* U+FA3D CJK COMPATIBILITY IDEOGRAPH-FA3D [2000] [Unicode3.2] */ - {0x00efa8be, 0x00f4dc}, /* U+FA3E CJK COMPATIBILITY IDEOGRAPH-FA3E [2000] [Unicode3.2] */ - {0x00efa8bf, 0x00f4de}, /* U+FA3F CJK COMPATIBILITY IDEOGRAPH-FA3F [2000] [Unicode3.2] */ - {0x00efa980, 0x00f4e1}, /* U+FA40 CJK COMPATIBILITY IDEOGRAPH-FA40 [2000] [Unicode3.2] */ - {0x00efa981, 0x00f5a8}, /* U+FA41 CJK COMPATIBILITY IDEOGRAPH-FA41 [2000] [Unicode3.2] */ - {0x00efa982, 0x00f5ab}, /* U+FA42 CJK COMPATIBILITY IDEOGRAPH-FA42 [2000] [Unicode3.2] */ - {0x00efa983, 0x00f5c3}, /* U+FA43 CJK COMPATIBILITY IDEOGRAPH-FA43 [2000] [Unicode3.2] */ - {0x00efa984, 0x00f5e5}, /* U+FA44 CJK COMPATIBILITY IDEOGRAPH-FA44 [2000] [Unicode3.2] */ - {0x00efa985, 0x00f6e9}, /* U+FA45 CJK COMPATIBILITY IDEOGRAPH-FA45 [2000] [Unicode3.2] */ - {0x00efa986, 0x00f6f7}, /* U+FA46 CJK COMPATIBILITY IDEOGRAPH-FA46 [2000] [Unicode3.2] */ - {0x00efa987, 0x00f7a5}, /* U+FA47 CJK COMPATIBILITY IDEOGRAPH-FA47 [2000] [Unicode3.2] */ - {0x00efa988, 0x00f7d5}, /* U+FA48 CJK COMPATIBILITY IDEOGRAPH-FA48 [2000] [Unicode3.2] */ - {0x00efa989, 0x8ff0a9}, /* U+FA49 CJK COMPATIBILITY IDEOGRAPH-FA49 [2000] [Unicode3.2] */ - {0x00efa98a, 0x00f8a5}, /* U+FA4A CJK COMPATIBILITY IDEOGRAPH-FA4A [2000] [Unicode3.2] */ - {0x00efa98b, 0x00f9a7}, /* U+FA4B CJK COMPATIBILITY IDEOGRAPH-FA4B [2000] [Unicode3.2] */ - {0x00efa98c, 0x00f9b3}, /* U+FA4C CJK COMPATIBILITY IDEOGRAPH-FA4C [2000] [Unicode3.2] */ - {0x00efa98d, 0x00f9b4}, /* U+FA4D CJK COMPATIBILITY IDEOGRAPH-FA4D [2000] [Unicode3.2] */ - {0x00efa98e, 0x00f9b7}, /* U+FA4E CJK COMPATIBILITY IDEOGRAPH-FA4E [2000] [Unicode3.2] */ - {0x00efa98f, 0x00f9b8}, /* U+FA4F CJK COMPATIBILITY IDEOGRAPH-FA4F [2000] [Unicode3.2] */ - {0x00efa990, 0x00f9b9}, /* U+FA50 CJK COMPATIBILITY IDEOGRAPH-FA50 [2000] [Unicode3.2] */ - {0x00efa991, 0x00f9bb}, /* U+FA51 CJK COMPATIBILITY IDEOGRAPH-FA51 [2000] [Unicode3.2] */ - {0x00efa992, 0x00f9bf}, /* U+FA52 CJK COMPATIBILITY IDEOGRAPH-FA52 [2000] [Unicode3.2] */ - {0x00efa993, 0x00f9c0}, /* U+FA53 CJK COMPATIBILITY IDEOGRAPH-FA53 [2000] [Unicode3.2] */ - {0x00efa994, 0x00f9cd}, /* U+FA54 CJK COMPATIBILITY IDEOGRAPH-FA54 [2000] [Unicode3.2] */ - {0x00efa995, 0x00f9d1}, /* U+FA55 CJK COMPATIBILITY IDEOGRAPH-FA55 [2000] [Unicode3.2] */ - {0x00efa996, 0x00f9e4}, /* U+FA56 CJK COMPATIBILITY IDEOGRAPH-FA56 [2000] [Unicode3.2] */ - {0x00efa997, 0x00faae}, /* U+FA57 CJK COMPATIBILITY IDEOGRAPH-FA57 [2000] [Unicode3.2] */ - {0x00efa998, 0x8ff4d0}, /* U+FA58 CJK COMPATIBILITY IDEOGRAPH-FA58 [2000] [Unicode3.2] */ - {0x00efa999, 0x00fab3}, /* U+FA59 CJK COMPATIBILITY IDEOGRAPH-FA59 [2000] [Unicode3.2] */ - {0x00efa99a, 0x00faba}, /* U+FA5A CJK COMPATIBILITY IDEOGRAPH-FA5A [2000] [Unicode3.2] */ - {0x00efa99b, 0x00fac4}, /* U+FA5B CJK COMPATIBILITY IDEOGRAPH-FA5B [2000] [Unicode3.2] */ - {0x00efa99c, 0x00fad8}, /* U+FA5C CJK COMPATIBILITY IDEOGRAPH-FA5C [2000] [Unicode3.2] */ - {0x00efa99d, 0x8ff5f4}, /* U+FA5D CJK COMPATIBILITY IDEOGRAPH-FA5D [2000] [Unicode3.2] */ - {0x00efa99e, 0x8ff5f5}, /* U+FA5E CJK COMPATIBILITY IDEOGRAPH-FA5E [2000] [Unicode3.2] */ - {0x00efa99f, 0x00fba7}, /* U+FA5F CJK COMPATIBILITY IDEOGRAPH-FA5F [2000] [Unicode3.2] */ - {0x00efa9a0, 0x00fbef}, /* U+FA60 CJK COMPATIBILITY IDEOGRAPH-FA60 [2000] [Unicode3.2] */ - {0x00efa9a1, 0x00fbf9}, /* U+FA61 CJK COMPATIBILITY IDEOGRAPH-FA61 [2000] [Unicode3.2] */ - {0x00efa9a2, 0x00fcaf}, /* U+FA62 CJK COMPATIBILITY IDEOGRAPH-FA62 [2000] [Unicode3.2] */ - {0x00efa9a3, 0x00fcb0}, /* U+FA63 CJK COMPATIBILITY IDEOGRAPH-FA63 [2000] [Unicode3.2] */ - {0x00efa9a4, 0x00fcb8}, /* U+FA64 CJK COMPATIBILITY IDEOGRAPH-FA64 [2000] [Unicode3.2] */ - {0x00efa9a5, 0x00fcbd}, /* U+FA65 CJK COMPATIBILITY IDEOGRAPH-FA65 [2000] [Unicode3.2] */ - {0x00efa9a6, 0x8ff9e9}, /* U+FA66 CJK COMPATIBILITY IDEOGRAPH-FA66 [2000] [Unicode3.2] */ - {0x00efa9a7, 0x00fcd9}, /* U+FA67 CJK COMPATIBILITY IDEOGRAPH-FA67 [2000] [Unicode3.2] */ - {0x00efa9a8, 0x00fde3}, /* U+FA68 CJK COMPATIBILITY IDEOGRAPH-FA68 [2000] [Unicode3.2] */ - {0x00efa9a9, 0x00fdf6}, /* U+FA69 CJK COMPATIBILITY IDEOGRAPH-FA69 [2000] [Unicode3.2] */ - {0x00efa9aa, 0x00fdfb}, /* U+FA6A CJK COMPATIBILITY IDEOGRAPH-FA6A [2000] [Unicode3.2] */ - {0x00efb985, 0x00a3be}, /* U+FE45 SESAME DOT [2000] [Unicode3.2] */ - {0x00efb986, 0x00a3bd}, /* U+FE46 WHITE SESAME DOT [2000] [Unicode3.2] */ - {0x00efbc81, 0x00a1aa}, /* U+FF01 FULLWIDTH EXCLAMATION MARK */ - {0x00efbc82, 0x00a2b0}, /* U+FF02 FULLWIDTH QUOTATION MARK [2000] */ - {0x00efbc83, 0x00a1f4}, /* U+FF03 FULLWIDTH NUMBER SIGN */ - {0x00efbc84, 0x00a1f0}, /* U+FF04 FULLWIDTH DOLLAR SIGN */ - {0x00efbc85, 0x00a1f3}, /* U+FF05 FULLWIDTH PERCENT SIGN */ - {0x00efbc86, 0x00a1f5}, /* U+FF06 FULLWIDTH AMPERSAND */ - {0x00efbc87, 0x00a2af}, /* U+FF07 FULLWIDTH APOSTROPHE [2000] */ - {0x00efbc88, 0x00a1ca}, /* U+FF08 FULLWIDTH LEFT PARENTHESIS */ - {0x00efbc89, 0x00a1cb}, /* U+FF09 FULLWIDTH RIGHT PARENTHESIS */ - {0x00efbc8a, 0x00a1f6}, /* U+FF0A FULLWIDTH ASTERISK */ - {0x00efbc8b, 0x00a1dc}, /* U+FF0B FULLWIDTH PLUS SIGN */ - {0x00efbc8c, 0x00a1a4}, /* U+FF0C FULLWIDTH COMMA */ - {0x00efbc8d, 0x00a2b1}, /* U+FF0D FULLWIDTH HYPHEN-MINUS [2000] */ - {0x00efbc8e, 0x00a1a5}, /* U+FF0E FULLWIDTH FULL STOP */ - {0x00efbc8f, 0x00a1bf}, /* U+FF0F FULLWIDTH SOLIDUS */ - {0x00efbc90, 0x00a3b0}, /* U+FF10 FULLWIDTH DIGIT ZERO */ - {0x00efbc91, 0x00a3b1}, /* U+FF11 FULLWIDTH DIGIT ONE */ - {0x00efbc92, 0x00a3b2}, /* U+FF12 FULLWIDTH DIGIT TWO */ - {0x00efbc93, 0x00a3b3}, /* U+FF13 FULLWIDTH DIGIT THREE */ - {0x00efbc94, 0x00a3b4}, /* U+FF14 FULLWIDTH DIGIT FOUR */ - {0x00efbc95, 0x00a3b5}, /* U+FF15 FULLWIDTH DIGIT FIVE */ - {0x00efbc96, 0x00a3b6}, /* U+FF16 FULLWIDTH DIGIT SIX */ - {0x00efbc97, 0x00a3b7}, /* U+FF17 FULLWIDTH DIGIT SEVEN */ - {0x00efbc98, 0x00a3b8}, /* U+FF18 FULLWIDTH DIGIT EIGHT */ - {0x00efbc99, 0x00a3b9}, /* U+FF19 FULLWIDTH DIGIT NINE */ - {0x00efbc9a, 0x00a1a7}, /* U+FF1A FULLWIDTH COLON */ - {0x00efbc9b, 0x00a1a8}, /* U+FF1B FULLWIDTH SEMICOLON */ - {0x00efbc9c, 0x00a1e3}, /* U+FF1C FULLWIDTH LESS-THAN SIGN */ - {0x00efbc9d, 0x00a1e1}, /* U+FF1D FULLWIDTH EQUALS SIGN */ - {0x00efbc9e, 0x00a1e4}, /* U+FF1E FULLWIDTH GREATER-THAN SIGN */ - {0x00efbc9f, 0x00a1a9}, /* U+FF1F FULLWIDTH QUESTION MARK */ - {0x00efbca0, 0x00a1f7}, /* U+FF20 FULLWIDTH COMMERCIAL AT */ - {0x00efbca1, 0x00a3c1}, /* U+FF21 FULLWIDTH LATIN CAPITAL LETTER A */ - {0x00efbca2, 0x00a3c2}, /* U+FF22 FULLWIDTH LATIN CAPITAL LETTER B */ - {0x00efbca3, 0x00a3c3}, /* U+FF23 FULLWIDTH LATIN CAPITAL LETTER C */ - {0x00efbca4, 0x00a3c4}, /* U+FF24 FULLWIDTH LATIN CAPITAL LETTER D */ - {0x00efbca5, 0x00a3c5}, /* U+FF25 FULLWIDTH LATIN CAPITAL LETTER E */ - {0x00efbca6, 0x00a3c6}, /* U+FF26 FULLWIDTH LATIN CAPITAL LETTER F */ - {0x00efbca7, 0x00a3c7}, /* U+FF27 FULLWIDTH LATIN CAPITAL LETTER G */ - {0x00efbca8, 0x00a3c8}, /* U+FF28 FULLWIDTH LATIN CAPITAL LETTER H */ - {0x00efbca9, 0x00a3c9}, /* U+FF29 FULLWIDTH LATIN CAPITAL LETTER I */ - {0x00efbcaa, 0x00a3ca}, /* U+FF2A FULLWIDTH LATIN CAPITAL LETTER J */ - {0x00efbcab, 0x00a3cb}, /* U+FF2B FULLWIDTH LATIN CAPITAL LETTER K */ - {0x00efbcac, 0x00a3cc}, /* U+FF2C FULLWIDTH LATIN CAPITAL LETTER L */ - {0x00efbcad, 0x00a3cd}, /* U+FF2D FULLWIDTH LATIN CAPITAL LETTER M */ - {0x00efbcae, 0x00a3ce}, /* U+FF2E FULLWIDTH LATIN CAPITAL LETTER N */ - {0x00efbcaf, 0x00a3cf}, /* U+FF2F FULLWIDTH LATIN CAPITAL LETTER O */ - {0x00efbcb0, 0x00a3d0}, /* U+FF30 FULLWIDTH LATIN CAPITAL LETTER P */ - {0x00efbcb1, 0x00a3d1}, /* U+FF31 FULLWIDTH LATIN CAPITAL LETTER Q */ - {0x00efbcb2, 0x00a3d2}, /* U+FF32 FULLWIDTH LATIN CAPITAL LETTER R */ - {0x00efbcb3, 0x00a3d3}, /* U+FF33 FULLWIDTH LATIN CAPITAL LETTER S */ - {0x00efbcb4, 0x00a3d4}, /* U+FF34 FULLWIDTH LATIN CAPITAL LETTER T */ - {0x00efbcb5, 0x00a3d5}, /* U+FF35 FULLWIDTH LATIN CAPITAL LETTER U */ - {0x00efbcb6, 0x00a3d6}, /* U+FF36 FULLWIDTH LATIN CAPITAL LETTER V */ - {0x00efbcb7, 0x00a3d7}, /* U+FF37 FULLWIDTH LATIN CAPITAL LETTER W */ - {0x00efbcb8, 0x00a3d8}, /* U+FF38 FULLWIDTH LATIN CAPITAL LETTER X */ - {0x00efbcb9, 0x00a3d9}, /* U+FF39 FULLWIDTH LATIN CAPITAL LETTER Y */ - {0x00efbcba, 0x00a3da}, /* U+FF3A FULLWIDTH LATIN CAPITAL LETTER Z */ - {0x00efbcbb, 0x00a1ce}, /* U+FF3B FULLWIDTH LEFT SQUARE BRACKET */ - {0x00efbcbc, 0x00a1c0}, /* U+FF3C FULLWIDTH REVERSE SOLIDUS */ - {0x00efbcbd, 0x00a1cf}, /* U+FF3D FULLWIDTH RIGHT SQUARE BRACKET */ - {0x00efbcbe, 0x00a1b0}, /* U+FF3E FULLWIDTH CIRCUMFLEX ACCENT */ - {0x00efbcbf, 0x00a1b2}, /* U+FF3F FULLWIDTH LOW LINE */ - {0x00efbd80, 0x00a1ae}, /* U+FF40 FULLWIDTH GRAVE ACCENT */ - {0x00efbd81, 0x00a3e1}, /* U+FF41 FULLWIDTH LATIN SMALL LETTER A */ - {0x00efbd82, 0x00a3e2}, /* U+FF42 FULLWIDTH LATIN SMALL LETTER B */ - {0x00efbd83, 0x00a3e3}, /* U+FF43 FULLWIDTH LATIN SMALL LETTER C */ - {0x00efbd84, 0x00a3e4}, /* U+FF44 FULLWIDTH LATIN SMALL LETTER D */ - {0x00efbd85, 0x00a3e5}, /* U+FF45 FULLWIDTH LATIN SMALL LETTER E */ - {0x00efbd86, 0x00a3e6}, /* U+FF46 FULLWIDTH LATIN SMALL LETTER F */ - {0x00efbd87, 0x00a3e7}, /* U+FF47 FULLWIDTH LATIN SMALL LETTER G */ - {0x00efbd88, 0x00a3e8}, /* U+FF48 FULLWIDTH LATIN SMALL LETTER H */ - {0x00efbd89, 0x00a3e9}, /* U+FF49 FULLWIDTH LATIN SMALL LETTER I */ - {0x00efbd8a, 0x00a3ea}, /* U+FF4A FULLWIDTH LATIN SMALL LETTER J */ - {0x00efbd8b, 0x00a3eb}, /* U+FF4B FULLWIDTH LATIN SMALL LETTER K */ - {0x00efbd8c, 0x00a3ec}, /* U+FF4C FULLWIDTH LATIN SMALL LETTER L */ - {0x00efbd8d, 0x00a3ed}, /* U+FF4D FULLWIDTH LATIN SMALL LETTER M */ - {0x00efbd8e, 0x00a3ee}, /* U+FF4E FULLWIDTH LATIN SMALL LETTER N */ - {0x00efbd8f, 0x00a3ef}, /* U+FF4F FULLWIDTH LATIN SMALL LETTER O */ - {0x00efbd90, 0x00a3f0}, /* U+FF50 FULLWIDTH LATIN SMALL LETTER P */ - {0x00efbd91, 0x00a3f1}, /* U+FF51 FULLWIDTH LATIN SMALL LETTER Q */ - {0x00efbd92, 0x00a3f2}, /* U+FF52 FULLWIDTH LATIN SMALL LETTER R */ - {0x00efbd93, 0x00a3f3}, /* U+FF53 FULLWIDTH LATIN SMALL LETTER S */ - {0x00efbd94, 0x00a3f4}, /* U+FF54 FULLWIDTH LATIN SMALL LETTER T */ - {0x00efbd95, 0x00a3f5}, /* U+FF55 FULLWIDTH LATIN SMALL LETTER U */ - {0x00efbd96, 0x00a3f6}, /* U+FF56 FULLWIDTH LATIN SMALL LETTER V */ - {0x00efbd97, 0x00a3f7}, /* U+FF57 FULLWIDTH LATIN SMALL LETTER W */ - {0x00efbd98, 0x00a3f8}, /* U+FF58 FULLWIDTH LATIN SMALL LETTER X */ - {0x00efbd99, 0x00a3f9}, /* U+FF59 FULLWIDTH LATIN SMALL LETTER Y */ - {0x00efbd9a, 0x00a3fa}, /* U+FF5A FULLWIDTH LATIN SMALL LETTER Z */ - {0x00efbd9b, 0x00a1d0}, /* U+FF5B FULLWIDTH LEFT CURLY BRACKET */ - {0x00efbd9c, 0x00a1c3}, /* U+FF5C FULLWIDTH VERTICAL LINE */ - {0x00efbd9d, 0x00a1d1}, /* U+FF5D FULLWIDTH RIGHT CURLY BRACKET */ - {0x00efbd9e, 0x00a2b2}, /* U+FF5E FULLWIDTH TILDE [2000] */ - {0x00efbd9f, 0x00a2d6}, /* U+FF5F FULLWIDTH LEFT WHITE PARENTHESIS [2000] [Unicode3.2] */ - {0x00efbda0, 0x00a2d7}, /* U+FF60 FULLWIDTH RIGHT WHITE PARENTHESIS [2000] [Unicode3.2] */ - {0x00efbda1, 0x008ea1}, /* U+FF61 HALFWIDTH IDEOGRAPHIC FULL STOP */ - {0x00efbda2, 0x008ea2}, /* U+FF62 HALFWIDTH LEFT CORNER BRACKET */ - {0x00efbda3, 0x008ea3}, /* U+FF63 HALFWIDTH RIGHT CORNER BRACKET */ - {0x00efbda4, 0x008ea4}, /* U+FF64 HALFWIDTH IDEOGRAPHIC COMMA */ - {0x00efbda5, 0x008ea5}, /* U+FF65 HALFWIDTH KATAKANA MIDDLE DOT */ - {0x00efbda6, 0x008ea6}, /* U+FF66 HALFWIDTH KATAKANA LETTER WO */ - {0x00efbda7, 0x008ea7}, /* U+FF67 HALFWIDTH KATAKANA LETTER SMALL A */ - {0x00efbda8, 0x008ea8}, /* U+FF68 HALFWIDTH KATAKANA LETTER SMALL I */ - {0x00efbda9, 0x008ea9}, /* U+FF69 HALFWIDTH KATAKANA LETTER SMALL U */ - {0x00efbdaa, 0x008eaa}, /* U+FF6A HALFWIDTH KATAKANA LETTER SMALL E */ - {0x00efbdab, 0x008eab}, /* U+FF6B HALFWIDTH KATAKANA LETTER SMALL O */ - {0x00efbdac, 0x008eac}, /* U+FF6C HALFWIDTH KATAKANA LETTER SMALL YA */ - {0x00efbdad, 0x008ead}, /* U+FF6D HALFWIDTH KATAKANA LETTER SMALL YU */ - {0x00efbdae, 0x008eae}, /* U+FF6E HALFWIDTH KATAKANA LETTER SMALL YO */ - {0x00efbdaf, 0x008eaf}, /* U+FF6F HALFWIDTH KATAKANA LETTER SMALL TU */ - {0x00efbdb0, 0x008eb0}, /* U+FF70 HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK */ - {0x00efbdb1, 0x008eb1}, /* U+FF71 HALFWIDTH KATAKANA LETTER A */ - {0x00efbdb2, 0x008eb2}, /* U+FF72 HALFWIDTH KATAKANA LETTER I */ - {0x00efbdb3, 0x008eb3}, /* U+FF73 HALFWIDTH KATAKANA LETTER U */ - {0x00efbdb4, 0x008eb4}, /* U+FF74 HALFWIDTH KATAKANA LETTER E */ - {0x00efbdb5, 0x008eb5}, /* U+FF75 HALFWIDTH KATAKANA LETTER O */ - {0x00efbdb6, 0x008eb6}, /* U+FF76 HALFWIDTH KATAKANA LETTER KA */ - {0x00efbdb7, 0x008eb7}, /* U+FF77 HALFWIDTH KATAKANA LETTER KI */ - {0x00efbdb8, 0x008eb8}, /* U+FF78 HALFWIDTH KATAKANA LETTER KU */ - {0x00efbdb9, 0x008eb9}, /* U+FF79 HALFWIDTH KATAKANA LETTER KE */ - {0x00efbdba, 0x008eba}, /* U+FF7A HALFWIDTH KATAKANA LETTER KO */ - {0x00efbdbb, 0x008ebb}, /* U+FF7B HALFWIDTH KATAKANA LETTER SA */ - {0x00efbdbc, 0x008ebc}, /* U+FF7C HALFWIDTH KATAKANA LETTER SI */ - {0x00efbdbd, 0x008ebd}, /* U+FF7D HALFWIDTH KATAKANA LETTER SU */ - {0x00efbdbe, 0x008ebe}, /* U+FF7E HALFWIDTH KATAKANA LETTER SE */ - {0x00efbdbf, 0x008ebf}, /* U+FF7F HALFWIDTH KATAKANA LETTER SO */ - {0x00efbe80, 0x008ec0}, /* U+FF80 HALFWIDTH KATAKANA LETTER TA */ - {0x00efbe81, 0x008ec1}, /* U+FF81 HALFWIDTH KATAKANA LETTER TI */ - {0x00efbe82, 0x008ec2}, /* U+FF82 HALFWIDTH KATAKANA LETTER TU */ - {0x00efbe83, 0x008ec3}, /* U+FF83 HALFWIDTH KATAKANA LETTER TE */ - {0x00efbe84, 0x008ec4}, /* U+FF84 HALFWIDTH KATAKANA LETTER TO */ - {0x00efbe85, 0x008ec5}, /* U+FF85 HALFWIDTH KATAKANA LETTER NA */ - {0x00efbe86, 0x008ec6}, /* U+FF86 HALFWIDTH KATAKANA LETTER NI */ - {0x00efbe87, 0x008ec7}, /* U+FF87 HALFWIDTH KATAKANA LETTER NU */ - {0x00efbe88, 0x008ec8}, /* U+FF88 HALFWIDTH KATAKANA LETTER NE */ - {0x00efbe89, 0x008ec9}, /* U+FF89 HALFWIDTH KATAKANA LETTER NO */ - {0x00efbe8a, 0x008eca}, /* U+FF8A HALFWIDTH KATAKANA LETTER HA */ - {0x00efbe8b, 0x008ecb}, /* U+FF8B HALFWIDTH KATAKANA LETTER HI */ - {0x00efbe8c, 0x008ecc}, /* U+FF8C HALFWIDTH KATAKANA LETTER HU */ - {0x00efbe8d, 0x008ecd}, /* U+FF8D HALFWIDTH KATAKANA LETTER HE */ - {0x00efbe8e, 0x008ece}, /* U+FF8E HALFWIDTH KATAKANA LETTER HO */ - {0x00efbe8f, 0x008ecf}, /* U+FF8F HALFWIDTH KATAKANA LETTER MA */ - {0x00efbe90, 0x008ed0}, /* U+FF90 HALFWIDTH KATAKANA LETTER MI */ - {0x00efbe91, 0x008ed1}, /* U+FF91 HALFWIDTH KATAKANA LETTER MU */ - {0x00efbe92, 0x008ed2}, /* U+FF92 HALFWIDTH KATAKANA LETTER ME */ - {0x00efbe93, 0x008ed3}, /* U+FF93 HALFWIDTH KATAKANA LETTER MO */ - {0x00efbe94, 0x008ed4}, /* U+FF94 HALFWIDTH KATAKANA LETTER YA */ - {0x00efbe95, 0x008ed5}, /* U+FF95 HALFWIDTH KATAKANA LETTER YU */ - {0x00efbe96, 0x008ed6}, /* U+FF96 HALFWIDTH KATAKANA LETTER YO */ - {0x00efbe97, 0x008ed7}, /* U+FF97 HALFWIDTH KATAKANA LETTER RA */ - {0x00efbe98, 0x008ed8}, /* U+FF98 HALFWIDTH KATAKANA LETTER RI */ - {0x00efbe99, 0x008ed9}, /* U+FF99 HALFWIDTH KATAKANA LETTER RU */ - {0x00efbe9a, 0x008eda}, /* U+FF9A HALFWIDTH KATAKANA LETTER RE */ - {0x00efbe9b, 0x008edb}, /* U+FF9B HALFWIDTH KATAKANA LETTER RO */ - {0x00efbe9c, 0x008edc}, /* U+FF9C HALFWIDTH KATAKANA LETTER WA */ - {0x00efbe9d, 0x008edd}, /* U+FF9D HALFWIDTH KATAKANA LETTER N */ - {0x00efbe9e, 0x008ede}, /* U+FF9E HALFWIDTH KATAKANA VOICED SOUND MARK */ - {0x00efbe9f, 0x008edf}, /* U+FF9F HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK */ - {0xf0a0808b, 0x00aea2}, /* U+2000B [2000] [Unicode3.1] */ +/* src/backend/utils/mb/Unicode/utf8_to_euc_jis_2004.map */ + +static const pg_utf_to_local ULmapEUC_JIS_2004[ 11303 ] = { /* */ + {0xc280, 0x0080}, /* U+0080 */ + {0xc281, 0x0081}, /* U+0081 */ + {0xc282, 0x0082}, /* U+0082 */ + {0xc283, 0x0083}, /* U+0083 */ + {0xc284, 0x0084}, /* U+0084 */ + {0xc285, 0x0085}, /* U+0085 */ + {0xc286, 0x0086}, /* U+0086 */ + {0xc287, 0x0087}, /* U+0087 */ + {0xc288, 0x0088}, /* U+0088 */ + {0xc289, 0x0089}, /* U+0089 */ + {0xc28a, 0x008a}, /* U+008A */ + {0xc28b, 0x008b}, /* U+008B */ + {0xc28c, 0x008c}, /* U+008C */ + {0xc28d, 0x008d}, /* U+008D */ + {0xc28e, 0x008e}, /* U+008E */ + {0xc28f, 0x008f}, /* U+008F */ + {0xc290, 0x0090}, /* U+0090 */ + {0xc291, 0x0091}, /* U+0091 */ + {0xc292, 0x0092}, /* U+0092 */ + {0xc293, 0x0093}, /* U+0093 */ + {0xc294, 0x0094}, /* U+0094 */ + {0xc295, 0x0095}, /* U+0095 */ + {0xc296, 0x0096}, /* U+0096 */ + {0xc297, 0x0097}, /* U+0097 */ + {0xc298, 0x0098}, /* U+0098 */ + {0xc299, 0x0099}, /* U+0099 */ + {0xc29a, 0x009a}, /* U+009A */ + {0xc29b, 0x009b}, /* U+009B */ + {0xc29c, 0x009c}, /* U+009C */ + {0xc29d, 0x009d}, /* U+009D */ + {0xc29e, 0x009e}, /* U+009E */ + {0xc29f, 0x009f}, /* U+009F */ + {0xc2a0, 0xa9a2}, /* U+00A0 NO-BREAK SPACE [2000] */ + {0xc2a1, 0xa9a3}, /* U+00A1 INVERTED EXCLAMATION MARK [2000] */ + {0xc2a2, 0xa1f1}, /* U+00A2 CENT SIGN Windows: U+FFE0 */ + {0xc2a3, 0xa1f2}, /* U+00A3 POUND SIGN Windows: U+FFE1 */ + {0xc2a4, 0xa9a4}, /* U+00A4 CURRENCY SIGN [2000] */ + {0xc2a5, 0xa1ef}, /* U+00A5 YEN SIGN Windows: U+FFE5 */ + {0xc2a6, 0xa9a5}, /* U+00A6 BROKEN BAR [2000] */ + {0xc2a7, 0xa1f8}, /* U+00A7 SECTION SIGN */ + {0xc2a8, 0xa1af}, /* U+00A8 DIAERESIS */ + {0xc2a9, 0xa9a6}, /* U+00A9 COPYRIGHT SIGN [2000] */ + {0xc2aa, 0xa9a7}, /* U+00AA FEMININE ORDINAL INDICATOR [2000] */ + {0xc2ab, 0xa9a8}, /* U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK [2000] */ + {0xc2ac, 0xa2cc}, /* U+00AC NOT SIGN [1983] Windows: U+FFE2 */ + {0xc2ad, 0xa9a9}, /* U+00AD SOFT HYPHEN [2000] */ + {0xc2ae, 0xa9aa}, /* U+00AE REGISTERED SIGN [2000] */ + {0xc2af, 0xa9ab}, /* U+00AF MACRON [2000] */ + {0xc2b0, 0xa1eb}, /* U+00B0 DEGREE SIGN */ + {0xc2b1, 0xa1de}, /* U+00B1 PLUS-MINUS SIGN */ + {0xc2b2, 0xa9ac}, /* U+00B2 SUPERSCRIPT TWO [2000] */ + {0xc2b3, 0xa9ad}, /* U+00B3 SUPERSCRIPT THREE [2000] */ + {0xc2b4, 0xa1ad}, /* U+00B4 ACUTE ACCENT */ + {0xc2b6, 0xa2f9}, /* U+00B6 PILCROW SIGN [1983] */ + {0xc2b7, 0xa9ae}, /* U+00B7 MIDDLE DOT [2000] */ + {0xc2b8, 0xa9af}, /* U+00B8 CEDILLA [2000] */ + {0xc2b9, 0xa9b0}, /* U+00B9 SUPERSCRIPT ONE [2000] */ + {0xc2ba, 0xa9b1}, /* U+00BA MASCULINE ORDINAL INDICATOR [2000] */ + {0xc2bb, 0xa9b2}, /* U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK [2000] */ + {0xc2bc, 0xa9b3}, /* U+00BC VULGAR FRACTION ONE QUARTER [2000] */ + {0xc2bd, 0xa9b4}, /* U+00BD VULGAR FRACTION ONE HALF [2000] */ + {0xc2be, 0xa9b5}, /* U+00BE VULGAR FRACTION THREE QUARTERS [2000] */ + {0xc2bf, 0xa9b6}, /* U+00BF INVERTED QUESTION MARK [2000] */ + {0xc380, 0xa9b7}, /* U+00C0 LATIN CAPITAL LETTER A WITH GRAVE [2000] */ + {0xc381, 0xa9b8}, /* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE [2000] */ + {0xc382, 0xa9b9}, /* U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX [2000] */ + {0xc383, 0xa9ba}, /* U+00C3 LATIN CAPITAL LETTER A WITH TILDE [2000] */ + {0xc384, 0xa9bb}, /* U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS [2000] */ + {0xc385, 0xa9bc}, /* U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE [2000] */ + {0xc386, 0xa9bd}, /* U+00C6 LATIN CAPITAL LETTER AE [2000] */ + {0xc387, 0xa9be}, /* U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA [2000] */ + {0xc388, 0xa9bf}, /* U+00C8 LATIN CAPITAL LETTER E WITH GRAVE [2000] */ + {0xc389, 0xa9c0}, /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE [2000] */ + {0xc38a, 0xa9c1}, /* U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX [2000] */ + {0xc38b, 0xa9c2}, /* U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS [2000] */ + {0xc38c, 0xa9c3}, /* U+00CC LATIN CAPITAL LETTER I WITH GRAVE [2000] */ + {0xc38d, 0xa9c4}, /* U+00CD LATIN CAPITAL LETTER I WITH ACUTE [2000] */ + {0xc38e, 0xa9c5}, /* U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX [2000] */ + {0xc38f, 0xa9c6}, /* U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS [2000] */ + {0xc390, 0xa9c7}, /* U+00D0 LATIN CAPITAL LETTER ETH [2000] */ + {0xc391, 0xa9c8}, /* U+00D1 LATIN CAPITAL LETTER N WITH TILDE [2000] */ + {0xc392, 0xa9c9}, /* U+00D2 LATIN CAPITAL LETTER O WITH GRAVE [2000] */ + {0xc393, 0xa9ca}, /* U+00D3 LATIN CAPITAL LETTER O WITH ACUTE [2000] */ + {0xc394, 0xa9cb}, /* U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX [2000] */ + {0xc395, 0xa9cc}, /* U+00D5 LATIN CAPITAL LETTER O WITH TILDE [2000] */ + {0xc396, 0xa9cd}, /* U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS [2000] */ + {0xc397, 0xa1df}, /* U+00D7 MULTIPLICATION SIGN */ + {0xc398, 0xa9ce}, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE [2000] */ + {0xc399, 0xa9cf}, /* U+00D9 LATIN CAPITAL LETTER U WITH GRAVE [2000] */ + {0xc39a, 0xa9d0}, /* U+00DA LATIN CAPITAL LETTER U WITH ACUTE [2000] */ + {0xc39b, 0xa9d1}, /* U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX [2000] */ + {0xc39c, 0xa9d2}, /* U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS [2000] */ + {0xc39d, 0xa9d3}, /* U+00DD LATIN CAPITAL LETTER Y WITH ACUTE [2000] */ + {0xc39e, 0xa9d4}, /* U+00DE LATIN CAPITAL LETTER THORN [2000] */ + {0xc39f, 0xa9d5}, /* U+00DF LATIN SMALL LETTER SHARP S [2000] */ + {0xc3a0, 0xa9d6}, /* U+00E0 LATIN SMALL LETTER A WITH GRAVE [2000] */ + {0xc3a1, 0xa9d7}, /* U+00E1 LATIN SMALL LETTER A WITH ACUTE [2000] */ + {0xc3a2, 0xa9d8}, /* U+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX [2000] */ + {0xc3a3, 0xa9d9}, /* U+00E3 LATIN SMALL LETTER A WITH TILDE [2000] */ + {0xc3a4, 0xa9da}, /* U+00E4 LATIN SMALL LETTER A WITH DIAERESIS [2000] */ + {0xc3a5, 0xa9db}, /* U+00E5 LATIN SMALL LETTER A WITH RING ABOVE [2000] */ + {0xc3a6, 0xa9dc}, /* U+00E6 LATIN SMALL LETTER AE [2000] */ + {0xc3a7, 0xa9dd}, /* U+00E7 LATIN SMALL LETTER C WITH CEDILLA [2000] */ + {0xc3a8, 0xa9de}, /* U+00E8 LATIN SMALL LETTER E WITH GRAVE [2000] */ + {0xc3a9, 0xa9df}, /* U+00E9 LATIN SMALL LETTER E WITH ACUTE [2000] */ + {0xc3aa, 0xa9e0}, /* U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX [2000] */ + {0xc3ab, 0xa9e1}, /* U+00EB LATIN SMALL LETTER E WITH DIAERESIS [2000] */ + {0xc3ac, 0xa9e2}, /* U+00EC LATIN SMALL LETTER I WITH GRAVE [2000] */ + {0xc3ad, 0xa9e3}, /* U+00ED LATIN SMALL LETTER I WITH ACUTE [2000] */ + {0xc3ae, 0xa9e4}, /* U+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX [2000] */ + {0xc3af, 0xa9e5}, /* U+00EF LATIN SMALL LETTER I WITH DIAERESIS [2000] */ + {0xc3b0, 0xa9e6}, /* U+00F0 LATIN SMALL LETTER ETH [2000] */ + {0xc3b1, 0xa9e7}, /* U+00F1 LATIN SMALL LETTER N WITH TILDE [2000] */ + {0xc3b2, 0xa9e8}, /* U+00F2 LATIN SMALL LETTER O WITH GRAVE [2000] */ + {0xc3b3, 0xa9e9}, /* U+00F3 LATIN SMALL LETTER O WITH ACUTE [2000] */ + {0xc3b4, 0xa9ea}, /* U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX [2000] */ + {0xc3b5, 0xa9eb}, /* U+00F5 LATIN SMALL LETTER O WITH TILDE [2000] */ + {0xc3b6, 0xa9ec}, /* U+00F6 LATIN SMALL LETTER O WITH DIAERESIS [2000] */ + {0xc3b7, 0xa1e0}, /* U+00F7 DIVISION SIGN */ + {0xc3b8, 0xa9ed}, /* U+00F8 LATIN SMALL LETTER O WITH STROKE [2000] */ + {0xc3b9, 0xa9ee}, /* U+00F9 LATIN SMALL LETTER U WITH GRAVE [2000] */ + {0xc3ba, 0xa9ef}, /* U+00FA LATIN SMALL LETTER U WITH ACUTE [2000] */ + {0xc3bb, 0xa9f0}, /* U+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX [2000] */ + {0xc3bc, 0xa9f1}, /* U+00FC LATIN SMALL LETTER U WITH DIAERESIS [2000] */ + {0xc3bd, 0xa9f2}, /* U+00FD LATIN SMALL LETTER Y WITH ACUTE [2000] */ + {0xc3be, 0xa9f3}, /* U+00FE LATIN SMALL LETTER THORN [2000] */ + {0xc3bf, 0xa9f4}, /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS [2000] */ + {0xc480, 0xa9f5}, /* U+0100 LATIN CAPITAL LETTER A WITH MACRON [2000] */ + {0xc481, 0xa9fa}, /* U+0101 LATIN SMALL LETTER A WITH MACRON [2000] */ + {0xc482, 0xaaba}, /* U+0102 LATIN CAPITAL LETTER A WITH BREVE [2000] */ + {0xc483, 0xaac9}, /* U+0103 LATIN SMALL LETTER A WITH BREVE [2000] */ + {0xc484, 0xaaa1}, /* U+0104 LATIN CAPITAL LETTER A WITH OGONEK [2000] */ + {0xc485, 0xaaac}, /* U+0105 LATIN SMALL LETTER A WITH OGONEK [2000] */ + {0xc486, 0xaabc}, /* U+0106 LATIN CAPITAL LETTER C WITH ACUTE [2000] */ + {0xc487, 0xaacb}, /* U+0107 LATIN SMALL LETTER C WITH ACUTE [2000] */ + {0xc488, 0xaad9}, /* U+0108 LATIN CAPITAL LETTER C WITH CIRCUMFLEX [2000] */ + {0xc489, 0xaadf}, /* U+0109 LATIN SMALL LETTER C WITH CIRCUMFLEX [2000] */ + {0xc48c, 0xaabd}, /* U+010C LATIN CAPITAL LETTER C WITH CARON [2000] */ + {0xc48d, 0xaacc}, /* U+010D LATIN SMALL LETTER C WITH CARON [2000] */ + {0xc48e, 0xaac0}, /* U+010E LATIN CAPITAL LETTER D WITH CARON [2000] */ + {0xc48f, 0xaacf}, /* U+010F LATIN SMALL LETTER D WITH CARON [2000] */ + {0xc491, 0xaad0}, /* U+0111 LATIN SMALL LETTER D WITH STROKE [2000] */ + {0xc492, 0xa9f8}, /* U+0112 LATIN CAPITAL LETTER E WITH MACRON [2000] */ + {0xc493, 0xa9fd}, /* U+0113 LATIN SMALL LETTER E WITH MACRON [2000] */ + {0xc498, 0xaabe}, /* U+0118 LATIN CAPITAL LETTER E WITH OGONEK [2000] */ + {0xc499, 0xaacd}, /* U+0119 LATIN SMALL LETTER E WITH OGONEK [2000] */ + {0xc49a, 0xaabf}, /* U+011A LATIN CAPITAL LETTER E WITH CARON [2000] */ + {0xc49b, 0xaace}, /* U+011B LATIN SMALL LETTER E WITH CARON [2000] */ + {0xc49c, 0xaada}, /* U+011C LATIN CAPITAL LETTER G WITH CIRCUMFLEX [2000] */ + {0xc49d, 0xaae0}, /* U+011D LATIN SMALL LETTER G WITH CIRCUMFLEX [2000] */ + {0xc4a4, 0xaadb}, /* U+0124 LATIN CAPITAL LETTER H WITH CIRCUMFLEX [2000] */ + {0xc4a5, 0xaae1}, /* U+0125 LATIN SMALL LETTER H WITH CIRCUMFLEX [2000] */ + {0xc4a7, 0xaafd}, /* U+0127 LATIN SMALL LETTER H WITH STROKE [2000] */ + {0xc4aa, 0xa9f6}, /* U+012A LATIN CAPITAL LETTER I WITH MACRON [2000] */ + {0xc4ab, 0xa9fb}, /* U+012B LATIN SMALL LETTER I WITH MACRON [2000] */ + {0xc4b4, 0xaadc}, /* U+0134 LATIN CAPITAL LETTER J WITH CIRCUMFLEX [2000] */ + {0xc4b5, 0xaae2}, /* U+0135 LATIN SMALL LETTER J WITH CIRCUMFLEX [2000] */ + {0xc4b9, 0xaabb}, /* U+0139 LATIN CAPITAL LETTER L WITH ACUTE [2000] */ + {0xc4ba, 0xaaca}, /* U+013A LATIN SMALL LETTER L WITH ACUTE [2000] */ + {0xc4bd, 0xaaa4}, /* U+013D LATIN CAPITAL LETTER L WITH CARON [2000] */ + {0xc4be, 0xaaaf}, /* U+013E LATIN SMALL LETTER L WITH CARON [2000] */ + {0xc581, 0xaaa3}, /* U+0141 LATIN CAPITAL LETTER L WITH STROKE [2000] */ + {0xc582, 0xaaae}, /* U+0142 LATIN SMALL LETTER L WITH STROKE [2000] */ + {0xc583, 0xaac1}, /* U+0143 LATIN CAPITAL LETTER N WITH ACUTE [2000] */ + {0xc584, 0xaad1}, /* U+0144 LATIN SMALL LETTER N WITH ACUTE [2000] */ + {0xc587, 0xaac2}, /* U+0147 LATIN CAPITAL LETTER N WITH CARON [2000] */ + {0xc588, 0xaad2}, /* U+0148 LATIN SMALL LETTER N WITH CARON [2000] */ + {0xc58b, 0xaafa}, /* U+014B LATIN SMALL LETTER ENG [2000] */ + {0xc58c, 0xa9f9}, /* U+014C LATIN CAPITAL LETTER O WITH MACRON [2000] */ + {0xc58d, 0xa9fe}, /* U+014D LATIN SMALL LETTER O WITH MACRON [2000] */ + {0xc590, 0xaac3}, /* U+0150 LATIN CAPITAL LETTER O WITH DOUBLE ACUTE [2000] */ + {0xc591, 0xaad3}, /* U+0151 LATIN SMALL LETTER O WITH DOUBLE ACUTE [2000] */ + {0xc592, 0xabab}, /* U+0152 LATIN CAPITAL LIGATURE OE [2000] */ + {0xc593, 0xabaa}, /* U+0153 LATIN SMALL LIGATURE OE [2000] */ + {0xc594, 0xaab9}, /* U+0154 LATIN CAPITAL LETTER R WITH ACUTE [2000] */ + {0xc595, 0xaac8}, /* U+0155 LATIN SMALL LETTER R WITH ACUTE [2000] */ + {0xc598, 0xaac4}, /* U+0158 LATIN CAPITAL LETTER R WITH CARON [2000] */ + {0xc599, 0xaad4}, /* U+0159 LATIN SMALL LETTER R WITH CARON [2000] */ + {0xc59a, 0xaaa5}, /* U+015A LATIN CAPITAL LETTER S WITH ACUTE [2000] */ + {0xc59b, 0xaab0}, /* U+015B LATIN SMALL LETTER S WITH ACUTE [2000] */ + {0xc59c, 0xaadd}, /* U+015C LATIN CAPITAL LETTER S WITH CIRCUMFLEX [2000] */ + {0xc59d, 0xaae3}, /* U+015D LATIN SMALL LETTER S WITH CIRCUMFLEX [2000] */ + {0xc59e, 0xaaa7}, /* U+015E LATIN CAPITAL LETTER S WITH CEDILLA [2000] */ + {0xc59f, 0xaab3}, /* U+015F LATIN SMALL LETTER S WITH CEDILLA [2000] */ + {0xc5a0, 0xaaa6}, /* U+0160 LATIN CAPITAL LETTER S WITH CARON [2000] */ + {0xc5a1, 0xaab2}, /* U+0161 LATIN SMALL LETTER S WITH CARON [2000] */ + {0xc5a2, 0xaac7}, /* U+0162 LATIN CAPITAL LETTER T WITH CEDILLA [2000] */ + {0xc5a3, 0xaad7}, /* U+0163 LATIN SMALL LETTER T WITH CEDILLA [2000] */ + {0xc5a4, 0xaaa8}, /* U+0164 LATIN CAPITAL LETTER T WITH CARON [2000] */ + {0xc5a5, 0xaab4}, /* U+0165 LATIN SMALL LETTER T WITH CARON [2000] */ + {0xc5aa, 0xa9f7}, /* U+016A LATIN CAPITAL LETTER U WITH MACRON [2000] */ + {0xc5ab, 0xa9fc}, /* U+016B LATIN SMALL LETTER U WITH MACRON [2000] */ + {0xc5ac, 0xaade}, /* U+016C LATIN CAPITAL LETTER U WITH BREVE [2000] */ + {0xc5ad, 0xaae4}, /* U+016D LATIN SMALL LETTER U WITH BREVE [2000] */ + {0xc5ae, 0xaac5}, /* U+016E LATIN CAPITAL LETTER U WITH RING ABOVE [2000] */ + {0xc5af, 0xaad5}, /* U+016F LATIN SMALL LETTER U WITH RING ABOVE [2000] */ + {0xc5b0, 0xaac6}, /* U+0170 LATIN CAPITAL LETTER U WITH DOUBLE ACUTE [2000] */ + {0xc5b1, 0xaad6}, /* U+0171 LATIN SMALL LETTER U WITH DOUBLE ACUTE [2000] */ + {0xc5b9, 0xaaa9}, /* U+0179 LATIN CAPITAL LETTER Z WITH ACUTE [2000] */ + {0xc5ba, 0xaab5}, /* U+017A LATIN SMALL LETTER Z WITH ACUTE [2000] */ + {0xc5bb, 0xaaab}, /* U+017B LATIN CAPITAL LETTER Z WITH DOT ABOVE [2000] */ + {0xc5bc, 0xaab8}, /* U+017C LATIN SMALL LETTER Z WITH DOT ABOVE [2000] */ + {0xc5bd, 0xaaaa}, /* U+017D LATIN CAPITAL LETTER Z WITH CARON [2000] */ + {0xc5be, 0xaab7}, /* U+017E LATIN SMALL LETTER Z WITH CARON [2000] */ + {0xc693, 0xaba9}, /* U+0193 LATIN CAPITAL LETTER G WITH HOOK [2000] */ + {0xc782, 0xaba4}, /* U+01C2 LATIN LETTER ALVEOLAR CLICK [2000] */ + {0xc78d, 0xa8ef}, /* U+01CD LATIN CAPITAL LETTER A WITH CARON [2000] */ + {0xc78e, 0xa8f0}, /* U+01CE LATIN SMALL LETTER A WITH CARON [2000] */ + {0xc790, 0xa8f1}, /* U+01D0 LATIN SMALL LETTER I WITH CARON [2000] */ + {0xc791, 0xa8f6}, /* U+01D1 LATIN CAPITAL LETTER O WITH CARON [2000] */ + {0xc792, 0xa8f7}, /* U+01D2 LATIN SMALL LETTER O WITH CARON [2000] */ + {0xc794, 0xa8f8}, /* U+01D4 LATIN SMALL LETTER U WITH CARON [2000] */ + {0xc796, 0xa8f9}, /* U+01D6 LATIN SMALL LETTER U WITH DIAERESIS AND MACRON [2000] */ + {0xc798, 0xa8fa}, /* U+01D8 LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE [2000] */ + {0xc79a, 0xa8fb}, /* U+01DA LATIN SMALL LETTER U WITH DIAERESIS AND CARON [2000] */ + {0xc79c, 0xa8fc}, /* U+01DC LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE [2000] */ + {0xc7b8, 0xa8f4}, /* U+01F8 LATIN CAPITAL LETTER N WITH GRAVE [2000] */ + {0xc7b9, 0xa8f5}, /* U+01F9 LATIN SMALL LETTER N WITH GRAVE [2000] */ + {0xc7bd, 0xabc5}, /* U+01FD LATIN SMALL LETTER AE WITH ACUTE [2000] */ + {0xc990, 0xabb3}, /* U+0250 LATIN SMALL LETTER TURNED A [2000] */ + {0xc991, 0xabb9}, /* U+0251 LATIN SMALL LETTER ALPHA [2000] */ + {0xc992, 0xabba}, /* U+0252 LATIN SMALL LETTER TURNED ALPHA [2000] */ + {0xc993, 0xaba5}, /* U+0253 LATIN SMALL LETTER B WITH HOOK [2000] */ + {0xc994, 0xabb8}, /* U+0254 LATIN SMALL LETTER OPEN O [2000] */ + {0xc995, 0xabbf}, /* U+0255 LATIN SMALL LETTER C WITH CURL [2000] */ + {0xc996, 0xaaee}, /* U+0256 LATIN SMALL LETTER D WITH TAIL [2000] */ + {0xc997, 0xaba6}, /* U+0257 LATIN SMALL LETTER D WITH HOOK [2000] */ + {0xc998, 0xabae}, /* U+0258 LATIN SMALL LETTER REVERSED E [2000] */ + {0xc999, 0xabb0}, /* U+0259 LATIN SMALL LETTER SCHWA [2000] */ + {0xc99a, 0xabc3}, /* U+025A LATIN SMALL LETTER SCHWA WITH HOOK [2000] */ + {0xc99c, 0xabb1}, /* U+025C LATIN SMALL LETTER REVERSED OPEN E [2000] */ + {0xc99e, 0xabb2}, /* U+025E LATIN SMALL LETTER CLOSED REVERSED OPEN E [2000] */ + {0xc99f, 0xaaf5}, /* U+025F LATIN SMALL LETTER DOTLESS J WITH STROKE [2000] */ + {0xc9a0, 0xaba8}, /* U+0260 LATIN SMALL LETTER G WITH HOOK [2000] */ + {0xc9a1, 0xaaf9}, /* U+0261 LATIN SMALL LETTER SCRIPT G [2000] */ + {0xc9a4, 0xabb6}, /* U+0264 LATIN SMALL LETTER RAMS HORN [2000] */ + {0xc9a5, 0xabbc}, /* U+0265 LATIN SMALL LETTER TURNED H [2000] */ + {0xc9a6, 0xaba2}, /* U+0266 LATIN SMALL LETTER H WITH HOOK [2000] */ + {0xc9a7, 0xabc2}, /* U+0267 LATIN SMALL LETTER HENG WITH HOOK [2000] */ + {0xc9a8, 0xabac}, /* U+0268 LATIN SMALL LETTER I WITH STROKE [2000] */ + {0xc9ac, 0xaaea}, /* U+026C LATIN SMALL LETTER L WITH BELT [2000] */ + {0xc9ad, 0xaaf4}, /* U+026D LATIN SMALL LETTER L WITH RETROFLEX HOOK [2000] */ + {0xc9ae, 0xaaeb}, /* U+026E LATIN SMALL LETTER LEZH [2000] */ + {0xc9af, 0xabb4}, /* U+026F LATIN SMALL LETTER TURNED M [2000] */ + {0xc9b0, 0xaafb}, /* U+0270 LATIN SMALL LETTER TURNED M WITH LONG LEG [2000] */ + {0xc9b1, 0xaae5}, /* U+0271 LATIN SMALL LETTER M WITH HOOK [2000] */ + {0xc9b2, 0xaaf6}, /* U+0272 LATIN SMALL LETTER N WITH LEFT HOOK [2000] */ + {0xc9b3, 0xaaef}, /* U+0273 LATIN SMALL LETTER N WITH RETROFLEX HOOK [2000] */ + {0xc9b5, 0xabaf}, /* U+0275 LATIN SMALL LETTER BARRED O [2000] */ + {0xc9b9, 0xaaec}, /* U+0279 LATIN SMALL LETTER TURNED R [2000] */ + {0xc9ba, 0xabc1}, /* U+027A LATIN SMALL LETTER TURNED R WITH LONG LEG [2000] */ + {0xc9bb, 0xaaf3}, /* U+027B LATIN SMALL LETTER TURNED R WITH HOOK [2000] */ + {0xc9bd, 0xaaf0}, /* U+027D LATIN SMALL LETTER R WITH TAIL [2000] */ + {0xc9be, 0xaae7}, /* U+027E LATIN SMALL LETTER R WITH FISHHOOK [2000] */ + {0xca81, 0xaafc}, /* U+0281 LATIN LETTER SMALL CAPITAL INVERTED R [2000] */ + {0xca82, 0xaaf1}, /* U+0282 LATIN SMALL LETTER S WITH HOOK [2000] */ + {0xca83, 0xaae8}, /* U+0283 LATIN SMALL LETTER ESH [2000] */ + {0xca84, 0xaba7}, /* U+0284 LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK [2000] */ + {0xca88, 0xaaed}, /* U+0288 LATIN SMALL LETTER T WITH RETROFLEX HOOK [2000] */ + {0xca89, 0xabad}, /* U+0289 LATIN SMALL LETTER U BAR [2000] */ + {0xca8a, 0xabb5}, /* U+028A LATIN SMALL LETTER UPSILON [2000] */ + {0xca8b, 0xaae6}, /* U+028B LATIN SMALL LETTER V WITH HOOK [2000] */ + {0xca8c, 0xabb7}, /* U+028C LATIN SMALL LETTER TURNED V [2000] */ + {0xca8d, 0xabbb}, /* U+028D LATIN SMALL LETTER TURNED W [2000] */ + {0xca8e, 0xaaf8}, /* U+028E LATIN SMALL LETTER TURNED Y [2000] */ + {0xca90, 0xaaf2}, /* U+0290 LATIN SMALL LETTER Z WITH RETROFLEX HOOK [2000] */ + {0xca91, 0xabc0}, /* U+0291 LATIN SMALL LETTER Z WITH CURL [2000] */ + {0xca92, 0xaae9}, /* U+0292 LATIN SMALL LETTER EZH [2000] */ + {0xca94, 0xaba1}, /* U+0294 LATIN LETTER GLOTTAL STOP [2000] */ + {0xca95, 0xaafe}, /* U+0295 LATIN LETTER PHARYNGEAL VOICED FRICATIVE [2000] */ + {0xca98, 0xaba3}, /* U+0298 LATIN LETTER BILABIAL CLICK [2000] */ + {0xca9d, 0xaaf7}, /* U+029D LATIN SMALL LETTER J WITH CROSSED-TAIL [2000] */ + {0xcaa1, 0xabbe}, /* U+02A1 LATIN LETTER GLOTTAL STOP WITH STROKE [2000] */ + {0xcaa2, 0xabbd}, /* U+02A2 LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE [2000] */ + {0xcb87, 0xaab1}, /* U+02C7 CARON [2000] */ + {0xcb88, 0xabd3}, /* U+02C8 MODIFIER LETTER VERTICAL LINE [2000] */ + {0xcb8c, 0xabd4}, /* U+02CC MODIFIER LETTER LOW VERTICAL LINE [2000] */ + {0xcb90, 0xabd5}, /* U+02D0 MODIFIER LETTER TRIANGULAR COLON [2000] */ + {0xcb91, 0xabd6}, /* U+02D1 MODIFIER LETTER HALF TRIANGULAR COLON [2000] */ + {0xcb98, 0xaaa2}, /* U+02D8 BREVE [2000] */ + {0xcb99, 0xaad8}, /* U+02D9 DOT ABOVE [2000] */ + {0xcb9b, 0xaaad}, /* U+02DB OGONEK [2000] */ + {0xcb9d, 0xaab6}, /* U+02DD DOUBLE ACUTE ACCENT [2000] */ + {0xcb9e, 0xabf1}, /* U+02DE MODIFIER LETTER RHOTIC HOOK [2000] */ + {0xcba5, 0xabe0}, /* U+02E5 MODIFIER LETTER EXTRA-HIGH TONE BAR [2000] */ + {0xcba6, 0xabe1}, /* U+02E6 MODIFIER LETTER HIGH TONE BAR [2000] */ + {0xcba7, 0xabe2}, /* U+02E7 MODIFIER LETTER MID TONE BAR [2000] */ + {0xcba8, 0xabe3}, /* U+02E8 MODIFIER LETTER LOW TONE BAR [2000] */ + {0xcba9, 0xabe4}, /* U+02E9 MODIFIER LETTER EXTRA-LOW TONE BAR [2000] */ + {0xcc80, 0xabdc}, /* U+0300 COMBINING GRAVE ACCENT [2000] */ + {0xcc81, 0xabda}, /* U+0301 COMBINING ACUTE ACCENT [2000] */ + {0xcc82, 0xabdf}, /* U+0302 COMBINING CIRCUMFLEX ACCENT [2000] */ + {0xcc83, 0xabfd}, /* U+0303 COMBINING TILDE [2000] */ + {0xcc84, 0xabdb}, /* U+0304 COMBINING MACRON [2000] */ + {0xcc86, 0xabd7}, /* U+0306 COMBINING BREVE [2000] */ + {0xcc88, 0xabed}, /* U+0308 COMBINING DIAERESIS [2000] */ + {0xcc8b, 0xabd9}, /* U+030B COMBINING DOUBLE ACUTE ACCENT [2000] */ + {0xcc8c, 0xabde}, /* U+030C COMBINING CARON [2000] */ + {0xcc8f, 0xabdd}, /* U+030F COMBINING DOUBLE GRAVE ACCENT [2000] */ + {0xcc98, 0xabf8}, /* U+0318 COMBINING LEFT TACK BELOW [2000] */ + {0xcc99, 0xabf9}, /* U+0319 COMBINING RIGHT TACK BELOW [2000] */ + {0xcc9a, 0xabfe}, /* U+031A COMBINING LEFT ANGLE ABOVE [2000] */ + {0xcc9c, 0xabea}, /* U+031C COMBINING LEFT HALF RING BELOW [2000] */ + {0xcc9d, 0xabf6}, /* U+031D COMBINING UP TACK BELOW [2000] */ + {0xcc9e, 0xabf7}, /* U+031E COMBINING DOWN TACK BELOW [2000] */ + {0xcc9f, 0xabeb}, /* U+031F COMBINING PLUS SIGN BELOW [2000] */ + {0xcca0, 0xabec}, /* U+0320 COMBINING MINUS SIGN BELOW [2000] */ + {0xcca4, 0xabf2}, /* U+0324 COMBINING DIAERESIS BELOW [2000] */ + {0xcca5, 0xabe7}, /* U+0325 COMBINING RING BELOW [2000] */ + {0xcca9, 0xabef}, /* U+0329 COMBINING VERTICAL LINE BELOW [2000] */ + {0xccaa, 0xabfa}, /* U+032A COMBINING BRIDGE BELOW [2000] */ + {0xccac, 0xabe8}, /* U+032C COMBINING CARON BELOW [2000] */ + {0xccaf, 0xabf0}, /* U+032F COMBINING INVERTED BREVE BELOW [2000] */ + {0xccb0, 0xabf3}, /* U+0330 COMBINING TILDE BELOW [2000] */ + {0xccb4, 0xabf5}, /* U+0334 COMBINING TILDE OVERLAY [2000] */ + {0xccb9, 0xabe9}, /* U+0339 COMBINING RIGHT HALF RING BELOW [2000] */ + {0xccba, 0xabfb}, /* U+033A COMBINING INVERTED BRIDGE BELOW [2000] */ + {0xccbb, 0xabfc}, /* U+033B COMBINING SQUARE BELOW [2000] */ + {0xccbc, 0xabf4}, /* U+033C COMBINING SEAGULL BELOW [2000] */ + {0xccbd, 0xabee}, /* U+033D COMBINING X ABOVE [2000] */ + {0xcda1, 0xabd2}, /* U+0361 COMBINING DOUBLE INVERTED BREVE [2000] */ + {0xce91, 0xa6a1}, /* U+0391 GREEK CAPITAL LETTER ALPHA */ + {0xce92, 0xa6a2}, /* U+0392 GREEK CAPITAL LETTER BETA */ + {0xce93, 0xa6a3}, /* U+0393 GREEK CAPITAL LETTER GAMMA */ + {0xce94, 0xa6a4}, /* U+0394 GREEK CAPITAL LETTER DELTA */ + {0xce95, 0xa6a5}, /* U+0395 GREEK CAPITAL LETTER EPSILON */ + {0xce96, 0xa6a6}, /* U+0396 GREEK CAPITAL LETTER ZETA */ + {0xce97, 0xa6a7}, /* U+0397 GREEK CAPITAL LETTER ETA */ + {0xce98, 0xa6a8}, /* U+0398 GREEK CAPITAL LETTER THETA */ + {0xce99, 0xa6a9}, /* U+0399 GREEK CAPITAL LETTER IOTA */ + {0xce9a, 0xa6aa}, /* U+039A GREEK CAPITAL LETTER KAPPA */ + {0xce9b, 0xa6ab}, /* U+039B GREEK CAPITAL LETTER LAMDA */ + {0xce9c, 0xa6ac}, /* U+039C GREEK CAPITAL LETTER MU */ + {0xce9d, 0xa6ad}, /* U+039D GREEK CAPITAL LETTER NU */ + {0xce9e, 0xa6ae}, /* U+039E GREEK CAPITAL LETTER XI */ + {0xce9f, 0xa6af}, /* U+039F GREEK CAPITAL LETTER OMICRON */ + {0xcea0, 0xa6b0}, /* U+03A0 GREEK CAPITAL LETTER PI */ + {0xcea1, 0xa6b1}, /* U+03A1 GREEK CAPITAL LETTER RHO */ + {0xcea3, 0xa6b2}, /* U+03A3 GREEK CAPITAL LETTER SIGMA */ + {0xcea4, 0xa6b3}, /* U+03A4 GREEK CAPITAL LETTER TAU */ + {0xcea5, 0xa6b4}, /* U+03A5 GREEK CAPITAL LETTER UPSILON */ + {0xcea6, 0xa6b5}, /* U+03A6 GREEK CAPITAL LETTER PHI */ + {0xcea7, 0xa6b6}, /* U+03A7 GREEK CAPITAL LETTER CHI */ + {0xcea8, 0xa6b7}, /* U+03A8 GREEK CAPITAL LETTER PSI */ + {0xcea9, 0xa6b8}, /* U+03A9 GREEK CAPITAL LETTER OMEGA */ + {0xceb1, 0xa6c1}, /* U+03B1 GREEK SMALL LETTER ALPHA */ + {0xceb2, 0xa6c2}, /* U+03B2 GREEK SMALL LETTER BETA */ + {0xceb3, 0xa6c3}, /* U+03B3 GREEK SMALL LETTER GAMMA */ + {0xceb4, 0xa6c4}, /* U+03B4 GREEK SMALL LETTER DELTA */ + {0xceb5, 0xa6c5}, /* U+03B5 GREEK SMALL LETTER EPSILON */ + {0xceb6, 0xa6c6}, /* U+03B6 GREEK SMALL LETTER ZETA */ + {0xceb7, 0xa6c7}, /* U+03B7 GREEK SMALL LETTER ETA */ + {0xceb8, 0xa6c8}, /* U+03B8 GREEK SMALL LETTER THETA */ + {0xceb9, 0xa6c9}, /* U+03B9 GREEK SMALL LETTER IOTA */ + {0xceba, 0xa6ca}, /* U+03BA GREEK SMALL LETTER KAPPA */ + {0xcebb, 0xa6cb}, /* U+03BB GREEK SMALL LETTER LAMDA */ + {0xcebc, 0xa6cc}, /* U+03BC GREEK SMALL LETTER MU */ + {0xcebd, 0xa6cd}, /* U+03BD GREEK SMALL LETTER NU */ + {0xcebe, 0xa6ce}, /* U+03BE GREEK SMALL LETTER XI */ + {0xcebf, 0xa6cf}, /* U+03BF GREEK SMALL LETTER OMICRON */ + {0xcf80, 0xa6d0}, /* U+03C0 GREEK SMALL LETTER PI */ + {0xcf81, 0xa6d1}, /* U+03C1 GREEK SMALL LETTER RHO */ + {0xcf82, 0xa6d9}, /* U+03C2 GREEK SMALL LETTER FINAL SIGMA [2000] */ + {0xcf83, 0xa6d2}, /* U+03C3 GREEK SMALL LETTER SIGMA */ + {0xcf84, 0xa6d3}, /* U+03C4 GREEK SMALL LETTER TAU */ + {0xcf85, 0xa6d4}, /* U+03C5 GREEK SMALL LETTER UPSILON */ + {0xcf86, 0xa6d5}, /* U+03C6 GREEK SMALL LETTER PHI */ + {0xcf87, 0xa6d6}, /* U+03C7 GREEK SMALL LETTER CHI */ + {0xcf88, 0xa6d7}, /* U+03C8 GREEK SMALL LETTER PSI */ + {0xcf89, 0xa6d8}, /* U+03C9 GREEK SMALL LETTER OMEGA */ + {0xd081, 0xa7a7}, /* U+0401 CYRILLIC CAPITAL LETTER IO */ + {0xd090, 0xa7a1}, /* U+0410 CYRILLIC CAPITAL LETTER A */ + {0xd091, 0xa7a2}, /* U+0411 CYRILLIC CAPITAL LETTER BE */ + {0xd092, 0xa7a3}, /* U+0412 CYRILLIC CAPITAL LETTER VE */ + {0xd093, 0xa7a4}, /* U+0413 CYRILLIC CAPITAL LETTER GHE */ + {0xd094, 0xa7a5}, /* U+0414 CYRILLIC CAPITAL LETTER DE */ + {0xd095, 0xa7a6}, /* U+0415 CYRILLIC CAPITAL LETTER IE */ + {0xd096, 0xa7a8}, /* U+0416 CYRILLIC CAPITAL LETTER ZHE */ + {0xd097, 0xa7a9}, /* U+0417 CYRILLIC CAPITAL LETTER ZE */ + {0xd098, 0xa7aa}, /* U+0418 CYRILLIC CAPITAL LETTER I */ + {0xd099, 0xa7ab}, /* U+0419 CYRILLIC CAPITAL LETTER SHORT I */ + {0xd09a, 0xa7ac}, /* U+041A CYRILLIC CAPITAL LETTER KA */ + {0xd09b, 0xa7ad}, /* U+041B CYRILLIC CAPITAL LETTER EL */ + {0xd09c, 0xa7ae}, /* U+041C CYRILLIC CAPITAL LETTER EM */ + {0xd09d, 0xa7af}, /* U+041D CYRILLIC CAPITAL LETTER EN */ + {0xd09e, 0xa7b0}, /* U+041E CYRILLIC CAPITAL LETTER O */ + {0xd09f, 0xa7b1}, /* U+041F CYRILLIC CAPITAL LETTER PE */ + {0xd0a0, 0xa7b2}, /* U+0420 CYRILLIC CAPITAL LETTER ER */ + {0xd0a1, 0xa7b3}, /* U+0421 CYRILLIC CAPITAL LETTER ES */ + {0xd0a2, 0xa7b4}, /* U+0422 CYRILLIC CAPITAL LETTER TE */ + {0xd0a3, 0xa7b5}, /* U+0423 CYRILLIC CAPITAL LETTER U */ + {0xd0a4, 0xa7b6}, /* U+0424 CYRILLIC CAPITAL LETTER EF */ + {0xd0a5, 0xa7b7}, /* U+0425 CYRILLIC CAPITAL LETTER HA */ + {0xd0a6, 0xa7b8}, /* U+0426 CYRILLIC CAPITAL LETTER TSE */ + {0xd0a7, 0xa7b9}, /* U+0427 CYRILLIC CAPITAL LETTER CHE */ + {0xd0a8, 0xa7ba}, /* U+0428 CYRILLIC CAPITAL LETTER SHA */ + {0xd0a9, 0xa7bb}, /* U+0429 CYRILLIC CAPITAL LETTER SHCHA */ + {0xd0aa, 0xa7bc}, /* U+042A CYRILLIC CAPITAL LETTER HARD SIGN */ + {0xd0ab, 0xa7bd}, /* U+042B CYRILLIC CAPITAL LETTER YERU */ + {0xd0ac, 0xa7be}, /* U+042C CYRILLIC CAPITAL LETTER SOFT SIGN */ + {0xd0ad, 0xa7bf}, /* U+042D CYRILLIC CAPITAL LETTER E */ + {0xd0ae, 0xa7c0}, /* U+042E CYRILLIC CAPITAL LETTER YU */ + {0xd0af, 0xa7c1}, /* U+042F CYRILLIC CAPITAL LETTER YA */ + {0xd0b0, 0xa7d1}, /* U+0430 CYRILLIC SMALL LETTER A */ + {0xd0b1, 0xa7d2}, /* U+0431 CYRILLIC SMALL LETTER BE */ + {0xd0b2, 0xa7d3}, /* U+0432 CYRILLIC SMALL LETTER VE */ + {0xd0b3, 0xa7d4}, /* U+0433 CYRILLIC SMALL LETTER GHE */ + {0xd0b4, 0xa7d5}, /* U+0434 CYRILLIC SMALL LETTER DE */ + {0xd0b5, 0xa7d6}, /* U+0435 CYRILLIC SMALL LETTER IE */ + {0xd0b6, 0xa7d8}, /* U+0436 CYRILLIC SMALL LETTER ZHE */ + {0xd0b7, 0xa7d9}, /* U+0437 CYRILLIC SMALL LETTER ZE */ + {0xd0b8, 0xa7da}, /* U+0438 CYRILLIC SMALL LETTER I */ + {0xd0b9, 0xa7db}, /* U+0439 CYRILLIC SMALL LETTER SHORT I */ + {0xd0ba, 0xa7dc}, /* U+043A CYRILLIC SMALL LETTER KA */ + {0xd0bb, 0xa7dd}, /* U+043B CYRILLIC SMALL LETTER EL */ + {0xd0bc, 0xa7de}, /* U+043C CYRILLIC SMALL LETTER EM */ + {0xd0bd, 0xa7df}, /* U+043D CYRILLIC SMALL LETTER EN */ + {0xd0be, 0xa7e0}, /* U+043E CYRILLIC SMALL LETTER O */ + {0xd0bf, 0xa7e1}, /* U+043F CYRILLIC SMALL LETTER PE */ + {0xd180, 0xa7e2}, /* U+0440 CYRILLIC SMALL LETTER ER */ + {0xd181, 0xa7e3}, /* U+0441 CYRILLIC SMALL LETTER ES */ + {0xd182, 0xa7e4}, /* U+0442 CYRILLIC SMALL LETTER TE */ + {0xd183, 0xa7e5}, /* U+0443 CYRILLIC SMALL LETTER U */ + {0xd184, 0xa7e6}, /* U+0444 CYRILLIC SMALL LETTER EF */ + {0xd185, 0xa7e7}, /* U+0445 CYRILLIC SMALL LETTER HA */ + {0xd186, 0xa7e8}, /* U+0446 CYRILLIC SMALL LETTER TSE */ + {0xd187, 0xa7e9}, /* U+0447 CYRILLIC SMALL LETTER CHE */ + {0xd188, 0xa7ea}, /* U+0448 CYRILLIC SMALL LETTER SHA */ + {0xd189, 0xa7eb}, /* U+0449 CYRILLIC SMALL LETTER SHCHA */ + {0xd18a, 0xa7ec}, /* U+044A CYRILLIC SMALL LETTER HARD SIGN */ + {0xd18b, 0xa7ed}, /* U+044B CYRILLIC SMALL LETTER YERU */ + {0xd18c, 0xa7ee}, /* U+044C CYRILLIC SMALL LETTER SOFT SIGN */ + {0xd18d, 0xa7ef}, /* U+044D CYRILLIC SMALL LETTER E */ + {0xd18e, 0xa7f0}, /* U+044E CYRILLIC SMALL LETTER YU */ + {0xd18f, 0xa7f1}, /* U+044F CYRILLIC SMALL LETTER YA */ + {0xd191, 0xa7d7}, /* U+0451 CYRILLIC SMALL LETTER IO */ + {0xe1b8be, 0xa8f2}, /* U+1E3E LATIN CAPITAL LETTER M WITH ACUTE [2000] */ + {0xe1b8bf, 0xa8f3}, /* U+1E3F LATIN SMALL LETTER M WITH ACUTE [2000] */ + {0xe1bdb0, 0xabc6}, /* U+1F70 GREEK SMALL LETTER ALPHA WITH VARIA [2000] */ + {0xe1bdb1, 0xabc7}, /* U+1F71 GREEK SMALL LETTER ALPHA WITH OXIA [2000] */ + {0xe1bdb2, 0xabd0}, /* U+1F72 GREEK SMALL LETTER EPSILON WITH VARIA [2000] */ + {0xe1bdb3, 0xabd1}, /* U+1F73 GREEK SMALL LETTER EPSILON WITH OXIA [2000] */ + {0xe28090, 0xa1be}, /* U+2010 HYPHEN */ + {0xe28093, 0xa3fc}, /* U+2013 EN DASH [2000] */ + {0xe28094, 0xa1bd}, /* U+2014 EM DASH Windows: U+2015 */ + {0xe28096, 0xa1c2}, /* U+2016 DOUBLE VERTICAL LINE Windows: U+2225 */ + {0xe28098, 0xa1c6}, /* U+2018 LEFT SINGLE QUOTATION MARK */ + {0xe28099, 0xa1c7}, /* U+2019 RIGHT SINGLE QUOTATION MARK */ + {0xe2809c, 0xa1c8}, /* U+201C LEFT DOUBLE QUOTATION MARK */ + {0xe2809d, 0xa1c9}, /* U+201D RIGHT DOUBLE QUOTATION MARK */ + {0xe280a0, 0xa2f7}, /* U+2020 DAGGER [1983] */ + {0xe280a1, 0xa2f8}, /* U+2021 DOUBLE DAGGER [1983] */ + {0xe280a2, 0xa3c0}, /* U+2022 BULLET [2000] */ + {0xe280a5, 0xa1c5}, /* U+2025 TWO DOT LEADER */ + {0xe280a6, 0xa1c4}, /* U+2026 HORIZONTAL ELLIPSIS */ + {0xe280b0, 0xa2f3}, /* U+2030 PER MILLE SIGN [1983] */ + {0xe280b2, 0xa1ec}, /* U+2032 PRIME */ + {0xe280b3, 0xa1ed}, /* U+2033 DOUBLE PRIME */ + {0xe280bb, 0xa2a8}, /* U+203B REFERENCE MARK */ + {0xe280bc, 0xa8eb}, /* U+203C DOUBLE EXCLAMATION MARK [2000] */ + {0xe280be, 0xa1b1}, /* U+203E OVERLINE Windows: U+FFE3 */ + {0xe280bf, 0xabd8}, /* U+203F UNDERTIE [2000] */ + {0xe28182, 0xacfe}, /* U+2042 ASTERISM [2000] */ + {0xe28187, 0xa8ec}, /* U+2047 DOUBLE QUESTION MARK [2000] [Unicode3.2] */ + {0xe28188, 0xa8ed}, /* U+2048 QUESTION EXCLAMATION MARK [2000] */ + {0xe28189, 0xa8ee}, /* U+2049 EXCLAMATION QUESTION MARK [2000] */ + {0xe28191, 0xacfd}, /* U+2051 TWO ASTERISKS ALIGNED VERTICALLY [2000] [Unicode3.2] */ + {0xe282ac, 0xa9a1}, /* U+20AC EURO SIGN [2000] */ + {0xe28483, 0xa1ee}, /* U+2103 DEGREE CELSIUS */ + {0xe2848f, 0xa3dd}, /* U+210F PLANCK CONSTANT OVER TWO PI [2000] */ + {0xe28493, 0xa3df}, /* U+2113 SCRIPT SMALL L [2000] */ + {0xe28496, 0xade2}, /* U+2116 NUMERO SIGN [2000] */ + {0xe284a1, 0xade4}, /* U+2121 TELEPHONE SIGN [2000] */ + {0xe284a7, 0xa3e0}, /* U+2127 INVERTED OHM SIGN [2000] */ + {0xe284ab, 0xa2f2}, /* U+212B ANGSTROM SIGN [1983] */ + {0xe284b5, 0xa3dc}, /* U+2135 ALEF SYMBOL [2000] */ + {0xe28593, 0xa7f8}, /* U+2153 VULGAR FRACTION ONE THIRD [2000] */ + {0xe28594, 0xa7f9}, /* U+2154 VULGAR FRACTION TWO THIRDS [2000] */ + {0xe28595, 0xa7fa}, /* U+2155 VULGAR FRACTION ONE FIFTH [2000] */ + {0xe285a0, 0xadb5}, /* U+2160 ROMAN NUMERAL ONE [2000] */ + {0xe285a1, 0xadb6}, /* U+2161 ROMAN NUMERAL TWO [2000] */ + {0xe285a2, 0xadb7}, /* U+2162 ROMAN NUMERAL THREE [2000] */ + {0xe285a3, 0xadb8}, /* U+2163 ROMAN NUMERAL FOUR [2000] */ + {0xe285a4, 0xadb9}, /* U+2164 ROMAN NUMERAL FIVE [2000] */ + {0xe285a5, 0xadba}, /* U+2165 ROMAN NUMERAL SIX [2000] */ + {0xe285a6, 0xadbb}, /* U+2166 ROMAN NUMERAL SEVEN [2000] */ + {0xe285a7, 0xadbc}, /* U+2167 ROMAN NUMERAL EIGHT [2000] */ + {0xe285a8, 0xadbd}, /* U+2168 ROMAN NUMERAL NINE [2000] */ + {0xe285a9, 0xadbe}, /* U+2169 ROMAN NUMERAL TEN [2000] */ + {0xe285aa, 0xadbf}, /* U+216A ROMAN NUMERAL ELEVEN [2000] */ + {0xe285ab, 0xadd7}, /* U+216B ROMAN NUMERAL TWELVE [2000] */ + {0xe285b0, 0xacb5}, /* U+2170 SMALL ROMAN NUMERAL ONE [2000] */ + {0xe285b1, 0xacb6}, /* U+2171 SMALL ROMAN NUMERAL TWO [2000] */ + {0xe285b2, 0xacb7}, /* U+2172 SMALL ROMAN NUMERAL THREE [2000] */ + {0xe285b3, 0xacb8}, /* U+2173 SMALL ROMAN NUMERAL FOUR [2000] */ + {0xe285b4, 0xacb9}, /* U+2174 SMALL ROMAN NUMERAL FIVE [2000] */ + {0xe285b5, 0xacba}, /* U+2175 SMALL ROMAN NUMERAL SIX [2000] */ + {0xe285b6, 0xacbb}, /* U+2176 SMALL ROMAN NUMERAL SEVEN [2000] */ + {0xe285b7, 0xacbc}, /* U+2177 SMALL ROMAN NUMERAL EIGHT [2000] */ + {0xe285b8, 0xacbd}, /* U+2178 SMALL ROMAN NUMERAL NINE [2000] */ + {0xe285b9, 0xacbe}, /* U+2179 SMALL ROMAN NUMERAL TEN [2000] */ + {0xe285ba, 0xacbf}, /* U+217A SMALL ROMAN NUMERAL ELEVEN [2000] */ + {0xe285bb, 0xacc0}, /* U+217B SMALL ROMAN NUMERAL TWELVE [2000] */ + {0xe28690, 0xa2ab}, /* U+2190 LEFTWARDS ARROW */ + {0xe28691, 0xa2ac}, /* U+2191 UPWARDS ARROW */ + {0xe28692, 0xa2aa}, /* U+2192 RIGHTWARDS ARROW */ + {0xe28693, 0xa2ad}, /* U+2193 DOWNWARDS ARROW */ + {0xe28694, 0xa2f1}, /* U+2194 LEFT RIGHT ARROW [2000] */ + {0xe28696, 0xa3a7}, /* U+2196 NORTH WEST ARROW [2000] */ + {0xe28697, 0xa3a5}, /* U+2197 NORTH EAST ARROW [2000] */ + {0xe28698, 0xa3a6}, /* U+2198 SOUTH EAST ARROW [2000] */ + {0xe28699, 0xa3a8}, /* U+2199 SOUTH WEST ARROW [2000] */ + {0xe28784, 0xa3a9}, /* U+21C4 RIGHTWARDS ARROW OVER LEFTWARDS ARROW [2000] */ + {0xe28792, 0xa2cd}, /* U+21D2 RIGHTWARDS DOUBLE ARROW [1983] */ + {0xe28794, 0xa2ce}, /* U+21D4 LEFT RIGHT DOUBLE ARROW [1983] */ + {0xe287a6, 0xa3ab}, /* U+21E6 LEFTWARDS WHITE ARROW [2000] */ + {0xe287a7, 0xa3ac}, /* U+21E7 UPWARDS WHITE ARROW [2000] */ + {0xe287a8, 0xa3aa}, /* U+21E8 RIGHTWARDS WHITE ARROW [2000] */ + {0xe287a9, 0xa3ad}, /* U+21E9 DOWNWARDS WHITE ARROW [2000] */ + {0xe28880, 0xa2cf}, /* U+2200 FOR ALL [1983] */ + {0xe28882, 0xa2df}, /* U+2202 PARTIAL DIFFERENTIAL [1983] */ + {0xe28883, 0xa2d0}, /* U+2203 THERE EXISTS [1983] */ + {0xe28885, 0xa2c7}, /* U+2205 EMPTY SET [2000] */ + {0xe28887, 0xa2e0}, /* U+2207 NABLA [1983] */ + {0xe28888, 0xa2ba}, /* U+2208 ELEMENT OF [1983] */ + {0xe28889, 0xa2c6}, /* U+2209 NOT AN ELEMENT OF [2000] */ + {0xe2888b, 0xa2bb}, /* U+220B CONTAINS AS MEMBER [1983] */ + {0xe28892, 0xa1dd}, /* U+2212 MINUS SIGN Windows: U+FF0D */ + {0xe28893, 0xa3db}, /* U+2213 MINUS-OR-PLUS SIGN [2000] */ + {0xe2889a, 0xa2e5}, /* U+221A SQUARE ROOT [1983] */ + {0xe2889d, 0xa2e7}, /* U+221D PROPORTIONAL TO [1983] */ + {0xe2889e, 0xa1e7}, /* U+221E INFINITY */ + {0xe2889f, 0xadf8}, /* U+221F RIGHT ANGLE [2000] */ + {0xe288a0, 0xa2dc}, /* U+2220 ANGLE [1983] */ + {0xe288a5, 0xa2d4}, /* U+2225 PARALLEL TO [2000] */ + {0xe288a6, 0xa2d5}, /* U+2226 NOT PARALLEL TO [2000] */ + {0xe288a7, 0xa2ca}, /* U+2227 LOGICAL AND [1983] */ + {0xe288a8, 0xa2cb}, /* U+2228 LOGICAL OR [1983] */ + {0xe288a9, 0xa2c1}, /* U+2229 INTERSECTION [1983] */ + {0xe288aa, 0xa2c0}, /* U+222A UNION [1983] */ + {0xe288ab, 0xa2e9}, /* U+222B INTEGRAL [1983] */ + {0xe288ac, 0xa2ea}, /* U+222C DOUBLE INTEGRAL [1983] */ + {0xe288ae, 0xadf3}, /* U+222E CONTOUR INTEGRAL [2000] */ + {0xe288b4, 0xa1e8}, /* U+2234 THEREFORE */ + {0xe288b5, 0xa2e8}, /* U+2235 BECAUSE [1983] */ + {0xe288bd, 0xa2e6}, /* U+223D REVERSED TILDE [1983] */ + {0xe28983, 0xa2ec}, /* U+2243 ASYMPTOTICALLY EQUAL TO [2000] */ + {0xe28985, 0xa2ed}, /* U+2245 APPROXIMATELY EQUAL TO [2000] */ + {0xe28988, 0xa2ee}, /* U+2248 ALMOST EQUAL TO [2000] */ + {0xe28992, 0xa2e2}, /* U+2252 APPROXIMATELY EQUAL TO OR THE IMAGE OF [1983] */ + {0xe289a0, 0xa1e2}, /* U+2260 NOT EQUAL TO */ + {0xe289a1, 0xa2e1}, /* U+2261 IDENTICAL TO [1983] */ + {0xe289a2, 0xa2eb}, /* U+2262 NOT IDENTICAL TO [2000] */ + {0xe289a6, 0xa1e5}, /* U+2266 LESS-THAN OVER EQUAL TO */ + {0xe289a7, 0xa1e6}, /* U+2267 GREATER-THAN OVER EQUAL TO */ + {0xe289aa, 0xa2e3}, /* U+226A MUCH LESS-THAN [1983] */ + {0xe289ab, 0xa2e4}, /* U+226B MUCH GREATER-THAN [1983] */ + {0xe289b6, 0xa2ef}, /* U+2276 LESS-THAN OR GREATER-THAN [2000] */ + {0xe289b7, 0xa2f0}, /* U+2277 GREATER-THAN OR LESS-THAN [2000] */ + {0xe28a82, 0xa2be}, /* U+2282 SUBSET OF [1983] */ + {0xe28a83, 0xa2bf}, /* U+2283 SUPERSET OF [1983] */ + {0xe28a84, 0xa2c2}, /* U+2284 NOT A SUBSET OF [2000] */ + {0xe28a85, 0xa2c3}, /* U+2285 NOT A SUPERSET OF [2000] */ + {0xe28a86, 0xa2bc}, /* U+2286 SUBSET OF OR EQUAL TO [1983] */ + {0xe28a87, 0xa2bd}, /* U+2287 SUPERSET OF OR EQUAL TO [1983] */ + {0xe28a8a, 0xa2c4}, /* U+228A SUBSET OF WITH NOT EQUAL TO [2000] */ + {0xe28a8b, 0xa2c5}, /* U+228B SUPERSET OF WITH NOT EQUAL TO [2000] */ + {0xe28a95, 0xa2d1}, /* U+2295 CIRCLED PLUS [2000] */ + {0xe28a96, 0xa2d2}, /* U+2296 CIRCLED MINUS [2000] */ + {0xe28a97, 0xa2d3}, /* U+2297 CIRCLED TIMES [2000] */ + {0xe28aa5, 0xa2dd}, /* U+22A5 UP TACK [1983] */ + {0xe28abf, 0xadf9}, /* U+22BF RIGHT TRIANGLE [2000] */ + {0xe28b9a, 0xa7f6}, /* U+22DA LESS-THAN EQUAL TO OR GREATER-THAN [2000] */ + {0xe28b9b, 0xa7f7}, /* U+22DB GREATER-THAN EQUAL TO OR LESS-THAN [2000] */ + {0xe28c85, 0xa2c8}, /* U+2305 PROJECTIVE [2000] */ + {0xe28c86, 0xa2c9}, /* U+2306 PERSPECTIVE [2000] */ + {0xe28c92, 0xa2de}, /* U+2312 ARC [1983] */ + {0xe28c98, 0xa7fc}, /* U+2318 PLACE OF INTEREST SIGN [2000] */ + {0xe28ebe, 0xa7c2}, /* U+23BE DENTISTRY SYMBOL LIGHT VERTICAL AND TOP RIGHT [2000] [Unicode3.2] */ + {0xe28ebf, 0xa7c3}, /* U+23BF DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM RIGHT [2000] [Unicode3.2] */ + {0xe28f80, 0xa7c4}, /* U+23C0 DENTISTRY SYMBOL LIGHT VERTICAL WITH CIRCLE [2000] [Unicode3.2] */ + {0xe28f81, 0xa7c5}, /* U+23C1 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH CIRCLE [2000] [Unicode3.2] */ + {0xe28f82, 0xa7c6}, /* U+23C2 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLE [2000] [Unicode3.2] */ + {0xe28f83, 0xa7c7}, /* U+23C3 DENTISTRY SYMBOL LIGHT VERTICAL WITH TRIANGLE [2000] [Unicode3.2] */ + {0xe28f84, 0xa7c8}, /* U+23C4 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH TRIANGLE [2000] [Unicode3.2] */ + {0xe28f85, 0xa7c9}, /* U+23C5 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH TRIANGLE [2000] [Unicode3.2] */ + {0xe28f86, 0xa7ca}, /* U+23C6 DENTISTRY SYMBOL LIGHT VERTICAL AND WAVE [2000] [Unicode3.2] */ + {0xe28f87, 0xa7cb}, /* U+23C7 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH WAVE [2000] [Unicode3.2] */ + {0xe28f88, 0xa7cc}, /* U+23C8 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH WAVE [2000] [Unicode3.2] */ + {0xe28f89, 0xa7cd}, /* U+23C9 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL [2000] [Unicode3.2] */ + {0xe28f8a, 0xa7ce}, /* U+23CA DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL [2000] [Unicode3.2] */ + {0xe28f8b, 0xa7cf}, /* U+23CB DENTISTRY SYMBOL LIGHT VERTICAL AND TOP LEFT [2000] [Unicode3.2] */ + {0xe28f8c, 0xa7d0}, /* U+23CC DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM LEFT [2000] [Unicode3.2] */ + {0xe28f8e, 0xa7fe}, /* U+23CE RETURN SYMBOL [2000] [Unicode3.2] */ + {0xe290a3, 0xa7fd}, /* U+2423 OPEN BOX [2000] */ + {0xe291a0, 0xada1}, /* U+2460 CIRCLED DIGIT ONE [2000] */ + {0xe291a1, 0xada2}, /* U+2461 CIRCLED DIGIT TWO [2000] */ + {0xe291a2, 0xada3}, /* U+2462 CIRCLED DIGIT THREE [2000] */ + {0xe291a3, 0xada4}, /* U+2463 CIRCLED DIGIT FOUR [2000] */ + {0xe291a4, 0xada5}, /* U+2464 CIRCLED DIGIT FIVE [2000] */ + {0xe291a5, 0xada6}, /* U+2465 CIRCLED DIGIT SIX [2000] */ + {0xe291a6, 0xada7}, /* U+2466 CIRCLED DIGIT SEVEN [2000] */ + {0xe291a7, 0xada8}, /* U+2467 CIRCLED DIGIT EIGHT [2000] */ + {0xe291a8, 0xada9}, /* U+2468 CIRCLED DIGIT NINE [2000] */ + {0xe291a9, 0xadaa}, /* U+2469 CIRCLED NUMBER TEN [2000] */ + {0xe291aa, 0xadab}, /* U+246A CIRCLED NUMBER ELEVEN [2000] */ + {0xe291ab, 0xadac}, /* U+246B CIRCLED NUMBER TWELVE [2000] */ + {0xe291ac, 0xadad}, /* U+246C CIRCLED NUMBER THIRTEEN [2000] */ + {0xe291ad, 0xadae}, /* U+246D CIRCLED NUMBER FOURTEEN [2000] */ + {0xe291ae, 0xadaf}, /* U+246E CIRCLED NUMBER FIFTEEN [2000] */ + {0xe291af, 0xadb0}, /* U+246F CIRCLED NUMBER SIXTEEN [2000] */ + {0xe291b0, 0xadb1}, /* U+2470 CIRCLED NUMBER SEVENTEEN [2000] */ + {0xe291b1, 0xadb2}, /* U+2471 CIRCLED NUMBER EIGHTEEN [2000] */ + {0xe291b2, 0xadb3}, /* U+2472 CIRCLED NUMBER NINETEEN [2000] */ + {0xe291b3, 0xadb4}, /* U+2473 CIRCLED NUMBER TWENTY [2000] */ + {0xe29390, 0xacc1}, /* U+24D0 CIRCLED LATIN SMALL LETTER A [2000] */ + {0xe29391, 0xacc2}, /* U+24D1 CIRCLED LATIN SMALL LETTER B [2000] */ + {0xe29392, 0xacc3}, /* U+24D2 CIRCLED LATIN SMALL LETTER C [2000] */ + {0xe29393, 0xacc4}, /* U+24D3 CIRCLED LATIN SMALL LETTER D [2000] */ + {0xe29394, 0xacc5}, /* U+24D4 CIRCLED LATIN SMALL LETTER E [2000] */ + {0xe29395, 0xacc6}, /* U+24D5 CIRCLED LATIN SMALL LETTER F [2000] */ + {0xe29396, 0xacc7}, /* U+24D6 CIRCLED LATIN SMALL LETTER G [2000] */ + {0xe29397, 0xacc8}, /* U+24D7 CIRCLED LATIN SMALL LETTER H [2000] */ + {0xe29398, 0xacc9}, /* U+24D8 CIRCLED LATIN SMALL LETTER I [2000] */ + {0xe29399, 0xacca}, /* U+24D9 CIRCLED LATIN SMALL LETTER J [2000] */ + {0xe2939a, 0xaccb}, /* U+24DA CIRCLED LATIN SMALL LETTER K [2000] */ + {0xe2939b, 0xaccc}, /* U+24DB CIRCLED LATIN SMALL LETTER L [2000] */ + {0xe2939c, 0xaccd}, /* U+24DC CIRCLED LATIN SMALL LETTER M [2000] */ + {0xe2939d, 0xacce}, /* U+24DD CIRCLED LATIN SMALL LETTER N [2000] */ + {0xe2939e, 0xaccf}, /* U+24DE CIRCLED LATIN SMALL LETTER O [2000] */ + {0xe2939f, 0xacd0}, /* U+24DF CIRCLED LATIN SMALL LETTER P [2000] */ + {0xe293a0, 0xacd1}, /* U+24E0 CIRCLED LATIN SMALL LETTER Q [2000] */ + {0xe293a1, 0xacd2}, /* U+24E1 CIRCLED LATIN SMALL LETTER R [2000] */ + {0xe293a2, 0xacd3}, /* U+24E2 CIRCLED LATIN SMALL LETTER S [2000] */ + {0xe293a3, 0xacd4}, /* U+24E3 CIRCLED LATIN SMALL LETTER T [2000] */ + {0xe293a4, 0xacd5}, /* U+24E4 CIRCLED LATIN SMALL LETTER U [2000] */ + {0xe293a5, 0xacd6}, /* U+24E5 CIRCLED LATIN SMALL LETTER V [2000] */ + {0xe293a6, 0xacd7}, /* U+24E6 CIRCLED LATIN SMALL LETTER W [2000] */ + {0xe293a7, 0xacd8}, /* U+24E7 CIRCLED LATIN SMALL LETTER X [2000] */ + {0xe293a8, 0xacd9}, /* U+24E8 CIRCLED LATIN SMALL LETTER Y [2000] */ + {0xe293a9, 0xacda}, /* U+24E9 CIRCLED LATIN SMALL LETTER Z [2000] */ + {0xe293ab, 0xacab}, /* U+24EB NEGATIVE CIRCLED NUMBER ELEVEN [2000] [Unicode3.2] */ + {0xe293ac, 0xacac}, /* U+24EC NEGATIVE CIRCLED NUMBER TWELVE [2000] [Unicode3.2] */ + {0xe293ad, 0xacad}, /* U+24ED NEGATIVE CIRCLED NUMBER THIRTEEN [2000] [Unicode3.2] */ + {0xe293ae, 0xacae}, /* U+24EE NEGATIVE CIRCLED NUMBER FOURTEEN [2000] [Unicode3.2] */ + {0xe293af, 0xacaf}, /* U+24EF NEGATIVE CIRCLED NUMBER FIFTEEN [2000] [Unicode3.2] */ + {0xe293b0, 0xacb0}, /* U+24F0 NEGATIVE CIRCLED NUMBER SIXTEEN [2000] [Unicode3.2] */ + {0xe293b1, 0xacb1}, /* U+24F1 NEGATIVE CIRCLED NUMBER SEVENTEEN [2000] [Unicode3.2] */ + {0xe293b2, 0xacb2}, /* U+24F2 NEGATIVE CIRCLED NUMBER EIGHTEEN [2000] [Unicode3.2] */ + {0xe293b3, 0xacb3}, /* U+24F3 NEGATIVE CIRCLED NUMBER NINETEEN [2000] [Unicode3.2] */ + {0xe293b4, 0xacb4}, /* U+24F4 NEGATIVE CIRCLED NUMBER TWENTY [2000] [Unicode3.2] */ + {0xe293b5, 0xa6da}, /* U+24F5 DOUBLE CIRCLED DIGIT ONE [2000] [Unicode3.2] */ + {0xe293b6, 0xa6db}, /* U+24F6 DOUBLE CIRCLED DIGIT TWO [2000] [Unicode3.2] */ + {0xe293b7, 0xa6dc}, /* U+24F7 DOUBLE CIRCLED DIGIT THREE [2000] [Unicode3.2] */ + {0xe293b8, 0xa6dd}, /* U+24F8 DOUBLE CIRCLED DIGIT FOUR [2000] [Unicode3.2] */ + {0xe293b9, 0xa6de}, /* U+24F9 DOUBLE CIRCLED DIGIT FIVE [2000] [Unicode3.2] */ + {0xe293ba, 0xa6df}, /* U+24FA DOUBLE CIRCLED DIGIT SIX [2000] [Unicode3.2] */ + {0xe293bb, 0xa6e0}, /* U+24FB DOUBLE CIRCLED DIGIT SEVEN [2000] [Unicode3.2] */ + {0xe293bc, 0xa6e1}, /* U+24FC DOUBLE CIRCLED DIGIT EIGHT [2000] [Unicode3.2] */ + {0xe293bd, 0xa6e2}, /* U+24FD DOUBLE CIRCLED DIGIT NINE [2000] [Unicode3.2] */ + {0xe293be, 0xa6e3}, /* U+24FE DOUBLE CIRCLED NUMBER TEN [2000] [Unicode3.2] */ + {0xe29480, 0xa8a1}, /* U+2500 BOX DRAWINGS LIGHT HORIZONTAL [1983] */ + {0xe29481, 0xa8ac}, /* U+2501 BOX DRAWINGS HEAVY HORIZONTAL [1983] */ + {0xe29482, 0xa8a2}, /* U+2502 BOX DRAWINGS LIGHT VERTICAL [1983] */ + {0xe29483, 0xa8ad}, /* U+2503 BOX DRAWINGS HEAVY VERTICAL [1983] */ + {0xe2948c, 0xa8a3}, /* U+250C BOX DRAWINGS LIGHT DOWN AND RIGHT [1983] */ + {0xe2948f, 0xa8ae}, /* U+250F BOX DRAWINGS HEAVY DOWN AND RIGHT [1983] */ + {0xe29490, 0xa8a4}, /* U+2510 BOX DRAWINGS LIGHT DOWN AND LEFT [1983] */ + {0xe29493, 0xa8af}, /* U+2513 BOX DRAWINGS HEAVY DOWN AND LEFT [1983] */ + {0xe29494, 0xa8a6}, /* U+2514 BOX DRAWINGS LIGHT UP AND RIGHT [1983] */ + {0xe29497, 0xa8b1}, /* U+2517 BOX DRAWINGS HEAVY UP AND RIGHT [1983] */ + {0xe29498, 0xa8a5}, /* U+2518 BOX DRAWINGS LIGHT UP AND LEFT [1983] */ + {0xe2949b, 0xa8b0}, /* U+251B BOX DRAWINGS HEAVY UP AND LEFT [1983] */ + {0xe2949c, 0xa8a7}, /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT [1983] */ + {0xe2949d, 0xa8bc}, /* U+251D BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY [1983] */ + {0xe294a0, 0xa8b7}, /* U+2520 BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT [1983] */ + {0xe294a3, 0xa8b2}, /* U+2523 BOX DRAWINGS HEAVY VERTICAL AND RIGHT [1983] */ + {0xe294a4, 0xa8a9}, /* U+2524 BOX DRAWINGS LIGHT VERTICAL AND LEFT [1983] */ + {0xe294a5, 0xa8be}, /* U+2525 BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY [1983] */ + {0xe294a8, 0xa8b9}, /* U+2528 BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT [1983] */ + {0xe294ab, 0xa8b4}, /* U+252B BOX DRAWINGS HEAVY VERTICAL AND LEFT [1983] */ + {0xe294ac, 0xa8a8}, /* U+252C BOX DRAWINGS LIGHT DOWN AND HORIZONTAL [1983] */ + {0xe294af, 0xa8b8}, /* U+252F BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY [1983] */ + {0xe294b0, 0xa8bd}, /* U+2530 BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT [1983] */ + {0xe294b3, 0xa8b3}, /* U+2533 BOX DRAWINGS HEAVY DOWN AND HORIZONTAL [1983] */ + {0xe294b4, 0xa8aa}, /* U+2534 BOX DRAWINGS LIGHT UP AND HORIZONTAL [1983] */ + {0xe294b7, 0xa8ba}, /* U+2537 BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY [1983] */ + {0xe294b8, 0xa8bf}, /* U+2538 BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT [1983] */ + {0xe294bb, 0xa8b5}, /* U+253B BOX DRAWINGS HEAVY UP AND HORIZONTAL [1983] */ + {0xe294bc, 0xa8ab}, /* U+253C BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL [1983] */ + {0xe294bf, 0xa8bb}, /* U+253F BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY [1983] */ + {0xe29582, 0xa8c0}, /* U+2542 BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT [1983] */ + {0xe2958b, 0xa8b6}, /* U+254B BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL [1983] */ + {0xe296a0, 0xa2a3}, /* U+25A0 BLACK SQUARE */ + {0xe296a1, 0xa2a2}, /* U+25A1 WHITE SQUARE */ + {0xe296b1, 0xa6ed}, /* U+25B1 WHITE PARALLELOGRAM [2000] */ + {0xe296b2, 0xa2a5}, /* U+25B2 BLACK UP-POINTING TRIANGLE */ + {0xe296b3, 0xa2a4}, /* U+25B3 WHITE UP-POINTING TRIANGLE */ + {0xe296b6, 0xa3a2}, /* U+25B6 BLACK RIGHT-POINTING TRIANGLE [2000] */ + {0xe296b7, 0xa3a1}, /* U+25B7 WHITE RIGHT-POINTING TRIANGLE [2000] */ + {0xe296bc, 0xa2a7}, /* U+25BC BLACK DOWN-POINTING TRIANGLE */ + {0xe296bd, 0xa2a6}, /* U+25BD WHITE DOWN-POINTING TRIANGLE */ + {0xe29780, 0xa3a4}, /* U+25C0 BLACK LEFT-POINTING TRIANGLE [2000] */ + {0xe29781, 0xa3a3}, /* U+25C1 WHITE LEFT-POINTING TRIANGLE [2000] */ + {0xe29786, 0xa2a1}, /* U+25C6 BLACK DIAMOND */ + {0xe29787, 0xa1fe}, /* U+25C7 WHITE DIAMOND */ + {0xe29789, 0xa3bb}, /* U+25C9 FISHEYE [2000] */ + {0xe2978b, 0xa1fb}, /* U+25CB WHITE CIRCLE */ + {0xe2978e, 0xa1fd}, /* U+25CE BULLSEYE */ + {0xe2978f, 0xa1fc}, /* U+25CF BLACK CIRCLE */ + {0xe29790, 0xa8e7}, /* U+25D0 CIRCLE WITH LEFT HALF BLACK [2000] */ + {0xe29791, 0xa8e8}, /* U+25D1 CIRCLE WITH RIGHT HALF BLACK [2000] */ + {0xe29792, 0xa8e9}, /* U+25D2 CIRCLE WITH LOWER HALF BLACK [2000] */ + {0xe29793, 0xa8ea}, /* U+25D3 CIRCLE WITH UPPER HALF BLACK [2000] */ + {0xe297a6, 0xa3bf}, /* U+25E6 WHITE BULLET [2000] */ + {0xe297af, 0xa2fe}, /* U+25EF LARGE CIRCLE [1983] */ + {0xe29880, 0xa6e8}, /* U+2600 BLACK SUN WITH RAYS [2000] */ + {0xe29881, 0xa6e9}, /* U+2601 CLOUD [2000] */ + {0xe29882, 0xa6ea}, /* U+2602 UMBRELLA [2000] */ + {0xe29883, 0xa6eb}, /* U+2603 SNOWMAN [2000] */ + {0xe29885, 0xa1fa}, /* U+2605 BLACK STAR */ + {0xe29886, 0xa1f9}, /* U+2606 WHITE STAR */ + {0xe2988e, 0xa6e7}, /* U+260E BLACK TELEPHONE [2000] */ + {0xe29896, 0xa6e4}, /* U+2616 WHITE SHOGI PIECE [2000] [Unicode3.2] */ + {0xe29897, 0xa6e5}, /* U+2617 BLACK SHOGI PIECE [2000] [Unicode3.2] */ + {0xe2989e, 0xadfe}, /* U+261E WHITE RIGHT POINTING INDEX [2000] */ + {0xe29980, 0xa1ea}, /* U+2640 FEMALE SIGN */ + {0xe29982, 0xa1e9}, /* U+2642 MALE SIGN */ + {0xe299a0, 0xa6ba}, /* U+2660 BLACK SPADE SUIT [2000] */ + {0xe299a1, 0xa6bd}, /* U+2661 WHITE HEART SUIT [2000] */ + {0xe299a2, 0xa6bb}, /* U+2662 WHITE DIAMOND SUIT [2000] */ + {0xe299a3, 0xa6c0}, /* U+2663 BLACK CLUB SUIT [2000] */ + {0xe299a4, 0xa6b9}, /* U+2664 WHITE SPADE SUIT [2000] */ + {0xe299a5, 0xa6be}, /* U+2665 BLACK HEART SUIT [2000] */ + {0xe299a6, 0xa6bc}, /* U+2666 BLACK DIAMOND SUIT [2000] */ + {0xe299a7, 0xa6bf}, /* U+2667 WHITE CLUB SUIT [2000] */ + {0xe299a8, 0xa6ec}, /* U+2668 HOT SPRINGS [2000] */ + {0xe299a9, 0xa2fd}, /* U+2669 QUARTER NOTE [2000] */ + {0xe299aa, 0xa2f6}, /* U+266A EIGHTH NOTE [1983] */ + {0xe299ab, 0xa2fb}, /* U+266B BEAMED EIGHTH NOTES [2000] */ + {0xe299ac, 0xa2fc}, /* U+266C BEAMED SIXTEENTH NOTES [2000] */ + {0xe299ad, 0xa2f5}, /* U+266D MUSIC FLAT SIGN [1983] */ + {0xe299ae, 0xa2fa}, /* U+266E MUSIC NATURAL SIGN [2000] */ + {0xe299af, 0xa2f4}, /* U+266F MUSIC SHARP SIGN [1983] */ + {0xe29c93, 0xa7fb}, /* U+2713 CHECK MARK [2000] */ + {0xe29d96, 0xadfd}, /* U+2756 BLACK DIAMOND MINUS WHITE X [2000] */ + {0xe29db6, 0xaca1}, /* U+2776 DINGBAT NEGATIVE CIRCLED DIGIT ONE [2000] */ + {0xe29db7, 0xaca2}, /* U+2777 DINGBAT NEGATIVE CIRCLED DIGIT TWO [2000] */ + {0xe29db8, 0xaca3}, /* U+2778 DINGBAT NEGATIVE CIRCLED DIGIT THREE [2000] */ + {0xe29db9, 0xaca4}, /* U+2779 DINGBAT NEGATIVE CIRCLED DIGIT FOUR [2000] */ + {0xe29dba, 0xaca5}, /* U+277A DINGBAT NEGATIVE CIRCLED DIGIT FIVE [2000] */ + {0xe29dbb, 0xaca6}, /* U+277B DINGBAT NEGATIVE CIRCLED DIGIT SIX [2000] */ + {0xe29dbc, 0xaca7}, /* U+277C DINGBAT NEGATIVE CIRCLED DIGIT SEVEN [2000] */ + {0xe29dbd, 0xaca8}, /* U+277D DINGBAT NEGATIVE CIRCLED DIGIT EIGHT [2000] */ + {0xe29dbe, 0xaca9}, /* U+277E DINGBAT NEGATIVE CIRCLED DIGIT NINE [2000] */ + {0xe29dbf, 0xacaa}, /* U+277F DINGBAT NEGATIVE CIRCLED NUMBER TEN [2000] */ + {0xe2a4b4, 0xa3ae}, /* U+2934 ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS [2000] [Unicode3.2] */ + {0xe2a4b5, 0xa3af}, /* U+2935 ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS [2000] [Unicode3.2] */ + {0xe2a6bf, 0xa3ba}, /* U+29BF CIRCLED BULLET [2000] [Unicode3.2] */ + {0xe2a7ba, 0xa3fd}, /* U+29FA DOUBLE PLUS [2000] [Unicode3.2] */ + {0xe2a7bb, 0xa3fe}, /* U+29FB TRIPLE PLUS [2000] [Unicode3.2] */ + {0xe38080, 0xa1a1}, /* U+3000 IDEOGRAPHIC SPACE */ + {0xe38081, 0xa1a2}, /* U+3001 IDEOGRAPHIC COMMA */ + {0xe38082, 0xa1a3}, /* U+3002 IDEOGRAPHIC FULL STOP */ + {0xe38083, 0xa1b7}, /* U+3003 DITTO MARK */ + {0xe38085, 0xa1b9}, /* U+3005 IDEOGRAPHIC ITERATION MARK */ + {0xe38086, 0xa1ba}, /* U+3006 IDEOGRAPHIC CLOSING MARK */ + {0xe38087, 0xa1bb}, /* U+3007 IDEOGRAPHIC NUMBER ZERO */ + {0xe38088, 0xa1d2}, /* U+3008 LEFT ANGLE BRACKET */ + {0xe38089, 0xa1d3}, /* U+3009 RIGHT ANGLE BRACKET */ + {0xe3808a, 0xa1d4}, /* U+300A LEFT DOUBLE ANGLE BRACKET */ + {0xe3808b, 0xa1d5}, /* U+300B RIGHT DOUBLE ANGLE BRACKET */ + {0xe3808c, 0xa1d6}, /* U+300C LEFT CORNER BRACKET */ + {0xe3808d, 0xa1d7}, /* U+300D RIGHT CORNER BRACKET */ + {0xe3808e, 0xa1d8}, /* U+300E LEFT WHITE CORNER BRACKET */ + {0xe3808f, 0xa1d9}, /* U+300F RIGHT WHITE CORNER BRACKET */ + {0xe38090, 0xa1da}, /* U+3010 LEFT BLACK LENTICULAR BRACKET */ + {0xe38091, 0xa1db}, /* U+3011 RIGHT BLACK LENTICULAR BRACKET */ + {0xe38092, 0xa2a9}, /* U+3012 POSTAL MARK */ + {0xe38093, 0xa2ae}, /* U+3013 GETA MARK */ + {0xe38094, 0xa1cc}, /* U+3014 LEFT TORTOISE SHELL BRACKET */ + {0xe38095, 0xa1cd}, /* U+3015 RIGHT TORTOISE SHELL BRACKET */ + {0xe38096, 0xa2da}, /* U+3016 LEFT WHITE LENTICULAR BRACKET [2000] */ + {0xe38097, 0xa2db}, /* U+3017 RIGHT WHITE LENTICULAR BRACKET [2000] */ + {0xe38098, 0xa2d8}, /* U+3018 LEFT WHITE TORTOISE SHELL BRACKET [2000] */ + {0xe38099, 0xa2d9}, /* U+3019 RIGHT WHITE TORTOISE SHELL BRACKET [2000] */ + {0xe3809c, 0xa1c1}, /* U+301C WAVE DASH Windows: U+FF5E */ + {0xe3809d, 0xade0}, /* U+301D REVERSED DOUBLE PRIME QUOTATION MARK [2000] */ + {0xe3809f, 0xade1}, /* U+301F LOW DOUBLE PRIME QUOTATION MARK [2000] */ + {0xe380a0, 0xa6e6}, /* U+3020 POSTAL MARK FACE [2000] */ + {0xe380b3, 0xa2b3}, /* U+3033 VERTICAL KANA REPEAT MARK UPPER HALF [2000] */ + {0xe380b4, 0xa2b4}, /* U+3034 VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF [2000] */ + {0xe380b5, 0xa2b5}, /* U+3035 VERTICAL KANA REPEAT MARK LOWER HALF [2000] */ + {0xe380bb, 0xa2b6}, /* U+303B VERTICAL IDEOGRAPHIC ITERATION MARK [2000] [Unicode3.2] */ + {0xe380bc, 0xa2b7}, /* U+303C MASU MARK [2000] [Unicode3.2] */ + {0xe380bd, 0xa3bc}, /* U+303D PART ALTERNATION MARK [2000] [Unicode3.2] */ + {0xe38181, 0xa4a1}, /* U+3041 HIRAGANA LETTER SMALL A */ + {0xe38182, 0xa4a2}, /* U+3042 HIRAGANA LETTER A */ + {0xe38183, 0xa4a3}, /* U+3043 HIRAGANA LETTER SMALL I */ + {0xe38184, 0xa4a4}, /* U+3044 HIRAGANA LETTER I */ + {0xe38185, 0xa4a5}, /* U+3045 HIRAGANA LETTER SMALL U */ + {0xe38186, 0xa4a6}, /* U+3046 HIRAGANA LETTER U */ + {0xe38187, 0xa4a7}, /* U+3047 HIRAGANA LETTER SMALL E */ + {0xe38188, 0xa4a8}, /* U+3048 HIRAGANA LETTER E */ + {0xe38189, 0xa4a9}, /* U+3049 HIRAGANA LETTER SMALL O */ + {0xe3818a, 0xa4aa}, /* U+304A HIRAGANA LETTER O */ + {0xe3818b, 0xa4ab}, /* U+304B HIRAGANA LETTER KA */ + {0xe3818c, 0xa4ac}, /* U+304C HIRAGANA LETTER GA */ + {0xe3818d, 0xa4ad}, /* U+304D HIRAGANA LETTER KI */ + {0xe3818e, 0xa4ae}, /* U+304E HIRAGANA LETTER GI */ + {0xe3818f, 0xa4af}, /* U+304F HIRAGANA LETTER KU */ + {0xe38190, 0xa4b0}, /* U+3050 HIRAGANA LETTER GU */ + {0xe38191, 0xa4b1}, /* U+3051 HIRAGANA LETTER KE */ + {0xe38192, 0xa4b2}, /* U+3052 HIRAGANA LETTER GE */ + {0xe38193, 0xa4b3}, /* U+3053 HIRAGANA LETTER KO */ + {0xe38194, 0xa4b4}, /* U+3054 HIRAGANA LETTER GO */ + {0xe38195, 0xa4b5}, /* U+3055 HIRAGANA LETTER SA */ + {0xe38196, 0xa4b6}, /* U+3056 HIRAGANA LETTER ZA */ + {0xe38197, 0xa4b7}, /* U+3057 HIRAGANA LETTER SI */ + {0xe38198, 0xa4b8}, /* U+3058 HIRAGANA LETTER ZI */ + {0xe38199, 0xa4b9}, /* U+3059 HIRAGANA LETTER SU */ + {0xe3819a, 0xa4ba}, /* U+305A HIRAGANA LETTER ZU */ + {0xe3819b, 0xa4bb}, /* U+305B HIRAGANA LETTER SE */ + {0xe3819c, 0xa4bc}, /* U+305C HIRAGANA LETTER ZE */ + {0xe3819d, 0xa4bd}, /* U+305D HIRAGANA LETTER SO */ + {0xe3819e, 0xa4be}, /* U+305E HIRAGANA LETTER ZO */ + {0xe3819f, 0xa4bf}, /* U+305F HIRAGANA LETTER TA */ + {0xe381a0, 0xa4c0}, /* U+3060 HIRAGANA LETTER DA */ + {0xe381a1, 0xa4c1}, /* U+3061 HIRAGANA LETTER TI */ + {0xe381a2, 0xa4c2}, /* U+3062 HIRAGANA LETTER DI */ + {0xe381a3, 0xa4c3}, /* U+3063 HIRAGANA LETTER SMALL TU */ + {0xe381a4, 0xa4c4}, /* U+3064 HIRAGANA LETTER TU */ + {0xe381a5, 0xa4c5}, /* U+3065 HIRAGANA LETTER DU */ + {0xe381a6, 0xa4c6}, /* U+3066 HIRAGANA LETTER TE */ + {0xe381a7, 0xa4c7}, /* U+3067 HIRAGANA LETTER DE */ + {0xe381a8, 0xa4c8}, /* U+3068 HIRAGANA LETTER TO */ + {0xe381a9, 0xa4c9}, /* U+3069 HIRAGANA LETTER DO */ + {0xe381aa, 0xa4ca}, /* U+306A HIRAGANA LETTER NA */ + {0xe381ab, 0xa4cb}, /* U+306B HIRAGANA LETTER NI */ + {0xe381ac, 0xa4cc}, /* U+306C HIRAGANA LETTER NU */ + {0xe381ad, 0xa4cd}, /* U+306D HIRAGANA LETTER NE */ + {0xe381ae, 0xa4ce}, /* U+306E HIRAGANA LETTER NO */ + {0xe381af, 0xa4cf}, /* U+306F HIRAGANA LETTER HA */ + {0xe381b0, 0xa4d0}, /* U+3070 HIRAGANA LETTER BA */ + {0xe381b1, 0xa4d1}, /* U+3071 HIRAGANA LETTER PA */ + {0xe381b2, 0xa4d2}, /* U+3072 HIRAGANA LETTER HI */ + {0xe381b3, 0xa4d3}, /* U+3073 HIRAGANA LETTER BI */ + {0xe381b4, 0xa4d4}, /* U+3074 HIRAGANA LETTER PI */ + {0xe381b5, 0xa4d5}, /* U+3075 HIRAGANA LETTER HU */ + {0xe381b6, 0xa4d6}, /* U+3076 HIRAGANA LETTER BU */ + {0xe381b7, 0xa4d7}, /* U+3077 HIRAGANA LETTER PU */ + {0xe381b8, 0xa4d8}, /* U+3078 HIRAGANA LETTER HE */ + {0xe381b9, 0xa4d9}, /* U+3079 HIRAGANA LETTER BE */ + {0xe381ba, 0xa4da}, /* U+307A HIRAGANA LETTER PE */ + {0xe381bb, 0xa4db}, /* U+307B HIRAGANA LETTER HO */ + {0xe381bc, 0xa4dc}, /* U+307C HIRAGANA LETTER BO */ + {0xe381bd, 0xa4dd}, /* U+307D HIRAGANA LETTER PO */ + {0xe381be, 0xa4de}, /* U+307E HIRAGANA LETTER MA */ + {0xe381bf, 0xa4df}, /* U+307F HIRAGANA LETTER MI */ + {0xe38280, 0xa4e0}, /* U+3080 HIRAGANA LETTER MU */ + {0xe38281, 0xa4e1}, /* U+3081 HIRAGANA LETTER ME */ + {0xe38282, 0xa4e2}, /* U+3082 HIRAGANA LETTER MO */ + {0xe38283, 0xa4e3}, /* U+3083 HIRAGANA LETTER SMALL YA */ + {0xe38284, 0xa4e4}, /* U+3084 HIRAGANA LETTER YA */ + {0xe38285, 0xa4e5}, /* U+3085 HIRAGANA LETTER SMALL YU */ + {0xe38286, 0xa4e6}, /* U+3086 HIRAGANA LETTER YU */ + {0xe38287, 0xa4e7}, /* U+3087 HIRAGANA LETTER SMALL YO */ + {0xe38288, 0xa4e8}, /* U+3088 HIRAGANA LETTER YO */ + {0xe38289, 0xa4e9}, /* U+3089 HIRAGANA LETTER RA */ + {0xe3828a, 0xa4ea}, /* U+308A HIRAGANA LETTER RI */ + {0xe3828b, 0xa4eb}, /* U+308B HIRAGANA LETTER RU */ + {0xe3828c, 0xa4ec}, /* U+308C HIRAGANA LETTER RE */ + {0xe3828d, 0xa4ed}, /* U+308D HIRAGANA LETTER RO */ + {0xe3828e, 0xa4ee}, /* U+308E HIRAGANA LETTER SMALL WA */ + {0xe3828f, 0xa4ef}, /* U+308F HIRAGANA LETTER WA */ + {0xe38290, 0xa4f0}, /* U+3090 HIRAGANA LETTER WI */ + {0xe38291, 0xa4f1}, /* U+3091 HIRAGANA LETTER WE */ + {0xe38292, 0xa4f2}, /* U+3092 HIRAGANA LETTER WO */ + {0xe38293, 0xa4f3}, /* U+3093 HIRAGANA LETTER N */ + {0xe38294, 0xa4f4}, /* U+3094 HIRAGANA LETTER VU [2000] */ + {0xe38295, 0xa4f5}, /* U+3095 HIRAGANA LETTER SMALL KA [2000] [Unicode3.2] */ + {0xe38296, 0xa4f6}, /* U+3096 HIRAGANA LETTER SMALL KE [2000] [Unicode3.2] */ + {0xe3829b, 0xa1ab}, /* U+309B KATAKANA-HIRAGANA VOICED SOUND MARK */ + {0xe3829c, 0xa1ac}, /* U+309C KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ + {0xe3829d, 0xa1b5}, /* U+309D HIRAGANA ITERATION MARK */ + {0xe3829e, 0xa1b6}, /* U+309E HIRAGANA VOICED ITERATION MARK */ + {0xe3829f, 0xa2b9}, /* U+309F HIRAGANA DIGRAPH YORI [2000] [Unicode3.2] */ + {0xe382a0, 0xa3fb}, /* U+30A0 KATAKANA-HIRAGANA DOUBLE HYPHEN [2000] [Unicode3.2] */ + {0xe382a1, 0xa5a1}, /* U+30A1 KATAKANA LETTER SMALL A */ + {0xe382a2, 0xa5a2}, /* U+30A2 KATAKANA LETTER A */ + {0xe382a3, 0xa5a3}, /* U+30A3 KATAKANA LETTER SMALL I */ + {0xe382a4, 0xa5a4}, /* U+30A4 KATAKANA LETTER I */ + {0xe382a5, 0xa5a5}, /* U+30A5 KATAKANA LETTER SMALL U */ + {0xe382a6, 0xa5a6}, /* U+30A6 KATAKANA LETTER U */ + {0xe382a7, 0xa5a7}, /* U+30A7 KATAKANA LETTER SMALL E */ + {0xe382a8, 0xa5a8}, /* U+30A8 KATAKANA LETTER E */ + {0xe382a9, 0xa5a9}, /* U+30A9 KATAKANA LETTER SMALL O */ + {0xe382aa, 0xa5aa}, /* U+30AA KATAKANA LETTER O */ + {0xe382ab, 0xa5ab}, /* U+30AB KATAKANA LETTER KA */ + {0xe382ac, 0xa5ac}, /* U+30AC KATAKANA LETTER GA */ + {0xe382ad, 0xa5ad}, /* U+30AD KATAKANA LETTER KI */ + {0xe382ae, 0xa5ae}, /* U+30AE KATAKANA LETTER GI */ + {0xe382af, 0xa5af}, /* U+30AF KATAKANA LETTER KU */ + {0xe382b0, 0xa5b0}, /* U+30B0 KATAKANA LETTER GU */ + {0xe382b1, 0xa5b1}, /* U+30B1 KATAKANA LETTER KE */ + {0xe382b2, 0xa5b2}, /* U+30B2 KATAKANA LETTER GE */ + {0xe382b3, 0xa5b3}, /* U+30B3 KATAKANA LETTER KO */ + {0xe382b4, 0xa5b4}, /* U+30B4 KATAKANA LETTER GO */ + {0xe382b5, 0xa5b5}, /* U+30B5 KATAKANA LETTER SA */ + {0xe382b6, 0xa5b6}, /* U+30B6 KATAKANA LETTER ZA */ + {0xe382b7, 0xa5b7}, /* U+30B7 KATAKANA LETTER SI */ + {0xe382b8, 0xa5b8}, /* U+30B8 KATAKANA LETTER ZI */ + {0xe382b9, 0xa5b9}, /* U+30B9 KATAKANA LETTER SU */ + {0xe382ba, 0xa5ba}, /* U+30BA KATAKANA LETTER ZU */ + {0xe382bb, 0xa5bb}, /* U+30BB KATAKANA LETTER SE */ + {0xe382bc, 0xa5bc}, /* U+30BC KATAKANA LETTER ZE */ + {0xe382bd, 0xa5bd}, /* U+30BD KATAKANA LETTER SO */ + {0xe382be, 0xa5be}, /* U+30BE KATAKANA LETTER ZO */ + {0xe382bf, 0xa5bf}, /* U+30BF KATAKANA LETTER TA */ + {0xe38380, 0xa5c0}, /* U+30C0 KATAKANA LETTER DA */ + {0xe38381, 0xa5c1}, /* U+30C1 KATAKANA LETTER TI */ + {0xe38382, 0xa5c2}, /* U+30C2 KATAKANA LETTER DI */ + {0xe38383, 0xa5c3}, /* U+30C3 KATAKANA LETTER SMALL TU */ + {0xe38384, 0xa5c4}, /* U+30C4 KATAKANA LETTER TU */ + {0xe38385, 0xa5c5}, /* U+30C5 KATAKANA LETTER DU */ + {0xe38386, 0xa5c6}, /* U+30C6 KATAKANA LETTER TE */ + {0xe38387, 0xa5c7}, /* U+30C7 KATAKANA LETTER DE */ + {0xe38388, 0xa5c8}, /* U+30C8 KATAKANA LETTER TO */ + {0xe38389, 0xa5c9}, /* U+30C9 KATAKANA LETTER DO */ + {0xe3838a, 0xa5ca}, /* U+30CA KATAKANA LETTER NA */ + {0xe3838b, 0xa5cb}, /* U+30CB KATAKANA LETTER NI */ + {0xe3838c, 0xa5cc}, /* U+30CC KATAKANA LETTER NU */ + {0xe3838d, 0xa5cd}, /* U+30CD KATAKANA LETTER NE */ + {0xe3838e, 0xa5ce}, /* U+30CE KATAKANA LETTER NO */ + {0xe3838f, 0xa5cf}, /* U+30CF KATAKANA LETTER HA */ + {0xe38390, 0xa5d0}, /* U+30D0 KATAKANA LETTER BA */ + {0xe38391, 0xa5d1}, /* U+30D1 KATAKANA LETTER PA */ + {0xe38392, 0xa5d2}, /* U+30D2 KATAKANA LETTER HI */ + {0xe38393, 0xa5d3}, /* U+30D3 KATAKANA LETTER BI */ + {0xe38394, 0xa5d4}, /* U+30D4 KATAKANA LETTER PI */ + {0xe38395, 0xa5d5}, /* U+30D5 KATAKANA LETTER HU */ + {0xe38396, 0xa5d6}, /* U+30D6 KATAKANA LETTER BU */ + {0xe38397, 0xa5d7}, /* U+30D7 KATAKANA LETTER PU */ + {0xe38398, 0xa5d8}, /* U+30D8 KATAKANA LETTER HE */ + {0xe38399, 0xa5d9}, /* U+30D9 KATAKANA LETTER BE */ + {0xe3839a, 0xa5da}, /* U+30DA KATAKANA LETTER PE */ + {0xe3839b, 0xa5db}, /* U+30DB KATAKANA LETTER HO */ + {0xe3839c, 0xa5dc}, /* U+30DC KATAKANA LETTER BO */ + {0xe3839d, 0xa5dd}, /* U+30DD KATAKANA LETTER PO */ + {0xe3839e, 0xa5de}, /* U+30DE KATAKANA LETTER MA */ + {0xe3839f, 0xa5df}, /* U+30DF KATAKANA LETTER MI */ + {0xe383a0, 0xa5e0}, /* U+30E0 KATAKANA LETTER MU */ + {0xe383a1, 0xa5e1}, /* U+30E1 KATAKANA LETTER ME */ + {0xe383a2, 0xa5e2}, /* U+30E2 KATAKANA LETTER MO */ + {0xe383a3, 0xa5e3}, /* U+30E3 KATAKANA LETTER SMALL YA */ + {0xe383a4, 0xa5e4}, /* U+30E4 KATAKANA LETTER YA */ + {0xe383a5, 0xa5e5}, /* U+30E5 KATAKANA LETTER SMALL YU */ + {0xe383a6, 0xa5e6}, /* U+30E6 KATAKANA LETTER YU */ + {0xe383a7, 0xa5e7}, /* U+30E7 KATAKANA LETTER SMALL YO */ + {0xe383a8, 0xa5e8}, /* U+30E8 KATAKANA LETTER YO */ + {0xe383a9, 0xa5e9}, /* U+30E9 KATAKANA LETTER RA */ + {0xe383aa, 0xa5ea}, /* U+30EA KATAKANA LETTER RI */ + {0xe383ab, 0xa5eb}, /* U+30EB KATAKANA LETTER RU */ + {0xe383ac, 0xa5ec}, /* U+30EC KATAKANA LETTER RE */ + {0xe383ad, 0xa5ed}, /* U+30ED KATAKANA LETTER RO */ + {0xe383ae, 0xa5ee}, /* U+30EE KATAKANA LETTER SMALL WA */ + {0xe383af, 0xa5ef}, /* U+30EF KATAKANA LETTER WA */ + {0xe383b0, 0xa5f0}, /* U+30F0 KATAKANA LETTER WI */ + {0xe383b1, 0xa5f1}, /* U+30F1 KATAKANA LETTER WE */ + {0xe383b2, 0xa5f2}, /* U+30F2 KATAKANA LETTER WO */ + {0xe383b3, 0xa5f3}, /* U+30F3 KATAKANA LETTER N */ + {0xe383b4, 0xa5f4}, /* U+30F4 KATAKANA LETTER VU */ + {0xe383b5, 0xa5f5}, /* U+30F5 KATAKANA LETTER SMALL KA */ + {0xe383b6, 0xa5f6}, /* U+30F6 KATAKANA LETTER SMALL KE */ + {0xe383b7, 0xa7f2}, /* U+30F7 KATAKANA LETTER VA [2000] */ + {0xe383b8, 0xa7f3}, /* U+30F8 KATAKANA LETTER VI [2000] */ + {0xe383b9, 0xa7f4}, /* U+30F9 KATAKANA LETTER VE [2000] */ + {0xe383ba, 0xa7f5}, /* U+30FA KATAKANA LETTER VO [2000] */ + {0xe383bb, 0xa1a6}, /* U+30FB KATAKANA MIDDLE DOT */ + {0xe383bc, 0xa1bc}, /* U+30FC KATAKANA-HIRAGANA PROLONGED SOUND MARK */ + {0xe383bd, 0xa1b3}, /* U+30FD KATAKANA ITERATION MARK */ + {0xe383be, 0xa1b4}, /* U+30FE KATAKANA VOICED ITERATION MARK */ + {0xe383bf, 0xa2b8}, /* U+30FF KATAKANA DIGRAPH KOTO [2000] [Unicode3.2] */ + {0xe387b0, 0xa6ee}, /* U+31F0 KATAKANA LETTER SMALL KU [2000] [Unicode3.2] */ + {0xe387b1, 0xa6ef}, /* U+31F1 KATAKANA LETTER SMALL SI [2000] [Unicode3.2] */ + {0xe387b2, 0xa6f0}, /* U+31F2 KATAKANA LETTER SMALL SU [2000] [Unicode3.2] */ + {0xe387b3, 0xa6f1}, /* U+31F3 KATAKANA LETTER SMALL TO [2000] [Unicode3.2] */ + {0xe387b4, 0xa6f2}, /* U+31F4 KATAKANA LETTER SMALL NU [2000] [Unicode3.2] */ + {0xe387b5, 0xa6f3}, /* U+31F5 KATAKANA LETTER SMALL HA [2000] [Unicode3.2] */ + {0xe387b6, 0xa6f4}, /* U+31F6 KATAKANA LETTER SMALL HI [2000] [Unicode3.2] */ + {0xe387b7, 0xa6f5}, /* U+31F7 KATAKANA LETTER SMALL HU [2000] [Unicode3.2] */ + {0xe387b8, 0xa6f6}, /* U+31F8 KATAKANA LETTER SMALL HE [2000] [Unicode3.2] */ + {0xe387b9, 0xa6f7}, /* U+31F9 KATAKANA LETTER SMALL HO [2000] [Unicode3.2] */ + {0xe387ba, 0xa6f9}, /* U+31FA KATAKANA LETTER SMALL MU [2000] [Unicode3.2] */ + {0xe387bb, 0xa6fa}, /* U+31FB KATAKANA LETTER SMALL RA [2000] [Unicode3.2] */ + {0xe387bc, 0xa6fb}, /* U+31FC KATAKANA LETTER SMALL RI [2000] [Unicode3.2] */ + {0xe387bd, 0xa6fc}, /* U+31FD KATAKANA LETTER SMALL RU [2000] [Unicode3.2] */ + {0xe387be, 0xa6fd}, /* U+31FE KATAKANA LETTER SMALL RE [2000] [Unicode3.2] */ + {0xe387bf, 0xa6fe}, /* U+31FF KATAKANA LETTER SMALL RO [2000] [Unicode3.2] */ + {0xe388b1, 0xadea}, /* U+3231 PARENTHESIZED IDEOGRAPH STOCK [2000] */ + {0xe388b2, 0xadeb}, /* U+3232 PARENTHESIZED IDEOGRAPH HAVE [2000] */ + {0xe388b9, 0xadec}, /* U+3239 PARENTHESIZED IDEOGRAPH REPRESENT [2000] */ + {0xe38991, 0xa8c1}, /* U+3251 CIRCLED NUMBER TWENTY ONE [2000] [Unicode3.2] */ + {0xe38992, 0xa8c2}, /* U+3252 CIRCLED NUMBER TWENTY TWO [2000] [Unicode3.2] */ + {0xe38993, 0xa8c3}, /* U+3253 CIRCLED NUMBER TWENTY THREE [2000] [Unicode3.2] */ + {0xe38994, 0xa8c4}, /* U+3254 CIRCLED NUMBER TWENTY FOUR [2000] [Unicode3.2] */ + {0xe38995, 0xa8c5}, /* U+3255 CIRCLED NUMBER TWENTY FIVE [2000] [Unicode3.2] */ + {0xe38996, 0xa8c6}, /* U+3256 CIRCLED NUMBER TWENTY SIX [2000] [Unicode3.2] */ + {0xe38997, 0xa8c7}, /* U+3257 CIRCLED NUMBER TWENTY SEVEN [2000] [Unicode3.2] */ + {0xe38998, 0xa8c8}, /* U+3258 CIRCLED NUMBER TWENTY EIGHT [2000] [Unicode3.2] */ + {0xe38999, 0xa8c9}, /* U+3259 CIRCLED NUMBER TWENTY NINE [2000] [Unicode3.2] */ + {0xe3899a, 0xa8ca}, /* U+325A CIRCLED NUMBER THIRTY [2000] [Unicode3.2] */ + {0xe3899b, 0xa8cb}, /* U+325B CIRCLED NUMBER THIRTY ONE [2000] [Unicode3.2] */ + {0xe3899c, 0xa8cc}, /* U+325C CIRCLED NUMBER THIRTY TWO [2000] [Unicode3.2] */ + {0xe3899d, 0xa8cd}, /* U+325D CIRCLED NUMBER THIRTY THREE [2000] [Unicode3.2] */ + {0xe3899e, 0xa8ce}, /* U+325E CIRCLED NUMBER THIRTY FOUR [2000] [Unicode3.2] */ + {0xe3899f, 0xa8cf}, /* U+325F CIRCLED NUMBER THIRTY FIVE [2000] [Unicode3.2] */ + {0xe38aa4, 0xade5}, /* U+32A4 CIRCLED IDEOGRAPH HIGH [2000] */ + {0xe38aa5, 0xade6}, /* U+32A5 CIRCLED IDEOGRAPH CENTRE [2000] */ + {0xe38aa6, 0xade7}, /* U+32A6 CIRCLED IDEOGRAPH LOW [2000] */ + {0xe38aa7, 0xade8}, /* U+32A7 CIRCLED IDEOGRAPH LEFT [2000] */ + {0xe38aa8, 0xade9}, /* U+32A8 CIRCLED IDEOGRAPH RIGHT [2000] */ + {0xe38ab1, 0xa8d0}, /* U+32B1 CIRCLED NUMBER THIRTY SIX [2000] [Unicode3.2] */ + {0xe38ab2, 0xa8d1}, /* U+32B2 CIRCLED NUMBER THIRTY SEVEN [2000] [Unicode3.2] */ + {0xe38ab3, 0xa8d2}, /* U+32B3 CIRCLED NUMBER THIRTY EIGHT [2000] [Unicode3.2] */ + {0xe38ab4, 0xa8d3}, /* U+32B4 CIRCLED NUMBER THIRTY NINE [2000] [Unicode3.2] */ + {0xe38ab5, 0xa8d4}, /* U+32B5 CIRCLED NUMBER FORTY [2000] [Unicode3.2] */ + {0xe38ab6, 0xa8d5}, /* U+32B6 CIRCLED NUMBER FORTY ONE [2000] [Unicode3.2] */ + {0xe38ab7, 0xa8d6}, /* U+32B7 CIRCLED NUMBER FORTY TWO [2000] [Unicode3.2] */ + {0xe38ab8, 0xa8d7}, /* U+32B8 CIRCLED NUMBER FORTY THREE [2000] [Unicode3.2] */ + {0xe38ab9, 0xa8d8}, /* U+32B9 CIRCLED NUMBER FORTY FOUR [2000] [Unicode3.2] */ + {0xe38aba, 0xa8d9}, /* U+32BA CIRCLED NUMBER FORTY FIVE [2000] [Unicode3.2] */ + {0xe38abb, 0xa8da}, /* U+32BB CIRCLED NUMBER FORTY SIX [2000] [Unicode3.2] */ + {0xe38abc, 0xa8db}, /* U+32BC CIRCLED NUMBER FORTY SEVEN [2000] [Unicode3.2] */ + {0xe38abd, 0xa8dc}, /* U+32BD CIRCLED NUMBER FORTY EIGHT [2000] [Unicode3.2] */ + {0xe38abe, 0xa8dd}, /* U+32BE CIRCLED NUMBER FORTY NINE [2000] [Unicode3.2] */ + {0xe38abf, 0xa8de}, /* U+32BF CIRCLED NUMBER FIFTY [2000] [Unicode3.2] */ + {0xe38b90, 0xacdb}, /* U+32D0 CIRCLED KATAKANA A [2000] */ + {0xe38b91, 0xacdc}, /* U+32D1 CIRCLED KATAKANA I [2000] */ + {0xe38b92, 0xacdd}, /* U+32D2 CIRCLED KATAKANA U [2000] */ + {0xe38b93, 0xacde}, /* U+32D3 CIRCLED KATAKANA E [2000] */ + {0xe38b94, 0xacdf}, /* U+32D4 CIRCLED KATAKANA O [2000] */ + {0xe38b95, 0xace0}, /* U+32D5 CIRCLED KATAKANA KA [2000] */ + {0xe38b96, 0xace1}, /* U+32D6 CIRCLED KATAKANA KI [2000] */ + {0xe38b97, 0xace2}, /* U+32D7 CIRCLED KATAKANA KU [2000] */ + {0xe38b98, 0xace3}, /* U+32D8 CIRCLED KATAKANA KE [2000] */ + {0xe38b99, 0xace4}, /* U+32D9 CIRCLED KATAKANA KO [2000] */ + {0xe38b9a, 0xace5}, /* U+32DA CIRCLED KATAKANA SA [2000] */ + {0xe38b9b, 0xace6}, /* U+32DB CIRCLED KATAKANA SI [2000] */ + {0xe38b9c, 0xace7}, /* U+32DC CIRCLED KATAKANA SU [2000] */ + {0xe38b9d, 0xace8}, /* U+32DD CIRCLED KATAKANA SE [2000] */ + {0xe38b9e, 0xace9}, /* U+32DE CIRCLED KATAKANA SO [2000] */ + {0xe38b9f, 0xacea}, /* U+32DF CIRCLED KATAKANA TA [2000] */ + {0xe38ba0, 0xaceb}, /* U+32E0 CIRCLED KATAKANA TI [2000] */ + {0xe38ba1, 0xacec}, /* U+32E1 CIRCLED KATAKANA TU [2000] */ + {0xe38ba2, 0xaced}, /* U+32E2 CIRCLED KATAKANA TE [2000] */ + {0xe38ba3, 0xacee}, /* U+32E3 CIRCLED KATAKANA TO [2000] */ + {0xe38ba5, 0xacf1}, /* U+32E5 CIRCLED KATAKANA NI [2000] */ + {0xe38ba9, 0xacf0}, /* U+32E9 CIRCLED KATAKANA HA [2000] */ + {0xe38bac, 0xacf3}, /* U+32EC CIRCLED KATAKANA HE [2000] */ + {0xe38bad, 0xacf2}, /* U+32ED CIRCLED KATAKANA HO [2000] */ + {0xe38bba, 0xacef}, /* U+32FA CIRCLED KATAKANA RO [2000] */ + {0xe38c83, 0xadc6}, /* U+3303 SQUARE AARU [2000] */ + {0xe38c8d, 0xadca}, /* U+330D SQUARE KARORII [2000] */ + {0xe38c94, 0xadc1}, /* U+3314 SQUARE KIRO [2000] */ + {0xe38c98, 0xadc4}, /* U+3318 SQUARE GURAMU [2000] */ + {0xe38ca2, 0xadc2}, /* U+3322 SQUARE SENTI [2000] */ + {0xe38ca3, 0xadcc}, /* U+3323 SQUARE SENTO [2000] */ + {0xe38ca6, 0xadcb}, /* U+3326 SQUARE DORU [2000] */ + {0xe38ca7, 0xadc5}, /* U+3327 SQUARE TON [2000] */ + {0xe38cab, 0xadcd}, /* U+332B SQUARE PAASENTO [2000] */ + {0xe38cb6, 0xadc7}, /* U+3336 SQUARE HEKUTAARU [2000] */ + {0xe38cbb, 0xadcf}, /* U+333B SQUARE PEEZI [2000] */ + {0xe38d89, 0xadc0}, /* U+3349 SQUARE MIRI [2000] */ + {0xe38d8a, 0xadce}, /* U+334A SQUARE MIRIBAARU [2000] */ + {0xe38d8d, 0xadc3}, /* U+334D SQUARE MEETORU [2000] */ + {0xe38d91, 0xadc8}, /* U+3351 SQUARE RITTORU [2000] */ + {0xe38d97, 0xadc9}, /* U+3357 SQUARE WATTO [2000] */ + {0xe38dbb, 0xaddf}, /* U+337B SQUARE ERA NAME HEISEI [2000] */ + {0xe38dbc, 0xadef}, /* U+337C SQUARE ERA NAME SYOUWA [2000] */ + {0xe38dbd, 0xadee}, /* U+337D SQUARE ERA NAME TAISYOU [2000] */ + {0xe38dbe, 0xaded}, /* U+337E SQUARE ERA NAME MEIZI [2000] */ + {0xe38e8e, 0xadd3}, /* U+338E SQUARE MG [2000] */ + {0xe38e8f, 0xadd4}, /* U+338F SQUARE KG [2000] */ + {0xe38e9c, 0xadd0}, /* U+339C SQUARE MM [2000] */ + {0xe38e9d, 0xadd1}, /* U+339D SQUARE CM [2000] */ + {0xe38e9e, 0xadd2}, /* U+339E SQUARE KM [2000] */ + {0xe38ea1, 0xadd6}, /* U+33A1 SQUARE M SQUARED [2000] */ + {0xe38f84, 0xadd5}, /* U+33C4 SQUARE CC [2000] */ + {0xe38f8b, 0xa3de}, /* U+33CB SQUARE HP [2000] */ + {0xe38f8d, 0xade3}, /* U+33CD SQUARE KK [2000] */ + {0xe39082, 0xaea3}, /* U+3402 [2000] */ + {0xe39086, 0x8fa1ad}, /* U+3406 [2000] */ + {0xe390ac, 0x8fa1b2}, /* U+342C [2000] */ + {0xe390ae, 0x8fa1b3}, /* U+342E [2000] */ + {0xe391a8, 0x8fa1de}, /* U+3468 [2000] */ + {0xe391aa, 0x8fa1d6}, /* U+346A [2000] */ + {0xe39292, 0x8fa1fe}, /* U+3492 [2000] */ + {0xe392b5, 0xaed3}, /* U+34B5 [2000] */ + {0xe392bc, 0x8fa3ab}, /* U+34BC [2000] */ + {0xe39381, 0x8ff4e8}, /* U+34C1 [2000] */ + {0xe39387, 0x8fa3af}, /* U+34C7 [2000] */ + {0xe3939b, 0xaedb}, /* U+34DB [2000] */ + {0xe3949f, 0x8fa3c8}, /* U+351F [2000] */ + {0xe3959d, 0x8fa3dd}, /* U+355D [2000] */ + {0xe3959e, 0x8fa3de}, /* U+355E [2000] */ + {0xe395a3, 0x8fa3e1}, /* U+3563 [2000] */ + {0xe395ae, 0x8fa3e7}, /* U+356E [2000] */ + {0xe396a6, 0x8fa4a3}, /* U+35A6 [2000] */ + {0xe396a8, 0x8fa4a6}, /* U+35A8 [2000] */ + {0xe39785, 0x8fa4af}, /* U+35C5 [2000] */ + {0xe3979a, 0x8fa4b8}, /* U+35DA [2000] */ + {0xe397b4, 0x8fa4c2}, /* U+35F4 [2000] */ + {0xe39885, 0x8fa4ca}, /* U+3605 [2000] */ + {0xe3998a, 0x8fa4f9}, /* U+364A [2000] */ + {0xe39a91, 0x8fa5bf}, /* U+3691 [2000] */ + {0xe39a96, 0x8fa5c3}, /* U+3696 [2000] */ + {0xe39a99, 0x8fa5c1}, /* U+3699 [2000] */ + {0xe39b8f, 0x8fa5d7}, /* U+36CF [2000] */ + {0xe39da1, 0x8fa8a3}, /* U+3761 [2000] */ + {0xe39da2, 0x8fa8a5}, /* U+3762 [2000] */ + {0xe39dab, 0x8fa8a9}, /* U+376B [2000] */ + {0xe39dac, 0x8fa8a8}, /* U+376C [2000] */ + {0xe39db5, 0x8fa8ac}, /* U+3775 [2000] */ + {0xe39e8d, 0xcfdf}, /* U+378D [2000] */ + {0xe39f81, 0x8fa8be}, /* U+37C1 [2000] */ + {0xe39fa2, 0xcfef}, /* U+37E2 [2000] */ + {0xe39fa8, 0x8fa8d6}, /* U+37E8 [2000] */ + {0xe39fb4, 0x8fa8d9}, /* U+37F4 [2000] */ + {0xe39fbd, 0x8fa8dc}, /* U+37FD [2000] */ + {0xe3a080, 0x8fa8de}, /* U+3800 [2000] */ + {0xe3a0af, 0x8fa8ef}, /* U+382F [2000] */ + {0xe3a0b6, 0x8fa8f1}, /* U+3836 [2000] */ + {0xe3a180, 0x8fa8f4}, /* U+3840 [2000] */ + {0xe3a19c, 0x8fa8f9}, /* U+385C [2000] */ + {0xe3a1a1, 0x8fa8fb}, /* U+3861 [2000] */ + {0xe3a3ba, 0x8facbb}, /* U+38FA [2000] */ + {0xe3a497, 0x8facc6}, /* U+3917 [2000] */ + {0xe3a49a, 0x8facca}, /* U+391A [2000] */ + {0xe3a5af, 0x8face0}, /* U+396F [2000] */ + {0xe3a9ae, 0x8faddb}, /* U+3A6E [2000] */ + {0xe3a9b3, 0x8faddf}, /* U+3A73 [2000] */ + {0xe3ab96, 0x8fadf1}, /* U+3AD6 [2000] */ + {0xe3ab97, 0x8faeb6}, /* U+3AD7 [2000] */ + {0xe3abaa, 0x8fadfc}, /* U+3AEA [2000] */ + {0xe3ac8e, 0x8faeae}, /* U+3B0E [2000] */ + {0xe3ac9a, 0x8faeb2}, /* U+3B1A [2000] */ + {0xe3ac9c, 0x8faeb4}, /* U+3B1C [2000] */ + {0xe3aca2, 0xf5c9}, /* U+3B22 [2000] */ + {0xe3adad, 0x8faeed}, /* U+3B6D [2000] */ + {0xe3adb7, 0x8faee5}, /* U+3B77 [2000] */ + {0xe3ae87, 0x8fafa8}, /* U+3B87 [2000] */ + {0xe3ae88, 0x8fafa9}, /* U+3B88 [2000] */ + {0xe3ae8d, 0x8fafac}, /* U+3B8D [2000] */ + {0xe3aea4, 0x8fafb4}, /* U+3BA4 [2000] */ + {0xe3aeb6, 0xf5fe}, /* U+3BB6 [2000] */ + {0xe3af83, 0xf6a1}, /* U+3BC3 [2000] */ + {0xe3af8d, 0x8fafc8}, /* U+3BCD [2000] */ + {0xe3afb0, 0x8fafdd}, /* U+3BF0 [2000] */ + {0xe3b08f, 0xf6ba}, /* U+3C0F [2000] */ + {0xe3b0a6, 0x8faff7}, /* U+3C26 [2000] */ + {0xe3b383, 0x8feebb}, /* U+3CC3 [2000] */ + {0xe3b392, 0x8feec2}, /* U+3CD2 [2000] */ + {0xe3b491, 0x8feef1}, /* U+3D11 [2000] */ + {0xe3b49e, 0x8feefe}, /* U+3D1E [2000] */ + {0xe3b5a4, 0x8fefc0}, /* U+3D64 [2000] */ + {0xe3b69a, 0x8fefd4}, /* U+3D9A [2000] */ + {0xe3b780, 0x8feff0}, /* U+3DC0 [2000] */ + {0xe3b794, 0x8feff7}, /* U+3DD4 [2000] */ + {0xe3b885, 0x8ff0a8}, /* U+3E05 [2000] */ + {0xe3b8bf, 0xf7e6}, /* U+3E3F [2000] */ + {0xe3b9a0, 0x8ff0bf}, /* U+3E60 [2000] */ + {0xe3b9a6, 0x8ff0c1}, /* U+3E66 [2000] */ + {0xe3b9a8, 0x8ff0c2}, /* U+3E68 [2000] */ + {0xe3ba83, 0x8ff0c9}, /* U+3E83 [2000] */ + {0xe3ba94, 0x8ff0d0}, /* U+3E94 [2000] */ + {0xe3bd97, 0x8ff1b4}, /* U+3F57 [2000] */ + {0xe3bdb2, 0xf8cd}, /* U+3F72 [2000] */ + {0xe3bdb5, 0x8ff1c6}, /* U+3F75 [2000] */ + {0xe3bdb7, 0x8ff1c8}, /* U+3F77 [2000] */ + {0xe3beae, 0x8ff1dc}, /* U+3FAE [2000] */ + {0xe3bf89, 0x8ff1e7}, /* U+3FC9 [2000] */ + {0xe3bf97, 0x8ff1ec}, /* U+3FD7 [2000] */ + {0xe480b9, 0x8ff2a2}, /* U+4039 [2000] */ + {0xe48198, 0x8ff2ad}, /* U+4058 [2000] */ + {0xe48293, 0x8ff2b9}, /* U+4093 [2000] */ + {0xe48485, 0x8ff2e4}, /* U+4105 [2000] */ + {0xe48588, 0x8ff2f4}, /* U+4148 [2000] */ + {0xe4858f, 0x8ff2f7}, /* U+414F [2000] */ + {0xe485a3, 0x8ff2fd}, /* U+4163 [2000] */ + {0xe486b4, 0x8ff3b3}, /* U+41B4 [2000] */ + {0xe486bf, 0x8ff3b7}, /* U+41BF [2000] */ + {0xe487a6, 0x8ff3c7}, /* U+41E6 [2000] */ + {0xe487ae, 0x8ff3cb}, /* U+41EE [2000] */ + {0xe487b3, 0x8ff3c8}, /* U+41F3 [2000] */ + {0xe48887, 0x8ff3d3}, /* U+4207 [2000] */ + {0xe4888e, 0x8ff3d7}, /* U+420E [2000] */ + {0xe489a4, 0xf9ed}, /* U+4264 [2000] */ + {0xe48b86, 0x8ff4ab}, /* U+42C6 [2000] */ + {0xe48b96, 0x8ff4b6}, /* U+42D6 [2000] */ + {0xe48b9d, 0x8ff4bb}, /* U+42DD [2000] */ + {0xe48c82, 0x8ff4ce}, /* U+4302 [2000] */ + {0xe48cab, 0x8ff4dd}, /* U+432B [2000] */ + {0xe48d83, 0x8ff4e1}, /* U+4343 [2000] */ + {0xe48fae, 0x8ff5be}, /* U+43EE [2000] */ + {0xe48fb0, 0x8ff5c2}, /* U+43F0 [2000] */ + {0xe49088, 0x8ff5c8}, /* U+4408 [2000] */ + {0xe49097, 0x8ff5ca}, /* U+4417 [2000] */ + {0xe4909c, 0x8ff5cc}, /* U+441C [2000] */ + {0xe490a2, 0x8ff5cf}, /* U+4422 [2000] */ + {0xe49193, 0xfad9}, /* U+4453 [2000] */ + {0xe4919b, 0xfada}, /* U+445B [2000] */ + {0xe491b6, 0x8ff5ec}, /* U+4476 [2000] */ + {0xe491ba, 0x8ff5ee}, /* U+447A [2000] */ + {0xe49291, 0x8ff5f7}, /* U+4491 [2000] */ + {0xe492b3, 0x8ff6b5}, /* U+44B3 [2000] */ + {0xe492be, 0x8ff6b2}, /* U+44BE [2000] */ + {0xe49394, 0x8ff6b4}, /* U+44D4 [2000] */ + {0xe49488, 0x8ff6d9}, /* U+4508 [2000] */ + {0xe4948d, 0x8ff6d4}, /* U+450D [2000] */ + {0xe494a5, 0x8ff6ed}, /* U+4525 [2000] */ + {0xe49583, 0x8ff6ee}, /* U+4543 [2000] */ + {0xe4969d, 0xfbd1}, /* U+459D [2000] */ + {0xe496b8, 0x8ff7cf}, /* U+45B8 [2000] */ + {0xe497a5, 0x8ff7ec}, /* U+45E5 [2000] */ + {0xe497aa, 0xfbe0}, /* U+45EA [2000] */ + {0xe4988f, 0x8ff8a4}, /* U+460F [2000] */ + {0xe49981, 0x8ff8ba}, /* U+4641 [2000] */ + {0xe499a5, 0x8ff8c3}, /* U+4665 [2000] */ + {0xe49aa1, 0x8ff8ce}, /* U+46A1 [2000] */ + {0xe49aaf, 0x8ff8d3}, /* U+46AF [2000] */ + {0xe49c8c, 0x8ff8eb}, /* U+470C [2000] */ + {0xe49da4, 0x8ff9a9}, /* U+4764 [2000] */ + {0xe49fbd, 0x8ff9bf}, /* U+47FD [2000] */ + {0xe4a096, 0x8ff9c9}, /* U+4816 [2000] */ + {0xe4a184, 0xfccb}, /* U+4844 [2000] */ + {0xe4a18e, 0x8ff9dc}, /* U+484E [2000] */ + {0xe4a2b5, 0x8ffaa7}, /* U+48B5 [2000] */ + {0xe4a6b0, 0xfdd8}, /* U+49B0 [2000] */ + {0xe4a7a7, 0x8ffbea}, /* U+49E7 [2000] */ + {0xe4a7ba, 0x8ffbf0}, /* U+49FA [2000] */ + {0xe4a884, 0x8ffbf5}, /* U+4A04 [2000] */ + {0xe4a8a9, 0x8ffbf8}, /* U+4A29 [2000] */ + {0xe4aabc, 0x8ffcb7}, /* U+4ABC [2000] */ + {0xe4acbb, 0x8ffcd5}, /* U+4B3B [2000] */ + {0xe4af82, 0x8ffda6}, /* U+4BC2 [2000] */ + {0xe4af8a, 0x8ffda8}, /* U+4BCA [2000] */ + {0xe4af92, 0x8ffdaa}, /* U+4BD2 [2000] */ + {0xe4afa8, 0x8ffdb1}, /* U+4BE8 [2000] */ + {0xe4b097, 0xfebe}, /* U+4C17 [2000] */ + {0xe4b0a0, 0x8ffdbf}, /* U+4C20 [2000] */ + {0xe4b384, 0x8ffeaa}, /* U+4CC4 [2000] */ + {0xe4b391, 0x8ffead}, /* U+4CD1 [2000] */ + {0xe4b487, 0x8ffecb}, /* U+4D07 [2000] */ + {0xe4b5b7, 0x8ffee0}, /* U+4D77 [2000] */ + {0xe4b880, 0xb0ec}, /* U+4E00 */ + {0xe4b881, 0xc3fa}, /* U+4E01 */ + {0xe4b882, 0x8fa1a2}, /* U+4E02 [2000] */ + {0xe4b883, 0xbcb7}, /* U+4E03 */ + {0xe4b887, 0xcbfc}, /* U+4E07 */ + {0xe4b888, 0xbee6}, /* U+4E08 */ + {0xe4b889, 0xbbb0}, /* U+4E09 */ + {0xe4b88a, 0xbee5}, /* U+4E0A */ + {0xe4b88b, 0xb2bc}, /* U+4E0B */ + {0xe4b88d, 0xc9d4}, /* U+4E0D */ + {0xe4b88e, 0xcdbf}, /* U+4E0E */ + {0xe4b88f, 0x8fa1a3}, /* U+4E0F [2000] */ + {0xe4b890, 0xd0a2}, /* U+4E10 */ + {0xe4b891, 0xb1af}, /* U+4E11 */ + {0xe4b892, 0x8fa1a4}, /* U+4E12 [2000] */ + {0xe4b894, 0xb3ee}, /* U+4E14 */ + {0xe4b895, 0xd0a3}, /* U+4E15 */ + {0xe4b896, 0xc0a4}, /* U+4E16 */ + {0xe4b897, 0xd2c2}, /* U+4E17 */ + {0xe4b898, 0xb5d6}, /* U+4E18 */ + {0xe4b899, 0xcaba}, /* U+4E19 */ + {0xe4b89e, 0xbee7}, /* U+4E1E */ + {0xe4b8a1, 0xcebe}, /* U+4E21 */ + {0xe4b8a6, 0xcac2}, /* U+4E26 */ + {0xe4b8a8, 0xaea4}, /* U+4E28 [2000] */ + {0xe4b8a9, 0x8fa1a5}, /* U+4E29 [2000] */ + {0xe4b8aa, 0xd0a4}, /* U+4E2A */ + {0xe4b8ab, 0x8fa1a6}, /* U+4E2B [2000] */ + {0xe4b8ac, 0x8ff0ae}, /* U+4E2C [2000] */ + {0xe4b8ad, 0xc3e6}, /* U+4E2D */ + {0xe4b8ae, 0x8fa1a7}, /* U+4E2E [2000] */ + {0xe4b8af, 0xaea5}, /* U+4E2F [2000] */ + {0xe4b8b0, 0xaea6}, /* U+4E30 [2000] */ + {0xe4b8b1, 0xd0a5}, /* U+4E31 */ + {0xe4b8b2, 0xb6fa}, /* U+4E32 */ + {0xe4b8b6, 0xd0a6}, /* U+4E36 */ + {0xe4b8b8, 0xb4dd}, /* U+4E38 */ + {0xe4b8b9, 0xc3b0}, /* U+4E39 */ + {0xe4b8bb, 0xbce7}, /* U+4E3B */ + {0xe4b8bc, 0xd0a7}, /* U+4E3C */ + {0xe4b8bf, 0xd0a8}, /* U+4E3F */ + {0xe4b980, 0x8fa1a8}, /* U+4E40 [2000] */ + {0xe4b982, 0xd0a9}, /* U+4E42 */ + {0xe4b983, 0xc7b5}, /* U+4E43 */ + {0xe4b985, 0xb5d7}, /* U+4E45 */ + {0xe4b987, 0x8fa1a9}, /* U+4E47 [2000] */ + {0xe4b988, 0x8fa1aa}, /* U+4E48 [2000] */ + {0xe4b98b, 0xc7b7}, /* U+4E4B */ + {0xe4b98d, 0xc6e3}, /* U+4E4D */ + {0xe4b98e, 0xb8c3}, /* U+4E4E */ + {0xe4b98f, 0xcbb3}, /* U+4E4F */ + {0xe4b991, 0x8fa1ac}, /* U+4E51 [2000] */ + {0xe4b995, 0xe9c9}, /* U+4E55 */ + {0xe4b996, 0xd0aa}, /* U+4E56 */ + {0xe4b997, 0xbee8}, /* U+4E57 */ + {0xe4b998, 0xd0ab}, /* U+4E58 */ + {0xe4b999, 0xb2b5}, /* U+4E59 */ + {0xe4b99a, 0x8fa1af}, /* U+4E5A [2000] */ + {0xe4b99d, 0xb6e5}, /* U+4E5D */ + {0xe4b99e, 0xb8f0}, /* U+4E5E */ + {0xe4b99f, 0xcce9}, /* U+4E5F */ + {0xe4b9a2, 0xd6a6}, /* U+4E62 */ + {0xe4b9a9, 0x8fa1b0}, /* U+4E69 [2000] */ + {0xe4b9b1, 0xcdf0}, /* U+4E71 */ + {0xe4b9b3, 0xc6fd}, /* U+4E73 */ + {0xe4b9be, 0xb4a5}, /* U+4E7E */ + {0xe4ba80, 0xb5b5}, /* U+4E80 */ + {0xe4ba82, 0xd0ac}, /* U+4E82 */ + {0xe4ba85, 0xd0ad}, /* U+4E85 */ + {0xe4ba86, 0xcebb}, /* U+4E86 */ + {0xe4ba88, 0xcdbd}, /* U+4E88 */ + {0xe4ba89, 0xc1e8}, /* U+4E89 */ + {0xe4ba8a, 0xd0af}, /* U+4E8A */ + {0xe4ba8b, 0xbbf6}, /* U+4E8B */ + {0xe4ba8c, 0xc6f3}, /* U+4E8C */ + {0xe4ba8d, 0xaea7}, /* U+4E8D [2000] */ + {0xe4ba8e, 0xd0b2}, /* U+4E8E */ + {0xe4ba91, 0xb1be}, /* U+4E91 */ + {0xe4ba92, 0xb8df}, /* U+4E92 */ + {0xe4ba94, 0xb8de}, /* U+4E94 */ + {0xe4ba95, 0xb0e6}, /* U+4E95 */ + {0xe4ba98, 0xcfcb}, /* U+4E98 */ + {0xe4ba99, 0xcfca}, /* U+4E99 */ + {0xe4ba9b, 0xbab3}, /* U+4E9B */ + {0xe4ba9c, 0xb0a1}, /* U+4E9C */ + {0xe4ba9d, 0x8fa1b1}, /* U+4E9D [2000] */ + {0xe4ba9e, 0xd0b3}, /* U+4E9E */ + {0xe4ba9f, 0xd0b4}, /* U+4E9F */ + {0xe4baa0, 0xd0b5}, /* U+4EA0 */ + {0xe4baa1, 0xcbb4}, /* U+4EA1 */ + {0xe4baa2, 0xd0b6}, /* U+4EA2 */ + {0xe4baa4, 0xb8f2}, /* U+4EA4 */ + {0xe4baa5, 0xb0e7}, /* U+4EA5 */ + {0xe4baa6, 0xcbf2}, /* U+4EA6 */ + {0xe4baa8, 0xb5fc}, /* U+4EA8 */ + {0xe4baab, 0xb5fd}, /* U+4EAB */ + {0xe4baac, 0xb5fe}, /* U+4EAC */ + {0xe4baad, 0xc4e2}, /* U+4EAD */ + {0xe4baae, 0xcebc}, /* U+4EAE */ + {0xe4bab0, 0xd0b7}, /* U+4EB0 */ + {0xe4bab3, 0xd0b8}, /* U+4EB3 */ + {0xe4bab6, 0xd0b9}, /* U+4EB6 */ + {0xe4bab9, 0x8fa1b4}, /* U+4EB9 [2000] */ + {0xe4baba, 0xbfcd}, /* U+4EBA */ + {0xe4babb, 0x8fa1b5}, /* U+4EBB [2000] */ + {0xe4babc, 0x8fa1b7}, /* U+4EBC [2000] */ + {0xe4bb80, 0xbdba}, /* U+4EC0 */ + {0xe4bb81, 0xbfce}, /* U+4EC1 */ + {0xe4bb82, 0xd0be}, /* U+4EC2 */ + {0xe4bb83, 0x8fa1b8}, /* U+4EC3 [2000] */ + {0xe4bb84, 0xd0bc}, /* U+4EC4 */ + {0xe4bb86, 0xd0bd}, /* U+4EC6 */ + {0xe4bb87, 0xb5d8}, /* U+4EC7 */ + {0xe4bb88, 0x8fa1b9}, /* U+4EC8 [2000] */ + {0xe4bb8a, 0xbaa3}, /* U+4ECA */ + {0xe4bb8b, 0xb2f0}, /* U+4ECB */ + {0xe4bb8d, 0xd0bb}, /* U+4ECD */ + {0xe4bb8e, 0xd0ba}, /* U+4ECE */ + {0xe4bb8f, 0xcaa9}, /* U+4ECF */ + {0xe4bb90, 0x8fa1ba}, /* U+4ED0 [2000] */ + {0xe4bb94, 0xbbc6}, /* U+4ED4 */ + {0xe4bb95, 0xbbc5}, /* U+4ED5 */ + {0xe4bb96, 0xc2be}, /* U+4ED6 */ + {0xe4bb97, 0xd0bf}, /* U+4ED7 */ + {0xe4bb98, 0xc9d5}, /* U+4ED8 */ + {0xe4bb99, 0xc0e7}, /* U+4ED9 */ + {0xe4bb9a, 0x8fa1bc}, /* U+4EDA [2000] */ + {0xe4bb9d, 0xa1b8}, /* U+4EDD */ + {0xe4bb9e, 0xd0c0}, /* U+4EDE */ + {0xe4bb9f, 0xd0c2}, /* U+4EDF */ + {0xe4bba1, 0xaea8}, /* U+4EE1 [2000] */ + {0xe4bba3, 0xc2e5}, /* U+4EE3 */ + {0xe4bba4, 0xcee1}, /* U+4EE4 */ + {0xe4bba5, 0xb0ca}, /* U+4EE5 */ + {0xe4bbab, 0x8fa1bb}, /* U+4EEB [2000] */ + {0xe4bbad, 0xd0c1}, /* U+4EED */ + {0xe4bbae, 0xb2be}, /* U+4EEE */ + {0xe4bbb0, 0xb6c4}, /* U+4EF0 */ + {0xe4bbb1, 0x8fa1bd}, /* U+4EF1 [2000] */ + {0xe4bbb2, 0xc3e7}, /* U+4EF2 */ + {0xe4bbb5, 0x8fa1be}, /* U+4EF5 [2000] */ + {0xe4bbb6, 0xb7ef}, /* U+4EF6 */ + {0xe4bbb7, 0xd0c3}, /* U+4EF7 */ + {0xe4bbbb, 0xc7a4}, /* U+4EFB */ + {0xe4bbbd, 0xaea9}, /* U+4EFD [2000] */ + {0xe4bbbf, 0xaeaa}, /* U+4EFF [2000] */ + {0xe4bc80, 0x8fa1bf}, /* U+4F00 [2000] */ + {0xe4bc81, 0xb4eb}, /* U+4F01 */ + {0xe4bc83, 0xaeab}, /* U+4F03 [2000] */ + {0xe4bc89, 0xd0c4}, /* U+4F09 */ + {0xe4bc8a, 0xb0cb}, /* U+4F0A */ + {0xe4bc8b, 0xaeac}, /* U+4F0B [2000] */ + {0xe4bc8d, 0xb8e0}, /* U+4F0D */ + {0xe4bc8e, 0xb4ec}, /* U+4F0E */ + {0xe4bc8f, 0xc9fa}, /* U+4F0F */ + {0xe4bc90, 0xc8b2}, /* U+4F10 */ + {0xe4bc91, 0xb5d9}, /* U+4F11 */ + {0xe4bc96, 0x8fa1c0}, /* U+4F16 [2000] */ + {0xe4bc9a, 0xb2f1}, /* U+4F1A */ + {0xe4bc9c, 0xd0e7}, /* U+4F1C */ + {0xe4bc9d, 0xc5c1}, /* U+4F1D */ + {0xe4bcaf, 0xc7ec}, /* U+4F2F */ + {0xe4bcb0, 0xd0c6}, /* U+4F30 */ + {0xe4bcb4, 0xc8bc}, /* U+4F34 */ + {0xe4bcb6, 0xcee2}, /* U+4F36 */ + {0xe4bcb7, 0x8fa1c2}, /* U+4F37 [2000] */ + {0xe4bcb8, 0xbfad}, /* U+4F38 */ + {0xe4bcba, 0xbbc7}, /* U+4F3A */ + {0xe4bcbc, 0xbbf7}, /* U+4F3C */ + {0xe4bcbd, 0xb2c0}, /* U+4F3D */ + {0xe4bcbe, 0x8fa1c3}, /* U+4F3E [2000] */ + {0xe4bd83, 0xc4d1}, /* U+4F43 */ + {0xe4bd86, 0xc3a2}, /* U+4F46 */ + {0xe4bd87, 0xd0ca}, /* U+4F47 */ + {0xe4bd88, 0xaeae}, /* U+4F48 [2000] */ + {0xe4bd89, 0xaeaf}, /* U+4F49 [2000] */ + {0xe4bd8d, 0xb0cc}, /* U+4F4D */ + {0xe4bd8e, 0xc4e3}, /* U+4F4E */ + {0xe4bd8f, 0xbdbb}, /* U+4F4F */ + {0xe4bd90, 0xbab4}, /* U+4F50 */ + {0xe4bd91, 0xcda4}, /* U+4F51 */ + {0xe4bd93, 0xc2ce}, /* U+4F53 */ + {0xe4bd94, 0x8fa1c4}, /* U+4F54 [2000] */ + {0xe4bd95, 0xb2bf}, /* U+4F55 */ + {0xe4bd96, 0xaeb0}, /* U+4F56 [2000] */ + {0xe4bd97, 0xd0c9}, /* U+4F57 */ + {0xe4bd98, 0x8fa1c5}, /* U+4F58 [2000] */ + {0xe4bd99, 0xcdbe}, /* U+4F59 */ + {0xe4bd9a, 0xd0c5}, /* U+4F5A */ + {0xe4bd9b, 0xd0c7}, /* U+4F5B */ + {0xe4bd9c, 0xbaee}, /* U+4F5C */ + {0xe4bd9d, 0xd0c8}, /* U+4F5D */ + {0xe4bd9e, 0xd5a4}, /* U+4F5E */ + {0xe4bd9f, 0xaeb1}, /* U+4F5F [2000] */ + {0xe4bda0, 0xaead}, /* U+4F60 [2000] */ + {0xe4bda4, 0x8fa1c1}, /* U+4F64 [2000] */ + {0xe4bda9, 0xd0d0}, /* U+4F69 */ + {0xe4bdaa, 0xaeb2}, /* U+4F6A [2000] */ + {0xe4bdac, 0xaeb3}, /* U+4F6C [2000] */ + {0xe4bdaf, 0xd0d3}, /* U+4F6F */ + {0xe4bdb0, 0xd0d1}, /* U+4F70 */ + {0xe4bdb3, 0xb2c2}, /* U+4F73 */ + {0xe4bdb5, 0xcabb}, /* U+4F75 */ + {0xe4bdb6, 0xd0cb}, /* U+4F76 */ + {0xe4bdb7, 0x8fa1c7}, /* U+4F77 [2000] */ + {0xe4bdb8, 0x8fa1c8}, /* U+4F78 [2000] */ + {0xe4bdba, 0x8fa1c9}, /* U+4F7A [2000] */ + {0xe4bdbb, 0xd0cf}, /* U+4F7B */ + {0xe4bdbc, 0xb8f3}, /* U+4F7C */ + {0xe4bdbd, 0x8fa1ca}, /* U+4F7D [2000] */ + {0xe4bdbe, 0xaeb4}, /* U+4F7E [2000] */ + {0xe4bdbf, 0xbbc8}, /* U+4F7F */ + {0xe4be82, 0x8fa1cb}, /* U+4F82 [2000] */ + {0xe4be83, 0xb4a6}, /* U+4F83 */ + {0xe4be85, 0x8fa1cc}, /* U+4F85 [2000] */ + {0xe4be86, 0xd0d4}, /* U+4F86 */ + {0xe4be88, 0xd0cc}, /* U+4F88 */ + {0xe4be8a, 0xaeb5}, /* U+4F8A [2000] */ + {0xe4be8b, 0xcee3}, /* U+4F8B */ + {0xe4be8d, 0xbbf8}, /* U+4F8D */ + {0xe4be8f, 0xd0cd}, /* U+4F8F */ + {0xe4be91, 0xd0d2}, /* U+4F91 */ + {0xe4be92, 0x8fa1cd}, /* U+4F92 [2000] */ + {0xe4be94, 0xaeb6}, /* U+4F94 [2000] */ + {0xe4be96, 0xd0d5}, /* U+4F96 */ + {0xe4be97, 0xaeb7}, /* U+4F97 [2000] */ + {0xe4be98, 0xd0ce}, /* U+4F98 */ + {0xe4be9a, 0x8fa1ce}, /* U+4F9A [2000] */ + {0xe4be9b, 0xb6a1}, /* U+4F9B */ + {0xe4be9d, 0xb0cd}, /* U+4F9D */ + {0xe4bea0, 0xb6a2}, /* U+4FA0 */ + {0xe4bea1, 0xb2c1}, /* U+4FA1 */ + {0xe4beab, 0xd5a5}, /* U+4FAB */ + {0xe4bead, 0xcbf9}, /* U+4FAD */ + {0xe4beae, 0xc9ee}, /* U+4FAE */ + {0xe4beaf, 0xb8f4}, /* U+4FAF */ + {0xe4beb2, 0x8fa1d0}, /* U+4FB2 [2000] */ + {0xe4beb5, 0xbfaf}, /* U+4FB5 */ + {0xe4beb6, 0xceb7}, /* U+4FB6 */ + {0xe4bebe, 0x8fa1d1}, /* U+4FBE [2000] */ + {0xe4bebf, 0xcad8}, /* U+4FBF */ + {0xe4bf82, 0xb7b8}, /* U+4FC2 */ + {0xe4bf83, 0xc2a5}, /* U+4FC3 */ + {0xe4bf84, 0xb2e4}, /* U+4FC4 */ + {0xe4bf85, 0x8fa1d2}, /* U+4FC5 [2000] */ + {0xe4bf89, 0xaeb9}, /* U+4FC9 [2000] */ + {0xe4bf8a, 0xbdd3}, /* U+4FCA */ + {0xe4bf8b, 0x8fa1d3}, /* U+4FCB [2000] */ + {0xe4bf8e, 0xd0d9}, /* U+4FCE */ + {0xe4bf8f, 0x8fa1d4}, /* U+4FCF [2000] */ + {0xe4bf90, 0xd0de}, /* U+4FD0 */ + {0xe4bf91, 0xd0dc}, /* U+4FD1 */ + {0xe4bf92, 0x8fa1d5}, /* U+4FD2 [2000] */ + {0xe4bf94, 0xd0d7}, /* U+4FD4 */ + {0xe4bf97, 0xc2af}, /* U+4FD7 */ + {0xe4bf98, 0xd0da}, /* U+4FD8 */ + {0xe4bf9a, 0xd0dd}, /* U+4FDA */ + {0xe4bf9b, 0xd0db}, /* U+4FDB */ + {0xe4bf9d, 0xcadd}, /* U+4FDD */ + {0xe4bf9f, 0xd0d8}, /* U+4FDF */ + {0xe4bfa0, 0xaeba}, /* U+4FE0 [2000] */ + {0xe4bfa1, 0xbfae}, /* U+4FE1 */ + {0xe4bfa3, 0xcbf3}, /* U+4FE3 */ + {0xe4bfa4, 0xd0df}, /* U+4FE4 */ + {0xe4bfa5, 0xd0e0}, /* U+4FE5 */ + {0xe4bfa6, 0x8fa1cf}, /* U+4FE6 [2000] */ + {0xe4bfae, 0xbda4}, /* U+4FEE */ + {0xe4bfaf, 0xd0ed}, /* U+4FEF */ + {0xe4bfb1, 0xaea1}, /* U+4FF1 [2004] */ + {0xe4bfb2, 0x8fa1d7}, /* U+4FF2 [2000] */ + {0xe4bfb3, 0xc7d0}, /* U+4FF3 */ + {0xe4bfb5, 0xc9b6}, /* U+4FF5 */ + {0xe4bfb6, 0xd0e8}, /* U+4FF6 */ + {0xe4bfb8, 0xcaf0}, /* U+4FF8 */ + {0xe4bfba, 0xb2b6}, /* U+4FFA */ + {0xe4bfbe, 0xd0ec}, /* U+4FFE */ + {0xe58080, 0x8fa1d8}, /* U+5000 [2000] */ + {0xe58081, 0xaebb}, /* U+5001 [2000] */ + {0xe58082, 0xaebc}, /* U+5002 [2000] */ + {0xe58085, 0xd0e6}, /* U+5005 */ + {0xe58086, 0xd0ef}, /* U+5006 */ + {0xe58089, 0xc1d2}, /* U+5009 */ + {0xe5808b, 0xb8c4}, /* U+500B */ + {0xe5808d, 0xc7dc}, /* U+500D */ + {0xe5808e, 0xaebd}, /* U+500E [2000] */ + {0xe5808f, 0xe0c7}, /* U+500F */ + {0xe58090, 0x8fa1d9}, /* U+5010 [2000] */ + {0xe58091, 0xd0ee}, /* U+5011 */ + {0xe58092, 0xc5dd}, /* U+5012 */ + {0xe58093, 0x8fa1da}, /* U+5013 [2000] */ + {0xe58094, 0xd0e3}, /* U+5014 */ + {0xe58096, 0xb8f6}, /* U+5016 */ + {0xe58098, 0xaebe}, /* U+5018 [2000] */ + {0xe58099, 0xb8f5}, /* U+5019 */ + {0xe5809a, 0xd0e1}, /* U+501A */ + {0xe5809c, 0x8fa1db}, /* U+501C [2000] */ + {0xe5809e, 0x8fa1dc}, /* U+501E [2000] */ + {0xe5809f, 0xbcda}, /* U+501F */ + {0xe580a1, 0xd0e9}, /* U+5021 */ + {0xe580a2, 0x8fa1dd}, /* U+5022 [2000] */ + {0xe580a3, 0xcaef}, /* U+5023 */ + {0xe580a4, 0xc3cd}, /* U+5024 */ + {0xe580a5, 0xd0e5}, /* U+5025 */ + {0xe580a6, 0xb7f1}, /* U+5026 */ + {0xe580a7, 0xaebf}, /* U+5027 [2000] */ + {0xe580a8, 0xd0e2}, /* U+5028 */ + {0xe580a9, 0xd0ea}, /* U+5029 */ + {0xe580aa, 0xd0e4}, /* U+502A */ + {0xe580ab, 0xced1}, /* U+502B */ + {0xe580ac, 0xd0eb}, /* U+502C */ + {0xe580ad, 0xcfc1}, /* U+502D */ + {0xe580ae, 0xaec0}, /* U+502E [2000] */ + {0xe580b6, 0xb6e6}, /* U+5036 */ + {0xe580b9, 0xb7f0}, /* U+5039 */ + {0xe580bb, 0xaec2}, /* U+503B [2000] */ + {0xe58180, 0xaec1}, /* U+5040 [2000] */ + {0xe58181, 0xaec3}, /* U+5041 [2000] */ + {0xe58182, 0x8fa1df}, /* U+5042 [2000] */ + {0xe58183, 0xd0f0}, /* U+5043 */ + {0xe58186, 0x8fa1e0}, /* U+5046 [2000] */ + {0xe58187, 0xd0f1}, /* U+5047 */ + {0xe58188, 0xd0f5}, /* U+5048 */ + {0xe58189, 0xb0ce}, /* U+5049 */ + {0xe5818e, 0x8fa1e1}, /* U+504E [2000] */ + {0xe5818f, 0xcad0}, /* U+504F */ + {0xe58190, 0xd0f4}, /* U+5050 */ + {0xe58193, 0x8fa1e2}, /* U+5053 [2000] */ + {0xe58195, 0xd0f3}, /* U+5055 */ + {0xe58196, 0xd0f7}, /* U+5056 */ + {0xe58197, 0x8fa1e3}, /* U+5057 [2000] */ + {0xe5819a, 0xd0f6}, /* U+505A */ + {0xe5819c, 0xc4e4}, /* U+505C */ + {0xe581a3, 0x8fa1e4}, /* U+5063 [2000] */ + {0xe581a5, 0xb7f2}, /* U+5065 */ + {0xe581a6, 0x8fa1e5}, /* U+5066 [2000] */ + {0xe581aa, 0x8fa1e6}, /* U+506A [2000] */ + {0xe581ac, 0xd0f8}, /* U+506C */ + {0xe581b0, 0x8fa1e7}, /* U+5070 [2000] */ + {0xe581b2, 0xbcc5}, /* U+5072 */ + {0xe581b4, 0xc2a6}, /* U+5074 */ + {0xe581b5, 0xc4e5}, /* U+5075 */ + {0xe581b6, 0xb6f6}, /* U+5076 */ + {0xe581b8, 0xd0f9}, /* U+5078 */ + {0xe581bd, 0xb5b6}, /* U+507D */ + {0xe58280, 0xd0fa}, /* U+5080 */ + {0xe58285, 0xd0fc}, /* U+5085 */ + {0xe58288, 0x8fa1e9}, /* U+5088 [2000] */ + {0xe5828d, 0xcbb5}, /* U+508D */ + {0xe58291, 0xb7e6}, /* U+5091 */ + {0xe58292, 0x8fa1ea}, /* U+5092 [2000] */ + {0xe58293, 0x8fa1eb}, /* U+5093 [2000] */ + {0xe58294, 0xaec4}, /* U+5094 [2000] */ + {0xe58295, 0x8fa1ec}, /* U+5095 [2000] */ + {0xe58296, 0x8fa1ed}, /* U+5096 [2000] */ + {0xe58298, 0xbbb1}, /* U+5098 */ + {0xe58299, 0xc8f7}, /* U+5099 */ + {0xe5829a, 0xd0fb}, /* U+509A */ + {0xe5829c, 0x8fa1ee}, /* U+509C [2000] */ + {0xe582a3, 0x8fa1e8}, /* U+50A3 [2000] */ + {0xe582aa, 0x8fa1ef}, /* U+50AA [2000] */ + {0xe582ac, 0xbac5}, /* U+50AC */ + {0xe582ad, 0xcdc3}, /* U+50AD */ + {0xe582b1, 0x8fa1f1}, /* U+50B1 [2000] */ + {0xe582b2, 0xd0fe}, /* U+50B2 */ + {0xe582b3, 0xd1a3}, /* U+50B3 */ + {0xe582b4, 0xd0fd}, /* U+50B4 */ + {0xe582b5, 0xbac4}, /* U+50B5 */ + {0xe582b7, 0xbdfd}, /* U+50B7 */ + {0xe582ba, 0x8fa1f2}, /* U+50BA [2000] */ + {0xe582bb, 0x8fa1f3}, /* U+50BB [2000] */ + {0xe582be, 0xb7b9}, /* U+50BE */ + {0xe58382, 0xd1a4}, /* U+50C2 */ + {0xe58384, 0x8fa1f4}, /* U+50C4 [2000] */ + {0xe58385, 0xb6cf}, /* U+50C5 */ + {0xe58387, 0x8fa1f5}, /* U+50C7 [2000] */ + {0xe58389, 0xd1a1}, /* U+50C9 */ + {0xe5838a, 0xd1a2}, /* U+50CA */ + {0xe5838c, 0xaec5}, /* U+50CC [2000] */ + {0xe5838d, 0xc6af}, /* U+50CD */ + {0xe5838e, 0x8fa1f8}, /* U+50CE [2000] */ + {0xe5838f, 0xc1fc}, /* U+50CF */ + {0xe58390, 0xaec7}, /* U+50D0 [2000] */ + {0xe58391, 0xb6a3}, /* U+50D1 */ + {0xe58394, 0x8fa1fa}, /* U+50D4 [2000] */ + {0xe58395, 0xcbcd}, /* U+50D5 */ + {0xe58396, 0xd1a5}, /* U+50D6 */ + {0xe58399, 0x8fa1fb}, /* U+50D9 [2000] */ + {0xe5839a, 0xcebd}, /* U+50DA */ + {0xe5839e, 0xd1a6}, /* U+50DE */ + {0xe583a1, 0x8fa1fc}, /* U+50E1 [2000] */ + {0xe583a3, 0xd1a9}, /* U+50E3 */ + {0xe583a5, 0xd1a7}, /* U+50E5 */ + {0xe583a6, 0xaec8}, /* U+50E6 [2000] */ + {0xe583a7, 0xc1ce}, /* U+50E7 */ + {0xe583a9, 0x8fa1fd}, /* U+50E9 [2000] */ + {0xe583ad, 0xd1a8}, /* U+50ED */ + {0xe583ae, 0xd1aa}, /* U+50EE */ + {0xe583b2, 0xaec6}, /* U+50F2 [2000] */ + {0xe583b3, 0x8fa1f6}, /* U+50F3 [2000] */ + {0xe583b5, 0xd1ac}, /* U+50F5 */ + {0xe583b9, 0xd1ab}, /* U+50F9 */ + {0xe583bb, 0xcac8}, /* U+50FB */ + {0xe58480, 0xb5b7}, /* U+5100 */ + {0xe58481, 0xd1ae}, /* U+5101 */ + {0xe58482, 0xd1af}, /* U+5102 */ + {0xe58483, 0xaecb}, /* U+5103 [2000] */ + {0xe58484, 0xb2af}, /* U+5104 */ + {0xe58486, 0xaeca}, /* U+5106 [2000] */ + {0xe58488, 0x8fa3a1}, /* U+5108 [2000] */ + {0xe58489, 0xd1ad}, /* U+5109 */ + {0xe5848b, 0xaecc}, /* U+510B [2000] */ + {0xe58492, 0xbcf4}, /* U+5112 */ + {0xe58494, 0xd1b2}, /* U+5114 */ + {0xe58495, 0xd1b1}, /* U+5115 */ + {0xe58496, 0xd1b0}, /* U+5116 */ + {0xe58497, 0x8fa3a3}, /* U+5117 [2000] */ + {0xe58498, 0xd0d6}, /* U+5118 */ + {0xe5849a, 0xd1b3}, /* U+511A */ + {0xe5849b, 0x8fa3a4}, /* U+511B [2000] */ + {0xe5849e, 0xaecd}, /* U+511E [2000] */ + {0xe5849f, 0xbdfe}, /* U+511F */ + {0xe584a1, 0xd1b4}, /* U+5121 */ + {0xe584aa, 0xcda5}, /* U+512A */ + {0xe584b2, 0xccd9}, /* U+5132 */ + {0xe584b5, 0xaece}, /* U+5135 [2000] */ + {0xe584b7, 0xd1b6}, /* U+5137 */ + {0xe584ba, 0xd1b5}, /* U+513A */ + {0xe584bb, 0xd1b8}, /* U+513B */ + {0xe584bc, 0xd1b7}, /* U+513C */ + {0xe584bf, 0xd1b9}, /* U+513F */ + {0xe58580, 0xd1ba}, /* U+5140 */ + {0xe58581, 0xb0f4}, /* U+5141 */ + {0xe58583, 0xb8b5}, /* U+5143 */ + {0xe58584, 0xb7bb}, /* U+5144 */ + {0xe58585, 0xbdbc}, /* U+5145 */ + {0xe58586, 0xc3fb}, /* U+5146 */ + {0xe58587, 0xb6a4}, /* U+5147 */ + {0xe58588, 0xc0e8}, /* U+5148 */ + {0xe58589, 0xb8f7}, /* U+5149 */ + {0xe5858a, 0xaecf}, /* U+514A [2000] */ + {0xe5858b, 0xb9ee}, /* U+514B */ + {0xe5858c, 0xd1bc}, /* U+514C */ + {0xe5858d, 0xccc8}, /* U+514D */ + {0xe5858e, 0xc5c6}, /* U+514E */ + {0xe58590, 0xbbf9}, /* U+5150 */ + {0xe58592, 0xd1bb}, /* U+5152 */ + {0xe58594, 0xd1bd}, /* U+5154 */ + {0xe58595, 0xaed1}, /* U+5155 [2000] */ + {0xe58597, 0xaed2}, /* U+5157 [2000] */ + {0xe5859a, 0xc5de}, /* U+515A */ + {0xe5859c, 0xb3f5}, /* U+515C */ + {0xe585a0, 0x8fa3a6}, /* U+5160 [2000] */ + {0xe585a2, 0xd1be}, /* U+5162 */ + {0xe585a5, 0xc6fe}, /* U+5165 */ + {0xe585a8, 0xc1b4}, /* U+5168 */ + {0xe585a9, 0xd1c0}, /* U+5169 */ + {0xe585aa, 0xd1c1}, /* U+516A */ + {0xe585ab, 0xc8ac}, /* U+516B */ + {0xe585ac, 0xb8f8}, /* U+516C */ + {0xe585ad, 0xcfbb}, /* U+516D */ + {0xe585ae, 0xd1c2}, /* U+516E */ + {0xe585b1, 0xb6a6}, /* U+5171 */ + {0xe585b3, 0x8fa3a8}, /* U+5173 [2000] */ + {0xe585b5, 0xcabc}, /* U+5175 */ + {0xe585b6, 0xc2b6}, /* U+5176 */ + {0xe585b7, 0xb6f1}, /* U+5177 */ + {0xe585b8, 0xc5b5}, /* U+5178 */ + {0xe585bb, 0x8ff4f4}, /* U+517B [2000] */ + {0xe585bc, 0xb7f3}, /* U+517C */ + {0xe58680, 0xd1c3}, /* U+5180 */ + {0xe58682, 0xd1c4}, /* U+5182 */ + {0xe58683, 0x8fa3a9}, /* U+5183 [2000] */ + {0xe58685, 0xc6e2}, /* U+5185 */ + {0xe58686, 0xb1df}, /* U+5186 */ + {0xe58689, 0xd1c7}, /* U+5189 */ + {0xe5868a, 0xbafd}, /* U+518A */ + {0xe5868b, 0x8fa3aa}, /* U+518B [2000] */ + {0xe5868c, 0xd1c6}, /* U+518C */ + {0xe5868d, 0xbac6}, /* U+518D */ + {0xe5868f, 0xd1c8}, /* U+518F */ + {0xe58690, 0xe6ee}, /* U+5190 */ + {0xe58691, 0xd1c9}, /* U+5191 */ + {0xe58692, 0xcbc1}, /* U+5192 */ + {0xe58693, 0xd1ca}, /* U+5193 */ + {0xe58695, 0xd1cb}, /* U+5195 */ + {0xe58696, 0xd1cc}, /* U+5196 */ + {0xe58697, 0xbee9}, /* U+5197 */ + {0xe58698, 0x8fa3ac}, /* U+5198 [2000] */ + {0xe58699, 0xbccc}, /* U+5199 */ + {0xe5869d, 0xaed4}, /* U+519D [2000] */ + {0xe586a0, 0xb4a7}, /* U+51A0 */ + {0xe586a2, 0xd1cf}, /* U+51A2 */ + {0xe586a3, 0x8fa3ad}, /* U+51A3 [2000] */ + {0xe586a4, 0xd1cd}, /* U+51A4 */ + {0xe586a5, 0xccbd}, /* U+51A5 */ + {0xe586a6, 0xd1ce}, /* U+51A6 */ + {0xe586a8, 0xc9da}, /* U+51A8 */ + {0xe586a9, 0xd1d0}, /* U+51A9 */ + {0xe586aa, 0xd1d1}, /* U+51AA */ + {0xe586ab, 0xd1d2}, /* U+51AB */ + {0xe586ac, 0xc5df}, /* U+51AC */ + {0xe586ad, 0x8fa3ae}, /* U+51AD [2000] */ + {0xe586b0, 0xd1d6}, /* U+51B0 */ + {0xe586b1, 0xd1d4}, /* U+51B1 */ + {0xe586b2, 0xd1d5}, /* U+51B2 */ + {0xe586b3, 0xd1d3}, /* U+51B3 */ + {0xe586b4, 0xbae3}, /* U+51B4 */ + {0xe586b5, 0xd1d7}, /* U+51B5 */ + {0xe586b6, 0xccea}, /* U+51B6 */ + {0xe586b7, 0xcee4}, /* U+51B7 */ + {0xe586bc, 0x8fa3b0}, /* U+51BC [2000] */ + {0xe586bd, 0xd1d8}, /* U+51BD */ + {0xe58783, 0xaed5}, /* U+51C3 [2000] */ + {0xe58784, 0xc0a8}, /* U+51C4 */ + {0xe58785, 0xd1d9}, /* U+51C5 */ + {0xe58786, 0xbdda}, /* U+51C6 */ + {0xe58789, 0xd1da}, /* U+51C9 */ + {0xe5878a, 0xaed6}, /* U+51CA [2000] */ + {0xe5878b, 0xc3fc}, /* U+51CB */ + {0xe5878c, 0xcebf}, /* U+51CC */ + {0xe5878d, 0xc5e0}, /* U+51CD */ + {0xe58796, 0xd2c5}, /* U+51D6 */ + {0xe5879b, 0xd1db}, /* U+51DB */ + {0xe5879c, 0xf4a5}, /* U+51DC [1990] */ + {0xe5879d, 0xb6c5}, /* U+51DD */ + {0xe5879e, 0xaed7}, /* U+51DE [2000] */ + {0xe587a0, 0xd1dc}, /* U+51E0 */ + {0xe587a1, 0xcbde}, /* U+51E1 */ + {0xe587a2, 0xaed8}, /* U+51E2 [2000] */ + {0xe587a6, 0xbde8}, /* U+51E6 */ + {0xe587a7, 0xc2fc}, /* U+51E7 */ + {0xe587a9, 0xd1de}, /* U+51E9 */ + {0xe587aa, 0xc6e4}, /* U+51EA */ + {0xe587ad, 0xd1df}, /* U+51ED */ + {0xe587ae, 0xaed9}, /* U+51EE [2000] */ + {0xe587b0, 0xd1e0}, /* U+51F0 */ + {0xe587b1, 0xb3ae}, /* U+51F1 */ + {0xe587b3, 0x8fa3b3}, /* U+51F3 [2000] */ + {0xe587b4, 0x8fa3b4}, /* U+51F4 [2000] */ + {0xe587b5, 0xd1e1}, /* U+51F5 */ + {0xe587b6, 0xb6a7}, /* U+51F6 */ + {0xe587b8, 0xc6cc}, /* U+51F8 */ + {0xe587b9, 0xb1fa}, /* U+51F9 */ + {0xe587ba, 0xbdd0}, /* U+51FA */ + {0xe587bd, 0xc8a1}, /* U+51FD */ + {0xe587be, 0xd1e2}, /* U+51FE */ + {0xe58880, 0xc5e1}, /* U+5200 */ + {0xe58881, 0xaeda}, /* U+5201 [2000] */ + {0xe58882, 0x8fa3b5}, /* U+5202 [2000] */ + {0xe58883, 0xbfcf}, /* U+5203 */ + {0xe58884, 0xd1e3}, /* U+5204 */ + {0xe58886, 0xcaac}, /* U+5206 */ + {0xe58887, 0xc0da}, /* U+5207 */ + {0xe58888, 0xb4a2}, /* U+5208 */ + {0xe5888a, 0xb4a9}, /* U+520A */ + {0xe5888b, 0xd1e4}, /* U+520B */ + {0xe5888e, 0xd1e6}, /* U+520E */ + {0xe58891, 0xb7ba}, /* U+5211 */ + {0xe58892, 0x8fa3b6}, /* U+5212 [2000] */ + {0xe58893, 0xaedc}, /* U+5213 [2000] */ + {0xe58894, 0xd1e5}, /* U+5214 */ + {0xe58895, 0xaedd}, /* U+5215 [2000] */ + {0xe58896, 0x8fa3b7}, /* U+5216 [2000] */ + {0xe58897, 0xcef3}, /* U+5217 */ + {0xe5889d, 0xbde9}, /* U+521D */ + {0xe588a4, 0xc8bd}, /* U+5224 */ + {0xe588a5, 0xcacc}, /* U+5225 */ + {0xe588a7, 0xd1e7}, /* U+5227 */ + {0xe588a9, 0xcdf8}, /* U+5229 */ + {0xe588aa, 0xd1e8}, /* U+522A */ + {0xe588ae, 0xd1e9}, /* U+522E */ + {0xe588b0, 0xc5fe}, /* U+5230 */ + {0xe588b3, 0xd1ea}, /* U+5233 */ + {0xe588b6, 0xc0a9}, /* U+5236 */ + {0xe588b7, 0xbafe}, /* U+5237 */ + {0xe588b8, 0xb7f4}, /* U+5238 */ + {0xe588b9, 0xd1eb}, /* U+5239 */ + {0xe588ba, 0xbbc9}, /* U+523A */ + {0xe588bb, 0xb9ef}, /* U+523B */ + {0xe58983, 0xc4e6}, /* U+5243 */ + {0xe58984, 0xd1ed}, /* U+5244 */ + {0xe58987, 0xc2a7}, /* U+5247 */ + {0xe58989, 0xaede}, /* U+5249 [2000] */ + {0xe5898a, 0xbaef}, /* U+524A */ + {0xe5898b, 0xd1ee}, /* U+524B */ + {0xe5898c, 0xd1ef}, /* U+524C */ + {0xe5898d, 0xc1b0}, /* U+524D */ + {0xe5898f, 0xd1ec}, /* U+524F */ + {0xe58994, 0xd1f1}, /* U+5254 */ + {0xe58995, 0x8fa3b9}, /* U+5255 [2000] */ + {0xe58996, 0xcbb6}, /* U+5256 */ + {0xe58997, 0xaedf}, /* U+5257 [2000] */ + {0xe5899b, 0xb9e4}, /* U+525B */ + {0xe5899c, 0x8fa3ba}, /* U+525C [2000] */ + {0xe5899d, 0xaffe}, /* U+525D [2004] */ + {0xe5899e, 0xd1f0}, /* U+525E */ + {0xe589a1, 0xaee0}, /* U+5261 [2000] */ + {0xe589a3, 0xb7f5}, /* U+5263 */ + {0xe589a4, 0xbade}, /* U+5264 */ + {0xe589a5, 0xc7ed}, /* U+5265 */ + {0xe589a9, 0xd1f4}, /* U+5269 */ + {0xe589aa, 0xd1f2}, /* U+526A */ + {0xe589ac, 0x8fa3bb}, /* U+526C [2000] */ + {0xe589af, 0xc9fb}, /* U+526F */ + {0xe589b0, 0xbeea}, /* U+5270 */ + {0xe589b1, 0xd1fb}, /* U+5271 */ + {0xe589b2, 0xb3e4}, /* U+5272 */ + {0xe589b3, 0xd1f5}, /* U+5273 */ + {0xe589b4, 0xd1f3}, /* U+5274 */ + {0xe589b5, 0xc1cf}, /* U+5275 */ + {0xe589b7, 0x8fa3bc}, /* U+5277 [2000] */ + {0xe589bd, 0xd1f7}, /* U+527D */ + {0xe589bf, 0xd1f6}, /* U+527F */ + {0xe58a82, 0x8fa3be}, /* U+5282 [2000] */ + {0xe58a83, 0xb3c4}, /* U+5283 */ + {0xe58a84, 0x8fa3bd}, /* U+5284 [2000] */ + {0xe58a87, 0xb7e0}, /* U+5287 */ + {0xe58a88, 0xd1fc}, /* U+5288 */ + {0xe58a89, 0xcead}, /* U+5289 */ + {0xe58a8d, 0xd1f8}, /* U+528D */ + {0xe58a91, 0xd1fd}, /* U+5291 */ + {0xe58a92, 0xd1fa}, /* U+5292 */ + {0xe58a93, 0xaee1}, /* U+5293 [2000] */ + {0xe58a94, 0xd1f9}, /* U+5294 */ + {0xe58a98, 0x8fa3c0}, /* U+5298 [2000] */ + {0xe58a9b, 0xcecf}, /* U+529B */ + {0xe58a9f, 0xb8f9}, /* U+529F */ + {0xe58aa0, 0xb2c3}, /* U+52A0 */ + {0xe58aa3, 0xcef4}, /* U+52A3 */ + {0xe58aa4, 0x8fa3c2}, /* U+52A4 [2000] */ + {0xe58aa6, 0x8fa3c3}, /* U+52A6 [2000] */ + {0xe58aa9, 0xbdf5}, /* U+52A9 */ + {0xe58aaa, 0xc5d8}, /* U+52AA */ + {0xe58aab, 0xb9e5}, /* U+52AB */ + {0xe58aac, 0xd2a2}, /* U+52AC */ + {0xe58aad, 0xd2a3}, /* U+52AD */ + {0xe58aaf, 0x8fa3c4}, /* U+52AF [2000] */ + {0xe58ab1, 0xcee5}, /* U+52B1 */ + {0xe58ab4, 0xcfab}, /* U+52B4 */ + {0xe58ab5, 0xd2a5}, /* U+52B5 */ + {0xe58ab9, 0xb8fa}, /* U+52B9 */ + {0xe58aba, 0x8fa3c5}, /* U+52BA [2000] */ + {0xe58abb, 0x8fa3c6}, /* U+52BB [2000] */ + {0xe58abc, 0xd2a4}, /* U+52BC */ + {0xe58abe, 0xb3af}, /* U+52BE */ + {0xe58b81, 0xd2a6}, /* U+52C1 */ + {0xe58b83, 0xcbd6}, /* U+52C3 */ + {0xe58b85, 0xc4bc}, /* U+52C5 */ + {0xe58b87, 0xcda6}, /* U+52C7 */ + {0xe58b88, 0xaee2}, /* U+52C8 [2000] */ + {0xe58b89, 0xcad9}, /* U+52C9 */ + {0xe58b8a, 0x8fa3c7}, /* U+52CA [2000] */ + {0xe58b8c, 0xaee4}, /* U+52CC [2000] */ + {0xe58b8d, 0xd2a7}, /* U+52CD */ + {0xe58b90, 0xaee5}, /* U+52D0 [2000] */ + {0xe58b91, 0x8fa3c9}, /* U+52D1 [2000] */ + {0xe58b92, 0xf0d5}, /* U+52D2 */ + {0xe58b95, 0xc6b0}, /* U+52D5 */ + {0xe58b96, 0xaee6}, /* U+52D6 [2000] */ + {0xe58b97, 0xd2a8}, /* U+52D7 */ + {0xe58b98, 0xb4aa}, /* U+52D8 */ + {0xe58b99, 0xccb3}, /* U+52D9 */ + {0xe58b9b, 0xaee7}, /* U+52DB [2000] */ + {0xe58b9d, 0xbea1}, /* U+52DD */ + {0xe58b9e, 0xd2a9}, /* U+52DE */ + {0xe58b9f, 0xcae7}, /* U+52DF */ + {0xe58ba0, 0xd2ad}, /* U+52E0 */ + {0xe58ba2, 0xc0aa}, /* U+52E2 */ + {0xe58ba3, 0xd2aa}, /* U+52E3 */ + {0xe58ba4, 0xb6d0}, /* U+52E4 */ + {0xe58ba6, 0xd2ab}, /* U+52E6 */ + {0xe58ba7, 0xb4ab}, /* U+52E7 */ + {0xe58bb0, 0xaee9}, /* U+52F0 [2000] */ + {0xe58bb2, 0xb7ae}, /* U+52F2 */ + {0xe58bb3, 0xd2ae}, /* U+52F3 */ + {0xe58bb5, 0xd2af}, /* U+52F5 */ + {0xe58bb7, 0x8fa3cb}, /* U+52F7 [2000] */ + {0xe58bb8, 0xd2b0}, /* U+52F8 */ + {0xe58bb9, 0xd2b1}, /* U+52F9 */ + {0xe58bba, 0xbcdb}, /* U+52FA */ + {0xe58bbb, 0xaeea}, /* U+52FB [2000] */ + {0xe58bbe, 0xb8fb}, /* U+52FE */ + {0xe58bbf, 0xccde}, /* U+52FF */ + {0xe58c80, 0xaeeb}, /* U+5300 [2000] */ + {0xe58c81, 0xcce8}, /* U+5301 */ + {0xe58c82, 0xc6f7}, /* U+5302 */ + {0xe58c85, 0xcaf1}, /* U+5305 */ + {0xe58c86, 0xd2b2}, /* U+5306 */ + {0xe58c87, 0xaeec}, /* U+5307 [2000] */ + {0xe58c88, 0xd2b3}, /* U+5308 */ + {0xe58c8a, 0x8fa3cc}, /* U+530A [2000] */ + {0xe58c8b, 0x8fa3cd}, /* U+530B [2000] */ + {0xe58c8d, 0xd2b5}, /* U+530D */ + {0xe58c8f, 0xd2b7}, /* U+530F */ + {0xe58c90, 0xd2b6}, /* U+5310 */ + {0xe58c95, 0xd2b8}, /* U+5315 */ + {0xe58c96, 0xb2bd}, /* U+5316 */ + {0xe58c97, 0xcbcc}, /* U+5317 */ + {0xe58c99, 0xbafc}, /* U+5319 */ + {0xe58c9a, 0xd2b9}, /* U+531A */ + {0xe58c9c, 0xaeed}, /* U+531C [2000] */ + {0xe58c9d, 0xc1d9}, /* U+531D */ + {0xe58ca0, 0xbea2}, /* U+5320 */ + {0xe58ca1, 0xb6a9}, /* U+5321 */ + {0xe58ca3, 0xd2ba}, /* U+5323 */ + {0xe58ca4, 0x8fa3ce}, /* U+5324 [2000] */ + {0xe58caa, 0xc8db}, /* U+532A */ + {0xe58caf, 0xd2bb}, /* U+532F */ + {0xe58cb1, 0xd2bc}, /* U+5331 */ + {0xe58cb3, 0xd2bd}, /* U+5333 */ + {0xe58cb5, 0x8fa3cf}, /* U+5335 [2000] */ + {0xe58cb8, 0xd2be}, /* U+5338 */ + {0xe58cb9, 0xc9a4}, /* U+5339 */ + {0xe58cba, 0xb6e8}, /* U+533A */ + {0xe58cbb, 0xb0e5}, /* U+533B */ + {0xe58cbe, 0x8fa3d0}, /* U+533E [2000] */ + {0xe58cbf, 0xc6bf}, /* U+533F */ + {0xe58d80, 0xd2bf}, /* U+5340 */ + {0xe58d81, 0xbdbd}, /* U+5341 */ + {0xe58d82, 0x8fa3d1}, /* U+5342 [2000] */ + {0xe58d83, 0xc0e9}, /* U+5343 */ + {0xe58d85, 0xd2c1}, /* U+5345 */ + {0xe58d86, 0xd2c0}, /* U+5346 */ + {0xe58d87, 0xbea3}, /* U+5347 */ + {0xe58d88, 0xb8e1}, /* U+5348 */ + {0xe58d89, 0xd2c3}, /* U+5349 */ + {0xe58d8a, 0xc8be}, /* U+534A */ + {0xe58d8d, 0xd2c4}, /* U+534D */ + {0xe58d91, 0xc8dc}, /* U+5351 */ + {0xe58d92, 0xc2b4}, /* U+5352 */ + {0xe58d93, 0xc2ee}, /* U+5353 */ + {0xe58d94, 0xb6a8}, /* U+5354 */ + {0xe58d97, 0xc6ee}, /* U+5357 */ + {0xe58d98, 0xc3b1}, /* U+5358 */ + {0xe58d9a, 0xc7ee}, /* U+535A */ + {0xe58d9c, 0xcbce}, /* U+535C */ + {0xe58d9e, 0xd2c6}, /* U+535E */ + {0xe58da0, 0xc0ea}, /* U+5360 */ + {0xe58da1, 0xaeef}, /* U+5361 [2000] */ + {0xe58da3, 0xaef0}, /* U+5363 [2000] */ + {0xe58da6, 0xb7b5}, /* U+5366 */ + {0xe58da7, 0x8fa3d4}, /* U+5367 [2000] */ + {0xe58da9, 0xd2c7}, /* U+5369 */ + {0xe58dac, 0x8fa3d5}, /* U+536C [2000] */ + {0xe58dae, 0xd2c8}, /* U+536E */ + {0xe58daf, 0xb1ac}, /* U+536F */ + {0xe58db0, 0xb0f5}, /* U+5370 */ + {0xe58db1, 0xb4ed}, /* U+5371 */ + {0xe58db3, 0xc2a8}, /* U+5373 */ + {0xe58db4, 0xb5d1}, /* U+5374 */ + {0xe58db5, 0xcdf1}, /* U+5375 */ + {0xe58db7, 0xd2cb}, /* U+5377 */ + {0xe58db8, 0xb2b7}, /* U+5378 */ + {0xe58dba, 0x8fa3d6}, /* U+537A [2000] */ + {0xe58dbb, 0xd2ca}, /* U+537B */ + {0xe58dbd, 0xaef1}, /* U+537D [2000] */ + {0xe58dbf, 0xb6aa}, /* U+537F */ + {0xe58e82, 0xd2cc}, /* U+5382 */ + {0xe58e84, 0xccf1}, /* U+5384 */ + {0xe58e93, 0xaef2}, /* U+5393 [2000] */ + {0xe58e96, 0xd2cd}, /* U+5396 */ + {0xe58e98, 0xced2}, /* U+5398 */ + {0xe58e9a, 0xb8fc}, /* U+539A */ + {0xe58e9d, 0xaef3}, /* U+539D [2000] */ + {0xe58e9f, 0xb8b6}, /* U+539F */ + {0xe58ea0, 0xd2ce}, /* U+53A0 */ + {0xe58ea4, 0x8fa3d7}, /* U+53A4 [2000] */ + {0xe58ea5, 0xd2d0}, /* U+53A5 */ + {0xe58ea6, 0xd2cf}, /* U+53A6 */ + {0xe58ea8, 0xbfdf}, /* U+53A8 */ + {0xe58ea9, 0xb1b9}, /* U+53A9 */ + {0xe58ead, 0xb1de}, /* U+53AD */ + {0xe58eae, 0xd2d1}, /* U+53AE */ + {0xe58eb0, 0xd2d2}, /* U+53B0 */ + {0xe58eb2, 0xaef4}, /* U+53B2 [2000] */ + {0xe58eb3, 0xb8b7}, /* U+53B3 */ + {0xe58eb4, 0x8fa3d8}, /* U+53B4 [2000] */ + {0xe58eb6, 0xd2d3}, /* U+53B6 */ + {0xe58eb7, 0x8fa3da}, /* U+53B7 [2000] */ + {0xe58ebb, 0xb5ee}, /* U+53BB */ + {0xe58f80, 0x8fa3db}, /* U+53C0 [2000] */ + {0xe58f82, 0xbbb2}, /* U+53C2 */ + {0xe58f83, 0xd2d4}, /* U+53C3 */ + {0xe58f88, 0xcbf4}, /* U+53C8 */ + {0xe58f89, 0xbab5}, /* U+53C9 */ + {0xe58f8a, 0xb5da}, /* U+53CA */ + {0xe58f8b, 0xcda7}, /* U+53CB */ + {0xe58f8c, 0xc1d0}, /* U+53CC */ + {0xe58f8d, 0xc8bf}, /* U+53CD */ + {0xe58f8e, 0xbcfd}, /* U+53CE */ + {0xe58f94, 0xbdc7}, /* U+53D4 */ + {0xe58f95, 0x8fa3df}, /* U+53D5 [2000] */ + {0xe58f96, 0xbce8}, /* U+53D6 */ + {0xe58f97, 0xbcf5}, /* U+53D7 */ + {0xe58f99, 0xbdf6}, /* U+53D9 */ + {0xe58f9a, 0x8fa3e0}, /* U+53DA [2000] */ + {0xe58f9b, 0xc8c0}, /* U+53DB */ + {0xe58f9f, 0xd2d7}, /* U+53DF */ + {0xe58fa1, 0xb1c3}, /* U+53E1 */ + {0xe58fa2, 0xc1d1}, /* U+53E2 */ + {0xe58fa3, 0xb8fd}, /* U+53E3 */ + {0xe58fa4, 0xb8c5}, /* U+53E4 */ + {0xe58fa5, 0xb6e7}, /* U+53E5 */ + {0xe58fa8, 0xd2db}, /* U+53E8 */ + {0xe58fa9, 0xc3a1}, /* U+53E9 */ + {0xe58faa, 0xc2fe}, /* U+53EA */ + {0xe58fab, 0xb6ab}, /* U+53EB */ + {0xe58fac, 0xbea4}, /* U+53EC */ + {0xe58fad, 0xd2dc}, /* U+53ED */ + {0xe58fae, 0xd2da}, /* U+53EE */ + {0xe58faf, 0xb2c4}, /* U+53EF */ + {0xe58fb0, 0xc2e6}, /* U+53F0 */ + {0xe58fb1, 0xbcb8}, /* U+53F1 */ + {0xe58fb2, 0xbbcb}, /* U+53F2 */ + {0xe58fb3, 0xb1a6}, /* U+53F3 */ + {0xe58fb4, 0x8fa3e2}, /* U+53F4 [2000] */ + {0xe58fb5, 0x8fa3e3}, /* U+53F5 [2000] */ + {0xe58fb6, 0xb3f0}, /* U+53F6 */ + {0xe58fb7, 0xb9e6}, /* U+53F7 */ + {0xe58fb8, 0xbbca}, /* U+53F8 */ + {0xe58fba, 0xd2dd}, /* U+53FA */ + {0xe59081, 0xd2de}, /* U+5401 */ + {0xe59083, 0xb5c9}, /* U+5403 */ + {0xe59084, 0xb3c6}, /* U+5404 */ + {0xe59088, 0xb9e7}, /* U+5408 */ + {0xe59089, 0xb5c8}, /* U+5409 */ + {0xe5908a, 0xc4df}, /* U+540A */ + {0xe5908b, 0xb1a5}, /* U+540B */ + {0xe5908c, 0xc6b1}, /* U+540C */ + {0xe5908d, 0xccbe}, /* U+540D */ + {0xe5908e, 0xb9a1}, /* U+540E */ + {0xe5908f, 0xcdf9}, /* U+540F */ + {0xe59090, 0xc5c7}, /* U+5410 */ + {0xe59091, 0xb8fe}, /* U+5411 */ + {0xe59092, 0xaef5}, /* U+5412 [2000] */ + {0xe5909b, 0xb7af}, /* U+541B */ + {0xe5909d, 0xd2e7}, /* U+541D */ + {0xe5909e, 0xcffe}, /* U+541E [2004] */ + {0xe5909f, 0xb6e3}, /* U+541F */ + {0xe590a0, 0xcbca}, /* U+5420 */ + {0xe590a4, 0x8fa3e5}, /* U+5424 [2000] */ + {0xe590a6, 0xc8dd}, /* U+5426 */ + {0xe590a7, 0xaef6}, /* U+5427 [2000] */ + {0xe590a8, 0x8fa3e6}, /* U+5428 [2000] */ + {0xe590a9, 0xd2e6}, /* U+5429 */ + {0xe590ab, 0xb4de}, /* U+542B */ + {0xe590ac, 0xd2e1}, /* U+542C */ + {0xe590ad, 0xd2e2}, /* U+542D */ + {0xe590ae, 0xd2e4}, /* U+542E */ + {0xe590b6, 0xd2e5}, /* U+5436 */ + {0xe590b8, 0xb5db}, /* U+5438 */ + {0xe590b9, 0xbfe1}, /* U+5439 */ + {0xe590bb, 0xcaad}, /* U+543B */ + {0xe590bc, 0xd2e3}, /* U+543C */ + {0xe590bd, 0xd2df}, /* U+543D */ + {0xe590be, 0xb8e3}, /* U+543E */ + {0xe59180, 0xd2e0}, /* U+5440 */ + {0xe59182, 0xcfa4}, /* U+5442 */ + {0xe59183, 0x8fa3e8}, /* U+5443 [2000] */ + {0xe59186, 0xcaf2}, /* U+5446 */ + {0xe59188, 0xc4e8}, /* U+5448 */ + {0xe59189, 0xb8e2}, /* U+5449 */ + {0xe5918a, 0xb9f0}, /* U+544A */ + {0xe5918d, 0xaef7}, /* U+544D [2000] */ + {0xe5918e, 0xd2e8}, /* U+544E */ + {0xe59191, 0xc6dd}, /* U+5451 */ + {0xe59195, 0x8fa3e4}, /* U+5455 [2000] */ + {0xe5919f, 0xd2ec}, /* U+545F */ + {0xe591a2, 0x8fa3e9}, /* U+5462 [2000] */ + {0xe591a6, 0x8fa3ea}, /* U+5466 [2000] */ + {0xe591a8, 0xbcfe}, /* U+5468 */ + {0xe591aa, 0xbcf6}, /* U+546A */ + {0xe591ab, 0xaef9}, /* U+546B [2000] */ + {0xe591ac, 0x8fa3eb}, /* U+546C [2000] */ + {0xe591b0, 0xd2ef}, /* U+5470 */ + {0xe591b1, 0xd2ed}, /* U+5471 */ + {0xe591b3, 0xcca3}, /* U+5473 */ + {0xe591b4, 0xaefa}, /* U+5474 [2000] */ + {0xe591b5, 0xd2ea}, /* U+5475 */ + {0xe591b6, 0xd2f3}, /* U+5476 */ + {0xe591b7, 0xd2ee}, /* U+5477 */ + {0xe591bb, 0xd2f1}, /* U+547B */ + {0xe591bc, 0xb8c6}, /* U+547C */ + {0xe591bd, 0xccbf}, /* U+547D */ + {0xe591bf, 0xaefb}, /* U+547F [2000] */ + {0xe59280, 0xd2f2}, /* U+5480 */ + {0xe59284, 0xd2f4}, /* U+5484 */ + {0xe59286, 0xd2f6}, /* U+5486 */ + {0xe59288, 0xaefc}, /* U+5488 [2000] */ + {0xe5928a, 0x8fa3ec}, /* U+548A [2000] */ + {0xe5928b, 0xbaf0}, /* U+548B */ + {0xe5928c, 0xcfc2}, /* U+548C */ + {0xe5928d, 0x8fa3ed}, /* U+548D [2000] */ + {0xe5928e, 0xd2eb}, /* U+548E */ + {0xe5928f, 0xd2e9}, /* U+548F */ + {0xe59290, 0xd2f5}, /* U+5490 */ + {0xe59292, 0xd2f0}, /* U+5492 */ + {0xe59295, 0x8fa3ee}, /* U+5495 [2000] */ + {0xe59296, 0xaefd}, /* U+5496 [2000] */ + {0xe5929c, 0xaef8}, /* U+549C [2000] */ + {0xe592a0, 0x8fa3ef}, /* U+54A0 [2000] */ + {0xe592a1, 0xaefe}, /* U+54A1 [2000] */ + {0xe592a2, 0xd2f8}, /* U+54A2 */ + {0xe592a4, 0xd3a3}, /* U+54A4 */ + {0xe592a5, 0xd2fa}, /* U+54A5 */ + {0xe592a6, 0x8fa3f0}, /* U+54A6 [2000] */ + {0xe592a8, 0xd2fe}, /* U+54A8 */ + {0xe592a9, 0xafa1}, /* U+54A9 [2000] */ + {0xe592ab, 0xd3a1}, /* U+54AB */ + {0xe592ac, 0xd2fb}, /* U+54AC */ + {0xe592ad, 0x8fa3f1}, /* U+54AD [2000] */ + {0xe592ae, 0x8fa3f2}, /* U+54AE [2000] */ + {0xe592af, 0xd3be}, /* U+54AF */ + {0xe592b2, 0xbae9}, /* U+54B2 */ + {0xe592b3, 0xb3b1}, /* U+54B3 */ + {0xe592b7, 0x8fa3f3}, /* U+54B7 [2000] */ + {0xe592b8, 0xd2f9}, /* U+54B8 */ + {0xe592ba, 0x8fa3f4}, /* U+54BA [2000] */ + {0xe592bc, 0xd3a5}, /* U+54BC */ + {0xe592bd, 0xb0f6}, /* U+54BD */ + {0xe592be, 0xd3a4}, /* U+54BE */ + {0xe592bf, 0x8fa3f5}, /* U+54BF [2000] */ + {0xe59380, 0xb0a5}, /* U+54C0 */ + {0xe59381, 0xc9ca}, /* U+54C1 */ + {0xe59382, 0xd3a2}, /* U+54C2 */ + {0xe59383, 0x8fa3f6}, /* U+54C3 [2000] */ + {0xe59384, 0xd2fc}, /* U+54C4 */ + {0xe59386, 0xafa2}, /* U+54C6 [2000] */ + {0xe59387, 0xd2f7}, /* U+54C7 */ + {0xe59388, 0xd2fd}, /* U+54C8 */ + {0xe59389, 0xbac8}, /* U+54C9 */ + {0xe59398, 0xd3a6}, /* U+54D8 */ + {0xe593a1, 0xb0f7}, /* U+54E1 */ + {0xe593a2, 0xd3af}, /* U+54E2 */ + {0xe593a5, 0xd3a7}, /* U+54E5 */ + {0xe593a6, 0xd3a8}, /* U+54E6 */ + {0xe593a8, 0xbea5}, /* U+54E8 */ + {0xe593a9, 0xcbe9}, /* U+54E9 */ + {0xe593ac, 0x8fa3f8}, /* U+54EC [2000] */ + {0xe593ad, 0xd3ad}, /* U+54ED */ + {0xe593ae, 0xd3ac}, /* U+54EE */ + {0xe593af, 0x8fa3f9}, /* U+54EF [2000] */ + {0xe593b1, 0x8fa3fa}, /* U+54F1 [2000] */ + {0xe593b2, 0xc5af}, /* U+54F2 */ + {0xe593b3, 0x8fa3fb}, /* U+54F3 [2000] */ + {0xe593ba, 0xd3ae}, /* U+54FA */ + {0xe593bd, 0xd3ab}, /* U+54FD */ + {0xe593bf, 0xafa3}, /* U+54FF [2000] */ + {0xe59480, 0x8fa3fc}, /* U+5500 [2000] */ + {0xe59481, 0x8fa3fd}, /* U+5501 [2000] */ + {0xe59484, 0xb1b4}, /* U+5504 */ + {0xe59486, 0xbab6}, /* U+5506 */ + {0xe59487, 0xbfb0}, /* U+5507 */ + {0xe59489, 0x8fa3fe}, /* U+5509 [2000] */ + {0xe5948e, 0xafa4}, /* U+550E [2000] */ + {0xe5948f, 0xd3a9}, /* U+550F */ + {0xe59490, 0xc5e2}, /* U+5510 */ + {0xe59494, 0xd3aa}, /* U+5514 */ + {0xe59496, 0xb0a2}, /* U+5516 */ + {0xe594ab, 0xafa5}, /* U+552B [2000] */ + {0xe594ae, 0xd3b4}, /* U+552E */ + {0xe594af, 0xcda3}, /* U+552F */ + {0xe594b1, 0xbea7}, /* U+5531 */ + {0xe594b3, 0xd3ba}, /* U+5533 */ + {0xe594b5, 0xafa6}, /* U+5535 [2000] */ + {0xe594b8, 0xd3b9}, /* U+5538 */ + {0xe594b9, 0xd3b0}, /* U+5539 */ + {0xe594bc, 0x8fa4a1}, /* U+553C [2000] */ + {0xe594be, 0xc2c3}, /* U+553E */ + {0xe59580, 0xd3b1}, /* U+5540 */ + {0xe59581, 0x8fa4a2}, /* U+5541 [2000] */ + {0xe59584, 0xc2ef}, /* U+5544 */ + {0xe59585, 0xd3b6}, /* U+5545 */ + {0xe59586, 0xbea6}, /* U+5546 */ + {0xe59587, 0x8fa4a4}, /* U+5547 [2000] */ + {0xe5958a, 0x8fa4a5}, /* U+554A [2000] */ + {0xe5958c, 0xd3b3}, /* U+554C */ + {0xe5958f, 0xcce4}, /* U+554F */ + {0xe59590, 0xafa7}, /* U+5550 [2000] */ + {0xe59593, 0xb7bc}, /* U+5553 */ + {0xe59596, 0xd3b7}, /* U+5556 */ + {0xe59597, 0xd3b8}, /* U+5557 */ + {0xe5959c, 0xd3b5}, /* U+555C */ + {0xe5959d, 0xd3bb}, /* U+555D */ + {0xe5959e, 0xafa8}, /* U+555E [2000] */ + {0xe595a0, 0x8fa4a7}, /* U+5560 [2000] */ + {0xe595a1, 0x8fa4a8}, /* U+5561 [2000] */ + {0xe595a3, 0xd3b2}, /* U+5563 */ + {0xe595a4, 0x8fa4a9}, /* U+5564 [2000] */ + {0xe595bb, 0xd3c1}, /* U+557B */ + {0xe595bc, 0xd3c6}, /* U+557C */ + {0xe595bd, 0x8fa4ab}, /* U+557D [2000] */ + {0xe595be, 0xd3c2}, /* U+557E */ + {0xe59680, 0xd3bd}, /* U+5580 */ + {0xe59681, 0xafa9}, /* U+5581 [2000] */ + {0xe59682, 0x8fa4ac}, /* U+5582 [2000] */ + {0xe59683, 0xd3c7}, /* U+5583 */ + {0xe59684, 0xc1b1}, /* U+5584 */ + {0xe59686, 0xafaa}, /* U+5586 [2000] */ + {0xe59687, 0xd3c9}, /* U+5587 */ + {0xe59688, 0x8fa4ad}, /* U+5588 [2000] */ + {0xe59689, 0xb9a2}, /* U+5589 */ + {0xe5968a, 0xd3bf}, /* U+558A */ + {0xe5968b, 0xc3fd}, /* U+558B */ + {0xe5968e, 0xafab}, /* U+558E [2000] */ + {0xe59691, 0x8fa4ae}, /* U+5591 [2000] */ + {0xe59698, 0xd3c3}, /* U+5598 */ + {0xe59699, 0xd3bc}, /* U+5599 */ + {0xe5969a, 0xb4ad}, /* U+559A */ + {0xe5969c, 0xb4ee}, /* U+559C */ + {0xe5969d, 0xb3e5}, /* U+559D */ + {0xe5969e, 0xd3c4}, /* U+559E */ + {0xe5969f, 0xd3c0}, /* U+559F */ + {0xe596a7, 0xb7f6}, /* U+55A7 */ + {0xe596a8, 0xd3ca}, /* U+55A8 */ + {0xe596a9, 0xd3c8}, /* U+55A9 */ + {0xe596aa, 0xc1d3}, /* U+55AA */ + {0xe596ab, 0xb5ca}, /* U+55AB */ + {0xe596ac, 0xb6ac}, /* U+55AC */ + {0xe596ad, 0xafad}, /* U+55AD [2000] */ + {0xe596ae, 0xd3c5}, /* U+55AE */ + {0xe596b0, 0xb6f4}, /* U+55B0 */ + {0xe596b6, 0xb1c4}, /* U+55B6 */ + {0xe596bf, 0x8fa4b3}, /* U+55BF [2000] */ + {0xe59784, 0xd3ce}, /* U+55C4 */ + {0xe59785, 0xd3cc}, /* U+55C5 */ + {0xe59787, 0xd4a7}, /* U+55C7 */ + {0xe59789, 0x8fa4b4}, /* U+55C9 [2000] */ + {0xe5978c, 0x8fa4b5}, /* U+55CC [2000] */ + {0xe5978e, 0xafae}, /* U+55CE [2000] */ + {0xe59791, 0x8fa4b6}, /* U+55D1 [2000] */ + {0xe59792, 0x8fa4b0}, /* U+55D2 [2000] */ + {0xe59794, 0xd3d1}, /* U+55D4 */ + {0xe5979a, 0xd3cb}, /* U+55DA */ + {0xe5979c, 0xd3cf}, /* U+55DC */ + {0xe5979d, 0x8fa4b7}, /* U+55DD [2000] */ + {0xe5979f, 0xd3cd}, /* U+55DF */ + {0xe597a2, 0x8fa4b9}, /* U+55E2 [2000] */ + {0xe597a3, 0xbbcc}, /* U+55E3 */ + {0xe597a4, 0xd3d0}, /* U+55E4 */ + {0xe597a9, 0x8fa4bb}, /* U+55E9 [2000] */ + {0xe597b7, 0xd3d3}, /* U+55F7 */ + {0xe597b9, 0xd3d8}, /* U+55F9 */ + {0xe597bd, 0xd3d6}, /* U+55FD */ + {0xe597be, 0xd3d5}, /* U+55FE */ + {0xe59886, 0xc3b2}, /* U+5606 */ + {0xe59887, 0x8fa4be}, /* U+5607 [2000] */ + {0xe59888, 0xafb0}, /* U+5608 [2000] */ + {0xe59889, 0xb2c5}, /* U+5609 */ + {0xe5988e, 0xafb1}, /* U+560E [2000] */ + {0xe59890, 0x8fa4bf}, /* U+5610 [2000] */ + {0xe59894, 0xd3d2}, /* U+5614 */ + {0xe59896, 0xd3d4}, /* U+5616 */ + {0xe59897, 0xbea8}, /* U+5617 */ + {0xe59898, 0xb1b3}, /* U+5618 */ + {0xe5989b, 0xd3d7}, /* U+561B */ + {0xe598a8, 0x8fa4bc}, /* U+5628 [2000] */ + {0xe598a9, 0xb2de}, /* U+5629 */ + {0xe598af, 0xd3e2}, /* U+562F */ + {0xe598b0, 0x8fa4c0}, /* U+5630 [2000] */ + {0xe598b1, 0xbefc}, /* U+5631 */ + {0xe598b2, 0xd3de}, /* U+5632 */ + {0xe598b4, 0xd3dc}, /* U+5634 */ + {0xe598b6, 0xd3dd}, /* U+5636 */ + {0xe598b7, 0x8fa4c1}, /* U+5637 [2000] */ + {0xe598b8, 0xd3df}, /* U+5638 */ + {0xe598bb, 0xafb2}, /* U+563B [2000] */ + {0xe598bd, 0x8fa4c3}, /* U+563D [2000] */ + {0xe598bf, 0x8fa4c4}, /* U+563F [2000] */ + {0xe59980, 0x8fa4c5}, /* U+5640 [2000] */ + {0xe59982, 0xb1bd}, /* U+5642 */ + {0xe59987, 0x8fa4c6}, /* U+5647 [2000] */ + {0xe59989, 0xafb3}, /* U+5649 [2000] */ + {0xe5998c, 0xc1b9}, /* U+564C */ + {0xe5998e, 0xd3d9}, /* U+564E */ + {0xe59990, 0xd3da}, /* U+5650 */ + {0xe59993, 0xf4a7}, /* U+5653 [2004] */ + {0xe5999b, 0xb3fa}, /* U+565B */ + {0xe5999e, 0x8fa4c7}, /* U+565E [2000] */ + {0xe599a0, 0x8fa4c8}, /* U+5660 [2000] */ + {0xe599a4, 0xd3e1}, /* U+5664 */ + {0xe599a6, 0xafb5}, /* U+5666 [2000] */ + {0xe599a8, 0xb4ef}, /* U+5668 */ + {0xe599aa, 0xd3e4}, /* U+566A */ + {0xe599ab, 0xd3e0}, /* U+566B */ + {0xe599ac, 0xd3e3}, /* U+566C */ + {0xe599ad, 0x8fa4c9}, /* U+566D [2000] */ + {0xe599af, 0xafb7}, /* U+566F [2000] */ + {0xe599b1, 0xafb8}, /* U+5671 [2000] */ + {0xe599b2, 0xafb9}, /* U+5672 [2000] */ + {0xe599b4, 0xcaae}, /* U+5674 */ + {0xe599b6, 0xafb4}, /* U+5676 [2000] */ + {0xe599b8, 0xc6d5}, /* U+5678 */ + {0xe599ba, 0xc8b8}, /* U+567A */ + {0xe59a80, 0xd3e6}, /* U+5680 */ + {0xe59a86, 0xd3e5}, /* U+5686 */ + {0xe59a87, 0xb3c5}, /* U+5687 */ + {0xe59a88, 0x8fa4cb}, /* U+5688 [2000] */ + {0xe59a8a, 0xd3e7}, /* U+568A */ + {0xe59a8c, 0x8fa4cc}, /* U+568C [2000] */ + {0xe59a8f, 0xd3ea}, /* U+568F */ + {0xe59a94, 0xd3e9}, /* U+5694 */ + {0xe59a95, 0x8fa4cd}, /* U+5695 [2000] */ + {0xe59a99, 0xafba}, /* U+5699 [2000] */ + {0xe59a9a, 0x8fa4ce}, /* U+569A [2000] */ + {0xe59a9d, 0x8fa4cf}, /* U+569D [2000] */ + {0xe59a9e, 0xafbb}, /* U+569E [2000] */ + {0xe59aa0, 0xd3e8}, /* U+56A0 */ + {0xe59aa2, 0xc7b9}, /* U+56A2 */ + {0xe59aa5, 0xd3eb}, /* U+56A5 */ + {0xe59aa8, 0x8fa4d0}, /* U+56A8 [2000] */ + {0xe59aa9, 0xafbc}, /* U+56A9 [2000] */ + {0xe59aac, 0xafbd}, /* U+56AC [2000] */ + {0xe59aad, 0x8fa4d1}, /* U+56AD [2000] */ + {0xe59aae, 0xd3ec}, /* U+56AE */ + {0xe59ab2, 0x8fa4d2}, /* U+56B2 [2000] */ + {0xe59ab3, 0xafbe}, /* U+56B3 [2000] */ + {0xe59ab4, 0xd3ee}, /* U+56B4 */ + {0xe59ab6, 0xd3ed}, /* U+56B6 */ + {0xe59abc, 0xd3f0}, /* U+56BC */ + {0xe59b80, 0xd3f3}, /* U+56C0 */ + {0xe59b81, 0xd3f1}, /* U+56C1 */ + {0xe59b82, 0xd3ef}, /* U+56C2 */ + {0xe59b83, 0xd3f2}, /* U+56C3 */ + {0xe59b85, 0x8fa4d3}, /* U+56C5 [2000] */ + {0xe59b88, 0xd3f4}, /* U+56C8 */ + {0xe59b89, 0xafbf}, /* U+56C9 [2000] */ + {0xe59b8a, 0xafc0}, /* U+56CA [2000] */ + {0xe59b8d, 0x8fa4d4}, /* U+56CD [2000] */ + {0xe59b8e, 0xd3f5}, /* U+56CE */ + {0xe59b91, 0xd3f6}, /* U+56D1 */ + {0xe59b93, 0xd3f7}, /* U+56D3 */ + {0xe59b97, 0xd3f8}, /* U+56D7 */ + {0xe59b98, 0xd1c5}, /* U+56D8 */ + {0xe59b9a, 0xbcfc}, /* U+56DA */ + {0xe59b9b, 0xbbcd}, /* U+56DB */ + {0xe59b9e, 0xb2f3}, /* U+56DE */ + {0xe59b9f, 0x8fa4d5}, /* U+56DF [2000] */ + {0xe59ba0, 0xb0f8}, /* U+56E0 */ + {0xe59ba3, 0xc3c4}, /* U+56E3 */ + {0xe59ba8, 0x8fa4d6}, /* U+56E8 [2000] */ + {0xe59bae, 0xd3f9}, /* U+56EE */ + {0xe59bb0, 0xbaa4}, /* U+56F0 */ + {0xe59bb2, 0xb0cf}, /* U+56F2 */ + {0xe59bb3, 0xbfde}, /* U+56F3 */ + {0xe59bb6, 0x8fa4d7}, /* U+56F6 [2000] */ + {0xe59bb7, 0x8fa4d8}, /* U+56F7 [2000] */ + {0xe59bb9, 0xd3fa}, /* U+56F9 */ + {0xe59bba, 0xb8c7}, /* U+56FA */ + {0xe59bbd, 0xb9f1}, /* U+56FD */ + {0xe59bbf, 0xd3fc}, /* U+56FF */ + {0xe59c80, 0xd3fb}, /* U+5700 */ + {0xe59c83, 0xcae0}, /* U+5703 */ + {0xe59c84, 0xd3fd}, /* U+5704 */ + {0xe59c88, 0xd4a1}, /* U+5708 */ + {0xe59c89, 0xd3fe}, /* U+5709 */ + {0xe59c8a, 0xafc1}, /* U+570A [2000] */ + {0xe59c8b, 0xd4a2}, /* U+570B */ + {0xe59c8d, 0xd4a3}, /* U+570D */ + {0xe59c8f, 0xb7f7}, /* U+570F */ + {0xe59c92, 0xb1e0}, /* U+5712 */ + {0xe59c93, 0xd4a4}, /* U+5713 */ + {0xe59c95, 0x8fa4da}, /* U+5715 [2000] */ + {0xe59c96, 0xd4a6}, /* U+5716 */ + {0xe59c98, 0xd4a5}, /* U+5718 */ + {0xe59c9c, 0xd4a8}, /* U+571C */ + {0xe59c9f, 0xc5da}, /* U+571F */ + {0xe59ca1, 0xafc3}, /* U+5721 [2000] */ + {0xe59ca3, 0x8fa4db}, /* U+5723 [2000] */ + {0xe59ca6, 0xd4a9}, /* U+5726 */ + {0xe59ca7, 0xb0b5}, /* U+5727 */ + {0xe59ca8, 0xbadf}, /* U+5728 */ + {0xe59ca9, 0x8fa4dd}, /* U+5729 [2000] */ + {0xe59cad, 0xb7bd}, /* U+572D */ + {0xe59caf, 0xafc4}, /* U+572F [2000] */ + {0xe59cb0, 0xc3cf}, /* U+5730 */ + {0xe59cb3, 0xafc5}, /* U+5733 [2000] */ + {0xe59cb4, 0xafc6}, /* U+5734 [2000] */ + {0xe59cb7, 0xd4aa}, /* U+5737 */ + {0xe59cb8, 0xd4ab}, /* U+5738 */ + {0xe59cbb, 0xd4ad}, /* U+573B */ + {0xe59d80, 0xd4ae}, /* U+5740 */ + {0xe59d82, 0xbae4}, /* U+5742 */ + {0xe59d85, 0x8fa4df}, /* U+5745 [2000] */ + {0xe59d86, 0x8fa4e0}, /* U+5746 [2000] */ + {0xe59d87, 0xb6d1}, /* U+5747 */ + {0xe59d8a, 0xcbb7}, /* U+574A */ + {0xe59d8c, 0x8fa4e1}, /* U+574C [2000] */ + {0xe59d8d, 0x8fa4e2}, /* U+574D [2000] */ + {0xe59d8e, 0xd4ac}, /* U+574E */ + {0xe59d8f, 0xd4af}, /* U+574F */ + {0xe59d90, 0xbac1}, /* U+5750 */ + {0xe59d91, 0xb9a3}, /* U+5751 */ + {0xe59da1, 0xd4b3}, /* U+5761 */ + {0xe59da4, 0xbaa5}, /* U+5764 */ + {0xe59da6, 0xc3b3}, /* U+5766 */ + {0xe59da8, 0x8fa4e4}, /* U+5768 [2000] */ + {0xe59da9, 0xd4b0}, /* U+5769 */ + {0xe59daa, 0xc4da}, /* U+576A */ + {0xe59daf, 0x8fa4e5}, /* U+576F [2000] */ + {0xe59db0, 0xafc7}, /* U+5770 [2000] */ + {0xe59db3, 0x8fa4e6}, /* U+5773 [2000] */ + {0xe59db4, 0x8fa4e7}, /* U+5774 [2000] */ + {0xe59db5, 0x8fa4e8}, /* U+5775 [2000] */ + {0xe59db7, 0xafc8}, /* U+5777 [2000] */ + {0xe59dbb, 0x8fa4e9}, /* U+577B [2000] */ + {0xe59dbc, 0xafc9}, /* U+577C [2000] */ + {0xe59dbf, 0xd4b4}, /* U+577F */ + {0xe59e82, 0xbfe2}, /* U+5782 */ + {0xe59e88, 0xd4b2}, /* U+5788 */ + {0xe59e89, 0xd4b5}, /* U+5789 */ + {0xe59e8b, 0xb7bf}, /* U+578B */ + {0xe59e93, 0xd4b6}, /* U+5793 */ + {0xe59e9a, 0x8fa4ed}, /* U+579A [2000] */ + {0xe59e9c, 0xafca}, /* U+579C [2000] */ + {0xe59e9d, 0x8fa4ee}, /* U+579D [2000] */ + {0xe59e9e, 0x8fa4ef}, /* U+579E [2000] */ + {0xe59ea0, 0xd4b7}, /* U+57A0 */ + {0xe59ea2, 0xb9a4}, /* U+57A2 */ + {0xe59ea3, 0xb3c0}, /* U+57A3 */ + {0xe59ea4, 0xd4b9}, /* U+57A4 */ + {0xe59ea8, 0x8fa4f0}, /* U+57A8 [2000] */ + {0xe59eaa, 0xd4ba}, /* U+57AA */ + {0xe59eac, 0x8fa4ec}, /* U+57AC [2000] */ + {0xe59eb0, 0xd4bb}, /* U+57B0 */ + {0xe59eb3, 0xd4b8}, /* U+57B3 */ + {0xe59eb8, 0xafcd}, /* U+57B8 [2000] */ + {0xe59f80, 0xd4b1}, /* U+57C0 */ + {0xe59f83, 0xd4bc}, /* U+57C3 */ + {0xe59f86, 0xd4bd}, /* U+57C6 */ + {0xe59f87, 0xafce}, /* U+57C7 [2000] */ + {0xe59f88, 0xafcf}, /* U+57C8 [2000] */ + {0xe59f8b, 0xcbe4}, /* U+57CB */ + {0xe59f8c, 0x8fa4f3}, /* U+57CC [2000] */ + {0xe59f8e, 0xbeeb}, /* U+57CE */ + {0xe59f8f, 0xafd0}, /* U+57CF [2000] */ + {0xe59f92, 0xd4bf}, /* U+57D2 */ + {0xe59f93, 0xd4c0}, /* U+57D3 */ + {0xe59f94, 0xd4be}, /* U+57D4 */ + {0xe59f96, 0xd4c2}, /* U+57D6 */ + {0xe59f97, 0x8fa4f1}, /* U+57D7 [2000] */ + {0xe59f9c, 0xc7b8}, /* U+57DC */ + {0xe59f9e, 0x8fa4f6}, /* U+57DE [2000] */ + {0xe59f9f, 0xb0e8}, /* U+57DF */ + {0xe59fa0, 0xc9d6}, /* U+57E0 */ + {0xe59fa3, 0xd4c3}, /* U+57E3 */ + {0xe59fa4, 0xafd1}, /* U+57E4 [2000] */ + {0xe59fa6, 0x8fa4f7}, /* U+57E6 [2000] */ + {0xe59fad, 0xafd2}, /* U+57ED [2000] */ + {0xe59fb0, 0x8fa4f8}, /* U+57F0 [2000] */ + {0xe59fb4, 0xbefd}, /* U+57F4 */ + {0xe59fb5, 0xafd3}, /* U+57F5 [2000] */ + {0xe59fb6, 0xafd4}, /* U+57F6 [2000] */ + {0xe59fb7, 0xbcb9}, /* U+57F7 */ + {0xe59fb8, 0x8fa4fa}, /* U+57F8 [2000] */ + {0xe59fb9, 0xc7dd}, /* U+57F9 */ + {0xe59fba, 0xb4f0}, /* U+57FA */ + {0xe59fbb, 0x8fa4fb}, /* U+57FB [2000] */ + {0xe59fbc, 0xbaeb}, /* U+57FC */ + {0xe59fbd, 0x8fa4fc}, /* U+57FD [2000] */ + {0xe59fbf, 0xafd5}, /* U+57FF [2000] */ + {0xe5a080, 0xcbd9}, /* U+5800 */ + {0xe5a082, 0xc6b2}, /* U+5802 */ + {0xe5a084, 0x8fa4fd}, /* U+5804 [2000] */ + {0xe5a085, 0xb7f8}, /* U+5805 */ + {0xe5a086, 0xc2cf}, /* U+5806 */ + {0xe5a089, 0xafd6}, /* U+5809 [2000] */ + {0xe5a08a, 0xd4c1}, /* U+580A */ + {0xe5a08b, 0xd4c4}, /* U+580B */ + {0xe5a095, 0xc2c4}, /* U+5815 */ + {0xe5a099, 0xd4c5}, /* U+5819 */ + {0xe5a09d, 0xd4c6}, /* U+581D */ + {0xe5a09e, 0x8fa4fe}, /* U+581E [2000] */ + {0xe5a0a0, 0x8fa5a1}, /* U+5820 [2000] */ + {0xe5a0a1, 0xd4c8}, /* U+5821 */ + {0xe5a0a4, 0xc4e9}, /* U+5824 */ + {0xe5a0a7, 0x8fa5a2}, /* U+5827 [2000] */ + {0xe5a0aa, 0xb4ae}, /* U+582A */ + {0xe5a0af, 0xf4a1}, /* U+582F [1983] */ + {0xe5a0b0, 0xb1e1}, /* U+5830 */ + {0xe5a0b1, 0xcaf3}, /* U+5831 */ + {0xe5a0b2, 0x8fa5a3}, /* U+5832 [2000] */ + {0xe5a0b4, 0xbeec}, /* U+5834 */ + {0xe5a0b5, 0xc5c8}, /* U+5835 */ + {0xe5a0b9, 0x8fa5a4}, /* U+5839 [2000] */ + {0xe5a0ba, 0xbae6}, /* U+583A */ + {0xe5a0bd, 0xd4ce}, /* U+583D */ + {0xe5a180, 0xcabd}, /* U+5840 */ + {0xe5a181, 0xcedd}, /* U+5841 */ + {0xe5a189, 0x8fa5a6}, /* U+5849 [2000] */ + {0xe5a18a, 0xb2f4}, /* U+584A */ + {0xe5a18b, 0xd4ca}, /* U+584B */ + {0xe5a18c, 0x8fa5a7}, /* U+584C [2000] */ + {0xe5a191, 0xc1ba}, /* U+5851 */ + {0xe5a192, 0xd4cd}, /* U+5852 */ + {0xe5a194, 0xc5e3}, /* U+5854 */ + {0xe5a197, 0xc5c9}, /* U+5857 */ + {0xe5a198, 0xc5e4}, /* U+5858 */ + {0xe5a199, 0xc8b9}, /* U+5859 */ + {0xe5a19a, 0xc4cd}, /* U+585A */ + {0xe5a19e, 0xbac9}, /* U+585E */ + {0xe5a1a1, 0xafd8}, /* U+5861 [2000] */ + {0xe5a1a2, 0xd4c9}, /* U+5862 */ + {0xe5a1a4, 0xafd9}, /* U+5864 [2000] */ + {0xe5a1a7, 0x8fa5a8}, /* U+5867 [2000] */ + {0xe5a1a9, 0xb1f6}, /* U+5869 */ + {0xe5a1ab, 0xc5b6}, /* U+586B */ + {0xe5a1b0, 0xd4cb}, /* U+5870 */ + {0xe5a1b2, 0xd4c7}, /* U+5872 */ + {0xe5a1b5, 0xbfd0}, /* U+5875 */ + {0xe5a1b9, 0xd4cf}, /* U+5879 */ + {0xe5a1bc, 0xafdb}, /* U+587C [2000] */ + {0xe5a1be, 0xbdce}, /* U+587E */ + {0xe5a283, 0xb6ad}, /* U+5883 */ + {0xe5a285, 0xd4d0}, /* U+5885 */ + {0xe5a289, 0xafdc}, /* U+5889 [2000] */ + {0xe5a28a, 0x8fa5a9}, /* U+588A [2000] */ + {0xe5a28b, 0x8fa5aa}, /* U+588B [2000] */ + {0xe5a28d, 0x8fa5ab}, /* U+588D [2000] */ + {0xe5a28f, 0x8fa5ac}, /* U+588F [2000] */ + {0xe5a290, 0x8fa5ad}, /* U+5890 [2000] */ + {0xe5a293, 0xcae8}, /* U+5893 */ + {0xe5a294, 0x8fa5ae}, /* U+5894 [2000] */ + {0xe5a297, 0xc1fd}, /* U+5897 */ + {0xe5a29c, 0xc4c6}, /* U+589C */ + {0xe5a29d, 0x8fa5af}, /* U+589D [2000] */ + {0xe5a29e, 0xafdd}, /* U+589E [2000] */ + {0xe5a29f, 0xd4d2}, /* U+589F */ + {0xe5a2a8, 0xcbcf}, /* U+58A8 */ + {0xe5a2a9, 0xafdf}, /* U+58A9 [2000] */ + {0xe5a2aa, 0x8fa5b0}, /* U+58AA [2000] */ + {0xe5a2ab, 0xd4d3}, /* U+58AB */ + {0xe5a2ae, 0xd4d8}, /* U+58AE */ + {0xe5a2b1, 0x8fa5b1}, /* U+58B1 [2000] */ + {0xe5a2b3, 0xcaaf}, /* U+58B3 */ + {0xe5a2b8, 0xd4d7}, /* U+58B8 */ + {0xe5a2b9, 0xd4d1}, /* U+58B9 */ + {0xe5a2ba, 0xd4d4}, /* U+58BA */ + {0xe5a2bb, 0xd4d6}, /* U+58BB */ + {0xe5a2be, 0xbaa6}, /* U+58BE */ + {0xe5a381, 0xcac9}, /* U+58C1 */ + {0xe5a383, 0x8fa5b3}, /* U+58C3 [2000] */ + {0xe5a385, 0xd4d9}, /* U+58C5 */ + {0xe5a387, 0xc3c5}, /* U+58C7 */ + {0xe5a38a, 0xb2f5}, /* U+58CA */ + {0xe5a38c, 0xbeed}, /* U+58CC */ + {0xe5a38d, 0x8fa5b4}, /* U+58CD [2000] */ + {0xe5a38e, 0xafe2}, /* U+58CE [2000] */ + {0xe5a391, 0xd4db}, /* U+58D1 */ + {0xe5a392, 0xafe1}, /* U+58D2 [2000] */ + {0xe5a393, 0xd4da}, /* U+58D3 */ + {0xe5a394, 0xafe3}, /* U+58D4 [2000] */ + {0xe5a395, 0xb9e8}, /* U+58D5 */ + {0xe5a397, 0xd4dc}, /* U+58D7 */ + {0xe5a398, 0xd4de}, /* U+58D8 */ + {0xe5a399, 0xd4dd}, /* U+58D9 */ + {0xe5a39a, 0xafe4}, /* U+58DA [2000] */ + {0xe5a39c, 0xd4e0}, /* U+58DC */ + {0xe5a39e, 0xd4d5}, /* U+58DE */ + {0xe5a39f, 0xd4e2}, /* U+58DF */ + {0xe5a3a0, 0xafe5}, /* U+58E0 [2000] */ + {0xe5a3a2, 0x8fa5b5}, /* U+58E2 [2000] */ + {0xe5a3a4, 0xd4e1}, /* U+58E4 */ + {0xe5a3a5, 0xd4df}, /* U+58E5 */ + {0xe5a3a9, 0xafe6}, /* U+58E9 [2000] */ + {0xe5a3ab, 0xbbce}, /* U+58EB */ + {0xe5a3ac, 0xbfd1}, /* U+58EC */ + {0xe5a3ae, 0xc1d4}, /* U+58EE */ + {0xe5a3af, 0xd4e3}, /* U+58EF */ + {0xe5a3b0, 0xc0bc}, /* U+58F0 */ + {0xe5a3b1, 0xb0ed}, /* U+58F1 */ + {0xe5a3b2, 0xc7e4}, /* U+58F2 */ + {0xe5a3b3, 0x8fa5b6}, /* U+58F3 [2000] */ + {0xe5a3b4, 0x8fa5b7}, /* U+58F4 [2000] */ + {0xe5a3b7, 0xc4db}, /* U+58F7 */ + {0xe5a3b9, 0xd4e5}, /* U+58F9 */ + {0xe5a3ba, 0xd4e4}, /* U+58FA */ + {0xe5a3bb, 0xd4e6}, /* U+58FB */ + {0xe5a3bc, 0xd4e7}, /* U+58FC */ + {0xe5a3bd, 0xd4e8}, /* U+58FD */ + {0xe5a482, 0xd4e9}, /* U+5902 */ + {0xe5a485, 0x8fa5b8}, /* U+5905 [2000] */ + {0xe5a486, 0x8fa5b9}, /* U+5906 [2000] */ + {0xe5a489, 0xcad1}, /* U+5909 */ + {0xe5a48a, 0xd4ea}, /* U+590A */ + {0xe5a48b, 0x8fa5ba}, /* U+590B [2000] */ + {0xe5a48c, 0xafe7}, /* U+590C [2000] */ + {0xe5a48d, 0x8fa5bb}, /* U+590D [2000] */ + {0xe5a48f, 0xb2c6}, /* U+590F */ + {0xe5a490, 0xd4eb}, /* U+5910 */ + {0xe5a494, 0x8fa5bc}, /* U+5914 [2000] */ + {0xe5a495, 0xcdbc}, /* U+5915 */ + {0xe5a496, 0xb3b0}, /* U+5916 */ + {0xe5a498, 0xd2c9}, /* U+5918 */ + {0xe5a499, 0xbdc8}, /* U+5919 */ + {0xe5a49a, 0xc2bf}, /* U+591A */ + {0xe5a49b, 0xd4ec}, /* U+591B */ + {0xe5a49c, 0xcceb}, /* U+591C */ + {0xe5a4a2, 0xccb4}, /* U+5922 */ + {0xe5a4a4, 0x8fa5bd}, /* U+5924 [2000] */ + {0xe5a4a5, 0xd4ee}, /* U+5925 */ + {0xe5a4a7, 0xc2e7}, /* U+5927 */ + {0xe5a4a9, 0xc5b7}, /* U+5929 */ + {0xe5a4aa, 0xc2c0}, /* U+592A */ + {0xe5a4ab, 0xc9d7}, /* U+592B */ + {0xe5a4ac, 0xd4ef}, /* U+592C */ + {0xe5a4ad, 0xd4f0}, /* U+592D */ + {0xe5a4ae, 0xb1fb}, /* U+592E */ + {0xe5a4b1, 0xbcba}, /* U+5931 */ + {0xe5a4b2, 0xd4f1}, /* U+5932 */ + {0xe5a4b7, 0xb0d0}, /* U+5937 */ + {0xe5a4b8, 0xd4f2}, /* U+5938 */ + {0xe5a4bd, 0x8fa5c0}, /* U+593D [2000] */ + {0xe5a4be, 0xd4f3}, /* U+593E */ + {0xe5a584, 0xb1e2}, /* U+5944 */ + {0xe5a586, 0x8fa5c2}, /* U+5946 [2000] */ + {0xe5a587, 0xb4f1}, /* U+5947 */ + {0xe5a588, 0xc6e0}, /* U+5948 */ + {0xe5a589, 0xcaf4}, /* U+5949 */ + {0xe5a58e, 0xd4f7}, /* U+594E */ + {0xe5a58f, 0xc1d5}, /* U+594F */ + {0xe5a590, 0xd4f6}, /* U+5950 */ + {0xe5a591, 0xb7c0}, /* U+5951 */ + {0xe5a594, 0xcbdb}, /* U+5954 */ + {0xe5a595, 0xd4f5}, /* U+5955 */ + {0xe5a597, 0xc5e5}, /* U+5957 */ + {0xe5a598, 0xd4f9}, /* U+5958 */ + {0xe5a59a, 0xd4f8}, /* U+595A */ + {0xe5a59b, 0x8fa5c5}, /* U+595B [2000] */ + {0xe5a59d, 0xafe9}, /* U+595D [2000] */ + {0xe5a59f, 0x8fa5c6}, /* U+595F [2000] */ + {0xe5a5a0, 0xd4fb}, /* U+5960 */ + {0xe5a5a2, 0xd4fa}, /* U+5962 */ + {0xe5a5a5, 0xb1fc}, /* U+5965 */ + {0xe5a5a7, 0xd4fc}, /* U+5967 */ + {0xe5a5a8, 0xbea9}, /* U+5968 */ + {0xe5a5a9, 0xd4fe}, /* U+5969 */ + {0xe5a5aa, 0xc3a5}, /* U+596A */ + {0xe5a5ac, 0xd4fd}, /* U+596C */ + {0xe5a5ad, 0xafea}, /* U+596D [2000] */ + {0xe5a5ae, 0xcab3}, /* U+596E */ + {0xe5a5b3, 0xbdf7}, /* U+5973 */ + {0xe5a5b4, 0xc5db}, /* U+5974 */ + {0xe5a5b5, 0x8fa5c8}, /* U+5975 [2000] */ + {0xe5a5b6, 0x8fa5c9}, /* U+5976 [2000] */ + {0xe5a5b8, 0xd5a1}, /* U+5978 */ + {0xe5a5bc, 0x8fa5ca}, /* U+597C [2000] */ + {0xe5a5bd, 0xb9a5}, /* U+597D */ + {0xe5a681, 0xd5a2}, /* U+5981 */ + {0xe5a682, 0xc7a1}, /* U+5982 */ + {0xe5a683, 0xc8de}, /* U+5983 */ + {0xe5a684, 0xccd1}, /* U+5984 */ + {0xe5a68a, 0xc7a5}, /* U+598A */ + {0xe5a68b, 0xafeb}, /* U+598B [2000] */ + {0xe5a68d, 0xd5ab}, /* U+598D */ + {0xe5a692, 0xafec}, /* U+5992 [2000] */ + {0xe5a693, 0xb5b8}, /* U+5993 */ + {0xe5a696, 0xcdc5}, /* U+5996 */ + {0xe5a699, 0xccaf}, /* U+5999 */ + {0xe5a69b, 0xd6ac}, /* U+599B */ + {0xe5a69d, 0xd5a3}, /* U+599D */ + {0xe5a69f, 0x8fa5cb}, /* U+599F [2000] */ + {0xe5a6a3, 0xd5a6}, /* U+59A3 */ + {0xe5a6a4, 0xafed}, /* U+59A4 [2000] */ + {0xe5a6a5, 0xc2c5}, /* U+59A5 */ + {0xe5a6a8, 0xcbb8}, /* U+59A8 */ + {0xe5a6ac, 0xc5ca}, /* U+59AC */ + {0xe5a6ae, 0x8fa5cc}, /* U+59AE [2000] */ + {0xe5a6b2, 0xd5a7}, /* U+59B2 */ + {0xe5a6b9, 0xcbe5}, /* U+59B9 */ + {0xe5a6bb, 0xbaca}, /* U+59BB */ + {0xe5a6bc, 0x8fa5cd}, /* U+59BC [2000] */ + {0xe5a6be, 0xbeaa}, /* U+59BE */ + {0xe5a783, 0xafee}, /* U+59C3 [2000] */ + {0xe5a786, 0xd5a8}, /* U+59C6 */ + {0xe5a788, 0x8fa5ce}, /* U+59C8 [2000] */ + {0xe5a789, 0xbbd0}, /* U+59C9 */ + {0xe5a78b, 0xbbcf}, /* U+59CB */ + {0xe5a78d, 0x8fa5cf}, /* U+59CD [2000] */ + {0xe5a790, 0xb0b9}, /* U+59D0 */ + {0xe5a791, 0xb8c8}, /* U+59D1 */ + {0xe5a792, 0xafef}, /* U+59D2 [2000] */ + {0xe5a793, 0xc0ab}, /* U+59D3 */ + {0xe5a794, 0xb0d1}, /* U+59D4 */ + {0xe5a799, 0xd5ac}, /* U+59D9 */ + {0xe5a79a, 0xd5ad}, /* U+59DA */ + {0xe5a79c, 0xd5aa}, /* U+59DC */ + {0xe5a79d, 0xaff0}, /* U+59DD [2000] */ + {0xe5a79e, 0x8fa5d0}, /* U+59DE [2000] */ + {0xe5a7a3, 0x8fa5d1}, /* U+59E3 [2000] */ + {0xe5a7a4, 0x8fa5d2}, /* U+59E4 [2000] */ + {0xe5a7a5, 0xb1b8}, /* U+59E5 */ + {0xe5a7a6, 0xb4af}, /* U+59E6 */ + {0xe5a7a7, 0x8fa5d3}, /* U+59E7 [2000] */ + {0xe5a7a8, 0xd5a9}, /* U+59E8 */ + {0xe5a7aa, 0xccc5}, /* U+59EA */ + {0xe5a7ab, 0xc9b1}, /* U+59EB */ + {0xe5a7ae, 0x8fa5d4}, /* U+59EE [2000] */ + {0xe5a7b6, 0xb0a8}, /* U+59F6 */ + {0xe5a7b8, 0xfefa}, /* U+59F8 [2004] */ + {0xe5a7bb, 0xb0f9}, /* U+59FB */ + {0xe5a7bf, 0xbbd1}, /* U+59FF */ + {0xe5a881, 0xb0d2}, /* U+5A01 */ + {0xe5a883, 0xb0a3}, /* U+5A03 */ + {0xe5a889, 0xd5b2}, /* U+5A09 */ + {0xe5a88c, 0x8fa5d8}, /* U+5A0C [2000] */ + {0xe5a88d, 0x8fa5d9}, /* U+5A0D [2000] */ + {0xe5a891, 0xd5b0}, /* U+5A11 */ + {0xe5a893, 0xaff1}, /* U+5A13 [2000] */ + {0xe5a897, 0x8fa5da}, /* U+5A17 [2000] */ + {0xe5a898, 0xccbc}, /* U+5A18 */ + {0xe5a89a, 0xd5b3}, /* U+5A1A */ + {0xe5a89c, 0xd5b1}, /* U+5A1C */ + {0xe5a89f, 0xd5af}, /* U+5A1F */ + {0xe5a8a0, 0xbfb1}, /* U+5A20 */ + {0xe5a8a3, 0xaff2}, /* U+5A23 [2000] */ + {0xe5a8a5, 0xd5ae}, /* U+5A25 */ + {0xe5a8a7, 0x8fa5db}, /* U+5A27 [2000] */ + {0xe5a8a9, 0xcada}, /* U+5A29 */ + {0xe5a8ad, 0x8fa5dc}, /* U+5A2D [2000] */ + {0xe5a8af, 0xb8e4}, /* U+5A2F */ + {0xe5a8b5, 0xd5b7}, /* U+5A35 */ + {0xe5a8b6, 0xd5b8}, /* U+5A36 */ + {0xe5a8bc, 0xbeab}, /* U+5A3C */ + {0xe5a980, 0xd5b4}, /* U+5A40 */ + {0xe5a981, 0xcfac}, /* U+5A41 */ + {0xe5a986, 0xc7cc}, /* U+5A46 */ + {0xe5a989, 0xd5b6}, /* U+5A49 */ + {0xe5a995, 0x8fa5dd}, /* U+5A55 [2000] */ + {0xe5a99a, 0xbaa7}, /* U+5A5A */ + {0xe5a9a2, 0xd5b9}, /* U+5A62 */ + {0xe5a9a5, 0x8fa5de}, /* U+5A65 [2000] */ + {0xe5a9a6, 0xc9d8}, /* U+5A66 */ + {0xe5a9a7, 0xaff3}, /* U+5A67 [2000] */ + {0xe5a9aa, 0xd5ba}, /* U+5A6A */ + {0xe5a9ac, 0xd5b5}, /* U+5A6C */ + {0xe5a9ad, 0xaff4}, /* U+5A6D [2000] */ + {0xe5a9b7, 0xaff5}, /* U+5A77 [2000] */ + {0xe5a9ba, 0x8fa5df}, /* U+5A7A [2000] */ + {0xe5a9be, 0xaff6}, /* U+5A7E [2000] */ + {0xe5a9bf, 0xccbb}, /* U+5A7F */ + {0xe5aa84, 0xaff7}, /* U+5A84 [2000] */ + {0xe5aa8b, 0x8fa5e0}, /* U+5A8B [2000] */ + {0xe5aa92, 0xc7de}, /* U+5A92 */ + {0xe5aa9a, 0xd5bb}, /* U+5A9A */ + {0xe5aa9b, 0xc9b2}, /* U+5A9B */ + {0xe5aa9c, 0x8fa5e1}, /* U+5A9C [2000] */ + {0xe5aa9e, 0xaff8}, /* U+5A9E [2000] */ + {0xe5aa9f, 0x8fa5e2}, /* U+5A9F [2000] */ + {0xe5aaa0, 0x8fa5e3}, /* U+5AA0 [2000] */ + {0xe5aaa2, 0x8fa5e4}, /* U+5AA2 [2000] */ + {0xe5aaa7, 0xaff9}, /* U+5AA7 [2000] */ + {0xe5aab1, 0x8fa5e5}, /* U+5AB1 [2000] */ + {0xe5aab3, 0x8fa5e6}, /* U+5AB3 [2000] */ + {0xe5aab5, 0x8fa5e7}, /* U+5AB5 [2000] */ + {0xe5aaba, 0x8fa5e8}, /* U+5ABA [2000] */ + {0xe5aabc, 0xd5bc}, /* U+5ABC */ + {0xe5aabd, 0xd5c0}, /* U+5ABD */ + {0xe5aabe, 0xd5bd}, /* U+5ABE */ + {0xe5aabf, 0x8fa5e9}, /* U+5ABF [2000] */ + {0xe5ab81, 0xb2c7}, /* U+5AC1 */ + {0xe5ab82, 0xd5bf}, /* U+5AC2 */ + {0xe5ab84, 0xaffa}, /* U+5AC4 [2000] */ + {0xe5ab89, 0xbcbb}, /* U+5AC9 */ + {0xe5ab8b, 0xd5be}, /* U+5ACB */ + {0xe5ab8c, 0xb7f9}, /* U+5ACC */ + {0xe5ab90, 0xd5cc}, /* U+5AD0 */ + {0xe5ab96, 0xd5c5}, /* U+5AD6 */ + {0xe5ab97, 0xd5c2}, /* U+5AD7 */ + {0xe5ab9a, 0x8fa5ea}, /* U+5ADA [2000] */ + {0xe5ab9c, 0x8fa5eb}, /* U+5ADC [2000] */ + {0xe5aba0, 0x8fa5ec}, /* U+5AE0 [2000] */ + {0xe5aba1, 0xc3e4}, /* U+5AE1 */ + {0xe5aba3, 0xd5c1}, /* U+5AE3 */ + {0xe5aba5, 0x8fa5ed}, /* U+5AE5 [2000] */ + {0xe5aba6, 0xd5c3}, /* U+5AE6 */ + {0xe5aba9, 0xd5c4}, /* U+5AE9 */ + {0xe5abae, 0x8fa5ef}, /* U+5AEE [2000] */ + {0xe5abb0, 0x8fa5ee}, /* U+5AF0 [2000] */ + {0xe5abb5, 0x8fa5f0}, /* U+5AF5 [2000] */ + {0xe5abba, 0xd5c6}, /* U+5AFA */ + {0xe5abbb, 0xd5c7}, /* U+5AFB */ + {0xe5ac80, 0x8fa5f1}, /* U+5B00 [2000] */ + {0xe5ac88, 0x8fa5f2}, /* U+5B08 [2000] */ + {0xe5ac89, 0xb4f2}, /* U+5B09 */ + {0xe5ac8b, 0xd5c9}, /* U+5B0B */ + {0xe5ac8c, 0xd5c8}, /* U+5B0C */ + {0xe5ac96, 0xd5ca}, /* U+5B16 */ + {0xe5ac97, 0x8fa5f3}, /* U+5B17 [2000] */ + {0xe5ac99, 0xaffc}, /* U+5B19 [2000] */ + {0xe5aca2, 0xbeee}, /* U+5B22 */ + {0xe5aca5, 0xaffd}, /* U+5B25 [2000] */ + {0xe5acaa, 0xd5cd}, /* U+5B2A */ + {0xe5acac, 0xc4dc}, /* U+5B2C */ + {0xe5acad, 0x8fa5f5}, /* U+5B2D [2000] */ + {0xe5acb0, 0xb1c5}, /* U+5B30 */ + {0xe5acb2, 0xd5cb}, /* U+5B32 */ + {0xe5acb4, 0x8fa5f4}, /* U+5B34 [2000] */ + {0xe5acb6, 0xd5ce}, /* U+5B36 */ + {0xe5acbe, 0xd5cf}, /* U+5B3E */ + {0xe5ad80, 0xd5d2}, /* U+5B40 */ + {0xe5ad81, 0xcfd5}, /* U+5B41 [2000] */ + {0xe5ad83, 0xd5d0}, /* U+5B43 */ + {0xe5ad85, 0xd5d1}, /* U+5B45 */ + {0xe5ad8c, 0x8fa5f6}, /* U+5B4C [2000] */ + {0xe5ad90, 0xbbd2}, /* U+5B50 */ + {0xe5ad91, 0xd5d3}, /* U+5B51 */ + {0xe5ad92, 0x8fa5f7}, /* U+5B52 [2000] */ + {0xe5ad94, 0xb9a6}, /* U+5B54 */ + {0xe5ad95, 0xd5d4}, /* U+5B55 */ + {0xe5ad96, 0xcfd6}, /* U+5B56 [2000] */ + {0xe5ad97, 0xbbfa}, /* U+5B57 */ + {0xe5ad98, 0xc2b8}, /* U+5B58 */ + {0xe5ad9a, 0xd5d5}, /* U+5B5A */ + {0xe5ad9b, 0xd5d6}, /* U+5B5B */ + {0xe5ad9c, 0xbbda}, /* U+5B5C */ + {0xe5ad9d, 0xb9a7}, /* U+5B5D */ + {0xe5ad9f, 0xccd2}, /* U+5B5F */ + {0xe5ada3, 0xb5a8}, /* U+5B63 */ + {0xe5ada4, 0xb8c9}, /* U+5B64 */ + {0xe5ada5, 0xd5d7}, /* U+5B65 */ + {0xe5ada6, 0xb3d8}, /* U+5B66 */ + {0xe5ada8, 0x8fa5f8}, /* U+5B68 [2000] */ + {0xe5ada9, 0xd5d8}, /* U+5B69 */ + {0xe5adab, 0xc2b9}, /* U+5B6B */ + {0xe5adaf, 0x8fa5f9}, /* U+5B6F [2000] */ + {0xe5adb0, 0xd5d9}, /* U+5B70 */ + {0xe5adb1, 0xd6a3}, /* U+5B71 */ + {0xe5adb3, 0xd5da}, /* U+5B73 */ + {0xe5adb5, 0xd5db}, /* U+5B75 */ + {0xe5adb8, 0xd5dc}, /* U+5B78 */ + {0xe5adba, 0xd5de}, /* U+5B7A */ + {0xe5adbc, 0x8fa5fa}, /* U+5B7C [2000] */ + {0xe5adbd, 0xcfd7}, /* U+5B7D [2000] */ + {0xe5adbf, 0x8fa5fb}, /* U+5B7F [2000] */ + {0xe5ae80, 0xd5df}, /* U+5B80 */ + {0xe5ae81, 0x8fa5fc}, /* U+5B81 [2000] */ + {0xe5ae83, 0xd5e0}, /* U+5B83 */ + {0xe5ae84, 0x8fa5fd}, /* U+5B84 [2000] */ + {0xe5ae85, 0xc2f0}, /* U+5B85 */ + {0xe5ae87, 0xb1a7}, /* U+5B87 */ + {0xe5ae88, 0xbce9}, /* U+5B88 */ + {0xe5ae89, 0xb0c2}, /* U+5B89 */ + {0xe5ae8b, 0xc1d7}, /* U+5B8B */ + {0xe5ae8c, 0xb4b0}, /* U+5B8C */ + {0xe5ae8d, 0xbcb5}, /* U+5B8D */ + {0xe5ae8f, 0xb9a8}, /* U+5B8F */ + {0xe5ae93, 0xcfd8}, /* U+5B93 [2000] */ + {0xe5ae95, 0xc5e6}, /* U+5B95 */ + {0xe5ae96, 0x8fa8a1}, /* U+5B96 [2000] */ + {0xe5ae97, 0xbda1}, /* U+5B97 */ + {0xe5ae98, 0xb4b1}, /* U+5B98 */ + {0xe5ae99, 0xc3e8}, /* U+5B99 */ + {0xe5ae9a, 0xc4ea}, /* U+5B9A */ + {0xe5ae9b, 0xb0b8}, /* U+5B9B */ + {0xe5ae9c, 0xb5b9}, /* U+5B9C */ + {0xe5ae9d, 0xcaf5}, /* U+5B9D */ + {0xe5ae9f, 0xbcc2}, /* U+5B9F */ + {0xe5aea2, 0xb5d2}, /* U+5BA2 */ + {0xe5aea3, 0xc0eb}, /* U+5BA3 */ + {0xe5aea4, 0xbcbc}, /* U+5BA4 */ + {0xe5aea5, 0xcda8}, /* U+5BA5 */ + {0xe5aea6, 0xd5e1}, /* U+5BA6 */ + {0xe5aeac, 0x8fa8a2}, /* U+5BAC [2000] */ + {0xe5aeae, 0xb5dc}, /* U+5BAE */ + {0xe5aeb0, 0xbacb}, /* U+5BB0 */ + {0xe5aeb3, 0xb3b2}, /* U+5BB3 */ + {0xe5aeb4, 0xb1e3}, /* U+5BB4 */ + {0xe5aeb5, 0xbeac}, /* U+5BB5 */ + {0xe5aeb6, 0xb2c8}, /* U+5BB6 */ + {0xe5aeb8, 0xd5e2}, /* U+5BB8 */ + {0xe5aeb9, 0xcdc6}, /* U+5BB9 */ + {0xe5aebf, 0xbdc9}, /* U+5BBF */ + {0xe5af80, 0x8fa8a4}, /* U+5BC0 [2000] */ + {0xe5af82, 0xbce4}, /* U+5BC2 */ + {0xe5af83, 0xd5e3}, /* U+5BC3 */ + {0xe5af84, 0xb4f3}, /* U+5BC4 */ + {0xe5af85, 0xc6d2}, /* U+5BC5 */ + {0xe5af86, 0xcca9}, /* U+5BC6 */ + {0xe5af87, 0xd5e4}, /* U+5BC7 */ + {0xe5af89, 0xd5e5}, /* U+5BC9 */ + {0xe5af8c, 0xc9d9}, /* U+5BCC */ + {0xe5af8e, 0x8fa8a6}, /* U+5BCE [2000] */ + {0xe5af90, 0xd5e7}, /* U+5BD0 */ + {0xe5af92, 0xb4a8}, /* U+5BD2 */ + {0xe5af93, 0xb6f7}, /* U+5BD3 */ + {0xe5af94, 0xd5e6}, /* U+5BD4 */ + {0xe5af96, 0x8fa8a7}, /* U+5BD6 [2000] */ + {0xe5af98, 0xcfd9}, /* U+5BD8 [2000] */ + {0xe5af9b, 0xb4b2}, /* U+5BDB */ + {0xe5af9d, 0xbfb2}, /* U+5BDD */ + {0xe5af9e, 0xd5eb}, /* U+5BDE */ + {0xe5af9f, 0xbba1}, /* U+5BDF */ + {0xe5afa1, 0xb2c9}, /* U+5BE1 */ + {0xe5afa2, 0xd5ea}, /* U+5BE2 */ + {0xe5afa4, 0xd5e8}, /* U+5BE4 */ + {0xe5afa5, 0xd5ec}, /* U+5BE5 */ + {0xe5afa6, 0xd5e9}, /* U+5BE6 */ + {0xe5afa7, 0xc7ab}, /* U+5BE7 */ + {0xe5afa8, 0xdccd}, /* U+5BE8 */ + {0xe5afa9, 0xbfb3}, /* U+5BE9 */ + {0xe5afab, 0xd5ed}, /* U+5BEB */ + {0xe5afac, 0xcfda}, /* U+5BEC [2000] */ + {0xe5afae, 0xcec0}, /* U+5BEE */ + {0xe5afb0, 0xd5ee}, /* U+5BF0 */ + {0xe5afb1, 0x8fa8aa}, /* U+5BF1 [2000] */ + {0xe5afb3, 0xd5f0}, /* U+5BF3 */ + {0xe5afb5, 0xc3fe}, /* U+5BF5 */ + {0xe5afb6, 0xd5ef}, /* U+5BF6 */ + {0xe5afb8, 0xc0a3}, /* U+5BF8 */ + {0xe5afba, 0xbbfb}, /* U+5BFA */ + {0xe5afbd, 0x8fa8ab}, /* U+5BFD [2000] */ + {0xe5afbe, 0xc2d0}, /* U+5BFE */ + {0xe5afbf, 0xbcf7}, /* U+5BFF */ + {0xe5b081, 0xc9f5}, /* U+5C01 */ + {0xe5b082, 0xc0ec}, /* U+5C02 */ + {0xe5b083, 0x8fa8ad}, /* U+5C03 [2000] */ + {0xe5b084, 0xbccd}, /* U+5C04 */ + {0xe5b085, 0xd5f1}, /* U+5C05 */ + {0xe5b086, 0xbead}, /* U+5C06 */ + {0xe5b087, 0xd5f2}, /* U+5C07 */ + {0xe5b088, 0xd5f3}, /* U+5C08 */ + {0xe5b089, 0xb0d3}, /* U+5C09 */ + {0xe5b08a, 0xc2ba}, /* U+5C0A */ + {0xe5b08b, 0xbfd2}, /* U+5C0B */ + {0xe5b08d, 0xd5f4}, /* U+5C0D */ + {0xe5b08e, 0xc6b3}, /* U+5C0E */ + {0xe5b08f, 0xbeae}, /* U+5C0F */ + {0xe5b091, 0xbeaf}, /* U+5C11 */ + {0xe5b092, 0xcfdb}, /* U+5C12 [2000] */ + {0xe5b093, 0xd5f5}, /* U+5C13 */ + {0xe5b096, 0xc0ed}, /* U+5C16 */ + {0xe5b09a, 0xbeb0}, /* U+5C1A */ + {0xe5b09e, 0xcfdc}, /* U+5C1E [2000] */ + {0xe5b0a0, 0xd5f6}, /* U+5C20 */ + {0xe5b0a2, 0xd5f7}, /* U+5C22 */ + {0xe5b0a3, 0xcfdd}, /* U+5C23 [2000] */ + {0xe5b0a4, 0xcce0}, /* U+5C24 */ + {0xe5b0a8, 0xd5f8}, /* U+5C28 */ + {0xe5b0a9, 0x8fa8ae}, /* U+5C29 [2000] */ + {0xe5b0ab, 0xcfde}, /* U+5C2B [2000] */ + {0xe5b0ad, 0xb6c6}, /* U+5C2D */ + {0xe5b0b0, 0x8fa8af}, /* U+5C30 [2000] */ + {0xe5b0b1, 0xbda2}, /* U+5C31 */ + {0xe5b0b8, 0xd5f9}, /* U+5C38 */ + {0xe5b0b9, 0xd5fa}, /* U+5C39 */ + {0xe5b0ba, 0xbcdc}, /* U+5C3A */ + {0xe5b0bb, 0xbfac}, /* U+5C3B */ + {0xe5b0bc, 0xc6f4}, /* U+5C3C */ + {0xe5b0bd, 0xbfd4}, /* U+5C3D */ + {0xe5b0be, 0xc8f8}, /* U+5C3E */ + {0xe5b0bf, 0xc7a2}, /* U+5C3F */ + {0xe5b180, 0xb6c9}, /* U+5C40 */ + {0xe5b181, 0xd5fb}, /* U+5C41 */ + {0xe5b185, 0xb5ef}, /* U+5C45 */ + {0xe5b186, 0xd5fc}, /* U+5C46 */ + {0xe5b188, 0xb6fe}, /* U+5C48 */ + {0xe5b18a, 0xc6cf}, /* U+5C4A */ + {0xe5b18b, 0xb2b0}, /* U+5C4B */ + {0xe5b18d, 0xbbd3}, /* U+5C4D */ + {0xe5b18e, 0xd5fd}, /* U+5C4E */ + {0xe5b18f, 0xd6a2}, /* U+5C4F */ + {0xe5b190, 0xd6a1}, /* U+5C50 */ + {0xe5b191, 0xb6fd}, /* U+5C51 */ + {0xe5b193, 0xd5fe}, /* U+5C53 */ + {0xe5b195, 0xc5b8}, /* U+5C55 */ + {0xe5b19b, 0xfefb}, /* U+5C5B [2004] */ + {0xe5b19e, 0xc2b0}, /* U+5C5E */ + {0xe5b19f, 0x8fa8b1}, /* U+5C5F [2000] */ + {0xe5b1a0, 0xc5cb}, /* U+5C60 */ + {0xe5b1a1, 0xbcc8}, /* U+5C61 */ + {0xe5b1a2, 0xcfe0}, /* U+5C62 [2000] */ + {0xe5b1a3, 0x8fa8b2}, /* U+5C63 [2000] */ + {0xe5b1a4, 0xc1d8}, /* U+5C64 */ + {0xe5b1a5, 0xcdfa}, /* U+5C65 */ + {0xe5b1a7, 0x8fa8b3}, /* U+5C67 [2000] */ + {0xe5b1a8, 0x8fa8b4}, /* U+5C68 [2000] */ + {0xe5b1a9, 0x8fa8b5}, /* U+5C69 [2000] */ + {0xe5b1ac, 0xd6a4}, /* U+5C6C */ + {0xe5b1ae, 0xd6a5}, /* U+5C6E */ + {0xe5b1af, 0xc6d6}, /* U+5C6F */ + {0xe5b1b0, 0x8fa8b6}, /* U+5C70 [2000] */ + {0xe5b1b1, 0xbbb3}, /* U+5C71 */ + {0xe5b1b6, 0xd6a7}, /* U+5C76 */ + {0xe5b1b9, 0xd6a8}, /* U+5C79 */ + {0xe5b1ba, 0xcfe4}, /* U+5C7A [2000] */ + {0xe5b1bc, 0x8fa8b9}, /* U+5C7C [2000] */ + {0xe5b288, 0x8fa8bc}, /* U+5C88 [2000] */ + {0xe5b28a, 0x8fa8bd}, /* U+5C8A [2000] */ + {0xe5b28c, 0xd6a9}, /* U+5C8C */ + {0xe5b28f, 0xcfe5}, /* U+5C8F [2000] */ + {0xe5b290, 0xb4f4}, /* U+5C90 */ + {0xe5b291, 0xd6aa}, /* U+5C91 */ + {0xe5b294, 0xd6ab}, /* U+5C94 */ + {0xe5b29f, 0xcfe6}, /* U+5C9F [2000] */ + {0xe5b2a0, 0x8fa8c1}, /* U+5CA0 [2000] */ + {0xe5b2a1, 0xb2ac}, /* U+5CA1 */ + {0xe5b2a2, 0x8fa8c2}, /* U+5CA2 [2000] */ + {0xe5b2a3, 0xcfe7}, /* U+5CA3 [2000] */ + {0xe5b2a6, 0x8fa8c3}, /* U+5CA6 [2000] */ + {0xe5b2a7, 0x8fa8c4}, /* U+5CA7 [2000] */ + {0xe5b2a8, 0xc1bb}, /* U+5CA8 */ + {0xe5b2a9, 0xb4e4}, /* U+5CA9 */ + {0xe5b2aa, 0xcfe8}, /* U+5CAA [2000] */ + {0xe5b2ab, 0xd6ad}, /* U+5CAB */ + {0xe5b2ac, 0xcca8}, /* U+5CAC */ + {0xe5b2ad, 0x8fa8c6}, /* U+5CAD [2000] */ + {0xe5b2b1, 0xc2d2}, /* U+5CB1 */ + {0xe5b2b3, 0xb3d9}, /* U+5CB3 */ + {0xe5b2b5, 0x8fa8c7}, /* U+5CB5 [2000] */ + {0xe5b2b6, 0xd6af}, /* U+5CB6 */ + {0xe5b2b7, 0xd6b1}, /* U+5CB7 */ + {0xe5b2b8, 0xb4df}, /* U+5CB8 */ + {0xe5b2ba, 0xcfe9}, /* U+5CBA [2000] */ + {0xe5b2bb, 0xd6ae}, /* U+5CBB */ + {0xe5b2bc, 0xd6b0}, /* U+5CBC */ + {0xe5b2be, 0xd6b3}, /* U+5CBE */ + {0xe5b385, 0xd6b2}, /* U+5CC5 */ + {0xe5b387, 0xd6b4}, /* U+5CC7 */ + {0xe5b389, 0x8fa8c9}, /* U+5CC9 [2000] */ + {0xe5b38b, 0xcfea}, /* U+5CCB [2000] */ + {0xe5b390, 0xcfeb}, /* U+5CD0 [2000] */ + {0xe5b392, 0xcfec}, /* U+5CD2 [2000] */ + {0xe5b399, 0xd6b5}, /* U+5CD9 */ + {0xe5b3a0, 0xc6bd}, /* U+5CE0 */ + {0xe5b3a1, 0xb6ae}, /* U+5CE1 */ + {0xe5b3a8, 0xb2e5}, /* U+5CE8 */ + {0xe5b3a9, 0xd6b6}, /* U+5CE9 */ + {0xe5b3aa, 0xd6bb}, /* U+5CEA */ + {0xe5b3ad, 0xd6b9}, /* U+5CED */ + {0xe5b3af, 0xcaf7}, /* U+5CEF */ + {0xe5b3b0, 0xcaf6}, /* U+5CF0 */ + {0xe5b3b4, 0xcfed}, /* U+5CF4 [2000] */ + {0xe5b3b6, 0xc5e7}, /* U+5CF6 */ + {0xe5b3ba, 0xd6b8}, /* U+5CFA */ + {0xe5b3bb, 0xbdd4}, /* U+5CFB */ + {0xe5b3bd, 0xd6b7}, /* U+5CFD */ + {0xe5b486, 0x8fa8cc}, /* U+5D06 [2000] */ + {0xe5b487, 0xbff2}, /* U+5D07 */ + {0xe5b48b, 0xd6bc}, /* U+5D0B */ + {0xe5b48d, 0xcff0}, /* U+5D0D [2000] */ + {0xe5b48e, 0xbaea}, /* U+5D0E */ + {0xe5b490, 0x8fa8cd}, /* U+5D10 [2000] */ + {0xe5b491, 0xd6c2}, /* U+5D11 */ + {0xe5b494, 0xd6c3}, /* U+5D14 */ + {0xe5b495, 0xd6bd}, /* U+5D15 */ + {0xe5b496, 0xb3b3}, /* U+5D16 */ + {0xe5b497, 0xd6be}, /* U+5D17 */ + {0xe5b498, 0xd6c7}, /* U+5D18 */ + {0xe5b499, 0xd6c6}, /* U+5D19 */ + {0xe5b49a, 0xd6c5}, /* U+5D1A */ + {0xe5b49b, 0xd6c1}, /* U+5D1B */ + {0xe5b49d, 0x8fa8cf}, /* U+5D1D [2000] */ + {0xe5b49f, 0xd6c0}, /* U+5D1F */ + {0xe5b4a0, 0x8fa8d0}, /* U+5D20 [2000] */ + {0xe5b4a2, 0xd6c4}, /* U+5D22 */ + {0xe5b4a4, 0x8fa8d1}, /* U+5D24 [2000] */ + {0xe5b4a6, 0x8fa8d2}, /* U+5D26 [2000] */ + {0xe5b4a7, 0xcff1}, /* U+5D27 [2000] */ + {0xe5b4a9, 0xcaf8}, /* U+5D29 */ + {0xe5b4ab, 0x8fa8ce}, /* U+5D2B [2000] */ + {0xe5b4b1, 0x8fa8d3}, /* U+5D31 [2000] */ + {0xe5b4b9, 0x8fa8d4}, /* U+5D39 [2000] */ + {0xe5b582, 0x8fa8d5}, /* U+5D42 [2000] */ + {0xe5b586, 0xcff3}, /* U+5D46 [2000] */ + {0xe5b587, 0xcff4}, /* U+5D47 [2000] */ + {0xe5b58a, 0xcff6}, /* U+5D4A [2000] */ + {0xe5b58b, 0xd6cb}, /* U+5D4B */ + {0xe5b58c, 0xd6c8}, /* U+5D4C */ + {0xe5b58e, 0xd6ca}, /* U+5D4E */ + {0xe5b590, 0xcdf2}, /* U+5D50 */ + {0xe5b592, 0xd6c9}, /* U+5D52 */ + {0xe5b593, 0xcff5}, /* U+5D53 [2000] */ + {0xe5b59c, 0xd6bf}, /* U+5D5C */ + {0xe5b5a1, 0x8fa8d7}, /* U+5D61 [2000] */ + {0xe5b5a9, 0xbff3}, /* U+5D69 */ + {0xe5b5aa, 0x8fa8d8}, /* U+5D6A [2000] */ + {0xe5b5ac, 0xd6cc}, /* U+5D6C */ + {0xe5b5ad, 0xcff7}, /* U+5D6D [2000] */ + {0xe5b5af, 0xbab7}, /* U+5D6F */ + {0xe5b5b0, 0x8fa8da}, /* U+5D70 [2000] */ + {0xe5b5b3, 0xd6cd}, /* U+5D73 */ + {0xe5b5b6, 0xd6ce}, /* U+5D76 */ + {0xe5b681, 0xcff8}, /* U+5D81 [2000] */ + {0xe5b682, 0xd6d1}, /* U+5D82 */ + {0xe5b684, 0xd6d0}, /* U+5D84 */ + {0xe5b687, 0xd6cf}, /* U+5D87 */ + {0xe5b688, 0x8fa8dd}, /* U+5D88 [2000] */ + {0xe5b68b, 0xc5e8}, /* U+5D8B */ + {0xe5b68c, 0xd6ba}, /* U+5D8C */ + {0xe5b690, 0xd6d7}, /* U+5D90 */ + {0xe5b692, 0x8fa8df}, /* U+5D92 [2000] */ + {0xe5b694, 0x8fa8e0}, /* U+5D94 [2000] */ + {0xe5b697, 0x8fa8e1}, /* U+5D97 [2000] */ + {0xe5b699, 0x8fa8e2}, /* U+5D99 [2000] */ + {0xe5b69d, 0xd6d3}, /* U+5D9D */ + {0xe5b6a0, 0xcff9}, /* U+5DA0 [2000] */ + {0xe5b6a2, 0xd6d2}, /* U+5DA2 */ + {0xe5b6a4, 0xcffa}, /* U+5DA4 [2000] */ + {0xe5b6a7, 0xcffb}, /* U+5DA7 [2000] */ + {0xe5b6ac, 0xd6d4}, /* U+5DAC */ + {0xe5b6ae, 0xd6d5}, /* U+5DAE */ + {0xe5b6b0, 0x8fa8e3}, /* U+5DB0 [2000] */ + {0xe5b6b2, 0x8fa8e4}, /* U+5DB2 [2000] */ + {0xe5b6b4, 0x8fa8e5}, /* U+5DB4 [2000] */ + {0xe5b6b7, 0xd6d8}, /* U+5DB7 */ + {0xe5b6b8, 0xcffc}, /* U+5DB8 [2000] */ + {0xe5b6b9, 0x8fa8e7}, /* U+5DB9 [2000] */ + {0xe5b6ba, 0xcee6}, /* U+5DBA */ + {0xe5b6bc, 0xd6d9}, /* U+5DBC */ + {0xe5b6bd, 0xd6d6}, /* U+5DBD */ + {0xe5b789, 0xd6da}, /* U+5DC9 */ + {0xe5b78b, 0xcffd}, /* U+5DCB [2000] */ + {0xe5b78c, 0xb4e0}, /* U+5DCC */ + {0xe5b78d, 0xd6db}, /* U+5DCD */ + {0xe5b791, 0x8fa8e8}, /* U+5DD1 [2000] */ + {0xe5b792, 0xd6dd}, /* U+5DD2 */ + {0xe5b793, 0xd6dc}, /* U+5DD3 */ + {0xe5b796, 0xd6de}, /* U+5DD6 */ + {0xe5b797, 0x8fa8e9}, /* U+5DD7 [2000] */ + {0xe5b798, 0x8fa8ea}, /* U+5DD8 [2000] */ + {0xe5b79b, 0xd6df}, /* U+5DDB */ + {0xe5b79d, 0xc0ee}, /* U+5DDD */ + {0xe5b79e, 0xbda3}, /* U+5DDE */ + {0xe5b7a0, 0x8fa8eb}, /* U+5DE0 [2000] */ + {0xe5b7a1, 0xbde4}, /* U+5DE1 */ + {0xe5b7a2, 0xf4a8}, /* U+5DE2 [2000] */ + {0xe5b7a3, 0xc1e3}, /* U+5DE3 */ + {0xe5b7a4, 0x8fa8ed}, /* U+5DE4 [2000] */ + {0xe5b7a5, 0xb9a9}, /* U+5DE5 */ + {0xe5b7a6, 0xbab8}, /* U+5DE6 */ + {0xe5b7a7, 0xb9aa}, /* U+5DE7 */ + {0xe5b7a8, 0xb5f0}, /* U+5DE8 */ + {0xe5b7a9, 0x8fa8ee}, /* U+5DE9 [2000] */ + {0xe5b7ab, 0xd6e0}, /* U+5DEB */ + {0xe5b7ae, 0xbab9}, /* U+5DEE */ + {0xe5b7b1, 0xb8ca}, /* U+5DF1 */ + {0xe5b7b2, 0xd6e1}, /* U+5DF2 */ + {0xe5b7b3, 0xcca6}, /* U+5DF3 */ + {0xe5b7b4, 0xc7c3}, /* U+5DF4 */ + {0xe5b7b5, 0xd6e2}, /* U+5DF5 */ + {0xe5b7b7, 0xb9ab}, /* U+5DF7 */ + {0xe5b7bb, 0xb4ac}, /* U+5DFB */ + {0xe5b7bd, 0xc3a7}, /* U+5DFD */ + {0xe5b7be, 0xb6d2}, /* U+5DFE */ + {0xe5b880, 0x8fa8f0}, /* U+5E00 [2000] */ + {0xe5b882, 0xbbd4}, /* U+5E02 */ + {0xe5b883, 0xc9db}, /* U+5E03 */ + {0xe5b886, 0xc8c1}, /* U+5E06 */ + {0xe5b88b, 0xd6e3}, /* U+5E0B */ + {0xe5b88c, 0xb4f5}, /* U+5E0C */ + {0xe5b891, 0xd6e6}, /* U+5E11 */ + {0xe5b892, 0x8fa8f2}, /* U+5E12 [2000] */ + {0xe5b894, 0xf4a9}, /* U+5E14 [2000] */ + {0xe5b895, 0x8fa8f3}, /* U+5E15 [2000] */ + {0xe5b896, 0xc4a1}, /* U+5E16 */ + {0xe5b898, 0xf4aa}, /* U+5E18 [2000] */ + {0xe5b899, 0xd6e5}, /* U+5E19 */ + {0xe5b89a, 0xd6e4}, /* U+5E1A */ + {0xe5b89b, 0xd6e7}, /* U+5E1B */ + {0xe5b89d, 0xc4eb}, /* U+5E1D */ + {0xe5b89f, 0x8fa8f5}, /* U+5E1F [2000] */ + {0xe5b8a5, 0xbfe3}, /* U+5E25 */ + {0xe5b8ab, 0xbbd5}, /* U+5E2B */ + {0xe5b8ad, 0xc0ca}, /* U+5E2D */ + {0xe5b8ae, 0x8fa8f6}, /* U+5E2E [2000] */ + {0xe5b8af, 0xc2d3}, /* U+5E2F */ + {0xe5b8b0, 0xb5a2}, /* U+5E30 */ + {0xe5b8b3, 0xc4a2}, /* U+5E33 */ + {0xe5b8b6, 0xd6e8}, /* U+5E36 */ + {0xe5b8b7, 0xd6e9}, /* U+5E37 */ + {0xe5b8b8, 0xbeef}, /* U+5E38 */ + {0xe5b8bd, 0xcbb9}, /* U+5E3D */ + {0xe5b8be, 0x8fa8f7}, /* U+5E3E [2000] */ + {0xe5b980, 0xd6ec}, /* U+5E40 */ + {0xe5b983, 0xd6eb}, /* U+5E43 */ + {0xe5b984, 0xd6ea}, /* U+5E44 */ + {0xe5b985, 0xc9fd}, /* U+5E45 */ + {0xe5b987, 0xd6f3}, /* U+5E47 */ + {0xe5b989, 0x8fa8f8}, /* U+5E49 [2000] */ + {0xe5b98c, 0xcbda}, /* U+5E4C */ + {0xe5b98e, 0xd6ed}, /* U+5E4E */ + {0xe5b994, 0xd6ef}, /* U+5E54 */ + {0xe5b995, 0xcbeb}, /* U+5E55 */ + {0xe5b996, 0x8fa8fa}, /* U+5E56 [2000] */ + {0xe5b997, 0xd6ee}, /* U+5E57 */ + {0xe5b998, 0xf4ab}, /* U+5E58 [2000] */ + {0xe5b99e, 0xf4ac}, /* U+5E5E [2000] */ + {0xe5b99f, 0xd6f0}, /* U+5E5F */ + {0xe5b9a1, 0xc8a8}, /* U+5E61 */ + {0xe5b9a2, 0xd6f1}, /* U+5E62 */ + {0xe5b9a3, 0xcabe}, /* U+5E63 */ + {0xe5b9a4, 0xd6f2}, /* U+5E64 */ + {0xe5b9ab, 0x8fa8fc}, /* U+5E6B [2000] */ + {0xe5b9ac, 0x8fa8fd}, /* U+5E6C [2000] */ + {0xe5b9ad, 0x8fa8fe}, /* U+5E6D [2000] */ + {0xe5b9ae, 0x8faca1}, /* U+5E6E [2000] */ + {0xe5b9b2, 0xb4b3}, /* U+5E72 */ + {0xe5b9b3, 0xcabf}, /* U+5E73 */ + {0xe5b9b4, 0xc7af}, /* U+5E74 */ + {0xe5b9b5, 0xd6f4}, /* U+5E75 */ + {0xe5b9b6, 0xd6f5}, /* U+5E76 */ + {0xe5b9b7, 0xfefc}, /* U+5E77 [2004] */ + {0xe5b9b8, 0xb9ac}, /* U+5E78 */ + {0xe5b9b9, 0xb4b4}, /* U+5E79 */ + {0xe5b9ba, 0xd6f6}, /* U+5E7A */ + {0xe5b9bb, 0xb8b8}, /* U+5E7B */ + {0xe5b9bc, 0xcdc4}, /* U+5E7C */ + {0xe5b9bd, 0xcda9}, /* U+5E7D */ + {0xe5b9be, 0xb4f6}, /* U+5E7E */ + {0xe5b9bf, 0xd6f8}, /* U+5E7F */ + {0xe5ba81, 0xc4a3}, /* U+5E81 */ + {0xe5ba83, 0xb9ad}, /* U+5E83 */ + {0xe5ba84, 0xbeb1}, /* U+5E84 */ + {0xe5ba87, 0xc8df}, /* U+5E87 */ + {0xe5ba8a, 0xbeb2}, /* U+5E8A */ + {0xe5ba8f, 0xbdf8}, /* U+5E8F */ + {0xe5ba95, 0xc4ec}, /* U+5E95 */ + {0xe5ba96, 0xcaf9}, /* U+5E96 */ + {0xe5ba97, 0xc5b9}, /* U+5E97 */ + {0xe5ba9a, 0xb9ae}, /* U+5E9A */ + {0xe5ba9c, 0xc9dc}, /* U+5E9C */ + {0xe5baa0, 0xd6f9}, /* U+5EA0 */ + {0xe5baa5, 0x8faca3}, /* U+5EA5 [2000] */ + {0xe5baa6, 0xc5d9}, /* U+5EA6 */ + {0xe5baa7, 0xbac2}, /* U+5EA7 */ + {0xe5baaa, 0x8faca4}, /* U+5EAA [2000] */ + {0xe5baab, 0xb8cb}, /* U+5EAB */ + {0xe5baac, 0x8faca5}, /* U+5EAC [2000] */ + {0xe5baad, 0xc4ed}, /* U+5EAD */ + {0xe5bab5, 0xb0c3}, /* U+5EB5 */ + {0xe5bab6, 0xbdee}, /* U+5EB6 */ + {0xe5bab7, 0xb9af}, /* U+5EB7 */ + {0xe5bab8, 0xcdc7}, /* U+5EB8 */ + {0xe5bab9, 0x8faca6}, /* U+5EB9 [2000] */ + {0xe5babe, 0xf4ad}, /* U+5EBE [2000] */ + {0xe5babf, 0x8faca7}, /* U+5EBF [2000] */ + {0xe5bb81, 0xd6fa}, /* U+5EC1 */ + {0xe5bb82, 0xd6fb}, /* U+5EC2 */ + {0xe5bb83, 0xc7d1}, /* U+5EC3 */ + {0xe5bb86, 0x8faca8}, /* U+5EC6 [2000] */ + {0xe5bb88, 0xd6fc}, /* U+5EC8 */ + {0xe5bb89, 0xcef7}, /* U+5EC9 */ + {0xe5bb8a, 0xcfad}, /* U+5ECA */ + {0xe5bb8b, 0xf4af}, /* U+5ECB [2000] */ + {0xe5bb8f, 0xd6fe}, /* U+5ECF */ + {0xe5bb90, 0xd6fd}, /* U+5ED0 */ + {0xe5bb92, 0x8faca9}, /* U+5ED2 [2000] */ + {0xe5bb93, 0xb3c7}, /* U+5ED3 */ + {0xe5bb96, 0xd7a1}, /* U+5ED6 */ + {0xe5bb99, 0x8facaa}, /* U+5ED9 [2000] */ + {0xe5bb9a, 0xd7a4}, /* U+5EDA */ + {0xe5bb9b, 0xd7a5}, /* U+5EDB */ + {0xe5bb9d, 0xd7a3}, /* U+5EDD */ + {0xe5bb9f, 0xc9c0}, /* U+5EDF */ + {0xe5bba0, 0xbeb3}, /* U+5EE0 */ + {0xe5bba1, 0xd7a7}, /* U+5EE1 */ + {0xe5bba2, 0xd7a6}, /* U+5EE2 */ + {0xe5bba3, 0xd7a2}, /* U+5EE3 */ + {0xe5bba8, 0xd7a8}, /* U+5EE8 */ + {0xe5bba9, 0xd7a9}, /* U+5EE9 */ + {0xe5bbac, 0xd7aa}, /* U+5EEC */ + {0xe5bbb0, 0xd7ad}, /* U+5EF0 */ + {0xe5bbb1, 0xd7ab}, /* U+5EF1 */ + {0xe5bbb3, 0xd7ac}, /* U+5EF3 */ + {0xe5bbb4, 0xd7ae}, /* U+5EF4 */ + {0xe5bbb6, 0xb1e4}, /* U+5EF6 */ + {0xe5bbb7, 0xc4ee}, /* U+5EF7 */ + {0xe5bbb8, 0xd7af}, /* U+5EF8 */ + {0xe5bbb9, 0xf4b0}, /* U+5EF9 [2000] */ + {0xe5bbba, 0xb7fa}, /* U+5EFA */ + {0xe5bbbb, 0xb2f6}, /* U+5EFB */ + {0xe5bbbc, 0xc7b6}, /* U+5EFC */ + {0xe5bbbd, 0x8facac}, /* U+5EFD [2000] */ + {0xe5bbbe, 0xd7b0}, /* U+5EFE */ + {0xe5bbbf, 0xc6fb}, /* U+5EFF */ + {0xe5bc80, 0xf4b1}, /* U+5F00 [2000] */ + {0xe5bc81, 0xcadb}, /* U+5F01 */ + {0xe5bc82, 0xf4b2}, /* U+5F02 [2000] */ + {0xe5bc83, 0xd7b1}, /* U+5F03 */ + {0xe5bc84, 0xcfae}, /* U+5F04 */ + {0xe5bc87, 0xf4b3}, /* U+5F07 [2000] */ + {0xe5bc88, 0x8facad}, /* U+5F08 [2000] */ + {0xe5bc89, 0xd7b2}, /* U+5F09 */ + {0xe5bc8a, 0xcac0}, /* U+5F0A */ + {0xe5bc8b, 0xd7b5}, /* U+5F0B */ + {0xe5bc8c, 0xd0a1}, /* U+5F0C */ + {0xe5bc8d, 0xd0b1}, /* U+5F0D */ + {0xe5bc8e, 0x8facae}, /* U+5F0E [2000] */ + {0xe5bc8f, 0xbcb0}, /* U+5F0F */ + {0xe5bc90, 0xc6f5}, /* U+5F10 */ + {0xe5bc91, 0xd7b6}, /* U+5F11 */ + {0xe5bc93, 0xb5dd}, /* U+5F13 */ + {0xe5bc94, 0xc4a4}, /* U+5F14 */ + {0xe5bc95, 0xb0fa}, /* U+5F15 */ + {0xe5bc96, 0xd7b7}, /* U+5F16 */ + {0xe5bc97, 0xcaa6}, /* U+5F17 */ + {0xe5bc98, 0xb9b0}, /* U+5F18 */ + {0xe5bc9b, 0xc3d0}, /* U+5F1B */ + {0xe5bc9c, 0x8facaf}, /* U+5F1C [2000] */ + {0xe5bc9d, 0xf4b4}, /* U+5F1D [2000] */ + {0xe5bc9e, 0x8facb1}, /* U+5F1E [2000] */ + {0xe5bc9f, 0xc4ef}, /* U+5F1F */ + {0xe5bca3, 0xf4b5}, /* U+5F23 [2000] */ + {0xe5bca5, 0xccef}, /* U+5F25 */ + {0xe5bca6, 0xb8b9}, /* U+5F26 */ + {0xe5bca7, 0xb8cc}, /* U+5F27 */ + {0xe5bca9, 0xd7b8}, /* U+5F29 */ + {0xe5bcad, 0xd7b9}, /* U+5F2D */ + {0xe5bcaf, 0xd7bf}, /* U+5F2F */ + {0xe5bcb1, 0xbce5}, /* U+5F31 */ + {0xe5bcb4, 0xf4b6}, /* U+5F34 [2000] */ + {0xe5bcb5, 0xc4a5}, /* U+5F35 */ + {0xe5bcb6, 0xf4b7}, /* U+5F36 [2000] */ + {0xe5bcb7, 0xb6af}, /* U+5F37 */ + {0xe5bcb8, 0xd7ba}, /* U+5F38 */ + {0xe5bcbc, 0xc9ab}, /* U+5F3C */ + {0xe5bcbd, 0xf4b8}, /* U+5F3D [2000] */ + {0xe5bcbe, 0xc3c6}, /* U+5F3E */ + {0xe5bd80, 0xf4b9}, /* U+5F40 [2000] */ + {0xe5bd81, 0xd7bb}, /* U+5F41 */ + {0xe5bd85, 0xf4ba}, /* U+5F45 [2000] */ + {0xe5bd87, 0x8facb2}, /* U+5F47 [2000] */ + {0xe5bd88, 0xd7bc}, /* U+5F48 */ + {0xe5bd8a, 0xb6b0}, /* U+5F4A */ + {0xe5bd8c, 0xd7bd}, /* U+5F4C */ + {0xe5bd8e, 0xd7be}, /* U+5F4E */ + {0xe5bd91, 0xd7c0}, /* U+5F51 */ + {0xe5bd93, 0xc5f6}, /* U+5F53 */ + {0xe5bd94, 0xf4bb}, /* U+5F54 [2000] */ + {0xe5bd96, 0xd7c1}, /* U+5F56 */ + {0xe5bd97, 0xd7c2}, /* U+5F57 */ + {0xe5bd98, 0xf4bc}, /* U+5F58 [2000] */ + {0xe5bd99, 0xd7c3}, /* U+5F59 */ + {0xe5bd9c, 0xd7b4}, /* U+5F5C */ + {0xe5bd9d, 0xd7b3}, /* U+5F5D */ + {0xe5bda1, 0xd7c4}, /* U+5F61 */ + {0xe5bda2, 0xb7c1}, /* U+5F62 */ + {0xe5bda3, 0x8facb3}, /* U+5F63 [2000] */ + {0xe5bda4, 0xf4bd}, /* U+5F64 [2000] */ + {0xe5bda6, 0xc9a7}, /* U+5F66 */ + {0xe5bda7, 0xf4be}, /* U+5F67 [2000] */ + {0xe5bda9, 0xbacc}, /* U+5F69 */ + {0xe5bdaa, 0xc9b7}, /* U+5F6A */ + {0xe5bdab, 0xc4a6}, /* U+5F6B */ + {0xe5bdac, 0xc9cb}, /* U+5F6C */ + {0xe5bdad, 0xd7c5}, /* U+5F6D */ + {0xe5bdb0, 0xbeb4}, /* U+5F70 */ + {0xe5bdb1, 0xb1c6}, /* U+5F71 */ + {0xe5bdb2, 0x8facb4}, /* U+5F72 [2000] */ + {0xe5bdb3, 0xd7c6}, /* U+5F73 */ + {0xe5bdb7, 0xd7c7}, /* U+5F77 */ + {0xe5bdb9, 0xccf2}, /* U+5F79 */ + {0xe5bdbc, 0xc8e0}, /* U+5F7C */ + {0xe5bdbd, 0xf4bf}, /* U+5F7D [2000] */ + {0xe5bdbe, 0x8facb5}, /* U+5F7E [2000] */ + {0xe5bdbf, 0xd7ca}, /* U+5F7F */ + {0xe5be80, 0xb1fd}, /* U+5F80 */ + {0xe5be81, 0xc0ac}, /* U+5F81 */ + {0xe5be82, 0xd7c9}, /* U+5F82 */ + {0xe5be83, 0xd7c8}, /* U+5F83 */ + {0xe5be84, 0xb7c2}, /* U+5F84 */ + {0xe5be85, 0xc2d4}, /* U+5F85 */ + {0xe5be87, 0xd7ce}, /* U+5F87 */ + {0xe5be88, 0xd7cc}, /* U+5F88 */ + {0xe5be89, 0xf4c0}, /* U+5F89 [2000] */ + {0xe5be8a, 0xd7cb}, /* U+5F8A */ + {0xe5be8b, 0xcea7}, /* U+5F8B */ + {0xe5be8c, 0xb8e5}, /* U+5F8C */ + {0xe5be8f, 0x8facb6}, /* U+5F8F [2000] */ + {0xe5be90, 0xbdf9}, /* U+5F90 */ + {0xe5be91, 0xd7cd}, /* U+5F91 */ + {0xe5be92, 0xc5cc}, /* U+5F92 */ + {0xe5be93, 0xbdbe}, /* U+5F93 */ + {0xe5be97, 0xc6c0}, /* U+5F97 */ + {0xe5be98, 0xd7d1}, /* U+5F98 */ + {0xe5be99, 0xd7d0}, /* U+5F99 */ + {0xe5be9c, 0xf4c1}, /* U+5F9C [2000] */ + {0xe5be9e, 0xd7cf}, /* U+5F9E */ + {0xe5bea0, 0xd7d2}, /* U+5FA0 */ + {0xe5bea1, 0xb8e6}, /* U+5FA1 */ + {0xe5bea2, 0x8facb7}, /* U+5FA2 [2000] */ + {0xe5bea4, 0x8facb8}, /* U+5FA4 [2000] */ + {0xe5bea7, 0xf4c2}, /* U+5FA7 [2000] */ + {0xe5bea8, 0xd7d3}, /* U+5FA8 */ + {0xe5bea9, 0xc9fc}, /* U+5FA9 */ + {0xe5beaa, 0xbddb}, /* U+5FAA */ + {0xe5bead, 0xd7d4}, /* U+5FAD */ + {0xe5beae, 0xc8f9}, /* U+5FAE */ + {0xe5beaf, 0xf4c3}, /* U+5FAF [2000] */ + {0xe5beb3, 0xc6c1}, /* U+5FB3 */ + {0xe5beb4, 0xc4a7}, /* U+5FB4 */ + {0xe5beb5, 0xf4c4}, /* U+5FB5 [2000] */ + {0xe5beb7, 0xf4c5}, /* U+5FB7 [2000] */ + {0xe5beb8, 0x8facb9}, /* U+5FB8 [2000] */ + {0xe5beb9, 0xc5b0}, /* U+5FB9 */ + {0xe5bebc, 0xd7d5}, /* U+5FBC */ + {0xe5bebd, 0xb5ab}, /* U+5FBD */ + {0xe5bf83, 0xbfb4}, /* U+5FC3 */ + {0xe5bf84, 0x8facba}, /* U+5FC4 [2000] */ + {0xe5bf85, 0xc9ac}, /* U+5FC5 */ + {0xe5bf87, 0x8facbc}, /* U+5FC7 [2000] */ + {0xe5bf89, 0xf4c6}, /* U+5FC9 [2000] */ + {0xe5bf8b, 0x8facbd}, /* U+5FCB [2000] */ + {0xe5bf8c, 0xb4f7}, /* U+5FCC */ + {0xe5bf8d, 0xc7a6}, /* U+5FCD */ + {0xe5bf92, 0x8facbe}, /* U+5FD2 [2000] */ + {0xe5bf93, 0x8facbf}, /* U+5FD3 [2000] */ + {0xe5bf94, 0x8facc0}, /* U+5FD4 [2000] */ + {0xe5bf96, 0xd7d6}, /* U+5FD6 */ + {0xe5bf97, 0xbbd6}, /* U+5FD7 */ + {0xe5bf98, 0xcbba}, /* U+5FD8 */ + {0xe5bf99, 0xcbbb}, /* U+5FD9 */ + {0xe5bf9c, 0xb1fe}, /* U+5FDC */ + {0xe5bf9d, 0xd7db}, /* U+5FDD */ + {0xe5bf9e, 0xf4c7}, /* U+5FDE [2000] */ + {0xe5bfa0, 0xc3e9}, /* U+5FE0 */ + {0xe5bfa1, 0xf4c8}, /* U+5FE1 [2000] */ + {0xe5bfa2, 0x8facc1}, /* U+5FE2 [2000] */ + {0xe5bfa4, 0xd7d8}, /* U+5FE4 */ + {0xe5bfa9, 0xf4c9}, /* U+5FE9 [2000] */ + {0xe5bfab, 0xb2f7}, /* U+5FEB */ + {0xe5bfae, 0x8facc2}, /* U+5FEE [2000] */ + {0xe5bfaf, 0x8facc3}, /* U+5FEF [2000] */ + {0xe5bfb0, 0xd8ad}, /* U+5FF0 */ + {0xe5bfb1, 0xd7da}, /* U+5FF1 */ + {0xe5bfb3, 0x8facc4}, /* U+5FF3 [2000] */ + {0xe5bfb5, 0xc7b0}, /* U+5FF5 */ + {0xe5bfb8, 0xd7d9}, /* U+5FF8 */ + {0xe5bfbb, 0xd7d7}, /* U+5FFB */ + {0xe5bfbc, 0x8facc5}, /* U+5FFC [2000] */ + {0xe5bfbd, 0xb9fa}, /* U+5FFD */ + {0xe5bfbf, 0xd7dd}, /* U+5FFF */ + {0xe6808d, 0xf4ca}, /* U+600D [2000] */ + {0xe6808e, 0xd7e3}, /* U+600E */ + {0xe6808f, 0xd7e9}, /* U+600F */ + {0xe68090, 0xd7e1}, /* U+6010 */ + {0xe68092, 0xc5dc}, /* U+6012 */ + {0xe68094, 0xf4cb}, /* U+6014 [2000] */ + {0xe68095, 0xd7e6}, /* U+6015 */ + {0xe68096, 0xc9dd}, /* U+6016 */ + {0xe68097, 0x8facc7}, /* U+6017 [2000] */ + {0xe68098, 0xf4cc}, /* U+6018 [2000] */ + {0xe68099, 0xd7e0}, /* U+6019 */ + {0xe6809b, 0xd7e5}, /* U+601B */ + {0xe6809c, 0xcee7}, /* U+601C */ + {0xe6809d, 0xbbd7}, /* U+601D */ + {0xe680a0, 0xc2d5}, /* U+6020 */ + {0xe680a1, 0xd7de}, /* U+6021 */ + {0xe680a2, 0x8facc8}, /* U+6022 [2000] */ + {0xe680a4, 0x8facc9}, /* U+6024 [2000] */ + {0xe680a5, 0xb5de}, /* U+6025 */ + {0xe680a6, 0xd7e8}, /* U+6026 */ + {0xe680a7, 0xc0ad}, /* U+6027 */ + {0xe680a8, 0xb1e5}, /* U+6028 */ + {0xe680a9, 0xd7e2}, /* U+6029 */ + {0xe680aa, 0xb2f8}, /* U+602A */ + {0xe680ab, 0xd7e7}, /* U+602B */ + {0xe680af, 0xb6b1}, /* U+602F */ + {0xe680b1, 0xd7e4}, /* U+6031 */ + {0xe680b3, 0xf4cd}, /* U+6033 [2000] */ + {0xe680b5, 0xf4ce}, /* U+6035 [2000] */ + {0xe680ba, 0xd7ea}, /* U+603A */ + {0xe68181, 0xd7ec}, /* U+6041 */ + {0xe68182, 0xd7f6}, /* U+6042 */ + {0xe68183, 0xd7f4}, /* U+6043 */ + {0xe68186, 0xd7f1}, /* U+6046 */ + {0xe68187, 0xf4cf}, /* U+6047 [2000] */ + {0xe6818a, 0xd7f0}, /* U+604A */ + {0xe6818b, 0xcef8}, /* U+604B */ + {0xe6818c, 0x8faccb}, /* U+604C [2000] */ + {0xe6818d, 0xd7f2}, /* U+604D */ + {0xe68190, 0xb6b2}, /* U+6050 */ + {0xe68192, 0xb9b1}, /* U+6052 */ + {0xe68195, 0xbdfa}, /* U+6055 */ + {0xe68199, 0xd7f9}, /* U+6059 */ + {0xe6819a, 0xd7eb}, /* U+605A */ + {0xe6819f, 0xd7ef}, /* U+605F */ + {0xe681a0, 0xd7df}, /* U+6060 */ + {0xe681a2, 0xb2fa}, /* U+6062 */ + {0xe681a3, 0xd7f3}, /* U+6063 */ + {0xe681a4, 0xd7f5}, /* U+6064 */ + {0xe681a5, 0xc3d1}, /* U+6065 */ + {0xe681a8, 0xbaa8}, /* U+6068 */ + {0xe681a9, 0xb2b8}, /* U+6069 */ + {0xe681aa, 0xd7ed}, /* U+606A */ + {0xe681ab, 0xd7f8}, /* U+606B */ + {0xe681ac, 0xd7f7}, /* U+606C */ + {0xe681ad, 0xb6b3}, /* U+606D */ + {0xe681af, 0xc2a9}, /* U+606F */ + {0xe681b0, 0xb3e6}, /* U+6070 */ + {0xe681b5, 0xb7c3}, /* U+6075 */ + {0xe681b7, 0xd7ee}, /* U+6077 */ + {0xe681bf, 0x8faccc}, /* U+607F [2000] */ + {0xe68281, 0xd7fa}, /* U+6081 */ + {0xe68283, 0xd7fd}, /* U+6083 */ + {0xe68284, 0xd8a1}, /* U+6084 */ + {0xe68289, 0xbcbd}, /* U+6089 */ + {0xe6828a, 0x8faccd}, /* U+608A [2000] */ + {0xe6828b, 0xd8a7}, /* U+608B */ + {0xe6828c, 0xc4f0}, /* U+608C */ + {0xe6828d, 0xd7fb}, /* U+608D */ + {0xe68292, 0xd8a5}, /* U+6092 */ + {0xe68294, 0xb2f9}, /* U+6094 */ + {0xe68295, 0x8facce}, /* U+6095 [2000] */ + {0xe68296, 0xd8a3}, /* U+6096 */ + {0xe68297, 0xd8a4}, /* U+6097 */ + {0xe6829a, 0xd7fe}, /* U+609A */ + {0xe6829b, 0xd8a2}, /* U+609B */ + {0xe6829d, 0xf4d1}, /* U+609D [2000] */ + {0xe6829e, 0xf4d2}, /* U+609E [2000] */ + {0xe6829f, 0xb8e7}, /* U+609F */ + {0xe682a0, 0xcdaa}, /* U+60A0 */ + {0xe682a3, 0xb4b5}, /* U+60A3 */ + {0xe682a6, 0xb1d9}, /* U+60A6 */ + {0xe682a7, 0xd8a6}, /* U+60A7 */ + {0xe682a8, 0x8faccf}, /* U+60A8 [2000] */ + {0xe682a9, 0xc7ba}, /* U+60A9 */ + {0xe682aa, 0xb0ad}, /* U+60AA */ + {0xe682b0, 0x8facd1}, /* U+60B0 [2000] */ + {0xe682b1, 0x8facd2}, /* U+60B1 [2000] */ + {0xe682b2, 0xc8e1}, /* U+60B2 */ + {0xe682b3, 0xd7dc}, /* U+60B3 */ + {0xe682b4, 0xd8ac}, /* U+60B4 */ + {0xe682b5, 0xd8b0}, /* U+60B5 */ + {0xe682b6, 0xcce5}, /* U+60B6 */ + {0xe682b8, 0xd8a9}, /* U+60B8 */ + {0xe682bc, 0xc5e9}, /* U+60BC */ + {0xe682bd, 0xd8ae}, /* U+60BD */ + {0xe682be, 0x8facd3}, /* U+60BE [2000] */ + {0xe68385, 0xbef0}, /* U+60C5 */ + {0xe68386, 0xd8af}, /* U+60C6 */ + {0xe68387, 0xc6d7}, /* U+60C7 */ + {0xe68388, 0x8facd4}, /* U+60C8 [2000] */ + {0xe6838b, 0xf4d3}, /* U+60CB [2000] */ + {0xe68391, 0xcfc7}, /* U+60D1 */ + {0xe68393, 0xd8ab}, /* U+60D3 */ + {0xe68394, 0xf4d4}, /* U+60D4 [2000] */ + {0xe68395, 0xf4d5}, /* U+60D5 [2000] */ + {0xe68398, 0xd8b1}, /* U+60D8 */ + {0xe68399, 0x8facd5}, /* U+60D9 [2000] */ + {0xe6839a, 0xb9fb}, /* U+60DA */ + {0xe6839b, 0x8facd6}, /* U+60DB [2000] */ + {0xe6839c, 0xc0cb}, /* U+60DC */ + {0xe6839d, 0xf4d6}, /* U+60DD [2000] */ + {0xe6839f, 0xb0d4}, /* U+60DF */ + {0xe683a0, 0xd8aa}, /* U+60E0 */ + {0xe683a1, 0xd8a8}, /* U+60E1 */ + {0xe683a3, 0xc1da}, /* U+60E3 */ + {0xe683a7, 0xd7fc}, /* U+60E7 */ + {0xe683a8, 0xbbb4}, /* U+60E8 */ + {0xe683ae, 0x8facd7}, /* U+60EE [2000] */ + {0xe683b0, 0xc2c6}, /* U+60F0 */ + {0xe683b1, 0xd8bd}, /* U+60F1 */ + {0xe683b2, 0x8facd8}, /* U+60F2 [2000] */ + {0xe683b3, 0xc1db}, /* U+60F3 */ + {0xe683b4, 0xd8b8}, /* U+60F4 */ + {0xe683b5, 0x8facd9}, /* U+60F5 [2000] */ + {0xe683b6, 0xd8b5}, /* U+60F6 */ + {0xe683b7, 0xd8b6}, /* U+60F7 */ + {0xe683b8, 0xf4d7}, /* U+60F8 [2000] */ + {0xe683b9, 0xbce6}, /* U+60F9 */ + {0xe683ba, 0xd8b9}, /* U+60FA */ + {0xe683bb, 0xd8bc}, /* U+60FB */ + {0xe68480, 0xd8b7}, /* U+6100 */ + {0xe68481, 0xbda5}, /* U+6101 */ + {0xe68483, 0xd8ba}, /* U+6103 */ + {0xe68486, 0xd8b4}, /* U+6106 */ + {0xe68488, 0xccfc}, /* U+6108 */ + {0xe68489, 0xccfb}, /* U+6109 */ + {0xe6848d, 0xd8be}, /* U+610D */ + {0xe6848e, 0xd8bf}, /* U+610E */ + {0xe6848f, 0xb0d5}, /* U+610F */ + {0xe68490, 0x8facda}, /* U+6110 [2000] */ + {0xe68492, 0x8facdb}, /* U+6112 [2000] */ + {0xe68493, 0x8facdc}, /* U+6113 [2000] */ + {0xe68495, 0xd8b3}, /* U+6115 */ + {0xe68499, 0x8facdd}, /* U+6119 [2000] */ + {0xe6849a, 0xb6f2}, /* U+611A */ + {0xe6849b, 0xb0a6}, /* U+611B */ + {0xe6849c, 0xf4d8}, /* U+611C [2000] */ + {0xe6849e, 0x8facde}, /* U+611E [2000] */ + {0xe6849f, 0xb4b6}, /* U+611F */ + {0xe684a1, 0xd8bb}, /* U+6121 */ + {0xe684a7, 0xd8c3}, /* U+6127 */ + {0xe684a8, 0xd8c2}, /* U+6128 */ + {0xe684ab, 0xf4d9}, /* U+612B [2000] */ + {0xe684ac, 0xd8c7}, /* U+612C */ + {0xe684b0, 0xf4da}, /* U+6130 [2000] */ + {0xe684b4, 0xd8c8}, /* U+6134 */ + {0xe684b7, 0xf4db}, /* U+6137 [2000] */ + {0xe684ba, 0x8facdf}, /* U+613A [2000] */ + {0xe684bc, 0xd8c6}, /* U+613C */ + {0xe684bd, 0xd8c9}, /* U+613D */ + {0xe684be, 0xd8c1}, /* U+613E */ + {0xe684bf, 0xd8c5}, /* U+613F */ + {0xe68581, 0x8face1}, /* U+6141 [2000] */ + {0xe68582, 0xd8ca}, /* U+6142 */ + {0xe68584, 0xd8cb}, /* U+6144 */ + {0xe68586, 0x8face2}, /* U+6146 [2000] */ + {0xe68587, 0xd8c0}, /* U+6147 */ + {0xe68588, 0xbbfc}, /* U+6148 */ + {0xe6858a, 0xd8c4}, /* U+614A */ + {0xe6858b, 0xc2d6}, /* U+614B */ + {0xe6858c, 0xb9b2}, /* U+614C */ + {0xe6858d, 0xd8b2}, /* U+614D */ + {0xe6858e, 0xbfb5}, /* U+614E */ + {0xe68593, 0xd8d8}, /* U+6153 */ + {0xe68595, 0xcae9}, /* U+6155 */ + {0xe68598, 0xd8ce}, /* U+6158 */ + {0xe68599, 0xd8cf}, /* U+6159 */ + {0xe6859a, 0xd8d0}, /* U+615A */ + {0xe6859d, 0xd8d7}, /* U+615D */ + {0xe6859f, 0xd8d6}, /* U+615F */ + {0xe685a0, 0x8face3}, /* U+6160 [2000] */ + {0xe685a2, 0xcbfd}, /* U+6162 */ + {0xe685a3, 0xb4b7}, /* U+6163 */ + {0xe685a5, 0xd8d4}, /* U+6165 */ + {0xe685a7, 0xb7c5}, /* U+6167 */ + {0xe685a8, 0xb3b4}, /* U+6168 */ + {0xe685ab, 0xd8d1}, /* U+616B */ + {0xe685ae, 0xceb8}, /* U+616E */ + {0xe685af, 0xd8d3}, /* U+616F */ + {0xe685b0, 0xb0d6}, /* U+6170 */ + {0xe685b1, 0xd8d5}, /* U+6171 */ + {0xe685b3, 0xd8cc}, /* U+6173 */ + {0xe685b4, 0xd8d2}, /* U+6174 */ + {0xe685b5, 0xd8d9}, /* U+6175 */ + {0xe685b6, 0xb7c4}, /* U+6176 */ + {0xe685b7, 0xd8cd}, /* U+6177 */ + {0xe685bc, 0x8face4}, /* U+617C [2000] */ + {0xe685be, 0xcddd}, /* U+617E */ + {0xe68682, 0xcdab}, /* U+6182 */ + {0xe68687, 0xd8dc}, /* U+6187 */ + {0xe6868a, 0xd8e0}, /* U+618A */ + {0xe6868d, 0xf4dd}, /* U+618D [2000] */ + {0xe6868e, 0xc1fe}, /* U+618E */ + {0xe68690, 0xcef9}, /* U+6190 */ + {0xe68691, 0xd8e1}, /* U+6191 */ + {0xe68692, 0x8face6}, /* U+6192 [2000] */ + {0xe68693, 0x8face7}, /* U+6193 [2000] */ + {0xe68694, 0xd8de}, /* U+6194 */ + {0xe68696, 0xd8db}, /* U+6196 */ + {0xe68697, 0x8face8}, /* U+6197 [2000] */ + {0xe68698, 0x8face9}, /* U+6198 [2000] */ + {0xe68699, 0xd8da}, /* U+6199 */ + {0xe6869a, 0xd8df}, /* U+619A */ + {0xe686a4, 0xcab0}, /* U+61A4 */ + {0xe686a5, 0x8facea}, /* U+61A5 [2000] */ + {0xe686a7, 0xc6b4}, /* U+61A7 */ + {0xe686a8, 0x8faceb}, /* U+61A8 [2000] */ + {0xe686a9, 0xb7c6}, /* U+61A9 */ + {0xe686ab, 0xd8e2}, /* U+61AB */ + {0xe686ac, 0xd8dd}, /* U+61AC */ + {0xe686ad, 0x8facec}, /* U+61AD [2000] */ + {0xe686ae, 0xd8e3}, /* U+61AE */ + {0xe686b2, 0xb7fb}, /* U+61B2 */ + {0xe686b6, 0xb2b1}, /* U+61B6 */ + {0xe686b9, 0xf4e0}, /* U+61B9 [2000] */ + {0xe686ba, 0xd8eb}, /* U+61BA */ + {0xe686bc, 0xf4df}, /* U+61BC [2000] */ + {0xe686be, 0xb4b8}, /* U+61BE */ + {0xe68783, 0xd8e9}, /* U+61C3 */ + {0xe68786, 0xd8ea}, /* U+61C6 */ + {0xe68787, 0xbaa9}, /* U+61C7 */ + {0xe68788, 0xd8e8}, /* U+61C8 */ + {0xe68789, 0xd8e6}, /* U+61C9 */ + {0xe6878a, 0xd8e5}, /* U+61CA */ + {0xe6878b, 0xd8ec}, /* U+61CB */ + {0xe6878c, 0xd8e4}, /* U+61CC */ + {0xe6878d, 0xd8ee}, /* U+61CD */ + {0xe68790, 0xb2fb}, /* U+61D0 */ + {0xe68795, 0x8facee}, /* U+61D5 [2000] */ + {0xe6879d, 0x8facef}, /* U+61DD [2000] */ + {0xe6879f, 0x8facf0}, /* U+61DF [2000] */ + {0xe687a3, 0xd8f0}, /* U+61E3 */ + {0xe687a6, 0xd8ef}, /* U+61E6 */ + {0xe687b2, 0xc4a8}, /* U+61F2 */ + {0xe687b4, 0xd8f3}, /* U+61F4 */ + {0xe687b5, 0x8facf1}, /* U+61F5 [2000] */ + {0xe687b6, 0xd8f1}, /* U+61F6 */ + {0xe687b7, 0xd8e7}, /* U+61F7 */ + {0xe687b8, 0xb7fc}, /* U+61F8 */ + {0xe687ba, 0xd8f2}, /* U+61FA */ + {0xe687bc, 0xd8f6}, /* U+61FC */ + {0xe687bd, 0xd8f5}, /* U+61FD */ + {0xe687be, 0xd8f7}, /* U+61FE */ + {0xe687bf, 0xd8f4}, /* U+61FF */ + {0xe68880, 0xd8f8}, /* U+6200 */ + {0xe68888, 0xd8f9}, /* U+6208 */ + {0xe68889, 0xd8fa}, /* U+6209 */ + {0xe6888a, 0xcaea}, /* U+620A */ + {0xe6888c, 0xd8fc}, /* U+620C */ + {0xe6888d, 0xd8fb}, /* U+620D */ + {0xe6888e, 0xbdbf}, /* U+620E */ + {0xe68890, 0xc0ae}, /* U+6210 */ + {0xe68891, 0xb2e6}, /* U+6211 */ + {0xe68892, 0xb2fc}, /* U+6212 */ + {0xe68894, 0xd8fd}, /* U+6214 */ + {0xe68895, 0x8facf3}, /* U+6215 [2000] */ + {0xe68896, 0xb0bf}, /* U+6216 */ + {0xe6889a, 0xc0cc}, /* U+621A */ + {0xe6889b, 0xd8fe}, /* U+621B */ + {0xe6889d, 0xecc3}, /* U+621D */ + {0xe6889e, 0xd9a1}, /* U+621E */ + {0xe6889f, 0xb7e1}, /* U+621F */ + {0xe688a1, 0xd9a2}, /* U+6221 */ + {0xe688a2, 0xf4e2}, /* U+6222 [2000] */ + {0xe688a3, 0x8facf4}, /* U+6223 [2000] */ + {0xe688a6, 0xc0ef}, /* U+6226 */ + {0xe688a9, 0x8facf5}, /* U+6229 [2000] */ + {0xe688aa, 0xd9a3}, /* U+622A */ + {0xe688ae, 0xd9a4}, /* U+622E */ + {0xe688af, 0xb5ba}, /* U+622F */ + {0xe688b0, 0xd9a5}, /* U+6230 */ + {0xe688b2, 0xd9a6}, /* U+6232 */ + {0xe688b3, 0xd9a7}, /* U+6233 */ + {0xe688b4, 0xc2d7}, /* U+6234 */ + {0xe688b8, 0xb8cd}, /* U+6238 */ + {0xe688bb, 0xcce1}, /* U+623B */ + {0xe688be, 0xf4e3}, /* U+623E [2000] */ + {0xe688bf, 0xcbbc}, /* U+623F */ + {0xe68980, 0xbdea}, /* U+6240 */ + {0xe68981, 0xd9a8}, /* U+6241 */ + {0xe68983, 0xf4e4}, /* U+6243 [2000] */ + {0xe68986, 0x8facf6}, /* U+6246 [2000] */ + {0xe68987, 0xc0f0}, /* U+6247 */ + {0xe68988, 0xeebd}, /* U+6248 */ + {0xe68989, 0xc8e2}, /* U+6249 */ + {0xe6898b, 0xbcea}, /* U+624B */ + {0xe6898c, 0x8facf7}, /* U+624C [2000] */ + {0xe6898d, 0xbacd}, /* U+624D */ + {0xe6898e, 0xd9a9}, /* U+624E */ + {0xe68991, 0x8facf8}, /* U+6251 [2000] */ + {0xe68992, 0x8facf9}, /* U+6252 [2000] */ + {0xe68993, 0xc2c7}, /* U+6253 */ + {0xe68995, 0xcaa7}, /* U+6255 */ + {0xe68996, 0xf4e5}, /* U+6256 [2000] */ + {0xe68998, 0xc2f1}, /* U+6258 */ + {0xe6899a, 0xf4e6}, /* U+625A [2000] */ + {0xe6899b, 0xd9ac}, /* U+625B */ + {0xe6899e, 0xd9aa}, /* U+625E */ + {0xe689a0, 0xd9ad}, /* U+6260 */ + {0xe689a1, 0x8facfa}, /* U+6261 [2000] */ + {0xe689a3, 0xd9ab}, /* U+6263 */ + {0xe689a4, 0x8facfb}, /* U+6264 [2000] */ + {0xe689a8, 0xd9ae}, /* U+6268 */ + {0xe689ad, 0x8facfd}, /* U+626D [2000] */ + {0xe689ae, 0xcab1}, /* U+626E */ + {0xe689af, 0xf4e7}, /* U+626F [2000] */ + {0xe689b1, 0xb0b7}, /* U+6271 */ + {0xe689b3, 0x8facfe}, /* U+6273 [2000] */ + {0xe689b6, 0xc9de}, /* U+6276 */ + {0xe689b9, 0xc8e3}, /* U+6279 */ + {0xe689bb, 0x8facfc}, /* U+627B [2000] */ + {0xe689bc, 0xd9af}, /* U+627C */ + {0xe689be, 0xd9b2}, /* U+627E */ + {0xe689bf, 0xbeb5}, /* U+627F */ + {0xe68a80, 0xb5bb}, /* U+6280 */ + {0xe68a82, 0xd9b0}, /* U+6282 */ + {0xe68a83, 0xd9b7}, /* U+6283 */ + {0xe68a84, 0xbeb6}, /* U+6284 */ + {0xe68a85, 0xf4e8}, /* U+6285 [2000] */ + {0xe68a89, 0xd9b1}, /* U+6289 */ + {0xe68a8a, 0xc7c4}, /* U+628A */ + {0xe68a91, 0xcdde}, /* U+6291 */ + {0xe68a92, 0xd9b3}, /* U+6292 */ + {0xe68a93, 0xd9b4}, /* U+6293 */ + {0xe68a94, 0xd9b8}, /* U+6294 */ + {0xe68a95, 0xc5ea}, /* U+6295 */ + {0xe68a96, 0xd9b5}, /* U+6296 */ + {0xe68a97, 0xb9b3}, /* U+6297 */ + {0xe68a98, 0xc0de}, /* U+6298 */ + {0xe68a99, 0x8fada1}, /* U+6299 [2000] */ + {0xe68a9b, 0xd9c6}, /* U+629B */ + {0xe68a9c, 0xc8b4}, /* U+629C */ + {0xe68a9e, 0xc2f2}, /* U+629E */ + {0xe68aa6, 0x8fada2}, /* U+62A6 [2000] */ + {0xe68aab, 0xc8e4}, /* U+62AB */ + {0xe68aac, 0xdaad}, /* U+62AC */ + {0xe68ab1, 0xcafa}, /* U+62B1 */ + {0xe68ab5, 0xc4f1}, /* U+62B5 */ + {0xe68ab9, 0xcbf5}, /* U+62B9 */ + {0xe68abb, 0xd9bb}, /* U+62BB */ + {0xe68abc, 0xb2a1}, /* U+62BC */ + {0xe68abd, 0xc3ea}, /* U+62BD */ + {0xe68b82, 0xd9c4}, /* U+62C2 */ + {0xe68b84, 0xf4e9}, /* U+62C4 [2000] */ + {0xe68b85, 0xc3b4}, /* U+62C5 */ + {0xe68b86, 0xd9be}, /* U+62C6 */ + {0xe68b87, 0xd9c5}, /* U+62C7 */ + {0xe68b88, 0xd9c0}, /* U+62C8 */ + {0xe68b89, 0xd9c7}, /* U+62C9 */ + {0xe68b8a, 0xd9c3}, /* U+62CA */ + {0xe68b8c, 0xd9c2}, /* U+62CC */ + {0xe68b8d, 0xc7ef}, /* U+62CD */ + {0xe68b8f, 0xd9bc}, /* U+62CF */ + {0xe68b90, 0xb2fd}, /* U+62D0 */ + {0xe68b91, 0xd9ba}, /* U+62D1 */ + {0xe68b92, 0xb5f1}, /* U+62D2 */ + {0xe68b93, 0xc2f3}, /* U+62D3 */ + {0xe68b94, 0xd9b6}, /* U+62D4 */ + {0xe68b95, 0x8fada3}, /* U+62D5 [2000] */ + {0xe68b96, 0xf4ea}, /* U+62D6 [2000] */ + {0xe68b97, 0xd9b9}, /* U+62D7 */ + {0xe68b98, 0xb9b4}, /* U+62D8 */ + {0xe68b99, 0xc0db}, /* U+62D9 */ + {0xe68b9b, 0xbeb7}, /* U+62DB */ + {0xe68b9c, 0xd9c1}, /* U+62DC */ + {0xe68b9d, 0xc7d2}, /* U+62DD */ + {0xe68ba0, 0xb5f2}, /* U+62E0 */ + {0xe68ba1, 0xb3c8}, /* U+62E1 */ + {0xe68bac, 0xb3e7}, /* U+62EC */ + {0xe68bad, 0xbfa1}, /* U+62ED */ + {0xe68bae, 0xd9c9}, /* U+62EE */ + {0xe68baf, 0xd9ce}, /* U+62EF */ + {0xe68bb1, 0xd9ca}, /* U+62F1 */ + {0xe68bb3, 0xb7fd}, /* U+62F3 */ + {0xe68bb5, 0xd9cf}, /* U+62F5 */ + {0xe68bb6, 0xbba2}, /* U+62F6 */ + {0xe68bb7, 0xb9e9}, /* U+62F7 */ + {0xe68bbc, 0xf4eb}, /* U+62FC [2000] */ + {0xe68bbd, 0x8fada5}, /* U+62FD [2000] */ + {0xe68bbe, 0xbda6}, /* U+62FE */ + {0xe68bbf, 0xd9bd}, /* U+62FF */ + {0xe68c81, 0xbbfd}, /* U+6301 */ + {0xe68c82, 0xd9cc}, /* U+6302 */ + {0xe68c83, 0x8fada6}, /* U+6303 [2000] */ + {0xe68c87, 0xbbd8}, /* U+6307 */ + {0xe68c88, 0xd9cd}, /* U+6308 */ + {0xe68c89, 0xb0c4}, /* U+6309 */ + {0xe68c8a, 0xf4ec}, /* U+630A [2000] */ + {0xe68c8c, 0xd9c8}, /* U+630C */ + {0xe68c8d, 0x8fada7}, /* U+630D [2000] */ + {0xe68c90, 0x8fada8}, /* U+6310 [2000] */ + {0xe68c91, 0xc4a9}, /* U+6311 */ + {0xe68c98, 0xf4ed}, /* U+6318 [2000] */ + {0xe68c99, 0xb5f3}, /* U+6319 */ + {0xe68c9f, 0xb6b4}, /* U+631F */ + {0xe68ca7, 0xd9cb}, /* U+6327 */ + {0xe68ca8, 0xb0a7}, /* U+6328 */ + {0xe68cab, 0xbac3}, /* U+632B */ + {0xe68caf, 0xbfb6}, /* U+632F */ + {0xe68cb2, 0x8fadab}, /* U+6332 [2000] */ + {0xe68cb5, 0x8fadac}, /* U+6335 [2000] */ + {0xe68cb9, 0xf4ee}, /* U+6339 [2000] */ + {0xe68cba, 0xc4f2}, /* U+633A */ + {0xe68cbb, 0x8fadad}, /* U+633B [2000] */ + {0xe68cbc, 0x8fadae}, /* U+633C [2000] */ + {0xe68cbd, 0xc8d4}, /* U+633D */ + {0xe68cbe, 0xd9d1}, /* U+633E */ + {0xe68cbf, 0xc1de}, /* U+633F */ + {0xe68d81, 0x8fadaf}, /* U+6341 [2000] */ + {0xe68d83, 0xf4ef}, /* U+6343 [2000] */ + {0xe68d84, 0x8fadb0}, /* U+6344 [2000] */ + {0xe68d89, 0xc2aa}, /* U+6349 */ + {0xe68d8c, 0xbbab}, /* U+634C */ + {0xe68d8d, 0xd9d2}, /* U+634D */ + {0xe68d8e, 0x8fadb1}, /* U+634E [2000] */ + {0xe68d8f, 0xd9d4}, /* U+634F */ + {0xe68d90, 0xd9d0}, /* U+6350 */ + {0xe68d95, 0xcae1}, /* U+6355 */ + {0xe68d97, 0xc4bd}, /* U+6357 */ + {0xe68d99, 0x8fadb3}, /* U+6359 [2000] */ + {0xe68d9c, 0xc1dc}, /* U+635C */ + {0xe68da5, 0xf4f0}, /* U+6365 [2000] */ + {0xe68da7, 0xcafb}, /* U+6367 */ + {0xe68da8, 0xbcce}, /* U+6368 */ + {0xe68da9, 0xd9e0}, /* U+6369 */ + {0xe68dab, 0xd9df}, /* U+636B */ + {0xe68dac, 0x8fadb6}, /* U+636C [2000] */ + {0xe68dae, 0xbff8}, /* U+636E */ + {0xe68db2, 0xb7fe}, /* U+6372 */ + {0xe68db6, 0xd9d9}, /* U+6376 */ + {0xe68db7, 0xbeb9}, /* U+6377 */ + {0xe68dba, 0xc6e8}, /* U+637A */ + {0xe68dbb, 0xc7b1}, /* U+637B */ + {0xe68dbc, 0xf4f1}, /* U+637C [2000] */ + {0xe68e80, 0xd9d7}, /* U+6380 */ + {0xe68e83, 0xc1dd}, /* U+6383 */ + {0xe68e84, 0x8fadb7}, /* U+6384 [2000] */ + {0xe68e88, 0xbcf8}, /* U+6388 */ + {0xe68e89, 0xd9dc}, /* U+6389 */ + {0xe68e8c, 0xbeb8}, /* U+638C */ + {0xe68e8e, 0xd9d6}, /* U+638E */ + {0xe68e8f, 0xd9db}, /* U+638F */ + {0xe68e92, 0xc7d3}, /* U+6392 */ + {0xe68e94, 0x8fadba}, /* U+6394 [2000] */ + {0xe68e96, 0xd9d5}, /* U+6396 */ + {0xe68e98, 0xb7a1}, /* U+6398 */ + {0xe68e99, 0x8fadb8}, /* U+6399 [2000] */ + {0xe68e9b, 0xb3dd}, /* U+639B */ + {0xe68e9f, 0xd9dd}, /* U+639F */ + {0xe68ea0, 0xceab}, /* U+63A0 */ + {0xe68ea1, 0xbace}, /* U+63A1 */ + {0xe68ea2, 0xc3b5}, /* U+63A2 */ + {0xe68ea3, 0xd9da}, /* U+63A3 */ + {0xe68ea5, 0xc0dc}, /* U+63A5 */ + {0xe68ea7, 0xb9b5}, /* U+63A7 */ + {0xe68ea8, 0xbfe4}, /* U+63A8 */ + {0xe68ea9, 0xb1e6}, /* U+63A9 */ + {0xe68eaa, 0xc1bc}, /* U+63AA */ + {0xe68eab, 0xd9d8}, /* U+63AB */ + {0xe68eac, 0xb5c5}, /* U+63AC */ + {0xe68eb2, 0xb7c7}, /* U+63B2 */ + {0xe68eb4, 0xc4cf}, /* U+63B4 */ + {0xe68eb5, 0xd9de}, /* U+63B5 */ + {0xe68ebb, 0xc1df}, /* U+63BB */ + {0xe68ebd, 0x8fadbb}, /* U+63BD [2000] */ + {0xe68ebe, 0xd9e1}, /* U+63BE */ + {0xe68f80, 0xd9e3}, /* U+63C0 */ + {0xe68f83, 0xc2b7}, /* U+63C3 */ + {0xe68f84, 0xd9e9}, /* U+63C4 */ + {0xe68f86, 0xd9e4}, /* U+63C6 */ + {0xe68f89, 0xd9e6}, /* U+63C9 */ + {0xe68f8f, 0xc9c1}, /* U+63CF */ + {0xe68f90, 0xc4f3}, /* U+63D0 */ + {0xe68f92, 0xd9e7}, /* U+63D2 */ + {0xe68f94, 0x8fadbd}, /* U+63D4 [2000] */ + {0xe68f95, 0x8fadbe}, /* U+63D5 [2000] */ + {0xe68f96, 0xcdac}, /* U+63D6 */ + {0xe68f9a, 0xcdc8}, /* U+63DA */ + {0xe68f9b, 0xb4b9}, /* U+63DB */ + {0xe68f9c, 0x8fadbf}, /* U+63DC [2000] */ + {0xe68fa0, 0x8fadc0}, /* U+63E0 [2000] */ + {0xe68fa1, 0xb0ae}, /* U+63E1 */ + {0xe68fa3, 0xd9e5}, /* U+63E3 */ + {0xe68fa5, 0xf4f2}, /* U+63E5 [2000] */ + {0xe68fa9, 0xd9e2}, /* U+63E9 */ + {0xe68fab, 0x8fadc1}, /* U+63EB [2000] */ + {0xe68fac, 0x8fadc2}, /* U+63EC [2000] */ + {0xe68fad, 0xf4f3}, /* U+63ED [2000] */ + {0xe68fae, 0xb4f8}, /* U+63EE */ + {0xe68fb2, 0x8fadc3}, /* U+63F2 [2000] */ + {0xe68fb4, 0xb1e7}, /* U+63F4 */ + {0xe68fb5, 0xf4f4}, /* U+63F5 [2000] */ + {0xe68fb6, 0xd9e8}, /* U+63F6 */ + {0xe68fb7, 0x8fadbc}, /* U+63F7 [2000] */ + {0xe68fba, 0xcdc9}, /* U+63FA */ + {0xe69086, 0xd9ec}, /* U+6406 */ + {0xe69089, 0x8fadc4}, /* U+6409 [2000] */ + {0xe6908d, 0xc2bb}, /* U+640D */ + {0xe6908f, 0xd9f3}, /* U+640F */ + {0xe69090, 0xf4f5}, /* U+6410 [2000] */ + {0xe69093, 0xd9ed}, /* U+6413 */ + {0xe69094, 0xf4f6}, /* U+6414 [2000] */ + {0xe69096, 0xd9ea}, /* U+6416 */ + {0xe69097, 0xd9f1}, /* U+6417 */ + {0xe6909c, 0xd9d3}, /* U+641C */ + {0xe6909e, 0x8fadc5}, /* U+641E [2000] */ + {0xe690a2, 0xf4f7}, /* U+6422 [2000] */ + {0xe690a5, 0x8fadc6}, /* U+6425 [2000] */ + {0xe690a6, 0xd9ee}, /* U+6426 */ + {0xe690a8, 0xd9f2}, /* U+6428 */ + {0xe690a9, 0x8fadc7}, /* U+6429 [2000] */ + {0xe690ac, 0xc8c2}, /* U+642C */ + {0xe690ad, 0xc5eb}, /* U+642D */ + {0xe690af, 0x8fadc8}, /* U+642F [2000] */ + {0xe690b4, 0xd9eb}, /* U+6434 */ + {0xe690b6, 0xd9ef}, /* U+6436 */ + {0xe690ba, 0xb7c8}, /* U+643A */ + {0xe690be, 0xbaf1}, /* U+643E */ + {0xe69182, 0xc0dd}, /* U+6442 */ + {0xe6918e, 0xd9f7}, /* U+644E */ + {0xe69191, 0xf4f9}, /* U+6451 [2000] */ + {0xe69198, 0xc5a6}, /* U+6458 */ + {0xe6919a, 0x8fadc9}, /* U+645A [2000] */ + {0xe6919b, 0x8fadca}, /* U+645B [2000] */ + {0xe6919d, 0x8fadcb}, /* U+645D [2000] */ + {0xe691a0, 0xf4fa}, /* U+6460 [2000] */ + {0xe691a7, 0xd9f4}, /* U+6467 */ + {0xe691a9, 0xcbe0}, /* U+6469 */ + {0xe691ad, 0xf4fb}, /* U+646D [2000] */ + {0xe691af, 0xd9f5}, /* U+646F */ + {0xe691b3, 0x8fadcc}, /* U+6473 [2000] */ + {0xe691b6, 0xd9f6}, /* U+6476 */ + {0xe691b8, 0xccce}, /* U+6478 */ + {0xe691b9, 0xf4f8}, /* U+6479 [2000] */ + {0xe691ba, 0xc0a2}, /* U+647A */ + {0xe691bd, 0x8fadcd}, /* U+647D [2000] */ + {0xe69283, 0xb7e2}, /* U+6483 */ + {0xe69287, 0x8fadce}, /* U+6487 [2000] */ + {0xe69288, 0xd9fd}, /* U+6488 */ + {0xe69291, 0x8fadcf}, /* U+6491 [2000] */ + {0xe69292, 0xbbb5}, /* U+6492 */ + {0xe69293, 0xd9fa}, /* U+6493 */ + {0xe69295, 0xd9f9}, /* U+6495 */ + {0xe6929a, 0xc7b2}, /* U+649A */ + {0xe6929d, 0x8fadd0}, /* U+649D [2000] */ + {0xe6929e, 0xc6b5}, /* U+649E */ + {0xe6929f, 0x8fadd1}, /* U+649F [2000] */ + {0xe692a4, 0xc5b1}, /* U+64A4 */ + {0xe692a5, 0xd9fb}, /* U+64A5 */ + {0xe692a9, 0xd9fc}, /* U+64A9 */ + {0xe692ab, 0xc9ef}, /* U+64AB */ + {0xe692ad, 0xc7c5}, /* U+64AD */ + {0xe692ae, 0xbba3}, /* U+64AE */ + {0xe692b0, 0xc0f1}, /* U+64B0 */ + {0xe692b2, 0xcbd0}, /* U+64B2 */ + {0xe692b9, 0xb3c9}, /* U+64B9 */ + {0xe692bb, 0xdaa5}, /* U+64BB */ + {0xe692bc, 0xd9fe}, /* U+64BC */ + {0xe692be, 0xf4fd}, /* U+64BE [2000] */ + {0xe692bf, 0xf4fe}, /* U+64BF [2000] */ + {0xe69381, 0xcdca}, /* U+64C1 */ + {0xe69382, 0xdaa7}, /* U+64C2 */ + {0xe69384, 0xf5a1}, /* U+64C4 [2000] */ + {0xe69385, 0xdaa3}, /* U+64C5 */ + {0xe69387, 0xdaa4}, /* U+64C7 */ + {0xe6938a, 0xf5a2}, /* U+64CA [2000] */ + {0xe6938b, 0x8fadd2}, /* U+64CB [2000] */ + {0xe6938c, 0x8fadd3}, /* U+64CC [2000] */ + {0xe6938d, 0xc1e0}, /* U+64CD */ + {0xe6938e, 0xf4fc}, /* U+64CE [2000] */ + {0xe69390, 0xf5a3}, /* U+64D0 [2000] */ + {0xe69392, 0xdaa2}, /* U+64D2 */ + {0xe69394, 0xd9bf}, /* U+64D4 */ + {0xe69395, 0x8fadd4}, /* U+64D5 [2000] */ + {0xe69397, 0x8fadd5}, /* U+64D7 [2000] */ + {0xe69398, 0xdaa6}, /* U+64D8 */ + {0xe6939a, 0xdaa1}, /* U+64DA */ + {0xe693a0, 0xdaab}, /* U+64E0 */ + {0xe693a1, 0xdaac}, /* U+64E1 */ + {0xe693a2, 0xc5a7}, /* U+64E2 */ + {0xe693a3, 0xdaae}, /* U+64E3 */ + {0xe693a4, 0x8fadd7}, /* U+64E4 [2000] */ + {0xe693a5, 0x8fadd8}, /* U+64E5 [2000] */ + {0xe693a6, 0xbba4}, /* U+64E6 */ + {0xe693a7, 0xdaa9}, /* U+64E7 */ + {0xe693ac, 0xb5bc}, /* U+64EC */ + {0xe693af, 0xdaaf}, /* U+64EF */ + {0xe693b1, 0xdaa8}, /* U+64F1 */ + {0xe693b2, 0xdab3}, /* U+64F2 */ + {0xe693b4, 0xdab2}, /* U+64F4 */ + {0xe693b6, 0xdab1}, /* U+64F6 */ + {0xe693b7, 0xf5a4}, /* U+64F7 [2000] */ + {0xe693ba, 0xdab4}, /* U+64FA */ + {0xe693bb, 0xf5a5}, /* U+64FB [2000] */ + {0xe693bd, 0xdab6}, /* U+64FD */ + {0xe693be, 0xbef1}, /* U+64FE */ + {0xe693bf, 0x8fadd9}, /* U+64FF [2000] */ + {0xe69480, 0xdab5}, /* U+6500 */ + {0xe69484, 0x8fadda}, /* U+6504 [2000] */ + {0xe69485, 0xdab9}, /* U+6505 */ + {0xe6948f, 0x8faddc}, /* U+650F [2000] */ + {0xe69494, 0x8faddd}, /* U+6514 [2000] */ + {0xe69496, 0x8fadde}, /* U+6516 [2000] */ + {0xe69498, 0xdab7}, /* U+6518 */ + {0xe6949c, 0xdab8}, /* U+651C */ + {0xe6949d, 0xd9f0}, /* U+651D */ + {0xe6949e, 0x8fade0}, /* U+651E [2000] */ + {0xe694a2, 0xf5a6}, /* U+6522 [2000] */ + {0xe694a3, 0xdabb}, /* U+6523 */ + {0xe694a4, 0xdaba}, /* U+6524 */ + {0xe694a9, 0xf5a7}, /* U+6529 [2000] */ + {0xe694aa, 0xd9f8}, /* U+652A */ + {0xe694ab, 0xdabc}, /* U+652B */ + {0xe694ac, 0xdab0}, /* U+652C */ + {0xe694af, 0xbbd9}, /* U+652F */ + {0xe694b2, 0x8fade1}, /* U+6532 [2000] */ + {0xe694b4, 0xdabd}, /* U+6534 */ + {0xe694b5, 0xdabe}, /* U+6535 */ + {0xe694b6, 0xdac0}, /* U+6536 */ + {0xe694b7, 0xdabf}, /* U+6537 */ + {0xe694b8, 0xdac1}, /* U+6538 */ + {0xe694b9, 0xb2fe}, /* U+6539 */ + {0xe694bb, 0xb9b6}, /* U+653B */ + {0xe694be, 0xcafc}, /* U+653E */ + {0xe694bf, 0xc0af}, /* U+653F */ + {0xe69584, 0x8fade2}, /* U+6544 [2000] */ + {0xe69585, 0xb8ce}, /* U+6545 */ + {0xe69588, 0xdac3}, /* U+6548 */ + {0xe6958d, 0xdac6}, /* U+654D */ + {0xe6958f, 0xc9d2}, /* U+654F */ + {0xe69591, 0xb5df}, /* U+6551 */ + {0xe69594, 0x8fade3}, /* U+6554 [2000] */ + {0xe69595, 0xdac5}, /* U+6555 */ + {0xe69596, 0xdac4}, /* U+6556 */ + {0xe69597, 0xc7d4}, /* U+6557 */ + {0xe69598, 0xdac7}, /* U+6558 */ + {0xe69599, 0xb6b5}, /* U+6559 */ + {0xe6959d, 0xdac9}, /* U+655D */ + {0xe6959e, 0xdac8}, /* U+655E */ + {0xe695a2, 0xb4ba}, /* U+6562 */ + {0xe695a3, 0xbbb6}, /* U+6563 */ + {0xe695a6, 0xc6d8}, /* U+6566 */ + {0xe695a7, 0xf5a9}, /* U+6567 [2000] */ + {0xe695ab, 0x8fade4}, /* U+656B [2000] */ + {0xe695ac, 0xb7c9}, /* U+656C */ + {0xe695b0, 0xbff4}, /* U+6570 */ + {0xe695b2, 0xdaca}, /* U+6572 */ + {0xe695b4, 0xc0b0}, /* U+6574 */ + {0xe695b5, 0xc5a8}, /* U+6575 */ + {0xe695b7, 0xc9df}, /* U+6577 */ + {0xe695b8, 0xdacb}, /* U+6578 */ + {0xe695ba, 0x8fade5}, /* U+657A [2000] */ + {0xe69681, 0x8fade6}, /* U+6581 [2000] */ + {0xe69682, 0xdacc}, /* U+6582 */ + {0xe69683, 0xdacd}, /* U+6583 */ + {0xe69684, 0x8fade7}, /* U+6584 [2000] */ + {0xe69685, 0x8fade8}, /* U+6585 [2000] */ + {0xe69687, 0xcab8}, /* U+6587 */ + {0xe69688, 0xd5dd}, /* U+6588 */ + {0xe69689, 0xc0c6}, /* U+6589 */ + {0xe6968a, 0x8fade9}, /* U+658A [2000] */ + {0xe6968c, 0xc9cc}, /* U+658C */ + {0xe6968e, 0xbad8}, /* U+658E */ + {0xe69690, 0xc8e5}, /* U+6590 */ + {0xe69691, 0xc8c3}, /* U+6591 */ + {0xe69697, 0xc5cd}, /* U+6597 */ + {0xe69699, 0xcec1}, /* U+6599 */ + {0xe6969b, 0xdacf}, /* U+659B */ + {0xe6969c, 0xbcd0}, /* U+659C */ + {0xe6969d, 0xf5aa}, /* U+659D [2000] */ + {0xe6969f, 0xdad0}, /* U+659F */ + {0xe696a1, 0xb0b6}, /* U+65A1 */ + {0xe696a4, 0xb6d4}, /* U+65A4 */ + {0xe696a5, 0xc0cd}, /* U+65A5 */ + {0xe696a7, 0xc9e0}, /* U+65A7 */ + {0xe696ab, 0xdad1}, /* U+65AB */ + {0xe696ac, 0xbbc2}, /* U+65AC */ + {0xe696ad, 0xc3c7}, /* U+65AD */ + {0xe696af, 0xbbdb}, /* U+65AF */ + {0xe696b0, 0xbfb7}, /* U+65B0 */ + {0xe696b2, 0x8fadea}, /* U+65B2 [2000] */ + {0xe696b5, 0x8fadeb}, /* U+65B5 [2000] */ + {0xe696b7, 0xdad2}, /* U+65B7 */ + {0xe696b8, 0x8fadec}, /* U+65B8 [2000] */ + {0xe696b9, 0xcafd}, /* U+65B9 */ + {0xe696bc, 0xb1f7}, /* U+65BC */ + {0xe696bd, 0xbbdc}, /* U+65BD */ + {0xe696bf, 0x8faded}, /* U+65BF [2000] */ + {0xe69781, 0xdad5}, /* U+65C1 */ + {0xe69782, 0x8fadee}, /* U+65C2 [2000] */ + {0xe69783, 0xdad3}, /* U+65C3 */ + {0xe69784, 0xdad6}, /* U+65C4 */ + {0xe69785, 0xceb9}, /* U+65C5 */ + {0xe69786, 0xdad4}, /* U+65C6 */ + {0xe69789, 0x8fadef}, /* U+65C9 [2000] */ + {0xe6978b, 0xc0fb}, /* U+65CB */ + {0xe6978c, 0xdad7}, /* U+65CC */ + {0xe6978f, 0xc2b2}, /* U+65CF */ + {0xe69792, 0xdad8}, /* U+65D2 */ + {0xe69794, 0x8fadf0}, /* U+65D4 [2000] */ + {0xe69797, 0xb4fa}, /* U+65D7 */ + {0xe69799, 0xdada}, /* U+65D9 */ + {0xe6979b, 0xdad9}, /* U+65DB */ + {0xe697a0, 0xdadb}, /* U+65E0 */ + {0xe697a1, 0xdadc}, /* U+65E1 */ + {0xe697a2, 0xb4fb}, /* U+65E2 */ + {0xe697a5, 0xc6fc}, /* U+65E5 */ + {0xe697a6, 0xc3b6}, /* U+65E6 */ + {0xe697a7, 0xb5ec}, /* U+65E7 */ + {0xe697a8, 0xbbdd}, /* U+65E8 */ + {0xe697a9, 0xc1e1}, /* U+65E9 */ + {0xe697ac, 0xbddc}, /* U+65EC */ + {0xe697ad, 0xb0b0}, /* U+65ED */ + {0xe697b1, 0xdadd}, /* U+65F1 */ + {0xe697b2, 0x8fadf2}, /* U+65F2 [2000] */ + {0xe697b9, 0x8fadf3}, /* U+65F9 [2000] */ + {0xe697ba, 0xb2a2}, /* U+65FA */ + {0xe697bb, 0xdae1}, /* U+65FB */ + {0xe697bc, 0x8fadf4}, /* U+65FC [2000] */ + {0xe69880, 0xf5ac}, /* U+6600 [2000] */ + {0xe69882, 0xb9b7}, /* U+6602 */ + {0xe69883, 0xdae0}, /* U+6603 */ + {0xe69884, 0x8fadf5}, /* U+6604 [2000] */ + {0xe69886, 0xbaab}, /* U+6606 */ + {0xe69887, 0xbeba}, /* U+6607 */ + {0xe69888, 0x8fadf6}, /* U+6608 [2000] */ + {0xe69889, 0xf5ad}, /* U+6609 [2000] */ + {0xe6988a, 0xdadf}, /* U+660A */ + {0xe6988c, 0xbebb}, /* U+660C */ + {0xe6988e, 0xccc0}, /* U+660E */ + {0xe6988f, 0xbaaa}, /* U+660F */ + {0xe69893, 0xb0d7}, /* U+6613 */ + {0xe69894, 0xc0ce}, /* U+6614 */ + {0xe69895, 0xf5ae}, /* U+6615 [2000] */ + {0xe6989c, 0xdae6}, /* U+661C */ + {0xe6989e, 0xf5af}, /* U+661E [2000] */ + {0xe6989f, 0xc0b1}, /* U+661F */ + {0xe698a0, 0xb1c7}, /* U+6620 */ + {0xe698a1, 0x8fadf7}, /* U+6621 [2000] */ + {0xe698a2, 0xf5b1}, /* U+6622 [2000] */ + {0xe698a4, 0xf5b2}, /* U+6624 [2000] */ + {0xe698a5, 0xbdd5}, /* U+6625 */ + {0xe698a7, 0xcbe6}, /* U+6627 */ + {0xe698a8, 0xbaf2}, /* U+6628 */ + {0xe698aa, 0x8fadf8}, /* U+662A [2000] */ + {0xe698ab, 0xf5b3}, /* U+662B [2000] */ + {0xe698ad, 0xbebc}, /* U+662D */ + {0xe698af, 0xc0a7}, /* U+662F */ + {0xe698b0, 0xf5b4}, /* U+6630 [2000] */ + {0xe698b1, 0xf5b5}, /* U+6631 [2000] */ + {0xe698b3, 0xf5b6}, /* U+6633 [2000] */ + {0xe698b4, 0xdae5}, /* U+6634 */ + {0xe698b5, 0xdae3}, /* U+6635 */ + {0xe698b6, 0xdae4}, /* U+6636 */ + {0xe698ba, 0xf5b0}, /* U+663A [2000] */ + {0xe698bc, 0xc3eb}, /* U+663C */ + {0xe698bf, 0xdba6}, /* U+663F */ + {0xe69981, 0xdaea}, /* U+6641 */ + {0xe69982, 0xbbfe}, /* U+6642 */ + {0xe69983, 0xb9b8}, /* U+6643 */ + {0xe69984, 0xdae8}, /* U+6644 */ + {0xe69985, 0x8fadf9}, /* U+6645 [2000] */ + {0xe69988, 0xf5b8}, /* U+6648 [2000] */ + {0xe69989, 0xdae9}, /* U+6649 */ + {0xe6998b, 0xbfb8}, /* U+664B */ + {0xe6998c, 0xf5b9}, /* U+664C [2000] */ + {0xe6998e, 0x8fadfb}, /* U+664E [2000] */ + {0xe6998f, 0xdae7}, /* U+664F */ + {0xe69991, 0x8fadfa}, /* U+6651 [2000] */ + {0xe69992, 0xbbaf}, /* U+6652 */ + {0xe69997, 0x8fadfe}, /* U+6657 [2000] */ + {0xe69999, 0xf5bb}, /* U+6659 [2000] */ + {0xe6999a, 0xf5bc}, /* U+665A [2000] */ + {0xe6999b, 0x8faea1}, /* U+665B [2000] */ + {0xe6999d, 0xdaec}, /* U+665D */ + {0xe6999e, 0xdaeb}, /* U+665E */ + {0xe6999f, 0xdaf0}, /* U+665F */ + {0xe699a1, 0xf5bd}, /* U+6661 [2000] */ + {0xe699a2, 0xdaf1}, /* U+6662 */ + {0xe699a3, 0x8faea2}, /* U+6663 [2000] */ + {0xe699a4, 0xdaed}, /* U+6664 */ + {0xe699a5, 0xf5be}, /* U+6665 [2000] */ + {0xe699a6, 0xb3a2}, /* U+6666 */ + {0xe699a7, 0xdaee}, /* U+6667 */ + {0xe699a8, 0xdaef}, /* U+6668 */ + {0xe699a9, 0xc8d5}, /* U+6669 */ + {0xe699aa, 0x8faea5}, /* U+666A [2000] */ + {0xe699ab, 0x8faea6}, /* U+666B [2000] */ + {0xe699ac, 0x8faea7}, /* U+666C [2000] */ + {0xe699ad, 0x8faea8}, /* U+666D [2000] */ + {0xe699ae, 0xc9e1}, /* U+666E */ + {0xe699af, 0xb7ca}, /* U+666F */ + {0xe699b0, 0xdaf2}, /* U+6670 */ + {0xe699b3, 0xf5bf}, /* U+6673 [2000] */ + {0xe699b4, 0xc0b2}, /* U+6674 */ + {0xe699b6, 0xbebd}, /* U+6676 */ + {0xe699b7, 0xf5c0}, /* U+6677 [2000] */ + {0xe699b8, 0xf5c1}, /* U+6678 [2000] */ + {0xe699ba, 0xc3d2}, /* U+667A */ + {0xe699bb, 0x8faea9}, /* U+667B [2000] */ + {0xe69a80, 0x8faeaa}, /* U+6680 [2000] */ + {0xe69a81, 0xb6c7}, /* U+6681 */ + {0xe69a83, 0xdaf3}, /* U+6683 */ + {0xe69a84, 0xdaf7}, /* U+6684 */ + {0xe69a87, 0xb2cb}, /* U+6687 */ + {0xe69a88, 0xdaf4}, /* U+6688 */ + {0xe69a89, 0xdaf6}, /* U+6689 */ + {0xe69a8d, 0xf5c2}, /* U+668D [2000] */ + {0xe69a8e, 0xdaf5}, /* U+668E */ + {0xe69a90, 0x8faeab}, /* U+6690 [2000] */ + {0xe69a91, 0xbdeb}, /* U+6691 */ + {0xe69a92, 0x8faeac}, /* U+6692 [2000] */ + {0xe69a96, 0xc3c8}, /* U+6696 */ + {0xe69a97, 0xb0c5}, /* U+6697 */ + {0xe69a98, 0xdaf8}, /* U+6698 */ + {0xe69a99, 0x8faead}, /* U+6699 [2000] */ + {0xe69a9d, 0xdaf9}, /* U+669D */ + {0xe69aa0, 0xf5c4}, /* U+66A0 [2000] */ + {0xe69aa2, 0xc4aa}, /* U+66A2 */ + {0xe69aa6, 0xcef1}, /* U+66A6 */ + {0xe69aab, 0xbbc3}, /* U+66AB */ + {0xe69aad, 0x8faeaf}, /* U+66AD [2000] */ + {0xe69aae, 0xcaeb}, /* U+66AE */ + {0xe69ab1, 0x8faeb0}, /* U+66B1 [2000] */ + {0xe69ab2, 0xf5c5}, /* U+66B2 [2000] */ + {0xe69ab4, 0xcbbd}, /* U+66B4 */ + {0xe69ab5, 0x8faeb1}, /* U+66B5 [2000] */ + {0xe69ab8, 0xdba2}, /* U+66B8 */ + {0xe69ab9, 0xdafb}, /* U+66B9 */ + {0xe69abb, 0xf5c6}, /* U+66BB [2000] */ + {0xe69abc, 0xdafe}, /* U+66BC */ + {0xe69abe, 0xdafd}, /* U+66BE */ + {0xe69abf, 0x8faeb3}, /* U+66BF [2000] */ + {0xe69b81, 0xdafa}, /* U+66C1 */ + {0xe69b84, 0xdba1}, /* U+66C4 */ + {0xe69b86, 0xf5c7}, /* U+66C6 [2000] */ + {0xe69b87, 0xc6de}, /* U+66C7 */ + {0xe69b88, 0xf5c8}, /* U+66C8 [2000] */ + {0xe69b89, 0xdafc}, /* U+66C9 */ + {0xe69b96, 0xdba3}, /* U+66D6 */ + {0xe69b99, 0xbdec}, /* U+66D9 */ + {0xe69b9a, 0xdba4}, /* U+66DA */ + {0xe69b9b, 0xf5ca}, /* U+66DB [2000] */ + {0xe69b9c, 0xcdcb}, /* U+66DC */ + {0xe69b9d, 0xc7f8}, /* U+66DD */ + {0xe69ba0, 0xdba5}, /* U+66E0 */ + {0xe69ba6, 0xdba7}, /* U+66E6 */ + {0xe69ba8, 0xf5cb}, /* U+66E8 [2000] */ + {0xe69ba9, 0xdba8}, /* U+66E9 */ + {0xe69bac, 0x8faeb5}, /* U+66EC [2000] */ + {0xe69bb0, 0xdba9}, /* U+66F0 */ + {0xe69bb2, 0xb6ca}, /* U+66F2 */ + {0xe69bb3, 0xb1c8}, /* U+66F3 */ + {0xe69bb4, 0xb9b9}, /* U+66F4 */ + {0xe69bb5, 0xdbaa}, /* U+66F5 */ + {0xe69bb7, 0xdbab}, /* U+66F7 */ + {0xe69bb8, 0xbdf1}, /* U+66F8 */ + {0xe69bb9, 0xc1e2}, /* U+66F9 */ + {0xe69bba, 0xf5cc}, /* U+66FA [2000] */ + {0xe69bbb, 0xf5b7}, /* U+66FB [2000] */ + {0xe69bbc, 0xd2d8}, /* U+66FC */ + {0xe69bbd, 0xc1be}, /* U+66FD */ + {0xe69bbe, 0xc1bd}, /* U+66FE */ + {0xe69bbf, 0xc2d8}, /* U+66FF */ + {0xe69c80, 0xbac7}, /* U+6700 */ + {0xe69c81, 0x8faeb7}, /* U+6701 [2000] */ + {0xe69c83, 0xd0f2}, /* U+6703 */ + {0xe69c85, 0x8faeb8}, /* U+6705 [2000] */ + {0xe69c88, 0xb7ee}, /* U+6708 */ + {0xe69c89, 0xcdad}, /* U+6709 */ + {0xe69c8b, 0xcafe}, /* U+670B */ + {0xe69c8d, 0xc9fe}, /* U+670D */ + {0xe69c8f, 0xdbac}, /* U+670F */ + {0xe69c92, 0x8faeb9}, /* U+6712 [2000] */ + {0xe69c93, 0xf5cd}, /* U+6713 [2000] */ + {0xe69c94, 0xbaf3}, /* U+6714 */ + {0xe69c95, 0xc4bf}, /* U+6715 */ + {0xe69c96, 0xdbad}, /* U+6716 */ + {0xe69c97, 0xcfaf}, /* U+6717 */ + {0xe69c99, 0x8faebb}, /* U+6719 [2000] */ + {0xe69c9b, 0xcbbe}, /* U+671B */ + {0xe69c9d, 0xc4ab}, /* U+671D */ + {0xe69c9e, 0xdbae}, /* U+671E */ + {0xe69c9f, 0xb4fc}, /* U+671F */ + {0xe69ca6, 0xdbaf}, /* U+6726 */ + {0xe69ca7, 0xdbb0}, /* U+6727 */ + {0xe69ca8, 0xccda}, /* U+6728 */ + {0xe69caa, 0xcca4}, /* U+672A */ + {0xe69cab, 0xcbf6}, /* U+672B */ + {0xe69cac, 0xcbdc}, /* U+672C */ + {0xe69cad, 0xbba5}, /* U+672D */ + {0xe69cae, 0xdbb2}, /* U+672E */ + {0xe69cb1, 0xbceb}, /* U+6731 */ + {0xe69cb3, 0xf5cf}, /* U+6733 [2000] */ + {0xe69cb4, 0xcbd1}, /* U+6734 */ + {0xe69cb6, 0xdbb4}, /* U+6736 */ + {0xe69cb7, 0xdbb7}, /* U+6737 */ + {0xe69cb8, 0xdbb6}, /* U+6738 */ + {0xe69cba, 0xb4f9}, /* U+673A */ + {0xe69cbd, 0xb5e0}, /* U+673D */ + {0xe69cbf, 0xdbb3}, /* U+673F */ + {0xe69d81, 0xdbb5}, /* U+6741 */ + {0xe69d86, 0xdbb8}, /* U+6746 */ + {0xe69d87, 0xf5d1}, /* U+6747 [2000] */ + {0xe69d88, 0xf5d2}, /* U+6748 [2000] */ + {0xe69d89, 0xbff9}, /* U+6749 */ + {0xe69d8c, 0x8faebe}, /* U+674C [2000] */ + {0xe69d8d, 0x8faebf}, /* U+674D [2000] */ + {0xe69d8e, 0xcdfb}, /* U+674E */ + {0xe69d8f, 0xb0c9}, /* U+674F */ + {0xe69d90, 0xbae0}, /* U+6750 */ + {0xe69d91, 0xc2bc}, /* U+6751 */ + {0xe69d93, 0xbcdd}, /* U+6753 */ + {0xe69d94, 0x8faec0}, /* U+6754 [2000] */ + {0xe69d96, 0xbef3}, /* U+6756 */ + {0xe69d99, 0xdbbb}, /* U+6759 */ + {0xe69d9c, 0xc5ce}, /* U+675C */ + {0xe69d9d, 0x8faec1}, /* U+675D [2000] */ + {0xe69d9e, 0xdbb9}, /* U+675E */ + {0xe69d9f, 0xc2ab}, /* U+675F */ + {0xe69da0, 0xdbba}, /* U+6760 */ + {0xe69da1, 0xbef2}, /* U+6761 */ + {0xe69da2, 0xccdd}, /* U+6762 */ + {0xe69da3, 0xdbbc}, /* U+6763 */ + {0xe69da4, 0xdbbd}, /* U+6764 */ + {0xe69da5, 0xcde8}, /* U+6765 */ + {0xe69da6, 0xf5d0}, /* U+6766 [2000] */ + {0xe69daa, 0xdbc2}, /* U+676A */ + {0xe69dad, 0xb9ba}, /* U+676D */ + {0xe69daf, 0xc7d5}, /* U+676F */ + {0xe69db0, 0xdbbf}, /* U+6770 */ + {0xe69db1, 0xc5ec}, /* U+6771 */ + {0xe69db2, 0xdade}, /* U+6772 */ + {0xe69db3, 0xdae2}, /* U+6773 */ + {0xe69db4, 0x8faec5}, /* U+6774 [2000] */ + {0xe69db5, 0xb5cf}, /* U+6775 */ + {0xe69db6, 0x8faec6}, /* U+6776 [2000] */ + {0xe69db7, 0xc7c7}, /* U+6777 */ + {0xe69dbb, 0xf5d3}, /* U+677B [2000] */ + {0xe69dbc, 0xdbc1}, /* U+677C */ + {0xe69dbe, 0xbebe}, /* U+677E */ + {0xe69dbf, 0xc8c4}, /* U+677F */ + {0xe69e81, 0xf5d4}, /* U+6781 [2000] */ + {0xe69e85, 0xdbc7}, /* U+6785 */ + {0xe69e87, 0xc8fa}, /* U+6787 */ + {0xe69e89, 0xdbbe}, /* U+6789 */ + {0xe69e8b, 0xdbc4}, /* U+678B */ + {0xe69e8c, 0xdbc3}, /* U+678C */ + {0xe69e90, 0xc0cf}, /* U+6790 */ + {0xe69e92, 0x8faec8}, /* U+6792 [2000] */ + {0xe69e93, 0xf5d5}, /* U+6793 [2000] */ + {0xe69e95, 0xcbed}, /* U+6795 */ + {0xe69e97, 0xced3}, /* U+6797 */ + {0xe69e98, 0xf5d6}, /* U+6798 [2000] */ + {0xe69e9a, 0xcbe7}, /* U+679A */ + {0xe69e9b, 0xf5d7}, /* U+679B [2000] */ + {0xe69e9c, 0xb2cc}, /* U+679C */ + {0xe69e9d, 0xbbde}, /* U+679D */ + {0xe69ea0, 0xcfc8}, /* U+67A0 */ + {0xe69ea1, 0xdbc6}, /* U+67A1 */ + {0xe69ea2, 0xbff5}, /* U+67A2 */ + {0xe69ea6, 0xdbc5}, /* U+67A6 */ + {0xe69ea9, 0xdbc0}, /* U+67A9 */ + {0xe69eaf, 0xb8cf}, /* U+67AF */ + {0xe69eb0, 0x8faecc}, /* U+67B0 [2000] */ + {0xe69eb2, 0x8faecd}, /* U+67B2 [2000] */ + {0xe69eb3, 0xdbcc}, /* U+67B3 */ + {0xe69eb4, 0xdbca}, /* U+67B4 */ + {0xe69eb6, 0xb2cd}, /* U+67B6 */ + {0xe69eb7, 0xdbc8}, /* U+67B7 */ + {0xe69eb8, 0xdbce}, /* U+67B8 */ + {0xe69eb9, 0xdbd4}, /* U+67B9 */ + {0xe69ebb, 0xf5d8}, /* U+67BB [2000] */ + {0xe69f80, 0xf5da}, /* U+67C0 [2000] */ + {0xe69f81, 0xc2c8}, /* U+67C1 */ + {0xe69f83, 0x8faece}, /* U+67C3 [2000] */ + {0xe69f84, 0xcac1}, /* U+67C4 */ + {0xe69f86, 0xdbd6}, /* U+67C6 */ + {0xe69f88, 0x8faecf}, /* U+67C8 [2000] */ + {0xe69f8a, 0xc9a2}, /* U+67CA */ + {0xe69f8e, 0xdbd5}, /* U+67CE */ + {0xe69f8f, 0xc7f0}, /* U+67CF */ + {0xe69f90, 0xcbbf}, /* U+67D0 */ + {0xe69f91, 0xb4bb}, /* U+67D1 */ + {0xe69f92, 0x8faed0}, /* U+67D2 [2000] */ + {0xe69f93, 0xc0f7}, /* U+67D3 */ + {0xe69f94, 0xbdc0}, /* U+67D4 */ + {0xe69f97, 0xf5db}, /* U+67D7 [2000] */ + {0xe69f98, 0xc4d3}, /* U+67D8 */ + {0xe69f99, 0x8faed1}, /* U+67D9 [2000] */ + {0xe69f9a, 0xcdae}, /* U+67DA */ + {0xe69f9b, 0x8faed2}, /* U+67DB [2000] */ + {0xe69f9d, 0xdbd1}, /* U+67DD */ + {0xe69f9e, 0xdbd0}, /* U+67DE */ + {0xe69fa2, 0xdbd2}, /* U+67E2 */ + {0xe69fa4, 0xdbcf}, /* U+67E4 */ + {0xe69fa7, 0xdbd7}, /* U+67E7 */ + {0xe69fa9, 0xdbcd}, /* U+67E9 */ + {0xe69fac, 0xdbcb}, /* U+67EC */ + {0xe69fae, 0xdbd3}, /* U+67EE */ + {0xe69faf, 0xdbc9}, /* U+67EF */ + {0xe69fb0, 0x8faed3}, /* U+67F0 [2000] */ + {0xe69fb1, 0xc3ec}, /* U+67F1 */ + {0xe69fb3, 0xccf8}, /* U+67F3 */ + {0xe69fb4, 0xbcc6}, /* U+67F4 */ + {0xe69fb5, 0xbaf4}, /* U+67F5 */ + {0xe69fb7, 0x8faed4}, /* U+67F7 [2000] */ + {0xe69fb9, 0xf5d9}, /* U+67F9 [2000] */ + {0xe69fbb, 0xbaba}, /* U+67FB */ + {0xe69fbc, 0xf5dc}, /* U+67FC [2000] */ + {0xe69fbe, 0xcbef}, /* U+67FE */ + {0xe69fbf, 0xb3c1}, /* U+67FF */ + {0xe6a081, 0xf5dd}, /* U+6801 [2000] */ + {0xe6a082, 0xc4ce}, /* U+6802 */ + {0xe6a083, 0xc6ca}, /* U+6803 */ + {0xe6a084, 0xb1c9}, /* U+6804 */ + {0xe6a090, 0x8faecb}, /* U+6810 [2000] */ + {0xe6a093, 0xc0f2}, /* U+6813 */ + {0xe6a096, 0xc0b4}, /* U+6816 */ + {0xe6a097, 0xb7aa}, /* U+6817 */ + {0xe6a098, 0x8faed8}, /* U+6818 [2000] */ + {0xe6a09d, 0xf5df}, /* U+681D [2000] */ + {0xe6a09e, 0xdbd9}, /* U+681E */ + {0xe6a09f, 0x8faed9}, /* U+681F [2000] */ + {0xe6a0a1, 0xb9bb}, /* U+6821 */ + {0xe6a0a2, 0xb3fc}, /* U+6822 */ + {0xe6a0a9, 0xdbdb}, /* U+6829 */ + {0xe6a0aa, 0xb3f4}, /* U+682A */ + {0xe6a0ab, 0xdbe1}, /* U+682B */ + {0xe6a0ac, 0xf5e0}, /* U+682C [2000] */ + {0xe6a0ad, 0x8faeda}, /* U+682D [2000] */ + {0xe6a0b1, 0xf5e1}, /* U+6831 [2000] */ + {0xe6a0b2, 0xdbde}, /* U+6832 */ + {0xe6a0b3, 0x8faedc}, /* U+6833 [2000] */ + {0xe6a0b4, 0xc0f3}, /* U+6834 */ + {0xe6a0b8, 0xb3cb}, /* U+6838 */ + {0xe6a0b9, 0xbaac}, /* U+6839 */ + {0xe6a0bb, 0x8faedd}, /* U+683B [2000] */ + {0xe6a0bc, 0xb3ca}, /* U+683C */ + {0xe6a0bd, 0xbacf}, /* U+683D */ + {0xe6a0be, 0x8faede}, /* U+683E [2000] */ + {0xe6a180, 0xdbdc}, /* U+6840 */ + {0xe6a181, 0xb7e5}, /* U+6841 */ + {0xe6a182, 0xb7cb}, /* U+6842 */ + {0xe6a183, 0xc5ed}, /* U+6843 */ + {0xe6a184, 0x8faedf}, /* U+6844 [2000] */ + {0xe6a185, 0x8faee0}, /* U+6845 [2000] */ + {0xe6a186, 0xdbda}, /* U+6846 */ + {0xe6a188, 0xb0c6}, /* U+6848 */ + {0xe6a189, 0x8faee1}, /* U+6849 [2000] */ + {0xe6a18c, 0x8faee2}, /* U+684C [2000] */ + {0xe6a18d, 0xdbdd}, /* U+684D */ + {0xe6a18e, 0xdbdf}, /* U+684E */ + {0xe6a190, 0xb6cd}, /* U+6850 */ + {0xe6a191, 0xb7ac}, /* U+6851 */ + {0xe6a192, 0xf5de}, /* U+6852 [2000] */ + {0xe6a193, 0xb4bc}, /* U+6853 */ + {0xe6a194, 0xb5cb}, /* U+6854 */ + {0xe6a195, 0x8faee3}, /* U+6855 [2000] */ + {0xe6a197, 0x8faee4}, /* U+6857 [2000] */ + {0xe6a199, 0xdbe2}, /* U+6859 */ + {0xe6a19b, 0xf5e2}, /* U+685B [2000] */ + {0xe6a19c, 0xbaf9}, /* U+685C */ + {0xe6a19d, 0xcbf1}, /* U+685D */ + {0xe6a19f, 0xbbb7}, /* U+685F */ + {0xe6a1a3, 0xdbe3}, /* U+6863 */ + {0xe6a1a7, 0xc9b0}, /* U+6867 */ + {0xe6a1ab, 0x8faee6}, /* U+686B [2000] */ + {0xe6a1ae, 0x8faee7}, /* U+686E [2000] */ + {0xe6a1b2, 0xf5e3}, /* U+6872 [2000] */ + {0xe6a1b4, 0xdbef}, /* U+6874 */ + {0xe6a1b5, 0xf5e4}, /* U+6875 [2000] */ + {0xe6a1b6, 0xb2b3}, /* U+6876 */ + {0xe6a1b7, 0xdbe4}, /* U+6877 */ + {0xe6a1ba, 0x8faee8}, /* U+687A [2000] */ + {0xe6a1bc, 0x8faee9}, /* U+687C [2000] */ + {0xe6a1be, 0xdbf5}, /* U+687E */ + {0xe6a1bf, 0xdbe5}, /* U+687F */ + {0xe6a281, 0xcec2}, /* U+6881 */ + {0xe6a282, 0x8faeea}, /* U+6882 [2000] */ + {0xe6a283, 0xdbec}, /* U+6883 */ + {0xe6a285, 0xc7df}, /* U+6885 */ + {0xe6a28d, 0xdbf4}, /* U+688D */ + {0xe6a28f, 0xdbe7}, /* U+688F */ + {0xe6a290, 0x8faeeb}, /* U+6890 [2000] */ + {0xe6a293, 0xb0b4}, /* U+6893 */ + {0xe6a294, 0xdbe9}, /* U+6894 */ + {0xe6a296, 0x8faeec}, /* U+6896 [2000] */ + {0xe6a297, 0xb9bc}, /* U+6897 */ + {0xe6a298, 0x8faeee}, /* U+6898 [2000] */ + {0xe6a299, 0x8faeef}, /* U+6899 [2000] */ + {0xe6a29a, 0x8faef0}, /* U+689A [2000] */ + {0xe6a29b, 0xdbeb}, /* U+689B */ + {0xe6a29c, 0x8faef1}, /* U+689C [2000] */ + {0xe6a29d, 0xdbea}, /* U+689D */ + {0xe6a29f, 0xdbe6}, /* U+689F */ + {0xe6a2a0, 0xdbf1}, /* U+68A0 */ + {0xe6a2a2, 0xbebf}, /* U+68A2 */ + {0xe6a2a3, 0xf5e6}, /* U+68A3 [2000] */ + {0xe6a2a5, 0xf5e7}, /* U+68A5 [2000] */ + {0xe6a2a6, 0xd4ed}, /* U+68A6 */ + {0xe6a2a7, 0xb8e8}, /* U+68A7 */ + {0xe6a2a8, 0xcdfc}, /* U+68A8 */ + {0xe6a2aa, 0x8faef2}, /* U+68AA [2000] */ + {0xe6a2ab, 0x8faef3}, /* U+68AB [2000] */ + {0xe6a2ad, 0xdbe8}, /* U+68AD */ + {0xe6a2af, 0xc4f4}, /* U+68AF */ + {0xe6a2b0, 0xb3a3}, /* U+68B0 */ + {0xe6a2b1, 0xbaad}, /* U+68B1 */ + {0xe6a2b2, 0xf5e8}, /* U+68B2 [2000] */ + {0xe6a2b3, 0xdbe0}, /* U+68B3 */ + {0xe6a2b4, 0x8faef4}, /* U+68B4 [2000] */ + {0xe6a2b5, 0xdbf0}, /* U+68B5 */ + {0xe6a2b6, 0xb3e1}, /* U+68B6 */ + {0xe6a2b9, 0xdbee}, /* U+68B9 */ + {0xe6a2ba, 0xdbf2}, /* U+68BA */ + {0xe6a2bb, 0x8faef5}, /* U+68BB [2000] */ + {0xe6a2bc, 0xc5ee}, /* U+68BC */ + {0xe6a383, 0x8faefa}, /* U+68C3 [2000] */ + {0xe6a384, 0xb4fe}, /* U+68C4 */ + {0xe6a385, 0x8faefb}, /* U+68C5 [2000] */ + {0xe6a386, 0xdcb2}, /* U+68C6 */ + {0xe6a388, 0xf5e9}, /* U+68C8 [2000] */ + {0xe6a389, 0xccc9}, /* U+68C9 */ + {0xe6a38a, 0xdbf7}, /* U+68CA */ + {0xe6a38b, 0xb4fd}, /* U+68CB */ + {0xe6a38c, 0x8faefc}, /* U+68CC [2000] */ + {0xe6a38d, 0xdbfe}, /* U+68CD */ + {0xe6a38f, 0x8faefd}, /* U+68CF [2000] */ + {0xe6a390, 0xf5ea}, /* U+68D0 [2000] */ + {0xe6a392, 0xcbc0}, /* U+68D2 */ + {0xe6a394, 0xdca1}, /* U+68D4 */ + {0xe6a395, 0xdca3}, /* U+68D5 */ + {0xe6a396, 0x8faefe}, /* U+68D6 [2000] */ + {0xe6a397, 0xdca7}, /* U+68D7 */ + {0xe6a398, 0xdbf9}, /* U+68D8 */ + {0xe6a399, 0x8fafa1}, /* U+68D9 [2000] */ + {0xe6a39a, 0xc3aa}, /* U+68DA */ + {0xe6a39f, 0xc5ef}, /* U+68DF */ + {0xe6a3a0, 0xdcab}, /* U+68E0 */ + {0xe6a3a1, 0xdbfc}, /* U+68E1 */ + {0xe6a3a3, 0xdca8}, /* U+68E3 */ + {0xe6a3a4, 0x8fafa2}, /* U+68E4 [2000] */ + {0xe6a3a5, 0x8fafa3}, /* U+68E5 [2000] */ + {0xe6a3a7, 0xdca2}, /* U+68E7 */ + {0xe6a3a8, 0xf5eb}, /* U+68E8 [2000] */ + {0xe6a3ac, 0x8fafa4}, /* U+68EC [2000] */ + {0xe6a3ad, 0xf5ec}, /* U+68ED [2000] */ + {0xe6a3ae, 0xbfb9}, /* U+68EE */ + {0xe6a3af, 0xdcac}, /* U+68EF */ + {0xe6a3b0, 0xf5ed}, /* U+68F0 [2000] */ + {0xe6a3b1, 0xf5ee}, /* U+68F1 [2000] */ + {0xe6a3b2, 0xc0b3}, /* U+68F2 */ + {0xe6a3b7, 0x8fafa5}, /* U+68F7 [2000] */ + {0xe6a3b9, 0xdcaa}, /* U+68F9 */ + {0xe6a3ba, 0xb4bd}, /* U+68FA */ + {0xe6a3bb, 0x8faef6}, /* U+68FB [2000] */ + {0xe6a3bc, 0xf5ef}, /* U+68FC [2000] */ + {0xe6a480, 0xcfd0}, /* U+6900 */ + {0xe6a481, 0xdbf6}, /* U+6901 */ + {0xe6a483, 0x8fafa6}, /* U+6903 [2000] */ + {0xe6a484, 0xdca6}, /* U+6904 */ + {0xe6a485, 0xb0d8}, /* U+6905 */ + {0xe6a487, 0x8fafa7}, /* U+6907 [2000] */ + {0xe6a488, 0xdbf8}, /* U+6908 */ + {0xe6a48a, 0xf5f0}, /* U+690A [2000] */ + {0xe6a48b, 0xccba}, /* U+690B */ + {0xe6a48c, 0xdbfd}, /* U+690C */ + {0xe6a48d, 0xbfa2}, /* U+690D */ + {0xe6a48e, 0xc4c7}, /* U+690E */ + {0xe6a48f, 0xdbf3}, /* U+690F */ + {0xe6a492, 0xdca5}, /* U+6912 */ + {0xe6a499, 0xbffa}, /* U+6919 */ + {0xe6a49a, 0xdcaf}, /* U+691A */ + {0xe6a49b, 0xb3f1}, /* U+691B */ + {0xe6a49c, 0xb8a1}, /* U+691C */ + {0xe6a4a1, 0xdcb1}, /* U+6921 */ + {0xe6a4a2, 0xdbfa}, /* U+6922 */ + {0xe6a4a3, 0xdcb0}, /* U+6923 */ + {0xe6a4a5, 0xdca9}, /* U+6925 */ + {0xe6a4a6, 0xdbfb}, /* U+6926 */ + {0xe6a4a8, 0xdcad}, /* U+6928 */ + {0xe6a4aa, 0xdcae}, /* U+692A */ + {0xe6a4b0, 0xdcbf}, /* U+6930 */ + {0xe6a4b4, 0xc6ce}, /* U+6934 */ + {0xe6a4b5, 0xf5f3}, /* U+6935 [2000] */ + {0xe6a4b6, 0xdca4}, /* U+6936 */ + {0xe6a4b9, 0xdcbb}, /* U+6939 */ + {0xe6a4bb, 0x8fafab}, /* U+693B [2000] */ + {0xe6a4bd, 0xdcbd}, /* U+693D */ + {0xe6a4bf, 0xc4d8}, /* U+693F */ + {0xe6a582, 0xf5f4}, /* U+6942 [2000] */ + {0xe6a586, 0x8fafad}, /* U+6946 [2000] */ + {0xe6a589, 0xf5f1}, /* U+6949 [2000] */ + {0xe6a58a, 0xcdcc}, /* U+694A */ + {0xe6a593, 0xc9f6}, /* U+6953 */ + {0xe6a594, 0xdcb8}, /* U+6954 */ + {0xe6a595, 0xc2ca}, /* U+6955 */ + {0xe6a597, 0xf5f5}, /* U+6957 [2000] */ + {0xe6a599, 0xdcbe}, /* U+6959 */ + {0xe6a59a, 0xc1bf}, /* U+695A */ + {0xe6a59c, 0xdcb5}, /* U+695C */ + {0xe6a59d, 0xdcc2}, /* U+695D */ + {0xe6a59e, 0xdcc1}, /* U+695E */ + {0xe6a5a0, 0xc6ef}, /* U+6960 */ + {0xe6a5a1, 0xdcc0}, /* U+6961 */ + {0xe6a5a2, 0xc6ea}, /* U+6962 */ + {0xe6a5a3, 0xf5f6}, /* U+6963 [2000] */ + {0xe6a5a4, 0xf5f7}, /* U+6964 [2000] */ + {0xe6a5a8, 0xf5f8}, /* U+6968 [2000] */ + {0xe6a5a9, 0x8fafae}, /* U+6969 [2000] */ + {0xe6a5aa, 0xdcc4}, /* U+696A */ + {0xe6a5ab, 0xdcb7}, /* U+696B */ + {0xe6a5ac, 0x8fafaf}, /* U+696C [2000] */ + {0xe6a5ad, 0xb6c8}, /* U+696D */ + {0xe6a5ae, 0xdcba}, /* U+696E */ + {0xe6a5af, 0xbddd}, /* U+696F */ + {0xe6a5b2, 0x8fafb0}, /* U+6972 [2000] */ + {0xe6a5b3, 0xc7e0}, /* U+6973 */ + {0xe6a5b4, 0xdcbc}, /* U+6974 */ + {0xe6a5b5, 0xb6cb}, /* U+6975 */ + {0xe6a5b7, 0xdcb4}, /* U+6977 */ + {0xe6a5b8, 0xdcb6}, /* U+6978 */ + {0xe6a5b9, 0xdcb3}, /* U+6979 */ + {0xe6a5ba, 0x8fafb1}, /* U+697A [2000] */ + {0xe6a5bc, 0xcfb0}, /* U+697C */ + {0xe6a5bd, 0xb3da}, /* U+697D */ + {0xe6a5be, 0xdcb9}, /* U+697E */ + {0xe6a5bf, 0x8fafb2}, /* U+697F [2000] */ + {0xe6a680, 0xf5f9}, /* U+6980 [2000] */ + {0xe6a681, 0xdcc3}, /* U+6981 */ + {0xe6a682, 0xb3b5}, /* U+6982 */ + {0xe6a68a, 0xbae7}, /* U+698A */ + {0xe6a68e, 0xb1dd}, /* U+698E */ + {0xe6a691, 0xdcd4}, /* U+6991 */ + {0xe6a692, 0x8fafb3}, /* U+6992 [2000] */ + {0xe6a694, 0xcfb1}, /* U+6994 */ + {0xe6a695, 0xdcd7}, /* U+6995 */ + {0xe6a696, 0x8fafb5}, /* U+6996 [2000] */ + {0xe6a698, 0x8fafb6}, /* U+6998 [2000] */ + {0xe6a69b, 0xbfba}, /* U+699B */ + {0xe6a69c, 0xdcd6}, /* U+699C */ + {0xe6a6a0, 0xdcd5}, /* U+69A0 */ + {0xe6a6a5, 0xf5fb}, /* U+69A5 [2000] */ + {0xe6a6a6, 0x8fafb7}, /* U+69A6 [2000] */ + {0xe6a6a7, 0xdcd2}, /* U+69A7 */ + {0xe6a6ad, 0xf5fc}, /* U+69AD [2000] */ + {0xe6a6ae, 0xdcc6}, /* U+69AE */ + {0xe6a6b0, 0x8fafb8}, /* U+69B0 [2000] */ + {0xe6a6b1, 0xdce3}, /* U+69B1 */ + {0xe6a6b2, 0xdcc5}, /* U+69B2 */ + {0xe6a6b4, 0xdcd8}, /* U+69B4 */ + {0xe6a6b7, 0x8fafb9}, /* U+69B7 [2000] */ + {0xe6a6ba, 0x8fafba}, /* U+69BA [2000] */ + {0xe6a6bb, 0xdcd0}, /* U+69BB */ + {0xe6a6bc, 0x8fafbb}, /* U+69BC [2000] */ + {0xe6a6be, 0xdccb}, /* U+69BE */ + {0xe6a6bf, 0xdcc8}, /* U+69BF */ + {0xe6a780, 0x8fafbc}, /* U+69C0 [2000] */ + {0xe6a781, 0xdcc9}, /* U+69C1 */ + {0xe6a783, 0xdcd1}, /* U+69C3 */ + {0xe6a787, 0xf4a2}, /* U+69C7 [1983] */ + {0xe6a78a, 0xdcce}, /* U+69CA */ + {0xe6a78b, 0xb9bd}, /* U+69CB */ + {0xe6a78c, 0xc4c8}, /* U+69CC */ + {0xe6a78d, 0xc1e4}, /* U+69CD */ + {0xe6a78e, 0xdccc}, /* U+69CE */ + {0xe6a78f, 0xf5fd}, /* U+69CF [2000] */ + {0xe6a790, 0xdcc7}, /* U+69D0 */ + {0xe6a791, 0x8fafbd}, /* U+69D1 [2000] */ + {0xe6a793, 0xdcca}, /* U+69D3 */ + {0xe6a796, 0x8fafbe}, /* U+69D6 [2000] */ + {0xe6a798, 0xcdcd}, /* U+69D8 */ + {0xe6a799, 0xcbea}, /* U+69D9 */ + {0xe6a79d, 0xdccf}, /* U+69DD */ + {0xe6a79e, 0xdcd9}, /* U+69DE */ + {0xe6a7a2, 0xf6a2}, /* U+69E2 [2000] */ + {0xe6a7a3, 0x8fafc4}, /* U+69E3 [2000] */ + {0xe6a7a7, 0xdce1}, /* U+69E7 */ + {0xe6a7a8, 0xdcda}, /* U+69E8 */ + {0xe6a7a9, 0xf6a3}, /* U+69E9 [2000] */ + {0xe6a7aa, 0xf6a4}, /* U+69EA [2000] */ + {0xe6a7ab, 0xdce7}, /* U+69EB */ + {0xe6a7ad, 0xdce5}, /* U+69ED */ + {0xe6a7ae, 0x8fafc5}, /* U+69EE [2000] */ + {0xe6a7af, 0x8fafc6}, /* U+69EF [2000] */ + {0xe6a7b2, 0xdce0}, /* U+69F2 */ + {0xe6a7b3, 0x8fafc7}, /* U+69F3 [2000] */ + {0xe6a7b4, 0x8fafc9}, /* U+69F4 [2000] */ + {0xe6a7b5, 0xf6a5}, /* U+69F5 [2000] */ + {0xe6a7b6, 0xf6a6}, /* U+69F6 [2000] */ + {0xe6a7b9, 0xdcdf}, /* U+69F9 */ + {0xe6a7bb, 0xc4d0}, /* U+69FB */ + {0xe6a7bd, 0xc1e5}, /* U+69FD */ + {0xe6a7be, 0x8fafca}, /* U+69FE [2000] */ + {0xe6a7bf, 0xdcdd}, /* U+69FF */ + {0xe6a882, 0xdcdb}, /* U+6A02 */ + {0xe6a885, 0xdce2}, /* U+6A05 */ + {0xe6a88a, 0xdce8}, /* U+6A0A */ + {0xe6a88b, 0xc8f5}, /* U+6A0B */ + {0xe6a88c, 0xdcee}, /* U+6A0C */ + {0xe6a88f, 0xf6a7}, /* U+6A0F [2000] */ + {0xe6a891, 0x8fafcb}, /* U+6A11 [2000] */ + {0xe6a892, 0xdce9}, /* U+6A12 */ + {0xe6a893, 0xdcec}, /* U+6A13 */ + {0xe6a894, 0xdce6}, /* U+6A14 */ + {0xe6a895, 0xf6a8}, /* U+6A15 [2000] */ + {0xe6a897, 0xc3f4}, /* U+6A17 */ + {0xe6a899, 0xc9b8}, /* U+6A19 */ + {0xe6a89a, 0x8fafcc}, /* U+6A1A [2000] */ + {0xe6a89b, 0xdcdc}, /* U+6A1B */ + {0xe6a89d, 0x8fafcd}, /* U+6A1D [2000] */ + {0xe6a89e, 0xdce4}, /* U+6A1E */ + {0xe6a89f, 0xbec0}, /* U+6A1F */ + {0xe6a8a1, 0xcccf}, /* U+6A21 */ + {0xe6a8a2, 0xdcf8}, /* U+6A22 */ + {0xe6a8a3, 0xdceb}, /* U+6A23 */ + {0xe6a8a9, 0xb8a2}, /* U+6A29 */ + {0xe6a8aa, 0xb2a3}, /* U+6A2A */ + {0xe6a8ab, 0xb3df}, /* U+6A2B */ + {0xe6a8ae, 0xdcd3}, /* U+6A2E */ + {0xe6a8b0, 0x8fafc1}, /* U+6A30 [2000] */ + {0xe6a8b2, 0x8fafcf}, /* U+6A32 [2000] */ + {0xe6a8b3, 0x8fafd0}, /* U+6A33 [2000] */ + {0xe6a8b4, 0x8fafd1}, /* U+6A34 [2000] */ + {0xe6a8b5, 0xbec1}, /* U+6A35 */ + {0xe6a8b6, 0xdcf0}, /* U+6A36 */ + {0xe6a8b8, 0xdcf7}, /* U+6A38 */ + {0xe6a8b9, 0xbcf9}, /* U+6A39 */ + {0xe6a8ba, 0xb3f2}, /* U+6A3A */ + {0xe6a8bb, 0xf6aa}, /* U+6A3B [2000] */ + {0xe6a8bd, 0xc3ae}, /* U+6A3D */ + {0xe6a8be, 0xf6ab}, /* U+6A3E [2000] */ + {0xe6a8bf, 0x8fafd2}, /* U+6A3F [2000] */ + {0xe6a984, 0xdced}, /* U+6A44 */ + {0xe6a985, 0xf6ac}, /* U+6A45 [2000] */ + {0xe6a986, 0x8fafd3}, /* U+6A46 [2000] */ + {0xe6a987, 0xdcf2}, /* U+6A47 */ + {0xe6a988, 0xdcf6}, /* U+6A48 */ + {0xe6a989, 0x8fafd4}, /* U+6A49 [2000] */ + {0xe6a98b, 0xb6b6}, /* U+6A4B */ + {0xe6a98e, 0x8fafd6}, /* U+6A4E [2000] */ + {0xe6a990, 0xf6ad}, /* U+6A50 [2000] */ + {0xe6a992, 0x8fafd7}, /* U+6A52 [2000] */ + {0xe6a996, 0xf6ae}, /* U+6A56 [2000] */ + {0xe6a998, 0xb5cc}, /* U+6A58 */ + {0xe6a999, 0xdcf4}, /* U+6A59 */ + {0xe6a99b, 0xf6af}, /* U+6A5B [2000] */ + {0xe6a99f, 0xb5a1}, /* U+6A5F */ + {0xe6a9a1, 0xc6cb}, /* U+6A61 */ + {0xe6a9a2, 0xdcf3}, /* U+6A62 */ + {0xe6a9a4, 0x8fafd8}, /* U+6A64 [2000] */ + {0xe6a9a6, 0xdcf5}, /* U+6A66 */ + {0xe6a9ab, 0xf6b0}, /* U+6A6B [2000] */ + {0xe6a9b2, 0xdcef}, /* U+6A72 */ + {0xe6a9b3, 0xf6b1}, /* U+6A73 [2000] */ + {0xe6a9b8, 0xdcf1}, /* U+6A78 */ + {0xe6a9ba, 0x8fafd5}, /* U+6A7A [2000] */ + {0xe6a9be, 0x8fafda}, /* U+6A7E [2000] */ + {0xe6a9bf, 0xb3e0}, /* U+6A7F */ + {0xe6aa80, 0xc3c9}, /* U+6A80 */ + {0xe6aa83, 0x8fafdb}, /* U+6A83 [2000] */ + {0xe6aa84, 0xdcfc}, /* U+6A84 */ + {0xe6aa89, 0xf6b3}, /* U+6A89 [2000] */ + {0xe6aa8b, 0x8fafdc}, /* U+6A8B [2000] */ + {0xe6aa8d, 0xdcfa}, /* U+6A8D */ + {0xe6aa8e, 0xb8e9}, /* U+6A8E */ + {0xe6aa90, 0xdcf9}, /* U+6A90 */ + {0xe6aa91, 0x8fafde}, /* U+6A91 [2000] */ + {0xe6aa94, 0xf6b4}, /* U+6A94 [2000] */ + {0xe6aa97, 0xdda1}, /* U+6A97 */ + {0xe6aa9c, 0xdbd8}, /* U+6A9C */ + {0xe6aa9d, 0xf6b5}, /* U+6A9D [2000] */ + {0xe6aa9e, 0xf6b6}, /* U+6A9E [2000] */ + {0xe6aa9f, 0x8fafdf}, /* U+6A9F [2000] */ + {0xe6aaa0, 0xdcfb}, /* U+6AA0 */ + {0xe6aaa1, 0x8fafe0}, /* U+6AA1 [2000] */ + {0xe6aaa2, 0xdcfd}, /* U+6AA2 */ + {0xe6aaa3, 0xdcfe}, /* U+6AA3 */ + {0xe6aaa5, 0xf6b7}, /* U+6AA5 [2000] */ + {0xe6aaaa, 0xddac}, /* U+6AAA */ + {0xe6aaab, 0x8fafe2}, /* U+6AAB [2000] */ + {0xe6aaac, 0xdda8}, /* U+6AAC */ + {0xe6aaae, 0xdbed}, /* U+6AAE */ + {0xe6aab3, 0xdda7}, /* U+6AB3 */ + {0xe6aab8, 0xdda6}, /* U+6AB8 */ + {0xe6aabb, 0xdda3}, /* U+6ABB */ + {0xe6aabd, 0x8fafe3}, /* U+6ABD [2000] */ + {0xe6ab81, 0xdcea}, /* U+6AC1 */ + {0xe6ab82, 0xdda5}, /* U+6AC2 */ + {0xe6ab83, 0xdda4}, /* U+6AC3 */ + {0xe6ab86, 0x8fafe4}, /* U+6AC6 [2000] */ + {0xe6ab90, 0x8fafe6}, /* U+6AD0 [2000] */ + {0xe6ab91, 0xddaa}, /* U+6AD1 */ + {0xe6ab93, 0xcfa6}, /* U+6AD3 */ + {0xe6ab94, 0x8fafe5}, /* U+6AD4 [2000] */ + {0xe6ab9a, 0xddad}, /* U+6ADA */ + {0xe6ab9b, 0xb6fb}, /* U+6ADB */ + {0xe6ab9c, 0x8fafe7}, /* U+6ADC [2000] */ + {0xe6ab9d, 0x8fafe8}, /* U+6ADD [2000] */ + {0xe6ab9e, 0xdda9}, /* U+6ADE */ + {0xe6ab9f, 0xddab}, /* U+6ADF */ + {0xe6aba4, 0xf6b8}, /* U+6AE4 [2000] */ + {0xe6aba7, 0xf6b9}, /* U+6AE7 [2000] */ + {0xe6aba8, 0xc8a7}, /* U+6AE8 */ + {0xe6abaa, 0xddae}, /* U+6AEA */ + {0xe6abac, 0x8fafeb}, /* U+6AEC [2000] */ + {0xe6abb1, 0x8fafec}, /* U+6AF1 [2000] */ + {0xe6abb2, 0x8fafed}, /* U+6AF2 [2000] */ + {0xe6abb3, 0x8fafee}, /* U+6AF3 [2000] */ + {0xe6abba, 0xddb2}, /* U+6AFA */ + {0xe6abbb, 0xddaf}, /* U+6AFB */ + {0xe6abbd, 0x8fafef}, /* U+6AFD [2000] */ + {0xe6ac84, 0xcdf3}, /* U+6B04 */ + {0xe6ac85, 0xddb0}, /* U+6B05 */ + {0xe6ac8a, 0xdcde}, /* U+6B0A */ + {0xe6ac8b, 0x8faff1}, /* U+6B0B [2000] */ + {0xe6ac8f, 0x8faff2}, /* U+6B0F [2000] */ + {0xe6ac90, 0x8faff3}, /* U+6B10 [2000] */ + {0xe6ac91, 0x8faff4}, /* U+6B11 [2000] */ + {0xe6ac92, 0xddb3}, /* U+6B12 */ + {0xe6ac96, 0xddb4}, /* U+6B16 */ + {0xe6ac97, 0x8faff6}, /* U+6B17 [2000] */ + {0xe6ac9b, 0xf6bc}, /* U+6B1B [2000] */ + {0xe6ac9d, 0xb1b5}, /* U+6B1D */ + {0xe6ac9e, 0xf6bd}, /* U+6B1E [2000] */ + {0xe6ac9f, 0xddb6}, /* U+6B1F */ + {0xe6aca0, 0xb7e7}, /* U+6B20 */ + {0xe6aca1, 0xbca1}, /* U+6B21 */ + {0xe6aca3, 0xb6d5}, /* U+6B23 */ + {0xe6aca7, 0xb2a4}, /* U+6B27 */ + {0xe6acac, 0xf6be}, /* U+6B2C [2000] */ + {0xe6acaf, 0x8faff8}, /* U+6B2F [2000] */ + {0xe6acb2, 0xcddf}, /* U+6B32 */ + {0xe6acb5, 0xf6bf}, /* U+6B35 [2000] */ + {0xe6acb7, 0xddb8}, /* U+6B37 */ + {0xe6acb8, 0xddb7}, /* U+6B38 */ + {0xe6acb9, 0xddba}, /* U+6B39 */ + {0xe6acba, 0xb5bd}, /* U+6B3A */ + {0xe6acbd, 0xb6d6}, /* U+6B3D */ + {0xe6acbe, 0xb4be}, /* U+6B3E */ + {0xe6ad83, 0xddbd}, /* U+6B43 */ + {0xe6ad86, 0xf6c0}, /* U+6B46 [2000] */ + {0xe6ad87, 0xddbc}, /* U+6B47 */ + {0xe6ad89, 0xddbe}, /* U+6B49 */ + {0xe6ad8a, 0x8faff9}, /* U+6B4A [2000] */ + {0xe6ad8c, 0xb2ce}, /* U+6B4C */ + {0xe6ad8e, 0xc3b7}, /* U+6B4E */ + {0xe6ad90, 0xddbf}, /* U+6B50 */ + {0xe6ad93, 0xb4bf}, /* U+6B53 */ + {0xe6ad94, 0xddc1}, /* U+6B54 */ + {0xe6ad96, 0xf6c1}, /* U+6B56 [2000] */ + {0xe6ad98, 0x8faffa}, /* U+6B58 [2000] */ + {0xe6ad99, 0xddc0}, /* U+6B59 */ + {0xe6ad9b, 0xddc2}, /* U+6B5B */ + {0xe6ad9f, 0xddc3}, /* U+6B5F */ + {0xe6ada0, 0xf6c2}, /* U+6B60 [2000] */ + {0xe6ada1, 0xddc4}, /* U+6B61 */ + {0xe6ada2, 0xbbdf}, /* U+6B62 */ + {0xe6ada3, 0xc0b5}, /* U+6B63 */ + {0xe6ada4, 0xbaa1}, /* U+6B64 */ + {0xe6ada5, 0xf6c3}, /* U+6B65 [2000] */ + {0xe6ada6, 0xc9f0}, /* U+6B66 */ + {0xe6ada7, 0xf6c4}, /* U+6B67 [2000] */ + {0xe6ada9, 0xcae2}, /* U+6B69 */ + {0xe6adaa, 0xcfc4}, /* U+6B6A */ + {0xe6adac, 0x8faffb}, /* U+6B6C [2000] */ + {0xe6adaf, 0xbbf5}, /* U+6B6F */ + {0xe6adb3, 0xbad0}, /* U+6B73 */ + {0xe6adb4, 0xcef2}, /* U+6B74 */ + {0xe6adb5, 0x8faffc}, /* U+6B75 [2000] */ + {0xe6adb7, 0xf6c5}, /* U+6B77 [2000] */ + {0xe6adb8, 0xddc5}, /* U+6B78 */ + {0xe6adb9, 0xddc6}, /* U+6B79 */ + {0xe6adba, 0x8faffd}, /* U+6B7A [2000] */ + {0xe6adbb, 0xbbe0}, /* U+6B7B */ + {0xe6adbf, 0xddc7}, /* U+6B7F */ + {0xe6ae80, 0xddc8}, /* U+6B80 */ + {0xe6ae81, 0x8faffe}, /* U+6B81 [2000] */ + {0xe6ae82, 0xf6c6}, /* U+6B82 [2000] */ + {0xe6ae83, 0xddca}, /* U+6B83 */ + {0xe6ae84, 0xddc9}, /* U+6B84 */ + {0xe6ae86, 0xcbd8}, /* U+6B86 */ + {0xe6ae89, 0xbdde}, /* U+6B89 */ + {0xe6ae8a, 0xbcec}, /* U+6B8A */ + {0xe6ae8b, 0xbbc4}, /* U+6B8B */ + {0xe6ae8d, 0xddcb}, /* U+6B8D */ + {0xe6ae95, 0xddcd}, /* U+6B95 */ + {0xe6ae96, 0xbfa3}, /* U+6B96 */ + {0xe6ae98, 0xddcc}, /* U+6B98 */ + {0xe6ae9b, 0x8feea1}, /* U+6B9B [2000] */ + {0xe6ae9e, 0xddce}, /* U+6B9E */ + {0xe6aea4, 0xddcf}, /* U+6BA4 */ + {0xe6aea9, 0xf6c7}, /* U+6BA9 [2000] */ + {0xe6aeaa, 0xddd0}, /* U+6BAA */ + {0xe6aeab, 0xddd1}, /* U+6BAB */ + {0xe6aead, 0xf6c8}, /* U+6BAD [2000] */ + {0xe6aeae, 0x8feea2}, /* U+6BAE [2000] */ + {0xe6aeaf, 0xddd2}, /* U+6BAF */ + {0xe6aeb1, 0xddd4}, /* U+6BB1 */ + {0xe6aeb2, 0xddd3}, /* U+6BB2 */ + {0xe6aeb3, 0xddd5}, /* U+6BB3 */ + {0xe6aeb4, 0xb2a5}, /* U+6BB4 */ + {0xe6aeb5, 0xc3ca}, /* U+6BB5 */ + {0xe6aeb7, 0xddd6}, /* U+6BB7 */ + {0xe6aeba, 0xbba6}, /* U+6BBA */ + {0xe6aebb, 0xb3cc}, /* U+6BBB */ + {0xe6aebc, 0xddd7}, /* U+6BBC */ + {0xe6aebd, 0x8feea4}, /* U+6BBD [2000] */ + {0xe6aebe, 0x8feea5}, /* U+6BBE [2000] */ + {0xe6aebf, 0xc5c2}, /* U+6BBF */ + {0xe6af80, 0xd4cc}, /* U+6BC0 */ + {0xe6af85, 0xb5a3}, /* U+6BC5 */ + {0xe6af86, 0xddd8}, /* U+6BC6 */ + {0xe6af87, 0x8feea6}, /* U+6BC7 [2000] */ + {0xe6af88, 0x8feea7}, /* U+6BC8 [2000] */ + {0xe6af89, 0x8feea8}, /* U+6BC9 [2000] */ + {0xe6af8b, 0xddd9}, /* U+6BCB */ + {0xe6af8d, 0xcaec}, /* U+6BCD */ + {0xe6af8e, 0xcbe8}, /* U+6BCE */ + {0xe6af8f, 0xf6ca}, /* U+6BCF [2000] */ + {0xe6af92, 0xc6c7}, /* U+6BD2 */ + {0xe6af93, 0xddda}, /* U+6BD3 */ + {0xe6af94, 0xc8e6}, /* U+6BD4 */ + {0xe6af96, 0xf6cb}, /* U+6BD6 [2000] */ + {0xe6af97, 0xf6cc}, /* U+6BD7 [2000] */ + {0xe6af98, 0xc8fb}, /* U+6BD8 */ + {0xe6af9a, 0x8feea9}, /* U+6BDA [2000] */ + {0xe6af9b, 0xccd3}, /* U+6BDB */ + {0xe6af9f, 0xdddb}, /* U+6BDF */ + {0xe6afa6, 0x8feeaa}, /* U+6BE6 [2000] */ + {0xe6afa7, 0x8feeab}, /* U+6BE7 [2000] */ + {0xe6afab, 0xdddd}, /* U+6BEB */ + {0xe6afac, 0xdddc}, /* U+6BEC */ + {0xe6afae, 0x8feeac}, /* U+6BEE [2000] */ + {0xe6afaf, 0xdddf}, /* U+6BEF */ + {0xe6afb1, 0x8feead}, /* U+6BF1 [2000] */ + {0xe6afb3, 0xddde}, /* U+6BF3 */ + {0xe6afbf, 0xf6cd}, /* U+6BFF [2000] */ + {0xe6b082, 0x8feeae}, /* U+6C02 [2000] */ + {0xe6b085, 0xf6ce}, /* U+6C05 [2000] */ + {0xe6b088, 0xdde1}, /* U+6C08 */ + {0xe6b08a, 0x8feeaf}, /* U+6C0A [2000] */ + {0xe6b08e, 0x8feeb0}, /* U+6C0E [2000] */ + {0xe6b08f, 0xbbe1}, /* U+6C0F */ + {0xe6b090, 0xf6cf}, /* U+6C10 [2000] */ + {0xe6b091, 0xccb1}, /* U+6C11 */ + {0xe6b093, 0xdde2}, /* U+6C13 */ + {0xe6b094, 0xdde3}, /* U+6C14 */ + {0xe6b097, 0xb5a4}, /* U+6C17 */ + {0xe6b09b, 0xdde4}, /* U+6C1B */ + {0xe6b0a3, 0xdde6}, /* U+6C23 */ + {0xe6b0a4, 0xdde5}, /* U+6C24 */ + {0xe6b0b3, 0xf6d0}, /* U+6C33 [2000] */ + {0xe6b0b4, 0xbfe5}, /* U+6C34 */ + {0xe6b0b5, 0x8feeb1}, /* U+6C35 [2000] */ + {0xe6b0b6, 0x8feeb2}, /* U+6C36 [2000] */ + {0xe6b0b7, 0xc9b9}, /* U+6C37 */ + {0xe6b0b8, 0xb1ca}, /* U+6C38 */ + {0xe6b0ba, 0x8feeb3}, /* U+6C3A [2000] */ + {0xe6b0be, 0xc8c5}, /* U+6C3E */ + {0xe6b0bf, 0x8feeb5}, /* U+6C3F [2000] */ + {0xe6b180, 0xc4f5}, /* U+6C40 */ + {0xe6b181, 0xbdc1}, /* U+6C41 */ + {0xe6b182, 0xb5e1}, /* U+6C42 */ + {0xe6b18d, 0x8feeb6}, /* U+6C4D [2000] */ + {0xe6b18e, 0xc8c6}, /* U+6C4E */ + {0xe6b190, 0xbcae}, /* U+6C50 */ + {0xe6b195, 0xdde8}, /* U+6C55 */ + {0xe6b197, 0xb4c0}, /* U+6C57 */ + {0xe6b199, 0xf6d1}, /* U+6C59 [2000] */ + {0xe6b19a, 0xb1f8}, /* U+6C5A */ + {0xe6b19b, 0x8feeb7}, /* U+6C5B [2000] */ + {0xe6b19c, 0xf6d2}, /* U+6C5C [2000] */ + {0xe6b19d, 0xc6f2}, /* U+6C5D */ + {0xe6b19e, 0xdde7}, /* U+6C5E */ + {0xe6b19f, 0xb9be}, /* U+6C5F */ + {0xe6b1a0, 0xc3d3}, /* U+6C60 */ + {0xe6b1a2, 0xdde9}, /* U+6C62 */ + {0xe6b1a7, 0x8feecf}, /* U+6C67 [2000] */ + {0xe6b1a8, 0xddf1}, /* U+6C68 */ + {0xe6b1aa, 0xddea}, /* U+6C6A */ + {0xe6b1ad, 0x8feeb8}, /* U+6C6D [2000] */ + {0xe6b1b0, 0xc2c1}, /* U+6C70 */ + {0xe6b1b2, 0xb5e2}, /* U+6C72 */ + {0xe6b1b3, 0xddf2}, /* U+6C73 */ + {0xe6b1b4, 0xf6d4}, /* U+6C74 [2000] */ + {0xe6b1b6, 0xf6d5}, /* U+6C76 [2000] */ + {0xe6b1ba, 0xb7e8}, /* U+6C7A */ + {0xe6b1bd, 0xb5a5}, /* U+6C7D */ + {0xe6b1be, 0xddf0}, /* U+6C7E */ + {0xe6b281, 0xddee}, /* U+6C81 */ + {0xe6b282, 0xddeb}, /* U+6C82 */ + {0xe6b283, 0xcde0}, /* U+6C83 */ + {0xe6b284, 0x8feeb9}, /* U+6C84 [2000] */ + {0xe6b285, 0xf6d6}, /* U+6C85 [2000] */ + {0xe6b286, 0xf6d7}, /* U+6C86 [2000] */ + {0xe6b288, 0xc4c0}, /* U+6C88 */ + {0xe6b289, 0x8feeba}, /* U+6C89 [2000] */ + {0xe6b28c, 0xc6d9}, /* U+6C8C */ + {0xe6b28d, 0xddec}, /* U+6C8D */ + {0xe6b290, 0xddf4}, /* U+6C90 */ + {0xe6b292, 0xddf3}, /* U+6C92 */ + {0xe6b293, 0xb7a3}, /* U+6C93 */ + {0xe6b294, 0x8feebc}, /* U+6C94 [2000] */ + {0xe6b295, 0x8feebd}, /* U+6C95 [2000] */ + {0xe6b296, 0xb2ad}, /* U+6C96 */ + {0xe6b297, 0x8feebe}, /* U+6C97 [2000] */ + {0xe6b298, 0xf6d8}, /* U+6C98 [2000] */ + {0xe6b299, 0xbabb}, /* U+6C99 */ + {0xe6b29a, 0xdded}, /* U+6C9A */ + {0xe6b29b, 0xddef}, /* U+6C9B */ + {0xe6b29c, 0xf6d9}, /* U+6C9C [2000] */ + {0xe6b2a1, 0xcbd7}, /* U+6CA1 */ + {0xe6b2a2, 0xc2f4}, /* U+6CA2 */ + {0xe6b2aa, 0xf6d3}, /* U+6CAA [2000] */ + {0xe6b2ab, 0xcbf7}, /* U+6CAB */ + {0xe6b2ad, 0x8feebf}, /* U+6CAD [2000] */ + {0xe6b2ae, 0xddfc}, /* U+6CAE */ + {0xe6b2b1, 0xddfd}, /* U+6CB1 */ + {0xe6b2b3, 0xb2cf}, /* U+6CB3 */ + {0xe6b2b8, 0xcaa8}, /* U+6CB8 */ + {0xe6b2b9, 0xccfd}, /* U+6CB9 */ + {0xe6b2ba, 0xdea1}, /* U+6CBA */ + {0xe6b2bb, 0xbca3}, /* U+6CBB */ + {0xe6b2bc, 0xbec2}, /* U+6CBC */ + {0xe6b2bd, 0xddf8}, /* U+6CBD */ + {0xe6b2be, 0xddfe}, /* U+6CBE */ + {0xe6b2bf, 0xb1e8}, /* U+6CBF */ + {0xe6b381, 0xb6b7}, /* U+6CC1 */ + {0xe6b382, 0x8feec0}, /* U+6CC2 [2000] */ + {0xe6b384, 0xddf5}, /* U+6CC4 */ + {0xe6b385, 0xddfa}, /* U+6CC5 */ + {0xe6b386, 0xf6db}, /* U+6CC6 [2000] */ + {0xe6b389, 0xc0f4}, /* U+6CC9 */ + {0xe6b38a, 0xc7f1}, /* U+6CCA */ + {0xe6b38c, 0xc8e7}, /* U+6CCC */ + {0xe6b390, 0x8feec1}, /* U+6CD0 [2000] */ + {0xe6b393, 0xddf7}, /* U+6CD3 */ + {0xe6b394, 0xf6dc}, /* U+6CD4 [2000] */ + {0xe6b395, 0xcba1}, /* U+6CD5 */ + {0xe6b396, 0x8feec3}, /* U+6CD6 [2000] */ + {0xe6b397, 0xddf9}, /* U+6CD7 */ + {0xe6b399, 0xdea4}, /* U+6CD9 */ + {0xe6b39a, 0x8feec4}, /* U+6CDA [2000] */ + {0xe6b39b, 0xdea2}, /* U+6CDB */ + {0xe6b39c, 0x8feec5}, /* U+6CDC [2000] */ + {0xe6b39d, 0xddfb}, /* U+6CDD */ + {0xe6b3a0, 0xf6dd}, /* U+6CE0 [2000] */ + {0xe6b3a1, 0xcba2}, /* U+6CE1 */ + {0xe6b3a2, 0xc7c8}, /* U+6CE2 */ + {0xe6b3a3, 0xb5e3}, /* U+6CE3 */ + {0xe6b3a5, 0xc5a5}, /* U+6CE5 */ + {0xe6b3a8, 0xc3ed}, /* U+6CE8 */ + {0xe6b3a9, 0x8feec6}, /* U+6CE9 [2000] */ + {0xe6b3aa, 0xdea5}, /* U+6CEA */ + {0xe6b3ab, 0xf6de}, /* U+6CEB [2000] */ + {0xe6b3ac, 0x8feec7}, /* U+6CEC [2000] */ + {0xe6b3ad, 0x8feec8}, /* U+6CED [2000] */ + {0xe6b3ae, 0xf6df}, /* U+6CEE [2000] */ + {0xe6b3af, 0xdea3}, /* U+6CEF */ + {0xe6b3b0, 0xc2d9}, /* U+6CF0 */ + {0xe6b3b1, 0xddf6}, /* U+6CF1 */ + {0xe6b3b3, 0xb1cb}, /* U+6CF3 */ + {0xe6b3bb, 0xf6da}, /* U+6CFB [2000] */ + {0xe6b480, 0x8feeca}, /* U+6D00 [2000] */ + {0xe6b484, 0xf6e1}, /* U+6D04 [2000] */ + {0xe6b48a, 0x8feecb}, /* U+6D0A [2000] */ + {0xe6b48b, 0xcdce}, /* U+6D0B */ + {0xe6b48c, 0xdeb0}, /* U+6D0C */ + {0xe6b48e, 0xf6e2}, /* U+6D0E [2000] */ + {0xe6b492, 0xdeaf}, /* U+6D12 */ + {0xe6b497, 0xc0f6}, /* U+6D17 */ + {0xe6b499, 0xdeac}, /* U+6D19 */ + {0xe6b49b, 0xcdec}, /* U+6D1B */ + {0xe6b49e, 0xc6b6}, /* U+6D1E */ + {0xe6b49f, 0xdea6}, /* U+6D1F */ + {0xe6b4a4, 0x8feecc}, /* U+6D24 [2000] */ + {0xe6b4a5, 0xc4c5}, /* U+6D25 */ + {0xe6b4a6, 0x8feecd}, /* U+6D26 [2000] */ + {0xe6b4a7, 0x8feece}, /* U+6D27 [2000] */ + {0xe6b4a9, 0xb1cc}, /* U+6D29 */ + {0xe6b4aa, 0xb9bf}, /* U+6D2A */ + {0xe6b4ab, 0xdea9}, /* U+6D2B */ + {0xe6b4ae, 0xf6e3}, /* U+6D2E [2000] */ + {0xe6b4af, 0x8feed0}, /* U+6D2F [2000] */ + {0xe6b4b1, 0xf6e4}, /* U+6D31 [2000] */ + {0xe6b4b2, 0xbda7}, /* U+6D32 */ + {0xe6b4b3, 0xdeae}, /* U+6D33 */ + {0xe6b4b4, 0x8feee5}, /* U+6D34 [2000] */ + {0xe6b4b5, 0xdead}, /* U+6D35 */ + {0xe6b4b6, 0xdea8}, /* U+6D36 */ + {0xe6b4b8, 0xdeab}, /* U+6D38 */ + {0xe6b4b9, 0xf6e5}, /* U+6D39 [2000] */ + {0xe6b4bb, 0xb3e8}, /* U+6D3B */ + {0xe6b4bc, 0x8feed1}, /* U+6D3C [2000] */ + {0xe6b4bd, 0xdeaa}, /* U+6D3D */ + {0xe6b4be, 0xc7c9}, /* U+6D3E */ + {0xe6b4bf, 0xf6e6}, /* U+6D3F [2000] */ + {0xe6b581, 0xceae}, /* U+6D41 */ + {0xe6b584, 0xbef4}, /* U+6D44 */ + {0xe6b585, 0xc0f5}, /* U+6D45 */ + {0xe6b598, 0xf6e7}, /* U+6D58 [2000] */ + {0xe6b599, 0xdeb6}, /* U+6D59 */ + {0xe6b59a, 0xdeb4}, /* U+6D5A */ + {0xe6b59b, 0x8feed2}, /* U+6D5B [2000] */ + {0xe6b59c, 0xc9cd}, /* U+6D5C */ + {0xe6b59e, 0x8feed3}, /* U+6D5E [2000] */ + {0xe6b5a0, 0x8feed4}, /* U+6D60 [2000] */ + {0xe6b5a3, 0xdeb1}, /* U+6D63 */ + {0xe6b5a4, 0xdeb3}, /* U+6D64 */ + {0xe6b5a5, 0xf6e8}, /* U+6D65 [2000] */ + {0xe6b5a6, 0xb1ba}, /* U+6D66 */ + {0xe6b5a9, 0xb9c0}, /* U+6D69 */ + {0xe6b5aa, 0xcfb2}, /* U+6D6A */ + {0xe6b5ac, 0xb3bd}, /* U+6D6C */ + {0xe6b5ae, 0xc9e2}, /* U+6D6E */ + {0xe6b5b0, 0x8feed5}, /* U+6D70 [2000] */ + {0xe6b5b4, 0xcde1}, /* U+6D74 */ + {0xe6b5b7, 0xb3a4}, /* U+6D77 */ + {0xe6b5b8, 0xbfbb}, /* U+6D78 */ + {0xe6b5b9, 0xdeb5}, /* U+6D79 */ + {0xe6b680, 0x8feed6}, /* U+6D80 [2000] */ + {0xe6b681, 0x8feed7}, /* U+6D81 [2000] */ + {0xe6b682, 0xf6ea}, /* U+6D82 [2000] */ + {0xe6b685, 0xdeba}, /* U+6D85 */ + {0xe6b687, 0xf6eb}, /* U+6D87 [2000] */ + {0xe6b688, 0xbec3}, /* U+6D88 */ + {0xe6b689, 0xf6ec}, /* U+6D89 [2000] */ + {0xe6b68a, 0x8feed8}, /* U+6D8A [2000] */ + {0xe6b68c, 0xcdb0}, /* U+6D8C */ + {0xe6b68d, 0x8feed9}, /* U+6D8D [2000] */ + {0xe6b68e, 0xdeb7}, /* U+6D8E */ + {0xe6b691, 0x8feeda}, /* U+6D91 [2000] */ + {0xe6b693, 0xdeb2}, /* U+6D93 */ + {0xe6b694, 0xf6ed}, /* U+6D94 [2000] */ + {0xe6b695, 0xdeb8}, /* U+6D95 */ + {0xe6b698, 0x8feedb}, /* U+6D98 [2000] */ + {0xe6b699, 0xcede}, /* U+6D99 */ + {0xe6b69b, 0xc5f3}, /* U+6D9B */ + {0xe6b69c, 0xc6c2}, /* U+6D9C */ + {0xe6b6aa, 0xf6ee}, /* U+6DAA [2000] */ + {0xe6b6ab, 0x8feee1}, /* U+6DAB [2000] */ + {0xe6b6ac, 0xf6ef}, /* U+6DAC [2000] */ + {0xe6b6ae, 0x8feee2}, /* U+6DAE [2000] */ + {0xe6b6af, 0xb3b6}, /* U+6DAF */ + {0xe6b6b2, 0xb1d5}, /* U+6DB2 */ + {0xe6b6b4, 0x8feee3}, /* U+6DB4 [2000] */ + {0xe6b6b5, 0xdebe}, /* U+6DB5 */ + {0xe6b6b8, 0xdec1}, /* U+6DB8 */ + {0xe6b6bc, 0xcec3}, /* U+6DBC */ + {0xe6b6bf, 0xf6f0}, /* U+6DBF [2000] */ + {0xe6b780, 0xcde4}, /* U+6DC0 */ + {0xe6b782, 0x8feee4}, /* U+6DC2 [2000] */ + {0xe6b784, 0xf6f1}, /* U+6DC4 [2000] */ + {0xe6b785, 0xdec8}, /* U+6DC5 */ + {0xe6b786, 0xdec2}, /* U+6DC6 */ + {0xe6b787, 0xdebf}, /* U+6DC7 */ + {0xe6b788, 0x8feee6}, /* U+6DC8 [2000] */ + {0xe6b78b, 0xced4}, /* U+6DCB */ + {0xe6b78c, 0xdec5}, /* U+6DCC */ + {0xe6b78e, 0x8feee7}, /* U+6DCE [2000] */ + {0xe6b78f, 0x8feee8}, /* U+6DCF [2000] */ + {0xe6b790, 0x8feee9}, /* U+6DD0 [2000] */ + {0xe6b791, 0xbdca}, /* U+6DD1 */ + {0xe6b792, 0xdec7}, /* U+6DD2 */ + {0xe6b795, 0xdecc}, /* U+6DD5 */ + {0xe6b796, 0xf6f2}, /* U+6DD6 [2000] */ + {0xe6b798, 0xc5f1}, /* U+6DD8 */ + {0xe6b799, 0xdeca}, /* U+6DD9 */ + {0xe6b79a, 0xf6f3}, /* U+6DDA [2000] */ + {0xe6b79b, 0xf6f4}, /* U+6DDB [2000] */ + {0xe6b79d, 0xf6f5}, /* U+6DDD [2000] */ + {0xe6b79e, 0xdec4}, /* U+6DDE */ + {0xe6b79f, 0x8feeea}, /* U+6DDF [2000] */ + {0xe6b7a1, 0xc3b8}, /* U+6DE1 */ + {0xe6b7a4, 0xdecb}, /* U+6DE4 */ + {0xe6b7a6, 0xdec0}, /* U+6DE6 */ + {0xe6b7a8, 0xdec6}, /* U+6DE8 */ + {0xe6b7a9, 0x8feeeb}, /* U+6DE9 [2000] */ + {0xe6b7aa, 0xdecd}, /* U+6DEA */ + {0xe6b7ab, 0xb0fc}, /* U+6DEB */ + {0xe6b7ac, 0xdec3}, /* U+6DEC */ + {0xe6b7ae, 0xdece}, /* U+6DEE */ + {0xe6b7b1, 0xbfbc}, /* U+6DF1 */ + {0xe6b7b3, 0xbddf}, /* U+6DF3 */ + {0xe6b7b5, 0xcaa5}, /* U+6DF5 */ + {0xe6b7b6, 0x8feeec}, /* U+6DF6 [2000] */ + {0xe6b7b7, 0xbaae}, /* U+6DF7 */ + {0xe6b7b9, 0xdebb}, /* U+6DF9 */ + {0xe6b7ba, 0xdec9}, /* U+6DFA */ + {0xe6b7bb, 0xc5ba}, /* U+6DFB */ + {0xe6b7bc, 0xf6f6}, /* U+6DFC [2000] */ + {0xe6b885, 0xc0b6}, /* U+6E05 */ + {0xe6b887, 0xb3e9}, /* U+6E07 */ + {0xe6b888, 0xbad1}, /* U+6E08 */ + {0xe6b889, 0xbec4}, /* U+6E09 */ + {0xe6b88a, 0xdebd}, /* U+6E0A */ + {0xe6b88b, 0xbdc2}, /* U+6E0B */ + {0xe6b893, 0xb7cc}, /* U+6E13 */ + {0xe6b895, 0xdebc}, /* U+6E15 */ + {0xe6b897, 0x8feedd}, /* U+6E17 [2000] */ + {0xe6b899, 0xded2}, /* U+6E19 */ + {0xe6b89a, 0xbded}, /* U+6E1A */ + {0xe6b89b, 0xb8ba}, /* U+6E1B */ + {0xe6b89d, 0xdee1}, /* U+6E1D */ + {0xe6b89e, 0x8feeee}, /* U+6E1E [2000] */ + {0xe6b89f, 0xdedb}, /* U+6E1F */ + {0xe6b8a0, 0xb5f4}, /* U+6E20 */ + {0xe6b8a1, 0xc5cf}, /* U+6E21 */ + {0xe6b8a2, 0x8feeef}, /* U+6E22 [2000] */ + {0xe6b8a3, 0xded6}, /* U+6E23 */ + {0xe6b8a4, 0xdedf}, /* U+6E24 */ + {0xe6b8a5, 0xb0af}, /* U+6E25 */ + {0xe6b8a6, 0xb1b2}, /* U+6E26 */ + {0xe6b8a7, 0x8feef0}, /* U+6E27 [2000] */ + {0xe6b8a9, 0xb2b9}, /* U+6E29 */ + {0xe6b8ab, 0xded8}, /* U+6E2B */ + {0xe6b8ac, 0xc2ac}, /* U+6E2C */ + {0xe6b8ad, 0xdecf}, /* U+6E2D */ + {0xe6b8ae, 0xded1}, /* U+6E2E */ + {0xe6b8af, 0xb9c1}, /* U+6E2F */ + {0xe6b8b2, 0x8feef2}, /* U+6E32 [2000] */ + {0xe6b8b4, 0xf6f8}, /* U+6E34 [2000] */ + {0xe6b8b6, 0x8feeed}, /* U+6E36 [2000] */ + {0xe6b8b8, 0xdee2}, /* U+6E38 */ + {0xe6b8ba, 0xdedd}, /* U+6E3A */ + {0xe6b8bc, 0x8feef3}, /* U+6E3C [2000] */ + {0xe6b8be, 0xded5}, /* U+6E3E */ + {0xe6b983, 0xdedc}, /* U+6E43 */ + {0xe6b984, 0xf6f9}, /* U+6E44 [2000] */ + {0xe6b988, 0x8feef4}, /* U+6E48 [2000] */ + {0xe6b989, 0x8feef5}, /* U+6E49 [2000] */ + {0xe6b98a, 0xccab}, /* U+6E4A */ + {0xe6b98b, 0x8feef6}, /* U+6E4B [2000] */ + {0xe6b98c, 0x8feef7}, /* U+6E4C [2000] */ + {0xe6b98d, 0xdeda}, /* U+6E4D */ + {0xe6b98e, 0xdede}, /* U+6E4E */ + {0xe6b98f, 0x8feef8}, /* U+6E4F [2000] */ + {0xe6b991, 0x8feef9}, /* U+6E51 [2000] */ + {0xe6b993, 0x8feefa}, /* U+6E53 [2000] */ + {0xe6b994, 0x8feefb}, /* U+6E54 [2000] */ + {0xe6b996, 0xb8d0}, /* U+6E56 */ + {0xe6b997, 0x8feefc}, /* U+6E57 [2000] */ + {0xe6b998, 0xbec5}, /* U+6E58 */ + {0xe6b99b, 0xc3b9}, /* U+6E5B */ + {0xe6b99c, 0xf6fa}, /* U+6E5C [2000] */ + {0xe6b99e, 0xf6fb}, /* U+6E5E [2000] */ + {0xe6b99f, 0xded4}, /* U+6E5F */ + {0xe6b9a3, 0x8feefd}, /* U+6E63 [2000] */ + {0xe6b9a7, 0xcdaf}, /* U+6E67 */ + {0xe6b9ab, 0xded7}, /* U+6E6B */ + {0xe6b9ae, 0xded0}, /* U+6E6E */ + {0xe6b9af, 0xc5f2}, /* U+6E6F */ + {0xe6b9b2, 0xded3}, /* U+6E72 */ + {0xe6b9b6, 0xded9}, /* U+6E76 */ + {0xe6b9be, 0xcfd1}, /* U+6E7E */ + {0xe6b9bf, 0xbcbe}, /* U+6E7F */ + {0xe6ba80, 0xcbfe}, /* U+6E80 */ + {0xe6ba82, 0xdee3}, /* U+6E82 */ + {0xe6ba8c, 0xc8ae}, /* U+6E8C */ + {0xe6ba8f, 0xdeef}, /* U+6E8F */ + {0xe6ba90, 0xb8bb}, /* U+6E90 */ + {0xe6ba93, 0x8fefa1}, /* U+6E93 [2000] */ + {0xe6ba96, 0xbde0}, /* U+6E96 */ + {0xe6ba98, 0xdee5}, /* U+6E98 */ + {0xe6ba9c, 0xceaf}, /* U+6E9C */ + {0xe6ba9d, 0xb9c2}, /* U+6E9D */ + {0xe6ba9f, 0xdef2}, /* U+6E9F */ + {0xe6baa2, 0xb0ee}, /* U+6EA2 */ + {0xe6baa5, 0xdef0}, /* U+6EA5 */ + {0xe6baa7, 0x8fefa2}, /* U+6EA7 [2000] */ + {0xe6baaa, 0xdee4}, /* U+6EAA */ + {0xe6baab, 0xf6fc}, /* U+6EAB [2000] */ + {0xe6baaf, 0xdeea}, /* U+6EAF */ + {0xe6bab1, 0xf6fd}, /* U+6EB1 [2000] */ + {0xe6bab2, 0xdeec}, /* U+6EB2 */ + {0xe6bab4, 0x8fefa3}, /* U+6EB4 [2000] */ + {0xe6bab6, 0xcdcf}, /* U+6EB6 */ + {0xe6bab7, 0xdee7}, /* U+6EB7 */ + {0xe6baba, 0xc5ae}, /* U+6EBA */ + {0xe6babd, 0xdee9}, /* U+6EBD */ + {0xe6babf, 0x8fefa4}, /* U+6EBF [2000] */ + {0xe6bb81, 0xf6fe}, /* U+6EC1 [2000] */ + {0xe6bb82, 0xdef1}, /* U+6EC2 */ + {0xe6bb83, 0x8fefa5}, /* U+6EC3 [2000] */ + {0xe6bb84, 0xdeeb}, /* U+6EC4 */ + {0xe6bb85, 0xccc7}, /* U+6EC5 */ + {0xe6bb87, 0xf7a1}, /* U+6EC7 [2000] */ + {0xe6bb89, 0xdee6}, /* U+6EC9 */ + {0xe6bb8a, 0x8fefa6}, /* U+6ECA [2000] */ + {0xe6bb8b, 0xbca2}, /* U+6ECB */ + {0xe6bb8c, 0xdefe}, /* U+6ECC */ + {0xe6bb8e, 0xf7a2}, /* U+6ECE [2000] */ + {0xe6bb91, 0xb3ea}, /* U+6ED1 */ + {0xe6bb93, 0xdee8}, /* U+6ED3 */ + {0xe6bb94, 0xdeed}, /* U+6ED4 */ + {0xe6bb95, 0xdeee}, /* U+6ED5 */ + {0xe6bb99, 0x8fefa7}, /* U+6ED9 [2000] */ + {0xe6bb9d, 0xc2ec}, /* U+6EDD */ + {0xe6bb9e, 0xc2da}, /* U+6EDE */ + {0xe6bbab, 0x8fefa9}, /* U+6EEB [2000] */ + {0xe6bbac, 0xdef6}, /* U+6EEC */ + {0xe6bbaf, 0xdefc}, /* U+6EEF */ + {0xe6bbb2, 0xdefa}, /* U+6EF2 */ + {0xe6bbb4, 0xc5a9}, /* U+6EF4 */ + {0xe6bbb7, 0xdfa3}, /* U+6EF7 */ + {0xe6bbb8, 0xdef7}, /* U+6EF8 */ + {0xe6bbb9, 0x8fefaa}, /* U+6EF9 [2000] */ + {0xe6bbbb, 0x8fefab}, /* U+6EFB [2000] */ + {0xe6bbbe, 0xdef8}, /* U+6EFE */ + {0xe6bbbf, 0xdee0}, /* U+6EFF */ + {0xe6bc81, 0xb5f9}, /* U+6F01 */ + {0xe6bc82, 0xc9ba}, /* U+6F02 */ + {0xe6bc86, 0xbcbf}, /* U+6F06 */ + {0xe6bc89, 0xb9f7}, /* U+6F09 */ + {0xe6bc8a, 0x8fefac}, /* U+6F0A [2000] */ + {0xe6bc8c, 0x8fefad}, /* U+6F0C [2000] */ + {0xe6bc8f, 0xcfb3}, /* U+6F0F */ + {0xe6bc90, 0xf7a3}, /* U+6F10 [2000] */ + {0xe6bc91, 0xdef4}, /* U+6F11 */ + {0xe6bc93, 0xdfa2}, /* U+6F13 */ + {0xe6bc94, 0xb1e9}, /* U+6F14 */ + {0xe6bc95, 0xc1e6}, /* U+6F15 */ + {0xe6bc98, 0x8fefae}, /* U+6F18 [2000] */ + {0xe6bc9a, 0xf7a4}, /* U+6F1A [2000] */ + {0xe6bca0, 0xc7f9}, /* U+6F20 */ + {0xe6bca2, 0xb4c1}, /* U+6F22 */ + {0xe6bca3, 0xcefa}, /* U+6F23 */ + {0xe6bca5, 0x8fefaf}, /* U+6F25 [2000] */ + {0xe6bcaa, 0xf7a6}, /* U+6F2A [2000] */ + {0xe6bcab, 0xcca1}, /* U+6F2B */ + {0xe6bcac, 0xc4d2}, /* U+6F2C */ + {0xe6bcaf, 0xf7a7}, /* U+6F2F [2000] */ + {0xe6bcb1, 0xdefb}, /* U+6F31 */ + {0xe6bcb2, 0xdefd}, /* U+6F32 */ + {0xe6bcb3, 0xf7a8}, /* U+6F33 [2000] */ + {0xe6bcb5, 0x8fefa8}, /* U+6F35 [2000] */ + {0xe6bcb6, 0x8fefb0}, /* U+6F36 [2000] */ + {0xe6bcb8, 0xc1b2}, /* U+6F38 */ + {0xe6bcbc, 0x8fefb1}, /* U+6F3C [2000] */ + {0xe6bcbe, 0xdfa1}, /* U+6F3E */ + {0xe6bcbf, 0xdef9}, /* U+6F3F */ + {0xe6bd81, 0xdef3}, /* U+6F41 */ + {0xe6bd85, 0xb4c3}, /* U+6F45 */ + {0xe6bd91, 0xf7a9}, /* U+6F51 [2000] */ + {0xe6bd92, 0x8fefb3}, /* U+6F52 [2000] */ + {0xe6bd94, 0xb7e9}, /* U+6F54 */ + {0xe6bd97, 0x8fefb4}, /* U+6F57 [2000] */ + {0xe6bd98, 0xdfaf}, /* U+6F58 */ + {0xe6bd99, 0xf7aa}, /* U+6F59 [2000] */ + {0xe6bd9a, 0x8fefb5}, /* U+6F5A [2000] */ + {0xe6bd9b, 0xdfaa}, /* U+6F5B */ + {0xe6bd9c, 0xc0f8}, /* U+6F5C */ + {0xe6bd9e, 0xf7ab}, /* U+6F5E [2000] */ + {0xe6bd9f, 0xb3e3}, /* U+6F5F */ + {0xe6bda0, 0x8fefb6}, /* U+6F60 [2000] */ + {0xe6bda1, 0xf7ac}, /* U+6F61 [2000] */ + {0xe6bda2, 0xf7ad}, /* U+6F62 [2000] */ + {0xe6bda4, 0xbde1}, /* U+6F64 */ + {0xe6bda6, 0xdfb3}, /* U+6F66 */ + {0xe6bda8, 0x8fefb7}, /* U+6F68 [2000] */ + {0xe6bdad, 0xdfac}, /* U+6F6D */ + {0xe6bdae, 0xc4ac}, /* U+6F6E */ + {0xe6bdaf, 0xdfa9}, /* U+6F6F */ + {0xe6bdb0, 0xc4d9}, /* U+6F70 */ + {0xe6bdb4, 0xdfcc}, /* U+6F74 */ + {0xe6bdb8, 0xdfa6}, /* U+6F78 */ + {0xe6bdba, 0xdfa5}, /* U+6F7A */ + {0xe6bdbc, 0xdfae}, /* U+6F7C */ + {0xe6bdbd, 0x8fefb9}, /* U+6F7D [2000] */ + {0xe6bdbe, 0xf7ae}, /* U+6F7E [2000] */ + {0xe6be80, 0xdfa8}, /* U+6F80 */ + {0xe6be81, 0xdfa7}, /* U+6F81 */ + {0xe6be82, 0xdfad}, /* U+6F82 */ + {0xe6be84, 0xc0a1}, /* U+6F84 */ + {0xe6be86, 0xdfa4}, /* U+6F86 */ + {0xe6be88, 0xf7af}, /* U+6F88 [2000] */ + {0xe6be8c, 0xf7b0}, /* U+6F8C [2000] */ + {0xe6be8d, 0xf7b1}, /* U+6F8D [2000] */ + {0xe6be8e, 0xdfb0}, /* U+6F8E */ + {0xe6be90, 0x8fefba}, /* U+6F90 [2000] */ + {0xe6be91, 0xdfb1}, /* U+6F91 */ + {0xe6be94, 0xf7b2}, /* U+6F94 [2000] */ + {0xe6be96, 0x8fefbb}, /* U+6F96 [2000] */ + {0xe6be97, 0xb4c2}, /* U+6F97 */ + {0xe6be98, 0x8fefb8}, /* U+6F98 [2000] */ + {0xe6be9f, 0x8fefbd}, /* U+6F9F [2000] */ + {0xe6bea0, 0xf7b3}, /* U+6FA0 [2000] */ + {0xe6bea1, 0xdfb6}, /* U+6FA1 */ + {0xe6bea3, 0xdfb5}, /* U+6FA3 */ + {0xe6bea4, 0xdfb7}, /* U+6FA4 */ + {0xe6bea5, 0x8fefbe}, /* U+6FA5 [2000] */ + {0xe6bea7, 0xf7b4}, /* U+6FA7 [2000] */ + {0xe6beaa, 0xdfba}, /* U+6FAA */ + {0xe6beaf, 0x8fefbf}, /* U+6FAF [2000] */ + {0xe6beb1, 0xc5c3}, /* U+6FB1 */ + {0xe6beb3, 0xdfb4}, /* U+6FB3 */ + {0xe6beb5, 0x8fefc1}, /* U+6FB5 [2000] */ + {0xe6beb6, 0xf7b5}, /* U+6FB6 [2000] */ + {0xe6beb9, 0xdfb8}, /* U+6FB9 */ + {0xe6bebc, 0xf7b6}, /* U+6FBC [2000] */ + {0xe6bebe, 0x8fefbc}, /* U+6FBE [2000] */ + {0xe6bf80, 0xb7e3}, /* U+6FC0 */ + {0xe6bf81, 0xc2f9}, /* U+6FC1 */ + {0xe6bf82, 0xdfb2}, /* U+6FC2 */ + {0xe6bf83, 0xc7bb}, /* U+6FC3 */ + {0xe6bf86, 0xdfb9}, /* U+6FC6 */ + {0xe6bf87, 0xf7b7}, /* U+6FC7 [2000] */ + {0xe6bf88, 0x8fefc2}, /* U+6FC8 [2000] */ + {0xe6bf89, 0x8fefc3}, /* U+6FC9 [2000] */ + {0xe6bf8a, 0xf7b8}, /* U+6FCA [2000] */ + {0xe6bf94, 0xdfbe}, /* U+6FD4 */ + {0xe6bf95, 0xdfbc}, /* U+6FD5 */ + {0xe6bf98, 0xdfbf}, /* U+6FD8 */ + {0xe6bf9a, 0x8fefc4}, /* U+6FDA [2000] */ + {0xe6bf9b, 0xdfc2}, /* U+6FDB */ + {0xe6bf9e, 0x8fefc5}, /* U+6FDE [2000] */ + {0xe6bf9f, 0xdfbb}, /* U+6FDF */ + {0xe6bfa0, 0xb9ea}, /* U+6FE0 */ + {0xe6bfa1, 0xc7a8}, /* U+6FE1 */ + {0xe6bfa4, 0xdeb9}, /* U+6FE4 */ + {0xe6bfa9, 0x8fefc6}, /* U+6FE9 [2000] */ + {0xe6bfab, 0xcdf4}, /* U+6FEB */ + {0xe6bfac, 0xdfbd}, /* U+6FEC */ + {0xe6bfae, 0xdfc1}, /* U+6FEE */ + {0xe6bfaf, 0xc2f5}, /* U+6FEF */ + {0xe6bfb0, 0xf7ba}, /* U+6FF0 [2000] */ + {0xe6bfb1, 0xdfc0}, /* U+6FF1 */ + {0xe6bfb3, 0xdfab}, /* U+6FF3 */ + {0xe6bfb5, 0xf7bb}, /* U+6FF5 [2000] */ + {0xe6bfb6, 0xefe9}, /* U+6FF6 */ + {0xe6bfb9, 0xf7b9}, /* U+6FF9 [2000] */ + {0xe6bfba, 0xdfc5}, /* U+6FFA */ + {0xe6bfbc, 0x8fefc8}, /* U+6FFC [2000] */ + {0xe6bfbe, 0xdfc9}, /* U+6FFE */ + {0xe78080, 0x8fefc9}, /* U+7000 [2000] */ + {0xe78081, 0xdfc7}, /* U+7001 */ + {0xe78085, 0xf7bc}, /* U+7005 [2000] */ + {0xe78086, 0xf7bd}, /* U+7006 [2000] */ + {0xe78087, 0x8fefca}, /* U+7007 [2000] */ + {0xe78089, 0xdfc3}, /* U+7009 */ + {0xe7808a, 0x8fefcb}, /* U+700A [2000] */ + {0xe7808b, 0xdfc4}, /* U+700B */ + {0xe7808f, 0xdfc8}, /* U+700F */ + {0xe78091, 0xdfc6}, /* U+7011 */ + {0xe78095, 0xc9ce}, /* U+7015 */ + {0xe78098, 0xdfce}, /* U+7018 */ + {0xe7809a, 0xdfcb}, /* U+701A */ + {0xe7809b, 0xdfca}, /* U+701B */ + {0xe7809d, 0xdfcd}, /* U+701D */ + {0xe7809e, 0xc6d4}, /* U+701E */ + {0xe7809f, 0xdfcf}, /* U+701F */ + {0xe780a3, 0x8fefcc}, /* U+7023 [2000] */ + {0xe780a6, 0xc3f5}, /* U+7026 */ + {0xe780a7, 0xc2ed}, /* U+7027 */ + {0xe780a8, 0xf7be}, /* U+7028 [2000] */ + {0xe780ac, 0xc0a5}, /* U+702C */ + {0xe780b0, 0xdfd0}, /* U+7030 */ + {0xe780b2, 0xdfd2}, /* U+7032 */ + {0xe780b9, 0x8fefce}, /* U+7039 [2000] */ + {0xe780ba, 0x8fefcf}, /* U+703A [2000] */ + {0xe780bc, 0x8fefd0}, /* U+703C [2000] */ + {0xe780be, 0xdfd1}, /* U+703E */ + {0xe78183, 0x8fefd1}, /* U+7043 [2000] */ + {0xe78187, 0x8fefd2}, /* U+7047 [2000] */ + {0xe7818a, 0xf7bf}, /* U+704A [2000] */ + {0xe7818b, 0x8fefd3}, /* U+704B [2000] */ + {0xe7818c, 0xdef5}, /* U+704C */ + {0xe7818e, 0xf7c2}, /* U+704E [2000] */ + {0xe78191, 0xdfd3}, /* U+7051 */ + {0xe78194, 0x8fefd5}, /* U+7054 [2000] */ + {0xe78198, 0xc6e7}, /* U+7058 */ + {0xe7819d, 0xf7c0}, /* U+705D [2000] */ + {0xe7819e, 0xf7c1}, /* U+705E [2000] */ + {0xe781a3, 0xdfd4}, /* U+7063 */ + {0xe781a4, 0xf7c3}, /* U+7064 [2000] */ + {0xe781a5, 0x8fefd6}, /* U+7065 [2000] */ + {0xe781a9, 0x8fefd7}, /* U+7069 [2000] */ + {0xe781ab, 0xb2d0}, /* U+706B */ + {0xe781ac, 0x8fefd8}, /* U+706C [2000] */ + {0xe781ae, 0x8fefd9}, /* U+706E [2000] */ + {0xe781af, 0xc5f4}, /* U+706F */ + {0xe781b0, 0xb3a5}, /* U+7070 */ + {0xe781b5, 0xf7c4}, /* U+7075 [2000] */ + {0xe781b6, 0x8fefda}, /* U+7076 [2000] */ + {0xe781b8, 0xb5e4}, /* U+7078 */ + {0xe781bc, 0xbcde}, /* U+707C */ + {0xe781bd, 0xbad2}, /* U+707D */ + {0xe781be, 0x8fefdb}, /* U+707E [2000] */ + {0xe78281, 0x8fefdc}, /* U+7081 [2000] */ + {0xe78285, 0xf7c5}, /* U+7085 [2000] */ + {0xe78286, 0x8fefdd}, /* U+7086 [2000] */ + {0xe78289, 0xcfa7}, /* U+7089 */ + {0xe7828a, 0xbfe6}, /* U+708A */ + {0xe7828e, 0xb1ea}, /* U+708E */ + {0xe78292, 0xdfd6}, /* U+7092 */ + {0xe78295, 0x8fefde}, /* U+7095 [2000] */ + {0xe78297, 0x8fefdf}, /* U+7097 [2000] */ + {0xe78299, 0xdfd5}, /* U+7099 */ + {0xe7829f, 0x8fefe2}, /* U+709F [2000] */ + {0xe782a4, 0xf7c6}, /* U+70A4 [2000] */ + {0xe782ab, 0xf7c7}, /* U+70AB [2000] */ + {0xe782ac, 0xdfd9}, /* U+70AC */ + {0xe782ad, 0xc3ba}, /* U+70AD */ + {0xe782ae, 0xdfdc}, /* U+70AE */ + {0xe782af, 0xdfd7}, /* U+70AF */ + {0xe782b1, 0x8fefe3}, /* U+70B1 [2000] */ + {0xe782b3, 0xdfdb}, /* U+70B3 */ + {0xe782b7, 0xf7c8}, /* U+70B7 [2000] */ + {0xe782b8, 0xdfda}, /* U+70B8 */ + {0xe782b9, 0xc5c0}, /* U+70B9 */ + {0xe782ba, 0xb0d9}, /* U+70BA */ + {0xe782bb, 0x8fefe0}, /* U+70BB [2000] */ + {0xe78388, 0xcef5}, /* U+70C8 */ + {0xe7838a, 0x8fefe6}, /* U+70CA [2000] */ + {0xe7838b, 0xdfde}, /* U+70CB */ + {0xe7838f, 0xb1a8}, /* U+70CF */ + {0xe78391, 0x8fefe7}, /* U+70D1 [2000] */ + {0xe78393, 0x8fefe8}, /* U+70D3 [2000] */ + {0xe78394, 0xf7c9}, /* U+70D4 [2000] */ + {0xe78398, 0xf7ca}, /* U+70D8 [2000] */ + {0xe78399, 0xdfe0}, /* U+70D9 */ + {0xe7839c, 0x8fefe9}, /* U+70DC [2000] */ + {0xe7839d, 0xdfdf}, /* U+70DD */ + {0xe7839f, 0xdfdd}, /* U+70DF */ + {0xe783a4, 0xf7cb}, /* U+70E4 [2000] */ + {0xe783ac, 0x8fefe5}, /* U+70EC [2000] */ + {0xe783b1, 0xdfd8}, /* U+70F1 */ + {0xe783b9, 0xcba3}, /* U+70F9 */ + {0xe783bd, 0xdfe2}, /* U+70FD */ + {0xe78483, 0x8fefea}, /* U+7103 [2000] */ + {0xe78484, 0x8fefeb}, /* U+7104 [2000] */ + {0xe78486, 0x8fefec}, /* U+7106 [2000] */ + {0xe78487, 0x8fefed}, /* U+7107 [2000] */ + {0xe78488, 0x8fefee}, /* U+7108 [2000] */ + {0xe78489, 0xdfe1}, /* U+7109 */ + {0xe7848c, 0x8fefef}, /* U+710C [2000] */ + {0xe7848f, 0xf7cc}, /* U+710F [2000] */ + {0xe78494, 0xb1eb}, /* U+7114 */ + {0xe78499, 0xdfe4}, /* U+7119 */ + {0xe7849a, 0xcab2}, /* U+711A */ + {0xe7849c, 0xdfe3}, /* U+711C */ + {0xe7849e, 0xf7ce}, /* U+711E [2000] */ + {0xe784a0, 0xf7cf}, /* U+7120 [2000] */ + {0xe784a1, 0xccb5}, /* U+7121 */ + {0xe784a6, 0xbec7}, /* U+7126 */ + {0xe784ab, 0xf7cd}, /* U+712B [2000] */ + {0xe784ae, 0xf7d0}, /* U+712E [2000] */ + {0xe784af, 0x8feff1}, /* U+712F [2000] */ + {0xe784b0, 0xf7d1}, /* U+7130 [2000] */ + {0xe784b1, 0x8feff2}, /* U+7131 [2000] */ + {0xe784b6, 0xc1b3}, /* U+7136 */ + {0xe784bc, 0xbec6}, /* U+713C */ + {0xe78586, 0xf7d2}, /* U+7146 [2000] */ + {0xe78587, 0xf7d3}, /* U+7147 [2000] */ + {0xe78589, 0xcefb}, /* U+7149 */ + {0xe7858a, 0x8feff4}, /* U+714A [2000] */ + {0xe7858c, 0xdfea}, /* U+714C */ + {0xe7858e, 0xc0f9}, /* U+714E */ + {0xe78590, 0x8feff3}, /* U+7150 [2000] */ + {0xe78591, 0xf7d4}, /* U+7151 [2000] */ + {0xe78592, 0xf7d6}, /* U+7152 [2000] */ + {0xe78593, 0x8feff5}, /* U+7153 [2000] */ + {0xe78595, 0xdfe6}, /* U+7155 */ + {0xe78596, 0xdfeb}, /* U+7156 */ + {0xe78599, 0xb1ec}, /* U+7159 */ + {0xe7859c, 0xf7d7}, /* U+715C [2000] */ + {0xe7859e, 0x8feff6}, /* U+715E [2000] */ + {0xe785a0, 0xf7d8}, /* U+7160 [2000] */ + {0xe785a2, 0xdfe9}, /* U+7162 */ + {0xe785a4, 0xc7e1}, /* U+7164 */ + {0xe785a5, 0xdfe5}, /* U+7165 */ + {0xe785a6, 0xdfe8}, /* U+7166 */ + {0xe785a7, 0xbec8}, /* U+7167 */ + {0xe785a8, 0xf7d9}, /* U+7168 [2000] */ + {0xe785a9, 0xc8d1}, /* U+7169 */ + {0xe785ac, 0xdfec}, /* U+716C */ + {0xe785ae, 0xbcd1}, /* U+716E */ + {0xe785bd, 0xc0fa}, /* U+717D */ + {0xe78680, 0x8feff9}, /* U+7180 [2000] */ + {0xe78684, 0xdfef}, /* U+7184 */ + {0xe78685, 0xf7db}, /* U+7185 [2000] */ + {0xe78687, 0xf7dc}, /* U+7187 [2000] */ + {0xe78688, 0xdfe7}, /* U+7188 */ + {0xe7868a, 0xb7a7}, /* U+718A */ + {0xe7868f, 0xdfed}, /* U+718F */ + {0xe78692, 0xf7dd}, /* U+7192 [2000] */ + {0xe78694, 0xcdd0}, /* U+7194 */ + {0xe78695, 0xdff0}, /* U+7195 */ + {0xe78696, 0x8feff8}, /* U+7196 [2000] */ + {0xe78699, 0xf4a6}, /* U+7199 [1990] */ + {0xe7869b, 0x8feffa}, /* U+719B [2000] */ + {0xe7869f, 0xbdcf}, /* U+719F */ + {0xe786a0, 0x8feffb}, /* U+71A0 [2000] */ + {0xe786a2, 0x8feffc}, /* U+71A2 [2000] */ + {0xe786a8, 0xdff1}, /* U+71A8 */ + {0xe786ac, 0xdff2}, /* U+71AC */ + {0xe786ae, 0x8feffd}, /* U+71AE [2000] */ + {0xe786af, 0x8feffe}, /* U+71AF [2000] */ + {0xe786b1, 0xc7ae}, /* U+71B1 */ + {0xe786b3, 0x8ff0a1}, /* U+71B3 [2000] */ + {0xe786b9, 0xdff4}, /* U+71B9 */ + {0xe786ba, 0xf7df}, /* U+71BA [2000] */ + {0xe786be, 0xdff5}, /* U+71BE */ + {0xe78781, 0xf7de}, /* U+71C1 [2000] */ + {0xe78783, 0xc7b3}, /* U+71C3 */ + {0xe78784, 0xf7e0}, /* U+71C4 [2000] */ + {0xe78788, 0xc5f5}, /* U+71C8 */ + {0xe78789, 0xdff7}, /* U+71C9 */ + {0xe7878b, 0x8ff0a3}, /* U+71CB [2000] */ + {0xe7878e, 0xdff9}, /* U+71CE */ + {0xe78790, 0xced5}, /* U+71D0 */ + {0xe78792, 0xdff6}, /* U+71D2 */ + {0xe78793, 0x8ff0a4}, /* U+71D3 [2000] */ + {0xe78794, 0xdff8}, /* U+71D4 */ + {0xe78795, 0xb1ed}, /* U+71D5 */ + {0xe78797, 0xdff3}, /* U+71D7 */ + {0xe78799, 0x8ff0a5}, /* U+71D9 [2000] */ + {0xe7879c, 0x8ff0a6}, /* U+71DC [2000] */ + {0xe7879f, 0xd3db}, /* U+71DF */ + {0xe787a0, 0xdffa}, /* U+71E0 */ + {0xe787a5, 0xc1e7}, /* U+71E5 */ + {0xe787a6, 0xbbb8}, /* U+71E6 */ + {0xe787a7, 0xdffc}, /* U+71E7 */ + {0xe787ac, 0xdffb}, /* U+71EC */ + {0xe787ad, 0xbfa4}, /* U+71ED */ + {0xe787ae, 0xd2d9}, /* U+71EE */ + {0xe787b5, 0xdffd}, /* U+71F5 */ + {0xe787b9, 0xe0a1}, /* U+71F9 */ + {0xe787bb, 0xdfee}, /* U+71FB */ + {0xe787bc, 0xdffe}, /* U+71FC */ + {0xe787be, 0xf7e1}, /* U+71FE [2000] */ + {0xe787bf, 0xe0a2}, /* U+71FF */ + {0xe78880, 0xf7e2}, /* U+7200 [2000] */ + {0xe78886, 0xc7fa}, /* U+7206 */ + {0xe78887, 0x8ff0a7}, /* U+7207 [2000] */ + {0xe7888d, 0xe0a3}, /* U+720D */ + {0xe78890, 0xe0a4}, /* U+7210 */ + {0xe78895, 0xf7e3}, /* U+7215 [2000] */ + {0xe7889b, 0xe0a5}, /* U+721B */ + {0xe788a8, 0xe0a6}, /* U+7228 */ + {0xe788aa, 0xc4de}, /* U+722A */ + {0xe788ab, 0x8ff0aa}, /* U+722B [2000] */ + {0xe788ac, 0xe0a8}, /* U+722C */ + {0xe788ad, 0xe0a7}, /* U+722D */ + {0xe788b0, 0xe0a9}, /* U+7230 */ + {0xe788b2, 0xe0aa}, /* U+7232 */ + {0xe788b4, 0x8ff0ab}, /* U+7234 [2000] */ + {0xe788b5, 0xbcdf}, /* U+7235 */ + {0xe788b6, 0xc9e3}, /* U+7236 */ + {0xe788b8, 0x8ff0ac}, /* U+7238 [2000] */ + {0xe788b9, 0x8ff0ad}, /* U+7239 [2000] */ + {0xe788ba, 0xccec}, /* U+723A */ + {0xe788bb, 0xe0ab}, /* U+723B */ + {0xe788bc, 0xe0ac}, /* U+723C */ + {0xe788bd, 0xc1d6}, /* U+723D */ + {0xe788be, 0xbca4}, /* U+723E */ + {0xe788bf, 0xe0ad}, /* U+723F */ + {0xe78980, 0xe0ae}, /* U+7240 */ + {0xe78982, 0x8ff0af}, /* U+7242 [2000] */ + {0xe78986, 0xe0af}, /* U+7246 */ + {0xe78987, 0xcad2}, /* U+7247 */ + {0xe78988, 0xc8c7}, /* U+7248 */ + {0xe7898b, 0xe0b0}, /* U+724B */ + {0xe7898c, 0xc7d7}, /* U+724C */ + {0xe78992, 0xc4ad}, /* U+7252 */ + {0xe78993, 0x8ff0b0}, /* U+7253 [2000] */ + {0xe78995, 0xf7e4}, /* U+7255 [2000] */ + {0xe78996, 0xf7e5}, /* U+7256 [2000] */ + {0xe78997, 0x8ff0b1}, /* U+7257 [2000] */ + {0xe78998, 0xe0b1}, /* U+7258 */ + {0xe78999, 0xb2e7}, /* U+7259 */ + {0xe7899b, 0xb5ed}, /* U+725B */ + {0xe7899d, 0xccc6}, /* U+725D */ + {0xe7899f, 0xccb6}, /* U+725F */ + {0xe789a1, 0xb2b4}, /* U+7261 */ + {0xe789a2, 0xcfb4}, /* U+7262 */ + {0xe789a3, 0x8ff0b2}, /* U+7263 [2000] */ + {0xe789a7, 0xcbd2}, /* U+7267 */ + {0xe789a9, 0xcaaa}, /* U+7269 */ + {0xe789ae, 0x8ff0b4}, /* U+726E [2000] */ + {0xe789af, 0x8ff0b5}, /* U+726F [2000] */ + {0xe789b2, 0xc0b7}, /* U+7272 */ + {0xe789b4, 0xe0b2}, /* U+7274 */ + {0xe789b8, 0x8ff0b6}, /* U+7278 [2000] */ + {0xe789b9, 0xc6c3}, /* U+7279 */ + {0xe789bd, 0xb8a3}, /* U+727D */ + {0xe789be, 0xe0b3}, /* U+727E */ + {0xe789bf, 0x8ff0b7}, /* U+727F [2000] */ + {0xe78a80, 0xbad4}, /* U+7280 */ + {0xe78a81, 0xe0b5}, /* U+7281 */ + {0xe78a82, 0xe0b4}, /* U+7282 */ + {0xe78a87, 0xe0b6}, /* U+7287 */ + {0xe78a8d, 0xf7e7}, /* U+728D [2000] */ + {0xe78a8e, 0x8ff0b8}, /* U+728E [2000] */ + {0xe78a92, 0xe0b7}, /* U+7292 */ + {0xe78a96, 0xe0b8}, /* U+7296 */ + {0xe78a9b, 0xf7e8}, /* U+729B [2000] */ + {0xe78aa0, 0xb5be}, /* U+72A0 */ + {0xe78aa2, 0xe0b9}, /* U+72A2 */ + {0xe78aa7, 0xe0ba}, /* U+72A7 */ + {0xe78aac, 0xb8a4}, /* U+72AC */ + {0xe78aad, 0x8ff0ba}, /* U+72AD [2000] */ + {0xe78aae, 0x8ff0bb}, /* U+72AE [2000] */ + {0xe78aaf, 0xc8c8}, /* U+72AF */ + {0xe78ab0, 0x8ff0bc}, /* U+72B0 [2000] */ + {0xe78ab1, 0x8ff0bd}, /* U+72B1 [2000] */ + {0xe78ab2, 0xe0bc}, /* U+72B2 */ + {0xe78ab6, 0xbef5}, /* U+72B6 */ + {0xe78ab9, 0xe0bb}, /* U+72B9 */ + {0xe78abe, 0xf7e9}, /* U+72BE [2000] */ + {0xe78b80, 0xf7ea}, /* U+72C0 [2000] */ + {0xe78b81, 0x8ff0be}, /* U+72C1 [2000] */ + {0xe78b82, 0xb6b8}, /* U+72C2 */ + {0xe78b83, 0xe0bd}, /* U+72C3 */ + {0xe78b84, 0xe0bf}, /* U+72C4 */ + {0xe78b86, 0xe0be}, /* U+72C6 */ + {0xe78b8c, 0x8ff0c0}, /* U+72CC [2000] */ + {0xe78b8e, 0xe0c0}, /* U+72CE */ + {0xe78b90, 0xb8d1}, /* U+72D0 */ + {0xe78b92, 0xe0c1}, /* U+72D2 */ + {0xe78b97, 0xb6e9}, /* U+72D7 */ + {0xe78b99, 0xc1c0}, /* U+72D9 */ + {0xe78b9b, 0xb9fd}, /* U+72DB */ + {0xe78ba0, 0xe0c3}, /* U+72E0 */ + {0xe78ba1, 0xe0c4}, /* U+72E1 */ + {0xe78ba2, 0xe0c2}, /* U+72E2 */ + {0xe78ba9, 0xbced}, /* U+72E9 */ + {0xe78bac, 0xc6c8}, /* U+72EC */ + {0xe78bad, 0xb6b9}, /* U+72ED */ + {0xe78bb3, 0x8ff0c3}, /* U+72F3 [2000] */ + {0xe78bb7, 0xe0c6}, /* U+72F7 */ + {0xe78bb8, 0xc3ac}, /* U+72F8 */ + {0xe78bb9, 0xe0c5}, /* U+72F9 */ + {0xe78bba, 0x8ff0c4}, /* U+72FA [2000] */ + {0xe78bbb, 0xf7eb}, /* U+72FB [2000] */ + {0xe78bbc, 0xcfb5}, /* U+72FC */ + {0xe78bbd, 0xc7e2}, /* U+72FD */ + {0xe78c87, 0x8ff0c5}, /* U+7307 [2000] */ + {0xe78c8a, 0xe0c9}, /* U+730A */ + {0xe78c92, 0x8ff0c6}, /* U+7312 [2000] */ + {0xe78c96, 0xe0cb}, /* U+7316 */ + {0xe78c97, 0xe0c8}, /* U+7317 */ + {0xe78c98, 0x8ff0c7}, /* U+7318 [2000] */ + {0xe78c99, 0x8ff0c8}, /* U+7319 [2000] */ + {0xe78c9b, 0xccd4}, /* U+731B */ + {0xe78c9c, 0xe0ca}, /* U+731C */ + {0xe78c9d, 0xe0cc}, /* U+731D */ + {0xe78c9f, 0xcec4}, /* U+731F */ + {0xe78ca5, 0xe0d0}, /* U+7325 */ + {0xe78ca7, 0xf7ed}, /* U+7327 [2000] */ + {0xe78ca8, 0xf7ee}, /* U+7328 [2000] */ + {0xe78ca9, 0xe0cf}, /* U+7329 */ + {0xe78caa, 0xc3f6}, /* U+732A */ + {0xe78cab, 0xc7ad}, /* U+732B */ + {0xe78cac, 0x8ff0cb}, /* U+732C [2000] */ + {0xe78cae, 0xb8a5}, /* U+732E */ + {0xe78caf, 0xe0ce}, /* U+732F */ + {0xe78cb1, 0x8ff0cc}, /* U+7331 [2000] */ + {0xe78cb3, 0x8ff0cd}, /* U+7333 [2000] */ + {0xe78cb4, 0xe0cd}, /* U+7334 */ + {0xe78cb6, 0xcdb1}, /* U+7336 */ + {0xe78cb7, 0xcdb2}, /* U+7337 */ + {0xe78cb9, 0x8ff0ca}, /* U+7339 [2000] */ + {0xe78cbd, 0x8ff0ce}, /* U+733D [2000] */ + {0xe78cbe, 0xe0d1}, /* U+733E */ + {0xe78cbf, 0xb1ee}, /* U+733F */ + {0xe78d84, 0xb9f6}, /* U+7344 */ + {0xe78d85, 0xbbe2}, /* U+7345 */ + {0xe78d8e, 0xe0d2}, /* U+734E */ + {0xe78d8f, 0xe0d3}, /* U+734F */ + {0xe78d90, 0xf7f0}, /* U+7350 [2000] */ + {0xe78d92, 0x8ff0cf}, /* U+7352 [2000] */ + {0xe78d97, 0xe0d5}, /* U+7357 */ + {0xe78da3, 0xbdc3}, /* U+7363 */ + {0xe78da6, 0xf7f1}, /* U+7366 [2000] */ + {0xe78da8, 0xe0d7}, /* U+7368 */ + {0xe78daa, 0xe0d6}, /* U+736A */ + {0xe78dab, 0x8ff0d1}, /* U+736B [2000] */ + {0xe78dac, 0x8ff0d2}, /* U+736C [2000] */ + {0xe78dae, 0x8ff0d4}, /* U+736E [2000] */ + {0xe78daf, 0x8ff0d5}, /* U+736F [2000] */ + {0xe78db0, 0xe0d8}, /* U+7370 */ + {0xe78db1, 0x8ff0d6}, /* U+7371 [2000] */ + {0xe78db2, 0xb3cd}, /* U+7372 */ + {0xe78db5, 0xe0da}, /* U+7375 */ + {0xe78db7, 0x8ff0d7}, /* U+7377 [2000] */ + {0xe78db8, 0xe0d9}, /* U+7378 */ + {0xe78dba, 0xe0dc}, /* U+737A */ + {0xe78dbb, 0xe0db}, /* U+737B */ + {0xe78dbc, 0xf7f2}, /* U+737C [2000] */ + {0xe78e81, 0x8ff0d8}, /* U+7381 [2000] */ + {0xe78e84, 0xb8bc}, /* U+7384 */ + {0xe78e85, 0x8ff0d9}, /* U+7385 [2000] */ + {0xe78e87, 0xcea8}, /* U+7387 */ + {0xe78e89, 0xb6cc}, /* U+7389 */ + {0xe78e8a, 0x8ff0da}, /* U+738A [2000] */ + {0xe78e8b, 0xb2a6}, /* U+738B */ + {0xe78e94, 0x8ff0db}, /* U+7394 [2000] */ + {0xe78e95, 0xf7f3}, /* U+7395 [2000] */ + {0xe78e96, 0xb6ea}, /* U+7396 */ + {0xe78e98, 0x8ff0dc}, /* U+7398 [2000] */ + {0xe78e9c, 0x8ff0dd}, /* U+739C [2000] */ + {0xe78e9e, 0x8ff0de}, /* U+739E [2000] */ + {0xe78e9f, 0xf7f4}, /* U+739F [2000] */ + {0xe78ea0, 0xf7f5}, /* U+73A0 [2000] */ + {0xe78ea2, 0xf7f6}, /* U+73A2 [2000] */ + {0xe78ea5, 0x8ff0df}, /* U+73A5 [2000] */ + {0xe78ea6, 0xf7f7}, /* U+73A6 [2000] */ + {0xe78ea8, 0x8ff0e0}, /* U+73A8 [2000] */ + {0xe78ea9, 0xb4e1}, /* U+73A9 */ + {0xe78eab, 0xf7f8}, /* U+73AB [2000] */ + {0xe78eb2, 0xcee8}, /* U+73B2 */ + {0xe78eb3, 0xe0de}, /* U+73B3 */ + {0xe78eb5, 0x8ff0e1}, /* U+73B5 [2000] */ + {0xe78eb7, 0x8ff0e2}, /* U+73B7 [2000] */ + {0xe78eb9, 0x8ff0e3}, /* U+73B9 [2000] */ + {0xe78ebb, 0xe0e0}, /* U+73BB */ + {0xe78ebc, 0x8ff0e4}, /* U+73BC [2000] */ + {0xe78ebf, 0x8ff0e5}, /* U+73BF [2000] */ + {0xe78f80, 0xe0e1}, /* U+73C0 */ + {0xe78f82, 0xb2d1}, /* U+73C2 */ + {0xe78f85, 0x8ff0e6}, /* U+73C5 [2000] */ + {0xe78f88, 0xe0dd}, /* U+73C8 */ + {0xe78f89, 0xf7f9}, /* U+73C9 [2000] */ + {0xe78f8a, 0xbbb9}, /* U+73CA */ + {0xe78f8b, 0x8ff0e7}, /* U+73CB [2000] */ + {0xe78f8d, 0xc4c1}, /* U+73CD */ + {0xe78f8e, 0xe0df}, /* U+73CE */ + {0xe78f8f, 0xf7fa}, /* U+73CF [2000] */ + {0xe78f96, 0xf7fb}, /* U+73D6 [2000] */ + {0xe78f99, 0xf7fc}, /* U+73D9 [2000] */ + {0xe78f9e, 0xe0e4}, /* U+73DE */ + {0xe78fa0, 0xbcee}, /* U+73E0 */ + {0xe78fa1, 0x8ff0e8}, /* U+73E1 [2000] */ + {0xe78fa3, 0xf7fd}, /* U+73E3 [2000] */ + {0xe78fa5, 0xe0e2}, /* U+73E5 */ + {0xe78fa7, 0x8ff0e9}, /* U+73E7 [2000] */ + {0xe78fa9, 0xf7fe}, /* U+73E9 [2000] */ + {0xe78faa, 0xb7be}, /* U+73EA */ + {0xe78fad, 0xc8c9}, /* U+73ED */ + {0xe78fae, 0xe0e3}, /* U+73EE */ + {0xe78fb1, 0xe0fe}, /* U+73F1 */ + {0xe78fb8, 0xe0e9}, /* U+73F8 */ + {0xe78fb9, 0x8ff0ea}, /* U+73F9 [2000] */ + {0xe78fba, 0x8ff0ec}, /* U+73FA [2000] */ + {0xe78fbe, 0xb8bd}, /* U+73FE */ + {0xe79081, 0x8ff0ed}, /* U+7401 [2000] */ + {0xe79083, 0xb5e5}, /* U+7403 */ + {0xe79085, 0xe0e6}, /* U+7405 */ + {0xe79086, 0xcdfd}, /* U+7406 */ + {0xe79087, 0xf8a1}, /* U+7407 [2000] */ + {0xe79089, 0xceb0}, /* U+7409 */ + {0xe7908a, 0xf8a2}, /* U+740A [2000] */ + {0xe79093, 0x8ff0eb}, /* U+7413 [2000] */ + {0xe7909a, 0xf8a3}, /* U+741A [2000] */ + {0xe7909b, 0xf8a4}, /* U+741B [2000] */ + {0xe790a2, 0xc2f6}, /* U+7422 */ + {0xe790a4, 0x8ff0ee}, /* U+7424 [2000] */ + {0xe790a5, 0xe0e8}, /* U+7425 */ + {0xe790a6, 0xf8a6}, /* U+7426 [2000] */ + {0xe790a8, 0xf8a7}, /* U+7428 [2000] */ + {0xe790aa, 0xf8a8}, /* U+742A [2000] */ + {0xe790ab, 0xf8a9}, /* U+742B [2000] */ + {0xe790ac, 0xf8aa}, /* U+742C [2000] */ + {0xe790ae, 0xf8ab}, /* U+742E [2000] */ + {0xe790af, 0xf8ac}, /* U+742F [2000] */ + {0xe790b0, 0xf8ad}, /* U+7430 [2000] */ + {0xe790b1, 0x8ff0ef}, /* U+7431 [2000] */ + {0xe790b2, 0xe0ea}, /* U+7432 */ + {0xe790b3, 0xced6}, /* U+7433 */ + {0xe790b4, 0xb6d7}, /* U+7434 */ + {0xe790b5, 0xc8fc}, /* U+7435 */ + {0xe790b6, 0xc7ca}, /* U+7436 */ + {0xe790b9, 0x8ff0f0}, /* U+7439 [2000] */ + {0xe790ba, 0xe0eb}, /* U+743A */ + {0xe790bf, 0xe0ed}, /* U+743F */ + {0xe79180, 0x8ff0f2}, /* U+7440 [2000] */ + {0xe79181, 0xe0f0}, /* U+7441 */ + {0xe79183, 0x8ff0f3}, /* U+7443 [2000] */ + {0xe79184, 0xf8ae}, /* U+7444 [2000] */ + {0xe79186, 0xf8af}, /* U+7446 [2000] */ + {0xe79187, 0xf8b0}, /* U+7447 [2000] */ + {0xe7918b, 0xf8b1}, /* U+744B [2000] */ + {0xe7918d, 0x8ff0f4}, /* U+744D [2000] */ + {0xe79192, 0x8ff0f5}, /* U+7452 [2000] */ + {0xe79193, 0x8ff0f1}, /* U+7453 [2000] */ + {0xe79195, 0xe0ec}, /* U+7455 */ + {0xe79197, 0xf8b2}, /* U+7457 [2000] */ + {0xe79199, 0xe0ef}, /* U+7459 */ + {0xe7919a, 0xb8ea}, /* U+745A */ + {0xe7919b, 0xb1cd}, /* U+745B */ + {0xe7919c, 0xe0f1}, /* U+745C */ + {0xe7919d, 0x8ff0f6}, /* U+745D [2000] */ + {0xe7919e, 0xbff0}, /* U+745E */ + {0xe7919f, 0xe0ee}, /* U+745F */ + {0xe791a0, 0xcedc}, /* U+7460 */ + {0xe791a2, 0xf8b3}, /* U+7462 [2000] */ + {0xe791a3, 0xe0f4}, /* U+7463 */ + {0xe791a4, 0xf4a4}, /* U+7464 [1983] */ + {0xe791a9, 0xe0f2}, /* U+7469 */ + {0xe791aa, 0xe0f5}, /* U+746A */ + {0xe791ab, 0xf8b4}, /* U+746B [2000] */ + {0xe791ad, 0xf8b5}, /* U+746D [2000] */ + {0xe791af, 0xe0e7}, /* U+746F */ + {0xe791b0, 0xe0f3}, /* U+7470 */ + {0xe791b1, 0x8ff0f7}, /* U+7471 [2000] */ + {0xe791b3, 0xbabc}, /* U+7473 */ + {0xe791b6, 0xe0f6}, /* U+7476 */ + {0xe791be, 0xe0f7}, /* U+747E */ + {0xe79281, 0x8ff0f8}, /* U+7481 [2000] */ + {0xe79283, 0xcdfe}, /* U+7483 */ + {0xe79285, 0x8ff0f9}, /* U+7485 [2000] */ + {0xe79286, 0xf8b6}, /* U+7486 [2000] */ + {0xe79287, 0xf8b7}, /* U+7487 [2000] */ + {0xe79288, 0x8ff0fa}, /* U+7488 [2000] */ + {0xe79289, 0xf8b8}, /* U+7489 [2000] */ + {0xe7928b, 0xe0f8}, /* U+748B */ + {0xe79290, 0xf8bd}, /* U+7490 [2000] */ + {0xe79292, 0x8ff0fc}, /* U+7492 [2000] */ + {0xe79297, 0x8ff0fd}, /* U+7497 [2000] */ + {0xe79298, 0xf8b9}, /* U+7498 [2000] */ + {0xe79299, 0x8ff0fe}, /* U+7499 [2000] */ + {0xe7929c, 0xf8ba}, /* U+749C [2000] */ + {0xe7929e, 0xe0f9}, /* U+749E */ + {0xe7929f, 0xf8bb}, /* U+749F [2000] */ + {0xe792a0, 0x8ff1a1}, /* U+74A0 [2000] */ + {0xe792a1, 0x8ff1a2}, /* U+74A1 [2000] */ + {0xe792a2, 0xe0e5}, /* U+74A2 */ + {0xe792a3, 0xf8bc}, /* U+74A3 [2000] */ + {0xe792a5, 0x8ff1a3}, /* U+74A5 [2000] */ + {0xe792a6, 0xf8be}, /* U+74A6 [2000] */ + {0xe792a7, 0xe0fa}, /* U+74A7 */ + {0xe792a8, 0xf8bf}, /* U+74A8 [2000] */ + {0xe792a9, 0xf8c0}, /* U+74A9 [2000] */ + {0xe792aa, 0x8ff1a4}, /* U+74AA [2000] */ + {0xe792ab, 0x8ff1a5}, /* U+74AB [2000] */ + {0xe792b0, 0xb4c4}, /* U+74B0 */ + {0xe792b5, 0xf8c1}, /* U+74B5 [2000] */ + {0xe792b9, 0x8ff1a6}, /* U+74B9 [2000] */ + {0xe792ba, 0x8ff1a8}, /* U+74BA [2000] */ + {0xe792bb, 0x8ff1a7}, /* U+74BB [2000] */ + {0xe792bd, 0xbca5}, /* U+74BD */ + {0xe792bf, 0xf8c2}, /* U+74BF [2000] */ + {0xe79388, 0xf8c3}, /* U+74C8 [2000] */ + {0xe79389, 0xf8c4}, /* U+74C9 [2000] */ + {0xe7938a, 0xe0fb}, /* U+74CA */ + {0xe7938f, 0xe0fc}, /* U+74CF */ + {0xe79394, 0xe0fd}, /* U+74D4 */ + {0xe79396, 0x8ff1a9}, /* U+74D6 [2000] */ + {0xe79398, 0x8ff1aa}, /* U+74D8 [2000] */ + {0xe7939a, 0xf8c5}, /* U+74DA [2000] */ + {0xe7939c, 0xb1bb}, /* U+74DC */ + {0xe7939e, 0x8ff1ab}, /* U+74DE [2000] */ + {0xe793a0, 0xe1a1}, /* U+74E0 */ + {0xe793a2, 0xc9bb}, /* U+74E2 */ + {0xe793a3, 0xe1a2}, /* U+74E3 */ + {0xe793a6, 0xb4a4}, /* U+74E6 */ + {0xe793a7, 0xe1a3}, /* U+74E7 */ + {0xe793a9, 0xe1a4}, /* U+74E9 */ + {0xe793ab, 0x8ff1ad}, /* U+74EB [2000] */ + {0xe793ae, 0xe1a5}, /* U+74EE */ + {0xe793af, 0x8ff1ac}, /* U+74EF [2000] */ + {0xe793b0, 0xe1a7}, /* U+74F0 */ + {0xe793b1, 0xe1a8}, /* U+74F1 */ + {0xe793b2, 0xe1a6}, /* U+74F2 */ + {0xe793b6, 0xc9d3}, /* U+74F6 */ + {0xe793b7, 0xe1aa}, /* U+74F7 */ + {0xe793b8, 0xe1a9}, /* U+74F8 */ + {0xe793ba, 0x8ff1af}, /* U+74FA [2000] */ + {0xe793bf, 0xf8c6}, /* U+74FF [2000] */ + {0xe79481, 0xf8c7}, /* U+7501 [2000] */ + {0xe79483, 0xe1ac}, /* U+7503 */ + {0xe79484, 0xe1ab}, /* U+7504 */ + {0xe79485, 0xe1ad}, /* U+7505 */ + {0xe7948c, 0xe1ae}, /* U+750C */ + {0xe7948d, 0xe1b0}, /* U+750D */ + {0xe7948e, 0xe1af}, /* U+750E */ + {0xe79491, 0xb9f9}, /* U+7511 */ + {0xe79493, 0xe1b2}, /* U+7513 */ + {0xe79495, 0xe1b1}, /* U+7515 */ + {0xe79497, 0xf8c8}, /* U+7517 [2000] */ + {0xe79498, 0xb4c5}, /* U+7518 */ + {0xe7949a, 0xbfd3}, /* U+751A */ + {0xe7949c, 0xc5bc}, /* U+751C */ + {0xe7949e, 0xe1b3}, /* U+751E */ + {0xe7949f, 0xc0b8}, /* U+751F */ + {0xe794a0, 0x8ff1b1}, /* U+7520 [2000] */ + {0xe794a3, 0xbbba}, /* U+7523 */ + {0xe794a4, 0x8ff1b2}, /* U+7524 [2000] */ + {0xe794a5, 0xb1f9}, /* U+7525 */ + {0xe794a6, 0xe1b4}, /* U+7526 */ + {0xe794a8, 0xcdd1}, /* U+7528 */ + {0xe794aa, 0x8ff1b3}, /* U+752A [2000] */ + {0xe794ab, 0xcae3}, /* U+752B */ + {0xe794ac, 0xe1b5}, /* U+752C */ + {0xe794af, 0xf8c9}, /* U+752F [2000] */ + {0xe794b0, 0xc5c4}, /* U+7530 */ + {0xe794b1, 0xcdb3}, /* U+7531 */ + {0xe794b2, 0xb9c3}, /* U+7532 */ + {0xe794b3, 0xbfbd}, /* U+7533 */ + {0xe794b7, 0xc3cb}, /* U+7537 */ + {0xe794b8, 0xd2b4}, /* U+7538 */ + {0xe794ba, 0xc4ae}, /* U+753A */ + {0xe794bb, 0xb2e8}, /* U+753B */ + {0xe794bc, 0xe1b6}, /* U+753C */ + {0xe794bd, 0x8ff1b6}, /* U+753D [2000] */ + {0xe794be, 0x8ff1b7}, /* U+753E [2000] */ + {0xe79580, 0x8ff1b8}, /* U+7540 [2000] */ + {0xe79584, 0xe1b7}, /* U+7544 */ + {0xe79586, 0xe1bc}, /* U+7546 */ + {0xe79588, 0x8ff1b9}, /* U+7548 [2000] */ + {0xe79589, 0xe1ba}, /* U+7549 */ + {0xe7958a, 0xe1b9}, /* U+754A */ + {0xe7958b, 0xdac2}, /* U+754B */ + {0xe7958c, 0xb3a6}, /* U+754C */ + {0xe7958d, 0xe1b8}, /* U+754D */ + {0xe7958e, 0x8ff1ba}, /* U+754E [2000] */ + {0xe7958f, 0xb0da}, /* U+754F */ + {0xe79590, 0x8ff1bb}, /* U+7550 [2000] */ + {0xe79591, 0xc8aa}, /* U+7551 */ + {0xe79592, 0x8ff1bc}, /* U+7552 [2000] */ + {0xe79594, 0xc8ca}, /* U+7554 */ + {0xe79599, 0xceb1}, /* U+7559 */ + {0xe7959a, 0xe1bd}, /* U+755A */ + {0xe7959b, 0xe1bb}, /* U+755B */ + {0xe7959c, 0xc3dc}, /* U+755C */ + {0xe7959d, 0xc0a6}, /* U+755D */ + {0xe795a0, 0xc8ab}, /* U+7560 */ + {0xe795a2, 0xc9ad}, /* U+7562 */ + {0xe795a4, 0xe1bf}, /* U+7564 */ + {0xe795a5, 0xceac}, /* U+7565 */ + {0xe795a6, 0xb7cd}, /* U+7566 */ + {0xe795a7, 0xe1c0}, /* U+7567 */ + {0xe795a9, 0xe1be}, /* U+7569 */ + {0xe795aa, 0xc8d6}, /* U+756A */ + {0xe795ab, 0xe1c1}, /* U+756B */ + {0xe795ac, 0x8ff1bd}, /* U+756C [2000] */ + {0xe795ad, 0xe1c2}, /* U+756D */ + {0xe795af, 0xf8ca}, /* U+756F [2000] */ + {0xe795b0, 0xb0db}, /* U+7570 */ + {0xe795b1, 0x8ff1bf}, /* U+7571 [2000] */ + {0xe795b2, 0x8ff1be}, /* U+7572 [2000] */ + {0xe795b3, 0xbef6}, /* U+7573 */ + {0xe795b4, 0xe1c7}, /* U+7574 */ + {0xe795b6, 0xe1c4}, /* U+7576 */ + {0xe795b7, 0xc6ed}, /* U+7577 */ + {0xe795b8, 0xe1c3}, /* U+7578 */ + {0xe795b9, 0xf8cb}, /* U+7579 [2000] */ + {0xe795ba, 0x8ff1c0}, /* U+757A [2000] */ + {0xe795bd, 0x8ff1c1}, /* U+757D [2000] */ + {0xe795be, 0x8ff1c2}, /* U+757E [2000] */ + {0xe795bf, 0xb5a6}, /* U+757F */ + {0xe79681, 0x8ff1c3}, /* U+7581 [2000] */ + {0xe79682, 0xe1ca}, /* U+7582 */ + {0xe79686, 0xe1c5}, /* U+7586 */ + {0xe79687, 0xe1c6}, /* U+7587 */ + {0xe79689, 0xe1c9}, /* U+7589 */ + {0xe7968a, 0xe1c8}, /* U+758A */ + {0xe7968b, 0xc9a5}, /* U+758B */ + {0xe7968c, 0x8ff1c5}, /* U+758C [2000] */ + {0xe7968e, 0xc1c2}, /* U+758E */ + {0xe7968f, 0xc1c1}, /* U+758F */ + {0xe79691, 0xb5bf}, /* U+7591 */ + {0xe79692, 0xf8cc}, /* U+7592 [2000] */ + {0xe79694, 0xe1cb}, /* U+7594 */ + {0xe7969a, 0xe1cc}, /* U+759A */ + {0xe7969d, 0xe1cd}, /* U+759D */ + {0xe796a2, 0x8ff1c7}, /* U+75A2 [2000] */ + {0xe796a3, 0xe1cf}, /* U+75A3 */ + {0xe796a5, 0xe1ce}, /* U+75A5 */ + {0xe796ab, 0xb1d6}, /* U+75AB */ + {0xe796b0, 0x8ff1c9}, /* U+75B0 [2000] */ + {0xe796b1, 0xe1d7}, /* U+75B1 */ + {0xe796b2, 0xc8e8}, /* U+75B2 */ + {0xe796b3, 0xe1d1}, /* U+75B3 */ + {0xe796b5, 0xe1d3}, /* U+75B5 */ + {0xe796b7, 0x8ff1ca}, /* U+75B7 [2000] */ + {0xe796b8, 0xe1d5}, /* U+75B8 */ + {0xe796b9, 0xbfbe}, /* U+75B9 */ + {0xe796bc, 0xe1d6}, /* U+75BC */ + {0xe796bd, 0xe1d4}, /* U+75BD */ + {0xe796be, 0xbcc0}, /* U+75BE */ + {0xe796bf, 0x8ff1cb}, /* U+75BF [2000] */ + {0xe79780, 0x8ff1cc}, /* U+75C0 [2000] */ + {0xe79782, 0xe1d0}, /* U+75C2 */ + {0xe79783, 0xe1d2}, /* U+75C3 */ + {0xe79785, 0xc9c2}, /* U+75C5 */ + {0xe79786, 0x8ff1cd}, /* U+75C6 [2000] */ + {0xe79787, 0xbec9}, /* U+75C7 */ + {0xe7978a, 0xe1d9}, /* U+75CA */ + {0xe7978d, 0xe1d8}, /* U+75CD */ + {0xe7978e, 0xf8ce}, /* U+75CE [2000] */ + {0xe7978f, 0x8ff1ce}, /* U+75CF [2000] */ + {0xe79792, 0xe1da}, /* U+75D2 */ + {0xe79793, 0x8ff1cf}, /* U+75D3 [2000] */ + {0xe79794, 0xbca6}, /* U+75D4 */ + {0xe79795, 0xbaaf}, /* U+75D5 */ + {0xe79798, 0xc5f7}, /* U+75D8 */ + {0xe79799, 0xe1db}, /* U+75D9 */ + {0xe7979b, 0xc4cb}, /* U+75DB */ + {0xe7979d, 0x8ff1d0}, /* U+75DD [2000] */ + {0xe7979e, 0xe1dd}, /* U+75DE */ + {0xe7979f, 0x8ff1d1}, /* U+75DF [2000] */ + {0xe797a0, 0x8ff1d2}, /* U+75E0 [2000] */ + {0xe797a2, 0xcea1}, /* U+75E2 */ + {0xe797a3, 0xe1dc}, /* U+75E3 */ + {0xe797a4, 0xf8cf}, /* U+75E4 [2000] */ + {0xe797a7, 0x8ff1d3}, /* U+75E7 [2000] */ + {0xe797a9, 0xc1e9}, /* U+75E9 */ + {0xe797ac, 0x8ff1d4}, /* U+75EC [2000] */ + {0xe797ae, 0x8ff1d5}, /* U+75EE [2000] */ + {0xe797b0, 0xe1e2}, /* U+75F0 */ + {0xe797b1, 0x8ff1d6}, /* U+75F1 [2000] */ + {0xe797b2, 0xe1e4}, /* U+75F2 */ + {0xe797b3, 0xe1e5}, /* U+75F3 */ + {0xe797b4, 0xc3d4}, /* U+75F4 */ + {0xe797b9, 0x8ff1d7}, /* U+75F9 [2000] */ + {0xe797ba, 0xe1e3}, /* U+75FA */ + {0xe797bc, 0xe1e0}, /* U+75FC */ + {0xe797be, 0xe1de}, /* U+75FE */ + {0xe797bf, 0xe1df}, /* U+75FF */ + {0xe79880, 0xf8d0}, /* U+7600 [2000] */ + {0xe79881, 0xe1e1}, /* U+7601 */ + {0xe79882, 0xf8d1}, /* U+7602 [2000] */ + {0xe79883, 0x8ff1d8}, /* U+7603 [2000] */ + {0xe79887, 0x8ff1da}, /* U+7607 [2000] */ + {0xe79888, 0xf8d2}, /* U+7608 [2000] */ + {0xe79889, 0xe1e8}, /* U+7609 */ + {0xe7988b, 0xe1e6}, /* U+760B */ + {0xe7988d, 0xe1e7}, /* U+760D */ + {0xe7988f, 0x8ff1db}, /* U+760F [2000] */ + {0xe79893, 0x8ff1de}, /* U+7613 [2000] */ + {0xe79895, 0xf8d3}, /* U+7615 [2000] */ + {0xe79896, 0xf8d4}, /* U+7616 [2000] */ + {0xe79898, 0x8ff1d9}, /* U+7618 [2000] */ + {0xe79899, 0xf8d5}, /* U+7619 [2000] */ + {0xe7989b, 0x8ff1df}, /* U+761B [2000] */ + {0xe7989c, 0x8ff1e0}, /* U+761C [2000] */ + {0xe7989e, 0xf8d6}, /* U+761E [2000] */ + {0xe7989f, 0xe1e9}, /* U+761F */ + {0xe798a0, 0xe1eb}, /* U+7620 */ + {0xe798a1, 0xe1ec}, /* U+7621 */ + {0xe798a2, 0xe1ed}, /* U+7622 */ + {0xe798a4, 0xe1ee}, /* U+7624 */ + {0xe798a5, 0x8ff1e2}, /* U+7625 [2000] */ + {0xe798a6, 0xfefd}, /* U+7626 [2004] */ + {0xe798a7, 0xe1ea}, /* U+7627 */ + {0xe798a8, 0x8ff1e3}, /* U+7628 [2000] */ + {0xe798ad, 0xf8d7}, /* U+762D [2000] */ + {0xe798b0, 0xe1f0}, /* U+7630 */ + {0xe798b3, 0x8ff1e5}, /* U+7633 [2000] */ + {0xe798b4, 0xe1ef}, /* U+7634 */ + {0xe798b5, 0xf8d8}, /* U+7635 [2000] */ + {0xe798bb, 0xe1f1}, /* U+763B */ + {0xe798bc, 0x8ff1e4}, /* U+763C [2000] */ + {0xe79981, 0x8ff1e8}, /* U+7641 [2000] */ + {0xe79982, 0xcec5}, /* U+7642 */ + {0xe79983, 0xf8d9}, /* U+7643 [2000] */ + {0xe79986, 0xe1f4}, /* U+7646 */ + {0xe79987, 0xe1f2}, /* U+7647 */ + {0xe79988, 0xe1f3}, /* U+7648 */ + {0xe79989, 0x8ff1ea}, /* U+7649 [2000] */ + {0xe7998b, 0xf8da}, /* U+764B [2000] */ + {0xe7998c, 0xb4e2}, /* U+764C */ + {0xe79992, 0xccfe}, /* U+7652 */ + {0xe79995, 0x8ff1eb}, /* U+7655 [2000] */ + {0xe79996, 0xcaca}, /* U+7656 */ + {0xe79998, 0xe1f6}, /* U+7658 */ + {0xe7999c, 0xe1f5}, /* U+765C */ + {0xe799a1, 0xe1f7}, /* U+7661 */ + {0xe799a2, 0xe1f8}, /* U+7662 */ + {0xe799a4, 0xf8db}, /* U+7664 [2000] */ + {0xe799a5, 0xf8dc}, /* U+7665 [2000] */ + {0xe799a7, 0xe1fc}, /* U+7667 */ + {0xe799a8, 0xe1f9}, /* U+7668 */ + {0xe799a9, 0xe1fa}, /* U+7669 */ + {0xe799aa, 0xe1fb}, /* U+766A */ + {0xe799ac, 0xe1fd}, /* U+766C */ + {0xe799ad, 0xf8dd}, /* U+766D [2000] */ + {0xe799ae, 0x8ff1ed}, /* U+766E [2000] */ + {0xe799af, 0xf8de}, /* U+766F [2000] */ + {0xe799b0, 0xe1fe}, /* U+7670 */ + {0xe799b1, 0xf8df}, /* U+7671 [2000] */ + {0xe799b2, 0xe2a1}, /* U+7672 */ + {0xe799b6, 0xe2a2}, /* U+7676 */ + {0xe799b8, 0xe2a3}, /* U+7678 */ + {0xe799ba, 0xc8af}, /* U+767A */ + {0xe799bb, 0xc5d0}, /* U+767B */ + {0xe799bc, 0xe2a4}, /* U+767C */ + {0xe799bd, 0xc7f2}, /* U+767D */ + {0xe799be, 0xc9b4}, /* U+767E */ + {0xe79a80, 0xe2a5}, /* U+7680 */ + {0xe79a81, 0xf8e0}, /* U+7681 [2000] */ + {0xe79a83, 0xe2a6}, /* U+7683 */ + {0xe79a84, 0xc5aa}, /* U+7684 */ + {0xe79a86, 0xb3a7}, /* U+7686 */ + {0xe79a87, 0xb9c4}, /* U+7687 */ + {0xe79a88, 0xe2a7}, /* U+7688 */ + {0xe79a8b, 0xe2a8}, /* U+768B */ + {0xe79a8e, 0xe2a9}, /* U+768E */ + {0xe79a90, 0xbba9}, /* U+7690 */ + {0xe79a93, 0xe2ab}, /* U+7693 */ + {0xe79a95, 0x8ff1ee}, /* U+7695 [2000] */ + {0xe79a96, 0xe2aa}, /* U+7696 */ + {0xe79a99, 0xe2ac}, /* U+7699 */ + {0xe79a9a, 0xe2ad}, /* U+769A */ + {0xe79a9b, 0xf8e1}, /* U+769B [2000] */ + {0xe79a9c, 0x8ff1ef}, /* U+769C [2000] */ + {0xe79a9d, 0xf8e2}, /* U+769D [2000] */ + {0xe79a9e, 0xf8e3}, /* U+769E [2000] */ + {0xe79aa0, 0x8ff1f1}, /* U+76A0 [2000] */ + {0xe79aa1, 0x8ff1f0}, /* U+76A1 [2000] */ + {0xe79aa6, 0xf8e4}, /* U+76A6 [2000] */ + {0xe79aa7, 0x8ff1f2}, /* U+76A7 [2000] */ + {0xe79aa8, 0x8ff1f3}, /* U+76A8 [2000] */ + {0xe79aaa, 0xf8e5}, /* U+76AA [2000] */ + {0xe79aae, 0xc8e9}, /* U+76AE */ + {0xe79aaf, 0x8ff1f4}, /* U+76AF [2000] */ + {0xe79ab0, 0xe2ae}, /* U+76B0 */ + {0xe79ab4, 0xe2af}, /* U+76B4 */ + {0xe79ab6, 0xf8e6}, /* U+76B6 [2000] */ + {0xe79ab7, 0xf3e9}, /* U+76B7 */ + {0xe79ab8, 0xe2b0}, /* U+76B8 */ + {0xe79ab9, 0xe2b1}, /* U+76B9 */ + {0xe79aba, 0xe2b2}, /* U+76BA */ + {0xe79abf, 0xbbae}, /* U+76BF */ + {0xe79b82, 0xe2b3}, /* U+76C2 */ + {0xe79b83, 0xc7d6}, /* U+76C3 */ + {0xe79b85, 0xf8e7}, /* U+76C5 [2000] */ + {0xe79b86, 0xcbdf}, /* U+76C6 */ + {0xe79b88, 0xb1ce}, /* U+76C8 */ + {0xe79b89, 0x8ff1f6}, /* U+76C9 [2000] */ + {0xe79b8a, 0xb1d7}, /* U+76CA */ + {0xe79b8c, 0xf8e8}, /* U+76CC [2000] */ + {0xe79b8d, 0xe2b4}, /* U+76CD */ + {0xe79b8e, 0xf8e9}, /* U+76CE [2000] */ + {0xe79b92, 0xe2b6}, /* U+76D2 */ + {0xe79b94, 0xf8ea}, /* U+76D4 [2000] */ + {0xe79b96, 0xe2b5}, /* U+76D6 */ + {0xe79b97, 0xc5f0}, /* U+76D7 */ + {0xe79b9b, 0xc0b9}, /* U+76DB */ + {0xe79b9c, 0xddb9}, /* U+76DC */ + {0xe79b9e, 0xe2b7}, /* U+76DE */ + {0xe79b9f, 0xccc1}, /* U+76DF */ + {0xe79ba1, 0xe2b8}, /* U+76E1 */ + {0xe79ba3, 0xb4c6}, /* U+76E3 */ + {0xe79ba4, 0xc8d7}, /* U+76E4 */ + {0xe79ba5, 0xe2b9}, /* U+76E5 */ + {0xe79ba6, 0xf8eb}, /* U+76E6 [2000] */ + {0xe79ba7, 0xe2ba}, /* U+76E7 */ + {0xe79ba8, 0x8ff1f8}, /* U+76E8 [2000] */ + {0xe79baa, 0xe2bb}, /* U+76EA */ + {0xe79bac, 0x8ff1f9}, /* U+76EC [2000] */ + {0xe79bae, 0xccdc}, /* U+76EE */ + {0xe79bb1, 0xf8ec}, /* U+76F1 [2000] */ + {0xe79bb2, 0xccd5}, /* U+76F2 */ + {0xe79bb4, 0xc4be}, /* U+76F4 */ + {0xe79bb8, 0xc1ea}, /* U+76F8 */ + {0xe79bbb, 0xe2bd}, /* U+76FB */ + {0xe79bbc, 0xf8ed}, /* U+76FC [2000] */ + {0xe79bbe, 0xbde2}, /* U+76FE */ + {0xe79c81, 0xbeca}, /* U+7701 */ + {0xe79c84, 0xe2c0}, /* U+7704 */ + {0xe79c87, 0xe2bf}, /* U+7707 */ + {0xe79c88, 0xe2be}, /* U+7708 */ + {0xe79c89, 0xc8fd}, /* U+7709 */ + {0xe79c8a, 0xf8ee}, /* U+770A [2000] */ + {0xe79c8b, 0xb4c7}, /* U+770B */ + {0xe79c8c, 0xb8a9}, /* U+770C */ + {0xe79c97, 0x8ff1fb}, /* U+7717 [2000] */ + {0xe79c99, 0xf8ef}, /* U+7719 [2000] */ + {0xe79c9a, 0x8ff1fc}, /* U+771A [2000] */ + {0xe79c9b, 0xe2c6}, /* U+771B */ + {0xe79c9e, 0xe2c3}, /* U+771E */ + {0xe79c9f, 0xbfbf}, /* U+771F */ + {0xe79ca0, 0xccb2}, /* U+7720 */ + {0xe79ca4, 0xe2c2}, /* U+7724 */ + {0xe79ca5, 0xe2c4}, /* U+7725 */ + {0xe79ca6, 0xe2c5}, /* U+7726 */ + {0xe79ca9, 0xe2c1}, /* U+7729 */ + {0xe79cad, 0x8ff1fd}, /* U+772D [2000] */ + {0xe79cb4, 0xf8f0}, /* U+7734 [2000] */ + {0xe79cb5, 0x8ff1fe}, /* U+7735 [2000] */ + {0xe79cb6, 0xf8f1}, /* U+7736 [2000] */ + {0xe79cb7, 0xe2c7}, /* U+7737 */ + {0xe79cb8, 0xe2c8}, /* U+7738 */ + {0xe79cba, 0xc4af}, /* U+773A */ + {0xe79cbc, 0xb4e3}, /* U+773C */ + {0xe79d80, 0xc3e5}, /* U+7740 */ + {0xe79d86, 0xf8f2}, /* U+7746 [2000] */ + {0xe79d87, 0xe2c9}, /* U+7747 */ + {0xe79d8d, 0xf8f3}, /* U+774D [2000] */ + {0xe79d8e, 0xf8f4}, /* U+774E [2000] */ + {0xe79d98, 0x8ff2a5}, /* U+7758 [2000] */ + {0xe79d9a, 0xe2ca}, /* U+775A */ + {0xe79d9b, 0xe2cd}, /* U+775B */ + {0xe79d9c, 0xf8f5}, /* U+775C [2000] */ + {0xe79d9f, 0xf8f6}, /* U+775F [2000] */ + {0xe79da0, 0x8ff2a6}, /* U+7760 [2000] */ + {0xe79da1, 0xbfe7}, /* U+7761 */ + {0xe79da2, 0xf8f7}, /* U+7762 [2000] */ + {0xe79da3, 0xc6c4}, /* U+7763 */ + {0xe79da5, 0xe2ce}, /* U+7765 */ + {0xe79da6, 0xcbd3}, /* U+7766 */ + {0xe79da8, 0xe2cb}, /* U+7768 */ + {0xe79daa, 0x8ff2a7}, /* U+776A [2000] */ + {0xe79dab, 0xe2cc}, /* U+776B */ + {0xe79db2, 0x8ff2a9}, /* U+7772 [2000] */ + {0xe79db9, 0xe2d1}, /* U+7779 */ + {0xe79dba, 0xf8f8}, /* U+777A [2000] */ + {0xe79dbc, 0x8ff2aa}, /* U+777C [2000] */ + {0xe79dbd, 0x8ff2ab}, /* U+777D [2000] */ + {0xe79dbe, 0xe2d0}, /* U+777E */ + {0xe79dbf, 0xe2cf}, /* U+777F */ + {0xe79e80, 0xf8f9}, /* U+7780 [2000] */ + {0xe79e8b, 0xe2d3}, /* U+778B */ + {0xe79e8e, 0xe2d2}, /* U+778E */ + {0xe79e91, 0xe2d4}, /* U+7791 */ + {0xe79e94, 0xf8fa}, /* U+7794 [2000] */ + {0xe79e9a, 0x8ff2ae}, /* U+779A [2000] */ + {0xe79e9e, 0xe2d6}, /* U+779E */ + {0xe79e9f, 0x8ff2af}, /* U+779F [2000] */ + {0xe79ea0, 0xe2d5}, /* U+77A0 */ + {0xe79ea2, 0x8ff2b0}, /* U+77A2 [2000] */ + {0xe79ea4, 0x8ff2b1}, /* U+77A4 [2000] */ + {0xe79ea5, 0xcacd}, /* U+77A5 */ + {0xe79ea9, 0x8ff2b2}, /* U+77A9 [2000] */ + {0xe79eaa, 0xf8fb}, /* U+77AA [2000] */ + {0xe79eac, 0xbdd6}, /* U+77AC */ + {0xe79ead, 0xcec6}, /* U+77AD */ + {0xe79eb0, 0xe2d7}, /* U+77B0 */ + {0xe79eb3, 0xc6b7}, /* U+77B3 */ + {0xe79eb6, 0xe2d8}, /* U+77B6 */ + {0xe79eb9, 0xe2d9}, /* U+77B9 */ + {0xe79ebb, 0xe2dd}, /* U+77BB */ + {0xe79ebc, 0xe2db}, /* U+77BC */ + {0xe79ebd, 0xe2dc}, /* U+77BD */ + {0xe79ebf, 0xe2da}, /* U+77BF */ + {0xe79f87, 0xe2de}, /* U+77C7 */ + {0xe79f8d, 0xe2df}, /* U+77CD */ + {0xe79f97, 0xe2e0}, /* U+77D7 */ + {0xe79f9a, 0xe2e1}, /* U+77DA */ + {0xe79f9b, 0xccb7}, /* U+77DB */ + {0xe79f9c, 0xe2e2}, /* U+77DC */ + {0xe79f9e, 0x8ff2b3}, /* U+77DE [2000] */ + {0xe79f9f, 0x8ff2b4}, /* U+77DF [2000] */ + {0xe79fa0, 0xf8fc}, /* U+77E0 [2000] */ + {0xe79fa2, 0xccf0}, /* U+77E2 */ + {0xe79fa3, 0xe2e3}, /* U+77E3 */ + {0xe79fa4, 0x8ff2b5}, /* U+77E4 [2000] */ + {0xe79fa5, 0xc3ce}, /* U+77E5 */ + {0xe79fa6, 0x8ff2b6}, /* U+77E6 [2000] */ + {0xe79fa7, 0xc7ea}, /* U+77E7 */ + {0xe79fa9, 0xb6eb}, /* U+77E9 */ + {0xe79faa, 0x8ff2b7}, /* U+77EA [2000] */ + {0xe79fac, 0x8ff2b8}, /* U+77EC [2000] */ + {0xe79fad, 0xc3bb}, /* U+77ED */ + {0xe79fae, 0xe2e4}, /* U+77EE */ + {0xe79faf, 0xb6ba}, /* U+77EF */ + {0xe79fb0, 0x8ff2ba}, /* U+77F0 [2000] */ + {0xe79fb3, 0xc0d0}, /* U+77F3 */ + {0xe79fb4, 0x8ff2bb}, /* U+77F4 [2000] */ + {0xe79fbb, 0x8ff2bc}, /* U+77FB [2000] */ + {0xe79fbc, 0xe2e5}, /* U+77FC */ + {0xe7a082, 0xbabd}, /* U+7802 */ + {0xe7a085, 0x8ff2be}, /* U+7805 [2000] */ + {0xe7a086, 0x8ff2bf}, /* U+7806 [2000] */ + {0xe7a089, 0x8ff2c0}, /* U+7809 [2000] */ + {0xe7a08c, 0xe2e6}, /* U+780C */ + {0xe7a08d, 0x8ff2c1}, /* U+780D [2000] */ + {0xe7a092, 0xe2e7}, /* U+7812 */ + {0xe7a094, 0xb8a6}, /* U+7814 */ + {0xe7a095, 0xbad5}, /* U+7815 */ + {0xe7a099, 0x8ff2c2}, /* U+7819 [2000] */ + {0xe7a0a0, 0xe2e9}, /* U+7820 */ + {0xe7a0a1, 0x8ff2c3}, /* U+7821 [2000] */ + {0xe7a0a5, 0xc5d6}, /* U+7825 */ + {0xe7a0a6, 0xbad6}, /* U+7826 */ + {0xe7a0a7, 0xb5ce}, /* U+7827 */ + {0xe7a0ac, 0x8ff2c4}, /* U+782C [2000] */ + {0xe7a0ad, 0xf8fd}, /* U+782D [2000] */ + {0xe7a0b2, 0xcba4}, /* U+7832 */ + {0xe7a0b4, 0xc7cb}, /* U+7834 */ + {0xe7a0ba, 0xc5d7}, /* U+783A */ + {0xe7a0bf, 0xb9dc}, /* U+783F */ + {0xe7a183, 0xf9a1}, /* U+7843 [2000] */ + {0xe7a185, 0xe2eb}, /* U+7845 */ + {0xe7a187, 0x8ff2c5}, /* U+7847 [2000] */ + {0xe7a18e, 0xf9a2}, /* U+784E [2000] */ + {0xe7a18f, 0xf9a3}, /* U+784F [2000] */ + {0xe7a191, 0xf9a4}, /* U+7851 [2000] */ + {0xe7a19d, 0xbecb}, /* U+785D */ + {0xe7a1a4, 0x8ff2c6}, /* U+7864 [2000] */ + {0xe7a1a8, 0xf9a5}, /* U+7868 [2000] */ + {0xe7a1aa, 0x8ff2c7}, /* U+786A [2000] */ + {0xe7a1ab, 0xceb2}, /* U+786B */ + {0xe7a1ac, 0xb9c5}, /* U+786C */ + {0xe7a1ae, 0xf9a6}, /* U+786E [2000] */ + {0xe7a1af, 0xb8a7}, /* U+786F */ + {0xe7a1b2, 0xc8a3}, /* U+7872 */ + {0xe7a1b4, 0xe2ed}, /* U+7874 */ + {0xe7a1bc, 0xe2ef}, /* U+787C */ + {0xe7a281, 0xb8eb}, /* U+7881 */ + {0xe7a286, 0xe2ee}, /* U+7886 */ + {0xe7a287, 0xc4f6}, /* U+7887 */ + {0xe7a28a, 0x8ff2c9}, /* U+788A [2000] */ + {0xe7a28c, 0xe2f1}, /* U+788C */ + {0xe7a28d, 0xb3b7}, /* U+788D */ + {0xe7a28e, 0xe2ec}, /* U+788E */ + {0xe7a291, 0xc8ea}, /* U+7891 */ + {0xe7a293, 0xb1b0}, /* U+7893 */ + {0xe7a294, 0x8ff2ca}, /* U+7894 [2000] */ + {0xe7a295, 0xbaec}, /* U+7895 */ + {0xe7a297, 0xcfd2}, /* U+7897 */ + {0xe7a29a, 0xe2f0}, /* U+789A */ + {0xe7a29d, 0x8ff2cc}, /* U+789D [2000] */ + {0xe7a29e, 0x8ff2cd}, /* U+789E [2000] */ + {0xe7a29f, 0x8ff2ce}, /* U+789F [2000] */ + {0xe7a2a3, 0xe2f2}, /* U+78A3 */ + {0xe7a2a4, 0x8ff2cb}, /* U+78A4 [2000] */ + {0xe7a2a7, 0xcacb}, /* U+78A7 */ + {0xe7a2a9, 0xc0d9}, /* U+78A9 */ + {0xe7a2aa, 0xe2f4}, /* U+78AA */ + {0xe7a2ad, 0xf9aa}, /* U+78AD [2000] */ + {0xe7a2af, 0xe2f5}, /* U+78AF */ + {0xe7a2b0, 0xf9a8}, /* U+78B0 [2000] */ + {0xe7a2b5, 0xe2f3}, /* U+78B5 */ + {0xe7a2ba, 0xb3ce}, /* U+78BA */ + {0xe7a2bb, 0x8ff2cf}, /* U+78BB [2000] */ + {0xe7a2bc, 0xe2fb}, /* U+78BC */ + {0xe7a2be, 0xe2fa}, /* U+78BE */ + {0xe7a381, 0xbca7}, /* U+78C1 */ + {0xe7a385, 0xe2fc}, /* U+78C5 */ + {0xe7a386, 0xe2f7}, /* U+78C6 */ + {0xe7a388, 0x8ff2d0}, /* U+78C8 [2000] */ + {0xe7a38a, 0xe2fd}, /* U+78CA */ + {0xe7a38b, 0xe2f8}, /* U+78CB */ + {0xe7a38c, 0x8ff2d1}, /* U+78CC [2000] */ + {0xe7a38e, 0x8ff2d2}, /* U+78CE [2000] */ + {0xe7a390, 0xc8d8}, /* U+78D0 */ + {0xe7a391, 0xe2f6}, /* U+78D1 */ + {0xe7a394, 0xe2f9}, /* U+78D4 */ + {0xe7a395, 0x8ff2d3}, /* U+78D5 [2000] */ + {0xe7a39a, 0xe3a2}, /* U+78DA */ + {0xe7a3a0, 0x8ff2d4}, /* U+78E0 [2000] */ + {0xe7a3a1, 0x8ff2d5}, /* U+78E1 [2000] */ + {0xe7a3a4, 0xf9ab}, /* U+78E4 [2000] */ + {0xe7a3a6, 0x8ff2d6}, /* U+78E6 [2000] */ + {0xe7a3a7, 0xe3a1}, /* U+78E7 */ + {0xe7a3a8, 0xcbe1}, /* U+78E8 */ + {0xe7a3ac, 0xe2fe}, /* U+78EC */ + {0xe7a3af, 0xb0eb}, /* U+78EF */ + {0xe7a3b2, 0xf9ac}, /* U+78F2 [2000] */ + {0xe7a3b4, 0xe3a4}, /* U+78F4 */ + {0xe7a3b7, 0xf9ae}, /* U+78F7 [2000] */ + {0xe7a3b9, 0x8ff2d7}, /* U+78F9 [2000] */ + {0xe7a3ba, 0x8ff2d8}, /* U+78FA [2000] */ + {0xe7a3bb, 0x8ff2d9}, /* U+78FB [2000] */ + {0xe7a3bd, 0xe3a3}, /* U+78FD */ + {0xe7a3be, 0x8ff2da}, /* U+78FE [2000] */ + {0xe7a480, 0xf9ad}, /* U+7900 [2000] */ + {0xe7a481, 0xbecc}, /* U+7901 */ + {0xe7a487, 0xe3a5}, /* U+7907 */ + {0xe7a48e, 0xc1c3}, /* U+790E */ + {0xe7a490, 0x8ff2dc}, /* U+7910 [2000] */ + {0xe7a491, 0xe3a7}, /* U+7911 */ + {0xe7a492, 0xe3a6}, /* U+7912 */ + {0xe7a499, 0xe3a8}, /* U+7919 */ + {0xe7a49b, 0x8ff2dd}, /* U+791B [2000] */ + {0xe7a49c, 0xf9af}, /* U+791C [2000] */ + {0xe7a4a5, 0x8ff2df}, /* U+7925 [2000] */ + {0xe7a4a6, 0xe2e8}, /* U+7926 */ + {0xe7a4aa, 0xe2ea}, /* U+792A */ + {0xe7a4ab, 0xe3aa}, /* U+792B */ + {0xe7a4ac, 0xe3a9}, /* U+792C */ + {0xe7a4ae, 0xf9b0}, /* U+792E [2000] */ + {0xe7a4b0, 0x8ff2de}, /* U+7930 [2000] */ + {0xe7a4b1, 0xf9b1}, /* U+7931 [2000] */ + {0xe7a4b4, 0xf9b2}, /* U+7934 [2000] */ + {0xe7a4ba, 0xbca8}, /* U+793A */ + {0xe7a4bb, 0x8ff2e0}, /* U+793B [2000] */ + {0xe7a4bc, 0xcee9}, /* U+793C */ + {0xe7a4be, 0xbcd2}, /* U+793E */ + {0xe7a580, 0xe3ab}, /* U+7940 */ + {0xe7a581, 0xb7b7}, /* U+7941 */ + {0xe7a585, 0xf9b5}, /* U+7945 [2000] */ + {0xe7a586, 0xf9b6}, /* U+7946 [2000] */ + {0xe7a587, 0xb5c0}, /* U+7947 */ + {0xe7a588, 0xb5a7}, /* U+7948 */ + {0xe7a589, 0xbbe3}, /* U+7949 */ + {0xe7a58a, 0x8ff2e1}, /* U+794A [2000] */ + {0xe7a590, 0xcdb4}, /* U+7950 */ + {0xe7a593, 0xe3b1}, /* U+7953 */ + {0xe7a595, 0xe3b0}, /* U+7955 */ + {0xe7a596, 0xc1c4}, /* U+7956 */ + {0xe7a597, 0xe3ad}, /* U+7957 */ + {0xe7a598, 0x8ff2e2}, /* U+7958 [2000] */ + {0xe7a59a, 0xe3af}, /* U+795A */ + {0xe7a59b, 0x8ff2e3}, /* U+795B [2000] */ + {0xe7a59c, 0xf9ba}, /* U+795C [2000] */ + {0xe7a59d, 0xbdcb}, /* U+795D */ + {0xe7a59e, 0xbfc0}, /* U+795E */ + {0xe7a59f, 0xe3ae}, /* U+795F */ + {0xe7a5a0, 0xe3ac}, /* U+7960 */ + {0xe7a5a2, 0xc7aa}, /* U+7962 */ + {0xe7a5a5, 0xbecd}, /* U+7965 */ + {0xe7a5a7, 0x8ff2e5}, /* U+7967 [2000] */ + {0xe7a5a8, 0xc9bc}, /* U+7968 */ + {0xe7a5ad, 0xbad7}, /* U+796D */ + {0xe7a5b2, 0x8ff2e6}, /* U+7972 [2000] */ + {0xe7a5b7, 0xc5f8}, /* U+7977 */ + {0xe7a5b9, 0xf9be}, /* U+7979 [2000] */ + {0xe7a5ba, 0xe3b2}, /* U+797A */ + {0xe7a5bf, 0xe3b3}, /* U+797F */ + {0xe7a680, 0xe3c9}, /* U+7980 */ + {0xe7a681, 0xb6d8}, /* U+7981 */ + {0xe7a684, 0xcfbd}, /* U+7984 */ + {0xe7a685, 0xc1b5}, /* U+7985 */ + {0xe7a68a, 0xe3b4}, /* U+798A */ + {0xe7a68d, 0xb2d2}, /* U+798D */ + {0xe7a68e, 0xc4f7}, /* U+798E */ + {0xe7a68f, 0xcaa1}, /* U+798F */ + {0xe7a694, 0x8ff2e7}, /* U+7994 [2000] */ + {0xe7a695, 0x8ff2e8}, /* U+7995 [2000] */ + {0xe7a696, 0x8ff2e9}, /* U+7996 [2000] */ + {0xe7a698, 0xf9c2}, /* U+7998 [2000] */ + {0xe7a69b, 0x8ff2ea}, /* U+799B [2000] */ + {0xe7a69d, 0xe3b5}, /* U+799D */ + {0xe7a6a1, 0x8ff2eb}, /* U+79A1 [2000] */ + {0xe7a6a6, 0xb5fa}, /* U+79A6 */ + {0xe7a6a7, 0xe3b6}, /* U+79A7 */ + {0xe7a6a9, 0x8ff2ec}, /* U+79A9 [2000] */ + {0xe7a6aa, 0xe3b8}, /* U+79AA */ + {0xe7a6ae, 0xe3b9}, /* U+79AE */ + {0xe7a6b0, 0xc7a9}, /* U+79B0 */ + {0xe7a6b1, 0xf9c3}, /* U+79B1 [2000] */ + {0xe7a6b3, 0xe3ba}, /* U+79B3 */ + {0xe7a6b4, 0x8ff2ed}, /* U+79B4 [2000] */ + {0xe7a6b8, 0xf9c4}, /* U+79B8 [2000] */ + {0xe7a6b9, 0xe3bb}, /* U+79B9 */ + {0xe7a6ba, 0xe3bc}, /* U+79BA */ + {0xe7a6bb, 0x8ff2ee}, /* U+79BB [2000] */ + {0xe7a6bd, 0xb6d9}, /* U+79BD */ + {0xe7a6be, 0xb2d3}, /* U+79BE */ + {0xe7a6bf, 0xc6c5}, /* U+79BF */ + {0xe7a780, 0xbda8}, /* U+79C0 */ + {0xe7a781, 0xbbe4}, /* U+79C1 */ + {0xe7a782, 0x8ff2ef}, /* U+79C2 [2000] */ + {0xe7a787, 0x8ff2f0}, /* U+79C7 [2000] */ + {0xe7a788, 0xf9c5}, /* U+79C8 [2000] */ + {0xe7a789, 0xe3bd}, /* U+79C9 */ + {0xe7a78a, 0xf9c6}, /* U+79CA [2000] */ + {0xe7a78b, 0xbda9}, /* U+79CB */ + {0xe7a78c, 0x8ff2f1}, /* U+79CC [2000] */ + {0xe7a78d, 0x8ff2f2}, /* U+79CD [2000] */ + {0xe7a791, 0xb2ca}, /* U+79D1 */ + {0xe7a792, 0xc9c3}, /* U+79D2 */ + {0xe7a794, 0xf9c8}, /* U+79D4 [2000] */ + {0xe7a795, 0xe3be}, /* U+79D5 */ + {0xe7a796, 0x8ff2f3}, /* U+79D6 [2000] */ + {0xe7a798, 0xc8eb}, /* U+79D8 */ + {0xe7a79e, 0xf9c9}, /* U+79DE [2000] */ + {0xe7a79f, 0xc1c5}, /* U+79DF */ + {0xe7a7a1, 0xe3c1}, /* U+79E1 */ + {0xe7a7a3, 0xe3c2}, /* U+79E3 */ + {0xe7a7a4, 0xc7e9}, /* U+79E4 */ + {0xe7a7a6, 0xbfc1}, /* U+79E6 */ + {0xe7a7a7, 0xe3bf}, /* U+79E7 */ + {0xe7a7a9, 0xc3e1}, /* U+79E9 */ + {0xe7a7ab, 0xf9ca}, /* U+79EB [2000] */ + {0xe7a7ac, 0xe3c0}, /* U+79EC */ + {0xe7a7ad, 0xf9cb}, /* U+79ED [2000] */ + {0xe7a7b0, 0xbece}, /* U+79F0 */ + {0xe7a7bb, 0xb0dc}, /* U+79FB */ + {0xe7a880, 0xb5a9}, /* U+7A00 */ + {0xe7a883, 0xf9cc}, /* U+7A03 [2000] */ + {0xe7a888, 0xe3c3}, /* U+7A08 */ + {0xe7a88a, 0x8ff2f8}, /* U+7A0A [2000] */ + {0xe7a88b, 0xc4f8}, /* U+7A0B */ + {0xe7a88d, 0xe3c4}, /* U+7A0D */ + {0xe7a88e, 0xc0c7}, /* U+7A0E */ + {0xe7a891, 0x8ff2f9}, /* U+7A11 [2000] */ + {0xe7a894, 0xccad}, /* U+7A14 */ + {0xe7a895, 0x8ff2fa}, /* U+7A15 [2000] */ + {0xe7a897, 0xc9a3}, /* U+7A17 */ + {0xe7a898, 0xe3c5}, /* U+7A18 */ + {0xe7a899, 0xe3c6}, /* U+7A19 */ + {0xe7a89a, 0xc3d5}, /* U+7A1A */ + {0xe7a89b, 0x8ff2fb}, /* U+7A1B [2000] */ + {0xe7a89c, 0xcec7}, /* U+7A1C */ + {0xe7a89e, 0x8ff2fc}, /* U+7A1E [2000] */ + {0xe7a89f, 0xe3c8}, /* U+7A1F */ + {0xe7a8a0, 0xe3c7}, /* U+7A20 */ + {0xe7a8ad, 0x8ff2fe}, /* U+7A2D [2000] */ + {0xe7a8ae, 0xbcef}, /* U+7A2E */ + {0xe7a8b1, 0xe3ca}, /* U+7A31 */ + {0xe7a8b2, 0xb0f0}, /* U+7A32 */ + {0xe7a8b7, 0xe3cd}, /* U+7A37 */ + {0xe7a8b8, 0x8ff3a1}, /* U+7A38 [2000] */ + {0xe7a8b9, 0xf9ce}, /* U+7A39 [2000] */ + {0xe7a8bb, 0xe3cb}, /* U+7A3B */ + {0xe7a8bc, 0xb2d4}, /* U+7A3C */ + {0xe7a8bd, 0xb7ce}, /* U+7A3D */ + {0xe7a8be, 0xe3cc}, /* U+7A3E */ + {0xe7a8bf, 0xb9c6}, /* U+7A3F */ + {0xe7a980, 0xb9f2}, /* U+7A40 */ + {0xe7a982, 0xcae6}, /* U+7A42 */ + {0xe7a983, 0xe3ce}, /* U+7A43 */ + {0xe7a986, 0xcbd4}, /* U+7A46 */ + {0xe7a987, 0x8ff3a2}, /* U+7A47 [2000] */ + {0xe7a989, 0xe3d0}, /* U+7A49 */ + {0xe7a98c, 0x8ff3a3}, /* U+7A4C [2000] */ + {0xe7a98d, 0xc0d1}, /* U+7A4D */ + {0xe7a98e, 0xb1cf}, /* U+7A4E */ + {0xe7a98f, 0xb2ba}, /* U+7A4F */ + {0xe7a990, 0xb0ac}, /* U+7A50 */ + {0xe7a996, 0x8ff3a4}, /* U+7A56 [2000] */ + {0xe7a997, 0xe3cf}, /* U+7A57 */ + {0xe7a999, 0x8ff3a5}, /* U+7A59 [2000] */ + {0xe7a99c, 0x8ff3a6}, /* U+7A5C [2000] */ + {0xe7a99d, 0xf9cf}, /* U+7A5D [2000] */ + {0xe7a99f, 0x8ff3a7}, /* U+7A5F [2000] */ + {0xe7a9a0, 0x8ff3a8}, /* U+7A60 [2000] */ + {0xe7a9a1, 0xe3d1}, /* U+7A61 */ + {0xe7a9a2, 0xe3d2}, /* U+7A62 */ + {0xe7a9a3, 0xbef7}, /* U+7A63 */ + {0xe7a9a7, 0x8ff3a9}, /* U+7A67 [2000] */ + {0xe7a9a9, 0xe3d3}, /* U+7A69 */ + {0xe7a9aa, 0x8ff3aa}, /* U+7A6A [2000] */ + {0xe7a9ab, 0xb3cf}, /* U+7A6B */ + {0xe7a9ad, 0xf9d0}, /* U+7A6D [2000] */ + {0xe7a9b0, 0xe3d5}, /* U+7A70 */ + {0xe7a9b4, 0xb7ea}, /* U+7A74 */ + {0xe7a9b5, 0x8ff3ab}, /* U+7A75 [2000] */ + {0xe7a9b6, 0xb5e6}, /* U+7A76 */ + {0xe7a9b8, 0x8ff3ac}, /* U+7A78 [2000] */ + {0xe7a9b9, 0xe3d6}, /* U+7A79 */ + {0xe7a9ba, 0xb6f5}, /* U+7A7A */ + {0xe7a9bd, 0xe3d7}, /* U+7A7D */ + {0xe7a9bf, 0xc0fc}, /* U+7A7F */ + {0xe7aa81, 0xc6cd}, /* U+7A81 */ + {0xe7aa82, 0x8ff3ad}, /* U+7A82 [2000] */ + {0xe7aa83, 0xc0e0}, /* U+7A83 */ + {0xe7aa84, 0xbaf5}, /* U+7A84 */ + {0xe7aa85, 0xf9d2}, /* U+7A85 [2000] */ + {0xe7aa88, 0xe3d8}, /* U+7A88 */ + {0xe7aa8a, 0x8ff3ae}, /* U+7A8A [2000] */ + {0xe7aa90, 0x8ff3af}, /* U+7A90 [2000] */ + {0xe7aa92, 0xc3e2}, /* U+7A92 */ + {0xe7aa93, 0xc1eb}, /* U+7A93 */ + {0xe7aa95, 0xe3da}, /* U+7A95 */ + {0xe7aa96, 0xe3dc}, /* U+7A96 */ + {0xe7aa97, 0xe3d9}, /* U+7A97 */ + {0xe7aa98, 0xe3db}, /* U+7A98 */ + {0xe7aa9f, 0xb7a2}, /* U+7A9F */ + {0xe7aaa0, 0xf9d3}, /* U+7AA0 [2000] */ + {0xe7aaa3, 0x8ff3b0}, /* U+7AA3 [2000] */ + {0xe7aaa9, 0xe3dd}, /* U+7AA9 */ + {0xe7aaaa, 0xb7a6}, /* U+7AAA */ + {0xe7aaac, 0x8ff3b1}, /* U+7AAC [2000] */ + {0xe7aaae, 0xb5e7}, /* U+7AAE */ + {0xe7aaaf, 0xcdd2}, /* U+7AAF */ + {0xe7aab0, 0xe3df}, /* U+7AB0 */ + {0xe7aab3, 0xf9d5}, /* U+7AB3 [2000] */ + {0xe7aab6, 0xe3e0}, /* U+7AB6 */ + {0xe7aab9, 0x8ff3b4}, /* U+7AB9 [2000] */ + {0xe7aaba, 0xb1ae}, /* U+7ABA */ + {0xe7aabb, 0xf9d6}, /* U+7ABB [2000] */ + {0xe7aabc, 0x8ff3b5}, /* U+7ABC [2000] */ + {0xe7aabe, 0x8ff3b6}, /* U+7ABE [2000] */ + {0xe7aabf, 0xe3e3}, /* U+7ABF */ + {0xe7ab83, 0xb3f6}, /* U+7AC3 */ + {0xe7ab84, 0xe3e2}, /* U+7AC4 */ + {0xe7ab85, 0xe3e1}, /* U+7AC5 */ + {0xe7ab87, 0xe3e5}, /* U+7AC7 */ + {0xe7ab88, 0xe3de}, /* U+7AC8 */ + {0xe7ab8a, 0xe3e6}, /* U+7ACA */ + {0xe7ab8b, 0xcea9}, /* U+7ACB */ + {0xe7ab8c, 0x8ff3b8}, /* U+7ACC [2000] */ + {0xe7ab8d, 0xe3e7}, /* U+7ACD */ + {0xe7ab8e, 0xf9d7}, /* U+7ACE [2000] */ + {0xe7ab8f, 0xe3e8}, /* U+7ACF */ + {0xe7ab91, 0x8ff3b9}, /* U+7AD1 [2000] */ + {0xe7ab92, 0xd4f4}, /* U+7AD2 */ + {0xe7ab93, 0xe3ea}, /* U+7AD3 */ + {0xe7ab95, 0xe3e9}, /* U+7AD5 */ + {0xe7ab99, 0xe3eb}, /* U+7AD9 */ + {0xe7ab9a, 0xe3ec}, /* U+7ADA */ + {0xe7ab9c, 0xceb5}, /* U+7ADC */ + {0xe7ab9d, 0xe3ed}, /* U+7ADD */ + {0xe7ab9f, 0xf0ef}, /* U+7ADF */ + {0xe7aba0, 0xbecf}, /* U+7AE0 */ + {0xe7aba1, 0xe3ee}, /* U+7AE1 */ + {0xe7aba2, 0xe3ef}, /* U+7AE2 */ + {0xe7aba3, 0xbdd7}, /* U+7AE3 */ + {0xe7aba5, 0xc6b8}, /* U+7AE5 */ + {0xe7aba6, 0xe3f0}, /* U+7AE6 */ + {0xe7aba7, 0x8ff3ba}, /* U+7AE7 [2000] */ + {0xe7aba8, 0x8ff3bb}, /* U+7AE8 [2000] */ + {0xe7abaa, 0xc3a8}, /* U+7AEA */ + {0xe7abab, 0xf9d8}, /* U+7AEB [2000] */ + {0xe7abad, 0xe3f1}, /* U+7AED */ + {0xe7abaf, 0xc3bc}, /* U+7AEF */ + {0xe7abb0, 0xe3f2}, /* U+7AF0 */ + {0xe7abb4, 0x8ff3bc}, /* U+7AF4 [2000] */ + {0xe7abb6, 0xb6a5}, /* U+7AF6 */ + {0xe7abb8, 0xd1bf}, /* U+7AF8 */ + {0xe7abb9, 0xc3dd}, /* U+7AF9 */ + {0xe7abba, 0xbcb3}, /* U+7AFA */ + {0xe7abbd, 0xf9d9}, /* U+7AFD [2000] */ + {0xe7abbf, 0xb4c8}, /* U+7AFF */ + {0xe7ac82, 0xe3f3}, /* U+7B02 */ + {0xe7ac84, 0xe4a2}, /* U+7B04 */ + {0xe7ac86, 0xe3f6}, /* U+7B06 */ + {0xe7ac87, 0x8ff3bf}, /* U+7B07 [2000] */ + {0xe7ac88, 0xb5e8}, /* U+7B08 */ + {0xe7ac8a, 0xe3f5}, /* U+7B0A */ + {0xe7ac8b, 0xe4a4}, /* U+7B0B */ + {0xe7ac8f, 0xe3f4}, /* U+7B0F */ + {0xe7ac91, 0xbed0}, /* U+7B11 */ + {0xe7ac92, 0xf9da}, /* U+7B12 [2000] */ + {0xe7ac98, 0xe3f8}, /* U+7B18 */ + {0xe7ac99, 0xe3f9}, /* U+7B19 */ + {0xe7ac9b, 0xc5ab}, /* U+7B1B */ + {0xe7ac9e, 0xe3fa}, /* U+7B1E */ + {0xe7aca0, 0xb3de}, /* U+7B20 */ + {0xe7aca5, 0xbfda}, /* U+7B25 */ + {0xe7aca6, 0xc9e4}, /* U+7B26 */ + {0xe7aca7, 0x8ff3c2}, /* U+7B27 [2000] */ + {0xe7aca8, 0xe3fc}, /* U+7B28 */ + {0xe7acaa, 0x8ff3c3}, /* U+7B2A [2000] */ + {0xe7acac, 0xc2e8}, /* U+7B2C */ + {0xe7acad, 0xf9db}, /* U+7B2D [2000] */ + {0xe7acae, 0x8ff3c4}, /* U+7B2E [2000] */ + {0xe7acaf, 0x8ff3c5}, /* U+7B2F [2000] */ + {0xe7acb1, 0x8ff3c6}, /* U+7B31 [2000] */ + {0xe7acb3, 0xe3f7}, /* U+7B33 */ + {0xe7acb5, 0xe3fb}, /* U+7B35 */ + {0xe7acb6, 0xe3fd}, /* U+7B36 */ + {0xe7acb9, 0xbafb}, /* U+7B39 */ + {0xe7acbb, 0xf9dc}, /* U+7B3B [2000] */ + {0xe7acbd, 0x8ff3c1}, /* U+7B3D [2000] */ + {0xe7ad81, 0x8ff3ca}, /* U+7B41 [2000] */ + {0xe7ad85, 0xe4a6}, /* U+7B45 */ + {0xe7ad86, 0xc9ae}, /* U+7B46 */ + {0xe7ad87, 0xf9dd}, /* U+7B47 [2000] */ + {0xe7ad88, 0xc8a6}, /* U+7B48 */ + {0xe7ad89, 0xc5f9}, /* U+7B49 */ + {0xe7ad8b, 0xb6da}, /* U+7B4B */ + {0xe7ad8c, 0xe4a5}, /* U+7B4C */ + {0xe7ad8d, 0xe4a3}, /* U+7B4D */ + {0xe7ad8e, 0xf9de}, /* U+7B4E [2000] */ + {0xe7ad8f, 0xc8b5}, /* U+7B4F */ + {0xe7ad90, 0xe3fe}, /* U+7B50 */ + {0xe7ad91, 0xc3de}, /* U+7B51 */ + {0xe7ad92, 0xc5fb}, /* U+7B52 */ + {0xe7ad94, 0xc5fa}, /* U+7B54 */ + {0xe7ad95, 0x8ff3cc}, /* U+7B55 [2000] */ + {0xe7ad96, 0xbaf6}, /* U+7B56 */ + {0xe7ad9d, 0xe4b8}, /* U+7B5D */ + {0xe7ada0, 0xf9df}, /* U+7B60 [2000] */ + {0xe7ada4, 0x8ff3ce}, /* U+7B64 [2000] */ + {0xe7ada5, 0xe4a8}, /* U+7B65 */ + {0xe7ada6, 0x8ff3cf}, /* U+7B66 [2000] */ + {0xe7ada7, 0xe4aa}, /* U+7B67 */ + {0xe7ada9, 0x8ff3d0}, /* U+7B69 [2000] */ + {0xe7adac, 0xe4ad}, /* U+7B6C */ + {0xe7adad, 0xf9e0}, /* U+7B6D [2000] */ + {0xe7adae, 0xe4ae}, /* U+7B6E */ + {0xe7adaf, 0xf9e1}, /* U+7B6F [2000] */ + {0xe7adb0, 0xe4ab}, /* U+7B70 */ + {0xe7adb1, 0xe4ac}, /* U+7B71 */ + {0xe7adb2, 0xf9e2}, /* U+7B72 [2000] */ + {0xe7adb3, 0x8ff3d1}, /* U+7B73 [2000] */ + {0xe7adb4, 0xe4a9}, /* U+7B74 */ + {0xe7adb5, 0xe4a7}, /* U+7B75 */ + {0xe7adb9, 0x8ff3cd}, /* U+7B79 [2000] */ + {0xe7adba, 0xe4a1}, /* U+7B7A */ + {0xe7adbf, 0x8ff3c9}, /* U+7B7F [2000] */ + {0xe7ae86, 0xcacf}, /* U+7B86 */ + {0xe7ae87, 0xb2d5}, /* U+7B87 */ + {0xe7ae8b, 0xe4b5}, /* U+7B8B */ + {0xe7ae8d, 0xe4b2}, /* U+7B8D */ + {0xe7ae8f, 0xe4b7}, /* U+7B8F */ + {0xe7ae90, 0x8ff3d4}, /* U+7B90 [2000] */ + {0xe7ae91, 0x8ff3d5}, /* U+7B91 [2000] */ + {0xe7ae92, 0xe4b6}, /* U+7B92 */ + {0xe7ae94, 0xc7f3}, /* U+7B94 */ + {0xe7ae95, 0xcca7}, /* U+7B95 */ + {0xe7ae97, 0xbbbb}, /* U+7B97 */ + {0xe7ae98, 0xe4b0}, /* U+7B98 */ + {0xe7ae99, 0xe4b9}, /* U+7B99 */ + {0xe7ae9a, 0xe4b4}, /* U+7B9A */ + {0xe7ae9b, 0x8ff3d6}, /* U+7B9B [2000] */ + {0xe7ae9c, 0xe4b3}, /* U+7B9C */ + {0xe7ae9d, 0xe4af}, /* U+7B9D */ + {0xe7ae9e, 0xf9e3}, /* U+7B9E [2000] */ + {0xe7ae9f, 0xe4b1}, /* U+7B9F */ + {0xe7aea1, 0xb4c9}, /* U+7BA1 */ + {0xe7aeaa, 0xc3bd}, /* U+7BAA */ + {0xe7aead, 0xc0fd}, /* U+7BAD */ + {0xe7aeaf, 0x8ff3d8}, /* U+7BAF [2000] */ + {0xe7aeb1, 0xc8a2}, /* U+7BB1 */ + {0xe7aeb4, 0xe4be}, /* U+7BB4 */ + {0xe7aeb5, 0x8ff3d9}, /* U+7BB5 [2000] */ + {0xe7aeb8, 0xc8a4}, /* U+7BB8 */ + {0xe7aebc, 0x8ff3da}, /* U+7BBC [2000] */ + {0xe7af80, 0xc0e1}, /* U+7BC0 */ + {0xe7af81, 0xe4bb}, /* U+7BC1 */ + {0xe7af84, 0xc8cf}, /* U+7BC4 */ + {0xe7af85, 0x8ff3db}, /* U+7BC5 [2000] */ + {0xe7af86, 0xe4bf}, /* U+7BC6 */ + {0xe7af87, 0xcad3}, /* U+7BC7 */ + {0xe7af89, 0xc3db}, /* U+7BC9 */ + {0xe7af8a, 0x8ff3dc}, /* U+7BCA [2000] */ + {0xe7af8b, 0xe4ba}, /* U+7BCB */ + {0xe7af8c, 0xe4bc}, /* U+7BCC */ + {0xe7af8f, 0xe4bd}, /* U+7BCF */ + {0xe7af94, 0x8ff3df}, /* U+7BD4 [2000] */ + {0xe7af96, 0x8ff3e0}, /* U+7BD6 [2000] */ + {0xe7af97, 0xf9e5}, /* U+7BD7 [2000] */ + {0xe7af99, 0xf9e6}, /* U+7BD9 [2000] */ + {0xe7af9a, 0x8ff3e1}, /* U+7BDA [2000] */ + {0xe7af9d, 0xe4c0}, /* U+7BDD */ + {0xe7afa0, 0xbcc4}, /* U+7BE0 */ + {0xe7afa4, 0xc6c6}, /* U+7BE4 */ + {0xe7afa5, 0xe4c5}, /* U+7BE5 */ + {0xe7afa6, 0xe4c4}, /* U+7BE6 */ + {0xe7afa9, 0xe4c1}, /* U+7BE9 */ + {0xe7afaa, 0x8ff3e2}, /* U+7BEA [2000] */ + {0xe7afad, 0xcfb6}, /* U+7BED */ + {0xe7afb0, 0x8ff3e3}, /* U+7BF0 [2000] */ + {0xe7afb3, 0xe4ca}, /* U+7BF3 */ + {0xe7afb6, 0xe4ce}, /* U+7BF6 */ + {0xe7afb7, 0xe4cb}, /* U+7BF7 */ + {0xe7b080, 0xe4c7}, /* U+7C00 */ + {0xe7b081, 0xf9e7}, /* U+7C01 [2000] */ + {0xe7b083, 0x8ff3e4}, /* U+7C03 [2000] */ + {0xe7b087, 0xe4c8}, /* U+7C07 */ + {0xe7b08b, 0x8ff3e5}, /* U+7C0B [2000] */ + {0xe7b08d, 0xe4cd}, /* U+7C0D */ + {0xe7b08e, 0x8ff3e6}, /* U+7C0E [2000] */ + {0xe7b08f, 0x8ff3e7}, /* U+7C0F [2000] */ + {0xe7b091, 0xe4c2}, /* U+7C11 */ + {0xe7b092, 0xd2d5}, /* U+7C12 */ + {0xe7b093, 0xe4c9}, /* U+7C13 */ + {0xe7b094, 0xe4c3}, /* U+7C14 */ + {0xe7b097, 0xe4cc}, /* U+7C17 */ + {0xe7b09e, 0xf9e9}, /* U+7C1E [2000] */ + {0xe7b09f, 0xe4d2}, /* U+7C1F */ + {0xe7b0a0, 0xf9ea}, /* U+7C20 [2000] */ + {0xe7b0a1, 0xb4ca}, /* U+7C21 */ + {0xe7b0a3, 0xe4cf}, /* U+7C23 */ + {0xe7b0a6, 0x8ff3e8}, /* U+7C26 [2000] */ + {0xe7b0a7, 0xe4d0}, /* U+7C27 */ + {0xe7b0aa, 0xe4d1}, /* U+7C2A */ + {0xe7b0ab, 0xe4d4}, /* U+7C2B */ + {0xe7b0b1, 0xf9e8}, /* U+7C31 [2000] */ + {0xe7b0b3, 0xf9eb}, /* U+7C33 [2000] */ + {0xe7b0b6, 0xf9ec}, /* U+7C36 [2000] */ + {0xe7b0b7, 0xe4d3}, /* U+7C37 */ + {0xe7b0b8, 0xc8f6}, /* U+7C38 */ + {0xe7b0bd, 0xe4d5}, /* U+7C3D */ + {0xe7b0be, 0xcefc}, /* U+7C3E */ + {0xe7b0bf, 0xcaed}, /* U+7C3F */ + {0xe7b180, 0xe4da}, /* U+7C40 */ + {0xe7b183, 0xe4d7}, /* U+7C43 */ + {0xe7b185, 0x8ff3e9}, /* U+7C45 [2000] */ + {0xe7b18a, 0x8ff3ea}, /* U+7C4A [2000] */ + {0xe7b18c, 0xe4d6}, /* U+7C4C */ + {0xe7b18d, 0xc0d2}, /* U+7C4D */ + {0xe7b18f, 0xe4d9}, /* U+7C4F */ + {0xe7b190, 0xe4db}, /* U+7C50 */ + {0xe7b191, 0x8ff3eb}, /* U+7C51 [2000] */ + {0xe7b194, 0xe4d8}, /* U+7C54 */ + {0xe7b196, 0xe4df}, /* U+7C56 */ + {0xe7b197, 0x8ff3ec}, /* U+7C57 [2000] */ + {0xe7b198, 0xe4dc}, /* U+7C58 */ + {0xe7b199, 0xf9ef}, /* U+7C59 [2000] */ + {0xe7b19e, 0x8ff3ed}, /* U+7C5E [2000] */ + {0xe7b19f, 0xe4dd}, /* U+7C5F */ + {0xe7b1a0, 0xe4c6}, /* U+7C60 */ + {0xe7b1a1, 0x8ff3ee}, /* U+7C61 [2000] */ + {0xe7b1a4, 0xe4de}, /* U+7C64 */ + {0xe7b1a5, 0xe4e0}, /* U+7C65 */ + {0xe7b1a9, 0x8ff3ef}, /* U+7C69 [2000] */ + {0xe7b1ac, 0xe4e1}, /* U+7C6C */ + {0xe7b1ad, 0xf9f0}, /* U+7C6D [2000] */ + {0xe7b1ae, 0x8ff3f0}, /* U+7C6E [2000] */ + {0xe7b1af, 0x8ff3f1}, /* U+7C6F [2000] */ + {0xe7b1b0, 0x8ff3f2}, /* U+7C70 [2000] */ + {0xe7b1b3, 0xcac6}, /* U+7C73 */ + {0xe7b1b5, 0xe4e2}, /* U+7C75 */ + {0xe7b1b9, 0xf9f1}, /* U+7C79 [2000] */ + {0xe7b1be, 0xcce2}, /* U+7C7E */ + {0xe7b281, 0xb6ce}, /* U+7C81 */ + {0xe7b282, 0xb7a9}, /* U+7C82 */ + {0xe7b283, 0xe4e3}, /* U+7C83 */ + {0xe7b289, 0xcab4}, /* U+7C89 */ + {0xe7b28b, 0xbfe8}, /* U+7C8B */ + {0xe7b28d, 0xccb0}, /* U+7C8D */ + {0xe7b28f, 0xf9f2}, /* U+7C8F [2000] */ + {0xe7b290, 0xe4e4}, /* U+7C90 */ + {0xe7b292, 0xceb3}, /* U+7C92 */ + {0xe7b294, 0xf9f3}, /* U+7C94 [2000] */ + {0xe7b295, 0xc7f4}, /* U+7C95 */ + {0xe7b297, 0xc1c6}, /* U+7C97 */ + {0xe7b298, 0xc7b4}, /* U+7C98 */ + {0xe7b29b, 0xbdcd}, /* U+7C9B */ + {0xe7b29f, 0xb0c0}, /* U+7C9F */ + {0xe7b2a0, 0xf9f4}, /* U+7CA0 [2000] */ + {0xe7b2a1, 0xe4e9}, /* U+7CA1 */ + {0xe7b2a2, 0xe4e7}, /* U+7CA2 */ + {0xe7b2a4, 0xe4e5}, /* U+7CA4 */ + {0xe7b2a5, 0xb4a1}, /* U+7CA5 */ + {0xe7b2a6, 0x8ff3f6}, /* U+7CA6 [2000] */ + {0xe7b2a7, 0xbed1}, /* U+7CA7 */ + {0xe7b2a8, 0xe4ea}, /* U+7CA8 */ + {0xe7b2ab, 0xe4e8}, /* U+7CAB */ + {0xe7b2ad, 0xe4e6}, /* U+7CAD */ + {0xe7b2ae, 0xe4ee}, /* U+7CAE */ + {0xe7b2b1, 0xe4ed}, /* U+7CB1 */ + {0xe7b2b2, 0xe4ec}, /* U+7CB2 */ + {0xe7b2b3, 0xe4eb}, /* U+7CB3 */ + {0xe7b2b6, 0x8ff3f8}, /* U+7CB6 [2000] */ + {0xe7b2b7, 0x8ff3f9}, /* U+7CB7 [2000] */ + {0xe7b2b9, 0xe4ef}, /* U+7CB9 */ + {0xe7b2bc, 0xf9f5}, /* U+7CBC [2000] */ + {0xe7b2bd, 0xe4f0}, /* U+7CBD */ + {0xe7b2be, 0xc0ba}, /* U+7CBE */ + {0xe7b2bf, 0x8ff3fa}, /* U+7CBF [2000] */ + {0xe7b380, 0xe4f1}, /* U+7CC0 */ + {0xe7b382, 0xe4f3}, /* U+7CC2 */ + {0xe7b384, 0x8ff3fc}, /* U+7CC4 [2000] */ + {0xe7b385, 0xe4f2}, /* U+7CC5 */ + {0xe7b388, 0x8ff3fe}, /* U+7CC8 [2000] */ + {0xe7b38a, 0xb8d2}, /* U+7CCA */ + {0xe7b38d, 0x8ff4a1}, /* U+7CCD [2000] */ + {0xe7b38e, 0xc1b8}, /* U+7CCE */ + {0xe7b392, 0xe4f5}, /* U+7CD2 */ + {0xe7b395, 0xf9f6}, /* U+7CD5 [2000] */ + {0xe7b396, 0xc5fc}, /* U+7CD6 */ + {0xe7b397, 0x8ff4a3}, /* U+7CD7 [2000] */ + {0xe7b398, 0xe4f4}, /* U+7CD8 */ + {0xe7b399, 0xf9f7}, /* U+7CD9 [2000] */ + {0xe7b39c, 0xe4f6}, /* U+7CDC */ + {0xe7b39d, 0xf9f8}, /* U+7CDD [2000] */ + {0xe7b39e, 0xcab5}, /* U+7CDE */ + {0xe7b39f, 0xc1ec}, /* U+7CDF */ + {0xe7b3a0, 0xb9c7}, /* U+7CE0 */ + {0xe7b3a2, 0xe4f7}, /* U+7CE2 */ + {0xe7b3a6, 0x8ff4a5}, /* U+7CE6 [2000] */ + {0xe7b3a7, 0xcec8}, /* U+7CE7 */ + {0xe7b3ab, 0x8ff4a6}, /* U+7CEB [2000] */ + {0xe7b3af, 0xe4f9}, /* U+7CEF */ + {0xe7b3b2, 0xe4fa}, /* U+7CF2 */ + {0xe7b3b4, 0xe4fb}, /* U+7CF4 */ + {0xe7b3b5, 0x8ff4a8}, /* U+7CF5 [2000] */ + {0xe7b3b6, 0xe4fc}, /* U+7CF6 */ + {0xe7b3b8, 0xbbe5}, /* U+7CF8 */ + {0xe7b3ba, 0xe4fd}, /* U+7CFA */ + {0xe7b3bb, 0xb7cf}, /* U+7CFB */ + {0xe7b3be, 0xb5ea}, /* U+7CFE */ + {0xe7b480, 0xb5aa}, /* U+7D00 */ + {0xe7b482, 0xe5a1}, /* U+7D02 */ + {0xe7b483, 0x8ff4a9}, /* U+7D03 [2000] */ + {0xe7b484, 0xccf3}, /* U+7D04 */ + {0xe7b485, 0xb9c8}, /* U+7D05 */ + {0xe7b486, 0xe4fe}, /* U+7D06 */ + {0xe7b487, 0xf9f9}, /* U+7D07 [2000] */ + {0xe7b488, 0xf9fa}, /* U+7D08 [2000] */ + {0xe7b489, 0x8ff4aa}, /* U+7D09 [2000] */ + {0xe7b48a, 0xe5a4}, /* U+7D0A */ + {0xe7b48b, 0xcce6}, /* U+7D0B */ + {0xe7b48d, 0xc7bc}, /* U+7D0D */ + {0xe7b490, 0xc9b3}, /* U+7D10 */ + {0xe7b492, 0x8ff4ac}, /* U+7D12 [2000] */ + {0xe7b493, 0xf9fb}, /* U+7D13 [2000] */ + {0xe7b494, 0xbde3}, /* U+7D14 */ + {0xe7b495, 0xe5a3}, /* U+7D15 */ + {0xe7b497, 0xbcd3}, /* U+7D17 */ + {0xe7b498, 0xb9c9}, /* U+7D18 */ + {0xe7b499, 0xbbe6}, /* U+7D19 */ + {0xe7b49a, 0xb5e9}, /* U+7D1A */ + {0xe7b49b, 0xcab6}, /* U+7D1B */ + {0xe7b49c, 0xe5a2}, /* U+7D1C */ + {0xe7b49d, 0xf9fc}, /* U+7D1D [2000] */ + {0xe7b49e, 0x8ff4ad}, /* U+7D1E [2000] */ + {0xe7b4a0, 0xc1c7}, /* U+7D20 */ + {0xe7b4a1, 0xcbc2}, /* U+7D21 */ + {0xe7b4a2, 0xbaf7}, /* U+7D22 */ + {0xe7b4a3, 0xf9fd}, /* U+7D23 [2000] */ + {0xe7b4ab, 0xbbe7}, /* U+7D2B */ + {0xe7b4ac, 0xc4dd}, /* U+7D2C */ + {0xe7b4ae, 0xe5a7}, /* U+7D2E */ + {0xe7b4af, 0xcedf}, /* U+7D2F */ + {0xe7b4b0, 0xbad9}, /* U+7D30 */ + {0xe7b4b1, 0xf9fe}, /* U+7D31 [2000] */ + {0xe7b4b2, 0xe5a8}, /* U+7D32 */ + {0xe7b4b3, 0xbfc2}, /* U+7D33 */ + {0xe7b4b5, 0xe5aa}, /* U+7D35 */ + {0xe7b4b9, 0xbed2}, /* U+7D39 */ + {0xe7b4ba, 0xbab0}, /* U+7D3A */ + {0xe7b4bd, 0x8ff4b0}, /* U+7D3D [2000] */ + {0xe7b4be, 0x8ff4b1}, /* U+7D3E [2000] */ + {0xe7b4bf, 0xe5a9}, /* U+7D3F */ + {0xe7b580, 0x8ff4b2}, /* U+7D40 [2000] */ + {0xe7b581, 0xfaa1}, /* U+7D41 [2000] */ + {0xe7b582, 0xbdaa}, /* U+7D42 */ + {0xe7b583, 0xb8be}, /* U+7D43 */ + {0xe7b584, 0xc1c8}, /* U+7D44 */ + {0xe7b585, 0xe5a5}, /* U+7D45 */ + {0xe7b586, 0xe5ab}, /* U+7D46 */ + {0xe7b587, 0x8ff4b3}, /* U+7D47 [2000] */ + {0xe7b588, 0xfaa2}, /* U+7D48 [2000] */ + {0xe7b58b, 0xe5a6}, /* U+7D4B */ + {0xe7b58c, 0xb7d0}, /* U+7D4C */ + {0xe7b58e, 0xe5ae}, /* U+7D4E */ + {0xe7b58f, 0xe5b2}, /* U+7D4F */ + {0xe7b590, 0xb7eb}, /* U+7D50 */ + {0xe7b593, 0xfaa3}, /* U+7D53 [2000] */ + {0xe7b596, 0xe5ad}, /* U+7D56 */ + {0xe7b599, 0x8ff4b7}, /* U+7D59 [2000] */ + {0xe7b59a, 0x8ff4b8}, /* U+7D5A [2000] */ + {0xe7b59b, 0xe5b6}, /* U+7D5B */ + {0xe7b59c, 0xfaa4}, /* U+7D5C [2000] */ + {0xe7b59e, 0xb9ca}, /* U+7D5E */ + {0xe7b5a1, 0xcded}, /* U+7D61 */ + {0xe7b5a2, 0xb0bc}, /* U+7D62 */ + {0xe7b5a3, 0xe5b3}, /* U+7D63 */ + {0xe7b5a6, 0xb5eb}, /* U+7D66 */ + {0xe7b5a8, 0xe5b0}, /* U+7D68 */ + {0xe7b5aa, 0x8ff4b9}, /* U+7D6A [2000] */ + {0xe7b5ae, 0xe5b1}, /* U+7D6E */ + {0xe7b5b0, 0x8ff4ba}, /* U+7D70 [2000] */ + {0xe7b5b1, 0xc5fd}, /* U+7D71 */ + {0xe7b5b2, 0xe5af}, /* U+7D72 */ + {0xe7b5b3, 0xe5ac}, /* U+7D73 */ + {0xe7b5b5, 0xb3a8}, /* U+7D75 */ + {0xe7b5b6, 0xc0e4}, /* U+7D76 */ + {0xe7b5b9, 0xb8a8}, /* U+7D79 */ + {0xe7b5ba, 0xfaa5}, /* U+7D7A [2000] */ + {0xe7b5bd, 0xe5b8}, /* U+7D7D */ + {0xe7b5bf, 0x8ff4bc}, /* U+7D7F [2000] */ + {0xe7b683, 0xfaa6}, /* U+7D83 [2000] */ + {0xe7b686, 0x8ff4be}, /* U+7D86 [2000] */ + {0xe7b688, 0x8ff4bf}, /* U+7D88 [2000] */ + {0xe7b689, 0xe5b5}, /* U+7D89 */ + {0xe7b68b, 0xfaa7}, /* U+7D8B [2000] */ + {0xe7b68c, 0x8ff4c0}, /* U+7D8C [2000] */ + {0xe7b68f, 0xe5b7}, /* U+7D8F */ + {0xe7b693, 0xe5b4}, /* U+7D93 */ + {0xe7b697, 0x8ff4c1}, /* U+7D97 [2000] */ + {0xe7b699, 0xb7d1}, /* U+7D99 */ + {0xe7b69a, 0xc2b3}, /* U+7D9A */ + {0xe7b69b, 0xe5b9}, /* U+7D9B */ + {0xe7b69c, 0xc1ee}, /* U+7D9C */ + {0xe7b69d, 0x8ff4c3}, /* U+7D9D [2000] */ + {0xe7b69f, 0xe5c6}, /* U+7D9F */ + {0xe7b6a0, 0xfaa8}, /* U+7DA0 [2000] */ + {0xe7b6a2, 0xe5c2}, /* U+7DA2 */ + {0xe7b6a3, 0xe5bc}, /* U+7DA3 */ + {0xe7b6a6, 0xfaa9}, /* U+7DA6 [2000] */ + {0xe7b6a7, 0x8ff4c4}, /* U+7DA7 [2000] */ + {0xe7b6aa, 0x8ff4c5}, /* U+7DAA [2000] */ + {0xe7b6ab, 0xe5c0}, /* U+7DAB */ + {0xe7b6ac, 0xbcfa}, /* U+7DAC */ + {0xe7b6ad, 0xb0dd}, /* U+7DAD */ + {0xe7b6ae, 0xe5bb}, /* U+7DAE */ + {0xe7b6af, 0xe5c3}, /* U+7DAF */ + {0xe7b6b0, 0xe5c7}, /* U+7DB0 */ + {0xe7b6b1, 0xb9cb}, /* U+7DB1 */ + {0xe7b6b2, 0xccd6}, /* U+7DB2 */ + {0xe7b6b4, 0xc4d6}, /* U+7DB4 */ + {0xe7b6b5, 0xe5bd}, /* U+7DB5 */ + {0xe7b6b6, 0x8ff4c6}, /* U+7DB6 [2000] */ + {0xe7b6b7, 0x8ff4c7}, /* U+7DB7 [2000] */ + {0xe7b6b8, 0xe5c5}, /* U+7DB8 */ + {0xe7b6ba, 0xe5ba}, /* U+7DBA */ + {0xe7b6bb, 0xc3be}, /* U+7DBB */ + {0xe7b6bd, 0xe5bf}, /* U+7DBD */ + {0xe7b6be, 0xb0bd}, /* U+7DBE */ + {0xe7b6bf, 0xccca}, /* U+7DBF */ + {0xe7b780, 0x8ff4c8}, /* U+7DC0 [2000] */ + {0xe7b782, 0xfaaa}, /* U+7DC2 [2000] */ + {0xe7b787, 0xe5be}, /* U+7DC7 */ + {0xe7b78a, 0xb6db}, /* U+7DCA */ + {0xe7b78b, 0xc8ec}, /* U+7DCB */ + {0xe7b78c, 0xfaab}, /* U+7DCC [2000] */ + {0xe7b78f, 0xc1ed}, /* U+7DCF */ + {0xe7b791, 0xced0}, /* U+7DD1 */ + {0xe7b792, 0xbdef}, /* U+7DD2 */ + {0xe7b795, 0xe5ee}, /* U+7DD5 */ + {0xe7b796, 0xfaac}, /* U+7DD6 [2000] */ + {0xe7b797, 0x8ff4c9}, /* U+7DD7 [2000] */ + {0xe7b798, 0xe5c8}, /* U+7DD8 */ + {0xe7b799, 0x8ff4ca}, /* U+7DD9 [2000] */ + {0xe7b79a, 0xc0fe}, /* U+7DDA */ + {0xe7b79c, 0xe5c4}, /* U+7DDC */ + {0xe7b79d, 0xe5c9}, /* U+7DDD */ + {0xe7b79e, 0xe5cb}, /* U+7DDE */ + {0xe7b7a0, 0xc4f9}, /* U+7DE0 */ + {0xe7b7a1, 0xe5ce}, /* U+7DE1 */ + {0xe7b7a3, 0xfaad}, /* U+7DE3 [2000] */ + {0xe7b7a4, 0xe5ca}, /* U+7DE4 */ + {0xe7b7a6, 0x8ff4cb}, /* U+7DE6 [2000] */ + {0xe7b7a8, 0xcad4}, /* U+7DE8 */ + {0xe7b7a9, 0xb4cb}, /* U+7DE9 */ + {0xe7b7ac, 0xcccb}, /* U+7DEC */ + {0xe7b7af, 0xb0de}, /* U+7DEF */ + {0xe7b7b1, 0x8ff4cc}, /* U+7DF1 [2000] */ + {0xe7b7b2, 0xe5cd}, /* U+7DF2 */ + {0xe7b7b4, 0xcefd}, /* U+7DF4 */ + {0xe7b7b9, 0x8ff4cd}, /* U+7DF9 [2000] */ + {0xe7b7bb, 0xe5cc}, /* U+7DFB */ + {0xe7b881, 0xb1ef}, /* U+7E01 */ + {0xe7b884, 0xc6ec}, /* U+7E04 */ + {0xe7b885, 0xe5cf}, /* U+7E05 */ + {0xe7b888, 0xfab0}, /* U+7E08 [2000] */ + {0xe7b889, 0xe5d6}, /* U+7E09 */ + {0xe7b88a, 0xe5d0}, /* U+7E0A */ + {0xe7b88b, 0xe5d7}, /* U+7E0B */ + {0xe7b890, 0x8ff4d1}, /* U+7E10 [2000] */ + {0xe7b891, 0xfab1}, /* U+7E11 [2000] */ + {0xe7b892, 0xe5d3}, /* U+7E12 */ + {0xe7b895, 0xfab2}, /* U+7E15 [2000] */ + {0xe7b897, 0x8ff4d2}, /* U+7E17 [2000] */ + {0xe7b89b, 0xc7fb}, /* U+7E1B */ + {0xe7b89d, 0x8ff4d3}, /* U+7E1D [2000] */ + {0xe7b89e, 0xbcca}, /* U+7E1E */ + {0xe7b89f, 0xe5d5}, /* U+7E1F */ + {0xe7b8a0, 0x8ff4d4}, /* U+7E20 [2000] */ + {0xe7b8a1, 0xe5d2}, /* U+7E21 */ + {0xe7b8a2, 0xe5d8}, /* U+7E22 */ + {0xe7b8a3, 0xe5d1}, /* U+7E23 */ + {0xe7b8a6, 0xbdc4}, /* U+7E26 */ + {0xe7b8a7, 0x8ff4d5}, /* U+7E27 [2000] */ + {0xe7b8a8, 0xfaaf}, /* U+7E28 [2000] */ + {0xe7b8ab, 0xcba5}, /* U+7E2B */ + {0xe7b8ac, 0x8ff4d6}, /* U+7E2C [2000] */ + {0xe7b8ae, 0xbdcc}, /* U+7E2E */ + {0xe7b8b1, 0xe5d4}, /* U+7E31 */ + {0xe7b8b2, 0xe5e0}, /* U+7E32 */ + {0xe7b8b5, 0xe5dc}, /* U+7E35 */ + {0xe7b8b7, 0xe5df}, /* U+7E37 */ + {0xe7b8b9, 0xe5dd}, /* U+7E39 */ + {0xe7b8ba, 0xe5e1}, /* U+7E3A */ + {0xe7b8bb, 0xe5db}, /* U+7E3B */ + {0xe7b8bd, 0xe5c1}, /* U+7E3D */ + {0xe7b8be, 0xc0d3}, /* U+7E3E */ + {0xe7b981, 0xc8cb}, /* U+7E41 */ + {0xe7b983, 0xe5de}, /* U+7E43 */ + {0xe7b985, 0x8ff4d7}, /* U+7E45 [2000] */ + {0xe7b986, 0xe5d9}, /* U+7E46 */ + {0xe7b987, 0xfab4}, /* U+7E47 [2000] */ + {0xe7b98a, 0xc1a1}, /* U+7E4A */ + {0xe7b98b, 0xb7d2}, /* U+7E4B */ + {0xe7b98d, 0xbdab}, /* U+7E4D */ + {0xe7b992, 0xfab5}, /* U+7E52 [2000] */ + {0xe7b994, 0xbfa5}, /* U+7E54 */ + {0xe7b995, 0xc1b6}, /* U+7E55 */ + {0xe7b996, 0xe5e4}, /* U+7E56 */ + {0xe7b999, 0xe5e6}, /* U+7E59 */ + {0xe7b99a, 0xe5e7}, /* U+7E5A */ + {0xe7b99d, 0xe5e3}, /* U+7E5D */ + {0xe7b99e, 0xe5e5}, /* U+7E5E */ + {0xe7b9a1, 0xfab6}, /* U+7E61 [2000] */ + {0xe7b9a6, 0xe5da}, /* U+7E66 */ + {0xe7b9a7, 0xe5e2}, /* U+7E67 */ + {0xe7b9a9, 0xe5ea}, /* U+7E69 */ + {0xe7b9aa, 0xe5e9}, /* U+7E6A */ + {0xe7b9ab, 0xfefe}, /* U+7E6B [2004] */ + {0xe7b9ad, 0xcbfa}, /* U+7E6D */ + {0xe7b9b0, 0xb7ab}, /* U+7E70 */ + {0xe7b9b3, 0x8ff4d8}, /* U+7E73 [2000] */ + {0xe7b9b5, 0x8ff4d9}, /* U+7E75 [2000] */ + {0xe7b9b9, 0xe5e8}, /* U+7E79 */ + {0xe7b9bb, 0xe5ec}, /* U+7E7B */ + {0xe7b9bc, 0xe5eb}, /* U+7E7C */ + {0xe7b9bd, 0xe5ef}, /* U+7E7D */ + {0xe7b9be, 0x8ff4da}, /* U+7E7E [2000] */ + {0xe7b9bf, 0xe5f1}, /* U+7E7F */ + {0xe7ba82, 0xbbbc}, /* U+7E82 */ + {0xe7ba83, 0xe5ed}, /* U+7E83 */ + {0xe7ba86, 0x8ff4db}, /* U+7E86 [2000] */ + {0xe7ba87, 0x8ff4dc}, /* U+7E87 [2000] */ + {0xe7ba88, 0xe5f2}, /* U+7E88 */ + {0xe7ba89, 0xe5f3}, /* U+7E89 */ + {0xe7ba8a, 0xfab7}, /* U+7E8A [2000] */ + {0xe7ba8c, 0xe5f4}, /* U+7E8C */ + {0xe7ba8d, 0xfab8}, /* U+7E8D [2000] */ + {0xe7ba8e, 0xe5fa}, /* U+7E8E */ + {0xe7ba8f, 0xc5bb}, /* U+7E8F */ + {0xe7ba90, 0xe5f6}, /* U+7E90 */ + {0xe7ba91, 0x8ff4de}, /* U+7E91 [2000] */ + {0xe7ba92, 0xe5f5}, /* U+7E92 */ + {0xe7ba93, 0xe5f7}, /* U+7E93 */ + {0xe7ba94, 0xe5f8}, /* U+7E94 */ + {0xe7ba96, 0xe5f9}, /* U+7E96 */ + {0xe7ba98, 0x8ff4df}, /* U+7E98 [2000] */ + {0xe7ba9a, 0x8ff4e0}, /* U+7E9A [2000] */ + {0xe7ba9b, 0xe5fb}, /* U+7E9B */ + {0xe7ba9c, 0xe5fc}, /* U+7E9C */ + {0xe7bcb6, 0xb4cc}, /* U+7F36 */ + {0xe7bcb8, 0xe5fd}, /* U+7F38 */ + {0xe7bcba, 0xe5fe}, /* U+7F3A */ + {0xe7bcbb, 0x8ff4e3}, /* U+7F3B [2000] */ + {0xe7bcbc, 0x8ff4e2}, /* U+7F3C [2000] */ + {0xe7bcbe, 0x8ff4e4}, /* U+7F3E [2000] */ + {0xe7bd83, 0x8ff4e5}, /* U+7F43 [2000] */ + {0xe7bd84, 0x8ff4e6}, /* U+7F44 [2000] */ + {0xe7bd85, 0xe6a1}, /* U+7F45 */ + {0xe7bd87, 0xfab9}, /* U+7F47 [2000] */ + {0xe7bd8c, 0xe6a2}, /* U+7F4C */ + {0xe7bd8d, 0xe6a3}, /* U+7F4D */ + {0xe7bd8e, 0xe6a4}, /* U+7F4E */ + {0xe7bd8f, 0x8ff4e7}, /* U+7F4F [2000] */ + {0xe7bd90, 0xe6a5}, /* U+7F50 */ + {0xe7bd91, 0xe6a6}, /* U+7F51 */ + {0xe7bd92, 0x8ff4ea}, /* U+7F52 [2000] */ + {0xe7bd94, 0xe6a8}, /* U+7F54 */ + {0xe7bd95, 0xe6a7}, /* U+7F55 */ + {0xe7bd98, 0xe6a9}, /* U+7F58 */ + {0xe7bd9f, 0xe6aa}, /* U+7F5F */ + {0xe7bda0, 0xe6ab}, /* U+7F60 */ + {0xe7bda1, 0x8ff4ec}, /* U+7F61 [2000] */ + {0xe7bda3, 0x8ff4ed}, /* U+7F63 [2000] */ + {0xe7bda4, 0x8ff4ee}, /* U+7F64 [2000] */ + {0xe7bda7, 0xe6ae}, /* U+7F67 */ + {0xe7bda8, 0xe6ac}, /* U+7F68 */ + {0xe7bda9, 0xe6ad}, /* U+7F69 */ + {0xe7bdaa, 0xbae1}, /* U+7F6A */ + {0xe7bdab, 0xb7d3}, /* U+7F6B */ + {0xe7bdad, 0x8ff4ef}, /* U+7F6D [2000] */ + {0xe7bdae, 0xc3d6}, /* U+7F6E */ + {0xe7bdb0, 0xc8b3}, /* U+7F70 */ + {0xe7bdb2, 0xbdf0}, /* U+7F72 */ + {0xe7bdb5, 0xc7cd}, /* U+7F75 */ + {0xe7bdb7, 0xc8ed}, /* U+7F77 */ + {0xe7bdb8, 0xe6af}, /* U+7F78 */ + {0xe7bdb9, 0xd8ed}, /* U+7F79 */ + {0xe7bdbd, 0x8ff4f0}, /* U+7F7D [2000] */ + {0xe7bdbe, 0x8ff4f1}, /* U+7F7E [2000] */ + {0xe7be82, 0xe6b0}, /* U+7F82 */ + {0xe7be83, 0xe6b2}, /* U+7F83 */ + {0xe7be85, 0xcde5}, /* U+7F85 */ + {0xe7be86, 0xe6b1}, /* U+7F86 */ + {0xe7be87, 0xe6b4}, /* U+7F87 */ + {0xe7be88, 0xe6b3}, /* U+7F88 */ + {0xe7be8a, 0xcdd3}, /* U+7F8A */ + {0xe7be8c, 0xe6b5}, /* U+7F8C */ + {0xe7be8e, 0xc8fe}, /* U+7F8E */ + {0xe7be90, 0x8ff4f3}, /* U+7F90 [2000] */ + {0xe7be91, 0xfabb}, /* U+7F91 [2000] */ + {0xe7be94, 0xe6b6}, /* U+7F94 */ + {0xe7be96, 0x8ff4f6}, /* U+7F96 [2000] */ + {0xe7be97, 0xfabc}, /* U+7F97 [2000] */ + {0xe7be9a, 0xe6b9}, /* U+7F9A */ + {0xe7be9c, 0x8ff4f7}, /* U+7F9C [2000] */ + {0xe7be9d, 0xe6b8}, /* U+7F9D */ + {0xe7be9e, 0xe6b7}, /* U+7F9E */ + {0xe7bea3, 0xe6ba}, /* U+7FA3 */ + {0xe7bea4, 0xb7b2}, /* U+7FA4 */ + {0xe7bea8, 0xc1a2}, /* U+7FA8 */ + {0xe7bea9, 0xb5c1}, /* U+7FA9 */ + {0xe7bead, 0x8ff4f8}, /* U+7FAD [2000] */ + {0xe7beae, 0xe6be}, /* U+7FAE */ + {0xe7beaf, 0xe6bb}, /* U+7FAF */ + {0xe7beb2, 0xe6bc}, /* U+7FB2 */ + {0xe7beb6, 0xe6bf}, /* U+7FB6 */ + {0xe7beb8, 0xe6c0}, /* U+7FB8 */ + {0xe7beb9, 0xe6bd}, /* U+7FB9 */ + {0xe7bebd, 0xb1a9}, /* U+7FBD */ + {0xe7bebf, 0xfabd}, /* U+7FBF [2000] */ + {0xe7bf81, 0xb2a7}, /* U+7FC1 */ + {0xe7bf83, 0x8ff4fa}, /* U+7FC3 [2000] */ + {0xe7bf85, 0xe6c2}, /* U+7FC5 */ + {0xe7bf86, 0xe6c3}, /* U+7FC6 */ + {0xe7bf8a, 0xe6c4}, /* U+7FCA */ + {0xe7bf8c, 0xcde2}, /* U+7FCC */ + {0xe7bf8e, 0xfabe}, /* U+7FCE [2000] */ + {0xe7bf8f, 0x8ff4fb}, /* U+7FCF [2000] */ + {0xe7bf92, 0xbdac}, /* U+7FD2 */ + {0xe7bf94, 0xe6c6}, /* U+7FD4 */ + {0xe7bf95, 0xe6c5}, /* U+7FD5 */ + {0xe7bf9b, 0xfabf}, /* U+7FDB [2000] */ + {0xe7bf9f, 0xfac0}, /* U+7FDF [2000] */ + {0xe7bfa0, 0xbfe9}, /* U+7FE0 */ + {0xe7bfa1, 0xe6c7}, /* U+7FE1 */ + {0xe7bfa3, 0x8ff4fc}, /* U+7FE3 [2000] */ + {0xe7bfa5, 0x8ff4fd}, /* U+7FE5 [2000] */ + {0xe7bfa6, 0xe6c8}, /* U+7FE6 */ + {0xe7bfa9, 0xe6c9}, /* U+7FE9 */ + {0xe7bfab, 0xb4e5}, /* U+7FEB */ + {0xe7bfac, 0xfac1}, /* U+7FEC [2000] */ + {0xe7bfae, 0xfac2}, /* U+7FEE [2000] */ + {0xe7bfaf, 0x8ff4fe}, /* U+7FEF [2000] */ + {0xe7bfb0, 0xb4cd}, /* U+7FF0 */ + {0xe7bfb2, 0x8ff5a1}, /* U+7FF2 [2000] */ + {0xe7bfb3, 0xe6ca}, /* U+7FF3 */ + {0xe7bfb9, 0xe6cb}, /* U+7FF9 */ + {0xe7bfba, 0xfac3}, /* U+7FFA [2000] */ + {0xe7bfbb, 0xcbdd}, /* U+7FFB */ + {0xe7bfbc, 0xcde3}, /* U+7FFC */ + {0xe88080, 0xcdd4}, /* U+8000 */ + {0xe88081, 0xcfb7}, /* U+8001 */ + {0xe88082, 0x8ff5a2}, /* U+8002 [2000] */ + {0xe88083, 0xb9cd}, /* U+8003 */ + {0xe88084, 0xe6ce}, /* U+8004 */ + {0xe88085, 0xbcd4}, /* U+8005 */ + {0xe88086, 0xe6cd}, /* U+8006 */ + {0xe88088, 0x8ff5a4}, /* U+8008 [2000] */ + {0xe8808a, 0x8ff5a3}, /* U+800A [2000] */ + {0xe8808b, 0xe6cf}, /* U+800B */ + {0xe8808c, 0xbca9}, /* U+800C */ + {0xe8808e, 0x8ff5a5}, /* U+800E [2000] */ + {0xe88090, 0xc2d1}, /* U+8010 */ + {0xe88091, 0x8ff5a6}, /* U+8011 [2000] */ + {0xe88092, 0xe6d0}, /* U+8012 */ + {0xe88094, 0xfac5}, /* U+8014 [2000] */ + {0xe88095, 0xb9cc}, /* U+8015 */ + {0xe88096, 0x8ff5a7}, /* U+8016 [2000] */ + {0xe88097, 0xccd7}, /* U+8017 */ + {0xe88098, 0xe6d1}, /* U+8018 */ + {0xe88099, 0xe6d2}, /* U+8019 */ + {0xe8809c, 0xe6d3}, /* U+801C */ + {0xe880a1, 0xe6d4}, /* U+8021 */ + {0xe880a4, 0x8ff5a8}, /* U+8024 [2000] */ + {0xe880a6, 0xfac6}, /* U+8026 [2000] */ + {0xe880a8, 0xe6d5}, /* U+8028 */ + {0xe880ac, 0x8ff5a9}, /* U+802C [2000] */ + {0xe880b0, 0x8ff5aa}, /* U+8030 [2000] */ + {0xe880b3, 0xbcaa}, /* U+8033 */ + {0xe880b5, 0xfac7}, /* U+8035 [2000] */ + {0xe880b6, 0xcced}, /* U+8036 */ + {0xe880b7, 0xfac8}, /* U+8037 [2000] */ + {0xe880bb, 0xe6d7}, /* U+803B */ + {0xe880bc, 0xfac9}, /* U+803C [2000] */ + {0xe880bd, 0xc3bf}, /* U+803D */ + {0xe880bf, 0xe6d6}, /* U+803F */ + {0xe88183, 0x8ff5ab}, /* U+8043 [2000] */ + {0xe88186, 0xe6d9}, /* U+8046 */ + {0xe8818a, 0xe6d8}, /* U+804A */ + {0xe88192, 0xe6da}, /* U+8052 */ + {0xe88196, 0xc0bb}, /* U+8056 */ + {0xe88198, 0xe6db}, /* U+8058 */ + {0xe8819a, 0xe6dc}, /* U+805A */ + {0xe8819e, 0xcab9}, /* U+805E */ + {0xe8819f, 0xe6dd}, /* U+805F */ + {0xe881a1, 0xc1ef}, /* U+8061 */ + {0xe881a2, 0xe6de}, /* U+8062 */ + {0xe881a6, 0x8ff5ac}, /* U+8066 [2000] */ + {0xe881a8, 0xe6df}, /* U+8068 */ + {0xe881af, 0xcefe}, /* U+806F */ + {0xe881b0, 0xe6e2}, /* U+8070 */ + {0xe881b1, 0x8ff5ad}, /* U+8071 [2000] */ + {0xe881b2, 0xe6e1}, /* U+8072 */ + {0xe881b3, 0xe6e0}, /* U+8073 */ + {0xe881b4, 0xc4b0}, /* U+8074 */ + {0xe881b5, 0x8ff5ae}, /* U+8075 [2000] */ + {0xe881b6, 0xe6e3}, /* U+8076 */ + {0xe881b7, 0xbfa6}, /* U+8077 */ + {0xe881b9, 0xe6e4}, /* U+8079 */ + {0xe881bb, 0x8ff5af}, /* U+807B [2000] */ + {0xe881bd, 0xe6e5}, /* U+807D */ + {0xe881be, 0xcfb8}, /* U+807E */ + {0xe881bf, 0xe6e6}, /* U+807F */ + {0xe88284, 0xe6e7}, /* U+8084 */ + {0xe88285, 0xe6e9}, /* U+8085 */ + {0xe88286, 0xe6e8}, /* U+8086 */ + {0xe88287, 0xc8a5}, /* U+8087 */ + {0xe88289, 0xc6f9}, /* U+8089 */ + {0xe8828b, 0xcfbe}, /* U+808B */ + {0xe8828c, 0xc8a9}, /* U+808C */ + {0xe88293, 0xe6eb}, /* U+8093 */ + {0xe88296, 0xbed3}, /* U+8096 */ + {0xe88298, 0xc9aa}, /* U+8098 */ + {0xe88299, 0x8ff5b0}, /* U+8099 [2000] */ + {0xe8829a, 0xe6ec}, /* U+809A */ + {0xe8829b, 0xe6ea}, /* U+809B */ + {0xe8829c, 0x8ff5b1}, /* U+809C [2000] */ + {0xe8829d, 0xb4ce}, /* U+809D */ + {0xe882a1, 0xb8d4}, /* U+80A1 */ + {0xe882a2, 0xbbe8}, /* U+80A2 */ + {0xe882a4, 0x8ff5b2}, /* U+80A4 [2000] */ + {0xe882a5, 0xc8ee}, /* U+80A5 */ + {0xe882a7, 0x8ff5b3}, /* U+80A7 [2000] */ + {0xe882a9, 0xb8aa}, /* U+80A9 */ + {0xe882aa, 0xcbc3}, /* U+80AA */ + {0xe882ac, 0xe6ef}, /* U+80AC */ + {0xe882ad, 0xe6ed}, /* U+80AD */ + {0xe882af, 0xb9ce}, /* U+80AF */ + {0xe882b1, 0xb9cf}, /* U+80B1 */ + {0xe882b2, 0xb0e9}, /* U+80B2 */ + {0xe882b4, 0xbae8}, /* U+80B4 */ + {0xe882b8, 0x8ff5b4}, /* U+80B8 [2000] */ + {0xe882ba, 0xc7d9}, /* U+80BA */ + {0xe88383, 0xb0df}, /* U+80C3 */ + {0xe88384, 0xe6f4}, /* U+80C4 */ + {0xe88385, 0x8ff5b6}, /* U+80C5 [2000] */ + {0xe88386, 0xc3c0}, /* U+80C6 */ + {0xe8838a, 0xfaca}, /* U+80CA [2000] */ + {0xe8838c, 0xc7d8}, /* U+80CC */ + {0xe8838e, 0xc2db}, /* U+80CE */ + {0xe88395, 0x8ff5b7}, /* U+80D5 [2000] */ + {0xe88396, 0xe6f6}, /* U+80D6 */ + {0xe88397, 0xfacb}, /* U+80D7 [2000] */ + {0xe88398, 0x8ff5b8}, /* U+80D8 [2000] */ + {0xe88399, 0xe6f2}, /* U+80D9 */ + {0xe8839a, 0xe6f5}, /* U+80DA */ + {0xe8839b, 0xe6f0}, /* U+80DB */ + {0xe8839d, 0xe6f3}, /* U+80DD */ + {0xe8839e, 0xcba6}, /* U+80DE */ + {0xe883a0, 0xfacc}, /* U+80E0 [2000] */ + {0xe883a1, 0xb8d5}, /* U+80E1 */ + {0xe883a4, 0xb0fd}, /* U+80E4 */ + {0xe883a5, 0xe6f1}, /* U+80E5 */ + {0xe883a6, 0x8ff5b9}, /* U+80E6 [2000] */ + {0xe883af, 0xe6f8}, /* U+80EF */ + {0xe883b1, 0xe6f9}, /* U+80F1 */ + {0xe883b3, 0xfacd}, /* U+80F3 [2000] */ + {0xe883b4, 0xc6b9}, /* U+80F4 */ + {0xe883b5, 0x8ff5bc}, /* U+80F5 [2000] */ + {0xe883b8, 0xb6bb}, /* U+80F8 */ + {0xe883bb, 0x8ff5bd}, /* U+80FB [2000] */ + {0xe883bc, 0xe7a6}, /* U+80FC */ + {0xe883bd, 0xc7bd}, /* U+80FD */ + {0xe88482, 0xbbe9}, /* U+8102 */ + {0xe88485, 0xb6bc}, /* U+8105 */ + {0xe88486, 0xc0c8}, /* U+8106 */ + {0xe88487, 0xcfc6}, /* U+8107 */ + {0xe88488, 0xccae}, /* U+8108 */ + {0xe88489, 0xe6f7}, /* U+8109 */ + {0xe8848a, 0xc0d4}, /* U+810A */ + {0xe8848d, 0x8ff5bb}, /* U+810D [2000] */ + {0xe88496, 0x8ff5c0}, /* U+8116 [2000] */ + {0xe88498, 0xface}, /* U+8118 [2000] */ + {0xe8849a, 0xb5d3}, /* U+811A */ + {0xe8849b, 0xe6fa}, /* U+811B */ + {0xe8849e, 0x8ff5c1}, /* U+811E [2000] */ + {0xe884a3, 0xe6fc}, /* U+8123 */ + {0xe884a4, 0x8ff5c3}, /* U+8124 [2000] */ + {0xe884a7, 0x8ff5c4}, /* U+8127 [2000] */ + {0xe884a9, 0xe6fb}, /* U+8129 */ + {0xe884ac, 0x8ff5c5}, /* U+812C [2000] */ + {0xe884af, 0xe6fd}, /* U+812F */ + {0xe884b1, 0xc3a6}, /* U+8131 */ + {0xe884b3, 0xc7be}, /* U+8133 */ + {0xe884b5, 0x8ff5bf}, /* U+8135 [2000] */ + {0xe884b9, 0xc4b1}, /* U+8139 */ + {0xe884bd, 0x8ff5c7}, /* U+813D [2000] */ + {0xe884be, 0xe7a3}, /* U+813E */ + {0xe88586, 0xe7a2}, /* U+8146 */ + {0xe8858a, 0xfacf}, /* U+814A [2000] */ + {0xe8858b, 0xe6fe}, /* U+814B */ + {0xe8858e, 0xbfd5}, /* U+814E */ + {0xe88590, 0xc9e5}, /* U+8150 */ + {0xe88591, 0xe7a5}, /* U+8151 */ + {0xe88593, 0xe7a4}, /* U+8153 */ + {0xe88594, 0xb9d0}, /* U+8154 */ + {0xe88595, 0xcfd3}, /* U+8155 */ + {0xe8859f, 0xe7b5}, /* U+815F */ + {0xe885a0, 0xfad0}, /* U+8160 [2000] */ + {0xe885a5, 0xe7a9}, /* U+8165 */ + {0xe885a6, 0xe7aa}, /* U+8166 */ + {0xe885a7, 0xfad1}, /* U+8167 [2000] */ + {0xe885a8, 0xfad2}, /* U+8168 [2000] */ + {0xe885a9, 0x8ff5c9}, /* U+8169 [2000] */ + {0xe885ab, 0xbcf0}, /* U+816B */ + {0xe885ad, 0xfad3}, /* U+816D [2000] */ + {0xe885ae, 0xe7a8}, /* U+816E */ + {0xe885b0, 0xb9f8}, /* U+8170 */ + {0xe885b1, 0xe7a7}, /* U+8171 */ + {0xe885b4, 0xe7ab}, /* U+8174 */ + {0xe885b8, 0xc4b2}, /* U+8178 */ + {0xe885b9, 0xcaa2}, /* U+8179 */ + {0xe885ba, 0xc1a3}, /* U+817A */ + {0xe885bf, 0xc2dc}, /* U+817F */ + {0xe88680, 0xe7af}, /* U+8180 */ + {0xe88681, 0x8ff5cb}, /* U+8181 [2000] */ + {0xe88682, 0xe7b0}, /* U+8182 */ + {0xe88683, 0xe7ac}, /* U+8183 */ + {0xe88684, 0x8ff5cd}, /* U+8184 [2000] */ + {0xe88685, 0x8ff5ce}, /* U+8185 [2000] */ + {0xe88688, 0xe7ad}, /* U+8188 */ + {0xe8868a, 0xe7ae}, /* U+818A */ + {0xe8868f, 0xb9d1}, /* U+818F */ + {0xe88693, 0xe7b6}, /* U+8193 */ + {0xe88695, 0xe7b2}, /* U+8195 */ + {0xe88698, 0x8ff5d0}, /* U+8198 [2000] */ + {0xe8869a, 0xc9e6}, /* U+819A */ + {0xe8869c, 0xcbec}, /* U+819C */ + {0xe8869d, 0xc9a8}, /* U+819D */ + {0xe886a0, 0xe7b1}, /* U+81A0 */ + {0xe886a3, 0xe7b4}, /* U+81A3 */ + {0xe886a4, 0xe7b3}, /* U+81A4 */ + {0xe886a8, 0xcbc4}, /* U+81A8 */ + {0xe886a9, 0xe7b7}, /* U+81A9 */ + {0xe886b0, 0xe7b8}, /* U+81B0 */ + {0xe886b2, 0x8ff5d1}, /* U+81B2 [2000] */ + {0xe886b3, 0xc1b7}, /* U+81B3 */ + {0xe886b5, 0xe7b9}, /* U+81B5 */ + {0xe886b8, 0xe7bb}, /* U+81B8 */ + {0xe886ba, 0xe7bf}, /* U+81BA */ + {0xe886bb, 0xfad4}, /* U+81BB [2000] */ + {0xe886bd, 0xe7bc}, /* U+81BD */ + {0xe886be, 0xe7ba}, /* U+81BE */ + {0xe886bf, 0xc7bf}, /* U+81BF */ + {0xe88780, 0xe7bd}, /* U+81C0 */ + {0xe88781, 0x8ff5d2}, /* U+81C1 [2000] */ + {0xe88782, 0xe7be}, /* U+81C2 */ + {0xe88783, 0x8ff5d3}, /* U+81C3 [2000] */ + {0xe88786, 0xb2b2}, /* U+81C6 */ + {0xe88788, 0xe7c5}, /* U+81C8 */ + {0xe88789, 0xe7c0}, /* U+81C9 */ + {0xe8878a, 0xfad5}, /* U+81CA [2000] */ + {0xe8878d, 0xe7c1}, /* U+81CD */ + {0xe8878f, 0xfad6}, /* U+81CF [2000] */ + {0xe88791, 0xe7c2}, /* U+81D1 */ + {0xe88793, 0xc2a1}, /* U+81D3 */ + {0xe88796, 0x8ff5d4}, /* U+81D6 [2000] */ + {0xe88797, 0xfad7}, /* U+81D7 [2000] */ + {0xe88798, 0xe7c4}, /* U+81D8 */ + {0xe88799, 0xe7c3}, /* U+81D9 */ + {0xe8879a, 0xe7c6}, /* U+81DA */ + {0xe8879b, 0x8ff5d5}, /* U+81DB [2000] */ + {0xe8879f, 0xe7c7}, /* U+81DF */ + {0xe887a0, 0xe7c8}, /* U+81E0 */ + {0xe887a3, 0xbfc3}, /* U+81E3 */ + {0xe887a4, 0x8ff5d7}, /* U+81E4 [2000] */ + {0xe887a5, 0xb2e9}, /* U+81E5 */ + {0xe887a7, 0xe7c9}, /* U+81E7 */ + {0xe887a8, 0xced7}, /* U+81E8 */ + {0xe887aa, 0xbcab}, /* U+81EA */ + {0xe887ac, 0x8ff5d9}, /* U+81EC [2000] */ + {0xe887ad, 0xbdad}, /* U+81ED */ + {0xe887b3, 0xbbea}, /* U+81F3 */ + {0xe887b4, 0xc3d7}, /* U+81F4 */ + {0xe887ba, 0xe7ca}, /* U+81FA */ + {0xe887bb, 0xe7cb}, /* U+81FB */ + {0xe887bc, 0xb1b1}, /* U+81FC */ + {0xe887bd, 0x8ff5db}, /* U+81FD [2000] */ + {0xe887be, 0xe7cc}, /* U+81FE */ + {0xe887bf, 0x8ff5dc}, /* U+81FF [2000] */ + {0xe88881, 0xe7cd}, /* U+8201 */ + {0xe88882, 0xe7ce}, /* U+8202 */ + {0xe88884, 0x8ff5de}, /* U+8204 [2000] */ + {0xe88885, 0xe7cf}, /* U+8205 */ + {0xe88887, 0xe7d0}, /* U+8207 */ + {0xe88888, 0xb6bd}, /* U+8208 */ + {0xe88889, 0xdaaa}, /* U+8209 */ + {0xe8888a, 0xe7d1}, /* U+820A */ + {0xe8888c, 0xc0e5}, /* U+820C */ + {0xe8888d, 0xe7d2}, /* U+820D */ + {0xe8888e, 0xbccb}, /* U+820E */ + {0xe88890, 0xe7d3}, /* U+8210 */ + {0xe88892, 0xd0b0}, /* U+8212 */ + {0xe88896, 0xe7d4}, /* U+8216 */ + {0xe88897, 0xcade}, /* U+8217 */ + {0xe88898, 0xb4dc}, /* U+8218 */ + {0xe88899, 0x8ff5e0}, /* U+8219 [2000] */ + {0xe8889b, 0xc1a4}, /* U+821B */ + {0xe8889c, 0xbdd8}, /* U+821C */ + {0xe8889e, 0xc9f1}, /* U+821E */ + {0xe8889f, 0xbdae}, /* U+821F */ + {0xe888a1, 0x8ff5e1}, /* U+8221 [2000] */ + {0xe888a2, 0x8ff5e2}, /* U+8222 [2000] */ + {0xe888a9, 0xe7d5}, /* U+8229 */ + {0xe888aa, 0xb9d2}, /* U+822A */ + {0xe888ab, 0xe7d6}, /* U+822B */ + {0xe888ac, 0xc8cc}, /* U+822C */ + {0xe888ae, 0xe7e4}, /* U+822E */ + {0xe888b2, 0x8ff5e4}, /* U+8232 [2000] */ + {0xe888b3, 0xe7d8}, /* U+8233 */ + {0xe888b4, 0x8ff5e5}, /* U+8234 [2000] */ + {0xe888b5, 0xc2c9}, /* U+8235 */ + {0xe888b6, 0xc7f5}, /* U+8236 */ + {0xe888b7, 0xb8bf}, /* U+8237 */ + {0xe888b8, 0xe7d7}, /* U+8238 */ + {0xe888b9, 0xc1a5}, /* U+8239 */ + {0xe888bc, 0x8ff5e6}, /* U+823C [2000] */ + {0xe88980, 0xe7d9}, /* U+8240 */ + {0xe88985, 0x8ff5e9}, /* U+8245 [2000] */ + {0xe88986, 0x8ff5e7}, /* U+8246 [2000] */ + {0xe88987, 0xc4fa}, /* U+8247 */ + {0xe88989, 0x8ff5e8}, /* U+8249 [2000] */ + {0xe8898b, 0x8ff5eb}, /* U+824B [2000] */ + {0xe8898f, 0x8ff5ed}, /* U+824F [2000] */ + {0xe88997, 0x8ff5ef}, /* U+8257 [2000] */ + {0xe88998, 0xe7db}, /* U+8258 */ + {0xe88999, 0xe7da}, /* U+8259 */ + {0xe8899a, 0xe7dd}, /* U+825A */ + {0xe8899c, 0x8ff5f1}, /* U+825C [2000] */ + {0xe8899d, 0xe7dc}, /* U+825D */ + {0xe8899f, 0xe7de}, /* U+825F */ + {0xe889a0, 0xfadb}, /* U+8260 [2000] */ + {0xe889a2, 0xe7e0}, /* U+8262 */ + {0xe889a3, 0x8ff5f2}, /* U+8263 [2000] */ + {0xe889a4, 0xe7df}, /* U+8264 */ + {0xe889a6, 0xb4cf}, /* U+8266 */ + {0xe889a8, 0xe7e1}, /* U+8268 */ + {0xe889aa, 0xe7e2}, /* U+826A */ + {0xe889ab, 0xe7e3}, /* U+826B */ + {0xe889ae, 0xbab1}, /* U+826E */ + {0xe889af, 0xcec9}, /* U+826F */ + {0xe889b1, 0xe7e5}, /* U+8271 */ + {0xe889b2, 0xbfa7}, /* U+8272 */ + {0xe889b4, 0xfadc}, /* U+8274 [2000] */ + {0xe889b6, 0xb1f0}, /* U+8276 */ + {0xe889b7, 0xe7e6}, /* U+8277 */ + {0xe889b8, 0xe7e7}, /* U+8278 */ + {0xe889b9, 0x8ff5f6}, /* U+8279 [2000] */ + {0xe889bd, 0x8ff5f8}, /* U+827D [2000] */ + {0xe889be, 0xe7e8}, /* U+827E */ + {0xe889bf, 0x8ff5f9}, /* U+827F [2000] */ + {0xe88a83, 0x8ff5fa}, /* U+8283 [2000] */ + {0xe88a8a, 0x8ff5fb}, /* U+828A [2000] */ + {0xe88a8b, 0xb0f2}, /* U+828B */ + {0xe88a8d, 0xe7e9}, /* U+828D */ + {0xe88a8e, 0xfade}, /* U+828E [2000] */ + {0xe88a92, 0xe7ea}, /* U+8292 */ + {0xe88a93, 0x8ff5fc}, /* U+8293 [2000] */ + {0xe88a99, 0xc9e7}, /* U+8299 */ + {0xe88a9d, 0xbcc7}, /* U+829D */ + {0xe88a9f, 0xe7ec}, /* U+829F */ + {0xe88aa1, 0xfadf}, /* U+82A1 [2000] */ + {0xe88aa3, 0xfae0}, /* U+82A3 [2000] */ + {0xe88aa4, 0xfae1}, /* U+82A4 [2000] */ + {0xe88aa5, 0xb3a9}, /* U+82A5 */ + {0xe88aa6, 0xb0b2}, /* U+82A6 */ + {0xe88aa7, 0x8ff5fd}, /* U+82A7 [2000] */ + {0xe88aa8, 0x8ff5fe}, /* U+82A8 [2000] */ + {0xe88aa9, 0xfae2}, /* U+82A9 [2000] */ + {0xe88aab, 0xe7eb}, /* U+82AB */ + {0xe88aac, 0xe7ee}, /* U+82AC */ + {0xe88aad, 0xc7ce}, /* U+82AD */ + {0xe88aae, 0xfae3}, /* U+82AE [2000] */ + {0xe88aaf, 0xbfc4}, /* U+82AF */ + {0xe88ab1, 0xb2d6}, /* U+82B1 */ + {0xe88ab2, 0x8ff6a1}, /* U+82B2 [2000] */ + {0xe88ab3, 0xcba7}, /* U+82B3 */ + {0xe88ab4, 0x8ff6a2}, /* U+82B4 [2000] */ + {0xe88ab7, 0xfae4}, /* U+82B7 [2000] */ + {0xe88ab8, 0xb7dd}, /* U+82B8 */ + {0xe88ab9, 0xb6dc}, /* U+82B9 */ + {0xe88aba, 0x8ff6a3}, /* U+82BA [2000] */ + {0xe88abb, 0xe7ed}, /* U+82BB */ + {0xe88abc, 0x8ff6a4}, /* U+82BC [2000] */ + {0xe88abd, 0xb2ea}, /* U+82BD */ + {0xe88abe, 0xfae5}, /* U+82BE [2000] */ + {0xe88abf, 0xfae6}, /* U+82BF [2000] */ + {0xe88b85, 0xb4a3}, /* U+82C5 */ + {0xe88b86, 0xfae7}, /* U+82C6 [2000] */ + {0xe88b91, 0xb1f1}, /* U+82D1 */ + {0xe88b92, 0xe7f2}, /* U+82D2 */ + {0xe88b93, 0xceea}, /* U+82D3 */ + {0xe88b94, 0xc2dd}, /* U+82D4 */ + {0xe88b95, 0xfae8}, /* U+82D5 [2000] */ + {0xe88b97, 0xc9c4}, /* U+82D7 */ + {0xe88b99, 0xe7fe}, /* U+82D9 */ + {0xe88b9b, 0xb2d7}, /* U+82DB */ + {0xe88b9c, 0xe7fc}, /* U+82DC */ + {0xe88b9e, 0xe7fa}, /* U+82DE */ + {0xe88b9f, 0xe7f1}, /* U+82DF */ + {0xe88ba1, 0xe7ef}, /* U+82E1 */ + {0xe88ba2, 0x8ff6a5}, /* U+82E2 [2000] */ + {0xe88ba3, 0xe7f0}, /* U+82E3 */ + {0xe88ba5, 0xbce3}, /* U+82E5 */ + {0xe88ba6, 0xb6ec}, /* U+82E6 */ + {0xe88ba7, 0xc3f7}, /* U+82E7 */ + {0xe88ba8, 0x8ff6a6}, /* U+82E8 [2000] */ + {0xe88bab, 0xc6d1}, /* U+82EB */ + {0xe88bb1, 0xb1d1}, /* U+82F1 */ + {0xe88bb3, 0xe7f4}, /* U+82F3 */ + {0xe88bb4, 0xe7f3}, /* U+82F4 */ + {0xe88bb7, 0x8ff6a7}, /* U+82F7 [2000] */ + {0xe88bb9, 0xe7f9}, /* U+82F9 */ + {0xe88bba, 0xe7f5}, /* U+82FA */ + {0xe88bbb, 0xe7f8}, /* U+82FB */ + {0xe88bbd, 0xfae9}, /* U+82FD [2000] */ + {0xe88bbe, 0xfaea}, /* U+82FE [2000] */ + {0xe88c80, 0xfaeb}, /* U+8300 [2000] */ + {0xe88c81, 0xfaec}, /* U+8301 [2000] */ + {0xe88c82, 0xccd0}, /* U+8302 */ + {0xe88c83, 0xe7f7}, /* U+8303 */ + {0xe88c84, 0xb2d8}, /* U+8304 */ + {0xe88c85, 0xb3fd}, /* U+8305 */ + {0xe88c86, 0xe7fb}, /* U+8306 */ + {0xe88c87, 0x8ff6a8}, /* U+8307 [2000] */ + {0xe88c88, 0x8ff6a9}, /* U+8308 [2000] */ + {0xe88c89, 0xe7fd}, /* U+8309 */ + {0xe88c8c, 0x8ff6aa}, /* U+830C [2000] */ + {0xe88c8e, 0xb7d4}, /* U+830E */ + {0xe88c96, 0xe8a3}, /* U+8316 */ + {0xe88c97, 0xe8ac}, /* U+8317 */ + {0xe88c98, 0xe8ad}, /* U+8318 */ + {0xe88c9b, 0x8ff6ac}, /* U+831B [2000] */ + {0xe88c9c, 0xb0ab}, /* U+831C */ + {0xe88c9d, 0x8ff6ad}, /* U+831D [2000] */ + {0xe88ca2, 0xfaee}, /* U+8322 [2000] */ + {0xe88ca3, 0xe8b4}, /* U+8323 */ + {0xe88ca8, 0xb0f1}, /* U+8328 */ + {0xe88cab, 0xe8ab}, /* U+832B */ + {0xe88cad, 0xfaef}, /* U+832D [2000] */ + {0xe88caf, 0xe8aa}, /* U+832F */ + {0xe88cb0, 0x8ff6ae}, /* U+8330 [2000] */ + {0xe88cb1, 0xe8a5}, /* U+8331 */ + {0xe88cb2, 0xe8a4}, /* U+8332 */ + {0xe88cb4, 0xe8a2}, /* U+8334 */ + {0xe88cb5, 0xe8a1}, /* U+8335 */ + {0xe88cb6, 0xc3e3}, /* U+8336 */ + {0xe88cb8, 0xc2fb}, /* U+8338 */ + {0xe88cb9, 0xe8a7}, /* U+8339 */ + {0xe88cba, 0xfaf0}, /* U+833A [2000] */ + {0xe88cbc, 0x8ff6af}, /* U+833C [2000] */ + {0xe88d80, 0xe8a6}, /* U+8340 */ + {0xe88d83, 0xfaf1}, /* U+8343 [2000] */ + {0xe88d84, 0x8ff6b0}, /* U+8344 [2000] */ + {0xe88d85, 0xe8a9}, /* U+8345 */ + {0xe88d87, 0xfaf2}, /* U+8347 [2000] */ + {0xe88d89, 0xc1f0}, /* U+8349 */ + {0xe88d8a, 0xb7d5}, /* U+834A */ + {0xe88d8f, 0xb1c1}, /* U+834F */ + {0xe88d90, 0xe8a8}, /* U+8350 */ + {0xe88d91, 0xfaf3}, /* U+8351 [2000] */ + {0xe88d92, 0xb9d3}, /* U+8352 */ + {0xe88d94, 0x8ff6ab}, /* U+8354 [2000] */ + {0xe88d95, 0xfaf4}, /* U+8355 [2000] */ + {0xe88d97, 0x8ff6b1}, /* U+8357 [2000] */ + {0xe88d98, 0xc1f1}, /* U+8358 */ + {0xe88da2, 0xfaed}, /* U+8362 [2000] */ + {0xe88da3, 0x8faeca}, /* U+8363 [2000] */ + {0xe88db3, 0xe8ba}, /* U+8373 */ + {0xe88db5, 0xe8bb}, /* U+8375 */ + {0xe88db7, 0xb2d9}, /* U+8377 */ + {0xe88dbb, 0xb2ae}, /* U+837B */ + {0xe88dbc, 0xe8b8}, /* U+837C */ + {0xe88dbd, 0xfaf5}, /* U+837D [2000] */ + {0xe88dbf, 0x8ff6b3}, /* U+837F [2000] */ + {0xe88e85, 0xe8ae}, /* U+8385 */ + {0xe88e86, 0xfaf6}, /* U+8386 [2000] */ + {0xe88e87, 0xe8b6}, /* U+8387 */ + {0xe88e89, 0xe8bd}, /* U+8389 */ + {0xe88e8a, 0xe8b7}, /* U+838A */ + {0xe88e8d, 0x8ff6b6}, /* U+838D [2000] */ + {0xe88e8e, 0xe8b5}, /* U+838E */ + {0xe88e92, 0xfaf7}, /* U+8392 [2000] */ + {0xe88e93, 0xe7f6}, /* U+8393 */ + {0xe88e94, 0x8ff6b7}, /* U+8394 [2000] */ + {0xe88e95, 0x8ff6b8}, /* U+8395 [2000] */ + {0xe88e96, 0xe8b3}, /* U+8396 */ + {0xe88e98, 0xfaf8}, /* U+8398 [2000] */ + {0xe88e9a, 0xe8af}, /* U+839A */ + {0xe88e9b, 0x8ff6b9}, /* U+839B [2000] */ + {0xe88e9d, 0x8ff6ba}, /* U+839D [2000] */ + {0xe88e9e, 0xb4d0}, /* U+839E */ + {0xe88e9f, 0xe8b1}, /* U+839F */ + {0xe88ea0, 0xe8bc}, /* U+83A0 */ + {0xe88ea2, 0xe8b2}, /* U+83A2 */ + {0xe88ea7, 0xfaf9}, /* U+83A7 [2000] */ + {0xe88ea8, 0xe8be}, /* U+83A8 */ + {0xe88ea9, 0xfafa}, /* U+83A9 [2000] */ + {0xe88eaa, 0xe8b0}, /* U+83AA */ + {0xe88eab, 0xc7fc}, /* U+83AB */ + {0xe88eb1, 0xcde9}, /* U+83B1 */ + {0xe88eb5, 0xe8b9}, /* U+83B5 */ + {0xe88ebd, 0xe8cf}, /* U+83BD */ + {0xe88ebf, 0xfafb}, /* U+83BF [2000] */ + {0xe88f80, 0xfafc}, /* U+83C0 [2000] */ + {0xe88f81, 0xe8c7}, /* U+83C1 */ + {0xe88f85, 0xbffb}, /* U+83C5 */ + {0xe88f87, 0xfafd}, /* U+83C7 [2000] */ + {0xe88f89, 0x8ff6bb}, /* U+83C9 [2000] */ + {0xe88f8a, 0xb5c6}, /* U+83CA */ + {0xe88f8c, 0xb6dd}, /* U+83CC */ + {0xe88f8e, 0xe8c2}, /* U+83CE */ + {0xe88f8f, 0xfafe}, /* U+83CF [2000] */ + {0xe88f90, 0x8ff6bc}, /* U+83D0 [2000] */ + {0xe88f91, 0xfba1}, /* U+83D1 [2000] */ + {0xe88f93, 0xb2db}, /* U+83D3 */ + {0xe88f94, 0x8ff6bd}, /* U+83D4 [2000] */ + {0xe88f96, 0xbed4}, /* U+83D6 */ + {0xe88f98, 0xe8c5}, /* U+83D8 */ + {0xe88f9c, 0xbada}, /* U+83DC */ + {0xe88f9d, 0x8ff6be}, /* U+83DD [2000] */ + {0xe88f9f, 0xc5d1}, /* U+83DF */ + {0xe88fa0, 0xe8ca}, /* U+83E0 */ + {0xe88fa1, 0xfba2}, /* U+83E1 [2000] */ + {0xe88fa5, 0x8ff6bf}, /* U+83E5 [2000] */ + {0xe88fa9, 0xcaee}, /* U+83E9 */ + {0xe88faa, 0xfba3}, /* U+83EA [2000] */ + {0xe88fab, 0xe8c1}, /* U+83EB */ + {0xe88faf, 0xb2da}, /* U+83EF */ + {0xe88fb0, 0xb8d6}, /* U+83F0 */ + {0xe88fb1, 0xc9a9}, /* U+83F1 */ + {0xe88fb2, 0xe8cb}, /* U+83F2 */ + {0xe88fb4, 0xe8bf}, /* U+83F4 */ + {0xe88fb7, 0xe8c8}, /* U+83F7 */ + {0xe88fb9, 0x8ff6c0}, /* U+83F9 [2000] */ + {0xe88fbb, 0xe8d2}, /* U+83FB */ + {0xe88fbd, 0xe8c3}, /* U+83FD */ + {0xe89081, 0xfba4}, /* U+8401 [2000] */ + {0xe89083, 0xe8c4}, /* U+8403 */ + {0xe89084, 0xc6ba}, /* U+8404 */ + {0xe89086, 0xfba5}, /* U+8406 [2000] */ + {0xe89087, 0xe8c9}, /* U+8407 */ + {0xe8908a, 0xfba6}, /* U+840A [2000] */ + {0xe8908b, 0xe8c6}, /* U+840B */ + {0xe8908c, 0xcba8}, /* U+840C */ + {0xe8908d, 0xe8cc}, /* U+840D */ + {0xe8908e, 0xb0e0}, /* U+840E */ + {0xe8908f, 0x8ff6c1}, /* U+840F [2000] */ + {0xe89091, 0x8ff6c2}, /* U+8411 [2000] */ + {0xe89093, 0xe8c0}, /* U+8413 */ + {0xe89095, 0x8ff6c3}, /* U+8415 [2000] */ + {0xe89097, 0x8ff6c5}, /* U+8417 [2000] */ + {0xe890a0, 0xe8ce}, /* U+8420 */ + {0xe890a2, 0xe8cd}, /* U+8422 */ + {0xe890a9, 0xc7eb}, /* U+8429 */ + {0xe890aa, 0xe8d4}, /* U+842A */ + {0xe890ac, 0xe8df}, /* U+842C */ + {0xe890b1, 0xb3fe}, /* U+8431 */ + {0xe890b5, 0xe8e2}, /* U+8435 */ + {0xe890b8, 0xe8d0}, /* U+8438 */ + {0xe890b9, 0x8ff6c6}, /* U+8439 [2000] */ + {0xe890bc, 0xe8d5}, /* U+843C */ + {0xe890bd, 0xcdee}, /* U+843D */ + {0xe89186, 0xe8de}, /* U+8446 */ + {0xe89188, 0xfba8}, /* U+8448 [2000] */ + {0xe89189, 0xcdd5}, /* U+8449 */ + {0xe8918a, 0x8ff6c7}, /* U+844A [2000] */ + {0xe8918e, 0xceaa}, /* U+844E */ + {0xe8918f, 0x8ff6c8}, /* U+844F [2000] */ + {0xe89191, 0x8ff6c9}, /* U+8451 [2000] */ + {0xe89192, 0x8ff6ca}, /* U+8452 [2000] */ + {0xe89197, 0xc3f8}, /* U+8457 */ + {0xe89199, 0x8ff6cb}, /* U+8459 [2000] */ + {0xe8919a, 0x8ff6cc}, /* U+845A [2000] */ + {0xe8919b, 0xb3eb}, /* U+845B */ + {0xe8919c, 0x8ff6cd}, /* U+845C [2000] */ + {0xe8919f, 0xfba9}, /* U+845F [2000] */ + {0xe891a1, 0xc9f2}, /* U+8461 */ + {0xe891a2, 0xe8e4}, /* U+8462 */ + {0xe891a3, 0xc6a1}, /* U+8463 */ + {0xe891a5, 0x8ff6cf}, /* U+8465 [2000] */ + {0xe891a6, 0xb0b1}, /* U+8466 */ + {0xe891a9, 0xe8dd}, /* U+8469 */ + {0xe891ab, 0xe8d9}, /* U+846B */ + {0xe891ac, 0xc1f2}, /* U+846C */ + {0xe891ad, 0xe8d3}, /* U+846D */ + {0xe891ae, 0xe8db}, /* U+846E */ + {0xe891af, 0xe8e0}, /* U+846F */ + {0xe891b0, 0xfbaa}, /* U+8470 [2000] */ + {0xe891b1, 0xc7ac}, /* U+8471 */ + {0xe891b3, 0xfbab}, /* U+8473 [2000] */ + {0xe891b5, 0xb0aa}, /* U+8475 */ + {0xe891b6, 0x8ff6d0}, /* U+8476 [2000] */ + {0xe891b7, 0xe8d8}, /* U+8477 */ + {0xe891b8, 0x8ff6d1}, /* U+8478 [2000] */ + {0xe891b9, 0xe8e1}, /* U+8479 */ + {0xe891ba, 0xc9f8}, /* U+847A */ + {0xe891bc, 0x8ff6d2}, /* U+847C [2000] */ + {0xe89281, 0x8ff6d3}, /* U+8481 [2000] */ + {0xe89282, 0xe8dc}, /* U+8482 */ + {0xe89284, 0xe8d7}, /* U+8484 */ + {0xe89285, 0xfbac}, /* U+8485 [2000] */ + {0xe8928b, 0xbed5}, /* U+848B */ + {0xe89290, 0xbdaf}, /* U+8490 */ + {0xe89294, 0xbcac}, /* U+8494 */ + {0xe89297, 0x8ff6d6}, /* U+8497 [2000] */ + {0xe89299, 0xccd8}, /* U+8499 */ + {0xe8929c, 0xc9c7}, /* U+849C */ + {0xe8929e, 0xfbad}, /* U+849E [2000] */ + {0xe8929f, 0xe8e7}, /* U+849F */ + {0xe892a1, 0xe8f0}, /* U+84A1 */ + {0xe892a6, 0x8ff6d7}, /* U+84A6 [2000] */ + {0xe892ad, 0xe8da}, /* U+84AD */ + {0xe892af, 0xfbae}, /* U+84AF [2000] */ + {0xe892b2, 0xb3f7}, /* U+84B2 */ + {0xe892b4, 0xfbaf}, /* U+84B4 [2000] */ + {0xe892b8, 0xbef8}, /* U+84B8 */ + {0xe892b9, 0xe8e5}, /* U+84B9 */ + {0xe892ba, 0xfbb0}, /* U+84BA [2000] */ + {0xe892bb, 0xe8ea}, /* U+84BB */ + {0xe892bc, 0xc1f3}, /* U+84BC */ + {0xe892be, 0x8ff6d8}, /* U+84BE [2000] */ + {0xe892bf, 0xe8e6}, /* U+84BF */ + {0xe89380, 0xfbb1}, /* U+84C0 [2000] */ + {0xe89381, 0xe8ed}, /* U+84C1 */ + {0xe89382, 0xfbb2}, /* U+84C2 [2000] */ + {0xe89384, 0xc3df}, /* U+84C4 */ + {0xe89386, 0xe8ee}, /* U+84C6 */ + {0xe89389, 0xcdd6}, /* U+84C9 */ + {0xe8938a, 0xe8e3}, /* U+84CA */ + {0xe8938b, 0xb3b8}, /* U+84CB */ + {0xe8938d, 0xe8e9}, /* U+84CD */ + {0xe8938e, 0x8ff6da}, /* U+84CE [2000] */ + {0xe8938f, 0x8ff6db}, /* U+84CF [2000] */ + {0xe89390, 0xe8ec}, /* U+84D0 */ + {0xe89391, 0xccac}, /* U+84D1 */ + {0xe89393, 0x8ff6dc}, /* U+84D3 [2000] */ + {0xe89396, 0xe8ef}, /* U+84D6 */ + {0xe89399, 0xe8e8}, /* U+84D9 */ + {0xe8939a, 0xe8eb}, /* U+84DA */ + {0xe8939c, 0x8ff6d5}, /* U+84DC [2000] */ + {0xe893a7, 0x8ff6de}, /* U+84E7 [2000] */ + {0xe893aa, 0x8ff6df}, /* U+84EA [2000] */ + {0xe893ac, 0xcba9}, /* U+84EC */ + {0xe893ae, 0xcfa1}, /* U+84EE */ + {0xe893af, 0x8ff6e0}, /* U+84EF [2000] */ + {0xe893b0, 0x8ff6e1}, /* U+84F0 [2000] */ + {0xe893b1, 0x8ff6e2}, /* U+84F1 [2000] */ + {0xe893b4, 0xe8f3}, /* U+84F4 */ + {0xe893ba, 0x8ff6e3}, /* U+84FA [2000] */ + {0xe893bc, 0xe8fa}, /* U+84FC */ + {0xe893bd, 0x8ff6e4}, /* U+84FD [2000] */ + {0xe893bf, 0xe8f2}, /* U+84FF */ + {0xe89480, 0xbcc3}, /* U+8500 */ + {0xe89486, 0xe8d1}, /* U+8506 */ + {0xe8948c, 0x8ff6e5}, /* U+850C [2000] */ + {0xe89491, 0xcace}, /* U+8511 */ + {0xe89493, 0xcca2}, /* U+8513 */ + {0xe89494, 0xe8f9}, /* U+8514 */ + {0xe89495, 0xe8f8}, /* U+8515 */ + {0xe89497, 0xe8f4}, /* U+8517 */ + {0xe89498, 0xe8f5}, /* U+8518 */ + {0xe8949a, 0xb1b6}, /* U+851A */ + {0xe8949b, 0x8ff6e6}, /* U+851B [2000] */ + {0xe8949e, 0xfbb5}, /* U+851E [2000] */ + {0xe8949f, 0xe8f7}, /* U+851F */ + {0xe894a1, 0xe8f1}, /* U+8521 */ + {0xe894a3, 0xfbb6}, /* U+8523 [2000] */ + {0xe894a4, 0x8ff6e7}, /* U+8524 [2000] */ + {0xe894a5, 0x8ff6e8}, /* U+8525 [2000] */ + {0xe894a6, 0xc4d5}, /* U+8526 */ + {0xe894ab, 0x8ff6e9}, /* U+852B [2000] */ + {0xe894ac, 0xe8f6}, /* U+852C */ + {0xe894ad, 0xb0fe}, /* U+852D */ + {0xe894af, 0xfbb7}, /* U+852F [2000] */ + {0xe894b2, 0xfbb4}, /* U+8532 [2000] */ + {0xe894b4, 0x8ff6ea}, /* U+8534 [2000] */ + {0xe894b5, 0xc2a2}, /* U+8535 */ + {0xe894bd, 0xcac3}, /* U+853D */ + {0xe894be, 0x8ff6ef}, /* U+853E [2000] */ + {0xe89580, 0xe8fb}, /* U+8540 */ + {0xe89581, 0xe9a1}, /* U+8541 */ + {0xe89583, 0xc8d9}, /* U+8543 */ + {0xe89588, 0xe8fe}, /* U+8548 */ + {0xe89589, 0xbed6}, /* U+8549 */ + {0xe8958a, 0xbcc9}, /* U+854A */ + {0xe8958b, 0xe9a3}, /* U+854B */ + {0xe8958e, 0xb6be}, /* U+854E */ + {0xe8958f, 0x8ff6eb}, /* U+854F [2000] */ + {0xe89591, 0x8ff6f0}, /* U+8551 [2000] */ + {0xe89593, 0x8ff6f1}, /* U+8553 [2000] */ + {0xe89595, 0xe9a4}, /* U+8555 */ + {0xe89597, 0xc9f9}, /* U+8557 */ + {0xe89598, 0xe8fd}, /* U+8558 */ + {0xe89599, 0xfbb8}, /* U+8559 [2000] */ + {0xe8959a, 0xe8d6}, /* U+855A */ + {0xe8959e, 0x8ff6f2}, /* U+855E [2000] */ + {0xe895a1, 0x8ff6f3}, /* U+8561 [2000] */ + {0xe895a2, 0x8ff6f4}, /* U+8562 [2000] */ + {0xe895a3, 0xe8fc}, /* U+8563 */ + {0xe895a4, 0xfbb9}, /* U+8564 [2000] */ + {0xe895a8, 0xcfcf}, /* U+8568 */ + {0xe895a9, 0xc6a2}, /* U+8569 */ + {0xe895aa, 0xc9f3}, /* U+856A */ + {0xe895ad, 0xe9ab}, /* U+856D */ + {0xe895af, 0x8ff6ec}, /* U+856F [2000] */ + {0xe895b7, 0xe9b1}, /* U+8577 */ + {0xe895ba, 0xfbbc}, /* U+857A [2000] */ + {0xe895bb, 0x8ff6f6}, /* U+857B [2000] */ + {0xe895bd, 0x8ff6f7}, /* U+857D [2000] */ + {0xe895be, 0xe9b2}, /* U+857E */ + {0xe895bf, 0x8ff6f8}, /* U+857F [2000] */ + {0xe89680, 0xe9a5}, /* U+8580 */ + {0xe89681, 0x8ff6f9}, /* U+8581 [2000] */ + {0xe89684, 0xc7f6}, /* U+8584 */ + {0xe89686, 0x8ff6fa}, /* U+8586 [2000] */ + {0xe89687, 0xe9af}, /* U+8587 */ + {0xe89688, 0xe9a7}, /* U+8588 */ + {0xe8968a, 0xe9a9}, /* U+858A */ + {0xe8968c, 0xfbbd}, /* U+858C [2000] */ + {0xe8968f, 0xfbbe}, /* U+858F [2000] */ + {0xe89690, 0xe9b3}, /* U+8590 */ + {0xe89691, 0xe9a8}, /* U+8591 */ + {0xe89693, 0x8ff6fb}, /* U+8593 [2000] */ + {0xe89694, 0xe9ac}, /* U+8594 */ + {0xe89697, 0xb1f2}, /* U+8597 */ + {0xe89699, 0xc6e5}, /* U+8599 */ + {0xe8969b, 0xe9ad}, /* U+859B */ + {0xe8969c, 0xe9b0}, /* U+859C */ + {0xe8969d, 0x8ff6fc}, /* U+859D [2000] */ + {0xe8969f, 0x8ff6fd}, /* U+859F [2000] */ + {0xe896a2, 0xfbbf}, /* U+85A2 [2000] */ + {0xe896a4, 0xe9a6}, /* U+85A4 */ + {0xe896a6, 0xc1a6}, /* U+85A6 */ + {0xe896a8, 0xe9aa}, /* U+85A8 */ + {0xe896a9, 0xbba7}, /* U+85A9 */ + {0xe896aa, 0xbfc5}, /* U+85AA */ + {0xe896ab, 0xb7b0}, /* U+85AB */ + {0xe896ac, 0xccf4}, /* U+85AC */ + {0xe896ad, 0xfbbb}, /* U+85AD [2000] */ + {0xe896ae, 0xccf9}, /* U+85AE */ + {0xe896af, 0xbdf2}, /* U+85AF */ + {0xe896b0, 0xfbc0}, /* U+85B0 [2000] */ + {0xe896b7, 0x8ff7a3}, /* U+85B7 [2000] */ + {0xe896b9, 0xe9b7}, /* U+85B9 */ + {0xe896ba, 0xe9b5}, /* U+85BA */ + {0xe896bc, 0x8ff7a4}, /* U+85BC [2000] */ + {0xe89781, 0xcfce}, /* U+85C1 */ + {0xe89787, 0x8ff7a5}, /* U+85C7 [2000] */ + {0xe89789, 0xe9b4}, /* U+85C9 */ + {0xe8978a, 0x8ff7a6}, /* U+85CA [2000] */ + {0xe8978b, 0xfbc1}, /* U+85CB [2000] */ + {0xe8978d, 0xcdf5}, /* U+85CD */ + {0xe8978e, 0xfbc2}, /* U+85CE [2000] */ + {0xe8978f, 0xe9b6}, /* U+85CF */ + {0xe89790, 0xe9b8}, /* U+85D0 */ + {0xe89795, 0xe9b9}, /* U+85D5 */ + {0xe89798, 0x8ff7a7}, /* U+85D8 [2000] */ + {0xe89799, 0x8ff7a8}, /* U+85D9 [2000] */ + {0xe8979c, 0xe9bc}, /* U+85DC */ + {0xe8979d, 0xe9ba}, /* U+85DD */ + {0xe8979f, 0x8ff7a9}, /* U+85DF [2000] */ + {0xe897a1, 0x8ff7aa}, /* U+85E1 [2000] */ + {0xe897a4, 0xc6a3}, /* U+85E4 */ + {0xe897a5, 0xe9bb}, /* U+85E5 */ + {0xe897a6, 0x8ff7ab}, /* U+85E6 [2000] */ + {0xe897a9, 0xc8cd}, /* U+85E9 */ + {0xe897aa, 0xe9ae}, /* U+85EA */ + {0xe897ad, 0xfbc3}, /* U+85ED [2000] */ + {0xe897b6, 0x8ff7ac}, /* U+85F6 [2000] */ + {0xe897b7, 0xbdf3}, /* U+85F7 */ + {0xe897b9, 0xe9bd}, /* U+85F9 */ + {0xe897ba, 0xe9c2}, /* U+85FA */ + {0xe897bb, 0xc1f4}, /* U+85FB */ + {0xe897be, 0xe9c1}, /* U+85FE */ + {0xe897bf, 0xfbc5}, /* U+85FF [2000] */ + {0xe89880, 0x8ff7ad}, /* U+8600 [2000] */ + {0xe89882, 0xe9a2}, /* U+8602 */ + {0xe89884, 0xfbc6}, /* U+8604 [2000] */ + {0xe89885, 0xfbc7}, /* U+8605 [2000] */ + {0xe89886, 0xe9c3}, /* U+8606 */ + {0xe89887, 0xc1c9}, /* U+8607 */ + {0xe8988a, 0xe9be}, /* U+860A */ + {0xe8988b, 0xe9c0}, /* U+860B */ + {0xe89890, 0xfbc8}, /* U+8610 [2000] */ + {0xe89891, 0x8ff7ae}, /* U+8611 [2000] */ + {0xe89892, 0xfbc4}, /* U+8612 [2000] */ + {0xe89893, 0xe9bf}, /* U+8613 */ + {0xe89896, 0xddb1}, /* U+8616 */ + {0xe89897, 0xdda2}, /* U+8617 */ + {0xe89898, 0xfbca}, /* U+8618 [2000] */ + {0xe8989a, 0xe9c5}, /* U+861A */ + {0xe8989e, 0x8ff7af}, /* U+861E [2000] */ + {0xe898a1, 0x8ff7b0}, /* U+8621 [2000] */ + {0xe898a2, 0xe9c4}, /* U+8622 */ + {0xe898a4, 0x8ff7b1}, /* U+8624 [2000] */ + {0xe898a7, 0x8ff7b2}, /* U+8627 [2000] */ + {0xe898a9, 0xfbcb}, /* U+8629 [2000] */ + {0xe898ad, 0xcdf6}, /* U+862D */ + {0xe898af, 0xe2bc}, /* U+862F */ + {0xe898b0, 0xe9c6}, /* U+8630 */ + {0xe898b8, 0xfbcc}, /* U+8638 [2000] */ + {0xe898b9, 0x8ff7b4}, /* U+8639 [2000] */ + {0xe898bc, 0x8ff7b5}, /* U+863C [2000] */ + {0xe898bf, 0xe9c7}, /* U+863F */ + {0xe89980, 0x8ff7b7}, /* U+8640 [2000] */ + {0xe89981, 0xafe8}, /* U+8641 [2000] */ + {0xe8998d, 0xe9c8}, /* U+864D */ + {0xe8998e, 0xb8d7}, /* U+864E */ + {0xe89990, 0xb5d4}, /* U+8650 */ + {0xe89993, 0x8ff7b9}, /* U+8653 [2000] */ + {0xe89994, 0xe9ca}, /* U+8654 */ + {0xe89995, 0xd1dd}, /* U+8655 */ + {0xe89996, 0x8ff7ba}, /* U+8656 [2000] */ + {0xe89997, 0xfbcd}, /* U+8657 [2000] */ + {0xe8999a, 0xb5f5}, /* U+865A */ + {0xe8999b, 0xfbce}, /* U+865B [2000] */ + {0xe8999c, 0xceba}, /* U+865C */ + {0xe8999e, 0xb6f3}, /* U+865E */ + {0xe8999f, 0xe9cb}, /* U+865F */ + {0xe899a2, 0xfbd0}, /* U+8662 [2000] */ + {0xe899a7, 0xe9cc}, /* U+8667 */ + {0xe899ab, 0xc3ee}, /* U+866B */ + {0xe899ac, 0xfbd2}, /* U+866C [2000] */ + {0xe899af, 0x8ff7bb}, /* U+866F [2000] */ + {0xe899b1, 0xe9cd}, /* U+8671 */ + {0xe899b5, 0xfbd3}, /* U+8675 [2000] */ + {0xe899b7, 0x8ff7bc}, /* U+8677 [2000] */ + {0xe899b9, 0xc6fa}, /* U+8679 */ + {0xe899ba, 0x8ff7bd}, /* U+867A [2000] */ + {0xe899bb, 0xb0ba}, /* U+867B */ + {0xe89a87, 0x8ff7be}, /* U+8687 [2000] */ + {0xe89a89, 0x8ff7bf}, /* U+8689 [2000] */ + {0xe89a8a, 0xb2e3}, /* U+868A */ + {0xe89a8b, 0xe9d2}, /* U+868B */ + {0xe89a8c, 0xe9d3}, /* U+868C */ + {0xe89a8d, 0x8ff7c0}, /* U+868D [2000] */ + {0xe89a91, 0x8ff7c1}, /* U+8691 [2000] */ + {0xe89a93, 0xe9ce}, /* U+8693 */ + {0xe89a95, 0xbbbd}, /* U+8695 */ + {0xe89a98, 0xfbd4}, /* U+8698 [2000] */ + {0xe89a9c, 0x8ff7c2}, /* U+869C [2000] */ + {0xe89a9d, 0x8ff7c3}, /* U+869D [2000] */ + {0xe89aa3, 0xe9cf}, /* U+86A3 */ + {0xe89aa4, 0xc7c2}, /* U+86A4 */ + {0xe89aa8, 0x8ff7c4}, /* U+86A8 [2000] */ + {0xe89aa9, 0xe9d0}, /* U+86A9 */ + {0xe89aaa, 0xe9d1}, /* U+86AA */ + {0xe89aab, 0xe9db}, /* U+86AB */ + {0xe89aaf, 0xe9d5}, /* U+86AF */ + {0xe89ab0, 0xe9d8}, /* U+86B0 */ + {0xe89ab1, 0x8ff7c6}, /* U+86B1 [2000] */ + {0xe89ab3, 0x8ff7c7}, /* U+86B3 [2000] */ + {0xe89ab6, 0xe9d4}, /* U+86B6 */ + {0xe89ab8, 0xfbd5}, /* U+86B8 [2000] */ + {0xe89b81, 0x8ff7c8}, /* U+86C1 [2000] */ + {0xe89b83, 0x8ff7c9}, /* U+86C3 [2000] */ + {0xe89b84, 0xe9d6}, /* U+86C4 */ + {0xe89b86, 0xe9d7}, /* U+86C6 */ + {0xe89b87, 0xbcd8}, /* U+86C7 */ + {0xe89b89, 0xe9d9}, /* U+86C9 */ + {0xe89b8b, 0xc3c1}, /* U+86CB */ + {0xe89b8d, 0xb7d6}, /* U+86CD */ + {0xe89b8e, 0xb3c2}, /* U+86CE */ + {0xe89b91, 0x8ff7ca}, /* U+86D1 [2000] */ + {0xe89b94, 0xe9dc}, /* U+86D4 */ + {0xe89b95, 0x8ff7cb}, /* U+86D5 [2000] */ + {0xe89b97, 0x8ff7cc}, /* U+86D7 [2000] */ + {0xe89b99, 0xb3bf}, /* U+86D9 */ + {0xe89b9b, 0xe9e1}, /* U+86DB */ + {0xe89b9e, 0xe9dd}, /* U+86DE */ + {0xe89b9f, 0xe9e0}, /* U+86DF */ + {0xe89ba3, 0x8ff7cd}, /* U+86E3 [2000] */ + {0xe89ba4, 0xc8ba}, /* U+86E4 */ + {0xe89ba6, 0x8ff7ce}, /* U+86E6 [2000] */ + {0xe89ba9, 0xe9de}, /* U+86E9 */ + {0xe89bac, 0xe9df}, /* U+86EC */ + {0xe89bad, 0xc9c8}, /* U+86ED */ + {0xe89bae, 0xc8da}, /* U+86EE */ + {0xe89baf, 0xe9e2}, /* U+86EF */ + {0xe89bb8, 0xc2fd}, /* U+86F8 */ + {0xe89bb9, 0xe9ec}, /* U+86F9 */ + {0xe89bba, 0xfbd6}, /* U+86FA [2000] */ + {0xe89bbb, 0xe9e8}, /* U+86FB */ + {0xe89bbc, 0xfbd7}, /* U+86FC [2000] */ + {0xe89bbd, 0xfbd8}, /* U+86FD [2000] */ + {0xe89bbe, 0xb2eb}, /* U+86FE */ + {0xe89c80, 0xe9e6}, /* U+8700 */ + {0xe89c82, 0xcbaa}, /* U+8702 */ + {0xe89c83, 0xe9e7}, /* U+8703 */ + {0xe89c85, 0x8ff7d0}, /* U+8705 [2000] */ + {0xe89c86, 0xe9e4}, /* U+8706 */ + {0xe89c87, 0x8ff7d1}, /* U+8707 [2000] */ + {0xe89c88, 0xe9e5}, /* U+8708 */ + {0xe89c89, 0xe9ea}, /* U+8709 */ + {0xe89c8a, 0xe9ed}, /* U+870A */ + {0xe89c8b, 0xfbd9}, /* U+870B [2000] */ + {0xe89c8d, 0xe9eb}, /* U+870D */ + {0xe89c8e, 0x8ff7d2}, /* U+870E [2000] */ + {0xe89c90, 0x8ff7d3}, /* U+8710 [2000] */ + {0xe89c91, 0xe9e9}, /* U+8711 */ + {0xe89c92, 0xe9e3}, /* U+8712 */ + {0xe89c93, 0x8ff7d4}, /* U+8713 [2000] */ + {0xe89c98, 0xc3d8}, /* U+8718 */ + {0xe89c99, 0x8ff7d5}, /* U+8719 [2000] */ + {0xe89c9a, 0xe9f4}, /* U+871A */ + {0xe89c9c, 0xccaa}, /* U+871C */ + {0xe89c9f, 0x8ff7d6}, /* U+871F [2000] */ + {0xe89ca1, 0x8ff7d7}, /* U+8721 [2000] */ + {0xe89ca3, 0x8ff7d8}, /* U+8723 [2000] */ + {0xe89ca5, 0xe9f2}, /* U+8725 */ + {0xe89ca9, 0xe9f3}, /* U+8729 */ + {0xe89cb1, 0x8ff7d9}, /* U+8731 [2000] */ + {0xe89cb4, 0xe9ee}, /* U+8734 */ + {0xe89cb7, 0xe9f0}, /* U+8737 */ + {0xe89cba, 0x8ff7da}, /* U+873A [2000] */ + {0xe89cbb, 0xe9f1}, /* U+873B */ + {0xe89cbe, 0x8ff7db}, /* U+873E [2000] */ + {0xe89cbf, 0xe9ef}, /* U+873F */ + {0xe89d80, 0x8ff7dc}, /* U+8740 [2000] */ + {0xe89d83, 0x8ff7dd}, /* U+8743 [2000] */ + {0xe89d89, 0xc0e6}, /* U+8749 */ + {0xe89d8b, 0xcfb9}, /* U+874B */ + {0xe89d8c, 0xe9f8}, /* U+874C */ + {0xe89d8e, 0xe9f9}, /* U+874E */ + {0xe89d91, 0x8ff7de}, /* U+8751 [2000] */ + {0xe89d93, 0xeaa1}, /* U+8753 */ + {0xe89d95, 0xbfaa}, /* U+8755 */ + {0xe89d97, 0xe9fb}, /* U+8757 */ + {0xe89d98, 0x8ff7df}, /* U+8758 [2000] */ + {0xe89d99, 0xe9fe}, /* U+8759 */ + {0xe89d9f, 0xe9f6}, /* U+875F */ + {0xe89da0, 0xe9f5}, /* U+8760 */ + {0xe89da3, 0xeaa2}, /* U+8763 */ + {0xe89da4, 0x8ff7e0}, /* U+8764 [2000] */ + {0xe89da5, 0x8ff7e1}, /* U+8765 [2000] */ + {0xe89da6, 0xb2dc}, /* U+8766 */ + {0xe89da8, 0xe9fc}, /* U+8768 */ + {0xe89daa, 0xeaa3}, /* U+876A */ + {0xe89dae, 0xe9fd}, /* U+876E */ + {0xe89db1, 0xfbda}, /* U+8771 [2000] */ + {0xe89db2, 0x8ff7e2}, /* U+8772 [2000] */ + {0xe89db4, 0xe9fa}, /* U+8774 */ + {0xe89db6, 0xc4b3}, /* U+8776 */ + {0xe89db8, 0xe9f7}, /* U+8778 */ + {0xe89dbc, 0x8ff7e3}, /* U+877C [2000] */ + {0xe89dbf, 0xc7e8}, /* U+877F */ + {0xe89e82, 0xeaa7}, /* U+8782 */ + {0xe89e87, 0xfbdb}, /* U+8787 [2000] */ + {0xe89e88, 0xfbdc}, /* U+8788 [2000] */ + {0xe89e89, 0x8ff7e7}, /* U+8789 [2000] */ + {0xe89e8b, 0x8ff7e8}, /* U+878B [2000] */ + {0xe89e8d, 0xcdbb}, /* U+878D */ + {0xe89e93, 0x8ff7e9}, /* U+8793 [2000] */ + {0xe89e9f, 0xeaa6}, /* U+879F */ + {0xe89ea0, 0x8ff7ea}, /* U+87A0 [2000] */ + {0xe89ea2, 0xeaa5}, /* U+87A2 */ + {0xe89ea7, 0x8ff7e6}, /* U+87A7 [2000] */ + {0xe89eab, 0xeaae}, /* U+87AB */ + {0xe89eac, 0xfbdd}, /* U+87AC [2000] */ + {0xe89ead, 0xfbde}, /* U+87AD [2000] */ + {0xe89eaf, 0xeaa8}, /* U+87AF */ + {0xe89eb3, 0xeab0}, /* U+87B3 */ + {0xe89eb5, 0xfbdf}, /* U+87B5 [2000] */ + {0xe89eba, 0xcde6}, /* U+87BA */ + {0xe89ebb, 0xeab3}, /* U+87BB */ + {0xe89ebd, 0xeaaa}, /* U+87BD */ + {0xe89ebe, 0x8ff7ed}, /* U+87BE [2000] */ + {0xe89f80, 0xeaab}, /* U+87C0 */ + {0xe89f81, 0x8ff7ef}, /* U+87C1 [2000] */ + {0xe89f84, 0xeaaf}, /* U+87C4 */ + {0xe89f86, 0xeab2}, /* U+87C6 */ + {0xe89f87, 0xeab1}, /* U+87C7 */ + {0xe89f8b, 0xeaa9}, /* U+87CB */ + {0xe89f8e, 0x8ff7f0}, /* U+87CE [2000] */ + {0xe89f90, 0xeaac}, /* U+87D0 */ + {0xe89f92, 0xeabd}, /* U+87D2 */ + {0xe89f96, 0xfbe1}, /* U+87D6 [2000] */ + {0xe89f9f, 0x8ff7f2}, /* U+87DF [2000] */ + {0xe89fa0, 0xeab6}, /* U+87E0 */ + {0xe89fa3, 0x8ff7f4}, /* U+87E3 [2000] */ + {0xe89fa5, 0x8ff7f5}, /* U+87E5 [2000] */ + {0xe89fa6, 0x8ff7f6}, /* U+87E6 [2000] */ + {0xe89faa, 0x8ff7f7}, /* U+87EA [2000] */ + {0xe89fab, 0x8ff7f8}, /* U+87EB [2000] */ + {0xe89fac, 0xfbe2}, /* U+87EC [2000] */ + {0xe89fad, 0x8ff7f9}, /* U+87ED [2000] */ + {0xe89faf, 0xeab4}, /* U+87EF */ + {0xe89fb2, 0xeab5}, /* U+87F2 */ + {0xe89fb5, 0x8ff7f1}, /* U+87F5 [2000] */ + {0xe89fb6, 0xeaba}, /* U+87F6 */ + {0xe89fb7, 0xeabb}, /* U+87F7 */ + {0xe89fb9, 0xb3aa}, /* U+87F9 */ + {0xe89fbb, 0xb5c2}, /* U+87FB */ + {0xe89fbe, 0xeab9}, /* U+87FE */ + {0xe8a081, 0x8ff7fa}, /* U+8801 [2000] */ + {0xe8a083, 0x8ff7fb}, /* U+8803 [2000] */ + {0xe8a085, 0xeaa4}, /* U+8805 */ + {0xe8a086, 0xfbe3}, /* U+8806 [2000] */ + {0xe8a08a, 0xfbe4}, /* U+880A [2000] */ + {0xe8a08b, 0x8ff7fc}, /* U+880B [2000] */ + {0xe8a08d, 0xeab8}, /* U+880D */ + {0xe8a08e, 0xeabc}, /* U+880E */ + {0xe8a08f, 0xeab7}, /* U+880F */ + {0xe8a090, 0xfbe5}, /* U+8810 [2000] */ + {0xe8a091, 0xeabe}, /* U+8811 */ + {0xe8a093, 0x8ff7fd}, /* U+8813 [2000] */ + {0xe8a094, 0xfbe6}, /* U+8814 [2000] */ + {0xe8a095, 0xeac0}, /* U+8815 */ + {0xe8a096, 0xeabf}, /* U+8816 */ + {0xe8a09f, 0xfbe7}, /* U+881F [2000] */ + {0xe8a0a1, 0xeac2}, /* U+8821 */ + {0xe8a0a2, 0xeac1}, /* U+8822 */ + {0xe8a0a3, 0xe9da}, /* U+8823 */ + {0xe8a0a7, 0xeac6}, /* U+8827 */ + {0xe8a0a8, 0x8ff7fe}, /* U+8828 [2000] */ + {0xe8a0ae, 0x8ff8a1}, /* U+882E [2000] */ + {0xe8a0b1, 0xeac3}, /* U+8831 */ + {0xe8a0b2, 0x8ff8a2}, /* U+8832 [2000] */ + {0xe8a0b6, 0xeac4}, /* U+8836 */ + {0xe8a0b9, 0xeac5}, /* U+8839 */ + {0xe8a0bb, 0xeac7}, /* U+883B */ + {0xe8a0bc, 0x8ff8a3}, /* U+883C [2000] */ + {0xe8a180, 0xb7ec}, /* U+8840 */ + {0xe8a182, 0xeac9}, /* U+8842 */ + {0xe8a184, 0xeac8}, /* U+8844 */ + {0xe8a186, 0xbdb0}, /* U+8846 */ + {0xe8a18a, 0x8ff8a5}, /* U+884A [2000] */ + {0xe8a18c, 0xb9d4}, /* U+884C */ + {0xe8a18d, 0xdea7}, /* U+884D */ + {0xe8a192, 0xeaca}, /* U+8852 */ + {0xe8a193, 0xbdd1}, /* U+8853 */ + {0xe8a197, 0xb3b9}, /* U+8857 */ + {0xe8a198, 0x8ff8a6}, /* U+8858 [2000] */ + {0xe8a199, 0xeacb}, /* U+8859 */ + {0xe8a19b, 0xb1d2}, /* U+885B */ + {0xe8a19d, 0xbed7}, /* U+885D */ + {0xe8a19e, 0xeacc}, /* U+885E */ + {0xe8a19f, 0x8ff8a7}, /* U+885F [2000] */ + {0xe8a1a1, 0xb9d5}, /* U+8861 */ + {0xe8a1a2, 0xeacd}, /* U+8862 */ + {0xe8a1a3, 0xb0e1}, /* U+8863 */ + {0xe8a1a4, 0x8ff8a8}, /* U+8864 [2000] */ + {0xe8a1a8, 0xc9bd}, /* U+8868 */ + {0xe8a1a9, 0x8ff8ab}, /* U+8869 [2000] */ + {0xe8a1ab, 0xeace}, /* U+886B */ + {0xe8a1af, 0x8ff8ad}, /* U+886F [2000] */ + {0xe8a1b0, 0xbfea}, /* U+8870 */ + {0xe8a1b2, 0xead5}, /* U+8872 */ + {0xe8a1b5, 0xead2}, /* U+8875 */ + {0xe8a1b7, 0xc3ef}, /* U+8877 */ + {0xe8a1bd, 0xead3}, /* U+887D */ + {0xe8a1be, 0xead0}, /* U+887E */ + {0xe8a1bf, 0xb6de}, /* U+887F */ + {0xe8a281, 0xeacf}, /* U+8881 */ + {0xe8a282, 0xead6}, /* U+8882 */ + {0xe8a288, 0xb7b6}, /* U+8888 */ + {0xe8a28b, 0xc2de}, /* U+888B */ + {0xe8a28d, 0xeadc}, /* U+888D */ + {0xe8a292, 0xead8}, /* U+8892 */ + {0xe8a296, 0xc2b5}, /* U+8896 */ + {0xe8a297, 0xead7}, /* U+8897 */ + {0xe8a298, 0xfbe8}, /* U+8898 [2000] */ + {0xe8a299, 0xeada}, /* U+8899 */ + {0xe8a29e, 0xead1}, /* U+889E */ + {0xe8a2a0, 0x8ff8ae}, /* U+88A0 [2000] */ + {0xe8a2a2, 0xeadb}, /* U+88A2 */ + {0xe8a2a4, 0xeadd}, /* U+88A4 */ + {0xe8a2aa, 0xfbe9}, /* U+88AA [2000] */ + {0xe8a2ab, 0xc8ef}, /* U+88AB */ + {0xe8a2ae, 0xead9}, /* U+88AE */ + {0xe8a2b0, 0xeade}, /* U+88B0 */ + {0xe8a2b1, 0xeae0}, /* U+88B1 */ + {0xe8a2b4, 0xb8d3}, /* U+88B4 */ + {0xe8a2b5, 0xead4}, /* U+88B5 */ + {0xe8a2b7, 0xb0c1}, /* U+88B7 */ + {0xe8a2bc, 0x8ff8af}, /* U+88BC [2000] */ + {0xe8a2bd, 0x8ff8b0}, /* U+88BD [2000] */ + {0xe8a2be, 0x8ff8b1}, /* U+88BE [2000] */ + {0xe8a2bf, 0xeadf}, /* U+88BF */ + {0xe8a380, 0x8ff8b2}, /* U+88C0 [2000] */ + {0xe8a381, 0xbadb}, /* U+88C1 */ + {0xe8a382, 0xcef6}, /* U+88C2 */ + {0xe8a383, 0xeae1}, /* U+88C3 */ + {0xe8a384, 0xeae2}, /* U+88C4 */ + {0xe8a385, 0xc1f5}, /* U+88C5 */ + {0xe8a38a, 0xfbea}, /* U+88CA [2000] */ + {0xe8a38e, 0xfbeb}, /* U+88CE [2000] */ + {0xe8a38f, 0xcea2}, /* U+88CF */ + {0xe8a391, 0x8ff8b5}, /* U+88D1 [2000] */ + {0xe8a392, 0x8ff8b3}, /* U+88D2 [2000] */ + {0xe8a393, 0x8ff8b6}, /* U+88D3 [2000] */ + {0xe8a394, 0xeae3}, /* U+88D4 */ + {0xe8a395, 0xcdb5}, /* U+88D5 */ + {0xe8a398, 0xeae4}, /* U+88D8 */ + {0xe8a399, 0xeae5}, /* U+88D9 */ + {0xe8a39b, 0x8ff8b7}, /* U+88DB [2000] */ + {0xe8a39c, 0xcae4}, /* U+88DC */ + {0xe8a39d, 0xeae6}, /* U+88DD */ + {0xe8a39f, 0xbac0}, /* U+88DF */ + {0xe8a3a1, 0xcea3}, /* U+88E1 */ + {0xe8a3a8, 0xeaeb}, /* U+88E8 */ + {0xe8a3b0, 0x8ff8b8}, /* U+88F0 [2000] */ + {0xe8a3b1, 0x8ff8b9}, /* U+88F1 [2000] */ + {0xe8a3b2, 0xeaec}, /* U+88F2 */ + {0xe8a3b3, 0xbed8}, /* U+88F3 */ + {0xe8a3b4, 0xeaea}, /* U+88F4 */ + {0xe8a3b5, 0xfbed}, /* U+88F5 [2000] */ + {0xe8a3b8, 0xcde7}, /* U+88F8 */ + {0xe8a3b9, 0xeae7}, /* U+88F9 */ + {0xe8a3bc, 0xeae9}, /* U+88FC */ + {0xe8a3bd, 0xc0bd}, /* U+88FD */ + {0xe8a3be, 0xbffe}, /* U+88FE */ + {0xe8a481, 0x8ff8bb}, /* U+8901 [2000] */ + {0xe8a482, 0xeae8}, /* U+8902 */ + {0xe8a484, 0xeaed}, /* U+8904 */ + {0xe8a487, 0xcaa3}, /* U+8907 */ + {0xe8a48a, 0xeaef}, /* U+890A */ + {0xe8a48c, 0xeaee}, /* U+890C */ + {0xe8a490, 0xb3ec}, /* U+8910 */ + {0xe8a492, 0xcbab}, /* U+8912 */ + {0xe8a493, 0xeaf0}, /* U+8913 */ + {0xe8a498, 0xfbf0}, /* U+8918 [2000] */ + {0xe8a499, 0xfbf1}, /* U+8919 [2000] */ + {0xe8a49a, 0xfbf2}, /* U+891A [2000] */ + {0xe8a49c, 0xfbee}, /* U+891C [2000] */ + {0xe8a49d, 0xeafc}, /* U+891D */ + {0xe8a49e, 0xeaf2}, /* U+891E */ + {0xe8a4a5, 0xeaf3}, /* U+8925 */ + {0xe8a4a7, 0xfbf3}, /* U+8927 [2000] */ + {0xe8a4aa, 0xeaf4}, /* U+892A */ + {0xe8a4ab, 0xeaf5}, /* U+892B */ + {0xe8a4b0, 0xfbf4}, /* U+8930 [2000] */ + {0xe8a4b2, 0xfbf5}, /* U+8932 [2000] */ + {0xe8a4b6, 0xeaf9}, /* U+8936 */ + {0xe8a4b7, 0x8ff8bd}, /* U+8937 [2000] */ + {0xe8a4b8, 0xeafa}, /* U+8938 */ + {0xe8a4b9, 0xfbf6}, /* U+8939 [2000] */ + {0xe8a4bb, 0xeaf8}, /* U+893B */ + {0xe8a580, 0xfbf7}, /* U+8940 [2000] */ + {0xe8a581, 0xeaf6}, /* U+8941 */ + {0xe8a582, 0x8ff8bf}, /* U+8942 [2000] */ + {0xe8a583, 0xeaf1}, /* U+8943 */ + {0xe8a584, 0xeaf7}, /* U+8944 */ + {0xe8a585, 0x8ff8c0}, /* U+8945 [2000] */ + {0xe8a589, 0x8ff8c1}, /* U+8949 [2000] */ + {0xe8a58c, 0xeafb}, /* U+894C */ + {0xe8a58d, 0xf0b7}, /* U+894D */ + {0xe8a596, 0xb2a8}, /* U+8956 */ + {0xe8a59e, 0xeafe}, /* U+895E */ + {0xe8a59f, 0xb6df}, /* U+895F */ + {0xe8a5a0, 0xeafd}, /* U+8960 */ + {0xe8a5a2, 0x8ff8c4}, /* U+8962 [2000] */ + {0xe8a5a4, 0xeba2}, /* U+8964 */ + {0xe8a5a6, 0xeba1}, /* U+8966 */ + {0xe8a5aa, 0xeba4}, /* U+896A */ + {0xe8a5ad, 0xeba3}, /* U+896D */ + {0xe8a5af, 0xeba5}, /* U+896F */ + {0xe8a5b2, 0xbdb1}, /* U+8972 */ + {0xe8a5b4, 0xeba6}, /* U+8974 */ + {0xe8a5b7, 0xeba7}, /* U+8977 */ + {0xe8a5be, 0xeba8}, /* U+897E */ + {0xe8a5bf, 0xc0be}, /* U+897F */ + {0xe8a680, 0x8ff8c5}, /* U+8980 [2000] */ + {0xe8a681, 0xcdd7}, /* U+8981 */ + {0xe8a683, 0xeba9}, /* U+8983 */ + {0xe8a686, 0xcaa4}, /* U+8986 */ + {0xe8a687, 0xc7c6}, /* U+8987 */ + {0xe8a688, 0xebaa}, /* U+8988 */ + {0xe8a689, 0x8ff8c6}, /* U+8989 [2000] */ + {0xe8a68a, 0xebab}, /* U+898A */ + {0xe8a68b, 0xb8ab}, /* U+898B */ + {0xe8a68f, 0xb5ac}, /* U+898F */ + {0xe8a690, 0x8ff8c7}, /* U+8990 [2000] */ + {0xe8a693, 0xebac}, /* U+8993 */ + {0xe8a694, 0xfbf8}, /* U+8994 [2000] */ + {0xe8a696, 0xbbeb}, /* U+8996 */ + {0xe8a697, 0xc7c1}, /* U+8997 */ + {0xe8a698, 0xebad}, /* U+8998 */ + {0xe8a69a, 0xb3d0}, /* U+899A */ + {0xe8a69f, 0x8ff8c8}, /* U+899F [2000] */ + {0xe8a6a1, 0xebae}, /* U+89A1 */ + {0xe8a6a6, 0xebb0}, /* U+89A6 */ + {0xe8a6a7, 0xcdf7}, /* U+89A7 */ + {0xe8a6a9, 0xebaf}, /* U+89A9 */ + {0xe8a6aa, 0xbfc6}, /* U+89AA */ + {0xe8a6ac, 0xebb1}, /* U+89AC */ + {0xe8a6af, 0xebb2}, /* U+89AF */ + {0xe8a6b0, 0x8ff8c9}, /* U+89B0 [2000] */ + {0xe8a6b2, 0xebb3}, /* U+89B2 */ + {0xe8a6b3, 0xb4d1}, /* U+89B3 */ + {0xe8a6b7, 0x8ff8ca}, /* U+89B7 [2000] */ + {0xe8a6ba, 0xebb4}, /* U+89BA */ + {0xe8a6bd, 0xebb5}, /* U+89BD */ + {0xe8a6bf, 0xebb6}, /* U+89BF */ + {0xe8a780, 0xebb7}, /* U+89C0 */ + {0xe8a792, 0xb3d1}, /* U+89D2 */ + {0xe8a794, 0xfbfa}, /* U+89D4 [2000] */ + {0xe8a796, 0x8ff8cb}, /* U+89D6 [2000] */ + {0xe8a798, 0x8ff8cc}, /* U+89D8 [2000] */ + {0xe8a79a, 0xebb8}, /* U+89DA */ + {0xe8a79c, 0xebb9}, /* U+89DC */ + {0xe8a79d, 0xebba}, /* U+89DD */ + {0xe8a7a3, 0xb2f2}, /* U+89E3 */ + {0xe8a7a5, 0xfbfb}, /* U+89E5 [2000] */ + {0xe8a7a6, 0xbfa8}, /* U+89E6 */ + {0xe8a7a7, 0xebbb}, /* U+89E7 */ + {0xe8a7ab, 0x8ff8cd}, /* U+89EB [2000] */ + {0xe8a7b1, 0x8ff8cf}, /* U+89F1 [2000] */ + {0xe8a7b3, 0x8ff8d0}, /* U+89F3 [2000] */ + {0xe8a7b4, 0xebbc}, /* U+89F4 */ + {0xe8a7b6, 0xfbfc}, /* U+89F6 [2000] */ + {0xe8a7b8, 0xebbd}, /* U+89F8 */ + {0xe8a7bd, 0x8ff8d1}, /* U+89FD [2000] */ + {0xe8a7bf, 0x8ff8d2}, /* U+89FF [2000] */ + {0xe8a880, 0xb8c0}, /* U+8A00 */ + {0xe8a882, 0xc4fb}, /* U+8A02 */ + {0xe8a883, 0xebbe}, /* U+8A03 */ + {0xe8a888, 0xb7d7}, /* U+8A08 */ + {0xe8a88a, 0xbfd6}, /* U+8A0A */ + {0xe8a88c, 0xebc1}, /* U+8A0C */ + {0xe8a88e, 0xc6a4}, /* U+8A0E */ + {0xe8a890, 0xebc0}, /* U+8A10 */ + {0xe8a891, 0x8ff8d4}, /* U+8A11 [2000] */ + {0xe8a892, 0xfbfd}, /* U+8A12 [2000] */ + {0xe8a893, 0xb7b1}, /* U+8A13 */ + {0xe8a894, 0x8ff8d5}, /* U+8A14 [2000] */ + {0xe8a895, 0xfbfe}, /* U+8A15 [2000] */ + {0xe8a896, 0xebbf}, /* U+8A16 */ + {0xe8a897, 0xc2f7}, /* U+8A17 */ + {0xe8a898, 0xb5ad}, /* U+8A18 */ + {0xe8a89b, 0xebc2}, /* U+8A1B */ + {0xe8a89d, 0xebc3}, /* U+8A1D */ + {0xe8a89f, 0xbed9}, /* U+8A1F */ + {0xe8a8a1, 0x8ff8d7}, /* U+8A21 [2000] */ + {0xe8a8a2, 0xfca1}, /* U+8A22 [2000] */ + {0xe8a8a3, 0xb7ed}, /* U+8A23 */ + {0xe8a8a5, 0xebc4}, /* U+8A25 */ + {0xe8a8aa, 0xcbac}, /* U+8A2A */ + {0xe8a8ad, 0xc0df}, /* U+8A2D */ + {0xe8a8b1, 0xb5f6}, /* U+8A31 */ + {0xe8a8b3, 0xccf5}, /* U+8A33 */ + {0xe8a8b4, 0xc1ca}, /* U+8A34 */ + {0xe8a8b5, 0x8ff8d8}, /* U+8A35 [2000] */ + {0xe8a8b6, 0xebc5}, /* U+8A36 */ + {0xe8a8b7, 0xfca2}, /* U+8A37 [2000] */ + {0xe8a8ba, 0xbfc7}, /* U+8A3A */ + {0xe8a8bb, 0xc3f0}, /* U+8A3B */ + {0xe8a8bc, 0xbeda}, /* U+8A3C */ + {0xe8a8be, 0x8ff8d9}, /* U+8A3E [2000] */ + {0xe8a981, 0xebc6}, /* U+8A41 */ + {0xe8a985, 0x8ff8da}, /* U+8A45 [2000] */ + {0xe8a986, 0xebc9}, /* U+8A46 */ + {0xe8a987, 0xfca3}, /* U+8A47 [2000] */ + {0xe8a988, 0xebca}, /* U+8A48 */ + {0xe8a98d, 0x8ff8db}, /* U+8A4D [2000] */ + {0xe8a98e, 0xfca4}, /* U+8A4E [2000] */ + {0xe8a990, 0xbabe}, /* U+8A50 */ + {0xe8a991, 0xc2c2}, /* U+8A51 */ + {0xe8a992, 0xebc8}, /* U+8A52 */ + {0xe8a994, 0xbedb}, /* U+8A54 */ + {0xe8a995, 0xc9be}, /* U+8A55 */ + {0xe8a998, 0x8ff8dc}, /* U+8A58 [2000] */ + {0xe8a99b, 0xebc7}, /* U+8A5B */ + {0xe8a99d, 0xfca5}, /* U+8A5D [2000] */ + {0xe8a99e, 0xbbec}, /* U+8A5E */ + {0xe8a9a0, 0xb1d3}, /* U+8A60 */ + {0xe8a9a1, 0xfca6}, /* U+8A61 [2000] */ + {0xe8a9a2, 0xebce}, /* U+8A62 */ + {0xe8a9a3, 0xb7d8}, /* U+8A63 */ + {0xe8a9a6, 0xbbee}, /* U+8A66 */ + {0xe8a9a9, 0xbbed}, /* U+8A69 */ + {0xe8a9ab, 0xcfcd}, /* U+8A6B */ + {0xe8a9ac, 0xebcd}, /* U+8A6C */ + {0xe8a9ad, 0xebcc}, /* U+8A6D */ + {0xe8a9ae, 0xc1a7}, /* U+8A6E */ + {0xe8a9b0, 0xb5cd}, /* U+8A70 */ + {0xe8a9b1, 0xcfc3}, /* U+8A71 */ + {0xe8a9b2, 0xb3ba}, /* U+8A72 */ + {0xe8a9b3, 0xbedc}, /* U+8A73 */ + {0xe8a9b5, 0xfca7}, /* U+8A75 [2000] */ + {0xe8a9b9, 0xfca8}, /* U+8A79 [2000] */ + {0xe8a9bc, 0xebcb}, /* U+8A7C */ + {0xe8aa82, 0xebd0}, /* U+8A82 */ + {0xe8aa84, 0xebd1}, /* U+8A84 */ + {0xe8aa85, 0xebcf}, /* U+8A85 */ + {0xe8aa87, 0xb8d8}, /* U+8A87 */ + {0xe8aa89, 0xcdc0}, /* U+8A89 */ + {0xe8aa8c, 0xbbef}, /* U+8A8C */ + {0xe8aa8d, 0xc7a7}, /* U+8A8D */ + {0xe8aa90, 0x8ff8de}, /* U+8A90 [2000] */ + {0xe8aa91, 0xebd4}, /* U+8A91 */ + {0xe8aa93, 0xc0c0}, /* U+8A93 */ + {0xe8aa95, 0xc3c2}, /* U+8A95 */ + {0xe8aa98, 0xcdb6}, /* U+8A98 */ + {0xe8aa9a, 0xebd7}, /* U+8A9A */ + {0xe8aa9e, 0xb8ec}, /* U+8A9E */ + {0xe8aaa0, 0xc0bf}, /* U+8AA0 */ + {0xe8aaa1, 0xebd3}, /* U+8AA1 */ + {0xe8aaa3, 0xebd8}, /* U+8AA3 */ + {0xe8aaa4, 0xb8ed}, /* U+8AA4 */ + {0xe8aaa5, 0xebd5}, /* U+8AA5 */ + {0xe8aaa6, 0xebd6}, /* U+8AA6 */ + {0xe8aaa7, 0xfca9}, /* U+8AA7 [2000] */ + {0xe8aaa8, 0xebd2}, /* U+8AA8 */ + {0xe8aaac, 0xc0e2}, /* U+8AAC */ + {0xe8aaad, 0xc6c9}, /* U+8AAD */ + {0xe8aaae, 0x8ff8dd}, /* U+8AAE [2000] */ + {0xe8aab0, 0xc3af}, /* U+8AB0 */ + {0xe8aab2, 0xb2dd}, /* U+8AB2 */ + {0xe8aab7, 0x8ff8df}, /* U+8AB7 [2000] */ + {0xe8aab9, 0xc8f0}, /* U+8AB9 */ + {0xe8aabc, 0xb5c3}, /* U+8ABC */ + {0xe8aabe, 0x8ff8e0}, /* U+8ABE [2000] */ + {0xe8aabf, 0xc4b4}, /* U+8ABF */ + {0xe8ab82, 0xebdb}, /* U+8AC2 */ + {0xe8ab84, 0xebd9}, /* U+8AC4 */ + {0xe8ab87, 0xc3cc}, /* U+8AC7 */ + {0xe8ab8b, 0xc0c1}, /* U+8ACB */ + {0xe8ab8c, 0xb4d2}, /* U+8ACC */ + {0xe8ab8d, 0xebda}, /* U+8ACD */ + {0xe8ab8f, 0xbfdb}, /* U+8ACF */ + {0xe8ab90, 0xfcaa}, /* U+8AD0 [2000] */ + {0xe8ab92, 0xceca}, /* U+8AD2 */ + {0xe8ab96, 0xcfc0}, /* U+8AD6 */ + {0xe8ab97, 0x8ff8e1}, /* U+8AD7 [2000] */ + {0xe8ab9a, 0xebdc}, /* U+8ADA */ + {0xe8ab9b, 0xebe7}, /* U+8ADB */ + {0xe8ab9c, 0xc4b5}, /* U+8ADC */ + {0xe8ab9e, 0xebe6}, /* U+8ADE */ + {0xe8ab9f, 0xfcab}, /* U+8ADF [2000] */ + {0xe8aba0, 0xebe3}, /* U+8AE0 */ + {0xe8aba1, 0xebeb}, /* U+8AE1 */ + {0xe8aba2, 0xebe4}, /* U+8AE2 */ + {0xe8aba4, 0xebe0}, /* U+8AE4 */ + {0xe8aba6, 0xc4fc}, /* U+8AE6 */ + {0xe8aba7, 0xebdf}, /* U+8AE7 */ + {0xe8abab, 0xebdd}, /* U+8AEB */ + {0xe8abad, 0xcda1}, /* U+8AED */ + {0xe8abae, 0xbbf0}, /* U+8AEE */ + {0xe8abb1, 0xebe1}, /* U+8AF1 */ + {0xe8abb3, 0xebde}, /* U+8AF3 */ + {0xe8abb4, 0xfcac}, /* U+8AF4 [2000] */ + {0xe8abb6, 0xfcad}, /* U+8AF6 [2000] */ + {0xe8abb7, 0xebe5}, /* U+8AF7 */ + {0xe8abb8, 0xbdf4}, /* U+8AF8 */ + {0xe8abba, 0xb8c1}, /* U+8AFA */ + {0xe8abbc, 0x8ff8e2}, /* U+8AFC [2000] */ + {0xe8abbe, 0xc2fa}, /* U+8AFE */ + {0xe8ac80, 0xcbc5}, /* U+8B00 */ + {0xe8ac81, 0xb1da}, /* U+8B01 */ + {0xe8ac82, 0xb0e2}, /* U+8B02 */ + {0xe8ac84, 0xc6a5}, /* U+8B04 */ + {0xe8ac85, 0x8ff8e5}, /* U+8B05 [2000] */ + {0xe8ac87, 0xebe9}, /* U+8B07 */ + {0xe8ac8a, 0x8ff8e4}, /* U+8B0A [2000] */ + {0xe8ac8c, 0xebe8}, /* U+8B0C */ + {0xe8ac8d, 0x8ff8e6}, /* U+8B0D [2000] */ + {0xe8ac8e, 0xc6e6}, /* U+8B0E */ + {0xe8ac90, 0xebed}, /* U+8B10 */ + {0xe8ac94, 0xebe2}, /* U+8B14 */ + {0xe8ac96, 0xebec}, /* U+8B16 */ + {0xe8ac97, 0xebee}, /* U+8B17 */ + {0xe8ac99, 0xb8ac}, /* U+8B19 */ + {0xe8ac9a, 0xebea}, /* U+8B1A */ + {0xe8ac9b, 0xb9d6}, /* U+8B1B */ + {0xe8ac9c, 0x8ff8e7}, /* U+8B1C [2000] */ + {0xe8ac9d, 0xbcd5}, /* U+8B1D */ + {0xe8ac9f, 0x8ff8e8}, /* U+8B1F [2000] */ + {0xe8aca0, 0xebef}, /* U+8B20 */ + {0xe8aca1, 0xcdd8}, /* U+8B21 */ + {0xe8aca6, 0xebf2}, /* U+8B26 */ + {0xe8aca8, 0xebf5}, /* U+8B28 */ + {0xe8acab, 0xebf3}, /* U+8B2B */ + {0xe8acac, 0xc9b5}, /* U+8B2C */ + {0xe8acad, 0x8ff8e9}, /* U+8B2D [2000] */ + {0xe8acb3, 0xebf0}, /* U+8B33 */ + {0xe8acb9, 0xb6e0}, /* U+8B39 */ + {0xe8acbe, 0xebf4}, /* U+8B3E */ + {0xe8ad81, 0xebf6}, /* U+8B41 */ + {0xe8ad83, 0x8ff8ea}, /* U+8B43 [2000] */ + {0xe8ad86, 0xfcb1}, /* U+8B46 [2000] */ + {0xe8ad89, 0xebfa}, /* U+8B49 */ + {0xe8ad8c, 0xebf7}, /* U+8B4C */ + {0xe8ad8e, 0xebf9}, /* U+8B4E */ + {0xe8ad8f, 0xebf8}, /* U+8B4F */ + {0xe8ad91, 0x8ff8ec}, /* U+8B51 [2000] */ + {0xe8ad94, 0xfcb2}, /* U+8B54 [2000] */ + {0xe8ad96, 0xebfb}, /* U+8B56 */ + {0xe8ad98, 0xbcb1}, /* U+8B58 */ + {0xe8ad99, 0xfcb3}, /* U+8B59 [2000] */ + {0xe8ad9a, 0xebfd}, /* U+8B5A */ + {0xe8ad9b, 0xebfc}, /* U+8B5B */ + {0xe8ad9c, 0xc9e8}, /* U+8B5C */ + {0xe8ad9e, 0x8ff8ed}, /* U+8B5E [2000] */ + {0xe8ad9f, 0xeca1}, /* U+8B5F */ + {0xe8ada6, 0xb7d9}, /* U+8B66 */ + {0xe8ada9, 0xfcb4}, /* U+8B69 [2000] */ + {0xe8adab, 0xebfe}, /* U+8B6B */ + {0xe8adac, 0xeca2}, /* U+8B6C */ + {0xe8adaf, 0xeca3}, /* U+8B6F */ + {0xe8adb0, 0xb5c4}, /* U+8B70 */ + {0xe8adb1, 0xe6c1}, /* U+8B71 */ + {0xe8adb2, 0xbef9}, /* U+8B72 */ + {0xe8adb4, 0xeca4}, /* U+8B74 */ + {0xe8adb6, 0x8ff8ee}, /* U+8B76 [2000] */ + {0xe8adb7, 0xb8ee}, /* U+8B77 */ + {0xe8adbd, 0xeca5}, /* U+8B7D */ + {0xe8adbf, 0x8ff8ef}, /* U+8B7F [2000] */ + {0xe8ae80, 0xeca6}, /* U+8B80 */ + {0xe8ae81, 0x8ff8f0}, /* U+8B81 [2000] */ + {0xe8ae83, 0xbbbe}, /* U+8B83 */ + {0xe8ae8a, 0xdace}, /* U+8B8A */ + {0xe8ae8b, 0x8ff8f1}, /* U+8B8B [2000] */ + {0xe8ae8c, 0xeca7}, /* U+8B8C */ + {0xe8ae8e, 0xeca8}, /* U+8B8E */ + {0xe8ae90, 0xbdb2}, /* U+8B90 */ + {0xe8ae92, 0xeca9}, /* U+8B92 */ + {0xe8ae93, 0xecaa}, /* U+8B93 */ + {0xe8ae94, 0x8ff8f2}, /* U+8B94 [2000] */ + {0xe8ae95, 0x8ff8f3}, /* U+8B95 [2000] */ + {0xe8ae96, 0xecab}, /* U+8B96 */ + {0xe8ae99, 0xecac}, /* U+8B99 */ + {0xe8ae9a, 0xecad}, /* U+8B9A */ + {0xe8ae9c, 0x8ff8f4}, /* U+8B9C [2000] */ + {0xe8ae9d, 0xfcb5}, /* U+8B9D [2000] */ + {0xe8ae9e, 0x8ff8f5}, /* U+8B9E [2000] */ + {0xe8b0b7, 0xc3ab}, /* U+8C37 */ + {0xe8b0b9, 0x8ff8f6}, /* U+8C39 [2000] */ + {0xe8b0ba, 0xecae}, /* U+8C3A */ + {0xe8b0bd, 0x8ff8f8}, /* U+8C3D [2000] */ + {0xe8b0bf, 0xecb0}, /* U+8C3F */ + {0xe8b181, 0xecaf}, /* U+8C41 */ + {0xe8b185, 0x8ff8fb}, /* U+8C45 [2000] */ + {0xe8b186, 0xc6a6}, /* U+8C46 */ + {0xe8b187, 0x8ff8fc}, /* U+8C47 [2000] */ + {0xe8b188, 0xecb1}, /* U+8C48 */ + {0xe8b189, 0xfcb6}, /* U+8C49 [2000] */ + {0xe8b18a, 0xcbad}, /* U+8C4A */ + {0xe8b18c, 0xecb2}, /* U+8C4C */ + {0xe8b18e, 0xecb3}, /* U+8C4E */ + {0xe8b18f, 0x8ff8fd}, /* U+8C4F [2000] */ + {0xe8b190, 0xecb4}, /* U+8C50 */ + {0xe8b194, 0x8ff8fe}, /* U+8C54 [2000] */ + {0xe8b195, 0xecb5}, /* U+8C55 */ + {0xe8b197, 0x8ff9a1}, /* U+8C57 [2000] */ + {0xe8b19a, 0xc6da}, /* U+8C5A */ + {0xe8b1a1, 0xbedd}, /* U+8C61 */ + {0xe8b1a2, 0xecb6}, /* U+8C62 */ + {0xe8b1a8, 0xfcb7}, /* U+8C68 [2000] */ + {0xe8b1a9, 0x8ff9a2}, /* U+8C69 [2000] */ + {0xe8b1aa, 0xb9eb}, /* U+8C6A */ + {0xe8b1ab, 0xd0ae}, /* U+8C6B */ + {0xe8b1ac, 0xecb7}, /* U+8C6C */ + {0xe8b1ad, 0x8ff9a3}, /* U+8C6D [2000] */ + {0xe8b1b3, 0x8ff9a4}, /* U+8C73 [2000] */ + {0xe8b1b8, 0xecb8}, /* U+8C78 */ + {0xe8b1b9, 0xc9bf}, /* U+8C79 */ + {0xe8b1ba, 0xecb9}, /* U+8C7A */ + {0xe8b1bc, 0xecc1}, /* U+8C7C */ + {0xe8b282, 0xecba}, /* U+8C82 */ + {0xe8b285, 0xecbc}, /* U+8C85 */ + {0xe8b289, 0xecbb}, /* U+8C89 */ + {0xe8b28a, 0xecbd}, /* U+8C8A */ + {0xe8b28c, 0xcbc6}, /* U+8C8C */ + {0xe8b28d, 0xecbe}, /* U+8C8D */ + {0xe8b28e, 0xecbf}, /* U+8C8E */ + {0xe8b292, 0x8ff9a7}, /* U+8C92 [2000] */ + {0xe8b293, 0x8ff9a6}, /* U+8C93 [2000] */ + {0xe8b294, 0xecc0}, /* U+8C94 */ + {0xe8b298, 0xecc2}, /* U+8C98 */ + {0xe8b299, 0x8ff9a8}, /* U+8C99 [2000] */ + {0xe8b29b, 0x8ff9aa}, /* U+8C9B [2000] */ + {0xe8b29d, 0xb3ad}, /* U+8C9D */ + {0xe8b29e, 0xc4e7}, /* U+8C9E */ + {0xe8b2a0, 0xc9e9}, /* U+8CA0 */ + {0xe8b2a1, 0xbae2}, /* U+8CA1 */ + {0xe8b2a2, 0xb9d7}, /* U+8CA2 */ + {0xe8b2a4, 0x8ff9ab}, /* U+8CA4 [2000] */ + {0xe8b2a7, 0xc9cf}, /* U+8CA7 */ + {0xe8b2a8, 0xb2df}, /* U+8CA8 */ + {0xe8b2a9, 0xc8ce}, /* U+8CA9 */ + {0xe8b2aa, 0xecc5}, /* U+8CAA */ + {0xe8b2ab, 0xb4d3}, /* U+8CAB */ + {0xe8b2ac, 0xc0d5}, /* U+8CAC */ + {0xe8b2ad, 0xecc4}, /* U+8CAD */ + {0xe8b2ae, 0xecc9}, /* U+8CAE */ + {0xe8b2af, 0xc3f9}, /* U+8CAF */ + {0xe8b2b0, 0xcce3}, /* U+8CB0 */ + {0xe8b2b2, 0xecc7}, /* U+8CB2 */ + {0xe8b2b3, 0xecc8}, /* U+8CB3 */ + {0xe8b2b4, 0xb5ae}, /* U+8CB4 */ + {0xe8b2b6, 0xecca}, /* U+8CB6 */ + {0xe8b2b7, 0xc7e3}, /* U+8CB7 */ + {0xe8b2b8, 0xc2df}, /* U+8CB8 */ + {0xe8b2bb, 0xc8f1}, /* U+8CBB */ + {0xe8b2bc, 0xc5bd}, /* U+8CBC */ + {0xe8b2bd, 0xecc6}, /* U+8CBD */ + {0xe8b2bf, 0xcbc7}, /* U+8CBF */ + {0xe8b380, 0xb2ec}, /* U+8CC0 */ + {0xe8b381, 0xeccc}, /* U+8CC1 */ + {0xe8b382, 0xcfa8}, /* U+8CC2 */ + {0xe8b383, 0xc4c2}, /* U+8CC3 */ + {0xe8b384, 0xcfc5}, /* U+8CC4 */ + {0xe8b387, 0xbbf1}, /* U+8CC7 */ + {0xe8b388, 0xeccb}, /* U+8CC8 */ + {0xe8b38a, 0xc2b1}, /* U+8CCA */ + {0xe8b38d, 0xecdc}, /* U+8CCD */ + {0xe8b38e, 0xc1a8}, /* U+8CCE */ + {0xe8b391, 0xc6f8}, /* U+8CD1 */ + {0xe8b393, 0xc9d0}, /* U+8CD3 */ + {0xe8b395, 0x8ff9ad}, /* U+8CD5 [2000] */ + {0xe8b396, 0x8ff9ac}, /* U+8CD6 [2000] */ + {0xe8b399, 0x8ff9ae}, /* U+8CD9 [2000] */ + {0xe8b39a, 0xeccf}, /* U+8CDA */ + {0xe8b39b, 0xbbbf}, /* U+8CDB */ + {0xe8b39c, 0xbbf2}, /* U+8CDC */ + {0xe8b39e, 0xbede}, /* U+8CDE */ + {0xe8b3a0, 0xc7e5}, /* U+8CE0 */ + {0xe8b3a1, 0xfcb9}, /* U+8CE1 [2000] */ + {0xe8b3a2, 0xb8ad}, /* U+8CE2 */ + {0xe8b3a3, 0xecce}, /* U+8CE3 */ + {0xe8b3a4, 0xeccd}, /* U+8CE4 */ + {0xe8b3a6, 0xc9ea}, /* U+8CE6 */ + {0xe8b3aa, 0xbcc1}, /* U+8CEA */ + {0xe8b3ad, 0xc5d2}, /* U+8CED */ + {0xe8b3b0, 0x8ff9b0}, /* U+8CF0 [2000] */ + {0xe8b3b1, 0x8ff9b1}, /* U+8CF1 [2000] */ + {0xe8b3b4, 0xfcba}, /* U+8CF4 [2000] */ + {0xe8b3b8, 0xfcbb}, /* U+8CF8 [2000] */ + {0xe8b3ba, 0xecd1}, /* U+8CFA */ + {0xe8b3bb, 0xecd2}, /* U+8CFB */ + {0xe8b3bc, 0xb9d8}, /* U+8CFC */ + {0xe8b3bd, 0xecd0}, /* U+8CFD */ + {0xe8b3be, 0xfcbc}, /* U+8CFE [2000] */ + {0xe8b484, 0xecd3}, /* U+8D04 */ + {0xe8b485, 0xecd4}, /* U+8D05 */ + {0xe8b487, 0xecd6}, /* U+8D07 */ + {0xe8b488, 0xc2a3}, /* U+8D08 */ + {0xe8b489, 0x8ff9b3}, /* U+8D09 [2000] */ + {0xe8b48a, 0xecd5}, /* U+8D0A */ + {0xe8b48b, 0xb4e6}, /* U+8D0B */ + {0xe8b48d, 0xecd8}, /* U+8D0D */ + {0xe8b48e, 0x8ff9b4}, /* U+8D0E [2000] */ + {0xe8b48f, 0xecd7}, /* U+8D0F */ + {0xe8b490, 0xecd9}, /* U+8D10 */ + {0xe8b492, 0xfcbe}, /* U+8D12 [2000] */ + {0xe8b493, 0xecdb}, /* U+8D13 */ + {0xe8b494, 0xecdd}, /* U+8D14 */ + {0xe8b496, 0xecde}, /* U+8D16 */ + {0xe8b49b, 0xfcbf}, /* U+8D1B [2000] */ + {0xe8b5a4, 0xc0d6}, /* U+8D64 */ + {0xe8b5a6, 0xbccf}, /* U+8D66 */ + {0xe8b5a7, 0xecdf}, /* U+8D67 */ + {0xe8b5ab, 0xb3d2}, /* U+8D6B */ + {0xe8b5ac, 0x8ff9b5}, /* U+8D6C [2000] */ + {0xe8b5ad, 0xece0}, /* U+8D6D */ + {0xe8b5b0, 0xc1f6}, /* U+8D70 */ + {0xe8b5b1, 0xece1}, /* U+8D71 */ + {0xe8b5b3, 0xece2}, /* U+8D73 */ + {0xe8b5b4, 0xc9eb}, /* U+8D74 */ + {0xe8b5b7, 0xb5af}, /* U+8D77 */ + {0xe8b681, 0xece3}, /* U+8D81 */ + {0xe8b684, 0x8ff9b6}, /* U+8D84 [2000] */ + {0xe8b685, 0xc4b6}, /* U+8D85 */ + {0xe8b68a, 0xb1db}, /* U+8D8A */ + {0xe8b695, 0x8ff9b7}, /* U+8D95 [2000] */ + {0xe8b699, 0xece4}, /* U+8D99 */ + {0xe8b6a3, 0xbcf1}, /* U+8DA3 */ + {0xe8b6a6, 0x8ff9b8}, /* U+8DA6 [2000] */ + {0xe8b6a8, 0xbff6}, /* U+8DA8 */ + {0xe8b6af, 0xfcc0}, /* U+8DAF [2000] */ + {0xe8b6b3, 0xc2ad}, /* U+8DB3 */ + {0xe8b6ba, 0xece7}, /* U+8DBA */ + {0xe8b6be, 0xece6}, /* U+8DBE */ + {0xe8b782, 0xece5}, /* U+8DC2 */ + {0xe8b786, 0x8ff9ba}, /* U+8DC6 [2000] */ + {0xe8b788, 0x8ff9bb}, /* U+8DC8 [2000] */ + {0xe8b78b, 0xeced}, /* U+8DCB */ + {0xe8b78c, 0xeceb}, /* U+8DCC */ + {0xe8b78e, 0xfcc1}, /* U+8DCE [2000] */ + {0xe8b78f, 0xece8}, /* U+8DCF */ + {0xe8b791, 0xfcc2}, /* U+8DD1 [2000] */ + {0xe8b796, 0xecea}, /* U+8DD6 */ + {0xe8b797, 0xfcc3}, /* U+8DD7 [2000] */ + {0xe8b799, 0x8ff9bc}, /* U+8DD9 [2000] */ + {0xe8b79a, 0xece9}, /* U+8DDA */ + {0xe8b79b, 0xecec}, /* U+8DDB */ + {0xe8b79d, 0xb5f7}, /* U+8DDD */ + {0xe8b79f, 0xecf0}, /* U+8DDF */ + {0xe8b7a1, 0xc0d7}, /* U+8DE1 */ + {0xe8b7a3, 0xecf1}, /* U+8DE3 */ + {0xe8b7a8, 0xb8d9}, /* U+8DE8 */ + {0xe8b7aa, 0xecee}, /* U+8DEA */ + {0xe8b7ab, 0xecef}, /* U+8DEB */ + {0xe8b7ac, 0x8ff9bd}, /* U+8DEC [2000] */ + {0xe8b7af, 0xcfa9}, /* U+8DEF */ + {0xe8b7b3, 0xc4b7}, /* U+8DF3 */ + {0xe8b7b5, 0xc1a9}, /* U+8DF5 */ + {0xe8b7bc, 0xecf2}, /* U+8DFC */ + {0xe8b7bd, 0x8ff9c0}, /* U+8DFD [2000] */ + {0xe8b7bf, 0xecf5}, /* U+8DFF */ + {0xe8b886, 0x8ff9c1}, /* U+8E06 [2000] */ + {0xe8b888, 0xecf3}, /* U+8E08 */ + {0xe8b889, 0xecf4}, /* U+8E09 */ + {0xe8b88a, 0xcdd9}, /* U+8E0A */ + {0xe8b88c, 0x8ff9be}, /* U+8E0C [2000] */ + {0xe8b88f, 0xc6a7}, /* U+8E0F */ + {0xe8b890, 0xecf8}, /* U+8E10 */ + {0xe8b894, 0x8ff9c3}, /* U+8E14 [2000] */ + {0xe8b896, 0x8ff9c4}, /* U+8E16 [2000] */ + {0xe8b89d, 0xecf6}, /* U+8E1D */ + {0xe8b89e, 0xecf7}, /* U+8E1E */ + {0xe8b89f, 0xecf9}, /* U+8E1F */ + {0xe8b8a0, 0xfcc4}, /* U+8E20 [2000] */ + {0xe8b8a1, 0x8ff9c5}, /* U+8E21 [2000] */ + {0xe8b8a2, 0x8ff9c6}, /* U+8E22 [2000] */ + {0xe8b8a3, 0xfcc5}, /* U+8E23 [2000] */ + {0xe8b8a7, 0x8ff9c7}, /* U+8E27 [2000] */ + {0xe8b8aa, 0xeda9}, /* U+8E2A */ + {0xe8b8b0, 0xecfc}, /* U+8E30 */ + {0xe8b8b4, 0xecfd}, /* U+8E34 */ + {0xe8b8b5, 0xecfb}, /* U+8E35 */ + {0xe8b8b6, 0x8ff9ca}, /* U+8E36 [2000] */ + {0xe8b8b9, 0x8ff9cb}, /* U+8E39 [2000] */ + {0xe8b8bd, 0xfcc6}, /* U+8E3D [2000] */ + {0xe8b982, 0xecfa}, /* U+8E42 */ + {0xe8b984, 0xc4fd}, /* U+8E44 */ + {0xe8b987, 0xeda1}, /* U+8E47 */ + {0xe8b988, 0xeda5}, /* U+8E48 */ + {0xe8b989, 0xeda2}, /* U+8E49 */ + {0xe8b98a, 0xecfe}, /* U+8E4A */ + {0xe8b98b, 0x8ff9cc}, /* U+8E4B [2000] */ + {0xe8b98c, 0xeda3}, /* U+8E4C */ + {0xe8b990, 0xeda4}, /* U+8E50 */ + {0xe8b994, 0x8ff9cd}, /* U+8E54 [2000] */ + {0xe8b995, 0xedab}, /* U+8E55 */ + {0xe8b999, 0xeda6}, /* U+8E59 */ + {0xe8b99f, 0xc0d8}, /* U+8E5F */ + {0xe8b9a0, 0xeda8}, /* U+8E60 */ + {0xe8b9a2, 0x8ff9ce}, /* U+8E62 [2000] */ + {0xe8b9a3, 0xedaa}, /* U+8E63 */ + {0xe8b9a4, 0xeda7}, /* U+8E64 */ + {0xe8b9ac, 0x8ff9cf}, /* U+8E6C [2000] */ + {0xe8b9ad, 0x8ff9d0}, /* U+8E6D [2000] */ + {0xe8b9af, 0x8ff9d1}, /* U+8E6F [2000] */ + {0xe8b9b0, 0xfcc7}, /* U+8E70 [2000] */ + {0xe8b9b2, 0xedad}, /* U+8E72 */ + {0xe8b9b4, 0xbdb3}, /* U+8E74 */ + {0xe8b9b6, 0xedac}, /* U+8E76 */ + {0xe8b9bb, 0xfcc8}, /* U+8E7B [2000] */ + {0xe8b9bc, 0xedae}, /* U+8E7C */ + {0xe8ba81, 0xedaf}, /* U+8E81 */ + {0xe8ba84, 0xedb2}, /* U+8E84 */ + {0xe8ba85, 0xedb1}, /* U+8E85 */ + {0xe8ba87, 0xedb0}, /* U+8E87 */ + {0xe8ba8a, 0xedb4}, /* U+8E8A */ + {0xe8ba8b, 0xedb3}, /* U+8E8B */ + {0xe8ba8d, 0xccf6}, /* U+8E8D */ + {0xe8ba91, 0xedb6}, /* U+8E91 */ + {0xe8ba93, 0xedb5}, /* U+8E93 */ + {0xe8ba94, 0xedb7}, /* U+8E94 */ + {0xe8ba98, 0x8ff9d2}, /* U+8E98 [2000] */ + {0xe8ba99, 0xedb8}, /* U+8E99 */ + {0xe8ba9e, 0x8ff9d3}, /* U+8E9E [2000] */ + {0xe8baa1, 0xedba}, /* U+8EA1 */ + {0xe8baaa, 0xedb9}, /* U+8EAA */ + {0xe8baab, 0xbfc8}, /* U+8EAB */ + {0xe8baac, 0xedbb}, /* U+8EAC */ + {0xe8baae, 0x8ff9d4}, /* U+8EAE [2000] */ + {0xe8baaf, 0xb6ed}, /* U+8EAF */ + {0xe8bab0, 0xedbc}, /* U+8EB0 */ + {0xe8bab1, 0xedbe}, /* U+8EB1 */ + {0xe8bab3, 0x8ff9d5}, /* U+8EB3 [2000] */ + {0xe8bab5, 0x8ff9d6}, /* U+8EB5 [2000] */ + {0xe8bab6, 0x8ff9d7}, /* U+8EB6 [2000] */ + {0xe8babb, 0x8ff9d8}, /* U+8EBB [2000] */ + {0xe8babe, 0xedbf}, /* U+8EBE */ + {0xe8bb80, 0xfcca}, /* U+8EC0 [2000] */ + {0xe8bb85, 0xedc0}, /* U+8EC5 */ + {0xe8bb86, 0xedbd}, /* U+8EC6 */ + {0xe8bb88, 0xedc1}, /* U+8EC8 */ + {0xe8bb8a, 0xbcd6}, /* U+8ECA */ + {0xe8bb8b, 0xedc2}, /* U+8ECB */ + {0xe8bb8c, 0xb5b0}, /* U+8ECC */ + {0xe8bb8d, 0xb7b3}, /* U+8ECD */ + {0xe8bb91, 0x8ff9da}, /* U+8ED1 [2000] */ + {0xe8bb92, 0xb8ae}, /* U+8ED2 */ + {0xe8bb94, 0x8ff9db}, /* U+8ED4 [2000] */ + {0xe8bb9b, 0xedc3}, /* U+8EDB */ + {0xe8bb9f, 0xc6f0}, /* U+8EDF */ + {0xe8bba2, 0xc5be}, /* U+8EE2 */ + {0xe8bba3, 0xedc4}, /* U+8EE3 */ + {0xe8bbab, 0xedc7}, /* U+8EEB */ + {0xe8bbb8, 0xbcb4}, /* U+8EF8 */ + {0xe8bbb9, 0x8ff9dd}, /* U+8EF9 [2000] */ + {0xe8bbba, 0xfccc}, /* U+8EFA [2000] */ + {0xe8bbbb, 0xedc6}, /* U+8EFB */ + {0xe8bbbc, 0xedc5}, /* U+8EFC */ + {0xe8bbbd, 0xb7da}, /* U+8EFD */ + {0xe8bbbe, 0xedc8}, /* U+8EFE */ + {0xe8bc80, 0x8ff9df}, /* U+8F00 [2000] */ + {0xe8bc83, 0xb3d3}, /* U+8F03 */ + {0xe8bc85, 0xedca}, /* U+8F05 */ + {0xe8bc88, 0x8ff9e0}, /* U+8F08 [2000] */ + {0xe8bc89, 0xbadc}, /* U+8F09 */ + {0xe8bc8a, 0xedc9}, /* U+8F0A */ + {0xe8bc8c, 0xedd2}, /* U+8F0C */ + {0xe8bc92, 0xedcc}, /* U+8F12 */ + {0xe8bc93, 0xedce}, /* U+8F13 */ + {0xe8bc94, 0xcae5}, /* U+8F14 */ + {0xe8bc95, 0xedcb}, /* U+8F15 */ + {0xe8bc97, 0x8ff9e1}, /* U+8F17 [2000] */ + {0xe8bc99, 0xedcd}, /* U+8F19 */ + {0xe8bc9b, 0xedd1}, /* U+8F1B */ + {0xe8bc9c, 0xedcf}, /* U+8F1C */ + {0xe8bc9d, 0xb5b1}, /* U+8F1D */ + {0xe8bc9e, 0xfccd}, /* U+8F1E [2000] */ + {0xe8bc9f, 0xedd0}, /* U+8F1F */ + {0xe8bca6, 0xedd3}, /* U+8F26 */ + {0xe8bca9, 0xc7da}, /* U+8F29 */ + {0xe8bcaa, 0xced8}, /* U+8F2A */ + {0xe8bcab, 0x8ff9e2}, /* U+8F2B [2000] */ + {0xe8bcad, 0xfcce}, /* U+8F2D [2000] */ + {0xe8bcaf, 0xbdb4}, /* U+8F2F */ + {0xe8bcb3, 0xedd4}, /* U+8F33 */ + {0xe8bcb6, 0xfccf}, /* U+8F36 [2000] */ + {0xe8bcb8, 0xcda2}, /* U+8F38 */ + {0xe8bcb9, 0xedd6}, /* U+8F39 */ + {0xe8bcbb, 0xedd5}, /* U+8F3B */ + {0xe8bcbe, 0xedd9}, /* U+8F3E */ + {0xe8bcbf, 0xcdc1}, /* U+8F3F */ + {0xe8bd80, 0x8ff9e3}, /* U+8F40 [2000] */ + {0xe8bd82, 0xedd8}, /* U+8F42 */ + {0xe8bd84, 0xb3ed}, /* U+8F44 */ + {0xe8bd85, 0xedd7}, /* U+8F45 */ + {0xe8bd86, 0xeddc}, /* U+8F46 */ + {0xe8bd89, 0xeddb}, /* U+8F49 */ + {0xe8bd8a, 0x8ff9e4}, /* U+8F4A [2000] */ + {0xe8bd8c, 0xedda}, /* U+8F4C */ + {0xe8bd8d, 0xc5b2}, /* U+8F4D */ + {0xe8bd8e, 0xeddd}, /* U+8F4E */ + {0xe8bd94, 0xfcd0}, /* U+8F54 [2000] */ + {0xe8bd97, 0xedde}, /* U+8F57 */ + {0xe8bd98, 0x8ff9e5}, /* U+8F58 [2000] */ + {0xe8bd9c, 0xeddf}, /* U+8F5C */ + {0xe8bd9f, 0xb9ec}, /* U+8F5F */ + {0xe8bda1, 0xb7a5}, /* U+8F61 */ + {0xe8bda2, 0xede0}, /* U+8F62 */ + {0xe8bda3, 0xede1}, /* U+8F63 */ + {0xe8bda4, 0xede2}, /* U+8F64 */ + {0xe8be9b, 0xbfc9}, /* U+8F9B */ + {0xe8be9c, 0xede3}, /* U+8F9C */ + {0xe8be9e, 0xbcad}, /* U+8F9E */ + {0xe8be9f, 0xede4}, /* U+8F9F */ + {0xe8bea3, 0xede5}, /* U+8FA3 */ + {0xe8bea4, 0x8ff9e7}, /* U+8FA4 [2000] */ + {0xe8bea6, 0xfcd2}, /* U+8FA6 [2000] */ + {0xe8bea7, 0xd2a1}, /* U+8FA7 */ + {0xe8bea8, 0xd1fe}, /* U+8FA8 */ + {0xe8bead, 0xede6}, /* U+8FAD */ + {0xe8beae, 0xe5f0}, /* U+8FAE */ + {0xe8beaf, 0xede7}, /* U+8FAF */ + {0xe8beb0, 0xc3a4}, /* U+8FB0 */ + {0xe8beb1, 0xbfab}, /* U+8FB1 */ + {0xe8beb2, 0xc7c0}, /* U+8FB2 */ + {0xe8beb4, 0x8ff9e8}, /* U+8FB4 [2000] */ + {0xe8beb5, 0xfcd3}, /* U+8FB5 [2000] */ + {0xe8beb6, 0x8ff9ea}, /* U+8FB6 [2000] */ + {0xe8beb7, 0xede8}, /* U+8FB7 */ + {0xe8beba, 0xcad5}, /* U+8FBA */ + {0xe8bebb, 0xc4d4}, /* U+8FBB */ + {0xe8bebc, 0xb9fe}, /* U+8FBC */ + {0xe8bebf, 0xc3a9}, /* U+8FBF */ + {0xe8bf81, 0x8ff9ec}, /* U+8FC1 [2000] */ + {0xe8bf82, 0xb1aa}, /* U+8FC2 */ + {0xe8bf84, 0xcbf8}, /* U+8FC4 */ + {0xe8bf85, 0xbfd7}, /* U+8FC5 */ + {0xe8bf86, 0x8ff9ed}, /* U+8FC6 [2000] */ + {0xe8bf8a, 0x8ff9ef}, /* U+8FCA [2000] */ + {0xe8bf8d, 0x8ff9f0}, /* U+8FCD [2000] */ + {0xe8bf8e, 0xb7de}, /* U+8FCE */ + {0xe8bf91, 0xb6e1}, /* U+8FD1 */ + {0xe8bf93, 0x8ff9f1}, /* U+8FD3 [2000] */ + {0xe8bf94, 0xcad6}, /* U+8FD4 */ + {0xe8bf95, 0x8ff9f2}, /* U+8FD5 [2000] */ + {0xe8bf9a, 0xede9}, /* U+8FDA */ + {0xe8bfa0, 0x8ff9f3}, /* U+8FE0 [2000] */ + {0xe8bfa2, 0xedeb}, /* U+8FE2 */ + {0xe8bfa4, 0xfcd4}, /* U+8FE4 [2000] */ + {0xe8bfa5, 0xedea}, /* U+8FE5 */ + {0xe8bfa6, 0xb2e0}, /* U+8FE6 */ + {0xe8bfa8, 0xfcd5}, /* U+8FE8 [2000] */ + {0xe8bfa9, 0xc6f6}, /* U+8FE9 */ + {0xe8bfaa, 0xedec}, /* U+8FEA */ + {0xe8bfab, 0xc7f7}, /* U+8FEB */ + {0xe8bfad, 0xc5b3}, /* U+8FED */ + {0xe8bfae, 0xfcd6}, /* U+8FEE [2000] */ + {0xe8bfaf, 0xeded}, /* U+8FEF */ + {0xe8bfb0, 0xbdd2}, /* U+8FF0 */ + {0xe8bfb1, 0x8ff9f4}, /* U+8FF1 [2000] */ + {0xe8bfb4, 0xedef}, /* U+8FF4 */ + {0xe8bfb5, 0x8ff9f5}, /* U+8FF5 [2000] */ + {0xe8bfb7, 0xccc2}, /* U+8FF7 */ + {0xe8bfb8, 0xedfe}, /* U+8FF8 */ + {0xe8bfb9, 0xedf1}, /* U+8FF9 */ + {0xe8bfba, 0xedf2}, /* U+8FFA */ + {0xe8bfbb, 0x8ff9f6}, /* U+8FFB [2000] */ + {0xe8bfbd, 0xc4c9}, /* U+8FFD */ + {0xe98080, 0xc2e0}, /* U+9000 */ + {0xe98081, 0xc1f7}, /* U+9001 */ + {0xe98082, 0x8ff9f7}, /* U+9002 [2000] */ + {0xe98083, 0xc6a8}, /* U+9003 */ + {0xe98085, 0xedf0}, /* U+9005 */ + {0xe98086, 0xb5d5}, /* U+9006 */ + {0xe98088, 0xfcd7}, /* U+9008 [2000] */ + {0xe9808b, 0xedf9}, /* U+900B */ + {0xe9808c, 0x8ff9f8}, /* U+900C [2000] */ + {0xe9808d, 0xedf6}, /* U+900D */ + {0xe9808e, 0xeea5}, /* U+900E */ + {0xe9808f, 0xc6a9}, /* U+900F */ + {0xe98090, 0xc3e0}, /* U+9010 */ + {0xe98091, 0xedf3}, /* U+9011 */ + {0xe98093, 0xc4fe}, /* U+9013 */ + {0xe98094, 0xc5d3}, /* U+9014 */ + {0xe98095, 0xedf4}, /* U+9015 */ + {0xe98096, 0xedf8}, /* U+9016 */ + {0xe98097, 0xbfe0}, /* U+9017 */ + {0xe98099, 0xc7e7}, /* U+9019 */ + {0xe9809a, 0xc4cc}, /* U+901A */ + {0xe9809d, 0xc0c2}, /* U+901D */ + {0xe9809e, 0xedf7}, /* U+901E */ + {0xe9809f, 0xc2ae}, /* U+901F */ + {0xe980a0, 0xc2a4}, /* U+9020 */ + {0xe980a1, 0xedf5}, /* U+9021 */ + {0xe980a2, 0xb0a9}, /* U+9022 */ + {0xe980a3, 0xcfa2}, /* U+9023 */ + {0xe980a7, 0xedfa}, /* U+9027 */ + {0xe980ad, 0xfcd8}, /* U+902D [2000] */ + {0xe980ae, 0xc2e1}, /* U+902E */ + {0xe980b1, 0xbdb5}, /* U+9031 */ + {0xe980b2, 0xbfca}, /* U+9032 */ + {0xe980b5, 0xedfc}, /* U+9035 */ + {0xe980b6, 0xedfb}, /* U+9036 */ + {0xe980b7, 0x8ff9f9}, /* U+9037 [2000] */ + {0xe980b8, 0xb0ef}, /* U+9038 */ + {0xe980b9, 0xedfd}, /* U+9039 */ + {0xe980bc, 0xc9af}, /* U+903C */ + {0xe980be, 0xeea7}, /* U+903E */ + {0xe98181, 0xc6db}, /* U+9041 */ + {0xe98182, 0xbfeb}, /* U+9042 */ + {0xe98183, 0x8ff9fb}, /* U+9043 [2000] */ + {0xe98184, 0x8ff9fc}, /* U+9044 [2000] */ + {0xe98185, 0xc3d9}, /* U+9045 */ + {0xe98187, 0xb6f8}, /* U+9047 */ + {0xe98189, 0xeea6}, /* U+9049 */ + {0xe9818a, 0xcdb7}, /* U+904A */ + {0xe9818b, 0xb1bf}, /* U+904B */ + {0xe9818d, 0xcad7}, /* U+904D */ + {0xe9818e, 0xb2e1}, /* U+904E */ + {0xe9818f, 0xeea1}, /* U+904F */ + {0xe98190, 0xeea2}, /* U+9050 */ + {0xe98191, 0xeea3}, /* U+9051 */ + {0xe98192, 0xeea4}, /* U+9052 */ + {0xe98193, 0xc6bb}, /* U+9053 */ + {0xe98194, 0xc3a3}, /* U+9054 */ + {0xe98195, 0xb0e3}, /* U+9055 */ + {0xe98196, 0xeea8}, /* U+9056 */ + {0xe98198, 0xeea9}, /* U+9058 */ + {0xe98199, 0xf4a3}, /* U+9059 [1983] */ + {0xe9819c, 0xc2bd}, /* U+905C */ + {0xe9819d, 0x8ff9fd}, /* U+905D [2000] */ + {0xe9819e, 0xeeaa}, /* U+905E */ + {0xe981a0, 0xb1f3}, /* U+9060 */ + {0xe981a1, 0xc1cc}, /* U+9061 */ + {0xe981a3, 0xb8af}, /* U+9063 */ + {0xe981a5, 0xcdda}, /* U+9065 */ + {0xe981a8, 0xeeab}, /* U+9068 */ + {0xe981a9, 0xc5ac}, /* U+9069 */ + {0xe981ad, 0xc1f8}, /* U+906D */ + {0xe981ae, 0xbcd7}, /* U+906E */ + {0xe981af, 0xeeac}, /* U+906F */ + {0xe981b2, 0xeeaf}, /* U+9072 */ + {0xe981b5, 0xbde5}, /* U+9075 */ + {0xe981b6, 0xeead}, /* U+9076 */ + {0xe981b7, 0xc1ab}, /* U+9077 */ + {0xe981b8, 0xc1aa}, /* U+9078 */ + {0xe981ba, 0xb0e4}, /* U+907A */ + {0xe981bc, 0xcecb}, /* U+907C */ + {0xe981bd, 0xeeb1}, /* U+907D */ + {0xe981bf, 0xc8f2}, /* U+907F */ + {0xe98280, 0xeeb3}, /* U+9080 */ + {0xe98281, 0xeeb2}, /* U+9081 */ + {0xe98282, 0xeeb0}, /* U+9082 */ + {0xe98283, 0xe3e4}, /* U+9083 */ + {0xe98284, 0xb4d4}, /* U+9084 */ + {0xe98285, 0x8ffaa2}, /* U+9085 [2000] */ + {0xe98287, 0xedee}, /* U+9087 */ + {0xe98288, 0xfcda}, /* U+9088 [2000] */ + {0xe98289, 0xeeb5}, /* U+9089 */ + {0xe9828a, 0xeeb4}, /* U+908A */ + {0xe9828c, 0x8ffaa3}, /* U+908C [2000] */ + {0xe9828f, 0xeeb6}, /* U+908F */ + {0xe98290, 0x8ffaa4}, /* U+9090 [2000] */ + {0xe98291, 0xcdb8}, /* U+9091 */ + {0xe98295, 0xfcdb}, /* U+9095 [2000] */ + {0xe98297, 0xfcdc}, /* U+9097 [2000] */ + {0xe98299, 0xfcdd}, /* U+9099 [2000] */ + {0xe9829b, 0xfcde}, /* U+909B [2000] */ + {0xe982a1, 0x8ffaa6}, /* U+90A1 [2000] */ + {0xe982a2, 0xfcdf}, /* U+90A2 [2000] */ + {0xe982a3, 0xc6e1}, /* U+90A3 */ + {0xe982a6, 0xcbae}, /* U+90A6 */ + {0xe982a8, 0xeeb7}, /* U+90A8 */ + {0xe982aa, 0xbcd9}, /* U+90AA */ + {0xe982af, 0xeeb8}, /* U+90AF */ + {0xe982b0, 0x8ffaa8}, /* U+90B0 [2000] */ + {0xe982b1, 0xeeb9}, /* U+90B1 */ + {0xe982b3, 0xfce0}, /* U+90B3 [2000] */ + {0xe982b5, 0xeeba}, /* U+90B5 */ + {0xe982b6, 0x8ffaa9}, /* U+90B6 [2000] */ + {0xe982b8, 0xc5a1}, /* U+90B8 */ + {0xe982be, 0xfce1}, /* U+90BE [2000] */ + {0xe98381, 0xb0ea}, /* U+90C1 */ + {0xe98383, 0x8ffaaa}, /* U+90C3 [2000] */ + {0xe98384, 0xfce2}, /* U+90C4 [2000] */ + {0xe98385, 0xfce3}, /* U+90C5 [2000] */ + {0xe98387, 0xfce4}, /* U+90C7 [2000] */ + {0xe98388, 0x8ffaab}, /* U+90C8 [2000] */ + {0xe9838a, 0xb9d9}, /* U+90CA */ + {0xe9838e, 0xcfba}, /* U+90CE */ + {0xe98397, 0xfce5}, /* U+90D7 [2000] */ + {0xe9839b, 0xeebe}, /* U+90DB */ + {0xe9839c, 0x8ffaad}, /* U+90DC [2000] */ + {0xe9839d, 0xfce6}, /* U+90DD [2000] */ + {0xe9839e, 0xfce7}, /* U+90DE [2000] */ + {0xe9839f, 0x8ffaae}, /* U+90DF [2000] */ + {0xe983a1, 0xb7b4}, /* U+90E1 */ + {0xe983a2, 0xeebb}, /* U+90E2 */ + {0xe983a4, 0xeebc}, /* U+90E4 */ + {0xe983a8, 0xc9f4}, /* U+90E8 */ + {0xe983ab, 0x8ffab3}, /* U+90EB [2000] */ + {0xe983ad, 0xb3d4}, /* U+90ED */ + {0xe983af, 0xfce8}, /* U+90EF [2000] */ + {0xe983b2, 0x8ffab1}, /* U+90F2 [2000] */ + {0xe983b4, 0xfce9}, /* U+90F4 [2000] */ + {0xe983b5, 0xcdb9}, /* U+90F5 */ + {0xe983b6, 0x8ffab0}, /* U+90F6 [2000] */ + {0xe983b7, 0xb6bf}, /* U+90F7 */ + {0xe983bd, 0xc5d4}, /* U+90FD */ + {0xe983be, 0x8ffab4}, /* U+90FE [2000] */ + {0xe983bf, 0x8ffab5}, /* U+90FF [2000] */ + {0xe98480, 0x8ffab2}, /* U+9100 [2000] */ + {0xe98482, 0xeebf}, /* U+9102 */ + {0xe98484, 0x8ffab6}, /* U+9104 [2000] */ + {0xe98486, 0x8ffab7}, /* U+9106 [2000] */ + {0xe98492, 0xeec0}, /* U+9112 */ + {0xe98494, 0xfceb}, /* U+9114 [2000] */ + {0xe98495, 0xfcec}, /* U+9115 [2000] */ + {0xe98496, 0xfced}, /* U+9116 [2000] */ + {0xe98498, 0x8ffab8}, /* U+9118 [2000] */ + {0xe98499, 0xeec1}, /* U+9119 */ + {0xe9849c, 0x8ffab9}, /* U+911C [2000] */ + {0xe9849e, 0x8ffaba}, /* U+911E [2000] */ + {0xe984a2, 0xfcee}, /* U+9122 [2000] */ + {0xe984a3, 0xfcef}, /* U+9123 [2000] */ + {0xe984a7, 0xfcf0}, /* U+9127 [2000] */ + {0xe984ad, 0xc5a2}, /* U+912D */ + {0xe984af, 0xfcf1}, /* U+912F [2000] */ + {0xe984b0, 0xeec3}, /* U+9130 */ + {0xe984b1, 0xfcf2}, /* U+9131 [2000] */ + {0xe984b2, 0xeec2}, /* U+9132 */ + {0xe984b4, 0xfcf3}, /* U+9134 [2000] */ + {0xe984b7, 0x8ffabb}, /* U+9137 [2000] */ + {0xe984b9, 0x8ffabc}, /* U+9139 [2000] */ + {0xe984ba, 0x8ffabd}, /* U+913A [2000] */ + {0xe984bd, 0xfcf4}, /* U+913D [2000] */ + {0xe98586, 0x8ffabe}, /* U+9146 [2000] */ + {0xe98587, 0x8ffabf}, /* U+9147 [2000] */ + {0xe98588, 0xfcf5}, /* U+9148 [2000] */ + {0xe98589, 0xc6d3}, /* U+9149 */ + {0xe9858a, 0xeec4}, /* U+914A */ + {0xe9858b, 0xbdb6}, /* U+914B */ + {0xe9858c, 0xbce0}, /* U+914C */ + {0xe9858d, 0xc7db}, /* U+914D */ + {0xe9858e, 0xc3f1}, /* U+914E */ + {0xe98592, 0xbcf2}, /* U+9152 */ + {0xe98594, 0xbfec}, /* U+9154 */ + {0xe98596, 0xeec5}, /* U+9156 */ + {0xe98597, 0x8ffac0}, /* U+9157 [2000] */ + {0xe98598, 0xeec6}, /* U+9158 */ + {0xe98599, 0x8ffac1}, /* U+9159 [2000] */ + {0xe9859b, 0xfcf6}, /* U+915B [2000] */ + {0xe985a1, 0x8ffac2}, /* U+9161 [2000] */ + {0xe985a2, 0xbfdd}, /* U+9162 */ + {0xe985a3, 0xeec7}, /* U+9163 */ + {0xe985a4, 0x8ffac3}, /* U+9164 [2000] */ + {0xe985a5, 0xeec8}, /* U+9165 */ + {0xe985a9, 0xeec9}, /* U+9169 */ + {0xe985aa, 0xcdef}, /* U+916A */ + {0xe985ac, 0xbdb7}, /* U+916C */ + {0xe985b2, 0xeecb}, /* U+9172 */ + {0xe985b3, 0xeeca}, /* U+9173 */ + {0xe985b4, 0x8ffac4}, /* U+9174 [2000] */ + {0xe985b5, 0xb9da}, /* U+9175 */ + {0xe985b7, 0xb9f3}, /* U+9177 */ + {0xe985b8, 0xbbc0}, /* U+9178 */ + {0xe985b9, 0x8ffac5}, /* U+9179 [2000] */ + {0xe98682, 0xeece}, /* U+9182 */ + {0xe98683, 0xfcf7}, /* U+9183 [2000] */ + {0xe98685, 0x8ffac6}, /* U+9185 [2000] */ + {0xe98687, 0xbde6}, /* U+9187 */ + {0xe98689, 0xeecd}, /* U+9189 */ + {0xe9868b, 0xeecc}, /* U+918B */ + {0xe9868d, 0xc2e9}, /* U+918D */ + {0xe9868e, 0x8ffac7}, /* U+918E [2000] */ + {0xe98690, 0xb8ef}, /* U+9190 */ + {0xe98692, 0xc0c3}, /* U+9192 */ + {0xe98697, 0xc8b0}, /* U+9197 */ + {0xe9869c, 0xbdb9}, /* U+919C */ + {0xe9869e, 0xfcf8}, /* U+919E [2000] */ + {0xe986a2, 0xeecf}, /* U+91A2 */ + {0xe986a4, 0xbedf}, /* U+91A4 */ + {0xe986a8, 0x8ffac8}, /* U+91A8 [2000] */ + {0xe986aa, 0xeed2}, /* U+91AA */ + {0xe986ab, 0xeed0}, /* U+91AB */ + {0xe986ac, 0xfcf9}, /* U+91AC [2000] */ + {0xe986ae, 0x8ffac9}, /* U+91AE [2000] */ + {0xe986af, 0xeed1}, /* U+91AF */ + {0xe986b1, 0xfcfa}, /* U+91B1 [2000] */ + {0xe986b3, 0x8ffaca}, /* U+91B3 [2000] */ + {0xe986b4, 0xeed4}, /* U+91B4 */ + {0xe986b5, 0xeed3}, /* U+91B5 */ + {0xe986b6, 0x8ffacb}, /* U+91B6 [2000] */ + {0xe986b8, 0xbefa}, /* U+91B8 */ + {0xe986ba, 0xeed5}, /* U+91BA */ + {0xe986bc, 0xfcfb}, /* U+91BC [2000] */ + {0xe98780, 0xeed6}, /* U+91C0 */ + {0xe98781, 0xeed7}, /* U+91C1 */ + {0xe98783, 0x8ffacc}, /* U+91C3 [2000] */ + {0xe98784, 0x8ffacd}, /* U+91C4 [2000] */ + {0xe98786, 0xc8d0}, /* U+91C6 */ + {0xe98787, 0xbad3}, /* U+91C7 */ + {0xe98788, 0xbce1}, /* U+91C8 */ + {0xe98789, 0xeed8}, /* U+91C9 */ + {0xe9878b, 0xeed9}, /* U+91CB */ + {0xe9878c, 0xcea4}, /* U+91CC */ + {0xe9878d, 0xbdc5}, /* U+91CD */ + {0xe9878e, 0xccee}, /* U+91CE */ + {0xe9878f, 0xcecc}, /* U+91CF */ + {0xe98790, 0xeeda}, /* U+91D0 */ + {0xe98791, 0xb6e2}, /* U+91D1 */ + {0xe98796, 0xeedb}, /* U+91D6 */ + {0xe98797, 0xfcfc}, /* U+91D7 [2000] */ + {0xe98798, 0xc5a3}, /* U+91D8 */ + {0xe9879a, 0x8fface}, /* U+91DA [2000] */ + {0xe9879b, 0xeede}, /* U+91DB */ + {0xe9879c, 0xb3f8}, /* U+91DC */ + {0xe9879d, 0xbfcb}, /* U+91DD */ + {0xe9879f, 0xeedc}, /* U+91DF */ + {0xe987a1, 0xeedd}, /* U+91E1 */ + {0xe987a3, 0xc4e0}, /* U+91E3 */ + {0xe987a4, 0xfcfe}, /* U+91E4 [2000] */ + {0xe987a5, 0xfda1}, /* U+91E5 [2000] */ + {0xe987a6, 0xcbd5}, /* U+91E6 */ + {0xe987a7, 0xb6fc}, /* U+91E7 */ + {0xe987ac, 0x8ffad1}, /* U+91EC [2000] */ + {0xe987ad, 0xfda2}, /* U+91ED [2000] */ + {0xe987ae, 0x8ffad2}, /* U+91EE [2000] */ + {0xe987b1, 0xfda3}, /* U+91F1 [2000] */ + {0xe987b5, 0xeee0}, /* U+91F5 */ + {0xe987b6, 0xeee1}, /* U+91F6 */ + {0xe987bb, 0xfcfd}, /* U+91FB [2000] */ + {0xe987bc, 0xeedf}, /* U+91FC */ + {0xe987bf, 0xeee3}, /* U+91FF */ + {0xe98881, 0x8ffad3}, /* U+9201 [2000] */ + {0xe98887, 0xfda4}, /* U+9207 [2000] */ + {0xe9888a, 0x8ffad4}, /* U+920A [2000] */ + {0xe9888d, 0xc6df}, /* U+920D */ + {0xe9888e, 0xb3c3}, /* U+920E */ + {0xe98890, 0xfda5}, /* U+9210 [2000] */ + {0xe98891, 0xeee7}, /* U+9211 */ + {0xe98894, 0xeee4}, /* U+9214 */ + {0xe98895, 0xeee6}, /* U+9215 */ + {0xe98896, 0x8ffad5}, /* U+9216 [2000] */ + {0xe98897, 0x8ffad6}, /* U+9217 [2000] */ + {0xe9889e, 0xeee2}, /* U+921E */ + {0xe988a9, 0xefcf}, /* U+9229 */ + {0xe988ac, 0xeee5}, /* U+922C */ + {0xe988b3, 0x8ffad8}, /* U+9233 [2000] */ + {0xe988b4, 0xceeb}, /* U+9234 */ + {0xe988b7, 0xb8da}, /* U+9237 */ + {0xe988b8, 0xfda6}, /* U+9238 [2000] */ + {0xe988b9, 0xfda7}, /* U+9239 [2000] */ + {0xe988ba, 0xfda8}, /* U+923A [2000] */ + {0xe988bc, 0xfda9}, /* U+923C [2000] */ + {0xe988bf, 0xeeef}, /* U+923F */ + {0xe98980, 0xfdaa}, /* U+9240 [2000] */ + {0xe98982, 0x8ffad9}, /* U+9242 [2000] */ + {0xe98983, 0xfdab}, /* U+9243 [2000] */ + {0xe98984, 0xc5b4}, /* U+9244 */ + {0xe98985, 0xeeea}, /* U+9245 */ + {0xe98987, 0x8ffada}, /* U+9247 [2000] */ + {0xe98988, 0xeeed}, /* U+9248 */ + {0xe98989, 0xeeeb}, /* U+9249 */ + {0xe9898a, 0x8ffadb}, /* U+924A [2000] */ + {0xe9898b, 0xeef0}, /* U+924B */ + {0xe9898e, 0x8ffadc}, /* U+924E [2000] */ + {0xe9898f, 0xfdac}, /* U+924F [2000] */ + {0xe98990, 0xeef1}, /* U+9250 */ + {0xe98991, 0x8ffadd}, /* U+9251 [2000] */ + {0xe98996, 0x8ffade}, /* U+9256 [2000] */ + {0xe98997, 0xeee9}, /* U+9257 */ + {0xe98999, 0x8ffadf}, /* U+9259 [2000] */ + {0xe9899a, 0xeef6}, /* U+925A */ + {0xe9899b, 0xb1f4}, /* U+925B */ + {0xe9899e, 0xeee8}, /* U+925E */ + {0xe989a0, 0x8ffae0}, /* U+9260 [2000] */ + {0xe989a1, 0x8ffae1}, /* U+9261 [2000] */ + {0xe989a2, 0xc8ad}, /* U+9262 */ + {0xe989a4, 0xeeec}, /* U+9264 */ + {0xe989a5, 0x8ffae2}, /* U+9265 [2000] */ + {0xe989a6, 0xbee0}, /* U+9266 */ + {0xe989a7, 0x8ffae3}, /* U+9267 [2000] */ + {0xe989a8, 0x8ffae4}, /* U+9268 [2000] */ + {0xe989b1, 0xb9db}, /* U+9271 */ + {0xe989b8, 0xfdad}, /* U+9278 [2000] */ + {0xe989bc, 0x8ffae7}, /* U+927C [2000] */ + {0xe989bd, 0x8ffae8}, /* U+927D [2000] */ + {0xe989be, 0xcbc8}, /* U+927E */ + {0xe989bf, 0x8ffae9}, /* U+927F [2000] */ + {0xe98a80, 0xb6e4}, /* U+9280 */ + {0xe98a83, 0xbdc6}, /* U+9283 */ + {0xe98a85, 0xc6bc}, /* U+9285 */ + {0xe98a88, 0xfdae}, /* U+9288 [2000] */ + {0xe98a89, 0x8ffaea}, /* U+9289 [2000] */ + {0xe98a8d, 0x8ffaeb}, /* U+928D [2000] */ + {0xe98a91, 0xc1ad}, /* U+9291 */ + {0xe98a93, 0xeef4}, /* U+9293 */ + {0xe98a95, 0xeeee}, /* U+9295 */ + {0xe98a96, 0xeef3}, /* U+9296 */ + {0xe98a97, 0x8ffaec}, /* U+9297 [2000] */ + {0xe98a98, 0xccc3}, /* U+9298 */ + {0xe98a99, 0x8ffaed}, /* U+9299 [2000] */ + {0xe98a9a, 0xc4b8}, /* U+929A */ + {0xe98a9b, 0xeef5}, /* U+929B */ + {0xe98a9c, 0xeef2}, /* U+929C */ + {0xe98a9f, 0x8ffaee}, /* U+929F [2000] */ + {0xe98aa7, 0x8ffaef}, /* U+92A7 [2000] */ + {0xe98aab, 0x8ffaf0}, /* U+92AB [2000] */ + {0xe98aad, 0xc1ac}, /* U+92AD */ + {0xe98ab2, 0x8ffaf3}, /* U+92B2 [2000] */ + {0xe98ab7, 0xeef9}, /* U+92B7 */ + {0xe98ab9, 0xeef8}, /* U+92B9 */ + {0xe98abf, 0x8ffaf4}, /* U+92BF [2000] */ + {0xe98b80, 0x8ffaf5}, /* U+92C0 [2000] */ + {0xe98b82, 0xfdaf}, /* U+92C2 [2000] */ + {0xe98b86, 0x8ffaf6}, /* U+92C6 [2000] */ + {0xe98b8b, 0xfdb0}, /* U+92CB [2000] */ + {0xe98b8c, 0xfdb1}, /* U+92CC [2000] */ + {0xe98b8e, 0x8ffaf7}, /* U+92CE [2000] */ + {0xe98b8f, 0xeef7}, /* U+92CF */ + {0xe98b90, 0x8ffaf8}, /* U+92D0 [2000] */ + {0xe98b92, 0xcbaf}, /* U+92D2 */ + {0xe98b93, 0xfdb2}, /* U+92D3 [2000] */ + {0xe98b97, 0x8ffaf9}, /* U+92D7 [2000] */ + {0xe98b99, 0x8ffafa}, /* U+92D9 [2000] */ + {0xe98ba0, 0xfdb3}, /* U+92E0 [2000] */ + {0xe98ba4, 0xbdfb}, /* U+92E4 */ + {0xe98ba5, 0x8ffafb}, /* U+92E5 [2000] */ + {0xe98ba7, 0x8ffafc}, /* U+92E7 [2000] */ + {0xe98ba9, 0xeefa}, /* U+92E9 */ + {0xe98baa, 0xcadf}, /* U+92EA */ + {0xe98bad, 0xb1d4}, /* U+92ED */ + {0xe98bb2, 0xc9c6}, /* U+92F2 */ + {0xe98bb3, 0xc3f2}, /* U+92F3 */ + {0xe98bb7, 0x8ffba2}, /* U+92F7 [2000] */ + {0xe98bb8, 0xb5f8}, /* U+92F8 */ + {0xe98bb9, 0x8ffba3}, /* U+92F9 [2000] */ + {0xe98bba, 0xeefc}, /* U+92FA */ + {0xe98bbb, 0x8ffba4}, /* U+92FB [2000] */ + {0xe98bbc, 0xb9dd}, /* U+92FC */ + {0xe98bbf, 0xfdb4}, /* U+92FF [2000] */ + {0xe98c82, 0x8ffba5}, /* U+9302 [2000] */ + {0xe98c84, 0xfdb5}, /* U+9304 [2000] */ + {0xe98c86, 0xbbac}, /* U+9306 */ + {0xe98c8d, 0x8ffba6}, /* U+930D [2000] */ + {0xe98c8f, 0xeefb}, /* U+930F */ + {0xe98c90, 0xbfed}, /* U+9310 */ + {0xe98c91, 0x8ffafd}, /* U+9311 [2000] */ + {0xe98c95, 0x8ffba7}, /* U+9315 [2000] */ + {0xe98c98, 0xbfee}, /* U+9318 */ + {0xe98c99, 0xefa1}, /* U+9319 */ + {0xe98c9a, 0xefa3}, /* U+931A */ + {0xe98c9d, 0x8ffba8}, /* U+931D [2000] */ + {0xe98c9e, 0x8ffba9}, /* U+931E [2000] */ + {0xe98c9f, 0xfdb6}, /* U+931F [2000] */ + {0xe98ca0, 0xbefb}, /* U+9320 */ + {0xe98ca1, 0xfdb7}, /* U+9321 [2000] */ + {0xe98ca2, 0xefa2}, /* U+9322 */ + {0xe98ca3, 0xefa4}, /* U+9323 */ + {0xe98ca5, 0xfdb8}, /* U+9325 [2000] */ + {0xe98ca6, 0xb6d3}, /* U+9326 */ + {0xe98ca7, 0x8ffbaa}, /* U+9327 [2000] */ + {0xe98ca8, 0xc9c5}, /* U+9328 */ + {0xe98ca9, 0x8ffbab}, /* U+9329 [2000] */ + {0xe98cab, 0xbce2}, /* U+932B */ + {0xe98cac, 0xcfa3}, /* U+932C */ + {0xe98cae, 0xeefe}, /* U+932E */ + {0xe98caf, 0xbaf8}, /* U+932F */ + {0xe98cb2, 0xcfbf}, /* U+9332 */ + {0xe98cb5, 0xefa6}, /* U+9335 */ + {0xe98cba, 0xefa5}, /* U+933A */ + {0xe98cbb, 0xefa7}, /* U+933B */ + {0xe98d84, 0xeefd}, /* U+9344 */ + {0xe98d87, 0x8ffbae}, /* U+9347 [2000] */ + {0xe98d88, 0xfdb9}, /* U+9348 [2000] */ + {0xe98d89, 0xfdba}, /* U+9349 [2000] */ + {0xe98d8a, 0xfdbb}, /* U+934A [2000] */ + {0xe98d8b, 0xc6e9}, /* U+934B */ + {0xe98d8d, 0xc5d5}, /* U+934D */ + {0xe98d91, 0x8ffbaf}, /* U+9351 [2000] */ + {0xe98d94, 0xc4d7}, /* U+9354 */ + {0xe98d96, 0xefac}, /* U+9356 */ + {0xe98d97, 0x8ffbb0}, /* U+9357 [2000] */ + {0xe98d9a, 0x8ffbb1}, /* U+935A [2000] */ + {0xe98d9b, 0xc3c3}, /* U+935B */ + {0xe98d9c, 0xefa8}, /* U+935C */ + {0xe98da0, 0xefa9}, /* U+9360 */ + {0xe98da4, 0xfdbc}, /* U+9364 [2000] */ + {0xe98da5, 0xfdbd}, /* U+9365 [2000] */ + {0xe98daa, 0xfdbe}, /* U+936A [2000] */ + {0xe98dab, 0x8ffbb2}, /* U+936B [2000] */ + {0xe98dac, 0xb7ad}, /* U+936C */ + {0xe98dae, 0xefab}, /* U+936E */ + {0xe98db0, 0xfdbf}, /* U+9370 [2000] */ + {0xe98db1, 0x8ffbb3}, /* U+9371 [2000] */ + {0xe98db3, 0x8ffbb4}, /* U+9373 [2000] */ + {0xe98db5, 0xb8b0}, /* U+9375 */ + {0xe98dbc, 0xefaa}, /* U+937C */ + {0xe98dbe, 0xbee1}, /* U+937E */ + {0xe98e88, 0x8ffbb8}, /* U+9388 [2000] */ + {0xe98e8b, 0x8ffbb9}, /* U+938B [2000] */ + {0xe98e8c, 0xb3f9}, /* U+938C */ + {0xe98e8f, 0x8ffbba}, /* U+938F [2000] */ + {0xe98e94, 0xefb0}, /* U+9394 */ + {0xe98e96, 0xbabf}, /* U+9396 */ + {0xe98e97, 0xc1f9}, /* U+9397 */ + {0xe98e9a, 0xc4ca}, /* U+939A */ + {0xe98e9b, 0xfdc0}, /* U+939B [2000] */ + {0xe98e9e, 0x8ffbbb}, /* U+939E [2000] */ + {0xe98ea1, 0x8ffbb5}, /* U+93A1 [2000] */ + {0xe98ea3, 0xfdc1}, /* U+93A3 [2000] */ + {0xe98ea7, 0xb3bb}, /* U+93A7 */ + {0xe98eac, 0xefae}, /* U+93AC */ + {0xe98ead, 0xefaf}, /* U+93AD */ + {0xe98eae, 0xc4c3}, /* U+93AE */ + {0xe98eb0, 0xefad}, /* U+93B0 */ + {0xe98eb9, 0xefb1}, /* U+93B9 */ + {0xe98eba, 0xfdc2}, /* U+93BA [2000] */ + {0xe98f81, 0x8ffbc0}, /* U+93C1 [2000] */ + {0xe98f83, 0xefb7}, /* U+93C3 */ + {0xe98f86, 0xfdc3}, /* U+93C6 [2000] */ + {0xe98f87, 0x8ffbc1}, /* U+93C7 [2000] */ + {0xe98f88, 0xefba}, /* U+93C8 */ + {0xe98f90, 0xefb9}, /* U+93D0 */ + {0xe98f91, 0xc5ad}, /* U+93D1 */ + {0xe98f96, 0xefb2}, /* U+93D6 */ + {0xe98f97, 0xefb3}, /* U+93D7 */ + {0xe98f98, 0xefb6}, /* U+93D8 */ + {0xe98f9c, 0x8ffbc2}, /* U+93DC [2000] */ + {0xe98f9d, 0xefb8}, /* U+93DD */ + {0xe98f9e, 0xfdc4}, /* U+93DE [2000] */ + {0xe98f9f, 0xfdc5}, /* U+93DF [2000] */ + {0xe98fa1, 0xb6c0}, /* U+93E1 */ + {0xe98fa2, 0x8ffbc3}, /* U+93E2 [2000] */ + {0xe98fa4, 0xefbb}, /* U+93E4 */ + {0xe98fa5, 0xefb5}, /* U+93E5 */ + {0xe98fa7, 0x8ffbc4}, /* U+93E7 [2000] */ + {0xe98fa8, 0xefb4}, /* U+93E8 */ + {0xe98fb1, 0x8ffbbf}, /* U+93F1 [2000] */ + {0xe98fb5, 0x8ffbbc}, /* U+93F5 [2000] */ + {0xe98fbb, 0x8ffbc9}, /* U+93FB [2000] */ + {0xe98fbd, 0xfdc7}, /* U+93FD [2000] */ + {0xe99083, 0xefbf}, /* U+9403 */ + {0xe99084, 0xfdc6}, /* U+9404 [2000] */ + {0xe99087, 0xefc0}, /* U+9407 */ + {0xe99089, 0x8ffbc5}, /* U+9409 [2000] */ + {0xe9908f, 0x8ffbc6}, /* U+940F [2000] */ + {0xe99090, 0xefc1}, /* U+9410 */ + {0xe99093, 0xefbe}, /* U+9413 */ + {0xe99094, 0xefbd}, /* U+9414 */ + {0xe99096, 0x8ffbc7}, /* U+9416 [2000] */ + {0xe99097, 0x8ffbc8}, /* U+9417 [2000] */ + {0xe99098, 0xbee2}, /* U+9418 */ + {0xe99099, 0xc6aa}, /* U+9419 */ + {0xe9909a, 0xefbc}, /* U+941A */ + {0xe990a1, 0xefc5}, /* U+9421 */ + {0xe990ab, 0xefc3}, /* U+942B */ + {0xe990b2, 0x8ffbca}, /* U+9432 [2000] */ + {0xe990b3, 0xfdc8}, /* U+9433 [2000] */ + {0xe990b4, 0x8ffbcb}, /* U+9434 [2000] */ + {0xe990b5, 0xefc4}, /* U+9435 */ + {0xe990b6, 0xefc2}, /* U+9436 */ + {0xe990b8, 0xc2f8}, /* U+9438 */ + {0xe990ba, 0xefc6}, /* U+943A */ + {0xe990bb, 0x8ffbcc}, /* U+943B [2000] */ + {0xe99181, 0xefc7}, /* U+9441 */ + {0xe99184, 0xefc9}, /* U+9444 */ + {0xe99185, 0x8ffbcd}, /* U+9445 [2000] */ + {0xe9918a, 0xfdc9}, /* U+944A [2000] */ + {0xe99191, 0xb4d5}, /* U+9451 */ + {0xe99192, 0xefc8}, /* U+9452 */ + {0xe99193, 0xccfa}, /* U+9453 */ + {0xe9919a, 0xefd4}, /* U+945A */ + {0xe9919b, 0xefca}, /* U+945B */ + {0xe9919e, 0xefcd}, /* U+945E */ + {0xe991a0, 0xefcb}, /* U+9460 */ + {0xe991a2, 0xefcc}, /* U+9462 */ + {0xe991a3, 0xfdca}, /* U+9463 [2000] */ + {0xe991aa, 0xefce}, /* U+946A */ + {0xe991ab, 0xfdcb}, /* U+946B [2000] */ + {0xe991ad, 0x8ffbd0}, /* U+946D [2000] */ + {0xe991af, 0x8ffbd1}, /* U+946F [2000] */ + {0xe991b0, 0xefd0}, /* U+9470 */ + {0xe991b1, 0xfdcc}, /* U+9471 [2000] */ + {0xe991b2, 0xfdcd}, /* U+9472 [2000] */ + {0xe991b5, 0xefd1}, /* U+9475 */ + {0xe991b7, 0xefd2}, /* U+9477 */ + {0xe991bc, 0xefd5}, /* U+947C */ + {0xe991bd, 0xefd3}, /* U+947D */ + {0xe991be, 0xefd6}, /* U+947E */ + {0xe991bf, 0xefd8}, /* U+947F */ + {0xe99281, 0xefd7}, /* U+9481 */ + {0xe995b7, 0xc4b9}, /* U+9577 */ + {0xe995b8, 0x8ffbd2}, /* U+9578 [2000] */ + {0xe995b9, 0x8ffbd3}, /* U+9579 [2000] */ + {0xe99680, 0xcce7}, /* U+9580 */ + {0xe99682, 0xefd9}, /* U+9582 */ + {0xe99683, 0xc1ae}, /* U+9583 */ + {0xe99686, 0x8ffbd4}, /* U+9586 [2000] */ + {0xe99687, 0xefda}, /* U+9587 */ + {0xe99689, 0xcac4}, /* U+9589 */ + {0xe9968a, 0xefdb}, /* U+958A */ + {0xe9968b, 0xb3ab}, /* U+958B */ + {0xe9968c, 0x8ffbd5}, /* U+958C [2000] */ + {0xe9968d, 0x8ffbd6}, /* U+958D [2000] */ + {0xe9968e, 0xfdce}, /* U+958E [2000] */ + {0xe9968f, 0xb1bc}, /* U+958F */ + {0xe99691, 0xb4d7}, /* U+9591 */ + {0xe99693, 0xb4d6}, /* U+9593 */ + {0xe99694, 0xefdc}, /* U+9594 */ + {0xe99696, 0xefdd}, /* U+9596 */ + {0xe99698, 0xefde}, /* U+9598 */ + {0xe99699, 0xefdf}, /* U+9599 */ + {0xe9969f, 0xfdcf}, /* U+959F [2000] */ + {0xe996a0, 0xefe0}, /* U+95A0 */ + {0xe996a2, 0xb4d8}, /* U+95A2 */ + {0xe996a3, 0xb3d5}, /* U+95A3 */ + {0xe996a4, 0xb9de}, /* U+95A4 */ + {0xe996a5, 0xc8b6}, /* U+95A5 */ + {0xe996a6, 0xfdd0}, /* U+95A6 [2000] */ + {0xe996a7, 0xefe2}, /* U+95A7 */ + {0xe996a8, 0xefe1}, /* U+95A8 */ + {0xe996a9, 0xfdd1}, /* U+95A9 [2000] */ + {0xe996ab, 0x8ffbd8}, /* U+95AB [2000] */ + {0xe996ac, 0xfdd2}, /* U+95AC [2000] */ + {0xe996ad, 0xefe3}, /* U+95AD */ + {0xe996b2, 0xb1dc}, /* U+95B2 */ + {0xe996b4, 0x8ffbd9}, /* U+95B4 [2000] */ + {0xe996b6, 0xfdd3}, /* U+95B6 [2000] */ + {0xe996b9, 0xefe6}, /* U+95B9 */ + {0xe996bb, 0xefe5}, /* U+95BB */ + {0xe996bc, 0xefe4}, /* U+95BC */ + {0xe996bd, 0xfdd4}, /* U+95BD [2000] */ + {0xe996be, 0xefe7}, /* U+95BE */ + {0xe99783, 0xefea}, /* U+95C3 */ + {0xe99787, 0xb0c7}, /* U+95C7 */ + {0xe99788, 0x8ffbdb}, /* U+95C8 [2000] */ + {0xe9978a, 0xefe8}, /* U+95CA */ + {0xe9978b, 0xfdd5}, /* U+95CB [2000] */ + {0xe9978c, 0xefec}, /* U+95CC */ + {0xe9978d, 0xefeb}, /* U+95CD */ + {0xe99790, 0xfdd6}, /* U+95D0 [2000] */ + {0xe99793, 0xfdd7}, /* U+95D3 [2000] */ + {0xe99794, 0xefee}, /* U+95D4 */ + {0xe99795, 0xefed}, /* U+95D5 */ + {0xe99796, 0xefef}, /* U+95D6 */ + {0xe99798, 0xc6ae}, /* U+95D8 */ + {0xe9979a, 0xfdd9}, /* U+95DA [2000] */ + {0xe9979c, 0xeff0}, /* U+95DC */ + {0xe9979e, 0xfdda}, /* U+95DE [2000] */ + {0xe997a1, 0xeff1}, /* U+95E1 */ + {0xe997a2, 0xeff3}, /* U+95E2 */ + {0xe997a5, 0xeff2}, /* U+95E5 */ + {0xe9989c, 0xc9ec}, /* U+961C */ + {0xe9989d, 0x8ffaa5}, /* U+961D [2000] */ + {0xe998a1, 0xeff4}, /* U+9621 */ + {0xe998a8, 0xeff5}, /* U+9628 */ + {0xe998aa, 0xbae5}, /* U+962A */ + {0xe998ac, 0x8ffbde}, /* U+962C [2000] */ + {0xe998ae, 0xeff6}, /* U+962E */ + {0xe998af, 0xeff7}, /* U+962F */ + {0xe998b2, 0xcbc9}, /* U+9632 */ + {0xe998b3, 0x8ffbdf}, /* U+9633 [2000] */ + {0xe998b4, 0x8ffbe0}, /* U+9634 [2000] */ + {0xe998bb, 0xc1cb}, /* U+963B */ + {0xe998bc, 0x8ffbe2}, /* U+963C [2000] */ + {0xe998bf, 0xb0a4}, /* U+963F */ + {0xe99980, 0xc2cb}, /* U+9640 */ + {0xe99981, 0x8ffbe3}, /* U+9641 [2000] */ + {0xe99982, 0xeff8}, /* U+9642 */ + {0xe99984, 0xc9ed}, /* U+9644 */ + {0xe9998b, 0xeffb}, /* U+964B */ + {0xe9998c, 0xeff9}, /* U+964C */ + {0xe9998d, 0xb9df}, /* U+964D */ + {0xe9998f, 0xeffa}, /* U+964F */ + {0xe99990, 0xb8c2}, /* U+9650 */ + {0xe99998, 0xfddb}, /* U+9658 [2000] */ + {0xe9999b, 0xcac5}, /* U+965B */ + {0xe9999c, 0xeffd}, /* U+965C */ + {0xe9999d, 0xf0a1}, /* U+965D */ + {0xe9999e, 0xeffe}, /* U+965E */ + {0xe9999f, 0xf0a2}, /* U+965F */ + {0xe999a1, 0x8ffbe4}, /* U+9661 [2000] */ + {0xe999a2, 0xb1a1}, /* U+9662 */ + {0xe999a3, 0xbfd8}, /* U+9663 */ + {0xe999a4, 0xbdfc}, /* U+9664 */ + {0xe999a5, 0xb4d9}, /* U+9665 */ + {0xe999a6, 0xf0a3}, /* U+9666 */ + {0xe999aa, 0xc7e6}, /* U+966A */ + {0xe999ac, 0xf0a5}, /* U+966C */ + {0xe999b0, 0xb1a2}, /* U+9670 */ + {0xe999b2, 0xf0a4}, /* U+9672 */ + {0xe999b3, 0xc4c4}, /* U+9673 */ + {0xe999b5, 0xcecd}, /* U+9675 */ + {0xe999b6, 0xc6ab}, /* U+9676 */ + {0xe999b7, 0xeffc}, /* U+9677 */ + {0xe999b8, 0xcea6}, /* U+9678 */ + {0xe999ba, 0xb8b1}, /* U+967A */ + {0xe999bd, 0xcddb}, /* U+967D */ + {0xe99a82, 0x8ffbe6}, /* U+9682 [2000] */ + {0xe99a84, 0xfddc}, /* U+9684 [2000] */ + {0xe99a85, 0xb6f9}, /* U+9685 */ + {0xe99a86, 0xceb4}, /* U+9686 */ + {0xe99a88, 0xb7a8}, /* U+9688 */ + {0xe99a8a, 0xc2e2}, /* U+968A */ + {0xe99a8b, 0xe7a1}, /* U+968B */ + {0xe99a8d, 0xf0a6}, /* U+968D */ + {0xe99a8e, 0xb3ac}, /* U+968E */ + {0xe99a8f, 0xbfef}, /* U+968F */ + {0xe99a94, 0xb3d6}, /* U+9694 */ + {0xe99a95, 0xf0a8}, /* U+9695 */ + {0xe99a97, 0xf0a9}, /* U+9697 */ + {0xe99a98, 0xf0a7}, /* U+9698 */ + {0xe99a99, 0xb7e4}, /* U+9699 */ + {0xe99a9a, 0x8ffbe8}, /* U+969A [2000] */ + {0xe99a9b, 0xbadd}, /* U+969B */ + {0xe99a9c, 0xbee3}, /* U+969C */ + {0xe99a9d, 0xfdde}, /* U+969D [2000] */ + {0xe99aa0, 0xb1a3}, /* U+96A0 */ + {0xe99aa3, 0xced9}, /* U+96A3 */ + {0xe99aa4, 0xfddf}, /* U+96A4 [2000] */ + {0xe99aa5, 0xfde0}, /* U+96A5 [2000] */ + {0xe99aa7, 0xf0ab}, /* U+96A7 */ + {0xe99aa8, 0xeeae}, /* U+96A8 */ + {0xe99aa9, 0x8ffbeb}, /* U+96A9 [2000] */ + {0xe99aaa, 0xf0aa}, /* U+96AA */ + {0xe99aaf, 0x8ffbec}, /* U+96AF [2000] */ + {0xe99ab0, 0xf0ae}, /* U+96B0 */ + {0xe99ab1, 0xf0ac}, /* U+96B1 */ + {0xe99ab2, 0xf0ad}, /* U+96B2 */ + {0xe99ab3, 0x8ffbed}, /* U+96B3 [2000] */ + {0xe99ab4, 0xf0af}, /* U+96B4 */ + {0xe99ab6, 0xf0b0}, /* U+96B6 */ + {0xe99ab7, 0xceec}, /* U+96B7 */ + {0xe99ab8, 0xf0b1}, /* U+96B8 */ + {0xe99ab9, 0xf0b2}, /* U+96B9 */ + {0xe99aba, 0x8ffbee}, /* U+96BA [2000] */ + {0xe99abb, 0xc0c9}, /* U+96BB */ + {0xe99abc, 0xc8bb}, /* U+96BC */ + {0xe99abd, 0x8ffbef}, /* U+96BD [2000] */ + {0xe99b80, 0xbffd}, /* U+96C0 */ + {0xe99b81, 0xb4e7}, /* U+96C1 */ + {0xe99b84, 0xcdba}, /* U+96C4 */ + {0xe99b85, 0xb2ed}, /* U+96C5 */ + {0xe99b86, 0xbdb8}, /* U+96C6 */ + {0xe99b87, 0xb8db}, /* U+96C7 */ + {0xe99b89, 0xf0b5}, /* U+96C9 */ + {0xe99b8b, 0xf0b4}, /* U+96CB */ + {0xe99b8c, 0xbbf3}, /* U+96CC */ + {0xe99b8d, 0xf0b6}, /* U+96CD */ + {0xe99b8e, 0xf0b3}, /* U+96CE */ + {0xe99b91, 0xbba8}, /* U+96D1 */ + {0xe99b92, 0xfde1}, /* U+96D2 [2000] */ + {0xe99b95, 0xf0ba}, /* U+96D5 */ + {0xe99b96, 0xeaad}, /* U+96D6 */ + {0xe99b98, 0x8ffbf2}, /* U+96D8 [2000] */ + {0xe99b99, 0xd2d6}, /* U+96D9 */ + {0xe99b9a, 0x8ffbf3}, /* U+96DA [2000] */ + {0xe99b9b, 0xbff7}, /* U+96DB */ + {0xe99b9c, 0xf0b8}, /* U+96DC */ + {0xe99b9d, 0x8ffbf4}, /* U+96DD [2000] */ + {0xe99b9e, 0xfde2}, /* U+96DE [2000] */ + {0xe99ba2, 0xcea5}, /* U+96E2 */ + {0xe99ba3, 0xc6f1}, /* U+96E3 */ + {0xe99ba8, 0xb1ab}, /* U+96E8 */ + {0xe99ba9, 0xfde4}, /* U+96E9 [2000] */ + {0xe99baa, 0xc0e3}, /* U+96EA */ + {0xe99bab, 0xbcb6}, /* U+96EB */ + {0xe99baf, 0xfde5}, /* U+96EF [2000] */ + {0xe99bb0, 0xcab7}, /* U+96F0 */ + {0xe99bb2, 0xb1c0}, /* U+96F2 */ + {0xe99bb6, 0xceed}, /* U+96F6 */ + {0xe99bb7, 0xcdeb}, /* U+96F7 */ + {0xe99bb9, 0xf0bb}, /* U+96F9 */ + {0xe99bbb, 0xc5c5}, /* U+96FB */ + {0xe99c80, 0xbcfb}, /* U+9700 */ + {0xe99c84, 0xf0bc}, /* U+9704 */ + {0xe99c86, 0xf0bd}, /* U+9706 */ + {0xe99c87, 0xbfcc}, /* U+9707 */ + {0xe99c88, 0xf0be}, /* U+9708 */ + {0xe99c8a, 0xceee}, /* U+970A */ + {0xe99c8d, 0xf0b9}, /* U+970D */ + {0xe99c8e, 0xf0c0}, /* U+970E */ + {0xe99c8f, 0xf0c2}, /* U+970F */ + {0xe99c91, 0xf0c1}, /* U+9711 */ + {0xe99c93, 0xf0bf}, /* U+9713 */ + {0xe99c94, 0x8ffbf6}, /* U+9714 [2000] */ + {0xe99c96, 0xf0c3}, /* U+9716 */ + {0xe99c99, 0xf0c4}, /* U+9719 */ + {0xe99c9c, 0xc1fa}, /* U+971C */ + {0xe99c9e, 0xb2e2}, /* U+971E */ + {0xe99ca3, 0x8ffbf7}, /* U+9723 [2000] */ + {0xe99ca4, 0xf0c5}, /* U+9724 */ + {0xe99ca7, 0xccb8}, /* U+9727 */ + {0xe99caa, 0xf0c6}, /* U+972A */ + {0xe99cb0, 0xf0c7}, /* U+9730 */ + {0xe99cb2, 0xcfaa}, /* U+9732 */ + {0xe99cb3, 0xfde6}, /* U+9733 [2000] */ + {0xe99cb6, 0x8ffbf9}, /* U+9736 [2000] */ + {0xe99cb8, 0xdbb1}, /* U+9738 */ + {0xe99cb9, 0xf0c8}, /* U+9739 */ + {0xe99cbb, 0xfde7}, /* U+973B [2000] */ + {0xe99cbd, 0xf0c9}, /* U+973D */ + {0xe99cbe, 0xf0ca}, /* U+973E */ + {0xe99d81, 0x8ffbfa}, /* U+9741 [2000] */ + {0xe99d82, 0xf0ce}, /* U+9742 */ + {0xe99d84, 0xf0cb}, /* U+9744 */ + {0xe99d86, 0xf0cc}, /* U+9746 */ + {0xe99d87, 0x8ffbfb}, /* U+9747 [2000] */ + {0xe99d88, 0xf0cd}, /* U+9748 */ + {0xe99d89, 0xf0cf}, /* U+9749 */ + {0xe99d8d, 0xfde8}, /* U+974D [2000] */ + {0xe99d8e, 0xfde9}, /* U+974E [2000] */ + {0xe99d8f, 0xfdea}, /* U+974F [2000] */ + {0xe99d92, 0xc0c4}, /* U+9752 */ + {0xe99d95, 0x8ffbfc}, /* U+9755 [2000] */ + {0xe99d96, 0xccf7}, /* U+9756 */ + {0xe99d97, 0x8ffbfd}, /* U+9757 [2000] */ + {0xe99d99, 0xc0c5}, /* U+9759 */ + {0xe99d9a, 0xfdeb}, /* U+975A [2000] */ + {0xe99d9b, 0x8ffbfe}, /* U+975B [2000] */ + {0xe99d9c, 0xf0d0}, /* U+975C */ + {0xe99d9e, 0xc8f3}, /* U+975E */ + {0xe99da0, 0xf0d1}, /* U+9760 */ + {0xe99da1, 0xf3d3}, /* U+9761 */ + {0xe99da2, 0xcccc}, /* U+9762 */ + {0xe99da4, 0xf0d2}, /* U+9764 */ + {0xe99da6, 0xf0d3}, /* U+9766 */ + {0xe99da8, 0xf0d4}, /* U+9768 */ + {0xe99da9, 0xb3d7}, /* U+9769 */ + {0xe99daa, 0x8ffca1}, /* U+976A [2000] */ + {0xe99dab, 0xf0d6}, /* U+976B */ + {0xe99dad, 0xbfd9}, /* U+976D */ + {0xe99dae, 0xfdec}, /* U+976E [2000] */ + {0xe99db1, 0xf0d7}, /* U+9771 */ + {0xe99db3, 0xfded}, /* U+9773 [2000] */ + {0xe99db4, 0xb7a4}, /* U+9774 */ + {0xe99db9, 0xf0d8}, /* U+9779 */ + {0xe99dba, 0xf0dc}, /* U+977A */ + {0xe99dbc, 0xf0da}, /* U+977C */ + {0xe99e81, 0xf0db}, /* U+9781 */ + {0xe99e84, 0xb3f3}, /* U+9784 */ + {0xe99e85, 0xf0d9}, /* U+9785 */ + {0xe99e86, 0xf0dd}, /* U+9786 */ + {0xe99e8b, 0xf0de}, /* U+978B */ + {0xe99e8d, 0xb0c8}, /* U+978D */ + {0xe99e8f, 0xf0df}, /* U+978F */ + {0xe99e90, 0xf0e0}, /* U+9790 */ + {0xe99e95, 0xfdee}, /* U+9795 [2000] */ + {0xe99e96, 0x8ffca4}, /* U+9796 [2000] */ + {0xe99e98, 0xbee4}, /* U+9798 */ + {0xe99e9a, 0x8ffca5}, /* U+979A [2000] */ + {0xe99e9c, 0xf0e1}, /* U+979C */ + {0xe99e9e, 0x8ffca6}, /* U+979E [2000] */ + {0xe99ea0, 0xb5c7}, /* U+97A0 */ + {0xe99ea2, 0x8ffca7}, /* U+97A2 [2000] */ + {0xe99ea3, 0xf0e4}, /* U+97A3 */ + {0xe99ea6, 0xf0e3}, /* U+97A6 */ + {0xe99ea8, 0xf0e2}, /* U+97A8 */ + {0xe99eab, 0xebf1}, /* U+97AB */ + {0xe99ead, 0xcadc}, /* U+97AD */ + {0xe99eae, 0xfdef}, /* U+97AE [2000] */ + {0xe99eb1, 0x8ffca8}, /* U+97B1 [2000] */ + {0xe99eb2, 0x8ffca9}, /* U+97B2 [2000] */ + {0xe99eb3, 0xf0e5}, /* U+97B3 */ + {0xe99eb4, 0xf0e6}, /* U+97B4 */ + {0xe99eba, 0xfdf0}, /* U+97BA [2000] */ + {0xe99ebe, 0x8ffcaa}, /* U+97BE [2000] */ + {0xe99f81, 0xfdf1}, /* U+97C1 [2000] */ + {0xe99f83, 0xf0e7}, /* U+97C3 */ + {0xe99f86, 0xf0e8}, /* U+97C6 */ + {0xe99f88, 0xf0e9}, /* U+97C8 */ + {0xe99f89, 0xfdf2}, /* U+97C9 [2000] */ + {0xe99f8b, 0xf0ea}, /* U+97CB */ + {0xe99f8c, 0x8ffcab}, /* U+97CC [2000] */ + {0xe99f91, 0x8ffcac}, /* U+97D1 [2000] */ + {0xe99f93, 0xb4da}, /* U+97D3 */ + {0xe99f94, 0x8ffcad}, /* U+97D4 [2000] */ + {0xe99f98, 0x8ffcae}, /* U+97D8 [2000] */ + {0xe99f99, 0x8ffcaf}, /* U+97D9 [2000] */ + {0xe99f9b, 0xfdf4}, /* U+97DB [2000] */ + {0xe99f9c, 0xf0eb}, /* U+97DC */ + {0xe99f9e, 0xfdf3}, /* U+97DE [2000] */ + {0xe99fa1, 0x8ffcb0}, /* U+97E1 [2000] */ + {0xe99fad, 0xf0ec}, /* U+97ED */ + {0xe99fae, 0xc7a3}, /* U+97EE */ + {0xe99fb1, 0x8ffcb1}, /* U+97F1 [2000] */ + {0xe99fb2, 0xf0ee}, /* U+97F2 */ + {0xe99fb3, 0xb2bb}, /* U+97F3 */ + {0xe99fb4, 0xfdf5}, /* U+97F4 [2000] */ + {0xe99fb5, 0xf0f1}, /* U+97F5 */ + {0xe99fb6, 0xf0f0}, /* U+97F6 */ + {0xe99fbb, 0xb1a4}, /* U+97FB */ + {0xe99fbf, 0xb6c1}, /* U+97FF */ + {0xe9a081, 0xcac7}, /* U+9801 */ + {0xe9a082, 0xc4ba}, /* U+9802 */ + {0xe9a083, 0xbaa2}, /* U+9803 */ + {0xe9a084, 0x8ffcb2}, /* U+9804 [2000] */ + {0xe9a085, 0xb9e0}, /* U+9805 */ + {0xe9a086, 0xbde7}, /* U+9806 */ + {0xe9a088, 0xbfdc}, /* U+9808 */ + {0xe9a08a, 0xfdf7}, /* U+980A [2000] */ + {0xe9a08c, 0xf0f3}, /* U+980C */ + {0xe9a08d, 0x8ffcb3}, /* U+980D [2000] */ + {0xe9a08e, 0x8ffcb4}, /* U+980E [2000] */ + {0xe9a08f, 0xf0f2}, /* U+980F */ + {0xe9a090, 0xcdc2}, /* U+9810 */ + {0xe9a091, 0xb4e8}, /* U+9811 */ + {0xe9a092, 0xc8d2}, /* U+9812 */ + {0xe9a093, 0xc6dc}, /* U+9813 */ + {0xe9a094, 0x8ffcb5}, /* U+9814 [2000] */ + {0xe9a096, 0x8ffcb6}, /* U+9816 [2000] */ + {0xe9a097, 0xbffc}, /* U+9817 */ + {0xe9a098, 0xcece}, /* U+9818 */ + {0xe9a09a, 0xb7db}, /* U+981A */ + {0xe9a09e, 0xfdf8}, /* U+981E [2000] */ + {0xe9a0a1, 0xf0f6}, /* U+9821 */ + {0xe9a0a3, 0x8ffcb9}, /* U+9823 [2000] */ + {0xe9a0a4, 0xf0f5}, /* U+9824 */ + {0xe9a0a5, 0x8ffcbc}, /* U+9825 [2000] */ + {0xe9a0ab, 0xfdf9}, /* U+982B [2000] */ + {0xe9a0ac, 0xcbcb}, /* U+982C */ + {0xe9a0ad, 0xc6ac}, /* U+982D */ + {0xe9a0b0, 0xfdfa}, /* U+9830 [2000] */ + {0xe9a0b2, 0x8ffcba}, /* U+9832 [2000] */ + {0xe9a0b3, 0x8ffcbb}, /* U+9833 [2000] */ + {0xe9a0b4, 0xb1d0}, /* U+9834 */ + {0xe9a0b7, 0xf0f7}, /* U+9837 */ + {0xe9a0b8, 0xf0f4}, /* U+9838 */ + {0xe9a0bb, 0xc9d1}, /* U+983B */ + {0xe9a0bc, 0xcdea}, /* U+983C */ + {0xe9a0bd, 0xf0f8}, /* U+983D */ + {0xe9a186, 0xf0f9}, /* U+9846 */ + {0xe9a187, 0x8ffcbd}, /* U+9847 [2000] */ + {0xe9a18b, 0xf0fb}, /* U+984B */ + {0xe9a18c, 0xc2ea}, /* U+984C */ + {0xe9a18d, 0xb3db}, /* U+984D */ + {0xe9a18e, 0xb3dc}, /* U+984E */ + {0xe9a18f, 0xf0fa}, /* U+984F */ + {0xe9a192, 0xfdfc}, /* U+9852 [2000] */ + {0xe9a193, 0xfdfd}, /* U+9853 [2000] */ + {0xe9a194, 0xb4e9}, /* U+9854 */ + {0xe9a195, 0xb8b2}, /* U+9855 */ + {0xe9a196, 0xfdfe}, /* U+9856 [2000] */ + {0xe9a197, 0xfea1}, /* U+9857 [2000] */ + {0xe9a198, 0xb4ea}, /* U+9858 */ + {0xe9a199, 0xfea2}, /* U+9859 [2000] */ + {0xe9a19a, 0xfea3}, /* U+985A [2000] */ + {0xe9a19b, 0xc5bf}, /* U+985B */ + {0xe9a19e, 0xcee0}, /* U+985E */ + {0xe9a1a5, 0xfea5}, /* U+9865 [2000] */ + {0xe9a1a6, 0x8ffcbe}, /* U+9866 [2000] */ + {0xe9a1a7, 0xb8dc}, /* U+9867 */ + {0xe9a1ab, 0xf0fc}, /* U+986B */ + {0xe9a1ac, 0xfea6}, /* U+986C [2000] */ + {0xe9a1af, 0xf0fd}, /* U+986F */ + {0xe9a1b0, 0xf0fe}, /* U+9870 */ + {0xe9a1b1, 0xf1a1}, /* U+9871 */ + {0xe9a1b3, 0xf1a3}, /* U+9873 */ + {0xe9a1b4, 0xf1a2}, /* U+9874 */ + {0xe9a2a8, 0xc9f7}, /* U+98A8 */ + {0xe9a2aa, 0xf1a4}, /* U+98AA */ + {0xe9a2ab, 0x8ffcbf}, /* U+98AB [2000] */ + {0xe9a2ad, 0x8ffcc0}, /* U+98AD [2000] */ + {0xe9a2af, 0xf1a5}, /* U+98AF */ + {0xe9a2b0, 0x8ffcc1}, /* U+98B0 [2000] */ + {0xe9a2b1, 0xf1a6}, /* U+98B1 */ + {0xe9a2b6, 0xf1a7}, /* U+98B6 */ + {0xe9a2b7, 0x8ffcc3}, /* U+98B7 [2000] */ + {0xe9a2b8, 0x8ffcc4}, /* U+98B8 [2000] */ + {0xe9a2ba, 0xfea7}, /* U+98BA [2000] */ + {0xe9a2bb, 0x8ffcc5}, /* U+98BB [2000] */ + {0xe9a2bc, 0x8ffcc6}, /* U+98BC [2000] */ + {0xe9a2bf, 0x8ffcc7}, /* U+98BF [2000] */ + {0xe9a382, 0x8ffcc8}, /* U+98C2 [2000] */ + {0xe9a383, 0xf1a9}, /* U+98C3 */ + {0xe9a384, 0xf1a8}, /* U+98C4 */ + {0xe9a386, 0xf1aa}, /* U+98C6 */ + {0xe9a387, 0x8ffcc9}, /* U+98C7 [2000] */ + {0xe9a388, 0xfea8}, /* U+98C8 [2000] */ + {0xe9a38b, 0x8ffcca}, /* U+98CB [2000] */ + {0xe9a39b, 0xc8f4}, /* U+98DB */ + {0xe9a39c, 0xe6cc}, /* U+98DC */ + {0xe9a39f, 0xbfa9}, /* U+98DF */ + {0xe9a3a0, 0x8ffccb}, /* U+98E0 [2000] */ + {0xe9a3a1, 0x8ffccd}, /* U+98E1 [2000] */ + {0xe9a3a2, 0xb5b2}, /* U+98E2 */ + {0xe9a3a3, 0x8ffcce}, /* U+98E3 [2000] */ + {0xe9a3a5, 0x8ffccf}, /* U+98E5 [2000] */ + {0xe9a3a7, 0xfea9}, /* U+98E7 [2000] */ + {0xe9a3a9, 0xf1ab}, /* U+98E9 */ + {0xe9a3aa, 0x8ffcd0}, /* U+98EA [2000] */ + {0xe9a3ab, 0xf1ac}, /* U+98EB */ + {0xe9a3ad, 0xd2ac}, /* U+98ED */ + {0xe9a3ae, 0xddbb}, /* U+98EE */ + {0xe9a3af, 0xc8d3}, /* U+98EF */ + {0xe9a3b0, 0x8ffcd1}, /* U+98F0 [2000] */ + {0xe9a3b1, 0x8ffcd2}, /* U+98F1 [2000] */ + {0xe9a3b2, 0xb0fb}, /* U+98F2 */ + {0xe9a3b3, 0x8ffcd3}, /* U+98F3 [2000] */ + {0xe9a3b4, 0xb0bb}, /* U+98F4 */ + {0xe9a3bc, 0xbbf4}, /* U+98FC */ + {0xe9a3bd, 0xcbb0}, /* U+98FD */ + {0xe9a3be, 0xbefe}, /* U+98FE */ + {0xe9a483, 0xf1ad}, /* U+9903 */ + {0xe9a485, 0xccdf}, /* U+9905 */ + {0xe9a488, 0x8ffcd4}, /* U+9908 [2000] */ + {0xe9a489, 0xf1ae}, /* U+9909 */ + {0xe9a48a, 0xcddc}, /* U+990A */ + {0xe9a48c, 0xb1c2}, /* U+990C */ + {0xe9a490, 0xbbc1}, /* U+9910 */ + {0xe9a492, 0xf1af}, /* U+9912 */ + {0xe9a493, 0xb2ee}, /* U+9913 */ + {0xe9a494, 0xf1b0}, /* U+9914 */ + {0xe9a496, 0x8ffcd7}, /* U+9916 [2000] */ + {0xe9a497, 0x8ffcd8}, /* U+9917 [2000] */ + {0xe9a498, 0xf1b1}, /* U+9918 */ + {0xe9a49a, 0x8ffcda}, /* U+991A [2000] */ + {0xe9a49b, 0x8ffcdb}, /* U+991B [2000] */ + {0xe9a49c, 0x8ffcdc}, /* U+991C [2000] */ + {0xe9a49d, 0xf1b3}, /* U+991D */ + {0xe9a49e, 0xf1b4}, /* U+991E */ + {0xe9a4a0, 0xf1b6}, /* U+9920 */ + {0xe9a4a1, 0xf1b2}, /* U+9921 */ + {0xe9a4a4, 0xf1b5}, /* U+9924 */ + {0xe9a4a8, 0xb4db}, /* U+9928 */ + {0xe9a4ac, 0xf1b7}, /* U+992C */ + {0xe9a4ae, 0xf1b8}, /* U+992E */ + {0xe9a4b1, 0x8ffcde}, /* U+9931 [2000] */ + {0xe9a4b2, 0x8ffcdf}, /* U+9932 [2000] */ + {0xe9a4b3, 0x8ffce0}, /* U+9933 [2000] */ + {0xe9a4ba, 0x8ffce1}, /* U+993A [2000] */ + {0xe9a4bb, 0x8ffce2}, /* U+993B [2000] */ + {0xe9a4bc, 0x8ffce3}, /* U+993C [2000] */ + {0xe9a4bd, 0xf1b9}, /* U+993D */ + {0xe9a4be, 0xf1ba}, /* U+993E */ + {0xe9a580, 0x8ffce4}, /* U+9940 [2000] */ + {0xe9a581, 0x8ffce5}, /* U+9941 [2000] */ + {0xe9a582, 0xf1bb}, /* U+9942 */ + {0xe9a585, 0xf1bd}, /* U+9945 */ + {0xe9a586, 0x8ffce6}, /* U+9946 [2000] */ + {0xe9a589, 0xf1bc}, /* U+9949 */ + {0xe9a58b, 0xf1bf}, /* U+994B */ + {0xe9a58c, 0xf1c2}, /* U+994C */ + {0xe9a58d, 0x8ffce7}, /* U+994D [2000] */ + {0xe9a58e, 0x8ffce8}, /* U+994E [2000] */ + {0xe9a590, 0xf1be}, /* U+9950 */ + {0xe9a591, 0xf1c0}, /* U+9951 */ + {0xe9a592, 0xf1c1}, /* U+9952 */ + {0xe9a595, 0xf1c3}, /* U+9955 */ + {0xe9a597, 0xb6c2}, /* U+9957 */ + {0xe9a598, 0xfeaa}, /* U+9958 [2000] */ + {0xe9a59c, 0x8ffce9}, /* U+995C [2000] */ + {0xe9a59f, 0x8ffcea}, /* U+995F [2000] */ + {0xe9a5a0, 0x8ffceb}, /* U+9960 [2000] */ + {0xe9a696, 0xbcf3}, /* U+9996 */ + {0xe9a697, 0xf1c4}, /* U+9997 */ + {0xe9a698, 0xf1c5}, /* U+9998 */ + {0xe9a699, 0xb9e1}, /* U+9999 */ + {0xe9a69e, 0xfeab}, /* U+999E [2000] */ + {0xe9a6a3, 0x8ffcec}, /* U+99A3 [2000] */ + {0xe9a6a5, 0xf1c6}, /* U+99A5 */ + {0xe9a6a6, 0x8ffced}, /* U+99A6 [2000] */ + {0xe9a6a8, 0xb3be}, /* U+99A8 */ + {0xe9a6ac, 0xc7cf}, /* U+99AC */ + {0xe9a6ad, 0xf1c7}, /* U+99AD */ + {0xe9a6ae, 0xf1c8}, /* U+99AE */ + {0xe9a6b3, 0xc3da}, /* U+99B3 */ + {0xe9a6b4, 0xc6eb}, /* U+99B4 */ + {0xe9a6b9, 0x8ffcee}, /* U+99B9 [2000] */ + {0xe9a6bc, 0xf1c9}, /* U+99BC */ + {0xe9a6bd, 0x8ffcef}, /* U+99BD [2000] */ + {0xe9a6bf, 0x8ffcf0}, /* U+99BF [2000] */ + {0xe9a781, 0xc7fd}, /* U+99C1 */ + {0xe9a783, 0x8ffcf1}, /* U+99C3 [2000] */ + {0xe9a784, 0xc2cc}, /* U+99C4 */ + {0xe9a785, 0xb1d8}, /* U+99C5 */ + {0xe9a786, 0xb6ee}, /* U+99C6 */ + {0xe9a788, 0xb6ef}, /* U+99C8 */ + {0xe9a789, 0x8ffcf2}, /* U+99C9 [2000] */ + {0xe9a790, 0xc3f3}, /* U+99D0 */ + {0xe9a791, 0xf1ce}, /* U+99D1 */ + {0xe9a792, 0xb6f0}, /* U+99D2 */ + {0xe9a794, 0x8ffcf3}, /* U+99D4 [2000] */ + {0xe9a795, 0xb2ef}, /* U+99D5 */ + {0xe9a798, 0xf1cd}, /* U+99D8 */ + {0xe9a799, 0x8ffcf4}, /* U+99D9 [2000] */ + {0xe9a79b, 0xf1cb}, /* U+99DB */ + {0xe9a79d, 0xf1cc}, /* U+99DD */ + {0xe9a79e, 0x8ffcf5}, /* U+99DE [2000] */ + {0xe9a79f, 0xf1ca}, /* U+99DF */ + {0xe9a7a2, 0xf1d8}, /* U+99E2 */ + {0xe9a7ad, 0xf1cf}, /* U+99ED */ + {0xe9a7ae, 0xf1d0}, /* U+99EE */ + {0xe9a7b0, 0x8ffcf7}, /* U+99F0 [2000] */ + {0xe9a7b1, 0xf1d1}, /* U+99F1 */ + {0xe9a7b2, 0xf1d2}, /* U+99F2 */ + {0xe9a7b8, 0xf1d4}, /* U+99F8 */ + {0xe9a7b9, 0x8ffcf8}, /* U+99F9 [2000] */ + {0xe9a7bb, 0xf1d3}, /* U+99FB */ + {0xe9a7bc, 0x8ffcf9}, /* U+99FC [2000] */ + {0xe9a7bf, 0xbdd9}, /* U+99FF */ + {0xe9a881, 0xf1d5}, /* U+9A01 */ + {0xe9a882, 0xfeac}, /* U+9A02 [2000] */ + {0xe9a883, 0xfead}, /* U+9A03 [2000] */ + {0xe9a885, 0xf1d7}, /* U+9A05 */ + {0xe9a88a, 0x8ffcfa}, /* U+9A0A [2000] */ + {0xe9a88e, 0xb5b3}, /* U+9A0E */ + {0xe9a88f, 0xf1d6}, /* U+9A0F */ + {0xe9a891, 0x8ffcfb}, /* U+9A11 [2000] */ + {0xe9a892, 0xc1fb}, /* U+9A12 */ + {0xe9a893, 0xb8b3}, /* U+9A13 */ + {0xe9a896, 0x8ffcfc}, /* U+9A16 [2000] */ + {0xe9a899, 0xf1d9}, /* U+9A19 */ + {0xe9a89a, 0x8ffcfd}, /* U+9A1A [2000] */ + {0xe9a8a0, 0x8ffcfe}, /* U+9A20 [2000] */ + {0xe9a8a4, 0xfeae}, /* U+9A24 [2000] */ + {0xe9a8a8, 0xc2cd}, /* U+9A28 */ + {0xe9a8ab, 0xf1da}, /* U+9A2B */ + {0xe9a8ad, 0xfeaf}, /* U+9A2D [2000] */ + {0xe9a8ae, 0xfeb0}, /* U+9A2E [2000] */ + {0xe9a8b0, 0xc6ad}, /* U+9A30 */ + {0xe9a8b1, 0x8ffda1}, /* U+9A31 [2000] */ + {0xe9a8b6, 0x8ffda2}, /* U+9A36 [2000] */ + {0xe9a8b7, 0xf1db}, /* U+9A37 */ + {0xe9a8b8, 0xfeb1}, /* U+9A38 [2000] */ + {0xe9a8be, 0xf1e0}, /* U+9A3E */ + {0xe9a980, 0xf1de}, /* U+9A40 */ + {0xe9a982, 0xf1dd}, /* U+9A42 */ + {0xe9a983, 0xf1df}, /* U+9A43 */ + {0xe9a984, 0x8ffda3}, /* U+9A44 [2000] */ + {0xe9a985, 0xf1dc}, /* U+9A45 */ + {0xe9a98a, 0xfeb2}, /* U+9A4A [2000] */ + {0xe9a98c, 0x8ffda4}, /* U+9A4C [2000] */ + {0xe9a98d, 0xf1e2}, /* U+9A4D */ + {0xe9a98e, 0xfeb3}, /* U+9A4E [2000] */ + {0xe9a992, 0xfeb4}, /* U+9A52 [2000] */ + {0xe9a995, 0xf1e1}, /* U+9A55 */ + {0xe9a997, 0xf1e4}, /* U+9A57 */ + {0xe9a998, 0x8ffda5}, /* U+9A58 [2000] */ + {0xe9a99a, 0xb6c3}, /* U+9A5A */ + {0xe9a99b, 0xf1e3}, /* U+9A5B */ + {0xe9a99f, 0xf1e5}, /* U+9A5F */ + {0xe9a9a2, 0xf1e6}, /* U+9A62 */ + {0xe9a9a4, 0xf1e8}, /* U+9A64 */ + {0xe9a9a5, 0xf1e7}, /* U+9A65 */ + {0xe9a9a9, 0xf1e9}, /* U+9A69 */ + {0xe9a9aa, 0xf1eb}, /* U+9A6A */ + {0xe9a9ab, 0xf1ea}, /* U+9A6B */ + {0xe9aaa8, 0xb9fc}, /* U+9AA8 */ + {0xe9aaad, 0xf1ec}, /* U+9AAD */ + {0xe9aaaf, 0x8ffda7}, /* U+9AAF [2000] */ + {0xe9aab0, 0xf1ed}, /* U+9AB0 */ + {0xe9aab6, 0xfeb5}, /* U+9AB6 [2000] */ + {0xe9aab7, 0x8ffda9}, /* U+9AB7 [2000] */ + {0xe9aab8, 0xb3bc}, /* U+9AB8 */ + {0xe9aab9, 0x8ffdab}, /* U+9AB9 [2000] */ + {0xe9aabc, 0xf1ee}, /* U+9ABC */ + {0xe9ab80, 0xf1ef}, /* U+9AC0 */ + {0xe9ab81, 0xfeb6}, /* U+9AC1 [2000] */ + {0xe9ab83, 0xfeb7}, /* U+9AC3 [2000] */ + {0xe9ab84, 0xbff1}, /* U+9AC4 */ + {0xe9ab86, 0x8ffdad}, /* U+9AC6 [2000] */ + {0xe9ab8e, 0xfeb8}, /* U+9ACE [2000] */ + {0xe9ab8f, 0xf1f0}, /* U+9ACF */ + {0xe9ab90, 0x8ffdae}, /* U+9AD0 [2000] */ + {0xe9ab91, 0xf1f1}, /* U+9AD1 */ + {0xe9ab92, 0x8ffdaf}, /* U+9AD2 [2000] */ + {0xe9ab93, 0xf1f2}, /* U+9AD3 */ + {0xe9ab94, 0xf1f3}, /* U+9AD4 */ + {0xe9ab95, 0x8ffdb0}, /* U+9AD5 [2000] */ + {0xe9ab96, 0xfeb9}, /* U+9AD6 [2000] */ + {0xe9ab98, 0xb9e2}, /* U+9AD8 */ + {0xe9ab9c, 0x8ffdb2}, /* U+9ADC [2000] */ + {0xe9ab9e, 0xf1f4}, /* U+9ADE */ + {0xe9ab9f, 0xf1f5}, /* U+9ADF */ + {0xe9aba0, 0x8ffdb3}, /* U+9AE0 [2000] */ + {0xe9aba2, 0xf1f6}, /* U+9AE2 */ + {0xe9aba3, 0xf1f7}, /* U+9AE3 */ + {0xe9aba5, 0x8ffdb4}, /* U+9AE5 [2000] */ + {0xe9aba6, 0xf1f8}, /* U+9AE6 */ + {0xe9aba9, 0x8ffdb5}, /* U+9AE9 [2000] */ + {0xe9abaa, 0xc8b1}, /* U+9AEA */ + {0xe9abab, 0xf1fa}, /* U+9AEB */ + {0xe9abad, 0xc9a6}, /* U+9AED */ + {0xe9abae, 0xf1fb}, /* U+9AEE */ + {0xe9abaf, 0xf1f9}, /* U+9AEF */ + {0xe9abb1, 0xf1fd}, /* U+9AF1 */ + {0xe9abb4, 0xf1fc}, /* U+9AF4 */ + {0xe9abb7, 0xf1fe}, /* U+9AF7 */ + {0xe9abb9, 0xfeba}, /* U+9AF9 [2000] */ + {0xe9abbb, 0xf2a1}, /* U+9AFB */ + {0xe9ac82, 0xfebb}, /* U+9B02 [2000] */ + {0xe9ac83, 0x8ffdb6}, /* U+9B03 [2000] */ + {0xe9ac86, 0xf2a2}, /* U+9B06 */ + {0xe9ac88, 0xfebc}, /* U+9B08 [2000] */ + {0xe9ac8c, 0x8ffdb7}, /* U+9B0C [2000] */ + {0xe9ac90, 0x8ffdb8}, /* U+9B10 [2000] */ + {0xe9ac92, 0x8ffdb9}, /* U+9B12 [2000] */ + {0xe9ac96, 0x8ffdba}, /* U+9B16 [2000] */ + {0xe9ac98, 0xf2a3}, /* U+9B18 */ + {0xe9ac9a, 0xf2a4}, /* U+9B1A */ + {0xe9ac9c, 0x8ffdbb}, /* U+9B1C [2000] */ + {0xe9ac9f, 0xf2a5}, /* U+9B1F */ + {0xe9aca0, 0xfebd}, /* U+9B20 [2000] */ + {0xe9aca2, 0xf2a6}, /* U+9B22 */ + {0xe9aca3, 0xf2a7}, /* U+9B23 */ + {0xe9aca5, 0xf2a8}, /* U+9B25 */ + {0xe9aca7, 0xf2a9}, /* U+9B27 */ + {0xe9aca8, 0xf2aa}, /* U+9B28 */ + {0xe9aca9, 0xf2ab}, /* U+9B29 */ + {0xe9acaa, 0xf2ac}, /* U+9B2A */ + {0xe9acab, 0x8ffdbc}, /* U+9B2B [2000] */ + {0xe9acad, 0xfebf}, /* U+9B2D [2000] */ + {0xe9acae, 0xf2ad}, /* U+9B2E */ + {0xe9acaf, 0xf2ae}, /* U+9B2F */ + {0xe9acb1, 0xddb5}, /* U+9B31 */ + {0xe9acb2, 0xf2af}, /* U+9B32 */ + {0xe9acb3, 0x8ffdbd}, /* U+9B33 [2000] */ + {0xe9acbb, 0xe4f8}, /* U+9B3B */ + {0xe9acbc, 0xb5b4}, /* U+9B3C */ + {0xe9acbd, 0x8ffdbe}, /* U+9B3D [2000] */ + {0xe9ad81, 0xb3a1}, /* U+9B41 */ + {0xe9ad82, 0xbab2}, /* U+9B42 */ + {0xe9ad83, 0xf2b1}, /* U+9B43 */ + {0xe9ad84, 0xf2b0}, /* U+9B44 */ + {0xe9ad85, 0xcca5}, /* U+9B45 */ + {0xe9ad8b, 0x8ffdc0}, /* U+9B4B [2000] */ + {0xe9ad8d, 0xf2b3}, /* U+9B4D */ + {0xe9ad8e, 0xf2b4}, /* U+9B4E */ + {0xe9ad8f, 0xf2b2}, /* U+9B4F */ + {0xe9ad91, 0xf2b5}, /* U+9B51 */ + {0xe9ad94, 0xcbe2}, /* U+9B54 */ + {0xe9ad98, 0xf2b6}, /* U+9B58 */ + {0xe9ad9a, 0xb5fb}, /* U+9B5A */ + {0xe9ad9e, 0xfec0}, /* U+9B5E [2000] */ + {0xe9ada3, 0x8ffdc1}, /* U+9B63 [2000] */ + {0xe9ada5, 0x8ffdc2}, /* U+9B65 [2000] */ + {0xe9ada6, 0xfec2}, /* U+9B66 [2000] */ + {0xe9adab, 0x8ffdc3}, /* U+9B6B [2000] */ + {0xe9adac, 0x8ffdc4}, /* U+9B6C [2000] */ + {0xe9adaf, 0xcfa5}, /* U+9B6F */ + {0xe9adb2, 0xfec3}, /* U+9B72 [2000] */ + {0xe9adb3, 0x8ffdc5}, /* U+9B73 [2000] */ + {0xe9adb4, 0xf2b7}, /* U+9B74 */ + {0xe9adb5, 0xfec4}, /* U+9B75 [2000] */ + {0xe9adb6, 0x8ffdc6}, /* U+9B76 [2000] */ + {0xe9adb7, 0x8ffdc7}, /* U+9B77 [2000] */ + {0xe9adb9, 0xfec1}, /* U+9B79 [2000] */ + {0xe9ae83, 0xf2b9}, /* U+9B83 */ + {0xe9ae84, 0xfec5}, /* U+9B84 [2000] */ + {0xe9ae8a, 0xfec6}, /* U+9B8A [2000] */ + {0xe9ae8e, 0xb0be}, /* U+9B8E */ + {0xe9ae8f, 0xfec7}, /* U+9B8F [2000] */ + {0xe9ae91, 0xf2ba}, /* U+9B91 */ + {0xe9ae92, 0xcaab}, /* U+9B92 */ + {0xe9ae93, 0xf2b8}, /* U+9B93 */ + {0xe9ae96, 0xf2bb}, /* U+9B96 */ + {0xe9ae97, 0xf2bc}, /* U+9B97 */ + {0xe9ae9e, 0xfec8}, /* U+9B9E [2000] */ + {0xe9ae9f, 0xf2bd}, /* U+9B9F */ + {0xe9aea0, 0xf2be}, /* U+9BA0 */ + {0xe9aea6, 0x8ffdc8}, /* U+9BA6 [2000] */ + {0xe9aea7, 0xfec9}, /* U+9BA7 [2000] */ + {0xe9aea8, 0xf2bf}, /* U+9BA8 */ + {0xe9aeaa, 0xcbee}, /* U+9BAA */ + {0xe9aeab, 0xbbad}, /* U+9BAB */ + {0xe9aeac, 0x8ffdc9}, /* U+9BAC [2000] */ + {0xe9aead, 0xbafa}, /* U+9BAD */ + {0xe9aeae, 0xc1af}, /* U+9BAE */ + {0xe9aeb1, 0x8ffdca}, /* U+9BB1 [2000] */ + {0xe9aeb2, 0x8ffdcd}, /* U+9BB2 [2000] */ + {0xe9aeb4, 0xf2c0}, /* U+9BB4 */ + {0xe9aeb8, 0x8ffdce}, /* U+9BB8 [2000] */ + {0xe9aeb9, 0xf2c3}, /* U+9BB9 */ + {0xe9aebe, 0x8ffdcf}, /* U+9BBE [2000] */ + {0xe9af80, 0xf2c1}, /* U+9BC0 */ + {0xe9af81, 0xfeca}, /* U+9BC1 [2000] */ + {0xe9af86, 0xf2c4}, /* U+9BC6 */ + {0xe9af87, 0x8ffdd0}, /* U+9BC7 [2000] */ + {0xe9af89, 0xb8f1}, /* U+9BC9 */ + {0xe9af8a, 0xf2c2}, /* U+9BCA */ + {0xe9af8e, 0xfecb}, /* U+9BCE [2000] */ + {0xe9af8f, 0xf2c5}, /* U+9BCF */ + {0xe9af91, 0xf2c6}, /* U+9BD1 */ + {0xe9af92, 0xf2c7}, /* U+9BD2 */ + {0xe9af94, 0xf2cb}, /* U+9BD4 */ + {0xe9af96, 0xbbaa}, /* U+9BD6 */ + {0xe9af98, 0x8ffdd2}, /* U+9BD8 [2000] */ + {0xe9af9b, 0xc2e4}, /* U+9BDB */ + {0xe9af9d, 0x8ffdd3}, /* U+9BDD [2000] */ + {0xe9afa1, 0xf2cc}, /* U+9BE1 */ + {0xe9afa2, 0xf2c9}, /* U+9BE2 */ + {0xe9afa3, 0xf2c8}, /* U+9BE3 */ + {0xe9afa4, 0xf2ca}, /* U+9BE4 */ + {0xe9afa5, 0xfecc}, /* U+9BE5 [2000] */ + {0xe9afa7, 0x8ffdd4}, /* U+9BE7 [2000] */ + {0xe9afa8, 0xb7df}, /* U+9BE8 */ + {0xe9afaa, 0x8ffdd5}, /* U+9BEA [2000] */ + {0xe9afab, 0x8ffdd6}, /* U+9BEB [2000] */ + {0xe9afae, 0x8ffdd8}, /* U+9BEE [2000] */ + {0xe9afaf, 0x8ffdd7}, /* U+9BEF [2000] */ + {0xe9afb0, 0xf2d0}, /* U+9BF0 */ + {0xe9afb1, 0xf2cf}, /* U+9BF1 */ + {0xe9afb2, 0xf2ce}, /* U+9BF2 */ + {0xe9afb3, 0x8ffdd1}, /* U+9BF3 [2000] */ + {0xe9afb5, 0xb0b3}, /* U+9BF5 */ + {0xe9afb7, 0x8ffddc}, /* U+9BF7 [2000] */ + {0xe9afb8, 0xfecd}, /* U+9BF8 [2000] */ + {0xe9afba, 0x8ffdda}, /* U+9BFA [2000] */ + {0xe9afbd, 0xfece}, /* U+9BFD [2000] */ + {0xe9b080, 0xfecf}, /* U+9C00 [2000] */ + {0xe9b084, 0xf2da}, /* U+9C04 */ + {0xe9b086, 0xf2d6}, /* U+9C06 */ + {0xe9b088, 0xf2d7}, /* U+9C08 */ + {0xe9b089, 0xf2d3}, /* U+9C09 */ + {0xe9b08a, 0xf2d9}, /* U+9C0A */ + {0xe9b08c, 0xf2d5}, /* U+9C0C */ + {0xe9b08d, 0xb3e2}, /* U+9C0D */ + {0xe9b090, 0xcfcc}, /* U+9C10 */ + {0xe9b092, 0xf2d8}, /* U+9C12 */ + {0xe9b093, 0xf2d4}, /* U+9C13 */ + {0xe9b094, 0xf2d2}, /* U+9C14 */ + {0xe9b095, 0xf2d1}, /* U+9C15 */ + {0xe9b096, 0x8ffdde}, /* U+9C16 [2000] */ + {0xe9b098, 0x8ffddf}, /* U+9C18 [2000] */ + {0xe9b099, 0x8ffde0}, /* U+9C19 [2000] */ + {0xe9b09a, 0x8ffde1}, /* U+9C1A [2000] */ + {0xe9b09b, 0xf2dc}, /* U+9C1B */ + {0xe9b09d, 0x8ffde2}, /* U+9C1D [2000] */ + {0xe9b0a1, 0xf2df}, /* U+9C21 */ + {0xe9b0a2, 0x8ffde3}, /* U+9C22 [2000] */ + {0xe9b0a3, 0xfed0}, /* U+9C23 [2000] */ + {0xe9b0a4, 0xf2de}, /* U+9C24 */ + {0xe9b0a5, 0xf2dd}, /* U+9C25 */ + {0xe9b0a7, 0x8ffde4}, /* U+9C27 [2000] */ + {0xe9b0a9, 0x8ffde5}, /* U+9C29 [2000] */ + {0xe9b0aa, 0x8ffde6}, /* U+9C2A [2000] */ + {0xe9b0ad, 0xc9c9}, /* U+9C2D */ + {0xe9b0ae, 0xf2db}, /* U+9C2E */ + {0xe9b0af, 0xb0f3}, /* U+9C2F */ + {0xe9b0b0, 0xf2e0}, /* U+9C30 */ + {0xe9b0b1, 0x8ffde8}, /* U+9C31 [2000] */ + {0xe9b0b2, 0xf2e2}, /* U+9C32 */ + {0xe9b0b6, 0x8ffde9}, /* U+9C36 [2000] */ + {0xe9b0b7, 0x8ffdea}, /* U+9C37 [2000] */ + {0xe9b0b9, 0xb3ef}, /* U+9C39 */ + {0xe9b0ba, 0xf2cd}, /* U+9C3A */ + {0xe9b0bb, 0xb1b7}, /* U+9C3B */ + {0xe9b0be, 0xf2e4}, /* U+9C3E */ + {0xe9b181, 0xfed1}, /* U+9C41 [2000] */ + {0xe9b185, 0x8ffdeb}, /* U+9C45 [2000] */ + {0xe9b186, 0xf2e3}, /* U+9C46 */ + {0xe9b187, 0xf2e1}, /* U+9C47 */ + {0xe9b188, 0xc3ad}, /* U+9C48 */ + {0xe9b189, 0x8ffdee}, /* U+9C49 [2000] */ + {0xe9b18a, 0x8ffdef}, /* U+9C4A [2000] */ + {0xe9b18f, 0xfed2}, /* U+9C4F [2000] */ + {0xe9b190, 0xfed3}, /* U+9C50 [2000] */ + {0xe9b192, 0xcbf0}, /* U+9C52 */ + {0xe9b193, 0xfed4}, /* U+9C53 [2000] */ + {0xe9b194, 0x8ffdf1}, /* U+9C54 [2000] */ + {0xe9b197, 0xceda}, /* U+9C57 */ + {0xe9b198, 0x8ffdf2}, /* U+9C58 [2000] */ + {0xe9b19a, 0xf2e5}, /* U+9C5A */ + {0xe9b19b, 0x8ffdf3}, /* U+9C5B [2000] */ + {0xe9b19c, 0x8ffdec}, /* U+9C5C [2000] */ + {0xe9b19d, 0x8ffdf4}, /* U+9C5D [2000] */ + {0xe9b19f, 0x8ffdf5}, /* U+9C5F [2000] */ + {0xe9b1a0, 0xf2e6}, /* U+9C60 */ + {0xe9b1a3, 0xfed5}, /* U+9C63 [2000] */ + {0xe9b1a5, 0xfed6}, /* U+9C65 [2000] */ + {0xe9b1a7, 0xf2e7}, /* U+9C67 */ + {0xe9b1a9, 0x8ffdf6}, /* U+9C69 [2000] */ + {0xe9b1aa, 0x8ffdf7}, /* U+9C6A [2000] */ + {0xe9b1ab, 0x8ffdf8}, /* U+9C6B [2000] */ + {0xe9b1ad, 0x8ffdf9}, /* U+9C6D [2000] */ + {0xe9b1ae, 0x8ffdfa}, /* U+9C6E [2000] */ + {0xe9b1b0, 0x8ffdfb}, /* U+9C70 [2000] */ + {0xe9b1b2, 0x8ffdfc}, /* U+9C72 [2000] */ + {0xe9b1b5, 0x8ffdfd}, /* U+9C75 [2000] */ + {0xe9b1b6, 0xf2e8}, /* U+9C76 */ + {0xe9b1b7, 0xfed7}, /* U+9C77 [2000] */ + {0xe9b1b8, 0xf2e9}, /* U+9C78 */ + {0xe9b1ba, 0x8ffdfe}, /* U+9C7A [2000] */ + {0xe9b3a5, 0xc4bb}, /* U+9CE5 */ + {0xe9b3a6, 0x8ffea1}, /* U+9CE6 [2000] */ + {0xe9b3a7, 0xf2ea}, /* U+9CE7 */ + {0xe9b3a9, 0xc8b7}, /* U+9CE9 */ + {0xe9b3ab, 0xf2ef}, /* U+9CEB */ + {0xe9b3ac, 0xf2eb}, /* U+9CEC */ + {0xe9b3b0, 0xf2ec}, /* U+9CF0 */ + {0xe9b3b2, 0x8ffea2}, /* U+9CF2 [2000] */ + {0xe9b3b3, 0xcbb1}, /* U+9CF3 */ + {0xe9b3b4, 0xccc4}, /* U+9CF4 */ + {0xe9b3b6, 0xc6d0}, /* U+9CF6 */ + {0xe9b482, 0x8ffea4}, /* U+9D02 [2000] */ + {0xe9b483, 0xf2f0}, /* U+9D03 */ + {0xe9b486, 0xf2f1}, /* U+9D06 */ + {0xe9b487, 0xc6be}, /* U+9D07 */ + {0xe9b488, 0xf2ee}, /* U+9D08 */ + {0xe9b489, 0xf2ed}, /* U+9D09 */ + {0xe9b48b, 0x8ffea3}, /* U+9D0B [2000] */ + {0xe9b48e, 0xb2aa}, /* U+9D0E */ + {0xe9b491, 0x8ffea6}, /* U+9D11 [2000] */ + {0xe9b492, 0xf2f9}, /* U+9D12 */ + {0xe9b495, 0xf2f8}, /* U+9D15 */ + {0xe9b497, 0x8ffea7}, /* U+9D17 [2000] */ + {0xe9b498, 0x8ffea8}, /* U+9D18 [2000] */ + {0xe9b49b, 0xb1f5}, /* U+9D1B */ + {0xe9b49d, 0xfed8}, /* U+9D1D [2000] */ + {0xe9b49e, 0xfed9}, /* U+9D1E [2000] */ + {0xe9b49f, 0xf2f6}, /* U+9D1F */ + {0xe9b4a3, 0xf2f5}, /* U+9D23 */ + {0xe9b4a6, 0xf2f3}, /* U+9D26 */ + {0xe9b4a8, 0xb3fb}, /* U+9D28 */ + {0xe9b4aa, 0xf2f2}, /* U+9D2A */ + {0xe9b4ab, 0xbcb2}, /* U+9D2B */ + {0xe9b4ac, 0xb2a9}, /* U+9D2C */ + {0xe9b4b2, 0x8ffeac}, /* U+9D32 [2000] */ + {0xe9b4bb, 0xb9e3}, /* U+9D3B */ + {0xe9b4be, 0xf2fc}, /* U+9D3E */ + {0xe9b4bf, 0xf2fb}, /* U+9D3F */ + {0xe9b581, 0xf2fa}, /* U+9D41 */ + {0xe9b582, 0x8ffeae}, /* U+9D42 [2000] */ + {0xe9b583, 0xfeda}, /* U+9D43 [2000] */ + {0xe9b584, 0xf2f7}, /* U+9D44 */ + {0xe9b586, 0xf2fd}, /* U+9D46 */ + {0xe9b587, 0xfedb}, /* U+9D47 [2000] */ + {0xe9b588, 0xf2fe}, /* U+9D48 */ + {0xe9b58a, 0x8ffeaf}, /* U+9D4A [2000] */ + {0xe9b590, 0xf3a5}, /* U+9D50 */ + {0xe9b591, 0xf3a4}, /* U+9D51 */ + {0xe9b592, 0xfedc}, /* U+9D52 [2000] */ + {0xe9b599, 0xf3a6}, /* U+9D59 */ + {0xe9b59c, 0xb1ad}, /* U+9D5C */ + {0xe9b59d, 0xf3a1}, /* U+9D5D */ + {0xe9b59e, 0xf3a2}, /* U+9D5E */ + {0xe9b59f, 0x8ffeb0}, /* U+9D5F [2000] */ + {0xe9b5a0, 0xb9f4}, /* U+9D60 */ + {0xe9b5a1, 0xccb9}, /* U+9D61 */ + {0xe9b5a2, 0x8ffeb1}, /* U+9D62 [2000] */ + {0xe9b5a3, 0xfedd}, /* U+9D63 [2000] */ + {0xe9b5a4, 0xf3a3}, /* U+9D64 */ + {0xe9b5a9, 0x8ffeb3}, /* U+9D69 [2000] */ + {0xe9b5ab, 0x8ffeb4}, /* U+9D6B [2000] */ + {0xe9b5ac, 0xcbb2}, /* U+9D6C */ + {0xe9b5af, 0xf3ab}, /* U+9D6F */ + {0xe9b5b0, 0xfede}, /* U+9D70 [2000] */ + {0xe9b5b2, 0xf3a7}, /* U+9D72 */ + {0xe9b5b3, 0x8ffeb6}, /* U+9D73 [2000] */ + {0xe9b5b6, 0x8ffeb7}, /* U+9D76 [2000] */ + {0xe9b5b7, 0x8ffeb8}, /* U+9D77 [2000] */ + {0xe9b5ba, 0xf3ac}, /* U+9D7A */ + {0xe9b5bc, 0xfedf}, /* U+9D7C [2000] */ + {0xe9b5be, 0x8ffeb9}, /* U+9D7E [2000] */ + {0xe9b684, 0x8ffeba}, /* U+9D84 [2000] */ + {0xe9b687, 0xf3a9}, /* U+9D87 */ + {0xe9b689, 0xf3a8}, /* U+9D89 */ + {0xe9b68a, 0xfee0}, /* U+9D8A [2000] */ + {0xe9b68d, 0x8ffebb}, /* U+9D8D [2000] */ + {0xe9b68f, 0xb7dc}, /* U+9D8F */ + {0xe9b696, 0xfee1}, /* U+9D96 [2000] */ + {0xe9b699, 0x8ffebc}, /* U+9D99 [2000] */ + {0xe9b69a, 0xf3ad}, /* U+9D9A */ + {0xe9b6a1, 0x8ffebd}, /* U+9DA1 [2000] */ + {0xe9b6a4, 0xf3ae}, /* U+9DA4 */ + {0xe9b6a9, 0xf3af}, /* U+9DA9 */ + {0xe9b6ab, 0xf3aa}, /* U+9DAB */ + {0xe9b6ac, 0xfee3}, /* U+9DAC [2000] */ + {0xe9b6af, 0xf2f4}, /* U+9DAF */ + {0xe9b6b2, 0xf3b0}, /* U+9DB2 */ + {0xe9b6b4, 0xc4e1}, /* U+9DB4 */ + {0xe9b6b5, 0x8ffebf}, /* U+9DB5 [2000] */ + {0xe9b6b8, 0xf3b4}, /* U+9DB8 */ + {0xe9b6b9, 0x8ffec0}, /* U+9DB9 [2000] */ + {0xe9b6ba, 0xf3b5}, /* U+9DBA */ + {0xe9b6bb, 0xf3b3}, /* U+9DBB */ + {0xe9b6bc, 0xfee4}, /* U+9DBC [2000] */ + {0xe9b6bd, 0x8ffec1}, /* U+9DBD [2000] */ + {0xe9b6bf, 0x8ffebe}, /* U+9DBF [2000] */ + {0xe9b780, 0xfee2}, /* U+9DC0 [2000] */ + {0xe9b781, 0xf3b2}, /* U+9DC1 */ + {0xe9b782, 0xf3b8}, /* U+9DC2 */ + {0xe9b783, 0x8ffec2}, /* U+9DC3 [2000] */ + {0xe9b784, 0xf3b1}, /* U+9DC4 */ + {0xe9b786, 0xf3b6}, /* U+9DC6 */ + {0xe9b787, 0x8ffec3}, /* U+9DC7 [2000] */ + {0xe9b789, 0x8ffec4}, /* U+9DC9 [2000] */ + {0xe9b78f, 0xf3b7}, /* U+9DCF */ + {0xe9b793, 0xf3ba}, /* U+9DD3 */ + {0xe9b796, 0x8ffec5}, /* U+9DD6 [2000] */ + {0xe9b797, 0xfee5}, /* U+9DD7 [2000] */ + {0xe9b799, 0xf3b9}, /* U+9DD9 */ + {0xe9b79a, 0x8ffec6}, /* U+9DDA [2000] */ + {0xe9b79f, 0x8ffec7}, /* U+9DDF [2000] */ + {0xe9b7a0, 0x8ffec8}, /* U+9DE0 [2000] */ + {0xe9b7a3, 0x8ffec9}, /* U+9DE3 [2000] */ + {0xe9b7a6, 0xf3bc}, /* U+9DE6 */ + {0xe9b7a7, 0xfee7}, /* U+9DE7 [2000] */ + {0xe9b7ad, 0xf3bd}, /* U+9DED */ + {0xe9b7af, 0xf3be}, /* U+9DEF */ + {0xe9b7b2, 0xcfc9}, /* U+9DF2 */ + {0xe9b7b4, 0x8ffeca}, /* U+9DF4 [2000] */ + {0xe9b7b8, 0xf3bb}, /* U+9DF8 */ + {0xe9b7b9, 0xc2eb}, /* U+9DF9 */ + {0xe9b7ba, 0xbaed}, /* U+9DFA */ + {0xe9b7bd, 0xf3bf}, /* U+9DFD */ + {0xe9b882, 0x8ffecd}, /* U+9E02 [2000] */ + {0xe9b887, 0xfee8}, /* U+9E07 [2000] */ + {0xe9b88a, 0x8ffecc}, /* U+9E0A [2000] */ + {0xe9b88d, 0x8ffece}, /* U+9E0D [2000] */ + {0xe9b895, 0xfee9}, /* U+9E15 [2000] */ + {0xe9b899, 0x8ffecf}, /* U+9E19 [2000] */ + {0xe9b89a, 0xf3c0}, /* U+9E1A */ + {0xe9b89b, 0xf3c1}, /* U+9E1B */ + {0xe9b89c, 0x8ffed0}, /* U+9E1C [2000] */ + {0xe9b89d, 0x8ffed1}, /* U+9E1D [2000] */ + {0xe9b89e, 0xf3c2}, /* U+9E1E */ + {0xe9b9b5, 0xf3c3}, /* U+9E75 */ + {0xe9b9b8, 0xb8b4}, /* U+9E78 */ + {0xe9b9b9, 0xf3c4}, /* U+9E79 */ + {0xe9b9bb, 0x8ffed2}, /* U+9E7B [2000] */ + {0xe9b9bc, 0xfeea}, /* U+9E7C [2000] */ + {0xe9b9bd, 0xf3c5}, /* U+9E7D */ + {0xe9b9bf, 0xbcaf}, /* U+9E7F */ + {0xe9ba80, 0x8ffed4}, /* U+9E80 [2000] */ + {0xe9ba81, 0xf3c6}, /* U+9E81 */ + {0xe9ba85, 0x8ffed5}, /* U+9E85 [2000] */ + {0xe9ba88, 0xf3c7}, /* U+9E88 */ + {0xe9ba8b, 0xf3c8}, /* U+9E8B */ + {0xe9ba8c, 0xf3c9}, /* U+9E8C */ + {0xe9ba91, 0xf3cc}, /* U+9E91 */ + {0xe9ba92, 0xf3ca}, /* U+9E92 */ + {0xe9ba93, 0xcfbc}, /* U+9E93 */ + {0xe9ba95, 0xf3cb}, /* U+9E95 */ + {0xe9ba97, 0xceef}, /* U+9E97 */ + {0xe9ba9b, 0x8ffed6}, /* U+9E9B [2000] */ + {0xe9ba9d, 0xf3cd}, /* U+9E9D */ + {0xe9ba9e, 0xfeeb}, /* U+9E9E [2000] */ + {0xe9ba9f, 0xcedb}, /* U+9E9F */ + {0xe9baa4, 0xfeec}, /* U+9EA4 [2000] */ + {0xe9baa5, 0xf3ce}, /* U+9EA5 */ + {0xe9baa6, 0xc7fe}, /* U+9EA6 */ + {0xe9baa8, 0x8ffed7}, /* U+9EA8 [2000] */ + {0xe9baa9, 0xf3cf}, /* U+9EA9 */ + {0xe9baaa, 0xf3d1}, /* U+9EAA */ + {0xe9baac, 0xfeed}, /* U+9EAC [2000] */ + {0xe9baad, 0xf3d2}, /* U+9EAD */ + {0xe9baaf, 0xfeee}, /* U+9EAF [2000] */ + {0xe9bab4, 0xfeef}, /* U+9EB4 [2000] */ + {0xe9bab5, 0xfef0}, /* U+9EB5 [2000] */ + {0xe9bab8, 0xf3d0}, /* U+9EB8 */ + {0xe9bab9, 0xb9ed}, /* U+9EB9 */ + {0xe9baba, 0xcccd}, /* U+9EBA */ + {0xe9babb, 0xcbe3}, /* U+9EBB */ + {0xe9babc, 0xd6f7}, /* U+9EBC */ + {0xe9babd, 0x8ffed9}, /* U+9EBD [2000] */ + {0xe9babe, 0xdde0}, /* U+9EBE */ + {0xe9babf, 0xcbfb}, /* U+9EBF */ + {0xe9bb83, 0xfef1}, /* U+9EC3 [2000] */ + {0xe9bb84, 0xb2ab}, /* U+9EC4 */ + {0xe9bb8c, 0xf3d4}, /* U+9ECC */ + {0xe9bb8d, 0xb5d0}, /* U+9ECD */ + {0xe9bb8e, 0xf3d5}, /* U+9ECE */ + {0xe9bb8f, 0xf3d6}, /* U+9ECF */ + {0xe9bb90, 0xf3d7}, /* U+9ED0 */ + {0xe9bb91, 0xfef2}, /* U+9ED1 [2000] */ + {0xe9bb92, 0xb9f5}, /* U+9ED2 */ + {0xe9bb94, 0xf3d8}, /* U+9ED4 */ + {0xe9bb98, 0xe0d4}, /* U+9ED8 */ + {0xe9bb99, 0xccdb}, /* U+9ED9 */ + {0xe9bb9b, 0xc2e3}, /* U+9EDB */ + {0xe9bb9c, 0xf3d9}, /* U+9EDC */ + {0xe9bb9d, 0xf3db}, /* U+9EDD */ + {0xe9bb9e, 0xf3da}, /* U+9EDE */ + {0xe9bb9f, 0x8ffedb}, /* U+9EDF [2000] */ + {0xe9bba0, 0xf3dc}, /* U+9EE0 */ + {0xe9bba5, 0xf3dd}, /* U+9EE5 */ + {0xe9bba7, 0x8ffedc}, /* U+9EE7 [2000] */ + {0xe9bba8, 0xf3de}, /* U+9EE8 */ + {0xe9bbae, 0x8ffedd}, /* U+9EEE [2000] */ + {0xe9bbaf, 0xf3df}, /* U+9EEF */ + {0xe9bbb4, 0xf3e0}, /* U+9EF4 */ + {0xe9bbb6, 0xf3e1}, /* U+9EF6 */ + {0xe9bbb7, 0xf3e2}, /* U+9EF7 */ + {0xe9bbb9, 0xf3e3}, /* U+9EF9 */ + {0xe9bbbb, 0xf3e4}, /* U+9EFB */ + {0xe9bbbc, 0xf3e5}, /* U+9EFC */ + {0xe9bbbd, 0xf3e6}, /* U+9EFD */ + {0xe9bbbf, 0x8ffede}, /* U+9EFF [2000] */ + {0xe9bc82, 0x8ffedf}, /* U+9F02 [2000] */ + {0xe9bc83, 0x8ffee1}, /* U+9F03 [2000] */ + {0xe9bc87, 0xf3e7}, /* U+9F07 */ + {0xe9bc88, 0xf3e8}, /* U+9F08 */ + {0xe9bc8e, 0xc5a4}, /* U+9F0E */ + {0xe9bc90, 0xfef3}, /* U+9F10 [2000] */ + {0xe9bc93, 0xb8dd}, /* U+9F13 */ + {0xe9bc95, 0xf3ea}, /* U+9F15 */ + {0xe9bc97, 0x8ffee2}, /* U+9F17 [2000] */ + {0xe9bc99, 0x8ffee3}, /* U+9F19 [2000] */ + {0xe9bca0, 0xc1cd}, /* U+9F20 */ + {0xe9bca1, 0xf3eb}, /* U+9F21 */ + {0xe9bcac, 0xf3ec}, /* U+9F2C */ + {0xe9bcaf, 0x8ffee4}, /* U+9F2F [2000] */ + {0xe9bcb7, 0x8ffee5}, /* U+9F37 [2000] */ + {0xe9bcb9, 0xfef4}, /* U+9F39 [2000] */ + {0xe9bcba, 0x8ffee6}, /* U+9F3A [2000] */ + {0xe9bcbb, 0xc9a1}, /* U+9F3B */ + {0xe9bcbd, 0x8ffee7}, /* U+9F3D [2000] */ + {0xe9bcbe, 0xf3ed}, /* U+9F3E */ + {0xe9bd81, 0x8ffee8}, /* U+9F41 [2000] */ + {0xe9bd85, 0x8ffee9}, /* U+9F45 [2000] */ + {0xe9bd86, 0x8ffeea}, /* U+9F46 [2000] */ + {0xe9bd8a, 0xf3ee}, /* U+9F4A */ + {0xe9bd8b, 0xe3b7}, /* U+9F4B */ + {0xe9bd8e, 0xecda}, /* U+9F4E */ + {0xe9bd8f, 0xf0ed}, /* U+9F4F */ + {0xe9bd92, 0xf3ef}, /* U+9F52 */ + {0xe9bd93, 0x8ffeeb}, /* U+9F53 [2000] */ + {0xe9bd94, 0xf3f0}, /* U+9F54 */ + {0xe9bd95, 0x8ffeec}, /* U+9F55 [2000] */ + {0xe9bd97, 0xfef5}, /* U+9F57 [2000] */ + {0xe9bd98, 0x8ffeed}, /* U+9F58 [2000] */ + {0xe9bd9d, 0x8ffeef}, /* U+9F5D [2000] */ + {0xe9bd9f, 0xf3f2}, /* U+9F5F */ + {0xe9bda0, 0xf3f3}, /* U+9F60 */ + {0xe9bda1, 0xf3f4}, /* U+9F61 */ + {0xe9bda2, 0xcef0}, /* U+9F62 */ + {0xe9bda3, 0xf3f1}, /* U+9F63 */ + {0xe9bda6, 0xf3f5}, /* U+9F66 */ + {0xe9bda7, 0xf3f6}, /* U+9F67 */ + {0xe9bda9, 0x8ffef1}, /* U+9F69 [2000] */ + {0xe9bdaa, 0xf3f8}, /* U+9F6A */ + {0xe9bdac, 0xf3f7}, /* U+9F6C */ + {0xe9bdad, 0x8ffef3}, /* U+9F6D [2000] */ + {0xe9bdb0, 0x8ffef4}, /* U+9F70 [2000] */ + {0xe9bdb2, 0xf3fa}, /* U+9F72 */ + {0xe9bdb5, 0x8ffef5}, /* U+9F75 [2000] */ + {0xe9bdb6, 0xf3fb}, /* U+9F76 */ + {0xe9bdb7, 0xf3f9}, /* U+9F77 */ + {0xe9be8d, 0xceb6}, /* U+9F8D */ + {0xe9be90, 0xfef6}, /* U+9F90 [2000] */ + {0xe9be94, 0xfef7}, /* U+9F94 [2000] */ + {0xe9be95, 0xf3fc}, /* U+9F95 */ + {0xe9be97, 0xfef8}, /* U+9F97 [2000] */ + {0xe9be9c, 0xf3fd}, /* U+9F9C */ + {0xe9be9d, 0xe3d4}, /* U+9F9D */ + {0xe9bea0, 0xf3fe}, /* U+9FA0 */ + {0xe9bea2, 0xfef9}, /* U+9FA2 [2000] */ + {0xefa49d, 0xf6bb}, /* U+F91D CJK COMPATIBILITY IDEOGRAPH-F91D [2000] */ + {0xefa4a8, 0xf4ae}, /* U+F928 CJK COMPATIBILITY IDEOGRAPH-F928 [2000] */ + {0xefa4a9, 0xf5ce}, /* U+F929 CJK COMPATIBILITY IDEOGRAPH-F929 [2000] */ + {0xefa4b6, 0xfbcf}, /* U+F936 CJK COMPATIBILITY IDEOGRAPH-F936 [2000] */ + {0xefa5b0, 0xf6c9}, /* U+F970 CJK COMPATIBILITY IDEOGRAPH-F970 [2000] */ + {0xefa790, 0xfea4}, /* U+F9D0 CJK COMPATIBILITY IDEOGRAPH-F9D0 [2000] */ + {0xefa79c, 0xfddd}, /* U+F9DC CJK COMPATIBILITY IDEOGRAPH-F9DC [2000] */ + {0xefa88f, 0xafcb}, /* U+FA0F CJK COMPATIBILITY IDEOGRAPH-FA0F [2000] */ + {0xefa890, 0xafd7}, /* U+FA10 CJK COMPATIBILITY IDEOGRAPH-FA10 [2000] */ + {0xefa891, 0xcff2}, /* U+FA11 CJK COMPATIBILITY IDEOGRAPH-FA11 [2000] */ + {0xefa893, 0x8faef9}, /* U+FA13 CJK COMPATIBILITY IDEOGRAPH-FA13 [2000] */ + {0xefa894, 0xf5fa}, /* U+FA14 CJK COMPATIBILITY IDEOGRAPH-FA14 [2000] */ + {0xefa895, 0xf7da}, /* U+FA15 CJK COMPATIBILITY IDEOGRAPH-FA15 [2000] */ + {0xefa896, 0xf7ef}, /* U+FA16 CJK COMPATIBILITY IDEOGRAPH-FA16 [2000] */ + {0xefa899, 0xf9bc}, /* U+FA19 CJK COMPATIBILITY IDEOGRAPH-FA19 [2000] */ + {0xefa89a, 0xf9bd}, /* U+FA1A CJK COMPATIBILITY IDEOGRAPH-FA1A [2000] */ + {0xefa89b, 0xf9c1}, /* U+FA1B CJK COMPATIBILITY IDEOGRAPH-FA1B [2000] */ + {0xefa89f, 0xfbba}, /* U+FA1F CJK COMPATIBILITY IDEOGRAPH-FA1F [2000] */ + {0xefa8a0, 0x8ff7b8}, /* U+FA20 CJK COMPATIBILITY IDEOGRAPH-FA20 [2000] */ + {0xefa8a1, 0x8ff7c5}, /* U+FA21 CJK COMPATIBILITY IDEOGRAPH-FA21 [2000] */ + {0xefa8a2, 0xfcae}, /* U+FA22 CJK COMPATIBILITY IDEOGRAPH-FA22 [2000] */ + {0xefa8a4, 0x8ff9ee}, /* U+FA24 CJK COMPATIBILITY IDEOGRAPH-FA24 [2000] */ + {0xefa8a6, 0xfcea}, /* U+FA26 CJK COMPATIBILITY IDEOGRAPH-FA26 [2000] */ + {0xefa8b0, 0xaeb8}, /* U+FA30 CJK COMPATIBILITY IDEOGRAPH-FA30 [2000] [Unicode3.2] */ + {0xefa8b1, 0xaec9}, /* U+FA31 CJK COMPATIBILITY IDEOGRAPH-FA31 [2000] [Unicode3.2] */ + {0xefa8b2, 0xaed0}, /* U+FA32 CJK COMPATIBILITY IDEOGRAPH-FA32 [2000] [Unicode3.2] */ + {0xefa8b3, 0xaee3}, /* U+FA33 CJK COMPATIBILITY IDEOGRAPH-FA33 [2000] [Unicode3.2] */ + {0xefa8b4, 0xaee8}, /* U+FA34 CJK COMPATIBILITY IDEOGRAPH-FA34 [2000] [Unicode3.2] */ + {0xefa8b5, 0xaeee}, /* U+FA35 CJK COMPATIBILITY IDEOGRAPH-FA35 [2000] [Unicode3.2] */ + {0xefa8b6, 0xafac}, /* U+FA36 CJK COMPATIBILITY IDEOGRAPH-FA36 [2000] [Unicode3.2] */ + {0xefa8b7, 0xafaf}, /* U+FA37 CJK COMPATIBILITY IDEOGRAPH-FA37 [2000] [Unicode3.2] */ + {0xefa8b8, 0xafb6}, /* U+FA38 CJK COMPATIBILITY IDEOGRAPH-FA38 [2000] [Unicode3.2] */ + {0xefa8b9, 0xafda}, /* U+FA39 CJK COMPATIBILITY IDEOGRAPH-FA39 [2000] [Unicode3.2] */ + {0xefa8ba, 0xafde}, /* U+FA3A CJK COMPATIBILITY IDEOGRAPH-FA3A [2000] [Unicode3.2] */ + {0xefa8bb, 0xcfe1}, /* U+FA3B CJK COMPATIBILITY IDEOGRAPH-FA3B [2000] [Unicode3.2] */ + {0xefa8bc, 0xcfe2}, /* U+FA3C CJK COMPATIBILITY IDEOGRAPH-FA3C [2000] [Unicode3.2] */ + {0xefa8bd, 0xf4d0}, /* U+FA3D CJK COMPATIBILITY IDEOGRAPH-FA3D [2000] [Unicode3.2] */ + {0xefa8be, 0xf4dc}, /* U+FA3E CJK COMPATIBILITY IDEOGRAPH-FA3E [2000] [Unicode3.2] */ + {0xefa8bf, 0xf4de}, /* U+FA3F CJK COMPATIBILITY IDEOGRAPH-FA3F [2000] [Unicode3.2] */ + {0xefa980, 0xf4e1}, /* U+FA40 CJK COMPATIBILITY IDEOGRAPH-FA40 [2000] [Unicode3.2] */ + {0xefa981, 0xf5a8}, /* U+FA41 CJK COMPATIBILITY IDEOGRAPH-FA41 [2000] [Unicode3.2] */ + {0xefa982, 0xf5ab}, /* U+FA42 CJK COMPATIBILITY IDEOGRAPH-FA42 [2000] [Unicode3.2] */ + {0xefa983, 0xf5c3}, /* U+FA43 CJK COMPATIBILITY IDEOGRAPH-FA43 [2000] [Unicode3.2] */ + {0xefa984, 0xf5e5}, /* U+FA44 CJK COMPATIBILITY IDEOGRAPH-FA44 [2000] [Unicode3.2] */ + {0xefa985, 0xf6e9}, /* U+FA45 CJK COMPATIBILITY IDEOGRAPH-FA45 [2000] [Unicode3.2] */ + {0xefa986, 0xf6f7}, /* U+FA46 CJK COMPATIBILITY IDEOGRAPH-FA46 [2000] [Unicode3.2] */ + {0xefa987, 0xf7a5}, /* U+FA47 CJK COMPATIBILITY IDEOGRAPH-FA47 [2000] [Unicode3.2] */ + {0xefa988, 0xf7d5}, /* U+FA48 CJK COMPATIBILITY IDEOGRAPH-FA48 [2000] [Unicode3.2] */ + {0xefa989, 0x8ff0a9}, /* U+FA49 CJK COMPATIBILITY IDEOGRAPH-FA49 [2000] [Unicode3.2] */ + {0xefa98a, 0xf8a5}, /* U+FA4A CJK COMPATIBILITY IDEOGRAPH-FA4A [2000] [Unicode3.2] */ + {0xefa98b, 0xf9a7}, /* U+FA4B CJK COMPATIBILITY IDEOGRAPH-FA4B [2000] [Unicode3.2] */ + {0xefa98c, 0xf9b3}, /* U+FA4C CJK COMPATIBILITY IDEOGRAPH-FA4C [2000] [Unicode3.2] */ + {0xefa98d, 0xf9b4}, /* U+FA4D CJK COMPATIBILITY IDEOGRAPH-FA4D [2000] [Unicode3.2] */ + {0xefa98e, 0xf9b7}, /* U+FA4E CJK COMPATIBILITY IDEOGRAPH-FA4E [2000] [Unicode3.2] */ + {0xefa98f, 0xf9b8}, /* U+FA4F CJK COMPATIBILITY IDEOGRAPH-FA4F [2000] [Unicode3.2] */ + {0xefa990, 0xf9b9}, /* U+FA50 CJK COMPATIBILITY IDEOGRAPH-FA50 [2000] [Unicode3.2] */ + {0xefa991, 0xf9bb}, /* U+FA51 CJK COMPATIBILITY IDEOGRAPH-FA51 [2000] [Unicode3.2] */ + {0xefa992, 0xf9bf}, /* U+FA52 CJK COMPATIBILITY IDEOGRAPH-FA52 [2000] [Unicode3.2] */ + {0xefa993, 0xf9c0}, /* U+FA53 CJK COMPATIBILITY IDEOGRAPH-FA53 [2000] [Unicode3.2] */ + {0xefa994, 0xf9cd}, /* U+FA54 CJK COMPATIBILITY IDEOGRAPH-FA54 [2000] [Unicode3.2] */ + {0xefa995, 0xf9d1}, /* U+FA55 CJK COMPATIBILITY IDEOGRAPH-FA55 [2000] [Unicode3.2] */ + {0xefa996, 0xf9e4}, /* U+FA56 CJK COMPATIBILITY IDEOGRAPH-FA56 [2000] [Unicode3.2] */ + {0xefa997, 0xfaae}, /* U+FA57 CJK COMPATIBILITY IDEOGRAPH-FA57 [2000] [Unicode3.2] */ + {0xefa998, 0x8ff4d0}, /* U+FA58 CJK COMPATIBILITY IDEOGRAPH-FA58 [2000] [Unicode3.2] */ + {0xefa999, 0xfab3}, /* U+FA59 CJK COMPATIBILITY IDEOGRAPH-FA59 [2000] [Unicode3.2] */ + {0xefa99a, 0xfaba}, /* U+FA5A CJK COMPATIBILITY IDEOGRAPH-FA5A [2000] [Unicode3.2] */ + {0xefa99b, 0xfac4}, /* U+FA5B CJK COMPATIBILITY IDEOGRAPH-FA5B [2000] [Unicode3.2] */ + {0xefa99c, 0xfad8}, /* U+FA5C CJK COMPATIBILITY IDEOGRAPH-FA5C [2000] [Unicode3.2] */ + {0xefa99d, 0x8ff5f4}, /* U+FA5D CJK COMPATIBILITY IDEOGRAPH-FA5D [2000] [Unicode3.2] */ + {0xefa99e, 0x8ff5f5}, /* U+FA5E CJK COMPATIBILITY IDEOGRAPH-FA5E [2000] [Unicode3.2] */ + {0xefa99f, 0xfba7}, /* U+FA5F CJK COMPATIBILITY IDEOGRAPH-FA5F [2000] [Unicode3.2] */ + {0xefa9a0, 0xfbef}, /* U+FA60 CJK COMPATIBILITY IDEOGRAPH-FA60 [2000] [Unicode3.2] */ + {0xefa9a1, 0xfbf9}, /* U+FA61 CJK COMPATIBILITY IDEOGRAPH-FA61 [2000] [Unicode3.2] */ + {0xefa9a2, 0xfcaf}, /* U+FA62 CJK COMPATIBILITY IDEOGRAPH-FA62 [2000] [Unicode3.2] */ + {0xefa9a3, 0xfcb0}, /* U+FA63 CJK COMPATIBILITY IDEOGRAPH-FA63 [2000] [Unicode3.2] */ + {0xefa9a4, 0xfcb8}, /* U+FA64 CJK COMPATIBILITY IDEOGRAPH-FA64 [2000] [Unicode3.2] */ + {0xefa9a5, 0xfcbd}, /* U+FA65 CJK COMPATIBILITY IDEOGRAPH-FA65 [2000] [Unicode3.2] */ + {0xefa9a6, 0x8ff9e9}, /* U+FA66 CJK COMPATIBILITY IDEOGRAPH-FA66 [2000] [Unicode3.2] */ + {0xefa9a7, 0xfcd9}, /* U+FA67 CJK COMPATIBILITY IDEOGRAPH-FA67 [2000] [Unicode3.2] */ + {0xefa9a8, 0xfde3}, /* U+FA68 CJK COMPATIBILITY IDEOGRAPH-FA68 [2000] [Unicode3.2] */ + {0xefa9a9, 0xfdf6}, /* U+FA69 CJK COMPATIBILITY IDEOGRAPH-FA69 [2000] [Unicode3.2] */ + {0xefa9aa, 0xfdfb}, /* U+FA6A CJK COMPATIBILITY IDEOGRAPH-FA6A [2000] [Unicode3.2] */ + {0xefb985, 0xa3be}, /* U+FE45 SESAME DOT [2000] [Unicode3.2] */ + {0xefb986, 0xa3bd}, /* U+FE46 WHITE SESAME DOT [2000] [Unicode3.2] */ + {0xefbc81, 0xa1aa}, /* U+FF01 FULLWIDTH EXCLAMATION MARK */ + {0xefbc82, 0xa2b0}, /* U+FF02 FULLWIDTH QUOTATION MARK [2000] */ + {0xefbc83, 0xa1f4}, /* U+FF03 FULLWIDTH NUMBER SIGN */ + {0xefbc84, 0xa1f0}, /* U+FF04 FULLWIDTH DOLLAR SIGN */ + {0xefbc85, 0xa1f3}, /* U+FF05 FULLWIDTH PERCENT SIGN */ + {0xefbc86, 0xa1f5}, /* U+FF06 FULLWIDTH AMPERSAND */ + {0xefbc87, 0xa2af}, /* U+FF07 FULLWIDTH APOSTROPHE */ + {0xefbc88, 0xa1ca}, /* U+FF08 FULLWIDTH LEFT PARENTHESIS */ + {0xefbc89, 0xa1cb}, /* U+FF09 FULLWIDTH RIGHT PARENTHESIS */ + {0xefbc8a, 0xa1f6}, /* U+FF0A FULLWIDTH ASTERISK */ + {0xefbc8b, 0xa1dc}, /* U+FF0B FULLWIDTH PLUS SIGN */ + {0xefbc8c, 0xa1a4}, /* U+FF0C FULLWIDTH COMMA */ + {0xefbc8d, 0xa2b1}, /* U+FF0D FULLWIDTH HYPHEN-MINUS [2000] */ + {0xefbc8e, 0xa1a5}, /* U+FF0E FULLWIDTH FULL STOP */ + {0xefbc8f, 0xa1bf}, /* U+FF0F FULLWIDTH SOLIDUS */ + {0xefbc90, 0xa3b0}, /* U+FF10 FULLWIDTH DIGIT ZERO */ + {0xefbc91, 0xa3b1}, /* U+FF11 FULLWIDTH DIGIT ONE */ + {0xefbc92, 0xa3b2}, /* U+FF12 FULLWIDTH DIGIT TWO */ + {0xefbc93, 0xa3b3}, /* U+FF13 FULLWIDTH DIGIT THREE */ + {0xefbc94, 0xa3b4}, /* U+FF14 FULLWIDTH DIGIT FOUR */ + {0xefbc95, 0xa3b5}, /* U+FF15 FULLWIDTH DIGIT FIVE */ + {0xefbc96, 0xa3b6}, /* U+FF16 FULLWIDTH DIGIT SIX */ + {0xefbc97, 0xa3b7}, /* U+FF17 FULLWIDTH DIGIT SEVEN */ + {0xefbc98, 0xa3b8}, /* U+FF18 FULLWIDTH DIGIT EIGHT */ + {0xefbc99, 0xa3b9}, /* U+FF19 FULLWIDTH DIGIT NINE */ + {0xefbc9a, 0xa1a7}, /* U+FF1A FULLWIDTH COLON */ + {0xefbc9b, 0xa1a8}, /* U+FF1B FULLWIDTH SEMICOLON */ + {0xefbc9c, 0xa1e3}, /* U+FF1C FULLWIDTH LESS-THAN SIGN */ + {0xefbc9d, 0xa1e1}, /* U+FF1D FULLWIDTH EQUALS SIGN */ + {0xefbc9e, 0xa1e4}, /* U+FF1E FULLWIDTH GREATER-THAN SIGN */ + {0xefbc9f, 0xa1a9}, /* U+FF1F FULLWIDTH QUESTION MARK */ + {0xefbca0, 0xa1f7}, /* U+FF20 FULLWIDTH COMMERCIAL AT */ + {0xefbca1, 0xa3c1}, /* U+FF21 FULLWIDTH LATIN CAPITAL LETTER A */ + {0xefbca2, 0xa3c2}, /* U+FF22 FULLWIDTH LATIN CAPITAL LETTER B */ + {0xefbca3, 0xa3c3}, /* U+FF23 FULLWIDTH LATIN CAPITAL LETTER C */ + {0xefbca4, 0xa3c4}, /* U+FF24 FULLWIDTH LATIN CAPITAL LETTER D */ + {0xefbca5, 0xa3c5}, /* U+FF25 FULLWIDTH LATIN CAPITAL LETTER E */ + {0xefbca6, 0xa3c6}, /* U+FF26 FULLWIDTH LATIN CAPITAL LETTER F */ + {0xefbca7, 0xa3c7}, /* U+FF27 FULLWIDTH LATIN CAPITAL LETTER G */ + {0xefbca8, 0xa3c8}, /* U+FF28 FULLWIDTH LATIN CAPITAL LETTER H */ + {0xefbca9, 0xa3c9}, /* U+FF29 FULLWIDTH LATIN CAPITAL LETTER I */ + {0xefbcaa, 0xa3ca}, /* U+FF2A FULLWIDTH LATIN CAPITAL LETTER J */ + {0xefbcab, 0xa3cb}, /* U+FF2B FULLWIDTH LATIN CAPITAL LETTER K */ + {0xefbcac, 0xa3cc}, /* U+FF2C FULLWIDTH LATIN CAPITAL LETTER L */ + {0xefbcad, 0xa3cd}, /* U+FF2D FULLWIDTH LATIN CAPITAL LETTER M */ + {0xefbcae, 0xa3ce}, /* U+FF2E FULLWIDTH LATIN CAPITAL LETTER N */ + {0xefbcaf, 0xa3cf}, /* U+FF2F FULLWIDTH LATIN CAPITAL LETTER O */ + {0xefbcb0, 0xa3d0}, /* U+FF30 FULLWIDTH LATIN CAPITAL LETTER P */ + {0xefbcb1, 0xa3d1}, /* U+FF31 FULLWIDTH LATIN CAPITAL LETTER Q */ + {0xefbcb2, 0xa3d2}, /* U+FF32 FULLWIDTH LATIN CAPITAL LETTER R */ + {0xefbcb3, 0xa3d3}, /* U+FF33 FULLWIDTH LATIN CAPITAL LETTER S */ + {0xefbcb4, 0xa3d4}, /* U+FF34 FULLWIDTH LATIN CAPITAL LETTER T */ + {0xefbcb5, 0xa3d5}, /* U+FF35 FULLWIDTH LATIN CAPITAL LETTER U */ + {0xefbcb6, 0xa3d6}, /* U+FF36 FULLWIDTH LATIN CAPITAL LETTER V */ + {0xefbcb7, 0xa3d7}, /* U+FF37 FULLWIDTH LATIN CAPITAL LETTER W */ + {0xefbcb8, 0xa3d8}, /* U+FF38 FULLWIDTH LATIN CAPITAL LETTER X */ + {0xefbcb9, 0xa3d9}, /* U+FF39 FULLWIDTH LATIN CAPITAL LETTER Y */ + {0xefbcba, 0xa3da}, /* U+FF3A FULLWIDTH LATIN CAPITAL LETTER Z */ + {0xefbcbb, 0xa1ce}, /* U+FF3B FULLWIDTH LEFT SQUARE BRACKET */ + {0xefbcbc, 0xa1c0}, /* U+FF3C FULLWIDTH REVERSE SOLIDUS */ + {0xefbcbd, 0xa1cf}, /* U+FF3D FULLWIDTH RIGHT SQUARE BRACKET */ + {0xefbcbe, 0xa1b0}, /* U+FF3E FULLWIDTH CIRCUMFLEX ACCENT */ + {0xefbcbf, 0xa1b2}, /* U+FF3F FULLWIDTH LOW LINE */ + {0xefbd80, 0xa1ae}, /* U+FF40 FULLWIDTH GRAVE ACCENT */ + {0xefbd81, 0xa3e1}, /* U+FF41 FULLWIDTH LATIN SMALL LETTER A */ + {0xefbd82, 0xa3e2}, /* U+FF42 FULLWIDTH LATIN SMALL LETTER B */ + {0xefbd83, 0xa3e3}, /* U+FF43 FULLWIDTH LATIN SMALL LETTER C */ + {0xefbd84, 0xa3e4}, /* U+FF44 FULLWIDTH LATIN SMALL LETTER D */ + {0xefbd85, 0xa3e5}, /* U+FF45 FULLWIDTH LATIN SMALL LETTER E */ + {0xefbd86, 0xa3e6}, /* U+FF46 FULLWIDTH LATIN SMALL LETTER F */ + {0xefbd87, 0xa3e7}, /* U+FF47 FULLWIDTH LATIN SMALL LETTER G */ + {0xefbd88, 0xa3e8}, /* U+FF48 FULLWIDTH LATIN SMALL LETTER H */ + {0xefbd89, 0xa3e9}, /* U+FF49 FULLWIDTH LATIN SMALL LETTER I */ + {0xefbd8a, 0xa3ea}, /* U+FF4A FULLWIDTH LATIN SMALL LETTER J */ + {0xefbd8b, 0xa3eb}, /* U+FF4B FULLWIDTH LATIN SMALL LETTER K */ + {0xefbd8c, 0xa3ec}, /* U+FF4C FULLWIDTH LATIN SMALL LETTER L */ + {0xefbd8d, 0xa3ed}, /* U+FF4D FULLWIDTH LATIN SMALL LETTER M */ + {0xefbd8e, 0xa3ee}, /* U+FF4E FULLWIDTH LATIN SMALL LETTER N */ + {0xefbd8f, 0xa3ef}, /* U+FF4F FULLWIDTH LATIN SMALL LETTER O */ + {0xefbd90, 0xa3f0}, /* U+FF50 FULLWIDTH LATIN SMALL LETTER P */ + {0xefbd91, 0xa3f1}, /* U+FF51 FULLWIDTH LATIN SMALL LETTER Q */ + {0xefbd92, 0xa3f2}, /* U+FF52 FULLWIDTH LATIN SMALL LETTER R */ + {0xefbd93, 0xa3f3}, /* U+FF53 FULLWIDTH LATIN SMALL LETTER S */ + {0xefbd94, 0xa3f4}, /* U+FF54 FULLWIDTH LATIN SMALL LETTER T */ + {0xefbd95, 0xa3f5}, /* U+FF55 FULLWIDTH LATIN SMALL LETTER U */ + {0xefbd96, 0xa3f6}, /* U+FF56 FULLWIDTH LATIN SMALL LETTER V */ + {0xefbd97, 0xa3f7}, /* U+FF57 FULLWIDTH LATIN SMALL LETTER W */ + {0xefbd98, 0xa3f8}, /* U+FF58 FULLWIDTH LATIN SMALL LETTER X */ + {0xefbd99, 0xa3f9}, /* U+FF59 FULLWIDTH LATIN SMALL LETTER Y */ + {0xefbd9a, 0xa3fa}, /* U+FF5A FULLWIDTH LATIN SMALL LETTER Z */ + {0xefbd9b, 0xa1d0}, /* U+FF5B FULLWIDTH LEFT CURLY BRACKET */ + {0xefbd9c, 0xa1c3}, /* U+FF5C FULLWIDTH VERTICAL LINE */ + {0xefbd9d, 0xa1d1}, /* U+FF5D FULLWIDTH RIGHT CURLY BRACKET */ + {0xefbd9e, 0xa2b2}, /* U+FF5E FULLWIDTH TILDE [2000] */ + {0xefbd9f, 0xa2d6}, /* U+FF5F FULLWIDTH LEFT WHITE PARENTHESIS [2000] [Unicode3.2] */ + {0xefbda0, 0xa2d7}, /* U+FF60 FULLWIDTH RIGHT WHITE PARENTHESIS [2000] [Unicode3.2] */ + {0xefbda1, 0x8ea1}, /* U+FF61 HALFWIDTH IDEOGRAPHIC FULL STOP */ + {0xefbda2, 0x8ea2}, /* U+FF62 HALFWIDTH LEFT CORNER BRACKET */ + {0xefbda3, 0x8ea3}, /* U+FF63 HALFWIDTH RIGHT CORNER BRACKET */ + {0xefbda4, 0x8ea4}, /* U+FF64 HALFWIDTH IDEOGRAPHIC COMMA */ + {0xefbda5, 0x8ea5}, /* U+FF65 HALFWIDTH KATAKANA MIDDLE DOT */ + {0xefbda6, 0x8ea6}, /* U+FF66 HALFWIDTH KATAKANA LETTER WO */ + {0xefbda7, 0x8ea7}, /* U+FF67 HALFWIDTH KATAKANA LETTER SMALL A */ + {0xefbda8, 0x8ea8}, /* U+FF68 HALFWIDTH KATAKANA LETTER SMALL I */ + {0xefbda9, 0x8ea9}, /* U+FF69 HALFWIDTH KATAKANA LETTER SMALL U */ + {0xefbdaa, 0x8eaa}, /* U+FF6A HALFWIDTH KATAKANA LETTER SMALL E */ + {0xefbdab, 0x8eab}, /* U+FF6B HALFWIDTH KATAKANA LETTER SMALL O */ + {0xefbdac, 0x8eac}, /* U+FF6C HALFWIDTH KATAKANA LETTER SMALL YA */ + {0xefbdad, 0x8ead}, /* U+FF6D HALFWIDTH KATAKANA LETTER SMALL YU */ + {0xefbdae, 0x8eae}, /* U+FF6E HALFWIDTH KATAKANA LETTER SMALL YO */ + {0xefbdaf, 0x8eaf}, /* U+FF6F HALFWIDTH KATAKANA LETTER SMALL TU */ + {0xefbdb0, 0x8eb0}, /* U+FF70 HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK */ + {0xefbdb1, 0x8eb1}, /* U+FF71 HALFWIDTH KATAKANA LETTER A */ + {0xefbdb2, 0x8eb2}, /* U+FF72 HALFWIDTH KATAKANA LETTER I */ + {0xefbdb3, 0x8eb3}, /* U+FF73 HALFWIDTH KATAKANA LETTER U */ + {0xefbdb4, 0x8eb4}, /* U+FF74 HALFWIDTH KATAKANA LETTER E */ + {0xefbdb5, 0x8eb5}, /* U+FF75 HALFWIDTH KATAKANA LETTER O */ + {0xefbdb6, 0x8eb6}, /* U+FF76 HALFWIDTH KATAKANA LETTER KA */ + {0xefbdb7, 0x8eb7}, /* U+FF77 HALFWIDTH KATAKANA LETTER KI */ + {0xefbdb8, 0x8eb8}, /* U+FF78 HALFWIDTH KATAKANA LETTER KU */ + {0xefbdb9, 0x8eb9}, /* U+FF79 HALFWIDTH KATAKANA LETTER KE */ + {0xefbdba, 0x8eba}, /* U+FF7A HALFWIDTH KATAKANA LETTER KO */ + {0xefbdbb, 0x8ebb}, /* U+FF7B HALFWIDTH KATAKANA LETTER SA */ + {0xefbdbc, 0x8ebc}, /* U+FF7C HALFWIDTH KATAKANA LETTER SI */ + {0xefbdbd, 0x8ebd}, /* U+FF7D HALFWIDTH KATAKANA LETTER SU */ + {0xefbdbe, 0x8ebe}, /* U+FF7E HALFWIDTH KATAKANA LETTER SE */ + {0xefbdbf, 0x8ebf}, /* U+FF7F HALFWIDTH KATAKANA LETTER SO */ + {0xefbe80, 0x8ec0}, /* U+FF80 HALFWIDTH KATAKANA LETTER TA */ + {0xefbe81, 0x8ec1}, /* U+FF81 HALFWIDTH KATAKANA LETTER TI */ + {0xefbe82, 0x8ec2}, /* U+FF82 HALFWIDTH KATAKANA LETTER TU */ + {0xefbe83, 0x8ec3}, /* U+FF83 HALFWIDTH KATAKANA LETTER TE */ + {0xefbe84, 0x8ec4}, /* U+FF84 HALFWIDTH KATAKANA LETTER TO */ + {0xefbe85, 0x8ec5}, /* U+FF85 HALFWIDTH KATAKANA LETTER NA */ + {0xefbe86, 0x8ec6}, /* U+FF86 HALFWIDTH KATAKANA LETTER NI */ + {0xefbe87, 0x8ec7}, /* U+FF87 HALFWIDTH KATAKANA LETTER NU */ + {0xefbe88, 0x8ec8}, /* U+FF88 HALFWIDTH KATAKANA LETTER NE */ + {0xefbe89, 0x8ec9}, /* U+FF89 HALFWIDTH KATAKANA LETTER NO */ + {0xefbe8a, 0x8eca}, /* U+FF8A HALFWIDTH KATAKANA LETTER HA */ + {0xefbe8b, 0x8ecb}, /* U+FF8B HALFWIDTH KATAKANA LETTER HI */ + {0xefbe8c, 0x8ecc}, /* U+FF8C HALFWIDTH KATAKANA LETTER HU */ + {0xefbe8d, 0x8ecd}, /* U+FF8D HALFWIDTH KATAKANA LETTER HE */ + {0xefbe8e, 0x8ece}, /* U+FF8E HALFWIDTH KATAKANA LETTER HO */ + {0xefbe8f, 0x8ecf}, /* U+FF8F HALFWIDTH KATAKANA LETTER MA */ + {0xefbe90, 0x8ed0}, /* U+FF90 HALFWIDTH KATAKANA LETTER MI */ + {0xefbe91, 0x8ed1}, /* U+FF91 HALFWIDTH KATAKANA LETTER MU */ + {0xefbe92, 0x8ed2}, /* U+FF92 HALFWIDTH KATAKANA LETTER ME */ + {0xefbe93, 0x8ed3}, /* U+FF93 HALFWIDTH KATAKANA LETTER MO */ + {0xefbe94, 0x8ed4}, /* U+FF94 HALFWIDTH KATAKANA LETTER YA */ + {0xefbe95, 0x8ed5}, /* U+FF95 HALFWIDTH KATAKANA LETTER YU */ + {0xefbe96, 0x8ed6}, /* U+FF96 HALFWIDTH KATAKANA LETTER YO */ + {0xefbe97, 0x8ed7}, /* U+FF97 HALFWIDTH KATAKANA LETTER RA */ + {0xefbe98, 0x8ed8}, /* U+FF98 HALFWIDTH KATAKANA LETTER RI */ + {0xefbe99, 0x8ed9}, /* U+FF99 HALFWIDTH KATAKANA LETTER RU */ + {0xefbe9a, 0x8eda}, /* U+FF9A HALFWIDTH KATAKANA LETTER RE */ + {0xefbe9b, 0x8edb}, /* U+FF9B HALFWIDTH KATAKANA LETTER RO */ + {0xefbe9c, 0x8edc}, /* U+FF9C HALFWIDTH KATAKANA LETTER WA */ + {0xefbe9d, 0x8edd}, /* U+FF9D HALFWIDTH KATAKANA LETTER N */ + {0xefbe9e, 0x8ede}, /* U+FF9E HALFWIDTH KATAKANA VOICED SOUND MARK */ + {0xefbe9f, 0x8edf}, /* U+FF9F HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK */ + {0xf0a0808b, 0xaea2}, /* U+2000B [2000] [Unicode3.1] */ {0xf0a08289, 0x8fa1a1}, /* U+20089 [2000] [Unicode3.1] */ {0xf0a082a2, 0x8fa1ab}, /* U+200A2 [2000] [Unicode3.1] */ {0xf0a082a4, 0x8fa1ae}, /* U+200A4 [2000] [Unicode3.1] */ @@ -11152,7 +11023,7 @@ static const pg_utf_to_local ULmapEUC_JIS_2004[] = { {0xf0a0a69d, 0x8fa3d3}, /* U+2099D [2000] [Unicode3.1] */ {0xf0a0ab93, 0x8fa3d9}, /* U+20AD3 [2000] [Unicode3.1] */ {0xf0a0ac9d, 0x8fa3dc}, /* U+20B1D [2000] [Unicode3.1] */ - {0xf0a0ae9f, 0x00cfd4}, /* U+20B9F [2004] [Unicode3.1] */ + {0xf0a0ae9f, 0xcfd4}, /* U+20B9F [2004] [Unicode3.1] */ {0xf0a0b585, 0x8fa3f7}, /* U+20D45 [2000] [Unicode3.1] */ {0xf0a0b7a1, 0x8fa4aa}, /* U+20DE1 [2000] [Unicode3.1] */ {0xf0a0b9a4, 0x8fa4ba}, /* U+20E64 [2000] [Unicode3.1] */ @@ -11160,25 +11031,25 @@ static const pg_utf_to_local ULmapEUC_JIS_2004[] = { {0xf0a0ba95, 0x8fa4b1}, /* U+20E95 [2000] [Unicode3.1] */ {0xf0a0bd9f, 0x8fa4bd}, /* U+20F5F [2000] [Unicode3.1] */ {0xf0a18881, 0x8fa4d9}, /* U+21201 [2000] [Unicode3.1] */ - {0xf0a188bd, 0x00afc2}, /* U+2123D [2000] [Unicode3.1] */ + {0xf0a188bd, 0xafc2}, /* U+2123D [2000] [Unicode3.1] */ {0xf0a18995, 0x8fa4dc}, /* U+21255 [2000] [Unicode3.1] */ {0xf0a189b4, 0x8fa4e3}, /* U+21274 [2000] [Unicode3.1] */ {0xf0a189bb, 0x8fa4de}, /* U+2127B [2000] [Unicode3.1] */ {0xf0a18b97, 0x8fa4eb}, /* U+212D7 [2000] [Unicode3.1] */ {0xf0a18ba4, 0x8fa4ea}, /* U+212E4 [2000] [Unicode3.1] */ {0xf0a18bbd, 0x8fa4f2}, /* U+212FD [2000] [Unicode3.1] */ - {0xf0a18c9b, 0x00afcc}, /* U+2131B [2000] [Unicode3.1] */ + {0xf0a18c9b, 0xafcc}, /* U+2131B [2000] [Unicode3.1] */ {0xf0a18cb6, 0x8fa4f4}, /* U+21336 [2000] [Unicode3.1] */ {0xf0a18d84, 0x8fa4f5}, /* U+21344 [2000] [Unicode3.1] */ {0xf0a18f84, 0x8fa5a5}, /* U+213C4 [2000] [Unicode3.1] */ {0xf0a191ad, 0x8fa5b2}, /* U+2146D [2000] [Unicode3.1] */ - {0xf0a191ae, 0x00afe0}, /* U+2146E [2000] [Unicode3.1] */ + {0xf0a191ae, 0xafe0}, /* U+2146E [2000] [Unicode3.1] */ {0xf0a19797, 0x8fa5be}, /* U+215D7 [2000] [Unicode3.1] */ {0xf0a19987, 0x8fa5c7}, /* U+21647 [2000] [Unicode3.1] */ - {0xf0a19ab4, 0x00cfe3}, /* U+216B4 [2000] [Unicode3.1] */ + {0xf0a19ab4, 0xcfe3}, /* U+216B4 [2000] [Unicode3.1] */ {0xf0a19c86, 0x8fa5d5}, /* U+21706 [2000] [Unicode3.1] */ {0xf0a19d82, 0x8fa5d6}, /* U+21742 [2000] [Unicode3.1] */ - {0xf0a1a2bd, 0x00affb}, /* U+218BD [2000] [Unicode3.1] */ + {0xf0a1a2bd, 0xaffb}, /* U+218BD [2000] [Unicode3.1] */ {0xf0a1a783, 0x8fa5fe}, /* U+219C3 [2000] [Unicode3.1] */ {0xf0a1b196, 0x8fa8b0}, /* U+21C56 [2000] [Unicode3.1] */ {0xf0a1b4ad, 0x8fa8b7}, /* U+21D2D [2000] [Unicode3.1] */ @@ -11191,7 +11062,7 @@ static const pg_utf_to_local ULmapEUC_JIS_2004[] = { {0xf0a1b6b7, 0x8fa8c8}, /* U+21DB7 [2000] [Unicode3.1] */ {0xf0a1b7a0, 0x8fa8ca}, /* U+21DE0 [2000] [Unicode3.1] */ {0xf0a1b8b3, 0x8fa8cb}, /* U+21E33 [2000] [Unicode3.1] */ - {0xf0a1b8b4, 0x00cfee}, /* U+21E34 [2000] [Unicode3.1] */ + {0xf0a1b8b4, 0xcfee}, /* U+21E34 [2000] [Unicode3.1] */ {0xf0a1bc9e, 0x8fa8db}, /* U+21F1E [2000] [Unicode3.1] */ {0xf0a1bdb6, 0x8fa8e6}, /* U+21F76 [2000] [Unicode3.1] */ {0xf0a1bfba, 0x8fa8ec}, /* U+21FFA [2000] [Unicode3.1] */ @@ -11213,7 +11084,7 @@ static const pg_utf_to_local ULmapEUC_JIS_2004[] = { {0xf0a2b7a1, 0x8fadd6}, /* U+22DE1 [2000] [Unicode3.1] */ {0xf0a386b6, 0x8faea4}, /* U+231B6 [2000] [Unicode3.1] */ {0xf0a38783, 0x8fadfd}, /* U+231C3 [2000] [Unicode3.1] */ - {0xf0a38784, 0x00f5ba}, /* U+231C4 [2000] [Unicode3.1] */ + {0xf0a38784, 0xf5ba}, /* U+231C4 [2000] [Unicode3.1] */ {0xf0a387b5, 0x8faea3}, /* U+231F5 [2000] [Unicode3.1] */ {0xf0a38db2, 0x8faeba}, /* U+23372 [2000] [Unicode3.1] */ {0xf0a38f90, 0x8faec2}, /* U+233D0 [2000] [Unicode3.1] */ @@ -11230,15 +11101,15 @@ static const pg_utf_to_local ULmapEUC_JIS_2004[] = { {0xf0a393a4, 0x8faef7}, /* U+234E4 [2000] [Unicode3.1] */ {0xf0a3959a, 0x8faef8}, /* U+2355A [2000] [Unicode3.1] */ {0xf0a39694, 0x8fafaa}, /* U+23594 [2000] [Unicode3.1] */ - {0xf0a39784, 0x00f5f2}, /* U+235C4 [2000] [Unicode3.1] */ + {0xf0a39784, 0xf5f2}, /* U+235C4 [2000] [Unicode3.1] */ {0xf0a398b8, 0x8fafc2}, /* U+23638 [2000] [Unicode3.1] */ {0xf0a398b9, 0x8fafbf}, /* U+23639 [2000] [Unicode3.1] */ {0xf0a398ba, 0x8fafc3}, /* U+2363A [2000] [Unicode3.1] */ {0xf0a39987, 0x8fafc0}, /* U+23647 [2000] [Unicode3.1] */ {0xf0a39c8c, 0x8fafd9}, /* U+2370C [2000] [Unicode3.1] */ {0xf0a39c9c, 0x8fafce}, /* U+2371C [2000] [Unicode3.1] */ - {0xf0a39cbf, 0x00f6a9}, /* U+2373F [2000] [Unicode3.1] */ - {0xf0a39da3, 0x00f6b2}, /* U+23763 [2000] [Unicode3.1] */ + {0xf0a39cbf, 0xf6a9}, /* U+2373F [2000] [Unicode3.1] */ + {0xf0a39da3, 0xf6b2}, /* U+23763 [2000] [Unicode3.1] */ {0xf0a39da4, 0x8fafe1}, /* U+23764 [2000] [Unicode3.1] */ {0xf0a39fa7, 0x8fafea}, /* U+237E7 [2000] [Unicode3.1] */ {0xf0a39fbf, 0x8fafe9}, /* U+237FF [2000] [Unicode3.1] */ @@ -11246,7 +11117,7 @@ static const pg_utf_to_local ULmapEUC_JIS_2004[] = { {0xf0a3a0bd, 0x8faff5}, /* U+2383D [2000] [Unicode3.1] */ {0xf0a3aa98, 0x8feea3}, /* U+23A98 [2000] [Unicode3.1] */ {0xf0a3b1bf, 0x8feeb4}, /* U+23C7F [2000] [Unicode3.1] */ - {0xf0a3b3be, 0x00f6e0}, /* U+23CFE [2000] [Unicode3.1] */ + {0xf0a3b3be, 0xf6e0}, /* U+23CFE [2000] [Unicode3.1] */ {0xf0a3b480, 0x8feec9}, /* U+23D00 [2000] [Unicode3.1] */ {0xf0a3b48e, 0x8ff4f5}, /* U+23D0E [2000] [Unicode3.1] */ {0xf0a3b580, 0x8feedc}, /* U+23D40 [2000] [Unicode3.1] */ @@ -11261,7 +11132,7 @@ static const pg_utf_to_local ULmapEUC_JIS_2004[] = { {0xf0a48ebc, 0x8ff0a2}, /* U+243BC [2000] [Unicode3.1] */ {0xf0a498a9, 0x8ff0b3}, /* U+24629 [2000] [Unicode3.1] */ {0xf0a49aa5, 0x8ff0b9}, /* U+246A5 [2000] [Unicode3.1] */ - {0xf0a49fb1, 0x00f7ec}, /* U+247F1 [2000] [Unicode3.1] */ + {0xf0a49fb1, 0xf7ec}, /* U+247F1 [2000] [Unicode3.1] */ {0xf0a4a296, 0x8ff0d3}, /* U+24896 [2000] [Unicode3.1] */ {0xf0a4a98d, 0x8ff0fb}, /* U+24A4D [2000] [Unicode3.1] */ {0xf0a4ad96, 0x8ff1ae}, /* U+24B56 [2000] [Unicode3.1] */ @@ -11281,14 +11152,14 @@ static const pg_utf_to_local ULmapEUC_JIS_2004[] = { {0xf0a5889e, 0x8ff2a8}, /* U+2521E [2000] [Unicode3.1] */ {0xf0a5898c, 0x8ff2ac}, /* U+2524C [2000] [Unicode3.1] */ {0xf0a590ae, 0x8ff2bd}, /* U+2542E [2000] [Unicode3.1] */ - {0xf0a5928e, 0x00f8fe}, /* U+2548E [2000] [Unicode3.1] */ + {0xf0a5928e, 0xf8fe}, /* U+2548E [2000] [Unicode3.1] */ {0xf0a59399, 0x8ff2c8}, /* U+254D9 [2000] [Unicode3.1] */ - {0xf0a5948e, 0x00f9a9}, /* U+2550E [2000] [Unicode3.1] */ + {0xf0a5948e, 0xf9a9}, /* U+2550E [2000] [Unicode3.1] */ {0xf0a596a7, 0x8ff2db}, /* U+255A7 [2000] [Unicode3.1] */ - {0xf0a59db1, 0x00f9c7}, /* U+25771 [2000] [Unicode3.1] */ + {0xf0a59db1, 0xf9c7}, /* U+25771 [2000] [Unicode3.1] */ {0xf0a59ea9, 0x8ff2f5}, /* U+257A9 [2000] [Unicode3.1] */ {0xf0a59eb4, 0x8ff2f6}, /* U+257B4 [2000] [Unicode3.1] */ - {0xf0a5a784, 0x00f9d4}, /* U+259C4 [2000] [Unicode3.1] */ + {0xf0a5a784, 0xf9d4}, /* U+259C4 [2000] [Unicode3.1] */ {0xf0a5a794, 0x8ff3b2}, /* U+259D4 [2000] [Unicode3.1] */ {0xf0a5aba3, 0x8ff3be}, /* U+25AE3 [2000] [Unicode3.1] */ {0xf0a5aba4, 0x8ff3bd}, /* U+25AE4 [2000] [Unicode3.1] */ @@ -11296,7 +11167,7 @@ static const pg_utf_to_local ULmapEUC_JIS_2004[] = { {0xf0a5aeb2, 0x8ff3d2}, /* U+25BB2 [2000] [Unicode3.1] */ {0xf0a5b18b, 0x8ff3dd}, /* U+25C4B [2000] [Unicode3.1] */ {0xf0a5b1a4, 0x8ff3de}, /* U+25C64 [2000] [Unicode3.1] */ - {0xf0a5b6a1, 0x00f9ee}, /* U+25DA1 [2000] [Unicode3.1] */ + {0xf0a5b6a1, 0xf9ee}, /* U+25DA1 [2000] [Unicode3.1] */ {0xf0a5b8ae, 0x8ff3f3}, /* U+25E2E [2000] [Unicode3.1] */ {0xf0a5b996, 0x8ff3f4}, /* U+25E56 [2000] [Unicode3.1] */ {0xf0a5b9a2, 0x8ff3f7}, /* U+25E62 [2000] [Unicode3.1] */ @@ -11329,17 +11200,17 @@ static const pg_utf_to_local ULmapEUC_JIS_2004[] = { {0xf0a6a998, 0x8ff5ea}, /* U+26A58 [2000] [Unicode3.1] */ {0xf0a6aa8c, 0x8ff5f0}, /* U+26A8C [2000] [Unicode3.1] */ {0xf0a6aab7, 0x8ff5f3}, /* U+26AB7 [2000] [Unicode3.1] */ - {0xf0a6abbf, 0x00fadd}, /* U+26AFF [2000] [Unicode3.1] */ + {0xf0a6abbf, 0xfadd}, /* U+26AFF [2000] [Unicode3.1] */ {0xf0a6b0a9, 0x8fa5c4}, /* U+26C29 [2000] [Unicode3.1] */ {0xf0a6b1b3, 0x8ff6c4}, /* U+26C73 [2000] [Unicode3.1] */ {0xf0a6b39d, 0x8ff6ce}, /* U+26CDD [2000] [Unicode3.1] */ - {0xf0a6b980, 0x00fbb3}, /* U+26E40 [2000] [Unicode3.1] */ + {0xf0a6b980, 0xfbb3}, /* U+26E40 [2000] [Unicode3.1] */ {0xf0a6b9a5, 0x8ff6dd}, /* U+26E65 [2000] [Unicode3.1] */ {0xf0a6be94, 0x8ff6f5}, /* U+26F94 [2000] [Unicode3.1] */ {0xf0a6bfb6, 0x8ff7a1}, /* U+26FF6 [2000] [Unicode3.1] */ {0xf0a6bfb7, 0x8ff7a2}, /* U+26FF7 [2000] [Unicode3.1] */ {0xf0a6bfb8, 0x8ff6fe}, /* U+26FF8 [2000] [Unicode3.1] */ - {0xf0a783b4, 0x00fbc9}, /* U+270F4 [2000] [Unicode3.1] */ + {0xf0a783b4, 0xfbc9}, /* U+270F4 [2000] [Unicode3.1] */ {0xf0a7848d, 0x8ff7b3}, /* U+2710D [2000] [Unicode3.1] */ {0xf0a784b9, 0x8ff7b6}, /* U+27139 [2000] [Unicode3.1] */ {0xf0a78f9a, 0x8ff7e5}, /* U+273DA [2000] [Unicode3.1] */ @@ -11350,7 +11221,7 @@ static const pg_utf_to_local ULmapEUC_JIS_2004[] = { {0xf0a79894, 0x8ff8aa}, /* U+27614 [2000] [Unicode3.1] */ {0xf0a79895, 0x8ff8a9}, /* U+27615 [2000] [Unicode3.1] */ {0xf0a798b1, 0x8ff8ac}, /* U+27631 [2000] [Unicode3.1] */ - {0xf0a79a84, 0x00fbec}, /* U+27684 [2000] [Unicode3.1] */ + {0xf0a79a84, 0xfbec}, /* U+27684 [2000] [Unicode3.1] */ {0xf0a79a93, 0x8ff8b4}, /* U+27693 [2000] [Unicode3.1] */ {0xf0a79c8e, 0x8ff8bc}, /* U+2770E [2000] [Unicode3.1] */ {0xf0a79ca3, 0x8ff8be}, /* U+27723 [2000] [Unicode3.1] */ @@ -11366,10 +11237,10 @@ static const pg_utf_to_local ULmapEUC_JIS_2004[] = { {0xf0a7beb7, 0x8ff9b9}, /* U+27FB7 [2000] [Unicode3.1] */ {0xf0a8828a, 0x8ff9c2}, /* U+2808A [2000] [Unicode3.1] */ {0xf0a882bb, 0x8ff9c8}, /* U+280BB [2000] [Unicode3.1] */ - {0xf0a889b7, 0x00fcc9}, /* U+28277 [2000] [Unicode3.1] */ + {0xf0a889b7, 0xfcc9}, /* U+28277 [2000] [Unicode3.1] */ {0xf0a88a82, 0x8ff9d9}, /* U+28282 [2000] [Unicode3.1] */ {0xf0a88bb3, 0x8ff9de}, /* U+282F3 [2000] [Unicode3.1] */ - {0xf0a88f8d, 0x00fcd1}, /* U+283CD [2000] [Unicode3.1] */ + {0xf0a88f8d, 0xfcd1}, /* U+283CD [2000] [Unicode3.1] */ {0xf0a8908c, 0x8ff9e6}, /* U+2840C [2000] [Unicode3.1] */ {0xf0a89195, 0x8ff9eb}, /* U+28455 [2000] [Unicode3.1] */ {0xf0a895ab, 0x8ff9fa}, /* U+2856B [2000] [Unicode3.1] */ @@ -11426,7 +11297,7 @@ static const pg_utf_to_local ULmapEUC_JIS_2004[] = { {0xf0aa80af, 0x8ffea9}, /* U+2A02F [2000] [Unicode3.1] */ {0xf0aa8282, 0x8ffeb5}, /* U+2A082 [2000] [Unicode3.1] */ {0xf0aa83b9, 0x8ffeb2}, /* U+2A0F9 [2000] [Unicode3.1] */ - {0xf0aa8690, 0x00fee6}, /* U+2A190 [2000] [Unicode3.1] */ + {0xf0aa8690, 0xfee6}, /* U+2A190 [2000] [Unicode3.1] */ {0xf0aa8e8c, 0x8ffed8}, /* U+2A38C [2000] [Unicode3.1] */ {0xf0aa90b7, 0x8ffeda}, /* U+2A437 [2000] [Unicode3.1] */ {0xf0aa97b1, 0x8ffeee}, /* U+2A5F1 [2000] [Unicode3.1] */ diff --git a/src/backend/utils/mb/Unicode/utf8_to_euc_jis_2004_combined.map b/src/backend/utils/mb/Unicode/utf8_to_euc_jis_2004_combined.map index d098e256df..0d57667a55 100644 --- a/src/backend/utils/mb/Unicode/utf8_to_euc_jis_2004_combined.map +++ b/src/backend/utils/mb/Unicode/utf8_to_euc_jis_2004_combined.map @@ -1,30 +1,29 @@ -/* - * This file was generated by UCS_to_EUC_JIS_2004.pl - */ -static const pg_utf_to_local_combined ULmapEUC_JIS_2004_combined[] = { - {0x0000c3a6, 0x0000cc80, 0x00abc4}, /* U+00E6+0300 [2000] */ - {0x0000c994, 0x0000cc80, 0x00abc8}, /* U+0254+0300 [2000] */ - {0x0000c994, 0x0000cc81, 0x00abc9}, /* U+0254+0301 [2000] */ - {0x0000c999, 0x0000cc80, 0x00abcc}, /* U+0259+0300 [2000] */ - {0x0000c999, 0x0000cc81, 0x00abcd}, /* U+0259+0301 [2000] */ - {0x0000c99a, 0x0000cc80, 0x00abce}, /* U+025A+0300 [2000] */ - {0x0000c99a, 0x0000cc81, 0x00abcf}, /* U+025A+0301 [2000] */ - {0x0000ca8c, 0x0000cc80, 0x00abca}, /* U+028C+0300 [2000] */ - {0x0000ca8c, 0x0000cc81, 0x00abcb}, /* U+028C+0301 [2000] */ - {0x0000cba5, 0x0000cba9, 0x00abe6}, /* U+02E5+02E9 [2000] */ - {0x0000cba9, 0x0000cba5, 0x00abe5}, /* U+02E9+02E5 [2000] */ - {0x00e3818b, 0x00e3829a, 0x00a4f7}, /* U+304B+309A [2000] */ - {0x00e3818d, 0x00e3829a, 0x00a4f8}, /* U+304D+309A [2000] */ - {0x00e3818f, 0x00e3829a, 0x00a4f9}, /* U+304F+309A [2000] */ - {0x00e38191, 0x00e3829a, 0x00a4fa}, /* U+3051+309A [2000] */ - {0x00e38193, 0x00e3829a, 0x00a4fb}, /* U+3053+309A [2000] */ - {0x00e382ab, 0x00e3829a, 0x00a5f7}, /* U+30AB+309A [2000] */ - {0x00e382ad, 0x00e3829a, 0x00a5f8}, /* U+30AD+309A [2000] */ - {0x00e382af, 0x00e3829a, 0x00a5f9}, /* U+30AF+309A [2000] */ - {0x00e382b1, 0x00e3829a, 0x00a5fa}, /* U+30B1+309A [2000] */ - {0x00e382b3, 0x00e3829a, 0x00a5fb}, /* U+30B3+309A [2000] */ - {0x00e382bb, 0x00e3829a, 0x00a5fc}, /* U+30BB+309A [2000] */ - {0x00e38384, 0x00e3829a, 0x00a5fd}, /* U+30C4+309A [2000] */ - {0x00e38388, 0x00e3829a, 0x00a5fe}, /* U+30C8+309A [2000] */ - {0x00e387b7, 0x00e3829a, 0x00a6f8} /* U+31F7+309A [2000] */ +/* src/backend/utils/mb/Unicode/utf8_to_euc_jis_2004_combined.map */ + +static const pg_utf_to_local_combined ULmapEUC_JIS_2004_combined[ 25 ] = { /* */ + {0x0000c3a6, 0x0000cc80, 0xabc4}, /* U+00E6+0300 [2000] */ + {0x0000c994, 0x0000cc80, 0xabc8}, /* U+0254+0300 [2000] */ + {0x0000c994, 0x0000cc81, 0xabc9}, /* U+0254+0301 [2000] */ + {0x0000c999, 0x0000cc80, 0xabcc}, /* U+0259+0300 [2000] */ + {0x0000c999, 0x0000cc81, 0xabcd}, /* U+0259+0301 [2000] */ + {0x0000c99a, 0x0000cc80, 0xabce}, /* U+025A+0300 [2000] */ + {0x0000c99a, 0x0000cc81, 0xabcf}, /* U+025A+0301 [2000] */ + {0x0000ca8c, 0x0000cc80, 0xabca}, /* U+028C+0300 [2000] */ + {0x0000ca8c, 0x0000cc81, 0xabcb}, /* U+028C+0301 [2000] */ + {0x0000cba5, 0x0000cba9, 0xabe6}, /* U+02E5+02E9 [2000] */ + {0x0000cba9, 0x0000cba5, 0xabe5}, /* U+02E9+02E5 [2000] */ + {0x00e3818b, 0x00e3829a, 0xa4f7}, /* U+304B+309A [2000] */ + {0x00e3818d, 0x00e3829a, 0xa4f8}, /* U+304D+309A [2000] */ + {0x00e3818f, 0x00e3829a, 0xa4f9}, /* U+304F+309A [2000] */ + {0x00e38191, 0x00e3829a, 0xa4fa}, /* U+3051+309A [2000] */ + {0x00e38193, 0x00e3829a, 0xa4fb}, /* U+3053+309A [2000] */ + {0x00e382ab, 0x00e3829a, 0xa5f7}, /* U+30AB+309A [2000] */ + {0x00e382ad, 0x00e3829a, 0xa5f8}, /* U+30AD+309A [2000] */ + {0x00e382af, 0x00e3829a, 0xa5f9}, /* U+30AF+309A [2000] */ + {0x00e382b1, 0x00e3829a, 0xa5fa}, /* U+30B1+309A [2000] */ + {0x00e382b3, 0x00e3829a, 0xa5fb}, /* U+30B3+309A [2000] */ + {0x00e382bb, 0x00e3829a, 0xa5fc}, /* U+30BB+309A [2000] */ + {0x00e38384, 0x00e3829a, 0xa5fd}, /* U+30C4+309A [2000] */ + {0x00e38388, 0x00e3829a, 0xa5fe}, /* U+30C8+309A [2000] */ + {0x00e387b7, 0x00e3829a, 0xa6f8} /* U+31F7+309A [2000] */ }; diff --git a/src/backend/utils/mb/Unicode/utf8_to_euc_jp.map b/src/backend/utils/mb/Unicode/utf8_to_euc_jp.map index 137d4fdef6..eef6db65b3 100644 --- a/src/backend/utils/mb/Unicode/utf8_to_euc_jp.map +++ b/src/backend/utils/mb/Unicode/utf8_to_euc_jp.map @@ -1,3 +1,5 @@ +/* src/backend/utils/mb/Unicode/utf8_to_euc_jp.map */ + static const pg_utf_to_local ULmapEUC_JP[ 13175 ] = { {0xc2a1, 0x8fa2c2}, {0xc2a4, 0x8fa2f0}, diff --git a/src/backend/utils/mb/Unicode/utf8_to_euc_kr.map b/src/backend/utils/mb/Unicode/utf8_to_euc_kr.map index 4a78b260ea..a642b2154f 100644 --- a/src/backend/utils/mb/Unicode/utf8_to_euc_kr.map +++ b/src/backend/utils/mb/Unicode/utf8_to_euc_kr.map @@ -1,3 +1,5 @@ +/* src/backend/utils/mb/Unicode/utf8_to_euc_kr.map */ + static const pg_utf_to_local ULmapEUC_KR[ 8227 ] = { {0xc2a1, 0xa2ae}, {0xc2a4, 0xa2b4}, diff --git a/src/backend/utils/mb/Unicode/utf8_to_johab.map b/src/backend/utils/mb/Unicode/utf8_to_johab.map index 869f8213d2..78997d82d0 100644 --- a/src/backend/utils/mb/Unicode/utf8_to_johab.map +++ b/src/backend/utils/mb/Unicode/utf8_to_johab.map @@ -1,3 +1,5 @@ +/* src/backend/utils/mb/Unicode/utf8_to_johab.map */ + static const pg_utf_to_local ULmapJOHAB[ 17049 ] = { {0xc2a1, 0xd9ae}, {0xc2a4, 0xd9b4}, diff --git a/src/backend/utils/mb/Unicode/utf8_to_shift_jis_2004.map b/src/backend/utils/mb/Unicode/utf8_to_shift_jis_2004.map index 5eb8c69564..e9f9e638c6 100644 --- a/src/backend/utils/mb/Unicode/utf8_to_shift_jis_2004.map +++ b/src/backend/utils/mb/Unicode/utf8_to_shift_jis_2004.map @@ -1,11404 +1,11275 @@ -/* - * This file was generated by UCS_to_SHIFT_JIS_2004.pl - */ -static const pg_utf_to_local ULmapSHIFT_JIS_2004[] = { - {0x00000000, 0x000000}, /* U+0000 */ - {0x00000001, 0x000001}, /* U+0001 */ - {0x00000002, 0x000002}, /* U+0002 */ - {0x00000003, 0x000003}, /* U+0003 */ - {0x00000004, 0x000004}, /* U+0004 */ - {0x00000005, 0x000005}, /* U+0005 */ - {0x00000006, 0x000006}, /* U+0006 */ - {0x00000007, 0x000007}, /* U+0007 */ - {0x00000008, 0x000008}, /* U+0008 */ - {0x00000009, 0x000009}, /* U+0009 */ - {0x0000000a, 0x00000a}, /* U+000A */ - {0x0000000b, 0x00000b}, /* U+000B */ - {0x0000000c, 0x00000c}, /* U+000C */ - {0x0000000d, 0x00000d}, /* U+000D */ - {0x0000000e, 0x00000e}, /* U+000E */ - {0x0000000f, 0x00000f}, /* U+000F */ - {0x00000010, 0x000010}, /* U+0010 */ - {0x00000011, 0x000011}, /* U+0011 */ - {0x00000012, 0x000012}, /* U+0012 */ - {0x00000013, 0x000013}, /* U+0013 */ - {0x00000014, 0x000014}, /* U+0014 */ - {0x00000015, 0x000015}, /* U+0015 */ - {0x00000016, 0x000016}, /* U+0016 */ - {0x00000017, 0x000017}, /* U+0017 */ - {0x00000018, 0x000018}, /* U+0018 */ - {0x00000019, 0x000019}, /* U+0019 */ - {0x0000001a, 0x00001a}, /* U+001A */ - {0x0000001b, 0x00001b}, /* U+001B */ - {0x0000001c, 0x00001c}, /* U+001C */ - {0x0000001d, 0x00001d}, /* U+001D */ - {0x0000001e, 0x00001e}, /* U+001E */ - {0x0000001f, 0x00001f}, /* U+001F */ - {0x00000020, 0x000020}, /* U+0020 SPACE */ - {0x00000021, 0x000021}, /* U+0021 EXCLAMATION MARK */ - {0x00000022, 0x000022}, /* U+0022 QUOTATION MARK */ - {0x00000023, 0x000023}, /* U+0023 NUMBER SIGN */ - {0x00000024, 0x000024}, /* U+0024 DOLLAR SIGN */ - {0x00000025, 0x000025}, /* U+0025 PERCENT SIGN */ - {0x00000026, 0x000026}, /* U+0026 AMPERSAND */ - {0x00000027, 0x000027}, /* U+0027 APOSTROPHE */ - {0x00000028, 0x000028}, /* U+0028 LEFT PARENTHESIS */ - {0x00000029, 0x000029}, /* U+0029 RIGHT PARENTHESIS */ - {0x0000002a, 0x00002a}, /* U+002A ASTERISK */ - {0x0000002b, 0x00002b}, /* U+002B PLUS SIGN */ - {0x0000002c, 0x00002c}, /* U+002C COMMA */ - {0x0000002d, 0x00002d}, /* U+002D HYPHEN-MINUS */ - {0x0000002e, 0x00002e}, /* U+002E FULL STOP */ - {0x0000002f, 0x00002f}, /* U+002F SOLIDUS */ - {0x00000030, 0x000030}, /* U+0030 DIGIT ZERO */ - {0x00000031, 0x000031}, /* U+0031 DIGIT ONE */ - {0x00000032, 0x000032}, /* U+0032 DIGIT TWO */ - {0x00000033, 0x000033}, /* U+0033 DIGIT THREE */ - {0x00000034, 0x000034}, /* U+0034 DIGIT FOUR */ - {0x00000035, 0x000035}, /* U+0035 DIGIT FIVE */ - {0x00000036, 0x000036}, /* U+0036 DIGIT SIX */ - {0x00000037, 0x000037}, /* U+0037 DIGIT SEVEN */ - {0x00000038, 0x000038}, /* U+0038 DIGIT EIGHT */ - {0x00000039, 0x000039}, /* U+0039 DIGIT NINE */ - {0x0000003a, 0x00003a}, /* U+003A COLON */ - {0x0000003b, 0x00003b}, /* U+003B SEMICOLON */ - {0x0000003c, 0x00003c}, /* U+003C LESS-THAN SIGN */ - {0x0000003d, 0x00003d}, /* U+003D EQUALS SIGN */ - {0x0000003e, 0x00003e}, /* U+003E GREATER-THAN SIGN */ - {0x0000003f, 0x00003f}, /* U+003F QUESTION MARK */ - {0x00000040, 0x000040}, /* U+0040 COMMERCIAL AT */ - {0x00000041, 0x000041}, /* U+0041 LATIN CAPITAL LETTER A */ - {0x00000042, 0x000042}, /* U+0042 LATIN CAPITAL LETTER B */ - {0x00000043, 0x000043}, /* U+0043 LATIN CAPITAL LETTER C */ - {0x00000044, 0x000044}, /* U+0044 LATIN CAPITAL LETTER D */ - {0x00000045, 0x000045}, /* U+0045 LATIN CAPITAL LETTER E */ - {0x00000046, 0x000046}, /* U+0046 LATIN CAPITAL LETTER F */ - {0x00000047, 0x000047}, /* U+0047 LATIN CAPITAL LETTER G */ - {0x00000048, 0x000048}, /* U+0048 LATIN CAPITAL LETTER H */ - {0x00000049, 0x000049}, /* U+0049 LATIN CAPITAL LETTER I */ - {0x0000004a, 0x00004a}, /* U+004A LATIN CAPITAL LETTER J */ - {0x0000004b, 0x00004b}, /* U+004B LATIN CAPITAL LETTER K */ - {0x0000004c, 0x00004c}, /* U+004C LATIN CAPITAL LETTER L */ - {0x0000004d, 0x00004d}, /* U+004D LATIN CAPITAL LETTER M */ - {0x0000004e, 0x00004e}, /* U+004E LATIN CAPITAL LETTER N */ - {0x0000004f, 0x00004f}, /* U+004F LATIN CAPITAL LETTER O */ - {0x00000050, 0x000050}, /* U+0050 LATIN CAPITAL LETTER P */ - {0x00000051, 0x000051}, /* U+0051 LATIN CAPITAL LETTER Q */ - {0x00000052, 0x000052}, /* U+0052 LATIN CAPITAL LETTER R */ - {0x00000053, 0x000053}, /* U+0053 LATIN CAPITAL LETTER S */ - {0x00000054, 0x000054}, /* U+0054 LATIN CAPITAL LETTER T */ - {0x00000055, 0x000055}, /* U+0055 LATIN CAPITAL LETTER U */ - {0x00000056, 0x000056}, /* U+0056 LATIN CAPITAL LETTER V */ - {0x00000057, 0x000057}, /* U+0057 LATIN CAPITAL LETTER W */ - {0x00000058, 0x000058}, /* U+0058 LATIN CAPITAL LETTER X */ - {0x00000059, 0x000059}, /* U+0059 LATIN CAPITAL LETTER Y */ - {0x0000005a, 0x00005a}, /* U+005A LATIN CAPITAL LETTER Z */ - {0x0000005b, 0x00005b}, /* U+005B LEFT SQUARE BRACKET */ - {0x0000005c, 0x00815f}, /* U+005C REVERSE SOLIDUS Fullwidth: U+FF3C */ - {0x0000005d, 0x00005d}, /* U+005D RIGHT SQUARE BRACKET */ - {0x0000005e, 0x00005e}, /* U+005E CIRCUMFLEX ACCENT */ - {0x0000005f, 0x00005f}, /* U+005F LOW LINE */ - {0x00000060, 0x000060}, /* U+0060 GRAVE ACCENT */ - {0x00000061, 0x000061}, /* U+0061 LATIN SMALL LETTER A */ - {0x00000062, 0x000062}, /* U+0062 LATIN SMALL LETTER B */ - {0x00000063, 0x000063}, /* U+0063 LATIN SMALL LETTER C */ - {0x00000064, 0x000064}, /* U+0064 LATIN SMALL LETTER D */ - {0x00000065, 0x000065}, /* U+0065 LATIN SMALL LETTER E */ - {0x00000066, 0x000066}, /* U+0066 LATIN SMALL LETTER F */ - {0x00000067, 0x000067}, /* U+0067 LATIN SMALL LETTER G */ - {0x00000068, 0x000068}, /* U+0068 LATIN SMALL LETTER H */ - {0x00000069, 0x000069}, /* U+0069 LATIN SMALL LETTER I */ - {0x0000006a, 0x00006a}, /* U+006A LATIN SMALL LETTER J */ - {0x0000006b, 0x00006b}, /* U+006B LATIN SMALL LETTER K */ - {0x0000006c, 0x00006c}, /* U+006C LATIN SMALL LETTER L */ - {0x0000006d, 0x00006d}, /* U+006D LATIN SMALL LETTER M */ - {0x0000006e, 0x00006e}, /* U+006E LATIN SMALL LETTER N */ - {0x0000006f, 0x00006f}, /* U+006F LATIN SMALL LETTER O */ - {0x00000070, 0x000070}, /* U+0070 LATIN SMALL LETTER P */ - {0x00000071, 0x000071}, /* U+0071 LATIN SMALL LETTER Q */ - {0x00000072, 0x000072}, /* U+0072 LATIN SMALL LETTER R */ - {0x00000073, 0x000073}, /* U+0073 LATIN SMALL LETTER S */ - {0x00000074, 0x000074}, /* U+0074 LATIN SMALL LETTER T */ - {0x00000075, 0x000075}, /* U+0075 LATIN SMALL LETTER U */ - {0x00000076, 0x000076}, /* U+0076 LATIN SMALL LETTER V */ - {0x00000077, 0x000077}, /* U+0077 LATIN SMALL LETTER W */ - {0x00000078, 0x000078}, /* U+0078 LATIN SMALL LETTER X */ - {0x00000079, 0x000079}, /* U+0079 LATIN SMALL LETTER Y */ - {0x0000007a, 0x00007a}, /* U+007A LATIN SMALL LETTER Z */ - {0x0000007b, 0x00007b}, /* U+007B LEFT CURLY BRACKET */ - {0x0000007c, 0x00007c}, /* U+007C VERTICAL LINE */ - {0x0000007d, 0x00007d}, /* U+007D RIGHT CURLY BRACKET */ - {0x0000007e, 0x0081b0}, /* U+007E TILDE [2000] Fullwidth: U+FF5E */ - {0x0000007f, 0x00007f}, /* U+007F */ - {0x0000c2a0, 0x008541}, /* U+00A0 NO-BREAK SPACE [2000] */ - {0x0000c2a1, 0x008542}, /* U+00A1 INVERTED EXCLAMATION MARK [2000] */ - {0x0000c2a2, 0x008191}, /* U+00A2 CENT SIGN Windows: U+FFE0 */ - {0x0000c2a3, 0x008192}, /* U+00A3 POUND SIGN Windows: U+FFE1 */ - {0x0000c2a4, 0x008543}, /* U+00A4 CURRENCY SIGN [2000] */ - {0x0000c2a5, 0x00005c}, /* U+00A5 YEN SIGN */ - {0x0000c2a6, 0x008544}, /* U+00A6 BROKEN BAR [2000] */ - {0x0000c2a7, 0x008198}, /* U+00A7 SECTION SIGN */ - {0x0000c2a8, 0x00814e}, /* U+00A8 DIAERESIS */ - {0x0000c2a9, 0x008545}, /* U+00A9 COPYRIGHT SIGN [2000] */ - {0x0000c2aa, 0x008546}, /* U+00AA FEMININE ORDINAL INDICATOR [2000] */ - {0x0000c2ab, 0x008547}, /* U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK [2000] */ - {0x0000c2ac, 0x0081ca}, /* U+00AC NOT SIGN [1983] Windows: U+FFE2 */ - {0x0000c2ad, 0x008548}, /* U+00AD SOFT HYPHEN [2000] */ - {0x0000c2ae, 0x008549}, /* U+00AE REGISTERED SIGN [2000] */ - {0x0000c2af, 0x00854a}, /* U+00AF MACRON [2000] */ - {0x0000c2b0, 0x00818b}, /* U+00B0 DEGREE SIGN */ - {0x0000c2b1, 0x00817d}, /* U+00B1 PLUS-MINUS SIGN */ - {0x0000c2b2, 0x00854b}, /* U+00B2 SUPERSCRIPT TWO [2000] */ - {0x0000c2b3, 0x00854c}, /* U+00B3 SUPERSCRIPT THREE [2000] */ - {0x0000c2b4, 0x00814c}, /* U+00B4 ACUTE ACCENT */ - {0x0000c2b6, 0x0081f7}, /* U+00B6 PILCROW SIGN [1983] */ - {0x0000c2b7, 0x00854d}, /* U+00B7 MIDDLE DOT [2000] */ - {0x0000c2b8, 0x00854e}, /* U+00B8 CEDILLA [2000] */ - {0x0000c2b9, 0x00854f}, /* U+00B9 SUPERSCRIPT ONE [2000] */ - {0x0000c2ba, 0x008550}, /* U+00BA MASCULINE ORDINAL INDICATOR [2000] */ - {0x0000c2bb, 0x008551}, /* U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK [2000] */ - {0x0000c2bc, 0x008552}, /* U+00BC VULGAR FRACTION ONE QUARTER [2000] */ - {0x0000c2bd, 0x008553}, /* U+00BD VULGAR FRACTION ONE HALF [2000] */ - {0x0000c2be, 0x008554}, /* U+00BE VULGAR FRACTION THREE QUARTERS [2000] */ - {0x0000c2bf, 0x008555}, /* U+00BF INVERTED QUESTION MARK [2000] */ - {0x0000c380, 0x008556}, /* U+00C0 LATIN CAPITAL LETTER A WITH GRAVE [2000] */ - {0x0000c381, 0x008557}, /* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE [2000] */ - {0x0000c382, 0x008558}, /* U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX [2000] */ - {0x0000c383, 0x008559}, /* U+00C3 LATIN CAPITAL LETTER A WITH TILDE [2000] */ - {0x0000c384, 0x00855a}, /* U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS [2000] */ - {0x0000c385, 0x00855b}, /* U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE [2000] */ - {0x0000c386, 0x00855c}, /* U+00C6 LATIN CAPITAL LETTER AE [2000] */ - {0x0000c387, 0x00855d}, /* U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA [2000] */ - {0x0000c388, 0x00855e}, /* U+00C8 LATIN CAPITAL LETTER E WITH GRAVE [2000] */ - {0x0000c389, 0x00855f}, /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE [2000] */ - {0x0000c38a, 0x008560}, /* U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX [2000] */ - {0x0000c38b, 0x008561}, /* U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS [2000] */ - {0x0000c38c, 0x008562}, /* U+00CC LATIN CAPITAL LETTER I WITH GRAVE [2000] */ - {0x0000c38d, 0x008563}, /* U+00CD LATIN CAPITAL LETTER I WITH ACUTE [2000] */ - {0x0000c38e, 0x008564}, /* U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX [2000] */ - {0x0000c38f, 0x008565}, /* U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS [2000] */ - {0x0000c390, 0x008566}, /* U+00D0 LATIN CAPITAL LETTER ETH [2000] */ - {0x0000c391, 0x008567}, /* U+00D1 LATIN CAPITAL LETTER N WITH TILDE [2000] */ - {0x0000c392, 0x008568}, /* U+00D2 LATIN CAPITAL LETTER O WITH GRAVE [2000] */ - {0x0000c393, 0x008569}, /* U+00D3 LATIN CAPITAL LETTER O WITH ACUTE [2000] */ - {0x0000c394, 0x00856a}, /* U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX [2000] */ - {0x0000c395, 0x00856b}, /* U+00D5 LATIN CAPITAL LETTER O WITH TILDE [2000] */ - {0x0000c396, 0x00856c}, /* U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS [2000] */ - {0x0000c397, 0x00817e}, /* U+00D7 MULTIPLICATION SIGN */ - {0x0000c398, 0x00856d}, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE [2000] */ - {0x0000c399, 0x00856e}, /* U+00D9 LATIN CAPITAL LETTER U WITH GRAVE [2000] */ - {0x0000c39a, 0x00856f}, /* U+00DA LATIN CAPITAL LETTER U WITH ACUTE [2000] */ - {0x0000c39b, 0x008570}, /* U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX [2000] */ - {0x0000c39c, 0x008571}, /* U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS [2000] */ - {0x0000c39d, 0x008572}, /* U+00DD LATIN CAPITAL LETTER Y WITH ACUTE [2000] */ - {0x0000c39e, 0x008573}, /* U+00DE LATIN CAPITAL LETTER THORN [2000] */ - {0x0000c39f, 0x008574}, /* U+00DF LATIN SMALL LETTER SHARP S [2000] */ - {0x0000c3a0, 0x008575}, /* U+00E0 LATIN SMALL LETTER A WITH GRAVE [2000] */ - {0x0000c3a1, 0x008576}, /* U+00E1 LATIN SMALL LETTER A WITH ACUTE [2000] */ - {0x0000c3a2, 0x008577}, /* U+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX [2000] */ - {0x0000c3a3, 0x008578}, /* U+00E3 LATIN SMALL LETTER A WITH TILDE [2000] */ - {0x0000c3a4, 0x008579}, /* U+00E4 LATIN SMALL LETTER A WITH DIAERESIS [2000] */ - {0x0000c3a5, 0x00857a}, /* U+00E5 LATIN SMALL LETTER A WITH RING ABOVE [2000] */ - {0x0000c3a6, 0x00857b}, /* U+00E6 LATIN SMALL LETTER AE [2000] */ - {0x0000c3a7, 0x00857c}, /* U+00E7 LATIN SMALL LETTER C WITH CEDILLA [2000] */ - {0x0000c3a8, 0x00857d}, /* U+00E8 LATIN SMALL LETTER E WITH GRAVE [2000] */ - {0x0000c3a9, 0x00857e}, /* U+00E9 LATIN SMALL LETTER E WITH ACUTE [2000] */ - {0x0000c3aa, 0x008580}, /* U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX [2000] */ - {0x0000c3ab, 0x008581}, /* U+00EB LATIN SMALL LETTER E WITH DIAERESIS [2000] */ - {0x0000c3ac, 0x008582}, /* U+00EC LATIN SMALL LETTER I WITH GRAVE [2000] */ - {0x0000c3ad, 0x008583}, /* U+00ED LATIN SMALL LETTER I WITH ACUTE [2000] */ - {0x0000c3ae, 0x008584}, /* U+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX [2000] */ - {0x0000c3af, 0x008585}, /* U+00EF LATIN SMALL LETTER I WITH DIAERESIS [2000] */ - {0x0000c3b0, 0x008586}, /* U+00F0 LATIN SMALL LETTER ETH [2000] */ - {0x0000c3b1, 0x008587}, /* U+00F1 LATIN SMALL LETTER N WITH TILDE [2000] */ - {0x0000c3b2, 0x008588}, /* U+00F2 LATIN SMALL LETTER O WITH GRAVE [2000] */ - {0x0000c3b3, 0x008589}, /* U+00F3 LATIN SMALL LETTER O WITH ACUTE [2000] */ - {0x0000c3b4, 0x00858a}, /* U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX [2000] */ - {0x0000c3b5, 0x00858b}, /* U+00F5 LATIN SMALL LETTER O WITH TILDE [2000] */ - {0x0000c3b6, 0x00858c}, /* U+00F6 LATIN SMALL LETTER O WITH DIAERESIS [2000] */ - {0x0000c3b7, 0x008180}, /* U+00F7 DIVISION SIGN */ - {0x0000c3b8, 0x00858d}, /* U+00F8 LATIN SMALL LETTER O WITH STROKE [2000] */ - {0x0000c3b9, 0x00858e}, /* U+00F9 LATIN SMALL LETTER U WITH GRAVE [2000] */ - {0x0000c3ba, 0x00858f}, /* U+00FA LATIN SMALL LETTER U WITH ACUTE [2000] */ - {0x0000c3bb, 0x008590}, /* U+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX [2000] */ - {0x0000c3bc, 0x008591}, /* U+00FC LATIN SMALL LETTER U WITH DIAERESIS [2000] */ - {0x0000c3bd, 0x008592}, /* U+00FD LATIN SMALL LETTER Y WITH ACUTE [2000] */ - {0x0000c3be, 0x008593}, /* U+00FE LATIN SMALL LETTER THORN [2000] */ - {0x0000c3bf, 0x008594}, /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS [2000] */ - {0x0000c480, 0x008595}, /* U+0100 LATIN CAPITAL LETTER A WITH MACRON [2000] */ - {0x0000c481, 0x00859a}, /* U+0101 LATIN SMALL LETTER A WITH MACRON [2000] */ - {0x0000c482, 0x0085b8}, /* U+0102 LATIN CAPITAL LETTER A WITH BREVE [2000] */ - {0x0000c483, 0x0085c7}, /* U+0103 LATIN SMALL LETTER A WITH BREVE [2000] */ - {0x0000c484, 0x00859f}, /* U+0104 LATIN CAPITAL LETTER A WITH OGONEK [2000] */ - {0x0000c485, 0x0085aa}, /* U+0105 LATIN SMALL LETTER A WITH OGONEK [2000] */ - {0x0000c486, 0x0085ba}, /* U+0106 LATIN CAPITAL LETTER C WITH ACUTE [2000] */ - {0x0000c487, 0x0085c9}, /* U+0107 LATIN SMALL LETTER C WITH ACUTE [2000] */ - {0x0000c488, 0x0085d7}, /* U+0108 LATIN CAPITAL LETTER C WITH CIRCUMFLEX [2000] */ - {0x0000c489, 0x0085dd}, /* U+0109 LATIN SMALL LETTER C WITH CIRCUMFLEX [2000] */ - {0x0000c48c, 0x0085bb}, /* U+010C LATIN CAPITAL LETTER C WITH CARON [2000] */ - {0x0000c48d, 0x0085ca}, /* U+010D LATIN SMALL LETTER C WITH CARON [2000] */ - {0x0000c48e, 0x0085be}, /* U+010E LATIN CAPITAL LETTER D WITH CARON [2000] */ - {0x0000c48f, 0x0085cd}, /* U+010F LATIN SMALL LETTER D WITH CARON [2000] */ - {0x0000c491, 0x0085ce}, /* U+0111 LATIN SMALL LETTER D WITH STROKE [2000] */ - {0x0000c492, 0x008598}, /* U+0112 LATIN CAPITAL LETTER E WITH MACRON [2000] */ - {0x0000c493, 0x00859d}, /* U+0113 LATIN SMALL LETTER E WITH MACRON [2000] */ - {0x0000c498, 0x0085bc}, /* U+0118 LATIN CAPITAL LETTER E WITH OGONEK [2000] */ - {0x0000c499, 0x0085cb}, /* U+0119 LATIN SMALL LETTER E WITH OGONEK [2000] */ - {0x0000c49a, 0x0085bd}, /* U+011A LATIN CAPITAL LETTER E WITH CARON [2000] */ - {0x0000c49b, 0x0085cc}, /* U+011B LATIN SMALL LETTER E WITH CARON [2000] */ - {0x0000c49c, 0x0085d8}, /* U+011C LATIN CAPITAL LETTER G WITH CIRCUMFLEX [2000] */ - {0x0000c49d, 0x0085de}, /* U+011D LATIN SMALL LETTER G WITH CIRCUMFLEX [2000] */ - {0x0000c4a4, 0x0085d9}, /* U+0124 LATIN CAPITAL LETTER H WITH CIRCUMFLEX [2000] */ - {0x0000c4a5, 0x0085df}, /* U+0125 LATIN SMALL LETTER H WITH CIRCUMFLEX [2000] */ - {0x0000c4a7, 0x0085fb}, /* U+0127 LATIN SMALL LETTER H WITH STROKE [2000] */ - {0x0000c4aa, 0x008596}, /* U+012A LATIN CAPITAL LETTER I WITH MACRON [2000] */ - {0x0000c4ab, 0x00859b}, /* U+012B LATIN SMALL LETTER I WITH MACRON [2000] */ - {0x0000c4b4, 0x0085da}, /* U+0134 LATIN CAPITAL LETTER J WITH CIRCUMFLEX [2000] */ - {0x0000c4b5, 0x0085e0}, /* U+0135 LATIN SMALL LETTER J WITH CIRCUMFLEX [2000] */ - {0x0000c4b9, 0x0085b9}, /* U+0139 LATIN CAPITAL LETTER L WITH ACUTE [2000] */ - {0x0000c4ba, 0x0085c8}, /* U+013A LATIN SMALL LETTER L WITH ACUTE [2000] */ - {0x0000c4bd, 0x0085a2}, /* U+013D LATIN CAPITAL LETTER L WITH CARON [2000] */ - {0x0000c4be, 0x0085ad}, /* U+013E LATIN SMALL LETTER L WITH CARON [2000] */ - {0x0000c581, 0x0085a1}, /* U+0141 LATIN CAPITAL LETTER L WITH STROKE [2000] */ - {0x0000c582, 0x0085ac}, /* U+0142 LATIN SMALL LETTER L WITH STROKE [2000] */ - {0x0000c583, 0x0085bf}, /* U+0143 LATIN CAPITAL LETTER N WITH ACUTE [2000] */ - {0x0000c584, 0x0085cf}, /* U+0144 LATIN SMALL LETTER N WITH ACUTE [2000] */ - {0x0000c587, 0x0085c0}, /* U+0147 LATIN CAPITAL LETTER N WITH CARON [2000] */ - {0x0000c588, 0x0085d0}, /* U+0148 LATIN SMALL LETTER N WITH CARON [2000] */ - {0x0000c58b, 0x0085f8}, /* U+014B LATIN SMALL LETTER ENG [2000] */ - {0x0000c58c, 0x008599}, /* U+014C LATIN CAPITAL LETTER O WITH MACRON [2000] */ - {0x0000c58d, 0x00859e}, /* U+014D LATIN SMALL LETTER O WITH MACRON [2000] */ - {0x0000c590, 0x0085c1}, /* U+0150 LATIN CAPITAL LETTER O WITH DOUBLE ACUTE [2000] */ - {0x0000c591, 0x0085d1}, /* U+0151 LATIN SMALL LETTER O WITH DOUBLE ACUTE [2000] */ - {0x0000c592, 0x00864a}, /* U+0152 LATIN CAPITAL LIGATURE OE [2000] */ - {0x0000c593, 0x008649}, /* U+0153 LATIN SMALL LIGATURE OE [2000] */ - {0x0000c594, 0x0085b7}, /* U+0154 LATIN CAPITAL LETTER R WITH ACUTE [2000] */ - {0x0000c595, 0x0085c6}, /* U+0155 LATIN SMALL LETTER R WITH ACUTE [2000] */ - {0x0000c598, 0x0085c2}, /* U+0158 LATIN CAPITAL LETTER R WITH CARON [2000] */ - {0x0000c599, 0x0085d2}, /* U+0159 LATIN SMALL LETTER R WITH CARON [2000] */ - {0x0000c59a, 0x0085a3}, /* U+015A LATIN CAPITAL LETTER S WITH ACUTE [2000] */ - {0x0000c59b, 0x0085ae}, /* U+015B LATIN SMALL LETTER S WITH ACUTE [2000] */ - {0x0000c59c, 0x0085db}, /* U+015C LATIN CAPITAL LETTER S WITH CIRCUMFLEX [2000] */ - {0x0000c59d, 0x0085e1}, /* U+015D LATIN SMALL LETTER S WITH CIRCUMFLEX [2000] */ - {0x0000c59e, 0x0085a5}, /* U+015E LATIN CAPITAL LETTER S WITH CEDILLA [2000] */ - {0x0000c59f, 0x0085b1}, /* U+015F LATIN SMALL LETTER S WITH CEDILLA [2000] */ - {0x0000c5a0, 0x0085a4}, /* U+0160 LATIN CAPITAL LETTER S WITH CARON [2000] */ - {0x0000c5a1, 0x0085b0}, /* U+0161 LATIN SMALL LETTER S WITH CARON [2000] */ - {0x0000c5a2, 0x0085c5}, /* U+0162 LATIN CAPITAL LETTER T WITH CEDILLA [2000] */ - {0x0000c5a3, 0x0085d5}, /* U+0163 LATIN SMALL LETTER T WITH CEDILLA [2000] */ - {0x0000c5a4, 0x0085a6}, /* U+0164 LATIN CAPITAL LETTER T WITH CARON [2000] */ - {0x0000c5a5, 0x0085b2}, /* U+0165 LATIN SMALL LETTER T WITH CARON [2000] */ - {0x0000c5aa, 0x008597}, /* U+016A LATIN CAPITAL LETTER U WITH MACRON [2000] */ - {0x0000c5ab, 0x00859c}, /* U+016B LATIN SMALL LETTER U WITH MACRON [2000] */ - {0x0000c5ac, 0x0085dc}, /* U+016C LATIN CAPITAL LETTER U WITH BREVE [2000] */ - {0x0000c5ad, 0x0085e2}, /* U+016D LATIN SMALL LETTER U WITH BREVE [2000] */ - {0x0000c5ae, 0x0085c3}, /* U+016E LATIN CAPITAL LETTER U WITH RING ABOVE [2000] */ - {0x0000c5af, 0x0085d3}, /* U+016F LATIN SMALL LETTER U WITH RING ABOVE [2000] */ - {0x0000c5b0, 0x0085c4}, /* U+0170 LATIN CAPITAL LETTER U WITH DOUBLE ACUTE [2000] */ - {0x0000c5b1, 0x0085d4}, /* U+0171 LATIN SMALL LETTER U WITH DOUBLE ACUTE [2000] */ - {0x0000c5b9, 0x0085a7}, /* U+0179 LATIN CAPITAL LETTER Z WITH ACUTE [2000] */ - {0x0000c5ba, 0x0085b3}, /* U+017A LATIN SMALL LETTER Z WITH ACUTE [2000] */ - {0x0000c5bb, 0x0085a9}, /* U+017B LATIN CAPITAL LETTER Z WITH DOT ABOVE [2000] */ - {0x0000c5bc, 0x0085b6}, /* U+017C LATIN SMALL LETTER Z WITH DOT ABOVE [2000] */ - {0x0000c5bd, 0x0085a8}, /* U+017D LATIN CAPITAL LETTER Z WITH CARON [2000] */ - {0x0000c5be, 0x0085b5}, /* U+017E LATIN SMALL LETTER Z WITH CARON [2000] */ - {0x0000c693, 0x008648}, /* U+0193 LATIN CAPITAL LETTER G WITH HOOK [2000] */ - {0x0000c782, 0x008643}, /* U+01C2 LATIN LETTER ALVEOLAR CLICK [2000] */ - {0x0000c78d, 0x0084ed}, /* U+01CD LATIN CAPITAL LETTER A WITH CARON [2000] */ - {0x0000c78e, 0x0084ee}, /* U+01CE LATIN SMALL LETTER A WITH CARON [2000] */ - {0x0000c790, 0x0084ef}, /* U+01D0 LATIN SMALL LETTER I WITH CARON [2000] */ - {0x0000c791, 0x0084f4}, /* U+01D1 LATIN CAPITAL LETTER O WITH CARON [2000] */ - {0x0000c792, 0x0084f5}, /* U+01D2 LATIN SMALL LETTER O WITH CARON [2000] */ - {0x0000c794, 0x0084f6}, /* U+01D4 LATIN SMALL LETTER U WITH CARON [2000] */ - {0x0000c796, 0x0084f7}, /* U+01D6 LATIN SMALL LETTER U WITH DIAERESIS AND MACRON [2000] */ - {0x0000c798, 0x0084f8}, /* U+01D8 LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE [2000] */ - {0x0000c79a, 0x0084f9}, /* U+01DA LATIN SMALL LETTER U WITH DIAERESIS AND CARON [2000] */ - {0x0000c79c, 0x0084fa}, /* U+01DC LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE [2000] */ - {0x0000c7b8, 0x0084f2}, /* U+01F8 LATIN CAPITAL LETTER N WITH GRAVE [2000] */ - {0x0000c7b9, 0x0084f3}, /* U+01F9 LATIN SMALL LETTER N WITH GRAVE [2000] */ - {0x0000c7bd, 0x008664}, /* U+01FD LATIN SMALL LETTER AE WITH ACUTE [2000] */ - {0x0000c990, 0x008652}, /* U+0250 LATIN SMALL LETTER TURNED A [2000] */ - {0x0000c991, 0x008658}, /* U+0251 LATIN SMALL LETTER ALPHA [2000] */ - {0x0000c992, 0x008659}, /* U+0252 LATIN SMALL LETTER TURNED ALPHA [2000] */ - {0x0000c993, 0x008644}, /* U+0253 LATIN SMALL LETTER B WITH HOOK [2000] */ - {0x0000c994, 0x008657}, /* U+0254 LATIN SMALL LETTER OPEN O [2000] */ - {0x0000c995, 0x00865e}, /* U+0255 LATIN SMALL LETTER C WITH CURL [2000] */ - {0x0000c996, 0x0085ec}, /* U+0256 LATIN SMALL LETTER D WITH TAIL [2000] */ - {0x0000c997, 0x008645}, /* U+0257 LATIN SMALL LETTER D WITH HOOK [2000] */ - {0x0000c998, 0x00864d}, /* U+0258 LATIN SMALL LETTER REVERSED E [2000] */ - {0x0000c999, 0x00864f}, /* U+0259 LATIN SMALL LETTER SCHWA [2000] */ - {0x0000c99a, 0x008662}, /* U+025A LATIN SMALL LETTER SCHWA WITH HOOK [2000] */ - {0x0000c99c, 0x008650}, /* U+025C LATIN SMALL LETTER REVERSED OPEN E [2000] */ - {0x0000c99e, 0x008651}, /* U+025E LATIN SMALL LETTER CLOSED REVERSED OPEN E [2000] */ - {0x0000c99f, 0x0085f3}, /* U+025F LATIN SMALL LETTER DOTLESS J WITH STROKE [2000] */ - {0x0000c9a0, 0x008647}, /* U+0260 LATIN SMALL LETTER G WITH HOOK [2000] */ - {0x0000c9a1, 0x0085f7}, /* U+0261 LATIN SMALL LETTER SCRIPT G [2000] */ - {0x0000c9a4, 0x008655}, /* U+0264 LATIN SMALL LETTER RAMS HORN [2000] */ - {0x0000c9a5, 0x00865b}, /* U+0265 LATIN SMALL LETTER TURNED H [2000] */ - {0x0000c9a6, 0x008641}, /* U+0266 LATIN SMALL LETTER H WITH HOOK [2000] */ - {0x0000c9a7, 0x008661}, /* U+0267 LATIN SMALL LETTER HENG WITH HOOK [2000] */ - {0x0000c9a8, 0x00864b}, /* U+0268 LATIN SMALL LETTER I WITH STROKE [2000] */ - {0x0000c9ac, 0x0085e8}, /* U+026C LATIN SMALL LETTER L WITH BELT [2000] */ - {0x0000c9ad, 0x0085f2}, /* U+026D LATIN SMALL LETTER L WITH RETROFLEX HOOK [2000] */ - {0x0000c9ae, 0x0085e9}, /* U+026E LATIN SMALL LETTER LEZH [2000] */ - {0x0000c9af, 0x008653}, /* U+026F LATIN SMALL LETTER TURNED M [2000] */ - {0x0000c9b0, 0x0085f9}, /* U+0270 LATIN SMALL LETTER TURNED M WITH LONG LEG [2000] */ - {0x0000c9b1, 0x0085e3}, /* U+0271 LATIN SMALL LETTER M WITH HOOK [2000] */ - {0x0000c9b2, 0x0085f4}, /* U+0272 LATIN SMALL LETTER N WITH LEFT HOOK [2000] */ - {0x0000c9b3, 0x0085ed}, /* U+0273 LATIN SMALL LETTER N WITH RETROFLEX HOOK [2000] */ - {0x0000c9b5, 0x00864e}, /* U+0275 LATIN SMALL LETTER BARRED O [2000] */ - {0x0000c9b9, 0x0085ea}, /* U+0279 LATIN SMALL LETTER TURNED R [2000] */ - {0x0000c9ba, 0x008660}, /* U+027A LATIN SMALL LETTER TURNED R WITH LONG LEG [2000] */ - {0x0000c9bb, 0x0085f1}, /* U+027B LATIN SMALL LETTER TURNED R WITH HOOK [2000] */ - {0x0000c9bd, 0x0085ee}, /* U+027D LATIN SMALL LETTER R WITH TAIL [2000] */ - {0x0000c9be, 0x0085e5}, /* U+027E LATIN SMALL LETTER R WITH FISHHOOK [2000] */ - {0x0000ca81, 0x0085fa}, /* U+0281 LATIN LETTER SMALL CAPITAL INVERTED R [2000] */ - {0x0000ca82, 0x0085ef}, /* U+0282 LATIN SMALL LETTER S WITH HOOK [2000] */ - {0x0000ca83, 0x0085e6}, /* U+0283 LATIN SMALL LETTER ESH [2000] */ - {0x0000ca84, 0x008646}, /* U+0284 LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK [2000] */ - {0x0000ca88, 0x0085eb}, /* U+0288 LATIN SMALL LETTER T WITH RETROFLEX HOOK [2000] */ - {0x0000ca89, 0x00864c}, /* U+0289 LATIN SMALL LETTER U BAR [2000] */ - {0x0000ca8a, 0x008654}, /* U+028A LATIN SMALL LETTER UPSILON [2000] */ - {0x0000ca8b, 0x0085e4}, /* U+028B LATIN SMALL LETTER V WITH HOOK [2000] */ - {0x0000ca8c, 0x008656}, /* U+028C LATIN SMALL LETTER TURNED V [2000] */ - {0x0000ca8d, 0x00865a}, /* U+028D LATIN SMALL LETTER TURNED W [2000] */ - {0x0000ca8e, 0x0085f6}, /* U+028E LATIN SMALL LETTER TURNED Y [2000] */ - {0x0000ca90, 0x0085f0}, /* U+0290 LATIN SMALL LETTER Z WITH RETROFLEX HOOK [2000] */ - {0x0000ca91, 0x00865f}, /* U+0291 LATIN SMALL LETTER Z WITH CURL [2000] */ - {0x0000ca92, 0x0085e7}, /* U+0292 LATIN SMALL LETTER EZH [2000] */ - {0x0000ca94, 0x008640}, /* U+0294 LATIN LETTER GLOTTAL STOP [2000] */ - {0x0000ca95, 0x0085fc}, /* U+0295 LATIN LETTER PHARYNGEAL VOICED FRICATIVE [2000] */ - {0x0000ca98, 0x008642}, /* U+0298 LATIN LETTER BILABIAL CLICK [2000] */ - {0x0000ca9d, 0x0085f5}, /* U+029D LATIN SMALL LETTER J WITH CROSSED-TAIL [2000] */ - {0x0000caa1, 0x00865d}, /* U+02A1 LATIN LETTER GLOTTAL STOP WITH STROKE [2000] */ - {0x0000caa2, 0x00865c}, /* U+02A2 LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE [2000] */ - {0x0000cb87, 0x0085af}, /* U+02C7 CARON [2000] */ - {0x0000cb88, 0x008672}, /* U+02C8 MODIFIER LETTER VERTICAL LINE [2000] */ - {0x0000cb8c, 0x008673}, /* U+02CC MODIFIER LETTER LOW VERTICAL LINE [2000] */ - {0x0000cb90, 0x008674}, /* U+02D0 MODIFIER LETTER TRIANGULAR COLON [2000] */ - {0x0000cb91, 0x008675}, /* U+02D1 MODIFIER LETTER HALF TRIANGULAR COLON [2000] */ - {0x0000cb98, 0x0085a0}, /* U+02D8 BREVE [2000] */ - {0x0000cb99, 0x0085d6}, /* U+02D9 DOT ABOVE [2000] */ - {0x0000cb9b, 0x0085ab}, /* U+02DB OGONEK [2000] */ - {0x0000cb9d, 0x0085b4}, /* U+02DD DOUBLE ACUTE ACCENT [2000] */ - {0x0000cb9e, 0x008691}, /* U+02DE MODIFIER LETTER RHOTIC HOOK [2000] */ - {0x0000cba5, 0x008680}, /* U+02E5 MODIFIER LETTER EXTRA-HIGH TONE BAR [2000] */ - {0x0000cba6, 0x008681}, /* U+02E6 MODIFIER LETTER HIGH TONE BAR [2000] */ - {0x0000cba7, 0x008682}, /* U+02E7 MODIFIER LETTER MID TONE BAR [2000] */ - {0x0000cba8, 0x008683}, /* U+02E8 MODIFIER LETTER LOW TONE BAR [2000] */ - {0x0000cba9, 0x008684}, /* U+02E9 MODIFIER LETTER EXTRA-LOW TONE BAR [2000] */ - {0x0000cc80, 0x00867b}, /* U+0300 COMBINING GRAVE ACCENT [2000] */ - {0x0000cc81, 0x008679}, /* U+0301 COMBINING ACUTE ACCENT [2000] */ - {0x0000cc82, 0x00867e}, /* U+0302 COMBINING CIRCUMFLEX ACCENT [2000] */ - {0x0000cc83, 0x00869d}, /* U+0303 COMBINING TILDE [2000] */ - {0x0000cc84, 0x00867a}, /* U+0304 COMBINING MACRON [2000] */ - {0x0000cc86, 0x008676}, /* U+0306 COMBINING BREVE [2000] */ - {0x0000cc88, 0x00868d}, /* U+0308 COMBINING DIAERESIS [2000] */ - {0x0000cc8b, 0x008678}, /* U+030B COMBINING DOUBLE ACUTE ACCENT [2000] */ - {0x0000cc8c, 0x00867d}, /* U+030C COMBINING CARON [2000] */ - {0x0000cc8f, 0x00867c}, /* U+030F COMBINING DOUBLE GRAVE ACCENT [2000] */ - {0x0000cc98, 0x008698}, /* U+0318 COMBINING LEFT TACK BELOW [2000] */ - {0x0000cc99, 0x008699}, /* U+0319 COMBINING RIGHT TACK BELOW [2000] */ - {0x0000cc9a, 0x00869e}, /* U+031A COMBINING LEFT ANGLE ABOVE [2000] */ - {0x0000cc9c, 0x00868a}, /* U+031C COMBINING LEFT HALF RING BELOW [2000] */ - {0x0000cc9d, 0x008696}, /* U+031D COMBINING UP TACK BELOW [2000] */ - {0x0000cc9e, 0x008697}, /* U+031E COMBINING DOWN TACK BELOW [2000] */ - {0x0000cc9f, 0x00868b}, /* U+031F COMBINING PLUS SIGN BELOW [2000] */ - {0x0000cca0, 0x00868c}, /* U+0320 COMBINING MINUS SIGN BELOW [2000] */ - {0x0000cca4, 0x008692}, /* U+0324 COMBINING DIAERESIS BELOW [2000] */ - {0x0000cca5, 0x008687}, /* U+0325 COMBINING RING BELOW [2000] */ - {0x0000cca9, 0x00868f}, /* U+0329 COMBINING VERTICAL LINE BELOW [2000] */ - {0x0000ccaa, 0x00869a}, /* U+032A COMBINING BRIDGE BELOW [2000] */ - {0x0000ccac, 0x008688}, /* U+032C COMBINING CARON BELOW [2000] */ - {0x0000ccaf, 0x008690}, /* U+032F COMBINING INVERTED BREVE BELOW [2000] */ - {0x0000ccb0, 0x008693}, /* U+0330 COMBINING TILDE BELOW [2000] */ - {0x0000ccb4, 0x008695}, /* U+0334 COMBINING TILDE OVERLAY [2000] */ - {0x0000ccb9, 0x008689}, /* U+0339 COMBINING RIGHT HALF RING BELOW [2000] */ - {0x0000ccba, 0x00869b}, /* U+033A COMBINING INVERTED BRIDGE BELOW [2000] */ - {0x0000ccbb, 0x00869c}, /* U+033B COMBINING SQUARE BELOW [2000] */ - {0x0000ccbc, 0x008694}, /* U+033C COMBINING SEAGULL BELOW [2000] */ - {0x0000ccbd, 0x00868e}, /* U+033D COMBINING X ABOVE [2000] */ - {0x0000cda1, 0x008671}, /* U+0361 COMBINING DOUBLE INVERTED BREVE [2000] */ - {0x0000ce91, 0x00839f}, /* U+0391 GREEK CAPITAL LETTER ALPHA */ - {0x0000ce92, 0x0083a0}, /* U+0392 GREEK CAPITAL LETTER BETA */ - {0x0000ce93, 0x0083a1}, /* U+0393 GREEK CAPITAL LETTER GAMMA */ - {0x0000ce94, 0x0083a2}, /* U+0394 GREEK CAPITAL LETTER DELTA */ - {0x0000ce95, 0x0083a3}, /* U+0395 GREEK CAPITAL LETTER EPSILON */ - {0x0000ce96, 0x0083a4}, /* U+0396 GREEK CAPITAL LETTER ZETA */ - {0x0000ce97, 0x0083a5}, /* U+0397 GREEK CAPITAL LETTER ETA */ - {0x0000ce98, 0x0083a6}, /* U+0398 GREEK CAPITAL LETTER THETA */ - {0x0000ce99, 0x0083a7}, /* U+0399 GREEK CAPITAL LETTER IOTA */ - {0x0000ce9a, 0x0083a8}, /* U+039A GREEK CAPITAL LETTER KAPPA */ - {0x0000ce9b, 0x0083a9}, /* U+039B GREEK CAPITAL LETTER LAMDA */ - {0x0000ce9c, 0x0083aa}, /* U+039C GREEK CAPITAL LETTER MU */ - {0x0000ce9d, 0x0083ab}, /* U+039D GREEK CAPITAL LETTER NU */ - {0x0000ce9e, 0x0083ac}, /* U+039E GREEK CAPITAL LETTER XI */ - {0x0000ce9f, 0x0083ad}, /* U+039F GREEK CAPITAL LETTER OMICRON */ - {0x0000cea0, 0x0083ae}, /* U+03A0 GREEK CAPITAL LETTER PI */ - {0x0000cea1, 0x0083af}, /* U+03A1 GREEK CAPITAL LETTER RHO */ - {0x0000cea3, 0x0083b0}, /* U+03A3 GREEK CAPITAL LETTER SIGMA */ - {0x0000cea4, 0x0083b1}, /* U+03A4 GREEK CAPITAL LETTER TAU */ - {0x0000cea5, 0x0083b2}, /* U+03A5 GREEK CAPITAL LETTER UPSILON */ - {0x0000cea6, 0x0083b3}, /* U+03A6 GREEK CAPITAL LETTER PHI */ - {0x0000cea7, 0x0083b4}, /* U+03A7 GREEK CAPITAL LETTER CHI */ - {0x0000cea8, 0x0083b5}, /* U+03A8 GREEK CAPITAL LETTER PSI */ - {0x0000cea9, 0x0083b6}, /* U+03A9 GREEK CAPITAL LETTER OMEGA */ - {0x0000ceb1, 0x0083bf}, /* U+03B1 GREEK SMALL LETTER ALPHA */ - {0x0000ceb2, 0x0083c0}, /* U+03B2 GREEK SMALL LETTER BETA */ - {0x0000ceb3, 0x0083c1}, /* U+03B3 GREEK SMALL LETTER GAMMA */ - {0x0000ceb4, 0x0083c2}, /* U+03B4 GREEK SMALL LETTER DELTA */ - {0x0000ceb5, 0x0083c3}, /* U+03B5 GREEK SMALL LETTER EPSILON */ - {0x0000ceb6, 0x0083c4}, /* U+03B6 GREEK SMALL LETTER ZETA */ - {0x0000ceb7, 0x0083c5}, /* U+03B7 GREEK SMALL LETTER ETA */ - {0x0000ceb8, 0x0083c6}, /* U+03B8 GREEK SMALL LETTER THETA */ - {0x0000ceb9, 0x0083c7}, /* U+03B9 GREEK SMALL LETTER IOTA */ - {0x0000ceba, 0x0083c8}, /* U+03BA GREEK SMALL LETTER KAPPA */ - {0x0000cebb, 0x0083c9}, /* U+03BB GREEK SMALL LETTER LAMDA */ - {0x0000cebc, 0x0083ca}, /* U+03BC GREEK SMALL LETTER MU */ - {0x0000cebd, 0x0083cb}, /* U+03BD GREEK SMALL LETTER NU */ - {0x0000cebe, 0x0083cc}, /* U+03BE GREEK SMALL LETTER XI */ - {0x0000cebf, 0x0083cd}, /* U+03BF GREEK SMALL LETTER OMICRON */ - {0x0000cf80, 0x0083ce}, /* U+03C0 GREEK SMALL LETTER PI */ - {0x0000cf81, 0x0083cf}, /* U+03C1 GREEK SMALL LETTER RHO */ - {0x0000cf82, 0x0083d7}, /* U+03C2 GREEK SMALL LETTER FINAL SIGMA [2000] */ - {0x0000cf83, 0x0083d0}, /* U+03C3 GREEK SMALL LETTER SIGMA */ - {0x0000cf84, 0x0083d1}, /* U+03C4 GREEK SMALL LETTER TAU */ - {0x0000cf85, 0x0083d2}, /* U+03C5 GREEK SMALL LETTER UPSILON */ - {0x0000cf86, 0x0083d3}, /* U+03C6 GREEK SMALL LETTER PHI */ - {0x0000cf87, 0x0083d4}, /* U+03C7 GREEK SMALL LETTER CHI */ - {0x0000cf88, 0x0083d5}, /* U+03C8 GREEK SMALL LETTER PSI */ - {0x0000cf89, 0x0083d6}, /* U+03C9 GREEK SMALL LETTER OMEGA */ - {0x0000d081, 0x008446}, /* U+0401 CYRILLIC CAPITAL LETTER IO */ - {0x0000d090, 0x008440}, /* U+0410 CYRILLIC CAPITAL LETTER A */ - {0x0000d091, 0x008441}, /* U+0411 CYRILLIC CAPITAL LETTER BE */ - {0x0000d092, 0x008442}, /* U+0412 CYRILLIC CAPITAL LETTER VE */ - {0x0000d093, 0x008443}, /* U+0413 CYRILLIC CAPITAL LETTER GHE */ - {0x0000d094, 0x008444}, /* U+0414 CYRILLIC CAPITAL LETTER DE */ - {0x0000d095, 0x008445}, /* U+0415 CYRILLIC CAPITAL LETTER IE */ - {0x0000d096, 0x008447}, /* U+0416 CYRILLIC CAPITAL LETTER ZHE */ - {0x0000d097, 0x008448}, /* U+0417 CYRILLIC CAPITAL LETTER ZE */ - {0x0000d098, 0x008449}, /* U+0418 CYRILLIC CAPITAL LETTER I */ - {0x0000d099, 0x00844a}, /* U+0419 CYRILLIC CAPITAL LETTER SHORT I */ - {0x0000d09a, 0x00844b}, /* U+041A CYRILLIC CAPITAL LETTER KA */ - {0x0000d09b, 0x00844c}, /* U+041B CYRILLIC CAPITAL LETTER EL */ - {0x0000d09c, 0x00844d}, /* U+041C CYRILLIC CAPITAL LETTER EM */ - {0x0000d09d, 0x00844e}, /* U+041D CYRILLIC CAPITAL LETTER EN */ - {0x0000d09e, 0x00844f}, /* U+041E CYRILLIC CAPITAL LETTER O */ - {0x0000d09f, 0x008450}, /* U+041F CYRILLIC CAPITAL LETTER PE */ - {0x0000d0a0, 0x008451}, /* U+0420 CYRILLIC CAPITAL LETTER ER */ - {0x0000d0a1, 0x008452}, /* U+0421 CYRILLIC CAPITAL LETTER ES */ - {0x0000d0a2, 0x008453}, /* U+0422 CYRILLIC CAPITAL LETTER TE */ - {0x0000d0a3, 0x008454}, /* U+0423 CYRILLIC CAPITAL LETTER U */ - {0x0000d0a4, 0x008455}, /* U+0424 CYRILLIC CAPITAL LETTER EF */ - {0x0000d0a5, 0x008456}, /* U+0425 CYRILLIC CAPITAL LETTER HA */ - {0x0000d0a6, 0x008457}, /* U+0426 CYRILLIC CAPITAL LETTER TSE */ - {0x0000d0a7, 0x008458}, /* U+0427 CYRILLIC CAPITAL LETTER CHE */ - {0x0000d0a8, 0x008459}, /* U+0428 CYRILLIC CAPITAL LETTER SHA */ - {0x0000d0a9, 0x00845a}, /* U+0429 CYRILLIC CAPITAL LETTER SHCHA */ - {0x0000d0aa, 0x00845b}, /* U+042A CYRILLIC CAPITAL LETTER HARD SIGN */ - {0x0000d0ab, 0x00845c}, /* U+042B CYRILLIC CAPITAL LETTER YERU */ - {0x0000d0ac, 0x00845d}, /* U+042C CYRILLIC CAPITAL LETTER SOFT SIGN */ - {0x0000d0ad, 0x00845e}, /* U+042D CYRILLIC CAPITAL LETTER E */ - {0x0000d0ae, 0x00845f}, /* U+042E CYRILLIC CAPITAL LETTER YU */ - {0x0000d0af, 0x008460}, /* U+042F CYRILLIC CAPITAL LETTER YA */ - {0x0000d0b0, 0x008470}, /* U+0430 CYRILLIC SMALL LETTER A */ - {0x0000d0b1, 0x008471}, /* U+0431 CYRILLIC SMALL LETTER BE */ - {0x0000d0b2, 0x008472}, /* U+0432 CYRILLIC SMALL LETTER VE */ - {0x0000d0b3, 0x008473}, /* U+0433 CYRILLIC SMALL LETTER GHE */ - {0x0000d0b4, 0x008474}, /* U+0434 CYRILLIC SMALL LETTER DE */ - {0x0000d0b5, 0x008475}, /* U+0435 CYRILLIC SMALL LETTER IE */ - {0x0000d0b6, 0x008477}, /* U+0436 CYRILLIC SMALL LETTER ZHE */ - {0x0000d0b7, 0x008478}, /* U+0437 CYRILLIC SMALL LETTER ZE */ - {0x0000d0b8, 0x008479}, /* U+0438 CYRILLIC SMALL LETTER I */ - {0x0000d0b9, 0x00847a}, /* U+0439 CYRILLIC SMALL LETTER SHORT I */ - {0x0000d0ba, 0x00847b}, /* U+043A CYRILLIC SMALL LETTER KA */ - {0x0000d0bb, 0x00847c}, /* U+043B CYRILLIC SMALL LETTER EL */ - {0x0000d0bc, 0x00847d}, /* U+043C CYRILLIC SMALL LETTER EM */ - {0x0000d0bd, 0x00847e}, /* U+043D CYRILLIC SMALL LETTER EN */ - {0x0000d0be, 0x008480}, /* U+043E CYRILLIC SMALL LETTER O */ - {0x0000d0bf, 0x008481}, /* U+043F CYRILLIC SMALL LETTER PE */ - {0x0000d180, 0x008482}, /* U+0440 CYRILLIC SMALL LETTER ER */ - {0x0000d181, 0x008483}, /* U+0441 CYRILLIC SMALL LETTER ES */ - {0x0000d182, 0x008484}, /* U+0442 CYRILLIC SMALL LETTER TE */ - {0x0000d183, 0x008485}, /* U+0443 CYRILLIC SMALL LETTER U */ - {0x0000d184, 0x008486}, /* U+0444 CYRILLIC SMALL LETTER EF */ - {0x0000d185, 0x008487}, /* U+0445 CYRILLIC SMALL LETTER HA */ - {0x0000d186, 0x008488}, /* U+0446 CYRILLIC SMALL LETTER TSE */ - {0x0000d187, 0x008489}, /* U+0447 CYRILLIC SMALL LETTER CHE */ - {0x0000d188, 0x00848a}, /* U+0448 CYRILLIC SMALL LETTER SHA */ - {0x0000d189, 0x00848b}, /* U+0449 CYRILLIC SMALL LETTER SHCHA */ - {0x0000d18a, 0x00848c}, /* U+044A CYRILLIC SMALL LETTER HARD SIGN */ - {0x0000d18b, 0x00848d}, /* U+044B CYRILLIC SMALL LETTER YERU */ - {0x0000d18c, 0x00848e}, /* U+044C CYRILLIC SMALL LETTER SOFT SIGN */ - {0x0000d18d, 0x00848f}, /* U+044D CYRILLIC SMALL LETTER E */ - {0x0000d18e, 0x008490}, /* U+044E CYRILLIC SMALL LETTER YU */ - {0x0000d18f, 0x008491}, /* U+044F CYRILLIC SMALL LETTER YA */ - {0x0000d191, 0x008476}, /* U+0451 CYRILLIC SMALL LETTER IO */ - {0x00e1b8be, 0x0084f0}, /* U+1E3E LATIN CAPITAL LETTER M WITH ACUTE [2000] */ - {0x00e1b8bf, 0x0084f1}, /* U+1E3F LATIN SMALL LETTER M WITH ACUTE [2000] */ - {0x00e1bdb0, 0x008665}, /* U+1F70 GREEK SMALL LETTER ALPHA WITH VARIA [2000] */ - {0x00e1bdb1, 0x008666}, /* U+1F71 GREEK SMALL LETTER ALPHA WITH OXIA [2000] */ - {0x00e1bdb2, 0x00866f}, /* U+1F72 GREEK SMALL LETTER EPSILON WITH VARIA [2000] */ - {0x00e1bdb3, 0x008670}, /* U+1F73 GREEK SMALL LETTER EPSILON WITH OXIA [2000] */ - {0x00e28090, 0x00815d}, /* U+2010 HYPHEN */ - {0x00e28093, 0x00829c}, /* U+2013 EN DASH [2000] */ - {0x00e28094, 0x00815c}, /* U+2014 EM DASH Windows: U+2015 */ - {0x00e28096, 0x008161}, /* U+2016 DOUBLE VERTICAL LINE Windows: U+2225 */ - {0x00e28098, 0x008165}, /* U+2018 LEFT SINGLE QUOTATION MARK */ - {0x00e28099, 0x008166}, /* U+2019 RIGHT SINGLE QUOTATION MARK */ - {0x00e2809c, 0x008167}, /* U+201C LEFT DOUBLE QUOTATION MARK */ - {0x00e2809d, 0x008168}, /* U+201D RIGHT DOUBLE QUOTATION MARK */ - {0x00e280a0, 0x0081f5}, /* U+2020 DAGGER [1983] */ - {0x00e280a1, 0x0081f6}, /* U+2021 DOUBLE DAGGER [1983] */ - {0x00e280a2, 0x00825f}, /* U+2022 BULLET [2000] */ - {0x00e280a5, 0x008164}, /* U+2025 TWO DOT LEADER */ - {0x00e280a6, 0x008163}, /* U+2026 HORIZONTAL ELLIPSIS */ - {0x00e280b0, 0x0081f1}, /* U+2030 PER MILLE SIGN [1983] */ - {0x00e280b2, 0x00818c}, /* U+2032 PRIME */ - {0x00e280b3, 0x00818d}, /* U+2033 DOUBLE PRIME */ - {0x00e280bb, 0x0081a6}, /* U+203B REFERENCE MARK */ - {0x00e280bc, 0x0084e9}, /* U+203C DOUBLE EXCLAMATION MARK [2000] */ - {0x00e280be, 0x00007e}, /* U+203E OVERLINE */ - {0x00e280bf, 0x008677}, /* U+203F UNDERTIE [2000] */ - {0x00e28182, 0x0086fc}, /* U+2042 ASTERISM [2000] */ - {0x00e28187, 0x0084ea}, /* U+2047 DOUBLE QUESTION MARK [2000] [Unicode3.2] */ - {0x00e28188, 0x0084eb}, /* U+2048 QUESTION EXCLAMATION MARK [2000] */ - {0x00e28189, 0x0084ec}, /* U+2049 EXCLAMATION QUESTION MARK [2000] */ - {0x00e28191, 0x0086fb}, /* U+2051 TWO ASTERISKS ALIGNED VERTICALLY [2000] [Unicode3.2] */ - {0x00e282ac, 0x008540}, /* U+20AC EURO SIGN [2000] */ - {0x00e28483, 0x00818e}, /* U+2103 DEGREE CELSIUS */ - {0x00e2848f, 0x00827c}, /* U+210F PLANCK CONSTANT OVER TWO PI [2000] */ - {0x00e28493, 0x00827e}, /* U+2113 SCRIPT SMALL L [2000] */ - {0x00e28496, 0x008782}, /* U+2116 NUMERO SIGN [2000] */ - {0x00e284a1, 0x008784}, /* U+2121 TELEPHONE SIGN [2000] */ - {0x00e284a7, 0x008280}, /* U+2127 INVERTED OHM SIGN [2000] */ - {0x00e284ab, 0x0081f0}, /* U+212B ANGSTROM SIGN [1983] */ - {0x00e284b5, 0x00827b}, /* U+2135 ALEF SYMBOL [2000] */ - {0x00e28593, 0x008498}, /* U+2153 VULGAR FRACTION ONE THIRD [2000] */ - {0x00e28594, 0x008499}, /* U+2154 VULGAR FRACTION TWO THIRDS [2000] */ - {0x00e28595, 0x00849a}, /* U+2155 VULGAR FRACTION ONE FIFTH [2000] */ - {0x00e285a0, 0x008754}, /* U+2160 ROMAN NUMERAL ONE [2000] */ - {0x00e285a1, 0x008755}, /* U+2161 ROMAN NUMERAL TWO [2000] */ - {0x00e285a2, 0x008756}, /* U+2162 ROMAN NUMERAL THREE [2000] */ - {0x00e285a3, 0x008757}, /* U+2163 ROMAN NUMERAL FOUR [2000] */ - {0x00e285a4, 0x008758}, /* U+2164 ROMAN NUMERAL FIVE [2000] */ - {0x00e285a5, 0x008759}, /* U+2165 ROMAN NUMERAL SIX [2000] */ - {0x00e285a6, 0x00875a}, /* U+2166 ROMAN NUMERAL SEVEN [2000] */ - {0x00e285a7, 0x00875b}, /* U+2167 ROMAN NUMERAL EIGHT [2000] */ - {0x00e285a8, 0x00875c}, /* U+2168 ROMAN NUMERAL NINE [2000] */ - {0x00e285a9, 0x00875d}, /* U+2169 ROMAN NUMERAL TEN [2000] */ - {0x00e285aa, 0x00875e}, /* U+216A ROMAN NUMERAL ELEVEN [2000] */ - {0x00e285ab, 0x008776}, /* U+216B ROMAN NUMERAL TWELVE [2000] */ - {0x00e285b0, 0x0086b3}, /* U+2170 SMALL ROMAN NUMERAL ONE [2000] */ - {0x00e285b1, 0x0086b4}, /* U+2171 SMALL ROMAN NUMERAL TWO [2000] */ - {0x00e285b2, 0x0086b5}, /* U+2172 SMALL ROMAN NUMERAL THREE [2000] */ - {0x00e285b3, 0x0086b6}, /* U+2173 SMALL ROMAN NUMERAL FOUR [2000] */ - {0x00e285b4, 0x0086b7}, /* U+2174 SMALL ROMAN NUMERAL FIVE [2000] */ - {0x00e285b5, 0x0086b8}, /* U+2175 SMALL ROMAN NUMERAL SIX [2000] */ - {0x00e285b6, 0x0086b9}, /* U+2176 SMALL ROMAN NUMERAL SEVEN [2000] */ - {0x00e285b7, 0x0086ba}, /* U+2177 SMALL ROMAN NUMERAL EIGHT [2000] */ - {0x00e285b8, 0x0086bb}, /* U+2178 SMALL ROMAN NUMERAL NINE [2000] */ - {0x00e285b9, 0x0086bc}, /* U+2179 SMALL ROMAN NUMERAL TEN [2000] */ - {0x00e285ba, 0x0086bd}, /* U+217A SMALL ROMAN NUMERAL ELEVEN [2000] */ - {0x00e285bb, 0x0086be}, /* U+217B SMALL ROMAN NUMERAL TWELVE [2000] */ - {0x00e28690, 0x0081a9}, /* U+2190 LEFTWARDS ARROW */ - {0x00e28691, 0x0081aa}, /* U+2191 UPWARDS ARROW */ - {0x00e28692, 0x0081a8}, /* U+2192 RIGHTWARDS ARROW */ - {0x00e28693, 0x0081ab}, /* U+2193 DOWNWARDS ARROW */ - {0x00e28694, 0x0081ef}, /* U+2194 LEFT RIGHT ARROW [2000] */ - {0x00e28696, 0x008246}, /* U+2196 NORTH WEST ARROW [2000] */ - {0x00e28697, 0x008244}, /* U+2197 NORTH EAST ARROW [2000] */ - {0x00e28698, 0x008245}, /* U+2198 SOUTH EAST ARROW [2000] */ - {0x00e28699, 0x008247}, /* U+2199 SOUTH WEST ARROW [2000] */ - {0x00e28784, 0x008248}, /* U+21C4 RIGHTWARDS ARROW OVER LEFTWARDS ARROW [2000] */ - {0x00e28792, 0x0081cb}, /* U+21D2 RIGHTWARDS DOUBLE ARROW [1983] */ - {0x00e28794, 0x0081cc}, /* U+21D4 LEFT RIGHT DOUBLE ARROW [1983] */ - {0x00e287a6, 0x00824a}, /* U+21E6 LEFTWARDS WHITE ARROW [2000] */ - {0x00e287a7, 0x00824b}, /* U+21E7 UPWARDS WHITE ARROW [2000] */ - {0x00e287a8, 0x008249}, /* U+21E8 RIGHTWARDS WHITE ARROW [2000] */ - {0x00e287a9, 0x00824c}, /* U+21E9 DOWNWARDS WHITE ARROW [2000] */ - {0x00e28880, 0x0081cd}, /* U+2200 FOR ALL [1983] */ - {0x00e28882, 0x0081dd}, /* U+2202 PARTIAL DIFFERENTIAL [1983] */ - {0x00e28883, 0x0081ce}, /* U+2203 THERE EXISTS [1983] */ - {0x00e28885, 0x0081c5}, /* U+2205 EMPTY SET [2000] */ - {0x00e28887, 0x0081de}, /* U+2207 NABLA [1983] */ - {0x00e28888, 0x0081b8}, /* U+2208 ELEMENT OF [1983] */ - {0x00e28889, 0x0081c4}, /* U+2209 NOT AN ELEMENT OF [2000] */ - {0x00e2888b, 0x0081b9}, /* U+220B CONTAINS AS MEMBER [1983] */ - {0x00e28892, 0x00817c}, /* U+2212 MINUS SIGN Windows: U+FF0D */ - {0x00e28893, 0x00827a}, /* U+2213 MINUS-OR-PLUS SIGN [2000] */ - {0x00e2889a, 0x0081e3}, /* U+221A SQUARE ROOT [1983] */ - {0x00e2889d, 0x0081e5}, /* U+221D PROPORTIONAL TO [1983] */ - {0x00e2889e, 0x008187}, /* U+221E INFINITY */ - {0x00e2889f, 0x008798}, /* U+221F RIGHT ANGLE [2000] */ - {0x00e288a0, 0x0081da}, /* U+2220 ANGLE [1983] */ - {0x00e288a5, 0x0081d2}, /* U+2225 PARALLEL TO [2000] */ - {0x00e288a6, 0x0081d3}, /* U+2226 NOT PARALLEL TO [2000] */ - {0x00e288a7, 0x0081c8}, /* U+2227 LOGICAL AND [1983] */ - {0x00e288a8, 0x0081c9}, /* U+2228 LOGICAL OR [1983] */ - {0x00e288a9, 0x0081bf}, /* U+2229 INTERSECTION [1983] */ - {0x00e288aa, 0x0081be}, /* U+222A UNION [1983] */ - {0x00e288ab, 0x0081e7}, /* U+222B INTEGRAL [1983] */ - {0x00e288ac, 0x0081e8}, /* U+222C DOUBLE INTEGRAL [1983] */ - {0x00e288ae, 0x008793}, /* U+222E CONTOUR INTEGRAL [2000] */ - {0x00e288b4, 0x008188}, /* U+2234 THEREFORE */ - {0x00e288b5, 0x0081e6}, /* U+2235 BECAUSE [1983] */ - {0x00e288bd, 0x0081e4}, /* U+223D REVERSED TILDE [1983] */ - {0x00e28983, 0x0081ea}, /* U+2243 ASYMPTOTICALLY EQUAL TO [2000] */ - {0x00e28985, 0x0081eb}, /* U+2245 APPROXIMATELY EQUAL TO [2000] */ - {0x00e28988, 0x0081ec}, /* U+2248 ALMOST EQUAL TO [2000] */ - {0x00e28992, 0x0081e0}, /* U+2252 APPROXIMATELY EQUAL TO OR THE IMAGE OF [1983] */ - {0x00e289a0, 0x008182}, /* U+2260 NOT EQUAL TO */ - {0x00e289a1, 0x0081df}, /* U+2261 IDENTICAL TO [1983] */ - {0x00e289a2, 0x0081e9}, /* U+2262 NOT IDENTICAL TO [2000] */ - {0x00e289a6, 0x008185}, /* U+2266 LESS-THAN OVER EQUAL TO */ - {0x00e289a7, 0x008186}, /* U+2267 GREATER-THAN OVER EQUAL TO */ - {0x00e289aa, 0x0081e1}, /* U+226A MUCH LESS-THAN [1983] */ - {0x00e289ab, 0x0081e2}, /* U+226B MUCH GREATER-THAN [1983] */ - {0x00e289b6, 0x0081ed}, /* U+2276 LESS-THAN OR GREATER-THAN [2000] */ - {0x00e289b7, 0x0081ee}, /* U+2277 GREATER-THAN OR LESS-THAN [2000] */ - {0x00e28a82, 0x0081bc}, /* U+2282 SUBSET OF [1983] */ - {0x00e28a83, 0x0081bd}, /* U+2283 SUPERSET OF [1983] */ - {0x00e28a84, 0x0081c0}, /* U+2284 NOT A SUBSET OF [2000] */ - {0x00e28a85, 0x0081c1}, /* U+2285 NOT A SUPERSET OF [2000] */ - {0x00e28a86, 0x0081ba}, /* U+2286 SUBSET OF OR EQUAL TO [1983] */ - {0x00e28a87, 0x0081bb}, /* U+2287 SUPERSET OF OR EQUAL TO [1983] */ - {0x00e28a8a, 0x0081c2}, /* U+228A SUBSET OF WITH NOT EQUAL TO [2000] */ - {0x00e28a8b, 0x0081c3}, /* U+228B SUPERSET OF WITH NOT EQUAL TO [2000] */ - {0x00e28a95, 0x0081cf}, /* U+2295 CIRCLED PLUS [2000] */ - {0x00e28a96, 0x0081d0}, /* U+2296 CIRCLED MINUS [2000] */ - {0x00e28a97, 0x0081d1}, /* U+2297 CIRCLED TIMES [2000] */ - {0x00e28aa5, 0x0081db}, /* U+22A5 UP TACK [1983] */ - {0x00e28abf, 0x008799}, /* U+22BF RIGHT TRIANGLE [2000] */ - {0x00e28b9a, 0x008496}, /* U+22DA LESS-THAN EQUAL TO OR GREATER-THAN [2000] */ - {0x00e28b9b, 0x008497}, /* U+22DB GREATER-THAN EQUAL TO OR LESS-THAN [2000] */ - {0x00e28c85, 0x0081c6}, /* U+2305 PROJECTIVE [2000] */ - {0x00e28c86, 0x0081c7}, /* U+2306 PERSPECTIVE [2000] */ - {0x00e28c92, 0x0081dc}, /* U+2312 ARC [1983] */ - {0x00e28c98, 0x00849c}, /* U+2318 PLACE OF INTEREST SIGN [2000] */ - {0x00e28ebe, 0x008461}, /* U+23BE DENTISTRY SYMBOL LIGHT VERTICAL AND TOP RIGHT [2000] [Unicode3.2] */ - {0x00e28ebf, 0x008462}, /* U+23BF DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM RIGHT [2000] [Unicode3.2] */ - {0x00e28f80, 0x008463}, /* U+23C0 DENTISTRY SYMBOL LIGHT VERTICAL WITH CIRCLE [2000] [Unicode3.2] */ - {0x00e28f81, 0x008464}, /* U+23C1 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH CIRCLE [2000] [Unicode3.2] */ - {0x00e28f82, 0x008465}, /* U+23C2 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLE [2000] [Unicode3.2] */ - {0x00e28f83, 0x008466}, /* U+23C3 DENTISTRY SYMBOL LIGHT VERTICAL WITH TRIANGLE [2000] [Unicode3.2] */ - {0x00e28f84, 0x008467}, /* U+23C4 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH TRIANGLE [2000] [Unicode3.2] */ - {0x00e28f85, 0x008468}, /* U+23C5 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH TRIANGLE [2000] [Unicode3.2] */ - {0x00e28f86, 0x008469}, /* U+23C6 DENTISTRY SYMBOL LIGHT VERTICAL AND WAVE [2000] [Unicode3.2] */ - {0x00e28f87, 0x00846a}, /* U+23C7 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH WAVE [2000] [Unicode3.2] */ - {0x00e28f88, 0x00846b}, /* U+23C8 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH WAVE [2000] [Unicode3.2] */ - {0x00e28f89, 0x00846c}, /* U+23C9 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL [2000] [Unicode3.2] */ - {0x00e28f8a, 0x00846d}, /* U+23CA DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL [2000] [Unicode3.2] */ - {0x00e28f8b, 0x00846e}, /* U+23CB DENTISTRY SYMBOL LIGHT VERTICAL AND TOP LEFT [2000] [Unicode3.2] */ - {0x00e28f8c, 0x00846f}, /* U+23CC DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM LEFT [2000] [Unicode3.2] */ - {0x00e28f8e, 0x00849e}, /* U+23CE RETURN SYMBOL [2000] [Unicode3.2] */ - {0x00e290a3, 0x00849d}, /* U+2423 OPEN BOX [2000] */ - {0x00e291a0, 0x008740}, /* U+2460 CIRCLED DIGIT ONE [2000] */ - {0x00e291a1, 0x008741}, /* U+2461 CIRCLED DIGIT TWO [2000] */ - {0x00e291a2, 0x008742}, /* U+2462 CIRCLED DIGIT THREE [2000] */ - {0x00e291a3, 0x008743}, /* U+2463 CIRCLED DIGIT FOUR [2000] */ - {0x00e291a4, 0x008744}, /* U+2464 CIRCLED DIGIT FIVE [2000] */ - {0x00e291a5, 0x008745}, /* U+2465 CIRCLED DIGIT SIX [2000] */ - {0x00e291a6, 0x008746}, /* U+2466 CIRCLED DIGIT SEVEN [2000] */ - {0x00e291a7, 0x008747}, /* U+2467 CIRCLED DIGIT EIGHT [2000] */ - {0x00e291a8, 0x008748}, /* U+2468 CIRCLED DIGIT NINE [2000] */ - {0x00e291a9, 0x008749}, /* U+2469 CIRCLED NUMBER TEN [2000] */ - {0x00e291aa, 0x00874a}, /* U+246A CIRCLED NUMBER ELEVEN [2000] */ - {0x00e291ab, 0x00874b}, /* U+246B CIRCLED NUMBER TWELVE [2000] */ - {0x00e291ac, 0x00874c}, /* U+246C CIRCLED NUMBER THIRTEEN [2000] */ - {0x00e291ad, 0x00874d}, /* U+246D CIRCLED NUMBER FOURTEEN [2000] */ - {0x00e291ae, 0x00874e}, /* U+246E CIRCLED NUMBER FIFTEEN [2000] */ - {0x00e291af, 0x00874f}, /* U+246F CIRCLED NUMBER SIXTEEN [2000] */ - {0x00e291b0, 0x008750}, /* U+2470 CIRCLED NUMBER SEVENTEEN [2000] */ - {0x00e291b1, 0x008751}, /* U+2471 CIRCLED NUMBER EIGHTEEN [2000] */ - {0x00e291b2, 0x008752}, /* U+2472 CIRCLED NUMBER NINETEEN [2000] */ - {0x00e291b3, 0x008753}, /* U+2473 CIRCLED NUMBER TWENTY [2000] */ - {0x00e29390, 0x0086bf}, /* U+24D0 CIRCLED LATIN SMALL LETTER A [2000] */ - {0x00e29391, 0x0086c0}, /* U+24D1 CIRCLED LATIN SMALL LETTER B [2000] */ - {0x00e29392, 0x0086c1}, /* U+24D2 CIRCLED LATIN SMALL LETTER C [2000] */ - {0x00e29393, 0x0086c2}, /* U+24D3 CIRCLED LATIN SMALL LETTER D [2000] */ - {0x00e29394, 0x0086c3}, /* U+24D4 CIRCLED LATIN SMALL LETTER E [2000] */ - {0x00e29395, 0x0086c4}, /* U+24D5 CIRCLED LATIN SMALL LETTER F [2000] */ - {0x00e29396, 0x0086c5}, /* U+24D6 CIRCLED LATIN SMALL LETTER G [2000] */ - {0x00e29397, 0x0086c6}, /* U+24D7 CIRCLED LATIN SMALL LETTER H [2000] */ - {0x00e29398, 0x0086c7}, /* U+24D8 CIRCLED LATIN SMALL LETTER I [2000] */ - {0x00e29399, 0x0086c8}, /* U+24D9 CIRCLED LATIN SMALL LETTER J [2000] */ - {0x00e2939a, 0x0086c9}, /* U+24DA CIRCLED LATIN SMALL LETTER K [2000] */ - {0x00e2939b, 0x0086ca}, /* U+24DB CIRCLED LATIN SMALL LETTER L [2000] */ - {0x00e2939c, 0x0086cb}, /* U+24DC CIRCLED LATIN SMALL LETTER M [2000] */ - {0x00e2939d, 0x0086cc}, /* U+24DD CIRCLED LATIN SMALL LETTER N [2000] */ - {0x00e2939e, 0x0086cd}, /* U+24DE CIRCLED LATIN SMALL LETTER O [2000] */ - {0x00e2939f, 0x0086ce}, /* U+24DF CIRCLED LATIN SMALL LETTER P [2000] */ - {0x00e293a0, 0x0086cf}, /* U+24E0 CIRCLED LATIN SMALL LETTER Q [2000] */ - {0x00e293a1, 0x0086d0}, /* U+24E1 CIRCLED LATIN SMALL LETTER R [2000] */ - {0x00e293a2, 0x0086d1}, /* U+24E2 CIRCLED LATIN SMALL LETTER S [2000] */ - {0x00e293a3, 0x0086d2}, /* U+24E3 CIRCLED LATIN SMALL LETTER T [2000] */ - {0x00e293a4, 0x0086d3}, /* U+24E4 CIRCLED LATIN SMALL LETTER U [2000] */ - {0x00e293a5, 0x0086d4}, /* U+24E5 CIRCLED LATIN SMALL LETTER V [2000] */ - {0x00e293a6, 0x0086d5}, /* U+24E6 CIRCLED LATIN SMALL LETTER W [2000] */ - {0x00e293a7, 0x0086d6}, /* U+24E7 CIRCLED LATIN SMALL LETTER X [2000] */ - {0x00e293a8, 0x0086d7}, /* U+24E8 CIRCLED LATIN SMALL LETTER Y [2000] */ - {0x00e293a9, 0x0086d8}, /* U+24E9 CIRCLED LATIN SMALL LETTER Z [2000] */ - {0x00e293ab, 0x0086a9}, /* U+24EB NEGATIVE CIRCLED NUMBER ELEVEN [2000] [Unicode3.2] */ - {0x00e293ac, 0x0086aa}, /* U+24EC NEGATIVE CIRCLED NUMBER TWELVE [2000] [Unicode3.2] */ - {0x00e293ad, 0x0086ab}, /* U+24ED NEGATIVE CIRCLED NUMBER THIRTEEN [2000] [Unicode3.2] */ - {0x00e293ae, 0x0086ac}, /* U+24EE NEGATIVE CIRCLED NUMBER FOURTEEN [2000] [Unicode3.2] */ - {0x00e293af, 0x0086ad}, /* U+24EF NEGATIVE CIRCLED NUMBER FIFTEEN [2000] [Unicode3.2] */ - {0x00e293b0, 0x0086ae}, /* U+24F0 NEGATIVE CIRCLED NUMBER SIXTEEN [2000] [Unicode3.2] */ - {0x00e293b1, 0x0086af}, /* U+24F1 NEGATIVE CIRCLED NUMBER SEVENTEEN [2000] [Unicode3.2] */ - {0x00e293b2, 0x0086b0}, /* U+24F2 NEGATIVE CIRCLED NUMBER EIGHTEEN [2000] [Unicode3.2] */ - {0x00e293b3, 0x0086b1}, /* U+24F3 NEGATIVE CIRCLED NUMBER NINETEEN [2000] [Unicode3.2] */ - {0x00e293b4, 0x0086b2}, /* U+24F4 NEGATIVE CIRCLED NUMBER TWENTY [2000] [Unicode3.2] */ - {0x00e293b5, 0x0083d8}, /* U+24F5 DOUBLE CIRCLED DIGIT ONE [2000] [Unicode3.2] */ - {0x00e293b6, 0x0083d9}, /* U+24F6 DOUBLE CIRCLED DIGIT TWO [2000] [Unicode3.2] */ - {0x00e293b7, 0x0083da}, /* U+24F7 DOUBLE CIRCLED DIGIT THREE [2000] [Unicode3.2] */ - {0x00e293b8, 0x0083db}, /* U+24F8 DOUBLE CIRCLED DIGIT FOUR [2000] [Unicode3.2] */ - {0x00e293b9, 0x0083dc}, /* U+24F9 DOUBLE CIRCLED DIGIT FIVE [2000] [Unicode3.2] */ - {0x00e293ba, 0x0083dd}, /* U+24FA DOUBLE CIRCLED DIGIT SIX [2000] [Unicode3.2] */ - {0x00e293bb, 0x0083de}, /* U+24FB DOUBLE CIRCLED DIGIT SEVEN [2000] [Unicode3.2] */ - {0x00e293bc, 0x0083df}, /* U+24FC DOUBLE CIRCLED DIGIT EIGHT [2000] [Unicode3.2] */ - {0x00e293bd, 0x0083e0}, /* U+24FD DOUBLE CIRCLED DIGIT NINE [2000] [Unicode3.2] */ - {0x00e293be, 0x0083e1}, /* U+24FE DOUBLE CIRCLED NUMBER TEN [2000] [Unicode3.2] */ - {0x00e29480, 0x00849f}, /* U+2500 BOX DRAWINGS LIGHT HORIZONTAL [1983] */ - {0x00e29481, 0x0084aa}, /* U+2501 BOX DRAWINGS HEAVY HORIZONTAL [1983] */ - {0x00e29482, 0x0084a0}, /* U+2502 BOX DRAWINGS LIGHT VERTICAL [1983] */ - {0x00e29483, 0x0084ab}, /* U+2503 BOX DRAWINGS HEAVY VERTICAL [1983] */ - {0x00e2948c, 0x0084a1}, /* U+250C BOX DRAWINGS LIGHT DOWN AND RIGHT [1983] */ - {0x00e2948f, 0x0084ac}, /* U+250F BOX DRAWINGS HEAVY DOWN AND RIGHT [1983] */ - {0x00e29490, 0x0084a2}, /* U+2510 BOX DRAWINGS LIGHT DOWN AND LEFT [1983] */ - {0x00e29493, 0x0084ad}, /* U+2513 BOX DRAWINGS HEAVY DOWN AND LEFT [1983] */ - {0x00e29494, 0x0084a4}, /* U+2514 BOX DRAWINGS LIGHT UP AND RIGHT [1983] */ - {0x00e29497, 0x0084af}, /* U+2517 BOX DRAWINGS HEAVY UP AND RIGHT [1983] */ - {0x00e29498, 0x0084a3}, /* U+2518 BOX DRAWINGS LIGHT UP AND LEFT [1983] */ - {0x00e2949b, 0x0084ae}, /* U+251B BOX DRAWINGS HEAVY UP AND LEFT [1983] */ - {0x00e2949c, 0x0084a5}, /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT [1983] */ - {0x00e2949d, 0x0084ba}, /* U+251D BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY [1983] */ - {0x00e294a0, 0x0084b5}, /* U+2520 BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT [1983] */ - {0x00e294a3, 0x0084b0}, /* U+2523 BOX DRAWINGS HEAVY VERTICAL AND RIGHT [1983] */ - {0x00e294a4, 0x0084a7}, /* U+2524 BOX DRAWINGS LIGHT VERTICAL AND LEFT [1983] */ - {0x00e294a5, 0x0084bc}, /* U+2525 BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY [1983] */ - {0x00e294a8, 0x0084b7}, /* U+2528 BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT [1983] */ - {0x00e294ab, 0x0084b2}, /* U+252B BOX DRAWINGS HEAVY VERTICAL AND LEFT [1983] */ - {0x00e294ac, 0x0084a6}, /* U+252C BOX DRAWINGS LIGHT DOWN AND HORIZONTAL [1983] */ - {0x00e294af, 0x0084b6}, /* U+252F BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY [1983] */ - {0x00e294b0, 0x0084bb}, /* U+2530 BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT [1983] */ - {0x00e294b3, 0x0084b1}, /* U+2533 BOX DRAWINGS HEAVY DOWN AND HORIZONTAL [1983] */ - {0x00e294b4, 0x0084a8}, /* U+2534 BOX DRAWINGS LIGHT UP AND HORIZONTAL [1983] */ - {0x00e294b7, 0x0084b8}, /* U+2537 BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY [1983] */ - {0x00e294b8, 0x0084bd}, /* U+2538 BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT [1983] */ - {0x00e294bb, 0x0084b3}, /* U+253B BOX DRAWINGS HEAVY UP AND HORIZONTAL [1983] */ - {0x00e294bc, 0x0084a9}, /* U+253C BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL [1983] */ - {0x00e294bf, 0x0084b9}, /* U+253F BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY [1983] */ - {0x00e29582, 0x0084be}, /* U+2542 BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT [1983] */ - {0x00e2958b, 0x0084b4}, /* U+254B BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL [1983] */ - {0x00e296a0, 0x0081a1}, /* U+25A0 BLACK SQUARE */ - {0x00e296a1, 0x0081a0}, /* U+25A1 WHITE SQUARE */ - {0x00e296b1, 0x0083eb}, /* U+25B1 WHITE PARALLELOGRAM [2000] */ - {0x00e296b2, 0x0081a3}, /* U+25B2 BLACK UP-POINTING TRIANGLE */ - {0x00e296b3, 0x0081a2}, /* U+25B3 WHITE UP-POINTING TRIANGLE */ - {0x00e296b6, 0x008241}, /* U+25B6 BLACK RIGHT-POINTING TRIANGLE [2000] */ - {0x00e296b7, 0x008240}, /* U+25B7 WHITE RIGHT-POINTING TRIANGLE [2000] */ - {0x00e296bc, 0x0081a5}, /* U+25BC BLACK DOWN-POINTING TRIANGLE */ - {0x00e296bd, 0x0081a4}, /* U+25BD WHITE DOWN-POINTING TRIANGLE */ - {0x00e29780, 0x008243}, /* U+25C0 BLACK LEFT-POINTING TRIANGLE [2000] */ - {0x00e29781, 0x008242}, /* U+25C1 WHITE LEFT-POINTING TRIANGLE [2000] */ - {0x00e29786, 0x00819f}, /* U+25C6 BLACK DIAMOND */ - {0x00e29787, 0x00819e}, /* U+25C7 WHITE DIAMOND */ - {0x00e29789, 0x00825a}, /* U+25C9 FISHEYE [2000] */ - {0x00e2978b, 0x00819b}, /* U+25CB WHITE CIRCLE */ - {0x00e2978e, 0x00819d}, /* U+25CE BULLSEYE */ - {0x00e2978f, 0x00819c}, /* U+25CF BLACK CIRCLE */ - {0x00e29790, 0x0084e5}, /* U+25D0 CIRCLE WITH LEFT HALF BLACK [2000] */ - {0x00e29791, 0x0084e6}, /* U+25D1 CIRCLE WITH RIGHT HALF BLACK [2000] */ - {0x00e29792, 0x0084e7}, /* U+25D2 CIRCLE WITH LOWER HALF BLACK [2000] */ - {0x00e29793, 0x0084e8}, /* U+25D3 CIRCLE WITH UPPER HALF BLACK [2000] */ - {0x00e297a6, 0x00825e}, /* U+25E6 WHITE BULLET [2000] */ - {0x00e297af, 0x0081fc}, /* U+25EF LARGE CIRCLE [1983] */ - {0x00e29880, 0x0083e6}, /* U+2600 BLACK SUN WITH RAYS [2000] */ - {0x00e29881, 0x0083e7}, /* U+2601 CLOUD [2000] */ - {0x00e29882, 0x0083e8}, /* U+2602 UMBRELLA [2000] */ - {0x00e29883, 0x0083e9}, /* U+2603 SNOWMAN [2000] */ - {0x00e29885, 0x00819a}, /* U+2605 BLACK STAR */ - {0x00e29886, 0x008199}, /* U+2606 WHITE STAR */ - {0x00e2988e, 0x0083e5}, /* U+260E BLACK TELEPHONE [2000] */ - {0x00e29896, 0x0083e2}, /* U+2616 WHITE SHOGI PIECE [2000] [Unicode3.2] */ - {0x00e29897, 0x0083e3}, /* U+2617 BLACK SHOGI PIECE [2000] [Unicode3.2] */ - {0x00e2989e, 0x00879e}, /* U+261E WHITE RIGHT POINTING INDEX [2000] */ - {0x00e29980, 0x00818a}, /* U+2640 FEMALE SIGN */ - {0x00e29982, 0x008189}, /* U+2642 MALE SIGN */ - {0x00e299a0, 0x0083b8}, /* U+2660 BLACK SPADE SUIT [2000] */ - {0x00e299a1, 0x0083bb}, /* U+2661 WHITE HEART SUIT [2000] */ - {0x00e299a2, 0x0083b9}, /* U+2662 WHITE DIAMOND SUIT [2000] */ - {0x00e299a3, 0x0083be}, /* U+2663 BLACK CLUB SUIT [2000] */ - {0x00e299a4, 0x0083b7}, /* U+2664 WHITE SPADE SUIT [2000] */ - {0x00e299a5, 0x0083bc}, /* U+2665 BLACK HEART SUIT [2000] */ - {0x00e299a6, 0x0083ba}, /* U+2666 BLACK DIAMOND SUIT [2000] */ - {0x00e299a7, 0x0083bd}, /* U+2667 WHITE CLUB SUIT [2000] */ - {0x00e299a8, 0x0083ea}, /* U+2668 HOT SPRINGS [2000] */ - {0x00e299a9, 0x0081fb}, /* U+2669 QUARTER NOTE [2000] */ - {0x00e299aa, 0x0081f4}, /* U+266A EIGHTH NOTE [1983] */ - {0x00e299ab, 0x0081f9}, /* U+266B BEAMED EIGHTH NOTES [2000] */ - {0x00e299ac, 0x0081fa}, /* U+266C BEAMED SIXTEENTH NOTES [2000] */ - {0x00e299ad, 0x0081f3}, /* U+266D MUSIC FLAT SIGN [1983] */ - {0x00e299ae, 0x0081f8}, /* U+266E MUSIC NATURAL SIGN [2000] */ - {0x00e299af, 0x0081f2}, /* U+266F MUSIC SHARP SIGN [1983] */ - {0x00e29c93, 0x00849b}, /* U+2713 CHECK MARK [2000] */ - {0x00e29d96, 0x00879d}, /* U+2756 BLACK DIAMOND MINUS WHITE X [2000] */ - {0x00e29db6, 0x00869f}, /* U+2776 DINGBAT NEGATIVE CIRCLED DIGIT ONE [2000] */ - {0x00e29db7, 0x0086a0}, /* U+2777 DINGBAT NEGATIVE CIRCLED DIGIT TWO [2000] */ - {0x00e29db8, 0x0086a1}, /* U+2778 DINGBAT NEGATIVE CIRCLED DIGIT THREE [2000] */ - {0x00e29db9, 0x0086a2}, /* U+2779 DINGBAT NEGATIVE CIRCLED DIGIT FOUR [2000] */ - {0x00e29dba, 0x0086a3}, /* U+277A DINGBAT NEGATIVE CIRCLED DIGIT FIVE [2000] */ - {0x00e29dbb, 0x0086a4}, /* U+277B DINGBAT NEGATIVE CIRCLED DIGIT SIX [2000] */ - {0x00e29dbc, 0x0086a5}, /* U+277C DINGBAT NEGATIVE CIRCLED DIGIT SEVEN [2000] */ - {0x00e29dbd, 0x0086a6}, /* U+277D DINGBAT NEGATIVE CIRCLED DIGIT EIGHT [2000] */ - {0x00e29dbe, 0x0086a7}, /* U+277E DINGBAT NEGATIVE CIRCLED DIGIT NINE [2000] */ - {0x00e29dbf, 0x0086a8}, /* U+277F DINGBAT NEGATIVE CIRCLED NUMBER TEN [2000] */ - {0x00e2a4b4, 0x00824d}, /* U+2934 ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS [2000] [Unicode3.2] */ - {0x00e2a4b5, 0x00824e}, /* U+2935 ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS [2000] [Unicode3.2] */ - {0x00e2a6bf, 0x008259}, /* U+29BF CIRCLED BULLET [2000] [Unicode3.2] */ - {0x00e2a7ba, 0x00829d}, /* U+29FA DOUBLE PLUS [2000] [Unicode3.2] */ - {0x00e2a7bb, 0x00829e}, /* U+29FB TRIPLE PLUS [2000] [Unicode3.2] */ - {0x00e38080, 0x008140}, /* U+3000 IDEOGRAPHIC SPACE */ - {0x00e38081, 0x008141}, /* U+3001 IDEOGRAPHIC COMMA */ - {0x00e38082, 0x008142}, /* U+3002 IDEOGRAPHIC FULL STOP */ - {0x00e38083, 0x008156}, /* U+3003 DITTO MARK */ - {0x00e38085, 0x008158}, /* U+3005 IDEOGRAPHIC ITERATION MARK */ - {0x00e38086, 0x008159}, /* U+3006 IDEOGRAPHIC CLOSING MARK */ - {0x00e38087, 0x00815a}, /* U+3007 IDEOGRAPHIC NUMBER ZERO */ - {0x00e38088, 0x008171}, /* U+3008 LEFT ANGLE BRACKET */ - {0x00e38089, 0x008172}, /* U+3009 RIGHT ANGLE BRACKET */ - {0x00e3808a, 0x008173}, /* U+300A LEFT DOUBLE ANGLE BRACKET */ - {0x00e3808b, 0x008174}, /* U+300B RIGHT DOUBLE ANGLE BRACKET */ - {0x00e3808c, 0x008175}, /* U+300C LEFT CORNER BRACKET */ - {0x00e3808d, 0x008176}, /* U+300D RIGHT CORNER BRACKET */ - {0x00e3808e, 0x008177}, /* U+300E LEFT WHITE CORNER BRACKET */ - {0x00e3808f, 0x008178}, /* U+300F RIGHT WHITE CORNER BRACKET */ - {0x00e38090, 0x008179}, /* U+3010 LEFT BLACK LENTICULAR BRACKET */ - {0x00e38091, 0x00817a}, /* U+3011 RIGHT BLACK LENTICULAR BRACKET */ - {0x00e38092, 0x0081a7}, /* U+3012 POSTAL MARK */ - {0x00e38093, 0x0081ac}, /* U+3013 GETA MARK */ - {0x00e38094, 0x00816b}, /* U+3014 LEFT TORTOISE SHELL BRACKET */ - {0x00e38095, 0x00816c}, /* U+3015 RIGHT TORTOISE SHELL BRACKET */ - {0x00e38096, 0x0081d8}, /* U+3016 LEFT WHITE LENTICULAR BRACKET [2000] */ - {0x00e38097, 0x0081d9}, /* U+3017 RIGHT WHITE LENTICULAR BRACKET [2000] */ - {0x00e38098, 0x0081d6}, /* U+3018 LEFT WHITE TORTOISE SHELL BRACKET [2000] */ - {0x00e38099, 0x0081d7}, /* U+3019 RIGHT WHITE TORTOISE SHELL BRACKET [2000] */ - {0x00e3809c, 0x008160}, /* U+301C WAVE DASH Windows: U+FF5E */ - {0x00e3809d, 0x008780}, /* U+301D REVERSED DOUBLE PRIME QUOTATION MARK [2000] */ - {0x00e3809f, 0x008781}, /* U+301F LOW DOUBLE PRIME QUOTATION MARK [2000] */ - {0x00e380a0, 0x0083e4}, /* U+3020 POSTAL MARK FACE [2000] */ - {0x00e380b3, 0x0081b1}, /* U+3033 VERTICAL KANA REPEAT MARK UPPER HALF [2000] */ - {0x00e380b4, 0x0081b2}, /* U+3034 VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF [2000] */ - {0x00e380b5, 0x0081b3}, /* U+3035 VERTICAL KANA REPEAT MARK LOWER HALF [2000] */ - {0x00e380bb, 0x0081b4}, /* U+303B VERTICAL IDEOGRAPHIC ITERATION MARK [2000] [Unicode3.2] */ - {0x00e380bc, 0x0081b5}, /* U+303C MASU MARK [2000] [Unicode3.2] */ - {0x00e380bd, 0x00825b}, /* U+303D PART ALTERNATION MARK [2000] [Unicode3.2] */ - {0x00e38181, 0x00829f}, /* U+3041 HIRAGANA LETTER SMALL A */ - {0x00e38182, 0x0082a0}, /* U+3042 HIRAGANA LETTER A */ - {0x00e38183, 0x0082a1}, /* U+3043 HIRAGANA LETTER SMALL I */ - {0x00e38184, 0x0082a2}, /* U+3044 HIRAGANA LETTER I */ - {0x00e38185, 0x0082a3}, /* U+3045 HIRAGANA LETTER SMALL U */ - {0x00e38186, 0x0082a4}, /* U+3046 HIRAGANA LETTER U */ - {0x00e38187, 0x0082a5}, /* U+3047 HIRAGANA LETTER SMALL E */ - {0x00e38188, 0x0082a6}, /* U+3048 HIRAGANA LETTER E */ - {0x00e38189, 0x0082a7}, /* U+3049 HIRAGANA LETTER SMALL O */ - {0x00e3818a, 0x0082a8}, /* U+304A HIRAGANA LETTER O */ - {0x00e3818b, 0x0082a9}, /* U+304B HIRAGANA LETTER KA */ - {0x00e3818c, 0x0082aa}, /* U+304C HIRAGANA LETTER GA */ - {0x00e3818d, 0x0082ab}, /* U+304D HIRAGANA LETTER KI */ - {0x00e3818e, 0x0082ac}, /* U+304E HIRAGANA LETTER GI */ - {0x00e3818f, 0x0082ad}, /* U+304F HIRAGANA LETTER KU */ - {0x00e38190, 0x0082ae}, /* U+3050 HIRAGANA LETTER GU */ - {0x00e38191, 0x0082af}, /* U+3051 HIRAGANA LETTER KE */ - {0x00e38192, 0x0082b0}, /* U+3052 HIRAGANA LETTER GE */ - {0x00e38193, 0x0082b1}, /* U+3053 HIRAGANA LETTER KO */ - {0x00e38194, 0x0082b2}, /* U+3054 HIRAGANA LETTER GO */ - {0x00e38195, 0x0082b3}, /* U+3055 HIRAGANA LETTER SA */ - {0x00e38196, 0x0082b4}, /* U+3056 HIRAGANA LETTER ZA */ - {0x00e38197, 0x0082b5}, /* U+3057 HIRAGANA LETTER SI */ - {0x00e38198, 0x0082b6}, /* U+3058 HIRAGANA LETTER ZI */ - {0x00e38199, 0x0082b7}, /* U+3059 HIRAGANA LETTER SU */ - {0x00e3819a, 0x0082b8}, /* U+305A HIRAGANA LETTER ZU */ - {0x00e3819b, 0x0082b9}, /* U+305B HIRAGANA LETTER SE */ - {0x00e3819c, 0x0082ba}, /* U+305C HIRAGANA LETTER ZE */ - {0x00e3819d, 0x0082bb}, /* U+305D HIRAGANA LETTER SO */ - {0x00e3819e, 0x0082bc}, /* U+305E HIRAGANA LETTER ZO */ - {0x00e3819f, 0x0082bd}, /* U+305F HIRAGANA LETTER TA */ - {0x00e381a0, 0x0082be}, /* U+3060 HIRAGANA LETTER DA */ - {0x00e381a1, 0x0082bf}, /* U+3061 HIRAGANA LETTER TI */ - {0x00e381a2, 0x0082c0}, /* U+3062 HIRAGANA LETTER DI */ - {0x00e381a3, 0x0082c1}, /* U+3063 HIRAGANA LETTER SMALL TU */ - {0x00e381a4, 0x0082c2}, /* U+3064 HIRAGANA LETTER TU */ - {0x00e381a5, 0x0082c3}, /* U+3065 HIRAGANA LETTER DU */ - {0x00e381a6, 0x0082c4}, /* U+3066 HIRAGANA LETTER TE */ - {0x00e381a7, 0x0082c5}, /* U+3067 HIRAGANA LETTER DE */ - {0x00e381a8, 0x0082c6}, /* U+3068 HIRAGANA LETTER TO */ - {0x00e381a9, 0x0082c7}, /* U+3069 HIRAGANA LETTER DO */ - {0x00e381aa, 0x0082c8}, /* U+306A HIRAGANA LETTER NA */ - {0x00e381ab, 0x0082c9}, /* U+306B HIRAGANA LETTER NI */ - {0x00e381ac, 0x0082ca}, /* U+306C HIRAGANA LETTER NU */ - {0x00e381ad, 0x0082cb}, /* U+306D HIRAGANA LETTER NE */ - {0x00e381ae, 0x0082cc}, /* U+306E HIRAGANA LETTER NO */ - {0x00e381af, 0x0082cd}, /* U+306F HIRAGANA LETTER HA */ - {0x00e381b0, 0x0082ce}, /* U+3070 HIRAGANA LETTER BA */ - {0x00e381b1, 0x0082cf}, /* U+3071 HIRAGANA LETTER PA */ - {0x00e381b2, 0x0082d0}, /* U+3072 HIRAGANA LETTER HI */ - {0x00e381b3, 0x0082d1}, /* U+3073 HIRAGANA LETTER BI */ - {0x00e381b4, 0x0082d2}, /* U+3074 HIRAGANA LETTER PI */ - {0x00e381b5, 0x0082d3}, /* U+3075 HIRAGANA LETTER HU */ - {0x00e381b6, 0x0082d4}, /* U+3076 HIRAGANA LETTER BU */ - {0x00e381b7, 0x0082d5}, /* U+3077 HIRAGANA LETTER PU */ - {0x00e381b8, 0x0082d6}, /* U+3078 HIRAGANA LETTER HE */ - {0x00e381b9, 0x0082d7}, /* U+3079 HIRAGANA LETTER BE */ - {0x00e381ba, 0x0082d8}, /* U+307A HIRAGANA LETTER PE */ - {0x00e381bb, 0x0082d9}, /* U+307B HIRAGANA LETTER HO */ - {0x00e381bc, 0x0082da}, /* U+307C HIRAGANA LETTER BO */ - {0x00e381bd, 0x0082db}, /* U+307D HIRAGANA LETTER PO */ - {0x00e381be, 0x0082dc}, /* U+307E HIRAGANA LETTER MA */ - {0x00e381bf, 0x0082dd}, /* U+307F HIRAGANA LETTER MI */ - {0x00e38280, 0x0082de}, /* U+3080 HIRAGANA LETTER MU */ - {0x00e38281, 0x0082df}, /* U+3081 HIRAGANA LETTER ME */ - {0x00e38282, 0x0082e0}, /* U+3082 HIRAGANA LETTER MO */ - {0x00e38283, 0x0082e1}, /* U+3083 HIRAGANA LETTER SMALL YA */ - {0x00e38284, 0x0082e2}, /* U+3084 HIRAGANA LETTER YA */ - {0x00e38285, 0x0082e3}, /* U+3085 HIRAGANA LETTER SMALL YU */ - {0x00e38286, 0x0082e4}, /* U+3086 HIRAGANA LETTER YU */ - {0x00e38287, 0x0082e5}, /* U+3087 HIRAGANA LETTER SMALL YO */ - {0x00e38288, 0x0082e6}, /* U+3088 HIRAGANA LETTER YO */ - {0x00e38289, 0x0082e7}, /* U+3089 HIRAGANA LETTER RA */ - {0x00e3828a, 0x0082e8}, /* U+308A HIRAGANA LETTER RI */ - {0x00e3828b, 0x0082e9}, /* U+308B HIRAGANA LETTER RU */ - {0x00e3828c, 0x0082ea}, /* U+308C HIRAGANA LETTER RE */ - {0x00e3828d, 0x0082eb}, /* U+308D HIRAGANA LETTER RO */ - {0x00e3828e, 0x0082ec}, /* U+308E HIRAGANA LETTER SMALL WA */ - {0x00e3828f, 0x0082ed}, /* U+308F HIRAGANA LETTER WA */ - {0x00e38290, 0x0082ee}, /* U+3090 HIRAGANA LETTER WI */ - {0x00e38291, 0x0082ef}, /* U+3091 HIRAGANA LETTER WE */ - {0x00e38292, 0x0082f0}, /* U+3092 HIRAGANA LETTER WO */ - {0x00e38293, 0x0082f1}, /* U+3093 HIRAGANA LETTER N */ - {0x00e38294, 0x0082f2}, /* U+3094 HIRAGANA LETTER VU [2000] */ - {0x00e38295, 0x0082f3}, /* U+3095 HIRAGANA LETTER SMALL KA [2000] [Unicode3.2] */ - {0x00e38296, 0x0082f4}, /* U+3096 HIRAGANA LETTER SMALL KE [2000] [Unicode3.2] */ - {0x00e3829b, 0x00814a}, /* U+309B KATAKANA-HIRAGANA VOICED SOUND MARK */ - {0x00e3829c, 0x00814b}, /* U+309C KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ - {0x00e3829d, 0x008154}, /* U+309D HIRAGANA ITERATION MARK */ - {0x00e3829e, 0x008155}, /* U+309E HIRAGANA VOICED ITERATION MARK */ - {0x00e3829f, 0x0081b7}, /* U+309F HIRAGANA DIGRAPH YORI [2000] [Unicode3.2] */ - {0x00e382a0, 0x00829b}, /* U+30A0 KATAKANA-HIRAGANA DOUBLE HYPHEN [2000] [Unicode3.2] */ - {0x00e382a1, 0x008340}, /* U+30A1 KATAKANA LETTER SMALL A */ - {0x00e382a2, 0x008341}, /* U+30A2 KATAKANA LETTER A */ - {0x00e382a3, 0x008342}, /* U+30A3 KATAKANA LETTER SMALL I */ - {0x00e382a4, 0x008343}, /* U+30A4 KATAKANA LETTER I */ - {0x00e382a5, 0x008344}, /* U+30A5 KATAKANA LETTER SMALL U */ - {0x00e382a6, 0x008345}, /* U+30A6 KATAKANA LETTER U */ - {0x00e382a7, 0x008346}, /* U+30A7 KATAKANA LETTER SMALL E */ - {0x00e382a8, 0x008347}, /* U+30A8 KATAKANA LETTER E */ - {0x00e382a9, 0x008348}, /* U+30A9 KATAKANA LETTER SMALL O */ - {0x00e382aa, 0x008349}, /* U+30AA KATAKANA LETTER O */ - {0x00e382ab, 0x00834a}, /* U+30AB KATAKANA LETTER KA */ - {0x00e382ac, 0x00834b}, /* U+30AC KATAKANA LETTER GA */ - {0x00e382ad, 0x00834c}, /* U+30AD KATAKANA LETTER KI */ - {0x00e382ae, 0x00834d}, /* U+30AE KATAKANA LETTER GI */ - {0x00e382af, 0x00834e}, /* U+30AF KATAKANA LETTER KU */ - {0x00e382b0, 0x00834f}, /* U+30B0 KATAKANA LETTER GU */ - {0x00e382b1, 0x008350}, /* U+30B1 KATAKANA LETTER KE */ - {0x00e382b2, 0x008351}, /* U+30B2 KATAKANA LETTER GE */ - {0x00e382b3, 0x008352}, /* U+30B3 KATAKANA LETTER KO */ - {0x00e382b4, 0x008353}, /* U+30B4 KATAKANA LETTER GO */ - {0x00e382b5, 0x008354}, /* U+30B5 KATAKANA LETTER SA */ - {0x00e382b6, 0x008355}, /* U+30B6 KATAKANA LETTER ZA */ - {0x00e382b7, 0x008356}, /* U+30B7 KATAKANA LETTER SI */ - {0x00e382b8, 0x008357}, /* U+30B8 KATAKANA LETTER ZI */ - {0x00e382b9, 0x008358}, /* U+30B9 KATAKANA LETTER SU */ - {0x00e382ba, 0x008359}, /* U+30BA KATAKANA LETTER ZU */ - {0x00e382bb, 0x00835a}, /* U+30BB KATAKANA LETTER SE */ - {0x00e382bc, 0x00835b}, /* U+30BC KATAKANA LETTER ZE */ - {0x00e382bd, 0x00835c}, /* U+30BD KATAKANA LETTER SO */ - {0x00e382be, 0x00835d}, /* U+30BE KATAKANA LETTER ZO */ - {0x00e382bf, 0x00835e}, /* U+30BF KATAKANA LETTER TA */ - {0x00e38380, 0x00835f}, /* U+30C0 KATAKANA LETTER DA */ - {0x00e38381, 0x008360}, /* U+30C1 KATAKANA LETTER TI */ - {0x00e38382, 0x008361}, /* U+30C2 KATAKANA LETTER DI */ - {0x00e38383, 0x008362}, /* U+30C3 KATAKANA LETTER SMALL TU */ - {0x00e38384, 0x008363}, /* U+30C4 KATAKANA LETTER TU */ - {0x00e38385, 0x008364}, /* U+30C5 KATAKANA LETTER DU */ - {0x00e38386, 0x008365}, /* U+30C6 KATAKANA LETTER TE */ - {0x00e38387, 0x008366}, /* U+30C7 KATAKANA LETTER DE */ - {0x00e38388, 0x008367}, /* U+30C8 KATAKANA LETTER TO */ - {0x00e38389, 0x008368}, /* U+30C9 KATAKANA LETTER DO */ - {0x00e3838a, 0x008369}, /* U+30CA KATAKANA LETTER NA */ - {0x00e3838b, 0x00836a}, /* U+30CB KATAKANA LETTER NI */ - {0x00e3838c, 0x00836b}, /* U+30CC KATAKANA LETTER NU */ - {0x00e3838d, 0x00836c}, /* U+30CD KATAKANA LETTER NE */ - {0x00e3838e, 0x00836d}, /* U+30CE KATAKANA LETTER NO */ - {0x00e3838f, 0x00836e}, /* U+30CF KATAKANA LETTER HA */ - {0x00e38390, 0x00836f}, /* U+30D0 KATAKANA LETTER BA */ - {0x00e38391, 0x008370}, /* U+30D1 KATAKANA LETTER PA */ - {0x00e38392, 0x008371}, /* U+30D2 KATAKANA LETTER HI */ - {0x00e38393, 0x008372}, /* U+30D3 KATAKANA LETTER BI */ - {0x00e38394, 0x008373}, /* U+30D4 KATAKANA LETTER PI */ - {0x00e38395, 0x008374}, /* U+30D5 KATAKANA LETTER HU */ - {0x00e38396, 0x008375}, /* U+30D6 KATAKANA LETTER BU */ - {0x00e38397, 0x008376}, /* U+30D7 KATAKANA LETTER PU */ - {0x00e38398, 0x008377}, /* U+30D8 KATAKANA LETTER HE */ - {0x00e38399, 0x008378}, /* U+30D9 KATAKANA LETTER BE */ - {0x00e3839a, 0x008379}, /* U+30DA KATAKANA LETTER PE */ - {0x00e3839b, 0x00837a}, /* U+30DB KATAKANA LETTER HO */ - {0x00e3839c, 0x00837b}, /* U+30DC KATAKANA LETTER BO */ - {0x00e3839d, 0x00837c}, /* U+30DD KATAKANA LETTER PO */ - {0x00e3839e, 0x00837d}, /* U+30DE KATAKANA LETTER MA */ - {0x00e3839f, 0x00837e}, /* U+30DF KATAKANA LETTER MI */ - {0x00e383a0, 0x008380}, /* U+30E0 KATAKANA LETTER MU */ - {0x00e383a1, 0x008381}, /* U+30E1 KATAKANA LETTER ME */ - {0x00e383a2, 0x008382}, /* U+30E2 KATAKANA LETTER MO */ - {0x00e383a3, 0x008383}, /* U+30E3 KATAKANA LETTER SMALL YA */ - {0x00e383a4, 0x008384}, /* U+30E4 KATAKANA LETTER YA */ - {0x00e383a5, 0x008385}, /* U+30E5 KATAKANA LETTER SMALL YU */ - {0x00e383a6, 0x008386}, /* U+30E6 KATAKANA LETTER YU */ - {0x00e383a7, 0x008387}, /* U+30E7 KATAKANA LETTER SMALL YO */ - {0x00e383a8, 0x008388}, /* U+30E8 KATAKANA LETTER YO */ - {0x00e383a9, 0x008389}, /* U+30E9 KATAKANA LETTER RA */ - {0x00e383aa, 0x00838a}, /* U+30EA KATAKANA LETTER RI */ - {0x00e383ab, 0x00838b}, /* U+30EB KATAKANA LETTER RU */ - {0x00e383ac, 0x00838c}, /* U+30EC KATAKANA LETTER RE */ - {0x00e383ad, 0x00838d}, /* U+30ED KATAKANA LETTER RO */ - {0x00e383ae, 0x00838e}, /* U+30EE KATAKANA LETTER SMALL WA */ - {0x00e383af, 0x00838f}, /* U+30EF KATAKANA LETTER WA */ - {0x00e383b0, 0x008390}, /* U+30F0 KATAKANA LETTER WI */ - {0x00e383b1, 0x008391}, /* U+30F1 KATAKANA LETTER WE */ - {0x00e383b2, 0x008392}, /* U+30F2 KATAKANA LETTER WO */ - {0x00e383b3, 0x008393}, /* U+30F3 KATAKANA LETTER N */ - {0x00e383b4, 0x008394}, /* U+30F4 KATAKANA LETTER VU */ - {0x00e383b5, 0x008395}, /* U+30F5 KATAKANA LETTER SMALL KA */ - {0x00e383b6, 0x008396}, /* U+30F6 KATAKANA LETTER SMALL KE */ - {0x00e383b7, 0x008492}, /* U+30F7 KATAKANA LETTER VA [2000] */ - {0x00e383b8, 0x008493}, /* U+30F8 KATAKANA LETTER VI [2000] */ - {0x00e383b9, 0x008494}, /* U+30F9 KATAKANA LETTER VE [2000] */ - {0x00e383ba, 0x008495}, /* U+30FA KATAKANA LETTER VO [2000] */ - {0x00e383bb, 0x008145}, /* U+30FB KATAKANA MIDDLE DOT */ - {0x00e383bc, 0x00815b}, /* U+30FC KATAKANA-HIRAGANA PROLONGED SOUND MARK */ - {0x00e383bd, 0x008152}, /* U+30FD KATAKANA ITERATION MARK */ - {0x00e383be, 0x008153}, /* U+30FE KATAKANA VOICED ITERATION MARK */ - {0x00e383bf, 0x0081b6}, /* U+30FF KATAKANA DIGRAPH KOTO [2000] [Unicode3.2] */ - {0x00e387b0, 0x0083ec}, /* U+31F0 KATAKANA LETTER SMALL KU [2000] [Unicode3.2] */ - {0x00e387b1, 0x0083ed}, /* U+31F1 KATAKANA LETTER SMALL SI [2000] [Unicode3.2] */ - {0x00e387b2, 0x0083ee}, /* U+31F2 KATAKANA LETTER SMALL SU [2000] [Unicode3.2] */ - {0x00e387b3, 0x0083ef}, /* U+31F3 KATAKANA LETTER SMALL TO [2000] [Unicode3.2] */ - {0x00e387b4, 0x0083f0}, /* U+31F4 KATAKANA LETTER SMALL NU [2000] [Unicode3.2] */ - {0x00e387b5, 0x0083f1}, /* U+31F5 KATAKANA LETTER SMALL HA [2000] [Unicode3.2] */ - {0x00e387b6, 0x0083f2}, /* U+31F6 KATAKANA LETTER SMALL HI [2000] [Unicode3.2] */ - {0x00e387b7, 0x0083f3}, /* U+31F7 KATAKANA LETTER SMALL HU [2000] [Unicode3.2] */ - {0x00e387b8, 0x0083f4}, /* U+31F8 KATAKANA LETTER SMALL HE [2000] [Unicode3.2] */ - {0x00e387b9, 0x0083f5}, /* U+31F9 KATAKANA LETTER SMALL HO [2000] [Unicode3.2] */ - {0x00e387ba, 0x0083f7}, /* U+31FA KATAKANA LETTER SMALL MU [2000] [Unicode3.2] */ - {0x00e387bb, 0x0083f8}, /* U+31FB KATAKANA LETTER SMALL RA [2000] [Unicode3.2] */ - {0x00e387bc, 0x0083f9}, /* U+31FC KATAKANA LETTER SMALL RI [2000] [Unicode3.2] */ - {0x00e387bd, 0x0083fa}, /* U+31FD KATAKANA LETTER SMALL RU [2000] [Unicode3.2] */ - {0x00e387be, 0x0083fb}, /* U+31FE KATAKANA LETTER SMALL RE [2000] [Unicode3.2] */ - {0x00e387bf, 0x0083fc}, /* U+31FF KATAKANA LETTER SMALL RO [2000] [Unicode3.2] */ - {0x00e388b1, 0x00878a}, /* U+3231 PARENTHESIZED IDEOGRAPH STOCK [2000] */ - {0x00e388b2, 0x00878b}, /* U+3232 PARENTHESIZED IDEOGRAPH HAVE [2000] */ - {0x00e388b9, 0x00878c}, /* U+3239 PARENTHESIZED IDEOGRAPH REPRESENT [2000] */ - {0x00e38991, 0x0084bf}, /* U+3251 CIRCLED NUMBER TWENTY ONE [2000] [Unicode3.2] */ - {0x00e38992, 0x0084c0}, /* U+3252 CIRCLED NUMBER TWENTY TWO [2000] [Unicode3.2] */ - {0x00e38993, 0x0084c1}, /* U+3253 CIRCLED NUMBER TWENTY THREE [2000] [Unicode3.2] */ - {0x00e38994, 0x0084c2}, /* U+3254 CIRCLED NUMBER TWENTY FOUR [2000] [Unicode3.2] */ - {0x00e38995, 0x0084c3}, /* U+3255 CIRCLED NUMBER TWENTY FIVE [2000] [Unicode3.2] */ - {0x00e38996, 0x0084c4}, /* U+3256 CIRCLED NUMBER TWENTY SIX [2000] [Unicode3.2] */ - {0x00e38997, 0x0084c5}, /* U+3257 CIRCLED NUMBER TWENTY SEVEN [2000] [Unicode3.2] */ - {0x00e38998, 0x0084c6}, /* U+3258 CIRCLED NUMBER TWENTY EIGHT [2000] [Unicode3.2] */ - {0x00e38999, 0x0084c7}, /* U+3259 CIRCLED NUMBER TWENTY NINE [2000] [Unicode3.2] */ - {0x00e3899a, 0x0084c8}, /* U+325A CIRCLED NUMBER THIRTY [2000] [Unicode3.2] */ - {0x00e3899b, 0x0084c9}, /* U+325B CIRCLED NUMBER THIRTY ONE [2000] [Unicode3.2] */ - {0x00e3899c, 0x0084ca}, /* U+325C CIRCLED NUMBER THIRTY TWO [2000] [Unicode3.2] */ - {0x00e3899d, 0x0084cb}, /* U+325D CIRCLED NUMBER THIRTY THREE [2000] [Unicode3.2] */ - {0x00e3899e, 0x0084cc}, /* U+325E CIRCLED NUMBER THIRTY FOUR [2000] [Unicode3.2] */ - {0x00e3899f, 0x0084cd}, /* U+325F CIRCLED NUMBER THIRTY FIVE [2000] [Unicode3.2] */ - {0x00e38aa4, 0x008785}, /* U+32A4 CIRCLED IDEOGRAPH HIGH [2000] */ - {0x00e38aa5, 0x008786}, /* U+32A5 CIRCLED IDEOGRAPH CENTRE [2000] */ - {0x00e38aa6, 0x008787}, /* U+32A6 CIRCLED IDEOGRAPH LOW [2000] */ - {0x00e38aa7, 0x008788}, /* U+32A7 CIRCLED IDEOGRAPH LEFT [2000] */ - {0x00e38aa8, 0x008789}, /* U+32A8 CIRCLED IDEOGRAPH RIGHT [2000] */ - {0x00e38ab1, 0x0084ce}, /* U+32B1 CIRCLED NUMBER THIRTY SIX [2000] [Unicode3.2] */ - {0x00e38ab2, 0x0084cf}, /* U+32B2 CIRCLED NUMBER THIRTY SEVEN [2000] [Unicode3.2] */ - {0x00e38ab3, 0x0084d0}, /* U+32B3 CIRCLED NUMBER THIRTY EIGHT [2000] [Unicode3.2] */ - {0x00e38ab4, 0x0084d1}, /* U+32B4 CIRCLED NUMBER THIRTY NINE [2000] [Unicode3.2] */ - {0x00e38ab5, 0x0084d2}, /* U+32B5 CIRCLED NUMBER FORTY [2000] [Unicode3.2] */ - {0x00e38ab6, 0x0084d3}, /* U+32B6 CIRCLED NUMBER FORTY ONE [2000] [Unicode3.2] */ - {0x00e38ab7, 0x0084d4}, /* U+32B7 CIRCLED NUMBER FORTY TWO [2000] [Unicode3.2] */ - {0x00e38ab8, 0x0084d5}, /* U+32B8 CIRCLED NUMBER FORTY THREE [2000] [Unicode3.2] */ - {0x00e38ab9, 0x0084d6}, /* U+32B9 CIRCLED NUMBER FORTY FOUR [2000] [Unicode3.2] */ - {0x00e38aba, 0x0084d7}, /* U+32BA CIRCLED NUMBER FORTY FIVE [2000] [Unicode3.2] */ - {0x00e38abb, 0x0084d8}, /* U+32BB CIRCLED NUMBER FORTY SIX [2000] [Unicode3.2] */ - {0x00e38abc, 0x0084d9}, /* U+32BC CIRCLED NUMBER FORTY SEVEN [2000] [Unicode3.2] */ - {0x00e38abd, 0x0084da}, /* U+32BD CIRCLED NUMBER FORTY EIGHT [2000] [Unicode3.2] */ - {0x00e38abe, 0x0084db}, /* U+32BE CIRCLED NUMBER FORTY NINE [2000] [Unicode3.2] */ - {0x00e38abf, 0x0084dc}, /* U+32BF CIRCLED NUMBER FIFTY [2000] [Unicode3.2] */ - {0x00e38b90, 0x0086d9}, /* U+32D0 CIRCLED KATAKANA A [2000] */ - {0x00e38b91, 0x0086da}, /* U+32D1 CIRCLED KATAKANA I [2000] */ - {0x00e38b92, 0x0086db}, /* U+32D2 CIRCLED KATAKANA U [2000] */ - {0x00e38b93, 0x0086dc}, /* U+32D3 CIRCLED KATAKANA E [2000] */ - {0x00e38b94, 0x0086dd}, /* U+32D4 CIRCLED KATAKANA O [2000] */ - {0x00e38b95, 0x0086de}, /* U+32D5 CIRCLED KATAKANA KA [2000] */ - {0x00e38b96, 0x0086df}, /* U+32D6 CIRCLED KATAKANA KI [2000] */ - {0x00e38b97, 0x0086e0}, /* U+32D7 CIRCLED KATAKANA KU [2000] */ - {0x00e38b98, 0x0086e1}, /* U+32D8 CIRCLED KATAKANA KE [2000] */ - {0x00e38b99, 0x0086e2}, /* U+32D9 CIRCLED KATAKANA KO [2000] */ - {0x00e38b9a, 0x0086e3}, /* U+32DA CIRCLED KATAKANA SA [2000] */ - {0x00e38b9b, 0x0086e4}, /* U+32DB CIRCLED KATAKANA SI [2000] */ - {0x00e38b9c, 0x0086e5}, /* U+32DC CIRCLED KATAKANA SU [2000] */ - {0x00e38b9d, 0x0086e6}, /* U+32DD CIRCLED KATAKANA SE [2000] */ - {0x00e38b9e, 0x0086e7}, /* U+32DE CIRCLED KATAKANA SO [2000] */ - {0x00e38b9f, 0x0086e8}, /* U+32DF CIRCLED KATAKANA TA [2000] */ - {0x00e38ba0, 0x0086e9}, /* U+32E0 CIRCLED KATAKANA TI [2000] */ - {0x00e38ba1, 0x0086ea}, /* U+32E1 CIRCLED KATAKANA TU [2000] */ - {0x00e38ba2, 0x0086eb}, /* U+32E2 CIRCLED KATAKANA TE [2000] */ - {0x00e38ba3, 0x0086ec}, /* U+32E3 CIRCLED KATAKANA TO [2000] */ - {0x00e38ba5, 0x0086ef}, /* U+32E5 CIRCLED KATAKANA NI [2000] */ - {0x00e38ba9, 0x0086ee}, /* U+32E9 CIRCLED KATAKANA HA [2000] */ - {0x00e38bac, 0x0086f1}, /* U+32EC CIRCLED KATAKANA HE [2000] */ - {0x00e38bad, 0x0086f0}, /* U+32ED CIRCLED KATAKANA HO [2000] */ - {0x00e38bba, 0x0086ed}, /* U+32FA CIRCLED KATAKANA RO [2000] */ - {0x00e38c83, 0x008765}, /* U+3303 SQUARE AARU [2000] */ - {0x00e38c8d, 0x008769}, /* U+330D SQUARE KARORII [2000] */ - {0x00e38c94, 0x008760}, /* U+3314 SQUARE KIRO [2000] */ - {0x00e38c98, 0x008763}, /* U+3318 SQUARE GURAMU [2000] */ - {0x00e38ca2, 0x008761}, /* U+3322 SQUARE SENTI [2000] */ - {0x00e38ca3, 0x00876b}, /* U+3323 SQUARE SENTO [2000] */ - {0x00e38ca6, 0x00876a}, /* U+3326 SQUARE DORU [2000] */ - {0x00e38ca7, 0x008764}, /* U+3327 SQUARE TON [2000] */ - {0x00e38cab, 0x00876c}, /* U+332B SQUARE PAASENTO [2000] */ - {0x00e38cb6, 0x008766}, /* U+3336 SQUARE HEKUTAARU [2000] */ - {0x00e38cbb, 0x00876e}, /* U+333B SQUARE PEEZI [2000] */ - {0x00e38d89, 0x00875f}, /* U+3349 SQUARE MIRI [2000] */ - {0x00e38d8a, 0x00876d}, /* U+334A SQUARE MIRIBAARU [2000] */ - {0x00e38d8d, 0x008762}, /* U+334D SQUARE MEETORU [2000] */ - {0x00e38d91, 0x008767}, /* U+3351 SQUARE RITTORU [2000] */ - {0x00e38d97, 0x008768}, /* U+3357 SQUARE WATTO [2000] */ - {0x00e38dbb, 0x00877e}, /* U+337B SQUARE ERA NAME HEISEI [2000] */ - {0x00e38dbc, 0x00878f}, /* U+337C SQUARE ERA NAME SYOUWA [2000] */ - {0x00e38dbd, 0x00878e}, /* U+337D SQUARE ERA NAME TAISYOU [2000] */ - {0x00e38dbe, 0x00878d}, /* U+337E SQUARE ERA NAME MEIZI [2000] */ - {0x00e38e8e, 0x008772}, /* U+338E SQUARE MG [2000] */ - {0x00e38e8f, 0x008773}, /* U+338F SQUARE KG [2000] */ - {0x00e38e9c, 0x00876f}, /* U+339C SQUARE MM [2000] */ - {0x00e38e9d, 0x008770}, /* U+339D SQUARE CM [2000] */ - {0x00e38e9e, 0x008771}, /* U+339E SQUARE KM [2000] */ - {0x00e38ea1, 0x008775}, /* U+33A1 SQUARE M SQUARED [2000] */ - {0x00e38f84, 0x008774}, /* U+33C4 SQUARE CC [2000] */ - {0x00e38f8b, 0x00827d}, /* U+33CB SQUARE HP [2000] */ - {0x00e38f8d, 0x008783}, /* U+33CD SQUARE KK [2000] */ - {0x00e39082, 0x0087a1}, /* U+3402 [2000] */ - {0x00e39086, 0x00f04c}, /* U+3406 [2000] */ - {0x00e390ac, 0x00f051}, /* U+342C [2000] */ - {0x00e390ae, 0x00f052}, /* U+342E [2000] */ - {0x00e391a8, 0x00f07d}, /* U+3468 [2000] */ - {0x00e391aa, 0x00f075}, /* U+346A [2000] */ - {0x00e39292, 0x00f09e}, /* U+3492 [2000] */ - {0x00e392b5, 0x0087d1}, /* U+34B5 [2000] */ - {0x00e392bc, 0x00f14a}, /* U+34BC [2000] */ - {0x00e39381, 0x00f7e6}, /* U+34C1 [2000] */ - {0x00e39387, 0x00f14e}, /* U+34C7 [2000] */ - {0x00e3939b, 0x0087d9}, /* U+34DB [2000] */ - {0x00e3949f, 0x00f167}, /* U+351F [2000] */ - {0x00e3959d, 0x00f17c}, /* U+355D [2000] */ - {0x00e3959e, 0x00f17d}, /* U+355E [2000] */ - {0x00e395a3, 0x00f181}, /* U+3563 [2000] */ - {0x00e395ae, 0x00f187}, /* U+356E [2000] */ - {0x00e396a6, 0x00f1a1}, /* U+35A6 [2000] */ - {0x00e396a8, 0x00f1a4}, /* U+35A8 [2000] */ - {0x00e39785, 0x00f1ad}, /* U+35C5 [2000] */ - {0x00e3979a, 0x00f1b6}, /* U+35DA [2000] */ - {0x00e397b4, 0x00f1c0}, /* U+35F4 [2000] */ - {0x00e39885, 0x00f1c8}, /* U+3605 [2000] */ - {0x00e3998a, 0x00f1f7}, /* U+364A [2000] */ - {0x00e39a91, 0x00f25e}, /* U+3691 [2000] */ - {0x00e39a96, 0x00f262}, /* U+3696 [2000] */ - {0x00e39a99, 0x00f260}, /* U+3699 [2000] */ - {0x00e39b8f, 0x00f276}, /* U+36CF [2000] */ - {0x00e39da1, 0x00f0a1}, /* U+3761 [2000] */ - {0x00e39da2, 0x00f0a3}, /* U+3762 [2000] */ - {0x00e39dab, 0x00f0a7}, /* U+376B [2000] */ - {0x00e39dac, 0x00f0a6}, /* U+376C [2000] */ - {0x00e39db5, 0x00f0aa}, /* U+3775 [2000] */ - {0x00e39e8d, 0x00987e}, /* U+378D [2000] */ - {0x00e39f81, 0x00f0bc}, /* U+37C1 [2000] */ - {0x00e39fa2, 0x00988f}, /* U+37E2 [2000] */ - {0x00e39fa8, 0x00f0d4}, /* U+37E8 [2000] */ - {0x00e39fb4, 0x00f0d7}, /* U+37F4 [2000] */ - {0x00e39fbd, 0x00f0da}, /* U+37FD [2000] */ - {0x00e3a080, 0x00f0dc}, /* U+3800 [2000] */ - {0x00e3a0af, 0x00f0ed}, /* U+382F [2000] */ - {0x00e3a0b6, 0x00f0ef}, /* U+3836 [2000] */ - {0x00e3a180, 0x00f0f2}, /* U+3840 [2000] */ - {0x00e3a19c, 0x00f0f7}, /* U+385C [2000] */ - {0x00e3a1a1, 0x00f0f9}, /* U+3861 [2000] */ - {0x00e3a3ba, 0x00f2b9}, /* U+38FA [2000] */ - {0x00e3a497, 0x00f2c4}, /* U+3917 [2000] */ - {0x00e3a49a, 0x00f2c8}, /* U+391A [2000] */ - {0x00e3a5af, 0x00f2de}, /* U+396F [2000] */ - {0x00e3a9ae, 0x00f37a}, /* U+3A6E [2000] */ - {0x00e3a9b3, 0x00f37e}, /* U+3A73 [2000] */ - {0x00e3ab96, 0x00f391}, /* U+3AD6 [2000] */ - {0x00e3ab97, 0x00f3b4}, /* U+3AD7 [2000] */ - {0x00e3abaa, 0x00f39c}, /* U+3AEA [2000] */ - {0x00e3ac8e, 0x00f3ac}, /* U+3B0E [2000] */ - {0x00e3ac9a, 0x00f3b0}, /* U+3B1A [2000] */ - {0x00e3ac9c, 0x00f3b2}, /* U+3B1C [2000] */ - {0x00e3aca2, 0x00eb68}, /* U+3B22 [2000] */ - {0x00e3adad, 0x00f3eb}, /* U+3B6D [2000] */ - {0x00e3adb7, 0x00f3e3}, /* U+3B77 [2000] */ - {0x00e3ae87, 0x00f447}, /* U+3B87 [2000] */ - {0x00e3ae88, 0x00f448}, /* U+3B88 [2000] */ - {0x00e3ae8d, 0x00f44b}, /* U+3B8D [2000] */ - {0x00e3aea4, 0x00f453}, /* U+3BA4 [2000] */ - {0x00e3aeb6, 0x00eb9e}, /* U+3BB6 [2000] */ - {0x00e3af83, 0x00eb9f}, /* U+3BC3 [2000] */ - {0x00e3af8d, 0x00f467}, /* U+3BCD [2000] */ - {0x00e3afb0, 0x00f47c}, /* U+3BF0 [2000] */ - {0x00e3b08f, 0x00ebb8}, /* U+3C0F [2000] */ - {0x00e3b0a6, 0x00f497}, /* U+3C26 [2000] */ - {0x00e3b383, 0x00f4b9}, /* U+3CC3 [2000] */ - {0x00e3b392, 0x00f4c0}, /* U+3CD2 [2000] */ - {0x00e3b491, 0x00f4ef}, /* U+3D11 [2000] */ - {0x00e3b49e, 0x00f4fc}, /* U+3D1E [2000] */ - {0x00e3b5a4, 0x00f55f}, /* U+3D64 [2000] */ - {0x00e3b69a, 0x00f573}, /* U+3D9A [2000] */ - {0x00e3b780, 0x00f590}, /* U+3DC0 [2000] */ - {0x00e3b794, 0x00f597}, /* U+3DD4 [2000] */ - {0x00e3b885, 0x00f5a6}, /* U+3E05 [2000] */ - {0x00e3b8bf, 0x00ec86}, /* U+3E3F [2000] */ - {0x00e3b9a0, 0x00f5bd}, /* U+3E60 [2000] */ - {0x00e3b9a6, 0x00f5bf}, /* U+3E66 [2000] */ - {0x00e3b9a8, 0x00f5c0}, /* U+3E68 [2000] */ - {0x00e3ba83, 0x00f5c7}, /* U+3E83 [2000] */ - {0x00e3ba94, 0x00f5ce}, /* U+3E94 [2000] */ - {0x00e3bd97, 0x00f653}, /* U+3F57 [2000] */ - {0x00e3bdb2, 0x00eccb}, /* U+3F72 [2000] */ - {0x00e3bdb5, 0x00f665}, /* U+3F75 [2000] */ - {0x00e3bdb7, 0x00f667}, /* U+3F77 [2000] */ - {0x00e3beae, 0x00f67b}, /* U+3FAE [2000] */ - {0x00e3bf89, 0x00f687}, /* U+3FC9 [2000] */ - {0x00e3bf97, 0x00f68c}, /* U+3FD7 [2000] */ - {0x00e480b9, 0x00f6a0}, /* U+4039 [2000] */ - {0x00e48198, 0x00f6ab}, /* U+4058 [2000] */ - {0x00e48293, 0x00f6b7}, /* U+4093 [2000] */ - {0x00e48485, 0x00f6e2}, /* U+4105 [2000] */ - {0x00e48588, 0x00f6f2}, /* U+4148 [2000] */ - {0x00e4858f, 0x00f6f5}, /* U+414F [2000] */ - {0x00e485a3, 0x00f6fb}, /* U+4163 [2000] */ - {0x00e486b4, 0x00f752}, /* U+41B4 [2000] */ - {0x00e486bf, 0x00f756}, /* U+41BF [2000] */ - {0x00e487a6, 0x00f766}, /* U+41E6 [2000] */ - {0x00e487ae, 0x00f76a}, /* U+41EE [2000] */ - {0x00e487b3, 0x00f767}, /* U+41F3 [2000] */ - {0x00e48887, 0x00f772}, /* U+4207 [2000] */ - {0x00e4888e, 0x00f776}, /* U+420E [2000] */ - {0x00e489a4, 0x00ed8d}, /* U+4264 [2000] */ - {0x00e48b86, 0x00f7a9}, /* U+42C6 [2000] */ - {0x00e48b96, 0x00f7b4}, /* U+42D6 [2000] */ - {0x00e48b9d, 0x00f7b9}, /* U+42DD [2000] */ - {0x00e48c82, 0x00f7cc}, /* U+4302 [2000] */ - {0x00e48cab, 0x00f7db}, /* U+432B [2000] */ - {0x00e48d83, 0x00f7df}, /* U+4343 [2000] */ - {0x00e48fae, 0x00f85d}, /* U+43EE [2000] */ - {0x00e48fb0, 0x00f861}, /* U+43F0 [2000] */ - {0x00e49088, 0x00f867}, /* U+4408 [2000] */ - {0x00e49097, 0x00f869}, /* U+4417 [2000] */ - {0x00e4909c, 0x00f86b}, /* U+441C [2000] */ - {0x00e490a2, 0x00f86e}, /* U+4422 [2000] */ - {0x00e49193, 0x00edd7}, /* U+4453 [2000] */ - {0x00e4919b, 0x00edd8}, /* U+445B [2000] */ - {0x00e491b6, 0x00f88c}, /* U+4476 [2000] */ - {0x00e491ba, 0x00f88e}, /* U+447A [2000] */ - {0x00e49291, 0x00f897}, /* U+4491 [2000] */ - {0x00e492b3, 0x00f8b3}, /* U+44B3 [2000] */ - {0x00e492be, 0x00f8b0}, /* U+44BE [2000] */ - {0x00e49394, 0x00f8b2}, /* U+44D4 [2000] */ - {0x00e49488, 0x00f8d7}, /* U+4508 [2000] */ - {0x00e4948d, 0x00f8d2}, /* U+450D [2000] */ - {0x00e494a5, 0x00f8eb}, /* U+4525 [2000] */ - {0x00e49583, 0x00f8ec}, /* U+4543 [2000] */ - {0x00e4969d, 0x00ee70}, /* U+459D [2000] */ - {0x00e496b8, 0x00f96e}, /* U+45B8 [2000] */ - {0x00e497a5, 0x00f98c}, /* U+45E5 [2000] */ - {0x00e497aa, 0x00ee80}, /* U+45EA [2000] */ - {0x00e4988f, 0x00f9a2}, /* U+460F [2000] */ - {0x00e49981, 0x00f9b8}, /* U+4641 [2000] */ - {0x00e499a5, 0x00f9c1}, /* U+4665 [2000] */ - {0x00e49aa1, 0x00f9cc}, /* U+46A1 [2000] */ - {0x00e49aaf, 0x00f9d1}, /* U+46AF [2000] */ - {0x00e49c8c, 0x00f9e9}, /* U+470C [2000] */ - {0x00e49da4, 0x00fa48}, /* U+4764 [2000] */ - {0x00e49fbd, 0x00fa5e}, /* U+47FD [2000] */ - {0x00e4a096, 0x00fa68}, /* U+4816 [2000] */ - {0x00e4a184, 0x00eec9}, /* U+4844 [2000] */ - {0x00e4a18e, 0x00fa7b}, /* U+484E [2000] */ - {0x00e4a2b5, 0x00faa5}, /* U+48B5 [2000] */ - {0x00e4a6b0, 0x00ef77}, /* U+49B0 [2000] */ - {0x00e4a7a7, 0x00fb8a}, /* U+49E7 [2000] */ - {0x00e4a7ba, 0x00fb90}, /* U+49FA [2000] */ - {0x00e4a884, 0x00fb95}, /* U+4A04 [2000] */ - {0x00e4a8a9, 0x00fb98}, /* U+4A29 [2000] */ - {0x00e4aabc, 0x00fbb5}, /* U+4ABC [2000] */ - {0x00e4acbb, 0x00fbd3}, /* U+4B3B [2000] */ - {0x00e4af82, 0x00fc45}, /* U+4BC2 [2000] */ - {0x00e4af8a, 0x00fc47}, /* U+4BCA [2000] */ - {0x00e4af92, 0x00fc49}, /* U+4BD2 [2000] */ - {0x00e4afa8, 0x00fc50}, /* U+4BE8 [2000] */ - {0x00e4b097, 0x00efbc}, /* U+4C17 [2000] */ - {0x00e4b0a0, 0x00fc5e}, /* U+4C20 [2000] */ - {0x00e4b384, 0x00fca8}, /* U+4CC4 [2000] */ - {0x00e4b391, 0x00fcab}, /* U+4CD1 [2000] */ - {0x00e4b487, 0x00fcc9}, /* U+4D07 [2000] */ - {0x00e4b5b7, 0x00fcde}, /* U+4D77 [2000] */ - {0x00e4b880, 0x0088ea}, /* U+4E00 */ - {0x00e4b881, 0x00929a}, /* U+4E01 */ - {0x00e4b882, 0x00f041}, /* U+4E02 [2000] */ - {0x00e4b883, 0x008eb5}, /* U+4E03 */ - {0x00e4b887, 0x00969c}, /* U+4E07 */ - {0x00e4b888, 0x008fe4}, /* U+4E08 */ - {0x00e4b889, 0x008e4f}, /* U+4E09 */ - {0x00e4b88a, 0x008fe3}, /* U+4E0A */ - {0x00e4b88b, 0x0089ba}, /* U+4E0B */ - {0x00e4b88d, 0x009573}, /* U+4E0D */ - {0x00e4b88e, 0x00975e}, /* U+4E0E */ - {0x00e4b88f, 0x00f042}, /* U+4E0F [2000] */ - {0x00e4b890, 0x0098a0}, /* U+4E10 */ - {0x00e4b891, 0x00894e}, /* U+4E11 */ - {0x00e4b892, 0x00f043}, /* U+4E12 [2000] */ - {0x00e4b894, 0x008a8e}, /* U+4E14 */ - {0x00e4b895, 0x0098a1}, /* U+4E15 */ - {0x00e4b896, 0x0090a2}, /* U+4E16 */ - {0x00e4b897, 0x0099c0}, /* U+4E17 */ - {0x00e4b898, 0x008b75}, /* U+4E18 */ - {0x00e4b899, 0x0095b8}, /* U+4E19 */ - {0x00e4b89e, 0x008fe5}, /* U+4E1E */ - {0x00e4b8a1, 0x0097bc}, /* U+4E21 */ - {0x00e4b8a6, 0x0095c0}, /* U+4E26 */ - {0x00e4b8a8, 0x0087a2}, /* U+4E28 [2000] */ - {0x00e4b8a9, 0x00f044}, /* U+4E29 [2000] */ - {0x00e4b8aa, 0x0098a2}, /* U+4E2A */ - {0x00e4b8ab, 0x00f045}, /* U+4E2B [2000] */ - {0x00e4b8ac, 0x00f5ac}, /* U+4E2C [2000] */ - {0x00e4b8ad, 0x009286}, /* U+4E2D */ - {0x00e4b8ae, 0x00f046}, /* U+4E2E [2000] */ - {0x00e4b8af, 0x0087a3}, /* U+4E2F [2000] */ - {0x00e4b8b0, 0x0087a4}, /* U+4E30 [2000] */ - {0x00e4b8b1, 0x0098a3}, /* U+4E31 */ - {0x00e4b8b2, 0x008bf8}, /* U+4E32 */ - {0x00e4b8b6, 0x0098a4}, /* U+4E36 */ - {0x00e4b8b8, 0x008adb}, /* U+4E38 */ - {0x00e4b8b9, 0x00924f}, /* U+4E39 */ - {0x00e4b8bb, 0x008ee5}, /* U+4E3B */ - {0x00e4b8bc, 0x0098a5}, /* U+4E3C */ - {0x00e4b8bf, 0x0098a6}, /* U+4E3F */ - {0x00e4b980, 0x00f047}, /* U+4E40 [2000] */ - {0x00e4b982, 0x0098a7}, /* U+4E42 */ - {0x00e4b983, 0x009454}, /* U+4E43 */ - {0x00e4b985, 0x008b76}, /* U+4E45 */ - {0x00e4b987, 0x00f048}, /* U+4E47 [2000] */ - {0x00e4b988, 0x00f049}, /* U+4E48 [2000] */ - {0x00e4b98b, 0x009456}, /* U+4E4B */ - {0x00e4b98d, 0x0093e1}, /* U+4E4D */ - {0x00e4b98e, 0x008cc1}, /* U+4E4E */ - {0x00e4b98f, 0x009652}, /* U+4E4F */ - {0x00e4b991, 0x00f04b}, /* U+4E51 [2000] */ - {0x00e4b995, 0x00e568}, /* U+4E55 */ - {0x00e4b996, 0x0098a8}, /* U+4E56 */ - {0x00e4b997, 0x008fe6}, /* U+4E57 */ - {0x00e4b998, 0x0098a9}, /* U+4E58 */ - {0x00e4b999, 0x0089b3}, /* U+4E59 */ - {0x00e4b99a, 0x00f04e}, /* U+4E5A [2000] */ - {0x00e4b99d, 0x008be3}, /* U+4E5D */ - {0x00e4b99e, 0x008cee}, /* U+4E5E */ - {0x00e4b99f, 0x0096e7}, /* U+4E5F */ - {0x00e4b9a2, 0x009ba4}, /* U+4E62 */ - {0x00e4b9a9, 0x00f04f}, /* U+4E69 [2000] */ - {0x00e4b9b1, 0x009790}, /* U+4E71 */ - {0x00e4b9b3, 0x0093fb}, /* U+4E73 */ - {0x00e4b9be, 0x008aa3}, /* U+4E7E */ - {0x00e4ba80, 0x008b54}, /* U+4E80 */ - {0x00e4ba82, 0x0098aa}, /* U+4E82 */ - {0x00e4ba85, 0x0098ab}, /* U+4E85 */ - {0x00e4ba86, 0x0097b9}, /* U+4E86 */ - {0x00e4ba88, 0x00975c}, /* U+4E88 */ - {0x00e4ba89, 0x009188}, /* U+4E89 */ - {0x00e4ba8a, 0x0098ad}, /* U+4E8A */ - {0x00e4ba8b, 0x008e96}, /* U+4E8B */ - {0x00e4ba8c, 0x0093f1}, /* U+4E8C */ - {0x00e4ba8d, 0x0087a5}, /* U+4E8D [2000] */ - {0x00e4ba8e, 0x0098b0}, /* U+4E8E */ - {0x00e4ba91, 0x00895d}, /* U+4E91 */ - {0x00e4ba92, 0x008cdd}, /* U+4E92 */ - {0x00e4ba94, 0x008cdc}, /* U+4E94 */ - {0x00e4ba95, 0x0088e4}, /* U+4E95 */ - {0x00e4ba98, 0x00986a}, /* U+4E98 */ - {0x00e4ba99, 0x009869}, /* U+4E99 */ - {0x00e4ba9b, 0x008db1}, /* U+4E9B */ - {0x00e4ba9c, 0x00889f}, /* U+4E9C */ - {0x00e4ba9d, 0x00f050}, /* U+4E9D [2000] */ - {0x00e4ba9e, 0x0098b1}, /* U+4E9E */ - {0x00e4ba9f, 0x0098b2}, /* U+4E9F */ - {0x00e4baa0, 0x0098b3}, /* U+4EA0 */ - {0x00e4baa1, 0x009653}, /* U+4EA1 */ - {0x00e4baa2, 0x0098b4}, /* U+4EA2 */ - {0x00e4baa4, 0x008cf0}, /* U+4EA4 */ - {0x00e4baa5, 0x0088e5}, /* U+4EA5 */ - {0x00e4baa6, 0x009692}, /* U+4EA6 */ - {0x00e4baa8, 0x008b9c}, /* U+4EA8 */ - {0x00e4baab, 0x008b9d}, /* U+4EAB */ - {0x00e4baac, 0x008b9e}, /* U+4EAC */ - {0x00e4baad, 0x0092e0}, /* U+4EAD */ - {0x00e4baae, 0x0097ba}, /* U+4EAE */ - {0x00e4bab0, 0x0098b5}, /* U+4EB0 */ - {0x00e4bab3, 0x0098b6}, /* U+4EB3 */ - {0x00e4bab6, 0x0098b7}, /* U+4EB6 */ - {0x00e4bab9, 0x00f053}, /* U+4EB9 [2000] */ - {0x00e4baba, 0x00906c}, /* U+4EBA */ - {0x00e4babb, 0x00f054}, /* U+4EBB [2000] */ - {0x00e4babc, 0x00f056}, /* U+4EBC [2000] */ - {0x00e4bb80, 0x008f59}, /* U+4EC0 */ - {0x00e4bb81, 0x00906d}, /* U+4EC1 */ - {0x00e4bb82, 0x0098bc}, /* U+4EC2 */ - {0x00e4bb83, 0x00f057}, /* U+4EC3 [2000] */ - {0x00e4bb84, 0x0098ba}, /* U+4EC4 */ - {0x00e4bb86, 0x0098bb}, /* U+4EC6 */ - {0x00e4bb87, 0x008b77}, /* U+4EC7 */ - {0x00e4bb88, 0x00f058}, /* U+4EC8 [2000] */ - {0x00e4bb8a, 0x008da1}, /* U+4ECA */ - {0x00e4bb8b, 0x0089ee}, /* U+4ECB */ - {0x00e4bb8d, 0x0098b9}, /* U+4ECD */ - {0x00e4bb8e, 0x0098b8}, /* U+4ECE */ - {0x00e4bb8f, 0x0095a7}, /* U+4ECF */ - {0x00e4bb90, 0x00f059}, /* U+4ED0 [2000] */ - {0x00e4bb94, 0x008e65}, /* U+4ED4 */ - {0x00e4bb95, 0x008e64}, /* U+4ED5 */ - {0x00e4bb96, 0x0091bc}, /* U+4ED6 */ - {0x00e4bb97, 0x0098bd}, /* U+4ED7 */ - {0x00e4bb98, 0x009574}, /* U+4ED8 */ - {0x00e4bb99, 0x0090e5}, /* U+4ED9 */ - {0x00e4bb9a, 0x00f05b}, /* U+4EDA [2000] */ - {0x00e4bb9d, 0x008157}, /* U+4EDD */ - {0x00e4bb9e, 0x0098be}, /* U+4EDE */ - {0x00e4bb9f, 0x0098c0}, /* U+4EDF */ - {0x00e4bba1, 0x0087a6}, /* U+4EE1 [2000] */ - {0x00e4bba3, 0x0091e3}, /* U+4EE3 */ - {0x00e4bba4, 0x0097df}, /* U+4EE4 */ - {0x00e4bba5, 0x0088c8}, /* U+4EE5 */ - {0x00e4bbab, 0x00f05a}, /* U+4EEB [2000] */ - {0x00e4bbad, 0x0098bf}, /* U+4EED */ - {0x00e4bbae, 0x0089bc}, /* U+4EEE */ - {0x00e4bbb0, 0x008bc2}, /* U+4EF0 */ - {0x00e4bbb1, 0x00f05c}, /* U+4EF1 [2000] */ - {0x00e4bbb2, 0x009287}, /* U+4EF2 */ - {0x00e4bbb5, 0x00f05d}, /* U+4EF5 [2000] */ - {0x00e4bbb6, 0x008c8f}, /* U+4EF6 */ - {0x00e4bbb7, 0x0098c1}, /* U+4EF7 */ - {0x00e4bbbb, 0x009443}, /* U+4EFB */ - {0x00e4bbbd, 0x0087a7}, /* U+4EFD [2000] */ - {0x00e4bbbf, 0x0087a8}, /* U+4EFF [2000] */ - {0x00e4bc80, 0x00f05e}, /* U+4F00 [2000] */ - {0x00e4bc81, 0x008ae9}, /* U+4F01 */ - {0x00e4bc83, 0x0087a9}, /* U+4F03 [2000] */ - {0x00e4bc89, 0x0098c2}, /* U+4F09 */ - {0x00e4bc8a, 0x0088c9}, /* U+4F0A */ - {0x00e4bc8b, 0x0087aa}, /* U+4F0B [2000] */ - {0x00e4bc8d, 0x008cde}, /* U+4F0D */ - {0x00e4bc8e, 0x008aea}, /* U+4F0E */ - {0x00e4bc8f, 0x00959a}, /* U+4F0F */ - {0x00e4bc90, 0x0094b0}, /* U+4F10 */ - {0x00e4bc91, 0x008b78}, /* U+4F11 */ - {0x00e4bc96, 0x00f05f}, /* U+4F16 [2000] */ - {0x00e4bc9a, 0x0089ef}, /* U+4F1A */ - {0x00e4bc9c, 0x0098e5}, /* U+4F1C */ - {0x00e4bc9d, 0x009360}, /* U+4F1D */ - {0x00e4bcaf, 0x00948c}, /* U+4F2F */ - {0x00e4bcb0, 0x0098c4}, /* U+4F30 */ - {0x00e4bcb4, 0x0094ba}, /* U+4F34 */ - {0x00e4bcb6, 0x0097e0}, /* U+4F36 */ - {0x00e4bcb7, 0x00f061}, /* U+4F37 [2000] */ - {0x00e4bcb8, 0x00904c}, /* U+4F38 */ - {0x00e4bcba, 0x008e66}, /* U+4F3A */ - {0x00e4bcbc, 0x008e97}, /* U+4F3C */ - {0x00e4bcbd, 0x0089be}, /* U+4F3D */ - {0x00e4bcbe, 0x00f062}, /* U+4F3E [2000] */ - {0x00e4bd83, 0x0092cf}, /* U+4F43 */ - {0x00e4bd86, 0x009241}, /* U+4F46 */ - {0x00e4bd87, 0x0098c8}, /* U+4F47 */ - {0x00e4bd88, 0x0087ac}, /* U+4F48 [2000] */ - {0x00e4bd89, 0x0087ad}, /* U+4F49 [2000] */ - {0x00e4bd8d, 0x0088ca}, /* U+4F4D */ - {0x00e4bd8e, 0x0092e1}, /* U+4F4E */ - {0x00e4bd8f, 0x008f5a}, /* U+4F4F */ - {0x00e4bd90, 0x008db2}, /* U+4F50 */ - {0x00e4bd91, 0x009743}, /* U+4F51 */ - {0x00e4bd93, 0x0091cc}, /* U+4F53 */ - {0x00e4bd94, 0x00f063}, /* U+4F54 [2000] */ - {0x00e4bd95, 0x0089bd}, /* U+4F55 */ - {0x00e4bd96, 0x0087ae}, /* U+4F56 [2000] */ - {0x00e4bd97, 0x0098c7}, /* U+4F57 */ - {0x00e4bd98, 0x00f064}, /* U+4F58 [2000] */ - {0x00e4bd99, 0x00975d}, /* U+4F59 */ - {0x00e4bd9a, 0x0098c3}, /* U+4F5A */ - {0x00e4bd9b, 0x0098c5}, /* U+4F5B */ - {0x00e4bd9c, 0x008dec}, /* U+4F5C */ - {0x00e4bd9d, 0x0098c6}, /* U+4F5D */ - {0x00e4bd9e, 0x009b43}, /* U+4F5E */ - {0x00e4bd9f, 0x0087af}, /* U+4F5F [2000] */ - {0x00e4bda0, 0x0087ab}, /* U+4F60 [2000] */ - {0x00e4bda4, 0x00f060}, /* U+4F64 [2000] */ - {0x00e4bda9, 0x0098ce}, /* U+4F69 */ - {0x00e4bdaa, 0x0087b0}, /* U+4F6A [2000] */ - {0x00e4bdac, 0x0087b1}, /* U+4F6C [2000] */ - {0x00e4bdaf, 0x0098d1}, /* U+4F6F */ - {0x00e4bdb0, 0x0098cf}, /* U+4F70 */ - {0x00e4bdb3, 0x0089c0}, /* U+4F73 */ - {0x00e4bdb5, 0x0095b9}, /* U+4F75 */ - {0x00e4bdb6, 0x0098c9}, /* U+4F76 */ - {0x00e4bdb7, 0x00f066}, /* U+4F77 [2000] */ - {0x00e4bdb8, 0x00f067}, /* U+4F78 [2000] */ - {0x00e4bdba, 0x00f068}, /* U+4F7A [2000] */ - {0x00e4bdbb, 0x0098cd}, /* U+4F7B */ - {0x00e4bdbc, 0x008cf1}, /* U+4F7C */ - {0x00e4bdbd, 0x00f069}, /* U+4F7D [2000] */ - {0x00e4bdbe, 0x0087b2}, /* U+4F7E [2000] */ - {0x00e4bdbf, 0x008e67}, /* U+4F7F */ - {0x00e4be82, 0x00f06a}, /* U+4F82 [2000] */ - {0x00e4be83, 0x008aa4}, /* U+4F83 */ - {0x00e4be85, 0x00f06b}, /* U+4F85 [2000] */ - {0x00e4be86, 0x0098d2}, /* U+4F86 */ - {0x00e4be88, 0x0098ca}, /* U+4F88 */ - {0x00e4be8a, 0x0087b3}, /* U+4F8A [2000] */ - {0x00e4be8b, 0x0097e1}, /* U+4F8B */ - {0x00e4be8d, 0x008e98}, /* U+4F8D */ - {0x00e4be8f, 0x0098cb}, /* U+4F8F */ - {0x00e4be91, 0x0098d0}, /* U+4F91 */ - {0x00e4be92, 0x00f06c}, /* U+4F92 [2000] */ - {0x00e4be94, 0x0087b4}, /* U+4F94 [2000] */ - {0x00e4be96, 0x0098d3}, /* U+4F96 */ - {0x00e4be97, 0x0087b5}, /* U+4F97 [2000] */ - {0x00e4be98, 0x0098cc}, /* U+4F98 */ - {0x00e4be9a, 0x00f06d}, /* U+4F9A [2000] */ - {0x00e4be9b, 0x008b9f}, /* U+4F9B */ - {0x00e4be9d, 0x0088cb}, /* U+4F9D */ - {0x00e4bea0, 0x008ba0}, /* U+4FA0 */ - {0x00e4bea1, 0x0089bf}, /* U+4FA1 */ - {0x00e4beab, 0x009b44}, /* U+4FAB */ - {0x00e4bead, 0x009699}, /* U+4FAD */ - {0x00e4beae, 0x00958e}, /* U+4FAE */ - {0x00e4beaf, 0x008cf2}, /* U+4FAF */ - {0x00e4beb2, 0x00f06f}, /* U+4FB2 [2000] */ - {0x00e4beb5, 0x00904e}, /* U+4FB5 */ - {0x00e4beb6, 0x0097b5}, /* U+4FB6 */ - {0x00e4bebe, 0x00f070}, /* U+4FBE [2000] */ - {0x00e4bebf, 0x0095d6}, /* U+4FBF */ - {0x00e4bf82, 0x008c57}, /* U+4FC2 */ - {0x00e4bf83, 0x0091a3}, /* U+4FC3 */ - {0x00e4bf84, 0x0089e2}, /* U+4FC4 */ - {0x00e4bf85, 0x00f071}, /* U+4FC5 [2000] */ - {0x00e4bf89, 0x0087b7}, /* U+4FC9 [2000] */ - {0x00e4bf8a, 0x008f72}, /* U+4FCA */ - {0x00e4bf8b, 0x00f072}, /* U+4FCB [2000] */ - {0x00e4bf8e, 0x0098d7}, /* U+4FCE */ - {0x00e4bf8f, 0x00f073}, /* U+4FCF [2000] */ - {0x00e4bf90, 0x0098dc}, /* U+4FD0 */ - {0x00e4bf91, 0x0098da}, /* U+4FD1 */ - {0x00e4bf92, 0x00f074}, /* U+4FD2 [2000] */ - {0x00e4bf94, 0x0098d5}, /* U+4FD4 */ - {0x00e4bf97, 0x0091ad}, /* U+4FD7 */ - {0x00e4bf98, 0x0098d8}, /* U+4FD8 */ - {0x00e4bf9a, 0x0098db}, /* U+4FDA */ - {0x00e4bf9b, 0x0098d9}, /* U+4FDB */ - {0x00e4bf9d, 0x0095db}, /* U+4FDD */ - {0x00e4bf9f, 0x0098d6}, /* U+4FDF */ - {0x00e4bfa0, 0x0087b8}, /* U+4FE0 [2000] */ - {0x00e4bfa1, 0x00904d}, /* U+4FE1 */ - {0x00e4bfa3, 0x009693}, /* U+4FE3 */ - {0x00e4bfa4, 0x0098dd}, /* U+4FE4 */ - {0x00e4bfa5, 0x0098de}, /* U+4FE5 */ - {0x00e4bfa6, 0x00f06e}, /* U+4FE6 [2000] */ - {0x00e4bfae, 0x008f43}, /* U+4FEE */ - {0x00e4bfaf, 0x0098eb}, /* U+4FEF */ - {0x00e4bfb1, 0x00879f}, /* U+4FF1 [2004] */ - {0x00e4bfb2, 0x00f076}, /* U+4FF2 [2000] */ - {0x00e4bfb3, 0x00946f}, /* U+4FF3 */ - {0x00e4bfb5, 0x009555}, /* U+4FF5 */ - {0x00e4bfb6, 0x0098e6}, /* U+4FF6 */ - {0x00e4bfb8, 0x0095ee}, /* U+4FF8 */ - {0x00e4bfba, 0x0089b4}, /* U+4FFA */ - {0x00e4bfbe, 0x0098ea}, /* U+4FFE */ - {0x00e58080, 0x00f077}, /* U+5000 [2000] */ - {0x00e58081, 0x0087b9}, /* U+5001 [2000] */ - {0x00e58082, 0x0087ba}, /* U+5002 [2000] */ - {0x00e58085, 0x0098e4}, /* U+5005 */ - {0x00e58086, 0x0098ed}, /* U+5006 */ - {0x00e58089, 0x009171}, /* U+5009 */ - {0x00e5808b, 0x008cc2}, /* U+500B */ - {0x00e5808d, 0x00947b}, /* U+500D */ - {0x00e5808e, 0x0087bb}, /* U+500E [2000] */ - {0x00e5808f, 0x00e0c5}, /* U+500F */ - {0x00e58090, 0x00f078}, /* U+5010 [2000] */ - {0x00e58091, 0x0098ec}, /* U+5011 */ - {0x00e58092, 0x00937c}, /* U+5012 */ - {0x00e58093, 0x00f079}, /* U+5013 [2000] */ - {0x00e58094, 0x0098e1}, /* U+5014 */ - {0x00e58096, 0x008cf4}, /* U+5016 */ - {0x00e58098, 0x0087bc}, /* U+5018 [2000] */ - {0x00e58099, 0x008cf3}, /* U+5019 */ - {0x00e5809a, 0x0098df}, /* U+501A */ - {0x00e5809c, 0x00f07a}, /* U+501C [2000] */ - {0x00e5809e, 0x00f07b}, /* U+501E [2000] */ - {0x00e5809f, 0x008ed8}, /* U+501F */ - {0x00e580a1, 0x0098e7}, /* U+5021 */ - {0x00e580a2, 0x00f07c}, /* U+5022 [2000] */ - {0x00e580a3, 0x0095ed}, /* U+5023 */ - {0x00e580a4, 0x00926c}, /* U+5024 */ - {0x00e580a5, 0x0098e3}, /* U+5025 */ - {0x00e580a6, 0x008c91}, /* U+5026 */ - {0x00e580a7, 0x0087bd}, /* U+5027 [2000] */ - {0x00e580a8, 0x0098e0}, /* U+5028 */ - {0x00e580a9, 0x0098e8}, /* U+5029 */ - {0x00e580aa, 0x0098e2}, /* U+502A */ - {0x00e580ab, 0x0097cf}, /* U+502B */ - {0x00e580ac, 0x0098e9}, /* U+502C */ - {0x00e580ad, 0x009860}, /* U+502D */ - {0x00e580ae, 0x0087be}, /* U+502E [2000] */ - {0x00e580b6, 0x008be4}, /* U+5036 */ - {0x00e580b9, 0x008c90}, /* U+5039 */ - {0x00e580bb, 0x0087c0}, /* U+503B [2000] */ - {0x00e58180, 0x0087bf}, /* U+5040 [2000] */ - {0x00e58181, 0x0087c1}, /* U+5041 [2000] */ - {0x00e58182, 0x00f07e}, /* U+5042 [2000] */ - {0x00e58183, 0x0098ee}, /* U+5043 */ - {0x00e58186, 0x00f080}, /* U+5046 [2000] */ - {0x00e58187, 0x0098ef}, /* U+5047 */ - {0x00e58188, 0x0098f3}, /* U+5048 */ - {0x00e58189, 0x0088cc}, /* U+5049 */ - {0x00e5818e, 0x00f081}, /* U+504E [2000] */ - {0x00e5818f, 0x0095ce}, /* U+504F */ - {0x00e58190, 0x0098f2}, /* U+5050 */ - {0x00e58193, 0x00f082}, /* U+5053 [2000] */ - {0x00e58195, 0x0098f1}, /* U+5055 */ - {0x00e58196, 0x0098f5}, /* U+5056 */ - {0x00e58197, 0x00f083}, /* U+5057 [2000] */ - {0x00e5819a, 0x0098f4}, /* U+505A */ - {0x00e5819c, 0x0092e2}, /* U+505C */ - {0x00e581a3, 0x00f084}, /* U+5063 [2000] */ - {0x00e581a5, 0x008c92}, /* U+5065 */ - {0x00e581a6, 0x00f085}, /* U+5066 [2000] */ - {0x00e581aa, 0x00f086}, /* U+506A [2000] */ - {0x00e581ac, 0x0098f6}, /* U+506C */ - {0x00e581b0, 0x00f087}, /* U+5070 [2000] */ - {0x00e581b2, 0x008ec3}, /* U+5072 */ - {0x00e581b4, 0x0091a4}, /* U+5074 */ - {0x00e581b5, 0x0092e3}, /* U+5075 */ - {0x00e581b6, 0x008bf4}, /* U+5076 */ - {0x00e581b8, 0x0098f7}, /* U+5078 */ - {0x00e581bd, 0x008b55}, /* U+507D */ - {0x00e58280, 0x0098f8}, /* U+5080 */ - {0x00e58285, 0x0098fa}, /* U+5085 */ - {0x00e58288, 0x00f089}, /* U+5088 [2000] */ - {0x00e5828d, 0x009654}, /* U+508D */ - {0x00e58291, 0x008c86}, /* U+5091 */ - {0x00e58292, 0x00f08a}, /* U+5092 [2000] */ - {0x00e58293, 0x00f08b}, /* U+5093 [2000] */ - {0x00e58294, 0x0087c2}, /* U+5094 [2000] */ - {0x00e58295, 0x00f08c}, /* U+5095 [2000] */ - {0x00e58296, 0x00f08d}, /* U+5096 [2000] */ - {0x00e58298, 0x008e50}, /* U+5098 */ - {0x00e58299, 0x0094f5}, /* U+5099 */ - {0x00e5829a, 0x0098f9}, /* U+509A */ - {0x00e5829c, 0x00f08e}, /* U+509C [2000] */ - {0x00e582a3, 0x00f088}, /* U+50A3 [2000] */ - {0x00e582aa, 0x00f08f}, /* U+50AA [2000] */ - {0x00e582ac, 0x008dc3}, /* U+50AC */ - {0x00e582ad, 0x009762}, /* U+50AD */ - {0x00e582b1, 0x00f091}, /* U+50B1 [2000] */ - {0x00e582b2, 0x0098fc}, /* U+50B2 */ - {0x00e582b3, 0x009942}, /* U+50B3 */ - {0x00e582b4, 0x0098fb}, /* U+50B4 */ - {0x00e582b5, 0x008dc2}, /* U+50B5 */ - {0x00e582b7, 0x008f9d}, /* U+50B7 */ - {0x00e582ba, 0x00f092}, /* U+50BA [2000] */ - {0x00e582bb, 0x00f093}, /* U+50BB [2000] */ - {0x00e582be, 0x008c58}, /* U+50BE */ - {0x00e58382, 0x009943}, /* U+50C2 */ - {0x00e58384, 0x00f094}, /* U+50C4 [2000] */ - {0x00e58385, 0x008bcd}, /* U+50C5 */ - {0x00e58387, 0x00f095}, /* U+50C7 [2000] */ - {0x00e58389, 0x009940}, /* U+50C9 */ - {0x00e5838a, 0x009941}, /* U+50CA */ - {0x00e5838c, 0x0087c3}, /* U+50CC [2000] */ - {0x00e5838d, 0x0093ad}, /* U+50CD */ - {0x00e5838e, 0x00f098}, /* U+50CE [2000] */ - {0x00e5838f, 0x00919c}, /* U+50CF */ - {0x00e58390, 0x0087c5}, /* U+50D0 [2000] */ - {0x00e58391, 0x008ba1}, /* U+50D1 */ - {0x00e58394, 0x00f09a}, /* U+50D4 [2000] */ - {0x00e58395, 0x00966c}, /* U+50D5 */ - {0x00e58396, 0x009944}, /* U+50D6 */ - {0x00e58399, 0x00f09b}, /* U+50D9 [2000] */ - {0x00e5839a, 0x0097bb}, /* U+50DA */ - {0x00e5839e, 0x009945}, /* U+50DE */ - {0x00e583a1, 0x00f09c}, /* U+50E1 [2000] */ - {0x00e583a3, 0x009948}, /* U+50E3 */ - {0x00e583a5, 0x009946}, /* U+50E5 */ - {0x00e583a6, 0x0087c6}, /* U+50E6 [2000] */ - {0x00e583a7, 0x00916d}, /* U+50E7 */ - {0x00e583a9, 0x00f09d}, /* U+50E9 [2000] */ - {0x00e583ad, 0x009947}, /* U+50ED */ - {0x00e583ae, 0x009949}, /* U+50EE */ - {0x00e583b2, 0x0087c4}, /* U+50F2 [2000] */ - {0x00e583b3, 0x00f096}, /* U+50F3 [2000] */ - {0x00e583b5, 0x00994b}, /* U+50F5 */ - {0x00e583b9, 0x00994a}, /* U+50F9 */ - {0x00e583bb, 0x0095c6}, /* U+50FB */ - {0x00e58480, 0x008b56}, /* U+5100 */ - {0x00e58481, 0x00994d}, /* U+5101 */ - {0x00e58482, 0x00994e}, /* U+5102 */ - {0x00e58483, 0x0087c9}, /* U+5103 [2000] */ - {0x00e58484, 0x0089ad}, /* U+5104 */ - {0x00e58486, 0x0087c8}, /* U+5106 [2000] */ - {0x00e58488, 0x00f140}, /* U+5108 [2000] */ - {0x00e58489, 0x00994c}, /* U+5109 */ - {0x00e5848b, 0x0087ca}, /* U+510B [2000] */ - {0x00e58492, 0x008ef2}, /* U+5112 */ - {0x00e58494, 0x009951}, /* U+5114 */ - {0x00e58495, 0x009950}, /* U+5115 */ - {0x00e58496, 0x00994f}, /* U+5116 */ - {0x00e58497, 0x00f142}, /* U+5117 [2000] */ - {0x00e58498, 0x0098d4}, /* U+5118 */ - {0x00e5849a, 0x009952}, /* U+511A */ - {0x00e5849b, 0x00f143}, /* U+511B [2000] */ - {0x00e5849e, 0x0087cb}, /* U+511E [2000] */ - {0x00e5849f, 0x008f9e}, /* U+511F */ - {0x00e584a1, 0x009953}, /* U+5121 */ - {0x00e584aa, 0x009744}, /* U+512A */ - {0x00e584b2, 0x0096d7}, /* U+5132 */ - {0x00e584b5, 0x0087cc}, /* U+5135 [2000] */ - {0x00e584b7, 0x009955}, /* U+5137 */ - {0x00e584ba, 0x009954}, /* U+513A */ - {0x00e584bb, 0x009957}, /* U+513B */ - {0x00e584bc, 0x009956}, /* U+513C */ - {0x00e584bf, 0x009958}, /* U+513F */ - {0x00e58580, 0x009959}, /* U+5140 */ - {0x00e58581, 0x0088f2}, /* U+5141 */ - {0x00e58583, 0x008cb3}, /* U+5143 */ - {0x00e58584, 0x008c5a}, /* U+5144 */ - {0x00e58585, 0x008f5b}, /* U+5145 */ - {0x00e58586, 0x00929b}, /* U+5146 */ - {0x00e58587, 0x008ba2}, /* U+5147 */ - {0x00e58588, 0x0090e6}, /* U+5148 */ - {0x00e58589, 0x008cf5}, /* U+5149 */ - {0x00e5858a, 0x0087cd}, /* U+514A [2000] */ - {0x00e5858b, 0x008d8e}, /* U+514B */ - {0x00e5858c, 0x00995b}, /* U+514C */ - {0x00e5858d, 0x0096c6}, /* U+514D */ - {0x00e5858e, 0x009365}, /* U+514E */ - {0x00e58590, 0x008e99}, /* U+5150 */ - {0x00e58592, 0x00995a}, /* U+5152 */ - {0x00e58594, 0x00995c}, /* U+5154 */ - {0x00e58595, 0x0087cf}, /* U+5155 [2000] */ - {0x00e58597, 0x0087d0}, /* U+5157 [2000] */ - {0x00e5859a, 0x00937d}, /* U+515A */ - {0x00e5859c, 0x008a95}, /* U+515C */ - {0x00e585a0, 0x00f145}, /* U+5160 [2000] */ - {0x00e585a2, 0x00995d}, /* U+5162 */ - {0x00e585a5, 0x0093fc}, /* U+5165 */ - {0x00e585a8, 0x009153}, /* U+5168 */ - {0x00e585a9, 0x00995f}, /* U+5169 */ - {0x00e585aa, 0x009960}, /* U+516A */ - {0x00e585ab, 0x0094aa}, /* U+516B */ - {0x00e585ac, 0x008cf6}, /* U+516C */ - {0x00e585ad, 0x00985a}, /* U+516D */ - {0x00e585ae, 0x009961}, /* U+516E */ - {0x00e585b1, 0x008ba4}, /* U+5171 */ - {0x00e585b3, 0x00f147}, /* U+5173 [2000] */ - {0x00e585b5, 0x0095ba}, /* U+5175 */ - {0x00e585b6, 0x0091b4}, /* U+5176 */ - {0x00e585b7, 0x008bef}, /* U+5177 */ - {0x00e585b8, 0x009354}, /* U+5178 */ - {0x00e585bb, 0x00f7f2}, /* U+517B [2000] */ - {0x00e585bc, 0x008c93}, /* U+517C */ - {0x00e58680, 0x009962}, /* U+5180 */ - {0x00e58682, 0x009963}, /* U+5182 */ - {0x00e58683, 0x00f148}, /* U+5183 [2000] */ - {0x00e58685, 0x0093e0}, /* U+5185 */ - {0x00e58686, 0x00897e}, /* U+5186 */ - {0x00e58689, 0x009966}, /* U+5189 */ - {0x00e5868a, 0x008dfb}, /* U+518A */ - {0x00e5868b, 0x00f149}, /* U+518B [2000] */ - {0x00e5868c, 0x009965}, /* U+518C */ - {0x00e5868d, 0x008dc4}, /* U+518D */ - {0x00e5868f, 0x009967}, /* U+518F */ - {0x00e58690, 0x00e3ec}, /* U+5190 */ - {0x00e58691, 0x009968}, /* U+5191 */ - {0x00e58692, 0x009660}, /* U+5192 */ - {0x00e58693, 0x009969}, /* U+5193 */ - {0x00e58695, 0x00996a}, /* U+5195 */ - {0x00e58696, 0x00996b}, /* U+5196 */ - {0x00e58697, 0x008fe7}, /* U+5197 */ - {0x00e58698, 0x00f14b}, /* U+5198 [2000] */ - {0x00e58699, 0x008eca}, /* U+5199 */ - {0x00e5869d, 0x0087d2}, /* U+519D [2000] */ - {0x00e586a0, 0x008aa5}, /* U+51A0 */ - {0x00e586a2, 0x00996e}, /* U+51A2 */ - {0x00e586a3, 0x00f14c}, /* U+51A3 [2000] */ - {0x00e586a4, 0x00996c}, /* U+51A4 */ - {0x00e586a5, 0x0096bb}, /* U+51A5 */ - {0x00e586a6, 0x00996d}, /* U+51A6 */ - {0x00e586a8, 0x009579}, /* U+51A8 */ - {0x00e586a9, 0x00996f}, /* U+51A9 */ - {0x00e586aa, 0x009970}, /* U+51AA */ - {0x00e586ab, 0x009971}, /* U+51AB */ - {0x00e586ac, 0x00937e}, /* U+51AC */ - {0x00e586ad, 0x00f14d}, /* U+51AD [2000] */ - {0x00e586b0, 0x009975}, /* U+51B0 */ - {0x00e586b1, 0x009973}, /* U+51B1 */ - {0x00e586b2, 0x009974}, /* U+51B2 */ - {0x00e586b3, 0x009972}, /* U+51B3 */ - {0x00e586b4, 0x008de1}, /* U+51B4 */ - {0x00e586b5, 0x009976}, /* U+51B5 */ - {0x00e586b6, 0x0096e8}, /* U+51B6 */ - {0x00e586b7, 0x0097e2}, /* U+51B7 */ - {0x00e586bc, 0x00f14f}, /* U+51BC [2000] */ - {0x00e586bd, 0x009977}, /* U+51BD */ - {0x00e58783, 0x0087d3}, /* U+51C3 [2000] */ - {0x00e58784, 0x0090a6}, /* U+51C4 */ - {0x00e58785, 0x009978}, /* U+51C5 */ - {0x00e58786, 0x008f79}, /* U+51C6 */ - {0x00e58789, 0x009979}, /* U+51C9 */ - {0x00e5878a, 0x0087d4}, /* U+51CA [2000] */ - {0x00e5878b, 0x00929c}, /* U+51CB */ - {0x00e5878c, 0x0097bd}, /* U+51CC */ - {0x00e5878d, 0x009380}, /* U+51CD */ - {0x00e58796, 0x0099c3}, /* U+51D6 */ - {0x00e5879b, 0x00997a}, /* U+51DB */ - {0x00e5879c, 0x00eaa3}, /* U+51DC [1990] */ - {0x00e5879d, 0x008bc3}, /* U+51DD */ - {0x00e5879e, 0x0087d5}, /* U+51DE [2000] */ - {0x00e587a0, 0x00997b}, /* U+51E0 */ - {0x00e587a1, 0x00967d}, /* U+51E1 */ - {0x00e587a2, 0x0087d6}, /* U+51E2 [2000] */ - {0x00e587a6, 0x008f88}, /* U+51E6 */ - {0x00e587a7, 0x0091fa}, /* U+51E7 */ - {0x00e587a9, 0x00997d}, /* U+51E9 */ - {0x00e587aa, 0x0093e2}, /* U+51EA */ - {0x00e587ad, 0x00997e}, /* U+51ED */ - {0x00e587ae, 0x0087d7}, /* U+51EE [2000] */ - {0x00e587b0, 0x009980}, /* U+51F0 */ - {0x00e587b1, 0x008a4d}, /* U+51F1 */ - {0x00e587b3, 0x00f152}, /* U+51F3 [2000] */ - {0x00e587b4, 0x00f153}, /* U+51F4 [2000] */ - {0x00e587b5, 0x009981}, /* U+51F5 */ - {0x00e587b6, 0x008ba5}, /* U+51F6 */ - {0x00e587b8, 0x0093ca}, /* U+51F8 */ - {0x00e587b9, 0x00899a}, /* U+51F9 */ - {0x00e587ba, 0x008f6f}, /* U+51FA */ - {0x00e587bd, 0x00949f}, /* U+51FD */ - {0x00e587be, 0x009982}, /* U+51FE */ - {0x00e58880, 0x009381}, /* U+5200 */ - {0x00e58881, 0x0087d8}, /* U+5201 [2000] */ - {0x00e58882, 0x00f154}, /* U+5202 [2000] */ - {0x00e58883, 0x00906e}, /* U+5203 */ - {0x00e58884, 0x009983}, /* U+5204 */ - {0x00e58886, 0x0095aa}, /* U+5206 */ - {0x00e58887, 0x0090d8}, /* U+5207 */ - {0x00e58888, 0x008aa0}, /* U+5208 */ - {0x00e5888a, 0x008aa7}, /* U+520A */ - {0x00e5888b, 0x009984}, /* U+520B */ - {0x00e5888e, 0x009986}, /* U+520E */ - {0x00e58891, 0x008c59}, /* U+5211 */ - {0x00e58892, 0x00f155}, /* U+5212 [2000] */ - {0x00e58893, 0x0087da}, /* U+5213 [2000] */ - {0x00e58894, 0x009985}, /* U+5214 */ - {0x00e58895, 0x0087db}, /* U+5215 [2000] */ - {0x00e58896, 0x00f156}, /* U+5216 [2000] */ - {0x00e58897, 0x0097f1}, /* U+5217 */ - {0x00e5889d, 0x008f89}, /* U+521D */ - {0x00e588a4, 0x0094bb}, /* U+5224 */ - {0x00e588a5, 0x0095ca}, /* U+5225 */ - {0x00e588a7, 0x009987}, /* U+5227 */ - {0x00e588a9, 0x009798}, /* U+5229 */ - {0x00e588aa, 0x009988}, /* U+522A */ - {0x00e588ae, 0x009989}, /* U+522E */ - {0x00e588b0, 0x00939e}, /* U+5230 */ - {0x00e588b3, 0x00998a}, /* U+5233 */ - {0x00e588b6, 0x0090a7}, /* U+5236 */ - {0x00e588b7, 0x008dfc}, /* U+5237 */ - {0x00e588b8, 0x008c94}, /* U+5238 */ - {0x00e588b9, 0x00998b}, /* U+5239 */ - {0x00e588ba, 0x008e68}, /* U+523A */ - {0x00e588bb, 0x008d8f}, /* U+523B */ - {0x00e58983, 0x0092e4}, /* U+5243 */ - {0x00e58984, 0x00998d}, /* U+5244 */ - {0x00e58987, 0x0091a5}, /* U+5247 */ - {0x00e58989, 0x0087dc}, /* U+5249 [2000] */ - {0x00e5898a, 0x008ded}, /* U+524A */ - {0x00e5898b, 0x00998e}, /* U+524B */ - {0x00e5898c, 0x00998f}, /* U+524C */ - {0x00e5898d, 0x00914f}, /* U+524D */ - {0x00e5898f, 0x00998c}, /* U+524F */ - {0x00e58994, 0x009991}, /* U+5254 */ - {0x00e58995, 0x00f158}, /* U+5255 [2000] */ - {0x00e58996, 0x009655}, /* U+5256 */ - {0x00e58997, 0x0087dd}, /* U+5257 [2000] */ - {0x00e5899b, 0x008d84}, /* U+525B */ - {0x00e5899c, 0x00f159}, /* U+525C [2000] */ - {0x00e5899d, 0x00889e}, /* U+525D [2004] */ - {0x00e5899e, 0x009990}, /* U+525E */ - {0x00e589a1, 0x0087de}, /* U+5261 [2000] */ - {0x00e589a3, 0x008c95}, /* U+5263 */ - {0x00e589a4, 0x008ddc}, /* U+5264 */ - {0x00e589a5, 0x00948d}, /* U+5265 */ - {0x00e589a9, 0x009994}, /* U+5269 */ - {0x00e589aa, 0x009992}, /* U+526A */ - {0x00e589ac, 0x00f15a}, /* U+526C [2000] */ - {0x00e589af, 0x00959b}, /* U+526F */ - {0x00e589b0, 0x008fe8}, /* U+5270 */ - {0x00e589b1, 0x00999b}, /* U+5271 */ - {0x00e589b2, 0x008a84}, /* U+5272 */ - {0x00e589b3, 0x009995}, /* U+5273 */ - {0x00e589b4, 0x009993}, /* U+5274 */ - {0x00e589b5, 0x00916e}, /* U+5275 */ - {0x00e589b7, 0x00f15b}, /* U+5277 [2000] */ - {0x00e589bd, 0x009997}, /* U+527D */ - {0x00e589bf, 0x009996}, /* U+527F */ - {0x00e58a82, 0x00f15d}, /* U+5282 [2000] */ - {0x00e58a83, 0x008a63}, /* U+5283 */ - {0x00e58a84, 0x00f15c}, /* U+5284 [2000] */ - {0x00e58a87, 0x008c80}, /* U+5287 */ - {0x00e58a88, 0x00999c}, /* U+5288 */ - {0x00e58a89, 0x0097ab}, /* U+5289 */ - {0x00e58a8d, 0x009998}, /* U+528D */ - {0x00e58a91, 0x00999d}, /* U+5291 */ - {0x00e58a92, 0x00999a}, /* U+5292 */ - {0x00e58a93, 0x0087df}, /* U+5293 [2000] */ - {0x00e58a94, 0x009999}, /* U+5294 */ - {0x00e58a98, 0x00f15f}, /* U+5298 [2000] */ - {0x00e58a9b, 0x0097cd}, /* U+529B */ - {0x00e58a9f, 0x008cf7}, /* U+529F */ - {0x00e58aa0, 0x0089c1}, /* U+52A0 */ - {0x00e58aa3, 0x0097f2}, /* U+52A3 */ - {0x00e58aa4, 0x00f161}, /* U+52A4 [2000] */ - {0x00e58aa6, 0x00f162}, /* U+52A6 [2000] */ - {0x00e58aa9, 0x008f95}, /* U+52A9 */ - {0x00e58aaa, 0x009377}, /* U+52AA */ - {0x00e58aab, 0x008d85}, /* U+52AB */ - {0x00e58aac, 0x0099a0}, /* U+52AC */ - {0x00e58aad, 0x0099a1}, /* U+52AD */ - {0x00e58aaf, 0x00f163}, /* U+52AF [2000] */ - {0x00e58ab1, 0x0097e3}, /* U+52B1 */ - {0x00e58ab4, 0x00984a}, /* U+52B4 */ - {0x00e58ab5, 0x0099a3}, /* U+52B5 */ - {0x00e58ab9, 0x008cf8}, /* U+52B9 */ - {0x00e58aba, 0x00f164}, /* U+52BA [2000] */ - {0x00e58abb, 0x00f165}, /* U+52BB [2000] */ - {0x00e58abc, 0x0099a2}, /* U+52BC */ - {0x00e58abe, 0x008a4e}, /* U+52BE */ - {0x00e58b81, 0x0099a4}, /* U+52C1 */ - {0x00e58b83, 0x009675}, /* U+52C3 */ - {0x00e58b85, 0x0092ba}, /* U+52C5 */ - {0x00e58b87, 0x009745}, /* U+52C7 */ - {0x00e58b88, 0x0087e0}, /* U+52C8 [2000] */ - {0x00e58b89, 0x0095d7}, /* U+52C9 */ - {0x00e58b8a, 0x00f166}, /* U+52CA [2000] */ - {0x00e58b8c, 0x0087e2}, /* U+52CC [2000] */ - {0x00e58b8d, 0x0099a5}, /* U+52CD */ - {0x00e58b90, 0x0087e3}, /* U+52D0 [2000] */ - {0x00e58b91, 0x00f168}, /* U+52D1 [2000] */ - {0x00e58b92, 0x00e8d3}, /* U+52D2 */ - {0x00e58b95, 0x0093ae}, /* U+52D5 */ - {0x00e58b96, 0x0087e4}, /* U+52D6 [2000] */ - {0x00e58b97, 0x0099a6}, /* U+52D7 */ - {0x00e58b98, 0x008aa8}, /* U+52D8 */ - {0x00e58b99, 0x0096b1}, /* U+52D9 */ - {0x00e58b9b, 0x0087e5}, /* U+52DB [2000] */ - {0x00e58b9d, 0x008f9f}, /* U+52DD */ - {0x00e58b9e, 0x0099a7}, /* U+52DE */ - {0x00e58b9f, 0x0095e5}, /* U+52DF */ - {0x00e58ba0, 0x0099ab}, /* U+52E0 */ - {0x00e58ba2, 0x0090a8}, /* U+52E2 */ - {0x00e58ba3, 0x0099a8}, /* U+52E3 */ - {0x00e58ba4, 0x008bce}, /* U+52E4 */ - {0x00e58ba6, 0x0099a9}, /* U+52E6 */ - {0x00e58ba7, 0x008aa9}, /* U+52E7 */ - {0x00e58bb0, 0x0087e7}, /* U+52F0 [2000] */ - {0x00e58bb2, 0x008c4d}, /* U+52F2 */ - {0x00e58bb3, 0x0099ac}, /* U+52F3 */ - {0x00e58bb5, 0x0099ad}, /* U+52F5 */ - {0x00e58bb7, 0x00f16a}, /* U+52F7 [2000] */ - {0x00e58bb8, 0x0099ae}, /* U+52F8 */ - {0x00e58bb9, 0x0099af}, /* U+52F9 */ - {0x00e58bba, 0x008ed9}, /* U+52FA */ - {0x00e58bbb, 0x0087e8}, /* U+52FB [2000] */ - {0x00e58bbe, 0x008cf9}, /* U+52FE */ - {0x00e58bbf, 0x0096dc}, /* U+52FF */ - {0x00e58c80, 0x0087e9}, /* U+5300 [2000] */ - {0x00e58c81, 0x0096e6}, /* U+5301 */ - {0x00e58c82, 0x0093f5}, /* U+5302 */ - {0x00e58c85, 0x0095ef}, /* U+5305 */ - {0x00e58c86, 0x0099b0}, /* U+5306 */ - {0x00e58c87, 0x0087ea}, /* U+5307 [2000] */ - {0x00e58c88, 0x0099b1}, /* U+5308 */ - {0x00e58c8a, 0x00f16b}, /* U+530A [2000] */ - {0x00e58c8b, 0x00f16c}, /* U+530B [2000] */ - {0x00e58c8d, 0x0099b3}, /* U+530D */ - {0x00e58c8f, 0x0099b5}, /* U+530F */ - {0x00e58c90, 0x0099b4}, /* U+5310 */ - {0x00e58c95, 0x0099b6}, /* U+5315 */ - {0x00e58c96, 0x0089bb}, /* U+5316 */ - {0x00e58c97, 0x00966b}, /* U+5317 */ - {0x00e58c99, 0x008dfa}, /* U+5319 */ - {0x00e58c9a, 0x0099b7}, /* U+531A */ - {0x00e58c9c, 0x0087eb}, /* U+531C [2000] */ - {0x00e58c9d, 0x009178}, /* U+531D */ - {0x00e58ca0, 0x008fa0}, /* U+5320 */ - {0x00e58ca1, 0x008ba7}, /* U+5321 */ - {0x00e58ca3, 0x0099b8}, /* U+5323 */ - {0x00e58ca4, 0x00f16d}, /* U+5324 [2000] */ - {0x00e58caa, 0x0094d9}, /* U+532A */ - {0x00e58caf, 0x0099b9}, /* U+532F */ - {0x00e58cb1, 0x0099ba}, /* U+5331 */ - {0x00e58cb3, 0x0099bb}, /* U+5333 */ - {0x00e58cb5, 0x00f16e}, /* U+5335 [2000] */ - {0x00e58cb8, 0x0099bc}, /* U+5338 */ - {0x00e58cb9, 0x009543}, /* U+5339 */ - {0x00e58cba, 0x008be6}, /* U+533A */ - {0x00e58cbb, 0x0088e3}, /* U+533B */ - {0x00e58cbe, 0x00f16f}, /* U+533E [2000] */ - {0x00e58cbf, 0x0093bd}, /* U+533F */ - {0x00e58d80, 0x0099bd}, /* U+5340 */ - {0x00e58d81, 0x008f5c}, /* U+5341 */ - {0x00e58d82, 0x00f170}, /* U+5342 [2000] */ - {0x00e58d83, 0x0090e7}, /* U+5343 */ - {0x00e58d85, 0x0099bf}, /* U+5345 */ - {0x00e58d86, 0x0099be}, /* U+5346 */ - {0x00e58d87, 0x008fa1}, /* U+5347 */ - {0x00e58d88, 0x008cdf}, /* U+5348 */ - {0x00e58d89, 0x0099c1}, /* U+5349 */ - {0x00e58d8a, 0x0094bc}, /* U+534A */ - {0x00e58d8d, 0x0099c2}, /* U+534D */ - {0x00e58d91, 0x0094da}, /* U+5351 */ - {0x00e58d92, 0x0091b2}, /* U+5352 */ - {0x00e58d93, 0x0091ec}, /* U+5353 */ - {0x00e58d94, 0x008ba6}, /* U+5354 */ - {0x00e58d97, 0x0093ec}, /* U+5357 */ - {0x00e58d98, 0x009250}, /* U+5358 */ - {0x00e58d9a, 0x00948e}, /* U+535A */ - {0x00e58d9c, 0x00966d}, /* U+535C */ - {0x00e58d9e, 0x0099c4}, /* U+535E */ - {0x00e58da0, 0x0090e8}, /* U+5360 */ - {0x00e58da1, 0x0087ed}, /* U+5361 [2000] */ - {0x00e58da3, 0x0087ee}, /* U+5363 [2000] */ - {0x00e58da6, 0x008c54}, /* U+5366 */ - {0x00e58da7, 0x00f173}, /* U+5367 [2000] */ - {0x00e58da9, 0x0099c5}, /* U+5369 */ - {0x00e58dac, 0x00f174}, /* U+536C [2000] */ - {0x00e58dae, 0x0099c6}, /* U+536E */ - {0x00e58daf, 0x00894b}, /* U+536F */ - {0x00e58db0, 0x0088f3}, /* U+5370 */ - {0x00e58db1, 0x008aeb}, /* U+5371 */ - {0x00e58db3, 0x0091a6}, /* U+5373 */ - {0x00e58db4, 0x008b70}, /* U+5374 */ - {0x00e58db5, 0x009791}, /* U+5375 */ - {0x00e58db7, 0x0099c9}, /* U+5377 */ - {0x00e58db8, 0x0089b5}, /* U+5378 */ - {0x00e58dba, 0x00f175}, /* U+537A [2000] */ - {0x00e58dbb, 0x0099c8}, /* U+537B */ - {0x00e58dbd, 0x0087ef}, /* U+537D [2000] */ - {0x00e58dbf, 0x008ba8}, /* U+537F */ - {0x00e58e82, 0x0099ca}, /* U+5382 */ - {0x00e58e84, 0x0096ef}, /* U+5384 */ - {0x00e58e93, 0x0087f0}, /* U+5393 [2000] */ - {0x00e58e96, 0x0099cb}, /* U+5396 */ - {0x00e58e98, 0x0097d0}, /* U+5398 */ - {0x00e58e9a, 0x008cfa}, /* U+539A */ - {0x00e58e9d, 0x0087f1}, /* U+539D [2000] */ - {0x00e58e9f, 0x008cb4}, /* U+539F */ - {0x00e58ea0, 0x0099cc}, /* U+53A0 */ - {0x00e58ea4, 0x00f176}, /* U+53A4 [2000] */ - {0x00e58ea5, 0x0099ce}, /* U+53A5 */ - {0x00e58ea6, 0x0099cd}, /* U+53A6 */ - {0x00e58ea8, 0x00907e}, /* U+53A8 */ - {0x00e58ea9, 0x008958}, /* U+53A9 */ - {0x00e58ead, 0x00897d}, /* U+53AD */ - {0x00e58eae, 0x0099cf}, /* U+53AE */ - {0x00e58eb0, 0x0099d0}, /* U+53B0 */ - {0x00e58eb2, 0x0087f2}, /* U+53B2 [2000] */ - {0x00e58eb3, 0x008cb5}, /* U+53B3 */ - {0x00e58eb4, 0x00f177}, /* U+53B4 [2000] */ - {0x00e58eb6, 0x0099d1}, /* U+53B6 */ - {0x00e58eb7, 0x00f179}, /* U+53B7 [2000] */ - {0x00e58ebb, 0x008b8e}, /* U+53BB */ - {0x00e58f80, 0x00f17a}, /* U+53C0 [2000] */ - {0x00e58f82, 0x008e51}, /* U+53C2 */ - {0x00e58f83, 0x0099d2}, /* U+53C3 */ - {0x00e58f88, 0x009694}, /* U+53C8 */ - {0x00e58f89, 0x008db3}, /* U+53C9 */ - {0x00e58f8a, 0x008b79}, /* U+53CA */ - {0x00e58f8b, 0x009746}, /* U+53CB */ - {0x00e58f8c, 0x00916f}, /* U+53CC */ - {0x00e58f8d, 0x0094bd}, /* U+53CD */ - {0x00e58f8e, 0x008efb}, /* U+53CE */ - {0x00e58f94, 0x008f66}, /* U+53D4 */ - {0x00e58f95, 0x00f17e}, /* U+53D5 [2000] */ - {0x00e58f96, 0x008ee6}, /* U+53D6 */ - {0x00e58f97, 0x008ef3}, /* U+53D7 */ - {0x00e58f99, 0x008f96}, /* U+53D9 */ - {0x00e58f9a, 0x00f180}, /* U+53DA [2000] */ - {0x00e58f9b, 0x0094be}, /* U+53DB */ - {0x00e58f9f, 0x0099d5}, /* U+53DF */ - {0x00e58fa1, 0x008962}, /* U+53E1 */ - {0x00e58fa2, 0x009170}, /* U+53E2 */ - {0x00e58fa3, 0x008cfb}, /* U+53E3 */ - {0x00e58fa4, 0x008cc3}, /* U+53E4 */ - {0x00e58fa5, 0x008be5}, /* U+53E5 */ - {0x00e58fa8, 0x0099d9}, /* U+53E8 */ - {0x00e58fa9, 0x009240}, /* U+53E9 */ - {0x00e58faa, 0x0091fc}, /* U+53EA */ - {0x00e58fab, 0x008ba9}, /* U+53EB */ - {0x00e58fac, 0x008fa2}, /* U+53EC */ - {0x00e58fad, 0x0099da}, /* U+53ED */ - {0x00e58fae, 0x0099d8}, /* U+53EE */ - {0x00e58faf, 0x0089c2}, /* U+53EF */ - {0x00e58fb0, 0x0091e4}, /* U+53F0 */ - {0x00e58fb1, 0x008eb6}, /* U+53F1 */ - {0x00e58fb2, 0x008e6a}, /* U+53F2 */ - {0x00e58fb3, 0x008945}, /* U+53F3 */ - {0x00e58fb4, 0x00f182}, /* U+53F4 [2000] */ - {0x00e58fb5, 0x00f183}, /* U+53F5 [2000] */ - {0x00e58fb6, 0x008a90}, /* U+53F6 */ - {0x00e58fb7, 0x008d86}, /* U+53F7 */ - {0x00e58fb8, 0x008e69}, /* U+53F8 */ - {0x00e58fba, 0x0099db}, /* U+53FA */ - {0x00e59081, 0x0099dc}, /* U+5401 */ - {0x00e59083, 0x008b68}, /* U+5403 */ - {0x00e59084, 0x008a65}, /* U+5404 */ - {0x00e59088, 0x008d87}, /* U+5408 */ - {0x00e59089, 0x008b67}, /* U+5409 */ - {0x00e5908a, 0x0092dd}, /* U+540A */ - {0x00e5908b, 0x008944}, /* U+540B */ - {0x00e5908c, 0x0093af}, /* U+540C */ - {0x00e5908d, 0x0096bc}, /* U+540D */ - {0x00e5908e, 0x008d40}, /* U+540E */ - {0x00e5908f, 0x009799}, /* U+540F */ - {0x00e59090, 0x009366}, /* U+5410 */ - {0x00e59091, 0x008cfc}, /* U+5411 */ - {0x00e59092, 0x0087f3}, /* U+5412 [2000] */ - {0x00e5909b, 0x008c4e}, /* U+541B */ - {0x00e5909d, 0x0099e5}, /* U+541D */ - {0x00e5909e, 0x00989e}, /* U+541E [2004] */ - {0x00e5909f, 0x008be1}, /* U+541F */ - {0x00e590a0, 0x009669}, /* U+5420 */ - {0x00e590a4, 0x00f185}, /* U+5424 [2000] */ - {0x00e590a6, 0x0094db}, /* U+5426 */ - {0x00e590a7, 0x0087f4}, /* U+5427 [2000] */ - {0x00e590a8, 0x00f186}, /* U+5428 [2000] */ - {0x00e590a9, 0x0099e4}, /* U+5429 */ - {0x00e590ab, 0x008adc}, /* U+542B */ - {0x00e590ac, 0x0099df}, /* U+542C */ - {0x00e590ad, 0x0099e0}, /* U+542D */ - {0x00e590ae, 0x0099e2}, /* U+542E */ - {0x00e590b6, 0x0099e3}, /* U+5436 */ - {0x00e590b8, 0x008b7a}, /* U+5438 */ - {0x00e590b9, 0x009081}, /* U+5439 */ - {0x00e590bb, 0x0095ab}, /* U+543B */ - {0x00e590bc, 0x0099e1}, /* U+543C */ - {0x00e590bd, 0x0099dd}, /* U+543D */ - {0x00e590be, 0x008ce1}, /* U+543E */ - {0x00e59180, 0x0099de}, /* U+5440 */ - {0x00e59182, 0x009843}, /* U+5442 */ - {0x00e59183, 0x00f188}, /* U+5443 [2000] */ - {0x00e59186, 0x0095f0}, /* U+5446 */ - {0x00e59188, 0x0092e6}, /* U+5448 */ - {0x00e59189, 0x008ce0}, /* U+5449 */ - {0x00e5918a, 0x008d90}, /* U+544A */ - {0x00e5918d, 0x0087f5}, /* U+544D [2000] */ - {0x00e5918e, 0x0099e6}, /* U+544E */ - {0x00e59191, 0x0093db}, /* U+5451 */ - {0x00e59195, 0x00f184}, /* U+5455 [2000] */ - {0x00e5919f, 0x0099ea}, /* U+545F */ - {0x00e591a2, 0x00f189}, /* U+5462 [2000] */ - {0x00e591a6, 0x00f18a}, /* U+5466 [2000] */ - {0x00e591a8, 0x008efc}, /* U+5468 */ - {0x00e591aa, 0x008ef4}, /* U+546A */ - {0x00e591ab, 0x0087f7}, /* U+546B [2000] */ - {0x00e591ac, 0x00f18b}, /* U+546C [2000] */ - {0x00e591b0, 0x0099ed}, /* U+5470 */ - {0x00e591b1, 0x0099eb}, /* U+5471 */ - {0x00e591b3, 0x0096a1}, /* U+5473 */ - {0x00e591b4, 0x0087f8}, /* U+5474 [2000] */ - {0x00e591b5, 0x0099e8}, /* U+5475 */ - {0x00e591b6, 0x0099f1}, /* U+5476 */ - {0x00e591b7, 0x0099ec}, /* U+5477 */ - {0x00e591bb, 0x0099ef}, /* U+547B */ - {0x00e591bc, 0x008cc4}, /* U+547C */ - {0x00e591bd, 0x0096bd}, /* U+547D */ - {0x00e591bf, 0x0087f9}, /* U+547F [2000] */ - {0x00e59280, 0x0099f0}, /* U+5480 */ - {0x00e59284, 0x0099f2}, /* U+5484 */ - {0x00e59286, 0x0099f4}, /* U+5486 */ - {0x00e59288, 0x0087fa}, /* U+5488 [2000] */ - {0x00e5928a, 0x00f18c}, /* U+548A [2000] */ - {0x00e5928b, 0x008dee}, /* U+548B */ - {0x00e5928c, 0x009861}, /* U+548C */ - {0x00e5928d, 0x00f18d}, /* U+548D [2000] */ - {0x00e5928e, 0x0099e9}, /* U+548E */ - {0x00e5928f, 0x0099e7}, /* U+548F */ - {0x00e59290, 0x0099f3}, /* U+5490 */ - {0x00e59292, 0x0099ee}, /* U+5492 */ - {0x00e59295, 0x00f18e}, /* U+5495 [2000] */ - {0x00e59296, 0x0087fb}, /* U+5496 [2000] */ - {0x00e5929c, 0x0087f6}, /* U+549C [2000] */ - {0x00e592a0, 0x00f18f}, /* U+54A0 [2000] */ - {0x00e592a1, 0x0087fc}, /* U+54A1 [2000] */ - {0x00e592a2, 0x0099f6}, /* U+54A2 */ - {0x00e592a4, 0x009a42}, /* U+54A4 */ - {0x00e592a5, 0x0099f8}, /* U+54A5 */ - {0x00e592a6, 0x00f190}, /* U+54A6 [2000] */ - {0x00e592a8, 0x0099fc}, /* U+54A8 */ - {0x00e592a9, 0x008840}, /* U+54A9 [2000] */ - {0x00e592ab, 0x009a40}, /* U+54AB */ - {0x00e592ac, 0x0099f9}, /* U+54AC */ - {0x00e592ad, 0x00f191}, /* U+54AD [2000] */ - {0x00e592ae, 0x00f192}, /* U+54AE [2000] */ - {0x00e592af, 0x009a5d}, /* U+54AF */ - {0x00e592b2, 0x008de7}, /* U+54B2 */ - {0x00e592b3, 0x008a50}, /* U+54B3 */ - {0x00e592b7, 0x00f193}, /* U+54B7 [2000] */ - {0x00e592b8, 0x0099f7}, /* U+54B8 */ - {0x00e592ba, 0x00f194}, /* U+54BA [2000] */ - {0x00e592bc, 0x009a44}, /* U+54BC */ - {0x00e592bd, 0x0088f4}, /* U+54BD */ - {0x00e592be, 0x009a43}, /* U+54BE */ - {0x00e592bf, 0x00f195}, /* U+54BF [2000] */ - {0x00e59380, 0x0088a3}, /* U+54C0 */ - {0x00e59381, 0x009569}, /* U+54C1 */ - {0x00e59382, 0x009a41}, /* U+54C2 */ - {0x00e59383, 0x00f196}, /* U+54C3 [2000] */ - {0x00e59384, 0x0099fa}, /* U+54C4 */ - {0x00e59386, 0x008841}, /* U+54C6 [2000] */ - {0x00e59387, 0x0099f5}, /* U+54C7 */ - {0x00e59388, 0x0099fb}, /* U+54C8 */ - {0x00e59389, 0x008dc6}, /* U+54C9 */ - {0x00e59398, 0x009a45}, /* U+54D8 */ - {0x00e593a1, 0x0088f5}, /* U+54E1 */ - {0x00e593a2, 0x009a4e}, /* U+54E2 */ - {0x00e593a5, 0x009a46}, /* U+54E5 */ - {0x00e593a6, 0x009a47}, /* U+54E6 */ - {0x00e593a8, 0x008fa3}, /* U+54E8 */ - {0x00e593a9, 0x009689}, /* U+54E9 */ - {0x00e593ac, 0x00f198}, /* U+54EC [2000] */ - {0x00e593ad, 0x009a4c}, /* U+54ED */ - {0x00e593ae, 0x009a4b}, /* U+54EE */ - {0x00e593af, 0x00f199}, /* U+54EF [2000] */ - {0x00e593b1, 0x00f19a}, /* U+54F1 [2000] */ - {0x00e593b2, 0x00934e}, /* U+54F2 */ - {0x00e593b3, 0x00f19b}, /* U+54F3 [2000] */ - {0x00e593ba, 0x009a4d}, /* U+54FA */ - {0x00e593bd, 0x009a4a}, /* U+54FD */ - {0x00e593bf, 0x008842}, /* U+54FF [2000] */ - {0x00e59480, 0x00f19c}, /* U+5500 [2000] */ - {0x00e59481, 0x00f19d}, /* U+5501 [2000] */ - {0x00e59484, 0x008953}, /* U+5504 */ - {0x00e59486, 0x008db4}, /* U+5506 */ - {0x00e59487, 0x00904f}, /* U+5507 */ - {0x00e59489, 0x00f19e}, /* U+5509 [2000] */ - {0x00e5948e, 0x008843}, /* U+550E [2000] */ - {0x00e5948f, 0x009a48}, /* U+550F */ - {0x00e59490, 0x009382}, /* U+5510 */ - {0x00e59494, 0x009a49}, /* U+5514 */ - {0x00e59496, 0x0088a0}, /* U+5516 */ - {0x00e594ab, 0x008844}, /* U+552B [2000] */ - {0x00e594ae, 0x009a53}, /* U+552E */ - {0x00e594af, 0x009742}, /* U+552F */ - {0x00e594b1, 0x008fa5}, /* U+5531 */ - {0x00e594b3, 0x009a59}, /* U+5533 */ - {0x00e594b5, 0x008845}, /* U+5535 [2000] */ - {0x00e594b8, 0x009a58}, /* U+5538 */ - {0x00e594b9, 0x009a4f}, /* U+5539 */ - {0x00e594bc, 0x00f19f}, /* U+553C [2000] */ - {0x00e594be, 0x0091c1}, /* U+553E */ - {0x00e59580, 0x009a50}, /* U+5540 */ - {0x00e59581, 0x00f1a0}, /* U+5541 [2000] */ - {0x00e59584, 0x0091ed}, /* U+5544 */ - {0x00e59585, 0x009a55}, /* U+5545 */ - {0x00e59586, 0x008fa4}, /* U+5546 */ - {0x00e59587, 0x00f1a2}, /* U+5547 [2000] */ - {0x00e5958a, 0x00f1a3}, /* U+554A [2000] */ - {0x00e5958c, 0x009a52}, /* U+554C */ - {0x00e5958f, 0x0096e2}, /* U+554F */ - {0x00e59590, 0x008846}, /* U+5550 [2000] */ - {0x00e59593, 0x008c5b}, /* U+5553 */ - {0x00e59596, 0x009a56}, /* U+5556 */ - {0x00e59597, 0x009a57}, /* U+5557 */ - {0x00e5959c, 0x009a54}, /* U+555C */ - {0x00e5959d, 0x009a5a}, /* U+555D */ - {0x00e5959e, 0x008847}, /* U+555E [2000] */ - {0x00e595a0, 0x00f1a5}, /* U+5560 [2000] */ - {0x00e595a1, 0x00f1a6}, /* U+5561 [2000] */ - {0x00e595a3, 0x009a51}, /* U+5563 */ - {0x00e595a4, 0x00f1a7}, /* U+5564 [2000] */ - {0x00e595bb, 0x009a60}, /* U+557B */ - {0x00e595bc, 0x009a65}, /* U+557C */ - {0x00e595bd, 0x00f1a9}, /* U+557D [2000] */ - {0x00e595be, 0x009a61}, /* U+557E */ - {0x00e59680, 0x009a5c}, /* U+5580 */ - {0x00e59681, 0x008848}, /* U+5581 [2000] */ - {0x00e59682, 0x00f1aa}, /* U+5582 [2000] */ - {0x00e59683, 0x009a66}, /* U+5583 */ - {0x00e59684, 0x009150}, /* U+5584 */ - {0x00e59686, 0x008849}, /* U+5586 [2000] */ - {0x00e59687, 0x009a68}, /* U+5587 */ - {0x00e59688, 0x00f1ab}, /* U+5588 [2000] */ - {0x00e59689, 0x008d41}, /* U+5589 */ - {0x00e5968a, 0x009a5e}, /* U+558A */ - {0x00e5968b, 0x00929d}, /* U+558B */ - {0x00e5968e, 0x00884a}, /* U+558E [2000] */ - {0x00e59691, 0x00f1ac}, /* U+5591 [2000] */ - {0x00e59698, 0x009a62}, /* U+5598 */ - {0x00e59699, 0x009a5b}, /* U+5599 */ - {0x00e5969a, 0x008aab}, /* U+559A */ - {0x00e5969c, 0x008aec}, /* U+559C */ - {0x00e5969d, 0x008a85}, /* U+559D */ - {0x00e5969e, 0x009a63}, /* U+559E */ - {0x00e5969f, 0x009a5f}, /* U+559F */ - {0x00e596a7, 0x008c96}, /* U+55A7 */ - {0x00e596a8, 0x009a69}, /* U+55A8 */ - {0x00e596a9, 0x009a67}, /* U+55A9 */ - {0x00e596aa, 0x009172}, /* U+55AA */ - {0x00e596ab, 0x008b69}, /* U+55AB */ - {0x00e596ac, 0x008baa}, /* U+55AC */ - {0x00e596ad, 0x00884c}, /* U+55AD [2000] */ - {0x00e596ae, 0x009a64}, /* U+55AE */ - {0x00e596b0, 0x008bf2}, /* U+55B0 */ - {0x00e596b6, 0x008963}, /* U+55B6 */ - {0x00e596bf, 0x00f1b1}, /* U+55BF [2000] */ - {0x00e59784, 0x009a6d}, /* U+55C4 */ - {0x00e59785, 0x009a6b}, /* U+55C5 */ - {0x00e59787, 0x009aa5}, /* U+55C7 */ - {0x00e59789, 0x00f1b2}, /* U+55C9 [2000] */ - {0x00e5978c, 0x00f1b3}, /* U+55CC [2000] */ - {0x00e5978e, 0x00884d}, /* U+55CE [2000] */ - {0x00e59791, 0x00f1b4}, /* U+55D1 [2000] */ - {0x00e59792, 0x00f1ae}, /* U+55D2 [2000] */ - {0x00e59794, 0x009a70}, /* U+55D4 */ - {0x00e5979a, 0x009a6a}, /* U+55DA */ - {0x00e5979c, 0x009a6e}, /* U+55DC */ - {0x00e5979d, 0x00f1b5}, /* U+55DD [2000] */ - {0x00e5979f, 0x009a6c}, /* U+55DF */ - {0x00e597a2, 0x00f1b7}, /* U+55E2 [2000] */ - {0x00e597a3, 0x008e6b}, /* U+55E3 */ - {0x00e597a4, 0x009a6f}, /* U+55E4 */ - {0x00e597a9, 0x00f1b9}, /* U+55E9 [2000] */ - {0x00e597b7, 0x009a72}, /* U+55F7 */ - {0x00e597b9, 0x009a77}, /* U+55F9 */ - {0x00e597bd, 0x009a75}, /* U+55FD */ - {0x00e597be, 0x009a74}, /* U+55FE */ - {0x00e59886, 0x009251}, /* U+5606 */ - {0x00e59887, 0x00f1bc}, /* U+5607 [2000] */ - {0x00e59888, 0x00884f}, /* U+5608 [2000] */ - {0x00e59889, 0x0089c3}, /* U+5609 */ - {0x00e5988e, 0x008850}, /* U+560E [2000] */ - {0x00e59890, 0x00f1bd}, /* U+5610 [2000] */ - {0x00e59894, 0x009a71}, /* U+5614 */ - {0x00e59896, 0x009a73}, /* U+5616 */ - {0x00e59897, 0x008fa6}, /* U+5617 */ - {0x00e59898, 0x008952}, /* U+5618 */ - {0x00e5989b, 0x009a76}, /* U+561B */ - {0x00e598a8, 0x00f1ba}, /* U+5628 [2000] */ - {0x00e598a9, 0x0089dc}, /* U+5629 */ - {0x00e598af, 0x009a82}, /* U+562F */ - {0x00e598b0, 0x00f1be}, /* U+5630 [2000] */ - {0x00e598b1, 0x008ffa}, /* U+5631 */ - {0x00e598b2, 0x009a7d}, /* U+5632 */ - {0x00e598b4, 0x009a7b}, /* U+5634 */ - {0x00e598b6, 0x009a7c}, /* U+5636 */ - {0x00e598b7, 0x00f1bf}, /* U+5637 [2000] */ - {0x00e598b8, 0x009a7e}, /* U+5638 */ - {0x00e598bb, 0x008851}, /* U+563B [2000] */ - {0x00e598bd, 0x00f1c1}, /* U+563D [2000] */ - {0x00e598bf, 0x00f1c2}, /* U+563F [2000] */ - {0x00e59980, 0x00f1c3}, /* U+5640 [2000] */ - {0x00e59982, 0x00895c}, /* U+5642 */ - {0x00e59987, 0x00f1c4}, /* U+5647 [2000] */ - {0x00e59989, 0x008852}, /* U+5649 [2000] */ - {0x00e5998c, 0x009158}, /* U+564C */ - {0x00e5998e, 0x009a78}, /* U+564E */ - {0x00e59990, 0x009a79}, /* U+5650 */ - {0x00e59993, 0x00eaa5}, /* U+5653 [2004] */ - {0x00e5999b, 0x008a9a}, /* U+565B */ - {0x00e5999e, 0x00f1c5}, /* U+565E [2000] */ - {0x00e599a0, 0x00f1c6}, /* U+5660 [2000] */ - {0x00e599a4, 0x009a81}, /* U+5664 */ - {0x00e599a6, 0x008854}, /* U+5666 [2000] */ - {0x00e599a8, 0x008aed}, /* U+5668 */ - {0x00e599aa, 0x009a84}, /* U+566A */ - {0x00e599ab, 0x009a80}, /* U+566B */ - {0x00e599ac, 0x009a83}, /* U+566C */ - {0x00e599ad, 0x00f1c7}, /* U+566D [2000] */ - {0x00e599af, 0x008856}, /* U+566F [2000] */ - {0x00e599b1, 0x008857}, /* U+5671 [2000] */ - {0x00e599b2, 0x008858}, /* U+5672 [2000] */ - {0x00e599b4, 0x0095ac}, /* U+5674 */ - {0x00e599b6, 0x008853}, /* U+5676 [2000] */ - {0x00e599b8, 0x0093d3}, /* U+5678 */ - {0x00e599ba, 0x0094b6}, /* U+567A */ - {0x00e59a80, 0x009a86}, /* U+5680 */ - {0x00e59a86, 0x009a85}, /* U+5686 */ - {0x00e59a87, 0x008a64}, /* U+5687 */ - {0x00e59a88, 0x00f1c9}, /* U+5688 [2000] */ - {0x00e59a8a, 0x009a87}, /* U+568A */ - {0x00e59a8c, 0x00f1ca}, /* U+568C [2000] */ - {0x00e59a8f, 0x009a8a}, /* U+568F */ - {0x00e59a94, 0x009a89}, /* U+5694 */ - {0x00e59a95, 0x00f1cb}, /* U+5695 [2000] */ - {0x00e59a99, 0x008859}, /* U+5699 [2000] */ - {0x00e59a9a, 0x00f1cc}, /* U+569A [2000] */ - {0x00e59a9d, 0x00f1cd}, /* U+569D [2000] */ - {0x00e59a9e, 0x00885a}, /* U+569E [2000] */ - {0x00e59aa0, 0x009a88}, /* U+56A0 */ - {0x00e59aa2, 0x009458}, /* U+56A2 */ - {0x00e59aa5, 0x009a8b}, /* U+56A5 */ - {0x00e59aa8, 0x00f1ce}, /* U+56A8 [2000] */ - {0x00e59aa9, 0x00885b}, /* U+56A9 [2000] */ - {0x00e59aac, 0x00885c}, /* U+56AC [2000] */ - {0x00e59aad, 0x00f1cf}, /* U+56AD [2000] */ - {0x00e59aae, 0x009a8c}, /* U+56AE */ - {0x00e59ab2, 0x00f1d0}, /* U+56B2 [2000] */ - {0x00e59ab3, 0x00885d}, /* U+56B3 [2000] */ - {0x00e59ab4, 0x009a8e}, /* U+56B4 */ - {0x00e59ab6, 0x009a8d}, /* U+56B6 */ - {0x00e59abc, 0x009a90}, /* U+56BC */ - {0x00e59b80, 0x009a93}, /* U+56C0 */ - {0x00e59b81, 0x009a91}, /* U+56C1 */ - {0x00e59b82, 0x009a8f}, /* U+56C2 */ - {0x00e59b83, 0x009a92}, /* U+56C3 */ - {0x00e59b85, 0x00f1d1}, /* U+56C5 [2000] */ - {0x00e59b88, 0x009a94}, /* U+56C8 */ - {0x00e59b89, 0x00885e}, /* U+56C9 [2000] */ - {0x00e59b8a, 0x00885f}, /* U+56CA [2000] */ - {0x00e59b8d, 0x00f1d2}, /* U+56CD [2000] */ - {0x00e59b8e, 0x009a95}, /* U+56CE */ - {0x00e59b91, 0x009a96}, /* U+56D1 */ - {0x00e59b93, 0x009a97}, /* U+56D3 */ - {0x00e59b97, 0x009a98}, /* U+56D7 */ - {0x00e59b98, 0x009964}, /* U+56D8 */ - {0x00e59b9a, 0x008efa}, /* U+56DA */ - {0x00e59b9b, 0x008e6c}, /* U+56DB */ - {0x00e59b9e, 0x0089f1}, /* U+56DE */ - {0x00e59b9f, 0x00f1d3}, /* U+56DF [2000] */ - {0x00e59ba0, 0x0088f6}, /* U+56E0 */ - {0x00e59ba3, 0x009263}, /* U+56E3 */ - {0x00e59ba8, 0x00f1d4}, /* U+56E8 [2000] */ - {0x00e59bae, 0x009a99}, /* U+56EE */ - {0x00e59bb0, 0x008da2}, /* U+56F0 */ - {0x00e59bb2, 0x0088cd}, /* U+56F2 */ - {0x00e59bb3, 0x00907d}, /* U+56F3 */ - {0x00e59bb6, 0x00f1d5}, /* U+56F6 [2000] */ - {0x00e59bb7, 0x00f1d6}, /* U+56F7 [2000] */ - {0x00e59bb9, 0x009a9a}, /* U+56F9 */ - {0x00e59bba, 0x008cc5}, /* U+56FA */ - {0x00e59bbd, 0x008d91}, /* U+56FD */ - {0x00e59bbf, 0x009a9c}, /* U+56FF */ - {0x00e59c80, 0x009a9b}, /* U+5700 */ - {0x00e59c83, 0x0095de}, /* U+5703 */ - {0x00e59c84, 0x009a9d}, /* U+5704 */ - {0x00e59c88, 0x009a9f}, /* U+5708 */ - {0x00e59c89, 0x009a9e}, /* U+5709 */ - {0x00e59c8a, 0x008860}, /* U+570A [2000] */ - {0x00e59c8b, 0x009aa0}, /* U+570B */ - {0x00e59c8d, 0x009aa1}, /* U+570D */ - {0x00e59c8f, 0x008c97}, /* U+570F */ - {0x00e59c92, 0x008980}, /* U+5712 */ - {0x00e59c93, 0x009aa2}, /* U+5713 */ - {0x00e59c95, 0x00f1d8}, /* U+5715 [2000] */ - {0x00e59c96, 0x009aa4}, /* U+5716 */ - {0x00e59c98, 0x009aa3}, /* U+5718 */ - {0x00e59c9c, 0x009aa6}, /* U+571C */ - {0x00e59c9f, 0x009379}, /* U+571F */ - {0x00e59ca1, 0x008862}, /* U+5721 [2000] */ - {0x00e59ca3, 0x00f1d9}, /* U+5723 [2000] */ - {0x00e59ca6, 0x009aa7}, /* U+5726 */ - {0x00e59ca7, 0x0088b3}, /* U+5727 */ - {0x00e59ca8, 0x008ddd}, /* U+5728 */ - {0x00e59ca9, 0x00f1db}, /* U+5729 [2000] */ - {0x00e59cad, 0x008c5c}, /* U+572D */ - {0x00e59caf, 0x008863}, /* U+572F [2000] */ - {0x00e59cb0, 0x00926e}, /* U+5730 */ - {0x00e59cb3, 0x008864}, /* U+5733 [2000] */ - {0x00e59cb4, 0x008865}, /* U+5734 [2000] */ - {0x00e59cb7, 0x009aa8}, /* U+5737 */ - {0x00e59cb8, 0x009aa9}, /* U+5738 */ - {0x00e59cbb, 0x009aab}, /* U+573B */ - {0x00e59d80, 0x009aac}, /* U+5740 */ - {0x00e59d82, 0x008de2}, /* U+5742 */ - {0x00e59d85, 0x00f1dd}, /* U+5745 [2000] */ - {0x00e59d86, 0x00f1de}, /* U+5746 [2000] */ - {0x00e59d87, 0x008bcf}, /* U+5747 */ - {0x00e59d8a, 0x009656}, /* U+574A */ - {0x00e59d8c, 0x00f1df}, /* U+574C [2000] */ - {0x00e59d8d, 0x00f1e0}, /* U+574D [2000] */ - {0x00e59d8e, 0x009aaa}, /* U+574E */ - {0x00e59d8f, 0x009aad}, /* U+574F */ - {0x00e59d90, 0x008dbf}, /* U+5750 */ - {0x00e59d91, 0x008d42}, /* U+5751 */ - {0x00e59da1, 0x009ab1}, /* U+5761 */ - {0x00e59da4, 0x008da3}, /* U+5764 */ - {0x00e59da6, 0x009252}, /* U+5766 */ - {0x00e59da8, 0x00f1e2}, /* U+5768 [2000] */ - {0x00e59da9, 0x009aae}, /* U+5769 */ - {0x00e59daa, 0x0092d8}, /* U+576A */ - {0x00e59daf, 0x00f1e3}, /* U+576F [2000] */ - {0x00e59db0, 0x008866}, /* U+5770 [2000] */ - {0x00e59db3, 0x00f1e4}, /* U+5773 [2000] */ - {0x00e59db4, 0x00f1e5}, /* U+5774 [2000] */ - {0x00e59db5, 0x00f1e6}, /* U+5775 [2000] */ - {0x00e59db7, 0x008867}, /* U+5777 [2000] */ - {0x00e59dbb, 0x00f1e7}, /* U+577B [2000] */ - {0x00e59dbc, 0x008868}, /* U+577C [2000] */ - {0x00e59dbf, 0x009ab2}, /* U+577F */ - {0x00e59e82, 0x009082}, /* U+5782 */ - {0x00e59e88, 0x009ab0}, /* U+5788 */ - {0x00e59e89, 0x009ab3}, /* U+5789 */ - {0x00e59e8b, 0x008c5e}, /* U+578B */ - {0x00e59e93, 0x009ab4}, /* U+5793 */ - {0x00e59e9a, 0x00f1eb}, /* U+579A [2000] */ - {0x00e59e9c, 0x008869}, /* U+579C [2000] */ - {0x00e59e9d, 0x00f1ec}, /* U+579D [2000] */ - {0x00e59e9e, 0x00f1ed}, /* U+579E [2000] */ - {0x00e59ea0, 0x009ab5}, /* U+57A0 */ - {0x00e59ea2, 0x008d43}, /* U+57A2 */ - {0x00e59ea3, 0x008a5f}, /* U+57A3 */ - {0x00e59ea4, 0x009ab7}, /* U+57A4 */ - {0x00e59ea8, 0x00f1ee}, /* U+57A8 [2000] */ - {0x00e59eaa, 0x009ab8}, /* U+57AA */ - {0x00e59eac, 0x00f1ea}, /* U+57AC [2000] */ - {0x00e59eb0, 0x009ab9}, /* U+57B0 */ - {0x00e59eb3, 0x009ab6}, /* U+57B3 */ - {0x00e59eb8, 0x00886c}, /* U+57B8 [2000] */ - {0x00e59f80, 0x009aaf}, /* U+57C0 */ - {0x00e59f83, 0x009aba}, /* U+57C3 */ - {0x00e59f86, 0x009abb}, /* U+57C6 */ - {0x00e59f87, 0x00886d}, /* U+57C7 [2000] */ - {0x00e59f88, 0x00886e}, /* U+57C8 [2000] */ - {0x00e59f8b, 0x009684}, /* U+57CB */ - {0x00e59f8c, 0x00f1f1}, /* U+57CC [2000] */ - {0x00e59f8e, 0x008fe9}, /* U+57CE */ - {0x00e59f8f, 0x00886f}, /* U+57CF [2000] */ - {0x00e59f92, 0x009abd}, /* U+57D2 */ - {0x00e59f93, 0x009abe}, /* U+57D3 */ - {0x00e59f94, 0x009abc}, /* U+57D4 */ - {0x00e59f96, 0x009ac0}, /* U+57D6 */ - {0x00e59f97, 0x00f1ef}, /* U+57D7 [2000] */ - {0x00e59f9c, 0x009457}, /* U+57DC */ - {0x00e59f9e, 0x00f1f4}, /* U+57DE [2000] */ - {0x00e59f9f, 0x0088e6}, /* U+57DF */ - {0x00e59fa0, 0x009575}, /* U+57E0 */ - {0x00e59fa3, 0x009ac1}, /* U+57E3 */ - {0x00e59fa4, 0x008870}, /* U+57E4 [2000] */ - {0x00e59fa6, 0x00f1f5}, /* U+57E6 [2000] */ - {0x00e59fad, 0x008871}, /* U+57ED [2000] */ - {0x00e59fb0, 0x00f1f6}, /* U+57F0 [2000] */ - {0x00e59fb4, 0x008ffb}, /* U+57F4 */ - {0x00e59fb5, 0x008872}, /* U+57F5 [2000] */ - {0x00e59fb6, 0x008873}, /* U+57F6 [2000] */ - {0x00e59fb7, 0x008eb7}, /* U+57F7 */ - {0x00e59fb8, 0x00f1f8}, /* U+57F8 [2000] */ - {0x00e59fb9, 0x00947c}, /* U+57F9 */ - {0x00e59fba, 0x008aee}, /* U+57FA */ - {0x00e59fbb, 0x00f1f9}, /* U+57FB [2000] */ - {0x00e59fbc, 0x008de9}, /* U+57FC */ - {0x00e59fbd, 0x00f1fa}, /* U+57FD [2000] */ - {0x00e59fbf, 0x008874}, /* U+57FF [2000] */ - {0x00e5a080, 0x009678}, /* U+5800 */ - {0x00e5a082, 0x0093b0}, /* U+5802 */ - {0x00e5a084, 0x00f1fb}, /* U+5804 [2000] */ - {0x00e5a085, 0x008c98}, /* U+5805 */ - {0x00e5a086, 0x0091cd}, /* U+5806 */ - {0x00e5a089, 0x008875}, /* U+5809 [2000] */ - {0x00e5a08a, 0x009abf}, /* U+580A */ - {0x00e5a08b, 0x009ac2}, /* U+580B */ - {0x00e5a095, 0x0091c2}, /* U+5815 */ - {0x00e5a099, 0x009ac3}, /* U+5819 */ - {0x00e5a09d, 0x009ac4}, /* U+581D */ - {0x00e5a09e, 0x00f1fc}, /* U+581E [2000] */ - {0x00e5a0a0, 0x00f240}, /* U+5820 [2000] */ - {0x00e5a0a1, 0x009ac6}, /* U+5821 */ - {0x00e5a0a4, 0x0092e7}, /* U+5824 */ - {0x00e5a0a7, 0x00f241}, /* U+5827 [2000] */ - {0x00e5a0aa, 0x008aac}, /* U+582A */ - {0x00e5a0af, 0x00ea9f}, /* U+582F [1983] */ - {0x00e5a0b0, 0x008981}, /* U+5830 */ - {0x00e5a0b1, 0x0095f1}, /* U+5831 */ - {0x00e5a0b2, 0x00f242}, /* U+5832 [2000] */ - {0x00e5a0b4, 0x008fea}, /* U+5834 */ - {0x00e5a0b5, 0x009367}, /* U+5835 */ - {0x00e5a0b9, 0x00f243}, /* U+5839 [2000] */ - {0x00e5a0ba, 0x008de4}, /* U+583A */ - {0x00e5a0bd, 0x009acc}, /* U+583D */ - {0x00e5a180, 0x0095bb}, /* U+5840 */ - {0x00e5a181, 0x0097db}, /* U+5841 */ - {0x00e5a189, 0x00f245}, /* U+5849 [2000] */ - {0x00e5a18a, 0x0089f2}, /* U+584A */ - {0x00e5a18b, 0x009ac8}, /* U+584B */ - {0x00e5a18c, 0x00f246}, /* U+584C [2000] */ - {0x00e5a191, 0x009159}, /* U+5851 */ - {0x00e5a192, 0x009acb}, /* U+5852 */ - {0x00e5a194, 0x009383}, /* U+5854 */ - {0x00e5a197, 0x009368}, /* U+5857 */ - {0x00e5a198, 0x009384}, /* U+5858 */ - {0x00e5a199, 0x0094b7}, /* U+5859 */ - {0x00e5a19a, 0x0092cb}, /* U+585A */ - {0x00e5a19e, 0x008dc7}, /* U+585E */ - {0x00e5a1a1, 0x008877}, /* U+5861 [2000] */ - {0x00e5a1a2, 0x009ac7}, /* U+5862 */ - {0x00e5a1a4, 0x008878}, /* U+5864 [2000] */ - {0x00e5a1a7, 0x00f247}, /* U+5867 [2000] */ - {0x00e5a1a9, 0x008996}, /* U+5869 */ - {0x00e5a1ab, 0x009355}, /* U+586B */ - {0x00e5a1b0, 0x009ac9}, /* U+5870 */ - {0x00e5a1b2, 0x009ac5}, /* U+5872 */ - {0x00e5a1b5, 0x00906f}, /* U+5875 */ - {0x00e5a1b9, 0x009acd}, /* U+5879 */ - {0x00e5a1bc, 0x00887a}, /* U+587C [2000] */ - {0x00e5a1be, 0x008f6d}, /* U+587E */ - {0x00e5a283, 0x008bab}, /* U+5883 */ - {0x00e5a285, 0x009ace}, /* U+5885 */ - {0x00e5a289, 0x00887b}, /* U+5889 [2000] */ - {0x00e5a28a, 0x00f248}, /* U+588A [2000] */ - {0x00e5a28b, 0x00f249}, /* U+588B [2000] */ - {0x00e5a28d, 0x00f24a}, /* U+588D [2000] */ - {0x00e5a28f, 0x00f24b}, /* U+588F [2000] */ - {0x00e5a290, 0x00f24c}, /* U+5890 [2000] */ - {0x00e5a293, 0x0095e6}, /* U+5893 */ - {0x00e5a294, 0x00f24d}, /* U+5894 [2000] */ - {0x00e5a297, 0x00919d}, /* U+5897 */ - {0x00e5a29c, 0x0092c4}, /* U+589C */ - {0x00e5a29d, 0x00f24e}, /* U+589D [2000] */ - {0x00e5a29e, 0x00887c}, /* U+589E [2000] */ - {0x00e5a29f, 0x009ad0}, /* U+589F */ - {0x00e5a2a8, 0x00966e}, /* U+58A8 */ - {0x00e5a2a9, 0x00887e}, /* U+58A9 [2000] */ - {0x00e5a2aa, 0x00f24f}, /* U+58AA [2000] */ - {0x00e5a2ab, 0x009ad1}, /* U+58AB */ - {0x00e5a2ae, 0x009ad6}, /* U+58AE */ - {0x00e5a2b1, 0x00f250}, /* U+58B1 [2000] */ - {0x00e5a2b3, 0x0095ad}, /* U+58B3 */ - {0x00e5a2b8, 0x009ad5}, /* U+58B8 */ - {0x00e5a2b9, 0x009acf}, /* U+58B9 */ - {0x00e5a2ba, 0x009ad2}, /* U+58BA */ - {0x00e5a2bb, 0x009ad4}, /* U+58BB */ - {0x00e5a2be, 0x008da4}, /* U+58BE */ - {0x00e5a381, 0x0095c7}, /* U+58C1 */ - {0x00e5a383, 0x00f252}, /* U+58C3 [2000] */ - {0x00e5a385, 0x009ad7}, /* U+58C5 */ - {0x00e5a387, 0x009264}, /* U+58C7 */ - {0x00e5a38a, 0x0089f3}, /* U+58CA */ - {0x00e5a38c, 0x008feb}, /* U+58CC */ - {0x00e5a38d, 0x00f253}, /* U+58CD [2000] */ - {0x00e5a38e, 0x008882}, /* U+58CE [2000] */ - {0x00e5a391, 0x009ad9}, /* U+58D1 */ - {0x00e5a392, 0x008881}, /* U+58D2 [2000] */ - {0x00e5a393, 0x009ad8}, /* U+58D3 */ - {0x00e5a394, 0x008883}, /* U+58D4 [2000] */ - {0x00e5a395, 0x008d88}, /* U+58D5 */ - {0x00e5a397, 0x009ada}, /* U+58D7 */ - {0x00e5a398, 0x009adc}, /* U+58D8 */ - {0x00e5a399, 0x009adb}, /* U+58D9 */ - {0x00e5a39a, 0x008884}, /* U+58DA [2000] */ - {0x00e5a39c, 0x009ade}, /* U+58DC */ - {0x00e5a39e, 0x009ad3}, /* U+58DE */ - {0x00e5a39f, 0x009ae0}, /* U+58DF */ - {0x00e5a3a0, 0x008885}, /* U+58E0 [2000] */ - {0x00e5a3a2, 0x00f254}, /* U+58E2 [2000] */ - {0x00e5a3a4, 0x009adf}, /* U+58E4 */ - {0x00e5a3a5, 0x009add}, /* U+58E5 */ - {0x00e5a3a9, 0x008886}, /* U+58E9 [2000] */ - {0x00e5a3ab, 0x008e6d}, /* U+58EB */ - {0x00e5a3ac, 0x009070}, /* U+58EC */ - {0x00e5a3ae, 0x009173}, /* U+58EE */ - {0x00e5a3af, 0x009ae1}, /* U+58EF */ - {0x00e5a3b0, 0x0090ba}, /* U+58F0 */ - {0x00e5a3b1, 0x0088eb}, /* U+58F1 */ - {0x00e5a3b2, 0x009484}, /* U+58F2 */ - {0x00e5a3b3, 0x00f255}, /* U+58F3 [2000] */ - {0x00e5a3b4, 0x00f256}, /* U+58F4 [2000] */ - {0x00e5a3b7, 0x0092d9}, /* U+58F7 */ - {0x00e5a3b9, 0x009ae3}, /* U+58F9 */ - {0x00e5a3ba, 0x009ae2}, /* U+58FA */ - {0x00e5a3bb, 0x009ae4}, /* U+58FB */ - {0x00e5a3bc, 0x009ae5}, /* U+58FC */ - {0x00e5a3bd, 0x009ae6}, /* U+58FD */ - {0x00e5a482, 0x009ae7}, /* U+5902 */ - {0x00e5a485, 0x00f257}, /* U+5905 [2000] */ - {0x00e5a486, 0x00f258}, /* U+5906 [2000] */ - {0x00e5a489, 0x0095cf}, /* U+5909 */ - {0x00e5a48a, 0x009ae8}, /* U+590A */ - {0x00e5a48b, 0x00f259}, /* U+590B [2000] */ - {0x00e5a48c, 0x008887}, /* U+590C [2000] */ - {0x00e5a48d, 0x00f25a}, /* U+590D [2000] */ - {0x00e5a48f, 0x0089c4}, /* U+590F */ - {0x00e5a490, 0x009ae9}, /* U+5910 */ - {0x00e5a494, 0x00f25b}, /* U+5914 [2000] */ - {0x00e5a495, 0x00975b}, /* U+5915 */ - {0x00e5a496, 0x008a4f}, /* U+5916 */ - {0x00e5a498, 0x0099c7}, /* U+5918 */ - {0x00e5a499, 0x008f67}, /* U+5919 */ - {0x00e5a49a, 0x0091bd}, /* U+591A */ - {0x00e5a49b, 0x009aea}, /* U+591B */ - {0x00e5a49c, 0x0096e9}, /* U+591C */ - {0x00e5a4a2, 0x0096b2}, /* U+5922 */ - {0x00e5a4a4, 0x00f25c}, /* U+5924 [2000] */ - {0x00e5a4a5, 0x009aec}, /* U+5925 */ - {0x00e5a4a7, 0x0091e5}, /* U+5927 */ - {0x00e5a4a9, 0x009356}, /* U+5929 */ - {0x00e5a4aa, 0x0091be}, /* U+592A */ - {0x00e5a4ab, 0x009576}, /* U+592B */ - {0x00e5a4ac, 0x009aed}, /* U+592C */ - {0x00e5a4ad, 0x009aee}, /* U+592D */ - {0x00e5a4ae, 0x00899b}, /* U+592E */ - {0x00e5a4b1, 0x008eb8}, /* U+5931 */ - {0x00e5a4b2, 0x009aef}, /* U+5932 */ - {0x00e5a4b7, 0x0088ce}, /* U+5937 */ - {0x00e5a4b8, 0x009af0}, /* U+5938 */ - {0x00e5a4bd, 0x00f25f}, /* U+593D [2000] */ - {0x00e5a4be, 0x009af1}, /* U+593E */ - {0x00e5a584, 0x008982}, /* U+5944 */ - {0x00e5a586, 0x00f261}, /* U+5946 [2000] */ - {0x00e5a587, 0x008aef}, /* U+5947 */ - {0x00e5a588, 0x0093de}, /* U+5948 */ - {0x00e5a589, 0x0095f2}, /* U+5949 */ - {0x00e5a58e, 0x009af5}, /* U+594E */ - {0x00e5a58f, 0x009174}, /* U+594F */ - {0x00e5a590, 0x009af4}, /* U+5950 */ - {0x00e5a591, 0x008c5f}, /* U+5951 */ - {0x00e5a594, 0x00967a}, /* U+5954 */ - {0x00e5a595, 0x009af3}, /* U+5955 */ - {0x00e5a597, 0x009385}, /* U+5957 */ - {0x00e5a598, 0x009af7}, /* U+5958 */ - {0x00e5a59a, 0x009af6}, /* U+595A */ - {0x00e5a59b, 0x00f264}, /* U+595B [2000] */ - {0x00e5a59d, 0x008889}, /* U+595D [2000] */ - {0x00e5a59f, 0x00f265}, /* U+595F [2000] */ - {0x00e5a5a0, 0x009af9}, /* U+5960 */ - {0x00e5a5a2, 0x009af8}, /* U+5962 */ - {0x00e5a5a5, 0x00899c}, /* U+5965 */ - {0x00e5a5a7, 0x009afa}, /* U+5967 */ - {0x00e5a5a8, 0x008fa7}, /* U+5968 */ - {0x00e5a5a9, 0x009afc}, /* U+5969 */ - {0x00e5a5aa, 0x009244}, /* U+596A */ - {0x00e5a5ac, 0x009afb}, /* U+596C */ - {0x00e5a5ad, 0x00888a}, /* U+596D [2000] */ - {0x00e5a5ae, 0x0095b1}, /* U+596E */ - {0x00e5a5b3, 0x008f97}, /* U+5973 */ - {0x00e5a5b4, 0x00937a}, /* U+5974 */ - {0x00e5a5b5, 0x00f267}, /* U+5975 [2000] */ - {0x00e5a5b6, 0x00f268}, /* U+5976 [2000] */ - {0x00e5a5b8, 0x009b40}, /* U+5978 */ - {0x00e5a5bc, 0x00f269}, /* U+597C [2000] */ - {0x00e5a5bd, 0x008d44}, /* U+597D */ - {0x00e5a681, 0x009b41}, /* U+5981 */ - {0x00e5a682, 0x009440}, /* U+5982 */ - {0x00e5a683, 0x0094dc}, /* U+5983 */ - {0x00e5a684, 0x0096cf}, /* U+5984 */ - {0x00e5a68a, 0x009444}, /* U+598A */ - {0x00e5a68b, 0x00888b}, /* U+598B [2000] */ - {0x00e5a68d, 0x009b4a}, /* U+598D */ - {0x00e5a692, 0x00888c}, /* U+5992 [2000] */ - {0x00e5a693, 0x008b57}, /* U+5993 */ - {0x00e5a696, 0x009764}, /* U+5996 */ - {0x00e5a699, 0x0096ad}, /* U+5999 */ - {0x00e5a69b, 0x009baa}, /* U+599B */ - {0x00e5a69d, 0x009b42}, /* U+599D */ - {0x00e5a69f, 0x00f26a}, /* U+599F [2000] */ - {0x00e5a6a3, 0x009b45}, /* U+59A3 */ - {0x00e5a6a4, 0x00888d}, /* U+59A4 [2000] */ - {0x00e5a6a5, 0x0091c3}, /* U+59A5 */ - {0x00e5a6a8, 0x009657}, /* U+59A8 */ - {0x00e5a6ac, 0x009369}, /* U+59AC */ - {0x00e5a6ae, 0x00f26b}, /* U+59AE [2000] */ - {0x00e5a6b2, 0x009b46}, /* U+59B2 */ - {0x00e5a6b9, 0x009685}, /* U+59B9 */ - {0x00e5a6bb, 0x008dc8}, /* U+59BB */ - {0x00e5a6bc, 0x00f26c}, /* U+59BC [2000] */ - {0x00e5a6be, 0x008fa8}, /* U+59BE */ - {0x00e5a783, 0x00888e}, /* U+59C3 [2000] */ - {0x00e5a786, 0x009b47}, /* U+59C6 */ - {0x00e5a788, 0x00f26d}, /* U+59C8 [2000] */ - {0x00e5a789, 0x008e6f}, /* U+59C9 */ - {0x00e5a78b, 0x008e6e}, /* U+59CB */ - {0x00e5a78d, 0x00f26e}, /* U+59CD [2000] */ - {0x00e5a790, 0x0088b7}, /* U+59D0 */ - {0x00e5a791, 0x008cc6}, /* U+59D1 */ - {0x00e5a792, 0x00888f}, /* U+59D2 [2000] */ - {0x00e5a793, 0x0090a9}, /* U+59D3 */ - {0x00e5a794, 0x0088cf}, /* U+59D4 */ - {0x00e5a799, 0x009b4b}, /* U+59D9 */ - {0x00e5a79a, 0x009b4c}, /* U+59DA */ - {0x00e5a79c, 0x009b49}, /* U+59DC */ - {0x00e5a79d, 0x008890}, /* U+59DD [2000] */ - {0x00e5a79e, 0x00f26f}, /* U+59DE [2000] */ - {0x00e5a7a3, 0x00f270}, /* U+59E3 [2000] */ - {0x00e5a7a4, 0x00f271}, /* U+59E4 [2000] */ - {0x00e5a7a5, 0x008957}, /* U+59E5 */ - {0x00e5a7a6, 0x008aad}, /* U+59E6 */ - {0x00e5a7a7, 0x00f272}, /* U+59E7 [2000] */ - {0x00e5a7a8, 0x009b48}, /* U+59E8 */ - {0x00e5a7aa, 0x0096c3}, /* U+59EA */ - {0x00e5a7ab, 0x009550}, /* U+59EB */ - {0x00e5a7ae, 0x00f273}, /* U+59EE [2000] */ - {0x00e5a7b6, 0x0088a6}, /* U+59F6 */ - {0x00e5a7b8, 0x00eff8}, /* U+59F8 [2004] */ - {0x00e5a7bb, 0x0088f7}, /* U+59FB */ - {0x00e5a7bf, 0x008e70}, /* U+59FF */ - {0x00e5a881, 0x0088d0}, /* U+5A01 */ - {0x00e5a883, 0x0088a1}, /* U+5A03 */ - {0x00e5a889, 0x009b51}, /* U+5A09 */ - {0x00e5a88c, 0x00f277}, /* U+5A0C [2000] */ - {0x00e5a88d, 0x00f278}, /* U+5A0D [2000] */ - {0x00e5a891, 0x009b4f}, /* U+5A11 */ - {0x00e5a893, 0x008891}, /* U+5A13 [2000] */ - {0x00e5a897, 0x00f279}, /* U+5A17 [2000] */ - {0x00e5a898, 0x0096ba}, /* U+5A18 */ - {0x00e5a89a, 0x009b52}, /* U+5A1A */ - {0x00e5a89c, 0x009b50}, /* U+5A1C */ - {0x00e5a89f, 0x009b4e}, /* U+5A1F */ - {0x00e5a8a0, 0x009050}, /* U+5A20 */ - {0x00e5a8a3, 0x008892}, /* U+5A23 [2000] */ - {0x00e5a8a5, 0x009b4d}, /* U+5A25 */ - {0x00e5a8a7, 0x00f27a}, /* U+5A27 [2000] */ - {0x00e5a8a9, 0x0095d8}, /* U+5A29 */ - {0x00e5a8ad, 0x00f27b}, /* U+5A2D [2000] */ - {0x00e5a8af, 0x008ce2}, /* U+5A2F */ - {0x00e5a8b5, 0x009b56}, /* U+5A35 */ - {0x00e5a8b6, 0x009b57}, /* U+5A36 */ - {0x00e5a8bc, 0x008fa9}, /* U+5A3C */ - {0x00e5a980, 0x009b53}, /* U+5A40 */ - {0x00e5a981, 0x00984b}, /* U+5A41 */ - {0x00e5a986, 0x00946b}, /* U+5A46 */ - {0x00e5a989, 0x009b55}, /* U+5A49 */ - {0x00e5a995, 0x00f27c}, /* U+5A55 [2000] */ - {0x00e5a99a, 0x008da5}, /* U+5A5A */ - {0x00e5a9a2, 0x009b58}, /* U+5A62 */ - {0x00e5a9a5, 0x00f27d}, /* U+5A65 [2000] */ - {0x00e5a9a6, 0x009577}, /* U+5A66 */ - {0x00e5a9a7, 0x008893}, /* U+5A67 [2000] */ - {0x00e5a9aa, 0x009b59}, /* U+5A6A */ - {0x00e5a9ac, 0x009b54}, /* U+5A6C */ - {0x00e5a9ad, 0x008894}, /* U+5A6D [2000] */ - {0x00e5a9b7, 0x008895}, /* U+5A77 [2000] */ - {0x00e5a9ba, 0x00f27e}, /* U+5A7A [2000] */ - {0x00e5a9be, 0x008896}, /* U+5A7E [2000] */ - {0x00e5a9bf, 0x0096b9}, /* U+5A7F */ - {0x00e5aa84, 0x008897}, /* U+5A84 [2000] */ - {0x00e5aa8b, 0x00f280}, /* U+5A8B [2000] */ - {0x00e5aa92, 0x00947d}, /* U+5A92 */ - {0x00e5aa9a, 0x009b5a}, /* U+5A9A */ - {0x00e5aa9b, 0x009551}, /* U+5A9B */ - {0x00e5aa9c, 0x00f281}, /* U+5A9C [2000] */ - {0x00e5aa9e, 0x008898}, /* U+5A9E [2000] */ - {0x00e5aa9f, 0x00f282}, /* U+5A9F [2000] */ - {0x00e5aaa0, 0x00f283}, /* U+5AA0 [2000] */ - {0x00e5aaa2, 0x00f284}, /* U+5AA2 [2000] */ - {0x00e5aaa7, 0x008899}, /* U+5AA7 [2000] */ - {0x00e5aab1, 0x00f285}, /* U+5AB1 [2000] */ - {0x00e5aab3, 0x00f286}, /* U+5AB3 [2000] */ - {0x00e5aab5, 0x00f287}, /* U+5AB5 [2000] */ - {0x00e5aaba, 0x00f288}, /* U+5ABA [2000] */ - {0x00e5aabc, 0x009b5b}, /* U+5ABC */ - {0x00e5aabd, 0x009b5f}, /* U+5ABD */ - {0x00e5aabe, 0x009b5c}, /* U+5ABE */ - {0x00e5aabf, 0x00f289}, /* U+5ABF [2000] */ - {0x00e5ab81, 0x0089c5}, /* U+5AC1 */ - {0x00e5ab82, 0x009b5e}, /* U+5AC2 */ - {0x00e5ab84, 0x00889a}, /* U+5AC4 [2000] */ - {0x00e5ab89, 0x008eb9}, /* U+5AC9 */ - {0x00e5ab8b, 0x009b5d}, /* U+5ACB */ - {0x00e5ab8c, 0x008c99}, /* U+5ACC */ - {0x00e5ab90, 0x009b6b}, /* U+5AD0 */ - {0x00e5ab96, 0x009b64}, /* U+5AD6 */ - {0x00e5ab97, 0x009b61}, /* U+5AD7 */ - {0x00e5ab9a, 0x00f28a}, /* U+5ADA [2000] */ - {0x00e5ab9c, 0x00f28b}, /* U+5ADC [2000] */ - {0x00e5aba0, 0x00f28c}, /* U+5AE0 [2000] */ - {0x00e5aba1, 0x009284}, /* U+5AE1 */ - {0x00e5aba3, 0x009b60}, /* U+5AE3 */ - {0x00e5aba5, 0x00f28d}, /* U+5AE5 [2000] */ - {0x00e5aba6, 0x009b62}, /* U+5AE6 */ - {0x00e5aba9, 0x009b63}, /* U+5AE9 */ - {0x00e5abae, 0x00f28f}, /* U+5AEE [2000] */ - {0x00e5abb0, 0x00f28e}, /* U+5AF0 [2000] */ - {0x00e5abb5, 0x00f290}, /* U+5AF5 [2000] */ - {0x00e5abba, 0x009b65}, /* U+5AFA */ - {0x00e5abbb, 0x009b66}, /* U+5AFB */ - {0x00e5ac80, 0x00f291}, /* U+5B00 [2000] */ - {0x00e5ac88, 0x00f292}, /* U+5B08 [2000] */ - {0x00e5ac89, 0x008af0}, /* U+5B09 */ - {0x00e5ac8b, 0x009b68}, /* U+5B0B */ - {0x00e5ac8c, 0x009b67}, /* U+5B0C */ - {0x00e5ac96, 0x009b69}, /* U+5B16 */ - {0x00e5ac97, 0x00f293}, /* U+5B17 [2000] */ - {0x00e5ac99, 0x00889c}, /* U+5B19 [2000] */ - {0x00e5aca2, 0x008fec}, /* U+5B22 */ - {0x00e5aca5, 0x00889d}, /* U+5B25 [2000] */ - {0x00e5acaa, 0x009b6c}, /* U+5B2A */ - {0x00e5acac, 0x0092da}, /* U+5B2C */ - {0x00e5acad, 0x00f295}, /* U+5B2D [2000] */ - {0x00e5acb0, 0x008964}, /* U+5B30 */ - {0x00e5acb2, 0x009b6a}, /* U+5B32 */ - {0x00e5acb4, 0x00f294}, /* U+5B34 [2000] */ - {0x00e5acb6, 0x009b6d}, /* U+5B36 */ - {0x00e5acbe, 0x009b6e}, /* U+5B3E */ - {0x00e5ad80, 0x009b71}, /* U+5B40 */ - {0x00e5ad81, 0x009874}, /* U+5B41 [2000] */ - {0x00e5ad83, 0x009b6f}, /* U+5B43 */ - {0x00e5ad85, 0x009b70}, /* U+5B45 */ - {0x00e5ad8c, 0x00f296}, /* U+5B4C [2000] */ - {0x00e5ad90, 0x008e71}, /* U+5B50 */ - {0x00e5ad91, 0x009b72}, /* U+5B51 */ - {0x00e5ad92, 0x00f297}, /* U+5B52 [2000] */ - {0x00e5ad94, 0x008d45}, /* U+5B54 */ - {0x00e5ad95, 0x009b73}, /* U+5B55 */ - {0x00e5ad96, 0x009875}, /* U+5B56 [2000] */ - {0x00e5ad97, 0x008e9a}, /* U+5B57 */ - {0x00e5ad98, 0x0091b6}, /* U+5B58 */ - {0x00e5ad9a, 0x009b74}, /* U+5B5A */ - {0x00e5ad9b, 0x009b75}, /* U+5B5B */ - {0x00e5ad9c, 0x008e79}, /* U+5B5C */ - {0x00e5ad9d, 0x008d46}, /* U+5B5D */ - {0x00e5ad9f, 0x0096d0}, /* U+5B5F */ - {0x00e5ada3, 0x008b47}, /* U+5B63 */ - {0x00e5ada4, 0x008cc7}, /* U+5B64 */ - {0x00e5ada5, 0x009b76}, /* U+5B65 */ - {0x00e5ada6, 0x008a77}, /* U+5B66 */ - {0x00e5ada8, 0x00f298}, /* U+5B68 [2000] */ - {0x00e5ada9, 0x009b77}, /* U+5B69 */ - {0x00e5adab, 0x0091b7}, /* U+5B6B */ - {0x00e5adaf, 0x00f299}, /* U+5B6F [2000] */ - {0x00e5adb0, 0x009b78}, /* U+5B70 */ - {0x00e5adb1, 0x009ba1}, /* U+5B71 */ - {0x00e5adb3, 0x009b79}, /* U+5B73 */ - {0x00e5adb5, 0x009b7a}, /* U+5B75 */ - {0x00e5adb8, 0x009b7b}, /* U+5B78 */ - {0x00e5adba, 0x009b7d}, /* U+5B7A */ - {0x00e5adbc, 0x00f29a}, /* U+5B7C [2000] */ - {0x00e5adbd, 0x009876}, /* U+5B7D [2000] */ - {0x00e5adbf, 0x00f29b}, /* U+5B7F [2000] */ - {0x00e5ae80, 0x009b7e}, /* U+5B80 */ - {0x00e5ae81, 0x00f29c}, /* U+5B81 [2000] */ - {0x00e5ae83, 0x009b80}, /* U+5B83 */ - {0x00e5ae84, 0x00f29d}, /* U+5B84 [2000] */ - {0x00e5ae85, 0x0091ee}, /* U+5B85 */ - {0x00e5ae87, 0x008946}, /* U+5B87 */ - {0x00e5ae88, 0x008ee7}, /* U+5B88 */ - {0x00e5ae89, 0x0088c0}, /* U+5B89 */ - {0x00e5ae8b, 0x009176}, /* U+5B8B */ - {0x00e5ae8c, 0x008aae}, /* U+5B8C */ - {0x00e5ae8d, 0x008eb3}, /* U+5B8D */ - {0x00e5ae8f, 0x008d47}, /* U+5B8F */ - {0x00e5ae93, 0x009877}, /* U+5B93 [2000] */ - {0x00e5ae95, 0x009386}, /* U+5B95 */ - {0x00e5ae96, 0x00f09f}, /* U+5B96 [2000] */ - {0x00e5ae97, 0x008f40}, /* U+5B97 */ - {0x00e5ae98, 0x008aaf}, /* U+5B98 */ - {0x00e5ae99, 0x009288}, /* U+5B99 */ - {0x00e5ae9a, 0x0092e8}, /* U+5B9A */ - {0x00e5ae9b, 0x0088b6}, /* U+5B9B */ - {0x00e5ae9c, 0x008b58}, /* U+5B9C */ - {0x00e5ae9d, 0x0095f3}, /* U+5B9D */ - {0x00e5ae9f, 0x008ec0}, /* U+5B9F */ - {0x00e5aea2, 0x008b71}, /* U+5BA2 */ - {0x00e5aea3, 0x0090e9}, /* U+5BA3 */ - {0x00e5aea4, 0x008eba}, /* U+5BA4 */ - {0x00e5aea5, 0x009747}, /* U+5BA5 */ - {0x00e5aea6, 0x009b81}, /* U+5BA6 */ - {0x00e5aeac, 0x00f0a0}, /* U+5BAC [2000] */ - {0x00e5aeae, 0x008b7b}, /* U+5BAE */ - {0x00e5aeb0, 0x008dc9}, /* U+5BB0 */ - {0x00e5aeb3, 0x008a51}, /* U+5BB3 */ - {0x00e5aeb4, 0x008983}, /* U+5BB4 */ - {0x00e5aeb5, 0x008faa}, /* U+5BB5 */ - {0x00e5aeb6, 0x0089c6}, /* U+5BB6 */ - {0x00e5aeb8, 0x009b82}, /* U+5BB8 */ - {0x00e5aeb9, 0x009765}, /* U+5BB9 */ - {0x00e5aebf, 0x008f68}, /* U+5BBF */ - {0x00e5af80, 0x00f0a2}, /* U+5BC0 [2000] */ - {0x00e5af82, 0x008ee2}, /* U+5BC2 */ - {0x00e5af83, 0x009b83}, /* U+5BC3 */ - {0x00e5af84, 0x008af1}, /* U+5BC4 */ - {0x00e5af85, 0x0093d0}, /* U+5BC5 */ - {0x00e5af86, 0x0096a7}, /* U+5BC6 */ - {0x00e5af87, 0x009b84}, /* U+5BC7 */ - {0x00e5af89, 0x009b85}, /* U+5BC9 */ - {0x00e5af8c, 0x009578}, /* U+5BCC */ - {0x00e5af8e, 0x00f0a4}, /* U+5BCE [2000] */ - {0x00e5af90, 0x009b87}, /* U+5BD0 */ - {0x00e5af92, 0x008aa6}, /* U+5BD2 */ - {0x00e5af93, 0x008bf5}, /* U+5BD3 */ - {0x00e5af94, 0x009b86}, /* U+5BD4 */ - {0x00e5af96, 0x00f0a5}, /* U+5BD6 [2000] */ - {0x00e5af98, 0x009878}, /* U+5BD8 [2000] */ - {0x00e5af9b, 0x008ab0}, /* U+5BDB */ - {0x00e5af9d, 0x009051}, /* U+5BDD */ - {0x00e5af9e, 0x009b8b}, /* U+5BDE */ - {0x00e5af9f, 0x008e40}, /* U+5BDF */ - {0x00e5afa1, 0x0089c7}, /* U+5BE1 */ - {0x00e5afa2, 0x009b8a}, /* U+5BE2 */ - {0x00e5afa4, 0x009b88}, /* U+5BE4 */ - {0x00e5afa5, 0x009b8c}, /* U+5BE5 */ - {0x00e5afa6, 0x009b89}, /* U+5BE6 */ - {0x00e5afa7, 0x00944a}, /* U+5BE7 */ - {0x00e5afa8, 0x009ecb}, /* U+5BE8 */ - {0x00e5afa9, 0x009052}, /* U+5BE9 */ - {0x00e5afab, 0x009b8d}, /* U+5BEB */ - {0x00e5afac, 0x009879}, /* U+5BEC [2000] */ - {0x00e5afae, 0x0097be}, /* U+5BEE */ - {0x00e5afb0, 0x009b8e}, /* U+5BF0 */ - {0x00e5afb1, 0x00f0a8}, /* U+5BF1 [2000] */ - {0x00e5afb3, 0x009b90}, /* U+5BF3 */ - {0x00e5afb5, 0x00929e}, /* U+5BF5 */ - {0x00e5afb6, 0x009b8f}, /* U+5BF6 */ - {0x00e5afb8, 0x0090a1}, /* U+5BF8 */ - {0x00e5afba, 0x008e9b}, /* U+5BFA */ - {0x00e5afbd, 0x00f0a9}, /* U+5BFD [2000] */ - {0x00e5afbe, 0x0091ce}, /* U+5BFE */ - {0x00e5afbf, 0x008ef5}, /* U+5BFF */ - {0x00e5b081, 0x009595}, /* U+5C01 */ - {0x00e5b082, 0x0090ea}, /* U+5C02 */ - {0x00e5b083, 0x00f0ab}, /* U+5C03 [2000] */ - {0x00e5b084, 0x008ecb}, /* U+5C04 */ - {0x00e5b085, 0x009b91}, /* U+5C05 */ - {0x00e5b086, 0x008fab}, /* U+5C06 */ - {0x00e5b087, 0x009b92}, /* U+5C07 */ - {0x00e5b088, 0x009b93}, /* U+5C08 */ - {0x00e5b089, 0x0088d1}, /* U+5C09 */ - {0x00e5b08a, 0x0091b8}, /* U+5C0A */ - {0x00e5b08b, 0x009071}, /* U+5C0B */ - {0x00e5b08d, 0x009b94}, /* U+5C0D */ - {0x00e5b08e, 0x0093b1}, /* U+5C0E */ - {0x00e5b08f, 0x008fac}, /* U+5C0F */ - {0x00e5b091, 0x008fad}, /* U+5C11 */ - {0x00e5b092, 0x00987a}, /* U+5C12 [2000] */ - {0x00e5b093, 0x009b95}, /* U+5C13 */ - {0x00e5b096, 0x0090eb}, /* U+5C16 */ - {0x00e5b09a, 0x008fae}, /* U+5C1A */ - {0x00e5b09e, 0x00987b}, /* U+5C1E [2000] */ - {0x00e5b0a0, 0x009b96}, /* U+5C20 */ - {0x00e5b0a2, 0x009b97}, /* U+5C22 */ - {0x00e5b0a3, 0x00987c}, /* U+5C23 [2000] */ - {0x00e5b0a4, 0x0096de}, /* U+5C24 */ - {0x00e5b0a8, 0x009b98}, /* U+5C28 */ - {0x00e5b0a9, 0x00f0ac}, /* U+5C29 [2000] */ - {0x00e5b0ab, 0x00987d}, /* U+5C2B [2000] */ - {0x00e5b0ad, 0x008bc4}, /* U+5C2D */ - {0x00e5b0b0, 0x00f0ad}, /* U+5C30 [2000] */ - {0x00e5b0b1, 0x008f41}, /* U+5C31 */ - {0x00e5b0b8, 0x009b99}, /* U+5C38 */ - {0x00e5b0b9, 0x009b9a}, /* U+5C39 */ - {0x00e5b0ba, 0x008eda}, /* U+5C3A */ - {0x00e5b0bb, 0x00904b}, /* U+5C3B */ - {0x00e5b0bc, 0x0093f2}, /* U+5C3C */ - {0x00e5b0bd, 0x009073}, /* U+5C3D */ - {0x00e5b0be, 0x0094f6}, /* U+5C3E */ - {0x00e5b0bf, 0x009441}, /* U+5C3F */ - {0x00e5b180, 0x008bc7}, /* U+5C40 */ - {0x00e5b181, 0x009b9b}, /* U+5C41 */ - {0x00e5b185, 0x008b8f}, /* U+5C45 */ - {0x00e5b186, 0x009b9c}, /* U+5C46 */ - {0x00e5b188, 0x008bfc}, /* U+5C48 */ - {0x00e5b18a, 0x0093cd}, /* U+5C4A */ - {0x00e5b18b, 0x0089ae}, /* U+5C4B */ - {0x00e5b18d, 0x008e72}, /* U+5C4D */ - {0x00e5b18e, 0x009b9d}, /* U+5C4E */ - {0x00e5b18f, 0x009ba0}, /* U+5C4F */ - {0x00e5b190, 0x009b9f}, /* U+5C50 */ - {0x00e5b191, 0x008bfb}, /* U+5C51 */ - {0x00e5b193, 0x009b9e}, /* U+5C53 */ - {0x00e5b195, 0x009357}, /* U+5C55 */ - {0x00e5b19b, 0x00eff9}, /* U+5C5B [2004] */ - {0x00e5b19e, 0x0091ae}, /* U+5C5E */ - {0x00e5b19f, 0x00f0af}, /* U+5C5F [2000] */ - {0x00e5b1a0, 0x00936a}, /* U+5C60 */ - {0x00e5b1a1, 0x008ec6}, /* U+5C61 */ - {0x00e5b1a2, 0x009880}, /* U+5C62 [2000] */ - {0x00e5b1a3, 0x00f0b0}, /* U+5C63 [2000] */ - {0x00e5b1a4, 0x009177}, /* U+5C64 */ - {0x00e5b1a5, 0x00979a}, /* U+5C65 */ - {0x00e5b1a7, 0x00f0b1}, /* U+5C67 [2000] */ - {0x00e5b1a8, 0x00f0b2}, /* U+5C68 [2000] */ - {0x00e5b1a9, 0x00f0b3}, /* U+5C69 [2000] */ - {0x00e5b1ac, 0x009ba2}, /* U+5C6C */ - {0x00e5b1ae, 0x009ba3}, /* U+5C6E */ - {0x00e5b1af, 0x0093d4}, /* U+5C6F */ - {0x00e5b1b0, 0x00f0b4}, /* U+5C70 [2000] */ - {0x00e5b1b1, 0x008e52}, /* U+5C71 */ - {0x00e5b1b6, 0x009ba5}, /* U+5C76 */ - {0x00e5b1b9, 0x009ba6}, /* U+5C79 */ - {0x00e5b1ba, 0x009884}, /* U+5C7A [2000] */ - {0x00e5b1bc, 0x00f0b7}, /* U+5C7C [2000] */ - {0x00e5b288, 0x00f0ba}, /* U+5C88 [2000] */ - {0x00e5b28a, 0x00f0bb}, /* U+5C8A [2000] */ - {0x00e5b28c, 0x009ba7}, /* U+5C8C */ - {0x00e5b28f, 0x009885}, /* U+5C8F [2000] */ - {0x00e5b290, 0x008af2}, /* U+5C90 */ - {0x00e5b291, 0x009ba8}, /* U+5C91 */ - {0x00e5b294, 0x009ba9}, /* U+5C94 */ - {0x00e5b29f, 0x009886}, /* U+5C9F [2000] */ - {0x00e5b2a0, 0x00f0bf}, /* U+5CA0 [2000] */ - {0x00e5b2a1, 0x0089aa}, /* U+5CA1 */ - {0x00e5b2a2, 0x00f0c0}, /* U+5CA2 [2000] */ - {0x00e5b2a3, 0x009887}, /* U+5CA3 [2000] */ - {0x00e5b2a6, 0x00f0c1}, /* U+5CA6 [2000] */ - {0x00e5b2a7, 0x00f0c2}, /* U+5CA7 [2000] */ - {0x00e5b2a8, 0x00915a}, /* U+5CA8 */ - {0x00e5b2a9, 0x008ae2}, /* U+5CA9 */ - {0x00e5b2aa, 0x009888}, /* U+5CAA [2000] */ - {0x00e5b2ab, 0x009bab}, /* U+5CAB */ - {0x00e5b2ac, 0x0096a6}, /* U+5CAC */ - {0x00e5b2ad, 0x00f0c4}, /* U+5CAD [2000] */ - {0x00e5b2b1, 0x0091d0}, /* U+5CB1 */ - {0x00e5b2b3, 0x008a78}, /* U+5CB3 */ - {0x00e5b2b5, 0x00f0c5}, /* U+5CB5 [2000] */ - {0x00e5b2b6, 0x009bad}, /* U+5CB6 */ - {0x00e5b2b7, 0x009baf}, /* U+5CB7 */ - {0x00e5b2b8, 0x008add}, /* U+5CB8 */ - {0x00e5b2ba, 0x009889}, /* U+5CBA [2000] */ - {0x00e5b2bb, 0x009bac}, /* U+5CBB */ - {0x00e5b2bc, 0x009bae}, /* U+5CBC */ - {0x00e5b2be, 0x009bb1}, /* U+5CBE */ - {0x00e5b385, 0x009bb0}, /* U+5CC5 */ - {0x00e5b387, 0x009bb2}, /* U+5CC7 */ - {0x00e5b389, 0x00f0c7}, /* U+5CC9 [2000] */ - {0x00e5b38b, 0x00988a}, /* U+5CCB [2000] */ - {0x00e5b390, 0x00988b}, /* U+5CD0 [2000] */ - {0x00e5b392, 0x00988c}, /* U+5CD2 [2000] */ - {0x00e5b399, 0x009bb3}, /* U+5CD9 */ - {0x00e5b3a0, 0x0093bb}, /* U+5CE0 */ - {0x00e5b3a1, 0x008bac}, /* U+5CE1 */ - {0x00e5b3a8, 0x0089e3}, /* U+5CE8 */ - {0x00e5b3a9, 0x009bb4}, /* U+5CE9 */ - {0x00e5b3aa, 0x009bb9}, /* U+5CEA */ - {0x00e5b3ad, 0x009bb7}, /* U+5CED */ - {0x00e5b3af, 0x0095f5}, /* U+5CEF */ - {0x00e5b3b0, 0x0095f4}, /* U+5CF0 */ - {0x00e5b3b4, 0x00988d}, /* U+5CF4 [2000] */ - {0x00e5b3b6, 0x009387}, /* U+5CF6 */ - {0x00e5b3ba, 0x009bb6}, /* U+5CFA */ - {0x00e5b3bb, 0x008f73}, /* U+5CFB */ - {0x00e5b3bd, 0x009bb5}, /* U+5CFD */ - {0x00e5b486, 0x00f0ca}, /* U+5D06 [2000] */ - {0x00e5b487, 0x009092}, /* U+5D07 */ - {0x00e5b48b, 0x009bba}, /* U+5D0B */ - {0x00e5b48d, 0x009890}, /* U+5D0D [2000] */ - {0x00e5b48e, 0x008de8}, /* U+5D0E */ - {0x00e5b490, 0x00f0cb}, /* U+5D10 [2000] */ - {0x00e5b491, 0x009bc0}, /* U+5D11 */ - {0x00e5b494, 0x009bc1}, /* U+5D14 */ - {0x00e5b495, 0x009bbb}, /* U+5D15 */ - {0x00e5b496, 0x008a52}, /* U+5D16 */ - {0x00e5b497, 0x009bbc}, /* U+5D17 */ - {0x00e5b498, 0x009bc5}, /* U+5D18 */ - {0x00e5b499, 0x009bc4}, /* U+5D19 */ - {0x00e5b49a, 0x009bc3}, /* U+5D1A */ - {0x00e5b49b, 0x009bbf}, /* U+5D1B */ - {0x00e5b49d, 0x00f0cd}, /* U+5D1D [2000] */ - {0x00e5b49f, 0x009bbe}, /* U+5D1F */ - {0x00e5b4a0, 0x00f0ce}, /* U+5D20 [2000] */ - {0x00e5b4a2, 0x009bc2}, /* U+5D22 */ - {0x00e5b4a4, 0x00f0cf}, /* U+5D24 [2000] */ - {0x00e5b4a6, 0x00f0d0}, /* U+5D26 [2000] */ - {0x00e5b4a7, 0x009891}, /* U+5D27 [2000] */ - {0x00e5b4a9, 0x0095f6}, /* U+5D29 */ - {0x00e5b4ab, 0x00f0cc}, /* U+5D2B [2000] */ - {0x00e5b4b1, 0x00f0d1}, /* U+5D31 [2000] */ - {0x00e5b4b9, 0x00f0d2}, /* U+5D39 [2000] */ - {0x00e5b582, 0x00f0d3}, /* U+5D42 [2000] */ - {0x00e5b586, 0x009893}, /* U+5D46 [2000] */ - {0x00e5b587, 0x009894}, /* U+5D47 [2000] */ - {0x00e5b58a, 0x009896}, /* U+5D4A [2000] */ - {0x00e5b58b, 0x009bc9}, /* U+5D4B */ - {0x00e5b58c, 0x009bc6}, /* U+5D4C */ - {0x00e5b58e, 0x009bc8}, /* U+5D4E */ - {0x00e5b590, 0x009792}, /* U+5D50 */ - {0x00e5b592, 0x009bc7}, /* U+5D52 */ - {0x00e5b593, 0x009895}, /* U+5D53 [2000] */ - {0x00e5b59c, 0x009bbd}, /* U+5D5C */ - {0x00e5b5a1, 0x00f0d5}, /* U+5D61 [2000] */ - {0x00e5b5a9, 0x009093}, /* U+5D69 */ - {0x00e5b5aa, 0x00f0d6}, /* U+5D6A [2000] */ - {0x00e5b5ac, 0x009bca}, /* U+5D6C */ - {0x00e5b5ad, 0x009897}, /* U+5D6D [2000] */ - {0x00e5b5af, 0x008db5}, /* U+5D6F */ - {0x00e5b5b0, 0x00f0d8}, /* U+5D70 [2000] */ - {0x00e5b5b3, 0x009bcb}, /* U+5D73 */ - {0x00e5b5b6, 0x009bcc}, /* U+5D76 */ - {0x00e5b681, 0x009898}, /* U+5D81 [2000] */ - {0x00e5b682, 0x009bcf}, /* U+5D82 */ - {0x00e5b684, 0x009bce}, /* U+5D84 */ - {0x00e5b687, 0x009bcd}, /* U+5D87 */ - {0x00e5b688, 0x00f0db}, /* U+5D88 [2000] */ - {0x00e5b68b, 0x009388}, /* U+5D8B */ - {0x00e5b68c, 0x009bb8}, /* U+5D8C */ - {0x00e5b690, 0x009bd5}, /* U+5D90 */ - {0x00e5b692, 0x00f0dd}, /* U+5D92 [2000] */ - {0x00e5b694, 0x00f0de}, /* U+5D94 [2000] */ - {0x00e5b697, 0x00f0df}, /* U+5D97 [2000] */ - {0x00e5b699, 0x00f0e0}, /* U+5D99 [2000] */ - {0x00e5b69d, 0x009bd1}, /* U+5D9D */ - {0x00e5b6a0, 0x009899}, /* U+5DA0 [2000] */ - {0x00e5b6a2, 0x009bd0}, /* U+5DA2 */ - {0x00e5b6a4, 0x00989a}, /* U+5DA4 [2000] */ - {0x00e5b6a7, 0x00989b}, /* U+5DA7 [2000] */ - {0x00e5b6ac, 0x009bd2}, /* U+5DAC */ - {0x00e5b6ae, 0x009bd3}, /* U+5DAE */ - {0x00e5b6b0, 0x00f0e1}, /* U+5DB0 [2000] */ - {0x00e5b6b2, 0x00f0e2}, /* U+5DB2 [2000] */ - {0x00e5b6b4, 0x00f0e3}, /* U+5DB4 [2000] */ - {0x00e5b6b7, 0x009bd6}, /* U+5DB7 */ - {0x00e5b6b8, 0x00989c}, /* U+5DB8 [2000] */ - {0x00e5b6b9, 0x00f0e5}, /* U+5DB9 [2000] */ - {0x00e5b6ba, 0x0097e4}, /* U+5DBA */ - {0x00e5b6bc, 0x009bd7}, /* U+5DBC */ - {0x00e5b6bd, 0x009bd4}, /* U+5DBD */ - {0x00e5b789, 0x009bd8}, /* U+5DC9 */ - {0x00e5b78b, 0x00989d}, /* U+5DCB [2000] */ - {0x00e5b78c, 0x008ade}, /* U+5DCC */ - {0x00e5b78d, 0x009bd9}, /* U+5DCD */ - {0x00e5b791, 0x00f0e6}, /* U+5DD1 [2000] */ - {0x00e5b792, 0x009bdb}, /* U+5DD2 */ - {0x00e5b793, 0x009bda}, /* U+5DD3 */ - {0x00e5b796, 0x009bdc}, /* U+5DD6 */ - {0x00e5b797, 0x00f0e7}, /* U+5DD7 [2000] */ - {0x00e5b798, 0x00f0e8}, /* U+5DD8 [2000] */ - {0x00e5b79b, 0x009bdd}, /* U+5DDB */ - {0x00e5b79d, 0x0090ec}, /* U+5DDD */ - {0x00e5b79e, 0x008f42}, /* U+5DDE */ - {0x00e5b7a0, 0x00f0e9}, /* U+5DE0 [2000] */ - {0x00e5b7a1, 0x008f84}, /* U+5DE1 */ - {0x00e5b7a2, 0x00eaa6}, /* U+5DE2 [2000] */ - {0x00e5b7a3, 0x009183}, /* U+5DE3 */ - {0x00e5b7a4, 0x00f0eb}, /* U+5DE4 [2000] */ - {0x00e5b7a5, 0x008d48}, /* U+5DE5 */ - {0x00e5b7a6, 0x008db6}, /* U+5DE6 */ - {0x00e5b7a7, 0x008d49}, /* U+5DE7 */ - {0x00e5b7a8, 0x008b90}, /* U+5DE8 */ - {0x00e5b7a9, 0x00f0ec}, /* U+5DE9 [2000] */ - {0x00e5b7ab, 0x009bde}, /* U+5DEB */ - {0x00e5b7ae, 0x008db7}, /* U+5DEE */ - {0x00e5b7b1, 0x008cc8}, /* U+5DF1 */ - {0x00e5b7b2, 0x009bdf}, /* U+5DF2 */ - {0x00e5b7b3, 0x0096a4}, /* U+5DF3 */ - {0x00e5b7b4, 0x009462}, /* U+5DF4 */ - {0x00e5b7b5, 0x009be0}, /* U+5DF5 */ - {0x00e5b7b7, 0x008d4a}, /* U+5DF7 */ - {0x00e5b7bb, 0x008aaa}, /* U+5DFB */ - {0x00e5b7bd, 0x009246}, /* U+5DFD */ - {0x00e5b7be, 0x008bd0}, /* U+5DFE */ - {0x00e5b880, 0x00f0ee}, /* U+5E00 [2000] */ - {0x00e5b882, 0x008e73}, /* U+5E02 */ - {0x00e5b883, 0x00957a}, /* U+5E03 */ - {0x00e5b886, 0x0094bf}, /* U+5E06 */ - {0x00e5b88b, 0x009be1}, /* U+5E0B */ - {0x00e5b88c, 0x008af3}, /* U+5E0C */ - {0x00e5b891, 0x009be4}, /* U+5E11 */ - {0x00e5b892, 0x00f0f0}, /* U+5E12 [2000] */ - {0x00e5b894, 0x00eaa7}, /* U+5E14 [2000] */ - {0x00e5b895, 0x00f0f1}, /* U+5E15 [2000] */ - {0x00e5b896, 0x00929f}, /* U+5E16 */ - {0x00e5b898, 0x00eaa8}, /* U+5E18 [2000] */ - {0x00e5b899, 0x009be3}, /* U+5E19 */ - {0x00e5b89a, 0x009be2}, /* U+5E1A */ - {0x00e5b89b, 0x009be5}, /* U+5E1B */ - {0x00e5b89d, 0x0092e9}, /* U+5E1D */ - {0x00e5b89f, 0x00f0f3}, /* U+5E1F [2000] */ - {0x00e5b8a5, 0x009083}, /* U+5E25 */ - {0x00e5b8ab, 0x008e74}, /* U+5E2B */ - {0x00e5b8ad, 0x0090c8}, /* U+5E2D */ - {0x00e5b8ae, 0x00f0f4}, /* U+5E2E [2000] */ - {0x00e5b8af, 0x0091d1}, /* U+5E2F */ - {0x00e5b8b0, 0x008b41}, /* U+5E30 */ - {0x00e5b8b3, 0x0092a0}, /* U+5E33 */ - {0x00e5b8b6, 0x009be6}, /* U+5E36 */ - {0x00e5b8b7, 0x009be7}, /* U+5E37 */ - {0x00e5b8b8, 0x008fed}, /* U+5E38 */ - {0x00e5b8bd, 0x009658}, /* U+5E3D */ - {0x00e5b8be, 0x00f0f5}, /* U+5E3E [2000] */ - {0x00e5b980, 0x009bea}, /* U+5E40 */ - {0x00e5b983, 0x009be9}, /* U+5E43 */ - {0x00e5b984, 0x009be8}, /* U+5E44 */ - {0x00e5b985, 0x00959d}, /* U+5E45 */ - {0x00e5b987, 0x009bf1}, /* U+5E47 */ - {0x00e5b989, 0x00f0f6}, /* U+5E49 [2000] */ - {0x00e5b98c, 0x009679}, /* U+5E4C */ - {0x00e5b98e, 0x009beb}, /* U+5E4E */ - {0x00e5b994, 0x009bed}, /* U+5E54 */ - {0x00e5b995, 0x00968b}, /* U+5E55 */ - {0x00e5b996, 0x00f0f8}, /* U+5E56 [2000] */ - {0x00e5b997, 0x009bec}, /* U+5E57 */ - {0x00e5b998, 0x00eaa9}, /* U+5E58 [2000] */ - {0x00e5b99e, 0x00eaaa}, /* U+5E5E [2000] */ - {0x00e5b99f, 0x009bee}, /* U+5E5F */ - {0x00e5b9a1, 0x0094a6}, /* U+5E61 */ - {0x00e5b9a2, 0x009bef}, /* U+5E62 */ - {0x00e5b9a3, 0x0095bc}, /* U+5E63 */ - {0x00e5b9a4, 0x009bf0}, /* U+5E64 */ - {0x00e5b9ab, 0x00f0fa}, /* U+5E6B [2000] */ - {0x00e5b9ac, 0x00f0fb}, /* U+5E6C [2000] */ - {0x00e5b9ad, 0x00f0fc}, /* U+5E6D [2000] */ - {0x00e5b9ae, 0x00f29f}, /* U+5E6E [2000] */ - {0x00e5b9b2, 0x008ab1}, /* U+5E72 */ - {0x00e5b9b3, 0x0095bd}, /* U+5E73 */ - {0x00e5b9b4, 0x00944e}, /* U+5E74 */ - {0x00e5b9b5, 0x009bf2}, /* U+5E75 */ - {0x00e5b9b6, 0x009bf3}, /* U+5E76 */ - {0x00e5b9b7, 0x00effa}, /* U+5E77 [2004] */ - {0x00e5b9b8, 0x008d4b}, /* U+5E78 */ - {0x00e5b9b9, 0x008ab2}, /* U+5E79 */ - {0x00e5b9ba, 0x009bf4}, /* U+5E7A */ - {0x00e5b9bb, 0x008cb6}, /* U+5E7B */ - {0x00e5b9bc, 0x009763}, /* U+5E7C */ - {0x00e5b9bd, 0x009748}, /* U+5E7D */ - {0x00e5b9be, 0x008af4}, /* U+5E7E */ - {0x00e5b9bf, 0x009bf6}, /* U+5E7F */ - {0x00e5ba81, 0x0092a1}, /* U+5E81 */ - {0x00e5ba83, 0x008d4c}, /* U+5E83 */ - {0x00e5ba84, 0x008faf}, /* U+5E84 */ - {0x00e5ba87, 0x0094dd}, /* U+5E87 */ - {0x00e5ba8a, 0x008fb0}, /* U+5E8A */ - {0x00e5ba8f, 0x008f98}, /* U+5E8F */ - {0x00e5ba95, 0x0092ea}, /* U+5E95 */ - {0x00e5ba96, 0x0095f7}, /* U+5E96 */ - {0x00e5ba97, 0x009358}, /* U+5E97 */ - {0x00e5ba9a, 0x008d4d}, /* U+5E9A */ - {0x00e5ba9c, 0x00957b}, /* U+5E9C */ - {0x00e5baa0, 0x009bf7}, /* U+5EA0 */ - {0x00e5baa5, 0x00f2a1}, /* U+5EA5 [2000] */ - {0x00e5baa6, 0x009378}, /* U+5EA6 */ - {0x00e5baa7, 0x008dc0}, /* U+5EA7 */ - {0x00e5baaa, 0x00f2a2}, /* U+5EAA [2000] */ - {0x00e5baab, 0x008cc9}, /* U+5EAB */ - {0x00e5baac, 0x00f2a3}, /* U+5EAC [2000] */ - {0x00e5baad, 0x0092eb}, /* U+5EAD */ - {0x00e5bab5, 0x0088c1}, /* U+5EB5 */ - {0x00e5bab6, 0x008f8e}, /* U+5EB6 */ - {0x00e5bab7, 0x008d4e}, /* U+5EB7 */ - {0x00e5bab8, 0x009766}, /* U+5EB8 */ - {0x00e5bab9, 0x00f2a4}, /* U+5EB9 [2000] */ - {0x00e5babe, 0x00eaab}, /* U+5EBE [2000] */ - {0x00e5babf, 0x00f2a5}, /* U+5EBF [2000] */ - {0x00e5bb81, 0x009bf8}, /* U+5EC1 */ - {0x00e5bb82, 0x009bf9}, /* U+5EC2 */ - {0x00e5bb83, 0x009470}, /* U+5EC3 */ - {0x00e5bb86, 0x00f2a6}, /* U+5EC6 [2000] */ - {0x00e5bb88, 0x009bfa}, /* U+5EC8 */ - {0x00e5bb89, 0x0097f5}, /* U+5EC9 */ - {0x00e5bb8a, 0x00984c}, /* U+5ECA */ - {0x00e5bb8b, 0x00eaad}, /* U+5ECB [2000] */ - {0x00e5bb8f, 0x009bfc}, /* U+5ECF */ - {0x00e5bb90, 0x009bfb}, /* U+5ED0 */ - {0x00e5bb92, 0x00f2a7}, /* U+5ED2 [2000] */ - {0x00e5bb93, 0x008a66}, /* U+5ED3 */ - {0x00e5bb96, 0x009c40}, /* U+5ED6 */ - {0x00e5bb99, 0x00f2a8}, /* U+5ED9 [2000] */ - {0x00e5bb9a, 0x009c43}, /* U+5EDA */ - {0x00e5bb9b, 0x009c44}, /* U+5EDB */ - {0x00e5bb9d, 0x009c42}, /* U+5EDD */ - {0x00e5bb9f, 0x00955f}, /* U+5EDF */ - {0x00e5bba0, 0x008fb1}, /* U+5EE0 */ - {0x00e5bba1, 0x009c46}, /* U+5EE1 */ - {0x00e5bba2, 0x009c45}, /* U+5EE2 */ - {0x00e5bba3, 0x009c41}, /* U+5EE3 */ - {0x00e5bba8, 0x009c47}, /* U+5EE8 */ - {0x00e5bba9, 0x009c48}, /* U+5EE9 */ - {0x00e5bbac, 0x009c49}, /* U+5EEC */ - {0x00e5bbb0, 0x009c4c}, /* U+5EF0 */ - {0x00e5bbb1, 0x009c4a}, /* U+5EF1 */ - {0x00e5bbb3, 0x009c4b}, /* U+5EF3 */ - {0x00e5bbb4, 0x009c4d}, /* U+5EF4 */ - {0x00e5bbb6, 0x008984}, /* U+5EF6 */ - {0x00e5bbb7, 0x0092ec}, /* U+5EF7 */ - {0x00e5bbb8, 0x009c4e}, /* U+5EF8 */ - {0x00e5bbb9, 0x00eaae}, /* U+5EF9 [2000] */ - {0x00e5bbba, 0x008c9a}, /* U+5EFA */ - {0x00e5bbbb, 0x0089f4}, /* U+5EFB */ - {0x00e5bbbc, 0x009455}, /* U+5EFC */ - {0x00e5bbbd, 0x00f2aa}, /* U+5EFD [2000] */ - {0x00e5bbbe, 0x009c4f}, /* U+5EFE */ - {0x00e5bbbf, 0x0093f9}, /* U+5EFF */ - {0x00e5bc80, 0x00eaaf}, /* U+5F00 [2000] */ - {0x00e5bc81, 0x0095d9}, /* U+5F01 */ - {0x00e5bc82, 0x00eab0}, /* U+5F02 [2000] */ - {0x00e5bc83, 0x009c50}, /* U+5F03 */ - {0x00e5bc84, 0x00984d}, /* U+5F04 */ - {0x00e5bc87, 0x00eab1}, /* U+5F07 [2000] */ - {0x00e5bc88, 0x00f2ab}, /* U+5F08 [2000] */ - {0x00e5bc89, 0x009c51}, /* U+5F09 */ - {0x00e5bc8a, 0x0095be}, /* U+5F0A */ - {0x00e5bc8b, 0x009c54}, /* U+5F0B */ - {0x00e5bc8c, 0x00989f}, /* U+5F0C */ - {0x00e5bc8d, 0x0098af}, /* U+5F0D */ - {0x00e5bc8e, 0x00f2ac}, /* U+5F0E [2000] */ - {0x00e5bc8f, 0x008eae}, /* U+5F0F */ - {0x00e5bc90, 0x0093f3}, /* U+5F10 */ - {0x00e5bc91, 0x009c55}, /* U+5F11 */ - {0x00e5bc93, 0x008b7c}, /* U+5F13 */ - {0x00e5bc94, 0x0092a2}, /* U+5F14 */ - {0x00e5bc95, 0x0088f8}, /* U+5F15 */ - {0x00e5bc96, 0x009c56}, /* U+5F16 */ - {0x00e5bc97, 0x0095a4}, /* U+5F17 */ - {0x00e5bc98, 0x008d4f}, /* U+5F18 */ - {0x00e5bc9b, 0x00926f}, /* U+5F1B */ - {0x00e5bc9c, 0x00f2ad}, /* U+5F1C [2000] */ - {0x00e5bc9d, 0x00eab2}, /* U+5F1D [2000] */ - {0x00e5bc9e, 0x00f2af}, /* U+5F1E [2000] */ - {0x00e5bc9f, 0x0092ed}, /* U+5F1F */ - {0x00e5bca3, 0x00eab3}, /* U+5F23 [2000] */ - {0x00e5bca5, 0x0096ed}, /* U+5F25 */ - {0x00e5bca6, 0x008cb7}, /* U+5F26 */ - {0x00e5bca7, 0x008cca}, /* U+5F27 */ - {0x00e5bca9, 0x009c57}, /* U+5F29 */ - {0x00e5bcad, 0x009c58}, /* U+5F2D */ - {0x00e5bcaf, 0x009c5e}, /* U+5F2F */ - {0x00e5bcb1, 0x008ee3}, /* U+5F31 */ - {0x00e5bcb4, 0x00eab4}, /* U+5F34 [2000] */ - {0x00e5bcb5, 0x0092a3}, /* U+5F35 */ - {0x00e5bcb6, 0x00eab5}, /* U+5F36 [2000] */ - {0x00e5bcb7, 0x008bad}, /* U+5F37 */ - {0x00e5bcb8, 0x009c59}, /* U+5F38 */ - {0x00e5bcbc, 0x00954a}, /* U+5F3C */ - {0x00e5bcbd, 0x00eab6}, /* U+5F3D [2000] */ - {0x00e5bcbe, 0x009265}, /* U+5F3E */ - {0x00e5bd80, 0x00eab7}, /* U+5F40 [2000] */ - {0x00e5bd81, 0x009c5a}, /* U+5F41 */ - {0x00e5bd85, 0x00eab8}, /* U+5F45 [2000] */ - {0x00e5bd87, 0x00f2b0}, /* U+5F47 [2000] */ - {0x00e5bd88, 0x009c5b}, /* U+5F48 */ - {0x00e5bd8a, 0x008bae}, /* U+5F4A */ - {0x00e5bd8c, 0x009c5c}, /* U+5F4C */ - {0x00e5bd8e, 0x009c5d}, /* U+5F4E */ - {0x00e5bd91, 0x009c5f}, /* U+5F51 */ - {0x00e5bd93, 0x009396}, /* U+5F53 */ - {0x00e5bd94, 0x00eab9}, /* U+5F54 [2000] */ - {0x00e5bd96, 0x009c60}, /* U+5F56 */ - {0x00e5bd97, 0x009c61}, /* U+5F57 */ - {0x00e5bd98, 0x00eaba}, /* U+5F58 [2000] */ - {0x00e5bd99, 0x009c62}, /* U+5F59 */ - {0x00e5bd9c, 0x009c53}, /* U+5F5C */ - {0x00e5bd9d, 0x009c52}, /* U+5F5D */ - {0x00e5bda1, 0x009c63}, /* U+5F61 */ - {0x00e5bda2, 0x008c60}, /* U+5F62 */ - {0x00e5bda3, 0x00f2b1}, /* U+5F63 [2000] */ - {0x00e5bda4, 0x00eabb}, /* U+5F64 [2000] */ - {0x00e5bda6, 0x009546}, /* U+5F66 */ - {0x00e5bda7, 0x00eabc}, /* U+5F67 [2000] */ - {0x00e5bda9, 0x008dca}, /* U+5F69 */ - {0x00e5bdaa, 0x009556}, /* U+5F6A */ - {0x00e5bdab, 0x0092a4}, /* U+5F6B */ - {0x00e5bdac, 0x00956a}, /* U+5F6C */ - {0x00e5bdad, 0x009c64}, /* U+5F6D */ - {0x00e5bdb0, 0x008fb2}, /* U+5F70 */ - {0x00e5bdb1, 0x008965}, /* U+5F71 */ - {0x00e5bdb2, 0x00f2b2}, /* U+5F72 [2000] */ - {0x00e5bdb3, 0x009c65}, /* U+5F73 */ - {0x00e5bdb7, 0x009c66}, /* U+5F77 */ - {0x00e5bdb9, 0x0096f0}, /* U+5F79 */ - {0x00e5bdbc, 0x0094de}, /* U+5F7C */ - {0x00e5bdbd, 0x00eabd}, /* U+5F7D [2000] */ - {0x00e5bdbe, 0x00f2b3}, /* U+5F7E [2000] */ - {0x00e5bdbf, 0x009c69}, /* U+5F7F */ - {0x00e5be80, 0x00899d}, /* U+5F80 */ - {0x00e5be81, 0x0090aa}, /* U+5F81 */ - {0x00e5be82, 0x009c68}, /* U+5F82 */ - {0x00e5be83, 0x009c67}, /* U+5F83 */ - {0x00e5be84, 0x008c61}, /* U+5F84 */ - {0x00e5be85, 0x0091d2}, /* U+5F85 */ - {0x00e5be87, 0x009c6d}, /* U+5F87 */ - {0x00e5be88, 0x009c6b}, /* U+5F88 */ - {0x00e5be89, 0x00eabe}, /* U+5F89 [2000] */ - {0x00e5be8a, 0x009c6a}, /* U+5F8A */ - {0x00e5be8b, 0x0097a5}, /* U+5F8B */ - {0x00e5be8c, 0x008ce3}, /* U+5F8C */ - {0x00e5be8f, 0x00f2b4}, /* U+5F8F [2000] */ - {0x00e5be90, 0x008f99}, /* U+5F90 */ - {0x00e5be91, 0x009c6c}, /* U+5F91 */ - {0x00e5be92, 0x00936b}, /* U+5F92 */ - {0x00e5be93, 0x008f5d}, /* U+5F93 */ - {0x00e5be97, 0x0093be}, /* U+5F97 */ - {0x00e5be98, 0x009c70}, /* U+5F98 */ - {0x00e5be99, 0x009c6f}, /* U+5F99 */ - {0x00e5be9c, 0x00eabf}, /* U+5F9C [2000] */ - {0x00e5be9e, 0x009c6e}, /* U+5F9E */ - {0x00e5bea0, 0x009c71}, /* U+5FA0 */ - {0x00e5bea1, 0x008ce4}, /* U+5FA1 */ - {0x00e5bea2, 0x00f2b5}, /* U+5FA2 [2000] */ - {0x00e5bea4, 0x00f2b6}, /* U+5FA4 [2000] */ - {0x00e5bea7, 0x00eac0}, /* U+5FA7 [2000] */ - {0x00e5bea8, 0x009c72}, /* U+5FA8 */ - {0x00e5bea9, 0x00959c}, /* U+5FA9 */ - {0x00e5beaa, 0x008f7a}, /* U+5FAA */ - {0x00e5bead, 0x009c73}, /* U+5FAD */ - {0x00e5beae, 0x0094f7}, /* U+5FAE */ - {0x00e5beaf, 0x00eac1}, /* U+5FAF [2000] */ - {0x00e5beb3, 0x0093bf}, /* U+5FB3 */ - {0x00e5beb4, 0x0092a5}, /* U+5FB4 */ - {0x00e5beb5, 0x00eac2}, /* U+5FB5 [2000] */ - {0x00e5beb7, 0x00eac3}, /* U+5FB7 [2000] */ - {0x00e5beb8, 0x00f2b7}, /* U+5FB8 [2000] */ - {0x00e5beb9, 0x00934f}, /* U+5FB9 */ - {0x00e5bebc, 0x009c74}, /* U+5FBC */ - {0x00e5bebd, 0x008b4a}, /* U+5FBD */ - {0x00e5bf83, 0x009053}, /* U+5FC3 */ - {0x00e5bf84, 0x00f2b8}, /* U+5FC4 [2000] */ - {0x00e5bf85, 0x00954b}, /* U+5FC5 */ - {0x00e5bf87, 0x00f2ba}, /* U+5FC7 [2000] */ - {0x00e5bf89, 0x00eac4}, /* U+5FC9 [2000] */ - {0x00e5bf8b, 0x00f2bb}, /* U+5FCB [2000] */ - {0x00e5bf8c, 0x008af5}, /* U+5FCC */ - {0x00e5bf8d, 0x009445}, /* U+5FCD */ - {0x00e5bf92, 0x00f2bc}, /* U+5FD2 [2000] */ - {0x00e5bf93, 0x00f2bd}, /* U+5FD3 [2000] */ - {0x00e5bf94, 0x00f2be}, /* U+5FD4 [2000] */ - {0x00e5bf96, 0x009c75}, /* U+5FD6 */ - {0x00e5bf97, 0x008e75}, /* U+5FD7 */ - {0x00e5bf98, 0x009659}, /* U+5FD8 */ - {0x00e5bf99, 0x00965a}, /* U+5FD9 */ - {0x00e5bf9c, 0x00899e}, /* U+5FDC */ - {0x00e5bf9d, 0x009c7a}, /* U+5FDD */ - {0x00e5bf9e, 0x00eac5}, /* U+5FDE [2000] */ - {0x00e5bfa0, 0x009289}, /* U+5FE0 */ - {0x00e5bfa1, 0x00eac6}, /* U+5FE1 [2000] */ - {0x00e5bfa2, 0x00f2bf}, /* U+5FE2 [2000] */ - {0x00e5bfa4, 0x009c77}, /* U+5FE4 */ - {0x00e5bfa9, 0x00eac7}, /* U+5FE9 [2000] */ - {0x00e5bfab, 0x0089f5}, /* U+5FEB */ - {0x00e5bfae, 0x00f2c0}, /* U+5FEE [2000] */ - {0x00e5bfaf, 0x00f2c1}, /* U+5FEF [2000] */ - {0x00e5bfb0, 0x009cab}, /* U+5FF0 */ - {0x00e5bfb1, 0x009c79}, /* U+5FF1 */ - {0x00e5bfb3, 0x00f2c2}, /* U+5FF3 [2000] */ - {0x00e5bfb5, 0x00944f}, /* U+5FF5 */ - {0x00e5bfb8, 0x009c78}, /* U+5FF8 */ - {0x00e5bfbb, 0x009c76}, /* U+5FFB */ - {0x00e5bfbc, 0x00f2c3}, /* U+5FFC [2000] */ - {0x00e5bfbd, 0x008d9a}, /* U+5FFD */ - {0x00e5bfbf, 0x009c7c}, /* U+5FFF */ - {0x00e6808d, 0x00eac8}, /* U+600D [2000] */ - {0x00e6808e, 0x009c83}, /* U+600E */ - {0x00e6808f, 0x009c89}, /* U+600F */ - {0x00e68090, 0x009c81}, /* U+6010 */ - {0x00e68092, 0x00937b}, /* U+6012 */ - {0x00e68094, 0x00eac9}, /* U+6014 [2000] */ - {0x00e68095, 0x009c86}, /* U+6015 */ - {0x00e68096, 0x00957c}, /* U+6016 */ - {0x00e68097, 0x00f2c5}, /* U+6017 [2000] */ - {0x00e68098, 0x00eaca}, /* U+6018 [2000] */ - {0x00e68099, 0x009c80}, /* U+6019 */ - {0x00e6809b, 0x009c85}, /* U+601B */ - {0x00e6809c, 0x0097e5}, /* U+601C */ - {0x00e6809d, 0x008e76}, /* U+601D */ - {0x00e680a0, 0x0091d3}, /* U+6020 */ - {0x00e680a1, 0x009c7d}, /* U+6021 */ - {0x00e680a2, 0x00f2c6}, /* U+6022 [2000] */ - {0x00e680a4, 0x00f2c7}, /* U+6024 [2000] */ - {0x00e680a5, 0x008b7d}, /* U+6025 */ - {0x00e680a6, 0x009c88}, /* U+6026 */ - {0x00e680a7, 0x0090ab}, /* U+6027 */ - {0x00e680a8, 0x008985}, /* U+6028 */ - {0x00e680a9, 0x009c82}, /* U+6029 */ - {0x00e680aa, 0x0089f6}, /* U+602A */ - {0x00e680ab, 0x009c87}, /* U+602B */ - {0x00e680af, 0x008baf}, /* U+602F */ - {0x00e680b1, 0x009c84}, /* U+6031 */ - {0x00e680b3, 0x00eacb}, /* U+6033 [2000] */ - {0x00e680b5, 0x00eacc}, /* U+6035 [2000] */ - {0x00e680ba, 0x009c8a}, /* U+603A */ - {0x00e68181, 0x009c8c}, /* U+6041 */ - {0x00e68182, 0x009c96}, /* U+6042 */ - {0x00e68183, 0x009c94}, /* U+6043 */ - {0x00e68186, 0x009c91}, /* U+6046 */ - {0x00e68187, 0x00eacd}, /* U+6047 [2000] */ - {0x00e6818a, 0x009c90}, /* U+604A */ - {0x00e6818b, 0x0097f6}, /* U+604B */ - {0x00e6818c, 0x00f2c9}, /* U+604C [2000] */ - {0x00e6818d, 0x009c92}, /* U+604D */ - {0x00e68190, 0x008bb0}, /* U+6050 */ - {0x00e68192, 0x008d50}, /* U+6052 */ - {0x00e68195, 0x008f9a}, /* U+6055 */ - {0x00e68199, 0x009c99}, /* U+6059 */ - {0x00e6819a, 0x009c8b}, /* U+605A */ - {0x00e6819f, 0x009c8f}, /* U+605F */ - {0x00e681a0, 0x009c7e}, /* U+6060 */ - {0x00e681a2, 0x0089f8}, /* U+6062 */ - {0x00e681a3, 0x009c93}, /* U+6063 */ - {0x00e681a4, 0x009c95}, /* U+6064 */ - {0x00e681a5, 0x009270}, /* U+6065 */ - {0x00e681a8, 0x008da6}, /* U+6068 */ - {0x00e681a9, 0x0089b6}, /* U+6069 */ - {0x00e681aa, 0x009c8d}, /* U+606A */ - {0x00e681ab, 0x009c98}, /* U+606B */ - {0x00e681ac, 0x009c97}, /* U+606C */ - {0x00e681ad, 0x008bb1}, /* U+606D */ - {0x00e681af, 0x0091a7}, /* U+606F */ - {0x00e681b0, 0x008a86}, /* U+6070 */ - {0x00e681b5, 0x008c62}, /* U+6075 */ - {0x00e681b7, 0x009c8e}, /* U+6077 */ - {0x00e681bf, 0x00f2ca}, /* U+607F [2000] */ - {0x00e68281, 0x009c9a}, /* U+6081 */ - {0x00e68283, 0x009c9d}, /* U+6083 */ - {0x00e68284, 0x009c9f}, /* U+6084 */ - {0x00e68289, 0x008ebb}, /* U+6089 */ - {0x00e6828a, 0x00f2cb}, /* U+608A [2000] */ - {0x00e6828b, 0x009ca5}, /* U+608B */ - {0x00e6828c, 0x0092ee}, /* U+608C */ - {0x00e6828d, 0x009c9b}, /* U+608D */ - {0x00e68292, 0x009ca3}, /* U+6092 */ - {0x00e68294, 0x0089f7}, /* U+6094 */ - {0x00e68295, 0x00f2cc}, /* U+6095 [2000] */ - {0x00e68296, 0x009ca1}, /* U+6096 */ - {0x00e68297, 0x009ca2}, /* U+6097 */ - {0x00e6829a, 0x009c9e}, /* U+609A */ - {0x00e6829b, 0x009ca0}, /* U+609B */ - {0x00e6829d, 0x00eacf}, /* U+609D [2000] */ - {0x00e6829e, 0x00ead0}, /* U+609E [2000] */ - {0x00e6829f, 0x008ce5}, /* U+609F */ - {0x00e682a0, 0x009749}, /* U+60A0 */ - {0x00e682a3, 0x008ab3}, /* U+60A3 */ - {0x00e682a6, 0x008978}, /* U+60A6 */ - {0x00e682a7, 0x009ca4}, /* U+60A7 */ - {0x00e682a8, 0x00f2cd}, /* U+60A8 [2000] */ - {0x00e682a9, 0x009459}, /* U+60A9 */ - {0x00e682aa, 0x0088ab}, /* U+60AA */ - {0x00e682b0, 0x00f2cf}, /* U+60B0 [2000] */ - {0x00e682b1, 0x00f2d0}, /* U+60B1 [2000] */ - {0x00e682b2, 0x0094df}, /* U+60B2 */ - {0x00e682b3, 0x009c7b}, /* U+60B3 */ - {0x00e682b4, 0x009caa}, /* U+60B4 */ - {0x00e682b5, 0x009cae}, /* U+60B5 */ - {0x00e682b6, 0x0096e3}, /* U+60B6 */ - {0x00e682b8, 0x009ca7}, /* U+60B8 */ - {0x00e682bc, 0x009389}, /* U+60BC */ - {0x00e682bd, 0x009cac}, /* U+60BD */ - {0x00e682be, 0x00f2d1}, /* U+60BE [2000] */ - {0x00e68385, 0x008fee}, /* U+60C5 */ - {0x00e68386, 0x009cad}, /* U+60C6 */ - {0x00e68387, 0x0093d5}, /* U+60C7 */ - {0x00e68388, 0x00f2d2}, /* U+60C8 [2000] */ - {0x00e6838b, 0x00ead1}, /* U+60CB [2000] */ - {0x00e68391, 0x009866}, /* U+60D1 */ - {0x00e68393, 0x009ca9}, /* U+60D3 */ - {0x00e68394, 0x00ead2}, /* U+60D4 [2000] */ - {0x00e68395, 0x00ead3}, /* U+60D5 [2000] */ - {0x00e68398, 0x009caf}, /* U+60D8 */ - {0x00e68399, 0x00f2d3}, /* U+60D9 [2000] */ - {0x00e6839a, 0x008d9b}, /* U+60DA */ - {0x00e6839b, 0x00f2d4}, /* U+60DB [2000] */ - {0x00e6839c, 0x0090c9}, /* U+60DC */ - {0x00e6839d, 0x00ead4}, /* U+60DD [2000] */ - {0x00e6839f, 0x0088d2}, /* U+60DF */ - {0x00e683a0, 0x009ca8}, /* U+60E0 */ - {0x00e683a1, 0x009ca6}, /* U+60E1 */ - {0x00e683a3, 0x009179}, /* U+60E3 */ - {0x00e683a7, 0x009c9c}, /* U+60E7 */ - {0x00e683a8, 0x008e53}, /* U+60E8 */ - {0x00e683ae, 0x00f2d5}, /* U+60EE [2000] */ - {0x00e683b0, 0x0091c4}, /* U+60F0 */ - {0x00e683b1, 0x009cbb}, /* U+60F1 */ - {0x00e683b2, 0x00f2d6}, /* U+60F2 [2000] */ - {0x00e683b3, 0x00917a}, /* U+60F3 */ - {0x00e683b4, 0x009cb6}, /* U+60F4 */ - {0x00e683b5, 0x00f2d7}, /* U+60F5 [2000] */ - {0x00e683b6, 0x009cb3}, /* U+60F6 */ - {0x00e683b7, 0x009cb4}, /* U+60F7 */ - {0x00e683b8, 0x00ead5}, /* U+60F8 [2000] */ - {0x00e683b9, 0x008ee4}, /* U+60F9 */ - {0x00e683ba, 0x009cb7}, /* U+60FA */ - {0x00e683bb, 0x009cba}, /* U+60FB */ - {0x00e68480, 0x009cb5}, /* U+6100 */ - {0x00e68481, 0x008f44}, /* U+6101 */ - {0x00e68483, 0x009cb8}, /* U+6103 */ - {0x00e68486, 0x009cb2}, /* U+6106 */ - {0x00e68488, 0x0096fa}, /* U+6108 */ - {0x00e68489, 0x0096f9}, /* U+6109 */ - {0x00e6848d, 0x009cbc}, /* U+610D */ - {0x00e6848e, 0x009cbd}, /* U+610E */ - {0x00e6848f, 0x0088d3}, /* U+610F */ - {0x00e68490, 0x00f2d8}, /* U+6110 [2000] */ - {0x00e68492, 0x00f2d9}, /* U+6112 [2000] */ - {0x00e68493, 0x00f2da}, /* U+6113 [2000] */ - {0x00e68495, 0x009cb1}, /* U+6115 */ - {0x00e68499, 0x00f2db}, /* U+6119 [2000] */ - {0x00e6849a, 0x008bf0}, /* U+611A */ - {0x00e6849b, 0x0088a4}, /* U+611B */ - {0x00e6849c, 0x00ead6}, /* U+611C [2000] */ - {0x00e6849e, 0x00f2dc}, /* U+611E [2000] */ - {0x00e6849f, 0x008ab4}, /* U+611F */ - {0x00e684a1, 0x009cb9}, /* U+6121 */ - {0x00e684a7, 0x009cc1}, /* U+6127 */ - {0x00e684a8, 0x009cc0}, /* U+6128 */ - {0x00e684ab, 0x00ead7}, /* U+612B [2000] */ - {0x00e684ac, 0x009cc5}, /* U+612C */ - {0x00e684b0, 0x00ead8}, /* U+6130 [2000] */ - {0x00e684b4, 0x009cc6}, /* U+6134 */ - {0x00e684b7, 0x00ead9}, /* U+6137 [2000] */ - {0x00e684ba, 0x00f2dd}, /* U+613A [2000] */ - {0x00e684bc, 0x009cc4}, /* U+613C */ - {0x00e684bd, 0x009cc7}, /* U+613D */ - {0x00e684be, 0x009cbf}, /* U+613E */ - {0x00e684bf, 0x009cc3}, /* U+613F */ - {0x00e68581, 0x00f2df}, /* U+6141 [2000] */ - {0x00e68582, 0x009cc8}, /* U+6142 */ - {0x00e68584, 0x009cc9}, /* U+6144 */ - {0x00e68586, 0x00f2e0}, /* U+6146 [2000] */ - {0x00e68587, 0x009cbe}, /* U+6147 */ - {0x00e68588, 0x008e9c}, /* U+6148 */ - {0x00e6858a, 0x009cc2}, /* U+614A */ - {0x00e6858b, 0x0091d4}, /* U+614B */ - {0x00e6858c, 0x008d51}, /* U+614C */ - {0x00e6858d, 0x009cb0}, /* U+614D */ - {0x00e6858e, 0x009054}, /* U+614E */ - {0x00e68593, 0x009cd6}, /* U+6153 */ - {0x00e68595, 0x0095e7}, /* U+6155 */ - {0x00e68598, 0x009ccc}, /* U+6158 */ - {0x00e68599, 0x009ccd}, /* U+6159 */ - {0x00e6859a, 0x009cce}, /* U+615A */ - {0x00e6859d, 0x009cd5}, /* U+615D */ - {0x00e6859f, 0x009cd4}, /* U+615F */ - {0x00e685a0, 0x00f2e1}, /* U+6160 [2000] */ - {0x00e685a2, 0x00969d}, /* U+6162 */ - {0x00e685a3, 0x008ab5}, /* U+6163 */ - {0x00e685a5, 0x009cd2}, /* U+6165 */ - {0x00e685a7, 0x008c64}, /* U+6167 */ - {0x00e685a8, 0x008a53}, /* U+6168 */ - {0x00e685ab, 0x009ccf}, /* U+616B */ - {0x00e685ae, 0x0097b6}, /* U+616E */ - {0x00e685af, 0x009cd1}, /* U+616F */ - {0x00e685b0, 0x0088d4}, /* U+6170 */ - {0x00e685b1, 0x009cd3}, /* U+6171 */ - {0x00e685b3, 0x009cca}, /* U+6173 */ - {0x00e685b4, 0x009cd0}, /* U+6174 */ - {0x00e685b5, 0x009cd7}, /* U+6175 */ - {0x00e685b6, 0x008c63}, /* U+6176 */ - {0x00e685b7, 0x009ccb}, /* U+6177 */ - {0x00e685bc, 0x00f2e2}, /* U+617C [2000] */ - {0x00e685be, 0x00977c}, /* U+617E */ - {0x00e68682, 0x00974a}, /* U+6182 */ - {0x00e68687, 0x009cda}, /* U+6187 */ - {0x00e6868a, 0x009cde}, /* U+618A */ - {0x00e6868d, 0x00eadb}, /* U+618D [2000] */ - {0x00e6868e, 0x00919e}, /* U+618E */ - {0x00e68690, 0x0097f7}, /* U+6190 */ - {0x00e68691, 0x009cdf}, /* U+6191 */ - {0x00e68692, 0x00f2e4}, /* U+6192 [2000] */ - {0x00e68693, 0x00f2e5}, /* U+6193 [2000] */ - {0x00e68694, 0x009cdc}, /* U+6194 */ - {0x00e68696, 0x009cd9}, /* U+6196 */ - {0x00e68697, 0x00f2e6}, /* U+6197 [2000] */ - {0x00e68698, 0x00f2e7}, /* U+6198 [2000] */ - {0x00e68699, 0x009cd8}, /* U+6199 */ - {0x00e6869a, 0x009cdd}, /* U+619A */ - {0x00e686a4, 0x0095ae}, /* U+61A4 */ - {0x00e686a5, 0x00f2e8}, /* U+61A5 [2000] */ - {0x00e686a7, 0x0093b2}, /* U+61A7 */ - {0x00e686a8, 0x00f2e9}, /* U+61A8 [2000] */ - {0x00e686a9, 0x008c65}, /* U+61A9 */ - {0x00e686ab, 0x009ce0}, /* U+61AB */ - {0x00e686ac, 0x009cdb}, /* U+61AC */ - {0x00e686ad, 0x00f2ea}, /* U+61AD [2000] */ - {0x00e686ae, 0x009ce1}, /* U+61AE */ - {0x00e686b2, 0x008c9b}, /* U+61B2 */ - {0x00e686b6, 0x0089af}, /* U+61B6 */ - {0x00e686b9, 0x00eade}, /* U+61B9 [2000] */ - {0x00e686ba, 0x009ce9}, /* U+61BA */ - {0x00e686bc, 0x00eadd}, /* U+61BC [2000] */ - {0x00e686be, 0x008ab6}, /* U+61BE */ - {0x00e68783, 0x009ce7}, /* U+61C3 */ - {0x00e68786, 0x009ce8}, /* U+61C6 */ - {0x00e68787, 0x008da7}, /* U+61C7 */ - {0x00e68788, 0x009ce6}, /* U+61C8 */ - {0x00e68789, 0x009ce4}, /* U+61C9 */ - {0x00e6878a, 0x009ce3}, /* U+61CA */ - {0x00e6878b, 0x009cea}, /* U+61CB */ - {0x00e6878c, 0x009ce2}, /* U+61CC */ - {0x00e6878d, 0x009cec}, /* U+61CD */ - {0x00e68790, 0x0089f9}, /* U+61D0 */ - {0x00e68795, 0x00f2ec}, /* U+61D5 [2000] */ - {0x00e6879d, 0x00f2ed}, /* U+61DD [2000] */ - {0x00e6879f, 0x00f2ee}, /* U+61DF [2000] */ - {0x00e687a3, 0x009cee}, /* U+61E3 */ - {0x00e687a6, 0x009ced}, /* U+61E6 */ - {0x00e687b2, 0x0092a6}, /* U+61F2 */ - {0x00e687b4, 0x009cf1}, /* U+61F4 */ - {0x00e687b5, 0x00f2ef}, /* U+61F5 [2000] */ - {0x00e687b6, 0x009cef}, /* U+61F6 */ - {0x00e687b7, 0x009ce5}, /* U+61F7 */ - {0x00e687b8, 0x008c9c}, /* U+61F8 */ - {0x00e687ba, 0x009cf0}, /* U+61FA */ - {0x00e687bc, 0x009cf4}, /* U+61FC */ - {0x00e687bd, 0x009cf3}, /* U+61FD */ - {0x00e687be, 0x009cf5}, /* U+61FE */ - {0x00e687bf, 0x009cf2}, /* U+61FF */ - {0x00e68880, 0x009cf6}, /* U+6200 */ - {0x00e68888, 0x009cf7}, /* U+6208 */ - {0x00e68889, 0x009cf8}, /* U+6209 */ - {0x00e6888a, 0x0095e8}, /* U+620A */ - {0x00e6888c, 0x009cfa}, /* U+620C */ - {0x00e6888d, 0x009cf9}, /* U+620D */ - {0x00e6888e, 0x008f5e}, /* U+620E */ - {0x00e68890, 0x0090ac}, /* U+6210 */ - {0x00e68891, 0x0089e4}, /* U+6211 */ - {0x00e68892, 0x0089fa}, /* U+6212 */ - {0x00e68894, 0x009cfb}, /* U+6214 */ - {0x00e68895, 0x00f2f1}, /* U+6215 [2000] */ - {0x00e68896, 0x0088bd}, /* U+6216 */ - {0x00e6889a, 0x0090ca}, /* U+621A */ - {0x00e6889b, 0x009cfc}, /* U+621B */ - {0x00e6889d, 0x00e6c1}, /* U+621D */ - {0x00e6889e, 0x009d40}, /* U+621E */ - {0x00e6889f, 0x008c81}, /* U+621F */ - {0x00e688a1, 0x009d41}, /* U+6221 */ - {0x00e688a2, 0x00eae0}, /* U+6222 [2000] */ - {0x00e688a3, 0x00f2f2}, /* U+6223 [2000] */ - {0x00e688a6, 0x0090ed}, /* U+6226 */ - {0x00e688a9, 0x00f2f3}, /* U+6229 [2000] */ - {0x00e688aa, 0x009d42}, /* U+622A */ - {0x00e688ae, 0x009d43}, /* U+622E */ - {0x00e688af, 0x008b59}, /* U+622F */ - {0x00e688b0, 0x009d44}, /* U+6230 */ - {0x00e688b2, 0x009d45}, /* U+6232 */ - {0x00e688b3, 0x009d46}, /* U+6233 */ - {0x00e688b4, 0x0091d5}, /* U+6234 */ - {0x00e688b8, 0x008ccb}, /* U+6238 */ - {0x00e688bb, 0x0096df}, /* U+623B */ - {0x00e688be, 0x00eae1}, /* U+623E [2000] */ - {0x00e688bf, 0x00965b}, /* U+623F */ - {0x00e68980, 0x008f8a}, /* U+6240 */ - {0x00e68981, 0x009d47}, /* U+6241 */ - {0x00e68983, 0x00eae2}, /* U+6243 [2000] */ - {0x00e68986, 0x00f2f4}, /* U+6246 [2000] */ - {0x00e68987, 0x0090ee}, /* U+6247 */ - {0x00e68988, 0x00e7bb}, /* U+6248 */ - {0x00e68989, 0x0094e0}, /* U+6249 */ - {0x00e6898b, 0x008ee8}, /* U+624B */ - {0x00e6898c, 0x00f2f5}, /* U+624C [2000] */ - {0x00e6898d, 0x008dcb}, /* U+624D */ - {0x00e6898e, 0x009d48}, /* U+624E */ - {0x00e68991, 0x00f2f6}, /* U+6251 [2000] */ - {0x00e68992, 0x00f2f7}, /* U+6252 [2000] */ - {0x00e68993, 0x0091c5}, /* U+6253 */ - {0x00e68995, 0x0095a5}, /* U+6255 */ - {0x00e68996, 0x00eae3}, /* U+6256 [2000] */ - {0x00e68998, 0x0091ef}, /* U+6258 */ - {0x00e6899a, 0x00eae4}, /* U+625A [2000] */ - {0x00e6899b, 0x009d4b}, /* U+625B */ - {0x00e6899e, 0x009d49}, /* U+625E */ - {0x00e689a0, 0x009d4c}, /* U+6260 */ - {0x00e689a1, 0x00f2f8}, /* U+6261 [2000] */ - {0x00e689a3, 0x009d4a}, /* U+6263 */ - {0x00e689a4, 0x00f2f9}, /* U+6264 [2000] */ - {0x00e689a8, 0x009d4d}, /* U+6268 */ - {0x00e689ad, 0x00f2fb}, /* U+626D [2000] */ - {0x00e689ae, 0x0095af}, /* U+626E */ - {0x00e689af, 0x00eae5}, /* U+626F [2000] */ - {0x00e689b1, 0x0088b5}, /* U+6271 */ - {0x00e689b3, 0x00f2fc}, /* U+6273 [2000] */ - {0x00e689b6, 0x00957d}, /* U+6276 */ - {0x00e689b9, 0x0094e1}, /* U+6279 */ - {0x00e689bb, 0x00f2fa}, /* U+627B [2000] */ - {0x00e689bc, 0x009d4e}, /* U+627C */ - {0x00e689be, 0x009d51}, /* U+627E */ - {0x00e689bf, 0x008fb3}, /* U+627F */ - {0x00e68a80, 0x008b5a}, /* U+6280 */ - {0x00e68a82, 0x009d4f}, /* U+6282 */ - {0x00e68a83, 0x009d56}, /* U+6283 */ - {0x00e68a84, 0x008fb4}, /* U+6284 */ - {0x00e68a85, 0x00eae6}, /* U+6285 [2000] */ - {0x00e68a89, 0x009d50}, /* U+6289 */ - {0x00e68a8a, 0x009463}, /* U+628A */ - {0x00e68a91, 0x00977d}, /* U+6291 */ - {0x00e68a92, 0x009d52}, /* U+6292 */ - {0x00e68a93, 0x009d53}, /* U+6293 */ - {0x00e68a94, 0x009d57}, /* U+6294 */ - {0x00e68a95, 0x00938a}, /* U+6295 */ - {0x00e68a96, 0x009d54}, /* U+6296 */ - {0x00e68a97, 0x008d52}, /* U+6297 */ - {0x00e68a98, 0x0090dc}, /* U+6298 */ - {0x00e68a99, 0x00f340}, /* U+6299 [2000] */ - {0x00e68a9b, 0x009d65}, /* U+629B */ - {0x00e68a9c, 0x0094b2}, /* U+629C */ - {0x00e68a9e, 0x0091f0}, /* U+629E */ - {0x00e68aa6, 0x00f341}, /* U+62A6 [2000] */ - {0x00e68aab, 0x0094e2}, /* U+62AB */ - {0x00e68aac, 0x009dab}, /* U+62AC */ - {0x00e68ab1, 0x0095f8}, /* U+62B1 */ - {0x00e68ab5, 0x0092ef}, /* U+62B5 */ - {0x00e68ab9, 0x009695}, /* U+62B9 */ - {0x00e68abb, 0x009d5a}, /* U+62BB */ - {0x00e68abc, 0x00899f}, /* U+62BC */ - {0x00e68abd, 0x00928a}, /* U+62BD */ - {0x00e68b82, 0x009d63}, /* U+62C2 */ - {0x00e68b84, 0x00eae7}, /* U+62C4 [2000] */ - {0x00e68b85, 0x009253}, /* U+62C5 */ - {0x00e68b86, 0x009d5d}, /* U+62C6 */ - {0x00e68b87, 0x009d64}, /* U+62C7 */ - {0x00e68b88, 0x009d5f}, /* U+62C8 */ - {0x00e68b89, 0x009d66}, /* U+62C9 */ - {0x00e68b8a, 0x009d62}, /* U+62CA */ - {0x00e68b8c, 0x009d61}, /* U+62CC */ - {0x00e68b8d, 0x00948f}, /* U+62CD */ - {0x00e68b8f, 0x009d5b}, /* U+62CF */ - {0x00e68b90, 0x0089fb}, /* U+62D0 */ - {0x00e68b91, 0x009d59}, /* U+62D1 */ - {0x00e68b92, 0x008b91}, /* U+62D2 */ - {0x00e68b93, 0x0091f1}, /* U+62D3 */ - {0x00e68b94, 0x009d55}, /* U+62D4 */ - {0x00e68b95, 0x00f342}, /* U+62D5 [2000] */ - {0x00e68b96, 0x00eae8}, /* U+62D6 [2000] */ - {0x00e68b97, 0x009d58}, /* U+62D7 */ - {0x00e68b98, 0x008d53}, /* U+62D8 */ - {0x00e68b99, 0x0090d9}, /* U+62D9 */ - {0x00e68b9b, 0x008fb5}, /* U+62DB */ - {0x00e68b9c, 0x009d60}, /* U+62DC */ - {0x00e68b9d, 0x009471}, /* U+62DD */ - {0x00e68ba0, 0x008b92}, /* U+62E0 */ - {0x00e68ba1, 0x008a67}, /* U+62E1 */ - {0x00e68bac, 0x008a87}, /* U+62EC */ - {0x00e68bad, 0x009040}, /* U+62ED */ - {0x00e68bae, 0x009d68}, /* U+62EE */ - {0x00e68baf, 0x009d6d}, /* U+62EF */ - {0x00e68bb1, 0x009d69}, /* U+62F1 */ - {0x00e68bb3, 0x008c9d}, /* U+62F3 */ - {0x00e68bb5, 0x009d6e}, /* U+62F5 */ - {0x00e68bb6, 0x008e41}, /* U+62F6 */ - {0x00e68bb7, 0x008d89}, /* U+62F7 */ - {0x00e68bbc, 0x00eae9}, /* U+62FC [2000] */ - {0x00e68bbd, 0x00f344}, /* U+62FD [2000] */ - {0x00e68bbe, 0x008f45}, /* U+62FE */ - {0x00e68bbf, 0x009d5c}, /* U+62FF */ - {0x00e68c81, 0x008e9d}, /* U+6301 */ - {0x00e68c82, 0x009d6b}, /* U+6302 */ - {0x00e68c83, 0x00f345}, /* U+6303 [2000] */ - {0x00e68c87, 0x008e77}, /* U+6307 */ - {0x00e68c88, 0x009d6c}, /* U+6308 */ - {0x00e68c89, 0x0088c2}, /* U+6309 */ - {0x00e68c8a, 0x00eaea}, /* U+630A [2000] */ - {0x00e68c8c, 0x009d67}, /* U+630C */ - {0x00e68c8d, 0x00f346}, /* U+630D [2000] */ - {0x00e68c90, 0x00f347}, /* U+6310 [2000] */ - {0x00e68c91, 0x0092a7}, /* U+6311 */ - {0x00e68c98, 0x00eaeb}, /* U+6318 [2000] */ - {0x00e68c99, 0x008b93}, /* U+6319 */ - {0x00e68c9f, 0x008bb2}, /* U+631F */ - {0x00e68ca7, 0x009d6a}, /* U+6327 */ - {0x00e68ca8, 0x0088a5}, /* U+6328 */ - {0x00e68cab, 0x008dc1}, /* U+632B */ - {0x00e68caf, 0x009055}, /* U+632F */ - {0x00e68cb2, 0x00f34a}, /* U+6332 [2000] */ - {0x00e68cb5, 0x00f34b}, /* U+6335 [2000] */ - {0x00e68cb9, 0x00eaec}, /* U+6339 [2000] */ - {0x00e68cba, 0x0092f0}, /* U+633A */ - {0x00e68cbb, 0x00f34c}, /* U+633B [2000] */ - {0x00e68cbc, 0x00f34d}, /* U+633C [2000] */ - {0x00e68cbd, 0x0094d2}, /* U+633D */ - {0x00e68cbe, 0x009d70}, /* U+633E */ - {0x00e68cbf, 0x00917d}, /* U+633F */ - {0x00e68d81, 0x00f34e}, /* U+6341 [2000] */ - {0x00e68d83, 0x00eaed}, /* U+6343 [2000] */ - {0x00e68d84, 0x00f34f}, /* U+6344 [2000] */ - {0x00e68d89, 0x0091a8}, /* U+6349 */ - {0x00e68d8c, 0x008e4a}, /* U+634C */ - {0x00e68d8d, 0x009d71}, /* U+634D */ - {0x00e68d8e, 0x00f350}, /* U+634E [2000] */ - {0x00e68d8f, 0x009d73}, /* U+634F */ - {0x00e68d90, 0x009d6f}, /* U+6350 */ - {0x00e68d95, 0x0095df}, /* U+6355 */ - {0x00e68d97, 0x0092bb}, /* U+6357 */ - {0x00e68d99, 0x00f352}, /* U+6359 [2000] */ - {0x00e68d9c, 0x00917b}, /* U+635C */ - {0x00e68da5, 0x00eaee}, /* U+6365 [2000] */ - {0x00e68da7, 0x0095f9}, /* U+6367 */ - {0x00e68da8, 0x008ecc}, /* U+6368 */ - {0x00e68da9, 0x009d80}, /* U+6369 */ - {0x00e68dab, 0x009d7e}, /* U+636B */ - {0x00e68dac, 0x00f355}, /* U+636C [2000] */ - {0x00e68dae, 0x009098}, /* U+636E */ - {0x00e68db2, 0x008c9e}, /* U+6372 */ - {0x00e68db6, 0x009d78}, /* U+6376 */ - {0x00e68db7, 0x008fb7}, /* U+6377 */ - {0x00e68dba, 0x0093e6}, /* U+637A */ - {0x00e68dbb, 0x009450}, /* U+637B */ - {0x00e68dbc, 0x00eaef}, /* U+637C [2000] */ - {0x00e68e80, 0x009d76}, /* U+6380 */ - {0x00e68e83, 0x00917c}, /* U+6383 */ - {0x00e68e84, 0x00f356}, /* U+6384 [2000] */ - {0x00e68e88, 0x008ef6}, /* U+6388 */ - {0x00e68e89, 0x009d7b}, /* U+6389 */ - {0x00e68e8c, 0x008fb6}, /* U+638C */ - {0x00e68e8e, 0x009d75}, /* U+638E */ - {0x00e68e8f, 0x009d7a}, /* U+638F */ - {0x00e68e92, 0x009472}, /* U+6392 */ - {0x00e68e94, 0x00f359}, /* U+6394 [2000] */ - {0x00e68e96, 0x009d74}, /* U+6396 */ - {0x00e68e98, 0x008c40}, /* U+6398 */ - {0x00e68e99, 0x00f357}, /* U+6399 [2000] */ - {0x00e68e9b, 0x008a7c}, /* U+639B */ - {0x00e68e9f, 0x009d7c}, /* U+639F */ - {0x00e68ea0, 0x0097a9}, /* U+63A0 */ - {0x00e68ea1, 0x008dcc}, /* U+63A1 */ - {0x00e68ea2, 0x009254}, /* U+63A2 */ - {0x00e68ea3, 0x009d79}, /* U+63A3 */ - {0x00e68ea5, 0x0090da}, /* U+63A5 */ - {0x00e68ea7, 0x008d54}, /* U+63A7 */ - {0x00e68ea8, 0x009084}, /* U+63A8 */ - {0x00e68ea9, 0x008986}, /* U+63A9 */ - {0x00e68eaa, 0x00915b}, /* U+63AA */ - {0x00e68eab, 0x009d77}, /* U+63AB */ - {0x00e68eac, 0x008b64}, /* U+63AC */ - {0x00e68eb2, 0x008c66}, /* U+63B2 */ - {0x00e68eb4, 0x0092cd}, /* U+63B4 */ - {0x00e68eb5, 0x009d7d}, /* U+63B5 */ - {0x00e68ebb, 0x00917e}, /* U+63BB */ - {0x00e68ebd, 0x00f35a}, /* U+63BD [2000] */ - {0x00e68ebe, 0x009d81}, /* U+63BE */ - {0x00e68f80, 0x009d83}, /* U+63C0 */ - {0x00e68f83, 0x0091b5}, /* U+63C3 */ - {0x00e68f84, 0x009d89}, /* U+63C4 */ - {0x00e68f86, 0x009d84}, /* U+63C6 */ - {0x00e68f89, 0x009d86}, /* U+63C9 */ - {0x00e68f8f, 0x009560}, /* U+63CF */ - {0x00e68f90, 0x0092f1}, /* U+63D0 */ - {0x00e68f92, 0x009d87}, /* U+63D2 */ - {0x00e68f94, 0x00f35c}, /* U+63D4 [2000] */ - {0x00e68f95, 0x00f35d}, /* U+63D5 [2000] */ - {0x00e68f96, 0x00974b}, /* U+63D6 */ - {0x00e68f9a, 0x009767}, /* U+63DA */ - {0x00e68f9b, 0x008ab7}, /* U+63DB */ - {0x00e68f9c, 0x00f35e}, /* U+63DC [2000] */ - {0x00e68fa0, 0x00f35f}, /* U+63E0 [2000] */ - {0x00e68fa1, 0x0088ac}, /* U+63E1 */ - {0x00e68fa3, 0x009d85}, /* U+63E3 */ - {0x00e68fa5, 0x00eaf0}, /* U+63E5 [2000] */ - {0x00e68fa9, 0x009d82}, /* U+63E9 */ - {0x00e68fab, 0x00f360}, /* U+63EB [2000] */ - {0x00e68fac, 0x00f361}, /* U+63EC [2000] */ - {0x00e68fad, 0x00eaf1}, /* U+63ED [2000] */ - {0x00e68fae, 0x008af6}, /* U+63EE */ - {0x00e68fb2, 0x00f362}, /* U+63F2 [2000] */ - {0x00e68fb4, 0x008987}, /* U+63F4 */ - {0x00e68fb5, 0x00eaf2}, /* U+63F5 [2000] */ - {0x00e68fb6, 0x009d88}, /* U+63F6 */ - {0x00e68fb7, 0x00f35b}, /* U+63F7 [2000] */ - {0x00e68fba, 0x009768}, /* U+63FA */ - {0x00e69086, 0x009d8c}, /* U+6406 */ - {0x00e69089, 0x00f363}, /* U+6409 [2000] */ - {0x00e6908d, 0x0091b9}, /* U+640D */ - {0x00e6908f, 0x009d93}, /* U+640F */ - {0x00e69090, 0x00eaf3}, /* U+6410 [2000] */ - {0x00e69093, 0x009d8d}, /* U+6413 */ - {0x00e69094, 0x00eaf4}, /* U+6414 [2000] */ - {0x00e69096, 0x009d8a}, /* U+6416 */ - {0x00e69097, 0x009d91}, /* U+6417 */ - {0x00e6909c, 0x009d72}, /* U+641C */ - {0x00e6909e, 0x00f364}, /* U+641E [2000] */ - {0x00e690a2, 0x00eaf5}, /* U+6422 [2000] */ - {0x00e690a5, 0x00f365}, /* U+6425 [2000] */ - {0x00e690a6, 0x009d8e}, /* U+6426 */ - {0x00e690a8, 0x009d92}, /* U+6428 */ - {0x00e690a9, 0x00f366}, /* U+6429 [2000] */ - {0x00e690ac, 0x0094c0}, /* U+642C */ - {0x00e690ad, 0x00938b}, /* U+642D */ - {0x00e690af, 0x00f367}, /* U+642F [2000] */ - {0x00e690b4, 0x009d8b}, /* U+6434 */ - {0x00e690b6, 0x009d8f}, /* U+6436 */ - {0x00e690ba, 0x008c67}, /* U+643A */ - {0x00e690be, 0x008def}, /* U+643E */ - {0x00e69182, 0x0090db}, /* U+6442 */ - {0x00e6918e, 0x009d97}, /* U+644E */ - {0x00e69191, 0x00eaf7}, /* U+6451 [2000] */ - {0x00e69198, 0x009345}, /* U+6458 */ - {0x00e6919a, 0x00f368}, /* U+645A [2000] */ - {0x00e6919b, 0x00f369}, /* U+645B [2000] */ - {0x00e6919d, 0x00f36a}, /* U+645D [2000] */ - {0x00e691a0, 0x00eaf8}, /* U+6460 [2000] */ - {0x00e691a7, 0x009d94}, /* U+6467 */ - {0x00e691a9, 0x009680}, /* U+6469 */ - {0x00e691ad, 0x00eaf9}, /* U+646D [2000] */ - {0x00e691af, 0x009d95}, /* U+646F */ - {0x00e691b3, 0x00f36b}, /* U+6473 [2000] */ - {0x00e691b6, 0x009d96}, /* U+6476 */ - {0x00e691b8, 0x0096cc}, /* U+6478 */ - {0x00e691b9, 0x00eaf6}, /* U+6479 [2000] */ - {0x00e691ba, 0x0090a0}, /* U+647A */ - {0x00e691bd, 0x00f36c}, /* U+647D [2000] */ - {0x00e69283, 0x008c82}, /* U+6483 */ - {0x00e69287, 0x00f36d}, /* U+6487 [2000] */ - {0x00e69288, 0x009d9d}, /* U+6488 */ - {0x00e69291, 0x00f36e}, /* U+6491 [2000] */ - {0x00e69292, 0x008e54}, /* U+6492 */ - {0x00e69293, 0x009d9a}, /* U+6493 */ - {0x00e69295, 0x009d99}, /* U+6495 */ - {0x00e6929a, 0x009451}, /* U+649A */ - {0x00e6929d, 0x00f36f}, /* U+649D [2000] */ - {0x00e6929e, 0x0093b3}, /* U+649E */ - {0x00e6929f, 0x00f370}, /* U+649F [2000] */ - {0x00e692a4, 0x009350}, /* U+64A4 */ - {0x00e692a5, 0x009d9b}, /* U+64A5 */ - {0x00e692a9, 0x009d9c}, /* U+64A9 */ - {0x00e692ab, 0x00958f}, /* U+64AB */ - {0x00e692ad, 0x009464}, /* U+64AD */ - {0x00e692ae, 0x008e42}, /* U+64AE */ - {0x00e692b0, 0x0090ef}, /* U+64B0 */ - {0x00e692b2, 0x00966f}, /* U+64B2 */ - {0x00e692b9, 0x008a68}, /* U+64B9 */ - {0x00e692bb, 0x009da3}, /* U+64BB */ - {0x00e692bc, 0x009d9e}, /* U+64BC */ - {0x00e692be, 0x00eafb}, /* U+64BE [2000] */ - {0x00e692bf, 0x00eafc}, /* U+64BF [2000] */ - {0x00e69381, 0x009769}, /* U+64C1 */ - {0x00e69382, 0x009da5}, /* U+64C2 */ - {0x00e69384, 0x00eb40}, /* U+64C4 [2000] */ - {0x00e69385, 0x009da1}, /* U+64C5 */ - {0x00e69387, 0x009da2}, /* U+64C7 */ - {0x00e6938a, 0x00eb41}, /* U+64CA [2000] */ - {0x00e6938b, 0x00f371}, /* U+64CB [2000] */ - {0x00e6938c, 0x00f372}, /* U+64CC [2000] */ - {0x00e6938d, 0x009180}, /* U+64CD */ - {0x00e6938e, 0x00eafa}, /* U+64CE [2000] */ - {0x00e69390, 0x00eb42}, /* U+64D0 [2000] */ - {0x00e69392, 0x009da0}, /* U+64D2 */ - {0x00e69394, 0x009d5e}, /* U+64D4 */ - {0x00e69395, 0x00f373}, /* U+64D5 [2000] */ - {0x00e69397, 0x00f374}, /* U+64D7 [2000] */ - {0x00e69398, 0x009da4}, /* U+64D8 */ - {0x00e6939a, 0x009d9f}, /* U+64DA */ - {0x00e693a0, 0x009da9}, /* U+64E0 */ - {0x00e693a1, 0x009daa}, /* U+64E1 */ - {0x00e693a2, 0x009346}, /* U+64E2 */ - {0x00e693a3, 0x009dac}, /* U+64E3 */ - {0x00e693a4, 0x00f376}, /* U+64E4 [2000] */ - {0x00e693a5, 0x00f377}, /* U+64E5 [2000] */ - {0x00e693a6, 0x008e43}, /* U+64E6 */ - {0x00e693a7, 0x009da7}, /* U+64E7 */ - {0x00e693ac, 0x008b5b}, /* U+64EC */ - {0x00e693af, 0x009dad}, /* U+64EF */ - {0x00e693b1, 0x009da6}, /* U+64F1 */ - {0x00e693b2, 0x009db1}, /* U+64F2 */ - {0x00e693b4, 0x009db0}, /* U+64F4 */ - {0x00e693b6, 0x009daf}, /* U+64F6 */ - {0x00e693b7, 0x00eb43}, /* U+64F7 [2000] */ - {0x00e693ba, 0x009db2}, /* U+64FA */ - {0x00e693bb, 0x00eb44}, /* U+64FB [2000] */ - {0x00e693bd, 0x009db4}, /* U+64FD */ - {0x00e693be, 0x008fef}, /* U+64FE */ - {0x00e693bf, 0x00f378}, /* U+64FF [2000] */ - {0x00e69480, 0x009db3}, /* U+6500 */ - {0x00e69484, 0x00f379}, /* U+6504 [2000] */ - {0x00e69485, 0x009db7}, /* U+6505 */ - {0x00e6948f, 0x00f37b}, /* U+650F [2000] */ - {0x00e69494, 0x00f37c}, /* U+6514 [2000] */ - {0x00e69496, 0x00f37d}, /* U+6516 [2000] */ - {0x00e69498, 0x009db5}, /* U+6518 */ - {0x00e6949c, 0x009db6}, /* U+651C */ - {0x00e6949d, 0x009d90}, /* U+651D */ - {0x00e6949e, 0x00f380}, /* U+651E [2000] */ - {0x00e694a2, 0x00eb45}, /* U+6522 [2000] */ - {0x00e694a3, 0x009db9}, /* U+6523 */ - {0x00e694a4, 0x009db8}, /* U+6524 */ - {0x00e694a9, 0x00eb46}, /* U+6529 [2000] */ - {0x00e694aa, 0x009d98}, /* U+652A */ - {0x00e694ab, 0x009dba}, /* U+652B */ - {0x00e694ac, 0x009dae}, /* U+652C */ - {0x00e694af, 0x008e78}, /* U+652F */ - {0x00e694b2, 0x00f381}, /* U+6532 [2000] */ - {0x00e694b4, 0x009dbb}, /* U+6534 */ - {0x00e694b5, 0x009dbc}, /* U+6535 */ - {0x00e694b6, 0x009dbe}, /* U+6536 */ - {0x00e694b7, 0x009dbd}, /* U+6537 */ - {0x00e694b8, 0x009dbf}, /* U+6538 */ - {0x00e694b9, 0x0089fc}, /* U+6539 */ - {0x00e694bb, 0x008d55}, /* U+653B */ - {0x00e694be, 0x0095fa}, /* U+653E */ - {0x00e694bf, 0x0090ad}, /* U+653F */ - {0x00e69584, 0x00f382}, /* U+6544 [2000] */ - {0x00e69585, 0x008ccc}, /* U+6545 */ - {0x00e69588, 0x009dc1}, /* U+6548 */ - {0x00e6958d, 0x009dc4}, /* U+654D */ - {0x00e6958f, 0x009571}, /* U+654F */ - {0x00e69591, 0x008b7e}, /* U+6551 */ - {0x00e69594, 0x00f383}, /* U+6554 [2000] */ - {0x00e69595, 0x009dc3}, /* U+6555 */ - {0x00e69596, 0x009dc2}, /* U+6556 */ - {0x00e69597, 0x009473}, /* U+6557 */ - {0x00e69598, 0x009dc5}, /* U+6558 */ - {0x00e69599, 0x008bb3}, /* U+6559 */ - {0x00e6959d, 0x009dc7}, /* U+655D */ - {0x00e6959e, 0x009dc6}, /* U+655E */ - {0x00e695a2, 0x008ab8}, /* U+6562 */ - {0x00e695a3, 0x008e55}, /* U+6563 */ - {0x00e695a6, 0x0093d6}, /* U+6566 */ - {0x00e695a7, 0x00eb48}, /* U+6567 [2000] */ - {0x00e695ab, 0x00f384}, /* U+656B [2000] */ - {0x00e695ac, 0x008c68}, /* U+656C */ - {0x00e695b0, 0x009094}, /* U+6570 */ - {0x00e695b2, 0x009dc8}, /* U+6572 */ - {0x00e695b4, 0x0090ae}, /* U+6574 */ - {0x00e695b5, 0x009347}, /* U+6575 */ - {0x00e695b7, 0x00957e}, /* U+6577 */ - {0x00e695b8, 0x009dc9}, /* U+6578 */ - {0x00e695ba, 0x00f385}, /* U+657A [2000] */ - {0x00e69681, 0x00f386}, /* U+6581 [2000] */ - {0x00e69682, 0x009dca}, /* U+6582 */ - {0x00e69683, 0x009dcb}, /* U+6583 */ - {0x00e69684, 0x00f387}, /* U+6584 [2000] */ - {0x00e69685, 0x00f388}, /* U+6585 [2000] */ - {0x00e69687, 0x0095b6}, /* U+6587 */ - {0x00e69688, 0x009b7c}, /* U+6588 */ - {0x00e69689, 0x0090c4}, /* U+6589 */ - {0x00e6968a, 0x00f389}, /* U+658A [2000] */ - {0x00e6968c, 0x00956b}, /* U+658C */ - {0x00e6968e, 0x008dd6}, /* U+658E */ - {0x00e69690, 0x0094e3}, /* U+6590 */ - {0x00e69691, 0x0094c1}, /* U+6591 */ - {0x00e69697, 0x00936c}, /* U+6597 */ - {0x00e69699, 0x0097bf}, /* U+6599 */ - {0x00e6969b, 0x009dcd}, /* U+659B */ - {0x00e6969c, 0x008ece}, /* U+659C */ - {0x00e6969d, 0x00eb49}, /* U+659D [2000] */ - {0x00e6969f, 0x009dce}, /* U+659F */ - {0x00e696a1, 0x0088b4}, /* U+65A1 */ - {0x00e696a4, 0x008bd2}, /* U+65A4 */ - {0x00e696a5, 0x0090cb}, /* U+65A5 */ - {0x00e696a7, 0x009580}, /* U+65A7 */ - {0x00e696ab, 0x009dcf}, /* U+65AB */ - {0x00e696ac, 0x008e61}, /* U+65AC */ - {0x00e696ad, 0x009266}, /* U+65AD */ - {0x00e696af, 0x008e7a}, /* U+65AF */ - {0x00e696b0, 0x009056}, /* U+65B0 */ - {0x00e696b2, 0x00f38a}, /* U+65B2 [2000] */ - {0x00e696b5, 0x00f38b}, /* U+65B5 [2000] */ - {0x00e696b7, 0x009dd0}, /* U+65B7 */ - {0x00e696b8, 0x00f38c}, /* U+65B8 [2000] */ - {0x00e696b9, 0x0095fb}, /* U+65B9 */ - {0x00e696bc, 0x008997}, /* U+65BC */ - {0x00e696bd, 0x008e7b}, /* U+65BD */ - {0x00e696bf, 0x00f38d}, /* U+65BF [2000] */ - {0x00e69781, 0x009dd3}, /* U+65C1 */ - {0x00e69782, 0x00f38e}, /* U+65C2 [2000] */ - {0x00e69783, 0x009dd1}, /* U+65C3 */ - {0x00e69784, 0x009dd4}, /* U+65C4 */ - {0x00e69785, 0x0097b7}, /* U+65C5 */ - {0x00e69786, 0x009dd2}, /* U+65C6 */ - {0x00e69789, 0x00f38f}, /* U+65C9 [2000] */ - {0x00e6978b, 0x0090f9}, /* U+65CB */ - {0x00e6978c, 0x009dd5}, /* U+65CC */ - {0x00e6978f, 0x0091b0}, /* U+65CF */ - {0x00e69792, 0x009dd6}, /* U+65D2 */ - {0x00e69794, 0x00f390}, /* U+65D4 [2000] */ - {0x00e69797, 0x008af8}, /* U+65D7 */ - {0x00e69799, 0x009dd8}, /* U+65D9 */ - {0x00e6979b, 0x009dd7}, /* U+65DB */ - {0x00e697a0, 0x009dd9}, /* U+65E0 */ - {0x00e697a1, 0x009dda}, /* U+65E1 */ - {0x00e697a2, 0x008af9}, /* U+65E2 */ - {0x00e697a5, 0x0093fa}, /* U+65E5 */ - {0x00e697a6, 0x009255}, /* U+65E6 */ - {0x00e697a7, 0x008b8c}, /* U+65E7 */ - {0x00e697a8, 0x008e7c}, /* U+65E8 */ - {0x00e697a9, 0x009181}, /* U+65E9 */ - {0x00e697ac, 0x008f7b}, /* U+65EC */ - {0x00e697ad, 0x0088ae}, /* U+65ED */ - {0x00e697b1, 0x009ddb}, /* U+65F1 */ - {0x00e697b2, 0x00f392}, /* U+65F2 [2000] */ - {0x00e697b9, 0x00f393}, /* U+65F9 [2000] */ - {0x00e697ba, 0x0089a0}, /* U+65FA */ - {0x00e697bb, 0x009ddf}, /* U+65FB */ - {0x00e697bc, 0x00f394}, /* U+65FC [2000] */ - {0x00e69880, 0x00eb4b}, /* U+6600 [2000] */ - {0x00e69882, 0x008d56}, /* U+6602 */ - {0x00e69883, 0x009dde}, /* U+6603 */ - {0x00e69884, 0x00f395}, /* U+6604 [2000] */ - {0x00e69886, 0x008da9}, /* U+6606 */ - {0x00e69887, 0x008fb8}, /* U+6607 */ - {0x00e69888, 0x00f396}, /* U+6608 [2000] */ - {0x00e69889, 0x00eb4c}, /* U+6609 [2000] */ - {0x00e6988a, 0x009ddd}, /* U+660A */ - {0x00e6988c, 0x008fb9}, /* U+660C */ - {0x00e6988e, 0x0096be}, /* U+660E */ - {0x00e6988f, 0x008da8}, /* U+660F */ - {0x00e69893, 0x0088d5}, /* U+6613 */ - {0x00e69894, 0x0090cc}, /* U+6614 */ - {0x00e69895, 0x00eb4d}, /* U+6615 [2000] */ - {0x00e6989c, 0x009de4}, /* U+661C */ - {0x00e6989e, 0x00eb4e}, /* U+661E [2000] */ - {0x00e6989f, 0x0090af}, /* U+661F */ - {0x00e698a0, 0x008966}, /* U+6620 */ - {0x00e698a1, 0x00f397}, /* U+6621 [2000] */ - {0x00e698a2, 0x00eb50}, /* U+6622 [2000] */ - {0x00e698a4, 0x00eb51}, /* U+6624 [2000] */ - {0x00e698a5, 0x008f74}, /* U+6625 */ - {0x00e698a7, 0x009686}, /* U+6627 */ - {0x00e698a8, 0x008df0}, /* U+6628 */ - {0x00e698aa, 0x00f398}, /* U+662A [2000] */ - {0x00e698ab, 0x00eb52}, /* U+662B [2000] */ - {0x00e698ad, 0x008fba}, /* U+662D */ - {0x00e698af, 0x0090a5}, /* U+662F */ - {0x00e698b0, 0x00eb53}, /* U+6630 [2000] */ - {0x00e698b1, 0x00eb54}, /* U+6631 [2000] */ - {0x00e698b3, 0x00eb55}, /* U+6633 [2000] */ - {0x00e698b4, 0x009de3}, /* U+6634 */ - {0x00e698b5, 0x009de1}, /* U+6635 */ - {0x00e698b6, 0x009de2}, /* U+6636 */ - {0x00e698ba, 0x00eb4f}, /* U+663A [2000] */ - {0x00e698bc, 0x00928b}, /* U+663C */ - {0x00e698bf, 0x009e45}, /* U+663F */ - {0x00e69981, 0x009de8}, /* U+6641 */ - {0x00e69982, 0x008e9e}, /* U+6642 */ - {0x00e69983, 0x008d57}, /* U+6643 */ - {0x00e69984, 0x009de6}, /* U+6644 */ - {0x00e69985, 0x00f399}, /* U+6645 [2000] */ - {0x00e69988, 0x00eb57}, /* U+6648 [2000] */ - {0x00e69989, 0x009de7}, /* U+6649 */ - {0x00e6998b, 0x009057}, /* U+664B */ - {0x00e6998c, 0x00eb58}, /* U+664C [2000] */ - {0x00e6998e, 0x00f39b}, /* U+664E [2000] */ - {0x00e6998f, 0x009de5}, /* U+664F */ - {0x00e69991, 0x00f39a}, /* U+6651 [2000] */ - {0x00e69992, 0x008e4e}, /* U+6652 */ - {0x00e69997, 0x00f39e}, /* U+6657 [2000] */ - {0x00e69999, 0x00eb5a}, /* U+6659 [2000] */ - {0x00e6999a, 0x00eb5b}, /* U+665A [2000] */ - {0x00e6999b, 0x00f39f}, /* U+665B [2000] */ - {0x00e6999d, 0x009dea}, /* U+665D */ - {0x00e6999e, 0x009de9}, /* U+665E */ - {0x00e6999f, 0x009dee}, /* U+665F */ - {0x00e699a1, 0x00eb5c}, /* U+6661 [2000] */ - {0x00e699a2, 0x009def}, /* U+6662 */ - {0x00e699a3, 0x00f3a0}, /* U+6663 [2000] */ - {0x00e699a4, 0x009deb}, /* U+6664 */ - {0x00e699a5, 0x00eb5d}, /* U+6665 [2000] */ - {0x00e699a6, 0x008a41}, /* U+6666 */ - {0x00e699a7, 0x009dec}, /* U+6667 */ - {0x00e699a8, 0x009ded}, /* U+6668 */ - {0x00e699a9, 0x0094d3}, /* U+6669 */ - {0x00e699aa, 0x00f3a3}, /* U+666A [2000] */ - {0x00e699ab, 0x00f3a4}, /* U+666B [2000] */ - {0x00e699ac, 0x00f3a5}, /* U+666C [2000] */ - {0x00e699ad, 0x00f3a6}, /* U+666D [2000] */ - {0x00e699ae, 0x009581}, /* U+666E */ - {0x00e699af, 0x008c69}, /* U+666F */ - {0x00e699b0, 0x009df0}, /* U+6670 */ - {0x00e699b3, 0x00eb5e}, /* U+6673 [2000] */ - {0x00e699b4, 0x0090b0}, /* U+6674 */ - {0x00e699b6, 0x008fbb}, /* U+6676 */ - {0x00e699b7, 0x00eb5f}, /* U+6677 [2000] */ - {0x00e699b8, 0x00eb60}, /* U+6678 [2000] */ - {0x00e699ba, 0x009271}, /* U+667A */ - {0x00e699bb, 0x00f3a7}, /* U+667B [2000] */ - {0x00e69a80, 0x00f3a8}, /* U+6680 [2000] */ - {0x00e69a81, 0x008bc5}, /* U+6681 */ - {0x00e69a83, 0x009df1}, /* U+6683 */ - {0x00e69a84, 0x009df5}, /* U+6684 */ - {0x00e69a87, 0x0089c9}, /* U+6687 */ - {0x00e69a88, 0x009df2}, /* U+6688 */ - {0x00e69a89, 0x009df4}, /* U+6689 */ - {0x00e69a8d, 0x00eb61}, /* U+668D [2000] */ - {0x00e69a8e, 0x009df3}, /* U+668E */ - {0x00e69a90, 0x00f3a9}, /* U+6690 [2000] */ - {0x00e69a91, 0x008f8b}, /* U+6691 */ - {0x00e69a92, 0x00f3aa}, /* U+6692 [2000] */ - {0x00e69a96, 0x009267}, /* U+6696 */ - {0x00e69a97, 0x0088c3}, /* U+6697 */ - {0x00e69a98, 0x009df6}, /* U+6698 */ - {0x00e69a99, 0x00f3ab}, /* U+6699 [2000] */ - {0x00e69a9d, 0x009df7}, /* U+669D */ - {0x00e69aa0, 0x00eb63}, /* U+66A0 [2000] */ - {0x00e69aa2, 0x0092a8}, /* U+66A2 */ - {0x00e69aa6, 0x0097ef}, /* U+66A6 */ - {0x00e69aab, 0x008e62}, /* U+66AB */ - {0x00e69aad, 0x00f3ad}, /* U+66AD [2000] */ - {0x00e69aae, 0x0095e9}, /* U+66AE */ - {0x00e69ab1, 0x00f3ae}, /* U+66B1 [2000] */ - {0x00e69ab2, 0x00eb64}, /* U+66B2 [2000] */ - {0x00e69ab4, 0x00965c}, /* U+66B4 */ - {0x00e69ab5, 0x00f3af}, /* U+66B5 [2000] */ - {0x00e69ab8, 0x009e41}, /* U+66B8 */ - {0x00e69ab9, 0x009df9}, /* U+66B9 */ - {0x00e69abb, 0x00eb65}, /* U+66BB [2000] */ - {0x00e69abc, 0x009dfc}, /* U+66BC */ - {0x00e69abe, 0x009dfb}, /* U+66BE */ - {0x00e69abf, 0x00f3b1}, /* U+66BF [2000] */ - {0x00e69b81, 0x009df8}, /* U+66C1 */ - {0x00e69b84, 0x009e40}, /* U+66C4 */ - {0x00e69b86, 0x00eb66}, /* U+66C6 [2000] */ - {0x00e69b87, 0x0093dc}, /* U+66C7 */ - {0x00e69b88, 0x00eb67}, /* U+66C8 [2000] */ - {0x00e69b89, 0x009dfa}, /* U+66C9 */ - {0x00e69b96, 0x009e42}, /* U+66D6 */ - {0x00e69b99, 0x008f8c}, /* U+66D9 */ - {0x00e69b9a, 0x009e43}, /* U+66DA */ - {0x00e69b9b, 0x00eb69}, /* U+66DB [2000] */ - {0x00e69b9c, 0x00976a}, /* U+66DC */ - {0x00e69b9d, 0x009498}, /* U+66DD */ - {0x00e69ba0, 0x009e44}, /* U+66E0 */ - {0x00e69ba6, 0x009e46}, /* U+66E6 */ - {0x00e69ba8, 0x00eb6a}, /* U+66E8 [2000] */ - {0x00e69ba9, 0x009e47}, /* U+66E9 */ - {0x00e69bac, 0x00f3b3}, /* U+66EC [2000] */ - {0x00e69bb0, 0x009e48}, /* U+66F0 */ - {0x00e69bb2, 0x008bc8}, /* U+66F2 */ - {0x00e69bb3, 0x008967}, /* U+66F3 */ - {0x00e69bb4, 0x008d58}, /* U+66F4 */ - {0x00e69bb5, 0x009e49}, /* U+66F5 */ - {0x00e69bb7, 0x009e4a}, /* U+66F7 */ - {0x00e69bb8, 0x008f91}, /* U+66F8 */ - {0x00e69bb9, 0x009182}, /* U+66F9 */ - {0x00e69bba, 0x00eb6b}, /* U+66FA [2000] */ - {0x00e69bbb, 0x00eb56}, /* U+66FB [2000] */ - {0x00e69bbc, 0x0099d6}, /* U+66FC */ - {0x00e69bbd, 0x00915d}, /* U+66FD */ - {0x00e69bbe, 0x00915c}, /* U+66FE */ - {0x00e69bbf, 0x0091d6}, /* U+66FF */ - {0x00e69c80, 0x008dc5}, /* U+6700 */ - {0x00e69c81, 0x00f3b5}, /* U+6701 [2000] */ - {0x00e69c83, 0x0098f0}, /* U+6703 */ - {0x00e69c85, 0x00f3b6}, /* U+6705 [2000] */ - {0x00e69c88, 0x008c8e}, /* U+6708 */ - {0x00e69c89, 0x00974c}, /* U+6709 */ - {0x00e69c8b, 0x0095fc}, /* U+670B */ - {0x00e69c8d, 0x00959e}, /* U+670D */ - {0x00e69c8f, 0x009e4b}, /* U+670F */ - {0x00e69c92, 0x00f3b7}, /* U+6712 [2000] */ - {0x00e69c93, 0x00eb6c}, /* U+6713 [2000] */ - {0x00e69c94, 0x008df1}, /* U+6714 */ - {0x00e69c95, 0x0092bd}, /* U+6715 */ - {0x00e69c96, 0x009e4c}, /* U+6716 */ - {0x00e69c97, 0x00984e}, /* U+6717 */ - {0x00e69c99, 0x00f3b9}, /* U+6719 [2000] */ - {0x00e69c9b, 0x00965d}, /* U+671B */ - {0x00e69c9d, 0x0092a9}, /* U+671D */ - {0x00e69c9e, 0x009e4d}, /* U+671E */ - {0x00e69c9f, 0x008afa}, /* U+671F */ - {0x00e69ca6, 0x009e4e}, /* U+6726 */ - {0x00e69ca7, 0x009e4f}, /* U+6727 */ - {0x00e69ca8, 0x0096d8}, /* U+6728 */ - {0x00e69caa, 0x0096a2}, /* U+672A */ - {0x00e69cab, 0x009696}, /* U+672B */ - {0x00e69cac, 0x00967b}, /* U+672C */ - {0x00e69cad, 0x008e44}, /* U+672D */ - {0x00e69cae, 0x009e51}, /* U+672E */ - {0x00e69cb1, 0x008ee9}, /* U+6731 */ - {0x00e69cb3, 0x00eb6e}, /* U+6733 [2000] */ - {0x00e69cb4, 0x009670}, /* U+6734 */ - {0x00e69cb6, 0x009e53}, /* U+6736 */ - {0x00e69cb7, 0x009e56}, /* U+6737 */ - {0x00e69cb8, 0x009e55}, /* U+6738 */ - {0x00e69cba, 0x008af7}, /* U+673A */ - {0x00e69cbd, 0x008b80}, /* U+673D */ - {0x00e69cbf, 0x009e52}, /* U+673F */ - {0x00e69d81, 0x009e54}, /* U+6741 */ - {0x00e69d86, 0x009e57}, /* U+6746 */ - {0x00e69d87, 0x00eb70}, /* U+6747 [2000] */ - {0x00e69d88, 0x00eb71}, /* U+6748 [2000] */ - {0x00e69d89, 0x009099}, /* U+6749 */ - {0x00e69d8c, 0x00f3bc}, /* U+674C [2000] */ - {0x00e69d8d, 0x00f3bd}, /* U+674D [2000] */ - {0x00e69d8e, 0x00979b}, /* U+674E */ - {0x00e69d8f, 0x0088c7}, /* U+674F */ - {0x00e69d90, 0x008dde}, /* U+6750 */ - {0x00e69d91, 0x0091ba}, /* U+6751 */ - {0x00e69d93, 0x008edb}, /* U+6753 */ - {0x00e69d94, 0x00f3be}, /* U+6754 [2000] */ - {0x00e69d96, 0x008ff1}, /* U+6756 */ - {0x00e69d99, 0x009e5a}, /* U+6759 */ - {0x00e69d9c, 0x00936d}, /* U+675C */ - {0x00e69d9d, 0x00f3bf}, /* U+675D [2000] */ - {0x00e69d9e, 0x009e58}, /* U+675E */ - {0x00e69d9f, 0x0091a9}, /* U+675F */ - {0x00e69da0, 0x009e59}, /* U+6760 */ - {0x00e69da1, 0x008ff0}, /* U+6761 */ - {0x00e69da2, 0x0096db}, /* U+6762 */ - {0x00e69da3, 0x009e5b}, /* U+6763 */ - {0x00e69da4, 0x009e5c}, /* U+6764 */ - {0x00e69da5, 0x009788}, /* U+6765 */ - {0x00e69da6, 0x00eb6f}, /* U+6766 [2000] */ - {0x00e69daa, 0x009e61}, /* U+676A */ - {0x00e69dad, 0x008d59}, /* U+676D */ - {0x00e69daf, 0x009474}, /* U+676F */ - {0x00e69db0, 0x009e5e}, /* U+6770 */ - {0x00e69db1, 0x00938c}, /* U+6771 */ - {0x00e69db2, 0x009ddc}, /* U+6772 */ - {0x00e69db3, 0x009de0}, /* U+6773 */ - {0x00e69db4, 0x00f3c3}, /* U+6774 [2000] */ - {0x00e69db5, 0x008b6e}, /* U+6775 */ - {0x00e69db6, 0x00f3c4}, /* U+6776 [2000] */ - {0x00e69db7, 0x009466}, /* U+6777 */ - {0x00e69dbb, 0x00eb72}, /* U+677B [2000] */ - {0x00e69dbc, 0x009e60}, /* U+677C */ - {0x00e69dbe, 0x008fbc}, /* U+677E */ - {0x00e69dbf, 0x0094c2}, /* U+677F */ - {0x00e69e81, 0x00eb73}, /* U+6781 [2000] */ - {0x00e69e85, 0x009e66}, /* U+6785 */ - {0x00e69e87, 0x0094f8}, /* U+6787 */ - {0x00e69e89, 0x009e5d}, /* U+6789 */ - {0x00e69e8b, 0x009e63}, /* U+678B */ - {0x00e69e8c, 0x009e62}, /* U+678C */ - {0x00e69e90, 0x0090cd}, /* U+6790 */ - {0x00e69e92, 0x00f3c6}, /* U+6792 [2000] */ - {0x00e69e93, 0x00eb74}, /* U+6793 [2000] */ - {0x00e69e95, 0x00968d}, /* U+6795 */ - {0x00e69e97, 0x0097d1}, /* U+6797 */ - {0x00e69e98, 0x00eb75}, /* U+6798 [2000] */ - {0x00e69e9a, 0x009687}, /* U+679A */ - {0x00e69e9b, 0x00eb76}, /* U+679B [2000] */ - {0x00e69e9c, 0x0089ca}, /* U+679C */ - {0x00e69e9d, 0x008e7d}, /* U+679D */ - {0x00e69ea0, 0x009867}, /* U+67A0 */ - {0x00e69ea1, 0x009e65}, /* U+67A1 */ - {0x00e69ea2, 0x009095}, /* U+67A2 */ - {0x00e69ea6, 0x009e64}, /* U+67A6 */ - {0x00e69ea9, 0x009e5f}, /* U+67A9 */ - {0x00e69eaf, 0x008ccd}, /* U+67AF */ - {0x00e69eb0, 0x00f3ca}, /* U+67B0 [2000] */ - {0x00e69eb2, 0x00f3cb}, /* U+67B2 [2000] */ - {0x00e69eb3, 0x009e6b}, /* U+67B3 */ - {0x00e69eb4, 0x009e69}, /* U+67B4 */ - {0x00e69eb6, 0x0089cb}, /* U+67B6 */ - {0x00e69eb7, 0x009e67}, /* U+67B7 */ - {0x00e69eb8, 0x009e6d}, /* U+67B8 */ - {0x00e69eb9, 0x009e73}, /* U+67B9 */ - {0x00e69ebb, 0x00eb77}, /* U+67BB [2000] */ - {0x00e69f80, 0x00eb79}, /* U+67C0 [2000] */ - {0x00e69f81, 0x0091c6}, /* U+67C1 */ - {0x00e69f83, 0x00f3cc}, /* U+67C3 [2000] */ - {0x00e69f84, 0x0095bf}, /* U+67C4 */ - {0x00e69f86, 0x009e75}, /* U+67C6 */ - {0x00e69f88, 0x00f3cd}, /* U+67C8 [2000] */ - {0x00e69f8a, 0x009541}, /* U+67CA */ - {0x00e69f8e, 0x009e74}, /* U+67CE */ - {0x00e69f8f, 0x009490}, /* U+67CF */ - {0x00e69f90, 0x00965e}, /* U+67D0 */ - {0x00e69f91, 0x008ab9}, /* U+67D1 */ - {0x00e69f92, 0x00f3ce}, /* U+67D2 [2000] */ - {0x00e69f93, 0x0090f5}, /* U+67D3 */ - {0x00e69f94, 0x008f5f}, /* U+67D4 */ - {0x00e69f97, 0x00eb7a}, /* U+67D7 [2000] */ - {0x00e69f98, 0x0092d1}, /* U+67D8 */ - {0x00e69f99, 0x00f3cf}, /* U+67D9 [2000] */ - {0x00e69f9a, 0x00974d}, /* U+67DA */ - {0x00e69f9b, 0x00f3d0}, /* U+67DB [2000] */ - {0x00e69f9d, 0x009e70}, /* U+67DD */ - {0x00e69f9e, 0x009e6f}, /* U+67DE */ - {0x00e69fa2, 0x009e71}, /* U+67E2 */ - {0x00e69fa4, 0x009e6e}, /* U+67E4 */ - {0x00e69fa7, 0x009e76}, /* U+67E7 */ - {0x00e69fa9, 0x009e6c}, /* U+67E9 */ - {0x00e69fac, 0x009e6a}, /* U+67EC */ - {0x00e69fae, 0x009e72}, /* U+67EE */ - {0x00e69faf, 0x009e68}, /* U+67EF */ - {0x00e69fb0, 0x00f3d1}, /* U+67F0 [2000] */ - {0x00e69fb1, 0x00928c}, /* U+67F1 */ - {0x00e69fb3, 0x0096f6}, /* U+67F3 */ - {0x00e69fb4, 0x008ec4}, /* U+67F4 */ - {0x00e69fb5, 0x008df2}, /* U+67F5 */ - {0x00e69fb7, 0x00f3d2}, /* U+67F7 [2000] */ - {0x00e69fb9, 0x00eb78}, /* U+67F9 [2000] */ - {0x00e69fbb, 0x008db8}, /* U+67FB */ - {0x00e69fbc, 0x00eb7b}, /* U+67FC [2000] */ - {0x00e69fbe, 0x00968f}, /* U+67FE */ - {0x00e69fbf, 0x008a60}, /* U+67FF */ - {0x00e6a081, 0x00eb7c}, /* U+6801 [2000] */ - {0x00e6a082, 0x0092cc}, /* U+6802 */ - {0x00e6a083, 0x0093c8}, /* U+6803 */ - {0x00e6a084, 0x008968}, /* U+6804 */ - {0x00e6a090, 0x00f3c9}, /* U+6810 [2000] */ - {0x00e6a093, 0x0090f0}, /* U+6813 */ - {0x00e6a096, 0x0090b2}, /* U+6816 */ - {0x00e6a097, 0x008c49}, /* U+6817 */ - {0x00e6a098, 0x00f3d6}, /* U+6818 [2000] */ - {0x00e6a09d, 0x00eb7e}, /* U+681D [2000] */ - {0x00e6a09e, 0x009e78}, /* U+681E */ - {0x00e6a09f, 0x00f3d7}, /* U+681F [2000] */ - {0x00e6a0a1, 0x008d5a}, /* U+6821 */ - {0x00e6a0a2, 0x008a9c}, /* U+6822 */ - {0x00e6a0a9, 0x009e7a}, /* U+6829 */ - {0x00e6a0aa, 0x008a94}, /* U+682A */ - {0x00e6a0ab, 0x009e81}, /* U+682B */ - {0x00e6a0ac, 0x00eb80}, /* U+682C [2000] */ - {0x00e6a0ad, 0x00f3d8}, /* U+682D [2000] */ - {0x00e6a0b1, 0x00eb81}, /* U+6831 [2000] */ - {0x00e6a0b2, 0x009e7d}, /* U+6832 */ - {0x00e6a0b3, 0x00f3da}, /* U+6833 [2000] */ - {0x00e6a0b4, 0x0090f1}, /* U+6834 */ - {0x00e6a0b8, 0x008a6a}, /* U+6838 */ - {0x00e6a0b9, 0x008daa}, /* U+6839 */ - {0x00e6a0bb, 0x00f3db}, /* U+683B [2000] */ - {0x00e6a0bc, 0x008a69}, /* U+683C */ - {0x00e6a0bd, 0x008dcd}, /* U+683D */ - {0x00e6a0be, 0x00f3dc}, /* U+683E [2000] */ - {0x00e6a180, 0x009e7b}, /* U+6840 */ - {0x00e6a181, 0x008c85}, /* U+6841 */ - {0x00e6a182, 0x008c6a}, /* U+6842 */ - {0x00e6a183, 0x00938d}, /* U+6843 */ - {0x00e6a184, 0x00f3dd}, /* U+6844 [2000] */ - {0x00e6a185, 0x00f3de}, /* U+6845 [2000] */ - {0x00e6a186, 0x009e79}, /* U+6846 */ - {0x00e6a188, 0x0088c4}, /* U+6848 */ - {0x00e6a189, 0x00f3df}, /* U+6849 [2000] */ - {0x00e6a18c, 0x00f3e0}, /* U+684C [2000] */ - {0x00e6a18d, 0x009e7c}, /* U+684D */ - {0x00e6a18e, 0x009e7e}, /* U+684E */ - {0x00e6a190, 0x008bcb}, /* U+6850 */ - {0x00e6a191, 0x008c4b}, /* U+6851 */ - {0x00e6a192, 0x00eb7d}, /* U+6852 [2000] */ - {0x00e6a193, 0x008aba}, /* U+6853 */ - {0x00e6a194, 0x008b6a}, /* U+6854 */ - {0x00e6a195, 0x00f3e1}, /* U+6855 [2000] */ - {0x00e6a197, 0x00f3e2}, /* U+6857 [2000] */ - {0x00e6a199, 0x009e82}, /* U+6859 */ - {0x00e6a19b, 0x00eb82}, /* U+685B [2000] */ - {0x00e6a19c, 0x008df7}, /* U+685C */ - {0x00e6a19d, 0x009691}, /* U+685D */ - {0x00e6a19f, 0x008e56}, /* U+685F */ - {0x00e6a1a3, 0x009e83}, /* U+6863 */ - {0x00e6a1a7, 0x00954f}, /* U+6867 */ - {0x00e6a1ab, 0x00f3e4}, /* U+686B [2000] */ - {0x00e6a1ae, 0x00f3e5}, /* U+686E [2000] */ - {0x00e6a1b2, 0x00eb83}, /* U+6872 [2000] */ - {0x00e6a1b4, 0x009e8f}, /* U+6874 */ - {0x00e6a1b5, 0x00eb84}, /* U+6875 [2000] */ - {0x00e6a1b6, 0x0089b1}, /* U+6876 */ - {0x00e6a1b7, 0x009e84}, /* U+6877 */ - {0x00e6a1ba, 0x00f3e6}, /* U+687A [2000] */ - {0x00e6a1bc, 0x00f3e7}, /* U+687C [2000] */ - {0x00e6a1be, 0x009e95}, /* U+687E */ - {0x00e6a1bf, 0x009e85}, /* U+687F */ - {0x00e6a281, 0x0097c0}, /* U+6881 */ - {0x00e6a282, 0x00f3e8}, /* U+6882 [2000] */ - {0x00e6a283, 0x009e8c}, /* U+6883 */ - {0x00e6a285, 0x00947e}, /* U+6885 */ - {0x00e6a28d, 0x009e94}, /* U+688D */ - {0x00e6a28f, 0x009e87}, /* U+688F */ - {0x00e6a290, 0x00f3e9}, /* U+6890 [2000] */ - {0x00e6a293, 0x0088b2}, /* U+6893 */ - {0x00e6a294, 0x009e89}, /* U+6894 */ - {0x00e6a296, 0x00f3ea}, /* U+6896 [2000] */ - {0x00e6a297, 0x008d5b}, /* U+6897 */ - {0x00e6a298, 0x00f3ec}, /* U+6898 [2000] */ - {0x00e6a299, 0x00f3ed}, /* U+6899 [2000] */ - {0x00e6a29a, 0x00f3ee}, /* U+689A [2000] */ - {0x00e6a29b, 0x009e8b}, /* U+689B */ - {0x00e6a29c, 0x00f3ef}, /* U+689C [2000] */ - {0x00e6a29d, 0x009e8a}, /* U+689D */ - {0x00e6a29f, 0x009e86}, /* U+689F */ - {0x00e6a2a0, 0x009e91}, /* U+68A0 */ - {0x00e6a2a2, 0x008fbd}, /* U+68A2 */ - {0x00e6a2a3, 0x00eb86}, /* U+68A3 [2000] */ - {0x00e6a2a5, 0x00eb87}, /* U+68A5 [2000] */ - {0x00e6a2a6, 0x009aeb}, /* U+68A6 */ - {0x00e6a2a7, 0x008ce6}, /* U+68A7 */ - {0x00e6a2a8, 0x00979c}, /* U+68A8 */ - {0x00e6a2aa, 0x00f3f0}, /* U+68AA [2000] */ - {0x00e6a2ab, 0x00f3f1}, /* U+68AB [2000] */ - {0x00e6a2ad, 0x009e88}, /* U+68AD */ - {0x00e6a2af, 0x0092f2}, /* U+68AF */ - {0x00e6a2b0, 0x008a42}, /* U+68B0 */ - {0x00e6a2b1, 0x008dab}, /* U+68B1 */ - {0x00e6a2b2, 0x00eb88}, /* U+68B2 [2000] */ - {0x00e6a2b3, 0x009e80}, /* U+68B3 */ - {0x00e6a2b4, 0x00f3f2}, /* U+68B4 [2000] */ - {0x00e6a2b5, 0x009e90}, /* U+68B5 */ - {0x00e6a2b6, 0x008a81}, /* U+68B6 */ - {0x00e6a2b9, 0x009e8e}, /* U+68B9 */ - {0x00e6a2ba, 0x009e92}, /* U+68BA */ - {0x00e6a2bb, 0x00f3f3}, /* U+68BB [2000] */ - {0x00e6a2bc, 0x00938e}, /* U+68BC */ - {0x00e6a383, 0x00f3f8}, /* U+68C3 [2000] */ - {0x00e6a384, 0x008afc}, /* U+68C4 */ - {0x00e6a385, 0x00f3f9}, /* U+68C5 [2000] */ - {0x00e6a386, 0x009eb0}, /* U+68C6 */ - {0x00e6a388, 0x00eb89}, /* U+68C8 [2000] */ - {0x00e6a389, 0x0096c7}, /* U+68C9 */ - {0x00e6a38a, 0x009e97}, /* U+68CA */ - {0x00e6a38b, 0x008afb}, /* U+68CB */ - {0x00e6a38c, 0x00f3fa}, /* U+68CC [2000] */ - {0x00e6a38d, 0x009e9e}, /* U+68CD */ - {0x00e6a38f, 0x00f3fb}, /* U+68CF [2000] */ - {0x00e6a390, 0x00eb8a}, /* U+68D0 [2000] */ - {0x00e6a392, 0x00965f}, /* U+68D2 */ - {0x00e6a394, 0x009e9f}, /* U+68D4 */ - {0x00e6a395, 0x009ea1}, /* U+68D5 */ - {0x00e6a396, 0x00f3fc}, /* U+68D6 [2000] */ - {0x00e6a397, 0x009ea5}, /* U+68D7 */ - {0x00e6a398, 0x009e99}, /* U+68D8 */ - {0x00e6a399, 0x00f440}, /* U+68D9 [2000] */ - {0x00e6a39a, 0x009249}, /* U+68DA */ - {0x00e6a39f, 0x00938f}, /* U+68DF */ - {0x00e6a3a0, 0x009ea9}, /* U+68E0 */ - {0x00e6a3a1, 0x009e9c}, /* U+68E1 */ - {0x00e6a3a3, 0x009ea6}, /* U+68E3 */ - {0x00e6a3a4, 0x00f441}, /* U+68E4 [2000] */ - {0x00e6a3a5, 0x00f442}, /* U+68E5 [2000] */ - {0x00e6a3a7, 0x009ea0}, /* U+68E7 */ - {0x00e6a3a8, 0x00eb8b}, /* U+68E8 [2000] */ - {0x00e6a3ac, 0x00f443}, /* U+68EC [2000] */ - {0x00e6a3ad, 0x00eb8c}, /* U+68ED [2000] */ - {0x00e6a3ae, 0x009058}, /* U+68EE */ - {0x00e6a3af, 0x009eaa}, /* U+68EF */ - {0x00e6a3b0, 0x00eb8d}, /* U+68F0 [2000] */ - {0x00e6a3b1, 0x00eb8e}, /* U+68F1 [2000] */ - {0x00e6a3b2, 0x0090b1}, /* U+68F2 */ - {0x00e6a3b7, 0x00f444}, /* U+68F7 [2000] */ - {0x00e6a3b9, 0x009ea8}, /* U+68F9 */ - {0x00e6a3ba, 0x008abb}, /* U+68FA */ - {0x00e6a3bb, 0x00f3f4}, /* U+68FB [2000] */ - {0x00e6a3bc, 0x00eb8f}, /* U+68FC [2000] */ - {0x00e6a480, 0x00986f}, /* U+6900 */ - {0x00e6a481, 0x009e96}, /* U+6901 */ - {0x00e6a483, 0x00f445}, /* U+6903 [2000] */ - {0x00e6a484, 0x009ea4}, /* U+6904 */ - {0x00e6a485, 0x0088d6}, /* U+6905 */ - {0x00e6a487, 0x00f446}, /* U+6907 [2000] */ - {0x00e6a488, 0x009e98}, /* U+6908 */ - {0x00e6a48a, 0x00eb90}, /* U+690A [2000] */ - {0x00e6a48b, 0x0096b8}, /* U+690B */ - {0x00e6a48c, 0x009e9d}, /* U+690C */ - {0x00e6a48d, 0x009041}, /* U+690D */ - {0x00e6a48e, 0x0092c5}, /* U+690E */ - {0x00e6a48f, 0x009e93}, /* U+690F */ - {0x00e6a492, 0x009ea3}, /* U+6912 */ - {0x00e6a499, 0x00909a}, /* U+6919 */ - {0x00e6a49a, 0x009ead}, /* U+691A */ - {0x00e6a49b, 0x008a91}, /* U+691B */ - {0x00e6a49c, 0x008c9f}, /* U+691C */ - {0x00e6a4a1, 0x009eaf}, /* U+6921 */ - {0x00e6a4a2, 0x009e9a}, /* U+6922 */ - {0x00e6a4a3, 0x009eae}, /* U+6923 */ - {0x00e6a4a5, 0x009ea7}, /* U+6925 */ - {0x00e6a4a6, 0x009e9b}, /* U+6926 */ - {0x00e6a4a8, 0x009eab}, /* U+6928 */ - {0x00e6a4aa, 0x009eac}, /* U+692A */ - {0x00e6a4b0, 0x009ebd}, /* U+6930 */ - {0x00e6a4b4, 0x0093cc}, /* U+6934 */ - {0x00e6a4b5, 0x00eb93}, /* U+6935 [2000] */ - {0x00e6a4b6, 0x009ea2}, /* U+6936 */ - {0x00e6a4b9, 0x009eb9}, /* U+6939 */ - {0x00e6a4bb, 0x00f44a}, /* U+693B [2000] */ - {0x00e6a4bd, 0x009ebb}, /* U+693D */ - {0x00e6a4bf, 0x0092d6}, /* U+693F */ - {0x00e6a582, 0x00eb94}, /* U+6942 [2000] */ - {0x00e6a586, 0x00f44c}, /* U+6946 [2000] */ - {0x00e6a589, 0x00eb91}, /* U+6949 [2000] */ - {0x00e6a58a, 0x00976b}, /* U+694A */ - {0x00e6a593, 0x009596}, /* U+6953 */ - {0x00e6a594, 0x009eb6}, /* U+6954 */ - {0x00e6a595, 0x0091c8}, /* U+6955 */ - {0x00e6a597, 0x00eb95}, /* U+6957 [2000] */ - {0x00e6a599, 0x009ebc}, /* U+6959 */ - {0x00e6a59a, 0x00915e}, /* U+695A */ - {0x00e6a59c, 0x009eb3}, /* U+695C */ - {0x00e6a59d, 0x009ec0}, /* U+695D */ - {0x00e6a59e, 0x009ebf}, /* U+695E */ - {0x00e6a5a0, 0x0093ed}, /* U+6960 */ - {0x00e6a5a1, 0x009ebe}, /* U+6961 */ - {0x00e6a5a2, 0x0093e8}, /* U+6962 */ - {0x00e6a5a3, 0x00eb96}, /* U+6963 [2000] */ - {0x00e6a5a4, 0x00eb97}, /* U+6964 [2000] */ - {0x00e6a5a8, 0x00eb98}, /* U+6968 [2000] */ - {0x00e6a5a9, 0x00f44d}, /* U+6969 [2000] */ - {0x00e6a5aa, 0x009ec2}, /* U+696A */ - {0x00e6a5ab, 0x009eb5}, /* U+696B */ - {0x00e6a5ac, 0x00f44e}, /* U+696C [2000] */ - {0x00e6a5ad, 0x008bc6}, /* U+696D */ - {0x00e6a5ae, 0x009eb8}, /* U+696E */ - {0x00e6a5af, 0x008f7c}, /* U+696F */ - {0x00e6a5b2, 0x00f44f}, /* U+6972 [2000] */ - {0x00e6a5b3, 0x009480}, /* U+6973 */ - {0x00e6a5b4, 0x009eba}, /* U+6974 */ - {0x00e6a5b5, 0x008bc9}, /* U+6975 */ - {0x00e6a5b7, 0x009eb2}, /* U+6977 */ - {0x00e6a5b8, 0x009eb4}, /* U+6978 */ - {0x00e6a5b9, 0x009eb1}, /* U+6979 */ - {0x00e6a5ba, 0x00f450}, /* U+697A [2000] */ - {0x00e6a5bc, 0x00984f}, /* U+697C */ - {0x00e6a5bd, 0x008a79}, /* U+697D */ - {0x00e6a5be, 0x009eb7}, /* U+697E */ - {0x00e6a5bf, 0x00f451}, /* U+697F [2000] */ - {0x00e6a680, 0x00eb99}, /* U+6980 [2000] */ - {0x00e6a681, 0x009ec1}, /* U+6981 */ - {0x00e6a682, 0x008a54}, /* U+6982 */ - {0x00e6a68a, 0x008de5}, /* U+698A */ - {0x00e6a68e, 0x00897c}, /* U+698E */ - {0x00e6a691, 0x009ed2}, /* U+6991 */ - {0x00e6a692, 0x00f452}, /* U+6992 [2000] */ - {0x00e6a694, 0x009850}, /* U+6994 */ - {0x00e6a695, 0x009ed5}, /* U+6995 */ - {0x00e6a696, 0x00f454}, /* U+6996 [2000] */ - {0x00e6a698, 0x00f455}, /* U+6998 [2000] */ - {0x00e6a69b, 0x009059}, /* U+699B */ - {0x00e6a69c, 0x009ed4}, /* U+699C */ - {0x00e6a6a0, 0x009ed3}, /* U+69A0 */ - {0x00e6a6a5, 0x00eb9b}, /* U+69A5 [2000] */ - {0x00e6a6a6, 0x00f456}, /* U+69A6 [2000] */ - {0x00e6a6a7, 0x009ed0}, /* U+69A7 */ - {0x00e6a6ad, 0x00eb9c}, /* U+69AD [2000] */ - {0x00e6a6ae, 0x009ec4}, /* U+69AE */ - {0x00e6a6b0, 0x00f457}, /* U+69B0 [2000] */ - {0x00e6a6b1, 0x009ee1}, /* U+69B1 */ - {0x00e6a6b2, 0x009ec3}, /* U+69B2 */ - {0x00e6a6b4, 0x009ed6}, /* U+69B4 */ - {0x00e6a6b7, 0x00f458}, /* U+69B7 [2000] */ - {0x00e6a6ba, 0x00f459}, /* U+69BA [2000] */ - {0x00e6a6bb, 0x009ece}, /* U+69BB */ - {0x00e6a6bc, 0x00f45a}, /* U+69BC [2000] */ - {0x00e6a6be, 0x009ec9}, /* U+69BE */ - {0x00e6a6bf, 0x009ec6}, /* U+69BF */ - {0x00e6a780, 0x00f45b}, /* U+69C0 [2000] */ - {0x00e6a781, 0x009ec7}, /* U+69C1 */ - {0x00e6a783, 0x009ecf}, /* U+69C3 */ - {0x00e6a787, 0x00eaa0}, /* U+69C7 [1983] */ - {0x00e6a78a, 0x009ecc}, /* U+69CA */ - {0x00e6a78b, 0x008d5c}, /* U+69CB */ - {0x00e6a78c, 0x0092c6}, /* U+69CC */ - {0x00e6a78d, 0x009184}, /* U+69CD */ - {0x00e6a78e, 0x009eca}, /* U+69CE */ - {0x00e6a78f, 0x00eb9d}, /* U+69CF [2000] */ - {0x00e6a790, 0x009ec5}, /* U+69D0 */ - {0x00e6a791, 0x00f45c}, /* U+69D1 [2000] */ - {0x00e6a793, 0x009ec8}, /* U+69D3 */ - {0x00e6a796, 0x00f45d}, /* U+69D6 [2000] */ - {0x00e6a798, 0x00976c}, /* U+69D8 */ - {0x00e6a799, 0x00968a}, /* U+69D9 */ - {0x00e6a79d, 0x009ecd}, /* U+69DD */ - {0x00e6a79e, 0x009ed7}, /* U+69DE */ - {0x00e6a7a2, 0x00eba0}, /* U+69E2 [2000] */ - {0x00e6a7a3, 0x00f463}, /* U+69E3 [2000] */ - {0x00e6a7a7, 0x009edf}, /* U+69E7 */ - {0x00e6a7a8, 0x009ed8}, /* U+69E8 */ - {0x00e6a7a9, 0x00eba1}, /* U+69E9 [2000] */ - {0x00e6a7aa, 0x00eba2}, /* U+69EA [2000] */ - {0x00e6a7ab, 0x009ee5}, /* U+69EB */ - {0x00e6a7ad, 0x009ee3}, /* U+69ED */ - {0x00e6a7ae, 0x00f464}, /* U+69EE [2000] */ - {0x00e6a7af, 0x00f465}, /* U+69EF [2000] */ - {0x00e6a7b2, 0x009ede}, /* U+69F2 */ - {0x00e6a7b3, 0x00f466}, /* U+69F3 [2000] */ - {0x00e6a7b4, 0x00f468}, /* U+69F4 [2000] */ - {0x00e6a7b5, 0x00eba3}, /* U+69F5 [2000] */ - {0x00e6a7b6, 0x00eba4}, /* U+69F6 [2000] */ - {0x00e6a7b9, 0x009edd}, /* U+69F9 */ - {0x00e6a7bb, 0x0092ce}, /* U+69FB */ - {0x00e6a7bd, 0x009185}, /* U+69FD */ - {0x00e6a7be, 0x00f469}, /* U+69FE [2000] */ - {0x00e6a7bf, 0x009edb}, /* U+69FF */ - {0x00e6a882, 0x009ed9}, /* U+6A02 */ - {0x00e6a885, 0x009ee0}, /* U+6A05 */ - {0x00e6a88a, 0x009ee6}, /* U+6A0A */ - {0x00e6a88b, 0x0094f3}, /* U+6A0B */ - {0x00e6a88c, 0x009eec}, /* U+6A0C */ - {0x00e6a88f, 0x00eba5}, /* U+6A0F [2000] */ - {0x00e6a891, 0x00f46a}, /* U+6A11 [2000] */ - {0x00e6a892, 0x009ee7}, /* U+6A12 */ - {0x00e6a893, 0x009eea}, /* U+6A13 */ - {0x00e6a894, 0x009ee4}, /* U+6A14 */ - {0x00e6a895, 0x00eba6}, /* U+6A15 [2000] */ - {0x00e6a897, 0x009294}, /* U+6A17 */ - {0x00e6a899, 0x009557}, /* U+6A19 */ - {0x00e6a89a, 0x00f46b}, /* U+6A1A [2000] */ - {0x00e6a89b, 0x009eda}, /* U+6A1B */ - {0x00e6a89d, 0x00f46c}, /* U+6A1D [2000] */ - {0x00e6a89e, 0x009ee2}, /* U+6A1E */ - {0x00e6a89f, 0x008fbe}, /* U+6A1F */ - {0x00e6a8a1, 0x0096cd}, /* U+6A21 */ - {0x00e6a8a2, 0x009ef6}, /* U+6A22 */ - {0x00e6a8a3, 0x009ee9}, /* U+6A23 */ - {0x00e6a8a9, 0x008ca0}, /* U+6A29 */ - {0x00e6a8aa, 0x0089a1}, /* U+6A2A */ - {0x00e6a8ab, 0x008a7e}, /* U+6A2B */ - {0x00e6a8ae, 0x009ed1}, /* U+6A2E */ - {0x00e6a8b0, 0x00f460}, /* U+6A30 [2000] */ - {0x00e6a8b2, 0x00f46e}, /* U+6A32 [2000] */ - {0x00e6a8b3, 0x00f46f}, /* U+6A33 [2000] */ - {0x00e6a8b4, 0x00f470}, /* U+6A34 [2000] */ - {0x00e6a8b5, 0x008fbf}, /* U+6A35 */ - {0x00e6a8b6, 0x009eee}, /* U+6A36 */ - {0x00e6a8b8, 0x009ef5}, /* U+6A38 */ - {0x00e6a8b9, 0x008ef7}, /* U+6A39 */ - {0x00e6a8ba, 0x008a92}, /* U+6A3A */ - {0x00e6a8bb, 0x00eba8}, /* U+6A3B [2000] */ - {0x00e6a8bd, 0x00924d}, /* U+6A3D */ - {0x00e6a8be, 0x00eba9}, /* U+6A3E [2000] */ - {0x00e6a8bf, 0x00f471}, /* U+6A3F [2000] */ - {0x00e6a984, 0x009eeb}, /* U+6A44 */ - {0x00e6a985, 0x00ebaa}, /* U+6A45 [2000] */ - {0x00e6a986, 0x00f472}, /* U+6A46 [2000] */ - {0x00e6a987, 0x009ef0}, /* U+6A47 */ - {0x00e6a988, 0x009ef4}, /* U+6A48 */ - {0x00e6a989, 0x00f473}, /* U+6A49 [2000] */ - {0x00e6a98b, 0x008bb4}, /* U+6A4B */ - {0x00e6a98e, 0x00f475}, /* U+6A4E [2000] */ - {0x00e6a990, 0x00ebab}, /* U+6A50 [2000] */ - {0x00e6a992, 0x00f476}, /* U+6A52 [2000] */ - {0x00e6a996, 0x00ebac}, /* U+6A56 [2000] */ - {0x00e6a998, 0x008b6b}, /* U+6A58 */ - {0x00e6a999, 0x009ef2}, /* U+6A59 */ - {0x00e6a99b, 0x00ebad}, /* U+6A5B [2000] */ - {0x00e6a99f, 0x008b40}, /* U+6A5F */ - {0x00e6a9a1, 0x0093c9}, /* U+6A61 */ - {0x00e6a9a2, 0x009ef1}, /* U+6A62 */ - {0x00e6a9a4, 0x00f477}, /* U+6A64 [2000] */ - {0x00e6a9a6, 0x009ef3}, /* U+6A66 */ - {0x00e6a9ab, 0x00ebae}, /* U+6A6B [2000] */ - {0x00e6a9b2, 0x009eed}, /* U+6A72 */ - {0x00e6a9b3, 0x00ebaf}, /* U+6A73 [2000] */ - {0x00e6a9b8, 0x009eef}, /* U+6A78 */ - {0x00e6a9ba, 0x00f474}, /* U+6A7A [2000] */ - {0x00e6a9be, 0x00f479}, /* U+6A7E [2000] */ - {0x00e6a9bf, 0x008a80}, /* U+6A7F */ - {0x00e6aa80, 0x009268}, /* U+6A80 */ - {0x00e6aa83, 0x00f47a}, /* U+6A83 [2000] */ - {0x00e6aa84, 0x009efa}, /* U+6A84 */ - {0x00e6aa89, 0x00ebb1}, /* U+6A89 [2000] */ - {0x00e6aa8b, 0x00f47b}, /* U+6A8B [2000] */ - {0x00e6aa8d, 0x009ef8}, /* U+6A8D */ - {0x00e6aa8e, 0x008ce7}, /* U+6A8E */ - {0x00e6aa90, 0x009ef7}, /* U+6A90 */ - {0x00e6aa91, 0x00f47d}, /* U+6A91 [2000] */ - {0x00e6aa94, 0x00ebb2}, /* U+6A94 [2000] */ - {0x00e6aa97, 0x009f40}, /* U+6A97 */ - {0x00e6aa9c, 0x009e77}, /* U+6A9C */ - {0x00e6aa9d, 0x00ebb3}, /* U+6A9D [2000] */ - {0x00e6aa9e, 0x00ebb4}, /* U+6A9E [2000] */ - {0x00e6aa9f, 0x00f47e}, /* U+6A9F [2000] */ - {0x00e6aaa0, 0x009ef9}, /* U+6AA0 */ - {0x00e6aaa1, 0x00f480}, /* U+6AA1 [2000] */ - {0x00e6aaa2, 0x009efb}, /* U+6AA2 */ - {0x00e6aaa3, 0x009efc}, /* U+6AA3 */ - {0x00e6aaa5, 0x00ebb5}, /* U+6AA5 [2000] */ - {0x00e6aaaa, 0x009f4b}, /* U+6AAA */ - {0x00e6aaab, 0x00f482}, /* U+6AAB [2000] */ - {0x00e6aaac, 0x009f47}, /* U+6AAC */ - {0x00e6aaae, 0x009e8d}, /* U+6AAE */ - {0x00e6aab3, 0x009f46}, /* U+6AB3 */ - {0x00e6aab8, 0x009f45}, /* U+6AB8 */ - {0x00e6aabb, 0x009f42}, /* U+6ABB */ - {0x00e6aabd, 0x00f483}, /* U+6ABD [2000] */ - {0x00e6ab81, 0x009ee8}, /* U+6AC1 */ - {0x00e6ab82, 0x009f44}, /* U+6AC2 */ - {0x00e6ab83, 0x009f43}, /* U+6AC3 */ - {0x00e6ab86, 0x00f484}, /* U+6AC6 [2000] */ - {0x00e6ab90, 0x00f486}, /* U+6AD0 [2000] */ - {0x00e6ab91, 0x009f49}, /* U+6AD1 */ - {0x00e6ab93, 0x009845}, /* U+6AD3 */ - {0x00e6ab94, 0x00f485}, /* U+6AD4 [2000] */ - {0x00e6ab9a, 0x009f4c}, /* U+6ADA */ - {0x00e6ab9b, 0x008bf9}, /* U+6ADB */ - {0x00e6ab9c, 0x00f487}, /* U+6ADC [2000] */ - {0x00e6ab9d, 0x00f488}, /* U+6ADD [2000] */ - {0x00e6ab9e, 0x009f48}, /* U+6ADE */ - {0x00e6ab9f, 0x009f4a}, /* U+6ADF */ - {0x00e6aba4, 0x00ebb6}, /* U+6AE4 [2000] */ - {0x00e6aba7, 0x00ebb7}, /* U+6AE7 [2000] */ - {0x00e6aba8, 0x0094a5}, /* U+6AE8 */ - {0x00e6abaa, 0x009f4d}, /* U+6AEA */ - {0x00e6abac, 0x00f48b}, /* U+6AEC [2000] */ - {0x00e6abb1, 0x00f48c}, /* U+6AF1 [2000] */ - {0x00e6abb2, 0x00f48d}, /* U+6AF2 [2000] */ - {0x00e6abb3, 0x00f48e}, /* U+6AF3 [2000] */ - {0x00e6abba, 0x009f51}, /* U+6AFA */ - {0x00e6abbb, 0x009f4e}, /* U+6AFB */ - {0x00e6abbd, 0x00f48f}, /* U+6AFD [2000] */ - {0x00e6ac84, 0x009793}, /* U+6B04 */ - {0x00e6ac85, 0x009f4f}, /* U+6B05 */ - {0x00e6ac8a, 0x009edc}, /* U+6B0A */ - {0x00e6ac8b, 0x00f491}, /* U+6B0B [2000] */ - {0x00e6ac8f, 0x00f492}, /* U+6B0F [2000] */ - {0x00e6ac90, 0x00f493}, /* U+6B10 [2000] */ - {0x00e6ac91, 0x00f494}, /* U+6B11 [2000] */ - {0x00e6ac92, 0x009f52}, /* U+6B12 */ - {0x00e6ac96, 0x009f53}, /* U+6B16 */ - {0x00e6ac97, 0x00f496}, /* U+6B17 [2000] */ - {0x00e6ac9b, 0x00ebba}, /* U+6B1B [2000] */ - {0x00e6ac9d, 0x008954}, /* U+6B1D */ - {0x00e6ac9e, 0x00ebbb}, /* U+6B1E [2000] */ - {0x00e6ac9f, 0x009f55}, /* U+6B1F */ - {0x00e6aca0, 0x008c87}, /* U+6B20 */ - {0x00e6aca1, 0x008e9f}, /* U+6B21 */ - {0x00e6aca3, 0x008bd3}, /* U+6B23 */ - {0x00e6aca7, 0x0089a2}, /* U+6B27 */ - {0x00e6acac, 0x00ebbc}, /* U+6B2C [2000] */ - {0x00e6acaf, 0x00f498}, /* U+6B2F [2000] */ - {0x00e6acb2, 0x00977e}, /* U+6B32 */ - {0x00e6acb5, 0x00ebbd}, /* U+6B35 [2000] */ - {0x00e6acb7, 0x009f57}, /* U+6B37 */ - {0x00e6acb8, 0x009f56}, /* U+6B38 */ - {0x00e6acb9, 0x009f59}, /* U+6B39 */ - {0x00e6acba, 0x008b5c}, /* U+6B3A */ - {0x00e6acbd, 0x008bd4}, /* U+6B3D */ - {0x00e6acbe, 0x008abc}, /* U+6B3E */ - {0x00e6ad83, 0x009f5c}, /* U+6B43 */ - {0x00e6ad86, 0x00ebbe}, /* U+6B46 [2000] */ - {0x00e6ad87, 0x009f5b}, /* U+6B47 */ - {0x00e6ad89, 0x009f5d}, /* U+6B49 */ - {0x00e6ad8a, 0x00f499}, /* U+6B4A [2000] */ - {0x00e6ad8c, 0x0089cc}, /* U+6B4C */ - {0x00e6ad8e, 0x009256}, /* U+6B4E */ - {0x00e6ad90, 0x009f5e}, /* U+6B50 */ - {0x00e6ad93, 0x008abd}, /* U+6B53 */ - {0x00e6ad94, 0x009f60}, /* U+6B54 */ - {0x00e6ad96, 0x00ebbf}, /* U+6B56 [2000] */ - {0x00e6ad98, 0x00f49a}, /* U+6B58 [2000] */ - {0x00e6ad99, 0x009f5f}, /* U+6B59 */ - {0x00e6ad9b, 0x009f61}, /* U+6B5B */ - {0x00e6ad9f, 0x009f62}, /* U+6B5F */ - {0x00e6ada0, 0x00ebc0}, /* U+6B60 [2000] */ - {0x00e6ada1, 0x009f63}, /* U+6B61 */ - {0x00e6ada2, 0x008e7e}, /* U+6B62 */ - {0x00e6ada3, 0x0090b3}, /* U+6B63 */ - {0x00e6ada4, 0x008d9f}, /* U+6B64 */ - {0x00e6ada5, 0x00ebc1}, /* U+6B65 [2000] */ - {0x00e6ada6, 0x009590}, /* U+6B66 */ - {0x00e6ada7, 0x00ebc2}, /* U+6B67 [2000] */ - {0x00e6ada9, 0x0095e0}, /* U+6B69 */ - {0x00e6adaa, 0x009863}, /* U+6B6A */ - {0x00e6adac, 0x00f49b}, /* U+6B6C [2000] */ - {0x00e6adaf, 0x008e95}, /* U+6B6F */ - {0x00e6adb3, 0x008dce}, /* U+6B73 */ - {0x00e6adb4, 0x0097f0}, /* U+6B74 */ - {0x00e6adb5, 0x00f49c}, /* U+6B75 [2000] */ - {0x00e6adb7, 0x00ebc3}, /* U+6B77 [2000] */ - {0x00e6adb8, 0x009f64}, /* U+6B78 */ - {0x00e6adb9, 0x009f65}, /* U+6B79 */ - {0x00e6adba, 0x00f49d}, /* U+6B7A [2000] */ - {0x00e6adbb, 0x008e80}, /* U+6B7B */ - {0x00e6adbf, 0x009f66}, /* U+6B7F */ - {0x00e6ae80, 0x009f67}, /* U+6B80 */ - {0x00e6ae81, 0x00f49e}, /* U+6B81 [2000] */ - {0x00e6ae82, 0x00ebc4}, /* U+6B82 [2000] */ - {0x00e6ae83, 0x009f69}, /* U+6B83 */ - {0x00e6ae84, 0x009f68}, /* U+6B84 */ - {0x00e6ae86, 0x009677}, /* U+6B86 */ - {0x00e6ae89, 0x008f7d}, /* U+6B89 */ - {0x00e6ae8a, 0x008eea}, /* U+6B8A */ - {0x00e6ae8b, 0x008e63}, /* U+6B8B */ - {0x00e6ae8d, 0x009f6a}, /* U+6B8D */ - {0x00e6ae95, 0x009f6c}, /* U+6B95 */ - {0x00e6ae96, 0x009042}, /* U+6B96 */ - {0x00e6ae98, 0x009f6b}, /* U+6B98 */ - {0x00e6ae9b, 0x00f49f}, /* U+6B9B [2000] */ - {0x00e6ae9e, 0x009f6d}, /* U+6B9E */ - {0x00e6aea4, 0x009f6e}, /* U+6BA4 */ - {0x00e6aea9, 0x00ebc5}, /* U+6BA9 [2000] */ - {0x00e6aeaa, 0x009f6f}, /* U+6BAA */ - {0x00e6aeab, 0x009f70}, /* U+6BAB */ - {0x00e6aead, 0x00ebc6}, /* U+6BAD [2000] */ - {0x00e6aeae, 0x00f4a0}, /* U+6BAE [2000] */ - {0x00e6aeaf, 0x009f71}, /* U+6BAF */ - {0x00e6aeb1, 0x009f73}, /* U+6BB1 */ - {0x00e6aeb2, 0x009f72}, /* U+6BB2 */ - {0x00e6aeb3, 0x009f74}, /* U+6BB3 */ - {0x00e6aeb4, 0x0089a3}, /* U+6BB4 */ - {0x00e6aeb5, 0x009269}, /* U+6BB5 */ - {0x00e6aeb7, 0x009f75}, /* U+6BB7 */ - {0x00e6aeba, 0x008e45}, /* U+6BBA */ - {0x00e6aebb, 0x008a6b}, /* U+6BBB */ - {0x00e6aebc, 0x009f76}, /* U+6BBC */ - {0x00e6aebd, 0x00f4a2}, /* U+6BBD [2000] */ - {0x00e6aebe, 0x00f4a3}, /* U+6BBE [2000] */ - {0x00e6aebf, 0x009361}, /* U+6BBF */ - {0x00e6af80, 0x009aca}, /* U+6BC0 */ - {0x00e6af85, 0x008b42}, /* U+6BC5 */ - {0x00e6af86, 0x009f77}, /* U+6BC6 */ - {0x00e6af87, 0x00f4a4}, /* U+6BC7 [2000] */ - {0x00e6af88, 0x00f4a5}, /* U+6BC8 [2000] */ - {0x00e6af89, 0x00f4a6}, /* U+6BC9 [2000] */ - {0x00e6af8b, 0x009f78}, /* U+6BCB */ - {0x00e6af8d, 0x0095ea}, /* U+6BCD */ - {0x00e6af8e, 0x009688}, /* U+6BCE */ - {0x00e6af8f, 0x00ebc8}, /* U+6BCF [2000] */ - {0x00e6af92, 0x0093c5}, /* U+6BD2 */ - {0x00e6af93, 0x009f79}, /* U+6BD3 */ - {0x00e6af94, 0x0094e4}, /* U+6BD4 */ - {0x00e6af96, 0x00ebc9}, /* U+6BD6 [2000] */ - {0x00e6af97, 0x00ebca}, /* U+6BD7 [2000] */ - {0x00e6af98, 0x0094f9}, /* U+6BD8 */ - {0x00e6af9a, 0x00f4a7}, /* U+6BDA [2000] */ - {0x00e6af9b, 0x0096d1}, /* U+6BDB */ - {0x00e6af9f, 0x009f7a}, /* U+6BDF */ - {0x00e6afa6, 0x00f4a8}, /* U+6BE6 [2000] */ - {0x00e6afa7, 0x00f4a9}, /* U+6BE7 [2000] */ - {0x00e6afab, 0x009f7c}, /* U+6BEB */ - {0x00e6afac, 0x009f7b}, /* U+6BEC */ - {0x00e6afae, 0x00f4aa}, /* U+6BEE [2000] */ - {0x00e6afaf, 0x009f7e}, /* U+6BEF */ - {0x00e6afb1, 0x00f4ab}, /* U+6BF1 [2000] */ - {0x00e6afb3, 0x009f7d}, /* U+6BF3 */ - {0x00e6afbf, 0x00ebcb}, /* U+6BFF [2000] */ - {0x00e6b082, 0x00f4ac}, /* U+6C02 [2000] */ - {0x00e6b085, 0x00ebcc}, /* U+6C05 [2000] */ - {0x00e6b088, 0x009f81}, /* U+6C08 */ - {0x00e6b08a, 0x00f4ad}, /* U+6C0A [2000] */ - {0x00e6b08e, 0x00f4ae}, /* U+6C0E [2000] */ - {0x00e6b08f, 0x008e81}, /* U+6C0F */ - {0x00e6b090, 0x00ebcd}, /* U+6C10 [2000] */ - {0x00e6b091, 0x0096af}, /* U+6C11 */ - {0x00e6b093, 0x009f82}, /* U+6C13 */ - {0x00e6b094, 0x009f83}, /* U+6C14 */ - {0x00e6b097, 0x008b43}, /* U+6C17 */ - {0x00e6b09b, 0x009f84}, /* U+6C1B */ - {0x00e6b0a3, 0x009f86}, /* U+6C23 */ - {0x00e6b0a4, 0x009f85}, /* U+6C24 */ - {0x00e6b0b3, 0x00ebce}, /* U+6C33 [2000] */ - {0x00e6b0b4, 0x009085}, /* U+6C34 */ - {0x00e6b0b5, 0x00f4af}, /* U+6C35 [2000] */ - {0x00e6b0b6, 0x00f4b0}, /* U+6C36 [2000] */ - {0x00e6b0b7, 0x009558}, /* U+6C37 */ - {0x00e6b0b8, 0x008969}, /* U+6C38 */ - {0x00e6b0ba, 0x00f4b1}, /* U+6C3A [2000] */ - {0x00e6b0be, 0x0094c3}, /* U+6C3E */ - {0x00e6b0bf, 0x00f4b3}, /* U+6C3F [2000] */ - {0x00e6b180, 0x0092f3}, /* U+6C40 */ - {0x00e6b181, 0x008f60}, /* U+6C41 */ - {0x00e6b182, 0x008b81}, /* U+6C42 */ - {0x00e6b18d, 0x00f4b4}, /* U+6C4D [2000] */ - {0x00e6b18e, 0x0094c4}, /* U+6C4E */ - {0x00e6b190, 0x008eac}, /* U+6C50 */ - {0x00e6b195, 0x009f88}, /* U+6C55 */ - {0x00e6b197, 0x008abe}, /* U+6C57 */ - {0x00e6b199, 0x00ebcf}, /* U+6C59 [2000] */ - {0x00e6b19a, 0x008998}, /* U+6C5A */ - {0x00e6b19b, 0x00f4b5}, /* U+6C5B [2000] */ - {0x00e6b19c, 0x00ebd0}, /* U+6C5C [2000] */ - {0x00e6b19d, 0x0093f0}, /* U+6C5D */ - {0x00e6b19e, 0x009f87}, /* U+6C5E */ - {0x00e6b19f, 0x008d5d}, /* U+6C5F */ - {0x00e6b1a0, 0x009272}, /* U+6C60 */ - {0x00e6b1a2, 0x009f89}, /* U+6C62 */ - {0x00e6b1a7, 0x00f4cd}, /* U+6C67 [2000] */ - {0x00e6b1a8, 0x009f91}, /* U+6C68 */ - {0x00e6b1aa, 0x009f8a}, /* U+6C6A */ - {0x00e6b1ad, 0x00f4b6}, /* U+6C6D [2000] */ - {0x00e6b1b0, 0x0091bf}, /* U+6C70 */ - {0x00e6b1b2, 0x008b82}, /* U+6C72 */ - {0x00e6b1b3, 0x009f92}, /* U+6C73 */ - {0x00e6b1b4, 0x00ebd2}, /* U+6C74 [2000] */ - {0x00e6b1b6, 0x00ebd3}, /* U+6C76 [2000] */ - {0x00e6b1ba, 0x008c88}, /* U+6C7A */ - {0x00e6b1bd, 0x008b44}, /* U+6C7D */ - {0x00e6b1be, 0x009f90}, /* U+6C7E */ - {0x00e6b281, 0x009f8e}, /* U+6C81 */ - {0x00e6b282, 0x009f8b}, /* U+6C82 */ - {0x00e6b283, 0x009780}, /* U+6C83 */ - {0x00e6b284, 0x00f4b7}, /* U+6C84 [2000] */ - {0x00e6b285, 0x00ebd4}, /* U+6C85 [2000] */ - {0x00e6b286, 0x00ebd5}, /* U+6C86 [2000] */ - {0x00e6b288, 0x0092be}, /* U+6C88 */ - {0x00e6b289, 0x00f4b8}, /* U+6C89 [2000] */ - {0x00e6b28c, 0x0093d7}, /* U+6C8C */ - {0x00e6b28d, 0x009f8c}, /* U+6C8D */ - {0x00e6b290, 0x009f94}, /* U+6C90 */ - {0x00e6b292, 0x009f93}, /* U+6C92 */ - {0x00e6b293, 0x008c42}, /* U+6C93 */ - {0x00e6b294, 0x00f4ba}, /* U+6C94 [2000] */ - {0x00e6b295, 0x00f4bb}, /* U+6C95 [2000] */ - {0x00e6b296, 0x0089ab}, /* U+6C96 */ - {0x00e6b297, 0x00f4bc}, /* U+6C97 [2000] */ - {0x00e6b298, 0x00ebd6}, /* U+6C98 [2000] */ - {0x00e6b299, 0x008db9}, /* U+6C99 */ - {0x00e6b29a, 0x009f8d}, /* U+6C9A */ - {0x00e6b29b, 0x009f8f}, /* U+6C9B */ - {0x00e6b29c, 0x00ebd7}, /* U+6C9C [2000] */ - {0x00e6b2a1, 0x009676}, /* U+6CA1 */ - {0x00e6b2a2, 0x0091f2}, /* U+6CA2 */ - {0x00e6b2aa, 0x00ebd1}, /* U+6CAA [2000] */ - {0x00e6b2ab, 0x009697}, /* U+6CAB */ - {0x00e6b2ad, 0x00f4bd}, /* U+6CAD [2000] */ - {0x00e6b2ae, 0x009f9c}, /* U+6CAE */ - {0x00e6b2b1, 0x009f9d}, /* U+6CB1 */ - {0x00e6b2b3, 0x0089cd}, /* U+6CB3 */ - {0x00e6b2b8, 0x0095a6}, /* U+6CB8 */ - {0x00e6b2b9, 0x0096fb}, /* U+6CB9 */ - {0x00e6b2ba, 0x009f9f}, /* U+6CBA */ - {0x00e6b2bb, 0x008ea1}, /* U+6CBB */ - {0x00e6b2bc, 0x008fc0}, /* U+6CBC */ - {0x00e6b2bd, 0x009f98}, /* U+6CBD */ - {0x00e6b2be, 0x009f9e}, /* U+6CBE */ - {0x00e6b2bf, 0x008988}, /* U+6CBF */ - {0x00e6b381, 0x008bb5}, /* U+6CC1 */ - {0x00e6b382, 0x00f4be}, /* U+6CC2 [2000] */ - {0x00e6b384, 0x009f95}, /* U+6CC4 */ - {0x00e6b385, 0x009f9a}, /* U+6CC5 */ - {0x00e6b386, 0x00ebd9}, /* U+6CC6 [2000] */ - {0x00e6b389, 0x0090f2}, /* U+6CC9 */ - {0x00e6b38a, 0x009491}, /* U+6CCA */ - {0x00e6b38c, 0x0094e5}, /* U+6CCC */ - {0x00e6b390, 0x00f4bf}, /* U+6CD0 [2000] */ - {0x00e6b393, 0x009f97}, /* U+6CD3 */ - {0x00e6b394, 0x00ebda}, /* U+6CD4 [2000] */ - {0x00e6b395, 0x009640}, /* U+6CD5 */ - {0x00e6b396, 0x00f4c1}, /* U+6CD6 [2000] */ - {0x00e6b397, 0x009f99}, /* U+6CD7 */ - {0x00e6b399, 0x009fa2}, /* U+6CD9 */ - {0x00e6b39a, 0x00f4c2}, /* U+6CDA [2000] */ - {0x00e6b39b, 0x009fa0}, /* U+6CDB */ - {0x00e6b39c, 0x00f4c3}, /* U+6CDC [2000] */ - {0x00e6b39d, 0x009f9b}, /* U+6CDD */ - {0x00e6b3a0, 0x00ebdb}, /* U+6CE0 [2000] */ - {0x00e6b3a1, 0x009641}, /* U+6CE1 */ - {0x00e6b3a2, 0x009467}, /* U+6CE2 */ - {0x00e6b3a3, 0x008b83}, /* U+6CE3 */ - {0x00e6b3a5, 0x009344}, /* U+6CE5 */ - {0x00e6b3a8, 0x00928d}, /* U+6CE8 */ - {0x00e6b3a9, 0x00f4c4}, /* U+6CE9 [2000] */ - {0x00e6b3aa, 0x009fa3}, /* U+6CEA */ - {0x00e6b3ab, 0x00ebdc}, /* U+6CEB [2000] */ - {0x00e6b3ac, 0x00f4c5}, /* U+6CEC [2000] */ - {0x00e6b3ad, 0x00f4c6}, /* U+6CED [2000] */ - {0x00e6b3ae, 0x00ebdd}, /* U+6CEE [2000] */ - {0x00e6b3af, 0x009fa1}, /* U+6CEF */ - {0x00e6b3b0, 0x0091d7}, /* U+6CF0 */ - {0x00e6b3b1, 0x009f96}, /* U+6CF1 */ - {0x00e6b3b3, 0x00896a}, /* U+6CF3 */ - {0x00e6b3bb, 0x00ebd8}, /* U+6CFB [2000] */ - {0x00e6b480, 0x00f4c8}, /* U+6D00 [2000] */ - {0x00e6b484, 0x00ebdf}, /* U+6D04 [2000] */ - {0x00e6b48a, 0x00f4c9}, /* U+6D0A [2000] */ - {0x00e6b48b, 0x00976d}, /* U+6D0B */ - {0x00e6b48c, 0x009fae}, /* U+6D0C */ - {0x00e6b48e, 0x00ebe0}, /* U+6D0E [2000] */ - {0x00e6b492, 0x009fad}, /* U+6D12 */ - {0x00e6b497, 0x0090f4}, /* U+6D17 */ - {0x00e6b499, 0x009faa}, /* U+6D19 */ - {0x00e6b49b, 0x00978c}, /* U+6D1B */ - {0x00e6b49e, 0x0093b4}, /* U+6D1E */ - {0x00e6b49f, 0x009fa4}, /* U+6D1F */ - {0x00e6b4a4, 0x00f4ca}, /* U+6D24 [2000] */ - {0x00e6b4a5, 0x0092c3}, /* U+6D25 */ - {0x00e6b4a6, 0x00f4cb}, /* U+6D26 [2000] */ - {0x00e6b4a7, 0x00f4cc}, /* U+6D27 [2000] */ - {0x00e6b4a9, 0x00896b}, /* U+6D29 */ - {0x00e6b4aa, 0x008d5e}, /* U+6D2A */ - {0x00e6b4ab, 0x009fa7}, /* U+6D2B */ - {0x00e6b4ae, 0x00ebe1}, /* U+6D2E [2000] */ - {0x00e6b4af, 0x00f4ce}, /* U+6D2F [2000] */ - {0x00e6b4b1, 0x00ebe2}, /* U+6D31 [2000] */ - {0x00e6b4b2, 0x008f46}, /* U+6D32 */ - {0x00e6b4b3, 0x009fac}, /* U+6D33 */ - {0x00e6b4b4, 0x00f4e3}, /* U+6D34 [2000] */ - {0x00e6b4b5, 0x009fab}, /* U+6D35 */ - {0x00e6b4b6, 0x009fa6}, /* U+6D36 */ - {0x00e6b4b8, 0x009fa9}, /* U+6D38 */ - {0x00e6b4b9, 0x00ebe3}, /* U+6D39 [2000] */ - {0x00e6b4bb, 0x008a88}, /* U+6D3B */ - {0x00e6b4bc, 0x00f4cf}, /* U+6D3C [2000] */ - {0x00e6b4bd, 0x009fa8}, /* U+6D3D */ - {0x00e6b4be, 0x009468}, /* U+6D3E */ - {0x00e6b4bf, 0x00ebe4}, /* U+6D3F [2000] */ - {0x00e6b581, 0x0097ac}, /* U+6D41 */ - {0x00e6b584, 0x008ff2}, /* U+6D44 */ - {0x00e6b585, 0x0090f3}, /* U+6D45 */ - {0x00e6b598, 0x00ebe5}, /* U+6D58 [2000] */ - {0x00e6b599, 0x009fb4}, /* U+6D59 */ - {0x00e6b59a, 0x009fb2}, /* U+6D5A */ - {0x00e6b59b, 0x00f4d0}, /* U+6D5B [2000] */ - {0x00e6b59c, 0x00956c}, /* U+6D5C */ - {0x00e6b59e, 0x00f4d1}, /* U+6D5E [2000] */ - {0x00e6b5a0, 0x00f4d2}, /* U+6D60 [2000] */ - {0x00e6b5a3, 0x009faf}, /* U+6D63 */ - {0x00e6b5a4, 0x009fb1}, /* U+6D64 */ - {0x00e6b5a5, 0x00ebe6}, /* U+6D65 [2000] */ - {0x00e6b5a6, 0x008959}, /* U+6D66 */ - {0x00e6b5a9, 0x008d5f}, /* U+6D69 */ - {0x00e6b5aa, 0x009851}, /* U+6D6A */ - {0x00e6b5ac, 0x008a5c}, /* U+6D6C */ - {0x00e6b5ae, 0x009582}, /* U+6D6E */ - {0x00e6b5b0, 0x00f4d3}, /* U+6D70 [2000] */ - {0x00e6b5b4, 0x009781}, /* U+6D74 */ - {0x00e6b5b7, 0x008a43}, /* U+6D77 */ - {0x00e6b5b8, 0x00905a}, /* U+6D78 */ - {0x00e6b5b9, 0x009fb3}, /* U+6D79 */ - {0x00e6b680, 0x00f4d4}, /* U+6D80 [2000] */ - {0x00e6b681, 0x00f4d5}, /* U+6D81 [2000] */ - {0x00e6b682, 0x00ebe8}, /* U+6D82 [2000] */ - {0x00e6b685, 0x009fb8}, /* U+6D85 */ - {0x00e6b687, 0x00ebe9}, /* U+6D87 [2000] */ - {0x00e6b688, 0x008fc1}, /* U+6D88 */ - {0x00e6b689, 0x00ebea}, /* U+6D89 [2000] */ - {0x00e6b68a, 0x00f4d6}, /* U+6D8A [2000] */ - {0x00e6b68c, 0x00974f}, /* U+6D8C */ - {0x00e6b68d, 0x00f4d7}, /* U+6D8D [2000] */ - {0x00e6b68e, 0x009fb5}, /* U+6D8E */ - {0x00e6b691, 0x00f4d8}, /* U+6D91 [2000] */ - {0x00e6b693, 0x009fb0}, /* U+6D93 */ - {0x00e6b694, 0x00ebeb}, /* U+6D94 [2000] */ - {0x00e6b695, 0x009fb6}, /* U+6D95 */ - {0x00e6b698, 0x00f4d9}, /* U+6D98 [2000] */ - {0x00e6b699, 0x0097dc}, /* U+6D99 */ - {0x00e6b69b, 0x009393}, /* U+6D9B */ - {0x00e6b69c, 0x0093c0}, /* U+6D9C */ - {0x00e6b6aa, 0x00ebec}, /* U+6DAA [2000] */ - {0x00e6b6ab, 0x00f4df}, /* U+6DAB [2000] */ - {0x00e6b6ac, 0x00ebed}, /* U+6DAC [2000] */ - {0x00e6b6ae, 0x00f4e0}, /* U+6DAE [2000] */ - {0x00e6b6af, 0x008a55}, /* U+6DAF */ - {0x00e6b6b2, 0x008974}, /* U+6DB2 */ - {0x00e6b6b4, 0x00f4e1}, /* U+6DB4 [2000] */ - {0x00e6b6b5, 0x009fbc}, /* U+6DB5 */ - {0x00e6b6b8, 0x009fbf}, /* U+6DB8 */ - {0x00e6b6bc, 0x0097c1}, /* U+6DBC */ - {0x00e6b6bf, 0x00ebee}, /* U+6DBF [2000] */ - {0x00e6b780, 0x009784}, /* U+6DC0 */ - {0x00e6b782, 0x00f4e2}, /* U+6DC2 [2000] */ - {0x00e6b784, 0x00ebef}, /* U+6DC4 [2000] */ - {0x00e6b785, 0x009fc6}, /* U+6DC5 */ - {0x00e6b786, 0x009fc0}, /* U+6DC6 */ - {0x00e6b787, 0x009fbd}, /* U+6DC7 */ - {0x00e6b788, 0x00f4e4}, /* U+6DC8 [2000] */ - {0x00e6b78b, 0x0097d2}, /* U+6DCB */ - {0x00e6b78c, 0x009fc3}, /* U+6DCC */ - {0x00e6b78e, 0x00f4e5}, /* U+6DCE [2000] */ - {0x00e6b78f, 0x00f4e6}, /* U+6DCF [2000] */ - {0x00e6b790, 0x00f4e7}, /* U+6DD0 [2000] */ - {0x00e6b791, 0x008f69}, /* U+6DD1 */ - {0x00e6b792, 0x009fc5}, /* U+6DD2 */ - {0x00e6b795, 0x009fca}, /* U+6DD5 */ - {0x00e6b796, 0x00ebf0}, /* U+6DD6 [2000] */ - {0x00e6b798, 0x009391}, /* U+6DD8 */ - {0x00e6b799, 0x009fc8}, /* U+6DD9 */ - {0x00e6b79a, 0x00ebf1}, /* U+6DDA [2000] */ - {0x00e6b79b, 0x00ebf2}, /* U+6DDB [2000] */ - {0x00e6b79d, 0x00ebf3}, /* U+6DDD [2000] */ - {0x00e6b79e, 0x009fc2}, /* U+6DDE */ - {0x00e6b79f, 0x00f4e8}, /* U+6DDF [2000] */ - {0x00e6b7a1, 0x009257}, /* U+6DE1 */ - {0x00e6b7a4, 0x009fc9}, /* U+6DE4 */ - {0x00e6b7a6, 0x009fbe}, /* U+6DE6 */ - {0x00e6b7a8, 0x009fc4}, /* U+6DE8 */ - {0x00e6b7a9, 0x00f4e9}, /* U+6DE9 [2000] */ - {0x00e6b7aa, 0x009fcb}, /* U+6DEA */ - {0x00e6b7ab, 0x0088fa}, /* U+6DEB */ - {0x00e6b7ac, 0x009fc1}, /* U+6DEC */ - {0x00e6b7ae, 0x009fcc}, /* U+6DEE */ - {0x00e6b7b1, 0x00905b}, /* U+6DF1 */ - {0x00e6b7b3, 0x008f7e}, /* U+6DF3 */ - {0x00e6b7b5, 0x0095a3}, /* U+6DF5 */ - {0x00e6b7b6, 0x00f4ea}, /* U+6DF6 [2000] */ - {0x00e6b7b7, 0x008dac}, /* U+6DF7 */ - {0x00e6b7b9, 0x009fb9}, /* U+6DF9 */ - {0x00e6b7ba, 0x009fc7}, /* U+6DFA */ - {0x00e6b7bb, 0x009359}, /* U+6DFB */ - {0x00e6b7bc, 0x00ebf4}, /* U+6DFC [2000] */ - {0x00e6b885, 0x0090b4}, /* U+6E05 */ - {0x00e6b887, 0x008a89}, /* U+6E07 */ - {0x00e6b888, 0x008dcf}, /* U+6E08 */ - {0x00e6b889, 0x008fc2}, /* U+6E09 */ - {0x00e6b88a, 0x009fbb}, /* U+6E0A */ - {0x00e6b88b, 0x008f61}, /* U+6E0B */ - {0x00e6b893, 0x008c6b}, /* U+6E13 */ - {0x00e6b895, 0x009fba}, /* U+6E15 */ - {0x00e6b897, 0x00f4db}, /* U+6E17 [2000] */ - {0x00e6b899, 0x009fd0}, /* U+6E19 */ - {0x00e6b89a, 0x008f8d}, /* U+6E1A */ - {0x00e6b89b, 0x008cb8}, /* U+6E1B */ - {0x00e6b89d, 0x009fdf}, /* U+6E1D */ - {0x00e6b89e, 0x00f4ec}, /* U+6E1E [2000] */ - {0x00e6b89f, 0x009fd9}, /* U+6E1F */ - {0x00e6b8a0, 0x008b94}, /* U+6E20 */ - {0x00e6b8a1, 0x00936e}, /* U+6E21 */ - {0x00e6b8a2, 0x00f4ed}, /* U+6E22 [2000] */ - {0x00e6b8a3, 0x009fd4}, /* U+6E23 */ - {0x00e6b8a4, 0x009fdd}, /* U+6E24 */ - {0x00e6b8a5, 0x0088ad}, /* U+6E25 */ - {0x00e6b8a6, 0x008951}, /* U+6E26 */ - {0x00e6b8a7, 0x00f4ee}, /* U+6E27 [2000] */ - {0x00e6b8a9, 0x0089b7}, /* U+6E29 */ - {0x00e6b8ab, 0x009fd6}, /* U+6E2B */ - {0x00e6b8ac, 0x0091aa}, /* U+6E2C */ - {0x00e6b8ad, 0x009fcd}, /* U+6E2D */ - {0x00e6b8ae, 0x009fcf}, /* U+6E2E */ - {0x00e6b8af, 0x008d60}, /* U+6E2F */ - {0x00e6b8b2, 0x00f4f0}, /* U+6E32 [2000] */ - {0x00e6b8b4, 0x00ebf6}, /* U+6E34 [2000] */ - {0x00e6b8b6, 0x00f4eb}, /* U+6E36 [2000] */ - {0x00e6b8b8, 0x009fe0}, /* U+6E38 */ - {0x00e6b8ba, 0x009fdb}, /* U+6E3A */ - {0x00e6b8bc, 0x00f4f1}, /* U+6E3C [2000] */ - {0x00e6b8be, 0x009fd3}, /* U+6E3E */ - {0x00e6b983, 0x009fda}, /* U+6E43 */ - {0x00e6b984, 0x00ebf7}, /* U+6E44 [2000] */ - {0x00e6b988, 0x00f4f2}, /* U+6E48 [2000] */ - {0x00e6b989, 0x00f4f3}, /* U+6E49 [2000] */ - {0x00e6b98a, 0x0096a9}, /* U+6E4A */ - {0x00e6b98b, 0x00f4f4}, /* U+6E4B [2000] */ - {0x00e6b98c, 0x00f4f5}, /* U+6E4C [2000] */ - {0x00e6b98d, 0x009fd8}, /* U+6E4D */ - {0x00e6b98e, 0x009fdc}, /* U+6E4E */ - {0x00e6b98f, 0x00f4f6}, /* U+6E4F [2000] */ - {0x00e6b991, 0x00f4f7}, /* U+6E51 [2000] */ - {0x00e6b993, 0x00f4f8}, /* U+6E53 [2000] */ - {0x00e6b994, 0x00f4f9}, /* U+6E54 [2000] */ - {0x00e6b996, 0x008cce}, /* U+6E56 */ - {0x00e6b997, 0x00f4fa}, /* U+6E57 [2000] */ - {0x00e6b998, 0x008fc3}, /* U+6E58 */ - {0x00e6b99b, 0x009258}, /* U+6E5B */ - {0x00e6b99c, 0x00ebf8}, /* U+6E5C [2000] */ - {0x00e6b99e, 0x00ebf9}, /* U+6E5E [2000] */ - {0x00e6b99f, 0x009fd2}, /* U+6E5F */ - {0x00e6b9a3, 0x00f4fb}, /* U+6E63 [2000] */ - {0x00e6b9a7, 0x00974e}, /* U+6E67 */ - {0x00e6b9ab, 0x009fd5}, /* U+6E6B */ - {0x00e6b9ae, 0x009fce}, /* U+6E6E */ - {0x00e6b9af, 0x009392}, /* U+6E6F */ - {0x00e6b9b2, 0x009fd1}, /* U+6E72 */ - {0x00e6b9b6, 0x009fd7}, /* U+6E76 */ - {0x00e6b9be, 0x009870}, /* U+6E7E */ - {0x00e6b9bf, 0x008ebc}, /* U+6E7F */ - {0x00e6ba80, 0x00969e}, /* U+6E80 */ - {0x00e6ba82, 0x009fe1}, /* U+6E82 */ - {0x00e6ba8c, 0x0094ac}, /* U+6E8C */ - {0x00e6ba8f, 0x009fed}, /* U+6E8F */ - {0x00e6ba90, 0x008cb9}, /* U+6E90 */ - {0x00e6ba93, 0x00f540}, /* U+6E93 [2000] */ - {0x00e6ba96, 0x008f80}, /* U+6E96 */ - {0x00e6ba98, 0x009fe3}, /* U+6E98 */ - {0x00e6ba9c, 0x0097ad}, /* U+6E9C */ - {0x00e6ba9d, 0x008d61}, /* U+6E9D */ - {0x00e6ba9f, 0x009ff0}, /* U+6E9F */ - {0x00e6baa2, 0x0088ec}, /* U+6EA2 */ - {0x00e6baa5, 0x009fee}, /* U+6EA5 */ - {0x00e6baa7, 0x00f541}, /* U+6EA7 [2000] */ - {0x00e6baaa, 0x009fe2}, /* U+6EAA */ - {0x00e6baab, 0x00ebfa}, /* U+6EAB [2000] */ - {0x00e6baaf, 0x009fe8}, /* U+6EAF */ - {0x00e6bab1, 0x00ebfb}, /* U+6EB1 [2000] */ - {0x00e6bab2, 0x009fea}, /* U+6EB2 */ - {0x00e6bab4, 0x00f542}, /* U+6EB4 [2000] */ - {0x00e6bab6, 0x00976e}, /* U+6EB6 */ - {0x00e6bab7, 0x009fe5}, /* U+6EB7 */ - {0x00e6baba, 0x00934d}, /* U+6EBA */ - {0x00e6babd, 0x009fe7}, /* U+6EBD */ - {0x00e6babf, 0x00f543}, /* U+6EBF [2000] */ - {0x00e6bb81, 0x00ebfc}, /* U+6EC1 [2000] */ - {0x00e6bb82, 0x009fef}, /* U+6EC2 */ - {0x00e6bb83, 0x00f544}, /* U+6EC3 [2000] */ - {0x00e6bb84, 0x009fe9}, /* U+6EC4 */ - {0x00e6bb85, 0x0096c5}, /* U+6EC5 */ - {0x00e6bb87, 0x00ec40}, /* U+6EC7 [2000] */ - {0x00e6bb89, 0x009fe4}, /* U+6EC9 */ - {0x00e6bb8a, 0x00f545}, /* U+6ECA [2000] */ - {0x00e6bb8b, 0x008ea0}, /* U+6ECB */ - {0x00e6bb8c, 0x009ffc}, /* U+6ECC */ - {0x00e6bb8e, 0x00ec41}, /* U+6ECE [2000] */ - {0x00e6bb91, 0x008a8a}, /* U+6ED1 */ - {0x00e6bb93, 0x009fe6}, /* U+6ED3 */ - {0x00e6bb94, 0x009feb}, /* U+6ED4 */ - {0x00e6bb95, 0x009fec}, /* U+6ED5 */ - {0x00e6bb99, 0x00f546}, /* U+6ED9 [2000] */ - {0x00e6bb9d, 0x0091ea}, /* U+6EDD */ - {0x00e6bb9e, 0x0091d8}, /* U+6EDE */ - {0x00e6bbab, 0x00f548}, /* U+6EEB [2000] */ - {0x00e6bbac, 0x009ff4}, /* U+6EEC */ - {0x00e6bbaf, 0x009ffa}, /* U+6EEF */ - {0x00e6bbb2, 0x009ff8}, /* U+6EF2 */ - {0x00e6bbb4, 0x009348}, /* U+6EF4 */ - {0x00e6bbb7, 0x00e042}, /* U+6EF7 */ - {0x00e6bbb8, 0x009ff5}, /* U+6EF8 */ - {0x00e6bbb9, 0x00f549}, /* U+6EF9 [2000] */ - {0x00e6bbbb, 0x00f54a}, /* U+6EFB [2000] */ - {0x00e6bbbe, 0x009ff6}, /* U+6EFE */ - {0x00e6bbbf, 0x009fde}, /* U+6EFF */ - {0x00e6bc81, 0x008b99}, /* U+6F01 */ - {0x00e6bc82, 0x009559}, /* U+6F02 */ - {0x00e6bc86, 0x008ebd}, /* U+6F06 */ - {0x00e6bc89, 0x008d97}, /* U+6F09 */ - {0x00e6bc8a, 0x00f54b}, /* U+6F0A [2000] */ - {0x00e6bc8c, 0x00f54c}, /* U+6F0C [2000] */ - {0x00e6bc8f, 0x009852}, /* U+6F0F */ - {0x00e6bc90, 0x00ec42}, /* U+6F10 [2000] */ - {0x00e6bc91, 0x009ff2}, /* U+6F11 */ - {0x00e6bc93, 0x00e041}, /* U+6F13 */ - {0x00e6bc94, 0x008989}, /* U+6F14 */ - {0x00e6bc95, 0x009186}, /* U+6F15 */ - {0x00e6bc98, 0x00f54d}, /* U+6F18 [2000] */ - {0x00e6bc9a, 0x00ec43}, /* U+6F1A [2000] */ - {0x00e6bca0, 0x009499}, /* U+6F20 */ - {0x00e6bca2, 0x008abf}, /* U+6F22 */ - {0x00e6bca3, 0x0097f8}, /* U+6F23 */ - {0x00e6bca5, 0x00f54e}, /* U+6F25 [2000] */ - {0x00e6bcaa, 0x00ec45}, /* U+6F2A [2000] */ - {0x00e6bcab, 0x00969f}, /* U+6F2B */ - {0x00e6bcac, 0x0092d0}, /* U+6F2C */ - {0x00e6bcaf, 0x00ec46}, /* U+6F2F [2000] */ - {0x00e6bcb1, 0x009ff9}, /* U+6F31 */ - {0x00e6bcb2, 0x009ffb}, /* U+6F32 */ - {0x00e6bcb3, 0x00ec47}, /* U+6F33 [2000] */ - {0x00e6bcb5, 0x00f547}, /* U+6F35 [2000] */ - {0x00e6bcb6, 0x00f54f}, /* U+6F36 [2000] */ - {0x00e6bcb8, 0x009151}, /* U+6F38 */ - {0x00e6bcbc, 0x00f550}, /* U+6F3C [2000] */ - {0x00e6bcbe, 0x00e040}, /* U+6F3E */ - {0x00e6bcbf, 0x009ff7}, /* U+6F3F */ - {0x00e6bd81, 0x009ff1}, /* U+6F41 */ - {0x00e6bd85, 0x008ac1}, /* U+6F45 */ - {0x00e6bd91, 0x00ec48}, /* U+6F51 [2000] */ - {0x00e6bd92, 0x00f552}, /* U+6F52 [2000] */ - {0x00e6bd94, 0x008c89}, /* U+6F54 */ - {0x00e6bd97, 0x00f553}, /* U+6F57 [2000] */ - {0x00e6bd98, 0x00e04e}, /* U+6F58 */ - {0x00e6bd99, 0x00ec49}, /* U+6F59 [2000] */ - {0x00e6bd9a, 0x00f554}, /* U+6F5A [2000] */ - {0x00e6bd9b, 0x00e049}, /* U+6F5B */ - {0x00e6bd9c, 0x0090f6}, /* U+6F5C */ - {0x00e6bd9e, 0x00ec4a}, /* U+6F5E [2000] */ - {0x00e6bd9f, 0x008a83}, /* U+6F5F */ - {0x00e6bda0, 0x00f555}, /* U+6F60 [2000] */ - {0x00e6bda1, 0x00ec4b}, /* U+6F61 [2000] */ - {0x00e6bda2, 0x00ec4c}, /* U+6F62 [2000] */ - {0x00e6bda4, 0x008f81}, /* U+6F64 */ - {0x00e6bda6, 0x00e052}, /* U+6F66 */ - {0x00e6bda8, 0x00f556}, /* U+6F68 [2000] */ - {0x00e6bdad, 0x00e04b}, /* U+6F6D */ - {0x00e6bdae, 0x0092aa}, /* U+6F6E */ - {0x00e6bdaf, 0x00e048}, /* U+6F6F */ - {0x00e6bdb0, 0x0092d7}, /* U+6F70 */ - {0x00e6bdb4, 0x00e06b}, /* U+6F74 */ - {0x00e6bdb8, 0x00e045}, /* U+6F78 */ - {0x00e6bdba, 0x00e044}, /* U+6F7A */ - {0x00e6bdbc, 0x00e04d}, /* U+6F7C */ - {0x00e6bdbd, 0x00f558}, /* U+6F7D [2000] */ - {0x00e6bdbe, 0x00ec4d}, /* U+6F7E [2000] */ - {0x00e6be80, 0x00e047}, /* U+6F80 */ - {0x00e6be81, 0x00e046}, /* U+6F81 */ - {0x00e6be82, 0x00e04c}, /* U+6F82 */ - {0x00e6be84, 0x00909f}, /* U+6F84 */ - {0x00e6be86, 0x00e043}, /* U+6F86 */ - {0x00e6be88, 0x00ec4e}, /* U+6F88 [2000] */ - {0x00e6be8c, 0x00ec4f}, /* U+6F8C [2000] */ - {0x00e6be8d, 0x00ec50}, /* U+6F8D [2000] */ - {0x00e6be8e, 0x00e04f}, /* U+6F8E */ - {0x00e6be90, 0x00f559}, /* U+6F90 [2000] */ - {0x00e6be91, 0x00e050}, /* U+6F91 */ - {0x00e6be94, 0x00ec51}, /* U+6F94 [2000] */ - {0x00e6be96, 0x00f55a}, /* U+6F96 [2000] */ - {0x00e6be97, 0x008ac0}, /* U+6F97 */ - {0x00e6be98, 0x00f557}, /* U+6F98 [2000] */ - {0x00e6be9f, 0x00f55c}, /* U+6F9F [2000] */ - {0x00e6bea0, 0x00ec52}, /* U+6FA0 [2000] */ - {0x00e6bea1, 0x00e055}, /* U+6FA1 */ - {0x00e6bea3, 0x00e054}, /* U+6FA3 */ - {0x00e6bea4, 0x00e056}, /* U+6FA4 */ - {0x00e6bea5, 0x00f55d}, /* U+6FA5 [2000] */ - {0x00e6bea7, 0x00ec53}, /* U+6FA7 [2000] */ - {0x00e6beaa, 0x00e059}, /* U+6FAA */ - {0x00e6beaf, 0x00f55e}, /* U+6FAF [2000] */ - {0x00e6beb1, 0x009362}, /* U+6FB1 */ - {0x00e6beb3, 0x00e053}, /* U+6FB3 */ - {0x00e6beb5, 0x00f560}, /* U+6FB5 [2000] */ - {0x00e6beb6, 0x00ec54}, /* U+6FB6 [2000] */ - {0x00e6beb9, 0x00e057}, /* U+6FB9 */ - {0x00e6bebc, 0x00ec55}, /* U+6FBC [2000] */ - {0x00e6bebe, 0x00f55b}, /* U+6FBE [2000] */ - {0x00e6bf80, 0x008c83}, /* U+6FC0 */ - {0x00e6bf81, 0x0091f7}, /* U+6FC1 */ - {0x00e6bf82, 0x00e051}, /* U+6FC2 */ - {0x00e6bf83, 0x00945a}, /* U+6FC3 */ - {0x00e6bf86, 0x00e058}, /* U+6FC6 */ - {0x00e6bf87, 0x00ec56}, /* U+6FC7 [2000] */ - {0x00e6bf88, 0x00f561}, /* U+6FC8 [2000] */ - {0x00e6bf89, 0x00f562}, /* U+6FC9 [2000] */ - {0x00e6bf8a, 0x00ec57}, /* U+6FCA [2000] */ - {0x00e6bf94, 0x00e05d}, /* U+6FD4 */ - {0x00e6bf95, 0x00e05b}, /* U+6FD5 */ - {0x00e6bf98, 0x00e05e}, /* U+6FD8 */ - {0x00e6bf9a, 0x00f563}, /* U+6FDA [2000] */ - {0x00e6bf9b, 0x00e061}, /* U+6FDB */ - {0x00e6bf9e, 0x00f564}, /* U+6FDE [2000] */ - {0x00e6bf9f, 0x00e05a}, /* U+6FDF */ - {0x00e6bfa0, 0x008d8a}, /* U+6FE0 */ - {0x00e6bfa1, 0x009447}, /* U+6FE1 */ - {0x00e6bfa4, 0x009fb7}, /* U+6FE4 */ - {0x00e6bfa9, 0x00f565}, /* U+6FE9 [2000] */ - {0x00e6bfab, 0x009794}, /* U+6FEB */ - {0x00e6bfac, 0x00e05c}, /* U+6FEC */ - {0x00e6bfae, 0x00e060}, /* U+6FEE */ - {0x00e6bfaf, 0x0091f3}, /* U+6FEF */ - {0x00e6bfb0, 0x00ec59}, /* U+6FF0 [2000] */ - {0x00e6bfb1, 0x00e05f}, /* U+6FF1 */ - {0x00e6bfb3, 0x00e04a}, /* U+6FF3 */ - {0x00e6bfb5, 0x00ec5a}, /* U+6FF5 [2000] */ - {0x00e6bfb6, 0x00e889}, /* U+6FF6 */ - {0x00e6bfb9, 0x00ec58}, /* U+6FF9 [2000] */ - {0x00e6bfba, 0x00e064}, /* U+6FFA */ - {0x00e6bfbc, 0x00f567}, /* U+6FFC [2000] */ - {0x00e6bfbe, 0x00e068}, /* U+6FFE */ - {0x00e78080, 0x00f568}, /* U+7000 [2000] */ - {0x00e78081, 0x00e066}, /* U+7001 */ - {0x00e78085, 0x00ec5b}, /* U+7005 [2000] */ - {0x00e78086, 0x00ec5c}, /* U+7006 [2000] */ - {0x00e78087, 0x00f569}, /* U+7007 [2000] */ - {0x00e78089, 0x00e062}, /* U+7009 */ - {0x00e7808a, 0x00f56a}, /* U+700A [2000] */ - {0x00e7808b, 0x00e063}, /* U+700B */ - {0x00e7808f, 0x00e067}, /* U+700F */ - {0x00e78091, 0x00e065}, /* U+7011 */ - {0x00e78095, 0x00956d}, /* U+7015 */ - {0x00e78098, 0x00e06d}, /* U+7018 */ - {0x00e7809a, 0x00e06a}, /* U+701A */ - {0x00e7809b, 0x00e069}, /* U+701B */ - {0x00e7809d, 0x00e06c}, /* U+701D */ - {0x00e7809e, 0x0093d2}, /* U+701E */ - {0x00e7809f, 0x00e06e}, /* U+701F */ - {0x00e780a3, 0x00f56b}, /* U+7023 [2000] */ - {0x00e780a6, 0x009295}, /* U+7026 */ - {0x00e780a7, 0x0091eb}, /* U+7027 */ - {0x00e780a8, 0x00ec5d}, /* U+7028 [2000] */ - {0x00e780ac, 0x0090a3}, /* U+702C */ - {0x00e780b0, 0x00e06f}, /* U+7030 */ - {0x00e780b2, 0x00e071}, /* U+7032 */ - {0x00e780b9, 0x00f56d}, /* U+7039 [2000] */ - {0x00e780ba, 0x00f56e}, /* U+703A [2000] */ - {0x00e780bc, 0x00f56f}, /* U+703C [2000] */ - {0x00e780be, 0x00e070}, /* U+703E */ - {0x00e78183, 0x00f570}, /* U+7043 [2000] */ - {0x00e78187, 0x00f571}, /* U+7047 [2000] */ - {0x00e7818a, 0x00ec5e}, /* U+704A [2000] */ - {0x00e7818b, 0x00f572}, /* U+704B [2000] */ - {0x00e7818c, 0x009ff3}, /* U+704C */ - {0x00e7818e, 0x00ec61}, /* U+704E [2000] */ - {0x00e78191, 0x00e072}, /* U+7051 */ - {0x00e78194, 0x00f574}, /* U+7054 [2000] */ - {0x00e78198, 0x0093e5}, /* U+7058 */ - {0x00e7819d, 0x00ec5f}, /* U+705D [2000] */ - {0x00e7819e, 0x00ec60}, /* U+705E [2000] */ - {0x00e781a3, 0x00e073}, /* U+7063 */ - {0x00e781a4, 0x00ec62}, /* U+7064 [2000] */ - {0x00e781a5, 0x00f575}, /* U+7065 [2000] */ - {0x00e781a9, 0x00f576}, /* U+7069 [2000] */ - {0x00e781ab, 0x0089ce}, /* U+706B */ - {0x00e781ac, 0x00f577}, /* U+706C [2000] */ - {0x00e781ae, 0x00f578}, /* U+706E [2000] */ - {0x00e781af, 0x009394}, /* U+706F */ - {0x00e781b0, 0x008a44}, /* U+7070 */ - {0x00e781b5, 0x00ec63}, /* U+7075 [2000] */ - {0x00e781b6, 0x00f579}, /* U+7076 [2000] */ - {0x00e781b8, 0x008b84}, /* U+7078 */ - {0x00e781bc, 0x008edc}, /* U+707C */ - {0x00e781bd, 0x008dd0}, /* U+707D */ - {0x00e781be, 0x00f57a}, /* U+707E [2000] */ - {0x00e78281, 0x00f57b}, /* U+7081 [2000] */ - {0x00e78285, 0x00ec64}, /* U+7085 [2000] */ - {0x00e78286, 0x00f57c}, /* U+7086 [2000] */ - {0x00e78289, 0x009846}, /* U+7089 */ - {0x00e7828a, 0x009086}, /* U+708A */ - {0x00e7828e, 0x00898a}, /* U+708E */ - {0x00e78292, 0x00e075}, /* U+7092 */ - {0x00e78295, 0x00f57d}, /* U+7095 [2000] */ - {0x00e78297, 0x00f57e}, /* U+7097 [2000] */ - {0x00e78299, 0x00e074}, /* U+7099 */ - {0x00e7829f, 0x00f582}, /* U+709F [2000] */ - {0x00e782a4, 0x00ec65}, /* U+70A4 [2000] */ - {0x00e782ab, 0x00ec66}, /* U+70AB [2000] */ - {0x00e782ac, 0x00e078}, /* U+70AC */ - {0x00e782ad, 0x009259}, /* U+70AD */ - {0x00e782ae, 0x00e07b}, /* U+70AE */ - {0x00e782af, 0x00e076}, /* U+70AF */ - {0x00e782b1, 0x00f583}, /* U+70B1 [2000] */ - {0x00e782b3, 0x00e07a}, /* U+70B3 */ - {0x00e782b7, 0x00ec67}, /* U+70B7 [2000] */ - {0x00e782b8, 0x00e079}, /* U+70B8 */ - {0x00e782b9, 0x00935f}, /* U+70B9 */ - {0x00e782ba, 0x0088d7}, /* U+70BA */ - {0x00e782bb, 0x00f580}, /* U+70BB [2000] */ - {0x00e78388, 0x0097f3}, /* U+70C8 */ - {0x00e7838a, 0x00f586}, /* U+70CA [2000] */ - {0x00e7838b, 0x00e07d}, /* U+70CB */ - {0x00e7838f, 0x008947}, /* U+70CF */ - {0x00e78391, 0x00f587}, /* U+70D1 [2000] */ - {0x00e78393, 0x00f588}, /* U+70D3 [2000] */ - {0x00e78394, 0x00ec68}, /* U+70D4 [2000] */ - {0x00e78398, 0x00ec69}, /* U+70D8 [2000] */ - {0x00e78399, 0x00e080}, /* U+70D9 */ - {0x00e7839c, 0x00f589}, /* U+70DC [2000] */ - {0x00e7839d, 0x00e07e}, /* U+70DD */ - {0x00e7839f, 0x00e07c}, /* U+70DF */ - {0x00e783a4, 0x00ec6a}, /* U+70E4 [2000] */ - {0x00e783ac, 0x00f585}, /* U+70EC [2000] */ - {0x00e783b1, 0x00e077}, /* U+70F1 */ - {0x00e783b9, 0x009642}, /* U+70F9 */ - {0x00e783bd, 0x00e082}, /* U+70FD */ - {0x00e78483, 0x00f58a}, /* U+7103 [2000] */ - {0x00e78484, 0x00f58b}, /* U+7104 [2000] */ - {0x00e78486, 0x00f58c}, /* U+7106 [2000] */ - {0x00e78487, 0x00f58d}, /* U+7107 [2000] */ - {0x00e78488, 0x00f58e}, /* U+7108 [2000] */ - {0x00e78489, 0x00e081}, /* U+7109 */ - {0x00e7848c, 0x00f58f}, /* U+710C [2000] */ - {0x00e7848f, 0x00ec6b}, /* U+710F [2000] */ - {0x00e78494, 0x00898b}, /* U+7114 */ - {0x00e78499, 0x00e084}, /* U+7119 */ - {0x00e7849a, 0x0095b0}, /* U+711A */ - {0x00e7849c, 0x00e083}, /* U+711C */ - {0x00e7849e, 0x00ec6d}, /* U+711E [2000] */ - {0x00e784a0, 0x00ec6e}, /* U+7120 [2000] */ - {0x00e784a1, 0x0096b3}, /* U+7121 */ - {0x00e784a6, 0x008fc5}, /* U+7126 */ - {0x00e784ab, 0x00ec6c}, /* U+712B [2000] */ - {0x00e784ae, 0x00ec6f}, /* U+712E [2000] */ - {0x00e784af, 0x00f591}, /* U+712F [2000] */ - {0x00e784b0, 0x00ec70}, /* U+7130 [2000] */ - {0x00e784b1, 0x00f592}, /* U+7131 [2000] */ - {0x00e784b6, 0x009152}, /* U+7136 */ - {0x00e784bc, 0x008fc4}, /* U+713C */ - {0x00e78586, 0x00ec71}, /* U+7146 [2000] */ - {0x00e78587, 0x00ec72}, /* U+7147 [2000] */ - {0x00e78589, 0x0097f9}, /* U+7149 */ - {0x00e7858a, 0x00f594}, /* U+714A [2000] */ - {0x00e7858c, 0x00e08a}, /* U+714C */ - {0x00e7858e, 0x0090f7}, /* U+714E */ - {0x00e78590, 0x00f593}, /* U+7150 [2000] */ - {0x00e78591, 0x00ec73}, /* U+7151 [2000] */ - {0x00e78592, 0x00ec75}, /* U+7152 [2000] */ - {0x00e78593, 0x00f595}, /* U+7153 [2000] */ - {0x00e78595, 0x00e086}, /* U+7155 */ - {0x00e78596, 0x00e08b}, /* U+7156 */ - {0x00e78599, 0x00898c}, /* U+7159 */ - {0x00e7859c, 0x00ec76}, /* U+715C [2000] */ - {0x00e7859e, 0x00f596}, /* U+715E [2000] */ - {0x00e785a0, 0x00ec77}, /* U+7160 [2000] */ - {0x00e785a2, 0x00e089}, /* U+7162 */ - {0x00e785a4, 0x009481}, /* U+7164 */ - {0x00e785a5, 0x00e085}, /* U+7165 */ - {0x00e785a6, 0x00e088}, /* U+7166 */ - {0x00e785a7, 0x008fc6}, /* U+7167 */ - {0x00e785a8, 0x00ec78}, /* U+7168 [2000] */ - {0x00e785a9, 0x0094cf}, /* U+7169 */ - {0x00e785ac, 0x00e08c}, /* U+716C */ - {0x00e785ae, 0x008ecf}, /* U+716E */ - {0x00e785bd, 0x0090f8}, /* U+717D */ - {0x00e78680, 0x00f599}, /* U+7180 [2000] */ - {0x00e78684, 0x00e08f}, /* U+7184 */ - {0x00e78685, 0x00ec7a}, /* U+7185 [2000] */ - {0x00e78687, 0x00ec7b}, /* U+7187 [2000] */ - {0x00e78688, 0x00e087}, /* U+7188 */ - {0x00e7868a, 0x008c46}, /* U+718A */ - {0x00e7868f, 0x00e08d}, /* U+718F */ - {0x00e78692, 0x00ec7c}, /* U+7192 [2000] */ - {0x00e78694, 0x00976f}, /* U+7194 */ - {0x00e78695, 0x00e090}, /* U+7195 */ - {0x00e78696, 0x00f598}, /* U+7196 [2000] */ - {0x00e78699, 0x00eaa4}, /* U+7199 [1990] */ - {0x00e7869b, 0x00f59a}, /* U+719B [2000] */ - {0x00e7869f, 0x008f6e}, /* U+719F */ - {0x00e786a0, 0x00f59b}, /* U+71A0 [2000] */ - {0x00e786a2, 0x00f59c}, /* U+71A2 [2000] */ - {0x00e786a8, 0x00e091}, /* U+71A8 */ - {0x00e786ac, 0x00e092}, /* U+71AC */ - {0x00e786ae, 0x00f59d}, /* U+71AE [2000] */ - {0x00e786af, 0x00f59e}, /* U+71AF [2000] */ - {0x00e786b1, 0x00944d}, /* U+71B1 */ - {0x00e786b3, 0x00f59f}, /* U+71B3 [2000] */ - {0x00e786b9, 0x00e094}, /* U+71B9 */ - {0x00e786ba, 0x00ec7e}, /* U+71BA [2000] */ - {0x00e786be, 0x00e095}, /* U+71BE */ - {0x00e78781, 0x00ec7d}, /* U+71C1 [2000] */ - {0x00e78783, 0x009452}, /* U+71C3 */ - {0x00e78784, 0x00ec80}, /* U+71C4 [2000] */ - {0x00e78788, 0x009395}, /* U+71C8 */ - {0x00e78789, 0x00e097}, /* U+71C9 */ - {0x00e7878b, 0x00f5a1}, /* U+71CB [2000] */ - {0x00e7878e, 0x00e099}, /* U+71CE */ - {0x00e78790, 0x0097d3}, /* U+71D0 */ - {0x00e78792, 0x00e096}, /* U+71D2 */ - {0x00e78793, 0x00f5a2}, /* U+71D3 [2000] */ - {0x00e78794, 0x00e098}, /* U+71D4 */ - {0x00e78795, 0x00898d}, /* U+71D5 */ - {0x00e78797, 0x00e093}, /* U+71D7 */ - {0x00e78799, 0x00f5a3}, /* U+71D9 [2000] */ - {0x00e7879c, 0x00f5a4}, /* U+71DC [2000] */ - {0x00e7879f, 0x009a7a}, /* U+71DF */ - {0x00e787a0, 0x00e09a}, /* U+71E0 */ - {0x00e787a5, 0x009187}, /* U+71E5 */ - {0x00e787a6, 0x008e57}, /* U+71E6 */ - {0x00e787a7, 0x00e09c}, /* U+71E7 */ - {0x00e787ac, 0x00e09b}, /* U+71EC */ - {0x00e787ad, 0x009043}, /* U+71ED */ - {0x00e787ae, 0x0099d7}, /* U+71EE */ - {0x00e787b5, 0x00e09d}, /* U+71F5 */ - {0x00e787b9, 0x00e09f}, /* U+71F9 */ - {0x00e787bb, 0x00e08e}, /* U+71FB */ - {0x00e787bc, 0x00e09e}, /* U+71FC */ - {0x00e787be, 0x00ec81}, /* U+71FE [2000] */ - {0x00e787bf, 0x00e0a0}, /* U+71FF */ - {0x00e78880, 0x00ec82}, /* U+7200 [2000] */ - {0x00e78886, 0x00949a}, /* U+7206 */ - {0x00e78887, 0x00f5a5}, /* U+7207 [2000] */ - {0x00e7888d, 0x00e0a1}, /* U+720D */ - {0x00e78890, 0x00e0a2}, /* U+7210 */ - {0x00e78895, 0x00ec83}, /* U+7215 [2000] */ - {0x00e7889b, 0x00e0a3}, /* U+721B */ - {0x00e788a8, 0x00e0a4}, /* U+7228 */ - {0x00e788aa, 0x0092dc}, /* U+722A */ - {0x00e788ab, 0x00f5a8}, /* U+722B [2000] */ - {0x00e788ac, 0x00e0a6}, /* U+722C */ - {0x00e788ad, 0x00e0a5}, /* U+722D */ - {0x00e788b0, 0x00e0a7}, /* U+7230 */ - {0x00e788b2, 0x00e0a8}, /* U+7232 */ - {0x00e788b4, 0x00f5a9}, /* U+7234 [2000] */ - {0x00e788b5, 0x008edd}, /* U+7235 */ - {0x00e788b6, 0x009583}, /* U+7236 */ - {0x00e788b8, 0x00f5aa}, /* U+7238 [2000] */ - {0x00e788b9, 0x00f5ab}, /* U+7239 [2000] */ - {0x00e788ba, 0x0096ea}, /* U+723A */ - {0x00e788bb, 0x00e0a9}, /* U+723B */ - {0x00e788bc, 0x00e0aa}, /* U+723C */ - {0x00e788bd, 0x009175}, /* U+723D */ - {0x00e788be, 0x008ea2}, /* U+723E */ - {0x00e788bf, 0x00e0ab}, /* U+723F */ - {0x00e78980, 0x00e0ac}, /* U+7240 */ - {0x00e78982, 0x00f5ad}, /* U+7242 [2000] */ - {0x00e78986, 0x00e0ad}, /* U+7246 */ - {0x00e78987, 0x0095d0}, /* U+7247 */ - {0x00e78988, 0x0094c5}, /* U+7248 */ - {0x00e7898b, 0x00e0ae}, /* U+724B */ - {0x00e7898c, 0x009476}, /* U+724C */ - {0x00e78992, 0x0092ab}, /* U+7252 */ - {0x00e78993, 0x00f5ae}, /* U+7253 [2000] */ - {0x00e78995, 0x00ec84}, /* U+7255 [2000] */ - {0x00e78996, 0x00ec85}, /* U+7256 [2000] */ - {0x00e78997, 0x00f5af}, /* U+7257 [2000] */ - {0x00e78998, 0x00e0af}, /* U+7258 */ - {0x00e78999, 0x0089e5}, /* U+7259 */ - {0x00e7899b, 0x008b8d}, /* U+725B */ - {0x00e7899d, 0x0096c4}, /* U+725D */ - {0x00e7899f, 0x0096b4}, /* U+725F */ - {0x00e789a1, 0x0089b2}, /* U+7261 */ - {0x00e789a2, 0x009853}, /* U+7262 */ - {0x00e789a3, 0x00f5b0}, /* U+7263 [2000] */ - {0x00e789a7, 0x009671}, /* U+7267 */ - {0x00e789a9, 0x0095a8}, /* U+7269 */ - {0x00e789ae, 0x00f5b2}, /* U+726E [2000] */ - {0x00e789af, 0x00f5b3}, /* U+726F [2000] */ - {0x00e789b2, 0x0090b5}, /* U+7272 */ - {0x00e789b4, 0x00e0b0}, /* U+7274 */ - {0x00e789b8, 0x00f5b4}, /* U+7278 [2000] */ - {0x00e789b9, 0x0093c1}, /* U+7279 */ - {0x00e789bd, 0x008ca1}, /* U+727D */ - {0x00e789be, 0x00e0b1}, /* U+727E */ - {0x00e789bf, 0x00f5b5}, /* U+727F [2000] */ - {0x00e78a80, 0x008dd2}, /* U+7280 */ - {0x00e78a81, 0x00e0b3}, /* U+7281 */ - {0x00e78a82, 0x00e0b2}, /* U+7282 */ - {0x00e78a87, 0x00e0b4}, /* U+7287 */ - {0x00e78a8d, 0x00ec87}, /* U+728D [2000] */ - {0x00e78a8e, 0x00f5b6}, /* U+728E [2000] */ - {0x00e78a92, 0x00e0b5}, /* U+7292 */ - {0x00e78a96, 0x00e0b6}, /* U+7296 */ - {0x00e78a9b, 0x00ec88}, /* U+729B [2000] */ - {0x00e78aa0, 0x008b5d}, /* U+72A0 */ - {0x00e78aa2, 0x00e0b7}, /* U+72A2 */ - {0x00e78aa7, 0x00e0b8}, /* U+72A7 */ - {0x00e78aac, 0x008ca2}, /* U+72AC */ - {0x00e78aad, 0x00f5b8}, /* U+72AD [2000] */ - {0x00e78aae, 0x00f5b9}, /* U+72AE [2000] */ - {0x00e78aaf, 0x0094c6}, /* U+72AF */ - {0x00e78ab0, 0x00f5ba}, /* U+72B0 [2000] */ - {0x00e78ab1, 0x00f5bb}, /* U+72B1 [2000] */ - {0x00e78ab2, 0x00e0ba}, /* U+72B2 */ - {0x00e78ab6, 0x008ff3}, /* U+72B6 */ - {0x00e78ab9, 0x00e0b9}, /* U+72B9 */ - {0x00e78abe, 0x00ec89}, /* U+72BE [2000] */ - {0x00e78b80, 0x00ec8a}, /* U+72C0 [2000] */ - {0x00e78b81, 0x00f5bc}, /* U+72C1 [2000] */ - {0x00e78b82, 0x008bb6}, /* U+72C2 */ - {0x00e78b83, 0x00e0bb}, /* U+72C3 */ - {0x00e78b84, 0x00e0bd}, /* U+72C4 */ - {0x00e78b86, 0x00e0bc}, /* U+72C6 */ - {0x00e78b8c, 0x00f5be}, /* U+72CC [2000] */ - {0x00e78b8e, 0x00e0be}, /* U+72CE */ - {0x00e78b90, 0x008ccf}, /* U+72D0 */ - {0x00e78b92, 0x00e0bf}, /* U+72D2 */ - {0x00e78b97, 0x008be7}, /* U+72D7 */ - {0x00e78b99, 0x00915f}, /* U+72D9 */ - {0x00e78b9b, 0x008d9d}, /* U+72DB */ - {0x00e78ba0, 0x00e0c1}, /* U+72E0 */ - {0x00e78ba1, 0x00e0c2}, /* U+72E1 */ - {0x00e78ba2, 0x00e0c0}, /* U+72E2 */ - {0x00e78ba9, 0x008eeb}, /* U+72E9 */ - {0x00e78bac, 0x0093c6}, /* U+72EC */ - {0x00e78bad, 0x008bb7}, /* U+72ED */ - {0x00e78bb3, 0x00f5c1}, /* U+72F3 [2000] */ - {0x00e78bb7, 0x00e0c4}, /* U+72F7 */ - {0x00e78bb8, 0x00924b}, /* U+72F8 */ - {0x00e78bb9, 0x00e0c3}, /* U+72F9 */ - {0x00e78bba, 0x00f5c2}, /* U+72FA [2000] */ - {0x00e78bbb, 0x00ec8b}, /* U+72FB [2000] */ - {0x00e78bbc, 0x009854}, /* U+72FC */ - {0x00e78bbd, 0x009482}, /* U+72FD */ - {0x00e78c87, 0x00f5c3}, /* U+7307 [2000] */ - {0x00e78c8a, 0x00e0c7}, /* U+730A */ - {0x00e78c92, 0x00f5c4}, /* U+7312 [2000] */ - {0x00e78c96, 0x00e0c9}, /* U+7316 */ - {0x00e78c97, 0x00e0c6}, /* U+7317 */ - {0x00e78c98, 0x00f5c5}, /* U+7318 [2000] */ - {0x00e78c99, 0x00f5c6}, /* U+7319 [2000] */ - {0x00e78c9b, 0x0096d2}, /* U+731B */ - {0x00e78c9c, 0x00e0c8}, /* U+731C */ - {0x00e78c9d, 0x00e0ca}, /* U+731D */ - {0x00e78c9f, 0x0097c2}, /* U+731F */ - {0x00e78ca5, 0x00e0ce}, /* U+7325 */ - {0x00e78ca7, 0x00ec8d}, /* U+7327 [2000] */ - {0x00e78ca8, 0x00ec8e}, /* U+7328 [2000] */ - {0x00e78ca9, 0x00e0cd}, /* U+7329 */ - {0x00e78caa, 0x009296}, /* U+732A */ - {0x00e78cab, 0x00944c}, /* U+732B */ - {0x00e78cac, 0x00f5c9}, /* U+732C [2000] */ - {0x00e78cae, 0x008ca3}, /* U+732E */ - {0x00e78caf, 0x00e0cc}, /* U+732F */ - {0x00e78cb1, 0x00f5ca}, /* U+7331 [2000] */ - {0x00e78cb3, 0x00f5cb}, /* U+7333 [2000] */ - {0x00e78cb4, 0x00e0cb}, /* U+7334 */ - {0x00e78cb6, 0x009750}, /* U+7336 */ - {0x00e78cb7, 0x009751}, /* U+7337 */ - {0x00e78cb9, 0x00f5c8}, /* U+7339 [2000] */ - {0x00e78cbd, 0x00f5cc}, /* U+733D [2000] */ - {0x00e78cbe, 0x00e0cf}, /* U+733E */ - {0x00e78cbf, 0x00898e}, /* U+733F */ - {0x00e78d84, 0x008d96}, /* U+7344 */ - {0x00e78d85, 0x008e82}, /* U+7345 */ - {0x00e78d8e, 0x00e0d0}, /* U+734E */ - {0x00e78d8f, 0x00e0d1}, /* U+734F */ - {0x00e78d90, 0x00ec90}, /* U+7350 [2000] */ - {0x00e78d92, 0x00f5cd}, /* U+7352 [2000] */ - {0x00e78d97, 0x00e0d3}, /* U+7357 */ - {0x00e78da3, 0x008f62}, /* U+7363 */ - {0x00e78da6, 0x00ec91}, /* U+7366 [2000] */ - {0x00e78da8, 0x00e0d5}, /* U+7368 */ - {0x00e78daa, 0x00e0d4}, /* U+736A */ - {0x00e78dab, 0x00f5cf}, /* U+736B [2000] */ - {0x00e78dac, 0x00f5d0}, /* U+736C [2000] */ - {0x00e78dae, 0x00f5d2}, /* U+736E [2000] */ - {0x00e78daf, 0x00f5d3}, /* U+736F [2000] */ - {0x00e78db0, 0x00e0d6}, /* U+7370 */ - {0x00e78db1, 0x00f5d4}, /* U+7371 [2000] */ - {0x00e78db2, 0x008a6c}, /* U+7372 */ - {0x00e78db5, 0x00e0d8}, /* U+7375 */ - {0x00e78db7, 0x00f5d5}, /* U+7377 [2000] */ - {0x00e78db8, 0x00e0d7}, /* U+7378 */ - {0x00e78dba, 0x00e0da}, /* U+737A */ - {0x00e78dbb, 0x00e0d9}, /* U+737B */ - {0x00e78dbc, 0x00ec92}, /* U+737C [2000] */ - {0x00e78e81, 0x00f5d6}, /* U+7381 [2000] */ - {0x00e78e84, 0x008cba}, /* U+7384 */ - {0x00e78e85, 0x00f5d7}, /* U+7385 [2000] */ - {0x00e78e87, 0x0097a6}, /* U+7387 */ - {0x00e78e89, 0x008bca}, /* U+7389 */ - {0x00e78e8a, 0x00f5d8}, /* U+738A [2000] */ - {0x00e78e8b, 0x0089a4}, /* U+738B */ - {0x00e78e94, 0x00f5d9}, /* U+7394 [2000] */ - {0x00e78e95, 0x00ec93}, /* U+7395 [2000] */ - {0x00e78e96, 0x008be8}, /* U+7396 */ - {0x00e78e98, 0x00f5da}, /* U+7398 [2000] */ - {0x00e78e9c, 0x00f5db}, /* U+739C [2000] */ - {0x00e78e9e, 0x00f5dc}, /* U+739E [2000] */ - {0x00e78e9f, 0x00ec94}, /* U+739F [2000] */ - {0x00e78ea0, 0x00ec95}, /* U+73A0 [2000] */ - {0x00e78ea2, 0x00ec96}, /* U+73A2 [2000] */ - {0x00e78ea5, 0x00f5dd}, /* U+73A5 [2000] */ - {0x00e78ea6, 0x00ec97}, /* U+73A6 [2000] */ - {0x00e78ea8, 0x00f5de}, /* U+73A8 [2000] */ - {0x00e78ea9, 0x008adf}, /* U+73A9 */ - {0x00e78eab, 0x00ec98}, /* U+73AB [2000] */ - {0x00e78eb2, 0x0097e6}, /* U+73B2 */ - {0x00e78eb3, 0x00e0dc}, /* U+73B3 */ - {0x00e78eb5, 0x00f5df}, /* U+73B5 [2000] */ - {0x00e78eb7, 0x00f5e0}, /* U+73B7 [2000] */ - {0x00e78eb9, 0x00f5e1}, /* U+73B9 [2000] */ - {0x00e78ebb, 0x00e0de}, /* U+73BB */ - {0x00e78ebc, 0x00f5e2}, /* U+73BC [2000] */ - {0x00e78ebf, 0x00f5e3}, /* U+73BF [2000] */ - {0x00e78f80, 0x00e0df}, /* U+73C0 */ - {0x00e78f82, 0x0089cf}, /* U+73C2 */ - {0x00e78f85, 0x00f5e4}, /* U+73C5 [2000] */ - {0x00e78f88, 0x00e0db}, /* U+73C8 */ - {0x00e78f89, 0x00ec99}, /* U+73C9 [2000] */ - {0x00e78f8a, 0x008e58}, /* U+73CA */ - {0x00e78f8b, 0x00f5e5}, /* U+73CB [2000] */ - {0x00e78f8d, 0x0092bf}, /* U+73CD */ - {0x00e78f8e, 0x00e0dd}, /* U+73CE */ - {0x00e78f8f, 0x00ec9a}, /* U+73CF [2000] */ - {0x00e78f96, 0x00ec9b}, /* U+73D6 [2000] */ - {0x00e78f99, 0x00ec9c}, /* U+73D9 [2000] */ - {0x00e78f9e, 0x00e0e2}, /* U+73DE */ - {0x00e78fa0, 0x008eec}, /* U+73E0 */ - {0x00e78fa1, 0x00f5e6}, /* U+73E1 [2000] */ - {0x00e78fa3, 0x00ec9d}, /* U+73E3 [2000] */ - {0x00e78fa5, 0x00e0e0}, /* U+73E5 */ - {0x00e78fa7, 0x00f5e7}, /* U+73E7 [2000] */ - {0x00e78fa9, 0x00ec9e}, /* U+73E9 [2000] */ - {0x00e78faa, 0x008c5d}, /* U+73EA */ - {0x00e78fad, 0x0094c7}, /* U+73ED */ - {0x00e78fae, 0x00e0e1}, /* U+73EE */ - {0x00e78fb1, 0x00e0fc}, /* U+73F1 */ - {0x00e78fb8, 0x00e0e7}, /* U+73F8 */ - {0x00e78fb9, 0x00f5e8}, /* U+73F9 [2000] */ - {0x00e78fba, 0x00f5ea}, /* U+73FA [2000] */ - {0x00e78fbe, 0x008cbb}, /* U+73FE */ - {0x00e79081, 0x00f5eb}, /* U+7401 [2000] */ - {0x00e79083, 0x008b85}, /* U+7403 */ - {0x00e79085, 0x00e0e4}, /* U+7405 */ - {0x00e79086, 0x00979d}, /* U+7406 */ - {0x00e79087, 0x00ec9f}, /* U+7407 [2000] */ - {0x00e79089, 0x0097ae}, /* U+7409 */ - {0x00e7908a, 0x00eca0}, /* U+740A [2000] */ - {0x00e79093, 0x00f5e9}, /* U+7413 [2000] */ - {0x00e7909a, 0x00eca1}, /* U+741A [2000] */ - {0x00e7909b, 0x00eca2}, /* U+741B [2000] */ - {0x00e790a2, 0x0091f4}, /* U+7422 */ - {0x00e790a4, 0x00f5ec}, /* U+7424 [2000] */ - {0x00e790a5, 0x00e0e6}, /* U+7425 */ - {0x00e790a6, 0x00eca4}, /* U+7426 [2000] */ - {0x00e790a8, 0x00eca5}, /* U+7428 [2000] */ - {0x00e790aa, 0x00eca6}, /* U+742A [2000] */ - {0x00e790ab, 0x00eca7}, /* U+742B [2000] */ - {0x00e790ac, 0x00eca8}, /* U+742C [2000] */ - {0x00e790ae, 0x00eca9}, /* U+742E [2000] */ - {0x00e790af, 0x00ecaa}, /* U+742F [2000] */ - {0x00e790b0, 0x00ecab}, /* U+7430 [2000] */ - {0x00e790b1, 0x00f5ed}, /* U+7431 [2000] */ - {0x00e790b2, 0x00e0e8}, /* U+7432 */ - {0x00e790b3, 0x0097d4}, /* U+7433 */ - {0x00e790b4, 0x008bd5}, /* U+7434 */ - {0x00e790b5, 0x0094fa}, /* U+7435 */ - {0x00e790b6, 0x009469}, /* U+7436 */ - {0x00e790b9, 0x00f5ee}, /* U+7439 [2000] */ - {0x00e790ba, 0x00e0e9}, /* U+743A */ - {0x00e790bf, 0x00e0eb}, /* U+743F */ - {0x00e79180, 0x00f5f0}, /* U+7440 [2000] */ - {0x00e79181, 0x00e0ee}, /* U+7441 */ - {0x00e79183, 0x00f5f1}, /* U+7443 [2000] */ - {0x00e79184, 0x00ecac}, /* U+7444 [2000] */ - {0x00e79186, 0x00ecad}, /* U+7446 [2000] */ - {0x00e79187, 0x00ecae}, /* U+7447 [2000] */ - {0x00e7918b, 0x00ecaf}, /* U+744B [2000] */ - {0x00e7918d, 0x00f5f2}, /* U+744D [2000] */ - {0x00e79192, 0x00f5f3}, /* U+7452 [2000] */ - {0x00e79193, 0x00f5ef}, /* U+7453 [2000] */ - {0x00e79195, 0x00e0ea}, /* U+7455 */ - {0x00e79197, 0x00ecb0}, /* U+7457 [2000] */ - {0x00e79199, 0x00e0ed}, /* U+7459 */ - {0x00e7919a, 0x008ce8}, /* U+745A */ - {0x00e7919b, 0x00896c}, /* U+745B */ - {0x00e7919c, 0x00e0ef}, /* U+745C */ - {0x00e7919d, 0x00f5f4}, /* U+745D [2000] */ - {0x00e7919e, 0x009090}, /* U+745E */ - {0x00e7919f, 0x00e0ec}, /* U+745F */ - {0x00e791a0, 0x0097da}, /* U+7460 */ - {0x00e791a2, 0x00ecb1}, /* U+7462 [2000] */ - {0x00e791a3, 0x00e0f2}, /* U+7463 */ - {0x00e791a4, 0x00eaa2}, /* U+7464 [1983] */ - {0x00e791a9, 0x00e0f0}, /* U+7469 */ - {0x00e791aa, 0x00e0f3}, /* U+746A */ - {0x00e791ab, 0x00ecb2}, /* U+746B [2000] */ - {0x00e791ad, 0x00ecb3}, /* U+746D [2000] */ - {0x00e791af, 0x00e0e5}, /* U+746F */ - {0x00e791b0, 0x00e0f1}, /* U+7470 */ - {0x00e791b1, 0x00f5f5}, /* U+7471 [2000] */ - {0x00e791b3, 0x008dba}, /* U+7473 */ - {0x00e791b6, 0x00e0f4}, /* U+7476 */ - {0x00e791be, 0x00e0f5}, /* U+747E */ - {0x00e79281, 0x00f5f6}, /* U+7481 [2000] */ - {0x00e79283, 0x00979e}, /* U+7483 */ - {0x00e79285, 0x00f5f7}, /* U+7485 [2000] */ - {0x00e79286, 0x00ecb4}, /* U+7486 [2000] */ - {0x00e79287, 0x00ecb5}, /* U+7487 [2000] */ - {0x00e79288, 0x00f5f8}, /* U+7488 [2000] */ - {0x00e79289, 0x00ecb6}, /* U+7489 [2000] */ - {0x00e7928b, 0x00e0f6}, /* U+748B */ - {0x00e79290, 0x00ecbb}, /* U+7490 [2000] */ - {0x00e79292, 0x00f5fa}, /* U+7492 [2000] */ - {0x00e79297, 0x00f5fb}, /* U+7497 [2000] */ - {0x00e79298, 0x00ecb7}, /* U+7498 [2000] */ - {0x00e79299, 0x00f5fc}, /* U+7499 [2000] */ - {0x00e7929c, 0x00ecb8}, /* U+749C [2000] */ - {0x00e7929e, 0x00e0f7}, /* U+749E */ - {0x00e7929f, 0x00ecb9}, /* U+749F [2000] */ - {0x00e792a0, 0x00f640}, /* U+74A0 [2000] */ - {0x00e792a1, 0x00f641}, /* U+74A1 [2000] */ - {0x00e792a2, 0x00e0e3}, /* U+74A2 */ - {0x00e792a3, 0x00ecba}, /* U+74A3 [2000] */ - {0x00e792a5, 0x00f642}, /* U+74A5 [2000] */ - {0x00e792a6, 0x00ecbc}, /* U+74A6 [2000] */ - {0x00e792a7, 0x00e0f8}, /* U+74A7 */ - {0x00e792a8, 0x00ecbd}, /* U+74A8 [2000] */ - {0x00e792a9, 0x00ecbe}, /* U+74A9 [2000] */ - {0x00e792aa, 0x00f643}, /* U+74AA [2000] */ - {0x00e792ab, 0x00f644}, /* U+74AB [2000] */ - {0x00e792b0, 0x008ac2}, /* U+74B0 */ - {0x00e792b5, 0x00ecbf}, /* U+74B5 [2000] */ - {0x00e792b9, 0x00f645}, /* U+74B9 [2000] */ - {0x00e792ba, 0x00f647}, /* U+74BA [2000] */ - {0x00e792bb, 0x00f646}, /* U+74BB [2000] */ - {0x00e792bd, 0x008ea3}, /* U+74BD */ - {0x00e792bf, 0x00ecc0}, /* U+74BF [2000] */ - {0x00e79388, 0x00ecc1}, /* U+74C8 [2000] */ - {0x00e79389, 0x00ecc2}, /* U+74C9 [2000] */ - {0x00e7938a, 0x00e0f9}, /* U+74CA */ - {0x00e7938f, 0x00e0fa}, /* U+74CF */ - {0x00e79394, 0x00e0fb}, /* U+74D4 */ - {0x00e79396, 0x00f648}, /* U+74D6 [2000] */ - {0x00e79398, 0x00f649}, /* U+74D8 [2000] */ - {0x00e7939a, 0x00ecc3}, /* U+74DA [2000] */ - {0x00e7939c, 0x00895a}, /* U+74DC */ - {0x00e7939e, 0x00f64a}, /* U+74DE [2000] */ - {0x00e793a0, 0x00e140}, /* U+74E0 */ - {0x00e793a2, 0x00955a}, /* U+74E2 */ - {0x00e793a3, 0x00e141}, /* U+74E3 */ - {0x00e793a6, 0x008aa2}, /* U+74E6 */ - {0x00e793a7, 0x00e142}, /* U+74E7 */ - {0x00e793a9, 0x00e143}, /* U+74E9 */ - {0x00e793ab, 0x00f64c}, /* U+74EB [2000] */ - {0x00e793ae, 0x00e144}, /* U+74EE */ - {0x00e793af, 0x00f64b}, /* U+74EF [2000] */ - {0x00e793b0, 0x00e146}, /* U+74F0 */ - {0x00e793b1, 0x00e147}, /* U+74F1 */ - {0x00e793b2, 0x00e145}, /* U+74F2 */ - {0x00e793b6, 0x009572}, /* U+74F6 */ - {0x00e793b7, 0x00e149}, /* U+74F7 */ - {0x00e793b8, 0x00e148}, /* U+74F8 */ - {0x00e793ba, 0x00f64e}, /* U+74FA [2000] */ - {0x00e793bf, 0x00ecc4}, /* U+74FF [2000] */ - {0x00e79481, 0x00ecc5}, /* U+7501 [2000] */ - {0x00e79483, 0x00e14b}, /* U+7503 */ - {0x00e79484, 0x00e14a}, /* U+7504 */ - {0x00e79485, 0x00e14c}, /* U+7505 */ - {0x00e7948c, 0x00e14d}, /* U+750C */ - {0x00e7948d, 0x00e14f}, /* U+750D */ - {0x00e7948e, 0x00e14e}, /* U+750E */ - {0x00e79491, 0x008d99}, /* U+7511 */ - {0x00e79493, 0x00e151}, /* U+7513 */ - {0x00e79495, 0x00e150}, /* U+7515 */ - {0x00e79497, 0x00ecc6}, /* U+7517 [2000] */ - {0x00e79498, 0x008ac3}, /* U+7518 */ - {0x00e7949a, 0x009072}, /* U+751A */ - {0x00e7949c, 0x00935b}, /* U+751C */ - {0x00e7949e, 0x00e152}, /* U+751E */ - {0x00e7949f, 0x0090b6}, /* U+751F */ - {0x00e794a0, 0x00f650}, /* U+7520 [2000] */ - {0x00e794a3, 0x008e59}, /* U+7523 */ - {0x00e794a4, 0x00f651}, /* U+7524 [2000] */ - {0x00e794a5, 0x008999}, /* U+7525 */ - {0x00e794a6, 0x00e153}, /* U+7526 */ - {0x00e794a8, 0x009770}, /* U+7528 */ - {0x00e794aa, 0x00f652}, /* U+752A [2000] */ - {0x00e794ab, 0x0095e1}, /* U+752B */ - {0x00e794ac, 0x00e154}, /* U+752C */ - {0x00e794af, 0x00ecc7}, /* U+752F [2000] */ - {0x00e794b0, 0x009363}, /* U+7530 */ - {0x00e794b1, 0x009752}, /* U+7531 */ - {0x00e794b2, 0x008d62}, /* U+7532 */ - {0x00e794b3, 0x00905c}, /* U+7533 */ - {0x00e794b7, 0x00926a}, /* U+7537 */ - {0x00e794b8, 0x0099b2}, /* U+7538 */ - {0x00e794ba, 0x0092ac}, /* U+753A */ - {0x00e794bb, 0x0089e6}, /* U+753B */ - {0x00e794bc, 0x00e155}, /* U+753C */ - {0x00e794bd, 0x00f655}, /* U+753D [2000] */ - {0x00e794be, 0x00f656}, /* U+753E [2000] */ - {0x00e79580, 0x00f657}, /* U+7540 [2000] */ - {0x00e79584, 0x00e156}, /* U+7544 */ - {0x00e79586, 0x00e15b}, /* U+7546 */ - {0x00e79588, 0x00f658}, /* U+7548 [2000] */ - {0x00e79589, 0x00e159}, /* U+7549 */ - {0x00e7958a, 0x00e158}, /* U+754A */ - {0x00e7958b, 0x009dc0}, /* U+754B */ - {0x00e7958c, 0x008a45}, /* U+754C */ - {0x00e7958d, 0x00e157}, /* U+754D */ - {0x00e7958e, 0x00f659}, /* U+754E [2000] */ - {0x00e7958f, 0x0088d8}, /* U+754F */ - {0x00e79590, 0x00f65a}, /* U+7550 [2000] */ - {0x00e79591, 0x0094a8}, /* U+7551 */ - {0x00e79592, 0x00f65b}, /* U+7552 [2000] */ - {0x00e79594, 0x0094c8}, /* U+7554 */ - {0x00e79599, 0x0097af}, /* U+7559 */ - {0x00e7959a, 0x00e15c}, /* U+755A */ - {0x00e7959b, 0x00e15a}, /* U+755B */ - {0x00e7959c, 0x00927b}, /* U+755C */ - {0x00e7959d, 0x0090a4}, /* U+755D */ - {0x00e795a0, 0x0094a9}, /* U+7560 */ - {0x00e795a2, 0x00954c}, /* U+7562 */ - {0x00e795a4, 0x00e15e}, /* U+7564 */ - {0x00e795a5, 0x0097aa}, /* U+7565 */ - {0x00e795a6, 0x008c6c}, /* U+7566 */ - {0x00e795a7, 0x00e15f}, /* U+7567 */ - {0x00e795a9, 0x00e15d}, /* U+7569 */ - {0x00e795aa, 0x0094d4}, /* U+756A */ - {0x00e795ab, 0x00e160}, /* U+756B */ - {0x00e795ac, 0x00f65c}, /* U+756C [2000] */ - {0x00e795ad, 0x00e161}, /* U+756D */ - {0x00e795af, 0x00ecc8}, /* U+756F [2000] */ - {0x00e795b0, 0x0088d9}, /* U+7570 */ - {0x00e795b1, 0x00f65e}, /* U+7571 [2000] */ - {0x00e795b2, 0x00f65d}, /* U+7572 [2000] */ - {0x00e795b3, 0x008ff4}, /* U+7573 */ - {0x00e795b4, 0x00e166}, /* U+7574 */ - {0x00e795b6, 0x00e163}, /* U+7576 */ - {0x00e795b7, 0x0093eb}, /* U+7577 */ - {0x00e795b8, 0x00e162}, /* U+7578 */ - {0x00e795b9, 0x00ecc9}, /* U+7579 [2000] */ - {0x00e795ba, 0x00f65f}, /* U+757A [2000] */ - {0x00e795bd, 0x00f660}, /* U+757D [2000] */ - {0x00e795be, 0x00f661}, /* U+757E [2000] */ - {0x00e795bf, 0x008b45}, /* U+757F */ - {0x00e79681, 0x00f662}, /* U+7581 [2000] */ - {0x00e79682, 0x00e169}, /* U+7582 */ - {0x00e79686, 0x00e164}, /* U+7586 */ - {0x00e79687, 0x00e165}, /* U+7587 */ - {0x00e79689, 0x00e168}, /* U+7589 */ - {0x00e7968a, 0x00e167}, /* U+758A */ - {0x00e7968b, 0x009544}, /* U+758B */ - {0x00e7968c, 0x00f664}, /* U+758C [2000] */ - {0x00e7968e, 0x009161}, /* U+758E */ - {0x00e7968f, 0x009160}, /* U+758F */ - {0x00e79691, 0x008b5e}, /* U+7591 */ - {0x00e79692, 0x00ecca}, /* U+7592 [2000] */ - {0x00e79694, 0x00e16a}, /* U+7594 */ - {0x00e7969a, 0x00e16b}, /* U+759A */ - {0x00e7969d, 0x00e16c}, /* U+759D */ - {0x00e796a2, 0x00f666}, /* U+75A2 [2000] */ - {0x00e796a3, 0x00e16e}, /* U+75A3 */ - {0x00e796a5, 0x00e16d}, /* U+75A5 */ - {0x00e796ab, 0x008975}, /* U+75AB */ - {0x00e796b0, 0x00f668}, /* U+75B0 [2000] */ - {0x00e796b1, 0x00e176}, /* U+75B1 */ - {0x00e796b2, 0x0094e6}, /* U+75B2 */ - {0x00e796b3, 0x00e170}, /* U+75B3 */ - {0x00e796b5, 0x00e172}, /* U+75B5 */ - {0x00e796b7, 0x00f669}, /* U+75B7 [2000] */ - {0x00e796b8, 0x00e174}, /* U+75B8 */ - {0x00e796b9, 0x00905d}, /* U+75B9 */ - {0x00e796bc, 0x00e175}, /* U+75BC */ - {0x00e796bd, 0x00e173}, /* U+75BD */ - {0x00e796be, 0x008ebe}, /* U+75BE */ - {0x00e796bf, 0x00f66a}, /* U+75BF [2000] */ - {0x00e79780, 0x00f66b}, /* U+75C0 [2000] */ - {0x00e79782, 0x00e16f}, /* U+75C2 */ - {0x00e79783, 0x00e171}, /* U+75C3 */ - {0x00e79785, 0x009561}, /* U+75C5 */ - {0x00e79786, 0x00f66c}, /* U+75C6 [2000] */ - {0x00e79787, 0x008fc7}, /* U+75C7 */ - {0x00e7978a, 0x00e178}, /* U+75CA */ - {0x00e7978d, 0x00e177}, /* U+75CD */ - {0x00e7978e, 0x00eccc}, /* U+75CE [2000] */ - {0x00e7978f, 0x00f66d}, /* U+75CF [2000] */ - {0x00e79792, 0x00e179}, /* U+75D2 */ - {0x00e79793, 0x00f66e}, /* U+75D3 [2000] */ - {0x00e79794, 0x008ea4}, /* U+75D4 */ - {0x00e79795, 0x008dad}, /* U+75D5 */ - {0x00e79798, 0x009397}, /* U+75D8 */ - {0x00e79799, 0x00e17a}, /* U+75D9 */ - {0x00e7979b, 0x0092c9}, /* U+75DB */ - {0x00e7979d, 0x00f66f}, /* U+75DD [2000] */ - {0x00e7979e, 0x00e17c}, /* U+75DE */ - {0x00e7979f, 0x00f670}, /* U+75DF [2000] */ - {0x00e797a0, 0x00f671}, /* U+75E0 [2000] */ - {0x00e797a2, 0x00979f}, /* U+75E2 */ - {0x00e797a3, 0x00e17b}, /* U+75E3 */ - {0x00e797a4, 0x00eccd}, /* U+75E4 [2000] */ - {0x00e797a7, 0x00f672}, /* U+75E7 [2000] */ - {0x00e797a9, 0x009189}, /* U+75E9 */ - {0x00e797ac, 0x00f673}, /* U+75EC [2000] */ - {0x00e797ae, 0x00f674}, /* U+75EE [2000] */ - {0x00e797b0, 0x00e182}, /* U+75F0 */ - {0x00e797b1, 0x00f675}, /* U+75F1 [2000] */ - {0x00e797b2, 0x00e184}, /* U+75F2 */ - {0x00e797b3, 0x00e185}, /* U+75F3 */ - {0x00e797b4, 0x009273}, /* U+75F4 */ - {0x00e797b9, 0x00f676}, /* U+75F9 [2000] */ - {0x00e797ba, 0x00e183}, /* U+75FA */ - {0x00e797bc, 0x00e180}, /* U+75FC */ - {0x00e797be, 0x00e17d}, /* U+75FE */ - {0x00e797bf, 0x00e17e}, /* U+75FF */ - {0x00e79880, 0x00ecce}, /* U+7600 [2000] */ - {0x00e79881, 0x00e181}, /* U+7601 */ - {0x00e79882, 0x00eccf}, /* U+7602 [2000] */ - {0x00e79883, 0x00f677}, /* U+7603 [2000] */ - {0x00e79887, 0x00f679}, /* U+7607 [2000] */ - {0x00e79888, 0x00ecd0}, /* U+7608 [2000] */ - {0x00e79889, 0x00e188}, /* U+7609 */ - {0x00e7988b, 0x00e186}, /* U+760B */ - {0x00e7988d, 0x00e187}, /* U+760D */ - {0x00e7988f, 0x00f67a}, /* U+760F [2000] */ - {0x00e79893, 0x00f67d}, /* U+7613 [2000] */ - {0x00e79895, 0x00ecd1}, /* U+7615 [2000] */ - {0x00e79896, 0x00ecd2}, /* U+7616 [2000] */ - {0x00e79898, 0x00f678}, /* U+7618 [2000] */ - {0x00e79899, 0x00ecd3}, /* U+7619 [2000] */ - {0x00e7989b, 0x00f67e}, /* U+761B [2000] */ - {0x00e7989c, 0x00f680}, /* U+761C [2000] */ - {0x00e7989e, 0x00ecd4}, /* U+761E [2000] */ - {0x00e7989f, 0x00e189}, /* U+761F */ - {0x00e798a0, 0x00e18b}, /* U+7620 */ - {0x00e798a1, 0x00e18c}, /* U+7621 */ - {0x00e798a2, 0x00e18d}, /* U+7622 */ - {0x00e798a4, 0x00e18e}, /* U+7624 */ - {0x00e798a5, 0x00f682}, /* U+7625 [2000] */ - {0x00e798a6, 0x00effb}, /* U+7626 [2004] */ - {0x00e798a7, 0x00e18a}, /* U+7627 */ - {0x00e798a8, 0x00f683}, /* U+7628 [2000] */ - {0x00e798ad, 0x00ecd5}, /* U+762D [2000] */ - {0x00e798b0, 0x00e190}, /* U+7630 */ - {0x00e798b3, 0x00f685}, /* U+7633 [2000] */ - {0x00e798b4, 0x00e18f}, /* U+7634 */ - {0x00e798b5, 0x00ecd6}, /* U+7635 [2000] */ - {0x00e798bb, 0x00e191}, /* U+763B */ - {0x00e798bc, 0x00f684}, /* U+763C [2000] */ - {0x00e79981, 0x00f688}, /* U+7641 [2000] */ - {0x00e79982, 0x0097c3}, /* U+7642 */ - {0x00e79983, 0x00ecd7}, /* U+7643 [2000] */ - {0x00e79986, 0x00e194}, /* U+7646 */ - {0x00e79987, 0x00e192}, /* U+7647 */ - {0x00e79988, 0x00e193}, /* U+7648 */ - {0x00e79989, 0x00f68a}, /* U+7649 [2000] */ - {0x00e7998b, 0x00ecd8}, /* U+764B [2000] */ - {0x00e7998c, 0x008ae0}, /* U+764C */ - {0x00e79992, 0x0096fc}, /* U+7652 */ - {0x00e79995, 0x00f68b}, /* U+7655 [2000] */ - {0x00e79996, 0x0095c8}, /* U+7656 */ - {0x00e79998, 0x00e196}, /* U+7658 */ - {0x00e7999c, 0x00e195}, /* U+765C */ - {0x00e799a1, 0x00e197}, /* U+7661 */ - {0x00e799a2, 0x00e198}, /* U+7662 */ - {0x00e799a4, 0x00ecd9}, /* U+7664 [2000] */ - {0x00e799a5, 0x00ecda}, /* U+7665 [2000] */ - {0x00e799a7, 0x00e19c}, /* U+7667 */ - {0x00e799a8, 0x00e199}, /* U+7668 */ - {0x00e799a9, 0x00e19a}, /* U+7669 */ - {0x00e799aa, 0x00e19b}, /* U+766A */ - {0x00e799ac, 0x00e19d}, /* U+766C */ - {0x00e799ad, 0x00ecdb}, /* U+766D [2000] */ - {0x00e799ae, 0x00f68d}, /* U+766E [2000] */ - {0x00e799af, 0x00ecdc}, /* U+766F [2000] */ - {0x00e799b0, 0x00e19e}, /* U+7670 */ - {0x00e799b1, 0x00ecdd}, /* U+7671 [2000] */ - {0x00e799b2, 0x00e19f}, /* U+7672 */ - {0x00e799b6, 0x00e1a0}, /* U+7676 */ - {0x00e799b8, 0x00e1a1}, /* U+7678 */ - {0x00e799ba, 0x0094ad}, /* U+767A */ - {0x00e799bb, 0x00936f}, /* U+767B */ - {0x00e799bc, 0x00e1a2}, /* U+767C */ - {0x00e799bd, 0x009492}, /* U+767D */ - {0x00e799be, 0x009553}, /* U+767E */ - {0x00e79a80, 0x00e1a3}, /* U+7680 */ - {0x00e79a81, 0x00ecde}, /* U+7681 [2000] */ - {0x00e79a83, 0x00e1a4}, /* U+7683 */ - {0x00e79a84, 0x009349}, /* U+7684 */ - {0x00e79a86, 0x008a46}, /* U+7686 */ - {0x00e79a87, 0x008d63}, /* U+7687 */ - {0x00e79a88, 0x00e1a5}, /* U+7688 */ - {0x00e79a8b, 0x00e1a6}, /* U+768B */ - {0x00e79a8e, 0x00e1a7}, /* U+768E */ - {0x00e79a90, 0x008e48}, /* U+7690 */ - {0x00e79a93, 0x00e1a9}, /* U+7693 */ - {0x00e79a95, 0x00f68e}, /* U+7695 [2000] */ - {0x00e79a96, 0x00e1a8}, /* U+7696 */ - {0x00e79a99, 0x00e1aa}, /* U+7699 */ - {0x00e79a9a, 0x00e1ab}, /* U+769A */ - {0x00e79a9b, 0x00ecdf}, /* U+769B [2000] */ - {0x00e79a9c, 0x00f68f}, /* U+769C [2000] */ - {0x00e79a9d, 0x00ece0}, /* U+769D [2000] */ - {0x00e79a9e, 0x00ece1}, /* U+769E [2000] */ - {0x00e79aa0, 0x00f691}, /* U+76A0 [2000] */ - {0x00e79aa1, 0x00f690}, /* U+76A1 [2000] */ - {0x00e79aa6, 0x00ece2}, /* U+76A6 [2000] */ - {0x00e79aa7, 0x00f692}, /* U+76A7 [2000] */ - {0x00e79aa8, 0x00f693}, /* U+76A8 [2000] */ - {0x00e79aaa, 0x00ece3}, /* U+76AA [2000] */ - {0x00e79aae, 0x0094e7}, /* U+76AE */ - {0x00e79aaf, 0x00f694}, /* U+76AF [2000] */ - {0x00e79ab0, 0x00e1ac}, /* U+76B0 */ - {0x00e79ab4, 0x00e1ad}, /* U+76B4 */ - {0x00e79ab6, 0x00ece4}, /* U+76B6 [2000] */ - {0x00e79ab7, 0x00ea89}, /* U+76B7 */ - {0x00e79ab8, 0x00e1ae}, /* U+76B8 */ - {0x00e79ab9, 0x00e1af}, /* U+76B9 */ - {0x00e79aba, 0x00e1b0}, /* U+76BA */ - {0x00e79abf, 0x008e4d}, /* U+76BF */ - {0x00e79b82, 0x00e1b1}, /* U+76C2 */ - {0x00e79b83, 0x009475}, /* U+76C3 */ - {0x00e79b85, 0x00ece5}, /* U+76C5 [2000] */ - {0x00e79b86, 0x00967e}, /* U+76C6 */ - {0x00e79b88, 0x00896d}, /* U+76C8 */ - {0x00e79b89, 0x00f696}, /* U+76C9 [2000] */ - {0x00e79b8a, 0x008976}, /* U+76CA */ - {0x00e79b8c, 0x00ece6}, /* U+76CC [2000] */ - {0x00e79b8d, 0x00e1b2}, /* U+76CD */ - {0x00e79b8e, 0x00ece7}, /* U+76CE [2000] */ - {0x00e79b92, 0x00e1b4}, /* U+76D2 */ - {0x00e79b94, 0x00ece8}, /* U+76D4 [2000] */ - {0x00e79b96, 0x00e1b3}, /* U+76D6 */ - {0x00e79b97, 0x009390}, /* U+76D7 */ - {0x00e79b9b, 0x0090b7}, /* U+76DB */ - {0x00e79b9c, 0x009f58}, /* U+76DC */ - {0x00e79b9e, 0x00e1b5}, /* U+76DE */ - {0x00e79b9f, 0x0096bf}, /* U+76DF */ - {0x00e79ba1, 0x00e1b6}, /* U+76E1 */ - {0x00e79ba3, 0x008ac4}, /* U+76E3 */ - {0x00e79ba4, 0x0094d5}, /* U+76E4 */ - {0x00e79ba5, 0x00e1b7}, /* U+76E5 */ - {0x00e79ba6, 0x00ece9}, /* U+76E6 [2000] */ - {0x00e79ba7, 0x00e1b8}, /* U+76E7 */ - {0x00e79ba8, 0x00f698}, /* U+76E8 [2000] */ - {0x00e79baa, 0x00e1b9}, /* U+76EA */ - {0x00e79bac, 0x00f699}, /* U+76EC [2000] */ - {0x00e79bae, 0x0096da}, /* U+76EE */ - {0x00e79bb1, 0x00ecea}, /* U+76F1 [2000] */ - {0x00e79bb2, 0x0096d3}, /* U+76F2 */ - {0x00e79bb4, 0x0092bc}, /* U+76F4 */ - {0x00e79bb8, 0x00918a}, /* U+76F8 */ - {0x00e79bbb, 0x00e1bb}, /* U+76FB */ - {0x00e79bbc, 0x00eceb}, /* U+76FC [2000] */ - {0x00e79bbe, 0x008f82}, /* U+76FE */ - {0x00e79c81, 0x008fc8}, /* U+7701 */ - {0x00e79c84, 0x00e1be}, /* U+7704 */ - {0x00e79c87, 0x00e1bd}, /* U+7707 */ - {0x00e79c88, 0x00e1bc}, /* U+7708 */ - {0x00e79c89, 0x0094fb}, /* U+7709 */ - {0x00e79c8a, 0x00ecec}, /* U+770A [2000] */ - {0x00e79c8b, 0x008ac5}, /* U+770B */ - {0x00e79c8c, 0x008ca7}, /* U+770C */ - {0x00e79c97, 0x00f69b}, /* U+7717 [2000] */ - {0x00e79c99, 0x00eced}, /* U+7719 [2000] */ - {0x00e79c9a, 0x00f69c}, /* U+771A [2000] */ - {0x00e79c9b, 0x00e1c4}, /* U+771B */ - {0x00e79c9e, 0x00e1c1}, /* U+771E */ - {0x00e79c9f, 0x00905e}, /* U+771F */ - {0x00e79ca0, 0x0096b0}, /* U+7720 */ - {0x00e79ca4, 0x00e1c0}, /* U+7724 */ - {0x00e79ca5, 0x00e1c2}, /* U+7725 */ - {0x00e79ca6, 0x00e1c3}, /* U+7726 */ - {0x00e79ca9, 0x00e1bf}, /* U+7729 */ - {0x00e79cad, 0x00f69d}, /* U+772D [2000] */ - {0x00e79cb4, 0x00ecee}, /* U+7734 [2000] */ - {0x00e79cb5, 0x00f69e}, /* U+7735 [2000] */ - {0x00e79cb6, 0x00ecef}, /* U+7736 [2000] */ - {0x00e79cb7, 0x00e1c5}, /* U+7737 */ - {0x00e79cb8, 0x00e1c6}, /* U+7738 */ - {0x00e79cba, 0x0092ad}, /* U+773A */ - {0x00e79cbc, 0x008ae1}, /* U+773C */ - {0x00e79d80, 0x009285}, /* U+7740 */ - {0x00e79d86, 0x00ecf0}, /* U+7746 [2000] */ - {0x00e79d87, 0x00e1c7}, /* U+7747 */ - {0x00e79d8d, 0x00ecf1}, /* U+774D [2000] */ - {0x00e79d8e, 0x00ecf2}, /* U+774E [2000] */ - {0x00e79d98, 0x00f6a3}, /* U+7758 [2000] */ - {0x00e79d9a, 0x00e1c8}, /* U+775A */ - {0x00e79d9b, 0x00e1cb}, /* U+775B */ - {0x00e79d9c, 0x00ecf3}, /* U+775C [2000] */ - {0x00e79d9f, 0x00ecf4}, /* U+775F [2000] */ - {0x00e79da0, 0x00f6a4}, /* U+7760 [2000] */ - {0x00e79da1, 0x009087}, /* U+7761 */ - {0x00e79da2, 0x00ecf5}, /* U+7762 [2000] */ - {0x00e79da3, 0x0093c2}, /* U+7763 */ - {0x00e79da5, 0x00e1cc}, /* U+7765 */ - {0x00e79da6, 0x009672}, /* U+7766 */ - {0x00e79da8, 0x00e1c9}, /* U+7768 */ - {0x00e79daa, 0x00f6a5}, /* U+776A [2000] */ - {0x00e79dab, 0x00e1ca}, /* U+776B */ - {0x00e79db2, 0x00f6a7}, /* U+7772 [2000] */ - {0x00e79db9, 0x00e1cf}, /* U+7779 */ - {0x00e79dba, 0x00ecf6}, /* U+777A [2000] */ - {0x00e79dbc, 0x00f6a8}, /* U+777C [2000] */ - {0x00e79dbd, 0x00f6a9}, /* U+777D [2000] */ - {0x00e79dbe, 0x00e1ce}, /* U+777E */ - {0x00e79dbf, 0x00e1cd}, /* U+777F */ - {0x00e79e80, 0x00ecf7}, /* U+7780 [2000] */ - {0x00e79e8b, 0x00e1d1}, /* U+778B */ - {0x00e79e8e, 0x00e1d0}, /* U+778E */ - {0x00e79e91, 0x00e1d2}, /* U+7791 */ - {0x00e79e94, 0x00ecf8}, /* U+7794 [2000] */ - {0x00e79e9a, 0x00f6ac}, /* U+779A [2000] */ - {0x00e79e9e, 0x00e1d4}, /* U+779E */ - {0x00e79e9f, 0x00f6ad}, /* U+779F [2000] */ - {0x00e79ea0, 0x00e1d3}, /* U+77A0 */ - {0x00e79ea2, 0x00f6ae}, /* U+77A2 [2000] */ - {0x00e79ea4, 0x00f6af}, /* U+77A4 [2000] */ - {0x00e79ea5, 0x0095cb}, /* U+77A5 */ - {0x00e79ea9, 0x00f6b0}, /* U+77A9 [2000] */ - {0x00e79eaa, 0x00ecf9}, /* U+77AA [2000] */ - {0x00e79eac, 0x008f75}, /* U+77AC */ - {0x00e79ead, 0x0097c4}, /* U+77AD */ - {0x00e79eb0, 0x00e1d5}, /* U+77B0 */ - {0x00e79eb3, 0x0093b5}, /* U+77B3 */ - {0x00e79eb6, 0x00e1d6}, /* U+77B6 */ - {0x00e79eb9, 0x00e1d7}, /* U+77B9 */ - {0x00e79ebb, 0x00e1db}, /* U+77BB */ - {0x00e79ebc, 0x00e1d9}, /* U+77BC */ - {0x00e79ebd, 0x00e1da}, /* U+77BD */ - {0x00e79ebf, 0x00e1d8}, /* U+77BF */ - {0x00e79f87, 0x00e1dc}, /* U+77C7 */ - {0x00e79f8d, 0x00e1dd}, /* U+77CD */ - {0x00e79f97, 0x00e1de}, /* U+77D7 */ - {0x00e79f9a, 0x00e1df}, /* U+77DA */ - {0x00e79f9b, 0x0096b5}, /* U+77DB */ - {0x00e79f9c, 0x00e1e0}, /* U+77DC */ - {0x00e79f9e, 0x00f6b1}, /* U+77DE [2000] */ - {0x00e79f9f, 0x00f6b2}, /* U+77DF [2000] */ - {0x00e79fa0, 0x00ecfa}, /* U+77E0 [2000] */ - {0x00e79fa2, 0x0096ee}, /* U+77E2 */ - {0x00e79fa3, 0x00e1e1}, /* U+77E3 */ - {0x00e79fa4, 0x00f6b3}, /* U+77E4 [2000] */ - {0x00e79fa5, 0x00926d}, /* U+77E5 */ - {0x00e79fa6, 0x00f6b4}, /* U+77E6 [2000] */ - {0x00e79fa7, 0x00948a}, /* U+77E7 */ - {0x00e79fa9, 0x008be9}, /* U+77E9 */ - {0x00e79faa, 0x00f6b5}, /* U+77EA [2000] */ - {0x00e79fac, 0x00f6b6}, /* U+77EC [2000] */ - {0x00e79fad, 0x00925a}, /* U+77ED */ - {0x00e79fae, 0x00e1e2}, /* U+77EE */ - {0x00e79faf, 0x008bb8}, /* U+77EF */ - {0x00e79fb0, 0x00f6b8}, /* U+77F0 [2000] */ - {0x00e79fb3, 0x0090ce}, /* U+77F3 */ - {0x00e79fb4, 0x00f6b9}, /* U+77F4 [2000] */ - {0x00e79fbb, 0x00f6ba}, /* U+77FB [2000] */ - {0x00e79fbc, 0x00e1e3}, /* U+77FC */ - {0x00e7a082, 0x008dbb}, /* U+7802 */ - {0x00e7a085, 0x00f6bc}, /* U+7805 [2000] */ - {0x00e7a086, 0x00f6bd}, /* U+7806 [2000] */ - {0x00e7a089, 0x00f6be}, /* U+7809 [2000] */ - {0x00e7a08c, 0x00e1e4}, /* U+780C */ - {0x00e7a08d, 0x00f6bf}, /* U+780D [2000] */ - {0x00e7a092, 0x00e1e5}, /* U+7812 */ - {0x00e7a094, 0x008ca4}, /* U+7814 */ - {0x00e7a095, 0x008dd3}, /* U+7815 */ - {0x00e7a099, 0x00f6c0}, /* U+7819 [2000] */ - {0x00e7a0a0, 0x00e1e7}, /* U+7820 */ - {0x00e7a0a1, 0x00f6c1}, /* U+7821 [2000] */ - {0x00e7a0a5, 0x009375}, /* U+7825 */ - {0x00e7a0a6, 0x008dd4}, /* U+7826 */ - {0x00e7a0a7, 0x008b6d}, /* U+7827 */ - {0x00e7a0ac, 0x00f6c2}, /* U+782C [2000] */ - {0x00e7a0ad, 0x00ecfb}, /* U+782D [2000] */ - {0x00e7a0b2, 0x009643}, /* U+7832 */ - {0x00e7a0b4, 0x00946a}, /* U+7834 */ - {0x00e7a0ba, 0x009376}, /* U+783A */ - {0x00e7a0bf, 0x008d7b}, /* U+783F */ - {0x00e7a183, 0x00ed40}, /* U+7843 [2000] */ - {0x00e7a185, 0x00e1e9}, /* U+7845 */ - {0x00e7a187, 0x00f6c3}, /* U+7847 [2000] */ - {0x00e7a18e, 0x00ed41}, /* U+784E [2000] */ - {0x00e7a18f, 0x00ed42}, /* U+784F [2000] */ - {0x00e7a191, 0x00ed43}, /* U+7851 [2000] */ - {0x00e7a19d, 0x008fc9}, /* U+785D */ - {0x00e7a1a4, 0x00f6c4}, /* U+7864 [2000] */ - {0x00e7a1a8, 0x00ed44}, /* U+7868 [2000] */ - {0x00e7a1aa, 0x00f6c5}, /* U+786A [2000] */ - {0x00e7a1ab, 0x0097b0}, /* U+786B */ - {0x00e7a1ac, 0x008d64}, /* U+786C */ - {0x00e7a1ae, 0x00ed45}, /* U+786E [2000] */ - {0x00e7a1af, 0x008ca5}, /* U+786F */ - {0x00e7a1b2, 0x0094a1}, /* U+7872 */ - {0x00e7a1b4, 0x00e1eb}, /* U+7874 */ - {0x00e7a1bc, 0x00e1ed}, /* U+787C */ - {0x00e7a281, 0x008ce9}, /* U+7881 */ - {0x00e7a286, 0x00e1ec}, /* U+7886 */ - {0x00e7a287, 0x0092f4}, /* U+7887 */ - {0x00e7a28a, 0x00f6c7}, /* U+788A [2000] */ - {0x00e7a28c, 0x00e1ef}, /* U+788C */ - {0x00e7a28d, 0x008a56}, /* U+788D */ - {0x00e7a28e, 0x00e1ea}, /* U+788E */ - {0x00e7a291, 0x0094e8}, /* U+7891 */ - {0x00e7a293, 0x00894f}, /* U+7893 */ - {0x00e7a294, 0x00f6c8}, /* U+7894 [2000] */ - {0x00e7a295, 0x008dea}, /* U+7895 */ - {0x00e7a297, 0x009871}, /* U+7897 */ - {0x00e7a29a, 0x00e1ee}, /* U+789A */ - {0x00e7a29d, 0x00f6ca}, /* U+789D [2000] */ - {0x00e7a29e, 0x00f6cb}, /* U+789E [2000] */ - {0x00e7a29f, 0x00f6cc}, /* U+789F [2000] */ - {0x00e7a2a3, 0x00e1f0}, /* U+78A3 */ - {0x00e7a2a4, 0x00f6c9}, /* U+78A4 [2000] */ - {0x00e7a2a7, 0x0095c9}, /* U+78A7 */ - {0x00e7a2a9, 0x0090d7}, /* U+78A9 */ - {0x00e7a2aa, 0x00e1f2}, /* U+78AA */ - {0x00e7a2ad, 0x00ed49}, /* U+78AD [2000] */ - {0x00e7a2af, 0x00e1f3}, /* U+78AF */ - {0x00e7a2b0, 0x00ed47}, /* U+78B0 [2000] */ - {0x00e7a2b5, 0x00e1f1}, /* U+78B5 */ - {0x00e7a2ba, 0x008a6d}, /* U+78BA */ - {0x00e7a2bb, 0x00f6cd}, /* U+78BB [2000] */ - {0x00e7a2bc, 0x00e1f9}, /* U+78BC */ - {0x00e7a2be, 0x00e1f8}, /* U+78BE */ - {0x00e7a381, 0x008ea5}, /* U+78C1 */ - {0x00e7a385, 0x00e1fa}, /* U+78C5 */ - {0x00e7a386, 0x00e1f5}, /* U+78C6 */ - {0x00e7a388, 0x00f6ce}, /* U+78C8 [2000] */ - {0x00e7a38a, 0x00e1fb}, /* U+78CA */ - {0x00e7a38b, 0x00e1f6}, /* U+78CB */ - {0x00e7a38c, 0x00f6cf}, /* U+78CC [2000] */ - {0x00e7a38e, 0x00f6d0}, /* U+78CE [2000] */ - {0x00e7a390, 0x0094d6}, /* U+78D0 */ - {0x00e7a391, 0x00e1f4}, /* U+78D1 */ - {0x00e7a394, 0x00e1f7}, /* U+78D4 */ - {0x00e7a395, 0x00f6d1}, /* U+78D5 [2000] */ - {0x00e7a39a, 0x00e241}, /* U+78DA */ - {0x00e7a3a0, 0x00f6d2}, /* U+78E0 [2000] */ - {0x00e7a3a1, 0x00f6d3}, /* U+78E1 [2000] */ - {0x00e7a3a4, 0x00ed4a}, /* U+78E4 [2000] */ - {0x00e7a3a6, 0x00f6d4}, /* U+78E6 [2000] */ - {0x00e7a3a7, 0x00e240}, /* U+78E7 */ - {0x00e7a3a8, 0x009681}, /* U+78E8 */ - {0x00e7a3ac, 0x00e1fc}, /* U+78EC */ - {0x00e7a3af, 0x0088e9}, /* U+78EF */ - {0x00e7a3b2, 0x00ed4b}, /* U+78F2 [2000] */ - {0x00e7a3b4, 0x00e243}, /* U+78F4 */ - {0x00e7a3b7, 0x00ed4d}, /* U+78F7 [2000] */ - {0x00e7a3b9, 0x00f6d5}, /* U+78F9 [2000] */ - {0x00e7a3ba, 0x00f6d6}, /* U+78FA [2000] */ - {0x00e7a3bb, 0x00f6d7}, /* U+78FB [2000] */ - {0x00e7a3bd, 0x00e242}, /* U+78FD */ - {0x00e7a3be, 0x00f6d8}, /* U+78FE [2000] */ - {0x00e7a480, 0x00ed4c}, /* U+7900 [2000] */ - {0x00e7a481, 0x008fca}, /* U+7901 */ - {0x00e7a487, 0x00e244}, /* U+7907 */ - {0x00e7a48e, 0x009162}, /* U+790E */ - {0x00e7a490, 0x00f6da}, /* U+7910 [2000] */ - {0x00e7a491, 0x00e246}, /* U+7911 */ - {0x00e7a492, 0x00e245}, /* U+7912 */ - {0x00e7a499, 0x00e247}, /* U+7919 */ - {0x00e7a49b, 0x00f6db}, /* U+791B [2000] */ - {0x00e7a49c, 0x00ed4e}, /* U+791C [2000] */ - {0x00e7a4a5, 0x00f6dd}, /* U+7925 [2000] */ - {0x00e7a4a6, 0x00e1e6}, /* U+7926 */ - {0x00e7a4aa, 0x00e1e8}, /* U+792A */ - {0x00e7a4ab, 0x00e249}, /* U+792B */ - {0x00e7a4ac, 0x00e248}, /* U+792C */ - {0x00e7a4ae, 0x00ed4f}, /* U+792E [2000] */ - {0x00e7a4b0, 0x00f6dc}, /* U+7930 [2000] */ - {0x00e7a4b1, 0x00ed50}, /* U+7931 [2000] */ - {0x00e7a4b4, 0x00ed51}, /* U+7934 [2000] */ - {0x00e7a4ba, 0x008ea6}, /* U+793A */ - {0x00e7a4bb, 0x00f6de}, /* U+793B [2000] */ - {0x00e7a4bc, 0x0097e7}, /* U+793C */ - {0x00e7a4be, 0x008ed0}, /* U+793E */ - {0x00e7a580, 0x00e24a}, /* U+7940 */ - {0x00e7a581, 0x008c56}, /* U+7941 */ - {0x00e7a585, 0x00ed54}, /* U+7945 [2000] */ - {0x00e7a586, 0x00ed55}, /* U+7946 [2000] */ - {0x00e7a587, 0x008b5f}, /* U+7947 */ - {0x00e7a588, 0x008b46}, /* U+7948 */ - {0x00e7a589, 0x008e83}, /* U+7949 */ - {0x00e7a58a, 0x00f6df}, /* U+794A [2000] */ - {0x00e7a590, 0x009753}, /* U+7950 */ - {0x00e7a593, 0x00e250}, /* U+7953 */ - {0x00e7a595, 0x00e24f}, /* U+7955 */ - {0x00e7a596, 0x009163}, /* U+7956 */ - {0x00e7a597, 0x00e24c}, /* U+7957 */ - {0x00e7a598, 0x00f6e0}, /* U+7958 [2000] */ - {0x00e7a59a, 0x00e24e}, /* U+795A */ - {0x00e7a59b, 0x00f6e1}, /* U+795B [2000] */ - {0x00e7a59c, 0x00ed59}, /* U+795C [2000] */ - {0x00e7a59d, 0x008f6a}, /* U+795D */ - {0x00e7a59e, 0x00905f}, /* U+795E */ - {0x00e7a59f, 0x00e24d}, /* U+795F */ - {0x00e7a5a0, 0x00e24b}, /* U+7960 */ - {0x00e7a5a2, 0x009449}, /* U+7962 */ - {0x00e7a5a5, 0x008fcb}, /* U+7965 */ - {0x00e7a5a7, 0x00f6e3}, /* U+7967 [2000] */ - {0x00e7a5a8, 0x00955b}, /* U+7968 */ - {0x00e7a5ad, 0x008dd5}, /* U+796D */ - {0x00e7a5b2, 0x00f6e4}, /* U+7972 [2000] */ - {0x00e7a5b7, 0x009398}, /* U+7977 */ - {0x00e7a5b9, 0x00ed5d}, /* U+7979 [2000] */ - {0x00e7a5ba, 0x00e251}, /* U+797A */ - {0x00e7a5bf, 0x00e252}, /* U+797F */ - {0x00e7a680, 0x00e268}, /* U+7980 */ - {0x00e7a681, 0x008bd6}, /* U+7981 */ - {0x00e7a684, 0x00985c}, /* U+7984 */ - {0x00e7a685, 0x009154}, /* U+7985 */ - {0x00e7a68a, 0x00e253}, /* U+798A */ - {0x00e7a68d, 0x0089d0}, /* U+798D */ - {0x00e7a68e, 0x0092f5}, /* U+798E */ - {0x00e7a68f, 0x00959f}, /* U+798F */ - {0x00e7a694, 0x00f6e5}, /* U+7994 [2000] */ - {0x00e7a695, 0x00f6e6}, /* U+7995 [2000] */ - {0x00e7a696, 0x00f6e7}, /* U+7996 [2000] */ - {0x00e7a698, 0x00ed61}, /* U+7998 [2000] */ - {0x00e7a69b, 0x00f6e8}, /* U+799B [2000] */ - {0x00e7a69d, 0x00e254}, /* U+799D */ - {0x00e7a6a1, 0x00f6e9}, /* U+79A1 [2000] */ - {0x00e7a6a6, 0x008b9a}, /* U+79A6 */ - {0x00e7a6a7, 0x00e255}, /* U+79A7 */ - {0x00e7a6a9, 0x00f6ea}, /* U+79A9 [2000] */ - {0x00e7a6aa, 0x00e257}, /* U+79AA */ - {0x00e7a6ae, 0x00e258}, /* U+79AE */ - {0x00e7a6b0, 0x009448}, /* U+79B0 */ - {0x00e7a6b1, 0x00ed62}, /* U+79B1 [2000] */ - {0x00e7a6b3, 0x00e259}, /* U+79B3 */ - {0x00e7a6b4, 0x00f6eb}, /* U+79B4 [2000] */ - {0x00e7a6b8, 0x00ed63}, /* U+79B8 [2000] */ - {0x00e7a6b9, 0x00e25a}, /* U+79B9 */ - {0x00e7a6ba, 0x00e25b}, /* U+79BA */ - {0x00e7a6bb, 0x00f6ec}, /* U+79BB [2000] */ - {0x00e7a6bd, 0x008bd7}, /* U+79BD */ - {0x00e7a6be, 0x0089d1}, /* U+79BE */ - {0x00e7a6bf, 0x0093c3}, /* U+79BF */ - {0x00e7a780, 0x008f47}, /* U+79C0 */ - {0x00e7a781, 0x008e84}, /* U+79C1 */ - {0x00e7a782, 0x00f6ed}, /* U+79C2 [2000] */ - {0x00e7a787, 0x00f6ee}, /* U+79C7 [2000] */ - {0x00e7a788, 0x00ed64}, /* U+79C8 [2000] */ - {0x00e7a789, 0x00e25c}, /* U+79C9 */ - {0x00e7a78a, 0x00ed65}, /* U+79CA [2000] */ - {0x00e7a78b, 0x008f48}, /* U+79CB */ - {0x00e7a78c, 0x00f6ef}, /* U+79CC [2000] */ - {0x00e7a78d, 0x00f6f0}, /* U+79CD [2000] */ - {0x00e7a791, 0x0089c8}, /* U+79D1 */ - {0x00e7a792, 0x009562}, /* U+79D2 */ - {0x00e7a794, 0x00ed67}, /* U+79D4 [2000] */ - {0x00e7a795, 0x00e25d}, /* U+79D5 */ - {0x00e7a796, 0x00f6f1}, /* U+79D6 [2000] */ - {0x00e7a798, 0x0094e9}, /* U+79D8 */ - {0x00e7a79e, 0x00ed68}, /* U+79DE [2000] */ - {0x00e7a79f, 0x009164}, /* U+79DF */ - {0x00e7a7a1, 0x00e260}, /* U+79E1 */ - {0x00e7a7a3, 0x00e261}, /* U+79E3 */ - {0x00e7a7a4, 0x009489}, /* U+79E4 */ - {0x00e7a7a6, 0x009060}, /* U+79E6 */ - {0x00e7a7a7, 0x00e25e}, /* U+79E7 */ - {0x00e7a7a9, 0x009281}, /* U+79E9 */ - {0x00e7a7ab, 0x00ed69}, /* U+79EB [2000] */ - {0x00e7a7ac, 0x00e25f}, /* U+79EC */ - {0x00e7a7ad, 0x00ed6a}, /* U+79ED [2000] */ - {0x00e7a7b0, 0x008fcc}, /* U+79F0 */ - {0x00e7a7bb, 0x0088da}, /* U+79FB */ - {0x00e7a880, 0x008b48}, /* U+7A00 */ - {0x00e7a883, 0x00ed6b}, /* U+7A03 [2000] */ - {0x00e7a888, 0x00e262}, /* U+7A08 */ - {0x00e7a88a, 0x00f6f6}, /* U+7A0A [2000] */ - {0x00e7a88b, 0x0092f6}, /* U+7A0B */ - {0x00e7a88d, 0x00e263}, /* U+7A0D */ - {0x00e7a88e, 0x0090c5}, /* U+7A0E */ - {0x00e7a891, 0x00f6f7}, /* U+7A11 [2000] */ - {0x00e7a894, 0x0096ab}, /* U+7A14 */ - {0x00e7a895, 0x00f6f8}, /* U+7A15 [2000] */ - {0x00e7a897, 0x009542}, /* U+7A17 */ - {0x00e7a898, 0x00e264}, /* U+7A18 */ - {0x00e7a899, 0x00e265}, /* U+7A19 */ - {0x00e7a89a, 0x009274}, /* U+7A1A */ - {0x00e7a89b, 0x00f6f9}, /* U+7A1B [2000] */ - {0x00e7a89c, 0x0097c5}, /* U+7A1C */ - {0x00e7a89e, 0x00f6fa}, /* U+7A1E [2000] */ - {0x00e7a89f, 0x00e267}, /* U+7A1F */ - {0x00e7a8a0, 0x00e266}, /* U+7A20 */ - {0x00e7a8ad, 0x00f6fc}, /* U+7A2D [2000] */ - {0x00e7a8ae, 0x008eed}, /* U+7A2E */ - {0x00e7a8b1, 0x00e269}, /* U+7A31 */ - {0x00e7a8b2, 0x0088ee}, /* U+7A32 */ - {0x00e7a8b7, 0x00e26c}, /* U+7A37 */ - {0x00e7a8b8, 0x00f740}, /* U+7A38 [2000] */ - {0x00e7a8b9, 0x00ed6d}, /* U+7A39 [2000] */ - {0x00e7a8bb, 0x00e26a}, /* U+7A3B */ - {0x00e7a8bc, 0x0089d2}, /* U+7A3C */ - {0x00e7a8bd, 0x008c6d}, /* U+7A3D */ - {0x00e7a8be, 0x00e26b}, /* U+7A3E */ - {0x00e7a8bf, 0x008d65}, /* U+7A3F */ - {0x00e7a980, 0x008d92}, /* U+7A40 */ - {0x00e7a982, 0x0095e4}, /* U+7A42 */ - {0x00e7a983, 0x00e26d}, /* U+7A43 */ - {0x00e7a986, 0x009673}, /* U+7A46 */ - {0x00e7a987, 0x00f741}, /* U+7A47 [2000] */ - {0x00e7a989, 0x00e26f}, /* U+7A49 */ - {0x00e7a98c, 0x00f742}, /* U+7A4C [2000] */ - {0x00e7a98d, 0x0090cf}, /* U+7A4D */ - {0x00e7a98e, 0x00896e}, /* U+7A4E */ - {0x00e7a98f, 0x0089b8}, /* U+7A4F */ - {0x00e7a990, 0x0088aa}, /* U+7A50 */ - {0x00e7a996, 0x00f743}, /* U+7A56 [2000] */ - {0x00e7a997, 0x00e26e}, /* U+7A57 */ - {0x00e7a999, 0x00f744}, /* U+7A59 [2000] */ - {0x00e7a99c, 0x00f745}, /* U+7A5C [2000] */ - {0x00e7a99d, 0x00ed6e}, /* U+7A5D [2000] */ - {0x00e7a99f, 0x00f746}, /* U+7A5F [2000] */ - {0x00e7a9a0, 0x00f747}, /* U+7A60 [2000] */ - {0x00e7a9a1, 0x00e270}, /* U+7A61 */ - {0x00e7a9a2, 0x00e271}, /* U+7A62 */ - {0x00e7a9a3, 0x008ff5}, /* U+7A63 */ - {0x00e7a9a7, 0x00f748}, /* U+7A67 [2000] */ - {0x00e7a9a9, 0x00e272}, /* U+7A69 */ - {0x00e7a9aa, 0x00f749}, /* U+7A6A [2000] */ - {0x00e7a9ab, 0x008a6e}, /* U+7A6B */ - {0x00e7a9ad, 0x00ed6f}, /* U+7A6D [2000] */ - {0x00e7a9b0, 0x00e274}, /* U+7A70 */ - {0x00e7a9b4, 0x008c8a}, /* U+7A74 */ - {0x00e7a9b5, 0x00f74a}, /* U+7A75 [2000] */ - {0x00e7a9b6, 0x008b86}, /* U+7A76 */ - {0x00e7a9b8, 0x00f74b}, /* U+7A78 [2000] */ - {0x00e7a9b9, 0x00e275}, /* U+7A79 */ - {0x00e7a9ba, 0x008bf3}, /* U+7A7A */ - {0x00e7a9bd, 0x00e276}, /* U+7A7D */ - {0x00e7a9bf, 0x0090fa}, /* U+7A7F */ - {0x00e7aa81, 0x0093cb}, /* U+7A81 */ - {0x00e7aa82, 0x00f74c}, /* U+7A82 [2000] */ - {0x00e7aa83, 0x0090de}, /* U+7A83 */ - {0x00e7aa84, 0x008df3}, /* U+7A84 */ - {0x00e7aa85, 0x00ed71}, /* U+7A85 [2000] */ - {0x00e7aa88, 0x00e277}, /* U+7A88 */ - {0x00e7aa8a, 0x00f74d}, /* U+7A8A [2000] */ - {0x00e7aa90, 0x00f74e}, /* U+7A90 [2000] */ - {0x00e7aa92, 0x009282}, /* U+7A92 */ - {0x00e7aa93, 0x00918b}, /* U+7A93 */ - {0x00e7aa95, 0x00e279}, /* U+7A95 */ - {0x00e7aa96, 0x00e27b}, /* U+7A96 */ - {0x00e7aa97, 0x00e278}, /* U+7A97 */ - {0x00e7aa98, 0x00e27a}, /* U+7A98 */ - {0x00e7aa9f, 0x008c41}, /* U+7A9F */ - {0x00e7aaa0, 0x00ed72}, /* U+7AA0 [2000] */ - {0x00e7aaa3, 0x00f74f}, /* U+7AA3 [2000] */ - {0x00e7aaa9, 0x00e27c}, /* U+7AA9 */ - {0x00e7aaaa, 0x008c45}, /* U+7AAA */ - {0x00e7aaac, 0x00f750}, /* U+7AAC [2000] */ - {0x00e7aaae, 0x008b87}, /* U+7AAE */ - {0x00e7aaaf, 0x009771}, /* U+7AAF */ - {0x00e7aab0, 0x00e27e}, /* U+7AB0 */ - {0x00e7aab3, 0x00ed74}, /* U+7AB3 [2000] */ - {0x00e7aab6, 0x00e280}, /* U+7AB6 */ - {0x00e7aab9, 0x00f753}, /* U+7AB9 [2000] */ - {0x00e7aaba, 0x00894d}, /* U+7ABA */ - {0x00e7aabb, 0x00ed75}, /* U+7ABB [2000] */ - {0x00e7aabc, 0x00f754}, /* U+7ABC [2000] */ - {0x00e7aabe, 0x00f755}, /* U+7ABE [2000] */ - {0x00e7aabf, 0x00e283}, /* U+7ABF */ - {0x00e7ab83, 0x008a96}, /* U+7AC3 */ - {0x00e7ab84, 0x00e282}, /* U+7AC4 */ - {0x00e7ab85, 0x00e281}, /* U+7AC5 */ - {0x00e7ab87, 0x00e285}, /* U+7AC7 */ - {0x00e7ab88, 0x00e27d}, /* U+7AC8 */ - {0x00e7ab8a, 0x00e286}, /* U+7ACA */ - {0x00e7ab8b, 0x0097a7}, /* U+7ACB */ - {0x00e7ab8c, 0x00f757}, /* U+7ACC [2000] */ - {0x00e7ab8d, 0x00e287}, /* U+7ACD */ - {0x00e7ab8e, 0x00ed76}, /* U+7ACE [2000] */ - {0x00e7ab8f, 0x00e288}, /* U+7ACF */ - {0x00e7ab91, 0x00f758}, /* U+7AD1 [2000] */ - {0x00e7ab92, 0x009af2}, /* U+7AD2 */ - {0x00e7ab93, 0x00e28a}, /* U+7AD3 */ - {0x00e7ab95, 0x00e289}, /* U+7AD5 */ - {0x00e7ab99, 0x00e28b}, /* U+7AD9 */ - {0x00e7ab9a, 0x00e28c}, /* U+7ADA */ - {0x00e7ab9c, 0x0097b3}, /* U+7ADC */ - {0x00e7ab9d, 0x00e28d}, /* U+7ADD */ - {0x00e7ab9f, 0x00e8ed}, /* U+7ADF */ - {0x00e7aba0, 0x008fcd}, /* U+7AE0 */ - {0x00e7aba1, 0x00e28e}, /* U+7AE1 */ - {0x00e7aba2, 0x00e28f}, /* U+7AE2 */ - {0x00e7aba3, 0x008f76}, /* U+7AE3 */ - {0x00e7aba5, 0x0093b6}, /* U+7AE5 */ - {0x00e7aba6, 0x00e290}, /* U+7AE6 */ - {0x00e7aba7, 0x00f759}, /* U+7AE7 [2000] */ - {0x00e7aba8, 0x00f75a}, /* U+7AE8 [2000] */ - {0x00e7abaa, 0x009247}, /* U+7AEA */ - {0x00e7abab, 0x00ed77}, /* U+7AEB [2000] */ - {0x00e7abad, 0x00e291}, /* U+7AED */ - {0x00e7abaf, 0x00925b}, /* U+7AEF */ - {0x00e7abb0, 0x00e292}, /* U+7AF0 */ - {0x00e7abb4, 0x00f75b}, /* U+7AF4 [2000] */ - {0x00e7abb6, 0x008ba3}, /* U+7AF6 */ - {0x00e7abb8, 0x00995e}, /* U+7AF8 */ - {0x00e7abb9, 0x00927c}, /* U+7AF9 */ - {0x00e7abba, 0x008eb1}, /* U+7AFA */ - {0x00e7abbd, 0x00ed78}, /* U+7AFD [2000] */ - {0x00e7abbf, 0x008ac6}, /* U+7AFF */ - {0x00e7ac82, 0x00e293}, /* U+7B02 */ - {0x00e7ac84, 0x00e2a0}, /* U+7B04 */ - {0x00e7ac86, 0x00e296}, /* U+7B06 */ - {0x00e7ac87, 0x00f75e}, /* U+7B07 [2000] */ - {0x00e7ac88, 0x008b88}, /* U+7B08 */ - {0x00e7ac8a, 0x00e295}, /* U+7B0A */ - {0x00e7ac8b, 0x00e2a2}, /* U+7B0B */ - {0x00e7ac8f, 0x00e294}, /* U+7B0F */ - {0x00e7ac91, 0x008fce}, /* U+7B11 */ - {0x00e7ac92, 0x00ed79}, /* U+7B12 [2000] */ - {0x00e7ac98, 0x00e298}, /* U+7B18 */ - {0x00e7ac99, 0x00e299}, /* U+7B19 */ - {0x00e7ac9b, 0x00934a}, /* U+7B1B */ - {0x00e7ac9e, 0x00e29a}, /* U+7B1E */ - {0x00e7aca0, 0x008a7d}, /* U+7B20 */ - {0x00e7aca5, 0x009079}, /* U+7B25 */ - {0x00e7aca6, 0x009584}, /* U+7B26 */ - {0x00e7aca7, 0x00f761}, /* U+7B27 [2000] */ - {0x00e7aca8, 0x00e29c}, /* U+7B28 */ - {0x00e7acaa, 0x00f762}, /* U+7B2A [2000] */ - {0x00e7acac, 0x0091e6}, /* U+7B2C */ - {0x00e7acad, 0x00ed7a}, /* U+7B2D [2000] */ - {0x00e7acae, 0x00f763}, /* U+7B2E [2000] */ - {0x00e7acaf, 0x00f764}, /* U+7B2F [2000] */ - {0x00e7acb1, 0x00f765}, /* U+7B31 [2000] */ - {0x00e7acb3, 0x00e297}, /* U+7B33 */ - {0x00e7acb5, 0x00e29b}, /* U+7B35 */ - {0x00e7acb6, 0x00e29d}, /* U+7B36 */ - {0x00e7acb9, 0x008df9}, /* U+7B39 */ - {0x00e7acbb, 0x00ed7b}, /* U+7B3B [2000] */ - {0x00e7acbd, 0x00f760}, /* U+7B3D [2000] */ - {0x00e7ad81, 0x00f769}, /* U+7B41 [2000] */ - {0x00e7ad85, 0x00e2a4}, /* U+7B45 */ - {0x00e7ad86, 0x00954d}, /* U+7B46 */ - {0x00e7ad87, 0x00ed7c}, /* U+7B47 [2000] */ - {0x00e7ad88, 0x0094a4}, /* U+7B48 */ - {0x00e7ad89, 0x009399}, /* U+7B49 */ - {0x00e7ad8b, 0x008bd8}, /* U+7B4B */ - {0x00e7ad8c, 0x00e2a3}, /* U+7B4C */ - {0x00e7ad8d, 0x00e2a1}, /* U+7B4D */ - {0x00e7ad8e, 0x00ed7d}, /* U+7B4E [2000] */ - {0x00e7ad8f, 0x0094b3}, /* U+7B4F */ - {0x00e7ad90, 0x00e29e}, /* U+7B50 */ - {0x00e7ad91, 0x00927d}, /* U+7B51 */ - {0x00e7ad92, 0x00939b}, /* U+7B52 */ - {0x00e7ad94, 0x00939a}, /* U+7B54 */ - {0x00e7ad95, 0x00f76b}, /* U+7B55 [2000] */ - {0x00e7ad96, 0x008df4}, /* U+7B56 */ - {0x00e7ad9d, 0x00e2b6}, /* U+7B5D */ - {0x00e7ada0, 0x00ed7e}, /* U+7B60 [2000] */ - {0x00e7ada4, 0x00f76d}, /* U+7B64 [2000] */ - {0x00e7ada5, 0x00e2a6}, /* U+7B65 */ - {0x00e7ada6, 0x00f76e}, /* U+7B66 [2000] */ - {0x00e7ada7, 0x00e2a8}, /* U+7B67 */ - {0x00e7ada9, 0x00f76f}, /* U+7B69 [2000] */ - {0x00e7adac, 0x00e2ab}, /* U+7B6C */ - {0x00e7adad, 0x00ed80}, /* U+7B6D [2000] */ - {0x00e7adae, 0x00e2ac}, /* U+7B6E */ - {0x00e7adaf, 0x00ed81}, /* U+7B6F [2000] */ - {0x00e7adb0, 0x00e2a9}, /* U+7B70 */ - {0x00e7adb1, 0x00e2aa}, /* U+7B71 */ - {0x00e7adb2, 0x00ed82}, /* U+7B72 [2000] */ - {0x00e7adb3, 0x00f770}, /* U+7B73 [2000] */ - {0x00e7adb4, 0x00e2a7}, /* U+7B74 */ - {0x00e7adb5, 0x00e2a5}, /* U+7B75 */ - {0x00e7adb9, 0x00f76c}, /* U+7B79 [2000] */ - {0x00e7adba, 0x00e29f}, /* U+7B7A */ - {0x00e7adbf, 0x00f768}, /* U+7B7F [2000] */ - {0x00e7ae86, 0x0095cd}, /* U+7B86 */ - {0x00e7ae87, 0x0089d3}, /* U+7B87 */ - {0x00e7ae8b, 0x00e2b3}, /* U+7B8B */ - {0x00e7ae8d, 0x00e2b0}, /* U+7B8D */ - {0x00e7ae8f, 0x00e2b5}, /* U+7B8F */ - {0x00e7ae90, 0x00f773}, /* U+7B90 [2000] */ - {0x00e7ae91, 0x00f774}, /* U+7B91 [2000] */ - {0x00e7ae92, 0x00e2b4}, /* U+7B92 */ - {0x00e7ae94, 0x009493}, /* U+7B94 */ - {0x00e7ae95, 0x0096a5}, /* U+7B95 */ - {0x00e7ae97, 0x008e5a}, /* U+7B97 */ - {0x00e7ae98, 0x00e2ae}, /* U+7B98 */ - {0x00e7ae99, 0x00e2b7}, /* U+7B99 */ - {0x00e7ae9a, 0x00e2b2}, /* U+7B9A */ - {0x00e7ae9b, 0x00f775}, /* U+7B9B [2000] */ - {0x00e7ae9c, 0x00e2b1}, /* U+7B9C */ - {0x00e7ae9d, 0x00e2ad}, /* U+7B9D */ - {0x00e7ae9e, 0x00ed83}, /* U+7B9E [2000] */ - {0x00e7ae9f, 0x00e2af}, /* U+7B9F */ - {0x00e7aea1, 0x008ac7}, /* U+7BA1 */ - {0x00e7aeaa, 0x00925c}, /* U+7BAA */ - {0x00e7aead, 0x0090fb}, /* U+7BAD */ - {0x00e7aeaf, 0x00f777}, /* U+7BAF [2000] */ - {0x00e7aeb1, 0x0094a0}, /* U+7BB1 */ - {0x00e7aeb4, 0x00e2bc}, /* U+7BB4 */ - {0x00e7aeb5, 0x00f778}, /* U+7BB5 [2000] */ - {0x00e7aeb8, 0x0094a2}, /* U+7BB8 */ - {0x00e7aebc, 0x00f779}, /* U+7BBC [2000] */ - {0x00e7af80, 0x0090df}, /* U+7BC0 */ - {0x00e7af81, 0x00e2b9}, /* U+7BC1 */ - {0x00e7af84, 0x0094cd}, /* U+7BC4 */ - {0x00e7af85, 0x00f77a}, /* U+7BC5 [2000] */ - {0x00e7af86, 0x00e2bd}, /* U+7BC6 */ - {0x00e7af87, 0x0095d1}, /* U+7BC7 */ - {0x00e7af89, 0x00927a}, /* U+7BC9 */ - {0x00e7af8a, 0x00f77b}, /* U+7BCA [2000] */ - {0x00e7af8b, 0x00e2b8}, /* U+7BCB */ - {0x00e7af8c, 0x00e2ba}, /* U+7BCC */ - {0x00e7af8f, 0x00e2bb}, /* U+7BCF */ - {0x00e7af94, 0x00f77e}, /* U+7BD4 [2000] */ - {0x00e7af96, 0x00f780}, /* U+7BD6 [2000] */ - {0x00e7af97, 0x00ed85}, /* U+7BD7 [2000] */ - {0x00e7af99, 0x00ed86}, /* U+7BD9 [2000] */ - {0x00e7af9a, 0x00f781}, /* U+7BDA [2000] */ - {0x00e7af9d, 0x00e2be}, /* U+7BDD */ - {0x00e7afa0, 0x008ec2}, /* U+7BE0 */ - {0x00e7afa4, 0x0093c4}, /* U+7BE4 */ - {0x00e7afa5, 0x00e2c3}, /* U+7BE5 */ - {0x00e7afa6, 0x00e2c2}, /* U+7BE6 */ - {0x00e7afa9, 0x00e2bf}, /* U+7BE9 */ - {0x00e7afaa, 0x00f782}, /* U+7BEA [2000] */ - {0x00e7afad, 0x009855}, /* U+7BED */ - {0x00e7afb0, 0x00f783}, /* U+7BF0 [2000] */ - {0x00e7afb3, 0x00e2c8}, /* U+7BF3 */ - {0x00e7afb6, 0x00e2cc}, /* U+7BF6 */ - {0x00e7afb7, 0x00e2c9}, /* U+7BF7 */ - {0x00e7b080, 0x00e2c5}, /* U+7C00 */ - {0x00e7b081, 0x00ed87}, /* U+7C01 [2000] */ - {0x00e7b083, 0x00f784}, /* U+7C03 [2000] */ - {0x00e7b087, 0x00e2c6}, /* U+7C07 */ - {0x00e7b08b, 0x00f785}, /* U+7C0B [2000] */ - {0x00e7b08d, 0x00e2cb}, /* U+7C0D */ - {0x00e7b08e, 0x00f786}, /* U+7C0E [2000] */ - {0x00e7b08f, 0x00f787}, /* U+7C0F [2000] */ - {0x00e7b091, 0x00e2c0}, /* U+7C11 */ - {0x00e7b092, 0x0099d3}, /* U+7C12 */ - {0x00e7b093, 0x00e2c7}, /* U+7C13 */ - {0x00e7b094, 0x00e2c1}, /* U+7C14 */ - {0x00e7b097, 0x00e2ca}, /* U+7C17 */ - {0x00e7b09e, 0x00ed89}, /* U+7C1E [2000] */ - {0x00e7b09f, 0x00e2d0}, /* U+7C1F */ - {0x00e7b0a0, 0x00ed8a}, /* U+7C20 [2000] */ - {0x00e7b0a1, 0x008ac8}, /* U+7C21 */ - {0x00e7b0a3, 0x00e2cd}, /* U+7C23 */ - {0x00e7b0a6, 0x00f788}, /* U+7C26 [2000] */ - {0x00e7b0a7, 0x00e2ce}, /* U+7C27 */ - {0x00e7b0aa, 0x00e2cf}, /* U+7C2A */ - {0x00e7b0ab, 0x00e2d2}, /* U+7C2B */ - {0x00e7b0b1, 0x00ed88}, /* U+7C31 [2000] */ - {0x00e7b0b3, 0x00ed8b}, /* U+7C33 [2000] */ - {0x00e7b0b6, 0x00ed8c}, /* U+7C36 [2000] */ - {0x00e7b0b7, 0x00e2d1}, /* U+7C37 */ - {0x00e7b0b8, 0x0094f4}, /* U+7C38 */ - {0x00e7b0bd, 0x00e2d3}, /* U+7C3D */ - {0x00e7b0be, 0x0097fa}, /* U+7C3E */ - {0x00e7b0bf, 0x0095eb}, /* U+7C3F */ - {0x00e7b180, 0x00e2d8}, /* U+7C40 */ - {0x00e7b183, 0x00e2d5}, /* U+7C43 */ - {0x00e7b185, 0x00f789}, /* U+7C45 [2000] */ - {0x00e7b18a, 0x00f78a}, /* U+7C4A [2000] */ - {0x00e7b18c, 0x00e2d4}, /* U+7C4C */ - {0x00e7b18d, 0x0090d0}, /* U+7C4D */ - {0x00e7b18f, 0x00e2d7}, /* U+7C4F */ - {0x00e7b190, 0x00e2d9}, /* U+7C50 */ - {0x00e7b191, 0x00f78b}, /* U+7C51 [2000] */ - {0x00e7b194, 0x00e2d6}, /* U+7C54 */ - {0x00e7b196, 0x00e2dd}, /* U+7C56 */ - {0x00e7b197, 0x00f78c}, /* U+7C57 [2000] */ - {0x00e7b198, 0x00e2da}, /* U+7C58 */ - {0x00e7b199, 0x00ed8f}, /* U+7C59 [2000] */ - {0x00e7b19e, 0x00f78d}, /* U+7C5E [2000] */ - {0x00e7b19f, 0x00e2db}, /* U+7C5F */ - {0x00e7b1a0, 0x00e2c4}, /* U+7C60 */ - {0x00e7b1a1, 0x00f78e}, /* U+7C61 [2000] */ - {0x00e7b1a4, 0x00e2dc}, /* U+7C64 */ - {0x00e7b1a5, 0x00e2de}, /* U+7C65 */ - {0x00e7b1a9, 0x00f78f}, /* U+7C69 [2000] */ - {0x00e7b1ac, 0x00e2df}, /* U+7C6C */ - {0x00e7b1ad, 0x00ed90}, /* U+7C6D [2000] */ - {0x00e7b1ae, 0x00f790}, /* U+7C6E [2000] */ - {0x00e7b1af, 0x00f791}, /* U+7C6F [2000] */ - {0x00e7b1b0, 0x00f792}, /* U+7C70 [2000] */ - {0x00e7b1b3, 0x0095c4}, /* U+7C73 */ - {0x00e7b1b5, 0x00e2e0}, /* U+7C75 */ - {0x00e7b1b9, 0x00ed91}, /* U+7C79 [2000] */ - {0x00e7b1be, 0x0096e0}, /* U+7C7E */ - {0x00e7b281, 0x008bcc}, /* U+7C81 */ - {0x00e7b282, 0x008c48}, /* U+7C82 */ - {0x00e7b283, 0x00e2e1}, /* U+7C83 */ - {0x00e7b289, 0x0095b2}, /* U+7C89 */ - {0x00e7b28b, 0x009088}, /* U+7C8B */ - {0x00e7b28d, 0x0096ae}, /* U+7C8D */ - {0x00e7b28f, 0x00ed92}, /* U+7C8F [2000] */ - {0x00e7b290, 0x00e2e2}, /* U+7C90 */ - {0x00e7b292, 0x0097b1}, /* U+7C92 */ - {0x00e7b294, 0x00ed93}, /* U+7C94 [2000] */ - {0x00e7b295, 0x009494}, /* U+7C95 */ - {0x00e7b297, 0x009165}, /* U+7C97 */ - {0x00e7b298, 0x009453}, /* U+7C98 */ - {0x00e7b29b, 0x008f6c}, /* U+7C9B */ - {0x00e7b29f, 0x0088be}, /* U+7C9F */ - {0x00e7b2a0, 0x00ed94}, /* U+7CA0 [2000] */ - {0x00e7b2a1, 0x00e2e7}, /* U+7CA1 */ - {0x00e7b2a2, 0x00e2e5}, /* U+7CA2 */ - {0x00e7b2a4, 0x00e2e3}, /* U+7CA4 */ - {0x00e7b2a5, 0x008a9f}, /* U+7CA5 */ - {0x00e7b2a6, 0x00f796}, /* U+7CA6 [2000] */ - {0x00e7b2a7, 0x008fcf}, /* U+7CA7 */ - {0x00e7b2a8, 0x00e2e8}, /* U+7CA8 */ - {0x00e7b2ab, 0x00e2e6}, /* U+7CAB */ - {0x00e7b2ad, 0x00e2e4}, /* U+7CAD */ - {0x00e7b2ae, 0x00e2ec}, /* U+7CAE */ - {0x00e7b2b1, 0x00e2eb}, /* U+7CB1 */ - {0x00e7b2b2, 0x00e2ea}, /* U+7CB2 */ - {0x00e7b2b3, 0x00e2e9}, /* U+7CB3 */ - {0x00e7b2b6, 0x00f798}, /* U+7CB6 [2000] */ - {0x00e7b2b7, 0x00f799}, /* U+7CB7 [2000] */ - {0x00e7b2b9, 0x00e2ed}, /* U+7CB9 */ - {0x00e7b2bc, 0x00ed95}, /* U+7CBC [2000] */ - {0x00e7b2bd, 0x00e2ee}, /* U+7CBD */ - {0x00e7b2be, 0x0090b8}, /* U+7CBE */ - {0x00e7b2bf, 0x00f79a}, /* U+7CBF [2000] */ - {0x00e7b380, 0x00e2ef}, /* U+7CC0 */ - {0x00e7b382, 0x00e2f1}, /* U+7CC2 */ - {0x00e7b384, 0x00f79c}, /* U+7CC4 [2000] */ - {0x00e7b385, 0x00e2f0}, /* U+7CC5 */ - {0x00e7b388, 0x00f79e}, /* U+7CC8 [2000] */ - {0x00e7b38a, 0x008cd0}, /* U+7CCA */ - {0x00e7b38d, 0x00f79f}, /* U+7CCD [2000] */ - {0x00e7b38e, 0x009157}, /* U+7CCE */ - {0x00e7b392, 0x00e2f3}, /* U+7CD2 */ - {0x00e7b395, 0x00ed96}, /* U+7CD5 [2000] */ - {0x00e7b396, 0x00939c}, /* U+7CD6 */ - {0x00e7b397, 0x00f7a1}, /* U+7CD7 [2000] */ - {0x00e7b398, 0x00e2f2}, /* U+7CD8 */ - {0x00e7b399, 0x00ed97}, /* U+7CD9 [2000] */ - {0x00e7b39c, 0x00e2f4}, /* U+7CDC */ - {0x00e7b39d, 0x00ed98}, /* U+7CDD [2000] */ - {0x00e7b39e, 0x0095b3}, /* U+7CDE */ - {0x00e7b39f, 0x00918c}, /* U+7CDF */ - {0x00e7b3a0, 0x008d66}, /* U+7CE0 */ - {0x00e7b3a2, 0x00e2f5}, /* U+7CE2 */ - {0x00e7b3a6, 0x00f7a3}, /* U+7CE6 [2000] */ - {0x00e7b3a7, 0x0097c6}, /* U+7CE7 */ - {0x00e7b3ab, 0x00f7a4}, /* U+7CEB [2000] */ - {0x00e7b3af, 0x00e2f7}, /* U+7CEF */ - {0x00e7b3b2, 0x00e2f8}, /* U+7CF2 */ - {0x00e7b3b4, 0x00e2f9}, /* U+7CF4 */ - {0x00e7b3b5, 0x00f7a6}, /* U+7CF5 [2000] */ - {0x00e7b3b6, 0x00e2fa}, /* U+7CF6 */ - {0x00e7b3b8, 0x008e85}, /* U+7CF8 */ - {0x00e7b3ba, 0x00e2fb}, /* U+7CFA */ - {0x00e7b3bb, 0x008c6e}, /* U+7CFB */ - {0x00e7b3be, 0x008b8a}, /* U+7CFE */ - {0x00e7b480, 0x008b49}, /* U+7D00 */ - {0x00e7b482, 0x00e340}, /* U+7D02 */ - {0x00e7b483, 0x00f7a7}, /* U+7D03 [2000] */ - {0x00e7b484, 0x0096f1}, /* U+7D04 */ - {0x00e7b485, 0x008d67}, /* U+7D05 */ - {0x00e7b486, 0x00e2fc}, /* U+7D06 */ - {0x00e7b487, 0x00ed99}, /* U+7D07 [2000] */ - {0x00e7b488, 0x00ed9a}, /* U+7D08 [2000] */ - {0x00e7b489, 0x00f7a8}, /* U+7D09 [2000] */ - {0x00e7b48a, 0x00e343}, /* U+7D0A */ - {0x00e7b48b, 0x0096e4}, /* U+7D0B */ - {0x00e7b48d, 0x00945b}, /* U+7D0D */ - {0x00e7b490, 0x009552}, /* U+7D10 */ - {0x00e7b492, 0x00f7aa}, /* U+7D12 [2000] */ - {0x00e7b493, 0x00ed9b}, /* U+7D13 [2000] */ - {0x00e7b494, 0x008f83}, /* U+7D14 */ - {0x00e7b495, 0x00e342}, /* U+7D15 */ - {0x00e7b497, 0x008ed1}, /* U+7D17 */ - {0x00e7b498, 0x008d68}, /* U+7D18 */ - {0x00e7b499, 0x008e86}, /* U+7D19 */ - {0x00e7b49a, 0x008b89}, /* U+7D1A */ - {0x00e7b49b, 0x0095b4}, /* U+7D1B */ - {0x00e7b49c, 0x00e341}, /* U+7D1C */ - {0x00e7b49d, 0x00ed9c}, /* U+7D1D [2000] */ - {0x00e7b49e, 0x00f7ab}, /* U+7D1E [2000] */ - {0x00e7b4a0, 0x009166}, /* U+7D20 */ - {0x00e7b4a1, 0x009661}, /* U+7D21 */ - {0x00e7b4a2, 0x008df5}, /* U+7D22 */ - {0x00e7b4a3, 0x00ed9d}, /* U+7D23 [2000] */ - {0x00e7b4ab, 0x008e87}, /* U+7D2B */ - {0x00e7b4ac, 0x0092db}, /* U+7D2C */ - {0x00e7b4ae, 0x00e346}, /* U+7D2E */ - {0x00e7b4af, 0x0097dd}, /* U+7D2F */ - {0x00e7b4b0, 0x008dd7}, /* U+7D30 */ - {0x00e7b4b1, 0x00ed9e}, /* U+7D31 [2000] */ - {0x00e7b4b2, 0x00e347}, /* U+7D32 */ - {0x00e7b4b3, 0x009061}, /* U+7D33 */ - {0x00e7b4b5, 0x00e349}, /* U+7D35 */ - {0x00e7b4b9, 0x008fd0}, /* U+7D39 */ - {0x00e7b4ba, 0x008dae}, /* U+7D3A */ - {0x00e7b4bd, 0x00f7ae}, /* U+7D3D [2000] */ - {0x00e7b4be, 0x00f7af}, /* U+7D3E [2000] */ - {0x00e7b4bf, 0x00e348}, /* U+7D3F */ - {0x00e7b580, 0x00f7b0}, /* U+7D40 [2000] */ - {0x00e7b581, 0x00ed9f}, /* U+7D41 [2000] */ - {0x00e7b582, 0x008f49}, /* U+7D42 */ - {0x00e7b583, 0x008cbc}, /* U+7D43 */ - {0x00e7b584, 0x009167}, /* U+7D44 */ - {0x00e7b585, 0x00e344}, /* U+7D45 */ - {0x00e7b586, 0x00e34a}, /* U+7D46 */ - {0x00e7b587, 0x00f7b1}, /* U+7D47 [2000] */ - {0x00e7b588, 0x00eda0}, /* U+7D48 [2000] */ - {0x00e7b58b, 0x00e345}, /* U+7D4B */ - {0x00e7b58c, 0x008c6f}, /* U+7D4C */ - {0x00e7b58e, 0x00e34d}, /* U+7D4E */ - {0x00e7b58f, 0x00e351}, /* U+7D4F */ - {0x00e7b590, 0x008c8b}, /* U+7D50 */ - {0x00e7b593, 0x00eda1}, /* U+7D53 [2000] */ - {0x00e7b596, 0x00e34c}, /* U+7D56 */ - {0x00e7b599, 0x00f7b5}, /* U+7D59 [2000] */ - {0x00e7b59a, 0x00f7b6}, /* U+7D5A [2000] */ - {0x00e7b59b, 0x00e355}, /* U+7D5B */ - {0x00e7b59c, 0x00eda2}, /* U+7D5C [2000] */ - {0x00e7b59e, 0x008d69}, /* U+7D5E */ - {0x00e7b5a1, 0x00978d}, /* U+7D61 */ - {0x00e7b5a2, 0x0088ba}, /* U+7D62 */ - {0x00e7b5a3, 0x00e352}, /* U+7D63 */ - {0x00e7b5a6, 0x008b8b}, /* U+7D66 */ - {0x00e7b5a8, 0x00e34f}, /* U+7D68 */ - {0x00e7b5aa, 0x00f7b7}, /* U+7D6A [2000] */ - {0x00e7b5ae, 0x00e350}, /* U+7D6E */ - {0x00e7b5b0, 0x00f7b8}, /* U+7D70 [2000] */ - {0x00e7b5b1, 0x00939d}, /* U+7D71 */ - {0x00e7b5b2, 0x00e34e}, /* U+7D72 */ - {0x00e7b5b3, 0x00e34b}, /* U+7D73 */ - {0x00e7b5b5, 0x008a47}, /* U+7D75 */ - {0x00e7b5b6, 0x0090e2}, /* U+7D76 */ - {0x00e7b5b9, 0x008ca6}, /* U+7D79 */ - {0x00e7b5ba, 0x00eda3}, /* U+7D7A [2000] */ - {0x00e7b5bd, 0x00e357}, /* U+7D7D */ - {0x00e7b5bf, 0x00f7ba}, /* U+7D7F [2000] */ - {0x00e7b683, 0x00eda4}, /* U+7D83 [2000] */ - {0x00e7b686, 0x00f7bc}, /* U+7D86 [2000] */ - {0x00e7b688, 0x00f7bd}, /* U+7D88 [2000] */ - {0x00e7b689, 0x00e354}, /* U+7D89 */ - {0x00e7b68b, 0x00eda5}, /* U+7D8B [2000] */ - {0x00e7b68c, 0x00f7be}, /* U+7D8C [2000] */ - {0x00e7b68f, 0x00e356}, /* U+7D8F */ - {0x00e7b693, 0x00e353}, /* U+7D93 */ - {0x00e7b697, 0x00f7bf}, /* U+7D97 [2000] */ - {0x00e7b699, 0x008c70}, /* U+7D99 */ - {0x00e7b69a, 0x0091b1}, /* U+7D9A */ - {0x00e7b69b, 0x00e358}, /* U+7D9B */ - {0x00e7b69c, 0x00918e}, /* U+7D9C */ - {0x00e7b69d, 0x00f7c1}, /* U+7D9D [2000] */ - {0x00e7b69f, 0x00e365}, /* U+7D9F */ - {0x00e7b6a0, 0x00eda6}, /* U+7DA0 [2000] */ - {0x00e7b6a2, 0x00e361}, /* U+7DA2 */ - {0x00e7b6a3, 0x00e35b}, /* U+7DA3 */ - {0x00e7b6a6, 0x00eda7}, /* U+7DA6 [2000] */ - {0x00e7b6a7, 0x00f7c2}, /* U+7DA7 [2000] */ - {0x00e7b6aa, 0x00f7c3}, /* U+7DAA [2000] */ - {0x00e7b6ab, 0x00e35f}, /* U+7DAB */ - {0x00e7b6ac, 0x008ef8}, /* U+7DAC */ - {0x00e7b6ad, 0x0088db}, /* U+7DAD */ - {0x00e7b6ae, 0x00e35a}, /* U+7DAE */ - {0x00e7b6af, 0x00e362}, /* U+7DAF */ - {0x00e7b6b0, 0x00e366}, /* U+7DB0 */ - {0x00e7b6b1, 0x008d6a}, /* U+7DB1 */ - {0x00e7b6b2, 0x0096d4}, /* U+7DB2 */ - {0x00e7b6b4, 0x0092d4}, /* U+7DB4 */ - {0x00e7b6b5, 0x00e35c}, /* U+7DB5 */ - {0x00e7b6b6, 0x00f7c4}, /* U+7DB6 [2000] */ - {0x00e7b6b7, 0x00f7c5}, /* U+7DB7 [2000] */ - {0x00e7b6b8, 0x00e364}, /* U+7DB8 */ - {0x00e7b6ba, 0x00e359}, /* U+7DBA */ - {0x00e7b6bb, 0x00925d}, /* U+7DBB */ - {0x00e7b6bd, 0x00e35e}, /* U+7DBD */ - {0x00e7b6be, 0x0088bb}, /* U+7DBE */ - {0x00e7b6bf, 0x0096c8}, /* U+7DBF */ - {0x00e7b780, 0x00f7c6}, /* U+7DC0 [2000] */ - {0x00e7b782, 0x00eda8}, /* U+7DC2 [2000] */ - {0x00e7b787, 0x00e35d}, /* U+7DC7 */ - {0x00e7b78a, 0x008bd9}, /* U+7DCA */ - {0x00e7b78b, 0x0094ea}, /* U+7DCB */ - {0x00e7b78c, 0x00eda9}, /* U+7DCC [2000] */ - {0x00e7b78f, 0x00918d}, /* U+7DCF */ - {0x00e7b791, 0x0097ce}, /* U+7DD1 */ - {0x00e7b792, 0x008f8f}, /* U+7DD2 */ - {0x00e7b795, 0x00e38e}, /* U+7DD5 */ - {0x00e7b796, 0x00edaa}, /* U+7DD6 [2000] */ - {0x00e7b797, 0x00f7c7}, /* U+7DD7 [2000] */ - {0x00e7b798, 0x00e367}, /* U+7DD8 */ - {0x00e7b799, 0x00f7c8}, /* U+7DD9 [2000] */ - {0x00e7b79a, 0x0090fc}, /* U+7DDA */ - {0x00e7b79c, 0x00e363}, /* U+7DDC */ - {0x00e7b79d, 0x00e368}, /* U+7DDD */ - {0x00e7b79e, 0x00e36a}, /* U+7DDE */ - {0x00e7b7a0, 0x0092f7}, /* U+7DE0 */ - {0x00e7b7a1, 0x00e36d}, /* U+7DE1 */ - {0x00e7b7a3, 0x00edab}, /* U+7DE3 [2000] */ - {0x00e7b7a4, 0x00e369}, /* U+7DE4 */ - {0x00e7b7a6, 0x00f7c9}, /* U+7DE6 [2000] */ - {0x00e7b7a8, 0x0095d2}, /* U+7DE8 */ - {0x00e7b7a9, 0x008ac9}, /* U+7DE9 */ - {0x00e7b7ac, 0x0096c9}, /* U+7DEC */ - {0x00e7b7af, 0x0088dc}, /* U+7DEF */ - {0x00e7b7b1, 0x00f7ca}, /* U+7DF1 [2000] */ - {0x00e7b7b2, 0x00e36c}, /* U+7DF2 */ - {0x00e7b7b4, 0x0097fb}, /* U+7DF4 */ - {0x00e7b7b9, 0x00f7cb}, /* U+7DF9 [2000] */ - {0x00e7b7bb, 0x00e36b}, /* U+7DFB */ - {0x00e7b881, 0x00898f}, /* U+7E01 */ - {0x00e7b884, 0x0093ea}, /* U+7E04 */ - {0x00e7b885, 0x00e36e}, /* U+7E05 */ - {0x00e7b888, 0x00edae}, /* U+7E08 [2000] */ - {0x00e7b889, 0x00e375}, /* U+7E09 */ - {0x00e7b88a, 0x00e36f}, /* U+7E0A */ - {0x00e7b88b, 0x00e376}, /* U+7E0B */ - {0x00e7b890, 0x00f7cf}, /* U+7E10 [2000] */ - {0x00e7b891, 0x00edaf}, /* U+7E11 [2000] */ - {0x00e7b892, 0x00e372}, /* U+7E12 */ - {0x00e7b895, 0x00edb0}, /* U+7E15 [2000] */ - {0x00e7b897, 0x00f7d0}, /* U+7E17 [2000] */ - {0x00e7b89b, 0x00949b}, /* U+7E1B */ - {0x00e7b89d, 0x00f7d1}, /* U+7E1D [2000] */ - {0x00e7b89e, 0x008ec8}, /* U+7E1E */ - {0x00e7b89f, 0x00e374}, /* U+7E1F */ - {0x00e7b8a0, 0x00f7d2}, /* U+7E20 [2000] */ - {0x00e7b8a1, 0x00e371}, /* U+7E21 */ - {0x00e7b8a2, 0x00e377}, /* U+7E22 */ - {0x00e7b8a3, 0x00e370}, /* U+7E23 */ - {0x00e7b8a6, 0x008f63}, /* U+7E26 */ - {0x00e7b8a7, 0x00f7d3}, /* U+7E27 [2000] */ - {0x00e7b8a8, 0x00edad}, /* U+7E28 [2000] */ - {0x00e7b8ab, 0x009644}, /* U+7E2B */ - {0x00e7b8ac, 0x00f7d4}, /* U+7E2C [2000] */ - {0x00e7b8ae, 0x008f6b}, /* U+7E2E */ - {0x00e7b8b1, 0x00e373}, /* U+7E31 */ - {0x00e7b8b2, 0x00e380}, /* U+7E32 */ - {0x00e7b8b5, 0x00e37b}, /* U+7E35 */ - {0x00e7b8b7, 0x00e37e}, /* U+7E37 */ - {0x00e7b8b9, 0x00e37c}, /* U+7E39 */ - {0x00e7b8ba, 0x00e381}, /* U+7E3A */ - {0x00e7b8bb, 0x00e37a}, /* U+7E3B */ - {0x00e7b8bd, 0x00e360}, /* U+7E3D */ - {0x00e7b8be, 0x0090d1}, /* U+7E3E */ - {0x00e7b981, 0x0094c9}, /* U+7E41 */ - {0x00e7b983, 0x00e37d}, /* U+7E43 */ - {0x00e7b985, 0x00f7d5}, /* U+7E45 [2000] */ - {0x00e7b986, 0x00e378}, /* U+7E46 */ - {0x00e7b987, 0x00edb2}, /* U+7E47 [2000] */ - {0x00e7b98a, 0x009140}, /* U+7E4A */ - {0x00e7b98b, 0x008c71}, /* U+7E4B */ - {0x00e7b98d, 0x008f4a}, /* U+7E4D */ - {0x00e7b992, 0x00edb3}, /* U+7E52 [2000] */ - {0x00e7b994, 0x009044}, /* U+7E54 */ - {0x00e7b995, 0x009155}, /* U+7E55 */ - {0x00e7b996, 0x00e384}, /* U+7E56 */ - {0x00e7b999, 0x00e386}, /* U+7E59 */ - {0x00e7b99a, 0x00e387}, /* U+7E5A */ - {0x00e7b99d, 0x00e383}, /* U+7E5D */ - {0x00e7b99e, 0x00e385}, /* U+7E5E */ - {0x00e7b9a1, 0x00edb4}, /* U+7E61 [2000] */ - {0x00e7b9a6, 0x00e379}, /* U+7E66 */ - {0x00e7b9a7, 0x00e382}, /* U+7E67 */ - {0x00e7b9a9, 0x00e38a}, /* U+7E69 */ - {0x00e7b9aa, 0x00e389}, /* U+7E6A */ - {0x00e7b9ab, 0x00effc}, /* U+7E6B [2004] */ - {0x00e7b9ad, 0x00969a}, /* U+7E6D */ - {0x00e7b9b0, 0x008c4a}, /* U+7E70 */ - {0x00e7b9b3, 0x00f7d6}, /* U+7E73 [2000] */ - {0x00e7b9b5, 0x00f7d7}, /* U+7E75 [2000] */ - {0x00e7b9b9, 0x00e388}, /* U+7E79 */ - {0x00e7b9bb, 0x00e38c}, /* U+7E7B */ - {0x00e7b9bc, 0x00e38b}, /* U+7E7C */ - {0x00e7b9bd, 0x00e38f}, /* U+7E7D */ - {0x00e7b9be, 0x00f7d8}, /* U+7E7E [2000] */ - {0x00e7b9bf, 0x00e391}, /* U+7E7F */ - {0x00e7ba82, 0x008e5b}, /* U+7E82 */ - {0x00e7ba83, 0x00e38d}, /* U+7E83 */ - {0x00e7ba86, 0x00f7d9}, /* U+7E86 [2000] */ - {0x00e7ba87, 0x00f7da}, /* U+7E87 [2000] */ - {0x00e7ba88, 0x00e392}, /* U+7E88 */ - {0x00e7ba89, 0x00e393}, /* U+7E89 */ - {0x00e7ba8a, 0x00edb5}, /* U+7E8A [2000] */ - {0x00e7ba8c, 0x00e394}, /* U+7E8C */ - {0x00e7ba8d, 0x00edb6}, /* U+7E8D [2000] */ - {0x00e7ba8e, 0x00e39a}, /* U+7E8E */ - {0x00e7ba8f, 0x00935a}, /* U+7E8F */ - {0x00e7ba90, 0x00e396}, /* U+7E90 */ - {0x00e7ba91, 0x00f7dc}, /* U+7E91 [2000] */ - {0x00e7ba92, 0x00e395}, /* U+7E92 */ - {0x00e7ba93, 0x00e397}, /* U+7E93 */ - {0x00e7ba94, 0x00e398}, /* U+7E94 */ - {0x00e7ba96, 0x00e399}, /* U+7E96 */ - {0x00e7ba98, 0x00f7dd}, /* U+7E98 [2000] */ - {0x00e7ba9a, 0x00f7de}, /* U+7E9A [2000] */ - {0x00e7ba9b, 0x00e39b}, /* U+7E9B */ - {0x00e7ba9c, 0x00e39c}, /* U+7E9C */ - {0x00e7bcb6, 0x008aca}, /* U+7F36 */ - {0x00e7bcb8, 0x00e39d}, /* U+7F38 */ - {0x00e7bcba, 0x00e39e}, /* U+7F3A */ - {0x00e7bcbb, 0x00f7e1}, /* U+7F3B [2000] */ - {0x00e7bcbc, 0x00f7e0}, /* U+7F3C [2000] */ - {0x00e7bcbe, 0x00f7e2}, /* U+7F3E [2000] */ - {0x00e7bd83, 0x00f7e3}, /* U+7F43 [2000] */ - {0x00e7bd84, 0x00f7e4}, /* U+7F44 [2000] */ - {0x00e7bd85, 0x00e39f}, /* U+7F45 */ - {0x00e7bd87, 0x00edb7}, /* U+7F47 [2000] */ - {0x00e7bd8c, 0x00e3a0}, /* U+7F4C */ - {0x00e7bd8d, 0x00e3a1}, /* U+7F4D */ - {0x00e7bd8e, 0x00e3a2}, /* U+7F4E */ - {0x00e7bd8f, 0x00f7e5}, /* U+7F4F [2000] */ - {0x00e7bd90, 0x00e3a3}, /* U+7F50 */ - {0x00e7bd91, 0x00e3a4}, /* U+7F51 */ - {0x00e7bd92, 0x00f7e8}, /* U+7F52 [2000] */ - {0x00e7bd94, 0x00e3a6}, /* U+7F54 */ - {0x00e7bd95, 0x00e3a5}, /* U+7F55 */ - {0x00e7bd98, 0x00e3a7}, /* U+7F58 */ - {0x00e7bd9f, 0x00e3a8}, /* U+7F5F */ - {0x00e7bda0, 0x00e3a9}, /* U+7F60 */ - {0x00e7bda1, 0x00f7ea}, /* U+7F61 [2000] */ - {0x00e7bda3, 0x00f7eb}, /* U+7F63 [2000] */ - {0x00e7bda4, 0x00f7ec}, /* U+7F64 [2000] */ - {0x00e7bda7, 0x00e3ac}, /* U+7F67 */ - {0x00e7bda8, 0x00e3aa}, /* U+7F68 */ - {0x00e7bda9, 0x00e3ab}, /* U+7F69 */ - {0x00e7bdaa, 0x008ddf}, /* U+7F6A */ - {0x00e7bdab, 0x008c72}, /* U+7F6B */ - {0x00e7bdad, 0x00f7ed}, /* U+7F6D [2000] */ - {0x00e7bdae, 0x009275}, /* U+7F6E */ - {0x00e7bdb0, 0x0094b1}, /* U+7F70 */ - {0x00e7bdb2, 0x008f90}, /* U+7F72 */ - {0x00e7bdb5, 0x00946c}, /* U+7F75 */ - {0x00e7bdb7, 0x0094eb}, /* U+7F77 */ - {0x00e7bdb8, 0x00e3ad}, /* U+7F78 */ - {0x00e7bdb9, 0x009ceb}, /* U+7F79 */ - {0x00e7bdbd, 0x00f7ee}, /* U+7F7D [2000] */ - {0x00e7bdbe, 0x00f7ef}, /* U+7F7E [2000] */ - {0x00e7be82, 0x00e3ae}, /* U+7F82 */ - {0x00e7be83, 0x00e3b0}, /* U+7F83 */ - {0x00e7be85, 0x009785}, /* U+7F85 */ - {0x00e7be86, 0x00e3af}, /* U+7F86 */ - {0x00e7be87, 0x00e3b2}, /* U+7F87 */ - {0x00e7be88, 0x00e3b1}, /* U+7F88 */ - {0x00e7be8a, 0x009772}, /* U+7F8A */ - {0x00e7be8c, 0x00e3b3}, /* U+7F8C */ - {0x00e7be8e, 0x0094fc}, /* U+7F8E */ - {0x00e7be90, 0x00f7f1}, /* U+7F90 [2000] */ - {0x00e7be91, 0x00edb9}, /* U+7F91 [2000] */ - {0x00e7be94, 0x00e3b4}, /* U+7F94 */ - {0x00e7be96, 0x00f7f4}, /* U+7F96 [2000] */ - {0x00e7be97, 0x00edba}, /* U+7F97 [2000] */ - {0x00e7be9a, 0x00e3b7}, /* U+7F9A */ - {0x00e7be9c, 0x00f7f5}, /* U+7F9C [2000] */ - {0x00e7be9d, 0x00e3b6}, /* U+7F9D */ - {0x00e7be9e, 0x00e3b5}, /* U+7F9E */ - {0x00e7bea3, 0x00e3b8}, /* U+7FA3 */ - {0x00e7bea4, 0x008c51}, /* U+7FA4 */ - {0x00e7bea8, 0x009141}, /* U+7FA8 */ - {0x00e7bea9, 0x008b60}, /* U+7FA9 */ - {0x00e7bead, 0x00f7f6}, /* U+7FAD [2000] */ - {0x00e7beae, 0x00e3bc}, /* U+7FAE */ - {0x00e7beaf, 0x00e3b9}, /* U+7FAF */ - {0x00e7beb2, 0x00e3ba}, /* U+7FB2 */ - {0x00e7beb6, 0x00e3bd}, /* U+7FB6 */ - {0x00e7beb8, 0x00e3be}, /* U+7FB8 */ - {0x00e7beb9, 0x00e3bb}, /* U+7FB9 */ - {0x00e7bebd, 0x008948}, /* U+7FBD */ - {0x00e7bebf, 0x00edbb}, /* U+7FBF [2000] */ - {0x00e7bf81, 0x0089a5}, /* U+7FC1 */ - {0x00e7bf83, 0x00f7f8}, /* U+7FC3 [2000] */ - {0x00e7bf85, 0x00e3c0}, /* U+7FC5 */ - {0x00e7bf86, 0x00e3c1}, /* U+7FC6 */ - {0x00e7bf8a, 0x00e3c2}, /* U+7FCA */ - {0x00e7bf8c, 0x009782}, /* U+7FCC */ - {0x00e7bf8e, 0x00edbc}, /* U+7FCE [2000] */ - {0x00e7bf8f, 0x00f7f9}, /* U+7FCF [2000] */ - {0x00e7bf92, 0x008f4b}, /* U+7FD2 */ - {0x00e7bf94, 0x00e3c4}, /* U+7FD4 */ - {0x00e7bf95, 0x00e3c3}, /* U+7FD5 */ - {0x00e7bf9b, 0x00edbd}, /* U+7FDB [2000] */ - {0x00e7bf9f, 0x00edbe}, /* U+7FDF [2000] */ - {0x00e7bfa0, 0x009089}, /* U+7FE0 */ - {0x00e7bfa1, 0x00e3c5}, /* U+7FE1 */ - {0x00e7bfa3, 0x00f7fa}, /* U+7FE3 [2000] */ - {0x00e7bfa5, 0x00f7fb}, /* U+7FE5 [2000] */ - {0x00e7bfa6, 0x00e3c6}, /* U+7FE6 */ - {0x00e7bfa9, 0x00e3c7}, /* U+7FE9 */ - {0x00e7bfab, 0x008ae3}, /* U+7FEB */ - {0x00e7bfac, 0x00edbf}, /* U+7FEC [2000] */ - {0x00e7bfae, 0x00edc0}, /* U+7FEE [2000] */ - {0x00e7bfaf, 0x00f7fc}, /* U+7FEF [2000] */ - {0x00e7bfb0, 0x008acb}, /* U+7FF0 */ - {0x00e7bfb2, 0x00f840}, /* U+7FF2 [2000] */ - {0x00e7bfb3, 0x00e3c8}, /* U+7FF3 */ - {0x00e7bfb9, 0x00e3c9}, /* U+7FF9 */ - {0x00e7bfba, 0x00edc1}, /* U+7FFA [2000] */ - {0x00e7bfbb, 0x00967c}, /* U+7FFB */ - {0x00e7bfbc, 0x009783}, /* U+7FFC */ - {0x00e88080, 0x009773}, /* U+8000 */ - {0x00e88081, 0x009856}, /* U+8001 */ - {0x00e88082, 0x00f841}, /* U+8002 [2000] */ - {0x00e88083, 0x008d6c}, /* U+8003 */ - {0x00e88084, 0x00e3cc}, /* U+8004 */ - {0x00e88085, 0x008ed2}, /* U+8005 */ - {0x00e88086, 0x00e3cb}, /* U+8006 */ - {0x00e88088, 0x00f843}, /* U+8008 [2000] */ - {0x00e8808a, 0x00f842}, /* U+800A [2000] */ - {0x00e8808b, 0x00e3cd}, /* U+800B */ - {0x00e8808c, 0x008ea7}, /* U+800C */ - {0x00e8808e, 0x00f844}, /* U+800E [2000] */ - {0x00e88090, 0x0091cf}, /* U+8010 */ - {0x00e88091, 0x00f845}, /* U+8011 [2000] */ - {0x00e88092, 0x00e3ce}, /* U+8012 */ - {0x00e88094, 0x00edc3}, /* U+8014 [2000] */ - {0x00e88095, 0x008d6b}, /* U+8015 */ - {0x00e88096, 0x00f846}, /* U+8016 [2000] */ - {0x00e88097, 0x0096d5}, /* U+8017 */ - {0x00e88098, 0x00e3cf}, /* U+8018 */ - {0x00e88099, 0x00e3d0}, /* U+8019 */ - {0x00e8809c, 0x00e3d1}, /* U+801C */ - {0x00e880a1, 0x00e3d2}, /* U+8021 */ - {0x00e880a4, 0x00f847}, /* U+8024 [2000] */ - {0x00e880a6, 0x00edc4}, /* U+8026 [2000] */ - {0x00e880a8, 0x00e3d3}, /* U+8028 */ - {0x00e880ac, 0x00f848}, /* U+802C [2000] */ - {0x00e880b0, 0x00f849}, /* U+8030 [2000] */ - {0x00e880b3, 0x008ea8}, /* U+8033 */ - {0x00e880b5, 0x00edc5}, /* U+8035 [2000] */ - {0x00e880b6, 0x0096eb}, /* U+8036 */ - {0x00e880b7, 0x00edc6}, /* U+8037 [2000] */ - {0x00e880bb, 0x00e3d5}, /* U+803B */ - {0x00e880bc, 0x00edc7}, /* U+803C [2000] */ - {0x00e880bd, 0x00925e}, /* U+803D */ - {0x00e880bf, 0x00e3d4}, /* U+803F */ - {0x00e88183, 0x00f84a}, /* U+8043 [2000] */ - {0x00e88186, 0x00e3d7}, /* U+8046 */ - {0x00e8818a, 0x00e3d6}, /* U+804A */ - {0x00e88192, 0x00e3d8}, /* U+8052 */ - {0x00e88196, 0x0090b9}, /* U+8056 */ - {0x00e88198, 0x00e3d9}, /* U+8058 */ - {0x00e8819a, 0x00e3da}, /* U+805A */ - {0x00e8819e, 0x0095b7}, /* U+805E */ - {0x00e8819f, 0x00e3db}, /* U+805F */ - {0x00e881a1, 0x00918f}, /* U+8061 */ - {0x00e881a2, 0x00e3dc}, /* U+8062 */ - {0x00e881a6, 0x00f84b}, /* U+8066 [2000] */ - {0x00e881a8, 0x00e3dd}, /* U+8068 */ - {0x00e881af, 0x0097fc}, /* U+806F */ - {0x00e881b0, 0x00e3e0}, /* U+8070 */ - {0x00e881b1, 0x00f84c}, /* U+8071 [2000] */ - {0x00e881b2, 0x00e3df}, /* U+8072 */ - {0x00e881b3, 0x00e3de}, /* U+8073 */ - {0x00e881b4, 0x0092ae}, /* U+8074 */ - {0x00e881b5, 0x00f84d}, /* U+8075 [2000] */ - {0x00e881b6, 0x00e3e1}, /* U+8076 */ - {0x00e881b7, 0x009045}, /* U+8077 */ - {0x00e881b9, 0x00e3e2}, /* U+8079 */ - {0x00e881bb, 0x00f84e}, /* U+807B [2000] */ - {0x00e881bd, 0x00e3e3}, /* U+807D */ - {0x00e881be, 0x009857}, /* U+807E */ - {0x00e881bf, 0x00e3e4}, /* U+807F */ - {0x00e88284, 0x00e3e5}, /* U+8084 */ - {0x00e88285, 0x00e3e7}, /* U+8085 */ - {0x00e88286, 0x00e3e6}, /* U+8086 */ - {0x00e88287, 0x0094a3}, /* U+8087 */ - {0x00e88289, 0x0093f7}, /* U+8089 */ - {0x00e8828b, 0x00985d}, /* U+808B */ - {0x00e8828c, 0x0094a7}, /* U+808C */ - {0x00e88293, 0x00e3e9}, /* U+8093 */ - {0x00e88296, 0x008fd1}, /* U+8096 */ - {0x00e88298, 0x009549}, /* U+8098 */ - {0x00e88299, 0x00f84f}, /* U+8099 [2000] */ - {0x00e8829a, 0x00e3ea}, /* U+809A */ - {0x00e8829b, 0x00e3e8}, /* U+809B */ - {0x00e8829c, 0x00f850}, /* U+809C [2000] */ - {0x00e8829d, 0x008acc}, /* U+809D */ - {0x00e882a1, 0x008cd2}, /* U+80A1 */ - {0x00e882a2, 0x008e88}, /* U+80A2 */ - {0x00e882a4, 0x00f851}, /* U+80A4 [2000] */ - {0x00e882a5, 0x0094ec}, /* U+80A5 */ - {0x00e882a7, 0x00f852}, /* U+80A7 [2000] */ - {0x00e882a9, 0x008ca8}, /* U+80A9 */ - {0x00e882aa, 0x009662}, /* U+80AA */ - {0x00e882ac, 0x00e3ed}, /* U+80AC */ - {0x00e882ad, 0x00e3eb}, /* U+80AD */ - {0x00e882af, 0x008d6d}, /* U+80AF */ - {0x00e882b1, 0x008d6e}, /* U+80B1 */ - {0x00e882b2, 0x0088e7}, /* U+80B2 */ - {0x00e882b4, 0x008de6}, /* U+80B4 */ - {0x00e882b8, 0x00f853}, /* U+80B8 [2000] */ - {0x00e882ba, 0x009478}, /* U+80BA */ - {0x00e88383, 0x0088dd}, /* U+80C3 */ - {0x00e88384, 0x00e3f2}, /* U+80C4 */ - {0x00e88385, 0x00f855}, /* U+80C5 [2000] */ - {0x00e88386, 0x00925f}, /* U+80C6 */ - {0x00e8838a, 0x00edc8}, /* U+80CA [2000] */ - {0x00e8838c, 0x009477}, /* U+80CC */ - {0x00e8838e, 0x0091d9}, /* U+80CE */ - {0x00e88395, 0x00f856}, /* U+80D5 [2000] */ - {0x00e88396, 0x00e3f4}, /* U+80D6 */ - {0x00e88397, 0x00edc9}, /* U+80D7 [2000] */ - {0x00e88398, 0x00f857}, /* U+80D8 [2000] */ - {0x00e88399, 0x00e3f0}, /* U+80D9 */ - {0x00e8839a, 0x00e3f3}, /* U+80DA */ - {0x00e8839b, 0x00e3ee}, /* U+80DB */ - {0x00e8839d, 0x00e3f1}, /* U+80DD */ - {0x00e8839e, 0x009645}, /* U+80DE */ - {0x00e883a0, 0x00edca}, /* U+80E0 [2000] */ - {0x00e883a1, 0x008cd3}, /* U+80E1 */ - {0x00e883a4, 0x0088fb}, /* U+80E4 */ - {0x00e883a5, 0x00e3ef}, /* U+80E5 */ - {0x00e883a6, 0x00f858}, /* U+80E6 [2000] */ - {0x00e883af, 0x00e3f6}, /* U+80EF */ - {0x00e883b1, 0x00e3f7}, /* U+80F1 */ - {0x00e883b3, 0x00edcb}, /* U+80F3 [2000] */ - {0x00e883b4, 0x0093b7}, /* U+80F4 */ - {0x00e883b5, 0x00f85b}, /* U+80F5 [2000] */ - {0x00e883b8, 0x008bb9}, /* U+80F8 */ - {0x00e883bb, 0x00f85c}, /* U+80FB [2000] */ - {0x00e883bc, 0x00e445}, /* U+80FC */ - {0x00e883bd, 0x00945c}, /* U+80FD */ - {0x00e88482, 0x008e89}, /* U+8102 */ - {0x00e88485, 0x008bba}, /* U+8105 */ - {0x00e88486, 0x0090c6}, /* U+8106 */ - {0x00e88487, 0x009865}, /* U+8107 */ - {0x00e88488, 0x0096ac}, /* U+8108 */ - {0x00e88489, 0x00e3f5}, /* U+8109 */ - {0x00e8848a, 0x0090d2}, /* U+810A */ - {0x00e8848d, 0x00f85a}, /* U+810D [2000] */ - {0x00e88496, 0x00f85f}, /* U+8116 [2000] */ - {0x00e88498, 0x00edcc}, /* U+8118 [2000] */ - {0x00e8849a, 0x008b72}, /* U+811A */ - {0x00e8849b, 0x00e3f8}, /* U+811B */ - {0x00e8849e, 0x00f860}, /* U+811E [2000] */ - {0x00e884a3, 0x00e3fa}, /* U+8123 */ - {0x00e884a4, 0x00f862}, /* U+8124 [2000] */ - {0x00e884a7, 0x00f863}, /* U+8127 [2000] */ - {0x00e884a9, 0x00e3f9}, /* U+8129 */ - {0x00e884ac, 0x00f864}, /* U+812C [2000] */ - {0x00e884af, 0x00e3fb}, /* U+812F */ - {0x00e884b1, 0x009245}, /* U+8131 */ - {0x00e884b3, 0x00945d}, /* U+8133 */ - {0x00e884b5, 0x00f85e}, /* U+8135 [2000] */ - {0x00e884b9, 0x0092af}, /* U+8139 */ - {0x00e884bd, 0x00f866}, /* U+813D [2000] */ - {0x00e884be, 0x00e442}, /* U+813E */ - {0x00e88586, 0x00e441}, /* U+8146 */ - {0x00e8858a, 0x00edcd}, /* U+814A [2000] */ - {0x00e8858b, 0x00e3fc}, /* U+814B */ - {0x00e8858e, 0x009074}, /* U+814E */ - {0x00e88590, 0x009585}, /* U+8150 */ - {0x00e88591, 0x00e444}, /* U+8151 */ - {0x00e88593, 0x00e443}, /* U+8153 */ - {0x00e88594, 0x008d6f}, /* U+8154 */ - {0x00e88595, 0x009872}, /* U+8155 */ - {0x00e8859f, 0x00e454}, /* U+815F */ - {0x00e885a0, 0x00edce}, /* U+8160 [2000] */ - {0x00e885a5, 0x00e448}, /* U+8165 */ - {0x00e885a6, 0x00e449}, /* U+8166 */ - {0x00e885a7, 0x00edcf}, /* U+8167 [2000] */ - {0x00e885a8, 0x00edd0}, /* U+8168 [2000] */ - {0x00e885a9, 0x00f868}, /* U+8169 [2000] */ - {0x00e885ab, 0x008eee}, /* U+816B */ - {0x00e885ad, 0x00edd1}, /* U+816D [2000] */ - {0x00e885ae, 0x00e447}, /* U+816E */ - {0x00e885b0, 0x008d98}, /* U+8170 */ - {0x00e885b1, 0x00e446}, /* U+8171 */ - {0x00e885b4, 0x00e44a}, /* U+8174 */ - {0x00e885b8, 0x0092b0}, /* U+8178 */ - {0x00e885b9, 0x0095a0}, /* U+8179 */ - {0x00e885ba, 0x009142}, /* U+817A */ - {0x00e885bf, 0x0091da}, /* U+817F */ - {0x00e88680, 0x00e44e}, /* U+8180 */ - {0x00e88681, 0x00f86a}, /* U+8181 [2000] */ - {0x00e88682, 0x00e44f}, /* U+8182 */ - {0x00e88683, 0x00e44b}, /* U+8183 */ - {0x00e88684, 0x00f86c}, /* U+8184 [2000] */ - {0x00e88685, 0x00f86d}, /* U+8185 [2000] */ - {0x00e88688, 0x00e44c}, /* U+8188 */ - {0x00e8868a, 0x00e44d}, /* U+818A */ - {0x00e8868f, 0x008d70}, /* U+818F */ - {0x00e88693, 0x00e455}, /* U+8193 */ - {0x00e88695, 0x00e451}, /* U+8195 */ - {0x00e88698, 0x00f86f}, /* U+8198 [2000] */ - {0x00e8869a, 0x009586}, /* U+819A */ - {0x00e8869c, 0x00968c}, /* U+819C */ - {0x00e8869d, 0x009547}, /* U+819D */ - {0x00e886a0, 0x00e450}, /* U+81A0 */ - {0x00e886a3, 0x00e453}, /* U+81A3 */ - {0x00e886a4, 0x00e452}, /* U+81A4 */ - {0x00e886a8, 0x009663}, /* U+81A8 */ - {0x00e886a9, 0x00e456}, /* U+81A9 */ - {0x00e886b0, 0x00e457}, /* U+81B0 */ - {0x00e886b2, 0x00f870}, /* U+81B2 [2000] */ - {0x00e886b3, 0x009156}, /* U+81B3 */ - {0x00e886b5, 0x00e458}, /* U+81B5 */ - {0x00e886b8, 0x00e45a}, /* U+81B8 */ - {0x00e886ba, 0x00e45e}, /* U+81BA */ - {0x00e886bb, 0x00edd2}, /* U+81BB [2000] */ - {0x00e886bd, 0x00e45b}, /* U+81BD */ - {0x00e886be, 0x00e459}, /* U+81BE */ - {0x00e886bf, 0x00945e}, /* U+81BF */ - {0x00e88780, 0x00e45c}, /* U+81C0 */ - {0x00e88781, 0x00f871}, /* U+81C1 [2000] */ - {0x00e88782, 0x00e45d}, /* U+81C2 */ - {0x00e88783, 0x00f872}, /* U+81C3 [2000] */ - {0x00e88786, 0x0089b0}, /* U+81C6 */ - {0x00e88788, 0x00e464}, /* U+81C8 */ - {0x00e88789, 0x00e45f}, /* U+81C9 */ - {0x00e8878a, 0x00edd3}, /* U+81CA [2000] */ - {0x00e8878d, 0x00e460}, /* U+81CD */ - {0x00e8878f, 0x00edd4}, /* U+81CF [2000] */ - {0x00e88791, 0x00e461}, /* U+81D1 */ - {0x00e88793, 0x00919f}, /* U+81D3 */ - {0x00e88796, 0x00f873}, /* U+81D6 [2000] */ - {0x00e88797, 0x00edd5}, /* U+81D7 [2000] */ - {0x00e88798, 0x00e463}, /* U+81D8 */ - {0x00e88799, 0x00e462}, /* U+81D9 */ - {0x00e8879a, 0x00e465}, /* U+81DA */ - {0x00e8879b, 0x00f874}, /* U+81DB [2000] */ - {0x00e8879f, 0x00e466}, /* U+81DF */ - {0x00e887a0, 0x00e467}, /* U+81E0 */ - {0x00e887a3, 0x009062}, /* U+81E3 */ - {0x00e887a4, 0x00f876}, /* U+81E4 [2000] */ - {0x00e887a5, 0x0089e7}, /* U+81E5 */ - {0x00e887a7, 0x00e468}, /* U+81E7 */ - {0x00e887a8, 0x0097d5}, /* U+81E8 */ - {0x00e887aa, 0x008ea9}, /* U+81EA */ - {0x00e887ac, 0x00f878}, /* U+81EC [2000] */ - {0x00e887ad, 0x008f4c}, /* U+81ED */ - {0x00e887b3, 0x008e8a}, /* U+81F3 */ - {0x00e887b4, 0x009276}, /* U+81F4 */ - {0x00e887ba, 0x00e469}, /* U+81FA */ - {0x00e887bb, 0x00e46a}, /* U+81FB */ - {0x00e887bc, 0x008950}, /* U+81FC */ - {0x00e887bd, 0x00f87a}, /* U+81FD [2000] */ - {0x00e887be, 0x00e46b}, /* U+81FE */ - {0x00e887bf, 0x00f87b}, /* U+81FF [2000] */ - {0x00e88881, 0x00e46c}, /* U+8201 */ - {0x00e88882, 0x00e46d}, /* U+8202 */ - {0x00e88884, 0x00f87d}, /* U+8204 [2000] */ - {0x00e88885, 0x00e46e}, /* U+8205 */ - {0x00e88887, 0x00e46f}, /* U+8207 */ - {0x00e88888, 0x008bbb}, /* U+8208 */ - {0x00e88889, 0x009da8}, /* U+8209 */ - {0x00e8888a, 0x00e470}, /* U+820A */ - {0x00e8888c, 0x0090e3}, /* U+820C */ - {0x00e8888d, 0x00e471}, /* U+820D */ - {0x00e8888e, 0x008ec9}, /* U+820E */ - {0x00e88890, 0x00e472}, /* U+8210 */ - {0x00e88892, 0x0098ae}, /* U+8212 */ - {0x00e88896, 0x00e473}, /* U+8216 */ - {0x00e88897, 0x0095dc}, /* U+8217 */ - {0x00e88898, 0x008ada}, /* U+8218 */ - {0x00e88899, 0x00f880}, /* U+8219 [2000] */ - {0x00e8889b, 0x009143}, /* U+821B */ - {0x00e8889c, 0x008f77}, /* U+821C */ - {0x00e8889e, 0x009591}, /* U+821E */ - {0x00e8889f, 0x008f4d}, /* U+821F */ - {0x00e888a1, 0x00f881}, /* U+8221 [2000] */ - {0x00e888a2, 0x00f882}, /* U+8222 [2000] */ - {0x00e888a9, 0x00e474}, /* U+8229 */ - {0x00e888aa, 0x008d71}, /* U+822A */ - {0x00e888ab, 0x00e475}, /* U+822B */ - {0x00e888ac, 0x0094ca}, /* U+822C */ - {0x00e888ae, 0x00e484}, /* U+822E */ - {0x00e888b2, 0x00f884}, /* U+8232 [2000] */ - {0x00e888b3, 0x00e477}, /* U+8233 */ - {0x00e888b4, 0x00f885}, /* U+8234 [2000] */ - {0x00e888b5, 0x0091c7}, /* U+8235 */ - {0x00e888b6, 0x009495}, /* U+8236 */ - {0x00e888b7, 0x008cbd}, /* U+8237 */ - {0x00e888b8, 0x00e476}, /* U+8238 */ - {0x00e888b9, 0x009144}, /* U+8239 */ - {0x00e888bc, 0x00f886}, /* U+823C [2000] */ - {0x00e88980, 0x00e478}, /* U+8240 */ - {0x00e88985, 0x00f889}, /* U+8245 [2000] */ - {0x00e88986, 0x00f887}, /* U+8246 [2000] */ - {0x00e88987, 0x0092f8}, /* U+8247 */ - {0x00e88989, 0x00f888}, /* U+8249 [2000] */ - {0x00e8898b, 0x00f88b}, /* U+824B [2000] */ - {0x00e8898f, 0x00f88d}, /* U+824F [2000] */ - {0x00e88997, 0x00f88f}, /* U+8257 [2000] */ - {0x00e88998, 0x00e47a}, /* U+8258 */ - {0x00e88999, 0x00e479}, /* U+8259 */ - {0x00e8899a, 0x00e47c}, /* U+825A */ - {0x00e8899c, 0x00f891}, /* U+825C [2000] */ - {0x00e8899d, 0x00e47b}, /* U+825D */ - {0x00e8899f, 0x00e47d}, /* U+825F */ - {0x00e889a0, 0x00edd9}, /* U+8260 [2000] */ - {0x00e889a2, 0x00e480}, /* U+8262 */ - {0x00e889a3, 0x00f892}, /* U+8263 [2000] */ - {0x00e889a4, 0x00e47e}, /* U+8264 */ - {0x00e889a6, 0x008acd}, /* U+8266 */ - {0x00e889a8, 0x00e481}, /* U+8268 */ - {0x00e889aa, 0x00e482}, /* U+826A */ - {0x00e889ab, 0x00e483}, /* U+826B */ - {0x00e889ae, 0x008daf}, /* U+826E */ - {0x00e889af, 0x0097c7}, /* U+826F */ - {0x00e889b1, 0x00e485}, /* U+8271 */ - {0x00e889b2, 0x009046}, /* U+8272 */ - {0x00e889b4, 0x00edda}, /* U+8274 [2000] */ - {0x00e889b6, 0x008990}, /* U+8276 */ - {0x00e889b7, 0x00e486}, /* U+8277 */ - {0x00e889b8, 0x00e487}, /* U+8278 */ - {0x00e889b9, 0x00f896}, /* U+8279 [2000] */ - {0x00e889bd, 0x00f898}, /* U+827D [2000] */ - {0x00e889be, 0x00e488}, /* U+827E */ - {0x00e889bf, 0x00f899}, /* U+827F [2000] */ - {0x00e88a83, 0x00f89a}, /* U+8283 [2000] */ - {0x00e88a8a, 0x00f89b}, /* U+828A [2000] */ - {0x00e88a8b, 0x0088f0}, /* U+828B */ - {0x00e88a8d, 0x00e489}, /* U+828D */ - {0x00e88a8e, 0x00eddc}, /* U+828E [2000] */ - {0x00e88a92, 0x00e48a}, /* U+8292 */ - {0x00e88a93, 0x00f89c}, /* U+8293 [2000] */ - {0x00e88a99, 0x009587}, /* U+8299 */ - {0x00e88a9d, 0x008ec5}, /* U+829D */ - {0x00e88a9f, 0x00e48c}, /* U+829F */ - {0x00e88aa1, 0x00eddd}, /* U+82A1 [2000] */ - {0x00e88aa3, 0x00edde}, /* U+82A3 [2000] */ - {0x00e88aa4, 0x00eddf}, /* U+82A4 [2000] */ - {0x00e88aa5, 0x008a48}, /* U+82A5 */ - {0x00e88aa6, 0x0088b0}, /* U+82A6 */ - {0x00e88aa7, 0x00f89d}, /* U+82A7 [2000] */ - {0x00e88aa8, 0x00f89e}, /* U+82A8 [2000] */ - {0x00e88aa9, 0x00ede0}, /* U+82A9 [2000] */ - {0x00e88aab, 0x00e48b}, /* U+82AB */ - {0x00e88aac, 0x00e48e}, /* U+82AC */ - {0x00e88aad, 0x00946d}, /* U+82AD */ - {0x00e88aae, 0x00ede1}, /* U+82AE [2000] */ - {0x00e88aaf, 0x009063}, /* U+82AF */ - {0x00e88ab1, 0x0089d4}, /* U+82B1 */ - {0x00e88ab2, 0x00f89f}, /* U+82B2 [2000] */ - {0x00e88ab3, 0x009646}, /* U+82B3 */ - {0x00e88ab4, 0x00f8a0}, /* U+82B4 [2000] */ - {0x00e88ab7, 0x00ede2}, /* U+82B7 [2000] */ - {0x00e88ab8, 0x008c7c}, /* U+82B8 */ - {0x00e88ab9, 0x008bda}, /* U+82B9 */ - {0x00e88aba, 0x00f8a1}, /* U+82BA [2000] */ - {0x00e88abb, 0x00e48d}, /* U+82BB */ - {0x00e88abc, 0x00f8a2}, /* U+82BC [2000] */ - {0x00e88abd, 0x0089e8}, /* U+82BD */ - {0x00e88abe, 0x00ede3}, /* U+82BE [2000] */ - {0x00e88abf, 0x00ede4}, /* U+82BF [2000] */ - {0x00e88b85, 0x008aa1}, /* U+82C5 */ - {0x00e88b86, 0x00ede5}, /* U+82C6 [2000] */ - {0x00e88b91, 0x008991}, /* U+82D1 */ - {0x00e88b92, 0x00e492}, /* U+82D2 */ - {0x00e88b93, 0x0097e8}, /* U+82D3 */ - {0x00e88b94, 0x0091db}, /* U+82D4 */ - {0x00e88b95, 0x00ede6}, /* U+82D5 [2000] */ - {0x00e88b97, 0x009563}, /* U+82D7 */ - {0x00e88b99, 0x00e49e}, /* U+82D9 */ - {0x00e88b9b, 0x0089d5}, /* U+82DB */ - {0x00e88b9c, 0x00e49c}, /* U+82DC */ - {0x00e88b9e, 0x00e49a}, /* U+82DE */ - {0x00e88b9f, 0x00e491}, /* U+82DF */ - {0x00e88ba1, 0x00e48f}, /* U+82E1 */ - {0x00e88ba2, 0x00f8a3}, /* U+82E2 [2000] */ - {0x00e88ba3, 0x00e490}, /* U+82E3 */ - {0x00e88ba5, 0x008ee1}, /* U+82E5 */ - {0x00e88ba6, 0x008bea}, /* U+82E6 */ - {0x00e88ba7, 0x009297}, /* U+82E7 */ - {0x00e88ba8, 0x00f8a4}, /* U+82E8 [2000] */ - {0x00e88bab, 0x0093cf}, /* U+82EB */ - {0x00e88bb1, 0x008970}, /* U+82F1 */ - {0x00e88bb3, 0x00e494}, /* U+82F3 */ - {0x00e88bb4, 0x00e493}, /* U+82F4 */ - {0x00e88bb7, 0x00f8a5}, /* U+82F7 [2000] */ - {0x00e88bb9, 0x00e499}, /* U+82F9 */ - {0x00e88bba, 0x00e495}, /* U+82FA */ - {0x00e88bbb, 0x00e498}, /* U+82FB */ - {0x00e88bbd, 0x00ede7}, /* U+82FD [2000] */ - {0x00e88bbe, 0x00ede8}, /* U+82FE [2000] */ - {0x00e88c80, 0x00ede9}, /* U+8300 [2000] */ - {0x00e88c81, 0x00edea}, /* U+8301 [2000] */ - {0x00e88c82, 0x0096ce}, /* U+8302 */ - {0x00e88c83, 0x00e497}, /* U+8303 */ - {0x00e88c84, 0x0089d6}, /* U+8304 */ - {0x00e88c85, 0x008a9d}, /* U+8305 */ - {0x00e88c86, 0x00e49b}, /* U+8306 */ - {0x00e88c87, 0x00f8a6}, /* U+8307 [2000] */ - {0x00e88c88, 0x00f8a7}, /* U+8308 [2000] */ - {0x00e88c89, 0x00e49d}, /* U+8309 */ - {0x00e88c8c, 0x00f8a8}, /* U+830C [2000] */ - {0x00e88c8e, 0x008c73}, /* U+830E */ - {0x00e88c96, 0x00e4a1}, /* U+8316 */ - {0x00e88c97, 0x00e4aa}, /* U+8317 */ - {0x00e88c98, 0x00e4ab}, /* U+8318 */ - {0x00e88c9b, 0x00f8aa}, /* U+831B [2000] */ - {0x00e88c9c, 0x0088a9}, /* U+831C */ - {0x00e88c9d, 0x00f8ab}, /* U+831D [2000] */ - {0x00e88ca2, 0x00edec}, /* U+8322 [2000] */ - {0x00e88ca3, 0x00e4b2}, /* U+8323 */ - {0x00e88ca8, 0x0088ef}, /* U+8328 */ - {0x00e88cab, 0x00e4a9}, /* U+832B */ - {0x00e88cad, 0x00eded}, /* U+832D [2000] */ - {0x00e88caf, 0x00e4a8}, /* U+832F */ - {0x00e88cb0, 0x00f8ac}, /* U+8330 [2000] */ - {0x00e88cb1, 0x00e4a3}, /* U+8331 */ - {0x00e88cb2, 0x00e4a2}, /* U+8332 */ - {0x00e88cb4, 0x00e4a0}, /* U+8334 */ - {0x00e88cb5, 0x00e49f}, /* U+8335 */ - {0x00e88cb6, 0x009283}, /* U+8336 */ - {0x00e88cb8, 0x0091f9}, /* U+8338 */ - {0x00e88cb9, 0x00e4a5}, /* U+8339 */ - {0x00e88cba, 0x00edee}, /* U+833A [2000] */ - {0x00e88cbc, 0x00f8ad}, /* U+833C [2000] */ - {0x00e88d80, 0x00e4a4}, /* U+8340 */ - {0x00e88d83, 0x00edef}, /* U+8343 [2000] */ - {0x00e88d84, 0x00f8ae}, /* U+8344 [2000] */ - {0x00e88d85, 0x00e4a7}, /* U+8345 */ - {0x00e88d87, 0x00edf0}, /* U+8347 [2000] */ - {0x00e88d89, 0x009190}, /* U+8349 */ - {0x00e88d8a, 0x008c74}, /* U+834A */ - {0x00e88d8f, 0x008960}, /* U+834F */ - {0x00e88d90, 0x00e4a6}, /* U+8350 */ - {0x00e88d91, 0x00edf1}, /* U+8351 [2000] */ - {0x00e88d92, 0x008d72}, /* U+8352 */ - {0x00e88d94, 0x00f8a9}, /* U+8354 [2000] */ - {0x00e88d95, 0x00edf2}, /* U+8355 [2000] */ - {0x00e88d97, 0x00f8af}, /* U+8357 [2000] */ - {0x00e88d98, 0x009191}, /* U+8358 */ - {0x00e88da2, 0x00edeb}, /* U+8362 [2000] */ - {0x00e88da3, 0x00f3c8}, /* U+8363 [2000] */ - {0x00e88db3, 0x00e4b8}, /* U+8373 */ - {0x00e88db5, 0x00e4b9}, /* U+8375 */ - {0x00e88db7, 0x0089d7}, /* U+8377 */ - {0x00e88dbb, 0x0089ac}, /* U+837B */ - {0x00e88dbc, 0x00e4b6}, /* U+837C */ - {0x00e88dbd, 0x00edf3}, /* U+837D [2000] */ - {0x00e88dbf, 0x00f8b1}, /* U+837F [2000] */ - {0x00e88e85, 0x00e4ac}, /* U+8385 */ - {0x00e88e86, 0x00edf4}, /* U+8386 [2000] */ - {0x00e88e87, 0x00e4b4}, /* U+8387 */ - {0x00e88e89, 0x00e4bb}, /* U+8389 */ - {0x00e88e8a, 0x00e4b5}, /* U+838A */ - {0x00e88e8d, 0x00f8b4}, /* U+838D [2000] */ - {0x00e88e8e, 0x00e4b3}, /* U+838E */ - {0x00e88e92, 0x00edf5}, /* U+8392 [2000] */ - {0x00e88e93, 0x00e496}, /* U+8393 */ - {0x00e88e94, 0x00f8b5}, /* U+8394 [2000] */ - {0x00e88e95, 0x00f8b6}, /* U+8395 [2000] */ - {0x00e88e96, 0x00e4b1}, /* U+8396 */ - {0x00e88e98, 0x00edf6}, /* U+8398 [2000] */ - {0x00e88e9a, 0x00e4ad}, /* U+839A */ - {0x00e88e9b, 0x00f8b7}, /* U+839B [2000] */ - {0x00e88e9d, 0x00f8b8}, /* U+839D [2000] */ - {0x00e88e9e, 0x008ace}, /* U+839E */ - {0x00e88e9f, 0x00e4af}, /* U+839F */ - {0x00e88ea0, 0x00e4ba}, /* U+83A0 */ - {0x00e88ea2, 0x00e4b0}, /* U+83A2 */ - {0x00e88ea7, 0x00edf7}, /* U+83A7 [2000] */ - {0x00e88ea8, 0x00e4bc}, /* U+83A8 */ - {0x00e88ea9, 0x00edf8}, /* U+83A9 [2000] */ - {0x00e88eaa, 0x00e4ae}, /* U+83AA */ - {0x00e88eab, 0x00949c}, /* U+83AB */ - {0x00e88eb1, 0x009789}, /* U+83B1 */ - {0x00e88eb5, 0x00e4b7}, /* U+83B5 */ - {0x00e88ebd, 0x00e4cd}, /* U+83BD */ - {0x00e88ebf, 0x00edf9}, /* U+83BF [2000] */ - {0x00e88f80, 0x00edfa}, /* U+83C0 [2000] */ - {0x00e88f81, 0x00e4c5}, /* U+83C1 */ - {0x00e88f85, 0x00909b}, /* U+83C5 */ - {0x00e88f87, 0x00edfb}, /* U+83C7 [2000] */ - {0x00e88f89, 0x00f8b9}, /* U+83C9 [2000] */ - {0x00e88f8a, 0x008b65}, /* U+83CA */ - {0x00e88f8c, 0x008bdb}, /* U+83CC */ - {0x00e88f8e, 0x00e4c0}, /* U+83CE */ - {0x00e88f8f, 0x00edfc}, /* U+83CF [2000] */ - {0x00e88f90, 0x00f8ba}, /* U+83D0 [2000] */ - {0x00e88f91, 0x00ee40}, /* U+83D1 [2000] */ - {0x00e88f93, 0x0089d9}, /* U+83D3 */ - {0x00e88f94, 0x00f8bb}, /* U+83D4 [2000] */ - {0x00e88f96, 0x008fd2}, /* U+83D6 */ - {0x00e88f98, 0x00e4c3}, /* U+83D8 */ - {0x00e88f9c, 0x008dd8}, /* U+83DC */ - {0x00e88f9d, 0x00f8bc}, /* U+83DD [2000] */ - {0x00e88f9f, 0x009370}, /* U+83DF */ - {0x00e88fa0, 0x00e4c8}, /* U+83E0 */ - {0x00e88fa1, 0x00ee41}, /* U+83E1 [2000] */ - {0x00e88fa5, 0x00f8bd}, /* U+83E5 [2000] */ - {0x00e88fa9, 0x0095ec}, /* U+83E9 */ - {0x00e88faa, 0x00ee42}, /* U+83EA [2000] */ - {0x00e88fab, 0x00e4bf}, /* U+83EB */ - {0x00e88faf, 0x0089d8}, /* U+83EF */ - {0x00e88fb0, 0x008cd4}, /* U+83F0 */ - {0x00e88fb1, 0x009548}, /* U+83F1 */ - {0x00e88fb2, 0x00e4c9}, /* U+83F2 */ - {0x00e88fb4, 0x00e4bd}, /* U+83F4 */ - {0x00e88fb7, 0x00e4c6}, /* U+83F7 */ - {0x00e88fb9, 0x00f8be}, /* U+83F9 [2000] */ - {0x00e88fbb, 0x00e4d0}, /* U+83FB */ - {0x00e88fbd, 0x00e4c1}, /* U+83FD */ - {0x00e89081, 0x00ee43}, /* U+8401 [2000] */ - {0x00e89083, 0x00e4c2}, /* U+8403 */ - {0x00e89084, 0x0093b8}, /* U+8404 */ - {0x00e89086, 0x00ee44}, /* U+8406 [2000] */ - {0x00e89087, 0x00e4c7}, /* U+8407 */ - {0x00e8908a, 0x00ee45}, /* U+840A [2000] */ - {0x00e8908b, 0x00e4c4}, /* U+840B */ - {0x00e8908c, 0x009647}, /* U+840C */ - {0x00e8908d, 0x00e4ca}, /* U+840D */ - {0x00e8908e, 0x0088de}, /* U+840E */ - {0x00e8908f, 0x00f8bf}, /* U+840F [2000] */ - {0x00e89091, 0x00f8c0}, /* U+8411 [2000] */ - {0x00e89093, 0x00e4be}, /* U+8413 */ - {0x00e89095, 0x00f8c1}, /* U+8415 [2000] */ - {0x00e89097, 0x00f8c3}, /* U+8417 [2000] */ - {0x00e890a0, 0x00e4cc}, /* U+8420 */ - {0x00e890a2, 0x00e4cb}, /* U+8422 */ - {0x00e890a9, 0x00948b}, /* U+8429 */ - {0x00e890aa, 0x00e4d2}, /* U+842A */ - {0x00e890ac, 0x00e4dd}, /* U+842C */ - {0x00e890b1, 0x008a9e}, /* U+8431 */ - {0x00e890b5, 0x00e4e0}, /* U+8435 */ - {0x00e890b8, 0x00e4ce}, /* U+8438 */ - {0x00e890b9, 0x00f8c4}, /* U+8439 [2000] */ - {0x00e890bc, 0x00e4d3}, /* U+843C */ - {0x00e890bd, 0x00978e}, /* U+843D */ - {0x00e89186, 0x00e4dc}, /* U+8446 */ - {0x00e89188, 0x00ee47}, /* U+8448 [2000] */ - {0x00e89189, 0x009774}, /* U+8449 */ - {0x00e8918a, 0x00f8c5}, /* U+844A [2000] */ - {0x00e8918e, 0x0097a8}, /* U+844E */ - {0x00e8918f, 0x00f8c6}, /* U+844F [2000] */ - {0x00e89191, 0x00f8c7}, /* U+8451 [2000] */ - {0x00e89192, 0x00f8c8}, /* U+8452 [2000] */ - {0x00e89197, 0x009298}, /* U+8457 */ - {0x00e89199, 0x00f8c9}, /* U+8459 [2000] */ - {0x00e8919a, 0x00f8ca}, /* U+845A [2000] */ - {0x00e8919b, 0x008a8b}, /* U+845B */ - {0x00e8919c, 0x00f8cb}, /* U+845C [2000] */ - {0x00e8919f, 0x00ee48}, /* U+845F [2000] */ - {0x00e891a1, 0x009592}, /* U+8461 */ - {0x00e891a2, 0x00e4e2}, /* U+8462 */ - {0x00e891a3, 0x00939f}, /* U+8463 */ - {0x00e891a5, 0x00f8cd}, /* U+8465 [2000] */ - {0x00e891a6, 0x0088af}, /* U+8466 */ - {0x00e891a9, 0x00e4db}, /* U+8469 */ - {0x00e891ab, 0x00e4d7}, /* U+846B */ - {0x00e891ac, 0x009192}, /* U+846C */ - {0x00e891ad, 0x00e4d1}, /* U+846D */ - {0x00e891ae, 0x00e4d9}, /* U+846E */ - {0x00e891af, 0x00e4de}, /* U+846F */ - {0x00e891b0, 0x00ee49}, /* U+8470 [2000] */ - {0x00e891b1, 0x00944b}, /* U+8471 */ - {0x00e891b3, 0x00ee4a}, /* U+8473 [2000] */ - {0x00e891b5, 0x0088a8}, /* U+8475 */ - {0x00e891b6, 0x00f8ce}, /* U+8476 [2000] */ - {0x00e891b7, 0x00e4d6}, /* U+8477 */ - {0x00e891b8, 0x00f8cf}, /* U+8478 [2000] */ - {0x00e891b9, 0x00e4df}, /* U+8479 */ - {0x00e891ba, 0x009598}, /* U+847A */ - {0x00e891bc, 0x00f8d0}, /* U+847C [2000] */ - {0x00e89281, 0x00f8d1}, /* U+8481 [2000] */ - {0x00e89282, 0x00e4da}, /* U+8482 */ - {0x00e89284, 0x00e4d5}, /* U+8484 */ - {0x00e89285, 0x00ee4b}, /* U+8485 [2000] */ - {0x00e8928b, 0x008fd3}, /* U+848B */ - {0x00e89290, 0x008f4e}, /* U+8490 */ - {0x00e89294, 0x008eaa}, /* U+8494 */ - {0x00e89297, 0x00f8d4}, /* U+8497 [2000] */ - {0x00e89299, 0x0096d6}, /* U+8499 */ - {0x00e8929c, 0x009566}, /* U+849C */ - {0x00e8929e, 0x00ee4c}, /* U+849E [2000] */ - {0x00e8929f, 0x00e4e5}, /* U+849F */ - {0x00e892a1, 0x00e4ee}, /* U+84A1 */ - {0x00e892a6, 0x00f8d5}, /* U+84A6 [2000] */ - {0x00e892ad, 0x00e4d8}, /* U+84AD */ - {0x00e892af, 0x00ee4d}, /* U+84AF [2000] */ - {0x00e892b2, 0x008a97}, /* U+84B2 */ - {0x00e892b4, 0x00ee4e}, /* U+84B4 [2000] */ - {0x00e892b8, 0x008ff6}, /* U+84B8 */ - {0x00e892b9, 0x00e4e3}, /* U+84B9 */ - {0x00e892ba, 0x00ee4f}, /* U+84BA [2000] */ - {0x00e892bb, 0x00e4e8}, /* U+84BB */ - {0x00e892bc, 0x009193}, /* U+84BC */ - {0x00e892be, 0x00f8d6}, /* U+84BE [2000] */ - {0x00e892bf, 0x00e4e4}, /* U+84BF */ - {0x00e89380, 0x00ee50}, /* U+84C0 [2000] */ - {0x00e89381, 0x00e4eb}, /* U+84C1 */ - {0x00e89382, 0x00ee51}, /* U+84C2 [2000] */ - {0x00e89384, 0x00927e}, /* U+84C4 */ - {0x00e89386, 0x00e4ec}, /* U+84C6 */ - {0x00e89389, 0x009775}, /* U+84C9 */ - {0x00e8938a, 0x00e4e1}, /* U+84CA */ - {0x00e8938b, 0x008a57}, /* U+84CB */ - {0x00e8938d, 0x00e4e7}, /* U+84CD */ - {0x00e8938e, 0x00f8d8}, /* U+84CE [2000] */ - {0x00e8938f, 0x00f8d9}, /* U+84CF [2000] */ - {0x00e89390, 0x00e4ea}, /* U+84D0 */ - {0x00e89391, 0x0096aa}, /* U+84D1 */ - {0x00e89393, 0x00f8da}, /* U+84D3 [2000] */ - {0x00e89396, 0x00e4ed}, /* U+84D6 */ - {0x00e89399, 0x00e4e6}, /* U+84D9 */ - {0x00e8939a, 0x00e4e9}, /* U+84DA */ - {0x00e8939c, 0x00f8d3}, /* U+84DC [2000] */ - {0x00e893a7, 0x00f8dc}, /* U+84E7 [2000] */ - {0x00e893aa, 0x00f8dd}, /* U+84EA [2000] */ - {0x00e893ac, 0x009648}, /* U+84EC */ - {0x00e893ae, 0x009840}, /* U+84EE */ - {0x00e893af, 0x00f8de}, /* U+84EF [2000] */ - {0x00e893b0, 0x00f8df}, /* U+84F0 [2000] */ - {0x00e893b1, 0x00f8e0}, /* U+84F1 [2000] */ - {0x00e893b4, 0x00e4f1}, /* U+84F4 */ - {0x00e893ba, 0x00f8e1}, /* U+84FA [2000] */ - {0x00e893bc, 0x00e4f8}, /* U+84FC */ - {0x00e893bd, 0x00f8e2}, /* U+84FD [2000] */ - {0x00e893bf, 0x00e4f0}, /* U+84FF */ - {0x00e89480, 0x008ec1}, /* U+8500 */ - {0x00e89486, 0x00e4cf}, /* U+8506 */ - {0x00e8948c, 0x00f8e3}, /* U+850C [2000] */ - {0x00e89491, 0x0095cc}, /* U+8511 */ - {0x00e89493, 0x0096a0}, /* U+8513 */ - {0x00e89494, 0x00e4f7}, /* U+8514 */ - {0x00e89495, 0x00e4f6}, /* U+8515 */ - {0x00e89497, 0x00e4f2}, /* U+8517 */ - {0x00e89498, 0x00e4f3}, /* U+8518 */ - {0x00e8949a, 0x008955}, /* U+851A */ - {0x00e8949b, 0x00f8e4}, /* U+851B [2000] */ - {0x00e8949e, 0x00ee54}, /* U+851E [2000] */ - {0x00e8949f, 0x00e4f5}, /* U+851F */ - {0x00e894a1, 0x00e4ef}, /* U+8521 */ - {0x00e894a3, 0x00ee55}, /* U+8523 [2000] */ - {0x00e894a4, 0x00f8e5}, /* U+8524 [2000] */ - {0x00e894a5, 0x00f8e6}, /* U+8525 [2000] */ - {0x00e894a6, 0x0092d3}, /* U+8526 */ - {0x00e894ab, 0x00f8e7}, /* U+852B [2000] */ - {0x00e894ac, 0x00e4f4}, /* U+852C */ - {0x00e894ad, 0x0088fc}, /* U+852D */ - {0x00e894af, 0x00ee56}, /* U+852F [2000] */ - {0x00e894b2, 0x00ee53}, /* U+8532 [2000] */ - {0x00e894b4, 0x00f8e8}, /* U+8534 [2000] */ - {0x00e894b5, 0x0091a0}, /* U+8535 */ - {0x00e894bd, 0x0095c1}, /* U+853D */ - {0x00e894be, 0x00f8ed}, /* U+853E [2000] */ - {0x00e89580, 0x00e4f9}, /* U+8540 */ - {0x00e89581, 0x00e540}, /* U+8541 */ - {0x00e89583, 0x0094d7}, /* U+8543 */ - {0x00e89588, 0x00e4fc}, /* U+8548 */ - {0x00e89589, 0x008fd4}, /* U+8549 */ - {0x00e8958a, 0x008ec7}, /* U+854A */ - {0x00e8958b, 0x00e542}, /* U+854B */ - {0x00e8958e, 0x008bbc}, /* U+854E */ - {0x00e8958f, 0x00f8e9}, /* U+854F [2000] */ - {0x00e89591, 0x00f8ee}, /* U+8551 [2000] */ - {0x00e89593, 0x00f8ef}, /* U+8553 [2000] */ - {0x00e89595, 0x00e543}, /* U+8555 */ - {0x00e89597, 0x009599}, /* U+8557 */ - {0x00e89598, 0x00e4fb}, /* U+8558 */ - {0x00e89599, 0x00ee57}, /* U+8559 [2000] */ - {0x00e8959a, 0x00e4d4}, /* U+855A */ - {0x00e8959e, 0x00f8f0}, /* U+855E [2000] */ - {0x00e895a1, 0x00f8f1}, /* U+8561 [2000] */ - {0x00e895a2, 0x00f8f2}, /* U+8562 [2000] */ - {0x00e895a3, 0x00e4fa}, /* U+8563 */ - {0x00e895a4, 0x00ee58}, /* U+8564 [2000] */ - {0x00e895a8, 0x00986e}, /* U+8568 */ - {0x00e895a9, 0x0093a0}, /* U+8569 */ - {0x00e895aa, 0x009593}, /* U+856A */ - {0x00e895ad, 0x00e54a}, /* U+856D */ - {0x00e895af, 0x00f8ea}, /* U+856F [2000] */ - {0x00e895b7, 0x00e550}, /* U+8577 */ - {0x00e895ba, 0x00ee5b}, /* U+857A [2000] */ - {0x00e895bb, 0x00f8f4}, /* U+857B [2000] */ - {0x00e895bd, 0x00f8f5}, /* U+857D [2000] */ - {0x00e895be, 0x00e551}, /* U+857E */ - {0x00e895bf, 0x00f8f6}, /* U+857F [2000] */ - {0x00e89680, 0x00e544}, /* U+8580 */ - {0x00e89681, 0x00f8f7}, /* U+8581 [2000] */ - {0x00e89684, 0x009496}, /* U+8584 */ - {0x00e89686, 0x00f8f8}, /* U+8586 [2000] */ - {0x00e89687, 0x00e54e}, /* U+8587 */ - {0x00e89688, 0x00e546}, /* U+8588 */ - {0x00e8968a, 0x00e548}, /* U+858A */ - {0x00e8968c, 0x00ee5c}, /* U+858C [2000] */ - {0x00e8968f, 0x00ee5d}, /* U+858F [2000] */ - {0x00e89690, 0x00e552}, /* U+8590 */ - {0x00e89691, 0x00e547}, /* U+8591 */ - {0x00e89693, 0x00f8f9}, /* U+8593 [2000] */ - {0x00e89694, 0x00e54b}, /* U+8594 */ - {0x00e89697, 0x008992}, /* U+8597 */ - {0x00e89699, 0x0093e3}, /* U+8599 */ - {0x00e8969b, 0x00e54c}, /* U+859B */ - {0x00e8969c, 0x00e54f}, /* U+859C */ - {0x00e8969d, 0x00f8fa}, /* U+859D [2000] */ - {0x00e8969f, 0x00f8fb}, /* U+859F [2000] */ - {0x00e896a2, 0x00ee5e}, /* U+85A2 [2000] */ - {0x00e896a4, 0x00e545}, /* U+85A4 */ - {0x00e896a6, 0x009145}, /* U+85A6 */ - {0x00e896a8, 0x00e549}, /* U+85A8 */ - {0x00e896a9, 0x008e46}, /* U+85A9 */ - {0x00e896aa, 0x009064}, /* U+85AA */ - {0x00e896ab, 0x008c4f}, /* U+85AB */ - {0x00e896ac, 0x0096f2}, /* U+85AC */ - {0x00e896ad, 0x00ee5a}, /* U+85AD [2000] */ - {0x00e896ae, 0x0096f7}, /* U+85AE */ - {0x00e896af, 0x008f92}, /* U+85AF */ - {0x00e896b0, 0x00ee5f}, /* U+85B0 [2000] */ - {0x00e896b7, 0x00f942}, /* U+85B7 [2000] */ - {0x00e896b9, 0x00e556}, /* U+85B9 */ - {0x00e896ba, 0x00e554}, /* U+85BA */ - {0x00e896bc, 0x00f943}, /* U+85BC [2000] */ - {0x00e89781, 0x00986d}, /* U+85C1 */ - {0x00e89787, 0x00f944}, /* U+85C7 [2000] */ - {0x00e89789, 0x00e553}, /* U+85C9 */ - {0x00e8978a, 0x00f945}, /* U+85CA [2000] */ - {0x00e8978b, 0x00ee60}, /* U+85CB [2000] */ - {0x00e8978d, 0x009795}, /* U+85CD */ - {0x00e8978e, 0x00ee61}, /* U+85CE [2000] */ - {0x00e8978f, 0x00e555}, /* U+85CF */ - {0x00e89790, 0x00e557}, /* U+85D0 */ - {0x00e89795, 0x00e558}, /* U+85D5 */ - {0x00e89798, 0x00f946}, /* U+85D8 [2000] */ - {0x00e89799, 0x00f947}, /* U+85D9 [2000] */ - {0x00e8979c, 0x00e55b}, /* U+85DC */ - {0x00e8979d, 0x00e559}, /* U+85DD */ - {0x00e8979f, 0x00f948}, /* U+85DF [2000] */ - {0x00e897a1, 0x00f949}, /* U+85E1 [2000] */ - {0x00e897a4, 0x0093a1}, /* U+85E4 */ - {0x00e897a5, 0x00e55a}, /* U+85E5 */ - {0x00e897a6, 0x00f94a}, /* U+85E6 [2000] */ - {0x00e897a9, 0x0094cb}, /* U+85E9 */ - {0x00e897aa, 0x00e54d}, /* U+85EA */ - {0x00e897ad, 0x00ee62}, /* U+85ED [2000] */ - {0x00e897b6, 0x00f94b}, /* U+85F6 [2000] */ - {0x00e897b7, 0x008f93}, /* U+85F7 */ - {0x00e897b9, 0x00e55c}, /* U+85F9 */ - {0x00e897ba, 0x00e561}, /* U+85FA */ - {0x00e897bb, 0x009194}, /* U+85FB */ - {0x00e897be, 0x00e560}, /* U+85FE */ - {0x00e897bf, 0x00ee64}, /* U+85FF [2000] */ - {0x00e89880, 0x00f94c}, /* U+8600 [2000] */ - {0x00e89882, 0x00e541}, /* U+8602 */ - {0x00e89884, 0x00ee65}, /* U+8604 [2000] */ - {0x00e89885, 0x00ee66}, /* U+8605 [2000] */ - {0x00e89886, 0x00e562}, /* U+8606 */ - {0x00e89887, 0x009168}, /* U+8607 */ - {0x00e8988a, 0x00e55d}, /* U+860A */ - {0x00e8988b, 0x00e55f}, /* U+860B */ - {0x00e89890, 0x00ee67}, /* U+8610 [2000] */ - {0x00e89891, 0x00f94d}, /* U+8611 [2000] */ - {0x00e89892, 0x00ee63}, /* U+8612 [2000] */ - {0x00e89893, 0x00e55e}, /* U+8613 */ - {0x00e89896, 0x009f50}, /* U+8616 */ - {0x00e89897, 0x009f41}, /* U+8617 */ - {0x00e89898, 0x00ee69}, /* U+8618 [2000] */ - {0x00e8989a, 0x00e564}, /* U+861A */ - {0x00e8989e, 0x00f94e}, /* U+861E [2000] */ - {0x00e898a1, 0x00f94f}, /* U+8621 [2000] */ - {0x00e898a2, 0x00e563}, /* U+8622 */ - {0x00e898a4, 0x00f950}, /* U+8624 [2000] */ - {0x00e898a7, 0x00f951}, /* U+8627 [2000] */ - {0x00e898a9, 0x00ee6a}, /* U+8629 [2000] */ - {0x00e898ad, 0x009796}, /* U+862D */ - {0x00e898af, 0x00e1ba}, /* U+862F */ - {0x00e898b0, 0x00e565}, /* U+8630 */ - {0x00e898b8, 0x00ee6b}, /* U+8638 [2000] */ - {0x00e898b9, 0x00f953}, /* U+8639 [2000] */ - {0x00e898bc, 0x00f954}, /* U+863C [2000] */ - {0x00e898bf, 0x00e566}, /* U+863F */ - {0x00e89980, 0x00f956}, /* U+8640 [2000] */ - {0x00e89981, 0x008888}, /* U+8641 [2000] */ - {0x00e8998d, 0x00e567}, /* U+864D */ - {0x00e8998e, 0x008cd5}, /* U+864E */ - {0x00e89990, 0x008b73}, /* U+8650 */ - {0x00e89993, 0x00f958}, /* U+8653 [2000] */ - {0x00e89994, 0x00e569}, /* U+8654 */ - {0x00e89995, 0x00997c}, /* U+8655 */ - {0x00e89996, 0x00f959}, /* U+8656 [2000] */ - {0x00e89997, 0x00ee6c}, /* U+8657 [2000] */ - {0x00e8999a, 0x008b95}, /* U+865A */ - {0x00e8999b, 0x00ee6d}, /* U+865B [2000] */ - {0x00e8999c, 0x0097b8}, /* U+865C */ - {0x00e8999e, 0x008bf1}, /* U+865E */ - {0x00e8999f, 0x00e56a}, /* U+865F */ - {0x00e899a2, 0x00ee6f}, /* U+8662 [2000] */ - {0x00e899a7, 0x00e56b}, /* U+8667 */ - {0x00e899ab, 0x00928e}, /* U+866B */ - {0x00e899ac, 0x00ee71}, /* U+866C [2000] */ - {0x00e899af, 0x00f95a}, /* U+866F [2000] */ - {0x00e899b1, 0x00e56c}, /* U+8671 */ - {0x00e899b5, 0x00ee72}, /* U+8675 [2000] */ - {0x00e899b7, 0x00f95b}, /* U+8677 [2000] */ - {0x00e899b9, 0x0093f8}, /* U+8679 */ - {0x00e899ba, 0x00f95c}, /* U+867A [2000] */ - {0x00e899bb, 0x0088b8}, /* U+867B */ - {0x00e89a87, 0x00f95d}, /* U+8687 [2000] */ - {0x00e89a89, 0x00f95e}, /* U+8689 [2000] */ - {0x00e89a8a, 0x0089e1}, /* U+868A */ - {0x00e89a8b, 0x00e571}, /* U+868B */ - {0x00e89a8c, 0x00e572}, /* U+868C */ - {0x00e89a8d, 0x00f95f}, /* U+868D [2000] */ - {0x00e89a91, 0x00f960}, /* U+8691 [2000] */ - {0x00e89a93, 0x00e56d}, /* U+8693 */ - {0x00e89a95, 0x008e5c}, /* U+8695 */ - {0x00e89a98, 0x00ee73}, /* U+8698 [2000] */ - {0x00e89a9c, 0x00f961}, /* U+869C [2000] */ - {0x00e89a9d, 0x00f962}, /* U+869D [2000] */ - {0x00e89aa3, 0x00e56e}, /* U+86A3 */ - {0x00e89aa4, 0x009461}, /* U+86A4 */ - {0x00e89aa8, 0x00f963}, /* U+86A8 [2000] */ - {0x00e89aa9, 0x00e56f}, /* U+86A9 */ - {0x00e89aaa, 0x00e570}, /* U+86AA */ - {0x00e89aab, 0x00e57a}, /* U+86AB */ - {0x00e89aaf, 0x00e574}, /* U+86AF */ - {0x00e89ab0, 0x00e577}, /* U+86B0 */ - {0x00e89ab1, 0x00f965}, /* U+86B1 [2000] */ - {0x00e89ab3, 0x00f966}, /* U+86B3 [2000] */ - {0x00e89ab6, 0x00e573}, /* U+86B6 */ - {0x00e89ab8, 0x00ee74}, /* U+86B8 [2000] */ - {0x00e89b81, 0x00f967}, /* U+86C1 [2000] */ - {0x00e89b83, 0x00f968}, /* U+86C3 [2000] */ - {0x00e89b84, 0x00e575}, /* U+86C4 */ - {0x00e89b86, 0x00e576}, /* U+86C6 */ - {0x00e89b87, 0x008ed6}, /* U+86C7 */ - {0x00e89b89, 0x00e578}, /* U+86C9 */ - {0x00e89b8b, 0x009260}, /* U+86CB */ - {0x00e89b8d, 0x008c75}, /* U+86CD */ - {0x00e89b8e, 0x008a61}, /* U+86CE */ - {0x00e89b91, 0x00f969}, /* U+86D1 [2000] */ - {0x00e89b94, 0x00e57b}, /* U+86D4 */ - {0x00e89b95, 0x00f96a}, /* U+86D5 [2000] */ - {0x00e89b97, 0x00f96b}, /* U+86D7 [2000] */ - {0x00e89b99, 0x008a5e}, /* U+86D9 */ - {0x00e89b9b, 0x00e581}, /* U+86DB */ - {0x00e89b9e, 0x00e57c}, /* U+86DE */ - {0x00e89b9f, 0x00e580}, /* U+86DF */ - {0x00e89ba3, 0x00f96c}, /* U+86E3 [2000] */ - {0x00e89ba4, 0x0094b8}, /* U+86E4 */ - {0x00e89ba6, 0x00f96d}, /* U+86E6 [2000] */ - {0x00e89ba9, 0x00e57d}, /* U+86E9 */ - {0x00e89bac, 0x00e57e}, /* U+86EC */ - {0x00e89bad, 0x009567}, /* U+86ED */ - {0x00e89bae, 0x0094d8}, /* U+86EE */ - {0x00e89baf, 0x00e582}, /* U+86EF */ - {0x00e89bb8, 0x0091fb}, /* U+86F8 */ - {0x00e89bb9, 0x00e58c}, /* U+86F9 */ - {0x00e89bba, 0x00ee75}, /* U+86FA [2000] */ - {0x00e89bbb, 0x00e588}, /* U+86FB */ - {0x00e89bbc, 0x00ee76}, /* U+86FC [2000] */ - {0x00e89bbd, 0x00ee77}, /* U+86FD [2000] */ - {0x00e89bbe, 0x0089e9}, /* U+86FE */ - {0x00e89c80, 0x00e586}, /* U+8700 */ - {0x00e89c82, 0x009649}, /* U+8702 */ - {0x00e89c83, 0x00e587}, /* U+8703 */ - {0x00e89c85, 0x00f96f}, /* U+8705 [2000] */ - {0x00e89c86, 0x00e584}, /* U+8706 */ - {0x00e89c87, 0x00f970}, /* U+8707 [2000] */ - {0x00e89c88, 0x00e585}, /* U+8708 */ - {0x00e89c89, 0x00e58a}, /* U+8709 */ - {0x00e89c8a, 0x00e58d}, /* U+870A */ - {0x00e89c8b, 0x00ee78}, /* U+870B [2000] */ - {0x00e89c8d, 0x00e58b}, /* U+870D */ - {0x00e89c8e, 0x00f971}, /* U+870E [2000] */ - {0x00e89c90, 0x00f972}, /* U+8710 [2000] */ - {0x00e89c91, 0x00e589}, /* U+8711 */ - {0x00e89c92, 0x00e583}, /* U+8712 */ - {0x00e89c93, 0x00f973}, /* U+8713 [2000] */ - {0x00e89c98, 0x009277}, /* U+8718 */ - {0x00e89c99, 0x00f974}, /* U+8719 [2000] */ - {0x00e89c9a, 0x00e594}, /* U+871A */ - {0x00e89c9c, 0x0096a8}, /* U+871C */ - {0x00e89c9f, 0x00f975}, /* U+871F [2000] */ - {0x00e89ca1, 0x00f976}, /* U+8721 [2000] */ - {0x00e89ca3, 0x00f977}, /* U+8723 [2000] */ - {0x00e89ca5, 0x00e592}, /* U+8725 */ - {0x00e89ca9, 0x00e593}, /* U+8729 */ - {0x00e89cb1, 0x00f978}, /* U+8731 [2000] */ - {0x00e89cb4, 0x00e58e}, /* U+8734 */ - {0x00e89cb7, 0x00e590}, /* U+8737 */ - {0x00e89cba, 0x00f979}, /* U+873A [2000] */ - {0x00e89cbb, 0x00e591}, /* U+873B */ - {0x00e89cbe, 0x00f97a}, /* U+873E [2000] */ - {0x00e89cbf, 0x00e58f}, /* U+873F */ - {0x00e89d80, 0x00f97b}, /* U+8740 [2000] */ - {0x00e89d83, 0x00f97c}, /* U+8743 [2000] */ - {0x00e89d89, 0x0090e4}, /* U+8749 */ - {0x00e89d8b, 0x009858}, /* U+874B */ - {0x00e89d8c, 0x00e598}, /* U+874C */ - {0x00e89d8e, 0x00e599}, /* U+874E */ - {0x00e89d91, 0x00f97d}, /* U+8751 [2000] */ - {0x00e89d93, 0x00e59f}, /* U+8753 */ - {0x00e89d95, 0x009049}, /* U+8755 */ - {0x00e89d97, 0x00e59b}, /* U+8757 */ - {0x00e89d98, 0x00f97e}, /* U+8758 [2000] */ - {0x00e89d99, 0x00e59e}, /* U+8759 */ - {0x00e89d9f, 0x00e596}, /* U+875F */ - {0x00e89da0, 0x00e595}, /* U+8760 */ - {0x00e89da3, 0x00e5a0}, /* U+8763 */ - {0x00e89da4, 0x00f980}, /* U+8764 [2000] */ - {0x00e89da5, 0x00f981}, /* U+8765 [2000] */ - {0x00e89da6, 0x0089da}, /* U+8766 */ - {0x00e89da8, 0x00e59c}, /* U+8768 */ - {0x00e89daa, 0x00e5a1}, /* U+876A */ - {0x00e89dae, 0x00e59d}, /* U+876E */ - {0x00e89db1, 0x00ee79}, /* U+8771 [2000] */ - {0x00e89db2, 0x00f982}, /* U+8772 [2000] */ - {0x00e89db4, 0x00e59a}, /* U+8774 */ - {0x00e89db6, 0x0092b1}, /* U+8776 */ - {0x00e89db8, 0x00e597}, /* U+8778 */ - {0x00e89dbc, 0x00f983}, /* U+877C [2000] */ - {0x00e89dbf, 0x009488}, /* U+877F */ - {0x00e89e82, 0x00e5a5}, /* U+8782 */ - {0x00e89e87, 0x00ee7a}, /* U+8787 [2000] */ - {0x00e89e88, 0x00ee7b}, /* U+8788 [2000] */ - {0x00e89e89, 0x00f987}, /* U+8789 [2000] */ - {0x00e89e8b, 0x00f988}, /* U+878B [2000] */ - {0x00e89e8d, 0x00975a}, /* U+878D */ - {0x00e89e93, 0x00f989}, /* U+8793 [2000] */ - {0x00e89e9f, 0x00e5a4}, /* U+879F */ - {0x00e89ea0, 0x00f98a}, /* U+87A0 [2000] */ - {0x00e89ea2, 0x00e5a3}, /* U+87A2 */ - {0x00e89ea7, 0x00f986}, /* U+87A7 [2000] */ - {0x00e89eab, 0x00e5ac}, /* U+87AB */ - {0x00e89eac, 0x00ee7c}, /* U+87AC [2000] */ - {0x00e89ead, 0x00ee7d}, /* U+87AD [2000] */ - {0x00e89eaf, 0x00e5a6}, /* U+87AF */ - {0x00e89eb3, 0x00e5ae}, /* U+87B3 */ - {0x00e89eb5, 0x00ee7e}, /* U+87B5 [2000] */ - {0x00e89eba, 0x009786}, /* U+87BA */ - {0x00e89ebb, 0x00e5b1}, /* U+87BB */ - {0x00e89ebd, 0x00e5a8}, /* U+87BD */ - {0x00e89ebe, 0x00f98d}, /* U+87BE [2000] */ - {0x00e89f80, 0x00e5a9}, /* U+87C0 */ - {0x00e89f81, 0x00f98f}, /* U+87C1 [2000] */ - {0x00e89f84, 0x00e5ad}, /* U+87C4 */ - {0x00e89f86, 0x00e5b0}, /* U+87C6 */ - {0x00e89f87, 0x00e5af}, /* U+87C7 */ - {0x00e89f8b, 0x00e5a7}, /* U+87CB */ - {0x00e89f8e, 0x00f990}, /* U+87CE [2000] */ - {0x00e89f90, 0x00e5aa}, /* U+87D0 */ - {0x00e89f92, 0x00e5bb}, /* U+87D2 */ - {0x00e89f96, 0x00ee81}, /* U+87D6 [2000] */ - {0x00e89f9f, 0x00f992}, /* U+87DF [2000] */ - {0x00e89fa0, 0x00e5b4}, /* U+87E0 */ - {0x00e89fa3, 0x00f994}, /* U+87E3 [2000] */ - {0x00e89fa5, 0x00f995}, /* U+87E5 [2000] */ - {0x00e89fa6, 0x00f996}, /* U+87E6 [2000] */ - {0x00e89faa, 0x00f997}, /* U+87EA [2000] */ - {0x00e89fab, 0x00f998}, /* U+87EB [2000] */ - {0x00e89fac, 0x00ee82}, /* U+87EC [2000] */ - {0x00e89fad, 0x00f999}, /* U+87ED [2000] */ - {0x00e89faf, 0x00e5b2}, /* U+87EF */ - {0x00e89fb2, 0x00e5b3}, /* U+87F2 */ - {0x00e89fb5, 0x00f991}, /* U+87F5 [2000] */ - {0x00e89fb6, 0x00e5b8}, /* U+87F6 */ - {0x00e89fb7, 0x00e5b9}, /* U+87F7 */ - {0x00e89fb9, 0x008a49}, /* U+87F9 */ - {0x00e89fbb, 0x008b61}, /* U+87FB */ - {0x00e89fbe, 0x00e5b7}, /* U+87FE */ - {0x00e8a081, 0x00f99a}, /* U+8801 [2000] */ - {0x00e8a083, 0x00f99b}, /* U+8803 [2000] */ - {0x00e8a085, 0x00e5a2}, /* U+8805 */ - {0x00e8a086, 0x00ee83}, /* U+8806 [2000] */ - {0x00e8a08a, 0x00ee84}, /* U+880A [2000] */ - {0x00e8a08b, 0x00f99c}, /* U+880B [2000] */ - {0x00e8a08d, 0x00e5b6}, /* U+880D */ - {0x00e8a08e, 0x00e5ba}, /* U+880E */ - {0x00e8a08f, 0x00e5b5}, /* U+880F */ - {0x00e8a090, 0x00ee85}, /* U+8810 [2000] */ - {0x00e8a091, 0x00e5bc}, /* U+8811 */ - {0x00e8a093, 0x00f99d}, /* U+8813 [2000] */ - {0x00e8a094, 0x00ee86}, /* U+8814 [2000] */ - {0x00e8a095, 0x00e5be}, /* U+8815 */ - {0x00e8a096, 0x00e5bd}, /* U+8816 */ - {0x00e8a09f, 0x00ee87}, /* U+881F [2000] */ - {0x00e8a0a1, 0x00e5c0}, /* U+8821 */ - {0x00e8a0a2, 0x00e5bf}, /* U+8822 */ - {0x00e8a0a3, 0x00e579}, /* U+8823 */ - {0x00e8a0a7, 0x00e5c4}, /* U+8827 */ - {0x00e8a0a8, 0x00f99e}, /* U+8828 [2000] */ - {0x00e8a0ae, 0x00f99f}, /* U+882E [2000] */ - {0x00e8a0b1, 0x00e5c1}, /* U+8831 */ - {0x00e8a0b2, 0x00f9a0}, /* U+8832 [2000] */ - {0x00e8a0b6, 0x00e5c2}, /* U+8836 */ - {0x00e8a0b9, 0x00e5c3}, /* U+8839 */ - {0x00e8a0bb, 0x00e5c5}, /* U+883B */ - {0x00e8a0bc, 0x00f9a1}, /* U+883C [2000] */ - {0x00e8a180, 0x008c8c}, /* U+8840 */ - {0x00e8a182, 0x00e5c7}, /* U+8842 */ - {0x00e8a184, 0x00e5c6}, /* U+8844 */ - {0x00e8a186, 0x008f4f}, /* U+8846 */ - {0x00e8a18a, 0x00f9a3}, /* U+884A [2000] */ - {0x00e8a18c, 0x008d73}, /* U+884C */ - {0x00e8a18d, 0x009fa5}, /* U+884D */ - {0x00e8a192, 0x00e5c8}, /* U+8852 */ - {0x00e8a193, 0x008f70}, /* U+8853 */ - {0x00e8a197, 0x008a58}, /* U+8857 */ - {0x00e8a198, 0x00f9a4}, /* U+8858 [2000] */ - {0x00e8a199, 0x00e5c9}, /* U+8859 */ - {0x00e8a19b, 0x008971}, /* U+885B */ - {0x00e8a19d, 0x008fd5}, /* U+885D */ - {0x00e8a19e, 0x00e5ca}, /* U+885E */ - {0x00e8a19f, 0x00f9a5}, /* U+885F [2000] */ - {0x00e8a1a1, 0x008d74}, /* U+8861 */ - {0x00e8a1a2, 0x00e5cb}, /* U+8862 */ - {0x00e8a1a3, 0x0088df}, /* U+8863 */ - {0x00e8a1a4, 0x00f9a6}, /* U+8864 [2000] */ - {0x00e8a1a8, 0x00955c}, /* U+8868 */ - {0x00e8a1a9, 0x00f9a9}, /* U+8869 [2000] */ - {0x00e8a1ab, 0x00e5cc}, /* U+886B */ - {0x00e8a1af, 0x00f9ab}, /* U+886F [2000] */ - {0x00e8a1b0, 0x00908a}, /* U+8870 */ - {0x00e8a1b2, 0x00e5d3}, /* U+8872 */ - {0x00e8a1b5, 0x00e5d0}, /* U+8875 */ - {0x00e8a1b7, 0x00928f}, /* U+8877 */ - {0x00e8a1bd, 0x00e5d1}, /* U+887D */ - {0x00e8a1be, 0x00e5ce}, /* U+887E */ - {0x00e8a1bf, 0x008bdc}, /* U+887F */ - {0x00e8a281, 0x00e5cd}, /* U+8881 */ - {0x00e8a282, 0x00e5d4}, /* U+8882 */ - {0x00e8a288, 0x008c55}, /* U+8888 */ - {0x00e8a28b, 0x0091dc}, /* U+888B */ - {0x00e8a28d, 0x00e5da}, /* U+888D */ - {0x00e8a292, 0x00e5d6}, /* U+8892 */ - {0x00e8a296, 0x0091b3}, /* U+8896 */ - {0x00e8a297, 0x00e5d5}, /* U+8897 */ - {0x00e8a298, 0x00ee88}, /* U+8898 [2000] */ - {0x00e8a299, 0x00e5d8}, /* U+8899 */ - {0x00e8a29e, 0x00e5cf}, /* U+889E */ - {0x00e8a2a0, 0x00f9ac}, /* U+88A0 [2000] */ - {0x00e8a2a2, 0x00e5d9}, /* U+88A2 */ - {0x00e8a2a4, 0x00e5db}, /* U+88A4 */ - {0x00e8a2aa, 0x00ee89}, /* U+88AA [2000] */ - {0x00e8a2ab, 0x0094ed}, /* U+88AB */ - {0x00e8a2ae, 0x00e5d7}, /* U+88AE */ - {0x00e8a2b0, 0x00e5dc}, /* U+88B0 */ - {0x00e8a2b1, 0x00e5de}, /* U+88B1 */ - {0x00e8a2b4, 0x008cd1}, /* U+88B4 */ - {0x00e8a2b5, 0x00e5d2}, /* U+88B5 */ - {0x00e8a2b7, 0x0088bf}, /* U+88B7 */ - {0x00e8a2bc, 0x00f9ad}, /* U+88BC [2000] */ - {0x00e8a2bd, 0x00f9ae}, /* U+88BD [2000] */ - {0x00e8a2be, 0x00f9af}, /* U+88BE [2000] */ - {0x00e8a2bf, 0x00e5dd}, /* U+88BF */ - {0x00e8a380, 0x00f9b0}, /* U+88C0 [2000] */ - {0x00e8a381, 0x008dd9}, /* U+88C1 */ - {0x00e8a382, 0x0097f4}, /* U+88C2 */ - {0x00e8a383, 0x00e5df}, /* U+88C3 */ - {0x00e8a384, 0x00e5e0}, /* U+88C4 */ - {0x00e8a385, 0x009195}, /* U+88C5 */ - {0x00e8a38a, 0x00ee8a}, /* U+88CA [2000] */ - {0x00e8a38e, 0x00ee8b}, /* U+88CE [2000] */ - {0x00e8a38f, 0x0097a0}, /* U+88CF */ - {0x00e8a391, 0x00f9b3}, /* U+88D1 [2000] */ - {0x00e8a392, 0x00f9b1}, /* U+88D2 [2000] */ - {0x00e8a393, 0x00f9b4}, /* U+88D3 [2000] */ - {0x00e8a394, 0x00e5e1}, /* U+88D4 */ - {0x00e8a395, 0x009754}, /* U+88D5 */ - {0x00e8a398, 0x00e5e2}, /* U+88D8 */ - {0x00e8a399, 0x00e5e3}, /* U+88D9 */ - {0x00e8a39b, 0x00f9b5}, /* U+88DB [2000] */ - {0x00e8a39c, 0x0095e2}, /* U+88DC */ - {0x00e8a39d, 0x00e5e4}, /* U+88DD */ - {0x00e8a39f, 0x008dbe}, /* U+88DF */ - {0x00e8a3a1, 0x0097a1}, /* U+88E1 */ - {0x00e8a3a8, 0x00e5e9}, /* U+88E8 */ - {0x00e8a3b0, 0x00f9b6}, /* U+88F0 [2000] */ - {0x00e8a3b1, 0x00f9b7}, /* U+88F1 [2000] */ - {0x00e8a3b2, 0x00e5ea}, /* U+88F2 */ - {0x00e8a3b3, 0x008fd6}, /* U+88F3 */ - {0x00e8a3b4, 0x00e5e8}, /* U+88F4 */ - {0x00e8a3b5, 0x00ee8d}, /* U+88F5 [2000] */ - {0x00e8a3b8, 0x009787}, /* U+88F8 */ - {0x00e8a3b9, 0x00e5e5}, /* U+88F9 */ - {0x00e8a3bc, 0x00e5e7}, /* U+88FC */ - {0x00e8a3bd, 0x0090bb}, /* U+88FD */ - {0x00e8a3be, 0x00909e}, /* U+88FE */ - {0x00e8a481, 0x00f9b9}, /* U+8901 [2000] */ - {0x00e8a482, 0x00e5e6}, /* U+8902 */ - {0x00e8a484, 0x00e5eb}, /* U+8904 */ - {0x00e8a487, 0x0095a1}, /* U+8907 */ - {0x00e8a48a, 0x00e5ed}, /* U+890A */ - {0x00e8a48c, 0x00e5ec}, /* U+890C */ - {0x00e8a490, 0x008a8c}, /* U+8910 */ - {0x00e8a492, 0x00964a}, /* U+8912 */ - {0x00e8a493, 0x00e5ee}, /* U+8913 */ - {0x00e8a498, 0x00ee90}, /* U+8918 [2000] */ - {0x00e8a499, 0x00ee91}, /* U+8919 [2000] */ - {0x00e8a49a, 0x00ee92}, /* U+891A [2000] */ - {0x00e8a49c, 0x00ee8e}, /* U+891C [2000] */ - {0x00e8a49d, 0x00e5fa}, /* U+891D */ - {0x00e8a49e, 0x00e5f0}, /* U+891E */ - {0x00e8a4a5, 0x00e5f1}, /* U+8925 */ - {0x00e8a4a7, 0x00ee93}, /* U+8927 [2000] */ - {0x00e8a4aa, 0x00e5f2}, /* U+892A */ - {0x00e8a4ab, 0x00e5f3}, /* U+892B */ - {0x00e8a4b0, 0x00ee94}, /* U+8930 [2000] */ - {0x00e8a4b2, 0x00ee95}, /* U+8932 [2000] */ - {0x00e8a4b6, 0x00e5f7}, /* U+8936 */ - {0x00e8a4b7, 0x00f9bb}, /* U+8937 [2000] */ - {0x00e8a4b8, 0x00e5f8}, /* U+8938 */ - {0x00e8a4b9, 0x00ee96}, /* U+8939 [2000] */ - {0x00e8a4bb, 0x00e5f6}, /* U+893B */ - {0x00e8a580, 0x00ee97}, /* U+8940 [2000] */ - {0x00e8a581, 0x00e5f4}, /* U+8941 */ - {0x00e8a582, 0x00f9bd}, /* U+8942 [2000] */ - {0x00e8a583, 0x00e5ef}, /* U+8943 */ - {0x00e8a584, 0x00e5f5}, /* U+8944 */ - {0x00e8a585, 0x00f9be}, /* U+8945 [2000] */ - {0x00e8a589, 0x00f9bf}, /* U+8949 [2000] */ - {0x00e8a58c, 0x00e5f9}, /* U+894C */ - {0x00e8a58d, 0x00e8b5}, /* U+894D */ - {0x00e8a596, 0x0089a6}, /* U+8956 */ - {0x00e8a59e, 0x00e5fc}, /* U+895E */ - {0x00e8a59f, 0x008bdd}, /* U+895F */ - {0x00e8a5a0, 0x00e5fb}, /* U+8960 */ - {0x00e8a5a2, 0x00f9c2}, /* U+8962 [2000] */ - {0x00e8a5a4, 0x00e641}, /* U+8964 */ - {0x00e8a5a6, 0x00e640}, /* U+8966 */ - {0x00e8a5aa, 0x00e643}, /* U+896A */ - {0x00e8a5ad, 0x00e642}, /* U+896D */ - {0x00e8a5af, 0x00e644}, /* U+896F */ - {0x00e8a5b2, 0x008f50}, /* U+8972 */ - {0x00e8a5b4, 0x00e645}, /* U+8974 */ - {0x00e8a5b7, 0x00e646}, /* U+8977 */ - {0x00e8a5be, 0x00e647}, /* U+897E */ - {0x00e8a5bf, 0x0090bc}, /* U+897F */ - {0x00e8a680, 0x00f9c3}, /* U+8980 [2000] */ - {0x00e8a681, 0x009776}, /* U+8981 */ - {0x00e8a683, 0x00e648}, /* U+8983 */ - {0x00e8a686, 0x0095a2}, /* U+8986 */ - {0x00e8a687, 0x009465}, /* U+8987 */ - {0x00e8a688, 0x00e649}, /* U+8988 */ - {0x00e8a689, 0x00f9c4}, /* U+8989 [2000] */ - {0x00e8a68a, 0x00e64a}, /* U+898A */ - {0x00e8a68b, 0x008ca9}, /* U+898B */ - {0x00e8a68f, 0x008b4b}, /* U+898F */ - {0x00e8a690, 0x00f9c5}, /* U+8990 [2000] */ - {0x00e8a693, 0x00e64b}, /* U+8993 */ - {0x00e8a694, 0x00ee98}, /* U+8994 [2000] */ - {0x00e8a696, 0x008e8b}, /* U+8996 */ - {0x00e8a697, 0x009460}, /* U+8997 */ - {0x00e8a698, 0x00e64c}, /* U+8998 */ - {0x00e8a69a, 0x008a6f}, /* U+899A */ - {0x00e8a69f, 0x00f9c6}, /* U+899F [2000] */ - {0x00e8a6a1, 0x00e64d}, /* U+89A1 */ - {0x00e8a6a6, 0x00e64f}, /* U+89A6 */ - {0x00e8a6a7, 0x009797}, /* U+89A7 */ - {0x00e8a6a9, 0x00e64e}, /* U+89A9 */ - {0x00e8a6aa, 0x009065}, /* U+89AA */ - {0x00e8a6ac, 0x00e650}, /* U+89AC */ - {0x00e8a6af, 0x00e651}, /* U+89AF */ - {0x00e8a6b0, 0x00f9c7}, /* U+89B0 [2000] */ - {0x00e8a6b2, 0x00e652}, /* U+89B2 */ - {0x00e8a6b3, 0x008acf}, /* U+89B3 */ - {0x00e8a6b7, 0x00f9c8}, /* U+89B7 [2000] */ - {0x00e8a6ba, 0x00e653}, /* U+89BA */ - {0x00e8a6bd, 0x00e654}, /* U+89BD */ - {0x00e8a6bf, 0x00e655}, /* U+89BF */ - {0x00e8a780, 0x00e656}, /* U+89C0 */ - {0x00e8a792, 0x008a70}, /* U+89D2 */ - {0x00e8a794, 0x00ee9a}, /* U+89D4 [2000] */ - {0x00e8a796, 0x00f9c9}, /* U+89D6 [2000] */ - {0x00e8a798, 0x00f9ca}, /* U+89D8 [2000] */ - {0x00e8a79a, 0x00e657}, /* U+89DA */ - {0x00e8a79c, 0x00e658}, /* U+89DC */ - {0x00e8a79d, 0x00e659}, /* U+89DD */ - {0x00e8a7a3, 0x0089f0}, /* U+89E3 */ - {0x00e8a7a5, 0x00ee9b}, /* U+89E5 [2000] */ - {0x00e8a7a6, 0x009047}, /* U+89E6 */ - {0x00e8a7a7, 0x00e65a}, /* U+89E7 */ - {0x00e8a7ab, 0x00f9cb}, /* U+89EB [2000] */ - {0x00e8a7b1, 0x00f9cd}, /* U+89F1 [2000] */ - {0x00e8a7b3, 0x00f9ce}, /* U+89F3 [2000] */ - {0x00e8a7b4, 0x00e65b}, /* U+89F4 */ - {0x00e8a7b6, 0x00ee9c}, /* U+89F6 [2000] */ - {0x00e8a7b8, 0x00e65c}, /* U+89F8 */ - {0x00e8a7bd, 0x00f9cf}, /* U+89FD [2000] */ - {0x00e8a7bf, 0x00f9d0}, /* U+89FF [2000] */ - {0x00e8a880, 0x008cbe}, /* U+8A00 */ - {0x00e8a882, 0x0092f9}, /* U+8A02 */ - {0x00e8a883, 0x00e65d}, /* U+8A03 */ - {0x00e8a888, 0x008c76}, /* U+8A08 */ - {0x00e8a88a, 0x009075}, /* U+8A0A */ - {0x00e8a88c, 0x00e660}, /* U+8A0C */ - {0x00e8a88e, 0x0093a2}, /* U+8A0E */ - {0x00e8a890, 0x00e65f}, /* U+8A10 */ - {0x00e8a891, 0x00f9d2}, /* U+8A11 [2000] */ - {0x00e8a892, 0x00ee9d}, /* U+8A12 [2000] */ - {0x00e8a893, 0x008c50}, /* U+8A13 */ - {0x00e8a894, 0x00f9d3}, /* U+8A14 [2000] */ - {0x00e8a895, 0x00ee9e}, /* U+8A15 [2000] */ - {0x00e8a896, 0x00e65e}, /* U+8A16 */ - {0x00e8a897, 0x0091f5}, /* U+8A17 */ - {0x00e8a898, 0x008b4c}, /* U+8A18 */ - {0x00e8a89b, 0x00e661}, /* U+8A1B */ - {0x00e8a89d, 0x00e662}, /* U+8A1D */ - {0x00e8a89f, 0x008fd7}, /* U+8A1F */ - {0x00e8a8a1, 0x00f9d5}, /* U+8A21 [2000] */ - {0x00e8a8a2, 0x00ee9f}, /* U+8A22 [2000] */ - {0x00e8a8a3, 0x008c8d}, /* U+8A23 */ - {0x00e8a8a5, 0x00e663}, /* U+8A25 */ - {0x00e8a8aa, 0x00964b}, /* U+8A2A */ - {0x00e8a8ad, 0x0090dd}, /* U+8A2D */ - {0x00e8a8b1, 0x008b96}, /* U+8A31 */ - {0x00e8a8b3, 0x0096f3}, /* U+8A33 */ - {0x00e8a8b4, 0x009169}, /* U+8A34 */ - {0x00e8a8b5, 0x00f9d6}, /* U+8A35 [2000] */ - {0x00e8a8b6, 0x00e664}, /* U+8A36 */ - {0x00e8a8b7, 0x00eea0}, /* U+8A37 [2000] */ - {0x00e8a8ba, 0x009066}, /* U+8A3A */ - {0x00e8a8bb, 0x009290}, /* U+8A3B */ - {0x00e8a8bc, 0x008fd8}, /* U+8A3C */ - {0x00e8a8be, 0x00f9d7}, /* U+8A3E [2000] */ - {0x00e8a981, 0x00e665}, /* U+8A41 */ - {0x00e8a985, 0x00f9d8}, /* U+8A45 [2000] */ - {0x00e8a986, 0x00e668}, /* U+8A46 */ - {0x00e8a987, 0x00eea1}, /* U+8A47 [2000] */ - {0x00e8a988, 0x00e669}, /* U+8A48 */ - {0x00e8a98d, 0x00f9d9}, /* U+8A4D [2000] */ - {0x00e8a98e, 0x00eea2}, /* U+8A4E [2000] */ - {0x00e8a990, 0x008dbc}, /* U+8A50 */ - {0x00e8a991, 0x0091c0}, /* U+8A51 */ - {0x00e8a992, 0x00e667}, /* U+8A52 */ - {0x00e8a994, 0x008fd9}, /* U+8A54 */ - {0x00e8a995, 0x00955d}, /* U+8A55 */ - {0x00e8a998, 0x00f9da}, /* U+8A58 [2000] */ - {0x00e8a99b, 0x00e666}, /* U+8A5B */ - {0x00e8a99d, 0x00eea3}, /* U+8A5D [2000] */ - {0x00e8a99e, 0x008e8c}, /* U+8A5E */ - {0x00e8a9a0, 0x008972}, /* U+8A60 */ - {0x00e8a9a1, 0x00eea4}, /* U+8A61 [2000] */ - {0x00e8a9a2, 0x00e66d}, /* U+8A62 */ - {0x00e8a9a3, 0x008c77}, /* U+8A63 */ - {0x00e8a9a6, 0x008e8e}, /* U+8A66 */ - {0x00e8a9a9, 0x008e8d}, /* U+8A69 */ - {0x00e8a9ab, 0x00986c}, /* U+8A6B */ - {0x00e8a9ac, 0x00e66c}, /* U+8A6C */ - {0x00e8a9ad, 0x00e66b}, /* U+8A6D */ - {0x00e8a9ae, 0x009146}, /* U+8A6E */ - {0x00e8a9b0, 0x008b6c}, /* U+8A70 */ - {0x00e8a9b1, 0x009862}, /* U+8A71 */ - {0x00e8a9b2, 0x008a59}, /* U+8A72 */ - {0x00e8a9b3, 0x008fda}, /* U+8A73 */ - {0x00e8a9b5, 0x00eea5}, /* U+8A75 [2000] */ - {0x00e8a9b9, 0x00eea6}, /* U+8A79 [2000] */ - {0x00e8a9bc, 0x00e66a}, /* U+8A7C */ - {0x00e8aa82, 0x00e66f}, /* U+8A82 */ - {0x00e8aa84, 0x00e670}, /* U+8A84 */ - {0x00e8aa85, 0x00e66e}, /* U+8A85 */ - {0x00e8aa87, 0x008cd6}, /* U+8A87 */ - {0x00e8aa89, 0x00975f}, /* U+8A89 */ - {0x00e8aa8c, 0x008e8f}, /* U+8A8C */ - {0x00e8aa8d, 0x009446}, /* U+8A8D */ - {0x00e8aa90, 0x00f9dc}, /* U+8A90 [2000] */ - {0x00e8aa91, 0x00e673}, /* U+8A91 */ - {0x00e8aa93, 0x0090be}, /* U+8A93 */ - {0x00e8aa95, 0x009261}, /* U+8A95 */ - {0x00e8aa98, 0x009755}, /* U+8A98 */ - {0x00e8aa9a, 0x00e676}, /* U+8A9A */ - {0x00e8aa9e, 0x008cea}, /* U+8A9E */ - {0x00e8aaa0, 0x0090bd}, /* U+8AA0 */ - {0x00e8aaa1, 0x00e672}, /* U+8AA1 */ - {0x00e8aaa3, 0x00e677}, /* U+8AA3 */ - {0x00e8aaa4, 0x008ceb}, /* U+8AA4 */ - {0x00e8aaa5, 0x00e674}, /* U+8AA5 */ - {0x00e8aaa6, 0x00e675}, /* U+8AA6 */ - {0x00e8aaa7, 0x00eea7}, /* U+8AA7 [2000] */ - {0x00e8aaa8, 0x00e671}, /* U+8AA8 */ - {0x00e8aaac, 0x0090e0}, /* U+8AAC */ - {0x00e8aaad, 0x0093c7}, /* U+8AAD */ - {0x00e8aaae, 0x00f9db}, /* U+8AAE [2000] */ - {0x00e8aab0, 0x00924e}, /* U+8AB0 */ - {0x00e8aab2, 0x0089db}, /* U+8AB2 */ - {0x00e8aab7, 0x00f9dd}, /* U+8AB7 [2000] */ - {0x00e8aab9, 0x0094ee}, /* U+8AB9 */ - {0x00e8aabc, 0x008b62}, /* U+8ABC */ - {0x00e8aabe, 0x00f9de}, /* U+8ABE [2000] */ - {0x00e8aabf, 0x0092b2}, /* U+8ABF */ - {0x00e8ab82, 0x00e67a}, /* U+8AC2 */ - {0x00e8ab84, 0x00e678}, /* U+8AC4 */ - {0x00e8ab87, 0x00926b}, /* U+8AC7 */ - {0x00e8ab8b, 0x0090bf}, /* U+8ACB */ - {0x00e8ab8c, 0x008ad0}, /* U+8ACC */ - {0x00e8ab8d, 0x00e679}, /* U+8ACD */ - {0x00e8ab8f, 0x00907a}, /* U+8ACF */ - {0x00e8ab90, 0x00eea8}, /* U+8AD0 [2000] */ - {0x00e8ab92, 0x0097c8}, /* U+8AD2 */ - {0x00e8ab96, 0x00985f}, /* U+8AD6 */ - {0x00e8ab97, 0x00f9df}, /* U+8AD7 [2000] */ - {0x00e8ab9a, 0x00e67b}, /* U+8ADA */ - {0x00e8ab9b, 0x00e687}, /* U+8ADB */ - {0x00e8ab9c, 0x0092b3}, /* U+8ADC */ - {0x00e8ab9e, 0x00e686}, /* U+8ADE */ - {0x00e8ab9f, 0x00eea9}, /* U+8ADF [2000] */ - {0x00e8aba0, 0x00e683}, /* U+8AE0 */ - {0x00e8aba1, 0x00e68b}, /* U+8AE1 */ - {0x00e8aba2, 0x00e684}, /* U+8AE2 */ - {0x00e8aba4, 0x00e680}, /* U+8AE4 */ - {0x00e8aba6, 0x0092fa}, /* U+8AE6 */ - {0x00e8aba7, 0x00e67e}, /* U+8AE7 */ - {0x00e8abab, 0x00e67c}, /* U+8AEB */ - {0x00e8abad, 0x009740}, /* U+8AED */ - {0x00e8abae, 0x008e90}, /* U+8AEE */ - {0x00e8abb1, 0x00e681}, /* U+8AF1 */ - {0x00e8abb3, 0x00e67d}, /* U+8AF3 */ - {0x00e8abb4, 0x00eeaa}, /* U+8AF4 [2000] */ - {0x00e8abb6, 0x00eeab}, /* U+8AF6 [2000] */ - {0x00e8abb7, 0x00e685}, /* U+8AF7 */ - {0x00e8abb8, 0x008f94}, /* U+8AF8 */ - {0x00e8abba, 0x008cbf}, /* U+8AFA */ - {0x00e8abbc, 0x00f9e0}, /* U+8AFC [2000] */ - {0x00e8abbe, 0x0091f8}, /* U+8AFE */ - {0x00e8ac80, 0x009664}, /* U+8B00 */ - {0x00e8ac81, 0x008979}, /* U+8B01 */ - {0x00e8ac82, 0x0088e0}, /* U+8B02 */ - {0x00e8ac84, 0x0093a3}, /* U+8B04 */ - {0x00e8ac85, 0x00f9e3}, /* U+8B05 [2000] */ - {0x00e8ac87, 0x00e689}, /* U+8B07 */ - {0x00e8ac8a, 0x00f9e2}, /* U+8B0A [2000] */ - {0x00e8ac8c, 0x00e688}, /* U+8B0C */ - {0x00e8ac8d, 0x00f9e4}, /* U+8B0D [2000] */ - {0x00e8ac8e, 0x0093e4}, /* U+8B0E */ - {0x00e8ac90, 0x00e68d}, /* U+8B10 */ - {0x00e8ac94, 0x00e682}, /* U+8B14 */ - {0x00e8ac96, 0x00e68c}, /* U+8B16 */ - {0x00e8ac97, 0x00e68e}, /* U+8B17 */ - {0x00e8ac99, 0x008caa}, /* U+8B19 */ - {0x00e8ac9a, 0x00e68a}, /* U+8B1A */ - {0x00e8ac9b, 0x008d75}, /* U+8B1B */ - {0x00e8ac9c, 0x00f9e5}, /* U+8B1C [2000] */ - {0x00e8ac9d, 0x008ed3}, /* U+8B1D */ - {0x00e8ac9f, 0x00f9e6}, /* U+8B1F [2000] */ - {0x00e8aca0, 0x00e68f}, /* U+8B20 */ - {0x00e8aca1, 0x009777}, /* U+8B21 */ - {0x00e8aca6, 0x00e692}, /* U+8B26 */ - {0x00e8aca8, 0x00e695}, /* U+8B28 */ - {0x00e8acab, 0x00e693}, /* U+8B2B */ - {0x00e8acac, 0x009554}, /* U+8B2C */ - {0x00e8acad, 0x00f9e7}, /* U+8B2D [2000] */ - {0x00e8acb3, 0x00e690}, /* U+8B33 */ - {0x00e8acb9, 0x008bde}, /* U+8B39 */ - {0x00e8acbe, 0x00e694}, /* U+8B3E */ - {0x00e8ad81, 0x00e696}, /* U+8B41 */ - {0x00e8ad83, 0x00f9e8}, /* U+8B43 [2000] */ - {0x00e8ad86, 0x00eeaf}, /* U+8B46 [2000] */ - {0x00e8ad89, 0x00e69a}, /* U+8B49 */ - {0x00e8ad8c, 0x00e697}, /* U+8B4C */ - {0x00e8ad8e, 0x00e699}, /* U+8B4E */ - {0x00e8ad8f, 0x00e698}, /* U+8B4F */ - {0x00e8ad91, 0x00f9ea}, /* U+8B51 [2000] */ - {0x00e8ad94, 0x00eeb0}, /* U+8B54 [2000] */ - {0x00e8ad96, 0x00e69b}, /* U+8B56 */ - {0x00e8ad98, 0x008eaf}, /* U+8B58 */ - {0x00e8ad99, 0x00eeb1}, /* U+8B59 [2000] */ - {0x00e8ad9a, 0x00e69d}, /* U+8B5A */ - {0x00e8ad9b, 0x00e69c}, /* U+8B5B */ - {0x00e8ad9c, 0x009588}, /* U+8B5C */ - {0x00e8ad9e, 0x00f9eb}, /* U+8B5E [2000] */ - {0x00e8ad9f, 0x00e69f}, /* U+8B5F */ - {0x00e8ada6, 0x008c78}, /* U+8B66 */ - {0x00e8ada9, 0x00eeb2}, /* U+8B69 [2000] */ - {0x00e8adab, 0x00e69e}, /* U+8B6B */ - {0x00e8adac, 0x00e6a0}, /* U+8B6C */ - {0x00e8adaf, 0x00e6a1}, /* U+8B6F */ - {0x00e8adb0, 0x008b63}, /* U+8B70 */ - {0x00e8adb1, 0x00e3bf}, /* U+8B71 */ - {0x00e8adb2, 0x008ff7}, /* U+8B72 */ - {0x00e8adb4, 0x00e6a2}, /* U+8B74 */ - {0x00e8adb6, 0x00f9ec}, /* U+8B76 [2000] */ - {0x00e8adb7, 0x008cec}, /* U+8B77 */ - {0x00e8adbd, 0x00e6a3}, /* U+8B7D */ - {0x00e8adbf, 0x00f9ed}, /* U+8B7F [2000] */ - {0x00e8ae80, 0x00e6a4}, /* U+8B80 */ - {0x00e8ae81, 0x00f9ee}, /* U+8B81 [2000] */ - {0x00e8ae83, 0x008e5d}, /* U+8B83 */ - {0x00e8ae8a, 0x009dcc}, /* U+8B8A */ - {0x00e8ae8b, 0x00f9ef}, /* U+8B8B [2000] */ - {0x00e8ae8c, 0x00e6a5}, /* U+8B8C */ - {0x00e8ae8e, 0x00e6a6}, /* U+8B8E */ - {0x00e8ae90, 0x008f51}, /* U+8B90 */ - {0x00e8ae92, 0x00e6a7}, /* U+8B92 */ - {0x00e8ae93, 0x00e6a8}, /* U+8B93 */ - {0x00e8ae94, 0x00f9f0}, /* U+8B94 [2000] */ - {0x00e8ae95, 0x00f9f1}, /* U+8B95 [2000] */ - {0x00e8ae96, 0x00e6a9}, /* U+8B96 */ - {0x00e8ae99, 0x00e6aa}, /* U+8B99 */ - {0x00e8ae9a, 0x00e6ab}, /* U+8B9A */ - {0x00e8ae9c, 0x00f9f2}, /* U+8B9C [2000] */ - {0x00e8ae9d, 0x00eeb3}, /* U+8B9D [2000] */ - {0x00e8ae9e, 0x00f9f3}, /* U+8B9E [2000] */ - {0x00e8b0b7, 0x00924a}, /* U+8C37 */ - {0x00e8b0b9, 0x00f9f4}, /* U+8C39 [2000] */ - {0x00e8b0ba, 0x00e6ac}, /* U+8C3A */ - {0x00e8b0bd, 0x00f9f6}, /* U+8C3D [2000] */ - {0x00e8b0bf, 0x00e6ae}, /* U+8C3F */ - {0x00e8b181, 0x00e6ad}, /* U+8C41 */ - {0x00e8b185, 0x00f9f9}, /* U+8C45 [2000] */ - {0x00e8b186, 0x0093a4}, /* U+8C46 */ - {0x00e8b187, 0x00f9fa}, /* U+8C47 [2000] */ - {0x00e8b188, 0x00e6af}, /* U+8C48 */ - {0x00e8b189, 0x00eeb4}, /* U+8C49 [2000] */ - {0x00e8b18a, 0x00964c}, /* U+8C4A */ - {0x00e8b18c, 0x00e6b0}, /* U+8C4C */ - {0x00e8b18e, 0x00e6b1}, /* U+8C4E */ - {0x00e8b18f, 0x00f9fb}, /* U+8C4F [2000] */ - {0x00e8b190, 0x00e6b2}, /* U+8C50 */ - {0x00e8b194, 0x00f9fc}, /* U+8C54 [2000] */ - {0x00e8b195, 0x00e6b3}, /* U+8C55 */ - {0x00e8b197, 0x00fa40}, /* U+8C57 [2000] */ - {0x00e8b19a, 0x0093d8}, /* U+8C5A */ - {0x00e8b1a1, 0x008fdb}, /* U+8C61 */ - {0x00e8b1a2, 0x00e6b4}, /* U+8C62 */ - {0x00e8b1a8, 0x00eeb5}, /* U+8C68 [2000] */ - {0x00e8b1a9, 0x00fa41}, /* U+8C69 [2000] */ - {0x00e8b1aa, 0x008d8b}, /* U+8C6A */ - {0x00e8b1ab, 0x0098ac}, /* U+8C6B */ - {0x00e8b1ac, 0x00e6b5}, /* U+8C6C */ - {0x00e8b1ad, 0x00fa42}, /* U+8C6D [2000] */ - {0x00e8b1b3, 0x00fa43}, /* U+8C73 [2000] */ - {0x00e8b1b8, 0x00e6b6}, /* U+8C78 */ - {0x00e8b1b9, 0x00955e}, /* U+8C79 */ - {0x00e8b1ba, 0x00e6b7}, /* U+8C7A */ - {0x00e8b1bc, 0x00e6bf}, /* U+8C7C */ - {0x00e8b282, 0x00e6b8}, /* U+8C82 */ - {0x00e8b285, 0x00e6ba}, /* U+8C85 */ - {0x00e8b289, 0x00e6b9}, /* U+8C89 */ - {0x00e8b28a, 0x00e6bb}, /* U+8C8A */ - {0x00e8b28c, 0x009665}, /* U+8C8C */ - {0x00e8b28d, 0x00e6bc}, /* U+8C8D */ - {0x00e8b28e, 0x00e6bd}, /* U+8C8E */ - {0x00e8b292, 0x00fa46}, /* U+8C92 [2000] */ - {0x00e8b293, 0x00fa45}, /* U+8C93 [2000] */ - {0x00e8b294, 0x00e6be}, /* U+8C94 */ - {0x00e8b298, 0x00e6c0}, /* U+8C98 */ - {0x00e8b299, 0x00fa47}, /* U+8C99 [2000] */ - {0x00e8b29b, 0x00fa49}, /* U+8C9B [2000] */ - {0x00e8b29d, 0x008a4c}, /* U+8C9D */ - {0x00e8b29e, 0x0092e5}, /* U+8C9E */ - {0x00e8b2a0, 0x009589}, /* U+8CA0 */ - {0x00e8b2a1, 0x008de0}, /* U+8CA1 */ - {0x00e8b2a2, 0x008d76}, /* U+8CA2 */ - {0x00e8b2a4, 0x00fa4a}, /* U+8CA4 [2000] */ - {0x00e8b2a7, 0x00956e}, /* U+8CA7 */ - {0x00e8b2a8, 0x0089dd}, /* U+8CA8 */ - {0x00e8b2a9, 0x0094cc}, /* U+8CA9 */ - {0x00e8b2aa, 0x00e6c3}, /* U+8CAA */ - {0x00e8b2ab, 0x008ad1}, /* U+8CAB */ - {0x00e8b2ac, 0x0090d3}, /* U+8CAC */ - {0x00e8b2ad, 0x00e6c2}, /* U+8CAD */ - {0x00e8b2ae, 0x00e6c7}, /* U+8CAE */ - {0x00e8b2af, 0x009299}, /* U+8CAF */ - {0x00e8b2b0, 0x0096e1}, /* U+8CB0 */ - {0x00e8b2b2, 0x00e6c5}, /* U+8CB2 */ - {0x00e8b2b3, 0x00e6c6}, /* U+8CB3 */ - {0x00e8b2b4, 0x008b4d}, /* U+8CB4 */ - {0x00e8b2b6, 0x00e6c8}, /* U+8CB6 */ - {0x00e8b2b7, 0x009483}, /* U+8CB7 */ - {0x00e8b2b8, 0x0091dd}, /* U+8CB8 */ - {0x00e8b2bb, 0x0094ef}, /* U+8CBB */ - {0x00e8b2bc, 0x00935c}, /* U+8CBC */ - {0x00e8b2bd, 0x00e6c4}, /* U+8CBD */ - {0x00e8b2bf, 0x009666}, /* U+8CBF */ - {0x00e8b380, 0x0089ea}, /* U+8CC0 */ - {0x00e8b381, 0x00e6ca}, /* U+8CC1 */ - {0x00e8b382, 0x009847}, /* U+8CC2 */ - {0x00e8b383, 0x0092c0}, /* U+8CC3 */ - {0x00e8b384, 0x009864}, /* U+8CC4 */ - {0x00e8b387, 0x008e91}, /* U+8CC7 */ - {0x00e8b388, 0x00e6c9}, /* U+8CC8 */ - {0x00e8b38a, 0x0091af}, /* U+8CCA */ - {0x00e8b38d, 0x00e6da}, /* U+8CCD */ - {0x00e8b38e, 0x009147}, /* U+8CCE */ - {0x00e8b391, 0x0093f6}, /* U+8CD1 */ - {0x00e8b393, 0x00956f}, /* U+8CD3 */ - {0x00e8b395, 0x00fa4c}, /* U+8CD5 [2000] */ - {0x00e8b396, 0x00fa4b}, /* U+8CD6 [2000] */ - {0x00e8b399, 0x00fa4d}, /* U+8CD9 [2000] */ - {0x00e8b39a, 0x00e6cd}, /* U+8CDA */ - {0x00e8b39b, 0x008e5e}, /* U+8CDB */ - {0x00e8b39c, 0x008e92}, /* U+8CDC */ - {0x00e8b39e, 0x008fdc}, /* U+8CDE */ - {0x00e8b3a0, 0x009485}, /* U+8CE0 */ - {0x00e8b3a1, 0x00eeb7}, /* U+8CE1 [2000] */ - {0x00e8b3a2, 0x008cab}, /* U+8CE2 */ - {0x00e8b3a3, 0x00e6cc}, /* U+8CE3 */ - {0x00e8b3a4, 0x00e6cb}, /* U+8CE4 */ - {0x00e8b3a6, 0x00958a}, /* U+8CE6 */ - {0x00e8b3aa, 0x008ebf}, /* U+8CEA */ - {0x00e8b3ad, 0x009371}, /* U+8CED */ - {0x00e8b3b0, 0x00fa4f}, /* U+8CF0 [2000] */ - {0x00e8b3b1, 0x00fa50}, /* U+8CF1 [2000] */ - {0x00e8b3b4, 0x00eeb8}, /* U+8CF4 [2000] */ - {0x00e8b3b8, 0x00eeb9}, /* U+8CF8 [2000] */ - {0x00e8b3ba, 0x00e6cf}, /* U+8CFA */ - {0x00e8b3bb, 0x00e6d0}, /* U+8CFB */ - {0x00e8b3bc, 0x008d77}, /* U+8CFC */ - {0x00e8b3bd, 0x00e6ce}, /* U+8CFD */ - {0x00e8b3be, 0x00eeba}, /* U+8CFE [2000] */ - {0x00e8b484, 0x00e6d1}, /* U+8D04 */ - {0x00e8b485, 0x00e6d2}, /* U+8D05 */ - {0x00e8b487, 0x00e6d4}, /* U+8D07 */ - {0x00e8b488, 0x0091a1}, /* U+8D08 */ - {0x00e8b489, 0x00fa52}, /* U+8D09 [2000] */ - {0x00e8b48a, 0x00e6d3}, /* U+8D0A */ - {0x00e8b48b, 0x008ae4}, /* U+8D0B */ - {0x00e8b48d, 0x00e6d6}, /* U+8D0D */ - {0x00e8b48e, 0x00fa53}, /* U+8D0E [2000] */ - {0x00e8b48f, 0x00e6d5}, /* U+8D0F */ - {0x00e8b490, 0x00e6d7}, /* U+8D10 */ - {0x00e8b492, 0x00eebc}, /* U+8D12 [2000] */ - {0x00e8b493, 0x00e6d9}, /* U+8D13 */ - {0x00e8b494, 0x00e6db}, /* U+8D14 */ - {0x00e8b496, 0x00e6dc}, /* U+8D16 */ - {0x00e8b49b, 0x00eebd}, /* U+8D1B [2000] */ - {0x00e8b5a4, 0x0090d4}, /* U+8D64 */ - {0x00e8b5a6, 0x008ecd}, /* U+8D66 */ - {0x00e8b5a7, 0x00e6dd}, /* U+8D67 */ - {0x00e8b5ab, 0x008a71}, /* U+8D6B */ - {0x00e8b5ac, 0x00fa54}, /* U+8D6C [2000] */ - {0x00e8b5ad, 0x00e6de}, /* U+8D6D */ - {0x00e8b5b0, 0x009196}, /* U+8D70 */ - {0x00e8b5b1, 0x00e6df}, /* U+8D71 */ - {0x00e8b5b3, 0x00e6e0}, /* U+8D73 */ - {0x00e8b5b4, 0x00958b}, /* U+8D74 */ - {0x00e8b5b7, 0x008b4e}, /* U+8D77 */ - {0x00e8b681, 0x00e6e1}, /* U+8D81 */ - {0x00e8b684, 0x00fa55}, /* U+8D84 [2000] */ - {0x00e8b685, 0x0092b4}, /* U+8D85 */ - {0x00e8b68a, 0x00897a}, /* U+8D8A */ - {0x00e8b695, 0x00fa56}, /* U+8D95 [2000] */ - {0x00e8b699, 0x00e6e2}, /* U+8D99 */ - {0x00e8b6a3, 0x008eef}, /* U+8DA3 */ - {0x00e8b6a6, 0x00fa57}, /* U+8DA6 [2000] */ - {0x00e8b6a8, 0x009096}, /* U+8DA8 */ - {0x00e8b6af, 0x00eebe}, /* U+8DAF [2000] */ - {0x00e8b6b3, 0x0091ab}, /* U+8DB3 */ - {0x00e8b6ba, 0x00e6e5}, /* U+8DBA */ - {0x00e8b6be, 0x00e6e4}, /* U+8DBE */ - {0x00e8b782, 0x00e6e3}, /* U+8DC2 */ - {0x00e8b786, 0x00fa59}, /* U+8DC6 [2000] */ - {0x00e8b788, 0x00fa5a}, /* U+8DC8 [2000] */ - {0x00e8b78b, 0x00e6eb}, /* U+8DCB */ - {0x00e8b78c, 0x00e6e9}, /* U+8DCC */ - {0x00e8b78e, 0x00eebf}, /* U+8DCE [2000] */ - {0x00e8b78f, 0x00e6e6}, /* U+8DCF */ - {0x00e8b791, 0x00eec0}, /* U+8DD1 [2000] */ - {0x00e8b796, 0x00e6e8}, /* U+8DD6 */ - {0x00e8b797, 0x00eec1}, /* U+8DD7 [2000] */ - {0x00e8b799, 0x00fa5b}, /* U+8DD9 [2000] */ - {0x00e8b79a, 0x00e6e7}, /* U+8DDA */ - {0x00e8b79b, 0x00e6ea}, /* U+8DDB */ - {0x00e8b79d, 0x008b97}, /* U+8DDD */ - {0x00e8b79f, 0x00e6ee}, /* U+8DDF */ - {0x00e8b7a1, 0x0090d5}, /* U+8DE1 */ - {0x00e8b7a3, 0x00e6ef}, /* U+8DE3 */ - {0x00e8b7a8, 0x008cd7}, /* U+8DE8 */ - {0x00e8b7aa, 0x00e6ec}, /* U+8DEA */ - {0x00e8b7ab, 0x00e6ed}, /* U+8DEB */ - {0x00e8b7ac, 0x00fa5c}, /* U+8DEC [2000] */ - {0x00e8b7af, 0x009848}, /* U+8DEF */ - {0x00e8b7b3, 0x0092b5}, /* U+8DF3 */ - {0x00e8b7b5, 0x009148}, /* U+8DF5 */ - {0x00e8b7bc, 0x00e6f0}, /* U+8DFC */ - {0x00e8b7bd, 0x00fa5f}, /* U+8DFD [2000] */ - {0x00e8b7bf, 0x00e6f3}, /* U+8DFF */ - {0x00e8b886, 0x00fa60}, /* U+8E06 [2000] */ - {0x00e8b888, 0x00e6f1}, /* U+8E08 */ - {0x00e8b889, 0x00e6f2}, /* U+8E09 */ - {0x00e8b88a, 0x009778}, /* U+8E0A */ - {0x00e8b88c, 0x00fa5d}, /* U+8E0C [2000] */ - {0x00e8b88f, 0x0093a5}, /* U+8E0F */ - {0x00e8b890, 0x00e6f6}, /* U+8E10 */ - {0x00e8b894, 0x00fa62}, /* U+8E14 [2000] */ - {0x00e8b896, 0x00fa63}, /* U+8E16 [2000] */ - {0x00e8b89d, 0x00e6f4}, /* U+8E1D */ - {0x00e8b89e, 0x00e6f5}, /* U+8E1E */ - {0x00e8b89f, 0x00e6f7}, /* U+8E1F */ - {0x00e8b8a0, 0x00eec2}, /* U+8E20 [2000] */ - {0x00e8b8a1, 0x00fa64}, /* U+8E21 [2000] */ - {0x00e8b8a2, 0x00fa65}, /* U+8E22 [2000] */ - {0x00e8b8a3, 0x00eec3}, /* U+8E23 [2000] */ - {0x00e8b8a7, 0x00fa66}, /* U+8E27 [2000] */ - {0x00e8b8aa, 0x00e748}, /* U+8E2A */ - {0x00e8b8b0, 0x00e6fa}, /* U+8E30 */ - {0x00e8b8b4, 0x00e6fb}, /* U+8E34 */ - {0x00e8b8b5, 0x00e6f9}, /* U+8E35 */ - {0x00e8b8b6, 0x00fa69}, /* U+8E36 [2000] */ - {0x00e8b8b9, 0x00fa6a}, /* U+8E39 [2000] */ - {0x00e8b8bd, 0x00eec4}, /* U+8E3D [2000] */ - {0x00e8b982, 0x00e6f8}, /* U+8E42 */ - {0x00e8b984, 0x0092fb}, /* U+8E44 */ - {0x00e8b987, 0x00e740}, /* U+8E47 */ - {0x00e8b988, 0x00e744}, /* U+8E48 */ - {0x00e8b989, 0x00e741}, /* U+8E49 */ - {0x00e8b98a, 0x00e6fc}, /* U+8E4A */ - {0x00e8b98b, 0x00fa6b}, /* U+8E4B [2000] */ - {0x00e8b98c, 0x00e742}, /* U+8E4C */ - {0x00e8b990, 0x00e743}, /* U+8E50 */ - {0x00e8b994, 0x00fa6c}, /* U+8E54 [2000] */ - {0x00e8b995, 0x00e74a}, /* U+8E55 */ - {0x00e8b999, 0x00e745}, /* U+8E59 */ - {0x00e8b99f, 0x0090d6}, /* U+8E5F */ - {0x00e8b9a0, 0x00e747}, /* U+8E60 */ - {0x00e8b9a2, 0x00fa6d}, /* U+8E62 [2000] */ - {0x00e8b9a3, 0x00e749}, /* U+8E63 */ - {0x00e8b9a4, 0x00e746}, /* U+8E64 */ - {0x00e8b9ac, 0x00fa6e}, /* U+8E6C [2000] */ - {0x00e8b9ad, 0x00fa6f}, /* U+8E6D [2000] */ - {0x00e8b9af, 0x00fa70}, /* U+8E6F [2000] */ - {0x00e8b9b0, 0x00eec5}, /* U+8E70 [2000] */ - {0x00e8b9b2, 0x00e74c}, /* U+8E72 */ - {0x00e8b9b4, 0x008f52}, /* U+8E74 */ - {0x00e8b9b6, 0x00e74b}, /* U+8E76 */ - {0x00e8b9bb, 0x00eec6}, /* U+8E7B [2000] */ - {0x00e8b9bc, 0x00e74d}, /* U+8E7C */ - {0x00e8ba81, 0x00e74e}, /* U+8E81 */ - {0x00e8ba84, 0x00e751}, /* U+8E84 */ - {0x00e8ba85, 0x00e750}, /* U+8E85 */ - {0x00e8ba87, 0x00e74f}, /* U+8E87 */ - {0x00e8ba8a, 0x00e753}, /* U+8E8A */ - {0x00e8ba8b, 0x00e752}, /* U+8E8B */ - {0x00e8ba8d, 0x0096f4}, /* U+8E8D */ - {0x00e8ba91, 0x00e755}, /* U+8E91 */ - {0x00e8ba93, 0x00e754}, /* U+8E93 */ - {0x00e8ba94, 0x00e756}, /* U+8E94 */ - {0x00e8ba98, 0x00fa71}, /* U+8E98 [2000] */ - {0x00e8ba99, 0x00e757}, /* U+8E99 */ - {0x00e8ba9e, 0x00fa72}, /* U+8E9E [2000] */ - {0x00e8baa1, 0x00e759}, /* U+8EA1 */ - {0x00e8baaa, 0x00e758}, /* U+8EAA */ - {0x00e8baab, 0x009067}, /* U+8EAB */ - {0x00e8baac, 0x00e75a}, /* U+8EAC */ - {0x00e8baae, 0x00fa73}, /* U+8EAE [2000] */ - {0x00e8baaf, 0x008beb}, /* U+8EAF */ - {0x00e8bab0, 0x00e75b}, /* U+8EB0 */ - {0x00e8bab1, 0x00e75d}, /* U+8EB1 */ - {0x00e8bab3, 0x00fa74}, /* U+8EB3 [2000] */ - {0x00e8bab5, 0x00fa75}, /* U+8EB5 [2000] */ - {0x00e8bab6, 0x00fa76}, /* U+8EB6 [2000] */ - {0x00e8babb, 0x00fa77}, /* U+8EBB [2000] */ - {0x00e8babe, 0x00e75e}, /* U+8EBE */ - {0x00e8bb80, 0x00eec8}, /* U+8EC0 [2000] */ - {0x00e8bb85, 0x00e75f}, /* U+8EC5 */ - {0x00e8bb86, 0x00e75c}, /* U+8EC6 */ - {0x00e8bb88, 0x00e760}, /* U+8EC8 */ - {0x00e8bb8a, 0x008ed4}, /* U+8ECA */ - {0x00e8bb8b, 0x00e761}, /* U+8ECB */ - {0x00e8bb8c, 0x008b4f}, /* U+8ECC */ - {0x00e8bb8d, 0x008c52}, /* U+8ECD */ - {0x00e8bb91, 0x00fa79}, /* U+8ED1 [2000] */ - {0x00e8bb92, 0x008cac}, /* U+8ED2 */ - {0x00e8bb94, 0x00fa7a}, /* U+8ED4 [2000] */ - {0x00e8bb9b, 0x00e762}, /* U+8EDB */ - {0x00e8bb9f, 0x0093ee}, /* U+8EDF */ - {0x00e8bba2, 0x00935d}, /* U+8EE2 */ - {0x00e8bba3, 0x00e763}, /* U+8EE3 */ - {0x00e8bbab, 0x00e766}, /* U+8EEB */ - {0x00e8bbb8, 0x008eb2}, /* U+8EF8 */ - {0x00e8bbb9, 0x00fa7c}, /* U+8EF9 [2000] */ - {0x00e8bbba, 0x00eeca}, /* U+8EFA [2000] */ - {0x00e8bbbb, 0x00e765}, /* U+8EFB */ - {0x00e8bbbc, 0x00e764}, /* U+8EFC */ - {0x00e8bbbd, 0x008c79}, /* U+8EFD */ - {0x00e8bbbe, 0x00e767}, /* U+8EFE */ - {0x00e8bc80, 0x00fa7e}, /* U+8F00 [2000] */ - {0x00e8bc83, 0x008a72}, /* U+8F03 */ - {0x00e8bc85, 0x00e769}, /* U+8F05 */ - {0x00e8bc88, 0x00fa80}, /* U+8F08 [2000] */ - {0x00e8bc89, 0x008dda}, /* U+8F09 */ - {0x00e8bc8a, 0x00e768}, /* U+8F0A */ - {0x00e8bc8c, 0x00e771}, /* U+8F0C */ - {0x00e8bc92, 0x00e76b}, /* U+8F12 */ - {0x00e8bc93, 0x00e76d}, /* U+8F13 */ - {0x00e8bc94, 0x0095e3}, /* U+8F14 */ - {0x00e8bc95, 0x00e76a}, /* U+8F15 */ - {0x00e8bc97, 0x00fa81}, /* U+8F17 [2000] */ - {0x00e8bc99, 0x00e76c}, /* U+8F19 */ - {0x00e8bc9b, 0x00e770}, /* U+8F1B */ - {0x00e8bc9c, 0x00e76e}, /* U+8F1C */ - {0x00e8bc9d, 0x008b50}, /* U+8F1D */ - {0x00e8bc9e, 0x00eecb}, /* U+8F1E [2000] */ - {0x00e8bc9f, 0x00e76f}, /* U+8F1F */ - {0x00e8bca6, 0x00e772}, /* U+8F26 */ - {0x00e8bca9, 0x009479}, /* U+8F29 */ - {0x00e8bcaa, 0x0097d6}, /* U+8F2A */ - {0x00e8bcab, 0x00fa82}, /* U+8F2B [2000] */ - {0x00e8bcad, 0x00eecc}, /* U+8F2D [2000] */ - {0x00e8bcaf, 0x008f53}, /* U+8F2F */ - {0x00e8bcb3, 0x00e773}, /* U+8F33 */ - {0x00e8bcb6, 0x00eecd}, /* U+8F36 [2000] */ - {0x00e8bcb8, 0x009741}, /* U+8F38 */ - {0x00e8bcb9, 0x00e775}, /* U+8F39 */ - {0x00e8bcbb, 0x00e774}, /* U+8F3B */ - {0x00e8bcbe, 0x00e778}, /* U+8F3E */ - {0x00e8bcbf, 0x009760}, /* U+8F3F */ - {0x00e8bd80, 0x00fa83}, /* U+8F40 [2000] */ - {0x00e8bd82, 0x00e777}, /* U+8F42 */ - {0x00e8bd84, 0x008a8d}, /* U+8F44 */ - {0x00e8bd85, 0x00e776}, /* U+8F45 */ - {0x00e8bd86, 0x00e77b}, /* U+8F46 */ - {0x00e8bd89, 0x00e77a}, /* U+8F49 */ - {0x00e8bd8a, 0x00fa84}, /* U+8F4A [2000] */ - {0x00e8bd8c, 0x00e779}, /* U+8F4C */ - {0x00e8bd8d, 0x009351}, /* U+8F4D */ - {0x00e8bd8e, 0x00e77c}, /* U+8F4E */ - {0x00e8bd94, 0x00eece}, /* U+8F54 [2000] */ - {0x00e8bd97, 0x00e77d}, /* U+8F57 */ - {0x00e8bd98, 0x00fa85}, /* U+8F58 [2000] */ - {0x00e8bd9c, 0x00e77e}, /* U+8F5C */ - {0x00e8bd9f, 0x008d8c}, /* U+8F5F */ - {0x00e8bda1, 0x008c44}, /* U+8F61 */ - {0x00e8bda2, 0x00e780}, /* U+8F62 */ - {0x00e8bda3, 0x00e781}, /* U+8F63 */ - {0x00e8bda4, 0x00e782}, /* U+8F64 */ - {0x00e8be9b, 0x009068}, /* U+8F9B */ - {0x00e8be9c, 0x00e783}, /* U+8F9C */ - {0x00e8be9e, 0x008eab}, /* U+8F9E */ - {0x00e8be9f, 0x00e784}, /* U+8F9F */ - {0x00e8bea3, 0x00e785}, /* U+8FA3 */ - {0x00e8bea4, 0x00fa87}, /* U+8FA4 [2000] */ - {0x00e8bea6, 0x00eed0}, /* U+8FA6 [2000] */ - {0x00e8bea7, 0x00999f}, /* U+8FA7 */ - {0x00e8bea8, 0x00999e}, /* U+8FA8 */ - {0x00e8bead, 0x00e786}, /* U+8FAD */ - {0x00e8beae, 0x00e390}, /* U+8FAE */ - {0x00e8beaf, 0x00e787}, /* U+8FAF */ - {0x00e8beb0, 0x009243}, /* U+8FB0 */ - {0x00e8beb1, 0x00904a}, /* U+8FB1 */ - {0x00e8beb2, 0x00945f}, /* U+8FB2 */ - {0x00e8beb4, 0x00fa88}, /* U+8FB4 [2000] */ - {0x00e8beb5, 0x00eed1}, /* U+8FB5 [2000] */ - {0x00e8beb6, 0x00fa8a}, /* U+8FB6 [2000] */ - {0x00e8beb7, 0x00e788}, /* U+8FB7 */ - {0x00e8beba, 0x0095d3}, /* U+8FBA */ - {0x00e8bebb, 0x0092d2}, /* U+8FBB */ - {0x00e8bebc, 0x008d9e}, /* U+8FBC */ - {0x00e8bebf, 0x009248}, /* U+8FBF */ - {0x00e8bf81, 0x00fa8c}, /* U+8FC1 [2000] */ - {0x00e8bf82, 0x008949}, /* U+8FC2 */ - {0x00e8bf84, 0x009698}, /* U+8FC4 */ - {0x00e8bf85, 0x009076}, /* U+8FC5 */ - {0x00e8bf86, 0x00fa8d}, /* U+8FC6 [2000] */ - {0x00e8bf8a, 0x00fa8f}, /* U+8FCA [2000] */ - {0x00e8bf8d, 0x00fa90}, /* U+8FCD [2000] */ - {0x00e8bf8e, 0x008c7d}, /* U+8FCE */ - {0x00e8bf91, 0x008bdf}, /* U+8FD1 */ - {0x00e8bf93, 0x00fa91}, /* U+8FD3 [2000] */ - {0x00e8bf94, 0x0095d4}, /* U+8FD4 */ - {0x00e8bf95, 0x00fa92}, /* U+8FD5 [2000] */ - {0x00e8bf9a, 0x00e789}, /* U+8FDA */ - {0x00e8bfa0, 0x00fa93}, /* U+8FE0 [2000] */ - {0x00e8bfa2, 0x00e78b}, /* U+8FE2 */ - {0x00e8bfa4, 0x00eed2}, /* U+8FE4 [2000] */ - {0x00e8bfa5, 0x00e78a}, /* U+8FE5 */ - {0x00e8bfa6, 0x0089de}, /* U+8FE6 */ - {0x00e8bfa8, 0x00eed3}, /* U+8FE8 [2000] */ - {0x00e8bfa9, 0x0093f4}, /* U+8FE9 */ - {0x00e8bfaa, 0x00e78c}, /* U+8FEA */ - {0x00e8bfab, 0x009497}, /* U+8FEB */ - {0x00e8bfad, 0x009352}, /* U+8FED */ - {0x00e8bfae, 0x00eed4}, /* U+8FEE [2000] */ - {0x00e8bfaf, 0x00e78d}, /* U+8FEF */ - {0x00e8bfb0, 0x008f71}, /* U+8FF0 */ - {0x00e8bfb1, 0x00fa94}, /* U+8FF1 [2000] */ - {0x00e8bfb4, 0x00e78f}, /* U+8FF4 */ - {0x00e8bfb5, 0x00fa95}, /* U+8FF5 [2000] */ - {0x00e8bfb7, 0x0096c0}, /* U+8FF7 */ - {0x00e8bfb8, 0x00e79e}, /* U+8FF8 */ - {0x00e8bfb9, 0x00e791}, /* U+8FF9 */ - {0x00e8bfba, 0x00e792}, /* U+8FFA */ - {0x00e8bfbb, 0x00fa96}, /* U+8FFB [2000] */ - {0x00e8bfbd, 0x0092c7}, /* U+8FFD */ - {0x00e98080, 0x0091de}, /* U+9000 */ - {0x00e98081, 0x009197}, /* U+9001 */ - {0x00e98082, 0x00fa97}, /* U+9002 [2000] */ - {0x00e98083, 0x0093a6}, /* U+9003 */ - {0x00e98085, 0x00e790}, /* U+9005 */ - {0x00e98086, 0x008b74}, /* U+9006 */ - {0x00e98088, 0x00eed5}, /* U+9008 [2000] */ - {0x00e9808b, 0x00e799}, /* U+900B */ - {0x00e9808c, 0x00fa98}, /* U+900C [2000] */ - {0x00e9808d, 0x00e796}, /* U+900D */ - {0x00e9808e, 0x00e7a3}, /* U+900E */ - {0x00e9808f, 0x0093a7}, /* U+900F */ - {0x00e98090, 0x009280}, /* U+9010 */ - {0x00e98091, 0x00e793}, /* U+9011 */ - {0x00e98093, 0x0092fc}, /* U+9013 */ - {0x00e98094, 0x009372}, /* U+9014 */ - {0x00e98095, 0x00e794}, /* U+9015 */ - {0x00e98096, 0x00e798}, /* U+9016 */ - {0x00e98097, 0x009080}, /* U+9017 */ - {0x00e98099, 0x009487}, /* U+9019 */ - {0x00e9809a, 0x0092ca}, /* U+901A */ - {0x00e9809d, 0x0090c0}, /* U+901D */ - {0x00e9809e, 0x00e797}, /* U+901E */ - {0x00e9809f, 0x0091ac}, /* U+901F */ - {0x00e980a0, 0x0091a2}, /* U+9020 */ - {0x00e980a1, 0x00e795}, /* U+9021 */ - {0x00e980a2, 0x0088a7}, /* U+9022 */ - {0x00e980a3, 0x009841}, /* U+9023 */ - {0x00e980a7, 0x00e79a}, /* U+9027 */ - {0x00e980ad, 0x00eed6}, /* U+902D [2000] */ - {0x00e980ae, 0x0091df}, /* U+902E */ - {0x00e980b1, 0x008f54}, /* U+9031 */ - {0x00e980b2, 0x009069}, /* U+9032 */ - {0x00e980b5, 0x00e79c}, /* U+9035 */ - {0x00e980b6, 0x00e79b}, /* U+9036 */ - {0x00e980b7, 0x00fa99}, /* U+9037 [2000] */ - {0x00e980b8, 0x0088ed}, /* U+9038 */ - {0x00e980b9, 0x00e79d}, /* U+9039 */ - {0x00e980bc, 0x00954e}, /* U+903C */ - {0x00e980be, 0x00e7a5}, /* U+903E */ - {0x00e98181, 0x0093d9}, /* U+9041 */ - {0x00e98182, 0x00908b}, /* U+9042 */ - {0x00e98183, 0x00fa9b}, /* U+9043 [2000] */ - {0x00e98184, 0x00fa9c}, /* U+9044 [2000] */ - {0x00e98185, 0x009278}, /* U+9045 */ - {0x00e98187, 0x008bf6}, /* U+9047 */ - {0x00e98189, 0x00e7a4}, /* U+9049 */ - {0x00e9818a, 0x009756}, /* U+904A */ - {0x00e9818b, 0x00895e}, /* U+904B */ - {0x00e9818d, 0x0095d5}, /* U+904D */ - {0x00e9818e, 0x0089df}, /* U+904E */ - {0x00e9818f, 0x00e79f}, /* U+904F */ - {0x00e98190, 0x00e7a0}, /* U+9050 */ - {0x00e98191, 0x00e7a1}, /* U+9051 */ - {0x00e98192, 0x00e7a2}, /* U+9052 */ - {0x00e98193, 0x0093b9}, /* U+9053 */ - {0x00e98194, 0x009242}, /* U+9054 */ - {0x00e98195, 0x0088e1}, /* U+9055 */ - {0x00e98196, 0x00e7a6}, /* U+9056 */ - {0x00e98198, 0x00e7a7}, /* U+9058 */ - {0x00e98199, 0x00eaa1}, /* U+9059 [1983] */ - {0x00e9819c, 0x0091bb}, /* U+905C */ - {0x00e9819d, 0x00fa9d}, /* U+905D [2000] */ - {0x00e9819e, 0x00e7a8}, /* U+905E */ - {0x00e981a0, 0x008993}, /* U+9060 */ - {0x00e981a1, 0x00916b}, /* U+9061 */ - {0x00e981a3, 0x008cad}, /* U+9063 */ - {0x00e981a5, 0x009779}, /* U+9065 */ - {0x00e981a8, 0x00e7a9}, /* U+9068 */ - {0x00e981a9, 0x00934b}, /* U+9069 */ - {0x00e981ad, 0x009198}, /* U+906D */ - {0x00e981ae, 0x008ed5}, /* U+906E */ - {0x00e981af, 0x00e7aa}, /* U+906F */ - {0x00e981b2, 0x00e7ad}, /* U+9072 */ - {0x00e981b5, 0x008f85}, /* U+9075 */ - {0x00e981b6, 0x00e7ab}, /* U+9076 */ - {0x00e981b7, 0x00914a}, /* U+9077 */ - {0x00e981b8, 0x009149}, /* U+9078 */ - {0x00e981ba, 0x0088e2}, /* U+907A */ - {0x00e981bc, 0x0097c9}, /* U+907C */ - {0x00e981bd, 0x00e7af}, /* U+907D */ - {0x00e981bf, 0x0094f0}, /* U+907F */ - {0x00e98280, 0x00e7b1}, /* U+9080 */ - {0x00e98281, 0x00e7b0}, /* U+9081 */ - {0x00e98282, 0x00e7ae}, /* U+9082 */ - {0x00e98283, 0x00e284}, /* U+9083 */ - {0x00e98284, 0x008ad2}, /* U+9084 */ - {0x00e98285, 0x00faa0}, /* U+9085 [2000] */ - {0x00e98287, 0x00e78e}, /* U+9087 */ - {0x00e98288, 0x00eed8}, /* U+9088 [2000] */ - {0x00e98289, 0x00e7b3}, /* U+9089 */ - {0x00e9828a, 0x00e7b2}, /* U+908A */ - {0x00e9828c, 0x00faa1}, /* U+908C [2000] */ - {0x00e9828f, 0x00e7b4}, /* U+908F */ - {0x00e98290, 0x00faa2}, /* U+9090 [2000] */ - {0x00e98291, 0x009757}, /* U+9091 */ - {0x00e98295, 0x00eed9}, /* U+9095 [2000] */ - {0x00e98297, 0x00eeda}, /* U+9097 [2000] */ - {0x00e98299, 0x00eedb}, /* U+9099 [2000] */ - {0x00e9829b, 0x00eedc}, /* U+909B [2000] */ - {0x00e982a1, 0x00faa4}, /* U+90A1 [2000] */ - {0x00e982a2, 0x00eedd}, /* U+90A2 [2000] */ - {0x00e982a3, 0x0093df}, /* U+90A3 */ - {0x00e982a6, 0x00964d}, /* U+90A6 */ - {0x00e982a8, 0x00e7b5}, /* U+90A8 */ - {0x00e982aa, 0x008ed7}, /* U+90AA */ - {0x00e982af, 0x00e7b6}, /* U+90AF */ - {0x00e982b0, 0x00faa6}, /* U+90B0 [2000] */ - {0x00e982b1, 0x00e7b7}, /* U+90B1 */ - {0x00e982b3, 0x00eede}, /* U+90B3 [2000] */ - {0x00e982b5, 0x00e7b8}, /* U+90B5 */ - {0x00e982b6, 0x00faa7}, /* U+90B6 [2000] */ - {0x00e982b8, 0x009340}, /* U+90B8 */ - {0x00e982be, 0x00eedf}, /* U+90BE [2000] */ - {0x00e98381, 0x0088e8}, /* U+90C1 */ - {0x00e98383, 0x00faa8}, /* U+90C3 [2000] */ - {0x00e98384, 0x00eee0}, /* U+90C4 [2000] */ - {0x00e98385, 0x00eee1}, /* U+90C5 [2000] */ - {0x00e98387, 0x00eee2}, /* U+90C7 [2000] */ - {0x00e98388, 0x00faa9}, /* U+90C8 [2000] */ - {0x00e9838a, 0x008d78}, /* U+90CA */ - {0x00e9838e, 0x009859}, /* U+90CE */ - {0x00e98397, 0x00eee3}, /* U+90D7 [2000] */ - {0x00e9839b, 0x00e7bc}, /* U+90DB */ - {0x00e9839c, 0x00faab}, /* U+90DC [2000] */ - {0x00e9839d, 0x00eee4}, /* U+90DD [2000] */ - {0x00e9839e, 0x00eee5}, /* U+90DE [2000] */ - {0x00e9839f, 0x00faac}, /* U+90DF [2000] */ - {0x00e983a1, 0x008c53}, /* U+90E1 */ - {0x00e983a2, 0x00e7b9}, /* U+90E2 */ - {0x00e983a4, 0x00e7ba}, /* U+90E4 */ - {0x00e983a8, 0x009594}, /* U+90E8 */ - {0x00e983ab, 0x00fab1}, /* U+90EB [2000] */ - {0x00e983ad, 0x008a73}, /* U+90ED */ - {0x00e983af, 0x00eee6}, /* U+90EF [2000] */ - {0x00e983b2, 0x00faaf}, /* U+90F2 [2000] */ - {0x00e983b4, 0x00eee7}, /* U+90F4 [2000] */ - {0x00e983b5, 0x009758}, /* U+90F5 */ - {0x00e983b6, 0x00faae}, /* U+90F6 [2000] */ - {0x00e983b7, 0x008bbd}, /* U+90F7 */ - {0x00e983bd, 0x009373}, /* U+90FD */ - {0x00e983be, 0x00fab2}, /* U+90FE [2000] */ - {0x00e983bf, 0x00fab3}, /* U+90FF [2000] */ - {0x00e98480, 0x00fab0}, /* U+9100 [2000] */ - {0x00e98482, 0x00e7bd}, /* U+9102 */ - {0x00e98484, 0x00fab4}, /* U+9104 [2000] */ - {0x00e98486, 0x00fab5}, /* U+9106 [2000] */ - {0x00e98492, 0x00e7be}, /* U+9112 */ - {0x00e98494, 0x00eee9}, /* U+9114 [2000] */ - {0x00e98495, 0x00eeea}, /* U+9115 [2000] */ - {0x00e98496, 0x00eeeb}, /* U+9116 [2000] */ - {0x00e98498, 0x00fab6}, /* U+9118 [2000] */ - {0x00e98499, 0x00e7bf}, /* U+9119 */ - {0x00e9849c, 0x00fab7}, /* U+911C [2000] */ - {0x00e9849e, 0x00fab8}, /* U+911E [2000] */ - {0x00e984a2, 0x00eeec}, /* U+9122 [2000] */ - {0x00e984a3, 0x00eeed}, /* U+9123 [2000] */ - {0x00e984a7, 0x00eeee}, /* U+9127 [2000] */ - {0x00e984ad, 0x009341}, /* U+912D */ - {0x00e984af, 0x00eeef}, /* U+912F [2000] */ - {0x00e984b0, 0x00e7c1}, /* U+9130 */ - {0x00e984b1, 0x00eef0}, /* U+9131 [2000] */ - {0x00e984b2, 0x00e7c0}, /* U+9132 */ - {0x00e984b4, 0x00eef1}, /* U+9134 [2000] */ - {0x00e984b7, 0x00fab9}, /* U+9137 [2000] */ - {0x00e984b9, 0x00faba}, /* U+9139 [2000] */ - {0x00e984ba, 0x00fabb}, /* U+913A [2000] */ - {0x00e984bd, 0x00eef2}, /* U+913D [2000] */ - {0x00e98586, 0x00fabc}, /* U+9146 [2000] */ - {0x00e98587, 0x00fabd}, /* U+9147 [2000] */ - {0x00e98588, 0x00eef3}, /* U+9148 [2000] */ - {0x00e98589, 0x0093d1}, /* U+9149 */ - {0x00e9858a, 0x00e7c2}, /* U+914A */ - {0x00e9858b, 0x008f55}, /* U+914B */ - {0x00e9858c, 0x008ede}, /* U+914C */ - {0x00e9858d, 0x00947a}, /* U+914D */ - {0x00e9858e, 0x009291}, /* U+914E */ - {0x00e98592, 0x008ef0}, /* U+9152 */ - {0x00e98594, 0x00908c}, /* U+9154 */ - {0x00e98596, 0x00e7c3}, /* U+9156 */ - {0x00e98597, 0x00fabe}, /* U+9157 [2000] */ - {0x00e98598, 0x00e7c4}, /* U+9158 */ - {0x00e98599, 0x00fabf}, /* U+9159 [2000] */ - {0x00e9859b, 0x00eef4}, /* U+915B [2000] */ - {0x00e985a1, 0x00fac0}, /* U+9161 [2000] */ - {0x00e985a2, 0x00907c}, /* U+9162 */ - {0x00e985a3, 0x00e7c5}, /* U+9163 */ - {0x00e985a4, 0x00fac1}, /* U+9164 [2000] */ - {0x00e985a5, 0x00e7c6}, /* U+9165 */ - {0x00e985a9, 0x00e7c7}, /* U+9169 */ - {0x00e985aa, 0x00978f}, /* U+916A */ - {0x00e985ac, 0x008f56}, /* U+916C */ - {0x00e985b2, 0x00e7c9}, /* U+9172 */ - {0x00e985b3, 0x00e7c8}, /* U+9173 */ - {0x00e985b4, 0x00fac2}, /* U+9174 [2000] */ - {0x00e985b5, 0x008d79}, /* U+9175 */ - {0x00e985b7, 0x008d93}, /* U+9177 */ - {0x00e985b8, 0x008e5f}, /* U+9178 */ - {0x00e985b9, 0x00fac3}, /* U+9179 [2000] */ - {0x00e98682, 0x00e7cc}, /* U+9182 */ - {0x00e98683, 0x00eef5}, /* U+9183 [2000] */ - {0x00e98685, 0x00fac4}, /* U+9185 [2000] */ - {0x00e98687, 0x008f86}, /* U+9187 */ - {0x00e98689, 0x00e7cb}, /* U+9189 */ - {0x00e9868b, 0x00e7ca}, /* U+918B */ - {0x00e9868d, 0x0091e7}, /* U+918D */ - {0x00e9868e, 0x00fac5}, /* U+918E [2000] */ - {0x00e98690, 0x008ced}, /* U+9190 */ - {0x00e98692, 0x0090c1}, /* U+9192 */ - {0x00e98697, 0x0094ae}, /* U+9197 */ - {0x00e9869c, 0x008f58}, /* U+919C */ - {0x00e9869e, 0x00eef6}, /* U+919E [2000] */ - {0x00e986a2, 0x00e7cd}, /* U+91A2 */ - {0x00e986a4, 0x008fdd}, /* U+91A4 */ - {0x00e986a8, 0x00fac6}, /* U+91A8 [2000] */ - {0x00e986aa, 0x00e7d0}, /* U+91AA */ - {0x00e986ab, 0x00e7ce}, /* U+91AB */ - {0x00e986ac, 0x00eef7}, /* U+91AC [2000] */ - {0x00e986ae, 0x00fac7}, /* U+91AE [2000] */ - {0x00e986af, 0x00e7cf}, /* U+91AF */ - {0x00e986b1, 0x00eef8}, /* U+91B1 [2000] */ - {0x00e986b3, 0x00fac8}, /* U+91B3 [2000] */ - {0x00e986b4, 0x00e7d2}, /* U+91B4 */ - {0x00e986b5, 0x00e7d1}, /* U+91B5 */ - {0x00e986b6, 0x00fac9}, /* U+91B6 [2000] */ - {0x00e986b8, 0x008ff8}, /* U+91B8 */ - {0x00e986ba, 0x00e7d3}, /* U+91BA */ - {0x00e986bc, 0x00eef9}, /* U+91BC [2000] */ - {0x00e98780, 0x00e7d4}, /* U+91C0 */ - {0x00e98781, 0x00e7d5}, /* U+91C1 */ - {0x00e98783, 0x00faca}, /* U+91C3 [2000] */ - {0x00e98784, 0x00facb}, /* U+91C4 [2000] */ - {0x00e98786, 0x0094ce}, /* U+91C6 */ - {0x00e98787, 0x008dd1}, /* U+91C7 */ - {0x00e98788, 0x008edf}, /* U+91C8 */ - {0x00e98789, 0x00e7d6}, /* U+91C9 */ - {0x00e9878b, 0x00e7d7}, /* U+91CB */ - {0x00e9878c, 0x0097a2}, /* U+91CC */ - {0x00e9878d, 0x008f64}, /* U+91CD */ - {0x00e9878e, 0x0096ec}, /* U+91CE */ - {0x00e9878f, 0x0097ca}, /* U+91CF */ - {0x00e98790, 0x00e7d8}, /* U+91D0 */ - {0x00e98791, 0x008be0}, /* U+91D1 */ - {0x00e98796, 0x00e7d9}, /* U+91D6 */ - {0x00e98797, 0x00eefa}, /* U+91D7 [2000] */ - {0x00e98798, 0x009342}, /* U+91D8 */ - {0x00e9879a, 0x00facc}, /* U+91DA [2000] */ - {0x00e9879b, 0x00e7dc}, /* U+91DB */ - {0x00e9879c, 0x008a98}, /* U+91DC */ - {0x00e9879d, 0x00906a}, /* U+91DD */ - {0x00e9879f, 0x00e7da}, /* U+91DF */ - {0x00e987a1, 0x00e7db}, /* U+91E1 */ - {0x00e987a3, 0x0092de}, /* U+91E3 */ - {0x00e987a4, 0x00eefc}, /* U+91E4 [2000] */ - {0x00e987a5, 0x00ef40}, /* U+91E5 [2000] */ - {0x00e987a6, 0x009674}, /* U+91E6 */ - {0x00e987a7, 0x008bfa}, /* U+91E7 */ - {0x00e987ac, 0x00facf}, /* U+91EC [2000] */ - {0x00e987ad, 0x00ef41}, /* U+91ED [2000] */ - {0x00e987ae, 0x00fad0}, /* U+91EE [2000] */ - {0x00e987b1, 0x00ef42}, /* U+91F1 [2000] */ - {0x00e987b5, 0x00e7de}, /* U+91F5 */ - {0x00e987b6, 0x00e7df}, /* U+91F6 */ - {0x00e987bb, 0x00eefb}, /* U+91FB [2000] */ - {0x00e987bc, 0x00e7dd}, /* U+91FC */ - {0x00e987bf, 0x00e7e1}, /* U+91FF */ - {0x00e98881, 0x00fad1}, /* U+9201 [2000] */ - {0x00e98887, 0x00ef43}, /* U+9207 [2000] */ - {0x00e9888a, 0x00fad2}, /* U+920A [2000] */ - {0x00e9888d, 0x0093dd}, /* U+920D */ - {0x00e9888e, 0x008a62}, /* U+920E */ - {0x00e98890, 0x00ef44}, /* U+9210 [2000] */ - {0x00e98891, 0x00e7e5}, /* U+9211 */ - {0x00e98894, 0x00e7e2}, /* U+9214 */ - {0x00e98895, 0x00e7e4}, /* U+9215 */ - {0x00e98896, 0x00fad3}, /* U+9216 [2000] */ - {0x00e98897, 0x00fad4}, /* U+9217 [2000] */ - {0x00e9889e, 0x00e7e0}, /* U+921E */ - {0x00e988a9, 0x00e86e}, /* U+9229 */ - {0x00e988ac, 0x00e7e3}, /* U+922C */ - {0x00e988b3, 0x00fad6}, /* U+9233 [2000] */ - {0x00e988b4, 0x0097e9}, /* U+9234 */ - {0x00e988b7, 0x008cd8}, /* U+9237 */ - {0x00e988b8, 0x00ef45}, /* U+9238 [2000] */ - {0x00e988b9, 0x00ef46}, /* U+9239 [2000] */ - {0x00e988ba, 0x00ef47}, /* U+923A [2000] */ - {0x00e988bc, 0x00ef48}, /* U+923C [2000] */ - {0x00e988bf, 0x00e7ed}, /* U+923F */ - {0x00e98980, 0x00ef49}, /* U+9240 [2000] */ - {0x00e98982, 0x00fad7}, /* U+9242 [2000] */ - {0x00e98983, 0x00ef4a}, /* U+9243 [2000] */ - {0x00e98984, 0x009353}, /* U+9244 */ - {0x00e98985, 0x00e7e8}, /* U+9245 */ - {0x00e98987, 0x00fad8}, /* U+9247 [2000] */ - {0x00e98988, 0x00e7eb}, /* U+9248 */ - {0x00e98989, 0x00e7e9}, /* U+9249 */ - {0x00e9898a, 0x00fad9}, /* U+924A [2000] */ - {0x00e9898b, 0x00e7ee}, /* U+924B */ - {0x00e9898e, 0x00fada}, /* U+924E [2000] */ - {0x00e9898f, 0x00ef4b}, /* U+924F [2000] */ - {0x00e98990, 0x00e7ef}, /* U+9250 */ - {0x00e98991, 0x00fadb}, /* U+9251 [2000] */ - {0x00e98996, 0x00fadc}, /* U+9256 [2000] */ - {0x00e98997, 0x00e7e7}, /* U+9257 */ - {0x00e98999, 0x00fadd}, /* U+9259 [2000] */ - {0x00e9899a, 0x00e7f4}, /* U+925A */ - {0x00e9899b, 0x008994}, /* U+925B */ - {0x00e9899e, 0x00e7e6}, /* U+925E */ - {0x00e989a0, 0x00fade}, /* U+9260 [2000] */ - {0x00e989a1, 0x00fadf}, /* U+9261 [2000] */ - {0x00e989a2, 0x0094ab}, /* U+9262 */ - {0x00e989a4, 0x00e7ea}, /* U+9264 */ - {0x00e989a5, 0x00fae0}, /* U+9265 [2000] */ - {0x00e989a6, 0x008fde}, /* U+9266 */ - {0x00e989a7, 0x00fae1}, /* U+9267 [2000] */ - {0x00e989a8, 0x00fae2}, /* U+9268 [2000] */ - {0x00e989b1, 0x008d7a}, /* U+9271 */ - {0x00e989b8, 0x00ef4c}, /* U+9278 [2000] */ - {0x00e989bc, 0x00fae5}, /* U+927C [2000] */ - {0x00e989bd, 0x00fae6}, /* U+927D [2000] */ - {0x00e989be, 0x009667}, /* U+927E */ - {0x00e989bf, 0x00fae7}, /* U+927F [2000] */ - {0x00e98a80, 0x008be2}, /* U+9280 */ - {0x00e98a83, 0x008f65}, /* U+9283 */ - {0x00e98a85, 0x0093ba}, /* U+9285 */ - {0x00e98a88, 0x00ef4d}, /* U+9288 [2000] */ - {0x00e98a89, 0x00fae8}, /* U+9289 [2000] */ - {0x00e98a8d, 0x00fae9}, /* U+928D [2000] */ - {0x00e98a91, 0x00914c}, /* U+9291 */ - {0x00e98a93, 0x00e7f2}, /* U+9293 */ - {0x00e98a95, 0x00e7ec}, /* U+9295 */ - {0x00e98a96, 0x00e7f1}, /* U+9296 */ - {0x00e98a97, 0x00faea}, /* U+9297 [2000] */ - {0x00e98a98, 0x0096c1}, /* U+9298 */ - {0x00e98a99, 0x00faeb}, /* U+9299 [2000] */ - {0x00e98a9a, 0x0092b6}, /* U+929A */ - {0x00e98a9b, 0x00e7f3}, /* U+929B */ - {0x00e98a9c, 0x00e7f0}, /* U+929C */ - {0x00e98a9f, 0x00faec}, /* U+929F [2000] */ - {0x00e98aa7, 0x00faed}, /* U+92A7 [2000] */ - {0x00e98aab, 0x00faee}, /* U+92AB [2000] */ - {0x00e98aad, 0x00914b}, /* U+92AD */ - {0x00e98ab2, 0x00faf1}, /* U+92B2 [2000] */ - {0x00e98ab7, 0x00e7f7}, /* U+92B7 */ - {0x00e98ab9, 0x00e7f6}, /* U+92B9 */ - {0x00e98abf, 0x00faf2}, /* U+92BF [2000] */ - {0x00e98b80, 0x00faf3}, /* U+92C0 [2000] */ - {0x00e98b82, 0x00ef4e}, /* U+92C2 [2000] */ - {0x00e98b86, 0x00faf4}, /* U+92C6 [2000] */ - {0x00e98b8b, 0x00ef4f}, /* U+92CB [2000] */ - {0x00e98b8c, 0x00ef50}, /* U+92CC [2000] */ - {0x00e98b8e, 0x00faf5}, /* U+92CE [2000] */ - {0x00e98b8f, 0x00e7f5}, /* U+92CF */ - {0x00e98b90, 0x00faf6}, /* U+92D0 [2000] */ - {0x00e98b92, 0x00964e}, /* U+92D2 */ - {0x00e98b93, 0x00ef51}, /* U+92D3 [2000] */ - {0x00e98b97, 0x00faf7}, /* U+92D7 [2000] */ - {0x00e98b99, 0x00faf8}, /* U+92D9 [2000] */ - {0x00e98ba0, 0x00ef52}, /* U+92E0 [2000] */ - {0x00e98ba4, 0x008f9b}, /* U+92E4 */ - {0x00e98ba5, 0x00faf9}, /* U+92E5 [2000] */ - {0x00e98ba7, 0x00fafa}, /* U+92E7 [2000] */ - {0x00e98ba9, 0x00e7f8}, /* U+92E9 */ - {0x00e98baa, 0x0095dd}, /* U+92EA */ - {0x00e98bad, 0x008973}, /* U+92ED */ - {0x00e98bb2, 0x009565}, /* U+92F2 */ - {0x00e98bb3, 0x009292}, /* U+92F3 */ - {0x00e98bb7, 0x00fb41}, /* U+92F7 [2000] */ - {0x00e98bb8, 0x008b98}, /* U+92F8 */ - {0x00e98bb9, 0x00fb42}, /* U+92F9 [2000] */ - {0x00e98bba, 0x00e7fa}, /* U+92FA */ - {0x00e98bbb, 0x00fb43}, /* U+92FB [2000] */ - {0x00e98bbc, 0x008d7c}, /* U+92FC */ - {0x00e98bbf, 0x00ef53}, /* U+92FF [2000] */ - {0x00e98c82, 0x00fb44}, /* U+9302 [2000] */ - {0x00e98c84, 0x00ef54}, /* U+9304 [2000] */ - {0x00e98c86, 0x008e4b}, /* U+9306 */ - {0x00e98c8d, 0x00fb45}, /* U+930D [2000] */ - {0x00e98c8f, 0x00e7f9}, /* U+930F */ - {0x00e98c90, 0x00908d}, /* U+9310 */ - {0x00e98c91, 0x00fafb}, /* U+9311 [2000] */ - {0x00e98c95, 0x00fb46}, /* U+9315 [2000] */ - {0x00e98c98, 0x00908e}, /* U+9318 */ - {0x00e98c99, 0x00e840}, /* U+9319 */ - {0x00e98c9a, 0x00e842}, /* U+931A */ - {0x00e98c9d, 0x00fb47}, /* U+931D [2000] */ - {0x00e98c9e, 0x00fb48}, /* U+931E [2000] */ - {0x00e98c9f, 0x00ef55}, /* U+931F [2000] */ - {0x00e98ca0, 0x008ff9}, /* U+9320 */ - {0x00e98ca1, 0x00ef56}, /* U+9321 [2000] */ - {0x00e98ca2, 0x00e841}, /* U+9322 */ - {0x00e98ca3, 0x00e843}, /* U+9323 */ - {0x00e98ca5, 0x00ef57}, /* U+9325 [2000] */ - {0x00e98ca6, 0x008bd1}, /* U+9326 */ - {0x00e98ca7, 0x00fb49}, /* U+9327 [2000] */ - {0x00e98ca8, 0x009564}, /* U+9328 */ - {0x00e98ca9, 0x00fb4a}, /* U+9329 [2000] */ - {0x00e98cab, 0x008ee0}, /* U+932B */ - {0x00e98cac, 0x009842}, /* U+932C */ - {0x00e98cae, 0x00e7fc}, /* U+932E */ - {0x00e98caf, 0x008df6}, /* U+932F */ - {0x00e98cb2, 0x00985e}, /* U+9332 */ - {0x00e98cb5, 0x00e845}, /* U+9335 */ - {0x00e98cba, 0x00e844}, /* U+933A */ - {0x00e98cbb, 0x00e846}, /* U+933B */ - {0x00e98d84, 0x00e7fb}, /* U+9344 */ - {0x00e98d87, 0x00fb4d}, /* U+9347 [2000] */ - {0x00e98d88, 0x00ef58}, /* U+9348 [2000] */ - {0x00e98d89, 0x00ef59}, /* U+9349 [2000] */ - {0x00e98d8a, 0x00ef5a}, /* U+934A [2000] */ - {0x00e98d8b, 0x0093e7}, /* U+934B */ - {0x00e98d8d, 0x009374}, /* U+934D */ - {0x00e98d91, 0x00fb4e}, /* U+9351 [2000] */ - {0x00e98d94, 0x0092d5}, /* U+9354 */ - {0x00e98d96, 0x00e84b}, /* U+9356 */ - {0x00e98d97, 0x00fb4f}, /* U+9357 [2000] */ - {0x00e98d9a, 0x00fb50}, /* U+935A [2000] */ - {0x00e98d9b, 0x009262}, /* U+935B */ - {0x00e98d9c, 0x00e847}, /* U+935C */ - {0x00e98da0, 0x00e848}, /* U+9360 */ - {0x00e98da4, 0x00ef5b}, /* U+9364 [2000] */ - {0x00e98da5, 0x00ef5c}, /* U+9365 [2000] */ - {0x00e98daa, 0x00ef5d}, /* U+936A [2000] */ - {0x00e98dab, 0x00fb51}, /* U+936B [2000] */ - {0x00e98dac, 0x008c4c}, /* U+936C */ - {0x00e98dae, 0x00e84a}, /* U+936E */ - {0x00e98db0, 0x00ef5e}, /* U+9370 [2000] */ - {0x00e98db1, 0x00fb52}, /* U+9371 [2000] */ - {0x00e98db3, 0x00fb53}, /* U+9373 [2000] */ - {0x00e98db5, 0x008cae}, /* U+9375 */ - {0x00e98dbc, 0x00e849}, /* U+937C */ - {0x00e98dbe, 0x008fdf}, /* U+937E */ - {0x00e98e88, 0x00fb57}, /* U+9388 [2000] */ - {0x00e98e8b, 0x00fb58}, /* U+938B [2000] */ - {0x00e98e8c, 0x008a99}, /* U+938C */ - {0x00e98e8f, 0x00fb59}, /* U+938F [2000] */ - {0x00e98e94, 0x00e84f}, /* U+9394 */ - {0x00e98e96, 0x008dbd}, /* U+9396 */ - {0x00e98e97, 0x009199}, /* U+9397 */ - {0x00e98e9a, 0x0092c8}, /* U+939A */ - {0x00e98e9b, 0x00ef5f}, /* U+939B [2000] */ - {0x00e98e9e, 0x00fb5a}, /* U+939E [2000] */ - {0x00e98ea1, 0x00fb54}, /* U+93A1 [2000] */ - {0x00e98ea3, 0x00ef60}, /* U+93A3 [2000] */ - {0x00e98ea7, 0x008a5a}, /* U+93A7 */ - {0x00e98eac, 0x00e84d}, /* U+93AC */ - {0x00e98ead, 0x00e84e}, /* U+93AD */ - {0x00e98eae, 0x0092c1}, /* U+93AE */ - {0x00e98eb0, 0x00e84c}, /* U+93B0 */ - {0x00e98eb9, 0x00e850}, /* U+93B9 */ - {0x00e98eba, 0x00ef61}, /* U+93BA [2000] */ - {0x00e98f81, 0x00fb5f}, /* U+93C1 [2000] */ - {0x00e98f83, 0x00e856}, /* U+93C3 */ - {0x00e98f86, 0x00ef62}, /* U+93C6 [2000] */ - {0x00e98f87, 0x00fb60}, /* U+93C7 [2000] */ - {0x00e98f88, 0x00e859}, /* U+93C8 */ - {0x00e98f90, 0x00e858}, /* U+93D0 */ - {0x00e98f91, 0x00934c}, /* U+93D1 */ - {0x00e98f96, 0x00e851}, /* U+93D6 */ - {0x00e98f97, 0x00e852}, /* U+93D7 */ - {0x00e98f98, 0x00e855}, /* U+93D8 */ - {0x00e98f9c, 0x00fb61}, /* U+93DC [2000] */ - {0x00e98f9d, 0x00e857}, /* U+93DD */ - {0x00e98f9e, 0x00ef63}, /* U+93DE [2000] */ - {0x00e98f9f, 0x00ef64}, /* U+93DF [2000] */ - {0x00e98fa1, 0x008bbe}, /* U+93E1 */ - {0x00e98fa2, 0x00fb62}, /* U+93E2 [2000] */ - {0x00e98fa4, 0x00e85a}, /* U+93E4 */ - {0x00e98fa5, 0x00e854}, /* U+93E5 */ - {0x00e98fa7, 0x00fb63}, /* U+93E7 [2000] */ - {0x00e98fa8, 0x00e853}, /* U+93E8 */ - {0x00e98fb1, 0x00fb5e}, /* U+93F1 [2000] */ - {0x00e98fb5, 0x00fb5b}, /* U+93F5 [2000] */ - {0x00e98fbb, 0x00fb68}, /* U+93FB [2000] */ - {0x00e98fbd, 0x00ef66}, /* U+93FD [2000] */ - {0x00e99083, 0x00e85e}, /* U+9403 */ - {0x00e99084, 0x00ef65}, /* U+9404 [2000] */ - {0x00e99087, 0x00e85f}, /* U+9407 */ - {0x00e99089, 0x00fb64}, /* U+9409 [2000] */ - {0x00e9908f, 0x00fb65}, /* U+940F [2000] */ - {0x00e99090, 0x00e860}, /* U+9410 */ - {0x00e99093, 0x00e85d}, /* U+9413 */ - {0x00e99094, 0x00e85c}, /* U+9414 */ - {0x00e99096, 0x00fb66}, /* U+9416 [2000] */ - {0x00e99097, 0x00fb67}, /* U+9417 [2000] */ - {0x00e99098, 0x008fe0}, /* U+9418 */ - {0x00e99099, 0x0093a8}, /* U+9419 */ - {0x00e9909a, 0x00e85b}, /* U+941A */ - {0x00e990a1, 0x00e864}, /* U+9421 */ - {0x00e990ab, 0x00e862}, /* U+942B */ - {0x00e990b2, 0x00fb69}, /* U+9432 [2000] */ - {0x00e990b3, 0x00ef67}, /* U+9433 [2000] */ - {0x00e990b4, 0x00fb6a}, /* U+9434 [2000] */ - {0x00e990b5, 0x00e863}, /* U+9435 */ - {0x00e990b6, 0x00e861}, /* U+9436 */ - {0x00e990b8, 0x0091f6}, /* U+9438 */ - {0x00e990ba, 0x00e865}, /* U+943A */ - {0x00e990bb, 0x00fb6b}, /* U+943B [2000] */ - {0x00e99181, 0x00e866}, /* U+9441 */ - {0x00e99184, 0x00e868}, /* U+9444 */ - {0x00e99185, 0x00fb6c}, /* U+9445 [2000] */ - {0x00e9918a, 0x00ef68}, /* U+944A [2000] */ - {0x00e99191, 0x008ad3}, /* U+9451 */ - {0x00e99192, 0x00e867}, /* U+9452 */ - {0x00e99193, 0x0096f8}, /* U+9453 */ - {0x00e9919a, 0x00e873}, /* U+945A */ - {0x00e9919b, 0x00e869}, /* U+945B */ - {0x00e9919e, 0x00e86c}, /* U+945E */ - {0x00e991a0, 0x00e86a}, /* U+9460 */ - {0x00e991a2, 0x00e86b}, /* U+9462 */ - {0x00e991a3, 0x00ef69}, /* U+9463 [2000] */ - {0x00e991aa, 0x00e86d}, /* U+946A */ - {0x00e991ab, 0x00ef6a}, /* U+946B [2000] */ - {0x00e991ad, 0x00fb6f}, /* U+946D [2000] */ - {0x00e991af, 0x00fb70}, /* U+946F [2000] */ - {0x00e991b0, 0x00e86f}, /* U+9470 */ - {0x00e991b1, 0x00ef6b}, /* U+9471 [2000] */ - {0x00e991b2, 0x00ef6c}, /* U+9472 [2000] */ - {0x00e991b5, 0x00e870}, /* U+9475 */ - {0x00e991b7, 0x00e871}, /* U+9477 */ - {0x00e991bc, 0x00e874}, /* U+947C */ - {0x00e991bd, 0x00e872}, /* U+947D */ - {0x00e991be, 0x00e875}, /* U+947E */ - {0x00e991bf, 0x00e877}, /* U+947F */ - {0x00e99281, 0x00e876}, /* U+9481 */ - {0x00e995b7, 0x0092b7}, /* U+9577 */ - {0x00e995b8, 0x00fb71}, /* U+9578 [2000] */ - {0x00e995b9, 0x00fb72}, /* U+9579 [2000] */ - {0x00e99680, 0x0096e5}, /* U+9580 */ - {0x00e99682, 0x00e878}, /* U+9582 */ - {0x00e99683, 0x00914d}, /* U+9583 */ - {0x00e99686, 0x00fb73}, /* U+9586 [2000] */ - {0x00e99687, 0x00e879}, /* U+9587 */ - {0x00e99689, 0x0095c2}, /* U+9589 */ - {0x00e9968a, 0x00e87a}, /* U+958A */ - {0x00e9968b, 0x008a4a}, /* U+958B */ - {0x00e9968c, 0x00fb74}, /* U+958C [2000] */ - {0x00e9968d, 0x00fb75}, /* U+958D [2000] */ - {0x00e9968e, 0x00ef6d}, /* U+958E [2000] */ - {0x00e9968f, 0x00895b}, /* U+958F */ - {0x00e99691, 0x008ad5}, /* U+9591 */ - {0x00e99693, 0x008ad4}, /* U+9593 */ - {0x00e99694, 0x00e87b}, /* U+9594 */ - {0x00e99696, 0x00e87c}, /* U+9596 */ - {0x00e99698, 0x00e87d}, /* U+9598 */ - {0x00e99699, 0x00e87e}, /* U+9599 */ - {0x00e9969f, 0x00ef6e}, /* U+959F [2000] */ - {0x00e996a0, 0x00e880}, /* U+95A0 */ - {0x00e996a2, 0x008ad6}, /* U+95A2 */ - {0x00e996a3, 0x008a74}, /* U+95A3 */ - {0x00e996a4, 0x008d7d}, /* U+95A4 */ - {0x00e996a5, 0x0094b4}, /* U+95A5 */ - {0x00e996a6, 0x00ef6f}, /* U+95A6 [2000] */ - {0x00e996a7, 0x00e882}, /* U+95A7 */ - {0x00e996a8, 0x00e881}, /* U+95A8 */ - {0x00e996a9, 0x00ef70}, /* U+95A9 [2000] */ - {0x00e996ab, 0x00fb77}, /* U+95AB [2000] */ - {0x00e996ac, 0x00ef71}, /* U+95AC [2000] */ - {0x00e996ad, 0x00e883}, /* U+95AD */ - {0x00e996b2, 0x00897b}, /* U+95B2 */ - {0x00e996b4, 0x00fb78}, /* U+95B4 [2000] */ - {0x00e996b6, 0x00ef72}, /* U+95B6 [2000] */ - {0x00e996b9, 0x00e886}, /* U+95B9 */ - {0x00e996bb, 0x00e885}, /* U+95BB */ - {0x00e996bc, 0x00e884}, /* U+95BC */ - {0x00e996bd, 0x00ef73}, /* U+95BD [2000] */ - {0x00e996be, 0x00e887}, /* U+95BE */ - {0x00e99783, 0x00e88a}, /* U+95C3 */ - {0x00e99787, 0x0088c5}, /* U+95C7 */ - {0x00e99788, 0x00fb7a}, /* U+95C8 [2000] */ - {0x00e9978a, 0x00e888}, /* U+95CA */ - {0x00e9978b, 0x00ef74}, /* U+95CB [2000] */ - {0x00e9978c, 0x00e88c}, /* U+95CC */ - {0x00e9978d, 0x00e88b}, /* U+95CD */ - {0x00e99790, 0x00ef75}, /* U+95D0 [2000] */ - {0x00e99793, 0x00ef76}, /* U+95D3 [2000] */ - {0x00e99794, 0x00e88e}, /* U+95D4 */ - {0x00e99795, 0x00e88d}, /* U+95D5 */ - {0x00e99796, 0x00e88f}, /* U+95D6 */ - {0x00e99798, 0x0093ac}, /* U+95D8 */ - {0x00e9979a, 0x00ef78}, /* U+95DA [2000] */ - {0x00e9979c, 0x00e890}, /* U+95DC */ - {0x00e9979e, 0x00ef79}, /* U+95DE [2000] */ - {0x00e997a1, 0x00e891}, /* U+95E1 */ - {0x00e997a2, 0x00e893}, /* U+95E2 */ - {0x00e997a5, 0x00e892}, /* U+95E5 */ - {0x00e9989c, 0x00958c}, /* U+961C */ - {0x00e9989d, 0x00faa3}, /* U+961D [2000] */ - {0x00e998a1, 0x00e894}, /* U+9621 */ - {0x00e998a8, 0x00e895}, /* U+9628 */ - {0x00e998aa, 0x008de3}, /* U+962A */ - {0x00e998ac, 0x00fb7d}, /* U+962C [2000] */ - {0x00e998ae, 0x00e896}, /* U+962E */ - {0x00e998af, 0x00e897}, /* U+962F */ - {0x00e998b2, 0x009668}, /* U+9632 */ - {0x00e998b3, 0x00fb7e}, /* U+9633 [2000] */ - {0x00e998b4, 0x00fb80}, /* U+9634 [2000] */ - {0x00e998bb, 0x00916a}, /* U+963B */ - {0x00e998bc, 0x00fb82}, /* U+963C [2000] */ - {0x00e998bf, 0x0088a2}, /* U+963F */ - {0x00e99980, 0x0091c9}, /* U+9640 */ - {0x00e99981, 0x00fb83}, /* U+9641 [2000] */ - {0x00e99982, 0x00e898}, /* U+9642 */ - {0x00e99984, 0x00958d}, /* U+9644 */ - {0x00e9998b, 0x00e89b}, /* U+964B */ - {0x00e9998c, 0x00e899}, /* U+964C */ - {0x00e9998d, 0x008d7e}, /* U+964D */ - {0x00e9998f, 0x00e89a}, /* U+964F */ - {0x00e99990, 0x008cc0}, /* U+9650 */ - {0x00e99998, 0x00ef7a}, /* U+9658 [2000] */ - {0x00e9999b, 0x0095c3}, /* U+965B */ - {0x00e9999c, 0x00e89d}, /* U+965C */ - {0x00e9999d, 0x00e89f}, /* U+965D */ - {0x00e9999e, 0x00e89e}, /* U+965E */ - {0x00e9999f, 0x00e8a0}, /* U+965F */ - {0x00e999a1, 0x00fb84}, /* U+9661 [2000] */ - {0x00e999a2, 0x008940}, /* U+9662 */ - {0x00e999a3, 0x009077}, /* U+9663 */ - {0x00e999a4, 0x008f9c}, /* U+9664 */ - {0x00e999a5, 0x008ad7}, /* U+9665 */ - {0x00e999a6, 0x00e8a1}, /* U+9666 */ - {0x00e999aa, 0x009486}, /* U+966A */ - {0x00e999ac, 0x00e8a3}, /* U+966C */ - {0x00e999b0, 0x008941}, /* U+9670 */ - {0x00e999b2, 0x00e8a2}, /* U+9672 */ - {0x00e999b3, 0x0092c2}, /* U+9673 */ - {0x00e999b5, 0x0097cb}, /* U+9675 */ - {0x00e999b6, 0x0093a9}, /* U+9676 */ - {0x00e999b7, 0x00e89c}, /* U+9677 */ - {0x00e999b8, 0x0097a4}, /* U+9678 */ - {0x00e999ba, 0x008caf}, /* U+967A */ - {0x00e999bd, 0x00977a}, /* U+967D */ - {0x00e99a82, 0x00fb86}, /* U+9682 [2000] */ - {0x00e99a84, 0x00ef7b}, /* U+9684 [2000] */ - {0x00e99a85, 0x008bf7}, /* U+9685 */ - {0x00e99a86, 0x0097b2}, /* U+9686 */ - {0x00e99a88, 0x008c47}, /* U+9688 */ - {0x00e99a8a, 0x0091e0}, /* U+968A */ - {0x00e99a8b, 0x00e440}, /* U+968B */ - {0x00e99a8d, 0x00e8a4}, /* U+968D */ - {0x00e99a8e, 0x008a4b}, /* U+968E */ - {0x00e99a8f, 0x00908f}, /* U+968F */ - {0x00e99a94, 0x008a75}, /* U+9694 */ - {0x00e99a95, 0x00e8a6}, /* U+9695 */ - {0x00e99a97, 0x00e8a7}, /* U+9697 */ - {0x00e99a98, 0x00e8a5}, /* U+9698 */ - {0x00e99a99, 0x008c84}, /* U+9699 */ - {0x00e99a9a, 0x00fb88}, /* U+969A [2000] */ - {0x00e99a9b, 0x008ddb}, /* U+969B */ - {0x00e99a9c, 0x008fe1}, /* U+969C */ - {0x00e99a9d, 0x00ef7d}, /* U+969D [2000] */ - {0x00e99aa0, 0x008942}, /* U+96A0 */ - {0x00e99aa3, 0x0097d7}, /* U+96A3 */ - {0x00e99aa4, 0x00ef7e}, /* U+96A4 [2000] */ - {0x00e99aa5, 0x00ef80}, /* U+96A5 [2000] */ - {0x00e99aa7, 0x00e8a9}, /* U+96A7 */ - {0x00e99aa8, 0x00e7ac}, /* U+96A8 */ - {0x00e99aa9, 0x00fb8b}, /* U+96A9 [2000] */ - {0x00e99aaa, 0x00e8a8}, /* U+96AA */ - {0x00e99aaf, 0x00fb8c}, /* U+96AF [2000] */ - {0x00e99ab0, 0x00e8ac}, /* U+96B0 */ - {0x00e99ab1, 0x00e8aa}, /* U+96B1 */ - {0x00e99ab2, 0x00e8ab}, /* U+96B2 */ - {0x00e99ab3, 0x00fb8d}, /* U+96B3 [2000] */ - {0x00e99ab4, 0x00e8ad}, /* U+96B4 */ - {0x00e99ab6, 0x00e8ae}, /* U+96B6 */ - {0x00e99ab7, 0x0097ea}, /* U+96B7 */ - {0x00e99ab8, 0x00e8af}, /* U+96B8 */ - {0x00e99ab9, 0x00e8b0}, /* U+96B9 */ - {0x00e99aba, 0x00fb8e}, /* U+96BA [2000] */ - {0x00e99abb, 0x0090c7}, /* U+96BB */ - {0x00e99abc, 0x0094b9}, /* U+96BC */ - {0x00e99abd, 0x00fb8f}, /* U+96BD [2000] */ - {0x00e99b80, 0x00909d}, /* U+96C0 */ - {0x00e99b81, 0x008ae5}, /* U+96C1 */ - {0x00e99b84, 0x009759}, /* U+96C4 */ - {0x00e99b85, 0x0089eb}, /* U+96C5 */ - {0x00e99b86, 0x008f57}, /* U+96C6 */ - {0x00e99b87, 0x008cd9}, /* U+96C7 */ - {0x00e99b89, 0x00e8b3}, /* U+96C9 */ - {0x00e99b8b, 0x00e8b2}, /* U+96CB */ - {0x00e99b8c, 0x008e93}, /* U+96CC */ - {0x00e99b8d, 0x00e8b4}, /* U+96CD */ - {0x00e99b8e, 0x00e8b1}, /* U+96CE */ - {0x00e99b91, 0x008e47}, /* U+96D1 */ - {0x00e99b92, 0x00ef81}, /* U+96D2 [2000] */ - {0x00e99b95, 0x00e8b8}, /* U+96D5 */ - {0x00e99b96, 0x00e5ab}, /* U+96D6 */ - {0x00e99b98, 0x00fb92}, /* U+96D8 [2000] */ - {0x00e99b99, 0x0099d4}, /* U+96D9 */ - {0x00e99b9a, 0x00fb93}, /* U+96DA [2000] */ - {0x00e99b9b, 0x009097}, /* U+96DB */ - {0x00e99b9c, 0x00e8b6}, /* U+96DC */ - {0x00e99b9d, 0x00fb94}, /* U+96DD [2000] */ - {0x00e99b9e, 0x00ef82}, /* U+96DE [2000] */ - {0x00e99ba2, 0x0097a3}, /* U+96E2 */ - {0x00e99ba3, 0x0093ef}, /* U+96E3 */ - {0x00e99ba8, 0x00894a}, /* U+96E8 */ - {0x00e99ba9, 0x00ef84}, /* U+96E9 [2000] */ - {0x00e99baa, 0x0090e1}, /* U+96EA */ - {0x00e99bab, 0x008eb4}, /* U+96EB */ - {0x00e99baf, 0x00ef85}, /* U+96EF [2000] */ - {0x00e99bb0, 0x0095b5}, /* U+96F0 */ - {0x00e99bb2, 0x00895f}, /* U+96F2 */ - {0x00e99bb6, 0x0097eb}, /* U+96F6 */ - {0x00e99bb7, 0x00978b}, /* U+96F7 */ - {0x00e99bb9, 0x00e8b9}, /* U+96F9 */ - {0x00e99bbb, 0x009364}, /* U+96FB */ - {0x00e99c80, 0x008ef9}, /* U+9700 */ - {0x00e99c84, 0x00e8ba}, /* U+9704 */ - {0x00e99c86, 0x00e8bb}, /* U+9706 */ - {0x00e99c87, 0x00906b}, /* U+9707 */ - {0x00e99c88, 0x00e8bc}, /* U+9708 */ - {0x00e99c8a, 0x0097ec}, /* U+970A */ - {0x00e99c8d, 0x00e8b7}, /* U+970D */ - {0x00e99c8e, 0x00e8be}, /* U+970E */ - {0x00e99c8f, 0x00e8c0}, /* U+970F */ - {0x00e99c91, 0x00e8bf}, /* U+9711 */ - {0x00e99c93, 0x00e8bd}, /* U+9713 */ - {0x00e99c94, 0x00fb96}, /* U+9714 [2000] */ - {0x00e99c96, 0x00e8c1}, /* U+9716 */ - {0x00e99c99, 0x00e8c2}, /* U+9719 */ - {0x00e99c9c, 0x00919a}, /* U+971C */ - {0x00e99c9e, 0x0089e0}, /* U+971E */ - {0x00e99ca3, 0x00fb97}, /* U+9723 [2000] */ - {0x00e99ca4, 0x00e8c3}, /* U+9724 */ - {0x00e99ca7, 0x0096b6}, /* U+9727 */ - {0x00e99caa, 0x00e8c4}, /* U+972A */ - {0x00e99cb0, 0x00e8c5}, /* U+9730 */ - {0x00e99cb2, 0x009849}, /* U+9732 */ - {0x00e99cb3, 0x00ef86}, /* U+9733 [2000] */ - {0x00e99cb6, 0x00fb99}, /* U+9736 [2000] */ - {0x00e99cb8, 0x009e50}, /* U+9738 */ - {0x00e99cb9, 0x00e8c6}, /* U+9739 */ - {0x00e99cbb, 0x00ef87}, /* U+973B [2000] */ - {0x00e99cbd, 0x00e8c7}, /* U+973D */ - {0x00e99cbe, 0x00e8c8}, /* U+973E */ - {0x00e99d81, 0x00fb9a}, /* U+9741 [2000] */ - {0x00e99d82, 0x00e8cc}, /* U+9742 */ - {0x00e99d84, 0x00e8c9}, /* U+9744 */ - {0x00e99d86, 0x00e8ca}, /* U+9746 */ - {0x00e99d87, 0x00fb9b}, /* U+9747 [2000] */ - {0x00e99d88, 0x00e8cb}, /* U+9748 */ - {0x00e99d89, 0x00e8cd}, /* U+9749 */ - {0x00e99d8d, 0x00ef88}, /* U+974D [2000] */ - {0x00e99d8e, 0x00ef89}, /* U+974E [2000] */ - {0x00e99d8f, 0x00ef8a}, /* U+974F [2000] */ - {0x00e99d92, 0x0090c2}, /* U+9752 */ - {0x00e99d95, 0x00fb9c}, /* U+9755 [2000] */ - {0x00e99d96, 0x0096f5}, /* U+9756 */ - {0x00e99d97, 0x00fb9d}, /* U+9757 [2000] */ - {0x00e99d99, 0x0090c3}, /* U+9759 */ - {0x00e99d9a, 0x00ef8b}, /* U+975A [2000] */ - {0x00e99d9b, 0x00fb9e}, /* U+975B [2000] */ - {0x00e99d9c, 0x00e8ce}, /* U+975C */ - {0x00e99d9e, 0x0094f1}, /* U+975E */ - {0x00e99da0, 0x00e8cf}, /* U+9760 */ - {0x00e99da1, 0x00ea72}, /* U+9761 */ - {0x00e99da2, 0x0096ca}, /* U+9762 */ - {0x00e99da4, 0x00e8d0}, /* U+9764 */ - {0x00e99da6, 0x00e8d1}, /* U+9766 */ - {0x00e99da8, 0x00e8d2}, /* U+9768 */ - {0x00e99da9, 0x008a76}, /* U+9769 */ - {0x00e99daa, 0x00fb9f}, /* U+976A [2000] */ - {0x00e99dab, 0x00e8d4}, /* U+976B */ - {0x00e99dad, 0x009078}, /* U+976D */ - {0x00e99dae, 0x00ef8c}, /* U+976E [2000] */ - {0x00e99db1, 0x00e8d5}, /* U+9771 */ - {0x00e99db3, 0x00ef8d}, /* U+9773 [2000] */ - {0x00e99db4, 0x008c43}, /* U+9774 */ - {0x00e99db9, 0x00e8d6}, /* U+9779 */ - {0x00e99dba, 0x00e8da}, /* U+977A */ - {0x00e99dbc, 0x00e8d8}, /* U+977C */ - {0x00e99e81, 0x00e8d9}, /* U+9781 */ - {0x00e99e84, 0x008a93}, /* U+9784 */ - {0x00e99e85, 0x00e8d7}, /* U+9785 */ - {0x00e99e86, 0x00e8db}, /* U+9786 */ - {0x00e99e8b, 0x00e8dc}, /* U+978B */ - {0x00e99e8d, 0x0088c6}, /* U+978D */ - {0x00e99e8f, 0x00e8dd}, /* U+978F */ - {0x00e99e90, 0x00e8de}, /* U+9790 */ - {0x00e99e95, 0x00ef8e}, /* U+9795 [2000] */ - {0x00e99e96, 0x00fba2}, /* U+9796 [2000] */ - {0x00e99e98, 0x008fe2}, /* U+9798 */ - {0x00e99e9a, 0x00fba3}, /* U+979A [2000] */ - {0x00e99e9c, 0x00e8df}, /* U+979C */ - {0x00e99e9e, 0x00fba4}, /* U+979E [2000] */ - {0x00e99ea0, 0x008b66}, /* U+97A0 */ - {0x00e99ea2, 0x00fba5}, /* U+97A2 [2000] */ - {0x00e99ea3, 0x00e8e2}, /* U+97A3 */ - {0x00e99ea6, 0x00e8e1}, /* U+97A6 */ - {0x00e99ea8, 0x00e8e0}, /* U+97A8 */ - {0x00e99eab, 0x00e691}, /* U+97AB */ - {0x00e99ead, 0x0095da}, /* U+97AD */ - {0x00e99eae, 0x00ef8f}, /* U+97AE [2000] */ - {0x00e99eb1, 0x00fba6}, /* U+97B1 [2000] */ - {0x00e99eb2, 0x00fba7}, /* U+97B2 [2000] */ - {0x00e99eb3, 0x00e8e3}, /* U+97B3 */ - {0x00e99eb4, 0x00e8e4}, /* U+97B4 */ - {0x00e99eba, 0x00ef90}, /* U+97BA [2000] */ - {0x00e99ebe, 0x00fba8}, /* U+97BE [2000] */ - {0x00e99f81, 0x00ef91}, /* U+97C1 [2000] */ - {0x00e99f83, 0x00e8e5}, /* U+97C3 */ - {0x00e99f86, 0x00e8e6}, /* U+97C6 */ - {0x00e99f88, 0x00e8e7}, /* U+97C8 */ - {0x00e99f89, 0x00ef92}, /* U+97C9 [2000] */ - {0x00e99f8b, 0x00e8e8}, /* U+97CB */ - {0x00e99f8c, 0x00fba9}, /* U+97CC [2000] */ - {0x00e99f91, 0x00fbaa}, /* U+97D1 [2000] */ - {0x00e99f93, 0x008ad8}, /* U+97D3 */ - {0x00e99f94, 0x00fbab}, /* U+97D4 [2000] */ - {0x00e99f98, 0x00fbac}, /* U+97D8 [2000] */ - {0x00e99f99, 0x00fbad}, /* U+97D9 [2000] */ - {0x00e99f9b, 0x00ef94}, /* U+97DB [2000] */ - {0x00e99f9c, 0x00e8e9}, /* U+97DC */ - {0x00e99f9e, 0x00ef93}, /* U+97DE [2000] */ - {0x00e99fa1, 0x00fbae}, /* U+97E1 [2000] */ - {0x00e99fad, 0x00e8ea}, /* U+97ED */ - {0x00e99fae, 0x009442}, /* U+97EE */ - {0x00e99fb1, 0x00fbaf}, /* U+97F1 [2000] */ - {0x00e99fb2, 0x00e8ec}, /* U+97F2 */ - {0x00e99fb3, 0x0089b9}, /* U+97F3 */ - {0x00e99fb4, 0x00ef95}, /* U+97F4 [2000] */ - {0x00e99fb5, 0x00e8ef}, /* U+97F5 */ - {0x00e99fb6, 0x00e8ee}, /* U+97F6 */ - {0x00e99fbb, 0x008943}, /* U+97FB */ - {0x00e99fbf, 0x008bbf}, /* U+97FF */ - {0x00e9a081, 0x0095c5}, /* U+9801 */ - {0x00e9a082, 0x0092b8}, /* U+9802 */ - {0x00e9a083, 0x008da0}, /* U+9803 */ - {0x00e9a084, 0x00fbb0}, /* U+9804 [2000] */ - {0x00e9a085, 0x008d80}, /* U+9805 */ - {0x00e9a086, 0x008f87}, /* U+9806 */ - {0x00e9a088, 0x00907b}, /* U+9808 */ - {0x00e9a08a, 0x00ef97}, /* U+980A [2000] */ - {0x00e9a08c, 0x00e8f1}, /* U+980C */ - {0x00e9a08d, 0x00fbb1}, /* U+980D [2000] */ - {0x00e9a08e, 0x00fbb2}, /* U+980E [2000] */ - {0x00e9a08f, 0x00e8f0}, /* U+980F */ - {0x00e9a090, 0x009761}, /* U+9810 */ - {0x00e9a091, 0x008ae6}, /* U+9811 */ - {0x00e9a092, 0x0094d0}, /* U+9812 */ - {0x00e9a093, 0x0093da}, /* U+9813 */ - {0x00e9a094, 0x00fbb3}, /* U+9814 [2000] */ - {0x00e9a096, 0x00fbb4}, /* U+9816 [2000] */ - {0x00e9a097, 0x00909c}, /* U+9817 */ - {0x00e9a098, 0x0097cc}, /* U+9818 */ - {0x00e9a09a, 0x008c7a}, /* U+981A */ - {0x00e9a09e, 0x00ef98}, /* U+981E [2000] */ - {0x00e9a0a1, 0x00e8f4}, /* U+9821 */ - {0x00e9a0a3, 0x00fbb7}, /* U+9823 [2000] */ - {0x00e9a0a4, 0x00e8f3}, /* U+9824 */ - {0x00e9a0a5, 0x00fbba}, /* U+9825 [2000] */ - {0x00e9a0ab, 0x00ef99}, /* U+982B [2000] */ - {0x00e9a0ac, 0x00966a}, /* U+982C */ - {0x00e9a0ad, 0x0093aa}, /* U+982D */ - {0x00e9a0b0, 0x00ef9a}, /* U+9830 [2000] */ - {0x00e9a0b2, 0x00fbb8}, /* U+9832 [2000] */ - {0x00e9a0b3, 0x00fbb9}, /* U+9833 [2000] */ - {0x00e9a0b4, 0x00896f}, /* U+9834 */ - {0x00e9a0b7, 0x00e8f5}, /* U+9837 */ - {0x00e9a0b8, 0x00e8f2}, /* U+9838 */ - {0x00e9a0bb, 0x009570}, /* U+983B */ - {0x00e9a0bc, 0x00978a}, /* U+983C */ - {0x00e9a0bd, 0x00e8f6}, /* U+983D */ - {0x00e9a186, 0x00e8f7}, /* U+9846 */ - {0x00e9a187, 0x00fbbb}, /* U+9847 [2000] */ - {0x00e9a18b, 0x00e8f9}, /* U+984B */ - {0x00e9a18c, 0x0091e8}, /* U+984C */ - {0x00e9a18d, 0x008a7a}, /* U+984D */ - {0x00e9a18e, 0x008a7b}, /* U+984E */ - {0x00e9a18f, 0x00e8f8}, /* U+984F */ - {0x00e9a192, 0x00ef9c}, /* U+9852 [2000] */ - {0x00e9a193, 0x00ef9d}, /* U+9853 [2000] */ - {0x00e9a194, 0x008ae7}, /* U+9854 */ - {0x00e9a195, 0x008cb0}, /* U+9855 */ - {0x00e9a196, 0x00ef9e}, /* U+9856 [2000] */ - {0x00e9a197, 0x00ef9f}, /* U+9857 [2000] */ - {0x00e9a198, 0x008ae8}, /* U+9858 */ - {0x00e9a199, 0x00efa0}, /* U+9859 [2000] */ - {0x00e9a19a, 0x00efa1}, /* U+985A [2000] */ - {0x00e9a19b, 0x00935e}, /* U+985B */ - {0x00e9a19e, 0x0097de}, /* U+985E */ - {0x00e9a1a5, 0x00efa3}, /* U+9865 [2000] */ - {0x00e9a1a6, 0x00fbbc}, /* U+9866 [2000] */ - {0x00e9a1a7, 0x008cda}, /* U+9867 */ - {0x00e9a1ab, 0x00e8fa}, /* U+986B */ - {0x00e9a1ac, 0x00efa4}, /* U+986C [2000] */ - {0x00e9a1af, 0x00e8fb}, /* U+986F */ - {0x00e9a1b0, 0x00e8fc}, /* U+9870 */ - {0x00e9a1b1, 0x00e940}, /* U+9871 */ - {0x00e9a1b3, 0x00e942}, /* U+9873 */ - {0x00e9a1b4, 0x00e941}, /* U+9874 */ - {0x00e9a2a8, 0x009597}, /* U+98A8 */ - {0x00e9a2aa, 0x00e943}, /* U+98AA */ - {0x00e9a2ab, 0x00fbbd}, /* U+98AB [2000] */ - {0x00e9a2ad, 0x00fbbe}, /* U+98AD [2000] */ - {0x00e9a2af, 0x00e944}, /* U+98AF */ - {0x00e9a2b0, 0x00fbbf}, /* U+98B0 [2000] */ - {0x00e9a2b1, 0x00e945}, /* U+98B1 */ - {0x00e9a2b6, 0x00e946}, /* U+98B6 */ - {0x00e9a2b7, 0x00fbc1}, /* U+98B7 [2000] */ - {0x00e9a2b8, 0x00fbc2}, /* U+98B8 [2000] */ - {0x00e9a2ba, 0x00efa5}, /* U+98BA [2000] */ - {0x00e9a2bb, 0x00fbc3}, /* U+98BB [2000] */ - {0x00e9a2bc, 0x00fbc4}, /* U+98BC [2000] */ - {0x00e9a2bf, 0x00fbc5}, /* U+98BF [2000] */ - {0x00e9a382, 0x00fbc6}, /* U+98C2 [2000] */ - {0x00e9a383, 0x00e948}, /* U+98C3 */ - {0x00e9a384, 0x00e947}, /* U+98C4 */ - {0x00e9a386, 0x00e949}, /* U+98C6 */ - {0x00e9a387, 0x00fbc7}, /* U+98C7 [2000] */ - {0x00e9a388, 0x00efa6}, /* U+98C8 [2000] */ - {0x00e9a38b, 0x00fbc8}, /* U+98CB [2000] */ - {0x00e9a39b, 0x0094f2}, /* U+98DB */ - {0x00e9a39c, 0x00e3ca}, /* U+98DC */ - {0x00e9a39f, 0x009048}, /* U+98DF */ - {0x00e9a3a0, 0x00fbc9}, /* U+98E0 [2000] */ - {0x00e9a3a1, 0x00fbcb}, /* U+98E1 [2000] */ - {0x00e9a3a2, 0x008b51}, /* U+98E2 */ - {0x00e9a3a3, 0x00fbcc}, /* U+98E3 [2000] */ - {0x00e9a3a5, 0x00fbcd}, /* U+98E5 [2000] */ - {0x00e9a3a7, 0x00efa7}, /* U+98E7 [2000] */ - {0x00e9a3a9, 0x00e94a}, /* U+98E9 */ - {0x00e9a3aa, 0x00fbce}, /* U+98EA [2000] */ - {0x00e9a3ab, 0x00e94b}, /* U+98EB */ - {0x00e9a3ad, 0x0099aa}, /* U+98ED */ - {0x00e9a3ae, 0x009f5a}, /* U+98EE */ - {0x00e9a3af, 0x0094d1}, /* U+98EF */ - {0x00e9a3b0, 0x00fbcf}, /* U+98F0 [2000] */ - {0x00e9a3b1, 0x00fbd0}, /* U+98F1 [2000] */ - {0x00e9a3b2, 0x0088f9}, /* U+98F2 */ - {0x00e9a3b3, 0x00fbd1}, /* U+98F3 [2000] */ - {0x00e9a3b4, 0x0088b9}, /* U+98F4 */ - {0x00e9a3bc, 0x008e94}, /* U+98FC */ - {0x00e9a3bd, 0x00964f}, /* U+98FD */ - {0x00e9a3be, 0x008ffc}, /* U+98FE */ - {0x00e9a483, 0x00e94c}, /* U+9903 */ - {0x00e9a485, 0x0096dd}, /* U+9905 */ - {0x00e9a488, 0x00fbd2}, /* U+9908 [2000] */ - {0x00e9a489, 0x00e94d}, /* U+9909 */ - {0x00e9a48a, 0x00977b}, /* U+990A */ - {0x00e9a48c, 0x008961}, /* U+990C */ - {0x00e9a490, 0x008e60}, /* U+9910 */ - {0x00e9a492, 0x00e94e}, /* U+9912 */ - {0x00e9a493, 0x0089ec}, /* U+9913 */ - {0x00e9a494, 0x00e94f}, /* U+9914 */ - {0x00e9a496, 0x00fbd5}, /* U+9916 [2000] */ - {0x00e9a497, 0x00fbd6}, /* U+9917 [2000] */ - {0x00e9a498, 0x00e950}, /* U+9918 */ - {0x00e9a49a, 0x00fbd8}, /* U+991A [2000] */ - {0x00e9a49b, 0x00fbd9}, /* U+991B [2000] */ - {0x00e9a49c, 0x00fbda}, /* U+991C [2000] */ - {0x00e9a49d, 0x00e952}, /* U+991D */ - {0x00e9a49e, 0x00e953}, /* U+991E */ - {0x00e9a4a0, 0x00e955}, /* U+9920 */ - {0x00e9a4a1, 0x00e951}, /* U+9921 */ - {0x00e9a4a4, 0x00e954}, /* U+9924 */ - {0x00e9a4a8, 0x008ad9}, /* U+9928 */ - {0x00e9a4ac, 0x00e956}, /* U+992C */ - {0x00e9a4ae, 0x00e957}, /* U+992E */ - {0x00e9a4b1, 0x00fbdc}, /* U+9931 [2000] */ - {0x00e9a4b2, 0x00fbdd}, /* U+9932 [2000] */ - {0x00e9a4b3, 0x00fbde}, /* U+9933 [2000] */ - {0x00e9a4ba, 0x00fbdf}, /* U+993A [2000] */ - {0x00e9a4bb, 0x00fbe0}, /* U+993B [2000] */ - {0x00e9a4bc, 0x00fbe1}, /* U+993C [2000] */ - {0x00e9a4bd, 0x00e958}, /* U+993D */ - {0x00e9a4be, 0x00e959}, /* U+993E */ - {0x00e9a580, 0x00fbe2}, /* U+9940 [2000] */ - {0x00e9a581, 0x00fbe3}, /* U+9941 [2000] */ - {0x00e9a582, 0x00e95a}, /* U+9942 */ - {0x00e9a585, 0x00e95c}, /* U+9945 */ - {0x00e9a586, 0x00fbe4}, /* U+9946 [2000] */ - {0x00e9a589, 0x00e95b}, /* U+9949 */ - {0x00e9a58b, 0x00e95e}, /* U+994B */ - {0x00e9a58c, 0x00e961}, /* U+994C */ - {0x00e9a58d, 0x00fbe5}, /* U+994D [2000] */ - {0x00e9a58e, 0x00fbe6}, /* U+994E [2000] */ - {0x00e9a590, 0x00e95d}, /* U+9950 */ - {0x00e9a591, 0x00e95f}, /* U+9951 */ - {0x00e9a592, 0x00e960}, /* U+9952 */ - {0x00e9a595, 0x00e962}, /* U+9955 */ - {0x00e9a597, 0x008bc0}, /* U+9957 */ - {0x00e9a598, 0x00efa8}, /* U+9958 [2000] */ - {0x00e9a59c, 0x00fbe7}, /* U+995C [2000] */ - {0x00e9a59f, 0x00fbe8}, /* U+995F [2000] */ - {0x00e9a5a0, 0x00fbe9}, /* U+9960 [2000] */ - {0x00e9a696, 0x008ef1}, /* U+9996 */ - {0x00e9a697, 0x00e963}, /* U+9997 */ - {0x00e9a698, 0x00e964}, /* U+9998 */ - {0x00e9a699, 0x008d81}, /* U+9999 */ - {0x00e9a69e, 0x00efa9}, /* U+999E [2000] */ - {0x00e9a6a3, 0x00fbea}, /* U+99A3 [2000] */ - {0x00e9a6a5, 0x00e965}, /* U+99A5 */ - {0x00e9a6a6, 0x00fbeb}, /* U+99A6 [2000] */ - {0x00e9a6a8, 0x008a5d}, /* U+99A8 */ - {0x00e9a6ac, 0x00946e}, /* U+99AC */ - {0x00e9a6ad, 0x00e966}, /* U+99AD */ - {0x00e9a6ae, 0x00e967}, /* U+99AE */ - {0x00e9a6b3, 0x009279}, /* U+99B3 */ - {0x00e9a6b4, 0x0093e9}, /* U+99B4 */ - {0x00e9a6b9, 0x00fbec}, /* U+99B9 [2000] */ - {0x00e9a6bc, 0x00e968}, /* U+99BC */ - {0x00e9a6bd, 0x00fbed}, /* U+99BD [2000] */ - {0x00e9a6bf, 0x00fbee}, /* U+99BF [2000] */ - {0x00e9a781, 0x00949d}, /* U+99C1 */ - {0x00e9a783, 0x00fbef}, /* U+99C3 [2000] */ - {0x00e9a784, 0x0091ca}, /* U+99C4 */ - {0x00e9a785, 0x008977}, /* U+99C5 */ - {0x00e9a786, 0x008bec}, /* U+99C6 */ - {0x00e9a788, 0x008bed}, /* U+99C8 */ - {0x00e9a789, 0x00fbf0}, /* U+99C9 [2000] */ - {0x00e9a790, 0x009293}, /* U+99D0 */ - {0x00e9a791, 0x00e96d}, /* U+99D1 */ - {0x00e9a792, 0x008bee}, /* U+99D2 */ - {0x00e9a794, 0x00fbf1}, /* U+99D4 [2000] */ - {0x00e9a795, 0x0089ed}, /* U+99D5 */ - {0x00e9a798, 0x00e96c}, /* U+99D8 */ - {0x00e9a799, 0x00fbf2}, /* U+99D9 [2000] */ - {0x00e9a79b, 0x00e96a}, /* U+99DB */ - {0x00e9a79d, 0x00e96b}, /* U+99DD */ - {0x00e9a79e, 0x00fbf3}, /* U+99DE [2000] */ - {0x00e9a79f, 0x00e969}, /* U+99DF */ - {0x00e9a7a2, 0x00e977}, /* U+99E2 */ - {0x00e9a7ad, 0x00e96e}, /* U+99ED */ - {0x00e9a7ae, 0x00e96f}, /* U+99EE */ - {0x00e9a7b0, 0x00fbf5}, /* U+99F0 [2000] */ - {0x00e9a7b1, 0x00e970}, /* U+99F1 */ - {0x00e9a7b2, 0x00e971}, /* U+99F2 */ - {0x00e9a7b8, 0x00e973}, /* U+99F8 */ - {0x00e9a7b9, 0x00fbf6}, /* U+99F9 [2000] */ - {0x00e9a7bb, 0x00e972}, /* U+99FB */ - {0x00e9a7bc, 0x00fbf7}, /* U+99FC [2000] */ - {0x00e9a7bf, 0x008f78}, /* U+99FF */ - {0x00e9a881, 0x00e974}, /* U+9A01 */ - {0x00e9a882, 0x00efaa}, /* U+9A02 [2000] */ - {0x00e9a883, 0x00efab}, /* U+9A03 [2000] */ - {0x00e9a885, 0x00e976}, /* U+9A05 */ - {0x00e9a88a, 0x00fbf8}, /* U+9A0A [2000] */ - {0x00e9a88e, 0x008b52}, /* U+9A0E */ - {0x00e9a88f, 0x00e975}, /* U+9A0F */ - {0x00e9a891, 0x00fbf9}, /* U+9A11 [2000] */ - {0x00e9a892, 0x00919b}, /* U+9A12 */ - {0x00e9a893, 0x008cb1}, /* U+9A13 */ - {0x00e9a896, 0x00fbfa}, /* U+9A16 [2000] */ - {0x00e9a899, 0x00e978}, /* U+9A19 */ - {0x00e9a89a, 0x00fbfb}, /* U+9A1A [2000] */ - {0x00e9a8a0, 0x00fbfc}, /* U+9A20 [2000] */ - {0x00e9a8a4, 0x00efac}, /* U+9A24 [2000] */ - {0x00e9a8a8, 0x0091cb}, /* U+9A28 */ - {0x00e9a8ab, 0x00e979}, /* U+9A2B */ - {0x00e9a8ad, 0x00efad}, /* U+9A2D [2000] */ - {0x00e9a8ae, 0x00efae}, /* U+9A2E [2000] */ - {0x00e9a8b0, 0x0093ab}, /* U+9A30 */ - {0x00e9a8b1, 0x00fc40}, /* U+9A31 [2000] */ - {0x00e9a8b6, 0x00fc41}, /* U+9A36 [2000] */ - {0x00e9a8b7, 0x00e97a}, /* U+9A37 */ - {0x00e9a8b8, 0x00efaf}, /* U+9A38 [2000] */ - {0x00e9a8be, 0x00e980}, /* U+9A3E */ - {0x00e9a980, 0x00e97d}, /* U+9A40 */ - {0x00e9a982, 0x00e97c}, /* U+9A42 */ - {0x00e9a983, 0x00e97e}, /* U+9A43 */ - {0x00e9a984, 0x00fc42}, /* U+9A44 [2000] */ - {0x00e9a985, 0x00e97b}, /* U+9A45 */ - {0x00e9a98a, 0x00efb0}, /* U+9A4A [2000] */ - {0x00e9a98c, 0x00fc43}, /* U+9A4C [2000] */ - {0x00e9a98d, 0x00e982}, /* U+9A4D */ - {0x00e9a98e, 0x00efb1}, /* U+9A4E [2000] */ - {0x00e9a992, 0x00efb2}, /* U+9A52 [2000] */ - {0x00e9a995, 0x00e981}, /* U+9A55 */ - {0x00e9a997, 0x00e984}, /* U+9A57 */ - {0x00e9a998, 0x00fc44}, /* U+9A58 [2000] */ - {0x00e9a99a, 0x008bc1}, /* U+9A5A */ - {0x00e9a99b, 0x00e983}, /* U+9A5B */ - {0x00e9a99f, 0x00e985}, /* U+9A5F */ - {0x00e9a9a2, 0x00e986}, /* U+9A62 */ - {0x00e9a9a4, 0x00e988}, /* U+9A64 */ - {0x00e9a9a5, 0x00e987}, /* U+9A65 */ - {0x00e9a9a9, 0x00e989}, /* U+9A69 */ - {0x00e9a9aa, 0x00e98b}, /* U+9A6A */ - {0x00e9a9ab, 0x00e98a}, /* U+9A6B */ - {0x00e9aaa8, 0x008d9c}, /* U+9AA8 */ - {0x00e9aaad, 0x00e98c}, /* U+9AAD */ - {0x00e9aaaf, 0x00fc46}, /* U+9AAF [2000] */ - {0x00e9aab0, 0x00e98d}, /* U+9AB0 */ - {0x00e9aab6, 0x00efb3}, /* U+9AB6 [2000] */ - {0x00e9aab7, 0x00fc48}, /* U+9AB7 [2000] */ - {0x00e9aab8, 0x008a5b}, /* U+9AB8 */ - {0x00e9aab9, 0x00fc4a}, /* U+9AB9 [2000] */ - {0x00e9aabc, 0x00e98e}, /* U+9ABC */ - {0x00e9ab80, 0x00e98f}, /* U+9AC0 */ - {0x00e9ab81, 0x00efb4}, /* U+9AC1 [2000] */ - {0x00e9ab83, 0x00efb5}, /* U+9AC3 [2000] */ - {0x00e9ab84, 0x009091}, /* U+9AC4 */ - {0x00e9ab86, 0x00fc4c}, /* U+9AC6 [2000] */ - {0x00e9ab8e, 0x00efb6}, /* U+9ACE [2000] */ - {0x00e9ab8f, 0x00e990}, /* U+9ACF */ - {0x00e9ab90, 0x00fc4d}, /* U+9AD0 [2000] */ - {0x00e9ab91, 0x00e991}, /* U+9AD1 */ - {0x00e9ab92, 0x00fc4e}, /* U+9AD2 [2000] */ - {0x00e9ab93, 0x00e992}, /* U+9AD3 */ - {0x00e9ab94, 0x00e993}, /* U+9AD4 */ - {0x00e9ab95, 0x00fc4f}, /* U+9AD5 [2000] */ - {0x00e9ab96, 0x00efb7}, /* U+9AD6 [2000] */ - {0x00e9ab98, 0x008d82}, /* U+9AD8 */ - {0x00e9ab9c, 0x00fc51}, /* U+9ADC [2000] */ - {0x00e9ab9e, 0x00e994}, /* U+9ADE */ - {0x00e9ab9f, 0x00e995}, /* U+9ADF */ - {0x00e9aba0, 0x00fc52}, /* U+9AE0 [2000] */ - {0x00e9aba2, 0x00e996}, /* U+9AE2 */ - {0x00e9aba3, 0x00e997}, /* U+9AE3 */ - {0x00e9aba5, 0x00fc53}, /* U+9AE5 [2000] */ - {0x00e9aba6, 0x00e998}, /* U+9AE6 */ - {0x00e9aba9, 0x00fc54}, /* U+9AE9 [2000] */ - {0x00e9abaa, 0x0094af}, /* U+9AEA */ - {0x00e9abab, 0x00e99a}, /* U+9AEB */ - {0x00e9abad, 0x009545}, /* U+9AED */ - {0x00e9abae, 0x00e99b}, /* U+9AEE */ - {0x00e9abaf, 0x00e999}, /* U+9AEF */ - {0x00e9abb1, 0x00e99d}, /* U+9AF1 */ - {0x00e9abb4, 0x00e99c}, /* U+9AF4 */ - {0x00e9abb7, 0x00e99e}, /* U+9AF7 */ - {0x00e9abb9, 0x00efb8}, /* U+9AF9 [2000] */ - {0x00e9abbb, 0x00e99f}, /* U+9AFB */ - {0x00e9ac82, 0x00efb9}, /* U+9B02 [2000] */ - {0x00e9ac83, 0x00fc55}, /* U+9B03 [2000] */ - {0x00e9ac86, 0x00e9a0}, /* U+9B06 */ - {0x00e9ac88, 0x00efba}, /* U+9B08 [2000] */ - {0x00e9ac8c, 0x00fc56}, /* U+9B0C [2000] */ - {0x00e9ac90, 0x00fc57}, /* U+9B10 [2000] */ - {0x00e9ac92, 0x00fc58}, /* U+9B12 [2000] */ - {0x00e9ac96, 0x00fc59}, /* U+9B16 [2000] */ - {0x00e9ac98, 0x00e9a1}, /* U+9B18 */ - {0x00e9ac9a, 0x00e9a2}, /* U+9B1A */ - {0x00e9ac9c, 0x00fc5a}, /* U+9B1C [2000] */ - {0x00e9ac9f, 0x00e9a3}, /* U+9B1F */ - {0x00e9aca0, 0x00efbb}, /* U+9B20 [2000] */ - {0x00e9aca2, 0x00e9a4}, /* U+9B22 */ - {0x00e9aca3, 0x00e9a5}, /* U+9B23 */ - {0x00e9aca5, 0x00e9a6}, /* U+9B25 */ - {0x00e9aca7, 0x00e9a7}, /* U+9B27 */ - {0x00e9aca8, 0x00e9a8}, /* U+9B28 */ - {0x00e9aca9, 0x00e9a9}, /* U+9B29 */ - {0x00e9acaa, 0x00e9aa}, /* U+9B2A */ - {0x00e9acab, 0x00fc5b}, /* U+9B2B [2000] */ - {0x00e9acad, 0x00efbd}, /* U+9B2D [2000] */ - {0x00e9acae, 0x00e9ab}, /* U+9B2E */ - {0x00e9acaf, 0x00e9ac}, /* U+9B2F */ - {0x00e9acb1, 0x009f54}, /* U+9B31 */ - {0x00e9acb2, 0x00e9ad}, /* U+9B32 */ - {0x00e9acb3, 0x00fc5c}, /* U+9B33 [2000] */ - {0x00e9acbb, 0x00e2f6}, /* U+9B3B */ - {0x00e9acbc, 0x008b53}, /* U+9B3C */ - {0x00e9acbd, 0x00fc5d}, /* U+9B3D [2000] */ - {0x00e9ad81, 0x008a40}, /* U+9B41 */ - {0x00e9ad82, 0x008db0}, /* U+9B42 */ - {0x00e9ad83, 0x00e9af}, /* U+9B43 */ - {0x00e9ad84, 0x00e9ae}, /* U+9B44 */ - {0x00e9ad85, 0x0096a3}, /* U+9B45 */ - {0x00e9ad8b, 0x00fc5f}, /* U+9B4B [2000] */ - {0x00e9ad8d, 0x00e9b1}, /* U+9B4D */ - {0x00e9ad8e, 0x00e9b2}, /* U+9B4E */ - {0x00e9ad8f, 0x00e9b0}, /* U+9B4F */ - {0x00e9ad91, 0x00e9b3}, /* U+9B51 */ - {0x00e9ad94, 0x009682}, /* U+9B54 */ - {0x00e9ad98, 0x00e9b4}, /* U+9B58 */ - {0x00e9ad9a, 0x008b9b}, /* U+9B5A */ - {0x00e9ad9e, 0x00efbe}, /* U+9B5E [2000] */ - {0x00e9ada3, 0x00fc60}, /* U+9B63 [2000] */ - {0x00e9ada5, 0x00fc61}, /* U+9B65 [2000] */ - {0x00e9ada6, 0x00efc0}, /* U+9B66 [2000] */ - {0x00e9adab, 0x00fc62}, /* U+9B6B [2000] */ - {0x00e9adac, 0x00fc63}, /* U+9B6C [2000] */ - {0x00e9adaf, 0x009844}, /* U+9B6F */ - {0x00e9adb2, 0x00efc1}, /* U+9B72 [2000] */ - {0x00e9adb3, 0x00fc64}, /* U+9B73 [2000] */ - {0x00e9adb4, 0x00e9b5}, /* U+9B74 */ - {0x00e9adb5, 0x00efc2}, /* U+9B75 [2000] */ - {0x00e9adb6, 0x00fc65}, /* U+9B76 [2000] */ - {0x00e9adb7, 0x00fc66}, /* U+9B77 [2000] */ - {0x00e9adb9, 0x00efbf}, /* U+9B79 [2000] */ - {0x00e9ae83, 0x00e9b7}, /* U+9B83 */ - {0x00e9ae84, 0x00efc3}, /* U+9B84 [2000] */ - {0x00e9ae8a, 0x00efc4}, /* U+9B8A [2000] */ - {0x00e9ae8e, 0x0088bc}, /* U+9B8E */ - {0x00e9ae8f, 0x00efc5}, /* U+9B8F [2000] */ - {0x00e9ae91, 0x00e9b8}, /* U+9B91 */ - {0x00e9ae92, 0x0095a9}, /* U+9B92 */ - {0x00e9ae93, 0x00e9b6}, /* U+9B93 */ - {0x00e9ae96, 0x00e9b9}, /* U+9B96 */ - {0x00e9ae97, 0x00e9ba}, /* U+9B97 */ - {0x00e9ae9e, 0x00efc6}, /* U+9B9E [2000] */ - {0x00e9ae9f, 0x00e9bb}, /* U+9B9F */ - {0x00e9aea0, 0x00e9bc}, /* U+9BA0 */ - {0x00e9aea6, 0x00fc67}, /* U+9BA6 [2000] */ - {0x00e9aea7, 0x00efc7}, /* U+9BA7 [2000] */ - {0x00e9aea8, 0x00e9bd}, /* U+9BA8 */ - {0x00e9aeaa, 0x00968e}, /* U+9BAA */ - {0x00e9aeab, 0x008e4c}, /* U+9BAB */ - {0x00e9aeac, 0x00fc68}, /* U+9BAC [2000] */ - {0x00e9aead, 0x008df8}, /* U+9BAD */ - {0x00e9aeae, 0x00914e}, /* U+9BAE */ - {0x00e9aeb1, 0x00fc69}, /* U+9BB1 [2000] */ - {0x00e9aeb2, 0x00fc6c}, /* U+9BB2 [2000] */ - {0x00e9aeb4, 0x00e9be}, /* U+9BB4 */ - {0x00e9aeb8, 0x00fc6d}, /* U+9BB8 [2000] */ - {0x00e9aeb9, 0x00e9c1}, /* U+9BB9 */ - {0x00e9aebe, 0x00fc6e}, /* U+9BBE [2000] */ - {0x00e9af80, 0x00e9bf}, /* U+9BC0 */ - {0x00e9af81, 0x00efc8}, /* U+9BC1 [2000] */ - {0x00e9af86, 0x00e9c2}, /* U+9BC6 */ - {0x00e9af87, 0x00fc6f}, /* U+9BC7 [2000] */ - {0x00e9af89, 0x008cef}, /* U+9BC9 */ - {0x00e9af8a, 0x00e9c0}, /* U+9BCA */ - {0x00e9af8e, 0x00efc9}, /* U+9BCE [2000] */ - {0x00e9af8f, 0x00e9c3}, /* U+9BCF */ - {0x00e9af91, 0x00e9c4}, /* U+9BD1 */ - {0x00e9af92, 0x00e9c5}, /* U+9BD2 */ - {0x00e9af94, 0x00e9c9}, /* U+9BD4 */ - {0x00e9af96, 0x008e49}, /* U+9BD6 */ - {0x00e9af98, 0x00fc71}, /* U+9BD8 [2000] */ - {0x00e9af9b, 0x0091e2}, /* U+9BDB */ - {0x00e9af9d, 0x00fc72}, /* U+9BDD [2000] */ - {0x00e9afa1, 0x00e9ca}, /* U+9BE1 */ - {0x00e9afa2, 0x00e9c7}, /* U+9BE2 */ - {0x00e9afa3, 0x00e9c6}, /* U+9BE3 */ - {0x00e9afa4, 0x00e9c8}, /* U+9BE4 */ - {0x00e9afa5, 0x00efca}, /* U+9BE5 [2000] */ - {0x00e9afa7, 0x00fc73}, /* U+9BE7 [2000] */ - {0x00e9afa8, 0x008c7e}, /* U+9BE8 */ - {0x00e9afaa, 0x00fc74}, /* U+9BEA [2000] */ - {0x00e9afab, 0x00fc75}, /* U+9BEB [2000] */ - {0x00e9afae, 0x00fc77}, /* U+9BEE [2000] */ - {0x00e9afaf, 0x00fc76}, /* U+9BEF [2000] */ - {0x00e9afb0, 0x00e9ce}, /* U+9BF0 */ - {0x00e9afb1, 0x00e9cd}, /* U+9BF1 */ - {0x00e9afb2, 0x00e9cc}, /* U+9BF2 */ - {0x00e9afb3, 0x00fc70}, /* U+9BF3 [2000] */ - {0x00e9afb5, 0x0088b1}, /* U+9BF5 */ - {0x00e9afb7, 0x00fc7b}, /* U+9BF7 [2000] */ - {0x00e9afb8, 0x00efcb}, /* U+9BF8 [2000] */ - {0x00e9afba, 0x00fc79}, /* U+9BFA [2000] */ - {0x00e9afbd, 0x00efcc}, /* U+9BFD [2000] */ - {0x00e9b080, 0x00efcd}, /* U+9C00 [2000] */ - {0x00e9b084, 0x00e9d8}, /* U+9C04 */ - {0x00e9b086, 0x00e9d4}, /* U+9C06 */ - {0x00e9b088, 0x00e9d5}, /* U+9C08 */ - {0x00e9b089, 0x00e9d1}, /* U+9C09 */ - {0x00e9b08a, 0x00e9d7}, /* U+9C0A */ - {0x00e9b08c, 0x00e9d3}, /* U+9C0C */ - {0x00e9b08d, 0x008a82}, /* U+9C0D */ - {0x00e9b090, 0x00986b}, /* U+9C10 */ - {0x00e9b092, 0x00e9d6}, /* U+9C12 */ - {0x00e9b093, 0x00e9d2}, /* U+9C13 */ - {0x00e9b094, 0x00e9d0}, /* U+9C14 */ - {0x00e9b095, 0x00e9cf}, /* U+9C15 */ - {0x00e9b096, 0x00fc7d}, /* U+9C16 [2000] */ - {0x00e9b098, 0x00fc7e}, /* U+9C18 [2000] */ - {0x00e9b099, 0x00fc80}, /* U+9C19 [2000] */ - {0x00e9b09a, 0x00fc81}, /* U+9C1A [2000] */ - {0x00e9b09b, 0x00e9da}, /* U+9C1B */ - {0x00e9b09d, 0x00fc82}, /* U+9C1D [2000] */ - {0x00e9b0a1, 0x00e9dd}, /* U+9C21 */ - {0x00e9b0a2, 0x00fc83}, /* U+9C22 [2000] */ - {0x00e9b0a3, 0x00efce}, /* U+9C23 [2000] */ - {0x00e9b0a4, 0x00e9dc}, /* U+9C24 */ - {0x00e9b0a5, 0x00e9db}, /* U+9C25 */ - {0x00e9b0a7, 0x00fc84}, /* U+9C27 [2000] */ - {0x00e9b0a9, 0x00fc85}, /* U+9C29 [2000] */ - {0x00e9b0aa, 0x00fc86}, /* U+9C2A [2000] */ - {0x00e9b0ad, 0x009568}, /* U+9C2D */ - {0x00e9b0ae, 0x00e9d9}, /* U+9C2E */ - {0x00e9b0af, 0x0088f1}, /* U+9C2F */ - {0x00e9b0b0, 0x00e9de}, /* U+9C30 */ - {0x00e9b0b1, 0x00fc88}, /* U+9C31 [2000] */ - {0x00e9b0b2, 0x00e9e0}, /* U+9C32 */ - {0x00e9b0b6, 0x00fc89}, /* U+9C36 [2000] */ - {0x00e9b0b7, 0x00fc8a}, /* U+9C37 [2000] */ - {0x00e9b0b9, 0x008a8f}, /* U+9C39 */ - {0x00e9b0ba, 0x00e9cb}, /* U+9C3A */ - {0x00e9b0bb, 0x008956}, /* U+9C3B */ - {0x00e9b0be, 0x00e9e2}, /* U+9C3E */ - {0x00e9b181, 0x00efcf}, /* U+9C41 [2000] */ - {0x00e9b185, 0x00fc8b}, /* U+9C45 [2000] */ - {0x00e9b186, 0x00e9e1}, /* U+9C46 */ - {0x00e9b187, 0x00e9df}, /* U+9C47 */ - {0x00e9b188, 0x00924c}, /* U+9C48 */ - {0x00e9b189, 0x00fc8e}, /* U+9C49 [2000] */ - {0x00e9b18a, 0x00fc8f}, /* U+9C4A [2000] */ - {0x00e9b18f, 0x00efd0}, /* U+9C4F [2000] */ - {0x00e9b190, 0x00efd1}, /* U+9C50 [2000] */ - {0x00e9b192, 0x009690}, /* U+9C52 */ - {0x00e9b193, 0x00efd2}, /* U+9C53 [2000] */ - {0x00e9b194, 0x00fc91}, /* U+9C54 [2000] */ - {0x00e9b197, 0x0097d8}, /* U+9C57 */ - {0x00e9b198, 0x00fc92}, /* U+9C58 [2000] */ - {0x00e9b19a, 0x00e9e3}, /* U+9C5A */ - {0x00e9b19b, 0x00fc93}, /* U+9C5B [2000] */ - {0x00e9b19c, 0x00fc8c}, /* U+9C5C [2000] */ - {0x00e9b19d, 0x00fc94}, /* U+9C5D [2000] */ - {0x00e9b19f, 0x00fc95}, /* U+9C5F [2000] */ - {0x00e9b1a0, 0x00e9e4}, /* U+9C60 */ - {0x00e9b1a3, 0x00efd3}, /* U+9C63 [2000] */ - {0x00e9b1a5, 0x00efd4}, /* U+9C65 [2000] */ - {0x00e9b1a7, 0x00e9e5}, /* U+9C67 */ - {0x00e9b1a9, 0x00fc96}, /* U+9C69 [2000] */ - {0x00e9b1aa, 0x00fc97}, /* U+9C6A [2000] */ - {0x00e9b1ab, 0x00fc98}, /* U+9C6B [2000] */ - {0x00e9b1ad, 0x00fc99}, /* U+9C6D [2000] */ - {0x00e9b1ae, 0x00fc9a}, /* U+9C6E [2000] */ - {0x00e9b1b0, 0x00fc9b}, /* U+9C70 [2000] */ - {0x00e9b1b2, 0x00fc9c}, /* U+9C72 [2000] */ - {0x00e9b1b5, 0x00fc9d}, /* U+9C75 [2000] */ - {0x00e9b1b6, 0x00e9e6}, /* U+9C76 */ - {0x00e9b1b7, 0x00efd5}, /* U+9C77 [2000] */ - {0x00e9b1b8, 0x00e9e7}, /* U+9C78 */ - {0x00e9b1ba, 0x00fc9e}, /* U+9C7A [2000] */ - {0x00e9b3a5, 0x0092b9}, /* U+9CE5 */ - {0x00e9b3a6, 0x00fc9f}, /* U+9CE6 [2000] */ - {0x00e9b3a7, 0x00e9e8}, /* U+9CE7 */ - {0x00e9b3a9, 0x0094b5}, /* U+9CE9 */ - {0x00e9b3ab, 0x00e9ed}, /* U+9CEB */ - {0x00e9b3ac, 0x00e9e9}, /* U+9CEC */ - {0x00e9b3b0, 0x00e9ea}, /* U+9CF0 */ - {0x00e9b3b2, 0x00fca0}, /* U+9CF2 [2000] */ - {0x00e9b3b3, 0x009650}, /* U+9CF3 */ - {0x00e9b3b4, 0x0096c2}, /* U+9CF4 */ - {0x00e9b3b6, 0x0093ce}, /* U+9CF6 */ - {0x00e9b482, 0x00fca2}, /* U+9D02 [2000] */ - {0x00e9b483, 0x00e9ee}, /* U+9D03 */ - {0x00e9b486, 0x00e9ef}, /* U+9D06 */ - {0x00e9b487, 0x0093bc}, /* U+9D07 */ - {0x00e9b488, 0x00e9ec}, /* U+9D08 */ - {0x00e9b489, 0x00e9eb}, /* U+9D09 */ - {0x00e9b48b, 0x00fca1}, /* U+9D0B [2000] */ - {0x00e9b48e, 0x0089a8}, /* U+9D0E */ - {0x00e9b491, 0x00fca4}, /* U+9D11 [2000] */ - {0x00e9b492, 0x00e9f7}, /* U+9D12 */ - {0x00e9b495, 0x00e9f6}, /* U+9D15 */ - {0x00e9b497, 0x00fca5}, /* U+9D17 [2000] */ - {0x00e9b498, 0x00fca6}, /* U+9D18 [2000] */ - {0x00e9b49b, 0x008995}, /* U+9D1B */ - {0x00e9b49d, 0x00efd6}, /* U+9D1D [2000] */ - {0x00e9b49e, 0x00efd7}, /* U+9D1E [2000] */ - {0x00e9b49f, 0x00e9f4}, /* U+9D1F */ - {0x00e9b4a3, 0x00e9f3}, /* U+9D23 */ - {0x00e9b4a6, 0x00e9f1}, /* U+9D26 */ - {0x00e9b4a8, 0x008a9b}, /* U+9D28 */ - {0x00e9b4aa, 0x00e9f0}, /* U+9D2A */ - {0x00e9b4ab, 0x008eb0}, /* U+9D2B */ - {0x00e9b4ac, 0x0089a7}, /* U+9D2C */ - {0x00e9b4b2, 0x00fcaa}, /* U+9D32 [2000] */ - {0x00e9b4bb, 0x008d83}, /* U+9D3B */ - {0x00e9b4be, 0x00e9fa}, /* U+9D3E */ - {0x00e9b4bf, 0x00e9f9}, /* U+9D3F */ - {0x00e9b581, 0x00e9f8}, /* U+9D41 */ - {0x00e9b582, 0x00fcac}, /* U+9D42 [2000] */ - {0x00e9b583, 0x00efd8}, /* U+9D43 [2000] */ - {0x00e9b584, 0x00e9f5}, /* U+9D44 */ - {0x00e9b586, 0x00e9fb}, /* U+9D46 */ - {0x00e9b587, 0x00efd9}, /* U+9D47 [2000] */ - {0x00e9b588, 0x00e9fc}, /* U+9D48 */ - {0x00e9b58a, 0x00fcad}, /* U+9D4A [2000] */ - {0x00e9b590, 0x00ea44}, /* U+9D50 */ - {0x00e9b591, 0x00ea43}, /* U+9D51 */ - {0x00e9b592, 0x00efda}, /* U+9D52 [2000] */ - {0x00e9b599, 0x00ea45}, /* U+9D59 */ - {0x00e9b59c, 0x00894c}, /* U+9D5C */ - {0x00e9b59d, 0x00ea40}, /* U+9D5D */ - {0x00e9b59e, 0x00ea41}, /* U+9D5E */ - {0x00e9b59f, 0x00fcae}, /* U+9D5F [2000] */ - {0x00e9b5a0, 0x008d94}, /* U+9D60 */ - {0x00e9b5a1, 0x0096b7}, /* U+9D61 */ - {0x00e9b5a2, 0x00fcaf}, /* U+9D62 [2000] */ - {0x00e9b5a3, 0x00efdb}, /* U+9D63 [2000] */ - {0x00e9b5a4, 0x00ea42}, /* U+9D64 */ - {0x00e9b5a9, 0x00fcb1}, /* U+9D69 [2000] */ - {0x00e9b5ab, 0x00fcb2}, /* U+9D6B [2000] */ - {0x00e9b5ac, 0x009651}, /* U+9D6C */ - {0x00e9b5af, 0x00ea4a}, /* U+9D6F */ - {0x00e9b5b0, 0x00efdc}, /* U+9D70 [2000] */ - {0x00e9b5b2, 0x00ea46}, /* U+9D72 */ - {0x00e9b5b3, 0x00fcb4}, /* U+9D73 [2000] */ - {0x00e9b5b6, 0x00fcb5}, /* U+9D76 [2000] */ - {0x00e9b5b7, 0x00fcb6}, /* U+9D77 [2000] */ - {0x00e9b5ba, 0x00ea4b}, /* U+9D7A */ - {0x00e9b5bc, 0x00efdd}, /* U+9D7C [2000] */ - {0x00e9b5be, 0x00fcb7}, /* U+9D7E [2000] */ - {0x00e9b684, 0x00fcb8}, /* U+9D84 [2000] */ - {0x00e9b687, 0x00ea48}, /* U+9D87 */ - {0x00e9b689, 0x00ea47}, /* U+9D89 */ - {0x00e9b68a, 0x00efde}, /* U+9D8A [2000] */ - {0x00e9b68d, 0x00fcb9}, /* U+9D8D [2000] */ - {0x00e9b68f, 0x008c7b}, /* U+9D8F */ - {0x00e9b696, 0x00efdf}, /* U+9D96 [2000] */ - {0x00e9b699, 0x00fcba}, /* U+9D99 [2000] */ - {0x00e9b69a, 0x00ea4c}, /* U+9D9A */ - {0x00e9b6a1, 0x00fcbb}, /* U+9DA1 [2000] */ - {0x00e9b6a4, 0x00ea4d}, /* U+9DA4 */ - {0x00e9b6a9, 0x00ea4e}, /* U+9DA9 */ - {0x00e9b6ab, 0x00ea49}, /* U+9DAB */ - {0x00e9b6ac, 0x00efe1}, /* U+9DAC [2000] */ - {0x00e9b6af, 0x00e9f2}, /* U+9DAF */ - {0x00e9b6b2, 0x00ea4f}, /* U+9DB2 */ - {0x00e9b6b4, 0x0092df}, /* U+9DB4 */ - {0x00e9b6b5, 0x00fcbd}, /* U+9DB5 [2000] */ - {0x00e9b6b8, 0x00ea53}, /* U+9DB8 */ - {0x00e9b6b9, 0x00fcbe}, /* U+9DB9 [2000] */ - {0x00e9b6ba, 0x00ea54}, /* U+9DBA */ - {0x00e9b6bb, 0x00ea52}, /* U+9DBB */ - {0x00e9b6bc, 0x00efe2}, /* U+9DBC [2000] */ - {0x00e9b6bd, 0x00fcbf}, /* U+9DBD [2000] */ - {0x00e9b6bf, 0x00fcbc}, /* U+9DBF [2000] */ - {0x00e9b780, 0x00efe0}, /* U+9DC0 [2000] */ - {0x00e9b781, 0x00ea51}, /* U+9DC1 */ - {0x00e9b782, 0x00ea57}, /* U+9DC2 */ - {0x00e9b783, 0x00fcc0}, /* U+9DC3 [2000] */ - {0x00e9b784, 0x00ea50}, /* U+9DC4 */ - {0x00e9b786, 0x00ea55}, /* U+9DC6 */ - {0x00e9b787, 0x00fcc1}, /* U+9DC7 [2000] */ - {0x00e9b789, 0x00fcc2}, /* U+9DC9 [2000] */ - {0x00e9b78f, 0x00ea56}, /* U+9DCF */ - {0x00e9b793, 0x00ea59}, /* U+9DD3 */ - {0x00e9b796, 0x00fcc3}, /* U+9DD6 [2000] */ - {0x00e9b797, 0x00efe3}, /* U+9DD7 [2000] */ - {0x00e9b799, 0x00ea58}, /* U+9DD9 */ - {0x00e9b79a, 0x00fcc4}, /* U+9DDA [2000] */ - {0x00e9b79f, 0x00fcc5}, /* U+9DDF [2000] */ - {0x00e9b7a0, 0x00fcc6}, /* U+9DE0 [2000] */ - {0x00e9b7a3, 0x00fcc7}, /* U+9DE3 [2000] */ - {0x00e9b7a6, 0x00ea5b}, /* U+9DE6 */ - {0x00e9b7a7, 0x00efe5}, /* U+9DE7 [2000] */ - {0x00e9b7ad, 0x00ea5c}, /* U+9DED */ - {0x00e9b7af, 0x00ea5d}, /* U+9DEF */ - {0x00e9b7b2, 0x009868}, /* U+9DF2 */ - {0x00e9b7b4, 0x00fcc8}, /* U+9DF4 [2000] */ - {0x00e9b7b8, 0x00ea5a}, /* U+9DF8 */ - {0x00e9b7b9, 0x0091e9}, /* U+9DF9 */ - {0x00e9b7ba, 0x008deb}, /* U+9DFA */ - {0x00e9b7bd, 0x00ea5e}, /* U+9DFD */ - {0x00e9b882, 0x00fccb}, /* U+9E02 [2000] */ - {0x00e9b887, 0x00efe6}, /* U+9E07 [2000] */ - {0x00e9b88a, 0x00fcca}, /* U+9E0A [2000] */ - {0x00e9b88d, 0x00fccc}, /* U+9E0D [2000] */ - {0x00e9b895, 0x00efe7}, /* U+9E15 [2000] */ - {0x00e9b899, 0x00fccd}, /* U+9E19 [2000] */ - {0x00e9b89a, 0x00ea5f}, /* U+9E1A */ - {0x00e9b89b, 0x00ea60}, /* U+9E1B */ - {0x00e9b89c, 0x00fcce}, /* U+9E1C [2000] */ - {0x00e9b89d, 0x00fccf}, /* U+9E1D [2000] */ - {0x00e9b89e, 0x00ea61}, /* U+9E1E */ - {0x00e9b9b5, 0x00ea62}, /* U+9E75 */ - {0x00e9b9b8, 0x008cb2}, /* U+9E78 */ - {0x00e9b9b9, 0x00ea63}, /* U+9E79 */ - {0x00e9b9bb, 0x00fcd0}, /* U+9E7B [2000] */ - {0x00e9b9bc, 0x00efe8}, /* U+9E7C [2000] */ - {0x00e9b9bd, 0x00ea64}, /* U+9E7D */ - {0x00e9b9bf, 0x008ead}, /* U+9E7F */ - {0x00e9ba80, 0x00fcd2}, /* U+9E80 [2000] */ - {0x00e9ba81, 0x00ea65}, /* U+9E81 */ - {0x00e9ba85, 0x00fcd3}, /* U+9E85 [2000] */ - {0x00e9ba88, 0x00ea66}, /* U+9E88 */ - {0x00e9ba8b, 0x00ea67}, /* U+9E8B */ - {0x00e9ba8c, 0x00ea68}, /* U+9E8C */ - {0x00e9ba91, 0x00ea6b}, /* U+9E91 */ - {0x00e9ba92, 0x00ea69}, /* U+9E92 */ - {0x00e9ba93, 0x00985b}, /* U+9E93 */ - {0x00e9ba95, 0x00ea6a}, /* U+9E95 */ - {0x00e9ba97, 0x0097ed}, /* U+9E97 */ - {0x00e9ba9b, 0x00fcd4}, /* U+9E9B [2000] */ - {0x00e9ba9d, 0x00ea6c}, /* U+9E9D */ - {0x00e9ba9e, 0x00efe9}, /* U+9E9E [2000] */ - {0x00e9ba9f, 0x0097d9}, /* U+9E9F */ - {0x00e9baa4, 0x00efea}, /* U+9EA4 [2000] */ - {0x00e9baa5, 0x00ea6d}, /* U+9EA5 */ - {0x00e9baa6, 0x00949e}, /* U+9EA6 */ - {0x00e9baa8, 0x00fcd5}, /* U+9EA8 [2000] */ - {0x00e9baa9, 0x00ea6e}, /* U+9EA9 */ - {0x00e9baaa, 0x00ea70}, /* U+9EAA */ - {0x00e9baac, 0x00efeb}, /* U+9EAC [2000] */ - {0x00e9baad, 0x00ea71}, /* U+9EAD */ - {0x00e9baaf, 0x00efec}, /* U+9EAF [2000] */ - {0x00e9bab4, 0x00efed}, /* U+9EB4 [2000] */ - {0x00e9bab5, 0x00efee}, /* U+9EB5 [2000] */ - {0x00e9bab8, 0x00ea6f}, /* U+9EB8 */ - {0x00e9bab9, 0x008d8d}, /* U+9EB9 */ - {0x00e9baba, 0x0096cb}, /* U+9EBA */ - {0x00e9babb, 0x009683}, /* U+9EBB */ - {0x00e9babc, 0x009bf5}, /* U+9EBC */ - {0x00e9babd, 0x00fcd7}, /* U+9EBD [2000] */ - {0x00e9babe, 0x009f80}, /* U+9EBE */ - {0x00e9babf, 0x00969b}, /* U+9EBF */ - {0x00e9bb83, 0x00efef}, /* U+9EC3 [2000] */ - {0x00e9bb84, 0x0089a9}, /* U+9EC4 */ - {0x00e9bb8c, 0x00ea73}, /* U+9ECC */ - {0x00e9bb8d, 0x008b6f}, /* U+9ECD */ - {0x00e9bb8e, 0x00ea74}, /* U+9ECE */ - {0x00e9bb8f, 0x00ea75}, /* U+9ECF */ - {0x00e9bb90, 0x00ea76}, /* U+9ED0 */ - {0x00e9bb91, 0x00eff0}, /* U+9ED1 [2000] */ - {0x00e9bb92, 0x008d95}, /* U+9ED2 */ - {0x00e9bb94, 0x00ea77}, /* U+9ED4 */ - {0x00e9bb98, 0x00e0d2}, /* U+9ED8 */ - {0x00e9bb99, 0x0096d9}, /* U+9ED9 */ - {0x00e9bb9b, 0x0091e1}, /* U+9EDB */ - {0x00e9bb9c, 0x00ea78}, /* U+9EDC */ - {0x00e9bb9d, 0x00ea7a}, /* U+9EDD */ - {0x00e9bb9e, 0x00ea79}, /* U+9EDE */ - {0x00e9bb9f, 0x00fcd9}, /* U+9EDF [2000] */ - {0x00e9bba0, 0x00ea7b}, /* U+9EE0 */ - {0x00e9bba5, 0x00ea7c}, /* U+9EE5 */ - {0x00e9bba7, 0x00fcda}, /* U+9EE7 [2000] */ - {0x00e9bba8, 0x00ea7d}, /* U+9EE8 */ - {0x00e9bbae, 0x00fcdb}, /* U+9EEE [2000] */ - {0x00e9bbaf, 0x00ea7e}, /* U+9EEF */ - {0x00e9bbb4, 0x00ea80}, /* U+9EF4 */ - {0x00e9bbb6, 0x00ea81}, /* U+9EF6 */ - {0x00e9bbb7, 0x00ea82}, /* U+9EF7 */ - {0x00e9bbb9, 0x00ea83}, /* U+9EF9 */ - {0x00e9bbbb, 0x00ea84}, /* U+9EFB */ - {0x00e9bbbc, 0x00ea85}, /* U+9EFC */ - {0x00e9bbbd, 0x00ea86}, /* U+9EFD */ - {0x00e9bbbf, 0x00fcdc}, /* U+9EFF [2000] */ - {0x00e9bc82, 0x00fcdd}, /* U+9F02 [2000] */ - {0x00e9bc83, 0x00fcdf}, /* U+9F03 [2000] */ - {0x00e9bc87, 0x00ea87}, /* U+9F07 */ - {0x00e9bc88, 0x00ea88}, /* U+9F08 */ - {0x00e9bc8e, 0x009343}, /* U+9F0E */ - {0x00e9bc90, 0x00eff1}, /* U+9F10 [2000] */ - {0x00e9bc93, 0x008cdb}, /* U+9F13 */ - {0x00e9bc95, 0x00ea8a}, /* U+9F15 */ - {0x00e9bc97, 0x00fce0}, /* U+9F17 [2000] */ - {0x00e9bc99, 0x00fce1}, /* U+9F19 [2000] */ - {0x00e9bca0, 0x00916c}, /* U+9F20 */ - {0x00e9bca1, 0x00ea8b}, /* U+9F21 */ - {0x00e9bcac, 0x00ea8c}, /* U+9F2C */ - {0x00e9bcaf, 0x00fce2}, /* U+9F2F [2000] */ - {0x00e9bcb7, 0x00fce3}, /* U+9F37 [2000] */ - {0x00e9bcb9, 0x00eff2}, /* U+9F39 [2000] */ - {0x00e9bcba, 0x00fce4}, /* U+9F3A [2000] */ - {0x00e9bcbb, 0x009540}, /* U+9F3B */ - {0x00e9bcbd, 0x00fce5}, /* U+9F3D [2000] */ - {0x00e9bcbe, 0x00ea8d}, /* U+9F3E */ - {0x00e9bd81, 0x00fce6}, /* U+9F41 [2000] */ - {0x00e9bd85, 0x00fce7}, /* U+9F45 [2000] */ - {0x00e9bd86, 0x00fce8}, /* U+9F46 [2000] */ - {0x00e9bd8a, 0x00ea8e}, /* U+9F4A */ - {0x00e9bd8b, 0x00e256}, /* U+9F4B */ - {0x00e9bd8e, 0x00e6d8}, /* U+9F4E */ - {0x00e9bd8f, 0x00e8eb}, /* U+9F4F */ - {0x00e9bd92, 0x00ea8f}, /* U+9F52 */ - {0x00e9bd93, 0x00fce9}, /* U+9F53 [2000] */ - {0x00e9bd94, 0x00ea90}, /* U+9F54 */ - {0x00e9bd95, 0x00fcea}, /* U+9F55 [2000] */ - {0x00e9bd97, 0x00eff3}, /* U+9F57 [2000] */ - {0x00e9bd98, 0x00fceb}, /* U+9F58 [2000] */ - {0x00e9bd9d, 0x00fced}, /* U+9F5D [2000] */ - {0x00e9bd9f, 0x00ea92}, /* U+9F5F */ - {0x00e9bda0, 0x00ea93}, /* U+9F60 */ - {0x00e9bda1, 0x00ea94}, /* U+9F61 */ - {0x00e9bda2, 0x0097ee}, /* U+9F62 */ - {0x00e9bda3, 0x00ea91}, /* U+9F63 */ - {0x00e9bda6, 0x00ea95}, /* U+9F66 */ - {0x00e9bda7, 0x00ea96}, /* U+9F67 */ - {0x00e9bda9, 0x00fcef}, /* U+9F69 [2000] */ - {0x00e9bdaa, 0x00ea98}, /* U+9F6A */ - {0x00e9bdac, 0x00ea97}, /* U+9F6C */ - {0x00e9bdad, 0x00fcf1}, /* U+9F6D [2000] */ - {0x00e9bdb0, 0x00fcf2}, /* U+9F70 [2000] */ - {0x00e9bdb2, 0x00ea9a}, /* U+9F72 */ - {0x00e9bdb5, 0x00fcf3}, /* U+9F75 [2000] */ - {0x00e9bdb6, 0x00ea9b}, /* U+9F76 */ - {0x00e9bdb7, 0x00ea99}, /* U+9F77 */ - {0x00e9be8d, 0x0097b4}, /* U+9F8D */ - {0x00e9be90, 0x00eff4}, /* U+9F90 [2000] */ - {0x00e9be94, 0x00eff5}, /* U+9F94 [2000] */ - {0x00e9be95, 0x00ea9c}, /* U+9F95 */ - {0x00e9be97, 0x00eff6}, /* U+9F97 [2000] */ - {0x00e9be9c, 0x00ea9d}, /* U+9F9C */ - {0x00e9be9d, 0x00e273}, /* U+9F9D */ - {0x00e9bea0, 0x00ea9e}, /* U+9FA0 */ - {0x00e9bea2, 0x00eff7}, /* U+9FA2 [2000] */ - {0x00efa49d, 0x00ebb9}, /* U+F91D CJK COMPATIBILITY IDEOGRAPH-F91D [2000] */ - {0x00efa4a8, 0x00eaac}, /* U+F928 CJK COMPATIBILITY IDEOGRAPH-F928 [2000] */ - {0x00efa4a9, 0x00eb6d}, /* U+F929 CJK COMPATIBILITY IDEOGRAPH-F929 [2000] */ - {0x00efa4b6, 0x00ee6e}, /* U+F936 CJK COMPATIBILITY IDEOGRAPH-F936 [2000] */ - {0x00efa5b0, 0x00ebc7}, /* U+F970 CJK COMPATIBILITY IDEOGRAPH-F970 [2000] */ - {0x00efa790, 0x00efa2}, /* U+F9D0 CJK COMPATIBILITY IDEOGRAPH-F9D0 [2000] */ - {0x00efa79c, 0x00ef7c}, /* U+F9DC CJK COMPATIBILITY IDEOGRAPH-F9DC [2000] */ - {0x00efa88f, 0x00886a}, /* U+FA0F CJK COMPATIBILITY IDEOGRAPH-FA0F [2000] */ - {0x00efa890, 0x008876}, /* U+FA10 CJK COMPATIBILITY IDEOGRAPH-FA10 [2000] */ - {0x00efa891, 0x009892}, /* U+FA11 CJK COMPATIBILITY IDEOGRAPH-FA11 [2000] */ - {0x00efa893, 0x00f3f7}, /* U+FA13 CJK COMPATIBILITY IDEOGRAPH-FA13 [2000] */ - {0x00efa894, 0x00eb9a}, /* U+FA14 CJK COMPATIBILITY IDEOGRAPH-FA14 [2000] */ - {0x00efa895, 0x00ec79}, /* U+FA15 CJK COMPATIBILITY IDEOGRAPH-FA15 [2000] */ - {0x00efa896, 0x00ec8f}, /* U+FA16 CJK COMPATIBILITY IDEOGRAPH-FA16 [2000] */ - {0x00efa899, 0x00ed5b}, /* U+FA19 CJK COMPATIBILITY IDEOGRAPH-FA19 [2000] */ - {0x00efa89a, 0x00ed5c}, /* U+FA1A CJK COMPATIBILITY IDEOGRAPH-FA1A [2000] */ - {0x00efa89b, 0x00ed60}, /* U+FA1B CJK COMPATIBILITY IDEOGRAPH-FA1B [2000] */ - {0x00efa89f, 0x00ee59}, /* U+FA1F CJK COMPATIBILITY IDEOGRAPH-FA1F [2000] */ - {0x00efa8a0, 0x00f957}, /* U+FA20 CJK COMPATIBILITY IDEOGRAPH-FA20 [2000] */ - {0x00efa8a1, 0x00f964}, /* U+FA21 CJK COMPATIBILITY IDEOGRAPH-FA21 [2000] */ - {0x00efa8a2, 0x00eeac}, /* U+FA22 CJK COMPATIBILITY IDEOGRAPH-FA22 [2000] */ - {0x00efa8a4, 0x00fa8e}, /* U+FA24 CJK COMPATIBILITY IDEOGRAPH-FA24 [2000] */ - {0x00efa8a6, 0x00eee8}, /* U+FA26 CJK COMPATIBILITY IDEOGRAPH-FA26 [2000] */ - {0x00efa8b0, 0x0087b6}, /* U+FA30 CJK COMPATIBILITY IDEOGRAPH-FA30 [2000] [Unicode3.2] */ - {0x00efa8b1, 0x0087c7}, /* U+FA31 CJK COMPATIBILITY IDEOGRAPH-FA31 [2000] [Unicode3.2] */ - {0x00efa8b2, 0x0087ce}, /* U+FA32 CJK COMPATIBILITY IDEOGRAPH-FA32 [2000] [Unicode3.2] */ - {0x00efa8b3, 0x0087e1}, /* U+FA33 CJK COMPATIBILITY IDEOGRAPH-FA33 [2000] [Unicode3.2] */ - {0x00efa8b4, 0x0087e6}, /* U+FA34 CJK COMPATIBILITY IDEOGRAPH-FA34 [2000] [Unicode3.2] */ - {0x00efa8b5, 0x0087ec}, /* U+FA35 CJK COMPATIBILITY IDEOGRAPH-FA35 [2000] [Unicode3.2] */ - {0x00efa8b6, 0x00884b}, /* U+FA36 CJK COMPATIBILITY IDEOGRAPH-FA36 [2000] [Unicode3.2] */ - {0x00efa8b7, 0x00884e}, /* U+FA37 CJK COMPATIBILITY IDEOGRAPH-FA37 [2000] [Unicode3.2] */ - {0x00efa8b8, 0x008855}, /* U+FA38 CJK COMPATIBILITY IDEOGRAPH-FA38 [2000] [Unicode3.2] */ - {0x00efa8b9, 0x008879}, /* U+FA39 CJK COMPATIBILITY IDEOGRAPH-FA39 [2000] [Unicode3.2] */ - {0x00efa8ba, 0x00887d}, /* U+FA3A CJK COMPATIBILITY IDEOGRAPH-FA3A [2000] [Unicode3.2] */ - {0x00efa8bb, 0x009881}, /* U+FA3B CJK COMPATIBILITY IDEOGRAPH-FA3B [2000] [Unicode3.2] */ - {0x00efa8bc, 0x009882}, /* U+FA3C CJK COMPATIBILITY IDEOGRAPH-FA3C [2000] [Unicode3.2] */ - {0x00efa8bd, 0x00eace}, /* U+FA3D CJK COMPATIBILITY IDEOGRAPH-FA3D [2000] [Unicode3.2] */ - {0x00efa8be, 0x00eada}, /* U+FA3E CJK COMPATIBILITY IDEOGRAPH-FA3E [2000] [Unicode3.2] */ - {0x00efa8bf, 0x00eadc}, /* U+FA3F CJK COMPATIBILITY IDEOGRAPH-FA3F [2000] [Unicode3.2] */ - {0x00efa980, 0x00eadf}, /* U+FA40 CJK COMPATIBILITY IDEOGRAPH-FA40 [2000] [Unicode3.2] */ - {0x00efa981, 0x00eb47}, /* U+FA41 CJK COMPATIBILITY IDEOGRAPH-FA41 [2000] [Unicode3.2] */ - {0x00efa982, 0x00eb4a}, /* U+FA42 CJK COMPATIBILITY IDEOGRAPH-FA42 [2000] [Unicode3.2] */ - {0x00efa983, 0x00eb62}, /* U+FA43 CJK COMPATIBILITY IDEOGRAPH-FA43 [2000] [Unicode3.2] */ - {0x00efa984, 0x00eb85}, /* U+FA44 CJK COMPATIBILITY IDEOGRAPH-FA44 [2000] [Unicode3.2] */ - {0x00efa985, 0x00ebe7}, /* U+FA45 CJK COMPATIBILITY IDEOGRAPH-FA45 [2000] [Unicode3.2] */ - {0x00efa986, 0x00ebf5}, /* U+FA46 CJK COMPATIBILITY IDEOGRAPH-FA46 [2000] [Unicode3.2] */ - {0x00efa987, 0x00ec44}, /* U+FA47 CJK COMPATIBILITY IDEOGRAPH-FA47 [2000] [Unicode3.2] */ - {0x00efa988, 0x00ec74}, /* U+FA48 CJK COMPATIBILITY IDEOGRAPH-FA48 [2000] [Unicode3.2] */ - {0x00efa989, 0x00f5a7}, /* U+FA49 CJK COMPATIBILITY IDEOGRAPH-FA49 [2000] [Unicode3.2] */ - {0x00efa98a, 0x00eca3}, /* U+FA4A CJK COMPATIBILITY IDEOGRAPH-FA4A [2000] [Unicode3.2] */ - {0x00efa98b, 0x00ed46}, /* U+FA4B CJK COMPATIBILITY IDEOGRAPH-FA4B [2000] [Unicode3.2] */ - {0x00efa98c, 0x00ed52}, /* U+FA4C CJK COMPATIBILITY IDEOGRAPH-FA4C [2000] [Unicode3.2] */ - {0x00efa98d, 0x00ed53}, /* U+FA4D CJK COMPATIBILITY IDEOGRAPH-FA4D [2000] [Unicode3.2] */ - {0x00efa98e, 0x00ed56}, /* U+FA4E CJK COMPATIBILITY IDEOGRAPH-FA4E [2000] [Unicode3.2] */ - {0x00efa98f, 0x00ed57}, /* U+FA4F CJK COMPATIBILITY IDEOGRAPH-FA4F [2000] [Unicode3.2] */ - {0x00efa990, 0x00ed58}, /* U+FA50 CJK COMPATIBILITY IDEOGRAPH-FA50 [2000] [Unicode3.2] */ - {0x00efa991, 0x00ed5a}, /* U+FA51 CJK COMPATIBILITY IDEOGRAPH-FA51 [2000] [Unicode3.2] */ - {0x00efa992, 0x00ed5e}, /* U+FA52 CJK COMPATIBILITY IDEOGRAPH-FA52 [2000] [Unicode3.2] */ - {0x00efa993, 0x00ed5f}, /* U+FA53 CJK COMPATIBILITY IDEOGRAPH-FA53 [2000] [Unicode3.2] */ - {0x00efa994, 0x00ed6c}, /* U+FA54 CJK COMPATIBILITY IDEOGRAPH-FA54 [2000] [Unicode3.2] */ - {0x00efa995, 0x00ed70}, /* U+FA55 CJK COMPATIBILITY IDEOGRAPH-FA55 [2000] [Unicode3.2] */ - {0x00efa996, 0x00ed84}, /* U+FA56 CJK COMPATIBILITY IDEOGRAPH-FA56 [2000] [Unicode3.2] */ - {0x00efa997, 0x00edac}, /* U+FA57 CJK COMPATIBILITY IDEOGRAPH-FA57 [2000] [Unicode3.2] */ - {0x00efa998, 0x00f7ce}, /* U+FA58 CJK COMPATIBILITY IDEOGRAPH-FA58 [2000] [Unicode3.2] */ - {0x00efa999, 0x00edb1}, /* U+FA59 CJK COMPATIBILITY IDEOGRAPH-FA59 [2000] [Unicode3.2] */ - {0x00efa99a, 0x00edb8}, /* U+FA5A CJK COMPATIBILITY IDEOGRAPH-FA5A [2000] [Unicode3.2] */ - {0x00efa99b, 0x00edc2}, /* U+FA5B CJK COMPATIBILITY IDEOGRAPH-FA5B [2000] [Unicode3.2] */ - {0x00efa99c, 0x00edd6}, /* U+FA5C CJK COMPATIBILITY IDEOGRAPH-FA5C [2000] [Unicode3.2] */ - {0x00efa99d, 0x00f894}, /* U+FA5D CJK COMPATIBILITY IDEOGRAPH-FA5D [2000] [Unicode3.2] */ - {0x00efa99e, 0x00f895}, /* U+FA5E CJK COMPATIBILITY IDEOGRAPH-FA5E [2000] [Unicode3.2] */ - {0x00efa99f, 0x00ee46}, /* U+FA5F CJK COMPATIBILITY IDEOGRAPH-FA5F [2000] [Unicode3.2] */ - {0x00efa9a0, 0x00ee8f}, /* U+FA60 CJK COMPATIBILITY IDEOGRAPH-FA60 [2000] [Unicode3.2] */ - {0x00efa9a1, 0x00ee99}, /* U+FA61 CJK COMPATIBILITY IDEOGRAPH-FA61 [2000] [Unicode3.2] */ - {0x00efa9a2, 0x00eead}, /* U+FA62 CJK COMPATIBILITY IDEOGRAPH-FA62 [2000] [Unicode3.2] */ - {0x00efa9a3, 0x00eeae}, /* U+FA63 CJK COMPATIBILITY IDEOGRAPH-FA63 [2000] [Unicode3.2] */ - {0x00efa9a4, 0x00eeb6}, /* U+FA64 CJK COMPATIBILITY IDEOGRAPH-FA64 [2000] [Unicode3.2] */ - {0x00efa9a5, 0x00eebb}, /* U+FA65 CJK COMPATIBILITY IDEOGRAPH-FA65 [2000] [Unicode3.2] */ - {0x00efa9a6, 0x00fa89}, /* U+FA66 CJK COMPATIBILITY IDEOGRAPH-FA66 [2000] [Unicode3.2] */ - {0x00efa9a7, 0x00eed7}, /* U+FA67 CJK COMPATIBILITY IDEOGRAPH-FA67 [2000] [Unicode3.2] */ - {0x00efa9a8, 0x00ef83}, /* U+FA68 CJK COMPATIBILITY IDEOGRAPH-FA68 [2000] [Unicode3.2] */ - {0x00efa9a9, 0x00ef96}, /* U+FA69 CJK COMPATIBILITY IDEOGRAPH-FA69 [2000] [Unicode3.2] */ - {0x00efa9aa, 0x00ef9b}, /* U+FA6A CJK COMPATIBILITY IDEOGRAPH-FA6A [2000] [Unicode3.2] */ - {0x00efb985, 0x00825d}, /* U+FE45 SESAME DOT [2000] [Unicode3.2] */ - {0x00efb986, 0x00825c}, /* U+FE46 WHITE SESAME DOT [2000] [Unicode3.2] */ - {0x00efbc81, 0x008149}, /* U+FF01 FULLWIDTH EXCLAMATION MARK */ - {0x00efbc82, 0x0081ae}, /* U+FF02 FULLWIDTH QUOTATION MARK [2000] */ - {0x00efbc83, 0x008194}, /* U+FF03 FULLWIDTH NUMBER SIGN */ - {0x00efbc84, 0x008190}, /* U+FF04 FULLWIDTH DOLLAR SIGN */ - {0x00efbc85, 0x008193}, /* U+FF05 FULLWIDTH PERCENT SIGN */ - {0x00efbc86, 0x008195}, /* U+FF06 FULLWIDTH AMPERSAND */ - {0x00efbc87, 0x0081ad}, /* U+FF07 FULLWIDTH APOSTROPHE [2000] */ - {0x00efbc88, 0x008169}, /* U+FF08 FULLWIDTH LEFT PARENTHESIS */ - {0x00efbc89, 0x00816a}, /* U+FF09 FULLWIDTH RIGHT PARENTHESIS */ - {0x00efbc8a, 0x008196}, /* U+FF0A FULLWIDTH ASTERISK */ - {0x00efbc8b, 0x00817b}, /* U+FF0B FULLWIDTH PLUS SIGN */ - {0x00efbc8c, 0x008143}, /* U+FF0C FULLWIDTH COMMA */ - {0x00efbc8d, 0x0081af}, /* U+FF0D FULLWIDTH HYPHEN-MINUS [2000] */ - {0x00efbc8e, 0x008144}, /* U+FF0E FULLWIDTH FULL STOP */ - {0x00efbc8f, 0x00815e}, /* U+FF0F FULLWIDTH SOLIDUS */ - {0x00efbc90, 0x00824f}, /* U+FF10 FULLWIDTH DIGIT ZERO */ - {0x00efbc91, 0x008250}, /* U+FF11 FULLWIDTH DIGIT ONE */ - {0x00efbc92, 0x008251}, /* U+FF12 FULLWIDTH DIGIT TWO */ - {0x00efbc93, 0x008252}, /* U+FF13 FULLWIDTH DIGIT THREE */ - {0x00efbc94, 0x008253}, /* U+FF14 FULLWIDTH DIGIT FOUR */ - {0x00efbc95, 0x008254}, /* U+FF15 FULLWIDTH DIGIT FIVE */ - {0x00efbc96, 0x008255}, /* U+FF16 FULLWIDTH DIGIT SIX */ - {0x00efbc97, 0x008256}, /* U+FF17 FULLWIDTH DIGIT SEVEN */ - {0x00efbc98, 0x008257}, /* U+FF18 FULLWIDTH DIGIT EIGHT */ - {0x00efbc99, 0x008258}, /* U+FF19 FULLWIDTH DIGIT NINE */ - {0x00efbc9a, 0x008146}, /* U+FF1A FULLWIDTH COLON */ - {0x00efbc9b, 0x008147}, /* U+FF1B FULLWIDTH SEMICOLON */ - {0x00efbc9c, 0x008183}, /* U+FF1C FULLWIDTH LESS-THAN SIGN */ - {0x00efbc9d, 0x008181}, /* U+FF1D FULLWIDTH EQUALS SIGN */ - {0x00efbc9e, 0x008184}, /* U+FF1E FULLWIDTH GREATER-THAN SIGN */ - {0x00efbc9f, 0x008148}, /* U+FF1F FULLWIDTH QUESTION MARK */ - {0x00efbca0, 0x008197}, /* U+FF20 FULLWIDTH COMMERCIAL AT */ - {0x00efbca1, 0x008260}, /* U+FF21 FULLWIDTH LATIN CAPITAL LETTER A */ - {0x00efbca2, 0x008261}, /* U+FF22 FULLWIDTH LATIN CAPITAL LETTER B */ - {0x00efbca3, 0x008262}, /* U+FF23 FULLWIDTH LATIN CAPITAL LETTER C */ - {0x00efbca4, 0x008263}, /* U+FF24 FULLWIDTH LATIN CAPITAL LETTER D */ - {0x00efbca5, 0x008264}, /* U+FF25 FULLWIDTH LATIN CAPITAL LETTER E */ - {0x00efbca6, 0x008265}, /* U+FF26 FULLWIDTH LATIN CAPITAL LETTER F */ - {0x00efbca7, 0x008266}, /* U+FF27 FULLWIDTH LATIN CAPITAL LETTER G */ - {0x00efbca8, 0x008267}, /* U+FF28 FULLWIDTH LATIN CAPITAL LETTER H */ - {0x00efbca9, 0x008268}, /* U+FF29 FULLWIDTH LATIN CAPITAL LETTER I */ - {0x00efbcaa, 0x008269}, /* U+FF2A FULLWIDTH LATIN CAPITAL LETTER J */ - {0x00efbcab, 0x00826a}, /* U+FF2B FULLWIDTH LATIN CAPITAL LETTER K */ - {0x00efbcac, 0x00826b}, /* U+FF2C FULLWIDTH LATIN CAPITAL LETTER L */ - {0x00efbcad, 0x00826c}, /* U+FF2D FULLWIDTH LATIN CAPITAL LETTER M */ - {0x00efbcae, 0x00826d}, /* U+FF2E FULLWIDTH LATIN CAPITAL LETTER N */ - {0x00efbcaf, 0x00826e}, /* U+FF2F FULLWIDTH LATIN CAPITAL LETTER O */ - {0x00efbcb0, 0x00826f}, /* U+FF30 FULLWIDTH LATIN CAPITAL LETTER P */ - {0x00efbcb1, 0x008270}, /* U+FF31 FULLWIDTH LATIN CAPITAL LETTER Q */ - {0x00efbcb2, 0x008271}, /* U+FF32 FULLWIDTH LATIN CAPITAL LETTER R */ - {0x00efbcb3, 0x008272}, /* U+FF33 FULLWIDTH LATIN CAPITAL LETTER S */ - {0x00efbcb4, 0x008273}, /* U+FF34 FULLWIDTH LATIN CAPITAL LETTER T */ - {0x00efbcb5, 0x008274}, /* U+FF35 FULLWIDTH LATIN CAPITAL LETTER U */ - {0x00efbcb6, 0x008275}, /* U+FF36 FULLWIDTH LATIN CAPITAL LETTER V */ - {0x00efbcb7, 0x008276}, /* U+FF37 FULLWIDTH LATIN CAPITAL LETTER W */ - {0x00efbcb8, 0x008277}, /* U+FF38 FULLWIDTH LATIN CAPITAL LETTER X */ - {0x00efbcb9, 0x008278}, /* U+FF39 FULLWIDTH LATIN CAPITAL LETTER Y */ - {0x00efbcba, 0x008279}, /* U+FF3A FULLWIDTH LATIN CAPITAL LETTER Z */ - {0x00efbcbb, 0x00816d}, /* U+FF3B FULLWIDTH LEFT SQUARE BRACKET */ - {0x00efbcbd, 0x00816e}, /* U+FF3D FULLWIDTH RIGHT SQUARE BRACKET */ - {0x00efbcbe, 0x00814f}, /* U+FF3E FULLWIDTH CIRCUMFLEX ACCENT */ - {0x00efbcbf, 0x008151}, /* U+FF3F FULLWIDTH LOW LINE */ - {0x00efbd80, 0x00814d}, /* U+FF40 FULLWIDTH GRAVE ACCENT */ - {0x00efbd81, 0x008281}, /* U+FF41 FULLWIDTH LATIN SMALL LETTER A */ - {0x00efbd82, 0x008282}, /* U+FF42 FULLWIDTH LATIN SMALL LETTER B */ - {0x00efbd83, 0x008283}, /* U+FF43 FULLWIDTH LATIN SMALL LETTER C */ - {0x00efbd84, 0x008284}, /* U+FF44 FULLWIDTH LATIN SMALL LETTER D */ - {0x00efbd85, 0x008285}, /* U+FF45 FULLWIDTH LATIN SMALL LETTER E */ - {0x00efbd86, 0x008286}, /* U+FF46 FULLWIDTH LATIN SMALL LETTER F */ - {0x00efbd87, 0x008287}, /* U+FF47 FULLWIDTH LATIN SMALL LETTER G */ - {0x00efbd88, 0x008288}, /* U+FF48 FULLWIDTH LATIN SMALL LETTER H */ - {0x00efbd89, 0x008289}, /* U+FF49 FULLWIDTH LATIN SMALL LETTER I */ - {0x00efbd8a, 0x00828a}, /* U+FF4A FULLWIDTH LATIN SMALL LETTER J */ - {0x00efbd8b, 0x00828b}, /* U+FF4B FULLWIDTH LATIN SMALL LETTER K */ - {0x00efbd8c, 0x00828c}, /* U+FF4C FULLWIDTH LATIN SMALL LETTER L */ - {0x00efbd8d, 0x00828d}, /* U+FF4D FULLWIDTH LATIN SMALL LETTER M */ - {0x00efbd8e, 0x00828e}, /* U+FF4E FULLWIDTH LATIN SMALL LETTER N */ - {0x00efbd8f, 0x00828f}, /* U+FF4F FULLWIDTH LATIN SMALL LETTER O */ - {0x00efbd90, 0x008290}, /* U+FF50 FULLWIDTH LATIN SMALL LETTER P */ - {0x00efbd91, 0x008291}, /* U+FF51 FULLWIDTH LATIN SMALL LETTER Q */ - {0x00efbd92, 0x008292}, /* U+FF52 FULLWIDTH LATIN SMALL LETTER R */ - {0x00efbd93, 0x008293}, /* U+FF53 FULLWIDTH LATIN SMALL LETTER S */ - {0x00efbd94, 0x008294}, /* U+FF54 FULLWIDTH LATIN SMALL LETTER T */ - {0x00efbd95, 0x008295}, /* U+FF55 FULLWIDTH LATIN SMALL LETTER U */ - {0x00efbd96, 0x008296}, /* U+FF56 FULLWIDTH LATIN SMALL LETTER V */ - {0x00efbd97, 0x008297}, /* U+FF57 FULLWIDTH LATIN SMALL LETTER W */ - {0x00efbd98, 0x008298}, /* U+FF58 FULLWIDTH LATIN SMALL LETTER X */ - {0x00efbd99, 0x008299}, /* U+FF59 FULLWIDTH LATIN SMALL LETTER Y */ - {0x00efbd9a, 0x00829a}, /* U+FF5A FULLWIDTH LATIN SMALL LETTER Z */ - {0x00efbd9b, 0x00816f}, /* U+FF5B FULLWIDTH LEFT CURLY BRACKET */ - {0x00efbd9c, 0x008162}, /* U+FF5C FULLWIDTH VERTICAL LINE */ - {0x00efbd9d, 0x008170}, /* U+FF5D FULLWIDTH RIGHT CURLY BRACKET */ - {0x00efbd9f, 0x0081d4}, /* U+FF5F FULLWIDTH LEFT WHITE PARENTHESIS [2000] [Unicode3.2] */ - {0x00efbda0, 0x0081d5}, /* U+FF60 FULLWIDTH RIGHT WHITE PARENTHESIS [2000] [Unicode3.2] */ - {0x00efbda1, 0x0000a1}, /* U+FF61 HALFWIDTH IDEOGRAPHIC FULL STOP */ - {0x00efbda2, 0x0000a2}, /* U+FF62 HALFWIDTH LEFT CORNER BRACKET */ - {0x00efbda3, 0x0000a3}, /* U+FF63 HALFWIDTH RIGHT CORNER BRACKET */ - {0x00efbda4, 0x0000a4}, /* U+FF64 HALFWIDTH IDEOGRAPHIC COMMA */ - {0x00efbda5, 0x0000a5}, /* U+FF65 HALFWIDTH KATAKANA MIDDLE DOT */ - {0x00efbda6, 0x0000a6}, /* U+FF66 HALFWIDTH KATAKANA LETTER WO */ - {0x00efbda7, 0x0000a7}, /* U+FF67 HALFWIDTH KATAKANA LETTER SMALL A */ - {0x00efbda8, 0x0000a8}, /* U+FF68 HALFWIDTH KATAKANA LETTER SMALL I */ - {0x00efbda9, 0x0000a9}, /* U+FF69 HALFWIDTH KATAKANA LETTER SMALL U */ - {0x00efbdaa, 0x0000aa}, /* U+FF6A HALFWIDTH KATAKANA LETTER SMALL E */ - {0x00efbdab, 0x0000ab}, /* U+FF6B HALFWIDTH KATAKANA LETTER SMALL O */ - {0x00efbdac, 0x0000ac}, /* U+FF6C HALFWIDTH KATAKANA LETTER SMALL YA */ - {0x00efbdad, 0x0000ad}, /* U+FF6D HALFWIDTH KATAKANA LETTER SMALL YU */ - {0x00efbdae, 0x0000ae}, /* U+FF6E HALFWIDTH KATAKANA LETTER SMALL YO */ - {0x00efbdaf, 0x0000af}, /* U+FF6F HALFWIDTH KATAKANA LETTER SMALL TU */ - {0x00efbdb0, 0x0000b0}, /* U+FF70 HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK */ - {0x00efbdb1, 0x0000b1}, /* U+FF71 HALFWIDTH KATAKANA LETTER A */ - {0x00efbdb2, 0x0000b2}, /* U+FF72 HALFWIDTH KATAKANA LETTER I */ - {0x00efbdb3, 0x0000b3}, /* U+FF73 HALFWIDTH KATAKANA LETTER U */ - {0x00efbdb4, 0x0000b4}, /* U+FF74 HALFWIDTH KATAKANA LETTER E */ - {0x00efbdb5, 0x0000b5}, /* U+FF75 HALFWIDTH KATAKANA LETTER O */ - {0x00efbdb6, 0x0000b6}, /* U+FF76 HALFWIDTH KATAKANA LETTER KA */ - {0x00efbdb7, 0x0000b7}, /* U+FF77 HALFWIDTH KATAKANA LETTER KI */ - {0x00efbdb8, 0x0000b8}, /* U+FF78 HALFWIDTH KATAKANA LETTER KU */ - {0x00efbdb9, 0x0000b9}, /* U+FF79 HALFWIDTH KATAKANA LETTER KE */ - {0x00efbdba, 0x0000ba}, /* U+FF7A HALFWIDTH KATAKANA LETTER KO */ - {0x00efbdbb, 0x0000bb}, /* U+FF7B HALFWIDTH KATAKANA LETTER SA */ - {0x00efbdbc, 0x0000bc}, /* U+FF7C HALFWIDTH KATAKANA LETTER SI */ - {0x00efbdbd, 0x0000bd}, /* U+FF7D HALFWIDTH KATAKANA LETTER SU */ - {0x00efbdbe, 0x0000be}, /* U+FF7E HALFWIDTH KATAKANA LETTER SE */ - {0x00efbdbf, 0x0000bf}, /* U+FF7F HALFWIDTH KATAKANA LETTER SO */ - {0x00efbe80, 0x0000c0}, /* U+FF80 HALFWIDTH KATAKANA LETTER TA */ - {0x00efbe81, 0x0000c1}, /* U+FF81 HALFWIDTH KATAKANA LETTER TI */ - {0x00efbe82, 0x0000c2}, /* U+FF82 HALFWIDTH KATAKANA LETTER TU */ - {0x00efbe83, 0x0000c3}, /* U+FF83 HALFWIDTH KATAKANA LETTER TE */ - {0x00efbe84, 0x0000c4}, /* U+FF84 HALFWIDTH KATAKANA LETTER TO */ - {0x00efbe85, 0x0000c5}, /* U+FF85 HALFWIDTH KATAKANA LETTER NA */ - {0x00efbe86, 0x0000c6}, /* U+FF86 HALFWIDTH KATAKANA LETTER NI */ - {0x00efbe87, 0x0000c7}, /* U+FF87 HALFWIDTH KATAKANA LETTER NU */ - {0x00efbe88, 0x0000c8}, /* U+FF88 HALFWIDTH KATAKANA LETTER NE */ - {0x00efbe89, 0x0000c9}, /* U+FF89 HALFWIDTH KATAKANA LETTER NO */ - {0x00efbe8a, 0x0000ca}, /* U+FF8A HALFWIDTH KATAKANA LETTER HA */ - {0x00efbe8b, 0x0000cb}, /* U+FF8B HALFWIDTH KATAKANA LETTER HI */ - {0x00efbe8c, 0x0000cc}, /* U+FF8C HALFWIDTH KATAKANA LETTER HU */ - {0x00efbe8d, 0x0000cd}, /* U+FF8D HALFWIDTH KATAKANA LETTER HE */ - {0x00efbe8e, 0x0000ce}, /* U+FF8E HALFWIDTH KATAKANA LETTER HO */ - {0x00efbe8f, 0x0000cf}, /* U+FF8F HALFWIDTH KATAKANA LETTER MA */ - {0x00efbe90, 0x0000d0}, /* U+FF90 HALFWIDTH KATAKANA LETTER MI */ - {0x00efbe91, 0x0000d1}, /* U+FF91 HALFWIDTH KATAKANA LETTER MU */ - {0x00efbe92, 0x0000d2}, /* U+FF92 HALFWIDTH KATAKANA LETTER ME */ - {0x00efbe93, 0x0000d3}, /* U+FF93 HALFWIDTH KATAKANA LETTER MO */ - {0x00efbe94, 0x0000d4}, /* U+FF94 HALFWIDTH KATAKANA LETTER YA */ - {0x00efbe95, 0x0000d5}, /* U+FF95 HALFWIDTH KATAKANA LETTER YU */ - {0x00efbe96, 0x0000d6}, /* U+FF96 HALFWIDTH KATAKANA LETTER YO */ - {0x00efbe97, 0x0000d7}, /* U+FF97 HALFWIDTH KATAKANA LETTER RA */ - {0x00efbe98, 0x0000d8}, /* U+FF98 HALFWIDTH KATAKANA LETTER RI */ - {0x00efbe99, 0x0000d9}, /* U+FF99 HALFWIDTH KATAKANA LETTER RU */ - {0x00efbe9a, 0x0000da}, /* U+FF9A HALFWIDTH KATAKANA LETTER RE */ - {0x00efbe9b, 0x0000db}, /* U+FF9B HALFWIDTH KATAKANA LETTER RO */ - {0x00efbe9c, 0x0000dc}, /* U+FF9C HALFWIDTH KATAKANA LETTER WA */ - {0x00efbe9d, 0x0000dd}, /* U+FF9D HALFWIDTH KATAKANA LETTER N */ - {0x00efbe9e, 0x0000de}, /* U+FF9E HALFWIDTH KATAKANA VOICED SOUND MARK */ - {0x00efbe9f, 0x0000df}, /* U+FF9F HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK */ - {0x00efbfa3, 0x008150}, /* U+FFE3 FULLWIDTH MACRON */ - {0x00efbfa5, 0x00818f}, /* U+FFE5 FULLWIDTH YEN SIGN */ - {0xf0a0808b, 0x0087a0}, /* U+2000B [2000] [Unicode3.1] */ - {0xf0a08289, 0x00f040}, /* U+20089 [2000] [Unicode3.1] */ - {0xf0a082a2, 0x00f04a}, /* U+200A2 [2000] [Unicode3.1] */ - {0xf0a082a4, 0x00f04d}, /* U+200A4 [2000] [Unicode3.1] */ - {0xf0a086a2, 0x00f055}, /* U+201A2 [2000] [Unicode3.1] */ - {0xf0a08893, 0x00f065}, /* U+20213 [2000] [Unicode3.1] */ - {0xf0a08cab, 0x00f090}, /* U+2032B [2000] [Unicode3.1] */ - {0xf0a08db1, 0x00f099}, /* U+20371 [2000] [Unicode3.1] */ - {0xf0a08e81, 0x00f097}, /* U+20381 [2000] [Unicode3.1] */ - {0xf0a08fb9, 0x00f141}, /* U+203F9 [2000] [Unicode3.1] */ - {0xf0a0918a, 0x00f144}, /* U+2044A [2000] [Unicode3.1] */ - {0xf0a09489, 0x00f146}, /* U+20509 [2000] [Unicode3.1] */ - {0xf0a09796, 0x00f150}, /* U+205D6 [2000] [Unicode3.1] */ - {0xf0a098a8, 0x00f151}, /* U+20628 [2000] [Unicode3.1] */ - {0xf0a09d8f, 0x00f157}, /* U+2074F [2000] [Unicode3.1] */ - {0xf0a0a087, 0x00f15e}, /* U+20807 [2000] [Unicode3.1] */ - {0xf0a0a0ba, 0x00f160}, /* U+2083A [2000] [Unicode3.1] */ - {0xf0a0a2b9, 0x00f169}, /* U+208B9 [2000] [Unicode3.1] */ - {0xf0a0a5bc, 0x00f171}, /* U+2097C [2000] [Unicode3.1] */ - {0xf0a0a69d, 0x00f172}, /* U+2099D [2000] [Unicode3.1] */ - {0xf0a0ab93, 0x00f178}, /* U+20AD3 [2000] [Unicode3.1] */ - {0xf0a0ac9d, 0x00f17b}, /* U+20B1D [2000] [Unicode3.1] */ - {0xf0a0ae9f, 0x009873}, /* U+20B9F [2004] [Unicode3.1] */ - {0xf0a0b585, 0x00f197}, /* U+20D45 [2000] [Unicode3.1] */ - {0xf0a0b7a1, 0x00f1a8}, /* U+20DE1 [2000] [Unicode3.1] */ - {0xf0a0b9a4, 0x00f1b8}, /* U+20E64 [2000] [Unicode3.1] */ - {0xf0a0b9ad, 0x00f1b0}, /* U+20E6D [2000] [Unicode3.1] */ - {0xf0a0ba95, 0x00f1af}, /* U+20E95 [2000] [Unicode3.1] */ - {0xf0a0bd9f, 0x00f1bb}, /* U+20F5F [2000] [Unicode3.1] */ - {0xf0a18881, 0x00f1d7}, /* U+21201 [2000] [Unicode3.1] */ - {0xf0a188bd, 0x008861}, /* U+2123D [2000] [Unicode3.1] */ - {0xf0a18995, 0x00f1da}, /* U+21255 [2000] [Unicode3.1] */ - {0xf0a189b4, 0x00f1e1}, /* U+21274 [2000] [Unicode3.1] */ - {0xf0a189bb, 0x00f1dc}, /* U+2127B [2000] [Unicode3.1] */ - {0xf0a18b97, 0x00f1e9}, /* U+212D7 [2000] [Unicode3.1] */ - {0xf0a18ba4, 0x00f1e8}, /* U+212E4 [2000] [Unicode3.1] */ - {0xf0a18bbd, 0x00f1f0}, /* U+212FD [2000] [Unicode3.1] */ - {0xf0a18c9b, 0x00886b}, /* U+2131B [2000] [Unicode3.1] */ - {0xf0a18cb6, 0x00f1f2}, /* U+21336 [2000] [Unicode3.1] */ - {0xf0a18d84, 0x00f1f3}, /* U+21344 [2000] [Unicode3.1] */ - {0xf0a18f84, 0x00f244}, /* U+213C4 [2000] [Unicode3.1] */ - {0xf0a191ad, 0x00f251}, /* U+2146D [2000] [Unicode3.1] */ - {0xf0a191ae, 0x008880}, /* U+2146E [2000] [Unicode3.1] */ - {0xf0a19797, 0x00f25d}, /* U+215D7 [2000] [Unicode3.1] */ - {0xf0a19987, 0x00f266}, /* U+21647 [2000] [Unicode3.1] */ - {0xf0a19ab4, 0x009883}, /* U+216B4 [2000] [Unicode3.1] */ - {0xf0a19c86, 0x00f274}, /* U+21706 [2000] [Unicode3.1] */ - {0xf0a19d82, 0x00f275}, /* U+21742 [2000] [Unicode3.1] */ - {0xf0a1a2bd, 0x00889b}, /* U+218BD [2000] [Unicode3.1] */ - {0xf0a1a783, 0x00f29e}, /* U+219C3 [2000] [Unicode3.1] */ - {0xf0a1b196, 0x00f0ae}, /* U+21C56 [2000] [Unicode3.1] */ - {0xf0a1b4ad, 0x00f0b5}, /* U+21D2D [2000] [Unicode3.1] */ - {0xf0a1b585, 0x00f0b6}, /* U+21D45 [2000] [Unicode3.1] */ - {0xf0a1b5a2, 0x00f0b9}, /* U+21D62 [2000] [Unicode3.1] */ - {0xf0a1b5b8, 0x00f0b8}, /* U+21D78 [2000] [Unicode3.1] */ - {0xf0a1b692, 0x00f0c3}, /* U+21D92 [2000] [Unicode3.1] */ - {0xf0a1b69c, 0x00f0be}, /* U+21D9C [2000] [Unicode3.1] */ - {0xf0a1b6a1, 0x00f0bd}, /* U+21DA1 [2000] [Unicode3.1] */ - {0xf0a1b6b7, 0x00f0c6}, /* U+21DB7 [2000] [Unicode3.1] */ - {0xf0a1b7a0, 0x00f0c8}, /* U+21DE0 [2000] [Unicode3.1] */ - {0xf0a1b8b3, 0x00f0c9}, /* U+21E33 [2000] [Unicode3.1] */ - {0xf0a1b8b4, 0x00988e}, /* U+21E34 [2000] [Unicode3.1] */ - {0xf0a1bc9e, 0x00f0d9}, /* U+21F1E [2000] [Unicode3.1] */ - {0xf0a1bdb6, 0x00f0e4}, /* U+21F76 [2000] [Unicode3.1] */ - {0xf0a1bfba, 0x00f0ea}, /* U+21FFA [2000] [Unicode3.1] */ - {0xf0a285bb, 0x00f2a0}, /* U+2217B [2000] [Unicode3.1] */ - {0xf0a28898, 0x00fcd1}, /* U+22218 [2000] [Unicode3.1] */ - {0xf0a28c9e, 0x00f2a9}, /* U+2231E [2000] [Unicode3.1] */ - {0xf0a28ead, 0x00f2ae}, /* U+223AD [2000] [Unicode3.1] */ - {0xf0a29bb3, 0x00f2ce}, /* U+226F3 [2000] [Unicode3.1] */ - {0xf0a2a19b, 0x00f2e3}, /* U+2285B [2000] [Unicode3.1] */ - {0xf0a2a2ab, 0x00f2eb}, /* U+228AB [2000] [Unicode3.1] */ - {0xf0a2a68f, 0x00f2f0}, /* U+2298F [2000] [Unicode3.1] */ - {0xf0a2aab8, 0x00f343}, /* U+22AB8 [2000] [Unicode3.1] */ - {0xf0a2ad86, 0x00f351}, /* U+22B46 [2000] [Unicode3.1] */ - {0xf0a2ad8f, 0x00f348}, /* U+22B4F [2000] [Unicode3.1] */ - {0xf0a2ad90, 0x00f349}, /* U+22B50 [2000] [Unicode3.1] */ - {0xf0a2aea6, 0x00f354}, /* U+22BA6 [2000] [Unicode3.1] */ - {0xf0a2b09d, 0x00f353}, /* U+22C1D [2000] [Unicode3.1] */ - {0xf0a2b0a4, 0x00f358}, /* U+22C24 [2000] [Unicode3.1] */ - {0xf0a2b7a1, 0x00f375}, /* U+22DE1 [2000] [Unicode3.1] */ - {0xf0a386b6, 0x00f3a2}, /* U+231B6 [2000] [Unicode3.1] */ - {0xf0a38783, 0x00f39d}, /* U+231C3 [2000] [Unicode3.1] */ - {0xf0a38784, 0x00eb59}, /* U+231C4 [2000] [Unicode3.1] */ - {0xf0a387b5, 0x00f3a1}, /* U+231F5 [2000] [Unicode3.1] */ - {0xf0a38db2, 0x00f3b8}, /* U+23372 [2000] [Unicode3.1] */ - {0xf0a38f90, 0x00f3c0}, /* U+233D0 [2000] [Unicode3.1] */ - {0xf0a38f92, 0x00f3bb}, /* U+233D2 [2000] [Unicode3.1] */ - {0xf0a38f93, 0x00f3ba}, /* U+233D3 [2000] [Unicode3.1] */ - {0xf0a38f95, 0x00f3c2}, /* U+233D5 [2000] [Unicode3.1] */ - {0xf0a38f9a, 0x00f3c5}, /* U+233DA [2000] [Unicode3.1] */ - {0xf0a38f9f, 0x00f3c7}, /* U+233DF [2000] [Unicode3.1] */ - {0xf0a38fa4, 0x00f3c1}, /* U+233E4 [2000] [Unicode3.1] */ - {0xf0a3918a, 0x00f3d3}, /* U+2344A [2000] [Unicode3.1] */ - {0xf0a3918b, 0x00f3d5}, /* U+2344B [2000] [Unicode3.1] */ - {0xf0a39191, 0x00f3d4}, /* U+23451 [2000] [Unicode3.1] */ - {0xf0a391a5, 0x00f3d9}, /* U+23465 [2000] [Unicode3.1] */ - {0xf0a393a4, 0x00f3f5}, /* U+234E4 [2000] [Unicode3.1] */ - {0xf0a3959a, 0x00f3f6}, /* U+2355A [2000] [Unicode3.1] */ - {0xf0a39694, 0x00f449}, /* U+23594 [2000] [Unicode3.1] */ - {0xf0a39784, 0x00eb92}, /* U+235C4 [2000] [Unicode3.1] */ - {0xf0a398b8, 0x00f461}, /* U+23638 [2000] [Unicode3.1] */ - {0xf0a398b9, 0x00f45e}, /* U+23639 [2000] [Unicode3.1] */ - {0xf0a398ba, 0x00f462}, /* U+2363A [2000] [Unicode3.1] */ - {0xf0a39987, 0x00f45f}, /* U+23647 [2000] [Unicode3.1] */ - {0xf0a39c8c, 0x00f478}, /* U+2370C [2000] [Unicode3.1] */ - {0xf0a39c9c, 0x00f46d}, /* U+2371C [2000] [Unicode3.1] */ - {0xf0a39cbf, 0x00eba7}, /* U+2373F [2000] [Unicode3.1] */ - {0xf0a39da3, 0x00ebb0}, /* U+23763 [2000] [Unicode3.1] */ - {0xf0a39da4, 0x00f481}, /* U+23764 [2000] [Unicode3.1] */ - {0xf0a39fa7, 0x00f48a}, /* U+237E7 [2000] [Unicode3.1] */ - {0xf0a39fbf, 0x00f489}, /* U+237FF [2000] [Unicode3.1] */ - {0xf0a3a0a4, 0x00f490}, /* U+23824 [2000] [Unicode3.1] */ - {0xf0a3a0bd, 0x00f495}, /* U+2383D [2000] [Unicode3.1] */ - {0xf0a3aa98, 0x00f4a1}, /* U+23A98 [2000] [Unicode3.1] */ - {0xf0a3b1bf, 0x00f4b2}, /* U+23C7F [2000] [Unicode3.1] */ - {0xf0a3b3be, 0x00ebde}, /* U+23CFE [2000] [Unicode3.1] */ - {0xf0a3b480, 0x00f4c7}, /* U+23D00 [2000] [Unicode3.1] */ - {0xf0a3b48e, 0x00f7f3}, /* U+23D0E [2000] [Unicode3.1] */ - {0xf0a3b580, 0x00f4da}, /* U+23D40 [2000] [Unicode3.1] */ - {0xf0a3b793, 0x00f4de}, /* U+23DD3 [2000] [Unicode3.1] */ - {0xf0a3b7b9, 0x00f4dd}, /* U+23DF9 [2000] [Unicode3.1] */ - {0xf0a3b7ba, 0x00f4dc}, /* U+23DFA [2000] [Unicode3.1] */ - {0xf0a3bdbe, 0x00f551}, /* U+23F7E [2000] [Unicode3.1] */ - {0xf0a48296, 0x00f566}, /* U+24096 [2000] [Unicode3.1] */ - {0xf0a48483, 0x00f56c}, /* U+24103 [2000] [Unicode3.1] */ - {0xf0a48786, 0x00f581}, /* U+241C6 [2000] [Unicode3.1] */ - {0xf0a487be, 0x00f584}, /* U+241FE [2000] [Unicode3.1] */ - {0xf0a48ebc, 0x00f5a0}, /* U+243BC [2000] [Unicode3.1] */ - {0xf0a498a9, 0x00f5b1}, /* U+24629 [2000] [Unicode3.1] */ - {0xf0a49aa5, 0x00f5b7}, /* U+246A5 [2000] [Unicode3.1] */ - {0xf0a49fb1, 0x00ec8c}, /* U+247F1 [2000] [Unicode3.1] */ - {0xf0a4a296, 0x00f5d1}, /* U+24896 [2000] [Unicode3.1] */ - {0xf0a4a98d, 0x00f5f9}, /* U+24A4D [2000] [Unicode3.1] */ - {0xf0a4ad96, 0x00f64d}, /* U+24B56 [2000] [Unicode3.1] */ - {0xf0a4adaf, 0x00f64f}, /* U+24B6F [2000] [Unicode3.1] */ - {0xf0a4b096, 0x00f654}, /* U+24C16 [2000] [Unicode3.1] */ - {0xf0a4b494, 0x00f663}, /* U+24D14 [2000] [Unicode3.1] */ - {0xf0a4b88e, 0x00f67c}, /* U+24E0E [2000] [Unicode3.1] */ - {0xf0a4b8b7, 0x00f681}, /* U+24E37 [2000] [Unicode3.1] */ - {0xf0a4b9aa, 0x00f686}, /* U+24E6A [2000] [Unicode3.1] */ - {0xf0a4ba8b, 0x00f689}, /* U+24E8B [2000] [Unicode3.1] */ - {0xf0a5818a, 0x00f695}, /* U+2504A [2000] [Unicode3.1] */ - {0xf0a58195, 0x00f697}, /* U+25055 [2000] [Unicode3.1] */ - {0xf0a584a2, 0x00f69a}, /* U+25122 [2000] [Unicode3.1] */ - {0xf0a586a9, 0x00f69f}, /* U+251A9 [2000] [Unicode3.1] */ - {0xf0a5878d, 0x00f6a2}, /* U+251CD [2000] [Unicode3.1] */ - {0xf0a587a5, 0x00f6a1}, /* U+251E5 [2000] [Unicode3.1] */ - {0xf0a5889e, 0x00f6a6}, /* U+2521E [2000] [Unicode3.1] */ - {0xf0a5898c, 0x00f6aa}, /* U+2524C [2000] [Unicode3.1] */ - {0xf0a590ae, 0x00f6bb}, /* U+2542E [2000] [Unicode3.1] */ - {0xf0a5928e, 0x00ecfc}, /* U+2548E [2000] [Unicode3.1] */ - {0xf0a59399, 0x00f6c6}, /* U+254D9 [2000] [Unicode3.1] */ - {0xf0a5948e, 0x00ed48}, /* U+2550E [2000] [Unicode3.1] */ - {0xf0a596a7, 0x00f6d9}, /* U+255A7 [2000] [Unicode3.1] */ - {0xf0a59db1, 0x00ed66}, /* U+25771 [2000] [Unicode3.1] */ - {0xf0a59ea9, 0x00f6f3}, /* U+257A9 [2000] [Unicode3.1] */ - {0xf0a59eb4, 0x00f6f4}, /* U+257B4 [2000] [Unicode3.1] */ - {0xf0a5a784, 0x00ed73}, /* U+259C4 [2000] [Unicode3.1] */ - {0xf0a5a794, 0x00f751}, /* U+259D4 [2000] [Unicode3.1] */ - {0xf0a5aba3, 0x00f75d}, /* U+25AE3 [2000] [Unicode3.1] */ - {0xf0a5aba4, 0x00f75c}, /* U+25AE4 [2000] [Unicode3.1] */ - {0xf0a5abb1, 0x00f75f}, /* U+25AF1 [2000] [Unicode3.1] */ - {0xf0a5aeb2, 0x00f771}, /* U+25BB2 [2000] [Unicode3.1] */ - {0xf0a5b18b, 0x00f77c}, /* U+25C4B [2000] [Unicode3.1] */ - {0xf0a5b1a4, 0x00f77d}, /* U+25C64 [2000] [Unicode3.1] */ - {0xf0a5b6a1, 0x00ed8e}, /* U+25DA1 [2000] [Unicode3.1] */ - {0xf0a5b8ae, 0x00f793}, /* U+25E2E [2000] [Unicode3.1] */ - {0xf0a5b996, 0x00f794}, /* U+25E56 [2000] [Unicode3.1] */ - {0xf0a5b9a2, 0x00f797}, /* U+25E62 [2000] [Unicode3.1] */ - {0xf0a5b9a5, 0x00f795}, /* U+25E65 [2000] [Unicode3.1] */ - {0xf0a5bb82, 0x00f79d}, /* U+25EC2 [2000] [Unicode3.1] */ - {0xf0a5bb98, 0x00f79b}, /* U+25ED8 [2000] [Unicode3.1] */ - {0xf0a5bba8, 0x00f7a0}, /* U+25EE8 [2000] [Unicode3.1] */ - {0xf0a5bca3, 0x00f7a2}, /* U+25F23 [2000] [Unicode3.1] */ - {0xf0a5bd9c, 0x00f7a5}, /* U+25F5C [2000] [Unicode3.1] */ - {0xf0a5bf94, 0x00f7ad}, /* U+25FD4 [2000] [Unicode3.1] */ - {0xf0a5bfa0, 0x00f7ac}, /* U+25FE0 [2000] [Unicode3.1] */ - {0xf0a5bfbb, 0x00f7b3}, /* U+25FFB [2000] [Unicode3.1] */ - {0xf0a6808c, 0x00f7b2}, /* U+2600C [2000] [Unicode3.1] */ - {0xf0a68097, 0x00f7bb}, /* U+26017 [2000] [Unicode3.1] */ - {0xf0a681a0, 0x00f7c0}, /* U+26060 [2000] [Unicode3.1] */ - {0xf0a683ad, 0x00f7cd}, /* U+260ED [2000] [Unicode3.1] */ - {0xf0a689b0, 0x00f7e7}, /* U+26270 [2000] [Unicode3.1] */ - {0xf0a68a86, 0x00f7e9}, /* U+26286 [2000] [Unicode3.1] */ - {0xf0a68d8c, 0x00f7f0}, /* U+2634C [2000] [Unicode3.1] */ - {0xf0a69082, 0x00f7f7}, /* U+26402 [2000] [Unicode3.1] */ - {0xf0a699be, 0x00f854}, /* U+2667E [2000] [Unicode3.1] */ - {0xf0a69ab0, 0x00f859}, /* U+266B0 [2000] [Unicode3.1] */ - {0xf0a69c9d, 0x00f865}, /* U+2671D [2000] [Unicode3.1] */ - {0xf0a6a39d, 0x00f875}, /* U+268DD [2000] [Unicode3.1] */ - {0xf0a6a3aa, 0x00f877}, /* U+268EA [2000] [Unicode3.1] */ - {0xf0a6a591, 0x00f879}, /* U+26951 [2000] [Unicode3.1] */ - {0xf0a6a5af, 0x00f87c}, /* U+2696F [2000] [Unicode3.1] */ - {0xf0a6a79d, 0x00f87e}, /* U+269DD [2000] [Unicode3.1] */ - {0xf0a6a89e, 0x00f883}, /* U+26A1E [2000] [Unicode3.1] */ - {0xf0a6a998, 0x00f88a}, /* U+26A58 [2000] [Unicode3.1] */ - {0xf0a6aa8c, 0x00f890}, /* U+26A8C [2000] [Unicode3.1] */ - {0xf0a6aab7, 0x00f893}, /* U+26AB7 [2000] [Unicode3.1] */ - {0xf0a6abbf, 0x00eddb}, /* U+26AFF [2000] [Unicode3.1] */ - {0xf0a6b0a9, 0x00f263}, /* U+26C29 [2000] [Unicode3.1] */ - {0xf0a6b1b3, 0x00f8c2}, /* U+26C73 [2000] [Unicode3.1] */ - {0xf0a6b39d, 0x00f8cc}, /* U+26CDD [2000] [Unicode3.1] */ - {0xf0a6b980, 0x00ee52}, /* U+26E40 [2000] [Unicode3.1] */ - {0xf0a6b9a5, 0x00f8db}, /* U+26E65 [2000] [Unicode3.1] */ - {0xf0a6be94, 0x00f8f3}, /* U+26F94 [2000] [Unicode3.1] */ - {0xf0a6bfb6, 0x00f940}, /* U+26FF6 [2000] [Unicode3.1] */ - {0xf0a6bfb7, 0x00f941}, /* U+26FF7 [2000] [Unicode3.1] */ - {0xf0a6bfb8, 0x00f8fc}, /* U+26FF8 [2000] [Unicode3.1] */ - {0xf0a783b4, 0x00ee68}, /* U+270F4 [2000] [Unicode3.1] */ - {0xf0a7848d, 0x00f952}, /* U+2710D [2000] [Unicode3.1] */ - {0xf0a784b9, 0x00f955}, /* U+27139 [2000] [Unicode3.1] */ - {0xf0a78f9a, 0x00f985}, /* U+273DA [2000] [Unicode3.1] */ - {0xf0a78f9b, 0x00f984}, /* U+273DB [2000] [Unicode3.1] */ - {0xf0a78fbe, 0x00f98b}, /* U+273FE [2000] [Unicode3.1] */ - {0xf0a79090, 0x00f98e}, /* U+27410 [2000] [Unicode3.1] */ - {0xf0a79189, 0x00f993}, /* U+27449 [2000] [Unicode3.1] */ - {0xf0a79894, 0x00f9a8}, /* U+27614 [2000] [Unicode3.1] */ - {0xf0a79895, 0x00f9a7}, /* U+27615 [2000] [Unicode3.1] */ - {0xf0a798b1, 0x00f9aa}, /* U+27631 [2000] [Unicode3.1] */ - {0xf0a79a84, 0x00ee8c}, /* U+27684 [2000] [Unicode3.1] */ - {0xf0a79a93, 0x00f9b2}, /* U+27693 [2000] [Unicode3.1] */ - {0xf0a79c8e, 0x00f9ba}, /* U+2770E [2000] [Unicode3.1] */ - {0xf0a79ca3, 0x00f9bc}, /* U+27723 [2000] [Unicode3.1] */ - {0xf0a79d92, 0x00f9c0}, /* U+27752 [2000] [Unicode3.1] */ - {0xf0a7a685, 0x00f9d4}, /* U+27985 [2000] [Unicode3.1] */ - {0xf0a7aa84, 0x00f9e1}, /* U+27A84 [2000] [Unicode3.1] */ - {0xf0a7aeb3, 0x00f9f5}, /* U+27BB3 [2000] [Unicode3.1] */ - {0xf0a7aebe, 0x00f9f7}, /* U+27BBE [2000] [Unicode3.1] */ - {0xf0a7af87, 0x00f9f8}, /* U+27BC7 [2000] [Unicode3.1] */ - {0xf0a7b2b8, 0x00fa44}, /* U+27CB8 [2000] [Unicode3.1] */ - {0xf0a7b6a0, 0x00fa4e}, /* U+27DA0 [2000] [Unicode3.1] */ - {0xf0a7b890, 0x00fa51}, /* U+27E10 [2000] [Unicode3.1] */ - {0xf0a7beb7, 0x00fa58}, /* U+27FB7 [2000] [Unicode3.1] */ - {0xf0a8828a, 0x00fa61}, /* U+2808A [2000] [Unicode3.1] */ - {0xf0a882bb, 0x00fa67}, /* U+280BB [2000] [Unicode3.1] */ - {0xf0a889b7, 0x00eec7}, /* U+28277 [2000] [Unicode3.1] */ - {0xf0a88a82, 0x00fa78}, /* U+28282 [2000] [Unicode3.1] */ - {0xf0a88bb3, 0x00fa7d}, /* U+282F3 [2000] [Unicode3.1] */ - {0xf0a88f8d, 0x00eecf}, /* U+283CD [2000] [Unicode3.1] */ - {0xf0a8908c, 0x00fa86}, /* U+2840C [2000] [Unicode3.1] */ - {0xf0a89195, 0x00fa8b}, /* U+28455 [2000] [Unicode3.1] */ - {0xf0a895ab, 0x00fa9a}, /* U+2856B [2000] [Unicode3.1] */ - {0xf0a89788, 0x00fa9e}, /* U+285C8 [2000] [Unicode3.1] */ - {0xf0a89789, 0x00fa9f}, /* U+285C9 [2000] [Unicode3.1] */ - {0xf0a89b97, 0x00faaa}, /* U+286D7 [2000] [Unicode3.1] */ - {0xf0a89bba, 0x00faad}, /* U+286FA [2000] [Unicode3.1] */ - {0xf0a8a586, 0x00face}, /* U+28946 [2000] [Unicode3.1] */ - {0xf0a8a589, 0x00facd}, /* U+28949 [2000] [Unicode3.1] */ - {0xf0a8a5ab, 0x00fad5}, /* U+2896B [2000] [Unicode3.1] */ - {0xf0a8a687, 0x00fae3}, /* U+28987 [2000] [Unicode3.1] */ - {0xf0a8a688, 0x00fae4}, /* U+28988 [2000] [Unicode3.1] */ - {0xf0a8a6ba, 0x00faef}, /* U+289BA [2000] [Unicode3.1] */ - {0xf0a8a6bb, 0x00faf0}, /* U+289BB [2000] [Unicode3.1] */ - {0xf0a8a89e, 0x00fafc}, /* U+28A1E [2000] [Unicode3.1] */ - {0xf0a8a8a9, 0x00fb40}, /* U+28A29 [2000] [Unicode3.1] */ - {0xf0a8a983, 0x00fb4c}, /* U+28A43 [2000] [Unicode3.1] */ - {0xf0a8a9b1, 0x00fb4b}, /* U+28A71 [2000] [Unicode3.1] */ - {0xf0a8aa99, 0x00fb55}, /* U+28A99 [2000] [Unicode3.1] */ - {0xf0a8ab8d, 0x00fb56}, /* U+28ACD [2000] [Unicode3.1] */ - {0xf0a8ab9d, 0x00fb5d}, /* U+28ADD [2000] [Unicode3.1] */ - {0xf0a8aba4, 0x00fb5c}, /* U+28AE4 [2000] [Unicode3.1] */ - {0xf0a8af81, 0x00fb6d}, /* U+28BC1 [2000] [Unicode3.1] */ - {0xf0a8afaf, 0x00fb6e}, /* U+28BEF [2000] [Unicode3.1] */ - {0xf0a8b490, 0x00fb76}, /* U+28D10 [2000] [Unicode3.1] */ - {0xf0a8b5b1, 0x00fb79}, /* U+28D71 [2000] [Unicode3.1] */ - {0xf0a8b7bb, 0x00fb7b}, /* U+28DFB [2000] [Unicode3.1] */ - {0xf0a8b89f, 0x00fb7c}, /* U+28E1F [2000] [Unicode3.1] */ - {0xf0a8b8b6, 0x00fb81}, /* U+28E36 [2000] [Unicode3.1] */ - {0xf0a8ba89, 0x00fb85}, /* U+28E89 [2000] [Unicode3.1] */ - {0xf0a8bbab, 0x00fb87}, /* U+28EEB [2000] [Unicode3.1] */ - {0xf0a8bcb2, 0x00fb89}, /* U+28F32 [2000] [Unicode3.1] */ - {0xf0a8bfb8, 0x00fb91}, /* U+28FF8 [2000] [Unicode3.1] */ - {0xf0a98aa0, 0x00fba0}, /* U+292A0 [2000] [Unicode3.1] */ - {0xf0a98ab1, 0x00fba1}, /* U+292B1 [2000] [Unicode3.1] */ - {0xf0a99290, 0x00fbb6}, /* U+29490 [2000] [Unicode3.1] */ - {0xf0a9978f, 0x00fbc0}, /* U+295CF [2000] [Unicode3.1] */ - {0xf0a999bf, 0x00fbca}, /* U+2967F [2000] [Unicode3.1] */ - {0xf0a99bb0, 0x00fbd4}, /* U+296F0 [2000] [Unicode3.1] */ - {0xf0a99c99, 0x00fbd7}, /* U+29719 [2000] [Unicode3.1] */ - {0xf0a99d90, 0x00fbdb}, /* U+29750 [2000] [Unicode3.1] */ - {0xf0a9a386, 0x00fbf4}, /* U+298C6 [2000] [Unicode3.1] */ - {0xf0a9a9b2, 0x00fc4b}, /* U+29A72 [2000] [Unicode3.1] */ - {0xf0a9b79b, 0x00fc6a}, /* U+29DDB [2000] [Unicode3.1] */ - {0xf0a9b895, 0x00fc78}, /* U+29E15 [2000] [Unicode3.1] */ - {0xf0a9b8bd, 0x00fc6b}, /* U+29E3D [2000] [Unicode3.1] */ - {0xf0a9b989, 0x00fc7c}, /* U+29E49 [2000] [Unicode3.1] */ - {0xf0a9ba8a, 0x00fc7a}, /* U+29E8A [2000] [Unicode3.1] */ - {0xf0a9bb84, 0x00fc87}, /* U+29EC4 [2000] [Unicode3.1] */ - {0xf0a9bb9b, 0x00fc90}, /* U+29EDB [2000] [Unicode3.1] */ - {0xf0a9bba9, 0x00fc8d}, /* U+29EE9 [2000] [Unicode3.1] */ - {0xf0a9bf8e, 0x00fca3}, /* U+29FCE [2000] [Unicode3.1] */ - {0xf0aa809a, 0x00fca9}, /* U+2A01A [2000] [Unicode3.1] */ - {0xf0aa80af, 0x00fca7}, /* U+2A02F [2000] [Unicode3.1] */ - {0xf0aa8282, 0x00fcb3}, /* U+2A082 [2000] [Unicode3.1] */ - {0xf0aa83b9, 0x00fcb0}, /* U+2A0F9 [2000] [Unicode3.1] */ - {0xf0aa8690, 0x00efe4}, /* U+2A190 [2000] [Unicode3.1] */ - {0xf0aa8e8c, 0x00fcd6}, /* U+2A38C [2000] [Unicode3.1] */ - {0xf0aa90b7, 0x00fcd8}, /* U+2A437 [2000] [Unicode3.1] */ - {0xf0aa97b1, 0x00fcec}, /* U+2A5F1 [2000] [Unicode3.1] */ - {0xf0aa9882, 0x00fcee}, /* U+2A602 [2000] [Unicode3.1] */ - {0xf0aa989a, 0x00fcf0}, /* U+2A61A [2000] [Unicode3.1] */ - {0xf0aa9ab2, 0x00fcf4} /* U+2A6B2 [2000] [Unicode3.1] */ +/* src/backend/utils/mb/Unicode/utf8_to_shift_jis_2004.map */ + +static const pg_utf_to_local ULmapSHIFT_JIS_2004[ 11271 ] = { /* */ + {0xc2a0, 0x8541}, /* U+00A0 NO-BREAK SPACE [2000] */ + {0xc2a1, 0x8542}, /* U+00A1 INVERTED EXCLAMATION MARK [2000] */ + {0xc2a2, 0x8191}, /* U+00A2 CENT SIGN Windows: U+FFE0 */ + {0xc2a3, 0x8192}, /* U+00A3 POUND SIGN Windows: U+FFE1 */ + {0xc2a4, 0x8543}, /* U+00A4 CURRENCY SIGN [2000] */ + {0xc2a5, 0x005c}, /* U+00A5 YEN SIGN */ + {0xc2a6, 0x8544}, /* U+00A6 BROKEN BAR [2000] */ + {0xc2a7, 0x8198}, /* U+00A7 SECTION SIGN */ + {0xc2a8, 0x814e}, /* U+00A8 DIAERESIS */ + {0xc2a9, 0x8545}, /* U+00A9 COPYRIGHT SIGN [2000] */ + {0xc2aa, 0x8546}, /* U+00AA FEMININE ORDINAL INDICATOR [2000] */ + {0xc2ab, 0x8547}, /* U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK [2000] */ + {0xc2ac, 0x81ca}, /* U+00AC NOT SIGN [1983] Windows: U+FFE2 */ + {0xc2ad, 0x8548}, /* U+00AD SOFT HYPHEN [2000] */ + {0xc2ae, 0x8549}, /* U+00AE REGISTERED SIGN [2000] */ + {0xc2af, 0x854a}, /* U+00AF MACRON [2000] */ + {0xc2b0, 0x818b}, /* U+00B0 DEGREE SIGN */ + {0xc2b1, 0x817d}, /* U+00B1 PLUS-MINUS SIGN */ + {0xc2b2, 0x854b}, /* U+00B2 SUPERSCRIPT TWO [2000] */ + {0xc2b3, 0x854c}, /* U+00B3 SUPERSCRIPT THREE [2000] */ + {0xc2b4, 0x814c}, /* U+00B4 ACUTE ACCENT */ + {0xc2b6, 0x81f7}, /* U+00B6 PILCROW SIGN [1983] */ + {0xc2b7, 0x854d}, /* U+00B7 MIDDLE DOT [2000] */ + {0xc2b8, 0x854e}, /* U+00B8 CEDILLA [2000] */ + {0xc2b9, 0x854f}, /* U+00B9 SUPERSCRIPT ONE [2000] */ + {0xc2ba, 0x8550}, /* U+00BA MASCULINE ORDINAL INDICATOR [2000] */ + {0xc2bb, 0x8551}, /* U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK [2000] */ + {0xc2bc, 0x8552}, /* U+00BC VULGAR FRACTION ONE QUARTER [2000] */ + {0xc2bd, 0x8553}, /* U+00BD VULGAR FRACTION ONE HALF [2000] */ + {0xc2be, 0x8554}, /* U+00BE VULGAR FRACTION THREE QUARTERS [2000] */ + {0xc2bf, 0x8555}, /* U+00BF INVERTED QUESTION MARK [2000] */ + {0xc380, 0x8556}, /* U+00C0 LATIN CAPITAL LETTER A WITH GRAVE [2000] */ + {0xc381, 0x8557}, /* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE [2000] */ + {0xc382, 0x8558}, /* U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX [2000] */ + {0xc383, 0x8559}, /* U+00C3 LATIN CAPITAL LETTER A WITH TILDE [2000] */ + {0xc384, 0x855a}, /* U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS [2000] */ + {0xc385, 0x855b}, /* U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE [2000] */ + {0xc386, 0x855c}, /* U+00C6 LATIN CAPITAL LETTER AE [2000] */ + {0xc387, 0x855d}, /* U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA [2000] */ + {0xc388, 0x855e}, /* U+00C8 LATIN CAPITAL LETTER E WITH GRAVE [2000] */ + {0xc389, 0x855f}, /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE [2000] */ + {0xc38a, 0x8560}, /* U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX [2000] */ + {0xc38b, 0x8561}, /* U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS [2000] */ + {0xc38c, 0x8562}, /* U+00CC LATIN CAPITAL LETTER I WITH GRAVE [2000] */ + {0xc38d, 0x8563}, /* U+00CD LATIN CAPITAL LETTER I WITH ACUTE [2000] */ + {0xc38e, 0x8564}, /* U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX [2000] */ + {0xc38f, 0x8565}, /* U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS [2000] */ + {0xc390, 0x8566}, /* U+00D0 LATIN CAPITAL LETTER ETH [2000] */ + {0xc391, 0x8567}, /* U+00D1 LATIN CAPITAL LETTER N WITH TILDE [2000] */ + {0xc392, 0x8568}, /* U+00D2 LATIN CAPITAL LETTER O WITH GRAVE [2000] */ + {0xc393, 0x8569}, /* U+00D3 LATIN CAPITAL LETTER O WITH ACUTE [2000] */ + {0xc394, 0x856a}, /* U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX [2000] */ + {0xc395, 0x856b}, /* U+00D5 LATIN CAPITAL LETTER O WITH TILDE [2000] */ + {0xc396, 0x856c}, /* U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS [2000] */ + {0xc397, 0x817e}, /* U+00D7 MULTIPLICATION SIGN */ + {0xc398, 0x856d}, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE [2000] */ + {0xc399, 0x856e}, /* U+00D9 LATIN CAPITAL LETTER U WITH GRAVE [2000] */ + {0xc39a, 0x856f}, /* U+00DA LATIN CAPITAL LETTER U WITH ACUTE [2000] */ + {0xc39b, 0x8570}, /* U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX [2000] */ + {0xc39c, 0x8571}, /* U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS [2000] */ + {0xc39d, 0x8572}, /* U+00DD LATIN CAPITAL LETTER Y WITH ACUTE [2000] */ + {0xc39e, 0x8573}, /* U+00DE LATIN CAPITAL LETTER THORN [2000] */ + {0xc39f, 0x8574}, /* U+00DF LATIN SMALL LETTER SHARP S [2000] */ + {0xc3a0, 0x8575}, /* U+00E0 LATIN SMALL LETTER A WITH GRAVE [2000] */ + {0xc3a1, 0x8576}, /* U+00E1 LATIN SMALL LETTER A WITH ACUTE [2000] */ + {0xc3a2, 0x8577}, /* U+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX [2000] */ + {0xc3a3, 0x8578}, /* U+00E3 LATIN SMALL LETTER A WITH TILDE [2000] */ + {0xc3a4, 0x8579}, /* U+00E4 LATIN SMALL LETTER A WITH DIAERESIS [2000] */ + {0xc3a5, 0x857a}, /* U+00E5 LATIN SMALL LETTER A WITH RING ABOVE [2000] */ + {0xc3a6, 0x857b}, /* U+00E6 LATIN SMALL LETTER AE [2000] */ + {0xc3a7, 0x857c}, /* U+00E7 LATIN SMALL LETTER C WITH CEDILLA [2000] */ + {0xc3a8, 0x857d}, /* U+00E8 LATIN SMALL LETTER E WITH GRAVE [2000] */ + {0xc3a9, 0x857e}, /* U+00E9 LATIN SMALL LETTER E WITH ACUTE [2000] */ + {0xc3aa, 0x8580}, /* U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX [2000] */ + {0xc3ab, 0x8581}, /* U+00EB LATIN SMALL LETTER E WITH DIAERESIS [2000] */ + {0xc3ac, 0x8582}, /* U+00EC LATIN SMALL LETTER I WITH GRAVE [2000] */ + {0xc3ad, 0x8583}, /* U+00ED LATIN SMALL LETTER I WITH ACUTE [2000] */ + {0xc3ae, 0x8584}, /* U+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX [2000] */ + {0xc3af, 0x8585}, /* U+00EF LATIN SMALL LETTER I WITH DIAERESIS [2000] */ + {0xc3b0, 0x8586}, /* U+00F0 LATIN SMALL LETTER ETH [2000] */ + {0xc3b1, 0x8587}, /* U+00F1 LATIN SMALL LETTER N WITH TILDE [2000] */ + {0xc3b2, 0x8588}, /* U+00F2 LATIN SMALL LETTER O WITH GRAVE [2000] */ + {0xc3b3, 0x8589}, /* U+00F3 LATIN SMALL LETTER O WITH ACUTE [2000] */ + {0xc3b4, 0x858a}, /* U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX [2000] */ + {0xc3b5, 0x858b}, /* U+00F5 LATIN SMALL LETTER O WITH TILDE [2000] */ + {0xc3b6, 0x858c}, /* U+00F6 LATIN SMALL LETTER O WITH DIAERESIS [2000] */ + {0xc3b7, 0x8180}, /* U+00F7 DIVISION SIGN */ + {0xc3b8, 0x858d}, /* U+00F8 LATIN SMALL LETTER O WITH STROKE [2000] */ + {0xc3b9, 0x858e}, /* U+00F9 LATIN SMALL LETTER U WITH GRAVE [2000] */ + {0xc3ba, 0x858f}, /* U+00FA LATIN SMALL LETTER U WITH ACUTE [2000] */ + {0xc3bb, 0x8590}, /* U+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX [2000] */ + {0xc3bc, 0x8591}, /* U+00FC LATIN SMALL LETTER U WITH DIAERESIS [2000] */ + {0xc3bd, 0x8592}, /* U+00FD LATIN SMALL LETTER Y WITH ACUTE [2000] */ + {0xc3be, 0x8593}, /* U+00FE LATIN SMALL LETTER THORN [2000] */ + {0xc3bf, 0x8594}, /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS [2000] */ + {0xc480, 0x8595}, /* U+0100 LATIN CAPITAL LETTER A WITH MACRON [2000] */ + {0xc481, 0x859a}, /* U+0101 LATIN SMALL LETTER A WITH MACRON [2000] */ + {0xc482, 0x85b8}, /* U+0102 LATIN CAPITAL LETTER A WITH BREVE [2000] */ + {0xc483, 0x85c7}, /* U+0103 LATIN SMALL LETTER A WITH BREVE [2000] */ + {0xc484, 0x859f}, /* U+0104 LATIN CAPITAL LETTER A WITH OGONEK [2000] */ + {0xc485, 0x85aa}, /* U+0105 LATIN SMALL LETTER A WITH OGONEK [2000] */ + {0xc486, 0x85ba}, /* U+0106 LATIN CAPITAL LETTER C WITH ACUTE [2000] */ + {0xc487, 0x85c9}, /* U+0107 LATIN SMALL LETTER C WITH ACUTE [2000] */ + {0xc488, 0x85d7}, /* U+0108 LATIN CAPITAL LETTER C WITH CIRCUMFLEX [2000] */ + {0xc489, 0x85dd}, /* U+0109 LATIN SMALL LETTER C WITH CIRCUMFLEX [2000] */ + {0xc48c, 0x85bb}, /* U+010C LATIN CAPITAL LETTER C WITH CARON [2000] */ + {0xc48d, 0x85ca}, /* U+010D LATIN SMALL LETTER C WITH CARON [2000] */ + {0xc48e, 0x85be}, /* U+010E LATIN CAPITAL LETTER D WITH CARON [2000] */ + {0xc48f, 0x85cd}, /* U+010F LATIN SMALL LETTER D WITH CARON [2000] */ + {0xc491, 0x85ce}, /* U+0111 LATIN SMALL LETTER D WITH STROKE [2000] */ + {0xc492, 0x8598}, /* U+0112 LATIN CAPITAL LETTER E WITH MACRON [2000] */ + {0xc493, 0x859d}, /* U+0113 LATIN SMALL LETTER E WITH MACRON [2000] */ + {0xc498, 0x85bc}, /* U+0118 LATIN CAPITAL LETTER E WITH OGONEK [2000] */ + {0xc499, 0x85cb}, /* U+0119 LATIN SMALL LETTER E WITH OGONEK [2000] */ + {0xc49a, 0x85bd}, /* U+011A LATIN CAPITAL LETTER E WITH CARON [2000] */ + {0xc49b, 0x85cc}, /* U+011B LATIN SMALL LETTER E WITH CARON [2000] */ + {0xc49c, 0x85d8}, /* U+011C LATIN CAPITAL LETTER G WITH CIRCUMFLEX [2000] */ + {0xc49d, 0x85de}, /* U+011D LATIN SMALL LETTER G WITH CIRCUMFLEX [2000] */ + {0xc4a4, 0x85d9}, /* U+0124 LATIN CAPITAL LETTER H WITH CIRCUMFLEX [2000] */ + {0xc4a5, 0x85df}, /* U+0125 LATIN SMALL LETTER H WITH CIRCUMFLEX [2000] */ + {0xc4a7, 0x85fb}, /* U+0127 LATIN SMALL LETTER H WITH STROKE [2000] */ + {0xc4aa, 0x8596}, /* U+012A LATIN CAPITAL LETTER I WITH MACRON [2000] */ + {0xc4ab, 0x859b}, /* U+012B LATIN SMALL LETTER I WITH MACRON [2000] */ + {0xc4b4, 0x85da}, /* U+0134 LATIN CAPITAL LETTER J WITH CIRCUMFLEX [2000] */ + {0xc4b5, 0x85e0}, /* U+0135 LATIN SMALL LETTER J WITH CIRCUMFLEX [2000] */ + {0xc4b9, 0x85b9}, /* U+0139 LATIN CAPITAL LETTER L WITH ACUTE [2000] */ + {0xc4ba, 0x85c8}, /* U+013A LATIN SMALL LETTER L WITH ACUTE [2000] */ + {0xc4bd, 0x85a2}, /* U+013D LATIN CAPITAL LETTER L WITH CARON [2000] */ + {0xc4be, 0x85ad}, /* U+013E LATIN SMALL LETTER L WITH CARON [2000] */ + {0xc581, 0x85a1}, /* U+0141 LATIN CAPITAL LETTER L WITH STROKE [2000] */ + {0xc582, 0x85ac}, /* U+0142 LATIN SMALL LETTER L WITH STROKE [2000] */ + {0xc583, 0x85bf}, /* U+0143 LATIN CAPITAL LETTER N WITH ACUTE [2000] */ + {0xc584, 0x85cf}, /* U+0144 LATIN SMALL LETTER N WITH ACUTE [2000] */ + {0xc587, 0x85c0}, /* U+0147 LATIN CAPITAL LETTER N WITH CARON [2000] */ + {0xc588, 0x85d0}, /* U+0148 LATIN SMALL LETTER N WITH CARON [2000] */ + {0xc58b, 0x85f8}, /* U+014B LATIN SMALL LETTER ENG [2000] */ + {0xc58c, 0x8599}, /* U+014C LATIN CAPITAL LETTER O WITH MACRON [2000] */ + {0xc58d, 0x859e}, /* U+014D LATIN SMALL LETTER O WITH MACRON [2000] */ + {0xc590, 0x85c1}, /* U+0150 LATIN CAPITAL LETTER O WITH DOUBLE ACUTE [2000] */ + {0xc591, 0x85d1}, /* U+0151 LATIN SMALL LETTER O WITH DOUBLE ACUTE [2000] */ + {0xc592, 0x864a}, /* U+0152 LATIN CAPITAL LIGATURE OE [2000] */ + {0xc593, 0x8649}, /* U+0153 LATIN SMALL LIGATURE OE [2000] */ + {0xc594, 0x85b7}, /* U+0154 LATIN CAPITAL LETTER R WITH ACUTE [2000] */ + {0xc595, 0x85c6}, /* U+0155 LATIN SMALL LETTER R WITH ACUTE [2000] */ + {0xc598, 0x85c2}, /* U+0158 LATIN CAPITAL LETTER R WITH CARON [2000] */ + {0xc599, 0x85d2}, /* U+0159 LATIN SMALL LETTER R WITH CARON [2000] */ + {0xc59a, 0x85a3}, /* U+015A LATIN CAPITAL LETTER S WITH ACUTE [2000] */ + {0xc59b, 0x85ae}, /* U+015B LATIN SMALL LETTER S WITH ACUTE [2000] */ + {0xc59c, 0x85db}, /* U+015C LATIN CAPITAL LETTER S WITH CIRCUMFLEX [2000] */ + {0xc59d, 0x85e1}, /* U+015D LATIN SMALL LETTER S WITH CIRCUMFLEX [2000] */ + {0xc59e, 0x85a5}, /* U+015E LATIN CAPITAL LETTER S WITH CEDILLA [2000] */ + {0xc59f, 0x85b1}, /* U+015F LATIN SMALL LETTER S WITH CEDILLA [2000] */ + {0xc5a0, 0x85a4}, /* U+0160 LATIN CAPITAL LETTER S WITH CARON [2000] */ + {0xc5a1, 0x85b0}, /* U+0161 LATIN SMALL LETTER S WITH CARON [2000] */ + {0xc5a2, 0x85c5}, /* U+0162 LATIN CAPITAL LETTER T WITH CEDILLA [2000] */ + {0xc5a3, 0x85d5}, /* U+0163 LATIN SMALL LETTER T WITH CEDILLA [2000] */ + {0xc5a4, 0x85a6}, /* U+0164 LATIN CAPITAL LETTER T WITH CARON [2000] */ + {0xc5a5, 0x85b2}, /* U+0165 LATIN SMALL LETTER T WITH CARON [2000] */ + {0xc5aa, 0x8597}, /* U+016A LATIN CAPITAL LETTER U WITH MACRON [2000] */ + {0xc5ab, 0x859c}, /* U+016B LATIN SMALL LETTER U WITH MACRON [2000] */ + {0xc5ac, 0x85dc}, /* U+016C LATIN CAPITAL LETTER U WITH BREVE [2000] */ + {0xc5ad, 0x85e2}, /* U+016D LATIN SMALL LETTER U WITH BREVE [2000] */ + {0xc5ae, 0x85c3}, /* U+016E LATIN CAPITAL LETTER U WITH RING ABOVE [2000] */ + {0xc5af, 0x85d3}, /* U+016F LATIN SMALL LETTER U WITH RING ABOVE [2000] */ + {0xc5b0, 0x85c4}, /* U+0170 LATIN CAPITAL LETTER U WITH DOUBLE ACUTE [2000] */ + {0xc5b1, 0x85d4}, /* U+0171 LATIN SMALL LETTER U WITH DOUBLE ACUTE [2000] */ + {0xc5b9, 0x85a7}, /* U+0179 LATIN CAPITAL LETTER Z WITH ACUTE [2000] */ + {0xc5ba, 0x85b3}, /* U+017A LATIN SMALL LETTER Z WITH ACUTE [2000] */ + {0xc5bb, 0x85a9}, /* U+017B LATIN CAPITAL LETTER Z WITH DOT ABOVE [2000] */ + {0xc5bc, 0x85b6}, /* U+017C LATIN SMALL LETTER Z WITH DOT ABOVE [2000] */ + {0xc5bd, 0x85a8}, /* U+017D LATIN CAPITAL LETTER Z WITH CARON [2000] */ + {0xc5be, 0x85b5}, /* U+017E LATIN SMALL LETTER Z WITH CARON [2000] */ + {0xc693, 0x8648}, /* U+0193 LATIN CAPITAL LETTER G WITH HOOK [2000] */ + {0xc782, 0x8643}, /* U+01C2 LATIN LETTER ALVEOLAR CLICK [2000] */ + {0xc78d, 0x84ed}, /* U+01CD LATIN CAPITAL LETTER A WITH CARON [2000] */ + {0xc78e, 0x84ee}, /* U+01CE LATIN SMALL LETTER A WITH CARON [2000] */ + {0xc790, 0x84ef}, /* U+01D0 LATIN SMALL LETTER I WITH CARON [2000] */ + {0xc791, 0x84f4}, /* U+01D1 LATIN CAPITAL LETTER O WITH CARON [2000] */ + {0xc792, 0x84f5}, /* U+01D2 LATIN SMALL LETTER O WITH CARON [2000] */ + {0xc794, 0x84f6}, /* U+01D4 LATIN SMALL LETTER U WITH CARON [2000] */ + {0xc796, 0x84f7}, /* U+01D6 LATIN SMALL LETTER U WITH DIAERESIS AND MACRON [2000] */ + {0xc798, 0x84f8}, /* U+01D8 LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE [2000] */ + {0xc79a, 0x84f9}, /* U+01DA LATIN SMALL LETTER U WITH DIAERESIS AND CARON [2000] */ + {0xc79c, 0x84fa}, /* U+01DC LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE [2000] */ + {0xc7b8, 0x84f2}, /* U+01F8 LATIN CAPITAL LETTER N WITH GRAVE [2000] */ + {0xc7b9, 0x84f3}, /* U+01F9 LATIN SMALL LETTER N WITH GRAVE [2000] */ + {0xc7bd, 0x8664}, /* U+01FD LATIN SMALL LETTER AE WITH ACUTE [2000] */ + {0xc990, 0x8652}, /* U+0250 LATIN SMALL LETTER TURNED A [2000] */ + {0xc991, 0x8658}, /* U+0251 LATIN SMALL LETTER ALPHA [2000] */ + {0xc992, 0x8659}, /* U+0252 LATIN SMALL LETTER TURNED ALPHA [2000] */ + {0xc993, 0x8644}, /* U+0253 LATIN SMALL LETTER B WITH HOOK [2000] */ + {0xc994, 0x8657}, /* U+0254 LATIN SMALL LETTER OPEN O [2000] */ + {0xc995, 0x865e}, /* U+0255 LATIN SMALL LETTER C WITH CURL [2000] */ + {0xc996, 0x85ec}, /* U+0256 LATIN SMALL LETTER D WITH TAIL [2000] */ + {0xc997, 0x8645}, /* U+0257 LATIN SMALL LETTER D WITH HOOK [2000] */ + {0xc998, 0x864d}, /* U+0258 LATIN SMALL LETTER REVERSED E [2000] */ + {0xc999, 0x864f}, /* U+0259 LATIN SMALL LETTER SCHWA [2000] */ + {0xc99a, 0x8662}, /* U+025A LATIN SMALL LETTER SCHWA WITH HOOK [2000] */ + {0xc99c, 0x8650}, /* U+025C LATIN SMALL LETTER REVERSED OPEN E [2000] */ + {0xc99e, 0x8651}, /* U+025E LATIN SMALL LETTER CLOSED REVERSED OPEN E [2000] */ + {0xc99f, 0x85f3}, /* U+025F LATIN SMALL LETTER DOTLESS J WITH STROKE [2000] */ + {0xc9a0, 0x8647}, /* U+0260 LATIN SMALL LETTER G WITH HOOK [2000] */ + {0xc9a1, 0x85f7}, /* U+0261 LATIN SMALL LETTER SCRIPT G [2000] */ + {0xc9a4, 0x8655}, /* U+0264 LATIN SMALL LETTER RAMS HORN [2000] */ + {0xc9a5, 0x865b}, /* U+0265 LATIN SMALL LETTER TURNED H [2000] */ + {0xc9a6, 0x8641}, /* U+0266 LATIN SMALL LETTER H WITH HOOK [2000] */ + {0xc9a7, 0x8661}, /* U+0267 LATIN SMALL LETTER HENG WITH HOOK [2000] */ + {0xc9a8, 0x864b}, /* U+0268 LATIN SMALL LETTER I WITH STROKE [2000] */ + {0xc9ac, 0x85e8}, /* U+026C LATIN SMALL LETTER L WITH BELT [2000] */ + {0xc9ad, 0x85f2}, /* U+026D LATIN SMALL LETTER L WITH RETROFLEX HOOK [2000] */ + {0xc9ae, 0x85e9}, /* U+026E LATIN SMALL LETTER LEZH [2000] */ + {0xc9af, 0x8653}, /* U+026F LATIN SMALL LETTER TURNED M [2000] */ + {0xc9b0, 0x85f9}, /* U+0270 LATIN SMALL LETTER TURNED M WITH LONG LEG [2000] */ + {0xc9b1, 0x85e3}, /* U+0271 LATIN SMALL LETTER M WITH HOOK [2000] */ + {0xc9b2, 0x85f4}, /* U+0272 LATIN SMALL LETTER N WITH LEFT HOOK [2000] */ + {0xc9b3, 0x85ed}, /* U+0273 LATIN SMALL LETTER N WITH RETROFLEX HOOK [2000] */ + {0xc9b5, 0x864e}, /* U+0275 LATIN SMALL LETTER BARRED O [2000] */ + {0xc9b9, 0x85ea}, /* U+0279 LATIN SMALL LETTER TURNED R [2000] */ + {0xc9ba, 0x8660}, /* U+027A LATIN SMALL LETTER TURNED R WITH LONG LEG [2000] */ + {0xc9bb, 0x85f1}, /* U+027B LATIN SMALL LETTER TURNED R WITH HOOK [2000] */ + {0xc9bd, 0x85ee}, /* U+027D LATIN SMALL LETTER R WITH TAIL [2000] */ + {0xc9be, 0x85e5}, /* U+027E LATIN SMALL LETTER R WITH FISHHOOK [2000] */ + {0xca81, 0x85fa}, /* U+0281 LATIN LETTER SMALL CAPITAL INVERTED R [2000] */ + {0xca82, 0x85ef}, /* U+0282 LATIN SMALL LETTER S WITH HOOK [2000] */ + {0xca83, 0x85e6}, /* U+0283 LATIN SMALL LETTER ESH [2000] */ + {0xca84, 0x8646}, /* U+0284 LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK [2000] */ + {0xca88, 0x85eb}, /* U+0288 LATIN SMALL LETTER T WITH RETROFLEX HOOK [2000] */ + {0xca89, 0x864c}, /* U+0289 LATIN SMALL LETTER U BAR [2000] */ + {0xca8a, 0x8654}, /* U+028A LATIN SMALL LETTER UPSILON [2000] */ + {0xca8b, 0x85e4}, /* U+028B LATIN SMALL LETTER V WITH HOOK [2000] */ + {0xca8c, 0x8656}, /* U+028C LATIN SMALL LETTER TURNED V [2000] */ + {0xca8d, 0x865a}, /* U+028D LATIN SMALL LETTER TURNED W [2000] */ + {0xca8e, 0x85f6}, /* U+028E LATIN SMALL LETTER TURNED Y [2000] */ + {0xca90, 0x85f0}, /* U+0290 LATIN SMALL LETTER Z WITH RETROFLEX HOOK [2000] */ + {0xca91, 0x865f}, /* U+0291 LATIN SMALL LETTER Z WITH CURL [2000] */ + {0xca92, 0x85e7}, /* U+0292 LATIN SMALL LETTER EZH [2000] */ + {0xca94, 0x8640}, /* U+0294 LATIN LETTER GLOTTAL STOP [2000] */ + {0xca95, 0x85fc}, /* U+0295 LATIN LETTER PHARYNGEAL VOICED FRICATIVE [2000] */ + {0xca98, 0x8642}, /* U+0298 LATIN LETTER BILABIAL CLICK [2000] */ + {0xca9d, 0x85f5}, /* U+029D LATIN SMALL LETTER J WITH CROSSED-TAIL [2000] */ + {0xcaa1, 0x865d}, /* U+02A1 LATIN LETTER GLOTTAL STOP WITH STROKE [2000] */ + {0xcaa2, 0x865c}, /* U+02A2 LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE [2000] */ + {0xcb87, 0x85af}, /* U+02C7 CARON [2000] */ + {0xcb88, 0x8672}, /* U+02C8 MODIFIER LETTER VERTICAL LINE [2000] */ + {0xcb8c, 0x8673}, /* U+02CC MODIFIER LETTER LOW VERTICAL LINE [2000] */ + {0xcb90, 0x8674}, /* U+02D0 MODIFIER LETTER TRIANGULAR COLON [2000] */ + {0xcb91, 0x8675}, /* U+02D1 MODIFIER LETTER HALF TRIANGULAR COLON [2000] */ + {0xcb98, 0x85a0}, /* U+02D8 BREVE [2000] */ + {0xcb99, 0x85d6}, /* U+02D9 DOT ABOVE [2000] */ + {0xcb9b, 0x85ab}, /* U+02DB OGONEK [2000] */ + {0xcb9d, 0x85b4}, /* U+02DD DOUBLE ACUTE ACCENT [2000] */ + {0xcb9e, 0x8691}, /* U+02DE MODIFIER LETTER RHOTIC HOOK [2000] */ + {0xcba5, 0x8680}, /* U+02E5 MODIFIER LETTER EXTRA-HIGH TONE BAR [2000] */ + {0xcba6, 0x8681}, /* U+02E6 MODIFIER LETTER HIGH TONE BAR [2000] */ + {0xcba7, 0x8682}, /* U+02E7 MODIFIER LETTER MID TONE BAR [2000] */ + {0xcba8, 0x8683}, /* U+02E8 MODIFIER LETTER LOW TONE BAR [2000] */ + {0xcba9, 0x8684}, /* U+02E9 MODIFIER LETTER EXTRA-LOW TONE BAR [2000] */ + {0xcc80, 0x867b}, /* U+0300 COMBINING GRAVE ACCENT [2000] */ + {0xcc81, 0x8679}, /* U+0301 COMBINING ACUTE ACCENT [2000] */ + {0xcc82, 0x867e}, /* U+0302 COMBINING CIRCUMFLEX ACCENT [2000] */ + {0xcc83, 0x869d}, /* U+0303 COMBINING TILDE [2000] */ + {0xcc84, 0x867a}, /* U+0304 COMBINING MACRON [2000] */ + {0xcc86, 0x8676}, /* U+0306 COMBINING BREVE [2000] */ + {0xcc88, 0x868d}, /* U+0308 COMBINING DIAERESIS [2000] */ + {0xcc8b, 0x8678}, /* U+030B COMBINING DOUBLE ACUTE ACCENT [2000] */ + {0xcc8c, 0x867d}, /* U+030C COMBINING CARON [2000] */ + {0xcc8f, 0x867c}, /* U+030F COMBINING DOUBLE GRAVE ACCENT [2000] */ + {0xcc98, 0x8698}, /* U+0318 COMBINING LEFT TACK BELOW [2000] */ + {0xcc99, 0x8699}, /* U+0319 COMBINING RIGHT TACK BELOW [2000] */ + {0xcc9a, 0x869e}, /* U+031A COMBINING LEFT ANGLE ABOVE [2000] */ + {0xcc9c, 0x868a}, /* U+031C COMBINING LEFT HALF RING BELOW [2000] */ + {0xcc9d, 0x8696}, /* U+031D COMBINING UP TACK BELOW [2000] */ + {0xcc9e, 0x8697}, /* U+031E COMBINING DOWN TACK BELOW [2000] */ + {0xcc9f, 0x868b}, /* U+031F COMBINING PLUS SIGN BELOW [2000] */ + {0xcca0, 0x868c}, /* U+0320 COMBINING MINUS SIGN BELOW [2000] */ + {0xcca4, 0x8692}, /* U+0324 COMBINING DIAERESIS BELOW [2000] */ + {0xcca5, 0x8687}, /* U+0325 COMBINING RING BELOW [2000] */ + {0xcca9, 0x868f}, /* U+0329 COMBINING VERTICAL LINE BELOW [2000] */ + {0xccaa, 0x869a}, /* U+032A COMBINING BRIDGE BELOW [2000] */ + {0xccac, 0x8688}, /* U+032C COMBINING CARON BELOW [2000] */ + {0xccaf, 0x8690}, /* U+032F COMBINING INVERTED BREVE BELOW [2000] */ + {0xccb0, 0x8693}, /* U+0330 COMBINING TILDE BELOW [2000] */ + {0xccb4, 0x8695}, /* U+0334 COMBINING TILDE OVERLAY [2000] */ + {0xccb9, 0x8689}, /* U+0339 COMBINING RIGHT HALF RING BELOW [2000] */ + {0xccba, 0x869b}, /* U+033A COMBINING INVERTED BRIDGE BELOW [2000] */ + {0xccbb, 0x869c}, /* U+033B COMBINING SQUARE BELOW [2000] */ + {0xccbc, 0x8694}, /* U+033C COMBINING SEAGULL BELOW [2000] */ + {0xccbd, 0x868e}, /* U+033D COMBINING X ABOVE [2000] */ + {0xcda1, 0x8671}, /* U+0361 COMBINING DOUBLE INVERTED BREVE [2000] */ + {0xce91, 0x839f}, /* U+0391 GREEK CAPITAL LETTER ALPHA */ + {0xce92, 0x83a0}, /* U+0392 GREEK CAPITAL LETTER BETA */ + {0xce93, 0x83a1}, /* U+0393 GREEK CAPITAL LETTER GAMMA */ + {0xce94, 0x83a2}, /* U+0394 GREEK CAPITAL LETTER DELTA */ + {0xce95, 0x83a3}, /* U+0395 GREEK CAPITAL LETTER EPSILON */ + {0xce96, 0x83a4}, /* U+0396 GREEK CAPITAL LETTER ZETA */ + {0xce97, 0x83a5}, /* U+0397 GREEK CAPITAL LETTER ETA */ + {0xce98, 0x83a6}, /* U+0398 GREEK CAPITAL LETTER THETA */ + {0xce99, 0x83a7}, /* U+0399 GREEK CAPITAL LETTER IOTA */ + {0xce9a, 0x83a8}, /* U+039A GREEK CAPITAL LETTER KAPPA */ + {0xce9b, 0x83a9}, /* U+039B GREEK CAPITAL LETTER LAMDA */ + {0xce9c, 0x83aa}, /* U+039C GREEK CAPITAL LETTER MU */ + {0xce9d, 0x83ab}, /* U+039D GREEK CAPITAL LETTER NU */ + {0xce9e, 0x83ac}, /* U+039E GREEK CAPITAL LETTER XI */ + {0xce9f, 0x83ad}, /* U+039F GREEK CAPITAL LETTER OMICRON */ + {0xcea0, 0x83ae}, /* U+03A0 GREEK CAPITAL LETTER PI */ + {0xcea1, 0x83af}, /* U+03A1 GREEK CAPITAL LETTER RHO */ + {0xcea3, 0x83b0}, /* U+03A3 GREEK CAPITAL LETTER SIGMA */ + {0xcea4, 0x83b1}, /* U+03A4 GREEK CAPITAL LETTER TAU */ + {0xcea5, 0x83b2}, /* U+03A5 GREEK CAPITAL LETTER UPSILON */ + {0xcea6, 0x83b3}, /* U+03A6 GREEK CAPITAL LETTER PHI */ + {0xcea7, 0x83b4}, /* U+03A7 GREEK CAPITAL LETTER CHI */ + {0xcea8, 0x83b5}, /* U+03A8 GREEK CAPITAL LETTER PSI */ + {0xcea9, 0x83b6}, /* U+03A9 GREEK CAPITAL LETTER OMEGA */ + {0xceb1, 0x83bf}, /* U+03B1 GREEK SMALL LETTER ALPHA */ + {0xceb2, 0x83c0}, /* U+03B2 GREEK SMALL LETTER BETA */ + {0xceb3, 0x83c1}, /* U+03B3 GREEK SMALL LETTER GAMMA */ + {0xceb4, 0x83c2}, /* U+03B4 GREEK SMALL LETTER DELTA */ + {0xceb5, 0x83c3}, /* U+03B5 GREEK SMALL LETTER EPSILON */ + {0xceb6, 0x83c4}, /* U+03B6 GREEK SMALL LETTER ZETA */ + {0xceb7, 0x83c5}, /* U+03B7 GREEK SMALL LETTER ETA */ + {0xceb8, 0x83c6}, /* U+03B8 GREEK SMALL LETTER THETA */ + {0xceb9, 0x83c7}, /* U+03B9 GREEK SMALL LETTER IOTA */ + {0xceba, 0x83c8}, /* U+03BA GREEK SMALL LETTER KAPPA */ + {0xcebb, 0x83c9}, /* U+03BB GREEK SMALL LETTER LAMDA */ + {0xcebc, 0x83ca}, /* U+03BC GREEK SMALL LETTER MU */ + {0xcebd, 0x83cb}, /* U+03BD GREEK SMALL LETTER NU */ + {0xcebe, 0x83cc}, /* U+03BE GREEK SMALL LETTER XI */ + {0xcebf, 0x83cd}, /* U+03BF GREEK SMALL LETTER OMICRON */ + {0xcf80, 0x83ce}, /* U+03C0 GREEK SMALL LETTER PI */ + {0xcf81, 0x83cf}, /* U+03C1 GREEK SMALL LETTER RHO */ + {0xcf82, 0x83d7}, /* U+03C2 GREEK SMALL LETTER FINAL SIGMA [2000] */ + {0xcf83, 0x83d0}, /* U+03C3 GREEK SMALL LETTER SIGMA */ + {0xcf84, 0x83d1}, /* U+03C4 GREEK SMALL LETTER TAU */ + {0xcf85, 0x83d2}, /* U+03C5 GREEK SMALL LETTER UPSILON */ + {0xcf86, 0x83d3}, /* U+03C6 GREEK SMALL LETTER PHI */ + {0xcf87, 0x83d4}, /* U+03C7 GREEK SMALL LETTER CHI */ + {0xcf88, 0x83d5}, /* U+03C8 GREEK SMALL LETTER PSI */ + {0xcf89, 0x83d6}, /* U+03C9 GREEK SMALL LETTER OMEGA */ + {0xd081, 0x8446}, /* U+0401 CYRILLIC CAPITAL LETTER IO */ + {0xd090, 0x8440}, /* U+0410 CYRILLIC CAPITAL LETTER A */ + {0xd091, 0x8441}, /* U+0411 CYRILLIC CAPITAL LETTER BE */ + {0xd092, 0x8442}, /* U+0412 CYRILLIC CAPITAL LETTER VE */ + {0xd093, 0x8443}, /* U+0413 CYRILLIC CAPITAL LETTER GHE */ + {0xd094, 0x8444}, /* U+0414 CYRILLIC CAPITAL LETTER DE */ + {0xd095, 0x8445}, /* U+0415 CYRILLIC CAPITAL LETTER IE */ + {0xd096, 0x8447}, /* U+0416 CYRILLIC CAPITAL LETTER ZHE */ + {0xd097, 0x8448}, /* U+0417 CYRILLIC CAPITAL LETTER ZE */ + {0xd098, 0x8449}, /* U+0418 CYRILLIC CAPITAL LETTER I */ + {0xd099, 0x844a}, /* U+0419 CYRILLIC CAPITAL LETTER SHORT I */ + {0xd09a, 0x844b}, /* U+041A CYRILLIC CAPITAL LETTER KA */ + {0xd09b, 0x844c}, /* U+041B CYRILLIC CAPITAL LETTER EL */ + {0xd09c, 0x844d}, /* U+041C CYRILLIC CAPITAL LETTER EM */ + {0xd09d, 0x844e}, /* U+041D CYRILLIC CAPITAL LETTER EN */ + {0xd09e, 0x844f}, /* U+041E CYRILLIC CAPITAL LETTER O */ + {0xd09f, 0x8450}, /* U+041F CYRILLIC CAPITAL LETTER PE */ + {0xd0a0, 0x8451}, /* U+0420 CYRILLIC CAPITAL LETTER ER */ + {0xd0a1, 0x8452}, /* U+0421 CYRILLIC CAPITAL LETTER ES */ + {0xd0a2, 0x8453}, /* U+0422 CYRILLIC CAPITAL LETTER TE */ + {0xd0a3, 0x8454}, /* U+0423 CYRILLIC CAPITAL LETTER U */ + {0xd0a4, 0x8455}, /* U+0424 CYRILLIC CAPITAL LETTER EF */ + {0xd0a5, 0x8456}, /* U+0425 CYRILLIC CAPITAL LETTER HA */ + {0xd0a6, 0x8457}, /* U+0426 CYRILLIC CAPITAL LETTER TSE */ + {0xd0a7, 0x8458}, /* U+0427 CYRILLIC CAPITAL LETTER CHE */ + {0xd0a8, 0x8459}, /* U+0428 CYRILLIC CAPITAL LETTER SHA */ + {0xd0a9, 0x845a}, /* U+0429 CYRILLIC CAPITAL LETTER SHCHA */ + {0xd0aa, 0x845b}, /* U+042A CYRILLIC CAPITAL LETTER HARD SIGN */ + {0xd0ab, 0x845c}, /* U+042B CYRILLIC CAPITAL LETTER YERU */ + {0xd0ac, 0x845d}, /* U+042C CYRILLIC CAPITAL LETTER SOFT SIGN */ + {0xd0ad, 0x845e}, /* U+042D CYRILLIC CAPITAL LETTER E */ + {0xd0ae, 0x845f}, /* U+042E CYRILLIC CAPITAL LETTER YU */ + {0xd0af, 0x8460}, /* U+042F CYRILLIC CAPITAL LETTER YA */ + {0xd0b0, 0x8470}, /* U+0430 CYRILLIC SMALL LETTER A */ + {0xd0b1, 0x8471}, /* U+0431 CYRILLIC SMALL LETTER BE */ + {0xd0b2, 0x8472}, /* U+0432 CYRILLIC SMALL LETTER VE */ + {0xd0b3, 0x8473}, /* U+0433 CYRILLIC SMALL LETTER GHE */ + {0xd0b4, 0x8474}, /* U+0434 CYRILLIC SMALL LETTER DE */ + {0xd0b5, 0x8475}, /* U+0435 CYRILLIC SMALL LETTER IE */ + {0xd0b6, 0x8477}, /* U+0436 CYRILLIC SMALL LETTER ZHE */ + {0xd0b7, 0x8478}, /* U+0437 CYRILLIC SMALL LETTER ZE */ + {0xd0b8, 0x8479}, /* U+0438 CYRILLIC SMALL LETTER I */ + {0xd0b9, 0x847a}, /* U+0439 CYRILLIC SMALL LETTER SHORT I */ + {0xd0ba, 0x847b}, /* U+043A CYRILLIC SMALL LETTER KA */ + {0xd0bb, 0x847c}, /* U+043B CYRILLIC SMALL LETTER EL */ + {0xd0bc, 0x847d}, /* U+043C CYRILLIC SMALL LETTER EM */ + {0xd0bd, 0x847e}, /* U+043D CYRILLIC SMALL LETTER EN */ + {0xd0be, 0x8480}, /* U+043E CYRILLIC SMALL LETTER O */ + {0xd0bf, 0x8481}, /* U+043F CYRILLIC SMALL LETTER PE */ + {0xd180, 0x8482}, /* U+0440 CYRILLIC SMALL LETTER ER */ + {0xd181, 0x8483}, /* U+0441 CYRILLIC SMALL LETTER ES */ + {0xd182, 0x8484}, /* U+0442 CYRILLIC SMALL LETTER TE */ + {0xd183, 0x8485}, /* U+0443 CYRILLIC SMALL LETTER U */ + {0xd184, 0x8486}, /* U+0444 CYRILLIC SMALL LETTER EF */ + {0xd185, 0x8487}, /* U+0445 CYRILLIC SMALL LETTER HA */ + {0xd186, 0x8488}, /* U+0446 CYRILLIC SMALL LETTER TSE */ + {0xd187, 0x8489}, /* U+0447 CYRILLIC SMALL LETTER CHE */ + {0xd188, 0x848a}, /* U+0448 CYRILLIC SMALL LETTER SHA */ + {0xd189, 0x848b}, /* U+0449 CYRILLIC SMALL LETTER SHCHA */ + {0xd18a, 0x848c}, /* U+044A CYRILLIC SMALL LETTER HARD SIGN */ + {0xd18b, 0x848d}, /* U+044B CYRILLIC SMALL LETTER YERU */ + {0xd18c, 0x848e}, /* U+044C CYRILLIC SMALL LETTER SOFT SIGN */ + {0xd18d, 0x848f}, /* U+044D CYRILLIC SMALL LETTER E */ + {0xd18e, 0x8490}, /* U+044E CYRILLIC SMALL LETTER YU */ + {0xd18f, 0x8491}, /* U+044F CYRILLIC SMALL LETTER YA */ + {0xd191, 0x8476}, /* U+0451 CYRILLIC SMALL LETTER IO */ + {0xe1b8be, 0x84f0}, /* U+1E3E LATIN CAPITAL LETTER M WITH ACUTE [2000] */ + {0xe1b8bf, 0x84f1}, /* U+1E3F LATIN SMALL LETTER M WITH ACUTE [2000] */ + {0xe1bdb0, 0x8665}, /* U+1F70 GREEK SMALL LETTER ALPHA WITH VARIA [2000] */ + {0xe1bdb1, 0x8666}, /* U+1F71 GREEK SMALL LETTER ALPHA WITH OXIA [2000] */ + {0xe1bdb2, 0x866f}, /* U+1F72 GREEK SMALL LETTER EPSILON WITH VARIA [2000] */ + {0xe1bdb3, 0x8670}, /* U+1F73 GREEK SMALL LETTER EPSILON WITH OXIA [2000] */ + {0xe28090, 0x815d}, /* U+2010 HYPHEN */ + {0xe28093, 0x829c}, /* U+2013 EN DASH [2000] */ + {0xe28094, 0x815c}, /* U+2014 EM DASH Windows: U+2015 */ + {0xe28096, 0x8161}, /* U+2016 DOUBLE VERTICAL LINE Windows: U+2225 */ + {0xe28098, 0x8165}, /* U+2018 LEFT SINGLE QUOTATION MARK */ + {0xe28099, 0x8166}, /* U+2019 RIGHT SINGLE QUOTATION MARK */ + {0xe2809c, 0x8167}, /* U+201C LEFT DOUBLE QUOTATION MARK */ + {0xe2809d, 0x8168}, /* U+201D RIGHT DOUBLE QUOTATION MARK */ + {0xe280a0, 0x81f5}, /* U+2020 DAGGER [1983] */ + {0xe280a1, 0x81f6}, /* U+2021 DOUBLE DAGGER [1983] */ + {0xe280a2, 0x825f}, /* U+2022 BULLET [2000] */ + {0xe280a5, 0x8164}, /* U+2025 TWO DOT LEADER */ + {0xe280a6, 0x8163}, /* U+2026 HORIZONTAL ELLIPSIS */ + {0xe280b0, 0x81f1}, /* U+2030 PER MILLE SIGN [1983] */ + {0xe280b2, 0x818c}, /* U+2032 PRIME */ + {0xe280b3, 0x818d}, /* U+2033 DOUBLE PRIME */ + {0xe280bb, 0x81a6}, /* U+203B REFERENCE MARK */ + {0xe280bc, 0x84e9}, /* U+203C DOUBLE EXCLAMATION MARK [2000] */ + {0xe280be, 0x007e}, /* U+203E OVERLINE */ + {0xe280bf, 0x8677}, /* U+203F UNDERTIE [2000] */ + {0xe28182, 0x86fc}, /* U+2042 ASTERISM [2000] */ + {0xe28187, 0x84ea}, /* U+2047 DOUBLE QUESTION MARK [2000] [Unicode3.2] */ + {0xe28188, 0x84eb}, /* U+2048 QUESTION EXCLAMATION MARK [2000] */ + {0xe28189, 0x84ec}, /* U+2049 EXCLAMATION QUESTION MARK [2000] */ + {0xe28191, 0x86fb}, /* U+2051 TWO ASTERISKS ALIGNED VERTICALLY [2000] [Unicode3.2] */ + {0xe282ac, 0x8540}, /* U+20AC EURO SIGN [2000] */ + {0xe28483, 0x818e}, /* U+2103 DEGREE CELSIUS */ + {0xe2848f, 0x827c}, /* U+210F PLANCK CONSTANT OVER TWO PI [2000] */ + {0xe28493, 0x827e}, /* U+2113 SCRIPT SMALL L [2000] */ + {0xe28496, 0x8782}, /* U+2116 NUMERO SIGN [2000] */ + {0xe284a1, 0x8784}, /* U+2121 TELEPHONE SIGN [2000] */ + {0xe284a7, 0x8280}, /* U+2127 INVERTED OHM SIGN [2000] */ + {0xe284ab, 0x81f0}, /* U+212B ANGSTROM SIGN [1983] */ + {0xe284b5, 0x827b}, /* U+2135 ALEF SYMBOL [2000] */ + {0xe28593, 0x8498}, /* U+2153 VULGAR FRACTION ONE THIRD [2000] */ + {0xe28594, 0x8499}, /* U+2154 VULGAR FRACTION TWO THIRDS [2000] */ + {0xe28595, 0x849a}, /* U+2155 VULGAR FRACTION ONE FIFTH [2000] */ + {0xe285a0, 0x8754}, /* U+2160 ROMAN NUMERAL ONE [2000] */ + {0xe285a1, 0x8755}, /* U+2161 ROMAN NUMERAL TWO [2000] */ + {0xe285a2, 0x8756}, /* U+2162 ROMAN NUMERAL THREE [2000] */ + {0xe285a3, 0x8757}, /* U+2163 ROMAN NUMERAL FOUR [2000] */ + {0xe285a4, 0x8758}, /* U+2164 ROMAN NUMERAL FIVE [2000] */ + {0xe285a5, 0x8759}, /* U+2165 ROMAN NUMERAL SIX [2000] */ + {0xe285a6, 0x875a}, /* U+2166 ROMAN NUMERAL SEVEN [2000] */ + {0xe285a7, 0x875b}, /* U+2167 ROMAN NUMERAL EIGHT [2000] */ + {0xe285a8, 0x875c}, /* U+2168 ROMAN NUMERAL NINE [2000] */ + {0xe285a9, 0x875d}, /* U+2169 ROMAN NUMERAL TEN [2000] */ + {0xe285aa, 0x875e}, /* U+216A ROMAN NUMERAL ELEVEN [2000] */ + {0xe285ab, 0x8776}, /* U+216B ROMAN NUMERAL TWELVE [2000] */ + {0xe285b0, 0x86b3}, /* U+2170 SMALL ROMAN NUMERAL ONE [2000] */ + {0xe285b1, 0x86b4}, /* U+2171 SMALL ROMAN NUMERAL TWO [2000] */ + {0xe285b2, 0x86b5}, /* U+2172 SMALL ROMAN NUMERAL THREE [2000] */ + {0xe285b3, 0x86b6}, /* U+2173 SMALL ROMAN NUMERAL FOUR [2000] */ + {0xe285b4, 0x86b7}, /* U+2174 SMALL ROMAN NUMERAL FIVE [2000] */ + {0xe285b5, 0x86b8}, /* U+2175 SMALL ROMAN NUMERAL SIX [2000] */ + {0xe285b6, 0x86b9}, /* U+2176 SMALL ROMAN NUMERAL SEVEN [2000] */ + {0xe285b7, 0x86ba}, /* U+2177 SMALL ROMAN NUMERAL EIGHT [2000] */ + {0xe285b8, 0x86bb}, /* U+2178 SMALL ROMAN NUMERAL NINE [2000] */ + {0xe285b9, 0x86bc}, /* U+2179 SMALL ROMAN NUMERAL TEN [2000] */ + {0xe285ba, 0x86bd}, /* U+217A SMALL ROMAN NUMERAL ELEVEN [2000] */ + {0xe285bb, 0x86be}, /* U+217B SMALL ROMAN NUMERAL TWELVE [2000] */ + {0xe28690, 0x81a9}, /* U+2190 LEFTWARDS ARROW */ + {0xe28691, 0x81aa}, /* U+2191 UPWARDS ARROW */ + {0xe28692, 0x81a8}, /* U+2192 RIGHTWARDS ARROW */ + {0xe28693, 0x81ab}, /* U+2193 DOWNWARDS ARROW */ + {0xe28694, 0x81ef}, /* U+2194 LEFT RIGHT ARROW [2000] */ + {0xe28696, 0x8246}, /* U+2196 NORTH WEST ARROW [2000] */ + {0xe28697, 0x8244}, /* U+2197 NORTH EAST ARROW [2000] */ + {0xe28698, 0x8245}, /* U+2198 SOUTH EAST ARROW [2000] */ + {0xe28699, 0x8247}, /* U+2199 SOUTH WEST ARROW [2000] */ + {0xe28784, 0x8248}, /* U+21C4 RIGHTWARDS ARROW OVER LEFTWARDS ARROW [2000] */ + {0xe28792, 0x81cb}, /* U+21D2 RIGHTWARDS DOUBLE ARROW [1983] */ + {0xe28794, 0x81cc}, /* U+21D4 LEFT RIGHT DOUBLE ARROW [1983] */ + {0xe287a6, 0x824a}, /* U+21E6 LEFTWARDS WHITE ARROW [2000] */ + {0xe287a7, 0x824b}, /* U+21E7 UPWARDS WHITE ARROW [2000] */ + {0xe287a8, 0x8249}, /* U+21E8 RIGHTWARDS WHITE ARROW [2000] */ + {0xe287a9, 0x824c}, /* U+21E9 DOWNWARDS WHITE ARROW [2000] */ + {0xe28880, 0x81cd}, /* U+2200 FOR ALL [1983] */ + {0xe28882, 0x81dd}, /* U+2202 PARTIAL DIFFERENTIAL [1983] */ + {0xe28883, 0x81ce}, /* U+2203 THERE EXISTS [1983] */ + {0xe28885, 0x81c5}, /* U+2205 EMPTY SET [2000] */ + {0xe28887, 0x81de}, /* U+2207 NABLA [1983] */ + {0xe28888, 0x81b8}, /* U+2208 ELEMENT OF [1983] */ + {0xe28889, 0x81c4}, /* U+2209 NOT AN ELEMENT OF [2000] */ + {0xe2888b, 0x81b9}, /* U+220B CONTAINS AS MEMBER [1983] */ + {0xe28892, 0x817c}, /* U+2212 MINUS SIGN Windows: U+FF0D */ + {0xe28893, 0x827a}, /* U+2213 MINUS-OR-PLUS SIGN [2000] */ + {0xe2889a, 0x81e3}, /* U+221A SQUARE ROOT [1983] */ + {0xe2889d, 0x81e5}, /* U+221D PROPORTIONAL TO [1983] */ + {0xe2889e, 0x8187}, /* U+221E INFINITY */ + {0xe2889f, 0x8798}, /* U+221F RIGHT ANGLE [2000] */ + {0xe288a0, 0x81da}, /* U+2220 ANGLE [1983] */ + {0xe288a5, 0x81d2}, /* U+2225 PARALLEL TO [2000] */ + {0xe288a6, 0x81d3}, /* U+2226 NOT PARALLEL TO [2000] */ + {0xe288a7, 0x81c8}, /* U+2227 LOGICAL AND [1983] */ + {0xe288a8, 0x81c9}, /* U+2228 LOGICAL OR [1983] */ + {0xe288a9, 0x81bf}, /* U+2229 INTERSECTION [1983] */ + {0xe288aa, 0x81be}, /* U+222A UNION [1983] */ + {0xe288ab, 0x81e7}, /* U+222B INTEGRAL [1983] */ + {0xe288ac, 0x81e8}, /* U+222C DOUBLE INTEGRAL [1983] */ + {0xe288ae, 0x8793}, /* U+222E CONTOUR INTEGRAL [2000] */ + {0xe288b4, 0x8188}, /* U+2234 THEREFORE */ + {0xe288b5, 0x81e6}, /* U+2235 BECAUSE [1983] */ + {0xe288bd, 0x81e4}, /* U+223D REVERSED TILDE [1983] */ + {0xe28983, 0x81ea}, /* U+2243 ASYMPTOTICALLY EQUAL TO [2000] */ + {0xe28985, 0x81eb}, /* U+2245 APPROXIMATELY EQUAL TO [2000] */ + {0xe28988, 0x81ec}, /* U+2248 ALMOST EQUAL TO [2000] */ + {0xe28992, 0x81e0}, /* U+2252 APPROXIMATELY EQUAL TO OR THE IMAGE OF [1983] */ + {0xe289a0, 0x8182}, /* U+2260 NOT EQUAL TO */ + {0xe289a1, 0x81df}, /* U+2261 IDENTICAL TO [1983] */ + {0xe289a2, 0x81e9}, /* U+2262 NOT IDENTICAL TO [2000] */ + {0xe289a6, 0x8185}, /* U+2266 LESS-THAN OVER EQUAL TO */ + {0xe289a7, 0x8186}, /* U+2267 GREATER-THAN OVER EQUAL TO */ + {0xe289aa, 0x81e1}, /* U+226A MUCH LESS-THAN [1983] */ + {0xe289ab, 0x81e2}, /* U+226B MUCH GREATER-THAN [1983] */ + {0xe289b6, 0x81ed}, /* U+2276 LESS-THAN OR GREATER-THAN [2000] */ + {0xe289b7, 0x81ee}, /* U+2277 GREATER-THAN OR LESS-THAN [2000] */ + {0xe28a82, 0x81bc}, /* U+2282 SUBSET OF [1983] */ + {0xe28a83, 0x81bd}, /* U+2283 SUPERSET OF [1983] */ + {0xe28a84, 0x81c0}, /* U+2284 NOT A SUBSET OF [2000] */ + {0xe28a85, 0x81c1}, /* U+2285 NOT A SUPERSET OF [2000] */ + {0xe28a86, 0x81ba}, /* U+2286 SUBSET OF OR EQUAL TO [1983] */ + {0xe28a87, 0x81bb}, /* U+2287 SUPERSET OF OR EQUAL TO [1983] */ + {0xe28a8a, 0x81c2}, /* U+228A SUBSET OF WITH NOT EQUAL TO [2000] */ + {0xe28a8b, 0x81c3}, /* U+228B SUPERSET OF WITH NOT EQUAL TO [2000] */ + {0xe28a95, 0x81cf}, /* U+2295 CIRCLED PLUS [2000] */ + {0xe28a96, 0x81d0}, /* U+2296 CIRCLED MINUS [2000] */ + {0xe28a97, 0x81d1}, /* U+2297 CIRCLED TIMES [2000] */ + {0xe28aa5, 0x81db}, /* U+22A5 UP TACK [1983] */ + {0xe28abf, 0x8799}, /* U+22BF RIGHT TRIANGLE [2000] */ + {0xe28b9a, 0x8496}, /* U+22DA LESS-THAN EQUAL TO OR GREATER-THAN [2000] */ + {0xe28b9b, 0x8497}, /* U+22DB GREATER-THAN EQUAL TO OR LESS-THAN [2000] */ + {0xe28c85, 0x81c6}, /* U+2305 PROJECTIVE [2000] */ + {0xe28c86, 0x81c7}, /* U+2306 PERSPECTIVE [2000] */ + {0xe28c92, 0x81dc}, /* U+2312 ARC [1983] */ + {0xe28c98, 0x849c}, /* U+2318 PLACE OF INTEREST SIGN [2000] */ + {0xe28ebe, 0x8461}, /* U+23BE DENTISTRY SYMBOL LIGHT VERTICAL AND TOP RIGHT [2000] [Unicode3.2] */ + {0xe28ebf, 0x8462}, /* U+23BF DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM RIGHT [2000] [Unicode3.2] */ + {0xe28f80, 0x8463}, /* U+23C0 DENTISTRY SYMBOL LIGHT VERTICAL WITH CIRCLE [2000] [Unicode3.2] */ + {0xe28f81, 0x8464}, /* U+23C1 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH CIRCLE [2000] [Unicode3.2] */ + {0xe28f82, 0x8465}, /* U+23C2 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLE [2000] [Unicode3.2] */ + {0xe28f83, 0x8466}, /* U+23C3 DENTISTRY SYMBOL LIGHT VERTICAL WITH TRIANGLE [2000] [Unicode3.2] */ + {0xe28f84, 0x8467}, /* U+23C4 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH TRIANGLE [2000] [Unicode3.2] */ + {0xe28f85, 0x8468}, /* U+23C5 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH TRIANGLE [2000] [Unicode3.2] */ + {0xe28f86, 0x8469}, /* U+23C6 DENTISTRY SYMBOL LIGHT VERTICAL AND WAVE [2000] [Unicode3.2] */ + {0xe28f87, 0x846a}, /* U+23C7 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH WAVE [2000] [Unicode3.2] */ + {0xe28f88, 0x846b}, /* U+23C8 DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH WAVE [2000] [Unicode3.2] */ + {0xe28f89, 0x846c}, /* U+23C9 DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL [2000] [Unicode3.2] */ + {0xe28f8a, 0x846d}, /* U+23CA DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL [2000] [Unicode3.2] */ + {0xe28f8b, 0x846e}, /* U+23CB DENTISTRY SYMBOL LIGHT VERTICAL AND TOP LEFT [2000] [Unicode3.2] */ + {0xe28f8c, 0x846f}, /* U+23CC DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM LEFT [2000] [Unicode3.2] */ + {0xe28f8e, 0x849e}, /* U+23CE RETURN SYMBOL [2000] [Unicode3.2] */ + {0xe290a3, 0x849d}, /* U+2423 OPEN BOX [2000] */ + {0xe291a0, 0x8740}, /* U+2460 CIRCLED DIGIT ONE [2000] */ + {0xe291a1, 0x8741}, /* U+2461 CIRCLED DIGIT TWO [2000] */ + {0xe291a2, 0x8742}, /* U+2462 CIRCLED DIGIT THREE [2000] */ + {0xe291a3, 0x8743}, /* U+2463 CIRCLED DIGIT FOUR [2000] */ + {0xe291a4, 0x8744}, /* U+2464 CIRCLED DIGIT FIVE [2000] */ + {0xe291a5, 0x8745}, /* U+2465 CIRCLED DIGIT SIX [2000] */ + {0xe291a6, 0x8746}, /* U+2466 CIRCLED DIGIT SEVEN [2000] */ + {0xe291a7, 0x8747}, /* U+2467 CIRCLED DIGIT EIGHT [2000] */ + {0xe291a8, 0x8748}, /* U+2468 CIRCLED DIGIT NINE [2000] */ + {0xe291a9, 0x8749}, /* U+2469 CIRCLED NUMBER TEN [2000] */ + {0xe291aa, 0x874a}, /* U+246A CIRCLED NUMBER ELEVEN [2000] */ + {0xe291ab, 0x874b}, /* U+246B CIRCLED NUMBER TWELVE [2000] */ + {0xe291ac, 0x874c}, /* U+246C CIRCLED NUMBER THIRTEEN [2000] */ + {0xe291ad, 0x874d}, /* U+246D CIRCLED NUMBER FOURTEEN [2000] */ + {0xe291ae, 0x874e}, /* U+246E CIRCLED NUMBER FIFTEEN [2000] */ + {0xe291af, 0x874f}, /* U+246F CIRCLED NUMBER SIXTEEN [2000] */ + {0xe291b0, 0x8750}, /* U+2470 CIRCLED NUMBER SEVENTEEN [2000] */ + {0xe291b1, 0x8751}, /* U+2471 CIRCLED NUMBER EIGHTEEN [2000] */ + {0xe291b2, 0x8752}, /* U+2472 CIRCLED NUMBER NINETEEN [2000] */ + {0xe291b3, 0x8753}, /* U+2473 CIRCLED NUMBER TWENTY [2000] */ + {0xe29390, 0x86bf}, /* U+24D0 CIRCLED LATIN SMALL LETTER A [2000] */ + {0xe29391, 0x86c0}, /* U+24D1 CIRCLED LATIN SMALL LETTER B [2000] */ + {0xe29392, 0x86c1}, /* U+24D2 CIRCLED LATIN SMALL LETTER C [2000] */ + {0xe29393, 0x86c2}, /* U+24D3 CIRCLED LATIN SMALL LETTER D [2000] */ + {0xe29394, 0x86c3}, /* U+24D4 CIRCLED LATIN SMALL LETTER E [2000] */ + {0xe29395, 0x86c4}, /* U+24D5 CIRCLED LATIN SMALL LETTER F [2000] */ + {0xe29396, 0x86c5}, /* U+24D6 CIRCLED LATIN SMALL LETTER G [2000] */ + {0xe29397, 0x86c6}, /* U+24D7 CIRCLED LATIN SMALL LETTER H [2000] */ + {0xe29398, 0x86c7}, /* U+24D8 CIRCLED LATIN SMALL LETTER I [2000] */ + {0xe29399, 0x86c8}, /* U+24D9 CIRCLED LATIN SMALL LETTER J [2000] */ + {0xe2939a, 0x86c9}, /* U+24DA CIRCLED LATIN SMALL LETTER K [2000] */ + {0xe2939b, 0x86ca}, /* U+24DB CIRCLED LATIN SMALL LETTER L [2000] */ + {0xe2939c, 0x86cb}, /* U+24DC CIRCLED LATIN SMALL LETTER M [2000] */ + {0xe2939d, 0x86cc}, /* U+24DD CIRCLED LATIN SMALL LETTER N [2000] */ + {0xe2939e, 0x86cd}, /* U+24DE CIRCLED LATIN SMALL LETTER O [2000] */ + {0xe2939f, 0x86ce}, /* U+24DF CIRCLED LATIN SMALL LETTER P [2000] */ + {0xe293a0, 0x86cf}, /* U+24E0 CIRCLED LATIN SMALL LETTER Q [2000] */ + {0xe293a1, 0x86d0}, /* U+24E1 CIRCLED LATIN SMALL LETTER R [2000] */ + {0xe293a2, 0x86d1}, /* U+24E2 CIRCLED LATIN SMALL LETTER S [2000] */ + {0xe293a3, 0x86d2}, /* U+24E3 CIRCLED LATIN SMALL LETTER T [2000] */ + {0xe293a4, 0x86d3}, /* U+24E4 CIRCLED LATIN SMALL LETTER U [2000] */ + {0xe293a5, 0x86d4}, /* U+24E5 CIRCLED LATIN SMALL LETTER V [2000] */ + {0xe293a6, 0x86d5}, /* U+24E6 CIRCLED LATIN SMALL LETTER W [2000] */ + {0xe293a7, 0x86d6}, /* U+24E7 CIRCLED LATIN SMALL LETTER X [2000] */ + {0xe293a8, 0x86d7}, /* U+24E8 CIRCLED LATIN SMALL LETTER Y [2000] */ + {0xe293a9, 0x86d8}, /* U+24E9 CIRCLED LATIN SMALL LETTER Z [2000] */ + {0xe293ab, 0x86a9}, /* U+24EB NEGATIVE CIRCLED NUMBER ELEVEN [2000] [Unicode3.2] */ + {0xe293ac, 0x86aa}, /* U+24EC NEGATIVE CIRCLED NUMBER TWELVE [2000] [Unicode3.2] */ + {0xe293ad, 0x86ab}, /* U+24ED NEGATIVE CIRCLED NUMBER THIRTEEN [2000] [Unicode3.2] */ + {0xe293ae, 0x86ac}, /* U+24EE NEGATIVE CIRCLED NUMBER FOURTEEN [2000] [Unicode3.2] */ + {0xe293af, 0x86ad}, /* U+24EF NEGATIVE CIRCLED NUMBER FIFTEEN [2000] [Unicode3.2] */ + {0xe293b0, 0x86ae}, /* U+24F0 NEGATIVE CIRCLED NUMBER SIXTEEN [2000] [Unicode3.2] */ + {0xe293b1, 0x86af}, /* U+24F1 NEGATIVE CIRCLED NUMBER SEVENTEEN [2000] [Unicode3.2] */ + {0xe293b2, 0x86b0}, /* U+24F2 NEGATIVE CIRCLED NUMBER EIGHTEEN [2000] [Unicode3.2] */ + {0xe293b3, 0x86b1}, /* U+24F3 NEGATIVE CIRCLED NUMBER NINETEEN [2000] [Unicode3.2] */ + {0xe293b4, 0x86b2}, /* U+24F4 NEGATIVE CIRCLED NUMBER TWENTY [2000] [Unicode3.2] */ + {0xe293b5, 0x83d8}, /* U+24F5 DOUBLE CIRCLED DIGIT ONE [2000] [Unicode3.2] */ + {0xe293b6, 0x83d9}, /* U+24F6 DOUBLE CIRCLED DIGIT TWO [2000] [Unicode3.2] */ + {0xe293b7, 0x83da}, /* U+24F7 DOUBLE CIRCLED DIGIT THREE [2000] [Unicode3.2] */ + {0xe293b8, 0x83db}, /* U+24F8 DOUBLE CIRCLED DIGIT FOUR [2000] [Unicode3.2] */ + {0xe293b9, 0x83dc}, /* U+24F9 DOUBLE CIRCLED DIGIT FIVE [2000] [Unicode3.2] */ + {0xe293ba, 0x83dd}, /* U+24FA DOUBLE CIRCLED DIGIT SIX [2000] [Unicode3.2] */ + {0xe293bb, 0x83de}, /* U+24FB DOUBLE CIRCLED DIGIT SEVEN [2000] [Unicode3.2] */ + {0xe293bc, 0x83df}, /* U+24FC DOUBLE CIRCLED DIGIT EIGHT [2000] [Unicode3.2] */ + {0xe293bd, 0x83e0}, /* U+24FD DOUBLE CIRCLED DIGIT NINE [2000] [Unicode3.2] */ + {0xe293be, 0x83e1}, /* U+24FE DOUBLE CIRCLED NUMBER TEN [2000] [Unicode3.2] */ + {0xe29480, 0x849f}, /* U+2500 BOX DRAWINGS LIGHT HORIZONTAL [1983] */ + {0xe29481, 0x84aa}, /* U+2501 BOX DRAWINGS HEAVY HORIZONTAL [1983] */ + {0xe29482, 0x84a0}, /* U+2502 BOX DRAWINGS LIGHT VERTICAL [1983] */ + {0xe29483, 0x84ab}, /* U+2503 BOX DRAWINGS HEAVY VERTICAL [1983] */ + {0xe2948c, 0x84a1}, /* U+250C BOX DRAWINGS LIGHT DOWN AND RIGHT [1983] */ + {0xe2948f, 0x84ac}, /* U+250F BOX DRAWINGS HEAVY DOWN AND RIGHT [1983] */ + {0xe29490, 0x84a2}, /* U+2510 BOX DRAWINGS LIGHT DOWN AND LEFT [1983] */ + {0xe29493, 0x84ad}, /* U+2513 BOX DRAWINGS HEAVY DOWN AND LEFT [1983] */ + {0xe29494, 0x84a4}, /* U+2514 BOX DRAWINGS LIGHT UP AND RIGHT [1983] */ + {0xe29497, 0x84af}, /* U+2517 BOX DRAWINGS HEAVY UP AND RIGHT [1983] */ + {0xe29498, 0x84a3}, /* U+2518 BOX DRAWINGS LIGHT UP AND LEFT [1983] */ + {0xe2949b, 0x84ae}, /* U+251B BOX DRAWINGS HEAVY UP AND LEFT [1983] */ + {0xe2949c, 0x84a5}, /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT [1983] */ + {0xe2949d, 0x84ba}, /* U+251D BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY [1983] */ + {0xe294a0, 0x84b5}, /* U+2520 BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT [1983] */ + {0xe294a3, 0x84b0}, /* U+2523 BOX DRAWINGS HEAVY VERTICAL AND RIGHT [1983] */ + {0xe294a4, 0x84a7}, /* U+2524 BOX DRAWINGS LIGHT VERTICAL AND LEFT [1983] */ + {0xe294a5, 0x84bc}, /* U+2525 BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY [1983] */ + {0xe294a8, 0x84b7}, /* U+2528 BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT [1983] */ + {0xe294ab, 0x84b2}, /* U+252B BOX DRAWINGS HEAVY VERTICAL AND LEFT [1983] */ + {0xe294ac, 0x84a6}, /* U+252C BOX DRAWINGS LIGHT DOWN AND HORIZONTAL [1983] */ + {0xe294af, 0x84b6}, /* U+252F BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY [1983] */ + {0xe294b0, 0x84bb}, /* U+2530 BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT [1983] */ + {0xe294b3, 0x84b1}, /* U+2533 BOX DRAWINGS HEAVY DOWN AND HORIZONTAL [1983] */ + {0xe294b4, 0x84a8}, /* U+2534 BOX DRAWINGS LIGHT UP AND HORIZONTAL [1983] */ + {0xe294b7, 0x84b8}, /* U+2537 BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY [1983] */ + {0xe294b8, 0x84bd}, /* U+2538 BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT [1983] */ + {0xe294bb, 0x84b3}, /* U+253B BOX DRAWINGS HEAVY UP AND HORIZONTAL [1983] */ + {0xe294bc, 0x84a9}, /* U+253C BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL [1983] */ + {0xe294bf, 0x84b9}, /* U+253F BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY [1983] */ + {0xe29582, 0x84be}, /* U+2542 BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT [1983] */ + {0xe2958b, 0x84b4}, /* U+254B BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL [1983] */ + {0xe296a0, 0x81a1}, /* U+25A0 BLACK SQUARE */ + {0xe296a1, 0x81a0}, /* U+25A1 WHITE SQUARE */ + {0xe296b1, 0x83eb}, /* U+25B1 WHITE PARALLELOGRAM [2000] */ + {0xe296b2, 0x81a3}, /* U+25B2 BLACK UP-POINTING TRIANGLE */ + {0xe296b3, 0x81a2}, /* U+25B3 WHITE UP-POINTING TRIANGLE */ + {0xe296b6, 0x8241}, /* U+25B6 BLACK RIGHT-POINTING TRIANGLE [2000] */ + {0xe296b7, 0x8240}, /* U+25B7 WHITE RIGHT-POINTING TRIANGLE [2000] */ + {0xe296bc, 0x81a5}, /* U+25BC BLACK DOWN-POINTING TRIANGLE */ + {0xe296bd, 0x81a4}, /* U+25BD WHITE DOWN-POINTING TRIANGLE */ + {0xe29780, 0x8243}, /* U+25C0 BLACK LEFT-POINTING TRIANGLE [2000] */ + {0xe29781, 0x8242}, /* U+25C1 WHITE LEFT-POINTING TRIANGLE [2000] */ + {0xe29786, 0x819f}, /* U+25C6 BLACK DIAMOND */ + {0xe29787, 0x819e}, /* U+25C7 WHITE DIAMOND */ + {0xe29789, 0x825a}, /* U+25C9 FISHEYE [2000] */ + {0xe2978b, 0x819b}, /* U+25CB WHITE CIRCLE */ + {0xe2978e, 0x819d}, /* U+25CE BULLSEYE */ + {0xe2978f, 0x819c}, /* U+25CF BLACK CIRCLE */ + {0xe29790, 0x84e5}, /* U+25D0 CIRCLE WITH LEFT HALF BLACK [2000] */ + {0xe29791, 0x84e6}, /* U+25D1 CIRCLE WITH RIGHT HALF BLACK [2000] */ + {0xe29792, 0x84e7}, /* U+25D2 CIRCLE WITH LOWER HALF BLACK [2000] */ + {0xe29793, 0x84e8}, /* U+25D3 CIRCLE WITH UPPER HALF BLACK [2000] */ + {0xe297a6, 0x825e}, /* U+25E6 WHITE BULLET [2000] */ + {0xe297af, 0x81fc}, /* U+25EF LARGE CIRCLE [1983] */ + {0xe29880, 0x83e6}, /* U+2600 BLACK SUN WITH RAYS [2000] */ + {0xe29881, 0x83e7}, /* U+2601 CLOUD [2000] */ + {0xe29882, 0x83e8}, /* U+2602 UMBRELLA [2000] */ + {0xe29883, 0x83e9}, /* U+2603 SNOWMAN [2000] */ + {0xe29885, 0x819a}, /* U+2605 BLACK STAR */ + {0xe29886, 0x8199}, /* U+2606 WHITE STAR */ + {0xe2988e, 0x83e5}, /* U+260E BLACK TELEPHONE [2000] */ + {0xe29896, 0x83e2}, /* U+2616 WHITE SHOGI PIECE [2000] [Unicode3.2] */ + {0xe29897, 0x83e3}, /* U+2617 BLACK SHOGI PIECE [2000] [Unicode3.2] */ + {0xe2989e, 0x879e}, /* U+261E WHITE RIGHT POINTING INDEX [2000] */ + {0xe29980, 0x818a}, /* U+2640 FEMALE SIGN */ + {0xe29982, 0x8189}, /* U+2642 MALE SIGN */ + {0xe299a0, 0x83b8}, /* U+2660 BLACK SPADE SUIT [2000] */ + {0xe299a1, 0x83bb}, /* U+2661 WHITE HEART SUIT [2000] */ + {0xe299a2, 0x83b9}, /* U+2662 WHITE DIAMOND SUIT [2000] */ + {0xe299a3, 0x83be}, /* U+2663 BLACK CLUB SUIT [2000] */ + {0xe299a4, 0x83b7}, /* U+2664 WHITE SPADE SUIT [2000] */ + {0xe299a5, 0x83bc}, /* U+2665 BLACK HEART SUIT [2000] */ + {0xe299a6, 0x83ba}, /* U+2666 BLACK DIAMOND SUIT [2000] */ + {0xe299a7, 0x83bd}, /* U+2667 WHITE CLUB SUIT [2000] */ + {0xe299a8, 0x83ea}, /* U+2668 HOT SPRINGS [2000] */ + {0xe299a9, 0x81fb}, /* U+2669 QUARTER NOTE [2000] */ + {0xe299aa, 0x81f4}, /* U+266A EIGHTH NOTE [1983] */ + {0xe299ab, 0x81f9}, /* U+266B BEAMED EIGHTH NOTES [2000] */ + {0xe299ac, 0x81fa}, /* U+266C BEAMED SIXTEENTH NOTES [2000] */ + {0xe299ad, 0x81f3}, /* U+266D MUSIC FLAT SIGN [1983] */ + {0xe299ae, 0x81f8}, /* U+266E MUSIC NATURAL SIGN [2000] */ + {0xe299af, 0x81f2}, /* U+266F MUSIC SHARP SIGN [1983] */ + {0xe29c93, 0x849b}, /* U+2713 CHECK MARK [2000] */ + {0xe29d96, 0x879d}, /* U+2756 BLACK DIAMOND MINUS WHITE X [2000] */ + {0xe29db6, 0x869f}, /* U+2776 DINGBAT NEGATIVE CIRCLED DIGIT ONE [2000] */ + {0xe29db7, 0x86a0}, /* U+2777 DINGBAT NEGATIVE CIRCLED DIGIT TWO [2000] */ + {0xe29db8, 0x86a1}, /* U+2778 DINGBAT NEGATIVE CIRCLED DIGIT THREE [2000] */ + {0xe29db9, 0x86a2}, /* U+2779 DINGBAT NEGATIVE CIRCLED DIGIT FOUR [2000] */ + {0xe29dba, 0x86a3}, /* U+277A DINGBAT NEGATIVE CIRCLED DIGIT FIVE [2000] */ + {0xe29dbb, 0x86a4}, /* U+277B DINGBAT NEGATIVE CIRCLED DIGIT SIX [2000] */ + {0xe29dbc, 0x86a5}, /* U+277C DINGBAT NEGATIVE CIRCLED DIGIT SEVEN [2000] */ + {0xe29dbd, 0x86a6}, /* U+277D DINGBAT NEGATIVE CIRCLED DIGIT EIGHT [2000] */ + {0xe29dbe, 0x86a7}, /* U+277E DINGBAT NEGATIVE CIRCLED DIGIT NINE [2000] */ + {0xe29dbf, 0x86a8}, /* U+277F DINGBAT NEGATIVE CIRCLED NUMBER TEN [2000] */ + {0xe2a4b4, 0x824d}, /* U+2934 ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS [2000] [Unicode3.2] */ + {0xe2a4b5, 0x824e}, /* U+2935 ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS [2000] [Unicode3.2] */ + {0xe2a6bf, 0x8259}, /* U+29BF CIRCLED BULLET [2000] [Unicode3.2] */ + {0xe2a7ba, 0x829d}, /* U+29FA DOUBLE PLUS [2000] [Unicode3.2] */ + {0xe2a7bb, 0x829e}, /* U+29FB TRIPLE PLUS [2000] [Unicode3.2] */ + {0xe38080, 0x8140}, /* U+3000 IDEOGRAPHIC SPACE */ + {0xe38081, 0x8141}, /* U+3001 IDEOGRAPHIC COMMA */ + {0xe38082, 0x8142}, /* U+3002 IDEOGRAPHIC FULL STOP */ + {0xe38083, 0x8156}, /* U+3003 DITTO MARK */ + {0xe38085, 0x8158}, /* U+3005 IDEOGRAPHIC ITERATION MARK */ + {0xe38086, 0x8159}, /* U+3006 IDEOGRAPHIC CLOSING MARK */ + {0xe38087, 0x815a}, /* U+3007 IDEOGRAPHIC NUMBER ZERO */ + {0xe38088, 0x8171}, /* U+3008 LEFT ANGLE BRACKET */ + {0xe38089, 0x8172}, /* U+3009 RIGHT ANGLE BRACKET */ + {0xe3808a, 0x8173}, /* U+300A LEFT DOUBLE ANGLE BRACKET */ + {0xe3808b, 0x8174}, /* U+300B RIGHT DOUBLE ANGLE BRACKET */ + {0xe3808c, 0x8175}, /* U+300C LEFT CORNER BRACKET */ + {0xe3808d, 0x8176}, /* U+300D RIGHT CORNER BRACKET */ + {0xe3808e, 0x8177}, /* U+300E LEFT WHITE CORNER BRACKET */ + {0xe3808f, 0x8178}, /* U+300F RIGHT WHITE CORNER BRACKET */ + {0xe38090, 0x8179}, /* U+3010 LEFT BLACK LENTICULAR BRACKET */ + {0xe38091, 0x817a}, /* U+3011 RIGHT BLACK LENTICULAR BRACKET */ + {0xe38092, 0x81a7}, /* U+3012 POSTAL MARK */ + {0xe38093, 0x81ac}, /* U+3013 GETA MARK */ + {0xe38094, 0x816b}, /* U+3014 LEFT TORTOISE SHELL BRACKET */ + {0xe38095, 0x816c}, /* U+3015 RIGHT TORTOISE SHELL BRACKET */ + {0xe38096, 0x81d8}, /* U+3016 LEFT WHITE LENTICULAR BRACKET [2000] */ + {0xe38097, 0x81d9}, /* U+3017 RIGHT WHITE LENTICULAR BRACKET [2000] */ + {0xe38098, 0x81d6}, /* U+3018 LEFT WHITE TORTOISE SHELL BRACKET [2000] */ + {0xe38099, 0x81d7}, /* U+3019 RIGHT WHITE TORTOISE SHELL BRACKET [2000] */ + {0xe3809c, 0x8160}, /* U+301C WAVE DASH Windows: U+FF5E */ + {0xe3809d, 0x8780}, /* U+301D REVERSED DOUBLE PRIME QUOTATION MARK [2000] */ + {0xe3809f, 0x8781}, /* U+301F LOW DOUBLE PRIME QUOTATION MARK [2000] */ + {0xe380a0, 0x83e4}, /* U+3020 POSTAL MARK FACE [2000] */ + {0xe380b3, 0x81b1}, /* U+3033 VERTICAL KANA REPEAT MARK UPPER HALF [2000] */ + {0xe380b4, 0x81b2}, /* U+3034 VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF [2000] */ + {0xe380b5, 0x81b3}, /* U+3035 VERTICAL KANA REPEAT MARK LOWER HALF [2000] */ + {0xe380bb, 0x81b4}, /* U+303B VERTICAL IDEOGRAPHIC ITERATION MARK [2000] [Unicode3.2] */ + {0xe380bc, 0x81b5}, /* U+303C MASU MARK [2000] [Unicode3.2] */ + {0xe380bd, 0x825b}, /* U+303D PART ALTERNATION MARK [2000] [Unicode3.2] */ + {0xe38181, 0x829f}, /* U+3041 HIRAGANA LETTER SMALL A */ + {0xe38182, 0x82a0}, /* U+3042 HIRAGANA LETTER A */ + {0xe38183, 0x82a1}, /* U+3043 HIRAGANA LETTER SMALL I */ + {0xe38184, 0x82a2}, /* U+3044 HIRAGANA LETTER I */ + {0xe38185, 0x82a3}, /* U+3045 HIRAGANA LETTER SMALL U */ + {0xe38186, 0x82a4}, /* U+3046 HIRAGANA LETTER U */ + {0xe38187, 0x82a5}, /* U+3047 HIRAGANA LETTER SMALL E */ + {0xe38188, 0x82a6}, /* U+3048 HIRAGANA LETTER E */ + {0xe38189, 0x82a7}, /* U+3049 HIRAGANA LETTER SMALL O */ + {0xe3818a, 0x82a8}, /* U+304A HIRAGANA LETTER O */ + {0xe3818b, 0x82a9}, /* U+304B HIRAGANA LETTER KA */ + {0xe3818c, 0x82aa}, /* U+304C HIRAGANA LETTER GA */ + {0xe3818d, 0x82ab}, /* U+304D HIRAGANA LETTER KI */ + {0xe3818e, 0x82ac}, /* U+304E HIRAGANA LETTER GI */ + {0xe3818f, 0x82ad}, /* U+304F HIRAGANA LETTER KU */ + {0xe38190, 0x82ae}, /* U+3050 HIRAGANA LETTER GU */ + {0xe38191, 0x82af}, /* U+3051 HIRAGANA LETTER KE */ + {0xe38192, 0x82b0}, /* U+3052 HIRAGANA LETTER GE */ + {0xe38193, 0x82b1}, /* U+3053 HIRAGANA LETTER KO */ + {0xe38194, 0x82b2}, /* U+3054 HIRAGANA LETTER GO */ + {0xe38195, 0x82b3}, /* U+3055 HIRAGANA LETTER SA */ + {0xe38196, 0x82b4}, /* U+3056 HIRAGANA LETTER ZA */ + {0xe38197, 0x82b5}, /* U+3057 HIRAGANA LETTER SI */ + {0xe38198, 0x82b6}, /* U+3058 HIRAGANA LETTER ZI */ + {0xe38199, 0x82b7}, /* U+3059 HIRAGANA LETTER SU */ + {0xe3819a, 0x82b8}, /* U+305A HIRAGANA LETTER ZU */ + {0xe3819b, 0x82b9}, /* U+305B HIRAGANA LETTER SE */ + {0xe3819c, 0x82ba}, /* U+305C HIRAGANA LETTER ZE */ + {0xe3819d, 0x82bb}, /* U+305D HIRAGANA LETTER SO */ + {0xe3819e, 0x82bc}, /* U+305E HIRAGANA LETTER ZO */ + {0xe3819f, 0x82bd}, /* U+305F HIRAGANA LETTER TA */ + {0xe381a0, 0x82be}, /* U+3060 HIRAGANA LETTER DA */ + {0xe381a1, 0x82bf}, /* U+3061 HIRAGANA LETTER TI */ + {0xe381a2, 0x82c0}, /* U+3062 HIRAGANA LETTER DI */ + {0xe381a3, 0x82c1}, /* U+3063 HIRAGANA LETTER SMALL TU */ + {0xe381a4, 0x82c2}, /* U+3064 HIRAGANA LETTER TU */ + {0xe381a5, 0x82c3}, /* U+3065 HIRAGANA LETTER DU */ + {0xe381a6, 0x82c4}, /* U+3066 HIRAGANA LETTER TE */ + {0xe381a7, 0x82c5}, /* U+3067 HIRAGANA LETTER DE */ + {0xe381a8, 0x82c6}, /* U+3068 HIRAGANA LETTER TO */ + {0xe381a9, 0x82c7}, /* U+3069 HIRAGANA LETTER DO */ + {0xe381aa, 0x82c8}, /* U+306A HIRAGANA LETTER NA */ + {0xe381ab, 0x82c9}, /* U+306B HIRAGANA LETTER NI */ + {0xe381ac, 0x82ca}, /* U+306C HIRAGANA LETTER NU */ + {0xe381ad, 0x82cb}, /* U+306D HIRAGANA LETTER NE */ + {0xe381ae, 0x82cc}, /* U+306E HIRAGANA LETTER NO */ + {0xe381af, 0x82cd}, /* U+306F HIRAGANA LETTER HA */ + {0xe381b0, 0x82ce}, /* U+3070 HIRAGANA LETTER BA */ + {0xe381b1, 0x82cf}, /* U+3071 HIRAGANA LETTER PA */ + {0xe381b2, 0x82d0}, /* U+3072 HIRAGANA LETTER HI */ + {0xe381b3, 0x82d1}, /* U+3073 HIRAGANA LETTER BI */ + {0xe381b4, 0x82d2}, /* U+3074 HIRAGANA LETTER PI */ + {0xe381b5, 0x82d3}, /* U+3075 HIRAGANA LETTER HU */ + {0xe381b6, 0x82d4}, /* U+3076 HIRAGANA LETTER BU */ + {0xe381b7, 0x82d5}, /* U+3077 HIRAGANA LETTER PU */ + {0xe381b8, 0x82d6}, /* U+3078 HIRAGANA LETTER HE */ + {0xe381b9, 0x82d7}, /* U+3079 HIRAGANA LETTER BE */ + {0xe381ba, 0x82d8}, /* U+307A HIRAGANA LETTER PE */ + {0xe381bb, 0x82d9}, /* U+307B HIRAGANA LETTER HO */ + {0xe381bc, 0x82da}, /* U+307C HIRAGANA LETTER BO */ + {0xe381bd, 0x82db}, /* U+307D HIRAGANA LETTER PO */ + {0xe381be, 0x82dc}, /* U+307E HIRAGANA LETTER MA */ + {0xe381bf, 0x82dd}, /* U+307F HIRAGANA LETTER MI */ + {0xe38280, 0x82de}, /* U+3080 HIRAGANA LETTER MU */ + {0xe38281, 0x82df}, /* U+3081 HIRAGANA LETTER ME */ + {0xe38282, 0x82e0}, /* U+3082 HIRAGANA LETTER MO */ + {0xe38283, 0x82e1}, /* U+3083 HIRAGANA LETTER SMALL YA */ + {0xe38284, 0x82e2}, /* U+3084 HIRAGANA LETTER YA */ + {0xe38285, 0x82e3}, /* U+3085 HIRAGANA LETTER SMALL YU */ + {0xe38286, 0x82e4}, /* U+3086 HIRAGANA LETTER YU */ + {0xe38287, 0x82e5}, /* U+3087 HIRAGANA LETTER SMALL YO */ + {0xe38288, 0x82e6}, /* U+3088 HIRAGANA LETTER YO */ + {0xe38289, 0x82e7}, /* U+3089 HIRAGANA LETTER RA */ + {0xe3828a, 0x82e8}, /* U+308A HIRAGANA LETTER RI */ + {0xe3828b, 0x82e9}, /* U+308B HIRAGANA LETTER RU */ + {0xe3828c, 0x82ea}, /* U+308C HIRAGANA LETTER RE */ + {0xe3828d, 0x82eb}, /* U+308D HIRAGANA LETTER RO */ + {0xe3828e, 0x82ec}, /* U+308E HIRAGANA LETTER SMALL WA */ + {0xe3828f, 0x82ed}, /* U+308F HIRAGANA LETTER WA */ + {0xe38290, 0x82ee}, /* U+3090 HIRAGANA LETTER WI */ + {0xe38291, 0x82ef}, /* U+3091 HIRAGANA LETTER WE */ + {0xe38292, 0x82f0}, /* U+3092 HIRAGANA LETTER WO */ + {0xe38293, 0x82f1}, /* U+3093 HIRAGANA LETTER N */ + {0xe38294, 0x82f2}, /* U+3094 HIRAGANA LETTER VU [2000] */ + {0xe38295, 0x82f3}, /* U+3095 HIRAGANA LETTER SMALL KA [2000] [Unicode3.2] */ + {0xe38296, 0x82f4}, /* U+3096 HIRAGANA LETTER SMALL KE [2000] [Unicode3.2] */ + {0xe3829b, 0x814a}, /* U+309B KATAKANA-HIRAGANA VOICED SOUND MARK */ + {0xe3829c, 0x814b}, /* U+309C KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ + {0xe3829d, 0x8154}, /* U+309D HIRAGANA ITERATION MARK */ + {0xe3829e, 0x8155}, /* U+309E HIRAGANA VOICED ITERATION MARK */ + {0xe3829f, 0x81b7}, /* U+309F HIRAGANA DIGRAPH YORI [2000] [Unicode3.2] */ + {0xe382a0, 0x829b}, /* U+30A0 KATAKANA-HIRAGANA DOUBLE HYPHEN [2000] [Unicode3.2] */ + {0xe382a1, 0x8340}, /* U+30A1 KATAKANA LETTER SMALL A */ + {0xe382a2, 0x8341}, /* U+30A2 KATAKANA LETTER A */ + {0xe382a3, 0x8342}, /* U+30A3 KATAKANA LETTER SMALL I */ + {0xe382a4, 0x8343}, /* U+30A4 KATAKANA LETTER I */ + {0xe382a5, 0x8344}, /* U+30A5 KATAKANA LETTER SMALL U */ + {0xe382a6, 0x8345}, /* U+30A6 KATAKANA LETTER U */ + {0xe382a7, 0x8346}, /* U+30A7 KATAKANA LETTER SMALL E */ + {0xe382a8, 0x8347}, /* U+30A8 KATAKANA LETTER E */ + {0xe382a9, 0x8348}, /* U+30A9 KATAKANA LETTER SMALL O */ + {0xe382aa, 0x8349}, /* U+30AA KATAKANA LETTER O */ + {0xe382ab, 0x834a}, /* U+30AB KATAKANA LETTER KA */ + {0xe382ac, 0x834b}, /* U+30AC KATAKANA LETTER GA */ + {0xe382ad, 0x834c}, /* U+30AD KATAKANA LETTER KI */ + {0xe382ae, 0x834d}, /* U+30AE KATAKANA LETTER GI */ + {0xe382af, 0x834e}, /* U+30AF KATAKANA LETTER KU */ + {0xe382b0, 0x834f}, /* U+30B0 KATAKANA LETTER GU */ + {0xe382b1, 0x8350}, /* U+30B1 KATAKANA LETTER KE */ + {0xe382b2, 0x8351}, /* U+30B2 KATAKANA LETTER GE */ + {0xe382b3, 0x8352}, /* U+30B3 KATAKANA LETTER KO */ + {0xe382b4, 0x8353}, /* U+30B4 KATAKANA LETTER GO */ + {0xe382b5, 0x8354}, /* U+30B5 KATAKANA LETTER SA */ + {0xe382b6, 0x8355}, /* U+30B6 KATAKANA LETTER ZA */ + {0xe382b7, 0x8356}, /* U+30B7 KATAKANA LETTER SI */ + {0xe382b8, 0x8357}, /* U+30B8 KATAKANA LETTER ZI */ + {0xe382b9, 0x8358}, /* U+30B9 KATAKANA LETTER SU */ + {0xe382ba, 0x8359}, /* U+30BA KATAKANA LETTER ZU */ + {0xe382bb, 0x835a}, /* U+30BB KATAKANA LETTER SE */ + {0xe382bc, 0x835b}, /* U+30BC KATAKANA LETTER ZE */ + {0xe382bd, 0x835c}, /* U+30BD KATAKANA LETTER SO */ + {0xe382be, 0x835d}, /* U+30BE KATAKANA LETTER ZO */ + {0xe382bf, 0x835e}, /* U+30BF KATAKANA LETTER TA */ + {0xe38380, 0x835f}, /* U+30C0 KATAKANA LETTER DA */ + {0xe38381, 0x8360}, /* U+30C1 KATAKANA LETTER TI */ + {0xe38382, 0x8361}, /* U+30C2 KATAKANA LETTER DI */ + {0xe38383, 0x8362}, /* U+30C3 KATAKANA LETTER SMALL TU */ + {0xe38384, 0x8363}, /* U+30C4 KATAKANA LETTER TU */ + {0xe38385, 0x8364}, /* U+30C5 KATAKANA LETTER DU */ + {0xe38386, 0x8365}, /* U+30C6 KATAKANA LETTER TE */ + {0xe38387, 0x8366}, /* U+30C7 KATAKANA LETTER DE */ + {0xe38388, 0x8367}, /* U+30C8 KATAKANA LETTER TO */ + {0xe38389, 0x8368}, /* U+30C9 KATAKANA LETTER DO */ + {0xe3838a, 0x8369}, /* U+30CA KATAKANA LETTER NA */ + {0xe3838b, 0x836a}, /* U+30CB KATAKANA LETTER NI */ + {0xe3838c, 0x836b}, /* U+30CC KATAKANA LETTER NU */ + {0xe3838d, 0x836c}, /* U+30CD KATAKANA LETTER NE */ + {0xe3838e, 0x836d}, /* U+30CE KATAKANA LETTER NO */ + {0xe3838f, 0x836e}, /* U+30CF KATAKANA LETTER HA */ + {0xe38390, 0x836f}, /* U+30D0 KATAKANA LETTER BA */ + {0xe38391, 0x8370}, /* U+30D1 KATAKANA LETTER PA */ + {0xe38392, 0x8371}, /* U+30D2 KATAKANA LETTER HI */ + {0xe38393, 0x8372}, /* U+30D3 KATAKANA LETTER BI */ + {0xe38394, 0x8373}, /* U+30D4 KATAKANA LETTER PI */ + {0xe38395, 0x8374}, /* U+30D5 KATAKANA LETTER HU */ + {0xe38396, 0x8375}, /* U+30D6 KATAKANA LETTER BU */ + {0xe38397, 0x8376}, /* U+30D7 KATAKANA LETTER PU */ + {0xe38398, 0x8377}, /* U+30D8 KATAKANA LETTER HE */ + {0xe38399, 0x8378}, /* U+30D9 KATAKANA LETTER BE */ + {0xe3839a, 0x8379}, /* U+30DA KATAKANA LETTER PE */ + {0xe3839b, 0x837a}, /* U+30DB KATAKANA LETTER HO */ + {0xe3839c, 0x837b}, /* U+30DC KATAKANA LETTER BO */ + {0xe3839d, 0x837c}, /* U+30DD KATAKANA LETTER PO */ + {0xe3839e, 0x837d}, /* U+30DE KATAKANA LETTER MA */ + {0xe3839f, 0x837e}, /* U+30DF KATAKANA LETTER MI */ + {0xe383a0, 0x8380}, /* U+30E0 KATAKANA LETTER MU */ + {0xe383a1, 0x8381}, /* U+30E1 KATAKANA LETTER ME */ + {0xe383a2, 0x8382}, /* U+30E2 KATAKANA LETTER MO */ + {0xe383a3, 0x8383}, /* U+30E3 KATAKANA LETTER SMALL YA */ + {0xe383a4, 0x8384}, /* U+30E4 KATAKANA LETTER YA */ + {0xe383a5, 0x8385}, /* U+30E5 KATAKANA LETTER SMALL YU */ + {0xe383a6, 0x8386}, /* U+30E6 KATAKANA LETTER YU */ + {0xe383a7, 0x8387}, /* U+30E7 KATAKANA LETTER SMALL YO */ + {0xe383a8, 0x8388}, /* U+30E8 KATAKANA LETTER YO */ + {0xe383a9, 0x8389}, /* U+30E9 KATAKANA LETTER RA */ + {0xe383aa, 0x838a}, /* U+30EA KATAKANA LETTER RI */ + {0xe383ab, 0x838b}, /* U+30EB KATAKANA LETTER RU */ + {0xe383ac, 0x838c}, /* U+30EC KATAKANA LETTER RE */ + {0xe383ad, 0x838d}, /* U+30ED KATAKANA LETTER RO */ + {0xe383ae, 0x838e}, /* U+30EE KATAKANA LETTER SMALL WA */ + {0xe383af, 0x838f}, /* U+30EF KATAKANA LETTER WA */ + {0xe383b0, 0x8390}, /* U+30F0 KATAKANA LETTER WI */ + {0xe383b1, 0x8391}, /* U+30F1 KATAKANA LETTER WE */ + {0xe383b2, 0x8392}, /* U+30F2 KATAKANA LETTER WO */ + {0xe383b3, 0x8393}, /* U+30F3 KATAKANA LETTER N */ + {0xe383b4, 0x8394}, /* U+30F4 KATAKANA LETTER VU */ + {0xe383b5, 0x8395}, /* U+30F5 KATAKANA LETTER SMALL KA */ + {0xe383b6, 0x8396}, /* U+30F6 KATAKANA LETTER SMALL KE */ + {0xe383b7, 0x8492}, /* U+30F7 KATAKANA LETTER VA [2000] */ + {0xe383b8, 0x8493}, /* U+30F8 KATAKANA LETTER VI [2000] */ + {0xe383b9, 0x8494}, /* U+30F9 KATAKANA LETTER VE [2000] */ + {0xe383ba, 0x8495}, /* U+30FA KATAKANA LETTER VO [2000] */ + {0xe383bb, 0x8145}, /* U+30FB KATAKANA MIDDLE DOT */ + {0xe383bc, 0x815b}, /* U+30FC KATAKANA-HIRAGANA PROLONGED SOUND MARK */ + {0xe383bd, 0x8152}, /* U+30FD KATAKANA ITERATION MARK */ + {0xe383be, 0x8153}, /* U+30FE KATAKANA VOICED ITERATION MARK */ + {0xe383bf, 0x81b6}, /* U+30FF KATAKANA DIGRAPH KOTO [2000] [Unicode3.2] */ + {0xe387b0, 0x83ec}, /* U+31F0 KATAKANA LETTER SMALL KU [2000] [Unicode3.2] */ + {0xe387b1, 0x83ed}, /* U+31F1 KATAKANA LETTER SMALL SI [2000] [Unicode3.2] */ + {0xe387b2, 0x83ee}, /* U+31F2 KATAKANA LETTER SMALL SU [2000] [Unicode3.2] */ + {0xe387b3, 0x83ef}, /* U+31F3 KATAKANA LETTER SMALL TO [2000] [Unicode3.2] */ + {0xe387b4, 0x83f0}, /* U+31F4 KATAKANA LETTER SMALL NU [2000] [Unicode3.2] */ + {0xe387b5, 0x83f1}, /* U+31F5 KATAKANA LETTER SMALL HA [2000] [Unicode3.2] */ + {0xe387b6, 0x83f2}, /* U+31F6 KATAKANA LETTER SMALL HI [2000] [Unicode3.2] */ + {0xe387b7, 0x83f3}, /* U+31F7 KATAKANA LETTER SMALL HU [2000] [Unicode3.2] */ + {0xe387b8, 0x83f4}, /* U+31F8 KATAKANA LETTER SMALL HE [2000] [Unicode3.2] */ + {0xe387b9, 0x83f5}, /* U+31F9 KATAKANA LETTER SMALL HO [2000] [Unicode3.2] */ + {0xe387ba, 0x83f7}, /* U+31FA KATAKANA LETTER SMALL MU [2000] [Unicode3.2] */ + {0xe387bb, 0x83f8}, /* U+31FB KATAKANA LETTER SMALL RA [2000] [Unicode3.2] */ + {0xe387bc, 0x83f9}, /* U+31FC KATAKANA LETTER SMALL RI [2000] [Unicode3.2] */ + {0xe387bd, 0x83fa}, /* U+31FD KATAKANA LETTER SMALL RU [2000] [Unicode3.2] */ + {0xe387be, 0x83fb}, /* U+31FE KATAKANA LETTER SMALL RE [2000] [Unicode3.2] */ + {0xe387bf, 0x83fc}, /* U+31FF KATAKANA LETTER SMALL RO [2000] [Unicode3.2] */ + {0xe388b1, 0x878a}, /* U+3231 PARENTHESIZED IDEOGRAPH STOCK [2000] */ + {0xe388b2, 0x878b}, /* U+3232 PARENTHESIZED IDEOGRAPH HAVE [2000] */ + {0xe388b9, 0x878c}, /* U+3239 PARENTHESIZED IDEOGRAPH REPRESENT [2000] */ + {0xe38991, 0x84bf}, /* U+3251 CIRCLED NUMBER TWENTY ONE [2000] [Unicode3.2] */ + {0xe38992, 0x84c0}, /* U+3252 CIRCLED NUMBER TWENTY TWO [2000] [Unicode3.2] */ + {0xe38993, 0x84c1}, /* U+3253 CIRCLED NUMBER TWENTY THREE [2000] [Unicode3.2] */ + {0xe38994, 0x84c2}, /* U+3254 CIRCLED NUMBER TWENTY FOUR [2000] [Unicode3.2] */ + {0xe38995, 0x84c3}, /* U+3255 CIRCLED NUMBER TWENTY FIVE [2000] [Unicode3.2] */ + {0xe38996, 0x84c4}, /* U+3256 CIRCLED NUMBER TWENTY SIX [2000] [Unicode3.2] */ + {0xe38997, 0x84c5}, /* U+3257 CIRCLED NUMBER TWENTY SEVEN [2000] [Unicode3.2] */ + {0xe38998, 0x84c6}, /* U+3258 CIRCLED NUMBER TWENTY EIGHT [2000] [Unicode3.2] */ + {0xe38999, 0x84c7}, /* U+3259 CIRCLED NUMBER TWENTY NINE [2000] [Unicode3.2] */ + {0xe3899a, 0x84c8}, /* U+325A CIRCLED NUMBER THIRTY [2000] [Unicode3.2] */ + {0xe3899b, 0x84c9}, /* U+325B CIRCLED NUMBER THIRTY ONE [2000] [Unicode3.2] */ + {0xe3899c, 0x84ca}, /* U+325C CIRCLED NUMBER THIRTY TWO [2000] [Unicode3.2] */ + {0xe3899d, 0x84cb}, /* U+325D CIRCLED NUMBER THIRTY THREE [2000] [Unicode3.2] */ + {0xe3899e, 0x84cc}, /* U+325E CIRCLED NUMBER THIRTY FOUR [2000] [Unicode3.2] */ + {0xe3899f, 0x84cd}, /* U+325F CIRCLED NUMBER THIRTY FIVE [2000] [Unicode3.2] */ + {0xe38aa4, 0x8785}, /* U+32A4 CIRCLED IDEOGRAPH HIGH [2000] */ + {0xe38aa5, 0x8786}, /* U+32A5 CIRCLED IDEOGRAPH CENTRE [2000] */ + {0xe38aa6, 0x8787}, /* U+32A6 CIRCLED IDEOGRAPH LOW [2000] */ + {0xe38aa7, 0x8788}, /* U+32A7 CIRCLED IDEOGRAPH LEFT [2000] */ + {0xe38aa8, 0x8789}, /* U+32A8 CIRCLED IDEOGRAPH RIGHT [2000] */ + {0xe38ab1, 0x84ce}, /* U+32B1 CIRCLED NUMBER THIRTY SIX [2000] [Unicode3.2] */ + {0xe38ab2, 0x84cf}, /* U+32B2 CIRCLED NUMBER THIRTY SEVEN [2000] [Unicode3.2] */ + {0xe38ab3, 0x84d0}, /* U+32B3 CIRCLED NUMBER THIRTY EIGHT [2000] [Unicode3.2] */ + {0xe38ab4, 0x84d1}, /* U+32B4 CIRCLED NUMBER THIRTY NINE [2000] [Unicode3.2] */ + {0xe38ab5, 0x84d2}, /* U+32B5 CIRCLED NUMBER FORTY [2000] [Unicode3.2] */ + {0xe38ab6, 0x84d3}, /* U+32B6 CIRCLED NUMBER FORTY ONE [2000] [Unicode3.2] */ + {0xe38ab7, 0x84d4}, /* U+32B7 CIRCLED NUMBER FORTY TWO [2000] [Unicode3.2] */ + {0xe38ab8, 0x84d5}, /* U+32B8 CIRCLED NUMBER FORTY THREE [2000] [Unicode3.2] */ + {0xe38ab9, 0x84d6}, /* U+32B9 CIRCLED NUMBER FORTY FOUR [2000] [Unicode3.2] */ + {0xe38aba, 0x84d7}, /* U+32BA CIRCLED NUMBER FORTY FIVE [2000] [Unicode3.2] */ + {0xe38abb, 0x84d8}, /* U+32BB CIRCLED NUMBER FORTY SIX [2000] [Unicode3.2] */ + {0xe38abc, 0x84d9}, /* U+32BC CIRCLED NUMBER FORTY SEVEN [2000] [Unicode3.2] */ + {0xe38abd, 0x84da}, /* U+32BD CIRCLED NUMBER FORTY EIGHT [2000] [Unicode3.2] */ + {0xe38abe, 0x84db}, /* U+32BE CIRCLED NUMBER FORTY NINE [2000] [Unicode3.2] */ + {0xe38abf, 0x84dc}, /* U+32BF CIRCLED NUMBER FIFTY [2000] [Unicode3.2] */ + {0xe38b90, 0x86d9}, /* U+32D0 CIRCLED KATAKANA A [2000] */ + {0xe38b91, 0x86da}, /* U+32D1 CIRCLED KATAKANA I [2000] */ + {0xe38b92, 0x86db}, /* U+32D2 CIRCLED KATAKANA U [2000] */ + {0xe38b93, 0x86dc}, /* U+32D3 CIRCLED KATAKANA E [2000] */ + {0xe38b94, 0x86dd}, /* U+32D4 CIRCLED KATAKANA O [2000] */ + {0xe38b95, 0x86de}, /* U+32D5 CIRCLED KATAKANA KA [2000] */ + {0xe38b96, 0x86df}, /* U+32D6 CIRCLED KATAKANA KI [2000] */ + {0xe38b97, 0x86e0}, /* U+32D7 CIRCLED KATAKANA KU [2000] */ + {0xe38b98, 0x86e1}, /* U+32D8 CIRCLED KATAKANA KE [2000] */ + {0xe38b99, 0x86e2}, /* U+32D9 CIRCLED KATAKANA KO [2000] */ + {0xe38b9a, 0x86e3}, /* U+32DA CIRCLED KATAKANA SA [2000] */ + {0xe38b9b, 0x86e4}, /* U+32DB CIRCLED KATAKANA SI [2000] */ + {0xe38b9c, 0x86e5}, /* U+32DC CIRCLED KATAKANA SU [2000] */ + {0xe38b9d, 0x86e6}, /* U+32DD CIRCLED KATAKANA SE [2000] */ + {0xe38b9e, 0x86e7}, /* U+32DE CIRCLED KATAKANA SO [2000] */ + {0xe38b9f, 0x86e8}, /* U+32DF CIRCLED KATAKANA TA [2000] */ + {0xe38ba0, 0x86e9}, /* U+32E0 CIRCLED KATAKANA TI [2000] */ + {0xe38ba1, 0x86ea}, /* U+32E1 CIRCLED KATAKANA TU [2000] */ + {0xe38ba2, 0x86eb}, /* U+32E2 CIRCLED KATAKANA TE [2000] */ + {0xe38ba3, 0x86ec}, /* U+32E3 CIRCLED KATAKANA TO [2000] */ + {0xe38ba5, 0x86ef}, /* U+32E5 CIRCLED KATAKANA NI [2000] */ + {0xe38ba9, 0x86ee}, /* U+32E9 CIRCLED KATAKANA HA [2000] */ + {0xe38bac, 0x86f1}, /* U+32EC CIRCLED KATAKANA HE [2000] */ + {0xe38bad, 0x86f0}, /* U+32ED CIRCLED KATAKANA HO [2000] */ + {0xe38bba, 0x86ed}, /* U+32FA CIRCLED KATAKANA RO [2000] */ + {0xe38c83, 0x8765}, /* U+3303 SQUARE AARU [2000] */ + {0xe38c8d, 0x8769}, /* U+330D SQUARE KARORII [2000] */ + {0xe38c94, 0x8760}, /* U+3314 SQUARE KIRO [2000] */ + {0xe38c98, 0x8763}, /* U+3318 SQUARE GURAMU [2000] */ + {0xe38ca2, 0x8761}, /* U+3322 SQUARE SENTI [2000] */ + {0xe38ca3, 0x876b}, /* U+3323 SQUARE SENTO [2000] */ + {0xe38ca6, 0x876a}, /* U+3326 SQUARE DORU [2000] */ + {0xe38ca7, 0x8764}, /* U+3327 SQUARE TON [2000] */ + {0xe38cab, 0x876c}, /* U+332B SQUARE PAASENTO [2000] */ + {0xe38cb6, 0x8766}, /* U+3336 SQUARE HEKUTAARU [2000] */ + {0xe38cbb, 0x876e}, /* U+333B SQUARE PEEZI [2000] */ + {0xe38d89, 0x875f}, /* U+3349 SQUARE MIRI [2000] */ + {0xe38d8a, 0x876d}, /* U+334A SQUARE MIRIBAARU [2000] */ + {0xe38d8d, 0x8762}, /* U+334D SQUARE MEETORU [2000] */ + {0xe38d91, 0x8767}, /* U+3351 SQUARE RITTORU [2000] */ + {0xe38d97, 0x8768}, /* U+3357 SQUARE WATTO [2000] */ + {0xe38dbb, 0x877e}, /* U+337B SQUARE ERA NAME HEISEI [2000] */ + {0xe38dbc, 0x878f}, /* U+337C SQUARE ERA NAME SYOUWA [2000] */ + {0xe38dbd, 0x878e}, /* U+337D SQUARE ERA NAME TAISYOU [2000] */ + {0xe38dbe, 0x878d}, /* U+337E SQUARE ERA NAME MEIZI [2000] */ + {0xe38e8e, 0x8772}, /* U+338E SQUARE MG [2000] */ + {0xe38e8f, 0x8773}, /* U+338F SQUARE KG [2000] */ + {0xe38e9c, 0x876f}, /* U+339C SQUARE MM [2000] */ + {0xe38e9d, 0x8770}, /* U+339D SQUARE CM [2000] */ + {0xe38e9e, 0x8771}, /* U+339E SQUARE KM [2000] */ + {0xe38ea1, 0x8775}, /* U+33A1 SQUARE M SQUARED [2000] */ + {0xe38f84, 0x8774}, /* U+33C4 SQUARE CC [2000] */ + {0xe38f8b, 0x827d}, /* U+33CB SQUARE HP [2000] */ + {0xe38f8d, 0x8783}, /* U+33CD SQUARE KK [2000] */ + {0xe39082, 0x87a1}, /* U+3402 [2000] */ + {0xe39086, 0xf04c}, /* U+3406 [2000] */ + {0xe390ac, 0xf051}, /* U+342C [2000] */ + {0xe390ae, 0xf052}, /* U+342E [2000] */ + {0xe391a8, 0xf07d}, /* U+3468 [2000] */ + {0xe391aa, 0xf075}, /* U+346A [2000] */ + {0xe39292, 0xf09e}, /* U+3492 [2000] */ + {0xe392b5, 0x87d1}, /* U+34B5 [2000] */ + {0xe392bc, 0xf14a}, /* U+34BC [2000] */ + {0xe39381, 0xf7e6}, /* U+34C1 [2000] */ + {0xe39387, 0xf14e}, /* U+34C7 [2000] */ + {0xe3939b, 0x87d9}, /* U+34DB [2000] */ + {0xe3949f, 0xf167}, /* U+351F [2000] */ + {0xe3959d, 0xf17c}, /* U+355D [2000] */ + {0xe3959e, 0xf17d}, /* U+355E [2000] */ + {0xe395a3, 0xf181}, /* U+3563 [2000] */ + {0xe395ae, 0xf187}, /* U+356E [2000] */ + {0xe396a6, 0xf1a1}, /* U+35A6 [2000] */ + {0xe396a8, 0xf1a4}, /* U+35A8 [2000] */ + {0xe39785, 0xf1ad}, /* U+35C5 [2000] */ + {0xe3979a, 0xf1b6}, /* U+35DA [2000] */ + {0xe397b4, 0xf1c0}, /* U+35F4 [2000] */ + {0xe39885, 0xf1c8}, /* U+3605 [2000] */ + {0xe3998a, 0xf1f7}, /* U+364A [2000] */ + {0xe39a91, 0xf25e}, /* U+3691 [2000] */ + {0xe39a96, 0xf262}, /* U+3696 [2000] */ + {0xe39a99, 0xf260}, /* U+3699 [2000] */ + {0xe39b8f, 0xf276}, /* U+36CF [2000] */ + {0xe39da1, 0xf0a1}, /* U+3761 [2000] */ + {0xe39da2, 0xf0a3}, /* U+3762 [2000] */ + {0xe39dab, 0xf0a7}, /* U+376B [2000] */ + {0xe39dac, 0xf0a6}, /* U+376C [2000] */ + {0xe39db5, 0xf0aa}, /* U+3775 [2000] */ + {0xe39e8d, 0x987e}, /* U+378D [2000] */ + {0xe39f81, 0xf0bc}, /* U+37C1 [2000] */ + {0xe39fa2, 0x988f}, /* U+37E2 [2000] */ + {0xe39fa8, 0xf0d4}, /* U+37E8 [2000] */ + {0xe39fb4, 0xf0d7}, /* U+37F4 [2000] */ + {0xe39fbd, 0xf0da}, /* U+37FD [2000] */ + {0xe3a080, 0xf0dc}, /* U+3800 [2000] */ + {0xe3a0af, 0xf0ed}, /* U+382F [2000] */ + {0xe3a0b6, 0xf0ef}, /* U+3836 [2000] */ + {0xe3a180, 0xf0f2}, /* U+3840 [2000] */ + {0xe3a19c, 0xf0f7}, /* U+385C [2000] */ + {0xe3a1a1, 0xf0f9}, /* U+3861 [2000] */ + {0xe3a3ba, 0xf2b9}, /* U+38FA [2000] */ + {0xe3a497, 0xf2c4}, /* U+3917 [2000] */ + {0xe3a49a, 0xf2c8}, /* U+391A [2000] */ + {0xe3a5af, 0xf2de}, /* U+396F [2000] */ + {0xe3a9ae, 0xf37a}, /* U+3A6E [2000] */ + {0xe3a9b3, 0xf37e}, /* U+3A73 [2000] */ + {0xe3ab96, 0xf391}, /* U+3AD6 [2000] */ + {0xe3ab97, 0xf3b4}, /* U+3AD7 [2000] */ + {0xe3abaa, 0xf39c}, /* U+3AEA [2000] */ + {0xe3ac8e, 0xf3ac}, /* U+3B0E [2000] */ + {0xe3ac9a, 0xf3b0}, /* U+3B1A [2000] */ + {0xe3ac9c, 0xf3b2}, /* U+3B1C [2000] */ + {0xe3aca2, 0xeb68}, /* U+3B22 [2000] */ + {0xe3adad, 0xf3eb}, /* U+3B6D [2000] */ + {0xe3adb7, 0xf3e3}, /* U+3B77 [2000] */ + {0xe3ae87, 0xf447}, /* U+3B87 [2000] */ + {0xe3ae88, 0xf448}, /* U+3B88 [2000] */ + {0xe3ae8d, 0xf44b}, /* U+3B8D [2000] */ + {0xe3aea4, 0xf453}, /* U+3BA4 [2000] */ + {0xe3aeb6, 0xeb9e}, /* U+3BB6 [2000] */ + {0xe3af83, 0xeb9f}, /* U+3BC3 [2000] */ + {0xe3af8d, 0xf467}, /* U+3BCD [2000] */ + {0xe3afb0, 0xf47c}, /* U+3BF0 [2000] */ + {0xe3b08f, 0xebb8}, /* U+3C0F [2000] */ + {0xe3b0a6, 0xf497}, /* U+3C26 [2000] */ + {0xe3b383, 0xf4b9}, /* U+3CC3 [2000] */ + {0xe3b392, 0xf4c0}, /* U+3CD2 [2000] */ + {0xe3b491, 0xf4ef}, /* U+3D11 [2000] */ + {0xe3b49e, 0xf4fc}, /* U+3D1E [2000] */ + {0xe3b5a4, 0xf55f}, /* U+3D64 [2000] */ + {0xe3b69a, 0xf573}, /* U+3D9A [2000] */ + {0xe3b780, 0xf590}, /* U+3DC0 [2000] */ + {0xe3b794, 0xf597}, /* U+3DD4 [2000] */ + {0xe3b885, 0xf5a6}, /* U+3E05 [2000] */ + {0xe3b8bf, 0xec86}, /* U+3E3F [2000] */ + {0xe3b9a0, 0xf5bd}, /* U+3E60 [2000] */ + {0xe3b9a6, 0xf5bf}, /* U+3E66 [2000] */ + {0xe3b9a8, 0xf5c0}, /* U+3E68 [2000] */ + {0xe3ba83, 0xf5c7}, /* U+3E83 [2000] */ + {0xe3ba94, 0xf5ce}, /* U+3E94 [2000] */ + {0xe3bd97, 0xf653}, /* U+3F57 [2000] */ + {0xe3bdb2, 0xeccb}, /* U+3F72 [2000] */ + {0xe3bdb5, 0xf665}, /* U+3F75 [2000] */ + {0xe3bdb7, 0xf667}, /* U+3F77 [2000] */ + {0xe3beae, 0xf67b}, /* U+3FAE [2000] */ + {0xe3bf89, 0xf687}, /* U+3FC9 [2000] */ + {0xe3bf97, 0xf68c}, /* U+3FD7 [2000] */ + {0xe480b9, 0xf6a0}, /* U+4039 [2000] */ + {0xe48198, 0xf6ab}, /* U+4058 [2000] */ + {0xe48293, 0xf6b7}, /* U+4093 [2000] */ + {0xe48485, 0xf6e2}, /* U+4105 [2000] */ + {0xe48588, 0xf6f2}, /* U+4148 [2000] */ + {0xe4858f, 0xf6f5}, /* U+414F [2000] */ + {0xe485a3, 0xf6fb}, /* U+4163 [2000] */ + {0xe486b4, 0xf752}, /* U+41B4 [2000] */ + {0xe486bf, 0xf756}, /* U+41BF [2000] */ + {0xe487a6, 0xf766}, /* U+41E6 [2000] */ + {0xe487ae, 0xf76a}, /* U+41EE [2000] */ + {0xe487b3, 0xf767}, /* U+41F3 [2000] */ + {0xe48887, 0xf772}, /* U+4207 [2000] */ + {0xe4888e, 0xf776}, /* U+420E [2000] */ + {0xe489a4, 0xed8d}, /* U+4264 [2000] */ + {0xe48b86, 0xf7a9}, /* U+42C6 [2000] */ + {0xe48b96, 0xf7b4}, /* U+42D6 [2000] */ + {0xe48b9d, 0xf7b9}, /* U+42DD [2000] */ + {0xe48c82, 0xf7cc}, /* U+4302 [2000] */ + {0xe48cab, 0xf7db}, /* U+432B [2000] */ + {0xe48d83, 0xf7df}, /* U+4343 [2000] */ + {0xe48fae, 0xf85d}, /* U+43EE [2000] */ + {0xe48fb0, 0xf861}, /* U+43F0 [2000] */ + {0xe49088, 0xf867}, /* U+4408 [2000] */ + {0xe49097, 0xf869}, /* U+4417 [2000] */ + {0xe4909c, 0xf86b}, /* U+441C [2000] */ + {0xe490a2, 0xf86e}, /* U+4422 [2000] */ + {0xe49193, 0xedd7}, /* U+4453 [2000] */ + {0xe4919b, 0xedd8}, /* U+445B [2000] */ + {0xe491b6, 0xf88c}, /* U+4476 [2000] */ + {0xe491ba, 0xf88e}, /* U+447A [2000] */ + {0xe49291, 0xf897}, /* U+4491 [2000] */ + {0xe492b3, 0xf8b3}, /* U+44B3 [2000] */ + {0xe492be, 0xf8b0}, /* U+44BE [2000] */ + {0xe49394, 0xf8b2}, /* U+44D4 [2000] */ + {0xe49488, 0xf8d7}, /* U+4508 [2000] */ + {0xe4948d, 0xf8d2}, /* U+450D [2000] */ + {0xe494a5, 0xf8eb}, /* U+4525 [2000] */ + {0xe49583, 0xf8ec}, /* U+4543 [2000] */ + {0xe4969d, 0xee70}, /* U+459D [2000] */ + {0xe496b8, 0xf96e}, /* U+45B8 [2000] */ + {0xe497a5, 0xf98c}, /* U+45E5 [2000] */ + {0xe497aa, 0xee80}, /* U+45EA [2000] */ + {0xe4988f, 0xf9a2}, /* U+460F [2000] */ + {0xe49981, 0xf9b8}, /* U+4641 [2000] */ + {0xe499a5, 0xf9c1}, /* U+4665 [2000] */ + {0xe49aa1, 0xf9cc}, /* U+46A1 [2000] */ + {0xe49aaf, 0xf9d1}, /* U+46AF [2000] */ + {0xe49c8c, 0xf9e9}, /* U+470C [2000] */ + {0xe49da4, 0xfa48}, /* U+4764 [2000] */ + {0xe49fbd, 0xfa5e}, /* U+47FD [2000] */ + {0xe4a096, 0xfa68}, /* U+4816 [2000] */ + {0xe4a184, 0xeec9}, /* U+4844 [2000] */ + {0xe4a18e, 0xfa7b}, /* U+484E [2000] */ + {0xe4a2b5, 0xfaa5}, /* U+48B5 [2000] */ + {0xe4a6b0, 0xef77}, /* U+49B0 [2000] */ + {0xe4a7a7, 0xfb8a}, /* U+49E7 [2000] */ + {0xe4a7ba, 0xfb90}, /* U+49FA [2000] */ + {0xe4a884, 0xfb95}, /* U+4A04 [2000] */ + {0xe4a8a9, 0xfb98}, /* U+4A29 [2000] */ + {0xe4aabc, 0xfbb5}, /* U+4ABC [2000] */ + {0xe4acbb, 0xfbd3}, /* U+4B3B [2000] */ + {0xe4af82, 0xfc45}, /* U+4BC2 [2000] */ + {0xe4af8a, 0xfc47}, /* U+4BCA [2000] */ + {0xe4af92, 0xfc49}, /* U+4BD2 [2000] */ + {0xe4afa8, 0xfc50}, /* U+4BE8 [2000] */ + {0xe4b097, 0xefbc}, /* U+4C17 [2000] */ + {0xe4b0a0, 0xfc5e}, /* U+4C20 [2000] */ + {0xe4b384, 0xfca8}, /* U+4CC4 [2000] */ + {0xe4b391, 0xfcab}, /* U+4CD1 [2000] */ + {0xe4b487, 0xfcc9}, /* U+4D07 [2000] */ + {0xe4b5b7, 0xfcde}, /* U+4D77 [2000] */ + {0xe4b880, 0x88ea}, /* U+4E00 */ + {0xe4b881, 0x929a}, /* U+4E01 */ + {0xe4b882, 0xf041}, /* U+4E02 [2000] */ + {0xe4b883, 0x8eb5}, /* U+4E03 */ + {0xe4b887, 0x969c}, /* U+4E07 */ + {0xe4b888, 0x8fe4}, /* U+4E08 */ + {0xe4b889, 0x8e4f}, /* U+4E09 */ + {0xe4b88a, 0x8fe3}, /* U+4E0A */ + {0xe4b88b, 0x89ba}, /* U+4E0B */ + {0xe4b88d, 0x9573}, /* U+4E0D */ + {0xe4b88e, 0x975e}, /* U+4E0E */ + {0xe4b88f, 0xf042}, /* U+4E0F [2000] */ + {0xe4b890, 0x98a0}, /* U+4E10 */ + {0xe4b891, 0x894e}, /* U+4E11 */ + {0xe4b892, 0xf043}, /* U+4E12 [2000] */ + {0xe4b894, 0x8a8e}, /* U+4E14 */ + {0xe4b895, 0x98a1}, /* U+4E15 */ + {0xe4b896, 0x90a2}, /* U+4E16 */ + {0xe4b897, 0x99c0}, /* U+4E17 */ + {0xe4b898, 0x8b75}, /* U+4E18 */ + {0xe4b899, 0x95b8}, /* U+4E19 */ + {0xe4b89e, 0x8fe5}, /* U+4E1E */ + {0xe4b8a1, 0x97bc}, /* U+4E21 */ + {0xe4b8a6, 0x95c0}, /* U+4E26 */ + {0xe4b8a8, 0x87a2}, /* U+4E28 [2000] */ + {0xe4b8a9, 0xf044}, /* U+4E29 [2000] */ + {0xe4b8aa, 0x98a2}, /* U+4E2A */ + {0xe4b8ab, 0xf045}, /* U+4E2B [2000] */ + {0xe4b8ac, 0xf5ac}, /* U+4E2C [2000] */ + {0xe4b8ad, 0x9286}, /* U+4E2D */ + {0xe4b8ae, 0xf046}, /* U+4E2E [2000] */ + {0xe4b8af, 0x87a3}, /* U+4E2F [2000] */ + {0xe4b8b0, 0x87a4}, /* U+4E30 [2000] */ + {0xe4b8b1, 0x98a3}, /* U+4E31 */ + {0xe4b8b2, 0x8bf8}, /* U+4E32 */ + {0xe4b8b6, 0x98a4}, /* U+4E36 */ + {0xe4b8b8, 0x8adb}, /* U+4E38 */ + {0xe4b8b9, 0x924f}, /* U+4E39 */ + {0xe4b8bb, 0x8ee5}, /* U+4E3B */ + {0xe4b8bc, 0x98a5}, /* U+4E3C */ + {0xe4b8bf, 0x98a6}, /* U+4E3F */ + {0xe4b980, 0xf047}, /* U+4E40 [2000] */ + {0xe4b982, 0x98a7}, /* U+4E42 */ + {0xe4b983, 0x9454}, /* U+4E43 */ + {0xe4b985, 0x8b76}, /* U+4E45 */ + {0xe4b987, 0xf048}, /* U+4E47 [2000] */ + {0xe4b988, 0xf049}, /* U+4E48 [2000] */ + {0xe4b98b, 0x9456}, /* U+4E4B */ + {0xe4b98d, 0x93e1}, /* U+4E4D */ + {0xe4b98e, 0x8cc1}, /* U+4E4E */ + {0xe4b98f, 0x9652}, /* U+4E4F */ + {0xe4b991, 0xf04b}, /* U+4E51 [2000] */ + {0xe4b995, 0xe568}, /* U+4E55 */ + {0xe4b996, 0x98a8}, /* U+4E56 */ + {0xe4b997, 0x8fe6}, /* U+4E57 */ + {0xe4b998, 0x98a9}, /* U+4E58 */ + {0xe4b999, 0x89b3}, /* U+4E59 */ + {0xe4b99a, 0xf04e}, /* U+4E5A [2000] */ + {0xe4b99d, 0x8be3}, /* U+4E5D */ + {0xe4b99e, 0x8cee}, /* U+4E5E */ + {0xe4b99f, 0x96e7}, /* U+4E5F */ + {0xe4b9a2, 0x9ba4}, /* U+4E62 */ + {0xe4b9a9, 0xf04f}, /* U+4E69 [2000] */ + {0xe4b9b1, 0x9790}, /* U+4E71 */ + {0xe4b9b3, 0x93fb}, /* U+4E73 */ + {0xe4b9be, 0x8aa3}, /* U+4E7E */ + {0xe4ba80, 0x8b54}, /* U+4E80 */ + {0xe4ba82, 0x98aa}, /* U+4E82 */ + {0xe4ba85, 0x98ab}, /* U+4E85 */ + {0xe4ba86, 0x97b9}, /* U+4E86 */ + {0xe4ba88, 0x975c}, /* U+4E88 */ + {0xe4ba89, 0x9188}, /* U+4E89 */ + {0xe4ba8a, 0x98ad}, /* U+4E8A */ + {0xe4ba8b, 0x8e96}, /* U+4E8B */ + {0xe4ba8c, 0x93f1}, /* U+4E8C */ + {0xe4ba8d, 0x87a5}, /* U+4E8D [2000] */ + {0xe4ba8e, 0x98b0}, /* U+4E8E */ + {0xe4ba91, 0x895d}, /* U+4E91 */ + {0xe4ba92, 0x8cdd}, /* U+4E92 */ + {0xe4ba94, 0x8cdc}, /* U+4E94 */ + {0xe4ba95, 0x88e4}, /* U+4E95 */ + {0xe4ba98, 0x986a}, /* U+4E98 */ + {0xe4ba99, 0x9869}, /* U+4E99 */ + {0xe4ba9b, 0x8db1}, /* U+4E9B */ + {0xe4ba9c, 0x889f}, /* U+4E9C */ + {0xe4ba9d, 0xf050}, /* U+4E9D [2000] */ + {0xe4ba9e, 0x98b1}, /* U+4E9E */ + {0xe4ba9f, 0x98b2}, /* U+4E9F */ + {0xe4baa0, 0x98b3}, /* U+4EA0 */ + {0xe4baa1, 0x9653}, /* U+4EA1 */ + {0xe4baa2, 0x98b4}, /* U+4EA2 */ + {0xe4baa4, 0x8cf0}, /* U+4EA4 */ + {0xe4baa5, 0x88e5}, /* U+4EA5 */ + {0xe4baa6, 0x9692}, /* U+4EA6 */ + {0xe4baa8, 0x8b9c}, /* U+4EA8 */ + {0xe4baab, 0x8b9d}, /* U+4EAB */ + {0xe4baac, 0x8b9e}, /* U+4EAC */ + {0xe4baad, 0x92e0}, /* U+4EAD */ + {0xe4baae, 0x97ba}, /* U+4EAE */ + {0xe4bab0, 0x98b5}, /* U+4EB0 */ + {0xe4bab3, 0x98b6}, /* U+4EB3 */ + {0xe4bab6, 0x98b7}, /* U+4EB6 */ + {0xe4bab9, 0xf053}, /* U+4EB9 [2000] */ + {0xe4baba, 0x906c}, /* U+4EBA */ + {0xe4babb, 0xf054}, /* U+4EBB [2000] */ + {0xe4babc, 0xf056}, /* U+4EBC [2000] */ + {0xe4bb80, 0x8f59}, /* U+4EC0 */ + {0xe4bb81, 0x906d}, /* U+4EC1 */ + {0xe4bb82, 0x98bc}, /* U+4EC2 */ + {0xe4bb83, 0xf057}, /* U+4EC3 [2000] */ + {0xe4bb84, 0x98ba}, /* U+4EC4 */ + {0xe4bb86, 0x98bb}, /* U+4EC6 */ + {0xe4bb87, 0x8b77}, /* U+4EC7 */ + {0xe4bb88, 0xf058}, /* U+4EC8 [2000] */ + {0xe4bb8a, 0x8da1}, /* U+4ECA */ + {0xe4bb8b, 0x89ee}, /* U+4ECB */ + {0xe4bb8d, 0x98b9}, /* U+4ECD */ + {0xe4bb8e, 0x98b8}, /* U+4ECE */ + {0xe4bb8f, 0x95a7}, /* U+4ECF */ + {0xe4bb90, 0xf059}, /* U+4ED0 [2000] */ + {0xe4bb94, 0x8e65}, /* U+4ED4 */ + {0xe4bb95, 0x8e64}, /* U+4ED5 */ + {0xe4bb96, 0x91bc}, /* U+4ED6 */ + {0xe4bb97, 0x98bd}, /* U+4ED7 */ + {0xe4bb98, 0x9574}, /* U+4ED8 */ + {0xe4bb99, 0x90e5}, /* U+4ED9 */ + {0xe4bb9a, 0xf05b}, /* U+4EDA [2000] */ + {0xe4bb9d, 0x8157}, /* U+4EDD */ + {0xe4bb9e, 0x98be}, /* U+4EDE */ + {0xe4bb9f, 0x98c0}, /* U+4EDF */ + {0xe4bba1, 0x87a6}, /* U+4EE1 [2000] */ + {0xe4bba3, 0x91e3}, /* U+4EE3 */ + {0xe4bba4, 0x97df}, /* U+4EE4 */ + {0xe4bba5, 0x88c8}, /* U+4EE5 */ + {0xe4bbab, 0xf05a}, /* U+4EEB [2000] */ + {0xe4bbad, 0x98bf}, /* U+4EED */ + {0xe4bbae, 0x89bc}, /* U+4EEE */ + {0xe4bbb0, 0x8bc2}, /* U+4EF0 */ + {0xe4bbb1, 0xf05c}, /* U+4EF1 [2000] */ + {0xe4bbb2, 0x9287}, /* U+4EF2 */ + {0xe4bbb5, 0xf05d}, /* U+4EF5 [2000] */ + {0xe4bbb6, 0x8c8f}, /* U+4EF6 */ + {0xe4bbb7, 0x98c1}, /* U+4EF7 */ + {0xe4bbbb, 0x9443}, /* U+4EFB */ + {0xe4bbbd, 0x87a7}, /* U+4EFD [2000] */ + {0xe4bbbf, 0x87a8}, /* U+4EFF [2000] */ + {0xe4bc80, 0xf05e}, /* U+4F00 [2000] */ + {0xe4bc81, 0x8ae9}, /* U+4F01 */ + {0xe4bc83, 0x87a9}, /* U+4F03 [2000] */ + {0xe4bc89, 0x98c2}, /* U+4F09 */ + {0xe4bc8a, 0x88c9}, /* U+4F0A */ + {0xe4bc8b, 0x87aa}, /* U+4F0B [2000] */ + {0xe4bc8d, 0x8cde}, /* U+4F0D */ + {0xe4bc8e, 0x8aea}, /* U+4F0E */ + {0xe4bc8f, 0x959a}, /* U+4F0F */ + {0xe4bc90, 0x94b0}, /* U+4F10 */ + {0xe4bc91, 0x8b78}, /* U+4F11 */ + {0xe4bc96, 0xf05f}, /* U+4F16 [2000] */ + {0xe4bc9a, 0x89ef}, /* U+4F1A */ + {0xe4bc9c, 0x98e5}, /* U+4F1C */ + {0xe4bc9d, 0x9360}, /* U+4F1D */ + {0xe4bcaf, 0x948c}, /* U+4F2F */ + {0xe4bcb0, 0x98c4}, /* U+4F30 */ + {0xe4bcb4, 0x94ba}, /* U+4F34 */ + {0xe4bcb6, 0x97e0}, /* U+4F36 */ + {0xe4bcb7, 0xf061}, /* U+4F37 [2000] */ + {0xe4bcb8, 0x904c}, /* U+4F38 */ + {0xe4bcba, 0x8e66}, /* U+4F3A */ + {0xe4bcbc, 0x8e97}, /* U+4F3C */ + {0xe4bcbd, 0x89be}, /* U+4F3D */ + {0xe4bcbe, 0xf062}, /* U+4F3E [2000] */ + {0xe4bd83, 0x92cf}, /* U+4F43 */ + {0xe4bd86, 0x9241}, /* U+4F46 */ + {0xe4bd87, 0x98c8}, /* U+4F47 */ + {0xe4bd88, 0x87ac}, /* U+4F48 [2000] */ + {0xe4bd89, 0x87ad}, /* U+4F49 [2000] */ + {0xe4bd8d, 0x88ca}, /* U+4F4D */ + {0xe4bd8e, 0x92e1}, /* U+4F4E */ + {0xe4bd8f, 0x8f5a}, /* U+4F4F */ + {0xe4bd90, 0x8db2}, /* U+4F50 */ + {0xe4bd91, 0x9743}, /* U+4F51 */ + {0xe4bd93, 0x91cc}, /* U+4F53 */ + {0xe4bd94, 0xf063}, /* U+4F54 [2000] */ + {0xe4bd95, 0x89bd}, /* U+4F55 */ + {0xe4bd96, 0x87ae}, /* U+4F56 [2000] */ + {0xe4bd97, 0x98c7}, /* U+4F57 */ + {0xe4bd98, 0xf064}, /* U+4F58 [2000] */ + {0xe4bd99, 0x975d}, /* U+4F59 */ + {0xe4bd9a, 0x98c3}, /* U+4F5A */ + {0xe4bd9b, 0x98c5}, /* U+4F5B */ + {0xe4bd9c, 0x8dec}, /* U+4F5C */ + {0xe4bd9d, 0x98c6}, /* U+4F5D */ + {0xe4bd9e, 0x9b43}, /* U+4F5E */ + {0xe4bd9f, 0x87af}, /* U+4F5F [2000] */ + {0xe4bda0, 0x87ab}, /* U+4F60 [2000] */ + {0xe4bda4, 0xf060}, /* U+4F64 [2000] */ + {0xe4bda9, 0x98ce}, /* U+4F69 */ + {0xe4bdaa, 0x87b0}, /* U+4F6A [2000] */ + {0xe4bdac, 0x87b1}, /* U+4F6C [2000] */ + {0xe4bdaf, 0x98d1}, /* U+4F6F */ + {0xe4bdb0, 0x98cf}, /* U+4F70 */ + {0xe4bdb3, 0x89c0}, /* U+4F73 */ + {0xe4bdb5, 0x95b9}, /* U+4F75 */ + {0xe4bdb6, 0x98c9}, /* U+4F76 */ + {0xe4bdb7, 0xf066}, /* U+4F77 [2000] */ + {0xe4bdb8, 0xf067}, /* U+4F78 [2000] */ + {0xe4bdba, 0xf068}, /* U+4F7A [2000] */ + {0xe4bdbb, 0x98cd}, /* U+4F7B */ + {0xe4bdbc, 0x8cf1}, /* U+4F7C */ + {0xe4bdbd, 0xf069}, /* U+4F7D [2000] */ + {0xe4bdbe, 0x87b2}, /* U+4F7E [2000] */ + {0xe4bdbf, 0x8e67}, /* U+4F7F */ + {0xe4be82, 0xf06a}, /* U+4F82 [2000] */ + {0xe4be83, 0x8aa4}, /* U+4F83 */ + {0xe4be85, 0xf06b}, /* U+4F85 [2000] */ + {0xe4be86, 0x98d2}, /* U+4F86 */ + {0xe4be88, 0x98ca}, /* U+4F88 */ + {0xe4be8a, 0x87b3}, /* U+4F8A [2000] */ + {0xe4be8b, 0x97e1}, /* U+4F8B */ + {0xe4be8d, 0x8e98}, /* U+4F8D */ + {0xe4be8f, 0x98cb}, /* U+4F8F */ + {0xe4be91, 0x98d0}, /* U+4F91 */ + {0xe4be92, 0xf06c}, /* U+4F92 [2000] */ + {0xe4be94, 0x87b4}, /* U+4F94 [2000] */ + {0xe4be96, 0x98d3}, /* U+4F96 */ + {0xe4be97, 0x87b5}, /* U+4F97 [2000] */ + {0xe4be98, 0x98cc}, /* U+4F98 */ + {0xe4be9a, 0xf06d}, /* U+4F9A [2000] */ + {0xe4be9b, 0x8b9f}, /* U+4F9B */ + {0xe4be9d, 0x88cb}, /* U+4F9D */ + {0xe4bea0, 0x8ba0}, /* U+4FA0 */ + {0xe4bea1, 0x89bf}, /* U+4FA1 */ + {0xe4beab, 0x9b44}, /* U+4FAB */ + {0xe4bead, 0x9699}, /* U+4FAD */ + {0xe4beae, 0x958e}, /* U+4FAE */ + {0xe4beaf, 0x8cf2}, /* U+4FAF */ + {0xe4beb2, 0xf06f}, /* U+4FB2 [2000] */ + {0xe4beb5, 0x904e}, /* U+4FB5 */ + {0xe4beb6, 0x97b5}, /* U+4FB6 */ + {0xe4bebe, 0xf070}, /* U+4FBE [2000] */ + {0xe4bebf, 0x95d6}, /* U+4FBF */ + {0xe4bf82, 0x8c57}, /* U+4FC2 */ + {0xe4bf83, 0x91a3}, /* U+4FC3 */ + {0xe4bf84, 0x89e2}, /* U+4FC4 */ + {0xe4bf85, 0xf071}, /* U+4FC5 [2000] */ + {0xe4bf89, 0x87b7}, /* U+4FC9 [2000] */ + {0xe4bf8a, 0x8f72}, /* U+4FCA */ + {0xe4bf8b, 0xf072}, /* U+4FCB [2000] */ + {0xe4bf8e, 0x98d7}, /* U+4FCE */ + {0xe4bf8f, 0xf073}, /* U+4FCF [2000] */ + {0xe4bf90, 0x98dc}, /* U+4FD0 */ + {0xe4bf91, 0x98da}, /* U+4FD1 */ + {0xe4bf92, 0xf074}, /* U+4FD2 [2000] */ + {0xe4bf94, 0x98d5}, /* U+4FD4 */ + {0xe4bf97, 0x91ad}, /* U+4FD7 */ + {0xe4bf98, 0x98d8}, /* U+4FD8 */ + {0xe4bf9a, 0x98db}, /* U+4FDA */ + {0xe4bf9b, 0x98d9}, /* U+4FDB */ + {0xe4bf9d, 0x95db}, /* U+4FDD */ + {0xe4bf9f, 0x98d6}, /* U+4FDF */ + {0xe4bfa0, 0x87b8}, /* U+4FE0 [2000] */ + {0xe4bfa1, 0x904d}, /* U+4FE1 */ + {0xe4bfa3, 0x9693}, /* U+4FE3 */ + {0xe4bfa4, 0x98dd}, /* U+4FE4 */ + {0xe4bfa5, 0x98de}, /* U+4FE5 */ + {0xe4bfa6, 0xf06e}, /* U+4FE6 [2000] */ + {0xe4bfae, 0x8f43}, /* U+4FEE */ + {0xe4bfaf, 0x98eb}, /* U+4FEF */ + {0xe4bfb1, 0x879f}, /* U+4FF1 [2004] */ + {0xe4bfb2, 0xf076}, /* U+4FF2 [2000] */ + {0xe4bfb3, 0x946f}, /* U+4FF3 */ + {0xe4bfb5, 0x9555}, /* U+4FF5 */ + {0xe4bfb6, 0x98e6}, /* U+4FF6 */ + {0xe4bfb8, 0x95ee}, /* U+4FF8 */ + {0xe4bfba, 0x89b4}, /* U+4FFA */ + {0xe4bfbe, 0x98ea}, /* U+4FFE */ + {0xe58080, 0xf077}, /* U+5000 [2000] */ + {0xe58081, 0x87b9}, /* U+5001 [2000] */ + {0xe58082, 0x87ba}, /* U+5002 [2000] */ + {0xe58085, 0x98e4}, /* U+5005 */ + {0xe58086, 0x98ed}, /* U+5006 */ + {0xe58089, 0x9171}, /* U+5009 */ + {0xe5808b, 0x8cc2}, /* U+500B */ + {0xe5808d, 0x947b}, /* U+500D */ + {0xe5808e, 0x87bb}, /* U+500E [2000] */ + {0xe5808f, 0xe0c5}, /* U+500F */ + {0xe58090, 0xf078}, /* U+5010 [2000] */ + {0xe58091, 0x98ec}, /* U+5011 */ + {0xe58092, 0x937c}, /* U+5012 */ + {0xe58093, 0xf079}, /* U+5013 [2000] */ + {0xe58094, 0x98e1}, /* U+5014 */ + {0xe58096, 0x8cf4}, /* U+5016 */ + {0xe58098, 0x87bc}, /* U+5018 [2000] */ + {0xe58099, 0x8cf3}, /* U+5019 */ + {0xe5809a, 0x98df}, /* U+501A */ + {0xe5809c, 0xf07a}, /* U+501C [2000] */ + {0xe5809e, 0xf07b}, /* U+501E [2000] */ + {0xe5809f, 0x8ed8}, /* U+501F */ + {0xe580a1, 0x98e7}, /* U+5021 */ + {0xe580a2, 0xf07c}, /* U+5022 [2000] */ + {0xe580a3, 0x95ed}, /* U+5023 */ + {0xe580a4, 0x926c}, /* U+5024 */ + {0xe580a5, 0x98e3}, /* U+5025 */ + {0xe580a6, 0x8c91}, /* U+5026 */ + {0xe580a7, 0x87bd}, /* U+5027 [2000] */ + {0xe580a8, 0x98e0}, /* U+5028 */ + {0xe580a9, 0x98e8}, /* U+5029 */ + {0xe580aa, 0x98e2}, /* U+502A */ + {0xe580ab, 0x97cf}, /* U+502B */ + {0xe580ac, 0x98e9}, /* U+502C */ + {0xe580ad, 0x9860}, /* U+502D */ + {0xe580ae, 0x87be}, /* U+502E [2000] */ + {0xe580b6, 0x8be4}, /* U+5036 */ + {0xe580b9, 0x8c90}, /* U+5039 */ + {0xe580bb, 0x87c0}, /* U+503B [2000] */ + {0xe58180, 0x87bf}, /* U+5040 [2000] */ + {0xe58181, 0x87c1}, /* U+5041 [2000] */ + {0xe58182, 0xf07e}, /* U+5042 [2000] */ + {0xe58183, 0x98ee}, /* U+5043 */ + {0xe58186, 0xf080}, /* U+5046 [2000] */ + {0xe58187, 0x98ef}, /* U+5047 */ + {0xe58188, 0x98f3}, /* U+5048 */ + {0xe58189, 0x88cc}, /* U+5049 */ + {0xe5818e, 0xf081}, /* U+504E [2000] */ + {0xe5818f, 0x95ce}, /* U+504F */ + {0xe58190, 0x98f2}, /* U+5050 */ + {0xe58193, 0xf082}, /* U+5053 [2000] */ + {0xe58195, 0x98f1}, /* U+5055 */ + {0xe58196, 0x98f5}, /* U+5056 */ + {0xe58197, 0xf083}, /* U+5057 [2000] */ + {0xe5819a, 0x98f4}, /* U+505A */ + {0xe5819c, 0x92e2}, /* U+505C */ + {0xe581a3, 0xf084}, /* U+5063 [2000] */ + {0xe581a5, 0x8c92}, /* U+5065 */ + {0xe581a6, 0xf085}, /* U+5066 [2000] */ + {0xe581aa, 0xf086}, /* U+506A [2000] */ + {0xe581ac, 0x98f6}, /* U+506C */ + {0xe581b0, 0xf087}, /* U+5070 [2000] */ + {0xe581b2, 0x8ec3}, /* U+5072 */ + {0xe581b4, 0x91a4}, /* U+5074 */ + {0xe581b5, 0x92e3}, /* U+5075 */ + {0xe581b6, 0x8bf4}, /* U+5076 */ + {0xe581b8, 0x98f7}, /* U+5078 */ + {0xe581bd, 0x8b55}, /* U+507D */ + {0xe58280, 0x98f8}, /* U+5080 */ + {0xe58285, 0x98fa}, /* U+5085 */ + {0xe58288, 0xf089}, /* U+5088 [2000] */ + {0xe5828d, 0x9654}, /* U+508D */ + {0xe58291, 0x8c86}, /* U+5091 */ + {0xe58292, 0xf08a}, /* U+5092 [2000] */ + {0xe58293, 0xf08b}, /* U+5093 [2000] */ + {0xe58294, 0x87c2}, /* U+5094 [2000] */ + {0xe58295, 0xf08c}, /* U+5095 [2000] */ + {0xe58296, 0xf08d}, /* U+5096 [2000] */ + {0xe58298, 0x8e50}, /* U+5098 */ + {0xe58299, 0x94f5}, /* U+5099 */ + {0xe5829a, 0x98f9}, /* U+509A */ + {0xe5829c, 0xf08e}, /* U+509C [2000] */ + {0xe582a3, 0xf088}, /* U+50A3 [2000] */ + {0xe582aa, 0xf08f}, /* U+50AA [2000] */ + {0xe582ac, 0x8dc3}, /* U+50AC */ + {0xe582ad, 0x9762}, /* U+50AD */ + {0xe582b1, 0xf091}, /* U+50B1 [2000] */ + {0xe582b2, 0x98fc}, /* U+50B2 */ + {0xe582b3, 0x9942}, /* U+50B3 */ + {0xe582b4, 0x98fb}, /* U+50B4 */ + {0xe582b5, 0x8dc2}, /* U+50B5 */ + {0xe582b7, 0x8f9d}, /* U+50B7 */ + {0xe582ba, 0xf092}, /* U+50BA [2000] */ + {0xe582bb, 0xf093}, /* U+50BB [2000] */ + {0xe582be, 0x8c58}, /* U+50BE */ + {0xe58382, 0x9943}, /* U+50C2 */ + {0xe58384, 0xf094}, /* U+50C4 [2000] */ + {0xe58385, 0x8bcd}, /* U+50C5 */ + {0xe58387, 0xf095}, /* U+50C7 [2000] */ + {0xe58389, 0x9940}, /* U+50C9 */ + {0xe5838a, 0x9941}, /* U+50CA */ + {0xe5838c, 0x87c3}, /* U+50CC [2000] */ + {0xe5838d, 0x93ad}, /* U+50CD */ + {0xe5838e, 0xf098}, /* U+50CE [2000] */ + {0xe5838f, 0x919c}, /* U+50CF */ + {0xe58390, 0x87c5}, /* U+50D0 [2000] */ + {0xe58391, 0x8ba1}, /* U+50D1 */ + {0xe58394, 0xf09a}, /* U+50D4 [2000] */ + {0xe58395, 0x966c}, /* U+50D5 */ + {0xe58396, 0x9944}, /* U+50D6 */ + {0xe58399, 0xf09b}, /* U+50D9 [2000] */ + {0xe5839a, 0x97bb}, /* U+50DA */ + {0xe5839e, 0x9945}, /* U+50DE */ + {0xe583a1, 0xf09c}, /* U+50E1 [2000] */ + {0xe583a3, 0x9948}, /* U+50E3 */ + {0xe583a5, 0x9946}, /* U+50E5 */ + {0xe583a6, 0x87c6}, /* U+50E6 [2000] */ + {0xe583a7, 0x916d}, /* U+50E7 */ + {0xe583a9, 0xf09d}, /* U+50E9 [2000] */ + {0xe583ad, 0x9947}, /* U+50ED */ + {0xe583ae, 0x9949}, /* U+50EE */ + {0xe583b2, 0x87c4}, /* U+50F2 [2000] */ + {0xe583b3, 0xf096}, /* U+50F3 [2000] */ + {0xe583b5, 0x994b}, /* U+50F5 */ + {0xe583b9, 0x994a}, /* U+50F9 */ + {0xe583bb, 0x95c6}, /* U+50FB */ + {0xe58480, 0x8b56}, /* U+5100 */ + {0xe58481, 0x994d}, /* U+5101 */ + {0xe58482, 0x994e}, /* U+5102 */ + {0xe58483, 0x87c9}, /* U+5103 [2000] */ + {0xe58484, 0x89ad}, /* U+5104 */ + {0xe58486, 0x87c8}, /* U+5106 [2000] */ + {0xe58488, 0xf140}, /* U+5108 [2000] */ + {0xe58489, 0x994c}, /* U+5109 */ + {0xe5848b, 0x87ca}, /* U+510B [2000] */ + {0xe58492, 0x8ef2}, /* U+5112 */ + {0xe58494, 0x9951}, /* U+5114 */ + {0xe58495, 0x9950}, /* U+5115 */ + {0xe58496, 0x994f}, /* U+5116 */ + {0xe58497, 0xf142}, /* U+5117 [2000] */ + {0xe58498, 0x98d4}, /* U+5118 */ + {0xe5849a, 0x9952}, /* U+511A */ + {0xe5849b, 0xf143}, /* U+511B [2000] */ + {0xe5849e, 0x87cb}, /* U+511E [2000] */ + {0xe5849f, 0x8f9e}, /* U+511F */ + {0xe584a1, 0x9953}, /* U+5121 */ + {0xe584aa, 0x9744}, /* U+512A */ + {0xe584b2, 0x96d7}, /* U+5132 */ + {0xe584b5, 0x87cc}, /* U+5135 [2000] */ + {0xe584b7, 0x9955}, /* U+5137 */ + {0xe584ba, 0x9954}, /* U+513A */ + {0xe584bb, 0x9957}, /* U+513B */ + {0xe584bc, 0x9956}, /* U+513C */ + {0xe584bf, 0x9958}, /* U+513F */ + {0xe58580, 0x9959}, /* U+5140 */ + {0xe58581, 0x88f2}, /* U+5141 */ + {0xe58583, 0x8cb3}, /* U+5143 */ + {0xe58584, 0x8c5a}, /* U+5144 */ + {0xe58585, 0x8f5b}, /* U+5145 */ + {0xe58586, 0x929b}, /* U+5146 */ + {0xe58587, 0x8ba2}, /* U+5147 */ + {0xe58588, 0x90e6}, /* U+5148 */ + {0xe58589, 0x8cf5}, /* U+5149 */ + {0xe5858a, 0x87cd}, /* U+514A [2000] */ + {0xe5858b, 0x8d8e}, /* U+514B */ + {0xe5858c, 0x995b}, /* U+514C */ + {0xe5858d, 0x96c6}, /* U+514D */ + {0xe5858e, 0x9365}, /* U+514E */ + {0xe58590, 0x8e99}, /* U+5150 */ + {0xe58592, 0x995a}, /* U+5152 */ + {0xe58594, 0x995c}, /* U+5154 */ + {0xe58595, 0x87cf}, /* U+5155 [2000] */ + {0xe58597, 0x87d0}, /* U+5157 [2000] */ + {0xe5859a, 0x937d}, /* U+515A */ + {0xe5859c, 0x8a95}, /* U+515C */ + {0xe585a0, 0xf145}, /* U+5160 [2000] */ + {0xe585a2, 0x995d}, /* U+5162 */ + {0xe585a5, 0x93fc}, /* U+5165 */ + {0xe585a8, 0x9153}, /* U+5168 */ + {0xe585a9, 0x995f}, /* U+5169 */ + {0xe585aa, 0x9960}, /* U+516A */ + {0xe585ab, 0x94aa}, /* U+516B */ + {0xe585ac, 0x8cf6}, /* U+516C */ + {0xe585ad, 0x985a}, /* U+516D */ + {0xe585ae, 0x9961}, /* U+516E */ + {0xe585b1, 0x8ba4}, /* U+5171 */ + {0xe585b3, 0xf147}, /* U+5173 [2000] */ + {0xe585b5, 0x95ba}, /* U+5175 */ + {0xe585b6, 0x91b4}, /* U+5176 */ + {0xe585b7, 0x8bef}, /* U+5177 */ + {0xe585b8, 0x9354}, /* U+5178 */ + {0xe585bb, 0xf7f2}, /* U+517B [2000] */ + {0xe585bc, 0x8c93}, /* U+517C */ + {0xe58680, 0x9962}, /* U+5180 */ + {0xe58682, 0x9963}, /* U+5182 */ + {0xe58683, 0xf148}, /* U+5183 [2000] */ + {0xe58685, 0x93e0}, /* U+5185 */ + {0xe58686, 0x897e}, /* U+5186 */ + {0xe58689, 0x9966}, /* U+5189 */ + {0xe5868a, 0x8dfb}, /* U+518A */ + {0xe5868b, 0xf149}, /* U+518B [2000] */ + {0xe5868c, 0x9965}, /* U+518C */ + {0xe5868d, 0x8dc4}, /* U+518D */ + {0xe5868f, 0x9967}, /* U+518F */ + {0xe58690, 0xe3ec}, /* U+5190 */ + {0xe58691, 0x9968}, /* U+5191 */ + {0xe58692, 0x9660}, /* U+5192 */ + {0xe58693, 0x9969}, /* U+5193 */ + {0xe58695, 0x996a}, /* U+5195 */ + {0xe58696, 0x996b}, /* U+5196 */ + {0xe58697, 0x8fe7}, /* U+5197 */ + {0xe58698, 0xf14b}, /* U+5198 [2000] */ + {0xe58699, 0x8eca}, /* U+5199 */ + {0xe5869d, 0x87d2}, /* U+519D [2000] */ + {0xe586a0, 0x8aa5}, /* U+51A0 */ + {0xe586a2, 0x996e}, /* U+51A2 */ + {0xe586a3, 0xf14c}, /* U+51A3 [2000] */ + {0xe586a4, 0x996c}, /* U+51A4 */ + {0xe586a5, 0x96bb}, /* U+51A5 */ + {0xe586a6, 0x996d}, /* U+51A6 */ + {0xe586a8, 0x9579}, /* U+51A8 */ + {0xe586a9, 0x996f}, /* U+51A9 */ + {0xe586aa, 0x9970}, /* U+51AA */ + {0xe586ab, 0x9971}, /* U+51AB */ + {0xe586ac, 0x937e}, /* U+51AC */ + {0xe586ad, 0xf14d}, /* U+51AD [2000] */ + {0xe586b0, 0x9975}, /* U+51B0 */ + {0xe586b1, 0x9973}, /* U+51B1 */ + {0xe586b2, 0x9974}, /* U+51B2 */ + {0xe586b3, 0x9972}, /* U+51B3 */ + {0xe586b4, 0x8de1}, /* U+51B4 */ + {0xe586b5, 0x9976}, /* U+51B5 */ + {0xe586b6, 0x96e8}, /* U+51B6 */ + {0xe586b7, 0x97e2}, /* U+51B7 */ + {0xe586bc, 0xf14f}, /* U+51BC [2000] */ + {0xe586bd, 0x9977}, /* U+51BD */ + {0xe58783, 0x87d3}, /* U+51C3 [2000] */ + {0xe58784, 0x90a6}, /* U+51C4 */ + {0xe58785, 0x9978}, /* U+51C5 */ + {0xe58786, 0x8f79}, /* U+51C6 */ + {0xe58789, 0x9979}, /* U+51C9 */ + {0xe5878a, 0x87d4}, /* U+51CA [2000] */ + {0xe5878b, 0x929c}, /* U+51CB */ + {0xe5878c, 0x97bd}, /* U+51CC */ + {0xe5878d, 0x9380}, /* U+51CD */ + {0xe58796, 0x99c3}, /* U+51D6 */ + {0xe5879b, 0x997a}, /* U+51DB */ + {0xe5879c, 0xeaa3}, /* U+51DC [1990] */ + {0xe5879d, 0x8bc3}, /* U+51DD */ + {0xe5879e, 0x87d5}, /* U+51DE [2000] */ + {0xe587a0, 0x997b}, /* U+51E0 */ + {0xe587a1, 0x967d}, /* U+51E1 */ + {0xe587a2, 0x87d6}, /* U+51E2 [2000] */ + {0xe587a6, 0x8f88}, /* U+51E6 */ + {0xe587a7, 0x91fa}, /* U+51E7 */ + {0xe587a9, 0x997d}, /* U+51E9 */ + {0xe587aa, 0x93e2}, /* U+51EA */ + {0xe587ad, 0x997e}, /* U+51ED */ + {0xe587ae, 0x87d7}, /* U+51EE [2000] */ + {0xe587b0, 0x9980}, /* U+51F0 */ + {0xe587b1, 0x8a4d}, /* U+51F1 */ + {0xe587b3, 0xf152}, /* U+51F3 [2000] */ + {0xe587b4, 0xf153}, /* U+51F4 [2000] */ + {0xe587b5, 0x9981}, /* U+51F5 */ + {0xe587b6, 0x8ba5}, /* U+51F6 */ + {0xe587b8, 0x93ca}, /* U+51F8 */ + {0xe587b9, 0x899a}, /* U+51F9 */ + {0xe587ba, 0x8f6f}, /* U+51FA */ + {0xe587bd, 0x949f}, /* U+51FD */ + {0xe587be, 0x9982}, /* U+51FE */ + {0xe58880, 0x9381}, /* U+5200 */ + {0xe58881, 0x87d8}, /* U+5201 [2000] */ + {0xe58882, 0xf154}, /* U+5202 [2000] */ + {0xe58883, 0x906e}, /* U+5203 */ + {0xe58884, 0x9983}, /* U+5204 */ + {0xe58886, 0x95aa}, /* U+5206 */ + {0xe58887, 0x90d8}, /* U+5207 */ + {0xe58888, 0x8aa0}, /* U+5208 */ + {0xe5888a, 0x8aa7}, /* U+520A */ + {0xe5888b, 0x9984}, /* U+520B */ + {0xe5888e, 0x9986}, /* U+520E */ + {0xe58891, 0x8c59}, /* U+5211 */ + {0xe58892, 0xf155}, /* U+5212 [2000] */ + {0xe58893, 0x87da}, /* U+5213 [2000] */ + {0xe58894, 0x9985}, /* U+5214 */ + {0xe58895, 0x87db}, /* U+5215 [2000] */ + {0xe58896, 0xf156}, /* U+5216 [2000] */ + {0xe58897, 0x97f1}, /* U+5217 */ + {0xe5889d, 0x8f89}, /* U+521D */ + {0xe588a4, 0x94bb}, /* U+5224 */ + {0xe588a5, 0x95ca}, /* U+5225 */ + {0xe588a7, 0x9987}, /* U+5227 */ + {0xe588a9, 0x9798}, /* U+5229 */ + {0xe588aa, 0x9988}, /* U+522A */ + {0xe588ae, 0x9989}, /* U+522E */ + {0xe588b0, 0x939e}, /* U+5230 */ + {0xe588b3, 0x998a}, /* U+5233 */ + {0xe588b6, 0x90a7}, /* U+5236 */ + {0xe588b7, 0x8dfc}, /* U+5237 */ + {0xe588b8, 0x8c94}, /* U+5238 */ + {0xe588b9, 0x998b}, /* U+5239 */ + {0xe588ba, 0x8e68}, /* U+523A */ + {0xe588bb, 0x8d8f}, /* U+523B */ + {0xe58983, 0x92e4}, /* U+5243 */ + {0xe58984, 0x998d}, /* U+5244 */ + {0xe58987, 0x91a5}, /* U+5247 */ + {0xe58989, 0x87dc}, /* U+5249 [2000] */ + {0xe5898a, 0x8ded}, /* U+524A */ + {0xe5898b, 0x998e}, /* U+524B */ + {0xe5898c, 0x998f}, /* U+524C */ + {0xe5898d, 0x914f}, /* U+524D */ + {0xe5898f, 0x998c}, /* U+524F */ + {0xe58994, 0x9991}, /* U+5254 */ + {0xe58995, 0xf158}, /* U+5255 [2000] */ + {0xe58996, 0x9655}, /* U+5256 */ + {0xe58997, 0x87dd}, /* U+5257 [2000] */ + {0xe5899b, 0x8d84}, /* U+525B */ + {0xe5899c, 0xf159}, /* U+525C [2000] */ + {0xe5899d, 0x889e}, /* U+525D [2004] */ + {0xe5899e, 0x9990}, /* U+525E */ + {0xe589a1, 0x87de}, /* U+5261 [2000] */ + {0xe589a3, 0x8c95}, /* U+5263 */ + {0xe589a4, 0x8ddc}, /* U+5264 */ + {0xe589a5, 0x948d}, /* U+5265 */ + {0xe589a9, 0x9994}, /* U+5269 */ + {0xe589aa, 0x9992}, /* U+526A */ + {0xe589ac, 0xf15a}, /* U+526C [2000] */ + {0xe589af, 0x959b}, /* U+526F */ + {0xe589b0, 0x8fe8}, /* U+5270 */ + {0xe589b1, 0x999b}, /* U+5271 */ + {0xe589b2, 0x8a84}, /* U+5272 */ + {0xe589b3, 0x9995}, /* U+5273 */ + {0xe589b4, 0x9993}, /* U+5274 */ + {0xe589b5, 0x916e}, /* U+5275 */ + {0xe589b7, 0xf15b}, /* U+5277 [2000] */ + {0xe589bd, 0x9997}, /* U+527D */ + {0xe589bf, 0x9996}, /* U+527F */ + {0xe58a82, 0xf15d}, /* U+5282 [2000] */ + {0xe58a83, 0x8a63}, /* U+5283 */ + {0xe58a84, 0xf15c}, /* U+5284 [2000] */ + {0xe58a87, 0x8c80}, /* U+5287 */ + {0xe58a88, 0x999c}, /* U+5288 */ + {0xe58a89, 0x97ab}, /* U+5289 */ + {0xe58a8d, 0x9998}, /* U+528D */ + {0xe58a91, 0x999d}, /* U+5291 */ + {0xe58a92, 0x999a}, /* U+5292 */ + {0xe58a93, 0x87df}, /* U+5293 [2000] */ + {0xe58a94, 0x9999}, /* U+5294 */ + {0xe58a98, 0xf15f}, /* U+5298 [2000] */ + {0xe58a9b, 0x97cd}, /* U+529B */ + {0xe58a9f, 0x8cf7}, /* U+529F */ + {0xe58aa0, 0x89c1}, /* U+52A0 */ + {0xe58aa3, 0x97f2}, /* U+52A3 */ + {0xe58aa4, 0xf161}, /* U+52A4 [2000] */ + {0xe58aa6, 0xf162}, /* U+52A6 [2000] */ + {0xe58aa9, 0x8f95}, /* U+52A9 */ + {0xe58aaa, 0x9377}, /* U+52AA */ + {0xe58aab, 0x8d85}, /* U+52AB */ + {0xe58aac, 0x99a0}, /* U+52AC */ + {0xe58aad, 0x99a1}, /* U+52AD */ + {0xe58aaf, 0xf163}, /* U+52AF [2000] */ + {0xe58ab1, 0x97e3}, /* U+52B1 */ + {0xe58ab4, 0x984a}, /* U+52B4 */ + {0xe58ab5, 0x99a3}, /* U+52B5 */ + {0xe58ab9, 0x8cf8}, /* U+52B9 */ + {0xe58aba, 0xf164}, /* U+52BA [2000] */ + {0xe58abb, 0xf165}, /* U+52BB [2000] */ + {0xe58abc, 0x99a2}, /* U+52BC */ + {0xe58abe, 0x8a4e}, /* U+52BE */ + {0xe58b81, 0x99a4}, /* U+52C1 */ + {0xe58b83, 0x9675}, /* U+52C3 */ + {0xe58b85, 0x92ba}, /* U+52C5 */ + {0xe58b87, 0x9745}, /* U+52C7 */ + {0xe58b88, 0x87e0}, /* U+52C8 [2000] */ + {0xe58b89, 0x95d7}, /* U+52C9 */ + {0xe58b8a, 0xf166}, /* U+52CA [2000] */ + {0xe58b8c, 0x87e2}, /* U+52CC [2000] */ + {0xe58b8d, 0x99a5}, /* U+52CD */ + {0xe58b90, 0x87e3}, /* U+52D0 [2000] */ + {0xe58b91, 0xf168}, /* U+52D1 [2000] */ + {0xe58b92, 0xe8d3}, /* U+52D2 */ + {0xe58b95, 0x93ae}, /* U+52D5 */ + {0xe58b96, 0x87e4}, /* U+52D6 [2000] */ + {0xe58b97, 0x99a6}, /* U+52D7 */ + {0xe58b98, 0x8aa8}, /* U+52D8 */ + {0xe58b99, 0x96b1}, /* U+52D9 */ + {0xe58b9b, 0x87e5}, /* U+52DB [2000] */ + {0xe58b9d, 0x8f9f}, /* U+52DD */ + {0xe58b9e, 0x99a7}, /* U+52DE */ + {0xe58b9f, 0x95e5}, /* U+52DF */ + {0xe58ba0, 0x99ab}, /* U+52E0 */ + {0xe58ba2, 0x90a8}, /* U+52E2 */ + {0xe58ba3, 0x99a8}, /* U+52E3 */ + {0xe58ba4, 0x8bce}, /* U+52E4 */ + {0xe58ba6, 0x99a9}, /* U+52E6 */ + {0xe58ba7, 0x8aa9}, /* U+52E7 */ + {0xe58bb0, 0x87e7}, /* U+52F0 [2000] */ + {0xe58bb2, 0x8c4d}, /* U+52F2 */ + {0xe58bb3, 0x99ac}, /* U+52F3 */ + {0xe58bb5, 0x99ad}, /* U+52F5 */ + {0xe58bb7, 0xf16a}, /* U+52F7 [2000] */ + {0xe58bb8, 0x99ae}, /* U+52F8 */ + {0xe58bb9, 0x99af}, /* U+52F9 */ + {0xe58bba, 0x8ed9}, /* U+52FA */ + {0xe58bbb, 0x87e8}, /* U+52FB [2000] */ + {0xe58bbe, 0x8cf9}, /* U+52FE */ + {0xe58bbf, 0x96dc}, /* U+52FF */ + {0xe58c80, 0x87e9}, /* U+5300 [2000] */ + {0xe58c81, 0x96e6}, /* U+5301 */ + {0xe58c82, 0x93f5}, /* U+5302 */ + {0xe58c85, 0x95ef}, /* U+5305 */ + {0xe58c86, 0x99b0}, /* U+5306 */ + {0xe58c87, 0x87ea}, /* U+5307 [2000] */ + {0xe58c88, 0x99b1}, /* U+5308 */ + {0xe58c8a, 0xf16b}, /* U+530A [2000] */ + {0xe58c8b, 0xf16c}, /* U+530B [2000] */ + {0xe58c8d, 0x99b3}, /* U+530D */ + {0xe58c8f, 0x99b5}, /* U+530F */ + {0xe58c90, 0x99b4}, /* U+5310 */ + {0xe58c95, 0x99b6}, /* U+5315 */ + {0xe58c96, 0x89bb}, /* U+5316 */ + {0xe58c97, 0x966b}, /* U+5317 */ + {0xe58c99, 0x8dfa}, /* U+5319 */ + {0xe58c9a, 0x99b7}, /* U+531A */ + {0xe58c9c, 0x87eb}, /* U+531C [2000] */ + {0xe58c9d, 0x9178}, /* U+531D */ + {0xe58ca0, 0x8fa0}, /* U+5320 */ + {0xe58ca1, 0x8ba7}, /* U+5321 */ + {0xe58ca3, 0x99b8}, /* U+5323 */ + {0xe58ca4, 0xf16d}, /* U+5324 [2000] */ + {0xe58caa, 0x94d9}, /* U+532A */ + {0xe58caf, 0x99b9}, /* U+532F */ + {0xe58cb1, 0x99ba}, /* U+5331 */ + {0xe58cb3, 0x99bb}, /* U+5333 */ + {0xe58cb5, 0xf16e}, /* U+5335 [2000] */ + {0xe58cb8, 0x99bc}, /* U+5338 */ + {0xe58cb9, 0x9543}, /* U+5339 */ + {0xe58cba, 0x8be6}, /* U+533A */ + {0xe58cbb, 0x88e3}, /* U+533B */ + {0xe58cbe, 0xf16f}, /* U+533E [2000] */ + {0xe58cbf, 0x93bd}, /* U+533F */ + {0xe58d80, 0x99bd}, /* U+5340 */ + {0xe58d81, 0x8f5c}, /* U+5341 */ + {0xe58d82, 0xf170}, /* U+5342 [2000] */ + {0xe58d83, 0x90e7}, /* U+5343 */ + {0xe58d85, 0x99bf}, /* U+5345 */ + {0xe58d86, 0x99be}, /* U+5346 */ + {0xe58d87, 0x8fa1}, /* U+5347 */ + {0xe58d88, 0x8cdf}, /* U+5348 */ + {0xe58d89, 0x99c1}, /* U+5349 */ + {0xe58d8a, 0x94bc}, /* U+534A */ + {0xe58d8d, 0x99c2}, /* U+534D */ + {0xe58d91, 0x94da}, /* U+5351 */ + {0xe58d92, 0x91b2}, /* U+5352 */ + {0xe58d93, 0x91ec}, /* U+5353 */ + {0xe58d94, 0x8ba6}, /* U+5354 */ + {0xe58d97, 0x93ec}, /* U+5357 */ + {0xe58d98, 0x9250}, /* U+5358 */ + {0xe58d9a, 0x948e}, /* U+535A */ + {0xe58d9c, 0x966d}, /* U+535C */ + {0xe58d9e, 0x99c4}, /* U+535E */ + {0xe58da0, 0x90e8}, /* U+5360 */ + {0xe58da1, 0x87ed}, /* U+5361 [2000] */ + {0xe58da3, 0x87ee}, /* U+5363 [2000] */ + {0xe58da6, 0x8c54}, /* U+5366 */ + {0xe58da7, 0xf173}, /* U+5367 [2000] */ + {0xe58da9, 0x99c5}, /* U+5369 */ + {0xe58dac, 0xf174}, /* U+536C [2000] */ + {0xe58dae, 0x99c6}, /* U+536E */ + {0xe58daf, 0x894b}, /* U+536F */ + {0xe58db0, 0x88f3}, /* U+5370 */ + {0xe58db1, 0x8aeb}, /* U+5371 */ + {0xe58db3, 0x91a6}, /* U+5373 */ + {0xe58db4, 0x8b70}, /* U+5374 */ + {0xe58db5, 0x9791}, /* U+5375 */ + {0xe58db7, 0x99c9}, /* U+5377 */ + {0xe58db8, 0x89b5}, /* U+5378 */ + {0xe58dba, 0xf175}, /* U+537A [2000] */ + {0xe58dbb, 0x99c8}, /* U+537B */ + {0xe58dbd, 0x87ef}, /* U+537D [2000] */ + {0xe58dbf, 0x8ba8}, /* U+537F */ + {0xe58e82, 0x99ca}, /* U+5382 */ + {0xe58e84, 0x96ef}, /* U+5384 */ + {0xe58e93, 0x87f0}, /* U+5393 [2000] */ + {0xe58e96, 0x99cb}, /* U+5396 */ + {0xe58e98, 0x97d0}, /* U+5398 */ + {0xe58e9a, 0x8cfa}, /* U+539A */ + {0xe58e9d, 0x87f1}, /* U+539D [2000] */ + {0xe58e9f, 0x8cb4}, /* U+539F */ + {0xe58ea0, 0x99cc}, /* U+53A0 */ + {0xe58ea4, 0xf176}, /* U+53A4 [2000] */ + {0xe58ea5, 0x99ce}, /* U+53A5 */ + {0xe58ea6, 0x99cd}, /* U+53A6 */ + {0xe58ea8, 0x907e}, /* U+53A8 */ + {0xe58ea9, 0x8958}, /* U+53A9 */ + {0xe58ead, 0x897d}, /* U+53AD */ + {0xe58eae, 0x99cf}, /* U+53AE */ + {0xe58eb0, 0x99d0}, /* U+53B0 */ + {0xe58eb2, 0x87f2}, /* U+53B2 [2000] */ + {0xe58eb3, 0x8cb5}, /* U+53B3 */ + {0xe58eb4, 0xf177}, /* U+53B4 [2000] */ + {0xe58eb6, 0x99d1}, /* U+53B6 */ + {0xe58eb7, 0xf179}, /* U+53B7 [2000] */ + {0xe58ebb, 0x8b8e}, /* U+53BB */ + {0xe58f80, 0xf17a}, /* U+53C0 [2000] */ + {0xe58f82, 0x8e51}, /* U+53C2 */ + {0xe58f83, 0x99d2}, /* U+53C3 */ + {0xe58f88, 0x9694}, /* U+53C8 */ + {0xe58f89, 0x8db3}, /* U+53C9 */ + {0xe58f8a, 0x8b79}, /* U+53CA */ + {0xe58f8b, 0x9746}, /* U+53CB */ + {0xe58f8c, 0x916f}, /* U+53CC */ + {0xe58f8d, 0x94bd}, /* U+53CD */ + {0xe58f8e, 0x8efb}, /* U+53CE */ + {0xe58f94, 0x8f66}, /* U+53D4 */ + {0xe58f95, 0xf17e}, /* U+53D5 [2000] */ + {0xe58f96, 0x8ee6}, /* U+53D6 */ + {0xe58f97, 0x8ef3}, /* U+53D7 */ + {0xe58f99, 0x8f96}, /* U+53D9 */ + {0xe58f9a, 0xf180}, /* U+53DA [2000] */ + {0xe58f9b, 0x94be}, /* U+53DB */ + {0xe58f9f, 0x99d5}, /* U+53DF */ + {0xe58fa1, 0x8962}, /* U+53E1 */ + {0xe58fa2, 0x9170}, /* U+53E2 */ + {0xe58fa3, 0x8cfb}, /* U+53E3 */ + {0xe58fa4, 0x8cc3}, /* U+53E4 */ + {0xe58fa5, 0x8be5}, /* U+53E5 */ + {0xe58fa8, 0x99d9}, /* U+53E8 */ + {0xe58fa9, 0x9240}, /* U+53E9 */ + {0xe58faa, 0x91fc}, /* U+53EA */ + {0xe58fab, 0x8ba9}, /* U+53EB */ + {0xe58fac, 0x8fa2}, /* U+53EC */ + {0xe58fad, 0x99da}, /* U+53ED */ + {0xe58fae, 0x99d8}, /* U+53EE */ + {0xe58faf, 0x89c2}, /* U+53EF */ + {0xe58fb0, 0x91e4}, /* U+53F0 */ + {0xe58fb1, 0x8eb6}, /* U+53F1 */ + {0xe58fb2, 0x8e6a}, /* U+53F2 */ + {0xe58fb3, 0x8945}, /* U+53F3 */ + {0xe58fb4, 0xf182}, /* U+53F4 [2000] */ + {0xe58fb5, 0xf183}, /* U+53F5 [2000] */ + {0xe58fb6, 0x8a90}, /* U+53F6 */ + {0xe58fb7, 0x8d86}, /* U+53F7 */ + {0xe58fb8, 0x8e69}, /* U+53F8 */ + {0xe58fba, 0x99db}, /* U+53FA */ + {0xe59081, 0x99dc}, /* U+5401 */ + {0xe59083, 0x8b68}, /* U+5403 */ + {0xe59084, 0x8a65}, /* U+5404 */ + {0xe59088, 0x8d87}, /* U+5408 */ + {0xe59089, 0x8b67}, /* U+5409 */ + {0xe5908a, 0x92dd}, /* U+540A */ + {0xe5908b, 0x8944}, /* U+540B */ + {0xe5908c, 0x93af}, /* U+540C */ + {0xe5908d, 0x96bc}, /* U+540D */ + {0xe5908e, 0x8d40}, /* U+540E */ + {0xe5908f, 0x9799}, /* U+540F */ + {0xe59090, 0x9366}, /* U+5410 */ + {0xe59091, 0x8cfc}, /* U+5411 */ + {0xe59092, 0x87f3}, /* U+5412 [2000] */ + {0xe5909b, 0x8c4e}, /* U+541B */ + {0xe5909d, 0x99e5}, /* U+541D */ + {0xe5909e, 0x989e}, /* U+541E [2004] */ + {0xe5909f, 0x8be1}, /* U+541F */ + {0xe590a0, 0x9669}, /* U+5420 */ + {0xe590a4, 0xf185}, /* U+5424 [2000] */ + {0xe590a6, 0x94db}, /* U+5426 */ + {0xe590a7, 0x87f4}, /* U+5427 [2000] */ + {0xe590a8, 0xf186}, /* U+5428 [2000] */ + {0xe590a9, 0x99e4}, /* U+5429 */ + {0xe590ab, 0x8adc}, /* U+542B */ + {0xe590ac, 0x99df}, /* U+542C */ + {0xe590ad, 0x99e0}, /* U+542D */ + {0xe590ae, 0x99e2}, /* U+542E */ + {0xe590b6, 0x99e3}, /* U+5436 */ + {0xe590b8, 0x8b7a}, /* U+5438 */ + {0xe590b9, 0x9081}, /* U+5439 */ + {0xe590bb, 0x95ab}, /* U+543B */ + {0xe590bc, 0x99e1}, /* U+543C */ + {0xe590bd, 0x99dd}, /* U+543D */ + {0xe590be, 0x8ce1}, /* U+543E */ + {0xe59180, 0x99de}, /* U+5440 */ + {0xe59182, 0x9843}, /* U+5442 */ + {0xe59183, 0xf188}, /* U+5443 [2000] */ + {0xe59186, 0x95f0}, /* U+5446 */ + {0xe59188, 0x92e6}, /* U+5448 */ + {0xe59189, 0x8ce0}, /* U+5449 */ + {0xe5918a, 0x8d90}, /* U+544A */ + {0xe5918d, 0x87f5}, /* U+544D [2000] */ + {0xe5918e, 0x99e6}, /* U+544E */ + {0xe59191, 0x93db}, /* U+5451 */ + {0xe59195, 0xf184}, /* U+5455 [2000] */ + {0xe5919f, 0x99ea}, /* U+545F */ + {0xe591a2, 0xf189}, /* U+5462 [2000] */ + {0xe591a6, 0xf18a}, /* U+5466 [2000] */ + {0xe591a8, 0x8efc}, /* U+5468 */ + {0xe591aa, 0x8ef4}, /* U+546A */ + {0xe591ab, 0x87f7}, /* U+546B [2000] */ + {0xe591ac, 0xf18b}, /* U+546C [2000] */ + {0xe591b0, 0x99ed}, /* U+5470 */ + {0xe591b1, 0x99eb}, /* U+5471 */ + {0xe591b3, 0x96a1}, /* U+5473 */ + {0xe591b4, 0x87f8}, /* U+5474 [2000] */ + {0xe591b5, 0x99e8}, /* U+5475 */ + {0xe591b6, 0x99f1}, /* U+5476 */ + {0xe591b7, 0x99ec}, /* U+5477 */ + {0xe591bb, 0x99ef}, /* U+547B */ + {0xe591bc, 0x8cc4}, /* U+547C */ + {0xe591bd, 0x96bd}, /* U+547D */ + {0xe591bf, 0x87f9}, /* U+547F [2000] */ + {0xe59280, 0x99f0}, /* U+5480 */ + {0xe59284, 0x99f2}, /* U+5484 */ + {0xe59286, 0x99f4}, /* U+5486 */ + {0xe59288, 0x87fa}, /* U+5488 [2000] */ + {0xe5928a, 0xf18c}, /* U+548A [2000] */ + {0xe5928b, 0x8dee}, /* U+548B */ + {0xe5928c, 0x9861}, /* U+548C */ + {0xe5928d, 0xf18d}, /* U+548D [2000] */ + {0xe5928e, 0x99e9}, /* U+548E */ + {0xe5928f, 0x99e7}, /* U+548F */ + {0xe59290, 0x99f3}, /* U+5490 */ + {0xe59292, 0x99ee}, /* U+5492 */ + {0xe59295, 0xf18e}, /* U+5495 [2000] */ + {0xe59296, 0x87fb}, /* U+5496 [2000] */ + {0xe5929c, 0x87f6}, /* U+549C [2000] */ + {0xe592a0, 0xf18f}, /* U+54A0 [2000] */ + {0xe592a1, 0x87fc}, /* U+54A1 [2000] */ + {0xe592a2, 0x99f6}, /* U+54A2 */ + {0xe592a4, 0x9a42}, /* U+54A4 */ + {0xe592a5, 0x99f8}, /* U+54A5 */ + {0xe592a6, 0xf190}, /* U+54A6 [2000] */ + {0xe592a8, 0x99fc}, /* U+54A8 */ + {0xe592a9, 0x8840}, /* U+54A9 [2000] */ + {0xe592ab, 0x9a40}, /* U+54AB */ + {0xe592ac, 0x99f9}, /* U+54AC */ + {0xe592ad, 0xf191}, /* U+54AD [2000] */ + {0xe592ae, 0xf192}, /* U+54AE [2000] */ + {0xe592af, 0x9a5d}, /* U+54AF */ + {0xe592b2, 0x8de7}, /* U+54B2 */ + {0xe592b3, 0x8a50}, /* U+54B3 */ + {0xe592b7, 0xf193}, /* U+54B7 [2000] */ + {0xe592b8, 0x99f7}, /* U+54B8 */ + {0xe592ba, 0xf194}, /* U+54BA [2000] */ + {0xe592bc, 0x9a44}, /* U+54BC */ + {0xe592bd, 0x88f4}, /* U+54BD */ + {0xe592be, 0x9a43}, /* U+54BE */ + {0xe592bf, 0xf195}, /* U+54BF [2000] */ + {0xe59380, 0x88a3}, /* U+54C0 */ + {0xe59381, 0x9569}, /* U+54C1 */ + {0xe59382, 0x9a41}, /* U+54C2 */ + {0xe59383, 0xf196}, /* U+54C3 [2000] */ + {0xe59384, 0x99fa}, /* U+54C4 */ + {0xe59386, 0x8841}, /* U+54C6 [2000] */ + {0xe59387, 0x99f5}, /* U+54C7 */ + {0xe59388, 0x99fb}, /* U+54C8 */ + {0xe59389, 0x8dc6}, /* U+54C9 */ + {0xe59398, 0x9a45}, /* U+54D8 */ + {0xe593a1, 0x88f5}, /* U+54E1 */ + {0xe593a2, 0x9a4e}, /* U+54E2 */ + {0xe593a5, 0x9a46}, /* U+54E5 */ + {0xe593a6, 0x9a47}, /* U+54E6 */ + {0xe593a8, 0x8fa3}, /* U+54E8 */ + {0xe593a9, 0x9689}, /* U+54E9 */ + {0xe593ac, 0xf198}, /* U+54EC [2000] */ + {0xe593ad, 0x9a4c}, /* U+54ED */ + {0xe593ae, 0x9a4b}, /* U+54EE */ + {0xe593af, 0xf199}, /* U+54EF [2000] */ + {0xe593b1, 0xf19a}, /* U+54F1 [2000] */ + {0xe593b2, 0x934e}, /* U+54F2 */ + {0xe593b3, 0xf19b}, /* U+54F3 [2000] */ + {0xe593ba, 0x9a4d}, /* U+54FA */ + {0xe593bd, 0x9a4a}, /* U+54FD */ + {0xe593bf, 0x8842}, /* U+54FF [2000] */ + {0xe59480, 0xf19c}, /* U+5500 [2000] */ + {0xe59481, 0xf19d}, /* U+5501 [2000] */ + {0xe59484, 0x8953}, /* U+5504 */ + {0xe59486, 0x8db4}, /* U+5506 */ + {0xe59487, 0x904f}, /* U+5507 */ + {0xe59489, 0xf19e}, /* U+5509 [2000] */ + {0xe5948e, 0x8843}, /* U+550E [2000] */ + {0xe5948f, 0x9a48}, /* U+550F */ + {0xe59490, 0x9382}, /* U+5510 */ + {0xe59494, 0x9a49}, /* U+5514 */ + {0xe59496, 0x88a0}, /* U+5516 */ + {0xe594ab, 0x8844}, /* U+552B [2000] */ + {0xe594ae, 0x9a53}, /* U+552E */ + {0xe594af, 0x9742}, /* U+552F */ + {0xe594b1, 0x8fa5}, /* U+5531 */ + {0xe594b3, 0x9a59}, /* U+5533 */ + {0xe594b5, 0x8845}, /* U+5535 [2000] */ + {0xe594b8, 0x9a58}, /* U+5538 */ + {0xe594b9, 0x9a4f}, /* U+5539 */ + {0xe594bc, 0xf19f}, /* U+553C [2000] */ + {0xe594be, 0x91c1}, /* U+553E */ + {0xe59580, 0x9a50}, /* U+5540 */ + {0xe59581, 0xf1a0}, /* U+5541 [2000] */ + {0xe59584, 0x91ed}, /* U+5544 */ + {0xe59585, 0x9a55}, /* U+5545 */ + {0xe59586, 0x8fa4}, /* U+5546 */ + {0xe59587, 0xf1a2}, /* U+5547 [2000] */ + {0xe5958a, 0xf1a3}, /* U+554A [2000] */ + {0xe5958c, 0x9a52}, /* U+554C */ + {0xe5958f, 0x96e2}, /* U+554F */ + {0xe59590, 0x8846}, /* U+5550 [2000] */ + {0xe59593, 0x8c5b}, /* U+5553 */ + {0xe59596, 0x9a56}, /* U+5556 */ + {0xe59597, 0x9a57}, /* U+5557 */ + {0xe5959c, 0x9a54}, /* U+555C */ + {0xe5959d, 0x9a5a}, /* U+555D */ + {0xe5959e, 0x8847}, /* U+555E [2000] */ + {0xe595a0, 0xf1a5}, /* U+5560 [2000] */ + {0xe595a1, 0xf1a6}, /* U+5561 [2000] */ + {0xe595a3, 0x9a51}, /* U+5563 */ + {0xe595a4, 0xf1a7}, /* U+5564 [2000] */ + {0xe595bb, 0x9a60}, /* U+557B */ + {0xe595bc, 0x9a65}, /* U+557C */ + {0xe595bd, 0xf1a9}, /* U+557D [2000] */ + {0xe595be, 0x9a61}, /* U+557E */ + {0xe59680, 0x9a5c}, /* U+5580 */ + {0xe59681, 0x8848}, /* U+5581 [2000] */ + {0xe59682, 0xf1aa}, /* U+5582 [2000] */ + {0xe59683, 0x9a66}, /* U+5583 */ + {0xe59684, 0x9150}, /* U+5584 */ + {0xe59686, 0x8849}, /* U+5586 [2000] */ + {0xe59687, 0x9a68}, /* U+5587 */ + {0xe59688, 0xf1ab}, /* U+5588 [2000] */ + {0xe59689, 0x8d41}, /* U+5589 */ + {0xe5968a, 0x9a5e}, /* U+558A */ + {0xe5968b, 0x929d}, /* U+558B */ + {0xe5968e, 0x884a}, /* U+558E [2000] */ + {0xe59691, 0xf1ac}, /* U+5591 [2000] */ + {0xe59698, 0x9a62}, /* U+5598 */ + {0xe59699, 0x9a5b}, /* U+5599 */ + {0xe5969a, 0x8aab}, /* U+559A */ + {0xe5969c, 0x8aec}, /* U+559C */ + {0xe5969d, 0x8a85}, /* U+559D */ + {0xe5969e, 0x9a63}, /* U+559E */ + {0xe5969f, 0x9a5f}, /* U+559F */ + {0xe596a7, 0x8c96}, /* U+55A7 */ + {0xe596a8, 0x9a69}, /* U+55A8 */ + {0xe596a9, 0x9a67}, /* U+55A9 */ + {0xe596aa, 0x9172}, /* U+55AA */ + {0xe596ab, 0x8b69}, /* U+55AB */ + {0xe596ac, 0x8baa}, /* U+55AC */ + {0xe596ad, 0x884c}, /* U+55AD [2000] */ + {0xe596ae, 0x9a64}, /* U+55AE */ + {0xe596b0, 0x8bf2}, /* U+55B0 */ + {0xe596b6, 0x8963}, /* U+55B6 */ + {0xe596bf, 0xf1b1}, /* U+55BF [2000] */ + {0xe59784, 0x9a6d}, /* U+55C4 */ + {0xe59785, 0x9a6b}, /* U+55C5 */ + {0xe59787, 0x9aa5}, /* U+55C7 */ + {0xe59789, 0xf1b2}, /* U+55C9 [2000] */ + {0xe5978c, 0xf1b3}, /* U+55CC [2000] */ + {0xe5978e, 0x884d}, /* U+55CE [2000] */ + {0xe59791, 0xf1b4}, /* U+55D1 [2000] */ + {0xe59792, 0xf1ae}, /* U+55D2 [2000] */ + {0xe59794, 0x9a70}, /* U+55D4 */ + {0xe5979a, 0x9a6a}, /* U+55DA */ + {0xe5979c, 0x9a6e}, /* U+55DC */ + {0xe5979d, 0xf1b5}, /* U+55DD [2000] */ + {0xe5979f, 0x9a6c}, /* U+55DF */ + {0xe597a2, 0xf1b7}, /* U+55E2 [2000] */ + {0xe597a3, 0x8e6b}, /* U+55E3 */ + {0xe597a4, 0x9a6f}, /* U+55E4 */ + {0xe597a9, 0xf1b9}, /* U+55E9 [2000] */ + {0xe597b7, 0x9a72}, /* U+55F7 */ + {0xe597b9, 0x9a77}, /* U+55F9 */ + {0xe597bd, 0x9a75}, /* U+55FD */ + {0xe597be, 0x9a74}, /* U+55FE */ + {0xe59886, 0x9251}, /* U+5606 */ + {0xe59887, 0xf1bc}, /* U+5607 [2000] */ + {0xe59888, 0x884f}, /* U+5608 [2000] */ + {0xe59889, 0x89c3}, /* U+5609 */ + {0xe5988e, 0x8850}, /* U+560E [2000] */ + {0xe59890, 0xf1bd}, /* U+5610 [2000] */ + {0xe59894, 0x9a71}, /* U+5614 */ + {0xe59896, 0x9a73}, /* U+5616 */ + {0xe59897, 0x8fa6}, /* U+5617 */ + {0xe59898, 0x8952}, /* U+5618 */ + {0xe5989b, 0x9a76}, /* U+561B */ + {0xe598a8, 0xf1ba}, /* U+5628 [2000] */ + {0xe598a9, 0x89dc}, /* U+5629 */ + {0xe598af, 0x9a82}, /* U+562F */ + {0xe598b0, 0xf1be}, /* U+5630 [2000] */ + {0xe598b1, 0x8ffa}, /* U+5631 */ + {0xe598b2, 0x9a7d}, /* U+5632 */ + {0xe598b4, 0x9a7b}, /* U+5634 */ + {0xe598b6, 0x9a7c}, /* U+5636 */ + {0xe598b7, 0xf1bf}, /* U+5637 [2000] */ + {0xe598b8, 0x9a7e}, /* U+5638 */ + {0xe598bb, 0x8851}, /* U+563B [2000] */ + {0xe598bd, 0xf1c1}, /* U+563D [2000] */ + {0xe598bf, 0xf1c2}, /* U+563F [2000] */ + {0xe59980, 0xf1c3}, /* U+5640 [2000] */ + {0xe59982, 0x895c}, /* U+5642 */ + {0xe59987, 0xf1c4}, /* U+5647 [2000] */ + {0xe59989, 0x8852}, /* U+5649 [2000] */ + {0xe5998c, 0x9158}, /* U+564C */ + {0xe5998e, 0x9a78}, /* U+564E */ + {0xe59990, 0x9a79}, /* U+5650 */ + {0xe59993, 0xeaa5}, /* U+5653 [2004] */ + {0xe5999b, 0x8a9a}, /* U+565B */ + {0xe5999e, 0xf1c5}, /* U+565E [2000] */ + {0xe599a0, 0xf1c6}, /* U+5660 [2000] */ + {0xe599a4, 0x9a81}, /* U+5664 */ + {0xe599a6, 0x8854}, /* U+5666 [2000] */ + {0xe599a8, 0x8aed}, /* U+5668 */ + {0xe599aa, 0x9a84}, /* U+566A */ + {0xe599ab, 0x9a80}, /* U+566B */ + {0xe599ac, 0x9a83}, /* U+566C */ + {0xe599ad, 0xf1c7}, /* U+566D [2000] */ + {0xe599af, 0x8856}, /* U+566F [2000] */ + {0xe599b1, 0x8857}, /* U+5671 [2000] */ + {0xe599b2, 0x8858}, /* U+5672 [2000] */ + {0xe599b4, 0x95ac}, /* U+5674 */ + {0xe599b6, 0x8853}, /* U+5676 [2000] */ + {0xe599b8, 0x93d3}, /* U+5678 */ + {0xe599ba, 0x94b6}, /* U+567A */ + {0xe59a80, 0x9a86}, /* U+5680 */ + {0xe59a86, 0x9a85}, /* U+5686 */ + {0xe59a87, 0x8a64}, /* U+5687 */ + {0xe59a88, 0xf1c9}, /* U+5688 [2000] */ + {0xe59a8a, 0x9a87}, /* U+568A */ + {0xe59a8c, 0xf1ca}, /* U+568C [2000] */ + {0xe59a8f, 0x9a8a}, /* U+568F */ + {0xe59a94, 0x9a89}, /* U+5694 */ + {0xe59a95, 0xf1cb}, /* U+5695 [2000] */ + {0xe59a99, 0x8859}, /* U+5699 [2000] */ + {0xe59a9a, 0xf1cc}, /* U+569A [2000] */ + {0xe59a9d, 0xf1cd}, /* U+569D [2000] */ + {0xe59a9e, 0x885a}, /* U+569E [2000] */ + {0xe59aa0, 0x9a88}, /* U+56A0 */ + {0xe59aa2, 0x9458}, /* U+56A2 */ + {0xe59aa5, 0x9a8b}, /* U+56A5 */ + {0xe59aa8, 0xf1ce}, /* U+56A8 [2000] */ + {0xe59aa9, 0x885b}, /* U+56A9 [2000] */ + {0xe59aac, 0x885c}, /* U+56AC [2000] */ + {0xe59aad, 0xf1cf}, /* U+56AD [2000] */ + {0xe59aae, 0x9a8c}, /* U+56AE */ + {0xe59ab2, 0xf1d0}, /* U+56B2 [2000] */ + {0xe59ab3, 0x885d}, /* U+56B3 [2000] */ + {0xe59ab4, 0x9a8e}, /* U+56B4 */ + {0xe59ab6, 0x9a8d}, /* U+56B6 */ + {0xe59abc, 0x9a90}, /* U+56BC */ + {0xe59b80, 0x9a93}, /* U+56C0 */ + {0xe59b81, 0x9a91}, /* U+56C1 */ + {0xe59b82, 0x9a8f}, /* U+56C2 */ + {0xe59b83, 0x9a92}, /* U+56C3 */ + {0xe59b85, 0xf1d1}, /* U+56C5 [2000] */ + {0xe59b88, 0x9a94}, /* U+56C8 */ + {0xe59b89, 0x885e}, /* U+56C9 [2000] */ + {0xe59b8a, 0x885f}, /* U+56CA [2000] */ + {0xe59b8d, 0xf1d2}, /* U+56CD [2000] */ + {0xe59b8e, 0x9a95}, /* U+56CE */ + {0xe59b91, 0x9a96}, /* U+56D1 */ + {0xe59b93, 0x9a97}, /* U+56D3 */ + {0xe59b97, 0x9a98}, /* U+56D7 */ + {0xe59b98, 0x9964}, /* U+56D8 */ + {0xe59b9a, 0x8efa}, /* U+56DA */ + {0xe59b9b, 0x8e6c}, /* U+56DB */ + {0xe59b9e, 0x89f1}, /* U+56DE */ + {0xe59b9f, 0xf1d3}, /* U+56DF [2000] */ + {0xe59ba0, 0x88f6}, /* U+56E0 */ + {0xe59ba3, 0x9263}, /* U+56E3 */ + {0xe59ba8, 0xf1d4}, /* U+56E8 [2000] */ + {0xe59bae, 0x9a99}, /* U+56EE */ + {0xe59bb0, 0x8da2}, /* U+56F0 */ + {0xe59bb2, 0x88cd}, /* U+56F2 */ + {0xe59bb3, 0x907d}, /* U+56F3 */ + {0xe59bb6, 0xf1d5}, /* U+56F6 [2000] */ + {0xe59bb7, 0xf1d6}, /* U+56F7 [2000] */ + {0xe59bb9, 0x9a9a}, /* U+56F9 */ + {0xe59bba, 0x8cc5}, /* U+56FA */ + {0xe59bbd, 0x8d91}, /* U+56FD */ + {0xe59bbf, 0x9a9c}, /* U+56FF */ + {0xe59c80, 0x9a9b}, /* U+5700 */ + {0xe59c83, 0x95de}, /* U+5703 */ + {0xe59c84, 0x9a9d}, /* U+5704 */ + {0xe59c88, 0x9a9f}, /* U+5708 */ + {0xe59c89, 0x9a9e}, /* U+5709 */ + {0xe59c8a, 0x8860}, /* U+570A [2000] */ + {0xe59c8b, 0x9aa0}, /* U+570B */ + {0xe59c8d, 0x9aa1}, /* U+570D */ + {0xe59c8f, 0x8c97}, /* U+570F */ + {0xe59c92, 0x8980}, /* U+5712 */ + {0xe59c93, 0x9aa2}, /* U+5713 */ + {0xe59c95, 0xf1d8}, /* U+5715 [2000] */ + {0xe59c96, 0x9aa4}, /* U+5716 */ + {0xe59c98, 0x9aa3}, /* U+5718 */ + {0xe59c9c, 0x9aa6}, /* U+571C */ + {0xe59c9f, 0x9379}, /* U+571F */ + {0xe59ca1, 0x8862}, /* U+5721 [2000] */ + {0xe59ca3, 0xf1d9}, /* U+5723 [2000] */ + {0xe59ca6, 0x9aa7}, /* U+5726 */ + {0xe59ca7, 0x88b3}, /* U+5727 */ + {0xe59ca8, 0x8ddd}, /* U+5728 */ + {0xe59ca9, 0xf1db}, /* U+5729 [2000] */ + {0xe59cad, 0x8c5c}, /* U+572D */ + {0xe59caf, 0x8863}, /* U+572F [2000] */ + {0xe59cb0, 0x926e}, /* U+5730 */ + {0xe59cb3, 0x8864}, /* U+5733 [2000] */ + {0xe59cb4, 0x8865}, /* U+5734 [2000] */ + {0xe59cb7, 0x9aa8}, /* U+5737 */ + {0xe59cb8, 0x9aa9}, /* U+5738 */ + {0xe59cbb, 0x9aab}, /* U+573B */ + {0xe59d80, 0x9aac}, /* U+5740 */ + {0xe59d82, 0x8de2}, /* U+5742 */ + {0xe59d85, 0xf1dd}, /* U+5745 [2000] */ + {0xe59d86, 0xf1de}, /* U+5746 [2000] */ + {0xe59d87, 0x8bcf}, /* U+5747 */ + {0xe59d8a, 0x9656}, /* U+574A */ + {0xe59d8c, 0xf1df}, /* U+574C [2000] */ + {0xe59d8d, 0xf1e0}, /* U+574D [2000] */ + {0xe59d8e, 0x9aaa}, /* U+574E */ + {0xe59d8f, 0x9aad}, /* U+574F */ + {0xe59d90, 0x8dbf}, /* U+5750 */ + {0xe59d91, 0x8d42}, /* U+5751 */ + {0xe59da1, 0x9ab1}, /* U+5761 */ + {0xe59da4, 0x8da3}, /* U+5764 */ + {0xe59da6, 0x9252}, /* U+5766 */ + {0xe59da8, 0xf1e2}, /* U+5768 [2000] */ + {0xe59da9, 0x9aae}, /* U+5769 */ + {0xe59daa, 0x92d8}, /* U+576A */ + {0xe59daf, 0xf1e3}, /* U+576F [2000] */ + {0xe59db0, 0x8866}, /* U+5770 [2000] */ + {0xe59db3, 0xf1e4}, /* U+5773 [2000] */ + {0xe59db4, 0xf1e5}, /* U+5774 [2000] */ + {0xe59db5, 0xf1e6}, /* U+5775 [2000] */ + {0xe59db7, 0x8867}, /* U+5777 [2000] */ + {0xe59dbb, 0xf1e7}, /* U+577B [2000] */ + {0xe59dbc, 0x8868}, /* U+577C [2000] */ + {0xe59dbf, 0x9ab2}, /* U+577F */ + {0xe59e82, 0x9082}, /* U+5782 */ + {0xe59e88, 0x9ab0}, /* U+5788 */ + {0xe59e89, 0x9ab3}, /* U+5789 */ + {0xe59e8b, 0x8c5e}, /* U+578B */ + {0xe59e93, 0x9ab4}, /* U+5793 */ + {0xe59e9a, 0xf1eb}, /* U+579A [2000] */ + {0xe59e9c, 0x8869}, /* U+579C [2000] */ + {0xe59e9d, 0xf1ec}, /* U+579D [2000] */ + {0xe59e9e, 0xf1ed}, /* U+579E [2000] */ + {0xe59ea0, 0x9ab5}, /* U+57A0 */ + {0xe59ea2, 0x8d43}, /* U+57A2 */ + {0xe59ea3, 0x8a5f}, /* U+57A3 */ + {0xe59ea4, 0x9ab7}, /* U+57A4 */ + {0xe59ea8, 0xf1ee}, /* U+57A8 [2000] */ + {0xe59eaa, 0x9ab8}, /* U+57AA */ + {0xe59eac, 0xf1ea}, /* U+57AC [2000] */ + {0xe59eb0, 0x9ab9}, /* U+57B0 */ + {0xe59eb3, 0x9ab6}, /* U+57B3 */ + {0xe59eb8, 0x886c}, /* U+57B8 [2000] */ + {0xe59f80, 0x9aaf}, /* U+57C0 */ + {0xe59f83, 0x9aba}, /* U+57C3 */ + {0xe59f86, 0x9abb}, /* U+57C6 */ + {0xe59f87, 0x886d}, /* U+57C7 [2000] */ + {0xe59f88, 0x886e}, /* U+57C8 [2000] */ + {0xe59f8b, 0x9684}, /* U+57CB */ + {0xe59f8c, 0xf1f1}, /* U+57CC [2000] */ + {0xe59f8e, 0x8fe9}, /* U+57CE */ + {0xe59f8f, 0x886f}, /* U+57CF [2000] */ + {0xe59f92, 0x9abd}, /* U+57D2 */ + {0xe59f93, 0x9abe}, /* U+57D3 */ + {0xe59f94, 0x9abc}, /* U+57D4 */ + {0xe59f96, 0x9ac0}, /* U+57D6 */ + {0xe59f97, 0xf1ef}, /* U+57D7 [2000] */ + {0xe59f9c, 0x9457}, /* U+57DC */ + {0xe59f9e, 0xf1f4}, /* U+57DE [2000] */ + {0xe59f9f, 0x88e6}, /* U+57DF */ + {0xe59fa0, 0x9575}, /* U+57E0 */ + {0xe59fa3, 0x9ac1}, /* U+57E3 */ + {0xe59fa4, 0x8870}, /* U+57E4 [2000] */ + {0xe59fa6, 0xf1f5}, /* U+57E6 [2000] */ + {0xe59fad, 0x8871}, /* U+57ED [2000] */ + {0xe59fb0, 0xf1f6}, /* U+57F0 [2000] */ + {0xe59fb4, 0x8ffb}, /* U+57F4 */ + {0xe59fb5, 0x8872}, /* U+57F5 [2000] */ + {0xe59fb6, 0x8873}, /* U+57F6 [2000] */ + {0xe59fb7, 0x8eb7}, /* U+57F7 */ + {0xe59fb8, 0xf1f8}, /* U+57F8 [2000] */ + {0xe59fb9, 0x947c}, /* U+57F9 */ + {0xe59fba, 0x8aee}, /* U+57FA */ + {0xe59fbb, 0xf1f9}, /* U+57FB [2000] */ + {0xe59fbc, 0x8de9}, /* U+57FC */ + {0xe59fbd, 0xf1fa}, /* U+57FD [2000] */ + {0xe59fbf, 0x8874}, /* U+57FF [2000] */ + {0xe5a080, 0x9678}, /* U+5800 */ + {0xe5a082, 0x93b0}, /* U+5802 */ + {0xe5a084, 0xf1fb}, /* U+5804 [2000] */ + {0xe5a085, 0x8c98}, /* U+5805 */ + {0xe5a086, 0x91cd}, /* U+5806 */ + {0xe5a089, 0x8875}, /* U+5809 [2000] */ + {0xe5a08a, 0x9abf}, /* U+580A */ + {0xe5a08b, 0x9ac2}, /* U+580B */ + {0xe5a095, 0x91c2}, /* U+5815 */ + {0xe5a099, 0x9ac3}, /* U+5819 */ + {0xe5a09d, 0x9ac4}, /* U+581D */ + {0xe5a09e, 0xf1fc}, /* U+581E [2000] */ + {0xe5a0a0, 0xf240}, /* U+5820 [2000] */ + {0xe5a0a1, 0x9ac6}, /* U+5821 */ + {0xe5a0a4, 0x92e7}, /* U+5824 */ + {0xe5a0a7, 0xf241}, /* U+5827 [2000] */ + {0xe5a0aa, 0x8aac}, /* U+582A */ + {0xe5a0af, 0xea9f}, /* U+582F [1983] */ + {0xe5a0b0, 0x8981}, /* U+5830 */ + {0xe5a0b1, 0x95f1}, /* U+5831 */ + {0xe5a0b2, 0xf242}, /* U+5832 [2000] */ + {0xe5a0b4, 0x8fea}, /* U+5834 */ + {0xe5a0b5, 0x9367}, /* U+5835 */ + {0xe5a0b9, 0xf243}, /* U+5839 [2000] */ + {0xe5a0ba, 0x8de4}, /* U+583A */ + {0xe5a0bd, 0x9acc}, /* U+583D */ + {0xe5a180, 0x95bb}, /* U+5840 */ + {0xe5a181, 0x97db}, /* U+5841 */ + {0xe5a189, 0xf245}, /* U+5849 [2000] */ + {0xe5a18a, 0x89f2}, /* U+584A */ + {0xe5a18b, 0x9ac8}, /* U+584B */ + {0xe5a18c, 0xf246}, /* U+584C [2000] */ + {0xe5a191, 0x9159}, /* U+5851 */ + {0xe5a192, 0x9acb}, /* U+5852 */ + {0xe5a194, 0x9383}, /* U+5854 */ + {0xe5a197, 0x9368}, /* U+5857 */ + {0xe5a198, 0x9384}, /* U+5858 */ + {0xe5a199, 0x94b7}, /* U+5859 */ + {0xe5a19a, 0x92cb}, /* U+585A */ + {0xe5a19e, 0x8dc7}, /* U+585E */ + {0xe5a1a1, 0x8877}, /* U+5861 [2000] */ + {0xe5a1a2, 0x9ac7}, /* U+5862 */ + {0xe5a1a4, 0x8878}, /* U+5864 [2000] */ + {0xe5a1a7, 0xf247}, /* U+5867 [2000] */ + {0xe5a1a9, 0x8996}, /* U+5869 */ + {0xe5a1ab, 0x9355}, /* U+586B */ + {0xe5a1b0, 0x9ac9}, /* U+5870 */ + {0xe5a1b2, 0x9ac5}, /* U+5872 */ + {0xe5a1b5, 0x906f}, /* U+5875 */ + {0xe5a1b9, 0x9acd}, /* U+5879 */ + {0xe5a1bc, 0x887a}, /* U+587C [2000] */ + {0xe5a1be, 0x8f6d}, /* U+587E */ + {0xe5a283, 0x8bab}, /* U+5883 */ + {0xe5a285, 0x9ace}, /* U+5885 */ + {0xe5a289, 0x887b}, /* U+5889 [2000] */ + {0xe5a28a, 0xf248}, /* U+588A [2000] */ + {0xe5a28b, 0xf249}, /* U+588B [2000] */ + {0xe5a28d, 0xf24a}, /* U+588D [2000] */ + {0xe5a28f, 0xf24b}, /* U+588F [2000] */ + {0xe5a290, 0xf24c}, /* U+5890 [2000] */ + {0xe5a293, 0x95e6}, /* U+5893 */ + {0xe5a294, 0xf24d}, /* U+5894 [2000] */ + {0xe5a297, 0x919d}, /* U+5897 */ + {0xe5a29c, 0x92c4}, /* U+589C */ + {0xe5a29d, 0xf24e}, /* U+589D [2000] */ + {0xe5a29e, 0x887c}, /* U+589E [2000] */ + {0xe5a29f, 0x9ad0}, /* U+589F */ + {0xe5a2a8, 0x966e}, /* U+58A8 */ + {0xe5a2a9, 0x887e}, /* U+58A9 [2000] */ + {0xe5a2aa, 0xf24f}, /* U+58AA [2000] */ + {0xe5a2ab, 0x9ad1}, /* U+58AB */ + {0xe5a2ae, 0x9ad6}, /* U+58AE */ + {0xe5a2b1, 0xf250}, /* U+58B1 [2000] */ + {0xe5a2b3, 0x95ad}, /* U+58B3 */ + {0xe5a2b8, 0x9ad5}, /* U+58B8 */ + {0xe5a2b9, 0x9acf}, /* U+58B9 */ + {0xe5a2ba, 0x9ad2}, /* U+58BA */ + {0xe5a2bb, 0x9ad4}, /* U+58BB */ + {0xe5a2be, 0x8da4}, /* U+58BE */ + {0xe5a381, 0x95c7}, /* U+58C1 */ + {0xe5a383, 0xf252}, /* U+58C3 [2000] */ + {0xe5a385, 0x9ad7}, /* U+58C5 */ + {0xe5a387, 0x9264}, /* U+58C7 */ + {0xe5a38a, 0x89f3}, /* U+58CA */ + {0xe5a38c, 0x8feb}, /* U+58CC */ + {0xe5a38d, 0xf253}, /* U+58CD [2000] */ + {0xe5a38e, 0x8882}, /* U+58CE [2000] */ + {0xe5a391, 0x9ad9}, /* U+58D1 */ + {0xe5a392, 0x8881}, /* U+58D2 [2000] */ + {0xe5a393, 0x9ad8}, /* U+58D3 */ + {0xe5a394, 0x8883}, /* U+58D4 [2000] */ + {0xe5a395, 0x8d88}, /* U+58D5 */ + {0xe5a397, 0x9ada}, /* U+58D7 */ + {0xe5a398, 0x9adc}, /* U+58D8 */ + {0xe5a399, 0x9adb}, /* U+58D9 */ + {0xe5a39a, 0x8884}, /* U+58DA [2000] */ + {0xe5a39c, 0x9ade}, /* U+58DC */ + {0xe5a39e, 0x9ad3}, /* U+58DE */ + {0xe5a39f, 0x9ae0}, /* U+58DF */ + {0xe5a3a0, 0x8885}, /* U+58E0 [2000] */ + {0xe5a3a2, 0xf254}, /* U+58E2 [2000] */ + {0xe5a3a4, 0x9adf}, /* U+58E4 */ + {0xe5a3a5, 0x9add}, /* U+58E5 */ + {0xe5a3a9, 0x8886}, /* U+58E9 [2000] */ + {0xe5a3ab, 0x8e6d}, /* U+58EB */ + {0xe5a3ac, 0x9070}, /* U+58EC */ + {0xe5a3ae, 0x9173}, /* U+58EE */ + {0xe5a3af, 0x9ae1}, /* U+58EF */ + {0xe5a3b0, 0x90ba}, /* U+58F0 */ + {0xe5a3b1, 0x88eb}, /* U+58F1 */ + {0xe5a3b2, 0x9484}, /* U+58F2 */ + {0xe5a3b3, 0xf255}, /* U+58F3 [2000] */ + {0xe5a3b4, 0xf256}, /* U+58F4 [2000] */ + {0xe5a3b7, 0x92d9}, /* U+58F7 */ + {0xe5a3b9, 0x9ae3}, /* U+58F9 */ + {0xe5a3ba, 0x9ae2}, /* U+58FA */ + {0xe5a3bb, 0x9ae4}, /* U+58FB */ + {0xe5a3bc, 0x9ae5}, /* U+58FC */ + {0xe5a3bd, 0x9ae6}, /* U+58FD */ + {0xe5a482, 0x9ae7}, /* U+5902 */ + {0xe5a485, 0xf257}, /* U+5905 [2000] */ + {0xe5a486, 0xf258}, /* U+5906 [2000] */ + {0xe5a489, 0x95cf}, /* U+5909 */ + {0xe5a48a, 0x9ae8}, /* U+590A */ + {0xe5a48b, 0xf259}, /* U+590B [2000] */ + {0xe5a48c, 0x8887}, /* U+590C [2000] */ + {0xe5a48d, 0xf25a}, /* U+590D [2000] */ + {0xe5a48f, 0x89c4}, /* U+590F */ + {0xe5a490, 0x9ae9}, /* U+5910 */ + {0xe5a494, 0xf25b}, /* U+5914 [2000] */ + {0xe5a495, 0x975b}, /* U+5915 */ + {0xe5a496, 0x8a4f}, /* U+5916 */ + {0xe5a498, 0x99c7}, /* U+5918 */ + {0xe5a499, 0x8f67}, /* U+5919 */ + {0xe5a49a, 0x91bd}, /* U+591A */ + {0xe5a49b, 0x9aea}, /* U+591B */ + {0xe5a49c, 0x96e9}, /* U+591C */ + {0xe5a4a2, 0x96b2}, /* U+5922 */ + {0xe5a4a4, 0xf25c}, /* U+5924 [2000] */ + {0xe5a4a5, 0x9aec}, /* U+5925 */ + {0xe5a4a7, 0x91e5}, /* U+5927 */ + {0xe5a4a9, 0x9356}, /* U+5929 */ + {0xe5a4aa, 0x91be}, /* U+592A */ + {0xe5a4ab, 0x9576}, /* U+592B */ + {0xe5a4ac, 0x9aed}, /* U+592C */ + {0xe5a4ad, 0x9aee}, /* U+592D */ + {0xe5a4ae, 0x899b}, /* U+592E */ + {0xe5a4b1, 0x8eb8}, /* U+5931 */ + {0xe5a4b2, 0x9aef}, /* U+5932 */ + {0xe5a4b7, 0x88ce}, /* U+5937 */ + {0xe5a4b8, 0x9af0}, /* U+5938 */ + {0xe5a4bd, 0xf25f}, /* U+593D [2000] */ + {0xe5a4be, 0x9af1}, /* U+593E */ + {0xe5a584, 0x8982}, /* U+5944 */ + {0xe5a586, 0xf261}, /* U+5946 [2000] */ + {0xe5a587, 0x8aef}, /* U+5947 */ + {0xe5a588, 0x93de}, /* U+5948 */ + {0xe5a589, 0x95f2}, /* U+5949 */ + {0xe5a58e, 0x9af5}, /* U+594E */ + {0xe5a58f, 0x9174}, /* U+594F */ + {0xe5a590, 0x9af4}, /* U+5950 */ + {0xe5a591, 0x8c5f}, /* U+5951 */ + {0xe5a594, 0x967a}, /* U+5954 */ + {0xe5a595, 0x9af3}, /* U+5955 */ + {0xe5a597, 0x9385}, /* U+5957 */ + {0xe5a598, 0x9af7}, /* U+5958 */ + {0xe5a59a, 0x9af6}, /* U+595A */ + {0xe5a59b, 0xf264}, /* U+595B [2000] */ + {0xe5a59d, 0x8889}, /* U+595D [2000] */ + {0xe5a59f, 0xf265}, /* U+595F [2000] */ + {0xe5a5a0, 0x9af9}, /* U+5960 */ + {0xe5a5a2, 0x9af8}, /* U+5962 */ + {0xe5a5a5, 0x899c}, /* U+5965 */ + {0xe5a5a7, 0x9afa}, /* U+5967 */ + {0xe5a5a8, 0x8fa7}, /* U+5968 */ + {0xe5a5a9, 0x9afc}, /* U+5969 */ + {0xe5a5aa, 0x9244}, /* U+596A */ + {0xe5a5ac, 0x9afb}, /* U+596C */ + {0xe5a5ad, 0x888a}, /* U+596D [2000] */ + {0xe5a5ae, 0x95b1}, /* U+596E */ + {0xe5a5b3, 0x8f97}, /* U+5973 */ + {0xe5a5b4, 0x937a}, /* U+5974 */ + {0xe5a5b5, 0xf267}, /* U+5975 [2000] */ + {0xe5a5b6, 0xf268}, /* U+5976 [2000] */ + {0xe5a5b8, 0x9b40}, /* U+5978 */ + {0xe5a5bc, 0xf269}, /* U+597C [2000] */ + {0xe5a5bd, 0x8d44}, /* U+597D */ + {0xe5a681, 0x9b41}, /* U+5981 */ + {0xe5a682, 0x9440}, /* U+5982 */ + {0xe5a683, 0x94dc}, /* U+5983 */ + {0xe5a684, 0x96cf}, /* U+5984 */ + {0xe5a68a, 0x9444}, /* U+598A */ + {0xe5a68b, 0x888b}, /* U+598B [2000] */ + {0xe5a68d, 0x9b4a}, /* U+598D */ + {0xe5a692, 0x888c}, /* U+5992 [2000] */ + {0xe5a693, 0x8b57}, /* U+5993 */ + {0xe5a696, 0x9764}, /* U+5996 */ + {0xe5a699, 0x96ad}, /* U+5999 */ + {0xe5a69b, 0x9baa}, /* U+599B */ + {0xe5a69d, 0x9b42}, /* U+599D */ + {0xe5a69f, 0xf26a}, /* U+599F [2000] */ + {0xe5a6a3, 0x9b45}, /* U+59A3 */ + {0xe5a6a4, 0x888d}, /* U+59A4 [2000] */ + {0xe5a6a5, 0x91c3}, /* U+59A5 */ + {0xe5a6a8, 0x9657}, /* U+59A8 */ + {0xe5a6ac, 0x9369}, /* U+59AC */ + {0xe5a6ae, 0xf26b}, /* U+59AE [2000] */ + {0xe5a6b2, 0x9b46}, /* U+59B2 */ + {0xe5a6b9, 0x9685}, /* U+59B9 */ + {0xe5a6bb, 0x8dc8}, /* U+59BB */ + {0xe5a6bc, 0xf26c}, /* U+59BC [2000] */ + {0xe5a6be, 0x8fa8}, /* U+59BE */ + {0xe5a783, 0x888e}, /* U+59C3 [2000] */ + {0xe5a786, 0x9b47}, /* U+59C6 */ + {0xe5a788, 0xf26d}, /* U+59C8 [2000] */ + {0xe5a789, 0x8e6f}, /* U+59C9 */ + {0xe5a78b, 0x8e6e}, /* U+59CB */ + {0xe5a78d, 0xf26e}, /* U+59CD [2000] */ + {0xe5a790, 0x88b7}, /* U+59D0 */ + {0xe5a791, 0x8cc6}, /* U+59D1 */ + {0xe5a792, 0x888f}, /* U+59D2 [2000] */ + {0xe5a793, 0x90a9}, /* U+59D3 */ + {0xe5a794, 0x88cf}, /* U+59D4 */ + {0xe5a799, 0x9b4b}, /* U+59D9 */ + {0xe5a79a, 0x9b4c}, /* U+59DA */ + {0xe5a79c, 0x9b49}, /* U+59DC */ + {0xe5a79d, 0x8890}, /* U+59DD [2000] */ + {0xe5a79e, 0xf26f}, /* U+59DE [2000] */ + {0xe5a7a3, 0xf270}, /* U+59E3 [2000] */ + {0xe5a7a4, 0xf271}, /* U+59E4 [2000] */ + {0xe5a7a5, 0x8957}, /* U+59E5 */ + {0xe5a7a6, 0x8aad}, /* U+59E6 */ + {0xe5a7a7, 0xf272}, /* U+59E7 [2000] */ + {0xe5a7a8, 0x9b48}, /* U+59E8 */ + {0xe5a7aa, 0x96c3}, /* U+59EA */ + {0xe5a7ab, 0x9550}, /* U+59EB */ + {0xe5a7ae, 0xf273}, /* U+59EE [2000] */ + {0xe5a7b6, 0x88a6}, /* U+59F6 */ + {0xe5a7b8, 0xeff8}, /* U+59F8 [2004] */ + {0xe5a7bb, 0x88f7}, /* U+59FB */ + {0xe5a7bf, 0x8e70}, /* U+59FF */ + {0xe5a881, 0x88d0}, /* U+5A01 */ + {0xe5a883, 0x88a1}, /* U+5A03 */ + {0xe5a889, 0x9b51}, /* U+5A09 */ + {0xe5a88c, 0xf277}, /* U+5A0C [2000] */ + {0xe5a88d, 0xf278}, /* U+5A0D [2000] */ + {0xe5a891, 0x9b4f}, /* U+5A11 */ + {0xe5a893, 0x8891}, /* U+5A13 [2000] */ + {0xe5a897, 0xf279}, /* U+5A17 [2000] */ + {0xe5a898, 0x96ba}, /* U+5A18 */ + {0xe5a89a, 0x9b52}, /* U+5A1A */ + {0xe5a89c, 0x9b50}, /* U+5A1C */ + {0xe5a89f, 0x9b4e}, /* U+5A1F */ + {0xe5a8a0, 0x9050}, /* U+5A20 */ + {0xe5a8a3, 0x8892}, /* U+5A23 [2000] */ + {0xe5a8a5, 0x9b4d}, /* U+5A25 */ + {0xe5a8a7, 0xf27a}, /* U+5A27 [2000] */ + {0xe5a8a9, 0x95d8}, /* U+5A29 */ + {0xe5a8ad, 0xf27b}, /* U+5A2D [2000] */ + {0xe5a8af, 0x8ce2}, /* U+5A2F */ + {0xe5a8b5, 0x9b56}, /* U+5A35 */ + {0xe5a8b6, 0x9b57}, /* U+5A36 */ + {0xe5a8bc, 0x8fa9}, /* U+5A3C */ + {0xe5a980, 0x9b53}, /* U+5A40 */ + {0xe5a981, 0x984b}, /* U+5A41 */ + {0xe5a986, 0x946b}, /* U+5A46 */ + {0xe5a989, 0x9b55}, /* U+5A49 */ + {0xe5a995, 0xf27c}, /* U+5A55 [2000] */ + {0xe5a99a, 0x8da5}, /* U+5A5A */ + {0xe5a9a2, 0x9b58}, /* U+5A62 */ + {0xe5a9a5, 0xf27d}, /* U+5A65 [2000] */ + {0xe5a9a6, 0x9577}, /* U+5A66 */ + {0xe5a9a7, 0x8893}, /* U+5A67 [2000] */ + {0xe5a9aa, 0x9b59}, /* U+5A6A */ + {0xe5a9ac, 0x9b54}, /* U+5A6C */ + {0xe5a9ad, 0x8894}, /* U+5A6D [2000] */ + {0xe5a9b7, 0x8895}, /* U+5A77 [2000] */ + {0xe5a9ba, 0xf27e}, /* U+5A7A [2000] */ + {0xe5a9be, 0x8896}, /* U+5A7E [2000] */ + {0xe5a9bf, 0x96b9}, /* U+5A7F */ + {0xe5aa84, 0x8897}, /* U+5A84 [2000] */ + {0xe5aa8b, 0xf280}, /* U+5A8B [2000] */ + {0xe5aa92, 0x947d}, /* U+5A92 */ + {0xe5aa9a, 0x9b5a}, /* U+5A9A */ + {0xe5aa9b, 0x9551}, /* U+5A9B */ + {0xe5aa9c, 0xf281}, /* U+5A9C [2000] */ + {0xe5aa9e, 0x8898}, /* U+5A9E [2000] */ + {0xe5aa9f, 0xf282}, /* U+5A9F [2000] */ + {0xe5aaa0, 0xf283}, /* U+5AA0 [2000] */ + {0xe5aaa2, 0xf284}, /* U+5AA2 [2000] */ + {0xe5aaa7, 0x8899}, /* U+5AA7 [2000] */ + {0xe5aab1, 0xf285}, /* U+5AB1 [2000] */ + {0xe5aab3, 0xf286}, /* U+5AB3 [2000] */ + {0xe5aab5, 0xf287}, /* U+5AB5 [2000] */ + {0xe5aaba, 0xf288}, /* U+5ABA [2000] */ + {0xe5aabc, 0x9b5b}, /* U+5ABC */ + {0xe5aabd, 0x9b5f}, /* U+5ABD */ + {0xe5aabe, 0x9b5c}, /* U+5ABE */ + {0xe5aabf, 0xf289}, /* U+5ABF [2000] */ + {0xe5ab81, 0x89c5}, /* U+5AC1 */ + {0xe5ab82, 0x9b5e}, /* U+5AC2 */ + {0xe5ab84, 0x889a}, /* U+5AC4 [2000] */ + {0xe5ab89, 0x8eb9}, /* U+5AC9 */ + {0xe5ab8b, 0x9b5d}, /* U+5ACB */ + {0xe5ab8c, 0x8c99}, /* U+5ACC */ + {0xe5ab90, 0x9b6b}, /* U+5AD0 */ + {0xe5ab96, 0x9b64}, /* U+5AD6 */ + {0xe5ab97, 0x9b61}, /* U+5AD7 */ + {0xe5ab9a, 0xf28a}, /* U+5ADA [2000] */ + {0xe5ab9c, 0xf28b}, /* U+5ADC [2000] */ + {0xe5aba0, 0xf28c}, /* U+5AE0 [2000] */ + {0xe5aba1, 0x9284}, /* U+5AE1 */ + {0xe5aba3, 0x9b60}, /* U+5AE3 */ + {0xe5aba5, 0xf28d}, /* U+5AE5 [2000] */ + {0xe5aba6, 0x9b62}, /* U+5AE6 */ + {0xe5aba9, 0x9b63}, /* U+5AE9 */ + {0xe5abae, 0xf28f}, /* U+5AEE [2000] */ + {0xe5abb0, 0xf28e}, /* U+5AF0 [2000] */ + {0xe5abb5, 0xf290}, /* U+5AF5 [2000] */ + {0xe5abba, 0x9b65}, /* U+5AFA */ + {0xe5abbb, 0x9b66}, /* U+5AFB */ + {0xe5ac80, 0xf291}, /* U+5B00 [2000] */ + {0xe5ac88, 0xf292}, /* U+5B08 [2000] */ + {0xe5ac89, 0x8af0}, /* U+5B09 */ + {0xe5ac8b, 0x9b68}, /* U+5B0B */ + {0xe5ac8c, 0x9b67}, /* U+5B0C */ + {0xe5ac96, 0x9b69}, /* U+5B16 */ + {0xe5ac97, 0xf293}, /* U+5B17 [2000] */ + {0xe5ac99, 0x889c}, /* U+5B19 [2000] */ + {0xe5aca2, 0x8fec}, /* U+5B22 */ + {0xe5aca5, 0x889d}, /* U+5B25 [2000] */ + {0xe5acaa, 0x9b6c}, /* U+5B2A */ + {0xe5acac, 0x92da}, /* U+5B2C */ + {0xe5acad, 0xf295}, /* U+5B2D [2000] */ + {0xe5acb0, 0x8964}, /* U+5B30 */ + {0xe5acb2, 0x9b6a}, /* U+5B32 */ + {0xe5acb4, 0xf294}, /* U+5B34 [2000] */ + {0xe5acb6, 0x9b6d}, /* U+5B36 */ + {0xe5acbe, 0x9b6e}, /* U+5B3E */ + {0xe5ad80, 0x9b71}, /* U+5B40 */ + {0xe5ad81, 0x9874}, /* U+5B41 [2000] */ + {0xe5ad83, 0x9b6f}, /* U+5B43 */ + {0xe5ad85, 0x9b70}, /* U+5B45 */ + {0xe5ad8c, 0xf296}, /* U+5B4C [2000] */ + {0xe5ad90, 0x8e71}, /* U+5B50 */ + {0xe5ad91, 0x9b72}, /* U+5B51 */ + {0xe5ad92, 0xf297}, /* U+5B52 [2000] */ + {0xe5ad94, 0x8d45}, /* U+5B54 */ + {0xe5ad95, 0x9b73}, /* U+5B55 */ + {0xe5ad96, 0x9875}, /* U+5B56 [2000] */ + {0xe5ad97, 0x8e9a}, /* U+5B57 */ + {0xe5ad98, 0x91b6}, /* U+5B58 */ + {0xe5ad9a, 0x9b74}, /* U+5B5A */ + {0xe5ad9b, 0x9b75}, /* U+5B5B */ + {0xe5ad9c, 0x8e79}, /* U+5B5C */ + {0xe5ad9d, 0x8d46}, /* U+5B5D */ + {0xe5ad9f, 0x96d0}, /* U+5B5F */ + {0xe5ada3, 0x8b47}, /* U+5B63 */ + {0xe5ada4, 0x8cc7}, /* U+5B64 */ + {0xe5ada5, 0x9b76}, /* U+5B65 */ + {0xe5ada6, 0x8a77}, /* U+5B66 */ + {0xe5ada8, 0xf298}, /* U+5B68 [2000] */ + {0xe5ada9, 0x9b77}, /* U+5B69 */ + {0xe5adab, 0x91b7}, /* U+5B6B */ + {0xe5adaf, 0xf299}, /* U+5B6F [2000] */ + {0xe5adb0, 0x9b78}, /* U+5B70 */ + {0xe5adb1, 0x9ba1}, /* U+5B71 */ + {0xe5adb3, 0x9b79}, /* U+5B73 */ + {0xe5adb5, 0x9b7a}, /* U+5B75 */ + {0xe5adb8, 0x9b7b}, /* U+5B78 */ + {0xe5adba, 0x9b7d}, /* U+5B7A */ + {0xe5adbc, 0xf29a}, /* U+5B7C [2000] */ + {0xe5adbd, 0x9876}, /* U+5B7D [2000] */ + {0xe5adbf, 0xf29b}, /* U+5B7F [2000] */ + {0xe5ae80, 0x9b7e}, /* U+5B80 */ + {0xe5ae81, 0xf29c}, /* U+5B81 [2000] */ + {0xe5ae83, 0x9b80}, /* U+5B83 */ + {0xe5ae84, 0xf29d}, /* U+5B84 [2000] */ + {0xe5ae85, 0x91ee}, /* U+5B85 */ + {0xe5ae87, 0x8946}, /* U+5B87 */ + {0xe5ae88, 0x8ee7}, /* U+5B88 */ + {0xe5ae89, 0x88c0}, /* U+5B89 */ + {0xe5ae8b, 0x9176}, /* U+5B8B */ + {0xe5ae8c, 0x8aae}, /* U+5B8C */ + {0xe5ae8d, 0x8eb3}, /* U+5B8D */ + {0xe5ae8f, 0x8d47}, /* U+5B8F */ + {0xe5ae93, 0x9877}, /* U+5B93 [2000] */ + {0xe5ae95, 0x9386}, /* U+5B95 */ + {0xe5ae96, 0xf09f}, /* U+5B96 [2000] */ + {0xe5ae97, 0x8f40}, /* U+5B97 */ + {0xe5ae98, 0x8aaf}, /* U+5B98 */ + {0xe5ae99, 0x9288}, /* U+5B99 */ + {0xe5ae9a, 0x92e8}, /* U+5B9A */ + {0xe5ae9b, 0x88b6}, /* U+5B9B */ + {0xe5ae9c, 0x8b58}, /* U+5B9C */ + {0xe5ae9d, 0x95f3}, /* U+5B9D */ + {0xe5ae9f, 0x8ec0}, /* U+5B9F */ + {0xe5aea2, 0x8b71}, /* U+5BA2 */ + {0xe5aea3, 0x90e9}, /* U+5BA3 */ + {0xe5aea4, 0x8eba}, /* U+5BA4 */ + {0xe5aea5, 0x9747}, /* U+5BA5 */ + {0xe5aea6, 0x9b81}, /* U+5BA6 */ + {0xe5aeac, 0xf0a0}, /* U+5BAC [2000] */ + {0xe5aeae, 0x8b7b}, /* U+5BAE */ + {0xe5aeb0, 0x8dc9}, /* U+5BB0 */ + {0xe5aeb3, 0x8a51}, /* U+5BB3 */ + {0xe5aeb4, 0x8983}, /* U+5BB4 */ + {0xe5aeb5, 0x8faa}, /* U+5BB5 */ + {0xe5aeb6, 0x89c6}, /* U+5BB6 */ + {0xe5aeb8, 0x9b82}, /* U+5BB8 */ + {0xe5aeb9, 0x9765}, /* U+5BB9 */ + {0xe5aebf, 0x8f68}, /* U+5BBF */ + {0xe5af80, 0xf0a2}, /* U+5BC0 [2000] */ + {0xe5af82, 0x8ee2}, /* U+5BC2 */ + {0xe5af83, 0x9b83}, /* U+5BC3 */ + {0xe5af84, 0x8af1}, /* U+5BC4 */ + {0xe5af85, 0x93d0}, /* U+5BC5 */ + {0xe5af86, 0x96a7}, /* U+5BC6 */ + {0xe5af87, 0x9b84}, /* U+5BC7 */ + {0xe5af89, 0x9b85}, /* U+5BC9 */ + {0xe5af8c, 0x9578}, /* U+5BCC */ + {0xe5af8e, 0xf0a4}, /* U+5BCE [2000] */ + {0xe5af90, 0x9b87}, /* U+5BD0 */ + {0xe5af92, 0x8aa6}, /* U+5BD2 */ + {0xe5af93, 0x8bf5}, /* U+5BD3 */ + {0xe5af94, 0x9b86}, /* U+5BD4 */ + {0xe5af96, 0xf0a5}, /* U+5BD6 [2000] */ + {0xe5af98, 0x9878}, /* U+5BD8 [2000] */ + {0xe5af9b, 0x8ab0}, /* U+5BDB */ + {0xe5af9d, 0x9051}, /* U+5BDD */ + {0xe5af9e, 0x9b8b}, /* U+5BDE */ + {0xe5af9f, 0x8e40}, /* U+5BDF */ + {0xe5afa1, 0x89c7}, /* U+5BE1 */ + {0xe5afa2, 0x9b8a}, /* U+5BE2 */ + {0xe5afa4, 0x9b88}, /* U+5BE4 */ + {0xe5afa5, 0x9b8c}, /* U+5BE5 */ + {0xe5afa6, 0x9b89}, /* U+5BE6 */ + {0xe5afa7, 0x944a}, /* U+5BE7 */ + {0xe5afa8, 0x9ecb}, /* U+5BE8 */ + {0xe5afa9, 0x9052}, /* U+5BE9 */ + {0xe5afab, 0x9b8d}, /* U+5BEB */ + {0xe5afac, 0x9879}, /* U+5BEC [2000] */ + {0xe5afae, 0x97be}, /* U+5BEE */ + {0xe5afb0, 0x9b8e}, /* U+5BF0 */ + {0xe5afb1, 0xf0a8}, /* U+5BF1 [2000] */ + {0xe5afb3, 0x9b90}, /* U+5BF3 */ + {0xe5afb5, 0x929e}, /* U+5BF5 */ + {0xe5afb6, 0x9b8f}, /* U+5BF6 */ + {0xe5afb8, 0x90a1}, /* U+5BF8 */ + {0xe5afba, 0x8e9b}, /* U+5BFA */ + {0xe5afbd, 0xf0a9}, /* U+5BFD [2000] */ + {0xe5afbe, 0x91ce}, /* U+5BFE */ + {0xe5afbf, 0x8ef5}, /* U+5BFF */ + {0xe5b081, 0x9595}, /* U+5C01 */ + {0xe5b082, 0x90ea}, /* U+5C02 */ + {0xe5b083, 0xf0ab}, /* U+5C03 [2000] */ + {0xe5b084, 0x8ecb}, /* U+5C04 */ + {0xe5b085, 0x9b91}, /* U+5C05 */ + {0xe5b086, 0x8fab}, /* U+5C06 */ + {0xe5b087, 0x9b92}, /* U+5C07 */ + {0xe5b088, 0x9b93}, /* U+5C08 */ + {0xe5b089, 0x88d1}, /* U+5C09 */ + {0xe5b08a, 0x91b8}, /* U+5C0A */ + {0xe5b08b, 0x9071}, /* U+5C0B */ + {0xe5b08d, 0x9b94}, /* U+5C0D */ + {0xe5b08e, 0x93b1}, /* U+5C0E */ + {0xe5b08f, 0x8fac}, /* U+5C0F */ + {0xe5b091, 0x8fad}, /* U+5C11 */ + {0xe5b092, 0x987a}, /* U+5C12 [2000] */ + {0xe5b093, 0x9b95}, /* U+5C13 */ + {0xe5b096, 0x90eb}, /* U+5C16 */ + {0xe5b09a, 0x8fae}, /* U+5C1A */ + {0xe5b09e, 0x987b}, /* U+5C1E [2000] */ + {0xe5b0a0, 0x9b96}, /* U+5C20 */ + {0xe5b0a2, 0x9b97}, /* U+5C22 */ + {0xe5b0a3, 0x987c}, /* U+5C23 [2000] */ + {0xe5b0a4, 0x96de}, /* U+5C24 */ + {0xe5b0a8, 0x9b98}, /* U+5C28 */ + {0xe5b0a9, 0xf0ac}, /* U+5C29 [2000] */ + {0xe5b0ab, 0x987d}, /* U+5C2B [2000] */ + {0xe5b0ad, 0x8bc4}, /* U+5C2D */ + {0xe5b0b0, 0xf0ad}, /* U+5C30 [2000] */ + {0xe5b0b1, 0x8f41}, /* U+5C31 */ + {0xe5b0b8, 0x9b99}, /* U+5C38 */ + {0xe5b0b9, 0x9b9a}, /* U+5C39 */ + {0xe5b0ba, 0x8eda}, /* U+5C3A */ + {0xe5b0bb, 0x904b}, /* U+5C3B */ + {0xe5b0bc, 0x93f2}, /* U+5C3C */ + {0xe5b0bd, 0x9073}, /* U+5C3D */ + {0xe5b0be, 0x94f6}, /* U+5C3E */ + {0xe5b0bf, 0x9441}, /* U+5C3F */ + {0xe5b180, 0x8bc7}, /* U+5C40 */ + {0xe5b181, 0x9b9b}, /* U+5C41 */ + {0xe5b185, 0x8b8f}, /* U+5C45 */ + {0xe5b186, 0x9b9c}, /* U+5C46 */ + {0xe5b188, 0x8bfc}, /* U+5C48 */ + {0xe5b18a, 0x93cd}, /* U+5C4A */ + {0xe5b18b, 0x89ae}, /* U+5C4B */ + {0xe5b18d, 0x8e72}, /* U+5C4D */ + {0xe5b18e, 0x9b9d}, /* U+5C4E */ + {0xe5b18f, 0x9ba0}, /* U+5C4F */ + {0xe5b190, 0x9b9f}, /* U+5C50 */ + {0xe5b191, 0x8bfb}, /* U+5C51 */ + {0xe5b193, 0x9b9e}, /* U+5C53 */ + {0xe5b195, 0x9357}, /* U+5C55 */ + {0xe5b19b, 0xeff9}, /* U+5C5B [2004] */ + {0xe5b19e, 0x91ae}, /* U+5C5E */ + {0xe5b19f, 0xf0af}, /* U+5C5F [2000] */ + {0xe5b1a0, 0x936a}, /* U+5C60 */ + {0xe5b1a1, 0x8ec6}, /* U+5C61 */ + {0xe5b1a2, 0x9880}, /* U+5C62 [2000] */ + {0xe5b1a3, 0xf0b0}, /* U+5C63 [2000] */ + {0xe5b1a4, 0x9177}, /* U+5C64 */ + {0xe5b1a5, 0x979a}, /* U+5C65 */ + {0xe5b1a7, 0xf0b1}, /* U+5C67 [2000] */ + {0xe5b1a8, 0xf0b2}, /* U+5C68 [2000] */ + {0xe5b1a9, 0xf0b3}, /* U+5C69 [2000] */ + {0xe5b1ac, 0x9ba2}, /* U+5C6C */ + {0xe5b1ae, 0x9ba3}, /* U+5C6E */ + {0xe5b1af, 0x93d4}, /* U+5C6F */ + {0xe5b1b0, 0xf0b4}, /* U+5C70 [2000] */ + {0xe5b1b1, 0x8e52}, /* U+5C71 */ + {0xe5b1b6, 0x9ba5}, /* U+5C76 */ + {0xe5b1b9, 0x9ba6}, /* U+5C79 */ + {0xe5b1ba, 0x9884}, /* U+5C7A [2000] */ + {0xe5b1bc, 0xf0b7}, /* U+5C7C [2000] */ + {0xe5b288, 0xf0ba}, /* U+5C88 [2000] */ + {0xe5b28a, 0xf0bb}, /* U+5C8A [2000] */ + {0xe5b28c, 0x9ba7}, /* U+5C8C */ + {0xe5b28f, 0x9885}, /* U+5C8F [2000] */ + {0xe5b290, 0x8af2}, /* U+5C90 */ + {0xe5b291, 0x9ba8}, /* U+5C91 */ + {0xe5b294, 0x9ba9}, /* U+5C94 */ + {0xe5b29f, 0x9886}, /* U+5C9F [2000] */ + {0xe5b2a0, 0xf0bf}, /* U+5CA0 [2000] */ + {0xe5b2a1, 0x89aa}, /* U+5CA1 */ + {0xe5b2a2, 0xf0c0}, /* U+5CA2 [2000] */ + {0xe5b2a3, 0x9887}, /* U+5CA3 [2000] */ + {0xe5b2a6, 0xf0c1}, /* U+5CA6 [2000] */ + {0xe5b2a7, 0xf0c2}, /* U+5CA7 [2000] */ + {0xe5b2a8, 0x915a}, /* U+5CA8 */ + {0xe5b2a9, 0x8ae2}, /* U+5CA9 */ + {0xe5b2aa, 0x9888}, /* U+5CAA [2000] */ + {0xe5b2ab, 0x9bab}, /* U+5CAB */ + {0xe5b2ac, 0x96a6}, /* U+5CAC */ + {0xe5b2ad, 0xf0c4}, /* U+5CAD [2000] */ + {0xe5b2b1, 0x91d0}, /* U+5CB1 */ + {0xe5b2b3, 0x8a78}, /* U+5CB3 */ + {0xe5b2b5, 0xf0c5}, /* U+5CB5 [2000] */ + {0xe5b2b6, 0x9bad}, /* U+5CB6 */ + {0xe5b2b7, 0x9baf}, /* U+5CB7 */ + {0xe5b2b8, 0x8add}, /* U+5CB8 */ + {0xe5b2ba, 0x9889}, /* U+5CBA [2000] */ + {0xe5b2bb, 0x9bac}, /* U+5CBB */ + {0xe5b2bc, 0x9bae}, /* U+5CBC */ + {0xe5b2be, 0x9bb1}, /* U+5CBE */ + {0xe5b385, 0x9bb0}, /* U+5CC5 */ + {0xe5b387, 0x9bb2}, /* U+5CC7 */ + {0xe5b389, 0xf0c7}, /* U+5CC9 [2000] */ + {0xe5b38b, 0x988a}, /* U+5CCB [2000] */ + {0xe5b390, 0x988b}, /* U+5CD0 [2000] */ + {0xe5b392, 0x988c}, /* U+5CD2 [2000] */ + {0xe5b399, 0x9bb3}, /* U+5CD9 */ + {0xe5b3a0, 0x93bb}, /* U+5CE0 */ + {0xe5b3a1, 0x8bac}, /* U+5CE1 */ + {0xe5b3a8, 0x89e3}, /* U+5CE8 */ + {0xe5b3a9, 0x9bb4}, /* U+5CE9 */ + {0xe5b3aa, 0x9bb9}, /* U+5CEA */ + {0xe5b3ad, 0x9bb7}, /* U+5CED */ + {0xe5b3af, 0x95f5}, /* U+5CEF */ + {0xe5b3b0, 0x95f4}, /* U+5CF0 */ + {0xe5b3b4, 0x988d}, /* U+5CF4 [2000] */ + {0xe5b3b6, 0x9387}, /* U+5CF6 */ + {0xe5b3ba, 0x9bb6}, /* U+5CFA */ + {0xe5b3bb, 0x8f73}, /* U+5CFB */ + {0xe5b3bd, 0x9bb5}, /* U+5CFD */ + {0xe5b486, 0xf0ca}, /* U+5D06 [2000] */ + {0xe5b487, 0x9092}, /* U+5D07 */ + {0xe5b48b, 0x9bba}, /* U+5D0B */ + {0xe5b48d, 0x9890}, /* U+5D0D [2000] */ + {0xe5b48e, 0x8de8}, /* U+5D0E */ + {0xe5b490, 0xf0cb}, /* U+5D10 [2000] */ + {0xe5b491, 0x9bc0}, /* U+5D11 */ + {0xe5b494, 0x9bc1}, /* U+5D14 */ + {0xe5b495, 0x9bbb}, /* U+5D15 */ + {0xe5b496, 0x8a52}, /* U+5D16 */ + {0xe5b497, 0x9bbc}, /* U+5D17 */ + {0xe5b498, 0x9bc5}, /* U+5D18 */ + {0xe5b499, 0x9bc4}, /* U+5D19 */ + {0xe5b49a, 0x9bc3}, /* U+5D1A */ + {0xe5b49b, 0x9bbf}, /* U+5D1B */ + {0xe5b49d, 0xf0cd}, /* U+5D1D [2000] */ + {0xe5b49f, 0x9bbe}, /* U+5D1F */ + {0xe5b4a0, 0xf0ce}, /* U+5D20 [2000] */ + {0xe5b4a2, 0x9bc2}, /* U+5D22 */ + {0xe5b4a4, 0xf0cf}, /* U+5D24 [2000] */ + {0xe5b4a6, 0xf0d0}, /* U+5D26 [2000] */ + {0xe5b4a7, 0x9891}, /* U+5D27 [2000] */ + {0xe5b4a9, 0x95f6}, /* U+5D29 */ + {0xe5b4ab, 0xf0cc}, /* U+5D2B [2000] */ + {0xe5b4b1, 0xf0d1}, /* U+5D31 [2000] */ + {0xe5b4b9, 0xf0d2}, /* U+5D39 [2000] */ + {0xe5b582, 0xf0d3}, /* U+5D42 [2000] */ + {0xe5b586, 0x9893}, /* U+5D46 [2000] */ + {0xe5b587, 0x9894}, /* U+5D47 [2000] */ + {0xe5b58a, 0x9896}, /* U+5D4A [2000] */ + {0xe5b58b, 0x9bc9}, /* U+5D4B */ + {0xe5b58c, 0x9bc6}, /* U+5D4C */ + {0xe5b58e, 0x9bc8}, /* U+5D4E */ + {0xe5b590, 0x9792}, /* U+5D50 */ + {0xe5b592, 0x9bc7}, /* U+5D52 */ + {0xe5b593, 0x9895}, /* U+5D53 [2000] */ + {0xe5b59c, 0x9bbd}, /* U+5D5C */ + {0xe5b5a1, 0xf0d5}, /* U+5D61 [2000] */ + {0xe5b5a9, 0x9093}, /* U+5D69 */ + {0xe5b5aa, 0xf0d6}, /* U+5D6A [2000] */ + {0xe5b5ac, 0x9bca}, /* U+5D6C */ + {0xe5b5ad, 0x9897}, /* U+5D6D [2000] */ + {0xe5b5af, 0x8db5}, /* U+5D6F */ + {0xe5b5b0, 0xf0d8}, /* U+5D70 [2000] */ + {0xe5b5b3, 0x9bcb}, /* U+5D73 */ + {0xe5b5b6, 0x9bcc}, /* U+5D76 */ + {0xe5b681, 0x9898}, /* U+5D81 [2000] */ + {0xe5b682, 0x9bcf}, /* U+5D82 */ + {0xe5b684, 0x9bce}, /* U+5D84 */ + {0xe5b687, 0x9bcd}, /* U+5D87 */ + {0xe5b688, 0xf0db}, /* U+5D88 [2000] */ + {0xe5b68b, 0x9388}, /* U+5D8B */ + {0xe5b68c, 0x9bb8}, /* U+5D8C */ + {0xe5b690, 0x9bd5}, /* U+5D90 */ + {0xe5b692, 0xf0dd}, /* U+5D92 [2000] */ + {0xe5b694, 0xf0de}, /* U+5D94 [2000] */ + {0xe5b697, 0xf0df}, /* U+5D97 [2000] */ + {0xe5b699, 0xf0e0}, /* U+5D99 [2000] */ + {0xe5b69d, 0x9bd1}, /* U+5D9D */ + {0xe5b6a0, 0x9899}, /* U+5DA0 [2000] */ + {0xe5b6a2, 0x9bd0}, /* U+5DA2 */ + {0xe5b6a4, 0x989a}, /* U+5DA4 [2000] */ + {0xe5b6a7, 0x989b}, /* U+5DA7 [2000] */ + {0xe5b6ac, 0x9bd2}, /* U+5DAC */ + {0xe5b6ae, 0x9bd3}, /* U+5DAE */ + {0xe5b6b0, 0xf0e1}, /* U+5DB0 [2000] */ + {0xe5b6b2, 0xf0e2}, /* U+5DB2 [2000] */ + {0xe5b6b4, 0xf0e3}, /* U+5DB4 [2000] */ + {0xe5b6b7, 0x9bd6}, /* U+5DB7 */ + {0xe5b6b8, 0x989c}, /* U+5DB8 [2000] */ + {0xe5b6b9, 0xf0e5}, /* U+5DB9 [2000] */ + {0xe5b6ba, 0x97e4}, /* U+5DBA */ + {0xe5b6bc, 0x9bd7}, /* U+5DBC */ + {0xe5b6bd, 0x9bd4}, /* U+5DBD */ + {0xe5b789, 0x9bd8}, /* U+5DC9 */ + {0xe5b78b, 0x989d}, /* U+5DCB [2000] */ + {0xe5b78c, 0x8ade}, /* U+5DCC */ + {0xe5b78d, 0x9bd9}, /* U+5DCD */ + {0xe5b791, 0xf0e6}, /* U+5DD1 [2000] */ + {0xe5b792, 0x9bdb}, /* U+5DD2 */ + {0xe5b793, 0x9bda}, /* U+5DD3 */ + {0xe5b796, 0x9bdc}, /* U+5DD6 */ + {0xe5b797, 0xf0e7}, /* U+5DD7 [2000] */ + {0xe5b798, 0xf0e8}, /* U+5DD8 [2000] */ + {0xe5b79b, 0x9bdd}, /* U+5DDB */ + {0xe5b79d, 0x90ec}, /* U+5DDD */ + {0xe5b79e, 0x8f42}, /* U+5DDE */ + {0xe5b7a0, 0xf0e9}, /* U+5DE0 [2000] */ + {0xe5b7a1, 0x8f84}, /* U+5DE1 */ + {0xe5b7a2, 0xeaa6}, /* U+5DE2 [2000] */ + {0xe5b7a3, 0x9183}, /* U+5DE3 */ + {0xe5b7a4, 0xf0eb}, /* U+5DE4 [2000] */ + {0xe5b7a5, 0x8d48}, /* U+5DE5 */ + {0xe5b7a6, 0x8db6}, /* U+5DE6 */ + {0xe5b7a7, 0x8d49}, /* U+5DE7 */ + {0xe5b7a8, 0x8b90}, /* U+5DE8 */ + {0xe5b7a9, 0xf0ec}, /* U+5DE9 [2000] */ + {0xe5b7ab, 0x9bde}, /* U+5DEB */ + {0xe5b7ae, 0x8db7}, /* U+5DEE */ + {0xe5b7b1, 0x8cc8}, /* U+5DF1 */ + {0xe5b7b2, 0x9bdf}, /* U+5DF2 */ + {0xe5b7b3, 0x96a4}, /* U+5DF3 */ + {0xe5b7b4, 0x9462}, /* U+5DF4 */ + {0xe5b7b5, 0x9be0}, /* U+5DF5 */ + {0xe5b7b7, 0x8d4a}, /* U+5DF7 */ + {0xe5b7bb, 0x8aaa}, /* U+5DFB */ + {0xe5b7bd, 0x9246}, /* U+5DFD */ + {0xe5b7be, 0x8bd0}, /* U+5DFE */ + {0xe5b880, 0xf0ee}, /* U+5E00 [2000] */ + {0xe5b882, 0x8e73}, /* U+5E02 */ + {0xe5b883, 0x957a}, /* U+5E03 */ + {0xe5b886, 0x94bf}, /* U+5E06 */ + {0xe5b88b, 0x9be1}, /* U+5E0B */ + {0xe5b88c, 0x8af3}, /* U+5E0C */ + {0xe5b891, 0x9be4}, /* U+5E11 */ + {0xe5b892, 0xf0f0}, /* U+5E12 [2000] */ + {0xe5b894, 0xeaa7}, /* U+5E14 [2000] */ + {0xe5b895, 0xf0f1}, /* U+5E15 [2000] */ + {0xe5b896, 0x929f}, /* U+5E16 */ + {0xe5b898, 0xeaa8}, /* U+5E18 [2000] */ + {0xe5b899, 0x9be3}, /* U+5E19 */ + {0xe5b89a, 0x9be2}, /* U+5E1A */ + {0xe5b89b, 0x9be5}, /* U+5E1B */ + {0xe5b89d, 0x92e9}, /* U+5E1D */ + {0xe5b89f, 0xf0f3}, /* U+5E1F [2000] */ + {0xe5b8a5, 0x9083}, /* U+5E25 */ + {0xe5b8ab, 0x8e74}, /* U+5E2B */ + {0xe5b8ad, 0x90c8}, /* U+5E2D */ + {0xe5b8ae, 0xf0f4}, /* U+5E2E [2000] */ + {0xe5b8af, 0x91d1}, /* U+5E2F */ + {0xe5b8b0, 0x8b41}, /* U+5E30 */ + {0xe5b8b3, 0x92a0}, /* U+5E33 */ + {0xe5b8b6, 0x9be6}, /* U+5E36 */ + {0xe5b8b7, 0x9be7}, /* U+5E37 */ + {0xe5b8b8, 0x8fed}, /* U+5E38 */ + {0xe5b8bd, 0x9658}, /* U+5E3D */ + {0xe5b8be, 0xf0f5}, /* U+5E3E [2000] */ + {0xe5b980, 0x9bea}, /* U+5E40 */ + {0xe5b983, 0x9be9}, /* U+5E43 */ + {0xe5b984, 0x9be8}, /* U+5E44 */ + {0xe5b985, 0x959d}, /* U+5E45 */ + {0xe5b987, 0x9bf1}, /* U+5E47 */ + {0xe5b989, 0xf0f6}, /* U+5E49 [2000] */ + {0xe5b98c, 0x9679}, /* U+5E4C */ + {0xe5b98e, 0x9beb}, /* U+5E4E */ + {0xe5b994, 0x9bed}, /* U+5E54 */ + {0xe5b995, 0x968b}, /* U+5E55 */ + {0xe5b996, 0xf0f8}, /* U+5E56 [2000] */ + {0xe5b997, 0x9bec}, /* U+5E57 */ + {0xe5b998, 0xeaa9}, /* U+5E58 [2000] */ + {0xe5b99e, 0xeaaa}, /* U+5E5E [2000] */ + {0xe5b99f, 0x9bee}, /* U+5E5F */ + {0xe5b9a1, 0x94a6}, /* U+5E61 */ + {0xe5b9a2, 0x9bef}, /* U+5E62 */ + {0xe5b9a3, 0x95bc}, /* U+5E63 */ + {0xe5b9a4, 0x9bf0}, /* U+5E64 */ + {0xe5b9ab, 0xf0fa}, /* U+5E6B [2000] */ + {0xe5b9ac, 0xf0fb}, /* U+5E6C [2000] */ + {0xe5b9ad, 0xf0fc}, /* U+5E6D [2000] */ + {0xe5b9ae, 0xf29f}, /* U+5E6E [2000] */ + {0xe5b9b2, 0x8ab1}, /* U+5E72 */ + {0xe5b9b3, 0x95bd}, /* U+5E73 */ + {0xe5b9b4, 0x944e}, /* U+5E74 */ + {0xe5b9b5, 0x9bf2}, /* U+5E75 */ + {0xe5b9b6, 0x9bf3}, /* U+5E76 */ + {0xe5b9b7, 0xeffa}, /* U+5E77 [2004] */ + {0xe5b9b8, 0x8d4b}, /* U+5E78 */ + {0xe5b9b9, 0x8ab2}, /* U+5E79 */ + {0xe5b9ba, 0x9bf4}, /* U+5E7A */ + {0xe5b9bb, 0x8cb6}, /* U+5E7B */ + {0xe5b9bc, 0x9763}, /* U+5E7C */ + {0xe5b9bd, 0x9748}, /* U+5E7D */ + {0xe5b9be, 0x8af4}, /* U+5E7E */ + {0xe5b9bf, 0x9bf6}, /* U+5E7F */ + {0xe5ba81, 0x92a1}, /* U+5E81 */ + {0xe5ba83, 0x8d4c}, /* U+5E83 */ + {0xe5ba84, 0x8faf}, /* U+5E84 */ + {0xe5ba87, 0x94dd}, /* U+5E87 */ + {0xe5ba8a, 0x8fb0}, /* U+5E8A */ + {0xe5ba8f, 0x8f98}, /* U+5E8F */ + {0xe5ba95, 0x92ea}, /* U+5E95 */ + {0xe5ba96, 0x95f7}, /* U+5E96 */ + {0xe5ba97, 0x9358}, /* U+5E97 */ + {0xe5ba9a, 0x8d4d}, /* U+5E9A */ + {0xe5ba9c, 0x957b}, /* U+5E9C */ + {0xe5baa0, 0x9bf7}, /* U+5EA0 */ + {0xe5baa5, 0xf2a1}, /* U+5EA5 [2000] */ + {0xe5baa6, 0x9378}, /* U+5EA6 */ + {0xe5baa7, 0x8dc0}, /* U+5EA7 */ + {0xe5baaa, 0xf2a2}, /* U+5EAA [2000] */ + {0xe5baab, 0x8cc9}, /* U+5EAB */ + {0xe5baac, 0xf2a3}, /* U+5EAC [2000] */ + {0xe5baad, 0x92eb}, /* U+5EAD */ + {0xe5bab5, 0x88c1}, /* U+5EB5 */ + {0xe5bab6, 0x8f8e}, /* U+5EB6 */ + {0xe5bab7, 0x8d4e}, /* U+5EB7 */ + {0xe5bab8, 0x9766}, /* U+5EB8 */ + {0xe5bab9, 0xf2a4}, /* U+5EB9 [2000] */ + {0xe5babe, 0xeaab}, /* U+5EBE [2000] */ + {0xe5babf, 0xf2a5}, /* U+5EBF [2000] */ + {0xe5bb81, 0x9bf8}, /* U+5EC1 */ + {0xe5bb82, 0x9bf9}, /* U+5EC2 */ + {0xe5bb83, 0x9470}, /* U+5EC3 */ + {0xe5bb86, 0xf2a6}, /* U+5EC6 [2000] */ + {0xe5bb88, 0x9bfa}, /* U+5EC8 */ + {0xe5bb89, 0x97f5}, /* U+5EC9 */ + {0xe5bb8a, 0x984c}, /* U+5ECA */ + {0xe5bb8b, 0xeaad}, /* U+5ECB [2000] */ + {0xe5bb8f, 0x9bfc}, /* U+5ECF */ + {0xe5bb90, 0x9bfb}, /* U+5ED0 */ + {0xe5bb92, 0xf2a7}, /* U+5ED2 [2000] */ + {0xe5bb93, 0x8a66}, /* U+5ED3 */ + {0xe5bb96, 0x9c40}, /* U+5ED6 */ + {0xe5bb99, 0xf2a8}, /* U+5ED9 [2000] */ + {0xe5bb9a, 0x9c43}, /* U+5EDA */ + {0xe5bb9b, 0x9c44}, /* U+5EDB */ + {0xe5bb9d, 0x9c42}, /* U+5EDD */ + {0xe5bb9f, 0x955f}, /* U+5EDF */ + {0xe5bba0, 0x8fb1}, /* U+5EE0 */ + {0xe5bba1, 0x9c46}, /* U+5EE1 */ + {0xe5bba2, 0x9c45}, /* U+5EE2 */ + {0xe5bba3, 0x9c41}, /* U+5EE3 */ + {0xe5bba8, 0x9c47}, /* U+5EE8 */ + {0xe5bba9, 0x9c48}, /* U+5EE9 */ + {0xe5bbac, 0x9c49}, /* U+5EEC */ + {0xe5bbb0, 0x9c4c}, /* U+5EF0 */ + {0xe5bbb1, 0x9c4a}, /* U+5EF1 */ + {0xe5bbb3, 0x9c4b}, /* U+5EF3 */ + {0xe5bbb4, 0x9c4d}, /* U+5EF4 */ + {0xe5bbb6, 0x8984}, /* U+5EF6 */ + {0xe5bbb7, 0x92ec}, /* U+5EF7 */ + {0xe5bbb8, 0x9c4e}, /* U+5EF8 */ + {0xe5bbb9, 0xeaae}, /* U+5EF9 [2000] */ + {0xe5bbba, 0x8c9a}, /* U+5EFA */ + {0xe5bbbb, 0x89f4}, /* U+5EFB */ + {0xe5bbbc, 0x9455}, /* U+5EFC */ + {0xe5bbbd, 0xf2aa}, /* U+5EFD [2000] */ + {0xe5bbbe, 0x9c4f}, /* U+5EFE */ + {0xe5bbbf, 0x93f9}, /* U+5EFF */ + {0xe5bc80, 0xeaaf}, /* U+5F00 [2000] */ + {0xe5bc81, 0x95d9}, /* U+5F01 */ + {0xe5bc82, 0xeab0}, /* U+5F02 [2000] */ + {0xe5bc83, 0x9c50}, /* U+5F03 */ + {0xe5bc84, 0x984d}, /* U+5F04 */ + {0xe5bc87, 0xeab1}, /* U+5F07 [2000] */ + {0xe5bc88, 0xf2ab}, /* U+5F08 [2000] */ + {0xe5bc89, 0x9c51}, /* U+5F09 */ + {0xe5bc8a, 0x95be}, /* U+5F0A */ + {0xe5bc8b, 0x9c54}, /* U+5F0B */ + {0xe5bc8c, 0x989f}, /* U+5F0C */ + {0xe5bc8d, 0x98af}, /* U+5F0D */ + {0xe5bc8e, 0xf2ac}, /* U+5F0E [2000] */ + {0xe5bc8f, 0x8eae}, /* U+5F0F */ + {0xe5bc90, 0x93f3}, /* U+5F10 */ + {0xe5bc91, 0x9c55}, /* U+5F11 */ + {0xe5bc93, 0x8b7c}, /* U+5F13 */ + {0xe5bc94, 0x92a2}, /* U+5F14 */ + {0xe5bc95, 0x88f8}, /* U+5F15 */ + {0xe5bc96, 0x9c56}, /* U+5F16 */ + {0xe5bc97, 0x95a4}, /* U+5F17 */ + {0xe5bc98, 0x8d4f}, /* U+5F18 */ + {0xe5bc9b, 0x926f}, /* U+5F1B */ + {0xe5bc9c, 0xf2ad}, /* U+5F1C [2000] */ + {0xe5bc9d, 0xeab2}, /* U+5F1D [2000] */ + {0xe5bc9e, 0xf2af}, /* U+5F1E [2000] */ + {0xe5bc9f, 0x92ed}, /* U+5F1F */ + {0xe5bca3, 0xeab3}, /* U+5F23 [2000] */ + {0xe5bca5, 0x96ed}, /* U+5F25 */ + {0xe5bca6, 0x8cb7}, /* U+5F26 */ + {0xe5bca7, 0x8cca}, /* U+5F27 */ + {0xe5bca9, 0x9c57}, /* U+5F29 */ + {0xe5bcad, 0x9c58}, /* U+5F2D */ + {0xe5bcaf, 0x9c5e}, /* U+5F2F */ + {0xe5bcb1, 0x8ee3}, /* U+5F31 */ + {0xe5bcb4, 0xeab4}, /* U+5F34 [2000] */ + {0xe5bcb5, 0x92a3}, /* U+5F35 */ + {0xe5bcb6, 0xeab5}, /* U+5F36 [2000] */ + {0xe5bcb7, 0x8bad}, /* U+5F37 */ + {0xe5bcb8, 0x9c59}, /* U+5F38 */ + {0xe5bcbc, 0x954a}, /* U+5F3C */ + {0xe5bcbd, 0xeab6}, /* U+5F3D [2000] */ + {0xe5bcbe, 0x9265}, /* U+5F3E */ + {0xe5bd80, 0xeab7}, /* U+5F40 [2000] */ + {0xe5bd81, 0x9c5a}, /* U+5F41 */ + {0xe5bd85, 0xeab8}, /* U+5F45 [2000] */ + {0xe5bd87, 0xf2b0}, /* U+5F47 [2000] */ + {0xe5bd88, 0x9c5b}, /* U+5F48 */ + {0xe5bd8a, 0x8bae}, /* U+5F4A */ + {0xe5bd8c, 0x9c5c}, /* U+5F4C */ + {0xe5bd8e, 0x9c5d}, /* U+5F4E */ + {0xe5bd91, 0x9c5f}, /* U+5F51 */ + {0xe5bd93, 0x9396}, /* U+5F53 */ + {0xe5bd94, 0xeab9}, /* U+5F54 [2000] */ + {0xe5bd96, 0x9c60}, /* U+5F56 */ + {0xe5bd97, 0x9c61}, /* U+5F57 */ + {0xe5bd98, 0xeaba}, /* U+5F58 [2000] */ + {0xe5bd99, 0x9c62}, /* U+5F59 */ + {0xe5bd9c, 0x9c53}, /* U+5F5C */ + {0xe5bd9d, 0x9c52}, /* U+5F5D */ + {0xe5bda1, 0x9c63}, /* U+5F61 */ + {0xe5bda2, 0x8c60}, /* U+5F62 */ + {0xe5bda3, 0xf2b1}, /* U+5F63 [2000] */ + {0xe5bda4, 0xeabb}, /* U+5F64 [2000] */ + {0xe5bda6, 0x9546}, /* U+5F66 */ + {0xe5bda7, 0xeabc}, /* U+5F67 [2000] */ + {0xe5bda9, 0x8dca}, /* U+5F69 */ + {0xe5bdaa, 0x9556}, /* U+5F6A */ + {0xe5bdab, 0x92a4}, /* U+5F6B */ + {0xe5bdac, 0x956a}, /* U+5F6C */ + {0xe5bdad, 0x9c64}, /* U+5F6D */ + {0xe5bdb0, 0x8fb2}, /* U+5F70 */ + {0xe5bdb1, 0x8965}, /* U+5F71 */ + {0xe5bdb2, 0xf2b2}, /* U+5F72 [2000] */ + {0xe5bdb3, 0x9c65}, /* U+5F73 */ + {0xe5bdb7, 0x9c66}, /* U+5F77 */ + {0xe5bdb9, 0x96f0}, /* U+5F79 */ + {0xe5bdbc, 0x94de}, /* U+5F7C */ + {0xe5bdbd, 0xeabd}, /* U+5F7D [2000] */ + {0xe5bdbe, 0xf2b3}, /* U+5F7E [2000] */ + {0xe5bdbf, 0x9c69}, /* U+5F7F */ + {0xe5be80, 0x899d}, /* U+5F80 */ + {0xe5be81, 0x90aa}, /* U+5F81 */ + {0xe5be82, 0x9c68}, /* U+5F82 */ + {0xe5be83, 0x9c67}, /* U+5F83 */ + {0xe5be84, 0x8c61}, /* U+5F84 */ + {0xe5be85, 0x91d2}, /* U+5F85 */ + {0xe5be87, 0x9c6d}, /* U+5F87 */ + {0xe5be88, 0x9c6b}, /* U+5F88 */ + {0xe5be89, 0xeabe}, /* U+5F89 [2000] */ + {0xe5be8a, 0x9c6a}, /* U+5F8A */ + {0xe5be8b, 0x97a5}, /* U+5F8B */ + {0xe5be8c, 0x8ce3}, /* U+5F8C */ + {0xe5be8f, 0xf2b4}, /* U+5F8F [2000] */ + {0xe5be90, 0x8f99}, /* U+5F90 */ + {0xe5be91, 0x9c6c}, /* U+5F91 */ + {0xe5be92, 0x936b}, /* U+5F92 */ + {0xe5be93, 0x8f5d}, /* U+5F93 */ + {0xe5be97, 0x93be}, /* U+5F97 */ + {0xe5be98, 0x9c70}, /* U+5F98 */ + {0xe5be99, 0x9c6f}, /* U+5F99 */ + {0xe5be9c, 0xeabf}, /* U+5F9C [2000] */ + {0xe5be9e, 0x9c6e}, /* U+5F9E */ + {0xe5bea0, 0x9c71}, /* U+5FA0 */ + {0xe5bea1, 0x8ce4}, /* U+5FA1 */ + {0xe5bea2, 0xf2b5}, /* U+5FA2 [2000] */ + {0xe5bea4, 0xf2b6}, /* U+5FA4 [2000] */ + {0xe5bea7, 0xeac0}, /* U+5FA7 [2000] */ + {0xe5bea8, 0x9c72}, /* U+5FA8 */ + {0xe5bea9, 0x959c}, /* U+5FA9 */ + {0xe5beaa, 0x8f7a}, /* U+5FAA */ + {0xe5bead, 0x9c73}, /* U+5FAD */ + {0xe5beae, 0x94f7}, /* U+5FAE */ + {0xe5beaf, 0xeac1}, /* U+5FAF [2000] */ + {0xe5beb3, 0x93bf}, /* U+5FB3 */ + {0xe5beb4, 0x92a5}, /* U+5FB4 */ + {0xe5beb5, 0xeac2}, /* U+5FB5 [2000] */ + {0xe5beb7, 0xeac3}, /* U+5FB7 [2000] */ + {0xe5beb8, 0xf2b7}, /* U+5FB8 [2000] */ + {0xe5beb9, 0x934f}, /* U+5FB9 */ + {0xe5bebc, 0x9c74}, /* U+5FBC */ + {0xe5bebd, 0x8b4a}, /* U+5FBD */ + {0xe5bf83, 0x9053}, /* U+5FC3 */ + {0xe5bf84, 0xf2b8}, /* U+5FC4 [2000] */ + {0xe5bf85, 0x954b}, /* U+5FC5 */ + {0xe5bf87, 0xf2ba}, /* U+5FC7 [2000] */ + {0xe5bf89, 0xeac4}, /* U+5FC9 [2000] */ + {0xe5bf8b, 0xf2bb}, /* U+5FCB [2000] */ + {0xe5bf8c, 0x8af5}, /* U+5FCC */ + {0xe5bf8d, 0x9445}, /* U+5FCD */ + {0xe5bf92, 0xf2bc}, /* U+5FD2 [2000] */ + {0xe5bf93, 0xf2bd}, /* U+5FD3 [2000] */ + {0xe5bf94, 0xf2be}, /* U+5FD4 [2000] */ + {0xe5bf96, 0x9c75}, /* U+5FD6 */ + {0xe5bf97, 0x8e75}, /* U+5FD7 */ + {0xe5bf98, 0x9659}, /* U+5FD8 */ + {0xe5bf99, 0x965a}, /* U+5FD9 */ + {0xe5bf9c, 0x899e}, /* U+5FDC */ + {0xe5bf9d, 0x9c7a}, /* U+5FDD */ + {0xe5bf9e, 0xeac5}, /* U+5FDE [2000] */ + {0xe5bfa0, 0x9289}, /* U+5FE0 */ + {0xe5bfa1, 0xeac6}, /* U+5FE1 [2000] */ + {0xe5bfa2, 0xf2bf}, /* U+5FE2 [2000] */ + {0xe5bfa4, 0x9c77}, /* U+5FE4 */ + {0xe5bfa9, 0xeac7}, /* U+5FE9 [2000] */ + {0xe5bfab, 0x89f5}, /* U+5FEB */ + {0xe5bfae, 0xf2c0}, /* U+5FEE [2000] */ + {0xe5bfaf, 0xf2c1}, /* U+5FEF [2000] */ + {0xe5bfb0, 0x9cab}, /* U+5FF0 */ + {0xe5bfb1, 0x9c79}, /* U+5FF1 */ + {0xe5bfb3, 0xf2c2}, /* U+5FF3 [2000] */ + {0xe5bfb5, 0x944f}, /* U+5FF5 */ + {0xe5bfb8, 0x9c78}, /* U+5FF8 */ + {0xe5bfbb, 0x9c76}, /* U+5FFB */ + {0xe5bfbc, 0xf2c3}, /* U+5FFC [2000] */ + {0xe5bfbd, 0x8d9a}, /* U+5FFD */ + {0xe5bfbf, 0x9c7c}, /* U+5FFF */ + {0xe6808d, 0xeac8}, /* U+600D [2000] */ + {0xe6808e, 0x9c83}, /* U+600E */ + {0xe6808f, 0x9c89}, /* U+600F */ + {0xe68090, 0x9c81}, /* U+6010 */ + {0xe68092, 0x937b}, /* U+6012 */ + {0xe68094, 0xeac9}, /* U+6014 [2000] */ + {0xe68095, 0x9c86}, /* U+6015 */ + {0xe68096, 0x957c}, /* U+6016 */ + {0xe68097, 0xf2c5}, /* U+6017 [2000] */ + {0xe68098, 0xeaca}, /* U+6018 [2000] */ + {0xe68099, 0x9c80}, /* U+6019 */ + {0xe6809b, 0x9c85}, /* U+601B */ + {0xe6809c, 0x97e5}, /* U+601C */ + {0xe6809d, 0x8e76}, /* U+601D */ + {0xe680a0, 0x91d3}, /* U+6020 */ + {0xe680a1, 0x9c7d}, /* U+6021 */ + {0xe680a2, 0xf2c6}, /* U+6022 [2000] */ + {0xe680a4, 0xf2c7}, /* U+6024 [2000] */ + {0xe680a5, 0x8b7d}, /* U+6025 */ + {0xe680a6, 0x9c88}, /* U+6026 */ + {0xe680a7, 0x90ab}, /* U+6027 */ + {0xe680a8, 0x8985}, /* U+6028 */ + {0xe680a9, 0x9c82}, /* U+6029 */ + {0xe680aa, 0x89f6}, /* U+602A */ + {0xe680ab, 0x9c87}, /* U+602B */ + {0xe680af, 0x8baf}, /* U+602F */ + {0xe680b1, 0x9c84}, /* U+6031 */ + {0xe680b3, 0xeacb}, /* U+6033 [2000] */ + {0xe680b5, 0xeacc}, /* U+6035 [2000] */ + {0xe680ba, 0x9c8a}, /* U+603A */ + {0xe68181, 0x9c8c}, /* U+6041 */ + {0xe68182, 0x9c96}, /* U+6042 */ + {0xe68183, 0x9c94}, /* U+6043 */ + {0xe68186, 0x9c91}, /* U+6046 */ + {0xe68187, 0xeacd}, /* U+6047 [2000] */ + {0xe6818a, 0x9c90}, /* U+604A */ + {0xe6818b, 0x97f6}, /* U+604B */ + {0xe6818c, 0xf2c9}, /* U+604C [2000] */ + {0xe6818d, 0x9c92}, /* U+604D */ + {0xe68190, 0x8bb0}, /* U+6050 */ + {0xe68192, 0x8d50}, /* U+6052 */ + {0xe68195, 0x8f9a}, /* U+6055 */ + {0xe68199, 0x9c99}, /* U+6059 */ + {0xe6819a, 0x9c8b}, /* U+605A */ + {0xe6819f, 0x9c8f}, /* U+605F */ + {0xe681a0, 0x9c7e}, /* U+6060 */ + {0xe681a2, 0x89f8}, /* U+6062 */ + {0xe681a3, 0x9c93}, /* U+6063 */ + {0xe681a4, 0x9c95}, /* U+6064 */ + {0xe681a5, 0x9270}, /* U+6065 */ + {0xe681a8, 0x8da6}, /* U+6068 */ + {0xe681a9, 0x89b6}, /* U+6069 */ + {0xe681aa, 0x9c8d}, /* U+606A */ + {0xe681ab, 0x9c98}, /* U+606B */ + {0xe681ac, 0x9c97}, /* U+606C */ + {0xe681ad, 0x8bb1}, /* U+606D */ + {0xe681af, 0x91a7}, /* U+606F */ + {0xe681b0, 0x8a86}, /* U+6070 */ + {0xe681b5, 0x8c62}, /* U+6075 */ + {0xe681b7, 0x9c8e}, /* U+6077 */ + {0xe681bf, 0xf2ca}, /* U+607F [2000] */ + {0xe68281, 0x9c9a}, /* U+6081 */ + {0xe68283, 0x9c9d}, /* U+6083 */ + {0xe68284, 0x9c9f}, /* U+6084 */ + {0xe68289, 0x8ebb}, /* U+6089 */ + {0xe6828a, 0xf2cb}, /* U+608A [2000] */ + {0xe6828b, 0x9ca5}, /* U+608B */ + {0xe6828c, 0x92ee}, /* U+608C */ + {0xe6828d, 0x9c9b}, /* U+608D */ + {0xe68292, 0x9ca3}, /* U+6092 */ + {0xe68294, 0x89f7}, /* U+6094 */ + {0xe68295, 0xf2cc}, /* U+6095 [2000] */ + {0xe68296, 0x9ca1}, /* U+6096 */ + {0xe68297, 0x9ca2}, /* U+6097 */ + {0xe6829a, 0x9c9e}, /* U+609A */ + {0xe6829b, 0x9ca0}, /* U+609B */ + {0xe6829d, 0xeacf}, /* U+609D [2000] */ + {0xe6829e, 0xead0}, /* U+609E [2000] */ + {0xe6829f, 0x8ce5}, /* U+609F */ + {0xe682a0, 0x9749}, /* U+60A0 */ + {0xe682a3, 0x8ab3}, /* U+60A3 */ + {0xe682a6, 0x8978}, /* U+60A6 */ + {0xe682a7, 0x9ca4}, /* U+60A7 */ + {0xe682a8, 0xf2cd}, /* U+60A8 [2000] */ + {0xe682a9, 0x9459}, /* U+60A9 */ + {0xe682aa, 0x88ab}, /* U+60AA */ + {0xe682b0, 0xf2cf}, /* U+60B0 [2000] */ + {0xe682b1, 0xf2d0}, /* U+60B1 [2000] */ + {0xe682b2, 0x94df}, /* U+60B2 */ + {0xe682b3, 0x9c7b}, /* U+60B3 */ + {0xe682b4, 0x9caa}, /* U+60B4 */ + {0xe682b5, 0x9cae}, /* U+60B5 */ + {0xe682b6, 0x96e3}, /* U+60B6 */ + {0xe682b8, 0x9ca7}, /* U+60B8 */ + {0xe682bc, 0x9389}, /* U+60BC */ + {0xe682bd, 0x9cac}, /* U+60BD */ + {0xe682be, 0xf2d1}, /* U+60BE [2000] */ + {0xe68385, 0x8fee}, /* U+60C5 */ + {0xe68386, 0x9cad}, /* U+60C6 */ + {0xe68387, 0x93d5}, /* U+60C7 */ + {0xe68388, 0xf2d2}, /* U+60C8 [2000] */ + {0xe6838b, 0xead1}, /* U+60CB [2000] */ + {0xe68391, 0x9866}, /* U+60D1 */ + {0xe68393, 0x9ca9}, /* U+60D3 */ + {0xe68394, 0xead2}, /* U+60D4 [2000] */ + {0xe68395, 0xead3}, /* U+60D5 [2000] */ + {0xe68398, 0x9caf}, /* U+60D8 */ + {0xe68399, 0xf2d3}, /* U+60D9 [2000] */ + {0xe6839a, 0x8d9b}, /* U+60DA */ + {0xe6839b, 0xf2d4}, /* U+60DB [2000] */ + {0xe6839c, 0x90c9}, /* U+60DC */ + {0xe6839d, 0xead4}, /* U+60DD [2000] */ + {0xe6839f, 0x88d2}, /* U+60DF */ + {0xe683a0, 0x9ca8}, /* U+60E0 */ + {0xe683a1, 0x9ca6}, /* U+60E1 */ + {0xe683a3, 0x9179}, /* U+60E3 */ + {0xe683a7, 0x9c9c}, /* U+60E7 */ + {0xe683a8, 0x8e53}, /* U+60E8 */ + {0xe683ae, 0xf2d5}, /* U+60EE [2000] */ + {0xe683b0, 0x91c4}, /* U+60F0 */ + {0xe683b1, 0x9cbb}, /* U+60F1 */ + {0xe683b2, 0xf2d6}, /* U+60F2 [2000] */ + {0xe683b3, 0x917a}, /* U+60F3 */ + {0xe683b4, 0x9cb6}, /* U+60F4 */ + {0xe683b5, 0xf2d7}, /* U+60F5 [2000] */ + {0xe683b6, 0x9cb3}, /* U+60F6 */ + {0xe683b7, 0x9cb4}, /* U+60F7 */ + {0xe683b8, 0xead5}, /* U+60F8 [2000] */ + {0xe683b9, 0x8ee4}, /* U+60F9 */ + {0xe683ba, 0x9cb7}, /* U+60FA */ + {0xe683bb, 0x9cba}, /* U+60FB */ + {0xe68480, 0x9cb5}, /* U+6100 */ + {0xe68481, 0x8f44}, /* U+6101 */ + {0xe68483, 0x9cb8}, /* U+6103 */ + {0xe68486, 0x9cb2}, /* U+6106 */ + {0xe68488, 0x96fa}, /* U+6108 */ + {0xe68489, 0x96f9}, /* U+6109 */ + {0xe6848d, 0x9cbc}, /* U+610D */ + {0xe6848e, 0x9cbd}, /* U+610E */ + {0xe6848f, 0x88d3}, /* U+610F */ + {0xe68490, 0xf2d8}, /* U+6110 [2000] */ + {0xe68492, 0xf2d9}, /* U+6112 [2000] */ + {0xe68493, 0xf2da}, /* U+6113 [2000] */ + {0xe68495, 0x9cb1}, /* U+6115 */ + {0xe68499, 0xf2db}, /* U+6119 [2000] */ + {0xe6849a, 0x8bf0}, /* U+611A */ + {0xe6849b, 0x88a4}, /* U+611B */ + {0xe6849c, 0xead6}, /* U+611C [2000] */ + {0xe6849e, 0xf2dc}, /* U+611E [2000] */ + {0xe6849f, 0x8ab4}, /* U+611F */ + {0xe684a1, 0x9cb9}, /* U+6121 */ + {0xe684a7, 0x9cc1}, /* U+6127 */ + {0xe684a8, 0x9cc0}, /* U+6128 */ + {0xe684ab, 0xead7}, /* U+612B [2000] */ + {0xe684ac, 0x9cc5}, /* U+612C */ + {0xe684b0, 0xead8}, /* U+6130 [2000] */ + {0xe684b4, 0x9cc6}, /* U+6134 */ + {0xe684b7, 0xead9}, /* U+6137 [2000] */ + {0xe684ba, 0xf2dd}, /* U+613A [2000] */ + {0xe684bc, 0x9cc4}, /* U+613C */ + {0xe684bd, 0x9cc7}, /* U+613D */ + {0xe684be, 0x9cbf}, /* U+613E */ + {0xe684bf, 0x9cc3}, /* U+613F */ + {0xe68581, 0xf2df}, /* U+6141 [2000] */ + {0xe68582, 0x9cc8}, /* U+6142 */ + {0xe68584, 0x9cc9}, /* U+6144 */ + {0xe68586, 0xf2e0}, /* U+6146 [2000] */ + {0xe68587, 0x9cbe}, /* U+6147 */ + {0xe68588, 0x8e9c}, /* U+6148 */ + {0xe6858a, 0x9cc2}, /* U+614A */ + {0xe6858b, 0x91d4}, /* U+614B */ + {0xe6858c, 0x8d51}, /* U+614C */ + {0xe6858d, 0x9cb0}, /* U+614D */ + {0xe6858e, 0x9054}, /* U+614E */ + {0xe68593, 0x9cd6}, /* U+6153 */ + {0xe68595, 0x95e7}, /* U+6155 */ + {0xe68598, 0x9ccc}, /* U+6158 */ + {0xe68599, 0x9ccd}, /* U+6159 */ + {0xe6859a, 0x9cce}, /* U+615A */ + {0xe6859d, 0x9cd5}, /* U+615D */ + {0xe6859f, 0x9cd4}, /* U+615F */ + {0xe685a0, 0xf2e1}, /* U+6160 [2000] */ + {0xe685a2, 0x969d}, /* U+6162 */ + {0xe685a3, 0x8ab5}, /* U+6163 */ + {0xe685a5, 0x9cd2}, /* U+6165 */ + {0xe685a7, 0x8c64}, /* U+6167 */ + {0xe685a8, 0x8a53}, /* U+6168 */ + {0xe685ab, 0x9ccf}, /* U+616B */ + {0xe685ae, 0x97b6}, /* U+616E */ + {0xe685af, 0x9cd1}, /* U+616F */ + {0xe685b0, 0x88d4}, /* U+6170 */ + {0xe685b1, 0x9cd3}, /* U+6171 */ + {0xe685b3, 0x9cca}, /* U+6173 */ + {0xe685b4, 0x9cd0}, /* U+6174 */ + {0xe685b5, 0x9cd7}, /* U+6175 */ + {0xe685b6, 0x8c63}, /* U+6176 */ + {0xe685b7, 0x9ccb}, /* U+6177 */ + {0xe685bc, 0xf2e2}, /* U+617C [2000] */ + {0xe685be, 0x977c}, /* U+617E */ + {0xe68682, 0x974a}, /* U+6182 */ + {0xe68687, 0x9cda}, /* U+6187 */ + {0xe6868a, 0x9cde}, /* U+618A */ + {0xe6868d, 0xeadb}, /* U+618D [2000] */ + {0xe6868e, 0x919e}, /* U+618E */ + {0xe68690, 0x97f7}, /* U+6190 */ + {0xe68691, 0x9cdf}, /* U+6191 */ + {0xe68692, 0xf2e4}, /* U+6192 [2000] */ + {0xe68693, 0xf2e5}, /* U+6193 [2000] */ + {0xe68694, 0x9cdc}, /* U+6194 */ + {0xe68696, 0x9cd9}, /* U+6196 */ + {0xe68697, 0xf2e6}, /* U+6197 [2000] */ + {0xe68698, 0xf2e7}, /* U+6198 [2000] */ + {0xe68699, 0x9cd8}, /* U+6199 */ + {0xe6869a, 0x9cdd}, /* U+619A */ + {0xe686a4, 0x95ae}, /* U+61A4 */ + {0xe686a5, 0xf2e8}, /* U+61A5 [2000] */ + {0xe686a7, 0x93b2}, /* U+61A7 */ + {0xe686a8, 0xf2e9}, /* U+61A8 [2000] */ + {0xe686a9, 0x8c65}, /* U+61A9 */ + {0xe686ab, 0x9ce0}, /* U+61AB */ + {0xe686ac, 0x9cdb}, /* U+61AC */ + {0xe686ad, 0xf2ea}, /* U+61AD [2000] */ + {0xe686ae, 0x9ce1}, /* U+61AE */ + {0xe686b2, 0x8c9b}, /* U+61B2 */ + {0xe686b6, 0x89af}, /* U+61B6 */ + {0xe686b9, 0xeade}, /* U+61B9 [2000] */ + {0xe686ba, 0x9ce9}, /* U+61BA */ + {0xe686bc, 0xeadd}, /* U+61BC [2000] */ + {0xe686be, 0x8ab6}, /* U+61BE */ + {0xe68783, 0x9ce7}, /* U+61C3 */ + {0xe68786, 0x9ce8}, /* U+61C6 */ + {0xe68787, 0x8da7}, /* U+61C7 */ + {0xe68788, 0x9ce6}, /* U+61C8 */ + {0xe68789, 0x9ce4}, /* U+61C9 */ + {0xe6878a, 0x9ce3}, /* U+61CA */ + {0xe6878b, 0x9cea}, /* U+61CB */ + {0xe6878c, 0x9ce2}, /* U+61CC */ + {0xe6878d, 0x9cec}, /* U+61CD */ + {0xe68790, 0x89f9}, /* U+61D0 */ + {0xe68795, 0xf2ec}, /* U+61D5 [2000] */ + {0xe6879d, 0xf2ed}, /* U+61DD [2000] */ + {0xe6879f, 0xf2ee}, /* U+61DF [2000] */ + {0xe687a3, 0x9cee}, /* U+61E3 */ + {0xe687a6, 0x9ced}, /* U+61E6 */ + {0xe687b2, 0x92a6}, /* U+61F2 */ + {0xe687b4, 0x9cf1}, /* U+61F4 */ + {0xe687b5, 0xf2ef}, /* U+61F5 [2000] */ + {0xe687b6, 0x9cef}, /* U+61F6 */ + {0xe687b7, 0x9ce5}, /* U+61F7 */ + {0xe687b8, 0x8c9c}, /* U+61F8 */ + {0xe687ba, 0x9cf0}, /* U+61FA */ + {0xe687bc, 0x9cf4}, /* U+61FC */ + {0xe687bd, 0x9cf3}, /* U+61FD */ + {0xe687be, 0x9cf5}, /* U+61FE */ + {0xe687bf, 0x9cf2}, /* U+61FF */ + {0xe68880, 0x9cf6}, /* U+6200 */ + {0xe68888, 0x9cf7}, /* U+6208 */ + {0xe68889, 0x9cf8}, /* U+6209 */ + {0xe6888a, 0x95e8}, /* U+620A */ + {0xe6888c, 0x9cfa}, /* U+620C */ + {0xe6888d, 0x9cf9}, /* U+620D */ + {0xe6888e, 0x8f5e}, /* U+620E */ + {0xe68890, 0x90ac}, /* U+6210 */ + {0xe68891, 0x89e4}, /* U+6211 */ + {0xe68892, 0x89fa}, /* U+6212 */ + {0xe68894, 0x9cfb}, /* U+6214 */ + {0xe68895, 0xf2f1}, /* U+6215 [2000] */ + {0xe68896, 0x88bd}, /* U+6216 */ + {0xe6889a, 0x90ca}, /* U+621A */ + {0xe6889b, 0x9cfc}, /* U+621B */ + {0xe6889d, 0xe6c1}, /* U+621D */ + {0xe6889e, 0x9d40}, /* U+621E */ + {0xe6889f, 0x8c81}, /* U+621F */ + {0xe688a1, 0x9d41}, /* U+6221 */ + {0xe688a2, 0xeae0}, /* U+6222 [2000] */ + {0xe688a3, 0xf2f2}, /* U+6223 [2000] */ + {0xe688a6, 0x90ed}, /* U+6226 */ + {0xe688a9, 0xf2f3}, /* U+6229 [2000] */ + {0xe688aa, 0x9d42}, /* U+622A */ + {0xe688ae, 0x9d43}, /* U+622E */ + {0xe688af, 0x8b59}, /* U+622F */ + {0xe688b0, 0x9d44}, /* U+6230 */ + {0xe688b2, 0x9d45}, /* U+6232 */ + {0xe688b3, 0x9d46}, /* U+6233 */ + {0xe688b4, 0x91d5}, /* U+6234 */ + {0xe688b8, 0x8ccb}, /* U+6238 */ + {0xe688bb, 0x96df}, /* U+623B */ + {0xe688be, 0xeae1}, /* U+623E [2000] */ + {0xe688bf, 0x965b}, /* U+623F */ + {0xe68980, 0x8f8a}, /* U+6240 */ + {0xe68981, 0x9d47}, /* U+6241 */ + {0xe68983, 0xeae2}, /* U+6243 [2000] */ + {0xe68986, 0xf2f4}, /* U+6246 [2000] */ + {0xe68987, 0x90ee}, /* U+6247 */ + {0xe68988, 0xe7bb}, /* U+6248 */ + {0xe68989, 0x94e0}, /* U+6249 */ + {0xe6898b, 0x8ee8}, /* U+624B */ + {0xe6898c, 0xf2f5}, /* U+624C [2000] */ + {0xe6898d, 0x8dcb}, /* U+624D */ + {0xe6898e, 0x9d48}, /* U+624E */ + {0xe68991, 0xf2f6}, /* U+6251 [2000] */ + {0xe68992, 0xf2f7}, /* U+6252 [2000] */ + {0xe68993, 0x91c5}, /* U+6253 */ + {0xe68995, 0x95a5}, /* U+6255 */ + {0xe68996, 0xeae3}, /* U+6256 [2000] */ + {0xe68998, 0x91ef}, /* U+6258 */ + {0xe6899a, 0xeae4}, /* U+625A [2000] */ + {0xe6899b, 0x9d4b}, /* U+625B */ + {0xe6899e, 0x9d49}, /* U+625E */ + {0xe689a0, 0x9d4c}, /* U+6260 */ + {0xe689a1, 0xf2f8}, /* U+6261 [2000] */ + {0xe689a3, 0x9d4a}, /* U+6263 */ + {0xe689a4, 0xf2f9}, /* U+6264 [2000] */ + {0xe689a8, 0x9d4d}, /* U+6268 */ + {0xe689ad, 0xf2fb}, /* U+626D [2000] */ + {0xe689ae, 0x95af}, /* U+626E */ + {0xe689af, 0xeae5}, /* U+626F [2000] */ + {0xe689b1, 0x88b5}, /* U+6271 */ + {0xe689b3, 0xf2fc}, /* U+6273 [2000] */ + {0xe689b6, 0x957d}, /* U+6276 */ + {0xe689b9, 0x94e1}, /* U+6279 */ + {0xe689bb, 0xf2fa}, /* U+627B [2000] */ + {0xe689bc, 0x9d4e}, /* U+627C */ + {0xe689be, 0x9d51}, /* U+627E */ + {0xe689bf, 0x8fb3}, /* U+627F */ + {0xe68a80, 0x8b5a}, /* U+6280 */ + {0xe68a82, 0x9d4f}, /* U+6282 */ + {0xe68a83, 0x9d56}, /* U+6283 */ + {0xe68a84, 0x8fb4}, /* U+6284 */ + {0xe68a85, 0xeae6}, /* U+6285 [2000] */ + {0xe68a89, 0x9d50}, /* U+6289 */ + {0xe68a8a, 0x9463}, /* U+628A */ + {0xe68a91, 0x977d}, /* U+6291 */ + {0xe68a92, 0x9d52}, /* U+6292 */ + {0xe68a93, 0x9d53}, /* U+6293 */ + {0xe68a94, 0x9d57}, /* U+6294 */ + {0xe68a95, 0x938a}, /* U+6295 */ + {0xe68a96, 0x9d54}, /* U+6296 */ + {0xe68a97, 0x8d52}, /* U+6297 */ + {0xe68a98, 0x90dc}, /* U+6298 */ + {0xe68a99, 0xf340}, /* U+6299 [2000] */ + {0xe68a9b, 0x9d65}, /* U+629B */ + {0xe68a9c, 0x94b2}, /* U+629C */ + {0xe68a9e, 0x91f0}, /* U+629E */ + {0xe68aa6, 0xf341}, /* U+62A6 [2000] */ + {0xe68aab, 0x94e2}, /* U+62AB */ + {0xe68aac, 0x9dab}, /* U+62AC */ + {0xe68ab1, 0x95f8}, /* U+62B1 */ + {0xe68ab5, 0x92ef}, /* U+62B5 */ + {0xe68ab9, 0x9695}, /* U+62B9 */ + {0xe68abb, 0x9d5a}, /* U+62BB */ + {0xe68abc, 0x899f}, /* U+62BC */ + {0xe68abd, 0x928a}, /* U+62BD */ + {0xe68b82, 0x9d63}, /* U+62C2 */ + {0xe68b84, 0xeae7}, /* U+62C4 [2000] */ + {0xe68b85, 0x9253}, /* U+62C5 */ + {0xe68b86, 0x9d5d}, /* U+62C6 */ + {0xe68b87, 0x9d64}, /* U+62C7 */ + {0xe68b88, 0x9d5f}, /* U+62C8 */ + {0xe68b89, 0x9d66}, /* U+62C9 */ + {0xe68b8a, 0x9d62}, /* U+62CA */ + {0xe68b8c, 0x9d61}, /* U+62CC */ + {0xe68b8d, 0x948f}, /* U+62CD */ + {0xe68b8f, 0x9d5b}, /* U+62CF */ + {0xe68b90, 0x89fb}, /* U+62D0 */ + {0xe68b91, 0x9d59}, /* U+62D1 */ + {0xe68b92, 0x8b91}, /* U+62D2 */ + {0xe68b93, 0x91f1}, /* U+62D3 */ + {0xe68b94, 0x9d55}, /* U+62D4 */ + {0xe68b95, 0xf342}, /* U+62D5 [2000] */ + {0xe68b96, 0xeae8}, /* U+62D6 [2000] */ + {0xe68b97, 0x9d58}, /* U+62D7 */ + {0xe68b98, 0x8d53}, /* U+62D8 */ + {0xe68b99, 0x90d9}, /* U+62D9 */ + {0xe68b9b, 0x8fb5}, /* U+62DB */ + {0xe68b9c, 0x9d60}, /* U+62DC */ + {0xe68b9d, 0x9471}, /* U+62DD */ + {0xe68ba0, 0x8b92}, /* U+62E0 */ + {0xe68ba1, 0x8a67}, /* U+62E1 */ + {0xe68bac, 0x8a87}, /* U+62EC */ + {0xe68bad, 0x9040}, /* U+62ED */ + {0xe68bae, 0x9d68}, /* U+62EE */ + {0xe68baf, 0x9d6d}, /* U+62EF */ + {0xe68bb1, 0x9d69}, /* U+62F1 */ + {0xe68bb3, 0x8c9d}, /* U+62F3 */ + {0xe68bb5, 0x9d6e}, /* U+62F5 */ + {0xe68bb6, 0x8e41}, /* U+62F6 */ + {0xe68bb7, 0x8d89}, /* U+62F7 */ + {0xe68bbc, 0xeae9}, /* U+62FC [2000] */ + {0xe68bbd, 0xf344}, /* U+62FD [2000] */ + {0xe68bbe, 0x8f45}, /* U+62FE */ + {0xe68bbf, 0x9d5c}, /* U+62FF */ + {0xe68c81, 0x8e9d}, /* U+6301 */ + {0xe68c82, 0x9d6b}, /* U+6302 */ + {0xe68c83, 0xf345}, /* U+6303 [2000] */ + {0xe68c87, 0x8e77}, /* U+6307 */ + {0xe68c88, 0x9d6c}, /* U+6308 */ + {0xe68c89, 0x88c2}, /* U+6309 */ + {0xe68c8a, 0xeaea}, /* U+630A [2000] */ + {0xe68c8c, 0x9d67}, /* U+630C */ + {0xe68c8d, 0xf346}, /* U+630D [2000] */ + {0xe68c90, 0xf347}, /* U+6310 [2000] */ + {0xe68c91, 0x92a7}, /* U+6311 */ + {0xe68c98, 0xeaeb}, /* U+6318 [2000] */ + {0xe68c99, 0x8b93}, /* U+6319 */ + {0xe68c9f, 0x8bb2}, /* U+631F */ + {0xe68ca7, 0x9d6a}, /* U+6327 */ + {0xe68ca8, 0x88a5}, /* U+6328 */ + {0xe68cab, 0x8dc1}, /* U+632B */ + {0xe68caf, 0x9055}, /* U+632F */ + {0xe68cb2, 0xf34a}, /* U+6332 [2000] */ + {0xe68cb5, 0xf34b}, /* U+6335 [2000] */ + {0xe68cb9, 0xeaec}, /* U+6339 [2000] */ + {0xe68cba, 0x92f0}, /* U+633A */ + {0xe68cbb, 0xf34c}, /* U+633B [2000] */ + {0xe68cbc, 0xf34d}, /* U+633C [2000] */ + {0xe68cbd, 0x94d2}, /* U+633D */ + {0xe68cbe, 0x9d70}, /* U+633E */ + {0xe68cbf, 0x917d}, /* U+633F */ + {0xe68d81, 0xf34e}, /* U+6341 [2000] */ + {0xe68d83, 0xeaed}, /* U+6343 [2000] */ + {0xe68d84, 0xf34f}, /* U+6344 [2000] */ + {0xe68d89, 0x91a8}, /* U+6349 */ + {0xe68d8c, 0x8e4a}, /* U+634C */ + {0xe68d8d, 0x9d71}, /* U+634D */ + {0xe68d8e, 0xf350}, /* U+634E [2000] */ + {0xe68d8f, 0x9d73}, /* U+634F */ + {0xe68d90, 0x9d6f}, /* U+6350 */ + {0xe68d95, 0x95df}, /* U+6355 */ + {0xe68d97, 0x92bb}, /* U+6357 */ + {0xe68d99, 0xf352}, /* U+6359 [2000] */ + {0xe68d9c, 0x917b}, /* U+635C */ + {0xe68da5, 0xeaee}, /* U+6365 [2000] */ + {0xe68da7, 0x95f9}, /* U+6367 */ + {0xe68da8, 0x8ecc}, /* U+6368 */ + {0xe68da9, 0x9d80}, /* U+6369 */ + {0xe68dab, 0x9d7e}, /* U+636B */ + {0xe68dac, 0xf355}, /* U+636C [2000] */ + {0xe68dae, 0x9098}, /* U+636E */ + {0xe68db2, 0x8c9e}, /* U+6372 */ + {0xe68db6, 0x9d78}, /* U+6376 */ + {0xe68db7, 0x8fb7}, /* U+6377 */ + {0xe68dba, 0x93e6}, /* U+637A */ + {0xe68dbb, 0x9450}, /* U+637B */ + {0xe68dbc, 0xeaef}, /* U+637C [2000] */ + {0xe68e80, 0x9d76}, /* U+6380 */ + {0xe68e83, 0x917c}, /* U+6383 */ + {0xe68e84, 0xf356}, /* U+6384 [2000] */ + {0xe68e88, 0x8ef6}, /* U+6388 */ + {0xe68e89, 0x9d7b}, /* U+6389 */ + {0xe68e8c, 0x8fb6}, /* U+638C */ + {0xe68e8e, 0x9d75}, /* U+638E */ + {0xe68e8f, 0x9d7a}, /* U+638F */ + {0xe68e92, 0x9472}, /* U+6392 */ + {0xe68e94, 0xf359}, /* U+6394 [2000] */ + {0xe68e96, 0x9d74}, /* U+6396 */ + {0xe68e98, 0x8c40}, /* U+6398 */ + {0xe68e99, 0xf357}, /* U+6399 [2000] */ + {0xe68e9b, 0x8a7c}, /* U+639B */ + {0xe68e9f, 0x9d7c}, /* U+639F */ + {0xe68ea0, 0x97a9}, /* U+63A0 */ + {0xe68ea1, 0x8dcc}, /* U+63A1 */ + {0xe68ea2, 0x9254}, /* U+63A2 */ + {0xe68ea3, 0x9d79}, /* U+63A3 */ + {0xe68ea5, 0x90da}, /* U+63A5 */ + {0xe68ea7, 0x8d54}, /* U+63A7 */ + {0xe68ea8, 0x9084}, /* U+63A8 */ + {0xe68ea9, 0x8986}, /* U+63A9 */ + {0xe68eaa, 0x915b}, /* U+63AA */ + {0xe68eab, 0x9d77}, /* U+63AB */ + {0xe68eac, 0x8b64}, /* U+63AC */ + {0xe68eb2, 0x8c66}, /* U+63B2 */ + {0xe68eb4, 0x92cd}, /* U+63B4 */ + {0xe68eb5, 0x9d7d}, /* U+63B5 */ + {0xe68ebb, 0x917e}, /* U+63BB */ + {0xe68ebd, 0xf35a}, /* U+63BD [2000] */ + {0xe68ebe, 0x9d81}, /* U+63BE */ + {0xe68f80, 0x9d83}, /* U+63C0 */ + {0xe68f83, 0x91b5}, /* U+63C3 */ + {0xe68f84, 0x9d89}, /* U+63C4 */ + {0xe68f86, 0x9d84}, /* U+63C6 */ + {0xe68f89, 0x9d86}, /* U+63C9 */ + {0xe68f8f, 0x9560}, /* U+63CF */ + {0xe68f90, 0x92f1}, /* U+63D0 */ + {0xe68f92, 0x9d87}, /* U+63D2 */ + {0xe68f94, 0xf35c}, /* U+63D4 [2000] */ + {0xe68f95, 0xf35d}, /* U+63D5 [2000] */ + {0xe68f96, 0x974b}, /* U+63D6 */ + {0xe68f9a, 0x9767}, /* U+63DA */ + {0xe68f9b, 0x8ab7}, /* U+63DB */ + {0xe68f9c, 0xf35e}, /* U+63DC [2000] */ + {0xe68fa0, 0xf35f}, /* U+63E0 [2000] */ + {0xe68fa1, 0x88ac}, /* U+63E1 */ + {0xe68fa3, 0x9d85}, /* U+63E3 */ + {0xe68fa5, 0xeaf0}, /* U+63E5 [2000] */ + {0xe68fa9, 0x9d82}, /* U+63E9 */ + {0xe68fab, 0xf360}, /* U+63EB [2000] */ + {0xe68fac, 0xf361}, /* U+63EC [2000] */ + {0xe68fad, 0xeaf1}, /* U+63ED [2000] */ + {0xe68fae, 0x8af6}, /* U+63EE */ + {0xe68fb2, 0xf362}, /* U+63F2 [2000] */ + {0xe68fb4, 0x8987}, /* U+63F4 */ + {0xe68fb5, 0xeaf2}, /* U+63F5 [2000] */ + {0xe68fb6, 0x9d88}, /* U+63F6 */ + {0xe68fb7, 0xf35b}, /* U+63F7 [2000] */ + {0xe68fba, 0x9768}, /* U+63FA */ + {0xe69086, 0x9d8c}, /* U+6406 */ + {0xe69089, 0xf363}, /* U+6409 [2000] */ + {0xe6908d, 0x91b9}, /* U+640D */ + {0xe6908f, 0x9d93}, /* U+640F */ + {0xe69090, 0xeaf3}, /* U+6410 [2000] */ + {0xe69093, 0x9d8d}, /* U+6413 */ + {0xe69094, 0xeaf4}, /* U+6414 [2000] */ + {0xe69096, 0x9d8a}, /* U+6416 */ + {0xe69097, 0x9d91}, /* U+6417 */ + {0xe6909c, 0x9d72}, /* U+641C */ + {0xe6909e, 0xf364}, /* U+641E [2000] */ + {0xe690a2, 0xeaf5}, /* U+6422 [2000] */ + {0xe690a5, 0xf365}, /* U+6425 [2000] */ + {0xe690a6, 0x9d8e}, /* U+6426 */ + {0xe690a8, 0x9d92}, /* U+6428 */ + {0xe690a9, 0xf366}, /* U+6429 [2000] */ + {0xe690ac, 0x94c0}, /* U+642C */ + {0xe690ad, 0x938b}, /* U+642D */ + {0xe690af, 0xf367}, /* U+642F [2000] */ + {0xe690b4, 0x9d8b}, /* U+6434 */ + {0xe690b6, 0x9d8f}, /* U+6436 */ + {0xe690ba, 0x8c67}, /* U+643A */ + {0xe690be, 0x8def}, /* U+643E */ + {0xe69182, 0x90db}, /* U+6442 */ + {0xe6918e, 0x9d97}, /* U+644E */ + {0xe69191, 0xeaf7}, /* U+6451 [2000] */ + {0xe69198, 0x9345}, /* U+6458 */ + {0xe6919a, 0xf368}, /* U+645A [2000] */ + {0xe6919b, 0xf369}, /* U+645B [2000] */ + {0xe6919d, 0xf36a}, /* U+645D [2000] */ + {0xe691a0, 0xeaf8}, /* U+6460 [2000] */ + {0xe691a7, 0x9d94}, /* U+6467 */ + {0xe691a9, 0x9680}, /* U+6469 */ + {0xe691ad, 0xeaf9}, /* U+646D [2000] */ + {0xe691af, 0x9d95}, /* U+646F */ + {0xe691b3, 0xf36b}, /* U+6473 [2000] */ + {0xe691b6, 0x9d96}, /* U+6476 */ + {0xe691b8, 0x96cc}, /* U+6478 */ + {0xe691b9, 0xeaf6}, /* U+6479 [2000] */ + {0xe691ba, 0x90a0}, /* U+647A */ + {0xe691bd, 0xf36c}, /* U+647D [2000] */ + {0xe69283, 0x8c82}, /* U+6483 */ + {0xe69287, 0xf36d}, /* U+6487 [2000] */ + {0xe69288, 0x9d9d}, /* U+6488 */ + {0xe69291, 0xf36e}, /* U+6491 [2000] */ + {0xe69292, 0x8e54}, /* U+6492 */ + {0xe69293, 0x9d9a}, /* U+6493 */ + {0xe69295, 0x9d99}, /* U+6495 */ + {0xe6929a, 0x9451}, /* U+649A */ + {0xe6929d, 0xf36f}, /* U+649D [2000] */ + {0xe6929e, 0x93b3}, /* U+649E */ + {0xe6929f, 0xf370}, /* U+649F [2000] */ + {0xe692a4, 0x9350}, /* U+64A4 */ + {0xe692a5, 0x9d9b}, /* U+64A5 */ + {0xe692a9, 0x9d9c}, /* U+64A9 */ + {0xe692ab, 0x958f}, /* U+64AB */ + {0xe692ad, 0x9464}, /* U+64AD */ + {0xe692ae, 0x8e42}, /* U+64AE */ + {0xe692b0, 0x90ef}, /* U+64B0 */ + {0xe692b2, 0x966f}, /* U+64B2 */ + {0xe692b9, 0x8a68}, /* U+64B9 */ + {0xe692bb, 0x9da3}, /* U+64BB */ + {0xe692bc, 0x9d9e}, /* U+64BC */ + {0xe692be, 0xeafb}, /* U+64BE [2000] */ + {0xe692bf, 0xeafc}, /* U+64BF [2000] */ + {0xe69381, 0x9769}, /* U+64C1 */ + {0xe69382, 0x9da5}, /* U+64C2 */ + {0xe69384, 0xeb40}, /* U+64C4 [2000] */ + {0xe69385, 0x9da1}, /* U+64C5 */ + {0xe69387, 0x9da2}, /* U+64C7 */ + {0xe6938a, 0xeb41}, /* U+64CA [2000] */ + {0xe6938b, 0xf371}, /* U+64CB [2000] */ + {0xe6938c, 0xf372}, /* U+64CC [2000] */ + {0xe6938d, 0x9180}, /* U+64CD */ + {0xe6938e, 0xeafa}, /* U+64CE [2000] */ + {0xe69390, 0xeb42}, /* U+64D0 [2000] */ + {0xe69392, 0x9da0}, /* U+64D2 */ + {0xe69394, 0x9d5e}, /* U+64D4 */ + {0xe69395, 0xf373}, /* U+64D5 [2000] */ + {0xe69397, 0xf374}, /* U+64D7 [2000] */ + {0xe69398, 0x9da4}, /* U+64D8 */ + {0xe6939a, 0x9d9f}, /* U+64DA */ + {0xe693a0, 0x9da9}, /* U+64E0 */ + {0xe693a1, 0x9daa}, /* U+64E1 */ + {0xe693a2, 0x9346}, /* U+64E2 */ + {0xe693a3, 0x9dac}, /* U+64E3 */ + {0xe693a4, 0xf376}, /* U+64E4 [2000] */ + {0xe693a5, 0xf377}, /* U+64E5 [2000] */ + {0xe693a6, 0x8e43}, /* U+64E6 */ + {0xe693a7, 0x9da7}, /* U+64E7 */ + {0xe693ac, 0x8b5b}, /* U+64EC */ + {0xe693af, 0x9dad}, /* U+64EF */ + {0xe693b1, 0x9da6}, /* U+64F1 */ + {0xe693b2, 0x9db1}, /* U+64F2 */ + {0xe693b4, 0x9db0}, /* U+64F4 */ + {0xe693b6, 0x9daf}, /* U+64F6 */ + {0xe693b7, 0xeb43}, /* U+64F7 [2000] */ + {0xe693ba, 0x9db2}, /* U+64FA */ + {0xe693bb, 0xeb44}, /* U+64FB [2000] */ + {0xe693bd, 0x9db4}, /* U+64FD */ + {0xe693be, 0x8fef}, /* U+64FE */ + {0xe693bf, 0xf378}, /* U+64FF [2000] */ + {0xe69480, 0x9db3}, /* U+6500 */ + {0xe69484, 0xf379}, /* U+6504 [2000] */ + {0xe69485, 0x9db7}, /* U+6505 */ + {0xe6948f, 0xf37b}, /* U+650F [2000] */ + {0xe69494, 0xf37c}, /* U+6514 [2000] */ + {0xe69496, 0xf37d}, /* U+6516 [2000] */ + {0xe69498, 0x9db5}, /* U+6518 */ + {0xe6949c, 0x9db6}, /* U+651C */ + {0xe6949d, 0x9d90}, /* U+651D */ + {0xe6949e, 0xf380}, /* U+651E [2000] */ + {0xe694a2, 0xeb45}, /* U+6522 [2000] */ + {0xe694a3, 0x9db9}, /* U+6523 */ + {0xe694a4, 0x9db8}, /* U+6524 */ + {0xe694a9, 0xeb46}, /* U+6529 [2000] */ + {0xe694aa, 0x9d98}, /* U+652A */ + {0xe694ab, 0x9dba}, /* U+652B */ + {0xe694ac, 0x9dae}, /* U+652C */ + {0xe694af, 0x8e78}, /* U+652F */ + {0xe694b2, 0xf381}, /* U+6532 [2000] */ + {0xe694b4, 0x9dbb}, /* U+6534 */ + {0xe694b5, 0x9dbc}, /* U+6535 */ + {0xe694b6, 0x9dbe}, /* U+6536 */ + {0xe694b7, 0x9dbd}, /* U+6537 */ + {0xe694b8, 0x9dbf}, /* U+6538 */ + {0xe694b9, 0x89fc}, /* U+6539 */ + {0xe694bb, 0x8d55}, /* U+653B */ + {0xe694be, 0x95fa}, /* U+653E */ + {0xe694bf, 0x90ad}, /* U+653F */ + {0xe69584, 0xf382}, /* U+6544 [2000] */ + {0xe69585, 0x8ccc}, /* U+6545 */ + {0xe69588, 0x9dc1}, /* U+6548 */ + {0xe6958d, 0x9dc4}, /* U+654D */ + {0xe6958f, 0x9571}, /* U+654F */ + {0xe69591, 0x8b7e}, /* U+6551 */ + {0xe69594, 0xf383}, /* U+6554 [2000] */ + {0xe69595, 0x9dc3}, /* U+6555 */ + {0xe69596, 0x9dc2}, /* U+6556 */ + {0xe69597, 0x9473}, /* U+6557 */ + {0xe69598, 0x9dc5}, /* U+6558 */ + {0xe69599, 0x8bb3}, /* U+6559 */ + {0xe6959d, 0x9dc7}, /* U+655D */ + {0xe6959e, 0x9dc6}, /* U+655E */ + {0xe695a2, 0x8ab8}, /* U+6562 */ + {0xe695a3, 0x8e55}, /* U+6563 */ + {0xe695a6, 0x93d6}, /* U+6566 */ + {0xe695a7, 0xeb48}, /* U+6567 [2000] */ + {0xe695ab, 0xf384}, /* U+656B [2000] */ + {0xe695ac, 0x8c68}, /* U+656C */ + {0xe695b0, 0x9094}, /* U+6570 */ + {0xe695b2, 0x9dc8}, /* U+6572 */ + {0xe695b4, 0x90ae}, /* U+6574 */ + {0xe695b5, 0x9347}, /* U+6575 */ + {0xe695b7, 0x957e}, /* U+6577 */ + {0xe695b8, 0x9dc9}, /* U+6578 */ + {0xe695ba, 0xf385}, /* U+657A [2000] */ + {0xe69681, 0xf386}, /* U+6581 [2000] */ + {0xe69682, 0x9dca}, /* U+6582 */ + {0xe69683, 0x9dcb}, /* U+6583 */ + {0xe69684, 0xf387}, /* U+6584 [2000] */ + {0xe69685, 0xf388}, /* U+6585 [2000] */ + {0xe69687, 0x95b6}, /* U+6587 */ + {0xe69688, 0x9b7c}, /* U+6588 */ + {0xe69689, 0x90c4}, /* U+6589 */ + {0xe6968a, 0xf389}, /* U+658A [2000] */ + {0xe6968c, 0x956b}, /* U+658C */ + {0xe6968e, 0x8dd6}, /* U+658E */ + {0xe69690, 0x94e3}, /* U+6590 */ + {0xe69691, 0x94c1}, /* U+6591 */ + {0xe69697, 0x936c}, /* U+6597 */ + {0xe69699, 0x97bf}, /* U+6599 */ + {0xe6969b, 0x9dcd}, /* U+659B */ + {0xe6969c, 0x8ece}, /* U+659C */ + {0xe6969d, 0xeb49}, /* U+659D [2000] */ + {0xe6969f, 0x9dce}, /* U+659F */ + {0xe696a1, 0x88b4}, /* U+65A1 */ + {0xe696a4, 0x8bd2}, /* U+65A4 */ + {0xe696a5, 0x90cb}, /* U+65A5 */ + {0xe696a7, 0x9580}, /* U+65A7 */ + {0xe696ab, 0x9dcf}, /* U+65AB */ + {0xe696ac, 0x8e61}, /* U+65AC */ + {0xe696ad, 0x9266}, /* U+65AD */ + {0xe696af, 0x8e7a}, /* U+65AF */ + {0xe696b0, 0x9056}, /* U+65B0 */ + {0xe696b2, 0xf38a}, /* U+65B2 [2000] */ + {0xe696b5, 0xf38b}, /* U+65B5 [2000] */ + {0xe696b7, 0x9dd0}, /* U+65B7 */ + {0xe696b8, 0xf38c}, /* U+65B8 [2000] */ + {0xe696b9, 0x95fb}, /* U+65B9 */ + {0xe696bc, 0x8997}, /* U+65BC */ + {0xe696bd, 0x8e7b}, /* U+65BD */ + {0xe696bf, 0xf38d}, /* U+65BF [2000] */ + {0xe69781, 0x9dd3}, /* U+65C1 */ + {0xe69782, 0xf38e}, /* U+65C2 [2000] */ + {0xe69783, 0x9dd1}, /* U+65C3 */ + {0xe69784, 0x9dd4}, /* U+65C4 */ + {0xe69785, 0x97b7}, /* U+65C5 */ + {0xe69786, 0x9dd2}, /* U+65C6 */ + {0xe69789, 0xf38f}, /* U+65C9 [2000] */ + {0xe6978b, 0x90f9}, /* U+65CB */ + {0xe6978c, 0x9dd5}, /* U+65CC */ + {0xe6978f, 0x91b0}, /* U+65CF */ + {0xe69792, 0x9dd6}, /* U+65D2 */ + {0xe69794, 0xf390}, /* U+65D4 [2000] */ + {0xe69797, 0x8af8}, /* U+65D7 */ + {0xe69799, 0x9dd8}, /* U+65D9 */ + {0xe6979b, 0x9dd7}, /* U+65DB */ + {0xe697a0, 0x9dd9}, /* U+65E0 */ + {0xe697a1, 0x9dda}, /* U+65E1 */ + {0xe697a2, 0x8af9}, /* U+65E2 */ + {0xe697a5, 0x93fa}, /* U+65E5 */ + {0xe697a6, 0x9255}, /* U+65E6 */ + {0xe697a7, 0x8b8c}, /* U+65E7 */ + {0xe697a8, 0x8e7c}, /* U+65E8 */ + {0xe697a9, 0x9181}, /* U+65E9 */ + {0xe697ac, 0x8f7b}, /* U+65EC */ + {0xe697ad, 0x88ae}, /* U+65ED */ + {0xe697b1, 0x9ddb}, /* U+65F1 */ + {0xe697b2, 0xf392}, /* U+65F2 [2000] */ + {0xe697b9, 0xf393}, /* U+65F9 [2000] */ + {0xe697ba, 0x89a0}, /* U+65FA */ + {0xe697bb, 0x9ddf}, /* U+65FB */ + {0xe697bc, 0xf394}, /* U+65FC [2000] */ + {0xe69880, 0xeb4b}, /* U+6600 [2000] */ + {0xe69882, 0x8d56}, /* U+6602 */ + {0xe69883, 0x9dde}, /* U+6603 */ + {0xe69884, 0xf395}, /* U+6604 [2000] */ + {0xe69886, 0x8da9}, /* U+6606 */ + {0xe69887, 0x8fb8}, /* U+6607 */ + {0xe69888, 0xf396}, /* U+6608 [2000] */ + {0xe69889, 0xeb4c}, /* U+6609 [2000] */ + {0xe6988a, 0x9ddd}, /* U+660A */ + {0xe6988c, 0x8fb9}, /* U+660C */ + {0xe6988e, 0x96be}, /* U+660E */ + {0xe6988f, 0x8da8}, /* U+660F */ + {0xe69893, 0x88d5}, /* U+6613 */ + {0xe69894, 0x90cc}, /* U+6614 */ + {0xe69895, 0xeb4d}, /* U+6615 [2000] */ + {0xe6989c, 0x9de4}, /* U+661C */ + {0xe6989e, 0xeb4e}, /* U+661E [2000] */ + {0xe6989f, 0x90af}, /* U+661F */ + {0xe698a0, 0x8966}, /* U+6620 */ + {0xe698a1, 0xf397}, /* U+6621 [2000] */ + {0xe698a2, 0xeb50}, /* U+6622 [2000] */ + {0xe698a4, 0xeb51}, /* U+6624 [2000] */ + {0xe698a5, 0x8f74}, /* U+6625 */ + {0xe698a7, 0x9686}, /* U+6627 */ + {0xe698a8, 0x8df0}, /* U+6628 */ + {0xe698aa, 0xf398}, /* U+662A [2000] */ + {0xe698ab, 0xeb52}, /* U+662B [2000] */ + {0xe698ad, 0x8fba}, /* U+662D */ + {0xe698af, 0x90a5}, /* U+662F */ + {0xe698b0, 0xeb53}, /* U+6630 [2000] */ + {0xe698b1, 0xeb54}, /* U+6631 [2000] */ + {0xe698b3, 0xeb55}, /* U+6633 [2000] */ + {0xe698b4, 0x9de3}, /* U+6634 */ + {0xe698b5, 0x9de1}, /* U+6635 */ + {0xe698b6, 0x9de2}, /* U+6636 */ + {0xe698ba, 0xeb4f}, /* U+663A [2000] */ + {0xe698bc, 0x928b}, /* U+663C */ + {0xe698bf, 0x9e45}, /* U+663F */ + {0xe69981, 0x9de8}, /* U+6641 */ + {0xe69982, 0x8e9e}, /* U+6642 */ + {0xe69983, 0x8d57}, /* U+6643 */ + {0xe69984, 0x9de6}, /* U+6644 */ + {0xe69985, 0xf399}, /* U+6645 [2000] */ + {0xe69988, 0xeb57}, /* U+6648 [2000] */ + {0xe69989, 0x9de7}, /* U+6649 */ + {0xe6998b, 0x9057}, /* U+664B */ + {0xe6998c, 0xeb58}, /* U+664C [2000] */ + {0xe6998e, 0xf39b}, /* U+664E [2000] */ + {0xe6998f, 0x9de5}, /* U+664F */ + {0xe69991, 0xf39a}, /* U+6651 [2000] */ + {0xe69992, 0x8e4e}, /* U+6652 */ + {0xe69997, 0xf39e}, /* U+6657 [2000] */ + {0xe69999, 0xeb5a}, /* U+6659 [2000] */ + {0xe6999a, 0xeb5b}, /* U+665A [2000] */ + {0xe6999b, 0xf39f}, /* U+665B [2000] */ + {0xe6999d, 0x9dea}, /* U+665D */ + {0xe6999e, 0x9de9}, /* U+665E */ + {0xe6999f, 0x9dee}, /* U+665F */ + {0xe699a1, 0xeb5c}, /* U+6661 [2000] */ + {0xe699a2, 0x9def}, /* U+6662 */ + {0xe699a3, 0xf3a0}, /* U+6663 [2000] */ + {0xe699a4, 0x9deb}, /* U+6664 */ + {0xe699a5, 0xeb5d}, /* U+6665 [2000] */ + {0xe699a6, 0x8a41}, /* U+6666 */ + {0xe699a7, 0x9dec}, /* U+6667 */ + {0xe699a8, 0x9ded}, /* U+6668 */ + {0xe699a9, 0x94d3}, /* U+6669 */ + {0xe699aa, 0xf3a3}, /* U+666A [2000] */ + {0xe699ab, 0xf3a4}, /* U+666B [2000] */ + {0xe699ac, 0xf3a5}, /* U+666C [2000] */ + {0xe699ad, 0xf3a6}, /* U+666D [2000] */ + {0xe699ae, 0x9581}, /* U+666E */ + {0xe699af, 0x8c69}, /* U+666F */ + {0xe699b0, 0x9df0}, /* U+6670 */ + {0xe699b3, 0xeb5e}, /* U+6673 [2000] */ + {0xe699b4, 0x90b0}, /* U+6674 */ + {0xe699b6, 0x8fbb}, /* U+6676 */ + {0xe699b7, 0xeb5f}, /* U+6677 [2000] */ + {0xe699b8, 0xeb60}, /* U+6678 [2000] */ + {0xe699ba, 0x9271}, /* U+667A */ + {0xe699bb, 0xf3a7}, /* U+667B [2000] */ + {0xe69a80, 0xf3a8}, /* U+6680 [2000] */ + {0xe69a81, 0x8bc5}, /* U+6681 */ + {0xe69a83, 0x9df1}, /* U+6683 */ + {0xe69a84, 0x9df5}, /* U+6684 */ + {0xe69a87, 0x89c9}, /* U+6687 */ + {0xe69a88, 0x9df2}, /* U+6688 */ + {0xe69a89, 0x9df4}, /* U+6689 */ + {0xe69a8d, 0xeb61}, /* U+668D [2000] */ + {0xe69a8e, 0x9df3}, /* U+668E */ + {0xe69a90, 0xf3a9}, /* U+6690 [2000] */ + {0xe69a91, 0x8f8b}, /* U+6691 */ + {0xe69a92, 0xf3aa}, /* U+6692 [2000] */ + {0xe69a96, 0x9267}, /* U+6696 */ + {0xe69a97, 0x88c3}, /* U+6697 */ + {0xe69a98, 0x9df6}, /* U+6698 */ + {0xe69a99, 0xf3ab}, /* U+6699 [2000] */ + {0xe69a9d, 0x9df7}, /* U+669D */ + {0xe69aa0, 0xeb63}, /* U+66A0 [2000] */ + {0xe69aa2, 0x92a8}, /* U+66A2 */ + {0xe69aa6, 0x97ef}, /* U+66A6 */ + {0xe69aab, 0x8e62}, /* U+66AB */ + {0xe69aad, 0xf3ad}, /* U+66AD [2000] */ + {0xe69aae, 0x95e9}, /* U+66AE */ + {0xe69ab1, 0xf3ae}, /* U+66B1 [2000] */ + {0xe69ab2, 0xeb64}, /* U+66B2 [2000] */ + {0xe69ab4, 0x965c}, /* U+66B4 */ + {0xe69ab5, 0xf3af}, /* U+66B5 [2000] */ + {0xe69ab8, 0x9e41}, /* U+66B8 */ + {0xe69ab9, 0x9df9}, /* U+66B9 */ + {0xe69abb, 0xeb65}, /* U+66BB [2000] */ + {0xe69abc, 0x9dfc}, /* U+66BC */ + {0xe69abe, 0x9dfb}, /* U+66BE */ + {0xe69abf, 0xf3b1}, /* U+66BF [2000] */ + {0xe69b81, 0x9df8}, /* U+66C1 */ + {0xe69b84, 0x9e40}, /* U+66C4 */ + {0xe69b86, 0xeb66}, /* U+66C6 [2000] */ + {0xe69b87, 0x93dc}, /* U+66C7 */ + {0xe69b88, 0xeb67}, /* U+66C8 [2000] */ + {0xe69b89, 0x9dfa}, /* U+66C9 */ + {0xe69b96, 0x9e42}, /* U+66D6 */ + {0xe69b99, 0x8f8c}, /* U+66D9 */ + {0xe69b9a, 0x9e43}, /* U+66DA */ + {0xe69b9b, 0xeb69}, /* U+66DB [2000] */ + {0xe69b9c, 0x976a}, /* U+66DC */ + {0xe69b9d, 0x9498}, /* U+66DD */ + {0xe69ba0, 0x9e44}, /* U+66E0 */ + {0xe69ba6, 0x9e46}, /* U+66E6 */ + {0xe69ba8, 0xeb6a}, /* U+66E8 [2000] */ + {0xe69ba9, 0x9e47}, /* U+66E9 */ + {0xe69bac, 0xf3b3}, /* U+66EC [2000] */ + {0xe69bb0, 0x9e48}, /* U+66F0 */ + {0xe69bb2, 0x8bc8}, /* U+66F2 */ + {0xe69bb3, 0x8967}, /* U+66F3 */ + {0xe69bb4, 0x8d58}, /* U+66F4 */ + {0xe69bb5, 0x9e49}, /* U+66F5 */ + {0xe69bb7, 0x9e4a}, /* U+66F7 */ + {0xe69bb8, 0x8f91}, /* U+66F8 */ + {0xe69bb9, 0x9182}, /* U+66F9 */ + {0xe69bba, 0xeb6b}, /* U+66FA [2000] */ + {0xe69bbb, 0xeb56}, /* U+66FB [2000] */ + {0xe69bbc, 0x99d6}, /* U+66FC */ + {0xe69bbd, 0x915d}, /* U+66FD */ + {0xe69bbe, 0x915c}, /* U+66FE */ + {0xe69bbf, 0x91d6}, /* U+66FF */ + {0xe69c80, 0x8dc5}, /* U+6700 */ + {0xe69c81, 0xf3b5}, /* U+6701 [2000] */ + {0xe69c83, 0x98f0}, /* U+6703 */ + {0xe69c85, 0xf3b6}, /* U+6705 [2000] */ + {0xe69c88, 0x8c8e}, /* U+6708 */ + {0xe69c89, 0x974c}, /* U+6709 */ + {0xe69c8b, 0x95fc}, /* U+670B */ + {0xe69c8d, 0x959e}, /* U+670D */ + {0xe69c8f, 0x9e4b}, /* U+670F */ + {0xe69c92, 0xf3b7}, /* U+6712 [2000] */ + {0xe69c93, 0xeb6c}, /* U+6713 [2000] */ + {0xe69c94, 0x8df1}, /* U+6714 */ + {0xe69c95, 0x92bd}, /* U+6715 */ + {0xe69c96, 0x9e4c}, /* U+6716 */ + {0xe69c97, 0x984e}, /* U+6717 */ + {0xe69c99, 0xf3b9}, /* U+6719 [2000] */ + {0xe69c9b, 0x965d}, /* U+671B */ + {0xe69c9d, 0x92a9}, /* U+671D */ + {0xe69c9e, 0x9e4d}, /* U+671E */ + {0xe69c9f, 0x8afa}, /* U+671F */ + {0xe69ca6, 0x9e4e}, /* U+6726 */ + {0xe69ca7, 0x9e4f}, /* U+6727 */ + {0xe69ca8, 0x96d8}, /* U+6728 */ + {0xe69caa, 0x96a2}, /* U+672A */ + {0xe69cab, 0x9696}, /* U+672B */ + {0xe69cac, 0x967b}, /* U+672C */ + {0xe69cad, 0x8e44}, /* U+672D */ + {0xe69cae, 0x9e51}, /* U+672E */ + {0xe69cb1, 0x8ee9}, /* U+6731 */ + {0xe69cb3, 0xeb6e}, /* U+6733 [2000] */ + {0xe69cb4, 0x9670}, /* U+6734 */ + {0xe69cb6, 0x9e53}, /* U+6736 */ + {0xe69cb7, 0x9e56}, /* U+6737 */ + {0xe69cb8, 0x9e55}, /* U+6738 */ + {0xe69cba, 0x8af7}, /* U+673A */ + {0xe69cbd, 0x8b80}, /* U+673D */ + {0xe69cbf, 0x9e52}, /* U+673F */ + {0xe69d81, 0x9e54}, /* U+6741 */ + {0xe69d86, 0x9e57}, /* U+6746 */ + {0xe69d87, 0xeb70}, /* U+6747 [2000] */ + {0xe69d88, 0xeb71}, /* U+6748 [2000] */ + {0xe69d89, 0x9099}, /* U+6749 */ + {0xe69d8c, 0xf3bc}, /* U+674C [2000] */ + {0xe69d8d, 0xf3bd}, /* U+674D [2000] */ + {0xe69d8e, 0x979b}, /* U+674E */ + {0xe69d8f, 0x88c7}, /* U+674F */ + {0xe69d90, 0x8dde}, /* U+6750 */ + {0xe69d91, 0x91ba}, /* U+6751 */ + {0xe69d93, 0x8edb}, /* U+6753 */ + {0xe69d94, 0xf3be}, /* U+6754 [2000] */ + {0xe69d96, 0x8ff1}, /* U+6756 */ + {0xe69d99, 0x9e5a}, /* U+6759 */ + {0xe69d9c, 0x936d}, /* U+675C */ + {0xe69d9d, 0xf3bf}, /* U+675D [2000] */ + {0xe69d9e, 0x9e58}, /* U+675E */ + {0xe69d9f, 0x91a9}, /* U+675F */ + {0xe69da0, 0x9e59}, /* U+6760 */ + {0xe69da1, 0x8ff0}, /* U+6761 */ + {0xe69da2, 0x96db}, /* U+6762 */ + {0xe69da3, 0x9e5b}, /* U+6763 */ + {0xe69da4, 0x9e5c}, /* U+6764 */ + {0xe69da5, 0x9788}, /* U+6765 */ + {0xe69da6, 0xeb6f}, /* U+6766 [2000] */ + {0xe69daa, 0x9e61}, /* U+676A */ + {0xe69dad, 0x8d59}, /* U+676D */ + {0xe69daf, 0x9474}, /* U+676F */ + {0xe69db0, 0x9e5e}, /* U+6770 */ + {0xe69db1, 0x938c}, /* U+6771 */ + {0xe69db2, 0x9ddc}, /* U+6772 */ + {0xe69db3, 0x9de0}, /* U+6773 */ + {0xe69db4, 0xf3c3}, /* U+6774 [2000] */ + {0xe69db5, 0x8b6e}, /* U+6775 */ + {0xe69db6, 0xf3c4}, /* U+6776 [2000] */ + {0xe69db7, 0x9466}, /* U+6777 */ + {0xe69dbb, 0xeb72}, /* U+677B [2000] */ + {0xe69dbc, 0x9e60}, /* U+677C */ + {0xe69dbe, 0x8fbc}, /* U+677E */ + {0xe69dbf, 0x94c2}, /* U+677F */ + {0xe69e81, 0xeb73}, /* U+6781 [2000] */ + {0xe69e85, 0x9e66}, /* U+6785 */ + {0xe69e87, 0x94f8}, /* U+6787 */ + {0xe69e89, 0x9e5d}, /* U+6789 */ + {0xe69e8b, 0x9e63}, /* U+678B */ + {0xe69e8c, 0x9e62}, /* U+678C */ + {0xe69e90, 0x90cd}, /* U+6790 */ + {0xe69e92, 0xf3c6}, /* U+6792 [2000] */ + {0xe69e93, 0xeb74}, /* U+6793 [2000] */ + {0xe69e95, 0x968d}, /* U+6795 */ + {0xe69e97, 0x97d1}, /* U+6797 */ + {0xe69e98, 0xeb75}, /* U+6798 [2000] */ + {0xe69e9a, 0x9687}, /* U+679A */ + {0xe69e9b, 0xeb76}, /* U+679B [2000] */ + {0xe69e9c, 0x89ca}, /* U+679C */ + {0xe69e9d, 0x8e7d}, /* U+679D */ + {0xe69ea0, 0x9867}, /* U+67A0 */ + {0xe69ea1, 0x9e65}, /* U+67A1 */ + {0xe69ea2, 0x9095}, /* U+67A2 */ + {0xe69ea6, 0x9e64}, /* U+67A6 */ + {0xe69ea9, 0x9e5f}, /* U+67A9 */ + {0xe69eaf, 0x8ccd}, /* U+67AF */ + {0xe69eb0, 0xf3ca}, /* U+67B0 [2000] */ + {0xe69eb2, 0xf3cb}, /* U+67B2 [2000] */ + {0xe69eb3, 0x9e6b}, /* U+67B3 */ + {0xe69eb4, 0x9e69}, /* U+67B4 */ + {0xe69eb6, 0x89cb}, /* U+67B6 */ + {0xe69eb7, 0x9e67}, /* U+67B7 */ + {0xe69eb8, 0x9e6d}, /* U+67B8 */ + {0xe69eb9, 0x9e73}, /* U+67B9 */ + {0xe69ebb, 0xeb77}, /* U+67BB [2000] */ + {0xe69f80, 0xeb79}, /* U+67C0 [2000] */ + {0xe69f81, 0x91c6}, /* U+67C1 */ + {0xe69f83, 0xf3cc}, /* U+67C3 [2000] */ + {0xe69f84, 0x95bf}, /* U+67C4 */ + {0xe69f86, 0x9e75}, /* U+67C6 */ + {0xe69f88, 0xf3cd}, /* U+67C8 [2000] */ + {0xe69f8a, 0x9541}, /* U+67CA */ + {0xe69f8e, 0x9e74}, /* U+67CE */ + {0xe69f8f, 0x9490}, /* U+67CF */ + {0xe69f90, 0x965e}, /* U+67D0 */ + {0xe69f91, 0x8ab9}, /* U+67D1 */ + {0xe69f92, 0xf3ce}, /* U+67D2 [2000] */ + {0xe69f93, 0x90f5}, /* U+67D3 */ + {0xe69f94, 0x8f5f}, /* U+67D4 */ + {0xe69f97, 0xeb7a}, /* U+67D7 [2000] */ + {0xe69f98, 0x92d1}, /* U+67D8 */ + {0xe69f99, 0xf3cf}, /* U+67D9 [2000] */ + {0xe69f9a, 0x974d}, /* U+67DA */ + {0xe69f9b, 0xf3d0}, /* U+67DB [2000] */ + {0xe69f9d, 0x9e70}, /* U+67DD */ + {0xe69f9e, 0x9e6f}, /* U+67DE */ + {0xe69fa2, 0x9e71}, /* U+67E2 */ + {0xe69fa4, 0x9e6e}, /* U+67E4 */ + {0xe69fa7, 0x9e76}, /* U+67E7 */ + {0xe69fa9, 0x9e6c}, /* U+67E9 */ + {0xe69fac, 0x9e6a}, /* U+67EC */ + {0xe69fae, 0x9e72}, /* U+67EE */ + {0xe69faf, 0x9e68}, /* U+67EF */ + {0xe69fb0, 0xf3d1}, /* U+67F0 [2000] */ + {0xe69fb1, 0x928c}, /* U+67F1 */ + {0xe69fb3, 0x96f6}, /* U+67F3 */ + {0xe69fb4, 0x8ec4}, /* U+67F4 */ + {0xe69fb5, 0x8df2}, /* U+67F5 */ + {0xe69fb7, 0xf3d2}, /* U+67F7 [2000] */ + {0xe69fb9, 0xeb78}, /* U+67F9 [2000] */ + {0xe69fbb, 0x8db8}, /* U+67FB */ + {0xe69fbc, 0xeb7b}, /* U+67FC [2000] */ + {0xe69fbe, 0x968f}, /* U+67FE */ + {0xe69fbf, 0x8a60}, /* U+67FF */ + {0xe6a081, 0xeb7c}, /* U+6801 [2000] */ + {0xe6a082, 0x92cc}, /* U+6802 */ + {0xe6a083, 0x93c8}, /* U+6803 */ + {0xe6a084, 0x8968}, /* U+6804 */ + {0xe6a090, 0xf3c9}, /* U+6810 [2000] */ + {0xe6a093, 0x90f0}, /* U+6813 */ + {0xe6a096, 0x90b2}, /* U+6816 */ + {0xe6a097, 0x8c49}, /* U+6817 */ + {0xe6a098, 0xf3d6}, /* U+6818 [2000] */ + {0xe6a09d, 0xeb7e}, /* U+681D [2000] */ + {0xe6a09e, 0x9e78}, /* U+681E */ + {0xe6a09f, 0xf3d7}, /* U+681F [2000] */ + {0xe6a0a1, 0x8d5a}, /* U+6821 */ + {0xe6a0a2, 0x8a9c}, /* U+6822 */ + {0xe6a0a9, 0x9e7a}, /* U+6829 */ + {0xe6a0aa, 0x8a94}, /* U+682A */ + {0xe6a0ab, 0x9e81}, /* U+682B */ + {0xe6a0ac, 0xeb80}, /* U+682C [2000] */ + {0xe6a0ad, 0xf3d8}, /* U+682D [2000] */ + {0xe6a0b1, 0xeb81}, /* U+6831 [2000] */ + {0xe6a0b2, 0x9e7d}, /* U+6832 */ + {0xe6a0b3, 0xf3da}, /* U+6833 [2000] */ + {0xe6a0b4, 0x90f1}, /* U+6834 */ + {0xe6a0b8, 0x8a6a}, /* U+6838 */ + {0xe6a0b9, 0x8daa}, /* U+6839 */ + {0xe6a0bb, 0xf3db}, /* U+683B [2000] */ + {0xe6a0bc, 0x8a69}, /* U+683C */ + {0xe6a0bd, 0x8dcd}, /* U+683D */ + {0xe6a0be, 0xf3dc}, /* U+683E [2000] */ + {0xe6a180, 0x9e7b}, /* U+6840 */ + {0xe6a181, 0x8c85}, /* U+6841 */ + {0xe6a182, 0x8c6a}, /* U+6842 */ + {0xe6a183, 0x938d}, /* U+6843 */ + {0xe6a184, 0xf3dd}, /* U+6844 [2000] */ + {0xe6a185, 0xf3de}, /* U+6845 [2000] */ + {0xe6a186, 0x9e79}, /* U+6846 */ + {0xe6a188, 0x88c4}, /* U+6848 */ + {0xe6a189, 0xf3df}, /* U+6849 [2000] */ + {0xe6a18c, 0xf3e0}, /* U+684C [2000] */ + {0xe6a18d, 0x9e7c}, /* U+684D */ + {0xe6a18e, 0x9e7e}, /* U+684E */ + {0xe6a190, 0x8bcb}, /* U+6850 */ + {0xe6a191, 0x8c4b}, /* U+6851 */ + {0xe6a192, 0xeb7d}, /* U+6852 [2000] */ + {0xe6a193, 0x8aba}, /* U+6853 */ + {0xe6a194, 0x8b6a}, /* U+6854 */ + {0xe6a195, 0xf3e1}, /* U+6855 [2000] */ + {0xe6a197, 0xf3e2}, /* U+6857 [2000] */ + {0xe6a199, 0x9e82}, /* U+6859 */ + {0xe6a19b, 0xeb82}, /* U+685B [2000] */ + {0xe6a19c, 0x8df7}, /* U+685C */ + {0xe6a19d, 0x9691}, /* U+685D */ + {0xe6a19f, 0x8e56}, /* U+685F */ + {0xe6a1a3, 0x9e83}, /* U+6863 */ + {0xe6a1a7, 0x954f}, /* U+6867 */ + {0xe6a1ab, 0xf3e4}, /* U+686B [2000] */ + {0xe6a1ae, 0xf3e5}, /* U+686E [2000] */ + {0xe6a1b2, 0xeb83}, /* U+6872 [2000] */ + {0xe6a1b4, 0x9e8f}, /* U+6874 */ + {0xe6a1b5, 0xeb84}, /* U+6875 [2000] */ + {0xe6a1b6, 0x89b1}, /* U+6876 */ + {0xe6a1b7, 0x9e84}, /* U+6877 */ + {0xe6a1ba, 0xf3e6}, /* U+687A [2000] */ + {0xe6a1bc, 0xf3e7}, /* U+687C [2000] */ + {0xe6a1be, 0x9e95}, /* U+687E */ + {0xe6a1bf, 0x9e85}, /* U+687F */ + {0xe6a281, 0x97c0}, /* U+6881 */ + {0xe6a282, 0xf3e8}, /* U+6882 [2000] */ + {0xe6a283, 0x9e8c}, /* U+6883 */ + {0xe6a285, 0x947e}, /* U+6885 */ + {0xe6a28d, 0x9e94}, /* U+688D */ + {0xe6a28f, 0x9e87}, /* U+688F */ + {0xe6a290, 0xf3e9}, /* U+6890 [2000] */ + {0xe6a293, 0x88b2}, /* U+6893 */ + {0xe6a294, 0x9e89}, /* U+6894 */ + {0xe6a296, 0xf3ea}, /* U+6896 [2000] */ + {0xe6a297, 0x8d5b}, /* U+6897 */ + {0xe6a298, 0xf3ec}, /* U+6898 [2000] */ + {0xe6a299, 0xf3ed}, /* U+6899 [2000] */ + {0xe6a29a, 0xf3ee}, /* U+689A [2000] */ + {0xe6a29b, 0x9e8b}, /* U+689B */ + {0xe6a29c, 0xf3ef}, /* U+689C [2000] */ + {0xe6a29d, 0x9e8a}, /* U+689D */ + {0xe6a29f, 0x9e86}, /* U+689F */ + {0xe6a2a0, 0x9e91}, /* U+68A0 */ + {0xe6a2a2, 0x8fbd}, /* U+68A2 */ + {0xe6a2a3, 0xeb86}, /* U+68A3 [2000] */ + {0xe6a2a5, 0xeb87}, /* U+68A5 [2000] */ + {0xe6a2a6, 0x9aeb}, /* U+68A6 */ + {0xe6a2a7, 0x8ce6}, /* U+68A7 */ + {0xe6a2a8, 0x979c}, /* U+68A8 */ + {0xe6a2aa, 0xf3f0}, /* U+68AA [2000] */ + {0xe6a2ab, 0xf3f1}, /* U+68AB [2000] */ + {0xe6a2ad, 0x9e88}, /* U+68AD */ + {0xe6a2af, 0x92f2}, /* U+68AF */ + {0xe6a2b0, 0x8a42}, /* U+68B0 */ + {0xe6a2b1, 0x8dab}, /* U+68B1 */ + {0xe6a2b2, 0xeb88}, /* U+68B2 [2000] */ + {0xe6a2b3, 0x9e80}, /* U+68B3 */ + {0xe6a2b4, 0xf3f2}, /* U+68B4 [2000] */ + {0xe6a2b5, 0x9e90}, /* U+68B5 */ + {0xe6a2b6, 0x8a81}, /* U+68B6 */ + {0xe6a2b9, 0x9e8e}, /* U+68B9 */ + {0xe6a2ba, 0x9e92}, /* U+68BA */ + {0xe6a2bb, 0xf3f3}, /* U+68BB [2000] */ + {0xe6a2bc, 0x938e}, /* U+68BC */ + {0xe6a383, 0xf3f8}, /* U+68C3 [2000] */ + {0xe6a384, 0x8afc}, /* U+68C4 */ + {0xe6a385, 0xf3f9}, /* U+68C5 [2000] */ + {0xe6a386, 0x9eb0}, /* U+68C6 */ + {0xe6a388, 0xeb89}, /* U+68C8 [2000] */ + {0xe6a389, 0x96c7}, /* U+68C9 */ + {0xe6a38a, 0x9e97}, /* U+68CA */ + {0xe6a38b, 0x8afb}, /* U+68CB */ + {0xe6a38c, 0xf3fa}, /* U+68CC [2000] */ + {0xe6a38d, 0x9e9e}, /* U+68CD */ + {0xe6a38f, 0xf3fb}, /* U+68CF [2000] */ + {0xe6a390, 0xeb8a}, /* U+68D0 [2000] */ + {0xe6a392, 0x965f}, /* U+68D2 */ + {0xe6a394, 0x9e9f}, /* U+68D4 */ + {0xe6a395, 0x9ea1}, /* U+68D5 */ + {0xe6a396, 0xf3fc}, /* U+68D6 [2000] */ + {0xe6a397, 0x9ea5}, /* U+68D7 */ + {0xe6a398, 0x9e99}, /* U+68D8 */ + {0xe6a399, 0xf440}, /* U+68D9 [2000] */ + {0xe6a39a, 0x9249}, /* U+68DA */ + {0xe6a39f, 0x938f}, /* U+68DF */ + {0xe6a3a0, 0x9ea9}, /* U+68E0 */ + {0xe6a3a1, 0x9e9c}, /* U+68E1 */ + {0xe6a3a3, 0x9ea6}, /* U+68E3 */ + {0xe6a3a4, 0xf441}, /* U+68E4 [2000] */ + {0xe6a3a5, 0xf442}, /* U+68E5 [2000] */ + {0xe6a3a7, 0x9ea0}, /* U+68E7 */ + {0xe6a3a8, 0xeb8b}, /* U+68E8 [2000] */ + {0xe6a3ac, 0xf443}, /* U+68EC [2000] */ + {0xe6a3ad, 0xeb8c}, /* U+68ED [2000] */ + {0xe6a3ae, 0x9058}, /* U+68EE */ + {0xe6a3af, 0x9eaa}, /* U+68EF */ + {0xe6a3b0, 0xeb8d}, /* U+68F0 [2000] */ + {0xe6a3b1, 0xeb8e}, /* U+68F1 [2000] */ + {0xe6a3b2, 0x90b1}, /* U+68F2 */ + {0xe6a3b7, 0xf444}, /* U+68F7 [2000] */ + {0xe6a3b9, 0x9ea8}, /* U+68F9 */ + {0xe6a3ba, 0x8abb}, /* U+68FA */ + {0xe6a3bb, 0xf3f4}, /* U+68FB [2000] */ + {0xe6a3bc, 0xeb8f}, /* U+68FC [2000] */ + {0xe6a480, 0x986f}, /* U+6900 */ + {0xe6a481, 0x9e96}, /* U+6901 */ + {0xe6a483, 0xf445}, /* U+6903 [2000] */ + {0xe6a484, 0x9ea4}, /* U+6904 */ + {0xe6a485, 0x88d6}, /* U+6905 */ + {0xe6a487, 0xf446}, /* U+6907 [2000] */ + {0xe6a488, 0x9e98}, /* U+6908 */ + {0xe6a48a, 0xeb90}, /* U+690A [2000] */ + {0xe6a48b, 0x96b8}, /* U+690B */ + {0xe6a48c, 0x9e9d}, /* U+690C */ + {0xe6a48d, 0x9041}, /* U+690D */ + {0xe6a48e, 0x92c5}, /* U+690E */ + {0xe6a48f, 0x9e93}, /* U+690F */ + {0xe6a492, 0x9ea3}, /* U+6912 */ + {0xe6a499, 0x909a}, /* U+6919 */ + {0xe6a49a, 0x9ead}, /* U+691A */ + {0xe6a49b, 0x8a91}, /* U+691B */ + {0xe6a49c, 0x8c9f}, /* U+691C */ + {0xe6a4a1, 0x9eaf}, /* U+6921 */ + {0xe6a4a2, 0x9e9a}, /* U+6922 */ + {0xe6a4a3, 0x9eae}, /* U+6923 */ + {0xe6a4a5, 0x9ea7}, /* U+6925 */ + {0xe6a4a6, 0x9e9b}, /* U+6926 */ + {0xe6a4a8, 0x9eab}, /* U+6928 */ + {0xe6a4aa, 0x9eac}, /* U+692A */ + {0xe6a4b0, 0x9ebd}, /* U+6930 */ + {0xe6a4b4, 0x93cc}, /* U+6934 */ + {0xe6a4b5, 0xeb93}, /* U+6935 [2000] */ + {0xe6a4b6, 0x9ea2}, /* U+6936 */ + {0xe6a4b9, 0x9eb9}, /* U+6939 */ + {0xe6a4bb, 0xf44a}, /* U+693B [2000] */ + {0xe6a4bd, 0x9ebb}, /* U+693D */ + {0xe6a4bf, 0x92d6}, /* U+693F */ + {0xe6a582, 0xeb94}, /* U+6942 [2000] */ + {0xe6a586, 0xf44c}, /* U+6946 [2000] */ + {0xe6a589, 0xeb91}, /* U+6949 [2000] */ + {0xe6a58a, 0x976b}, /* U+694A */ + {0xe6a593, 0x9596}, /* U+6953 */ + {0xe6a594, 0x9eb6}, /* U+6954 */ + {0xe6a595, 0x91c8}, /* U+6955 */ + {0xe6a597, 0xeb95}, /* U+6957 [2000] */ + {0xe6a599, 0x9ebc}, /* U+6959 */ + {0xe6a59a, 0x915e}, /* U+695A */ + {0xe6a59c, 0x9eb3}, /* U+695C */ + {0xe6a59d, 0x9ec0}, /* U+695D */ + {0xe6a59e, 0x9ebf}, /* U+695E */ + {0xe6a5a0, 0x93ed}, /* U+6960 */ + {0xe6a5a1, 0x9ebe}, /* U+6961 */ + {0xe6a5a2, 0x93e8}, /* U+6962 */ + {0xe6a5a3, 0xeb96}, /* U+6963 [2000] */ + {0xe6a5a4, 0xeb97}, /* U+6964 [2000] */ + {0xe6a5a8, 0xeb98}, /* U+6968 [2000] */ + {0xe6a5a9, 0xf44d}, /* U+6969 [2000] */ + {0xe6a5aa, 0x9ec2}, /* U+696A */ + {0xe6a5ab, 0x9eb5}, /* U+696B */ + {0xe6a5ac, 0xf44e}, /* U+696C [2000] */ + {0xe6a5ad, 0x8bc6}, /* U+696D */ + {0xe6a5ae, 0x9eb8}, /* U+696E */ + {0xe6a5af, 0x8f7c}, /* U+696F */ + {0xe6a5b2, 0xf44f}, /* U+6972 [2000] */ + {0xe6a5b3, 0x9480}, /* U+6973 */ + {0xe6a5b4, 0x9eba}, /* U+6974 */ + {0xe6a5b5, 0x8bc9}, /* U+6975 */ + {0xe6a5b7, 0x9eb2}, /* U+6977 */ + {0xe6a5b8, 0x9eb4}, /* U+6978 */ + {0xe6a5b9, 0x9eb1}, /* U+6979 */ + {0xe6a5ba, 0xf450}, /* U+697A [2000] */ + {0xe6a5bc, 0x984f}, /* U+697C */ + {0xe6a5bd, 0x8a79}, /* U+697D */ + {0xe6a5be, 0x9eb7}, /* U+697E */ + {0xe6a5bf, 0xf451}, /* U+697F [2000] */ + {0xe6a680, 0xeb99}, /* U+6980 [2000] */ + {0xe6a681, 0x9ec1}, /* U+6981 */ + {0xe6a682, 0x8a54}, /* U+6982 */ + {0xe6a68a, 0x8de5}, /* U+698A */ + {0xe6a68e, 0x897c}, /* U+698E */ + {0xe6a691, 0x9ed2}, /* U+6991 */ + {0xe6a692, 0xf452}, /* U+6992 [2000] */ + {0xe6a694, 0x9850}, /* U+6994 */ + {0xe6a695, 0x9ed5}, /* U+6995 */ + {0xe6a696, 0xf454}, /* U+6996 [2000] */ + {0xe6a698, 0xf455}, /* U+6998 [2000] */ + {0xe6a69b, 0x9059}, /* U+699B */ + {0xe6a69c, 0x9ed4}, /* U+699C */ + {0xe6a6a0, 0x9ed3}, /* U+69A0 */ + {0xe6a6a5, 0xeb9b}, /* U+69A5 [2000] */ + {0xe6a6a6, 0xf456}, /* U+69A6 [2000] */ + {0xe6a6a7, 0x9ed0}, /* U+69A7 */ + {0xe6a6ad, 0xeb9c}, /* U+69AD [2000] */ + {0xe6a6ae, 0x9ec4}, /* U+69AE */ + {0xe6a6b0, 0xf457}, /* U+69B0 [2000] */ + {0xe6a6b1, 0x9ee1}, /* U+69B1 */ + {0xe6a6b2, 0x9ec3}, /* U+69B2 */ + {0xe6a6b4, 0x9ed6}, /* U+69B4 */ + {0xe6a6b7, 0xf458}, /* U+69B7 [2000] */ + {0xe6a6ba, 0xf459}, /* U+69BA [2000] */ + {0xe6a6bb, 0x9ece}, /* U+69BB */ + {0xe6a6bc, 0xf45a}, /* U+69BC [2000] */ + {0xe6a6be, 0x9ec9}, /* U+69BE */ + {0xe6a6bf, 0x9ec6}, /* U+69BF */ + {0xe6a780, 0xf45b}, /* U+69C0 [2000] */ + {0xe6a781, 0x9ec7}, /* U+69C1 */ + {0xe6a783, 0x9ecf}, /* U+69C3 */ + {0xe6a787, 0xeaa0}, /* U+69C7 [1983] */ + {0xe6a78a, 0x9ecc}, /* U+69CA */ + {0xe6a78b, 0x8d5c}, /* U+69CB */ + {0xe6a78c, 0x92c6}, /* U+69CC */ + {0xe6a78d, 0x9184}, /* U+69CD */ + {0xe6a78e, 0x9eca}, /* U+69CE */ + {0xe6a78f, 0xeb9d}, /* U+69CF [2000] */ + {0xe6a790, 0x9ec5}, /* U+69D0 */ + {0xe6a791, 0xf45c}, /* U+69D1 [2000] */ + {0xe6a793, 0x9ec8}, /* U+69D3 */ + {0xe6a796, 0xf45d}, /* U+69D6 [2000] */ + {0xe6a798, 0x976c}, /* U+69D8 */ + {0xe6a799, 0x968a}, /* U+69D9 */ + {0xe6a79d, 0x9ecd}, /* U+69DD */ + {0xe6a79e, 0x9ed7}, /* U+69DE */ + {0xe6a7a2, 0xeba0}, /* U+69E2 [2000] */ + {0xe6a7a3, 0xf463}, /* U+69E3 [2000] */ + {0xe6a7a7, 0x9edf}, /* U+69E7 */ + {0xe6a7a8, 0x9ed8}, /* U+69E8 */ + {0xe6a7a9, 0xeba1}, /* U+69E9 [2000] */ + {0xe6a7aa, 0xeba2}, /* U+69EA [2000] */ + {0xe6a7ab, 0x9ee5}, /* U+69EB */ + {0xe6a7ad, 0x9ee3}, /* U+69ED */ + {0xe6a7ae, 0xf464}, /* U+69EE [2000] */ + {0xe6a7af, 0xf465}, /* U+69EF [2000] */ + {0xe6a7b2, 0x9ede}, /* U+69F2 */ + {0xe6a7b3, 0xf466}, /* U+69F3 [2000] */ + {0xe6a7b4, 0xf468}, /* U+69F4 [2000] */ + {0xe6a7b5, 0xeba3}, /* U+69F5 [2000] */ + {0xe6a7b6, 0xeba4}, /* U+69F6 [2000] */ + {0xe6a7b9, 0x9edd}, /* U+69F9 */ + {0xe6a7bb, 0x92ce}, /* U+69FB */ + {0xe6a7bd, 0x9185}, /* U+69FD */ + {0xe6a7be, 0xf469}, /* U+69FE [2000] */ + {0xe6a7bf, 0x9edb}, /* U+69FF */ + {0xe6a882, 0x9ed9}, /* U+6A02 */ + {0xe6a885, 0x9ee0}, /* U+6A05 */ + {0xe6a88a, 0x9ee6}, /* U+6A0A */ + {0xe6a88b, 0x94f3}, /* U+6A0B */ + {0xe6a88c, 0x9eec}, /* U+6A0C */ + {0xe6a88f, 0xeba5}, /* U+6A0F [2000] */ + {0xe6a891, 0xf46a}, /* U+6A11 [2000] */ + {0xe6a892, 0x9ee7}, /* U+6A12 */ + {0xe6a893, 0x9eea}, /* U+6A13 */ + {0xe6a894, 0x9ee4}, /* U+6A14 */ + {0xe6a895, 0xeba6}, /* U+6A15 [2000] */ + {0xe6a897, 0x9294}, /* U+6A17 */ + {0xe6a899, 0x9557}, /* U+6A19 */ + {0xe6a89a, 0xf46b}, /* U+6A1A [2000] */ + {0xe6a89b, 0x9eda}, /* U+6A1B */ + {0xe6a89d, 0xf46c}, /* U+6A1D [2000] */ + {0xe6a89e, 0x9ee2}, /* U+6A1E */ + {0xe6a89f, 0x8fbe}, /* U+6A1F */ + {0xe6a8a1, 0x96cd}, /* U+6A21 */ + {0xe6a8a2, 0x9ef6}, /* U+6A22 */ + {0xe6a8a3, 0x9ee9}, /* U+6A23 */ + {0xe6a8a9, 0x8ca0}, /* U+6A29 */ + {0xe6a8aa, 0x89a1}, /* U+6A2A */ + {0xe6a8ab, 0x8a7e}, /* U+6A2B */ + {0xe6a8ae, 0x9ed1}, /* U+6A2E */ + {0xe6a8b0, 0xf460}, /* U+6A30 [2000] */ + {0xe6a8b2, 0xf46e}, /* U+6A32 [2000] */ + {0xe6a8b3, 0xf46f}, /* U+6A33 [2000] */ + {0xe6a8b4, 0xf470}, /* U+6A34 [2000] */ + {0xe6a8b5, 0x8fbf}, /* U+6A35 */ + {0xe6a8b6, 0x9eee}, /* U+6A36 */ + {0xe6a8b8, 0x9ef5}, /* U+6A38 */ + {0xe6a8b9, 0x8ef7}, /* U+6A39 */ + {0xe6a8ba, 0x8a92}, /* U+6A3A */ + {0xe6a8bb, 0xeba8}, /* U+6A3B [2000] */ + {0xe6a8bd, 0x924d}, /* U+6A3D */ + {0xe6a8be, 0xeba9}, /* U+6A3E [2000] */ + {0xe6a8bf, 0xf471}, /* U+6A3F [2000] */ + {0xe6a984, 0x9eeb}, /* U+6A44 */ + {0xe6a985, 0xebaa}, /* U+6A45 [2000] */ + {0xe6a986, 0xf472}, /* U+6A46 [2000] */ + {0xe6a987, 0x9ef0}, /* U+6A47 */ + {0xe6a988, 0x9ef4}, /* U+6A48 */ + {0xe6a989, 0xf473}, /* U+6A49 [2000] */ + {0xe6a98b, 0x8bb4}, /* U+6A4B */ + {0xe6a98e, 0xf475}, /* U+6A4E [2000] */ + {0xe6a990, 0xebab}, /* U+6A50 [2000] */ + {0xe6a992, 0xf476}, /* U+6A52 [2000] */ + {0xe6a996, 0xebac}, /* U+6A56 [2000] */ + {0xe6a998, 0x8b6b}, /* U+6A58 */ + {0xe6a999, 0x9ef2}, /* U+6A59 */ + {0xe6a99b, 0xebad}, /* U+6A5B [2000] */ + {0xe6a99f, 0x8b40}, /* U+6A5F */ + {0xe6a9a1, 0x93c9}, /* U+6A61 */ + {0xe6a9a2, 0x9ef1}, /* U+6A62 */ + {0xe6a9a4, 0xf477}, /* U+6A64 [2000] */ + {0xe6a9a6, 0x9ef3}, /* U+6A66 */ + {0xe6a9ab, 0xebae}, /* U+6A6B [2000] */ + {0xe6a9b2, 0x9eed}, /* U+6A72 */ + {0xe6a9b3, 0xebaf}, /* U+6A73 [2000] */ + {0xe6a9b8, 0x9eef}, /* U+6A78 */ + {0xe6a9ba, 0xf474}, /* U+6A7A [2000] */ + {0xe6a9be, 0xf479}, /* U+6A7E [2000] */ + {0xe6a9bf, 0x8a80}, /* U+6A7F */ + {0xe6aa80, 0x9268}, /* U+6A80 */ + {0xe6aa83, 0xf47a}, /* U+6A83 [2000] */ + {0xe6aa84, 0x9efa}, /* U+6A84 */ + {0xe6aa89, 0xebb1}, /* U+6A89 [2000] */ + {0xe6aa8b, 0xf47b}, /* U+6A8B [2000] */ + {0xe6aa8d, 0x9ef8}, /* U+6A8D */ + {0xe6aa8e, 0x8ce7}, /* U+6A8E */ + {0xe6aa90, 0x9ef7}, /* U+6A90 */ + {0xe6aa91, 0xf47d}, /* U+6A91 [2000] */ + {0xe6aa94, 0xebb2}, /* U+6A94 [2000] */ + {0xe6aa97, 0x9f40}, /* U+6A97 */ + {0xe6aa9c, 0x9e77}, /* U+6A9C */ + {0xe6aa9d, 0xebb3}, /* U+6A9D [2000] */ + {0xe6aa9e, 0xebb4}, /* U+6A9E [2000] */ + {0xe6aa9f, 0xf47e}, /* U+6A9F [2000] */ + {0xe6aaa0, 0x9ef9}, /* U+6AA0 */ + {0xe6aaa1, 0xf480}, /* U+6AA1 [2000] */ + {0xe6aaa2, 0x9efb}, /* U+6AA2 */ + {0xe6aaa3, 0x9efc}, /* U+6AA3 */ + {0xe6aaa5, 0xebb5}, /* U+6AA5 [2000] */ + {0xe6aaaa, 0x9f4b}, /* U+6AAA */ + {0xe6aaab, 0xf482}, /* U+6AAB [2000] */ + {0xe6aaac, 0x9f47}, /* U+6AAC */ + {0xe6aaae, 0x9e8d}, /* U+6AAE */ + {0xe6aab3, 0x9f46}, /* U+6AB3 */ + {0xe6aab8, 0x9f45}, /* U+6AB8 */ + {0xe6aabb, 0x9f42}, /* U+6ABB */ + {0xe6aabd, 0xf483}, /* U+6ABD [2000] */ + {0xe6ab81, 0x9ee8}, /* U+6AC1 */ + {0xe6ab82, 0x9f44}, /* U+6AC2 */ + {0xe6ab83, 0x9f43}, /* U+6AC3 */ + {0xe6ab86, 0xf484}, /* U+6AC6 [2000] */ + {0xe6ab90, 0xf486}, /* U+6AD0 [2000] */ + {0xe6ab91, 0x9f49}, /* U+6AD1 */ + {0xe6ab93, 0x9845}, /* U+6AD3 */ + {0xe6ab94, 0xf485}, /* U+6AD4 [2000] */ + {0xe6ab9a, 0x9f4c}, /* U+6ADA */ + {0xe6ab9b, 0x8bf9}, /* U+6ADB */ + {0xe6ab9c, 0xf487}, /* U+6ADC [2000] */ + {0xe6ab9d, 0xf488}, /* U+6ADD [2000] */ + {0xe6ab9e, 0x9f48}, /* U+6ADE */ + {0xe6ab9f, 0x9f4a}, /* U+6ADF */ + {0xe6aba4, 0xebb6}, /* U+6AE4 [2000] */ + {0xe6aba7, 0xebb7}, /* U+6AE7 [2000] */ + {0xe6aba8, 0x94a5}, /* U+6AE8 */ + {0xe6abaa, 0x9f4d}, /* U+6AEA */ + {0xe6abac, 0xf48b}, /* U+6AEC [2000] */ + {0xe6abb1, 0xf48c}, /* U+6AF1 [2000] */ + {0xe6abb2, 0xf48d}, /* U+6AF2 [2000] */ + {0xe6abb3, 0xf48e}, /* U+6AF3 [2000] */ + {0xe6abba, 0x9f51}, /* U+6AFA */ + {0xe6abbb, 0x9f4e}, /* U+6AFB */ + {0xe6abbd, 0xf48f}, /* U+6AFD [2000] */ + {0xe6ac84, 0x9793}, /* U+6B04 */ + {0xe6ac85, 0x9f4f}, /* U+6B05 */ + {0xe6ac8a, 0x9edc}, /* U+6B0A */ + {0xe6ac8b, 0xf491}, /* U+6B0B [2000] */ + {0xe6ac8f, 0xf492}, /* U+6B0F [2000] */ + {0xe6ac90, 0xf493}, /* U+6B10 [2000] */ + {0xe6ac91, 0xf494}, /* U+6B11 [2000] */ + {0xe6ac92, 0x9f52}, /* U+6B12 */ + {0xe6ac96, 0x9f53}, /* U+6B16 */ + {0xe6ac97, 0xf496}, /* U+6B17 [2000] */ + {0xe6ac9b, 0xebba}, /* U+6B1B [2000] */ + {0xe6ac9d, 0x8954}, /* U+6B1D */ + {0xe6ac9e, 0xebbb}, /* U+6B1E [2000] */ + {0xe6ac9f, 0x9f55}, /* U+6B1F */ + {0xe6aca0, 0x8c87}, /* U+6B20 */ + {0xe6aca1, 0x8e9f}, /* U+6B21 */ + {0xe6aca3, 0x8bd3}, /* U+6B23 */ + {0xe6aca7, 0x89a2}, /* U+6B27 */ + {0xe6acac, 0xebbc}, /* U+6B2C [2000] */ + {0xe6acaf, 0xf498}, /* U+6B2F [2000] */ + {0xe6acb2, 0x977e}, /* U+6B32 */ + {0xe6acb5, 0xebbd}, /* U+6B35 [2000] */ + {0xe6acb7, 0x9f57}, /* U+6B37 */ + {0xe6acb8, 0x9f56}, /* U+6B38 */ + {0xe6acb9, 0x9f59}, /* U+6B39 */ + {0xe6acba, 0x8b5c}, /* U+6B3A */ + {0xe6acbd, 0x8bd4}, /* U+6B3D */ + {0xe6acbe, 0x8abc}, /* U+6B3E */ + {0xe6ad83, 0x9f5c}, /* U+6B43 */ + {0xe6ad86, 0xebbe}, /* U+6B46 [2000] */ + {0xe6ad87, 0x9f5b}, /* U+6B47 */ + {0xe6ad89, 0x9f5d}, /* U+6B49 */ + {0xe6ad8a, 0xf499}, /* U+6B4A [2000] */ + {0xe6ad8c, 0x89cc}, /* U+6B4C */ + {0xe6ad8e, 0x9256}, /* U+6B4E */ + {0xe6ad90, 0x9f5e}, /* U+6B50 */ + {0xe6ad93, 0x8abd}, /* U+6B53 */ + {0xe6ad94, 0x9f60}, /* U+6B54 */ + {0xe6ad96, 0xebbf}, /* U+6B56 [2000] */ + {0xe6ad98, 0xf49a}, /* U+6B58 [2000] */ + {0xe6ad99, 0x9f5f}, /* U+6B59 */ + {0xe6ad9b, 0x9f61}, /* U+6B5B */ + {0xe6ad9f, 0x9f62}, /* U+6B5F */ + {0xe6ada0, 0xebc0}, /* U+6B60 [2000] */ + {0xe6ada1, 0x9f63}, /* U+6B61 */ + {0xe6ada2, 0x8e7e}, /* U+6B62 */ + {0xe6ada3, 0x90b3}, /* U+6B63 */ + {0xe6ada4, 0x8d9f}, /* U+6B64 */ + {0xe6ada5, 0xebc1}, /* U+6B65 [2000] */ + {0xe6ada6, 0x9590}, /* U+6B66 */ + {0xe6ada7, 0xebc2}, /* U+6B67 [2000] */ + {0xe6ada9, 0x95e0}, /* U+6B69 */ + {0xe6adaa, 0x9863}, /* U+6B6A */ + {0xe6adac, 0xf49b}, /* U+6B6C [2000] */ + {0xe6adaf, 0x8e95}, /* U+6B6F */ + {0xe6adb3, 0x8dce}, /* U+6B73 */ + {0xe6adb4, 0x97f0}, /* U+6B74 */ + {0xe6adb5, 0xf49c}, /* U+6B75 [2000] */ + {0xe6adb7, 0xebc3}, /* U+6B77 [2000] */ + {0xe6adb8, 0x9f64}, /* U+6B78 */ + {0xe6adb9, 0x9f65}, /* U+6B79 */ + {0xe6adba, 0xf49d}, /* U+6B7A [2000] */ + {0xe6adbb, 0x8e80}, /* U+6B7B */ + {0xe6adbf, 0x9f66}, /* U+6B7F */ + {0xe6ae80, 0x9f67}, /* U+6B80 */ + {0xe6ae81, 0xf49e}, /* U+6B81 [2000] */ + {0xe6ae82, 0xebc4}, /* U+6B82 [2000] */ + {0xe6ae83, 0x9f69}, /* U+6B83 */ + {0xe6ae84, 0x9f68}, /* U+6B84 */ + {0xe6ae86, 0x9677}, /* U+6B86 */ + {0xe6ae89, 0x8f7d}, /* U+6B89 */ + {0xe6ae8a, 0x8eea}, /* U+6B8A */ + {0xe6ae8b, 0x8e63}, /* U+6B8B */ + {0xe6ae8d, 0x9f6a}, /* U+6B8D */ + {0xe6ae95, 0x9f6c}, /* U+6B95 */ + {0xe6ae96, 0x9042}, /* U+6B96 */ + {0xe6ae98, 0x9f6b}, /* U+6B98 */ + {0xe6ae9b, 0xf49f}, /* U+6B9B [2000] */ + {0xe6ae9e, 0x9f6d}, /* U+6B9E */ + {0xe6aea4, 0x9f6e}, /* U+6BA4 */ + {0xe6aea9, 0xebc5}, /* U+6BA9 [2000] */ + {0xe6aeaa, 0x9f6f}, /* U+6BAA */ + {0xe6aeab, 0x9f70}, /* U+6BAB */ + {0xe6aead, 0xebc6}, /* U+6BAD [2000] */ + {0xe6aeae, 0xf4a0}, /* U+6BAE [2000] */ + {0xe6aeaf, 0x9f71}, /* U+6BAF */ + {0xe6aeb1, 0x9f73}, /* U+6BB1 */ + {0xe6aeb2, 0x9f72}, /* U+6BB2 */ + {0xe6aeb3, 0x9f74}, /* U+6BB3 */ + {0xe6aeb4, 0x89a3}, /* U+6BB4 */ + {0xe6aeb5, 0x9269}, /* U+6BB5 */ + {0xe6aeb7, 0x9f75}, /* U+6BB7 */ + {0xe6aeba, 0x8e45}, /* U+6BBA */ + {0xe6aebb, 0x8a6b}, /* U+6BBB */ + {0xe6aebc, 0x9f76}, /* U+6BBC */ + {0xe6aebd, 0xf4a2}, /* U+6BBD [2000] */ + {0xe6aebe, 0xf4a3}, /* U+6BBE [2000] */ + {0xe6aebf, 0x9361}, /* U+6BBF */ + {0xe6af80, 0x9aca}, /* U+6BC0 */ + {0xe6af85, 0x8b42}, /* U+6BC5 */ + {0xe6af86, 0x9f77}, /* U+6BC6 */ + {0xe6af87, 0xf4a4}, /* U+6BC7 [2000] */ + {0xe6af88, 0xf4a5}, /* U+6BC8 [2000] */ + {0xe6af89, 0xf4a6}, /* U+6BC9 [2000] */ + {0xe6af8b, 0x9f78}, /* U+6BCB */ + {0xe6af8d, 0x95ea}, /* U+6BCD */ + {0xe6af8e, 0x9688}, /* U+6BCE */ + {0xe6af8f, 0xebc8}, /* U+6BCF [2000] */ + {0xe6af92, 0x93c5}, /* U+6BD2 */ + {0xe6af93, 0x9f79}, /* U+6BD3 */ + {0xe6af94, 0x94e4}, /* U+6BD4 */ + {0xe6af96, 0xebc9}, /* U+6BD6 [2000] */ + {0xe6af97, 0xebca}, /* U+6BD7 [2000] */ + {0xe6af98, 0x94f9}, /* U+6BD8 */ + {0xe6af9a, 0xf4a7}, /* U+6BDA [2000] */ + {0xe6af9b, 0x96d1}, /* U+6BDB */ + {0xe6af9f, 0x9f7a}, /* U+6BDF */ + {0xe6afa6, 0xf4a8}, /* U+6BE6 [2000] */ + {0xe6afa7, 0xf4a9}, /* U+6BE7 [2000] */ + {0xe6afab, 0x9f7c}, /* U+6BEB */ + {0xe6afac, 0x9f7b}, /* U+6BEC */ + {0xe6afae, 0xf4aa}, /* U+6BEE [2000] */ + {0xe6afaf, 0x9f7e}, /* U+6BEF */ + {0xe6afb1, 0xf4ab}, /* U+6BF1 [2000] */ + {0xe6afb3, 0x9f7d}, /* U+6BF3 */ + {0xe6afbf, 0xebcb}, /* U+6BFF [2000] */ + {0xe6b082, 0xf4ac}, /* U+6C02 [2000] */ + {0xe6b085, 0xebcc}, /* U+6C05 [2000] */ + {0xe6b088, 0x9f81}, /* U+6C08 */ + {0xe6b08a, 0xf4ad}, /* U+6C0A [2000] */ + {0xe6b08e, 0xf4ae}, /* U+6C0E [2000] */ + {0xe6b08f, 0x8e81}, /* U+6C0F */ + {0xe6b090, 0xebcd}, /* U+6C10 [2000] */ + {0xe6b091, 0x96af}, /* U+6C11 */ + {0xe6b093, 0x9f82}, /* U+6C13 */ + {0xe6b094, 0x9f83}, /* U+6C14 */ + {0xe6b097, 0x8b43}, /* U+6C17 */ + {0xe6b09b, 0x9f84}, /* U+6C1B */ + {0xe6b0a3, 0x9f86}, /* U+6C23 */ + {0xe6b0a4, 0x9f85}, /* U+6C24 */ + {0xe6b0b3, 0xebce}, /* U+6C33 [2000] */ + {0xe6b0b4, 0x9085}, /* U+6C34 */ + {0xe6b0b5, 0xf4af}, /* U+6C35 [2000] */ + {0xe6b0b6, 0xf4b0}, /* U+6C36 [2000] */ + {0xe6b0b7, 0x9558}, /* U+6C37 */ + {0xe6b0b8, 0x8969}, /* U+6C38 */ + {0xe6b0ba, 0xf4b1}, /* U+6C3A [2000] */ + {0xe6b0be, 0x94c3}, /* U+6C3E */ + {0xe6b0bf, 0xf4b3}, /* U+6C3F [2000] */ + {0xe6b180, 0x92f3}, /* U+6C40 */ + {0xe6b181, 0x8f60}, /* U+6C41 */ + {0xe6b182, 0x8b81}, /* U+6C42 */ + {0xe6b18d, 0xf4b4}, /* U+6C4D [2000] */ + {0xe6b18e, 0x94c4}, /* U+6C4E */ + {0xe6b190, 0x8eac}, /* U+6C50 */ + {0xe6b195, 0x9f88}, /* U+6C55 */ + {0xe6b197, 0x8abe}, /* U+6C57 */ + {0xe6b199, 0xebcf}, /* U+6C59 [2000] */ + {0xe6b19a, 0x8998}, /* U+6C5A */ + {0xe6b19b, 0xf4b5}, /* U+6C5B [2000] */ + {0xe6b19c, 0xebd0}, /* U+6C5C [2000] */ + {0xe6b19d, 0x93f0}, /* U+6C5D */ + {0xe6b19e, 0x9f87}, /* U+6C5E */ + {0xe6b19f, 0x8d5d}, /* U+6C5F */ + {0xe6b1a0, 0x9272}, /* U+6C60 */ + {0xe6b1a2, 0x9f89}, /* U+6C62 */ + {0xe6b1a7, 0xf4cd}, /* U+6C67 [2000] */ + {0xe6b1a8, 0x9f91}, /* U+6C68 */ + {0xe6b1aa, 0x9f8a}, /* U+6C6A */ + {0xe6b1ad, 0xf4b6}, /* U+6C6D [2000] */ + {0xe6b1b0, 0x91bf}, /* U+6C70 */ + {0xe6b1b2, 0x8b82}, /* U+6C72 */ + {0xe6b1b3, 0x9f92}, /* U+6C73 */ + {0xe6b1b4, 0xebd2}, /* U+6C74 [2000] */ + {0xe6b1b6, 0xebd3}, /* U+6C76 [2000] */ + {0xe6b1ba, 0x8c88}, /* U+6C7A */ + {0xe6b1bd, 0x8b44}, /* U+6C7D */ + {0xe6b1be, 0x9f90}, /* U+6C7E */ + {0xe6b281, 0x9f8e}, /* U+6C81 */ + {0xe6b282, 0x9f8b}, /* U+6C82 */ + {0xe6b283, 0x9780}, /* U+6C83 */ + {0xe6b284, 0xf4b7}, /* U+6C84 [2000] */ + {0xe6b285, 0xebd4}, /* U+6C85 [2000] */ + {0xe6b286, 0xebd5}, /* U+6C86 [2000] */ + {0xe6b288, 0x92be}, /* U+6C88 */ + {0xe6b289, 0xf4b8}, /* U+6C89 [2000] */ + {0xe6b28c, 0x93d7}, /* U+6C8C */ + {0xe6b28d, 0x9f8c}, /* U+6C8D */ + {0xe6b290, 0x9f94}, /* U+6C90 */ + {0xe6b292, 0x9f93}, /* U+6C92 */ + {0xe6b293, 0x8c42}, /* U+6C93 */ + {0xe6b294, 0xf4ba}, /* U+6C94 [2000] */ + {0xe6b295, 0xf4bb}, /* U+6C95 [2000] */ + {0xe6b296, 0x89ab}, /* U+6C96 */ + {0xe6b297, 0xf4bc}, /* U+6C97 [2000] */ + {0xe6b298, 0xebd6}, /* U+6C98 [2000] */ + {0xe6b299, 0x8db9}, /* U+6C99 */ + {0xe6b29a, 0x9f8d}, /* U+6C9A */ + {0xe6b29b, 0x9f8f}, /* U+6C9B */ + {0xe6b29c, 0xebd7}, /* U+6C9C [2000] */ + {0xe6b2a1, 0x9676}, /* U+6CA1 */ + {0xe6b2a2, 0x91f2}, /* U+6CA2 */ + {0xe6b2aa, 0xebd1}, /* U+6CAA [2000] */ + {0xe6b2ab, 0x9697}, /* U+6CAB */ + {0xe6b2ad, 0xf4bd}, /* U+6CAD [2000] */ + {0xe6b2ae, 0x9f9c}, /* U+6CAE */ + {0xe6b2b1, 0x9f9d}, /* U+6CB1 */ + {0xe6b2b3, 0x89cd}, /* U+6CB3 */ + {0xe6b2b8, 0x95a6}, /* U+6CB8 */ + {0xe6b2b9, 0x96fb}, /* U+6CB9 */ + {0xe6b2ba, 0x9f9f}, /* U+6CBA */ + {0xe6b2bb, 0x8ea1}, /* U+6CBB */ + {0xe6b2bc, 0x8fc0}, /* U+6CBC */ + {0xe6b2bd, 0x9f98}, /* U+6CBD */ + {0xe6b2be, 0x9f9e}, /* U+6CBE */ + {0xe6b2bf, 0x8988}, /* U+6CBF */ + {0xe6b381, 0x8bb5}, /* U+6CC1 */ + {0xe6b382, 0xf4be}, /* U+6CC2 [2000] */ + {0xe6b384, 0x9f95}, /* U+6CC4 */ + {0xe6b385, 0x9f9a}, /* U+6CC5 */ + {0xe6b386, 0xebd9}, /* U+6CC6 [2000] */ + {0xe6b389, 0x90f2}, /* U+6CC9 */ + {0xe6b38a, 0x9491}, /* U+6CCA */ + {0xe6b38c, 0x94e5}, /* U+6CCC */ + {0xe6b390, 0xf4bf}, /* U+6CD0 [2000] */ + {0xe6b393, 0x9f97}, /* U+6CD3 */ + {0xe6b394, 0xebda}, /* U+6CD4 [2000] */ + {0xe6b395, 0x9640}, /* U+6CD5 */ + {0xe6b396, 0xf4c1}, /* U+6CD6 [2000] */ + {0xe6b397, 0x9f99}, /* U+6CD7 */ + {0xe6b399, 0x9fa2}, /* U+6CD9 */ + {0xe6b39a, 0xf4c2}, /* U+6CDA [2000] */ + {0xe6b39b, 0x9fa0}, /* U+6CDB */ + {0xe6b39c, 0xf4c3}, /* U+6CDC [2000] */ + {0xe6b39d, 0x9f9b}, /* U+6CDD */ + {0xe6b3a0, 0xebdb}, /* U+6CE0 [2000] */ + {0xe6b3a1, 0x9641}, /* U+6CE1 */ + {0xe6b3a2, 0x9467}, /* U+6CE2 */ + {0xe6b3a3, 0x8b83}, /* U+6CE3 */ + {0xe6b3a5, 0x9344}, /* U+6CE5 */ + {0xe6b3a8, 0x928d}, /* U+6CE8 */ + {0xe6b3a9, 0xf4c4}, /* U+6CE9 [2000] */ + {0xe6b3aa, 0x9fa3}, /* U+6CEA */ + {0xe6b3ab, 0xebdc}, /* U+6CEB [2000] */ + {0xe6b3ac, 0xf4c5}, /* U+6CEC [2000] */ + {0xe6b3ad, 0xf4c6}, /* U+6CED [2000] */ + {0xe6b3ae, 0xebdd}, /* U+6CEE [2000] */ + {0xe6b3af, 0x9fa1}, /* U+6CEF */ + {0xe6b3b0, 0x91d7}, /* U+6CF0 */ + {0xe6b3b1, 0x9f96}, /* U+6CF1 */ + {0xe6b3b3, 0x896a}, /* U+6CF3 */ + {0xe6b3bb, 0xebd8}, /* U+6CFB [2000] */ + {0xe6b480, 0xf4c8}, /* U+6D00 [2000] */ + {0xe6b484, 0xebdf}, /* U+6D04 [2000] */ + {0xe6b48a, 0xf4c9}, /* U+6D0A [2000] */ + {0xe6b48b, 0x976d}, /* U+6D0B */ + {0xe6b48c, 0x9fae}, /* U+6D0C */ + {0xe6b48e, 0xebe0}, /* U+6D0E [2000] */ + {0xe6b492, 0x9fad}, /* U+6D12 */ + {0xe6b497, 0x90f4}, /* U+6D17 */ + {0xe6b499, 0x9faa}, /* U+6D19 */ + {0xe6b49b, 0x978c}, /* U+6D1B */ + {0xe6b49e, 0x93b4}, /* U+6D1E */ + {0xe6b49f, 0x9fa4}, /* U+6D1F */ + {0xe6b4a4, 0xf4ca}, /* U+6D24 [2000] */ + {0xe6b4a5, 0x92c3}, /* U+6D25 */ + {0xe6b4a6, 0xf4cb}, /* U+6D26 [2000] */ + {0xe6b4a7, 0xf4cc}, /* U+6D27 [2000] */ + {0xe6b4a9, 0x896b}, /* U+6D29 */ + {0xe6b4aa, 0x8d5e}, /* U+6D2A */ + {0xe6b4ab, 0x9fa7}, /* U+6D2B */ + {0xe6b4ae, 0xebe1}, /* U+6D2E [2000] */ + {0xe6b4af, 0xf4ce}, /* U+6D2F [2000] */ + {0xe6b4b1, 0xebe2}, /* U+6D31 [2000] */ + {0xe6b4b2, 0x8f46}, /* U+6D32 */ + {0xe6b4b3, 0x9fac}, /* U+6D33 */ + {0xe6b4b4, 0xf4e3}, /* U+6D34 [2000] */ + {0xe6b4b5, 0x9fab}, /* U+6D35 */ + {0xe6b4b6, 0x9fa6}, /* U+6D36 */ + {0xe6b4b8, 0x9fa9}, /* U+6D38 */ + {0xe6b4b9, 0xebe3}, /* U+6D39 [2000] */ + {0xe6b4bb, 0x8a88}, /* U+6D3B */ + {0xe6b4bc, 0xf4cf}, /* U+6D3C [2000] */ + {0xe6b4bd, 0x9fa8}, /* U+6D3D */ + {0xe6b4be, 0x9468}, /* U+6D3E */ + {0xe6b4bf, 0xebe4}, /* U+6D3F [2000] */ + {0xe6b581, 0x97ac}, /* U+6D41 */ + {0xe6b584, 0x8ff2}, /* U+6D44 */ + {0xe6b585, 0x90f3}, /* U+6D45 */ + {0xe6b598, 0xebe5}, /* U+6D58 [2000] */ + {0xe6b599, 0x9fb4}, /* U+6D59 */ + {0xe6b59a, 0x9fb2}, /* U+6D5A */ + {0xe6b59b, 0xf4d0}, /* U+6D5B [2000] */ + {0xe6b59c, 0x956c}, /* U+6D5C */ + {0xe6b59e, 0xf4d1}, /* U+6D5E [2000] */ + {0xe6b5a0, 0xf4d2}, /* U+6D60 [2000] */ + {0xe6b5a3, 0x9faf}, /* U+6D63 */ + {0xe6b5a4, 0x9fb1}, /* U+6D64 */ + {0xe6b5a5, 0xebe6}, /* U+6D65 [2000] */ + {0xe6b5a6, 0x8959}, /* U+6D66 */ + {0xe6b5a9, 0x8d5f}, /* U+6D69 */ + {0xe6b5aa, 0x9851}, /* U+6D6A */ + {0xe6b5ac, 0x8a5c}, /* U+6D6C */ + {0xe6b5ae, 0x9582}, /* U+6D6E */ + {0xe6b5b0, 0xf4d3}, /* U+6D70 [2000] */ + {0xe6b5b4, 0x9781}, /* U+6D74 */ + {0xe6b5b7, 0x8a43}, /* U+6D77 */ + {0xe6b5b8, 0x905a}, /* U+6D78 */ + {0xe6b5b9, 0x9fb3}, /* U+6D79 */ + {0xe6b680, 0xf4d4}, /* U+6D80 [2000] */ + {0xe6b681, 0xf4d5}, /* U+6D81 [2000] */ + {0xe6b682, 0xebe8}, /* U+6D82 [2000] */ + {0xe6b685, 0x9fb8}, /* U+6D85 */ + {0xe6b687, 0xebe9}, /* U+6D87 [2000] */ + {0xe6b688, 0x8fc1}, /* U+6D88 */ + {0xe6b689, 0xebea}, /* U+6D89 [2000] */ + {0xe6b68a, 0xf4d6}, /* U+6D8A [2000] */ + {0xe6b68c, 0x974f}, /* U+6D8C */ + {0xe6b68d, 0xf4d7}, /* U+6D8D [2000] */ + {0xe6b68e, 0x9fb5}, /* U+6D8E */ + {0xe6b691, 0xf4d8}, /* U+6D91 [2000] */ + {0xe6b693, 0x9fb0}, /* U+6D93 */ + {0xe6b694, 0xebeb}, /* U+6D94 [2000] */ + {0xe6b695, 0x9fb6}, /* U+6D95 */ + {0xe6b698, 0xf4d9}, /* U+6D98 [2000] */ + {0xe6b699, 0x97dc}, /* U+6D99 */ + {0xe6b69b, 0x9393}, /* U+6D9B */ + {0xe6b69c, 0x93c0}, /* U+6D9C */ + {0xe6b6aa, 0xebec}, /* U+6DAA [2000] */ + {0xe6b6ab, 0xf4df}, /* U+6DAB [2000] */ + {0xe6b6ac, 0xebed}, /* U+6DAC [2000] */ + {0xe6b6ae, 0xf4e0}, /* U+6DAE [2000] */ + {0xe6b6af, 0x8a55}, /* U+6DAF */ + {0xe6b6b2, 0x8974}, /* U+6DB2 */ + {0xe6b6b4, 0xf4e1}, /* U+6DB4 [2000] */ + {0xe6b6b5, 0x9fbc}, /* U+6DB5 */ + {0xe6b6b8, 0x9fbf}, /* U+6DB8 */ + {0xe6b6bc, 0x97c1}, /* U+6DBC */ + {0xe6b6bf, 0xebee}, /* U+6DBF [2000] */ + {0xe6b780, 0x9784}, /* U+6DC0 */ + {0xe6b782, 0xf4e2}, /* U+6DC2 [2000] */ + {0xe6b784, 0xebef}, /* U+6DC4 [2000] */ + {0xe6b785, 0x9fc6}, /* U+6DC5 */ + {0xe6b786, 0x9fc0}, /* U+6DC6 */ + {0xe6b787, 0x9fbd}, /* U+6DC7 */ + {0xe6b788, 0xf4e4}, /* U+6DC8 [2000] */ + {0xe6b78b, 0x97d2}, /* U+6DCB */ + {0xe6b78c, 0x9fc3}, /* U+6DCC */ + {0xe6b78e, 0xf4e5}, /* U+6DCE [2000] */ + {0xe6b78f, 0xf4e6}, /* U+6DCF [2000] */ + {0xe6b790, 0xf4e7}, /* U+6DD0 [2000] */ + {0xe6b791, 0x8f69}, /* U+6DD1 */ + {0xe6b792, 0x9fc5}, /* U+6DD2 */ + {0xe6b795, 0x9fca}, /* U+6DD5 */ + {0xe6b796, 0xebf0}, /* U+6DD6 [2000] */ + {0xe6b798, 0x9391}, /* U+6DD8 */ + {0xe6b799, 0x9fc8}, /* U+6DD9 */ + {0xe6b79a, 0xebf1}, /* U+6DDA [2000] */ + {0xe6b79b, 0xebf2}, /* U+6DDB [2000] */ + {0xe6b79d, 0xebf3}, /* U+6DDD [2000] */ + {0xe6b79e, 0x9fc2}, /* U+6DDE */ + {0xe6b79f, 0xf4e8}, /* U+6DDF [2000] */ + {0xe6b7a1, 0x9257}, /* U+6DE1 */ + {0xe6b7a4, 0x9fc9}, /* U+6DE4 */ + {0xe6b7a6, 0x9fbe}, /* U+6DE6 */ + {0xe6b7a8, 0x9fc4}, /* U+6DE8 */ + {0xe6b7a9, 0xf4e9}, /* U+6DE9 [2000] */ + {0xe6b7aa, 0x9fcb}, /* U+6DEA */ + {0xe6b7ab, 0x88fa}, /* U+6DEB */ + {0xe6b7ac, 0x9fc1}, /* U+6DEC */ + {0xe6b7ae, 0x9fcc}, /* U+6DEE */ + {0xe6b7b1, 0x905b}, /* U+6DF1 */ + {0xe6b7b3, 0x8f7e}, /* U+6DF3 */ + {0xe6b7b5, 0x95a3}, /* U+6DF5 */ + {0xe6b7b6, 0xf4ea}, /* U+6DF6 [2000] */ + {0xe6b7b7, 0x8dac}, /* U+6DF7 */ + {0xe6b7b9, 0x9fb9}, /* U+6DF9 */ + {0xe6b7ba, 0x9fc7}, /* U+6DFA */ + {0xe6b7bb, 0x9359}, /* U+6DFB */ + {0xe6b7bc, 0xebf4}, /* U+6DFC [2000] */ + {0xe6b885, 0x90b4}, /* U+6E05 */ + {0xe6b887, 0x8a89}, /* U+6E07 */ + {0xe6b888, 0x8dcf}, /* U+6E08 */ + {0xe6b889, 0x8fc2}, /* U+6E09 */ + {0xe6b88a, 0x9fbb}, /* U+6E0A */ + {0xe6b88b, 0x8f61}, /* U+6E0B */ + {0xe6b893, 0x8c6b}, /* U+6E13 */ + {0xe6b895, 0x9fba}, /* U+6E15 */ + {0xe6b897, 0xf4db}, /* U+6E17 [2000] */ + {0xe6b899, 0x9fd0}, /* U+6E19 */ + {0xe6b89a, 0x8f8d}, /* U+6E1A */ + {0xe6b89b, 0x8cb8}, /* U+6E1B */ + {0xe6b89d, 0x9fdf}, /* U+6E1D */ + {0xe6b89e, 0xf4ec}, /* U+6E1E [2000] */ + {0xe6b89f, 0x9fd9}, /* U+6E1F */ + {0xe6b8a0, 0x8b94}, /* U+6E20 */ + {0xe6b8a1, 0x936e}, /* U+6E21 */ + {0xe6b8a2, 0xf4ed}, /* U+6E22 [2000] */ + {0xe6b8a3, 0x9fd4}, /* U+6E23 */ + {0xe6b8a4, 0x9fdd}, /* U+6E24 */ + {0xe6b8a5, 0x88ad}, /* U+6E25 */ + {0xe6b8a6, 0x8951}, /* U+6E26 */ + {0xe6b8a7, 0xf4ee}, /* U+6E27 [2000] */ + {0xe6b8a9, 0x89b7}, /* U+6E29 */ + {0xe6b8ab, 0x9fd6}, /* U+6E2B */ + {0xe6b8ac, 0x91aa}, /* U+6E2C */ + {0xe6b8ad, 0x9fcd}, /* U+6E2D */ + {0xe6b8ae, 0x9fcf}, /* U+6E2E */ + {0xe6b8af, 0x8d60}, /* U+6E2F */ + {0xe6b8b2, 0xf4f0}, /* U+6E32 [2000] */ + {0xe6b8b4, 0xebf6}, /* U+6E34 [2000] */ + {0xe6b8b6, 0xf4eb}, /* U+6E36 [2000] */ + {0xe6b8b8, 0x9fe0}, /* U+6E38 */ + {0xe6b8ba, 0x9fdb}, /* U+6E3A */ + {0xe6b8bc, 0xf4f1}, /* U+6E3C [2000] */ + {0xe6b8be, 0x9fd3}, /* U+6E3E */ + {0xe6b983, 0x9fda}, /* U+6E43 */ + {0xe6b984, 0xebf7}, /* U+6E44 [2000] */ + {0xe6b988, 0xf4f2}, /* U+6E48 [2000] */ + {0xe6b989, 0xf4f3}, /* U+6E49 [2000] */ + {0xe6b98a, 0x96a9}, /* U+6E4A */ + {0xe6b98b, 0xf4f4}, /* U+6E4B [2000] */ + {0xe6b98c, 0xf4f5}, /* U+6E4C [2000] */ + {0xe6b98d, 0x9fd8}, /* U+6E4D */ + {0xe6b98e, 0x9fdc}, /* U+6E4E */ + {0xe6b98f, 0xf4f6}, /* U+6E4F [2000] */ + {0xe6b991, 0xf4f7}, /* U+6E51 [2000] */ + {0xe6b993, 0xf4f8}, /* U+6E53 [2000] */ + {0xe6b994, 0xf4f9}, /* U+6E54 [2000] */ + {0xe6b996, 0x8cce}, /* U+6E56 */ + {0xe6b997, 0xf4fa}, /* U+6E57 [2000] */ + {0xe6b998, 0x8fc3}, /* U+6E58 */ + {0xe6b99b, 0x9258}, /* U+6E5B */ + {0xe6b99c, 0xebf8}, /* U+6E5C [2000] */ + {0xe6b99e, 0xebf9}, /* U+6E5E [2000] */ + {0xe6b99f, 0x9fd2}, /* U+6E5F */ + {0xe6b9a3, 0xf4fb}, /* U+6E63 [2000] */ + {0xe6b9a7, 0x974e}, /* U+6E67 */ + {0xe6b9ab, 0x9fd5}, /* U+6E6B */ + {0xe6b9ae, 0x9fce}, /* U+6E6E */ + {0xe6b9af, 0x9392}, /* U+6E6F */ + {0xe6b9b2, 0x9fd1}, /* U+6E72 */ + {0xe6b9b6, 0x9fd7}, /* U+6E76 */ + {0xe6b9be, 0x9870}, /* U+6E7E */ + {0xe6b9bf, 0x8ebc}, /* U+6E7F */ + {0xe6ba80, 0x969e}, /* U+6E80 */ + {0xe6ba82, 0x9fe1}, /* U+6E82 */ + {0xe6ba8c, 0x94ac}, /* U+6E8C */ + {0xe6ba8f, 0x9fed}, /* U+6E8F */ + {0xe6ba90, 0x8cb9}, /* U+6E90 */ + {0xe6ba93, 0xf540}, /* U+6E93 [2000] */ + {0xe6ba96, 0x8f80}, /* U+6E96 */ + {0xe6ba98, 0x9fe3}, /* U+6E98 */ + {0xe6ba9c, 0x97ad}, /* U+6E9C */ + {0xe6ba9d, 0x8d61}, /* U+6E9D */ + {0xe6ba9f, 0x9ff0}, /* U+6E9F */ + {0xe6baa2, 0x88ec}, /* U+6EA2 */ + {0xe6baa5, 0x9fee}, /* U+6EA5 */ + {0xe6baa7, 0xf541}, /* U+6EA7 [2000] */ + {0xe6baaa, 0x9fe2}, /* U+6EAA */ + {0xe6baab, 0xebfa}, /* U+6EAB [2000] */ + {0xe6baaf, 0x9fe8}, /* U+6EAF */ + {0xe6bab1, 0xebfb}, /* U+6EB1 [2000] */ + {0xe6bab2, 0x9fea}, /* U+6EB2 */ + {0xe6bab4, 0xf542}, /* U+6EB4 [2000] */ + {0xe6bab6, 0x976e}, /* U+6EB6 */ + {0xe6bab7, 0x9fe5}, /* U+6EB7 */ + {0xe6baba, 0x934d}, /* U+6EBA */ + {0xe6babd, 0x9fe7}, /* U+6EBD */ + {0xe6babf, 0xf543}, /* U+6EBF [2000] */ + {0xe6bb81, 0xebfc}, /* U+6EC1 [2000] */ + {0xe6bb82, 0x9fef}, /* U+6EC2 */ + {0xe6bb83, 0xf544}, /* U+6EC3 [2000] */ + {0xe6bb84, 0x9fe9}, /* U+6EC4 */ + {0xe6bb85, 0x96c5}, /* U+6EC5 */ + {0xe6bb87, 0xec40}, /* U+6EC7 [2000] */ + {0xe6bb89, 0x9fe4}, /* U+6EC9 */ + {0xe6bb8a, 0xf545}, /* U+6ECA [2000] */ + {0xe6bb8b, 0x8ea0}, /* U+6ECB */ + {0xe6bb8c, 0x9ffc}, /* U+6ECC */ + {0xe6bb8e, 0xec41}, /* U+6ECE [2000] */ + {0xe6bb91, 0x8a8a}, /* U+6ED1 */ + {0xe6bb93, 0x9fe6}, /* U+6ED3 */ + {0xe6bb94, 0x9feb}, /* U+6ED4 */ + {0xe6bb95, 0x9fec}, /* U+6ED5 */ + {0xe6bb99, 0xf546}, /* U+6ED9 [2000] */ + {0xe6bb9d, 0x91ea}, /* U+6EDD */ + {0xe6bb9e, 0x91d8}, /* U+6EDE */ + {0xe6bbab, 0xf548}, /* U+6EEB [2000] */ + {0xe6bbac, 0x9ff4}, /* U+6EEC */ + {0xe6bbaf, 0x9ffa}, /* U+6EEF */ + {0xe6bbb2, 0x9ff8}, /* U+6EF2 */ + {0xe6bbb4, 0x9348}, /* U+6EF4 */ + {0xe6bbb7, 0xe042}, /* U+6EF7 */ + {0xe6bbb8, 0x9ff5}, /* U+6EF8 */ + {0xe6bbb9, 0xf549}, /* U+6EF9 [2000] */ + {0xe6bbbb, 0xf54a}, /* U+6EFB [2000] */ + {0xe6bbbe, 0x9ff6}, /* U+6EFE */ + {0xe6bbbf, 0x9fde}, /* U+6EFF */ + {0xe6bc81, 0x8b99}, /* U+6F01 */ + {0xe6bc82, 0x9559}, /* U+6F02 */ + {0xe6bc86, 0x8ebd}, /* U+6F06 */ + {0xe6bc89, 0x8d97}, /* U+6F09 */ + {0xe6bc8a, 0xf54b}, /* U+6F0A [2000] */ + {0xe6bc8c, 0xf54c}, /* U+6F0C [2000] */ + {0xe6bc8f, 0x9852}, /* U+6F0F */ + {0xe6bc90, 0xec42}, /* U+6F10 [2000] */ + {0xe6bc91, 0x9ff2}, /* U+6F11 */ + {0xe6bc93, 0xe041}, /* U+6F13 */ + {0xe6bc94, 0x8989}, /* U+6F14 */ + {0xe6bc95, 0x9186}, /* U+6F15 */ + {0xe6bc98, 0xf54d}, /* U+6F18 [2000] */ + {0xe6bc9a, 0xec43}, /* U+6F1A [2000] */ + {0xe6bca0, 0x9499}, /* U+6F20 */ + {0xe6bca2, 0x8abf}, /* U+6F22 */ + {0xe6bca3, 0x97f8}, /* U+6F23 */ + {0xe6bca5, 0xf54e}, /* U+6F25 [2000] */ + {0xe6bcaa, 0xec45}, /* U+6F2A [2000] */ + {0xe6bcab, 0x969f}, /* U+6F2B */ + {0xe6bcac, 0x92d0}, /* U+6F2C */ + {0xe6bcaf, 0xec46}, /* U+6F2F [2000] */ + {0xe6bcb1, 0x9ff9}, /* U+6F31 */ + {0xe6bcb2, 0x9ffb}, /* U+6F32 */ + {0xe6bcb3, 0xec47}, /* U+6F33 [2000] */ + {0xe6bcb5, 0xf547}, /* U+6F35 [2000] */ + {0xe6bcb6, 0xf54f}, /* U+6F36 [2000] */ + {0xe6bcb8, 0x9151}, /* U+6F38 */ + {0xe6bcbc, 0xf550}, /* U+6F3C [2000] */ + {0xe6bcbe, 0xe040}, /* U+6F3E */ + {0xe6bcbf, 0x9ff7}, /* U+6F3F */ + {0xe6bd81, 0x9ff1}, /* U+6F41 */ + {0xe6bd85, 0x8ac1}, /* U+6F45 */ + {0xe6bd91, 0xec48}, /* U+6F51 [2000] */ + {0xe6bd92, 0xf552}, /* U+6F52 [2000] */ + {0xe6bd94, 0x8c89}, /* U+6F54 */ + {0xe6bd97, 0xf553}, /* U+6F57 [2000] */ + {0xe6bd98, 0xe04e}, /* U+6F58 */ + {0xe6bd99, 0xec49}, /* U+6F59 [2000] */ + {0xe6bd9a, 0xf554}, /* U+6F5A [2000] */ + {0xe6bd9b, 0xe049}, /* U+6F5B */ + {0xe6bd9c, 0x90f6}, /* U+6F5C */ + {0xe6bd9e, 0xec4a}, /* U+6F5E [2000] */ + {0xe6bd9f, 0x8a83}, /* U+6F5F */ + {0xe6bda0, 0xf555}, /* U+6F60 [2000] */ + {0xe6bda1, 0xec4b}, /* U+6F61 [2000] */ + {0xe6bda2, 0xec4c}, /* U+6F62 [2000] */ + {0xe6bda4, 0x8f81}, /* U+6F64 */ + {0xe6bda6, 0xe052}, /* U+6F66 */ + {0xe6bda8, 0xf556}, /* U+6F68 [2000] */ + {0xe6bdad, 0xe04b}, /* U+6F6D */ + {0xe6bdae, 0x92aa}, /* U+6F6E */ + {0xe6bdaf, 0xe048}, /* U+6F6F */ + {0xe6bdb0, 0x92d7}, /* U+6F70 */ + {0xe6bdb4, 0xe06b}, /* U+6F74 */ + {0xe6bdb8, 0xe045}, /* U+6F78 */ + {0xe6bdba, 0xe044}, /* U+6F7A */ + {0xe6bdbc, 0xe04d}, /* U+6F7C */ + {0xe6bdbd, 0xf558}, /* U+6F7D [2000] */ + {0xe6bdbe, 0xec4d}, /* U+6F7E [2000] */ + {0xe6be80, 0xe047}, /* U+6F80 */ + {0xe6be81, 0xe046}, /* U+6F81 */ + {0xe6be82, 0xe04c}, /* U+6F82 */ + {0xe6be84, 0x909f}, /* U+6F84 */ + {0xe6be86, 0xe043}, /* U+6F86 */ + {0xe6be88, 0xec4e}, /* U+6F88 [2000] */ + {0xe6be8c, 0xec4f}, /* U+6F8C [2000] */ + {0xe6be8d, 0xec50}, /* U+6F8D [2000] */ + {0xe6be8e, 0xe04f}, /* U+6F8E */ + {0xe6be90, 0xf559}, /* U+6F90 [2000] */ + {0xe6be91, 0xe050}, /* U+6F91 */ + {0xe6be94, 0xec51}, /* U+6F94 [2000] */ + {0xe6be96, 0xf55a}, /* U+6F96 [2000] */ + {0xe6be97, 0x8ac0}, /* U+6F97 */ + {0xe6be98, 0xf557}, /* U+6F98 [2000] */ + {0xe6be9f, 0xf55c}, /* U+6F9F [2000] */ + {0xe6bea0, 0xec52}, /* U+6FA0 [2000] */ + {0xe6bea1, 0xe055}, /* U+6FA1 */ + {0xe6bea3, 0xe054}, /* U+6FA3 */ + {0xe6bea4, 0xe056}, /* U+6FA4 */ + {0xe6bea5, 0xf55d}, /* U+6FA5 [2000] */ + {0xe6bea7, 0xec53}, /* U+6FA7 [2000] */ + {0xe6beaa, 0xe059}, /* U+6FAA */ + {0xe6beaf, 0xf55e}, /* U+6FAF [2000] */ + {0xe6beb1, 0x9362}, /* U+6FB1 */ + {0xe6beb3, 0xe053}, /* U+6FB3 */ + {0xe6beb5, 0xf560}, /* U+6FB5 [2000] */ + {0xe6beb6, 0xec54}, /* U+6FB6 [2000] */ + {0xe6beb9, 0xe057}, /* U+6FB9 */ + {0xe6bebc, 0xec55}, /* U+6FBC [2000] */ + {0xe6bebe, 0xf55b}, /* U+6FBE [2000] */ + {0xe6bf80, 0x8c83}, /* U+6FC0 */ + {0xe6bf81, 0x91f7}, /* U+6FC1 */ + {0xe6bf82, 0xe051}, /* U+6FC2 */ + {0xe6bf83, 0x945a}, /* U+6FC3 */ + {0xe6bf86, 0xe058}, /* U+6FC6 */ + {0xe6bf87, 0xec56}, /* U+6FC7 [2000] */ + {0xe6bf88, 0xf561}, /* U+6FC8 [2000] */ + {0xe6bf89, 0xf562}, /* U+6FC9 [2000] */ + {0xe6bf8a, 0xec57}, /* U+6FCA [2000] */ + {0xe6bf94, 0xe05d}, /* U+6FD4 */ + {0xe6bf95, 0xe05b}, /* U+6FD5 */ + {0xe6bf98, 0xe05e}, /* U+6FD8 */ + {0xe6bf9a, 0xf563}, /* U+6FDA [2000] */ + {0xe6bf9b, 0xe061}, /* U+6FDB */ + {0xe6bf9e, 0xf564}, /* U+6FDE [2000] */ + {0xe6bf9f, 0xe05a}, /* U+6FDF */ + {0xe6bfa0, 0x8d8a}, /* U+6FE0 */ + {0xe6bfa1, 0x9447}, /* U+6FE1 */ + {0xe6bfa4, 0x9fb7}, /* U+6FE4 */ + {0xe6bfa9, 0xf565}, /* U+6FE9 [2000] */ + {0xe6bfab, 0x9794}, /* U+6FEB */ + {0xe6bfac, 0xe05c}, /* U+6FEC */ + {0xe6bfae, 0xe060}, /* U+6FEE */ + {0xe6bfaf, 0x91f3}, /* U+6FEF */ + {0xe6bfb0, 0xec59}, /* U+6FF0 [2000] */ + {0xe6bfb1, 0xe05f}, /* U+6FF1 */ + {0xe6bfb3, 0xe04a}, /* U+6FF3 */ + {0xe6bfb5, 0xec5a}, /* U+6FF5 [2000] */ + {0xe6bfb6, 0xe889}, /* U+6FF6 */ + {0xe6bfb9, 0xec58}, /* U+6FF9 [2000] */ + {0xe6bfba, 0xe064}, /* U+6FFA */ + {0xe6bfbc, 0xf567}, /* U+6FFC [2000] */ + {0xe6bfbe, 0xe068}, /* U+6FFE */ + {0xe78080, 0xf568}, /* U+7000 [2000] */ + {0xe78081, 0xe066}, /* U+7001 */ + {0xe78085, 0xec5b}, /* U+7005 [2000] */ + {0xe78086, 0xec5c}, /* U+7006 [2000] */ + {0xe78087, 0xf569}, /* U+7007 [2000] */ + {0xe78089, 0xe062}, /* U+7009 */ + {0xe7808a, 0xf56a}, /* U+700A [2000] */ + {0xe7808b, 0xe063}, /* U+700B */ + {0xe7808f, 0xe067}, /* U+700F */ + {0xe78091, 0xe065}, /* U+7011 */ + {0xe78095, 0x956d}, /* U+7015 */ + {0xe78098, 0xe06d}, /* U+7018 */ + {0xe7809a, 0xe06a}, /* U+701A */ + {0xe7809b, 0xe069}, /* U+701B */ + {0xe7809d, 0xe06c}, /* U+701D */ + {0xe7809e, 0x93d2}, /* U+701E */ + {0xe7809f, 0xe06e}, /* U+701F */ + {0xe780a3, 0xf56b}, /* U+7023 [2000] */ + {0xe780a6, 0x9295}, /* U+7026 */ + {0xe780a7, 0x91eb}, /* U+7027 */ + {0xe780a8, 0xec5d}, /* U+7028 [2000] */ + {0xe780ac, 0x90a3}, /* U+702C */ + {0xe780b0, 0xe06f}, /* U+7030 */ + {0xe780b2, 0xe071}, /* U+7032 */ + {0xe780b9, 0xf56d}, /* U+7039 [2000] */ + {0xe780ba, 0xf56e}, /* U+703A [2000] */ + {0xe780bc, 0xf56f}, /* U+703C [2000] */ + {0xe780be, 0xe070}, /* U+703E */ + {0xe78183, 0xf570}, /* U+7043 [2000] */ + {0xe78187, 0xf571}, /* U+7047 [2000] */ + {0xe7818a, 0xec5e}, /* U+704A [2000] */ + {0xe7818b, 0xf572}, /* U+704B [2000] */ + {0xe7818c, 0x9ff3}, /* U+704C */ + {0xe7818e, 0xec61}, /* U+704E [2000] */ + {0xe78191, 0xe072}, /* U+7051 */ + {0xe78194, 0xf574}, /* U+7054 [2000] */ + {0xe78198, 0x93e5}, /* U+7058 */ + {0xe7819d, 0xec5f}, /* U+705D [2000] */ + {0xe7819e, 0xec60}, /* U+705E [2000] */ + {0xe781a3, 0xe073}, /* U+7063 */ + {0xe781a4, 0xec62}, /* U+7064 [2000] */ + {0xe781a5, 0xf575}, /* U+7065 [2000] */ + {0xe781a9, 0xf576}, /* U+7069 [2000] */ + {0xe781ab, 0x89ce}, /* U+706B */ + {0xe781ac, 0xf577}, /* U+706C [2000] */ + {0xe781ae, 0xf578}, /* U+706E [2000] */ + {0xe781af, 0x9394}, /* U+706F */ + {0xe781b0, 0x8a44}, /* U+7070 */ + {0xe781b5, 0xec63}, /* U+7075 [2000] */ + {0xe781b6, 0xf579}, /* U+7076 [2000] */ + {0xe781b8, 0x8b84}, /* U+7078 */ + {0xe781bc, 0x8edc}, /* U+707C */ + {0xe781bd, 0x8dd0}, /* U+707D */ + {0xe781be, 0xf57a}, /* U+707E [2000] */ + {0xe78281, 0xf57b}, /* U+7081 [2000] */ + {0xe78285, 0xec64}, /* U+7085 [2000] */ + {0xe78286, 0xf57c}, /* U+7086 [2000] */ + {0xe78289, 0x9846}, /* U+7089 */ + {0xe7828a, 0x9086}, /* U+708A */ + {0xe7828e, 0x898a}, /* U+708E */ + {0xe78292, 0xe075}, /* U+7092 */ + {0xe78295, 0xf57d}, /* U+7095 [2000] */ + {0xe78297, 0xf57e}, /* U+7097 [2000] */ + {0xe78299, 0xe074}, /* U+7099 */ + {0xe7829f, 0xf582}, /* U+709F [2000] */ + {0xe782a4, 0xec65}, /* U+70A4 [2000] */ + {0xe782ab, 0xec66}, /* U+70AB [2000] */ + {0xe782ac, 0xe078}, /* U+70AC */ + {0xe782ad, 0x9259}, /* U+70AD */ + {0xe782ae, 0xe07b}, /* U+70AE */ + {0xe782af, 0xe076}, /* U+70AF */ + {0xe782b1, 0xf583}, /* U+70B1 [2000] */ + {0xe782b3, 0xe07a}, /* U+70B3 */ + {0xe782b7, 0xec67}, /* U+70B7 [2000] */ + {0xe782b8, 0xe079}, /* U+70B8 */ + {0xe782b9, 0x935f}, /* U+70B9 */ + {0xe782ba, 0x88d7}, /* U+70BA */ + {0xe782bb, 0xf580}, /* U+70BB [2000] */ + {0xe78388, 0x97f3}, /* U+70C8 */ + {0xe7838a, 0xf586}, /* U+70CA [2000] */ + {0xe7838b, 0xe07d}, /* U+70CB */ + {0xe7838f, 0x8947}, /* U+70CF */ + {0xe78391, 0xf587}, /* U+70D1 [2000] */ + {0xe78393, 0xf588}, /* U+70D3 [2000] */ + {0xe78394, 0xec68}, /* U+70D4 [2000] */ + {0xe78398, 0xec69}, /* U+70D8 [2000] */ + {0xe78399, 0xe080}, /* U+70D9 */ + {0xe7839c, 0xf589}, /* U+70DC [2000] */ + {0xe7839d, 0xe07e}, /* U+70DD */ + {0xe7839f, 0xe07c}, /* U+70DF */ + {0xe783a4, 0xec6a}, /* U+70E4 [2000] */ + {0xe783ac, 0xf585}, /* U+70EC [2000] */ + {0xe783b1, 0xe077}, /* U+70F1 */ + {0xe783b9, 0x9642}, /* U+70F9 */ + {0xe783bd, 0xe082}, /* U+70FD */ + {0xe78483, 0xf58a}, /* U+7103 [2000] */ + {0xe78484, 0xf58b}, /* U+7104 [2000] */ + {0xe78486, 0xf58c}, /* U+7106 [2000] */ + {0xe78487, 0xf58d}, /* U+7107 [2000] */ + {0xe78488, 0xf58e}, /* U+7108 [2000] */ + {0xe78489, 0xe081}, /* U+7109 */ + {0xe7848c, 0xf58f}, /* U+710C [2000] */ + {0xe7848f, 0xec6b}, /* U+710F [2000] */ + {0xe78494, 0x898b}, /* U+7114 */ + {0xe78499, 0xe084}, /* U+7119 */ + {0xe7849a, 0x95b0}, /* U+711A */ + {0xe7849c, 0xe083}, /* U+711C */ + {0xe7849e, 0xec6d}, /* U+711E [2000] */ + {0xe784a0, 0xec6e}, /* U+7120 [2000] */ + {0xe784a1, 0x96b3}, /* U+7121 */ + {0xe784a6, 0x8fc5}, /* U+7126 */ + {0xe784ab, 0xec6c}, /* U+712B [2000] */ + {0xe784ae, 0xec6f}, /* U+712E [2000] */ + {0xe784af, 0xf591}, /* U+712F [2000] */ + {0xe784b0, 0xec70}, /* U+7130 [2000] */ + {0xe784b1, 0xf592}, /* U+7131 [2000] */ + {0xe784b6, 0x9152}, /* U+7136 */ + {0xe784bc, 0x8fc4}, /* U+713C */ + {0xe78586, 0xec71}, /* U+7146 [2000] */ + {0xe78587, 0xec72}, /* U+7147 [2000] */ + {0xe78589, 0x97f9}, /* U+7149 */ + {0xe7858a, 0xf594}, /* U+714A [2000] */ + {0xe7858c, 0xe08a}, /* U+714C */ + {0xe7858e, 0x90f7}, /* U+714E */ + {0xe78590, 0xf593}, /* U+7150 [2000] */ + {0xe78591, 0xec73}, /* U+7151 [2000] */ + {0xe78592, 0xec75}, /* U+7152 [2000] */ + {0xe78593, 0xf595}, /* U+7153 [2000] */ + {0xe78595, 0xe086}, /* U+7155 */ + {0xe78596, 0xe08b}, /* U+7156 */ + {0xe78599, 0x898c}, /* U+7159 */ + {0xe7859c, 0xec76}, /* U+715C [2000] */ + {0xe7859e, 0xf596}, /* U+715E [2000] */ + {0xe785a0, 0xec77}, /* U+7160 [2000] */ + {0xe785a2, 0xe089}, /* U+7162 */ + {0xe785a4, 0x9481}, /* U+7164 */ + {0xe785a5, 0xe085}, /* U+7165 */ + {0xe785a6, 0xe088}, /* U+7166 */ + {0xe785a7, 0x8fc6}, /* U+7167 */ + {0xe785a8, 0xec78}, /* U+7168 [2000] */ + {0xe785a9, 0x94cf}, /* U+7169 */ + {0xe785ac, 0xe08c}, /* U+716C */ + {0xe785ae, 0x8ecf}, /* U+716E */ + {0xe785bd, 0x90f8}, /* U+717D */ + {0xe78680, 0xf599}, /* U+7180 [2000] */ + {0xe78684, 0xe08f}, /* U+7184 */ + {0xe78685, 0xec7a}, /* U+7185 [2000] */ + {0xe78687, 0xec7b}, /* U+7187 [2000] */ + {0xe78688, 0xe087}, /* U+7188 */ + {0xe7868a, 0x8c46}, /* U+718A */ + {0xe7868f, 0xe08d}, /* U+718F */ + {0xe78692, 0xec7c}, /* U+7192 [2000] */ + {0xe78694, 0x976f}, /* U+7194 */ + {0xe78695, 0xe090}, /* U+7195 */ + {0xe78696, 0xf598}, /* U+7196 [2000] */ + {0xe78699, 0xeaa4}, /* U+7199 [1990] */ + {0xe7869b, 0xf59a}, /* U+719B [2000] */ + {0xe7869f, 0x8f6e}, /* U+719F */ + {0xe786a0, 0xf59b}, /* U+71A0 [2000] */ + {0xe786a2, 0xf59c}, /* U+71A2 [2000] */ + {0xe786a8, 0xe091}, /* U+71A8 */ + {0xe786ac, 0xe092}, /* U+71AC */ + {0xe786ae, 0xf59d}, /* U+71AE [2000] */ + {0xe786af, 0xf59e}, /* U+71AF [2000] */ + {0xe786b1, 0x944d}, /* U+71B1 */ + {0xe786b3, 0xf59f}, /* U+71B3 [2000] */ + {0xe786b9, 0xe094}, /* U+71B9 */ + {0xe786ba, 0xec7e}, /* U+71BA [2000] */ + {0xe786be, 0xe095}, /* U+71BE */ + {0xe78781, 0xec7d}, /* U+71C1 [2000] */ + {0xe78783, 0x9452}, /* U+71C3 */ + {0xe78784, 0xec80}, /* U+71C4 [2000] */ + {0xe78788, 0x9395}, /* U+71C8 */ + {0xe78789, 0xe097}, /* U+71C9 */ + {0xe7878b, 0xf5a1}, /* U+71CB [2000] */ + {0xe7878e, 0xe099}, /* U+71CE */ + {0xe78790, 0x97d3}, /* U+71D0 */ + {0xe78792, 0xe096}, /* U+71D2 */ + {0xe78793, 0xf5a2}, /* U+71D3 [2000] */ + {0xe78794, 0xe098}, /* U+71D4 */ + {0xe78795, 0x898d}, /* U+71D5 */ + {0xe78797, 0xe093}, /* U+71D7 */ + {0xe78799, 0xf5a3}, /* U+71D9 [2000] */ + {0xe7879c, 0xf5a4}, /* U+71DC [2000] */ + {0xe7879f, 0x9a7a}, /* U+71DF */ + {0xe787a0, 0xe09a}, /* U+71E0 */ + {0xe787a5, 0x9187}, /* U+71E5 */ + {0xe787a6, 0x8e57}, /* U+71E6 */ + {0xe787a7, 0xe09c}, /* U+71E7 */ + {0xe787ac, 0xe09b}, /* U+71EC */ + {0xe787ad, 0x9043}, /* U+71ED */ + {0xe787ae, 0x99d7}, /* U+71EE */ + {0xe787b5, 0xe09d}, /* U+71F5 */ + {0xe787b9, 0xe09f}, /* U+71F9 */ + {0xe787bb, 0xe08e}, /* U+71FB */ + {0xe787bc, 0xe09e}, /* U+71FC */ + {0xe787be, 0xec81}, /* U+71FE [2000] */ + {0xe787bf, 0xe0a0}, /* U+71FF */ + {0xe78880, 0xec82}, /* U+7200 [2000] */ + {0xe78886, 0x949a}, /* U+7206 */ + {0xe78887, 0xf5a5}, /* U+7207 [2000] */ + {0xe7888d, 0xe0a1}, /* U+720D */ + {0xe78890, 0xe0a2}, /* U+7210 */ + {0xe78895, 0xec83}, /* U+7215 [2000] */ + {0xe7889b, 0xe0a3}, /* U+721B */ + {0xe788a8, 0xe0a4}, /* U+7228 */ + {0xe788aa, 0x92dc}, /* U+722A */ + {0xe788ab, 0xf5a8}, /* U+722B [2000] */ + {0xe788ac, 0xe0a6}, /* U+722C */ + {0xe788ad, 0xe0a5}, /* U+722D */ + {0xe788b0, 0xe0a7}, /* U+7230 */ + {0xe788b2, 0xe0a8}, /* U+7232 */ + {0xe788b4, 0xf5a9}, /* U+7234 [2000] */ + {0xe788b5, 0x8edd}, /* U+7235 */ + {0xe788b6, 0x9583}, /* U+7236 */ + {0xe788b8, 0xf5aa}, /* U+7238 [2000] */ + {0xe788b9, 0xf5ab}, /* U+7239 [2000] */ + {0xe788ba, 0x96ea}, /* U+723A */ + {0xe788bb, 0xe0a9}, /* U+723B */ + {0xe788bc, 0xe0aa}, /* U+723C */ + {0xe788bd, 0x9175}, /* U+723D */ + {0xe788be, 0x8ea2}, /* U+723E */ + {0xe788bf, 0xe0ab}, /* U+723F */ + {0xe78980, 0xe0ac}, /* U+7240 */ + {0xe78982, 0xf5ad}, /* U+7242 [2000] */ + {0xe78986, 0xe0ad}, /* U+7246 */ + {0xe78987, 0x95d0}, /* U+7247 */ + {0xe78988, 0x94c5}, /* U+7248 */ + {0xe7898b, 0xe0ae}, /* U+724B */ + {0xe7898c, 0x9476}, /* U+724C */ + {0xe78992, 0x92ab}, /* U+7252 */ + {0xe78993, 0xf5ae}, /* U+7253 [2000] */ + {0xe78995, 0xec84}, /* U+7255 [2000] */ + {0xe78996, 0xec85}, /* U+7256 [2000] */ + {0xe78997, 0xf5af}, /* U+7257 [2000] */ + {0xe78998, 0xe0af}, /* U+7258 */ + {0xe78999, 0x89e5}, /* U+7259 */ + {0xe7899b, 0x8b8d}, /* U+725B */ + {0xe7899d, 0x96c4}, /* U+725D */ + {0xe7899f, 0x96b4}, /* U+725F */ + {0xe789a1, 0x89b2}, /* U+7261 */ + {0xe789a2, 0x9853}, /* U+7262 */ + {0xe789a3, 0xf5b0}, /* U+7263 [2000] */ + {0xe789a7, 0x9671}, /* U+7267 */ + {0xe789a9, 0x95a8}, /* U+7269 */ + {0xe789ae, 0xf5b2}, /* U+726E [2000] */ + {0xe789af, 0xf5b3}, /* U+726F [2000] */ + {0xe789b2, 0x90b5}, /* U+7272 */ + {0xe789b4, 0xe0b0}, /* U+7274 */ + {0xe789b8, 0xf5b4}, /* U+7278 [2000] */ + {0xe789b9, 0x93c1}, /* U+7279 */ + {0xe789bd, 0x8ca1}, /* U+727D */ + {0xe789be, 0xe0b1}, /* U+727E */ + {0xe789bf, 0xf5b5}, /* U+727F [2000] */ + {0xe78a80, 0x8dd2}, /* U+7280 */ + {0xe78a81, 0xe0b3}, /* U+7281 */ + {0xe78a82, 0xe0b2}, /* U+7282 */ + {0xe78a87, 0xe0b4}, /* U+7287 */ + {0xe78a8d, 0xec87}, /* U+728D [2000] */ + {0xe78a8e, 0xf5b6}, /* U+728E [2000] */ + {0xe78a92, 0xe0b5}, /* U+7292 */ + {0xe78a96, 0xe0b6}, /* U+7296 */ + {0xe78a9b, 0xec88}, /* U+729B [2000] */ + {0xe78aa0, 0x8b5d}, /* U+72A0 */ + {0xe78aa2, 0xe0b7}, /* U+72A2 */ + {0xe78aa7, 0xe0b8}, /* U+72A7 */ + {0xe78aac, 0x8ca2}, /* U+72AC */ + {0xe78aad, 0xf5b8}, /* U+72AD [2000] */ + {0xe78aae, 0xf5b9}, /* U+72AE [2000] */ + {0xe78aaf, 0x94c6}, /* U+72AF */ + {0xe78ab0, 0xf5ba}, /* U+72B0 [2000] */ + {0xe78ab1, 0xf5bb}, /* U+72B1 [2000] */ + {0xe78ab2, 0xe0ba}, /* U+72B2 */ + {0xe78ab6, 0x8ff3}, /* U+72B6 */ + {0xe78ab9, 0xe0b9}, /* U+72B9 */ + {0xe78abe, 0xec89}, /* U+72BE [2000] */ + {0xe78b80, 0xec8a}, /* U+72C0 [2000] */ + {0xe78b81, 0xf5bc}, /* U+72C1 [2000] */ + {0xe78b82, 0x8bb6}, /* U+72C2 */ + {0xe78b83, 0xe0bb}, /* U+72C3 */ + {0xe78b84, 0xe0bd}, /* U+72C4 */ + {0xe78b86, 0xe0bc}, /* U+72C6 */ + {0xe78b8c, 0xf5be}, /* U+72CC [2000] */ + {0xe78b8e, 0xe0be}, /* U+72CE */ + {0xe78b90, 0x8ccf}, /* U+72D0 */ + {0xe78b92, 0xe0bf}, /* U+72D2 */ + {0xe78b97, 0x8be7}, /* U+72D7 */ + {0xe78b99, 0x915f}, /* U+72D9 */ + {0xe78b9b, 0x8d9d}, /* U+72DB */ + {0xe78ba0, 0xe0c1}, /* U+72E0 */ + {0xe78ba1, 0xe0c2}, /* U+72E1 */ + {0xe78ba2, 0xe0c0}, /* U+72E2 */ + {0xe78ba9, 0x8eeb}, /* U+72E9 */ + {0xe78bac, 0x93c6}, /* U+72EC */ + {0xe78bad, 0x8bb7}, /* U+72ED */ + {0xe78bb3, 0xf5c1}, /* U+72F3 [2000] */ + {0xe78bb7, 0xe0c4}, /* U+72F7 */ + {0xe78bb8, 0x924b}, /* U+72F8 */ + {0xe78bb9, 0xe0c3}, /* U+72F9 */ + {0xe78bba, 0xf5c2}, /* U+72FA [2000] */ + {0xe78bbb, 0xec8b}, /* U+72FB [2000] */ + {0xe78bbc, 0x9854}, /* U+72FC */ + {0xe78bbd, 0x9482}, /* U+72FD */ + {0xe78c87, 0xf5c3}, /* U+7307 [2000] */ + {0xe78c8a, 0xe0c7}, /* U+730A */ + {0xe78c92, 0xf5c4}, /* U+7312 [2000] */ + {0xe78c96, 0xe0c9}, /* U+7316 */ + {0xe78c97, 0xe0c6}, /* U+7317 */ + {0xe78c98, 0xf5c5}, /* U+7318 [2000] */ + {0xe78c99, 0xf5c6}, /* U+7319 [2000] */ + {0xe78c9b, 0x96d2}, /* U+731B */ + {0xe78c9c, 0xe0c8}, /* U+731C */ + {0xe78c9d, 0xe0ca}, /* U+731D */ + {0xe78c9f, 0x97c2}, /* U+731F */ + {0xe78ca5, 0xe0ce}, /* U+7325 */ + {0xe78ca7, 0xec8d}, /* U+7327 [2000] */ + {0xe78ca8, 0xec8e}, /* U+7328 [2000] */ + {0xe78ca9, 0xe0cd}, /* U+7329 */ + {0xe78caa, 0x9296}, /* U+732A */ + {0xe78cab, 0x944c}, /* U+732B */ + {0xe78cac, 0xf5c9}, /* U+732C [2000] */ + {0xe78cae, 0x8ca3}, /* U+732E */ + {0xe78caf, 0xe0cc}, /* U+732F */ + {0xe78cb1, 0xf5ca}, /* U+7331 [2000] */ + {0xe78cb3, 0xf5cb}, /* U+7333 [2000] */ + {0xe78cb4, 0xe0cb}, /* U+7334 */ + {0xe78cb6, 0x9750}, /* U+7336 */ + {0xe78cb7, 0x9751}, /* U+7337 */ + {0xe78cb9, 0xf5c8}, /* U+7339 [2000] */ + {0xe78cbd, 0xf5cc}, /* U+733D [2000] */ + {0xe78cbe, 0xe0cf}, /* U+733E */ + {0xe78cbf, 0x898e}, /* U+733F */ + {0xe78d84, 0x8d96}, /* U+7344 */ + {0xe78d85, 0x8e82}, /* U+7345 */ + {0xe78d8e, 0xe0d0}, /* U+734E */ + {0xe78d8f, 0xe0d1}, /* U+734F */ + {0xe78d90, 0xec90}, /* U+7350 [2000] */ + {0xe78d92, 0xf5cd}, /* U+7352 [2000] */ + {0xe78d97, 0xe0d3}, /* U+7357 */ + {0xe78da3, 0x8f62}, /* U+7363 */ + {0xe78da6, 0xec91}, /* U+7366 [2000] */ + {0xe78da8, 0xe0d5}, /* U+7368 */ + {0xe78daa, 0xe0d4}, /* U+736A */ + {0xe78dab, 0xf5cf}, /* U+736B [2000] */ + {0xe78dac, 0xf5d0}, /* U+736C [2000] */ + {0xe78dae, 0xf5d2}, /* U+736E [2000] */ + {0xe78daf, 0xf5d3}, /* U+736F [2000] */ + {0xe78db0, 0xe0d6}, /* U+7370 */ + {0xe78db1, 0xf5d4}, /* U+7371 [2000] */ + {0xe78db2, 0x8a6c}, /* U+7372 */ + {0xe78db5, 0xe0d8}, /* U+7375 */ + {0xe78db7, 0xf5d5}, /* U+7377 [2000] */ + {0xe78db8, 0xe0d7}, /* U+7378 */ + {0xe78dba, 0xe0da}, /* U+737A */ + {0xe78dbb, 0xe0d9}, /* U+737B */ + {0xe78dbc, 0xec92}, /* U+737C [2000] */ + {0xe78e81, 0xf5d6}, /* U+7381 [2000] */ + {0xe78e84, 0x8cba}, /* U+7384 */ + {0xe78e85, 0xf5d7}, /* U+7385 [2000] */ + {0xe78e87, 0x97a6}, /* U+7387 */ + {0xe78e89, 0x8bca}, /* U+7389 */ + {0xe78e8a, 0xf5d8}, /* U+738A [2000] */ + {0xe78e8b, 0x89a4}, /* U+738B */ + {0xe78e94, 0xf5d9}, /* U+7394 [2000] */ + {0xe78e95, 0xec93}, /* U+7395 [2000] */ + {0xe78e96, 0x8be8}, /* U+7396 */ + {0xe78e98, 0xf5da}, /* U+7398 [2000] */ + {0xe78e9c, 0xf5db}, /* U+739C [2000] */ + {0xe78e9e, 0xf5dc}, /* U+739E [2000] */ + {0xe78e9f, 0xec94}, /* U+739F [2000] */ + {0xe78ea0, 0xec95}, /* U+73A0 [2000] */ + {0xe78ea2, 0xec96}, /* U+73A2 [2000] */ + {0xe78ea5, 0xf5dd}, /* U+73A5 [2000] */ + {0xe78ea6, 0xec97}, /* U+73A6 [2000] */ + {0xe78ea8, 0xf5de}, /* U+73A8 [2000] */ + {0xe78ea9, 0x8adf}, /* U+73A9 */ + {0xe78eab, 0xec98}, /* U+73AB [2000] */ + {0xe78eb2, 0x97e6}, /* U+73B2 */ + {0xe78eb3, 0xe0dc}, /* U+73B3 */ + {0xe78eb5, 0xf5df}, /* U+73B5 [2000] */ + {0xe78eb7, 0xf5e0}, /* U+73B7 [2000] */ + {0xe78eb9, 0xf5e1}, /* U+73B9 [2000] */ + {0xe78ebb, 0xe0de}, /* U+73BB */ + {0xe78ebc, 0xf5e2}, /* U+73BC [2000] */ + {0xe78ebf, 0xf5e3}, /* U+73BF [2000] */ + {0xe78f80, 0xe0df}, /* U+73C0 */ + {0xe78f82, 0x89cf}, /* U+73C2 */ + {0xe78f85, 0xf5e4}, /* U+73C5 [2000] */ + {0xe78f88, 0xe0db}, /* U+73C8 */ + {0xe78f89, 0xec99}, /* U+73C9 [2000] */ + {0xe78f8a, 0x8e58}, /* U+73CA */ + {0xe78f8b, 0xf5e5}, /* U+73CB [2000] */ + {0xe78f8d, 0x92bf}, /* U+73CD */ + {0xe78f8e, 0xe0dd}, /* U+73CE */ + {0xe78f8f, 0xec9a}, /* U+73CF [2000] */ + {0xe78f96, 0xec9b}, /* U+73D6 [2000] */ + {0xe78f99, 0xec9c}, /* U+73D9 [2000] */ + {0xe78f9e, 0xe0e2}, /* U+73DE */ + {0xe78fa0, 0x8eec}, /* U+73E0 */ + {0xe78fa1, 0xf5e6}, /* U+73E1 [2000] */ + {0xe78fa3, 0xec9d}, /* U+73E3 [2000] */ + {0xe78fa5, 0xe0e0}, /* U+73E5 */ + {0xe78fa7, 0xf5e7}, /* U+73E7 [2000] */ + {0xe78fa9, 0xec9e}, /* U+73E9 [2000] */ + {0xe78faa, 0x8c5d}, /* U+73EA */ + {0xe78fad, 0x94c7}, /* U+73ED */ + {0xe78fae, 0xe0e1}, /* U+73EE */ + {0xe78fb1, 0xe0fc}, /* U+73F1 */ + {0xe78fb8, 0xe0e7}, /* U+73F8 */ + {0xe78fb9, 0xf5e8}, /* U+73F9 [2000] */ + {0xe78fba, 0xf5ea}, /* U+73FA [2000] */ + {0xe78fbe, 0x8cbb}, /* U+73FE */ + {0xe79081, 0xf5eb}, /* U+7401 [2000] */ + {0xe79083, 0x8b85}, /* U+7403 */ + {0xe79085, 0xe0e4}, /* U+7405 */ + {0xe79086, 0x979d}, /* U+7406 */ + {0xe79087, 0xec9f}, /* U+7407 [2000] */ + {0xe79089, 0x97ae}, /* U+7409 */ + {0xe7908a, 0xeca0}, /* U+740A [2000] */ + {0xe79093, 0xf5e9}, /* U+7413 [2000] */ + {0xe7909a, 0xeca1}, /* U+741A [2000] */ + {0xe7909b, 0xeca2}, /* U+741B [2000] */ + {0xe790a2, 0x91f4}, /* U+7422 */ + {0xe790a4, 0xf5ec}, /* U+7424 [2000] */ + {0xe790a5, 0xe0e6}, /* U+7425 */ + {0xe790a6, 0xeca4}, /* U+7426 [2000] */ + {0xe790a8, 0xeca5}, /* U+7428 [2000] */ + {0xe790aa, 0xeca6}, /* U+742A [2000] */ + {0xe790ab, 0xeca7}, /* U+742B [2000] */ + {0xe790ac, 0xeca8}, /* U+742C [2000] */ + {0xe790ae, 0xeca9}, /* U+742E [2000] */ + {0xe790af, 0xecaa}, /* U+742F [2000] */ + {0xe790b0, 0xecab}, /* U+7430 [2000] */ + {0xe790b1, 0xf5ed}, /* U+7431 [2000] */ + {0xe790b2, 0xe0e8}, /* U+7432 */ + {0xe790b3, 0x97d4}, /* U+7433 */ + {0xe790b4, 0x8bd5}, /* U+7434 */ + {0xe790b5, 0x94fa}, /* U+7435 */ + {0xe790b6, 0x9469}, /* U+7436 */ + {0xe790b9, 0xf5ee}, /* U+7439 [2000] */ + {0xe790ba, 0xe0e9}, /* U+743A */ + {0xe790bf, 0xe0eb}, /* U+743F */ + {0xe79180, 0xf5f0}, /* U+7440 [2000] */ + {0xe79181, 0xe0ee}, /* U+7441 */ + {0xe79183, 0xf5f1}, /* U+7443 [2000] */ + {0xe79184, 0xecac}, /* U+7444 [2000] */ + {0xe79186, 0xecad}, /* U+7446 [2000] */ + {0xe79187, 0xecae}, /* U+7447 [2000] */ + {0xe7918b, 0xecaf}, /* U+744B [2000] */ + {0xe7918d, 0xf5f2}, /* U+744D [2000] */ + {0xe79192, 0xf5f3}, /* U+7452 [2000] */ + {0xe79193, 0xf5ef}, /* U+7453 [2000] */ + {0xe79195, 0xe0ea}, /* U+7455 */ + {0xe79197, 0xecb0}, /* U+7457 [2000] */ + {0xe79199, 0xe0ed}, /* U+7459 */ + {0xe7919a, 0x8ce8}, /* U+745A */ + {0xe7919b, 0x896c}, /* U+745B */ + {0xe7919c, 0xe0ef}, /* U+745C */ + {0xe7919d, 0xf5f4}, /* U+745D [2000] */ + {0xe7919e, 0x9090}, /* U+745E */ + {0xe7919f, 0xe0ec}, /* U+745F */ + {0xe791a0, 0x97da}, /* U+7460 */ + {0xe791a2, 0xecb1}, /* U+7462 [2000] */ + {0xe791a3, 0xe0f2}, /* U+7463 */ + {0xe791a4, 0xeaa2}, /* U+7464 [1983] */ + {0xe791a9, 0xe0f0}, /* U+7469 */ + {0xe791aa, 0xe0f3}, /* U+746A */ + {0xe791ab, 0xecb2}, /* U+746B [2000] */ + {0xe791ad, 0xecb3}, /* U+746D [2000] */ + {0xe791af, 0xe0e5}, /* U+746F */ + {0xe791b0, 0xe0f1}, /* U+7470 */ + {0xe791b1, 0xf5f5}, /* U+7471 [2000] */ + {0xe791b3, 0x8dba}, /* U+7473 */ + {0xe791b6, 0xe0f4}, /* U+7476 */ + {0xe791be, 0xe0f5}, /* U+747E */ + {0xe79281, 0xf5f6}, /* U+7481 [2000] */ + {0xe79283, 0x979e}, /* U+7483 */ + {0xe79285, 0xf5f7}, /* U+7485 [2000] */ + {0xe79286, 0xecb4}, /* U+7486 [2000] */ + {0xe79287, 0xecb5}, /* U+7487 [2000] */ + {0xe79288, 0xf5f8}, /* U+7488 [2000] */ + {0xe79289, 0xecb6}, /* U+7489 [2000] */ + {0xe7928b, 0xe0f6}, /* U+748B */ + {0xe79290, 0xecbb}, /* U+7490 [2000] */ + {0xe79292, 0xf5fa}, /* U+7492 [2000] */ + {0xe79297, 0xf5fb}, /* U+7497 [2000] */ + {0xe79298, 0xecb7}, /* U+7498 [2000] */ + {0xe79299, 0xf5fc}, /* U+7499 [2000] */ + {0xe7929c, 0xecb8}, /* U+749C [2000] */ + {0xe7929e, 0xe0f7}, /* U+749E */ + {0xe7929f, 0xecb9}, /* U+749F [2000] */ + {0xe792a0, 0xf640}, /* U+74A0 [2000] */ + {0xe792a1, 0xf641}, /* U+74A1 [2000] */ + {0xe792a2, 0xe0e3}, /* U+74A2 */ + {0xe792a3, 0xecba}, /* U+74A3 [2000] */ + {0xe792a5, 0xf642}, /* U+74A5 [2000] */ + {0xe792a6, 0xecbc}, /* U+74A6 [2000] */ + {0xe792a7, 0xe0f8}, /* U+74A7 */ + {0xe792a8, 0xecbd}, /* U+74A8 [2000] */ + {0xe792a9, 0xecbe}, /* U+74A9 [2000] */ + {0xe792aa, 0xf643}, /* U+74AA [2000] */ + {0xe792ab, 0xf644}, /* U+74AB [2000] */ + {0xe792b0, 0x8ac2}, /* U+74B0 */ + {0xe792b5, 0xecbf}, /* U+74B5 [2000] */ + {0xe792b9, 0xf645}, /* U+74B9 [2000] */ + {0xe792ba, 0xf647}, /* U+74BA [2000] */ + {0xe792bb, 0xf646}, /* U+74BB [2000] */ + {0xe792bd, 0x8ea3}, /* U+74BD */ + {0xe792bf, 0xecc0}, /* U+74BF [2000] */ + {0xe79388, 0xecc1}, /* U+74C8 [2000] */ + {0xe79389, 0xecc2}, /* U+74C9 [2000] */ + {0xe7938a, 0xe0f9}, /* U+74CA */ + {0xe7938f, 0xe0fa}, /* U+74CF */ + {0xe79394, 0xe0fb}, /* U+74D4 */ + {0xe79396, 0xf648}, /* U+74D6 [2000] */ + {0xe79398, 0xf649}, /* U+74D8 [2000] */ + {0xe7939a, 0xecc3}, /* U+74DA [2000] */ + {0xe7939c, 0x895a}, /* U+74DC */ + {0xe7939e, 0xf64a}, /* U+74DE [2000] */ + {0xe793a0, 0xe140}, /* U+74E0 */ + {0xe793a2, 0x955a}, /* U+74E2 */ + {0xe793a3, 0xe141}, /* U+74E3 */ + {0xe793a6, 0x8aa2}, /* U+74E6 */ + {0xe793a7, 0xe142}, /* U+74E7 */ + {0xe793a9, 0xe143}, /* U+74E9 */ + {0xe793ab, 0xf64c}, /* U+74EB [2000] */ + {0xe793ae, 0xe144}, /* U+74EE */ + {0xe793af, 0xf64b}, /* U+74EF [2000] */ + {0xe793b0, 0xe146}, /* U+74F0 */ + {0xe793b1, 0xe147}, /* U+74F1 */ + {0xe793b2, 0xe145}, /* U+74F2 */ + {0xe793b6, 0x9572}, /* U+74F6 */ + {0xe793b7, 0xe149}, /* U+74F7 */ + {0xe793b8, 0xe148}, /* U+74F8 */ + {0xe793ba, 0xf64e}, /* U+74FA [2000] */ + {0xe793bf, 0xecc4}, /* U+74FF [2000] */ + {0xe79481, 0xecc5}, /* U+7501 [2000] */ + {0xe79483, 0xe14b}, /* U+7503 */ + {0xe79484, 0xe14a}, /* U+7504 */ + {0xe79485, 0xe14c}, /* U+7505 */ + {0xe7948c, 0xe14d}, /* U+750C */ + {0xe7948d, 0xe14f}, /* U+750D */ + {0xe7948e, 0xe14e}, /* U+750E */ + {0xe79491, 0x8d99}, /* U+7511 */ + {0xe79493, 0xe151}, /* U+7513 */ + {0xe79495, 0xe150}, /* U+7515 */ + {0xe79497, 0xecc6}, /* U+7517 [2000] */ + {0xe79498, 0x8ac3}, /* U+7518 */ + {0xe7949a, 0x9072}, /* U+751A */ + {0xe7949c, 0x935b}, /* U+751C */ + {0xe7949e, 0xe152}, /* U+751E */ + {0xe7949f, 0x90b6}, /* U+751F */ + {0xe794a0, 0xf650}, /* U+7520 [2000] */ + {0xe794a3, 0x8e59}, /* U+7523 */ + {0xe794a4, 0xf651}, /* U+7524 [2000] */ + {0xe794a5, 0x8999}, /* U+7525 */ + {0xe794a6, 0xe153}, /* U+7526 */ + {0xe794a8, 0x9770}, /* U+7528 */ + {0xe794aa, 0xf652}, /* U+752A [2000] */ + {0xe794ab, 0x95e1}, /* U+752B */ + {0xe794ac, 0xe154}, /* U+752C */ + {0xe794af, 0xecc7}, /* U+752F [2000] */ + {0xe794b0, 0x9363}, /* U+7530 */ + {0xe794b1, 0x9752}, /* U+7531 */ + {0xe794b2, 0x8d62}, /* U+7532 */ + {0xe794b3, 0x905c}, /* U+7533 */ + {0xe794b7, 0x926a}, /* U+7537 */ + {0xe794b8, 0x99b2}, /* U+7538 */ + {0xe794ba, 0x92ac}, /* U+753A */ + {0xe794bb, 0x89e6}, /* U+753B */ + {0xe794bc, 0xe155}, /* U+753C */ + {0xe794bd, 0xf655}, /* U+753D [2000] */ + {0xe794be, 0xf656}, /* U+753E [2000] */ + {0xe79580, 0xf657}, /* U+7540 [2000] */ + {0xe79584, 0xe156}, /* U+7544 */ + {0xe79586, 0xe15b}, /* U+7546 */ + {0xe79588, 0xf658}, /* U+7548 [2000] */ + {0xe79589, 0xe159}, /* U+7549 */ + {0xe7958a, 0xe158}, /* U+754A */ + {0xe7958b, 0x9dc0}, /* U+754B */ + {0xe7958c, 0x8a45}, /* U+754C */ + {0xe7958d, 0xe157}, /* U+754D */ + {0xe7958e, 0xf659}, /* U+754E [2000] */ + {0xe7958f, 0x88d8}, /* U+754F */ + {0xe79590, 0xf65a}, /* U+7550 [2000] */ + {0xe79591, 0x94a8}, /* U+7551 */ + {0xe79592, 0xf65b}, /* U+7552 [2000] */ + {0xe79594, 0x94c8}, /* U+7554 */ + {0xe79599, 0x97af}, /* U+7559 */ + {0xe7959a, 0xe15c}, /* U+755A */ + {0xe7959b, 0xe15a}, /* U+755B */ + {0xe7959c, 0x927b}, /* U+755C */ + {0xe7959d, 0x90a4}, /* U+755D */ + {0xe795a0, 0x94a9}, /* U+7560 */ + {0xe795a2, 0x954c}, /* U+7562 */ + {0xe795a4, 0xe15e}, /* U+7564 */ + {0xe795a5, 0x97aa}, /* U+7565 */ + {0xe795a6, 0x8c6c}, /* U+7566 */ + {0xe795a7, 0xe15f}, /* U+7567 */ + {0xe795a9, 0xe15d}, /* U+7569 */ + {0xe795aa, 0x94d4}, /* U+756A */ + {0xe795ab, 0xe160}, /* U+756B */ + {0xe795ac, 0xf65c}, /* U+756C [2000] */ + {0xe795ad, 0xe161}, /* U+756D */ + {0xe795af, 0xecc8}, /* U+756F [2000] */ + {0xe795b0, 0x88d9}, /* U+7570 */ + {0xe795b1, 0xf65e}, /* U+7571 [2000] */ + {0xe795b2, 0xf65d}, /* U+7572 [2000] */ + {0xe795b3, 0x8ff4}, /* U+7573 */ + {0xe795b4, 0xe166}, /* U+7574 */ + {0xe795b6, 0xe163}, /* U+7576 */ + {0xe795b7, 0x93eb}, /* U+7577 */ + {0xe795b8, 0xe162}, /* U+7578 */ + {0xe795b9, 0xecc9}, /* U+7579 [2000] */ + {0xe795ba, 0xf65f}, /* U+757A [2000] */ + {0xe795bd, 0xf660}, /* U+757D [2000] */ + {0xe795be, 0xf661}, /* U+757E [2000] */ + {0xe795bf, 0x8b45}, /* U+757F */ + {0xe79681, 0xf662}, /* U+7581 [2000] */ + {0xe79682, 0xe169}, /* U+7582 */ + {0xe79686, 0xe164}, /* U+7586 */ + {0xe79687, 0xe165}, /* U+7587 */ + {0xe79689, 0xe168}, /* U+7589 */ + {0xe7968a, 0xe167}, /* U+758A */ + {0xe7968b, 0x9544}, /* U+758B */ + {0xe7968c, 0xf664}, /* U+758C [2000] */ + {0xe7968e, 0x9161}, /* U+758E */ + {0xe7968f, 0x9160}, /* U+758F */ + {0xe79691, 0x8b5e}, /* U+7591 */ + {0xe79692, 0xecca}, /* U+7592 [2000] */ + {0xe79694, 0xe16a}, /* U+7594 */ + {0xe7969a, 0xe16b}, /* U+759A */ + {0xe7969d, 0xe16c}, /* U+759D */ + {0xe796a2, 0xf666}, /* U+75A2 [2000] */ + {0xe796a3, 0xe16e}, /* U+75A3 */ + {0xe796a5, 0xe16d}, /* U+75A5 */ + {0xe796ab, 0x8975}, /* U+75AB */ + {0xe796b0, 0xf668}, /* U+75B0 [2000] */ + {0xe796b1, 0xe176}, /* U+75B1 */ + {0xe796b2, 0x94e6}, /* U+75B2 */ + {0xe796b3, 0xe170}, /* U+75B3 */ + {0xe796b5, 0xe172}, /* U+75B5 */ + {0xe796b7, 0xf669}, /* U+75B7 [2000] */ + {0xe796b8, 0xe174}, /* U+75B8 */ + {0xe796b9, 0x905d}, /* U+75B9 */ + {0xe796bc, 0xe175}, /* U+75BC */ + {0xe796bd, 0xe173}, /* U+75BD */ + {0xe796be, 0x8ebe}, /* U+75BE */ + {0xe796bf, 0xf66a}, /* U+75BF [2000] */ + {0xe79780, 0xf66b}, /* U+75C0 [2000] */ + {0xe79782, 0xe16f}, /* U+75C2 */ + {0xe79783, 0xe171}, /* U+75C3 */ + {0xe79785, 0x9561}, /* U+75C5 */ + {0xe79786, 0xf66c}, /* U+75C6 [2000] */ + {0xe79787, 0x8fc7}, /* U+75C7 */ + {0xe7978a, 0xe178}, /* U+75CA */ + {0xe7978d, 0xe177}, /* U+75CD */ + {0xe7978e, 0xeccc}, /* U+75CE [2000] */ + {0xe7978f, 0xf66d}, /* U+75CF [2000] */ + {0xe79792, 0xe179}, /* U+75D2 */ + {0xe79793, 0xf66e}, /* U+75D3 [2000] */ + {0xe79794, 0x8ea4}, /* U+75D4 */ + {0xe79795, 0x8dad}, /* U+75D5 */ + {0xe79798, 0x9397}, /* U+75D8 */ + {0xe79799, 0xe17a}, /* U+75D9 */ + {0xe7979b, 0x92c9}, /* U+75DB */ + {0xe7979d, 0xf66f}, /* U+75DD [2000] */ + {0xe7979e, 0xe17c}, /* U+75DE */ + {0xe7979f, 0xf670}, /* U+75DF [2000] */ + {0xe797a0, 0xf671}, /* U+75E0 [2000] */ + {0xe797a2, 0x979f}, /* U+75E2 */ + {0xe797a3, 0xe17b}, /* U+75E3 */ + {0xe797a4, 0xeccd}, /* U+75E4 [2000] */ + {0xe797a7, 0xf672}, /* U+75E7 [2000] */ + {0xe797a9, 0x9189}, /* U+75E9 */ + {0xe797ac, 0xf673}, /* U+75EC [2000] */ + {0xe797ae, 0xf674}, /* U+75EE [2000] */ + {0xe797b0, 0xe182}, /* U+75F0 */ + {0xe797b1, 0xf675}, /* U+75F1 [2000] */ + {0xe797b2, 0xe184}, /* U+75F2 */ + {0xe797b3, 0xe185}, /* U+75F3 */ + {0xe797b4, 0x9273}, /* U+75F4 */ + {0xe797b9, 0xf676}, /* U+75F9 [2000] */ + {0xe797ba, 0xe183}, /* U+75FA */ + {0xe797bc, 0xe180}, /* U+75FC */ + {0xe797be, 0xe17d}, /* U+75FE */ + {0xe797bf, 0xe17e}, /* U+75FF */ + {0xe79880, 0xecce}, /* U+7600 [2000] */ + {0xe79881, 0xe181}, /* U+7601 */ + {0xe79882, 0xeccf}, /* U+7602 [2000] */ + {0xe79883, 0xf677}, /* U+7603 [2000] */ + {0xe79887, 0xf679}, /* U+7607 [2000] */ + {0xe79888, 0xecd0}, /* U+7608 [2000] */ + {0xe79889, 0xe188}, /* U+7609 */ + {0xe7988b, 0xe186}, /* U+760B */ + {0xe7988d, 0xe187}, /* U+760D */ + {0xe7988f, 0xf67a}, /* U+760F [2000] */ + {0xe79893, 0xf67d}, /* U+7613 [2000] */ + {0xe79895, 0xecd1}, /* U+7615 [2000] */ + {0xe79896, 0xecd2}, /* U+7616 [2000] */ + {0xe79898, 0xf678}, /* U+7618 [2000] */ + {0xe79899, 0xecd3}, /* U+7619 [2000] */ + {0xe7989b, 0xf67e}, /* U+761B [2000] */ + {0xe7989c, 0xf680}, /* U+761C [2000] */ + {0xe7989e, 0xecd4}, /* U+761E [2000] */ + {0xe7989f, 0xe189}, /* U+761F */ + {0xe798a0, 0xe18b}, /* U+7620 */ + {0xe798a1, 0xe18c}, /* U+7621 */ + {0xe798a2, 0xe18d}, /* U+7622 */ + {0xe798a4, 0xe18e}, /* U+7624 */ + {0xe798a5, 0xf682}, /* U+7625 [2000] */ + {0xe798a6, 0xeffb}, /* U+7626 [2004] */ + {0xe798a7, 0xe18a}, /* U+7627 */ + {0xe798a8, 0xf683}, /* U+7628 [2000] */ + {0xe798ad, 0xecd5}, /* U+762D [2000] */ + {0xe798b0, 0xe190}, /* U+7630 */ + {0xe798b3, 0xf685}, /* U+7633 [2000] */ + {0xe798b4, 0xe18f}, /* U+7634 */ + {0xe798b5, 0xecd6}, /* U+7635 [2000] */ + {0xe798bb, 0xe191}, /* U+763B */ + {0xe798bc, 0xf684}, /* U+763C [2000] */ + {0xe79981, 0xf688}, /* U+7641 [2000] */ + {0xe79982, 0x97c3}, /* U+7642 */ + {0xe79983, 0xecd7}, /* U+7643 [2000] */ + {0xe79986, 0xe194}, /* U+7646 */ + {0xe79987, 0xe192}, /* U+7647 */ + {0xe79988, 0xe193}, /* U+7648 */ + {0xe79989, 0xf68a}, /* U+7649 [2000] */ + {0xe7998b, 0xecd8}, /* U+764B [2000] */ + {0xe7998c, 0x8ae0}, /* U+764C */ + {0xe79992, 0x96fc}, /* U+7652 */ + {0xe79995, 0xf68b}, /* U+7655 [2000] */ + {0xe79996, 0x95c8}, /* U+7656 */ + {0xe79998, 0xe196}, /* U+7658 */ + {0xe7999c, 0xe195}, /* U+765C */ + {0xe799a1, 0xe197}, /* U+7661 */ + {0xe799a2, 0xe198}, /* U+7662 */ + {0xe799a4, 0xecd9}, /* U+7664 [2000] */ + {0xe799a5, 0xecda}, /* U+7665 [2000] */ + {0xe799a7, 0xe19c}, /* U+7667 */ + {0xe799a8, 0xe199}, /* U+7668 */ + {0xe799a9, 0xe19a}, /* U+7669 */ + {0xe799aa, 0xe19b}, /* U+766A */ + {0xe799ac, 0xe19d}, /* U+766C */ + {0xe799ad, 0xecdb}, /* U+766D [2000] */ + {0xe799ae, 0xf68d}, /* U+766E [2000] */ + {0xe799af, 0xecdc}, /* U+766F [2000] */ + {0xe799b0, 0xe19e}, /* U+7670 */ + {0xe799b1, 0xecdd}, /* U+7671 [2000] */ + {0xe799b2, 0xe19f}, /* U+7672 */ + {0xe799b6, 0xe1a0}, /* U+7676 */ + {0xe799b8, 0xe1a1}, /* U+7678 */ + {0xe799ba, 0x94ad}, /* U+767A */ + {0xe799bb, 0x936f}, /* U+767B */ + {0xe799bc, 0xe1a2}, /* U+767C */ + {0xe799bd, 0x9492}, /* U+767D */ + {0xe799be, 0x9553}, /* U+767E */ + {0xe79a80, 0xe1a3}, /* U+7680 */ + {0xe79a81, 0xecde}, /* U+7681 [2000] */ + {0xe79a83, 0xe1a4}, /* U+7683 */ + {0xe79a84, 0x9349}, /* U+7684 */ + {0xe79a86, 0x8a46}, /* U+7686 */ + {0xe79a87, 0x8d63}, /* U+7687 */ + {0xe79a88, 0xe1a5}, /* U+7688 */ + {0xe79a8b, 0xe1a6}, /* U+768B */ + {0xe79a8e, 0xe1a7}, /* U+768E */ + {0xe79a90, 0x8e48}, /* U+7690 */ + {0xe79a93, 0xe1a9}, /* U+7693 */ + {0xe79a95, 0xf68e}, /* U+7695 [2000] */ + {0xe79a96, 0xe1a8}, /* U+7696 */ + {0xe79a99, 0xe1aa}, /* U+7699 */ + {0xe79a9a, 0xe1ab}, /* U+769A */ + {0xe79a9b, 0xecdf}, /* U+769B [2000] */ + {0xe79a9c, 0xf68f}, /* U+769C [2000] */ + {0xe79a9d, 0xece0}, /* U+769D [2000] */ + {0xe79a9e, 0xece1}, /* U+769E [2000] */ + {0xe79aa0, 0xf691}, /* U+76A0 [2000] */ + {0xe79aa1, 0xf690}, /* U+76A1 [2000] */ + {0xe79aa6, 0xece2}, /* U+76A6 [2000] */ + {0xe79aa7, 0xf692}, /* U+76A7 [2000] */ + {0xe79aa8, 0xf693}, /* U+76A8 [2000] */ + {0xe79aaa, 0xece3}, /* U+76AA [2000] */ + {0xe79aae, 0x94e7}, /* U+76AE */ + {0xe79aaf, 0xf694}, /* U+76AF [2000] */ + {0xe79ab0, 0xe1ac}, /* U+76B0 */ + {0xe79ab4, 0xe1ad}, /* U+76B4 */ + {0xe79ab6, 0xece4}, /* U+76B6 [2000] */ + {0xe79ab7, 0xea89}, /* U+76B7 */ + {0xe79ab8, 0xe1ae}, /* U+76B8 */ + {0xe79ab9, 0xe1af}, /* U+76B9 */ + {0xe79aba, 0xe1b0}, /* U+76BA */ + {0xe79abf, 0x8e4d}, /* U+76BF */ + {0xe79b82, 0xe1b1}, /* U+76C2 */ + {0xe79b83, 0x9475}, /* U+76C3 */ + {0xe79b85, 0xece5}, /* U+76C5 [2000] */ + {0xe79b86, 0x967e}, /* U+76C6 */ + {0xe79b88, 0x896d}, /* U+76C8 */ + {0xe79b89, 0xf696}, /* U+76C9 [2000] */ + {0xe79b8a, 0x8976}, /* U+76CA */ + {0xe79b8c, 0xece6}, /* U+76CC [2000] */ + {0xe79b8d, 0xe1b2}, /* U+76CD */ + {0xe79b8e, 0xece7}, /* U+76CE [2000] */ + {0xe79b92, 0xe1b4}, /* U+76D2 */ + {0xe79b94, 0xece8}, /* U+76D4 [2000] */ + {0xe79b96, 0xe1b3}, /* U+76D6 */ + {0xe79b97, 0x9390}, /* U+76D7 */ + {0xe79b9b, 0x90b7}, /* U+76DB */ + {0xe79b9c, 0x9f58}, /* U+76DC */ + {0xe79b9e, 0xe1b5}, /* U+76DE */ + {0xe79b9f, 0x96bf}, /* U+76DF */ + {0xe79ba1, 0xe1b6}, /* U+76E1 */ + {0xe79ba3, 0x8ac4}, /* U+76E3 */ + {0xe79ba4, 0x94d5}, /* U+76E4 */ + {0xe79ba5, 0xe1b7}, /* U+76E5 */ + {0xe79ba6, 0xece9}, /* U+76E6 [2000] */ + {0xe79ba7, 0xe1b8}, /* U+76E7 */ + {0xe79ba8, 0xf698}, /* U+76E8 [2000] */ + {0xe79baa, 0xe1b9}, /* U+76EA */ + {0xe79bac, 0xf699}, /* U+76EC [2000] */ + {0xe79bae, 0x96da}, /* U+76EE */ + {0xe79bb1, 0xecea}, /* U+76F1 [2000] */ + {0xe79bb2, 0x96d3}, /* U+76F2 */ + {0xe79bb4, 0x92bc}, /* U+76F4 */ + {0xe79bb8, 0x918a}, /* U+76F8 */ + {0xe79bbb, 0xe1bb}, /* U+76FB */ + {0xe79bbc, 0xeceb}, /* U+76FC [2000] */ + {0xe79bbe, 0x8f82}, /* U+76FE */ + {0xe79c81, 0x8fc8}, /* U+7701 */ + {0xe79c84, 0xe1be}, /* U+7704 */ + {0xe79c87, 0xe1bd}, /* U+7707 */ + {0xe79c88, 0xe1bc}, /* U+7708 */ + {0xe79c89, 0x94fb}, /* U+7709 */ + {0xe79c8a, 0xecec}, /* U+770A [2000] */ + {0xe79c8b, 0x8ac5}, /* U+770B */ + {0xe79c8c, 0x8ca7}, /* U+770C */ + {0xe79c97, 0xf69b}, /* U+7717 [2000] */ + {0xe79c99, 0xeced}, /* U+7719 [2000] */ + {0xe79c9a, 0xf69c}, /* U+771A [2000] */ + {0xe79c9b, 0xe1c4}, /* U+771B */ + {0xe79c9e, 0xe1c1}, /* U+771E */ + {0xe79c9f, 0x905e}, /* U+771F */ + {0xe79ca0, 0x96b0}, /* U+7720 */ + {0xe79ca4, 0xe1c0}, /* U+7724 */ + {0xe79ca5, 0xe1c2}, /* U+7725 */ + {0xe79ca6, 0xe1c3}, /* U+7726 */ + {0xe79ca9, 0xe1bf}, /* U+7729 */ + {0xe79cad, 0xf69d}, /* U+772D [2000] */ + {0xe79cb4, 0xecee}, /* U+7734 [2000] */ + {0xe79cb5, 0xf69e}, /* U+7735 [2000] */ + {0xe79cb6, 0xecef}, /* U+7736 [2000] */ + {0xe79cb7, 0xe1c5}, /* U+7737 */ + {0xe79cb8, 0xe1c6}, /* U+7738 */ + {0xe79cba, 0x92ad}, /* U+773A */ + {0xe79cbc, 0x8ae1}, /* U+773C */ + {0xe79d80, 0x9285}, /* U+7740 */ + {0xe79d86, 0xecf0}, /* U+7746 [2000] */ + {0xe79d87, 0xe1c7}, /* U+7747 */ + {0xe79d8d, 0xecf1}, /* U+774D [2000] */ + {0xe79d8e, 0xecf2}, /* U+774E [2000] */ + {0xe79d98, 0xf6a3}, /* U+7758 [2000] */ + {0xe79d9a, 0xe1c8}, /* U+775A */ + {0xe79d9b, 0xe1cb}, /* U+775B */ + {0xe79d9c, 0xecf3}, /* U+775C [2000] */ + {0xe79d9f, 0xecf4}, /* U+775F [2000] */ + {0xe79da0, 0xf6a4}, /* U+7760 [2000] */ + {0xe79da1, 0x9087}, /* U+7761 */ + {0xe79da2, 0xecf5}, /* U+7762 [2000] */ + {0xe79da3, 0x93c2}, /* U+7763 */ + {0xe79da5, 0xe1cc}, /* U+7765 */ + {0xe79da6, 0x9672}, /* U+7766 */ + {0xe79da8, 0xe1c9}, /* U+7768 */ + {0xe79daa, 0xf6a5}, /* U+776A [2000] */ + {0xe79dab, 0xe1ca}, /* U+776B */ + {0xe79db2, 0xf6a7}, /* U+7772 [2000] */ + {0xe79db9, 0xe1cf}, /* U+7779 */ + {0xe79dba, 0xecf6}, /* U+777A [2000] */ + {0xe79dbc, 0xf6a8}, /* U+777C [2000] */ + {0xe79dbd, 0xf6a9}, /* U+777D [2000] */ + {0xe79dbe, 0xe1ce}, /* U+777E */ + {0xe79dbf, 0xe1cd}, /* U+777F */ + {0xe79e80, 0xecf7}, /* U+7780 [2000] */ + {0xe79e8b, 0xe1d1}, /* U+778B */ + {0xe79e8e, 0xe1d0}, /* U+778E */ + {0xe79e91, 0xe1d2}, /* U+7791 */ + {0xe79e94, 0xecf8}, /* U+7794 [2000] */ + {0xe79e9a, 0xf6ac}, /* U+779A [2000] */ + {0xe79e9e, 0xe1d4}, /* U+779E */ + {0xe79e9f, 0xf6ad}, /* U+779F [2000] */ + {0xe79ea0, 0xe1d3}, /* U+77A0 */ + {0xe79ea2, 0xf6ae}, /* U+77A2 [2000] */ + {0xe79ea4, 0xf6af}, /* U+77A4 [2000] */ + {0xe79ea5, 0x95cb}, /* U+77A5 */ + {0xe79ea9, 0xf6b0}, /* U+77A9 [2000] */ + {0xe79eaa, 0xecf9}, /* U+77AA [2000] */ + {0xe79eac, 0x8f75}, /* U+77AC */ + {0xe79ead, 0x97c4}, /* U+77AD */ + {0xe79eb0, 0xe1d5}, /* U+77B0 */ + {0xe79eb3, 0x93b5}, /* U+77B3 */ + {0xe79eb6, 0xe1d6}, /* U+77B6 */ + {0xe79eb9, 0xe1d7}, /* U+77B9 */ + {0xe79ebb, 0xe1db}, /* U+77BB */ + {0xe79ebc, 0xe1d9}, /* U+77BC */ + {0xe79ebd, 0xe1da}, /* U+77BD */ + {0xe79ebf, 0xe1d8}, /* U+77BF */ + {0xe79f87, 0xe1dc}, /* U+77C7 */ + {0xe79f8d, 0xe1dd}, /* U+77CD */ + {0xe79f97, 0xe1de}, /* U+77D7 */ + {0xe79f9a, 0xe1df}, /* U+77DA */ + {0xe79f9b, 0x96b5}, /* U+77DB */ + {0xe79f9c, 0xe1e0}, /* U+77DC */ + {0xe79f9e, 0xf6b1}, /* U+77DE [2000] */ + {0xe79f9f, 0xf6b2}, /* U+77DF [2000] */ + {0xe79fa0, 0xecfa}, /* U+77E0 [2000] */ + {0xe79fa2, 0x96ee}, /* U+77E2 */ + {0xe79fa3, 0xe1e1}, /* U+77E3 */ + {0xe79fa4, 0xf6b3}, /* U+77E4 [2000] */ + {0xe79fa5, 0x926d}, /* U+77E5 */ + {0xe79fa6, 0xf6b4}, /* U+77E6 [2000] */ + {0xe79fa7, 0x948a}, /* U+77E7 */ + {0xe79fa9, 0x8be9}, /* U+77E9 */ + {0xe79faa, 0xf6b5}, /* U+77EA [2000] */ + {0xe79fac, 0xf6b6}, /* U+77EC [2000] */ + {0xe79fad, 0x925a}, /* U+77ED */ + {0xe79fae, 0xe1e2}, /* U+77EE */ + {0xe79faf, 0x8bb8}, /* U+77EF */ + {0xe79fb0, 0xf6b8}, /* U+77F0 [2000] */ + {0xe79fb3, 0x90ce}, /* U+77F3 */ + {0xe79fb4, 0xf6b9}, /* U+77F4 [2000] */ + {0xe79fbb, 0xf6ba}, /* U+77FB [2000] */ + {0xe79fbc, 0xe1e3}, /* U+77FC */ + {0xe7a082, 0x8dbb}, /* U+7802 */ + {0xe7a085, 0xf6bc}, /* U+7805 [2000] */ + {0xe7a086, 0xf6bd}, /* U+7806 [2000] */ + {0xe7a089, 0xf6be}, /* U+7809 [2000] */ + {0xe7a08c, 0xe1e4}, /* U+780C */ + {0xe7a08d, 0xf6bf}, /* U+780D [2000] */ + {0xe7a092, 0xe1e5}, /* U+7812 */ + {0xe7a094, 0x8ca4}, /* U+7814 */ + {0xe7a095, 0x8dd3}, /* U+7815 */ + {0xe7a099, 0xf6c0}, /* U+7819 [2000] */ + {0xe7a0a0, 0xe1e7}, /* U+7820 */ + {0xe7a0a1, 0xf6c1}, /* U+7821 [2000] */ + {0xe7a0a5, 0x9375}, /* U+7825 */ + {0xe7a0a6, 0x8dd4}, /* U+7826 */ + {0xe7a0a7, 0x8b6d}, /* U+7827 */ + {0xe7a0ac, 0xf6c2}, /* U+782C [2000] */ + {0xe7a0ad, 0xecfb}, /* U+782D [2000] */ + {0xe7a0b2, 0x9643}, /* U+7832 */ + {0xe7a0b4, 0x946a}, /* U+7834 */ + {0xe7a0ba, 0x9376}, /* U+783A */ + {0xe7a0bf, 0x8d7b}, /* U+783F */ + {0xe7a183, 0xed40}, /* U+7843 [2000] */ + {0xe7a185, 0xe1e9}, /* U+7845 */ + {0xe7a187, 0xf6c3}, /* U+7847 [2000] */ + {0xe7a18e, 0xed41}, /* U+784E [2000] */ + {0xe7a18f, 0xed42}, /* U+784F [2000] */ + {0xe7a191, 0xed43}, /* U+7851 [2000] */ + {0xe7a19d, 0x8fc9}, /* U+785D */ + {0xe7a1a4, 0xf6c4}, /* U+7864 [2000] */ + {0xe7a1a8, 0xed44}, /* U+7868 [2000] */ + {0xe7a1aa, 0xf6c5}, /* U+786A [2000] */ + {0xe7a1ab, 0x97b0}, /* U+786B */ + {0xe7a1ac, 0x8d64}, /* U+786C */ + {0xe7a1ae, 0xed45}, /* U+786E [2000] */ + {0xe7a1af, 0x8ca5}, /* U+786F */ + {0xe7a1b2, 0x94a1}, /* U+7872 */ + {0xe7a1b4, 0xe1eb}, /* U+7874 */ + {0xe7a1bc, 0xe1ed}, /* U+787C */ + {0xe7a281, 0x8ce9}, /* U+7881 */ + {0xe7a286, 0xe1ec}, /* U+7886 */ + {0xe7a287, 0x92f4}, /* U+7887 */ + {0xe7a28a, 0xf6c7}, /* U+788A [2000] */ + {0xe7a28c, 0xe1ef}, /* U+788C */ + {0xe7a28d, 0x8a56}, /* U+788D */ + {0xe7a28e, 0xe1ea}, /* U+788E */ + {0xe7a291, 0x94e8}, /* U+7891 */ + {0xe7a293, 0x894f}, /* U+7893 */ + {0xe7a294, 0xf6c8}, /* U+7894 [2000] */ + {0xe7a295, 0x8dea}, /* U+7895 */ + {0xe7a297, 0x9871}, /* U+7897 */ + {0xe7a29a, 0xe1ee}, /* U+789A */ + {0xe7a29d, 0xf6ca}, /* U+789D [2000] */ + {0xe7a29e, 0xf6cb}, /* U+789E [2000] */ + {0xe7a29f, 0xf6cc}, /* U+789F [2000] */ + {0xe7a2a3, 0xe1f0}, /* U+78A3 */ + {0xe7a2a4, 0xf6c9}, /* U+78A4 [2000] */ + {0xe7a2a7, 0x95c9}, /* U+78A7 */ + {0xe7a2a9, 0x90d7}, /* U+78A9 */ + {0xe7a2aa, 0xe1f2}, /* U+78AA */ + {0xe7a2ad, 0xed49}, /* U+78AD [2000] */ + {0xe7a2af, 0xe1f3}, /* U+78AF */ + {0xe7a2b0, 0xed47}, /* U+78B0 [2000] */ + {0xe7a2b5, 0xe1f1}, /* U+78B5 */ + {0xe7a2ba, 0x8a6d}, /* U+78BA */ + {0xe7a2bb, 0xf6cd}, /* U+78BB [2000] */ + {0xe7a2bc, 0xe1f9}, /* U+78BC */ + {0xe7a2be, 0xe1f8}, /* U+78BE */ + {0xe7a381, 0x8ea5}, /* U+78C1 */ + {0xe7a385, 0xe1fa}, /* U+78C5 */ + {0xe7a386, 0xe1f5}, /* U+78C6 */ + {0xe7a388, 0xf6ce}, /* U+78C8 [2000] */ + {0xe7a38a, 0xe1fb}, /* U+78CA */ + {0xe7a38b, 0xe1f6}, /* U+78CB */ + {0xe7a38c, 0xf6cf}, /* U+78CC [2000] */ + {0xe7a38e, 0xf6d0}, /* U+78CE [2000] */ + {0xe7a390, 0x94d6}, /* U+78D0 */ + {0xe7a391, 0xe1f4}, /* U+78D1 */ + {0xe7a394, 0xe1f7}, /* U+78D4 */ + {0xe7a395, 0xf6d1}, /* U+78D5 [2000] */ + {0xe7a39a, 0xe241}, /* U+78DA */ + {0xe7a3a0, 0xf6d2}, /* U+78E0 [2000] */ + {0xe7a3a1, 0xf6d3}, /* U+78E1 [2000] */ + {0xe7a3a4, 0xed4a}, /* U+78E4 [2000] */ + {0xe7a3a6, 0xf6d4}, /* U+78E6 [2000] */ + {0xe7a3a7, 0xe240}, /* U+78E7 */ + {0xe7a3a8, 0x9681}, /* U+78E8 */ + {0xe7a3ac, 0xe1fc}, /* U+78EC */ + {0xe7a3af, 0x88e9}, /* U+78EF */ + {0xe7a3b2, 0xed4b}, /* U+78F2 [2000] */ + {0xe7a3b4, 0xe243}, /* U+78F4 */ + {0xe7a3b7, 0xed4d}, /* U+78F7 [2000] */ + {0xe7a3b9, 0xf6d5}, /* U+78F9 [2000] */ + {0xe7a3ba, 0xf6d6}, /* U+78FA [2000] */ + {0xe7a3bb, 0xf6d7}, /* U+78FB [2000] */ + {0xe7a3bd, 0xe242}, /* U+78FD */ + {0xe7a3be, 0xf6d8}, /* U+78FE [2000] */ + {0xe7a480, 0xed4c}, /* U+7900 [2000] */ + {0xe7a481, 0x8fca}, /* U+7901 */ + {0xe7a487, 0xe244}, /* U+7907 */ + {0xe7a48e, 0x9162}, /* U+790E */ + {0xe7a490, 0xf6da}, /* U+7910 [2000] */ + {0xe7a491, 0xe246}, /* U+7911 */ + {0xe7a492, 0xe245}, /* U+7912 */ + {0xe7a499, 0xe247}, /* U+7919 */ + {0xe7a49b, 0xf6db}, /* U+791B [2000] */ + {0xe7a49c, 0xed4e}, /* U+791C [2000] */ + {0xe7a4a5, 0xf6dd}, /* U+7925 [2000] */ + {0xe7a4a6, 0xe1e6}, /* U+7926 */ + {0xe7a4aa, 0xe1e8}, /* U+792A */ + {0xe7a4ab, 0xe249}, /* U+792B */ + {0xe7a4ac, 0xe248}, /* U+792C */ + {0xe7a4ae, 0xed4f}, /* U+792E [2000] */ + {0xe7a4b0, 0xf6dc}, /* U+7930 [2000] */ + {0xe7a4b1, 0xed50}, /* U+7931 [2000] */ + {0xe7a4b4, 0xed51}, /* U+7934 [2000] */ + {0xe7a4ba, 0x8ea6}, /* U+793A */ + {0xe7a4bb, 0xf6de}, /* U+793B [2000] */ + {0xe7a4bc, 0x97e7}, /* U+793C */ + {0xe7a4be, 0x8ed0}, /* U+793E */ + {0xe7a580, 0xe24a}, /* U+7940 */ + {0xe7a581, 0x8c56}, /* U+7941 */ + {0xe7a585, 0xed54}, /* U+7945 [2000] */ + {0xe7a586, 0xed55}, /* U+7946 [2000] */ + {0xe7a587, 0x8b5f}, /* U+7947 */ + {0xe7a588, 0x8b46}, /* U+7948 */ + {0xe7a589, 0x8e83}, /* U+7949 */ + {0xe7a58a, 0xf6df}, /* U+794A [2000] */ + {0xe7a590, 0x9753}, /* U+7950 */ + {0xe7a593, 0xe250}, /* U+7953 */ + {0xe7a595, 0xe24f}, /* U+7955 */ + {0xe7a596, 0x9163}, /* U+7956 */ + {0xe7a597, 0xe24c}, /* U+7957 */ + {0xe7a598, 0xf6e0}, /* U+7958 [2000] */ + {0xe7a59a, 0xe24e}, /* U+795A */ + {0xe7a59b, 0xf6e1}, /* U+795B [2000] */ + {0xe7a59c, 0xed59}, /* U+795C [2000] */ + {0xe7a59d, 0x8f6a}, /* U+795D */ + {0xe7a59e, 0x905f}, /* U+795E */ + {0xe7a59f, 0xe24d}, /* U+795F */ + {0xe7a5a0, 0xe24b}, /* U+7960 */ + {0xe7a5a2, 0x9449}, /* U+7962 */ + {0xe7a5a5, 0x8fcb}, /* U+7965 */ + {0xe7a5a7, 0xf6e3}, /* U+7967 [2000] */ + {0xe7a5a8, 0x955b}, /* U+7968 */ + {0xe7a5ad, 0x8dd5}, /* U+796D */ + {0xe7a5b2, 0xf6e4}, /* U+7972 [2000] */ + {0xe7a5b7, 0x9398}, /* U+7977 */ + {0xe7a5b9, 0xed5d}, /* U+7979 [2000] */ + {0xe7a5ba, 0xe251}, /* U+797A */ + {0xe7a5bf, 0xe252}, /* U+797F */ + {0xe7a680, 0xe268}, /* U+7980 */ + {0xe7a681, 0x8bd6}, /* U+7981 */ + {0xe7a684, 0x985c}, /* U+7984 */ + {0xe7a685, 0x9154}, /* U+7985 */ + {0xe7a68a, 0xe253}, /* U+798A */ + {0xe7a68d, 0x89d0}, /* U+798D */ + {0xe7a68e, 0x92f5}, /* U+798E */ + {0xe7a68f, 0x959f}, /* U+798F */ + {0xe7a694, 0xf6e5}, /* U+7994 [2000] */ + {0xe7a695, 0xf6e6}, /* U+7995 [2000] */ + {0xe7a696, 0xf6e7}, /* U+7996 [2000] */ + {0xe7a698, 0xed61}, /* U+7998 [2000] */ + {0xe7a69b, 0xf6e8}, /* U+799B [2000] */ + {0xe7a69d, 0xe254}, /* U+799D */ + {0xe7a6a1, 0xf6e9}, /* U+79A1 [2000] */ + {0xe7a6a6, 0x8b9a}, /* U+79A6 */ + {0xe7a6a7, 0xe255}, /* U+79A7 */ + {0xe7a6a9, 0xf6ea}, /* U+79A9 [2000] */ + {0xe7a6aa, 0xe257}, /* U+79AA */ + {0xe7a6ae, 0xe258}, /* U+79AE */ + {0xe7a6b0, 0x9448}, /* U+79B0 */ + {0xe7a6b1, 0xed62}, /* U+79B1 [2000] */ + {0xe7a6b3, 0xe259}, /* U+79B3 */ + {0xe7a6b4, 0xf6eb}, /* U+79B4 [2000] */ + {0xe7a6b8, 0xed63}, /* U+79B8 [2000] */ + {0xe7a6b9, 0xe25a}, /* U+79B9 */ + {0xe7a6ba, 0xe25b}, /* U+79BA */ + {0xe7a6bb, 0xf6ec}, /* U+79BB [2000] */ + {0xe7a6bd, 0x8bd7}, /* U+79BD */ + {0xe7a6be, 0x89d1}, /* U+79BE */ + {0xe7a6bf, 0x93c3}, /* U+79BF */ + {0xe7a780, 0x8f47}, /* U+79C0 */ + {0xe7a781, 0x8e84}, /* U+79C1 */ + {0xe7a782, 0xf6ed}, /* U+79C2 [2000] */ + {0xe7a787, 0xf6ee}, /* U+79C7 [2000] */ + {0xe7a788, 0xed64}, /* U+79C8 [2000] */ + {0xe7a789, 0xe25c}, /* U+79C9 */ + {0xe7a78a, 0xed65}, /* U+79CA [2000] */ + {0xe7a78b, 0x8f48}, /* U+79CB */ + {0xe7a78c, 0xf6ef}, /* U+79CC [2000] */ + {0xe7a78d, 0xf6f0}, /* U+79CD [2000] */ + {0xe7a791, 0x89c8}, /* U+79D1 */ + {0xe7a792, 0x9562}, /* U+79D2 */ + {0xe7a794, 0xed67}, /* U+79D4 [2000] */ + {0xe7a795, 0xe25d}, /* U+79D5 */ + {0xe7a796, 0xf6f1}, /* U+79D6 [2000] */ + {0xe7a798, 0x94e9}, /* U+79D8 */ + {0xe7a79e, 0xed68}, /* U+79DE [2000] */ + {0xe7a79f, 0x9164}, /* U+79DF */ + {0xe7a7a1, 0xe260}, /* U+79E1 */ + {0xe7a7a3, 0xe261}, /* U+79E3 */ + {0xe7a7a4, 0x9489}, /* U+79E4 */ + {0xe7a7a6, 0x9060}, /* U+79E6 */ + {0xe7a7a7, 0xe25e}, /* U+79E7 */ + {0xe7a7a9, 0x9281}, /* U+79E9 */ + {0xe7a7ab, 0xed69}, /* U+79EB [2000] */ + {0xe7a7ac, 0xe25f}, /* U+79EC */ + {0xe7a7ad, 0xed6a}, /* U+79ED [2000] */ + {0xe7a7b0, 0x8fcc}, /* U+79F0 */ + {0xe7a7bb, 0x88da}, /* U+79FB */ + {0xe7a880, 0x8b48}, /* U+7A00 */ + {0xe7a883, 0xed6b}, /* U+7A03 [2000] */ + {0xe7a888, 0xe262}, /* U+7A08 */ + {0xe7a88a, 0xf6f6}, /* U+7A0A [2000] */ + {0xe7a88b, 0x92f6}, /* U+7A0B */ + {0xe7a88d, 0xe263}, /* U+7A0D */ + {0xe7a88e, 0x90c5}, /* U+7A0E */ + {0xe7a891, 0xf6f7}, /* U+7A11 [2000] */ + {0xe7a894, 0x96ab}, /* U+7A14 */ + {0xe7a895, 0xf6f8}, /* U+7A15 [2000] */ + {0xe7a897, 0x9542}, /* U+7A17 */ + {0xe7a898, 0xe264}, /* U+7A18 */ + {0xe7a899, 0xe265}, /* U+7A19 */ + {0xe7a89a, 0x9274}, /* U+7A1A */ + {0xe7a89b, 0xf6f9}, /* U+7A1B [2000] */ + {0xe7a89c, 0x97c5}, /* U+7A1C */ + {0xe7a89e, 0xf6fa}, /* U+7A1E [2000] */ + {0xe7a89f, 0xe267}, /* U+7A1F */ + {0xe7a8a0, 0xe266}, /* U+7A20 */ + {0xe7a8ad, 0xf6fc}, /* U+7A2D [2000] */ + {0xe7a8ae, 0x8eed}, /* U+7A2E */ + {0xe7a8b1, 0xe269}, /* U+7A31 */ + {0xe7a8b2, 0x88ee}, /* U+7A32 */ + {0xe7a8b7, 0xe26c}, /* U+7A37 */ + {0xe7a8b8, 0xf740}, /* U+7A38 [2000] */ + {0xe7a8b9, 0xed6d}, /* U+7A39 [2000] */ + {0xe7a8bb, 0xe26a}, /* U+7A3B */ + {0xe7a8bc, 0x89d2}, /* U+7A3C */ + {0xe7a8bd, 0x8c6d}, /* U+7A3D */ + {0xe7a8be, 0xe26b}, /* U+7A3E */ + {0xe7a8bf, 0x8d65}, /* U+7A3F */ + {0xe7a980, 0x8d92}, /* U+7A40 */ + {0xe7a982, 0x95e4}, /* U+7A42 */ + {0xe7a983, 0xe26d}, /* U+7A43 */ + {0xe7a986, 0x9673}, /* U+7A46 */ + {0xe7a987, 0xf741}, /* U+7A47 [2000] */ + {0xe7a989, 0xe26f}, /* U+7A49 */ + {0xe7a98c, 0xf742}, /* U+7A4C [2000] */ + {0xe7a98d, 0x90cf}, /* U+7A4D */ + {0xe7a98e, 0x896e}, /* U+7A4E */ + {0xe7a98f, 0x89b8}, /* U+7A4F */ + {0xe7a990, 0x88aa}, /* U+7A50 */ + {0xe7a996, 0xf743}, /* U+7A56 [2000] */ + {0xe7a997, 0xe26e}, /* U+7A57 */ + {0xe7a999, 0xf744}, /* U+7A59 [2000] */ + {0xe7a99c, 0xf745}, /* U+7A5C [2000] */ + {0xe7a99d, 0xed6e}, /* U+7A5D [2000] */ + {0xe7a99f, 0xf746}, /* U+7A5F [2000] */ + {0xe7a9a0, 0xf747}, /* U+7A60 [2000] */ + {0xe7a9a1, 0xe270}, /* U+7A61 */ + {0xe7a9a2, 0xe271}, /* U+7A62 */ + {0xe7a9a3, 0x8ff5}, /* U+7A63 */ + {0xe7a9a7, 0xf748}, /* U+7A67 [2000] */ + {0xe7a9a9, 0xe272}, /* U+7A69 */ + {0xe7a9aa, 0xf749}, /* U+7A6A [2000] */ + {0xe7a9ab, 0x8a6e}, /* U+7A6B */ + {0xe7a9ad, 0xed6f}, /* U+7A6D [2000] */ + {0xe7a9b0, 0xe274}, /* U+7A70 */ + {0xe7a9b4, 0x8c8a}, /* U+7A74 */ + {0xe7a9b5, 0xf74a}, /* U+7A75 [2000] */ + {0xe7a9b6, 0x8b86}, /* U+7A76 */ + {0xe7a9b8, 0xf74b}, /* U+7A78 [2000] */ + {0xe7a9b9, 0xe275}, /* U+7A79 */ + {0xe7a9ba, 0x8bf3}, /* U+7A7A */ + {0xe7a9bd, 0xe276}, /* U+7A7D */ + {0xe7a9bf, 0x90fa}, /* U+7A7F */ + {0xe7aa81, 0x93cb}, /* U+7A81 */ + {0xe7aa82, 0xf74c}, /* U+7A82 [2000] */ + {0xe7aa83, 0x90de}, /* U+7A83 */ + {0xe7aa84, 0x8df3}, /* U+7A84 */ + {0xe7aa85, 0xed71}, /* U+7A85 [2000] */ + {0xe7aa88, 0xe277}, /* U+7A88 */ + {0xe7aa8a, 0xf74d}, /* U+7A8A [2000] */ + {0xe7aa90, 0xf74e}, /* U+7A90 [2000] */ + {0xe7aa92, 0x9282}, /* U+7A92 */ + {0xe7aa93, 0x918b}, /* U+7A93 */ + {0xe7aa95, 0xe279}, /* U+7A95 */ + {0xe7aa96, 0xe27b}, /* U+7A96 */ + {0xe7aa97, 0xe278}, /* U+7A97 */ + {0xe7aa98, 0xe27a}, /* U+7A98 */ + {0xe7aa9f, 0x8c41}, /* U+7A9F */ + {0xe7aaa0, 0xed72}, /* U+7AA0 [2000] */ + {0xe7aaa3, 0xf74f}, /* U+7AA3 [2000] */ + {0xe7aaa9, 0xe27c}, /* U+7AA9 */ + {0xe7aaaa, 0x8c45}, /* U+7AAA */ + {0xe7aaac, 0xf750}, /* U+7AAC [2000] */ + {0xe7aaae, 0x8b87}, /* U+7AAE */ + {0xe7aaaf, 0x9771}, /* U+7AAF */ + {0xe7aab0, 0xe27e}, /* U+7AB0 */ + {0xe7aab3, 0xed74}, /* U+7AB3 [2000] */ + {0xe7aab6, 0xe280}, /* U+7AB6 */ + {0xe7aab9, 0xf753}, /* U+7AB9 [2000] */ + {0xe7aaba, 0x894d}, /* U+7ABA */ + {0xe7aabb, 0xed75}, /* U+7ABB [2000] */ + {0xe7aabc, 0xf754}, /* U+7ABC [2000] */ + {0xe7aabe, 0xf755}, /* U+7ABE [2000] */ + {0xe7aabf, 0xe283}, /* U+7ABF */ + {0xe7ab83, 0x8a96}, /* U+7AC3 */ + {0xe7ab84, 0xe282}, /* U+7AC4 */ + {0xe7ab85, 0xe281}, /* U+7AC5 */ + {0xe7ab87, 0xe285}, /* U+7AC7 */ + {0xe7ab88, 0xe27d}, /* U+7AC8 */ + {0xe7ab8a, 0xe286}, /* U+7ACA */ + {0xe7ab8b, 0x97a7}, /* U+7ACB */ + {0xe7ab8c, 0xf757}, /* U+7ACC [2000] */ + {0xe7ab8d, 0xe287}, /* U+7ACD */ + {0xe7ab8e, 0xed76}, /* U+7ACE [2000] */ + {0xe7ab8f, 0xe288}, /* U+7ACF */ + {0xe7ab91, 0xf758}, /* U+7AD1 [2000] */ + {0xe7ab92, 0x9af2}, /* U+7AD2 */ + {0xe7ab93, 0xe28a}, /* U+7AD3 */ + {0xe7ab95, 0xe289}, /* U+7AD5 */ + {0xe7ab99, 0xe28b}, /* U+7AD9 */ + {0xe7ab9a, 0xe28c}, /* U+7ADA */ + {0xe7ab9c, 0x97b3}, /* U+7ADC */ + {0xe7ab9d, 0xe28d}, /* U+7ADD */ + {0xe7ab9f, 0xe8ed}, /* U+7ADF */ + {0xe7aba0, 0x8fcd}, /* U+7AE0 */ + {0xe7aba1, 0xe28e}, /* U+7AE1 */ + {0xe7aba2, 0xe28f}, /* U+7AE2 */ + {0xe7aba3, 0x8f76}, /* U+7AE3 */ + {0xe7aba5, 0x93b6}, /* U+7AE5 */ + {0xe7aba6, 0xe290}, /* U+7AE6 */ + {0xe7aba7, 0xf759}, /* U+7AE7 [2000] */ + {0xe7aba8, 0xf75a}, /* U+7AE8 [2000] */ + {0xe7abaa, 0x9247}, /* U+7AEA */ + {0xe7abab, 0xed77}, /* U+7AEB [2000] */ + {0xe7abad, 0xe291}, /* U+7AED */ + {0xe7abaf, 0x925b}, /* U+7AEF */ + {0xe7abb0, 0xe292}, /* U+7AF0 */ + {0xe7abb4, 0xf75b}, /* U+7AF4 [2000] */ + {0xe7abb6, 0x8ba3}, /* U+7AF6 */ + {0xe7abb8, 0x995e}, /* U+7AF8 */ + {0xe7abb9, 0x927c}, /* U+7AF9 */ + {0xe7abba, 0x8eb1}, /* U+7AFA */ + {0xe7abbd, 0xed78}, /* U+7AFD [2000] */ + {0xe7abbf, 0x8ac6}, /* U+7AFF */ + {0xe7ac82, 0xe293}, /* U+7B02 */ + {0xe7ac84, 0xe2a0}, /* U+7B04 */ + {0xe7ac86, 0xe296}, /* U+7B06 */ + {0xe7ac87, 0xf75e}, /* U+7B07 [2000] */ + {0xe7ac88, 0x8b88}, /* U+7B08 */ + {0xe7ac8a, 0xe295}, /* U+7B0A */ + {0xe7ac8b, 0xe2a2}, /* U+7B0B */ + {0xe7ac8f, 0xe294}, /* U+7B0F */ + {0xe7ac91, 0x8fce}, /* U+7B11 */ + {0xe7ac92, 0xed79}, /* U+7B12 [2000] */ + {0xe7ac98, 0xe298}, /* U+7B18 */ + {0xe7ac99, 0xe299}, /* U+7B19 */ + {0xe7ac9b, 0x934a}, /* U+7B1B */ + {0xe7ac9e, 0xe29a}, /* U+7B1E */ + {0xe7aca0, 0x8a7d}, /* U+7B20 */ + {0xe7aca5, 0x9079}, /* U+7B25 */ + {0xe7aca6, 0x9584}, /* U+7B26 */ + {0xe7aca7, 0xf761}, /* U+7B27 [2000] */ + {0xe7aca8, 0xe29c}, /* U+7B28 */ + {0xe7acaa, 0xf762}, /* U+7B2A [2000] */ + {0xe7acac, 0x91e6}, /* U+7B2C */ + {0xe7acad, 0xed7a}, /* U+7B2D [2000] */ + {0xe7acae, 0xf763}, /* U+7B2E [2000] */ + {0xe7acaf, 0xf764}, /* U+7B2F [2000] */ + {0xe7acb1, 0xf765}, /* U+7B31 [2000] */ + {0xe7acb3, 0xe297}, /* U+7B33 */ + {0xe7acb5, 0xe29b}, /* U+7B35 */ + {0xe7acb6, 0xe29d}, /* U+7B36 */ + {0xe7acb9, 0x8df9}, /* U+7B39 */ + {0xe7acbb, 0xed7b}, /* U+7B3B [2000] */ + {0xe7acbd, 0xf760}, /* U+7B3D [2000] */ + {0xe7ad81, 0xf769}, /* U+7B41 [2000] */ + {0xe7ad85, 0xe2a4}, /* U+7B45 */ + {0xe7ad86, 0x954d}, /* U+7B46 */ + {0xe7ad87, 0xed7c}, /* U+7B47 [2000] */ + {0xe7ad88, 0x94a4}, /* U+7B48 */ + {0xe7ad89, 0x9399}, /* U+7B49 */ + {0xe7ad8b, 0x8bd8}, /* U+7B4B */ + {0xe7ad8c, 0xe2a3}, /* U+7B4C */ + {0xe7ad8d, 0xe2a1}, /* U+7B4D */ + {0xe7ad8e, 0xed7d}, /* U+7B4E [2000] */ + {0xe7ad8f, 0x94b3}, /* U+7B4F */ + {0xe7ad90, 0xe29e}, /* U+7B50 */ + {0xe7ad91, 0x927d}, /* U+7B51 */ + {0xe7ad92, 0x939b}, /* U+7B52 */ + {0xe7ad94, 0x939a}, /* U+7B54 */ + {0xe7ad95, 0xf76b}, /* U+7B55 [2000] */ + {0xe7ad96, 0x8df4}, /* U+7B56 */ + {0xe7ad9d, 0xe2b6}, /* U+7B5D */ + {0xe7ada0, 0xed7e}, /* U+7B60 [2000] */ + {0xe7ada4, 0xf76d}, /* U+7B64 [2000] */ + {0xe7ada5, 0xe2a6}, /* U+7B65 */ + {0xe7ada6, 0xf76e}, /* U+7B66 [2000] */ + {0xe7ada7, 0xe2a8}, /* U+7B67 */ + {0xe7ada9, 0xf76f}, /* U+7B69 [2000] */ + {0xe7adac, 0xe2ab}, /* U+7B6C */ + {0xe7adad, 0xed80}, /* U+7B6D [2000] */ + {0xe7adae, 0xe2ac}, /* U+7B6E */ + {0xe7adaf, 0xed81}, /* U+7B6F [2000] */ + {0xe7adb0, 0xe2a9}, /* U+7B70 */ + {0xe7adb1, 0xe2aa}, /* U+7B71 */ + {0xe7adb2, 0xed82}, /* U+7B72 [2000] */ + {0xe7adb3, 0xf770}, /* U+7B73 [2000] */ + {0xe7adb4, 0xe2a7}, /* U+7B74 */ + {0xe7adb5, 0xe2a5}, /* U+7B75 */ + {0xe7adb9, 0xf76c}, /* U+7B79 [2000] */ + {0xe7adba, 0xe29f}, /* U+7B7A */ + {0xe7adbf, 0xf768}, /* U+7B7F [2000] */ + {0xe7ae86, 0x95cd}, /* U+7B86 */ + {0xe7ae87, 0x89d3}, /* U+7B87 */ + {0xe7ae8b, 0xe2b3}, /* U+7B8B */ + {0xe7ae8d, 0xe2b0}, /* U+7B8D */ + {0xe7ae8f, 0xe2b5}, /* U+7B8F */ + {0xe7ae90, 0xf773}, /* U+7B90 [2000] */ + {0xe7ae91, 0xf774}, /* U+7B91 [2000] */ + {0xe7ae92, 0xe2b4}, /* U+7B92 */ + {0xe7ae94, 0x9493}, /* U+7B94 */ + {0xe7ae95, 0x96a5}, /* U+7B95 */ + {0xe7ae97, 0x8e5a}, /* U+7B97 */ + {0xe7ae98, 0xe2ae}, /* U+7B98 */ + {0xe7ae99, 0xe2b7}, /* U+7B99 */ + {0xe7ae9a, 0xe2b2}, /* U+7B9A */ + {0xe7ae9b, 0xf775}, /* U+7B9B [2000] */ + {0xe7ae9c, 0xe2b1}, /* U+7B9C */ + {0xe7ae9d, 0xe2ad}, /* U+7B9D */ + {0xe7ae9e, 0xed83}, /* U+7B9E [2000] */ + {0xe7ae9f, 0xe2af}, /* U+7B9F */ + {0xe7aea1, 0x8ac7}, /* U+7BA1 */ + {0xe7aeaa, 0x925c}, /* U+7BAA */ + {0xe7aead, 0x90fb}, /* U+7BAD */ + {0xe7aeaf, 0xf777}, /* U+7BAF [2000] */ + {0xe7aeb1, 0x94a0}, /* U+7BB1 */ + {0xe7aeb4, 0xe2bc}, /* U+7BB4 */ + {0xe7aeb5, 0xf778}, /* U+7BB5 [2000] */ + {0xe7aeb8, 0x94a2}, /* U+7BB8 */ + {0xe7aebc, 0xf779}, /* U+7BBC [2000] */ + {0xe7af80, 0x90df}, /* U+7BC0 */ + {0xe7af81, 0xe2b9}, /* U+7BC1 */ + {0xe7af84, 0x94cd}, /* U+7BC4 */ + {0xe7af85, 0xf77a}, /* U+7BC5 [2000] */ + {0xe7af86, 0xe2bd}, /* U+7BC6 */ + {0xe7af87, 0x95d1}, /* U+7BC7 */ + {0xe7af89, 0x927a}, /* U+7BC9 */ + {0xe7af8a, 0xf77b}, /* U+7BCA [2000] */ + {0xe7af8b, 0xe2b8}, /* U+7BCB */ + {0xe7af8c, 0xe2ba}, /* U+7BCC */ + {0xe7af8f, 0xe2bb}, /* U+7BCF */ + {0xe7af94, 0xf77e}, /* U+7BD4 [2000] */ + {0xe7af96, 0xf780}, /* U+7BD6 [2000] */ + {0xe7af97, 0xed85}, /* U+7BD7 [2000] */ + {0xe7af99, 0xed86}, /* U+7BD9 [2000] */ + {0xe7af9a, 0xf781}, /* U+7BDA [2000] */ + {0xe7af9d, 0xe2be}, /* U+7BDD */ + {0xe7afa0, 0x8ec2}, /* U+7BE0 */ + {0xe7afa4, 0x93c4}, /* U+7BE4 */ + {0xe7afa5, 0xe2c3}, /* U+7BE5 */ + {0xe7afa6, 0xe2c2}, /* U+7BE6 */ + {0xe7afa9, 0xe2bf}, /* U+7BE9 */ + {0xe7afaa, 0xf782}, /* U+7BEA [2000] */ + {0xe7afad, 0x9855}, /* U+7BED */ + {0xe7afb0, 0xf783}, /* U+7BF0 [2000] */ + {0xe7afb3, 0xe2c8}, /* U+7BF3 */ + {0xe7afb6, 0xe2cc}, /* U+7BF6 */ + {0xe7afb7, 0xe2c9}, /* U+7BF7 */ + {0xe7b080, 0xe2c5}, /* U+7C00 */ + {0xe7b081, 0xed87}, /* U+7C01 [2000] */ + {0xe7b083, 0xf784}, /* U+7C03 [2000] */ + {0xe7b087, 0xe2c6}, /* U+7C07 */ + {0xe7b08b, 0xf785}, /* U+7C0B [2000] */ + {0xe7b08d, 0xe2cb}, /* U+7C0D */ + {0xe7b08e, 0xf786}, /* U+7C0E [2000] */ + {0xe7b08f, 0xf787}, /* U+7C0F [2000] */ + {0xe7b091, 0xe2c0}, /* U+7C11 */ + {0xe7b092, 0x99d3}, /* U+7C12 */ + {0xe7b093, 0xe2c7}, /* U+7C13 */ + {0xe7b094, 0xe2c1}, /* U+7C14 */ + {0xe7b097, 0xe2ca}, /* U+7C17 */ + {0xe7b09e, 0xed89}, /* U+7C1E [2000] */ + {0xe7b09f, 0xe2d0}, /* U+7C1F */ + {0xe7b0a0, 0xed8a}, /* U+7C20 [2000] */ + {0xe7b0a1, 0x8ac8}, /* U+7C21 */ + {0xe7b0a3, 0xe2cd}, /* U+7C23 */ + {0xe7b0a6, 0xf788}, /* U+7C26 [2000] */ + {0xe7b0a7, 0xe2ce}, /* U+7C27 */ + {0xe7b0aa, 0xe2cf}, /* U+7C2A */ + {0xe7b0ab, 0xe2d2}, /* U+7C2B */ + {0xe7b0b1, 0xed88}, /* U+7C31 [2000] */ + {0xe7b0b3, 0xed8b}, /* U+7C33 [2000] */ + {0xe7b0b6, 0xed8c}, /* U+7C36 [2000] */ + {0xe7b0b7, 0xe2d1}, /* U+7C37 */ + {0xe7b0b8, 0x94f4}, /* U+7C38 */ + {0xe7b0bd, 0xe2d3}, /* U+7C3D */ + {0xe7b0be, 0x97fa}, /* U+7C3E */ + {0xe7b0bf, 0x95eb}, /* U+7C3F */ + {0xe7b180, 0xe2d8}, /* U+7C40 */ + {0xe7b183, 0xe2d5}, /* U+7C43 */ + {0xe7b185, 0xf789}, /* U+7C45 [2000] */ + {0xe7b18a, 0xf78a}, /* U+7C4A [2000] */ + {0xe7b18c, 0xe2d4}, /* U+7C4C */ + {0xe7b18d, 0x90d0}, /* U+7C4D */ + {0xe7b18f, 0xe2d7}, /* U+7C4F */ + {0xe7b190, 0xe2d9}, /* U+7C50 */ + {0xe7b191, 0xf78b}, /* U+7C51 [2000] */ + {0xe7b194, 0xe2d6}, /* U+7C54 */ + {0xe7b196, 0xe2dd}, /* U+7C56 */ + {0xe7b197, 0xf78c}, /* U+7C57 [2000] */ + {0xe7b198, 0xe2da}, /* U+7C58 */ + {0xe7b199, 0xed8f}, /* U+7C59 [2000] */ + {0xe7b19e, 0xf78d}, /* U+7C5E [2000] */ + {0xe7b19f, 0xe2db}, /* U+7C5F */ + {0xe7b1a0, 0xe2c4}, /* U+7C60 */ + {0xe7b1a1, 0xf78e}, /* U+7C61 [2000] */ + {0xe7b1a4, 0xe2dc}, /* U+7C64 */ + {0xe7b1a5, 0xe2de}, /* U+7C65 */ + {0xe7b1a9, 0xf78f}, /* U+7C69 [2000] */ + {0xe7b1ac, 0xe2df}, /* U+7C6C */ + {0xe7b1ad, 0xed90}, /* U+7C6D [2000] */ + {0xe7b1ae, 0xf790}, /* U+7C6E [2000] */ + {0xe7b1af, 0xf791}, /* U+7C6F [2000] */ + {0xe7b1b0, 0xf792}, /* U+7C70 [2000] */ + {0xe7b1b3, 0x95c4}, /* U+7C73 */ + {0xe7b1b5, 0xe2e0}, /* U+7C75 */ + {0xe7b1b9, 0xed91}, /* U+7C79 [2000] */ + {0xe7b1be, 0x96e0}, /* U+7C7E */ + {0xe7b281, 0x8bcc}, /* U+7C81 */ + {0xe7b282, 0x8c48}, /* U+7C82 */ + {0xe7b283, 0xe2e1}, /* U+7C83 */ + {0xe7b289, 0x95b2}, /* U+7C89 */ + {0xe7b28b, 0x9088}, /* U+7C8B */ + {0xe7b28d, 0x96ae}, /* U+7C8D */ + {0xe7b28f, 0xed92}, /* U+7C8F [2000] */ + {0xe7b290, 0xe2e2}, /* U+7C90 */ + {0xe7b292, 0x97b1}, /* U+7C92 */ + {0xe7b294, 0xed93}, /* U+7C94 [2000] */ + {0xe7b295, 0x9494}, /* U+7C95 */ + {0xe7b297, 0x9165}, /* U+7C97 */ + {0xe7b298, 0x9453}, /* U+7C98 */ + {0xe7b29b, 0x8f6c}, /* U+7C9B */ + {0xe7b29f, 0x88be}, /* U+7C9F */ + {0xe7b2a0, 0xed94}, /* U+7CA0 [2000] */ + {0xe7b2a1, 0xe2e7}, /* U+7CA1 */ + {0xe7b2a2, 0xe2e5}, /* U+7CA2 */ + {0xe7b2a4, 0xe2e3}, /* U+7CA4 */ + {0xe7b2a5, 0x8a9f}, /* U+7CA5 */ + {0xe7b2a6, 0xf796}, /* U+7CA6 [2000] */ + {0xe7b2a7, 0x8fcf}, /* U+7CA7 */ + {0xe7b2a8, 0xe2e8}, /* U+7CA8 */ + {0xe7b2ab, 0xe2e6}, /* U+7CAB */ + {0xe7b2ad, 0xe2e4}, /* U+7CAD */ + {0xe7b2ae, 0xe2ec}, /* U+7CAE */ + {0xe7b2b1, 0xe2eb}, /* U+7CB1 */ + {0xe7b2b2, 0xe2ea}, /* U+7CB2 */ + {0xe7b2b3, 0xe2e9}, /* U+7CB3 */ + {0xe7b2b6, 0xf798}, /* U+7CB6 [2000] */ + {0xe7b2b7, 0xf799}, /* U+7CB7 [2000] */ + {0xe7b2b9, 0xe2ed}, /* U+7CB9 */ + {0xe7b2bc, 0xed95}, /* U+7CBC [2000] */ + {0xe7b2bd, 0xe2ee}, /* U+7CBD */ + {0xe7b2be, 0x90b8}, /* U+7CBE */ + {0xe7b2bf, 0xf79a}, /* U+7CBF [2000] */ + {0xe7b380, 0xe2ef}, /* U+7CC0 */ + {0xe7b382, 0xe2f1}, /* U+7CC2 */ + {0xe7b384, 0xf79c}, /* U+7CC4 [2000] */ + {0xe7b385, 0xe2f0}, /* U+7CC5 */ + {0xe7b388, 0xf79e}, /* U+7CC8 [2000] */ + {0xe7b38a, 0x8cd0}, /* U+7CCA */ + {0xe7b38d, 0xf79f}, /* U+7CCD [2000] */ + {0xe7b38e, 0x9157}, /* U+7CCE */ + {0xe7b392, 0xe2f3}, /* U+7CD2 */ + {0xe7b395, 0xed96}, /* U+7CD5 [2000] */ + {0xe7b396, 0x939c}, /* U+7CD6 */ + {0xe7b397, 0xf7a1}, /* U+7CD7 [2000] */ + {0xe7b398, 0xe2f2}, /* U+7CD8 */ + {0xe7b399, 0xed97}, /* U+7CD9 [2000] */ + {0xe7b39c, 0xe2f4}, /* U+7CDC */ + {0xe7b39d, 0xed98}, /* U+7CDD [2000] */ + {0xe7b39e, 0x95b3}, /* U+7CDE */ + {0xe7b39f, 0x918c}, /* U+7CDF */ + {0xe7b3a0, 0x8d66}, /* U+7CE0 */ + {0xe7b3a2, 0xe2f5}, /* U+7CE2 */ + {0xe7b3a6, 0xf7a3}, /* U+7CE6 [2000] */ + {0xe7b3a7, 0x97c6}, /* U+7CE7 */ + {0xe7b3ab, 0xf7a4}, /* U+7CEB [2000] */ + {0xe7b3af, 0xe2f7}, /* U+7CEF */ + {0xe7b3b2, 0xe2f8}, /* U+7CF2 */ + {0xe7b3b4, 0xe2f9}, /* U+7CF4 */ + {0xe7b3b5, 0xf7a6}, /* U+7CF5 [2000] */ + {0xe7b3b6, 0xe2fa}, /* U+7CF6 */ + {0xe7b3b8, 0x8e85}, /* U+7CF8 */ + {0xe7b3ba, 0xe2fb}, /* U+7CFA */ + {0xe7b3bb, 0x8c6e}, /* U+7CFB */ + {0xe7b3be, 0x8b8a}, /* U+7CFE */ + {0xe7b480, 0x8b49}, /* U+7D00 */ + {0xe7b482, 0xe340}, /* U+7D02 */ + {0xe7b483, 0xf7a7}, /* U+7D03 [2000] */ + {0xe7b484, 0x96f1}, /* U+7D04 */ + {0xe7b485, 0x8d67}, /* U+7D05 */ + {0xe7b486, 0xe2fc}, /* U+7D06 */ + {0xe7b487, 0xed99}, /* U+7D07 [2000] */ + {0xe7b488, 0xed9a}, /* U+7D08 [2000] */ + {0xe7b489, 0xf7a8}, /* U+7D09 [2000] */ + {0xe7b48a, 0xe343}, /* U+7D0A */ + {0xe7b48b, 0x96e4}, /* U+7D0B */ + {0xe7b48d, 0x945b}, /* U+7D0D */ + {0xe7b490, 0x9552}, /* U+7D10 */ + {0xe7b492, 0xf7aa}, /* U+7D12 [2000] */ + {0xe7b493, 0xed9b}, /* U+7D13 [2000] */ + {0xe7b494, 0x8f83}, /* U+7D14 */ + {0xe7b495, 0xe342}, /* U+7D15 */ + {0xe7b497, 0x8ed1}, /* U+7D17 */ + {0xe7b498, 0x8d68}, /* U+7D18 */ + {0xe7b499, 0x8e86}, /* U+7D19 */ + {0xe7b49a, 0x8b89}, /* U+7D1A */ + {0xe7b49b, 0x95b4}, /* U+7D1B */ + {0xe7b49c, 0xe341}, /* U+7D1C */ + {0xe7b49d, 0xed9c}, /* U+7D1D [2000] */ + {0xe7b49e, 0xf7ab}, /* U+7D1E [2000] */ + {0xe7b4a0, 0x9166}, /* U+7D20 */ + {0xe7b4a1, 0x9661}, /* U+7D21 */ + {0xe7b4a2, 0x8df5}, /* U+7D22 */ + {0xe7b4a3, 0xed9d}, /* U+7D23 [2000] */ + {0xe7b4ab, 0x8e87}, /* U+7D2B */ + {0xe7b4ac, 0x92db}, /* U+7D2C */ + {0xe7b4ae, 0xe346}, /* U+7D2E */ + {0xe7b4af, 0x97dd}, /* U+7D2F */ + {0xe7b4b0, 0x8dd7}, /* U+7D30 */ + {0xe7b4b1, 0xed9e}, /* U+7D31 [2000] */ + {0xe7b4b2, 0xe347}, /* U+7D32 */ + {0xe7b4b3, 0x9061}, /* U+7D33 */ + {0xe7b4b5, 0xe349}, /* U+7D35 */ + {0xe7b4b9, 0x8fd0}, /* U+7D39 */ + {0xe7b4ba, 0x8dae}, /* U+7D3A */ + {0xe7b4bd, 0xf7ae}, /* U+7D3D [2000] */ + {0xe7b4be, 0xf7af}, /* U+7D3E [2000] */ + {0xe7b4bf, 0xe348}, /* U+7D3F */ + {0xe7b580, 0xf7b0}, /* U+7D40 [2000] */ + {0xe7b581, 0xed9f}, /* U+7D41 [2000] */ + {0xe7b582, 0x8f49}, /* U+7D42 */ + {0xe7b583, 0x8cbc}, /* U+7D43 */ + {0xe7b584, 0x9167}, /* U+7D44 */ + {0xe7b585, 0xe344}, /* U+7D45 */ + {0xe7b586, 0xe34a}, /* U+7D46 */ + {0xe7b587, 0xf7b1}, /* U+7D47 [2000] */ + {0xe7b588, 0xeda0}, /* U+7D48 [2000] */ + {0xe7b58b, 0xe345}, /* U+7D4B */ + {0xe7b58c, 0x8c6f}, /* U+7D4C */ + {0xe7b58e, 0xe34d}, /* U+7D4E */ + {0xe7b58f, 0xe351}, /* U+7D4F */ + {0xe7b590, 0x8c8b}, /* U+7D50 */ + {0xe7b593, 0xeda1}, /* U+7D53 [2000] */ + {0xe7b596, 0xe34c}, /* U+7D56 */ + {0xe7b599, 0xf7b5}, /* U+7D59 [2000] */ + {0xe7b59a, 0xf7b6}, /* U+7D5A [2000] */ + {0xe7b59b, 0xe355}, /* U+7D5B */ + {0xe7b59c, 0xeda2}, /* U+7D5C [2000] */ + {0xe7b59e, 0x8d69}, /* U+7D5E */ + {0xe7b5a1, 0x978d}, /* U+7D61 */ + {0xe7b5a2, 0x88ba}, /* U+7D62 */ + {0xe7b5a3, 0xe352}, /* U+7D63 */ + {0xe7b5a6, 0x8b8b}, /* U+7D66 */ + {0xe7b5a8, 0xe34f}, /* U+7D68 */ + {0xe7b5aa, 0xf7b7}, /* U+7D6A [2000] */ + {0xe7b5ae, 0xe350}, /* U+7D6E */ + {0xe7b5b0, 0xf7b8}, /* U+7D70 [2000] */ + {0xe7b5b1, 0x939d}, /* U+7D71 */ + {0xe7b5b2, 0xe34e}, /* U+7D72 */ + {0xe7b5b3, 0xe34b}, /* U+7D73 */ + {0xe7b5b5, 0x8a47}, /* U+7D75 */ + {0xe7b5b6, 0x90e2}, /* U+7D76 */ + {0xe7b5b9, 0x8ca6}, /* U+7D79 */ + {0xe7b5ba, 0xeda3}, /* U+7D7A [2000] */ + {0xe7b5bd, 0xe357}, /* U+7D7D */ + {0xe7b5bf, 0xf7ba}, /* U+7D7F [2000] */ + {0xe7b683, 0xeda4}, /* U+7D83 [2000] */ + {0xe7b686, 0xf7bc}, /* U+7D86 [2000] */ + {0xe7b688, 0xf7bd}, /* U+7D88 [2000] */ + {0xe7b689, 0xe354}, /* U+7D89 */ + {0xe7b68b, 0xeda5}, /* U+7D8B [2000] */ + {0xe7b68c, 0xf7be}, /* U+7D8C [2000] */ + {0xe7b68f, 0xe356}, /* U+7D8F */ + {0xe7b693, 0xe353}, /* U+7D93 */ + {0xe7b697, 0xf7bf}, /* U+7D97 [2000] */ + {0xe7b699, 0x8c70}, /* U+7D99 */ + {0xe7b69a, 0x91b1}, /* U+7D9A */ + {0xe7b69b, 0xe358}, /* U+7D9B */ + {0xe7b69c, 0x918e}, /* U+7D9C */ + {0xe7b69d, 0xf7c1}, /* U+7D9D [2000] */ + {0xe7b69f, 0xe365}, /* U+7D9F */ + {0xe7b6a0, 0xeda6}, /* U+7DA0 [2000] */ + {0xe7b6a2, 0xe361}, /* U+7DA2 */ + {0xe7b6a3, 0xe35b}, /* U+7DA3 */ + {0xe7b6a6, 0xeda7}, /* U+7DA6 [2000] */ + {0xe7b6a7, 0xf7c2}, /* U+7DA7 [2000] */ + {0xe7b6aa, 0xf7c3}, /* U+7DAA [2000] */ + {0xe7b6ab, 0xe35f}, /* U+7DAB */ + {0xe7b6ac, 0x8ef8}, /* U+7DAC */ + {0xe7b6ad, 0x88db}, /* U+7DAD */ + {0xe7b6ae, 0xe35a}, /* U+7DAE */ + {0xe7b6af, 0xe362}, /* U+7DAF */ + {0xe7b6b0, 0xe366}, /* U+7DB0 */ + {0xe7b6b1, 0x8d6a}, /* U+7DB1 */ + {0xe7b6b2, 0x96d4}, /* U+7DB2 */ + {0xe7b6b4, 0x92d4}, /* U+7DB4 */ + {0xe7b6b5, 0xe35c}, /* U+7DB5 */ + {0xe7b6b6, 0xf7c4}, /* U+7DB6 [2000] */ + {0xe7b6b7, 0xf7c5}, /* U+7DB7 [2000] */ + {0xe7b6b8, 0xe364}, /* U+7DB8 */ + {0xe7b6ba, 0xe359}, /* U+7DBA */ + {0xe7b6bb, 0x925d}, /* U+7DBB */ + {0xe7b6bd, 0xe35e}, /* U+7DBD */ + {0xe7b6be, 0x88bb}, /* U+7DBE */ + {0xe7b6bf, 0x96c8}, /* U+7DBF */ + {0xe7b780, 0xf7c6}, /* U+7DC0 [2000] */ + {0xe7b782, 0xeda8}, /* U+7DC2 [2000] */ + {0xe7b787, 0xe35d}, /* U+7DC7 */ + {0xe7b78a, 0x8bd9}, /* U+7DCA */ + {0xe7b78b, 0x94ea}, /* U+7DCB */ + {0xe7b78c, 0xeda9}, /* U+7DCC [2000] */ + {0xe7b78f, 0x918d}, /* U+7DCF */ + {0xe7b791, 0x97ce}, /* U+7DD1 */ + {0xe7b792, 0x8f8f}, /* U+7DD2 */ + {0xe7b795, 0xe38e}, /* U+7DD5 */ + {0xe7b796, 0xedaa}, /* U+7DD6 [2000] */ + {0xe7b797, 0xf7c7}, /* U+7DD7 [2000] */ + {0xe7b798, 0xe367}, /* U+7DD8 */ + {0xe7b799, 0xf7c8}, /* U+7DD9 [2000] */ + {0xe7b79a, 0x90fc}, /* U+7DDA */ + {0xe7b79c, 0xe363}, /* U+7DDC */ + {0xe7b79d, 0xe368}, /* U+7DDD */ + {0xe7b79e, 0xe36a}, /* U+7DDE */ + {0xe7b7a0, 0x92f7}, /* U+7DE0 */ + {0xe7b7a1, 0xe36d}, /* U+7DE1 */ + {0xe7b7a3, 0xedab}, /* U+7DE3 [2000] */ + {0xe7b7a4, 0xe369}, /* U+7DE4 */ + {0xe7b7a6, 0xf7c9}, /* U+7DE6 [2000] */ + {0xe7b7a8, 0x95d2}, /* U+7DE8 */ + {0xe7b7a9, 0x8ac9}, /* U+7DE9 */ + {0xe7b7ac, 0x96c9}, /* U+7DEC */ + {0xe7b7af, 0x88dc}, /* U+7DEF */ + {0xe7b7b1, 0xf7ca}, /* U+7DF1 [2000] */ + {0xe7b7b2, 0xe36c}, /* U+7DF2 */ + {0xe7b7b4, 0x97fb}, /* U+7DF4 */ + {0xe7b7b9, 0xf7cb}, /* U+7DF9 [2000] */ + {0xe7b7bb, 0xe36b}, /* U+7DFB */ + {0xe7b881, 0x898f}, /* U+7E01 */ + {0xe7b884, 0x93ea}, /* U+7E04 */ + {0xe7b885, 0xe36e}, /* U+7E05 */ + {0xe7b888, 0xedae}, /* U+7E08 [2000] */ + {0xe7b889, 0xe375}, /* U+7E09 */ + {0xe7b88a, 0xe36f}, /* U+7E0A */ + {0xe7b88b, 0xe376}, /* U+7E0B */ + {0xe7b890, 0xf7cf}, /* U+7E10 [2000] */ + {0xe7b891, 0xedaf}, /* U+7E11 [2000] */ + {0xe7b892, 0xe372}, /* U+7E12 */ + {0xe7b895, 0xedb0}, /* U+7E15 [2000] */ + {0xe7b897, 0xf7d0}, /* U+7E17 [2000] */ + {0xe7b89b, 0x949b}, /* U+7E1B */ + {0xe7b89d, 0xf7d1}, /* U+7E1D [2000] */ + {0xe7b89e, 0x8ec8}, /* U+7E1E */ + {0xe7b89f, 0xe374}, /* U+7E1F */ + {0xe7b8a0, 0xf7d2}, /* U+7E20 [2000] */ + {0xe7b8a1, 0xe371}, /* U+7E21 */ + {0xe7b8a2, 0xe377}, /* U+7E22 */ + {0xe7b8a3, 0xe370}, /* U+7E23 */ + {0xe7b8a6, 0x8f63}, /* U+7E26 */ + {0xe7b8a7, 0xf7d3}, /* U+7E27 [2000] */ + {0xe7b8a8, 0xedad}, /* U+7E28 [2000] */ + {0xe7b8ab, 0x9644}, /* U+7E2B */ + {0xe7b8ac, 0xf7d4}, /* U+7E2C [2000] */ + {0xe7b8ae, 0x8f6b}, /* U+7E2E */ + {0xe7b8b1, 0xe373}, /* U+7E31 */ + {0xe7b8b2, 0xe380}, /* U+7E32 */ + {0xe7b8b5, 0xe37b}, /* U+7E35 */ + {0xe7b8b7, 0xe37e}, /* U+7E37 */ + {0xe7b8b9, 0xe37c}, /* U+7E39 */ + {0xe7b8ba, 0xe381}, /* U+7E3A */ + {0xe7b8bb, 0xe37a}, /* U+7E3B */ + {0xe7b8bd, 0xe360}, /* U+7E3D */ + {0xe7b8be, 0x90d1}, /* U+7E3E */ + {0xe7b981, 0x94c9}, /* U+7E41 */ + {0xe7b983, 0xe37d}, /* U+7E43 */ + {0xe7b985, 0xf7d5}, /* U+7E45 [2000] */ + {0xe7b986, 0xe378}, /* U+7E46 */ + {0xe7b987, 0xedb2}, /* U+7E47 [2000] */ + {0xe7b98a, 0x9140}, /* U+7E4A */ + {0xe7b98b, 0x8c71}, /* U+7E4B */ + {0xe7b98d, 0x8f4a}, /* U+7E4D */ + {0xe7b992, 0xedb3}, /* U+7E52 [2000] */ + {0xe7b994, 0x9044}, /* U+7E54 */ + {0xe7b995, 0x9155}, /* U+7E55 */ + {0xe7b996, 0xe384}, /* U+7E56 */ + {0xe7b999, 0xe386}, /* U+7E59 */ + {0xe7b99a, 0xe387}, /* U+7E5A */ + {0xe7b99d, 0xe383}, /* U+7E5D */ + {0xe7b99e, 0xe385}, /* U+7E5E */ + {0xe7b9a1, 0xedb4}, /* U+7E61 [2000] */ + {0xe7b9a6, 0xe379}, /* U+7E66 */ + {0xe7b9a7, 0xe382}, /* U+7E67 */ + {0xe7b9a9, 0xe38a}, /* U+7E69 */ + {0xe7b9aa, 0xe389}, /* U+7E6A */ + {0xe7b9ab, 0xeffc}, /* U+7E6B [2004] */ + {0xe7b9ad, 0x969a}, /* U+7E6D */ + {0xe7b9b0, 0x8c4a}, /* U+7E70 */ + {0xe7b9b3, 0xf7d6}, /* U+7E73 [2000] */ + {0xe7b9b5, 0xf7d7}, /* U+7E75 [2000] */ + {0xe7b9b9, 0xe388}, /* U+7E79 */ + {0xe7b9bb, 0xe38c}, /* U+7E7B */ + {0xe7b9bc, 0xe38b}, /* U+7E7C */ + {0xe7b9bd, 0xe38f}, /* U+7E7D */ + {0xe7b9be, 0xf7d8}, /* U+7E7E [2000] */ + {0xe7b9bf, 0xe391}, /* U+7E7F */ + {0xe7ba82, 0x8e5b}, /* U+7E82 */ + {0xe7ba83, 0xe38d}, /* U+7E83 */ + {0xe7ba86, 0xf7d9}, /* U+7E86 [2000] */ + {0xe7ba87, 0xf7da}, /* U+7E87 [2000] */ + {0xe7ba88, 0xe392}, /* U+7E88 */ + {0xe7ba89, 0xe393}, /* U+7E89 */ + {0xe7ba8a, 0xedb5}, /* U+7E8A [2000] */ + {0xe7ba8c, 0xe394}, /* U+7E8C */ + {0xe7ba8d, 0xedb6}, /* U+7E8D [2000] */ + {0xe7ba8e, 0xe39a}, /* U+7E8E */ + {0xe7ba8f, 0x935a}, /* U+7E8F */ + {0xe7ba90, 0xe396}, /* U+7E90 */ + {0xe7ba91, 0xf7dc}, /* U+7E91 [2000] */ + {0xe7ba92, 0xe395}, /* U+7E92 */ + {0xe7ba93, 0xe397}, /* U+7E93 */ + {0xe7ba94, 0xe398}, /* U+7E94 */ + {0xe7ba96, 0xe399}, /* U+7E96 */ + {0xe7ba98, 0xf7dd}, /* U+7E98 [2000] */ + {0xe7ba9a, 0xf7de}, /* U+7E9A [2000] */ + {0xe7ba9b, 0xe39b}, /* U+7E9B */ + {0xe7ba9c, 0xe39c}, /* U+7E9C */ + {0xe7bcb6, 0x8aca}, /* U+7F36 */ + {0xe7bcb8, 0xe39d}, /* U+7F38 */ + {0xe7bcba, 0xe39e}, /* U+7F3A */ + {0xe7bcbb, 0xf7e1}, /* U+7F3B [2000] */ + {0xe7bcbc, 0xf7e0}, /* U+7F3C [2000] */ + {0xe7bcbe, 0xf7e2}, /* U+7F3E [2000] */ + {0xe7bd83, 0xf7e3}, /* U+7F43 [2000] */ + {0xe7bd84, 0xf7e4}, /* U+7F44 [2000] */ + {0xe7bd85, 0xe39f}, /* U+7F45 */ + {0xe7bd87, 0xedb7}, /* U+7F47 [2000] */ + {0xe7bd8c, 0xe3a0}, /* U+7F4C */ + {0xe7bd8d, 0xe3a1}, /* U+7F4D */ + {0xe7bd8e, 0xe3a2}, /* U+7F4E */ + {0xe7bd8f, 0xf7e5}, /* U+7F4F [2000] */ + {0xe7bd90, 0xe3a3}, /* U+7F50 */ + {0xe7bd91, 0xe3a4}, /* U+7F51 */ + {0xe7bd92, 0xf7e8}, /* U+7F52 [2000] */ + {0xe7bd94, 0xe3a6}, /* U+7F54 */ + {0xe7bd95, 0xe3a5}, /* U+7F55 */ + {0xe7bd98, 0xe3a7}, /* U+7F58 */ + {0xe7bd9f, 0xe3a8}, /* U+7F5F */ + {0xe7bda0, 0xe3a9}, /* U+7F60 */ + {0xe7bda1, 0xf7ea}, /* U+7F61 [2000] */ + {0xe7bda3, 0xf7eb}, /* U+7F63 [2000] */ + {0xe7bda4, 0xf7ec}, /* U+7F64 [2000] */ + {0xe7bda7, 0xe3ac}, /* U+7F67 */ + {0xe7bda8, 0xe3aa}, /* U+7F68 */ + {0xe7bda9, 0xe3ab}, /* U+7F69 */ + {0xe7bdaa, 0x8ddf}, /* U+7F6A */ + {0xe7bdab, 0x8c72}, /* U+7F6B */ + {0xe7bdad, 0xf7ed}, /* U+7F6D [2000] */ + {0xe7bdae, 0x9275}, /* U+7F6E */ + {0xe7bdb0, 0x94b1}, /* U+7F70 */ + {0xe7bdb2, 0x8f90}, /* U+7F72 */ + {0xe7bdb5, 0x946c}, /* U+7F75 */ + {0xe7bdb7, 0x94eb}, /* U+7F77 */ + {0xe7bdb8, 0xe3ad}, /* U+7F78 */ + {0xe7bdb9, 0x9ceb}, /* U+7F79 */ + {0xe7bdbd, 0xf7ee}, /* U+7F7D [2000] */ + {0xe7bdbe, 0xf7ef}, /* U+7F7E [2000] */ + {0xe7be82, 0xe3ae}, /* U+7F82 */ + {0xe7be83, 0xe3b0}, /* U+7F83 */ + {0xe7be85, 0x9785}, /* U+7F85 */ + {0xe7be86, 0xe3af}, /* U+7F86 */ + {0xe7be87, 0xe3b2}, /* U+7F87 */ + {0xe7be88, 0xe3b1}, /* U+7F88 */ + {0xe7be8a, 0x9772}, /* U+7F8A */ + {0xe7be8c, 0xe3b3}, /* U+7F8C */ + {0xe7be8e, 0x94fc}, /* U+7F8E */ + {0xe7be90, 0xf7f1}, /* U+7F90 [2000] */ + {0xe7be91, 0xedb9}, /* U+7F91 [2000] */ + {0xe7be94, 0xe3b4}, /* U+7F94 */ + {0xe7be96, 0xf7f4}, /* U+7F96 [2000] */ + {0xe7be97, 0xedba}, /* U+7F97 [2000] */ + {0xe7be9a, 0xe3b7}, /* U+7F9A */ + {0xe7be9c, 0xf7f5}, /* U+7F9C [2000] */ + {0xe7be9d, 0xe3b6}, /* U+7F9D */ + {0xe7be9e, 0xe3b5}, /* U+7F9E */ + {0xe7bea3, 0xe3b8}, /* U+7FA3 */ + {0xe7bea4, 0x8c51}, /* U+7FA4 */ + {0xe7bea8, 0x9141}, /* U+7FA8 */ + {0xe7bea9, 0x8b60}, /* U+7FA9 */ + {0xe7bead, 0xf7f6}, /* U+7FAD [2000] */ + {0xe7beae, 0xe3bc}, /* U+7FAE */ + {0xe7beaf, 0xe3b9}, /* U+7FAF */ + {0xe7beb2, 0xe3ba}, /* U+7FB2 */ + {0xe7beb6, 0xe3bd}, /* U+7FB6 */ + {0xe7beb8, 0xe3be}, /* U+7FB8 */ + {0xe7beb9, 0xe3bb}, /* U+7FB9 */ + {0xe7bebd, 0x8948}, /* U+7FBD */ + {0xe7bebf, 0xedbb}, /* U+7FBF [2000] */ + {0xe7bf81, 0x89a5}, /* U+7FC1 */ + {0xe7bf83, 0xf7f8}, /* U+7FC3 [2000] */ + {0xe7bf85, 0xe3c0}, /* U+7FC5 */ + {0xe7bf86, 0xe3c1}, /* U+7FC6 */ + {0xe7bf8a, 0xe3c2}, /* U+7FCA */ + {0xe7bf8c, 0x9782}, /* U+7FCC */ + {0xe7bf8e, 0xedbc}, /* U+7FCE [2000] */ + {0xe7bf8f, 0xf7f9}, /* U+7FCF [2000] */ + {0xe7bf92, 0x8f4b}, /* U+7FD2 */ + {0xe7bf94, 0xe3c4}, /* U+7FD4 */ + {0xe7bf95, 0xe3c3}, /* U+7FD5 */ + {0xe7bf9b, 0xedbd}, /* U+7FDB [2000] */ + {0xe7bf9f, 0xedbe}, /* U+7FDF [2000] */ + {0xe7bfa0, 0x9089}, /* U+7FE0 */ + {0xe7bfa1, 0xe3c5}, /* U+7FE1 */ + {0xe7bfa3, 0xf7fa}, /* U+7FE3 [2000] */ + {0xe7bfa5, 0xf7fb}, /* U+7FE5 [2000] */ + {0xe7bfa6, 0xe3c6}, /* U+7FE6 */ + {0xe7bfa9, 0xe3c7}, /* U+7FE9 */ + {0xe7bfab, 0x8ae3}, /* U+7FEB */ + {0xe7bfac, 0xedbf}, /* U+7FEC [2000] */ + {0xe7bfae, 0xedc0}, /* U+7FEE [2000] */ + {0xe7bfaf, 0xf7fc}, /* U+7FEF [2000] */ + {0xe7bfb0, 0x8acb}, /* U+7FF0 */ + {0xe7bfb2, 0xf840}, /* U+7FF2 [2000] */ + {0xe7bfb3, 0xe3c8}, /* U+7FF3 */ + {0xe7bfb9, 0xe3c9}, /* U+7FF9 */ + {0xe7bfba, 0xedc1}, /* U+7FFA [2000] */ + {0xe7bfbb, 0x967c}, /* U+7FFB */ + {0xe7bfbc, 0x9783}, /* U+7FFC */ + {0xe88080, 0x9773}, /* U+8000 */ + {0xe88081, 0x9856}, /* U+8001 */ + {0xe88082, 0xf841}, /* U+8002 [2000] */ + {0xe88083, 0x8d6c}, /* U+8003 */ + {0xe88084, 0xe3cc}, /* U+8004 */ + {0xe88085, 0x8ed2}, /* U+8005 */ + {0xe88086, 0xe3cb}, /* U+8006 */ + {0xe88088, 0xf843}, /* U+8008 [2000] */ + {0xe8808a, 0xf842}, /* U+800A [2000] */ + {0xe8808b, 0xe3cd}, /* U+800B */ + {0xe8808c, 0x8ea7}, /* U+800C */ + {0xe8808e, 0xf844}, /* U+800E [2000] */ + {0xe88090, 0x91cf}, /* U+8010 */ + {0xe88091, 0xf845}, /* U+8011 [2000] */ + {0xe88092, 0xe3ce}, /* U+8012 */ + {0xe88094, 0xedc3}, /* U+8014 [2000] */ + {0xe88095, 0x8d6b}, /* U+8015 */ + {0xe88096, 0xf846}, /* U+8016 [2000] */ + {0xe88097, 0x96d5}, /* U+8017 */ + {0xe88098, 0xe3cf}, /* U+8018 */ + {0xe88099, 0xe3d0}, /* U+8019 */ + {0xe8809c, 0xe3d1}, /* U+801C */ + {0xe880a1, 0xe3d2}, /* U+8021 */ + {0xe880a4, 0xf847}, /* U+8024 [2000] */ + {0xe880a6, 0xedc4}, /* U+8026 [2000] */ + {0xe880a8, 0xe3d3}, /* U+8028 */ + {0xe880ac, 0xf848}, /* U+802C [2000] */ + {0xe880b0, 0xf849}, /* U+8030 [2000] */ + {0xe880b3, 0x8ea8}, /* U+8033 */ + {0xe880b5, 0xedc5}, /* U+8035 [2000] */ + {0xe880b6, 0x96eb}, /* U+8036 */ + {0xe880b7, 0xedc6}, /* U+8037 [2000] */ + {0xe880bb, 0xe3d5}, /* U+803B */ + {0xe880bc, 0xedc7}, /* U+803C [2000] */ + {0xe880bd, 0x925e}, /* U+803D */ + {0xe880bf, 0xe3d4}, /* U+803F */ + {0xe88183, 0xf84a}, /* U+8043 [2000] */ + {0xe88186, 0xe3d7}, /* U+8046 */ + {0xe8818a, 0xe3d6}, /* U+804A */ + {0xe88192, 0xe3d8}, /* U+8052 */ + {0xe88196, 0x90b9}, /* U+8056 */ + {0xe88198, 0xe3d9}, /* U+8058 */ + {0xe8819a, 0xe3da}, /* U+805A */ + {0xe8819e, 0x95b7}, /* U+805E */ + {0xe8819f, 0xe3db}, /* U+805F */ + {0xe881a1, 0x918f}, /* U+8061 */ + {0xe881a2, 0xe3dc}, /* U+8062 */ + {0xe881a6, 0xf84b}, /* U+8066 [2000] */ + {0xe881a8, 0xe3dd}, /* U+8068 */ + {0xe881af, 0x97fc}, /* U+806F */ + {0xe881b0, 0xe3e0}, /* U+8070 */ + {0xe881b1, 0xf84c}, /* U+8071 [2000] */ + {0xe881b2, 0xe3df}, /* U+8072 */ + {0xe881b3, 0xe3de}, /* U+8073 */ + {0xe881b4, 0x92ae}, /* U+8074 */ + {0xe881b5, 0xf84d}, /* U+8075 [2000] */ + {0xe881b6, 0xe3e1}, /* U+8076 */ + {0xe881b7, 0x9045}, /* U+8077 */ + {0xe881b9, 0xe3e2}, /* U+8079 */ + {0xe881bb, 0xf84e}, /* U+807B [2000] */ + {0xe881bd, 0xe3e3}, /* U+807D */ + {0xe881be, 0x9857}, /* U+807E */ + {0xe881bf, 0xe3e4}, /* U+807F */ + {0xe88284, 0xe3e5}, /* U+8084 */ + {0xe88285, 0xe3e7}, /* U+8085 */ + {0xe88286, 0xe3e6}, /* U+8086 */ + {0xe88287, 0x94a3}, /* U+8087 */ + {0xe88289, 0x93f7}, /* U+8089 */ + {0xe8828b, 0x985d}, /* U+808B */ + {0xe8828c, 0x94a7}, /* U+808C */ + {0xe88293, 0xe3e9}, /* U+8093 */ + {0xe88296, 0x8fd1}, /* U+8096 */ + {0xe88298, 0x9549}, /* U+8098 */ + {0xe88299, 0xf84f}, /* U+8099 [2000] */ + {0xe8829a, 0xe3ea}, /* U+809A */ + {0xe8829b, 0xe3e8}, /* U+809B */ + {0xe8829c, 0xf850}, /* U+809C [2000] */ + {0xe8829d, 0x8acc}, /* U+809D */ + {0xe882a1, 0x8cd2}, /* U+80A1 */ + {0xe882a2, 0x8e88}, /* U+80A2 */ + {0xe882a4, 0xf851}, /* U+80A4 [2000] */ + {0xe882a5, 0x94ec}, /* U+80A5 */ + {0xe882a7, 0xf852}, /* U+80A7 [2000] */ + {0xe882a9, 0x8ca8}, /* U+80A9 */ + {0xe882aa, 0x9662}, /* U+80AA */ + {0xe882ac, 0xe3ed}, /* U+80AC */ + {0xe882ad, 0xe3eb}, /* U+80AD */ + {0xe882af, 0x8d6d}, /* U+80AF */ + {0xe882b1, 0x8d6e}, /* U+80B1 */ + {0xe882b2, 0x88e7}, /* U+80B2 */ + {0xe882b4, 0x8de6}, /* U+80B4 */ + {0xe882b8, 0xf853}, /* U+80B8 [2000] */ + {0xe882ba, 0x9478}, /* U+80BA */ + {0xe88383, 0x88dd}, /* U+80C3 */ + {0xe88384, 0xe3f2}, /* U+80C4 */ + {0xe88385, 0xf855}, /* U+80C5 [2000] */ + {0xe88386, 0x925f}, /* U+80C6 */ + {0xe8838a, 0xedc8}, /* U+80CA [2000] */ + {0xe8838c, 0x9477}, /* U+80CC */ + {0xe8838e, 0x91d9}, /* U+80CE */ + {0xe88395, 0xf856}, /* U+80D5 [2000] */ + {0xe88396, 0xe3f4}, /* U+80D6 */ + {0xe88397, 0xedc9}, /* U+80D7 [2000] */ + {0xe88398, 0xf857}, /* U+80D8 [2000] */ + {0xe88399, 0xe3f0}, /* U+80D9 */ + {0xe8839a, 0xe3f3}, /* U+80DA */ + {0xe8839b, 0xe3ee}, /* U+80DB */ + {0xe8839d, 0xe3f1}, /* U+80DD */ + {0xe8839e, 0x9645}, /* U+80DE */ + {0xe883a0, 0xedca}, /* U+80E0 [2000] */ + {0xe883a1, 0x8cd3}, /* U+80E1 */ + {0xe883a4, 0x88fb}, /* U+80E4 */ + {0xe883a5, 0xe3ef}, /* U+80E5 */ + {0xe883a6, 0xf858}, /* U+80E6 [2000] */ + {0xe883af, 0xe3f6}, /* U+80EF */ + {0xe883b1, 0xe3f7}, /* U+80F1 */ + {0xe883b3, 0xedcb}, /* U+80F3 [2000] */ + {0xe883b4, 0x93b7}, /* U+80F4 */ + {0xe883b5, 0xf85b}, /* U+80F5 [2000] */ + {0xe883b8, 0x8bb9}, /* U+80F8 */ + {0xe883bb, 0xf85c}, /* U+80FB [2000] */ + {0xe883bc, 0xe445}, /* U+80FC */ + {0xe883bd, 0x945c}, /* U+80FD */ + {0xe88482, 0x8e89}, /* U+8102 */ + {0xe88485, 0x8bba}, /* U+8105 */ + {0xe88486, 0x90c6}, /* U+8106 */ + {0xe88487, 0x9865}, /* U+8107 */ + {0xe88488, 0x96ac}, /* U+8108 */ + {0xe88489, 0xe3f5}, /* U+8109 */ + {0xe8848a, 0x90d2}, /* U+810A */ + {0xe8848d, 0xf85a}, /* U+810D [2000] */ + {0xe88496, 0xf85f}, /* U+8116 [2000] */ + {0xe88498, 0xedcc}, /* U+8118 [2000] */ + {0xe8849a, 0x8b72}, /* U+811A */ + {0xe8849b, 0xe3f8}, /* U+811B */ + {0xe8849e, 0xf860}, /* U+811E [2000] */ + {0xe884a3, 0xe3fa}, /* U+8123 */ + {0xe884a4, 0xf862}, /* U+8124 [2000] */ + {0xe884a7, 0xf863}, /* U+8127 [2000] */ + {0xe884a9, 0xe3f9}, /* U+8129 */ + {0xe884ac, 0xf864}, /* U+812C [2000] */ + {0xe884af, 0xe3fb}, /* U+812F */ + {0xe884b1, 0x9245}, /* U+8131 */ + {0xe884b3, 0x945d}, /* U+8133 */ + {0xe884b5, 0xf85e}, /* U+8135 [2000] */ + {0xe884b9, 0x92af}, /* U+8139 */ + {0xe884bd, 0xf866}, /* U+813D [2000] */ + {0xe884be, 0xe442}, /* U+813E */ + {0xe88586, 0xe441}, /* U+8146 */ + {0xe8858a, 0xedcd}, /* U+814A [2000] */ + {0xe8858b, 0xe3fc}, /* U+814B */ + {0xe8858e, 0x9074}, /* U+814E */ + {0xe88590, 0x9585}, /* U+8150 */ + {0xe88591, 0xe444}, /* U+8151 */ + {0xe88593, 0xe443}, /* U+8153 */ + {0xe88594, 0x8d6f}, /* U+8154 */ + {0xe88595, 0x9872}, /* U+8155 */ + {0xe8859f, 0xe454}, /* U+815F */ + {0xe885a0, 0xedce}, /* U+8160 [2000] */ + {0xe885a5, 0xe448}, /* U+8165 */ + {0xe885a6, 0xe449}, /* U+8166 */ + {0xe885a7, 0xedcf}, /* U+8167 [2000] */ + {0xe885a8, 0xedd0}, /* U+8168 [2000] */ + {0xe885a9, 0xf868}, /* U+8169 [2000] */ + {0xe885ab, 0x8eee}, /* U+816B */ + {0xe885ad, 0xedd1}, /* U+816D [2000] */ + {0xe885ae, 0xe447}, /* U+816E */ + {0xe885b0, 0x8d98}, /* U+8170 */ + {0xe885b1, 0xe446}, /* U+8171 */ + {0xe885b4, 0xe44a}, /* U+8174 */ + {0xe885b8, 0x92b0}, /* U+8178 */ + {0xe885b9, 0x95a0}, /* U+8179 */ + {0xe885ba, 0x9142}, /* U+817A */ + {0xe885bf, 0x91da}, /* U+817F */ + {0xe88680, 0xe44e}, /* U+8180 */ + {0xe88681, 0xf86a}, /* U+8181 [2000] */ + {0xe88682, 0xe44f}, /* U+8182 */ + {0xe88683, 0xe44b}, /* U+8183 */ + {0xe88684, 0xf86c}, /* U+8184 [2000] */ + {0xe88685, 0xf86d}, /* U+8185 [2000] */ + {0xe88688, 0xe44c}, /* U+8188 */ + {0xe8868a, 0xe44d}, /* U+818A */ + {0xe8868f, 0x8d70}, /* U+818F */ + {0xe88693, 0xe455}, /* U+8193 */ + {0xe88695, 0xe451}, /* U+8195 */ + {0xe88698, 0xf86f}, /* U+8198 [2000] */ + {0xe8869a, 0x9586}, /* U+819A */ + {0xe8869c, 0x968c}, /* U+819C */ + {0xe8869d, 0x9547}, /* U+819D */ + {0xe886a0, 0xe450}, /* U+81A0 */ + {0xe886a3, 0xe453}, /* U+81A3 */ + {0xe886a4, 0xe452}, /* U+81A4 */ + {0xe886a8, 0x9663}, /* U+81A8 */ + {0xe886a9, 0xe456}, /* U+81A9 */ + {0xe886b0, 0xe457}, /* U+81B0 */ + {0xe886b2, 0xf870}, /* U+81B2 [2000] */ + {0xe886b3, 0x9156}, /* U+81B3 */ + {0xe886b5, 0xe458}, /* U+81B5 */ + {0xe886b8, 0xe45a}, /* U+81B8 */ + {0xe886ba, 0xe45e}, /* U+81BA */ + {0xe886bb, 0xedd2}, /* U+81BB [2000] */ + {0xe886bd, 0xe45b}, /* U+81BD */ + {0xe886be, 0xe459}, /* U+81BE */ + {0xe886bf, 0x945e}, /* U+81BF */ + {0xe88780, 0xe45c}, /* U+81C0 */ + {0xe88781, 0xf871}, /* U+81C1 [2000] */ + {0xe88782, 0xe45d}, /* U+81C2 */ + {0xe88783, 0xf872}, /* U+81C3 [2000] */ + {0xe88786, 0x89b0}, /* U+81C6 */ + {0xe88788, 0xe464}, /* U+81C8 */ + {0xe88789, 0xe45f}, /* U+81C9 */ + {0xe8878a, 0xedd3}, /* U+81CA [2000] */ + {0xe8878d, 0xe460}, /* U+81CD */ + {0xe8878f, 0xedd4}, /* U+81CF [2000] */ + {0xe88791, 0xe461}, /* U+81D1 */ + {0xe88793, 0x919f}, /* U+81D3 */ + {0xe88796, 0xf873}, /* U+81D6 [2000] */ + {0xe88797, 0xedd5}, /* U+81D7 [2000] */ + {0xe88798, 0xe463}, /* U+81D8 */ + {0xe88799, 0xe462}, /* U+81D9 */ + {0xe8879a, 0xe465}, /* U+81DA */ + {0xe8879b, 0xf874}, /* U+81DB [2000] */ + {0xe8879f, 0xe466}, /* U+81DF */ + {0xe887a0, 0xe467}, /* U+81E0 */ + {0xe887a3, 0x9062}, /* U+81E3 */ + {0xe887a4, 0xf876}, /* U+81E4 [2000] */ + {0xe887a5, 0x89e7}, /* U+81E5 */ + {0xe887a7, 0xe468}, /* U+81E7 */ + {0xe887a8, 0x97d5}, /* U+81E8 */ + {0xe887aa, 0x8ea9}, /* U+81EA */ + {0xe887ac, 0xf878}, /* U+81EC [2000] */ + {0xe887ad, 0x8f4c}, /* U+81ED */ + {0xe887b3, 0x8e8a}, /* U+81F3 */ + {0xe887b4, 0x9276}, /* U+81F4 */ + {0xe887ba, 0xe469}, /* U+81FA */ + {0xe887bb, 0xe46a}, /* U+81FB */ + {0xe887bc, 0x8950}, /* U+81FC */ + {0xe887bd, 0xf87a}, /* U+81FD [2000] */ + {0xe887be, 0xe46b}, /* U+81FE */ + {0xe887bf, 0xf87b}, /* U+81FF [2000] */ + {0xe88881, 0xe46c}, /* U+8201 */ + {0xe88882, 0xe46d}, /* U+8202 */ + {0xe88884, 0xf87d}, /* U+8204 [2000] */ + {0xe88885, 0xe46e}, /* U+8205 */ + {0xe88887, 0xe46f}, /* U+8207 */ + {0xe88888, 0x8bbb}, /* U+8208 */ + {0xe88889, 0x9da8}, /* U+8209 */ + {0xe8888a, 0xe470}, /* U+820A */ + {0xe8888c, 0x90e3}, /* U+820C */ + {0xe8888d, 0xe471}, /* U+820D */ + {0xe8888e, 0x8ec9}, /* U+820E */ + {0xe88890, 0xe472}, /* U+8210 */ + {0xe88892, 0x98ae}, /* U+8212 */ + {0xe88896, 0xe473}, /* U+8216 */ + {0xe88897, 0x95dc}, /* U+8217 */ + {0xe88898, 0x8ada}, /* U+8218 */ + {0xe88899, 0xf880}, /* U+8219 [2000] */ + {0xe8889b, 0x9143}, /* U+821B */ + {0xe8889c, 0x8f77}, /* U+821C */ + {0xe8889e, 0x9591}, /* U+821E */ + {0xe8889f, 0x8f4d}, /* U+821F */ + {0xe888a1, 0xf881}, /* U+8221 [2000] */ + {0xe888a2, 0xf882}, /* U+8222 [2000] */ + {0xe888a9, 0xe474}, /* U+8229 */ + {0xe888aa, 0x8d71}, /* U+822A */ + {0xe888ab, 0xe475}, /* U+822B */ + {0xe888ac, 0x94ca}, /* U+822C */ + {0xe888ae, 0xe484}, /* U+822E */ + {0xe888b2, 0xf884}, /* U+8232 [2000] */ + {0xe888b3, 0xe477}, /* U+8233 */ + {0xe888b4, 0xf885}, /* U+8234 [2000] */ + {0xe888b5, 0x91c7}, /* U+8235 */ + {0xe888b6, 0x9495}, /* U+8236 */ + {0xe888b7, 0x8cbd}, /* U+8237 */ + {0xe888b8, 0xe476}, /* U+8238 */ + {0xe888b9, 0x9144}, /* U+8239 */ + {0xe888bc, 0xf886}, /* U+823C [2000] */ + {0xe88980, 0xe478}, /* U+8240 */ + {0xe88985, 0xf889}, /* U+8245 [2000] */ + {0xe88986, 0xf887}, /* U+8246 [2000] */ + {0xe88987, 0x92f8}, /* U+8247 */ + {0xe88989, 0xf888}, /* U+8249 [2000] */ + {0xe8898b, 0xf88b}, /* U+824B [2000] */ + {0xe8898f, 0xf88d}, /* U+824F [2000] */ + {0xe88997, 0xf88f}, /* U+8257 [2000] */ + {0xe88998, 0xe47a}, /* U+8258 */ + {0xe88999, 0xe479}, /* U+8259 */ + {0xe8899a, 0xe47c}, /* U+825A */ + {0xe8899c, 0xf891}, /* U+825C [2000] */ + {0xe8899d, 0xe47b}, /* U+825D */ + {0xe8899f, 0xe47d}, /* U+825F */ + {0xe889a0, 0xedd9}, /* U+8260 [2000] */ + {0xe889a2, 0xe480}, /* U+8262 */ + {0xe889a3, 0xf892}, /* U+8263 [2000] */ + {0xe889a4, 0xe47e}, /* U+8264 */ + {0xe889a6, 0x8acd}, /* U+8266 */ + {0xe889a8, 0xe481}, /* U+8268 */ + {0xe889aa, 0xe482}, /* U+826A */ + {0xe889ab, 0xe483}, /* U+826B */ + {0xe889ae, 0x8daf}, /* U+826E */ + {0xe889af, 0x97c7}, /* U+826F */ + {0xe889b1, 0xe485}, /* U+8271 */ + {0xe889b2, 0x9046}, /* U+8272 */ + {0xe889b4, 0xedda}, /* U+8274 [2000] */ + {0xe889b6, 0x8990}, /* U+8276 */ + {0xe889b7, 0xe486}, /* U+8277 */ + {0xe889b8, 0xe487}, /* U+8278 */ + {0xe889b9, 0xf896}, /* U+8279 [2000] */ + {0xe889bd, 0xf898}, /* U+827D [2000] */ + {0xe889be, 0xe488}, /* U+827E */ + {0xe889bf, 0xf899}, /* U+827F [2000] */ + {0xe88a83, 0xf89a}, /* U+8283 [2000] */ + {0xe88a8a, 0xf89b}, /* U+828A [2000] */ + {0xe88a8b, 0x88f0}, /* U+828B */ + {0xe88a8d, 0xe489}, /* U+828D */ + {0xe88a8e, 0xeddc}, /* U+828E [2000] */ + {0xe88a92, 0xe48a}, /* U+8292 */ + {0xe88a93, 0xf89c}, /* U+8293 [2000] */ + {0xe88a99, 0x9587}, /* U+8299 */ + {0xe88a9d, 0x8ec5}, /* U+829D */ + {0xe88a9f, 0xe48c}, /* U+829F */ + {0xe88aa1, 0xeddd}, /* U+82A1 [2000] */ + {0xe88aa3, 0xedde}, /* U+82A3 [2000] */ + {0xe88aa4, 0xeddf}, /* U+82A4 [2000] */ + {0xe88aa5, 0x8a48}, /* U+82A5 */ + {0xe88aa6, 0x88b0}, /* U+82A6 */ + {0xe88aa7, 0xf89d}, /* U+82A7 [2000] */ + {0xe88aa8, 0xf89e}, /* U+82A8 [2000] */ + {0xe88aa9, 0xede0}, /* U+82A9 [2000] */ + {0xe88aab, 0xe48b}, /* U+82AB */ + {0xe88aac, 0xe48e}, /* U+82AC */ + {0xe88aad, 0x946d}, /* U+82AD */ + {0xe88aae, 0xede1}, /* U+82AE [2000] */ + {0xe88aaf, 0x9063}, /* U+82AF */ + {0xe88ab1, 0x89d4}, /* U+82B1 */ + {0xe88ab2, 0xf89f}, /* U+82B2 [2000] */ + {0xe88ab3, 0x9646}, /* U+82B3 */ + {0xe88ab4, 0xf8a0}, /* U+82B4 [2000] */ + {0xe88ab7, 0xede2}, /* U+82B7 [2000] */ + {0xe88ab8, 0x8c7c}, /* U+82B8 */ + {0xe88ab9, 0x8bda}, /* U+82B9 */ + {0xe88aba, 0xf8a1}, /* U+82BA [2000] */ + {0xe88abb, 0xe48d}, /* U+82BB */ + {0xe88abc, 0xf8a2}, /* U+82BC [2000] */ + {0xe88abd, 0x89e8}, /* U+82BD */ + {0xe88abe, 0xede3}, /* U+82BE [2000] */ + {0xe88abf, 0xede4}, /* U+82BF [2000] */ + {0xe88b85, 0x8aa1}, /* U+82C5 */ + {0xe88b86, 0xede5}, /* U+82C6 [2000] */ + {0xe88b91, 0x8991}, /* U+82D1 */ + {0xe88b92, 0xe492}, /* U+82D2 */ + {0xe88b93, 0x97e8}, /* U+82D3 */ + {0xe88b94, 0x91db}, /* U+82D4 */ + {0xe88b95, 0xede6}, /* U+82D5 [2000] */ + {0xe88b97, 0x9563}, /* U+82D7 */ + {0xe88b99, 0xe49e}, /* U+82D9 */ + {0xe88b9b, 0x89d5}, /* U+82DB */ + {0xe88b9c, 0xe49c}, /* U+82DC */ + {0xe88b9e, 0xe49a}, /* U+82DE */ + {0xe88b9f, 0xe491}, /* U+82DF */ + {0xe88ba1, 0xe48f}, /* U+82E1 */ + {0xe88ba2, 0xf8a3}, /* U+82E2 [2000] */ + {0xe88ba3, 0xe490}, /* U+82E3 */ + {0xe88ba5, 0x8ee1}, /* U+82E5 */ + {0xe88ba6, 0x8bea}, /* U+82E6 */ + {0xe88ba7, 0x9297}, /* U+82E7 */ + {0xe88ba8, 0xf8a4}, /* U+82E8 [2000] */ + {0xe88bab, 0x93cf}, /* U+82EB */ + {0xe88bb1, 0x8970}, /* U+82F1 */ + {0xe88bb3, 0xe494}, /* U+82F3 */ + {0xe88bb4, 0xe493}, /* U+82F4 */ + {0xe88bb7, 0xf8a5}, /* U+82F7 [2000] */ + {0xe88bb9, 0xe499}, /* U+82F9 */ + {0xe88bba, 0xe495}, /* U+82FA */ + {0xe88bbb, 0xe498}, /* U+82FB */ + {0xe88bbd, 0xede7}, /* U+82FD [2000] */ + {0xe88bbe, 0xede8}, /* U+82FE [2000] */ + {0xe88c80, 0xede9}, /* U+8300 [2000] */ + {0xe88c81, 0xedea}, /* U+8301 [2000] */ + {0xe88c82, 0x96ce}, /* U+8302 */ + {0xe88c83, 0xe497}, /* U+8303 */ + {0xe88c84, 0x89d6}, /* U+8304 */ + {0xe88c85, 0x8a9d}, /* U+8305 */ + {0xe88c86, 0xe49b}, /* U+8306 */ + {0xe88c87, 0xf8a6}, /* U+8307 [2000] */ + {0xe88c88, 0xf8a7}, /* U+8308 [2000] */ + {0xe88c89, 0xe49d}, /* U+8309 */ + {0xe88c8c, 0xf8a8}, /* U+830C [2000] */ + {0xe88c8e, 0x8c73}, /* U+830E */ + {0xe88c96, 0xe4a1}, /* U+8316 */ + {0xe88c97, 0xe4aa}, /* U+8317 */ + {0xe88c98, 0xe4ab}, /* U+8318 */ + {0xe88c9b, 0xf8aa}, /* U+831B [2000] */ + {0xe88c9c, 0x88a9}, /* U+831C */ + {0xe88c9d, 0xf8ab}, /* U+831D [2000] */ + {0xe88ca2, 0xedec}, /* U+8322 [2000] */ + {0xe88ca3, 0xe4b2}, /* U+8323 */ + {0xe88ca8, 0x88ef}, /* U+8328 */ + {0xe88cab, 0xe4a9}, /* U+832B */ + {0xe88cad, 0xeded}, /* U+832D [2000] */ + {0xe88caf, 0xe4a8}, /* U+832F */ + {0xe88cb0, 0xf8ac}, /* U+8330 [2000] */ + {0xe88cb1, 0xe4a3}, /* U+8331 */ + {0xe88cb2, 0xe4a2}, /* U+8332 */ + {0xe88cb4, 0xe4a0}, /* U+8334 */ + {0xe88cb5, 0xe49f}, /* U+8335 */ + {0xe88cb6, 0x9283}, /* U+8336 */ + {0xe88cb8, 0x91f9}, /* U+8338 */ + {0xe88cb9, 0xe4a5}, /* U+8339 */ + {0xe88cba, 0xedee}, /* U+833A [2000] */ + {0xe88cbc, 0xf8ad}, /* U+833C [2000] */ + {0xe88d80, 0xe4a4}, /* U+8340 */ + {0xe88d83, 0xedef}, /* U+8343 [2000] */ + {0xe88d84, 0xf8ae}, /* U+8344 [2000] */ + {0xe88d85, 0xe4a7}, /* U+8345 */ + {0xe88d87, 0xedf0}, /* U+8347 [2000] */ + {0xe88d89, 0x9190}, /* U+8349 */ + {0xe88d8a, 0x8c74}, /* U+834A */ + {0xe88d8f, 0x8960}, /* U+834F */ + {0xe88d90, 0xe4a6}, /* U+8350 */ + {0xe88d91, 0xedf1}, /* U+8351 [2000] */ + {0xe88d92, 0x8d72}, /* U+8352 */ + {0xe88d94, 0xf8a9}, /* U+8354 [2000] */ + {0xe88d95, 0xedf2}, /* U+8355 [2000] */ + {0xe88d97, 0xf8af}, /* U+8357 [2000] */ + {0xe88d98, 0x9191}, /* U+8358 */ + {0xe88da2, 0xedeb}, /* U+8362 [2000] */ + {0xe88da3, 0xf3c8}, /* U+8363 [2000] */ + {0xe88db3, 0xe4b8}, /* U+8373 */ + {0xe88db5, 0xe4b9}, /* U+8375 */ + {0xe88db7, 0x89d7}, /* U+8377 */ + {0xe88dbb, 0x89ac}, /* U+837B */ + {0xe88dbc, 0xe4b6}, /* U+837C */ + {0xe88dbd, 0xedf3}, /* U+837D [2000] */ + {0xe88dbf, 0xf8b1}, /* U+837F [2000] */ + {0xe88e85, 0xe4ac}, /* U+8385 */ + {0xe88e86, 0xedf4}, /* U+8386 [2000] */ + {0xe88e87, 0xe4b4}, /* U+8387 */ + {0xe88e89, 0xe4bb}, /* U+8389 */ + {0xe88e8a, 0xe4b5}, /* U+838A */ + {0xe88e8d, 0xf8b4}, /* U+838D [2000] */ + {0xe88e8e, 0xe4b3}, /* U+838E */ + {0xe88e92, 0xedf5}, /* U+8392 [2000] */ + {0xe88e93, 0xe496}, /* U+8393 */ + {0xe88e94, 0xf8b5}, /* U+8394 [2000] */ + {0xe88e95, 0xf8b6}, /* U+8395 [2000] */ + {0xe88e96, 0xe4b1}, /* U+8396 */ + {0xe88e98, 0xedf6}, /* U+8398 [2000] */ + {0xe88e9a, 0xe4ad}, /* U+839A */ + {0xe88e9b, 0xf8b7}, /* U+839B [2000] */ + {0xe88e9d, 0xf8b8}, /* U+839D [2000] */ + {0xe88e9e, 0x8ace}, /* U+839E */ + {0xe88e9f, 0xe4af}, /* U+839F */ + {0xe88ea0, 0xe4ba}, /* U+83A0 */ + {0xe88ea2, 0xe4b0}, /* U+83A2 */ + {0xe88ea7, 0xedf7}, /* U+83A7 [2000] */ + {0xe88ea8, 0xe4bc}, /* U+83A8 */ + {0xe88ea9, 0xedf8}, /* U+83A9 [2000] */ + {0xe88eaa, 0xe4ae}, /* U+83AA */ + {0xe88eab, 0x949c}, /* U+83AB */ + {0xe88eb1, 0x9789}, /* U+83B1 */ + {0xe88eb5, 0xe4b7}, /* U+83B5 */ + {0xe88ebd, 0xe4cd}, /* U+83BD */ + {0xe88ebf, 0xedf9}, /* U+83BF [2000] */ + {0xe88f80, 0xedfa}, /* U+83C0 [2000] */ + {0xe88f81, 0xe4c5}, /* U+83C1 */ + {0xe88f85, 0x909b}, /* U+83C5 */ + {0xe88f87, 0xedfb}, /* U+83C7 [2000] */ + {0xe88f89, 0xf8b9}, /* U+83C9 [2000] */ + {0xe88f8a, 0x8b65}, /* U+83CA */ + {0xe88f8c, 0x8bdb}, /* U+83CC */ + {0xe88f8e, 0xe4c0}, /* U+83CE */ + {0xe88f8f, 0xedfc}, /* U+83CF [2000] */ + {0xe88f90, 0xf8ba}, /* U+83D0 [2000] */ + {0xe88f91, 0xee40}, /* U+83D1 [2000] */ + {0xe88f93, 0x89d9}, /* U+83D3 */ + {0xe88f94, 0xf8bb}, /* U+83D4 [2000] */ + {0xe88f96, 0x8fd2}, /* U+83D6 */ + {0xe88f98, 0xe4c3}, /* U+83D8 */ + {0xe88f9c, 0x8dd8}, /* U+83DC */ + {0xe88f9d, 0xf8bc}, /* U+83DD [2000] */ + {0xe88f9f, 0x9370}, /* U+83DF */ + {0xe88fa0, 0xe4c8}, /* U+83E0 */ + {0xe88fa1, 0xee41}, /* U+83E1 [2000] */ + {0xe88fa5, 0xf8bd}, /* U+83E5 [2000] */ + {0xe88fa9, 0x95ec}, /* U+83E9 */ + {0xe88faa, 0xee42}, /* U+83EA [2000] */ + {0xe88fab, 0xe4bf}, /* U+83EB */ + {0xe88faf, 0x89d8}, /* U+83EF */ + {0xe88fb0, 0x8cd4}, /* U+83F0 */ + {0xe88fb1, 0x9548}, /* U+83F1 */ + {0xe88fb2, 0xe4c9}, /* U+83F2 */ + {0xe88fb4, 0xe4bd}, /* U+83F4 */ + {0xe88fb7, 0xe4c6}, /* U+83F7 */ + {0xe88fb9, 0xf8be}, /* U+83F9 [2000] */ + {0xe88fbb, 0xe4d0}, /* U+83FB */ + {0xe88fbd, 0xe4c1}, /* U+83FD */ + {0xe89081, 0xee43}, /* U+8401 [2000] */ + {0xe89083, 0xe4c2}, /* U+8403 */ + {0xe89084, 0x93b8}, /* U+8404 */ + {0xe89086, 0xee44}, /* U+8406 [2000] */ + {0xe89087, 0xe4c7}, /* U+8407 */ + {0xe8908a, 0xee45}, /* U+840A [2000] */ + {0xe8908b, 0xe4c4}, /* U+840B */ + {0xe8908c, 0x9647}, /* U+840C */ + {0xe8908d, 0xe4ca}, /* U+840D */ + {0xe8908e, 0x88de}, /* U+840E */ + {0xe8908f, 0xf8bf}, /* U+840F [2000] */ + {0xe89091, 0xf8c0}, /* U+8411 [2000] */ + {0xe89093, 0xe4be}, /* U+8413 */ + {0xe89095, 0xf8c1}, /* U+8415 [2000] */ + {0xe89097, 0xf8c3}, /* U+8417 [2000] */ + {0xe890a0, 0xe4cc}, /* U+8420 */ + {0xe890a2, 0xe4cb}, /* U+8422 */ + {0xe890a9, 0x948b}, /* U+8429 */ + {0xe890aa, 0xe4d2}, /* U+842A */ + {0xe890ac, 0xe4dd}, /* U+842C */ + {0xe890b1, 0x8a9e}, /* U+8431 */ + {0xe890b5, 0xe4e0}, /* U+8435 */ + {0xe890b8, 0xe4ce}, /* U+8438 */ + {0xe890b9, 0xf8c4}, /* U+8439 [2000] */ + {0xe890bc, 0xe4d3}, /* U+843C */ + {0xe890bd, 0x978e}, /* U+843D */ + {0xe89186, 0xe4dc}, /* U+8446 */ + {0xe89188, 0xee47}, /* U+8448 [2000] */ + {0xe89189, 0x9774}, /* U+8449 */ + {0xe8918a, 0xf8c5}, /* U+844A [2000] */ + {0xe8918e, 0x97a8}, /* U+844E */ + {0xe8918f, 0xf8c6}, /* U+844F [2000] */ + {0xe89191, 0xf8c7}, /* U+8451 [2000] */ + {0xe89192, 0xf8c8}, /* U+8452 [2000] */ + {0xe89197, 0x9298}, /* U+8457 */ + {0xe89199, 0xf8c9}, /* U+8459 [2000] */ + {0xe8919a, 0xf8ca}, /* U+845A [2000] */ + {0xe8919b, 0x8a8b}, /* U+845B */ + {0xe8919c, 0xf8cb}, /* U+845C [2000] */ + {0xe8919f, 0xee48}, /* U+845F [2000] */ + {0xe891a1, 0x9592}, /* U+8461 */ + {0xe891a2, 0xe4e2}, /* U+8462 */ + {0xe891a3, 0x939f}, /* U+8463 */ + {0xe891a5, 0xf8cd}, /* U+8465 [2000] */ + {0xe891a6, 0x88af}, /* U+8466 */ + {0xe891a9, 0xe4db}, /* U+8469 */ + {0xe891ab, 0xe4d7}, /* U+846B */ + {0xe891ac, 0x9192}, /* U+846C */ + {0xe891ad, 0xe4d1}, /* U+846D */ + {0xe891ae, 0xe4d9}, /* U+846E */ + {0xe891af, 0xe4de}, /* U+846F */ + {0xe891b0, 0xee49}, /* U+8470 [2000] */ + {0xe891b1, 0x944b}, /* U+8471 */ + {0xe891b3, 0xee4a}, /* U+8473 [2000] */ + {0xe891b5, 0x88a8}, /* U+8475 */ + {0xe891b6, 0xf8ce}, /* U+8476 [2000] */ + {0xe891b7, 0xe4d6}, /* U+8477 */ + {0xe891b8, 0xf8cf}, /* U+8478 [2000] */ + {0xe891b9, 0xe4df}, /* U+8479 */ + {0xe891ba, 0x9598}, /* U+847A */ + {0xe891bc, 0xf8d0}, /* U+847C [2000] */ + {0xe89281, 0xf8d1}, /* U+8481 [2000] */ + {0xe89282, 0xe4da}, /* U+8482 */ + {0xe89284, 0xe4d5}, /* U+8484 */ + {0xe89285, 0xee4b}, /* U+8485 [2000] */ + {0xe8928b, 0x8fd3}, /* U+848B */ + {0xe89290, 0x8f4e}, /* U+8490 */ + {0xe89294, 0x8eaa}, /* U+8494 */ + {0xe89297, 0xf8d4}, /* U+8497 [2000] */ + {0xe89299, 0x96d6}, /* U+8499 */ + {0xe8929c, 0x9566}, /* U+849C */ + {0xe8929e, 0xee4c}, /* U+849E [2000] */ + {0xe8929f, 0xe4e5}, /* U+849F */ + {0xe892a1, 0xe4ee}, /* U+84A1 */ + {0xe892a6, 0xf8d5}, /* U+84A6 [2000] */ + {0xe892ad, 0xe4d8}, /* U+84AD */ + {0xe892af, 0xee4d}, /* U+84AF [2000] */ + {0xe892b2, 0x8a97}, /* U+84B2 */ + {0xe892b4, 0xee4e}, /* U+84B4 [2000] */ + {0xe892b8, 0x8ff6}, /* U+84B8 */ + {0xe892b9, 0xe4e3}, /* U+84B9 */ + {0xe892ba, 0xee4f}, /* U+84BA [2000] */ + {0xe892bb, 0xe4e8}, /* U+84BB */ + {0xe892bc, 0x9193}, /* U+84BC */ + {0xe892be, 0xf8d6}, /* U+84BE [2000] */ + {0xe892bf, 0xe4e4}, /* U+84BF */ + {0xe89380, 0xee50}, /* U+84C0 [2000] */ + {0xe89381, 0xe4eb}, /* U+84C1 */ + {0xe89382, 0xee51}, /* U+84C2 [2000] */ + {0xe89384, 0x927e}, /* U+84C4 */ + {0xe89386, 0xe4ec}, /* U+84C6 */ + {0xe89389, 0x9775}, /* U+84C9 */ + {0xe8938a, 0xe4e1}, /* U+84CA */ + {0xe8938b, 0x8a57}, /* U+84CB */ + {0xe8938d, 0xe4e7}, /* U+84CD */ + {0xe8938e, 0xf8d8}, /* U+84CE [2000] */ + {0xe8938f, 0xf8d9}, /* U+84CF [2000] */ + {0xe89390, 0xe4ea}, /* U+84D0 */ + {0xe89391, 0x96aa}, /* U+84D1 */ + {0xe89393, 0xf8da}, /* U+84D3 [2000] */ + {0xe89396, 0xe4ed}, /* U+84D6 */ + {0xe89399, 0xe4e6}, /* U+84D9 */ + {0xe8939a, 0xe4e9}, /* U+84DA */ + {0xe8939c, 0xf8d3}, /* U+84DC [2000] */ + {0xe893a7, 0xf8dc}, /* U+84E7 [2000] */ + {0xe893aa, 0xf8dd}, /* U+84EA [2000] */ + {0xe893ac, 0x9648}, /* U+84EC */ + {0xe893ae, 0x9840}, /* U+84EE */ + {0xe893af, 0xf8de}, /* U+84EF [2000] */ + {0xe893b0, 0xf8df}, /* U+84F0 [2000] */ + {0xe893b1, 0xf8e0}, /* U+84F1 [2000] */ + {0xe893b4, 0xe4f1}, /* U+84F4 */ + {0xe893ba, 0xf8e1}, /* U+84FA [2000] */ + {0xe893bc, 0xe4f8}, /* U+84FC */ + {0xe893bd, 0xf8e2}, /* U+84FD [2000] */ + {0xe893bf, 0xe4f0}, /* U+84FF */ + {0xe89480, 0x8ec1}, /* U+8500 */ + {0xe89486, 0xe4cf}, /* U+8506 */ + {0xe8948c, 0xf8e3}, /* U+850C [2000] */ + {0xe89491, 0x95cc}, /* U+8511 */ + {0xe89493, 0x96a0}, /* U+8513 */ + {0xe89494, 0xe4f7}, /* U+8514 */ + {0xe89495, 0xe4f6}, /* U+8515 */ + {0xe89497, 0xe4f2}, /* U+8517 */ + {0xe89498, 0xe4f3}, /* U+8518 */ + {0xe8949a, 0x8955}, /* U+851A */ + {0xe8949b, 0xf8e4}, /* U+851B [2000] */ + {0xe8949e, 0xee54}, /* U+851E [2000] */ + {0xe8949f, 0xe4f5}, /* U+851F */ + {0xe894a1, 0xe4ef}, /* U+8521 */ + {0xe894a3, 0xee55}, /* U+8523 [2000] */ + {0xe894a4, 0xf8e5}, /* U+8524 [2000] */ + {0xe894a5, 0xf8e6}, /* U+8525 [2000] */ + {0xe894a6, 0x92d3}, /* U+8526 */ + {0xe894ab, 0xf8e7}, /* U+852B [2000] */ + {0xe894ac, 0xe4f4}, /* U+852C */ + {0xe894ad, 0x88fc}, /* U+852D */ + {0xe894af, 0xee56}, /* U+852F [2000] */ + {0xe894b2, 0xee53}, /* U+8532 [2000] */ + {0xe894b4, 0xf8e8}, /* U+8534 [2000] */ + {0xe894b5, 0x91a0}, /* U+8535 */ + {0xe894bd, 0x95c1}, /* U+853D */ + {0xe894be, 0xf8ed}, /* U+853E [2000] */ + {0xe89580, 0xe4f9}, /* U+8540 */ + {0xe89581, 0xe540}, /* U+8541 */ + {0xe89583, 0x94d7}, /* U+8543 */ + {0xe89588, 0xe4fc}, /* U+8548 */ + {0xe89589, 0x8fd4}, /* U+8549 */ + {0xe8958a, 0x8ec7}, /* U+854A */ + {0xe8958b, 0xe542}, /* U+854B */ + {0xe8958e, 0x8bbc}, /* U+854E */ + {0xe8958f, 0xf8e9}, /* U+854F [2000] */ + {0xe89591, 0xf8ee}, /* U+8551 [2000] */ + {0xe89593, 0xf8ef}, /* U+8553 [2000] */ + {0xe89595, 0xe543}, /* U+8555 */ + {0xe89597, 0x9599}, /* U+8557 */ + {0xe89598, 0xe4fb}, /* U+8558 */ + {0xe89599, 0xee57}, /* U+8559 [2000] */ + {0xe8959a, 0xe4d4}, /* U+855A */ + {0xe8959e, 0xf8f0}, /* U+855E [2000] */ + {0xe895a1, 0xf8f1}, /* U+8561 [2000] */ + {0xe895a2, 0xf8f2}, /* U+8562 [2000] */ + {0xe895a3, 0xe4fa}, /* U+8563 */ + {0xe895a4, 0xee58}, /* U+8564 [2000] */ + {0xe895a8, 0x986e}, /* U+8568 */ + {0xe895a9, 0x93a0}, /* U+8569 */ + {0xe895aa, 0x9593}, /* U+856A */ + {0xe895ad, 0xe54a}, /* U+856D */ + {0xe895af, 0xf8ea}, /* U+856F [2000] */ + {0xe895b7, 0xe550}, /* U+8577 */ + {0xe895ba, 0xee5b}, /* U+857A [2000] */ + {0xe895bb, 0xf8f4}, /* U+857B [2000] */ + {0xe895bd, 0xf8f5}, /* U+857D [2000] */ + {0xe895be, 0xe551}, /* U+857E */ + {0xe895bf, 0xf8f6}, /* U+857F [2000] */ + {0xe89680, 0xe544}, /* U+8580 */ + {0xe89681, 0xf8f7}, /* U+8581 [2000] */ + {0xe89684, 0x9496}, /* U+8584 */ + {0xe89686, 0xf8f8}, /* U+8586 [2000] */ + {0xe89687, 0xe54e}, /* U+8587 */ + {0xe89688, 0xe546}, /* U+8588 */ + {0xe8968a, 0xe548}, /* U+858A */ + {0xe8968c, 0xee5c}, /* U+858C [2000] */ + {0xe8968f, 0xee5d}, /* U+858F [2000] */ + {0xe89690, 0xe552}, /* U+8590 */ + {0xe89691, 0xe547}, /* U+8591 */ + {0xe89693, 0xf8f9}, /* U+8593 [2000] */ + {0xe89694, 0xe54b}, /* U+8594 */ + {0xe89697, 0x8992}, /* U+8597 */ + {0xe89699, 0x93e3}, /* U+8599 */ + {0xe8969b, 0xe54c}, /* U+859B */ + {0xe8969c, 0xe54f}, /* U+859C */ + {0xe8969d, 0xf8fa}, /* U+859D [2000] */ + {0xe8969f, 0xf8fb}, /* U+859F [2000] */ + {0xe896a2, 0xee5e}, /* U+85A2 [2000] */ + {0xe896a4, 0xe545}, /* U+85A4 */ + {0xe896a6, 0x9145}, /* U+85A6 */ + {0xe896a8, 0xe549}, /* U+85A8 */ + {0xe896a9, 0x8e46}, /* U+85A9 */ + {0xe896aa, 0x9064}, /* U+85AA */ + {0xe896ab, 0x8c4f}, /* U+85AB */ + {0xe896ac, 0x96f2}, /* U+85AC */ + {0xe896ad, 0xee5a}, /* U+85AD [2000] */ + {0xe896ae, 0x96f7}, /* U+85AE */ + {0xe896af, 0x8f92}, /* U+85AF */ + {0xe896b0, 0xee5f}, /* U+85B0 [2000] */ + {0xe896b7, 0xf942}, /* U+85B7 [2000] */ + {0xe896b9, 0xe556}, /* U+85B9 */ + {0xe896ba, 0xe554}, /* U+85BA */ + {0xe896bc, 0xf943}, /* U+85BC [2000] */ + {0xe89781, 0x986d}, /* U+85C1 */ + {0xe89787, 0xf944}, /* U+85C7 [2000] */ + {0xe89789, 0xe553}, /* U+85C9 */ + {0xe8978a, 0xf945}, /* U+85CA [2000] */ + {0xe8978b, 0xee60}, /* U+85CB [2000] */ + {0xe8978d, 0x9795}, /* U+85CD */ + {0xe8978e, 0xee61}, /* U+85CE [2000] */ + {0xe8978f, 0xe555}, /* U+85CF */ + {0xe89790, 0xe557}, /* U+85D0 */ + {0xe89795, 0xe558}, /* U+85D5 */ + {0xe89798, 0xf946}, /* U+85D8 [2000] */ + {0xe89799, 0xf947}, /* U+85D9 [2000] */ + {0xe8979c, 0xe55b}, /* U+85DC */ + {0xe8979d, 0xe559}, /* U+85DD */ + {0xe8979f, 0xf948}, /* U+85DF [2000] */ + {0xe897a1, 0xf949}, /* U+85E1 [2000] */ + {0xe897a4, 0x93a1}, /* U+85E4 */ + {0xe897a5, 0xe55a}, /* U+85E5 */ + {0xe897a6, 0xf94a}, /* U+85E6 [2000] */ + {0xe897a9, 0x94cb}, /* U+85E9 */ + {0xe897aa, 0xe54d}, /* U+85EA */ + {0xe897ad, 0xee62}, /* U+85ED [2000] */ + {0xe897b6, 0xf94b}, /* U+85F6 [2000] */ + {0xe897b7, 0x8f93}, /* U+85F7 */ + {0xe897b9, 0xe55c}, /* U+85F9 */ + {0xe897ba, 0xe561}, /* U+85FA */ + {0xe897bb, 0x9194}, /* U+85FB */ + {0xe897be, 0xe560}, /* U+85FE */ + {0xe897bf, 0xee64}, /* U+85FF [2000] */ + {0xe89880, 0xf94c}, /* U+8600 [2000] */ + {0xe89882, 0xe541}, /* U+8602 */ + {0xe89884, 0xee65}, /* U+8604 [2000] */ + {0xe89885, 0xee66}, /* U+8605 [2000] */ + {0xe89886, 0xe562}, /* U+8606 */ + {0xe89887, 0x9168}, /* U+8607 */ + {0xe8988a, 0xe55d}, /* U+860A */ + {0xe8988b, 0xe55f}, /* U+860B */ + {0xe89890, 0xee67}, /* U+8610 [2000] */ + {0xe89891, 0xf94d}, /* U+8611 [2000] */ + {0xe89892, 0xee63}, /* U+8612 [2000] */ + {0xe89893, 0xe55e}, /* U+8613 */ + {0xe89896, 0x9f50}, /* U+8616 */ + {0xe89897, 0x9f41}, /* U+8617 */ + {0xe89898, 0xee69}, /* U+8618 [2000] */ + {0xe8989a, 0xe564}, /* U+861A */ + {0xe8989e, 0xf94e}, /* U+861E [2000] */ + {0xe898a1, 0xf94f}, /* U+8621 [2000] */ + {0xe898a2, 0xe563}, /* U+8622 */ + {0xe898a4, 0xf950}, /* U+8624 [2000] */ + {0xe898a7, 0xf951}, /* U+8627 [2000] */ + {0xe898a9, 0xee6a}, /* U+8629 [2000] */ + {0xe898ad, 0x9796}, /* U+862D */ + {0xe898af, 0xe1ba}, /* U+862F */ + {0xe898b0, 0xe565}, /* U+8630 */ + {0xe898b8, 0xee6b}, /* U+8638 [2000] */ + {0xe898b9, 0xf953}, /* U+8639 [2000] */ + {0xe898bc, 0xf954}, /* U+863C [2000] */ + {0xe898bf, 0xe566}, /* U+863F */ + {0xe89980, 0xf956}, /* U+8640 [2000] */ + {0xe89981, 0x8888}, /* U+8641 [2000] */ + {0xe8998d, 0xe567}, /* U+864D */ + {0xe8998e, 0x8cd5}, /* U+864E */ + {0xe89990, 0x8b73}, /* U+8650 */ + {0xe89993, 0xf958}, /* U+8653 [2000] */ + {0xe89994, 0xe569}, /* U+8654 */ + {0xe89995, 0x997c}, /* U+8655 */ + {0xe89996, 0xf959}, /* U+8656 [2000] */ + {0xe89997, 0xee6c}, /* U+8657 [2000] */ + {0xe8999a, 0x8b95}, /* U+865A */ + {0xe8999b, 0xee6d}, /* U+865B [2000] */ + {0xe8999c, 0x97b8}, /* U+865C */ + {0xe8999e, 0x8bf1}, /* U+865E */ + {0xe8999f, 0xe56a}, /* U+865F */ + {0xe899a2, 0xee6f}, /* U+8662 [2000] */ + {0xe899a7, 0xe56b}, /* U+8667 */ + {0xe899ab, 0x928e}, /* U+866B */ + {0xe899ac, 0xee71}, /* U+866C [2000] */ + {0xe899af, 0xf95a}, /* U+866F [2000] */ + {0xe899b1, 0xe56c}, /* U+8671 */ + {0xe899b5, 0xee72}, /* U+8675 [2000] */ + {0xe899b7, 0xf95b}, /* U+8677 [2000] */ + {0xe899b9, 0x93f8}, /* U+8679 */ + {0xe899ba, 0xf95c}, /* U+867A [2000] */ + {0xe899bb, 0x88b8}, /* U+867B */ + {0xe89a87, 0xf95d}, /* U+8687 [2000] */ + {0xe89a89, 0xf95e}, /* U+8689 [2000] */ + {0xe89a8a, 0x89e1}, /* U+868A */ + {0xe89a8b, 0xe571}, /* U+868B */ + {0xe89a8c, 0xe572}, /* U+868C */ + {0xe89a8d, 0xf95f}, /* U+868D [2000] */ + {0xe89a91, 0xf960}, /* U+8691 [2000] */ + {0xe89a93, 0xe56d}, /* U+8693 */ + {0xe89a95, 0x8e5c}, /* U+8695 */ + {0xe89a98, 0xee73}, /* U+8698 [2000] */ + {0xe89a9c, 0xf961}, /* U+869C [2000] */ + {0xe89a9d, 0xf962}, /* U+869D [2000] */ + {0xe89aa3, 0xe56e}, /* U+86A3 */ + {0xe89aa4, 0x9461}, /* U+86A4 */ + {0xe89aa8, 0xf963}, /* U+86A8 [2000] */ + {0xe89aa9, 0xe56f}, /* U+86A9 */ + {0xe89aaa, 0xe570}, /* U+86AA */ + {0xe89aab, 0xe57a}, /* U+86AB */ + {0xe89aaf, 0xe574}, /* U+86AF */ + {0xe89ab0, 0xe577}, /* U+86B0 */ + {0xe89ab1, 0xf965}, /* U+86B1 [2000] */ + {0xe89ab3, 0xf966}, /* U+86B3 [2000] */ + {0xe89ab6, 0xe573}, /* U+86B6 */ + {0xe89ab8, 0xee74}, /* U+86B8 [2000] */ + {0xe89b81, 0xf967}, /* U+86C1 [2000] */ + {0xe89b83, 0xf968}, /* U+86C3 [2000] */ + {0xe89b84, 0xe575}, /* U+86C4 */ + {0xe89b86, 0xe576}, /* U+86C6 */ + {0xe89b87, 0x8ed6}, /* U+86C7 */ + {0xe89b89, 0xe578}, /* U+86C9 */ + {0xe89b8b, 0x9260}, /* U+86CB */ + {0xe89b8d, 0x8c75}, /* U+86CD */ + {0xe89b8e, 0x8a61}, /* U+86CE */ + {0xe89b91, 0xf969}, /* U+86D1 [2000] */ + {0xe89b94, 0xe57b}, /* U+86D4 */ + {0xe89b95, 0xf96a}, /* U+86D5 [2000] */ + {0xe89b97, 0xf96b}, /* U+86D7 [2000] */ + {0xe89b99, 0x8a5e}, /* U+86D9 */ + {0xe89b9b, 0xe581}, /* U+86DB */ + {0xe89b9e, 0xe57c}, /* U+86DE */ + {0xe89b9f, 0xe580}, /* U+86DF */ + {0xe89ba3, 0xf96c}, /* U+86E3 [2000] */ + {0xe89ba4, 0x94b8}, /* U+86E4 */ + {0xe89ba6, 0xf96d}, /* U+86E6 [2000] */ + {0xe89ba9, 0xe57d}, /* U+86E9 */ + {0xe89bac, 0xe57e}, /* U+86EC */ + {0xe89bad, 0x9567}, /* U+86ED */ + {0xe89bae, 0x94d8}, /* U+86EE */ + {0xe89baf, 0xe582}, /* U+86EF */ + {0xe89bb8, 0x91fb}, /* U+86F8 */ + {0xe89bb9, 0xe58c}, /* U+86F9 */ + {0xe89bba, 0xee75}, /* U+86FA [2000] */ + {0xe89bbb, 0xe588}, /* U+86FB */ + {0xe89bbc, 0xee76}, /* U+86FC [2000] */ + {0xe89bbd, 0xee77}, /* U+86FD [2000] */ + {0xe89bbe, 0x89e9}, /* U+86FE */ + {0xe89c80, 0xe586}, /* U+8700 */ + {0xe89c82, 0x9649}, /* U+8702 */ + {0xe89c83, 0xe587}, /* U+8703 */ + {0xe89c85, 0xf96f}, /* U+8705 [2000] */ + {0xe89c86, 0xe584}, /* U+8706 */ + {0xe89c87, 0xf970}, /* U+8707 [2000] */ + {0xe89c88, 0xe585}, /* U+8708 */ + {0xe89c89, 0xe58a}, /* U+8709 */ + {0xe89c8a, 0xe58d}, /* U+870A */ + {0xe89c8b, 0xee78}, /* U+870B [2000] */ + {0xe89c8d, 0xe58b}, /* U+870D */ + {0xe89c8e, 0xf971}, /* U+870E [2000] */ + {0xe89c90, 0xf972}, /* U+8710 [2000] */ + {0xe89c91, 0xe589}, /* U+8711 */ + {0xe89c92, 0xe583}, /* U+8712 */ + {0xe89c93, 0xf973}, /* U+8713 [2000] */ + {0xe89c98, 0x9277}, /* U+8718 */ + {0xe89c99, 0xf974}, /* U+8719 [2000] */ + {0xe89c9a, 0xe594}, /* U+871A */ + {0xe89c9c, 0x96a8}, /* U+871C */ + {0xe89c9f, 0xf975}, /* U+871F [2000] */ + {0xe89ca1, 0xf976}, /* U+8721 [2000] */ + {0xe89ca3, 0xf977}, /* U+8723 [2000] */ + {0xe89ca5, 0xe592}, /* U+8725 */ + {0xe89ca9, 0xe593}, /* U+8729 */ + {0xe89cb1, 0xf978}, /* U+8731 [2000] */ + {0xe89cb4, 0xe58e}, /* U+8734 */ + {0xe89cb7, 0xe590}, /* U+8737 */ + {0xe89cba, 0xf979}, /* U+873A [2000] */ + {0xe89cbb, 0xe591}, /* U+873B */ + {0xe89cbe, 0xf97a}, /* U+873E [2000] */ + {0xe89cbf, 0xe58f}, /* U+873F */ + {0xe89d80, 0xf97b}, /* U+8740 [2000] */ + {0xe89d83, 0xf97c}, /* U+8743 [2000] */ + {0xe89d89, 0x90e4}, /* U+8749 */ + {0xe89d8b, 0x9858}, /* U+874B */ + {0xe89d8c, 0xe598}, /* U+874C */ + {0xe89d8e, 0xe599}, /* U+874E */ + {0xe89d91, 0xf97d}, /* U+8751 [2000] */ + {0xe89d93, 0xe59f}, /* U+8753 */ + {0xe89d95, 0x9049}, /* U+8755 */ + {0xe89d97, 0xe59b}, /* U+8757 */ + {0xe89d98, 0xf97e}, /* U+8758 [2000] */ + {0xe89d99, 0xe59e}, /* U+8759 */ + {0xe89d9f, 0xe596}, /* U+875F */ + {0xe89da0, 0xe595}, /* U+8760 */ + {0xe89da3, 0xe5a0}, /* U+8763 */ + {0xe89da4, 0xf980}, /* U+8764 [2000] */ + {0xe89da5, 0xf981}, /* U+8765 [2000] */ + {0xe89da6, 0x89da}, /* U+8766 */ + {0xe89da8, 0xe59c}, /* U+8768 */ + {0xe89daa, 0xe5a1}, /* U+876A */ + {0xe89dae, 0xe59d}, /* U+876E */ + {0xe89db1, 0xee79}, /* U+8771 [2000] */ + {0xe89db2, 0xf982}, /* U+8772 [2000] */ + {0xe89db4, 0xe59a}, /* U+8774 */ + {0xe89db6, 0x92b1}, /* U+8776 */ + {0xe89db8, 0xe597}, /* U+8778 */ + {0xe89dbc, 0xf983}, /* U+877C [2000] */ + {0xe89dbf, 0x9488}, /* U+877F */ + {0xe89e82, 0xe5a5}, /* U+8782 */ + {0xe89e87, 0xee7a}, /* U+8787 [2000] */ + {0xe89e88, 0xee7b}, /* U+8788 [2000] */ + {0xe89e89, 0xf987}, /* U+8789 [2000] */ + {0xe89e8b, 0xf988}, /* U+878B [2000] */ + {0xe89e8d, 0x975a}, /* U+878D */ + {0xe89e93, 0xf989}, /* U+8793 [2000] */ + {0xe89e9f, 0xe5a4}, /* U+879F */ + {0xe89ea0, 0xf98a}, /* U+87A0 [2000] */ + {0xe89ea2, 0xe5a3}, /* U+87A2 */ + {0xe89ea7, 0xf986}, /* U+87A7 [2000] */ + {0xe89eab, 0xe5ac}, /* U+87AB */ + {0xe89eac, 0xee7c}, /* U+87AC [2000] */ + {0xe89ead, 0xee7d}, /* U+87AD [2000] */ + {0xe89eaf, 0xe5a6}, /* U+87AF */ + {0xe89eb3, 0xe5ae}, /* U+87B3 */ + {0xe89eb5, 0xee7e}, /* U+87B5 [2000] */ + {0xe89eba, 0x9786}, /* U+87BA */ + {0xe89ebb, 0xe5b1}, /* U+87BB */ + {0xe89ebd, 0xe5a8}, /* U+87BD */ + {0xe89ebe, 0xf98d}, /* U+87BE [2000] */ + {0xe89f80, 0xe5a9}, /* U+87C0 */ + {0xe89f81, 0xf98f}, /* U+87C1 [2000] */ + {0xe89f84, 0xe5ad}, /* U+87C4 */ + {0xe89f86, 0xe5b0}, /* U+87C6 */ + {0xe89f87, 0xe5af}, /* U+87C7 */ + {0xe89f8b, 0xe5a7}, /* U+87CB */ + {0xe89f8e, 0xf990}, /* U+87CE [2000] */ + {0xe89f90, 0xe5aa}, /* U+87D0 */ + {0xe89f92, 0xe5bb}, /* U+87D2 */ + {0xe89f96, 0xee81}, /* U+87D6 [2000] */ + {0xe89f9f, 0xf992}, /* U+87DF [2000] */ + {0xe89fa0, 0xe5b4}, /* U+87E0 */ + {0xe89fa3, 0xf994}, /* U+87E3 [2000] */ + {0xe89fa5, 0xf995}, /* U+87E5 [2000] */ + {0xe89fa6, 0xf996}, /* U+87E6 [2000] */ + {0xe89faa, 0xf997}, /* U+87EA [2000] */ + {0xe89fab, 0xf998}, /* U+87EB [2000] */ + {0xe89fac, 0xee82}, /* U+87EC [2000] */ + {0xe89fad, 0xf999}, /* U+87ED [2000] */ + {0xe89faf, 0xe5b2}, /* U+87EF */ + {0xe89fb2, 0xe5b3}, /* U+87F2 */ + {0xe89fb5, 0xf991}, /* U+87F5 [2000] */ + {0xe89fb6, 0xe5b8}, /* U+87F6 */ + {0xe89fb7, 0xe5b9}, /* U+87F7 */ + {0xe89fb9, 0x8a49}, /* U+87F9 */ + {0xe89fbb, 0x8b61}, /* U+87FB */ + {0xe89fbe, 0xe5b7}, /* U+87FE */ + {0xe8a081, 0xf99a}, /* U+8801 [2000] */ + {0xe8a083, 0xf99b}, /* U+8803 [2000] */ + {0xe8a085, 0xe5a2}, /* U+8805 */ + {0xe8a086, 0xee83}, /* U+8806 [2000] */ + {0xe8a08a, 0xee84}, /* U+880A [2000] */ + {0xe8a08b, 0xf99c}, /* U+880B [2000] */ + {0xe8a08d, 0xe5b6}, /* U+880D */ + {0xe8a08e, 0xe5ba}, /* U+880E */ + {0xe8a08f, 0xe5b5}, /* U+880F */ + {0xe8a090, 0xee85}, /* U+8810 [2000] */ + {0xe8a091, 0xe5bc}, /* U+8811 */ + {0xe8a093, 0xf99d}, /* U+8813 [2000] */ + {0xe8a094, 0xee86}, /* U+8814 [2000] */ + {0xe8a095, 0xe5be}, /* U+8815 */ + {0xe8a096, 0xe5bd}, /* U+8816 */ + {0xe8a09f, 0xee87}, /* U+881F [2000] */ + {0xe8a0a1, 0xe5c0}, /* U+8821 */ + {0xe8a0a2, 0xe5bf}, /* U+8822 */ + {0xe8a0a3, 0xe579}, /* U+8823 */ + {0xe8a0a7, 0xe5c4}, /* U+8827 */ + {0xe8a0a8, 0xf99e}, /* U+8828 [2000] */ + {0xe8a0ae, 0xf99f}, /* U+882E [2000] */ + {0xe8a0b1, 0xe5c1}, /* U+8831 */ + {0xe8a0b2, 0xf9a0}, /* U+8832 [2000] */ + {0xe8a0b6, 0xe5c2}, /* U+8836 */ + {0xe8a0b9, 0xe5c3}, /* U+8839 */ + {0xe8a0bb, 0xe5c5}, /* U+883B */ + {0xe8a0bc, 0xf9a1}, /* U+883C [2000] */ + {0xe8a180, 0x8c8c}, /* U+8840 */ + {0xe8a182, 0xe5c7}, /* U+8842 */ + {0xe8a184, 0xe5c6}, /* U+8844 */ + {0xe8a186, 0x8f4f}, /* U+8846 */ + {0xe8a18a, 0xf9a3}, /* U+884A [2000] */ + {0xe8a18c, 0x8d73}, /* U+884C */ + {0xe8a18d, 0x9fa5}, /* U+884D */ + {0xe8a192, 0xe5c8}, /* U+8852 */ + {0xe8a193, 0x8f70}, /* U+8853 */ + {0xe8a197, 0x8a58}, /* U+8857 */ + {0xe8a198, 0xf9a4}, /* U+8858 [2000] */ + {0xe8a199, 0xe5c9}, /* U+8859 */ + {0xe8a19b, 0x8971}, /* U+885B */ + {0xe8a19d, 0x8fd5}, /* U+885D */ + {0xe8a19e, 0xe5ca}, /* U+885E */ + {0xe8a19f, 0xf9a5}, /* U+885F [2000] */ + {0xe8a1a1, 0x8d74}, /* U+8861 */ + {0xe8a1a2, 0xe5cb}, /* U+8862 */ + {0xe8a1a3, 0x88df}, /* U+8863 */ + {0xe8a1a4, 0xf9a6}, /* U+8864 [2000] */ + {0xe8a1a8, 0x955c}, /* U+8868 */ + {0xe8a1a9, 0xf9a9}, /* U+8869 [2000] */ + {0xe8a1ab, 0xe5cc}, /* U+886B */ + {0xe8a1af, 0xf9ab}, /* U+886F [2000] */ + {0xe8a1b0, 0x908a}, /* U+8870 */ + {0xe8a1b2, 0xe5d3}, /* U+8872 */ + {0xe8a1b5, 0xe5d0}, /* U+8875 */ + {0xe8a1b7, 0x928f}, /* U+8877 */ + {0xe8a1bd, 0xe5d1}, /* U+887D */ + {0xe8a1be, 0xe5ce}, /* U+887E */ + {0xe8a1bf, 0x8bdc}, /* U+887F */ + {0xe8a281, 0xe5cd}, /* U+8881 */ + {0xe8a282, 0xe5d4}, /* U+8882 */ + {0xe8a288, 0x8c55}, /* U+8888 */ + {0xe8a28b, 0x91dc}, /* U+888B */ + {0xe8a28d, 0xe5da}, /* U+888D */ + {0xe8a292, 0xe5d6}, /* U+8892 */ + {0xe8a296, 0x91b3}, /* U+8896 */ + {0xe8a297, 0xe5d5}, /* U+8897 */ + {0xe8a298, 0xee88}, /* U+8898 [2000] */ + {0xe8a299, 0xe5d8}, /* U+8899 */ + {0xe8a29e, 0xe5cf}, /* U+889E */ + {0xe8a2a0, 0xf9ac}, /* U+88A0 [2000] */ + {0xe8a2a2, 0xe5d9}, /* U+88A2 */ + {0xe8a2a4, 0xe5db}, /* U+88A4 */ + {0xe8a2aa, 0xee89}, /* U+88AA [2000] */ + {0xe8a2ab, 0x94ed}, /* U+88AB */ + {0xe8a2ae, 0xe5d7}, /* U+88AE */ + {0xe8a2b0, 0xe5dc}, /* U+88B0 */ + {0xe8a2b1, 0xe5de}, /* U+88B1 */ + {0xe8a2b4, 0x8cd1}, /* U+88B4 */ + {0xe8a2b5, 0xe5d2}, /* U+88B5 */ + {0xe8a2b7, 0x88bf}, /* U+88B7 */ + {0xe8a2bc, 0xf9ad}, /* U+88BC [2000] */ + {0xe8a2bd, 0xf9ae}, /* U+88BD [2000] */ + {0xe8a2be, 0xf9af}, /* U+88BE [2000] */ + {0xe8a2bf, 0xe5dd}, /* U+88BF */ + {0xe8a380, 0xf9b0}, /* U+88C0 [2000] */ + {0xe8a381, 0x8dd9}, /* U+88C1 */ + {0xe8a382, 0x97f4}, /* U+88C2 */ + {0xe8a383, 0xe5df}, /* U+88C3 */ + {0xe8a384, 0xe5e0}, /* U+88C4 */ + {0xe8a385, 0x9195}, /* U+88C5 */ + {0xe8a38a, 0xee8a}, /* U+88CA [2000] */ + {0xe8a38e, 0xee8b}, /* U+88CE [2000] */ + {0xe8a38f, 0x97a0}, /* U+88CF */ + {0xe8a391, 0xf9b3}, /* U+88D1 [2000] */ + {0xe8a392, 0xf9b1}, /* U+88D2 [2000] */ + {0xe8a393, 0xf9b4}, /* U+88D3 [2000] */ + {0xe8a394, 0xe5e1}, /* U+88D4 */ + {0xe8a395, 0x9754}, /* U+88D5 */ + {0xe8a398, 0xe5e2}, /* U+88D8 */ + {0xe8a399, 0xe5e3}, /* U+88D9 */ + {0xe8a39b, 0xf9b5}, /* U+88DB [2000] */ + {0xe8a39c, 0x95e2}, /* U+88DC */ + {0xe8a39d, 0xe5e4}, /* U+88DD */ + {0xe8a39f, 0x8dbe}, /* U+88DF */ + {0xe8a3a1, 0x97a1}, /* U+88E1 */ + {0xe8a3a8, 0xe5e9}, /* U+88E8 */ + {0xe8a3b0, 0xf9b6}, /* U+88F0 [2000] */ + {0xe8a3b1, 0xf9b7}, /* U+88F1 [2000] */ + {0xe8a3b2, 0xe5ea}, /* U+88F2 */ + {0xe8a3b3, 0x8fd6}, /* U+88F3 */ + {0xe8a3b4, 0xe5e8}, /* U+88F4 */ + {0xe8a3b5, 0xee8d}, /* U+88F5 [2000] */ + {0xe8a3b8, 0x9787}, /* U+88F8 */ + {0xe8a3b9, 0xe5e5}, /* U+88F9 */ + {0xe8a3bc, 0xe5e7}, /* U+88FC */ + {0xe8a3bd, 0x90bb}, /* U+88FD */ + {0xe8a3be, 0x909e}, /* U+88FE */ + {0xe8a481, 0xf9b9}, /* U+8901 [2000] */ + {0xe8a482, 0xe5e6}, /* U+8902 */ + {0xe8a484, 0xe5eb}, /* U+8904 */ + {0xe8a487, 0x95a1}, /* U+8907 */ + {0xe8a48a, 0xe5ed}, /* U+890A */ + {0xe8a48c, 0xe5ec}, /* U+890C */ + {0xe8a490, 0x8a8c}, /* U+8910 */ + {0xe8a492, 0x964a}, /* U+8912 */ + {0xe8a493, 0xe5ee}, /* U+8913 */ + {0xe8a498, 0xee90}, /* U+8918 [2000] */ + {0xe8a499, 0xee91}, /* U+8919 [2000] */ + {0xe8a49a, 0xee92}, /* U+891A [2000] */ + {0xe8a49c, 0xee8e}, /* U+891C [2000] */ + {0xe8a49d, 0xe5fa}, /* U+891D */ + {0xe8a49e, 0xe5f0}, /* U+891E */ + {0xe8a4a5, 0xe5f1}, /* U+8925 */ + {0xe8a4a7, 0xee93}, /* U+8927 [2000] */ + {0xe8a4aa, 0xe5f2}, /* U+892A */ + {0xe8a4ab, 0xe5f3}, /* U+892B */ + {0xe8a4b0, 0xee94}, /* U+8930 [2000] */ + {0xe8a4b2, 0xee95}, /* U+8932 [2000] */ + {0xe8a4b6, 0xe5f7}, /* U+8936 */ + {0xe8a4b7, 0xf9bb}, /* U+8937 [2000] */ + {0xe8a4b8, 0xe5f8}, /* U+8938 */ + {0xe8a4b9, 0xee96}, /* U+8939 [2000] */ + {0xe8a4bb, 0xe5f6}, /* U+893B */ + {0xe8a580, 0xee97}, /* U+8940 [2000] */ + {0xe8a581, 0xe5f4}, /* U+8941 */ + {0xe8a582, 0xf9bd}, /* U+8942 [2000] */ + {0xe8a583, 0xe5ef}, /* U+8943 */ + {0xe8a584, 0xe5f5}, /* U+8944 */ + {0xe8a585, 0xf9be}, /* U+8945 [2000] */ + {0xe8a589, 0xf9bf}, /* U+8949 [2000] */ + {0xe8a58c, 0xe5f9}, /* U+894C */ + {0xe8a58d, 0xe8b5}, /* U+894D */ + {0xe8a596, 0x89a6}, /* U+8956 */ + {0xe8a59e, 0xe5fc}, /* U+895E */ + {0xe8a59f, 0x8bdd}, /* U+895F */ + {0xe8a5a0, 0xe5fb}, /* U+8960 */ + {0xe8a5a2, 0xf9c2}, /* U+8962 [2000] */ + {0xe8a5a4, 0xe641}, /* U+8964 */ + {0xe8a5a6, 0xe640}, /* U+8966 */ + {0xe8a5aa, 0xe643}, /* U+896A */ + {0xe8a5ad, 0xe642}, /* U+896D */ + {0xe8a5af, 0xe644}, /* U+896F */ + {0xe8a5b2, 0x8f50}, /* U+8972 */ + {0xe8a5b4, 0xe645}, /* U+8974 */ + {0xe8a5b7, 0xe646}, /* U+8977 */ + {0xe8a5be, 0xe647}, /* U+897E */ + {0xe8a5bf, 0x90bc}, /* U+897F */ + {0xe8a680, 0xf9c3}, /* U+8980 [2000] */ + {0xe8a681, 0x9776}, /* U+8981 */ + {0xe8a683, 0xe648}, /* U+8983 */ + {0xe8a686, 0x95a2}, /* U+8986 */ + {0xe8a687, 0x9465}, /* U+8987 */ + {0xe8a688, 0xe649}, /* U+8988 */ + {0xe8a689, 0xf9c4}, /* U+8989 [2000] */ + {0xe8a68a, 0xe64a}, /* U+898A */ + {0xe8a68b, 0x8ca9}, /* U+898B */ + {0xe8a68f, 0x8b4b}, /* U+898F */ + {0xe8a690, 0xf9c5}, /* U+8990 [2000] */ + {0xe8a693, 0xe64b}, /* U+8993 */ + {0xe8a694, 0xee98}, /* U+8994 [2000] */ + {0xe8a696, 0x8e8b}, /* U+8996 */ + {0xe8a697, 0x9460}, /* U+8997 */ + {0xe8a698, 0xe64c}, /* U+8998 */ + {0xe8a69a, 0x8a6f}, /* U+899A */ + {0xe8a69f, 0xf9c6}, /* U+899F [2000] */ + {0xe8a6a1, 0xe64d}, /* U+89A1 */ + {0xe8a6a6, 0xe64f}, /* U+89A6 */ + {0xe8a6a7, 0x9797}, /* U+89A7 */ + {0xe8a6a9, 0xe64e}, /* U+89A9 */ + {0xe8a6aa, 0x9065}, /* U+89AA */ + {0xe8a6ac, 0xe650}, /* U+89AC */ + {0xe8a6af, 0xe651}, /* U+89AF */ + {0xe8a6b0, 0xf9c7}, /* U+89B0 [2000] */ + {0xe8a6b2, 0xe652}, /* U+89B2 */ + {0xe8a6b3, 0x8acf}, /* U+89B3 */ + {0xe8a6b7, 0xf9c8}, /* U+89B7 [2000] */ + {0xe8a6ba, 0xe653}, /* U+89BA */ + {0xe8a6bd, 0xe654}, /* U+89BD */ + {0xe8a6bf, 0xe655}, /* U+89BF */ + {0xe8a780, 0xe656}, /* U+89C0 */ + {0xe8a792, 0x8a70}, /* U+89D2 */ + {0xe8a794, 0xee9a}, /* U+89D4 [2000] */ + {0xe8a796, 0xf9c9}, /* U+89D6 [2000] */ + {0xe8a798, 0xf9ca}, /* U+89D8 [2000] */ + {0xe8a79a, 0xe657}, /* U+89DA */ + {0xe8a79c, 0xe658}, /* U+89DC */ + {0xe8a79d, 0xe659}, /* U+89DD */ + {0xe8a7a3, 0x89f0}, /* U+89E3 */ + {0xe8a7a5, 0xee9b}, /* U+89E5 [2000] */ + {0xe8a7a6, 0x9047}, /* U+89E6 */ + {0xe8a7a7, 0xe65a}, /* U+89E7 */ + {0xe8a7ab, 0xf9cb}, /* U+89EB [2000] */ + {0xe8a7b1, 0xf9cd}, /* U+89F1 [2000] */ + {0xe8a7b3, 0xf9ce}, /* U+89F3 [2000] */ + {0xe8a7b4, 0xe65b}, /* U+89F4 */ + {0xe8a7b6, 0xee9c}, /* U+89F6 [2000] */ + {0xe8a7b8, 0xe65c}, /* U+89F8 */ + {0xe8a7bd, 0xf9cf}, /* U+89FD [2000] */ + {0xe8a7bf, 0xf9d0}, /* U+89FF [2000] */ + {0xe8a880, 0x8cbe}, /* U+8A00 */ + {0xe8a882, 0x92f9}, /* U+8A02 */ + {0xe8a883, 0xe65d}, /* U+8A03 */ + {0xe8a888, 0x8c76}, /* U+8A08 */ + {0xe8a88a, 0x9075}, /* U+8A0A */ + {0xe8a88c, 0xe660}, /* U+8A0C */ + {0xe8a88e, 0x93a2}, /* U+8A0E */ + {0xe8a890, 0xe65f}, /* U+8A10 */ + {0xe8a891, 0xf9d2}, /* U+8A11 [2000] */ + {0xe8a892, 0xee9d}, /* U+8A12 [2000] */ + {0xe8a893, 0x8c50}, /* U+8A13 */ + {0xe8a894, 0xf9d3}, /* U+8A14 [2000] */ + {0xe8a895, 0xee9e}, /* U+8A15 [2000] */ + {0xe8a896, 0xe65e}, /* U+8A16 */ + {0xe8a897, 0x91f5}, /* U+8A17 */ + {0xe8a898, 0x8b4c}, /* U+8A18 */ + {0xe8a89b, 0xe661}, /* U+8A1B */ + {0xe8a89d, 0xe662}, /* U+8A1D */ + {0xe8a89f, 0x8fd7}, /* U+8A1F */ + {0xe8a8a1, 0xf9d5}, /* U+8A21 [2000] */ + {0xe8a8a2, 0xee9f}, /* U+8A22 [2000] */ + {0xe8a8a3, 0x8c8d}, /* U+8A23 */ + {0xe8a8a5, 0xe663}, /* U+8A25 */ + {0xe8a8aa, 0x964b}, /* U+8A2A */ + {0xe8a8ad, 0x90dd}, /* U+8A2D */ + {0xe8a8b1, 0x8b96}, /* U+8A31 */ + {0xe8a8b3, 0x96f3}, /* U+8A33 */ + {0xe8a8b4, 0x9169}, /* U+8A34 */ + {0xe8a8b5, 0xf9d6}, /* U+8A35 [2000] */ + {0xe8a8b6, 0xe664}, /* U+8A36 */ + {0xe8a8b7, 0xeea0}, /* U+8A37 [2000] */ + {0xe8a8ba, 0x9066}, /* U+8A3A */ + {0xe8a8bb, 0x9290}, /* U+8A3B */ + {0xe8a8bc, 0x8fd8}, /* U+8A3C */ + {0xe8a8be, 0xf9d7}, /* U+8A3E [2000] */ + {0xe8a981, 0xe665}, /* U+8A41 */ + {0xe8a985, 0xf9d8}, /* U+8A45 [2000] */ + {0xe8a986, 0xe668}, /* U+8A46 */ + {0xe8a987, 0xeea1}, /* U+8A47 [2000] */ + {0xe8a988, 0xe669}, /* U+8A48 */ + {0xe8a98d, 0xf9d9}, /* U+8A4D [2000] */ + {0xe8a98e, 0xeea2}, /* U+8A4E [2000] */ + {0xe8a990, 0x8dbc}, /* U+8A50 */ + {0xe8a991, 0x91c0}, /* U+8A51 */ + {0xe8a992, 0xe667}, /* U+8A52 */ + {0xe8a994, 0x8fd9}, /* U+8A54 */ + {0xe8a995, 0x955d}, /* U+8A55 */ + {0xe8a998, 0xf9da}, /* U+8A58 [2000] */ + {0xe8a99b, 0xe666}, /* U+8A5B */ + {0xe8a99d, 0xeea3}, /* U+8A5D [2000] */ + {0xe8a99e, 0x8e8c}, /* U+8A5E */ + {0xe8a9a0, 0x8972}, /* U+8A60 */ + {0xe8a9a1, 0xeea4}, /* U+8A61 [2000] */ + {0xe8a9a2, 0xe66d}, /* U+8A62 */ + {0xe8a9a3, 0x8c77}, /* U+8A63 */ + {0xe8a9a6, 0x8e8e}, /* U+8A66 */ + {0xe8a9a9, 0x8e8d}, /* U+8A69 */ + {0xe8a9ab, 0x986c}, /* U+8A6B */ + {0xe8a9ac, 0xe66c}, /* U+8A6C */ + {0xe8a9ad, 0xe66b}, /* U+8A6D */ + {0xe8a9ae, 0x9146}, /* U+8A6E */ + {0xe8a9b0, 0x8b6c}, /* U+8A70 */ + {0xe8a9b1, 0x9862}, /* U+8A71 */ + {0xe8a9b2, 0x8a59}, /* U+8A72 */ + {0xe8a9b3, 0x8fda}, /* U+8A73 */ + {0xe8a9b5, 0xeea5}, /* U+8A75 [2000] */ + {0xe8a9b9, 0xeea6}, /* U+8A79 [2000] */ + {0xe8a9bc, 0xe66a}, /* U+8A7C */ + {0xe8aa82, 0xe66f}, /* U+8A82 */ + {0xe8aa84, 0xe670}, /* U+8A84 */ + {0xe8aa85, 0xe66e}, /* U+8A85 */ + {0xe8aa87, 0x8cd6}, /* U+8A87 */ + {0xe8aa89, 0x975f}, /* U+8A89 */ + {0xe8aa8c, 0x8e8f}, /* U+8A8C */ + {0xe8aa8d, 0x9446}, /* U+8A8D */ + {0xe8aa90, 0xf9dc}, /* U+8A90 [2000] */ + {0xe8aa91, 0xe673}, /* U+8A91 */ + {0xe8aa93, 0x90be}, /* U+8A93 */ + {0xe8aa95, 0x9261}, /* U+8A95 */ + {0xe8aa98, 0x9755}, /* U+8A98 */ + {0xe8aa9a, 0xe676}, /* U+8A9A */ + {0xe8aa9e, 0x8cea}, /* U+8A9E */ + {0xe8aaa0, 0x90bd}, /* U+8AA0 */ + {0xe8aaa1, 0xe672}, /* U+8AA1 */ + {0xe8aaa3, 0xe677}, /* U+8AA3 */ + {0xe8aaa4, 0x8ceb}, /* U+8AA4 */ + {0xe8aaa5, 0xe674}, /* U+8AA5 */ + {0xe8aaa6, 0xe675}, /* U+8AA6 */ + {0xe8aaa7, 0xeea7}, /* U+8AA7 [2000] */ + {0xe8aaa8, 0xe671}, /* U+8AA8 */ + {0xe8aaac, 0x90e0}, /* U+8AAC */ + {0xe8aaad, 0x93c7}, /* U+8AAD */ + {0xe8aaae, 0xf9db}, /* U+8AAE [2000] */ + {0xe8aab0, 0x924e}, /* U+8AB0 */ + {0xe8aab2, 0x89db}, /* U+8AB2 */ + {0xe8aab7, 0xf9dd}, /* U+8AB7 [2000] */ + {0xe8aab9, 0x94ee}, /* U+8AB9 */ + {0xe8aabc, 0x8b62}, /* U+8ABC */ + {0xe8aabe, 0xf9de}, /* U+8ABE [2000] */ + {0xe8aabf, 0x92b2}, /* U+8ABF */ + {0xe8ab82, 0xe67a}, /* U+8AC2 */ + {0xe8ab84, 0xe678}, /* U+8AC4 */ + {0xe8ab87, 0x926b}, /* U+8AC7 */ + {0xe8ab8b, 0x90bf}, /* U+8ACB */ + {0xe8ab8c, 0x8ad0}, /* U+8ACC */ + {0xe8ab8d, 0xe679}, /* U+8ACD */ + {0xe8ab8f, 0x907a}, /* U+8ACF */ + {0xe8ab90, 0xeea8}, /* U+8AD0 [2000] */ + {0xe8ab92, 0x97c8}, /* U+8AD2 */ + {0xe8ab96, 0x985f}, /* U+8AD6 */ + {0xe8ab97, 0xf9df}, /* U+8AD7 [2000] */ + {0xe8ab9a, 0xe67b}, /* U+8ADA */ + {0xe8ab9b, 0xe687}, /* U+8ADB */ + {0xe8ab9c, 0x92b3}, /* U+8ADC */ + {0xe8ab9e, 0xe686}, /* U+8ADE */ + {0xe8ab9f, 0xeea9}, /* U+8ADF [2000] */ + {0xe8aba0, 0xe683}, /* U+8AE0 */ + {0xe8aba1, 0xe68b}, /* U+8AE1 */ + {0xe8aba2, 0xe684}, /* U+8AE2 */ + {0xe8aba4, 0xe680}, /* U+8AE4 */ + {0xe8aba6, 0x92fa}, /* U+8AE6 */ + {0xe8aba7, 0xe67e}, /* U+8AE7 */ + {0xe8abab, 0xe67c}, /* U+8AEB */ + {0xe8abad, 0x9740}, /* U+8AED */ + {0xe8abae, 0x8e90}, /* U+8AEE */ + {0xe8abb1, 0xe681}, /* U+8AF1 */ + {0xe8abb3, 0xe67d}, /* U+8AF3 */ + {0xe8abb4, 0xeeaa}, /* U+8AF4 [2000] */ + {0xe8abb6, 0xeeab}, /* U+8AF6 [2000] */ + {0xe8abb7, 0xe685}, /* U+8AF7 */ + {0xe8abb8, 0x8f94}, /* U+8AF8 */ + {0xe8abba, 0x8cbf}, /* U+8AFA */ + {0xe8abbc, 0xf9e0}, /* U+8AFC [2000] */ + {0xe8abbe, 0x91f8}, /* U+8AFE */ + {0xe8ac80, 0x9664}, /* U+8B00 */ + {0xe8ac81, 0x8979}, /* U+8B01 */ + {0xe8ac82, 0x88e0}, /* U+8B02 */ + {0xe8ac84, 0x93a3}, /* U+8B04 */ + {0xe8ac85, 0xf9e3}, /* U+8B05 [2000] */ + {0xe8ac87, 0xe689}, /* U+8B07 */ + {0xe8ac8a, 0xf9e2}, /* U+8B0A [2000] */ + {0xe8ac8c, 0xe688}, /* U+8B0C */ + {0xe8ac8d, 0xf9e4}, /* U+8B0D [2000] */ + {0xe8ac8e, 0x93e4}, /* U+8B0E */ + {0xe8ac90, 0xe68d}, /* U+8B10 */ + {0xe8ac94, 0xe682}, /* U+8B14 */ + {0xe8ac96, 0xe68c}, /* U+8B16 */ + {0xe8ac97, 0xe68e}, /* U+8B17 */ + {0xe8ac99, 0x8caa}, /* U+8B19 */ + {0xe8ac9a, 0xe68a}, /* U+8B1A */ + {0xe8ac9b, 0x8d75}, /* U+8B1B */ + {0xe8ac9c, 0xf9e5}, /* U+8B1C [2000] */ + {0xe8ac9d, 0x8ed3}, /* U+8B1D */ + {0xe8ac9f, 0xf9e6}, /* U+8B1F [2000] */ + {0xe8aca0, 0xe68f}, /* U+8B20 */ + {0xe8aca1, 0x9777}, /* U+8B21 */ + {0xe8aca6, 0xe692}, /* U+8B26 */ + {0xe8aca8, 0xe695}, /* U+8B28 */ + {0xe8acab, 0xe693}, /* U+8B2B */ + {0xe8acac, 0x9554}, /* U+8B2C */ + {0xe8acad, 0xf9e7}, /* U+8B2D [2000] */ + {0xe8acb3, 0xe690}, /* U+8B33 */ + {0xe8acb9, 0x8bde}, /* U+8B39 */ + {0xe8acbe, 0xe694}, /* U+8B3E */ + {0xe8ad81, 0xe696}, /* U+8B41 */ + {0xe8ad83, 0xf9e8}, /* U+8B43 [2000] */ + {0xe8ad86, 0xeeaf}, /* U+8B46 [2000] */ + {0xe8ad89, 0xe69a}, /* U+8B49 */ + {0xe8ad8c, 0xe697}, /* U+8B4C */ + {0xe8ad8e, 0xe699}, /* U+8B4E */ + {0xe8ad8f, 0xe698}, /* U+8B4F */ + {0xe8ad91, 0xf9ea}, /* U+8B51 [2000] */ + {0xe8ad94, 0xeeb0}, /* U+8B54 [2000] */ + {0xe8ad96, 0xe69b}, /* U+8B56 */ + {0xe8ad98, 0x8eaf}, /* U+8B58 */ + {0xe8ad99, 0xeeb1}, /* U+8B59 [2000] */ + {0xe8ad9a, 0xe69d}, /* U+8B5A */ + {0xe8ad9b, 0xe69c}, /* U+8B5B */ + {0xe8ad9c, 0x9588}, /* U+8B5C */ + {0xe8ad9e, 0xf9eb}, /* U+8B5E [2000] */ + {0xe8ad9f, 0xe69f}, /* U+8B5F */ + {0xe8ada6, 0x8c78}, /* U+8B66 */ + {0xe8ada9, 0xeeb2}, /* U+8B69 [2000] */ + {0xe8adab, 0xe69e}, /* U+8B6B */ + {0xe8adac, 0xe6a0}, /* U+8B6C */ + {0xe8adaf, 0xe6a1}, /* U+8B6F */ + {0xe8adb0, 0x8b63}, /* U+8B70 */ + {0xe8adb1, 0xe3bf}, /* U+8B71 */ + {0xe8adb2, 0x8ff7}, /* U+8B72 */ + {0xe8adb4, 0xe6a2}, /* U+8B74 */ + {0xe8adb6, 0xf9ec}, /* U+8B76 [2000] */ + {0xe8adb7, 0x8cec}, /* U+8B77 */ + {0xe8adbd, 0xe6a3}, /* U+8B7D */ + {0xe8adbf, 0xf9ed}, /* U+8B7F [2000] */ + {0xe8ae80, 0xe6a4}, /* U+8B80 */ + {0xe8ae81, 0xf9ee}, /* U+8B81 [2000] */ + {0xe8ae83, 0x8e5d}, /* U+8B83 */ + {0xe8ae8a, 0x9dcc}, /* U+8B8A */ + {0xe8ae8b, 0xf9ef}, /* U+8B8B [2000] */ + {0xe8ae8c, 0xe6a5}, /* U+8B8C */ + {0xe8ae8e, 0xe6a6}, /* U+8B8E */ + {0xe8ae90, 0x8f51}, /* U+8B90 */ + {0xe8ae92, 0xe6a7}, /* U+8B92 */ + {0xe8ae93, 0xe6a8}, /* U+8B93 */ + {0xe8ae94, 0xf9f0}, /* U+8B94 [2000] */ + {0xe8ae95, 0xf9f1}, /* U+8B95 [2000] */ + {0xe8ae96, 0xe6a9}, /* U+8B96 */ + {0xe8ae99, 0xe6aa}, /* U+8B99 */ + {0xe8ae9a, 0xe6ab}, /* U+8B9A */ + {0xe8ae9c, 0xf9f2}, /* U+8B9C [2000] */ + {0xe8ae9d, 0xeeb3}, /* U+8B9D [2000] */ + {0xe8ae9e, 0xf9f3}, /* U+8B9E [2000] */ + {0xe8b0b7, 0x924a}, /* U+8C37 */ + {0xe8b0b9, 0xf9f4}, /* U+8C39 [2000] */ + {0xe8b0ba, 0xe6ac}, /* U+8C3A */ + {0xe8b0bd, 0xf9f6}, /* U+8C3D [2000] */ + {0xe8b0bf, 0xe6ae}, /* U+8C3F */ + {0xe8b181, 0xe6ad}, /* U+8C41 */ + {0xe8b185, 0xf9f9}, /* U+8C45 [2000] */ + {0xe8b186, 0x93a4}, /* U+8C46 */ + {0xe8b187, 0xf9fa}, /* U+8C47 [2000] */ + {0xe8b188, 0xe6af}, /* U+8C48 */ + {0xe8b189, 0xeeb4}, /* U+8C49 [2000] */ + {0xe8b18a, 0x964c}, /* U+8C4A */ + {0xe8b18c, 0xe6b0}, /* U+8C4C */ + {0xe8b18e, 0xe6b1}, /* U+8C4E */ + {0xe8b18f, 0xf9fb}, /* U+8C4F [2000] */ + {0xe8b190, 0xe6b2}, /* U+8C50 */ + {0xe8b194, 0xf9fc}, /* U+8C54 [2000] */ + {0xe8b195, 0xe6b3}, /* U+8C55 */ + {0xe8b197, 0xfa40}, /* U+8C57 [2000] */ + {0xe8b19a, 0x93d8}, /* U+8C5A */ + {0xe8b1a1, 0x8fdb}, /* U+8C61 */ + {0xe8b1a2, 0xe6b4}, /* U+8C62 */ + {0xe8b1a8, 0xeeb5}, /* U+8C68 [2000] */ + {0xe8b1a9, 0xfa41}, /* U+8C69 [2000] */ + {0xe8b1aa, 0x8d8b}, /* U+8C6A */ + {0xe8b1ab, 0x98ac}, /* U+8C6B */ + {0xe8b1ac, 0xe6b5}, /* U+8C6C */ + {0xe8b1ad, 0xfa42}, /* U+8C6D [2000] */ + {0xe8b1b3, 0xfa43}, /* U+8C73 [2000] */ + {0xe8b1b8, 0xe6b6}, /* U+8C78 */ + {0xe8b1b9, 0x955e}, /* U+8C79 */ + {0xe8b1ba, 0xe6b7}, /* U+8C7A */ + {0xe8b1bc, 0xe6bf}, /* U+8C7C */ + {0xe8b282, 0xe6b8}, /* U+8C82 */ + {0xe8b285, 0xe6ba}, /* U+8C85 */ + {0xe8b289, 0xe6b9}, /* U+8C89 */ + {0xe8b28a, 0xe6bb}, /* U+8C8A */ + {0xe8b28c, 0x9665}, /* U+8C8C */ + {0xe8b28d, 0xe6bc}, /* U+8C8D */ + {0xe8b28e, 0xe6bd}, /* U+8C8E */ + {0xe8b292, 0xfa46}, /* U+8C92 [2000] */ + {0xe8b293, 0xfa45}, /* U+8C93 [2000] */ + {0xe8b294, 0xe6be}, /* U+8C94 */ + {0xe8b298, 0xe6c0}, /* U+8C98 */ + {0xe8b299, 0xfa47}, /* U+8C99 [2000] */ + {0xe8b29b, 0xfa49}, /* U+8C9B [2000] */ + {0xe8b29d, 0x8a4c}, /* U+8C9D */ + {0xe8b29e, 0x92e5}, /* U+8C9E */ + {0xe8b2a0, 0x9589}, /* U+8CA0 */ + {0xe8b2a1, 0x8de0}, /* U+8CA1 */ + {0xe8b2a2, 0x8d76}, /* U+8CA2 */ + {0xe8b2a4, 0xfa4a}, /* U+8CA4 [2000] */ + {0xe8b2a7, 0x956e}, /* U+8CA7 */ + {0xe8b2a8, 0x89dd}, /* U+8CA8 */ + {0xe8b2a9, 0x94cc}, /* U+8CA9 */ + {0xe8b2aa, 0xe6c3}, /* U+8CAA */ + {0xe8b2ab, 0x8ad1}, /* U+8CAB */ + {0xe8b2ac, 0x90d3}, /* U+8CAC */ + {0xe8b2ad, 0xe6c2}, /* U+8CAD */ + {0xe8b2ae, 0xe6c7}, /* U+8CAE */ + {0xe8b2af, 0x9299}, /* U+8CAF */ + {0xe8b2b0, 0x96e1}, /* U+8CB0 */ + {0xe8b2b2, 0xe6c5}, /* U+8CB2 */ + {0xe8b2b3, 0xe6c6}, /* U+8CB3 */ + {0xe8b2b4, 0x8b4d}, /* U+8CB4 */ + {0xe8b2b6, 0xe6c8}, /* U+8CB6 */ + {0xe8b2b7, 0x9483}, /* U+8CB7 */ + {0xe8b2b8, 0x91dd}, /* U+8CB8 */ + {0xe8b2bb, 0x94ef}, /* U+8CBB */ + {0xe8b2bc, 0x935c}, /* U+8CBC */ + {0xe8b2bd, 0xe6c4}, /* U+8CBD */ + {0xe8b2bf, 0x9666}, /* U+8CBF */ + {0xe8b380, 0x89ea}, /* U+8CC0 */ + {0xe8b381, 0xe6ca}, /* U+8CC1 */ + {0xe8b382, 0x9847}, /* U+8CC2 */ + {0xe8b383, 0x92c0}, /* U+8CC3 */ + {0xe8b384, 0x9864}, /* U+8CC4 */ + {0xe8b387, 0x8e91}, /* U+8CC7 */ + {0xe8b388, 0xe6c9}, /* U+8CC8 */ + {0xe8b38a, 0x91af}, /* U+8CCA */ + {0xe8b38d, 0xe6da}, /* U+8CCD */ + {0xe8b38e, 0x9147}, /* U+8CCE */ + {0xe8b391, 0x93f6}, /* U+8CD1 */ + {0xe8b393, 0x956f}, /* U+8CD3 */ + {0xe8b395, 0xfa4c}, /* U+8CD5 [2000] */ + {0xe8b396, 0xfa4b}, /* U+8CD6 [2000] */ + {0xe8b399, 0xfa4d}, /* U+8CD9 [2000] */ + {0xe8b39a, 0xe6cd}, /* U+8CDA */ + {0xe8b39b, 0x8e5e}, /* U+8CDB */ + {0xe8b39c, 0x8e92}, /* U+8CDC */ + {0xe8b39e, 0x8fdc}, /* U+8CDE */ + {0xe8b3a0, 0x9485}, /* U+8CE0 */ + {0xe8b3a1, 0xeeb7}, /* U+8CE1 [2000] */ + {0xe8b3a2, 0x8cab}, /* U+8CE2 */ + {0xe8b3a3, 0xe6cc}, /* U+8CE3 */ + {0xe8b3a4, 0xe6cb}, /* U+8CE4 */ + {0xe8b3a6, 0x958a}, /* U+8CE6 */ + {0xe8b3aa, 0x8ebf}, /* U+8CEA */ + {0xe8b3ad, 0x9371}, /* U+8CED */ + {0xe8b3b0, 0xfa4f}, /* U+8CF0 [2000] */ + {0xe8b3b1, 0xfa50}, /* U+8CF1 [2000] */ + {0xe8b3b4, 0xeeb8}, /* U+8CF4 [2000] */ + {0xe8b3b8, 0xeeb9}, /* U+8CF8 [2000] */ + {0xe8b3ba, 0xe6cf}, /* U+8CFA */ + {0xe8b3bb, 0xe6d0}, /* U+8CFB */ + {0xe8b3bc, 0x8d77}, /* U+8CFC */ + {0xe8b3bd, 0xe6ce}, /* U+8CFD */ + {0xe8b3be, 0xeeba}, /* U+8CFE [2000] */ + {0xe8b484, 0xe6d1}, /* U+8D04 */ + {0xe8b485, 0xe6d2}, /* U+8D05 */ + {0xe8b487, 0xe6d4}, /* U+8D07 */ + {0xe8b488, 0x91a1}, /* U+8D08 */ + {0xe8b489, 0xfa52}, /* U+8D09 [2000] */ + {0xe8b48a, 0xe6d3}, /* U+8D0A */ + {0xe8b48b, 0x8ae4}, /* U+8D0B */ + {0xe8b48d, 0xe6d6}, /* U+8D0D */ + {0xe8b48e, 0xfa53}, /* U+8D0E [2000] */ + {0xe8b48f, 0xe6d5}, /* U+8D0F */ + {0xe8b490, 0xe6d7}, /* U+8D10 */ + {0xe8b492, 0xeebc}, /* U+8D12 [2000] */ + {0xe8b493, 0xe6d9}, /* U+8D13 */ + {0xe8b494, 0xe6db}, /* U+8D14 */ + {0xe8b496, 0xe6dc}, /* U+8D16 */ + {0xe8b49b, 0xeebd}, /* U+8D1B [2000] */ + {0xe8b5a4, 0x90d4}, /* U+8D64 */ + {0xe8b5a6, 0x8ecd}, /* U+8D66 */ + {0xe8b5a7, 0xe6dd}, /* U+8D67 */ + {0xe8b5ab, 0x8a71}, /* U+8D6B */ + {0xe8b5ac, 0xfa54}, /* U+8D6C [2000] */ + {0xe8b5ad, 0xe6de}, /* U+8D6D */ + {0xe8b5b0, 0x9196}, /* U+8D70 */ + {0xe8b5b1, 0xe6df}, /* U+8D71 */ + {0xe8b5b3, 0xe6e0}, /* U+8D73 */ + {0xe8b5b4, 0x958b}, /* U+8D74 */ + {0xe8b5b7, 0x8b4e}, /* U+8D77 */ + {0xe8b681, 0xe6e1}, /* U+8D81 */ + {0xe8b684, 0xfa55}, /* U+8D84 [2000] */ + {0xe8b685, 0x92b4}, /* U+8D85 */ + {0xe8b68a, 0x897a}, /* U+8D8A */ + {0xe8b695, 0xfa56}, /* U+8D95 [2000] */ + {0xe8b699, 0xe6e2}, /* U+8D99 */ + {0xe8b6a3, 0x8eef}, /* U+8DA3 */ + {0xe8b6a6, 0xfa57}, /* U+8DA6 [2000] */ + {0xe8b6a8, 0x9096}, /* U+8DA8 */ + {0xe8b6af, 0xeebe}, /* U+8DAF [2000] */ + {0xe8b6b3, 0x91ab}, /* U+8DB3 */ + {0xe8b6ba, 0xe6e5}, /* U+8DBA */ + {0xe8b6be, 0xe6e4}, /* U+8DBE */ + {0xe8b782, 0xe6e3}, /* U+8DC2 */ + {0xe8b786, 0xfa59}, /* U+8DC6 [2000] */ + {0xe8b788, 0xfa5a}, /* U+8DC8 [2000] */ + {0xe8b78b, 0xe6eb}, /* U+8DCB */ + {0xe8b78c, 0xe6e9}, /* U+8DCC */ + {0xe8b78e, 0xeebf}, /* U+8DCE [2000] */ + {0xe8b78f, 0xe6e6}, /* U+8DCF */ + {0xe8b791, 0xeec0}, /* U+8DD1 [2000] */ + {0xe8b796, 0xe6e8}, /* U+8DD6 */ + {0xe8b797, 0xeec1}, /* U+8DD7 [2000] */ + {0xe8b799, 0xfa5b}, /* U+8DD9 [2000] */ + {0xe8b79a, 0xe6e7}, /* U+8DDA */ + {0xe8b79b, 0xe6ea}, /* U+8DDB */ + {0xe8b79d, 0x8b97}, /* U+8DDD */ + {0xe8b79f, 0xe6ee}, /* U+8DDF */ + {0xe8b7a1, 0x90d5}, /* U+8DE1 */ + {0xe8b7a3, 0xe6ef}, /* U+8DE3 */ + {0xe8b7a8, 0x8cd7}, /* U+8DE8 */ + {0xe8b7aa, 0xe6ec}, /* U+8DEA */ + {0xe8b7ab, 0xe6ed}, /* U+8DEB */ + {0xe8b7ac, 0xfa5c}, /* U+8DEC [2000] */ + {0xe8b7af, 0x9848}, /* U+8DEF */ + {0xe8b7b3, 0x92b5}, /* U+8DF3 */ + {0xe8b7b5, 0x9148}, /* U+8DF5 */ + {0xe8b7bc, 0xe6f0}, /* U+8DFC */ + {0xe8b7bd, 0xfa5f}, /* U+8DFD [2000] */ + {0xe8b7bf, 0xe6f3}, /* U+8DFF */ + {0xe8b886, 0xfa60}, /* U+8E06 [2000] */ + {0xe8b888, 0xe6f1}, /* U+8E08 */ + {0xe8b889, 0xe6f2}, /* U+8E09 */ + {0xe8b88a, 0x9778}, /* U+8E0A */ + {0xe8b88c, 0xfa5d}, /* U+8E0C [2000] */ + {0xe8b88f, 0x93a5}, /* U+8E0F */ + {0xe8b890, 0xe6f6}, /* U+8E10 */ + {0xe8b894, 0xfa62}, /* U+8E14 [2000] */ + {0xe8b896, 0xfa63}, /* U+8E16 [2000] */ + {0xe8b89d, 0xe6f4}, /* U+8E1D */ + {0xe8b89e, 0xe6f5}, /* U+8E1E */ + {0xe8b89f, 0xe6f7}, /* U+8E1F */ + {0xe8b8a0, 0xeec2}, /* U+8E20 [2000] */ + {0xe8b8a1, 0xfa64}, /* U+8E21 [2000] */ + {0xe8b8a2, 0xfa65}, /* U+8E22 [2000] */ + {0xe8b8a3, 0xeec3}, /* U+8E23 [2000] */ + {0xe8b8a7, 0xfa66}, /* U+8E27 [2000] */ + {0xe8b8aa, 0xe748}, /* U+8E2A */ + {0xe8b8b0, 0xe6fa}, /* U+8E30 */ + {0xe8b8b4, 0xe6fb}, /* U+8E34 */ + {0xe8b8b5, 0xe6f9}, /* U+8E35 */ + {0xe8b8b6, 0xfa69}, /* U+8E36 [2000] */ + {0xe8b8b9, 0xfa6a}, /* U+8E39 [2000] */ + {0xe8b8bd, 0xeec4}, /* U+8E3D [2000] */ + {0xe8b982, 0xe6f8}, /* U+8E42 */ + {0xe8b984, 0x92fb}, /* U+8E44 */ + {0xe8b987, 0xe740}, /* U+8E47 */ + {0xe8b988, 0xe744}, /* U+8E48 */ + {0xe8b989, 0xe741}, /* U+8E49 */ + {0xe8b98a, 0xe6fc}, /* U+8E4A */ + {0xe8b98b, 0xfa6b}, /* U+8E4B [2000] */ + {0xe8b98c, 0xe742}, /* U+8E4C */ + {0xe8b990, 0xe743}, /* U+8E50 */ + {0xe8b994, 0xfa6c}, /* U+8E54 [2000] */ + {0xe8b995, 0xe74a}, /* U+8E55 */ + {0xe8b999, 0xe745}, /* U+8E59 */ + {0xe8b99f, 0x90d6}, /* U+8E5F */ + {0xe8b9a0, 0xe747}, /* U+8E60 */ + {0xe8b9a2, 0xfa6d}, /* U+8E62 [2000] */ + {0xe8b9a3, 0xe749}, /* U+8E63 */ + {0xe8b9a4, 0xe746}, /* U+8E64 */ + {0xe8b9ac, 0xfa6e}, /* U+8E6C [2000] */ + {0xe8b9ad, 0xfa6f}, /* U+8E6D [2000] */ + {0xe8b9af, 0xfa70}, /* U+8E6F [2000] */ + {0xe8b9b0, 0xeec5}, /* U+8E70 [2000] */ + {0xe8b9b2, 0xe74c}, /* U+8E72 */ + {0xe8b9b4, 0x8f52}, /* U+8E74 */ + {0xe8b9b6, 0xe74b}, /* U+8E76 */ + {0xe8b9bb, 0xeec6}, /* U+8E7B [2000] */ + {0xe8b9bc, 0xe74d}, /* U+8E7C */ + {0xe8ba81, 0xe74e}, /* U+8E81 */ + {0xe8ba84, 0xe751}, /* U+8E84 */ + {0xe8ba85, 0xe750}, /* U+8E85 */ + {0xe8ba87, 0xe74f}, /* U+8E87 */ + {0xe8ba8a, 0xe753}, /* U+8E8A */ + {0xe8ba8b, 0xe752}, /* U+8E8B */ + {0xe8ba8d, 0x96f4}, /* U+8E8D */ + {0xe8ba91, 0xe755}, /* U+8E91 */ + {0xe8ba93, 0xe754}, /* U+8E93 */ + {0xe8ba94, 0xe756}, /* U+8E94 */ + {0xe8ba98, 0xfa71}, /* U+8E98 [2000] */ + {0xe8ba99, 0xe757}, /* U+8E99 */ + {0xe8ba9e, 0xfa72}, /* U+8E9E [2000] */ + {0xe8baa1, 0xe759}, /* U+8EA1 */ + {0xe8baaa, 0xe758}, /* U+8EAA */ + {0xe8baab, 0x9067}, /* U+8EAB */ + {0xe8baac, 0xe75a}, /* U+8EAC */ + {0xe8baae, 0xfa73}, /* U+8EAE [2000] */ + {0xe8baaf, 0x8beb}, /* U+8EAF */ + {0xe8bab0, 0xe75b}, /* U+8EB0 */ + {0xe8bab1, 0xe75d}, /* U+8EB1 */ + {0xe8bab3, 0xfa74}, /* U+8EB3 [2000] */ + {0xe8bab5, 0xfa75}, /* U+8EB5 [2000] */ + {0xe8bab6, 0xfa76}, /* U+8EB6 [2000] */ + {0xe8babb, 0xfa77}, /* U+8EBB [2000] */ + {0xe8babe, 0xe75e}, /* U+8EBE */ + {0xe8bb80, 0xeec8}, /* U+8EC0 [2000] */ + {0xe8bb85, 0xe75f}, /* U+8EC5 */ + {0xe8bb86, 0xe75c}, /* U+8EC6 */ + {0xe8bb88, 0xe760}, /* U+8EC8 */ + {0xe8bb8a, 0x8ed4}, /* U+8ECA */ + {0xe8bb8b, 0xe761}, /* U+8ECB */ + {0xe8bb8c, 0x8b4f}, /* U+8ECC */ + {0xe8bb8d, 0x8c52}, /* U+8ECD */ + {0xe8bb91, 0xfa79}, /* U+8ED1 [2000] */ + {0xe8bb92, 0x8cac}, /* U+8ED2 */ + {0xe8bb94, 0xfa7a}, /* U+8ED4 [2000] */ + {0xe8bb9b, 0xe762}, /* U+8EDB */ + {0xe8bb9f, 0x93ee}, /* U+8EDF */ + {0xe8bba2, 0x935d}, /* U+8EE2 */ + {0xe8bba3, 0xe763}, /* U+8EE3 */ + {0xe8bbab, 0xe766}, /* U+8EEB */ + {0xe8bbb8, 0x8eb2}, /* U+8EF8 */ + {0xe8bbb9, 0xfa7c}, /* U+8EF9 [2000] */ + {0xe8bbba, 0xeeca}, /* U+8EFA [2000] */ + {0xe8bbbb, 0xe765}, /* U+8EFB */ + {0xe8bbbc, 0xe764}, /* U+8EFC */ + {0xe8bbbd, 0x8c79}, /* U+8EFD */ + {0xe8bbbe, 0xe767}, /* U+8EFE */ + {0xe8bc80, 0xfa7e}, /* U+8F00 [2000] */ + {0xe8bc83, 0x8a72}, /* U+8F03 */ + {0xe8bc85, 0xe769}, /* U+8F05 */ + {0xe8bc88, 0xfa80}, /* U+8F08 [2000] */ + {0xe8bc89, 0x8dda}, /* U+8F09 */ + {0xe8bc8a, 0xe768}, /* U+8F0A */ + {0xe8bc8c, 0xe771}, /* U+8F0C */ + {0xe8bc92, 0xe76b}, /* U+8F12 */ + {0xe8bc93, 0xe76d}, /* U+8F13 */ + {0xe8bc94, 0x95e3}, /* U+8F14 */ + {0xe8bc95, 0xe76a}, /* U+8F15 */ + {0xe8bc97, 0xfa81}, /* U+8F17 [2000] */ + {0xe8bc99, 0xe76c}, /* U+8F19 */ + {0xe8bc9b, 0xe770}, /* U+8F1B */ + {0xe8bc9c, 0xe76e}, /* U+8F1C */ + {0xe8bc9d, 0x8b50}, /* U+8F1D */ + {0xe8bc9e, 0xeecb}, /* U+8F1E [2000] */ + {0xe8bc9f, 0xe76f}, /* U+8F1F */ + {0xe8bca6, 0xe772}, /* U+8F26 */ + {0xe8bca9, 0x9479}, /* U+8F29 */ + {0xe8bcaa, 0x97d6}, /* U+8F2A */ + {0xe8bcab, 0xfa82}, /* U+8F2B [2000] */ + {0xe8bcad, 0xeecc}, /* U+8F2D [2000] */ + {0xe8bcaf, 0x8f53}, /* U+8F2F */ + {0xe8bcb3, 0xe773}, /* U+8F33 */ + {0xe8bcb6, 0xeecd}, /* U+8F36 [2000] */ + {0xe8bcb8, 0x9741}, /* U+8F38 */ + {0xe8bcb9, 0xe775}, /* U+8F39 */ + {0xe8bcbb, 0xe774}, /* U+8F3B */ + {0xe8bcbe, 0xe778}, /* U+8F3E */ + {0xe8bcbf, 0x9760}, /* U+8F3F */ + {0xe8bd80, 0xfa83}, /* U+8F40 [2000] */ + {0xe8bd82, 0xe777}, /* U+8F42 */ + {0xe8bd84, 0x8a8d}, /* U+8F44 */ + {0xe8bd85, 0xe776}, /* U+8F45 */ + {0xe8bd86, 0xe77b}, /* U+8F46 */ + {0xe8bd89, 0xe77a}, /* U+8F49 */ + {0xe8bd8a, 0xfa84}, /* U+8F4A [2000] */ + {0xe8bd8c, 0xe779}, /* U+8F4C */ + {0xe8bd8d, 0x9351}, /* U+8F4D */ + {0xe8bd8e, 0xe77c}, /* U+8F4E */ + {0xe8bd94, 0xeece}, /* U+8F54 [2000] */ + {0xe8bd97, 0xe77d}, /* U+8F57 */ + {0xe8bd98, 0xfa85}, /* U+8F58 [2000] */ + {0xe8bd9c, 0xe77e}, /* U+8F5C */ + {0xe8bd9f, 0x8d8c}, /* U+8F5F */ + {0xe8bda1, 0x8c44}, /* U+8F61 */ + {0xe8bda2, 0xe780}, /* U+8F62 */ + {0xe8bda3, 0xe781}, /* U+8F63 */ + {0xe8bda4, 0xe782}, /* U+8F64 */ + {0xe8be9b, 0x9068}, /* U+8F9B */ + {0xe8be9c, 0xe783}, /* U+8F9C */ + {0xe8be9e, 0x8eab}, /* U+8F9E */ + {0xe8be9f, 0xe784}, /* U+8F9F */ + {0xe8bea3, 0xe785}, /* U+8FA3 */ + {0xe8bea4, 0xfa87}, /* U+8FA4 [2000] */ + {0xe8bea6, 0xeed0}, /* U+8FA6 [2000] */ + {0xe8bea7, 0x999f}, /* U+8FA7 */ + {0xe8bea8, 0x999e}, /* U+8FA8 */ + {0xe8bead, 0xe786}, /* U+8FAD */ + {0xe8beae, 0xe390}, /* U+8FAE */ + {0xe8beaf, 0xe787}, /* U+8FAF */ + {0xe8beb0, 0x9243}, /* U+8FB0 */ + {0xe8beb1, 0x904a}, /* U+8FB1 */ + {0xe8beb2, 0x945f}, /* U+8FB2 */ + {0xe8beb4, 0xfa88}, /* U+8FB4 [2000] */ + {0xe8beb5, 0xeed1}, /* U+8FB5 [2000] */ + {0xe8beb6, 0xfa8a}, /* U+8FB6 [2000] */ + {0xe8beb7, 0xe788}, /* U+8FB7 */ + {0xe8beba, 0x95d3}, /* U+8FBA */ + {0xe8bebb, 0x92d2}, /* U+8FBB */ + {0xe8bebc, 0x8d9e}, /* U+8FBC */ + {0xe8bebf, 0x9248}, /* U+8FBF */ + {0xe8bf81, 0xfa8c}, /* U+8FC1 [2000] */ + {0xe8bf82, 0x8949}, /* U+8FC2 */ + {0xe8bf84, 0x9698}, /* U+8FC4 */ + {0xe8bf85, 0x9076}, /* U+8FC5 */ + {0xe8bf86, 0xfa8d}, /* U+8FC6 [2000] */ + {0xe8bf8a, 0xfa8f}, /* U+8FCA [2000] */ + {0xe8bf8d, 0xfa90}, /* U+8FCD [2000] */ + {0xe8bf8e, 0x8c7d}, /* U+8FCE */ + {0xe8bf91, 0x8bdf}, /* U+8FD1 */ + {0xe8bf93, 0xfa91}, /* U+8FD3 [2000] */ + {0xe8bf94, 0x95d4}, /* U+8FD4 */ + {0xe8bf95, 0xfa92}, /* U+8FD5 [2000] */ + {0xe8bf9a, 0xe789}, /* U+8FDA */ + {0xe8bfa0, 0xfa93}, /* U+8FE0 [2000] */ + {0xe8bfa2, 0xe78b}, /* U+8FE2 */ + {0xe8bfa4, 0xeed2}, /* U+8FE4 [2000] */ + {0xe8bfa5, 0xe78a}, /* U+8FE5 */ + {0xe8bfa6, 0x89de}, /* U+8FE6 */ + {0xe8bfa8, 0xeed3}, /* U+8FE8 [2000] */ + {0xe8bfa9, 0x93f4}, /* U+8FE9 */ + {0xe8bfaa, 0xe78c}, /* U+8FEA */ + {0xe8bfab, 0x9497}, /* U+8FEB */ + {0xe8bfad, 0x9352}, /* U+8FED */ + {0xe8bfae, 0xeed4}, /* U+8FEE [2000] */ + {0xe8bfaf, 0xe78d}, /* U+8FEF */ + {0xe8bfb0, 0x8f71}, /* U+8FF0 */ + {0xe8bfb1, 0xfa94}, /* U+8FF1 [2000] */ + {0xe8bfb4, 0xe78f}, /* U+8FF4 */ + {0xe8bfb5, 0xfa95}, /* U+8FF5 [2000] */ + {0xe8bfb7, 0x96c0}, /* U+8FF7 */ + {0xe8bfb8, 0xe79e}, /* U+8FF8 */ + {0xe8bfb9, 0xe791}, /* U+8FF9 */ + {0xe8bfba, 0xe792}, /* U+8FFA */ + {0xe8bfbb, 0xfa96}, /* U+8FFB [2000] */ + {0xe8bfbd, 0x92c7}, /* U+8FFD */ + {0xe98080, 0x91de}, /* U+9000 */ + {0xe98081, 0x9197}, /* U+9001 */ + {0xe98082, 0xfa97}, /* U+9002 [2000] */ + {0xe98083, 0x93a6}, /* U+9003 */ + {0xe98085, 0xe790}, /* U+9005 */ + {0xe98086, 0x8b74}, /* U+9006 */ + {0xe98088, 0xeed5}, /* U+9008 [2000] */ + {0xe9808b, 0xe799}, /* U+900B */ + {0xe9808c, 0xfa98}, /* U+900C [2000] */ + {0xe9808d, 0xe796}, /* U+900D */ + {0xe9808e, 0xe7a3}, /* U+900E */ + {0xe9808f, 0x93a7}, /* U+900F */ + {0xe98090, 0x9280}, /* U+9010 */ + {0xe98091, 0xe793}, /* U+9011 */ + {0xe98093, 0x92fc}, /* U+9013 */ + {0xe98094, 0x9372}, /* U+9014 */ + {0xe98095, 0xe794}, /* U+9015 */ + {0xe98096, 0xe798}, /* U+9016 */ + {0xe98097, 0x9080}, /* U+9017 */ + {0xe98099, 0x9487}, /* U+9019 */ + {0xe9809a, 0x92ca}, /* U+901A */ + {0xe9809d, 0x90c0}, /* U+901D */ + {0xe9809e, 0xe797}, /* U+901E */ + {0xe9809f, 0x91ac}, /* U+901F */ + {0xe980a0, 0x91a2}, /* U+9020 */ + {0xe980a1, 0xe795}, /* U+9021 */ + {0xe980a2, 0x88a7}, /* U+9022 */ + {0xe980a3, 0x9841}, /* U+9023 */ + {0xe980a7, 0xe79a}, /* U+9027 */ + {0xe980ad, 0xeed6}, /* U+902D [2000] */ + {0xe980ae, 0x91df}, /* U+902E */ + {0xe980b1, 0x8f54}, /* U+9031 */ + {0xe980b2, 0x9069}, /* U+9032 */ + {0xe980b5, 0xe79c}, /* U+9035 */ + {0xe980b6, 0xe79b}, /* U+9036 */ + {0xe980b7, 0xfa99}, /* U+9037 [2000] */ + {0xe980b8, 0x88ed}, /* U+9038 */ + {0xe980b9, 0xe79d}, /* U+9039 */ + {0xe980bc, 0x954e}, /* U+903C */ + {0xe980be, 0xe7a5}, /* U+903E */ + {0xe98181, 0x93d9}, /* U+9041 */ + {0xe98182, 0x908b}, /* U+9042 */ + {0xe98183, 0xfa9b}, /* U+9043 [2000] */ + {0xe98184, 0xfa9c}, /* U+9044 [2000] */ + {0xe98185, 0x9278}, /* U+9045 */ + {0xe98187, 0x8bf6}, /* U+9047 */ + {0xe98189, 0xe7a4}, /* U+9049 */ + {0xe9818a, 0x9756}, /* U+904A */ + {0xe9818b, 0x895e}, /* U+904B */ + {0xe9818d, 0x95d5}, /* U+904D */ + {0xe9818e, 0x89df}, /* U+904E */ + {0xe9818f, 0xe79f}, /* U+904F */ + {0xe98190, 0xe7a0}, /* U+9050 */ + {0xe98191, 0xe7a1}, /* U+9051 */ + {0xe98192, 0xe7a2}, /* U+9052 */ + {0xe98193, 0x93b9}, /* U+9053 */ + {0xe98194, 0x9242}, /* U+9054 */ + {0xe98195, 0x88e1}, /* U+9055 */ + {0xe98196, 0xe7a6}, /* U+9056 */ + {0xe98198, 0xe7a7}, /* U+9058 */ + {0xe98199, 0xeaa1}, /* U+9059 [1983] */ + {0xe9819c, 0x91bb}, /* U+905C */ + {0xe9819d, 0xfa9d}, /* U+905D [2000] */ + {0xe9819e, 0xe7a8}, /* U+905E */ + {0xe981a0, 0x8993}, /* U+9060 */ + {0xe981a1, 0x916b}, /* U+9061 */ + {0xe981a3, 0x8cad}, /* U+9063 */ + {0xe981a5, 0x9779}, /* U+9065 */ + {0xe981a8, 0xe7a9}, /* U+9068 */ + {0xe981a9, 0x934b}, /* U+9069 */ + {0xe981ad, 0x9198}, /* U+906D */ + {0xe981ae, 0x8ed5}, /* U+906E */ + {0xe981af, 0xe7aa}, /* U+906F */ + {0xe981b2, 0xe7ad}, /* U+9072 */ + {0xe981b5, 0x8f85}, /* U+9075 */ + {0xe981b6, 0xe7ab}, /* U+9076 */ + {0xe981b7, 0x914a}, /* U+9077 */ + {0xe981b8, 0x9149}, /* U+9078 */ + {0xe981ba, 0x88e2}, /* U+907A */ + {0xe981bc, 0x97c9}, /* U+907C */ + {0xe981bd, 0xe7af}, /* U+907D */ + {0xe981bf, 0x94f0}, /* U+907F */ + {0xe98280, 0xe7b1}, /* U+9080 */ + {0xe98281, 0xe7b0}, /* U+9081 */ + {0xe98282, 0xe7ae}, /* U+9082 */ + {0xe98283, 0xe284}, /* U+9083 */ + {0xe98284, 0x8ad2}, /* U+9084 */ + {0xe98285, 0xfaa0}, /* U+9085 [2000] */ + {0xe98287, 0xe78e}, /* U+9087 */ + {0xe98288, 0xeed8}, /* U+9088 [2000] */ + {0xe98289, 0xe7b3}, /* U+9089 */ + {0xe9828a, 0xe7b2}, /* U+908A */ + {0xe9828c, 0xfaa1}, /* U+908C [2000] */ + {0xe9828f, 0xe7b4}, /* U+908F */ + {0xe98290, 0xfaa2}, /* U+9090 [2000] */ + {0xe98291, 0x9757}, /* U+9091 */ + {0xe98295, 0xeed9}, /* U+9095 [2000] */ + {0xe98297, 0xeeda}, /* U+9097 [2000] */ + {0xe98299, 0xeedb}, /* U+9099 [2000] */ + {0xe9829b, 0xeedc}, /* U+909B [2000] */ + {0xe982a1, 0xfaa4}, /* U+90A1 [2000] */ + {0xe982a2, 0xeedd}, /* U+90A2 [2000] */ + {0xe982a3, 0x93df}, /* U+90A3 */ + {0xe982a6, 0x964d}, /* U+90A6 */ + {0xe982a8, 0xe7b5}, /* U+90A8 */ + {0xe982aa, 0x8ed7}, /* U+90AA */ + {0xe982af, 0xe7b6}, /* U+90AF */ + {0xe982b0, 0xfaa6}, /* U+90B0 [2000] */ + {0xe982b1, 0xe7b7}, /* U+90B1 */ + {0xe982b3, 0xeede}, /* U+90B3 [2000] */ + {0xe982b5, 0xe7b8}, /* U+90B5 */ + {0xe982b6, 0xfaa7}, /* U+90B6 [2000] */ + {0xe982b8, 0x9340}, /* U+90B8 */ + {0xe982be, 0xeedf}, /* U+90BE [2000] */ + {0xe98381, 0x88e8}, /* U+90C1 */ + {0xe98383, 0xfaa8}, /* U+90C3 [2000] */ + {0xe98384, 0xeee0}, /* U+90C4 [2000] */ + {0xe98385, 0xeee1}, /* U+90C5 [2000] */ + {0xe98387, 0xeee2}, /* U+90C7 [2000] */ + {0xe98388, 0xfaa9}, /* U+90C8 [2000] */ + {0xe9838a, 0x8d78}, /* U+90CA */ + {0xe9838e, 0x9859}, /* U+90CE */ + {0xe98397, 0xeee3}, /* U+90D7 [2000] */ + {0xe9839b, 0xe7bc}, /* U+90DB */ + {0xe9839c, 0xfaab}, /* U+90DC [2000] */ + {0xe9839d, 0xeee4}, /* U+90DD [2000] */ + {0xe9839e, 0xeee5}, /* U+90DE [2000] */ + {0xe9839f, 0xfaac}, /* U+90DF [2000] */ + {0xe983a1, 0x8c53}, /* U+90E1 */ + {0xe983a2, 0xe7b9}, /* U+90E2 */ + {0xe983a4, 0xe7ba}, /* U+90E4 */ + {0xe983a8, 0x9594}, /* U+90E8 */ + {0xe983ab, 0xfab1}, /* U+90EB [2000] */ + {0xe983ad, 0x8a73}, /* U+90ED */ + {0xe983af, 0xeee6}, /* U+90EF [2000] */ + {0xe983b2, 0xfaaf}, /* U+90F2 [2000] */ + {0xe983b4, 0xeee7}, /* U+90F4 [2000] */ + {0xe983b5, 0x9758}, /* U+90F5 */ + {0xe983b6, 0xfaae}, /* U+90F6 [2000] */ + {0xe983b7, 0x8bbd}, /* U+90F7 */ + {0xe983bd, 0x9373}, /* U+90FD */ + {0xe983be, 0xfab2}, /* U+90FE [2000] */ + {0xe983bf, 0xfab3}, /* U+90FF [2000] */ + {0xe98480, 0xfab0}, /* U+9100 [2000] */ + {0xe98482, 0xe7bd}, /* U+9102 */ + {0xe98484, 0xfab4}, /* U+9104 [2000] */ + {0xe98486, 0xfab5}, /* U+9106 [2000] */ + {0xe98492, 0xe7be}, /* U+9112 */ + {0xe98494, 0xeee9}, /* U+9114 [2000] */ + {0xe98495, 0xeeea}, /* U+9115 [2000] */ + {0xe98496, 0xeeeb}, /* U+9116 [2000] */ + {0xe98498, 0xfab6}, /* U+9118 [2000] */ + {0xe98499, 0xe7bf}, /* U+9119 */ + {0xe9849c, 0xfab7}, /* U+911C [2000] */ + {0xe9849e, 0xfab8}, /* U+911E [2000] */ + {0xe984a2, 0xeeec}, /* U+9122 [2000] */ + {0xe984a3, 0xeeed}, /* U+9123 [2000] */ + {0xe984a7, 0xeeee}, /* U+9127 [2000] */ + {0xe984ad, 0x9341}, /* U+912D */ + {0xe984af, 0xeeef}, /* U+912F [2000] */ + {0xe984b0, 0xe7c1}, /* U+9130 */ + {0xe984b1, 0xeef0}, /* U+9131 [2000] */ + {0xe984b2, 0xe7c0}, /* U+9132 */ + {0xe984b4, 0xeef1}, /* U+9134 [2000] */ + {0xe984b7, 0xfab9}, /* U+9137 [2000] */ + {0xe984b9, 0xfaba}, /* U+9139 [2000] */ + {0xe984ba, 0xfabb}, /* U+913A [2000] */ + {0xe984bd, 0xeef2}, /* U+913D [2000] */ + {0xe98586, 0xfabc}, /* U+9146 [2000] */ + {0xe98587, 0xfabd}, /* U+9147 [2000] */ + {0xe98588, 0xeef3}, /* U+9148 [2000] */ + {0xe98589, 0x93d1}, /* U+9149 */ + {0xe9858a, 0xe7c2}, /* U+914A */ + {0xe9858b, 0x8f55}, /* U+914B */ + {0xe9858c, 0x8ede}, /* U+914C */ + {0xe9858d, 0x947a}, /* U+914D */ + {0xe9858e, 0x9291}, /* U+914E */ + {0xe98592, 0x8ef0}, /* U+9152 */ + {0xe98594, 0x908c}, /* U+9154 */ + {0xe98596, 0xe7c3}, /* U+9156 */ + {0xe98597, 0xfabe}, /* U+9157 [2000] */ + {0xe98598, 0xe7c4}, /* U+9158 */ + {0xe98599, 0xfabf}, /* U+9159 [2000] */ + {0xe9859b, 0xeef4}, /* U+915B [2000] */ + {0xe985a1, 0xfac0}, /* U+9161 [2000] */ + {0xe985a2, 0x907c}, /* U+9162 */ + {0xe985a3, 0xe7c5}, /* U+9163 */ + {0xe985a4, 0xfac1}, /* U+9164 [2000] */ + {0xe985a5, 0xe7c6}, /* U+9165 */ + {0xe985a9, 0xe7c7}, /* U+9169 */ + {0xe985aa, 0x978f}, /* U+916A */ + {0xe985ac, 0x8f56}, /* U+916C */ + {0xe985b2, 0xe7c9}, /* U+9172 */ + {0xe985b3, 0xe7c8}, /* U+9173 */ + {0xe985b4, 0xfac2}, /* U+9174 [2000] */ + {0xe985b5, 0x8d79}, /* U+9175 */ + {0xe985b7, 0x8d93}, /* U+9177 */ + {0xe985b8, 0x8e5f}, /* U+9178 */ + {0xe985b9, 0xfac3}, /* U+9179 [2000] */ + {0xe98682, 0xe7cc}, /* U+9182 */ + {0xe98683, 0xeef5}, /* U+9183 [2000] */ + {0xe98685, 0xfac4}, /* U+9185 [2000] */ + {0xe98687, 0x8f86}, /* U+9187 */ + {0xe98689, 0xe7cb}, /* U+9189 */ + {0xe9868b, 0xe7ca}, /* U+918B */ + {0xe9868d, 0x91e7}, /* U+918D */ + {0xe9868e, 0xfac5}, /* U+918E [2000] */ + {0xe98690, 0x8ced}, /* U+9190 */ + {0xe98692, 0x90c1}, /* U+9192 */ + {0xe98697, 0x94ae}, /* U+9197 */ + {0xe9869c, 0x8f58}, /* U+919C */ + {0xe9869e, 0xeef6}, /* U+919E [2000] */ + {0xe986a2, 0xe7cd}, /* U+91A2 */ + {0xe986a4, 0x8fdd}, /* U+91A4 */ + {0xe986a8, 0xfac6}, /* U+91A8 [2000] */ + {0xe986aa, 0xe7d0}, /* U+91AA */ + {0xe986ab, 0xe7ce}, /* U+91AB */ + {0xe986ac, 0xeef7}, /* U+91AC [2000] */ + {0xe986ae, 0xfac7}, /* U+91AE [2000] */ + {0xe986af, 0xe7cf}, /* U+91AF */ + {0xe986b1, 0xeef8}, /* U+91B1 [2000] */ + {0xe986b3, 0xfac8}, /* U+91B3 [2000] */ + {0xe986b4, 0xe7d2}, /* U+91B4 */ + {0xe986b5, 0xe7d1}, /* U+91B5 */ + {0xe986b6, 0xfac9}, /* U+91B6 [2000] */ + {0xe986b8, 0x8ff8}, /* U+91B8 */ + {0xe986ba, 0xe7d3}, /* U+91BA */ + {0xe986bc, 0xeef9}, /* U+91BC [2000] */ + {0xe98780, 0xe7d4}, /* U+91C0 */ + {0xe98781, 0xe7d5}, /* U+91C1 */ + {0xe98783, 0xfaca}, /* U+91C3 [2000] */ + {0xe98784, 0xfacb}, /* U+91C4 [2000] */ + {0xe98786, 0x94ce}, /* U+91C6 */ + {0xe98787, 0x8dd1}, /* U+91C7 */ + {0xe98788, 0x8edf}, /* U+91C8 */ + {0xe98789, 0xe7d6}, /* U+91C9 */ + {0xe9878b, 0xe7d7}, /* U+91CB */ + {0xe9878c, 0x97a2}, /* U+91CC */ + {0xe9878d, 0x8f64}, /* U+91CD */ + {0xe9878e, 0x96ec}, /* U+91CE */ + {0xe9878f, 0x97ca}, /* U+91CF */ + {0xe98790, 0xe7d8}, /* U+91D0 */ + {0xe98791, 0x8be0}, /* U+91D1 */ + {0xe98796, 0xe7d9}, /* U+91D6 */ + {0xe98797, 0xeefa}, /* U+91D7 [2000] */ + {0xe98798, 0x9342}, /* U+91D8 */ + {0xe9879a, 0xfacc}, /* U+91DA [2000] */ + {0xe9879b, 0xe7dc}, /* U+91DB */ + {0xe9879c, 0x8a98}, /* U+91DC */ + {0xe9879d, 0x906a}, /* U+91DD */ + {0xe9879f, 0xe7da}, /* U+91DF */ + {0xe987a1, 0xe7db}, /* U+91E1 */ + {0xe987a3, 0x92de}, /* U+91E3 */ + {0xe987a4, 0xeefc}, /* U+91E4 [2000] */ + {0xe987a5, 0xef40}, /* U+91E5 [2000] */ + {0xe987a6, 0x9674}, /* U+91E6 */ + {0xe987a7, 0x8bfa}, /* U+91E7 */ + {0xe987ac, 0xfacf}, /* U+91EC [2000] */ + {0xe987ad, 0xef41}, /* U+91ED [2000] */ + {0xe987ae, 0xfad0}, /* U+91EE [2000] */ + {0xe987b1, 0xef42}, /* U+91F1 [2000] */ + {0xe987b5, 0xe7de}, /* U+91F5 */ + {0xe987b6, 0xe7df}, /* U+91F6 */ + {0xe987bb, 0xeefb}, /* U+91FB [2000] */ + {0xe987bc, 0xe7dd}, /* U+91FC */ + {0xe987bf, 0xe7e1}, /* U+91FF */ + {0xe98881, 0xfad1}, /* U+9201 [2000] */ + {0xe98887, 0xef43}, /* U+9207 [2000] */ + {0xe9888a, 0xfad2}, /* U+920A [2000] */ + {0xe9888d, 0x93dd}, /* U+920D */ + {0xe9888e, 0x8a62}, /* U+920E */ + {0xe98890, 0xef44}, /* U+9210 [2000] */ + {0xe98891, 0xe7e5}, /* U+9211 */ + {0xe98894, 0xe7e2}, /* U+9214 */ + {0xe98895, 0xe7e4}, /* U+9215 */ + {0xe98896, 0xfad3}, /* U+9216 [2000] */ + {0xe98897, 0xfad4}, /* U+9217 [2000] */ + {0xe9889e, 0xe7e0}, /* U+921E */ + {0xe988a9, 0xe86e}, /* U+9229 */ + {0xe988ac, 0xe7e3}, /* U+922C */ + {0xe988b3, 0xfad6}, /* U+9233 [2000] */ + {0xe988b4, 0x97e9}, /* U+9234 */ + {0xe988b7, 0x8cd8}, /* U+9237 */ + {0xe988b8, 0xef45}, /* U+9238 [2000] */ + {0xe988b9, 0xef46}, /* U+9239 [2000] */ + {0xe988ba, 0xef47}, /* U+923A [2000] */ + {0xe988bc, 0xef48}, /* U+923C [2000] */ + {0xe988bf, 0xe7ed}, /* U+923F */ + {0xe98980, 0xef49}, /* U+9240 [2000] */ + {0xe98982, 0xfad7}, /* U+9242 [2000] */ + {0xe98983, 0xef4a}, /* U+9243 [2000] */ + {0xe98984, 0x9353}, /* U+9244 */ + {0xe98985, 0xe7e8}, /* U+9245 */ + {0xe98987, 0xfad8}, /* U+9247 [2000] */ + {0xe98988, 0xe7eb}, /* U+9248 */ + {0xe98989, 0xe7e9}, /* U+9249 */ + {0xe9898a, 0xfad9}, /* U+924A [2000] */ + {0xe9898b, 0xe7ee}, /* U+924B */ + {0xe9898e, 0xfada}, /* U+924E [2000] */ + {0xe9898f, 0xef4b}, /* U+924F [2000] */ + {0xe98990, 0xe7ef}, /* U+9250 */ + {0xe98991, 0xfadb}, /* U+9251 [2000] */ + {0xe98996, 0xfadc}, /* U+9256 [2000] */ + {0xe98997, 0xe7e7}, /* U+9257 */ + {0xe98999, 0xfadd}, /* U+9259 [2000] */ + {0xe9899a, 0xe7f4}, /* U+925A */ + {0xe9899b, 0x8994}, /* U+925B */ + {0xe9899e, 0xe7e6}, /* U+925E */ + {0xe989a0, 0xfade}, /* U+9260 [2000] */ + {0xe989a1, 0xfadf}, /* U+9261 [2000] */ + {0xe989a2, 0x94ab}, /* U+9262 */ + {0xe989a4, 0xe7ea}, /* U+9264 */ + {0xe989a5, 0xfae0}, /* U+9265 [2000] */ + {0xe989a6, 0x8fde}, /* U+9266 */ + {0xe989a7, 0xfae1}, /* U+9267 [2000] */ + {0xe989a8, 0xfae2}, /* U+9268 [2000] */ + {0xe989b1, 0x8d7a}, /* U+9271 */ + {0xe989b8, 0xef4c}, /* U+9278 [2000] */ + {0xe989bc, 0xfae5}, /* U+927C [2000] */ + {0xe989bd, 0xfae6}, /* U+927D [2000] */ + {0xe989be, 0x9667}, /* U+927E */ + {0xe989bf, 0xfae7}, /* U+927F [2000] */ + {0xe98a80, 0x8be2}, /* U+9280 */ + {0xe98a83, 0x8f65}, /* U+9283 */ + {0xe98a85, 0x93ba}, /* U+9285 */ + {0xe98a88, 0xef4d}, /* U+9288 [2000] */ + {0xe98a89, 0xfae8}, /* U+9289 [2000] */ + {0xe98a8d, 0xfae9}, /* U+928D [2000] */ + {0xe98a91, 0x914c}, /* U+9291 */ + {0xe98a93, 0xe7f2}, /* U+9293 */ + {0xe98a95, 0xe7ec}, /* U+9295 */ + {0xe98a96, 0xe7f1}, /* U+9296 */ + {0xe98a97, 0xfaea}, /* U+9297 [2000] */ + {0xe98a98, 0x96c1}, /* U+9298 */ + {0xe98a99, 0xfaeb}, /* U+9299 [2000] */ + {0xe98a9a, 0x92b6}, /* U+929A */ + {0xe98a9b, 0xe7f3}, /* U+929B */ + {0xe98a9c, 0xe7f0}, /* U+929C */ + {0xe98a9f, 0xfaec}, /* U+929F [2000] */ + {0xe98aa7, 0xfaed}, /* U+92A7 [2000] */ + {0xe98aab, 0xfaee}, /* U+92AB [2000] */ + {0xe98aad, 0x914b}, /* U+92AD */ + {0xe98ab2, 0xfaf1}, /* U+92B2 [2000] */ + {0xe98ab7, 0xe7f7}, /* U+92B7 */ + {0xe98ab9, 0xe7f6}, /* U+92B9 */ + {0xe98abf, 0xfaf2}, /* U+92BF [2000] */ + {0xe98b80, 0xfaf3}, /* U+92C0 [2000] */ + {0xe98b82, 0xef4e}, /* U+92C2 [2000] */ + {0xe98b86, 0xfaf4}, /* U+92C6 [2000] */ + {0xe98b8b, 0xef4f}, /* U+92CB [2000] */ + {0xe98b8c, 0xef50}, /* U+92CC [2000] */ + {0xe98b8e, 0xfaf5}, /* U+92CE [2000] */ + {0xe98b8f, 0xe7f5}, /* U+92CF */ + {0xe98b90, 0xfaf6}, /* U+92D0 [2000] */ + {0xe98b92, 0x964e}, /* U+92D2 */ + {0xe98b93, 0xef51}, /* U+92D3 [2000] */ + {0xe98b97, 0xfaf7}, /* U+92D7 [2000] */ + {0xe98b99, 0xfaf8}, /* U+92D9 [2000] */ + {0xe98ba0, 0xef52}, /* U+92E0 [2000] */ + {0xe98ba4, 0x8f9b}, /* U+92E4 */ + {0xe98ba5, 0xfaf9}, /* U+92E5 [2000] */ + {0xe98ba7, 0xfafa}, /* U+92E7 [2000] */ + {0xe98ba9, 0xe7f8}, /* U+92E9 */ + {0xe98baa, 0x95dd}, /* U+92EA */ + {0xe98bad, 0x8973}, /* U+92ED */ + {0xe98bb2, 0x9565}, /* U+92F2 */ + {0xe98bb3, 0x9292}, /* U+92F3 */ + {0xe98bb7, 0xfb41}, /* U+92F7 [2000] */ + {0xe98bb8, 0x8b98}, /* U+92F8 */ + {0xe98bb9, 0xfb42}, /* U+92F9 [2000] */ + {0xe98bba, 0xe7fa}, /* U+92FA */ + {0xe98bbb, 0xfb43}, /* U+92FB [2000] */ + {0xe98bbc, 0x8d7c}, /* U+92FC */ + {0xe98bbf, 0xef53}, /* U+92FF [2000] */ + {0xe98c82, 0xfb44}, /* U+9302 [2000] */ + {0xe98c84, 0xef54}, /* U+9304 [2000] */ + {0xe98c86, 0x8e4b}, /* U+9306 */ + {0xe98c8d, 0xfb45}, /* U+930D [2000] */ + {0xe98c8f, 0xe7f9}, /* U+930F */ + {0xe98c90, 0x908d}, /* U+9310 */ + {0xe98c91, 0xfafb}, /* U+9311 [2000] */ + {0xe98c95, 0xfb46}, /* U+9315 [2000] */ + {0xe98c98, 0x908e}, /* U+9318 */ + {0xe98c99, 0xe840}, /* U+9319 */ + {0xe98c9a, 0xe842}, /* U+931A */ + {0xe98c9d, 0xfb47}, /* U+931D [2000] */ + {0xe98c9e, 0xfb48}, /* U+931E [2000] */ + {0xe98c9f, 0xef55}, /* U+931F [2000] */ + {0xe98ca0, 0x8ff9}, /* U+9320 */ + {0xe98ca1, 0xef56}, /* U+9321 [2000] */ + {0xe98ca2, 0xe841}, /* U+9322 */ + {0xe98ca3, 0xe843}, /* U+9323 */ + {0xe98ca5, 0xef57}, /* U+9325 [2000] */ + {0xe98ca6, 0x8bd1}, /* U+9326 */ + {0xe98ca7, 0xfb49}, /* U+9327 [2000] */ + {0xe98ca8, 0x9564}, /* U+9328 */ + {0xe98ca9, 0xfb4a}, /* U+9329 [2000] */ + {0xe98cab, 0x8ee0}, /* U+932B */ + {0xe98cac, 0x9842}, /* U+932C */ + {0xe98cae, 0xe7fc}, /* U+932E */ + {0xe98caf, 0x8df6}, /* U+932F */ + {0xe98cb2, 0x985e}, /* U+9332 */ + {0xe98cb5, 0xe845}, /* U+9335 */ + {0xe98cba, 0xe844}, /* U+933A */ + {0xe98cbb, 0xe846}, /* U+933B */ + {0xe98d84, 0xe7fb}, /* U+9344 */ + {0xe98d87, 0xfb4d}, /* U+9347 [2000] */ + {0xe98d88, 0xef58}, /* U+9348 [2000] */ + {0xe98d89, 0xef59}, /* U+9349 [2000] */ + {0xe98d8a, 0xef5a}, /* U+934A [2000] */ + {0xe98d8b, 0x93e7}, /* U+934B */ + {0xe98d8d, 0x9374}, /* U+934D */ + {0xe98d91, 0xfb4e}, /* U+9351 [2000] */ + {0xe98d94, 0x92d5}, /* U+9354 */ + {0xe98d96, 0xe84b}, /* U+9356 */ + {0xe98d97, 0xfb4f}, /* U+9357 [2000] */ + {0xe98d9a, 0xfb50}, /* U+935A [2000] */ + {0xe98d9b, 0x9262}, /* U+935B */ + {0xe98d9c, 0xe847}, /* U+935C */ + {0xe98da0, 0xe848}, /* U+9360 */ + {0xe98da4, 0xef5b}, /* U+9364 [2000] */ + {0xe98da5, 0xef5c}, /* U+9365 [2000] */ + {0xe98daa, 0xef5d}, /* U+936A [2000] */ + {0xe98dab, 0xfb51}, /* U+936B [2000] */ + {0xe98dac, 0x8c4c}, /* U+936C */ + {0xe98dae, 0xe84a}, /* U+936E */ + {0xe98db0, 0xef5e}, /* U+9370 [2000] */ + {0xe98db1, 0xfb52}, /* U+9371 [2000] */ + {0xe98db3, 0xfb53}, /* U+9373 [2000] */ + {0xe98db5, 0x8cae}, /* U+9375 */ + {0xe98dbc, 0xe849}, /* U+937C */ + {0xe98dbe, 0x8fdf}, /* U+937E */ + {0xe98e88, 0xfb57}, /* U+9388 [2000] */ + {0xe98e8b, 0xfb58}, /* U+938B [2000] */ + {0xe98e8c, 0x8a99}, /* U+938C */ + {0xe98e8f, 0xfb59}, /* U+938F [2000] */ + {0xe98e94, 0xe84f}, /* U+9394 */ + {0xe98e96, 0x8dbd}, /* U+9396 */ + {0xe98e97, 0x9199}, /* U+9397 */ + {0xe98e9a, 0x92c8}, /* U+939A */ + {0xe98e9b, 0xef5f}, /* U+939B [2000] */ + {0xe98e9e, 0xfb5a}, /* U+939E [2000] */ + {0xe98ea1, 0xfb54}, /* U+93A1 [2000] */ + {0xe98ea3, 0xef60}, /* U+93A3 [2000] */ + {0xe98ea7, 0x8a5a}, /* U+93A7 */ + {0xe98eac, 0xe84d}, /* U+93AC */ + {0xe98ead, 0xe84e}, /* U+93AD */ + {0xe98eae, 0x92c1}, /* U+93AE */ + {0xe98eb0, 0xe84c}, /* U+93B0 */ + {0xe98eb9, 0xe850}, /* U+93B9 */ + {0xe98eba, 0xef61}, /* U+93BA [2000] */ + {0xe98f81, 0xfb5f}, /* U+93C1 [2000] */ + {0xe98f83, 0xe856}, /* U+93C3 */ + {0xe98f86, 0xef62}, /* U+93C6 [2000] */ + {0xe98f87, 0xfb60}, /* U+93C7 [2000] */ + {0xe98f88, 0xe859}, /* U+93C8 */ + {0xe98f90, 0xe858}, /* U+93D0 */ + {0xe98f91, 0x934c}, /* U+93D1 */ + {0xe98f96, 0xe851}, /* U+93D6 */ + {0xe98f97, 0xe852}, /* U+93D7 */ + {0xe98f98, 0xe855}, /* U+93D8 */ + {0xe98f9c, 0xfb61}, /* U+93DC [2000] */ + {0xe98f9d, 0xe857}, /* U+93DD */ + {0xe98f9e, 0xef63}, /* U+93DE [2000] */ + {0xe98f9f, 0xef64}, /* U+93DF [2000] */ + {0xe98fa1, 0x8bbe}, /* U+93E1 */ + {0xe98fa2, 0xfb62}, /* U+93E2 [2000] */ + {0xe98fa4, 0xe85a}, /* U+93E4 */ + {0xe98fa5, 0xe854}, /* U+93E5 */ + {0xe98fa7, 0xfb63}, /* U+93E7 [2000] */ + {0xe98fa8, 0xe853}, /* U+93E8 */ + {0xe98fb1, 0xfb5e}, /* U+93F1 [2000] */ + {0xe98fb5, 0xfb5b}, /* U+93F5 [2000] */ + {0xe98fbb, 0xfb68}, /* U+93FB [2000] */ + {0xe98fbd, 0xef66}, /* U+93FD [2000] */ + {0xe99083, 0xe85e}, /* U+9403 */ + {0xe99084, 0xef65}, /* U+9404 [2000] */ + {0xe99087, 0xe85f}, /* U+9407 */ + {0xe99089, 0xfb64}, /* U+9409 [2000] */ + {0xe9908f, 0xfb65}, /* U+940F [2000] */ + {0xe99090, 0xe860}, /* U+9410 */ + {0xe99093, 0xe85d}, /* U+9413 */ + {0xe99094, 0xe85c}, /* U+9414 */ + {0xe99096, 0xfb66}, /* U+9416 [2000] */ + {0xe99097, 0xfb67}, /* U+9417 [2000] */ + {0xe99098, 0x8fe0}, /* U+9418 */ + {0xe99099, 0x93a8}, /* U+9419 */ + {0xe9909a, 0xe85b}, /* U+941A */ + {0xe990a1, 0xe864}, /* U+9421 */ + {0xe990ab, 0xe862}, /* U+942B */ + {0xe990b2, 0xfb69}, /* U+9432 [2000] */ + {0xe990b3, 0xef67}, /* U+9433 [2000] */ + {0xe990b4, 0xfb6a}, /* U+9434 [2000] */ + {0xe990b5, 0xe863}, /* U+9435 */ + {0xe990b6, 0xe861}, /* U+9436 */ + {0xe990b8, 0x91f6}, /* U+9438 */ + {0xe990ba, 0xe865}, /* U+943A */ + {0xe990bb, 0xfb6b}, /* U+943B [2000] */ + {0xe99181, 0xe866}, /* U+9441 */ + {0xe99184, 0xe868}, /* U+9444 */ + {0xe99185, 0xfb6c}, /* U+9445 [2000] */ + {0xe9918a, 0xef68}, /* U+944A [2000] */ + {0xe99191, 0x8ad3}, /* U+9451 */ + {0xe99192, 0xe867}, /* U+9452 */ + {0xe99193, 0x96f8}, /* U+9453 */ + {0xe9919a, 0xe873}, /* U+945A */ + {0xe9919b, 0xe869}, /* U+945B */ + {0xe9919e, 0xe86c}, /* U+945E */ + {0xe991a0, 0xe86a}, /* U+9460 */ + {0xe991a2, 0xe86b}, /* U+9462 */ + {0xe991a3, 0xef69}, /* U+9463 [2000] */ + {0xe991aa, 0xe86d}, /* U+946A */ + {0xe991ab, 0xef6a}, /* U+946B [2000] */ + {0xe991ad, 0xfb6f}, /* U+946D [2000] */ + {0xe991af, 0xfb70}, /* U+946F [2000] */ + {0xe991b0, 0xe86f}, /* U+9470 */ + {0xe991b1, 0xef6b}, /* U+9471 [2000] */ + {0xe991b2, 0xef6c}, /* U+9472 [2000] */ + {0xe991b5, 0xe870}, /* U+9475 */ + {0xe991b7, 0xe871}, /* U+9477 */ + {0xe991bc, 0xe874}, /* U+947C */ + {0xe991bd, 0xe872}, /* U+947D */ + {0xe991be, 0xe875}, /* U+947E */ + {0xe991bf, 0xe877}, /* U+947F */ + {0xe99281, 0xe876}, /* U+9481 */ + {0xe995b7, 0x92b7}, /* U+9577 */ + {0xe995b8, 0xfb71}, /* U+9578 [2000] */ + {0xe995b9, 0xfb72}, /* U+9579 [2000] */ + {0xe99680, 0x96e5}, /* U+9580 */ + {0xe99682, 0xe878}, /* U+9582 */ + {0xe99683, 0x914d}, /* U+9583 */ + {0xe99686, 0xfb73}, /* U+9586 [2000] */ + {0xe99687, 0xe879}, /* U+9587 */ + {0xe99689, 0x95c2}, /* U+9589 */ + {0xe9968a, 0xe87a}, /* U+958A */ + {0xe9968b, 0x8a4a}, /* U+958B */ + {0xe9968c, 0xfb74}, /* U+958C [2000] */ + {0xe9968d, 0xfb75}, /* U+958D [2000] */ + {0xe9968e, 0xef6d}, /* U+958E [2000] */ + {0xe9968f, 0x895b}, /* U+958F */ + {0xe99691, 0x8ad5}, /* U+9591 */ + {0xe99693, 0x8ad4}, /* U+9593 */ + {0xe99694, 0xe87b}, /* U+9594 */ + {0xe99696, 0xe87c}, /* U+9596 */ + {0xe99698, 0xe87d}, /* U+9598 */ + {0xe99699, 0xe87e}, /* U+9599 */ + {0xe9969f, 0xef6e}, /* U+959F [2000] */ + {0xe996a0, 0xe880}, /* U+95A0 */ + {0xe996a2, 0x8ad6}, /* U+95A2 */ + {0xe996a3, 0x8a74}, /* U+95A3 */ + {0xe996a4, 0x8d7d}, /* U+95A4 */ + {0xe996a5, 0x94b4}, /* U+95A5 */ + {0xe996a6, 0xef6f}, /* U+95A6 [2000] */ + {0xe996a7, 0xe882}, /* U+95A7 */ + {0xe996a8, 0xe881}, /* U+95A8 */ + {0xe996a9, 0xef70}, /* U+95A9 [2000] */ + {0xe996ab, 0xfb77}, /* U+95AB [2000] */ + {0xe996ac, 0xef71}, /* U+95AC [2000] */ + {0xe996ad, 0xe883}, /* U+95AD */ + {0xe996b2, 0x897b}, /* U+95B2 */ + {0xe996b4, 0xfb78}, /* U+95B4 [2000] */ + {0xe996b6, 0xef72}, /* U+95B6 [2000] */ + {0xe996b9, 0xe886}, /* U+95B9 */ + {0xe996bb, 0xe885}, /* U+95BB */ + {0xe996bc, 0xe884}, /* U+95BC */ + {0xe996bd, 0xef73}, /* U+95BD [2000] */ + {0xe996be, 0xe887}, /* U+95BE */ + {0xe99783, 0xe88a}, /* U+95C3 */ + {0xe99787, 0x88c5}, /* U+95C7 */ + {0xe99788, 0xfb7a}, /* U+95C8 [2000] */ + {0xe9978a, 0xe888}, /* U+95CA */ + {0xe9978b, 0xef74}, /* U+95CB [2000] */ + {0xe9978c, 0xe88c}, /* U+95CC */ + {0xe9978d, 0xe88b}, /* U+95CD */ + {0xe99790, 0xef75}, /* U+95D0 [2000] */ + {0xe99793, 0xef76}, /* U+95D3 [2000] */ + {0xe99794, 0xe88e}, /* U+95D4 */ + {0xe99795, 0xe88d}, /* U+95D5 */ + {0xe99796, 0xe88f}, /* U+95D6 */ + {0xe99798, 0x93ac}, /* U+95D8 */ + {0xe9979a, 0xef78}, /* U+95DA [2000] */ + {0xe9979c, 0xe890}, /* U+95DC */ + {0xe9979e, 0xef79}, /* U+95DE [2000] */ + {0xe997a1, 0xe891}, /* U+95E1 */ + {0xe997a2, 0xe893}, /* U+95E2 */ + {0xe997a5, 0xe892}, /* U+95E5 */ + {0xe9989c, 0x958c}, /* U+961C */ + {0xe9989d, 0xfaa3}, /* U+961D [2000] */ + {0xe998a1, 0xe894}, /* U+9621 */ + {0xe998a8, 0xe895}, /* U+9628 */ + {0xe998aa, 0x8de3}, /* U+962A */ + {0xe998ac, 0xfb7d}, /* U+962C [2000] */ + {0xe998ae, 0xe896}, /* U+962E */ + {0xe998af, 0xe897}, /* U+962F */ + {0xe998b2, 0x9668}, /* U+9632 */ + {0xe998b3, 0xfb7e}, /* U+9633 [2000] */ + {0xe998b4, 0xfb80}, /* U+9634 [2000] */ + {0xe998bb, 0x916a}, /* U+963B */ + {0xe998bc, 0xfb82}, /* U+963C [2000] */ + {0xe998bf, 0x88a2}, /* U+963F */ + {0xe99980, 0x91c9}, /* U+9640 */ + {0xe99981, 0xfb83}, /* U+9641 [2000] */ + {0xe99982, 0xe898}, /* U+9642 */ + {0xe99984, 0x958d}, /* U+9644 */ + {0xe9998b, 0xe89b}, /* U+964B */ + {0xe9998c, 0xe899}, /* U+964C */ + {0xe9998d, 0x8d7e}, /* U+964D */ + {0xe9998f, 0xe89a}, /* U+964F */ + {0xe99990, 0x8cc0}, /* U+9650 */ + {0xe99998, 0xef7a}, /* U+9658 [2000] */ + {0xe9999b, 0x95c3}, /* U+965B */ + {0xe9999c, 0xe89d}, /* U+965C */ + {0xe9999d, 0xe89f}, /* U+965D */ + {0xe9999e, 0xe89e}, /* U+965E */ + {0xe9999f, 0xe8a0}, /* U+965F */ + {0xe999a1, 0xfb84}, /* U+9661 [2000] */ + {0xe999a2, 0x8940}, /* U+9662 */ + {0xe999a3, 0x9077}, /* U+9663 */ + {0xe999a4, 0x8f9c}, /* U+9664 */ + {0xe999a5, 0x8ad7}, /* U+9665 */ + {0xe999a6, 0xe8a1}, /* U+9666 */ + {0xe999aa, 0x9486}, /* U+966A */ + {0xe999ac, 0xe8a3}, /* U+966C */ + {0xe999b0, 0x8941}, /* U+9670 */ + {0xe999b2, 0xe8a2}, /* U+9672 */ + {0xe999b3, 0x92c2}, /* U+9673 */ + {0xe999b5, 0x97cb}, /* U+9675 */ + {0xe999b6, 0x93a9}, /* U+9676 */ + {0xe999b7, 0xe89c}, /* U+9677 */ + {0xe999b8, 0x97a4}, /* U+9678 */ + {0xe999ba, 0x8caf}, /* U+967A */ + {0xe999bd, 0x977a}, /* U+967D */ + {0xe99a82, 0xfb86}, /* U+9682 [2000] */ + {0xe99a84, 0xef7b}, /* U+9684 [2000] */ + {0xe99a85, 0x8bf7}, /* U+9685 */ + {0xe99a86, 0x97b2}, /* U+9686 */ + {0xe99a88, 0x8c47}, /* U+9688 */ + {0xe99a8a, 0x91e0}, /* U+968A */ + {0xe99a8b, 0xe440}, /* U+968B */ + {0xe99a8d, 0xe8a4}, /* U+968D */ + {0xe99a8e, 0x8a4b}, /* U+968E */ + {0xe99a8f, 0x908f}, /* U+968F */ + {0xe99a94, 0x8a75}, /* U+9694 */ + {0xe99a95, 0xe8a6}, /* U+9695 */ + {0xe99a97, 0xe8a7}, /* U+9697 */ + {0xe99a98, 0xe8a5}, /* U+9698 */ + {0xe99a99, 0x8c84}, /* U+9699 */ + {0xe99a9a, 0xfb88}, /* U+969A [2000] */ + {0xe99a9b, 0x8ddb}, /* U+969B */ + {0xe99a9c, 0x8fe1}, /* U+969C */ + {0xe99a9d, 0xef7d}, /* U+969D [2000] */ + {0xe99aa0, 0x8942}, /* U+96A0 */ + {0xe99aa3, 0x97d7}, /* U+96A3 */ + {0xe99aa4, 0xef7e}, /* U+96A4 [2000] */ + {0xe99aa5, 0xef80}, /* U+96A5 [2000] */ + {0xe99aa7, 0xe8a9}, /* U+96A7 */ + {0xe99aa8, 0xe7ac}, /* U+96A8 */ + {0xe99aa9, 0xfb8b}, /* U+96A9 [2000] */ + {0xe99aaa, 0xe8a8}, /* U+96AA */ + {0xe99aaf, 0xfb8c}, /* U+96AF [2000] */ + {0xe99ab0, 0xe8ac}, /* U+96B0 */ + {0xe99ab1, 0xe8aa}, /* U+96B1 */ + {0xe99ab2, 0xe8ab}, /* U+96B2 */ + {0xe99ab3, 0xfb8d}, /* U+96B3 [2000] */ + {0xe99ab4, 0xe8ad}, /* U+96B4 */ + {0xe99ab6, 0xe8ae}, /* U+96B6 */ + {0xe99ab7, 0x97ea}, /* U+96B7 */ + {0xe99ab8, 0xe8af}, /* U+96B8 */ + {0xe99ab9, 0xe8b0}, /* U+96B9 */ + {0xe99aba, 0xfb8e}, /* U+96BA [2000] */ + {0xe99abb, 0x90c7}, /* U+96BB */ + {0xe99abc, 0x94b9}, /* U+96BC */ + {0xe99abd, 0xfb8f}, /* U+96BD [2000] */ + {0xe99b80, 0x909d}, /* U+96C0 */ + {0xe99b81, 0x8ae5}, /* U+96C1 */ + {0xe99b84, 0x9759}, /* U+96C4 */ + {0xe99b85, 0x89eb}, /* U+96C5 */ + {0xe99b86, 0x8f57}, /* U+96C6 */ + {0xe99b87, 0x8cd9}, /* U+96C7 */ + {0xe99b89, 0xe8b3}, /* U+96C9 */ + {0xe99b8b, 0xe8b2}, /* U+96CB */ + {0xe99b8c, 0x8e93}, /* U+96CC */ + {0xe99b8d, 0xe8b4}, /* U+96CD */ + {0xe99b8e, 0xe8b1}, /* U+96CE */ + {0xe99b91, 0x8e47}, /* U+96D1 */ + {0xe99b92, 0xef81}, /* U+96D2 [2000] */ + {0xe99b95, 0xe8b8}, /* U+96D5 */ + {0xe99b96, 0xe5ab}, /* U+96D6 */ + {0xe99b98, 0xfb92}, /* U+96D8 [2000] */ + {0xe99b99, 0x99d4}, /* U+96D9 */ + {0xe99b9a, 0xfb93}, /* U+96DA [2000] */ + {0xe99b9b, 0x9097}, /* U+96DB */ + {0xe99b9c, 0xe8b6}, /* U+96DC */ + {0xe99b9d, 0xfb94}, /* U+96DD [2000] */ + {0xe99b9e, 0xef82}, /* U+96DE [2000] */ + {0xe99ba2, 0x97a3}, /* U+96E2 */ + {0xe99ba3, 0x93ef}, /* U+96E3 */ + {0xe99ba8, 0x894a}, /* U+96E8 */ + {0xe99ba9, 0xef84}, /* U+96E9 [2000] */ + {0xe99baa, 0x90e1}, /* U+96EA */ + {0xe99bab, 0x8eb4}, /* U+96EB */ + {0xe99baf, 0xef85}, /* U+96EF [2000] */ + {0xe99bb0, 0x95b5}, /* U+96F0 */ + {0xe99bb2, 0x895f}, /* U+96F2 */ + {0xe99bb6, 0x97eb}, /* U+96F6 */ + {0xe99bb7, 0x978b}, /* U+96F7 */ + {0xe99bb9, 0xe8b9}, /* U+96F9 */ + {0xe99bbb, 0x9364}, /* U+96FB */ + {0xe99c80, 0x8ef9}, /* U+9700 */ + {0xe99c84, 0xe8ba}, /* U+9704 */ + {0xe99c86, 0xe8bb}, /* U+9706 */ + {0xe99c87, 0x906b}, /* U+9707 */ + {0xe99c88, 0xe8bc}, /* U+9708 */ + {0xe99c8a, 0x97ec}, /* U+970A */ + {0xe99c8d, 0xe8b7}, /* U+970D */ + {0xe99c8e, 0xe8be}, /* U+970E */ + {0xe99c8f, 0xe8c0}, /* U+970F */ + {0xe99c91, 0xe8bf}, /* U+9711 */ + {0xe99c93, 0xe8bd}, /* U+9713 */ + {0xe99c94, 0xfb96}, /* U+9714 [2000] */ + {0xe99c96, 0xe8c1}, /* U+9716 */ + {0xe99c99, 0xe8c2}, /* U+9719 */ + {0xe99c9c, 0x919a}, /* U+971C */ + {0xe99c9e, 0x89e0}, /* U+971E */ + {0xe99ca3, 0xfb97}, /* U+9723 [2000] */ + {0xe99ca4, 0xe8c3}, /* U+9724 */ + {0xe99ca7, 0x96b6}, /* U+9727 */ + {0xe99caa, 0xe8c4}, /* U+972A */ + {0xe99cb0, 0xe8c5}, /* U+9730 */ + {0xe99cb2, 0x9849}, /* U+9732 */ + {0xe99cb3, 0xef86}, /* U+9733 [2000] */ + {0xe99cb6, 0xfb99}, /* U+9736 [2000] */ + {0xe99cb8, 0x9e50}, /* U+9738 */ + {0xe99cb9, 0xe8c6}, /* U+9739 */ + {0xe99cbb, 0xef87}, /* U+973B [2000] */ + {0xe99cbd, 0xe8c7}, /* U+973D */ + {0xe99cbe, 0xe8c8}, /* U+973E */ + {0xe99d81, 0xfb9a}, /* U+9741 [2000] */ + {0xe99d82, 0xe8cc}, /* U+9742 */ + {0xe99d84, 0xe8c9}, /* U+9744 */ + {0xe99d86, 0xe8ca}, /* U+9746 */ + {0xe99d87, 0xfb9b}, /* U+9747 [2000] */ + {0xe99d88, 0xe8cb}, /* U+9748 */ + {0xe99d89, 0xe8cd}, /* U+9749 */ + {0xe99d8d, 0xef88}, /* U+974D [2000] */ + {0xe99d8e, 0xef89}, /* U+974E [2000] */ + {0xe99d8f, 0xef8a}, /* U+974F [2000] */ + {0xe99d92, 0x90c2}, /* U+9752 */ + {0xe99d95, 0xfb9c}, /* U+9755 [2000] */ + {0xe99d96, 0x96f5}, /* U+9756 */ + {0xe99d97, 0xfb9d}, /* U+9757 [2000] */ + {0xe99d99, 0x90c3}, /* U+9759 */ + {0xe99d9a, 0xef8b}, /* U+975A [2000] */ + {0xe99d9b, 0xfb9e}, /* U+975B [2000] */ + {0xe99d9c, 0xe8ce}, /* U+975C */ + {0xe99d9e, 0x94f1}, /* U+975E */ + {0xe99da0, 0xe8cf}, /* U+9760 */ + {0xe99da1, 0xea72}, /* U+9761 */ + {0xe99da2, 0x96ca}, /* U+9762 */ + {0xe99da4, 0xe8d0}, /* U+9764 */ + {0xe99da6, 0xe8d1}, /* U+9766 */ + {0xe99da8, 0xe8d2}, /* U+9768 */ + {0xe99da9, 0x8a76}, /* U+9769 */ + {0xe99daa, 0xfb9f}, /* U+976A [2000] */ + {0xe99dab, 0xe8d4}, /* U+976B */ + {0xe99dad, 0x9078}, /* U+976D */ + {0xe99dae, 0xef8c}, /* U+976E [2000] */ + {0xe99db1, 0xe8d5}, /* U+9771 */ + {0xe99db3, 0xef8d}, /* U+9773 [2000] */ + {0xe99db4, 0x8c43}, /* U+9774 */ + {0xe99db9, 0xe8d6}, /* U+9779 */ + {0xe99dba, 0xe8da}, /* U+977A */ + {0xe99dbc, 0xe8d8}, /* U+977C */ + {0xe99e81, 0xe8d9}, /* U+9781 */ + {0xe99e84, 0x8a93}, /* U+9784 */ + {0xe99e85, 0xe8d7}, /* U+9785 */ + {0xe99e86, 0xe8db}, /* U+9786 */ + {0xe99e8b, 0xe8dc}, /* U+978B */ + {0xe99e8d, 0x88c6}, /* U+978D */ + {0xe99e8f, 0xe8dd}, /* U+978F */ + {0xe99e90, 0xe8de}, /* U+9790 */ + {0xe99e95, 0xef8e}, /* U+9795 [2000] */ + {0xe99e96, 0xfba2}, /* U+9796 [2000] */ + {0xe99e98, 0x8fe2}, /* U+9798 */ + {0xe99e9a, 0xfba3}, /* U+979A [2000] */ + {0xe99e9c, 0xe8df}, /* U+979C */ + {0xe99e9e, 0xfba4}, /* U+979E [2000] */ + {0xe99ea0, 0x8b66}, /* U+97A0 */ + {0xe99ea2, 0xfba5}, /* U+97A2 [2000] */ + {0xe99ea3, 0xe8e2}, /* U+97A3 */ + {0xe99ea6, 0xe8e1}, /* U+97A6 */ + {0xe99ea8, 0xe8e0}, /* U+97A8 */ + {0xe99eab, 0xe691}, /* U+97AB */ + {0xe99ead, 0x95da}, /* U+97AD */ + {0xe99eae, 0xef8f}, /* U+97AE [2000] */ + {0xe99eb1, 0xfba6}, /* U+97B1 [2000] */ + {0xe99eb2, 0xfba7}, /* U+97B2 [2000] */ + {0xe99eb3, 0xe8e3}, /* U+97B3 */ + {0xe99eb4, 0xe8e4}, /* U+97B4 */ + {0xe99eba, 0xef90}, /* U+97BA [2000] */ + {0xe99ebe, 0xfba8}, /* U+97BE [2000] */ + {0xe99f81, 0xef91}, /* U+97C1 [2000] */ + {0xe99f83, 0xe8e5}, /* U+97C3 */ + {0xe99f86, 0xe8e6}, /* U+97C6 */ + {0xe99f88, 0xe8e7}, /* U+97C8 */ + {0xe99f89, 0xef92}, /* U+97C9 [2000] */ + {0xe99f8b, 0xe8e8}, /* U+97CB */ + {0xe99f8c, 0xfba9}, /* U+97CC [2000] */ + {0xe99f91, 0xfbaa}, /* U+97D1 [2000] */ + {0xe99f93, 0x8ad8}, /* U+97D3 */ + {0xe99f94, 0xfbab}, /* U+97D4 [2000] */ + {0xe99f98, 0xfbac}, /* U+97D8 [2000] */ + {0xe99f99, 0xfbad}, /* U+97D9 [2000] */ + {0xe99f9b, 0xef94}, /* U+97DB [2000] */ + {0xe99f9c, 0xe8e9}, /* U+97DC */ + {0xe99f9e, 0xef93}, /* U+97DE [2000] */ + {0xe99fa1, 0xfbae}, /* U+97E1 [2000] */ + {0xe99fad, 0xe8ea}, /* U+97ED */ + {0xe99fae, 0x9442}, /* U+97EE */ + {0xe99fb1, 0xfbaf}, /* U+97F1 [2000] */ + {0xe99fb2, 0xe8ec}, /* U+97F2 */ + {0xe99fb3, 0x89b9}, /* U+97F3 */ + {0xe99fb4, 0xef95}, /* U+97F4 [2000] */ + {0xe99fb5, 0xe8ef}, /* U+97F5 */ + {0xe99fb6, 0xe8ee}, /* U+97F6 */ + {0xe99fbb, 0x8943}, /* U+97FB */ + {0xe99fbf, 0x8bbf}, /* U+97FF */ + {0xe9a081, 0x95c5}, /* U+9801 */ + {0xe9a082, 0x92b8}, /* U+9802 */ + {0xe9a083, 0x8da0}, /* U+9803 */ + {0xe9a084, 0xfbb0}, /* U+9804 [2000] */ + {0xe9a085, 0x8d80}, /* U+9805 */ + {0xe9a086, 0x8f87}, /* U+9806 */ + {0xe9a088, 0x907b}, /* U+9808 */ + {0xe9a08a, 0xef97}, /* U+980A [2000] */ + {0xe9a08c, 0xe8f1}, /* U+980C */ + {0xe9a08d, 0xfbb1}, /* U+980D [2000] */ + {0xe9a08e, 0xfbb2}, /* U+980E [2000] */ + {0xe9a08f, 0xe8f0}, /* U+980F */ + {0xe9a090, 0x9761}, /* U+9810 */ + {0xe9a091, 0x8ae6}, /* U+9811 */ + {0xe9a092, 0x94d0}, /* U+9812 */ + {0xe9a093, 0x93da}, /* U+9813 */ + {0xe9a094, 0xfbb3}, /* U+9814 [2000] */ + {0xe9a096, 0xfbb4}, /* U+9816 [2000] */ + {0xe9a097, 0x909c}, /* U+9817 */ + {0xe9a098, 0x97cc}, /* U+9818 */ + {0xe9a09a, 0x8c7a}, /* U+981A */ + {0xe9a09e, 0xef98}, /* U+981E [2000] */ + {0xe9a0a1, 0xe8f4}, /* U+9821 */ + {0xe9a0a3, 0xfbb7}, /* U+9823 [2000] */ + {0xe9a0a4, 0xe8f3}, /* U+9824 */ + {0xe9a0a5, 0xfbba}, /* U+9825 [2000] */ + {0xe9a0ab, 0xef99}, /* U+982B [2000] */ + {0xe9a0ac, 0x966a}, /* U+982C */ + {0xe9a0ad, 0x93aa}, /* U+982D */ + {0xe9a0b0, 0xef9a}, /* U+9830 [2000] */ + {0xe9a0b2, 0xfbb8}, /* U+9832 [2000] */ + {0xe9a0b3, 0xfbb9}, /* U+9833 [2000] */ + {0xe9a0b4, 0x896f}, /* U+9834 */ + {0xe9a0b7, 0xe8f5}, /* U+9837 */ + {0xe9a0b8, 0xe8f2}, /* U+9838 */ + {0xe9a0bb, 0x9570}, /* U+983B */ + {0xe9a0bc, 0x978a}, /* U+983C */ + {0xe9a0bd, 0xe8f6}, /* U+983D */ + {0xe9a186, 0xe8f7}, /* U+9846 */ + {0xe9a187, 0xfbbb}, /* U+9847 [2000] */ + {0xe9a18b, 0xe8f9}, /* U+984B */ + {0xe9a18c, 0x91e8}, /* U+984C */ + {0xe9a18d, 0x8a7a}, /* U+984D */ + {0xe9a18e, 0x8a7b}, /* U+984E */ + {0xe9a18f, 0xe8f8}, /* U+984F */ + {0xe9a192, 0xef9c}, /* U+9852 [2000] */ + {0xe9a193, 0xef9d}, /* U+9853 [2000] */ + {0xe9a194, 0x8ae7}, /* U+9854 */ + {0xe9a195, 0x8cb0}, /* U+9855 */ + {0xe9a196, 0xef9e}, /* U+9856 [2000] */ + {0xe9a197, 0xef9f}, /* U+9857 [2000] */ + {0xe9a198, 0x8ae8}, /* U+9858 */ + {0xe9a199, 0xefa0}, /* U+9859 [2000] */ + {0xe9a19a, 0xefa1}, /* U+985A [2000] */ + {0xe9a19b, 0x935e}, /* U+985B */ + {0xe9a19e, 0x97de}, /* U+985E */ + {0xe9a1a5, 0xefa3}, /* U+9865 [2000] */ + {0xe9a1a6, 0xfbbc}, /* U+9866 [2000] */ + {0xe9a1a7, 0x8cda}, /* U+9867 */ + {0xe9a1ab, 0xe8fa}, /* U+986B */ + {0xe9a1ac, 0xefa4}, /* U+986C [2000] */ + {0xe9a1af, 0xe8fb}, /* U+986F */ + {0xe9a1b0, 0xe8fc}, /* U+9870 */ + {0xe9a1b1, 0xe940}, /* U+9871 */ + {0xe9a1b3, 0xe942}, /* U+9873 */ + {0xe9a1b4, 0xe941}, /* U+9874 */ + {0xe9a2a8, 0x9597}, /* U+98A8 */ + {0xe9a2aa, 0xe943}, /* U+98AA */ + {0xe9a2ab, 0xfbbd}, /* U+98AB [2000] */ + {0xe9a2ad, 0xfbbe}, /* U+98AD [2000] */ + {0xe9a2af, 0xe944}, /* U+98AF */ + {0xe9a2b0, 0xfbbf}, /* U+98B0 [2000] */ + {0xe9a2b1, 0xe945}, /* U+98B1 */ + {0xe9a2b6, 0xe946}, /* U+98B6 */ + {0xe9a2b7, 0xfbc1}, /* U+98B7 [2000] */ + {0xe9a2b8, 0xfbc2}, /* U+98B8 [2000] */ + {0xe9a2ba, 0xefa5}, /* U+98BA [2000] */ + {0xe9a2bb, 0xfbc3}, /* U+98BB [2000] */ + {0xe9a2bc, 0xfbc4}, /* U+98BC [2000] */ + {0xe9a2bf, 0xfbc5}, /* U+98BF [2000] */ + {0xe9a382, 0xfbc6}, /* U+98C2 [2000] */ + {0xe9a383, 0xe948}, /* U+98C3 */ + {0xe9a384, 0xe947}, /* U+98C4 */ + {0xe9a386, 0xe949}, /* U+98C6 */ + {0xe9a387, 0xfbc7}, /* U+98C7 [2000] */ + {0xe9a388, 0xefa6}, /* U+98C8 [2000] */ + {0xe9a38b, 0xfbc8}, /* U+98CB [2000] */ + {0xe9a39b, 0x94f2}, /* U+98DB */ + {0xe9a39c, 0xe3ca}, /* U+98DC */ + {0xe9a39f, 0x9048}, /* U+98DF */ + {0xe9a3a0, 0xfbc9}, /* U+98E0 [2000] */ + {0xe9a3a1, 0xfbcb}, /* U+98E1 [2000] */ + {0xe9a3a2, 0x8b51}, /* U+98E2 */ + {0xe9a3a3, 0xfbcc}, /* U+98E3 [2000] */ + {0xe9a3a5, 0xfbcd}, /* U+98E5 [2000] */ + {0xe9a3a7, 0xefa7}, /* U+98E7 [2000] */ + {0xe9a3a9, 0xe94a}, /* U+98E9 */ + {0xe9a3aa, 0xfbce}, /* U+98EA [2000] */ + {0xe9a3ab, 0xe94b}, /* U+98EB */ + {0xe9a3ad, 0x99aa}, /* U+98ED */ + {0xe9a3ae, 0x9f5a}, /* U+98EE */ + {0xe9a3af, 0x94d1}, /* U+98EF */ + {0xe9a3b0, 0xfbcf}, /* U+98F0 [2000] */ + {0xe9a3b1, 0xfbd0}, /* U+98F1 [2000] */ + {0xe9a3b2, 0x88f9}, /* U+98F2 */ + {0xe9a3b3, 0xfbd1}, /* U+98F3 [2000] */ + {0xe9a3b4, 0x88b9}, /* U+98F4 */ + {0xe9a3bc, 0x8e94}, /* U+98FC */ + {0xe9a3bd, 0x964f}, /* U+98FD */ + {0xe9a3be, 0x8ffc}, /* U+98FE */ + {0xe9a483, 0xe94c}, /* U+9903 */ + {0xe9a485, 0x96dd}, /* U+9905 */ + {0xe9a488, 0xfbd2}, /* U+9908 [2000] */ + {0xe9a489, 0xe94d}, /* U+9909 */ + {0xe9a48a, 0x977b}, /* U+990A */ + {0xe9a48c, 0x8961}, /* U+990C */ + {0xe9a490, 0x8e60}, /* U+9910 */ + {0xe9a492, 0xe94e}, /* U+9912 */ + {0xe9a493, 0x89ec}, /* U+9913 */ + {0xe9a494, 0xe94f}, /* U+9914 */ + {0xe9a496, 0xfbd5}, /* U+9916 [2000] */ + {0xe9a497, 0xfbd6}, /* U+9917 [2000] */ + {0xe9a498, 0xe950}, /* U+9918 */ + {0xe9a49a, 0xfbd8}, /* U+991A [2000] */ + {0xe9a49b, 0xfbd9}, /* U+991B [2000] */ + {0xe9a49c, 0xfbda}, /* U+991C [2000] */ + {0xe9a49d, 0xe952}, /* U+991D */ + {0xe9a49e, 0xe953}, /* U+991E */ + {0xe9a4a0, 0xe955}, /* U+9920 */ + {0xe9a4a1, 0xe951}, /* U+9921 */ + {0xe9a4a4, 0xe954}, /* U+9924 */ + {0xe9a4a8, 0x8ad9}, /* U+9928 */ + {0xe9a4ac, 0xe956}, /* U+992C */ + {0xe9a4ae, 0xe957}, /* U+992E */ + {0xe9a4b1, 0xfbdc}, /* U+9931 [2000] */ + {0xe9a4b2, 0xfbdd}, /* U+9932 [2000] */ + {0xe9a4b3, 0xfbde}, /* U+9933 [2000] */ + {0xe9a4ba, 0xfbdf}, /* U+993A [2000] */ + {0xe9a4bb, 0xfbe0}, /* U+993B [2000] */ + {0xe9a4bc, 0xfbe1}, /* U+993C [2000] */ + {0xe9a4bd, 0xe958}, /* U+993D */ + {0xe9a4be, 0xe959}, /* U+993E */ + {0xe9a580, 0xfbe2}, /* U+9940 [2000] */ + {0xe9a581, 0xfbe3}, /* U+9941 [2000] */ + {0xe9a582, 0xe95a}, /* U+9942 */ + {0xe9a585, 0xe95c}, /* U+9945 */ + {0xe9a586, 0xfbe4}, /* U+9946 [2000] */ + {0xe9a589, 0xe95b}, /* U+9949 */ + {0xe9a58b, 0xe95e}, /* U+994B */ + {0xe9a58c, 0xe961}, /* U+994C */ + {0xe9a58d, 0xfbe5}, /* U+994D [2000] */ + {0xe9a58e, 0xfbe6}, /* U+994E [2000] */ + {0xe9a590, 0xe95d}, /* U+9950 */ + {0xe9a591, 0xe95f}, /* U+9951 */ + {0xe9a592, 0xe960}, /* U+9952 */ + {0xe9a595, 0xe962}, /* U+9955 */ + {0xe9a597, 0x8bc0}, /* U+9957 */ + {0xe9a598, 0xefa8}, /* U+9958 [2000] */ + {0xe9a59c, 0xfbe7}, /* U+995C [2000] */ + {0xe9a59f, 0xfbe8}, /* U+995F [2000] */ + {0xe9a5a0, 0xfbe9}, /* U+9960 [2000] */ + {0xe9a696, 0x8ef1}, /* U+9996 */ + {0xe9a697, 0xe963}, /* U+9997 */ + {0xe9a698, 0xe964}, /* U+9998 */ + {0xe9a699, 0x8d81}, /* U+9999 */ + {0xe9a69e, 0xefa9}, /* U+999E [2000] */ + {0xe9a6a3, 0xfbea}, /* U+99A3 [2000] */ + {0xe9a6a5, 0xe965}, /* U+99A5 */ + {0xe9a6a6, 0xfbeb}, /* U+99A6 [2000] */ + {0xe9a6a8, 0x8a5d}, /* U+99A8 */ + {0xe9a6ac, 0x946e}, /* U+99AC */ + {0xe9a6ad, 0xe966}, /* U+99AD */ + {0xe9a6ae, 0xe967}, /* U+99AE */ + {0xe9a6b3, 0x9279}, /* U+99B3 */ + {0xe9a6b4, 0x93e9}, /* U+99B4 */ + {0xe9a6b9, 0xfbec}, /* U+99B9 [2000] */ + {0xe9a6bc, 0xe968}, /* U+99BC */ + {0xe9a6bd, 0xfbed}, /* U+99BD [2000] */ + {0xe9a6bf, 0xfbee}, /* U+99BF [2000] */ + {0xe9a781, 0x949d}, /* U+99C1 */ + {0xe9a783, 0xfbef}, /* U+99C3 [2000] */ + {0xe9a784, 0x91ca}, /* U+99C4 */ + {0xe9a785, 0x8977}, /* U+99C5 */ + {0xe9a786, 0x8bec}, /* U+99C6 */ + {0xe9a788, 0x8bed}, /* U+99C8 */ + {0xe9a789, 0xfbf0}, /* U+99C9 [2000] */ + {0xe9a790, 0x9293}, /* U+99D0 */ + {0xe9a791, 0xe96d}, /* U+99D1 */ + {0xe9a792, 0x8bee}, /* U+99D2 */ + {0xe9a794, 0xfbf1}, /* U+99D4 [2000] */ + {0xe9a795, 0x89ed}, /* U+99D5 */ + {0xe9a798, 0xe96c}, /* U+99D8 */ + {0xe9a799, 0xfbf2}, /* U+99D9 [2000] */ + {0xe9a79b, 0xe96a}, /* U+99DB */ + {0xe9a79d, 0xe96b}, /* U+99DD */ + {0xe9a79e, 0xfbf3}, /* U+99DE [2000] */ + {0xe9a79f, 0xe969}, /* U+99DF */ + {0xe9a7a2, 0xe977}, /* U+99E2 */ + {0xe9a7ad, 0xe96e}, /* U+99ED */ + {0xe9a7ae, 0xe96f}, /* U+99EE */ + {0xe9a7b0, 0xfbf5}, /* U+99F0 [2000] */ + {0xe9a7b1, 0xe970}, /* U+99F1 */ + {0xe9a7b2, 0xe971}, /* U+99F2 */ + {0xe9a7b8, 0xe973}, /* U+99F8 */ + {0xe9a7b9, 0xfbf6}, /* U+99F9 [2000] */ + {0xe9a7bb, 0xe972}, /* U+99FB */ + {0xe9a7bc, 0xfbf7}, /* U+99FC [2000] */ + {0xe9a7bf, 0x8f78}, /* U+99FF */ + {0xe9a881, 0xe974}, /* U+9A01 */ + {0xe9a882, 0xefaa}, /* U+9A02 [2000] */ + {0xe9a883, 0xefab}, /* U+9A03 [2000] */ + {0xe9a885, 0xe976}, /* U+9A05 */ + {0xe9a88a, 0xfbf8}, /* U+9A0A [2000] */ + {0xe9a88e, 0x8b52}, /* U+9A0E */ + {0xe9a88f, 0xe975}, /* U+9A0F */ + {0xe9a891, 0xfbf9}, /* U+9A11 [2000] */ + {0xe9a892, 0x919b}, /* U+9A12 */ + {0xe9a893, 0x8cb1}, /* U+9A13 */ + {0xe9a896, 0xfbfa}, /* U+9A16 [2000] */ + {0xe9a899, 0xe978}, /* U+9A19 */ + {0xe9a89a, 0xfbfb}, /* U+9A1A [2000] */ + {0xe9a8a0, 0xfbfc}, /* U+9A20 [2000] */ + {0xe9a8a4, 0xefac}, /* U+9A24 [2000] */ + {0xe9a8a8, 0x91cb}, /* U+9A28 */ + {0xe9a8ab, 0xe979}, /* U+9A2B */ + {0xe9a8ad, 0xefad}, /* U+9A2D [2000] */ + {0xe9a8ae, 0xefae}, /* U+9A2E [2000] */ + {0xe9a8b0, 0x93ab}, /* U+9A30 */ + {0xe9a8b1, 0xfc40}, /* U+9A31 [2000] */ + {0xe9a8b6, 0xfc41}, /* U+9A36 [2000] */ + {0xe9a8b7, 0xe97a}, /* U+9A37 */ + {0xe9a8b8, 0xefaf}, /* U+9A38 [2000] */ + {0xe9a8be, 0xe980}, /* U+9A3E */ + {0xe9a980, 0xe97d}, /* U+9A40 */ + {0xe9a982, 0xe97c}, /* U+9A42 */ + {0xe9a983, 0xe97e}, /* U+9A43 */ + {0xe9a984, 0xfc42}, /* U+9A44 [2000] */ + {0xe9a985, 0xe97b}, /* U+9A45 */ + {0xe9a98a, 0xefb0}, /* U+9A4A [2000] */ + {0xe9a98c, 0xfc43}, /* U+9A4C [2000] */ + {0xe9a98d, 0xe982}, /* U+9A4D */ + {0xe9a98e, 0xefb1}, /* U+9A4E [2000] */ + {0xe9a992, 0xefb2}, /* U+9A52 [2000] */ + {0xe9a995, 0xe981}, /* U+9A55 */ + {0xe9a997, 0xe984}, /* U+9A57 */ + {0xe9a998, 0xfc44}, /* U+9A58 [2000] */ + {0xe9a99a, 0x8bc1}, /* U+9A5A */ + {0xe9a99b, 0xe983}, /* U+9A5B */ + {0xe9a99f, 0xe985}, /* U+9A5F */ + {0xe9a9a2, 0xe986}, /* U+9A62 */ + {0xe9a9a4, 0xe988}, /* U+9A64 */ + {0xe9a9a5, 0xe987}, /* U+9A65 */ + {0xe9a9a9, 0xe989}, /* U+9A69 */ + {0xe9a9aa, 0xe98b}, /* U+9A6A */ + {0xe9a9ab, 0xe98a}, /* U+9A6B */ + {0xe9aaa8, 0x8d9c}, /* U+9AA8 */ + {0xe9aaad, 0xe98c}, /* U+9AAD */ + {0xe9aaaf, 0xfc46}, /* U+9AAF [2000] */ + {0xe9aab0, 0xe98d}, /* U+9AB0 */ + {0xe9aab6, 0xefb3}, /* U+9AB6 [2000] */ + {0xe9aab7, 0xfc48}, /* U+9AB7 [2000] */ + {0xe9aab8, 0x8a5b}, /* U+9AB8 */ + {0xe9aab9, 0xfc4a}, /* U+9AB9 [2000] */ + {0xe9aabc, 0xe98e}, /* U+9ABC */ + {0xe9ab80, 0xe98f}, /* U+9AC0 */ + {0xe9ab81, 0xefb4}, /* U+9AC1 [2000] */ + {0xe9ab83, 0xefb5}, /* U+9AC3 [2000] */ + {0xe9ab84, 0x9091}, /* U+9AC4 */ + {0xe9ab86, 0xfc4c}, /* U+9AC6 [2000] */ + {0xe9ab8e, 0xefb6}, /* U+9ACE [2000] */ + {0xe9ab8f, 0xe990}, /* U+9ACF */ + {0xe9ab90, 0xfc4d}, /* U+9AD0 [2000] */ + {0xe9ab91, 0xe991}, /* U+9AD1 */ + {0xe9ab92, 0xfc4e}, /* U+9AD2 [2000] */ + {0xe9ab93, 0xe992}, /* U+9AD3 */ + {0xe9ab94, 0xe993}, /* U+9AD4 */ + {0xe9ab95, 0xfc4f}, /* U+9AD5 [2000] */ + {0xe9ab96, 0xefb7}, /* U+9AD6 [2000] */ + {0xe9ab98, 0x8d82}, /* U+9AD8 */ + {0xe9ab9c, 0xfc51}, /* U+9ADC [2000] */ + {0xe9ab9e, 0xe994}, /* U+9ADE */ + {0xe9ab9f, 0xe995}, /* U+9ADF */ + {0xe9aba0, 0xfc52}, /* U+9AE0 [2000] */ + {0xe9aba2, 0xe996}, /* U+9AE2 */ + {0xe9aba3, 0xe997}, /* U+9AE3 */ + {0xe9aba5, 0xfc53}, /* U+9AE5 [2000] */ + {0xe9aba6, 0xe998}, /* U+9AE6 */ + {0xe9aba9, 0xfc54}, /* U+9AE9 [2000] */ + {0xe9abaa, 0x94af}, /* U+9AEA */ + {0xe9abab, 0xe99a}, /* U+9AEB */ + {0xe9abad, 0x9545}, /* U+9AED */ + {0xe9abae, 0xe99b}, /* U+9AEE */ + {0xe9abaf, 0xe999}, /* U+9AEF */ + {0xe9abb1, 0xe99d}, /* U+9AF1 */ + {0xe9abb4, 0xe99c}, /* U+9AF4 */ + {0xe9abb7, 0xe99e}, /* U+9AF7 */ + {0xe9abb9, 0xefb8}, /* U+9AF9 [2000] */ + {0xe9abbb, 0xe99f}, /* U+9AFB */ + {0xe9ac82, 0xefb9}, /* U+9B02 [2000] */ + {0xe9ac83, 0xfc55}, /* U+9B03 [2000] */ + {0xe9ac86, 0xe9a0}, /* U+9B06 */ + {0xe9ac88, 0xefba}, /* U+9B08 [2000] */ + {0xe9ac8c, 0xfc56}, /* U+9B0C [2000] */ + {0xe9ac90, 0xfc57}, /* U+9B10 [2000] */ + {0xe9ac92, 0xfc58}, /* U+9B12 [2000] */ + {0xe9ac96, 0xfc59}, /* U+9B16 [2000] */ + {0xe9ac98, 0xe9a1}, /* U+9B18 */ + {0xe9ac9a, 0xe9a2}, /* U+9B1A */ + {0xe9ac9c, 0xfc5a}, /* U+9B1C [2000] */ + {0xe9ac9f, 0xe9a3}, /* U+9B1F */ + {0xe9aca0, 0xefbb}, /* U+9B20 [2000] */ + {0xe9aca2, 0xe9a4}, /* U+9B22 */ + {0xe9aca3, 0xe9a5}, /* U+9B23 */ + {0xe9aca5, 0xe9a6}, /* U+9B25 */ + {0xe9aca7, 0xe9a7}, /* U+9B27 */ + {0xe9aca8, 0xe9a8}, /* U+9B28 */ + {0xe9aca9, 0xe9a9}, /* U+9B29 */ + {0xe9acaa, 0xe9aa}, /* U+9B2A */ + {0xe9acab, 0xfc5b}, /* U+9B2B [2000] */ + {0xe9acad, 0xefbd}, /* U+9B2D [2000] */ + {0xe9acae, 0xe9ab}, /* U+9B2E */ + {0xe9acaf, 0xe9ac}, /* U+9B2F */ + {0xe9acb1, 0x9f54}, /* U+9B31 */ + {0xe9acb2, 0xe9ad}, /* U+9B32 */ + {0xe9acb3, 0xfc5c}, /* U+9B33 [2000] */ + {0xe9acbb, 0xe2f6}, /* U+9B3B */ + {0xe9acbc, 0x8b53}, /* U+9B3C */ + {0xe9acbd, 0xfc5d}, /* U+9B3D [2000] */ + {0xe9ad81, 0x8a40}, /* U+9B41 */ + {0xe9ad82, 0x8db0}, /* U+9B42 */ + {0xe9ad83, 0xe9af}, /* U+9B43 */ + {0xe9ad84, 0xe9ae}, /* U+9B44 */ + {0xe9ad85, 0x96a3}, /* U+9B45 */ + {0xe9ad8b, 0xfc5f}, /* U+9B4B [2000] */ + {0xe9ad8d, 0xe9b1}, /* U+9B4D */ + {0xe9ad8e, 0xe9b2}, /* U+9B4E */ + {0xe9ad8f, 0xe9b0}, /* U+9B4F */ + {0xe9ad91, 0xe9b3}, /* U+9B51 */ + {0xe9ad94, 0x9682}, /* U+9B54 */ + {0xe9ad98, 0xe9b4}, /* U+9B58 */ + {0xe9ad9a, 0x8b9b}, /* U+9B5A */ + {0xe9ad9e, 0xefbe}, /* U+9B5E [2000] */ + {0xe9ada3, 0xfc60}, /* U+9B63 [2000] */ + {0xe9ada5, 0xfc61}, /* U+9B65 [2000] */ + {0xe9ada6, 0xefc0}, /* U+9B66 [2000] */ + {0xe9adab, 0xfc62}, /* U+9B6B [2000] */ + {0xe9adac, 0xfc63}, /* U+9B6C [2000] */ + {0xe9adaf, 0x9844}, /* U+9B6F */ + {0xe9adb2, 0xefc1}, /* U+9B72 [2000] */ + {0xe9adb3, 0xfc64}, /* U+9B73 [2000] */ + {0xe9adb4, 0xe9b5}, /* U+9B74 */ + {0xe9adb5, 0xefc2}, /* U+9B75 [2000] */ + {0xe9adb6, 0xfc65}, /* U+9B76 [2000] */ + {0xe9adb7, 0xfc66}, /* U+9B77 [2000] */ + {0xe9adb9, 0xefbf}, /* U+9B79 [2000] */ + {0xe9ae83, 0xe9b7}, /* U+9B83 */ + {0xe9ae84, 0xefc3}, /* U+9B84 [2000] */ + {0xe9ae8a, 0xefc4}, /* U+9B8A [2000] */ + {0xe9ae8e, 0x88bc}, /* U+9B8E */ + {0xe9ae8f, 0xefc5}, /* U+9B8F [2000] */ + {0xe9ae91, 0xe9b8}, /* U+9B91 */ + {0xe9ae92, 0x95a9}, /* U+9B92 */ + {0xe9ae93, 0xe9b6}, /* U+9B93 */ + {0xe9ae96, 0xe9b9}, /* U+9B96 */ + {0xe9ae97, 0xe9ba}, /* U+9B97 */ + {0xe9ae9e, 0xefc6}, /* U+9B9E [2000] */ + {0xe9ae9f, 0xe9bb}, /* U+9B9F */ + {0xe9aea0, 0xe9bc}, /* U+9BA0 */ + {0xe9aea6, 0xfc67}, /* U+9BA6 [2000] */ + {0xe9aea7, 0xefc7}, /* U+9BA7 [2000] */ + {0xe9aea8, 0xe9bd}, /* U+9BA8 */ + {0xe9aeaa, 0x968e}, /* U+9BAA */ + {0xe9aeab, 0x8e4c}, /* U+9BAB */ + {0xe9aeac, 0xfc68}, /* U+9BAC [2000] */ + {0xe9aead, 0x8df8}, /* U+9BAD */ + {0xe9aeae, 0x914e}, /* U+9BAE */ + {0xe9aeb1, 0xfc69}, /* U+9BB1 [2000] */ + {0xe9aeb2, 0xfc6c}, /* U+9BB2 [2000] */ + {0xe9aeb4, 0xe9be}, /* U+9BB4 */ + {0xe9aeb8, 0xfc6d}, /* U+9BB8 [2000] */ + {0xe9aeb9, 0xe9c1}, /* U+9BB9 */ + {0xe9aebe, 0xfc6e}, /* U+9BBE [2000] */ + {0xe9af80, 0xe9bf}, /* U+9BC0 */ + {0xe9af81, 0xefc8}, /* U+9BC1 [2000] */ + {0xe9af86, 0xe9c2}, /* U+9BC6 */ + {0xe9af87, 0xfc6f}, /* U+9BC7 [2000] */ + {0xe9af89, 0x8cef}, /* U+9BC9 */ + {0xe9af8a, 0xe9c0}, /* U+9BCA */ + {0xe9af8e, 0xefc9}, /* U+9BCE [2000] */ + {0xe9af8f, 0xe9c3}, /* U+9BCF */ + {0xe9af91, 0xe9c4}, /* U+9BD1 */ + {0xe9af92, 0xe9c5}, /* U+9BD2 */ + {0xe9af94, 0xe9c9}, /* U+9BD4 */ + {0xe9af96, 0x8e49}, /* U+9BD6 */ + {0xe9af98, 0xfc71}, /* U+9BD8 [2000] */ + {0xe9af9b, 0x91e2}, /* U+9BDB */ + {0xe9af9d, 0xfc72}, /* U+9BDD [2000] */ + {0xe9afa1, 0xe9ca}, /* U+9BE1 */ + {0xe9afa2, 0xe9c7}, /* U+9BE2 */ + {0xe9afa3, 0xe9c6}, /* U+9BE3 */ + {0xe9afa4, 0xe9c8}, /* U+9BE4 */ + {0xe9afa5, 0xefca}, /* U+9BE5 [2000] */ + {0xe9afa7, 0xfc73}, /* U+9BE7 [2000] */ + {0xe9afa8, 0x8c7e}, /* U+9BE8 */ + {0xe9afaa, 0xfc74}, /* U+9BEA [2000] */ + {0xe9afab, 0xfc75}, /* U+9BEB [2000] */ + {0xe9afae, 0xfc77}, /* U+9BEE [2000] */ + {0xe9afaf, 0xfc76}, /* U+9BEF [2000] */ + {0xe9afb0, 0xe9ce}, /* U+9BF0 */ + {0xe9afb1, 0xe9cd}, /* U+9BF1 */ + {0xe9afb2, 0xe9cc}, /* U+9BF2 */ + {0xe9afb3, 0xfc70}, /* U+9BF3 [2000] */ + {0xe9afb5, 0x88b1}, /* U+9BF5 */ + {0xe9afb7, 0xfc7b}, /* U+9BF7 [2000] */ + {0xe9afb8, 0xefcb}, /* U+9BF8 [2000] */ + {0xe9afba, 0xfc79}, /* U+9BFA [2000] */ + {0xe9afbd, 0xefcc}, /* U+9BFD [2000] */ + {0xe9b080, 0xefcd}, /* U+9C00 [2000] */ + {0xe9b084, 0xe9d8}, /* U+9C04 */ + {0xe9b086, 0xe9d4}, /* U+9C06 */ + {0xe9b088, 0xe9d5}, /* U+9C08 */ + {0xe9b089, 0xe9d1}, /* U+9C09 */ + {0xe9b08a, 0xe9d7}, /* U+9C0A */ + {0xe9b08c, 0xe9d3}, /* U+9C0C */ + {0xe9b08d, 0x8a82}, /* U+9C0D */ + {0xe9b090, 0x986b}, /* U+9C10 */ + {0xe9b092, 0xe9d6}, /* U+9C12 */ + {0xe9b093, 0xe9d2}, /* U+9C13 */ + {0xe9b094, 0xe9d0}, /* U+9C14 */ + {0xe9b095, 0xe9cf}, /* U+9C15 */ + {0xe9b096, 0xfc7d}, /* U+9C16 [2000] */ + {0xe9b098, 0xfc7e}, /* U+9C18 [2000] */ + {0xe9b099, 0xfc80}, /* U+9C19 [2000] */ + {0xe9b09a, 0xfc81}, /* U+9C1A [2000] */ + {0xe9b09b, 0xe9da}, /* U+9C1B */ + {0xe9b09d, 0xfc82}, /* U+9C1D [2000] */ + {0xe9b0a1, 0xe9dd}, /* U+9C21 */ + {0xe9b0a2, 0xfc83}, /* U+9C22 [2000] */ + {0xe9b0a3, 0xefce}, /* U+9C23 [2000] */ + {0xe9b0a4, 0xe9dc}, /* U+9C24 */ + {0xe9b0a5, 0xe9db}, /* U+9C25 */ + {0xe9b0a7, 0xfc84}, /* U+9C27 [2000] */ + {0xe9b0a9, 0xfc85}, /* U+9C29 [2000] */ + {0xe9b0aa, 0xfc86}, /* U+9C2A [2000] */ + {0xe9b0ad, 0x9568}, /* U+9C2D */ + {0xe9b0ae, 0xe9d9}, /* U+9C2E */ + {0xe9b0af, 0x88f1}, /* U+9C2F */ + {0xe9b0b0, 0xe9de}, /* U+9C30 */ + {0xe9b0b1, 0xfc88}, /* U+9C31 [2000] */ + {0xe9b0b2, 0xe9e0}, /* U+9C32 */ + {0xe9b0b6, 0xfc89}, /* U+9C36 [2000] */ + {0xe9b0b7, 0xfc8a}, /* U+9C37 [2000] */ + {0xe9b0b9, 0x8a8f}, /* U+9C39 */ + {0xe9b0ba, 0xe9cb}, /* U+9C3A */ + {0xe9b0bb, 0x8956}, /* U+9C3B */ + {0xe9b0be, 0xe9e2}, /* U+9C3E */ + {0xe9b181, 0xefcf}, /* U+9C41 [2000] */ + {0xe9b185, 0xfc8b}, /* U+9C45 [2000] */ + {0xe9b186, 0xe9e1}, /* U+9C46 */ + {0xe9b187, 0xe9df}, /* U+9C47 */ + {0xe9b188, 0x924c}, /* U+9C48 */ + {0xe9b189, 0xfc8e}, /* U+9C49 [2000] */ + {0xe9b18a, 0xfc8f}, /* U+9C4A [2000] */ + {0xe9b18f, 0xefd0}, /* U+9C4F [2000] */ + {0xe9b190, 0xefd1}, /* U+9C50 [2000] */ + {0xe9b192, 0x9690}, /* U+9C52 */ + {0xe9b193, 0xefd2}, /* U+9C53 [2000] */ + {0xe9b194, 0xfc91}, /* U+9C54 [2000] */ + {0xe9b197, 0x97d8}, /* U+9C57 */ + {0xe9b198, 0xfc92}, /* U+9C58 [2000] */ + {0xe9b19a, 0xe9e3}, /* U+9C5A */ + {0xe9b19b, 0xfc93}, /* U+9C5B [2000] */ + {0xe9b19c, 0xfc8c}, /* U+9C5C [2000] */ + {0xe9b19d, 0xfc94}, /* U+9C5D [2000] */ + {0xe9b19f, 0xfc95}, /* U+9C5F [2000] */ + {0xe9b1a0, 0xe9e4}, /* U+9C60 */ + {0xe9b1a3, 0xefd3}, /* U+9C63 [2000] */ + {0xe9b1a5, 0xefd4}, /* U+9C65 [2000] */ + {0xe9b1a7, 0xe9e5}, /* U+9C67 */ + {0xe9b1a9, 0xfc96}, /* U+9C69 [2000] */ + {0xe9b1aa, 0xfc97}, /* U+9C6A [2000] */ + {0xe9b1ab, 0xfc98}, /* U+9C6B [2000] */ + {0xe9b1ad, 0xfc99}, /* U+9C6D [2000] */ + {0xe9b1ae, 0xfc9a}, /* U+9C6E [2000] */ + {0xe9b1b0, 0xfc9b}, /* U+9C70 [2000] */ + {0xe9b1b2, 0xfc9c}, /* U+9C72 [2000] */ + {0xe9b1b5, 0xfc9d}, /* U+9C75 [2000] */ + {0xe9b1b6, 0xe9e6}, /* U+9C76 */ + {0xe9b1b7, 0xefd5}, /* U+9C77 [2000] */ + {0xe9b1b8, 0xe9e7}, /* U+9C78 */ + {0xe9b1ba, 0xfc9e}, /* U+9C7A [2000] */ + {0xe9b3a5, 0x92b9}, /* U+9CE5 */ + {0xe9b3a6, 0xfc9f}, /* U+9CE6 [2000] */ + {0xe9b3a7, 0xe9e8}, /* U+9CE7 */ + {0xe9b3a9, 0x94b5}, /* U+9CE9 */ + {0xe9b3ab, 0xe9ed}, /* U+9CEB */ + {0xe9b3ac, 0xe9e9}, /* U+9CEC */ + {0xe9b3b0, 0xe9ea}, /* U+9CF0 */ + {0xe9b3b2, 0xfca0}, /* U+9CF2 [2000] */ + {0xe9b3b3, 0x9650}, /* U+9CF3 */ + {0xe9b3b4, 0x96c2}, /* U+9CF4 */ + {0xe9b3b6, 0x93ce}, /* U+9CF6 */ + {0xe9b482, 0xfca2}, /* U+9D02 [2000] */ + {0xe9b483, 0xe9ee}, /* U+9D03 */ + {0xe9b486, 0xe9ef}, /* U+9D06 */ + {0xe9b487, 0x93bc}, /* U+9D07 */ + {0xe9b488, 0xe9ec}, /* U+9D08 */ + {0xe9b489, 0xe9eb}, /* U+9D09 */ + {0xe9b48b, 0xfca1}, /* U+9D0B [2000] */ + {0xe9b48e, 0x89a8}, /* U+9D0E */ + {0xe9b491, 0xfca4}, /* U+9D11 [2000] */ + {0xe9b492, 0xe9f7}, /* U+9D12 */ + {0xe9b495, 0xe9f6}, /* U+9D15 */ + {0xe9b497, 0xfca5}, /* U+9D17 [2000] */ + {0xe9b498, 0xfca6}, /* U+9D18 [2000] */ + {0xe9b49b, 0x8995}, /* U+9D1B */ + {0xe9b49d, 0xefd6}, /* U+9D1D [2000] */ + {0xe9b49e, 0xefd7}, /* U+9D1E [2000] */ + {0xe9b49f, 0xe9f4}, /* U+9D1F */ + {0xe9b4a3, 0xe9f3}, /* U+9D23 */ + {0xe9b4a6, 0xe9f1}, /* U+9D26 */ + {0xe9b4a8, 0x8a9b}, /* U+9D28 */ + {0xe9b4aa, 0xe9f0}, /* U+9D2A */ + {0xe9b4ab, 0x8eb0}, /* U+9D2B */ + {0xe9b4ac, 0x89a7}, /* U+9D2C */ + {0xe9b4b2, 0xfcaa}, /* U+9D32 [2000] */ + {0xe9b4bb, 0x8d83}, /* U+9D3B */ + {0xe9b4be, 0xe9fa}, /* U+9D3E */ + {0xe9b4bf, 0xe9f9}, /* U+9D3F */ + {0xe9b581, 0xe9f8}, /* U+9D41 */ + {0xe9b582, 0xfcac}, /* U+9D42 [2000] */ + {0xe9b583, 0xefd8}, /* U+9D43 [2000] */ + {0xe9b584, 0xe9f5}, /* U+9D44 */ + {0xe9b586, 0xe9fb}, /* U+9D46 */ + {0xe9b587, 0xefd9}, /* U+9D47 [2000] */ + {0xe9b588, 0xe9fc}, /* U+9D48 */ + {0xe9b58a, 0xfcad}, /* U+9D4A [2000] */ + {0xe9b590, 0xea44}, /* U+9D50 */ + {0xe9b591, 0xea43}, /* U+9D51 */ + {0xe9b592, 0xefda}, /* U+9D52 [2000] */ + {0xe9b599, 0xea45}, /* U+9D59 */ + {0xe9b59c, 0x894c}, /* U+9D5C */ + {0xe9b59d, 0xea40}, /* U+9D5D */ + {0xe9b59e, 0xea41}, /* U+9D5E */ + {0xe9b59f, 0xfcae}, /* U+9D5F [2000] */ + {0xe9b5a0, 0x8d94}, /* U+9D60 */ + {0xe9b5a1, 0x96b7}, /* U+9D61 */ + {0xe9b5a2, 0xfcaf}, /* U+9D62 [2000] */ + {0xe9b5a3, 0xefdb}, /* U+9D63 [2000] */ + {0xe9b5a4, 0xea42}, /* U+9D64 */ + {0xe9b5a9, 0xfcb1}, /* U+9D69 [2000] */ + {0xe9b5ab, 0xfcb2}, /* U+9D6B [2000] */ + {0xe9b5ac, 0x9651}, /* U+9D6C */ + {0xe9b5af, 0xea4a}, /* U+9D6F */ + {0xe9b5b0, 0xefdc}, /* U+9D70 [2000] */ + {0xe9b5b2, 0xea46}, /* U+9D72 */ + {0xe9b5b3, 0xfcb4}, /* U+9D73 [2000] */ + {0xe9b5b6, 0xfcb5}, /* U+9D76 [2000] */ + {0xe9b5b7, 0xfcb6}, /* U+9D77 [2000] */ + {0xe9b5ba, 0xea4b}, /* U+9D7A */ + {0xe9b5bc, 0xefdd}, /* U+9D7C [2000] */ + {0xe9b5be, 0xfcb7}, /* U+9D7E [2000] */ + {0xe9b684, 0xfcb8}, /* U+9D84 [2000] */ + {0xe9b687, 0xea48}, /* U+9D87 */ + {0xe9b689, 0xea47}, /* U+9D89 */ + {0xe9b68a, 0xefde}, /* U+9D8A [2000] */ + {0xe9b68d, 0xfcb9}, /* U+9D8D [2000] */ + {0xe9b68f, 0x8c7b}, /* U+9D8F */ + {0xe9b696, 0xefdf}, /* U+9D96 [2000] */ + {0xe9b699, 0xfcba}, /* U+9D99 [2000] */ + {0xe9b69a, 0xea4c}, /* U+9D9A */ + {0xe9b6a1, 0xfcbb}, /* U+9DA1 [2000] */ + {0xe9b6a4, 0xea4d}, /* U+9DA4 */ + {0xe9b6a9, 0xea4e}, /* U+9DA9 */ + {0xe9b6ab, 0xea49}, /* U+9DAB */ + {0xe9b6ac, 0xefe1}, /* U+9DAC [2000] */ + {0xe9b6af, 0xe9f2}, /* U+9DAF */ + {0xe9b6b2, 0xea4f}, /* U+9DB2 */ + {0xe9b6b4, 0x92df}, /* U+9DB4 */ + {0xe9b6b5, 0xfcbd}, /* U+9DB5 [2000] */ + {0xe9b6b8, 0xea53}, /* U+9DB8 */ + {0xe9b6b9, 0xfcbe}, /* U+9DB9 [2000] */ + {0xe9b6ba, 0xea54}, /* U+9DBA */ + {0xe9b6bb, 0xea52}, /* U+9DBB */ + {0xe9b6bc, 0xefe2}, /* U+9DBC [2000] */ + {0xe9b6bd, 0xfcbf}, /* U+9DBD [2000] */ + {0xe9b6bf, 0xfcbc}, /* U+9DBF [2000] */ + {0xe9b780, 0xefe0}, /* U+9DC0 [2000] */ + {0xe9b781, 0xea51}, /* U+9DC1 */ + {0xe9b782, 0xea57}, /* U+9DC2 */ + {0xe9b783, 0xfcc0}, /* U+9DC3 [2000] */ + {0xe9b784, 0xea50}, /* U+9DC4 */ + {0xe9b786, 0xea55}, /* U+9DC6 */ + {0xe9b787, 0xfcc1}, /* U+9DC7 [2000] */ + {0xe9b789, 0xfcc2}, /* U+9DC9 [2000] */ + {0xe9b78f, 0xea56}, /* U+9DCF */ + {0xe9b793, 0xea59}, /* U+9DD3 */ + {0xe9b796, 0xfcc3}, /* U+9DD6 [2000] */ + {0xe9b797, 0xefe3}, /* U+9DD7 [2000] */ + {0xe9b799, 0xea58}, /* U+9DD9 */ + {0xe9b79a, 0xfcc4}, /* U+9DDA [2000] */ + {0xe9b79f, 0xfcc5}, /* U+9DDF [2000] */ + {0xe9b7a0, 0xfcc6}, /* U+9DE0 [2000] */ + {0xe9b7a3, 0xfcc7}, /* U+9DE3 [2000] */ + {0xe9b7a6, 0xea5b}, /* U+9DE6 */ + {0xe9b7a7, 0xefe5}, /* U+9DE7 [2000] */ + {0xe9b7ad, 0xea5c}, /* U+9DED */ + {0xe9b7af, 0xea5d}, /* U+9DEF */ + {0xe9b7b2, 0x9868}, /* U+9DF2 */ + {0xe9b7b4, 0xfcc8}, /* U+9DF4 [2000] */ + {0xe9b7b8, 0xea5a}, /* U+9DF8 */ + {0xe9b7b9, 0x91e9}, /* U+9DF9 */ + {0xe9b7ba, 0x8deb}, /* U+9DFA */ + {0xe9b7bd, 0xea5e}, /* U+9DFD */ + {0xe9b882, 0xfccb}, /* U+9E02 [2000] */ + {0xe9b887, 0xefe6}, /* U+9E07 [2000] */ + {0xe9b88a, 0xfcca}, /* U+9E0A [2000] */ + {0xe9b88d, 0xfccc}, /* U+9E0D [2000] */ + {0xe9b895, 0xefe7}, /* U+9E15 [2000] */ + {0xe9b899, 0xfccd}, /* U+9E19 [2000] */ + {0xe9b89a, 0xea5f}, /* U+9E1A */ + {0xe9b89b, 0xea60}, /* U+9E1B */ + {0xe9b89c, 0xfcce}, /* U+9E1C [2000] */ + {0xe9b89d, 0xfccf}, /* U+9E1D [2000] */ + {0xe9b89e, 0xea61}, /* U+9E1E */ + {0xe9b9b5, 0xea62}, /* U+9E75 */ + {0xe9b9b8, 0x8cb2}, /* U+9E78 */ + {0xe9b9b9, 0xea63}, /* U+9E79 */ + {0xe9b9bb, 0xfcd0}, /* U+9E7B [2000] */ + {0xe9b9bc, 0xefe8}, /* U+9E7C [2000] */ + {0xe9b9bd, 0xea64}, /* U+9E7D */ + {0xe9b9bf, 0x8ead}, /* U+9E7F */ + {0xe9ba80, 0xfcd2}, /* U+9E80 [2000] */ + {0xe9ba81, 0xea65}, /* U+9E81 */ + {0xe9ba85, 0xfcd3}, /* U+9E85 [2000] */ + {0xe9ba88, 0xea66}, /* U+9E88 */ + {0xe9ba8b, 0xea67}, /* U+9E8B */ + {0xe9ba8c, 0xea68}, /* U+9E8C */ + {0xe9ba91, 0xea6b}, /* U+9E91 */ + {0xe9ba92, 0xea69}, /* U+9E92 */ + {0xe9ba93, 0x985b}, /* U+9E93 */ + {0xe9ba95, 0xea6a}, /* U+9E95 */ + {0xe9ba97, 0x97ed}, /* U+9E97 */ + {0xe9ba9b, 0xfcd4}, /* U+9E9B [2000] */ + {0xe9ba9d, 0xea6c}, /* U+9E9D */ + {0xe9ba9e, 0xefe9}, /* U+9E9E [2000] */ + {0xe9ba9f, 0x97d9}, /* U+9E9F */ + {0xe9baa4, 0xefea}, /* U+9EA4 [2000] */ + {0xe9baa5, 0xea6d}, /* U+9EA5 */ + {0xe9baa6, 0x949e}, /* U+9EA6 */ + {0xe9baa8, 0xfcd5}, /* U+9EA8 [2000] */ + {0xe9baa9, 0xea6e}, /* U+9EA9 */ + {0xe9baaa, 0xea70}, /* U+9EAA */ + {0xe9baac, 0xefeb}, /* U+9EAC [2000] */ + {0xe9baad, 0xea71}, /* U+9EAD */ + {0xe9baaf, 0xefec}, /* U+9EAF [2000] */ + {0xe9bab4, 0xefed}, /* U+9EB4 [2000] */ + {0xe9bab5, 0xefee}, /* U+9EB5 [2000] */ + {0xe9bab8, 0xea6f}, /* U+9EB8 */ + {0xe9bab9, 0x8d8d}, /* U+9EB9 */ + {0xe9baba, 0x96cb}, /* U+9EBA */ + {0xe9babb, 0x9683}, /* U+9EBB */ + {0xe9babc, 0x9bf5}, /* U+9EBC */ + {0xe9babd, 0xfcd7}, /* U+9EBD [2000] */ + {0xe9babe, 0x9f80}, /* U+9EBE */ + {0xe9babf, 0x969b}, /* U+9EBF */ + {0xe9bb83, 0xefef}, /* U+9EC3 [2000] */ + {0xe9bb84, 0x89a9}, /* U+9EC4 */ + {0xe9bb8c, 0xea73}, /* U+9ECC */ + {0xe9bb8d, 0x8b6f}, /* U+9ECD */ + {0xe9bb8e, 0xea74}, /* U+9ECE */ + {0xe9bb8f, 0xea75}, /* U+9ECF */ + {0xe9bb90, 0xea76}, /* U+9ED0 */ + {0xe9bb91, 0xeff0}, /* U+9ED1 [2000] */ + {0xe9bb92, 0x8d95}, /* U+9ED2 */ + {0xe9bb94, 0xea77}, /* U+9ED4 */ + {0xe9bb98, 0xe0d2}, /* U+9ED8 */ + {0xe9bb99, 0x96d9}, /* U+9ED9 */ + {0xe9bb9b, 0x91e1}, /* U+9EDB */ + {0xe9bb9c, 0xea78}, /* U+9EDC */ + {0xe9bb9d, 0xea7a}, /* U+9EDD */ + {0xe9bb9e, 0xea79}, /* U+9EDE */ + {0xe9bb9f, 0xfcd9}, /* U+9EDF [2000] */ + {0xe9bba0, 0xea7b}, /* U+9EE0 */ + {0xe9bba5, 0xea7c}, /* U+9EE5 */ + {0xe9bba7, 0xfcda}, /* U+9EE7 [2000] */ + {0xe9bba8, 0xea7d}, /* U+9EE8 */ + {0xe9bbae, 0xfcdb}, /* U+9EEE [2000] */ + {0xe9bbaf, 0xea7e}, /* U+9EEF */ + {0xe9bbb4, 0xea80}, /* U+9EF4 */ + {0xe9bbb6, 0xea81}, /* U+9EF6 */ + {0xe9bbb7, 0xea82}, /* U+9EF7 */ + {0xe9bbb9, 0xea83}, /* U+9EF9 */ + {0xe9bbbb, 0xea84}, /* U+9EFB */ + {0xe9bbbc, 0xea85}, /* U+9EFC */ + {0xe9bbbd, 0xea86}, /* U+9EFD */ + {0xe9bbbf, 0xfcdc}, /* U+9EFF [2000] */ + {0xe9bc82, 0xfcdd}, /* U+9F02 [2000] */ + {0xe9bc83, 0xfcdf}, /* U+9F03 [2000] */ + {0xe9bc87, 0xea87}, /* U+9F07 */ + {0xe9bc88, 0xea88}, /* U+9F08 */ + {0xe9bc8e, 0x9343}, /* U+9F0E */ + {0xe9bc90, 0xeff1}, /* U+9F10 [2000] */ + {0xe9bc93, 0x8cdb}, /* U+9F13 */ + {0xe9bc95, 0xea8a}, /* U+9F15 */ + {0xe9bc97, 0xfce0}, /* U+9F17 [2000] */ + {0xe9bc99, 0xfce1}, /* U+9F19 [2000] */ + {0xe9bca0, 0x916c}, /* U+9F20 */ + {0xe9bca1, 0xea8b}, /* U+9F21 */ + {0xe9bcac, 0xea8c}, /* U+9F2C */ + {0xe9bcaf, 0xfce2}, /* U+9F2F [2000] */ + {0xe9bcb7, 0xfce3}, /* U+9F37 [2000] */ + {0xe9bcb9, 0xeff2}, /* U+9F39 [2000] */ + {0xe9bcba, 0xfce4}, /* U+9F3A [2000] */ + {0xe9bcbb, 0x9540}, /* U+9F3B */ + {0xe9bcbd, 0xfce5}, /* U+9F3D [2000] */ + {0xe9bcbe, 0xea8d}, /* U+9F3E */ + {0xe9bd81, 0xfce6}, /* U+9F41 [2000] */ + {0xe9bd85, 0xfce7}, /* U+9F45 [2000] */ + {0xe9bd86, 0xfce8}, /* U+9F46 [2000] */ + {0xe9bd8a, 0xea8e}, /* U+9F4A */ + {0xe9bd8b, 0xe256}, /* U+9F4B */ + {0xe9bd8e, 0xe6d8}, /* U+9F4E */ + {0xe9bd8f, 0xe8eb}, /* U+9F4F */ + {0xe9bd92, 0xea8f}, /* U+9F52 */ + {0xe9bd93, 0xfce9}, /* U+9F53 [2000] */ + {0xe9bd94, 0xea90}, /* U+9F54 */ + {0xe9bd95, 0xfcea}, /* U+9F55 [2000] */ + {0xe9bd97, 0xeff3}, /* U+9F57 [2000] */ + {0xe9bd98, 0xfceb}, /* U+9F58 [2000] */ + {0xe9bd9d, 0xfced}, /* U+9F5D [2000] */ + {0xe9bd9f, 0xea92}, /* U+9F5F */ + {0xe9bda0, 0xea93}, /* U+9F60 */ + {0xe9bda1, 0xea94}, /* U+9F61 */ + {0xe9bda2, 0x97ee}, /* U+9F62 */ + {0xe9bda3, 0xea91}, /* U+9F63 */ + {0xe9bda6, 0xea95}, /* U+9F66 */ + {0xe9bda7, 0xea96}, /* U+9F67 */ + {0xe9bda9, 0xfcef}, /* U+9F69 [2000] */ + {0xe9bdaa, 0xea98}, /* U+9F6A */ + {0xe9bdac, 0xea97}, /* U+9F6C */ + {0xe9bdad, 0xfcf1}, /* U+9F6D [2000] */ + {0xe9bdb0, 0xfcf2}, /* U+9F70 [2000] */ + {0xe9bdb2, 0xea9a}, /* U+9F72 */ + {0xe9bdb5, 0xfcf3}, /* U+9F75 [2000] */ + {0xe9bdb6, 0xea9b}, /* U+9F76 */ + {0xe9bdb7, 0xea99}, /* U+9F77 */ + {0xe9be8d, 0x97b4}, /* U+9F8D */ + {0xe9be90, 0xeff4}, /* U+9F90 [2000] */ + {0xe9be94, 0xeff5}, /* U+9F94 [2000] */ + {0xe9be95, 0xea9c}, /* U+9F95 */ + {0xe9be97, 0xeff6}, /* U+9F97 [2000] */ + {0xe9be9c, 0xea9d}, /* U+9F9C */ + {0xe9be9d, 0xe273}, /* U+9F9D */ + {0xe9bea0, 0xea9e}, /* U+9FA0 */ + {0xe9bea2, 0xeff7}, /* U+9FA2 [2000] */ + {0xefa49d, 0xebb9}, /* U+F91D CJK COMPATIBILITY IDEOGRAPH-F91D [2000] */ + {0xefa4a8, 0xeaac}, /* U+F928 CJK COMPATIBILITY IDEOGRAPH-F928 [2000] */ + {0xefa4a9, 0xeb6d}, /* U+F929 CJK COMPATIBILITY IDEOGRAPH-F929 [2000] */ + {0xefa4b6, 0xee6e}, /* U+F936 CJK COMPATIBILITY IDEOGRAPH-F936 [2000] */ + {0xefa5b0, 0xebc7}, /* U+F970 CJK COMPATIBILITY IDEOGRAPH-F970 [2000] */ + {0xefa790, 0xefa2}, /* U+F9D0 CJK COMPATIBILITY IDEOGRAPH-F9D0 [2000] */ + {0xefa79c, 0xef7c}, /* U+F9DC CJK COMPATIBILITY IDEOGRAPH-F9DC [2000] */ + {0xefa88f, 0x886a}, /* U+FA0F CJK COMPATIBILITY IDEOGRAPH-FA0F [2000] */ + {0xefa890, 0x8876}, /* U+FA10 CJK COMPATIBILITY IDEOGRAPH-FA10 [2000] */ + {0xefa891, 0x9892}, /* U+FA11 CJK COMPATIBILITY IDEOGRAPH-FA11 [2000] */ + {0xefa893, 0xf3f7}, /* U+FA13 CJK COMPATIBILITY IDEOGRAPH-FA13 [2000] */ + {0xefa894, 0xeb9a}, /* U+FA14 CJK COMPATIBILITY IDEOGRAPH-FA14 [2000] */ + {0xefa895, 0xec79}, /* U+FA15 CJK COMPATIBILITY IDEOGRAPH-FA15 [2000] */ + {0xefa896, 0xec8f}, /* U+FA16 CJK COMPATIBILITY IDEOGRAPH-FA16 [2000] */ + {0xefa899, 0xed5b}, /* U+FA19 CJK COMPATIBILITY IDEOGRAPH-FA19 [2000] */ + {0xefa89a, 0xed5c}, /* U+FA1A CJK COMPATIBILITY IDEOGRAPH-FA1A [2000] */ + {0xefa89b, 0xed60}, /* U+FA1B CJK COMPATIBILITY IDEOGRAPH-FA1B [2000] */ + {0xefa89f, 0xee59}, /* U+FA1F CJK COMPATIBILITY IDEOGRAPH-FA1F [2000] */ + {0xefa8a0, 0xf957}, /* U+FA20 CJK COMPATIBILITY IDEOGRAPH-FA20 [2000] */ + {0xefa8a1, 0xf964}, /* U+FA21 CJK COMPATIBILITY IDEOGRAPH-FA21 [2000] */ + {0xefa8a2, 0xeeac}, /* U+FA22 CJK COMPATIBILITY IDEOGRAPH-FA22 [2000] */ + {0xefa8a4, 0xfa8e}, /* U+FA24 CJK COMPATIBILITY IDEOGRAPH-FA24 [2000] */ + {0xefa8a6, 0xeee8}, /* U+FA26 CJK COMPATIBILITY IDEOGRAPH-FA26 [2000] */ + {0xefa8b0, 0x87b6}, /* U+FA30 CJK COMPATIBILITY IDEOGRAPH-FA30 [2000] [Unicode3.2] */ + {0xefa8b1, 0x87c7}, /* U+FA31 CJK COMPATIBILITY IDEOGRAPH-FA31 [2000] [Unicode3.2] */ + {0xefa8b2, 0x87ce}, /* U+FA32 CJK COMPATIBILITY IDEOGRAPH-FA32 [2000] [Unicode3.2] */ + {0xefa8b3, 0x87e1}, /* U+FA33 CJK COMPATIBILITY IDEOGRAPH-FA33 [2000] [Unicode3.2] */ + {0xefa8b4, 0x87e6}, /* U+FA34 CJK COMPATIBILITY IDEOGRAPH-FA34 [2000] [Unicode3.2] */ + {0xefa8b5, 0x87ec}, /* U+FA35 CJK COMPATIBILITY IDEOGRAPH-FA35 [2000] [Unicode3.2] */ + {0xefa8b6, 0x884b}, /* U+FA36 CJK COMPATIBILITY IDEOGRAPH-FA36 [2000] [Unicode3.2] */ + {0xefa8b7, 0x884e}, /* U+FA37 CJK COMPATIBILITY IDEOGRAPH-FA37 [2000] [Unicode3.2] */ + {0xefa8b8, 0x8855}, /* U+FA38 CJK COMPATIBILITY IDEOGRAPH-FA38 [2000] [Unicode3.2] */ + {0xefa8b9, 0x8879}, /* U+FA39 CJK COMPATIBILITY IDEOGRAPH-FA39 [2000] [Unicode3.2] */ + {0xefa8ba, 0x887d}, /* U+FA3A CJK COMPATIBILITY IDEOGRAPH-FA3A [2000] [Unicode3.2] */ + {0xefa8bb, 0x9881}, /* U+FA3B CJK COMPATIBILITY IDEOGRAPH-FA3B [2000] [Unicode3.2] */ + {0xefa8bc, 0x9882}, /* U+FA3C CJK COMPATIBILITY IDEOGRAPH-FA3C [2000] [Unicode3.2] */ + {0xefa8bd, 0xeace}, /* U+FA3D CJK COMPATIBILITY IDEOGRAPH-FA3D [2000] [Unicode3.2] */ + {0xefa8be, 0xeada}, /* U+FA3E CJK COMPATIBILITY IDEOGRAPH-FA3E [2000] [Unicode3.2] */ + {0xefa8bf, 0xeadc}, /* U+FA3F CJK COMPATIBILITY IDEOGRAPH-FA3F [2000] [Unicode3.2] */ + {0xefa980, 0xeadf}, /* U+FA40 CJK COMPATIBILITY IDEOGRAPH-FA40 [2000] [Unicode3.2] */ + {0xefa981, 0xeb47}, /* U+FA41 CJK COMPATIBILITY IDEOGRAPH-FA41 [2000] [Unicode3.2] */ + {0xefa982, 0xeb4a}, /* U+FA42 CJK COMPATIBILITY IDEOGRAPH-FA42 [2000] [Unicode3.2] */ + {0xefa983, 0xeb62}, /* U+FA43 CJK COMPATIBILITY IDEOGRAPH-FA43 [2000] [Unicode3.2] */ + {0xefa984, 0xeb85}, /* U+FA44 CJK COMPATIBILITY IDEOGRAPH-FA44 [2000] [Unicode3.2] */ + {0xefa985, 0xebe7}, /* U+FA45 CJK COMPATIBILITY IDEOGRAPH-FA45 [2000] [Unicode3.2] */ + {0xefa986, 0xebf5}, /* U+FA46 CJK COMPATIBILITY IDEOGRAPH-FA46 [2000] [Unicode3.2] */ + {0xefa987, 0xec44}, /* U+FA47 CJK COMPATIBILITY IDEOGRAPH-FA47 [2000] [Unicode3.2] */ + {0xefa988, 0xec74}, /* U+FA48 CJK COMPATIBILITY IDEOGRAPH-FA48 [2000] [Unicode3.2] */ + {0xefa989, 0xf5a7}, /* U+FA49 CJK COMPATIBILITY IDEOGRAPH-FA49 [2000] [Unicode3.2] */ + {0xefa98a, 0xeca3}, /* U+FA4A CJK COMPATIBILITY IDEOGRAPH-FA4A [2000] [Unicode3.2] */ + {0xefa98b, 0xed46}, /* U+FA4B CJK COMPATIBILITY IDEOGRAPH-FA4B [2000] [Unicode3.2] */ + {0xefa98c, 0xed52}, /* U+FA4C CJK COMPATIBILITY IDEOGRAPH-FA4C [2000] [Unicode3.2] */ + {0xefa98d, 0xed53}, /* U+FA4D CJK COMPATIBILITY IDEOGRAPH-FA4D [2000] [Unicode3.2] */ + {0xefa98e, 0xed56}, /* U+FA4E CJK COMPATIBILITY IDEOGRAPH-FA4E [2000] [Unicode3.2] */ + {0xefa98f, 0xed57}, /* U+FA4F CJK COMPATIBILITY IDEOGRAPH-FA4F [2000] [Unicode3.2] */ + {0xefa990, 0xed58}, /* U+FA50 CJK COMPATIBILITY IDEOGRAPH-FA50 [2000] [Unicode3.2] */ + {0xefa991, 0xed5a}, /* U+FA51 CJK COMPATIBILITY IDEOGRAPH-FA51 [2000] [Unicode3.2] */ + {0xefa992, 0xed5e}, /* U+FA52 CJK COMPATIBILITY IDEOGRAPH-FA52 [2000] [Unicode3.2] */ + {0xefa993, 0xed5f}, /* U+FA53 CJK COMPATIBILITY IDEOGRAPH-FA53 [2000] [Unicode3.2] */ + {0xefa994, 0xed6c}, /* U+FA54 CJK COMPATIBILITY IDEOGRAPH-FA54 [2000] [Unicode3.2] */ + {0xefa995, 0xed70}, /* U+FA55 CJK COMPATIBILITY IDEOGRAPH-FA55 [2000] [Unicode3.2] */ + {0xefa996, 0xed84}, /* U+FA56 CJK COMPATIBILITY IDEOGRAPH-FA56 [2000] [Unicode3.2] */ + {0xefa997, 0xedac}, /* U+FA57 CJK COMPATIBILITY IDEOGRAPH-FA57 [2000] [Unicode3.2] */ + {0xefa998, 0xf7ce}, /* U+FA58 CJK COMPATIBILITY IDEOGRAPH-FA58 [2000] [Unicode3.2] */ + {0xefa999, 0xedb1}, /* U+FA59 CJK COMPATIBILITY IDEOGRAPH-FA59 [2000] [Unicode3.2] */ + {0xefa99a, 0xedb8}, /* U+FA5A CJK COMPATIBILITY IDEOGRAPH-FA5A [2000] [Unicode3.2] */ + {0xefa99b, 0xedc2}, /* U+FA5B CJK COMPATIBILITY IDEOGRAPH-FA5B [2000] [Unicode3.2] */ + {0xefa99c, 0xedd6}, /* U+FA5C CJK COMPATIBILITY IDEOGRAPH-FA5C [2000] [Unicode3.2] */ + {0xefa99d, 0xf894}, /* U+FA5D CJK COMPATIBILITY IDEOGRAPH-FA5D [2000] [Unicode3.2] */ + {0xefa99e, 0xf895}, /* U+FA5E CJK COMPATIBILITY IDEOGRAPH-FA5E [2000] [Unicode3.2] */ + {0xefa99f, 0xee46}, /* U+FA5F CJK COMPATIBILITY IDEOGRAPH-FA5F [2000] [Unicode3.2] */ + {0xefa9a0, 0xee8f}, /* U+FA60 CJK COMPATIBILITY IDEOGRAPH-FA60 [2000] [Unicode3.2] */ + {0xefa9a1, 0xee99}, /* U+FA61 CJK COMPATIBILITY IDEOGRAPH-FA61 [2000] [Unicode3.2] */ + {0xefa9a2, 0xeead}, /* U+FA62 CJK COMPATIBILITY IDEOGRAPH-FA62 [2000] [Unicode3.2] */ + {0xefa9a3, 0xeeae}, /* U+FA63 CJK COMPATIBILITY IDEOGRAPH-FA63 [2000] [Unicode3.2] */ + {0xefa9a4, 0xeeb6}, /* U+FA64 CJK COMPATIBILITY IDEOGRAPH-FA64 [2000] [Unicode3.2] */ + {0xefa9a5, 0xeebb}, /* U+FA65 CJK COMPATIBILITY IDEOGRAPH-FA65 [2000] [Unicode3.2] */ + {0xefa9a6, 0xfa89}, /* U+FA66 CJK COMPATIBILITY IDEOGRAPH-FA66 [2000] [Unicode3.2] */ + {0xefa9a7, 0xeed7}, /* U+FA67 CJK COMPATIBILITY IDEOGRAPH-FA67 [2000] [Unicode3.2] */ + {0xefa9a8, 0xef83}, /* U+FA68 CJK COMPATIBILITY IDEOGRAPH-FA68 [2000] [Unicode3.2] */ + {0xefa9a9, 0xef96}, /* U+FA69 CJK COMPATIBILITY IDEOGRAPH-FA69 [2000] [Unicode3.2] */ + {0xefa9aa, 0xef9b}, /* U+FA6A CJK COMPATIBILITY IDEOGRAPH-FA6A [2000] [Unicode3.2] */ + {0xefb985, 0x825d}, /* U+FE45 SESAME DOT [2000] [Unicode3.2] */ + {0xefb986, 0x825c}, /* U+FE46 WHITE SESAME DOT [2000] [Unicode3.2] */ + {0xefbc81, 0x8149}, /* U+FF01 FULLWIDTH EXCLAMATION MARK */ + {0xefbc82, 0x81ae}, /* U+FF02 FULLWIDTH QUOTATION MARK [2000] */ + {0xefbc83, 0x8194}, /* U+FF03 FULLWIDTH NUMBER SIGN */ + {0xefbc84, 0x8190}, /* U+FF04 FULLWIDTH DOLLAR SIGN */ + {0xefbc85, 0x8193}, /* U+FF05 FULLWIDTH PERCENT SIGN */ + {0xefbc86, 0x8195}, /* U+FF06 FULLWIDTH AMPERSAND */ + {0xefbc87, 0x81ad}, /* U+FF07 FULLWIDTH APOSTROPHE */ + {0xefbc88, 0x8169}, /* U+FF08 FULLWIDTH LEFT PARENTHESIS */ + {0xefbc89, 0x816a}, /* U+FF09 FULLWIDTH RIGHT PARENTHESIS */ + {0xefbc8a, 0x8196}, /* U+FF0A FULLWIDTH ASTERISK */ + {0xefbc8b, 0x817b}, /* U+FF0B FULLWIDTH PLUS SIGN */ + {0xefbc8c, 0x8143}, /* U+FF0C FULLWIDTH COMMA */ + {0xefbc8d, 0x81af}, /* U+FF0D FULLWIDTH HYPHEN-MINUS [2000] */ + {0xefbc8e, 0x8144}, /* U+FF0E FULLWIDTH FULL STOP */ + {0xefbc8f, 0x815e}, /* U+FF0F FULLWIDTH SOLIDUS */ + {0xefbc90, 0x824f}, /* U+FF10 FULLWIDTH DIGIT ZERO */ + {0xefbc91, 0x8250}, /* U+FF11 FULLWIDTH DIGIT ONE */ + {0xefbc92, 0x8251}, /* U+FF12 FULLWIDTH DIGIT TWO */ + {0xefbc93, 0x8252}, /* U+FF13 FULLWIDTH DIGIT THREE */ + {0xefbc94, 0x8253}, /* U+FF14 FULLWIDTH DIGIT FOUR */ + {0xefbc95, 0x8254}, /* U+FF15 FULLWIDTH DIGIT FIVE */ + {0xefbc96, 0x8255}, /* U+FF16 FULLWIDTH DIGIT SIX */ + {0xefbc97, 0x8256}, /* U+FF17 FULLWIDTH DIGIT SEVEN */ + {0xefbc98, 0x8257}, /* U+FF18 FULLWIDTH DIGIT EIGHT */ + {0xefbc99, 0x8258}, /* U+FF19 FULLWIDTH DIGIT NINE */ + {0xefbc9a, 0x8146}, /* U+FF1A FULLWIDTH COLON */ + {0xefbc9b, 0x8147}, /* U+FF1B FULLWIDTH SEMICOLON */ + {0xefbc9c, 0x8183}, /* U+FF1C FULLWIDTH LESS-THAN SIGN */ + {0xefbc9d, 0x8181}, /* U+FF1D FULLWIDTH EQUALS SIGN */ + {0xefbc9e, 0x8184}, /* U+FF1E FULLWIDTH GREATER-THAN SIGN */ + {0xefbc9f, 0x8148}, /* U+FF1F FULLWIDTH QUESTION MARK */ + {0xefbca0, 0x8197}, /* U+FF20 FULLWIDTH COMMERCIAL AT */ + {0xefbca1, 0x8260}, /* U+FF21 FULLWIDTH LATIN CAPITAL LETTER A */ + {0xefbca2, 0x8261}, /* U+FF22 FULLWIDTH LATIN CAPITAL LETTER B */ + {0xefbca3, 0x8262}, /* U+FF23 FULLWIDTH LATIN CAPITAL LETTER C */ + {0xefbca4, 0x8263}, /* U+FF24 FULLWIDTH LATIN CAPITAL LETTER D */ + {0xefbca5, 0x8264}, /* U+FF25 FULLWIDTH LATIN CAPITAL LETTER E */ + {0xefbca6, 0x8265}, /* U+FF26 FULLWIDTH LATIN CAPITAL LETTER F */ + {0xefbca7, 0x8266}, /* U+FF27 FULLWIDTH LATIN CAPITAL LETTER G */ + {0xefbca8, 0x8267}, /* U+FF28 FULLWIDTH LATIN CAPITAL LETTER H */ + {0xefbca9, 0x8268}, /* U+FF29 FULLWIDTH LATIN CAPITAL LETTER I */ + {0xefbcaa, 0x8269}, /* U+FF2A FULLWIDTH LATIN CAPITAL LETTER J */ + {0xefbcab, 0x826a}, /* U+FF2B FULLWIDTH LATIN CAPITAL LETTER K */ + {0xefbcac, 0x826b}, /* U+FF2C FULLWIDTH LATIN CAPITAL LETTER L */ + {0xefbcad, 0x826c}, /* U+FF2D FULLWIDTH LATIN CAPITAL LETTER M */ + {0xefbcae, 0x826d}, /* U+FF2E FULLWIDTH LATIN CAPITAL LETTER N */ + {0xefbcaf, 0x826e}, /* U+FF2F FULLWIDTH LATIN CAPITAL LETTER O */ + {0xefbcb0, 0x826f}, /* U+FF30 FULLWIDTH LATIN CAPITAL LETTER P */ + {0xefbcb1, 0x8270}, /* U+FF31 FULLWIDTH LATIN CAPITAL LETTER Q */ + {0xefbcb2, 0x8271}, /* U+FF32 FULLWIDTH LATIN CAPITAL LETTER R */ + {0xefbcb3, 0x8272}, /* U+FF33 FULLWIDTH LATIN CAPITAL LETTER S */ + {0xefbcb4, 0x8273}, /* U+FF34 FULLWIDTH LATIN CAPITAL LETTER T */ + {0xefbcb5, 0x8274}, /* U+FF35 FULLWIDTH LATIN CAPITAL LETTER U */ + {0xefbcb6, 0x8275}, /* U+FF36 FULLWIDTH LATIN CAPITAL LETTER V */ + {0xefbcb7, 0x8276}, /* U+FF37 FULLWIDTH LATIN CAPITAL LETTER W */ + {0xefbcb8, 0x8277}, /* U+FF38 FULLWIDTH LATIN CAPITAL LETTER X */ + {0xefbcb9, 0x8278}, /* U+FF39 FULLWIDTH LATIN CAPITAL LETTER Y */ + {0xefbcba, 0x8279}, /* U+FF3A FULLWIDTH LATIN CAPITAL LETTER Z */ + {0xefbcbb, 0x816d}, /* U+FF3B FULLWIDTH LEFT SQUARE BRACKET */ + {0xefbcbd, 0x816e}, /* U+FF3D FULLWIDTH RIGHT SQUARE BRACKET */ + {0xefbcbe, 0x814f}, /* U+FF3E FULLWIDTH CIRCUMFLEX ACCENT */ + {0xefbcbf, 0x8151}, /* U+FF3F FULLWIDTH LOW LINE */ + {0xefbd80, 0x814d}, /* U+FF40 FULLWIDTH GRAVE ACCENT */ + {0xefbd81, 0x8281}, /* U+FF41 FULLWIDTH LATIN SMALL LETTER A */ + {0xefbd82, 0x8282}, /* U+FF42 FULLWIDTH LATIN SMALL LETTER B */ + {0xefbd83, 0x8283}, /* U+FF43 FULLWIDTH LATIN SMALL LETTER C */ + {0xefbd84, 0x8284}, /* U+FF44 FULLWIDTH LATIN SMALL LETTER D */ + {0xefbd85, 0x8285}, /* U+FF45 FULLWIDTH LATIN SMALL LETTER E */ + {0xefbd86, 0x8286}, /* U+FF46 FULLWIDTH LATIN SMALL LETTER F */ + {0xefbd87, 0x8287}, /* U+FF47 FULLWIDTH LATIN SMALL LETTER G */ + {0xefbd88, 0x8288}, /* U+FF48 FULLWIDTH LATIN SMALL LETTER H */ + {0xefbd89, 0x8289}, /* U+FF49 FULLWIDTH LATIN SMALL LETTER I */ + {0xefbd8a, 0x828a}, /* U+FF4A FULLWIDTH LATIN SMALL LETTER J */ + {0xefbd8b, 0x828b}, /* U+FF4B FULLWIDTH LATIN SMALL LETTER K */ + {0xefbd8c, 0x828c}, /* U+FF4C FULLWIDTH LATIN SMALL LETTER L */ + {0xefbd8d, 0x828d}, /* U+FF4D FULLWIDTH LATIN SMALL LETTER M */ + {0xefbd8e, 0x828e}, /* U+FF4E FULLWIDTH LATIN SMALL LETTER N */ + {0xefbd8f, 0x828f}, /* U+FF4F FULLWIDTH LATIN SMALL LETTER O */ + {0xefbd90, 0x8290}, /* U+FF50 FULLWIDTH LATIN SMALL LETTER P */ + {0xefbd91, 0x8291}, /* U+FF51 FULLWIDTH LATIN SMALL LETTER Q */ + {0xefbd92, 0x8292}, /* U+FF52 FULLWIDTH LATIN SMALL LETTER R */ + {0xefbd93, 0x8293}, /* U+FF53 FULLWIDTH LATIN SMALL LETTER S */ + {0xefbd94, 0x8294}, /* U+FF54 FULLWIDTH LATIN SMALL LETTER T */ + {0xefbd95, 0x8295}, /* U+FF55 FULLWIDTH LATIN SMALL LETTER U */ + {0xefbd96, 0x8296}, /* U+FF56 FULLWIDTH LATIN SMALL LETTER V */ + {0xefbd97, 0x8297}, /* U+FF57 FULLWIDTH LATIN SMALL LETTER W */ + {0xefbd98, 0x8298}, /* U+FF58 FULLWIDTH LATIN SMALL LETTER X */ + {0xefbd99, 0x8299}, /* U+FF59 FULLWIDTH LATIN SMALL LETTER Y */ + {0xefbd9a, 0x829a}, /* U+FF5A FULLWIDTH LATIN SMALL LETTER Z */ + {0xefbd9b, 0x816f}, /* U+FF5B FULLWIDTH LEFT CURLY BRACKET */ + {0xefbd9c, 0x8162}, /* U+FF5C FULLWIDTH VERTICAL LINE */ + {0xefbd9d, 0x8170}, /* U+FF5D FULLWIDTH RIGHT CURLY BRACKET */ + {0xefbd9f, 0x81d4}, /* U+FF5F FULLWIDTH LEFT WHITE PARENTHESIS [2000] [Unicode3.2] */ + {0xefbda0, 0x81d5}, /* U+FF60 FULLWIDTH RIGHT WHITE PARENTHESIS [2000] [Unicode3.2] */ + {0xefbda1, 0x00a1}, /* U+FF61 HALFWIDTH IDEOGRAPHIC FULL STOP */ + {0xefbda2, 0x00a2}, /* U+FF62 HALFWIDTH LEFT CORNER BRACKET */ + {0xefbda3, 0x00a3}, /* U+FF63 HALFWIDTH RIGHT CORNER BRACKET */ + {0xefbda4, 0x00a4}, /* U+FF64 HALFWIDTH IDEOGRAPHIC COMMA */ + {0xefbda5, 0x00a5}, /* U+FF65 HALFWIDTH KATAKANA MIDDLE DOT */ + {0xefbda6, 0x00a6}, /* U+FF66 HALFWIDTH KATAKANA LETTER WO */ + {0xefbda7, 0x00a7}, /* U+FF67 HALFWIDTH KATAKANA LETTER SMALL A */ + {0xefbda8, 0x00a8}, /* U+FF68 HALFWIDTH KATAKANA LETTER SMALL I */ + {0xefbda9, 0x00a9}, /* U+FF69 HALFWIDTH KATAKANA LETTER SMALL U */ + {0xefbdaa, 0x00aa}, /* U+FF6A HALFWIDTH KATAKANA LETTER SMALL E */ + {0xefbdab, 0x00ab}, /* U+FF6B HALFWIDTH KATAKANA LETTER SMALL O */ + {0xefbdac, 0x00ac}, /* U+FF6C HALFWIDTH KATAKANA LETTER SMALL YA */ + {0xefbdad, 0x00ad}, /* U+FF6D HALFWIDTH KATAKANA LETTER SMALL YU */ + {0xefbdae, 0x00ae}, /* U+FF6E HALFWIDTH KATAKANA LETTER SMALL YO */ + {0xefbdaf, 0x00af}, /* U+FF6F HALFWIDTH KATAKANA LETTER SMALL TU */ + {0xefbdb0, 0x00b0}, /* U+FF70 HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK */ + {0xefbdb1, 0x00b1}, /* U+FF71 HALFWIDTH KATAKANA LETTER A */ + {0xefbdb2, 0x00b2}, /* U+FF72 HALFWIDTH KATAKANA LETTER I */ + {0xefbdb3, 0x00b3}, /* U+FF73 HALFWIDTH KATAKANA LETTER U */ + {0xefbdb4, 0x00b4}, /* U+FF74 HALFWIDTH KATAKANA LETTER E */ + {0xefbdb5, 0x00b5}, /* U+FF75 HALFWIDTH KATAKANA LETTER O */ + {0xefbdb6, 0x00b6}, /* U+FF76 HALFWIDTH KATAKANA LETTER KA */ + {0xefbdb7, 0x00b7}, /* U+FF77 HALFWIDTH KATAKANA LETTER KI */ + {0xefbdb8, 0x00b8}, /* U+FF78 HALFWIDTH KATAKANA LETTER KU */ + {0xefbdb9, 0x00b9}, /* U+FF79 HALFWIDTH KATAKANA LETTER KE */ + {0xefbdba, 0x00ba}, /* U+FF7A HALFWIDTH KATAKANA LETTER KO */ + {0xefbdbb, 0x00bb}, /* U+FF7B HALFWIDTH KATAKANA LETTER SA */ + {0xefbdbc, 0x00bc}, /* U+FF7C HALFWIDTH KATAKANA LETTER SI */ + {0xefbdbd, 0x00bd}, /* U+FF7D HALFWIDTH KATAKANA LETTER SU */ + {0xefbdbe, 0x00be}, /* U+FF7E HALFWIDTH KATAKANA LETTER SE */ + {0xefbdbf, 0x00bf}, /* U+FF7F HALFWIDTH KATAKANA LETTER SO */ + {0xefbe80, 0x00c0}, /* U+FF80 HALFWIDTH KATAKANA LETTER TA */ + {0xefbe81, 0x00c1}, /* U+FF81 HALFWIDTH KATAKANA LETTER TI */ + {0xefbe82, 0x00c2}, /* U+FF82 HALFWIDTH KATAKANA LETTER TU */ + {0xefbe83, 0x00c3}, /* U+FF83 HALFWIDTH KATAKANA LETTER TE */ + {0xefbe84, 0x00c4}, /* U+FF84 HALFWIDTH KATAKANA LETTER TO */ + {0xefbe85, 0x00c5}, /* U+FF85 HALFWIDTH KATAKANA LETTER NA */ + {0xefbe86, 0x00c6}, /* U+FF86 HALFWIDTH KATAKANA LETTER NI */ + {0xefbe87, 0x00c7}, /* U+FF87 HALFWIDTH KATAKANA LETTER NU */ + {0xefbe88, 0x00c8}, /* U+FF88 HALFWIDTH KATAKANA LETTER NE */ + {0xefbe89, 0x00c9}, /* U+FF89 HALFWIDTH KATAKANA LETTER NO */ + {0xefbe8a, 0x00ca}, /* U+FF8A HALFWIDTH KATAKANA LETTER HA */ + {0xefbe8b, 0x00cb}, /* U+FF8B HALFWIDTH KATAKANA LETTER HI */ + {0xefbe8c, 0x00cc}, /* U+FF8C HALFWIDTH KATAKANA LETTER HU */ + {0xefbe8d, 0x00cd}, /* U+FF8D HALFWIDTH KATAKANA LETTER HE */ + {0xefbe8e, 0x00ce}, /* U+FF8E HALFWIDTH KATAKANA LETTER HO */ + {0xefbe8f, 0x00cf}, /* U+FF8F HALFWIDTH KATAKANA LETTER MA */ + {0xefbe90, 0x00d0}, /* U+FF90 HALFWIDTH KATAKANA LETTER MI */ + {0xefbe91, 0x00d1}, /* U+FF91 HALFWIDTH KATAKANA LETTER MU */ + {0xefbe92, 0x00d2}, /* U+FF92 HALFWIDTH KATAKANA LETTER ME */ + {0xefbe93, 0x00d3}, /* U+FF93 HALFWIDTH KATAKANA LETTER MO */ + {0xefbe94, 0x00d4}, /* U+FF94 HALFWIDTH KATAKANA LETTER YA */ + {0xefbe95, 0x00d5}, /* U+FF95 HALFWIDTH KATAKANA LETTER YU */ + {0xefbe96, 0x00d6}, /* U+FF96 HALFWIDTH KATAKANA LETTER YO */ + {0xefbe97, 0x00d7}, /* U+FF97 HALFWIDTH KATAKANA LETTER RA */ + {0xefbe98, 0x00d8}, /* U+FF98 HALFWIDTH KATAKANA LETTER RI */ + {0xefbe99, 0x00d9}, /* U+FF99 HALFWIDTH KATAKANA LETTER RU */ + {0xefbe9a, 0x00da}, /* U+FF9A HALFWIDTH KATAKANA LETTER RE */ + {0xefbe9b, 0x00db}, /* U+FF9B HALFWIDTH KATAKANA LETTER RO */ + {0xefbe9c, 0x00dc}, /* U+FF9C HALFWIDTH KATAKANA LETTER WA */ + {0xefbe9d, 0x00dd}, /* U+FF9D HALFWIDTH KATAKANA LETTER N */ + {0xefbe9e, 0x00de}, /* U+FF9E HALFWIDTH KATAKANA VOICED SOUND MARK */ + {0xefbe9f, 0x00df}, /* U+FF9F HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK */ + {0xefbfa3, 0x8150}, /* U+FFE3 FULLWIDTH MACRON */ + {0xefbfa5, 0x818f}, /* U+FFE5 FULLWIDTH YEN SIGN */ + {0xf0a0808b, 0x87a0}, /* U+2000B [2000] [Unicode3.1] */ + {0xf0a08289, 0xf040}, /* U+20089 [2000] [Unicode3.1] */ + {0xf0a082a2, 0xf04a}, /* U+200A2 [2000] [Unicode3.1] */ + {0xf0a082a4, 0xf04d}, /* U+200A4 [2000] [Unicode3.1] */ + {0xf0a086a2, 0xf055}, /* U+201A2 [2000] [Unicode3.1] */ + {0xf0a08893, 0xf065}, /* U+20213 [2000] [Unicode3.1] */ + {0xf0a08cab, 0xf090}, /* U+2032B [2000] [Unicode3.1] */ + {0xf0a08db1, 0xf099}, /* U+20371 [2000] [Unicode3.1] */ + {0xf0a08e81, 0xf097}, /* U+20381 [2000] [Unicode3.1] */ + {0xf0a08fb9, 0xf141}, /* U+203F9 [2000] [Unicode3.1] */ + {0xf0a0918a, 0xf144}, /* U+2044A [2000] [Unicode3.1] */ + {0xf0a09489, 0xf146}, /* U+20509 [2000] [Unicode3.1] */ + {0xf0a09796, 0xf150}, /* U+205D6 [2000] [Unicode3.1] */ + {0xf0a098a8, 0xf151}, /* U+20628 [2000] [Unicode3.1] */ + {0xf0a09d8f, 0xf157}, /* U+2074F [2000] [Unicode3.1] */ + {0xf0a0a087, 0xf15e}, /* U+20807 [2000] [Unicode3.1] */ + {0xf0a0a0ba, 0xf160}, /* U+2083A [2000] [Unicode3.1] */ + {0xf0a0a2b9, 0xf169}, /* U+208B9 [2000] [Unicode3.1] */ + {0xf0a0a5bc, 0xf171}, /* U+2097C [2000] [Unicode3.1] */ + {0xf0a0a69d, 0xf172}, /* U+2099D [2000] [Unicode3.1] */ + {0xf0a0ab93, 0xf178}, /* U+20AD3 [2000] [Unicode3.1] */ + {0xf0a0ac9d, 0xf17b}, /* U+20B1D [2000] [Unicode3.1] */ + {0xf0a0ae9f, 0x9873}, /* U+20B9F [2004] [Unicode3.1] */ + {0xf0a0b585, 0xf197}, /* U+20D45 [2000] [Unicode3.1] */ + {0xf0a0b7a1, 0xf1a8}, /* U+20DE1 [2000] [Unicode3.1] */ + {0xf0a0b9a4, 0xf1b8}, /* U+20E64 [2000] [Unicode3.1] */ + {0xf0a0b9ad, 0xf1b0}, /* U+20E6D [2000] [Unicode3.1] */ + {0xf0a0ba95, 0xf1af}, /* U+20E95 [2000] [Unicode3.1] */ + {0xf0a0bd9f, 0xf1bb}, /* U+20F5F [2000] [Unicode3.1] */ + {0xf0a18881, 0xf1d7}, /* U+21201 [2000] [Unicode3.1] */ + {0xf0a188bd, 0x8861}, /* U+2123D [2000] [Unicode3.1] */ + {0xf0a18995, 0xf1da}, /* U+21255 [2000] [Unicode3.1] */ + {0xf0a189b4, 0xf1e1}, /* U+21274 [2000] [Unicode3.1] */ + {0xf0a189bb, 0xf1dc}, /* U+2127B [2000] [Unicode3.1] */ + {0xf0a18b97, 0xf1e9}, /* U+212D7 [2000] [Unicode3.1] */ + {0xf0a18ba4, 0xf1e8}, /* U+212E4 [2000] [Unicode3.1] */ + {0xf0a18bbd, 0xf1f0}, /* U+212FD [2000] [Unicode3.1] */ + {0xf0a18c9b, 0x886b}, /* U+2131B [2000] [Unicode3.1] */ + {0xf0a18cb6, 0xf1f2}, /* U+21336 [2000] [Unicode3.1] */ + {0xf0a18d84, 0xf1f3}, /* U+21344 [2000] [Unicode3.1] */ + {0xf0a18f84, 0xf244}, /* U+213C4 [2000] [Unicode3.1] */ + {0xf0a191ad, 0xf251}, /* U+2146D [2000] [Unicode3.1] */ + {0xf0a191ae, 0x8880}, /* U+2146E [2000] [Unicode3.1] */ + {0xf0a19797, 0xf25d}, /* U+215D7 [2000] [Unicode3.1] */ + {0xf0a19987, 0xf266}, /* U+21647 [2000] [Unicode3.1] */ + {0xf0a19ab4, 0x9883}, /* U+216B4 [2000] [Unicode3.1] */ + {0xf0a19c86, 0xf274}, /* U+21706 [2000] [Unicode3.1] */ + {0xf0a19d82, 0xf275}, /* U+21742 [2000] [Unicode3.1] */ + {0xf0a1a2bd, 0x889b}, /* U+218BD [2000] [Unicode3.1] */ + {0xf0a1a783, 0xf29e}, /* U+219C3 [2000] [Unicode3.1] */ + {0xf0a1b196, 0xf0ae}, /* U+21C56 [2000] [Unicode3.1] */ + {0xf0a1b4ad, 0xf0b5}, /* U+21D2D [2000] [Unicode3.1] */ + {0xf0a1b585, 0xf0b6}, /* U+21D45 [2000] [Unicode3.1] */ + {0xf0a1b5a2, 0xf0b9}, /* U+21D62 [2000] [Unicode3.1] */ + {0xf0a1b5b8, 0xf0b8}, /* U+21D78 [2000] [Unicode3.1] */ + {0xf0a1b692, 0xf0c3}, /* U+21D92 [2000] [Unicode3.1] */ + {0xf0a1b69c, 0xf0be}, /* U+21D9C [2000] [Unicode3.1] */ + {0xf0a1b6a1, 0xf0bd}, /* U+21DA1 [2000] [Unicode3.1] */ + {0xf0a1b6b7, 0xf0c6}, /* U+21DB7 [2000] [Unicode3.1] */ + {0xf0a1b7a0, 0xf0c8}, /* U+21DE0 [2000] [Unicode3.1] */ + {0xf0a1b8b3, 0xf0c9}, /* U+21E33 [2000] [Unicode3.1] */ + {0xf0a1b8b4, 0x988e}, /* U+21E34 [2000] [Unicode3.1] */ + {0xf0a1bc9e, 0xf0d9}, /* U+21F1E [2000] [Unicode3.1] */ + {0xf0a1bdb6, 0xf0e4}, /* U+21F76 [2000] [Unicode3.1] */ + {0xf0a1bfba, 0xf0ea}, /* U+21FFA [2000] [Unicode3.1] */ + {0xf0a285bb, 0xf2a0}, /* U+2217B [2000] [Unicode3.1] */ + {0xf0a28898, 0xfcd1}, /* U+22218 [2000] [Unicode3.1] */ + {0xf0a28c9e, 0xf2a9}, /* U+2231E [2000] [Unicode3.1] */ + {0xf0a28ead, 0xf2ae}, /* U+223AD [2000] [Unicode3.1] */ + {0xf0a29bb3, 0xf2ce}, /* U+226F3 [2000] [Unicode3.1] */ + {0xf0a2a19b, 0xf2e3}, /* U+2285B [2000] [Unicode3.1] */ + {0xf0a2a2ab, 0xf2eb}, /* U+228AB [2000] [Unicode3.1] */ + {0xf0a2a68f, 0xf2f0}, /* U+2298F [2000] [Unicode3.1] */ + {0xf0a2aab8, 0xf343}, /* U+22AB8 [2000] [Unicode3.1] */ + {0xf0a2ad86, 0xf351}, /* U+22B46 [2000] [Unicode3.1] */ + {0xf0a2ad8f, 0xf348}, /* U+22B4F [2000] [Unicode3.1] */ + {0xf0a2ad90, 0xf349}, /* U+22B50 [2000] [Unicode3.1] */ + {0xf0a2aea6, 0xf354}, /* U+22BA6 [2000] [Unicode3.1] */ + {0xf0a2b09d, 0xf353}, /* U+22C1D [2000] [Unicode3.1] */ + {0xf0a2b0a4, 0xf358}, /* U+22C24 [2000] [Unicode3.1] */ + {0xf0a2b7a1, 0xf375}, /* U+22DE1 [2000] [Unicode3.1] */ + {0xf0a386b6, 0xf3a2}, /* U+231B6 [2000] [Unicode3.1] */ + {0xf0a38783, 0xf39d}, /* U+231C3 [2000] [Unicode3.1] */ + {0xf0a38784, 0xeb59}, /* U+231C4 [2000] [Unicode3.1] */ + {0xf0a387b5, 0xf3a1}, /* U+231F5 [2000] [Unicode3.1] */ + {0xf0a38db2, 0xf3b8}, /* U+23372 [2000] [Unicode3.1] */ + {0xf0a38f90, 0xf3c0}, /* U+233D0 [2000] [Unicode3.1] */ + {0xf0a38f92, 0xf3bb}, /* U+233D2 [2000] [Unicode3.1] */ + {0xf0a38f93, 0xf3ba}, /* U+233D3 [2000] [Unicode3.1] */ + {0xf0a38f95, 0xf3c2}, /* U+233D5 [2000] [Unicode3.1] */ + {0xf0a38f9a, 0xf3c5}, /* U+233DA [2000] [Unicode3.1] */ + {0xf0a38f9f, 0xf3c7}, /* U+233DF [2000] [Unicode3.1] */ + {0xf0a38fa4, 0xf3c1}, /* U+233E4 [2000] [Unicode3.1] */ + {0xf0a3918a, 0xf3d3}, /* U+2344A [2000] [Unicode3.1] */ + {0xf0a3918b, 0xf3d5}, /* U+2344B [2000] [Unicode3.1] */ + {0xf0a39191, 0xf3d4}, /* U+23451 [2000] [Unicode3.1] */ + {0xf0a391a5, 0xf3d9}, /* U+23465 [2000] [Unicode3.1] */ + {0xf0a393a4, 0xf3f5}, /* U+234E4 [2000] [Unicode3.1] */ + {0xf0a3959a, 0xf3f6}, /* U+2355A [2000] [Unicode3.1] */ + {0xf0a39694, 0xf449}, /* U+23594 [2000] [Unicode3.1] */ + {0xf0a39784, 0xeb92}, /* U+235C4 [2000] [Unicode3.1] */ + {0xf0a398b8, 0xf461}, /* U+23638 [2000] [Unicode3.1] */ + {0xf0a398b9, 0xf45e}, /* U+23639 [2000] [Unicode3.1] */ + {0xf0a398ba, 0xf462}, /* U+2363A [2000] [Unicode3.1] */ + {0xf0a39987, 0xf45f}, /* U+23647 [2000] [Unicode3.1] */ + {0xf0a39c8c, 0xf478}, /* U+2370C [2000] [Unicode3.1] */ + {0xf0a39c9c, 0xf46d}, /* U+2371C [2000] [Unicode3.1] */ + {0xf0a39cbf, 0xeba7}, /* U+2373F [2000] [Unicode3.1] */ + {0xf0a39da3, 0xebb0}, /* U+23763 [2000] [Unicode3.1] */ + {0xf0a39da4, 0xf481}, /* U+23764 [2000] [Unicode3.1] */ + {0xf0a39fa7, 0xf48a}, /* U+237E7 [2000] [Unicode3.1] */ + {0xf0a39fbf, 0xf489}, /* U+237FF [2000] [Unicode3.1] */ + {0xf0a3a0a4, 0xf490}, /* U+23824 [2000] [Unicode3.1] */ + {0xf0a3a0bd, 0xf495}, /* U+2383D [2000] [Unicode3.1] */ + {0xf0a3aa98, 0xf4a1}, /* U+23A98 [2000] [Unicode3.1] */ + {0xf0a3b1bf, 0xf4b2}, /* U+23C7F [2000] [Unicode3.1] */ + {0xf0a3b3be, 0xebde}, /* U+23CFE [2000] [Unicode3.1] */ + {0xf0a3b480, 0xf4c7}, /* U+23D00 [2000] [Unicode3.1] */ + {0xf0a3b48e, 0xf7f3}, /* U+23D0E [2000] [Unicode3.1] */ + {0xf0a3b580, 0xf4da}, /* U+23D40 [2000] [Unicode3.1] */ + {0xf0a3b793, 0xf4de}, /* U+23DD3 [2000] [Unicode3.1] */ + {0xf0a3b7b9, 0xf4dd}, /* U+23DF9 [2000] [Unicode3.1] */ + {0xf0a3b7ba, 0xf4dc}, /* U+23DFA [2000] [Unicode3.1] */ + {0xf0a3bdbe, 0xf551}, /* U+23F7E [2000] [Unicode3.1] */ + {0xf0a48296, 0xf566}, /* U+24096 [2000] [Unicode3.1] */ + {0xf0a48483, 0xf56c}, /* U+24103 [2000] [Unicode3.1] */ + {0xf0a48786, 0xf581}, /* U+241C6 [2000] [Unicode3.1] */ + {0xf0a487be, 0xf584}, /* U+241FE [2000] [Unicode3.1] */ + {0xf0a48ebc, 0xf5a0}, /* U+243BC [2000] [Unicode3.1] */ + {0xf0a498a9, 0xf5b1}, /* U+24629 [2000] [Unicode3.1] */ + {0xf0a49aa5, 0xf5b7}, /* U+246A5 [2000] [Unicode3.1] */ + {0xf0a49fb1, 0xec8c}, /* U+247F1 [2000] [Unicode3.1] */ + {0xf0a4a296, 0xf5d1}, /* U+24896 [2000] [Unicode3.1] */ + {0xf0a4a98d, 0xf5f9}, /* U+24A4D [2000] [Unicode3.1] */ + {0xf0a4ad96, 0xf64d}, /* U+24B56 [2000] [Unicode3.1] */ + {0xf0a4adaf, 0xf64f}, /* U+24B6F [2000] [Unicode3.1] */ + {0xf0a4b096, 0xf654}, /* U+24C16 [2000] [Unicode3.1] */ + {0xf0a4b494, 0xf663}, /* U+24D14 [2000] [Unicode3.1] */ + {0xf0a4b88e, 0xf67c}, /* U+24E0E [2000] [Unicode3.1] */ + {0xf0a4b8b7, 0xf681}, /* U+24E37 [2000] [Unicode3.1] */ + {0xf0a4b9aa, 0xf686}, /* U+24E6A [2000] [Unicode3.1] */ + {0xf0a4ba8b, 0xf689}, /* U+24E8B [2000] [Unicode3.1] */ + {0xf0a5818a, 0xf695}, /* U+2504A [2000] [Unicode3.1] */ + {0xf0a58195, 0xf697}, /* U+25055 [2000] [Unicode3.1] */ + {0xf0a584a2, 0xf69a}, /* U+25122 [2000] [Unicode3.1] */ + {0xf0a586a9, 0xf69f}, /* U+251A9 [2000] [Unicode3.1] */ + {0xf0a5878d, 0xf6a2}, /* U+251CD [2000] [Unicode3.1] */ + {0xf0a587a5, 0xf6a1}, /* U+251E5 [2000] [Unicode3.1] */ + {0xf0a5889e, 0xf6a6}, /* U+2521E [2000] [Unicode3.1] */ + {0xf0a5898c, 0xf6aa}, /* U+2524C [2000] [Unicode3.1] */ + {0xf0a590ae, 0xf6bb}, /* U+2542E [2000] [Unicode3.1] */ + {0xf0a5928e, 0xecfc}, /* U+2548E [2000] [Unicode3.1] */ + {0xf0a59399, 0xf6c6}, /* U+254D9 [2000] [Unicode3.1] */ + {0xf0a5948e, 0xed48}, /* U+2550E [2000] [Unicode3.1] */ + {0xf0a596a7, 0xf6d9}, /* U+255A7 [2000] [Unicode3.1] */ + {0xf0a59db1, 0xed66}, /* U+25771 [2000] [Unicode3.1] */ + {0xf0a59ea9, 0xf6f3}, /* U+257A9 [2000] [Unicode3.1] */ + {0xf0a59eb4, 0xf6f4}, /* U+257B4 [2000] [Unicode3.1] */ + {0xf0a5a784, 0xed73}, /* U+259C4 [2000] [Unicode3.1] */ + {0xf0a5a794, 0xf751}, /* U+259D4 [2000] [Unicode3.1] */ + {0xf0a5aba3, 0xf75d}, /* U+25AE3 [2000] [Unicode3.1] */ + {0xf0a5aba4, 0xf75c}, /* U+25AE4 [2000] [Unicode3.1] */ + {0xf0a5abb1, 0xf75f}, /* U+25AF1 [2000] [Unicode3.1] */ + {0xf0a5aeb2, 0xf771}, /* U+25BB2 [2000] [Unicode3.1] */ + {0xf0a5b18b, 0xf77c}, /* U+25C4B [2000] [Unicode3.1] */ + {0xf0a5b1a4, 0xf77d}, /* U+25C64 [2000] [Unicode3.1] */ + {0xf0a5b6a1, 0xed8e}, /* U+25DA1 [2000] [Unicode3.1] */ + {0xf0a5b8ae, 0xf793}, /* U+25E2E [2000] [Unicode3.1] */ + {0xf0a5b996, 0xf794}, /* U+25E56 [2000] [Unicode3.1] */ + {0xf0a5b9a2, 0xf797}, /* U+25E62 [2000] [Unicode3.1] */ + {0xf0a5b9a5, 0xf795}, /* U+25E65 [2000] [Unicode3.1] */ + {0xf0a5bb82, 0xf79d}, /* U+25EC2 [2000] [Unicode3.1] */ + {0xf0a5bb98, 0xf79b}, /* U+25ED8 [2000] [Unicode3.1] */ + {0xf0a5bba8, 0xf7a0}, /* U+25EE8 [2000] [Unicode3.1] */ + {0xf0a5bca3, 0xf7a2}, /* U+25F23 [2000] [Unicode3.1] */ + {0xf0a5bd9c, 0xf7a5}, /* U+25F5C [2000] [Unicode3.1] */ + {0xf0a5bf94, 0xf7ad}, /* U+25FD4 [2000] [Unicode3.1] */ + {0xf0a5bfa0, 0xf7ac}, /* U+25FE0 [2000] [Unicode3.1] */ + {0xf0a5bfbb, 0xf7b3}, /* U+25FFB [2000] [Unicode3.1] */ + {0xf0a6808c, 0xf7b2}, /* U+2600C [2000] [Unicode3.1] */ + {0xf0a68097, 0xf7bb}, /* U+26017 [2000] [Unicode3.1] */ + {0xf0a681a0, 0xf7c0}, /* U+26060 [2000] [Unicode3.1] */ + {0xf0a683ad, 0xf7cd}, /* U+260ED [2000] [Unicode3.1] */ + {0xf0a689b0, 0xf7e7}, /* U+26270 [2000] [Unicode3.1] */ + {0xf0a68a86, 0xf7e9}, /* U+26286 [2000] [Unicode3.1] */ + {0xf0a68d8c, 0xf7f0}, /* U+2634C [2000] [Unicode3.1] */ + {0xf0a69082, 0xf7f7}, /* U+26402 [2000] [Unicode3.1] */ + {0xf0a699be, 0xf854}, /* U+2667E [2000] [Unicode3.1] */ + {0xf0a69ab0, 0xf859}, /* U+266B0 [2000] [Unicode3.1] */ + {0xf0a69c9d, 0xf865}, /* U+2671D [2000] [Unicode3.1] */ + {0xf0a6a39d, 0xf875}, /* U+268DD [2000] [Unicode3.1] */ + {0xf0a6a3aa, 0xf877}, /* U+268EA [2000] [Unicode3.1] */ + {0xf0a6a591, 0xf879}, /* U+26951 [2000] [Unicode3.1] */ + {0xf0a6a5af, 0xf87c}, /* U+2696F [2000] [Unicode3.1] */ + {0xf0a6a79d, 0xf87e}, /* U+269DD [2000] [Unicode3.1] */ + {0xf0a6a89e, 0xf883}, /* U+26A1E [2000] [Unicode3.1] */ + {0xf0a6a998, 0xf88a}, /* U+26A58 [2000] [Unicode3.1] */ + {0xf0a6aa8c, 0xf890}, /* U+26A8C [2000] [Unicode3.1] */ + {0xf0a6aab7, 0xf893}, /* U+26AB7 [2000] [Unicode3.1] */ + {0xf0a6abbf, 0xeddb}, /* U+26AFF [2000] [Unicode3.1] */ + {0xf0a6b0a9, 0xf263}, /* U+26C29 [2000] [Unicode3.1] */ + {0xf0a6b1b3, 0xf8c2}, /* U+26C73 [2000] [Unicode3.1] */ + {0xf0a6b39d, 0xf8cc}, /* U+26CDD [2000] [Unicode3.1] */ + {0xf0a6b980, 0xee52}, /* U+26E40 [2000] [Unicode3.1] */ + {0xf0a6b9a5, 0xf8db}, /* U+26E65 [2000] [Unicode3.1] */ + {0xf0a6be94, 0xf8f3}, /* U+26F94 [2000] [Unicode3.1] */ + {0xf0a6bfb6, 0xf940}, /* U+26FF6 [2000] [Unicode3.1] */ + {0xf0a6bfb7, 0xf941}, /* U+26FF7 [2000] [Unicode3.1] */ + {0xf0a6bfb8, 0xf8fc}, /* U+26FF8 [2000] [Unicode3.1] */ + {0xf0a783b4, 0xee68}, /* U+270F4 [2000] [Unicode3.1] */ + {0xf0a7848d, 0xf952}, /* U+2710D [2000] [Unicode3.1] */ + {0xf0a784b9, 0xf955}, /* U+27139 [2000] [Unicode3.1] */ + {0xf0a78f9a, 0xf985}, /* U+273DA [2000] [Unicode3.1] */ + {0xf0a78f9b, 0xf984}, /* U+273DB [2000] [Unicode3.1] */ + {0xf0a78fbe, 0xf98b}, /* U+273FE [2000] [Unicode3.1] */ + {0xf0a79090, 0xf98e}, /* U+27410 [2000] [Unicode3.1] */ + {0xf0a79189, 0xf993}, /* U+27449 [2000] [Unicode3.1] */ + {0xf0a79894, 0xf9a8}, /* U+27614 [2000] [Unicode3.1] */ + {0xf0a79895, 0xf9a7}, /* U+27615 [2000] [Unicode3.1] */ + {0xf0a798b1, 0xf9aa}, /* U+27631 [2000] [Unicode3.1] */ + {0xf0a79a84, 0xee8c}, /* U+27684 [2000] [Unicode3.1] */ + {0xf0a79a93, 0xf9b2}, /* U+27693 [2000] [Unicode3.1] */ + {0xf0a79c8e, 0xf9ba}, /* U+2770E [2000] [Unicode3.1] */ + {0xf0a79ca3, 0xf9bc}, /* U+27723 [2000] [Unicode3.1] */ + {0xf0a79d92, 0xf9c0}, /* U+27752 [2000] [Unicode3.1] */ + {0xf0a7a685, 0xf9d4}, /* U+27985 [2000] [Unicode3.1] */ + {0xf0a7aa84, 0xf9e1}, /* U+27A84 [2000] [Unicode3.1] */ + {0xf0a7aeb3, 0xf9f5}, /* U+27BB3 [2000] [Unicode3.1] */ + {0xf0a7aebe, 0xf9f7}, /* U+27BBE [2000] [Unicode3.1] */ + {0xf0a7af87, 0xf9f8}, /* U+27BC7 [2000] [Unicode3.1] */ + {0xf0a7b2b8, 0xfa44}, /* U+27CB8 [2000] [Unicode3.1] */ + {0xf0a7b6a0, 0xfa4e}, /* U+27DA0 [2000] [Unicode3.1] */ + {0xf0a7b890, 0xfa51}, /* U+27E10 [2000] [Unicode3.1] */ + {0xf0a7beb7, 0xfa58}, /* U+27FB7 [2000] [Unicode3.1] */ + {0xf0a8828a, 0xfa61}, /* U+2808A [2000] [Unicode3.1] */ + {0xf0a882bb, 0xfa67}, /* U+280BB [2000] [Unicode3.1] */ + {0xf0a889b7, 0xeec7}, /* U+28277 [2000] [Unicode3.1] */ + {0xf0a88a82, 0xfa78}, /* U+28282 [2000] [Unicode3.1] */ + {0xf0a88bb3, 0xfa7d}, /* U+282F3 [2000] [Unicode3.1] */ + {0xf0a88f8d, 0xeecf}, /* U+283CD [2000] [Unicode3.1] */ + {0xf0a8908c, 0xfa86}, /* U+2840C [2000] [Unicode3.1] */ + {0xf0a89195, 0xfa8b}, /* U+28455 [2000] [Unicode3.1] */ + {0xf0a895ab, 0xfa9a}, /* U+2856B [2000] [Unicode3.1] */ + {0xf0a89788, 0xfa9e}, /* U+285C8 [2000] [Unicode3.1] */ + {0xf0a89789, 0xfa9f}, /* U+285C9 [2000] [Unicode3.1] */ + {0xf0a89b97, 0xfaaa}, /* U+286D7 [2000] [Unicode3.1] */ + {0xf0a89bba, 0xfaad}, /* U+286FA [2000] [Unicode3.1] */ + {0xf0a8a586, 0xface}, /* U+28946 [2000] [Unicode3.1] */ + {0xf0a8a589, 0xfacd}, /* U+28949 [2000] [Unicode3.1] */ + {0xf0a8a5ab, 0xfad5}, /* U+2896B [2000] [Unicode3.1] */ + {0xf0a8a687, 0xfae3}, /* U+28987 [2000] [Unicode3.1] */ + {0xf0a8a688, 0xfae4}, /* U+28988 [2000] [Unicode3.1] */ + {0xf0a8a6ba, 0xfaef}, /* U+289BA [2000] [Unicode3.1] */ + {0xf0a8a6bb, 0xfaf0}, /* U+289BB [2000] [Unicode3.1] */ + {0xf0a8a89e, 0xfafc}, /* U+28A1E [2000] [Unicode3.1] */ + {0xf0a8a8a9, 0xfb40}, /* U+28A29 [2000] [Unicode3.1] */ + {0xf0a8a983, 0xfb4c}, /* U+28A43 [2000] [Unicode3.1] */ + {0xf0a8a9b1, 0xfb4b}, /* U+28A71 [2000] [Unicode3.1] */ + {0xf0a8aa99, 0xfb55}, /* U+28A99 [2000] [Unicode3.1] */ + {0xf0a8ab8d, 0xfb56}, /* U+28ACD [2000] [Unicode3.1] */ + {0xf0a8ab9d, 0xfb5d}, /* U+28ADD [2000] [Unicode3.1] */ + {0xf0a8aba4, 0xfb5c}, /* U+28AE4 [2000] [Unicode3.1] */ + {0xf0a8af81, 0xfb6d}, /* U+28BC1 [2000] [Unicode3.1] */ + {0xf0a8afaf, 0xfb6e}, /* U+28BEF [2000] [Unicode3.1] */ + {0xf0a8b490, 0xfb76}, /* U+28D10 [2000] [Unicode3.1] */ + {0xf0a8b5b1, 0xfb79}, /* U+28D71 [2000] [Unicode3.1] */ + {0xf0a8b7bb, 0xfb7b}, /* U+28DFB [2000] [Unicode3.1] */ + {0xf0a8b89f, 0xfb7c}, /* U+28E1F [2000] [Unicode3.1] */ + {0xf0a8b8b6, 0xfb81}, /* U+28E36 [2000] [Unicode3.1] */ + {0xf0a8ba89, 0xfb85}, /* U+28E89 [2000] [Unicode3.1] */ + {0xf0a8bbab, 0xfb87}, /* U+28EEB [2000] [Unicode3.1] */ + {0xf0a8bcb2, 0xfb89}, /* U+28F32 [2000] [Unicode3.1] */ + {0xf0a8bfb8, 0xfb91}, /* U+28FF8 [2000] [Unicode3.1] */ + {0xf0a98aa0, 0xfba0}, /* U+292A0 [2000] [Unicode3.1] */ + {0xf0a98ab1, 0xfba1}, /* U+292B1 [2000] [Unicode3.1] */ + {0xf0a99290, 0xfbb6}, /* U+29490 [2000] [Unicode3.1] */ + {0xf0a9978f, 0xfbc0}, /* U+295CF [2000] [Unicode3.1] */ + {0xf0a999bf, 0xfbca}, /* U+2967F [2000] [Unicode3.1] */ + {0xf0a99bb0, 0xfbd4}, /* U+296F0 [2000] [Unicode3.1] */ + {0xf0a99c99, 0xfbd7}, /* U+29719 [2000] [Unicode3.1] */ + {0xf0a99d90, 0xfbdb}, /* U+29750 [2000] [Unicode3.1] */ + {0xf0a9a386, 0xfbf4}, /* U+298C6 [2000] [Unicode3.1] */ + {0xf0a9a9b2, 0xfc4b}, /* U+29A72 [2000] [Unicode3.1] */ + {0xf0a9b79b, 0xfc6a}, /* U+29DDB [2000] [Unicode3.1] */ + {0xf0a9b895, 0xfc78}, /* U+29E15 [2000] [Unicode3.1] */ + {0xf0a9b8bd, 0xfc6b}, /* U+29E3D [2000] [Unicode3.1] */ + {0xf0a9b989, 0xfc7c}, /* U+29E49 [2000] [Unicode3.1] */ + {0xf0a9ba8a, 0xfc7a}, /* U+29E8A [2000] [Unicode3.1] */ + {0xf0a9bb84, 0xfc87}, /* U+29EC4 [2000] [Unicode3.1] */ + {0xf0a9bb9b, 0xfc90}, /* U+29EDB [2000] [Unicode3.1] */ + {0xf0a9bba9, 0xfc8d}, /* U+29EE9 [2000] [Unicode3.1] */ + {0xf0a9bf8e, 0xfca3}, /* U+29FCE [2000] [Unicode3.1] */ + {0xf0aa809a, 0xfca9}, /* U+2A01A [2000] [Unicode3.1] */ + {0xf0aa80af, 0xfca7}, /* U+2A02F [2000] [Unicode3.1] */ + {0xf0aa8282, 0xfcb3}, /* U+2A082 [2000] [Unicode3.1] */ + {0xf0aa83b9, 0xfcb0}, /* U+2A0F9 [2000] [Unicode3.1] */ + {0xf0aa8690, 0xefe4}, /* U+2A190 [2000] [Unicode3.1] */ + {0xf0aa8e8c, 0xfcd6}, /* U+2A38C [2000] [Unicode3.1] */ + {0xf0aa90b7, 0xfcd8}, /* U+2A437 [2000] [Unicode3.1] */ + {0xf0aa97b1, 0xfcec}, /* U+2A5F1 [2000] [Unicode3.1] */ + {0xf0aa9882, 0xfcee}, /* U+2A602 [2000] [Unicode3.1] */ + {0xf0aa989a, 0xfcf0}, /* U+2A61A [2000] [Unicode3.1] */ + {0xf0aa9ab2, 0xfcf4} /* U+2A6B2 [2000] [Unicode3.1] */ }; diff --git a/src/backend/utils/mb/Unicode/utf8_to_shift_jis_2004_combined.map b/src/backend/utils/mb/Unicode/utf8_to_shift_jis_2004_combined.map index e55d4a2a6c..3642851fd6 100644 --- a/src/backend/utils/mb/Unicode/utf8_to_shift_jis_2004_combined.map +++ b/src/backend/utils/mb/Unicode/utf8_to_shift_jis_2004_combined.map @@ -1,7 +1,6 @@ -/* - * This file was generated by UCS_to_SHIFT_JIS_2004.pl - */ -static const pg_utf_to_local_combined ULmapSHIFT_JIS_2004_combined[] = { +/* src/backend/utils/mb/Unicode/utf8_to_shift_jis_2004_combined.map */ + +static const pg_utf_to_local_combined ULmapSHIFT_JIS_2004_combined[ 25 ] = { /* */ {0x0000c3a6, 0x0000cc80, 0x8663}, /* U+00E6+0300 [2000] */ {0x0000c994, 0x0000cc80, 0x8667}, /* U+0254+0300 [2000] */ {0x0000c994, 0x0000cc81, 0x8668}, /* U+0254+0301 [2000] */ diff --git a/src/backend/utils/mb/Unicode/utf8_to_sjis.map b/src/backend/utils/mb/Unicode/utf8_to_sjis.map index bcb76c9150..cd6ea48ffc 100644 --- a/src/backend/utils/mb/Unicode/utf8_to_sjis.map +++ b/src/backend/utils/mb/Unicode/utf8_to_sjis.map @@ -1,8 +1,9 @@ -static const pg_utf_to_local ULmapSJIS[ 7398 ] = { - {0xc19c, 0x815f}, +/* src/backend/utils/mb/Unicode/utf8_to_sjis.map */ + +static const pg_utf_to_local ULmapSJIS[ 7397 ] = { {0xc2a2, 0x8191}, {0xc2a3, 0x8192}, - {0xc2a5, 0x5c}, + {0xc2a5, 0x005c}, {0xc2a7, 0x8198}, {0xc2a8, 0x814e}, {0xc2ac, 0x81ca}, @@ -141,7 +142,7 @@ static const pg_utf_to_local ULmapSJIS[ 7398 ] = { {0xe280b2, 0x818c}, {0xe280b3, 0x818d}, {0xe280bb, 0x81a6}, - {0xe280be, 0x7e}, + {0xe280be, 0x007e}, {0xe28483, 0x818e}, {0xe28496, 0xfa59}, {0xe284a1, 0xfa5a}, diff --git a/src/backend/utils/mb/Unicode/utf8_to_uhc.map b/src/backend/utils/mb/Unicode/utf8_to_uhc.map index 15dfb56a09..dc04726364 100644 --- a/src/backend/utils/mb/Unicode/utf8_to_uhc.map +++ b/src/backend/utils/mb/Unicode/utf8_to_uhc.map @@ -1,3 +1,5 @@ +/* src/backend/utils/mb/Unicode/utf8_to_uhc.map */ + static const pg_utf_to_local ULmapUHC[ 17237 ] = { {0xc2a1, 0xa2ae}, {0xc2a4, 0xa2b4}, diff --git a/src/backend/utils/mb/conv.c b/src/backend/utils/mb/conv.c index d50336bed5..9014a5727c 100644 --- a/src/backend/utils/mb/conv.c +++ b/src/backend/utils/mb/conv.c @@ -2,7 +2,7 @@ * * Utility functions for conversion procs. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/ascii_and_mic/ascii_and_mic.c b/src/backend/utils/mb/conversion_procs/ascii_and_mic/ascii_and_mic.c index dec2cdf6f7..4bbeea1e6f 100644 --- a/src/backend/utils/mb/conversion_procs/ascii_and_mic/ascii_and_mic.c +++ b/src/backend/utils/mb/conversion_procs/ascii_and_mic/ascii_and_mic.c @@ -2,7 +2,7 @@ * * ASCII and MULE_INTERNAL * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/cyrillic_and_mic/cyrillic_and_mic.c b/src/backend/utils/mb/conversion_procs/cyrillic_and_mic/cyrillic_and_mic.c index 5ea2a95bc1..677d7ea3eb 100644 --- a/src/backend/utils/mb/conversion_procs/cyrillic_and_mic/cyrillic_and_mic.c +++ b/src/backend/utils/mb/conversion_procs/cyrillic_and_mic/cyrillic_and_mic.c @@ -2,7 +2,7 @@ * * Cyrillic and MULE_INTERNAL * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/euc2004_sjis2004/euc2004_sjis2004.c b/src/backend/utils/mb/conversion_procs/euc2004_sjis2004/euc2004_sjis2004.c index 9e9145f972..c55bcc978c 100644 --- a/src/backend/utils/mb/conversion_procs/euc2004_sjis2004/euc2004_sjis2004.c +++ b/src/backend/utils/mb/conversion_procs/euc2004_sjis2004/euc2004_sjis2004.c @@ -2,7 +2,7 @@ * * EUC_JIS_2004, SHIFT_JIS_2004 * - * Copyright (c) 2007-2016, PostgreSQL Global Development Group + * Copyright (c) 2007-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/mb/conversion_procs/euc2004_sjis2004/euc2004_sjis2004.c diff --git a/src/backend/utils/mb/conversion_procs/euc_cn_and_mic/euc_cn_and_mic.c b/src/backend/utils/mb/conversion_procs/euc_cn_and_mic/euc_cn_and_mic.c index e804892d50..c897bb2e49 100644 --- a/src/backend/utils/mb/conversion_procs/euc_cn_and_mic/euc_cn_and_mic.c +++ b/src/backend/utils/mb/conversion_procs/euc_cn_and_mic/euc_cn_and_mic.c @@ -2,7 +2,7 @@ * * EUC_CN and MULE_INTERNAL * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/euc_jp_and_sjis/euc_jp_and_sjis.c b/src/backend/utils/mb/conversion_procs/euc_jp_and_sjis/euc_jp_and_sjis.c index 26a0e44a51..414aeff3b9 100644 --- a/src/backend/utils/mb/conversion_procs/euc_jp_and_sjis/euc_jp_and_sjis.c +++ b/src/backend/utils/mb/conversion_procs/euc_jp_and_sjis/euc_jp_and_sjis.c @@ -2,7 +2,7 @@ * * EUC_JP, SJIS and MULE_INTERNAL * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/euc_kr_and_mic/euc_kr_and_mic.c b/src/backend/utils/mb/conversion_procs/euc_kr_and_mic/euc_kr_and_mic.c index 84bad24d52..94f4f813ef 100644 --- a/src/backend/utils/mb/conversion_procs/euc_kr_and_mic/euc_kr_and_mic.c +++ b/src/backend/utils/mb/conversion_procs/euc_kr_and_mic/euc_kr_and_mic.c @@ -2,7 +2,7 @@ * * EUC_KR and MULE_INTERNAL * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/euc_tw_and_big5/euc_tw_and_big5.c b/src/backend/utils/mb/conversion_procs/euc_tw_and_big5/euc_tw_and_big5.c index 05f8f77318..cb7e296f26 100644 --- a/src/backend/utils/mb/conversion_procs/euc_tw_and_big5/euc_tw_and_big5.c +++ b/src/backend/utils/mb/conversion_procs/euc_tw_and_big5/euc_tw_and_big5.c @@ -2,7 +2,7 @@ * * EUC_TW, BIG5 and MULE_INTERNAL * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/latin2_and_win1250/latin2_and_win1250.c b/src/backend/utils/mb/conversion_procs/latin2_and_win1250/latin2_and_win1250.c index 292eeda259..62b103a8dd 100644 --- a/src/backend/utils/mb/conversion_procs/latin2_and_win1250/latin2_and_win1250.c +++ b/src/backend/utils/mb/conversion_procs/latin2_and_win1250/latin2_and_win1250.c @@ -2,7 +2,7 @@ * * LATIN2 and WIN1250 * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/latin_and_mic/latin_and_mic.c b/src/backend/utils/mb/conversion_procs/latin_and_mic/latin_and_mic.c index e88c098979..02fa94b8aa 100644 --- a/src/backend/utils/mb/conversion_procs/latin_and_mic/latin_and_mic.c +++ b/src/backend/utils/mb/conversion_procs/latin_and_mic/latin_and_mic.c @@ -2,7 +2,7 @@ * * LATINn and MULE_INTERNAL * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_ascii/utf8_and_ascii.c b/src/backend/utils/mb/conversion_procs/utf8_and_ascii/utf8_and_ascii.c index c0fc3b4984..724d3dd27e 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_ascii/utf8_and_ascii.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_ascii/utf8_and_ascii.c @@ -2,7 +2,7 @@ * * ASCII <--> UTF8 * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_big5/utf8_and_big5.c b/src/backend/utils/mb/conversion_procs/utf8_and_big5/utf8_and_big5.c index 3d71167756..746ed3580f 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_big5/utf8_and_big5.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_big5/utf8_and_big5.c @@ -2,7 +2,7 @@ * * BIG5 <--> UTF8 * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_cyrillic/utf8_and_cyrillic.c b/src/backend/utils/mb/conversion_procs/utf8_and_cyrillic/utf8_and_cyrillic.c index 6e2be740b5..d568c6331e 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_cyrillic/utf8_and_cyrillic.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_cyrillic/utf8_and_cyrillic.c @@ -2,7 +2,7 @@ * * UTF8 and Cyrillic * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_euc2004/utf8_and_euc2004.c b/src/backend/utils/mb/conversion_procs/utf8_and_euc2004/utf8_and_euc2004.c index 4d14b262ae..ebf5f23f99 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_euc2004/utf8_and_euc2004.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_euc2004/utf8_and_euc2004.c @@ -2,7 +2,7 @@ * * EUC_JIS_2004 <--> UTF8 * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_euc_cn/utf8_and_euc_cn.c b/src/backend/utils/mb/conversion_procs/utf8_and_euc_cn/utf8_and_euc_cn.c index 953123c8a7..cb0751c3db 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_euc_cn/utf8_and_euc_cn.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_euc_cn/utf8_and_euc_cn.c @@ -2,7 +2,7 @@ * * EUC_CN <--> UTF8 * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_euc_jp/utf8_and_euc_jp.c b/src/backend/utils/mb/conversion_procs/utf8_and_euc_jp/utf8_and_euc_jp.c index dd020d22e4..6512eeef60 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_euc_jp/utf8_and_euc_jp.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_euc_jp/utf8_and_euc_jp.c @@ -2,7 +2,7 @@ * * EUC_JP <--> UTF8 * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_euc_kr/utf8_and_euc_kr.c b/src/backend/utils/mb/conversion_procs/utf8_and_euc_kr/utf8_and_euc_kr.c index 7b5e04e8c8..f85720fa94 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_euc_kr/utf8_and_euc_kr.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_euc_kr/utf8_and_euc_kr.c @@ -2,7 +2,7 @@ * * EUC_KR <--> UTF8 * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_euc_tw/utf8_and_euc_tw.c b/src/backend/utils/mb/conversion_procs/utf8_and_euc_tw/utf8_and_euc_tw.c index 023a279c44..1ce4099cda 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_euc_tw/utf8_and_euc_tw.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_euc_tw/utf8_and_euc_tw.c @@ -2,7 +2,7 @@ * * EUC_TW <--> UTF8 * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_gb18030/utf8_and_gb18030.c b/src/backend/utils/mb/conversion_procs/utf8_and_gb18030/utf8_and_gb18030.c index 5e8ec3db7c..22dd642663 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_gb18030/utf8_and_gb18030.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_gb18030/utf8_and_gb18030.c @@ -2,7 +2,7 @@ * * GB18030 <--> UTF8 * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_gbk/utf8_and_gbk.c b/src/backend/utils/mb/conversion_procs/utf8_and_gbk/utf8_and_gbk.c index d6613a0e85..1238e3d12d 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_gbk/utf8_and_gbk.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_gbk/utf8_and_gbk.c @@ -2,7 +2,7 @@ * * GBK <--> UTF8 * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_iso8859/utf8_and_iso8859.c b/src/backend/utils/mb/conversion_procs/utf8_and_iso8859/utf8_and_iso8859.c index 9204b5fcbf..48acd3faba 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_iso8859/utf8_and_iso8859.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_iso8859/utf8_and_iso8859.c @@ -2,7 +2,7 @@ * * ISO 8859 2-16 <--> UTF8 * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_iso8859_1/utf8_and_iso8859_1.c b/src/backend/utils/mb/conversion_procs/utf8_and_iso8859_1/utf8_and_iso8859_1.c index 45364f5014..2cfc7bb83b 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_iso8859_1/utf8_and_iso8859_1.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_iso8859_1/utf8_and_iso8859_1.c @@ -2,7 +2,7 @@ * * ISO8859_1 <--> UTF8 * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_johab/utf8_and_johab.c b/src/backend/utils/mb/conversion_procs/utf8_and_johab/utf8_and_johab.c index 2eaeae6f72..51690b97ad 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_johab/utf8_and_johab.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_johab/utf8_and_johab.c @@ -2,7 +2,7 @@ * * JOHAB <--> UTF8 * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_sjis/utf8_and_sjis.c b/src/backend/utils/mb/conversion_procs/utf8_and_sjis/utf8_and_sjis.c index 204e2a0b35..605fe403b0 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_sjis/utf8_and_sjis.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_sjis/utf8_and_sjis.c @@ -2,7 +2,7 @@ * * SJIS <--> UTF8 * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_sjis2004/utf8_and_sjis2004.c b/src/backend/utils/mb/conversion_procs/utf8_and_sjis2004/utf8_and_sjis2004.c index b80eb7e46d..8d8f508aba 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_sjis2004/utf8_and_sjis2004.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_sjis2004/utf8_and_sjis2004.c @@ -2,7 +2,7 @@ * * SHIFT_JIS_2004 <--> UTF8 * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_uhc/utf8_and_uhc.c b/src/backend/utils/mb/conversion_procs/utf8_and_uhc/utf8_and_uhc.c index 71214d20d8..97e895c66a 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_uhc/utf8_and_uhc.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_uhc/utf8_and_uhc.c @@ -2,7 +2,7 @@ * * UHC <--> UTF8 * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_win/utf8_and_win.c b/src/backend/utils/mb/conversion_procs/utf8_and_win/utf8_and_win.c index 4d9c641ec6..ab6e624452 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_win/utf8_and_win.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_win/utf8_and_win.c @@ -2,7 +2,7 @@ * * WIN <--> UTF8 * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/mbutils.c b/src/backend/utils/mb/mbutils.c index 7f1c881cce..95644e3468 100644 --- a/src/backend/utils/mb/mbutils.c +++ b/src/backend/utils/mb/mbutils.c @@ -23,7 +23,7 @@ * the result is validly encoded according to the destination encoding. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/misc/Makefile b/src/backend/utils/misc/Makefile index a5b487d0b6..0ad1b8b595 100644 --- a/src/backend/utils/misc/Makefile +++ b/src/backend/utils/misc/Makefile @@ -14,8 +14,9 @@ include $(top_builddir)/src/Makefile.global override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS) -OBJS = guc.o help_config.o pg_config.o pg_controldata.o pg_rusage.o \ - ps_status.o rls.o sampling.o superuser.o timeout.o tzparser.o +OBJS = backend_random.o guc.o help_config.o pg_config.o pg_controldata.o \ + pg_rusage.o ps_status.o rls.o sampling.o superuser.o timeout.o \ + tzparser.o # This location might depend on the installation directories. Therefore # we can't subsitute it into pg_config.h. diff --git a/src/backend/utils/misc/backend_random.c b/src/backend/utils/misc/backend_random.c new file mode 100644 index 0000000000..dcc23638e1 --- /dev/null +++ b/src/backend/utils/misc/backend_random.c @@ -0,0 +1,158 @@ +/*------------------------------------------------------------------------- + * + * backend_random.c + * Backend random number generation routine. + * + * pg_backend_random() function fills a buffer with random bytes. Normally, + * it is just a thin wrapper around pg_strong_random(), but when compiled + * with --disable-strong-random, we provide a built-in implementation. + * + * This function is used for generating nonces in authentication, and for + * random salt generation in pgcrypto. The built-in implementation is not + * cryptographically strong, but if the user asked for it, we'll go ahead + * and use it anyway. + * + * The built-in implementation uses the standard erand48 algorithm, with + * a seed shared between all backends. + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/utils/misc/backend_random.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include + +#include "miscadmin.h" +#include "storage/lwlock.h" +#include "storage/shmem.h" +#include "utils/backend_random.h" +#include "utils/timestamp.h" + +#ifdef HAVE_STRONG_RANDOM + +Size +BackendRandomShmemSize(void) +{ + return 0; +} + +void +BackendRandomShmemInit(void) +{ + /* do nothing */ +} + +bool +pg_backend_random(char *dst, int len) +{ + /* should not be called in postmaster */ + Assert (IsUnderPostmaster || !IsPostmasterEnvironment); + + return pg_strong_random(dst, len); +} + +#else + +/* + * Seed for the PRNG, stored in shared memory. + * + * Protected by BackendRandomLock. + */ +typedef struct +{ + bool initialized; + unsigned short seed[3]; +} BackendRandomShmemStruct; + +static BackendRandomShmemStruct *BackendRandomShmem; + +Size +BackendRandomShmemSize(void) +{ + return sizeof(BackendRandomShmemStruct); +} + +void +BackendRandomShmemInit(void) +{ + bool found; + + BackendRandomShmem = (BackendRandomShmemStruct *) + ShmemInitStruct("Backend PRNG state", + BackendRandomShmemSize(), + &found); + + if (!IsUnderPostmaster) + { + Assert(!found); + + BackendRandomShmem->initialized = false; + } + else + Assert(found); +} + +bool +pg_backend_random(char *dst, int len) +{ + int i; + char *end = dst + len; + + /* should not be called in postmaster */ + Assert (IsUnderPostmaster || !IsPostmasterEnvironment); + + LWLockAcquire(BackendRandomLock, LW_EXCLUSIVE); + + /* + * Seed the PRNG on the first use. + */ + if (!BackendRandomShmem->initialized) + { + struct timeval now; + + gettimeofday(&now, NULL); + + BackendRandomShmem->seed[0] = now.tv_sec; + BackendRandomShmem->seed[1] = (unsigned short) (now.tv_usec); + BackendRandomShmem->seed[2] = (unsigned short) (now.tv_usec >> 16); + + /* + * Mix in the cancel key, generated by the postmaster. This adds + * what little entropy the postmaster had to the seed. + */ + BackendRandomShmem->seed[0] ^= (MyCancelKey); + BackendRandomShmem->seed[1] ^= (MyCancelKey >> 16); + + BackendRandomShmem->initialized = true; + } + + for (i = 0; dst < end; i++) + { + uint32 r; + int j; + + /* + * pg_jrand48 returns a 32-bit integer. Fill the next 4 bytes from it. + */ + r = (uint32) pg_jrand48(BackendRandomShmem->seed); + + for (j = 0; j < 4 && dst < end; j++) + { + *(dst++) = (char) (r & 0xFF); + r >>= 8; + } + } + LWLockRelease(BackendRandomLock); + + return true; +} + + +#endif /* HAVE_STRONG_RANDOM */ diff --git a/src/backend/utils/misc/guc-file.l b/src/backend/utils/misc/guc-file.l index 48052f9320..f01b814c6e 100644 --- a/src/backend/utils/misc/guc-file.l +++ b/src/backend/utils/misc/guc-file.l @@ -2,7 +2,7 @@ /* * Scanner for the configuration file * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/backend/utils/misc/guc-file.l */ @@ -145,9 +145,7 @@ ProcessConfigFile(GucContext context) */ config_cxt = AllocSetContextCreate(CurrentMemoryContext, "config file processing", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); caller_cxt = MemoryContextSwitchTo(config_cxt); /* diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 9c93df0f0a..5f43b1ec92 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -6,7 +6,7 @@ * See src/backend/utils/misc/README for more information. * * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * Written by Peter Eisentraut . * * IDENTIFICATION @@ -34,6 +34,7 @@ #include "catalog/namespace.h" #include "commands/async.h" #include "commands/prepare.h" +#include "commands/user.h" #include "commands/vacuum.h" #include "commands/variable.h" #include "commands/trigger.h" @@ -58,6 +59,7 @@ #include "postmaster/postmaster.h" #include "postmaster/syslogger.h" #include "postmaster/walwriter.h" +#include "replication/logicallauncher.h" #include "replication/slot.h" #include "replication/syncrep.h" #include "replication/walreceiver.h" @@ -82,6 +84,7 @@ #include "utils/rls.h" #include "utils/snapmgr.h" #include "utils/tzparser.h" +#include "utils/varlena.h" #include "utils/xml.h" #ifndef PG_KRB_SRVTAB @@ -393,6 +396,24 @@ static const struct config_enum_entry force_parallel_mode_options[] = { {NULL, 0, false} }; +/* + * password_encryption used to be a boolean, so accept all the likely + * variants of "on" and "off", too. + */ +static const struct config_enum_entry password_encryption_options[] = { + {"plain", PASSWORD_TYPE_PLAINTEXT, false}, + {"md5", PASSWORD_TYPE_MD5, false}, + {"off", PASSWORD_TYPE_PLAINTEXT, false}, + {"on", PASSWORD_TYPE_MD5, false}, + {"true", PASSWORD_TYPE_MD5, true}, + {"false", PASSWORD_TYPE_PLAINTEXT, true}, + {"yes", PASSWORD_TYPE_MD5, true}, + {"no", PASSWORD_TYPE_PLAINTEXT, true}, + {"1", PASSWORD_TYPE_MD5, true}, + {"0", PASSWORD_TYPE_PLAINTEXT, true}, + {NULL, 0, false} +}; + /* * Options for enum values stored in other modules */ @@ -421,9 +442,6 @@ char *event_source; bool row_security; bool check_function_bodies = true; bool default_with_oids = false; -bool SQL_inheritance = true; - -bool Password_encryption = true; int log_min_error_statement = ERROR; int log_min_messages = WARNING; @@ -690,7 +708,7 @@ typedef struct #if XLOG_BLCKSZ < 1024 || XLOG_BLCKSZ > (1024*1024) #error XLOG_BLCKSZ must be between 1KB and 1MB #endif -#if XLOG_SEG_SIZE < (1024*1024) || XLOG_BLCKSZ > (1024*1024*1024) +#if XLOG_SEG_SIZE < (1024*1024) || XLOG_SEG_SIZE > (1024*1024*1024) #error XLOG_SEG_SIZE must be between 1MB and 1GB #endif @@ -918,7 +936,7 @@ static struct config_bool ConfigureNamesBool[] = NULL, NULL, NULL }, { - {"ssl", PGC_POSTMASTER, CONN_AUTH_SECURITY, + {"ssl", PGC_SIGHUP, CONN_AUTH_SECURITY, gettext_noop("Enables SSL connections."), NULL }, @@ -927,7 +945,7 @@ static struct config_bool ConfigureNamesBool[] = check_ssl, NULL, NULL }, { - {"ssl_prefer_server_ciphers", PGC_POSTMASTER, CONN_AUTH_SECURITY, + {"ssl_prefer_server_ciphers", PGC_SIGHUP, CONN_AUTH_SECURITY, gettext_noop("Give priority to server ciphersuite order."), NULL }, @@ -1210,7 +1228,11 @@ static struct config_bool ConfigureNamesBool[] = gettext_noop("Enables updating of the process title every time a new SQL command is received by the server.") }, &update_process_title, +#ifdef WIN32 + false, +#else true, +#endif NULL, NULL, NULL }, @@ -1300,26 +1322,6 @@ static struct config_bool ConfigureNamesBool[] = false, NULL, NULL, NULL }, - { - {"sql_inheritance", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, - gettext_noop("Causes subtables to be included by default in various commands."), - NULL - }, - &SQL_inheritance, - true, - NULL, NULL, NULL - }, - { - {"password_encryption", PGC_USERSET, CONN_AUTH_SECURITY, - gettext_noop("Encrypt passwords."), - gettext_noop("When a password is specified in CREATE USER or " - "ALTER USER without writing either ENCRYPTED or UNENCRYPTED, " - "this parameter determines whether the password is to be encrypted.") - }, - &Password_encryption, - true, - NULL, NULL, NULL - }, { {"transform_null_equals", PGC_USERSET, COMPAT_OPTIONS_CLIENT, gettext_noop("Treats \"expr=NULL\" as \"expr IS NULL\"."), @@ -2246,7 +2248,7 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_S }, &CheckPointTimeout, - 300, 30, 3600, + 300, 30, 86400, NULL, NULL, NULL }, @@ -2271,7 +2273,6 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_BLOCKS }, &checkpoint_flush_after, - /* see bufmgr.h: OS dependent default */ DEFAULT_CHECKPOINT_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES, NULL, NULL, NULL }, @@ -2300,12 +2301,12 @@ static struct config_int ConfigureNamesInt[] = { {"wal_writer_flush_after", PGC_SIGHUP, WAL_SETTINGS, - gettext_noop("Amount of WAL written out by WAL writer triggering a flush."), + gettext_noop("Amount of WAL written out by WAL writer that triggers a flush."), NULL, GUC_UNIT_XBLOCKS }, &WalWriterFlushAfter, - 128, 0, INT_MAX, + (1024 * 1024) / XLOG_BLCKSZ, 0, INT_MAX, NULL, NULL, NULL }, @@ -2316,7 +2317,7 @@ static struct config_int ConfigureNamesInt[] = NULL }, &max_wal_senders, - 0, 0, MAX_BACKENDS, + 10, 0, MAX_BACKENDS, NULL, NULL, NULL }, @@ -2327,7 +2328,7 @@ static struct config_int ConfigureNamesInt[] = NULL }, &max_replication_slots, - 0, 0, MAX_BACKENDS /* XXX? */ , + 10, 0, MAX_BACKENDS /* XXX? */ , NULL, NULL, NULL }, @@ -2429,7 +2430,6 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_BLOCKS }, &bgwriter_flush_after, - /* see bufmgr.h: OS dependent default */ DEFAULT_BGWRITER_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES, NULL, NULL, NULL }, @@ -2457,7 +2457,7 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_BLOCKS }, &backend_flush_after, - 0, 0, WRITEBACK_MAX_PENDING_FLUSHES, + DEFAULT_BACKEND_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES, NULL, NULL, NULL }, @@ -2473,6 +2473,18 @@ static struct config_int ConfigureNamesInt[] = check_max_worker_processes, NULL, NULL }, + { + {"max_logical_replication_workers", + PGC_POSTMASTER, + RESOURCES_ASYNCHRONOUS, + gettext_noop("Maximum number of logical replication worker processes."), + NULL, + }, + &max_logical_replication_workers, + 4, 0, MAX_BACKENDS, + NULL, NULL, NULL + }, + { {"log_rotation_age", PGC_SIGHUP, LOGGING_WHERE, gettext_noop("Automatic log file rotation will occur after N minutes."), @@ -2656,6 +2668,16 @@ static struct config_int ConfigureNamesInt[] = NULL, NULL, NULL }, + { + {"max_parallel_workers", PGC_USERSET, RESOURCES_ASYNCHRONOUS, + gettext_noop("Sets the maximum number of parallel workers than can be active at one time."), + NULL + }, + &max_parallel_workers, + 8, 0, 1024, + NULL, NULL, NULL + }, + { {"autovacuum_work_mem", PGC_SIGHUP, RESOURCES_MEM, gettext_noop("Sets the maximum memory to be used by each autovacuum worker process."), @@ -2754,7 +2776,7 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_BLOCKS, }, &min_parallel_relation_size, - 1024, 0, INT_MAX / 3, + (8 * 1024 * 1024) / BLCKSZ, 0, INT_MAX / 3, NULL, NULL, NULL }, @@ -3004,7 +3026,7 @@ static struct config_string ConfigureNamesString[] = gettext_noop("If blank, no prefix is used.") }, &Log_line_prefix, - "", + "%m [%p] ", NULL, NULL, NULL }, @@ -3427,7 +3449,7 @@ static struct config_string ConfigureNamesString[] = }, { - {"ssl_cert_file", PGC_POSTMASTER, CONN_AUTH_SECURITY, + {"ssl_cert_file", PGC_SIGHUP, CONN_AUTH_SECURITY, gettext_noop("Location of the SSL server certificate file."), NULL }, @@ -3437,7 +3459,7 @@ static struct config_string ConfigureNamesString[] = }, { - {"ssl_key_file", PGC_POSTMASTER, CONN_AUTH_SECURITY, + {"ssl_key_file", PGC_SIGHUP, CONN_AUTH_SECURITY, gettext_noop("Location of the SSL server private key file."), NULL }, @@ -3447,7 +3469,7 @@ static struct config_string ConfigureNamesString[] = }, { - {"ssl_ca_file", PGC_POSTMASTER, CONN_AUTH_SECURITY, + {"ssl_ca_file", PGC_SIGHUP, CONN_AUTH_SECURITY, gettext_noop("Location of the SSL certificate authority file."), NULL }, @@ -3457,7 +3479,7 @@ static struct config_string ConfigureNamesString[] = }, { - {"ssl_crl_file", PGC_POSTMASTER, CONN_AUTH_SECURITY, + {"ssl_crl_file", PGC_SIGHUP, CONN_AUTH_SECURITY, gettext_noop("Location of the SSL certificate revocation list file."), NULL }, @@ -3499,7 +3521,7 @@ static struct config_string ConfigureNamesString[] = }, { - {"ssl_ciphers", PGC_POSTMASTER, CONN_AUTH_SECURITY, + {"ssl_ciphers", PGC_SIGHUP, CONN_AUTH_SECURITY, gettext_noop("Sets the list of allowed SSL ciphers."), NULL, GUC_SUPERUSER_ONLY @@ -3514,7 +3536,7 @@ static struct config_string ConfigureNamesString[] = }, { - {"ssl_ecdh_curve", PGC_POSTMASTER, CONN_AUTH_SECURITY, + {"ssl_ecdh_curve", PGC_SIGHUP, CONN_AUTH_SECURITY, gettext_noop("Sets the curve to use for ECDH."), NULL, GUC_SUPERUSER_ONLY @@ -3741,7 +3763,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_level, - WAL_LEVEL_MINIMAL, wal_level_options, + WAL_LEVEL_REPLICA, wal_level_options, NULL, NULL, NULL }, @@ -3806,6 +3828,18 @@ static struct config_enum ConfigureNamesEnum[] = NULL, NULL, NULL }, + { + {"password_encryption", PGC_USERSET, CONN_AUTH_SECURITY, + gettext_noop("Encrypt passwords."), + gettext_noop("When a password is specified in CREATE USER or " + "ALTER USER without writing either ENCRYPTED or UNENCRYPTED, " + "this parameter determines whether the password is to be encrypted.") + }, + &Password_encryption, + PASSWORD_TYPE_MD5, password_encryption_options, + NULL, NULL, NULL + }, + /* End-of-list marker */ { {NULL, 0, 0, NULL, NULL}, NULL, 0, NULL, NULL, NULL, NULL @@ -7994,20 +8028,23 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow) /* unit */ if (conf->vartype == PGC_INT) { - static char buf[8]; - switch (conf->flags & (GUC_UNIT_MEMORY | GUC_UNIT_TIME)) { case GUC_UNIT_KB: values[2] = "kB"; break; case GUC_UNIT_BLOCKS: - snprintf(buf, sizeof(buf), "%dkB", BLCKSZ / 1024); - values[2] = buf; + snprintf(buffer, sizeof(buffer), "%dkB", BLCKSZ / 1024); + values[2] = pstrdup(buffer); break; case GUC_UNIT_XBLOCKS: - snprintf(buf, sizeof(buf), "%dkB", XLOG_BLCKSZ / 1024); - values[2] = buf; + snprintf(buffer, sizeof(buffer), "%dkB", XLOG_BLCKSZ / 1024); + values[2] = pstrdup(buffer); + break; + case GUC_UNIT_XSEGS: + snprintf(buffer, sizeof(buffer), "%dMB", + XLOG_SEG_SIZE / (1024 * 1024)); + values[2] = pstrdup(buffer); break; case GUC_UNIT_MS: values[2] = "ms"; @@ -8018,7 +8055,12 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow) case GUC_UNIT_MIN: values[2] = "min"; break; + case 0: + values[2] = NULL; + break; default: + elog(ERROR, "unrecognized GUC units value: %d", + conf->flags & (GUC_UNIT_MEMORY | GUC_UNIT_TIME)); values[2] = NULL; break; } @@ -8873,7 +8915,9 @@ can_skip_gucvar(struct config_generic * gconf) /* * estimate_variable_size: - * Estimate max size for dumping the given GUC variable. + * Compute space needed for dumping the given GUC variable. + * + * It's OK to overestimate, but not to underestimate. */ static Size estimate_variable_size(struct config_generic * gconf) @@ -8884,9 +8928,8 @@ estimate_variable_size(struct config_generic * gconf) if (can_skip_gucvar(gconf)) return 0; - size = 0; - - size = add_size(size, strlen(gconf->name) + 1); + /* Name, plus trailing zero byte. */ + size = strlen(gconf->name) + 1; /* Get the maximum display length of the GUC value. */ switch (gconf->vartype) @@ -8907,7 +8950,7 @@ estimate_variable_size(struct config_generic * gconf) * small values. Maximum value is 2147483647, i.e. 10 chars. * Include one byte for sign. */ - if (abs(*conf->variable) < 1000) + if (Abs(*conf->variable) < 1000) valsize = 3 + 1; else valsize = 10 + 1; @@ -8917,11 +8960,12 @@ estimate_variable_size(struct config_generic * gconf) case PGC_REAL: { /* - * We are going to print it with %.17g. Account for sign, - * decimal point, and e+nnn notation. E.g. - * -3.9932904234000002e+110 + * We are going to print it with %e with REALTYPE_PRECISION + * fractional digits. Account for sign, leading digit, + * decimal point, and exponent with up to 3 digits. E.g. + * -3.99329042340000021e+110 */ - valsize = REALTYPE_PRECISION + 1 + 1 + 5; + valsize = 1 + 1 + 1 + REALTYPE_PRECISION + 5; } break; @@ -8929,7 +8973,15 @@ estimate_variable_size(struct config_generic * gconf) { struct config_string *conf = (struct config_string *) gconf; - valsize = strlen(*conf->variable); + /* + * If the value is NULL, we transmit it as an empty string. + * Although this is not physically the same value, GUC + * generally treats a NULL the same as empty string. + */ + if (*conf->variable) + valsize = strlen(*conf->variable); + else + valsize = 0; } break; @@ -8942,17 +8994,17 @@ estimate_variable_size(struct config_generic * gconf) break; } - /* Allow space for terminating zero-byte */ + /* Allow space for terminating zero-byte for value */ size = add_size(size, valsize + 1); if (gconf->sourcefile) size = add_size(size, strlen(gconf->sourcefile)); - /* Allow space for terminating zero-byte */ + /* Allow space for terminating zero-byte for sourcefile */ size = add_size(size, 1); - /* Include line whenever we include file. */ - if (gconf->sourcefile) + /* Include line whenever file is nonempty. */ + if (gconf->sourcefile && gconf->sourcefile[0]) size = add_size(size, sizeof(gconf->sourceline)); size = add_size(size, sizeof(gconf->source)); @@ -9070,7 +9122,7 @@ serialize_variable(char **destptr, Size *maxbytes, { struct config_real *conf = (struct config_real *) gconf; - do_serialize(destptr, maxbytes, "%.*g", + do_serialize(destptr, maxbytes, "%.*e", REALTYPE_PRECISION, *conf->variable); } break; @@ -9079,7 +9131,9 @@ serialize_variable(char **destptr, Size *maxbytes, { struct config_string *conf = (struct config_string *) gconf; - do_serialize(destptr, maxbytes, "%s", *conf->variable); + /* NULL becomes empty string, see estimate_variable_size() */ + do_serialize(destptr, maxbytes, "%s", + *conf->variable ? *conf->variable : ""); } break; @@ -9096,7 +9150,7 @@ serialize_variable(char **destptr, Size *maxbytes, do_serialize(destptr, maxbytes, "%s", (gconf->sourcefile ? gconf->sourcefile : "")); - if (gconf->sourcefile) + if (gconf->sourcefile && gconf->sourcefile[0]) do_serialize_binary(destptr, maxbytes, &gconf->sourceline, sizeof(gconf->sourceline)); @@ -9163,7 +9217,7 @@ read_gucstate(char **srcptr, char *srcend) for (ptr = *srcptr; ptr < srcend && *ptr != '\0'; ptr++) ; - if (ptr > srcend) + if (ptr >= srcend) elog(ERROR, "could not find null terminator in GUC state"); /* Set the new position to the byte following the terminating NUL */ @@ -9217,9 +9271,7 @@ RestoreGUCState(void *gucstate) { int result; - if ((varname = read_gucstate(&srcptr, srcend)) == NULL) - break; - + varname = read_gucstate(&srcptr, srcend); varvalue = read_gucstate(&srcptr, srcend); varsourcefile = read_gucstate(&srcptr, srcend); if (varsourcefile[0]) diff --git a/src/backend/utils/misc/help_config.c b/src/backend/utils/misc/help_config.c index 7e24489c38..7bc8f92f6d 100644 --- a/src/backend/utils/misc/help_config.c +++ b/src/backend/utils/misc/help_config.c @@ -7,7 +7,7 @@ * or GUC_DISALLOW_IN_FILE are not displayed, unless the user specifically * requests that variable by name * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/misc/help_config.c diff --git a/src/backend/utils/misc/pg_config.c b/src/backend/utils/misc/pg_config.c index 1fbdd1f4db..468c7cc9e1 100644 --- a/src/backend/utils/misc/pg_config.c +++ b/src/backend/utils/misc/pg_config.c @@ -3,7 +3,7 @@ * pg_config.c * Expose same output as pg_config except as an SRF * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c index 34ee76a237..93a3d38b1d 100644 --- a/src/backend/utils/misc/pg_controldata.c +++ b/src/backend/utils/misc/pg_controldata.c @@ -5,7 +5,7 @@ * Routines to expose the contents of the control data file via * a set of SQL functions. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -34,6 +34,7 @@ pg_control_system(PG_FUNCTION_ARGS) TupleDesc tupdesc; HeapTuple htup; ControlFileData *ControlFile; + bool crc_ok; /* * Construct a tuple descriptor for the result row. This must match this @@ -51,7 +52,10 @@ pg_control_system(PG_FUNCTION_ARGS) tupdesc = BlessTupleDesc(tupdesc); /* read the control file */ - ControlFile = get_controlfile(DataDir, NULL); + ControlFile = get_controlfile(DataDir, NULL, &crc_ok); + if (!crc_ok) + ereport(ERROR, + (errmsg("calculated CRC checksum does not match value stored in file"))); values[0] = Int32GetDatum(ControlFile->pg_control_version); nulls[0] = false; @@ -80,6 +84,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS) ControlFileData *ControlFile; XLogSegNo segno; char xlogfilename[MAXFNAMELEN]; + bool crc_ok; /* * Construct a tuple descriptor for the result row. This must match this @@ -127,7 +132,10 @@ pg_control_checkpoint(PG_FUNCTION_ARGS) tupdesc = BlessTupleDesc(tupdesc); /* Read the control file. */ - ControlFile = get_controlfile(DataDir, NULL); + ControlFile = get_controlfile(DataDir, NULL, &crc_ok); + if (!crc_ok) + ereport(ERROR, + (errmsg("calculated CRC checksum does not match value stored in file"))); /* * Calculate name of the WAL file containing the latest checkpoint's REDO @@ -210,6 +218,7 @@ pg_control_recovery(PG_FUNCTION_ARGS) TupleDesc tupdesc; HeapTuple htup; ControlFileData *ControlFile; + bool crc_ok; /* * Construct a tuple descriptor for the result row. This must match this @@ -229,7 +238,10 @@ pg_control_recovery(PG_FUNCTION_ARGS) tupdesc = BlessTupleDesc(tupdesc); /* read the control file */ - ControlFile = get_controlfile(DataDir, NULL); + ControlFile = get_controlfile(DataDir, NULL, &crc_ok); + if (!crc_ok) + ereport(ERROR, + (errmsg("calculated CRC checksum does not match value stored in file"))); values[0] = LSNGetDatum(ControlFile->minRecoveryPoint); nulls[0] = false; @@ -259,6 +271,7 @@ pg_control_init(PG_FUNCTION_ARGS) TupleDesc tupdesc; HeapTuple htup; ControlFileData *ControlFile; + bool crc_ok; /* * Construct a tuple descriptor for the result row. This must match this @@ -294,7 +307,10 @@ pg_control_init(PG_FUNCTION_ARGS) tupdesc = BlessTupleDesc(tupdesc); /* read the control file */ - ControlFile = get_controlfile(DataDir, NULL); + ControlFile = get_controlfile(DataDir, NULL, &crc_ok); + if (!crc_ok) + ereport(ERROR, + (errmsg("calculated CRC checksum does not match value stored in file"))); values[0] = Int32GetDatum(ControlFile->maxAlign); nulls[0] = false; diff --git a/src/backend/utils/misc/pg_rusage.c b/src/backend/utils/misc/pg_rusage.c index 8781a383c0..e4dccc383a 100644 --- a/src/backend/utils/misc/pg_rusage.c +++ b/src/backend/utils/misc/pg_rusage.c @@ -4,7 +4,7 @@ * Resource usage measurement support routines. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -61,11 +61,11 @@ pg_rusage_show(const PGRUsage *ru0) } snprintf(result, sizeof(result), - "CPU %d.%02ds/%d.%02du sec elapsed %d.%02d sec", - (int) (ru1.ru.ru_stime.tv_sec - ru0->ru.ru_stime.tv_sec), - (int) (ru1.ru.ru_stime.tv_usec - ru0->ru.ru_stime.tv_usec) / 10000, + "CPU: user: %d.%02d s, system: %d.%02d s, elapsed: %d.%02d s", (int) (ru1.ru.ru_utime.tv_sec - ru0->ru.ru_utime.tv_sec), (int) (ru1.ru.ru_utime.tv_usec - ru0->ru.ru_utime.tv_usec) / 10000, + (int) (ru1.ru.ru_stime.tv_sec - ru0->ru.ru_stime.tv_sec), + (int) (ru1.ru.ru_stime.tv_usec - ru0->ru.ru_stime.tv_usec) / 10000, (int) (ru1.tv.tv_sec - ru0->tv.tv_sec), (int) (ru1.tv.tv_usec - ru0->tv.tv_usec) / 10000); diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 6d0666c44f..661b0fa9b6 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -16,9 +16,9 @@ # # This file is read on server startup and when the server receives a SIGHUP # signal. If you edit the file on a running system, you have to SIGHUP the -# server for the changes to take effect, or use "pg_ctl reload". Some -# parameters, which are marked below, require a server shutdown and restart to -# take effect. +# server for the changes to take effect, run "pg_ctl reload", or execute +# "SELECT pg_reload_conf()". Some parameters, which are marked below, +# require a server shutdown and restart to take effect. # # Any parameter can also be given as a command-line option to the server, e.g., # "postgres -c log_connections=on". Some parameters can be changed at run time @@ -76,16 +76,15 @@ # - Security and Authentication - #authentication_timeout = 1min # 1s-600s -#ssl = off # (change requires restart) +#ssl = off #ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers - # (change requires restart) -#ssl_prefer_server_ciphers = on # (change requires restart) -#ssl_ecdh_curve = 'prime256v1' # (change requires restart) -#ssl_cert_file = 'server.crt' # (change requires restart) -#ssl_key_file = 'server.key' # (change requires restart) -#ssl_ca_file = '' # (change requires restart) -#ssl_crl_file = '' # (change requires restart) -#password_encryption = on +#ssl_prefer_server_ciphers = on +#ssl_ecdh_curve = 'prime256v1' +#ssl_cert_file = 'server.crt' +#ssl_key_file = 'server.key' +#ssl_ca_file = '' +#ssl_crl_file = '' +#password_encryption = md5 # md5 or plain #db_user_namespace = off #row_security = on @@ -156,17 +155,18 @@ #bgwriter_delay = 200ms # 10-10000ms between rounds #bgwriter_lru_maxpages = 100 # 0-1000 max buffers written/round #bgwriter_lru_multiplier = 2.0 # 0-10.0 multiplier on buffers scanned/round -#bgwriter_flush_after = 0 # 0 disables, - # default is 512kB on linux, 0 otherwise +#bgwriter_flush_after = 0 # measured in pages, 0 disables # - Asynchronous Behavior - #effective_io_concurrency = 1 # 1-1000; 0 disables prefetching #max_worker_processes = 8 # (change requires restart) #max_parallel_workers_per_gather = 2 # taken from max_worker_processes +#max_parallel_workers = 8 # total maximum number of worker_processes +#max_logical_replication_workers = 4 # taken from max_worker_processes #old_snapshot_threshold = -1 # 1min-60d; -1 disables; 0 is immediate - # (change requires restart) -#backend_flush_after = 0 # 0 disables, default is 0 + # (change requires restart) +#backend_flush_after = 0 # measured in pages, 0 disables #------------------------------------------------------------------------------ @@ -175,11 +175,11 @@ # - Settings - -#wal_level = minimal # minimal, replica, or logical +#wal_level = replica # minimal, replica, or logical # (change requires restart) #fsync = on # flush data to disk for crash safety - # (turning this off can cause - # unrecoverable data corruption) + # (turning this off can cause + # unrecoverable data corruption) #synchronous_commit = on # synchronization level; # off, local, remote_write, remote_apply, or on #wal_sync_method = fsync # the default is the first option @@ -196,19 +196,18 @@ #wal_buffers = -1 # min 32kB, -1 sets based on shared_buffers # (change requires restart) #wal_writer_delay = 200ms # 1-10000 milliseconds -#wal_writer_flush_after = 1MB # 0 disables +#wal_writer_flush_after = 1MB # measured in pages, 0 disables #commit_delay = 0 # range 0-100000, in microseconds #commit_siblings = 5 # range 1-1000 # - Checkpoints - -#checkpoint_timeout = 5min # range 30s-1h +#checkpoint_timeout = 5min # range 30s-1d #max_wal_size = 1GB #min_wal_size = 80MB #checkpoint_completion_target = 0.5 # checkpoint target duration, 0.0 - 1.0 -#checkpoint_flush_after = 0 # 0 disables, - # default is 256kB on linux, 0 otherwise +#checkpoint_flush_after = 0 # measured in pages, 0 disables #checkpoint_warning = 30s # 0 disables # - Archiving - @@ -231,12 +230,12 @@ # Set these on the master and on any standby that will send replication data. -#max_wal_senders = 0 # max number of walsender processes +#max_wal_senders = 10 # max number of walsender processes # (change requires restart) #wal_keep_segments = 0 # in logfile segments, 16MB each; 0 disables #wal_sender_timeout = 60s # in milliseconds; 0 disables -#max_replication_slots = 0 # max number of replication slots +#max_replication_slots = 10 # max number of replication slots # (change requires restart) #track_commit_timestamp = off # collect timestamp of transaction commit # (change requires restart) @@ -246,7 +245,8 @@ # These settings are ignored on a standby server. #synchronous_standby_names = '' # standby servers that provide sync rep - # number of sync standbys and comma-separated list of application_name + # method to choose sync standbys, number of sync standbys + # and comma-separated list of application_name # from standby(s); '*' = all #vacuum_defer_cleanup_age = 0 # number of xacts by which cleanup is delayed @@ -430,7 +430,7 @@ #log_duration = off #log_error_verbosity = default # terse, default, or verbose messages #log_hostname = off -#log_line_prefix = '' # special values: +#log_line_prefix = '%m [%p] ' # special values: # %a = application name # %u = user name # %d = database name @@ -538,7 +538,7 @@ #session_replication_role = 'origin' #statement_timeout = 0 # in milliseconds, 0 is disabled #lock_timeout = 0 # in milliseconds, 0 is disabled -#idle_in_transaction_session_timeout = 0 # in milliseconds, 0 is disabled +#idle_in_transaction_session_timeout = 0 # in milliseconds, 0 is disabled #vacuum_freeze_min_age = 50000000 #vacuum_freeze_table_age = 150000000 #vacuum_multixact_freeze_min_age = 5000000 @@ -606,7 +606,6 @@ #lo_compat_privileges = off #operator_precedence_warning = off #quote_all_identifiers = off -#sql_inheritance = on #standard_conforming_strings = on #synchronize_seqscans = on diff --git a/src/backend/utils/misc/ps_status.c b/src/backend/utils/misc/ps_status.c index 892a810bab..4007a17800 100644 --- a/src/backend/utils/misc/ps_status.c +++ b/src/backend/utils/misc/ps_status.c @@ -7,7 +7,7 @@ * * src/backend/utils/misc/ps_status.c * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * various details abducted from various places *-------------------------------------------------------------------- */ @@ -113,6 +113,9 @@ static char **save_argv; * overwritten during init_ps_display. Also, the physical location of the * environment strings may be moved, so this should be called before any code * that might try to hang onto a getenv() result.) + * + * Note that in case of failure this cannot call elog() as that is not + * initialized yet. We rely on write_stderr() instead. */ char ** save_ps_display_args(int argc, char **argv) @@ -163,8 +166,20 @@ save_ps_display_args(int argc, char **argv) * move the environment out of the way */ new_environ = (char **) malloc((i + 1) * sizeof(char *)); + if (!new_environ) + { + write_stderr("out of memory\n"); + exit(1); + } for (i = 0; environ[i] != NULL; i++) + { new_environ[i] = strdup(environ[i]); + if (!new_environ[i]) + { + write_stderr("out of memory\n"); + exit(1); + } + } new_environ[i] = NULL; environ = new_environ; } @@ -189,15 +204,27 @@ save_ps_display_args(int argc, char **argv) int i; new_argv = (char **) malloc((argc + 1) * sizeof(char *)); + if (!new_argv) + { + write_stderr("out of memory\n"); + exit(1); + } for (i = 0; i < argc; i++) + { new_argv[i] = strdup(argv[i]); + if (!new_argv[i]) + { + write_stderr("out of memory\n"); + exit(1); + } + } new_argv[argc] = NULL; #if defined(__darwin__) /* - * Darwin (and perhaps other NeXT-derived platforms?) has a static - * copy of the argv pointer, which we may fix like so: + * macOS (and perhaps other NeXT-derived platforms?) has a static copy + * of the argv pointer, which we may fix like so: */ *_NSGetArgv() = new_argv; #endif diff --git a/src/backend/utils/misc/rls.c b/src/backend/utils/misc/rls.c index c33f29e9f2..faf1599404 100644 --- a/src/backend/utils/misc/rls.c +++ b/src/backend/utils/misc/rls.c @@ -3,7 +3,7 @@ * rls.c * RLS-related utility functions. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -26,6 +26,7 @@ #include "utils/lsyscache.h" #include "utils/rls.h" #include "utils/syscache.h" +#include "utils/varlena.h" /* diff --git a/src/backend/utils/misc/sampling.c b/src/backend/utils/misc/sampling.c index d0d00ab3ed..c36459ebad 100644 --- a/src/backend/utils/misc/sampling.c +++ b/src/backend/utils/misc/sampling.c @@ -3,7 +3,7 @@ * sampling.c * Relation block sampling routines. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/misc/superuser.c b/src/backend/utils/misc/superuser.c index dd70e02c9a..175a0677db 100644 --- a/src/backend/utils/misc/superuser.c +++ b/src/backend/utils/misc/superuser.c @@ -9,7 +9,7 @@ * the single-user case works. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/misc/timeout.c b/src/backend/utils/misc/timeout.c index 7171a7c59c..d7fc040ad3 100644 --- a/src/backend/utils/misc/timeout.c +++ b/src/backend/utils/misc/timeout.c @@ -3,7 +3,7 @@ * timeout.c * Routines to multiplex SIGALRM interrupts for multiple timeout reasons. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/misc/tzparser.c b/src/backend/utils/misc/tzparser.c index a960343baa..04d6ee3503 100644 --- a/src/backend/utils/misc/tzparser.c +++ b/src/backend/utils/misc/tzparser.c @@ -11,7 +11,7 @@ * PG_TRY if necessary. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -450,9 +450,7 @@ load_tzoffsets(const char *filename) */ tmpContext = AllocSetContextCreate(CurrentMemoryContext, "TZParserMemory", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MAXSIZE); + ALLOCSET_SMALL_SIZES); oldContext = MemoryContextSwitchTo(tmpContext); /* Initialize array at a reasonable size */ diff --git a/src/backend/utils/mmgr/Makefile b/src/backend/utils/mmgr/Makefile index b2403e186f..1842bae386 100644 --- a/src/backend/utils/mmgr/Makefile +++ b/src/backend/utils/mmgr/Makefile @@ -12,6 +12,6 @@ subdir = src/backend/utils/mmgr top_builddir = ../../../.. include $(top_builddir)/src/Makefile.global -OBJS = aset.o mcxt.o portalmem.o +OBJS = aset.o dsa.o freepage.o mcxt.o portalmem.o include $(top_srcdir)/src/backend/common.mk diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c index d26991ed23..4dfc3ec260 100644 --- a/src/backend/utils/mmgr/aset.c +++ b/src/backend/utils/mmgr/aset.c @@ -7,7 +7,7 @@ * type. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -427,10 +427,14 @@ randomize_mem(char *ptr, size_t size) * Create a new AllocSet context. * * parent: parent context, or NULL if top-level context - * name: name of context (for debugging --- string will be copied) + * name: name of context (for debugging only, need not be unique) * minContextSize: minimum context size * initBlockSize: initial allocation block size * maxBlockSize: maximum allocation block size + * + * Notes: the name string will be copied into context-lifespan storage. + * Most callers should abstract the context size parameters using a macro + * such as ALLOCSET_DEFAULT_SIZES. */ MemoryContext AllocSetContextCreate(MemoryContext parent, @@ -441,6 +445,26 @@ AllocSetContextCreate(MemoryContext parent, { AllocSet set; + /* + * First, validate allocation parameters. (If we're going to throw an + * error, we should do so before the context is created, not after.) We + * somewhat arbitrarily enforce a minimum 1K block size. + */ + if (initBlockSize != MAXALIGN(initBlockSize) || + initBlockSize < 1024) + elog(ERROR, "invalid initBlockSize for memory context: %zu", + initBlockSize); + if (maxBlockSize != MAXALIGN(maxBlockSize) || + maxBlockSize < initBlockSize || + !AllocHugeSizeIsValid(maxBlockSize)) /* must be safe to double */ + elog(ERROR, "invalid maxBlockSize for memory context: %zu", + maxBlockSize); + if (minContextSize != 0 && + (minContextSize != MAXALIGN(minContextSize) || + minContextSize <= ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ)) + elog(ERROR, "invalid minContextSize for memory context: %zu", + minContextSize); + /* Do the type-independent part of context creation */ set = (AllocSet) MemoryContextCreate(T_AllocSetContext, sizeof(AllocSetContext), @@ -448,18 +472,7 @@ AllocSetContextCreate(MemoryContext parent, parent, name); - /* - * Make sure alloc parameters are reasonable, and save them. - * - * We somewhat arbitrarily enforce a minimum 1K block size. - */ - initBlockSize = MAXALIGN(initBlockSize); - if (initBlockSize < 1024) - initBlockSize = 1024; - maxBlockSize = MAXALIGN(maxBlockSize); - if (maxBlockSize < initBlockSize) - maxBlockSize = initBlockSize; - Assert(AllocHugeSizeIsValid(maxBlockSize)); /* must be safe to double */ + /* Save allocation parameters */ set->initBlockSize = initBlockSize; set->maxBlockSize = maxBlockSize; set->nextBlockSize = initBlockSize; @@ -491,9 +504,9 @@ AllocSetContextCreate(MemoryContext parent, /* * Grab always-allocated space, if requested */ - if (minContextSize > ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ) + if (minContextSize > 0) { - Size blksize = MAXALIGN(minContextSize); + Size blksize = minContextSize; AllocBlock block; block = (AllocBlock) malloc(blksize); diff --git a/src/backend/utils/mmgr/dsa.c b/src/backend/utils/mmgr/dsa.c new file mode 100644 index 0000000000..7dc43f1ea7 --- /dev/null +++ b/src/backend/utils/mmgr/dsa.c @@ -0,0 +1,2182 @@ +/*------------------------------------------------------------------------- + * + * dsa.c + * Dynamic shared memory areas. + * + * This module provides dynamic shared memory areas which are built on top of + * DSM segments. While dsm.c allows segments of memory of shared memory to be + * created and shared between backends, it isn't designed to deal with small + * objects. A DSA area is a shared memory heap usually backed by one or more + * DSM segments which can allocate memory using dsa_allocate() and dsa_free(). + * Alternatively, it can be created in pre-existing shared memory, including a + * DSM segment, and then create extra DSM segments as required. Unlike the + * regular system heap, it deals in pseudo-pointers which must be converted to + * backend-local pointers before they are dereferenced. These pseudo-pointers + * can however be shared with other backends, and can be used to construct + * shared data structures. + * + * Each DSA area manages a set of DSM segments, adding new segments as + * required and detaching them when they are no longer needed. Each segment + * contains a number of 4KB pages, a free page manager for tracking + * consecutive runs of free pages, and a page map for tracking the source of + * objects allocated on each page. Allocation requests above 8KB are handled + * by choosing a segment and finding consecutive free pages in its free page + * manager. Allocation requests for smaller sizes are handled using pools of + * objects of a selection of sizes. Each pool consists of a number of 16 page + * (64KB) superblocks allocated in the same way as large objects. Allocation + * of large objects and new superblocks is serialized by a single LWLock, but + * allocation of small objects from pre-existing superblocks uses one LWLock + * per pool. Currently there is one pool, and therefore one lock, per size + * class. Per-core pools to increase concurrency and strategies for reducing + * the resulting fragmentation are areas for future research. Each superblock + * is managed with a 'span', which tracks the superblock's freelist. Free + * requests are handled by looking in the page map to find which span an + * address was allocated from, so that small objects can be returned to the + * appropriate free list, and large object pages can be returned directly to + * the free page map. When allocating, simple heuristics for selecting + * segments and superblocks try to encourage occupied memory to be + * concentrated, increasing the likelihood that whole superblocks can become + * empty and be returned to the free page manager, and whole segments can + * become empty and be returned to the operating system. + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/utils/mmgr/dsa.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "port/atomics.h" +#include "storage/dsm.h" +#include "storage/ipc.h" +#include "storage/lwlock.h" +#include "storage/shmem.h" +#include "utils/dsa.h" +#include "utils/freepage.h" +#include "utils/memutils.h" + +/* + * The size of the initial DSM segment that backs a dsa_area created by + * dsa_create. After creating some number of segments of this size we'll + * double this size, and so on. Larger segments may be created if necessary + * to satisfy large requests. + */ +#define DSA_INITIAL_SEGMENT_SIZE ((Size) (1 * 1024 * 1024)) + +/* + * How many segments to create before we double the segment size. If this is + * low, then there is likely to be a lot of wasted space in the largest + * segment. If it is high, then we risk running out of segment slots (see + * dsm.c's limits on total number of segments), or limiting the total size + * an area can manage when using small pointers. + */ +#define DSA_NUM_SEGMENTS_AT_EACH_SIZE 4 + +/* + * The number of bits used to represent the offset part of a dsa_pointer. + * This controls the maximum size of a segment, the maximum possible + * allocation size and also the maximum number of segments per area. + */ +#if SIZEOF_DSA_POINTER == 4 +#define DSA_OFFSET_WIDTH 27 /* 32 segments of size up to 128MB */ +#else +#define DSA_OFFSET_WIDTH 40 /* 1024 segments of size up to 1TB */ +#endif + +/* + * The maximum number of DSM segments that an area can own, determined by + * the number of bits remaining (but capped at 1024). + */ +#define DSA_MAX_SEGMENTS \ + Min(1024, (1 << ((SIZEOF_DSA_POINTER * 8) - DSA_OFFSET_WIDTH))) + +/* The bitmask for extracting the offset from a dsa_pointer. */ +#define DSA_OFFSET_BITMASK (((dsa_pointer) 1 << DSA_OFFSET_WIDTH) - 1) + +/* The maximum size of a DSM segment. */ +#define DSA_MAX_SEGMENT_SIZE ((Size) 1 << DSA_OFFSET_WIDTH) + +/* Number of pages (see FPM_PAGE_SIZE) per regular superblock. */ +#define DSA_PAGES_PER_SUPERBLOCK 16 + +/* + * A magic number used as a sanity check for following DSM segments belonging + * to a DSA area (this number will be XORed with the area handle and + * the segment index). + */ +#define DSA_SEGMENT_HEADER_MAGIC 0x0ce26608 + +/* Build a dsa_pointer given a segment number and offset. */ +#define DSA_MAKE_POINTER(segment_number, offset) \ + (((dsa_pointer) (segment_number) << DSA_OFFSET_WIDTH) | (offset)) + +/* Extract the segment number from a dsa_pointer. */ +#define DSA_EXTRACT_SEGMENT_NUMBER(dp) ((dp) >> DSA_OFFSET_WIDTH) + +/* Extract the offset from a dsa_pointer. */ +#define DSA_EXTRACT_OFFSET(dp) ((dp) & DSA_OFFSET_BITMASK) + +/* The type used for index segment indexes (zero based). */ +typedef Size dsa_segment_index; + +/* Sentinel value for dsa_segment_index indicating 'none' or 'end'. */ +#define DSA_SEGMENT_INDEX_NONE (~(dsa_segment_index)0) + +/* + * How many bins of segments do we have? The bins are used to categorize + * segments by their largest contiguous run of free pages. + */ +#define DSA_NUM_SEGMENT_BINS 16 + +/* + * What is the lowest bin that holds segments that *might* have n contiguous + * free pages? There is no point in looking in segments in lower bins; they + * definitely can't service a request for n free pages. + */ +#define contiguous_pages_to_segment_bin(n) Min(fls(n), DSA_NUM_SEGMENT_BINS - 1) + +/* Macros for access to locks. */ +#define DSA_AREA_LOCK(area) (&area->control->lock) +#define DSA_SCLASS_LOCK(area, sclass) (&area->control->pools[sclass].lock) + +/* + * The header for an individual segment. This lives at the start of each DSM + * segment owned by a DSA area including the first segment (where it appears + * as part of the dsa_area_control struct). + */ +typedef struct +{ + /* Sanity check magic value. */ + uint32 magic; + /* Total number of pages in this segment (excluding metadata area). */ + Size usable_pages; + /* Total size of this segment in bytes. */ + Size size; + + /* + * Index of the segment that precedes this one in the same segment bin, or + * DSA_SEGMENT_INDEX_NONE if this is the first one. + */ + dsa_segment_index prev; + + /* + * Index of the segment that follows this one in the same segment bin, or + * DSA_SEGMENT_INDEX_NONE if this is the last one. + */ + dsa_segment_index next; + /* The index of the bin that contains this segment. */ + Size bin; + + /* + * A flag raised to indicate that this segment is being returned to the + * operating system and has been unpinned. + */ + bool freed; +} dsa_segment_header; + +/* + * Metadata for one superblock. + * + * For most blocks, span objects are stored out-of-line; that is, the span + * object is not stored within the block itself. But, as an exception, for a + * "span of spans", the span object is stored "inline". The allocation is + * always exactly one page, and the dsa_area_span object is located at + * the beginning of that page. The size class is DSA_SCLASS_BLOCK_OF_SPANS, + * and the remaining fields are used just as they would be in an ordinary + * block. We can't allocate spans out of ordinary superblocks because + * creating an ordinary superblock requires us to be able to allocate a span + * *first*. Doing it this way avoids that circularity. + */ +typedef struct +{ + dsa_pointer pool; /* Containing pool. */ + dsa_pointer prevspan; /* Previous span. */ + dsa_pointer nextspan; /* Next span. */ + dsa_pointer start; /* Starting address. */ + Size npages; /* Length of span in pages. */ + uint16 size_class; /* Size class. */ + uint16 ninitialized; /* Maximum number of objects ever allocated. */ + uint16 nallocatable; /* Number of objects currently allocatable. */ + uint16 firstfree; /* First object on free list. */ + uint16 nmax; /* Maximum number of objects ever possible. */ + uint16 fclass; /* Current fullness class. */ +} dsa_area_span; + +/* + * Given a pointer to an object in a span, access the index of the next free + * object in the same span (ie in the span's freelist) as an L-value. + */ +#define NextFreeObjectIndex(object) (* (uint16 *) (object)) + +/* + * Small allocations are handled by dividing a single block of memory into + * many small objects of equal size. The possible allocation sizes are + * defined by the following array. Larger size classes are spaced more widely + * than smaller size classes. We fudge the spacing for size classes >1kB to + * avoid space wastage: based on the knowledge that we plan to allocate 64kB + * blocks, we bump the maximum object size up to the largest multiple of + * 8 bytes that still lets us fit the same number of objects into one block. + * + * NB: Because of this fudging, if we were ever to use differently-sized blocks + * for small allocations, these size classes would need to be reworked to be + * optimal for the new size. + * + * NB: The optimal spacing for size classes, as well as the size of the blocks + * out of which small objects are allocated, is not a question that has one + * right answer. Some allocators (such as tcmalloc) use more closely-spaced + * size classes than we do here, while others (like aset.c) use more + * widely-spaced classes. Spacing the classes more closely avoids wasting + * memory within individual chunks, but also means a larger number of + * potentially-unfilled blocks. + */ +static const uint16 dsa_size_classes[] = { + sizeof(dsa_area_span), 0, /* special size classes */ + 8, 16, 24, 32, 40, 48, 56, 64, /* 8 classes separated by 8 bytes */ + 80, 96, 112, 128, /* 4 classes separated by 16 bytes */ + 160, 192, 224, 256, /* 4 classes separated by 32 bytes */ + 320, 384, 448, 512, /* 4 classes separated by 64 bytes */ + 640, 768, 896, 1024, /* 4 classes separated by 128 bytes */ + 1280, 1560, 1816, 2048, /* 4 classes separated by ~256 bytes */ + 2616, 3120, 3640, 4096, /* 4 classes separated by ~512 bytes */ + 5456, 6552, 7280, 8192 /* 4 classes separated by ~1024 bytes */ +}; +#define DSA_NUM_SIZE_CLASSES lengthof(dsa_size_classes) + +/* Special size classes. */ +#define DSA_SCLASS_BLOCK_OF_SPANS 0 +#define DSA_SCLASS_SPAN_LARGE 1 + +/* + * The following lookup table is used to map the size of small objects + * (less than 1kB) onto the corresponding size class. To use this table, + * round the size of the object up to the next multiple of 8 bytes, and then + * index into this array. + */ +static char dsa_size_class_map[] = { + 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 11, 11, 12, 12, 13, 13, + 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, + 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, + 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25 +}; +#define DSA_SIZE_CLASS_MAP_QUANTUM 8 + +/* + * Superblocks are binned by how full they are. Generally, each fullness + * class corresponds to one quartile, but the block being used for + * allocations is always at the head of the list for fullness class 1, + * regardless of how full it really is. + */ +#define DSA_FULLNESS_CLASSES 4 + +/* + * A dsa_area_pool represents a set of objects of a given size class. + * + * Perhaps there should be multiple pools for the same size class for + * contention avoidance, but for now there is just one! + */ +typedef struct +{ + /* A lock protecting access to this pool. */ + LWLock lock; + /* A set of linked lists of spans, arranged by fullness. */ + dsa_pointer spans[DSA_FULLNESS_CLASSES]; + /* Should we pad this out to a cacheline boundary? */ +} dsa_area_pool; + +/* + * The control block for an area. This lives in shared memory, at the start of + * the first DSM segment controlled by this area. + */ +typedef struct +{ + /* The segment header for the first segment. */ + dsa_segment_header segment_header; + /* The handle for this area. */ + dsa_handle handle; + /* The handles of the segments owned by this area. */ + dsm_handle segment_handles[DSA_MAX_SEGMENTS]; + /* Lists of segments, binned by maximum contiguous run of free pages. */ + dsa_segment_index segment_bins[DSA_NUM_SEGMENT_BINS]; + /* The object pools for each size class. */ + dsa_area_pool pools[DSA_NUM_SIZE_CLASSES]; + /* The total size of all active segments. */ + Size total_segment_size; + /* The maximum total size of backing storage we are allowed. */ + Size max_total_segment_size; + /* Highest used segment index in the history of this area. */ + dsa_segment_index high_segment_index; + /* The reference count for this area. */ + int refcnt; + /* A flag indicating that this area has been pinned. */ + bool pinned; + /* The number of times that segments have been freed. */ + Size freed_segment_counter; + /* The LWLock tranche ID. */ + int lwlock_tranche_id; + /* The general lock (protects everything except object pools). */ + LWLock lock; +} dsa_area_control; + +/* Given a pointer to a pool, find a dsa_pointer. */ +#define DsaAreaPoolToDsaPointer(area, p) \ + DSA_MAKE_POINTER(0, (char *) p - (char *) area->control) + +/* + * A dsa_segment_map is stored within the backend-private memory of each + * individual backend. It holds the base address of the segment within that + * backend, plus the addresses of key objects within the segment. Those + * could instead be derived from the base address but it's handy to have them + * around. + */ +typedef struct +{ + dsm_segment *segment; /* DSM segment */ + char *mapped_address; /* Address at which segment is mapped */ + dsa_segment_header *header; /* Header (same as mapped_address) */ + FreePageManager *fpm; /* Free page manager within segment. */ + dsa_pointer *pagemap; /* Page map within segment. */ +} dsa_segment_map; + +/* + * Per-backend state for a storage area. Backends obtain one of these by + * creating an area or attaching to an existing one using a handle. Each + * process that needs to use an area uses its own object to track where the + * segments are mapped. + */ +struct dsa_area +{ + /* Pointer to the control object in shared memory. */ + dsa_area_control *control; + + /* Has the mapping been pinned? */ + bool mapping_pinned; + + /* + * This backend's array of segment maps, ordered by segment index + * corresponding to control->segment_handles. Some of the area's segments + * may not be mapped in in this backend yet, and some slots may have been + * freed and need to be detached; these operations happen on demand. + */ + dsa_segment_map segment_maps[DSA_MAX_SEGMENTS]; + + /* The highest segment index this backend has ever mapped. */ + dsa_segment_index high_segment_index; + + /* The last observed freed_segment_counter. */ + Size freed_segment_counter; +}; + +#define DSA_SPAN_NOTHING_FREE ((uint16) -1) +#define DSA_SUPERBLOCK_SIZE (DSA_PAGES_PER_SUPERBLOCK * FPM_PAGE_SIZE) + +/* Given a pointer to a segment_map, obtain a segment index number. */ +#define get_segment_index(area, segment_map_ptr) \ + (segment_map_ptr - &area->segment_maps[0]) + +static void init_span(dsa_area *area, dsa_pointer span_pointer, + dsa_area_pool *pool, dsa_pointer start, Size npages, + uint16 size_class); +static bool transfer_first_span(dsa_area *area, dsa_area_pool *pool, + int fromclass, int toclass); +static inline dsa_pointer alloc_object(dsa_area *area, int size_class); +static bool ensure_active_superblock(dsa_area *area, dsa_area_pool *pool, + int size_class); +static dsa_segment_map *get_segment_by_index(dsa_area *area, + dsa_segment_index index); +static void destroy_superblock(dsa_area *area, dsa_pointer span_pointer); +static void unlink_span(dsa_area *area, dsa_area_span *span); +static void add_span_to_fullness_class(dsa_area *area, dsa_area_span *span, + dsa_pointer span_pointer, int fclass); +static void unlink_segment(dsa_area *area, dsa_segment_map *segment_map); +static dsa_segment_map *get_best_segment(dsa_area *area, Size npages); +static dsa_segment_map *make_new_segment(dsa_area *area, Size requested_pages); +static dsa_area *create_internal(void *place, size_t size, + int tranche_id, + dsm_handle control_handle, + dsm_segment *control_segment); +static dsa_area *attach_internal(void *place, dsm_segment *segment, + dsa_handle handle); +static void check_for_freed_segments(dsa_area *area); + +/* + * Create a new shared area in a new DSM segment. Further DSM segments will + * be allocated as required to extend the available space. + * + * We can't allocate a LWLock tranche_id within this function, because tranche + * IDs are a scarce resource; there are only 64k available, using low numbers + * when possible matters, and we have no provision for recycling them. So, + * we require the caller to provide one. + */ +dsa_area * +dsa_create(int tranche_id) +{ + dsm_segment *segment; + dsa_area *area; + + /* + * Create the DSM segment that will hold the shared control object and the + * first segment of usable space. + */ + segment = dsm_create(DSA_INITIAL_SEGMENT_SIZE, 0); + + /* + * All segments backing this area are pinned, so that DSA can explicitly + * control their lifetime (otherwise a newly created segment belonging to + * this area might be freed when the only backend that happens to have it + * mapped in ends, corrupting the area). + */ + dsm_pin_segment(segment); + + /* Create a new DSA area with the control object in this segment. */ + area = create_internal(dsm_segment_address(segment), + DSA_INITIAL_SEGMENT_SIZE, + tranche_id, + dsm_segment_handle(segment), segment); + + /* Clean up when the control segment detaches. */ + on_dsm_detach(segment, &dsa_on_dsm_detach_release_in_place, + PointerGetDatum(dsm_segment_address(segment))); + + return area; +} + +/* + * Create a new shared area in an existing shared memory space, which may be + * either DSM or Postmaster-initialized memory. DSM segments will be + * allocated as required to extend the available space, though that can be + * prevented with dsa_set_size_limit(area, size) using the same size provided + * to dsa_create_in_place. + * + * Areas created in-place must eventually be released by the backend that + * created them and all backends that attach to them. This can be done + * explicitly with dsa_release_in_place, or, in the special case that 'place' + * happens to be in a pre-existing DSM segment, by passing in a pointer to the + * segment so that a detach hook can be registered with the containing DSM + * segment. + * + * See dsa_create() for a note about the tranche arguments. + */ +dsa_area * +dsa_create_in_place(void *place, size_t size, + int tranche_id, dsm_segment *segment) +{ + dsa_area *area; + + area = create_internal(place, size, tranche_id, + DSM_HANDLE_INVALID, NULL); + + /* + * Clean up when the control segment detaches, if a containing DSM segment + * was provided. + */ + if (segment != NULL) + on_dsm_detach(segment, &dsa_on_dsm_detach_release_in_place, + PointerGetDatum(place)); + + return area; +} + +/* + * Obtain a handle that can be passed to other processes so that they can + * attach to the given area. Cannot be called for areas created with + * dsa_create_in_place. + */ +dsa_handle +dsa_get_handle(dsa_area *area) +{ + Assert(area->control->handle != DSM_HANDLE_INVALID); + return area->control->handle; +} + +/* + * Attach to an area given a handle generated (possibly in another process) by + * dsa_get_area_handle. The area must have been created with dsa_create (not + * dsa_create_in_place). + */ +dsa_area * +dsa_attach(dsa_handle handle) +{ + dsm_segment *segment; + dsa_area *area; + + /* + * An area handle is really a DSM segment handle for the first segment, so + * we go ahead and attach to that. + */ + segment = dsm_attach(handle); + if (segment == NULL) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("could not attach to dsa_handle"))); + + area = attach_internal(dsm_segment_address(segment), segment, handle); + + /* Clean up when the control segment detaches. */ + on_dsm_detach(segment, &dsa_on_dsm_detach_release_in_place, + PointerGetDatum(dsm_segment_address(segment))); + + return area; +} + +/* + * Attach to an area that was created with dsa_create_in_place. The caller + * must somehow know the location in memory that was used when the area was + * created, though it may be mapped at a different virtual address in this + * process. + * + * See dsa_create_in_place for note about releasing in-place areas, and the + * optional 'segment' argument which can be provided to allow automatic + * release if the containing memory happens to be a DSM segment. + */ +dsa_area * +dsa_attach_in_place(void *place, dsm_segment *segment) +{ + dsa_area *area; + + area = attach_internal(place, NULL, DSM_HANDLE_INVALID); + + /* + * Clean up when the control segment detaches, if a containing DSM segment + * was provided. + */ + if (segment != NULL) + on_dsm_detach(segment, &dsa_on_dsm_detach_release_in_place, + PointerGetDatum(place)); + + return area; +} + +/* + * Release a DSA area that was produced by dsa_create_in_place or + * dsa_attach_in_place. The 'segment' argument is ignored but provides an + * interface suitable for on_dsm_detach, for the convenience of users who want + * to create a DSA segment inside an existing DSM segment and have it + * automatically released when the containing DSM segment is detached. + * 'place' should be the address of the place where the area was created. + * + * This callback is automatically registered for the DSM segment containing + * the control object of in-place areas when a segment is provided to + * dsa_create_in_place or dsa_attach_in_place, and also for all areas created + * with dsa_create. + */ +void +dsa_on_dsm_detach_release_in_place(dsm_segment *segment, Datum place) +{ + dsa_release_in_place(DatumGetPointer(place)); +} + +/* + * Release a DSA area that was produced by dsa_create_in_place or + * dsa_attach_in_place. The 'code' argument is ignored but provides an + * interface suitable for on_shmem_exit or before_shmem_exit, for the + * convenience of users who want to create a DSA segment inside shared memory + * other than a DSM segment and have it automatically release at backend exit. + * 'place' should be the address of the place where the area was created. + */ +void +dsa_on_shmem_exit_release_in_place(int code, Datum place) +{ + dsa_release_in_place(DatumGetPointer(place)); +} + +/* + * Release a DSA area that was produced by dsa_create_in_place or + * dsa_attach_in_place. It is preferable to use one of the 'dsa_on_XXX' + * callbacks so that this is managed automatically, because failure to release + * an area created in-place leaks its segments permanently. + * + * This is also called automatically for areas produced by dsa_create or + * dsa_attach as an implementation detail. + */ +void +dsa_release_in_place(void *place) +{ + dsa_area_control *control = (dsa_area_control *) place; + int i; + + LWLockAcquire(&control->lock, LW_EXCLUSIVE); + Assert(control->segment_header.magic == + (DSA_SEGMENT_HEADER_MAGIC ^ control->handle ^ 0)); + Assert(control->refcnt > 0); + if (--control->refcnt == 0) + { + for (i = 0; i <= control->high_segment_index; ++i) + { + dsm_handle handle; + + handle = control->segment_handles[i]; + if (handle != DSM_HANDLE_INVALID) + dsm_unpin_segment(handle); + } + } + LWLockRelease(&control->lock); +} + +/* + * Keep a DSA area attached until end of session or explicit detach. + * + * By default, areas are owned by the current resource owner, which means they + * are detached automatically when that scope ends. + */ +void +dsa_pin_mapping(dsa_area *area) +{ + int i; + + Assert(!area->mapping_pinned); + area->mapping_pinned = true; + + for (i = 0; i <= area->high_segment_index; ++i) + if (area->segment_maps[i].segment != NULL) + dsm_pin_mapping(area->segment_maps[i].segment); +} + +/* + * Allocate memory in this storage area. The return value is a dsa_pointer + * that can be passed to other processes, and converted to a local pointer + * with dsa_get_address. If no memory is available, returns + * InvalidDsaPointer. + */ +dsa_pointer +dsa_allocate(dsa_area *area, Size size) +{ + uint16 size_class; + dsa_pointer start_pointer; + dsa_segment_map *segment_map; + + Assert(size > 0); + + /* + * If bigger than the largest size class, just grab a run of pages from + * the free page manager, instead of allocating an object from a pool. + * There will still be a span, but it's a special class of span that + * manages this whole allocation and simply gives all pages back to the + * free page manager when dsa_free is called. + */ + if (size > dsa_size_classes[lengthof(dsa_size_classes) - 1]) + { + Size npages = fpm_size_to_pages(size); + Size first_page; + dsa_pointer span_pointer; + dsa_area_pool *pool = &area->control->pools[DSA_SCLASS_SPAN_LARGE]; + + /* Obtain a span object. */ + span_pointer = alloc_object(area, DSA_SCLASS_BLOCK_OF_SPANS); + if (!DsaPointerIsValid(span_pointer)) + return InvalidDsaPointer; + + LWLockAcquire(DSA_AREA_LOCK(area), LW_EXCLUSIVE); + + /* Find a segment from which to allocate. */ + segment_map = get_best_segment(area, npages); + if (segment_map == NULL) + segment_map = make_new_segment(area, npages); + if (segment_map == NULL) + { + /* Can't make any more segments: game over. */ + LWLockRelease(DSA_AREA_LOCK(area)); + dsa_free(area, span_pointer); + return InvalidDsaPointer; + } + + /* + * Ask the free page manager for a run of pages. This should always + * succeed, since both get_best_segment and make_new_segment should + * only return a non-NULL pointer if it actually contains enough + * contiguous freespace. If it does fail, something in our backend + * private state is out of whack, so use FATAL to kill the process. + */ + if (!FreePageManagerGet(segment_map->fpm, npages, &first_page)) + elog(FATAL, + "dsa_allocate could not find %zu free pages", npages); + LWLockRelease(DSA_AREA_LOCK(area)); + + start_pointer = DSA_MAKE_POINTER(get_segment_index(area, segment_map), + first_page * FPM_PAGE_SIZE); + + /* Initialize span and pagemap. */ + LWLockAcquire(DSA_SCLASS_LOCK(area, DSA_SCLASS_SPAN_LARGE), + LW_EXCLUSIVE); + init_span(area, span_pointer, pool, start_pointer, npages, + DSA_SCLASS_SPAN_LARGE); + segment_map->pagemap[first_page] = span_pointer; + LWLockRelease(DSA_SCLASS_LOCK(area, DSA_SCLASS_SPAN_LARGE)); + + return start_pointer; + } + + /* Map allocation to a size class. */ + if (size < lengthof(dsa_size_class_map) * DSA_SIZE_CLASS_MAP_QUANTUM) + { + int mapidx; + + /* For smaller sizes we have a lookup table... */ + mapidx = ((size + DSA_SIZE_CLASS_MAP_QUANTUM - 1) / + DSA_SIZE_CLASS_MAP_QUANTUM) - 1; + size_class = dsa_size_class_map[mapidx]; + } + else + { + uint16 min; + uint16 max; + + /* ... and for the rest we search by binary chop. */ + min = dsa_size_class_map[lengthof(dsa_size_class_map) - 1]; + max = lengthof(dsa_size_classes) - 1; + + while (min < max) + { + uint16 mid = (min + max) / 2; + uint16 class_size = dsa_size_classes[mid]; + + if (class_size < size) + min = mid + 1; + else + max = mid; + } + + size_class = min; + } + Assert(size <= dsa_size_classes[size_class]); + Assert(size_class == 0 || size > dsa_size_classes[size_class - 1]); + + /* + * Attempt to allocate an object from the appropriate pool. This might + * return InvalidDsaPointer if there's no space available. + */ + return alloc_object(area, size_class); +} + +/* + * Free memory obtained with dsa_allocate. + */ +void +dsa_free(dsa_area *area, dsa_pointer dp) +{ + dsa_segment_map *segment_map; + int pageno; + dsa_pointer span_pointer; + dsa_area_span *span; + char *superblock; + char *object; + Size size; + int size_class; + + /* Make sure we don't have a stale segment in the slot 'dp' refers to. */ + check_for_freed_segments(area); + + /* Locate the object, span and pool. */ + segment_map = get_segment_by_index(area, DSA_EXTRACT_SEGMENT_NUMBER(dp)); + pageno = DSA_EXTRACT_OFFSET(dp) / FPM_PAGE_SIZE; + span_pointer = segment_map->pagemap[pageno]; + span = dsa_get_address(area, span_pointer); + superblock = dsa_get_address(area, span->start); + object = dsa_get_address(area, dp); + size_class = span->size_class; + size = dsa_size_classes[size_class]; + + /* + * Special case for large objects that live in a special span: we return + * those pages directly to the free page manager and free the span. + */ + if (span->size_class == DSA_SCLASS_SPAN_LARGE) + { + +#ifdef CLOBBER_FREED_MEMORY + memset(object, 0x7f, span->npages * FPM_PAGE_SIZE); +#endif + + /* Give pages back to free page manager. */ + LWLockAcquire(DSA_AREA_LOCK(area), LW_EXCLUSIVE); + FreePageManagerPut(segment_map->fpm, + DSA_EXTRACT_OFFSET(span->start) / FPM_PAGE_SIZE, + span->npages); + LWLockRelease(DSA_AREA_LOCK(area)); + /* Unlink span. */ + LWLockAcquire(DSA_SCLASS_LOCK(area, DSA_SCLASS_SPAN_LARGE), + LW_EXCLUSIVE); + unlink_span(area, span); + LWLockRelease(DSA_SCLASS_LOCK(area, DSA_SCLASS_SPAN_LARGE)); + /* Free the span object so it can be reused. */ + dsa_free(area, span_pointer); + return; + } + +#ifdef CLOBBER_FREED_MEMORY + memset(object, 0x7f, size); +#endif + + LWLockAcquire(DSA_SCLASS_LOCK(area, size_class), LW_EXCLUSIVE); + + /* Put the object on the span's freelist. */ + Assert(object >= superblock); + Assert(object < superblock + DSA_SUPERBLOCK_SIZE); + Assert((object - superblock) % size == 0); + NextFreeObjectIndex(object) = span->firstfree; + span->firstfree = (object - superblock) / size; + ++span->nallocatable; + + /* + * See if the span needs to moved to a different fullness class, or be + * freed so its pages can be given back to the segment. + */ + if (span->nallocatable == 1 && span->fclass == DSA_FULLNESS_CLASSES - 1) + { + /* + * The block was completely full and is located in the + * highest-numbered fullness class, which is never scanned for free + * chunks. We must move it to the next-lower fullness class. + */ + unlink_span(area, span); + add_span_to_fullness_class(area, span, span_pointer, + DSA_FULLNESS_CLASSES - 2); + + /* + * If this is the only span, and there is no active span, then we + * should probably move this span to fullness class 1. (Otherwise if + * you allocate exactly all the objects in the only span, it moves to + * class 3, then you free them all, it moves to 2, and then is given + * back, leaving no active span). + */ + } + else if (span->nallocatable == span->nmax && + (span->fclass != 1 || span->prevspan != InvalidDsaPointer)) + { + /* + * This entire block is free, and it's not the active block for this + * size class. Return the memory to the free page manager. We don't + * do this for the active block to prevent hysteresis: if we + * repeatedly allocate and free the only chunk in the active block, it + * will be very inefficient if we deallocate and reallocate the block + * every time. + */ + destroy_superblock(area, span_pointer); + } + + LWLockRelease(DSA_SCLASS_LOCK(area, size_class)); +} + +/* + * Obtain a backend-local address for a dsa_pointer. 'dp' must point to + * memory allocated by the given area (possibly in another process) that + * hasn't yet been freed. This may cause a segment to be mapped into the + * current process if required, and may cause freed segments to be unmapped. + */ +void * +dsa_get_address(dsa_area *area, dsa_pointer dp) +{ + dsa_segment_index index; + Size offset; + + /* Convert InvalidDsaPointer to NULL. */ + if (!DsaPointerIsValid(dp)) + return NULL; + + /* Process any requests to detach from freed segments. */ + check_for_freed_segments(area); + + /* Break the dsa_pointer into its components. */ + index = DSA_EXTRACT_SEGMENT_NUMBER(dp); + offset = DSA_EXTRACT_OFFSET(dp); + Assert(index < DSA_MAX_SEGMENTS); + + /* Check if we need to cause this segment to be mapped in. */ + if (unlikely(area->segment_maps[index].mapped_address == NULL)) + { + /* Call for effect (we don't need the result). */ + get_segment_by_index(area, index); + } + + return area->segment_maps[index].mapped_address + offset; +} + +/* + * Pin this area, so that it will continue to exist even if all backends + * detach from it. In that case, the area can still be reattached to if a + * handle has been recorded somewhere. + */ +void +dsa_pin(dsa_area *area) +{ + LWLockAcquire(DSA_AREA_LOCK(area), LW_EXCLUSIVE); + if (area->control->pinned) + { + LWLockRelease(DSA_AREA_LOCK(area)); + elog(ERROR, "dsa_area already pinned"); + } + area->control->pinned = true; + ++area->control->refcnt; + LWLockRelease(DSA_AREA_LOCK(area)); +} + +/* + * Undo the effects of dsa_pin, so that the given area can be freed when no + * backends are attached to it. May be called only if dsa_pin has been + * called. + */ +void +dsa_unpin(dsa_area *area) +{ + LWLockAcquire(DSA_AREA_LOCK(area), LW_EXCLUSIVE); + Assert(area->control->refcnt > 1); + if (!area->control->pinned) + { + LWLockRelease(DSA_AREA_LOCK(area)); + elog(ERROR, "dsa_area not pinned"); + } + area->control->pinned = false; + --area->control->refcnt; + LWLockRelease(DSA_AREA_LOCK(area)); +} + +/* + * Set the total size limit for this area. This limit is checked whenever new + * segments need to be allocated from the operating system. If the new size + * limit is already exceeded, this has no immediate effect. + * + * Note that the total virtual memory usage may be temporarily larger than + * this limit when segments have been freed, but not yet detached by all + * backends that have attached to them. + */ +void +dsa_set_size_limit(dsa_area *area, Size limit) +{ + LWLockAcquire(DSA_AREA_LOCK(area), LW_EXCLUSIVE); + area->control->max_total_segment_size = limit; + LWLockRelease(DSA_AREA_LOCK(area)); +} + +/* + * Aggressively free all spare memory in the hope of returning DSM segments to + * the operating system. + */ +void +dsa_trim(dsa_area *area) +{ + int size_class; + + /* + * Trim in reverse pool order so we get to the spans-of-spans last, just + * in case any become entirely free while processing all the other pools. + */ + for (size_class = DSA_NUM_SIZE_CLASSES - 1; size_class >= 0; --size_class) + { + dsa_area_pool *pool = &area->control->pools[size_class]; + dsa_pointer span_pointer; + + if (size_class == DSA_SCLASS_SPAN_LARGE) + { + /* Large object frees give back segments aggressively already. */ + continue; + } + + /* + * Search fullness class 1 only. That is where we expect to find an + * entirely empty superblock (entirely empty superblocks in other + * fullness classes are returned to the free page map by dsa_free). + */ + LWLockAcquire(DSA_SCLASS_LOCK(area, size_class), LW_EXCLUSIVE); + span_pointer = pool->spans[1]; + while (DsaPointerIsValid(span_pointer)) + { + dsa_area_span *span = dsa_get_address(area, span_pointer); + dsa_pointer next = span->nextspan; + + if (span->nallocatable == span->nmax) + destroy_superblock(area, span_pointer); + + span_pointer = next; + } + LWLockRelease(DSA_SCLASS_LOCK(area, size_class)); + } +} + +/* + * Print out debugging information about the internal state of the shared + * memory area. + */ +void +dsa_dump(dsa_area *area) +{ + Size i, + j; + + /* + * Note: This gives an inconsistent snapshot as it acquires and releases + * individual locks as it goes... + */ + + LWLockAcquire(DSA_AREA_LOCK(area), LW_EXCLUSIVE); + fprintf(stderr, "dsa_area handle %x:\n", area->control->handle); + fprintf(stderr, " max_total_segment_size: %zu\n", + area->control->max_total_segment_size); + fprintf(stderr, " total_segment_size: %zu\n", + area->control->total_segment_size); + fprintf(stderr, " refcnt: %d\n", area->control->refcnt); + fprintf(stderr, " pinned: %c\n", area->control->pinned ? 't' : 'f'); + fprintf(stderr, " segment bins:\n"); + for (i = 0; i < DSA_NUM_SEGMENT_BINS; ++i) + { + if (area->control->segment_bins[i] != DSA_SEGMENT_INDEX_NONE) + { + dsa_segment_index segment_index; + + fprintf(stderr, + " segment bin %zu (at least %d contiguous pages free):\n", + i, 1 << (i - 1)); + segment_index = area->control->segment_bins[i]; + while (segment_index != DSA_SEGMENT_INDEX_NONE) + { + dsa_segment_map *segment_map; + + segment_map = + get_segment_by_index(area, segment_index); + + fprintf(stderr, + " segment index %zu, usable_pages = %zu, " + "contiguous_pages = %zu, mapped at %p\n", + segment_index, + segment_map->header->usable_pages, + fpm_largest(segment_map->fpm), + segment_map->mapped_address); + segment_index = segment_map->header->next; + } + } + } + LWLockRelease(DSA_AREA_LOCK(area)); + + fprintf(stderr, " pools:\n"); + for (i = 0; i < DSA_NUM_SIZE_CLASSES; ++i) + { + bool found = false; + + LWLockAcquire(DSA_SCLASS_LOCK(area, i), LW_EXCLUSIVE); + for (j = 0; j < DSA_FULLNESS_CLASSES; ++j) + if (DsaPointerIsValid(area->control->pools[i].spans[j])) + found = true; + if (found) + { + if (i == DSA_SCLASS_BLOCK_OF_SPANS) + fprintf(stderr, " pool for blocks of span objects:\n"); + else if (i == DSA_SCLASS_SPAN_LARGE) + fprintf(stderr, " pool for large object spans:\n"); + else + fprintf(stderr, + " pool for size class %zu (object size %hu bytes):\n", + i, dsa_size_classes[i]); + for (j = 0; j < DSA_FULLNESS_CLASSES; ++j) + { + if (!DsaPointerIsValid(area->control->pools[i].spans[j])) + fprintf(stderr, " fullness class %zu is empty\n", j); + else + { + dsa_pointer span_pointer = area->control->pools[i].spans[j]; + + fprintf(stderr, " fullness class %zu:\n", j); + while (DsaPointerIsValid(span_pointer)) + { + dsa_area_span *span; + + span = dsa_get_address(area, span_pointer); + fprintf(stderr, + " span descriptor at " + DSA_POINTER_FORMAT ", superblock at " + DSA_POINTER_FORMAT + ", pages = %zu, objects free = %hu/%hu\n", + span_pointer, span->start, span->npages, + span->nallocatable, span->nmax); + span_pointer = span->nextspan; + } + } + } + } + LWLockRelease(DSA_SCLASS_LOCK(area, i)); + } +} + +/* + * Return the smallest size that you can successfully provide to + * dsa_create_in_place. + */ +Size +dsa_minimum_size(void) +{ + Size size; + int pages = 0; + + size = MAXALIGN(sizeof(dsa_area_control)) + + MAXALIGN(sizeof(FreePageManager)); + + /* Figure out how many pages we need, including the page map... */ + while (((size + FPM_PAGE_SIZE - 1) / FPM_PAGE_SIZE) > pages) + { + ++pages; + size += sizeof(dsa_pointer); + } + + return pages * FPM_PAGE_SIZE; +} + +/* + * Workhorse function for dsa_create and dsa_create_in_place. + */ +static dsa_area * +create_internal(void *place, size_t size, + int tranche_id, + dsm_handle control_handle, + dsm_segment *control_segment) +{ + dsa_area_control *control; + dsa_area *area; + dsa_segment_map *segment_map; + Size usable_pages; + Size total_pages; + Size metadata_bytes; + int i; + + /* Sanity check on the space we have to work in. */ + if (size < dsa_minimum_size()) + elog(ERROR, "dsa_area space must be at least %zu, but %zu provided", + dsa_minimum_size(), size); + + /* Now figure out how much space is usable */ + total_pages = size / FPM_PAGE_SIZE; + metadata_bytes = + MAXALIGN(sizeof(dsa_area_control)) + + MAXALIGN(sizeof(FreePageManager)) + + total_pages * sizeof(dsa_pointer); + /* Add padding up to next page boundary. */ + if (metadata_bytes % FPM_PAGE_SIZE != 0) + metadata_bytes += FPM_PAGE_SIZE - (metadata_bytes % FPM_PAGE_SIZE); + Assert(metadata_bytes <= size); + usable_pages = (size - metadata_bytes) / FPM_PAGE_SIZE; + + /* + * Initialize the dsa_area_control object located at the start of the + * space. + */ + control = (dsa_area_control *) place; + control->segment_header.magic = + DSA_SEGMENT_HEADER_MAGIC ^ control_handle ^ 0; + control->segment_header.next = DSA_SEGMENT_INDEX_NONE; + control->segment_header.prev = DSA_SEGMENT_INDEX_NONE; + control->segment_header.usable_pages = usable_pages; + control->segment_header.freed = false; + control->segment_header.size = DSA_INITIAL_SEGMENT_SIZE; + control->handle = control_handle; + control->max_total_segment_size = (Size) -1; + control->total_segment_size = size; + memset(&control->segment_handles[0], 0, + sizeof(dsm_handle) * DSA_MAX_SEGMENTS); + control->segment_handles[0] = control_handle; + for (i = 0; i < DSA_NUM_SEGMENT_BINS; ++i) + control->segment_bins[i] = DSA_SEGMENT_INDEX_NONE; + control->high_segment_index = 0; + control->refcnt = 1; + control->freed_segment_counter = 0; + control->lwlock_tranche_id = tranche_id; + + /* + * Create the dsa_area object that this backend will use to access the + * area. Other backends will need to obtain their own dsa_area object by + * attaching. + */ + area = palloc(sizeof(dsa_area)); + area->control = control; + area->mapping_pinned = false; + memset(area->segment_maps, 0, sizeof(dsa_segment_map) * DSA_MAX_SEGMENTS); + area->high_segment_index = 0; + LWLockInitialize(&control->lock, control->lwlock_tranche_id); + for (i = 0; i < DSA_NUM_SIZE_CLASSES; ++i) + LWLockInitialize(DSA_SCLASS_LOCK(area, i), + control->lwlock_tranche_id); + + /* Set up the segment map for this process's mapping. */ + segment_map = &area->segment_maps[0]; + segment_map->segment = control_segment; + segment_map->mapped_address = place; + segment_map->header = (dsa_segment_header *) place; + segment_map->fpm = (FreePageManager *) + (segment_map->mapped_address + + MAXALIGN(sizeof(dsa_area_control))); + segment_map->pagemap = (dsa_pointer *) + (segment_map->mapped_address + + MAXALIGN(sizeof(dsa_area_control)) + + MAXALIGN(sizeof(FreePageManager))); + + /* Set up the free page map. */ + FreePageManagerInitialize(segment_map->fpm, segment_map->mapped_address); + /* There can be 0 usable pages if size is dsa_minimum_size(). */ + + if (usable_pages > 0) + FreePageManagerPut(segment_map->fpm, metadata_bytes / FPM_PAGE_SIZE, + usable_pages); + + /* Put this segment into the appropriate bin. */ + control->segment_bins[contiguous_pages_to_segment_bin(usable_pages)] = 0; + segment_map->header->bin = contiguous_pages_to_segment_bin(usable_pages); + + return area; +} + +/* + * Workhorse function for dsa_attach and dsa_attach_in_place. + */ +static dsa_area * +attach_internal(void *place, dsm_segment *segment, dsa_handle handle) +{ + dsa_area_control *control; + dsa_area *area; + dsa_segment_map *segment_map; + + control = (dsa_area_control *) place; + Assert(control->handle == handle); + Assert(control->segment_handles[0] == handle); + Assert(control->segment_header.magic == + (DSA_SEGMENT_HEADER_MAGIC ^ handle ^ 0)); + + /* Build the backend-local area object. */ + area = palloc(sizeof(dsa_area)); + area->control = control; + area->mapping_pinned = false; + memset(&area->segment_maps[0], 0, + sizeof(dsa_segment_map) * DSA_MAX_SEGMENTS); + area->high_segment_index = 0; + + /* Set up the segment map for this process's mapping. */ + segment_map = &area->segment_maps[0]; + segment_map->segment = segment; /* NULL for in-place */ + segment_map->mapped_address = place; + segment_map->header = (dsa_segment_header *) segment_map->mapped_address; + segment_map->fpm = (FreePageManager *) + (segment_map->mapped_address + MAXALIGN(sizeof(dsa_area_control))); + segment_map->pagemap = (dsa_pointer *) + (segment_map->mapped_address + MAXALIGN(sizeof(dsa_area_control)) + + MAXALIGN(sizeof(FreePageManager))); + + /* Bump the reference count. */ + LWLockAcquire(DSA_AREA_LOCK(area), LW_EXCLUSIVE); + ++control->refcnt; + LWLockRelease(DSA_AREA_LOCK(area)); + + return area; +} + +/* + * Add a new span to fullness class 1 of the indicated pool. + */ +static void +init_span(dsa_area *area, + dsa_pointer span_pointer, + dsa_area_pool *pool, dsa_pointer start, Size npages, + uint16 size_class) +{ + dsa_area_span *span = dsa_get_address(area, span_pointer); + Size obsize = dsa_size_classes[size_class]; + + /* + * The per-pool lock must be held because we manipulate the span list for + * this pool. + */ + Assert(LWLockHeldByMe(DSA_SCLASS_LOCK(area, size_class))); + + /* Push this span onto the front of the span list for fullness class 1. */ + if (DsaPointerIsValid(pool->spans[1])) + { + dsa_area_span *head = (dsa_area_span *) + dsa_get_address(area, pool->spans[1]); + + head->prevspan = span_pointer; + } + span->pool = DsaAreaPoolToDsaPointer(area, pool); + span->nextspan = pool->spans[1]; + span->prevspan = InvalidDsaPointer; + pool->spans[1] = span_pointer; + + span->start = start; + span->npages = npages; + span->size_class = size_class; + span->ninitialized = 0; + if (size_class == DSA_SCLASS_BLOCK_OF_SPANS) + { + /* + * A block-of-spans contains its own descriptor, so mark one object as + * initialized and reduce the count of allocatable objects by one. + * Doing this here has the side effect of also reducing nmax by one, + * which is important to make sure we free this object at the correct + * time. + */ + span->ninitialized = 1; + span->nallocatable = FPM_PAGE_SIZE / obsize - 1; + } + else if (size_class != DSA_SCLASS_SPAN_LARGE) + span->nallocatable = DSA_SUPERBLOCK_SIZE / obsize; + span->firstfree = DSA_SPAN_NOTHING_FREE; + span->nmax = span->nallocatable; + span->fclass = 1; +} + +/* + * Transfer the first span in one fullness class to the head of another + * fullness class. + */ +static bool +transfer_first_span(dsa_area *area, + dsa_area_pool *pool, int fromclass, int toclass) +{ + dsa_pointer span_pointer; + dsa_area_span *span; + dsa_area_span *nextspan; + + /* Can't do it if source list is empty. */ + span_pointer = pool->spans[fromclass]; + if (!DsaPointerIsValid(span_pointer)) + return false; + + /* Remove span from head of source list. */ + span = dsa_get_address(area, span_pointer); + pool->spans[fromclass] = span->nextspan; + if (DsaPointerIsValid(span->nextspan)) + { + nextspan = (dsa_area_span *) + dsa_get_address(area, span->nextspan); + nextspan->prevspan = InvalidDsaPointer; + } + + /* Add span to head of target list. */ + span->nextspan = pool->spans[toclass]; + pool->spans[toclass] = span_pointer; + if (DsaPointerIsValid(span->nextspan)) + { + nextspan = (dsa_area_span *) + dsa_get_address(area, span->nextspan); + nextspan->prevspan = span_pointer; + } + span->fclass = toclass; + + return true; +} + +/* + * Allocate one object of the requested size class from the given area. + */ +static inline dsa_pointer +alloc_object(dsa_area *area, int size_class) +{ + dsa_area_pool *pool = &area->control->pools[size_class]; + dsa_area_span *span; + dsa_pointer block; + dsa_pointer result; + char *object; + Size size; + + /* + * Even though ensure_active_superblock can in turn call alloc_object if + * it needs to allocate a new span, that's always from a different pool, + * and the order of lock acquisition is always the same, so it's OK that + * we hold this lock for the duration of this function. + */ + Assert(!LWLockHeldByMe(DSA_SCLASS_LOCK(area, size_class))); + LWLockAcquire(DSA_SCLASS_LOCK(area, size_class), LW_EXCLUSIVE); + + /* + * If there's no active superblock, we must successfully obtain one or + * fail the request. + */ + if (!DsaPointerIsValid(pool->spans[1]) && + !ensure_active_superblock(area, pool, size_class)) + { + result = InvalidDsaPointer; + } + else + { + /* + * There should be a block in fullness class 1 at this point, and it + * should never be completely full. Thus we can either pop an object + * from the free list or, failing that, initialize a new object. + */ + Assert(DsaPointerIsValid(pool->spans[1])); + span = (dsa_area_span *) + dsa_get_address(area, pool->spans[1]); + Assert(span->nallocatable > 0); + block = span->start; + Assert(size_class < DSA_NUM_SIZE_CLASSES); + size = dsa_size_classes[size_class]; + if (span->firstfree != DSA_SPAN_NOTHING_FREE) + { + result = block + span->firstfree * size; + object = dsa_get_address(area, result); + span->firstfree = NextFreeObjectIndex(object); + } + else + { + result = block + span->ninitialized * size; + ++span->ninitialized; + } + --span->nallocatable; + + /* If it's now full, move it to the highest-numbered fullness class. */ + if (span->nallocatable == 0) + transfer_first_span(area, pool, 1, DSA_FULLNESS_CLASSES - 1); + } + + Assert(LWLockHeldByMe(DSA_SCLASS_LOCK(area, size_class))); + LWLockRelease(DSA_SCLASS_LOCK(area, size_class)); + + return result; +} + +/* + * Ensure an active (i.e. fullness class 1) superblock, unless all existing + * superblocks are completely full and no more can be allocated. + * + * Fullness classes K of 0..N are loosely intended to represent blocks whose + * utilization percentage is at least K/N, but we only enforce this rigorously + * for the highest-numbered fullness class, which always contains exactly + * those blocks that are completely full. It's otherwise acceptable for a + * block to be in a higher-numbered fullness class than the one to which it + * logically belongs. In addition, the active block, which is always the + * first block in fullness class 1, is permitted to have a higher allocation + * percentage than would normally be allowable for that fullness class; we + * don't move it until it's completely full, and then it goes to the + * highest-numbered fullness class. + * + * It might seem odd that the active block is the head of fullness class 1 + * rather than fullness class 0, but experience with other allocators has + * shown that it's usually better to allocate from a block that's moderately + * full rather than one that's nearly empty. Insofar as is reasonably + * possible, we want to avoid performing new allocations in a block that would + * otherwise become empty soon. + */ +static bool +ensure_active_superblock(dsa_area *area, dsa_area_pool *pool, + int size_class) +{ + dsa_pointer span_pointer; + dsa_pointer start_pointer; + Size obsize = dsa_size_classes[size_class]; + Size nmax; + int fclass; + Size npages = 1; + Size first_page; + Size i; + dsa_segment_map *segment_map; + + Assert(LWLockHeldByMe(DSA_SCLASS_LOCK(area, size_class))); + + /* + * Compute the number of objects that will fit in a block of this size + * class. Span-of-spans blocks are just a single page, and the first + * object isn't available for use because it describes the block-of-spans + * itself. + */ + if (size_class == DSA_SCLASS_BLOCK_OF_SPANS) + nmax = FPM_PAGE_SIZE / obsize - 1; + else + nmax = DSA_SUPERBLOCK_SIZE / obsize; + + /* + * If fullness class 1 is empty, try to find a span to put in it by + * scanning higher-numbered fullness classes (excluding the last one, + * whose blocks are certain to all be completely full). + */ + for (fclass = 2; fclass < DSA_FULLNESS_CLASSES - 1; ++fclass) + { + span_pointer = pool->spans[fclass]; + + while (DsaPointerIsValid(span_pointer)) + { + int tfclass; + dsa_area_span *span; + dsa_area_span *nextspan; + dsa_area_span *prevspan; + dsa_pointer next_span_pointer; + + span = (dsa_area_span *) + dsa_get_address(area, span_pointer); + next_span_pointer = span->nextspan; + + /* Figure out what fullness class should contain this span. */ + tfclass = (nmax - span->nallocatable) + * (DSA_FULLNESS_CLASSES - 1) / nmax; + + /* Look up next span. */ + if (DsaPointerIsValid(span->nextspan)) + nextspan = (dsa_area_span *) + dsa_get_address(area, span->nextspan); + else + nextspan = NULL; + + /* + * If utilization has dropped enough that this now belongs in some + * other fullness class, move it there. + */ + if (tfclass < fclass) + { + /* Remove from the current fullness class list. */ + if (pool->spans[fclass] == span_pointer) + { + /* It was the head; remove it. */ + Assert(!DsaPointerIsValid(span->prevspan)); + pool->spans[fclass] = span->nextspan; + if (nextspan != NULL) + nextspan->prevspan = InvalidDsaPointer; + } + else + { + /* It was not the head. */ + Assert(DsaPointerIsValid(span->prevspan)); + prevspan = (dsa_area_span *) + dsa_get_address(area, span->prevspan); + prevspan->nextspan = span->nextspan; + } + if (nextspan != NULL) + nextspan->prevspan = span->prevspan; + + /* Push onto the head of the new fullness class list. */ + span->nextspan = pool->spans[tfclass]; + pool->spans[tfclass] = span_pointer; + span->prevspan = InvalidDsaPointer; + if (DsaPointerIsValid(span->nextspan)) + { + nextspan = (dsa_area_span *) + dsa_get_address(area, span->nextspan); + nextspan->prevspan = span_pointer; + } + span->fclass = tfclass; + } + + /* Advance to next span on list. */ + span_pointer = next_span_pointer; + } + + /* Stop now if we found a suitable block. */ + if (DsaPointerIsValid(pool->spans[1])) + return true; + } + + /* + * If there are no blocks that properly belong in fullness class 1, pick + * one from some other fullness class and move it there anyway, so that we + * have an allocation target. Our last choice is to transfer a block + * that's almost empty (and might become completely empty soon if left + * alone), but even that is better than failing, which is what we must do + * if there are no blocks at all with freespace. + */ + Assert(!DsaPointerIsValid(pool->spans[1])); + for (fclass = 2; fclass < DSA_FULLNESS_CLASSES - 1; ++fclass) + if (transfer_first_span(area, pool, fclass, 1)) + return true; + if (!DsaPointerIsValid(pool->spans[1]) && + transfer_first_span(area, pool, 0, 1)) + return true; + + /* + * We failed to find an existing span with free objects, so we need to + * allocate a new superblock and construct a new span to manage it. + * + * First, get a dsa_area_span object to describe the new superblock block + * ... unless this allocation is for a dsa_area_span object, in which case + * that's surely not going to work. We handle that case by storing the + * span describing a block-of-spans inline. + */ + if (size_class != DSA_SCLASS_BLOCK_OF_SPANS) + { + span_pointer = alloc_object(area, DSA_SCLASS_BLOCK_OF_SPANS); + if (!DsaPointerIsValid(span_pointer)) + return false; + npages = DSA_PAGES_PER_SUPERBLOCK; + } + + /* Find or create a segment and allocate the superblock. */ + LWLockAcquire(DSA_AREA_LOCK(area), LW_EXCLUSIVE); + segment_map = get_best_segment(area, npages); + if (segment_map == NULL) + { + segment_map = make_new_segment(area, npages); + if (segment_map == NULL) + { + LWLockRelease(DSA_AREA_LOCK(area)); + return false; + } + } + if (!FreePageManagerGet(segment_map->fpm, npages, &first_page)) + { + LWLockRelease(DSA_AREA_LOCK(area)); + if (size_class != DSA_SCLASS_BLOCK_OF_SPANS) + dsa_free(area, span_pointer); + return false; + } + LWLockRelease(DSA_AREA_LOCK(area)); + + /* Compute the start of the superblock. */ + start_pointer = + DSA_MAKE_POINTER(get_segment_index(area, segment_map), + first_page * FPM_PAGE_SIZE); + + /* + * If this is a block-of-spans, carve the descriptor right out of the + * allocated space. + */ + if (size_class == DSA_SCLASS_BLOCK_OF_SPANS) + { + /* + * We have a pointer into the segment. We need to build a dsa_pointer + * from the segment index and offset into the segment. + */ + span_pointer = start_pointer; + } + + /* Initialize span and pagemap. */ + init_span(area, span_pointer, pool, start_pointer, npages, size_class); + for (i = 0; i < npages; ++i) + segment_map->pagemap[first_page + i] = span_pointer; + + return true; +} + +/* + * Return the segment map corresponding to a given segment index, mapping the + * segment in if necessary. For internal segment book-keeping, this is called + * with the area lock held. It is also called by dsa_free and dsa_get_address + * without any locking, relying on the fact they have a known live segment + * index and they always call check_for_freed_segments to ensures that any + * freed segment occupying the same slot is detached first. + */ +static dsa_segment_map * +get_segment_by_index(dsa_area *area, dsa_segment_index index) +{ + if (unlikely(area->segment_maps[index].mapped_address == NULL)) + { + dsm_handle handle; + dsm_segment *segment; + dsa_segment_map *segment_map; + + /* + * If we are reached by dsa_free or dsa_get_address, there must be at + * least one object allocated in the referenced segment. Otherwise, + * their caller has a double-free or access-after-free bug, which we + * have no hope of detecting. So we know it's safe to access this + * array slot without holding a lock; it won't change underneath us. + * Furthermore, we know that we can see the latest contents of the + * slot, as explained in check_for_freed_segments, which those + * functions call before arriving here. + */ + handle = area->control->segment_handles[index]; + + /* It's an error to try to access an unused slot. */ + if (handle == DSM_HANDLE_INVALID) + elog(ERROR, + "dsa_area could not attach to a segment that has been freed"); + + segment = dsm_attach(handle); + if (segment == NULL) + elog(ERROR, "dsa_area could not attach to segment"); + if (area->mapping_pinned) + dsm_pin_mapping(segment); + segment_map = &area->segment_maps[index]; + segment_map->segment = segment; + segment_map->mapped_address = dsm_segment_address(segment); + segment_map->header = + (dsa_segment_header *) segment_map->mapped_address; + segment_map->fpm = (FreePageManager *) + (segment_map->mapped_address + + MAXALIGN(sizeof(dsa_segment_header))); + segment_map->pagemap = (dsa_pointer *) + (segment_map->mapped_address + + MAXALIGN(sizeof(dsa_segment_header)) + + MAXALIGN(sizeof(FreePageManager))); + + /* Remember the highest index this backend has ever mapped. */ + if (area->high_segment_index < index) + area->high_segment_index = index; + + Assert(segment_map->header->magic == + (DSA_SEGMENT_HEADER_MAGIC ^ area->control->handle ^ index)); + } + + return &area->segment_maps[index]; +} + +/* + * Return a superblock to the free page manager. If the underlying segment + * has become entirely free, then return it to the operating system. + * + * The appropriate pool lock must be held. + */ +static void +destroy_superblock(dsa_area *area, dsa_pointer span_pointer) +{ + dsa_area_span *span = dsa_get_address(area, span_pointer); + int size_class = span->size_class; + dsa_segment_map *segment_map; + + segment_map = + get_segment_by_index(area, DSA_EXTRACT_SEGMENT_NUMBER(span->start)); + + /* Remove it from its fullness class list. */ + unlink_span(area, span); + + /* + * Note: Here we acquire the area lock while we already hold a per-pool + * lock. We never hold the area lock and then take a pool lock, or we + * could deadlock. + */ + LWLockAcquire(DSA_AREA_LOCK(area), LW_EXCLUSIVE); + FreePageManagerPut(segment_map->fpm, + DSA_EXTRACT_OFFSET(span->start) / FPM_PAGE_SIZE, + span->npages); + /* Check if the segment is now entirely free. */ + if (fpm_largest(segment_map->fpm) == segment_map->header->usable_pages) + { + dsa_segment_index index = get_segment_index(area, segment_map); + + /* If it's not the segment with extra control data, free it. */ + if (index != 0) + { + /* + * Give it back to the OS, and allow other backends to detect that + * they need to detach. + */ + unlink_segment(area, segment_map); + segment_map->header->freed = true; + Assert(area->control->total_segment_size >= + segment_map->header->size); + area->control->total_segment_size -= + segment_map->header->size; + dsm_unpin_segment(dsm_segment_handle(segment_map->segment)); + dsm_detach(segment_map->segment); + area->control->segment_handles[index] = DSM_HANDLE_INVALID; + ++area->control->freed_segment_counter; + segment_map->segment = NULL; + segment_map->header = NULL; + segment_map->mapped_address = NULL; + } + } + LWLockRelease(DSA_AREA_LOCK(area)); + + /* + * Span-of-spans blocks store the span which describes them within the + * block itself, so freeing the storage implicitly frees the descriptor + * also. If this is a block of any other type, we need to separately free + * the span object also. This recursive call to dsa_free will acquire the + * span pool's lock. We can't deadlock because the acquisition order is + * always some other pool and then the span pool. + */ + if (size_class != DSA_SCLASS_BLOCK_OF_SPANS) + dsa_free(area, span_pointer); +} + +static void +unlink_span(dsa_area *area, dsa_area_span *span) +{ + if (DsaPointerIsValid(span->nextspan)) + { + dsa_area_span *next = dsa_get_address(area, span->nextspan); + + next->prevspan = span->prevspan; + } + if (DsaPointerIsValid(span->prevspan)) + { + dsa_area_span *prev = dsa_get_address(area, span->prevspan); + + prev->nextspan = span->nextspan; + } + else + { + dsa_area_pool *pool = dsa_get_address(area, span->pool); + + pool->spans[span->fclass] = span->nextspan; + } +} + +static void +add_span_to_fullness_class(dsa_area *area, dsa_area_span *span, + dsa_pointer span_pointer, + int fclass) +{ + dsa_area_pool *pool = dsa_get_address(area, span->pool); + + if (DsaPointerIsValid(pool->spans[fclass])) + { + dsa_area_span *head = dsa_get_address(area, + pool->spans[fclass]); + + head->prevspan = span_pointer; + } + span->prevspan = InvalidDsaPointer; + span->nextspan = pool->spans[fclass]; + pool->spans[fclass] = span_pointer; + span->fclass = fclass; +} + +/* + * Detach from an area that was either created or attached to by this process. + */ +void +dsa_detach(dsa_area *area) +{ + int i; + + /* Detach from all segments. */ + for (i = 0; i <= area->high_segment_index; ++i) + if (area->segment_maps[i].segment != NULL) + dsm_detach(area->segment_maps[i].segment); + + /* + * Note that 'detaching' (= detaching from DSM segments) doesn't include + * 'releasing' (= adjusting the reference count). It would be nice to + * combine these operations, but client code might never get around to + * calling dsa_detach because of an error path, and a detach hook on any + * particular segment is too late to detach other segments in the area + * without risking a 'leak' warning in the non-error path. + */ + + /* Free the backend-local area object. */ + pfree(area); +} + +/* + * Unlink a segment from the bin that contains it. + */ +static void +unlink_segment(dsa_area *area, dsa_segment_map *segment_map) +{ + if (segment_map->header->prev != DSA_SEGMENT_INDEX_NONE) + { + dsa_segment_map *prev; + + prev = get_segment_by_index(area, segment_map->header->prev); + prev->header->next = segment_map->header->next; + } + else + { + Assert(area->control->segment_bins[segment_map->header->bin] == + get_segment_index(area, segment_map)); + area->control->segment_bins[segment_map->header->bin] = + segment_map->header->next; + } + if (segment_map->header->next != DSA_SEGMENT_INDEX_NONE) + { + dsa_segment_map *next; + + next = get_segment_by_index(area, segment_map->header->next); + next->header->prev = segment_map->header->prev; + } +} + +/* + * Find a segment that could satisfy a request for 'npages' of contiguous + * memory, or return NULL if none can be found. This may involve attaching to + * segments that weren't previously attached so that we can query their free + * pages map. + */ +static dsa_segment_map * +get_best_segment(dsa_area *area, Size npages) +{ + Size bin; + + Assert(LWLockHeldByMe(DSA_AREA_LOCK(area))); + + /* + * Start searching from the first bin that *might* have enough contiguous + * pages. + */ + for (bin = contiguous_pages_to_segment_bin(npages); + bin < DSA_NUM_SEGMENT_BINS; + ++bin) + { + /* + * The minimum contiguous size that any segment in this bin should + * have. We'll re-bin if we see segments with fewer. + */ + Size threshold = (Size) 1 << (bin - 1); + dsa_segment_index segment_index; + + /* Search this bin for a segment with enough contiguous space. */ + segment_index = area->control->segment_bins[bin]; + while (segment_index != DSA_SEGMENT_INDEX_NONE) + { + dsa_segment_map *segment_map; + dsa_segment_index next_segment_index; + Size contiguous_pages; + + segment_map = get_segment_by_index(area, segment_index); + next_segment_index = segment_map->header->next; + contiguous_pages = fpm_largest(segment_map->fpm); + + /* Not enough for the request, still enough for this bin. */ + if (contiguous_pages >= threshold && contiguous_pages < npages) + { + segment_index = next_segment_index; + continue; + } + + /* Re-bin it if it's no longer in the appropriate bin. */ + if (contiguous_pages < threshold) + { + Size new_bin; + + new_bin = contiguous_pages_to_segment_bin(contiguous_pages); + + /* Remove it from its current bin. */ + unlink_segment(area, segment_map); + + /* Push it onto the front of its new bin. */ + segment_map->header->prev = DSA_SEGMENT_INDEX_NONE; + segment_map->header->next = + area->control->segment_bins[new_bin]; + segment_map->header->bin = new_bin; + area->control->segment_bins[new_bin] = segment_index; + if (segment_map->header->next != DSA_SEGMENT_INDEX_NONE) + { + dsa_segment_map *next; + + next = get_segment_by_index(area, + segment_map->header->next); + Assert(next->header->bin == new_bin); + next->header->prev = segment_index; + } + + /* + * But fall through to see if it's enough to satisfy this + * request anyway.... + */ + } + + /* Check if we are done. */ + if (contiguous_pages >= npages) + return segment_map; + + /* Continue searching the same bin. */ + segment_index = next_segment_index; + } + } + + /* Not found. */ + return NULL; +} + +/* + * Create a new segment that can handle at least requested_pages. Returns + * NULL if the requested total size limit or maximum allowed number of + * segments would be exceeded. + */ +static dsa_segment_map * +make_new_segment(dsa_area *area, Size requested_pages) +{ + dsa_segment_index new_index; + Size metadata_bytes; + Size total_size; + Size total_pages; + Size usable_pages; + dsa_segment_map *segment_map; + dsm_segment *segment; + + Assert(LWLockHeldByMe(DSA_AREA_LOCK(area))); + + /* Find a segment slot that is not in use (linearly for now). */ + for (new_index = 1; new_index < DSA_MAX_SEGMENTS; ++new_index) + { + if (area->control->segment_handles[new_index] == DSM_HANDLE_INVALID) + break; + } + if (new_index == DSA_MAX_SEGMENTS) + return NULL; + + /* + * If the total size limit is already exceeded, then we exit early and + * avoid arithmetic wraparound in the unsigned expressions below. + */ + if (area->control->total_segment_size >= + area->control->max_total_segment_size) + return NULL; + + /* + * The size should be at least as big as requested, and at least big + * enough to follow a geometric series that approximately doubles the + * total storage each time we create a new segment. We use geometric + * growth because the underlying DSM system isn't designed for large + * numbers of segments (otherwise we might even consider just using one + * DSM segment for each large allocation and for each superblock, and then + * we wouldn't need to use FreePageManager). + * + * We decide on a total segment size first, so that we produce tidy + * power-of-two sized segments. This is a good property to have if we + * move to huge pages in the future. Then we work back to the number of + * pages we can fit. + */ + total_size = DSA_INITIAL_SEGMENT_SIZE * + ((Size) 1 << (new_index / DSA_NUM_SEGMENTS_AT_EACH_SIZE)); + total_size = Min(total_size, DSA_MAX_SEGMENT_SIZE); + total_size = Min(total_size, + area->control->max_total_segment_size - + area->control->total_segment_size); + + total_pages = total_size / FPM_PAGE_SIZE; + metadata_bytes = + MAXALIGN(sizeof(dsa_segment_header)) + + MAXALIGN(sizeof(FreePageManager)) + + sizeof(dsa_pointer) * total_pages; + + /* Add padding up to next page boundary. */ + if (metadata_bytes % FPM_PAGE_SIZE != 0) + metadata_bytes += FPM_PAGE_SIZE - (metadata_bytes % FPM_PAGE_SIZE); + if (total_size <= metadata_bytes) + return NULL; + usable_pages = (total_size - metadata_bytes) / FPM_PAGE_SIZE; + Assert(metadata_bytes + usable_pages * FPM_PAGE_SIZE <= total_size); + + /* See if that is enough... */ + if (requested_pages > usable_pages) + { + /* + * We'll make an odd-sized segment, working forward from the requested + * number of pages. + */ + usable_pages = requested_pages; + metadata_bytes = + MAXALIGN(sizeof(dsa_segment_header)) + + MAXALIGN(sizeof(FreePageManager)) + + usable_pages * sizeof(dsa_pointer); + + /* Add padding up to next page boundary. */ + if (metadata_bytes % FPM_PAGE_SIZE != 0) + metadata_bytes += FPM_PAGE_SIZE - (metadata_bytes % FPM_PAGE_SIZE); + total_size = metadata_bytes + usable_pages * FPM_PAGE_SIZE; + + /* Is that too large for dsa_pointer's addressing scheme? */ + if (total_size > DSA_MAX_SEGMENT_SIZE) + return NULL; + + /* Would that exceed the limit? */ + if (total_size > area->control->max_total_segment_size - + area->control->total_segment_size) + return NULL; + } + + /* Create the segment. */ + segment = dsm_create(total_size, 0); + if (segment == NULL) + return NULL; + dsm_pin_segment(segment); + if (area->mapping_pinned) + dsm_pin_mapping(segment); + + /* Store the handle in shared memory to be found by index. */ + area->control->segment_handles[new_index] = + dsm_segment_handle(segment); + /* Track the highest segment index in the history of the area. */ + if (area->control->high_segment_index < new_index) + area->control->high_segment_index = new_index; + /* Track the highest segment index this backend has ever mapped. */ + if (area->high_segment_index < new_index) + area->high_segment_index = new_index; + /* Track total size of all segments. */ + area->control->total_segment_size += total_size; + Assert(area->control->total_segment_size <= + area->control->max_total_segment_size); + + /* Build a segment map for this segment in this backend. */ + segment_map = &area->segment_maps[new_index]; + segment_map->segment = segment; + segment_map->mapped_address = dsm_segment_address(segment); + segment_map->header = (dsa_segment_header *) segment_map->mapped_address; + segment_map->fpm = (FreePageManager *) + (segment_map->mapped_address + + MAXALIGN(sizeof(dsa_segment_header))); + segment_map->pagemap = (dsa_pointer *) + (segment_map->mapped_address + + MAXALIGN(sizeof(dsa_segment_header)) + + MAXALIGN(sizeof(FreePageManager))); + + /* Set up the free page map. */ + FreePageManagerInitialize(segment_map->fpm, segment_map->mapped_address); + FreePageManagerPut(segment_map->fpm, metadata_bytes / FPM_PAGE_SIZE, + usable_pages); + + /* Set up the segment header and put it in the appropriate bin. */ + segment_map->header->magic = + DSA_SEGMENT_HEADER_MAGIC ^ area->control->handle ^ new_index; + segment_map->header->usable_pages = usable_pages; + segment_map->header->size = total_size; + segment_map->header->bin = contiguous_pages_to_segment_bin(usable_pages); + segment_map->header->prev = DSA_SEGMENT_INDEX_NONE; + segment_map->header->next = + area->control->segment_bins[segment_map->header->bin]; + segment_map->header->freed = false; + area->control->segment_bins[segment_map->header->bin] = new_index; + if (segment_map->header->next != DSA_SEGMENT_INDEX_NONE) + { + dsa_segment_map *next = + get_segment_by_index(area, segment_map->header->next); + + Assert(next->header->bin == segment_map->header->bin); + next->header->prev = new_index; + } + + return segment_map; +} + +/* + * Check if any segments have been freed by destroy_superblock, so we can + * detach from them in this backend. This function is called by + * dsa_get_address and dsa_free to make sure that a dsa_pointer they have + * received can be resolved to the correct segment. + * + * The danger we want to defend against is that there could be an old segment + * mapped into a given slot in this backend, and the dsa_pointer they have + * might refer to some new segment in the same slot. So those functions must + * be sure to process all instructions to detach from a freed segment that had + * been generated by the time this process received the dsa_pointer, before + * they call get_segment_by_index. + */ +static void +check_for_freed_segments(dsa_area *area) +{ + Size freed_segment_counter; + + /* + * Any other process that has freed a segment has incremented + * free_segment_counter while holding an LWLock, and that must precede any + * backend creating a new segment in the same slot while holding an + * LWLock, and that must precede the creation of any dsa_pointer pointing + * into the new segment which might reach us here, and the caller must + * have sent the dsa_pointer to this process using appropriate memory + * synchronization (some kind of locking or atomic primitive or system + * call). So all we need to do on the reading side is ask for the load of + * freed_segment_counter to follow the caller's load of the dsa_pointer it + * has, and we can be sure to detect any segments that had been freed as + * of the time that the dsa_pointer reached this process. + */ + pg_read_barrier(); + freed_segment_counter = area->control->freed_segment_counter; + if (unlikely(area->freed_segment_counter != freed_segment_counter)) + { + int i; + + /* Check all currently mapped segments to find what's been freed. */ + LWLockAcquire(DSA_AREA_LOCK(area), LW_EXCLUSIVE); + for (i = 0; i <= area->high_segment_index; ++i) + { + if (area->segment_maps[i].header != NULL && + area->segment_maps[i].header->freed) + { + dsm_detach(area->segment_maps[i].segment); + area->segment_maps[i].segment = NULL; + area->segment_maps[i].header = NULL; + area->segment_maps[i].mapped_address = NULL; + } + } + LWLockRelease(DSA_AREA_LOCK(area)); + area->freed_segment_counter = freed_segment_counter; + } +} diff --git a/src/backend/utils/mmgr/freepage.c b/src/backend/utils/mmgr/freepage.c new file mode 100644 index 0000000000..230756e0cd --- /dev/null +++ b/src/backend/utils/mmgr/freepage.c @@ -0,0 +1,1886 @@ +/*------------------------------------------------------------------------- + * + * freepage.c + * Management of free memory pages. + * + * The intention of this code is to provide infrastructure for memory + * allocators written specifically for PostgreSQL. At least in the case + * of dynamic shared memory, we can't simply use malloc() or even + * relatively thin wrappers like palloc() which sit on top of it, because + * no allocator built into the operating system will deal with relative + * pointers. In the future, we may find other cases in which greater + * control over our own memory management seems desirable. + * + * A FreePageManager keeps track of which 4kB pages of memory are currently + * unused from the point of view of some higher-level memory allocator. + * Unlike a user-facing allocator such as palloc(), a FreePageManager can + * only allocate and free in units of whole pages, and freeing an + * allocation can only be done given knowledge of its length in pages. + * + * Since a free page manager has only a fixed amount of dedicated memory, + * and since there is no underlying allocator, it uses the free pages + * it is given to manage to store its bookkeeping data. It keeps multiple + * freelists of runs of pages, sorted by the size of the run; the head of + * each freelist is stored in the FreePageManager itself, and the first + * page of each run contains a relative pointer to the next run. See + * FreePageManagerGetInternal for more details on how the freelists are + * managed. + * + * To avoid memory fragmentation, it's important to consolidate adjacent + * spans of pages whenever possible; otherwise, large allocation requests + * might not be satisfied even when sufficient contiguous space is + * available. Therefore, in addition to the freelists, we maintain an + * in-memory btree of free page ranges ordered by page number. If a + * range being freed precedes or follows a range that is already free, + * the existing range is extended; if it exactly bridges the gap between + * free ranges, then the two existing ranges are consolidated with the + * newly-freed range to form one great big range of free pages. + * + * When there is only one range of free pages, the btree is trivial and + * is stored within the FreePageManager proper; otherwise, pages are + * allocated from the area under management as needed. Even in cases + * where memory fragmentation is very severe, only a tiny fraction of + * the pages under management are consumed by this btree. + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/utils/mmgr/freepage.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" +#include "lib/stringinfo.h" +#include "miscadmin.h" + +#include "utils/freepage.h" +#include "utils/relptr.h" + + +/* Magic numbers to identify various page types */ +#define FREE_PAGE_SPAN_LEADER_MAGIC 0xea4020f0 +#define FREE_PAGE_LEAF_MAGIC 0x98eae728 +#define FREE_PAGE_INTERNAL_MAGIC 0x19aa32c9 + +/* Doubly linked list of spans of free pages; stored in first page of span. */ +struct FreePageSpanLeader +{ + int magic; /* always FREE_PAGE_SPAN_LEADER_MAGIC */ + Size npages; /* number of pages in span */ + RelptrFreePageSpanLeader prev; + RelptrFreePageSpanLeader next; +}; + +/* Common header for btree leaf and internal pages. */ +typedef struct FreePageBtreeHeader +{ + int magic; /* FREE_PAGE_LEAF_MAGIC or + * FREE_PAGE_INTERNAL_MAGIC */ + Size nused; /* number of items used */ + RelptrFreePageBtree parent; /* uplink */ +} FreePageBtreeHeader; + +/* Internal key; points to next level of btree. */ +typedef struct FreePageBtreeInternalKey +{ + Size first_page; /* low bound for keys on child page */ + RelptrFreePageBtree child; /* downlink */ +} FreePageBtreeInternalKey; + +/* Leaf key; no payload data. */ +typedef struct FreePageBtreeLeafKey +{ + Size first_page; /* first page in span */ + Size npages; /* number of pages in span */ +} FreePageBtreeLeafKey; + +/* Work out how many keys will fit on a page. */ +#define FPM_ITEMS_PER_INTERNAL_PAGE \ + ((FPM_PAGE_SIZE - sizeof(FreePageBtreeHeader)) / \ + sizeof(FreePageBtreeInternalKey)) +#define FPM_ITEMS_PER_LEAF_PAGE \ + ((FPM_PAGE_SIZE - sizeof(FreePageBtreeHeader)) / \ + sizeof(FreePageBtreeLeafKey)) + +/* A btree page of either sort */ +struct FreePageBtree +{ + FreePageBtreeHeader hdr; + union + { + FreePageBtreeInternalKey internal_key[FPM_ITEMS_PER_INTERNAL_PAGE]; + FreePageBtreeLeafKey leaf_key[FPM_ITEMS_PER_LEAF_PAGE]; + } u; +}; + +/* Results of a btree search */ +typedef struct FreePageBtreeSearchResult +{ + FreePageBtree *page; + Size index; + bool found; + unsigned split_pages; +} FreePageBtreeSearchResult; + +/* Helper functions */ +static void FreePageBtreeAdjustAncestorKeys(FreePageManager *fpm, + FreePageBtree *btp); +static Size FreePageBtreeCleanup(FreePageManager *fpm); +static FreePageBtree *FreePageBtreeFindLeftSibling(char *base, + FreePageBtree *btp); +static FreePageBtree *FreePageBtreeFindRightSibling(char *base, + FreePageBtree *btp); +static Size FreePageBtreeFirstKey(FreePageBtree *btp); +static FreePageBtree *FreePageBtreeGetRecycled(FreePageManager *fpm); +static void FreePageBtreeInsertInternal(char *base, FreePageBtree *btp, + Size index, Size first_page, FreePageBtree *child); +static void FreePageBtreeInsertLeaf(FreePageBtree *btp, Size index, + Size first_page, Size npages); +static void FreePageBtreeRecycle(FreePageManager *fpm, Size pageno); +static void FreePageBtreeRemove(FreePageManager *fpm, FreePageBtree *btp, + Size index); +static void FreePageBtreeRemovePage(FreePageManager *fpm, FreePageBtree *btp); +static void FreePageBtreeSearch(FreePageManager *fpm, Size first_page, + FreePageBtreeSearchResult *result); +static Size FreePageBtreeSearchInternal(FreePageBtree *btp, Size first_page); +static Size FreePageBtreeSearchLeaf(FreePageBtree *btp, Size first_page); +static FreePageBtree *FreePageBtreeSplitPage(FreePageManager *fpm, + FreePageBtree *btp); +static void FreePageBtreeUpdateParentPointers(char *base, FreePageBtree *btp); +static void FreePageManagerDumpBtree(FreePageManager *fpm, FreePageBtree *btp, + FreePageBtree *parent, int level, StringInfo buf); +static void FreePageManagerDumpSpans(FreePageManager *fpm, + FreePageSpanLeader *span, Size expected_pages, + StringInfo buf); +static bool FreePageManagerGetInternal(FreePageManager *fpm, Size npages, + Size *first_page); +static Size FreePageManagerPutInternal(FreePageManager *fpm, Size first_page, + Size npages, bool soft); +static void FreePagePopSpanLeader(FreePageManager *fpm, Size pageno); +static void FreePagePushSpanLeader(FreePageManager *fpm, Size first_page, + Size npages); +static Size FreePageManagerLargestContiguous(FreePageManager *fpm); +static void FreePageManagerUpdateLargest(FreePageManager *fpm); + +#if FPM_EXTRA_ASSERTS +static Size sum_free_pages(FreePageManager *fpm); +#endif + +/* + * Initialize a new, empty free page manager. + * + * 'fpm' should reference caller-provided memory large enough to contain a + * FreePageManager. We'll initialize it here. + * + * 'base' is the address to which all pointers are relative. When managing + * a dynamic shared memory segment, it should normally be the base of the + * segment. When managing backend-private memory, it can be either NULL or, + * if managing a single contiguous extent of memory, the start of that extent. + */ +void +FreePageManagerInitialize(FreePageManager *fpm, char *base) +{ + Size f; + + relptr_store(base, fpm->self, fpm); + relptr_store(base, fpm->btree_root, (FreePageBtree *) NULL); + relptr_store(base, fpm->btree_recycle, (FreePageSpanLeader *) NULL); + fpm->btree_depth = 0; + fpm->btree_recycle_count = 0; + fpm->singleton_first_page = 0; + fpm->singleton_npages = 0; + fpm->contiguous_pages = 0; + fpm->contiguous_pages_dirty = true; +#ifdef FPM_EXTRA_ASSERTS + fpm->free_pages = 0; +#endif + + for (f = 0; f < FPM_NUM_FREELISTS; f++) + relptr_store(base, fpm->freelist[f], (FreePageSpanLeader *) NULL); +} + +/* + * Allocate a run of pages of the given length from the free page manager. + * The return value indicates whether we were able to satisfy the request; + * if true, the first page of the allocation is stored in *first_page. + */ +bool +FreePageManagerGet(FreePageManager *fpm, Size npages, Size *first_page) +{ + bool result; + Size contiguous_pages; + + result = FreePageManagerGetInternal(fpm, npages, first_page); + + /* + * It's a bit counterintuitive, but allocating pages can actually create + * opportunities for cleanup that create larger ranges. We might pull a + * key out of the btree that enables the item at the head of the btree + * recycle list to be inserted; and then if there are more items behind it + * one of those might cause two currently-separated ranges to merge, + * creating a single range of contiguous pages larger than any that + * existed previously. It might be worth trying to improve the cleanup + * algorithm to avoid such corner cases, but for now we just notice the + * condition and do the appropriate reporting. + */ + contiguous_pages = FreePageBtreeCleanup(fpm); + if (fpm->contiguous_pages < contiguous_pages) + fpm->contiguous_pages = contiguous_pages; + + /* + * FreePageManagerGetInternal may have set contiguous_pages_dirty. + * Recompute contigous_pages if so. + */ + FreePageManagerUpdateLargest(fpm); + +#ifdef FPM_EXTRA_ASSERTS + if (result) + { + Assert(fpm->free_pages >= npages); + fpm->free_pages -= npages; + } + Assert(fpm->free_pages == sum_free_pages(fpm)); + Assert(fpm->contiguous_pages == FreePageManagerLargestContiguous(fpm)); +#endif + return result; +} + +#ifdef FPM_EXTRA_ASSERTS +static void +sum_free_pages_recurse(FreePageManager *fpm, FreePageBtree *btp, Size *sum) +{ + char *base = fpm_segment_base(fpm); + + Assert(btp->hdr.magic == FREE_PAGE_INTERNAL_MAGIC || + btp->hdr.magic == FREE_PAGE_LEAF_MAGIC); + ++*sum; + if (btp->hdr.magic == FREE_PAGE_INTERNAL_MAGIC) + { + Size index; + + + for (index = 0; index < btp->hdr.nused; ++index) + { + FreePageBtree *child; + + child = relptr_access(base, btp->u.internal_key[index].child); + sum_free_pages_recurse(fpm, child, sum); + } + } +} +static Size +sum_free_pages(FreePageManager *fpm) +{ + FreePageSpanLeader *recycle; + char *base = fpm_segment_base(fpm); + Size sum = 0; + int list; + + /* Count the spans by scanning the freelists. */ + for (list = 0; list < FPM_NUM_FREELISTS; ++list) + { + + if (!relptr_is_null(fpm->freelist[list])) + { + FreePageSpanLeader *candidate = + relptr_access(base, fpm->freelist[list]); + + do + { + sum += candidate->npages; + candidate = relptr_access(base, candidate->next); + } while (candidate != NULL); + } + } + + /* Count btree internal pages. */ + if (fpm->btree_depth > 0) + { + FreePageBtree *root = relptr_access(base, fpm->btree_root); + + sum_free_pages_recurse(fpm, root, &sum); + } + + /* Count the recycle list. */ + for (recycle = relptr_access(base, fpm->btree_recycle); + recycle != NULL; + recycle = relptr_access(base, recycle->next)) + { + Assert(recycle->npages == 1); + ++sum; + } + + return sum; +} +#endif + +/* + * Compute the size of the largest run of pages that the user could + * succesfully get. + */ +static Size +FreePageManagerLargestContiguous(FreePageManager *fpm) +{ + char *base; + Size largest; + + base = fpm_segment_base(fpm); + largest = 0; + if (!relptr_is_null(fpm->freelist[FPM_NUM_FREELISTS - 1])) + { + FreePageSpanLeader *candidate; + + candidate = relptr_access(base, fpm->freelist[FPM_NUM_FREELISTS - 1]); + do + { + if (candidate->npages > largest) + largest = candidate->npages; + candidate = relptr_access(base, candidate->next); + } while (candidate != NULL); + } + else + { + Size f = FPM_NUM_FREELISTS - 1; + + do + { + --f; + if (!relptr_is_null(fpm->freelist[f])) + { + largest = f + 1; + break; + } + } while (f > 0); + } + + return largest; +} + +/* + * Recompute the size of the largest run of pages that the user could + * succesfully get, if it has been marked dirty. + */ +static void +FreePageManagerUpdateLargest(FreePageManager *fpm) +{ + if (!fpm->contiguous_pages_dirty) + return; + + fpm->contiguous_pages = FreePageManagerLargestContiguous(fpm); + fpm->contiguous_pages_dirty = false; +} + +/* + * Transfer a run of pages to the free page manager. + */ +void +FreePageManagerPut(FreePageManager *fpm, Size first_page, Size npages) +{ + Size contiguous_pages; + + Assert(npages > 0); + + /* Record the new pages. */ + contiguous_pages = + FreePageManagerPutInternal(fpm, first_page, npages, false); + + /* + * If the new range we inserted into the page manager was contiguous with + * an existing range, it may have opened up cleanup opportunities. + */ + if (contiguous_pages > npages) + { + Size cleanup_contiguous_pages; + + cleanup_contiguous_pages = FreePageBtreeCleanup(fpm); + if (cleanup_contiguous_pages > contiguous_pages) + contiguous_pages = cleanup_contiguous_pages; + } + + /* See if we now have a new largest chunk. */ + if (fpm->contiguous_pages < contiguous_pages) + fpm->contiguous_pages = contiguous_pages; + + /* + * The earlier call to FreePageManagerPutInternal may have set + * contiguous_pages_dirty if it needed to allocate internal pages, so + * recompute contiguous_pages if necessary. + */ + FreePageManagerUpdateLargest(fpm); + +#ifdef FPM_EXTRA_ASSERTS + fpm->free_pages += npages; + Assert(fpm->free_pages == sum_free_pages(fpm)); + Assert(fpm->contiguous_pages == FreePageManagerLargestContiguous(fpm)); +#endif +} + +/* + * Produce a debugging dump of the state of a free page manager. + */ +char * +FreePageManagerDump(FreePageManager *fpm) +{ + char *base = fpm_segment_base(fpm); + StringInfoData buf; + FreePageSpanLeader *recycle; + bool dumped_any_freelist = false; + Size f; + + /* Initialize output buffer. */ + initStringInfo(&buf); + + /* Dump general stuff. */ + appendStringInfo(&buf, "metadata: self %zu max contiguous pages = %zu\n", + fpm->self.relptr_off, fpm->contiguous_pages); + + /* Dump btree. */ + if (fpm->btree_depth > 0) + { + FreePageBtree *root; + + appendStringInfo(&buf, "btree depth %u:\n", fpm->btree_depth); + root = relptr_access(base, fpm->btree_root); + FreePageManagerDumpBtree(fpm, root, NULL, 0, &buf); + } + else if (fpm->singleton_npages > 0) + { + appendStringInfo(&buf, "singleton: %zu(%zu)\n", + fpm->singleton_first_page, fpm->singleton_npages); + } + + /* Dump btree recycle list. */ + recycle = relptr_access(base, fpm->btree_recycle); + if (recycle != NULL) + { + appendStringInfo(&buf, "btree recycle:"); + FreePageManagerDumpSpans(fpm, recycle, 1, &buf); + } + + /* Dump free lists. */ + for (f = 0; f < FPM_NUM_FREELISTS; ++f) + { + FreePageSpanLeader *span; + + if (relptr_is_null(fpm->freelist[f])) + continue; + if (!dumped_any_freelist) + { + appendStringInfo(&buf, "freelists:\n"); + dumped_any_freelist = true; + } + appendStringInfo(&buf, " %zu:", f + 1); + span = relptr_access(base, fpm->freelist[f]); + FreePageManagerDumpSpans(fpm, span, f + 1, &buf); + } + + /* And return result to caller. */ + return buf.data; +} + + +/* + * The first_page value stored at index zero in any non-root page must match + * the first_page value stored in its parent at the index which points to that + * page. So when the value stored at index zero in a btree page changes, we've + * got to walk up the tree adjusting ancestor keys until we reach an ancestor + * where that key isn't index zero. This function should be called after + * updating the first key on the target page; it will propagate the change + * upward as far as needed. + * + * We assume here that the first key on the page has not changed enough to + * require changes in the ordering of keys on its ancestor pages. Thus, + * if we search the parent page for the first key greater than or equal to + * the first key on the current page, the downlink to this page will be either + * the exact index returned by the search (if the first key decreased) + * or one less (if the first key increased). + */ +static void +FreePageBtreeAdjustAncestorKeys(FreePageManager *fpm, FreePageBtree *btp) +{ + char *base = fpm_segment_base(fpm); + Size first_page; + FreePageBtree *parent; + FreePageBtree *child; + + /* This might be either a leaf or an internal page. */ + Assert(btp->hdr.nused > 0); + if (btp->hdr.magic == FREE_PAGE_LEAF_MAGIC) + { + Assert(btp->hdr.nused <= FPM_ITEMS_PER_LEAF_PAGE); + first_page = btp->u.leaf_key[0].first_page; + } + else + { + Assert(btp->hdr.magic == FREE_PAGE_INTERNAL_MAGIC); + Assert(btp->hdr.nused <= FPM_ITEMS_PER_INTERNAL_PAGE); + first_page = btp->u.internal_key[0].first_page; + } + child = btp; + + /* Loop until we find an ancestor that does not require adjustment. */ + for (;;) + { + Size s; + + parent = relptr_access(base, child->hdr.parent); + if (parent == NULL) + break; + s = FreePageBtreeSearchInternal(parent, first_page); + + /* Key is either at index s or index s-1; figure out which. */ + if (s >= parent->hdr.nused) + { + Assert(s == parent->hdr.nused); + --s; + } + else + { + FreePageBtree *check; + + check = relptr_access(base, parent->u.internal_key[s].child); + if (check != child) + { + Assert(s > 0); + --s; + } + } + +#ifdef USE_ASSERT_CHECKING + /* Debugging double-check. */ + { + FreePageBtree *check; + + check = relptr_access(base, parent->u.internal_key[s].child); + Assert(s < parent->hdr.nused); + Assert(child == check); + } +#endif + + /* Update the parent key. */ + parent->u.internal_key[s].first_page = first_page; + + /* + * If this is the first key in the parent, go up another level; else + * done. + */ + if (s > 0) + break; + child = parent; + } +} + +/* + * Attempt to reclaim space from the free-page btree. The return value is + * the largest range of contiguous pages created by the cleanup operation. + */ +static Size +FreePageBtreeCleanup(FreePageManager *fpm) +{ + char *base = fpm_segment_base(fpm); + Size max_contiguous_pages = 0; + + /* Attempt to shrink the depth of the btree. */ + while (!relptr_is_null(fpm->btree_root)) + { + FreePageBtree *root = relptr_access(base, fpm->btree_root); + + /* If the root contains only one key, reduce depth by one. */ + if (root->hdr.nused == 1) + { + /* Shrink depth of tree by one. */ + Assert(fpm->btree_depth > 0); + --fpm->btree_depth; + if (root->hdr.magic == FREE_PAGE_LEAF_MAGIC) + { + /* If root is a leaf, convert only entry to singleton range. */ + relptr_store(base, fpm->btree_root, (FreePageBtree *) NULL); + fpm->singleton_first_page = root->u.leaf_key[0].first_page; + fpm->singleton_npages = root->u.leaf_key[0].npages; + } + else + { + FreePageBtree *newroot; + + /* If root is an internal page, make only child the root. */ + Assert(root->hdr.magic == FREE_PAGE_INTERNAL_MAGIC); + relptr_copy(fpm->btree_root, root->u.internal_key[0].child); + newroot = relptr_access(base, fpm->btree_root); + relptr_store(base, newroot->hdr.parent, (FreePageBtree *) NULL); + } + FreePageBtreeRecycle(fpm, fpm_pointer_to_page(base, root)); + } + else if (root->hdr.nused == 2 && + root->hdr.magic == FREE_PAGE_LEAF_MAGIC) + { + Size end_of_first; + Size start_of_second; + + end_of_first = root->u.leaf_key[0].first_page + + root->u.leaf_key[0].npages; + start_of_second = root->u.leaf_key[1].first_page; + + if (end_of_first + 1 == start_of_second) + { + Size root_page = fpm_pointer_to_page(base, root); + + if (end_of_first == root_page) + { + FreePagePopSpanLeader(fpm, root->u.leaf_key[0].first_page); + FreePagePopSpanLeader(fpm, root->u.leaf_key[1].first_page); + fpm->singleton_first_page = root->u.leaf_key[0].first_page; + fpm->singleton_npages = root->u.leaf_key[0].npages + + root->u.leaf_key[1].npages + 1; + fpm->btree_depth = 0; + relptr_store(base, fpm->btree_root, + (FreePageBtree *) NULL); + FreePagePushSpanLeader(fpm, fpm->singleton_first_page, + fpm->singleton_npages); + Assert(max_contiguous_pages == 0); + max_contiguous_pages = fpm->singleton_npages; + } + } + + /* Whether it worked or not, it's time to stop. */ + break; + } + else + { + /* Nothing more to do. Stop. */ + break; + } + } + + /* + * Attempt to free recycled btree pages. We skip this if releasing the + * recycled page would require a btree page split, because the page we're + * trying to recycle would be consumed by the split, which would be + * counterproductive. + * + * We also currently only ever attempt to recycle the first page on the + * list; that could be made more aggressive, but it's not clear that the + * complexity would be worthwhile. + */ + while (fpm->btree_recycle_count > 0) + { + FreePageBtree *btp; + Size first_page; + Size contiguous_pages; + + btp = FreePageBtreeGetRecycled(fpm); + first_page = fpm_pointer_to_page(base, btp); + contiguous_pages = FreePageManagerPutInternal(fpm, first_page, 1, true); + if (contiguous_pages == 0) + { + FreePageBtreeRecycle(fpm, first_page); + break; + } + else + { + if (contiguous_pages > max_contiguous_pages) + max_contiguous_pages = contiguous_pages; + } + } + + return max_contiguous_pages; +} + +/* + * Consider consolidating the given page with its left or right sibling, + * if it's fairly empty. + */ +static void +FreePageBtreeConsolidate(FreePageManager *fpm, FreePageBtree *btp) +{ + char *base = fpm_segment_base(fpm); + FreePageBtree *np; + Size max; + + /* + * We only try to consolidate pages that are less than a third full. We + * could be more aggressive about this, but that might risk performing + * consolidation only to end up splitting again shortly thereafter. Since + * the btree should be very small compared to the space under management, + * our goal isn't so much to ensure that it always occupies the absolutely + * smallest possible number of pages as to reclaim pages before things get + * too egregiously out of hand. + */ + if (btp->hdr.magic == FREE_PAGE_LEAF_MAGIC) + max = FPM_ITEMS_PER_LEAF_PAGE; + else + { + Assert(btp->hdr.magic == FREE_PAGE_INTERNAL_MAGIC); + max = FPM_ITEMS_PER_INTERNAL_PAGE; + } + if (btp->hdr.nused >= max / 3) + return; + + /* + * If we can fit our right sibling's keys onto this page, consolidate. + */ + np = FreePageBtreeFindRightSibling(base, btp); + if (np != NULL && btp->hdr.nused + np->hdr.nused <= max) + { + if (btp->hdr.magic == FREE_PAGE_LEAF_MAGIC) + { + memcpy(&btp->u.leaf_key[btp->hdr.nused], &np->u.leaf_key[0], + sizeof(FreePageBtreeLeafKey) * np->hdr.nused); + btp->hdr.nused += np->hdr.nused; + } + else + { + memcpy(&btp->u.internal_key[btp->hdr.nused], &np->u.internal_key[0], + sizeof(FreePageBtreeInternalKey) * np->hdr.nused); + btp->hdr.nused += np->hdr.nused; + FreePageBtreeUpdateParentPointers(base, btp); + } + FreePageBtreeRemovePage(fpm, np); + return; + } + + /* + * If we can fit our keys onto our left sibling's page, consolidate. In + * this case, we move our keys onto the other page rather than visca + * versa, to avoid having to adjust ancestor keys. + */ + np = FreePageBtreeFindLeftSibling(base, btp); + if (np != NULL && btp->hdr.nused + np->hdr.nused <= max) + { + if (btp->hdr.magic == FREE_PAGE_LEAF_MAGIC) + { + memcpy(&np->u.leaf_key[np->hdr.nused], &btp->u.leaf_key[0], + sizeof(FreePageBtreeLeafKey) * btp->hdr.nused); + np->hdr.nused += btp->hdr.nused; + } + else + { + memcpy(&np->u.internal_key[np->hdr.nused], &btp->u.internal_key[0], + sizeof(FreePageBtreeInternalKey) * btp->hdr.nused); + np->hdr.nused += btp->hdr.nused; + FreePageBtreeUpdateParentPointers(base, np); + } + FreePageBtreeRemovePage(fpm, btp); + return; + } +} + +/* + * Find the passed page's left sibling; that is, the page at the same level + * of the tree whose keyspace immediately precedes ours. + */ +static FreePageBtree * +FreePageBtreeFindLeftSibling(char *base, FreePageBtree *btp) +{ + FreePageBtree *p = btp; + int levels = 0; + + /* Move up until we can move left. */ + for (;;) + { + Size first_page; + Size index; + + first_page = FreePageBtreeFirstKey(p); + p = relptr_access(base, p->hdr.parent); + + if (p == NULL) + return NULL; /* we were passed the rightmost page */ + + index = FreePageBtreeSearchInternal(p, first_page); + if (index > 0) + { + Assert(p->u.internal_key[index].first_page == first_page); + p = relptr_access(base, p->u.internal_key[index - 1].child); + break; + } + Assert(index == 0); + ++levels; + } + + /* Descend left. */ + while (levels > 0) + { + Assert(p->hdr.magic == FREE_PAGE_INTERNAL_MAGIC); + p = relptr_access(base, p->u.internal_key[p->hdr.nused - 1].child); + --levels; + } + Assert(p->hdr.magic == btp->hdr.magic); + + return p; +} + +/* + * Find the passed page's right sibling; that is, the page at the same level + * of the tree whose keyspace immediately follows ours. + */ +static FreePageBtree * +FreePageBtreeFindRightSibling(char *base, FreePageBtree *btp) +{ + FreePageBtree *p = btp; + int levels = 0; + + /* Move up until we can move right. */ + for (;;) + { + Size first_page; + Size index; + + first_page = FreePageBtreeFirstKey(p); + p = relptr_access(base, p->hdr.parent); + + if (p == NULL) + return NULL; /* we were passed the rightmost page */ + + index = FreePageBtreeSearchInternal(p, first_page); + if (index < p->hdr.nused - 1) + { + Assert(p->u.internal_key[index].first_page == first_page); + p = relptr_access(base, p->u.internal_key[index + 1].child); + break; + } + Assert(index == p->hdr.nused - 1); + ++levels; + } + + /* Descend left. */ + while (levels > 0) + { + Assert(p->hdr.magic == FREE_PAGE_INTERNAL_MAGIC); + p = relptr_access(base, p->u.internal_key[0].child); + --levels; + } + Assert(p->hdr.magic == btp->hdr.magic); + + return p; +} + +/* + * Get the first key on a btree page. + */ +static Size +FreePageBtreeFirstKey(FreePageBtree *btp) +{ + Assert(btp->hdr.nused > 0); + + if (btp->hdr.magic == FREE_PAGE_LEAF_MAGIC) + return btp->u.leaf_key[0].first_page; + else + { + Assert(btp->hdr.magic == FREE_PAGE_INTERNAL_MAGIC); + return btp->u.internal_key[0].first_page; + } +} + +/* + * Get a page from the btree recycle list for use as a btree page. + */ +static FreePageBtree * +FreePageBtreeGetRecycled(FreePageManager *fpm) +{ + char *base = fpm_segment_base(fpm); + FreePageSpanLeader *victim = relptr_access(base, fpm->btree_recycle); + FreePageSpanLeader *newhead; + + Assert(victim != NULL); + newhead = relptr_access(base, victim->next); + if (newhead != NULL) + relptr_copy(newhead->prev, victim->prev); + relptr_store(base, fpm->btree_recycle, newhead); + Assert(fpm_pointer_is_page_aligned(base, victim)); + fpm->btree_recycle_count--; + return (FreePageBtree *) victim; +} + +/* + * Insert an item into an internal page. + */ +static void +FreePageBtreeInsertInternal(char *base, FreePageBtree *btp, Size index, + Size first_page, FreePageBtree *child) +{ + Assert(btp->hdr.magic == FREE_PAGE_INTERNAL_MAGIC); + Assert(btp->hdr.nused <= FPM_ITEMS_PER_INTERNAL_PAGE); + Assert(index <= btp->hdr.nused); + memmove(&btp->u.internal_key[index + 1], &btp->u.internal_key[index], + sizeof(FreePageBtreeInternalKey) * (btp->hdr.nused - index)); + btp->u.internal_key[index].first_page = first_page; + relptr_store(base, btp->u.internal_key[index].child, child); + ++btp->hdr.nused; +} + +/* + * Insert an item into a leaf page. + */ +static void +FreePageBtreeInsertLeaf(FreePageBtree *btp, Size index, Size first_page, + Size npages) +{ + Assert(btp->hdr.magic == FREE_PAGE_LEAF_MAGIC); + Assert(btp->hdr.nused <= FPM_ITEMS_PER_LEAF_PAGE); + Assert(index <= btp->hdr.nused); + memmove(&btp->u.leaf_key[index + 1], &btp->u.leaf_key[index], + sizeof(FreePageBtreeLeafKey) * (btp->hdr.nused - index)); + btp->u.leaf_key[index].first_page = first_page; + btp->u.leaf_key[index].npages = npages; + ++btp->hdr.nused; +} + +/* + * Put a page on the btree recycle list. + */ +static void +FreePageBtreeRecycle(FreePageManager *fpm, Size pageno) +{ + char *base = fpm_segment_base(fpm); + FreePageSpanLeader *head = relptr_access(base, fpm->btree_recycle); + FreePageSpanLeader *span; + + span = (FreePageSpanLeader *) fpm_page_to_pointer(base, pageno); + span->magic = FREE_PAGE_SPAN_LEADER_MAGIC; + span->npages = 1; + relptr_store(base, span->next, head); + relptr_store(base, span->prev, (FreePageSpanLeader *) NULL); + if (head != NULL) + relptr_store(base, head->prev, span); + relptr_store(base, fpm->btree_recycle, span); + fpm->btree_recycle_count++; +} + +/* + * Remove an item from the btree at the given position on the given page. + */ +static void +FreePageBtreeRemove(FreePageManager *fpm, FreePageBtree *btp, Size index) +{ + Assert(btp->hdr.magic == FREE_PAGE_LEAF_MAGIC); + Assert(index < btp->hdr.nused); + + /* When last item is removed, extirpate entire page from btree. */ + if (btp->hdr.nused == 1) + { + FreePageBtreeRemovePage(fpm, btp); + return; + } + + /* Physically remove the key from the page. */ + --btp->hdr.nused; + if (index < btp->hdr.nused) + memmove(&btp->u.leaf_key[index], &btp->u.leaf_key[index + 1], + sizeof(FreePageBtreeLeafKey) * (btp->hdr.nused - index)); + + /* If we just removed the first key, adjust ancestor keys. */ + if (index == 0) + FreePageBtreeAdjustAncestorKeys(fpm, btp); + + /* Consider whether to consolidate this page with a sibling. */ + FreePageBtreeConsolidate(fpm, btp); +} + +/* + * Remove a page from the btree. Caller is responsible for having relocated + * any keys from this page that are still wanted. The page is placed on the + * recycled list. + */ +static void +FreePageBtreeRemovePage(FreePageManager *fpm, FreePageBtree *btp) +{ + char *base = fpm_segment_base(fpm); + FreePageBtree *parent; + Size index; + Size first_page; + + for (;;) + { + /* Find parent page. */ + parent = relptr_access(base, btp->hdr.parent); + if (parent == NULL) + { + /* We are removing the root page. */ + relptr_store(base, fpm->btree_root, (FreePageBtree *) NULL); + fpm->btree_depth = 0; + Assert(fpm->singleton_first_page == 0); + Assert(fpm->singleton_npages == 0); + return; + } + + /* + * If the parent contains only one item, we need to remove it as well. + */ + if (parent->hdr.nused > 1) + break; + FreePageBtreeRecycle(fpm, fpm_pointer_to_page(base, btp)); + btp = parent; + } + + /* Find and remove the downlink. */ + first_page = FreePageBtreeFirstKey(btp); + if (parent->hdr.magic == FREE_PAGE_LEAF_MAGIC) + { + index = FreePageBtreeSearchLeaf(parent, first_page); + Assert(index < parent->hdr.nused); + if (index < parent->hdr.nused - 1) + memmove(&parent->u.leaf_key[index], + &parent->u.leaf_key[index + 1], + sizeof(FreePageBtreeLeafKey) + * (parent->hdr.nused - index - 1)); + } + else + { + index = FreePageBtreeSearchInternal(parent, first_page); + Assert(index < parent->hdr.nused); + if (index < parent->hdr.nused - 1) + memmove(&parent->u.internal_key[index], + &parent->u.internal_key[index + 1], + sizeof(FreePageBtreeInternalKey) + * (parent->hdr.nused - index - 1)); + } + parent->hdr.nused--; + Assert(parent->hdr.nused > 0); + + /* Recycle the page. */ + FreePageBtreeRecycle(fpm, fpm_pointer_to_page(base, btp)); + + /* Adjust ancestor keys if needed. */ + if (index == 0) + FreePageBtreeAdjustAncestorKeys(fpm, parent); + + /* Consider whether to consolidate the parent with a sibling. */ + FreePageBtreeConsolidate(fpm, parent); +} + +/* + * Search the btree for an entry for the given first page and initialize + * *result with the results of the search. result->page and result->index + * indicate either the position of an exact match or the position at which + * the new key should be inserted. result->found is true for an exact match, + * otherwise false. result->split_pages will contain the number of additional + * btree pages that will be needed when performing a split to insert a key. + * Except as described above, the contents of fields in the result object are + * undefined on return. + */ +static void +FreePageBtreeSearch(FreePageManager *fpm, Size first_page, + FreePageBtreeSearchResult *result) +{ + char *base = fpm_segment_base(fpm); + FreePageBtree *btp = relptr_access(base, fpm->btree_root); + Size index; + + result->split_pages = 1; + + /* If the btree is empty, there's nothing to find. */ + if (btp == NULL) + { + result->page = NULL; + result->found = false; + return; + } + + /* Descend until we hit a leaf. */ + while (btp->hdr.magic == FREE_PAGE_INTERNAL_MAGIC) + { + FreePageBtree *child; + bool found_exact; + + index = FreePageBtreeSearchInternal(btp, first_page); + found_exact = index < btp->hdr.nused && + btp->u.internal_key[index].first_page == first_page; + + /* + * If we found an exact match we descend directly. Otherwise, we + * descend into the child to the left if possible so that we can find + * the insertion point at that child's high end. + */ + if (!found_exact && index > 0) + --index; + + /* Track required split depth for leaf insert. */ + if (btp->hdr.nused >= FPM_ITEMS_PER_INTERNAL_PAGE) + { + Assert(btp->hdr.nused == FPM_ITEMS_PER_INTERNAL_PAGE); + result->split_pages++; + } + else + result->split_pages = 0; + + /* Descend to appropriate child page. */ + Assert(index < btp->hdr.nused); + child = relptr_access(base, btp->u.internal_key[index].child); + Assert(relptr_access(base, child->hdr.parent) == btp); + btp = child; + } + + /* Track required split depth for leaf insert. */ + if (btp->hdr.nused >= FPM_ITEMS_PER_LEAF_PAGE) + { + Assert(btp->hdr.nused == FPM_ITEMS_PER_INTERNAL_PAGE); + result->split_pages++; + } + else + result->split_pages = 0; + + /* Search leaf page. */ + index = FreePageBtreeSearchLeaf(btp, first_page); + + /* Assemble results. */ + result->page = btp; + result->index = index; + result->found = index < btp->hdr.nused && + first_page == btp->u.leaf_key[index].first_page; +} + +/* + * Search an internal page for the first key greater than or equal to a given + * page number. Returns the index of that key, or one greater than the number + * of keys on the page if none. + */ +static Size +FreePageBtreeSearchInternal(FreePageBtree *btp, Size first_page) +{ + Size low = 0; + Size high = btp->hdr.nused; + + Assert(btp->hdr.magic == FREE_PAGE_INTERNAL_MAGIC); + Assert(high > 0 && high <= FPM_ITEMS_PER_INTERNAL_PAGE); + + while (low < high) + { + Size mid = (low + high) / 2; + Size val = btp->u.internal_key[mid].first_page; + + if (first_page == val) + return mid; + else if (first_page < val) + high = mid; + else + low = mid + 1; + } + + return low; +} + +/* + * Search a leaf page for the first key greater than or equal to a given + * page number. Returns the index of that key, or one greater than the number + * of keys on the page if none. + */ +static Size +FreePageBtreeSearchLeaf(FreePageBtree *btp, Size first_page) +{ + Size low = 0; + Size high = btp->hdr.nused; + + Assert(btp->hdr.magic == FREE_PAGE_LEAF_MAGIC); + Assert(high > 0 && high <= FPM_ITEMS_PER_LEAF_PAGE); + + while (low < high) + { + Size mid = (low + high) / 2; + Size val = btp->u.leaf_key[mid].first_page; + + if (first_page == val) + return mid; + else if (first_page < val) + high = mid; + else + low = mid + 1; + } + + return low; +} + +/* + * Allocate a new btree page and move half the keys from the provided page + * to the new page. Caller is responsible for making sure that there's a + * page available from fpm->btree_recycle. Returns a pointer to the new page, + * to which caller must add a downlink. + */ +static FreePageBtree * +FreePageBtreeSplitPage(FreePageManager *fpm, FreePageBtree *btp) +{ + FreePageBtree *newsibling; + + newsibling = FreePageBtreeGetRecycled(fpm); + newsibling->hdr.magic = btp->hdr.magic; + newsibling->hdr.nused = btp->hdr.nused / 2; + relptr_copy(newsibling->hdr.parent, btp->hdr.parent); + btp->hdr.nused -= newsibling->hdr.nused; + + if (btp->hdr.magic == FREE_PAGE_LEAF_MAGIC) + memcpy(&newsibling->u.leaf_key, + &btp->u.leaf_key[btp->hdr.nused], + sizeof(FreePageBtreeLeafKey) * newsibling->hdr.nused); + else + { + Assert(btp->hdr.magic == FREE_PAGE_INTERNAL_MAGIC); + memcpy(&newsibling->u.internal_key, + &btp->u.internal_key[btp->hdr.nused], + sizeof(FreePageBtreeInternalKey) * newsibling->hdr.nused); + FreePageBtreeUpdateParentPointers(fpm_segment_base(fpm), newsibling); + } + + return newsibling; +} + +/* + * When internal pages are split or merged, the parent pointers of their + * children must be updated. + */ +static void +FreePageBtreeUpdateParentPointers(char *base, FreePageBtree *btp) +{ + Size i; + + Assert(btp->hdr.magic == FREE_PAGE_INTERNAL_MAGIC); + for (i = 0; i < btp->hdr.nused; ++i) + { + FreePageBtree *child; + + child = relptr_access(base, btp->u.internal_key[i].child); + relptr_store(base, child->hdr.parent, btp); + } +} + +/* + * Debugging dump of btree data. + */ +static void +FreePageManagerDumpBtree(FreePageManager *fpm, FreePageBtree *btp, + FreePageBtree *parent, int level, StringInfo buf) +{ + char *base = fpm_segment_base(fpm); + Size pageno = fpm_pointer_to_page(base, btp); + Size index; + FreePageBtree *check_parent; + + check_stack_depth(); + check_parent = relptr_access(base, btp->hdr.parent); + appendStringInfo(buf, " %zu@%d %c", pageno, level, + btp->hdr.magic == FREE_PAGE_INTERNAL_MAGIC ? 'i' : 'l'); + if (parent != check_parent) + appendStringInfo(buf, " [actual parent %zu, expected %zu]", + fpm_pointer_to_page(base, check_parent), + fpm_pointer_to_page(base, parent)); + appendStringInfoChar(buf, ':'); + for (index = 0; index < btp->hdr.nused; ++index) + { + if (btp->hdr.magic == FREE_PAGE_INTERNAL_MAGIC) + appendStringInfo(buf, " %zu->%zu", + btp->u.internal_key[index].first_page, + btp->u.internal_key[index].child.relptr_off / FPM_PAGE_SIZE); + else + appendStringInfo(buf, " %zu(%zu)", + btp->u.leaf_key[index].first_page, + btp->u.leaf_key[index].npages); + } + appendStringInfo(buf, "\n"); + + if (btp->hdr.magic == FREE_PAGE_INTERNAL_MAGIC) + { + for (index = 0; index < btp->hdr.nused; ++index) + { + FreePageBtree *child; + + child = relptr_access(base, btp->u.internal_key[index].child); + FreePageManagerDumpBtree(fpm, child, btp, level + 1, buf); + } + } +} + +/* + * Debugging dump of free-span data. + */ +static void +FreePageManagerDumpSpans(FreePageManager *fpm, FreePageSpanLeader *span, + Size expected_pages, StringInfo buf) +{ + char *base = fpm_segment_base(fpm); + + while (span != NULL) + { + if (span->npages != expected_pages) + appendStringInfo(buf, " %zu(%zu)", fpm_pointer_to_page(base, span), + span->npages); + else + appendStringInfo(buf, " %zu", fpm_pointer_to_page(base, span)); + span = relptr_access(base, span->next); + } + + appendStringInfo(buf, "\n"); +} + +/* + * This function allocates a run of pages of the given length from the free + * page manager. + */ +static bool +FreePageManagerGetInternal(FreePageManager *fpm, Size npages, Size *first_page) +{ + char *base = fpm_segment_base(fpm); + FreePageSpanLeader *victim = NULL; + FreePageSpanLeader *prev; + FreePageSpanLeader *next; + FreePageBtreeSearchResult result; + Size victim_page = 0; /* placate compiler */ + Size f; + + /* + * Search for a free span. + * + * Right now, we use a simple best-fit policy here, but it's possible for + * this to result in memory fragmentation if we're repeatedly asked to + * allocate chunks just a little smaller than what we have available. + * Hopefully, this is unlikely, because we expect most requests to be + * single pages or superblock-sized chunks -- but no policy can be optimal + * under all circumstances unless it has knowledge of future allocation + * patterns. + */ + for (f = Min(npages, FPM_NUM_FREELISTS) - 1; f < FPM_NUM_FREELISTS; ++f) + { + /* Skip empty freelists. */ + if (relptr_is_null(fpm->freelist[f])) + continue; + + /* + * All of the freelists except the last one contain only items of a + * single size, so we just take the first one. But the final free + * list contains everything too big for any of the other lists, so we + * need to search the list. + */ + if (f < FPM_NUM_FREELISTS - 1) + victim = relptr_access(base, fpm->freelist[f]); + else + { + FreePageSpanLeader *candidate; + + candidate = relptr_access(base, fpm->freelist[f]); + do + { + if (candidate->npages >= npages && (victim == NULL || + victim->npages > candidate->npages)) + { + victim = candidate; + if (victim->npages == npages) + break; + } + candidate = relptr_access(base, candidate->next); + } while (candidate != NULL); + } + break; + } + + /* If we didn't find an allocatable span, return failure. */ + if (victim == NULL) + return false; + + /* Remove span from free list. */ + Assert(victim->magic == FREE_PAGE_SPAN_LEADER_MAGIC); + prev = relptr_access(base, victim->prev); + next = relptr_access(base, victim->next); + if (prev != NULL) + relptr_copy(prev->next, victim->next); + else + relptr_copy(fpm->freelist[f], victim->next); + if (next != NULL) + relptr_copy(next->prev, victim->prev); + victim_page = fpm_pointer_to_page(base, victim); + + /* Decide whether we might be invalidating contiguous_pages. */ + if (f == FPM_NUM_FREELISTS - 1 && + victim->npages == fpm->contiguous_pages) + { + /* + * The victim span came from the oversized freelist, and had the same + * size as the longest span. There may or may not be another one of + * the same size, so contiguous_pages must be recomputed just to be + * safe. + */ + fpm->contiguous_pages_dirty = true; + } + else if (f + 1 == fpm->contiguous_pages && + relptr_is_null(fpm->freelist[f])) + { + /* + * The victim span came from a fixed sized freelist, and it was the + * list for spans of the same size as the current longest span, and + * the list is now empty after removing the victim. So + * contiguous_pages must be recomputed without a doubt. + */ + fpm->contiguous_pages_dirty = true; + } + + /* + * If we haven't initialized the btree yet, the victim must be the single + * span stored within the FreePageManager itself. Otherwise, we need to + * update the btree. + */ + if (relptr_is_null(fpm->btree_root)) + { + Assert(victim_page == fpm->singleton_first_page); + Assert(victim->npages == fpm->singleton_npages); + Assert(victim->npages >= npages); + fpm->singleton_first_page += npages; + fpm->singleton_npages -= npages; + if (fpm->singleton_npages > 0) + FreePagePushSpanLeader(fpm, fpm->singleton_first_page, + fpm->singleton_npages); + } + else + { + /* + * If the span we found is exactly the right size, remove it from the + * btree completely. Otherwise, adjust the btree entry to reflect the + * still-unallocated portion of the span, and put that portion on the + * appropriate free list. + */ + FreePageBtreeSearch(fpm, victim_page, &result); + Assert(result.found); + if (victim->npages == npages) + FreePageBtreeRemove(fpm, result.page, result.index); + else + { + FreePageBtreeLeafKey *key; + + /* Adjust btree to reflect remaining pages. */ + Assert(victim->npages > npages); + key = &result.page->u.leaf_key[result.index]; + Assert(key->npages == victim->npages); + key->first_page += npages; + key->npages -= npages; + if (result.index == 0) + FreePageBtreeAdjustAncestorKeys(fpm, result.page); + + /* Put the unallocated pages back on the appropriate free list. */ + FreePagePushSpanLeader(fpm, victim_page + npages, + victim->npages - npages); + } + } + + /* Return results to caller. */ + *first_page = fpm_pointer_to_page(base, victim); + return true; +} + +/* + * Put a range of pages into the btree and freelists, consolidating it with + * existing free spans just before and/or after it. If 'soft' is true, + * only perform the insertion if it can be done without allocating new btree + * pages; if false, do it always. Returns 0 if the soft flag caused the + * insertion to be skipped, or otherwise the size of the contiguous span + * created by the insertion. This may be larger than npages if we're able + * to consolidate with an adjacent range. *internal_pages_used is set to + * true if the btree allocated pages for internal purposes, which might + * invalidate the current largest run requiring it to be recomputed. + */ +static Size +FreePageManagerPutInternal(FreePageManager *fpm, Size first_page, Size npages, + bool soft) +{ + char *base = fpm_segment_base(fpm); + FreePageBtreeSearchResult result; + FreePageBtreeLeafKey *prevkey = NULL; + FreePageBtreeLeafKey *nextkey = NULL; + FreePageBtree *np; + Size nindex; + + Assert(npages > 0); + + /* We can store a single free span without initializing the btree. */ + if (fpm->btree_depth == 0) + { + if (fpm->singleton_npages == 0) + { + /* Don't have a span yet; store this one. */ + fpm->singleton_first_page = first_page; + fpm->singleton_npages = npages; + FreePagePushSpanLeader(fpm, first_page, npages); + return fpm->singleton_npages; + } + else if (fpm->singleton_first_page + fpm->singleton_npages == + first_page) + { + /* New span immediately follows sole existing span. */ + fpm->singleton_npages += npages; + FreePagePopSpanLeader(fpm, fpm->singleton_first_page); + FreePagePushSpanLeader(fpm, fpm->singleton_first_page, + fpm->singleton_npages); + return fpm->singleton_npages; + } + else if (first_page + npages == fpm->singleton_first_page) + { + /* New span immediately precedes sole existing span. */ + FreePagePopSpanLeader(fpm, fpm->singleton_first_page); + fpm->singleton_first_page = first_page; + fpm->singleton_npages += npages; + FreePagePushSpanLeader(fpm, fpm->singleton_first_page, + fpm->singleton_npages); + return fpm->singleton_npages; + } + else + { + /* Not contiguous; we need to initialize the btree. */ + Size root_page; + FreePageBtree *root; + + if (!relptr_is_null(fpm->btree_recycle)) + root = FreePageBtreeGetRecycled(fpm); + else if (FreePageManagerGetInternal(fpm, 1, &root_page)) + root = (FreePageBtree *) fpm_page_to_pointer(base, root_page); + else + { + /* We'd better be able to get a page from the existing range. */ + elog(FATAL, "free page manager btree is corrupt"); + } + + /* Create the btree and move the preexisting range into it. */ + root->hdr.magic = FREE_PAGE_LEAF_MAGIC; + root->hdr.nused = 1; + relptr_store(base, root->hdr.parent, (FreePageBtree *) NULL); + root->u.leaf_key[0].first_page = fpm->singleton_first_page; + root->u.leaf_key[0].npages = fpm->singleton_npages; + relptr_store(base, fpm->btree_root, root); + fpm->singleton_first_page = 0; + fpm->singleton_npages = 0; + fpm->btree_depth = 1; + + /* + * Corner case: it may be that the btree root took the very last + * free page. In that case, the sole btree entry covers a zero + * page run, which is invalid. Overwrite it with the entry we're + * trying to insert and get out. + */ + if (root->u.leaf_key[0].npages == 0) + { + root->u.leaf_key[0].first_page = first_page; + root->u.leaf_key[0].npages = npages; + FreePagePushSpanLeader(fpm, first_page, npages); + return npages; + } + + /* Fall through to insert the new key. */ + } + } + + /* Search the btree. */ + FreePageBtreeSearch(fpm, first_page, &result); + Assert(!result.found); + if (result.index > 0) + prevkey = &result.page->u.leaf_key[result.index - 1]; + if (result.index < result.page->hdr.nused) + { + np = result.page; + nindex = result.index; + nextkey = &result.page->u.leaf_key[result.index]; + } + else + { + np = FreePageBtreeFindRightSibling(base, result.page); + nindex = 0; + if (np != NULL) + nextkey = &np->u.leaf_key[0]; + } + + /* Consolidate with the previous entry if possible. */ + if (prevkey != NULL && prevkey->first_page + prevkey->npages >= first_page) + { + bool remove_next = false; + Size result; + + Assert(prevkey->first_page + prevkey->npages == first_page); + prevkey->npages = (first_page - prevkey->first_page) + npages; + + /* Check whether we can *also* consolidate with the following entry. */ + if (nextkey != NULL && + prevkey->first_page + prevkey->npages >= nextkey->first_page) + { + Assert(prevkey->first_page + prevkey->npages == + nextkey->first_page); + prevkey->npages = (nextkey->first_page - prevkey->first_page) + + nextkey->npages; + FreePagePopSpanLeader(fpm, nextkey->first_page); + remove_next = true; + } + + /* Put the span on the correct freelist and save size. */ + FreePagePopSpanLeader(fpm, prevkey->first_page); + FreePagePushSpanLeader(fpm, prevkey->first_page, prevkey->npages); + result = prevkey->npages; + + /* + * If we consolidated with both the preceding and following entries, + * we must remove the following entry. We do this last, because + * removing an element from the btree may invalidate pointers we hold + * into the current data structure. + * + * NB: The btree is technically in an invalid state a this point + * because we've already updated prevkey to cover the same key space + * as nextkey. FreePageBtreeRemove() shouldn't notice that, though. + */ + if (remove_next) + FreePageBtreeRemove(fpm, np, nindex); + + return result; + } + + /* Consolidate with the next entry if possible. */ + if (nextkey != NULL && first_page + npages >= nextkey->first_page) + { + Size newpages; + + /* Compute new size for span. */ + Assert(first_page + npages == nextkey->first_page); + newpages = (nextkey->first_page - first_page) + nextkey->npages; + + /* Put span on correct free list. */ + FreePagePopSpanLeader(fpm, nextkey->first_page); + FreePagePushSpanLeader(fpm, first_page, newpages); + + /* Update key in place. */ + nextkey->first_page = first_page; + nextkey->npages = newpages; + + /* If reducing first key on page, ancestors might need adjustment. */ + if (nindex == 0) + FreePageBtreeAdjustAncestorKeys(fpm, np); + + return nextkey->npages; + } + + /* Split leaf page and as many of its ancestors as necessary. */ + if (result.split_pages > 0) + { + /* + * NB: We could consider various coping strategies here to avoid a + * split; most obviously, if np != result.page, we could target that + * page instead. More complicated shuffling strategies could be + * possible as well; basically, unless every single leaf page is 100% + * full, we can jam this key in there if we try hard enough. It's + * unlikely that trying that hard is worthwhile, but it's possible we + * might need to make more than no effort. For now, we just do the + * easy thing, which is nothing. + */ + + /* If this is a soft insert, it's time to give up. */ + if (soft) + return 0; + + /* Check whether we need to allocate more btree pages to split. */ + if (result.split_pages > fpm->btree_recycle_count) + { + Size pages_needed; + Size recycle_page; + Size i; + + /* + * Allocate the required number of pages and split each one in + * turn. This should never fail, because if we've got enough + * spans of free pages kicking around that we need additional + * storage space just to remember them all, then we should + * certainly have enough to expand the btree, which should only + * ever use a tiny number of pages compared to the number under + * management. If it does, something's badly screwed up. + */ + pages_needed = result.split_pages - fpm->btree_recycle_count; + for (i = 0; i < pages_needed; ++i) + { + if (!FreePageManagerGetInternal(fpm, 1, &recycle_page)) + elog(FATAL, "free page manager btree is corrupt"); + FreePageBtreeRecycle(fpm, recycle_page); + } + + /* + * The act of allocating pages to recycle may have invalidated the + * results of our previous btree reserch, so repeat it. (We could + * recheck whether any of our split-avoidance strategies that were + * not viable before now are, but it hardly seems worthwhile, so + * we don't bother. Consolidation can't be possible now if it + * wasn't previously.) + */ + FreePageBtreeSearch(fpm, first_page, &result); + + /* + * The act of allocating pages for use in constructing our btree + * should never cause any page to become more full, so the new + * split depth should be no greater than the old one, and perhaps + * less if we fortutiously allocated a chunk that freed up a slot + * on the page we need to update. + */ + Assert(result.split_pages <= fpm->btree_recycle_count); + } + + /* If we still need to perform a split, do it. */ + if (result.split_pages > 0) + { + FreePageBtree *split_target = result.page; + FreePageBtree *child = NULL; + Size key = first_page; + + for (;;) + { + FreePageBtree *newsibling; + FreePageBtree *parent; + + /* Identify parent page, which must receive downlink. */ + parent = relptr_access(base, split_target->hdr.parent); + + /* Split the page - downlink not added yet. */ + newsibling = FreePageBtreeSplitPage(fpm, split_target); + + /* + * At this point in the loop, we're always carrying a pending + * insertion. On the first pass, it's the actual key we're + * trying to insert; on subsequent passes, it's the downlink + * that needs to be added as a result of the split performed + * during the previous loop iteration. Since we've just split + * the page, there's definitely room on one of the two + * resulting pages. + */ + if (child == NULL) + { + Size index; + FreePageBtree *insert_into; + + insert_into = key < newsibling->u.leaf_key[0].first_page ? + split_target : newsibling; + index = FreePageBtreeSearchLeaf(insert_into, key); + FreePageBtreeInsertLeaf(insert_into, index, key, npages); + if (index == 0 && insert_into == split_target) + FreePageBtreeAdjustAncestorKeys(fpm, split_target); + } + else + { + Size index; + FreePageBtree *insert_into; + + insert_into = + key < newsibling->u.internal_key[0].first_page ? + split_target : newsibling; + index = FreePageBtreeSearchInternal(insert_into, key); + FreePageBtreeInsertInternal(base, insert_into, index, + key, child); + relptr_store(base, child->hdr.parent, insert_into); + if (index == 0 && insert_into == split_target) + FreePageBtreeAdjustAncestorKeys(fpm, split_target); + } + + /* If the page we just split has no parent, split the root. */ + if (parent == NULL) + { + FreePageBtree *newroot; + + newroot = FreePageBtreeGetRecycled(fpm); + newroot->hdr.magic = FREE_PAGE_INTERNAL_MAGIC; + newroot->hdr.nused = 2; + relptr_store(base, newroot->hdr.parent, + (FreePageBtree *) NULL); + newroot->u.internal_key[0].first_page = + FreePageBtreeFirstKey(split_target); + relptr_store(base, newroot->u.internal_key[0].child, + split_target); + relptr_store(base, split_target->hdr.parent, newroot); + newroot->u.internal_key[1].first_page = + FreePageBtreeFirstKey(newsibling); + relptr_store(base, newroot->u.internal_key[1].child, + newsibling); + relptr_store(base, newsibling->hdr.parent, newroot); + relptr_store(base, fpm->btree_root, newroot); + fpm->btree_depth++; + + break; + } + + /* If the parent page isn't full, insert the downlink. */ + key = newsibling->u.internal_key[0].first_page; + if (parent->hdr.nused < FPM_ITEMS_PER_INTERNAL_PAGE) + { + Size index; + + index = FreePageBtreeSearchInternal(parent, key); + FreePageBtreeInsertInternal(base, parent, index, + key, newsibling); + relptr_store(base, newsibling->hdr.parent, parent); + if (index == 0) + FreePageBtreeAdjustAncestorKeys(fpm, parent); + break; + } + + /* The parent also needs to be split, so loop around. */ + child = newsibling; + split_target = parent; + } + + /* + * The loop above did the insert, so just need to update the free + * list, and we're done. + */ + FreePagePushSpanLeader(fpm, first_page, npages); + + return npages; + } + } + + /* Physically add the key to the page. */ + Assert(result.page->hdr.nused < FPM_ITEMS_PER_LEAF_PAGE); + FreePageBtreeInsertLeaf(result.page, result.index, first_page, npages); + + /* If new first key on page, ancestors might need adjustment. */ + if (result.index == 0) + FreePageBtreeAdjustAncestorKeys(fpm, result.page); + + /* Put it on the free list. */ + FreePagePushSpanLeader(fpm, first_page, npages); + + return npages; +} + +/* + * Remove a FreePageSpanLeader from the linked-list that contains it, either + * because we're changing the size of the span, or because we're allocating it. + */ +static void +FreePagePopSpanLeader(FreePageManager *fpm, Size pageno) +{ + char *base = fpm_segment_base(fpm); + FreePageSpanLeader *span; + FreePageSpanLeader *next; + FreePageSpanLeader *prev; + + span = (FreePageSpanLeader *) fpm_page_to_pointer(base, pageno); + + next = relptr_access(base, span->next); + prev = relptr_access(base, span->prev); + if (next != NULL) + relptr_copy(next->prev, span->prev); + if (prev != NULL) + relptr_copy(prev->next, span->next); + else + { + Size f = Min(span->npages, FPM_NUM_FREELISTS) - 1; + + Assert(fpm->freelist[f].relptr_off == pageno * FPM_PAGE_SIZE); + relptr_copy(fpm->freelist[f], span->next); + } +} + +/* + * Initialize a new FreePageSpanLeader and put it on the appropriate free list. + */ +static void +FreePagePushSpanLeader(FreePageManager *fpm, Size first_page, Size npages) +{ + char *base = fpm_segment_base(fpm); + Size f = Min(npages, FPM_NUM_FREELISTS) - 1; + FreePageSpanLeader *head = relptr_access(base, fpm->freelist[f]); + FreePageSpanLeader *span; + + span = (FreePageSpanLeader *) fpm_page_to_pointer(base, first_page); + span->magic = FREE_PAGE_SPAN_LEADER_MAGIC; + span->npages = npages; + relptr_store(base, span->next, head); + relptr_store(base, span->prev, (FreePageSpanLeader *) NULL); + if (head != NULL) + relptr_store(base, head->prev, span); + relptr_store(base, fpm->freelist[f], span); +} diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c index 6b7894213c..6ad0bb47b6 100644 --- a/src/backend/utils/mmgr/mcxt.c +++ b/src/backend/utils/mmgr/mcxt.c @@ -9,7 +9,7 @@ * context's MemoryContextMethods struct. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -91,16 +91,13 @@ MemoryContextInit(void) AssertState(TopMemoryContext == NULL); /* - * Initialize TopMemoryContext as an AllocSetContext with slow growth rate - * --- we don't really expect much to be allocated in it. - * - * (There is special-case code in MemoryContextCreate() for this call.) + * First, initialize TopMemoryContext, which will hold the MemoryContext + * nodes for all other contexts. (There is special-case code in + * MemoryContextCreate() to handle this call.) */ TopMemoryContext = AllocSetContextCreate((MemoryContext) NULL, "TopMemoryContext", - 0, - 8 * 1024, - 8 * 1024); + ALLOCSET_DEFAULT_SIZES); /* * Not having any other place to point CurrentMemoryContext, make it point diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c index 425cae12ea..e8ebc4684c 100644 --- a/src/backend/utils/mmgr/portalmem.c +++ b/src/backend/utils/mmgr/portalmem.c @@ -8,7 +8,7 @@ * doesn't actually run the executor for them. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -108,9 +108,7 @@ EnablePortalManager(void) PortalMemory = AllocSetContextCreate(TopMemoryContext, "PortalMemory", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); ctl.keysize = MAX_PORTALNAME_LEN; ctl.entrysize = sizeof(PortalHashEnt); @@ -141,45 +139,26 @@ GetPortalByName(const char *name) } /* - * PortalListGetPrimaryStmt + * PortalGetPrimaryStmt * Get the "primary" stmt within a portal, ie, the one marked canSetTag. * * Returns NULL if no such stmt. If multiple PlannedStmt structs within the * portal are marked canSetTag, returns the first one. Neither of these * cases should occur in present usages of this function. - * - * Copes if given a list of Querys --- can't happen in a portal, but this - * code also supports plancache.c, which needs both cases. - * - * Note: the reason this is just handed a List is so that plancache.c - * can share the code. For use with a portal, use PortalGetPrimaryStmt - * rather than calling this directly. */ -Node * -PortalListGetPrimaryStmt(List *stmts) +PlannedStmt * +PortalGetPrimaryStmt(Portal portal) { ListCell *lc; - foreach(lc, stmts) + foreach(lc, portal->stmts) { - Node *stmt = (Node *) lfirst(lc); + PlannedStmt *stmt = (PlannedStmt *) lfirst(lc); - if (IsA(stmt, PlannedStmt)) - { - if (((PlannedStmt *) stmt)->canSetTag) - return stmt; - } - else if (IsA(stmt, Query)) - { - if (((Query *) stmt)->canSetTag) - return stmt; - } - else - { - /* Utility stmts are assumed canSetTag if they're the only stmt */ - if (list_length(stmts) == 1) - return stmt; - } + Assert(IsA(stmt, PlannedStmt)); + + if (stmt->canSetTag) + return stmt; } return NULL; } @@ -221,9 +200,7 @@ CreatePortal(const char *name, bool allowDup, bool dupSilent) /* initialize portal heap context; typically it won't store much */ portal->heap = AllocSetContextCreate(PortalMemory, "PortalHeapMemory", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MAXSIZE); + ALLOCSET_SMALL_SIZES); /* create a resource owner for the portal */ portal->resowner = ResourceOwnerCreate(CurTransactionResourceOwner, @@ -361,9 +338,7 @@ PortalCreateHoldStore(Portal portal) portal->holdContext = AllocSetContextCreate(PortalMemory, "PortalHoldContext", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* * Create the tuple store, selecting cross-transaction temp files, and diff --git a/src/backend/utils/probes.d b/src/backend/utils/probes.d index 976774e795..1aaadc1519 100644 --- a/src/backend/utils/probes.d +++ b/src/backend/utils/probes.d @@ -1,7 +1,7 @@ /* ---------- * DTrace probes for PostgreSQL backend * - * Copyright (c) 2006-2016, PostgreSQL Global Development Group + * Copyright (c) 2006-2017, PostgreSQL Global Development Group * * src/backend/utils/probes.d * ---------- @@ -12,7 +12,7 @@ * Typedefs used in PostgreSQL. * * NOTE: Do not use system-provided typedefs (e.g. uintptr_t, uint32_t, etc) - * in probe definitions, as they cause compilation errors on Mac OS X 10.5. + * in probe definitions, as they cause compilation errors on macOS 10.5. */ #define LocalTransactionId unsigned int #define LWLockMode int @@ -28,14 +28,14 @@ provider postgresql { probe transaction__commit(LocalTransactionId); probe transaction__abort(LocalTransactionId); - probe lwlock__acquire(const char *, int, LWLockMode); - probe lwlock__release(const char *, int); - probe lwlock__wait__start(const char *, int, LWLockMode); - probe lwlock__wait__done(const char *, int, LWLockMode); - probe lwlock__condacquire(const char *, int, LWLockMode); - probe lwlock__condacquire__fail(const char *, int, LWLockMode); - probe lwlock__acquire__or__wait(const char *, int, LWLockMode); - probe lwlock__acquire__or__wait__fail(const char *, int, LWLockMode); + probe lwlock__acquire(const char *, LWLockMode); + probe lwlock__release(const char *); + probe lwlock__wait__start(const char *, LWLockMode); + probe lwlock__wait__done(const char *, LWLockMode); + probe lwlock__condacquire(const char *, LWLockMode); + probe lwlock__condacquire__fail(const char *, LWLockMode); + probe lwlock__acquire__or__wait(const char *, LWLockMode); + probe lwlock__acquire__or__wait__fail(const char *, LWLockMode); probe lock__wait__start(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, LOCKMODE); probe lock__wait__done(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, LOCKMODE); diff --git a/src/backend/utils/resowner/resowner.c b/src/backend/utils/resowner/resowner.c index 07075ce06d..af46d78125 100644 --- a/src/backend/utils/resowner/resowner.c +++ b/src/backend/utils/resowner/resowner.c @@ -9,7 +9,7 @@ * See utils/resowner/README for more info. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -668,9 +668,6 @@ ResourceOwnerReleaseInternal(ResourceOwner owner, PrintFileLeakWarning(res); FileClose(res); } - - /* Clean up index scans too */ - ReleaseResources_hash(); } /* Let add-on modules get a chance too */ diff --git a/src/backend/utils/sort/logtape.c b/src/backend/utils/sort/logtape.c index 774520752f..f6a9dba97d 100644 --- a/src/backend/utils/sort/logtape.c +++ b/src/backend/utils/sort/logtape.c @@ -31,15 +31,8 @@ * in BLCKSZ-size blocks. Space allocation boils down to keeping track * of which blocks in the underlying file belong to which logical tape, * plus any blocks that are free (recycled and not yet reused). - * The blocks in each logical tape are remembered using a method borrowed - * from the Unix HFS filesystem: we store data block numbers in an - * "indirect block". If an indirect block fills up, we write it out to - * the underlying file and remember its location in a second-level indirect - * block. In the same way second-level blocks are remembered in third- - * level blocks, and so on if necessary (of course we're talking huge - * amounts of data here). The topmost indirect block of a given logical - * tape is never actually written out to the physical file, but all lower- - * level indirect blocks will be. + * The blocks in each logical tape form a chain, with a prev- and next- + * pointer in each block. * * The initial write pass is guaranteed to fill the underlying file * perfectly sequentially, no matter how data is divided into logical tapes. @@ -52,12 +45,17 @@ * not clear this helps much, but it can't hurt. (XXX perhaps a LIFO * policy for free blocks would be better?) * + * To further make the I/Os more sequential, we can use a larger buffer + * when reading, and read multiple blocks from the same tape in one go, + * whenever the buffer becomes empty. LogicalTapeAssignReadBufferSize() + * can be used to set the size of the read buffer. + * * To support the above policy of writing to the lowest free block, * ltsGetFreeBlock sorts the list of free block numbers into decreasing * order each time it is asked for a block and the list isn't currently * sorted. This is an efficient way to handle it because we expect cycles * of releasing many blocks followed by re-using many blocks, due to - * tuplesort.c's "preread" behavior. + * the larger read buffer. * * Since all the bookkeeping and buffer memory is allocated with palloc(), * and the underlying file(s) are made with OpenTemporaryFile, all resources @@ -66,7 +64,7 @@ * care that all calls for a single LogicalTapeSet are made in the same * palloc context. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -79,59 +77,68 @@ #include "storage/buffile.h" #include "utils/logtape.h" +#include "utils/memutils.h" /* - * Block indexes are "long"s, so we can fit this many per indirect block. - * NB: we assume this is an exact fit! - */ -#define BLOCKS_PER_INDIR_BLOCK ((int) (BLCKSZ / sizeof(long))) - -/* - * We use a struct like this for each active indirection level of each - * logical tape. If the indirect block is not the highest level of its - * tape, the "nextup" link points to the next higher level. Only the - * "ptrs" array is written out if we have to dump the indirect block to - * disk. If "ptrs" is not completely full, we store -1L in the first - * unused slot at completion of the write phase for the logical tape. + * A TapeBlockTrailer is stored at the end of each BLCKSZ block. + * + * The first block of a tape has prev == -1. The last block of a tape + * stores the number of valid bytes on the block, inverted, in 'next' + * Therefore next < 0 indicates the last block. */ -typedef struct IndirectBlock +typedef struct TapeBlockTrailer { - int nextSlot; /* next pointer slot to write or read */ - struct IndirectBlock *nextup; /* parent indirect level, or NULL if - * top */ - long ptrs[BLOCKS_PER_INDIR_BLOCK]; /* indexes of contained blocks */ -} IndirectBlock; + long prev; /* previous block on this tape, or -1 on first + * block */ + long next; /* next block on this tape, or # of valid + * bytes on last block (if < 0) */ +} TapeBlockTrailer; + +#define TapeBlockPayloadSize (BLCKSZ - sizeof(TapeBlockTrailer)) +#define TapeBlockGetTrailer(buf) \ + ((TapeBlockTrailer *) ((char *) buf + TapeBlockPayloadSize)) + +#define TapeBlockIsLast(buf) (TapeBlockGetTrailer(buf)->next < 0) +#define TapeBlockGetNBytes(buf) \ + (TapeBlockIsLast(buf) ? \ + (- TapeBlockGetTrailer(buf)->next) : TapeBlockPayloadSize) +#define TapeBlockSetNBytes(buf, nbytes) \ + (TapeBlockGetTrailer(buf)->next = -(nbytes)) + /* * This data structure represents a single "logical tape" within the set - * of logical tapes stored in the same file. We must keep track of the - * current partially-read-or-written data block as well as the active - * indirect block level(s). + * of logical tapes stored in the same file. + * + * While writing, we hold the current partially-written data block in the + * buffer. While reading, we can hold multiple blocks in the buffer. Note + * that we don't retain the trailers of a block when it's read into the + * buffer. The buffer therefore contains one large contiguous chunk of data + * from the tape. */ typedef struct LogicalTape { - IndirectBlock *indirect; /* bottom of my indirect-block hierarchy */ bool writing; /* T while in write phase */ bool frozen; /* T if blocks should not be freed when read */ bool dirty; /* does buffer need to be written? */ /* - * The total data volume in the logical tape is numFullBlocks * BLCKSZ + - * lastBlockBytes. BUT: we do not update lastBlockBytes during writing, - * only at completion of a write phase. + * Block numbers of the first, current, and next block of the tape. + * + * The "current" block number is only valid when writing, or reading from + * a frozen tape. (When reading from an unfrozen tape, we use a larger + * read buffer that holds multiple blocks, so the "current" block is + * ambiguous.) */ - long numFullBlocks; /* number of complete blocks in log tape */ - int lastBlockBytes; /* valid bytes in last (incomplete) block */ + long firstBlockNumber; + long curBlockNumber; + long nextBlockNumber; /* - * Buffer for current data block. Note we don't bother to store the - * actual file block number of the data block (during the write phase it - * hasn't been assigned yet, and during read we don't care anymore). But - * we do need the relative block number so we can detect end-of-tape while - * reading. + * Buffer for current data block(s). */ char *buffer; /* physical buffer (separately palloc'd) */ - long curBlockNumber; /* this block's logical blk# within tape */ + int buffer_size; /* allocated size of the buffer */ int pos; /* next read/write position in buffer */ int nbytes; /* total # of valid bytes in buffer */ } LogicalTape; @@ -175,19 +182,6 @@ static void ltsWriteBlock(LogicalTapeSet *lts, long blocknum, void *buffer); static void ltsReadBlock(LogicalTapeSet *lts, long blocknum, void *buffer); static long ltsGetFreeBlock(LogicalTapeSet *lts); static void ltsReleaseBlock(LogicalTapeSet *lts, long blocknum); -static void ltsRecordBlockNum(LogicalTapeSet *lts, IndirectBlock *indirect, - long blocknum); -static long ltsRewindIndirectBlock(LogicalTapeSet *lts, - IndirectBlock *indirect, - bool freezing); -static long ltsRewindFrozenIndirectBlock(LogicalTapeSet *lts, - IndirectBlock *indirect); -static long ltsRecallNextBlockNum(LogicalTapeSet *lts, - IndirectBlock *indirect, - bool frozen); -static long ltsRecallPrevBlockNum(LogicalTapeSet *lts, - IndirectBlock *indirect); -static void ltsDumpBuffer(LogicalTapeSet *lts, LogicalTape *lt); /* @@ -227,6 +221,47 @@ ltsReadBlock(LogicalTapeSet *lts, long blocknum, void *buffer) blocknum))); } +/* + * Read as many blocks as we can into the per-tape buffer. + * + * Returns true if anything was read, 'false' on EOF. + */ +static bool +ltsReadFillBuffer(LogicalTapeSet *lts, LogicalTape *lt) +{ + lt->pos = 0; + lt->nbytes = 0; + + do + { + char *thisbuf = lt->buffer + lt->nbytes; + + /* Fetch next block number */ + if (lt->nextBlockNumber == -1L) + break; /* EOF */ + + /* Read the block */ + ltsReadBlock(lts, lt->nextBlockNumber, (void *) thisbuf); + if (!lt->frozen) + ltsReleaseBlock(lts, lt->nextBlockNumber); + lt->curBlockNumber = lt->nextBlockNumber; + + lt->nbytes += TapeBlockGetNBytes(thisbuf); + if (TapeBlockIsLast(thisbuf)) + { + lt->nextBlockNumber = -1L; + /* EOF */ + break; + } + else + lt->nextBlockNumber = TapeBlockGetTrailer(thisbuf)->next; + + /* Advance to next block, if we have buffer space left */ + } while (lt->buffer_size - lt->nbytes > BLCKSZ); + + return (lt->nbytes > 0); +} + /* * qsort comparator for sorting freeBlocks[] into decreasing order. */ @@ -306,203 +341,6 @@ ltsReleaseBlock(LogicalTapeSet *lts, long blocknum) lts->blocksSorted = false; } -/* - * These routines manipulate indirect-block hierarchies. All are recursive - * so that they don't have any specific limit on the depth of hierarchy. - */ - -/* - * Record a data block number in a logical tape's lowest indirect block, - * or record an indirect block's number in the next higher indirect level. - */ -static void -ltsRecordBlockNum(LogicalTapeSet *lts, IndirectBlock *indirect, - long blocknum) -{ - if (indirect->nextSlot >= BLOCKS_PER_INDIR_BLOCK) - { - /* - * This indirect block is full, so dump it out and recursively save - * its address in the next indirection level. Create a new - * indirection level if there wasn't one before. - */ - long indirblock = ltsGetFreeBlock(lts); - - ltsWriteBlock(lts, indirblock, (void *) indirect->ptrs); - if (indirect->nextup == NULL) - { - indirect->nextup = (IndirectBlock *) palloc(sizeof(IndirectBlock)); - indirect->nextup->nextSlot = 0; - indirect->nextup->nextup = NULL; - } - ltsRecordBlockNum(lts, indirect->nextup, indirblock); - - /* - * Reset to fill another indirect block at this level. - */ - indirect->nextSlot = 0; - } - indirect->ptrs[indirect->nextSlot++] = blocknum; -} - -/* - * Reset a logical tape's indirect-block hierarchy after a write pass - * to prepare for reading. We dump out partly-filled blocks except - * at the top of the hierarchy, and we rewind each level to the start. - * This call returns the first data block number, or -1L if the tape - * is empty. - * - * Unless 'freezing' is true, release indirect blocks to the free pool after - * reading them. - */ -static long -ltsRewindIndirectBlock(LogicalTapeSet *lts, - IndirectBlock *indirect, - bool freezing) -{ - /* Handle case of never-written-to tape */ - if (indirect == NULL) - return -1L; - - /* Insert sentinel if block is not full */ - if (indirect->nextSlot < BLOCKS_PER_INDIR_BLOCK) - indirect->ptrs[indirect->nextSlot] = -1L; - - /* - * If block is not topmost, write it out, and recurse to obtain address of - * first block in this hierarchy level. Read that one in. - */ - if (indirect->nextup != NULL) - { - long indirblock = ltsGetFreeBlock(lts); - - ltsWriteBlock(lts, indirblock, (void *) indirect->ptrs); - ltsRecordBlockNum(lts, indirect->nextup, indirblock); - indirblock = ltsRewindIndirectBlock(lts, indirect->nextup, freezing); - Assert(indirblock != -1L); - ltsReadBlock(lts, indirblock, (void *) indirect->ptrs); - if (!freezing) - ltsReleaseBlock(lts, indirblock); - } - - /* - * Reset my next-block pointer, and then fetch a block number if any. - */ - indirect->nextSlot = 0; - if (indirect->ptrs[0] == -1L) - return -1L; - return indirect->ptrs[indirect->nextSlot++]; -} - -/* - * Rewind a previously-frozen indirect-block hierarchy for another read pass. - * This call returns the first data block number, or -1L if the tape - * is empty. - */ -static long -ltsRewindFrozenIndirectBlock(LogicalTapeSet *lts, - IndirectBlock *indirect) -{ - /* Handle case of never-written-to tape */ - if (indirect == NULL) - return -1L; - - /* - * If block is not topmost, recurse to obtain address of first block in - * this hierarchy level. Read that one in. - */ - if (indirect->nextup != NULL) - { - long indirblock; - - indirblock = ltsRewindFrozenIndirectBlock(lts, indirect->nextup); - Assert(indirblock != -1L); - ltsReadBlock(lts, indirblock, (void *) indirect->ptrs); - } - - /* - * Reset my next-block pointer, and then fetch a block number if any. - */ - indirect->nextSlot = 0; - if (indirect->ptrs[0] == -1L) - return -1L; - return indirect->ptrs[indirect->nextSlot++]; -} - -/* - * Obtain next data block number in the forward direction, or -1L if no more. - * - * Unless 'frozen' is true, release indirect blocks to the free pool after - * reading them. - */ -static long -ltsRecallNextBlockNum(LogicalTapeSet *lts, - IndirectBlock *indirect, - bool frozen) -{ - /* Handle case of never-written-to tape */ - if (indirect == NULL) - return -1L; - - if (indirect->nextSlot >= BLOCKS_PER_INDIR_BLOCK || - indirect->ptrs[indirect->nextSlot] == -1L) - { - long indirblock; - - if (indirect->nextup == NULL) - return -1L; /* nothing left at this level */ - indirblock = ltsRecallNextBlockNum(lts, indirect->nextup, frozen); - if (indirblock == -1L) - return -1L; /* nothing left at this level */ - ltsReadBlock(lts, indirblock, (void *) indirect->ptrs); - if (!frozen) - ltsReleaseBlock(lts, indirblock); - indirect->nextSlot = 0; - } - if (indirect->ptrs[indirect->nextSlot] == -1L) - return -1L; - return indirect->ptrs[indirect->nextSlot++]; -} - -/* - * Obtain next data block number in the reverse direction, or -1L if no more. - * - * Note this fetches the block# before the one last returned, no matter which - * direction of call returned that one. If we fail, no change in state. - * - * This routine can only be used in 'frozen' state, so there's no need to - * pass a parameter telling whether to release blocks ... we never do. - */ -static long -ltsRecallPrevBlockNum(LogicalTapeSet *lts, - IndirectBlock *indirect) -{ - /* Handle case of never-written-to tape */ - if (indirect == NULL) - return -1L; - - if (indirect->nextSlot <= 1) - { - long indirblock; - - if (indirect->nextup == NULL) - return -1L; /* nothing left at this level */ - indirblock = ltsRecallPrevBlockNum(lts, indirect->nextup); - if (indirblock == -1L) - return -1L; /* nothing left at this level */ - ltsReadBlock(lts, indirblock, (void *) indirect->ptrs); - - /* - * The previous block would only have been written out if full, so we - * need not search it for a -1 sentinel. - */ - indirect->nextSlot = BLOCKS_PER_INDIR_BLOCK + 1; - } - indirect->nextSlot--; - return indirect->ptrs[indirect->nextSlot - 1]; -} - - /* * Create a set of logical tapes in a temporary underlying file. * @@ -531,22 +369,21 @@ LogicalTapeSetCreate(int ntapes) lts->nTapes = ntapes; /* - * Initialize per-tape structs. Note we allocate the I/O buffer and - * first-level indirect block for a tape only when it is first actually - * written to. This avoids wasting memory space when tuplesort.c - * overestimates the number of tapes needed. + * Initialize per-tape structs. Note we allocate the I/O buffer and the + * first block for a tape only when it is first actually written to. This + * avoids wasting memory space when tuplesort.c overestimates the number + * of tapes needed. */ for (i = 0; i < ntapes; i++) { lt = <s->tapes[i]; - lt->indirect = NULL; lt->writing = true; lt->frozen = false; lt->dirty = false; - lt->numFullBlocks = 0L; - lt->lastBlockBytes = 0; + lt->firstBlockNumber = -1L; + lt->curBlockNumber = -1L; lt->buffer = NULL; - lt->curBlockNumber = 0L; + lt->buffer_size = 0; lt->pos = 0; lt->nbytes = 0; } @@ -560,19 +397,12 @@ void LogicalTapeSetClose(LogicalTapeSet *lts) { LogicalTape *lt; - IndirectBlock *ib, - *nextib; int i; BufFileClose(lts->pfile); for (i = 0; i < lts->nTapes; i++) { lt = <s->tapes[i]; - for (ib = lt->indirect; ib != NULL; ib = nextib) - { - nextib = ib->nextup; - pfree(ib); - } if (lt->buffer) pfree(lt->buffer); } @@ -595,21 +425,6 @@ LogicalTapeSetForgetFreeSpace(LogicalTapeSet *lts) lts->forgetFreeSpace = true; } -/* - * Dump the dirty buffer of a logical tape. - */ -static void -ltsDumpBuffer(LogicalTapeSet *lts, LogicalTape *lt) -{ - long datablock = ltsGetFreeBlock(lts); - - Assert(lt->dirty); - ltsWriteBlock(lts, datablock, (void *) lt->buffer); - ltsRecordBlockNum(lts, lt->indirect, datablock); - lt->dirty = false; - /* Caller must do other state update as needed */ -} - /* * Write to a logical tape. * @@ -626,35 +441,55 @@ LogicalTapeWrite(LogicalTapeSet *lts, int tapenum, lt = <s->tapes[tapenum]; Assert(lt->writing); - /* Allocate data buffer and first indirect block on first write */ + /* Allocate data buffer and first block on first write */ if (lt->buffer == NULL) + { lt->buffer = (char *) palloc(BLCKSZ); - if (lt->indirect == NULL) + lt->buffer_size = BLCKSZ; + } + if (lt->curBlockNumber == -1) { - lt->indirect = (IndirectBlock *) palloc(sizeof(IndirectBlock)); - lt->indirect->nextSlot = 0; - lt->indirect->nextup = NULL; + Assert(lt->firstBlockNumber == -1); + Assert(lt->pos == 0); + + lt->curBlockNumber = ltsGetFreeBlock(lts); + lt->firstBlockNumber = lt->curBlockNumber; + + TapeBlockGetTrailer(lt->buffer)->prev = -1L; } + Assert(lt->buffer_size == BLCKSZ); while (size > 0) { - if (lt->pos >= BLCKSZ) + if (lt->pos >= TapeBlockPayloadSize) { /* Buffer full, dump it out */ - if (lt->dirty) - ltsDumpBuffer(lts, lt); - else + long nextBlockNumber; + + if (!lt->dirty) { /* Hmm, went directly from reading to writing? */ elog(ERROR, "invalid logtape state: should be dirty"); } - lt->numFullBlocks++; - lt->curBlockNumber++; + + /* + * First allocate the next block, so that we can store it in the + * 'next' pointer of this block. + */ + nextBlockNumber = ltsGetFreeBlock(lts); + + /* set the next-pointer and dump the current block. */ + TapeBlockGetTrailer(lt->buffer)->next = nextBlockNumber; + ltsWriteBlock(lts, lt->curBlockNumber, (void *) lt->buffer); + + /* initialize the prev-pointer of the next block */ + TapeBlockGetTrailer(lt->buffer)->prev = lt->curBlockNumber; + lt->curBlockNumber = nextBlockNumber; lt->pos = 0; lt->nbytes = 0; } - nthistime = BLCKSZ - lt->pos; + nthistime = TapeBlockPayloadSize - lt->pos; if (nthistime > size) nthistime = size; Assert(nthistime > 0); @@ -671,90 +506,114 @@ LogicalTapeWrite(LogicalTapeSet *lts, int tapenum, } /* - * Rewind logical tape and switch from writing to reading or vice versa. + * Rewind logical tape and switch from writing to reading. * - * Unless the tape has been "frozen" in read state, forWrite must be the - * opposite of the previous tape state. + * The tape must currently be in writing state, or "frozen" in read state. + * + * 'buffer_size' specifies how much memory to use for the read buffer. + * Regardless of the argument, the actual amount of memory used is between + * BLCKSZ and MaxAllocSize, and is a multiple of BLCKSZ. The given value is + * rounded down and truncated to fit those constraints, if necessary. If the + * tape is frozen, the 'buffer_size' argument is ignored, and a small BLCKSZ + * byte buffer is used. */ void -LogicalTapeRewind(LogicalTapeSet *lts, int tapenum, bool forWrite) +LogicalTapeRewindForRead(LogicalTapeSet *lts, int tapenum, size_t buffer_size) { LogicalTape *lt; - long datablocknum; Assert(tapenum >= 0 && tapenum < lts->nTapes); lt = <s->tapes[tapenum]; - if (!forWrite) + /* + * Round and cap buffer_size if needed. + */ + if (lt->frozen) + buffer_size = BLCKSZ; + else { - if (lt->writing) - { - /* - * Completion of a write phase. Flush last partial data block, - * flush any partial indirect blocks, rewind for normal - * (destructive) read. - */ - if (lt->dirty) - ltsDumpBuffer(lts, lt); - lt->lastBlockBytes = lt->nbytes; - lt->writing = false; - datablocknum = ltsRewindIndirectBlock(lts, lt->indirect, false); - } - else - { - /* - * This is only OK if tape is frozen; we rewind for (another) read - * pass. - */ - Assert(lt->frozen); - datablocknum = ltsRewindFrozenIndirectBlock(lts, lt->indirect); - } - /* Read the first block, or reset if tape is empty */ - lt->curBlockNumber = 0L; - lt->pos = 0; - lt->nbytes = 0; - if (datablocknum != -1L) + /* need at least one block */ + if (buffer_size < BLCKSZ) + buffer_size = BLCKSZ; + + /* + * palloc() larger than MaxAllocSize would fail (a multi-gigabyte + * buffer is unlikely to be helpful, anyway) + */ + if (buffer_size > MaxAllocSize) + buffer_size = MaxAllocSize; + + /* round down to BLCKSZ boundary */ + buffer_size -= buffer_size % BLCKSZ; + } + + if (lt->writing) + { + /* + * Completion of a write phase. Flush last partial data block, and + * rewind for normal (destructive) read. + */ + if (lt->dirty) { - ltsReadBlock(lts, datablocknum, (void *) lt->buffer); - if (!lt->frozen) - ltsReleaseBlock(lts, datablocknum); - lt->nbytes = (lt->curBlockNumber < lt->numFullBlocks) ? - BLCKSZ : lt->lastBlockBytes; + TapeBlockSetNBytes(lt->buffer, lt->nbytes); + ltsWriteBlock(lts, lt->curBlockNumber, (void *) lt->buffer); } + lt->writing = false; } else { /* - * Completion of a read phase. Rewind and prepare for write. - * - * NOTE: we assume the caller has read the tape to the end; otherwise - * untouched data and indirect blocks will not have been freed. We - * could add more code to free any unread blocks, but in current usage - * of this module it'd be useless code. + * This is only OK if tape is frozen; we rewind for (another) read + * pass. */ - IndirectBlock *ib, - *nextib; + Assert(lt->frozen); + } - Assert(!lt->writing && !lt->frozen); - /* Must truncate the indirect-block hierarchy down to one level. */ - if (lt->indirect) - { - for (ib = lt->indirect->nextup; ib != NULL; ib = nextib) - { - nextib = ib->nextup; - pfree(ib); - } - lt->indirect->nextSlot = 0; - lt->indirect->nextup = NULL; - } - lt->writing = true; - lt->dirty = false; - lt->numFullBlocks = 0L; - lt->lastBlockBytes = 0; - lt->curBlockNumber = 0L; - lt->pos = 0; - lt->nbytes = 0; + /* Allocate a read buffer (unless the tape is empty) */ + if (lt->buffer) + pfree(lt->buffer); + lt->buffer = NULL; + lt->buffer_size = 0; + if (lt->firstBlockNumber != -1L) + { + lt->buffer = palloc(buffer_size); + lt->buffer_size = buffer_size; } + + /* Read the first block, or reset if tape is empty */ + lt->nextBlockNumber = lt->firstBlockNumber; + lt->pos = 0; + lt->nbytes = 0; + ltsReadFillBuffer(lts, lt); +} + +/* + * Rewind logical tape and switch from reading to writing. + * + * NOTE: we assume the caller has read the tape to the end; otherwise + * untouched data and indirect blocks will not have been freed. We + * could add more code to free any unread blocks, but in current usage + * of this module it'd be useless code. + */ +void +LogicalTapeRewindForWrite(LogicalTapeSet *lts, int tapenum) +{ + LogicalTape *lt; + + Assert(tapenum >= 0 && tapenum < lts->nTapes); + lt = <s->tapes[tapenum]; + + Assert(!lt->writing && !lt->frozen); + lt->writing = true; + lt->dirty = false; + lt->firstBlockNumber = -1L; + lt->curBlockNumber = -1L; + lt->pos = 0; + lt->nbytes = 0; + if (lt->buffer) + pfree(lt->buffer); + lt->buffer = NULL; + lt->buffer_size = 0; } /* @@ -779,20 +638,8 @@ LogicalTapeRead(LogicalTapeSet *lts, int tapenum, if (lt->pos >= lt->nbytes) { /* Try to load more data into buffer. */ - long datablocknum = ltsRecallNextBlockNum(lts, lt->indirect, - lt->frozen); - - if (datablocknum == -1L) + if (!ltsReadFillBuffer(lts, lt)) break; /* EOF */ - lt->curBlockNumber++; - lt->pos = 0; - ltsReadBlock(lts, datablocknum, (void *) lt->buffer); - if (!lt->frozen) - ltsReleaseBlock(lts, datablocknum); - lt->nbytes = (lt->curBlockNumber < lt->numFullBlocks) ? - BLCKSZ : lt->lastBlockBytes; - if (lt->nbytes <= 0) - break; /* EOF (possible here?) */ } nthistime = lt->nbytes - lt->pos; @@ -826,32 +673,52 @@ void LogicalTapeFreeze(LogicalTapeSet *lts, int tapenum) { LogicalTape *lt; - long datablocknum; Assert(tapenum >= 0 && tapenum < lts->nTapes); lt = <s->tapes[tapenum]; Assert(lt->writing); /* - * Completion of a write phase. Flush last partial data block, flush any - * partial indirect blocks, rewind for nondestructive read. + * Completion of a write phase. Flush last partial data block, and rewind + * for nondestructive read. */ if (lt->dirty) - ltsDumpBuffer(lts, lt); - lt->lastBlockBytes = lt->nbytes; + { + TapeBlockSetNBytes(lt->buffer, lt->nbytes); + ltsWriteBlock(lts, lt->curBlockNumber, (void *) lt->buffer); + lt->writing = false; + } lt->writing = false; lt->frozen = true; - datablocknum = ltsRewindIndirectBlock(lts, lt->indirect, true); + + /* + * The seek and backspace functions assume a single block read buffer. + * That's OK with current usage. A larger buffer is helpful to make the + * read pattern of the backing file look more sequential to the OS, when + * we're reading from multiple tapes. But at the end of a sort, when a + * tape is frozen, we only read from a single tape anyway. + */ + if (!lt->buffer || lt->buffer_size != BLCKSZ) + { + if (lt->buffer) + pfree(lt->buffer); + lt->buffer = palloc(BLCKSZ); + lt->buffer_size = BLCKSZ; + } + /* Read the first block, or reset if tape is empty */ - lt->curBlockNumber = 0L; + lt->curBlockNumber = lt->firstBlockNumber; lt->pos = 0; lt->nbytes = 0; - if (datablocknum != -1L) - { - ltsReadBlock(lts, datablocknum, (void *) lt->buffer); - lt->nbytes = (lt->curBlockNumber < lt->numFullBlocks) ? - BLCKSZ : lt->lastBlockBytes; - } + + if (lt->firstBlockNumber == -1L) + lt->nextBlockNumber = -1L; + ltsReadBlock(lts, lt->curBlockNumber, (void *) lt->buffer); + if (TapeBlockIsLast(lt->buffer)) + lt->nextBlockNumber = -1L; + else + lt->nextBlockNumber = TapeBlockGetTrailer(lt->buffer)->next; + lt->nbytes = TapeBlockGetNBytes(lt->buffer); } /* @@ -862,19 +729,21 @@ LogicalTapeFreeze(LogicalTapeSet *lts, int tapenum) * random access during write, and an unfrozen read tape may have * already discarded the desired data! * - * Return value is TRUE if seek successful, FALSE if there isn't that much - * data before the current point (in which case there's no state change). + * Returns the number of bytes backed up. It can be less than the + * requested amount, if there isn't that much data before the current + * position. The tape is positioned to the beginning of the tape in + * that case. */ -bool +size_t LogicalTapeBackspace(LogicalTapeSet *lts, int tapenum, size_t size) { LogicalTape *lt; - long nblocks; - int newpos; + size_t seekpos = 0; Assert(tapenum >= 0 && tapenum < lts->nTapes); lt = <s->tapes[tapenum]; Assert(lt->frozen); + Assert(lt->buffer_size == BLCKSZ); /* * Easy case for seek within current block. @@ -882,45 +751,50 @@ LogicalTapeBackspace(LogicalTapeSet *lts, int tapenum, size_t size) if (size <= (size_t) lt->pos) { lt->pos -= (int) size; - return true; - } - - /* - * Not-so-easy case. Figure out whether it's possible at all. - */ - size -= (size_t) lt->pos; /* part within this block */ - nblocks = size / BLCKSZ; - size = size % BLCKSZ; - if (size) - { - nblocks++; - newpos = (int) (BLCKSZ - size); + return size; } - else - newpos = 0; - if (nblocks > lt->curBlockNumber) - return false; /* a seek too far... */ /* - * OK, we need to back up nblocks blocks. This implementation would be - * pretty inefficient for long seeks, but we really aren't expecting that - * (a seek over one tuple is typical). + * Not-so-easy case, have to walk back the chain of blocks. This + * implementation would be pretty inefficient for long seeks, but we + * really aren't doing that (a seek over one tuple is typical). */ - while (nblocks-- > 0) + seekpos = (size_t) lt->pos; /* part within this block */ + while (size > seekpos) { - long datablocknum = ltsRecallPrevBlockNum(lts, lt->indirect); + long prev = TapeBlockGetTrailer(lt->buffer)->prev; - if (datablocknum == -1L) - elog(ERROR, "unexpected end of tape"); - lt->curBlockNumber--; - if (nblocks == 0) + if (prev == -1L) { - ltsReadBlock(lts, datablocknum, (void *) lt->buffer); - lt->nbytes = BLCKSZ; + /* Tried to back up beyond the beginning of tape. */ + if (lt->curBlockNumber != lt->firstBlockNumber) + elog(ERROR, "unexpected end of tape"); + lt->pos = 0; + return seekpos; } + + ltsReadBlock(lts, prev, (void *) lt->buffer); + + if (TapeBlockGetTrailer(lt->buffer)->next != lt->curBlockNumber) + elog(ERROR, "broken tape, next of block %ld is %ld, expected %ld", + prev, + TapeBlockGetTrailer(lt->buffer)->next, + lt->curBlockNumber); + + lt->nbytes = TapeBlockPayloadSize; + lt->curBlockNumber = prev; + lt->nextBlockNumber = TapeBlockGetTrailer(lt->buffer)->next; + + seekpos += TapeBlockPayloadSize; } - lt->pos = newpos; - return true; + + /* + * 'seekpos' can now be greater than 'size', because it points to the + * beginning the target block. The difference is the position within the + * page. + */ + lt->pos = seekpos - size; + return size; } /* @@ -928,10 +802,10 @@ LogicalTapeBackspace(LogicalTapeSet *lts, int tapenum, size_t size) * * *Only* a frozen-for-read tape can be seeked. * - * Return value is TRUE if seek successful, FALSE if there isn't that much - * data in the tape (in which case there's no state change). + * Must be called with a block/offset previously returned by + * LogicalTapeTell(). */ -bool +void LogicalTapeSeek(LogicalTapeSet *lts, int tapenum, long blocknum, int offset) { @@ -940,52 +814,20 @@ LogicalTapeSeek(LogicalTapeSet *lts, int tapenum, Assert(tapenum >= 0 && tapenum < lts->nTapes); lt = <s->tapes[tapenum]; Assert(lt->frozen); - Assert(offset >= 0 && offset <= BLCKSZ); - - /* - * Easy case for seek within current block. - */ - if (blocknum == lt->curBlockNumber && offset <= lt->nbytes) - { - lt->pos = offset; - return true; - } - - /* - * Not-so-easy case. Figure out whether it's possible at all. - */ - if (blocknum < 0 || blocknum > lt->numFullBlocks || - (blocknum == lt->numFullBlocks && offset > lt->lastBlockBytes)) - return false; + Assert(offset >= 0 && offset <= TapeBlockPayloadSize); + Assert(lt->buffer_size == BLCKSZ); - /* - * OK, advance or back up to the target block. This implementation would - * be pretty inefficient for long seeks, but we really aren't expecting - * that (a seek over one tuple is typical). - */ - while (lt->curBlockNumber > blocknum) + if (blocknum != lt->curBlockNumber) { - long datablocknum = ltsRecallPrevBlockNum(lts, lt->indirect); - - if (datablocknum == -1L) - elog(ERROR, "unexpected end of tape"); - if (--lt->curBlockNumber == blocknum) - ltsReadBlock(lts, datablocknum, (void *) lt->buffer); + ltsReadBlock(lts, blocknum, (void *) lt->buffer); + lt->curBlockNumber = blocknum; + lt->nbytes = TapeBlockPayloadSize; + lt->nextBlockNumber = TapeBlockGetTrailer(lt->buffer)->next; } - while (lt->curBlockNumber < blocknum) - { - long datablocknum = ltsRecallNextBlockNum(lts, lt->indirect, - lt->frozen); - if (datablocknum == -1L) - elog(ERROR, "unexpected end of tape"); - if (++lt->curBlockNumber == blocknum) - ltsReadBlock(lts, datablocknum, (void *) lt->buffer); - } - lt->nbytes = (lt->curBlockNumber < lt->numFullBlocks) ? - BLCKSZ : lt->lastBlockBytes; + if (offset > lt->nbytes) + elog(ERROR, "invalid tape seek position"); lt->pos = offset; - return true; } /* @@ -1002,6 +844,10 @@ LogicalTapeTell(LogicalTapeSet *lts, int tapenum, Assert(tapenum >= 0 && tapenum < lts->nTapes); lt = <s->tapes[tapenum]; + + /* With a larger buffer, 'pos' wouldn't be the same as offset within page */ + Assert(lt->buffer_size == BLCKSZ); + *blocknum = lt->curBlockNumber; *offset = lt->pos; } diff --git a/src/backend/utils/sort/sortsupport.c b/src/backend/utils/sort/sortsupport.c index e9eeb18b7e..73170b7429 100644 --- a/src/backend/utils/sort/sortsupport.c +++ b/src/backend/utils/sort/sortsupport.c @@ -4,7 +4,7 @@ * Support routines for accelerated sorting. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c index 510565c339..e1e692d5f0 100644 --- a/src/backend/utils/sort/tuplesort.c +++ b/src/backend/utils/sort/tuplesort.c @@ -13,26 +13,26 @@ * See Knuth, volume 3, for more than you want to know about the external * sorting algorithm. Historically, we divided the input into sorted runs * using replacement selection, in the form of a priority tree implemented - * as a heap (essentially his Algorithm 5.2.3H -- although that strategy is - * often avoided altogether), but that can now only happen first the first - * run. We merge the runs using polyphase merge, Knuth's Algorithm + * as a heap (essentially his Algorithm 5.2.3H), but now we only do that + * for the first run, and only if the run would otherwise end up being very + * short. We merge the runs using polyphase merge, Knuth's Algorithm * 5.4.2D. The logical "tapes" used by Algorithm D are implemented by * logtape.c, which avoids space wastage by recycling disk space as soon * as each block is read from its "tape". * - * We never form the initial runs using Knuth's recommended replacement - * selection data structure (Algorithm 5.4.1R), because it uses a fixed - * number of records in memory at all times. Since we are dealing with - * tuples that may vary considerably in size, we want to be able to vary - * the number of records kept in memory to ensure full utilization of the - * allowed sort memory space. So, we keep the tuples in a variable-size - * heap, with the next record to go out at the top of the heap. Like - * Algorithm 5.4.1R, each record is stored with the run number that it - * must go into, and we use (run number, key) as the ordering key for the - * heap. When the run number at the top of the heap changes, we know that - * no more records of the prior run are left in the heap. Note that there - * are in practice only ever two distinct run numbers, due to the greatly - * reduced use of replacement selection in PostgreSQL 9.6. + * We do not use Knuth's recommended data structure (Algorithm 5.4.1R) for + * the replacement selection, because it uses a fixed number of records + * in memory at all times. Since we are dealing with tuples that may vary + * considerably in size, we want to be able to vary the number of records + * kept in memory to ensure full utilization of the allowed sort memory + * space. So, we keep the tuples in a variable-size heap, with the next + * record to go out at the top of the heap. Like Algorithm 5.4.1R, each + * record is stored with the run number that it must go into, and we use + * (run number, key) as the ordering key for the heap. When the run number + * at the top of the heap changes, we know that no more records of the prior + * run are left in the heap. Note that there are in practice only ever two + * distinct run numbers, because since PostgreSQL 9.6, we only use + * replacement selection to form the first run. * * In PostgreSQL 9.6, a heap (based on Knuth's Algorithm H, with some small * customizations) is only used with the aim of producing just one run, @@ -69,25 +69,25 @@ * using Algorithm D. * * When merging runs, we use a heap containing just the frontmost tuple from - * each source run; we repeatedly output the smallest tuple and insert the - * next tuple from its source tape (if any). When the heap empties, the merge - * is complete. The basic merge algorithm thus needs very little memory --- - * only M tuples for an M-way merge, and M is constrained to a small number. - * However, we can still make good use of our full workMem allocation by - * pre-reading additional tuples from each source tape. Without prereading, - * our access pattern to the temporary file would be very erratic; on average - * we'd read one block from each of M source tapes during the same time that - * we're writing M blocks to the output tape, so there is no sequentiality of - * access at all, defeating the read-ahead methods used by most Unix kernels. - * Worse, the output tape gets written into a very random sequence of blocks - * of the temp file, ensuring that things will be even worse when it comes - * time to read that tape. A straightforward merge pass thus ends up doing a - * lot of waiting for disk seeks. We can improve matters by prereading from - * each source tape sequentially, loading about workMem/M bytes from each tape - * in turn. Then we run the merge algorithm, writing but not reading until - * one of the preloaded tuple series runs out. Then we switch back to preread - * mode, fill memory again, and repeat. This approach helps to localize both - * read and write accesses. + * each source run; we repeatedly output the smallest tuple and replace it + * with the next tuple from its source tape (if any). When the heap empties, + * the merge is complete. The basic merge algorithm thus needs very little + * memory --- only M tuples for an M-way merge, and M is constrained to a + * small number. However, we can still make good use of our full workMem + * allocation by pre-reading additional blocks from each source tape. Without + * prereading, our access pattern to the temporary file would be very erratic; + * on average we'd read one block from each of M source tapes during the same + * time that we're writing M blocks to the output tape, so there is no + * sequentiality of access at all, defeating the read-ahead methods used by + * most Unix kernels. Worse, the output tape gets written into a very random + * sequence of blocks of the temp file, ensuring that things will be even + * worse when it comes time to read that tape. A straightforward merge pass + * thus ends up doing a lot of waiting for disk seeks. We can improve matters + * by prereading from each source tape sequentially, loading about workMem/M + * bytes from each tape in turn, and making the sequential blocks immediately + * available for reuse. This approach helps to localize both read and write + * accesses. The pre-reading is handled by logtape.c, we just tell it how + * much memory to use for the buffers. * * When the caller requests random access to the sort result, we form * the final sorted run on a logical tape which is then "frozen", so @@ -108,10 +108,11 @@ * code we determine the number of tapes M on the basis of workMem: we want * workMem/M to be large enough that we read a fair amount of data each time * we preread from a tape, so as to maintain the locality of access described - * above. Nonetheless, with large workMem we can have many tapes. + * above. Nonetheless, with large workMem we can have many tapes (but not + * too many -- see the comments in tuplesort_merge_order). * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -162,9 +163,9 @@ bool optimize_bounded_sort = true; * The objects we actually sort are SortTuple structs. These contain * a pointer to the tuple proper (might be a MinimalTuple or IndexTuple), * which is a separate palloc chunk --- we assume it is just one chunk and - * can be freed by a simple pfree() (except during final on-the-fly merge, - * when memory is used in batch). SortTuples also contain the tuple's - * first key column in Datum/nullflag format, and an index integer. + * can be freed by a simple pfree() (except during merge, when we use a + * simple slab allocator). SortTuples also contain the tuple's first key + * column in Datum/nullflag format, and an index integer. * * Storing the first key column lets us save heap_getattr or index_getattr * calls during tuple comparisons. We could extract and save all the key @@ -191,9 +192,8 @@ bool optimize_bounded_sort = true; * it now only distinguishes RUN_FIRST and HEAP_RUN_NEXT, since replacement * selection is always abandoned after the first run; no other run number * should be represented here. During merge passes, we re-use it to hold the - * input tape number that each tuple in the heap was read from, or to hold the - * index of the next tuple pre-read from the same tape in the case of pre-read - * entries. tupindex goes unused if the sort occurs entirely in memory. + * input tape number that each tuple in the heap was read from. tupindex goes + * unused if the sort occurs entirely in memory. */ typedef struct { @@ -203,6 +203,24 @@ typedef struct int tupindex; /* see notes above */ } SortTuple; +/* + * During merge, we use a pre-allocated set of fixed-size slots to hold + * tuples. To avoid palloc/pfree overhead. + * + * Merge doesn't require a lot of memory, so we can afford to waste some, + * by using gratuitously-sized slots. If a tuple is larger than 1 kB, the + * palloc() overhead is not significant anymore. + * + * 'nextfree' is valid when this chunk is in the free list. When in use, the + * slot holds a tuple. + */ +#define SLAB_SLOT_SIZE 1024 + +typedef union SlabSlot +{ + union SlabSlot *nextfree; + char buffer[SLAB_SLOT_SIZE]; +} SlabSlot; /* * Possible states of a Tuplesort object. These denote the states that @@ -222,15 +240,16 @@ typedef enum * Parameters for calculation of number of tapes to use --- see inittapes() * and tuplesort_merge_order(). * - * In this calculation we assume that each tape will cost us about 3 blocks - * worth of buffer space (which is an underestimate for very large data - * volumes, but it's probably close enough --- see logtape.c). + * In this calculation we assume that each tape will cost us about 1 blocks + * worth of buffer space. This ignores the overhead of all the other data + * structures needed for each tape, but it's probably close enough. * * MERGE_BUFFER_SIZE is how much data we'd like to read from each input * tape during a preread cycle (see discussion at top of file). */ #define MINORDER 6 /* minimum merge order */ -#define TAPE_BUFFER_OVERHEAD (BLCKSZ * 3) +#define MAXORDER 500 /* maximum merge order */ +#define TAPE_BUFFER_OVERHEAD BLCKSZ #define MERGE_BUFFER_SIZE (BLCKSZ * 32) /* @@ -288,41 +307,28 @@ struct Tuplesortstate /* * Function to write a stored tuple onto tape. The representation of the * tuple on tape need not be the same as it is in memory; requirements on - * the tape representation are given below. After writing the tuple, - * pfree() the out-of-line data (not the SortTuple struct!), and increase - * state->availMem by the amount of memory space thereby released. + * the tape representation are given below. Unless the slab allocator is + * used, after writing the tuple, pfree() the out-of-line data (not the + * SortTuple struct!), and increase state->availMem by the amount of + * memory space thereby released. */ void (*writetup) (Tuplesortstate *state, int tapenum, SortTuple *stup); /* * Function to read a stored tuple from tape back into memory. 'len' is - * the already-read length of the stored tuple. Create a palloc'd copy, - * initialize tuple/datum1/isnull1 in the target SortTuple struct, and - * decrease state->availMem by the amount of memory space consumed. (See - * batchUsed notes for details on how memory is handled when incremental - * accounting is abandoned.) + * the already-read length of the stored tuple. The tuple is allocated + * from the slab memory arena, or is palloc'd, see readtup_alloc(). */ void (*readtup) (Tuplesortstate *state, SortTuple *stup, int tapenum, unsigned int len); - /* - * Function to move a caller tuple. This is usually implemented as a - * memmove() shim, but function may also perform additional fix-up of - * caller tuple where needed. Batch memory support requires the movement - * of caller tuples from one location in memory to another. - */ - void (*movetup) (void *dest, void *src, unsigned int len); - /* * This array holds the tuples now in sort memory. If we are in state * INITIAL, the tuples are in no particular order; if we are in state * SORTEDINMEM, the tuples are in final sorted order; in states BUILDRUNS * and FINALMERGE, the tuples are organized in "heap" order per Algorithm - * H. (Note that memtupcount only counts the tuples that are part of the - * heap --- during merge passes, memtuples[] entries beyond tapeRange are - * never in the heap and are used to hold pre-read tuples.) In state - * SORTEDONTAPE, the array is not used. + * H. In state SORTEDONTAPE, the array is not used. */ SortTuple *memtuples; /* array of SortTuple structs */ int memtupcount; /* number of tuples currently present */ @@ -330,13 +336,48 @@ struct Tuplesortstate bool growmemtuples; /* memtuples' growth still underway? */ /* - * Memory for tuples is sometimes allocated in batch, rather than - * incrementally. This implies that incremental memory accounting has - * been abandoned. Currently, this only happens for the final on-the-fly - * merge step. Large batch allocations can store tuples (e.g. - * IndexTuples) without palloc() fragmentation and other overhead. + * Memory for tuples is sometimes allocated using a simple slab allocator, + * rather than with palloc(). Currently, we switch to slab allocation + * when we start merging. Merging only needs to keep a small, fixed + * number of tuples in memory at any time, so we can avoid the + * palloc/pfree overhead by recycling a fixed number of fixed-size slots + * to hold the tuples. + * + * For the slab, we use one large allocation, divided into SLAB_SLOT_SIZE + * slots. The allocation is sized to have one slot per tape, plus one + * additional slot. We need that many slots to hold all the tuples kept + * in the heap during merge, plus the one we have last returned from the + * sort, with tuplesort_gettuple. + * + * Initially, all the slots are kept in a linked list of free slots. When + * a tuple is read from a tape, it is put to the next available slot, if + * it fits. If the tuple is larger than SLAB_SLOT_SIZE, it is palloc'd + * instead. + * + * When we're done processing a tuple, we return the slot back to the free + * list, or pfree() if it was palloc'd. We know that a tuple was + * allocated from the slab, if its pointer value is between + * slabMemoryBegin and -End. + * + * When the slab allocator is used, the USEMEM/LACKMEM mechanism of + * tracking memory usage is not used. + */ + bool slabAllocatorUsed; + + char *slabMemoryBegin; /* beginning of slab memory arena */ + char *slabMemoryEnd; /* end of slab memory arena */ + SlabSlot *slabFreeHead; /* head of free list */ + + /* Buffer size to use for reading input tapes, during merge. */ + size_t read_buffer_size; + + /* + * When we return a tuple to the caller in tuplesort_gettuple_XXX, that + * came from a tape (that is, in TSS_SORTEDONTAPE or TSS_FINALMERGE + * modes), we remember the tuple in 'lastReturnedTuple', so that we can + * recycle the memory on next gettuple call. */ - bool batchUsed; + void *lastReturnedTuple; /* * While building initial runs, this indicates if the replacement @@ -358,42 +399,11 @@ struct Tuplesortstate */ /* - * These variables are only used during merge passes. mergeactive[i] is - * true if we are reading an input run from (actual) tape number i and - * have not yet exhausted that run. mergenext[i] is the memtuples index - * of the next pre-read tuple (next to be loaded into the heap) for tape - * i, or 0 if we are out of pre-read tuples. mergelast[i] similarly - * points to the last pre-read tuple from each tape. mergeavailslots[i] - * is the number of unused memtuples[] slots reserved for tape i, and - * mergeavailmem[i] is the amount of unused space allocated for tape i. - * mergefreelist and mergefirstfree keep track of unused locations in the - * memtuples[] array. The memtuples[].tupindex fields link together - * pre-read tuples for each tape as well as recycled locations in - * mergefreelist. It is OK to use 0 as a null link in these lists, because - * memtuples[0] is part of the merge heap and is never a pre-read tuple. + * This variable is only used during merge passes. mergeactive[i] is true + * if we are reading an input run from (actual) tape number i and have not + * yet exhausted that run. */ bool *mergeactive; /* active input run source? */ - int *mergenext; /* first preread tuple for each source */ - int *mergelast; /* last preread tuple for each source */ - int *mergeavailslots; /* slots left for prereading each tape */ - int64 *mergeavailmem; /* availMem for prereading each tape */ - int mergefreelist; /* head of freelist of recycled slots */ - int mergefirstfree; /* first slot never used in this merge */ - - /* - * Per-tape batch state, when final on-the-fly merge consumes memory from - * just a few large allocations. - * - * Aside from the general benefits of performing fewer individual retail - * palloc() calls, this also helps make merging more cache efficient, - * since each tape's tuples must naturally be accessed sequentially (in - * sorted order). - */ - int64 spacePerTape; /* Space (memory) for tuples (not slots) */ - char **mergetuples; /* Each tape's memory allocation */ - char **mergecurrent; /* Current offset into each tape's memory */ - char **mergetail; /* Last item's start point for each tape */ - char **mergeoverflow; /* Retail palloc() "overflow" for each tape */ /* * Variables for Algorithm D. Note that destTape is a "logical" tape @@ -481,12 +491,34 @@ struct Tuplesortstate #endif }; +/* + * Is the given tuple allocated from the slab memory arena? + */ +#define IS_SLAB_SLOT(state, tuple) \ + ((char *) (tuple) >= (state)->slabMemoryBegin && \ + (char *) (tuple) < (state)->slabMemoryEnd) + +/* + * Return the given tuple to the slab memory free list, or free it + * if it was palloc'd. + */ +#define RELEASE_SLAB_SLOT(state, tuple) \ + do { \ + SlabSlot *buf = (SlabSlot *) tuple; \ + \ + if (IS_SLAB_SLOT((state), buf)) \ + { \ + buf->nextfree = (state)->slabFreeHead; \ + (state)->slabFreeHead = buf; \ + } else \ + pfree(buf); \ + } while(0) + #define COMPARETUP(state,a,b) ((*(state)->comparetup) (a, b, state)) #define COPYTUP(state,stup,tup) ((*(state)->copytup) (state, stup, tup)) #define WRITETUP(state,tape,stup) ((*(state)->writetup) (state, tape, stup)) #define READTUP(state,stup,tape,len) ((*(state)->readtup) (state, stup, tape, len)) -#define MOVETUP(dest,src,len) ((*(state)->movetup) (dest, src, len)) -#define LACKMEM(state) ((state)->availMem < 0 && !(state)->batchUsed) +#define LACKMEM(state) ((state)->availMem < 0 && !(state)->slabAllocatorUsed) #define USEMEM(state,amt) ((state)->availMem -= (amt)) #define FREEMEM(state,amt) ((state)->availMem += (amt)) @@ -551,30 +583,25 @@ static bool consider_abort_common(Tuplesortstate *state); static bool useselection(Tuplesortstate *state); static void inittapes(Tuplesortstate *state); static void selectnewtape(Tuplesortstate *state); +static void init_slab_allocator(Tuplesortstate *state, int numSlots); static void mergeruns(Tuplesortstate *state); static void mergeonerun(Tuplesortstate *state); -static void beginmerge(Tuplesortstate *state, bool finalMergeBatch); -static void batchmemtuples(Tuplesortstate *state); -static void mergebatch(Tuplesortstate *state, int64 spacePerTape); -static void mergebatchone(Tuplesortstate *state, int srcTape, - SortTuple *stup, bool *should_free); -static void mergebatchfreetape(Tuplesortstate *state, int srcTape, - SortTuple *rtup, bool *should_free); -static void *mergebatchalloc(Tuplesortstate *state, int tapenum, Size tuplen); -static void mergepreread(Tuplesortstate *state); -static void mergeprereadone(Tuplesortstate *state, int srcTape); +static void beginmerge(Tuplesortstate *state); +static bool mergereadnext(Tuplesortstate *state, int srcTape, SortTuple *stup); static void dumptuples(Tuplesortstate *state, bool alltuples); static void dumpbatch(Tuplesortstate *state, bool alltuples); static void make_bounded_heap(Tuplesortstate *state); static void sort_bounded_heap(Tuplesortstate *state); static void tuplesort_sort_memtuples(Tuplesortstate *state); static void tuplesort_heap_insert(Tuplesortstate *state, SortTuple *tuple, - int tupleindex, bool checkIndex); -static void tuplesort_heap_siftup(Tuplesortstate *state, bool checkIndex); + bool checkIndex); +static void tuplesort_heap_replace_top(Tuplesortstate *state, SortTuple *tuple, + bool checkIndex); +static void tuplesort_heap_delete_top(Tuplesortstate *state, bool checkIndex); static void reversedirection(Tuplesortstate *state); static unsigned int getlen(Tuplesortstate *state, int tapenum, bool eofOK); static void markrunend(Tuplesortstate *state, int tapenum); -static void *readtup_alloc(Tuplesortstate *state, int tapenum, Size tuplen); +static void *readtup_alloc(Tuplesortstate *state, Size tuplen); static int comparetup_heap(const SortTuple *a, const SortTuple *b, Tuplesortstate *state); static void copytup_heap(Tuplesortstate *state, SortTuple *stup, void *tup); @@ -582,7 +609,6 @@ static void writetup_heap(Tuplesortstate *state, int tapenum, SortTuple *stup); static void readtup_heap(Tuplesortstate *state, SortTuple *stup, int tapenum, unsigned int len); -static void movetup_heap(void *dest, void *src, unsigned int len); static int comparetup_cluster(const SortTuple *a, const SortTuple *b, Tuplesortstate *state); static void copytup_cluster(Tuplesortstate *state, SortTuple *stup, void *tup); @@ -590,7 +616,6 @@ static void writetup_cluster(Tuplesortstate *state, int tapenum, SortTuple *stup); static void readtup_cluster(Tuplesortstate *state, SortTuple *stup, int tapenum, unsigned int len); -static void movetup_cluster(void *dest, void *src, unsigned int len); static int comparetup_index_btree(const SortTuple *a, const SortTuple *b, Tuplesortstate *state); static int comparetup_index_hash(const SortTuple *a, const SortTuple *b, @@ -600,7 +625,6 @@ static void writetup_index(Tuplesortstate *state, int tapenum, SortTuple *stup); static void readtup_index(Tuplesortstate *state, SortTuple *stup, int tapenum, unsigned int len); -static void movetup_index(void *dest, void *src, unsigned int len); static int comparetup_datum(const SortTuple *a, const SortTuple *b, Tuplesortstate *state); static void copytup_datum(Tuplesortstate *state, SortTuple *stup, void *tup); @@ -608,7 +632,6 @@ static void writetup_datum(Tuplesortstate *state, int tapenum, SortTuple *stup); static void readtup_datum(Tuplesortstate *state, SortTuple *stup, int tapenum, unsigned int len); -static void movetup_datum(void *dest, void *src, unsigned int len); static void free_sort_tuple(Tuplesortstate *state, SortTuple *stup); /* @@ -654,9 +677,7 @@ tuplesort_begin_common(int workMem, bool randomAccess) */ sortcontext = AllocSetContextCreate(CurrentMemoryContext, "TupleSort main", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* * Caller tuple (e.g. IndexTuple) memory context. @@ -669,9 +690,7 @@ tuplesort_begin_common(int workMem, bool randomAccess) */ tuplecontext = AllocSetContextCreate(sortcontext, "Caller tuples", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); /* * Make the Tuplesortstate within the per-sort context. This way, we @@ -707,7 +726,7 @@ tuplesort_begin_common(int workMem, bool randomAccess) ALLOCSET_SEPARATE_THRESHOLD / sizeof(SortTuple) + 1); state->growmemtuples = true; - state->batchUsed = false; + state->slabAllocatorUsed = false; state->memtuples = (SortTuple *) palloc(state->memtupsize * sizeof(SortTuple)); USEMEM(state, GetMemoryChunkSpace(state->memtuples)); @@ -764,7 +783,6 @@ tuplesort_begin_heap(TupleDesc tupDesc, state->copytup = copytup_heap; state->writetup = writetup_heap; state->readtup = readtup_heap; - state->movetup = movetup_heap; state->tupDesc = tupDesc; /* assume we need not copy tupDesc */ state->abbrevNext = 10; @@ -837,7 +855,6 @@ tuplesort_begin_cluster(TupleDesc tupDesc, state->copytup = copytup_cluster; state->writetup = writetup_cluster; state->readtup = readtup_cluster; - state->movetup = movetup_cluster; state->abbrevNext = 10; state->indexInfo = BuildIndexInfo(indexRel); @@ -929,7 +946,6 @@ tuplesort_begin_index_btree(Relation heapRel, state->copytup = copytup_index; state->writetup = writetup_index; state->readtup = readtup_index; - state->movetup = movetup_index; state->abbrevNext = 10; state->heapRel = heapRel; @@ -997,7 +1013,6 @@ tuplesort_begin_index_hash(Relation heapRel, state->copytup = copytup_index; state->writetup = writetup_index; state->readtup = readtup_index; - state->movetup = movetup_index; state->heapRel = heapRel; state->indexRel = indexRel; @@ -1040,7 +1055,6 @@ tuplesort_begin_datum(Oid datumType, Oid sortOperator, Oid sortCollation, state->copytup = copytup_datum; state->writetup = writetup_datum; state->readtup = readtup_datum; - state->movetup = movetup_datum; state->abbrevNext = 10; state->datumType = datumType; @@ -1443,7 +1457,7 @@ tuplesort_putindextuplevalues(Tuplesortstate *state, Relation rel, mtup->datum1 = index_getattr(tuple, 1, RelationGetDescr(state->indexRel), - &stup.isnull1); + &mtup->isnull1); } } @@ -1621,10 +1635,10 @@ puttuple_common(Tuplesortstate *state, SortTuple *tuple) } else { - /* discard top of heap, sift up, insert new tuple */ + /* discard top of heap, replacing it with the new tuple */ free_sort_tuple(state, &state->memtuples[0]); - tuplesort_heap_siftup(state, false); - tuplesort_heap_insert(state, tuple, 0, false); + tuple->tupindex = 0; /* not used */ + tuplesort_heap_replace_top(state, tuple, false); } break; @@ -1669,7 +1683,8 @@ puttuple_common(Tuplesortstate *state, SortTuple *tuple) * initial COMPARETUP() call is required for the tuple, to * determine that the tuple does not belong in RUN_FIRST). */ - tuplesort_heap_insert(state, tuple, state->currentRun, true); + tuple->tupindex = state->currentRun; + tuplesort_heap_insert(state, tuple, true); } else { @@ -1826,21 +1841,21 @@ tuplesort_performsort(Tuplesortstate *state) /* * Internal routine to fetch the next tuple in either forward or back * direction into *stup. Returns FALSE if no more tuples. - * If *should_free is set, the caller must pfree stup.tuple when done with it. - * Otherwise, caller should not use tuple following next call here. + * Returned tuple belongs to tuplesort memory context, and must not be freed + * by caller. Caller should not use tuple following next call here. */ static bool tuplesort_gettuple_common(Tuplesortstate *state, bool forward, - SortTuple *stup, bool *should_free) + SortTuple *stup) { unsigned int tuplen; + size_t nmoved; switch (state->status) { case TSS_SORTEDINMEM: Assert(forward || state->randomAccess); - Assert(!state->batchUsed); - *should_free = false; + Assert(!state->slabAllocatorUsed); if (forward) { if (state->current < state->memtupcount) @@ -1884,15 +1899,34 @@ tuplesort_gettuple_common(Tuplesortstate *state, bool forward, case TSS_SORTEDONTAPE: Assert(forward || state->randomAccess); - Assert(!state->batchUsed); - *should_free = true; + Assert(state->slabAllocatorUsed); + + /* + * The slot that held the tuple that we returned in previous + * gettuple call can now be reused. + */ + if (state->lastReturnedTuple) + { + RELEASE_SLAB_SLOT(state, state->lastReturnedTuple); + state->lastReturnedTuple = NULL; + } + if (forward) { if (state->eof_reached) return false; + if ((tuplen = getlen(state, state->result_tape, true)) != 0) { READTUP(state, stup, state->result_tape, tuplen); + + /* + * Remember the tuple we return, so that we can recycle + * its memory on next call. (This can be NULL, in the + * !state->tuples case). + */ + state->lastReturnedTuple = stup->tuple; + return true; } else @@ -1915,10 +1949,13 @@ tuplesort_gettuple_common(Tuplesortstate *state, bool forward, * end of file; back up to fetch last tuple's ending length * word. If seek fails we must have a completely empty file. */ - if (!LogicalTapeBackspace(state->tapeset, - state->result_tape, - 2 * sizeof(unsigned int))) + nmoved = LogicalTapeBackspace(state->tapeset, + state->result_tape, + 2 * sizeof(unsigned int)); + if (nmoved == 0) return false; + else if (nmoved != 2 * sizeof(unsigned int)) + elog(ERROR, "unexpected tape position"); state->eof_reached = false; } else @@ -1927,31 +1964,34 @@ tuplesort_gettuple_common(Tuplesortstate *state, bool forward, * Back up and fetch previously-returned tuple's ending length * word. If seek fails, assume we are at start of file. */ - if (!LogicalTapeBackspace(state->tapeset, - state->result_tape, - sizeof(unsigned int))) + nmoved = LogicalTapeBackspace(state->tapeset, + state->result_tape, + sizeof(unsigned int)); + if (nmoved == 0) return false; + else if (nmoved != sizeof(unsigned int)) + elog(ERROR, "unexpected tape position"); tuplen = getlen(state, state->result_tape, false); /* * Back up to get ending length word of tuple before it. */ - if (!LogicalTapeBackspace(state->tapeset, - state->result_tape, - tuplen + 2 * sizeof(unsigned int))) + nmoved = LogicalTapeBackspace(state->tapeset, + state->result_tape, + tuplen + 2 * sizeof(unsigned int)); + if (nmoved == tuplen + sizeof(unsigned int)) { /* - * If that fails, presumably the prev tuple is the first - * in the file. Back up so that it becomes next to read - * in forward direction (not obviously right, but that is - * what in-memory case does). + * We backed up over the previous tuple, but there was no + * ending length word before it. That means that the prev + * tuple is the first tuple in the file. It is now the + * next to read in forward direction (not obviously right, + * but that is what in-memory case does). */ - if (!LogicalTapeBackspace(state->tapeset, - state->result_tape, - tuplen + sizeof(unsigned int))) - elog(ERROR, "bogus tuple length in backward scan"); return false; } + else if (nmoved != tuplen + 2 * sizeof(unsigned int)) + elog(ERROR, "bogus tuple length in backward scan"); } tuplen = getlen(state, state->result_tape, false); @@ -1961,18 +2001,35 @@ tuplesort_gettuple_common(Tuplesortstate *state, bool forward, * Note: READTUP expects we are positioned after the initial * length word of the tuple, so back up to that point. */ - if (!LogicalTapeBackspace(state->tapeset, - state->result_tape, - tuplen)) + nmoved = LogicalTapeBackspace(state->tapeset, + state->result_tape, + tuplen); + if (nmoved != tuplen) elog(ERROR, "bogus tuple length in backward scan"); READTUP(state, stup, state->result_tape, tuplen); + + /* + * Remember the tuple we return, so that we can recycle its memory + * on next call. (This can be NULL, in the Datum case). + */ + state->lastReturnedTuple = stup->tuple; + return true; case TSS_FINALMERGE: Assert(forward); - Assert(state->batchUsed || !state->tuples); - /* For now, assume tuple is stored in tape's batch memory */ - *should_free = false; + /* We are managing memory ourselves, with the slab allocator. */ + Assert(state->slabAllocatorUsed); + + /* + * The slab slot holding the tuple that we returned in previous + * gettuple call can now be reused. + */ + if (state->lastReturnedTuple) + { + RELEASE_SLAB_SLOT(state, state->lastReturnedTuple); + state->lastReturnedTuple = NULL; + } /* * This code should match the inner loop of mergeonerun(). @@ -1980,54 +2037,38 @@ tuplesort_gettuple_common(Tuplesortstate *state, bool forward, if (state->memtupcount > 0) { int srcTape = state->memtuples[0].tupindex; - int tupIndex; - SortTuple *newtup; + SortTuple newtup; + + *stup = state->memtuples[0]; /* - * Returned tuple is still counted in our memory space most of - * the time. See mergebatchone() for discussion of why caller - * may occasionally be required to free returned tuple, and - * how preread memory is managed with regard to edge cases - * more generally. + * Remember the tuple we return, so that we can recycle its + * memory on next call. (This can be NULL, in the Datum case). */ - *stup = state->memtuples[0]; - tuplesort_heap_siftup(state, false); - if ((tupIndex = state->mergenext[srcTape]) == 0) + state->lastReturnedTuple = stup->tuple; + + /* + * Pull next tuple from tape, and replace the returned tuple + * at top of the heap with it. + */ + if (!mergereadnext(state, srcTape, &newtup)) { /* - * out of preloaded data on this tape, try to read more - * - * Unlike mergeonerun(), we only preload from the single - * tape that's run dry, though not before preparing its - * batch memory for a new round of sequential consumption. - * See mergepreread() comments. + * If no more data, we've reached end of run on this tape. + * Remove the top node from the heap. */ - if (state->batchUsed) - mergebatchone(state, srcTape, stup, should_free); - - mergeprereadone(state, srcTape); + tuplesort_heap_delete_top(state, false); /* - * if still no data, we've reached end of run on this tape + * Rewind to free the read buffer. It'd go away at the + * end of the sort anyway, but better to release the + * memory early. */ - if ((tupIndex = state->mergenext[srcTape]) == 0) - { - /* Free tape's buffer, avoiding dangling pointer */ - if (state->batchUsed) - mergebatchfreetape(state, srcTape, stup, should_free); - return true; - } + LogicalTapeRewindForWrite(state->tapeset, srcTape); + return true; } - /* pull next preread tuple from list, insert in heap */ - newtup = &state->memtuples[tupIndex]; - state->mergenext[srcTape] = newtup->tupindex; - if (state->mergenext[srcTape] == 0) - state->mergelast[srcTape] = 0; - tuplesort_heap_insert(state, newtup, srcTape, false); - /* put the now-unused memtuples entry on the freelist */ - newtup->tupindex = state->mergefreelist; - state->mergefreelist = tupIndex; - state->mergeavailslots[srcTape]++; + newtup.tupindex = srcTape; + tuplesort_heap_replace_top(state, &newtup, false); return true; } return false; @@ -2049,6 +2090,10 @@ tuplesort_gettuple_common(Tuplesortstate *state, bool forward, * determination of "non-equal tuple" based on simple binary inequality. A * NULL value in leading attribute will set abbreviated value to zeroed * representation, which caller may rely on in abbreviated inequality check. + * + * The slot receives a copied tuple (sometimes allocated in caller memory + * context) that will stay valid regardless of future manipulations of the + * tuplesort's state. */ bool tuplesort_gettupleslot(Tuplesortstate *state, bool forward, @@ -2056,9 +2101,8 @@ tuplesort_gettupleslot(Tuplesortstate *state, bool forward, { MemoryContext oldcontext = MemoryContextSwitchTo(state->sortcontext); SortTuple stup; - bool should_free; - if (!tuplesort_gettuple_common(state, forward, &stup, &should_free)) + if (!tuplesort_gettuple_common(state, forward, &stup)) stup.tuple = NULL; MemoryContextSwitchTo(oldcontext); @@ -2069,7 +2113,8 @@ tuplesort_gettupleslot(Tuplesortstate *state, bool forward, if (state->sortKeys->abbrev_converter && abbrev) *abbrev = stup.datum1; - ExecStoreMinimalTuple((MinimalTuple) stup.tuple, slot, should_free); + stup.tuple = heap_copy_minimal_tuple((MinimalTuple) stup.tuple); + ExecStoreMinimalTuple((MinimalTuple) stup.tuple, slot, true); return true; } else @@ -2081,18 +2126,17 @@ tuplesort_gettupleslot(Tuplesortstate *state, bool forward, /* * Fetch the next tuple in either forward or back direction. - * Returns NULL if no more tuples. If *should_free is set, the - * caller must pfree the returned tuple when done with it. - * If it is not set, caller should not use tuple following next - * call here. + * Returns NULL if no more tuples. Returned tuple belongs to tuplesort memory + * context, and must not be freed by caller. Caller should not use tuple + * following next call here. */ HeapTuple -tuplesort_getheaptuple(Tuplesortstate *state, bool forward, bool *should_free) +tuplesort_getheaptuple(Tuplesortstate *state, bool forward) { MemoryContext oldcontext = MemoryContextSwitchTo(state->sortcontext); SortTuple stup; - if (!tuplesort_gettuple_common(state, forward, &stup, should_free)) + if (!tuplesort_gettuple_common(state, forward, &stup)) stup.tuple = NULL; MemoryContextSwitchTo(oldcontext); @@ -2102,19 +2146,17 @@ tuplesort_getheaptuple(Tuplesortstate *state, bool forward, bool *should_free) /* * Fetch the next index tuple in either forward or back direction. - * Returns NULL if no more tuples. If *should_free is set, the - * caller must pfree the returned tuple when done with it. - * If it is not set, caller should not use tuple following next - * call here. + * Returns NULL if no more tuples. Returned tuple belongs to tuplesort memory + * context, and must not be freed by caller. Caller should not use tuple + * following next call here. */ IndexTuple -tuplesort_getindextuple(Tuplesortstate *state, bool forward, - bool *should_free) +tuplesort_getindextuple(Tuplesortstate *state, bool forward) { MemoryContext oldcontext = MemoryContextSwitchTo(state->sortcontext); SortTuple stup; - if (!tuplesort_gettuple_common(state, forward, &stup, should_free)) + if (!tuplesort_gettuple_common(state, forward, &stup)) stup.tuple = NULL; MemoryContextSwitchTo(oldcontext); @@ -2127,7 +2169,8 @@ tuplesort_getindextuple(Tuplesortstate *state, bool forward, * Returns FALSE if no more datums. * * If the Datum is pass-by-ref type, the returned value is freshly palloc'd - * and is now owned by the caller. + * and is now owned by the caller (this differs from similar routines for + * other types of tuplesorts). * * Caller may optionally be passed back abbreviated value (on TRUE return * value) when abbreviation was used, which can be used to cheaply avoid @@ -2142,9 +2185,8 @@ tuplesort_getdatum(Tuplesortstate *state, bool forward, { MemoryContext oldcontext = MemoryContextSwitchTo(state->sortcontext); SortTuple stup; - bool should_free; - if (!tuplesort_gettuple_common(state, forward, &stup, &should_free)) + if (!tuplesort_gettuple_common(state, forward, &stup)) { MemoryContextSwitchTo(oldcontext); return false; @@ -2162,11 +2204,7 @@ tuplesort_getdatum(Tuplesortstate *state, bool forward, else { /* use stup.tuple because stup.datum1 may be an abbreviation */ - - if (should_free) - *val = PointerGetDatum(stup.tuple); - else - *val = datumCopy(PointerGetDatum(stup.tuple), false, state->datumTypeLen); + *val = datumCopy(PointerGetDatum(stup.tuple), false, state->datumTypeLen); *isNull = false; } @@ -2224,16 +2262,12 @@ tuplesort_skiptuples(Tuplesortstate *state, int64 ntuples, bool forward) while (ntuples-- > 0) { SortTuple stup; - bool should_free; - if (!tuplesort_gettuple_common(state, forward, - &stup, &should_free)) + if (!tuplesort_gettuple_common(state, forward, &stup)) { MemoryContextSwitchTo(oldcontext); return false; } - if (should_free && stup.tuple) - pfree(stup.tuple); CHECK_FOR_INTERRUPTS(); } MemoryContextSwitchTo(oldcontext); @@ -2269,8 +2303,19 @@ tuplesort_merge_order(int64 allowedMem) mOrder = (allowedMem - TAPE_BUFFER_OVERHEAD) / (MERGE_BUFFER_SIZE + TAPE_BUFFER_OVERHEAD); - /* Even in minimum memory, use at least a MINORDER merge */ + /* + * Even in minimum memory, use at least a MINORDER merge. On the other + * hand, even when we have lots of memory, do not use more than a MAXORDER + * merge. Tapes are pretty cheap, but they're not entirely free. Each + * additional tape reduces the amount of memory available to build runs, + * which in turn can cause the same sort to need more runs, which makes + * merging slower even if it can still be done in a single pass. Also, + * high order merges are quite slow due to CPU cache effects; it can be + * faster to pay the I/O cost of a polyphase merge than to perform a single + * merge pass across many hundreds of tapes. + */ mOrder = Max(mOrder, MINORDER); + mOrder = Min(mOrder, MAXORDER); return mOrder; } @@ -2312,13 +2357,6 @@ inittapes(Tuplesortstate *state) /* Compute number of tapes to use: merge order plus 1 */ maxTapes = tuplesort_merge_order(state->allowedMem) + 1; - /* - * We must have at least 2*maxTapes slots in the memtuples[] array, else - * we'd not have room for merge heap plus preread. It seems unlikely that - * this case would ever occur, but be safe. - */ - maxTapes = Min(maxTapes, state->memtupsize / 2); - state->maxTapes = maxTapes; state->tapeRange = maxTapes - 1; @@ -2329,13 +2367,13 @@ inittapes(Tuplesortstate *state) #endif /* - * Decrease availMem to reflect the space needed for tape buffers; but - * don't decrease it to the point that we have no room for tuples. (That - * case is only likely to occur if sorting pass-by-value Datums; in all - * other scenarios the memtuples[] array is unlikely to occupy more than - * half of allowedMem. In the pass-by-value case it's not important to - * account for tuple space, so we don't care if LACKMEM becomes - * inaccurate.) + * Decrease availMem to reflect the space needed for tape buffers, when + * writing the initial runs; but don't decrease it to the point that we + * have no room for tuples. (That case is only likely to occur if sorting + * pass-by-value Datums; in all other scenarios the memtuples[] array is + * unlikely to occupy more than half of allowedMem. In the pass-by-value + * case it's not important to account for tuple space, so we don't care if + * LACKMEM becomes inaccurate.) */ tapeSpace = (int64) maxTapes *TAPE_BUFFER_OVERHEAD; @@ -2354,14 +2392,6 @@ inittapes(Tuplesortstate *state) state->tapeset = LogicalTapeSetCreate(maxTapes); state->mergeactive = (bool *) palloc0(maxTapes * sizeof(bool)); - state->mergenext = (int *) palloc0(maxTapes * sizeof(int)); - state->mergelast = (int *) palloc0(maxTapes * sizeof(int)); - state->mergeavailslots = (int *) palloc0(maxTapes * sizeof(int)); - state->mergeavailmem = (int64 *) palloc0(maxTapes * sizeof(int64)); - state->mergetuples = (char **) palloc0(maxTapes * sizeof(char *)); - state->mergecurrent = (char **) palloc0(maxTapes * sizeof(char *)); - state->mergetail = (char **) palloc0(maxTapes * sizeof(char *)); - state->mergeoverflow = (char **) palloc0(maxTapes * sizeof(char *)); state->tp_fib = (int *) palloc0(maxTapes * sizeof(int)); state->tp_runs = (int *) palloc0(maxTapes * sizeof(int)); state->tp_dummy = (int *) palloc0(maxTapes * sizeof(int)); @@ -2398,7 +2428,8 @@ inittapes(Tuplesortstate *state) /* Must copy source tuple to avoid possible overwrite */ SortTuple stup = state->memtuples[j]; - tuplesort_heap_insert(state, &stup, 0, false); + stup.tupindex = RUN_FIRST; + tuplesort_heap_insert(state, &stup, false); } Assert(state->memtupcount == ntuples); } @@ -2459,6 +2490,39 @@ selectnewtape(Tuplesortstate *state) state->destTape = 0; } +/* + * Initialize the slab allocation arena, for the given number of slots. + */ +static void +init_slab_allocator(Tuplesortstate *state, int numSlots) +{ + if (numSlots > 0) + { + char *p; + int i; + + state->slabMemoryBegin = palloc(numSlots * SLAB_SLOT_SIZE); + state->slabMemoryEnd = state->slabMemoryBegin + + numSlots * SLAB_SLOT_SIZE; + state->slabFreeHead = (SlabSlot *) state->slabMemoryBegin; + USEMEM(state, numSlots * SLAB_SLOT_SIZE); + + p = state->slabMemoryBegin; + for (i = 0; i < numSlots - 1; i++) + { + ((SlabSlot *) p)->nextfree = (SlabSlot *) (p + SLAB_SLOT_SIZE); + p += SLAB_SLOT_SIZE; + } + ((SlabSlot *) p)->nextfree = NULL; + } + else + { + state->slabMemoryBegin = state->slabMemoryEnd = NULL; + state->slabFreeHead = NULL; + } + state->slabAllocatorUsed = true; +} + /* * mergeruns -- merge all the completed initial runs. * @@ -2472,6 +2536,8 @@ mergeruns(Tuplesortstate *state) svTape, svRuns, svDummy; + int numTapes; + int numInputTapes; Assert(state->status == TSS_BUILDRUNS); Assert(state->memtupcount == 0); @@ -2492,6 +2558,56 @@ mergeruns(Tuplesortstate *state) state->sortKeys->abbrev_full_comparator = NULL; } + /* + * Reset tuple memory. We've freed all the tuples that we previously + * allocated. We will use the slab allocator from now on. + */ + MemoryContextDelete(state->tuplecontext); + state->tuplecontext = NULL; + + /* + * We no longer need a large memtuples array. (We will allocate a smaller + * one for the heap later.) + */ + FREEMEM(state, GetMemoryChunkSpace(state->memtuples)); + pfree(state->memtuples); + state->memtuples = NULL; + + /* + * If we had fewer runs than tapes, refund the memory that we imagined we + * would need for the tape buffers of the unused tapes. + * + * numTapes and numInputTapes reflect the actual number of tapes we will + * use. Note that the output tape's tape number is maxTapes - 1, so the + * tape numbers of the used tapes are not consecutive, and you cannot just + * loop from 0 to numTapes to visit all used tapes! + */ + if (state->Level == 1) + { + numInputTapes = state->currentRun; + numTapes = numInputTapes + 1; + FREEMEM(state, (state->maxTapes - numTapes) * TAPE_BUFFER_OVERHEAD); + } + else + { + numInputTapes = state->tapeRange; + numTapes = state->maxTapes; + } + + /* + * Initialize the slab allocator. We need one slab slot per input tape, + * for the tuples in the heap, plus one to hold the tuple last returned + * from tuplesort_gettuple. (If we're sorting pass-by-val Datums, + * however, we don't need to do allocate anything.) + * + * From this point on, we no longer use the USEMEM()/LACKMEM() mechanism + * to track memory usage of individual tuples. + */ + if (state->tuples) + init_slab_allocator(state, numInputTapes + 1); + else + init_slab_allocator(state, 0); + /* * If we produced only one initial run (quite likely if the total data * volume is between 1X and 2X workMem when replacement selection is used, @@ -2508,9 +2624,45 @@ mergeruns(Tuplesortstate *state) return; } + /* + * Allocate a new 'memtuples' array, for the heap. It will hold one tuple + * from each input tape. + */ + state->memtupsize = numInputTapes; + state->memtuples = (SortTuple *) palloc(numInputTapes * sizeof(SortTuple)); + USEMEM(state, GetMemoryChunkSpace(state->memtuples)); + + /* + * Use all the remaining memory we have available for read buffers among + * the input tapes. + * + * We do this only after checking for the case that we produced only one + * initial run, because there is no need to use a large read buffer when + * we're reading from a single tape. With one tape, the I/O pattern will + * be the same regardless of the buffer size. + * + * We don't try to "rebalance" the memory among tapes, when we start a new + * merge phase, even if some tapes are inactive in the new phase. That + * would be hard, because logtape.c doesn't know where one run ends and + * another begins. When a new merge phase begins, and a tape doesn't + * participate in it, its buffer nevertheless already contains tuples from + * the next run on same tape, so we cannot release the buffer. That's OK + * in practice, merge performance isn't that sensitive to the amount of + * buffers used, and most merge phases use all or almost all tapes, + * anyway. + */ +#ifdef TRACE_SORT + if (trace_sort) + elog(LOG, "using " INT64_FORMAT " KB of memory for read buffers among %d input tapes", + (state->availMem) / 1024, numInputTapes); +#endif + + state->read_buffer_size = Max(state->availMem / numInputTapes, 0); + USEMEM(state, state->read_buffer_size * numInputTapes); + /* End of step D2: rewind all output tapes to prepare for merging */ for (tapenum = 0; tapenum < state->tapeRange; tapenum++) - LogicalTapeRewind(state->tapeset, tapenum, false); + LogicalTapeRewindForRead(state->tapeset, tapenum, state->read_buffer_size); for (;;) { @@ -2538,7 +2690,7 @@ mergeruns(Tuplesortstate *state) /* Tell logtape.c we won't be writing anymore */ LogicalTapeSetForgetFreeSpace(state->tapeset); /* Initialize for the final merge pass */ - beginmerge(state, state->tuples); + beginmerge(state); state->status = TSS_FINALMERGE; return; } @@ -2573,11 +2725,10 @@ mergeruns(Tuplesortstate *state) if (--state->Level == 0) break; /* rewind output tape T to use as new input */ - LogicalTapeRewind(state->tapeset, state->tp_tapenum[state->tapeRange], - false); + LogicalTapeRewindForRead(state->tapeset, state->tp_tapenum[state->tapeRange], + state->read_buffer_size); /* rewind used-up input tape P, and prepare it for write pass */ - LogicalTapeRewind(state->tapeset, state->tp_tapenum[state->tapeRange - 1], - true); + LogicalTapeRewindForWrite(state->tapeset, state->tp_tapenum[state->tapeRange - 1]); state->tp_runs[state->tapeRange - 1] = 0; /* @@ -2608,6 +2759,13 @@ mergeruns(Tuplesortstate *state) state->result_tape = state->tp_tapenum[state->tapeRange]; LogicalTapeFreeze(state->tapeset, state->result_tape); state->status = TSS_SORTEDONTAPE; + + /* Release the read buffers of all the other tapes, by rewinding them. */ + for (tapenum = 0; tapenum < state->maxTapes; tapenum++) + { + if (tapenum != state->result_tape) + LogicalTapeRewindForWrite(state->tapeset, tapenum); + } } /* @@ -2621,16 +2779,12 @@ mergeonerun(Tuplesortstate *state) { int destTape = state->tp_tapenum[state->tapeRange]; int srcTape; - int tupIndex; - SortTuple *tup; - int64 priorAvail, - spaceFreed; /* * Start the merge by loading one tuple from each active source tape into * the heap. We can also decrease the input run/dummy run counts. */ - beginmerge(state, false); + beginmerge(state); /* * Execute merge by repeatedly extracting lowest tuple in heap, writing it @@ -2639,44 +2793,30 @@ mergeonerun(Tuplesortstate *state) */ while (state->memtupcount > 0) { + SortTuple stup; + /* write the tuple to destTape */ - priorAvail = state->availMem; srcTape = state->memtuples[0].tupindex; WRITETUP(state, destTape, &state->memtuples[0]); - /* writetup adjusted total free space, now fix per-tape space */ - spaceFreed = state->availMem - priorAvail; - state->mergeavailmem[srcTape] += spaceFreed; - /* compact the heap */ - tuplesort_heap_siftup(state, false); - if ((tupIndex = state->mergenext[srcTape]) == 0) + + /* recycle the slot of the tuple we just wrote out, for the next read */ + if (state->memtuples[0].tuple) + RELEASE_SLAB_SLOT(state, state->memtuples[0].tuple); + + /* + * pull next tuple from the tape, and replace the written-out tuple in + * the heap with it. + */ + if (mergereadnext(state, srcTape, &stup)) { - /* out of preloaded data on this tape, try to read more */ - mergepreread(state); - /* if still no data, we've reached end of run on this tape */ - if ((tupIndex = state->mergenext[srcTape]) == 0) - continue; + stup.tupindex = srcTape; + tuplesort_heap_replace_top(state, &stup, false); + } - /* pull next preread tuple from list, insert in heap */ - tup = &state->memtuples[tupIndex]; - state->mergenext[srcTape] = tup->tupindex; - if (state->mergenext[srcTape] == 0) - state->mergelast[srcTape] = 0; - tuplesort_heap_insert(state, tup, srcTape, false); - /* put the now-unused memtuples entry on the freelist */ - tup->tupindex = state->mergefreelist; - state->mergefreelist = tupIndex; - state->mergeavailslots[srcTape]++; + else + tuplesort_heap_delete_top(state, false); } - /* - * Reset tuple memory. We've freed all of the tuples that we previously - * allocated, but AllocSetFree will have put those chunks of memory on - * particular free lists, bucketed by size class. Thus, although all of - * that memory is free, it is effectively fragmented. Resetting the - * context gets us out from under that problem. - */ - MemoryContextReset(state->tuplecontext); - /* * When the heap empties, we're done. Write an end-of-run marker on the * output tape, and increment its count of real runs. @@ -2695,21 +2835,15 @@ mergeonerun(Tuplesortstate *state) * beginmerge - initialize for a merge pass * * We decrease the counts of real and dummy runs for each tape, and mark - * which tapes contain active input runs in mergeactive[]. Then, load - * as many tuples as we can from each active input tape, and finally - * fill the merge heap with the first tuple from each active tape. - * - * finalMergeBatch indicates if this is the beginning of a final on-the-fly - * merge where a batched allocation of tuple memory is required. + * which tapes contain active input runs in mergeactive[]. Then, fill the + * merge heap with the first tuple from each active tape. */ static void -beginmerge(Tuplesortstate *state, bool finalMergeBatch) +beginmerge(Tuplesortstate *state) { int activeTapes; int tapenum; int srcTape; - int slotsPerTape; - int64 spacePerTape; /* Heap should be empty here */ Assert(state->memtupcount == 0); @@ -2731,499 +2865,44 @@ beginmerge(Tuplesortstate *state, bool finalMergeBatch) activeTapes++; } } - state->activeTapes = activeTapes; - - /* Clear merge-pass state variables */ - memset(state->mergenext, 0, - state->maxTapes * sizeof(*state->mergenext)); - memset(state->mergelast, 0, - state->maxTapes * sizeof(*state->mergelast)); - state->mergefreelist = 0; /* nothing in the freelist */ - state->mergefirstfree = activeTapes; /* 1st slot avail for preread */ - - if (finalMergeBatch) - { - /* Free outright buffers for tape never actually allocated */ - FREEMEM(state, (state->maxTapes - activeTapes) * TAPE_BUFFER_OVERHEAD); - - /* - * Grow memtuples one last time, since the palloc() overhead no longer - * incurred can make a big difference - */ - batchmemtuples(state); - } - - /* - * Initialize space allocation to let each active input tape have an equal - * share of preread space. - */ Assert(activeTapes > 0); - slotsPerTape = (state->memtupsize - state->mergefirstfree) / activeTapes; - Assert(slotsPerTape > 0); - spacePerTape = MAXALIGN_DOWN(state->availMem / activeTapes); - for (srcTape = 0; srcTape < state->maxTapes; srcTape++) - { - if (state->mergeactive[srcTape]) - { - state->mergeavailslots[srcTape] = slotsPerTape; - state->mergeavailmem[srcTape] = spacePerTape; - } - } - - /* - * Preallocate tuple batch memory for each tape. This is the memory used - * for tuples themselves (not SortTuples), so it's never used by - * pass-by-value datum sorts. Memory allocation is performed here at most - * once per sort, just in advance of the final on-the-fly merge step. - */ - if (finalMergeBatch) - mergebatch(state, spacePerTape); - - /* - * Preread as many tuples as possible (and at least one) from each active - * tape - */ - mergepreread(state); + state->activeTapes = activeTapes; /* Load the merge heap with the first tuple from each input tape */ for (srcTape = 0; srcTape < state->maxTapes; srcTape++) { - int tupIndex = state->mergenext[srcTape]; - SortTuple *tup; + SortTuple tup; - if (tupIndex) + if (mergereadnext(state, srcTape, &tup)) { - tup = &state->memtuples[tupIndex]; - state->mergenext[srcTape] = tup->tupindex; - if (state->mergenext[srcTape] == 0) - state->mergelast[srcTape] = 0; - tuplesort_heap_insert(state, tup, srcTape, false); - /* put the now-unused memtuples entry on the freelist */ - tup->tupindex = state->mergefreelist; - state->mergefreelist = tupIndex; - state->mergeavailslots[srcTape]++; - -#ifdef TRACE_SORT - if (trace_sort && finalMergeBatch) - { - int64 perTapeKB = (spacePerTape + 1023) / 1024; - int64 usedSpaceKB; - int usedSlots; - - /* - * Report how effective batchmemtuples() was in balancing the - * number of slots against the need for memory for the - * underlying tuples (e.g. IndexTuples). The big preread of - * all tapes when switching to FINALMERGE state should be - * fairly representative of memory utilization during the - * final merge step, and in any case is the only point at - * which all tapes are guaranteed to have depleted either - * their batch memory allowance or slot allowance. Ideally, - * both will be completely depleted for every tape by now. - */ - usedSpaceKB = (state->mergecurrent[srcTape] - - state->mergetuples[srcTape] + 1023) / 1024; - usedSlots = slotsPerTape - state->mergeavailslots[srcTape]; - - elog(LOG, "tape %d initially used " INT64_FORMAT " KB of " - INT64_FORMAT " KB batch (%2.3f) and %d out of %d slots " - "(%2.3f)", srcTape, - usedSpaceKB, perTapeKB, - (double) usedSpaceKB / (double) perTapeKB, - usedSlots, slotsPerTape, - (double) usedSlots / (double) slotsPerTape); - } -#endif + tup.tupindex = srcTape; + tuplesort_heap_insert(state, &tup, false); } } } /* - * batchmemtuples - grow memtuples without palloc overhead + * mergereadnext - read next tuple from one merge input tape * - * When called, availMem should be approximately the amount of memory we'd - * require to allocate memtupsize - memtupcount tuples (not SortTuples/slots) - * that were allocated with palloc() overhead, and in doing so use up all - * allocated slots. However, though slots and tuple memory is in balance - * following the last grow_memtuples() call, that's predicated on the observed - * average tuple size for the "final" grow_memtuples() call, which includes - * palloc overhead. During the final merge pass, where we will arrange to - * squeeze out the palloc overhead, we might need more slots in the memtuples - * array. - * - * To make that happen, arrange for the amount of remaining memory to be - * exactly equal to the palloc overhead multiplied by the current size of - * the memtuples array, force the grow_memtuples flag back to true (it's - * probably but not necessarily false on entry to this routine), and then - * call grow_memtuples. This simulates loading enough tuples to fill the - * whole memtuples array and then having some space left over because of the - * elided palloc overhead. We expect that grow_memtuples() will conclude that - * it can't double the size of the memtuples array but that it can increase - * it by some percentage; but if it does decide to double it, that just means - * that we've never managed to use many slots in the memtuples array, in which - * case doubling it shouldn't hurt anything anyway. + * Returns false on EOF. */ -static void -batchmemtuples(Tuplesortstate *state) -{ - int64 refund; - int64 availMemLessRefund; - int memtupsize = state->memtupsize; - - /* For simplicity, assume no memtuples are actually currently counted */ - Assert(state->memtupcount == 0); - - /* - * Refund STANDARDCHUNKHEADERSIZE per tuple. - * - * This sometimes fails to make memory use perfectly balanced, but it - * should never make the situation worse. Note that Assert-enabled builds - * get a larger refund, due to a varying STANDARDCHUNKHEADERSIZE. - */ - refund = memtupsize * STANDARDCHUNKHEADERSIZE; - availMemLessRefund = state->availMem - refund; - - /* - * To establish balanced memory use after refunding palloc overhead, - * temporarily have our accounting indicate that we've allocated all - * memory we're allowed to less that refund, and call grow_memtuples() to - * have it increase the number of slots. - */ - state->growmemtuples = true; - USEMEM(state, availMemLessRefund); - (void) grow_memtuples(state); - /* Should not matter, but be tidy */ - FREEMEM(state, availMemLessRefund); - state->growmemtuples = false; - -#ifdef TRACE_SORT - if (trace_sort) - { - Size OldKb = (memtupsize * sizeof(SortTuple) + 1023) / 1024; - Size NewKb = (state->memtupsize * sizeof(SortTuple) + 1023) / 1024; - - elog(LOG, "grew memtuples %1.2fx from %d (%zu KB) to %d (%zu KB) for final merge", - (double) NewKb / (double) OldKb, - memtupsize, OldKb, - state->memtupsize, NewKb); - } -#endif -} - -/* - * mergebatch - initialize tuple memory in batch - * - * This allows sequential access to sorted tuples buffered in memory from - * tapes/runs on disk during a final on-the-fly merge step. Note that the - * memory is not used for SortTuples, but for the underlying tuples (e.g. - * MinimalTuples). - * - * Note that when batch memory is used, there is a simple division of space - * into large buffers (one per active tape). The conventional incremental - * memory accounting (calling USEMEM() and FREEMEM()) is abandoned. Instead, - * when each tape's memory budget is exceeded, a retail palloc() "overflow" is - * performed, which is then immediately detected in a way that is analogous to - * LACKMEM(). This keeps each tape's use of memory fair, which is always a - * goal. - */ -static void -mergebatch(Tuplesortstate *state, int64 spacePerTape) -{ - int srcTape; - - Assert(state->activeTapes > 0); - Assert(state->tuples); - - /* - * For the purposes of tuplesort's memory accounting, the batch allocation - * is special, and regular memory accounting through USEMEM() calls is - * abandoned (see mergeprereadone()). - */ - for (srcTape = 0; srcTape < state->maxTapes; srcTape++) - { - char *mergetuples; - - if (!state->mergeactive[srcTape]) - continue; - - /* Allocate buffer for each active tape */ - mergetuples = MemoryContextAllocHuge(state->tuplecontext, - spacePerTape); - - /* Initialize state for tape */ - state->mergetuples[srcTape] = mergetuples; - state->mergecurrent[srcTape] = mergetuples; - state->mergetail[srcTape] = mergetuples; - state->mergeoverflow[srcTape] = NULL; - } - - state->batchUsed = true; - state->spacePerTape = spacePerTape; -} - -/* - * mergebatchone - prepare batch memory for one merge input tape - * - * This is called following the exhaustion of preread tuples for one input - * tape. All that actually occurs is that the state for the source tape is - * reset to indicate that all memory may be reused. - * - * This routine must deal with fixing up the tuple that is about to be returned - * to the client, due to "overflow" allocations. - */ -static void -mergebatchone(Tuplesortstate *state, int srcTape, SortTuple *rtup, - bool *should_free) -{ - Assert(state->batchUsed); - - /* - * Tuple about to be returned to caller ("stup") is final preread tuple - * from tape, just removed from the top of the heap. Special steps around - * memory management must be performed for that tuple, to make sure it - * isn't overwritten early. - */ - if (!state->mergeoverflow[srcTape]) - { - Size tupLen; - - /* - * Mark tuple buffer range for reuse, but be careful to move final, - * tail tuple to start of space for next run so that it's available to - * caller when stup is returned, and remains available at least until - * the next tuple is requested. - */ - tupLen = state->mergecurrent[srcTape] - state->mergetail[srcTape]; - state->mergecurrent[srcTape] = state->mergetuples[srcTape]; - MOVETUP(state->mergecurrent[srcTape], state->mergetail[srcTape], - tupLen); - - /* Make SortTuple at top of the merge heap point to new tuple */ - rtup->tuple = (void *) state->mergecurrent[srcTape]; - - state->mergetail[srcTape] = state->mergecurrent[srcTape]; - state->mergecurrent[srcTape] += tupLen; - } - else - { - /* - * Handle an "overflow" retail palloc. - * - * This is needed when we run out of tuple memory for the tape. - */ - state->mergecurrent[srcTape] = state->mergetuples[srcTape]; - state->mergetail[srcTape] = state->mergetuples[srcTape]; - - if (rtup->tuple) - { - Assert(rtup->tuple == (void *) state->mergeoverflow[srcTape]); - /* Caller should free palloc'd tuple */ - *should_free = true; - } - state->mergeoverflow[srcTape] = NULL; - } -} - -/* - * mergebatchfreetape - handle final clean-up for batch memory once tape is - * about to become exhausted - * - * All tuples are returned from tape, but a single final tuple, *rtup, is to be - * passed back to caller. Free tape's batch allocation buffer while ensuring - * that the final tuple is managed appropriately. - */ -static void -mergebatchfreetape(Tuplesortstate *state, int srcTape, SortTuple *rtup, - bool *should_free) -{ - Assert(state->batchUsed); - Assert(state->status == TSS_FINALMERGE); - - /* - * Tuple may or may not already be an overflow allocation from - * mergebatchone() - */ - if (!*should_free && rtup->tuple) - { - /* - * Final tuple still in tape's batch allocation. - * - * Return palloc()'d copy to caller, and have it freed in a similar - * manner to overflow allocation. Otherwise, we'd free batch memory - * and pass back a pointer to garbage. Note that we deliberately - * allocate this in the parent tuplesort context, to be on the safe - * side. - */ - Size tuplen; - void *oldTuple = rtup->tuple; - - tuplen = state->mergecurrent[srcTape] - state->mergetail[srcTape]; - rtup->tuple = MemoryContextAlloc(state->sortcontext, tuplen); - MOVETUP(rtup->tuple, oldTuple, tuplen); - *should_free = true; - } - - /* Free spacePerTape-sized buffer */ - pfree(state->mergetuples[srcTape]); -} - -/* - * mergebatchalloc - allocate memory for one tuple using a batch memory - * "logical allocation". - * - * This is used for the final on-the-fly merge phase only. READTUP() routines - * receive memory from here in place of palloc() and USEMEM() calls. - * - * Tuple tapenum is passed, ensuring each tape's tuples are stored in sorted, - * contiguous order (while allowing safe reuse of memory made available to - * each tape). This maximizes locality of access as tuples are returned by - * final merge. - * - * Caller must not subsequently attempt to free memory returned here. In - * general, only mergebatch* functions know about how memory returned from - * here should be freed, and this function's caller must ensure that batch - * memory management code will definitely have the opportunity to do the right - * thing during the final on-the-fly merge. - */ -static void * -mergebatchalloc(Tuplesortstate *state, int tapenum, Size tuplen) -{ - Size reserve_tuplen = MAXALIGN(tuplen); - char *ret; - - /* Should overflow at most once before mergebatchone() call: */ - Assert(state->mergeoverflow[tapenum] == NULL); - Assert(state->batchUsed); - - /* It should be possible to use precisely spacePerTape memory at once */ - if (state->mergecurrent[tapenum] + reserve_tuplen <= - state->mergetuples[tapenum] + state->spacePerTape) - { - /* - * Usual case -- caller is returned pointer into its tape's buffer, - * and an offset from that point is recorded as where tape has - * consumed up to for current round of preloading. - */ - ret = state->mergetail[tapenum] = state->mergecurrent[tapenum]; - state->mergecurrent[tapenum] += reserve_tuplen; - } - else - { - /* - * Allocate memory, and record as tape's overflow allocation. This - * will be detected quickly, in a similar fashion to a LACKMEM() - * condition, and should not happen again before a new round of - * preloading for caller's tape. Note that we deliberately allocate - * this in the parent tuplesort context, to be on the safe side. - * - * Sometimes, this does not happen because merging runs out of slots - * before running out of memory. - */ - ret = state->mergeoverflow[tapenum] = - MemoryContextAlloc(state->sortcontext, tuplen); - } - - return ret; -} - -/* - * mergepreread - load tuples from merge input tapes - * - * This routine exists to improve sequentiality of reads during a merge pass, - * as explained in the header comments of this file. Load tuples from each - * active source tape until the tape's run is exhausted or it has used up - * its fair share of available memory. In any case, we guarantee that there - * is at least one preread tuple available from each unexhausted input tape. - * - * We invoke this routine at the start of a merge pass for initial load, - * and then whenever any tape's preread data runs out. Note that we load - * as much data as possible from all tapes, not just the one that ran out. - * This is because logtape.c works best with a usage pattern that alternates - * between reading a lot of data and writing a lot of data, so whenever we - * are forced to read, we should fill working memory completely. - * - * In FINALMERGE state, we *don't* use this routine, but instead just preread - * from the single tape that ran dry. There's no read/write alternation in - * that state and so no point in scanning through all the tapes to fix one. - * (Moreover, there may be quite a lot of inactive tapes in that state, since - * we might have had many fewer runs than tapes. In a regular tape-to-tape - * merge we can expect most of the tapes to be active. Plus, only - * FINALMERGE state has to consider memory management for a batch - * allocation.) - */ -static void -mergepreread(Tuplesortstate *state) -{ - int srcTape; - - for (srcTape = 0; srcTape < state->maxTapes; srcTape++) - mergeprereadone(state, srcTape); -} - -/* - * mergeprereadone - load tuples from one merge input tape - * - * Read tuples from the specified tape until it has used up its free memory - * or array slots; but ensure that we have at least one tuple, if any are - * to be had. - */ -static void -mergeprereadone(Tuplesortstate *state, int srcTape) +static bool +mergereadnext(Tuplesortstate *state, int srcTape, SortTuple *stup) { unsigned int tuplen; - SortTuple stup; - int tupIndex; - int64 priorAvail, - spaceUsed; if (!state->mergeactive[srcTape]) - return; /* tape's run is already exhausted */ - - /* - * Manage per-tape availMem. Only actually matters when batch memory not - * in use. - */ - priorAvail = state->availMem; - state->availMem = state->mergeavailmem[srcTape]; + return false; /* tape's run is already exhausted */ - /* - * When batch memory is used if final on-the-fly merge, only mergeoverflow - * test is relevant; otherwise, only LACKMEM() test is relevant. - */ - while ((state->mergeavailslots[srcTape] > 0 && - state->mergeoverflow[srcTape] == NULL && !LACKMEM(state)) || - state->mergenext[srcTape] == 0) + /* read next tuple, if any */ + if ((tuplen = getlen(state, srcTape, true)) == 0) { - /* read next tuple, if any */ - if ((tuplen = getlen(state, srcTape, true)) == 0) - { - state->mergeactive[srcTape] = false; - break; - } - READTUP(state, &stup, srcTape, tuplen); - /* find a free slot in memtuples[] for it */ - tupIndex = state->mergefreelist; - if (tupIndex) - state->mergefreelist = state->memtuples[tupIndex].tupindex; - else - { - tupIndex = state->mergefirstfree++; - Assert(tupIndex < state->memtupsize); - } - state->mergeavailslots[srcTape]--; - /* store tuple, append to list for its tape */ - stup.tupindex = 0; - state->memtuples[tupIndex] = stup; - if (state->mergelast[srcTape]) - state->memtuples[state->mergelast[srcTape]].tupindex = tupIndex; - else - state->mergenext[srcTape] = tupIndex; - state->mergelast[srcTape] = tupIndex; + state->mergeactive[srcTape] = false; + return false; } - /* update per-tape and global availmem counts */ - spaceUsed = state->mergeavailmem[srcTape] - state->availMem; - state->mergeavailmem[srcTape] = state->availMem; - state->availMem = priorAvail - spaceUsed; + READTUP(state, stup, srcTape, tuplen); + + return true; } /* @@ -3260,13 +2939,12 @@ dumptuples(Tuplesortstate *state, bool alltuples) * Still holding out for a case favorable to replacement * selection. Still incrementally spilling using heap. * - * Dump the heap's frontmost entry, and sift up to remove it from - * the heap. + * Dump the heap's frontmost entry, and remove it from the heap. */ Assert(state->memtupcount > 0); WRITETUP(state, state->tp_tapenum[state->destTape], &state->memtuples[0]); - tuplesort_heap_siftup(state, true); + tuplesort_heap_delete_top(state, true); } else { @@ -3357,14 +3035,14 @@ dumpbatch(Tuplesortstate *state, bool alltuples) * a call with no subsequent run actually written to destTape), we prefer * to write out a 0 tuple run. * - * mergepreread()/mergeprereadone() are prepared for 0 tuple runs, and - * will reliably mark the tape inactive for the merge when called from - * beginmerge(). This case is therefore similar to the case where - * mergeonerun() finds a dummy run for the tape, and so doesn't need to - * merge a run from the tape (or conceptually "merges" the dummy run, if - * you prefer). According to Knuth, Algorithm D "isn't strictly optimal" - * in its method of distribution and dummy run assignment; this edge case - * seems very unlikely to make that appreciably worse. + * mergereadnext() is prepared for 0 tuple runs, and will reliably mark + * the tape inactive for the merge when called from beginmerge(). This + * case is therefore similar to the case where mergeonerun() finds a dummy + * run for the tape, and so doesn't need to merge a run from the tape (or + * conceptually "merges" the dummy run, if you prefer). According to + * Knuth, Algorithm D "isn't strictly optimal" in its method of + * distribution and dummy run assignment; this edge case seems very + * unlikely to make that appreciably worse. */ Assert(state->status == TSS_BUILDRUNS); @@ -3409,9 +3087,9 @@ dumpbatch(Tuplesortstate *state, bool alltuples) /* * Reset tuple memory. We've freed all of the tuples that we previously * allocated. It's important to avoid fragmentation when there is a stark - * change in allocation patterns due to the use of batch memory. - * Fragmentation due to AllocSetFree's bucketing by size class might be - * particularly bad if this step wasn't taken. + * change in the sizes of incoming tuples. Fragmentation due to + * AllocSetFree's bucketing by size class might be particularly bad if + * this step wasn't taken. */ MemoryContextReset(state->tuplecontext); @@ -3449,9 +3127,9 @@ tuplesort_rescan(Tuplesortstate *state) state->markpos_eof = false; break; case TSS_SORTEDONTAPE: - LogicalTapeRewind(state->tapeset, - state->result_tape, - false); + LogicalTapeRewindForRead(state->tapeset, + state->result_tape, + 0); state->eof_reached = false; state->markpos_block = 0L; state->markpos_offset = 0; @@ -3514,11 +3192,10 @@ tuplesort_restorepos(Tuplesortstate *state) state->eof_reached = state->markpos_eof; break; case TSS_SORTEDONTAPE: - if (!LogicalTapeSeek(state->tapeset, - state->result_tape, - state->markpos_block, - state->markpos_offset)) - elog(ERROR, "tuplesort_restorepos failed"); + LogicalTapeSeek(state->tapeset, + state->result_tape, + state->markpos_block, + state->markpos_offset); state->eof_reached = state->markpos_eof; break; default: @@ -3629,27 +3306,29 @@ make_bounded_heap(Tuplesortstate *state) state->memtupcount = 0; /* make the heap empty */ for (i = 0; i < tupcount; i++) { - if (state->memtupcount >= state->bound && - COMPARETUP(state, &state->memtuples[i], &state->memtuples[0]) <= 0) - { - /* New tuple would just get thrown out, so skip it */ - free_sort_tuple(state, &state->memtuples[i]); - CHECK_FOR_INTERRUPTS(); - } - else + if (state->memtupcount < state->bound) { /* Insert next tuple into heap */ /* Must copy source tuple to avoid possible overwrite */ SortTuple stup = state->memtuples[i]; - tuplesort_heap_insert(state, &stup, 0, false); - - /* If heap too full, discard largest entry */ - if (state->memtupcount > state->bound) + stup.tupindex = 0; /* not used */ + tuplesort_heap_insert(state, &stup, false); + } + else + { + /* + * The heap is full. Replace the largest entry with the new + * tuple, or just discard it, if it's larger than anything already + * in the heap. + */ + if (COMPARETUP(state, &state->memtuples[i], &state->memtuples[0]) <= 0) { - free_sort_tuple(state, &state->memtuples[0]); - tuplesort_heap_siftup(state, false); + free_sort_tuple(state, &state->memtuples[i]); + CHECK_FOR_INTERRUPTS(); } + else + tuplesort_heap_replace_top(state, &state->memtuples[i], false); } } @@ -3670,16 +3349,16 @@ sort_bounded_heap(Tuplesortstate *state) Assert(tupcount == state->bound); /* - * We can unheapify in place because each sift-up will remove the largest - * entry, which we can promptly store in the newly freed slot at the end. - * Once we're down to a single-entry heap, we're done. + * We can unheapify in place because each delete-top call will remove the + * largest entry, which we can promptly store in the newly freed slot at + * the end. Once we're down to a single-entry heap, we're done. */ while (state->memtupcount > 1) { SortTuple stup = state->memtuples[0]; /* this sifts-up the next-largest entry and decreases memtupcount */ - tuplesort_heap_siftup(state, false); + tuplesort_heap_delete_top(state, false); state->memtuples[state->memtupcount] = stup; } state->memtupcount = tupcount; @@ -3723,30 +3402,21 @@ tuplesort_sort_memtuples(Tuplesortstate *state) * Insert a new tuple into an empty or existing heap, maintaining the * heap invariant. Caller is responsible for ensuring there's room. * - * Note: we assume *tuple is a temporary variable that can be scribbled on. - * For some callers, tuple actually points to a memtuples[] entry above the + * Note: For some callers, tuple points to a memtuples[] entry above the * end of the heap. This is safe as long as it's not immediately adjacent * to the end of the heap (ie, in the [memtupcount] array entry) --- if it * is, it might get overwritten before being moved into the heap! */ static void tuplesort_heap_insert(Tuplesortstate *state, SortTuple *tuple, - int tupleindex, bool checkIndex) + bool checkIndex) { SortTuple *memtuples; int j; - /* - * Save the tupleindex --- see notes above about writing on *tuple. It's a - * historical artifact that tupleindex is passed as a separate argument - * and not in *tuple, but it's notationally convenient so let's leave it - * that way. - */ - tuple->tupindex = tupleindex; - memtuples = state->memtuples; Assert(state->memtupcount < state->memtupsize); - Assert(!checkIndex || tupleindex == RUN_FIRST); + Assert(!checkIndex || tuple->tupindex == RUN_FIRST); CHECK_FOR_INTERRUPTS(); @@ -3768,25 +3438,51 @@ tuplesort_heap_insert(Tuplesortstate *state, SortTuple *tuple, } /* - * The tuple at state->memtuples[0] has been removed from the heap. - * Decrement memtupcount, and sift up to maintain the heap invariant. + * Remove the tuple at state->memtuples[0] from the heap. Decrement + * memtupcount, and sift up to maintain the heap invariant. + * + * The caller has already free'd the tuple the top node points to, + * if necessary. */ static void -tuplesort_heap_siftup(Tuplesortstate *state, bool checkIndex) +tuplesort_heap_delete_top(Tuplesortstate *state, bool checkIndex) { SortTuple *memtuples = state->memtuples; SortTuple *tuple; - int i, - n; Assert(!checkIndex || state->currentRun == RUN_FIRST); if (--state->memtupcount <= 0) return; + /* + * Remove the last tuple in the heap, and re-insert it, by replacing the + * current top node with it. + */ + tuple = &memtuples[state->memtupcount]; + tuplesort_heap_replace_top(state, tuple, checkIndex); +} + +/* + * Replace the tuple at state->memtuples[0] with a new tuple. Sift up to + * maintain the heap invariant. + * + * This corresponds to Knuth's "sift-up" algorithm (Algorithm 5.2.3H, + * Heapsort, steps H3-H8). + */ +static void +tuplesort_heap_replace_top(Tuplesortstate *state, SortTuple *tuple, + bool checkIndex) +{ + SortTuple *memtuples = state->memtuples; + int i, + n; + + Assert(!checkIndex || state->currentRun == RUN_FIRST); + Assert(state->memtupcount >= 1); + CHECK_FOR_INTERRUPTS(); n = state->memtupcount; - tuple = &memtuples[n]; /* tuple that must be reinserted */ i = 0; /* i is where the "hole" is */ for (;;) { @@ -3850,38 +3546,31 @@ markrunend(Tuplesortstate *state, int tapenum) } /* - * Get memory for tuple from within READTUP() routine. Allocate - * memory and account for that, or consume from tape's batch - * allocation. + * Get memory for tuple from within READTUP() routine. * - * Memory returned here in the final on-the-fly merge case is recycled - * from tape's batch allocation. Otherwise, callers must pfree() or - * reset tuple child memory context, and account for that with a - * FREEMEM(). Currently, this only ever needs to happen in WRITETUP() - * routines. + * We use next free slot from the slab allocator, or palloc() if the tuple + * is too large for that. */ static void * -readtup_alloc(Tuplesortstate *state, int tapenum, Size tuplen) +readtup_alloc(Tuplesortstate *state, Size tuplen) { - if (state->batchUsed) - { - /* - * No USEMEM() call, because during final on-the-fly merge accounting - * is based on tape-private state. ("Overflow" allocations are - * detected as an indication that a new round or preloading is - * required. Preloading marks existing contents of tape's batch buffer - * for reuse.) - */ - return mergebatchalloc(state, tapenum, tuplen); - } + SlabSlot *buf; + + /* + * We pre-allocate enough slots in the slab arena that we should never run + * out. + */ + Assert(state->slabFreeHead); + + if (tuplen > SLAB_SLOT_SIZE || !state->slabFreeHead) + return MemoryContextAlloc(state->sortcontext, tuplen); else { - char *ret; + buf = state->slabFreeHead; + /* Reuse this slot */ + state->slabFreeHead = buf->nextfree; - /* Batch allocation yet to be performed */ - ret = MemoryContextAlloc(state->tuplecontext, tuplen); - USEMEM(state, GetMemoryChunkSpace(ret)); - return ret; + return buf; } } @@ -4050,8 +3739,11 @@ writetup_heap(Tuplesortstate *state, int tapenum, SortTuple *stup) LogicalTapeWrite(state->tapeset, tapenum, (void *) &tuplen, sizeof(tuplen)); - FREEMEM(state, GetMemoryChunkSpace(tuple)); - heap_free_minimal_tuple(tuple); + if (!state->slabAllocatorUsed) + { + FREEMEM(state, GetMemoryChunkSpace(tuple)); + heap_free_minimal_tuple(tuple); + } } static void @@ -4060,7 +3752,7 @@ readtup_heap(Tuplesortstate *state, SortTuple *stup, { unsigned int tupbodylen = len - sizeof(int); unsigned int tuplen = tupbodylen + MINIMAL_TUPLE_DATA_OFFSET; - MinimalTuple tuple = (MinimalTuple) readtup_alloc(state, tapenum, tuplen); + MinimalTuple tuple = (MinimalTuple) readtup_alloc(state, tuplen); char *tupbody = (char *) tuple + MINIMAL_TUPLE_DATA_OFFSET; HeapTupleData htup; @@ -4081,12 +3773,6 @@ readtup_heap(Tuplesortstate *state, SortTuple *stup, &stup->isnull1); } -static void -movetup_heap(void *dest, void *src, unsigned int len) -{ - memmove(dest, src, len); -} - /* * Routines specialized for the CLUSTER case (HeapTuple data, with * comparisons per a btree index definition) @@ -4271,7 +3957,7 @@ copytup_cluster(Tuplesortstate *state, SortTuple *stup, void *tup) mtup->datum1 = heap_getattr(tuple, state->indexInfo->ii_KeyAttrNumbers[0], state->tupDesc, - &stup->isnull1); + &mtup->isnull1); } } } @@ -4293,8 +3979,11 @@ writetup_cluster(Tuplesortstate *state, int tapenum, SortTuple *stup) LogicalTapeWrite(state->tapeset, tapenum, &tuplen, sizeof(tuplen)); - FREEMEM(state, GetMemoryChunkSpace(tuple)); - heap_freetuple(tuple); + if (!state->slabAllocatorUsed) + { + FREEMEM(state, GetMemoryChunkSpace(tuple)); + heap_freetuple(tuple); + } } static void @@ -4303,7 +3992,6 @@ readtup_cluster(Tuplesortstate *state, SortTuple *stup, { unsigned int t_len = tuplen - sizeof(ItemPointerData) - sizeof(int); HeapTuple tuple = (HeapTuple) readtup_alloc(state, - tapenum, t_len + HEAPTUPLESIZE); /* Reconstruct the HeapTupleData header */ @@ -4328,19 +4016,6 @@ readtup_cluster(Tuplesortstate *state, SortTuple *stup, &stup->isnull1); } -static void -movetup_cluster(void *dest, void *src, unsigned int len) -{ - HeapTuple tuple; - - memmove(dest, src, len); - - /* Repoint the HeapTupleData header */ - tuple = (HeapTuple) dest; - tuple->t_data = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE); -} - - /* * Routines specialized for IndexTuple case * @@ -4588,7 +4263,7 @@ copytup_index(Tuplesortstate *state, SortTuple *stup, void *tup) mtup->datum1 = index_getattr(tuple, 1, RelationGetDescr(state->indexRel), - &stup->isnull1); + &mtup->isnull1); } } } @@ -4608,8 +4283,11 @@ writetup_index(Tuplesortstate *state, int tapenum, SortTuple *stup) LogicalTapeWrite(state->tapeset, tapenum, (void *) &tuplen, sizeof(tuplen)); - FREEMEM(state, GetMemoryChunkSpace(tuple)); - pfree(tuple); + if (!state->slabAllocatorUsed) + { + FREEMEM(state, GetMemoryChunkSpace(tuple)); + pfree(tuple); + } } static void @@ -4617,7 +4295,7 @@ readtup_index(Tuplesortstate *state, SortTuple *stup, int tapenum, unsigned int len) { unsigned int tuplen = len - sizeof(unsigned int); - IndexTuple tuple = (IndexTuple) readtup_alloc(state, tapenum, tuplen); + IndexTuple tuple = (IndexTuple) readtup_alloc(state, tuplen); LogicalTapeReadExact(state->tapeset, tapenum, tuple, tuplen); @@ -4632,12 +4310,6 @@ readtup_index(Tuplesortstate *state, SortTuple *stup, &stup->isnull1); } -static void -movetup_index(void *dest, void *src, unsigned int len) -{ - memmove(dest, src, len); -} - /* * Routines specialized for DatumTuple case */ @@ -4704,7 +4376,7 @@ writetup_datum(Tuplesortstate *state, int tapenum, SortTuple *stup) LogicalTapeWrite(state->tapeset, tapenum, (void *) &writtenlen, sizeof(writtenlen)); - if (stup->tuple) + if (!state->slabAllocatorUsed && stup->tuple) { FREEMEM(state, GetMemoryChunkSpace(stup->tuple)); pfree(stup->tuple); @@ -4734,7 +4406,7 @@ readtup_datum(Tuplesortstate *state, SortTuple *stup, } else { - void *raddr = readtup_alloc(state, tapenum, tuplen); + void *raddr = readtup_alloc(state, tuplen); LogicalTapeReadExact(state->tapeset, tapenum, raddr, tuplen); @@ -4748,12 +4420,6 @@ readtup_datum(Tuplesortstate *state, SortTuple *stup, &tuplen, sizeof(tuplen)); } -static void -movetup_datum(void *dest, void *src, unsigned int len) -{ - memmove(dest, src, len); -} - /* * Convenience routine to free a tuple previously loaded into sort memory */ diff --git a/src/backend/utils/sort/tuplestore.c b/src/backend/utils/sort/tuplestore.c index 1347fc4520..84abf5f67e 100644 --- a/src/backend/utils/sort/tuplestore.c +++ b/src/backend/utils/sort/tuplestore.c @@ -43,7 +43,7 @@ * before switching to the other state or activating a different read pointer. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/time/combocid.c b/src/backend/utils/time/combocid.c index f033d1d5c9..baff998641 100644 --- a/src/backend/utils/time/combocid.c +++ b/src/backend/utils/time/combocid.c @@ -30,7 +30,7 @@ * destroyed at the end of each transaction. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c index 1ec9f70f0e..92afc32509 100644 --- a/src/backend/utils/time/snapmgr.c +++ b/src/backend/utils/time/snapmgr.c @@ -1,4 +1,5 @@ /*------------------------------------------------------------------------- + * * snapmgr.c * PostgreSQL snapshot manager * @@ -8,7 +9,7 @@ * (tracked by separate refcounts on each snapshot), its memory can be freed. * * The FirstXactSnapshot, if any, is treated a bit specially: we increment its - * regd_count and count it in RegisteredSnapshots, but this reference is not + * regd_count and list it in RegisteredSnapshots, but this reference is not * tracked by a resource owner. We used to use the TopTransactionResourceOwner * to track this snapshot reference, but that introduces logical circularity * and thus makes it impossible to clean up in a sane fashion. It's better to @@ -16,22 +17,25 @@ * module is entirely lower-level than ResourceOwners. * * Likewise, any snapshots that have been exported by pg_export_snapshot - * have regd_count = 1 and are counted in RegisteredSnapshots, but are not + * have regd_count = 1 and are listed in RegisteredSnapshots, but are not * tracked by any resource owner. * + * Likewise, the CatalogSnapshot is listed in RegisteredSnapshots when it + * is valid, but is not tracked by any resource owner. + * * The same is true for historic snapshots used during logical decoding, - * their lifetime is managed separately (as they live longer as one xact.c + * their lifetime is managed separately (as they live longer than one xact.c * transaction). * * These arrangements let us reset MyPgXact->xmin when there are no snapshots - * referenced by this transaction. (One possible improvement would be to be - * able to advance Xmin when the snapshot with the earliest Xmin is no longer - * referenced. That's a bit harder though, it requires more locking, and - * anyway it should be rather uncommon to keep temporary snapshots referenced - * for too long.) + * referenced by this transaction, and advance it when the one with oldest + * Xmin is no longer referenced. For simplicity however, only registered + * snapshots not active snapshots participate in tracking which one is oldest; + * we don't try to change MyPgXact->xmin except when the active-snapshot + * stack is empty. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -131,7 +135,7 @@ static volatile OldSnapshotControlData *oldSnapshotControl; * SecondarySnapshot is a snapshot that's always up-to-date as of the current * instant, even in transaction-snapshot mode. It should only be used for * special-purpose code (say, RI checking.) CatalogSnapshot points to an - * MVCC snapshot intended to be used for catalog scans; we must refresh it + * MVCC snapshot intended to be used for catalog scans; we must invalidate it * whenever a system catalog change occurs. * * These SnapshotData structs are static to simplify memory allocation @@ -147,11 +151,6 @@ static Snapshot SecondarySnapshot = NULL; static Snapshot CatalogSnapshot = NULL; static Snapshot HistoricSnapshot = NULL; -/* - * Staleness detection for CatalogSnapshot. - */ -static bool CatalogSnapshotStale = true; - /* * These are updated by GetSnapshotData. We initialize them this way * for the convenience of TransactionIdIsInProgress: even in bootstrap @@ -193,8 +192,7 @@ static ActiveSnapshotElt *OldestActiveSnapshot = NULL; /* * Currently registered Snapshots. Ordered in a heap by xmin, so that we can - * quickly find the one with lowest xmin, to advance our MyPgXat->xmin. - * resowner.c also tracks these. + * quickly find the one with lowest xmin, to advance our MyPgXact->xmin. */ static int xmin_cmp(const pairingheap_node *a, const pairingheap_node *b, void *arg); @@ -316,6 +314,12 @@ GetTransactionSnapshot(void) /* First call in transaction? */ if (!FirstSnapshotSet) { + /* + * Don't allow catalog snapshot to be older than xact snapshot. Must + * do this first to allow the empty-heap Assert to succeed. + */ + InvalidateCatalogSnapshot(); + Assert(pairingheap_is_empty(&RegisteredSnapshots)); Assert(FirstXactSnapshot == NULL); @@ -347,9 +351,6 @@ GetTransactionSnapshot(void) else CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData); - /* Don't allow catalog snapshot to be older than xact snapshot. */ - CatalogSnapshotStale = true; - FirstSnapshotSet = true; return CurrentSnapshot; } @@ -358,7 +359,7 @@ GetTransactionSnapshot(void) return CurrentSnapshot; /* Don't allow catalog snapshot to be older than xact snapshot. */ - CatalogSnapshotStale = true; + InvalidateCatalogSnapshot(); CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData); @@ -463,36 +464,72 @@ GetNonHistoricCatalogSnapshot(Oid relid) * scan a relation for which neither catcache nor snapshot invalidations * are sent, we must refresh the snapshot every time. */ - if (!CatalogSnapshotStale && !RelationInvalidatesSnapshotsOnly(relid) && + if (CatalogSnapshot && + !RelationInvalidatesSnapshotsOnly(relid) && !RelationHasSysCache(relid)) - CatalogSnapshotStale = true; + InvalidateCatalogSnapshot(); - if (CatalogSnapshotStale) + if (CatalogSnapshot == NULL) { /* Get new snapshot. */ CatalogSnapshot = GetSnapshotData(&CatalogSnapshotData); /* - * Mark new snapshost as valid. We must do this last, in case an - * ERROR occurs inside GetSnapshotData(). + * Make sure the catalog snapshot will be accounted for in decisions + * about advancing PGXACT->xmin. We could apply RegisterSnapshot, but + * that would result in making a physical copy, which is overkill; and + * it would also create a dependency on some resource owner, which we + * do not want for reasons explained at the head of this file. Instead + * just shove the CatalogSnapshot into the pairing heap manually. This + * has to be reversed in InvalidateCatalogSnapshot, of course. + * + * NB: it had better be impossible for this to throw error, since the + * CatalogSnapshot pointer is already valid. */ - CatalogSnapshotStale = false; + pairingheap_add(&RegisteredSnapshots, &CatalogSnapshot->ph_node); } return CatalogSnapshot; } /* - * Mark the current catalog snapshot as invalid. We could change this API - * to allow the caller to provide more fine-grained invalidation details, so - * that a change to relation A wouldn't prevent us from using our cached - * snapshot to scan relation B, but so far there's no evidence that the CPU - * cycles we spent tracking such fine details would be well-spent. + * InvalidateCatalogSnapshot + * Mark the current catalog snapshot, if any, as invalid + * + * We could change this API to allow the caller to provide more fine-grained + * invalidation details, so that a change to relation A wouldn't prevent us + * from using our cached snapshot to scan relation B, but so far there's no + * evidence that the CPU cycles we spent tracking such fine details would be + * well-spent. */ void InvalidateCatalogSnapshot(void) { - CatalogSnapshotStale = true; + if (CatalogSnapshot) + { + pairingheap_remove(&RegisteredSnapshots, &CatalogSnapshot->ph_node); + CatalogSnapshot = NULL; + SnapshotResetXmin(); + } +} + +/* + * InvalidateCatalogSnapshotConditionally + * Drop catalog snapshot if it's the only one we have + * + * This is called when we are about to wait for client input, so we don't + * want to continue holding the catalog snapshot if it might mean that the + * global xmin horizon can't advance. However, if there are other snapshots + * still active or registered, the catalog snapshot isn't likely to be the + * oldest one, so we might as well keep it. + */ +void +InvalidateCatalogSnapshotConditionally(void) +{ + if (CatalogSnapshot && + ActiveSnapshot == NULL && + pairingheap_is_singular(&RegisteredSnapshots)) + InvalidateCatalogSnapshot(); } /* @@ -509,6 +546,7 @@ SnapshotSetCommandId(CommandId curcid) CurrentSnapshot->curcid = curcid; if (SecondarySnapshot) SecondarySnapshot->curcid = curcid; + /* Should we do the same with CatalogSnapshot? */ } /* @@ -526,6 +564,9 @@ SetTransactionSnapshot(Snapshot sourcesnap, TransactionId sourcexid, /* Caller should have checked this already */ Assert(!FirstSnapshotSet); + /* Better do this to ensure following Assert succeeds. */ + InvalidateCatalogSnapshot(); + Assert(pairingheap_is_empty(&RegisteredSnapshots)); Assert(FirstXactSnapshot == NULL); Assert(!HistoricSnapshotActive()); @@ -918,7 +959,15 @@ xmin_cmp(const pairingheap_node *a, const pairingheap_node *b, void *arg) * Even if there are some remaining snapshots, we may be able to advance our * PGXACT->xmin to some degree. This typically happens when a portal is * dropped. For efficiency, we only consider recomputing PGXACT->xmin when - * the active snapshot stack is empty. + * the active snapshot stack is empty; this allows us not to need to track + * which active snapshot is oldest. + * + * Note: it's tempting to use GetOldestSnapshot() here so that we can include + * active snapshots in the calculation. However, that compares by LSN not + * xmin so it's not entirely clear that it's the same thing. Also, we'd be + * critically dependent on the assumption that the bottommost active snapshot + * stack entry has the oldest xmin. (Current uses of GetOldestSnapshot() are + * not actually critical, but this would be.) */ static void SnapshotResetXmin(void) @@ -1006,7 +1055,7 @@ AtEOXact_Snapshot(bool isCommit) { /* * In transaction-snapshot mode we must release our privately-managed - * reference to the transaction snapshot. We must decrement + * reference to the transaction snapshot. We must remove it from * RegisteredSnapshots to keep the check below happy. But we don't bother * to do FreeSnapshot, for two reasons: the memory will go away with * TopTransactionContext anyway, and if someone has left the snapshot @@ -1046,7 +1095,7 @@ AtEOXact_Snapshot(bool isCommit) /* * As with the FirstXactSnapshot, we needn't spend any effort on * cleaning up the per-snapshot data structures, but we do need to - * unlink them from RegisteredSnapshots to prevent a warning below. + * remove them from RegisteredSnapshots to prevent a warning below. */ foreach(lc, exportedSnapshots) { @@ -1058,6 +1107,9 @@ AtEOXact_Snapshot(bool isCommit) exportedSnapshots = NIL; } + /* Drop catalog snapshot if any */ + InvalidateCatalogSnapshot(); + /* On commit, complain about leftover snapshots */ if (isCommit) { diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c index d99c847000..053a6d1c70 100644 --- a/src/backend/utils/time/tqual.c +++ b/src/backend/utils/time/tqual.c @@ -50,7 +50,7 @@ * HeapTupleSatisfiesAny() * all tuples are visible * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -418,8 +418,8 @@ HeapTupleSatisfiesToast(HeapTuple htup, Snapshot snapshot, /* * An invalid Xmin can be left behind by a speculative insertion that - * is canceled by super-deleting the tuple. We shouldn't see any of - * those in TOAST tables, but better safe than sorry. + * is canceled by super-deleting the tuple. This also applies to + * TOAST tuples created during speculative insertion. */ else if (!TransactionIdIsValid(HeapTupleHeaderGetXmin(tuple))) return false; diff --git a/src/bin/Makefile b/src/bin/Makefile index c926558d00..e0a5d92028 100644 --- a/src/bin/Makefile +++ b/src/bin/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin (client programs) # -# Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/bin/Makefile diff --git a/src/bin/initdb/Makefile b/src/bin/initdb/Makefile index 094c8945c9..eaed05043b 100644 --- a/src/bin/initdb/Makefile +++ b/src/bin/initdb/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/initdb # -# Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/bin/initdb/Makefile @@ -18,6 +18,9 @@ include $(top_builddir)/src/Makefile.global override CPPFLAGS := -DFRONTEND -I$(libpq_srcdir) -I$(top_srcdir)/src/timezone $(CPPFLAGS) +# note: we need libpq only because fe_utils does +LDFLAGS += -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport) + # use system timezone data? ifneq (,$(with_system_tzdata)) override CPPFLAGS += '-DSYSTEMTZDIR="$(with_system_tzdata)"' @@ -27,7 +30,7 @@ OBJS= initdb.o findtimezone.o localtime.o encnames.o $(WIN32RES) all: initdb -initdb: $(OBJS) | submake-libpgport +initdb: $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) # We used to pull in all of libpq to get encnames.c, but that diff --git a/src/bin/initdb/findtimezone.c b/src/bin/initdb/findtimezone.c index 5a443131ee..5d48ffe4a8 100644 --- a/src/bin/initdb/findtimezone.c +++ b/src/bin/initdb/findtimezone.c @@ -3,7 +3,7 @@ * findtimezone.c * Functions for determining the default timezone to use. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/initdb/findtimezone.c @@ -584,7 +584,7 @@ static const struct /* * This list was built from the contents of the registry at * HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time - * Zones on Windows 2003 R2. + * Zones on Windows 10 and Windows 7. * * The zones have been matched to Olson timezones by looking at the cities * listed in the win32 display name (in the comment here) in most cases. @@ -592,417 +592,590 @@ static const struct { "Afghanistan Standard Time", "Afghanistan Daylight Time", "Asia/Kabul" - }, /* (GMT+04:30) Kabul */ + }, /* (UTC+04:30) Kabul */ { "Alaskan Standard Time", "Alaskan Daylight Time", "US/Alaska" - }, /* (GMT-09:00) Alaska */ + }, /* (UTC-09:00) Alaska */ + { + "Aleutian Standard Time", "Aleutian Daylight Time", + "US/Aleutan" + }, /* (UTC-10:00) Aleutian Islands */ + { + "Altai Standard Time", "Altai Daylight Time", + "Asia/Barnaul" + }, /* (UTC+07:00) Barnaul, Gorno-Altaysk */ { "Arab Standard Time", "Arab Daylight Time", "Asia/Kuwait" - }, /* (GMT+03:00) Kuwait, Riyadh */ + }, /* (UTC+03:00) Kuwait, Riyadh */ { "Arabian Standard Time", "Arabian Daylight Time", "Asia/Muscat" - }, /* (GMT+04:00) Abu Dhabi, Muscat */ + }, /* (UTC+04:00) Abu Dhabi, Muscat */ { "Arabic Standard Time", "Arabic Daylight Time", "Asia/Baghdad" - }, /* (GMT+03:00) Baghdad */ + }, /* (UTC+03:00) Baghdad */ { "Argentina Standard Time", "Argentina Daylight Time", "America/Buenos_Aires" - }, /* (GMT-03:00) Buenos Aires */ + }, /* (UTC-03:00) City of Buenos Aires */ { "Armenian Standard Time", "Armenian Daylight Time", "Asia/Yerevan" - }, /* (GMT+04:00) Yerevan */ + }, /* (UTC+04:00) Baku, Tbilisi, Yerevan */ + { + "Astrakhan Standard Time", "Astrakhan Daylight Time", + "Europe/Astrakhan" + }, /* (UTC+04:00) Astrakhan, Ulyanovsk */ { "Atlantic Standard Time", "Atlantic Daylight Time", "Canada/Atlantic" - }, /* (GMT-04:00) Atlantic Time (Canada) */ + }, /* (UTC-04:00) Atlantic Time (Canada) */ { "AUS Central Standard Time", "AUS Central Daylight Time", "Australia/Darwin" - }, /* (GMT+09:30) Darwin */ + }, /* (UTC+09:30) Darwin */ + { + "Aus Central W. Standard Time", "Aus Central W. Daylight Time", + "Australia/Eucla" + }, /* (UTC+08:45) Eucla */ { "AUS Eastern Standard Time", "AUS Eastern Daylight Time", "Australia/Canberra" - }, /* (GMT+10:00) Canberra, Melbourne, Sydney */ + }, /* (UTC+10:00) Canberra, Melbourne, Sydney */ { "Azerbaijan Standard Time", "Azerbaijan Daylight Time", "Asia/Baku" - }, /* (GMT+04:00) Baku */ + }, /* (UTC+04:00) Baku */ { "Azores Standard Time", "Azores Daylight Time", "Atlantic/Azores" - }, /* (GMT-01:00) Azores */ + }, /* (UTC-01:00) Azores */ + { + "Bahia Standard Time", "Bahia Daylight Time", + "America/Salvador" + }, /* (UTC-03:00) Salvador */ { "Bangladesh Standard Time", "Bangladesh Daylight Time", "Asia/Dhaka" - }, /* (GMT+06:00) Dhaka */ + }, /* (UTC+06:00) Dhaka */ + { + "Bougainville Standard Time", "Bougainville Daylight Time", + "Pacific/Bougainville" + }, /* (UTC+11:00) Bougainville Island */ + { + "Belarus Standard Time", "Belarus Daylight Time", + "Europe/Minsk" + }, /* (UTC+03:00) Minsk */ + { + "Cabo Verde Standard Time", "Cabo Verde Daylight Time", + "Atlantic/Cape_Verde" + }, /* (UTC-01:00) Cabo Verde Is. */ + { + "Chatham Islands Standard Time", "Chatham Islands Daylight Time", + "Pacific/Chatham" + }, /* (UTC+12:45) Chatham Islands */ { "Canada Central Standard Time", "Canada Central Daylight Time", "Canada/Saskatchewan" - }, /* (GMT-06:00) Saskatchewan */ + }, /* (UTC-06:00) Saskatchewan */ { "Cape Verde Standard Time", "Cape Verde Daylight Time", "Atlantic/Cape_Verde" - }, /* (GMT-01:00) Cape Verde Is. */ + }, /* (UTC-01:00) Cape Verde Is. */ { "Caucasus Standard Time", "Caucasus Daylight Time", "Asia/Baku" - }, /* (GMT+04:00) Baku, Tbilisi, Yerevan */ + }, /* (UTC+04:00) Yerevan */ { "Cen. Australia Standard Time", "Cen. Australia Daylight Time", "Australia/Adelaide" - }, /* (GMT+09:30) Adelaide */ + }, /* (UTC+09:30) Adelaide */ /* Central America (other than Mexico) generally does not observe DST */ { "Central America Standard Time", "Central America Daylight Time", "CST6" - }, /* (GMT-06:00) Central America */ + }, /* (UTC-06:00) Central America */ { "Central Asia Standard Time", "Central Asia Daylight Time", "Asia/Dhaka" - }, /* (GMT+06:00) Astana, Dhaka */ + }, /* (UTC+06:00) Astana */ { "Central Brazilian Standard Time", "Central Brazilian Daylight Time", "America/Cuiaba" - }, /* (GMT-04:00) Cuiaba */ + }, /* (UTC-04:00) Cuiaba */ { "Central Europe Standard Time", "Central Europe Daylight Time", "Europe/Belgrade" - }, /* (GMT+01:00) Belgrade, Bratislava, Budapest, + }, /* (UTC+01:00) Belgrade, Bratislava, Budapest, * Ljubljana, Prague */ { "Central European Standard Time", "Central European Daylight Time", "Europe/Sarajevo" - }, /* (GMT+01:00) Sarajevo, Skopje, Warsaw, + }, /* (UTC+01:00) Sarajevo, Skopje, Warsaw, * Zagreb */ { "Central Pacific Standard Time", "Central Pacific Daylight Time", "Pacific/Noumea" - }, /* (GMT+11:00) Magadan, Solomon Is., New - * Caledonia */ + }, /* (UTC+11:00) Solomon Is., New Caledonia */ { "Central Standard Time", "Central Daylight Time", "US/Central" - }, /* (GMT-06:00) Central Time (US & Canada) */ + }, /* (UTC-06:00) Central Time (US & Canada) */ { "Central Standard Time (Mexico)", "Central Daylight Time (Mexico)", "America/Mexico_City" - }, /* (GMT-06:00) Guadalajara, Mexico City, - * Monterrey - New */ + }, /* (UTC-06:00) Guadalajara, Mexico City, + * Monterrey */ { "China Standard Time", "China Daylight Time", "Asia/Hong_Kong" - }, /* (GMT+08:00) Beijing, Chongqing, Hong Kong, + }, /* (UTC+08:00) Beijing, Chongqing, Hong Kong, * Urumqi */ + { + "Cuba Standard Time", "Cuba Daylight Time", + "America/Havana" + }, /* (UTC-05:00) Havana */ { "Dateline Standard Time", "Dateline Daylight Time", - "Etc/GMT+12" - }, /* (GMT-12:00) International Date Line West */ + "Etc/UTC+12" + }, /* (UTC-12:00) International Date Line West */ { "E. Africa Standard Time", "E. Africa Daylight Time", "Africa/Nairobi" - }, /* (GMT+03:00) Nairobi */ + }, /* (UTC+03:00) Nairobi */ { "E. Australia Standard Time", "E. Australia Daylight Time", "Australia/Brisbane" - }, /* (GMT+10:00) Brisbane */ + }, /* (UTC+10:00) Brisbane */ { "E. Europe Standard Time", "E. Europe Daylight Time", "Europe/Bucharest" - }, /* (GMT+02:00) Bucharest */ + }, /* (UTC+02:00) E. Europe */ { "E. South America Standard Time", "E. South America Daylight Time", "America/Araguaina" - }, /* (GMT-03:00) Brasilia */ + }, /* (UTC-03:00) Brasilia */ { "Eastern Standard Time", "Eastern Daylight Time", "US/Eastern" - }, /* (GMT-05:00) Eastern Time (US & Canada) */ + }, /* (UTC-05:00) Eastern Time (US & Canada) */ + { + "Eastern Standard Time (Mexico)", "Eastern Daylight Time (Mexico)", + "America/Mexico_City" + }, /* (UTC-05:00) Chetumal */ + { + "Easter Island Standard Time", "Easter Island Daylight Time", + "Pacific/Easter" + }, /* (UTC-06:00) Easter Island */ { "Egypt Standard Time", "Egypt Daylight Time", "Africa/Cairo" - }, /* (GMT+02:00) Cairo */ + }, /* (UTC+02:00) Cairo */ { - "Ekaterinburg Standard Time", "Ekaterinburg Daylight Time", + "Ekaterinburg Standard Time (RTZ 4)", "Ekaterinburg Daylight Time", "Asia/Yekaterinburg" - }, /* (GMT+05:00) Ekaterinburg */ + }, /* (UTC+05:00) Ekaterinburg */ { "Fiji Standard Time", "Fiji Daylight Time", "Pacific/Fiji" - }, /* (GMT+12:00) Fiji, Kamchatka, Marshall Is. */ + }, /* (UTC+12:00) Fiji */ { "FLE Standard Time", "FLE Daylight Time", "Europe/Helsinki" - }, /* (GMT+02:00) Helsinki, Kyiv, Riga, Sofia, + }, /* (UTC+02:00) Helsinki, Kyiv, Riga, Sofia, * Tallinn, Vilnius */ { "Georgian Standard Time", "Georgian Daylight Time", "Asia/Tbilisi" - }, /* (GMT+03:00) Tbilisi */ + }, /* (UTC+04:00) Tbilisi */ { "GMT Standard Time", "GMT Daylight Time", "Europe/London" - }, /* (GMT) Greenwich Mean Time : Dublin, - * Edinburgh, Lisbon, London */ + }, /* (UTC) Dublin, Edinburgh, Lisbon, London */ { "Greenland Standard Time", "Greenland Daylight Time", "America/Godthab" - }, /* (GMT-03:00) Greenland */ + }, /* (UTC-03:00) Greenland */ { "Greenwich Standard Time", "Greenwich Daylight Time", "Africa/Casablanca" - }, /* (GMT) Casablanca, Monrovia */ + }, /* (UTC) Monrovia, Reykjavik */ { "GTB Standard Time", "GTB Daylight Time", "Europe/Athens" - }, /* (GMT+02:00) Athens, Istanbul, Minsk */ + }, /* (UTC+02:00) Athens, Bucharest */ + { + "Haiti Standard Time", "Haiti Daylight Time", + "US/Eastern" + }, /* (UTC-05:00) Haiti */ { "Hawaiian Standard Time", "Hawaiian Daylight Time", "US/Hawaii" - }, /* (GMT-10:00) Hawaii */ + }, /* (UTC-10:00) Hawaii */ { "India Standard Time", "India Daylight Time", "Asia/Calcutta" - }, /* (GMT+05:30) Chennai, Kolkata, Mumbai, New + }, /* (UTC+05:30) Chennai, Kolkata, Mumbai, New * Delhi */ { "Iran Standard Time", "Iran Daylight Time", "Asia/Tehran" - }, /* (GMT+03:30) Tehran */ + }, /* (UTC+03:30) Tehran */ { "Jerusalem Standard Time", "Jerusalem Daylight Time", "Asia/Jerusalem" - }, /* (GMT+02:00) Jerusalem */ + }, /* (UTC+02:00) Jerusalem */ { "Jordan Standard Time", "Jordan Daylight Time", "Asia/Amman" - }, /* (GMT+02:00) Amman */ + }, /* (UTC+02:00) Amman */ { "Kamchatka Standard Time", "Kamchatka Daylight Time", "Asia/Kamchatka" - }, /* (GMT+12:00) Petropavlovsk-Kamchatsky */ + }, /* (UTC+12:00) Petropavlovsk-Kamchatsky - Old */ { "Korea Standard Time", "Korea Daylight Time", "Asia/Seoul" - }, /* (GMT+09:00) Seoul */ + }, /* (UTC+09:00) Seoul */ + { + "Libya Standard Time", "Libya Daylight Time", + "Africa/Tripoli" + }, /* (UTC+02:00) Tripoli */ + { + "Line Islands Standard Time", "Line Islands Daylight Time", + "Pacific/Kiritimati" + }, /* (UTC+14:00) Kiritimati Island */ + { + "Lord Howe Standard Time", "Lord Howe Daylight Time", + "Australia/Lord_Howe" + }, /* (UTC+10:30) Lord Howe Island */ + { + "Magadan Standard Time", "Magadan Daylight Time", + "Asia/Magadan" + }, /* (UTC+10:00) Magadan */ + { + "Marquesas Standard Time", "Marquesas Daylight Time", + "Pacific/Marquesas" + }, /* (UTC-09:30) Marquesas Islands */ { "Mauritius Standard Time", "Mauritius Daylight Time", "Indian/Mauritius" - }, /* (GMT+04:00) Port Louis */ + }, /* (UTC+04:00) Port Louis */ { "Mexico Standard Time", "Mexico Daylight Time", "America/Mexico_City" - }, /* (GMT-06:00) Guadalajara, Mexico City, + }, /* (UTC-06:00) Guadalajara, Mexico City, * Monterrey */ { "Mexico Standard Time 2", "Mexico Daylight Time 2", "America/Chihuahua" - }, /* (GMT-07:00) Chihuahua, La Paz, Mazatlan */ + }, /* (UTC-07:00) Chihuahua, La Paz, Mazatlan */ { "Mid-Atlantic Standard Time", "Mid-Atlantic Daylight Time", "Atlantic/South_Georgia" - }, /* (GMT-02:00) Mid-Atlantic */ + }, /* (UTC-02:00) Mid-Atlantic - Old */ { "Middle East Standard Time", "Middle East Daylight Time", "Asia/Beirut" - }, /* (GMT+02:00) Beirut */ + }, /* (UTC+02:00) Beirut */ { "Montevideo Standard Time", "Montevideo Daylight Time", "America/Montevideo" - }, /* (GMT-03:00) Montevideo */ + }, /* (UTC-03:00) Montevideo */ { "Morocco Standard Time", "Morocco Daylight Time", "Africa/Casablanca" - }, /* (GMT) Casablanca */ + }, /* (UTC) Casablanca */ { "Mountain Standard Time", "Mountain Daylight Time", "US/Mountain" - }, /* (GMT-07:00) Mountain Time (US & Canada) */ + }, /* (UTC-07:00) Mountain Time (US & Canada) */ { "Mountain Standard Time (Mexico)", "Mountain Daylight Time (Mexico)", "America/Chihuahua" - }, /* (GMT-07:00) Chihuahua, La Paz, Mazatlan - - * New */ + }, /* (UTC-07:00) Chihuahua, La Paz, Mazatlan */ { "Myanmar Standard Time", "Myanmar Daylight Time", "Asia/Rangoon" - }, /* (GMT+06:30) Rangoon */ + }, /* (UTC+06:30) Yangon (Rangoon) */ { "N. Central Asia Standard Time", "N. Central Asia Daylight Time", "Asia/Novosibirsk" - }, /* (GMT+06:00) Novosibirsk */ + }, /* (UTC+06:00) Novosibirsk (RTZ 5) */ { "Namibia Standard Time", "Namibia Daylight Time", "Africa/Windhoek" - }, /* (GMT+02:00) Windhoek */ + }, /* (UTC+01:00) Windhoek */ { "Nepal Standard Time", "Nepal Daylight Time", "Asia/Katmandu" - }, /* (GMT+05:45) Kathmandu */ + }, /* (UTC+05:45) Kathmandu */ { "New Zealand Standard Time", "New Zealand Daylight Time", "Pacific/Auckland" - }, /* (GMT+12:00) Auckland, Wellington */ + }, /* (UTC+12:00) Auckland, Wellington */ { "Newfoundland Standard Time", "Newfoundland Daylight Time", "Canada/Newfoundland" - }, /* (GMT-03:30) Newfoundland */ + }, /* (UTC-03:30) Newfoundland */ + { + "Norfolk Standard Time", "Norfolk Daylight Time", + "Pacific/Norfolk" + }, /* (UTC+11:00) Norfolk Island */ { "North Asia East Standard Time", "North Asia East Daylight Time", "Asia/Irkutsk" - }, /* (GMT+08:00) Irkutsk, Ulaan Bataar */ + }, /* (UTC+08:00) Irkutsk, Ulaan Bataar */ { "North Asia Standard Time", "North Asia Daylight Time", "Asia/Krasnoyarsk" - }, /* (GMT+07:00) Krasnoyarsk */ + }, /* (UTC+07:00) Krasnoyarsk */ + { + "North Korea Standard Time", "North Korea Daylight Time", + "Asia/Pyongyang" + }, /* (UTC+08:30) Pyongyang */ { "Pacific SA Standard Time", "Pacific SA Daylight Time", "America/Santiago" - }, /* (GMT-04:00) Santiago */ + }, /* (UTC-03:00) Santiago */ { "Pacific Standard Time", "Pacific Daylight Time", "US/Pacific" - }, /* (GMT-08:00) Pacific Time (US & Canada); - * Tijuana */ + }, /* (UTC-08:00) Pacific Time (US & Canada) */ { "Pacific Standard Time (Mexico)", "Pacific Daylight Time (Mexico)", "America/Tijuana" - }, /* (GMT-08:00) Tijuana, Baja California */ + }, /* (UTC-08:00) Baja California */ { "Pakistan Standard Time", "Pakistan Daylight Time", "Asia/Karachi" - }, /* (GMT+05:00) Islamabad, Karachi */ + }, /* (UTC+05:00) Islamabad, Karachi */ { "Paraguay Standard Time", "Paraguay Daylight Time", "America/Asuncion" - }, /* (GMT-04:00) Asuncion */ + }, /* (UTC-04:00) Asuncion */ { "Romance Standard Time", "Romance Daylight Time", "Europe/Brussels" - }, /* (GMT+01:00) Brussels, Copenhagen, Madrid, + }, /* (UTC+01:00) Brussels, Copenhagen, Madrid, * Paris */ + { + "Russia TZ 1 Standard Time", "Russia TZ 1 Daylight Time", + "Europe/Kaliningrad" + }, /* (UTC+02:00) Kaliningrad (RTZ 1) */ + { + "Russia TZ 2 Standard Time", "Russia TZ 2 Daylight Time", + "Europe/Moscow" + }, /* (UTC+03:00) Moscow, St. Petersburg, + * Volgograd (RTZ 2) */ + { + "Russia TZ 3 Standard Time", "Russia TZ 3 Daylight Time", + "Europe/Samara" + }, /* (UTC+04:00) Izhevsk, Samara (RTZ 3) */ + { + "Russia TZ 4 Standard Time", "Russia TZ 4 Daylight Time", + "Asia/Yekaterinburg" + }, /* (UTC+05:00) Ekaterinburg (RTZ 4) */ + { + "Russia TZ 5 Standard Time", "Russia TZ 5 Daylight Time", + "Asia/Novosibirsk" + }, /* (UTC+06:00) Novosibirsk (RTZ 5) */ + { + "Russia TZ 6 Standard Time", "Russia TZ 6 Daylight Time", + "Asia/Krasnoyarsk" + }, /* (UTC+07:00) Krasnoyarsk (RTZ 6) */ + { + "Russia TZ 7 Standard Time", "Russia TZ 7 Daylight Time", + "Asia/Irkutsk" + }, /* (UTC+08:00) Irkutsk (RTZ 7) */ + { + "Russia TZ 8 Standard Time", "Russia TZ 8 Daylight Time", + "Asia/Yakutsk" + }, /* (UTC+09:00) Yakutsk (RTZ 8) */ + { + "Russia TZ 9 Standard Time", "Russia TZ 9 Daylight Time", + "Asia/Vladivostok" + }, /* (UTC+10:00) Vladivostok, Magadan + * (RTZ 9) */ + { + "Russia TZ 10 Standard Time", "Russia TZ 10 Daylight Time", + "Asia/Magadan" + }, /* (UTC+11:00) Chokurdakh (RTZ 10) */ + { + "Russia TZ 11 Standard Time", "Russia TZ 11 Daylight Time", + "Asia/Anadyr" + }, /* (UTC+12:00) Anadyr, Petropavlovsk-Kamchatsky + * (RTZ 11) */ { "Russian Standard Time", "Russian Daylight Time", "Europe/Moscow" - }, /* (GMT+03:00) Moscow, St. Petersburg, + }, /* (UTC+03:00) Moscow, St. Petersburg, * Volgograd */ { "SA Eastern Standard Time", "SA Eastern Daylight Time", "America/Buenos_Aires" - }, /* (GMT-03:00) Buenos Aires, Georgetown */ + }, /* (UTC-03:00) Cayenne, Fortaleza */ { "SA Pacific Standard Time", "SA Pacific Daylight Time", "America/Bogota" - }, /* (GMT-05:00) Bogota, Lima, Quito */ + }, /* (UTC-05:00) Bogota, Lima, Quito, Rio + * Branco */ { "SA Western Standard Time", "SA Western Daylight Time", "America/Caracas" - }, /* (GMT-04:00) Caracas, La Paz */ + }, /* (UTC-04:00) Georgetown, La Paz, Manaus, + * San Juan */ + { + "Saint Pierre Standard Time", "Saint Pierre Daylight Time", + "America/Miquelon" + }, /* (UTC-03:00) Saint Pierre and Miquelon */ { "Samoa Standard Time", "Samoa Daylight Time", - "Pacific/Midway" - }, /* (GMT-11:00) Midway Island, Samoa */ + "Pacific/Samoa" + }, /* (UTC+13:00) Samoa */ { "SE Asia Standard Time", "SE Asia Daylight Time", "Asia/Bangkok" - }, /* (GMT+07:00) Bangkok, Hanoi, Jakarta */ + }, /* (UTC+07:00) Bangkok, Hanoi, Jakarta */ { "Malay Peninsula Standard Time", "Malay Peninsula Daylight Time", "Asia/Kuala_Lumpur" - }, /* (GMT+08:00) Kuala Lumpur, Singapore */ + }, /* (UTC+08:00) Kuala Lumpur, Singapore */ + { + "Sakhalin Standard Time", "Sakhalin Daylight Time", + "Asia/Sakhalin" + }, /* (UTC+11:00) Sakhalin */ { "South Africa Standard Time", "South Africa Daylight Time", "Africa/Harare" - }, /* (GMT+02:00) Harare, Pretoria */ + }, /* (UTC+02:00) Harare, Pretoria */ { "Sri Lanka Standard Time", "Sri Lanka Daylight Time", "Asia/Colombo" - }, /* (GMT+06:00) Sri Jayawardenepura */ + }, /* (UTC+05:30) Sri Jayawardenepura */ + { + "Syria Standard Time", "Syria Daylight Time", + "Asia/Damascus" + }, /* (UTC+02:00) Damascus */ { "Taipei Standard Time", "Taipei Daylight Time", "Asia/Taipei" - }, /* (GMT+08:00) Taipei */ + }, /* (UTC+08:00) Taipei */ { "Tasmania Standard Time", "Tasmania Daylight Time", "Australia/Hobart" - }, /* (GMT+10:00) Hobart */ + }, /* (UTC+10:00) Hobart */ + { + "Tocantins Standard Time", "Tocantins Daylight Time", + "America/Araguaina" + }, /* (UTC-03:00) Araguaina */ { "Tokyo Standard Time", "Tokyo Daylight Time", "Asia/Tokyo" - }, /* (GMT+09:00) Osaka, Sapporo, Tokyo */ + }, /* (UTC+09:00) Osaka, Sapporo, Tokyo */ { "Tonga Standard Time", "Tonga Daylight Time", "Pacific/Tongatapu" - }, /* (GMT+13:00) Nuku'alofa */ + }, /* (UTC+13:00) Nuku'alofa */ + { + "Tomsk Standard Time", "Tomsk Daylight Time", + "Asia/Tomsk" + }, /* (UTC+07:00) Tomsk */ + { + "Transbaikal Standard Time", "Transbaikal Daylight Time", + "Asia/Chita" + }, /* (UTC+09:00) Chita */ + { + "Turkey Standard Time", "Turkey Daylight Time", + "Europe/Istanbul" + }, /* (UTC+02:00) Istanbul */ + { + "Turks and Caicos Standard Time", "Turks and Caicos Daylight Time", + "America/Grand_Turk" + }, /* (UTC-04:00) Turks and Caicos */ { "Ulaanbaatar Standard Time", "Ulaanbaatar Daylight Time", "Asia/Ulaanbaatar", - }, /* (GMT+08:00) Ulaanbaatar */ + }, /* (UTC+08:00) Ulaanbaatar */ { "US Eastern Standard Time", "US Eastern Daylight Time", "US/Eastern" - }, /* (GMT-05:00) Indiana (East) */ + }, /* (UTC-05:00) Indiana (East) */ { "US Mountain Standard Time", "US Mountain Daylight Time", "US/Arizona" - }, /* (GMT-07:00) Arizona */ + }, /* (UTC-07:00) Arizona */ { "Coordinated Universal Time", "Coordinated Universal Time", "UTC" - }, /* (GMT) Coordinated Universal Time */ + }, /* (UTC) Coordinated Universal Time */ { "UTC+12", "UTC+12", "Etc/GMT+12" - }, /* (GMT+12:00) Coordinated Universal Time+12 */ + }, /* (UTC+12:00) Coordinated Universal Time+12 */ { "UTC-02", "UTC-02", "Etc/GMT-02" - }, /* (GMT-02:00) Coordinated Universal Time-02 */ + }, /* (UTC-02:00) Coordinated Universal Time-02 */ + { + "UTC-08", "UTC-08", + "Etc/GMT-08" + }, /* (UTC-08:00) Coordinated Universal Time-08 */ + { + "UTC-09", "UTC-09", + "Etc/GMT-09" + }, /* (UTC-09:00) Coordinated Universal Time-09 */ { "UTC-11", "UTC-11", "Etc/GMT-11" - }, /* (GMT-11:00) Coordinated Universal Time-11 */ + }, /* (UTC-11:00) Coordinated Universal Time-11 */ { "Venezuela Standard Time", "Venezuela Daylight Time", "America/Caracas", - }, /* (GMT-04:30) Caracas */ + }, /* (UTC-04:30) Caracas */ { "Vladivostok Standard Time", "Vladivostok Daylight Time", "Asia/Vladivostok" - }, /* (GMT+10:00) Vladivostok */ + }, /* (UTC+10:00) Vladivostok (RTZ 9) */ { "W. Australia Standard Time", "W. Australia Daylight Time", "Australia/Perth" - }, /* (GMT+08:00) Perth */ + }, /* (UTC+08:00) Perth */ #ifdef NOT_USED /* Could not find a match for this one (just a guess). Excluded for now. */ { "W. Central Africa Standard Time", "W. Central Africa Daylight Time", "WAT" - }, /* (GMT+01:00) West Central Africa */ + }, /* (UTC+01:00) West Central Africa */ #endif { "W. Europe Standard Time", "W. Europe Daylight Time", "CET" - }, /* (GMT+01:00) Amsterdam, Berlin, Bern, Rome, + }, /* (UTC+01:00) Amsterdam, Berlin, Bern, Rome, * Stockholm, Vienna */ + { + "W. Mongolia Standard Time", "W. Mongolia Daylight Time", + "Asia/Hovd" + }, /* (UTC+07:00) Hovd */ { "West Asia Standard Time", "West Asia Daylight Time", "Asia/Karachi" - }, /* (GMT+05:00) Islamabad, Karachi, Tashkent */ + }, /* (UTC+05:00) Ashgabat, Tashkent */ + { + "West Bank Gaza Standard Time", "West Bank Gaza Daylight Time", + "Asia/Gaza" + }, /* (UTC+02:00) Gaza, Hebron */ { "West Pacific Standard Time", "West Pacific Daylight Time", "Pacific/Guam" - }, /* (GMT+10:00) Guam, Port Moresby */ + }, /* (UTC+10:00) Guam, Port Moresby */ { "Yakutsk Standard Time", "Yakutsk Daylight Time", "Asia/Yakutsk" - }, /* (GMT+09:00) Yakutsk */ + }, /* (UTC+09:00) Yakutsk */ { NULL, NULL, NULL } diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index 73cb7ee683..443c2ee468 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -38,7 +38,7 @@ * * This code is released under the terms of the PostgreSQL License. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/initdb/initdb.c @@ -61,21 +61,17 @@ #endif #include "catalog/catalog.h" +#include "catalog/pg_authid.h" +#include "common/file_utils.h" #include "common/restricted_token.h" #include "common/username.h" -#include "mb/pg_wchar.h" +#include "fe_utils/string_utils.h" #include "getaddrinfo.h" #include "getopt_long.h" +#include "mb/pg_wchar.h" #include "miscadmin.h" -/* 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 - /* Ideally this would be in a .h file, but it hardly seems worth the trouble */ extern const char *select_default_timezone(const char *share_path); @@ -134,6 +130,7 @@ static const char *default_text_search_config = ""; static char *username = ""; static bool pwprompt = false; static char *pwfilename = NULL; +static char *superuser_password = NULL; static const char *authmethodhost = ""; static const char *authmethodlocal = ""; static bool debug = false; @@ -199,7 +196,7 @@ static const char *backend_options = "--single -F -O -j -c search_path=pg_catalo static const char *const subdirs[] = { "global", - "pg_xlog/archive_status", + "pg_wal/archive_status", "pg_clog", "pg_commit_ts", "pg_dynshmem", @@ -235,13 +232,6 @@ static char **filter_lines_with_token(char **lines, const char *token); #endif static char **readfile(const char *path); static void writefile(char *path, char **lines); -static void walkdir(const char *path, - void (*action) (const char *fname, bool isdir), - bool process_symlinks); -#ifdef PG_FLUSH_DATA_WORKS -static void pre_sync_fname(const char *fname, bool isdir); -#endif -static void fsync_fname_ext(const char *fname, bool isdir); static FILE *popen_check(const char *command, const char *mode); static void exit_nicely(void); static char *get_id(void); @@ -254,7 +244,7 @@ static void test_config_settings(void); static void setup_config(void); static void bootstrap_template1(void); static void setup_auth(FILE *cmdfd); -static void get_set_pwd(FILE *cmdfd); +static void get_su_pwd(void); static void setup_depend(FILE *cmdfd); static void setup_sysviews(FILE *cmdfd); static void setup_description(FILE *cmdfd); @@ -268,7 +258,6 @@ static void load_plpgsql(FILE *cmdfd); static void vacuum_db(FILE *cmdfd); static void make_template0(FILE *cmdfd); static void make_postgres(FILE *cmdfd); -static void fsync_pgdata(void); static void trapsig(int signum); static void check_ok(void); static char *escape_quotes(const char *src); @@ -331,14 +320,6 @@ do { \ output_failed = true, output_errno = errno; \ } while (0) -#ifndef WIN32 -#define QUOTE_PATH "" -#define DIR_SEP "/" -#else -#define QUOTE_PATH "\"" -#define DIR_SEP "\\" -#endif - static char * escape_quotes(const char *src) { @@ -534,177 +515,6 @@ writefile(char *path, char **lines) } } -/* - * 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, - void (*action) (const char *fname, bool isdir), - bool process_symlinks) -{ - DIR *dir; - struct dirent *de; - - dir = opendir(path); - if (dir == NULL) - { - fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"), - progname, path, strerror(errno)); - return; - } - - while (errno = 0, (de = readdir(dir)) != NULL) - { - char subpath[MAXPGPATH]; - struct stat fst; - int sret; - - if (strcmp(de->d_name, ".") == 0 || - strcmp(de->d_name, "..") == 0) - continue; - - snprintf(subpath, MAXPGPATH, "%s/%s", path, de->d_name); - - if (process_symlinks) - sret = stat(subpath, &fst); - else - sret = lstat(subpath, &fst); - - if (sret < 0) - { - fprintf(stderr, _("%s: could not stat file \"%s\": %s\n"), - progname, subpath, strerror(errno)); - continue; - } - - if (S_ISREG(fst.st_mode)) - (*action) (subpath, false); - else if (S_ISDIR(fst.st_mode)) - walkdir(subpath, action, false); - } - - if (errno) - fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"), - progname, path, strerror(errno)); - - (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 void -pre_sync_fname(const char *fname, bool isdir) -{ - int fd; - - fd = open(fname, O_RDONLY | PG_BINARY); - - if (fd < 0) - { - if (errno == EACCES || (isdir && errno == EISDIR)) - return; - fprintf(stderr, _("%s: could not open file \"%s\": %s\n"), - progname, fname, strerror(errno)); - return; - } - - /* - * 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); -} - -#endif /* PG_FLUSH_DATA_WORKS */ - -/* - * fsync_fname_ext -- 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. Reports - * other errors non-fatally. - */ -static void -fsync_fname_ext(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); - if (fd < 0) - { - if (errno == EACCES || (isdir && errno == EISDIR)) - return; - fprintf(stderr, _("%s: could not open file \"%s\": %s\n"), - progname, fname, strerror(errno)); - return; - } - - 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)) - fprintf(stderr, _("%s: could not fsync file \"%s\": %s\n"), - progname, fname, strerror(errno)); - - (void) close(fd); -} - /* * Open a subcommand with suitable error messaging */ @@ -1286,12 +1096,39 @@ setup_config(void) conflines = replace_token(conflines, "#dynamic_shared_memory_type = posix", repltok); +#if DEFAULT_BACKEND_FLUSH_AFTER > 0 + snprintf(repltok, sizeof(repltok), "#backend_flush_after = %dkB", + DEFAULT_BACKEND_FLUSH_AFTER * (BLCKSZ / 1024)); + conflines = replace_token(conflines, "#backend_flush_after = 0", + repltok); +#endif + +#if DEFAULT_BGWRITER_FLUSH_AFTER > 0 + snprintf(repltok, sizeof(repltok), "#bgwriter_flush_after = %dkB", + DEFAULT_BGWRITER_FLUSH_AFTER * (BLCKSZ / 1024)); + conflines = replace_token(conflines, "#bgwriter_flush_after = 0", + repltok); +#endif + +#if DEFAULT_CHECKPOINT_FLUSH_AFTER > 0 + snprintf(repltok, sizeof(repltok), "#checkpoint_flush_after = %dkB", + DEFAULT_CHECKPOINT_FLUSH_AFTER * (BLCKSZ / 1024)); + conflines = replace_token(conflines, "#checkpoint_flush_after = 0", + repltok); +#endif + #ifndef USE_PREFETCH conflines = replace_token(conflines, "#effective_io_concurrency = 1", "#effective_io_concurrency = 0"); #endif +#ifdef WIN32 + conflines = replace_token(conflines, + "#update_process_title = on", + "#update_process_title = off"); +#endif + snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data); writefile(path, conflines); @@ -1545,30 +1382,35 @@ setup_auth(FILE *cmdfd) for (line = pg_authid_setup; *line != NULL; line++) PG_CMD_PUTS(*line); + + if (superuser_password) + PG_CMD_PRINTF2("ALTER USER \"%s\" WITH PASSWORD E'%s';\n\n", + username, escape_quotes(superuser_password)); } /* - * get the superuser password if required, and call postgres to set it + * get the superuser password if required */ static void -get_set_pwd(FILE *cmdfd) +get_su_pwd(void) { - char *pwd1, - *pwd2; + char pwd1[100]; + char pwd2[100]; if (pwprompt) { /* * Read password from terminal */ - pwd1 = simple_prompt("Enter new superuser password: ", 100, false); - pwd2 = simple_prompt("Enter it again: ", 100, false); + printf("\n"); + fflush(stdout); + simple_prompt("Enter new superuser password: ", pwd1, sizeof(pwd1), false); + simple_prompt("Enter it again: ", pwd2, sizeof(pwd2), false); if (strcmp(pwd1, pwd2) != 0) { fprintf(stderr, _("Passwords didn't match.\n")); exit_nicely(); } - free(pwd2); } else { @@ -1581,7 +1423,6 @@ get_set_pwd(FILE *cmdfd) * for now. */ FILE *pwf = fopen(pwfilename, "r"); - char pwdbuf[MAXPGPATH]; int i; if (!pwf) @@ -1590,7 +1431,7 @@ get_set_pwd(FILE *cmdfd) progname, pwfilename, strerror(errno)); exit_nicely(); } - if (!fgets(pwdbuf, sizeof(pwdbuf), pwf)) + if (!fgets(pwd1, sizeof(pwd1), pwf)) { if (ferror(pwf)) fprintf(stderr, _("%s: could not read password from file \"%s\": %s\n"), @@ -1602,18 +1443,12 @@ get_set_pwd(FILE *cmdfd) } fclose(pwf); - i = strlen(pwdbuf); - while (i > 0 && (pwdbuf[i - 1] == '\r' || pwdbuf[i - 1] == '\n')) - pwdbuf[--i] = '\0'; - - pwd1 = pg_strdup(pwdbuf); - + i = strlen(pwd1); + while (i > 0 && (pwd1[i - 1] == '\r' || pwd1[i - 1] == '\n')) + pwd1[--i] = '\0'; } - PG_CMD_PRINTF2("ALTER USER \"%s\" WITH PASSWORD E'%s';\n\n", - username, escape_quotes(pwd1)); - - free(pwd1); + superuser_password = pg_strdup(pwd1); } /* @@ -1774,178 +1609,16 @@ setup_description(FILE *cmdfd) PG_CMD_PUTS("DROP TABLE tmp_pg_shdescription;\n\n"); } -#ifdef HAVE_LOCALE_T -/* - * "Normalize" a locale name, stripping off encoding tags such as - * ".utf8" (e.g., "en_US.utf8" -> "en_US", but "br_FR.iso885915@euro" - * -> "br_FR@euro"). Return true if a new, different name was - * generated. - */ -static bool -normalize_locale_name(char *new, const char *old) -{ - char *n = new; - const char *o = old; - bool changed = false; - - while (*o) - { - if (*o == '.') - { - /* skip over encoding tag such as ".utf8" or ".UTF-8" */ - o++; - while ((*o >= 'A' && *o <= 'Z') - || (*o >= 'a' && *o <= 'z') - || (*o >= '0' && *o <= '9') - || (*o == '-')) - o++; - changed = true; - } - else - *n++ = *o++; - } - *n = '\0'; - - return changed; -} -#endif /* HAVE_LOCALE_T */ - /* * populate pg_collation */ static void setup_collation(FILE *cmdfd) { -#if defined(HAVE_LOCALE_T) && !defined(WIN32) - int i; - FILE *locale_a_handle; - char localebuf[NAMEDATALEN]; /* we assume ASCII so this is fine */ - int count = 0; - - locale_a_handle = popen_check("locale -a", "r"); - if (!locale_a_handle) - return; /* complaint already printed */ - - PG_CMD_PUTS("CREATE TEMP TABLE tmp_pg_collation ( " - " collname name, " - " locale name, " - " encoding int) WITHOUT OIDS;\n\n"); - - while (fgets(localebuf, sizeof(localebuf), locale_a_handle)) - { - size_t len; - int enc; - bool skip; - char *quoted_locale; - char alias[NAMEDATALEN]; - - len = strlen(localebuf); - - if (len == 0 || localebuf[len - 1] != '\n') - { - if (debug) - fprintf(stderr, _("%s: locale name too long, skipped: \"%s\"\n"), - progname, localebuf); - continue; - } - localebuf[len - 1] = '\0'; - - /* - * Some systems have locale names that don't consist entirely of ASCII - * letters (such as "bokmål" or "français"). This is - * pretty silly, since we need the locale itself to interpret the - * non-ASCII characters. We can't do much with those, so we filter - * them out. - */ - skip = false; - for (i = 0; i < len; i++) - { - if (IS_HIGHBIT_SET(localebuf[i])) - { - skip = true; - break; - } - } - if (skip) - { - if (debug) - fprintf(stderr, _("%s: locale name has non-ASCII characters, skipped: \"%s\"\n"), - progname, localebuf); - continue; - } - - enc = pg_get_encoding_from_locale(localebuf, debug); - if (enc < 0) - { - /* error message printed by pg_get_encoding_from_locale() */ - continue; - } - if (!PG_VALID_BE_ENCODING(enc)) - continue; /* ignore locales for client-only encodings */ - if (enc == PG_SQL_ASCII) - continue; /* C/POSIX are already in the catalog */ - - count++; - - quoted_locale = escape_quotes(localebuf); - - PG_CMD_PRINTF3("INSERT INTO tmp_pg_collation VALUES (E'%s', E'%s', %d);\n\n", - quoted_locale, quoted_locale, enc); - - /* - * Generate aliases such as "en_US" in addition to "en_US.utf8" for - * ease of use. Note that collation names are unique per encoding - * only, so this doesn't clash with "en_US" for LATIN1, say. - */ - if (normalize_locale_name(alias, localebuf)) - { - char *quoted_alias = escape_quotes(alias); - - PG_CMD_PRINTF3("INSERT INTO tmp_pg_collation VALUES (E'%s', E'%s', %d);\n\n", - quoted_alias, quoted_locale, enc); - free(quoted_alias); - } - free(quoted_locale); - } + PG_CMD_PUTS("SELECT pg_import_system_collations(if_not_exists => false, schema => 'pg_catalog');\n\n"); /* Add an SQL-standard name */ - PG_CMD_PRINTF1("INSERT INTO tmp_pg_collation VALUES ('ucs_basic', 'C', %d);\n\n", PG_UTF8); - - /* - * When copying collations to the final location, eliminate aliases that - * conflict with an existing locale name for the same encoding. For - * example, "br_FR.iso88591" is normalized to "br_FR", both for encoding - * LATIN1. But the unnormalized locale "br_FR" already exists for LATIN1. - * Prefer the alias that matches the OS locale name, else the first locale - * name by sort order (arbitrary choice to be deterministic). - * - * Also, eliminate any aliases that conflict with pg_collation's - * hard-wired entries for "C" etc. - */ - PG_CMD_PUTS("INSERT INTO pg_collation (collname, collnamespace, collowner, collencoding, collcollate, collctype) " - " SELECT DISTINCT ON (collname, encoding)" - " collname, " - " (SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog') AS collnamespace, " - " (SELECT relowner FROM pg_class WHERE relname = 'pg_collation') AS collowner, " - " encoding, locale, locale " - " FROM tmp_pg_collation" - " WHERE NOT EXISTS (SELECT 1 FROM pg_collation WHERE collname = tmp_pg_collation.collname)" - " ORDER BY collname, encoding, (collname = locale) DESC, locale;\n\n"); - - /* - * Even though the table is temp, drop it explicitly so it doesn't get - * copied into template0/postgres databases. - */ - PG_CMD_PUTS("DROP TABLE tmp_pg_collation;\n\n"); - - pclose(locale_a_handle); - - if (count == 0 && !debug) - { - printf(_("No usable system locales were found.\n")); - printf(_("Use the option \"--debug\" to see details.\n")); - } -#endif /* not HAVE_LOCALE_T && not WIN32 */ + PG_CMD_PRINTF2("INSERT INTO pg_collation (collname, collnamespace, collowner, collencoding, collcollate, collctype) VALUES ('ucs_basic', 'pg_catalog'::regnamespace, %u, %d, 'C', 'C');\n\n", BOOTSTRAP_SUPERUSERID, PG_UTF8); } /* @@ -2016,7 +1689,7 @@ setup_privileges(FILE *cmdfd) " SET relacl = (SELECT array_agg(a.acl) FROM " " (SELECT E'=r/\"$POSTGRES_SUPERUSERNAME\"' as acl " " UNION SELECT unnest(pg_catalog.acldefault(" - " CASE WHEN relkind = 'S' THEN 's' ELSE 'r' END::\"char\",10::oid))" + " CASE WHEN relkind = 'S' THEN 's' ELSE 'r' END::\"char\"," CppAsString2(BOOTSTRAP_SUPERUSERID) "::oid))" " ) as a) " " WHERE relkind IN ('r', 'v', 'm', 'S') AND relacl IS NULL;\n\n", "GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n\n", @@ -2278,79 +1951,6 @@ make_postgres(FILE *cmdfd) PG_CMD_PUTS(*line); } -/* - * 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_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. - * - * Errors are reported but not considered fatal. - */ -static void -fsync_pgdata(void) -{ - bool xlog_is_symlink; - char pg_xlog[MAXPGPATH]; - char pg_tblspc[MAXPGPATH]; - - fputs(_("syncing data to disk ... "), stdout); - fflush(stdout); - - snprintf(pg_xlog, MAXPGPATH, "%s/pg_xlog", pg_data); - snprintf(pg_tblspc, MAXPGPATH, "%s/pg_tblspc", pg_data); - - /* - * If pg_xlog is a symlink, we'll need to recurse into it separately, - * because the first walkdir below will ignore it. - */ - xlog_is_symlink = false; - -#ifndef WIN32 - { - struct stat st; - - if (lstat(pg_xlog, &st) < 0) - fprintf(stderr, _("%s: could not stat file \"%s\": %s\n"), - progname, pg_xlog, strerror(errno)); - else if (S_ISLNK(st.st_mode)) - xlog_is_symlink = true; - } -#else - if (pgwin32_is_junction(pg_xlog)) - xlog_is_symlink = true; -#endif - - /* - * 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_xlog, 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_xlog 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_ext, false); - if (xlog_is_symlink) - walkdir(pg_xlog, fsync_fname_ext, false); - walkdir(pg_tblspc, fsync_fname_ext, true); - - check_ok(); -} - - /* * signal handler in case we are interrupted. * @@ -2660,8 +2260,8 @@ usage(const char *progname) printf(_(" -d, --debug generate lots of debugging output\n")); printf(_(" -k, --data-checksums use data page checksums\n")); printf(_(" -L DIRECTORY where to find the input files\n")); - printf(_(" -n, --noclean do not clean up after errors\n")); - printf(_(" -N, --nosync do not wait for changes to be written safely to disk\n")); + printf(_(" -n, --no-clean do not clean up after errors\n")); + printf(_(" -N, --no-sync do not wait for changes to be written safely to disk\n")); printf(_(" -s, --show show internal settings\n")); printf(_(" -S, --sync-only only sync data directory\n")); printf(_("\nOther options:\n")); @@ -3088,7 +2688,7 @@ create_xlog_or_symlink(void) char *subdirloc; /* form name of the place for the subdirectory or symlink */ - subdirloc = psprintf("%s/pg_xlog", pg_data); + subdirloc = psprintf("%s/pg_wal", pg_data); if (strcmp(xlog_dir, "") != 0) { @@ -3221,7 +2821,7 @@ initialize_data_directory(void) create_xlog_or_symlink(); - /* Create required subdirectories (other than pg_xlog) */ + /* Create required subdirectories (other than pg_wal) */ printf(_("creating subdirectories ... ")); fflush(stdout); @@ -3280,8 +2880,6 @@ initialize_data_directory(void) PG_CMD_OPEN; setup_auth(cmdfd); - if (pwprompt || pwfilename) - get_set_pwd(cmdfd); setup_depend(cmdfd); @@ -3338,8 +2936,10 @@ main(int argc, char *argv[]) {"version", no_argument, NULL, 'V'}, {"debug", no_argument, NULL, 'd'}, {"show", no_argument, NULL, 's'}, - {"noclean", no_argument, NULL, 'n'}, - {"nosync", no_argument, NULL, 'N'}, + {"noclean", no_argument, NULL, 'n'}, /* for backwards compatibility */ + {"no-clean", no_argument, NULL, 'n'}, + {"nosync", no_argument, NULL, 'N'}, /* for backwards compatibility */ + {"no-sync", no_argument, NULL, 'N'}, {"sync-only", no_argument, NULL, 'S'}, {"xlogdir", required_argument, NULL, 'X'}, {"data-checksums", no_argument, NULL, 'k'}, @@ -3353,7 +2953,8 @@ main(int argc, char *argv[]) int c; int option_index; char *effective_user; - char bin_dir[MAXPGPATH]; + PQExpBuffer start_db_cmd; + char pg_ctl_path[MAXPGPATH]; /* * Ensure that buffering behavior of stdout and stderr matches what it is @@ -3424,7 +3025,7 @@ main(int argc, char *argv[]) break; case 'n': noclean = true; - printf(_("Running in noclean mode. Mistakes will not be cleaned up.\n")); + printf(_("Running in no-clean mode. Mistakes will not be cleaned up.\n")); break; case 'N': do_sync = false; @@ -3515,7 +3116,10 @@ main(int argc, char *argv[]) exit_nicely(); } - fsync_pgdata(); + fputs(_("syncing data to disk ... "), stdout); + fflush(stdout); + fsync_pgdata(pg_data, progname, PG_VERSION_NUM); + check_ok(); return 0; } @@ -3569,26 +3173,53 @@ main(int argc, char *argv[]) else printf(_("Data page checksums are disabled.\n")); + if (pwprompt || pwfilename) + get_su_pwd(); + printf("\n"); initialize_data_directory(); if (do_sync) - fsync_pgdata(); + { + fputs(_("syncing data to disk ... "), stdout); + fflush(stdout); + fsync_pgdata(pg_data, progname, PG_VERSION_NUM); + check_ok(); + } else printf(_("\nSync to disk skipped.\nThe data directory might become corrupt if the operating system crashes.\n")); if (authwarning != NULL) fprintf(stderr, "%s", authwarning); - /* Get directory specification used to start this executable */ - strlcpy(bin_dir, argv[0], sizeof(bin_dir)); - get_parent_directory(bin_dir); + /* + * Build up a shell command to tell the user how to start the server + */ + start_db_cmd = createPQExpBuffer(); + + /* Get directory specification used to start initdb ... */ + strlcpy(pg_ctl_path, argv[0], sizeof(pg_ctl_path)); + canonicalize_path(pg_ctl_path); + get_parent_directory(pg_ctl_path); + /* ... and tag on pg_ctl instead */ + join_path_components(pg_ctl_path, pg_ctl_path, "pg_ctl"); + + /* path to pg_ctl, properly quoted */ + appendShellString(start_db_cmd, pg_ctl_path); + + /* add -D switch, with properly quoted data directory */ + appendPQExpBufferStr(start_db_cmd, " -D "); + appendShellString(start_db_cmd, pgdata_native); + + /* add suggested -l switch and "start" command */ + appendPQExpBufferStr(start_db_cmd, " -l logfile start"); printf(_("\nSuccess. You can now start the database server using:\n\n" - " %s%s%spg_ctl%s -D %s%s%s -l logfile start\n\n"), - QUOTE_PATH, bin_dir, (strlen(bin_dir) > 0) ? DIR_SEP : "", QUOTE_PATH, - QUOTE_PATH, pgdata_native, QUOTE_PATH); + " %s\n\n"), + start_db_cmd->data); + + destroyPQExpBuffer(start_db_cmd); return 0; } diff --git a/src/bin/initdb/nls.mk b/src/bin/initdb/nls.mk index 0d5368304e..7a12daa6fb 100644 --- a/src/bin/initdb/nls.mk +++ b/src/bin/initdb/nls.mk @@ -1,5 +1,5 @@ # src/bin/initdb/nls.mk CATALOG_NAME = initdb AVAIL_LANGUAGES = cs de es fr it ja ko pl pt_BR ru sv zh_CN -GETTEXT_FILES = findtimezone.c initdb.c ../../common/exec.c ../../common/fe_memutils.c ../../common/pgfnames.c ../../common/restricted_token.c ../../common/rmtree.c ../../common/username.c ../../common/wait_error.c ../../port/dirmod.c +GETTEXT_FILES = findtimezone.c initdb.c ../../common/exec.c ../../common/fe_memutils.c ../../common/file_utils.c ../../common/pgfnames.c ../../common/restricted_token.c ../../common/rmtree.c ../../common/username.c ../../common/wait_error.c ../../port/dirmod.c GETTEXT_TRIGGERS = simple_prompt diff --git a/src/bin/pg_archivecleanup/nls.mk b/src/bin/pg_archivecleanup/nls.mk new file mode 100644 index 0000000000..fd959a5c8b --- /dev/null +++ b/src/bin/pg_archivecleanup/nls.mk @@ -0,0 +1,4 @@ +# src/bin/pg_archivecleanup/nls.mk +CATALOG_NAME = pg_archivecleanup +AVAIL_LANGUAGES = +GETTEXT_FILES = pg_archivecleanup.c diff --git a/src/bin/pg_archivecleanup/pg_archivecleanup.c b/src/bin/pg_archivecleanup/pg_archivecleanup.c index 2b3d15dd58..f1651d4273 100644 --- a/src/bin/pg_archivecleanup/pg_archivecleanup.c +++ b/src/bin/pg_archivecleanup/pg_archivecleanup.c @@ -70,7 +70,7 @@ Initialize(void) if (stat(archiveLocation, &stat_buf) != 0 || !S_ISDIR(stat_buf.st_mode)) { - fprintf(stderr, "%s: archive location \"%s\" does not exist\n", + fprintf(stderr, _("%s: archive location \"%s\" does not exist\n"), progname, archiveLocation); exit(2); } @@ -146,19 +146,19 @@ CleanupPriorWALFiles(void) printf("%s\n", WALFilePath); if (debug) fprintf(stderr, - "%s: file \"%s\" would be removed\n", + _("%s: file \"%s\" would be removed\n"), progname, WALFilePath); continue; } if (debug) - fprintf(stderr, "%s: removing file \"%s\"\n", + fprintf(stderr, _("%s: removing file \"%s\"\n"), progname, WALFilePath); rc = unlink(WALFilePath); if (rc != 0) { - fprintf(stderr, "%s: ERROR: could not remove file \"%s\": %s\n", + fprintf(stderr, _("%s: ERROR: could not remove file \"%s\": %s\n"), progname, WALFilePath, strerror(errno)); break; } @@ -166,14 +166,14 @@ CleanupPriorWALFiles(void) } if (errno) - fprintf(stderr, "%s: could not read archive location \"%s\": %s\n", + fprintf(stderr, _("%s: could not read archive location \"%s\": %s\n"), progname, archiveLocation, strerror(errno)); if (closedir(xldir)) - fprintf(stderr, "%s: could not close archive location \"%s\": %s\n", + fprintf(stderr, _("%s: could not close archive location \"%s\": %s\n"), progname, archiveLocation, strerror(errno)); } else - fprintf(stderr, "%s: could not open archive location \"%s\": %s\n", + fprintf(stderr, _("%s: could not open archive location \"%s\": %s\n"), progname, archiveLocation, strerror(errno)); } @@ -246,8 +246,8 @@ SetWALFileNameForCleanup(void) if (!fnameOK) { - fprintf(stderr, "%s: invalid filename input\n", progname); - fprintf(stderr, "Try \"%s --help\" for more information.\n", progname); + fprintf(stderr, _("%s: invalid filename input\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(2); } } @@ -260,25 +260,25 @@ SetWALFileNameForCleanup(void) static void usage(void) { - printf("%s removes older WAL files from PostgreSQL archives.\n\n", progname); - printf("Usage:\n"); - printf(" %s [OPTION]... ARCHIVELOCATION OLDESTKEPTWALFILE\n", progname); - printf("\nOptions:\n"); - printf(" -d generate debug output (verbose mode)\n"); - printf(" -n dry run, show the names of the files that would be removed\n"); - printf(" -V, --version output version information, then exit\n"); - printf(" -x EXT clean up files if they have this extension\n"); - printf(" -?, --help show this help, then exit\n"); - printf("\n" - "For use as archive_cleanup_command in recovery.conf when standby_mode = on:\n" - " archive_cleanup_command = 'pg_archivecleanup [OPTION]... ARCHIVELOCATION %%r'\n" - "e.g.\n" - " archive_cleanup_command = 'pg_archivecleanup /mnt/server/archiverdir %%r'\n"); - printf("\n" - "Or for use as a standalone archive cleaner:\n" - "e.g.\n" - " pg_archivecleanup /mnt/server/archiverdir 000000010000000000000010.00000020.backup\n"); - printf("\nReport bugs to .\n"); + printf(_("%s removes older WAL files from PostgreSQL archives.\n\n"), progname); + printf(_("Usage:\n")); + printf(_(" %s [OPTION]... ARCHIVELOCATION OLDESTKEPTWALFILE\n"), progname); + printf(_("\nOptions:\n")); + printf(_(" -d generate debug output (verbose mode)\n")); + printf(_(" -n dry run, show the names of the files that would be removed\n")); + printf(_(" -V, --version output version information, then exit\n")); + printf(_(" -x EXT clean up files if they have this extension\n")); + printf(_(" -?, --help show this help, then exit\n")); + printf(_("\n" + "For use as archive_cleanup_command in recovery.conf when standby_mode = on:\n" + " archive_cleanup_command = 'pg_archivecleanup [OPTION]... ARCHIVELOCATION %%r'\n" + "e.g.\n" + " archive_cleanup_command = 'pg_archivecleanup /mnt/server/archiverdir %%r'\n")); + printf(_("\n" + "Or for use as a standalone archive cleaner:\n" + "e.g.\n" + " pg_archivecleanup /mnt/server/archiverdir 000000010000000000000010.00000020.backup\n")); + printf(_("\nReport bugs to .\n")); } /*------------ MAIN ----------------------------------------*/ @@ -287,6 +287,7 @@ main(int argc, char **argv) { int c; + set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_archivecleanup")); progname = get_progname(argv[0]); if (argc > 1) @@ -314,11 +315,11 @@ main(int argc, char **argv) dryrun = true; break; case 'x': - additional_ext = strdup(optarg); /* Extension to remove + additional_ext = pg_strdup(optarg); /* Extension to remove * from xlogfile names */ break; default: - fprintf(stderr, "Try \"%s --help\" for more information.\n", progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(2); break; } @@ -338,8 +339,8 @@ main(int argc, char **argv) } else { - fprintf(stderr, "%s: must specify archive location\n", progname); - fprintf(stderr, "Try \"%s --help\" for more information.\n", progname); + fprintf(stderr, _("%s: must specify archive location\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(2); } @@ -350,15 +351,15 @@ main(int argc, char **argv) } else { - fprintf(stderr, "%s: must specify restartfilename\n", progname); - fprintf(stderr, "Try \"%s --help\" for more information.\n", progname); + fprintf(stderr, _("%s: must specify restartfilename\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(2); } if (optind < argc) { - fprintf(stderr, "%s: too many parameters\n", progname); - fprintf(stderr, "Try \"%s --help\" for more information.\n", progname); + fprintf(stderr, _("%s: too many parameters\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(2); } @@ -376,7 +377,7 @@ main(int argc, char **argv) { snprintf(WALFilePath, MAXPGPATH, "%s/%s", archiveLocation, exclusiveCleanupFileName); - fprintf(stderr, "%s: keep WAL file \"%s\" and later\n", + fprintf(stderr, _("%s: keep WAL file \"%s\" and later\n"), progname, WALFilePath); } diff --git a/src/bin/pg_basebackup/Makefile b/src/bin/pg_basebackup/Makefile index 585467205b..a6c307492f 100644 --- a/src/bin/pg_basebackup/Makefile +++ b/src/bin/pg_basebackup/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/pg_basebackup # -# Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/bin/pg_basebackup/Makefile @@ -12,23 +12,26 @@ PGFILEDESC = "pg_basebackup/pg_receivexlog/pg_recvlogical - streaming WAL and backup receivers" PGAPPICON=win32 +EXTRA_INSTALL=contrib/test_decoding + subdir = src/bin/pg_basebackup top_builddir = ../../.. include $(top_builddir)/src/Makefile.global override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS) +LDFLAGS += -L$(top_builddir)/src/fe_utils -lpgfeutils -lpq -OBJS=receivelog.o streamutil.o $(WIN32RES) +OBJS=receivelog.o streamutil.o walmethods.o $(WIN32RES) all: pg_basebackup pg_receivexlog pg_recvlogical -pg_basebackup: pg_basebackup.o $(OBJS) | submake-libpq submake-libpgport +pg_basebackup: pg_basebackup.o $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils $(CC) $(CFLAGS) pg_basebackup.o $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) -pg_receivexlog: pg_receivexlog.o $(OBJS) | submake-libpq submake-libpgport +pg_receivexlog: pg_receivexlog.o $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils $(CC) $(CFLAGS) pg_receivexlog.o $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) -pg_recvlogical: pg_recvlogical.o $(OBJS) | submake-libpq submake-libpgport +pg_recvlogical: pg_recvlogical.o $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils $(CC) $(CFLAGS) pg_recvlogical.o $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) install: all installdirs diff --git a/src/bin/pg_basebackup/nls.mk b/src/bin/pg_basebackup/nls.mk index ec466dcaa2..dba43b857e 100644 --- a/src/bin/pg_basebackup/nls.mk +++ b/src/bin/pg_basebackup/nls.mk @@ -1,4 +1,5 @@ # src/bin/pg_basebackup/nls.mk CATALOG_NAME = pg_basebackup AVAIL_LANGUAGES = de es fr it ko pl pt_BR ru zh_CN -GETTEXT_FILES = pg_basebackup.c pg_receivexlog.c pg_recvlogical.c receivelog.c streamutil.c ../../common/fe_memutils.c +GETTEXT_FILES = pg_basebackup.c pg_receivexlog.c pg_recvlogical.c receivelog.c streamutil.c ../../common/fe_memutils.c ../../common/file_utils.c +GETTEXT_TRIGGERS = simple_prompt diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c index ed41db8e6e..ce1fe3bf00 100644 --- a/src/bin/pg_basebackup/pg_basebackup.c +++ b/src/bin/pg_basebackup/pg_basebackup.c @@ -4,7 +4,7 @@ * * Author: Magnus Hagander * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/pg_basebackup/pg_basebackup.c @@ -20,12 +20,16 @@ #include #include #include - +#ifdef HAVE_SYS_SELECT_H +#include +#endif #ifdef HAVE_LIBZ #include #endif +#include "common/file_utils.h" #include "common/string.h" +#include "fe_utils/string_utils.h" #include "getopt_long.h" #include "libpq-fe.h" #include "pqexpbuffer.h" @@ -51,23 +55,54 @@ typedef struct TablespaceList TablespaceListCell *tail; } TablespaceList; +/* + * pg_xlog has been renamed to pg_wal in version 10. This version number + * should be compared with PQserverVersion(). + */ +#define MINIMUM_VERSION_FOR_PG_WAL 100000 + +/* + * Temporary replication slots are supported from version 10. + */ +#define MINIMUM_VERSION_FOR_TEMP_SLOTS 100000 + +/* + * Different ways to include WAL + */ +typedef enum +{ + NO_WAL, + FETCH_WAL, + STREAM_WAL +} IncludeWal; + /* Global options */ static char *basedir = NULL; static TablespaceList tablespace_dirs = {NULL, NULL}; static char *xlog_dir = ""; static char format = 'p'; /* p(lain)/t(ar) */ static char *label = "pg_basebackup base backup"; +static bool noclean = false; static bool showprogress = false; static int verbose = 0; static int compresslevel = 0; -static bool includewal = false; -static bool streamwal = false; +static IncludeWal includewal = STREAM_WAL; static bool fastcheckpoint = false; static bool writerecoveryconf = false; +static bool do_sync = true; static int standby_message_timeout = 10 * 1000; /* 10 sec = default */ static pg_time_t last_progress_report = 0; static int32 maxrate = 0; /* no limit by default */ +static char *replication_slot = NULL; +static bool temp_replication_slot = true; +static bool success = false; +static bool made_new_pgdata = false; +static bool found_existing_pgdata = false; +static bool made_new_xlogdir = false; +static bool found_existing_xlogdir = false; +static bool made_tablespace_dirs = false; +static bool found_tablespace_dirs = false; /* Progress counters */ static uint64 totalsize; @@ -81,6 +116,7 @@ static int bgpipe[2] = {-1, -1}; /* Handle to child process */ static pid_t bgchild = -1; +static bool in_log_streamer = false; /* End position for xlog streaming, empty string if unknown yet */ static XLogRecPtr xlogendptr; @@ -97,7 +133,7 @@ static PQExpBuffer recoveryconfcontents = NULL; /* Function headers */ static void usage(void); static void disconnect_and_exit(int code); -static void verify_dir_is_empty_or_create(char *dirname); +static void verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found); static void progress_report(int tablespacenum, const char *filename, bool force); static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum); @@ -113,6 +149,69 @@ static const char *get_tablespace_mapping(const char *dir); static void tablespace_list_append(const char *arg); +static void +cleanup_directories_atexit(void) +{ + if (success || in_log_streamer) + return; + + if (!noclean) + { + if (made_new_pgdata) + { + fprintf(stderr, _("%s: removing data directory \"%s\"\n"), + progname, basedir); + if (!rmtree(basedir, true)) + fprintf(stderr, _("%s: failed to remove data directory\n"), + progname); + } + else if (found_existing_pgdata) + { + fprintf(stderr, + _("%s: removing contents of data directory \"%s\"\n"), + progname, basedir); + if (!rmtree(basedir, false)) + fprintf(stderr, _("%s: failed to remove contents of data directory\n"), + progname); + } + + if (made_new_xlogdir) + { + fprintf(stderr, _("%s: removing transaction log directory \"%s\"\n"), + progname, xlog_dir); + if (!rmtree(xlog_dir, true)) + fprintf(stderr, _("%s: failed to remove transaction log directory\n"), + progname); + } + else if (found_existing_xlogdir) + { + fprintf(stderr, + _("%s: removing contents of transaction log directory \"%s\"\n"), + progname, xlog_dir); + if (!rmtree(xlog_dir, false)) + fprintf(stderr, _("%s: failed to remove contents of transaction log directory\n"), + progname); + } + } + else + { + if (made_new_pgdata || found_existing_pgdata) + fprintf(stderr, + _("%s: data directory \"%s\" not removed at user's request\n"), + progname, basedir); + + if (made_new_xlogdir || found_existing_xlogdir) + fprintf(stderr, + _("%s: transaction log directory \"%s\" not removed at user's request\n"), + progname, xlog_dir); + } + + if (made_tablespace_dirs || found_tablespace_dirs) + fprintf(stderr, + _("%s: changes to tablespace directories will not be undone\n"), + progname); +} + static void disconnect_and_exit(int code) { @@ -240,10 +339,10 @@ usage(void) printf(_(" -R, --write-recovery-conf\n" " write recovery.conf after backup\n")); printf(_(" -S, --slot=SLOTNAME replication slot to use\n")); + printf(_(" --no-slot prevent creation of temporary replication slot\n")); printf(_(" -T, --tablespace-mapping=OLDDIR=NEWDIR\n" " relocate tablespace in OLDDIR to NEWDIR\n")); - printf(_(" -x, --xlog include required WAL files in backup (fetch mode)\n")); - printf(_(" -X, --xlog-method=fetch|stream\n" + printf(_(" -X, --xlog-method=none|fetch|stream\n" " include required WAL files with specified method\n")); printf(_(" --xlogdir=XLOGDIR location for the transaction log directory\n")); printf(_(" -z, --gzip compress tar output\n")); @@ -252,6 +351,8 @@ usage(void) printf(_(" -c, --checkpoint=fast|spread\n" " set fast or spread checkpointing\n")); printf(_(" -l, --label=LABEL set backup label\n")); + printf(_(" -n, --no-clean do not clean up after errors\n")); + printf(_(" -N, --no-sync do not wait for changes to be written safely to disk\n")); printf(_(" -P, --progress show progress information\n")); printf(_(" -v, --verbose output verbose messages\n")); printf(_(" -V, --version output version information, then exit\n")); @@ -364,9 +465,10 @@ typedef struct { PGconn *bgconn; XLogRecPtr startptr; - char xlogdir[MAXPGPATH]; + char xlog[MAXPGPATH]; /* directory or tarfile depending on mode */ char *sysidentifier; int timeline; + bool temp_slot; } logstreamer_param; static int @@ -374,6 +476,8 @@ LogStreamerMain(logstreamer_param *param) { StreamCtl stream; + in_log_streamer = true; + MemSet(&stream, 0, sizeof(stream)); stream.startpos = param->startptr; stream.timeline = param->timeline; @@ -381,9 +485,18 @@ LogStreamerMain(logstreamer_param *param) stream.stream_stop = reached_end_position; stream.standby_message_timeout = standby_message_timeout; stream.synchronous = false; + stream.do_sync = do_sync; stream.mark_done = true; - stream.basedir = param->xlogdir; stream.partial_suffix = NULL; + stream.replication_slot = replication_slot; + stream.temp_slot = param->temp_slot; + if (stream.temp_slot && !stream.replication_slot) + stream.replication_slot = psprintf("pg_basebackup_%d", (int) getpid()); + + if (format == 'p') + stream.walmethod = CreateWalDirectoryMethod(param->xlog, 0, do_sync); + else + stream.walmethod = CreateWalTarMethod(param->xlog, compresslevel, do_sync); if (!ReceiveXlogStream(param->bgconn, &stream)) @@ -394,7 +507,22 @@ LogStreamerMain(logstreamer_param *param) */ return 1; + if (!stream.walmethod->finish()) + { + fprintf(stderr, + _("%s: could not finish writing WAL files: %s\n"), + progname, strerror(errno)); + return 1; + } + PQfinish(param->bgconn); + + if (format == 'p') + FreeWalDirectoryMethod(); + else + FreeWalTarMethod(); + pg_free(stream.walmethod); + return 0; } @@ -444,22 +572,38 @@ StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier) /* Error message already written in GetConnection() */ exit(1); - snprintf(param->xlogdir, sizeof(param->xlogdir), "%s/pg_xlog", basedir); + /* In post-10 cluster, pg_xlog has been renamed to pg_wal */ + snprintf(param->xlog, sizeof(param->xlog), "%s/%s", + basedir, + PQserverVersion(conn) < MINIMUM_VERSION_FOR_PG_WAL ? + "pg_xlog" : "pg_wal"); - /* - * Create pg_xlog/archive_status (and thus pg_xlog) so we can write to - * basedir/pg_xlog as the directory entry in the tar file may arrive - * later. - */ - snprintf(statusdir, sizeof(statusdir), "%s/pg_xlog/archive_status", - basedir); + /* Temporary replication slots are only supported in 10 and newer */ + if (PQserverVersion(conn) < MINIMUM_VERSION_FOR_TEMP_SLOTS) + param->temp_slot = false; + else + param->temp_slot = temp_replication_slot; - if (pg_mkdir_p(statusdir, S_IRWXU) != 0 && errno != EEXIST) + if (format == 'p') { - fprintf(stderr, - _("%s: could not create directory \"%s\": %s\n"), - progname, statusdir, strerror(errno)); - disconnect_and_exit(1); + /* + * Create pg_wal/archive_status or pg_xlog/archive_status (and thus + * pg_wal or pg_xlog) depending on the target server so we can write to + * basedir/pg_wal or basedir/pg_xlog as the directory entry in the tar + * file may arrive later. + */ + snprintf(statusdir, sizeof(statusdir), "%s/%s/archive_status", + basedir, + PQserverVersion(conn) < MINIMUM_VERSION_FOR_PG_WAL ? + "pg_xlog" : "pg_wal"); + + if (pg_mkdir_p(statusdir, S_IRWXU) != 0 && errno != EEXIST) + { + fprintf(stderr, + _("%s: could not create directory \"%s\": %s\n"), + progname, statusdir, strerror(errno)); + disconnect_and_exit(1); + } } /* @@ -500,7 +644,7 @@ StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier) * be give and the process ended. */ static void -verify_dir_is_empty_or_create(char *dirname) +verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found) { switch (pg_check_dir(dirname)) { @@ -516,12 +660,16 @@ verify_dir_is_empty_or_create(char *dirname) progname, dirname, strerror(errno)); disconnect_and_exit(1); } + if (created) + *created = true; return; case 1: /* * Exists, empty */ + if (found) + *found = true; return; case 2: case 3: @@ -1114,6 +1262,10 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum) if (copybuf != NULL) PQfreemem(copybuf); + + /* sync the resulting tar file, errors are not considered fatal */ + if (do_sync && strcmp(basedir, "-") != 0) + (void) fsync_fname(filename, false, progname); } @@ -1248,15 +1400,17 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum) if (mkdir(filename, S_IRWXU) != 0) { /* - * When streaming WAL, pg_xlog will have been created - * by the wal receiver process. Also, when transaction - * log directory location was specified, pg_xlog has - * already been created as a symbolic link before - * starting the actual backup. So just ignore creation - * failures on related directories. + * When streaming WAL, pg_wal (or pg_xlog for pre-9.6 + * clusters) will have been created by the wal receiver + * process. Also, when transaction log directory location + * was specified, pg_wal (or pg_xlog) has already been + * created as a symbolic link before starting the actual + * backup. So just ignore creation failures on related + * directories. */ - if (!((pg_str_endswith(filename, "/pg_xlog") || - pg_str_endswith(filename, "/archive_status")) && + if (!((pg_str_endswith(filename, "/pg_wal") || + pg_str_endswith(filename, "/pg_xlog")|| + pg_str_endswith(filename, "/archive_status")) && errno == EEXIST)) { fprintf(stderr, @@ -1390,69 +1544,11 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum) if (basetablespace && writerecoveryconf) WriteRecoveryConf(); -} - -/* - * Escape a parameter value so that it can be used as part of a libpq - * connection string, e.g. in: - * - * application_name= - * - * The returned string is malloc'd. Return NULL on out-of-memory. - */ -static char * -escapeConnectionParameter(const char *src) -{ - bool need_quotes = false; - bool need_escaping = false; - const char *p; - char *dstbuf; - char *dst; /* - * First check if quoting is needed. Any quote (') or backslash (\) - * characters need to be escaped. Parameters are separated by whitespace, - * so any string containing whitespace characters need to be quoted. An - * empty string is represented by ''. + * No data is synced here, everything is done for all tablespaces at the + * end. */ - if (strchr(src, '\'') != NULL || strchr(src, '\\') != NULL) - need_escaping = true; - - for (p = src; *p; p++) - { - if (isspace((unsigned char) *p)) - { - need_quotes = true; - break; - } - } - - if (*src == '\0') - return pg_strdup("''"); - - if (!need_quotes && !need_escaping) - return pg_strdup(src); /* no quoting or escaping needed */ - - /* - * Allocate a buffer large enough for the worst case that all the source - * characters need to be escaped, plus quotes. - */ - dstbuf = pg_malloc(strlen(src) * 2 + 2 + 1); - - dst = dstbuf; - if (need_quotes) - *(dst++) = '\''; - for (; *src; src++) - { - if (*src == '\'' || *src == '\\') - *(dst++) = '\\'; - *(dst++) = *src; - } - if (need_quotes) - *(dst++) = '\''; - *dst = '\0'; - - return dstbuf; } /* @@ -1523,9 +1619,8 @@ GenerateRecoveryConf(PGconn *conn) * Write "keyword=value" pieces, the value string is escaped and/or * quoted if necessary. */ - escaped = escapeConnectionParameter(option->val); - appendPQExpBuffer(&conninfo_buf, "%s=%s", option->keyword, escaped); - free(escaped); + appendPQExpBuffer(&conninfo_buf, "%s=", option->keyword); + appendConnStrVal(&conninfo_buf, option->val); } /* @@ -1603,15 +1698,10 @@ BaseBackup(void) char xlogend[64]; int minServerMajor, maxServerMajor; - int serverMajor; + int serverVersion, + serverMajor; - /* - * Connect in replication mode to the server - */ - conn = GetConnection(); - if (!conn) - /* Error message already written in GetConnection() */ - exit(1); + Assert(conn != NULL); /* * Check server version. BASE_BACKUP command was introduced in 9.1, so we @@ -1619,7 +1709,8 @@ BaseBackup(void) */ minServerMajor = 901; maxServerMajor = PG_VERSION_NUM / 100; - serverMajor = PQserverVersion(conn) / 100; + serverVersion = PQserverVersion(conn); + serverMajor = serverVersion / 100; if (serverMajor < minServerMajor || serverMajor > maxServerMajor) { const char *serverver = PQparameterStatus(conn, "server_version"); @@ -1633,9 +1724,13 @@ BaseBackup(void) * If WAL streaming was requested, also check that the server is new * enough for that. */ - if (streamwal && !CheckServerVersionForStreaming(conn)) + if (includewal == STREAM_WAL && !CheckServerVersionForStreaming(conn)) { - /* Error message already written in CheckServerVersionForStreaming() */ + /* + * Error message already written in CheckServerVersionForStreaming(), + * but add a hint about using -X none. + */ + fprintf(stderr, _("HINT: use -X none or -X fetch to disable log streaming\n")); disconnect_and_exit(1); } @@ -1663,9 +1758,9 @@ BaseBackup(void) psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s", escaped_label, showprogress ? "PROGRESS" : "", - includewal && !streamwal ? "WAL" : "", + includewal == FETCH_WAL ? "WAL" : "", fastcheckpoint ? "FAST" : "", - includewal ? "NOWAIT" : "", + includewal == NO_WAL ? "" : "NOWAIT", maxrate_clause ? maxrate_clause : "", format == 't' ? "TABLESPACE_MAP" : ""); @@ -1708,7 +1803,7 @@ BaseBackup(void) PQclear(res); MemSet(xlogend, 0, sizeof(xlogend)); - if (verbose && includewal) + if (verbose && includewal != NO_WAL) fprintf(stderr, _("transaction log start point: %s on timeline %u\n"), xlogstart, starttli); @@ -1746,7 +1841,7 @@ BaseBackup(void) { char *path = (char *) get_tablespace_mapping(PQgetvalue(res, i, 1)); - verify_dir_is_empty_or_create(path); + verify_dir_is_empty_or_create(path, &made_tablespace_dirs, &found_tablespace_dirs); } } @@ -1765,7 +1860,7 @@ BaseBackup(void) * If we're streaming WAL, start the streaming session before we start * receiving the actual data chunks. */ - if (streamwal) + if (includewal == STREAM_WAL) { if (verbose) fprintf(stderr, _("%s: starting background WAL receiver\n"), @@ -1811,7 +1906,7 @@ BaseBackup(void) disconnect_and_exit(1); } strlcpy(xlogend, PQgetvalue(res, 0, 0), sizeof(xlogend)); - if (verbose && includewal) + if (verbose && includewal != NO_WAL) fprintf(stderr, "transaction log end point: %s\n", xlogend); PQclear(res); @@ -1932,6 +2027,26 @@ BaseBackup(void) PQclear(res); PQfinish(conn); + /* + * Make data persistent on disk once backup is completed. For tar + * format once syncing the parent directory is fine, each tar file + * created per tablespace has been already synced. In plain format, + * all the data of the base directory is synced, taking into account + * all the tablespaces. Errors are not considered fatal. + */ + if (do_sync) + { + if (format == 't') + { + if (strcmp(basedir, "-") != 0) + (void) fsync_fname(basedir, true, progname); + } + else + { + (void) fsync_pgdata(basedir, progname, serverVersion); + } + } + if (verbose) fprintf(stderr, "%s: base backup completed\n", progname); } @@ -1950,11 +2065,12 @@ main(int argc, char **argv) {"write-recovery-conf", no_argument, NULL, 'R'}, {"slot", required_argument, NULL, 'S'}, {"tablespace-mapping", required_argument, NULL, 'T'}, - {"xlog", no_argument, NULL, 'x'}, {"xlog-method", required_argument, NULL, 'X'}, {"gzip", no_argument, NULL, 'z'}, {"compress", required_argument, NULL, 'Z'}, {"label", required_argument, NULL, 'l'}, + {"no-clean", no_argument, NULL, 'n'}, + {"no-sync", no_argument, NULL, 'N'}, {"dbname", required_argument, NULL, 'd'}, {"host", required_argument, NULL, 'h'}, {"port", required_argument, NULL, 'p'}, @@ -1965,11 +2081,13 @@ main(int argc, char **argv) {"verbose", no_argument, NULL, 'v'}, {"progress", no_argument, NULL, 'P'}, {"xlogdir", required_argument, NULL, 1}, + {"no-slot", no_argument, NULL, 2}, {NULL, 0, NULL, 0} }; int c; int option_index; + bool no_slot = false; progname = get_progname(argv[0]); set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_basebackup")); @@ -1989,7 +2107,9 @@ main(int argc, char **argv) } } - while ((c = getopt_long(argc, argv, "D:F:r:RT:xX:l:zZ:d:c:h:p:U:s:S:wWvP", + atexit(cleanup_directories_atexit); + + while ((c = getopt_long(argc, argv, "D:F:r:RT:X:l:nNzZ:d:c:h:p:U:s:S:wWvP", long_options, &option_index)) != -1) { switch (c) @@ -2017,43 +2137,40 @@ main(int argc, char **argv) writerecoveryconf = true; break; case 'S': + + /* + * When specifying replication slot name, use a permanent + * slot. + */ replication_slot = pg_strdup(optarg); + temp_replication_slot = false; + break; + case 2: + no_slot = true; break; case 'T': tablespace_list_append(optarg); break; - case 'x': - if (includewal) - { - fprintf(stderr, - _("%s: cannot specify both --xlog and --xlog-method\n"), - progname); - exit(1); - } - - includewal = true; - streamwal = false; - break; case 'X': - if (includewal) + if (strcmp(optarg, "n") == 0 || + strcmp(optarg, "none") == 0) { - fprintf(stderr, - _("%s: cannot specify both --xlog and --xlog-method\n"), - progname); - exit(1); + includewal = NO_WAL; } - - includewal = true; - if (strcmp(optarg, "f") == 0 || + else if (strcmp(optarg, "f") == 0 || strcmp(optarg, "fetch") == 0) - streamwal = false; + { + includewal = FETCH_WAL; + } else if (strcmp(optarg, "s") == 0 || strcmp(optarg, "stream") == 0) - streamwal = true; + { + includewal = STREAM_WAL; + } else { fprintf(stderr, - _("%s: invalid xlog-method option \"%s\", must be \"fetch\" or \"stream\"\n"), + _("%s: invalid xlog-method option \"%s\", must be \"fetch\", \"stream\" or \"none\"\n"), progname, optarg); exit(1); } @@ -2064,6 +2181,12 @@ main(int argc, char **argv) case 'l': label = pg_strdup(optarg); break; + case 'n': + noclean = true; + break; + case 'N': + do_sync = false; + break; case 'z': #ifdef HAVE_LIBZ compresslevel = Z_DEFAULT_COMPRESSION; @@ -2173,17 +2296,17 @@ main(int argc, char **argv) exit(1); } - if (format != 'p' && streamwal) + if (format == 't' && includewal == STREAM_WAL && strcmp(basedir, "-") == 0) { fprintf(stderr, - _("%s: WAL streaming can only be used in plain mode\n"), + _("%s: cannot stream transaction logs in tar mode to stdout\n"), progname); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } - if (replication_slot && !streamwal) + if (replication_slot && includewal != STREAM_WAL) { fprintf(stderr, _("%s: replication slots can only be used with WAL streaming\n"), @@ -2193,6 +2316,20 @@ main(int argc, char **argv) exit(1); } + if (no_slot) + { + if (replication_slot) + { + fprintf(stderr, + _("%s: --no-slot cannot be used with slot name\n"), + progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); + exit(1); + } + temp_replication_slot = false; + } + if (strcmp(xlog_dir, "") != 0) { if (format != 'p') @@ -2233,33 +2370,47 @@ main(int argc, char **argv) * unless we are writing to stdout. */ if (format == 'p' || strcmp(basedir, "-") != 0) - verify_dir_is_empty_or_create(basedir); + verify_dir_is_empty_or_create(basedir, &made_new_pgdata, &found_existing_pgdata); + + /* connection in replication mode to server */ + conn = GetConnection(); + if (!conn) + { + /* Error message already written in GetConnection() */ + exit(1); + } /* Create transaction log symlink, if required */ if (strcmp(xlog_dir, "") != 0) { char *linkloc; - verify_dir_is_empty_or_create(xlog_dir); + verify_dir_is_empty_or_create(xlog_dir, &made_new_xlogdir, &found_existing_xlogdir); - /* form name of the place where the symlink must go */ - linkloc = psprintf("%s/pg_xlog", basedir); + /* + * Form name of the place where the symlink must go. pg_xlog has + * been renamed to pg_wal in post-10 clusters. + */ + linkloc = psprintf("%s/%s", basedir, + PQserverVersion(conn) < MINIMUM_VERSION_FOR_PG_WAL ? + "pg_xlog" : "pg_wal"); #ifdef HAVE_SYMLINK if (symlink(xlog_dir, linkloc) != 0) { fprintf(stderr, _("%s: could not create symbolic link \"%s\": %s\n"), progname, linkloc, strerror(errno)); - exit(1); + disconnect_and_exit(1); } #else fprintf(stderr, _("%s: symlinks are not supported on this platform\n")); - exit(1); + disconnect_and_exit(1); #endif free(linkloc); } BaseBackup(); + success = true; return 0; } diff --git a/src/bin/pg_basebackup/pg_receivexlog.c b/src/bin/pg_basebackup/pg_receivexlog.c index 7f7ee9dc9b..135e2070f3 100644 --- a/src/bin/pg_basebackup/pg_receivexlog.c +++ b/src/bin/pg_basebackup/pg_receivexlog.c @@ -5,7 +5,7 @@ * * Author: Magnus Hagander * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/pg_basebackup/pg_receivexlog.c @@ -34,6 +34,7 @@ /* Global options */ static char *basedir = NULL; static int verbose = 0; +static int compresslevel = 0; static int noloop = 0; static int standby_message_timeout = 10 * 1000; /* 10 sec = default */ static volatile bool time_to_abort = false; @@ -41,6 +42,7 @@ static bool do_create_slot = false; static bool slot_exists_ok = false; static bool do_drop_slot = false; static bool synchronous = false; +static char *replication_slot = NULL; static void usage(void); @@ -57,6 +59,15 @@ static bool stop_streaming(XLogRecPtr segendpos, uint32 timeline, exit(code); \ } +/* Routines to evaluate segment file format */ +#define IsCompressXLogFileName(fname) \ + (strlen(fname) == XLOG_FNAME_LEN + strlen(".gz") && \ + strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN && \ + strcmp((fname) + XLOG_FNAME_LEN, ".gz") == 0) +#define IsPartialCompressXLogFileName(fname) \ + (strlen(fname) == XLOG_FNAME_LEN + strlen(".gz.partial") && \ + strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN && \ + strcmp((fname) + XLOG_FNAME_LEN, ".gz.partial") == 0) static void usage(void) @@ -75,6 +86,7 @@ usage(void) printf(_(" --synchronous flush transaction log immediately after writing\n")); printf(_(" -v, --verbose output verbose messages\n")); printf(_(" -V, --version output version information, then exit\n")); + printf(_(" -Z, --compress=0-9 compress logs with given compression level\n")); printf(_(" -?, --help show this help, then exit\n")); printf(_("\nConnection options:\n")); printf(_(" -d, --dbname=CONNSTR connection string\n")); @@ -187,14 +199,31 @@ FindStreamingStart(uint32 *tli) uint32 tli; XLogSegNo segno; bool ispartial; + bool iscompress; /* * Check if the filename looks like an xlog file, or a .partial file. */ if (IsXLogFileName(dirent->d_name)) + { ispartial = false; + iscompress = false; + } else if (IsPartialXLogFileName(dirent->d_name)) + { ispartial = true; + iscompress = false; + } + else if (IsCompressXLogFileName(dirent->d_name)) + { + ispartial = false; + iscompress = true; + } + else if (IsPartialCompressXLogFileName(dirent->d_name)) + { + ispartial = true; + iscompress = true; + } else continue; @@ -205,9 +234,15 @@ FindStreamingStart(uint32 *tli) /* * Check that the segment has the right size, if it's supposed to be - * completed. + * completed. For non-compressed segments just check the on-disk size + * and see if it matches a completed segment. + * For compressed segments, look at the last 4 bytes of the compressed + * file, which is where the uncompressed size is located for gz files + * with a size lower than 4GB, and then compare it to the size of a + * completed segment. The 4 last bytes correspond to the ISIZE member + * according to http://www.zlib.org/rfc-gzip.html. */ - if (!ispartial) + if (!ispartial && !iscompress) { struct stat statbuf; char fullpath[MAXPGPATH]; @@ -228,6 +263,47 @@ FindStreamingStart(uint32 *tli) continue; } } + else if (!ispartial && iscompress) + { + int fd; + char buf[4]; + int bytes_out; + char fullpath[MAXPGPATH]; + + snprintf(fullpath, sizeof(fullpath), "%s/%s", basedir, dirent->d_name); + + fd = open(fullpath, O_RDONLY | PG_BINARY); + if (fd < 0) + { + fprintf(stderr, _("%s: could not open compressed file \"%s\": %s\n"), + progname, fullpath, strerror(errno)); + disconnect_and_exit(1); + } + if (lseek(fd, (off_t)(-4), SEEK_END) < 0) + { + fprintf(stderr, _("%s: could not seek compressed file \"%s\": %s\n"), + progname, fullpath, strerror(errno)); + disconnect_and_exit(1); + } + if (read(fd, (char *) buf, sizeof(buf)) != sizeof(buf)) + { + fprintf(stderr, _("%s: could not read compressed file \"%s\": %s\n"), + progname, fullpath, strerror(errno)); + disconnect_and_exit(1); + } + + close(fd); + bytes_out = (buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; + + if (bytes_out != XLOG_SEG_SIZE) + { + fprintf(stderr, + _("%s: compressed segment file \"%s\" has incorrect uncompressed size %d, skipping\n"), + progname, dirent->d_name, bytes_out); + continue; + } + } /* Looks like a valid segment. Remember that we saw it. */ if ((segno > high_segno) || @@ -336,13 +412,29 @@ StreamLog(void) stream.stream_stop = stop_streaming; stream.standby_message_timeout = standby_message_timeout; stream.synchronous = synchronous; + stream.do_sync = true; stream.mark_done = false; - stream.basedir = basedir; + stream.walmethod = CreateWalDirectoryMethod(basedir, compresslevel, + stream.do_sync); stream.partial_suffix = ".partial"; + stream.replication_slot = replication_slot; + stream.temp_slot = false; ReceiveXlogStream(conn, &stream); + if (!stream.walmethod->finish()) + { + fprintf(stderr, + _("%s: could not finish writing WAL files: %s\n"), + progname, strerror(errno)); + return; + } + PQfinish(conn); + + FreeWalDirectoryMethod(); + pg_free(stream.walmethod); + conn = NULL; } @@ -376,6 +468,7 @@ main(int argc, char **argv) {"status-interval", required_argument, NULL, 's'}, {"slot", required_argument, NULL, 'S'}, {"verbose", no_argument, NULL, 'v'}, + {"compress", required_argument, NULL, 'Z'}, /* action */ {"create-slot", no_argument, NULL, 1}, {"drop-slot", no_argument, NULL, 2}, @@ -406,7 +499,7 @@ main(int argc, char **argv) } } - while ((c = getopt_long(argc, argv, "D:d:h:p:U:s:S:nwWv", + while ((c = getopt_long(argc, argv, "D:d:h:p:U:s:S:nwWvZ:", long_options, &option_index)) != -1) { switch (c) @@ -456,6 +549,15 @@ main(int argc, char **argv) case 'v': verbose++; break; + case 'Z': + compresslevel = atoi(optarg); + if (compresslevel < 0 || compresslevel > 9) + { + fprintf(stderr, _("%s: invalid compression level \"%s\"\n"), + progname, optarg); + exit(1); + } + break; /* action */ case 1: do_create_slot = true; @@ -522,6 +624,16 @@ main(int argc, char **argv) exit(1); } +#ifndef HAVE_LIBZ + if (compresslevel != 0) + { + fprintf(stderr, + _("%s: this build does not support compression\n"), + progname); + exit(1); + } +#endif + /* * Check existence of destination folder. */ diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c index 4c6cf7054e..d16d08b664 100644 --- a/src/bin/pg_basebackup/pg_recvlogical.c +++ b/src/bin/pg_basebackup/pg_recvlogical.c @@ -3,7 +3,7 @@ * pg_recvlogical.c - receive data from a logical decoding slot in a streaming * fashion and write it to a local file. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/pg_basebackup/pg_recvlogical.c @@ -15,6 +15,9 @@ #include #include #include +#ifdef HAVE_SYS_SELECT_H +#include +#endif /* local includes */ #include "streamutil.h" @@ -37,10 +40,12 @@ static int noloop = 0; static int standby_message_timeout = 10 * 1000; /* 10 sec = default */ static int fsync_interval = 10 * 1000; /* 10 sec = default */ static XLogRecPtr startpos = InvalidXLogRecPtr; +static XLogRecPtr endpos = InvalidXLogRecPtr; static bool do_create_slot = false; static bool slot_exists_ok = false; static bool do_start_slot = false; static bool do_drop_slot = false; +static char *replication_slot = NULL; /* filled pairwise with option, value. value may be NULL */ static char **options; @@ -60,6 +65,9 @@ static XLogRecPtr output_fsync_lsn = InvalidXLogRecPtr; static void usage(void); static void StreamLogicalLog(void); static void disconnect_and_exit(int code); +static bool flushAndSendFeedback(PGconn *conn, TimestampTz *now); +static void prepareToTerminate(PGconn *conn, XLogRecPtr endpos, + bool keepalive, XLogRecPtr lsn); static void usage(void) @@ -78,6 +86,7 @@ usage(void) " time between fsyncs to the output file (default: %d)\n"), (fsync_interval / 1000)); printf(_(" --if-not-exists do not error if slot already exists when creating a slot\n")); printf(_(" -I, --startpos=LSN where in an existing slot should the streaming start\n")); + printf(_(" -E, --endpos=LSN exit after receiving the specified LSN\n")); printf(_(" -n, --no-loop do not loop on connection lost\n")); printf(_(" -o, --option=NAME[=VALUE]\n" " pass option NAME with optional value VALUE to the\n" @@ -278,6 +287,7 @@ StreamLogicalLog(void) int bytes_written; int64 now; int hdr_len; + XLogRecPtr cur_record_lsn = InvalidXLogRecPtr; if (copybuf != NULL) { @@ -451,6 +461,7 @@ StreamLogicalLog(void) int pos; bool replyRequested; XLogRecPtr walEnd; + bool endposReached = false; /* * Parse the keepalive message, enclosed in the CopyData message. @@ -473,18 +484,32 @@ StreamLogicalLog(void) } replyRequested = copybuf[pos]; - /* If the server requested an immediate reply, send one. */ - if (replyRequested) + if (endpos != InvalidXLogRecPtr && walEnd >= endpos) { - /* fsync data, so we send a recent flush pointer */ - if (!OutputFsync(now)) - goto error; + /* + * If there's nothing to read on the socket until a keepalive + * we know that the server has nothing to send us; and if + * walEnd has passed endpos, we know nothing else can have + * committed before endpos. So we can bail out now. + */ + endposReached = true; + } - now = feGetCurrentTimestamp(); - if (!sendFeedback(conn, now, true, false)) + /* Send a reply, if necessary */ + if (replyRequested || endposReached) + { + if (!flushAndSendFeedback(conn, &now)) goto error; last_status = now; } + + if (endposReached) + { + prepareToTerminate(conn, endpos, true, InvalidXLogRecPtr); + time_to_abort = true; + break; + } + continue; } else if (copybuf[0] != 'w') @@ -494,7 +519,6 @@ StreamLogicalLog(void) goto error; } - /* * Read the header of the XLogData message, enclosed in the CopyData * message. We only need the WAL location field (dataStart), the rest @@ -512,12 +536,23 @@ StreamLogicalLog(void) } /* Extract WAL location for this block */ - { - XLogRecPtr temp = fe_recvint64(©buf[1]); + cur_record_lsn = fe_recvint64(©buf[1]); - output_written_lsn = Max(temp, output_written_lsn); + if (endpos != InvalidXLogRecPtr && cur_record_lsn > endpos) + { + /* + * We've read past our endpoint, so prepare to go away being + * cautious about what happens to our output data. + */ + if (!flushAndSendFeedback(conn, &now)) + goto error; + prepareToTerminate(conn, endpos, false, cur_record_lsn); + time_to_abort = true; + break; } + output_written_lsn = Max(cur_record_lsn, output_written_lsn); + bytes_left = r - hdr_len; bytes_written = 0; @@ -554,10 +589,29 @@ StreamLogicalLog(void) strerror(errno)); goto error; } + + if (endpos != InvalidXLogRecPtr && cur_record_lsn == endpos) + { + /* endpos was exactly the record we just processed, we're done */ + if (!flushAndSendFeedback(conn, &now)) + goto error; + prepareToTerminate(conn, endpos, false, cur_record_lsn); + time_to_abort = true; + break; + } } res = PQgetResult(conn); - if (PQresultStatus(res) != PGRES_COMMAND_OK) + if (PQresultStatus(res) == PGRES_COPY_OUT) + { + /* + * We're doing a client-initiated clean exit and have sent CopyDone to + * the server. We've already sent replay confirmation and fsync'd so + * we can just clean up the connection now. + */ + goto error; + } + else if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, _("%s: unexpected termination of replication stream: %s"), @@ -635,6 +689,7 @@ main(int argc, char **argv) {"password", no_argument, NULL, 'W'}, /* replication options */ {"startpos", required_argument, NULL, 'I'}, + {"endpos", required_argument, NULL, 'E'}, {"option", required_argument, NULL, 'o'}, {"plugin", required_argument, NULL, 'P'}, {"status-interval", required_argument, NULL, 's'}, @@ -670,7 +725,7 @@ main(int argc, char **argv) } } - while ((c = getopt_long(argc, argv, "f:F:nvd:h:p:U:wWI:o:P:s:S:", + while ((c = getopt_long(argc, argv, "f:F:nvd:h:p:U:wWI:E:o:P:s:S:", long_options, &option_index)) != -1) { switch (c) @@ -730,6 +785,16 @@ main(int argc, char **argv) } startpos = ((uint64) hi) << 32 | lo; break; + case 'E': + if (sscanf(optarg, "%X/%X", &hi, &lo) != 2) + { + fprintf(stderr, + _("%s: could not parse end position \"%s\"\n"), + progname, optarg); + exit(1); + } + endpos = ((uint64) hi) << 32 | lo; + break; case 'o': { char *data = pg_strdup(optarg); @@ -854,6 +919,16 @@ main(int argc, char **argv) exit(1); } + if (endpos != InvalidXLogRecPtr && !do_start_slot) + { + fprintf(stderr, + _("%s: --endpos may only be specified with --start\n"), + progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); + exit(1); + } + #ifndef WIN32 pqsignal(SIGINT, sigint_handler); pqsignal(SIGHUP, sighup_handler); @@ -920,8 +995,8 @@ main(int argc, char **argv) if (time_to_abort) { /* - * We've been Ctrl-C'ed. That's not an error, so exit without an - * errorcode. + * We've been Ctrl-C'ed or reached an exit limit condition. That's + * not an error, so exit without an errorcode. */ disconnect_and_exit(0); } @@ -940,3 +1015,47 @@ main(int argc, char **argv) } } } + +/* + * Fsync our output data, and send a feedback message to the server. Returns + * true if successful, false otherwise. + * + * If successful, *now is updated to the current timestamp just before sending + * feedback. + */ +static bool +flushAndSendFeedback(PGconn *conn, TimestampTz *now) +{ + /* flush data to disk, so that we send a recent flush pointer */ + if (!OutputFsync(*now)) + return false; + *now = feGetCurrentTimestamp(); + if (!sendFeedback(conn, *now, true, false)) + return false; + + return true; +} + +/* + * Try to inform the server about of upcoming demise, but don't wait around or + * retry on failure. + */ +static void +prepareToTerminate(PGconn *conn, XLogRecPtr endpos, bool keepalive, XLogRecPtr lsn) +{ + (void) PQputCopyEnd(conn, NULL); + (void) PQflush(conn); + + if (verbose) + { + if (keepalive) + fprintf(stderr, "%s: endpos %X/%X reached by keepalive\n", + progname, + (uint32) (endpos >> 32), (uint32) endpos); + else + fprintf(stderr, "%s: endpos %X/%X reached by record at %X/%X\n", + progname, (uint32) (endpos >> 32), (uint32) (endpos), + (uint32) (lsn >> 32), (uint32) lsn); + + } +} diff --git a/src/bin/pg_basebackup/receivelog.c b/src/bin/pg_basebackup/receivelog.c index 595213f042..55612832a6 100644 --- a/src/bin/pg_basebackup/receivelog.c +++ b/src/bin/pg_basebackup/receivelog.c @@ -5,7 +5,7 @@ * * Author: Magnus Hagander * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/pg_basebackup/receivelog.c @@ -16,6 +16,9 @@ #include #include +#ifdef HAVE_SYS_SELECT_H +#include +#endif /* local includes */ #include "receivelog.h" @@ -23,10 +26,11 @@ #include "libpq-fe.h" #include "access/xlog_internal.h" +#include "common/file_utils.h" /* fd and filename for currently open WAL file */ -static int walfile = -1; +static Walfile *walfile = NULL; static char current_walfile_name[MAXPGPATH] = ""; static bool reportFlushPosition = false; static XLogRecPtr lastFlushPosition = InvalidXLogRecPtr; @@ -37,8 +41,8 @@ static PGresult *HandleCopyStream(PGconn *conn, StreamCtl *stream, XLogRecPtr *stoppos); static int CopyStreamPoll(PGconn *conn, long timeout_ms); static int CopyStreamReceive(PGconn *conn, long timeout, char **buffer); -static bool ProcessKeepaliveMsg(PGconn *conn, char *copybuf, int len, - XLogRecPtr blockpos, int64 *last_status); +static bool ProcessKeepaliveMsg(PGconn *conn, StreamCtl *stream, char *copybuf, + int len, XLogRecPtr blockpos, int64 *last_status); static bool ProcessXLogDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len, XLogRecPtr *blockpos); static PGresult *HandleEndOfCopyStream(PGconn *conn, StreamCtl *stream, char *copybuf, @@ -52,33 +56,23 @@ static bool ReadEndOfStreamingResult(PGresult *res, XLogRecPtr *startpos, uint32 *timeline); static bool -mark_file_as_archived(const char *basedir, const char *fname) +mark_file_as_archived(StreamCtl *stream, const char *fname) { - int fd; + Walfile *f; static char tmppath[MAXPGPATH]; - snprintf(tmppath, sizeof(tmppath), "%s/archive_status/%s.done", - basedir, fname); + snprintf(tmppath, sizeof(tmppath), "archive_status/%s.done", + fname); - fd = open(tmppath, O_WRONLY | O_CREAT | PG_BINARY, S_IRUSR | S_IWUSR); - if (fd < 0) + f = stream->walmethod->open_for_write(tmppath, NULL, 0); + if (f == NULL) { fprintf(stderr, _("%s: could not create archive status file \"%s\": %s\n"), - progname, tmppath, strerror(errno)); + progname, tmppath, stream->walmethod->getlasterror()); return false; } - if (fsync(fd) != 0) - { - fprintf(stderr, _("%s: could not fsync file \"%s\": %s\n"), - progname, tmppath, strerror(errno)); - - close(fd); - - return false; - } - - close(fd); + stream->walmethod->close(f, CLOSE_NORMAL); return true; } @@ -86,85 +80,91 @@ mark_file_as_archived(const char *basedir, const char *fname) /* * Open a new WAL file in the specified directory. * - * The file will be padded to 16Mb with zeroes. The base filename (without - * partial_suffix) is stored in current_walfile_name. + * Returns true if OK; on failure, returns false after printing an error msg. + * On success, 'walfile' is set to the FD for the file, and the base filename + * (without partial_suffix) is stored in 'current_walfile_name'. + * + * The file will be padded to 16Mb with zeroes. */ static bool open_walfile(StreamCtl *stream, XLogRecPtr startpoint) { - int f; + Walfile *f; char fn[MAXPGPATH]; - struct stat statbuf; - char *zerobuf; - int bytes; + ssize_t size; XLogSegNo segno; XLByteToSeg(startpoint, segno); XLogFileName(current_walfile_name, stream->timeline, segno); - snprintf(fn, sizeof(fn), "%s/%s%s", stream->basedir, current_walfile_name, + snprintf(fn, sizeof(fn), "%s%s", current_walfile_name, stream->partial_suffix ? stream->partial_suffix : ""); - f = open(fn, O_WRONLY | O_CREAT | PG_BINARY, S_IRUSR | S_IWUSR); - if (f == -1) - { - fprintf(stderr, - _("%s: could not open transaction log file \"%s\": %s\n"), - progname, fn, strerror(errno)); - return false; - } /* - * Verify that the file is either empty (just created), or a complete - * XLogSegSize segment. Anything in between indicates a corrupt file. + * When streaming to files, if an existing file exists we verify that it's + * either empty (just created), or a complete XLogSegSize segment (in + * which case it has been created and padded). Anything else indicates a + * corrupt file. + * + * When streaming to tar, no file with this name will exist before, so we + * never have to verify a size. */ - if (fstat(f, &statbuf) != 0) + if (stream->walmethod->existsfile(fn)) { - fprintf(stderr, - _("%s: could not stat transaction log file \"%s\": %s\n"), - progname, fn, strerror(errno)); - close(f); - return false; - } - if (statbuf.st_size == XLogSegSize) - { - /* File is open and ready to use */ - walfile = f; - return true; - } - if (statbuf.st_size != 0) - { - fprintf(stderr, - _("%s: transaction log file \"%s\" has %d bytes, should be 0 or %d\n"), - progname, fn, (int) statbuf.st_size, XLogSegSize); - close(f); - return false; - } + size = stream->walmethod->get_file_size(fn); + if (size < 0) + { + fprintf(stderr, + _("%s: could not get size of transaction log file \"%s\": %s\n"), + progname, fn, stream->walmethod->getlasterror()); + return false; + } + if (size == XLogSegSize) + { + /* Already padded file. Open it for use */ + f = stream->walmethod->open_for_write(current_walfile_name, stream->partial_suffix, 0); + if (f == NULL) + { + fprintf(stderr, + _("%s: could not open existing transaction log file \"%s\": %s\n"), + progname, fn, stream->walmethod->getlasterror()); + return false; + } - /* New, empty, file. So pad it to 16Mb with zeroes */ - zerobuf = pg_malloc0(XLOG_BLCKSZ); - for (bytes = 0; bytes < XLogSegSize; bytes += XLOG_BLCKSZ) - { - if (write(f, zerobuf, XLOG_BLCKSZ) != XLOG_BLCKSZ) + /* fsync file in case of a previous crash */ + if (!stream->walmethod->sync(f)) + { + stream->walmethod->close(f, CLOSE_UNLINK); + return false; + } + + walfile = f; + return true; + } + if (size != 0) { + /* if write didn't set errno, assume problem is no disk space */ + if (errno == 0) + errno = ENOSPC; fprintf(stderr, - _("%s: could not pad transaction log file \"%s\": %s\n"), - progname, fn, strerror(errno)); - free(zerobuf); - close(f); - unlink(fn); + _("%s: transaction log file \"%s\" has %d bytes, should be 0 or %d\n"), + progname, fn, (int) size, XLogSegSize); return false; } + /* File existed and was empty, so fall through and open */ } - free(zerobuf); - if (lseek(f, SEEK_SET, 0) != 0) + /* No file existed, so create one */ + + f = stream->walmethod->open_for_write(current_walfile_name, stream->partial_suffix, XLogSegSize); + if (f == NULL) { fprintf(stderr, - _("%s: could not seek to beginning of transaction log file \"%s\": %s\n"), - progname, fn, strerror(errno)); - close(f); + _("%s: could not open transaction log file \"%s\": %s\n"), + progname, fn, stream->walmethod->getlasterror()); return false; } + walfile = f; return true; } @@ -178,56 +178,46 @@ static bool close_walfile(StreamCtl *stream, XLogRecPtr pos) { off_t currpos; + int r; - if (walfile == -1) + if (walfile == NULL) return true; - currpos = lseek(walfile, 0, SEEK_CUR); + currpos = stream->walmethod->get_current_pos(walfile); if (currpos == -1) { fprintf(stderr, _("%s: could not determine seek position in file \"%s\": %s\n"), - progname, current_walfile_name, strerror(errno)); + progname, current_walfile_name, stream->walmethod->getlasterror()); + stream->walmethod->close(walfile, CLOSE_UNLINK); + walfile = NULL; + return false; } - if (fsync(walfile) != 0) + if (stream->partial_suffix) { - fprintf(stderr, _("%s: could not fsync file \"%s\": %s\n"), - progname, current_walfile_name, strerror(errno)); - return false; + if (currpos == XLOG_SEG_SIZE) + r = stream->walmethod->close(walfile, CLOSE_NORMAL); + else + { + fprintf(stderr, + _("%s: not renaming \"%s%s\", segment is not complete\n"), + progname, current_walfile_name, stream->partial_suffix); + r = stream->walmethod->close(walfile, CLOSE_NO_RENAME); + } } + else + r = stream->walmethod->close(walfile, CLOSE_NORMAL); - if (close(walfile) != 0) + walfile = NULL; + + if (r != 0) { fprintf(stderr, _("%s: could not close file \"%s\": %s\n"), - progname, current_walfile_name, strerror(errno)); - walfile = -1; + progname, current_walfile_name, stream->walmethod->getlasterror()); return false; } - walfile = -1; - - /* - * If we finished writing a .partial file, rename it into place. - */ - if (currpos == XLOG_SEG_SIZE && stream->partial_suffix) - { - char oldfn[MAXPGPATH]; - char newfn[MAXPGPATH]; - - snprintf(oldfn, sizeof(oldfn), "%s/%s%s", stream->basedir, current_walfile_name, stream->partial_suffix); - snprintf(newfn, sizeof(newfn), "%s/%s", stream->basedir, current_walfile_name); - if (rename(oldfn, newfn) != 0) - { - fprintf(stderr, _("%s: could not rename file \"%s\": %s\n"), - progname, current_walfile_name, strerror(errno)); - return false; - } - } - else if (stream->partial_suffix) - fprintf(stderr, - _("%s: not renaming \"%s%s\", segment is not complete\n"), - progname, current_walfile_name, stream->partial_suffix); /* * Mark file as archived if requested by the caller - pg_basebackup needs @@ -238,7 +228,7 @@ close_walfile(StreamCtl *stream, XLogRecPtr pos) if (currpos == XLOG_SEG_SIZE && stream->mark_done) { /* writes error message if failed */ - if (!mark_file_as_archived(stream->basedir, current_walfile_name)) + if (!mark_file_as_archived(stream, current_walfile_name)) return false; } @@ -253,9 +243,7 @@ close_walfile(StreamCtl *stream, XLogRecPtr pos) static bool existsTimeLineHistoryFile(StreamCtl *stream) { - char path[MAXPGPATH]; char histfname[MAXFNAMELEN]; - int fd; /* * Timeline 1 never has a history file. We treat that as if it existed, @@ -266,31 +254,15 @@ existsTimeLineHistoryFile(StreamCtl *stream) TLHistoryFileName(histfname, stream->timeline); - snprintf(path, sizeof(path), "%s/%s", stream->basedir, histfname); - - fd = open(path, O_RDONLY | PG_BINARY, 0); - if (fd < 0) - { - if (errno != ENOENT) - fprintf(stderr, _("%s: could not open timeline history file \"%s\": %s\n"), - progname, path, strerror(errno)); - return false; - } - else - { - close(fd); - return true; - } + return stream->walmethod->existsfile(histfname); } static bool writeTimeLineHistoryFile(StreamCtl *stream, char *filename, char *content) { int size = strlen(content); - char path[MAXPGPATH]; - char tmppath[MAXPGPATH]; char histfname[MAXFNAMELEN]; - int fd; + Walfile *f; /* * Check that the server's idea of how timeline history files should be @@ -304,62 +276,31 @@ writeTimeLineHistoryFile(StreamCtl *stream, char *filename, char *content) return false; } - snprintf(path, sizeof(path), "%s/%s", stream->basedir, histfname); - - /* - * Write into a temp file name. - */ - snprintf(tmppath, MAXPGPATH, "%s.tmp", path); - - unlink(tmppath); - - fd = open(tmppath, O_WRONLY | O_CREAT | PG_BINARY, S_IRUSR | S_IWUSR); - if (fd < 0) + f = stream->walmethod->open_for_write(histfname, ".tmp", 0); + if (f == NULL) { fprintf(stderr, _("%s: could not create timeline history file \"%s\": %s\n"), - progname, tmppath, strerror(errno)); + progname, histfname, stream->walmethod->getlasterror()); return false; } - errno = 0; - if ((int) write(fd, content, size) != size) + if ((int) stream->walmethod->write(f, content, size) != size) { - int save_errno = errno; + fprintf(stderr, _("%s: could not write timeline history file \"%s\": %s\n"), + progname, histfname, stream->walmethod->getlasterror()); /* * If we fail to make the file, delete it to release disk space */ - close(fd); - unlink(tmppath); - errno = save_errno; + stream->walmethod->close(f, CLOSE_UNLINK); - fprintf(stderr, _("%s: could not write timeline history file \"%s\": %s\n"), - progname, tmppath, strerror(errno)); return false; } - if (fsync(fd) != 0) - { - close(fd); - fprintf(stderr, _("%s: could not fsync file \"%s\": %s\n"), - progname, tmppath, strerror(errno)); - return false; - } - - if (close(fd) != 0) + if (stream->walmethod->close(f, CLOSE_NORMAL) != 0) { fprintf(stderr, _("%s: could not close file \"%s\": %s\n"), - progname, tmppath, strerror(errno)); - return false; - } - - /* - * Now move the completed history file into place with its final name. - */ - if (rename(tmppath, path) < 0) - { - fprintf(stderr, _("%s: could not rename file \"%s\" to \"%s\": %s\n"), - progname, tmppath, path, strerror(errno)); + progname, histfname, stream->walmethod->getlasterror()); return false; } @@ -367,7 +308,7 @@ writeTimeLineHistoryFile(StreamCtl *stream, char *filename, char *content) if (stream->mark_done) { /* writes error message if failed */ - if (!mark_file_as_archived(stream->basedir, histfname)) + if (!mark_file_as_archived(stream, histfname)) return false; } @@ -503,26 +444,28 @@ ReceiveXlogStream(PGconn *conn, StreamCtl *stream) if (!CheckServerVersionForStreaming(conn)) return false; - if (replication_slot != NULL) + /* + * Decide whether we want to report the flush position. If we report + * the flush position, the primary will know what WAL we'll + * possibly re-request, and it can then remove older WAL safely. + * We must always do that when we are using slots. + * + * Reporting the flush position makes one eligible as a synchronous + * replica. People shouldn't include generic names in + * synchronous_standby_names, but we've protected them against it so + * far, so let's continue to do so unless specifically requested. + */ + if (stream->replication_slot != NULL) { - /* - * Report the flush position, so the primary can know what WAL we'll - * possibly re-request, and remove older WAL safely. - * - * We only report it when a slot has explicitly been used, because - * reporting the flush position makes one eligible as a synchronous - * replica. People shouldn't include generic names in - * synchronous_standby_names, but we've protected them against it so - * far, so let's continue to do so in the situations when possible. If - * they've got a slot, though, we need to report the flush position, - * so that the master can remove WAL. - */ reportFlushPosition = true; - sprintf(slotcmd, "SLOT \"%s\" ", replication_slot); + sprintf(slotcmd, "SLOT \"%s\" ", stream->replication_slot); } else { - reportFlushPosition = false; + if (stream->synchronous) + reportFlushPosition = true; + else + reportFlushPosition = false; slotcmd[0] = 0; } @@ -565,6 +508,24 @@ ReceiveXlogStream(PGconn *conn, StreamCtl *stream) PQclear(res); } + /* + * Create temporary replication slot if one is needed + */ + if (stream->temp_slot) + { + snprintf(query, sizeof(query), + "CREATE_REPLICATION_SLOT \"%s\" TEMPORARY PHYSICAL RESERVE_WAL", + stream->replication_slot); + res = PQexec(conn, query); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + fprintf(stderr, _("%s: could not create temporary replication slot \"%s\": %s"), + progname, stream->replication_slot, PQerrorMessage(conn)); + PQclear(res); + return false; + } + } + /* * initialize flush position to starting point, it's the caller's * responsibility that that's sane. @@ -575,7 +536,9 @@ ReceiveXlogStream(PGconn *conn, StreamCtl *stream) { /* * Fetch the timeline history file for this timeline, if we don't have - * it already. + * it already. When streaming log to tar, this will always return + * false, as we are never streaming into an existing file and + * therefore there can be no pre-existing timeline history file. */ if (!existsTimeLineHistoryFile(stream)) { @@ -734,10 +697,10 @@ ReceiveXlogStream(PGconn *conn, StreamCtl *stream) } error: - if (walfile != -1 && close(walfile) != 0) + if (walfile != NULL && stream->walmethod->close(walfile, CLOSE_NO_RENAME) != 0) fprintf(stderr, _("%s: could not close file \"%s\": %s\n"), - progname, current_walfile_name, strerror(errno)); - walfile = -1; + progname, current_walfile_name, stream->walmethod->getlasterror()); + walfile = NULL; return false; } @@ -821,12 +784,12 @@ HandleCopyStream(PGconn *conn, StreamCtl *stream, * If synchronous option is true, issue sync command as soon as there * are WAL data which has not been flushed yet. */ - if (stream->synchronous && lastFlushPosition < blockpos && walfile != -1) + if (stream->synchronous && lastFlushPosition < blockpos && walfile != NULL) { - if (fsync(walfile) != 0) + if (stream->walmethod->sync(walfile) != 0) { fprintf(stderr, _("%s: could not fsync file \"%s\": %s\n"), - progname, current_walfile_name, strerror(errno)); + progname, current_walfile_name, stream->walmethod->getlasterror()); goto error; } lastFlushPosition = blockpos; @@ -877,7 +840,7 @@ HandleCopyStream(PGconn *conn, StreamCtl *stream, /* Check the message type. */ if (copybuf[0] == 'k') { - if (!ProcessKeepaliveMsg(conn, copybuf, r, blockpos, + if (!ProcessKeepaliveMsg(conn, stream, copybuf, r, blockpos, &last_status)) goto error; } @@ -1030,7 +993,7 @@ CopyStreamReceive(PGconn *conn, long timeout, char **buffer) * Process the keepalive message. */ static bool -ProcessKeepaliveMsg(PGconn *conn, char *copybuf, int len, +ProcessKeepaliveMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len, XLogRecPtr blockpos, int64 *last_status) { int pos; @@ -1057,7 +1020,7 @@ ProcessKeepaliveMsg(PGconn *conn, char *copybuf, int len, if (replyRequested && still_sending) { if (reportFlushPosition && lastFlushPosition < blockpos && - walfile != -1) + walfile != NULL) { /* * If a valid flush location needs to be reported, flush the @@ -1066,10 +1029,10 @@ ProcessKeepaliveMsg(PGconn *conn, char *copybuf, int len, * data has been successfully replicated or not, at the normal * shutdown of the server. */ - if (fsync(walfile) != 0) + if (stream->walmethod->sync(walfile) != 0) { fprintf(stderr, _("%s: could not fsync file \"%s\": %s\n"), - progname, current_walfile_name, strerror(errno)); + progname, current_walfile_name, stream->walmethod->getlasterror()); return false; } lastFlushPosition = blockpos; @@ -1127,7 +1090,7 @@ ProcessXLogDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len, * Verify that the initial location in the stream matches where we think * we are. */ - if (walfile == -1) + if (walfile == NULL) { /* No file open yet */ if (xlogoff != 0) @@ -1141,12 +1104,11 @@ ProcessXLogDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len, else { /* More data in existing segment */ - /* XXX: store seek value don't reseek all the time */ - if (lseek(walfile, 0, SEEK_CUR) != xlogoff) + if (stream->walmethod->get_current_pos(walfile) != xlogoff) { fprintf(stderr, _("%s: got WAL data offset %08x, expected %08x\n"), - progname, xlogoff, (int) lseek(walfile, 0, SEEK_CUR)); + progname, xlogoff, (int) stream->walmethod->get_current_pos(walfile)); return false; } } @@ -1167,7 +1129,7 @@ ProcessXLogDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len, else bytes_to_write = bytes_left; - if (walfile == -1) + if (walfile == NULL) { if (!open_walfile(stream, *blockpos)) { @@ -1176,14 +1138,13 @@ ProcessXLogDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len, } } - if (write(walfile, - copybuf + hdr_len + bytes_written, - bytes_to_write) != bytes_to_write) + if (stream->walmethod->write(walfile, copybuf + hdr_len + bytes_written, + bytes_to_write) != bytes_to_write) { fprintf(stderr, _("%s: could not write %u bytes to WAL file \"%s\": %s\n"), progname, bytes_to_write, current_walfile_name, - strerror(errno)); + stream->walmethod->getlasterror()); return false; } diff --git a/src/bin/pg_basebackup/receivelog.h b/src/bin/pg_basebackup/receivelog.h index 554ff8b5b2..42e93ac745 100644 --- a/src/bin/pg_basebackup/receivelog.h +++ b/src/bin/pg_basebackup/receivelog.h @@ -2,7 +2,7 @@ * * receivelog.h * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/pg_basebackup/receivelog.h @@ -13,6 +13,7 @@ #define RECEIVELOG_H #include "libpq-fe.h" +#include "walmethods.h" #include "access/xlogdefs.h" @@ -34,13 +35,17 @@ typedef struct StreamCtl * timeline */ int standby_message_timeout; /* Send status messages this * often */ - bool synchronous; /* Flush data on write */ + bool synchronous; /* Flush immediately WAL data on write */ bool mark_done; /* Mark segment as done in generated archive */ + bool do_sync; /* Flush to disk to ensure consistent state of + * data */ stream_stop_callback stream_stop; /* Stop streaming when returns true */ - char *basedir; /* Received segments written to this dir */ + WalWriteMethod *walmethod; /* How to write the WAL */ char *partial_suffix; /* Suffix appended to partially received files */ + char *replication_slot; /* Replication slot to use, or NULL */ + bool temp_slot; /* Create temporary replication slot */ } StreamCtl; diff --git a/src/bin/pg_basebackup/streamutil.c b/src/bin/pg_basebackup/streamutil.c index 72d8657004..31290d35f6 100644 --- a/src/bin/pg_basebackup/streamutil.c +++ b/src/bin/pg_basebackup/streamutil.c @@ -4,7 +4,7 @@ * * Author: Magnus Hagander * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/pg_basebackup/streamutil.c @@ -38,10 +38,10 @@ char *connection_string = NULL; char *dbhost = NULL; char *dbuser = NULL; char *dbport = NULL; -char *replication_slot = NULL; char *dbname = NULL; int dbgetpassword = 0; /* 0=auto, -1=never, 1=always */ -static char *dbpassword = NULL; +static bool have_password = false; +static char password[100]; PGconn *conn = NULL; /* @@ -141,24 +141,23 @@ GetConnection(void) } /* If -W was given, force prompt for password, but only the first time */ - need_password = (dbgetpassword == 1 && dbpassword == NULL); + need_password = (dbgetpassword == 1 && !have_password); do { /* Get a new password if appropriate */ if (need_password) { - if (dbpassword) - free(dbpassword); - dbpassword = simple_prompt(_("Password: "), 100, false); + simple_prompt("Password: ", password, sizeof(password), false); + have_password = true; need_password = false; } /* Use (or reuse, on a subsequent connection) password if we have it */ - if (dbpassword) + if (have_password) { keywords[i] = "password"; - values[i] = dbpassword; + values[i] = password; } else { diff --git a/src/bin/pg_basebackup/streamutil.h b/src/bin/pg_basebackup/streamutil.h index d2d5a6dbae..663bfac5cc 100644 --- a/src/bin/pg_basebackup/streamutil.h +++ b/src/bin/pg_basebackup/streamutil.h @@ -2,7 +2,7 @@ * * streamutil.h * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/pg_basebackup/streamutil.h @@ -23,7 +23,6 @@ extern char *dbuser; extern char *dbport; extern char *dbname; extern int dbgetpassword; -extern char *replication_slot; /* Connection kept global so we can disconnect easily */ extern PGconn *conn; diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl b/src/bin/pg_basebackup/t/010_pg_basebackup.pl index 6c33936d25..2c5a3658d5 100644 --- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl +++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl @@ -4,7 +4,7 @@ use Config; use PostgresNode; use TestLib; -use Test::More tests => 51; +use Test::More tests => 72; program_help_ok('pg_basebackup'); program_version_ok('pg_basebackup'); @@ -40,6 +40,14 @@ [ 'pg_basebackup', '-D', "$tempdir/backup" ], 'pg_basebackup fails because of WAL configuration'); +ok(! -d "$tempdir/backup", 'backup directory was cleaned up'); + +$node->command_fails( + [ 'pg_basebackup', '-D', "$tempdir/backup", '-n' ], + 'failing run with no-clean option'); + +ok(-d "$tempdir/backup", 'backup directory was created and left behind'); + open CONF, ">>$pgdata/postgresql.conf"; print CONF "max_replication_slots = 10\n"; print CONF "max_wal_senders = 10\n"; @@ -47,15 +55,43 @@ close CONF; $node->restart; -$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backup" ], +# Write some files to test that they are not copied. +foreach my $filename (qw(backup_label tablespace_map postgresql.auto.conf.tmp)) +{ + open FILE, ">>$pgdata/$filename"; + print FILE "DONOTCOPY"; + close FILE; +} + +$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backup", '-X', 'none' ], 'pg_basebackup runs'); ok(-f "$tempdir/backup/PG_VERSION", 'backup was created'); +# Only archive_status directory should be copied in pg_wal/. is_deeply( - [ sort(slurp_dir("$tempdir/backup/pg_xlog/")) ], + [ sort(slurp_dir("$tempdir/backup/pg_wal/")) ], [ sort qw(. .. archive_status) ], 'no WAL files copied'); +# Contents of these directories should not be copied. +foreach my $dirname (qw(pg_dynshmem pg_notify pg_replslot pg_serial pg_snapshots pg_stat_tmp pg_subtrans)) +{ + is_deeply( + [ sort(slurp_dir("$tempdir/backup/$dirname/")) ], + [ sort qw(. ..) ], + "contents of $dirname/ not copied"); +} + +# These files should not be copied. +foreach my $filename (qw(postgresql.auto.conf.tmp postmaster.opts postmaster.pid tablespace_map)) +{ + ok(! -f "$tempdir/backup/$filename", "$filename not copied"); +} + +# Make sure existing backup_label was ignored. +isnt(slurp_file("$tempdir/backup/backup_label"), 'DONOTCOPY', + 'existing backup_label not copied'); + $node->command_ok( [ 'pg_basebackup', '-D', "$tempdir/backup2", '--xlogdir', "$tempdir/xlog2" ], @@ -102,7 +138,17 @@ # skip on Windows. SKIP: { - skip "symlinks not supported on Windows", 10 if ($windows_os); + skip "symlinks not supported on Windows", 11 if ($windows_os); + + # Move pg_replslot out of $pgdata and create a symlink to it. + $node->stop; + + rename("$pgdata/pg_replslot", "$tempdir/pg_replslot") + or BAIL_OUT "could not move $pgdata/pg_replslot"; + symlink("$tempdir/pg_replslot", "$pgdata/pg_replslot") + or BAIL_OUT "could not symlink to $pgdata/pg_replslot"; + + $node->start; # Create a temporary directory in the system location and symlink it # to our physical temp location. That way we can use shorter names @@ -140,6 +186,8 @@ "tablespace symlink was updated"); closedir $dh; + ok(-d "$tempdir/backup1/pg_replslot", 'pg_replslot symlink copied as directory'); + mkdir "$tempdir/tbl=spc2"; $node->safe_psql('postgres', "DROP TABLE test1;"); $node->safe_psql('postgres', "DROP TABLESPACE tblspc1;"); @@ -167,28 +215,38 @@ ok(-f "$tempdir/backupR/recovery.conf", 'recovery.conf was created'); my $recovery_conf = slurp_file "$tempdir/backupR/recovery.conf"; -# using a character class for the final "'" here works around an apparent -# bug in several version of the Msys DTK perl my $port = $node->port; like( $recovery_conf, - qr/^standby_mode = 'on[']$/m, + qr/^standby_mode = 'on'\n/m, 'recovery.conf sets standby_mode'); like( $recovery_conf, - qr/^primary_conninfo = '.*port=$port.*'$/m, + qr/^primary_conninfo = '.*port=$port.*'\n/m, 'recovery.conf sets primary_conninfo'); +$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backupxd" ], + 'pg_basebackup runs in default xlog mode'); +ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxd/pg_wal")), + 'WAL files copied'); + $node->command_ok( [ 'pg_basebackup', '-D', "$tempdir/backupxf", '-X', 'fetch' ], 'pg_basebackup -X fetch runs'); -ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxf/pg_xlog")), +ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxf/pg_wal")), 'WAL files copied'); $node->command_ok( [ 'pg_basebackup', '-D', "$tempdir/backupxs", '-X', 'stream' ], 'pg_basebackup -X stream runs'); -ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxf/pg_xlog")), +ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxf/pg_wal")), 'WAL files copied'); +$node->command_ok( + [ 'pg_basebackup', '-D', "$tempdir/backupxst", '-X', 'stream', '-Ft' ], + 'pg_basebackup -X stream runs in tar mode'); +ok(-f "$tempdir/backupxst/pg_wal.tar", "tar file was created"); +$node->command_ok( + [ 'pg_basebackup', '-D', "$tempdir/backupnoslot", '-X', 'stream', '--no-slot' ], + 'pg_basebackup -X stream runs with --no-slot'); $node->command_fails( [ 'pg_basebackup', '-D', "$tempdir/fail", '-S', 'slot1' ], @@ -221,5 +279,5 @@ 'pg_basebackup with replication slot and -R runs'); like( slurp_file("$tempdir/backupxs_sl_R/recovery.conf"), - qr/^primary_slot_name = 'slot1'$/m, + qr/^primary_slot_name = 'slot1'\n/m, 'recovery.conf sets primary_slot_name'); diff --git a/src/bin/pg_basebackup/t/030_pg_recvlogical.pl b/src/bin/pg_basebackup/t/030_pg_recvlogical.pl new file mode 100644 index 0000000000..dca5ef2181 --- /dev/null +++ b/src/bin/pg_basebackup/t/030_pg_recvlogical.pl @@ -0,0 +1,46 @@ +use strict; +use warnings; +use TestLib; +use PostgresNode; +use Test::More tests => 15; + +program_help_ok('pg_recvlogical'); +program_version_ok('pg_recvlogical'); +program_options_handling_ok('pg_recvlogical'); + +my $node = get_new_node('main'); + +# Initialize node without replication settings +$node->init(allows_streaming => 1, has_archiving => 1); +$node->append_conf('postgresql.conf', q{ +wal_level = 'logical' +max_replication_slots = 4 +max_wal_senders = 4 +log_min_messages = 'debug1' +log_error_verbosity = verbose +}); +$node->dump_info; +$node->start; + +$node->command_fails(['pg_recvlogical'], + 'pg_recvlogical needs a slot name'); +$node->command_fails(['pg_recvlogical', '-S', 'test'], + 'pg_recvlogical needs a database'); +$node->command_fails(['pg_recvlogical', '-S', 'test', '-d', 'postgres'], + 'pg_recvlogical needs an action'); +$node->command_fails(['pg_recvlogical', '-S', 'test', '-d', $node->connstr('postgres'), '--start'], + 'no destionation file'); + +$node->command_ok(['pg_recvlogical', '-S', 'test', '-d', $node->connstr('postgres'), '--create-slot'], + 'slot created'); + +my $slot = $node->slot('test'); +isnt($slot->{'restart_lsn'}, '', 'restart lsn is defined for new slot'); + +$node->psql('postgres', 'CREATE TABLE test_table(x integer)'); +$node->psql('postgres', 'INSERT INTO test_table(x) SELECT y FROM generate_series(1, 10) a(y);'); +my $nextlsn = $node->safe_psql('postgres', 'SELECT pg_current_xlog_insert_location()'); +chomp($nextlsn); + +$node->command_ok(['pg_recvlogical', '-S', 'test', '-d', $node->connstr('postgres'), '--start', '--endpos', "$nextlsn", '--no-loop', '-f', '-'], + 'replayed a transaction'); diff --git a/src/bin/pg_basebackup/walmethods.c b/src/bin/pg_basebackup/walmethods.c new file mode 100644 index 0000000000..d9ad596bf0 --- /dev/null +++ b/src/bin/pg_basebackup/walmethods.c @@ -0,0 +1,986 @@ +/*------------------------------------------------------------------------- + * + * walmethods.c - implementations of different ways to write received wal + * + * NOTE! The caller must ensure that only one method is instantiated in + * any given program, and that it's only instantiated once! + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/bin/pg_basebackup/walmethods.c + *------------------------------------------------------------------------- + */ + +#include "postgres_fe.h" + +#include +#include +#include +#ifdef HAVE_LIBZ +#include +#endif + +#include "pgtar.h" +#include "common/file_utils.h" + +#include "receivelog.h" +#include "streamutil.h" + +/* Size of zlib buffer for .tar.gz */ +#define ZLIB_OUT_SIZE 4096 + +/*------------------------------------------------------------------------- + * WalDirectoryMethod - write wal to a directory looking like pg_xlog + *------------------------------------------------------------------------- + */ + +/* + * Global static data for this method + */ +typedef struct DirectoryMethodData +{ + char *basedir; + int compression; + bool sync; +} DirectoryMethodData; +static DirectoryMethodData *dir_data = NULL; + +/* + * Local file handle + */ +typedef struct DirectoryMethodFile +{ + int fd; + off_t currpos; + char *pathname; + char *fullpath; + char *temp_suffix; +#ifdef HAVE_LIBZ + gzFile gzfp; +#endif +} DirectoryMethodFile; + +static char * +dir_getlasterror(void) +{ + /* Directory method always sets errno, so just use strerror */ + return strerror(errno); +} + +static Walfile +dir_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_size) +{ + static char tmppath[MAXPGPATH]; + int fd; + DirectoryMethodFile *f; +#ifdef HAVE_LIBZ + gzFile gzfp = NULL; +#endif + + snprintf(tmppath, sizeof(tmppath), "%s/%s%s%s", + dir_data->basedir, pathname, + dir_data->compression > 0 ? ".gz" : "", + temp_suffix ? temp_suffix : ""); + + /* + * Open a file for non-compressed as well as compressed files. Tracking + * the file descriptor is important for dir_sync() method as gzflush() + * does not do any system calls to fsync() to make changes permanent on + * disk. + */ + fd = open(tmppath, O_WRONLY | O_CREAT | PG_BINARY, S_IRUSR | S_IWUSR); + if (fd < 0) + return NULL; + +#ifdef HAVE_LIBZ + if (dir_data->compression > 0) + { + gzfp = gzdopen(fd, "wb"); + if (gzfp == NULL) + { + close(fd); + return NULL; + } + + if (gzsetparams(gzfp, dir_data->compression, + Z_DEFAULT_STRATEGY) != Z_OK) + { + gzclose(gzfp); + return NULL; + } + } +#endif + + /* Do pre-padding on non-compressed files */ + if (pad_to_size && dir_data->compression == 0) + { + char *zerobuf; + int bytes; + + zerobuf = pg_malloc0(XLOG_BLCKSZ); + for (bytes = 0; bytes < pad_to_size; bytes += XLOG_BLCKSZ) + { + if (write(fd, zerobuf, XLOG_BLCKSZ) != XLOG_BLCKSZ) + { + int save_errno = errno; + + pg_free(zerobuf); + close(fd); + errno = save_errno; + return NULL; + } + } + pg_free(zerobuf); + + if (lseek(fd, 0, SEEK_SET) != 0) + { + int save_errno = errno; + + close(fd); + errno = save_errno; + return NULL; + } + } + + /* + * fsync WAL file and containing directory, to ensure the file is + * persistently created and zeroed (if padded). That's particularly + * important when using synchronous mode, where the file is modified and + * fsynced in-place, without a directory fsync. + */ + if (dir_data->sync) + { + if (fsync_fname(tmppath, false, progname) != 0 || + fsync_parent_path(tmppath, progname) != 0) + { +#ifdef HAVE_LIBZ + if (dir_data->compression > 0) + gzclose(gzfp); + else +#endif + close(fd); + return NULL; + } + } + + f = pg_malloc0(sizeof(DirectoryMethodFile)); +#ifdef HAVE_LIBZ + if (dir_data->compression > 0) + f->gzfp = gzfp; +#endif + f->fd = fd; + f->currpos = 0; + f->pathname = pg_strdup(pathname); + f->fullpath = pg_strdup(tmppath); + if (temp_suffix) + f->temp_suffix = pg_strdup(temp_suffix); + + return f; +} + +static ssize_t +dir_write(Walfile f, const void *buf, size_t count) +{ + ssize_t r; + DirectoryMethodFile *df = (DirectoryMethodFile *) f; + + Assert(f != NULL); + +#ifdef HAVE_LIBZ + if (dir_data->compression > 0) + r = (ssize_t) gzwrite(df->gzfp, buf, count); + else +#endif + r = write(df->fd, buf, count); + if (r > 0) + df->currpos += r; + return r; +} + +static off_t +dir_get_current_pos(Walfile f) +{ + Assert(f != NULL); + + /* Use a cached value to prevent lots of reseeks */ + return ((DirectoryMethodFile *) f)->currpos; +} + +static int +dir_close(Walfile f, WalCloseMethod method) +{ + int r; + DirectoryMethodFile *df = (DirectoryMethodFile *) f; + static char tmppath[MAXPGPATH]; + static char tmppath2[MAXPGPATH]; + + Assert(f != NULL); + +#ifdef HAVE_LIBZ + if (dir_data->compression > 0) + r = gzclose(df->gzfp); + else +#endif + r = close(df->fd); + + if (r == 0) + { + /* Build path to the current version of the file */ + if (method == CLOSE_NORMAL && df->temp_suffix) + { + /* + * If we have a temp prefix, normal operation is to rename the + * file. + */ + snprintf(tmppath, sizeof(tmppath), "%s/%s%s%s", + dir_data->basedir, df->pathname, + dir_data->compression > 0 ? ".gz" : "", + df->temp_suffix); + snprintf(tmppath2, sizeof(tmppath2), "%s/%s%s", + dir_data->basedir, df->pathname, + dir_data->compression > 0 ? ".gz" : ""); + r = durable_rename(tmppath, tmppath2, progname); + } + else if (method == CLOSE_UNLINK) + { + /* Unlink the file once it's closed */ + snprintf(tmppath, sizeof(tmppath), "%s/%s%s%s", + dir_data->basedir, df->pathname, + dir_data->compression > 0 ? ".gz" : "", + df->temp_suffix ? df->temp_suffix : ""); + r = unlink(tmppath); + } + else + { + /* + * Else either CLOSE_NORMAL and no temp suffix, or + * CLOSE_NO_RENAME. In this case, fsync the file and containing + * directory if sync mode is requested. + */ + if (dir_data->sync) + { + r = fsync_fname(df->fullpath, false, progname); + if (r == 0) + r = fsync_parent_path(df->fullpath, progname); + } + } + } + + pg_free(df->pathname); + pg_free(df->fullpath); + if (df->temp_suffix) + pg_free(df->temp_suffix); + pg_free(df); + + return r; +} + +static int +dir_sync(Walfile f) +{ + Assert(f != NULL); + + if (!dir_data->sync) + return 0; + +#ifdef HAVE_LIBZ + if (dir_data->compression > 0) + { + if (gzflush(((DirectoryMethodFile *) f)->gzfp, Z_SYNC_FLUSH) != Z_OK) + return -1; + } +#endif + + return fsync(((DirectoryMethodFile *) f)->fd); +} + +static ssize_t +dir_get_file_size(const char *pathname) +{ + struct stat statbuf; + static char tmppath[MAXPGPATH]; + + snprintf(tmppath, sizeof(tmppath), "%s/%s", + dir_data->basedir, pathname); + + if (stat(tmppath, &statbuf) != 0) + return -1; + + return statbuf.st_size; +} + +static bool +dir_existsfile(const char *pathname) +{ + static char tmppath[MAXPGPATH]; + int fd; + + snprintf(tmppath, sizeof(tmppath), "%s/%s", + dir_data->basedir, pathname); + + fd = open(tmppath, O_RDONLY | PG_BINARY, 0); + if (fd < 0) + return false; + close(fd); + return true; +} + +static bool +dir_finish(void) +{ + if (dir_data->sync) + { + /* + * Files are fsynced when they are closed, but we need to fsync the + * directory entry here as well. + */ + if (fsync_fname(dir_data->basedir, true, progname) != 0) + return false; + } + return true; +} + + +WalWriteMethod * +CreateWalDirectoryMethod(const char *basedir, int compression, bool sync) +{ + WalWriteMethod *method; + + method = pg_malloc0(sizeof(WalWriteMethod)); + method->open_for_write = dir_open_for_write; + method->write = dir_write; + method->get_current_pos = dir_get_current_pos; + method->get_file_size = dir_get_file_size; + method->close = dir_close; + method->sync = dir_sync; + method->existsfile = dir_existsfile; + method->finish = dir_finish; + method->getlasterror = dir_getlasterror; + + dir_data = pg_malloc0(sizeof(DirectoryMethodData)); + dir_data->compression = compression; + dir_data->basedir = pg_strdup(basedir); + dir_data->sync = sync; + + return method; +} + +void +FreeWalDirectoryMethod(void) +{ + pg_free(dir_data->basedir); + pg_free(dir_data); +} + + +/*------------------------------------------------------------------------- + * WalTarMethod - write wal to a tar file containing pg_xlog contents + *------------------------------------------------------------------------- + */ + +typedef struct TarMethodFile +{ + off_t ofs_start; /* Where does the *header* for this file start */ + off_t currpos; + char header[512]; + char *pathname; + size_t pad_to_size; +} TarMethodFile; + +typedef struct TarMethodData +{ + char *tarfilename; + int fd; + int compression; + bool sync; + TarMethodFile *currentfile; + char lasterror[1024]; +#ifdef HAVE_LIBZ + z_streamp zp; + void *zlibOut; +#endif +} TarMethodData; +static TarMethodData *tar_data = NULL; + +#define tar_clear_error() tar_data->lasterror[0] = '\0' +#define tar_set_error(msg) strlcpy(tar_data->lasterror, msg, sizeof(tar_data->lasterror)) + +static char * +tar_getlasterror(void) +{ + /* + * If a custom error is set, return that one. Otherwise, assume errno is + * set and return that one. + */ + if (tar_data->lasterror[0]) + return tar_data->lasterror; + return strerror(errno); +} + +#ifdef HAVE_LIBZ +static bool +tar_write_compressed_data(void *buf, size_t count, bool flush) +{ + tar_data->zp->next_in = buf; + tar_data->zp->avail_in = count; + + while (tar_data->zp->avail_in || flush) + { + int r; + + r = deflate(tar_data->zp, flush ? Z_FINISH : Z_NO_FLUSH); + if (r == Z_STREAM_ERROR) + { + tar_set_error("deflate failed"); + return false; + } + + if (tar_data->zp->avail_out < ZLIB_OUT_SIZE) + { + size_t len = ZLIB_OUT_SIZE - tar_data->zp->avail_out; + + if (write(tar_data->fd, tar_data->zlibOut, len) != len) + return false; + + tar_data->zp->next_out = tar_data->zlibOut; + tar_data->zp->avail_out = ZLIB_OUT_SIZE; + } + + if (r == Z_STREAM_END) + break; + } + + if (flush) + { + /* Reset the stream for writing */ + if (deflateReset(tar_data->zp) != Z_OK) + { + tar_set_error("deflateReset failed"); + return false; + } + } + + return true; +} +#endif + +static ssize_t +tar_write(Walfile f, const void *buf, size_t count) +{ + ssize_t r; + + Assert(f != NULL); + tar_clear_error(); + + /* Tarfile will always be positioned at the end */ + if (!tar_data->compression) + { + r = write(tar_data->fd, buf, count); + if (r > 0) + ((TarMethodFile *) f)->currpos += r; + return r; + } +#ifdef HAVE_LIBZ + else + { + if (!tar_write_compressed_data((void *) buf, count, false)) + return -1; + ((TarMethodFile *) f)->currpos += count; + return count; + } +#else + else + /* Can't happen - compression enabled with no libz */ + return -1; +#endif +} + +static bool +tar_write_padding_data(TarMethodFile * f, size_t bytes) +{ + char *zerobuf = pg_malloc0(XLOG_BLCKSZ); + size_t bytesleft = bytes; + + while (bytesleft) + { + size_t bytestowrite = bytesleft > XLOG_BLCKSZ ? XLOG_BLCKSZ : bytesleft; + + ssize_t r = tar_write(f, zerobuf, bytestowrite); + + if (r < 0) + { + pg_free(zerobuf); + return false; + } + bytesleft -= r; + } + + pg_free(zerobuf); + return true; +} + +static Walfile +tar_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_size) +{ + int save_errno; + static char tmppath[MAXPGPATH]; + + tar_clear_error(); + + if (tar_data->fd < 0) + { + /* + * We open the tar file only when we first try to write to it. + */ + tar_data->fd = open(tar_data->tarfilename, + O_WRONLY | O_CREAT | PG_BINARY, S_IRUSR | S_IWUSR); + if (tar_data->fd < 0) + return NULL; + +#ifdef HAVE_LIBZ + if (tar_data->compression) + { + tar_data->zp = (z_streamp) pg_malloc(sizeof(z_stream)); + tar_data->zp->zalloc = Z_NULL; + tar_data->zp->zfree = Z_NULL; + tar_data->zp->opaque = Z_NULL; + tar_data->zp->next_out = tar_data->zlibOut; + tar_data->zp->avail_out = ZLIB_OUT_SIZE; + + /* + * Initialize deflation library. Adding the magic value 16 to the + * default 15 for the windowBits parameter makes the output be + * gzip instead of zlib. + */ + if (deflateInit2(tar_data->zp, tar_data->compression, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY) != Z_OK) + { + pg_free(tar_data->zp); + tar_data->zp = NULL; + tar_set_error("deflateInit2 failed"); + return NULL; + } + } +#endif + + /* There's no tar header itself, the file starts with regular files */ + } + + Assert(tar_data->currentfile == NULL); + if (tar_data->currentfile != NULL) + { + tar_set_error("implementation error: tar files can't have more than one open file\n"); + return NULL; + } + + tar_data->currentfile = pg_malloc0(sizeof(TarMethodFile)); + + snprintf(tmppath, sizeof(tmppath), "%s%s", + pathname, temp_suffix ? temp_suffix : ""); + + /* Create a header with size set to 0 - we will fill out the size on close */ + if (tarCreateHeader(tar_data->currentfile->header, tmppath, NULL, 0, S_IRUSR | S_IWUSR, 0, 0, time(NULL)) != TAR_OK) + { + pg_free(tar_data->currentfile); + tar_data->currentfile = NULL; + tar_set_error("could not create tar header"); + return NULL; + } + +#ifdef HAVE_LIBZ + if (tar_data->compression) + { + /* Flush existing data */ + if (!tar_write_compressed_data(NULL, 0, true)) + return NULL; + + /* Turn off compression for header */ + if (deflateParams(tar_data->zp, 0, 0) != Z_OK) + { + tar_set_error("deflateParams failed"); + return NULL; + } + } +#endif + + tar_data->currentfile->ofs_start = lseek(tar_data->fd, 0, SEEK_CUR); + if (tar_data->currentfile->ofs_start == -1) + { + save_errno = errno; + pg_free(tar_data->currentfile); + tar_data->currentfile = NULL; + errno = save_errno; + return NULL; + } + tar_data->currentfile->currpos = 0; + + if (!tar_data->compression) + { + if (write(tar_data->fd, tar_data->currentfile->header, 512) != 512) + { + save_errno = errno; + pg_free(tar_data->currentfile); + tar_data->currentfile = NULL; + errno = save_errno; + return NULL; + } + } +#ifdef HAVE_LIBZ + else + { + /* Write header through the zlib APIs but with no compression */ + if (!tar_write_compressed_data(tar_data->currentfile->header, 512, true)) + return NULL; + + /* Re-enable compression for the rest of the file */ + if (deflateParams(tar_data->zp, tar_data->compression, 0) != Z_OK) + { + tar_set_error("deflateParams failed"); + return NULL; + } + } +#endif + + tar_data->currentfile->pathname = pg_strdup(pathname); + + /* + * Uncompressed files are padded on creation, but for compression we can't + * do that + */ + if (pad_to_size) + { + tar_data->currentfile->pad_to_size = pad_to_size; + if (!tar_data->compression) + { + /* Uncompressed, so pad now */ + tar_write_padding_data(tar_data->currentfile, pad_to_size); + /* Seek back to start */ + if (lseek(tar_data->fd, tar_data->currentfile->ofs_start + 512, SEEK_SET) != tar_data->currentfile->ofs_start + 512) + return NULL; + + tar_data->currentfile->currpos = 0; + } + } + + return tar_data->currentfile; +} + +static ssize_t +tar_get_file_size(const char *pathname) +{ + tar_clear_error(); + + /* Currently not used, so not supported */ + errno = ENOSYS; + return -1; +} + +static off_t +tar_get_current_pos(Walfile f) +{ + Assert(f != NULL); + tar_clear_error(); + + return ((TarMethodFile *) f)->currpos; +} + +static int +tar_sync(Walfile f) +{ + Assert(f != NULL); + tar_clear_error(); + + if (!tar_data->sync) + return 0; + + /* + * Always sync the whole tarfile, because that's all we can do. This makes + * no sense on compressed files, so just ignore those. + */ + if (tar_data->compression) + return 0; + + return fsync(tar_data->fd); +} + +static int +tar_close(Walfile f, WalCloseMethod method) +{ + ssize_t filesize; + int padding; + TarMethodFile *tf = (TarMethodFile *) f; + + Assert(f != NULL); + tar_clear_error(); + + if (method == CLOSE_UNLINK) + { + if (tar_data->compression) + { + tar_set_error("unlink not supported with compression"); + return -1; + } + + /* + * Unlink the file that we just wrote to the tar. We do this by + * truncating it to the start of the header. This is safe as we only + * allow writing of the very last file. + */ + if (ftruncate(tar_data->fd, tf->ofs_start) != 0) + return -1; + + pg_free(tf->pathname); + pg_free(tf); + tar_data->currentfile = NULL; + + return 0; + } + + /* + * Pad the file itself with zeroes if necessary. Note that this is + * different from the tar format padding -- this is the padding we asked + * for when the file was opened. + */ + if (tf->pad_to_size) + { + if (tar_data->compression) + { + /* + * A compressed tarfile is padded on close since we cannot know + * the size of the compressed output until the end. + */ + size_t sizeleft = tf->pad_to_size - tf->currpos; + + if (sizeleft) + { + if (!tar_write_padding_data(tf, sizeleft)) + return -1; + } + } + else + { + /* + * An uncompressed tarfile was padded on creation, so just adjust + * the current position as if we seeked to the end. + */ + tf->currpos = tf->pad_to_size; + } + } + + /* + * Get the size of the file, and pad the current data up to the nearest + * 512 byte boundary. + */ + filesize = tar_get_current_pos(f); + padding = ((filesize + 511) & ~511) - filesize; + if (padding) + { + char zerobuf[512]; + + MemSet(zerobuf, 0, padding); + if (tar_write(f, zerobuf, padding) != padding) + return -1; + } + + +#ifdef HAVE_LIBZ + if (tar_data->compression) + { + /* Flush the current buffer */ + if (!tar_write_compressed_data(NULL, 0, true)) + { + errno = EINVAL; + return -1; + } + } +#endif + + /* + * Now go back and update the header with the correct filesize and + * possibly also renaming the file. We overwrite the entire current header + * when done, including the checksum. + */ + print_tar_number(&(tf->header[124]), 12, filesize); + + if (method == CLOSE_NORMAL) + + /* + * We overwrite it with what it was before if we have no tempname, + * since we're going to write the buffer anyway. + */ + strlcpy(&(tf->header[0]), tf->pathname, 100); + + print_tar_number(&(tf->header[148]), 8, tarChecksum(((TarMethodFile *) f)->header)); + if (lseek(tar_data->fd, tf->ofs_start, SEEK_SET) != ((TarMethodFile *) f)->ofs_start) + return -1; + if (!tar_data->compression) + { + if (write(tar_data->fd, tf->header, 512) != 512) + return -1; + } +#ifdef HAVE_LIBZ + else + { + /* Turn off compression */ + if (deflateParams(tar_data->zp, 0, 0) != Z_OK) + { + tar_set_error("deflateParams failed"); + return -1; + } + + /* Overwrite the header, assuming the size will be the same */ + if (!tar_write_compressed_data(tar_data->currentfile->header, 512, true)) + return -1; + + /* Turn compression back on */ + if (deflateParams(tar_data->zp, tar_data->compression, 0) != Z_OK) + { + tar_set_error("deflateParams failed"); + return -1; + } + } +#endif + + /* Move file pointer back down to end, so we can write the next file */ + if (lseek(tar_data->fd, 0, SEEK_END) < 0) + return -1; + + /* Always fsync on close, so the padding gets fsynced */ + tar_sync(f); + + /* Clean up and done */ + pg_free(tf->pathname); + pg_free(tf); + tar_data->currentfile = NULL; + + return 0; +} + +static bool +tar_existsfile(const char *pathname) +{ + tar_clear_error(); + /* We only deal with new tarfiles, so nothing externally created exists */ + return false; +} + +static bool +tar_finish(void) +{ + char zerobuf[1024]; + + tar_clear_error(); + + if (tar_data->currentfile) + { + if (tar_close(tar_data->currentfile, CLOSE_NORMAL) != 0) + return false; + } + + /* A tarfile always ends with two empty blocks */ + MemSet(zerobuf, 0, sizeof(zerobuf)); + if (!tar_data->compression) + { + if (write(tar_data->fd, zerobuf, sizeof(zerobuf)) != sizeof(zerobuf)) + return false; + } +#ifdef HAVE_LIBZ + else + { + if (!tar_write_compressed_data(zerobuf, sizeof(zerobuf), false)) + return false; + + /* Also flush all data to make sure the gzip stream is finished */ + tar_data->zp->next_in = NULL; + tar_data->zp->avail_in = 0; + while (true) + { + int r; + + r = deflate(tar_data->zp, Z_FINISH); + + if (r == Z_STREAM_ERROR) + { + tar_set_error("deflate failed"); + return false; + } + if (tar_data->zp->avail_out < ZLIB_OUT_SIZE) + { + size_t len = ZLIB_OUT_SIZE - tar_data->zp->avail_out; + + if (write(tar_data->fd, tar_data->zlibOut, len) != len) + return false; + } + if (r == Z_STREAM_END) + break; + } + + if (deflateEnd(tar_data->zp) != Z_OK) + { + tar_set_error("deflateEnd failed"); + return false; + } + } +#endif + + /* sync the empty blocks as well, since they're after the last file */ + if (tar_data->sync) + fsync(tar_data->fd); + + if (close(tar_data->fd) != 0) + return false; + + tar_data->fd = -1; + + if (tar_data->sync) + { + if (fsync_fname(tar_data->tarfilename, false, progname) != 0) + return false; + if (fsync_parent_path(tar_data->tarfilename, progname) != 0) + return false; + } + + return true; +} + +WalWriteMethod * +CreateWalTarMethod(const char *tarbase, int compression, bool sync) +{ + WalWriteMethod *method; + const char *suffix = (compression != 0) ? ".tar.gz" : ".tar"; + + method = pg_malloc0(sizeof(WalWriteMethod)); + method->open_for_write = tar_open_for_write; + method->write = tar_write; + method->get_current_pos = tar_get_current_pos; + method->get_file_size = tar_get_file_size; + method->close = tar_close; + method->sync = tar_sync; + method->existsfile = tar_existsfile; + method->finish = tar_finish; + method->getlasterror = tar_getlasterror; + + tar_data = pg_malloc0(sizeof(TarMethodData)); + tar_data->tarfilename = pg_malloc0(strlen(tarbase) + strlen(suffix) + 1); + sprintf(tar_data->tarfilename, "%s%s", tarbase, suffix); + tar_data->fd = -1; + tar_data->compression = compression; + tar_data->sync = sync; +#ifdef HAVE_LIBZ + if (compression) + tar_data->zlibOut = (char *) pg_malloc(ZLIB_OUT_SIZE + 1); +#endif + + return method; +} + +void +FreeWalTarMethod(void) +{ + pg_free(tar_data->tarfilename); +#ifdef HAVE_LIBZ + if (tar_data->compression) + pg_free(tar_data->zlibOut); +#endif + pg_free(tar_data); +} diff --git a/src/bin/pg_basebackup/walmethods.h b/src/bin/pg_basebackup/walmethods.h new file mode 100644 index 0000000000..2cd8b6d755 --- /dev/null +++ b/src/bin/pg_basebackup/walmethods.h @@ -0,0 +1,50 @@ +/*------------------------------------------------------------------------- + * + * walmethods.h + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/bin/pg_basebackup/walmethods.h + *------------------------------------------------------------------------- + */ + + +typedef void *Walfile; + +typedef enum +{ + CLOSE_NORMAL, + CLOSE_UNLINK, + CLOSE_NO_RENAME +} WalCloseMethod; + +typedef struct WalWriteMethod WalWriteMethod; +struct WalWriteMethod +{ + Walfile(*open_for_write) (const char *pathname, const char *temp_suffix, size_t pad_to_size); + int (*close) (Walfile f, WalCloseMethod method); + bool (*existsfile) (const char *pathname); + ssize_t (*get_file_size) (const char *pathname); + + ssize_t (*write) (Walfile f, const void *buf, size_t count); + off_t (*get_current_pos) (Walfile f); + int (*sync) (Walfile f); + bool (*finish) (void); + char *(*getlasterror) (void); +}; + +/* + * Available WAL methods: + * - WalDirectoryMethod - write WAL to regular files in a standard pg_xlog + * - TarDirectoryMethod - write WAL to a tarfile corresponding to pg_xlog + * (only implements the methods required for pg_basebackup, + * not all those required for pg_receivexlog) + */ +WalWriteMethod *CreateWalDirectoryMethod(const char *basedir, + int compression, bool sync); +WalWriteMethod *CreateWalTarMethod(const char *tarbase, int compression, bool sync); + +/* Cleanup routines for previously-created methods */ +void FreeWalDirectoryMethod(void); +void FreeWalTarMethod(void); diff --git a/src/bin/pg_config/Makefile b/src/bin/pg_config/Makefile index 26fbaadadd..c41008763e 100644 --- a/src/bin/pg_config/Makefile +++ b/src/bin/pg_config/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/pg_config # -# Copyright (c) 1998-2016, PostgreSQL Global Development Group +# Copyright (c) 1998-2017, PostgreSQL Global Development Group # # src/bin/pg_config/Makefile # diff --git a/src/bin/pg_config/pg_config.c b/src/bin/pg_config/pg_config.c index 9048566f0d..fa2a5a9943 100644 --- a/src/bin/pg_config/pg_config.c +++ b/src/bin/pg_config/pg_config.c @@ -15,7 +15,7 @@ * * This code is released under the terms of the PostgreSQL License. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * src/bin/pg_config/pg_config.c * diff --git a/src/bin/pg_controldata/Makefile b/src/bin/pg_controldata/Makefile index e3858820b3..fd87daa11a 100644 --- a/src/bin/pg_controldata/Makefile +++ b/src/bin/pg_controldata/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/pg_controldata # -# Copyright (c) 1998-2016, PostgreSQL Global Development Group +# Copyright (c) 1998-2017, PostgreSQL Global Development Group # # src/bin/pg_controldata/Makefile # diff --git a/src/bin/pg_controldata/pg_controldata.c b/src/bin/pg_controldata/pg_controldata.c index 96619a2076..20077a6639 100644 --- a/src/bin/pg_controldata/pg_controldata.c +++ b/src/bin/pg_controldata/pg_controldata.c @@ -86,6 +86,7 @@ int main(int argc, char *argv[]) { ControlFileData *ControlFile; + bool crc_ok; char *DataDir = NULL; time_t time_tmp; char pgctime_str[128]; @@ -155,7 +156,11 @@ main(int argc, char *argv[]) } /* get a copy of the control file */ - ControlFile = get_controlfile(DataDir, progname); + ControlFile = get_controlfile(DataDir, progname, &crc_ok); + if (!crc_ok) + printf(_("WARNING: Calculated CRC checksum does not match value stored in file.\n" + "Either the file is corrupt, or it has a different layout than this program\n" + "is expecting. The results below are untrustworthy.\n\n")); /* * This slightly-chintzy coding will work as long as the control file diff --git a/src/bin/pg_ctl/Makefile b/src/bin/pg_ctl/Makefile index 6000eab256..f5ec088c42 100644 --- a/src/bin/pg_ctl/Makefile +++ b/src/bin/pg_ctl/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/pg_ctl # -# Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/bin/pg_ctl/Makefile diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c index efc07291ad..93e5891950 100644 --- a/src/bin/pg_ctl/pg_ctl.c +++ b/src/bin/pg_ctl/pg_ctl.c @@ -2,7 +2,7 @@ * * pg_ctl --- start/stops/restarts the PostgreSQL server * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * src/bin/pg_ctl/pg_ctl.c * @@ -19,6 +19,8 @@ #include "postgres_fe.h" +#include "catalog/pg_control.h" +#include "common/controldata_utils.h" #include "libpq-fe.h" #include "pqexpbuffer.h" @@ -69,8 +71,7 @@ typedef enum #define DEFAULT_WAIT 60 -static bool do_wait = false; -static bool wait_set = false; +static bool do_wait = true; static int wait_seconds = DEFAULT_WAIT; static bool wait_seconds_arg = false; static bool silent_mode = false; @@ -96,7 +97,6 @@ static char postopts_file[MAXPGPATH]; static char version_file[MAXPGPATH]; static char pid_file[MAXPGPATH]; static char backup_file[MAXPGPATH]; -static char recovery_file[MAXPGPATH]; static char promote_file[MAXPGPATH]; #ifdef WIN32 @@ -158,6 +158,8 @@ static bool postmaster_is_alive(pid_t pid); static void unlimit_core_size(void); #endif +static DBState get_control_dbstate(void); + #ifdef WIN32 static void @@ -988,12 +990,12 @@ do_stop(void) /* * If backup_label exists, an online backup is running. Warn the user * that smart shutdown will wait for it to finish. However, if - * recovery.conf is also present, we're recovering from an online + * the server is in archive recovery, we're recovering from an online * backup instead of performing one. */ if (shutdown_mode == SMART_MODE && stat(backup_file, &statbuf) == 0 && - stat(recovery_file, &statbuf) != 0) + get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY) { print_msg(_("WARNING: online backup mode is active\n" "Shutdown will not complete until pg_stop_backup() is called.\n\n")); @@ -1076,12 +1078,12 @@ do_restart(void) /* * If backup_label exists, an online backup is running. Warn the user * that smart shutdown will wait for it to finish. However, if - * recovery.conf is also present, we're recovering from an online + * the server is in archive recovery, we're recovering from an online * backup instead of performing one. */ if (shutdown_mode == SMART_MODE && stat(backup_file, &statbuf) == 0 && - stat(recovery_file, &statbuf) != 0) + get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY) { print_msg(_("WARNING: online backup mode is active\n" "Shutdown will not complete until pg_stop_backup() is called.\n\n")); @@ -1168,7 +1170,6 @@ do_promote(void) { FILE *prmfile; pgpid_t pid; - struct stat statbuf; pid = get_pgpid(false); @@ -1187,8 +1188,7 @@ do_promote(void) exit(1); } - /* If recovery.conf doesn't exist, the server is not in standby mode */ - if (stat(recovery_file, &statbuf) != 0) + if (get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY) { write_stderr(_("%s: cannot promote server; " "server is not in standby mode\n"), @@ -1227,7 +1227,34 @@ do_promote(void) exit(1); } - print_msg(_("server promoting\n")); + if (do_wait) + { + DBState state = DB_STARTUP; + + print_msg(_("waiting for server to promote...")); + while (wait_seconds > 0) + { + state = get_control_dbstate(); + if (state == DB_IN_PRODUCTION) + break; + + print_msg("."); + pg_usleep(1000000); /* 1 sec */ + wait_seconds--; + } + if (state == DB_IN_PRODUCTION) + { + print_msg(_(" done\n")); + print_msg(_("server promoted\n")); + } + else + { + print_msg(_(" stopped waiting\n")); + print_msg(_("server is still promoting\n")); + } + } + else + print_msg(_("server promoting\n")); } @@ -1913,9 +1940,9 @@ do_help(void) printf(_(" %s stop [-W] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"), progname); printf(_(" %s restart [-w] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n" " [-o \"OPTIONS\"]\n"), progname); - printf(_(" %s reload [-D DATADIR] [-s]\n"), progname); - printf(_(" %s status [-D DATADIR]\n"), progname); - printf(_(" %s promote [-D DATADIR] [-s]\n"), progname); + printf(_(" %s reload [-D DATADIR] [-s]\n"), progname); + printf(_(" %s status [-D DATADIR]\n"), progname); + printf(_(" %s promote [-w] [-t SECS] [-D DATADIR] [-s]\n"), progname); printf(_(" %s kill SIGNALNAME PID\n"), progname); #ifdef WIN32 printf(_(" %s register [-N SERVICENAME] [-U USERNAME] [-P PASSWORD] [-D DATADIR]\n" @@ -1931,8 +1958,8 @@ do_help(void) printf(_(" -s, --silent only print errors, no informational messages\n")); printf(_(" -t, --timeout=SECS seconds to wait when using -w option\n")); printf(_(" -V, --version output version information, then exit\n")); - printf(_(" -w wait until operation completes\n")); - printf(_(" -W do not wait until operation completes\n")); + printf(_(" -w, --wait wait until operation completes (default)\n")); + printf(_(" -W, --no-wait do not wait until operation completes\n")); printf(_(" -?, --help show this help, then exit\n")); printf(_("(The default is to wait for shutdown, but not for start or restart.)\n\n")); printf(_("If the -D option is omitted, the environment variable PGDATA is used.\n")); @@ -1944,7 +1971,7 @@ do_help(void) printf(_(" -c, --core-files not applicable on this platform\n")); #endif printf(_(" -l, --log=FILENAME write (or append) server log to FILENAME\n")); - printf(_(" -o OPTIONS command line options to pass to postgres\n" + printf(_(" -o, --options=OPTIONS command line options to pass to postgres\n" " (PostgreSQL server executable) or initdb\n")); printf(_(" -p PATH-TO-POSTGRES normally not necessary\n")); printf(_("\nOptions for stop or restart:\n")); @@ -2115,6 +2142,25 @@ adjust_data_dir(void) } +static DBState +get_control_dbstate(void) +{ + DBState ret; + bool crc_ok; + ControlFileData *control_file_data = get_controlfile(pg_data, progname, &crc_ok); + + if (!crc_ok) + { + write_stderr(_("%s: control file appears to be corrupt\n"), progname); + exit(1); + } + + ret = control_file_data->state; + pfree(control_file_data); + return ret; +} + + int main(int argc, char **argv) { @@ -2124,9 +2170,12 @@ main(int argc, char **argv) {"log", required_argument, NULL, 'l'}, {"mode", required_argument, NULL, 'm'}, {"pgdata", required_argument, NULL, 'D'}, + {"options", required_argument, NULL, 'o'}, {"silent", no_argument, NULL, 's'}, {"timeout", required_argument, NULL, 't'}, {"core-files", no_argument, NULL, 'c'}, + {"wait", no_argument, NULL, 'w'}, + {"no-wait", no_argument, NULL, 'W'}, {NULL, 0, NULL, 0} }; @@ -2273,11 +2322,9 @@ main(int argc, char **argv) break; case 'w': do_wait = true; - wait_set = true; break; case 'W': do_wait = false; - wait_set = true; break; case 'c': allow_core_files = true; @@ -2373,22 +2420,6 @@ main(int argc, char **argv) exit(1); } - if (!wait_set) - { - switch (ctl_command) - { - case RESTART_COMMAND: - case START_COMMAND: - do_wait = false; - break; - case STOP_COMMAND: - do_wait = true; - break; - default: - break; - } - } - if (ctl_command == RELOAD_COMMAND) { sig = SIGHUP; @@ -2401,7 +2432,6 @@ main(int argc, char **argv) snprintf(version_file, MAXPGPATH, "%s/PG_VERSION", pg_data); snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data); snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data); - snprintf(recovery_file, MAXPGPATH, "%s/recovery.conf", pg_data); } switch (ctl_command) diff --git a/src/bin/pg_ctl/t/001_start_stop.pl b/src/bin/pg_ctl/t/001_start_stop.pl index cbe99d79ad..8f16bf9795 100644 --- a/src/bin/pg_ctl/t/001_start_stop.pl +++ b/src/bin/pg_ctl/t/001_start_stop.pl @@ -32,24 +32,24 @@ print CONF "listen_addresses = '127.0.0.1'\n"; } close CONF; -command_ok([ 'pg_ctl', 'start', '-D', "$tempdir/data", '-w' ], - 'pg_ctl start -w'); +command_ok([ 'pg_ctl', 'start', '-D', "$tempdir/data" ], + 'pg_ctl start'); # sleep here is because Windows builds can't check postmaster.pid exactly, # so they may mistake a pre-existing postmaster.pid for one created by the # postmaster they start. Waiting more than the 2 seconds slop time allowed # by test_postmaster_connection prevents that mistake. sleep 3 if ($windows_os); -command_fails([ 'pg_ctl', 'start', '-D', "$tempdir/data", '-w' ], - 'second pg_ctl start -w fails'); -command_ok([ 'pg_ctl', 'stop', '-D', "$tempdir/data", '-w', '-m', 'fast' ], - 'pg_ctl stop -w'); -command_fails([ 'pg_ctl', 'stop', '-D', "$tempdir/data", '-w', '-m', 'fast' ], +command_fails([ 'pg_ctl', 'start', '-D', "$tempdir/data" ], + 'second pg_ctl start fails'); +command_ok([ 'pg_ctl', 'stop', '-D', "$tempdir/data" ], + 'pg_ctl stop'); +command_fails([ 'pg_ctl', 'stop', '-D', "$tempdir/data" ], 'second pg_ctl stop fails'); -command_ok([ 'pg_ctl', 'restart', '-D', "$tempdir/data", '-w', '-m', 'fast' ], +command_ok([ 'pg_ctl', 'restart', '-D', "$tempdir/data" ], 'pg_ctl restart with server not running'); -command_ok([ 'pg_ctl', 'restart', '-D', "$tempdir/data", '-w', '-m', 'fast' ], +command_ok([ 'pg_ctl', 'restart', '-D', "$tempdir/data" ], 'pg_ctl restart with server running'); -system_or_bail 'pg_ctl', 'stop', '-D', "$tempdir/data", '-m', 'fast'; +system_or_bail 'pg_ctl', 'stop', '-D', "$tempdir/data"; diff --git a/src/bin/pg_ctl/t/002_status.pl b/src/bin/pg_ctl/t/002_status.pl index 98e171e394..606d10560f 100644 --- a/src/bin/pg_ctl/t/002_status.pl +++ b/src/bin/pg_ctl/t/002_status.pl @@ -22,4 +22,4 @@ command_exit_is([ 'pg_ctl', 'status', '-D', $node->data_dir ], 0, 'pg_ctl status with server running'); -system_or_bail 'pg_ctl', 'stop', '-D', $node->data_dir, '-m', 'fast'; +system_or_bail 'pg_ctl', 'stop', '-D', $node->data_dir; diff --git a/src/bin/pg_ctl/t/003_promote.pl b/src/bin/pg_ctl/t/003_promote.pl new file mode 100644 index 0000000000..7b1df29fa3 --- /dev/null +++ b/src/bin/pg_ctl/t/003_promote.pl @@ -0,0 +1,55 @@ +use strict; +use warnings; + +use PostgresNode; +use TestLib; +use Test::More tests => 12; + +my $tempdir = TestLib::tempdir; + +command_fails_like([ 'pg_ctl', '-D', "$tempdir/nonexistent", 'promote' ], + qr/directory .* does not exist/, + 'pg_ctl promote with nonexistent directory'); + +my $node_primary = get_new_node('primary'); +$node_primary->init(allows_streaming => 1); + +command_fails_like([ 'pg_ctl', '-D', $node_primary->data_dir, 'promote' ], + qr/PID file .* does not exist/, + 'pg_ctl promote of not running instance fails'); + +$node_primary->start; + +command_fails_like([ 'pg_ctl', '-D', $node_primary->data_dir, 'promote' ], + qr/not in standby mode/, + 'pg_ctl promote of primary instance fails'); + +my $node_standby = get_new_node('standby'); +$node_primary->backup('my_backup'); +$node_standby->init_from_backup($node_primary, 'my_backup', has_streaming => 1); +$node_standby->start; + +is($node_standby->safe_psql('postgres', 'SELECT pg_is_in_recovery()'), + 't', 'standby is in recovery'); + +command_ok([ 'pg_ctl', '-D', $node_standby->data_dir, '-W', 'promote' ], + 'pg_ctl -W promote of standby runs'); + +ok($node_standby->poll_query_until('postgres', 'SELECT NOT pg_is_in_recovery()'), + 'promoted standby is not in recovery'); + +# same again with default wait option +$node_standby = get_new_node('standby2'); +$node_standby->init_from_backup($node_primary, 'my_backup', has_streaming => 1); +$node_standby->start; + +is($node_standby->safe_psql('postgres', 'SELECT pg_is_in_recovery()'), + 't', 'standby is in recovery'); + +command_ok([ 'pg_ctl', '-D', $node_standby->data_dir, 'promote' ], + 'pg_ctl promote of standby runs'); + +# no wait here + +is($node_standby->safe_psql('postgres', 'SELECT pg_is_in_recovery()'), + 'f', 'promoted standby is not in recovery'); diff --git a/src/bin/pg_dump/Makefile b/src/bin/pg_dump/Makefile index 25336a5f25..b58636eabf 100644 --- a/src/bin/pg_dump/Makefile +++ b/src/bin/pg_dump/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/pg_dump # -# Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/bin/pg_dump/Makefile diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c index 1cbb9874f3..89530a9f0f 100644 --- a/src/bin/pg_dump/common.c +++ b/src/bin/pg_dump/common.c @@ -4,7 +4,7 @@ * Catalog routines used by pg_dump; long ago these were shared * by another dump tool, but not anymore. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -68,6 +68,8 @@ static int numextmembers; static void flagInhTables(TableInfo *tbinfo, int numTables, InhInfo *inhinfo, int numInherits); +static void flagPartitions(TableInfo *tblinfo, int numTables, + PartInfo *partinfo, int numPartitions); static void flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables); static DumpableObject **buildIndexArray(void *objArray, int numObjs, Size objSize); @@ -75,6 +77,8 @@ static int DOCatalogIdCompare(const void *p1, const void *p2); static int ExtensionMemberIdCompare(const void *p1, const void *p2); static void findParentsByOid(TableInfo *self, InhInfo *inhinfo, int numInherits); +static void findPartitionParentByOid(TableInfo *self, PartInfo *partinfo, + int numPartitions); static int strInArray(const char *pattern, char **arr, int arr_size); @@ -93,8 +97,10 @@ getSchemaData(Archive *fout, int *numTablesPtr) NamespaceInfo *nspinfo; ExtensionInfo *extinfo; InhInfo *inhinfo; + PartInfo *partinfo; int numAggregates; int numInherits; + int numPartitions; int numRules; int numProcLangs; int numCasts; @@ -231,6 +237,10 @@ getSchemaData(Archive *fout, int *numTablesPtr) write_msg(NULL, "reading table inheritance information\n"); inhinfo = getInherits(fout, &numInherits); + if (g_verbose) + write_msg(NULL, "reading partition information\n"); + partinfo = getPartitions(fout, &numPartitions); + if (g_verbose) write_msg(NULL, "reading event triggers\n"); getEventTriggers(fout, &numEventTriggers); @@ -245,6 +255,11 @@ getSchemaData(Archive *fout, int *numTablesPtr) write_msg(NULL, "finding inheritance relationships\n"); flagInhTables(tblinfo, numTables, inhinfo, numInherits); + /* Link tables to partition parents, mark parents as interesting */ + if (g_verbose) + write_msg(NULL, "finding partition relationships\n"); + flagPartitions(tblinfo, numTables, partinfo, numPartitions); + if (g_verbose) write_msg(NULL, "reading column info for interesting tables\n"); getTableAttrs(fout, tblinfo, numTables); @@ -273,6 +288,22 @@ getSchemaData(Archive *fout, int *numTablesPtr) write_msg(NULL, "reading policies\n"); getPolicies(fout, tblinfo, numTables); + if (g_verbose) + write_msg(NULL, "reading partition key information for interesting tables\n"); + getTablePartitionKeyInfo(fout, tblinfo, numTables); + + if (g_verbose) + write_msg(NULL, "reading publications\n"); + getPublications(fout); + + if (g_verbose) + write_msg(NULL, "reading publication membership\n"); + getPublicationTables(fout, tblinfo, numTables); + + if (g_verbose) + write_msg(NULL, "reading subscriptions\n"); + getSubscriptions(fout); + *numTablesPtr = numTables; return tblinfo; } @@ -319,6 +350,43 @@ flagInhTables(TableInfo *tblinfo, int numTables, } } +/* flagPartitions - + * Fill in parent link fields of every target table that is partition, + * and mark parents of partitions as interesting + * + * modifies tblinfo + */ +static void +flagPartitions(TableInfo *tblinfo, int numTables, + PartInfo *partinfo, int numPartitions) +{ + int i; + + for (i = 0; i < numTables; i++) + { + /* Some kinds are never partitions */ + if (tblinfo[i].relkind == RELKIND_SEQUENCE || + tblinfo[i].relkind == RELKIND_VIEW || + tblinfo[i].relkind == RELKIND_MATVIEW) + continue; + + /* Don't bother computing anything for non-target tables, either */ + if (!tblinfo[i].dobj.dump) + continue; + + /* Find the parent TableInfo and save */ + findPartitionParentByOid(&tblinfo[i], partinfo, numPartitions); + + /* Mark the parent as interesting for getTableAttrs */ + if (tblinfo[i].partitionOf) + { + tblinfo[i].partitionOf->interesting = true; + addObjectDependency(&tblinfo[i].dobj, + tblinfo[i].partitionOf->dobj.dumpId); + } + } +} + /* flagInhAttrs - * for each dumpable table in tblinfo, flag its inherited attributes * @@ -919,6 +987,40 @@ findParentsByOid(TableInfo *self, self->parents = NULL; } +/* + * findPartitionParentByOid + * find a partition's parent in tblinfo[] + */ +static void +findPartitionParentByOid(TableInfo *self, PartInfo *partinfo, + int numPartitions) +{ + Oid oid = self->dobj.catId.oid; + int i; + + for (i = 0; i < numPartitions; i++) + { + if (partinfo[i].partrelid == oid) + { + TableInfo *parent; + + parent = findTableByOid(partinfo[i].partparent); + if (parent == NULL) + { + write_msg(NULL, "failed sanity check, parent OID %u of table \"%s\" (OID %u) not found\n", + partinfo[i].partparent, + self->dobj.name, + oid); + exit_nicely(1); + } + self->partitionOf = parent; + + /* While we're at it, also save the partdef */ + self->partitiondef = partinfo[i].partdef; + } + } +} + /* * parseOidArray * parse a string of numbers delimited by spaces into a character array diff --git a/src/bin/pg_dump/compress_io.c b/src/bin/pg_dump/compress_io.c index e0ef9cd60a..631fa337e6 100644 --- a/src/bin/pg_dump/compress_io.c +++ b/src/bin/pg_dump/compress_io.c @@ -4,7 +4,7 @@ * Routines for archivers to write an uncompressed or compressed data * stream. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * This file includes two APIs for dealing with compressed data. The first diff --git a/src/bin/pg_dump/compress_io.h b/src/bin/pg_dump/compress_io.h index 2a45600943..8f2e752cba 100644 --- a/src/bin/pg_dump/compress_io.h +++ b/src/bin/pg_dump/compress_io.h @@ -3,7 +3,7 @@ * compress_io.h * Interface to compress_io.c routines * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c index cd1e8c4a68..81ec650e5c 100644 --- a/src/bin/pg_dump/dumputils.c +++ b/src/bin/pg_dump/dumputils.c @@ -5,7 +5,7 @@ * Basically this is stuff that is useful in both pg_dump and pg_dumpall. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/pg_dump/dumputils.c @@ -18,8 +18,6 @@ #include "fe_utils/string_utils.h" -#define supports_grant_options(version) ((version) >= 70400) - static bool parseAclItem(const char *item, const char *type, const char *name, const char *subname, int remoteVersion, PQExpBuffer grantee, PQExpBuffer grantor, @@ -246,11 +244,9 @@ buildACLCommands(const char *name, const char *subname, /* * For the owner, the default privilege level is ALL WITH - * GRANT OPTION (only ALL prior to 7.4). + * GRANT OPTION. */ - if (supports_grant_options(remoteVersion) - ? strcmp(privswgo->data, "ALL") != 0 - : strcmp(privs->data, "ALL") != 0) + if (strcmp(privswgo->data, "ALL") != 0) { appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix); if (subname) @@ -403,16 +399,19 @@ buildDefaultACLCommands(const char *type, const char *nspname, * username=privilegecodes/grantor * or * group groupname=privilegecodes/grantor - * (the /grantor part will not be present if pre-7.4 database). + * (the "group" case occurs only with servers before 8.1). + * + * Returns true on success, false on parse error. On success, the components + * of the string are returned in the PQExpBuffer parameters. * * The returned grantee string will be the dequoted username or groupname - * (preceded with "group " in the latter case). The returned grantor is - * the dequoted grantor name or empty. Privilege characters are decoded - * and split between privileges with grant option (privswgo) and without - * (privs). + * (preceded with "group " in the latter case). Note that a grant to PUBLIC + * is represented by an empty grantee string. The returned grantor is the + * dequoted grantor name. Privilege characters are decoded and split between + * privileges with grant option (privswgo) and without (privs). * - * Note: for cross-version compatibility, it's important to use ALL when - * appropriate. + * Note: for cross-version compatibility, it's important to use ALL to + * represent the privilege sets whenever appropriate. */ static bool parseAclItem(const char *item, const char *type, @@ -439,7 +438,7 @@ parseAclItem(const char *item, const char *type, return false; } - /* grantor may be listed after / */ + /* grantor should appear after / */ slpos = strchr(eqpos + 1, '/'); if (slpos) { @@ -452,7 +451,10 @@ parseAclItem(const char *item, const char *type, } } else - resetPQExpBuffer(grantor); + { + free(buf); + return false; + } /* privilege codes */ #define CONVERT_PRIV(code, keywd) \ @@ -490,29 +492,19 @@ do { \ { /* table only */ CONVERT_PRIV('a', "INSERT"); - if (remoteVersion >= 70200) - CONVERT_PRIV('x', "REFERENCES"); + CONVERT_PRIV('x', "REFERENCES"); /* rest are not applicable to columns */ if (subname == NULL) { - if (remoteVersion >= 70200) - { - CONVERT_PRIV('d', "DELETE"); - CONVERT_PRIV('t', "TRIGGER"); - } + CONVERT_PRIV('d', "DELETE"); + CONVERT_PRIV('t', "TRIGGER"); if (remoteVersion >= 80400) CONVERT_PRIV('D', "TRUNCATE"); } } /* UPDATE */ - if (remoteVersion >= 70200 || - strcmp(type, "SEQUENCE") == 0 || - strcmp(type, "SEQUENCES") == 0) - CONVERT_PRIV('w', "UPDATE"); - else - /* 7.0 and 7.1 have a simpler worldview */ - CONVERT_PRIV('w', "UPDATE,DELETE"); + CONVERT_PRIV('w', "UPDATE"); } else if (strcmp(type, "FUNCTION") == 0 || strcmp(type, "FUNCTIONS") == 0) diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h index b2fd7d37d0..ba61fa9bd2 100644 --- a/src/bin/pg_dump/dumputils.h +++ b/src/bin/pg_dump/dumputils.h @@ -5,7 +5,7 @@ * Basically this is stuff that is useful in both pg_dump and pg_dumpall. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/pg_dump/dumputils.h diff --git a/src/bin/pg_dump/parallel.c b/src/bin/pg_dump/parallel.c index 4549d11e20..775a7f858c 100644 --- a/src/bin/pg_dump/parallel.c +++ b/src/bin/pg_dump/parallel.c @@ -4,7 +4,7 @@ * * Parallel support for pg_dump and pg_restore * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -20,45 +20,41 @@ * the desired number of worker processes, which each enter WaitForCommands(). * * The master process dispatches an individual work item to one of the worker - * processes in DispatchJobForTocEntry(). That calls - * AH->MasterStartParallelItemPtr, a routine of the output format. This - * function's arguments are the parents archive handle AH (containing the full - * catalog information), the TocEntry that the worker should work on and a - * T_Action value indicating whether this is a backup or a restore task. The - * function simply converts the TocEntry assignment into a command string that - * is then sent over to the worker process. In the simplest case that would be - * something like "DUMP 1234", with 1234 being the TocEntry id. - * + * processes in DispatchJobForTocEntry(). We send a command string such as + * "DUMP 1234" or "RESTORE 1234", where 1234 is the TocEntry ID. * The worker process receives and decodes the command and passes it to the * routine pointed to by AH->WorkerJobDumpPtr or AH->WorkerJobRestorePtr, * which are routines of the current archive format. That routine performs - * the required action (dump or restore) and returns a malloc'd status string. - * The status string is passed back to the master where it is interpreted by - * AH->MasterEndParallelItemPtr, another format-specific routine. That - * function can update state or catalog information on the master's side, - * depending on the reply from the worker process. In the end it returns a - * status code, which is 0 for successful execution. + * the required action (dump or restore) and returns an integer status code. + * This is passed back to the master where we pass it to the + * ParallelCompletionPtr callback function that was passed to + * DispatchJobForTocEntry(). The callback function does state updating + * for the master control logic in pg_backup_archiver.c. * - * Remember that we have forked off the workers only after we have read in - * the catalog. That's why our worker processes can also access the catalog - * information. (In the Windows case, the workers are threads in the same - * process. To avoid problems, they work with cloned copies of the Archive - * data structure; see RunWorker().) + * In principle additional archive-format-specific information might be needed + * in commands or worker status responses, but so far that hasn't proved + * necessary, since workers have full copies of the ArchiveHandle/TocEntry + * data structures. Remember that we have forked off the workers only after + * we have read in the catalog. That's why our worker processes can also + * access the catalog information. (In the Windows case, the workers are + * threads in the same process. To avoid problems, they work with cloned + * copies of the Archive data structure; see RunWorker().) * * In the master process, the workerStatus field for each worker has one of * the following values: * WRKR_IDLE: it's waiting for a command - * WRKR_WORKING: it's been sent a command - * WRKR_FINISHED: it's returned a result + * WRKR_WORKING: it's working on a command * WRKR_TERMINATED: process ended - * The FINISHED state indicates that the worker is idle, but we've not yet - * dealt with the status code it returned from the prior command. - * ReapWorkerStatus() extracts the unhandled command status value and sets - * the workerStatus back to WRKR_IDLE. + * The pstate->te[] entry for each worker is valid when it's in WRKR_WORKING + * state, and must be NULL in other states. */ #include "postgres_fe.h" +#ifdef HAVE_SYS_SELECT_H +#include +#endif + #include "parallel.h" #include "pg_backup_utils.h" #include "fe_utils/string_utils.h" @@ -75,6 +71,47 @@ #define PIPE_READ 0 #define PIPE_WRITE 1 +#define NO_SLOT (-1) /* Failure result for GetIdleWorker() */ + +/* Worker process statuses */ +typedef enum +{ + WRKR_IDLE, + WRKR_WORKING, + WRKR_TERMINATED +} T_WorkerStatus; + +/* + * Private per-parallel-worker state (typedef for this is in parallel.h). + * + * Much of this is valid only in the master process (or, on Windows, should + * be touched only by the master thread). But the AH field should be touched + * only by workers. The pipe descriptors are valid everywhere. + */ +struct ParallelSlot +{ + T_WorkerStatus workerStatus; /* see enum above */ + + /* These fields are valid if workerStatus == WRKR_WORKING: */ + ParallelCompletionPtr callback; /* function to call on completion */ + void *callback_data; /* passthru data for it */ + + ArchiveHandle *AH; /* Archive data worker is using */ + + int pipeRead; /* master's end of the pipes */ + int pipeWrite; + int pipeRevRead; /* child's end of the pipes */ + int pipeRevWrite; + + /* Child process/thread identity info: */ +#ifdef WIN32 + uintptr_t hThread; + unsigned int threadId; +#else + pid_t pid; +#endif +}; + #ifdef WIN32 /* @@ -171,9 +208,12 @@ static void setup_cancel_handler(void); static void set_cancel_pstate(ParallelState *pstate); static void set_cancel_slot_archive(ParallelSlot *slot, ArchiveHandle *AH); static void RunWorker(ArchiveHandle *AH, ParallelSlot *slot); +static int GetIdleWorker(ParallelState *pstate); static bool HasEveryWorkerTerminated(ParallelState *pstate); static void lockTableForWorker(ArchiveHandle *AH, TocEntry *te); static void WaitForCommands(ArchiveHandle *AH, int pipefd[2]); +static bool ListenToWorkers(ArchiveHandle *AH, ParallelState *pstate, + bool do_wait); static char *getMessageFromMaster(int pipefd[2]); static void sendMessageToMaster(int pipefd[2], const char *str); static int select_loop(int maxFd, fd_set *workerset); @@ -345,8 +385,8 @@ archive_close_connection(int code, void *arg) * fail to detect it because there would be no EOF condition on * the other end of the pipe.) */ - if (slot->args->AH) - DisconnectDatabase(&(slot->args->AH->public)); + if (slot->AH) + DisconnectDatabase(&(slot->AH->public)); #ifdef WIN32 closesocket(slot->pipeRevRead); @@ -403,7 +443,7 @@ ShutdownWorkersHard(ParallelState *pstate) EnterCriticalSection(&signal_info_lock); for (i = 0; i < pstate->numWorkers; i++) { - ArchiveHandle *AH = pstate->parallelSlot[i].args->AH; + ArchiveHandle *AH = pstate->parallelSlot[i].AH; char errbuf[1]; if (AH != NULL && AH->connCancel != NULL) @@ -476,9 +516,10 @@ WaitForTerminatingWorkers(ParallelState *pstate) } #endif /* WIN32 */ - /* On all platforms, update workerStatus as well */ + /* On all platforms, update workerStatus and te[] as well */ Assert(j < pstate->numWorkers); slot->workerStatus = WRKR_TERMINATED; + pstate->te[j] = NULL; } } @@ -630,7 +671,7 @@ consoleHandler(DWORD dwCtrlType) for (i = 0; i < signal_info.pstate->numWorkers; i++) { ParallelSlot *slot = &(signal_info.pstate->parallelSlot[i]); - ArchiveHandle *AH = slot->args->AH; + ArchiveHandle *AH = slot->AH; HANDLE hThread = (HANDLE) slot->hThread; /* @@ -785,7 +826,7 @@ set_cancel_slot_archive(ParallelSlot *slot, ArchiveHandle *AH) EnterCriticalSection(&signal_info_lock); #endif - slot->args->AH = AH; + slot->AH = AH; #ifdef WIN32 LeaveCriticalSection(&signal_info_lock); @@ -871,20 +912,22 @@ ParallelBackupStart(ArchiveHandle *AH) { ParallelState *pstate; int i; - const size_t slotSize = AH->public.numWorkers * sizeof(ParallelSlot); Assert(AH->public.numWorkers > 0); pstate = (ParallelState *) pg_malloc(sizeof(ParallelState)); pstate->numWorkers = AH->public.numWorkers; + pstate->te = NULL; pstate->parallelSlot = NULL; if (AH->public.numWorkers == 1) return pstate; - pstate->parallelSlot = (ParallelSlot *) pg_malloc(slotSize); - memset((void *) pstate->parallelSlot, 0, slotSize); + pstate->te = (TocEntry **) + pg_malloc0(pstate->numWorkers * sizeof(TocEntry *)); + pstate->parallelSlot = (ParallelSlot *) + pg_malloc0(pstate->numWorkers * sizeof(ParallelSlot)); #ifdef WIN32 /* Make fmtId() and fmtQualifiedId() use thread-local storage */ @@ -930,10 +973,12 @@ ParallelBackupStart(ArchiveHandle *AH) "could not create communication channels: %s\n", strerror(errno)); + pstate->te[i] = NULL; /* just for safety */ + slot->workerStatus = WRKR_IDLE; - slot->args = (ParallelArgs *) pg_malloc(sizeof(ParallelArgs)); - slot->args->AH = NULL; - slot->args->te = NULL; + slot->AH = NULL; + slot->callback = NULL; + slot->callback_data = NULL; /* master's ends of the pipes */ slot->pipeRead = pipeWM[PIPE_READ]; @@ -1062,43 +1107,156 @@ ParallelBackupEnd(ArchiveHandle *AH, ParallelState *pstate) set_cancel_pstate(NULL); /* Release state (mere neatnik-ism, since we're about to terminate) */ + free(pstate->te); free(pstate->parallelSlot); free(pstate); } /* - * Dispatch a job to some free worker (caller must ensure there is one!) + * These next four functions handle construction and parsing of the command + * strings and response strings for parallel workers. + * + * Currently, these can be the same regardless of which archive format we are + * processing. In future, we might want to let format modules override these + * functions to add format-specific data to a command or response. + */ + +/* + * buildWorkerCommand: format a command string to send to a worker. + * + * The string is built in the caller-supplied buffer of size buflen. + */ +static void +buildWorkerCommand(ArchiveHandle *AH, TocEntry *te, T_Action act, + char *buf, int buflen) +{ + if (act == ACT_DUMP) + snprintf(buf, buflen, "DUMP %d", te->dumpId); + else if (act == ACT_RESTORE) + snprintf(buf, buflen, "RESTORE %d", te->dumpId); + else + Assert(false); +} + +/* + * parseWorkerCommand: interpret a command string in a worker. + */ +static void +parseWorkerCommand(ArchiveHandle *AH, TocEntry **te, T_Action *act, + const char *msg) +{ + DumpId dumpId; + int nBytes; + + if (messageStartsWith(msg, "DUMP ")) + { + *act = ACT_DUMP; + sscanf(msg, "DUMP %d%n", &dumpId, &nBytes); + Assert(nBytes == strlen(msg)); + *te = getTocEntryByDumpId(AH, dumpId); + Assert(*te != NULL); + } + else if (messageStartsWith(msg, "RESTORE ")) + { + *act = ACT_RESTORE; + sscanf(msg, "RESTORE %d%n", &dumpId, &nBytes); + Assert(nBytes == strlen(msg)); + *te = getTocEntryByDumpId(AH, dumpId); + Assert(*te != NULL); + } + else + exit_horribly(modulename, + "unrecognized command received from master: \"%s\"\n", + msg); +} + +/* + * buildWorkerResponse: format a response string to send to the master. + * + * The string is built in the caller-supplied buffer of size buflen. + */ +static void +buildWorkerResponse(ArchiveHandle *AH, TocEntry *te, T_Action act, int status, + char *buf, int buflen) +{ + snprintf(buf, buflen, "OK %d %d %d", + te->dumpId, + status, + status == WORKER_IGNORED_ERRORS ? AH->public.n_errors : 0); +} + +/* + * parseWorkerResponse: parse the status message returned by a worker. + * + * Returns the integer status code, and may update fields of AH and/or te. + */ +static int +parseWorkerResponse(ArchiveHandle *AH, TocEntry *te, + const char *msg) +{ + DumpId dumpId; + int nBytes, + n_errors; + int status = 0; + + if (messageStartsWith(msg, "OK ")) + { + sscanf(msg, "OK %d %d %d%n", &dumpId, &status, &n_errors, &nBytes); + + Assert(dumpId == te->dumpId); + Assert(nBytes == strlen(msg)); + + AH->public.n_errors += n_errors; + } + else + exit_horribly(modulename, + "invalid message received from worker: \"%s\"\n", + msg); + + return status; +} + +/* + * Dispatch a job to some free worker. * * te is the TocEntry to be processed, act is the action to be taken on it. + * callback is the function to call on completion of the job. + * + * If no worker is currently available, this will block, and previously + * registered callback functions may be called. */ void -DispatchJobForTocEntry(ArchiveHandle *AH, ParallelState *pstate, TocEntry *te, - T_Action act) +DispatchJobForTocEntry(ArchiveHandle *AH, + ParallelState *pstate, + TocEntry *te, + T_Action act, + ParallelCompletionPtr callback, + void *callback_data) { int worker; - char *arg; + char buf[256]; - /* our caller makes sure that at least one worker is idle */ - worker = GetIdleWorker(pstate); - Assert(worker != NO_SLOT); + /* Get a worker, waiting if none are idle */ + while ((worker = GetIdleWorker(pstate)) == NO_SLOT) + WaitForWorkers(AH, pstate, WFW_ONE_IDLE); /* Construct and send command string */ - arg = (AH->MasterStartParallelItemPtr) (AH, te, act); - - sendMessageToWorker(pstate, worker, arg); + buildWorkerCommand(AH, te, act, buf, sizeof(buf)); - /* XXX aren't we leaking string here? (no, because it's static. Ick.) */ + sendMessageToWorker(pstate, worker, buf); /* Remember worker is busy, and which TocEntry it's working on */ pstate->parallelSlot[worker].workerStatus = WRKR_WORKING; - pstate->parallelSlot[worker].args->te = te; + pstate->parallelSlot[worker].callback = callback; + pstate->parallelSlot[worker].callback_data = callback_data; + pstate->te[worker] = te; } /* * Find an idle worker and return its slot number. * Return NO_SLOT if none are idle. */ -int +static int GetIdleWorker(ParallelState *pstate) { int i; @@ -1203,10 +1361,10 @@ static void WaitForCommands(ArchiveHandle *AH, int pipefd[2]) { char *command; - DumpId dumpId; - int nBytes; - char *str; TocEntry *te; + T_Action act; + int status = 0; + char buf[256]; for (;;) { @@ -1216,47 +1374,29 @@ WaitForCommands(ArchiveHandle *AH, int pipefd[2]) return; } - if (messageStartsWith(command, "DUMP ")) - { - /* Decode the command */ - sscanf(command + strlen("DUMP "), "%d%n", &dumpId, &nBytes); - Assert(nBytes == strlen(command) - strlen("DUMP ")); - te = getTocEntryByDumpId(AH, dumpId); - Assert(te != NULL); + /* Decode the command */ + parseWorkerCommand(AH, &te, &act, command); + if (act == ACT_DUMP) + { /* Acquire lock on this table within the worker's session */ lockTableForWorker(AH, te); /* Perform the dump command */ - str = (AH->WorkerJobDumpPtr) (AH, te); - - /* Return status to master */ - sendMessageToMaster(pipefd, str); - - /* we are responsible for freeing the status string */ - free(str); + status = (AH->WorkerJobDumpPtr) (AH, te); } - else if (messageStartsWith(command, "RESTORE ")) + else if (act == ACT_RESTORE) { - /* Decode the command */ - sscanf(command + strlen("RESTORE "), "%d%n", &dumpId, &nBytes); - Assert(nBytes == strlen(command) - strlen("RESTORE ")); - te = getTocEntryByDumpId(AH, dumpId); - Assert(te != NULL); - /* Perform the restore command */ - str = (AH->WorkerJobRestorePtr) (AH, te); - - /* Return status to master */ - sendMessageToMaster(pipefd, str); - - /* we are responsible for freeing the status string */ - free(str); + status = (AH->WorkerJobRestorePtr) (AH, te); } else - exit_horribly(modulename, - "unrecognized command received from master: \"%s\"\n", - command); + Assert(false); + + /* Return status to master */ + buildWorkerResponse(AH, te, act, status, buf, sizeof(buf)); + + sendMessageToMaster(pipefd, buf); /* command was pg_malloc'd and we are responsible for free()ing it. */ free(command); @@ -1269,18 +1409,17 @@ WaitForCommands(ArchiveHandle *AH, int pipefd[2]) * If do_wait is true, wait to get a status message; otherwise, just return * immediately if there is none available. * - * When we get a status message, we let MasterEndParallelItemPtr process it, - * then save the resulting status code and switch the worker's state to - * WRKR_FINISHED. Later, caller must call ReapWorkerStatus() to verify - * that the status was "OK" and push the worker back to IDLE state. + * When we get a status message, we pass the status code to the callback + * function that was specified to DispatchJobForTocEntry, then reset the + * worker status to IDLE. * - * XXX Rube Goldberg would be proud of this API, but no one else should be. + * Returns true if we collected a status message, else false. * * XXX is it worth checking for more than one status message per call? * It seems somewhat unlikely that multiple workers would finish at exactly * the same time. */ -void +static bool ListenToWorkers(ArchiveHandle *AH, ParallelState *pstate, bool do_wait) { int worker; @@ -1294,34 +1433,20 @@ ListenToWorkers(ArchiveHandle *AH, ParallelState *pstate, bool do_wait) /* If do_wait is true, we must have detected EOF on some socket */ if (do_wait) exit_horribly(modulename, "a worker process died unexpectedly\n"); - return; + return false; } /* Process it and update our idea of the worker's status */ if (messageStartsWith(msg, "OK ")) { - TocEntry *te = pstate->parallelSlot[worker].args->te; - char *statusString; + ParallelSlot *slot = &pstate->parallelSlot[worker]; + TocEntry *te = pstate->te[worker]; + int status; - if (messageStartsWith(msg, "OK RESTORE ")) - { - statusString = msg + strlen("OK RESTORE "); - pstate->parallelSlot[worker].status = - (AH->MasterEndParallelItemPtr) - (AH, te, statusString, ACT_RESTORE); - } - else if (messageStartsWith(msg, "OK DUMP ")) - { - statusString = msg + strlen("OK DUMP "); - pstate->parallelSlot[worker].status = - (AH->MasterEndParallelItemPtr) - (AH, te, statusString, ACT_DUMP); - } - else - exit_horribly(modulename, - "invalid message received from worker: \"%s\"\n", - msg); - pstate->parallelSlot[worker].workerStatus = WRKR_FINISHED; + status = parseWorkerResponse(AH, te, msg); + slot->callback(AH, te, status, slot->callback_data); + slot->workerStatus = WRKR_IDLE; + pstate->te[worker] = NULL; } else exit_horribly(modulename, @@ -1330,110 +1455,79 @@ ListenToWorkers(ArchiveHandle *AH, ParallelState *pstate, bool do_wait) /* Free the string returned from getMessageFromWorker */ free(msg); -} - -/* - * Check to see if any worker is in WRKR_FINISHED state. If so, - * return its command status code into *status, reset it to IDLE state, - * and return its slot number. Otherwise return NO_SLOT. - * - * This function is executed in the master process. - */ -int -ReapWorkerStatus(ParallelState *pstate, int *status) -{ - int i; - for (i = 0; i < pstate->numWorkers; i++) - { - if (pstate->parallelSlot[i].workerStatus == WRKR_FINISHED) - { - *status = pstate->parallelSlot[i].status; - pstate->parallelSlot[i].status = 0; - pstate->parallelSlot[i].workerStatus = WRKR_IDLE; - return i; - } - } - return NO_SLOT; + return true; } /* - * Wait, if necessary, until we have at least one idle worker. - * Reap worker status as necessary to move FINISHED workers to IDLE state. + * Check for status results from workers, waiting if necessary. + * + * Available wait modes are: + * WFW_NO_WAIT: reap any available status, but don't block + * WFW_GOT_STATUS: wait for at least one more worker to finish + * WFW_ONE_IDLE: wait for at least one worker to be idle + * WFW_ALL_IDLE: wait for all workers to be idle * - * We assume that no extra processing is required when reaping a finished - * command, except for checking that the status was OK (zero). - * Caution: that assumption means that this function can only be used in - * parallel dump, not parallel restore, because the latter has a more - * complex set of rules about handling status. + * Any received results are passed to the callback specified to + * DispatchJobForTocEntry. * * This function is executed in the master process. */ void -EnsureIdleWorker(ArchiveHandle *AH, ParallelState *pstate) +WaitForWorkers(ArchiveHandle *AH, ParallelState *pstate, WFW_WaitOption mode) { - int ret_worker; - int work_status; + bool do_wait = false; - for (;;) + /* + * In GOT_STATUS mode, always block waiting for a message, since we can't + * return till we get something. In other modes, we don't block the first + * time through the loop. + */ + if (mode == WFW_GOT_STATUS) { - int nTerm = 0; - - while ((ret_worker = ReapWorkerStatus(pstate, &work_status)) != NO_SLOT) - { - if (work_status != 0) - exit_horribly(modulename, "error processing a parallel work item\n"); - - nTerm++; - } - - /* - * We need to make sure that we have an idle worker before dispatching - * the next item. If nTerm > 0 we already have that (quick check). - */ - if (nTerm > 0) - return; - - /* explicit check for an idle worker */ - if (GetIdleWorker(pstate) != NO_SLOT) - return; + /* Assert that caller knows what it's doing */ + Assert(!IsEveryWorkerIdle(pstate)); + do_wait = true; + } + for (;;) + { /* - * If we have no idle worker, read the result of one or more workers - * and loop the loop to call ReapWorkerStatus() on them + * Check for status messages, even if we don't need to block. We do + * not try very hard to reap all available messages, though, since + * there's unlikely to be more than one. */ - ListenToWorkers(AH, pstate, true); - } -} - -/* - * Wait for all workers to be idle. - * Reap worker status as necessary to move FINISHED workers to IDLE state. - * - * We assume that no extra processing is required when reaping a finished - * command, except for checking that the status was OK (zero). - * Caution: that assumption means that this function can only be used in - * parallel dump, not parallel restore, because the latter has a more - * complex set of rules about handling status. - * - * This function is executed in the master process. - */ -void -EnsureWorkersFinished(ArchiveHandle *AH, ParallelState *pstate) -{ - int work_status; + if (ListenToWorkers(AH, pstate, do_wait)) + { + /* + * If we got a message, we are done by definition for GOT_STATUS + * mode, and we can also be certain that there's at least one idle + * worker. So we're done in all but ALL_IDLE mode. + */ + if (mode != WFW_ALL_IDLE) + return; + } - if (!pstate || pstate->numWorkers == 1) - return; + /* Check whether we must wait for new status messages */ + switch (mode) + { + case WFW_NO_WAIT: + return; /* never wait */ + case WFW_GOT_STATUS: + Assert(false); /* can't get here, because we waited */ + break; + case WFW_ONE_IDLE: + if (GetIdleWorker(pstate) != NO_SLOT) + return; + break; + case WFW_ALL_IDLE: + if (IsEveryWorkerIdle(pstate)) + return; + break; + } - /* Waiting for the remaining worker processes to finish */ - while (!IsEveryWorkerIdle(pstate)) - { - if (ReapWorkerStatus(pstate, &work_status) == NO_SLOT) - ListenToWorkers(AH, pstate, true); - else if (work_status != 0) - exit_horribly(modulename, - "error processing a parallel work item\n"); + /* Loop back, and this time wait for something to happen */ + do_wait = true; } } diff --git a/src/bin/pg_dump/parallel.h b/src/bin/pg_dump/parallel.h index 21739ca87c..ad99735226 100644 --- a/src/bin/pg_dump/parallel.h +++ b/src/bin/pg_dump/parallel.h @@ -2,14 +2,11 @@ * * parallel.h * - * Parallel support header file for the pg_dump archiver + * Parallel support for pg_dump and pg_restore * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * The author is not responsible for loss or damages that may - * result from its use. - * * IDENTIFICATION * src/bin/pg_dump/parallel.h * @@ -21,45 +18,31 @@ #include "pg_backup_archiver.h" -typedef enum -{ - WRKR_TERMINATED = 0, - WRKR_IDLE, - WRKR_WORKING, - WRKR_FINISHED -} T_WorkerStatus; - -/* Arguments needed for a worker process */ -typedef struct ParallelArgs -{ - ArchiveHandle *AH; - TocEntry *te; -} ParallelArgs; +/* Function to call in master process on completion of a worker task */ +typedef void (*ParallelCompletionPtr) (ArchiveHandle *AH, + TocEntry *te, + int status, + void *callback_data); -/* State for each parallel activity slot */ -typedef struct ParallelSlot +/* Wait options for WaitForWorkers */ +typedef enum { - ParallelArgs *args; - T_WorkerStatus workerStatus; - int status; - int pipeRead; /* master's end of the pipes */ - int pipeWrite; - int pipeRevRead; /* child's end of the pipes */ - int pipeRevWrite; -#ifdef WIN32 - uintptr_t hThread; - unsigned int threadId; -#else - pid_t pid; -#endif -} ParallelSlot; + WFW_NO_WAIT, + WFW_GOT_STATUS, + WFW_ONE_IDLE, + WFW_ALL_IDLE +} WFW_WaitOption; -#define NO_SLOT (-1) +/* ParallelSlot is an opaque struct known only within parallel.c */ +typedef struct ParallelSlot ParallelSlot; +/* Overall state for parallel.c */ typedef struct ParallelState { - int numWorkers; - ParallelSlot *parallelSlot; + int numWorkers; /* allowed number of workers */ + /* these arrays have numWorkers entries, one per worker: */ + TocEntry **te; /* item being worked on, or NULL */ + ParallelSlot *parallelSlot; /* private info about each worker */ } ParallelState; #ifdef WIN32 @@ -69,17 +52,17 @@ extern DWORD mainThreadId; extern void init_parallel_dump_utils(void); -extern int GetIdleWorker(ParallelState *pstate); extern bool IsEveryWorkerIdle(ParallelState *pstate); -extern void ListenToWorkers(ArchiveHandle *AH, ParallelState *pstate, bool do_wait); -extern int ReapWorkerStatus(ParallelState *pstate, int *status); -extern void EnsureIdleWorker(ArchiveHandle *AH, ParallelState *pstate); -extern void EnsureWorkersFinished(ArchiveHandle *AH, ParallelState *pstate); +extern void WaitForWorkers(ArchiveHandle *AH, ParallelState *pstate, + WFW_WaitOption mode); extern ParallelState *ParallelBackupStart(ArchiveHandle *AH); extern void DispatchJobForTocEntry(ArchiveHandle *AH, ParallelState *pstate, - TocEntry *te, T_Action act); + TocEntry *te, + T_Action act, + ParallelCompletionPtr callback, + void *callback_data); extern void ParallelBackupEnd(ArchiveHandle *AH, ParallelState *pstate); extern void set_archive_cancel_info(ArchiveHandle *AH, PGconn *conn); diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h index 4afa92f5f6..6480fb8e74 100644 --- a/src/bin/pg_dump/pg_backup.h +++ b/src/bin/pg_dump/pg_backup.h @@ -99,6 +99,7 @@ typedef struct _restoreOptions SimpleStringList indexNames; SimpleStringList functionNames; SimpleStringList schemaNames; + SimpleStringList schemaExcludeNames; SimpleStringList triggerNames; SimpleStringList tableNames; @@ -117,6 +118,8 @@ typedef struct _restoreOptions bool *idWanted; /* array showing which dump IDs to emit */ int enable_row_security; + int sequence_data; /* dump sequence data even in schema-only mode */ + int include_subscriptions; } RestoreOptions; typedef struct _dumpOptions @@ -150,6 +153,8 @@ typedef struct _dumpOptions int outputNoTablespaces; int use_setsessauth; int enable_row_security; + int include_subscriptions; + int no_create_subscription_slots; /* default, if no "inclusion" switches appear, is to dump everything */ bool include_everything; @@ -157,8 +162,11 @@ typedef struct _dumpOptions int outputClean; int outputCreateDB; bool outputBlobs; + bool dontOutputBlobs; int outputNoOwner; char *outputSuperuser; + + int sequence_data; /* dump sequence data even in schema-only mode */ } DumpOptions; /* diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c index 05bdbdbf02..929f1b592b 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -97,9 +97,14 @@ static void par_list_remove(TocEntry *te); static TocEntry *get_next_work_item(ArchiveHandle *AH, TocEntry *ready_list, ParallelState *pstate); -static void mark_work_done(ArchiveHandle *AH, TocEntry *ready_list, - int worker, int status, - ParallelState *pstate); +static void mark_dump_job_done(ArchiveHandle *AH, + TocEntry *te, + int status, + void *callback_data); +static void mark_restore_job_done(ArchiveHandle *AH, + TocEntry *te, + int status, + void *callback_data); static void fix_dependencies(ArchiveHandle *AH); static bool has_lock_conflicts(TocEntry *te1, TocEntry *te2); static void repoint_table_dependencies(ArchiveHandle *AH); @@ -166,6 +171,8 @@ dumpOptionsFromRestoreOptions(RestoreOptions *ropt) dopt->lockWaitTimeout = ropt->lockWaitTimeout; dopt->include_everything = ropt->include_everything; dopt->enable_row_security = ropt->enable_row_security; + dopt->sequence_data = ropt->sequence_data; + dopt->include_subscriptions = ropt->include_subscriptions; return dopt; } @@ -383,7 +390,7 @@ RestoreArchive(Archive *AHX) * target. */ AHX->minRemoteVersion = 0; - AHX->maxRemoteVersion = 999999; + AHX->maxRemoteVersion = 9999999; ConnectDatabase(AHX, ropt->dbname, ropt->pghost, ropt->pgport, ropt->username, @@ -515,7 +522,6 @@ RestoreArchive(Archive *AHX) * knows how to do it, without depending on * te->dropStmt; use that. For other objects we need * to parse the command. - * */ if (strncmp(te->desc, "BLOB", 4) == 0) { @@ -523,10 +529,8 @@ RestoreArchive(Archive *AHX) } else { - char buffer[40]; - char *mark; char *dropStmt = pg_strdup(te->dropStmt); - char *dropStmtPtr = dropStmt; + char *dropStmtOrig = dropStmt; PQExpBuffer ftStmt = createPQExpBuffer(); /* @@ -543,18 +547,28 @@ RestoreArchive(Archive *AHX) /* * ALTER TABLE..ALTER COLUMN..DROP DEFAULT does * not support the IF EXISTS clause, and therefore - * we simply emit the original command for such - * objects. For other objects, we need to extract - * the first part of the DROP which includes the - * object type. Most of the time this matches + * we simply emit the original command for DEFAULT + * objects (modulo the adjustment made above). + * + * If we used CREATE OR REPLACE VIEW as a means of + * quasi-dropping an ON SELECT rule, that should + * be emitted unchanged as well. + * + * For other object types, we need to extract the + * first part of the DROP which includes the + * object type. Most of the time this matches * te->desc, so search for that; however for the * different kinds of CONSTRAINTs, we know to * search for hardcoded "DROP CONSTRAINT" instead. */ - if (strcmp(te->desc, "DEFAULT") == 0) + if (strcmp(te->desc, "DEFAULT") == 0 || + strncmp(dropStmt, "CREATE OR REPLACE VIEW", 22) == 0) appendPQExpBufferStr(ftStmt, dropStmt); else { + char buffer[40]; + char *mark; + if (strcmp(te->desc, "CONSTRAINT") == 0 || strcmp(te->desc, "CHECK CONSTRAINT") == 0 || strcmp(te->desc, "FK CONSTRAINT") == 0) @@ -564,19 +578,28 @@ RestoreArchive(Archive *AHX) te->desc); mark = strstr(dropStmt, buffer); - Assert(mark != NULL); - *mark = '\0'; - appendPQExpBuffer(ftStmt, "%s%s IF EXISTS%s", - dropStmt, buffer, - mark + strlen(buffer)); + if (mark) + { + *mark = '\0'; + appendPQExpBuffer(ftStmt, "%s%s IF EXISTS%s", + dropStmt, buffer, + mark + strlen(buffer)); + } + else + { + /* complain and emit unmodified command */ + write_msg(modulename, + "WARNING: could not find where to insert IF EXISTS in statement \"%s\"\n", + dropStmtOrig); + appendPQExpBufferStr(ftStmt, dropStmt); + } } ahprintf(AH, "%s", ftStmt->data); destroyPQExpBuffer(ftStmt); - - pg_free(dropStmtPtr); + pg_free(dropStmtOrig); } } } @@ -1100,7 +1123,8 @@ PrintTOCSummary(Archive *AHX) fmtName = "UNKNOWN"; } - ahprintf(AH, "; Dump Version: %d.%d-%d\n", AH->vmaj, AH->vmin, AH->vrev); + ahprintf(AH, "; Dump Version: %d.%d-%d\n", + ARCHIVE_MAJOR(AH->version), ARCHIVE_MINOR(AH->version), ARCHIVE_REV(AH->version)); ahprintf(AH, "; Format: %s\n", fmtName); ahprintf(AH, "; Integer: %d bytes\n", (int) AH->intSize); ahprintf(AH, "; Offset: %d bytes\n", (int) AH->offSize); @@ -2101,6 +2125,9 @@ _discoverArchiveFormat(ArchiveHandle *AH) if (strncmp(sig, "PGDMP", 5) == 0) { int byteread; + char vmaj, + vmin, + vrev; /* * Finish reading (most of) a custom-format header. @@ -2110,31 +2137,30 @@ _discoverArchiveFormat(ArchiveHandle *AH) if ((byteread = fgetc(fh)) == EOF) READ_ERROR_EXIT(fh); - AH->vmaj = byteread; + vmaj = byteread; if ((byteread = fgetc(fh)) == EOF) READ_ERROR_EXIT(fh); - AH->vmin = byteread; + vmin = byteread; /* Save these too... */ - AH->lookahead[AH->lookaheadLen++] = AH->vmaj; - AH->lookahead[AH->lookaheadLen++] = AH->vmin; + AH->lookahead[AH->lookaheadLen++] = vmaj; + AH->lookahead[AH->lookaheadLen++] = vmin; /* Check header version; varies from V1.0 */ - if (AH->vmaj > 1 || ((AH->vmaj == 1) && (AH->vmin > 0))) /* Version > 1.0 */ + if (vmaj > 1 || (vmaj == 1 && vmin > 0)) /* Version > 1.0 */ { if ((byteread = fgetc(fh)) == EOF) READ_ERROR_EXIT(fh); - AH->vrev = byteread; - AH->lookahead[AH->lookaheadLen++] = AH->vrev; + vrev = byteread; + AH->lookahead[AH->lookaheadLen++] = vrev; } else - AH->vrev = 0; + vrev = 0; - /* Make a convenient integer 00 */ - AH->version = ((AH->vmaj * 256 + AH->vmin) * 256 + AH->vrev) * 256 + 0; + AH->version = MAKE_ARCHIVE_VERSION(vmaj, vmin, vrev); if ((AH->intSize = fgetc(fh)) == EOF) READ_ERROR_EXIT(fh); @@ -2229,12 +2255,7 @@ _allocAH(const char *FileSpec, const ArchiveFormat fmt, /* AH->debugLevel = 100; */ - AH->vmaj = K_VERS_MAJOR; - AH->vmin = K_VERS_MINOR; - AH->vrev = K_VERS_REV; - - /* Make a convenient integer 00 */ - AH->version = ((AH->vmaj * 256 + AH->vmin) * 256 + AH->vrev) * 256 + 0; + AH->version = K_VERS_SELF; /* initialize for backwards compatible string processing */ AH->public.encoding = 0; /* PG_SQL_ASCII */ @@ -2355,8 +2376,8 @@ WriteDataChunks(ArchiveHandle *AH, ParallelState *pstate) * If we are in a parallel backup, then we are always the master * process. Dispatch each data-transfer job to a worker. */ - EnsureIdleWorker(AH, pstate); - DispatchJobForTocEntry(AH, pstate, te, ACT_DUMP); + DispatchJobForTocEntry(AH, pstate, te, ACT_DUMP, + mark_dump_job_done, NULL); } else WriteDataChunksForTocEntry(AH, te); @@ -2365,9 +2386,32 @@ WriteDataChunks(ArchiveHandle *AH, ParallelState *pstate) /* * If parallel, wait for workers to finish. */ - EnsureWorkersFinished(AH, pstate); + if (pstate && pstate->numWorkers > 1) + WaitForWorkers(AH, pstate, WFW_ALL_IDLE); +} + + +/* + * Callback function that's invoked in the master process after a step has + * been parallel dumped. + * + * We don't need to do anything except check for worker failure. + */ +static void +mark_dump_job_done(ArchiveHandle *AH, + TocEntry *te, + int status, + void *callback_data) +{ + ahlog(AH, 1, "finished item %d %s %s\n", + te->dumpId, te->desc, te->tag); + + if (status != 0) + exit_horribly(modulename, "worker process failed: exit code %d\n", + status); } + void WriteDataChunksForTocEntry(ArchiveHandle *AH, TocEntry *te) { @@ -2751,6 +2795,11 @@ _tocEntryRequired(TocEntry *te, teSection curSection, RestoreOptions *ropt) return 0; } + if (ropt->schemaExcludeNames.head != NULL && + te->namespace && + simple_string_list_member(&ropt->schemaExcludeNames, te->namespace)) + return 0; + if (ropt->selTypes) { if (strcmp(te->desc, "TABLE") == 0 || @@ -2826,7 +2875,10 @@ _tocEntryRequired(TocEntry *te, teSection curSection, RestoreOptions *ropt) /* Mask it if we only want schema */ if (ropt->schemaOnly) - res = res & REQ_SCHEMA; + { + if (!(ropt->sequence_data && strcmp(te->desc, "SEQUENCE SET") == 0)) + res = res & REQ_SCHEMA; + } /* Mask it if we only want data */ if (ropt->dataOnly) @@ -3215,6 +3267,8 @@ _getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH) strcmp(type, "SCHEMA") == 0 || strcmp(type, "FOREIGN DATA WRAPPER") == 0 || strcmp(type, "SERVER") == 0 || + strcmp(type, "PUBLICATION") == 0 || + strcmp(type, "SUBSCRIPTION") == 0 || strcmp(type, "USER MAPPING") == 0) { /* We already know that search_path was set properly */ @@ -3425,7 +3479,9 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData, bool acl_pass) strcmp(te->desc, "TEXT SEARCH DICTIONARY") == 0 || strcmp(te->desc, "TEXT SEARCH CONFIGURATION") == 0 || strcmp(te->desc, "FOREIGN DATA WRAPPER") == 0 || - strcmp(te->desc, "SERVER") == 0) + strcmp(te->desc, "SERVER") == 0 || + strcmp(te->desc, "PUBLICATION") == 0 || + strcmp(te->desc, "SUBSCRIPTION") == 0) { PQExpBuffer temp = createPQExpBuffer(); @@ -3495,9 +3551,9 @@ WriteHead(ArchiveHandle *AH) struct tm crtm; (*AH->WriteBufPtr) (AH, "PGDMP", 5); /* Magic code */ - (*AH->WriteBytePtr) (AH, AH->vmaj); - (*AH->WriteBytePtr) (AH, AH->vmin); - (*AH->WriteBytePtr) (AH, AH->vrev); + (*AH->WriteBytePtr) (AH, ARCHIVE_MAJOR(AH->version)); + (*AH->WriteBytePtr) (AH, ARCHIVE_MINOR(AH->version)); + (*AH->WriteBytePtr) (AH, ARCHIVE_REV(AH->version)); (*AH->WriteBytePtr) (AH, AH->intSize); (*AH->WriteBytePtr) (AH, AH->offSize); (*AH->WriteBytePtr) (AH, AH->format); @@ -3530,24 +3586,28 @@ ReadHead(ArchiveHandle *AH) */ if (!AH->readHeader) { + char vmaj, + vmin, + vrev; + (*AH->ReadBufPtr) (AH, tmpMag, 5); if (strncmp(tmpMag, "PGDMP", 5) != 0) exit_horribly(modulename, "did not find magic string in file header\n"); - AH->vmaj = (*AH->ReadBytePtr) (AH); - AH->vmin = (*AH->ReadBytePtr) (AH); + vmaj = (*AH->ReadBytePtr) (AH); + vmin = (*AH->ReadBytePtr) (AH); - if (AH->vmaj > 1 || ((AH->vmaj == 1) && (AH->vmin > 0))) /* Version > 1.0 */ - AH->vrev = (*AH->ReadBytePtr) (AH); + if (vmaj > 1 || (vmaj == 1 && vmin > 0)) /* Version > 1.0 */ + vrev = (*AH->ReadBytePtr) (AH); else - AH->vrev = 0; + vrev = 0; - AH->version = ((AH->vmaj * 256 + AH->vmin) * 256 + AH->vrev) * 256 + 0; + AH->version = MAKE_ARCHIVE_VERSION(vmaj, vmin, vrev); if (AH->version < K_VERS_1_0 || AH->version > K_VERS_MAX) exit_horribly(modulename, "unsupported version (%d.%d) in file header\n", - AH->vmaj, AH->vmin); + vmaj, vmin); AH->intSize = (*AH->ReadBytePtr) (AH); if (AH->intSize > 32) @@ -3764,11 +3824,9 @@ static void restore_toc_entries_parallel(ArchiveHandle *AH, ParallelState *pstate, TocEntry *pending_list) { - int work_status; bool skipped_some; TocEntry ready_list; TocEntry *next_work_item; - int ret_child; ahlog(AH, 2, "entering restore_toc_entries_parallel\n"); @@ -3845,54 +3903,29 @@ restore_toc_entries_parallel(ArchiveHandle *AH, ParallelState *pstate, par_list_remove(next_work_item); - DispatchJobForTocEntry(AH, pstate, next_work_item, ACT_RESTORE); + DispatchJobForTocEntry(AH, pstate, next_work_item, ACT_RESTORE, + mark_restore_job_done, &ready_list); } else { /* at least one child is working and we have nothing ready. */ } - for (;;) - { - int nTerm = 0; - - /* - * In order to reduce dependencies as soon as possible and - * especially to reap the status of workers who are working on - * items that pending items depend on, we do a non-blocking check - * for ended workers first. - * - * However, if we do not have any other work items currently that - * workers can work on, we do not busy-loop here but instead - * really wait for at least one worker to terminate. Hence we call - * ListenToWorkers(..., ..., do_wait = true) in this case. - */ - ListenToWorkers(AH, pstate, !next_work_item); - - while ((ret_child = ReapWorkerStatus(pstate, &work_status)) != NO_SLOT) - { - nTerm++; - mark_work_done(AH, &ready_list, ret_child, work_status, pstate); - } - - /* - * We need to make sure that we have an idle worker before - * re-running the loop. If nTerm > 0 we already have that (quick - * check). - */ - if (nTerm > 0) - break; - - /* if nobody terminated, explicitly check for an idle worker */ - if (GetIdleWorker(pstate) != NO_SLOT) - break; - - /* - * If we have no idle worker, read the result of one or more - * workers and loop the loop to call ReapWorkerStatus() on them. - */ - ListenToWorkers(AH, pstate, true); - } + /* + * Before dispatching another job, check to see if anything has + * finished. We should check every time through the loop so as to + * reduce dependencies as soon as possible. If we were unable to + * dispatch any job this time through, wait until some worker finishes + * (and, hopefully, unblocks some pending item). If we did dispatch + * something, continue as soon as there's at least one idle worker. + * Note that in either case, there's guaranteed to be at least one + * idle worker when we return to the top of the loop. This ensures we + * won't block inside DispatchJobForTocEntry, which would be + * undesirable: we'd rather postpone dispatching until we see what's + * been unblocked by finished jobs. + */ + WaitForWorkers(AH, pstate, + next_work_item ? WFW_ONE_IDLE : WFW_GOT_STATUS); } ahlog(AH, 1, "finished main parallel loop\n"); @@ -4020,9 +4053,13 @@ get_next_work_item(ArchiveHandle *AH, TocEntry *ready_list, int count = 0; for (k = 0; k < pstate->numWorkers; k++) - if (pstate->parallelSlot[k].args->te != NULL && - pstate->parallelSlot[k].args->te->section == SECTION_DATA) + { + TocEntry *running_te = pstate->te[k]; + + if (running_te != NULL && + running_te->section == SECTION_DATA) count++; + } if (pstate->numWorkers == 0 || count * 4 < pstate->numWorkers) pref_non_data = false; } @@ -4039,14 +4076,12 @@ get_next_work_item(ArchiveHandle *AH, TocEntry *ready_list, * that a currently running item also needs lock on, or vice versa. If * so, we don't want to schedule them together. */ - for (i = 0; i < pstate->numWorkers && !conflicts; i++) + for (i = 0; i < pstate->numWorkers; i++) { - TocEntry *running_te; + TocEntry *running_te = pstate->te[i]; - if (pstate->parallelSlot[i].workerStatus != WRKR_WORKING) + if (running_te == NULL) continue; - running_te = pstate->parallelSlot[i].args->te; - if (has_lock_conflicts(te, running_te) || has_lock_conflicts(running_te, te)) { @@ -4086,10 +4121,8 @@ get_next_work_item(ArchiveHandle *AH, TocEntry *ready_list, * our work is finished, the master process will assign us a new work item. */ int -parallel_restore(ParallelArgs *args) +parallel_restore(ArchiveHandle *AH, TocEntry *te) { - ArchiveHandle *AH = args->AH; - TocEntry *te = args->te; int status; Assert(AH->connection != NULL); @@ -4105,22 +4138,18 @@ parallel_restore(ParallelArgs *args) /* - * Housekeeping to be done after a step has been parallel restored. + * Callback function that's invoked in the master process after a step has + * been parallel restored. * - * Clear the appropriate slot, free all the extra memory we allocated, - * update status, and reduce the dependency count of any dependent items. + * Update status and reduce the dependency count of any dependent items. */ static void -mark_work_done(ArchiveHandle *AH, TocEntry *ready_list, - int worker, int status, - ParallelState *pstate) +mark_restore_job_done(ArchiveHandle *AH, + TocEntry *te, + int status, + void *callback_data) { - TocEntry *te = NULL; - - te = pstate->parallelSlot[worker].args->te; - - if (te == NULL) - exit_horribly(modulename, "could not find slot of finished worker\n"); + TocEntry *ready_list = (TocEntry *) callback_data; ahlog(AH, 1, "finished item %d %s %s\n", te->dumpId, te->desc, te->tag); diff --git a/src/bin/pg_dump/pg_backup_archiver.h b/src/bin/pg_dump/pg_backup_archiver.h index 0376f2bff7..a44e16ee45 100644 --- a/src/bin/pg_dump/pg_backup_archiver.h +++ b/src/bin/pg_dump/pg_backup_archiver.h @@ -62,37 +62,45 @@ typedef struct _z_stream typedef z_stream *z_streamp; #endif -/* Current archive version number (the format we can output) */ -#define K_VERS_MAJOR 1 -#define K_VERS_MINOR 12 -#define K_VERS_REV 0 - /* Data block types */ #define BLK_DATA 1 #define BLK_BLOBS 3 +/* Encode version components into a convenient integer */ +#define MAKE_ARCHIVE_VERSION(major, minor, rev) (((major) * 256 + (minor)) * 256 + (rev)) + +#define ARCHIVE_MAJOR(version) (((version) >> 16) & 255) +#define ARCHIVE_MINOR(version) (((version) >> 8) & 255) +#define ARCHIVE_REV(version) (((version) ) & 255) + /* Historical version numbers (checked in code) */ -#define K_VERS_1_0 (( (1 * 256 + 0) * 256 + 0) * 256 + 0) -#define K_VERS_1_2 (( (1 * 256 + 2) * 256 + 0) * 256 + 0) /* Allow No ZLIB */ -#define K_VERS_1_3 (( (1 * 256 + 3) * 256 + 0) * 256 + 0) /* BLOBs */ -#define K_VERS_1_4 (( (1 * 256 + 4) * 256 + 0) * 256 + 0) /* Date & name in header */ -#define K_VERS_1_5 (( (1 * 256 + 5) * 256 + 0) * 256 + 0) /* Handle dependencies */ -#define K_VERS_1_6 (( (1 * 256 + 6) * 256 + 0) * 256 + 0) /* Schema field in TOCs */ -#define K_VERS_1_7 (( (1 * 256 + 7) * 256 + 0) * 256 + 0) /* File Offset size in - * header */ -#define K_VERS_1_8 (( (1 * 256 + 8) * 256 + 0) * 256 + 0) /* change interpretation - * of ID numbers and - * dependencies */ -#define K_VERS_1_9 (( (1 * 256 + 9) * 256 + 0) * 256 + 0) /* add default_with_oids - * tracking */ -#define K_VERS_1_10 (( (1 * 256 + 10) * 256 + 0) * 256 + 0) /* add tablespace */ -#define K_VERS_1_11 (( (1 * 256 + 11) * 256 + 0) * 256 + 0) /* add toc section - * indicator */ -#define K_VERS_1_12 (( (1 * 256 + 12) * 256 + 0) * 256 + 0) /* add separate BLOB - * entries */ +#define K_VERS_1_0 MAKE_ARCHIVE_VERSION(1, 0, 0) +#define K_VERS_1_2 MAKE_ARCHIVE_VERSION(1, 2, 0) /* Allow No ZLIB */ +#define K_VERS_1_3 MAKE_ARCHIVE_VERSION(1, 3, 0) /* BLOBs */ +#define K_VERS_1_4 MAKE_ARCHIVE_VERSION(1, 4, 0) /* Date & name in header */ +#define K_VERS_1_5 MAKE_ARCHIVE_VERSION(1, 5, 0) /* Handle dependencies */ +#define K_VERS_1_6 MAKE_ARCHIVE_VERSION(1, 6, 0) /* Schema field in TOCs */ +#define K_VERS_1_7 MAKE_ARCHIVE_VERSION(1, 7, 0) /* File Offset size in + * header */ +#define K_VERS_1_8 MAKE_ARCHIVE_VERSION(1, 8, 0) /* change interpretation + * of ID numbers and + * dependencies */ +#define K_VERS_1_9 MAKE_ARCHIVE_VERSION(1, 9, 0) /* add default_with_oids + * tracking */ +#define K_VERS_1_10 MAKE_ARCHIVE_VERSION(1, 10, 0) /* add tablespace */ +#define K_VERS_1_11 MAKE_ARCHIVE_VERSION(1, 11, 0) /* add toc section + * indicator */ +#define K_VERS_1_12 MAKE_ARCHIVE_VERSION(1, 12, 0) /* add separate BLOB + * entries */ + +/* Current archive version number (the format we can output) */ +#define K_VERS_MAJOR 1 +#define K_VERS_MINOR 12 +#define K_VERS_REV 0 +#define K_VERS_SELF MAKE_ARCHIVE_VERSION(K_VERS_MAJOR, K_VERS_MINOR, K_VERS_REV); /* Newest format we can read */ -#define K_VERS_MAX (( (1 * 256 + 12) * 256 + 255) * 256 + 0) +#define K_VERS_MAX MAKE_ARCHIVE_VERSION(K_VERS_MAJOR, K_VERS_MINOR, 255) /* Flags to indicate disposition of offsets stored in files */ @@ -111,7 +119,6 @@ typedef z_stream *z_streamp; typedef struct _archiveHandle ArchiveHandle; typedef struct _tocEntry TocEntry; -struct ParallelArgs; struct ParallelState; #define READ_ERROR_EXIT(fd) \ @@ -162,12 +169,8 @@ typedef void (*PrintTocDataPtr) (ArchiveHandle *AH, TocEntry *te); typedef void (*ClonePtr) (ArchiveHandle *AH); typedef void (*DeClonePtr) (ArchiveHandle *AH); -typedef char *(*WorkerJobRestorePtr) (ArchiveHandle *AH, TocEntry *te); -typedef char *(*WorkerJobDumpPtr) (ArchiveHandle *AH, TocEntry *te); -typedef char *(*MasterStartParallelItemPtr) (ArchiveHandle *AH, TocEntry *te, - T_Action act); -typedef int (*MasterEndParallelItemPtr) (ArchiveHandle *AH, TocEntry *te, - const char *str, T_Action act); +typedef int (*WorkerJobDumpPtr) (ArchiveHandle *AH, TocEntry *te); +typedef int (*WorkerJobRestorePtr) (ArchiveHandle *AH, TocEntry *te); typedef size_t (*CustomOutPtr) (ArchiveHandle *AH, const void *buf, size_t len); @@ -210,10 +213,7 @@ typedef enum struct _archiveHandle { Archive public; /* Public part of archive */ - char vmaj; /* Version of file */ - char vmin; - char vrev; - int version; /* Conveniently formatted version */ + int version; /* Version of file */ char *archiveRemoteVersion; /* When reading an archive, the * version of the dumped DB */ @@ -267,9 +267,6 @@ struct _archiveHandle StartBlobPtr StartBlobPtr; EndBlobPtr EndBlobPtr; - MasterStartParallelItemPtr MasterStartParallelItemPtr; - MasterEndParallelItemPtr MasterEndParallelItemPtr; - SetupWorkerPtr SetupWorkerPtr; WorkerJobDumpPtr WorkerJobDumpPtr; WorkerJobRestorePtr WorkerJobRestorePtr; @@ -375,7 +372,7 @@ struct _tocEntry int nLockDeps; /* number of such dependencies */ }; -extern int parallel_restore(struct ParallelArgs *args); +extern int parallel_restore(ArchiveHandle *AH, TocEntry *te); extern void on_exit_close_archive(Archive *AHX); extern void warn_or_exit_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt,...) pg_attribute_printf(3, 4); diff --git a/src/bin/pg_dump/pg_backup_custom.c b/src/bin/pg_dump/pg_backup_custom.c index 66329dc90c..5388c08b29 100644 --- a/src/bin/pg_dump/pg_backup_custom.c +++ b/src/bin/pg_dump/pg_backup_custom.c @@ -61,9 +61,7 @@ static void _LoadBlobs(ArchiveHandle *AH, bool drop); static void _Clone(ArchiveHandle *AH); static void _DeClone(ArchiveHandle *AH); -static char *_MasterStartParallelItem(ArchiveHandle *AH, TocEntry *te, T_Action act); -static int _MasterEndParallelItem(ArchiveHandle *AH, TocEntry *te, const char *str, T_Action act); -char *_WorkerJobRestoreCustom(ArchiveHandle *AH, TocEntry *te); +static int _WorkerJobRestoreCustom(ArchiveHandle *AH, TocEntry *te); typedef struct { @@ -133,9 +131,6 @@ InitArchiveFmt_Custom(ArchiveHandle *AH) AH->ClonePtr = _Clone; AH->DeClonePtr = _DeClone; - AH->MasterStartParallelItemPtr = _MasterStartParallelItem; - AH->MasterEndParallelItemPtr = _MasterEndParallelItem; - /* no parallel dump in the custom archive, only parallel restore */ AH->WorkerJobDumpPtr = NULL; AH->WorkerJobRestorePtr = _WorkerJobRestoreCustom; @@ -808,77 +803,13 @@ _DeClone(ArchiveHandle *AH) } /* - * This function is executed in the child of a parallel backup for the - * custom format archive and dumps the actual data. - */ -char * -_WorkerJobRestoreCustom(ArchiveHandle *AH, TocEntry *te) -{ - /* - * short fixed-size string + some ID so far, this needs to be malloc'ed - * instead of static because we work with threads on windows - */ - const int buflen = 64; - char *buf = (char *) pg_malloc(buflen); - ParallelArgs pargs; - int status; - - pargs.AH = AH; - pargs.te = te; - - status = parallel_restore(&pargs); - - snprintf(buf, buflen, "OK RESTORE %d %d %d", te->dumpId, status, - status == WORKER_IGNORED_ERRORS ? AH->public.n_errors : 0); - - return buf; -} - -/* - * This function is executed in the parent process. Depending on the desired - * action (dump or restore) it creates a string that is understood by the - * _WorkerJobDump /_WorkerJobRestore functions of the dump format. - */ -static char * -_MasterStartParallelItem(ArchiveHandle *AH, TocEntry *te, T_Action act) -{ - /* - * A static char is okay here, even on Windows because we call this - * function only from one process (the master). - */ - static char buf[64]; /* short fixed-size string + number */ - - /* no parallel dump in the custom archive format */ - Assert(act == ACT_RESTORE); - - snprintf(buf, sizeof(buf), "RESTORE %d", te->dumpId); - - return buf; -} - -/* - * This function is executed in the parent process. It analyzes the response of - * the _WorkerJobDump / _WorkerJobRestore functions of the dump format. + * This function is executed in the child of a parallel restore from a + * custom-format archive and restores the actual data for one TOC entry. */ static int -_MasterEndParallelItem(ArchiveHandle *AH, TocEntry *te, const char *str, T_Action act) +_WorkerJobRestoreCustom(ArchiveHandle *AH, TocEntry *te) { - DumpId dumpId; - int nBytes, - status, - n_errors; - - /* no parallel dump in the custom archive */ - Assert(act == ACT_RESTORE); - - sscanf(str, "%d %d %d%n", &dumpId, &status, &n_errors, &nBytes); - - Assert(nBytes == strlen(str)); - Assert(dumpId == te->dumpId); - - AH->public.n_errors += n_errors; - - return status; + return parallel_restore(AH, te); } /*-------------------------------------------------- diff --git a/src/bin/pg_dump/pg_backup_db.c b/src/bin/pg_dump/pg_backup_db.c index d2a3de3c5d..3b9cd89b4a 100644 --- a/src/bin/pg_dump/pg_backup_db.c +++ b/src/bin/pg_dump/pg_backup_db.c @@ -134,6 +134,7 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser) const char *newdb; const char *newuser; char *password; + char passbuf[100]; bool new_pass; if (!reqdb) @@ -149,13 +150,12 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser) ahlog(AH, 1, "connecting to database \"%s\" as user \"%s\"\n", newdb, newuser); - password = AH->savedPassword ? pg_strdup(AH->savedPassword) : NULL; + password = AH->savedPassword; if (AH->promptPassword == TRI_YES && password == NULL) { - password = simple_prompt("Password: ", 100, false); - if (password == NULL) - exit_horribly(modulename, "out of memory\n"); + simple_prompt("Password: ", passbuf, sizeof(passbuf), false); + password = passbuf; } initPQExpBuffer(&connstr); @@ -201,16 +201,14 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser) fprintf(stderr, "Connecting to %s as %s\n", newdb, newuser); - if (password) - free(password); - if (AH->promptPassword != TRI_NO) - password = simple_prompt("Password: ", 100, false); + { + simple_prompt("Password: ", passbuf, sizeof(passbuf), false); + password = passbuf; + } else exit_horribly(modulename, "connection needs password\n"); - if (password == NULL) - exit_horribly(modulename, "out of memory\n"); new_pass = true; } } while (new_pass); @@ -225,8 +223,6 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser) free(AH->savedPassword); AH->savedPassword = pg_strdup(PQpass(newConn)); } - if (password) - free(password); termPQExpBuffer(&connstr); @@ -258,18 +254,18 @@ ConnectDatabase(Archive *AHX, { ArchiveHandle *AH = (ArchiveHandle *) AHX; char *password; + char passbuf[100]; bool new_pass; if (AH->connection) exit_horribly(modulename, "already connected to a database\n"); - password = AH->savedPassword ? pg_strdup(AH->savedPassword) : NULL; + password = AH->savedPassword; if (prompt_password == TRI_YES && password == NULL) { - password = simple_prompt("Password: ", 100, false); - if (password == NULL) - exit_horribly(modulename, "out of memory\n"); + simple_prompt("Password: ", passbuf, sizeof(passbuf), false); + password = passbuf; } AH->promptPassword = prompt_password; @@ -309,9 +305,8 @@ ConnectDatabase(Archive *AHX, prompt_password != TRI_NO) { PQfinish(AH->connection); - password = simple_prompt("Password: ", 100, false); - if (password == NULL) - exit_horribly(modulename, "out of memory\n"); + simple_prompt("Password: ", passbuf, sizeof(passbuf), false); + password = passbuf; new_pass = true; } } while (new_pass); @@ -332,8 +327,6 @@ ConnectDatabase(Archive *AHX, free(AH->savedPassword); AH->savedPassword = pg_strdup(PQpass(AH->connection)); } - if (password) - free(password); /* check for version mismatch */ _check_database_version(AH); diff --git a/src/bin/pg_dump/pg_backup_directory.c b/src/bin/pg_dump/pg_backup_directory.c index e52f12258a..0d7322f73a 100644 --- a/src/bin/pg_dump/pg_backup_directory.c +++ b/src/bin/pg_dump/pg_backup_directory.c @@ -17,7 +17,7 @@ * sync. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 2000, Philip Warner * @@ -89,11 +89,8 @@ static void _LoadBlobs(ArchiveHandle *AH); static void _Clone(ArchiveHandle *AH); static void _DeClone(ArchiveHandle *AH); -static char *_MasterStartParallelItem(ArchiveHandle *AH, TocEntry *te, T_Action act); -static int _MasterEndParallelItem(ArchiveHandle *AH, TocEntry *te, - const char *str, T_Action act); -static char *_WorkerJobRestoreDirectory(ArchiveHandle *AH, TocEntry *te); -static char *_WorkerJobDumpDirectory(ArchiveHandle *AH, TocEntry *te); +static int _WorkerJobRestoreDirectory(ArchiveHandle *AH, TocEntry *te); +static int _WorkerJobDumpDirectory(ArchiveHandle *AH, TocEntry *te); static void setFilePath(ArchiveHandle *AH, char *buf, const char *relativeFilename); @@ -140,9 +137,6 @@ InitArchiveFmt_Directory(ArchiveHandle *AH) AH->WorkerJobRestorePtr = _WorkerJobRestoreDirectory; AH->WorkerJobDumpPtr = _WorkerJobDumpDirectory; - AH->MasterStartParallelItemPtr = _MasterStartParallelItem; - AH->MasterEndParallelItemPtr = _MasterEndParallelItem; - /* Set up our private context */ ctx = (lclContext *) pg_malloc0(sizeof(lclContext)); AH->formatData = (void *) ctx; @@ -754,53 +748,12 @@ _DeClone(ArchiveHandle *AH) } /* - * This function is executed in the parent process. Depending on the desired - * action (dump or restore) it creates a string that is understood by the - * _WorkerJobDump /_WorkerJobRestore functions of the dump format. - */ -static char * -_MasterStartParallelItem(ArchiveHandle *AH, TocEntry *te, T_Action act) -{ - /* - * A static char is okay here, even on Windows because we call this - * function only from one process (the master). - */ - static char buf[64]; - - if (act == ACT_DUMP) - snprintf(buf, sizeof(buf), "DUMP %d", te->dumpId); - else if (act == ACT_RESTORE) - snprintf(buf, sizeof(buf), "RESTORE %d", te->dumpId); - - return buf; -} - -/* - * This function is executed in the child of a parallel backup for the - * directory archive and dumps the actual data. - * - * We are currently returning only the DumpId so theoretically we could - * make this function returning an int (or a DumpId). However, to - * facilitate further enhancements and because sooner or later we need to - * convert this to a string and send it via a message anyway, we stick with - * char *. It is parsed on the other side by the _EndMasterParallel() - * function of the respective dump format. + * This function is executed in the child of a parallel backup for a + * directory-format archive and dumps the actual data for one TOC entry. */ -static char * +static int _WorkerJobDumpDirectory(ArchiveHandle *AH, TocEntry *te) { - /* - * short fixed-size string + some ID so far, this needs to be malloc'ed - * instead of static because we work with threads on windows - */ - const int buflen = 64; - char *buf = (char *) pg_malloc(buflen); - lclTocEntry *tctx = (lclTocEntry *) te->formatData; - - /* This should never happen */ - if (!tctx) - exit_horribly(modulename, "error during backup\n"); - /* * This function returns void. We either fail and die horribly or * succeed... A failure will be detected by the parent when the child dies @@ -808,67 +761,15 @@ _WorkerJobDumpDirectory(ArchiveHandle *AH, TocEntry *te) */ WriteDataChunksForTocEntry(AH, te); - snprintf(buf, buflen, "OK DUMP %d", te->dumpId); - - return buf; -} - -/* - * This function is executed in the child of a parallel backup for the - * directory archive and dumps the actual data. - */ -static char * -_WorkerJobRestoreDirectory(ArchiveHandle *AH, TocEntry *te) -{ - /* - * short fixed-size string + some ID so far, this needs to be malloc'ed - * instead of static because we work with threads on windows - */ - const int buflen = 64; - char *buf = (char *) pg_malloc(buflen); - ParallelArgs pargs; - int status; - - pargs.AH = AH; - pargs.te = te; - - status = parallel_restore(&pargs); - - snprintf(buf, buflen, "OK RESTORE %d %d %d", te->dumpId, status, - status == WORKER_IGNORED_ERRORS ? AH->public.n_errors : 0); - - return buf; + return 0; } /* - * This function is executed in the parent process. It analyzes the response of - * the _WorkerJobDumpDirectory/_WorkerJobRestoreDirectory functions of the - * respective dump format. + * This function is executed in the child of a parallel restore from a + * directory-format archive and restores the actual data for one TOC entry. */ static int -_MasterEndParallelItem(ArchiveHandle *AH, TocEntry *te, const char *str, T_Action act) +_WorkerJobRestoreDirectory(ArchiveHandle *AH, TocEntry *te) { - DumpId dumpId; - int nBytes, - n_errors; - int status = 0; - - if (act == ACT_DUMP) - { - sscanf(str, "%d%n", &dumpId, &nBytes); - - Assert(dumpId == te->dumpId); - Assert(nBytes == strlen(str)); - } - else if (act == ACT_RESTORE) - { - sscanf(str, "%d %d %d%n", &dumpId, &status, &n_errors, &nBytes); - - Assert(dumpId == te->dumpId); - Assert(nBytes == strlen(str)); - - AH->public.n_errors += n_errors; - } - - return status; + return parallel_restore(AH, te); } diff --git a/src/bin/pg_dump/pg_backup_tar.c b/src/bin/pg_dump/pg_backup_tar.c index 8dfc6a98de..9cadd0c4a4 100644 --- a/src/bin/pg_dump/pg_backup_tar.c +++ b/src/bin/pg_dump/pg_backup_tar.c @@ -152,9 +152,6 @@ InitArchiveFmt_Tar(ArchiveHandle *AH) AH->ClonePtr = NULL; AH->DeClonePtr = NULL; - AH->MasterStartParallelItemPtr = NULL; - AH->MasterEndParallelItemPtr = NULL; - AH->WorkerJobDumpPtr = NULL; AH->WorkerJobRestorePtr = NULL; diff --git a/src/bin/pg_dump/pg_backup_utils.c b/src/bin/pg_dump/pg_backup_utils.c index 01bf576455..d7907fde95 100644 --- a/src/bin/pg_dump/pg_backup_utils.c +++ b/src/bin/pg_dump/pg_backup_utils.c @@ -4,7 +4,7 @@ * Utility routines shared by pg_dump and pg_restore * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/pg_dump/pg_backup_utils.c diff --git a/src/bin/pg_dump/pg_backup_utils.h b/src/bin/pg_dump/pg_backup_utils.h index f50e36cb0b..04b53f496e 100644 --- a/src/bin/pg_dump/pg_backup_utils.h +++ b/src/bin/pg_dump/pg_backup_utils.h @@ -4,7 +4,7 @@ * Utility routines shared by pg_dump and pg_restore. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/pg_dump/pg_backup_utils.h diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index a5c2d09e29..0bb363957a 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -4,7 +4,7 @@ * pg_dump is a utility for dumping out a postgres database * into a script file. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * pg_dump will read the system catalogs in a database and dump out a @@ -96,8 +96,11 @@ bool g_verbose; /* User wants verbose narration of our /* subquery used to convert user ID (eg, datdba) to user name */ static const char *username_subquery; -/* obsolete as of 7.3: */ -static Oid g_last_builtin_oid; /* value of the last builtin oid */ +/* + * For 8.0 and earlier servers, pulled from pg_database, for 8.1+ we use + * FirstNormalObjectId - 1. + */ +static Oid g_last_builtin_oid; /* value of the last builtin oid */ /* The specified names/patterns should to match at least one entity */ static int strict_names = 0; @@ -142,7 +145,7 @@ static void expand_table_name_patterns(Archive *fout, SimpleStringList *patterns, SimpleOidList *oids, bool strict_names); -static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid, Oid objoid); +static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid); static void dumpTableData(Archive *fout, TableDataInfo *tdinfo); static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo); static void guessConstraintInheritance(TableInfo *tblinfo, int numTables); @@ -219,7 +222,7 @@ static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs, DumpableObject *boundaryObjs); static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo); -static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids); +static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids, char relkind); static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo, bool oids); static void buildMatViewRefreshDependencies(Archive *fout); static void getTableDataFKConstraints(void); @@ -236,15 +239,16 @@ static char *convertRegProcReference(Archive *fout, const char *proc); static char *convertOperatorReference(Archive *fout, const char *opr); static char *convertTSFunction(Archive *fout, Oid funcOid); -static Oid findLastBuiltinOid_V71(Archive *fout, const char *); -static Oid findLastBuiltinOid_V70(Archive *fout); +static Oid findLastBuiltinOid_V71(Archive *fout, const char *); static void selectSourceSchema(Archive *fout, const char *schemaName); static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts); -static char *myFormatType(const char *typname, int32 typmod); static void getBlobs(Archive *fout); static void dumpBlob(Archive *fout, BlobInfo *binfo); static int dumpBlobs(Archive *fout, void *arg); static void dumpPolicy(Archive *fout, PolicyInfo *polinfo); +static void dumpPublication(Archive *fout, PublicationInfo *pubinfo); +static void dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo); +static void dumpSubscription(Archive *fout, SubscriptionInfo *subinfo); static void dumpDatabase(Archive *AH); static void dumpEncoding(Archive *AH); static void dumpStdStrings(Archive *AH); @@ -297,6 +301,7 @@ main(int argc, char **argv) static struct option long_options[] = { {"data-only", no_argument, NULL, 'a'}, {"blobs", no_argument, NULL, 'b'}, + {"no-blobs", no_argument, NULL, 'B'}, {"clean", no_argument, NULL, 'c'}, {"create", no_argument, NULL, 'C'}, {"dbname", required_argument, NULL, 'd'}, @@ -336,6 +341,7 @@ main(int argc, char **argv) {"enable-row-security", no_argument, &dopt.enable_row_security, 1}, {"exclude-table-data", required_argument, NULL, 4}, {"if-exists", no_argument, &dopt.if_exists, 1}, + {"include-subscriptions", no_argument, &dopt.include_subscriptions, 1}, {"inserts", no_argument, &dopt.dump_inserts, 1}, {"lock-wait-timeout", required_argument, NULL, 2}, {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1}, @@ -346,6 +352,7 @@ main(int argc, char **argv) {"snapshot", required_argument, NULL, 6}, {"strict-names", no_argument, &strict_names, 1}, {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1}, + {"no-create-subscription-slots", no_argument, &dopt.no_create_subscription_slots, 1}, {"no-security-labels", no_argument, &dopt.no_security_labels, 1}, {"no-synchronized-snapshots", no_argument, &dopt.no_synchronized_snapshots, 1}, {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1}, @@ -369,10 +376,6 @@ main(int argc, char **argv) progname = get_progname(argv[0]); - /* Set default options based on progname */ - if (strcmp(progname, "pg_backup") == 0) - format = "c"; - if (argc > 1) { if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) @@ -389,7 +392,7 @@ main(int argc, char **argv) InitDumpOptions(&dopt); - while ((c = getopt_long(argc, argv, "abcCd:E:f:F:h:j:n:N:oOp:RsS:t:T:U:vwWxZ:", + while ((c = getopt_long(argc, argv, "abBcCd:E:f:F:h:j:n:N:oOp:RsS:t:T:U:vwWxZ:", long_options, &optindex)) != -1) { switch (c) @@ -402,6 +405,10 @@ main(int argc, char **argv) dopt.outputBlobs = true; break; + case 'B': /* Don't dump blobs */ + dopt.dontOutputBlobs = true; + break; + case 'c': /* clean (i.e., drop) schema prior to create */ dopt.outputClean = 1; break; @@ -556,6 +563,14 @@ main(int argc, char **argv) if (dopt.column_inserts) dopt.dump_inserts = 1; + /* + * Binary upgrade mode implies dumping sequence data even in schema-only + * mode. This is not exposed as a separate option, but kept separate + * internally for clarity. + */ + if (dopt.binary_upgrade) + dopt.sequence_data = 1; + if (dopt.dataOnly && dopt.schemaOnly) { write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n"); @@ -613,7 +628,7 @@ main(int argc, char **argv) || numWorkers > MAXIMUM_WAIT_OBJECTS #endif ) - exit_horribly(NULL, "%s: invalid number of parallel jobs\n", progname); + exit_horribly(NULL, "invalid number of parallel jobs\n"); /* Parallel backup only in the directory archive format so far */ if (archiveFormat != archDirectory && numWorkers > 1) @@ -633,10 +648,10 @@ main(int argc, char **argv) fout->verbose = g_verbose; /* - * We allow the server to be back to 7.0, and up to any minor release of + * We allow the server to be back to 8.0, and up to any minor release of * our own major version. (See also version check in pg_dumpall.c.) */ - fout->minRemoteVersion = 70000; + fout->minRemoteVersion = 80000; fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99; fout->numWorkers = numWorkers; @@ -665,10 +680,8 @@ main(int argc, char **argv) /* Select the appropriate subquery to convert user IDs to names */ if (fout->remoteVersion >= 80100) username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid ="; - else if (fout->remoteVersion >= 70300) - username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid ="; else - username_subquery = "SELECT usename FROM pg_user WHERE usesysid ="; + username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid ="; /* check the version for the synchronized snapshots feature */ if (numWorkers > 1 && fout->remoteVersion < 90200 @@ -683,17 +696,19 @@ main(int argc, char **argv) exit_horribly(NULL, "Exported snapshots are not supported by this server version.\n"); - /* Find the last built-in OID, if needed */ - if (fout->remoteVersion < 70300) - { - if (fout->remoteVersion >= 70100) - g_last_builtin_oid = findLastBuiltinOid_V71(fout, - PQdb(GetConnection(fout))); - else - g_last_builtin_oid = findLastBuiltinOid_V70(fout); - if (g_verbose) - write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid); - } + /* + * Find the last built-in OID, if needed (prior to 8.1) + * + * With 8.1 and above, we can just use FirstNormalObjectId - 1. + */ + if (fout->remoteVersion < 80100) + g_last_builtin_oid = findLastBuiltinOid_V71(fout, + PQdb(GetConnection(fout))); + else + g_last_builtin_oid = FirstNormalObjectId - 1; + + if (g_verbose) + write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid); /* Expand schema selection patterns into OID lists */ if (schema_include_patterns.head != NULL) @@ -729,10 +744,15 @@ main(int argc, char **argv) /* non-matching exclusion patterns aren't an error */ /* - * Dumping blobs is now default unless we saw an inclusion switch or -s - * ... but even if we did see one of these, -b turns it back on. + * Dumping blobs is the default for dumps where an inclusion switch is not + * used (an "include everything" dump). -B can be used to exclude blobs + * from those dumps. -b can be used to include blobs even when an + * inclusion switch is used. + * + * -s means "schema only" and blobs are data, not schema, so we never + * include blobs when -s is used. */ - if (dopt.include_everything && !dopt.schemaOnly) + if (dopt.include_everything && !dopt.schemaOnly && !dopt.dontOutputBlobs) dopt.outputBlobs = true; /* @@ -746,12 +766,15 @@ main(int argc, char **argv) if (!dopt.schemaOnly) { - getTableData(&dopt, tblinfo, numTables, dopt.oids); + getTableData(&dopt, tblinfo, numTables, dopt.oids, 0); buildMatViewRefreshDependencies(fout); if (dopt.dataOnly) getTableDataFKConstraints(); } + if (dopt.schemaOnly && dopt.sequence_data) + getTableData(&dopt, tblinfo, numTables, dopt.oids, RELKIND_SEQUENCE); + if (dopt.outputBlobs) getBlobs(fout); @@ -774,16 +797,11 @@ main(int argc, char **argv) /* * Sort the objects into a safe dump order (no forward references). * - * In 7.3 or later, we can rely on dependency information to help us - * determine a safe order, so the initial sort is mostly for cosmetic - * purposes: we sort by name to ensure that logically identical schemas - * will dump identically. Before 7.3 we don't have dependencies and we - * use OID ordering as an (unreliable) guide to creation order. + * We rely on dependency information to help us determine a safe order, so + * the initial sort is mostly for cosmetic purposes: we sort by name to + * ensure that logically identical schemas will dump identically. */ - if (fout->remoteVersion >= 70300) - sortDumpableObjectsByTypeName(dobjs, numObjs); - else - sortDumpableObjectsByTypeOid(dobjs, numObjs); + sortDumpableObjectsByTypeName(dobjs, numObjs); /* If we do a parallel dump, we want the largest tables to go first */ if (archiveFormat == archDirectory && numWorkers > 1) @@ -835,6 +853,8 @@ main(int argc, char **argv) ropt->lockWaitTimeout = dopt.lockWaitTimeout; ropt->include_everything = dopt.include_everything; ropt->enable_row_security = dopt.enable_row_security; + ropt->sequence_data = dopt.sequence_data; + ropt->include_subscriptions = dopt.include_subscriptions; if (compressLevel == -1) ropt->compression = 0; @@ -893,6 +913,7 @@ help(const char *progname) printf(_("\nOptions controlling the output content:\n")); printf(_(" -a, --data-only dump only the data, not the schema\n")); printf(_(" -b, --blobs include large objects in dump\n")); + printf(_(" -B, --no-blobs exclude large objects in dump\n")); printf(_(" -c, --clean clean (drop) database objects before recreating\n")); printf(_(" -C, --create include commands to create database in dump\n")); printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n")); @@ -914,7 +935,10 @@ help(const char *progname) " access to)\n")); printf(_(" --exclude-table-data=TABLE do NOT dump data for the named table(s)\n")); printf(_(" --if-exists use IF EXISTS when dropping objects\n")); + printf(_(" --include-subscriptions dump logical replication subscriptions\n")); printf(_(" --inserts dump data as INSERT commands, rather than COPY\n")); + printf(_(" --no-create-subscription-slots\n" + " do not create replication slots for subscriptions\n")); printf(_(" --no-security-labels do not dump security label assignments\n")); printf(_(" --no-synchronized-snapshots do not use synchronized snapshots in parallel jobs\n")); printf(_(" --no-tablespaces do not dump tablespace assignments\n")); @@ -1000,12 +1024,12 @@ setup_connection(Archive *AH, const char *dumpencoding, ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES"); /* - * If supported, set extra_float_digits so that we can dump float data - * exactly (given correctly implemented float I/O code, anyway) + * Set extra_float_digits so that we can dump float data exactly (given + * correctly implemented float I/O code, anyway) */ if (AH->remoteVersion >= 90000) ExecuteSqlStatement(AH, "SET extra_float_digits TO 3"); - else if (AH->remoteVersion >= 70400) + else ExecuteSqlStatement(AH, "SET extra_float_digits TO 2"); /* @@ -1018,8 +1042,7 @@ setup_connection(Archive *AH, const char *dumpencoding, /* * Disable timeouts if supported. */ - if (AH->remoteVersion >= 70300) - ExecuteSqlStatement(AH, "SET statement_timeout = 0"); + ExecuteSqlStatement(AH, "SET statement_timeout = 0"); if (AH->remoteVersion >= 90300) ExecuteSqlStatement(AH, "SET lock_timeout = 0"); if (AH->remoteVersion >= 90600) @@ -1065,16 +1088,12 @@ setup_connection(Archive *AH, const char *dumpencoding, "SET TRANSACTION ISOLATION LEVEL " "REPEATABLE READ, READ ONLY"); } - else if (AH->remoteVersion >= 70400) + else { - /* note: comma was not accepted in SET TRANSACTION before 8.0 */ ExecuteSqlStatement(AH, "SET TRANSACTION ISOLATION LEVEL " - "SERIALIZABLE READ ONLY"); + "SERIALIZABLE, READ ONLY"); } - else - ExecuteSqlStatement(AH, - "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE"); /* * If user specified a snapshot to use, select that. In a parallel dump @@ -1190,9 +1209,6 @@ expand_schema_name_patterns(Archive *fout, if (patterns->head == NULL) return; /* nothing to do */ - if (fout->remoteVersion < 70300) - exit_horribly(NULL, "server version must be at least 7.3 to use schema selection switches\n"); - query = createPQExpBuffer(); /* @@ -1209,7 +1225,7 @@ expand_schema_name_patterns(Archive *fout, res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); if (strict_names && PQntuples(res) == 0) - exit_horribly(NULL, "no matching tables were found for pattern \"%s\"\n", cell->val); + exit_horribly(NULL, "no matching schemas were found for pattern \"%s\"\n", cell->val); for (i = 0; i < PQntuples(res); i++) { @@ -1253,9 +1269,10 @@ expand_table_name_patterns(Archive *fout, "SELECT c.oid" "\nFROM pg_catalog.pg_class c" "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace" - "\nWHERE c.relkind in ('%c', '%c', '%c', '%c', '%c')\n", + "\nWHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c')\n", RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW, - RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE); + RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE, + RELKIND_PARTITIONED_TABLE); processSQLNamePattern(GetConnection(fout), query, cell->val, true, false, "n.nspname", "c.relname", NULL, "pg_catalog.pg_table_is_visible(c.oid)"); @@ -1302,7 +1319,7 @@ checkExtensionMembership(DumpableObject *dobj, Archive *fout) /* * In 9.6 and above, mark the member object to have any non-initial ACL, - * policies, and security lables dumped. + * policies, and security labels dumped. * * Note that any initial ACLs (see pg_init_privs) will be removed when we * extract the information about the object. We don't provide support for @@ -1324,8 +1341,8 @@ checkExtensionMembership(DumpableObject *dobj, Archive *fout) dobj->dump = DUMP_COMPONENT_NONE; else dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL | - DUMP_COMPONENT_SECLABEL | DUMP_COMPONENT_POLICY); - + DUMP_COMPONENT_SECLABEL | + DUMP_COMPONENT_POLICY); } return true; @@ -1338,15 +1355,11 @@ checkExtensionMembership(DumpableObject *dobj, Archive *fout) static void selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout) { - if (checkExtensionMembership(&nsinfo->dobj, fout)) - return; /* extension membership overrides all else */ - /* * If specific tables are being dumped, do not dump any complete * namespaces. If specific namespaces are being dumped, dump just those * namespaces. Otherwise, dump all non-system namespaces. */ - if (table_include_oids.head != NULL) nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE; else if (schema_include_oids.head != NULL) @@ -1355,18 +1368,21 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout) nsinfo->dobj.catId.oid) ? DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE; else if (fout->remoteVersion >= 90600 && - strncmp(nsinfo->dobj.name, "pg_catalog", - strlen("pg_catalog")) == 0) - + strcmp(nsinfo->dobj.name, "pg_catalog") == 0) + { /* * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if * they are interesting (and not the original ACLs which were set at * initdb time, see pg_init_privs). */ nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL; + } else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 || strcmp(nsinfo->dobj.name, "information_schema") == 0) + { + /* Other system schemas don't get dumped */ nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE; + } else nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL; @@ -1377,6 +1393,15 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout) simple_oid_list_member(&schema_exclude_oids, nsinfo->dobj.catId.oid)) nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE; + + /* + * If the schema belongs to an extension, allow extension membership to + * override the dump decision for the schema itself. However, this does + * not change dump_contains, so this won't change what we do with objects + * within the schema. (If they belong to the extension, they'll get + * suppressed by it, otherwise not.) + */ + (void) checkExtensionMembership(&nsinfo->dobj, fout); } /* @@ -1499,7 +1524,7 @@ selectDumpableCast(CastInfo *cast, Archive *fout) * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not * support ACLs currently. */ - if (cast->dobj.catId.oid < (Oid) FirstNormalObjectId) + if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid) cast->dobj.dump = DUMP_COMPONENT_NONE; else cast->dobj.dump = fout->dopt->include_everything ? @@ -1531,7 +1556,7 @@ selectDumpableProcLang(ProcLangInfo *plang, Archive *fout) plang->dobj.dump = DUMP_COMPONENT_NONE; else { - if (plang->dobj.catId.oid < (Oid) FirstNormalObjectId) + if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid) plang->dobj.dump = fout->remoteVersion < 90600 ? DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL; else @@ -1557,7 +1582,7 @@ selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout) * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but * they do not support ACLs currently. */ - if (method->dobj.catId.oid < (Oid) FirstNormalObjectId) + if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid) method->dobj.dump = DUMP_COMPONENT_NONE; else method->dobj.dump = fout->dopt->include_everything ? @@ -1582,7 +1607,7 @@ selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt) * change permissions on those objects, if they wish to, and have those * changes preserved. */ - if (dopt->binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId) + if (dopt->binary_upgrade && extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid) extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL; else extinfo->dobj.dump = extinfo->dobj.dump_contains = @@ -1653,15 +1678,12 @@ dumpTableData_copy(Archive *fout, void *dcontext) selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name); /* - * If possible, specify the column list explicitly so that we have no - * possibility of retrieving data in the wrong column order. (The default - * column ordering of COPY will not be what we want in certain corner - * cases involving ADD COLUMN and inheritance.) + * Specify the column list explicitly so that we have no possibility of + * retrieving data in the wrong column order. (The default column + * ordering of COPY will not be what we want in certain corner cases + * involving ADD COLUMN and inheritance.) */ - if (fout->remoteVersion >= 70300) - column_list = fmtCopyColumnList(tbinfo, clistBuf); - else - column_list = ""; /* can't select columns in COPY */ + column_list = fmtCopyColumnList(tbinfo, clistBuf); if (oids && hasoids) { @@ -1821,22 +1843,11 @@ dumpTableData_insert(Archive *fout, void *dcontext) */ selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name); - if (fout->remoteVersion >= 70100) - { - appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR " - "SELECT * FROM ONLY %s", - fmtQualifiedId(fout->remoteVersion, - tbinfo->dobj.namespace->dobj.name, - classname)); - } - else - { - appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR " - "SELECT * FROM %s", - fmtQualifiedId(fout->remoteVersion, - tbinfo->dobj.namespace->dobj.name, - classname)); - } + appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR " + "SELECT * FROM ONLY %s", + fmtQualifiedId(fout->remoteVersion, + tbinfo->dobj.namespace->dobj.name, + classname)); if (tdinfo->filtercond) appendPQExpBuffer(q, " %s", tdinfo->filtercond); @@ -2082,13 +2093,14 @@ refreshMatViewData(Archive *fout, TableDataInfo *tdinfo) * set up dumpable objects representing the contents of tables */ static void -getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids) +getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids, char relkind) { int i; for (i = 0; i < numTables; i++) { - if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA) + if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA && + (!relkind || tblinfo[i].relkind == relkind)) makeTableDataInfo(dopt, &(tblinfo[i]), oids); } } @@ -2117,6 +2129,9 @@ makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo, bool oids) /* Skip FOREIGN TABLEs (no data to dump) */ if (tbinfo->relkind == RELKIND_FOREIGN_TABLE) return; + /* Skip partitioned tables (data in partitions) */ + if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE) + return; /* Don't dump data in unlogged tables, if so requested */ if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED && @@ -2133,6 +2148,8 @@ makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo, bool oids) if (tbinfo->relkind == RELKIND_MATVIEW) tdinfo->dobj.objType = DO_REFRESH_MATVIEW; + else if (tbinfo->relkind == RELKIND_SEQUENCE) + tdinfo->dobj.objType = DO_SEQUENCE_SET; else tdinfo->dobj.objType = DO_TABLE_DATA; @@ -2472,7 +2489,7 @@ dumpDatabase(Archive *fout) username_subquery); appendStringLiteralAH(dbQry, datname, fout); } - else if (fout->remoteVersion >= 80000) + else { appendPQExpBuffer(dbQry, "SELECT tableoid, oid, " "(%s datdba) AS dba, " @@ -2484,34 +2501,6 @@ dumpDatabase(Archive *fout) username_subquery); appendStringLiteralAH(dbQry, datname, fout); } - else if (fout->remoteVersion >= 70100) - { - appendPQExpBuffer(dbQry, "SELECT tableoid, oid, " - "(%s datdba) AS dba, " - "pg_encoding_to_char(encoding) AS encoding, " - "NULL AS datcollate, NULL AS datctype, " - "0 AS datfrozenxid, 0 AS datminmxid, " - "NULL AS tablespace " - "FROM pg_database " - "WHERE datname = ", - username_subquery); - appendStringLiteralAH(dbQry, datname, fout); - } - else - { - appendPQExpBuffer(dbQry, "SELECT " - "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, " - "oid, " - "(%s datdba) AS dba, " - "pg_encoding_to_char(encoding) AS encoding, " - "NULL AS datcollate, NULL AS datctype, " - "0 AS datfrozenxid, 0 AS datminmxid, " - "NULL AS tablespace " - "FROM pg_database " - "WHERE datname = ", - username_subquery); - appendStringLiteralAH(dbQry, datname, fout); - } res = ExecuteSqlQueryForSingleRow(fout, dbQry->data); @@ -2552,7 +2541,8 @@ dumpDatabase(Archive *fout) appendPQExpBufferStr(creaQry, " LC_CTYPE = "); appendStringLiteralAH(creaQry, ctype, fout); } - if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0) + if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 && + !dopt->outputNoTablespaces) appendPQExpBuffer(creaQry, " TABLESPACE = %s", fmtId(tablespace)); appendPQExpBufferStr(creaQry, ";\n"); @@ -2866,22 +2856,17 @@ getBlobs(Archive *fout) else if (fout->remoteVersion >= 90000) appendPQExpBuffer(blobQry, "SELECT oid, (%s lomowner) AS rolname, lomacl, " - "NULL AS rlomacl, NULL as initlomacl, " - "NULL as initrlomacl " + "NULL AS rlomacl, NULL AS initlomacl, " + "NULL AS initrlomacl " " FROM pg_largeobject_metadata", username_subquery); - else if (fout->remoteVersion >= 70100) - appendPQExpBufferStr(blobQry, - "SELECT DISTINCT loid, NULL::oid, NULL, " - "NULL AS rlomacl, NULL AS initlomacl, " - "NULL AS initrlomacl " - " FROM pg_largeobject"); else appendPQExpBufferStr(blobQry, - "SELECT oid, NULL::oid, NULL, " - "NULL AS rlomacl, NULL AS initlomacl, " - "NULL AS initrlomacl " - " FROM pg_class WHERE relkind = 'l'"); + "SELECT DISTINCT loid AS oid, " + "NULL::name AS rolname, NULL::oid AS lomacl, " + "NULL::oid AS rlomacl, NULL::oid AS initlomacl, " + "NULL::oid AS initrlomacl " + " FROM pg_largeobject"); res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK); @@ -2913,11 +2898,11 @@ getBlobs(Archive *fout) binfo[i].initblobacl = pg_strdup(PQgetvalue(res, i, i_initlomacl)); binfo[i].initrblobacl = pg_strdup(PQgetvalue(res, i, i_initrlomacl)); - if (PQgetisnull(res, i, i_lomacl) && PQgetisnull(res, i, i_rlomacl) && + if (PQgetisnull(res, i, i_lomacl) && + PQgetisnull(res, i, i_rlomacl) && PQgetisnull(res, i, i_initlomacl) && PQgetisnull(res, i, i_initrlomacl)) binfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL; - } /* @@ -3021,10 +3006,8 @@ dumpBlobs(Archive *fout, void *arg) */ if (fout->remoteVersion >= 90000) blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata"; - else if (fout->remoteVersion >= 70100) - blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject"; else - blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'"; + blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject"; ExecuteSqlStatement(fout, blobQry); @@ -3088,6 +3071,7 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables) int i_tableoid; int i_polname; int i_polcmd; + int i_polpermissive; int i_polroles; int i_polqual; int i_polwithcheck; @@ -3133,7 +3117,8 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables) polinfo->dobj.name = pg_strdup(tbinfo->dobj.name); polinfo->poltable = tbinfo; polinfo->polname = NULL; - polinfo->polcmd = NULL; + polinfo->polcmd = '\0'; + polinfo->polpermissive = 0; polinfo->polroles = NULL; polinfo->polqual = NULL; polinfo->polwithcheck = NULL; @@ -3152,15 +3137,26 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables) resetPQExpBuffer(query); /* Get the policies for the table. */ - appendPQExpBuffer(query, - "SELECT oid, tableoid, pol.polname, pol.polcmd, " - "CASE WHEN pol.polroles = '{0}' THEN 'PUBLIC' ELSE " - " pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(rolname) from pg_catalog.pg_roles WHERE oid = ANY(pol.polroles)), ', ') END AS polroles, " - "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, " - "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck " - "FROM pg_catalog.pg_policy pol " - "WHERE polrelid = '%u'", - tbinfo->dobj.catId.oid); + if (fout->remoteVersion >= 100000) + appendPQExpBuffer(query, + "SELECT oid, tableoid, pol.polname, pol.polcmd, pol.polpermissive, " + "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE " + " pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(rolname) from pg_catalog.pg_roles WHERE oid = ANY(pol.polroles)), ', ') END AS polroles, " + "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, " + "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck " + "FROM pg_catalog.pg_policy pol " + "WHERE polrelid = '%u'", + tbinfo->dobj.catId.oid); + else + appendPQExpBuffer(query, + "SELECT oid, tableoid, pol.polname, pol.polcmd, 't' as polpermissive, " + "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE " + " pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(rolname) from pg_catalog.pg_roles WHERE oid = ANY(pol.polroles)), ', ') END AS polroles, " + "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, " + "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck " + "FROM pg_catalog.pg_policy pol " + "WHERE polrelid = '%u'", + tbinfo->dobj.catId.oid); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); ntups = PQntuples(res); @@ -3180,6 +3176,7 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables) i_tableoid = PQfnumber(res, "tableoid"); i_polname = PQfnumber(res, "polname"); i_polcmd = PQfnumber(res, "polcmd"); + i_polpermissive = PQfnumber(res, "polpermissive"); i_polroles = PQfnumber(res, "polroles"); i_polqual = PQfnumber(res, "polqual"); i_polwithcheck = PQfnumber(res, "polwithcheck"); @@ -3198,8 +3195,13 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables) polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname)); polinfo[j].dobj.name = pg_strdup(polinfo[j].polname); - polinfo[j].polcmd = pg_strdup(PQgetvalue(res, j, i_polcmd)); - polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles)); + polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd)); + polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't'; + + if (PQgetisnull(res, j, i_polroles)) + polinfo[j].polroles = NULL; + else + polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles)); if (PQgetisnull(res, j, i_polqual)) polinfo[j].polqual = NULL; @@ -3261,19 +3263,19 @@ dumpPolicy(Archive *fout, PolicyInfo *polinfo) return; } - if (strcmp(polinfo->polcmd, "*") == 0) - cmd = "ALL"; - else if (strcmp(polinfo->polcmd, "r") == 0) - cmd = "SELECT"; - else if (strcmp(polinfo->polcmd, "a") == 0) - cmd = "INSERT"; - else if (strcmp(polinfo->polcmd, "w") == 0) - cmd = "UPDATE"; - else if (strcmp(polinfo->polcmd, "d") == 0) - cmd = "DELETE"; + if (polinfo->polcmd == '*') + cmd = ""; + else if (polinfo->polcmd == 'r') + cmd = " FOR SELECT"; + else if (polinfo->polcmd == 'a') + cmd = " FOR INSERT"; + else if (polinfo->polcmd == 'w') + cmd = " FOR UPDATE"; + else if (polinfo->polcmd == 'd') + cmd = " FOR DELETE"; else { - write_msg(NULL, "unexpected policy command type: \"%s\"\n", + write_msg(NULL, "unexpected policy command type: %c\n", polinfo->polcmd); exit_nicely(1); } @@ -3282,7 +3284,9 @@ dumpPolicy(Archive *fout, PolicyInfo *polinfo) delqry = createPQExpBuffer(); appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname)); - appendPQExpBuffer(query, " ON %s FOR %s", fmtId(tbinfo->dobj.name), cmd); + + appendPQExpBuffer(query, " ON %s%s%s", fmtId(tbinfo->dobj.name), + !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd); if (polinfo->polroles != NULL) appendPQExpBuffer(query, " TO %s", polinfo->polroles); @@ -3316,160 +3320,603 @@ dumpPolicy(Archive *fout, PolicyInfo *polinfo) destroyPQExpBuffer(delqry); } -static void -binary_upgrade_set_type_oids_by_type_oid(Archive *fout, - PQExpBuffer upgrade_buffer, - Oid pg_type_oid) +/* + * getPublications + * get information about publications + */ +void +getPublications(Archive *fout) { - PQExpBuffer upgrade_query = createPQExpBuffer(); - PGresult *upgrade_res; - Oid pg_type_array_oid; - - appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n"); - appendPQExpBuffer(upgrade_buffer, - "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n", - pg_type_oid); - - /* we only support old >= 8.3 for binary upgrades */ - appendPQExpBuffer(upgrade_query, - "SELECT typarray " - "FROM pg_catalog.pg_type " - "WHERE pg_type.oid = '%u'::pg_catalog.oid;", - pg_type_oid); + PQExpBuffer query; + PGresult *res; + PublicationInfo *pubinfo; + int i_tableoid; + int i_oid; + int i_pubname; + int i_rolname; + int i_puballtables; + int i_pubinsert; + int i_pubupdate; + int i_pubdelete; + int i, + ntups; - upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data); + if (fout->remoteVersion < 100000) + return; - pg_type_array_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "typarray"))); + query = createPQExpBuffer(); - if (OidIsValid(pg_type_array_oid)) - { - appendPQExpBufferStr(upgrade_buffer, - "\n-- For binary upgrade, must preserve pg_type array oid\n"); - appendPQExpBuffer(upgrade_buffer, - "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n", - pg_type_array_oid); - } + resetPQExpBuffer(query); - PQclear(upgrade_res); - destroyPQExpBuffer(upgrade_query); -} + /* Get the publications. */ + appendPQExpBuffer(query, + "SELECT p.tableoid, p.oid, p.pubname, " + "(%s p.pubowner) AS rolname, " + "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete " + "FROM pg_catalog.pg_publication p", + username_subquery); -static bool -binary_upgrade_set_type_oids_by_rel_oid(Archive *fout, - PQExpBuffer upgrade_buffer, - Oid pg_rel_oid) -{ - PQExpBuffer upgrade_query = createPQExpBuffer(); - PGresult *upgrade_res; - Oid pg_type_oid; - bool toast_set = false; + res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); - /* we only support old >= 8.3 for binary upgrades */ - appendPQExpBuffer(upgrade_query, - "SELECT c.reltype AS crel, t.reltype AS trel " - "FROM pg_catalog.pg_class c " - "LEFT JOIN pg_catalog.pg_class t ON " - " (c.reltoastrelid = t.oid) " - "WHERE c.oid = '%u'::pg_catalog.oid;", - pg_rel_oid); + ntups = PQntuples(res); - upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data); + if (ntups == 0) + { + /* + * There are no publications defined. Clean up and return. + */ + PQclear(res); + return; + } - pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel"))); + i_tableoid = PQfnumber(res, "tableoid"); + i_oid = PQfnumber(res, "oid"); + i_pubname = PQfnumber(res, "pubname"); + i_rolname = PQfnumber(res, "rolname"); + i_puballtables = PQfnumber(res, "puballtables"); + i_pubinsert = PQfnumber(res, "pubinsert"); + i_pubupdate = PQfnumber(res, "pubupdate"); + i_pubdelete = PQfnumber(res, "pubdelete"); - binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer, - pg_type_oid); + pubinfo = pg_malloc(ntups * sizeof(PublicationInfo)); - if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel"))) + for (i = 0; i < ntups; i++) { - /* Toast tables do not have pg_type array rows */ - Oid pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0, - PQfnumber(upgrade_res, "trel"))); - - appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n"); - appendPQExpBuffer(upgrade_buffer, - "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n", - pg_type_toast_oid); - - toast_set = true; + pubinfo[i].dobj.objType = DO_PUBLICATION; + pubinfo[i].dobj.catId.tableoid = + atooid(PQgetvalue(res, i, i_tableoid)); + pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid)); + AssignDumpId(&pubinfo[i].dobj); + pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname)); + pubinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname)); + pubinfo[i].puballtables = + (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0); + pubinfo[i].pubinsert = + (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0); + pubinfo[i].pubupdate = + (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0); + pubinfo[i].pubdelete = + (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0); + + if (strlen(pubinfo[i].rolname) == 0) + write_msg(NULL, "WARNING: owner of publication \"%s\" appears to be invalid\n", + pubinfo[i].dobj.name); } + PQclear(res); - PQclear(upgrade_res); - destroyPQExpBuffer(upgrade_query); - - return toast_set; + destroyPQExpBuffer(query); } +/* + * dumpPublication + * dump the definition of the given publication + */ static void -binary_upgrade_set_pg_class_oids(Archive *fout, - PQExpBuffer upgrade_buffer, Oid pg_class_oid, - bool is_index) +dumpPublication(Archive *fout, PublicationInfo *pubinfo) { - PQExpBuffer upgrade_query = createPQExpBuffer(); - PGresult *upgrade_res; - Oid pg_class_reltoastrelid; - Oid pg_index_indexrelid; + DumpOptions *dopt = fout->dopt; + PQExpBuffer delq; + PQExpBuffer query; - appendPQExpBuffer(upgrade_query, - "SELECT c.reltoastrelid, i.indexrelid " - "FROM pg_catalog.pg_class c LEFT JOIN " - "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) " - "WHERE c.oid = '%u'::pg_catalog.oid;", - pg_class_oid); + if (dopt->dataOnly) + return; - upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data); + delq = createPQExpBuffer(); + query = createPQExpBuffer(); - pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid"))); - pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid"))); + appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n", + fmtId(pubinfo->dobj.name)); - appendPQExpBufferStr(upgrade_buffer, - "\n-- For binary upgrade, must preserve pg_class oids\n"); + appendPQExpBuffer(query, "CREATE PUBLICATION %s", + fmtId(pubinfo->dobj.name)); - if (!is_index) - { - appendPQExpBuffer(upgrade_buffer, - "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n", - pg_class_oid); - /* only tables have toast tables, not indexes */ - if (OidIsValid(pg_class_reltoastrelid)) - { - /* - * One complexity is that the table definition might not require - * the creation of a TOAST table, and the TOAST table might have - * been created long after table creation, when the table was - * loaded with wide data. By setting the TOAST oid we force - * creation of the TOAST heap and TOAST index by the backend so we - * can cleanly copy the files during binary upgrade. - */ + if (pubinfo->puballtables) + appendPQExpBufferStr(query, " FOR ALL TABLES"); - appendPQExpBuffer(upgrade_buffer, - "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n", - pg_class_reltoastrelid); + appendPQExpBufferStr(query, " WITH ("); + if (pubinfo->pubinsert) + appendPQExpBufferStr(query, "PUBLISH INSERT"); + else + appendPQExpBufferStr(query, "NOPUBLISH INSERT"); - /* every toast table has an index */ - appendPQExpBuffer(upgrade_buffer, - "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n", - pg_index_indexrelid); - } - } + if (pubinfo->pubupdate) + appendPQExpBufferStr(query, ", PUBLISH UPDATE"); else - appendPQExpBuffer(upgrade_buffer, - "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n", - pg_class_oid); + appendPQExpBufferStr(query, ", NOPUBLISH UPDATE"); - appendPQExpBufferChar(upgrade_buffer, '\n'); + if (pubinfo->pubdelete) + appendPQExpBufferStr(query, ", PUBLISH DELETE"); + else + appendPQExpBufferStr(query, ", NOPUBLISH DELETE"); - PQclear(upgrade_res); - destroyPQExpBuffer(upgrade_query); + appendPQExpBufferStr(query, ");\n"); + + ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId, + pubinfo->dobj.name, + NULL, + NULL, + pubinfo->rolname, false, + "PUBLICATION", SECTION_POST_DATA, + query->data, delq->data, NULL, + NULL, 0, + NULL, NULL); + + destroyPQExpBuffer(delq); + destroyPQExpBuffer(query); } /* - * If the DumpableObject is a member of an extension, add a suitable - * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer. + * getPublicationTables + * get information about publication membership for dumpable tables. */ -static void -binary_upgrade_extension_member(PQExpBuffer upgrade_buffer, - DumpableObject *dobj, +void +getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables) +{ + PQExpBuffer query; + PGresult *res; + PublicationRelInfo *pubrinfo; + int i_tableoid; + int i_oid; + int i_pubname; + int i, + j, + ntups; + + if (fout->remoteVersion < 100000) + return; + + query = createPQExpBuffer(); + + for (i = 0; i < numTables; i++) + { + TableInfo *tbinfo = &tblinfo[i]; + + /* Only plain tables can be aded to publications. */ + if (tbinfo->relkind != RELKIND_RELATION) + continue; + + /* + * Ignore publication membership of tables whose definitions are + * not to be dumped. + */ + if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)) + continue; + + if (g_verbose) + write_msg(NULL, "reading publication membership for table \"%s.%s\"\n", + tbinfo->dobj.namespace->dobj.name, + tbinfo->dobj.name); + + resetPQExpBuffer(query); + + /* Get the publication memebership for the table. */ + appendPQExpBuffer(query, + "SELECT pr.tableoid, pr.oid, p.pubname " + "FROM pg_catalog.pg_publication_rel pr," + " pg_catalog.pg_publication p " + "WHERE pr.prrelid = '%u'" + " AND p.oid = pr.prpubid", + tbinfo->dobj.catId.oid); + res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); + + ntups = PQntuples(res); + + if (ntups == 0) + { + /* + * Table is not member of any publications. Clean up and return. + */ + PQclear(res); + continue; + } + + i_tableoid = PQfnumber(res, "tableoid"); + i_oid = PQfnumber(res, "oid"); + i_pubname = PQfnumber(res, "pubname"); + + pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo)); + + for (j = 0; j < ntups; j++) + { + pubrinfo[j].dobj.objType = DO_PUBLICATION_REL; + pubrinfo[j].dobj.catId.tableoid = + atooid(PQgetvalue(res, j, i_tableoid)); + pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid)); + AssignDumpId(&pubrinfo[j].dobj); + pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace; + pubrinfo[j].pubname = pg_strdup(PQgetvalue(res, j, i_pubname)); + pubrinfo[j].pubtable = tbinfo; + } + PQclear(res); + } + destroyPQExpBuffer(query); +} + +/* + * dumpPublicationTable + * dump the definition of the given publication table mapping + */ +static void +dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo) +{ + DumpOptions *dopt = fout->dopt; + TableInfo *tbinfo = pubrinfo->pubtable; + PQExpBuffer query; + char *tag; + + if (dopt->dataOnly) + return; + + tag = psprintf("%s %s", pubrinfo->pubname, tbinfo->dobj.name); + + query = createPQExpBuffer(); + + appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE", + fmtId(pubrinfo->pubname)); + appendPQExpBuffer(query, " %s;", + fmtId(tbinfo->dobj.name)); + + /* + * There is no point in creating drop query as drop query as the drop + * is done by table drop. + */ + ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId, + tag, + tbinfo->dobj.namespace->dobj.name, + NULL, + "", false, + "PUBLICATION TABLE", SECTION_POST_DATA, + query->data, "", NULL, + NULL, 0, + NULL, NULL); + + free(tag); + destroyPQExpBuffer(query); +} + + +/* + * getSubscriptions + * get information about subscriptions + */ +void +getSubscriptions(Archive *fout) +{ + DumpOptions *dopt = fout->dopt; + PQExpBuffer query; + PGresult *res; + SubscriptionInfo *subinfo; + int i_tableoid; + int i_oid; + int i_subname; + int i_rolname; + int i_subenabled; + int i_subconninfo; + int i_subslotname; + int i_subpublications; + int i, + ntups; + + if (!dopt->include_subscriptions || fout->remoteVersion < 100000) + return; + + query = createPQExpBuffer(); + + resetPQExpBuffer(query); + + /* Get the subscriptions in current database. */ + appendPQExpBuffer(query, + "SELECT s.tableoid, s.oid, s.subname," + "(%s s.subowner) AS rolname, s.subenabled, " + " s.subconninfo, s.subslotname, s.subpublications " + "FROM pg_catalog.pg_subscription s " + "WHERE s.subdbid = (SELECT oid FROM pg_catalog.pg_database" + " WHERE datname = current_database())", + username_subquery); + res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); + + ntups = PQntuples(res); + + if (ntups == 0) + { + /* + * There are no subscriptions defined. Clean up and return. + */ + PQclear(res); + return; + } + + i_tableoid = PQfnumber(res, "tableoid"); + i_oid = PQfnumber(res, "oid"); + i_subname = PQfnumber(res, "subname"); + i_rolname = PQfnumber(res, "rolname"); + i_subenabled = PQfnumber(res, "subenabled"); + i_subconninfo = PQfnumber(res, "subconninfo"); + i_subslotname = PQfnumber(res, "subslotname"); + i_subpublications = PQfnumber(res, "subpublications"); + + subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo)); + + for (i = 0; i < ntups; i++) + { + subinfo[i].dobj.objType = DO_SUBSCRIPTION; + subinfo[i].dobj.catId.tableoid = + atooid(PQgetvalue(res, i, i_tableoid)); + subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid)); + AssignDumpId(&subinfo[i].dobj); + subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname)); + subinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname)); + subinfo[i].subenabled = + (strcmp(PQgetvalue(res, i, i_subenabled), "t") == 0); + subinfo[i].subconninfo = pg_strdup(PQgetvalue(res, i, i_subconninfo)); + subinfo[i].subslotname = pg_strdup(PQgetvalue(res, i, i_subslotname)); + subinfo[i].subpublications = + pg_strdup(PQgetvalue(res, i, i_subpublications)); + + if (strlen(subinfo[i].rolname) == 0) + write_msg(NULL, "WARNING: owner of subscription \"%s\" appears to be invalid\n", + subinfo[i].dobj.name); + } + PQclear(res); + + destroyPQExpBuffer(query); +} + +/* + * dumpSubscription + * dump the definition of the given subscription + */ +static void +dumpSubscription(Archive *fout, SubscriptionInfo *subinfo) +{ + DumpOptions *dopt = fout->dopt; + PQExpBuffer delq; + PQExpBuffer query; + PQExpBuffer publications; + char **pubnames = NULL; + int npubnames = 0; + int i; + + if (dopt->dataOnly) + return; + + delq = createPQExpBuffer(); + query = createPQExpBuffer(); + + appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n", + fmtId(subinfo->dobj.name)); + + appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ", + fmtId(subinfo->dobj.name)); + appendStringLiteralAH(query, subinfo->subconninfo, fout); + + /* Build list of quoted publications and append them to query. */ + if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames)) + { + write_msg(NULL, + "WARNING: could not parse subpublications array\n"); + if (pubnames) + free(pubnames); + pubnames = NULL; + npubnames = 0; + } + + publications = createPQExpBuffer(); + for (i = 0; i < npubnames; i++) + { + if (i > 0) + appendPQExpBufferStr(publications, ", "); + + appendPQExpBufferStr(publications, fmtId(pubnames[i])); + } + + appendPQExpBuffer(query, " PUBLICATION %s WITH (", publications->data); + + if (subinfo->subenabled) + appendPQExpBufferStr(query, "ENABLED"); + else + appendPQExpBufferStr(query, "DISABLED"); + + appendPQExpBufferStr(query, ", SLOT NAME = "); + appendStringLiteralAH(query, subinfo->subslotname, fout); + + if (dopt->no_create_subscription_slots) + appendPQExpBufferStr(query, ", NOCREATE SLOT"); + + appendPQExpBufferStr(query, ");\n"); + + ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId, + subinfo->dobj.name, + NULL, + NULL, + subinfo->rolname, false, + "SUBSCRIPTION", SECTION_POST_DATA, + query->data, delq->data, NULL, + NULL, 0, + NULL, NULL); + + destroyPQExpBuffer(publications); + if (pubnames) + free(pubnames); + + destroyPQExpBuffer(delq); + destroyPQExpBuffer(query); +} + +static void +binary_upgrade_set_type_oids_by_type_oid(Archive *fout, + PQExpBuffer upgrade_buffer, + Oid pg_type_oid) +{ + PQExpBuffer upgrade_query = createPQExpBuffer(); + PGresult *upgrade_res; + Oid pg_type_array_oid; + + appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n"); + appendPQExpBuffer(upgrade_buffer, + "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n", + pg_type_oid); + + /* we only support old >= 8.3 for binary upgrades */ + appendPQExpBuffer(upgrade_query, + "SELECT typarray " + "FROM pg_catalog.pg_type " + "WHERE pg_type.oid = '%u'::pg_catalog.oid;", + pg_type_oid); + + upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data); + + pg_type_array_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "typarray"))); + + if (OidIsValid(pg_type_array_oid)) + { + appendPQExpBufferStr(upgrade_buffer, + "\n-- For binary upgrade, must preserve pg_type array oid\n"); + appendPQExpBuffer(upgrade_buffer, + "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n", + pg_type_array_oid); + } + + PQclear(upgrade_res); + destroyPQExpBuffer(upgrade_query); +} + +static bool +binary_upgrade_set_type_oids_by_rel_oid(Archive *fout, + PQExpBuffer upgrade_buffer, + Oid pg_rel_oid) +{ + PQExpBuffer upgrade_query = createPQExpBuffer(); + PGresult *upgrade_res; + Oid pg_type_oid; + bool toast_set = false; + + /* we only support old >= 8.3 for binary upgrades */ + appendPQExpBuffer(upgrade_query, + "SELECT c.reltype AS crel, t.reltype AS trel " + "FROM pg_catalog.pg_class c " + "LEFT JOIN pg_catalog.pg_class t ON " + " (c.reltoastrelid = t.oid) " + "WHERE c.oid = '%u'::pg_catalog.oid;", + pg_rel_oid); + + upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data); + + pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel"))); + + binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer, + pg_type_oid); + + if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel"))) + { + /* Toast tables do not have pg_type array rows */ + Oid pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0, + PQfnumber(upgrade_res, "trel"))); + + appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n"); + appendPQExpBuffer(upgrade_buffer, + "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n", + pg_type_toast_oid); + + toast_set = true; + } + + PQclear(upgrade_res); + destroyPQExpBuffer(upgrade_query); + + return toast_set; +} + +static void +binary_upgrade_set_pg_class_oids(Archive *fout, + PQExpBuffer upgrade_buffer, Oid pg_class_oid, + bool is_index) +{ + PQExpBuffer upgrade_query = createPQExpBuffer(); + PGresult *upgrade_res; + Oid pg_class_reltoastrelid; + Oid pg_index_indexrelid; + + appendPQExpBuffer(upgrade_query, + "SELECT c.reltoastrelid, i.indexrelid " + "FROM pg_catalog.pg_class c LEFT JOIN " + "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) " + "WHERE c.oid = '%u'::pg_catalog.oid;", + pg_class_oid); + + upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data); + + pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid"))); + pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid"))); + + appendPQExpBufferStr(upgrade_buffer, + "\n-- For binary upgrade, must preserve pg_class oids\n"); + + if (!is_index) + { + appendPQExpBuffer(upgrade_buffer, + "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n", + pg_class_oid); + /* only tables have toast tables, not indexes */ + if (OidIsValid(pg_class_reltoastrelid)) + { + /* + * One complexity is that the table definition might not require + * the creation of a TOAST table, and the TOAST table might have + * been created long after table creation, when the table was + * loaded with wide data. By setting the TOAST oid we force + * creation of the TOAST heap and TOAST index by the backend so we + * can cleanly copy the files during binary upgrade. + */ + + appendPQExpBuffer(upgrade_buffer, + "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n", + pg_class_reltoastrelid); + + /* every toast table has an index */ + appendPQExpBuffer(upgrade_buffer, + "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n", + pg_index_indexrelid); + } + } + else + appendPQExpBuffer(upgrade_buffer, + "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n", + pg_class_oid); + + appendPQExpBufferChar(upgrade_buffer, '\n'); + + PQclear(upgrade_res); + destroyPQExpBuffer(upgrade_query); +} + +/* + * If the DumpableObject is a member of an extension, add a suitable + * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer. + */ +static void +binary_upgrade_extension_member(PQExpBuffer upgrade_buffer, + DumpableObject *dobj, const char *objlabel) { DumpableObject *extobj = NULL; @@ -3526,45 +3973,6 @@ getNamespaces(Archive *fout, int *numNamespaces) int i_initnspacl; int i_initrnspacl; - /* - * Before 7.3, there are no real namespaces; create two dummy entries, one - * for user stuff and one for system stuff. - */ - if (fout->remoteVersion < 70300) - { - nsinfo = (NamespaceInfo *) pg_malloc(2 * sizeof(NamespaceInfo)); - - nsinfo[0].dobj.objType = DO_NAMESPACE; - nsinfo[0].dobj.catId.tableoid = 0; - nsinfo[0].dobj.catId.oid = 0; - AssignDumpId(&nsinfo[0].dobj); - nsinfo[0].dobj.name = pg_strdup("public"); - nsinfo[0].rolname = pg_strdup(""); - nsinfo[0].nspacl = pg_strdup(""); - nsinfo[0].rnspacl = pg_strdup(""); - nsinfo[0].initnspacl = pg_strdup(""); - nsinfo[0].initrnspacl = pg_strdup(""); - - selectDumpableNamespace(&nsinfo[0], fout); - - nsinfo[1].dobj.objType = DO_NAMESPACE; - nsinfo[1].dobj.catId.tableoid = 0; - nsinfo[1].dobj.catId.oid = 1; - AssignDumpId(&nsinfo[1].dobj); - nsinfo[1].dobj.name = pg_strdup("pg_catalog"); - nsinfo[1].rolname = pg_strdup(""); - nsinfo[1].nspacl = pg_strdup(""); - nsinfo[1].rnspacl = pg_strdup(""); - nsinfo[1].initnspacl = pg_strdup(""); - nsinfo[1].initrnspacl = pg_strdup(""); - - selectDumpableNamespace(&nsinfo[1], fout); - - *numNamespaces = 2; - - return nsinfo; - } - query = createPQExpBuffer(); /* Make sure we are in proper schema */ @@ -3674,37 +4082,16 @@ getNamespaces(Archive *fout, int *numNamespaces) /* * findNamespace: - * given a namespace OID and an object OID, look up the info read by - * getNamespaces - * - * NB: for pre-7.3 source database, we use object OID to guess whether it's - * a system object or not. In 7.3 and later there is no guessing, and we - * don't use objoid at all. + * given a namespace OID, look up the info read by getNamespaces */ static NamespaceInfo * -findNamespace(Archive *fout, Oid nsoid, Oid objoid) +findNamespace(Archive *fout, Oid nsoid) { NamespaceInfo *nsinfo; - if (fout->remoteVersion >= 70300) - { - nsinfo = findNamespaceByOid(nsoid); - } - else - { - /* This code depends on the dummy objects set up by getNamespaces. */ - Oid i; - - if (objoid > g_last_builtin_oid) - i = 0; /* user object */ - else - i = 1; /* system object */ - nsinfo = findNamespaceByOid(i); - } - + nsinfo = findNamespaceByOid(nsoid); if (nsinfo == NULL) exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid); - return nsinfo; } @@ -3821,8 +4208,6 @@ getTypes(Archive *fout, int *numTypes) int i_inittypacl; int i_initrtypacl; int i_rolname; - int i_typinput; - int i_typoutput; int i_typelem; int i_typrelid; int i_typrelkind; @@ -3867,8 +4252,7 @@ getTypes(Archive *fout, int *numTypes) "%s AS inittypacl, " "%s AS initrtypacl, " "(%s t.typowner) AS rolname, " - "t.typinput::oid AS typinput, " - "t.typoutput::oid AS typoutput, t.typelem, t.typrelid, " + "t.typelem, t.typrelid, " "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" " "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, " "t.typtype, t.typisdefined, " @@ -3896,8 +4280,7 @@ getTypes(Archive *fout, int *numTypes) "typnamespace, typacl, NULL as rtypacl, " "NULL AS inittypacl, NULL AS initrtypacl, " "(%s typowner) AS rolname, " - "typinput::oid AS typinput, " - "typoutput::oid AS typoutput, typelem, typrelid, " + "typelem, typrelid, " "CASE WHEN typrelid = 0 THEN ' '::\"char\" " "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, " "typtype, typisdefined, " @@ -3912,8 +4295,7 @@ getTypes(Archive *fout, int *numTypes) "typnamespace, NULL AS typacl, NULL as rtypacl, " "NULL AS inittypacl, NULL AS initrtypacl, " "(%s typowner) AS rolname, " - "typinput::oid AS typinput, " - "typoutput::oid AS typoutput, typelem, typrelid, " + "typelem, typrelid, " "CASE WHEN typrelid = 0 THEN ' '::\"char\" " "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, " "typtype, typisdefined, " @@ -3922,46 +4304,13 @@ getTypes(Archive *fout, int *numTypes) "FROM pg_type", username_subquery); } - else if (fout->remoteVersion >= 70300) + else { appendPQExpBuffer(query, "SELECT tableoid, oid, typname, " "typnamespace, NULL AS typacl, NULL as rtypacl, " "NULL AS inittypacl, NULL AS initrtypacl, " "(%s typowner) AS rolname, " - "typinput::oid AS typinput, " - "typoutput::oid AS typoutput, typelem, typrelid, " - "CASE WHEN typrelid = 0 THEN ' '::\"char\" " - "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, " - "typtype, typisdefined, " - "typname[0] = '_' AND typelem != 0 AS isarray " - "FROM pg_type", - username_subquery); - } - else if (fout->remoteVersion >= 70100) - { - appendPQExpBuffer(query, "SELECT tableoid, oid, typname, " - "0::oid AS typnamespace, NULL AS typacl, NULL as rtypacl, " - "NULL AS inittypacl, NULL AS initrtypacl, " - "(%s typowner) AS rolname, " - "typinput::oid AS typinput, " - "typoutput::oid AS typoutput, typelem, typrelid, " - "CASE WHEN typrelid = 0 THEN ' '::\"char\" " - "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, " - "typtype, typisdefined, " - "typname[0] = '_' AND typelem != 0 AS isarray " - "FROM pg_type", - username_subquery); - } - else - { - appendPQExpBuffer(query, "SELECT " - "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, " - "oid, typname, " - "0::oid AS typnamespace, NULL AS typacl, NULL as rtypacl, " - "NULL AS inittypacl, NULL AS initrtypacl, " - "(%s typowner) AS rolname, " - "typinput::oid AS typinput, " - "typoutput::oid AS typoutput, typelem, typrelid, " + "typelem, typrelid, " "CASE WHEN typrelid = 0 THEN ' '::\"char\" " "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, " "typtype, typisdefined, " @@ -3985,8 +4334,6 @@ getTypes(Archive *fout, int *numTypes) i_inittypacl = PQfnumber(res, "inittypacl"); i_initrtypacl = PQfnumber(res, "initrtypacl"); i_rolname = PQfnumber(res, "rolname"); - i_typinput = PQfnumber(res, "typinput"); - i_typoutput = PQfnumber(res, "typoutput"); i_typelem = PQfnumber(res, "typelem"); i_typrelid = PQfnumber(res, "typrelid"); i_typrelkind = PQfnumber(res, "typrelkind"); @@ -4003,8 +4350,7 @@ getTypes(Archive *fout, int *numTypes) tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname)); tyinfo[i].dobj.namespace = findNamespace(fout, - atooid(PQgetvalue(res, i, i_typnamespace)), - tyinfo[i].dobj.catId.oid); + atooid(PQgetvalue(res, i, i_typnamespace))); tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname)); tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl)); tyinfo[i].rtypacl = pg_strdup(PQgetvalue(res, i, i_rtypacl)); @@ -4073,48 +4419,6 @@ getTypes(Archive *fout, int *numTypes) * this is taken care of while sorting dependencies. */ stinfo->dobj.dump = DUMP_COMPONENT_NONE; - - /* - * However, if dumping from pre-7.3, there will be no dependency - * info so we have to fake it here. We only need to worry about - * typinput and typoutput since the other functions only exist - * post-7.3. - */ - if (fout->remoteVersion < 70300) - { - Oid typinput; - Oid typoutput; - FuncInfo *funcInfo; - - typinput = atooid(PQgetvalue(res, i, i_typinput)); - typoutput = atooid(PQgetvalue(res, i, i_typoutput)); - - funcInfo = findFuncByOid(typinput); - if (funcInfo && funcInfo->dobj.dump & DUMP_COMPONENT_DEFINITION) - { - /* base type depends on function */ - addObjectDependency(&tyinfo[i].dobj, - funcInfo->dobj.dumpId); - /* function depends on shell type */ - addObjectDependency(&funcInfo->dobj, - stinfo->dobj.dumpId); - /* mark shell type as to be dumped */ - stinfo->dobj.dump = DUMP_COMPONENT_ALL; - } - - funcInfo = findFuncByOid(typoutput); - if (funcInfo && funcInfo->dobj.dump & DUMP_COMPONENT_DEFINITION) - { - /* base type depends on function */ - addObjectDependency(&tyinfo[i].dobj, - funcInfo->dobj.dumpId); - /* function depends on shell type */ - addObjectDependency(&funcInfo->dobj, - stinfo->dobj.dumpId); - /* mark shell type as to be dumped */ - stinfo->dobj.dump = DUMP_COMPONENT_ALL; - } - } } if (strlen(tyinfo[i].rolname) == 0) @@ -4162,38 +4466,13 @@ getOperators(Archive *fout, int *numOprs) /* Make sure we are in proper schema */ selectSourceSchema(fout, "pg_catalog"); - if (fout->remoteVersion >= 70300) - { - appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, " - "oprnamespace, " - "(%s oprowner) AS rolname, " - "oprkind, " - "oprcode::oid AS oprcode " - "FROM pg_operator", - username_subquery); - } - else if (fout->remoteVersion >= 70100) - { - appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, " - "0::oid AS oprnamespace, " - "(%s oprowner) AS rolname, " - "oprkind, " - "oprcode::oid AS oprcode " - "FROM pg_operator", - username_subquery); - } - else - { - appendPQExpBuffer(query, "SELECT " - "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, " - "oid, oprname, " - "0::oid AS oprnamespace, " - "(%s oprowner) AS rolname, " - "oprkind, " - "oprcode::oid AS oprcode " - "FROM pg_operator", - username_subquery); - } + appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, " + "oprnamespace, " + "(%s oprowner) AS rolname, " + "oprkind, " + "oprcode::oid AS oprcode " + "FROM pg_operator", + username_subquery); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -4219,8 +4498,7 @@ getOperators(Archive *fout, int *numOprs) oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname)); oprinfo[i].dobj.namespace = findNamespace(fout, - atooid(PQgetvalue(res, i, i_oprnamespace)), - oprinfo[i].dobj.catId.oid); + atooid(PQgetvalue(res, i, i_oprnamespace))); oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname)); oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0]; oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode)); @@ -4309,8 +4587,7 @@ getCollations(Archive *fout, int *numCollations) collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname)); collinfo[i].dobj.namespace = findNamespace(fout, - atooid(PQgetvalue(res, i, i_collnamespace)), - collinfo[i].dobj.catId.oid); + atooid(PQgetvalue(res, i, i_collnamespace))); collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname)); /* Decide whether we want to dump it */ @@ -4348,13 +4625,6 @@ getConversions(Archive *fout, int *numConversions) int i_connamespace; int i_rolname; - /* Conversions didn't exist pre-7.3 */ - if (fout->remoteVersion < 70300) - { - *numConversions = 0; - return NULL; - } - query = createPQExpBuffer(); /* @@ -4393,8 +4663,7 @@ getConversions(Archive *fout, int *numConversions) convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname)); convinfo[i].dobj.namespace = findNamespace(fout, - atooid(PQgetvalue(res, i, i_connamespace)), - convinfo[i].dobj.catId.oid); + atooid(PQgetvalue(res, i, i_connamespace))); convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname)); /* Decide whether we want to dump it */ @@ -4517,30 +4786,11 @@ getOpclasses(Archive *fout, int *numOpclasses) /* Make sure we are in proper schema */ selectSourceSchema(fout, "pg_catalog"); - if (fout->remoteVersion >= 70300) - { - appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, " - "opcnamespace, " - "(%s opcowner) AS rolname " - "FROM pg_opclass", - username_subquery); - } - else if (fout->remoteVersion >= 70100) - { - appendPQExpBufferStr(query, "SELECT tableoid, oid, opcname, " - "0::oid AS opcnamespace, " - "''::name AS rolname " - "FROM pg_opclass"); - } - else - { - appendPQExpBufferStr(query, "SELECT " - "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, " - "oid, opcname, " - "0::oid AS opcnamespace, " - "''::name AS rolname " - "FROM pg_opclass"); - } + appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, " + "opcnamespace, " + "(%s opcowner) AS rolname " + "FROM pg_opclass", + username_subquery); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -4564,8 +4814,7 @@ getOpclasses(Archive *fout, int *numOpclasses) opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname)); opcinfo[i].dobj.namespace = findNamespace(fout, - atooid(PQgetvalue(res, i, i_opcnamespace)), - opcinfo[i].dobj.catId.oid); + atooid(PQgetvalue(res, i, i_opcnamespace))); opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname)); /* Decide whether we want to dump it */ @@ -4574,12 +4823,9 @@ getOpclasses(Archive *fout, int *numOpclasses) /* Op Classes do not currently have ACLs. */ opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL; - if (fout->remoteVersion >= 70300) - { - if (strlen(opcinfo[i].rolname) == 0) - write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n", - opcinfo[i].dobj.name); - } + if (strlen(opcinfo[i].rolname) == 0) + write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n", + opcinfo[i].dobj.name); } PQclear(res); @@ -4655,8 +4901,7 @@ getOpfamilies(Archive *fout, int *numOpfamilies) opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname)); opfinfo[i].dobj.namespace = findNamespace(fout, - atooid(PQgetvalue(res, i, i_opfnamespace)), - opfinfo[i].dobj.catId.oid); + atooid(PQgetvalue(res, i, i_opfnamespace))); opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname)); /* Decide whether we want to dump it */ @@ -4665,12 +4910,9 @@ getOpfamilies(Archive *fout, int *numOpfamilies) /* Extensions do not currently have ACLs. */ opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL; - if (fout->remoteVersion >= 70300) - { - if (strlen(opfinfo[i].rolname) == 0) - write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n", - opfinfo[i].dobj.name); - } + if (strlen(opfinfo[i].rolname) == 0) + write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n", + opfinfo[i].dobj.name); } PQclear(res); @@ -4788,7 +5030,7 @@ getAggregates(Archive *fout, int *numAggs) "deptype = 'e')"); appendPQExpBufferChar(query, ')'); } - else if (fout->remoteVersion >= 70300) + else { appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, " "pronamespace AS aggnamespace, " @@ -4804,38 +5046,6 @@ getAggregates(Archive *fout, int *numAggs) "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')", username_subquery); } - else if (fout->remoteVersion >= 70100) - { - appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, " - "0::oid AS aggnamespace, " - "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, " - "aggbasetype AS proargtypes, " - "(%s aggowner) AS rolname, " - "NULL AS aggacl, " - "NULL AS raggacl, " - "NULL AS initaggacl, NULL AS initraggacl " - "FROM pg_aggregate " - "where oid > '%u'::oid", - username_subquery, - g_last_builtin_oid); - } - else - { - appendPQExpBuffer(query, "SELECT " - "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, " - "oid, aggname, " - "0::oid AS aggnamespace, " - "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, " - "aggbasetype AS proargtypes, " - "(%s aggowner) AS rolname, " - "NULL AS aggacl, " - "NULL AS raggacl, " - "NULL AS initaggacl, NULL AS initraggacl " - "FROM pg_aggregate " - "where oid > '%u'::oid", - username_subquery, - g_last_builtin_oid); - } res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -4865,8 +5075,7 @@ getAggregates(Archive *fout, int *numAggs) agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname)); agginfo[i].aggfn.dobj.namespace = findNamespace(fout, - atooid(PQgetvalue(res, i, i_aggnamespace)), - agginfo[i].aggfn.dobj.catId.oid); + atooid(PQgetvalue(res, i, i_aggnamespace))); agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname)); if (strlen(agginfo[i].aggfn.rolname) == 0) write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n", @@ -4883,13 +5092,9 @@ getAggregates(Archive *fout, int *numAggs) else { agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid)); - if (fout->remoteVersion >= 70300) - parseOidArray(PQgetvalue(res, i, i_proargtypes), - agginfo[i].aggfn.argtypes, - agginfo[i].aggfn.nargs); - else - /* it's just aggbasetype */ - agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes)); + parseOidArray(PQgetvalue(res, i, i_proargtypes), + agginfo[i].aggfn.argtypes, + agginfo[i].aggfn.nargs); } /* Decide whether we want to dump it */ @@ -4943,20 +5148,26 @@ getFuncs(Archive *fout, int *numFuncs) selectSourceSchema(fout, "pg_catalog"); /* - * Find all interesting functions. We include functions in pg_catalog, if - * they have an ACL different from what we set at initdb time (which is - * saved in pg_init_privs for us to perform this check). There may also - * be functions which are members of extensions which we must dump if we - * are in binary upgrade mode (we'll mark those functions as to-be-dumped - * when we check if the extension is to-be-dumped and we're in binary - * upgrade mode). + * Find all interesting functions. This is a bit complicated: + * + * 1. Always exclude aggregates; those are handled elsewhere. + * + * 2. Always exclude functions that are internally dependent on something + * else, since presumably those will be created as a result of creating + * the something else. This currently acts only to suppress constructor + * functions for range types (so we only need it in 9.2 and up). Note + * this is OK only because the constructors don't have any dependencies + * the range type doesn't have; otherwise we might not get creation + * ordering correct. * - * Also, in 9.2 and up, exclude functions that are internally dependent on - * something else, since presumably those will be created as a result of - * creating the something else. This currently only acts to suppress - * constructor functions for range types. Note that this is OK only - * because the constructors don't have any dependencies the range type - * doesn't have; otherwise we might not get creation ordering correct. + * 3. Otherwise, we normally exclude functions in pg_catalog. However, if + * they're members of extensions and we are in binary-upgrade mode then + * include them, since we want to dump extension members individually in + * that mode. Also, if they are used by casts or transforms then we need + * to gather the information about them, though they won't be dumped if + * they are built-in. Also, in 9.6 and up, include functions in + * pg_catalog if they have an ACL different from what's shown in + * pg_init_privs. */ if (fout->remoteVersion >= 90600) { @@ -4983,19 +5194,28 @@ getFuncs(Archive *fout, int *numFuncs) "(p.oid = pip.objoid " "AND pip.classoid = 'pg_proc'::regclass " "AND pip.objsubid = 0) " - "WHERE NOT proisagg " - "AND NOT EXISTS (SELECT 1 FROM pg_depend " + "WHERE NOT proisagg" + "\n AND NOT EXISTS (SELECT 1 FROM pg_depend " "WHERE classid = 'pg_proc'::regclass AND " - "objid = p.oid AND deptype = 'i') AND (" - "pronamespace != " + "objid = p.oid AND deptype = 'i')" + "\n AND (" + "\n pronamespace != " "(SELECT oid FROM pg_namespace " - "WHERE nspname = 'pg_catalog') OR " - "p.proacl IS DISTINCT FROM pip.initprivs", + "WHERE nspname = 'pg_catalog')" + "\n OR EXISTS (SELECT 1 FROM pg_cast" + "\n WHERE pg_cast.oid > %u " + "\n AND p.oid = pg_cast.castfunc)" + "\n OR EXISTS (SELECT 1 FROM pg_transform" + "\n WHERE pg_transform.oid > %u AND " + "\n (p.oid = pg_transform.trffromsql" + "\n OR p.oid = pg_transform.trftosql))", acl_subquery->data, racl_subquery->data, initacl_subquery->data, initracl_subquery->data, - username_subquery); + username_subquery, + g_last_builtin_oid, + g_last_builtin_oid); if (dopt->binary_upgrade) appendPQExpBufferStr(query, "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE " @@ -5003,6 +5223,8 @@ getFuncs(Archive *fout, int *numFuncs) "objid = p.oid AND " "refclassid = 'pg_extension'::regclass AND " "deptype = 'e')"); + appendPQExpBufferStr(query, + "\n OR p.proacl IS DISTINCT FROM pip.initprivs"); appendPQExpBufferChar(query, ')'); destroyPQExpBuffer(acl_subquery); @@ -5010,7 +5232,7 @@ getFuncs(Archive *fout, int *numFuncs) destroyPQExpBuffer(initacl_subquery); destroyPQExpBuffer(initracl_subquery); } - else if (fout->remoteVersion >= 70300) + else { appendPQExpBuffer(query, "SELECT tableoid, oid, proname, prolang, " @@ -5020,16 +5242,31 @@ getFuncs(Archive *fout, int *numFuncs) "pronamespace, " "(%s proowner) AS rolname " "FROM pg_proc p " - "WHERE NOT proisagg AND (" - "pronamespace != " - "(SELECT oid FROM pg_namespace " - "WHERE nspname = 'pg_catalog')", + "WHERE NOT proisagg", username_subquery); if (fout->remoteVersion >= 90200) appendPQExpBufferStr(query, "\n AND NOT EXISTS (SELECT 1 FROM pg_depend " "WHERE classid = 'pg_proc'::regclass AND " "objid = p.oid AND deptype = 'i')"); + appendPQExpBuffer(query, + "\n AND (" + "\n pronamespace != " + "(SELECT oid FROM pg_namespace " + "WHERE nspname = 'pg_catalog')" + "\n OR EXISTS (SELECT 1 FROM pg_cast" + "\n WHERE pg_cast.oid > '%u'::oid" + "\n AND p.oid = pg_cast.castfunc)", + g_last_builtin_oid); + + if (fout->remoteVersion >= 90500) + appendPQExpBuffer(query, + "\n OR EXISTS (SELECT 1 FROM pg_transform" + "\n WHERE pg_transform.oid > '%u'::oid" + "\n AND (p.oid = pg_transform.trffromsql" + "\n OR p.oid = pg_transform.trftosql))", + g_last_builtin_oid); + if (dopt->binary_upgrade && fout->remoteVersion >= 90100) appendPQExpBufferStr(query, "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE " @@ -5039,39 +5276,6 @@ getFuncs(Archive *fout, int *numFuncs) "deptype = 'e')"); appendPQExpBufferChar(query, ')'); } - else if (fout->remoteVersion >= 70100) - { - appendPQExpBuffer(query, - "SELECT tableoid, oid, proname, prolang, " - "pronargs, proargtypes, prorettype, " - "NULL AS proacl, " - "NULL AS rproacl, " - "NULL as initproacl, NULL AS initrproacl, " - "0::oid AS pronamespace, " - "(%s proowner) AS rolname " - "FROM pg_proc " - "WHERE pg_proc.oid > '%u'::oid", - username_subquery, - g_last_builtin_oid); - } - else - { - appendPQExpBuffer(query, - "SELECT " - "(SELECT oid FROM pg_class " - " WHERE relname = 'pg_proc') AS tableoid, " - "oid, proname, prolang, " - "pronargs, proargtypes, prorettype, " - "NULL AS proacl, " - "NULL AS rproacl, " - "NULL as initproacl, NULL AS initrproacl, " - "0::oid AS pronamespace, " - "(%s proowner) AS rolname " - "FROM pg_proc " - "where pg_proc.oid > '%u'::oid", - username_subquery, - g_last_builtin_oid); - } res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -5104,8 +5308,7 @@ getFuncs(Archive *fout, int *numFuncs) finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname)); finfo[i].dobj.namespace = findNamespace(fout, - atooid(PQgetvalue(res, i, i_pronamespace)), - finfo[i].dobj.catId.oid); + atooid(PQgetvalue(res, i, i_pronamespace))); finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname)); finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang)); finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype)); @@ -5292,7 +5495,7 @@ getTables(Archive *fout, int *numTables) "(c.oid = pip.objoid " "AND pip.classoid = 'pg_class'::regclass " "AND pip.objsubid = 0) " - "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') " + "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c', '%c') " "ORDER BY c.oid", acl_subquery->data, racl_subquery->data, @@ -5306,7 +5509,8 @@ getTables(Archive *fout, int *numTables) RELKIND_SEQUENCE, RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW, RELKIND_COMPOSITE_TYPE, - RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE); + RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE, + RELKIND_PARTITIONED_TABLE); destroyPQExpBuffer(acl_subquery); destroyPQExpBuffer(racl_subquery); @@ -5602,58 +5806,16 @@ getTables(Archive *fout, int *numTables) "c.relhasindex, c.relhasrules, c.relhasoids, " "'f'::bool AS relrowsecurity, " "'f'::bool AS relforcerowsecurity, " - "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, " - "tc.relfrozenxid AS tfrozenxid, " - "0 AS tminmxid, " - "'p' AS relpersistence, 't' as relispopulated, " - "'d' AS relreplident, c.relpages, " - "NULL AS reloftype, " - "d.refobjid AS owning_tab, " - "d.refobjsubid AS owning_col, " - "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " - "c.reloptions AS reloptions, " - "NULL AS toast_reloptions, " - "NULL AS changed_acl " - "FROM pg_class c " - "LEFT JOIN pg_depend d ON " - "(c.relkind = '%c' AND " - "d.classid = c.tableoid AND d.objid = c.oid AND " - "d.objsubid = 0 AND " - "d.refclassid = c.tableoid AND d.deptype = 'a') " - "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) " - "WHERE c.relkind in ('%c', '%c', '%c', '%c') " - "ORDER BY c.oid", - username_subquery, - RELKIND_SEQUENCE, - RELKIND_RELATION, RELKIND_SEQUENCE, - RELKIND_VIEW, RELKIND_COMPOSITE_TYPE); - } - else if (fout->remoteVersion >= 80000) - { - /* - * Left join to pick up dependency info linking sequences to their - * owning column, if any - */ - appendPQExpBuffer(query, - "SELECT c.tableoid, c.oid, relname, " - "relacl, NULL as rrelacl, " - "NULL AS initrelacl, NULL AS initrrelacl, " - "relkind, relnamespace, " - "(%s relowner) AS rolname, " - "relchecks, (reltriggers <> 0) AS relhastriggers, " - "relhasindex, relhasrules, relhasoids, " - "'f'::bool AS relrowsecurity, " - "'f'::bool AS relforcerowsecurity, " - "0 AS relfrozenxid, 0 AS relminmxid," - "0 AS toid, " - "0 AS tfrozenxid, 0 AS tminmxid," + "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, " + "tc.relfrozenxid AS tfrozenxid, " + "0 AS tminmxid, " "'p' AS relpersistence, 't' as relispopulated, " - "'d' AS relreplident, relpages, " + "'d' AS relreplident, c.relpages, " "NULL AS reloftype, " "d.refobjid AS owning_tab, " "d.refobjsubid AS owning_col, " "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " - "NULL AS reloptions, " + "c.reloptions AS reloptions, " "NULL AS toast_reloptions, " "NULL AS changed_acl " "FROM pg_class c " @@ -5661,15 +5823,16 @@ getTables(Archive *fout, int *numTables) "(c.relkind = '%c' AND " "d.classid = c.tableoid AND d.objid = c.oid AND " "d.objsubid = 0 AND " - "d.refclassid = c.tableoid AND d.deptype = 'i') " - "WHERE relkind in ('%c', '%c', '%c', '%c') " + "d.refclassid = c.tableoid AND d.deptype = 'a') " + "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) " + "WHERE c.relkind in ('%c', '%c', '%c', '%c') " "ORDER BY c.oid", username_subquery, RELKIND_SEQUENCE, RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW, RELKIND_COMPOSITE_TYPE); } - else if (fout->remoteVersion >= 70300) + else { /* * Left join to pick up dependency info linking sequences to their @@ -5693,7 +5856,7 @@ getTables(Archive *fout, int *numTables) "NULL AS reloftype, " "d.refobjid AS owning_tab, " "d.refobjsubid AS owning_col, " - "NULL AS reltablespace, " + "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " "NULL AS reloptions, " "NULL AS toast_reloptions, " "NULL AS changed_acl " @@ -5703,119 +5866,13 @@ getTables(Archive *fout, int *numTables) "d.classid = c.tableoid AND d.objid = c.oid AND " "d.objsubid = 0 AND " "d.refclassid = c.tableoid AND d.deptype = 'i') " - "WHERE relkind IN ('%c', '%c', '%c', '%c') " + "WHERE relkind in ('%c', '%c', '%c', '%c') " "ORDER BY c.oid", username_subquery, RELKIND_SEQUENCE, RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW, RELKIND_COMPOSITE_TYPE); } - else if (fout->remoteVersion >= 70200) - { - appendPQExpBuffer(query, - "SELECT tableoid, oid, relname, relacl, " - "NULL as rrelacl, " - "NULL AS initrelacl, NULL AS initrrelacl, " - "relkind, " - "0::oid AS relnamespace, " - "(%s relowner) AS rolname, " - "relchecks, (reltriggers <> 0) AS relhastriggers, " - "relhasindex, relhasrules, relhasoids, " - "'f'::bool AS relrowsecurity, " - "'f'::bool AS relforcerowsecurity, " - "0 AS relfrozenxid, 0 AS relminmxid," - "0 AS toid, " - "0 AS tfrozenxid, 0 AS tminmxid," - "'p' AS relpersistence, 't' as relispopulated, " - "'d' AS relreplident, relpages, " - "NULL AS reloftype, " - "NULL::oid AS owning_tab, " - "NULL::int4 AS owning_col, " - "NULL AS reltablespace, " - "NULL AS reloptions, " - "NULL AS toast_reloptions, " - "NULL AS changed_acl " - "FROM pg_class " - "WHERE relkind IN ('%c', '%c', '%c') " - "ORDER BY oid", - username_subquery, - RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW); - } - else if (fout->remoteVersion >= 70100) - { - /* all tables have oids in 7.1 */ - appendPQExpBuffer(query, - "SELECT tableoid, oid, relname, relacl, " - "NULL as rrelacl, " - "NULL AS initrelacl, NULL AS initrrelacl, " - "relkind, " - "0::oid AS relnamespace, " - "(%s relowner) AS rolname, " - "relchecks, (reltriggers <> 0) AS relhastriggers, " - "relhasindex, relhasrules, " - "'t'::bool AS relhasoids, " - "'f'::bool AS relrowsecurity, " - "'f'::bool AS relforcerowsecurity, " - "0 AS relfrozenxid, 0 AS relminmxid," - "0 AS toid, " - "0 AS tfrozenxid, 0 AS tminmxid," - "'p' AS relpersistence, 't' as relispopulated, " - "'d' AS relreplident, relpages, " - "NULL AS reloftype, " - "NULL::oid AS owning_tab, " - "NULL::int4 AS owning_col, " - "NULL AS reltablespace, " - "NULL AS reloptions, " - "NULL AS toast_reloptions, " - "NULL AS changed_acl " - "FROM pg_class " - "WHERE relkind IN ('%c', '%c', '%c') " - "ORDER BY oid", - username_subquery, - RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW); - } - else - { - /* - * Before 7.1, view relkind was not set to 'v', so we must check if we - * have a view by looking for a rule in pg_rewrite. - */ - appendPQExpBuffer(query, - "SELECT " - "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, " - "oid, relname, relacl, NULL as rrelacl, " - "NULL AS initrelacl, NULL AS initrrelacl, " - "CASE WHEN relhasrules and relkind = 'r' " - " and EXISTS(SELECT rulename FROM pg_rewrite r WHERE " - " r.ev_class = c.oid AND r.ev_type = '1') " - "THEN '%c'::\"char\" " - "ELSE relkind END AS relkind," - "0::oid AS relnamespace, " - "(%s relowner) AS rolname, " - "relchecks, (reltriggers <> 0) AS relhastriggers, " - "relhasindex, relhasrules, " - "'t'::bool AS relhasoids, " - "'f'::bool AS relrowsecurity, " - "'f'::bool AS relforcerowsecurity, " - "0 AS relfrozenxid, 0 AS relminmxid," - "0 AS toid, " - "0 AS tfrozenxid, 0 AS tminmxid," - "'p' AS relpersistence, 't' as relispopulated, " - "'d' AS relreplident, 0 AS relpages, " - "NULL AS reloftype, " - "NULL::oid AS owning_tab, " - "NULL::int4 AS owning_col, " - "NULL AS reltablespace, " - "NULL AS reloptions, " - "NULL AS toast_reloptions, " - "NULL AS changed_acl " - "FROM pg_class c " - "WHERE relkind IN ('%c', '%c') " - "ORDER BY oid", - RELKIND_VIEW, - username_subquery, - RELKIND_RELATION, RELKIND_SEQUENCE); - } res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -5869,7 +5926,7 @@ getTables(Archive *fout, int *numTables) i_reloftype = PQfnumber(res, "reloftype"); i_changed_acl = PQfnumber(res, "changed_acl"); - if (dopt->lockWaitTimeout && fout->remoteVersion >= 70300) + if (dopt->lockWaitTimeout) { /* * Arrange to fail instead of waiting forever for a table lock. @@ -5893,8 +5950,7 @@ getTables(Archive *fout, int *numTables) tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname)); tblinfo[i].dobj.namespace = findNamespace(fout, - atooid(PQgetvalue(res, i, i_relnamespace)), - tblinfo[i].dobj.catId.oid); + atooid(PQgetvalue(res, i, i_relnamespace))); tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname)); tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl)); tblinfo[i].rrelacl = pg_strdup(PQgetvalue(res, i, i_rrelacl)); @@ -5965,7 +6021,7 @@ getTables(Archive *fout, int *numTables) tblinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL; tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false; - + tblinfo[i].dummy_view = false; /* might get set during sort */ tblinfo[i].postponed_def = false; /* might get set during sort */ /* @@ -5982,7 +6038,9 @@ getTables(Archive *fout, int *numTables) * We only need to lock the table for certain components; see * pg_dump.h */ - if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION && + if (tblinfo[i].dobj.dump && + (tblinfo[i].relkind == RELKIND_RELATION || + tblinfo->relkind == RELKIND_PARTITIONED_TABLE) && (tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK)) { resetPQExpBuffer(query); @@ -6000,7 +6058,7 @@ getTables(Archive *fout, int *numTables) tblinfo[i].dobj.name); } - if (dopt->lockWaitTimeout && fout->remoteVersion >= 70300) + if (dopt->lockWaitTimeout) { ExecuteSqlStatement(fout, "SET statement_timeout = 0"); } @@ -6037,6 +6095,9 @@ getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables) continue; /* not an owned sequence */ owning_tab = findTableByOid(seqinfo->owning_tab); + if (owning_tab == NULL) + exit_horribly(NULL, "failed sanity check, parent table OID %u of sequence OID %u not found\n", + seqinfo->owning_tab, seqinfo->dobj.catId.oid); /* * We need to dump the components that are being dumped for the table @@ -6082,9 +6143,16 @@ getInherits(Archive *fout, int *numInherits) /* Make sure we are in proper schema */ selectSourceSchema(fout, "pg_catalog"); - /* find all the inheritance information */ - - appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits"); + /* + * Find all the inheritance information, excluding implicit inheritance + * via partitioning. We handle that case using getPartitions(), because + * we want more information about partitions than just the parent-child + * relationship. + */ + appendPQExpBufferStr(query, + "SELECT inhrelid, inhparent " + "FROM pg_inherits " + "WHERE inhparent NOT IN (SELECT oid FROM pg_class WHERE relkind = 'P')"); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -6110,6 +6178,72 @@ getInherits(Archive *fout, int *numInherits) return inhinfo; } +/* + * getPartitions + * read all the partition inheritance and partition bound information + * from the system catalogs return them in the PartInfo* structure + * + * numPartitions is set to the number of pairs read in + */ +PartInfo * +getPartitions(Archive *fout, int *numPartitions) +{ + PGresult *res; + int ntups; + int i; + PQExpBuffer query; + PartInfo *partinfo; + + int i_partrelid; + int i_partparent; + int i_partbound; + + /* Before version 10, there are no partitions */ + if (fout->remoteVersion < 100000) + { + *numPartitions = 0; + return NULL; + } + + query = createPQExpBuffer(); + + /* Make sure we are in proper schema */ + selectSourceSchema(fout, "pg_catalog"); + + /* find the inheritance and boundary information about partitions */ + + appendPQExpBufferStr(query, + "SELECT inhrelid as partrelid, inhparent AS partparent," + " pg_get_expr(relpartbound, inhrelid) AS partbound" + " FROM pg_class c, pg_inherits" + " WHERE c.oid = inhrelid AND c.relispartition"); + + res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); + + ntups = PQntuples(res); + + *numPartitions = ntups; + + partinfo = (PartInfo *) pg_malloc(ntups * sizeof(PartInfo)); + + i_partrelid = PQfnumber(res, "partrelid"); + i_partparent = PQfnumber(res, "partparent"); + i_partbound = PQfnumber(res, "partbound"); + + for (i = 0; i < ntups; i++) + { + partinfo[i].partrelid = atooid(PQgetvalue(res, i, i_partrelid)); + partinfo[i].partparent = atooid(PQgetvalue(res, i, i_partparent)); + partinfo[i].partdef = pg_strdup(PQgetvalue(res, i, i_partbound)); + } + + PQclear(res); + + destroyPQExpBuffer(query); + + return partinfo; +} + /* * getIndexes * get information about every index on a dumpable table @@ -6273,7 +6407,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) "ORDER BY indexname", tbinfo->dobj.catId.oid); } - else if (fout->remoteVersion >= 80000) + else { appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, " @@ -6302,87 +6436,6 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) "ORDER BY indexname", tbinfo->dobj.catId.oid); } - else if (fout->remoteVersion >= 70300) - { - appendPQExpBuffer(query, - "SELECT t.tableoid, t.oid, " - "t.relname AS indexname, " - "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, " - "t.relnatts AS indnkeys, " - "i.indkey, i.indisclustered, " - "false AS indisreplident, t.relpages, " - "c.contype, c.conname, " - "c.condeferrable, c.condeferred, " - "c.tableoid AS contableoid, " - "c.oid AS conoid, " - "null AS condef, " - "NULL AS tablespace, " - "null AS indreloptions " - "FROM pg_catalog.pg_index i " - "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) " - "LEFT JOIN pg_catalog.pg_depend d " - "ON (d.classid = t.tableoid " - "AND d.objid = t.oid " - "AND d.deptype = 'i') " - "LEFT JOIN pg_catalog.pg_constraint c " - "ON (d.refclassid = c.tableoid " - "AND d.refobjid = c.oid) " - "WHERE i.indrelid = '%u'::pg_catalog.oid " - "ORDER BY indexname", - tbinfo->dobj.catId.oid); - } - else if (fout->remoteVersion >= 70100) - { - appendPQExpBuffer(query, - "SELECT t.tableoid, t.oid, " - "t.relname AS indexname, " - "pg_get_indexdef(i.indexrelid) AS indexdef, " - "t.relnatts AS indnkeys, " - "i.indkey, false AS indisclustered, " - "false AS indisreplident, t.relpages, " - "CASE WHEN i.indisprimary THEN 'p'::char " - "ELSE '0'::char END AS contype, " - "t.relname AS conname, " - "false AS condeferrable, " - "false AS condeferred, " - "0::oid AS contableoid, " - "t.oid AS conoid, " - "null AS condef, " - "NULL AS tablespace, " - "null AS indreloptions " - "FROM pg_index i, pg_class t " - "WHERE t.oid = i.indexrelid " - "AND i.indrelid = '%u'::oid " - "ORDER BY indexname", - tbinfo->dobj.catId.oid); - } - else - { - appendPQExpBuffer(query, - "SELECT " - "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, " - "t.oid, " - "t.relname AS indexname, " - "pg_get_indexdef(i.indexrelid) AS indexdef, " - "t.relnatts AS indnkeys, " - "i.indkey, false AS indisclustered, " - "false AS indisreplident, t.relpages, " - "CASE WHEN i.indisprimary THEN 'p'::char " - "ELSE '0'::char END AS contype, " - "t.relname AS conname, " - "false AS condeferrable, " - "false AS condeferred, " - "0::oid AS contableoid, " - "t.oid AS conoid, " - "null AS condef, " - "NULL AS tablespace, " - "null AS indreloptions " - "FROM pg_index i, pg_class t " - "WHERE t.oid = i.indexrelid " - "AND i.indrelid = '%u'::oid " - "ORDER BY indexname", - tbinfo->dobj.catId.oid); - } res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -6425,19 +6478,9 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys)); indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace)); indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions)); - - /* - * In pre-7.4 releases, indkeys may contain more entries than - * indnkeys says (since indnkeys will be 1 for a functional - * index). We don't actually care about this case since we don't - * examine indkeys except for indexes associated with PRIMARY and - * UNIQUE constraints, which are never functional indexes. But we - * have to allocate enough space to keep parseOidArray from - * complaining. - */ - indxinfo[j].indkeys = (Oid *) pg_malloc(INDEX_MAX_KEYS * sizeof(Oid)); + indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnkeys * sizeof(Oid)); parseOidArray(PQgetvalue(res, j, i_indkey), - indxinfo[j].indkeys, INDEX_MAX_KEYS); + indxinfo[j].indkeys, indxinfo[j].indnkeys); indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't'); indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't'); indxinfo[j].relpages = atoi(PQgetvalue(res, j, i_relpages)); @@ -6448,9 +6491,6 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) /* * If we found a constraint matching the index, create an * entry for it. - * - * In a pre-7.3 database, we take this path iff the index was - * marked indisprimary. */ constrinfo[j].dobj.objType = DO_CONSTRAINT; constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid)); @@ -6473,10 +6513,6 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) constrinfo[j].separate = true; indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId; - - /* If pre-7.3 DB, better make sure table comes first */ - addObjectDependency(&constrinfo[j].dobj, - tbinfo->dobj.dumpId); } else { @@ -6515,10 +6551,6 @@ getConstraints(Archive *fout, TableInfo tblinfo[], int numTables) i_condef; int ntups; - /* pg_constraint was created in 7.3, so nothing to do if older */ - if (fout->remoteVersion < 70300) - return; - query = createPQExpBuffer(); for (i = 0; i < numTables; i++) @@ -6604,10 +6636,6 @@ getDomainConstraints(Archive *fout, TypeInfo *tyinfo) i_consrc; int ntups; - /* pg_constraint was created in 7.3, so nothing to do if older */ - if (fout->remoteVersion < 70300) - return; - /* * select appropriate schema to ensure names in constraint are properly * qualified @@ -6625,17 +6653,9 @@ getDomainConstraints(Archive *fout, TypeInfo *tyinfo) "ORDER BY conname", tyinfo->dobj.catId.oid); - else if (fout->remoteVersion >= 70400) - appendPQExpBuffer(query, "SELECT tableoid, oid, conname, " - "pg_catalog.pg_get_constraintdef(oid) AS consrc, " - "true as convalidated " - "FROM pg_catalog.pg_constraint " - "WHERE contypid = '%u'::pg_catalog.oid " - "ORDER BY conname", - tyinfo->dobj.catId.oid); else appendPQExpBuffer(query, "SELECT tableoid, oid, conname, " - "'CHECK (' || consrc || ')' AS consrc, " + "pg_catalog.pg_get_constraintdef(oid) AS consrc, " "true as convalidated " "FROM pg_catalog.pg_constraint " "WHERE contypid = '%u'::pg_catalog.oid " @@ -6728,20 +6748,10 @@ getRules(Archive *fout, int *numRules) "FROM pg_rewrite " "ORDER BY oid"); } - else if (fout->remoteVersion >= 70100) - { - appendPQExpBufferStr(query, "SELECT " - "tableoid, oid, rulename, " - "ev_class AS ruletable, ev_type, is_instead, " - "'O'::char AS ev_enabled " - "FROM pg_rewrite " - "ORDER BY oid"); - } else { appendPQExpBufferStr(query, "SELECT " - "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, " - "oid, rulename, " + "tableoid, oid, rulename, " "ev_class AS ruletable, ev_type, is_instead, " "'O'::char AS ev_enabled " "FROM pg_rewrite " @@ -6810,16 +6820,6 @@ getRules(Archive *fout, int *numRules) } else ruleinfo[i].separate = true; - - /* - * If we're forced to break a dependency loop by dumping a view as a - * table and separate _RETURN rule, we'll move the view's reloptions - * to the rule. (This is necessary because tables and views have - * different valid reloptions, so we can't apply the options until the - * backend knows it's a view.) Otherwise the rule's reloptions stay - * NULL. - */ - ruleinfo[i].reloptions = NULL; } PQclear(res); @@ -6914,7 +6914,7 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables) "AND tgconstraint = 0", tbinfo->dobj.catId.oid); } - else if (fout->remoteVersion >= 70300) + else { /* * We ignore triggers that are tied to a foreign-key constraint, @@ -6937,34 +6937,7 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables) " WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))", tbinfo->dobj.catId.oid); } - else if (fout->remoteVersion >= 70100) - { - appendPQExpBuffer(query, - "SELECT tgname, tgfoid::regproc AS tgfname, " - "tgtype, tgnargs, tgargs, tgenabled, " - "tgisconstraint, tgconstrname, tgdeferrable, " - "tgconstrrelid, tginitdeferred, tableoid, oid, " - "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) " - " AS tgconstrrelname " - "FROM pg_trigger " - "WHERE tgrelid = '%u'::oid", - tbinfo->dobj.catId.oid); - } - else - { - appendPQExpBuffer(query, - "SELECT tgname, tgfoid::regproc AS tgfname, " - "tgtype, tgnargs, tgargs, tgenabled, " - "tgisconstraint, tgconstrname, tgdeferrable, " - "tgconstrrelid, tginitdeferred, " - "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, " - "oid, " - "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) " - " AS tgconstrrelname " - "FROM pg_trigger " - "WHERE tgrelid = '%u'::oid", - tbinfo->dobj.catId.oid); - } + res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); ntups = PQntuples(res); @@ -7227,92 +7200,53 @@ getProcLangs(Archive *fout, int *numProcLangs) "lanname, lanpltrusted, lanplcallfoid, " "laninline, lanvalidator, lanacl, NULL AS rlanacl, " "NULL AS initlanacl, NULL AS initrlanacl, " - "(%s lanowner) AS lanowner " - "FROM pg_language " - "WHERE lanispl " - "ORDER BY oid", - username_subquery); - } - else if (fout->remoteVersion >= 80300) - { - /* pg_language has a lanowner column */ - appendPQExpBuffer(query, "SELECT tableoid, oid, " - "lanname, lanpltrusted, lanplcallfoid, " - "0 AS laninline, lanvalidator, lanacl, " - "NULL AS rlanacl, " - "NULL AS initlanacl, NULL AS initrlanacl, " - "(%s lanowner) AS lanowner " - "FROM pg_language " - "WHERE lanispl " - "ORDER BY oid", - username_subquery); - } - else if (fout->remoteVersion >= 80100) - { - /* Languages are owned by the bootstrap superuser, OID 10 */ - appendPQExpBuffer(query, "SELECT tableoid, oid, " - "lanname, lanpltrusted, lanplcallfoid, " - "0 AS laninline, lanvalidator, lanacl, " - "NULL AS rlanacl, " - "NULL AS initlanacl, NULL AS initrlanacl, " - "(%s '10') AS lanowner " - "FROM pg_language " - "WHERE lanispl " - "ORDER BY oid", - username_subquery); - } - else if (fout->remoteVersion >= 70400) - { - /* Languages are owned by the bootstrap superuser, sysid 1 */ - appendPQExpBuffer(query, "SELECT tableoid, oid, " - "lanname, lanpltrusted, lanplcallfoid, " - "0 AS laninline, lanvalidator, lanacl, " - "NULL AS rlanacl, " - "NULL AS initlanacl, NULL AS initrlanacl, " - "(%s '1') AS lanowner " + "(%s lanowner) AS lanowner " "FROM pg_language " "WHERE lanispl " "ORDER BY oid", username_subquery); } - else if (fout->remoteVersion >= 70300) + else if (fout->remoteVersion >= 80300) { - /* No clear notion of an owner at all before 7.4 ... */ + /* pg_language has a lanowner column */ appendPQExpBuffer(query, "SELECT tableoid, oid, " "lanname, lanpltrusted, lanplcallfoid, " "0 AS laninline, lanvalidator, lanacl, " "NULL AS rlanacl, " "NULL AS initlanacl, NULL AS initrlanacl, " - "NULL AS lanowner " + "(%s lanowner) AS lanowner " "FROM pg_language " "WHERE lanispl " - "ORDER BY oid"); + "ORDER BY oid", + username_subquery); } - else if (fout->remoteVersion >= 70100) + else if (fout->remoteVersion >= 80100) { + /* Languages are owned by the bootstrap superuser, OID 10 */ appendPQExpBuffer(query, "SELECT tableoid, oid, " "lanname, lanpltrusted, lanplcallfoid, " - "0 AS laninline, 0 AS lanvalidator, NULL AS lanacl, " + "0 AS laninline, lanvalidator, lanacl, " "NULL AS rlanacl, " "NULL AS initlanacl, NULL AS initrlanacl, " - "NULL AS lanowner " + "(%s '10') AS lanowner " "FROM pg_language " "WHERE lanispl " - "ORDER BY oid"); + "ORDER BY oid", + username_subquery); } else { - appendPQExpBuffer(query, "SELECT " - "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, " - "oid, " + /* Languages are owned by the bootstrap superuser, sysid 1 */ + appendPQExpBuffer(query, "SELECT tableoid, oid, " "lanname, lanpltrusted, lanplcallfoid, " - "0 AS laninline, 0 AS lanvalidator, NULL AS lanacl, " + "0 AS laninline, lanvalidator, lanacl, " "NULL AS rlanacl, " "NULL AS initlanacl, NULL AS initrlanacl, " - "NULL AS lanowner " + "(%s '1') AS lanowner " "FROM pg_language " "WHERE lanispl " - "ORDER BY oid"); + "ORDER BY oid", + username_subquery); } res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -7362,20 +7296,6 @@ getProcLangs(Archive *fout, int *numProcLangs) PQgetisnull(res, i, i_initlanacl) && PQgetisnull(res, i, i_initrlanacl)) planginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL; - - if (fout->remoteVersion < 70300) - { - /* - * We need to make a dependency to ensure the function will be - * dumped first. (In 7.3 and later the regular dependency - * mechanism will handle this for us.) - */ - FuncInfo *funcInfo = findFuncByOid(planginfo[i].lanplcallfoid); - - if (funcInfo) - addObjectDependency(&planginfo[i].dobj, - funcInfo->dobj.dumpId); - } } PQclear(res); @@ -7417,25 +7337,13 @@ getCasts(Archive *fout, int *numCasts) "castmethod " "FROM pg_cast ORDER BY 3,4"); } - else if (fout->remoteVersion >= 70300) + else { appendPQExpBufferStr(query, "SELECT tableoid, oid, " "castsource, casttarget, castfunc, castcontext, " "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod " "FROM pg_cast ORDER BY 3,4"); } - else - { - appendPQExpBufferStr(query, "SELECT 0 AS tableoid, p.oid, " - "t1.oid AS castsource, t2.oid AS casttarget, " - "p.oid AS castfunc, 'e' AS castcontext, " - "'f' AS castmethod " - "FROM pg_type t1, pg_type t2, pg_proc p " - "WHERE p.pronargs = 1 AND " - "p.proargtypes[0] = t1.oid AND " - "p.prorettype = t2.oid AND p.proname = t2.typname " - "ORDER BY 3,4"); - } res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -7482,22 +7390,6 @@ getCasts(Archive *fout, int *numCasts) sTypeInfo->dobj.name, tTypeInfo->dobj.name); castinfo[i].dobj.name = namebuf.data; - if (fout->remoteVersion < 70300 && - OidIsValid(castinfo[i].castfunc)) - { - /* - * We need to make a dependency to ensure the function will be - * dumped first. (In 7.3 and later the regular dependency - * mechanism handles this for us.) - */ - FuncInfo *funcInfo; - - funcInfo = findFuncByOid(castinfo[i].castfunc); - if (funcInfo) - addObjectDependency(&castinfo[i].dobj, - funcInfo->dobj.dumpId); - } - /* Decide whether we want to dump it */ selectDumpableCast(&(castinfo[i]), fout); @@ -7622,6 +7514,49 @@ getTransforms(Archive *fout, int *numTransforms) return transforminfo; } +/* + * getTablePartitionKeyInfo - + * for each interesting partitioned table, read information about its + * partition key + * + * modifies tblinfo + */ +void +getTablePartitionKeyInfo(Archive *fout, TableInfo *tblinfo, int numTables) +{ + PQExpBuffer q; + int i; + PGresult *res; + + /* No partitioned tables before 10 */ + if (fout->remoteVersion < 100000) + return; + + q = createPQExpBuffer(); + + for (i = 0; i < numTables; i++) + { + TableInfo *tbinfo = &(tblinfo[i]); + + /* Only partitioned tables have partition key */ + if (tbinfo->relkind != RELKIND_PARTITIONED_TABLE) + continue; + + /* Don't bother computing anything for non-target tables, either */ + if (!tbinfo->dobj.dump) + continue; + + resetPQExpBuffer(q); + appendPQExpBuffer(q, "SELECT pg_catalog.pg_get_partkeydef('%u'::pg_catalog.oid)", + tbinfo->dobj.catId.oid); + res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK); + Assert(PQntuples(res) == 1); + tbinfo->partkeydef = pg_strdup(PQgetvalue(res, 0, 0)); + } + + destroyPQExpBuffer(q); +} + /* * getTableAttrs - * for each interesting table, read info about its attributes @@ -7684,10 +7619,7 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables) /* * we must read the attribute names in attribute number order! because - * we will use the attnum to index into the attnames array later. We - * actually ask to order by "attrelid, attnum" because (at least up to - * 7.3) the planner is not smart enough to realize it needn't re-sort - * the output of an indexscan on pg_attribute_relid_attnum_index. + * we will use the attnum to index into the attnames array later. */ if (g_verbose) write_msg(NULL, "finding the columns and types of table \"%s.%s\"\n", @@ -7719,7 +7651,7 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables) "ON a.atttypid = t.oid " "WHERE a.attrelid = '%u'::pg_catalog.oid " "AND a.attnum > 0::pg_catalog.int2 " - "ORDER BY a.attrelid, a.attnum", + "ORDER BY a.attnum", tbinfo->dobj.catId.oid); } else if (fout->remoteVersion >= 90100) @@ -7743,7 +7675,7 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables) "ON a.atttypid = t.oid " "WHERE a.attrelid = '%u'::pg_catalog.oid " "AND a.attnum > 0::pg_catalog.int2 " - "ORDER BY a.attrelid, a.attnum", + "ORDER BY a.attnum", tbinfo->dobj.catId.oid); } else if (fout->remoteVersion >= 90000) @@ -7761,10 +7693,10 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables) "ON a.atttypid = t.oid " "WHERE a.attrelid = '%u'::pg_catalog.oid " "AND a.attnum > 0::pg_catalog.int2 " - "ORDER BY a.attrelid, a.attnum", + "ORDER BY a.attnum", tbinfo->dobj.catId.oid); } - else if (fout->remoteVersion >= 70300) + else { /* need left join here to not fail on dropped columns ... */ appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, " @@ -7778,50 +7710,7 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables) "ON a.atttypid = t.oid " "WHERE a.attrelid = '%u'::pg_catalog.oid " "AND a.attnum > 0::pg_catalog.int2 " - "ORDER BY a.attrelid, a.attnum", - tbinfo->dobj.catId.oid); - } - else if (fout->remoteVersion >= 70100) - { - /* - * attstattarget doesn't exist in 7.1. It does exist in 7.2, but - * we don't dump it because we can't tell whether it's been - * explicitly set or was just a default. - * - * attislocal doesn't exist before 7.3, either; in older databases - * we assume it's TRUE, else we'd fail to dump non-inherited atts. - */ - appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, " - "-1 AS attstattarget, a.attstorage, " - "t.typstorage, a.attnotnull, a.atthasdef, " - "false AS attisdropped, a.attlen, " - "a.attalign, true AS attislocal, " - "format_type(t.oid,a.atttypmod) AS atttypname, " - "'' AS attoptions, 0 AS attcollation, " - "NULL AS attfdwoptions " - "FROM pg_attribute a LEFT JOIN pg_type t " - "ON a.atttypid = t.oid " - "WHERE a.attrelid = '%u'::oid " - "AND a.attnum > 0::int2 " - "ORDER BY a.attrelid, a.attnum", - tbinfo->dobj.catId.oid); - } - else - { - /* format_type not available before 7.1 */ - appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, " - "-1 AS attstattarget, " - "attstorage, attstorage AS typstorage, " - "attnotnull, atthasdef, false AS attisdropped, " - "attlen, attalign, " - "true AS attislocal, " - "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, " - "'' AS attoptions, 0 AS attcollation, " - "NULL AS attfdwoptions " - "FROM pg_attribute a " - "WHERE attrelid = '%u'::oid " - "AND attnum > 0::int2 " - "ORDER BY attrelid, attnum", + "ORDER BY a.attnum", tbinfo->dobj.catId.oid); } @@ -7907,42 +7796,12 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables) tbinfo->dobj.namespace->dobj.name, tbinfo->dobj.name); - resetPQExpBuffer(q); - if (fout->remoteVersion >= 70300) - { - appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, " + printfPQExpBuffer(q, "SELECT tableoid, oid, adnum, " "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc " - "FROM pg_catalog.pg_attrdef " - "WHERE adrelid = '%u'::pg_catalog.oid", - tbinfo->dobj.catId.oid); - } - else if (fout->remoteVersion >= 70200) - { - /* 7.2 did not have OIDs in pg_attrdef */ - appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, adnum, " - "pg_get_expr(adbin, adrelid) AS adsrc " - "FROM pg_attrdef " - "WHERE adrelid = '%u'::oid", - tbinfo->dobj.catId.oid); - } - else if (fout->remoteVersion >= 70100) - { - /* no pg_get_expr, so must rely on adsrc */ - appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc " - "FROM pg_attrdef " - "WHERE adrelid = '%u'::oid", - tbinfo->dobj.catId.oid); - } - else - { - /* no pg_get_expr, no tableoid either */ - appendPQExpBuffer(q, "SELECT " - "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, " - "oid, adnum, adsrc " - "FROM pg_attrdef " - "WHERE adrelid = '%u'::oid", - tbinfo->dobj.catId.oid); - } + "FROM pg_catalog.pg_attrdef " + "WHERE adrelid = '%u'::pg_catalog.oid", + tbinfo->dobj.catId.oid); + res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK); numDefaults = PQntuples(res); @@ -7988,17 +7847,11 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables) if (tbinfo->relkind == RELKIND_VIEW) { attrdefs[j].separate = true; - /* needed in case pre-7.3 DB: */ - addObjectDependency(&attrdefs[j].dobj, - tbinfo->dobj.dumpId); } else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1)) { /* column will be suppressed, print default separately */ attrdefs[j].separate = true; - /* needed in case pre-7.3 DB: */ - addObjectDependency(&attrdefs[j].dobj, - tbinfo->dobj.dumpId); } else { @@ -8060,7 +7913,7 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables) "ORDER BY conname", tbinfo->dobj.catId.oid); } - else if (fout->remoteVersion >= 70400) + else { appendPQExpBuffer(q, "SELECT tableoid, oid, conname, " "pg_catalog.pg_get_constraintdef(oid) AS consrc, " @@ -8071,54 +7924,7 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables) "ORDER BY conname", tbinfo->dobj.catId.oid); } - else if (fout->remoteVersion >= 70300) - { - /* no pg_get_constraintdef, must use consrc */ - appendPQExpBuffer(q, "SELECT tableoid, oid, conname, " - "'CHECK (' || consrc || ')' AS consrc, " - "true AS conislocal, true AS convalidated " - "FROM pg_catalog.pg_constraint " - "WHERE conrelid = '%u'::pg_catalog.oid " - " AND contype = 'c' " - "ORDER BY conname", - tbinfo->dobj.catId.oid); - } - else if (fout->remoteVersion >= 70200) - { - /* 7.2 did not have OIDs in pg_relcheck */ - appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, " - "rcname AS conname, " - "'CHECK (' || rcsrc || ')' AS consrc, " - "true AS conislocal, true AS convalidated " - "FROM pg_relcheck " - "WHERE rcrelid = '%u'::oid " - "ORDER BY rcname", - tbinfo->dobj.catId.oid); - } - else if (fout->remoteVersion >= 70100) - { - appendPQExpBuffer(q, "SELECT tableoid, oid, " - "rcname AS conname, " - "'CHECK (' || rcsrc || ')' AS consrc, " - "true AS conislocal, true AS convalidated " - "FROM pg_relcheck " - "WHERE rcrelid = '%u'::oid " - "ORDER BY rcname", - tbinfo->dobj.catId.oid); - } - else - { - /* no tableoid in 7.0 */ - appendPQExpBuffer(q, "SELECT " - "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, " - "oid, rcname AS conname, " - "'CHECK (' || rcsrc || ')' AS consrc, " - "true AS conislocal, true AS convalidated " - "FROM pg_relcheck " - "WHERE rcrelid = '%u'::oid " - "ORDER BY rcname", - tbinfo->dobj.catId.oid); - } + res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK); numConstrs = PQntuples(res); @@ -8286,8 +8092,7 @@ getTSParsers(Archive *fout, int *numTSParsers) prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname)); prsinfo[i].dobj.namespace = findNamespace(fout, - atooid(PQgetvalue(res, i, i_prsnamespace)), - prsinfo[i].dobj.catId.oid); + atooid(PQgetvalue(res, i, i_prsnamespace))); prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart)); prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken)); prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend)); @@ -8373,8 +8178,7 @@ getTSDictionaries(Archive *fout, int *numTSDicts) dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname)); dictinfo[i].dobj.namespace = findNamespace(fout, - atooid(PQgetvalue(res, i, i_dictnamespace)), - dictinfo[i].dobj.catId.oid); + atooid(PQgetvalue(res, i, i_dictnamespace))); dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname)); dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate)); if (PQgetisnull(res, i, i_dictinitoption)) @@ -8457,8 +8261,7 @@ getTSTemplates(Archive *fout, int *numTSTemplates) tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname)); tmplinfo[i].dobj.namespace = findNamespace(fout, - atooid(PQgetvalue(res, i, i_tmplnamespace)), - tmplinfo[i].dobj.catId.oid); + atooid(PQgetvalue(res, i, i_tmplnamespace))); tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit)); tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize)); @@ -8538,8 +8341,7 @@ getTSConfigurations(Archive *fout, int *numTSConfigs) cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname)); cfginfo[i].dobj.namespace = findNamespace(fout, - atooid(PQgetvalue(res, i, i_cfgnamespace)), - cfginfo[i].dobj.catId.oid); + atooid(PQgetvalue(res, i, i_cfgnamespace))); cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname)); cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser)); @@ -8947,8 +8749,7 @@ getDefaultACLs(Archive *fout, int *numDefaultACLs) daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype)); if (nspid != InvalidOid) - daclinfo[i].dobj.namespace = findNamespace(fout, nspid, - daclinfo[i].dobj.catId.oid); + daclinfo[i].dobj.namespace = findNamespace(fout, nspid); else daclinfo[i].dobj.namespace = NULL; @@ -9156,14 +8957,6 @@ findComments(Archive *fout, Oid classoid, Oid objoid, if (ncomments < 0) ncomments = collectComments(fout, &comments); - /* - * Pre-7.2, pg_description does not contain classoid, so collectComments - * just stores a zero. If there's a collision on object OID, well, you - * get duplicate comments. - */ - if (fout->remoteVersion < 70200) - classoid = 0; - /* * Do binary search to find some item matching the object. */ @@ -9251,25 +9044,9 @@ collectComments(Archive *fout, CommentItem **items) query = createPQExpBuffer(); - if (fout->remoteVersion >= 70300) - { - appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid " - "FROM pg_catalog.pg_description " - "ORDER BY classoid, objoid, objsubid"); - } - else if (fout->remoteVersion >= 70200) - { - appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid " - "FROM pg_description " - "ORDER BY classoid, objoid, objsubid"); - } - else - { - /* Note: this will fail to find attribute comments in pre-7.2... */ - appendPQExpBufferStr(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid " - "FROM pg_description " - "ORDER BY objoid"); - } + appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid " + "FROM pg_catalog.pg_description " + "ORDER BY classoid, objoid, objsubid"); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -9382,11 +9159,11 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj) case DO_TRANSFORM: dumpTransform(fout, (TransformInfo *) dobj); break; + case DO_SEQUENCE_SET: + dumpSequenceData(fout, (TableDataInfo *) dobj); + break; case DO_TABLE_DATA: - if (((TableDataInfo *) dobj)->tdtable->relkind == RELKIND_SEQUENCE) - dumpSequenceData(fout, (TableDataInfo *) dobj); - else - dumpTableData(fout, (TableDataInfo *) dobj); + dumpTableData(fout, (TableDataInfo *) dobj); break; case DO_DUMMY_TYPE: /* table rowtypes and array types are never dumped separately */ @@ -9427,6 +9204,15 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj) case DO_POLICY: dumpPolicy(fout, (PolicyInfo *) dobj); break; + case DO_PUBLICATION: + dumpPublication(fout, (PublicationInfo *) dobj); + break; + case DO_PUBLICATION_REL: + dumpPublicationTable(fout, (PublicationRelInfo *) dobj); + break; + case DO_SUBSCRIPTION: + dumpSubscription(fout, (SubscriptionInfo *) dobj); + break; case DO_PRE_DATA_BOUNDARY: case DO_POST_DATA_BOUNDARY: /* never dumped, nothing to do */ @@ -9451,10 +9237,6 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo) if (!nspinfo->dobj.dump || dopt->dataOnly) return; - /* don't dump dummy namespace from pre-7.3 source */ - if (strlen(nspinfo->dobj.name) == 0) - return; - q = createPQExpBuffer(); delq = createPQExpBuffer(); labelq = createPQExpBuffer(); @@ -9554,8 +9336,8 @@ dumpExtension(Archive *fout, ExtensionInfo *extinfo) /* * We unconditionally create the extension, so we must drop it if it * exists. This could happen if the user deleted 'plpgsql' and then - * readded it, causing its oid to be greater than FirstNormalObjectId. - * The FirstNormalObjectId test was kept to avoid repeatedly dropping + * readded it, causing its oid to be greater than g_last_builtin_oid. + * The g_last_builtin_oid test was kept to avoid repeatedly dropping * and recreating extensions like 'plpgsql'. */ appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname); @@ -10109,7 +9891,7 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo) "WHERE oid = '%u'::pg_catalog.oid", tyinfo->dobj.catId.oid); } - else if (fout->remoteVersion >= 80000) + else { appendPQExpBuffer(query, "SELECT typlen, " "typinput, typoutput, typreceive, typsend, " @@ -10127,105 +9909,6 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo) "WHERE oid = '%u'::pg_catalog.oid", tyinfo->dobj.catId.oid); } - else if (fout->remoteVersion >= 70400) - { - appendPQExpBuffer(query, "SELECT typlen, " - "typinput, typoutput, typreceive, typsend, " - "'-' AS typmodin, '-' AS typmodout, " - "'-' AS typanalyze, " - "typreceive::pg_catalog.oid AS typreceiveoid, " - "typsend::pg_catalog.oid AS typsendoid, " - "0 AS typmodinoid, 0 AS typmodoutoid, " - "0 AS typanalyzeoid, " - "'U' AS typcategory, false AS typispreferred, " - "typdelim, typbyval, typalign, typstorage, " - "false AS typcollatable, " - "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault " - "FROM pg_catalog.pg_type " - "WHERE oid = '%u'::pg_catalog.oid", - tyinfo->dobj.catId.oid); - } - else if (fout->remoteVersion >= 70300) - { - appendPQExpBuffer(query, "SELECT typlen, " - "typinput, typoutput, " - "'-' AS typreceive, '-' AS typsend, " - "'-' AS typmodin, '-' AS typmodout, " - "'-' AS typanalyze, " - "0 AS typreceiveoid, 0 AS typsendoid, " - "0 AS typmodinoid, 0 AS typmodoutoid, " - "0 AS typanalyzeoid, " - "'U' AS typcategory, false AS typispreferred, " - "typdelim, typbyval, typalign, typstorage, " - "false AS typcollatable, " - "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault " - "FROM pg_catalog.pg_type " - "WHERE oid = '%u'::pg_catalog.oid", - tyinfo->dobj.catId.oid); - } - else if (fout->remoteVersion >= 70200) - { - /* - * Note: although pre-7.3 catalogs contain typreceive and typsend, - * ignore them because they are not right. - */ - appendPQExpBuffer(query, "SELECT typlen, " - "typinput, typoutput, " - "'-' AS typreceive, '-' AS typsend, " - "'-' AS typmodin, '-' AS typmodout, " - "'-' AS typanalyze, " - "0 AS typreceiveoid, 0 AS typsendoid, " - "0 AS typmodinoid, 0 AS typmodoutoid, " - "0 AS typanalyzeoid, " - "'U' AS typcategory, false AS typispreferred, " - "typdelim, typbyval, typalign, typstorage, " - "false AS typcollatable, " - "NULL AS typdefaultbin, typdefault " - "FROM pg_type " - "WHERE oid = '%u'::oid", - tyinfo->dobj.catId.oid); - } - else if (fout->remoteVersion >= 70100) - { - /* - * Ignore pre-7.2 typdefault; the field exists but has an unusable - * representation. - */ - appendPQExpBuffer(query, "SELECT typlen, " - "typinput, typoutput, " - "'-' AS typreceive, '-' AS typsend, " - "'-' AS typmodin, '-' AS typmodout, " - "'-' AS typanalyze, " - "0 AS typreceiveoid, 0 AS typsendoid, " - "0 AS typmodinoid, 0 AS typmodoutoid, " - "0 AS typanalyzeoid, " - "'U' AS typcategory, false AS typispreferred, " - "typdelim, typbyval, typalign, typstorage, " - "false AS typcollatable, " - "NULL AS typdefaultbin, NULL AS typdefault " - "FROM pg_type " - "WHERE oid = '%u'::oid", - tyinfo->dobj.catId.oid); - } - else - { - appendPQExpBuffer(query, "SELECT typlen, " - "typinput, typoutput, " - "'-' AS typreceive, '-' AS typsend, " - "'-' AS typmodin, '-' AS typmodout, " - "'-' AS typanalyze, " - "0 AS typreceiveoid, 0 AS typsendoid, " - "0 AS typmodinoid, 0 AS typmodoutoid, " - "0 AS typanalyzeoid, " - "'U' AS typcategory, false AS typispreferred, " - "typdelim, typbyval, typalign, " - "'p'::char AS typstorage, " - "false AS typcollatable, " - "NULL AS typdefaultbin, NULL AS typdefault " - "FROM pg_type " - "WHERE oid = '%u'::oid", - tyinfo->dobj.catId.oid); - } res = ExecuteSqlQueryForSingleRow(fout, query->data); @@ -10283,30 +9966,19 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo) qtypname, (strcmp(typlen, "-1") == 0) ? "variable" : typlen); - if (fout->remoteVersion >= 70300) - { - /* regproc result is correctly quoted as of 7.3 */ - appendPQExpBuffer(q, ",\n INPUT = %s", typinput); - appendPQExpBuffer(q, ",\n OUTPUT = %s", typoutput); - if (OidIsValid(typreceiveoid)) - appendPQExpBuffer(q, ",\n RECEIVE = %s", typreceive); - if (OidIsValid(typsendoid)) - appendPQExpBuffer(q, ",\n SEND = %s", typsend); - if (OidIsValid(typmodinoid)) - appendPQExpBuffer(q, ",\n TYPMOD_IN = %s", typmodin); - if (OidIsValid(typmodoutoid)) - appendPQExpBuffer(q, ",\n TYPMOD_OUT = %s", typmodout); - if (OidIsValid(typanalyzeoid)) - appendPQExpBuffer(q, ",\n ANALYZE = %s", typanalyze); - } - else - { - /* regproc delivers an unquoted name before 7.3 */ - /* cannot combine these because fmtId uses static result area */ - appendPQExpBuffer(q, ",\n INPUT = %s", fmtId(typinput)); - appendPQExpBuffer(q, ",\n OUTPUT = %s", fmtId(typoutput)); - /* receive/send/typmodin/typmodout/analyze need not be printed */ - } + /* regproc result is sufficiently quoted already */ + appendPQExpBuffer(q, ",\n INPUT = %s", typinput); + appendPQExpBuffer(q, ",\n OUTPUT = %s", typoutput); + if (OidIsValid(typreceiveoid)) + appendPQExpBuffer(q, ",\n RECEIVE = %s", typreceive); + if (OidIsValid(typsendoid)) + appendPQExpBuffer(q, ",\n SEND = %s", typsend); + if (OidIsValid(typmodinoid)) + appendPQExpBuffer(q, ",\n TYPMOD_IN = %s", typmodin); + if (OidIsValid(typmodoutoid)) + appendPQExpBuffer(q, ",\n TYPMOD_OUT = %s", typmodout); + if (OidIsValid(typanalyzeoid)) + appendPQExpBuffer(q, ",\n ANALYZE = %s", typanalyze); if (strcmp(typcollatable, "t") == 0) appendPQExpBufferStr(q, ",\n COLLATABLE = true"); @@ -10451,7 +10123,6 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo) } else { - /* We assume here that remoteVersion must be at least 70300 */ appendPQExpBuffer(query, "SELECT typnotnull, " "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, " "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, " @@ -10652,9 +10323,8 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo) else { /* - * We assume here that remoteVersion must be at least 70300. Since - * ALTER TYPE could not drop columns until 9.1, attisdropped should - * always be false. + * Since ALTER TYPE could not drop columns until 9.1, attisdropped + * should always be false. */ appendPQExpBuffer(query, "SELECT a.attname, " "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, " @@ -10841,7 +10511,6 @@ dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo) query = createPQExpBuffer(); - /* We assume here that remoteVersion must be at least 70300 */ appendPQExpBuffer(query, "SELECT c.tableoid, a.attname, a.attnum " "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a " @@ -11425,7 +11094,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) "WHERE oid = '%u'::pg_catalog.oid", finfo->dobj.catId.oid); } - else if (fout->remoteVersion >= 80000) + else { appendPQExpBuffer(query, "SELECT proretset, prosrc, probin, " @@ -11441,58 +11110,6 @@ dumpFunc(Archive *fout, FuncInfo *finfo) "WHERE oid = '%u'::pg_catalog.oid", finfo->dobj.catId.oid); } - else if (fout->remoteVersion >= 70300) - { - appendPQExpBuffer(query, - "SELECT proretset, prosrc, probin, " - "null AS proallargtypes, " - "null AS proargmodes, " - "null AS proargnames, " - "false AS proiswindow, " - "provolatile, proisstrict, prosecdef, " - "false AS proleakproof, " - "null AS proconfig, 0 AS procost, 0 AS prorows, " - "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " - "FROM pg_catalog.pg_proc " - "WHERE oid = '%u'::pg_catalog.oid", - finfo->dobj.catId.oid); - } - else if (fout->remoteVersion >= 70100) - { - appendPQExpBuffer(query, - "SELECT proretset, prosrc, probin, " - "null AS proallargtypes, " - "null AS proargmodes, " - "null AS proargnames, " - "false AS proiswindow, " - "case when proiscachable then 'i' else 'v' end AS provolatile, " - "proisstrict, " - "false AS prosecdef, " - "false AS proleakproof, " - "null AS proconfig, 0 AS procost, 0 AS prorows, " - "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname " - "FROM pg_proc " - "WHERE oid = '%u'::oid", - finfo->dobj.catId.oid); - } - else - { - appendPQExpBuffer(query, - "SELECT proretset, prosrc, probin, " - "null AS proallargtypes, " - "null AS proargmodes, " - "null AS proargnames, " - "false AS proiswindow, " - "CASE WHEN proiscachable THEN 'i' ELSE 'v' END AS provolatile, " - "false AS proisstrict, " - "false AS prosecdef, " - "false AS proleakproof, " - "NULL AS proconfig, 0 AS procost, 0 AS prorows, " - "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname " - "FROM pg_proc " - "WHERE oid = '%u'::oid", - finfo->dobj.catId.oid); - } res = ExecuteSqlQueryForSingleRow(fout, query->data); @@ -11844,7 +11461,8 @@ dumpCast(Archive *fout, CastInfo *cast) { funcInfo = findFuncByOid(cast->castfunc); if (funcInfo == NULL) - return; + exit_horribly(NULL, "unable to find function definition for OID %u", + cast->castfunc); } /* @@ -11953,13 +11571,15 @@ dumpTransform(Archive *fout, TransformInfo *transform) { fromsqlFuncInfo = findFuncByOid(transform->trffromsql); if (fromsqlFuncInfo == NULL) - return; + exit_horribly(NULL, "unable to find function definition for OID %u", + transform->trffromsql); } if (OidIsValid(transform->trftosql)) { tosqlFuncInfo = findFuncByOid(transform->trftosql); if (tosqlFuncInfo == NULL) - return; + exit_horribly(NULL, "unable to find function definition for OID %u", + transform->trftosql); } /* Make sure we are in proper schema (needed for getFormattedTypeName) */ @@ -12065,7 +11685,6 @@ dumpOpr(Archive *fout, OprInfo *oprinfo) PQExpBuffer labelq; PQExpBuffer oprid; PQExpBuffer details; - const char *name; PGresult *res; int i_oprkind; int i_oprcode; @@ -12126,7 +11745,7 @@ dumpOpr(Archive *fout, OprInfo *oprinfo) "WHERE oid = '%u'::pg_catalog.oid", oprinfo->dobj.catId.oid); } - else if (fout->remoteVersion >= 70300) + else { appendPQExpBuffer(query, "SELECT oprkind, " "oprcode::pg_catalog.regprocedure, " @@ -12139,35 +11758,7 @@ dumpOpr(Archive *fout, OprInfo *oprinfo) "(oprlsortop != 0) AS oprcanmerge, " "oprcanhash " "FROM pg_catalog.pg_operator " - "WHERE oid = '%u'::pg_catalog.oid", - oprinfo->dobj.catId.oid); - } - else if (fout->remoteVersion >= 70100) - { - appendPQExpBuffer(query, "SELECT oprkind, oprcode, " - "CASE WHEN oprleft = 0 THEN '-' " - "ELSE format_type(oprleft, NULL) END AS oprleft, " - "CASE WHEN oprright = 0 THEN '-' " - "ELSE format_type(oprright, NULL) END AS oprright, " - "oprcom, oprnegate, oprrest, oprjoin, " - "(oprlsortop != 0) AS oprcanmerge, " - "oprcanhash " - "FROM pg_operator " - "WHERE oid = '%u'::oid", - oprinfo->dobj.catId.oid); - } - else - { - appendPQExpBuffer(query, "SELECT oprkind, oprcode, " - "CASE WHEN oprleft = 0 THEN '-'::name " - "ELSE (SELECT typname FROM pg_type WHERE oid = oprleft) END AS oprleft, " - "CASE WHEN oprright = 0 THEN '-'::name " - "ELSE (SELECT typname FROM pg_type WHERE oid = oprright) END AS oprright, " - "oprcom, oprnegate, oprrest, oprjoin, " - "(oprlsortop != 0) AS oprcanmerge, " - "oprcanhash " - "FROM pg_operator " - "WHERE oid = '%u'::oid", + "WHERE oid = '%u'::pg_catalog.oid", oprinfo->dobj.catId.oid); } @@ -12212,12 +11803,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo) if (strcmp(oprkind, "r") == 0 || strcmp(oprkind, "b") == 0) { - if (fout->remoteVersion >= 70100) - name = oprleft; - else - name = fmtId(oprleft); - appendPQExpBuffer(details, ",\n LEFTARG = %s", name); - appendPQExpBufferStr(oprid, name); + appendPQExpBuffer(details, ",\n LEFTARG = %s", oprleft); + appendPQExpBufferStr(oprid, oprleft); } else appendPQExpBufferStr(oprid, "NONE"); @@ -12225,12 +11812,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo) if (strcmp(oprkind, "l") == 0 || strcmp(oprkind, "b") == 0) { - if (fout->remoteVersion >= 70100) - name = oprright; - else - name = fmtId(oprright); - appendPQExpBuffer(details, ",\n RIGHTARG = %s", name); - appendPQExpBuffer(oprid, ", %s)", name); + appendPQExpBuffer(details, ",\n RIGHTARG = %s", oprright); + appendPQExpBuffer(oprid, ", %s)", oprright); } else appendPQExpBufferStr(oprid, ", NONE)"); @@ -12317,40 +11900,34 @@ dumpOpr(Archive *fout, OprInfo *oprinfo) * Returns allocated string of what to print, or NULL if function references * is InvalidOid. Returned string is expected to be free'd by the caller. * - * In 7.3 the input is a REGPROCEDURE display; we have to strip the - * argument-types part. In prior versions, the input is a REGPROC display. + * The input is a REGPROCEDURE display; we have to strip the argument-types + * part. */ static char * convertRegProcReference(Archive *fout, const char *proc) { + char *name; + char *paren; + bool inquote; + /* In all cases "-" means a null reference */ if (strcmp(proc, "-") == 0) return NULL; - if (fout->remoteVersion >= 70300) + name = pg_strdup(proc); + /* find non-double-quoted left paren */ + inquote = false; + for (paren = name; *paren; paren++) { - char *name; - char *paren; - bool inquote; - - name = pg_strdup(proc); - /* find non-double-quoted left paren */ - inquote = false; - for (paren = name; *paren; paren++) + if (*paren == '(' && !inquote) { - if (*paren == '(' && !inquote) - { - *paren = '\0'; - break; - } - if (*paren == '"') - inquote = !inquote; + *paren = '\0'; + break; } - return name; + if (*paren == '"') + inquote = !inquote; } - - /* REGPROC before 7.3 does not quote its result */ - return pg_strdup(fmtId(proc)); + return name; } /* @@ -12359,60 +11936,44 @@ convertRegProcReference(Archive *fout, const char *proc) * Returns an allocated string of what to print, or NULL to print nothing. * Caller is responsible for free'ing result string. * - * In 7.3 and up the input is a REGOPERATOR display; we have to strip the - * argument-types part, and add OPERATOR() decoration if the name is - * schema-qualified. In older versions, the input is just a numeric OID, - * which we search our operator list for. + * The input is a REGOPERATOR display; we have to strip the argument-types + * part, and add OPERATOR() decoration if the name is schema-qualified. */ static char * convertOperatorReference(Archive *fout, const char *opr) { - OprInfo *oprInfo; + char *name; + char *oname; + char *ptr; + bool inquote; + bool sawdot; /* In all cases "0" means a null reference */ if (strcmp(opr, "0") == 0) return NULL; - if (fout->remoteVersion >= 70300) - { - char *name; - char *oname; - char *ptr; - bool inquote; - bool sawdot; - - name = pg_strdup(opr); - /* find non-double-quoted left paren, and check for non-quoted dot */ - inquote = false; - sawdot = false; - for (ptr = name; *ptr; ptr++) + name = pg_strdup(opr); + /* find non-double-quoted left paren, and check for non-quoted dot */ + inquote = false; + sawdot = false; + for (ptr = name; *ptr; ptr++) + { + if (*ptr == '"') + inquote = !inquote; + else if (*ptr == '.' && !inquote) + sawdot = true; + else if (*ptr == '(' && !inquote) { - if (*ptr == '"') - inquote = !inquote; - else if (*ptr == '.' && !inquote) - sawdot = true; - else if (*ptr == '(' && !inquote) - { - *ptr = '\0'; - break; - } + *ptr = '\0'; + break; } - /* If not schema-qualified, don't need to add OPERATOR() */ - if (!sawdot) - return name; - oname = psprintf("OPERATOR(%s)", name); - free(name); - return oname; - } - - oprInfo = findOprByOid(atooid(opr)); - if (oprInfo == NULL) - { - write_msg(NULL, "WARNING: could not find operator with OID %s\n", - opr); - return NULL; } - return pg_strdup(oprInfo->dobj.name); + /* If not schema-qualified, don't need to add OPERATOR() */ + if (!sawdot) + return name; + oname = psprintf("OPERATOR(%s)", name); + free(name); + return oname; } /* @@ -12489,6 +12050,9 @@ dumpAccessMethod(Archive *fout, AccessMethodInfo *aminfo) appendPQExpBuffer(labelq, "ACCESS METHOD %s", qamname); + if (dopt->binary_upgrade) + binary_upgrade_extension_member(q, &aminfo->dobj, labelq->data); + if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION) ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId, aminfo->dobj.name, @@ -12566,14 +12130,6 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo) if (!opcinfo->dobj.dump || dopt->dataOnly) return; - /* - * XXX currently we do not implement dumping of operator classes from - * pre-7.3 databases. This could be done but it seems not worth the - * trouble. - */ - if (fout->remoteVersion < 70300) - return; - query = createPQExpBuffer(); q = createPQExpBuffer(); delq = createPQExpBuffer(); @@ -13323,7 +12879,7 @@ dumpConversion(Archive *fout, ConvInfo *convinfo) appendStringLiteralAH(q, conforencoding, fout); appendPQExpBufferStr(q, " TO "); appendStringLiteralAH(q, contoencoding, fout); - /* regproc is automatically quoted in 7.3 and above */ + /* regproc output is already sufficiently quoted */ appendPQExpBuffer(q, " FROM %s;\n", conproc); appendPQExpBuffer(labelq, "CONVERSION %s", fmtId(convinfo->dobj.name)); @@ -13549,7 +13105,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo) "AND p.oid = '%u'::pg_catalog.oid", agginfo->aggfn.dobj.catId.oid); } - else if (fout->remoteVersion >= 70300) + else { appendPQExpBuffer(query, "SELECT aggtransfn, " "aggfinalfn, aggtranstype::pg_catalog.regtype, " @@ -13567,41 +13123,6 @@ dumpAgg(Archive *fout, AggInfo *agginfo) "AND p.oid = '%u'::pg_catalog.oid", agginfo->aggfn.dobj.catId.oid); } - else if (fout->remoteVersion >= 70100) - { - appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, " - "format_type(aggtranstype, NULL) AS aggtranstype, " - "'-' AS aggcombinefn, '-' AS aggserialfn, " - "'-' AS aggdeserialfn, '-' AS aggmtransfn, " - "'-' AS aggminvtransfn, '-' AS aggmfinalfn, " - "0 AS aggmtranstype, false AS aggfinalextra, " - "false AS aggmfinalextra, 0 AS aggsortop, " - "false AS hypothetical, " - "0 AS aggtransspace, agginitval, " - "0 AS aggmtransspace, NULL AS aggminitval, " - "true AS convertok " - "FROM pg_aggregate " - "WHERE oid = '%u'::oid", - agginfo->aggfn.dobj.catId.oid); - } - else - { - appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, " - "aggfinalfn, " - "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, " - "'-' AS aggcombinefn, '-' AS aggserialfn, " - "'-' AS aggdeserialfn, '-' AS aggmtransfn, " - "'-' AS aggminvtransfn, '-' AS aggmfinalfn, " - "0 AS aggmtranstype, false AS aggfinalextra, " - "false AS aggmfinalextra, 0 AS aggsortop, " - "false AS hypothetical, " - "0 AS aggtransspace, agginitval1 AS agginitval, " - "0 AS aggmtransspace, NULL AS aggminitval, " - "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok " - "FROM pg_aggregate " - "WHERE oid = '%u'::oid", - agginfo->aggfn.dobj.catId.oid); - } res = ExecuteSqlQueryForSingleRow(fout, query->data); @@ -13681,28 +13202,9 @@ dumpAgg(Archive *fout, AggInfo *agginfo) return; } - if (fout->remoteVersion >= 70300) - { - /* If using 7.3's regproc or regtype, data is already quoted */ - appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s", - aggtransfn, - aggtranstype); - } - else if (fout->remoteVersion >= 70100) - { - /* format_type quotes, regproc does not */ - appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s", - fmtId(aggtransfn), - aggtranstype); - } - else - { - /* need quotes all around */ - appendPQExpBuffer(details, " SFUNC = %s,\n", - fmtId(aggtransfn)); - appendPQExpBuffer(details, " STYPE = %s", - fmtId(aggtranstype)); - } + /* regproc and regtype output is already sufficiently quoted */ + appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s", + aggtransfn, aggtranstype); if (strcmp(aggtransspace, "0") != 0) { @@ -15101,19 +14603,9 @@ createViewAsClause(Archive *fout, TableInfo *tbinfo) int len; /* Fetch the view definition */ - if (fout->remoteVersion >= 70300) - { - /* Beginning in 7.3, viewname is not unique; rely on OID */ - appendPQExpBuffer(query, + appendPQExpBuffer(query, "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef", - tbinfo->dobj.catId.oid); - } - else - { - appendPQExpBufferStr(query, "SELECT definition AS viewdef " - "FROM pg_views WHERE viewname = "); - appendStringLiteralAH(query, tbinfo->dobj.name, fout); - } + tbinfo->dobj.catId.oid); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -15143,6 +14635,54 @@ createViewAsClause(Archive *fout, TableInfo *tbinfo) return result; } +/* + * Create a dummy AS clause for a view. This is used when the real view + * definition has to be postponed because of circular dependencies. + * We must duplicate the view's external properties -- column names and types + * (including collation) -- so that it works for subsequent references. + * + * This returns a new buffer which must be freed by the caller. + */ +static PQExpBuffer +createDummyViewAsClause(Archive *fout, TableInfo *tbinfo) +{ + PQExpBuffer result = createPQExpBuffer(); + int j; + + appendPQExpBufferStr(result, "SELECT"); + + for (j = 0; j < tbinfo->numatts; j++) + { + if (j > 0) + appendPQExpBufferChar(result, ','); + appendPQExpBufferStr(result, "\n "); + + appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]); + + /* + * Must add collation if not default for the type, because CREATE OR + * REPLACE VIEW won't change it + */ + if (OidIsValid(tbinfo->attcollation[j])) + { + CollInfo *coll; + + coll = findCollationByOid(tbinfo->attcollation[j]); + if (coll) + { + /* always schema-qualify, don't try to be smart */ + appendPQExpBuffer(result, " COLLATE %s.", + fmtId(coll->dobj.namespace->dobj.name)); + appendPQExpBufferStr(result, fmtId(coll->dobj.name)); + } + } + + appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j])); + } + + return result; +} + /* * dumpTableSchema * write the declaration (not data) of one user-defined table or view @@ -15176,6 +14716,10 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) { PQExpBuffer result; + /* + * Note: keep this code in sync with the is_view case in dumpRule() + */ + reltypename = "VIEW"; /* @@ -15192,17 +14736,22 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) tbinfo->dobj.catId.oid, false); appendPQExpBuffer(q, "CREATE VIEW %s", fmtId(tbinfo->dobj.name)); - if (nonemptyReloptions(tbinfo->reloptions)) + if (tbinfo->dummy_view) + result = createDummyViewAsClause(fout, tbinfo); + else { - appendPQExpBufferStr(q, " WITH ("); - appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout); - appendPQExpBufferChar(q, ')'); + if (nonemptyReloptions(tbinfo->reloptions)) + { + appendPQExpBufferStr(q, " WITH ("); + appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout); + appendPQExpBufferChar(q, ')'); + } + result = createViewAsClause(fout, tbinfo); } - result = createViewAsClause(fout, tbinfo); appendPQExpBuffer(q, " AS\n%s", result->data); destroyPQExpBuffer(result); - if (tbinfo->checkoption != NULL) + if (tbinfo->checkoption != NULL && !tbinfo->dummy_view) appendPQExpBuffer(q, "\n WITH %s CHECK OPTION", tbinfo->checkoption); appendPQExpBufferStr(q, ";\n"); @@ -15288,6 +14837,17 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) if (tbinfo->reloftype && !dopt->binary_upgrade) appendPQExpBuffer(q, " OF %s", tbinfo->reloftype); + if (tbinfo->partitionOf && !dopt->binary_upgrade) + { + TableInfo *parentRel = tbinfo->partitionOf; + + appendPQExpBuffer(q, " PARTITION OF "); + if (parentRel->dobj.namespace != tbinfo->dobj.namespace) + appendPQExpBuffer(q, "%s.", + fmtId(parentRel->dobj.namespace->dobj.name)); + appendPQExpBufferStr(q, fmtId(parentRel->dobj.name)); + } + if (tbinfo->relkind != RELKIND_MATVIEW) { /* Dump the attributes */ @@ -15316,8 +14876,11 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) (!tbinfo->inhNotNull[j] || dopt->binary_upgrade)); - /* Skip column if fully defined by reloftype */ - if (tbinfo->reloftype && + /* + * Skip column if fully defined by reloftype or the + * partition parent. + */ + if ((tbinfo->reloftype || tbinfo->partitionOf) && !has_default && !has_notnull && !dopt->binary_upgrade) continue; @@ -15346,21 +14909,15 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) } /* Attribute type */ - if (tbinfo->reloftype && !dopt->binary_upgrade) + if ((tbinfo->reloftype || tbinfo->partitionOf) && + !dopt->binary_upgrade) { appendPQExpBufferStr(q, " WITH OPTIONS"); } - else if (fout->remoteVersion >= 70100) - { - appendPQExpBuffer(q, " %s", - tbinfo->atttypnames[j]); - } else { - /* If no format_type, fake it */ appendPQExpBuffer(q, " %s", - myFormatType(tbinfo->atttypnames[j], - tbinfo->atttypmod[j])); + tbinfo->atttypnames[j]); } /* Add collation if not default for the type */ @@ -15411,15 +14968,22 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) if (actual_atts) appendPQExpBufferStr(q, "\n)"); - else if (!(tbinfo->reloftype && !dopt->binary_upgrade)) + else if (!((tbinfo->reloftype || tbinfo->partitionOf) && + !dopt->binary_upgrade)) { /* * We must have a parenthesized attribute list, even though - * empty, when not using the OF TYPE syntax. + * empty, when not using the OF TYPE or PARTITION OF syntax. */ appendPQExpBufferStr(q, " (\n)"); } + if (tbinfo->partitiondef && !dopt->binary_upgrade) + { + appendPQExpBufferStr(q, "\n"); + appendPQExpBufferStr(q, tbinfo->partitiondef); + } + if (numParents > 0 && !dopt->binary_upgrade) { appendPQExpBufferStr(q, "\nINHERITS ("); @@ -15437,6 +15001,9 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) appendPQExpBufferChar(q, ')'); } + if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE) + appendPQExpBuffer(q, "\nPARTITION BY %s", tbinfo->partkeydef); + if (tbinfo->relkind == RELKIND_FOREIGN_TABLE) appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname)); } @@ -15497,7 +15064,8 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) */ if (dopt->binary_upgrade && (tbinfo->relkind == RELKIND_RELATION || - tbinfo->relkind == RELKIND_FOREIGN_TABLE)) + tbinfo->relkind == RELKIND_FOREIGN_TABLE || + tbinfo->relkind == RELKIND_PARTITIONED_TABLE)) { for (j = 0; j < tbinfo->numatts; j++) { @@ -15515,7 +15083,8 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout); appendPQExpBufferStr(q, "::pg_catalog.regclass;\n"); - if (tbinfo->relkind == RELKIND_RELATION) + if (tbinfo->relkind == RELKIND_RELATION || + tbinfo->relkind == RELKIND_PARTITIONED_TABLE) appendPQExpBuffer(q, "ALTER TABLE ONLY %s ", fmtId(tbinfo->dobj.name)); else @@ -15584,6 +15153,16 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) tbinfo->reloftype); } + if (tbinfo->partitionOf) + { + appendPQExpBufferStr(q, "\n-- For binary upgrade, set up partitions this way.\n"); + appendPQExpBuffer(q, "ALTER TABLE ONLY %s ", + fmtId(tbinfo->partitionOf->dobj.name)); + appendPQExpBuffer(q, "ATTACH PARTITION %s %s;\n", + fmtId(tbinfo->dobj.name), + tbinfo->partitiondef); + } + appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n"); appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n" "SET relfrozenxid = '%u', relminmxid = '%u'\n" @@ -15732,6 +15311,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) * dump properties we only have ALTER TABLE syntax for */ if ((tbinfo->relkind == RELKIND_RELATION || + tbinfo->relkind == RELKIND_PARTITIONED_TABLE || tbinfo->relkind == RELKIND_MATVIEW) && tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT) { @@ -16264,17 +15844,18 @@ dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo) } /* - * findLastBuiltInOid - + * findLastBuiltinOid_V71 - + * * find the last built in oid * - * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the - * pg_database entry for the current database + * For 7.1 through 8.0, we do this by retrieving datlastsysoid from the + * pg_database entry for the current database. */ static Oid findLastBuiltinOid_V71(Archive *fout, const char *dbname) { PGresult *res; - Oid last_oid; + Oid last_oid; PQExpBuffer query = createPQExpBuffer(); resetPQExpBuffer(query); @@ -16285,27 +15866,7 @@ findLastBuiltinOid_V71(Archive *fout, const char *dbname) last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid"))); PQclear(res); destroyPQExpBuffer(query); - return last_oid; -} - -/* - * findLastBuiltInOid - - * find the last built in oid - * - * For 7.0, we do this by assuming that the last thing that initdb does is to - * create the pg_indexes view. This sucks in general, but seeing that 7.0.x - * initdb won't be changing anymore, it'll do. - */ -static Oid -findLastBuiltinOid_V70(Archive *fout) -{ - PGresult *res; - int last_oid; - res = ExecuteSqlQueryForSingleRow(fout, - "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'"); - last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid"))); - PQclear(res); return last_oid; } @@ -16336,11 +15897,29 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE); snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE); - if (fout->remoteVersion >= 80400) + if (fout->remoteVersion >= 100000) { appendPQExpBuffer(query, - "SELECT sequence_name, " - "start_value, increment_by, " + "SELECT seqstart, seqincrement, " + "CASE WHEN seqincrement > 0 AND seqmax = %s THEN NULL " + " WHEN seqincrement < 0 AND seqmax = -1 THEN NULL " + " ELSE seqmax " + "END AS seqmax, " + "CASE WHEN seqincrement > 0 AND seqmin = 1 THEN NULL " + " WHEN seqincrement < 0 AND seqmin = %s THEN NULL " + " ELSE seqmin " + "END AS seqmin, " + "seqcache, seqcycle " + "FROM pg_class c " + "JOIN pg_sequence s ON (s.seqrelid = c.oid) " + "WHERE relname = ", + bufx, bufm); + appendStringLiteralAH(query, tbinfo->dobj.name, fout); + } + else if (fout->remoteVersion >= 80400) + { + appendPQExpBuffer(query, + "SELECT start_value, increment_by, " "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL " " WHEN increment_by < 0 AND max_value = -1 THEN NULL " " ELSE max_value " @@ -16356,8 +15935,7 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) else { appendPQExpBuffer(query, - "SELECT sequence_name, " - "0 AS start_value, increment_by, " + "SELECT 0 AS start_value, increment_by, " "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL " " WHEN increment_by < 0 AND max_value = -1 THEN NULL " " ELSE max_value " @@ -16382,24 +15960,14 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) exit_nicely(1); } - /* Disable this check: it fails if sequence has been renamed */ -#ifdef NOT_USED - if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0) - { - write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n", - tbinfo->dobj.name, PQgetvalue(res, 0, 0)); - exit_nicely(1); - } -#endif - - startv = PQgetvalue(res, 0, 1); - incby = PQgetvalue(res, 0, 2); + startv = PQgetvalue(res, 0, 0); + incby = PQgetvalue(res, 0, 1); + if (!PQgetisnull(res, 0, 2)) + maxv = PQgetvalue(res, 0, 2); if (!PQgetisnull(res, 0, 3)) - maxv = PQgetvalue(res, 0, 3); - if (!PQgetisnull(res, 0, 4)) - minv = PQgetvalue(res, 0, 4); - cache = PQgetvalue(res, 0, 5); - cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0); + minv = PQgetvalue(res, 0, 3); + cache = PQgetvalue(res, 0, 4); + cycled = (strcmp(PQgetvalue(res, 0, 5), "t") == 0); /* * DROP must be fully qualified in case same name appears in pg_catalog @@ -16479,7 +16047,11 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) { TableInfo *owning_tab = findTableByOid(tbinfo->owning_tab); - if (owning_tab && owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION) + if (owning_tab == NULL) + exit_horribly(NULL, "failed sanity check, parent table OID %u of sequence OID %u not found\n", + tbinfo->owning_tab, tbinfo->dobj.catId.oid); + + if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION) { resetPQExpBuffer(query); appendPQExpBuffer(query, "ALTER SEQUENCE %s", @@ -16560,7 +16132,7 @@ dumpSequenceData(Archive *fout, TableDataInfo *tdinfo) appendPQExpBuffer(query, ", %s, %s);\n", last, (called ? "true" : "false")); - if (tbinfo->dobj.dump & DUMP_COMPONENT_DATA) + if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA) ArchiveEntry(fout, nilCatalogId, createDumpId(), tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name, @@ -16683,13 +16255,9 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo) { if (OidIsValid(tginfo->tgconstrrelid)) { - /* If we are using regclass, name is already quoted */ - if (fout->remoteVersion >= 70300) - appendPQExpBuffer(query, " FROM %s\n ", - tginfo->tgconstrrelname); - else - appendPQExpBuffer(query, " FROM %s\n ", - fmtId(tginfo->tgconstrrelname)); + /* regclass output is already quoted */ + appendPQExpBuffer(query, " FROM %s\n ", + tginfo->tgconstrrelname); } if (!tginfo->tgdeferrable) appendPQExpBufferStr(query, "NOT "); @@ -16705,13 +16273,9 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo) else appendPQExpBufferStr(query, " FOR EACH STATEMENT\n "); - /* In 7.3, result of regproc is already quoted */ - if (fout->remoteVersion >= 70300) - appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(", - tginfo->tgfname); - else - appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(", - fmtId(tginfo->tgfname)); + /* regproc output is already sufficiently quoted */ + appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(", + tginfo->tgfname); tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs, &lentgargs); @@ -16875,6 +16439,7 @@ dumpRule(Archive *fout, RuleInfo *rinfo) { DumpOptions *dopt = fout->dopt; TableInfo *tbinfo = rinfo->ruletable; + bool is_view; PQExpBuffer query; PQExpBuffer cmd; PQExpBuffer delcmd; @@ -16893,6 +16458,12 @@ dumpRule(Archive *fout, RuleInfo *rinfo) if (!rinfo->separate) return; + /* + * If it's an ON SELECT rule, we want to print it as a view definition, + * instead of a rule. + */ + is_view = (rinfo->ev_type == '1' && rinfo->is_instead); + /* * Make sure we are in proper schema. */ @@ -16903,30 +16474,50 @@ dumpRule(Archive *fout, RuleInfo *rinfo) delcmd = createPQExpBuffer(); labelq = createPQExpBuffer(); - if (fout->remoteVersion >= 70300) + if (is_view) { - appendPQExpBuffer(query, - "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition", - rinfo->dobj.catId.oid); + PQExpBuffer result; + + /* + * We need OR REPLACE here because we'll be replacing a dummy view. + * Otherwise this should look largely like the regular view dump code. + */ + appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s", + fmtId(tbinfo->dobj.name)); + if (nonemptyReloptions(tbinfo->reloptions)) + { + appendPQExpBufferStr(cmd, " WITH ("); + appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout); + appendPQExpBufferChar(cmd, ')'); + } + result = createViewAsClause(fout, tbinfo); + appendPQExpBuffer(cmd, " AS\n%s", result->data); + destroyPQExpBuffer(result); + if (tbinfo->checkoption != NULL) + appendPQExpBuffer(cmd, "\n WITH %s CHECK OPTION", + tbinfo->checkoption); + appendPQExpBufferStr(cmd, ";\n"); } else { - /* Rule name was unique before 7.3 ... */ + /* In the rule case, just print pg_get_ruledef's result verbatim */ appendPQExpBuffer(query, - "SELECT pg_get_ruledef('%s') AS definition", - rinfo->dobj.name); - } + "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)", + rinfo->dobj.catId.oid); - res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); + res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); - if (PQntuples(res) != 1) - { - write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n", - rinfo->dobj.name, tbinfo->dobj.name); - exit_nicely(1); - } + if (PQntuples(res) != 1) + { + write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n", + rinfo->dobj.name, tbinfo->dobj.name); + exit_nicely(1); + } + + printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0)); - printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0)); + PQclear(res); + } /* * Add the command to alter the rules replication firing semantics if it @@ -16953,26 +16544,35 @@ dumpRule(Archive *fout, RuleInfo *rinfo) } /* - * Apply view's reloptions when its ON SELECT rule is separate. + * DROP must be fully qualified in case same name appears in pg_catalog */ - if (nonemptyReloptions(rinfo->reloptions)) + if (is_view) + { + /* + * We can't DROP a view's ON SELECT rule. Instead, use CREATE OR + * REPLACE VIEW to replace the rule with something with minimal + * dependencies. + */ + PQExpBuffer result; + + appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s.", + fmtId(tbinfo->dobj.namespace->dobj.name)); + appendPQExpBuffer(delcmd, "%s", + fmtId(tbinfo->dobj.name)); + result = createDummyViewAsClause(fout, tbinfo); + appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data); + destroyPQExpBuffer(result); + } + else { - appendPQExpBuffer(cmd, "ALTER VIEW %s SET (", + appendPQExpBuffer(delcmd, "DROP RULE %s ", + fmtId(rinfo->dobj.name)); + appendPQExpBuffer(delcmd, "ON %s.", + fmtId(tbinfo->dobj.namespace->dobj.name)); + appendPQExpBuffer(delcmd, "%s;\n", fmtId(tbinfo->dobj.name)); - appendReloptionsArrayAH(cmd, rinfo->reloptions, "", fout); - appendPQExpBufferStr(cmd, ");\n"); } - /* - * DROP must be fully qualified in case same name appears in pg_catalog - */ - appendPQExpBuffer(delcmd, "DROP RULE %s ", - fmtId(rinfo->dobj.name)); - appendPQExpBuffer(delcmd, "ON %s.", - fmtId(tbinfo->dobj.namespace->dobj.name)); - appendPQExpBuffer(delcmd, "%s;\n", - fmtId(tbinfo->dobj.name)); - appendPQExpBuffer(labelq, "RULE %s", fmtId(rinfo->dobj.name)); appendPQExpBuffer(labelq, " ON %s", @@ -16998,8 +16598,6 @@ dumpRule(Archive *fout, RuleInfo *rinfo) tbinfo->rolname, rinfo->dobj.catId, 0, rinfo->dobj.dumpId); - PQclear(res); - free(tag); destroyPQExpBuffer(query); destroyPQExpBuffer(cmd); @@ -17305,10 +16903,6 @@ getDependencies(Archive *fout) DumpableObject *dobj, *refdobj; - /* No dependency info available before 7.3 */ - if (fout->remoteVersion < 70300) - return; - if (g_verbose) write_msg(NULL, "reading dependency data\n"); @@ -17482,6 +17076,7 @@ addBoundaryDependencies(DumpableObject **dobjs, int numObjs, addObjectDependency(preDataBound, dobj->dumpId); break; case DO_TABLE_DATA: + case DO_SEQUENCE_SET: case DO_BLOB_DATA: /* Data objects: must come between the boundaries */ addObjectDependency(dobj, preDataBound->dumpId); @@ -17493,6 +17088,9 @@ addBoundaryDependencies(DumpableObject **dobjs, int numObjs, case DO_EVENT_TRIGGER: case DO_DEFAULT_ACL: case DO_POLICY: + case DO_PUBLICATION: + case DO_PUBLICATION_REL: + case DO_SUBSCRIPTION: /* Post-data objects: must come after the post-data boundary */ addObjectDependency(dobj, postDataBound->dumpId); break; @@ -17660,10 +17258,6 @@ selectSourceSchema(Archive *fout, const char *schemaName) /* This is checked by the callers already */ Assert(schemaName != NULL && *schemaName != '\0'); - /* Not relevant if fetching from pre-7.3 DB */ - if (fout->remoteVersion < 70300) - return; - query = createPQExpBuffer(); appendPQExpBuffer(query, "SET search_path = %s", fmtId(schemaName)); @@ -17679,8 +17273,8 @@ selectSourceSchema(Archive *fout, const char *schemaName) * getFormattedTypeName - retrieve a nicely-formatted type name for the * given type name. * - * NB: in 7.3 and up the result may depend on the currently-selected - * schema; this is why we don't try to cache the names. + * NB: the result may depend on the currently-selected search_path; this is + * why we don't try to cache the names. */ static char * getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts) @@ -17702,36 +17296,13 @@ getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts) } query = createPQExpBuffer(); - if (fout->remoteVersion >= 70300) - { - appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)", - oid); - } - else if (fout->remoteVersion >= 70100) - { - appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)", - oid); - } - else - { - appendPQExpBuffer(query, "SELECT typname " - "FROM pg_type " - "WHERE oid = '%u'::oid", - oid); - } + appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)", + oid); res = ExecuteSqlQueryForSingleRow(fout, query->data); - if (fout->remoteVersion >= 70100) - { - /* already quoted */ - result = pg_strdup(PQgetvalue(res, 0, 0)); - } - else - { - /* may need to quote it */ - result = pg_strdup(fmtId(PQgetvalue(res, 0, 0))); - } + /* result of format_type is already quoted */ + result = pg_strdup(PQgetvalue(res, 0, 0)); PQclear(res); destroyPQExpBuffer(query); @@ -17739,76 +17310,6 @@ getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts) return result; } -/* - * myFormatType --- local implementation of format_type for use with 7.0. - */ -static char * -myFormatType(const char *typname, int32 typmod) -{ - char *result; - bool isarray = false; - PQExpBuffer buf = createPQExpBuffer(); - - /* Handle array types */ - if (typname[0] == '_') - { - isarray = true; - typname++; - } - - /* Show lengths on bpchar and varchar */ - if (strcmp(typname, "bpchar") == 0) - { - int len = (typmod - VARHDRSZ); - - appendPQExpBufferStr(buf, "character"); - if (len > 1) - appendPQExpBuffer(buf, "(%d)", - typmod - VARHDRSZ); - } - else if (strcmp(typname, "varchar") == 0) - { - appendPQExpBufferStr(buf, "character varying"); - if (typmod != -1) - appendPQExpBuffer(buf, "(%d)", - typmod - VARHDRSZ); - } - else if (strcmp(typname, "numeric") == 0) - { - appendPQExpBufferStr(buf, "numeric"); - if (typmod != -1) - { - int32 tmp_typmod; - int precision; - int scale; - - tmp_typmod = typmod - VARHDRSZ; - precision = (tmp_typmod >> 16) & 0xffff; - scale = tmp_typmod & 0xffff; - appendPQExpBuffer(buf, "(%d,%d)", - precision, scale); - } - } - - /* - * char is an internal single-byte data type; Let's make sure we force it - * through with quotes. - thomas 1998-12-13 - */ - else if (strcmp(typname, "char") == 0) - appendPQExpBufferStr(buf, "\"char\""); - else - appendPQExpBufferStr(buf, fmtId(typname)); - - /* Append array qualifier for array types */ - if (isarray) - appendPQExpBufferStr(buf, "[]"); - - result = pg_strdup(buf->data); - destroyPQExpBuffer(buf); - - return result; -} - /* * Return a column list clause for the given relation. * diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index 2bfa2d9742..77de22fcb8 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -3,7 +3,7 @@ * pg_dump.h * Common header file for the pg_dump utility * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/pg_dump/pg_dump.h @@ -63,6 +63,7 @@ typedef enum DO_PROCLANG, DO_CAST, DO_TABLE_DATA, + DO_SEQUENCE_SET, DO_DUMMY_TYPE, DO_TSPARSER, DO_TSDICT, @@ -78,7 +79,10 @@ typedef enum DO_POST_DATA_BOUNDARY, DO_EVENT_TRIGGER, DO_REFRESH_MATVIEW, - DO_POLICY + DO_POLICY, + DO_PUBLICATION, + DO_PUBLICATION_REL, + DO_SUBSCRIPTION } DumpableObjectType; /* component types of an object which can be selected for dumping */ @@ -286,6 +290,7 @@ typedef struct _tableInfo int relpages; /* table's size in pages (from pg_class) */ bool interesting; /* true if need to collect more data */ + bool dummy_view; /* view's real definition must be postponed */ bool postponed_def; /* matview must be postponed into post-data */ /* @@ -310,6 +315,7 @@ typedef struct _tableInfo bool *inhNotNull; /* true if NOT NULL is inherited */ struct _attrDefInfo **attrdefs; /* DEFAULT expressions */ struct _constraintInfo *checkexprs; /* CHECK constraints */ + char *partkeydef; /* partition key definition */ /* * Stuff computed only for dumpable tables. @@ -319,6 +325,8 @@ typedef struct _tableInfo struct _tableDataInfo *dataObj; /* TableDataInfo, if dumping its data */ int numTriggers; /* number of triggers for table */ struct _triggerInfo *triggers; /* array of TriggerInfo structs */ + struct _tableInfo *partitionOf; /* TableInfo for the partition parent */ + char *partitiondef; /* partition key definition */ } TableInfo; typedef struct _attrDefInfo @@ -363,8 +371,6 @@ typedef struct _ruleInfo char ev_enabled; bool separate; /* TRUE if must dump as separate item */ /* separate is always true for non-ON SELECT rules */ - char *reloptions; /* options specified by WITH (...) */ - /* reloptions is only set if we need to dump the options with the rule */ } RuleInfo; typedef struct _triggerInfo @@ -459,6 +465,15 @@ typedef struct _inhInfo Oid inhparent; /* OID of its parent */ } InhInfo; +/* PartInfo isn't a DumpableObject, just temporary state */ +typedef struct _partInfo +{ + Oid partrelid; /* OID of a partition */ + Oid partparent; /* OID of its parent */ + char *partdef; /* partition bound definition */ +} PartInfo; + + typedef struct _prsInfo { DumpableObject dobj; @@ -547,12 +562,50 @@ typedef struct _policyInfo DumpableObject dobj; TableInfo *poltable; char *polname; /* null indicates RLS is enabled on rel */ - char *polcmd; + char polcmd; + bool polpermissive; char *polroles; char *polqual; char *polwithcheck; } PolicyInfo; +/* + * The PublicationInfo struct is used to represent publications. + */ +typedef struct _PublicationInfo +{ + DumpableObject dobj; + char *rolname; + bool puballtables; + bool pubinsert; + bool pubupdate; + bool pubdelete; +} PublicationInfo; + +/* + * The PublicationRelInfo struct is used to represent publication table + * mapping. + */ +typedef struct _PublicationRelInfo +{ + DumpableObject dobj; + TableInfo *pubtable; + char *pubname; +} PublicationRelInfo; + +/* + * The SubscriptionInfo struct is used to represent subscription. + */ +typedef struct _SubscriptionInfo +{ + DumpableObject dobj; + char *rolname; + bool subenabled; + char *subconninfo; + char *subslotname; + char *subpublications; +} SubscriptionInfo; + /* * We build an array of these with an entry for each object that is an * extension member according to pg_depend. @@ -605,7 +658,6 @@ extern void parseOidArray(const char *str, Oid *array, int arraysize); extern void sortDumpableObjects(DumpableObject **objs, int numObjs, DumpId preBoundaryId, DumpId postBoundaryId); extern void sortDumpableObjectsByTypeName(DumpableObject **objs, int numObjs); -extern void sortDumpableObjectsByTypeOid(DumpableObject **objs, int numObjs); extern void sortDataAndIndexObjectsBySize(DumpableObject **objs, int numObjs); /* @@ -625,6 +677,7 @@ extern ConvInfo *getConversions(Archive *fout, int *numConversions); extern TableInfo *getTables(Archive *fout, int *numTables); extern void getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables); extern InhInfo *getInherits(Archive *fout, int *numInherits); +extern PartInfo *getPartitions(Archive *fout, int *numPartitions); extern void getIndexes(Archive *fout, TableInfo tblinfo[], int numTables); extern void getConstraints(Archive *fout, TableInfo tblinfo[], int numTables); extern RuleInfo *getRules(Archive *fout, int *numRules); @@ -649,5 +702,10 @@ extern void processExtensionTables(Archive *fout, ExtensionInfo extinfo[], int numExtensions); extern EventTriggerInfo *getEventTriggers(Archive *fout, int *numEventTriggers); extern void getPolicies(Archive *fout, TableInfo tblinfo[], int numTables); +extern void getTablePartitionKeyInfo(Archive *fout, TableInfo *tblinfo, int numTables); +extern void getPublications(Archive *fout); +extern void getPublicationTables(Archive *fout, TableInfo tblinfo[], + int numTables); +extern void getSubscriptions(Archive *fout); #endif /* PG_DUMP_H */ diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c index d87f08d356..ea643397ba 100644 --- a/src/bin/pg_dump/pg_dump_sort.c +++ b/src/bin/pg_dump/pg_dump_sort.c @@ -4,7 +4,7 @@ * Sort the items of a dump into a safe order for dumping * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -23,63 +23,7 @@ static const char *modulename = gettext_noop("sorter"); /* - * Sort priority for object types when dumping a pre-7.3 database. - * Objects are sorted by priority levels, and within an equal priority level - * by OID. (This is a relatively crude hack to provide semi-reasonable - * behavior for old databases without full dependency info.) Note: collations, - * extensions, text search, foreign-data, materialized view, event trigger, - * policies, transforms, access methods and default ACL objects can't really - * happen here, so the rather bogus priorities for them don't matter. - * - * NOTE: object-type priorities must match the section assignments made in - * pg_dump.c; that is, PRE_DATA objects must sort before DO_PRE_DATA_BOUNDARY, - * POST_DATA objects must sort after DO_POST_DATA_BOUNDARY, and DATA objects - * must sort between them. - */ -static const int oldObjectTypePriority[] = -{ - 1, /* DO_NAMESPACE */ - 1, /* DO_EXTENSION */ - 2, /* DO_TYPE */ - 2, /* DO_SHELL_TYPE */ - 2, /* DO_FUNC */ - 3, /* DO_AGG */ - 3, /* DO_OPERATOR */ - 3, /* DO_ACCESS_METHOD */ - 4, /* DO_OPCLASS */ - 4, /* DO_OPFAMILY */ - 4, /* DO_COLLATION */ - 5, /* DO_CONVERSION */ - 6, /* DO_TABLE */ - 8, /* DO_ATTRDEF */ - 15, /* DO_INDEX */ - 16, /* DO_RULE */ - 17, /* DO_TRIGGER */ - 14, /* DO_CONSTRAINT */ - 18, /* DO_FK_CONSTRAINT */ - 2, /* DO_PROCLANG */ - 2, /* DO_CAST */ - 11, /* DO_TABLE_DATA */ - 7, /* DO_DUMMY_TYPE */ - 4, /* DO_TSPARSER */ - 4, /* DO_TSDICT */ - 4, /* DO_TSTEMPLATE */ - 4, /* DO_TSCONFIG */ - 4, /* DO_FDW */ - 4, /* DO_FOREIGN_SERVER */ - 19, /* DO_DEFAULT_ACL */ - 4, /* DO_TRANSFORM */ - 9, /* DO_BLOB */ - 12, /* DO_BLOB_DATA */ - 10, /* DO_PRE_DATA_BOUNDARY */ - 13, /* DO_POST_DATA_BOUNDARY */ - 20, /* DO_EVENT_TRIGGER */ - 15, /* DO_REFRESH_MATVIEW */ - 21 /* DO_POLICY */ -}; - -/* - * Sort priority for object types when dumping newer databases. + * Sort priority for database object types. * Objects are sorted by type, and within a type by name. * * NOTE: object-type priorities must match the section assignments made in @@ -87,7 +31,7 @@ static const int oldObjectTypePriority[] = * POST_DATA objects must sort after DO_POST_DATA_BOUNDARY, and DATA objects * must sort between them. */ -static const int newObjectTypePriority[] = +static const int dbObjectTypePriority[] = { 1, /* DO_NAMESPACE */ 4, /* DO_EXTENSION */ @@ -103,14 +47,15 @@ static const int newObjectTypePriority[] = 11, /* DO_CONVERSION */ 18, /* DO_TABLE */ 20, /* DO_ATTRDEF */ - 27, /* DO_INDEX */ - 28, /* DO_RULE */ - 29, /* DO_TRIGGER */ - 26, /* DO_CONSTRAINT */ - 30, /* DO_FK_CONSTRAINT */ + 28, /* DO_INDEX */ + 29, /* DO_RULE */ + 30, /* DO_TRIGGER */ + 27, /* DO_CONSTRAINT */ + 31, /* DO_FK_CONSTRAINT */ 2, /* DO_PROCLANG */ 10, /* DO_CAST */ 23, /* DO_TABLE_DATA */ + 24, /* DO_SEQUENCE_SET */ 19, /* DO_DUMMY_TYPE */ 12, /* DO_TSPARSER */ 14, /* DO_TSDICT */ @@ -118,15 +63,18 @@ static const int newObjectTypePriority[] = 15, /* DO_TSCONFIG */ 16, /* DO_FDW */ 17, /* DO_FOREIGN_SERVER */ - 31, /* DO_DEFAULT_ACL */ + 32, /* DO_DEFAULT_ACL */ 3, /* DO_TRANSFORM */ 21, /* DO_BLOB */ - 24, /* DO_BLOB_DATA */ + 25, /* DO_BLOB_DATA */ 22, /* DO_PRE_DATA_BOUNDARY */ - 25, /* DO_POST_DATA_BOUNDARY */ - 32, /* DO_EVENT_TRIGGER */ - 33, /* DO_REFRESH_MATVIEW */ - 34 /* DO_POLICY */ + 26, /* DO_POST_DATA_BOUNDARY */ + 33, /* DO_EVENT_TRIGGER */ + 34, /* DO_REFRESH_MATVIEW */ + 35, /* DO_POLICY */ + 36, /* DO_PUBLICATION */ + 37, /* DO_PUBLICATION_REL */ + 38 /* DO_SUBSCRIPTION */ }; static DumpId preDataBoundId; @@ -134,7 +82,6 @@ static DumpId postDataBoundId; static int DOTypeNameCompare(const void *p1, const void *p2); -static int DOTypeOidCompare(const void *p1, const void *p2); static bool TopoSort(DumpableObject **objs, int numObjs, DumpableObject **ordering, @@ -266,8 +213,8 @@ DOTypeNameCompare(const void *p1, const void *p2) int cmpval; /* Sort by type */ - cmpval = newObjectTypePriority[obj1->objType] - - newObjectTypePriority[obj2->objType]; + cmpval = dbObjectTypePriority[obj1->objType] - + dbObjectTypePriority[obj2->objType]; if (cmpval != 0) return cmpval; @@ -345,37 +292,6 @@ DOTypeNameCompare(const void *p1, const void *p2) } -/* - * Sort the given objects into a type/OID-based ordering - * - * This is used with pre-7.3 source databases as a crude substitute for the - * lack of dependency information. - */ -void -sortDumpableObjectsByTypeOid(DumpableObject **objs, int numObjs) -{ - if (numObjs > 1) - qsort((void *) objs, numObjs, sizeof(DumpableObject *), - DOTypeOidCompare); -} - -static int -DOTypeOidCompare(const void *p1, const void *p2) -{ - DumpableObject *obj1 = *(DumpableObject *const *) p1; - DumpableObject *obj2 = *(DumpableObject *const *) p2; - int cmpval; - - cmpval = oldObjectTypePriority[obj1->objType] - - oldObjectTypePriority[obj2->objType]; - - if (cmpval != 0) - return cmpval; - - return oidcmp(obj1->catId.oid, obj2->catId.oid); -} - - /* * Sort the given objects into a safe dump order using dependency * information (to the extent we have it available). @@ -873,6 +789,7 @@ repairViewRuleLoop(DumpableObject *viewobj, { /* remove rule's dependency on view */ removeObjectDependency(ruleobj, viewobj->dumpId); + /* flags on the two objects are already set correctly for this case */ } /* @@ -892,27 +809,17 @@ repairViewRuleMultiLoop(DumpableObject *viewobj, { TableInfo *viewinfo = (TableInfo *) viewobj; RuleInfo *ruleinfo = (RuleInfo *) ruleobj; - int i; /* remove view's dependency on rule */ removeObjectDependency(viewobj, ruleobj->dumpId); - /* pretend view is a plain table and dump it that way */ - viewinfo->relkind = 'r'; /* RELKIND_RELATION */ + /* mark view to be printed with a dummy definition */ + viewinfo->dummy_view = true; /* mark rule as needing its own dump */ ruleinfo->separate = true; - /* move any reloptions from view to rule */ - if (viewinfo->reloptions) - { - ruleinfo->reloptions = viewinfo->reloptions; - viewinfo->reloptions = NULL; - } /* put back rule's dependency on view */ addObjectDependency(ruleobj, viewobj->dumpId); /* now that rule is separate, it must be post-data */ addObjectDependency(ruleobj, postDataBoundId); - /* also, any triggers on the view must be dumped after the rule */ - for (i = 0; i < viewinfo->numTriggers; i++) - addObjectDependency(&(viewinfo->triggers[i].dobj), ruleobj->dumpId); } /* @@ -1433,6 +1340,11 @@ describeDumpableObject(DumpableObject *obj, char *buf, int bufsize) "TABLE DATA %s (ID %d OID %u)", obj->name, obj->dumpId, obj->catId.oid); return; + case DO_SEQUENCE_SET: + snprintf(buf, bufsize, + "SEQUENCE SET %s (ID %d OID %u)", + obj->name, obj->dumpId, obj->catId.oid); + return; case DO_DUMMY_TYPE: snprintf(buf, bufsize, "DUMMY TYPE %s (ID %d OID %u)", @@ -1488,6 +1400,21 @@ describeDumpableObject(DumpableObject *obj, char *buf, int bufsize) "POLICY (ID %d OID %u)", obj->dumpId, obj->catId.oid); return; + case DO_PUBLICATION: + snprintf(buf, bufsize, + "PUBLICATION (ID %d OID %u)", + obj->dumpId, obj->catId.oid); + return; + case DO_PUBLICATION_REL: + snprintf(buf, bufsize, + "PUBLICATION TABLE (ID %d OID %u)", + obj->dumpId, obj->catId.oid); + return; + case DO_SUBSCRIPTION: + snprintf(buf, bufsize, + "SUBSCRIPTION (ID %d OID %u)", + obj->dumpId, obj->catId.oid); + return; case DO_PRE_DATA_BOUNDARY: snprintf(buf, bufsize, "PRE-DATA BOUNDARY (ID %d)", diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index 54a9f48200..6895d02bfc 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -2,7 +2,7 @@ * * pg_dumpall.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * pg_dumpall forces all pg_dump output to be text, since it also outputs @@ -480,10 +480,7 @@ main(int argc, char *argv[]) dropDBs(conn); if (!roles_only && !no_tablespaces) - { - if (server_version >= 80000) - dropTablespaces(conn); - } + dropTablespaces(conn); if (!tablespaces_only) dropRoles(conn); @@ -505,12 +502,9 @@ main(int argc, char *argv[]) dumpGroups(conn); } + /* Dump tablespaces */ if (!roles_only && !no_tablespaces) - { - /* Dump tablespaces */ - if (server_version >= 80000) - dumpTablespaces(conn); - } + dumpTablespaces(conn); /* Dump CREATE DATABASE commands */ if (binary_upgrade || (!globals_only && !roles_only && !tablespaces_only)) @@ -549,6 +543,7 @@ help(void) printf(_("\nGeneral options:\n")); printf(_(" -f, --file=FILENAME output file name\n")); + printf(_(" -v, --verbose verbose mode\n")); printf(_(" -V, --version output version information, then exit\n")); printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n")); printf(_(" -?, --help show this help, then exit\n")); @@ -886,9 +881,8 @@ dumpRoles(PGconn *conn) * We do it this way because config settings for roles could mention the * names of other roles. */ - if (server_version >= 70300) - for (i = 0; i < PQntuples(res); i++) - dumpUserConfig(conn, PQgetvalue(res, i, i_rolname)); + for (i = 0; i < PQntuples(res); i++) + dumpUserConfig(conn, PQgetvalue(res, i, i_rolname)); PQclear(res); @@ -1204,16 +1198,10 @@ dropDBs(PGconn *conn) PGresult *res; int i; - if (server_version >= 70100) - res = executeQuery(conn, - "SELECT datname " - "FROM pg_database d " - "WHERE datallowconn ORDER BY 1"); - else - res = executeQuery(conn, - "SELECT datname " - "FROM pg_database d " - "ORDER BY 1"); + res = executeQuery(conn, + "SELECT datname " + "FROM pg_database d " + "WHERE datallowconn ORDER BY 1"); if (PQntuples(res) > 0) fprintf(OPF, "--\n-- Drop databases\n--\n\n"); @@ -1269,12 +1257,10 @@ dumpCreateDB(PGconn *conn) * We will dump encoding and locale specifications in the CREATE DATABASE * commands for just those databases with values different from defaults. * - * We consider template0's encoding and locale (or, pre-7.1, template1's) - * to define the installation default. Pre-8.4 installations do not have - * per-database locale settings; for them, every database must necessarily - * be using the installation default, so there's no need to do anything - * (which is good, since in very old versions there is no good way to find - * out what the installation locale is anyway...) + * We consider template0's encoding and locale to define the installation + * default. Pre-8.4 installations do not have per-database locale + * settings; for them, every database must necessarily be using the + * installation default, so there's no need to do anything. */ if (server_version >= 80400) res = executeQuery(conn, @@ -1282,18 +1268,12 @@ dumpCreateDB(PGconn *conn) "datcollate, datctype " "FROM pg_database " "WHERE datname = 'template0'"); - else if (server_version >= 70100) - res = executeQuery(conn, - "SELECT pg_encoding_to_char(encoding), " - "null::text AS datcollate, null::text AS datctype " - "FROM pg_database " - "WHERE datname = 'template0'"); else res = executeQuery(conn, "SELECT pg_encoding_to_char(encoding), " "null::text AS datcollate, null::text AS datctype " "FROM pg_database " - "WHERE datname = 'template1'"); + "WHERE datname = 'template0'"); /* If for some reason the template DB isn't there, treat as unknown */ if (PQntuples(res) > 0) @@ -1328,11 +1308,13 @@ dumpCreateDB(PGconn *conn) "pg_encoding_to_char(d.encoding), " "datcollate, datctype, datfrozenxid, datminmxid, " "datistemplate, " - "(SELECT pg_catalog.array_agg(acl) FROM (SELECT pg_catalog.unnest(coalesce(datacl,pg_catalog.acldefault('d',datdba))) AS acl " - "EXCEPT SELECT pg_catalog.unnest(pg_catalog.acldefault('d',datdba))) as foo)" + "(SELECT pg_catalog.array_agg(acl ORDER BY acl::text COLLATE \"C\") FROM ( " + " SELECT pg_catalog.unnest(coalesce(datacl,pg_catalog.acldefault('d',datdba))) AS acl " + " EXCEPT SELECT pg_catalog.unnest(pg_catalog.acldefault('d',datdba))) as datacls)" "AS datacl, " - "(SELECT pg_catalog.array_agg(acl) FROM (SELECT pg_catalog.unnest(pg_catalog.acldefault('d',datdba)) AS acl " - "EXCEPT SELECT pg_catalog.unnest(coalesce(datacl,pg_catalog.acldefault('d',datdba)))) as foo)" + "(SELECT pg_catalog.array_agg(acl ORDER BY acl::text COLLATE \"C\") FROM ( " + " SELECT pg_catalog.unnest(pg_catalog.acldefault('d',datdba)) AS acl " + " EXCEPT SELECT pg_catalog.unnest(coalesce(datacl,pg_catalog.acldefault('d',datdba)))) as rdatacls)" "AS rdatacl, " "datconnlimit, " "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace " @@ -1371,7 +1353,7 @@ dumpCreateDB(PGconn *conn) "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace " "FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) " "WHERE datallowconn ORDER BY 1"); - else if (server_version >= 80000) + else res = executeQuery(conn, "SELECT datname, " "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " @@ -1382,47 +1364,6 @@ dumpCreateDB(PGconn *conn) "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace " "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) " "WHERE datallowconn ORDER BY 1"); - else if (server_version >= 70300) - res = executeQuery(conn, - "SELECT datname, " - "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " - "pg_encoding_to_char(d.encoding), " - "null::text AS datcollate, null::text AS datctype, datfrozenxid, 0 AS datminmxid, " - "datistemplate, datacl, '' as rdatacl, " - "-1 as datconnlimit, " - "'pg_default' AS dattablespace " - "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) " - "WHERE datallowconn ORDER BY 1"); - else if (server_version >= 70100) - res = executeQuery(conn, - "SELECT datname, " - "coalesce(" - "(select usename from pg_shadow where usesysid=datdba), " - "(select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " - "pg_encoding_to_char(d.encoding), " - "null::text AS datcollate, null::text AS datctype, 0 AS datfrozenxid, 0 AS datminmxid, " - "datistemplate, '' as datacl, '' as rdatacl, " - "-1 as datconnlimit, " - "'pg_default' AS dattablespace " - "FROM pg_database d " - "WHERE datallowconn ORDER BY 1"); - else - { - /* - * Note: 7.0 fails to cope with sub-select in COALESCE, so just deal - * with getting a NULL by not printing any OWNER clause. - */ - res = executeQuery(conn, - "SELECT datname, " - "(select usename from pg_shadow where usesysid=datdba), " - "pg_encoding_to_char(d.encoding), " - "null::text AS datcollate, null::text AS datctype, 0 AS datfrozenxid, 0 AS datminmxid, " - "'f' as datistemplate, " - "'' as datacl, '' as rdatacl, -1 as datconnlimit, " - "'pg_default' AS dattablespace " - "FROM pg_database d " - "ORDER BY 1"); - } for (i = 0; i < PQntuples(res); i++) { @@ -1541,8 +1482,7 @@ dumpCreateDB(PGconn *conn) fprintf(OPF, "%s", buf->data); - if (server_version >= 70300) - dumpDatabaseConfig(conn, dbname); + dumpDatabaseConfig(conn, dbname); free(fdbname); } @@ -1738,10 +1678,7 @@ dumpDatabases(PGconn *conn) PGresult *res; int i; - if (server_version >= 70100) - res = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1"); - else - res = executeQuery(conn, "SELECT datname FROM pg_database ORDER BY 1"); + res = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1"); for (i = 0; i < PQntuples(res); i++) { @@ -1884,13 +1821,17 @@ connectDatabase(const char *dbname, const char *connection_string, bool new_pass; const char *remoteversion_str; int my_version; - static char *password = NULL; const char **keywords = NULL; const char **values = NULL; PQconninfoOption *conn_opts = NULL; + static bool have_password = false; + static char password[100]; - if (prompt_password == TRI_YES && !password) - password = simple_prompt("Password: ", 100, false); + if (prompt_password == TRI_YES && !have_password) + { + simple_prompt("Password: ", password, sizeof(password), false); + have_password = true; + } /* * Start the connection. Loop until we have a password if requested by @@ -1970,7 +1911,7 @@ connectDatabase(const char *dbname, const char *connection_string, values[i] = pguser; i++; } - if (password) + if (have_password) { keywords[i] = "password"; values[i] = password; @@ -1998,11 +1939,12 @@ connectDatabase(const char *dbname, const char *connection_string, if (PQstatus(conn) == CONNECTION_BAD && PQconnectionNeedsPassword(conn) && - password == NULL && + !have_password && prompt_password != TRI_NO) { PQfinish(conn); - password = simple_prompt("Password: ", 100, false); + simple_prompt("Password: ", password, sizeof(password), false); + have_password = true; new_pass = true; } } while (new_pass); @@ -2057,11 +1999,11 @@ connectDatabase(const char *dbname, const char *connection_string, my_version = PG_VERSION_NUM; /* - * We allow the server to be back to 7.0, and up to any minor release of + * We allow the server to be back to 8.0, and up to any minor release of * our own major version. (See also version check in pg_dump.c.) */ if (my_version != server_version - && (server_version < 70000 || + && (server_version < 80000 || (server_version / 100) > (my_version / 100))) { fprintf(stderr, _("server version: %s; %s version: %s\n"), @@ -2071,11 +2013,9 @@ connectDatabase(const char *dbname, const char *connection_string, } /* - * On 7.3 and later, make sure we are not fooled by non-system schemas in - * the search path. + * Make sure we are not fooled by non-system schemas in the search path. */ - if (server_version >= 70300) - executeCommand(conn, "SET search_path = pg_catalog"); + executeCommand(conn, "SET search_path = pg_catalog"); return conn; } diff --git a/src/bin/pg_dump/pg_restore.c b/src/bin/pg_dump/pg_restore.c index fb08e6bb8e..497677494b 100644 --- a/src/bin/pg_dump/pg_restore.c +++ b/src/bin/pg_dump/pg_restore.c @@ -72,6 +72,7 @@ main(int argc, char **argv) char *inputFileSpec; static int disable_triggers = 0; static int enable_row_security = 0; + static int include_subscriptions = 0; static int if_exists = 0; static int no_data_for_failed_tables = 0; static int outputNoTablespaces = 0; @@ -85,6 +86,7 @@ main(int argc, char **argv) {"data-only", 0, NULL, 'a'}, {"dbname", 1, NULL, 'd'}, {"exit-on-error", 0, NULL, 'e'}, + {"exclude-schema", 1, NULL, 'N'}, {"file", 1, NULL, 'f'}, {"format", 1, NULL, 'F'}, {"function", 1, NULL, 'P'}, @@ -115,6 +117,7 @@ main(int argc, char **argv) {"disable-triggers", no_argument, &disable_triggers, 1}, {"enable-row-security", no_argument, &enable_row_security, 1}, {"if-exists", no_argument, &if_exists, 1}, + {"include-subscriptions", no_argument, &include_subscriptions, 1}, {"no-data-for-failed-tables", no_argument, &no_data_for_failed_tables, 1}, {"no-tablespaces", no_argument, &outputNoTablespaces, 1}, {"role", required_argument, NULL, 2}, @@ -148,7 +151,7 @@ main(int argc, char **argv) } } - while ((c = getopt_long(argc, argv, "acCd:ef:F:h:I:j:lL:n:Op:P:RsS:t:T:U:vwWx1", + while ((c = getopt_long(argc, argv, "acCd:ef:F:h:I:j:lL:n:N:Op:P:RsS:t:T:U:vwWx1", cmdopts, NULL)) != -1) { switch (c) @@ -196,6 +199,10 @@ main(int argc, char **argv) simple_string_list_append(&opts->schemaNames, optarg); break; + case 'N': /* Do not dump data for this schema */ + simple_string_list_append(&opts->schemaExcludeNames, optarg); + break; + case 'O': opts->noOwner = 1; break; @@ -325,6 +332,22 @@ main(int argc, char **argv) exit_nicely(1); } + if (numWorkers <= 0) + { + fprintf(stderr, _("%s: invalid number of parallel jobs\n"), progname); + exit(1); + } + + /* See comments in pg_dump.c */ +#ifdef WIN32 + if (numWorkers > MAXIMUM_WAIT_OBJECTS) + { + fprintf(stderr, _("%s: maximum number of parallel jobs is %d\n"), + progname, MAXIMUM_WAIT_OBJECTS); + exit(1); + } +#endif + /* Can't do single-txn mode with multiple connections */ if (opts->single_txn && numWorkers > 1) { @@ -335,6 +358,7 @@ main(int argc, char **argv) opts->disable_triggers = disable_triggers; opts->enable_row_security = enable_row_security; + opts->include_subscriptions = include_subscriptions; opts->noDataForFailedTables = no_data_for_failed_tables; opts->noTablespace = outputNoTablespaces; opts->use_setsessauth = use_setsessauth; @@ -397,16 +421,6 @@ main(int argc, char **argv) if (opts->tocFile) SortTocFromFile(AH); - /* See comments in pg_dump.c */ -#ifdef WIN32 - if (numWorkers > MAXIMUM_WAIT_OBJECTS) - { - fprintf(stderr, _("%s: maximum number of parallel jobs is %d\n"), - progname, MAXIMUM_WAIT_OBJECTS); - exit(1); - } -#endif - AH->numWorkers = numWorkers; if (opts->tocSummary) @@ -456,6 +470,7 @@ usage(const char *progname) printf(_(" -L, --use-list=FILENAME use table of contents from this file for\n" " selecting/ordering output\n")); printf(_(" -n, --schema=NAME restore only objects in this schema\n")); + printf(_(" -N, --exclude-schema=NAME do not restore objects in this schema\n")); printf(_(" -O, --no-owner skip restoration of object ownership\n")); printf(_(" -P, --function=NAME(args) restore named function\n")); printf(_(" -s, --schema-only restore only the schema, no data\n")); diff --git a/src/bin/pg_dump/t/001_basic.pl b/src/bin/pg_dump/t/001_basic.pl index 6d545b29e2..e11f3dff2c 100644 --- a/src/bin/pg_dump/t/001_basic.pl +++ b/src/bin/pg_dump/t/001_basic.pl @@ -4,7 +4,7 @@ use Config; use PostgresNode; use TestLib; -use Test::More tests => 15; +use Test::More tests => 42; my $tempdir = TestLib::tempdir; my $tempdir_short = TestLib::tempdir_short; @@ -16,6 +16,14 @@ program_version_ok('pg_dump'); program_options_handling_ok('pg_dump'); +program_help_ok('pg_restore'); +program_version_ok('pg_restore'); +program_options_handling_ok('pg_restore'); + +program_help_ok('pg_dumpall'); +program_version_ok('pg_dumpall'); +program_options_handling_ok('pg_dumpall'); + ######################################### # Test various invalid options and disallowed combinations # Doesn't require a PG instance to be set up, so do this first. @@ -23,17 +31,40 @@ command_exit_is([ 'pg_dump', 'qqq', 'abc' ], 1, 'pg_dump: too many command-line arguments (first is "asd")'); +command_exit_is([ 'pg_restore', 'qqq', 'abc' ], + 1, 'pg_restore too many command-line arguments (first is "asd")'); + +command_exit_is([ 'pg_dumpall', 'qqq', 'abc' ], + 1, 'pg_dumpall: too many command-line arguments (first is "qqq")'); + command_exit_is( [ 'pg_dump', '-s', '-a' ], 1, 'pg_dump: options -s/--schema-only and -a/--data-only cannot be used together' ); +command_exit_is( + [ 'pg_restore', '-s', '-a' ], + 1, +'pg_restore: options -s/--schema-only and -a/--data-only cannot be used together' +); + +command_exit_is( + [ 'pg_restore', '-d', 'xxx', '-f', 'xxx' ], + 1, +'pg_restore: options -d/--dbname and -f/--file cannot be used together' +); + command_exit_is( [ 'pg_dump', '-c', '-a' ], 1, 'pg_dump: options -c/--clean and -a/--data-only cannot be used together'); +command_exit_is( + [ 'pg_restore', '-c', '-a' ], + 1, + 'pg_restore: options -c/--clean and -a/--data-only cannot be used together'); + command_exit_is( [ 'pg_dump', '--inserts', '-o' ], 1, @@ -48,3 +79,31 @@ command_exit_is([ 'pg_dump', '-j3' ], 1, 'pg_dump: parallel backup only supported by the directory format'); + +command_exit_is([ 'pg_restore', '--single-transaction', '-j3' ], + 1, 'pg_restore: cannot specify both --single-transaction and multiple jobs'); + +command_exit_is([ 'pg_restore', '--if-exists' ], + 1, 'pg_restore: option --if-exists requires option -c/--clean'); + +# pg_dumpall command-line argument checks +command_exit_is( + [ 'pg_dumpall', '-g', '-r' ], + 1, +'pg_restore: options -g/--globals-only and -r/--roles-only cannot be used together' +); + +command_exit_is( + [ 'pg_dumpall', '-g', '-t' ], + 1, +'pg_restore: options -g/--globals-only and -t/--tablespaces-only cannot be used together' +); + +command_exit_is( + [ 'pg_dumpall', '-r', '-t' ], + 1, +'pg_restore: options -r/--roles-only and -t/--tablespaces-only cannot be used together' +); + +command_exit_is([ 'pg_dumpall', '--if-exists' ], + 1, 'pg_dumpall: option --if-exists requires option -c/--clean'); diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index 37cbdcdaa5..488eec30f5 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -88,7 +88,7 @@ "$tempdir/defaults_custom_format.dump", 'postgres', ], restore_cmd => [ 'pg_restore', - '-f', + '-Fc', '-f', "$tempdir/defaults_custom_format.sql", "$tempdir/defaults_custom_format.dump", ], }, defaults_dir_format => { @@ -98,7 +98,7 @@ 'postgres', ], restore_cmd => [ 'pg_restore', - '-f', + '-Fd', '-f', "$tempdir/defaults_dir_format.sql", "$tempdir/defaults_dir_format", ], }, defaults_parallel => { @@ -117,7 +117,7 @@ 'postgres', ], restore_cmd => [ 'pg_restore', - '-f', + '-Ft', '-f', "$tempdir/defaults_tar_format.sql", "$tempdir/defaults_tar_format.tar", ], }, exclude_dump_test_schema => { @@ -136,7 +136,7 @@ '--exclude-table-data=dump_test.test_table', 'postgres', ], }, pg_dumpall_globals => { dump_cmd => - [ 'pg_dumpall', '-f', "$tempdir/pg_dumpall_globals.sql", '-g', ], }, + [ 'pg_dumpall', '-v', '-f', "$tempdir/pg_dumpall_globals.sql", '-g', ], }, pg_dumpall_globals_clean => { dump_cmd => [ 'pg_dumpall', '-f', "$tempdir/pg_dumpall_globals_clean.sql", @@ -144,6 +144,9 @@ pg_dumpall_dbprivs => { dump_cmd => [ 'pg_dumpall', '-f', "$tempdir/pg_dumpall_dbprivs.sql", ], }, + no_blobs => { + dump_cmd => + [ 'pg_dump', '-f', "$tempdir/no_blobs.sql", '-B', 'postgres', ], }, no_privs => { dump_cmd => [ 'pg_dump', '-f', "$tempdir/no_privs.sql", '-x', 'postgres', ], }, @@ -184,7 +187,7 @@ test_schema_plus_blobs => { dump_cmd => [ 'pg_dump', '-f', "$tempdir/test_schema_plus_blobs.sql", - '-n', 'dump_test', '-b', 'postgres', ], },); + '-n', 'dump_test', '-b', '-B', 'postgres', ], },); ############################################################### # Definition of the tests to run. @@ -225,6 +228,7 @@ my %tests = ( 'ALTER DEFAULT PRIVILEGES FOR ROLE regress_dump_test_role' => { + all_runs => 1, create_order => 14, create_sql => 'ALTER DEFAULT PRIVILEGES FOR ROLE regress_dump_test_role IN SCHEMA dump_test @@ -242,20 +246,27 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, + no_owner => 1, only_dump_test_schema => 1, pg_dumpall_dbprivs => 1, schema_only => 1, section_post_data => 1, test_schema_plus_blobs => 1, }, unlike => { + column_inserts => 1, + data_only => 1, exclude_dump_test_schema => 1, no_privs => 1, only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, section_pre_data => 1, section_data => 1, }, }, + 'ALTER ROLE regress_dump_test_role' => { + all_runs => 1, regexp => qr/^ \QALTER ROLE regress_dump_test_role WITH \E \QNOSUPERUSER INHERIT NOCREATEROLE NOCREATEDB NOLOGIN \E @@ -269,20 +280,28 @@ binary_upgrade => 1, clean => 1, clean_if_exists => 1, + column_inserts => 1, createdb => 1, + data_only => 1, defaults => 1, exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, only_dump_test_table => 1, + role => 1, schema_only => 1, section_pre_data => 1, + section_data => 1, section_post_data => 1, test_schema_plus_blobs => 1, }, }, + 'ALTER FUNCTION dump_test.pltestlang_call_handler() OWNER TO' => { + all_runs => 1, + catch_all => 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)', regexp => qr/^ \QALTER FUNCTION dump_test.pltestlang_call_handler() \E \QOWNER TO \E @@ -295,6 +314,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, only_dump_test_schema => 1, pg_dumpall_dbprivs => 1, @@ -303,8 +323,42 @@ test_schema_plus_blobs => 1, }, unlike => { exclude_dump_test_schema => 1, - only_dump_test_table => 1, }, }, + only_dump_test_table => 1, + role => 1, }, }, + + 'ALTER LARGE OBJECT ... OWNER TO' => { + all_runs => 1, + regexp => qr/^ALTER LARGE OBJECT \d+ OWNER TO .*;/m, + like => { + clean => 1, + clean_if_exists => 1, + column_inserts => 1, + createdb => 1, + data_only => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + pg_dumpall_dbprivs => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, }, + unlike => { + binary_upgrade => 1, + no_blobs => 1, + no_owner => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + pg_dumpall_globals_clean => 1, + role => 1, + schema_only => 1, + section_data => 1, + section_post_data => 1, }, }, + 'ALTER PROCEDURAL LANGUAGE pltestlang OWNER TO' => { + all_runs => 1, + catch_all => 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)', regexp => qr/^ALTER PROCEDURAL LANGUAGE pltestlang OWNER TO .*;/m, like => { binary_upgrade => 1, @@ -315,6 +369,7 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, pg_dumpall_dbprivs => 1, schema_only => 1, @@ -322,8 +377,12 @@ unlike => { only_dump_test_schema => 1, only_dump_test_table => 1, + role => 1, test_schema_plus_blobs => 1, }, }, + 'ALTER SCHEMA dump_test OWNER TO' => { + all_runs => 1, + catch_all => 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)', regexp => qr/^ALTER SCHEMA dump_test OWNER TO .*;/m, like => { binary_upgrade => 1, @@ -333,6 +392,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, only_dump_test_schema => 1, pg_dumpall_dbprivs => 1, @@ -341,8 +401,12 @@ test_schema_plus_blobs => 1, }, unlike => { exclude_dump_test_schema => 1, - only_dump_test_table => 1, }, }, + only_dump_test_table => 1, + role => 1, }, }, + 'ALTER SCHEMA dump_test_second_schema OWNER TO' => { + all_runs => 1, + catch_all => 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)', regexp => qr/^ALTER SCHEMA dump_test_second_schema OWNER TO .*;/m, like => { binary_upgrade => 1, @@ -353,15 +417,19 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, pg_dumpall_dbprivs => 1, + role => 1, schema_only => 1, section_pre_data => 1, }, unlike => { only_dump_test_schema => 1, only_dump_test_table => 1, test_schema_plus_blobs => 1, }, }, + 'ALTER SEQUENCE test_table_col1_seq' => { + all_runs => 1, regexp => qr/^ \QALTER SEQUENCE test_table_col1_seq OWNED BY test_table.col1;\E /xm, @@ -372,6 +440,7 @@ createdb => 1, defaults => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -381,12 +450,18 @@ section_pre_data => 1, test_schema_plus_blobs => 1, }, unlike => { + column_inserts => 1, + data_only => 1, exclude_test_table => 1, exclude_dump_test_schema => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, section_post_data => 1, }, }, + 'ALTER SEQUENCE test_third_table_col1_seq' => { + all_runs => 1, regexp => qr/^ \QALTER SEQUENCE test_third_table_col1_seq OWNED BY test_third_table.col1;\E /xm, @@ -399,19 +474,27 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, + role => 1, schema_only => 1, section_pre_data => 1, }, unlike => { + column_inserts => 1, + data_only => 1, only_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + section_data => 1, section_post_data => 1, test_schema_plus_blobs => 1, }, }, + 'ALTER TABLE ONLY test_table ADD CONSTRAINT ... PRIMARY KEY' => { + all_runs => 1, + catch_all => 'ALTER TABLE ... commands', regexp => qr/^ \QALTER TABLE ONLY test_table\E \n^\s+ \QADD CONSTRAINT test_table_pkey PRIMARY KEY (col1);\E @@ -423,7 +506,9 @@ createdb => 1, defaults => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, + no_owner => 1, only_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_dbprivs => 1, @@ -433,9 +518,13 @@ unlike => { exclude_dump_test_schema => 1, exclude_test_table => 1, + role => 1, section_pre_data => 1, section_data => 1, }, }, + 'ALTER TABLE test_table OWNER TO' => { + all_runs => 1, + catch_all => 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)', regexp => qr/^ALTER TABLE test_table OWNER TO .*;/m, like => { binary_upgrade => 1, @@ -444,6 +533,7 @@ createdb => 1, defaults => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, only_dump_test_schema => 1, only_dump_test_table => 1, @@ -453,8 +543,12 @@ test_schema_plus_blobs => 1, }, unlike => { exclude_dump_test_schema => 1, - exclude_test_table => 1, }, }, + exclude_test_table => 1, + role => 1, }, }, + 'ALTER TABLE test_table ENABLE ROW LEVEL SECURITY' => { + all_runs => 1, + catch_all => 'ALTER TABLE ... commands', create_order => 23, create_sql => 'ALTER TABLE dump_test.test_table ENABLE ROW LEVEL SECURITY;', @@ -466,7 +560,9 @@ createdb => 1, defaults => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, + no_owner => 1, only_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_dbprivs => 1, @@ -476,8 +572,12 @@ unlike => { section_pre_data => 1, exclude_dump_test_schema => 1, - exclude_test_table => 1, }, }, + exclude_test_table => 1, + role => 1, }, }, + 'ALTER TABLE test_second_table OWNER TO' => { + all_runs => 1, + catch_all => 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)', regexp => qr/^ALTER TABLE test_second_table OWNER TO .*;/m, like => { binary_upgrade => 1, @@ -487,6 +587,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, only_dump_test_schema => 1, pg_dumpall_dbprivs => 1, @@ -495,8 +596,12 @@ test_schema_plus_blobs => 1, }, unlike => { exclude_dump_test_schema => 1, - only_dump_test_table => 1, }, }, + only_dump_test_table => 1, + role => 1, }, }, + 'ALTER TABLE test_third_table OWNER TO' => { + all_runs => 1, + catch_all => 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)', regexp => qr/^ALTER TABLE test_third_table OWNER TO .*;/m, like => { binary_upgrade => 1, @@ -507,8 +612,10 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, pg_dumpall_dbprivs => 1, + role => 1, schema_only => 1, section_pre_data => 1, }, unlike => { @@ -516,18 +623,24 @@ only_dump_test_table => 1, test_schema_plus_blobs => 1, }, }, - # catch-all for ALTER ... OWNER (except LARGE OBJECTs) - 'ALTER ... OWNER commands (except LARGE OBJECTs)' => { - regexp => qr/^ALTER (?!LARGE OBJECT)(.*) OWNER TO .*;/m, + # catch-all for ALTER ... OWNER (except LARGE OBJECTs and PUBLICATIONs) + 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)' => { + all_runs => 0, # catch-all + regexp => qr/^ALTER (?!LARGE OBJECT|PUBLICATION)(.*) OWNER TO .*;/m, like => {}, # use more-specific options above unlike => { - column_inserts => 1, - data_only => 1, - section_data => 1, }, }, + column_inserts => 1, + data_only => 1, + no_owner => 1, + pg_dumpall_globals => 1, + pg_dumpall_globals_clean => 1, + section_data => 1, + section_post_data => 1, }, }, - # catch-all for ALTER TABLE ... + # catch-all for ALTER TABLE ... (except OWNER TO) 'ALTER TABLE ... commands' => { - regexp => qr/^ALTER TABLE .*;/m, + all_runs => 0, # catch-all + regexp => qr/^ALTER TABLE .* (?!OWNER TO)(.*);/m, like => {}, # use more-specific options above unlike => { column_inserts => 1, @@ -536,52 +649,81 @@ pg_dumpall_globals_clean => 1, section_data => 1, }, }, - # catch-all for ALTER ... OWNER - 'ALTER ... OWNER commands' => { - regexp => qr/^ALTER .* OWNER TO .*;/m, - like => {}, # use more-specific options above - unlike => { - no_owner => 1, - pg_dumpall_globals => 1, - pg_dumpall_globals_clean => 1, - section_post_data => 1, }, }, + 'BLOB create (using lo_from_bytea)' => { + all_runs => 1, + create_order => 50, + create_sql => 'SELECT pg_catalog.lo_from_bytea(0, \'\\x310a320a330a340a350a360a370a380a390a\');', + regexp => qr/^SELECT pg_catalog\.lo_create\('\d+'\);/m, + like => { + clean => 1, + clean_if_exists => 1, + column_inserts => 1, + createdb => 1, + data_only => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + pg_dumpall_dbprivs => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + binary_upgrade => 1, + no_blobs => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + pg_dumpall_globals_clean => 1, + role => 1, + schema_only => 1, + section_data => 1, + section_post_data => 1, + }, + }, + 'BLOB load (using lo_from_bytea)' => { + all_runs => 1, + regexp => qr/^ + \QSELECT pg_catalog.lo_open\E \('\d+',\ \d+\);\n + \QSELECT pg_catalog.lowrite(0, \E + \Q'\x310a320a330a340a350a360a370a380a390a');\E\n + \QSELECT pg_catalog.lo_close(0);\E + /xm, + like => { + clean => 1, + clean_if_exists => 1, + column_inserts => 1, + createdb => 1, + defaults => 1, + data_only => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_owner => 1, + no_privs => 1, + pg_dumpall_dbprivs => 1, + section_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + binary_upgrade => 1, + no_blobs => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + pg_dumpall_globals_clean => 1, + role => 1, + schema_only => 1, + section_pre_data => 1, + section_post_data => 1, + }, + }, - # 'BLOB load (contents are of test_table)' => { - # create_order => 14, - # create_sql => - # "\\o '$tempdir/large_object_test.sql'\n" - # . "table dump_test.test_table;\n" - # . "\\o\n" - # . "\\lo_import '$tempdir/large_object_test.sql'\n", - # regexp => qr/^ - # \QSELECT pg_catalog.lo_open\E \('\d+',\ \d+\);\n - # \QSELECT pg_catalog.lowrite(0, \E - # \Q'\x310a320a330a340a350a360a370a380a390a');\E\n - # \QSELECT pg_catalog.lo_close(0);\E - # /xm, - # like => { - # clean => 1, - # clean_if_exists => 1, - # createdb => 1, - # defaults => 1, - # exclude_dump_test_schema => 1, - # exclude_test_table => 1, - # exclude_test_table_data => 1, - # no_privs => 1, - # pg_dumpall_dbprivs => 1, - # section_data => 1, - # test_schema_plus_blobs => 1, - # }, - # unlike => { - # binary_upgrade => 1, - # only_dump_test_schema => 1, - # only_dump_test_table => 1, - # pg_dumpall_globals => 1, - # schema_only => 1, - # section_post_data => 1, - # }, - # }, 'COMMENT ON DATABASE postgres' => { + all_runs => 1, + catch_all => 'COMMENT commands', regexp => qr/^COMMENT ON DATABASE postgres IS .*;/m, like => { binary_upgrade => 1, @@ -592,15 +734,20 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, schema_only => 1, section_pre_data => 1, }, unlike => { - only_dump_test_schema => 1, - only_dump_test_table => 1, }, }, + only_dump_test_schema => 1, + only_dump_test_table => 1, + role => 1, + test_schema_plus_blobs => 1, }, }, 'COMMENT ON EXTENSION plpgsql' => { + all_runs => 1, + catch_all => 'COMMENT commands', regexp => qr/^COMMENT ON EXTENSION plpgsql IS .*;/m, like => { clean => 1, @@ -610,16 +757,21 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, schema_only => 1, section_pre_data => 1, }, unlike => { - binary_upgrade => 1, - only_dump_test_schema => 1, - only_dump_test_table => 1, }, }, + binary_upgrade => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + role => 1, + test_schema_plus_blobs => 1, }, }, 'COMMENT ON TABLE dump_test.test_table' => { + all_runs => 1, + catch_all => 'COMMENT commands', create_order => 36, create_sql => 'COMMENT ON TABLE dump_test.test_table IS \'comment on table\';', @@ -631,17 +783,22 @@ createdb => 1, defaults => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_dbprivs => 1, schema_only => 1, - section_pre_data => 1, }, + section_pre_data => 1, + test_schema_plus_blobs => 1, }, unlike => { exclude_dump_test_schema => 1, - exclude_test_table => 1, }, }, + exclude_test_table => 1, + role => 1, }, }, 'COMMENT ON COLUMN dump_test.test_table.col1' => { + all_runs => 1, + catch_all => 'COMMENT commands', create_order => 36, create_sql => 'COMMENT ON COLUMN dump_test.test_table.col1 IS \'comment on column\';', @@ -655,17 +812,22 @@ createdb => 1, defaults => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_dbprivs => 1, schema_only => 1, - section_pre_data => 1, }, + section_pre_data => 1, + test_schema_plus_blobs => 1, }, unlike => { exclude_dump_test_schema => 1, - exclude_test_table => 1, }, }, + exclude_test_table => 1, + role => 1, }, }, 'COMMENT ON COLUMN dump_test.composite.f1' => { + all_runs => 1, + catch_all => 'COMMENT commands', create_order => 44, create_sql => 'COMMENT ON COLUMN dump_test.composite.f1 IS \'comment on column of type\';', @@ -680,18 +842,22 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, pg_dumpall_dbprivs => 1, schema_only => 1, - section_pre_data => 1, }, + section_pre_data => 1, + test_schema_plus_blobs => 1, }, unlike => { exclude_dump_test_schema => 1, - only_dump_test_table => 1, }, }, + only_dump_test_table => 1, + role => 1, }, }, # catch-all for COMMENTs 'COMMENT commands' => { + all_runs => 0, # catch-all regexp => qr/^COMMENT ON /m, like => {}, # use more-specific options above unlike => { @@ -701,7 +867,10 @@ pg_dumpall_globals_clean => 1, section_data => 1, section_post_data => 1, }, }, + 'COPY test_table' => { + all_runs => 1, + catch_all => 'COPY ... commands', create_order => 4, create_sql => 'INSERT INTO dump_test.test_table (col1) ' . 'SELECT generate_series FROM generate_series(1,9);', @@ -715,6 +884,7 @@ createdb => 1, data_only => 1, defaults => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -725,8 +895,12 @@ unlike => { exclude_dump_test_schema => 1, exclude_test_table => 1, - exclude_test_table_data => 1, }, }, + exclude_test_table_data => 1, + role => 1, }, }, + 'COPY fk_reference_test_table' => { + all_runs => 1, + catch_all => 'COPY ... commands', create_order => 22, create_sql => 'INSERT INTO dump_test.fk_reference_test_table (col1) ' . 'SELECT generate_series FROM generate_series(1,5);', @@ -742,6 +916,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -750,8 +925,15 @@ test_schema_plus_blobs => 1, }, unlike => { exclude_dump_test_schema => 1, - only_dump_test_table => 1, }, }, + only_dump_test_table => 1, + role => 1, }, }, + + # In a data-only dump, we do try to actually order according to FKs, + # so this check is just making sure that the referring table comes after + # the referred-to table. 'COPY fk_reference_test_table second' => { + all_runs => 0, # really only for data-only + catch_all => 'COPY ... commands', regexp => qr/^ \QCOPY test_table (col1) FROM stdin;\E \n(?:\d\n){9}\\\.\n.* @@ -759,11 +941,11 @@ \n(?:\d\n){5}\\\.\n /xms, like => { data_only => 1, }, - unlike => { - exclude_dump_test_schema => 1, - exclude_test_table => 1, - exclude_test_table_data => 1, }, }, + unlike => { }, }, + 'COPY test_second_table' => { + all_runs => 1, + catch_all => 'COPY ... commands', create_order => 7, create_sql => 'INSERT INTO dump_test.test_second_table (col1, col2) ' . 'SELECT generate_series, generate_series::text ' @@ -780,6 +962,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -788,8 +971,12 @@ test_schema_plus_blobs => 1, }, unlike => { exclude_dump_test_schema => 1, - only_dump_test_table => 1, }, }, + only_dump_test_table => 1, + role => 1, }, }, + 'COPY test_third_table' => { + all_runs => 1, + catch_all => 'COPY ... commands', create_order => 12, create_sql => 'INSERT INTO dump_test_second_schema.test_third_table (col1) ' @@ -807,62 +994,64 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, + role => 1, section_data => 1, }, unlike => { only_dump_test_schema => 1, only_dump_test_table => 1, test_schema_plus_blobs => 1, }, }, + + 'COPY ... commands' => { # catch-all for COPY + all_runs => 0, # catch-all + regexp => qr/^COPY /m, + like => {}, # use more-specific options above + unlike => { + binary_upgrade => 1, + column_inserts => 1, + pg_dumpall_globals => 1, + pg_dumpall_globals_clean => 1, + schema_only => 1, + section_pre_data => 1, + section_post_data => 1, }, }, + 'INSERT INTO test_table' => { + all_runs => 1, + catch_all => 'INSERT INTO ...', regexp => qr/^ (?:INSERT\ INTO\ test_table\ \(col1\)\ VALUES\ \(\d\);\n){9} /xm, like => { column_inserts => 1, }, - unlike => { - clean => 1, - clean_if_exists => 1, - createdb => 1, - data_only => 1, - defaults => 1, - exclude_dump_test_schema => 1, - exclude_test_table => 1, - exclude_test_table_data => 1, - no_privs => 1, - no_owner => 1, - pg_dumpall_dbprivs => 1, - section_data => 1, - only_dump_test_schema => 1, - only_dump_test_table => 1, - test_schema_plus_blobs => 1, }, }, + unlike => { }, }, + 'INSERT INTO test_second_table' => { + all_runs => 1, + catch_all => 'INSERT INTO ...', regexp => qr/^ (?:INSERT\ INTO\ test_second_table\ \(col1,\ col2\) \ VALUES\ \(\d,\ '\d'\);\n){9}/xm, like => { column_inserts => 1, }, - unlike => { - clean => 1, - clean_if_exists => 1, - createdb => 1, - data_only => 1, - defaults => 1, - exclude_dump_test_schema => 1, - exclude_test_table => 1, - exclude_test_table_data => 1, - no_privs => 1, - no_owner => 1, - pg_dumpall_dbprivs => 1, - section_data => 1, - only_dump_test_schema => 1, - only_dump_test_table => 1, - test_schema_plus_blobs => 1, }, }, + unlike => { }, }, + 'INSERT INTO test_third_table' => { + all_runs => 1, + catch_all => 'INSERT INTO ...', regexp => qr/^ (?:INSERT\ INTO\ test_third_table\ \(col1\) \ VALUES\ \(\d\);\n){9}/xm, like => { column_inserts => 1, }, + unlike => { }, }, + + # INSERT INTO catch-all + 'INSERT INTO ...' => { + all_runs => 0, # catch-all + regexp => qr/^INSERT INTO .* VALUES .*;/xm, + like => { }, # use more-specific options above unlike => { + binary_upgrade => 1, clean => 1, clean_if_exists => 1, createdb => 1, @@ -871,24 +1060,24 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, + pg_dumpall_globals => 1, + pg_dumpall_globals_clean => 1, section_data => 1, only_dump_test_schema => 1, only_dump_test_table => 1, - test_schema_plus_blobs => 1, }, }, - 'COPY ... commands' => { # catch-all for COPY - regexp => qr/^COPY /m, - like => {}, # use more-specific options above - unlike => { - binary_upgrade => 1, - column_inserts => 1, - pg_dumpall_globals => 1, - pg_dumpall_globals_clean => 1, + role => 1, schema_only => 1, - section_post_data => 1, }, }, + section_pre_data => 1, + section_data => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, }, }, + 'CREATE ROLE regress_dump_test_role' => { + all_runs => 1, create_order => 1, create_sql => 'CREATE ROLE regress_dump_test_role;', regexp => qr/^CREATE ROLE regress_dump_test_role;/m, @@ -900,20 +1089,54 @@ binary_upgrade => 1, clean => 1, clean_if_exists => 1, + column_inserts => 1, createdb => 1, + data_only => 1, defaults => 1, exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, only_dump_test_table => 1, + role => 1, schema_only => 1, section_pre_data => 1, + section_data => 1, section_post_data => 1, test_schema_plus_blobs => 1, }, }, + + 'CREATE CAST FOR timestamptz' => { + create_order => 51, + create_sql => 'CREATE CAST (timestamptz AS interval) WITH FUNCTION age(timestamptz) AS ASSIGNMENT;', + regexp => qr/CREATE CAST \(timestamp with time zone AS interval\) WITH FUNCTION pg_catalog\.age\(timestamp with time zone\) AS ASSIGNMENT;/m, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_blobs => 1, + no_privs => 1, + no_owner => 1, + pg_dumpall_dbprivs => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, }, }, + 'CREATE DATABASE postgres' => { + all_runs => 1, regexp => qr/^ \QCREATE DATABASE postgres WITH TEMPLATE = template0 \E .*;/xm, @@ -922,10 +1145,13 @@ binary_upgrade => 1, clean => 1, clean_if_exists => 1, + column_inserts => 1, + data_only => 1, defaults => 1, exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -933,11 +1159,15 @@ pg_dumpall_dbprivs => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, schema_only => 1, section_pre_data => 1, + section_data => 1, section_post_data => 1, test_schema_plus_blobs => 1, }, }, + 'CREATE DATABASE dump_test' => { + all_runs => 1, create_order => 47, create_sql => 'CREATE DATABASE dump_test;', regexp => qr/^ @@ -948,22 +1178,29 @@ binary_upgrade => 1, clean => 1, clean_if_exists => 1, + column_inserts => 1, createdb => 1, + data_only => 1, defaults => 1, exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, schema_only => 1, section_pre_data => 1, + section_data => 1, section_post_data => 1, test_schema_plus_blobs => 1, }, }, + 'CREATE EXTENSION ... plpgsql' => { + all_runs => 1, regexp => qr/^ \QCREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;\E /xm, @@ -975,6 +1212,7 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, @@ -982,13 +1220,19 @@ section_pre_data => 1, }, unlike => { binary_upgrade => 1, + column_inserts => 1, + data_only => 1, only_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, section_post_data => 1, test_schema_plus_blobs => 1, }, }, + 'CREATE AGGREGATE dump_test.newavg' => { + all_runs => 1, create_order => 25, create_sql => 'CREATE AGGREGATE dump_test.newavg ( sfunc = int4_avg_accum, @@ -1012,6 +1256,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1020,12 +1265,18 @@ section_pre_data => 1, test_schema_plus_blobs => 1, }, unlike => { + column_inserts => 1, + data_only => 1, exclude_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, section_post_data => 1, }, }, + 'CREATE DOMAIN dump_test.us_postal_code' => { + all_runs => 1, create_order => 29, create_sql => 'CREATE DOMAIN dump_test.us_postal_code AS TEXT CHECK(VALUE ~ \'^\d{5}$\' OR @@ -1046,6 +1297,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1054,12 +1306,18 @@ section_pre_data => 1, test_schema_plus_blobs => 1, }, unlike => { + column_inserts => 1, + data_only => 1, exclude_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, section_post_data => 1, }, }, + 'CREATE FUNCTION dump_test.pltestlang_call_handler' => { + all_runs => 1, create_order => 17, create_sql => 'CREATE FUNCTION dump_test.pltestlang_call_handler() RETURNS LANGUAGE_HANDLER AS \'$libdir/plpgsql\', @@ -1079,6 +1337,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1087,12 +1346,18 @@ section_pre_data => 1, test_schema_plus_blobs => 1, }, unlike => { + column_inserts => 1, + data_only => 1, exclude_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, section_post_data => 1, }, }, + 'CREATE FUNCTION dump_test.trigger_func' => { + all_runs => 1, create_order => 30, create_sql => 'CREATE FUNCTION dump_test.trigger_func() RETURNS trigger LANGUAGE plpgsql @@ -1111,6 +1376,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1119,12 +1385,18 @@ section_pre_data => 1, test_schema_plus_blobs => 1, }, unlike => { + column_inserts => 1, + data_only => 1, exclude_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, section_post_data => 1, }, }, + 'CREATE FUNCTION dump_test.event_trigger_func' => { + all_runs => 1, create_order => 32, create_sql => 'CREATE FUNCTION dump_test.event_trigger_func() RETURNS event_trigger LANGUAGE plpgsql @@ -1143,6 +1415,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1151,12 +1424,18 @@ section_pre_data => 1, test_schema_plus_blobs => 1, }, unlike => { + column_inserts => 1, + data_only => 1, exclude_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, section_post_data => 1, }, }, + 'CREATE EVENT TRIGGER test_event_trigger' => { + all_runs => 1, create_order => 33, create_sql => 'CREATE EVENT TRIGGER test_event_trigger ON ddl_command_start @@ -1175,19 +1454,26 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, schema_only => 1, section_post_data => 1, }, unlike => { - section_pre_data => 1, + column_inserts => 1, + data_only => 1, only_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, + section_pre_data => 1, test_schema_plus_blobs => 1, }, }, + 'CREATE TRIGGER test_trigger' => { + all_runs => 1, create_order => 31, create_sql => 'CREATE TRIGGER test_trigger BEFORE INSERT ON dump_test.test_table @@ -1205,6 +1491,7 @@ createdb => 1, defaults => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1214,12 +1501,18 @@ section_post_data => 1, test_schema_plus_blobs => 1, }, unlike => { - section_pre_data => 1, + column_inserts => 1, + data_only => 1, exclude_dump_test_schema => 1, exclude_test_table => 1, pg_dumpall_globals => 1, - pg_dumpall_globals_clean => 1, }, }, + pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, + section_pre_data => 1, }, }, + 'CREATE TYPE dump_test.planets AS ENUM' => { + all_runs => 1, create_order => 37, create_sql => 'CREATE TYPE dump_test.planets AS ENUM ( \'venus\', \'earth\', \'mars\' );', @@ -1236,6 +1529,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1244,12 +1538,19 @@ section_pre_data => 1, test_schema_plus_blobs => 1, }, unlike => { + binary_upgrade => 1, + column_inserts => 1, + data_only => 1, exclude_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, section_post_data => 1, }, }, + 'CREATE TYPE dump_test.planets AS ENUM pg_upgrade' => { + all_runs => 1, regexp => qr/^ \QCREATE TYPE planets AS ENUM (\E \n\);.*^ @@ -1263,10 +1564,13 @@ unlike => { clean => 1, clean_if_exists => 1, + column_inserts => 1, createdb => 1, + data_only => 1, defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1278,8 +1582,13 @@ only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, + section_pre_data => 1, section_post_data => 1, }, }, + 'CREATE TYPE dump_test.textrange AS RANGE' => { + all_runs => 1, create_order => 38, create_sql => 'CREATE TYPE dump_test.textrange AS RANGE (subtype=text, collation="C");', @@ -1289,12 +1598,14 @@ \n\s+\Qcollation = pg_catalog."C"\E \n\);/xm, like => { + binary_upgrade => 1, clean => 1, clean_if_exists => 1, createdb => 1, defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1303,22 +1614,30 @@ section_pre_data => 1, test_schema_plus_blobs => 1, }, unlike => { + column_inserts => 1, + data_only => 1, exclude_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, section_post_data => 1, }, }, + 'CREATE TYPE dump_test.int42' => { + all_runs => 1, create_order => 39, create_sql => 'CREATE TYPE dump_test.int42;', regexp => qr/^CREATE TYPE int42;/m, like => { + binary_upgrade => 1, clean => 1, clean_if_exists => 1, createdb => 1, defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1327,12 +1646,18 @@ section_pre_data => 1, test_schema_plus_blobs => 1, }, unlike => { + column_inserts => 1, + data_only => 1, exclude_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, section_post_data => 1, }, }, + 'CREATE FUNCTION dump_test.int42_in' => { + all_runs => 1, create_order => 40, create_sql => 'CREATE FUNCTION dump_test.int42_in(cstring) RETURNS dump_test.int42 AS \'int4in\' @@ -1350,6 +1675,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1358,12 +1684,18 @@ section_pre_data => 1, test_schema_plus_blobs => 1, }, unlike => { + column_inserts => 1, + data_only => 1, exclude_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, section_post_data => 1, }, }, + 'CREATE FUNCTION dump_test.int42_out' => { + all_runs => 1, create_order => 41, create_sql => 'CREATE FUNCTION dump_test.int42_out(dump_test.int42) RETURNS cstring AS \'int4out\' @@ -1381,6 +1713,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1389,12 +1722,18 @@ section_pre_data => 1, test_schema_plus_blobs => 1, }, unlike => { + column_inserts => 1, + data_only => 1, exclude_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, section_post_data => 1, }, }, + 'CREATE TYPE dump_test.int42 populated' => { + all_runs => 1, create_order => 42, create_sql => 'CREATE TYPE dump_test.int42 ( internallength = 4, @@ -1414,12 +1753,14 @@ \n\s+PASSEDBYVALUE\n\); /xm, like => { + binary_upgrade => 1, clean => 1, clean_if_exists => 1, createdb => 1, defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1428,12 +1769,18 @@ section_pre_data => 1, test_schema_plus_blobs => 1, }, unlike => { + column_inserts => 1, + data_only => 1, exclude_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, section_post_data => 1, }, }, + 'CREATE TYPE dump_test.composite' => { + all_runs => 1, create_order => 43, create_sql => 'CREATE TYPE dump_test.composite AS ( f1 int, @@ -1446,12 +1793,14 @@ \n\); /xm, like => { + binary_upgrade => 1, clean => 1, clean_if_exists => 1, createdb => 1, defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1460,12 +1809,18 @@ section_pre_data => 1, test_schema_plus_blobs => 1, }, unlike => { + column_inserts => 1, + data_only => 1, exclude_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, section_post_data => 1, }, }, + 'CREATE FOREIGN DATA WRAPPER dummy' => { + all_runs => 1, create_order => 35, create_sql => 'CREATE FOREIGN DATA WRAPPER dummy;', regexp => qr/CREATE FOREIGN DATA WRAPPER dummy;/m, @@ -1478,19 +1833,26 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, schema_only => 1, section_pre_data => 1, }, unlike => { + column_inserts => 1, + data_only => 1, only_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, section_post_data => 1, test_schema_plus_blobs => 1, }, }, + 'CREATE SERVER s1 FOREIGN DATA WRAPPER dummy' => { + all_runs => 1, create_order => 36, create_sql => 'CREATE SERVER s1 FOREIGN DATA WRAPPER dummy;', regexp => qr/CREATE SERVER s1 FOREIGN DATA WRAPPER dummy;/m, @@ -1503,50 +1865,54 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, schema_only => 1, section_pre_data => 1, }, unlike => { + column_inserts => 1, + data_only => 1, only_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, section_post_data => 1, test_schema_plus_blobs => 1, }, }, -####################################### - # Currently broken. -####################################### -# -# 'CREATE TRANSFORM FOR int' => { -# create_order => 34, -# create_sql => 'CREATE TRANSFORM FOR int LANGUAGE SQL (FROM SQL WITH FUNCTION varchar_transform(internal), TO SQL WITH FUNCTION int4recv(internal));', -# regexp => qr/CREATE TRANSFORM FOR int LANGUAGE SQL \(FROM SQL WITH FUNCTION varchar_transform\(internal\), TO SQL WITH FUNCTION int4recv\(internal\)\);/m, -# like => { -# binary_upgrade => 1, -# clean => 1, -# clean_if_exists => 1, -# createdb => 1, -# defaults => 1, -# exclude_dump_test_schema => 1, -# exclude_test_table => 1, -# exclude_test_table_data => 1, -# no_privs => 1, -# no_owner => 1, -# pg_dumpall_dbprivs => 1, -# schema_only => 1, -# section_post_data => 1, -# }, -# unlike => { -# section_pre_data => 1, -# only_dump_test_schema => 1, -# only_dump_test_table => 1, -# pg_dumpall_globals => 1, -# test_schema_plus_blobs => 1, -# }, -# }, + + 'CREATE TRANSFORM FOR int' => { + create_order => 34, + create_sql => 'CREATE TRANSFORM FOR int LANGUAGE SQL (FROM SQL WITH FUNCTION varchar_transform(internal), TO SQL WITH FUNCTION int4recv(internal));', + regexp => qr/CREATE TRANSFORM FOR integer LANGUAGE sql \(FROM SQL WITH FUNCTION pg_catalog\.varchar_transform\(internal\), TO SQL WITH FUNCTION pg_catalog\.int4recv\(internal\)\);/m, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_blobs => 1, + no_privs => 1, + no_owner => 1, + pg_dumpall_dbprivs => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, }, }, + 'CREATE LANGUAGE pltestlang' => { + all_runs => 1, + catch_all => 'CREATE ... commands', create_order => 18, create_sql => 'CREATE LANGUAGE pltestlang HANDLER dump_test.pltestlang_call_handler;', @@ -1562,6 +1928,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, @@ -1572,10 +1939,14 @@ only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, section_post_data => 1, only_dump_test_schema => 1, test_schema_plus_blobs => 1, }, }, + 'CREATE MATERIALIZED VIEW matview' => { + all_runs => 1, + catch_all => 'CREATE ... commands', create_order => 20, create_sql => 'CREATE MATERIALIZED VIEW dump_test.matview (col1) AS SELECT * FROM dump_test.test_table;', @@ -1593,6 +1964,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1605,8 +1977,12 @@ only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, section_post_data => 1, }, }, + 'CREATE MATERIALIZED VIEW matview_second' => { + all_runs => 1, + catch_all => 'CREATE ... commands', create_order => 21, create_sql => 'CREATE MATERIALIZED VIEW dump_test.matview_second (col1) AS @@ -1625,6 +2001,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1637,14 +2014,18 @@ only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, section_post_data => 1, }, }, + 'CREATE POLICY p1 ON test_table' => { + all_runs => 1, + catch_all => 'CREATE ... commands', create_order => 22, create_sql => 'CREATE POLICY p1 ON dump_test.test_table USING (true) WITH CHECK (true);', regexp => qr/^ - \QCREATE POLICY p1 ON test_table FOR ALL TO PUBLIC \E + \QCREATE POLICY p1 ON test_table \E \QUSING (true) WITH CHECK (true);\E /xm, like => { @@ -1654,6 +2035,7 @@ createdb => 1, defaults => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1663,12 +2045,16 @@ section_post_data => 1, test_schema_plus_blobs => 1, }, unlike => { - section_pre_data => 1, exclude_dump_test_schema => 1, exclude_test_table => 1, pg_dumpall_globals => 1, - pg_dumpall_globals_clean => 1, }, }, + pg_dumpall_globals_clean => 1, + role => 1, + section_pre_data => 1, }, }, + 'CREATE POLICY p2 ON test_table FOR SELECT' => { + all_runs => 1, + catch_all => 'CREATE ... commands', create_order => 24, create_sql => 'CREATE POLICY p2 ON dump_test.test_table FOR SELECT TO regress_dump_test_role USING (true);', @@ -1683,6 +2069,7 @@ createdb => 1, defaults => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1692,12 +2079,16 @@ section_post_data => 1, test_schema_plus_blobs => 1, }, unlike => { - section_pre_data => 1, exclude_dump_test_schema => 1, exclude_test_table => 1, pg_dumpall_globals => 1, - pg_dumpall_globals_clean => 1, }, }, + pg_dumpall_globals_clean => 1, + role => 1, + section_pre_data => 1, }, }, + 'CREATE POLICY p3 ON test_table FOR INSERT' => { + all_runs => 1, + catch_all => 'CREATE ... commands', create_order => 25, create_sql => 'CREATE POLICY p3 ON dump_test.test_table FOR INSERT TO regress_dump_test_role WITH CHECK (true);', @@ -1712,6 +2103,7 @@ createdb => 1, defaults => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1721,12 +2113,16 @@ section_post_data => 1, test_schema_plus_blobs => 1, }, unlike => { - section_pre_data => 1, exclude_dump_test_schema => 1, exclude_test_table => 1, pg_dumpall_globals => 1, - pg_dumpall_globals_clean => 1, }, }, + pg_dumpall_globals_clean => 1, + role => 1, + section_pre_data => 1, }, }, + 'CREATE POLICY p4 ON test_table FOR UPDATE' => { + all_runs => 1, + catch_all => 'CREATE ... commands', create_order => 26, create_sql => 'CREATE POLICY p4 ON dump_test.test_table FOR UPDATE TO regress_dump_test_role USING (true) WITH CHECK (true);', @@ -1741,6 +2137,7 @@ createdb => 1, defaults => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1750,12 +2147,16 @@ section_post_data => 1, test_schema_plus_blobs => 1, }, unlike => { - section_pre_data => 1, exclude_dump_test_schema => 1, exclude_test_table => 1, pg_dumpall_globals => 1, - pg_dumpall_globals_clean => 1, }, }, + pg_dumpall_globals_clean => 1, + role => 1, + section_pre_data => 1, }, }, + 'CREATE POLICY p5 ON test_table FOR DELETE' => { + all_runs => 1, + catch_all => 'CREATE ... commands', create_order => 27, create_sql => 'CREATE POLICY p5 ON dump_test.test_table FOR DELETE TO regress_dump_test_role USING (true);', @@ -1763,6 +2164,93 @@ \QCREATE POLICY p5 ON test_table FOR DELETE \E \QTO regress_dump_test_role USING (true);\E /xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table_data => 1, + no_blobs => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_dbprivs => 1, + schema_only => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, }, + unlike => { + exclude_dump_test_schema => 1, + exclude_test_table => 1, + pg_dumpall_globals => 1, + pg_dumpall_globals_clean => 1, + role => 1, + section_pre_data => 1, }, }, + 'CREATE POLICY p6 ON test_table AS RESTRICTIVE' => { + create_order => 27, + create_sql => 'CREATE POLICY p6 ON dump_test.test_table AS RESTRICTIVE + USING (false);', + regexp => qr/^ + \QCREATE POLICY p6 ON test_table AS RESTRICTIVE \E + \QUSING (false);\E + /xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_dbprivs => 1, + schema_only => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, }, + unlike => { + exclude_dump_test_schema => 1, + exclude_test_table => 1, + pg_dumpall_globals => 1, + pg_dumpall_globals_clean => 1, + role => 1, + section_pre_data => 1, }, }, + + 'CREATE PUBLICATION pub1' => { + create_order => 50, + create_sql => 'CREATE PUBLICATION pub1;', + regexp => qr/^ + \QCREATE PUBLICATION pub1 WITH (PUBLISH INSERT, PUBLISH UPDATE, PUBLISH DELETE);\E + /xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table_data => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_dbprivs => 1, + schema_only => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, }, + unlike => { + section_pre_data => 1, + pg_dumpall_globals => 1, + pg_dumpall_globals_clean => 1, }, }, + 'ALTER PUBLICATION pub1 ADD TABLE test_table' => { + create_order => 51, + create_sql => 'ALTER PUBLICATION pub1 ADD TABLE dump_test.test_table;', + regexp => qr/^ + \QALTER PUBLICATION pub1 ADD TABLE test_table;\E + /xm, like => { binary_upgrade => 1, clean => 1, @@ -1784,7 +2272,10 @@ exclude_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, }, }, + 'CREATE SCHEMA dump_test' => { + all_runs => 1, + catch_all => 'CREATE ... commands', create_order => 2, create_sql => 'CREATE SCHEMA dump_test;', regexp => qr/^CREATE SCHEMA dump_test;/m, @@ -1796,6 +2287,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1808,8 +2300,12 @@ only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, section_post_data => 1, }, }, + 'CREATE SCHEMA dump_test_second_schema' => { + all_runs => 1, + catch_all => 'CREATE ... commands', create_order => 9, create_sql => 'CREATE SCHEMA dump_test_second_schema;', regexp => qr/^CREATE SCHEMA dump_test_second_schema;/m, @@ -1822,9 +2318,11 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, + role => 1, schema_only => 1, section_pre_data => 1, }, unlike => { @@ -1834,7 +2332,10 @@ pg_dumpall_globals_clean => 1, section_post_data => 1, test_schema_plus_blobs => 1, }, }, + 'CREATE TABLE test_table' => { + all_runs => 1, + catch_all => 'CREATE ... commands', create_order => 3, create_sql => 'CREATE TABLE dump_test.test_table ( col1 serial primary key, @@ -1853,6 +2354,7 @@ createdb => 1, defaults => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1866,8 +2368,12 @@ exclude_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, section_post_data => 1, }, }, + 'CREATE TABLE fk_reference_test_table' => { + all_runs => 1, + catch_all => 'CREATE ... commands', create_order => 21, create_sql => 'CREATE TABLE dump_test.fk_reference_test_table ( col1 int primary key references dump_test.test_table @@ -1885,6 +2391,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1897,8 +2404,12 @@ only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, section_post_data => 1, }, }, + 'CREATE TABLE test_second_table' => { + all_runs => 1, + catch_all => 'CREATE ... commands', create_order => 6, create_sql => 'CREATE TABLE dump_test.test_second_table ( col1 int, @@ -1918,6 +2429,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1930,8 +2442,12 @@ only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, section_post_data => 1, }, }, + 'CREATE TABLE test_third_table' => { + all_runs => 1, + catch_all => 'CREATE ... commands', create_order => 11, create_sql => 'CREATE TABLE dump_test_second_schema.test_third_table ( col1 serial @@ -1950,9 +2466,11 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, + role => 1, schema_only => 1, section_pre_data => 1, }, unlike => { @@ -1962,7 +2480,10 @@ pg_dumpall_globals_clean => 1, section_post_data => 1, test_schema_plus_blobs => 1, }, }, + 'CREATE SEQUENCE test_table_col1_seq' => { + all_runs => 1, + catch_all => 'CREATE ... commands', regexp => qr/^ \QCREATE SEQUENCE test_table_col1_seq\E \n\s+\QSTART WITH 1\E @@ -1979,6 +2500,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -1991,8 +2513,12 @@ exclude_dump_test_schema => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + role => 1, section_post_data => 1, }, }, + 'CREATE SEQUENCE test_third_table_col1_seq' => { + all_runs => 1, + catch_all => 'CREATE ... commands', regexp => qr/^ \QCREATE SEQUENCE test_third_table_col1_seq\E \n\s+\QSTART WITH 1\E @@ -2010,9 +2536,11 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, + role => 1, schema_only => 1, section_pre_data => 1, }, unlike => { @@ -2022,7 +2550,10 @@ pg_dumpall_globals_clean => 1, section_post_data => 1, test_schema_plus_blobs => 1, }, }, + 'CREATE UNIQUE INDEX test_third_table_idx ON test_third_table' => { + all_runs => 1, + catch_all => 'CREATE ... commands', create_order => 13, create_sql => 'CREATE UNIQUE INDEX test_third_table_idx ON dump_test_second_schema.test_third_table (col1);', @@ -2039,9 +2570,11 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, + role => 1, schema_only => 1, section_post_data => 1, }, unlike => { @@ -2049,86 +2582,143 @@ only_dump_test_table => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, + section_pre_data => 1, test_schema_plus_blobs => 1, }, }, + 'CREATE ... commands' => { # catch-all for CREATE + all_runs => 0, # catch-all regexp => qr/^CREATE /m, like => {}, # use more-specific options above unlike => { column_inserts => 1, data_only => 1, section_data => 1, }, }, + 'DROP EXTENSION plpgsql' => { + all_runs => 1, + catch_all => 'DROP ... commands', regexp => qr/^DROP EXTENSION plpgsql;/m, like => { clean => 1, }, - unlike => { clean_if_exists => 1, }, }, + unlike => { + clean_if_exists => 1, + pg_dumpall_globals_clean => 1, }, }, + 'DROP FUNCTION dump_test.pltestlang_call_handler()' => { regexp => qr/^DROP FUNCTION dump_test\.pltestlang_call_handler\(\);/m, like => { clean => 1, }, - unlike => { clean_if_exists => 1, }, }, + unlike => { + clean_if_exists => 1, + pg_dumpall_globals_clean => 1, }, }, + 'DROP LANGUAGE pltestlang' => { regexp => qr/^DROP PROCEDURAL LANGUAGE pltestlang;/m, like => { clean => 1, }, - unlike => { clean_if_exists => 1, }, }, + unlike => { + clean_if_exists => 1, + pg_dumpall_globals_clean => 1, }, }, + 'DROP SCHEMA dump_test' => { regexp => qr/^DROP SCHEMA dump_test;/m, like => { clean => 1, }, - unlike => { clean_if_exists => 1, }, }, + unlike => { + clean_if_exists => 1, + pg_dumpall_globals_clean => 1, }, }, + 'DROP SCHEMA dump_test_second_schema' => { regexp => qr/^DROP SCHEMA dump_test_second_schema;/m, like => { clean => 1, }, - unlike => { clean_if_exists => 1, }, }, + unlike => { + clean_if_exists => 1, + pg_dumpall_globals_clean => 1, }, }, + 'DROP TABLE test_table' => { regexp => qr/^DROP TABLE dump_test\.test_table;/m, like => { clean => 1, }, - unlike => { clean_if_exists => 1, }, }, + unlike => { + clean_if_exists => 1, + pg_dumpall_globals_clean => 1, }, }, + 'DROP TABLE fk_reference_test_table' => { regexp => qr/^DROP TABLE dump_test\.fk_reference_test_table;/m, like => { clean => 1, }, - unlike => { clean_if_exists => 1, }, }, + unlike => { + clean_if_exists => 1, + pg_dumpall_globals_clean => 1, }, }, + 'DROP TABLE test_second_table' => { regexp => qr/^DROP TABLE dump_test\.test_second_table;/m, like => { clean => 1, }, - unlike => { clean_if_exists => 1, }, }, + unlike => { + clean_if_exists => 1, + pg_dumpall_globals_clean => 1, }, }, + 'DROP TABLE test_third_table' => { regexp => qr/^DROP TABLE dump_test_second_schema\.test_third_table;/m, like => { clean => 1, }, - unlike => { clean_if_exists => 1, }, }, + unlike => { + clean_if_exists => 1, + pg_dumpall_globals_clean => 1, }, }, + 'DROP EXTENSION IF EXISTS plpgsql' => { regexp => qr/^DROP EXTENSION IF EXISTS plpgsql;/m, like => { clean_if_exists => 1, }, - unlike => { clean => 1, }, }, + unlike => { + clean => 1, + pg_dumpall_globals_clean => 1, }, }, + 'DROP FUNCTION IF EXISTS dump_test.pltestlang_call_handler()' => { regexp => qr/^ \QDROP FUNCTION IF EXISTS dump_test.pltestlang_call_handler();\E /xm, like => { clean_if_exists => 1, }, - unlike => { clean => 1, }, }, + unlike => { + clean => 1, + pg_dumpall_globals_clean => 1, }, }, + 'DROP LANGUAGE IF EXISTS pltestlang' => { regexp => qr/^DROP PROCEDURAL LANGUAGE IF EXISTS pltestlang;/m, like => { clean_if_exists => 1, }, - unlike => { clean => 1, }, }, + unlike => { + clean => 1, + pg_dumpall_globals_clean => 1, }, }, + 'DROP SCHEMA IF EXISTS dump_test' => { regexp => qr/^DROP SCHEMA IF EXISTS dump_test;/m, like => { clean_if_exists => 1, }, - unlike => { clean => 1, }, }, + unlike => { + clean => 1, + pg_dumpall_globals_clean => 1, }, }, + 'DROP SCHEMA IF EXISTS dump_test_second_schema' => { regexp => qr/^DROP SCHEMA IF EXISTS dump_test_second_schema;/m, like => { clean_if_exists => 1, }, - unlike => { clean => 1, }, }, + unlike => { + clean => 1, + pg_dumpall_globals_clean => 1, }, }, + 'DROP TABLE IF EXISTS test_table' => { regexp => qr/^DROP TABLE IF EXISTS dump_test\.test_table;/m, like => { clean_if_exists => 1, }, - unlike => { clean => 1, }, }, + unlike => { + clean => 1, + pg_dumpall_globals_clean => 1, }, }, + 'DROP TABLE IF EXISTS test_second_table' => { regexp => qr/^DROP TABLE IF EXISTS dump_test\.test_second_table;/m, like => { clean_if_exists => 1, }, - unlike => { clean => 1, }, }, + unlike => { + clean => 1, + pg_dumpall_globals_clean => 1, }, }, + 'DROP TABLE IF EXISTS test_third_table' => { regexp => qr/^ \QDROP TABLE IF EXISTS dump_test_second_schema.test_third_table;\E /xm, like => { clean_if_exists => 1, }, - unlike => { clean => 1, }, }, + unlike => { + clean => 1, + pg_dumpall_globals_clean => 1, }, }, + 'DROP ROLE regress_dump_test_role' => { regexp => qr/^ \QDROP ROLE regress_dump_test_role;\E @@ -2137,16 +2727,19 @@ unlike => { clean => 1, clean_if_exists => 1, }, }, + 'DROP ROLE pg_' => { regexp => qr/^ \QDROP ROLE pg_\E.*; /xm, - like => {}, + like => { }, unlike => { clean => 1, clean_if_exists => 1, pg_dumpall_globals_clean => 1, }, }, + 'DROP ... commands' => { # catch-all for DROP + all_runs => 0, # catch-all regexp => qr/^DROP /m, like => {}, # use more-specific options above unlike => { @@ -2158,14 +2751,23 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_dbprivs => 1, pg_dumpall_globals => 1, - schema_only => 1, }, }, + role => 1, + schema_only => 1, + section_data => 1, + section_pre_data => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, }, }, + 'GRANT USAGE ON SCHEMA dump_test_second_schema' => { + all_runs => 1, + catch_all => 'GRANT commands', create_order => 10, create_sql => 'GRANT USAGE ON SCHEMA dump_test_second_schema TO regress_dump_test_role;', @@ -2181,8 +2783,10 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, + role => 1, schema_only => 1, section_pre_data => 1, }, unlike => { @@ -2190,7 +2794,10 @@ only_dump_test_table => 1, pg_dumpall_globals => 1, test_schema_plus_blobs => 1, }, }, + 'GRANT CREATE ON DATABASE dump_test' => { + all_runs => 1, + catch_all => 'GRANT commands', create_order => 48, create_sql => 'GRANT CREATE ON DATABASE dump_test TO regress_dump_test_role;', @@ -2207,14 +2814,19 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_owner => 1, only_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_globals => 1, + role => 1, schema_only => 1, section_pre_data => 1, test_schema_plus_blobs => 1, }, }, + 'GRANT SELECT ON TABLE test_table' => { + all_runs => 1, + catch_all => 'GRANT commands', create_order => 5, create_sql => 'GRANT SELECT ON TABLE dump_test.test_table TO regress_dump_test_role;', @@ -2227,6 +2839,7 @@ createdb => 1, defaults => 1, exclude_test_table_data => 1, + no_blobs => 1, no_owner => 1, only_dump_test_schema => 1, only_dump_test_table => 1, @@ -2237,8 +2850,12 @@ unlike => { exclude_dump_test_schema => 1, exclude_test_table => 1, - pg_dumpall_globals => 1, }, }, + pg_dumpall_globals => 1, + role => 1, }, }, + 'GRANT SELECT ON TABLE test_third_table' => { + all_runs => 1, + catch_all => 'GRANT commands', create_order => 19, create_sql => 'GRANT SELECT ON TABLE dump_test_second_schema.test_third_table @@ -2254,8 +2871,10 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, + role => 1, schema_only => 1, section_pre_data => 1, }, unlike => { @@ -2263,7 +2882,10 @@ only_dump_test_table => 1, pg_dumpall_globals => 1, test_schema_plus_blobs => 1, }, }, + 'GRANT ALL ON SEQUENCE test_third_table_col1_seq' => { + all_runs => 1, + catch_all => 'GRANT commands', create_order => 28, create_sql => 'GRANT ALL ON SEQUENCE dump_test_second_schema.test_third_table_col1_seq @@ -2280,8 +2902,10 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, + role => 1, schema_only => 1, section_pre_data => 1, }, unlike => { @@ -2289,7 +2913,10 @@ only_dump_test_table => 1, pg_dumpall_globals => 1, test_schema_plus_blobs => 1, }, }, + 'GRANT INSERT(col1) ON TABLE test_second_table' => { + all_runs => 1, + catch_all => 'GRANT commands', create_order => 8, create_sql => 'GRANT INSERT (col1) ON TABLE dump_test.test_second_table @@ -2305,6 +2932,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_owner => 1, only_dump_test_schema => 1, pg_dumpall_dbprivs => 1, @@ -2314,8 +2942,12 @@ unlike => { exclude_dump_test_schema => 1, only_dump_test_table => 1, - pg_dumpall_globals => 1, }, }, + pg_dumpall_globals => 1, + role => 1, }, }, + 'GRANT EXECUTE ON FUNCTION pg_sleep() TO regress_dump_test_role' => { + all_runs => 1, + catch_all => 'GRANT commands', create_order => 16, create_sql => 'GRANT EXECUTE ON FUNCTION pg_sleep(float8) TO regress_dump_test_role;', @@ -2331,6 +2963,7 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, schema_only => 1, @@ -2338,8 +2971,13 @@ unlike => { only_dump_test_schema => 1, only_dump_test_table => 1, + pg_dumpall_globals => 1, + role => 1, test_schema_plus_blobs => 1, }, }, + 'GRANT SELECT (proname ...) ON TABLE pg_proc TO public' => { + all_runs => 1, + catch_all => 'GRANT commands', create_order => 46, create_sql => 'GRANT SELECT ( tableoid, @@ -2415,6 +3053,7 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, schema_only => 1, @@ -2422,16 +3061,24 @@ unlike => { only_dump_test_schema => 1, only_dump_test_table => 1, + pg_dumpall_globals => 1, + role => 1, test_schema_plus_blobs => 1, }, }, + 'GRANT commands' => { # catch-all for GRANT commands + all_runs => 0, # catch-all regexp => qr/^GRANT /m, - like => {}, # use more-specific options above + like => { }, # use more-specific options above unlike => { - column_inserts => 1, - data_only => 1, - no_privs => 1, - section_data => 1, }, }, + column_inserts => 1, + data_only => 1, + no_privs => 1, + pg_dumpall_globals_clean => 1, + section_data => 1, + section_post_data => 1, }, }, + 'REFRESH MATERIALIZED VIEW matview' => { + all_runs => 1, regexp => qr/^REFRESH MATERIALIZED VIEW matview;/m, like => { clean => 1, @@ -2440,6 +3087,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -2448,12 +3096,19 @@ section_post_data => 1, }, unlike => { binary_upgrade => 1, + column_inserts => 1, + data_only => 1, exclude_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_globals => 1, + pg_dumpall_globals_clean => 1, + role => 1, schema_only => 1, + section_data => 1, section_pre_data => 1, }, }, + 'REFRESH MATERIALIZED VIEW matview_second' => { + all_runs => 1, regexp => qr/^ \QREFRESH MATERIALIZED VIEW matview;\E \n.* @@ -2466,6 +3121,7 @@ defaults => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_privs => 1, no_owner => 1, only_dump_test_schema => 1, @@ -2474,17 +3130,26 @@ section_post_data => 1, }, unlike => { binary_upgrade => 1, + column_inserts => 1, + data_only => 1, exclude_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_globals => 1, + pg_dumpall_globals_clean => 1, + role => 1, schema_only => 1, + section_data => 1, section_pre_data => 1, }, }, + 'REVOKE CONNECT ON DATABASE dump_test FROM public' => { + all_runs => 1, + catch_all => 'REVOKE commands', create_order => 49, create_sql => 'REVOKE CONNECT ON DATABASE dump_test FROM public;', regexp => qr/^ \QREVOKE CONNECT,TEMPORARY ON DATABASE dump_test FROM PUBLIC;\E\n - \QGRANT TEMPORARY ON DATABASE dump_test TO PUBLIC;\E + \QGRANT TEMPORARY ON DATABASE dump_test TO PUBLIC;\E\n + \QGRANT CREATE ON DATABASE dump_test TO regress_dump_test_role;\E /xm, like => { pg_dumpall_dbprivs => 1, }, unlike => { @@ -2496,13 +3161,22 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_owner => 1, only_dump_test_schema => 1, only_dump_test_table => 1, + pg_dumpall_globals => 1, + pg_dumpall_globals_clean => 1, + role => 1, schema_only => 1, + section_data => 1, section_pre_data => 1, + section_post_data => 1, test_schema_plus_blobs => 1, }, }, + 'REVOKE EXECUTE ON FUNCTION pg_sleep() FROM public' => { + all_runs => 1, + catch_all => 'REVOKE commands', create_order => 15, create_sql => 'REVOKE EXECUTE ON FUNCTION pg_sleep(float8) FROM public;', @@ -2518,14 +3192,20 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, schema_only => 1, section_pre_data => 1, }, unlike => { - only_dump_test_schema => 1, - only_dump_test_table => 1, - test_schema_plus_blobs => 1, }, }, + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, }, }, + 'REVOKE SELECT ON TABLE pg_proc FROM public' => { create_order => 45, create_sql => 'REVOKE SELECT ON TABLE pg_proc FROM public;', @@ -2539,14 +3219,20 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, schema_only => 1, section_pre_data => 1, }, unlike => { - only_dump_test_schema => 1, - only_dump_test_table => 1, - test_schema_plus_blobs => 1, }, }, + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, }, }, + 'REVOKE CREATE ON SCHEMA public FROM public' => { create_order => 16, create_sql => 'REVOKE CREATE ON SCHEMA public FROM public;', @@ -2563,14 +3249,20 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, schema_only => 1, section_pre_data => 1, }, unlike => { - only_dump_test_schema => 1, - only_dump_test_table => 1, - test_schema_plus_blobs => 1, }, }, + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, }, }, + 'REVOKE USAGE ON LANGUAGE plpgsql FROM public' => { create_order => 16, create_sql => 'REVOKE USAGE ON LANGUAGE plpgsql FROM public;', @@ -2584,15 +3276,22 @@ exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, + no_blobs => 1, no_owner => 1, pg_dumpall_dbprivs => 1, schema_only => 1, section_pre_data => 1, }, unlike => { - only_dump_test_schema => 1, - only_dump_test_table => 1, - test_schema_plus_blobs => 1, }, }, + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals_clean => 1, + role => 1, + section_data => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, }, }, + 'REVOKE commands' => { # catch-all for REVOKE commands + all_runs => 0, # catch-all regexp => qr/^REVOKE /m, like => {}, # use more-specific options above unlike => { @@ -2643,6 +3342,10 @@ { $num_tests++; } + if ($tests{$test}->{all_runs}) + { + $num_tests++; + } } } plan tests => $num_tests; @@ -2737,6 +3440,24 @@ $tests{$test}->{regexp}, "$run: does not dump $test"); } + # Complain if there isn't a like or unlike for this test, unless that is ok + if ($tests{$test}->{all_runs}) + { + if (!defined($tests{$test}->{catch_all})) + { + ok (defined($tests{$test}->{like}->{$test_key}) || defined($tests{$test}->{unlike}->{$test_key}), "$run defined for `$test'"); + } + else + { + my $catch_all = $tests{$test}->{catch_all}; + + ok (defined($tests{$test}->{like}->{$test_key}) || + defined($tests{$catch_all}->{like}->{$test_key}) || + defined($tests{$test}->{unlike}->{$test_key}) || + defined($tests{$catch_all}->{unlike}->{$test_key}), + "$run defined for `$test' or `$catch_all'"); + } + } } } diff --git a/src/bin/pg_dump/t/010_dump_connstr.pl b/src/bin/pg_dump/t/010_dump_connstr.pl new file mode 100644 index 0000000000..2d0d1e4298 --- /dev/null +++ b/src/bin/pg_dump/t/010_dump_connstr.pl @@ -0,0 +1,142 @@ +use strict; +use warnings; + +use PostgresNode; +use TestLib; +use Test::More tests => 14; + +# In a SQL_ASCII database, pgwin32_message_to_UTF16() needs to +# interpret everything as UTF8. We're going to use byte sequences +# that aren't valid UTF-8 strings, so that would fail. Use LATIN1, +# which accepts any byte and has a conversion from each byte to UTF-8. +$ENV{LC_ALL} = 'C'; +$ENV{PGCLIENTENCODING} = 'LATIN1'; + +# Create database and user names covering the range of LATIN1 +# characters, for use in a connection string by pg_dumpall. Skip ',' +# because of pg_regress --create-role, skip [\n\r] because pg_dumpall +# does not allow them. +my $dbname1 = generate_ascii_string(1, 9) . + generate_ascii_string(11, 12) . + generate_ascii_string(14, 33) . + ($TestLib::windows_os ? '' : '"x"') . # IPC::Run mishandles '"' on Windows + generate_ascii_string(35, 43) . + generate_ascii_string(45, 63); # contains '=' +my $dbname2 = generate_ascii_string(67, 129); # skip 64-66 to keep length to 62 +my $dbname3 = generate_ascii_string(130, 192); +my $dbname4 = generate_ascii_string(193, 255); + +my $node = get_new_node('main'); +$node->init(extra => ['--locale=C', '--encoding=LATIN1']); +# prep pg_hba.conf and pg_ident.conf +$node->run_log([$ENV{PG_REGRESS}, '--config-auth', $node->data_dir, + '--create-role', "$dbname1,$dbname2,$dbname3,$dbname4"]); +$node->start; + +my $backupdir = $node->backup_dir; +my $discard = "$backupdir/discard.sql"; +my $plain = "$backupdir/plain.sql"; +my $dirfmt = "$backupdir/dirfmt"; + +foreach my $dbname ($dbname1, $dbname2, $dbname3, $dbname4, 'CamelCase') +{ + $node->run_log(['createdb', $dbname]); + $node->run_log(['createuser', '-s', $dbname]); +} + + +# For these tests, pg_dumpall -r is used because it produces a short +# dump. +$node->command_ok(['pg_dumpall', '-r', '-f', $discard, '--dbname', + $node->connstr($dbname1), '-U', $dbname4], + 'pg_dumpall with long ASCII name 1'); +$node->command_ok(['pg_dumpall', '-r', '-f', $discard, '--dbname', + $node->connstr($dbname2), '-U', $dbname3], + 'pg_dumpall with long ASCII name 2'); +$node->command_ok(['pg_dumpall', '-r', '-f', $discard, '--dbname', + $node->connstr($dbname3), '-U', $dbname2], + 'pg_dumpall with long ASCII name 3'); +$node->command_ok(['pg_dumpall', '-r', '-f', $discard, '--dbname', + $node->connstr($dbname4), '-U', $dbname1], + 'pg_dumpall with long ASCII name 4'); +$node->command_ok(['pg_dumpall', '-r', '-l', 'dbname=template1'], + 'pg_dumpall -l accepts connection string'); + +$node->run_log(['createdb', "foo\n\rbar"]); +# not sufficient to use -r here +$node->command_fails(['pg_dumpall', '-f', $discard], + 'pg_dumpall with \n\r in database name'); +$node->run_log(['dropdb', "foo\n\rbar"]); + + +# make a table, so the parallel worker has something to dump +$node->safe_psql($dbname1, 'CREATE TABLE t0()'); +# XXX no printed message when this fails, just SIGPIPE termination +$node->command_ok(['pg_dump', '-Fd', '-j2', '-f', $dirfmt, + '-U', $dbname1, $node->connstr($dbname1)], + 'parallel dump'); + +# recreate $dbname1 for restore test +$node->run_log(['dropdb', $dbname1]); +$node->run_log(['createdb', $dbname1]); + +$node->command_ok(['pg_restore', '-v', '-d', 'template1', '-j2', + '-U', $dbname1, $dirfmt], + 'parallel restore'); + +$node->run_log(['dropdb', $dbname1]); + +$node->command_ok(['pg_restore', '-C', '-v', '-d', 'template1', '-j2', + '-U', $dbname1, $dirfmt], + 'parallel restore with create'); + + +$node->command_ok(['pg_dumpall', '-f', $plain, '-U', $dbname1], + 'take full dump'); +system_log('cat', $plain); +my($stderr, $result); +my $bootstrap_super = 'boot'; +my $restore_super = qq{a'b\\c=d\\ne"f}; + + +# Restore full dump through psql using environment variables for +# dbname/user connection parameters + +my $envar_node = get_new_node('destination_envar'); +$envar_node->init(extra => ['-U', $bootstrap_super, + '--locale=C', '--encoding=LATIN1']); +$envar_node->run_log([$ENV{PG_REGRESS}, + '--config-auth', $envar_node->data_dir, + '--create-role', "$bootstrap_super,$restore_super"]); +$envar_node->start; + +# make superuser for restore +$envar_node->run_log(['createuser', '-U', $bootstrap_super, '-s', $restore_super]); + +{ + local $ENV{PGPORT} = $envar_node->port; + local $ENV{PGUSER} = $restore_super; + $result = run_log(['psql', '-X', '-f', $plain], '2>', \$stderr); +} +ok($result, 'restore full dump using environment variables for connection parameters'); +is($stderr, '', 'no dump errors'); + + +# Restore full dump through psql using command-line options for +# dbname/user connection parameters. "\connect dbname=" forgets +# user/port from command line. + +$restore_super =~ s/"//g if $TestLib::windows_os; # IPC::Run mishandles '"' on Windows +my $cmdline_node = get_new_node('destination_cmdline'); +$cmdline_node->init(extra => ['-U', $bootstrap_super, + '--locale=C', '--encoding=LATIN1']); +$cmdline_node->run_log([$ENV{PG_REGRESS}, + '--config-auth', $cmdline_node->data_dir, + '--create-role', "$bootstrap_super,$restore_super"]); +$cmdline_node->start; +$cmdline_node->run_log(['createuser', '-U', $bootstrap_super, '-s', $restore_super]); +{ + $result = run_log(['psql', '-p', $cmdline_node->port, '-U', $restore_super, '-X', '-f', $plain], '2>', \$stderr); +} +ok($result, 'restore full dump with command-line options for connection parameters'); +is($stderr, '', 'no dump errors'); diff --git a/src/bin/pg_resetxlog/Makefile b/src/bin/pg_resetxlog/Makefile index dfd23c1031..e04892479b 100644 --- a/src/bin/pg_resetxlog/Makefile +++ b/src/bin/pg_resetxlog/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/pg_resetxlog # -# Copyright (c) 1998-2016, PostgreSQL Global Development Group +# Copyright (c) 1998-2017, PostgreSQL Global Development Group # # src/bin/pg_resetxlog/Makefile # diff --git a/src/bin/pg_resetxlog/pg_resetxlog.c b/src/bin/pg_resetxlog/pg_resetxlog.c index 525b82ba7a..963802efc8 100644 --- a/src/bin/pg_resetxlog/pg_resetxlog.c +++ b/src/bin/pg_resetxlog/pg_resetxlog.c @@ -20,7 +20,7 @@ * step 2 ... * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/pg_resetxlog/pg_resetxlog.c @@ -890,7 +890,7 @@ FindEndOfXLOG(void) newXlogSegNo = ControlFile.checkPointCopy.redo / ControlFile.xlog_seg_size; /* - * Scan the pg_xlog directory to find existing WAL segment files. We + * Scan the pg_wal directory to find existing WAL segment files. We * assume any present have been used; in most scenarios this should be * conservative, because of xlog.c's attempts to pre-create files. */ diff --git a/src/bin/pg_rewind/Makefile b/src/bin/pg_rewind/Makefile index d03a0a2eae..828ae01ef1 100644 --- a/src/bin/pg_rewind/Makefile +++ b/src/bin/pg_rewind/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/pg_rewind # -# Portions Copyright (c) 2013-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 2013-2017, PostgreSQL Global Development Group # # src/bin/pg_rewind/Makefile # diff --git a/src/bin/pg_rewind/RewindTest.pm b/src/bin/pg_rewind/RewindTest.pm index 135d8f0449..1c482617ad 100644 --- a/src/bin/pg_rewind/RewindTest.pm +++ b/src/bin/pg_rewind/RewindTest.pm @@ -133,7 +133,7 @@ sub create_standby $node_standby = get_new_node('standby'); $node_master->backup('my_backup'); $node_standby->init_from_backup($node_master, 'my_backup'); - my $connstr_master = $node_master->connstr('postgres'); + my $connstr_master = $node_master->connstr(); $node_standby->append_conf( "recovery.conf", qq( @@ -161,12 +161,8 @@ sub promote_standby or die "Timed out while waiting for standby to receive and write WAL"; # Now promote slave and insert some new data on master, this will put - # the master out-of-sync with the standby. Wait until the standby is - # out of recovery mode, and is ready to accept read-write connections. + # the master out-of-sync with the standby. $node_standby->promote; - $node_standby->poll_query_until('postgres', - "SELECT NOT pg_is_in_recovery()") - or die "Timed out while waiting for promotion of standby"; # Force a checkpoint after the promotion. pg_rewind looks at the control # file to determine what timeline the server is on, and that isn't updated diff --git a/src/bin/pg_rewind/copy_fetch.c b/src/bin/pg_rewind/copy_fetch.c index 327e7ef541..1fc7f74e0d 100644 --- a/src/bin/pg_rewind/copy_fetch.c +++ b/src/bin/pg_rewind/copy_fetch.c @@ -3,7 +3,7 @@ * copy_fetch.c * Functions for using a data directory as the source. * - * Portions Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2013-2017, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ @@ -131,10 +131,10 @@ recurse_dir(const char *datadir, const char *parentpath, /* * If it's a symlink within pg_tblspc, we need to recurse into it, * to process all the tablespaces. We also follow a symlink if - * it's for pg_xlog. Symlinks elsewhere are ignored. + * it's for pg_wal. Symlinks elsewhere are ignored. */ if ((parentpath && strcmp(parentpath, "pg_tblspc") == 0) || - strcmp(path, "pg_xlog") == 0) + strcmp(path, "pg_wal") == 0) recurse_dir(datadir, path, callback); #else pg_fatal("\"%s\" is a symbolic link, but symbolic links are not supported on this platform\n", @@ -158,7 +158,7 @@ recurse_dir(const char *datadir, const char *parentpath, * If 'trunc' is true, any existing file with the same name is truncated. */ static void -copy_file_range(const char *path, off_t begin, off_t end, bool trunc) +rewind_copy_file_range(const char *path, off_t begin, off_t end, bool trunc) { char buf[BLCKSZ]; char srcpath[MAXPGPATH]; @@ -224,7 +224,7 @@ copy_executeFileMap(filemap_t *map) break; case FILE_ACTION_COPY: - copy_file_range(entry->path, 0, entry->newsize, true); + rewind_copy_file_range(entry->path, 0, entry->newsize, true); break; case FILE_ACTION_TRUNCATE: @@ -232,7 +232,8 @@ copy_executeFileMap(filemap_t *map) break; case FILE_ACTION_COPY_TAIL: - copy_file_range(entry->path, entry->oldsize, entry->newsize, false); + rewind_copy_file_range(entry->path, entry->oldsize, + entry->newsize, false); break; case FILE_ACTION_CREATE: @@ -259,7 +260,7 @@ execute_pagemap(datapagemap_t *pagemap, const char *path) while (datapagemap_next(iter, &blkno)) { offset = blkno * BLCKSZ; - copy_file_range(path, offset, offset + BLCKSZ, false); + rewind_copy_file_range(path, offset, offset + BLCKSZ, false); /* Ok, this block has now been copied from new data dir to old */ } pg_free(iter); diff --git a/src/bin/pg_rewind/datapagemap.c b/src/bin/pg_rewind/datapagemap.c index a79b427527..e53920d556 100644 --- a/src/bin/pg_rewind/datapagemap.c +++ b/src/bin/pg_rewind/datapagemap.c @@ -5,7 +5,7 @@ * * This is a fairly simple bitmap. * - * Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Copyright (c) 2013-2017, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/bin/pg_rewind/datapagemap.h b/src/bin/pg_rewind/datapagemap.h index b36a668fe7..15ebd68b27 100644 --- a/src/bin/pg_rewind/datapagemap.h +++ b/src/bin/pg_rewind/datapagemap.h @@ -2,7 +2,7 @@ * * datapagemap.h * - * Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Copyright (c) 2013-2017, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/bin/pg_rewind/fetch.c b/src/bin/pg_rewind/fetch.c index d881e7586b..08a296d7d4 100644 --- a/src/bin/pg_rewind/fetch.c +++ b/src/bin/pg_rewind/fetch.c @@ -10,7 +10,7 @@ * connection (libpq_fetch.c) * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/bin/pg_rewind/fetch.h b/src/bin/pg_rewind/fetch.h index c7c1e88adf..e56fd973cd 100644 --- a/src/bin/pg_rewind/fetch.h +++ b/src/bin/pg_rewind/fetch.h @@ -8,7 +8,7 @@ * directory (copy method), or a remote PostgreSQL server (libpq fetch * method). * - * Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Copyright (c) 2013-2017, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/bin/pg_rewind/file_ops.c b/src/bin/pg_rewind/file_ops.c index e88cf629b4..f8ca4c925d 100644 --- a/src/bin/pg_rewind/file_ops.c +++ b/src/bin/pg_rewind/file_ops.c @@ -8,7 +8,7 @@ * do nothing if it's enabled. You should avoid accessing the target files * directly but if you do, make sure you honor the --dry-run mode! * - * Portions Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2013-2017, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/bin/pg_rewind/file_ops.h b/src/bin/pg_rewind/file_ops.h index f7aede3bbb..d247f3dc65 100644 --- a/src/bin/pg_rewind/file_ops.h +++ b/src/bin/pg_rewind/file_ops.h @@ -3,7 +3,7 @@ * file_ops.h * Helper functions for operating on files * - * Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Copyright (c) 2013-2017, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c index 9b00dc1cdc..151930234c 100644 --- a/src/bin/pg_rewind/filemap.c +++ b/src/bin/pg_rewind/filemap.c @@ -3,7 +3,7 @@ * filemap.c * A data structure for keeping track of files that have changed. * - * Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Copyright (c) 2013-2017, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ @@ -79,11 +79,11 @@ process_source_file(const char *path, file_type_t type, size_t newsize, return; /* - * Pretend that pg_xlog is a directory, even if it's really a symlink. We + * Pretend that pg_wal is a directory, even if it's really a symlink. We * don't want to mess with the symlink itself, nor complain if it's a * symlink in source but not in target or vice versa. */ - if (strcmp(path, "pg_xlog") == 0 && type == FILE_TYPE_SYMLINK) + if (strcmp(path, "pg_wal") == 0 && type == FILE_TYPE_SYMLINK) type = FILE_TYPE_DIRECTORY; /* @@ -120,7 +120,7 @@ process_source_file(const char *path, file_type_t type, size_t newsize, switch (type) { case FILE_TYPE_DIRECTORY: - if (exists && !S_ISDIR(statbuf.st_mode) && strcmp(path, "pg_xlog") != 0) + if (exists && !S_ISDIR(statbuf.st_mode) && strcmp(path, "pg_wal") != 0) { /* it's a directory in source, but not in target. Strange.. */ pg_fatal("\"%s\" is not a directory\n", localpath); @@ -296,7 +296,7 @@ process_target_file(const char *path, file_type_t type, size_t oldsize, /* * Like in process_source_file, pretend that xlog is always a directory. */ - if (strcmp(path, "pg_xlog") == 0 && type == FILE_TYPE_SYMLINK) + if (strcmp(path, "pg_wal") == 0 && type == FILE_TYPE_SYMLINK) type = FILE_TYPE_DIRECTORY; key.path = (char *) path; diff --git a/src/bin/pg_rewind/filemap.h b/src/bin/pg_rewind/filemap.h index b6f66b49e5..3431047bf7 100644 --- a/src/bin/pg_rewind/filemap.h +++ b/src/bin/pg_rewind/filemap.h @@ -2,7 +2,7 @@ * * filemap.h * - * Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Copyright (c) 2013-2017, PostgreSQL Global Development Group *------------------------------------------------------------------------- */ #ifndef FILEMAP_H diff --git a/src/bin/pg_rewind/libpq_fetch.c b/src/bin/pg_rewind/libpq_fetch.c index 92390099eb..a903849ee4 100644 --- a/src/bin/pg_rewind/libpq_fetch.c +++ b/src/bin/pg_rewind/libpq_fetch.c @@ -3,7 +3,7 @@ * libpq_fetch.c * Functions for fetching files from a remote server. * - * Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Copyright (c) 2013-2017, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ @@ -49,6 +49,7 @@ void libpqConnect(const char *connstr) { char *str; + PGresult *res; conn = PQconnectdb(connstr); if (PQstatus(conn) == CONNECTION_BAD) @@ -77,6 +78,19 @@ libpqConnect(const char *connstr) if (strcmp(str, "on") != 0) pg_fatal("full_page_writes must be enabled in the source server\n"); pg_free(str); + + /* + * Although we don't do any "real" updates, we do work with a temporary + * table. We don't care about synchronous commit for that. It doesn't + * otherwise matter much, but if the server is using synchronous + * replication, and replication isn't working for some reason, we don't + * want to get stuck, waiting for it to start working again. + */ + res = PQexec(conn, "SET synchronous_commit = off"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) + pg_fatal("could not set up connection context: %s", + PQresultErrorMessage(res)); + PQclear(res); } /* diff --git a/src/bin/pg_rewind/logging.c b/src/bin/pg_rewind/logging.c index a232abb39f..cae776df12 100644 --- a/src/bin/pg_rewind/logging.c +++ b/src/bin/pg_rewind/logging.c @@ -3,7 +3,7 @@ * logging.c * logging functions * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ @@ -34,26 +34,26 @@ pg_log_v(eLogType type, const char *fmt, va_list ap) { char message[QUERY_ALLOC]; - vsnprintf(message, sizeof(message), fmt, ap); + vsnprintf(message, sizeof(message), _(fmt), ap); switch (type) { case PG_DEBUG: if (debug) - printf("%s", _(message)); + printf("%s", message); break; case PG_PROGRESS: if (showprogress) - printf("%s", _(message)); + printf("%s", message); break; case PG_WARNING: - printf("%s", _(message)); + printf("%s", message); break; case PG_FATAL: - printf("\n%s", _(message)); + printf("\n%s", message); printf("%s", _("Failure, exiting\n")); exit(1); break; diff --git a/src/bin/pg_rewind/logging.h b/src/bin/pg_rewind/logging.h index f2a9e89fd6..c2f4689104 100644 --- a/src/bin/pg_rewind/logging.h +++ b/src/bin/pg_rewind/logging.h @@ -4,7 +4,7 @@ * prototypes for logging functions * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * *------------------------------------------------------------------------- diff --git a/src/bin/pg_rewind/parsexlog.c b/src/bin/pg_rewind/parsexlog.c index b53591d02a..cb433819e4 100644 --- a/src/bin/pg_rewind/parsexlog.c +++ b/src/bin/pg_rewind/parsexlog.c @@ -3,7 +3,7 @@ * parsexlog.c * Functions for reading Write-Ahead-Log * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * *------------------------------------------------------------------------- @@ -54,7 +54,7 @@ static int SimpleXLogPageRead(XLogReaderState *xlogreader, TimeLineID *pageTLI); /* - * Read WAL from the datadir/pg_xlog, starting from 'startpoint' on timeline + * Read WAL from the datadir/pg_wal, starting from 'startpoint' on timeline * index 'tliIndex' in target timeline history, until 'endpoint'. Make note of * the data blocks touched by the WAL records, and return them in a page map. */ diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c index 5fdd4c5605..2014feea40 100644 --- a/src/bin/pg_rewind/pg_rewind.c +++ b/src/bin/pg_rewind/pg_rewind.c @@ -3,7 +3,7 @@ * pg_rewind.c * Synchronizes a PostgreSQL data directory to a new timeline * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ @@ -162,6 +162,13 @@ main(int argc, char **argv) exit(1); } + if (datadir_source != NULL && connstr_source != NULL) + { + fprintf(stderr, _("%s: only one of --source-pgdata or --source-server can be specified\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); + exit(1); + } + if (datadir_target == NULL) { fprintf(stderr, _("%s: no target data directory specified (--target-pgdata)\n"), progname); diff --git a/src/bin/pg_rewind/pg_rewind.h b/src/bin/pg_rewind/pg_rewind.h index f5e02d7056..5c8e7bb1bf 100644 --- a/src/bin/pg_rewind/pg_rewind.h +++ b/src/bin/pg_rewind/pg_rewind.h @@ -3,7 +3,7 @@ * pg_rewind.h * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * *------------------------------------------------------------------------- diff --git a/src/bin/pg_rewind/t/004_pg_xlog_symlink.pl b/src/bin/pg_rewind/t/004_pg_xlog_symlink.pl index bdcab5688b..12950ea1ca 100644 --- a/src/bin/pg_rewind/t/004_pg_xlog_symlink.pl +++ b/src/bin/pg_rewind/t/004_pg_xlog_symlink.pl @@ -1,5 +1,5 @@ # -# Test pg_rewind when the target's pg_xlog directory is a symlink. +# Test pg_rewind when the target's pg_wal directory is a symlink. # use strict; use warnings; @@ -30,10 +30,10 @@ sub run_test my $test_master_datadir = $node_master->data_dir; - # turn pg_xlog into a symlink - print("moving $test_master_datadir/pg_xlog to $master_xlogdir\n"); - move("$test_master_datadir/pg_xlog", $master_xlogdir) or die; - symlink($master_xlogdir, "$test_master_datadir/pg_xlog") or die; + # turn pg_wal into a symlink + print("moving $test_master_datadir/pg_wal to $master_xlogdir\n"); + move("$test_master_datadir/pg_wal", $master_xlogdir) or die; + symlink($master_xlogdir, "$test_master_datadir/pg_wal") or die; RewindTest::start_master(); diff --git a/src/bin/pg_rewind/timeline.c b/src/bin/pg_rewind/timeline.c index ec86434ffc..f1a792ff6b 100644 --- a/src/bin/pg_rewind/timeline.c +++ b/src/bin/pg_rewind/timeline.c @@ -3,7 +3,7 @@ * timeline.c * timeline-related functions. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/bin/pg_test_fsync/nls.mk b/src/bin/pg_test_fsync/nls.mk new file mode 100644 index 0000000000..6c95731020 --- /dev/null +++ b/src/bin/pg_test_fsync/nls.mk @@ -0,0 +1,5 @@ +# src/bin/pg_test_fsync/nls.mk +CATALOG_NAME = pg_test_fsync +AVAIL_LANGUAGES = +GETTEXT_FILES = pg_test_fsync.c +GETTEXT_TRIGGERS = die diff --git a/src/bin/pg_test_fsync/pg_test_fsync.c b/src/bin/pg_test_fsync/pg_test_fsync.c index c8427623d2..d65c0ab110 100644 --- a/src/bin/pg_test_fsync/pg_test_fsync.c +++ b/src/bin/pg_test_fsync/pg_test_fsync.c @@ -44,7 +44,7 @@ do { \ if (CreateThread(NULL, 0, process_alarm, NULL, 0, NULL) == \ INVALID_HANDLE_VALUE) \ { \ - fprintf(stderr, "Cannot create thread for alarm\n"); \ + fprintf(stderr, _("Cannot create thread for alarm\n")); \ exit(1); \ } \ gettimeofday(&start_t, NULL); \ @@ -96,6 +96,7 @@ static void die(const char *str); int main(int argc, char *argv[]) { + set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_test_fsync")); progname = get_progname(argv[0]); handle_args(argc, argv); @@ -148,7 +149,7 @@ handle_args(int argc, char *argv[]) { if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) { - printf("Usage: %s [-f FILENAME] [-s SECS-PER-TEST]\n", progname); + printf(_("Usage: %s [-f FILENAME] [-s SECS-PER-TEST]\n"), progname); exit(0); } if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) @@ -172,7 +173,7 @@ handle_args(int argc, char *argv[]) break; default: - fprintf(stderr, "Try \"%s --help\" for more information.\n", + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); break; @@ -182,18 +183,18 @@ handle_args(int argc, char *argv[]) if (argc > optind) { fprintf(stderr, - "%s: too many command-line arguments (first is \"%s\")\n", + _("%s: too many command-line arguments (first is \"%s\")\n"), progname, argv[optind]); - fprintf(stderr, "Try \"%s --help\" for more information.\n", + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } - printf("%d seconds per test\n", secs_per_test); + printf(_("%d seconds per test\n"), secs_per_test); #if PG_O_DIRECT != 0 - printf("O_DIRECT supported on this platform for open_datasync and open_sync.\n"); + printf(_("O_DIRECT supported on this platform for open_datasync and open_sync.\n")); #else - printf("Direct I/O is not supported on this platform.\n"); + printf(_("Direct I/O is not supported on this platform.\n")); #endif } @@ -239,10 +240,10 @@ test_sync(int writes_per_op) bool fs_warning = false; if (writes_per_op == 1) - printf("\nCompare file sync methods using one %dkB write:\n", XLOG_BLCKSZ_K); + printf(_("\nCompare file sync methods using one %dkB write:\n"), XLOG_BLCKSZ_K); else - printf("\nCompare file sync methods using two %dkB writes:\n", XLOG_BLCKSZ_K); - printf("(in wal_sync_method preference order, except fdatasync is Linux's default)\n"); + printf(_("\nCompare file sync methods using two %dkB writes:\n"), XLOG_BLCKSZ_K); + printf(_("(in wal_sync_method preference order, except fdatasync is Linux's default)\n")); /* * Test open_datasync if available @@ -253,7 +254,7 @@ test_sync(int writes_per_op) #ifdef OPEN_DATASYNC_FLAG if ((tmpfile = open(filename, O_RDWR | O_DSYNC | PG_O_DIRECT, 0)) == -1) { - printf(NA_FORMAT, "n/a*\n"); + printf(NA_FORMAT, _("n/a*\n")); fs_warning = true; } else @@ -271,7 +272,7 @@ test_sync(int writes_per_op) close(tmpfile); } #else - printf(NA_FORMAT, "n/a\n"); + printf(NA_FORMAT, _("n/a\n")); #endif /* @@ -296,7 +297,7 @@ test_sync(int writes_per_op) STOP_TIMER; close(tmpfile); #else - printf(NA_FORMAT, "n/a\n"); + printf(NA_FORMAT, _("n/a\n")); #endif /* @@ -344,7 +345,7 @@ test_sync(int writes_per_op) STOP_TIMER; close(tmpfile); #else - printf(NA_FORMAT, "n/a\n"); + printf(NA_FORMAT, _("n/a\n")); #endif /* @@ -356,7 +357,7 @@ test_sync(int writes_per_op) #ifdef OPEN_SYNC_FLAG if ((tmpfile = open(filename, O_RDWR | OPEN_SYNC_FLAG | PG_O_DIRECT, 0)) == -1) { - printf(NA_FORMAT, "n/a*\n"); + printf(NA_FORMAT, _("n/a*\n")); fs_warning = true; } else @@ -381,28 +382,28 @@ test_sync(int writes_per_op) close(tmpfile); } #else - printf(NA_FORMAT, "n/a\n"); + printf(NA_FORMAT, _("n/a\n")); #endif if (fs_warning) { - printf("* This file system and its mount options do not support direct\n"); - printf("I/O, e.g. ext4 in journaled mode.\n"); + printf(_("* This file system and its mount options do not support direct\n" + " I/O, e.g. ext4 in journaled mode.\n")); } } static void test_open_syncs(void) { - printf("\nCompare open_sync with different write sizes:\n"); - printf("(This is designed to compare the cost of writing 16kB in different write\n" - "open_sync sizes.)\n"); - - test_open_sync(" 1 * 16kB open_sync write", 16); - test_open_sync(" 2 * 8kB open_sync writes", 8); - test_open_sync(" 4 * 4kB open_sync writes", 4); - test_open_sync(" 8 * 2kB open_sync writes", 2); - test_open_sync("16 * 1kB open_sync writes", 1); + printf(_("\nCompare open_sync with different write sizes:\n")); + printf(_("(This is designed to compare the cost of writing 16kB in different write\n" + "open_sync sizes.)\n")); + + test_open_sync(_(" 1 * 16kB open_sync write"), 16); + test_open_sync(_(" 2 * 8kB open_sync writes"), 8); + test_open_sync(_(" 4 * 4kB open_sync writes"), 4); + test_open_sync(_(" 8 * 2kB open_sync writes"), 2); + test_open_sync(_("16 * 1kB open_sync writes"), 1); } /* @@ -422,7 +423,7 @@ test_open_sync(const char *msg, int writes_size) #ifdef OPEN_SYNC_FLAG if ((tmpfile = open(filename, O_RDWR | OPEN_SYNC_FLAG | PG_O_DIRECT, 0)) == -1) - printf(NA_FORMAT, "n/a*\n"); + printf(NA_FORMAT, _("n/a*\n")); else { START_TIMER; @@ -439,7 +440,7 @@ test_open_sync(const char *msg, int writes_size) close(tmpfile); } #else - printf(NA_FORMAT, "n/a\n"); + printf(NA_FORMAT, _("n/a\n")); #endif } @@ -455,9 +456,9 @@ test_file_descriptor_sync(void) * against the same file. Possibly this should be done with writethrough * on platforms which support it. */ - printf("\nTest if fsync on non-write file descriptor is honored:\n"); - printf("(If the times are similar, fsync() can sync data written on a different\n" - "descriptor.)\n"); + printf(_("\nTest if fsync on non-write file descriptor is honored:\n")); + printf(_("(If the times are similar, fsync() can sync data written on a different\n" + "descriptor.)\n")); /* * first write, fsync and close, which is the normal behavior without @@ -521,7 +522,7 @@ test_non_sync(void) /* * Test a simple write without fsync */ - printf("\nNon-sync'ed %dkB writes:\n", XLOG_BLCKSZ_K); + printf(_("\nNon-sync'ed %dkB writes:\n"), XLOG_BLCKSZ_K); printf(LABEL_FORMAT, "write"); fflush(stdout); @@ -598,6 +599,6 @@ process_alarm(LPVOID param) static void die(const char *str) { - fprintf(stderr, "%s: %s\n", str, strerror(errno)); + fprintf(stderr, _("%s: %s\n"), _(str), strerror(errno)); exit(1); } diff --git a/src/bin/pg_test_timing/nls.mk b/src/bin/pg_test_timing/nls.mk new file mode 100644 index 0000000000..e12ea5cfdb --- /dev/null +++ b/src/bin/pg_test_timing/nls.mk @@ -0,0 +1,4 @@ +# src/bin/pg_test_timing/nls.mk +CATALOG_NAME = pg_test_timing +AVAIL_LANGUAGES = +GETTEXT_FILES = pg_test_timing.c diff --git a/src/bin/pg_test_timing/pg_test_timing.c b/src/bin/pg_test_timing/pg_test_timing.c index e5c11de6bb..2f1ab7cd60 100644 --- a/src/bin/pg_test_timing/pg_test_timing.c +++ b/src/bin/pg_test_timing/pg_test_timing.c @@ -25,6 +25,7 @@ main(int argc, char *argv[]) { uint64 loop_count; + set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_test_timing")); progname = get_progname(argv[0]); handle_args(argc, argv); @@ -51,7 +52,7 @@ handle_args(int argc, char *argv[]) { if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) { - printf("Usage: %s [-d DURATION]\n", progname); + printf(_("Usage: %s [-d DURATION]\n"), progname); exit(0); } if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) @@ -71,7 +72,7 @@ handle_args(int argc, char *argv[]) break; default: - fprintf(stderr, "Try \"%s --help\" for more information.\n", + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); break; @@ -81,23 +82,26 @@ handle_args(int argc, char *argv[]) if (argc > optind) { fprintf(stderr, - "%s: too many command-line arguments (first is \"%s\")\n", + _("%s: too many command-line arguments (first is \"%s\")\n"), progname, argv[optind]); - fprintf(stderr, "Try \"%s --help\" for more information.\n", + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } if (test_duration > 0) { - printf("Testing timing overhead for %d seconds.\n", test_duration); + printf(ngettext("Testing timing overhead for %d second.\n", + "Testing timing overhead for %d seconds.\n", + test_duration), + test_duration); } else { fprintf(stderr, - "%s: duration must be a positive integer (duration is \"%d\")\n", + _("%s: duration must be a positive integer (duration is \"%d\")\n"), progname, test_duration); - fprintf(stderr, "Try \"%s --help\" for more information.\n", + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } @@ -133,8 +137,8 @@ test_timing(int32 duration) /* Did time go backwards? */ if (diff < 0) { - printf("Detected clock going backwards in time.\n"); - printf("Time warp: %d microseconds\n", diff); + fprintf(stderr, _("Detected clock going backwards in time.\n")); + fprintf(stderr, _("Time warp: %d ms\n"), diff); exit(1); } @@ -157,7 +161,7 @@ test_timing(int32 duration) INSTR_TIME_SUBTRACT(end_time, start_time); - printf("Per loop time including overhead: %0.2f nsec\n", + printf(_("Per loop time including overhead: %0.2f ns\n"), INSTR_TIME_GET_DOUBLE(end_time) * 1e9 / loop_count); return loop_count; @@ -173,8 +177,8 @@ output(uint64 loop_count) while (max_bit > 0 && histogram[max_bit] == 0) max_bit--; - printf("Histogram of timing durations:\n"); - printf("%6s %10s %10s\n", "< usec", "% of total", "count"); + printf(_("Histogram of timing durations:\n")); + printf("%6s %10s %10s\n", _("< us"), _("% of total"), _("count")); for (i = 0; i <= max_bit; i++) { diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c index f901e3c512..b6efad429a 100644 --- a/src/bin/pg_upgrade/check.c +++ b/src/bin/pg_upgrade/check.c @@ -3,7 +3,7 @@ * * server checks and output routines * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * src/bin/pg_upgrade/check.c */ @@ -431,8 +431,8 @@ create_script_for_cluster_analyze(char **analyze_script_file_name) SCRIPT_PREFIX, SCRIPT_EXT); if ((script = fopen_priv(*analyze_script_file_name, "w")) == NULL) - pg_fatal("Could not open file \"%s\": %s\n", - *analyze_script_file_name, getErrorText()); + pg_fatal("could not open file \"%s\": %s\n", + *analyze_script_file_name, strerror(errno)); #ifndef WIN32 /* add shebang header */ @@ -486,8 +486,8 @@ create_script_for_cluster_analyze(char **analyze_script_file_name) #ifndef WIN32 if (chmod(*analyze_script_file_name, S_IRWXU) != 0) - pg_fatal("Could not add execute permission to file \"%s\": %s\n", - *analyze_script_file_name, getErrorText()); + pg_fatal("could not add execute permission to file \"%s\": %s\n", + *analyze_script_file_name, strerror(errno)); #endif termPQExpBuffer(&user_specification); @@ -559,8 +559,8 @@ create_script_for_old_cluster_deletion(char **deletion_script_file_name) prep_status("Creating script to delete old cluster"); if ((script = fopen_priv(*deletion_script_file_name, "w")) == NULL) - pg_fatal("Could not open file \"%s\": %s\n", - *deletion_script_file_name, getErrorText()); + pg_fatal("could not open file \"%s\": %s\n", + *deletion_script_file_name, strerror(errno)); #ifndef WIN32 /* add shebang header */ @@ -615,8 +615,8 @@ create_script_for_old_cluster_deletion(char **deletion_script_file_name) #ifndef WIN32 if (chmod(*deletion_script_file_name, S_IRWXU) != 0) - pg_fatal("Could not add execute permission to file \"%s\": %s\n", - *deletion_script_file_name, getErrorText()); + pg_fatal("could not add execute permission to file \"%s\": %s\n", + *deletion_script_file_name, strerror(errno)); #endif check_ok(); @@ -819,8 +819,8 @@ check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster) { found = true; if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL) - pg_fatal("Could not open file \"%s\": %s\n", - output_path, getErrorText()); + pg_fatal("could not open file \"%s\": %s\n", + output_path, strerror(errno)); if (!db_used) { fprintf(script, "Database: %s\n", active_db->db_name); @@ -922,8 +922,8 @@ check_for_reg_data_type_usage(ClusterInfo *cluster) { found = true; if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL) - pg_fatal("Could not open file \"%s\": %s\n", - output_path, getErrorText()); + pg_fatal("could not open file \"%s\": %s\n", + output_path, strerror(errno)); if (!db_used) { fprintf(script, "Database: %s\n", active_db->db_name); @@ -1013,8 +1013,8 @@ check_for_jsonb_9_4_usage(ClusterInfo *cluster) { found = true; if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL) - pg_fatal("Could not open file \"%s\": %s\n", - output_path, getErrorText()); + pg_fatal("could not open file \"%s\": %s\n", + output_path, strerror(errno)); if (!db_used) { fprintf(script, "Database: %s\n", active_db->db_name); @@ -1082,15 +1082,15 @@ get_bin_version(ClusterInfo *cluster) char cmd[MAXPGPATH], cmd_output[MAX_STRING]; FILE *output; - int pre_dot, - post_dot; + int pre_dot = 0, + post_dot = 0; snprintf(cmd, sizeof(cmd), "\"%s/pg_ctl\" --version", cluster->bindir); if ((output = popen(cmd, "r")) == NULL || fgets(cmd_output, sizeof(cmd_output), output) == NULL) - pg_fatal("Could not get pg_ctl version data using %s: %s\n", - cmd, getErrorText()); + pg_fatal("could not get pg_ctl version data using %s: %s\n", + cmd, strerror(errno)); pclose(output); @@ -1098,7 +1098,7 @@ get_bin_version(ClusterInfo *cluster) if (strchr(cmd_output, '\n') != NULL) *strchr(cmd_output, '\n') = '\0'; - if (sscanf(cmd_output, "%*s %*s %d.%d", &pre_dot, &post_dot) != 2) + if (sscanf(cmd_output, "%*s %*s %d.%d", &pre_dot, &post_dot) < 1) pg_fatal("could not get version from %s\n", cmd); cluster->bin_version = (pre_dot * 100 + post_dot) * 100; diff --git a/src/bin/pg_upgrade/controldata.c b/src/bin/pg_upgrade/controldata.c index d89cf196ab..b9387ff5a9 100644 --- a/src/bin/pg_upgrade/controldata.c +++ b/src/bin/pg_upgrade/controldata.c @@ -3,7 +3,7 @@ * * controldata functions * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * src/bin/pg_upgrade/controldata.c */ @@ -119,8 +119,8 @@ get_control_data(ClusterInfo *cluster, bool live_check) fflush(stderr); if ((output = popen(cmd, "r")) == NULL) - pg_fatal("Could not get control data using %s: %s\n", - cmd, getErrorText()); + pg_fatal("could not get control data using %s: %s\n", + cmd, strerror(errno)); /* Only in <= 9.2 */ if (GET_MAJOR_VERSION(cluster->major_version) <= 902) diff --git a/src/bin/pg_upgrade/dump.c b/src/bin/pg_upgrade/dump.c index 81fb725338..f18be22c16 100644 --- a/src/bin/pg_upgrade/dump.c +++ b/src/bin/pg_upgrade/dump.c @@ -3,7 +3,7 @@ * * dump functions * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * src/bin/pg_upgrade/dump.c */ diff --git a/src/bin/pg_upgrade/exec.c b/src/bin/pg_upgrade/exec.c index dd30952441..3a30ea7438 100644 --- a/src/bin/pg_upgrade/exec.c +++ b/src/bin/pg_upgrade/exec.c @@ -3,7 +3,7 @@ * * execution functions * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * src/bin/pg_upgrade/exec.c */ @@ -14,7 +14,7 @@ #include #include -static void check_data_dir(const char *pg_data); +static void check_data_dir(ClusterInfo *cluster); static void check_bin_dir(ClusterInfo *cluster); static void validate_exec(const char *dir, const char *cmdName); @@ -191,7 +191,7 @@ pid_lock_file_exists(const char *datadir) /* ENOTDIR means we will throw a more useful error later */ if (errno != ENOENT && errno != ENOTDIR) pg_fatal("could not open file \"%s\" for reading: %s\n", - path, getErrorText()); + path, strerror(errno)); return false; } @@ -220,9 +220,9 @@ verify_directories(void) pg_fatal("You must have read and write access in the current directory.\n"); check_bin_dir(&old_cluster); - check_data_dir(old_cluster.pgdata); + check_data_dir(&old_cluster); check_bin_dir(&new_cluster); - check_data_dir(new_cluster.pgdata); + check_data_dir(&new_cluster); } @@ -252,6 +252,32 @@ win32_check_directory_write_permissions(void) #endif +/* + * check_single_dir() + * + * Check for the presence of a single directory in PGDATA, and fail if + * is it missing or not accessible. + */ +static void +check_single_dir(const char *pg_data, const char *subdir) +{ + struct stat statBuf; + char subDirName[MAXPGPATH]; + + snprintf(subDirName, sizeof(subDirName), "%s%s%s", pg_data, + /* Win32 can't stat() a directory with a trailing slash. */ + *subdir ? "/" : "", + subdir); + + if (stat(subDirName, &statBuf) != 0) + report_status(PG_FATAL, "check for \"%s\" failed: %s\n", + subDirName, strerror(errno)); + else if (!S_ISDIR(statBuf.st_mode)) + report_status(PG_FATAL, "%s is not a directory\n", + subDirName); +} + + /* * check_data_dir() * @@ -262,34 +288,27 @@ win32_check_directory_write_permissions(void) * */ static void -check_data_dir(const char *pg_data) +check_data_dir(ClusterInfo *cluster) { - char subDirName[MAXPGPATH]; - int subdirnum; - - /* start check with top-most directory */ - const char *requiredSubdirs[] = {"", "base", "global", "pg_clog", - "pg_multixact", "pg_subtrans", "pg_tblspc", "pg_twophase", - "pg_xlog"}; - - for (subdirnum = 0; - subdirnum < sizeof(requiredSubdirs) / sizeof(requiredSubdirs[0]); - ++subdirnum) - { - struct stat statBuf; - - snprintf(subDirName, sizeof(subDirName), "%s%s%s", pg_data, - /* Win32 can't stat() a directory with a trailing slash. */ - *requiredSubdirs[subdirnum] ? "/" : "", - requiredSubdirs[subdirnum]); - - if (stat(subDirName, &statBuf) != 0) - report_status(PG_FATAL, "check for \"%s\" failed: %s\n", - subDirName, getErrorText()); - else if (!S_ISDIR(statBuf.st_mode)) - report_status(PG_FATAL, "%s is not a directory\n", - subDirName); - } + const char *pg_data = cluster->pgdata; + + /* get old and new cluster versions */ + old_cluster.major_version = get_major_server_version(&old_cluster); + new_cluster.major_version = get_major_server_version(&new_cluster); + + check_single_dir(pg_data, ""); + check_single_dir(pg_data, "base"); + check_single_dir(pg_data, "global"); + check_single_dir(pg_data, "pg_multixact"); + check_single_dir(pg_data, "pg_subtrans"); + check_single_dir(pg_data, "pg_tblspc"); + check_single_dir(pg_data, "pg_twophase"); + + /* pg_xlog has been renamed to pg_wal in post-10 cluster */ + if (GET_MAJOR_VERSION(cluster->major_version) < 1000) + check_single_dir(pg_data, "pg_xlog"); + else + check_single_dir(pg_data, "pg_wal"); } @@ -309,7 +328,7 @@ check_bin_dir(ClusterInfo *cluster) /* check bindir */ if (stat(cluster->bindir, &statBuf) != 0) report_status(PG_FATAL, "check for \"%s\" failed: %s\n", - cluster->bindir, getErrorText()); + cluster->bindir, strerror(errno)); else if (!S_ISDIR(statBuf.st_mode)) report_status(PG_FATAL, "%s is not a directory\n", cluster->bindir); @@ -352,7 +371,7 @@ validate_exec(const char *dir, const char *cmdName) */ if (stat(path, &buf) < 0) pg_fatal("check for \"%s\" failed: %s\n", - path, getErrorText()); + path, strerror(errno)); else if (!S_ISREG(buf.st_mode)) pg_fatal("check for \"%s\" failed: not an executable file\n", path); diff --git a/src/bin/pg_upgrade/file.c b/src/bin/pg_upgrade/file.c index b33f0b46e3..50897e7b7a 100644 --- a/src/bin/pg_upgrade/file.c +++ b/src/bin/pg_upgrade/file.c @@ -3,7 +3,7 @@ * * file system operations * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * src/bin/pg_upgrade/file.c */ @@ -18,12 +18,8 @@ #include #include -#define BITS_PER_HEAPBLOCK_OLD 1 - -#ifndef WIN32 -static int copy_file(const char *fromfile, const char *tofile); -#else +#ifdef WIN32 static int win32_pghardlink(const char *src, const char *dst); #endif @@ -31,72 +27,29 @@ static int win32_pghardlink(const char *src, const char *dst); /* * copyFile() * - * Copies a relation file from src to dst. + * Copies a relation file from src to dst. + * schemaName/relName are relation's SQL name (used for error messages only). */ -const char * -copyFile(const char *src, const char *dst) +void +copyFile(const char *src, const char *dst, + const char *schemaName, const char *relName) { #ifndef WIN32 - if (copy_file(src, dst) == -1) -#else - if (CopyFile(src, dst, true) == 0) -#endif - return getErrorText(); - else - return NULL; -} - - -/* - * linkFile() - * - * Creates a hard link between the given relation files. We use - * this function to perform a true in-place update. If the on-disk - * format of the new cluster is bit-for-bit compatible with the on-disk - * format of the old cluster, we can simply link each relation - * instead of copying the data from the old cluster to the new cluster. - */ -const char * -linkFile(const char *src, const char *dst) -{ - if (pg_link_file(src, dst) == -1) - return getErrorText(); - else - return NULL; -} - - -#ifndef WIN32 -static int -copy_file(const char *srcfile, const char *dstfile) -{ -#define COPY_BUF_SIZE (50 * BLCKSZ) - int src_fd; int dest_fd; char *buffer; - int ret = 0; - int save_errno = 0; - - if ((srcfile == NULL) || (dstfile == NULL)) - { - errno = EINVAL; - return -1; - } - if ((src_fd = open(srcfile, O_RDONLY, 0)) < 0) - return -1; - - if ((dest_fd = open(dstfile, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) < 0) - { - save_errno = errno; + if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0) + pg_fatal("error while copying relation \"%s.%s\": could not open file \"%s\": %s\n", + schemaName, relName, src, strerror(errno)); - if (src_fd != 0) - close(src_fd); + if ((dest_fd = open(dst, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, + S_IRUSR | S_IWUSR)) < 0) + pg_fatal("error while copying relation \"%s.%s\": could not create file \"%s\": %s\n", + schemaName, relName, dst, strerror(errno)); - errno = save_errno; - return -1; - } + /* copy in fairly large chunks for best efficiency */ +#define COPY_BUF_SIZE (50 * BLCKSZ) buffer = (char *) pg_malloc(COPY_BUF_SIZE); @@ -106,103 +59,121 @@ copy_file(const char *srcfile, const char *dstfile) ssize_t nbytes = read(src_fd, buffer, COPY_BUF_SIZE); if (nbytes < 0) - { - save_errno = errno; - ret = -1; - break; - } + pg_fatal("error while copying relation \"%s.%s\": could not read file \"%s\": %s\n", + schemaName, relName, src, strerror(errno)); if (nbytes == 0) break; errno = 0; - if (write(dest_fd, buffer, nbytes) != nbytes) { /* if write didn't set errno, assume problem is no disk space */ if (errno == 0) errno = ENOSPC; - save_errno = errno; - ret = -1; - break; + pg_fatal("error while copying relation \"%s.%s\": could not write file \"%s\": %s\n", + schemaName, relName, dst, strerror(errno)); } } pg_free(buffer); + close(src_fd); + close(dest_fd); - if (src_fd != 0) - close(src_fd); +#else /* WIN32 */ + + if (CopyFile(src, dst, true) == 0) + { + _dosmaperr(GetLastError()); + pg_fatal("error while copying relation \"%s.%s\" (\"%s\" to \"%s\"): %s\n", + schemaName, relName, src, dst, strerror(errno)); + } - if (dest_fd != 0) - close(dest_fd); +#endif /* WIN32 */ +} - if (save_errno != 0) - errno = save_errno; - return ret; +/* + * linkFile() + * + * Hard-links a relation file from src to dst. + * schemaName/relName are relation's SQL name (used for error messages only). + */ +void +linkFile(const char *src, const char *dst, + const char *schemaName, const char *relName) +{ + if (pg_link_file(src, dst) < 0) + pg_fatal("error while creating link for relation \"%s.%s\" (\"%s\" to \"%s\"): %s\n", + schemaName, relName, src, dst, strerror(errno)); } -#endif /* * rewriteVisibilityMap() * + * Transform a visibility map file, copying from src to dst. + * schemaName/relName are relation's SQL name (used for error messages only). + * * In versions of PostgreSQL prior to catversion 201603011, PostgreSQL's * visibility map included one bit per heap page; it now includes two. * When upgrading a cluster from before that time to a current PostgreSQL * version, we could refuse to copy visibility maps from the old cluster * to the new cluster; the next VACUUM would recreate them, but at the * price of scanning the entire table. So, instead, we rewrite the old - * visibility maps in the new format. That way, the all-visible bit - * remains set for the pages for which it was set previously. The - * all-frozen bit is never set by this conversion; we leave that to - * VACUUM. + * visibility maps in the new format. That way, the all-visible bits + * remain set for the pages for which they were set previously. The + * all-frozen bits are never set by this conversion; we leave that to VACUUM. */ -const char * -rewriteVisibilityMap(const char *fromfile, const char *tofile) +void +rewriteVisibilityMap(const char *fromfile, const char *tofile, + const char *schemaName, const char *relName) { - int src_fd = 0; - int dst_fd = 0; - char buffer[BLCKSZ]; - ssize_t bytesRead; + int src_fd; + int dst_fd; + char *buffer; + char *new_vmbuf; ssize_t totalBytesRead = 0; ssize_t src_filesize; int rewriteVmBytesPerPage; BlockNumber new_blkno = 0; struct stat statbuf; - /* Compute we need how many old page bytes to rewrite a new page */ + /* Compute number of old-format bytes per new page */ rewriteVmBytesPerPage = (BLCKSZ - SizeOfPageHeaderData) / 2; - if ((fromfile == NULL) || (tofile == NULL)) - return "Invalid old file or new file"; - - if ((src_fd = open(fromfile, O_RDONLY, 0)) < 0) - return getErrorText(); + if ((src_fd = open(fromfile, O_RDONLY | PG_BINARY, 0)) < 0) + pg_fatal("error while copying relation \"%s.%s\": could not open file \"%s\": %s\n", + schemaName, relName, fromfile, strerror(errno)); if (fstat(src_fd, &statbuf) != 0) - { - close(src_fd); - return getErrorText(); - } + pg_fatal("error while copying relation \"%s.%s\": could not stat file \"%s\": %s\n", + schemaName, relName, fromfile, strerror(errno)); - if ((dst_fd = open(tofile, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) < 0) - { - close(src_fd); - return getErrorText(); - } + if ((dst_fd = open(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, + S_IRUSR | S_IWUSR)) < 0) + pg_fatal("error while copying relation \"%s.%s\": could not create file \"%s\": %s\n", + schemaName, relName, tofile, strerror(errno)); /* Save old file size */ src_filesize = statbuf.st_size; + /* + * Malloc the work buffers, rather than making them local arrays, to + * ensure adequate alignment. + */ + buffer = (char *) pg_malloc(BLCKSZ); + new_vmbuf = (char *) pg_malloc(BLCKSZ); + /* * Turn each visibility map page into 2 pages one by one. Each new page - * has the same page header as the old one. If the last section of last - * page is empty, we skip it, mostly to avoid turning one-page visibility - * maps for small relations into two pages needlessly. + * has the same page header as the old one. If the last section of the + * last page is empty, we skip it, mostly to avoid turning one-page + * visibility maps for small relations into two pages needlessly. */ while (totalBytesRead < src_filesize) { + ssize_t bytesRead; char *old_cur; char *old_break; char *old_blkend; @@ -211,9 +182,12 @@ rewriteVisibilityMap(const char *fromfile, const char *tofile) if ((bytesRead = read(src_fd, buffer, BLCKSZ)) != BLCKSZ) { - close(dst_fd); - close(src_fd); - return getErrorText(); + if (bytesRead < 0) + pg_fatal("error while copying relation \"%s.%s\": could not read file \"%s\": %s\n", + schemaName, relName, fromfile, strerror(errno)); + else + pg_fatal("error while copying relation \"%s.%s\": partial page found in file \"%s\"\n", + schemaName, relName, fromfile); } totalBytesRead += BLCKSZ; @@ -225,82 +199,83 @@ rewriteVisibilityMap(const char *fromfile, const char *tofile) /* * These old_* variables point to old visibility map page. old_cur * points to current position on old page. old_blkend points to end of - * old block. old_break points to old page break position for - * rewriting a new page. After wrote a new page, old_break proceeds - * rewriteVmBytesPerPage bytes. + * old block. old_break is the end+1 position on the old page for the + * data that will be transferred to the current new page. */ old_cur = buffer + SizeOfPageHeaderData; old_blkend = buffer + bytesRead; old_break = old_cur + rewriteVmBytesPerPage; - while (old_blkend >= old_break) + while (old_break <= old_blkend) { - char new_vmbuf[BLCKSZ]; - char *new_cur = new_vmbuf; + char *new_cur; bool empty = true; bool old_lastpart; - /* Copy page header in advance */ + /* First, copy old page header to new page */ memcpy(new_vmbuf, &pageheader, SizeOfPageHeaderData); - /* Rewrite the last part of the old page? */ - old_lastpart = old_lastblk && (old_blkend == old_break); + /* Rewriting the last part of the last old page? */ + old_lastpart = old_lastblk && (old_break == old_blkend); - new_cur += SizeOfPageHeaderData; + new_cur = new_vmbuf + SizeOfPageHeaderData; /* Process old page bytes one by one, and turn it into new page. */ - while (old_break > old_cur) + while (old_cur < old_break) { + uint8 byte = *(uint8 *) old_cur; uint16 new_vmbits = 0; int i; /* Generate new format bits while keeping old information */ for (i = 0; i < BITS_PER_BYTE; i++) { - uint8 byte = *(uint8 *) old_cur; - - if (byte & (1 << (BITS_PER_HEAPBLOCK_OLD * i))) + if (byte & (1 << i)) { empty = false; - new_vmbits |= 1 << (BITS_PER_HEAPBLOCK * i); + new_vmbits |= + VISIBILITYMAP_ALL_VISIBLE << (BITS_PER_HEAPBLOCK * i); } } - /* Copy new visibility map bit to new format page */ - memcpy(new_cur, &new_vmbits, BITS_PER_HEAPBLOCK); + /* Copy new visibility map bytes to new-format page */ + new_cur[0] = (char) (new_vmbits & 0xFF); + new_cur[1] = (char) (new_vmbits >> 8); - old_cur += BITS_PER_HEAPBLOCK_OLD; + old_cur++; new_cur += BITS_PER_HEAPBLOCK; } - /* If the last part of the old page is empty, skip writing it */ + /* If the last part of the last page is empty, skip writing it */ if (old_lastpart && empty) break; - /* Set new checksum for a visibility map page (if enabled) */ - if (old_cluster.controldata.data_checksum_version != 0 && - new_cluster.controldata.data_checksum_version != 0) + /* Set new checksum for visibility map page, if enabled */ + if (new_cluster.controldata.data_checksum_version != 0) ((PageHeader) new_vmbuf)->pd_checksum = pg_checksum_page(new_vmbuf, new_blkno); + errno = 0; if (write(dst_fd, new_vmbuf, BLCKSZ) != BLCKSZ) { - close(dst_fd); - close(src_fd); - return getErrorText(); + /* if write didn't set errno, assume problem is no disk space */ + if (errno == 0) + errno = ENOSPC; + pg_fatal("error while copying relation \"%s.%s\": could not write file \"%s\": %s\n", + schemaName, relName, tofile, strerror(errno)); } + /* Advance for next new page */ old_break += rewriteVmBytesPerPage; new_blkno++; } } - /* Close files */ + /* Clean up */ + pg_free(buffer); + pg_free(new_vmbuf); close(dst_fd); close(src_fd); - - return NULL; - } void @@ -313,16 +288,16 @@ check_hard_link(void) snprintf(new_link_file, sizeof(new_link_file), "%s/PG_VERSION.linktest", new_cluster.pgdata); unlink(new_link_file); /* might fail */ - if (pg_link_file(existing_file, new_link_file) == -1) - { - pg_fatal("Could not create hard link between old and new data directories: %s\n" + if (pg_link_file(existing_file, new_link_file) < 0) + pg_fatal("could not create hard link between old and new data directories: %s\n" "In link mode the old and new data directories must be on the same file system volume.\n", - getErrorText()); - } + strerror(errno)); + unlink(new_link_file); } #ifdef WIN32 +/* implementation of pg_link_file() on Windows */ static int win32_pghardlink(const char *src, const char *dst) { @@ -331,7 +306,10 @@ win32_pghardlink(const char *src, const char *dst) * http://msdn.microsoft.com/en-us/library/aa363860(VS.85).aspx */ if (CreateHardLinkA(dst, src, NULL) == 0) + { + _dosmaperr(GetLastError()); return -1; + } else return 0; } @@ -346,7 +324,8 @@ fopen_priv(const char *path, const char *mode) FILE *fp; fp = fopen(path, mode); - umask(old_umask); + + umask(old_umask); /* we assume this can't change errno */ return fp; } diff --git a/src/bin/pg_upgrade/function.c b/src/bin/pg_upgrade/function.c index eaae976c53..685d1de0b7 100644 --- a/src/bin/pg_upgrade/function.c +++ b/src/bin/pg_upgrade/function.c @@ -3,7 +3,7 @@ * * server-side function support * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * src/bin/pg_upgrade/function.c */ @@ -12,6 +12,31 @@ #include "pg_upgrade.h" #include "access/transam.h" +#include "catalog/pg_language.h" + + +/* + * qsort comparator for pointers to library names + * + * We sort first by name length, then alphabetically for names of the same + * length. This is to ensure that, eg, "hstore_plpython" sorts after both + * "hstore" and "plpython"; otherwise transform modules will probably fail + * their LOAD tests. (The backend ought to cope with that consideration, + * but it doesn't yet, and even when it does it'll still be a good idea + * to have a predictable order of probing here.) + */ +static int +library_name_compare(const void *p1, const void *p2) +{ + const char *str1 = *(const char *const *) p1; + const char *str2 = *(const char *const *) p2; + int slen1 = strlen(str1); + int slen2 = strlen(str2); + + if (slen1 != slen2) + return slen1 - slen2; + return strcmp(str1, str2); +} /* @@ -38,17 +63,15 @@ get_loadable_libraries(void) PGconn *conn = connectToServer(&old_cluster, active_db->db_name); /* - * Fetch all libraries referenced in this DB. We can't exclude the - * "pg_catalog" schema because, while such functions are not - * explicitly dumped by pg_dump, they do reference implicit objects - * that pg_dump does dump, e.g. CREATE LANGUAGE plperl. + * Fetch all libraries containing non-built-in C functions in this DB. */ ress[dbnum] = executeQueryOrDie(conn, "SELECT DISTINCT probin " - "FROM pg_catalog.pg_proc " - "WHERE prolang = 13 /* C */ AND " + "FROM pg_catalog.pg_proc " + "WHERE prolang = %u AND " "probin IS NOT NULL AND " "oid >= %u;", + ClanguageId, FirstNormalObjectId); totaltups += PQntuples(ress[dbnum]); @@ -69,13 +92,15 @@ get_loadable_libraries(void) res = executeQueryOrDie(conn, "SELECT 1 " - "FROM pg_catalog.pg_proc JOIN pg_namespace " - " ON pronamespace = pg_namespace.oid " + "FROM pg_catalog.pg_proc p " + " JOIN pg_catalog.pg_namespace n " + " ON pronamespace = n.oid " "WHERE proname = 'plpython_call_handler' AND " "nspname = 'public' AND " - "prolang = 13 /* C */ AND " + "prolang = %u AND " "probin = '$libdir/plpython' AND " - "pg_proc.oid >= %u;", + "p.oid >= %u;", + ClanguageId, FirstNormalObjectId); if (PQntuples(res) > 0) { @@ -112,13 +137,18 @@ get_loadable_libraries(void) if (found_public_plpython_handler) pg_fatal("Remove the problem functions from the old cluster to continue.\n"); - /* Allocate what's certainly enough space */ - os_info.libraries = (char **) pg_malloc(totaltups * sizeof(char *)); - /* - * Now remove duplicates across DBs. This is pretty inefficient code, but - * there probably aren't enough entries to matter. + * Now we want to remove duplicates across DBs and sort the library names + * into order. This avoids multiple probes of the same library, and + * ensures that libraries are probed in a consistent order, which is + * important for reproducible behavior if one library depends on another. + * + * First transfer all the names into one array, then sort, then remove + * duplicates. Note: we strdup each name in the first loop so that we can + * safely clear the PGresults in the same loop. This is a bit wasteful + * but it's unlikely there are enough names to matter. */ + os_info.libraries = (char **) pg_malloc(totaltups * sizeof(char *)); totaltups = 0; for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++) @@ -131,27 +161,34 @@ get_loadable_libraries(void) for (rowno = 0; rowno < ntups; rowno++) { char *lib = PQgetvalue(res, rowno, 0); - bool dup = false; - int n; - for (n = 0; n < totaltups; n++) - { - if (strcmp(lib, os_info.libraries[n]) == 0) - { - dup = true; - break; - } - } - if (!dup) - os_info.libraries[totaltups++] = pg_strdup(lib); + os_info.libraries[totaltups++] = pg_strdup(lib); } - PQclear(res); } - os_info.num_libraries = totaltups; - pg_free(ress); + + if (totaltups > 1) + { + int i, + lastnondup; + + qsort((void *) os_info.libraries, totaltups, sizeof(char *), + library_name_compare); + + for (i = 1, lastnondup = 0; i < totaltups; i++) + { + if (strcmp(os_info.libraries[i], + os_info.libraries[lastnondup]) != 0) + os_info.libraries[++lastnondup] = os_info.libraries[i]; + else + pg_free(os_info.libraries[i]); + } + totaltups = lastnondup + 1; + } + + os_info.num_libraries = totaltups; } @@ -213,9 +250,9 @@ check_loadable_libraries(void) found = true; if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL) - pg_fatal("Could not open file \"%s\": %s\n", - output_path, getErrorText()); - fprintf(script, "Could not load library \"%s\"\n%s\n", + pg_fatal("could not open file \"%s\": %s\n", + output_path, strerror(errno)); + fprintf(script, _("could not load library \"%s\":\n%s\n"), lib, PQerrorMessage(conn)); } diff --git a/src/bin/pg_upgrade/info.c b/src/bin/pg_upgrade/info.c index 1200c7fca2..853d8990ff 100644 --- a/src/bin/pg_upgrade/info.c +++ b/src/bin/pg_upgrade/info.c @@ -3,7 +3,7 @@ * * information support functions * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * src/bin/pg_upgrade/info.c */ @@ -238,7 +238,7 @@ report_unmatched_relation(const RelInfo *rel, const DbInfo *db, bool is_new_db) { snprintf(reldesc + strlen(reldesc), sizeof(reldesc) - strlen(reldesc), - " which is an index on \"%s.%s\"", + _(" which is an index on \"%s.%s\""), hrel->nspname, hrel->relname); /* Shift attention to index's table for toast check */ rel = hrel; @@ -248,7 +248,7 @@ report_unmatched_relation(const RelInfo *rel, const DbInfo *db, bool is_new_db) if (i >= db->rel_arr.nrels) snprintf(reldesc + strlen(reldesc), sizeof(reldesc) - strlen(reldesc), - " which is an index on OID %u", rel->indtable); + _(" which is an index on OID %u"), rel->indtable); } if (rel->toastheap) { @@ -260,7 +260,7 @@ report_unmatched_relation(const RelInfo *rel, const DbInfo *db, bool is_new_db) { snprintf(reldesc + strlen(reldesc), sizeof(reldesc) - strlen(reldesc), - " which is the TOAST table for \"%s.%s\"", + _(" which is the TOAST table for \"%s.%s\""), brel->nspname, brel->relname); break; } @@ -268,7 +268,7 @@ report_unmatched_relation(const RelInfo *rel, const DbInfo *db, bool is_new_db) if (i >= db->rel_arr.nrels) snprintf(reldesc + strlen(reldesc), sizeof(reldesc) - strlen(reldesc), - " which is the TOAST table for OID %u", rel->toastheap); + _(" which is the TOAST table for OID %u"), rel->toastheap); } if (is_new_db) @@ -444,7 +444,7 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo) " SELECT c.oid, 0::oid, 0::oid " " FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n " " ON c.relnamespace = n.oid " - " WHERE relkind IN ('r', 'm', 'S') AND " + " WHERE relkind IN ('r', 'm') AND " /* exclude possible orphaned temp tables */ " ((n.nspname !~ '^pg_temp_' AND " " n.nspname !~ '^pg_toast_temp_' AND " diff --git a/src/bin/pg_upgrade/nls.mk b/src/bin/pg_upgrade/nls.mk new file mode 100644 index 0000000000..a0c846d9ea --- /dev/null +++ b/src/bin/pg_upgrade/nls.mk @@ -0,0 +1,12 @@ +# src/bin/pg_upgrade/nls.mk +CATALOG_NAME = pg_upgrade +AVAIL_LANGUAGES = +GETTEXT_FILES = check.c controldata.c dump.c exec.c file.c function.c \ + info.c option.c parallel.c pg_upgrade.c relfilenode.c \ + server.c tablespace.c util.c version.c +GETTEXT_TRIGGERS = pg_fatal pg_log:2 prep_status report_status:2 +GETTEXT_FLAGS = \ + pg_fatal:1:c-format \ + pg_log:2:c-format \ + prep_status:1:c-format \ + report_status:2:c-format diff --git a/src/bin/pg_upgrade/option.c b/src/bin/pg_upgrade/option.c index 4597355461..82d2443bcd 100644 --- a/src/bin/pg_upgrade/option.c +++ b/src/bin/pg_upgrade/option.c @@ -3,7 +3,7 @@ * * options functions * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * src/bin/pg_upgrade/option.c */ @@ -240,13 +240,13 @@ parseCommandLine(int argc, char *argv[]) /* Get values from env if not already set */ check_required_directory(&old_cluster.bindir, NULL, "PGBINOLD", "-b", - "old cluster binaries reside"); + _("old cluster binaries reside")); check_required_directory(&new_cluster.bindir, NULL, "PGBINNEW", "-B", - "new cluster binaries reside"); + _("new cluster binaries reside")); check_required_directory(&old_cluster.pgdata, &old_cluster.pgconfig, - "PGDATAOLD", "-d", "old cluster data resides"); + "PGDATAOLD", "-d", _("old cluster data resides")); check_required_directory(&new_cluster.pgdata, &new_cluster.pgconfig, - "PGDATANEW", "-D", "new cluster data resides"); + "PGDATANEW", "-D", _("new cluster data resides")); #ifdef WIN32 @@ -275,56 +275,53 @@ parseCommandLine(int argc, char *argv[]) static void usage(void) { - printf(_("pg_upgrade upgrades a PostgreSQL cluster to a different major version.\n\ -\nUsage:\n\ - pg_upgrade [OPTION]...\n\ -\n\ -Options:\n\ - -b, --old-bindir=BINDIR old cluster executable directory\n\ - -B, --new-bindir=BINDIR new cluster executable directory\n\ - -c, --check check clusters only, don't change any data\n\ - -d, --old-datadir=DATADIR old cluster data directory\n\ - -D, --new-datadir=DATADIR new cluster data directory\n\ - -j, --jobs number of simultaneous processes or threads to use\n\ - -k, --link link instead of copying files to new cluster\n\ - -o, --old-options=OPTIONS old cluster options to pass to the server\n\ - -O, --new-options=OPTIONS new cluster options to pass to the server\n\ - -p, --old-port=PORT old cluster port number (default %d)\n\ - -P, --new-port=PORT new cluster port number (default %d)\n\ - -r, --retain retain SQL and log files after success\n\ - -U, --username=NAME cluster superuser (default \"%s\")\n\ - -v, --verbose enable verbose internal logging\n\ - -V, --version display version information, then exit\n\ - -?, --help show this help, then exit\n\ -\n\ -Before running pg_upgrade you must:\n\ - create a new database cluster (using the new version of initdb)\n\ - shutdown the postmaster servicing the old cluster\n\ - shutdown the postmaster servicing the new cluster\n\ -\n\ -When you run pg_upgrade, you must provide the following information:\n\ - the data directory for the old cluster (-d DATADIR)\n\ - the data directory for the new cluster (-D DATADIR)\n\ - the \"bin\" directory for the old version (-b BINDIR)\n\ - the \"bin\" directory for the new version (-B BINDIR)\n\ -\n\ -For example:\n\ - pg_upgrade -d oldCluster/data -D newCluster/data -b oldCluster/bin -B newCluster/bin\n\ -or\n"), old_cluster.port, new_cluster.port, os_info.user); + printf(_("pg_upgrade upgrades a PostgreSQL cluster to a different major version.\n\n")); + printf(_("Usage:\n")); + printf(_(" pg_upgrade [OPTION]...\n\n")); + printf(_("Options:\n")); + printf(_(" -b, --old-bindir=BINDIR old cluster executable directory\n")); + printf(_(" -B, --new-bindir=BINDIR new cluster executable directory\n")); + printf(_(" -c, --check check clusters only, don't change any data\n")); + printf(_(" -d, --old-datadir=DATADIR old cluster data directory\n")); + printf(_(" -D, --new-datadir=DATADIR new cluster data directory\n")); + printf(_(" -j, --jobs number of simultaneous processes or threads to use\n")); + printf(_(" -k, --link link instead of copying files to new cluster\n")); + printf(_(" -o, --old-options=OPTIONS old cluster options to pass to the server\n")); + printf(_(" -O, --new-options=OPTIONS new cluster options to pass to the server\n")); + printf(_(" -p, --old-port=PORT old cluster port number (default %d)\n"), old_cluster.port); + printf(_(" -P, --new-port=PORT new cluster port number (default %d)\n"), new_cluster.port); + printf(_(" -r, --retain retain SQL and log files after success\n")); + printf(_(" -U, --username=NAME cluster superuser (default \"%s\")\n"), os_info.user); + printf(_(" -v, --verbose enable verbose internal logging\n")); + printf(_(" -V, --version display version information, then exit\n")); + printf(_(" -?, --help show this help, then exit\n")); + printf(_("\n" + "Before running pg_upgrade you must:\n" + " create a new database cluster (using the new version of initdb)\n" + " shutdown the postmaster servicing the old cluster\n" + " shutdown the postmaster servicing the new cluster\n")); + printf(_("\n" + "When you run pg_upgrade, you must provide the following information:\n" + " the data directory for the old cluster (-d DATADIR)\n" + " the data directory for the new cluster (-D DATADIR)\n" + " the \"bin\" directory for the old version (-b BINDIR)\n" + " the \"bin\" directory for the new version (-B BINDIR)\n")); + printf(_("\n" + "For example:\n" + " pg_upgrade -d oldCluster/data -D newCluster/data -b oldCluster/bin -B newCluster/bin\n" + "or\n")); #ifndef WIN32 - printf(_("\ - $ export PGDATAOLD=oldCluster/data\n\ - $ export PGDATANEW=newCluster/data\n\ - $ export PGBINOLD=oldCluster/bin\n\ - $ export PGBINNEW=newCluster/bin\n\ - $ pg_upgrade\n")); + printf(_(" $ export PGDATAOLD=oldCluster/data\n" + " $ export PGDATANEW=newCluster/data\n" + " $ export PGBINOLD=oldCluster/bin\n" + " $ export PGBINNEW=newCluster/bin\n" + " $ pg_upgrade\n")); #else - printf(_("\ - C:\\> set PGDATAOLD=oldCluster/data\n\ - C:\\> set PGDATANEW=newCluster/data\n\ - C:\\> set PGBINOLD=oldCluster/bin\n\ - C:\\> set PGBINNEW=newCluster/bin\n\ - C:\\> pg_upgrade\n")); + printf(_(" C:\\> set PGDATAOLD=oldCluster/data\n" + " C:\\> set PGDATANEW=newCluster/data\n" + " C:\\> set PGBINOLD=oldCluster/bin\n" + " C:\\> set PGBINNEW=newCluster/bin\n" + " C:\\> pg_upgrade\n")); #endif printf(_("\nReport bugs to .\n")); } @@ -422,8 +419,8 @@ adjust_data_dir(ClusterInfo *cluster) if ((output = popen(cmd, "r")) == NULL || fgets(cmd_output, sizeof(cmd_output), output) == NULL) - pg_fatal("Could not get data directory using %s: %s\n", - cmd, getErrorText()); + pg_fatal("could not get data directory using %s: %s\n", + cmd, strerror(errno)); pclose(output); diff --git a/src/bin/pg_upgrade/parallel.c b/src/bin/pg_upgrade/parallel.c index 9ed55c0598..d35015f52a 100644 --- a/src/bin/pg_upgrade/parallel.c +++ b/src/bin/pg_upgrade/parallel.c @@ -3,7 +3,7 @@ * * multi-process support * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * src/bin/pg_upgrade/parallel.c */ diff --git a/src/bin/pg_upgrade/pg_upgrade.c b/src/bin/pg_upgrade/pg_upgrade.c index fa118e9e4f..797e36d253 100644 --- a/src/bin/pg_upgrade/pg_upgrade.c +++ b/src/bin/pg_upgrade/pg_upgrade.c @@ -3,7 +3,7 @@ * * main source file * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * src/bin/pg_upgrade/pg_upgrade.c */ @@ -75,6 +75,7 @@ main(int argc, char **argv) char *deletion_script_file_name = NULL; bool live_check = false; + set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_upgrade")); parseCommandLine(argc, argv); get_restricted_token(os_info.progname); @@ -225,7 +226,7 @@ setup(char *argv0, bool *live_check) /* get path to pg_upgrade executable */ if (find_my_exec(argv0, exec_path) < 0) - pg_fatal("Could not get path name to pg_upgrade: %s\n", getErrorText()); + pg_fatal("%s: could not find own program executable\n", argv0); /* Trim off program name and keep just path */ *last_dir_separator(exec_path) = '\0'; diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h index 20f9a91087..42e7aebb01 100644 --- a/src/bin/pg_upgrade/pg_upgrade.h +++ b/src/bin/pg_upgrade/pg_upgrade.h @@ -1,7 +1,7 @@ /* * pg_upgrade.h * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * src/bin/pg_upgrade/pg_upgrade.h */ @@ -367,10 +367,12 @@ bool pid_lock_file_exists(const char *datadir); /* file.c */ -const char *copyFile(const char *src, const char *dst); -const char *linkFile(const char *src, const char *dst); -const char *rewriteVisibilityMap(const char *fromfile, const char *tofile); - +void copyFile(const char *src, const char *dst, + const char *schemaName, const char *relName); +void linkFile(const char *src, const char *dst, + const char *schemaName, const char *relName); +void rewriteVisibilityMap(const char *fromfile, const char *tofile, + const char *schemaName, const char *relName); void check_hard_link(void); FILE *fopen_priv(const char *path, const char *mode); @@ -431,7 +433,6 @@ void pg_fatal(const char *fmt,...) pg_attribute_printf(1, 2) pg_attribute_noret void end_progress_output(void); void prep_status(const char *fmt,...) pg_attribute_printf(1, 2); void check_ok(void); -const char *getErrorText(void); unsigned int str2uint(const char *str); void pg_putenv(const char *var, const char *val); diff --git a/src/bin/pg_upgrade/relfilenode.c b/src/bin/pg_upgrade/relfilenode.c index 85cb717f74..06d3ed04a7 100644 --- a/src/bin/pg_upgrade/relfilenode.c +++ b/src/bin/pg_upgrade/relfilenode.c @@ -3,7 +3,7 @@ * * relfilenode functions * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * src/bin/pg_upgrade/relfilenode.c */ @@ -30,8 +30,10 @@ void transfer_all_new_tablespaces(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr, char *old_pgdata, char *new_pgdata) { - pg_log(PG_REPORT, "%s user relation files\n", - user_opts.transfer_mode == TRANSFER_MODE_LINK ? "Linking" : "Copying"); + if (user_opts.transfer_mode == TRANSFER_MODE_LINK) + pg_log(PG_REPORT, "Linking user relation files\n"); + else + pg_log(PG_REPORT, "Copying user relation files\n"); /* * Transferring files by tablespace is tricky because a single database @@ -183,7 +185,6 @@ transfer_single_new_db(FileNameMap *maps, int size, char *old_tablespace) static void transfer_relfile(FileNameMap *map, const char *type_suffix, bool vm_must_add_frozenbit) { - const char *msg; char old_file[MAXPGPATH]; char new_file[MAXPGPATH]; int segno; @@ -229,7 +230,7 @@ transfer_relfile(FileNameMap *map, const char *type_suffix, bool vm_must_add_fro else pg_fatal("error while checking for file existence \"%s.%s\" (\"%s\" to \"%s\"): %s\n", map->nspname, map->relname, old_file, new_file, - getErrorText()); + strerror(errno)); } /* If file is empty, just return */ @@ -242,35 +243,24 @@ transfer_relfile(FileNameMap *map, const char *type_suffix, bool vm_must_add_fro /* Copying files might take some time, so give feedback. */ pg_log(PG_STATUS, "%s", old_file); - if (user_opts.transfer_mode == TRANSFER_MODE_COPY) + if (vm_must_add_frozenbit && strcmp(type_suffix, "_vm") == 0) { - pg_log(PG_VERBOSE, "copying \"%s\" to \"%s\"\n", old_file, new_file); - - /* Rewrite visibility map if needed */ - if (vm_must_add_frozenbit && (strcmp(type_suffix, "_vm") == 0)) - msg = rewriteVisibilityMap(old_file, new_file); - else - msg = copyFile(old_file, new_file); - - if (msg) - pg_fatal("error while copying relation \"%s.%s\" (\"%s\" to \"%s\"): %s\n", - map->nspname, map->relname, old_file, new_file, msg); + /* Need to rewrite visibility map format */ + pg_log(PG_VERBOSE, "rewriting \"%s\" to \"%s\"\n", + old_file, new_file); + rewriteVisibilityMap(old_file, new_file, map->nspname, map->relname); + } + else if (user_opts.transfer_mode == TRANSFER_MODE_COPY) + { + pg_log(PG_VERBOSE, "copying \"%s\" to \"%s\"\n", + old_file, new_file); + copyFile(old_file, new_file, map->nspname, map->relname); } else { - pg_log(PG_VERBOSE, "linking \"%s\" to \"%s\"\n", old_file, new_file); - - /* Rewrite visibility map if needed */ - if (vm_must_add_frozenbit && (strcmp(type_suffix, "_vm") == 0)) - msg = rewriteVisibilityMap(old_file, new_file); - else - msg = linkFile(old_file, new_file); - - if (msg) - pg_fatal("error while creating link for relation \"%s.%s\" (\"%s\" to \"%s\"): %s\n", - map->nspname, map->relname, old_file, new_file, msg); + pg_log(PG_VERBOSE, "linking \"%s\" to \"%s\"\n", + old_file, new_file); + linkFile(old_file, new_file, map->nspname, map->relname); } } - - return; } diff --git a/src/bin/pg_upgrade/server.c b/src/bin/pg_upgrade/server.c index 830335f501..87a98983e2 100644 --- a/src/bin/pg_upgrade/server.c +++ b/src/bin/pg_upgrade/server.c @@ -3,7 +3,7 @@ * * database server functions * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * src/bin/pg_upgrade/server.c */ @@ -36,7 +36,7 @@ connectToServer(ClusterInfo *cluster, const char *db_name) if (conn) PQfinish(conn); - printf("Failure, exiting\n"); + printf(_("Failure, exiting\n")); exit(1); } @@ -136,7 +136,7 @@ executeQueryOrDie(PGconn *conn, const char *fmt,...) PQerrorMessage(conn)); PQclear(result); PQfinish(conn); - printf("Failure, exiting\n"); + printf(_("Failure, exiting\n")); exit(1); } else @@ -166,7 +166,7 @@ get_major_server_version(ClusterInfo *cluster) if (fscanf(version_fd, "%63s", cluster->major_version_str) == 0 || sscanf(cluster->major_version_str, "%d.%d", &integer_version, - &fractional_version) != 2) + &fractional_version) < 1) pg_fatal("could not get version from %s\n", cluster->pgdata); fclose(version_fd); @@ -320,7 +320,7 @@ stop_postmaster(bool fast) "\"%s/pg_ctl\" -w -D \"%s\" -o \"%s\" %s stop", cluster->bindir, cluster->pgconfig, cluster->pgopts ? cluster->pgopts : "", - fast ? "-m fast" : ""); + fast ? "-m fast" : "-m smart"); os_info.running_cluster = NULL; } diff --git a/src/bin/pg_upgrade/tablespace.c b/src/bin/pg_upgrade/tablespace.c index dfbce59ca3..24f7bd960c 100644 --- a/src/bin/pg_upgrade/tablespace.c +++ b/src/bin/pg_upgrade/tablespace.c @@ -3,7 +3,7 @@ * * tablespace functions * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * src/bin/pg_upgrade/tablespace.c */ @@ -90,8 +90,8 @@ get_tablespace_paths(void) os_info.old_tablespaces[tblnum]); else report_status(PG_FATAL, - "cannot stat() tablespace directory \"%s\": %s\n", - os_info.old_tablespaces[tblnum], getErrorText()); + "could not stat tablespace directory \"%s\": %s\n", + os_info.old_tablespaces[tblnum], strerror(errno)); } if (!S_ISDIR(statBuf.st_mode)) report_status(PG_FATAL, diff --git a/src/bin/pg_upgrade/test.sh b/src/bin/pg_upgrade/test.sh index d417932301..cbc5259550 100644 --- a/src/bin/pg_upgrade/test.sh +++ b/src/bin/pg_upgrade/test.sh @@ -6,7 +6,7 @@ # runs the regression tests (to put in some data), runs pg_dumpall, # runs pg_upgrade, runs pg_dumpall again, compares the dumps. # -# Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California set -e @@ -83,6 +83,8 @@ if [ "$1" = '--install' ]; then export DYLD_LIBRARY_PATH LIBPATH=$libdir:$LIBPATH export LIBPATH + SHLIB_PATH=$libdir:$SHLIB_PATH + export SHLIB_PATH PATH=$libdir:$PATH # We need to make it use psql from our temporary installation, diff --git a/src/bin/pg_upgrade/util.c b/src/bin/pg_upgrade/util.c index 5b24ec0917..44c1bc880e 100644 --- a/src/bin/pg_upgrade/util.c +++ b/src/bin/pg_upgrade/util.c @@ -3,7 +3,7 @@ * * utility functions * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * src/bin/pg_upgrade/util.c */ @@ -89,7 +89,7 @@ pg_log_v(eLogType type, const char *fmt, va_list ap) { char message[QUERY_ALLOC]; - vsnprintf(message, sizeof(message), fmt, ap); + vsnprintf(message, sizeof(message), _(fmt), ap); /* PG_VERBOSE and PG_STATUS are only output in verbose mode */ /* fopen() on log_opts.internal might have failed, so check it */ @@ -108,7 +108,7 @@ pg_log_v(eLogType type, const char *fmt, va_list ap) { case PG_VERBOSE: if (log_opts.verbose) - printf("%s", _(message)); + printf("%s", message); break; case PG_STATUS: @@ -123,17 +123,17 @@ pg_log_v(eLogType type, const char *fmt, va_list ap) strlen(message) <= MESSAGE_WIDTH - 2 ? message : message + strlen(message) - MESSAGE_WIDTH + 3 + 2); else - printf(" %s\n", _(message)); + printf(" %s\n", message); break; case PG_REPORT: case PG_WARNING: - printf("%s", _(message)); + printf("%s", message); break; case PG_FATAL: - printf("\n%s", _(message)); - printf("Failure, exiting\n"); + printf("\n%s", message); + printf(_("Failure, exiting\n")); exit(1); break; @@ -163,7 +163,7 @@ pg_fatal(const char *fmt,...) va_start(args, fmt); pg_log_v(PG_FATAL, fmt, args); va_end(args); - printf("Failure, exiting\n"); + printf(_("Failure, exiting\n")); exit(1); } @@ -232,21 +232,6 @@ get_user_info(char **user_name_p) } -/* - * getErrorText() - * - * Returns the text of the most recent error - */ -const char * -getErrorText(void) -{ -#ifdef WIN32 - _dosmaperr(GetLastError()); -#endif - return pg_strdup(strerror(errno)); -} - - /* * str2uint() * diff --git a/src/bin/pg_upgrade/version.c b/src/bin/pg_upgrade/version.c index 36c299c101..fb56feabd9 100644 --- a/src/bin/pg_upgrade/version.c +++ b/src/bin/pg_upgrade/version.c @@ -3,7 +3,7 @@ * * Postgres-version-specific routines * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * src/bin/pg_upgrade/version.c */ @@ -52,7 +52,8 @@ new_9_0_populate_pg_largeobject_metadata(ClusterInfo *cluster, bool check_mode) PQExpBufferData connectbuf; if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL) - pg_fatal("could not open file \"%s\": %s\n", output_path, getErrorText()); + pg_fatal("could not open file \"%s\": %s\n", output_path, + strerror(errno)); initPQExpBuffer(&connectbuf); appendPsqlMetaConnect(&connectbuf, active_db->db_name); @@ -150,7 +151,8 @@ old_9_3_check_for_line_data_type_usage(ClusterInfo *cluster) { found = true; if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL) - pg_fatal("could not open file \"%s\": %s\n", output_path, getErrorText()); + pg_fatal("could not open file \"%s\": %s\n", output_path, + strerror(errno)); if (!db_used) { fprintf(script, "Database: %s\n", active_db->db_name); diff --git a/src/bin/pg_xlogdump/compat.c b/src/bin/pg_xlogdump/compat.c index 845c2e5234..ff5acdc830 100644 --- a/src/bin/pg_xlogdump/compat.c +++ b/src/bin/pg_xlogdump/compat.c @@ -3,7 +3,7 @@ * compat.c * Reimplementations of various backend functions. * - * Portions Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2013-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/pg_xlogdump/compat.c diff --git a/src/bin/pg_xlogdump/nls.mk b/src/bin/pg_xlogdump/nls.mk new file mode 100644 index 0000000000..2b254c35c6 --- /dev/null +++ b/src/bin/pg_xlogdump/nls.mk @@ -0,0 +1,6 @@ +# src/bin/pg_xlogdump/nls.mk +CATALOG_NAME = pg_xlogdump +AVAIL_LANGUAGES = +GETTEXT_FILES = pg_xlogdump.c +GETTEXT_TRIGGERS = fatal_error +GETTEXT_FLAGS = fatal_error:1:c-format diff --git a/src/bin/pg_xlogdump/pg_xlogdump.c b/src/bin/pg_xlogdump/pg_xlogdump.c index 02575eb1c5..590d2ad587 100644 --- a/src/bin/pg_xlogdump/pg_xlogdump.c +++ b/src/bin/pg_xlogdump/pg_xlogdump.c @@ -2,7 +2,7 @@ * * pg_xlogdump.c - decode and display WAL * - * Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Copyright (c) 2013-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/pg_xlogdump/pg_xlogdump.c @@ -79,9 +79,9 @@ fatal_error(const char *fmt,...) fflush(stdout); - fprintf(stderr, "%s: FATAL: ", progname); + fprintf(stderr, _("%s: FATAL: "), progname); va_start(args, fmt); - vfprintf(stderr, fmt, args); + vfprintf(stderr, _(fmt), args); va_end(args); fputc('\n', stderr); @@ -249,6 +249,7 @@ XLogDumpXLogRead(const char *directory, TimeLineID timeline_id, if (sendFile < 0 || !XLByteInSeg(recptr, sendSegNo)) { char fname[MAXFNAMELEN]; + int tries; /* Switch to another logfile segment */ if (sendFile >= 0) @@ -258,7 +259,30 @@ XLogDumpXLogRead(const char *directory, TimeLineID timeline_id, XLogFileName(fname, timeline_id, sendSegNo); - sendFile = fuzzy_open_file(directory, fname); + /* + * In follow mode there is a short period of time after the + * server has written the end of the previous file before the + * new file is available. So we loop for 5 seconds looking + * for the file to appear before giving up. + */ + for (tries = 0; tries < 10; tries++) + { + sendFile = fuzzy_open_file(directory, fname); + if (sendFile >= 0) + break; + if (errno == ENOENT) + { + int save_errno = errno; + + /* File not there yet, try again */ + pg_usleep(500 * 1000); + + errno = save_errno; + continue; + } + /* Any other error, fall through and fail */ + break; + } if (sendFile < 0) fatal_error("could not find file \"%s\": %s", @@ -646,27 +670,28 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats) static void usage(void) { - printf("%s decodes and displays PostgreSQL transaction logs for debugging.\n\n", + printf(_("%s decodes and displays PostgreSQL transaction logs for debugging.\n\n"), progname); - printf("Usage:\n"); - printf(" %s [OPTION]... [STARTSEG [ENDSEG]] \n", progname); - printf("\nOptions:\n"); - printf(" -b, --bkp-details output detailed information about backup blocks\n"); - printf(" -e, --end=RECPTR stop reading at log position RECPTR\n"); - printf(" -f, --follow keep retrying after reaching end of WAL\n"); - printf(" -n, --limit=N number of records to display\n"); - printf(" -p, --path=PATH directory in which to find log segment files\n"); - printf(" (default: ./pg_xlog)\n"); - printf(" -r, --rmgr=RMGR only show records generated by resource manager RMGR\n"); - printf(" use --rmgr=list to list valid resource manager names\n"); - printf(" -s, --start=RECPTR start reading at log position RECPTR\n"); - printf(" -t, --timeline=TLI timeline from which to read log records\n"); - printf(" (default: 1 or the value used in STARTSEG)\n"); - printf(" -V, --version output version information, then exit\n"); - printf(" -x, --xid=XID only show records with TransactionId XID\n"); - printf(" -z, --stats[=record] show statistics instead of records\n"); - printf(" (optionally, show per-record statistics)\n"); - printf(" -?, --help show this help, then exit\n"); + printf(_("Usage:\n")); + printf(_(" %s [OPTION]... [STARTSEG [ENDSEG]] \n"), progname); + printf(_("\nOptions:\n")); + printf(_(" -b, --bkp-details output detailed information about backup blocks\n")); + printf(_(" -e, --end=RECPTR stop reading at log position RECPTR\n")); + printf(_(" -f, --follow keep retrying after reaching end of WAL\n")); + printf(_(" -n, --limit=N number of records to display\n")); + printf(_(" -p, --path=PATH directory in which to find log segment files or a\n" + " directory with a ./pg_wal that contains such files\n" + " (default: current directory, ./pg_wal, PGDATA/pg_wal)\n")); + printf(_(" -r, --rmgr=RMGR only show records generated by resource manager RMGR\n" + " use --rmgr=list to list valid resource manager names\n")); + printf(_(" -s, --start=RECPTR start reading at log position RECPTR\n")); + printf(_(" -t, --timeline=TLI timeline from which to read log records\n" + " (default: 1 or the value used in STARTSEG)\n")); + printf(_(" -V, --version output version information, then exit\n")); + printf(_(" -x, --xid=XID only show records with TransactionId XID\n")); + printf(_(" -z, --stats[=record] show statistics instead of records\n" + " (optionally, show per-record statistics)\n")); + printf(_(" -?, --help show this help, then exit\n")); } int @@ -701,6 +726,7 @@ main(int argc, char **argv) int option; int optindex = 0; + set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_xlogdump")); progname = get_progname(argv[0]); memset(&private, 0, sizeof(XLogDumpPrivate)); @@ -724,7 +750,7 @@ main(int argc, char **argv) if (argc <= 1) { - fprintf(stderr, "%s: no arguments specified\n", progname); + fprintf(stderr, _("%s: no arguments specified\n"), progname); goto bad_argument; } @@ -739,7 +765,7 @@ main(int argc, char **argv) case 'e': if (sscanf(optarg, "%X/%X", &xlogid, &xrecoff) != 2) { - fprintf(stderr, "%s: could not parse end log position \"%s\"\n", + fprintf(stderr, _("%s: could not parse end log position \"%s\"\n"), progname, optarg); goto bad_argument; } @@ -755,7 +781,7 @@ main(int argc, char **argv) case 'n': if (sscanf(optarg, "%d", &config.stop_after_records) != 1) { - fprintf(stderr, "%s: could not parse limit \"%s\"\n", + fprintf(stderr, _("%s: could not parse limit \"%s\"\n"), progname, optarg); goto bad_argument; } @@ -784,7 +810,7 @@ main(int argc, char **argv) if (config.filter_by_rmgr == -1) { - fprintf(stderr, "%s: resource manager \"%s\" does not exist\n", + fprintf(stderr, _("%s: resource manager \"%s\" does not exist\n"), progname, optarg); goto bad_argument; } @@ -793,7 +819,7 @@ main(int argc, char **argv) case 's': if (sscanf(optarg, "%X/%X", &xlogid, &xrecoff) != 2) { - fprintf(stderr, "%s: could not parse start log position \"%s\"\n", + fprintf(stderr, _("%s: could not parse start log position \"%s\"\n"), progname, optarg); goto bad_argument; } @@ -803,7 +829,7 @@ main(int argc, char **argv) case 't': if (sscanf(optarg, "%d", &private.timeline) != 1) { - fprintf(stderr, "%s: could not parse timeline \"%s\"\n", + fprintf(stderr, _("%s: could not parse timeline \"%s\"\n"), progname, optarg); goto bad_argument; } @@ -815,7 +841,7 @@ main(int argc, char **argv) case 'x': if (sscanf(optarg, "%u", &config.filter_by_xid) != 1) { - fprintf(stderr, "%s: could not parse \"%s\" as a valid xid\n", + fprintf(stderr, _("%s: could not parse \"%s\" as a valid xid\n"), progname, optarg); goto bad_argument; } @@ -830,7 +856,7 @@ main(int argc, char **argv) config.stats_per_record = true; else if (strcmp(optarg, "rmgr") != 0) { - fprintf(stderr, "%s: unrecognised argument to --stats: %s\n", + fprintf(stderr, _("%s: unrecognised argument to --stats: %s\n"), progname, optarg); goto bad_argument; } @@ -844,7 +870,7 @@ main(int argc, char **argv) if ((optind + 2) < argc) { fprintf(stderr, - "%s: too many command-line arguments (first is \"%s\")\n", + _("%s: too many command-line arguments (first is \"%s\")\n"), progname, argv[optind + 2]); goto bad_argument; } @@ -855,7 +881,7 @@ main(int argc, char **argv) if (!verify_directory(private.inpath)) { fprintf(stderr, - "%s: path \"%s\" cannot be opened: %s\n", + _("%s: path \"%s\" cannot be opened: %s\n"), progname, private.inpath, strerror(errno)); goto bad_argument; } @@ -893,7 +919,7 @@ main(int argc, char **argv) else if (!XLByteInSeg(private.startptr, segno)) { fprintf(stderr, - "%s: start log position %X/%X is not inside file \"%s\"\n", + _("%s: start log position %X/%X is not inside file \"%s\"\n"), progname, (uint32) (private.startptr >> 32), (uint32) private.startptr, @@ -937,7 +963,7 @@ main(int argc, char **argv) private.endptr != (segno + 1) * XLogSegSize) { fprintf(stderr, - "%s: end log position %X/%X is not inside file \"%s\"\n", + _("%s: end log position %X/%X is not inside file \"%s\"\n"), progname, (uint32) (private.endptr >> 32), (uint32) private.endptr, @@ -949,7 +975,7 @@ main(int argc, char **argv) /* we don't know what to print */ if (XLogRecPtrIsInvalid(private.startptr)) { - fprintf(stderr, "%s: no start log position given.\n", progname); + fprintf(stderr, _("%s: no start log position given.\n"), progname); goto bad_argument; } @@ -974,7 +1000,7 @@ main(int argc, char **argv) * a segment (e.g. we were used in file mode). */ if (first_record != private.startptr && (private.startptr % XLogSegSize) != 0) - printf("first record is after %X/%X, at %X/%X, skipping over %u bytes\n", + printf(_("first record is after %X/%X, at %X/%X, skipping over %u bytes\n"), (uint32) (private.startptr >> 32), (uint32) private.startptr, (uint32) (first_record >> 32), (uint32) first_record, (uint32) (first_record - private.startptr)); @@ -1033,6 +1059,6 @@ main(int argc, char **argv) return EXIT_SUCCESS; bad_argument: - fprintf(stderr, "Try \"%s --help\" for more information.\n", progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); return EXIT_FAILURE; } diff --git a/src/bin/pg_xlogdump/rmgrdesc.c b/src/bin/pg_xlogdump/rmgrdesc.c index 017b9c5b34..8fe20ce97e 100644 --- a/src/bin/pg_xlogdump/rmgrdesc.c +++ b/src/bin/pg_xlogdump/rmgrdesc.c @@ -14,7 +14,7 @@ #include "access/generic_xlog.h" #include "access/gin.h" #include "access/gist_private.h" -#include "access/hash.h" +#include "access/hash_xlog.h" #include "access/heapam_xlog.h" #include "access/multixact.h" #include "access/nbtree.h" diff --git a/src/bin/pgbench/exprparse.y b/src/bin/pgbench/exprparse.y index 0cc665b75b..b3a2d9bfd3 100644 --- a/src/bin/pgbench/exprparse.y +++ b/src/bin/pgbench/exprparse.y @@ -4,7 +4,7 @@ * exprparse.y * bison grammar for a simple expression syntax * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/pgbench/exprparse.y diff --git a/src/bin/pgbench/exprscan.l b/src/bin/pgbench/exprscan.l index 20891a3b22..dc1367bbdb 100644 --- a/src/bin/pgbench/exprscan.l +++ b/src/bin/pgbench/exprscan.l @@ -15,7 +15,7 @@ * * Note that this lexer operates within the framework created by psqlscan.l, * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/pgbench/exprscan.l @@ -66,6 +66,9 @@ space [ \t\r\f\v] nonspace [^ \t\r\f\v\n] newline [\n] +/* Line continuation marker */ +continuation \\{newline} + /* Exclusive states */ %x EXPR @@ -96,8 +99,20 @@ newline [\n] return 1; } + /* + * We need this rule to avoid returning "word\" instead of recognizing + * a continuation marker just after a word: + */ +{nonspace}+{continuation} { + /* Found "word\\\n", emit and return just "word" */ + psqlscan_emit(cur_state, yytext, yyleng - 2); + return 1; + } + {space}+ { /* ignore */ } +{continuation} { /* ignore */ } + {newline} { /* report end of command */ last_was_newline = true; @@ -138,14 +153,16 @@ newline [\n] return FUNCTION; } +{space}+ { /* ignore */ } + +{continuation} { /* ignore */ } + {newline} { /* report end of command */ last_was_newline = true; return 0; } -{space}+ { /* ignore */ } - . { /* * must strdup yytext so that expr_yyerror_more doesn't diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index 87fb006d87..f6cb5d4b10 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -5,7 +5,7 @@ * Originally written by Tatsuo Ishii and enhanced by many contributors. * * src/bin/pgbench/pgbench.c - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * ALL RIGHTS RESERVED; * * Permission to use, copy, modify, and distribute this software and its @@ -42,6 +42,7 @@ #include #include #include +#include #include #ifdef HAVE_SYS_SELECT_H #include @@ -180,6 +181,7 @@ char *pghost = ""; char *pgport = ""; char *login = NULL; char *dbName; +char *logfile_prefix = NULL; const char *progname; #define WSEP '@' /* weight separator */ @@ -226,7 +228,7 @@ typedef struct SimpleStats */ typedef struct StatsData { - long start_time; /* interval start time, for aggregates */ + time_t start_time; /* interval start time, for aggregates */ int64 cnt; /* number of transactions */ int64 skipped; /* number of transactions skipped under --rate * and --latency-limit */ @@ -235,24 +237,95 @@ typedef struct StatsData } StatsData; /* - * Connection state + * Connection state machine states. + */ +typedef enum +{ + /* + * The client must first choose a script to execute. Once chosen, it can + * either be throttled (state CSTATE_START_THROTTLE under --rate) or start + * right away (state CSTATE_START_TX). + */ + CSTATE_CHOOSE_SCRIPT, + + /* + * In CSTATE_START_THROTTLE state, we calculate when to begin the next + * transaction, and advance to CSTATE_THROTTLE. CSTATE_THROTTLE state + * sleeps until that moment. (If throttling is not enabled, doCustom() + * falls directly through from CSTATE_START_THROTTLE to CSTATE_START_TX.) + */ + CSTATE_START_THROTTLE, + CSTATE_THROTTLE, + + /* + * CSTATE_START_TX performs start-of-transaction processing. Establishes + * a new connection for the transaction, in --connect mode, and records + * the transaction start time. + */ + CSTATE_START_TX, + + /* + * We loop through these states, to process each command in the script: + * + * CSTATE_START_COMMAND starts the execution of a command. On a SQL + * command, the command is sent to the server, and we move to + * CSTATE_WAIT_RESULT state. On a \sleep meta-command, the timer is set, + * and we enter the CSTATE_SLEEP state to wait for it to expire. Other + * meta-commands are executed immediately. + * + * CSTATE_WAIT_RESULT waits until we get a result set back from the server + * for the current command. + * + * CSTATE_SLEEP waits until the end of \sleep. + * + * CSTATE_END_COMMAND records the end-of-command timestamp, increments the + * command counter, and loops back to CSTATE_START_COMMAND state. + */ + CSTATE_START_COMMAND, + CSTATE_WAIT_RESULT, + CSTATE_SLEEP, + CSTATE_END_COMMAND, + + /* + * CSTATE_END_TX performs end-of-transaction processing. Calculates + * latency, and logs the transaction. In --connect mode, closes the + * current connection. Chooses the next script to execute and starts over + * in CSTATE_START_THROTTLE state, or enters CSTATE_FINISHED if we have no + * more work to do. + */ + CSTATE_END_TX, + + /* + * Final states. CSTATE_ABORTED means that the script execution was + * aborted because a command failed, CSTATE_FINISHED means success. + */ + CSTATE_ABORTED, + CSTATE_FINISHED +} ConnectionStateEnum; + +/* + * Connection state. */ typedef struct { PGconn *con; /* connection handle to DB */ int id; /* client No. */ - int state; /* state No. */ - bool listen; /* whether an async query has been sent */ - bool sleeping; /* whether the client is napping */ - bool throttling; /* whether nap is for throttling */ - bool is_throttled; /* whether transaction throttling is done */ + ConnectionStateEnum state; /* state machine's current state. */ + + int use_file; /* index in sql_script for this client */ + int command; /* command number in script */ + + /* client variables */ Variable *variables; /* array of variable definitions */ int nvariables; /* number of variables */ bool vars_sorted; /* are variables sorted by name? */ + + /* various times about current transaction */ int64 txn_scheduled; /* scheduled start time of transaction (usec) */ + int64 sleep_until; /* scheduled start time of next cmd (usec) */ instr_time txn_begin; /* used for measuring schedule lag times */ instr_time stmt_begin; /* used for measuring statement latencies */ - int use_file; /* index in sql_scripts for this client */ + bool prepared[MAX_SCRIPTS]; /* whether client prepared the script */ /* per client collected stats */ @@ -377,7 +450,7 @@ static const BuiltinScript builtin_script[] = static void setIntValue(PgBenchValue *pv, int64 ival); static void setDoubleValue(PgBenchValue *pv, double dval); static bool evaluateExpr(TState *, CState *, PgBenchExpr *, PgBenchValue *); -static void doLog(TState *thread, CState *st, instr_time *now, +static void doLog(TState *thread, CState *st, StatsData *agg, bool skipped, double latency, double lag); static void processXactStats(TState *thread, CState *st, instr_time *now, bool skipped, StatsData *agg); @@ -440,6 +513,8 @@ usage(void) " --aggregate-interval=NUM aggregate data over NUM seconds\n" " --progress-timestamp use Unix epoch timestamps for progress\n" " --sampling-rate=NUM fraction of transactions to log (e.g., 0.01 for 1%%)\n" + " --log-prefix=PREFIX prefix for transaction time log file\n" + " (default: \"pgbench_log\")\n" "\nCommon options:\n" " -d, --debug print debugging output\n" " -h, --host=HOSTNAME database server host or socket directory\n" @@ -706,7 +781,7 @@ mergeSimpleStats(SimpleStats *acc, SimpleStats *ss) * the given value. */ static void -initStats(StatsData *sd, double start_time) +initStats(StatsData *sd, time_t start_time) { sd->start_time = start_time; sd->cnt = 0; @@ -773,8 +848,9 @@ static PGconn * doConnect(void) { PGconn *conn; - static char *password = NULL; bool new_pass; + static bool have_password = false; + static char password[100]; /* * Start the connection. Loop until we have a password if requested by @@ -794,7 +870,7 @@ doConnect(void) keywords[2] = "user"; values[2] = login; keywords[3] = "password"; - values[3] = password; + values[3] = have_password ? password : NULL; keywords[4] = "dbname"; values[4] = dbName; keywords[5] = "fallback_application_name"; @@ -815,10 +891,11 @@ doConnect(void) if (PQstatus(conn) == CONNECTION_BAD && PQconnectionNeedsPassword(conn) && - password == NULL) + !have_password) { PQfinish(conn); - password = simple_prompt("Password: ", 100, false); + simple_prompt("Password: ", password, sizeof(password), false); + have_password = true; new_pass = true; } } while (new_pass); @@ -1379,7 +1456,7 @@ evalFunc(TState *thread, CState *st, Assert(nargs == 1); fprintf(stderr, "debug(script=%d,command=%d): ", - st->use_file, st->state + 1); + st->use_file, st->command + 1); if (varg->type == PGBT_INT) fprintf(stderr, "int " INT64_FORMAT "\n", varg->u.ival); @@ -1730,15 +1807,12 @@ preparedStatementName(char *buffer, int file, int state) sprintf(buffer, "P%d_%d", file, state); } -static bool -clientDone(CState *st) +static void +commandFailed(CState *st, char *message) { - if (st->con != NULL) - { - PQfinish(st->con); - st->con = NULL; - } - return false; /* always false */ + fprintf(stderr, + "client %d aborted in command %d of script %d; %s\n", + st->id, st->command, st->use_file, message); } /* return a script number with a weighted choice. */ @@ -1760,430 +1834,607 @@ chooseScript(TState *thread) return i - 1; } -/* return false iff client should be disconnected */ +/* Send a SQL command, using the chosen querymode */ static bool -doCustom(TState *thread, CState *st, StatsData *agg) +sendCommand(CState *st, Command *command) { - PGresult *res; - Command **commands; - bool trans_needs_throttle = false; - instr_time now; + int r; - /* - * gettimeofday() isn't free, so we get the current timestamp lazily the - * first time it's needed, and reuse the same value throughout this - * function after that. This also ensures that e.g. the calculated latency - * reported in the log file and in the totals are the same. Zero means - * "not set yet". Reset "now" when we step to the next command with "goto - * top", though. - */ -top: - INSTR_TIME_SET_ZERO(now); + if (querymode == QUERY_SIMPLE) + { + char *sql; - commands = sql_script[st->use_file].commands; + sql = pg_strdup(command->argv[0]); + sql = assignVariables(st, sql); - /* - * Handle throttling once per transaction by sleeping. It is simpler to - * do this here rather than at the end, because so much complicated logic - * happens below when statements finish. - */ - if (throttle_delay && !st->is_throttled) + if (debug) + fprintf(stderr, "client %d sending %s\n", st->id, sql); + r = PQsendQuery(st->con, sql); + free(sql); + } + else if (querymode == QUERY_EXTENDED) { - /* - * Generate a delay such that the series of delays will approximate a - * Poisson distribution centered on the throttle_delay time. - * - * If transactions are too slow or a given wait is shorter than a - * transaction, the next transaction will start right away. - */ - int64 wait = getPoissonRand(thread, throttle_delay); + const char *sql = command->argv[0]; + const char *params[MAX_ARGS]; - thread->throttle_trigger += wait; - st->txn_scheduled = thread->throttle_trigger; + getQueryParams(st, command, params); - /* stop client if next transaction is beyond pgbench end of execution */ - if (duration > 0 && st->txn_scheduled > end_time) - return clientDone(st); + if (debug) + fprintf(stderr, "client %d sending %s\n", st->id, sql); + r = PQsendQueryParams(st->con, sql, command->argc - 1, + NULL, params, NULL, NULL, 0); + } + else if (querymode == QUERY_PREPARED) + { + char name[MAX_PREPARE_NAME]; + const char *params[MAX_ARGS]; - /* - * If this --latency-limit is used, and this slot is already late so - * that the transaction will miss the latency limit even if it - * completed immediately, we skip this time slot and iterate till the - * next slot that isn't late yet. - */ - if (latency_limit) + if (!st->prepared[st->use_file]) { - int64 now_us; + int j; + Command **commands = sql_script[st->use_file].commands; - if (INSTR_TIME_IS_ZERO(now)) - INSTR_TIME_SET_CURRENT(now); - now_us = INSTR_TIME_GET_MICROSEC(now); - while (thread->throttle_trigger < now_us - latency_limit) + for (j = 0; commands[j] != NULL; j++) { - processXactStats(thread, st, &now, true, agg); - /* next rendez-vous */ - wait = getPoissonRand(thread, throttle_delay); - thread->throttle_trigger += wait; - st->txn_scheduled = thread->throttle_trigger; + PGresult *res; + char name[MAX_PREPARE_NAME]; + + if (commands[j]->type != SQL_COMMAND) + continue; + preparedStatementName(name, st->use_file, j); + res = PQprepare(st->con, name, + commands[j]->argv[0], commands[j]->argc - 1, NULL); + if (PQresultStatus(res) != PGRES_COMMAND_OK) + fprintf(stderr, "%s", PQerrorMessage(st->con)); + PQclear(res); } + st->prepared[st->use_file] = true; } - st->sleeping = true; - st->throttling = true; - st->is_throttled = true; + getQueryParams(st, command, params); + preparedStatementName(name, st->use_file, st->command); + if (debug) - fprintf(stderr, "client %d throttling " INT64_FORMAT " us\n", - st->id, wait); + fprintf(stderr, "client %d sending %s\n", st->id, name); + r = PQsendQueryPrepared(st->con, name, command->argc - 1, + params, NULL, NULL, 0); } + else /* unknown sql mode */ + r = 0; - if (st->sleeping) - { /* are we sleeping? */ - if (INSTR_TIME_IS_ZERO(now)) - INSTR_TIME_SET_CURRENT(now); - if (INSTR_TIME_GET_MICROSEC(now) < st->txn_scheduled) - return true; /* Still sleeping, nothing to do here */ - /* Else done sleeping, go ahead with next command */ - st->sleeping = false; - st->throttling = false; + if (r == 0) + { + if (debug) + fprintf(stderr, "client %d could not send %s\n", + st->id, command->argv[0]); + st->ecnt++; + return false; } + else + return true; +} - if (st->listen) - { /* are we receiver? */ - if (commands[st->state]->type == SQL_COMMAND) +/* + * Parse the argument to a \sleep command, and return the requested amount + * of delay, in microseconds. Returns true on success, false on error. + */ +static bool +evaluateSleep(CState *st, int argc, char **argv, int *usecs) +{ + char *var; + int usec; + + if (*argv[1] == ':') + { + if ((var = getVariable(st, argv[1] + 1)) == NULL) { - if (debug) - fprintf(stderr, "client %d receiving\n", st->id); - if (!PQconsumeInput(st->con)) - { /* there's something wrong */ - fprintf(stderr, "client %d aborted in state %d; perhaps the backend died while processing\n", st->id, st->state); - return clientDone(st); - } - if (PQisBusy(st->con)) - return true; /* don't have the whole result yet */ + fprintf(stderr, "%s: undefined variable \"%s\"\n", + argv[0], argv[1]); + return false; } + usec = atoi(var); + } + else + usec = atoi(argv[1]); - /* - * command finished: accumulate per-command execution times in - * thread-local data structure, if per-command latencies are requested - */ - if (is_latencies) - { - if (INSTR_TIME_IS_ZERO(now)) - INSTR_TIME_SET_CURRENT(now); + if (argc > 2) + { + if (pg_strcasecmp(argv[2], "ms") == 0) + usec *= 1000; + else if (pg_strcasecmp(argv[2], "s") == 0) + usec *= 1000000; + } + else + usec *= 1000000; - /* XXX could use a mutex here, but we choose not to */ - addToSimpleStats(&commands[st->state]->stats, - INSTR_TIME_GET_DOUBLE(now) - - INSTR_TIME_GET_DOUBLE(st->stmt_begin)); - } + *usecs = usec; + return true; +} - /* transaction finished: calculate latency and log the transaction */ - if (commands[st->state + 1] == NULL) - { - if (progress || throttle_delay || latency_limit || - per_script_stats || use_log) - processXactStats(thread, st, &now, false, agg); - else - thread->stats.cnt++; - } +/* + * Advance the state machine of a connection, if possible. + */ +static void +doCustom(TState *thread, CState *st, StatsData *agg) +{ + PGresult *res; + Command *command; + instr_time now; + bool end_tx_processed = false; + int64 wait; - if (commands[st->state]->type == SQL_COMMAND) - { - /* - * Read and discard the query result; note this is not included in - * the statement latency numbers. - */ - res = PQgetResult(st->con); - switch (PQresultStatus(res)) - { - case PGRES_COMMAND_OK: - case PGRES_TUPLES_OK: - break; /* OK */ - default: - fprintf(stderr, "client %d aborted in state %d: %s", - st->id, st->state, PQerrorMessage(st->con)); - PQclear(res); - return clientDone(st); - } - PQclear(res); - discard_response(st); - } + /* + * gettimeofday() isn't free, so we get the current timestamp lazily the + * first time it's needed, and reuse the same value throughout this + * function after that. This also ensures that e.g. the calculated + * latency reported in the log file and in the totals are the same. Zero + * means "not set yet". Reset "now" when we execute shell commands or + * expressions, which might take a non-negligible amount of time, though. + */ + INSTR_TIME_SET_ZERO(now); - if (commands[st->state + 1] == NULL) + /* + * Loop in the state machine, until we have to wait for a result from the + * server (or have to sleep, for throttling or for \sleep). + * + * Note: In the switch-statement below, 'break' will loop back here, + * meaning "continue in the state machine". Return is used to return to + * the caller. + */ + for (;;) + { + switch (st->state) { - if (is_connect) - { - PQfinish(st->con); - st->con = NULL; - } + /* + * Select transaction to run. + */ + case CSTATE_CHOOSE_SCRIPT: - ++st->cnt; - if ((st->cnt >= nxacts && duration <= 0) || timer_exceeded) - return clientDone(st); /* exit success */ - } + st->use_file = chooseScript(thread); - /* increment state counter */ - st->state++; - if (commands[st->state] == NULL) - { - st->state = 0; - st->use_file = chooseScript(thread); - commands = sql_script[st->use_file].commands; - if (debug) - fprintf(stderr, "client %d executing script \"%s\"\n", st->id, - sql_script[st->use_file].desc); - st->is_throttled = false; - - /* - * No transaction is underway anymore, which means there is - * nothing to listen to right now. When throttling rate limits - * are active, a sleep will happen next, as the next transaction - * starts. And then in any case the next SQL command will set - * listen back to true. - */ - st->listen = false; - trans_needs_throttle = (throttle_delay > 0); - } - } + if (debug) + fprintf(stderr, "client %d executing script \"%s\"\n", st->id, + sql_script[st->use_file].desc); - if (st->con == NULL) - { - instr_time start, - end; + if (throttle_delay > 0) + st->state = CSTATE_START_THROTTLE; + else + st->state = CSTATE_START_TX; + break; - INSTR_TIME_SET_CURRENT(start); - if ((st->con = doConnect()) == NULL) - { - fprintf(stderr, "client %d aborted while establishing connection\n", - st->id); - return clientDone(st); - } - INSTR_TIME_SET_CURRENT(end); - INSTR_TIME_ACCUM_DIFF(thread->conn_time, end, start); - - /* Reset session-local state */ - st->listen = false; - st->sleeping = false; - st->throttling = false; - st->is_throttled = false; - memset(st->prepared, 0, sizeof(st->prepared)); - } + /* + * Handle throttling once per transaction by sleeping. + */ + case CSTATE_START_THROTTLE: - /* - * This ensures that a throttling delay is inserted before proceeding with - * sql commands, after the first transaction. The first transaction - * throttling is performed when first entering doCustom. - */ - if (trans_needs_throttle) - { - trans_needs_throttle = false; - goto top; - } + /* + * Generate a delay such that the series of delays will + * approximate a Poisson distribution centered on the + * throttle_delay time. + * + * If transactions are too slow or a given wait is shorter + * than a transaction, the next transaction will start right + * away. + */ + Assert(throttle_delay > 0); + wait = getPoissonRand(thread, throttle_delay); - /* Record transaction start time under logging, progress or throttling */ - if ((use_log || progress || throttle_delay || latency_limit || - per_script_stats) && st->state == 0) - { - INSTR_TIME_SET_CURRENT(st->txn_begin); + thread->throttle_trigger += wait; + st->txn_scheduled = thread->throttle_trigger; - /* - * When not throttling, this is also the transaction's scheduled start - * time. - */ - if (!throttle_delay) - st->txn_scheduled = INSTR_TIME_GET_MICROSEC(st->txn_begin); - } + /* + * stop client if next transaction is beyond pgbench end of + * execution + */ + if (duration > 0 && st->txn_scheduled > end_time) + { + st->state = CSTATE_FINISHED; + break; + } - /* Record statement start time if per-command latencies are requested */ - if (is_latencies) - INSTR_TIME_SET_CURRENT(st->stmt_begin); + /* + * If this --latency-limit is used, and this slot is already + * late so that the transaction will miss the latency limit + * even if it completed immediately, we skip this time slot + * and iterate till the next slot that isn't late yet. + */ + if (latency_limit) + { + int64 now_us; - if (commands[st->state]->type == SQL_COMMAND) - { - const Command *command = commands[st->state]; - int r; + if (INSTR_TIME_IS_ZERO(now)) + INSTR_TIME_SET_CURRENT(now); + now_us = INSTR_TIME_GET_MICROSEC(now); + while (thread->throttle_trigger < now_us - latency_limit) + { + processXactStats(thread, st, &now, true, agg); + /* next rendez-vous */ + wait = getPoissonRand(thread, throttle_delay); + thread->throttle_trigger += wait; + st->txn_scheduled = thread->throttle_trigger; + } + } - if (querymode == QUERY_SIMPLE) - { - char *sql; + st->state = CSTATE_THROTTLE; + if (debug) + fprintf(stderr, "client %d throttling " INT64_FORMAT " us\n", + st->id, wait); + break; - sql = pg_strdup(command->argv[0]); - sql = assignVariables(st, sql); + /* + * Wait until it's time to start next transaction. + */ + case CSTATE_THROTTLE: + if (INSTR_TIME_IS_ZERO(now)) + INSTR_TIME_SET_CURRENT(now); + if (INSTR_TIME_GET_MICROSEC(now) < st->txn_scheduled) + return; /* Still sleeping, nothing to do here */ + + /* Else done sleeping, start the transaction */ + st->state = CSTATE_START_TX; + break; - if (debug) - fprintf(stderr, "client %d sending %s\n", st->id, sql); - r = PQsendQuery(st->con, sql); - free(sql); - } - else if (querymode == QUERY_EXTENDED) - { - const char *sql = command->argv[0]; - const char *params[MAX_ARGS]; + /* Start new transaction */ + case CSTATE_START_TX: - getQueryParams(st, command, params); + /* + * Establish connection on first call, or if is_connect is + * true. + */ + if (st->con == NULL) + { + instr_time start; - if (debug) - fprintf(stderr, "client %d sending %s\n", st->id, sql); - r = PQsendQueryParams(st->con, sql, command->argc - 1, - NULL, params, NULL, NULL, 0); - } - else if (querymode == QUERY_PREPARED) - { - char name[MAX_PREPARE_NAME]; - const char *params[MAX_ARGS]; + if (INSTR_TIME_IS_ZERO(now)) + INSTR_TIME_SET_CURRENT(now); + start = now; + if ((st->con = doConnect()) == NULL) + { + fprintf(stderr, "client %d aborted while establishing connection\n", + st->id); + st->state = CSTATE_ABORTED; + break; + } + INSTR_TIME_SET_CURRENT(now); + INSTR_TIME_ACCUM_DIFF(thread->conn_time, now, start); - if (!st->prepared[st->use_file]) - { - int j; + /* Reset session-local state */ + memset(st->prepared, 0, sizeof(st->prepared)); + } - for (j = 0; commands[j] != NULL; j++) + /* + * Record transaction start time under logging, progress or + * throttling. + */ + if (use_log || progress || throttle_delay || latency_limit || + per_script_stats) { - PGresult *res; - char name[MAX_PREPARE_NAME]; + if (INSTR_TIME_IS_ZERO(now)) + INSTR_TIME_SET_CURRENT(now); + st->txn_begin = now; + + /* + * When not throttling, this is also the transaction's + * scheduled start time. + */ + if (!throttle_delay) + st->txn_scheduled = INSTR_TIME_GET_MICROSEC(now); + } - if (commands[j]->type != SQL_COMMAND) - continue; - preparedStatementName(name, st->use_file, j); - res = PQprepare(st->con, name, - commands[j]->argv[0], commands[j]->argc - 1, NULL); - if (PQresultStatus(res) != PGRES_COMMAND_OK) - fprintf(stderr, "%s", PQerrorMessage(st->con)); - PQclear(res); + /* Begin with the first command */ + st->command = 0; + st->state = CSTATE_START_COMMAND; + break; + + /* + * Send a command to server (or execute a meta-command) + */ + case CSTATE_START_COMMAND: + command = sql_script[st->use_file].commands[st->command]; + + /* + * If we reached the end of the script, move to end-of-xact + * processing. + */ + if (command == NULL) + { + st->state = CSTATE_END_TX; + break; } - st->prepared[st->use_file] = true; - } - getQueryParams(st, command, params); - preparedStatementName(name, st->use_file, st->state); + /* + * Record statement start time if per-command latencies are + * requested + */ + if (is_latencies) + { + if (INSTR_TIME_IS_ZERO(now)) + INSTR_TIME_SET_CURRENT(now); + st->stmt_begin = now; + } - if (debug) - fprintf(stderr, "client %d sending %s\n", st->id, name); - r = PQsendQueryPrepared(st->con, name, command->argc - 1, - params, NULL, NULL, 0); - } - else /* unknown sql mode */ - r = 0; + if (command->type == SQL_COMMAND) + { + if (!sendCommand(st, command)) + { + /* + * Failed. Stay in CSTATE_START_COMMAND state, to + * retry. ??? What the point or retrying? Should + * rather abort? + */ + return; + } + else + st->state = CSTATE_WAIT_RESULT; + } + else if (command->type == META_COMMAND) + { + int argc = command->argc, + i; + char **argv = command->argv; - if (r == 0) - { - if (debug) - fprintf(stderr, "client %d could not send %s\n", - st->id, command->argv[0]); - st->ecnt++; - } - else - st->listen = true; /* flags that should be listened */ - } - else if (commands[st->state]->type == META_COMMAND) - { - int argc = commands[st->state]->argc, - i; - char **argv = commands[st->state]->argv; + if (debug) + { + fprintf(stderr, "client %d executing \\%s", st->id, argv[0]); + for (i = 1; i < argc; i++) + fprintf(stderr, " %s", argv[i]); + fprintf(stderr, "\n"); + } - if (debug) - { - fprintf(stderr, "client %d executing \\%s", st->id, argv[0]); - for (i = 1; i < argc; i++) - fprintf(stderr, " %s", argv[i]); - fprintf(stderr, "\n"); - } + if (pg_strcasecmp(argv[0], "sleep") == 0) + { + /* + * A \sleep doesn't execute anything, we just get the + * delay from the argument, and enter the CSTATE_SLEEP + * state. (The per-command latency will be recorded + * in CSTATE_SLEEP state, not here, after the delay + * has elapsed.) + */ + int usec; + + if (!evaluateSleep(st, argc, argv, &usec)) + { + commandFailed(st, "execution of meta-command 'sleep' failed"); + st->state = CSTATE_ABORTED; + break; + } - if (pg_strcasecmp(argv[0], "set") == 0) - { - PgBenchExpr *expr = commands[st->state]->expr; - PgBenchValue result; + if (INSTR_TIME_IS_ZERO(now)) + INSTR_TIME_SET_CURRENT(now); + st->sleep_until = INSTR_TIME_GET_MICROSEC(now) + usec; + st->state = CSTATE_SLEEP; + break; + } + else + { + if (pg_strcasecmp(argv[0], "set") == 0) + { + PgBenchExpr *expr = command->expr; + PgBenchValue result; - if (!evaluateExpr(thread, st, expr, &result)) - { - st->ecnt++; - return true; - } + if (!evaluateExpr(thread, st, expr, &result)) + { + commandFailed(st, "evaluation of meta-command 'set' failed"); + st->state = CSTATE_ABORTED; + break; + } - if (!putVariableNumber(st, argv[0], argv[1], &result)) - { - st->ecnt++; - return true; - } + if (!putVariableNumber(st, argv[0], argv[1], &result)) + { + commandFailed(st, "assignment of meta-command 'set' failed"); + st->state = CSTATE_ABORTED; + break; + } + } + else if (pg_strcasecmp(argv[0], "setshell") == 0) + { + bool ret = runShellCommand(st, argv[1], argv + 2, argc - 2); - st->listen = true; - } - else if (pg_strcasecmp(argv[0], "sleep") == 0) - { - char *var; - int usec; - instr_time now; + if (timer_exceeded) /* timeout */ + { + st->state = CSTATE_FINISHED; + break; + } + else if (!ret) /* on error */ + { + commandFailed(st, "execution of meta-command 'setshell' failed"); + st->state = CSTATE_ABORTED; + break; + } + else + { + /* succeeded */ + } + } + else if (pg_strcasecmp(argv[0], "shell") == 0) + { + bool ret = runShellCommand(st, NULL, argv + 1, argc - 1); - if (*argv[1] == ':') - { - if ((var = getVariable(st, argv[1] + 1)) == NULL) + if (timer_exceeded) /* timeout */ + { + st->state = CSTATE_FINISHED; + break; + } + else if (!ret) /* on error */ + { + commandFailed(st, "execution of meta-command 'shell' failed"); + st->state = CSTATE_ABORTED; + break; + } + else + { + /* succeeded */ + } + } + + /* + * executing the expression or shell command might + * take a non-negligible amount of time, so reset + * 'now' + */ + INSTR_TIME_SET_ZERO(now); + + st->state = CSTATE_END_COMMAND; + } + } + break; + + /* + * Wait for the current SQL command to complete + */ + case CSTATE_WAIT_RESULT: + command = sql_script[st->use_file].commands[st->command]; + if (debug) + fprintf(stderr, "client %d receiving\n", st->id); + if (!PQconsumeInput(st->con)) + { /* there's something wrong */ + commandFailed(st, "perhaps the backend died while processing"); + st->state = CSTATE_ABORTED; + break; + } + if (PQisBusy(st->con)) + return; /* don't have the whole result yet */ + + /* + * Read and discard the query result; + */ + res = PQgetResult(st->con); + switch (PQresultStatus(res)) { - fprintf(stderr, "%s: undefined variable \"%s\"\n", - argv[0], argv[1]); - st->ecnt++; - return true; + case PGRES_COMMAND_OK: + case PGRES_TUPLES_OK: + case PGRES_EMPTY_QUERY: + /* OK */ + PQclear(res); + discard_response(st); + st->state = CSTATE_END_COMMAND; + break; + default: + commandFailed(st, PQerrorMessage(st->con)); + PQclear(res); + st->state = CSTATE_ABORTED; + break; } - usec = atoi(var); - } - else - usec = atoi(argv[1]); + break; - if (argc > 2) - { - if (pg_strcasecmp(argv[2], "ms") == 0) - usec *= 1000; - else if (pg_strcasecmp(argv[2], "s") == 0) - usec *= 1000000; - } - else - usec *= 1000000; + /* + * Wait until sleep is done. This state is entered after a + * \sleep metacommand. The behavior is similar to + * CSTATE_THROTTLE, but proceeds to CSTATE_START_COMMAND + * instead of CSTATE_START_TX. + */ + case CSTATE_SLEEP: + if (INSTR_TIME_IS_ZERO(now)) + INSTR_TIME_SET_CURRENT(now); + if (INSTR_TIME_GET_MICROSEC(now) < st->sleep_until) + return; /* Still sleeping, nothing to do here */ + /* Else done sleeping. */ + st->state = CSTATE_END_COMMAND; + break; - INSTR_TIME_SET_CURRENT(now); - st->txn_scheduled = INSTR_TIME_GET_MICROSEC(now) + usec; - st->sleeping = true; + /* + * End of command: record stats and proceed to next command. + */ + case CSTATE_END_COMMAND: - st->listen = true; - } - else if (pg_strcasecmp(argv[0], "setshell") == 0) - { - bool ret = runShellCommand(st, argv[1], argv + 2, argc - 2); + /* + * command completed: accumulate per-command execution times + * in thread-local data structure, if per-command latencies + * are requested. + */ + if (is_latencies) + { + if (INSTR_TIME_IS_ZERO(now)) + INSTR_TIME_SET_CURRENT(now); - if (timer_exceeded) /* timeout */ - return clientDone(st); - else if (!ret) /* on error */ - { - st->ecnt++; - return true; - } - else /* succeeded */ - st->listen = true; - } - else if (pg_strcasecmp(argv[0], "shell") == 0) - { - bool ret = runShellCommand(st, NULL, argv + 1, argc - 1); + /* XXX could use a mutex here, but we choose not to */ + command = sql_script[st->use_file].commands[st->command]; + addToSimpleStats(&command->stats, + INSTR_TIME_GET_DOUBLE(now) - + INSTR_TIME_GET_DOUBLE(st->stmt_begin)); + } - if (timer_exceeded) /* timeout */ - return clientDone(st); - else if (!ret) /* on error */ - { - st->ecnt++; - return true; - } - else /* succeeded */ - st->listen = true; - } + /* Go ahead with next command */ + st->command++; + st->state = CSTATE_START_COMMAND; + break; - /* after a meta command, immediately proceed with next command */ - goto top; - } + /* + * End of transaction. + */ + case CSTATE_END_TX: - return true; + /* + * transaction finished: calculate latency and log the + * transaction + */ + if (progress || throttle_delay || latency_limit || + per_script_stats || use_log) + processXactStats(thread, st, &now, false, agg); + else + thread->stats.cnt++; + + if (is_connect) + { + PQfinish(st->con); + st->con = NULL; + INSTR_TIME_SET_ZERO(now); + } + + ++st->cnt; + if ((st->cnt >= nxacts && duration <= 0) || timer_exceeded) + { + /* exit success */ + st->state = CSTATE_FINISHED; + break; + } + + /* + * No transaction is underway anymore. + */ + st->state = CSTATE_CHOOSE_SCRIPT; + + /* + * If we paced through all commands in the script in this + * loop, without returning to the caller even once, do it now. + * This gives the thread a chance to process other + * connections, and to do progress reporting. This can + * currently only happen if the script consists entirely of + * meta-commands. + */ + if (end_tx_processed) + return; + else + { + end_tx_processed = true; + break; + } + + /* + * Final states. Close the connection if it's still open. + */ + case CSTATE_ABORTED: + case CSTATE_FINISHED: + if (st->con != NULL) + { + PQfinish(st->con); + st->con = NULL; + } + return; + } + } } /* - * print log entry after completing one transaction. + * Print log entry after completing one transaction. + * + * We print Unix-epoch timestamps in the log, so that entries can be + * correlated against other logs. On some platforms this could be obtained + * from the instr_time reading the caller has, but rather than get entangled + * with that, we just eat the cost of an extra syscall in all cases. */ static void -doLog(TState *thread, CState *st, instr_time *now, +doLog(TState *thread, CState *st, StatsData *agg, bool skipped, double latency, double lag) { FILE *logfile = thread->logfile; @@ -2202,15 +2453,17 @@ doLog(TState *thread, CState *st, instr_time *now, if (agg_interval > 0) { /* - * Loop until we reach the interval of the current transaction, and - * print all the empty intervals in between (this may happen with very - * low tps, e.g. --rate=0.1). + * Loop until we reach the interval of the current moment, and print + * any empty intervals in between (this may happen with very low tps, + * e.g. --rate=0.1). */ - while (agg->start_time + agg_interval < INSTR_TIME_GET_DOUBLE(*now)) + time_t now = time(NULL); + + while (agg->start_time + agg_interval <= now) { /* print aggregated report to logfile */ fprintf(logfile, "%ld " INT64_FORMAT " %.0f %.0f %.0f %.0f", - agg->start_time, + (long) agg->start_time, agg->cnt, agg->latency.sum, agg->latency.sum2, @@ -2238,27 +2491,17 @@ doLog(TState *thread, CState *st, instr_time *now, else { /* no, print raw transactions */ -#ifndef WIN32 + struct timeval tv; - /* This is more than we really ought to know about instr_time */ + gettimeofday(&tv, NULL); if (skipped) fprintf(logfile, "%d " INT64_FORMAT " skipped %d %ld %ld", st->id, st->cnt, st->use_file, - (long) now->tv_sec, (long) now->tv_usec); + (long) tv.tv_sec, (long) tv.tv_usec); else fprintf(logfile, "%d " INT64_FORMAT " %.0f %d %ld %ld", st->id, st->cnt, latency, st->use_file, - (long) now->tv_sec, (long) now->tv_usec); -#else - - /* On Windows, instr_time doesn't provide a timestamp anyway */ - if (skipped) - fprintf(logfile, "%d " INT64_FORMAT " skipped %d 0 0", - st->id, st->cnt, st->use_file); - else - fprintf(logfile, "%d " INT64_FORMAT " %.0f %d 0 0", - st->id, st->cnt, latency, st->use_file); -#endif + (long) tv.tv_sec, (long) tv.tv_usec); if (throttle_delay) fprintf(logfile, " %.0f", lag); fputc('\n', logfile); @@ -2277,7 +2520,7 @@ processXactStats(TState *thread, CState *st, instr_time *now, double latency = 0.0, lag = 0.0; - if ((!skipped || agg_interval) && INSTR_TIME_IS_ZERO(*now)) + if ((!skipped) && INSTR_TIME_IS_ZERO(*now)) INSTR_TIME_SET_CURRENT(*now); if (!skipped) @@ -2299,7 +2542,7 @@ processXactStats(TState *thread, CState *st, instr_time *now, thread->stats.cnt++; if (use_log) - doLog(thread, st, now, agg, skipped, latency, lag); + doLog(thread, st, agg, skipped, latency, lag); /* XXX could use a mutex here, but we choose not to */ if (per_script_stats) @@ -2961,7 +3204,7 @@ ParseScript(const char *script, const char *desc, int weight) ps.desc = desc; ps.weight = weight; ps.commands = (Command **) pg_malloc(sizeof(Command *) * alloc_num); - initStats(&ps.stats, 0.0); + initStats(&ps.stats, 0); /* Prepare to parse script */ sstate = psql_scan_create(&pgbench_callbacks); @@ -3255,6 +3498,7 @@ printResults(TState *threads, StatsData *total, instr_time total_time, tps_exclude = total->cnt / (time_include - (INSTR_TIME_GET_DOUBLE(conn_total_time) / nclients)); + /* Report test parameters. */ printf("transaction type: %s\n", num_scripts == 1 ? sql_script[0].desc : "multiple scripts"); printf("scaling factor: %d\n", scale); @@ -3291,9 +3535,11 @@ printResults(TState *threads, StatsData *total, instr_time total_time, if (throttle_delay || progress || latency_limit) printSimpleStats("latency", &total->latency); else - /* only an average latency computed from the duration is available */ - printf("latency average: %.3f ms\n", - 1000.0 * duration * nclients / total->cnt); + { + /* no measurement, show average latency computed from run time */ + printf("latency average = %.3f ms\n", + 1000.0 * time_include * nclients / total->cnt); + } if (throttle_delay) { @@ -3319,7 +3565,7 @@ printResults(TState *threads, StatsData *total, instr_time total_time, { if (num_scripts > 1) printf("SQL script %d: %s\n" - " - weight = %d (targets %.1f%% of total)\n" + " - weight: %d (targets %.1f%% of total)\n" " - " INT64_FORMAT " transactions (%.1f%% of total, tps = %f)\n", i + 1, sql_script[i].desc, sql_script[i].weight, @@ -3398,6 +3644,7 @@ main(int argc, char **argv) {"sampling-rate", required_argument, NULL, 4}, {"aggregate-interval", required_argument, NULL, 5}, {"progress-timestamp", no_argument, NULL, 6}, + {"log-prefix", required_argument, NULL, 7}, {NULL, 0, NULL, 0} }; @@ -3727,10 +3974,6 @@ main(int argc, char **argv) } break; case 5: -#ifdef WIN32 - fprintf(stderr, "--aggregate-interval is not currently supported on Windows\n"); - exit(1); -#else benchmarking_option_set = true; agg_interval = atoi(optarg); if (agg_interval <= 0) @@ -3739,12 +3982,15 @@ main(int argc, char **argv) optarg); exit(1); } -#endif break; case 6: progress_timestamp = true; benchmarking_option_set = true; break; + case 7: + benchmarking_option_set = true; + logfile_prefix = pg_strdup(optarg); + break; default: fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); @@ -3842,6 +4088,12 @@ main(int argc, char **argv) exit(1); } + if (!use_log && logfile_prefix) + { + fprintf(stderr, "log file prefix (--log-prefix) is allowed only when logging transactions (-l)\n"); + exit(1); + } + if (duration > 0 && agg_interval > duration) { fprintf(stderr, "number of seconds for aggregation (%d) must not be higher than test duration (%d)\n", agg_interval, duration); @@ -4012,7 +4264,7 @@ main(int argc, char **argv) thread->random_state[2] = random(); thread->logfile = NULL; /* filled in later */ thread->latency_late = 0; - initStats(&thread->stats, 0.0); + initStats(&thread->stats, 0); nclients_dealt += thread->nstate; } @@ -4066,7 +4318,7 @@ main(int argc, char **argv) #endif /* ENABLE_THREAD_SAFETY */ /* wait for threads and accumulate results */ - initStats(&stats, 0.0); + initStats(&stats, 0); INSTR_TIME_SET_ZERO(conn_total_time); for (i = 0; i < nthreads; i++) { @@ -4139,15 +4391,20 @@ threadRun(void *arg) INSTR_TIME_SET_ZERO(thread->conn_time); + initStats(&aggs, time(NULL)); + last = aggs; + /* open log file if requested */ if (use_log) { - char logpath[64]; + char logpath[MAXPGPATH]; + char *prefix = logfile_prefix ? logfile_prefix : "pgbench_log"; if (thread->tid == 0) - snprintf(logpath, sizeof(logpath), "pgbench_log.%d", main_pid); + snprintf(logpath, sizeof(logpath), "%s.%d", prefix, main_pid); else - snprintf(logpath, sizeof(logpath), "pgbench_log.%d.%d", main_pid, thread->tid); + snprintf(logpath, sizeof(logpath), "%s.%d.%d", prefix, main_pid, thread->tid); + thread->logfile = fopen(logpath, "w"); if (thread->logfile == NULL) @@ -4172,101 +4429,85 @@ threadRun(void *arg) INSTR_TIME_SET_CURRENT(thread->conn_time); INSTR_TIME_SUBTRACT(thread->conn_time, thread->start_time); - initStats(&aggs, INSTR_TIME_GET_DOUBLE(thread->start_time)); - last = aggs; - - /* send start up queries in async manner */ + /* explicitly initialize the state machines */ for (i = 0; i < nstate; i++) { - CState *st = &state[i]; - int prev_ecnt = st->ecnt; - Command **commands; - - st->use_file = chooseScript(thread); - commands = sql_script[st->use_file].commands; - if (debug) - fprintf(stderr, "client %d executing script \"%s\"\n", st->id, - sql_script[st->use_file].desc); - if (!doCustom(thread, st, &aggs)) - remains--; /* I've aborted */ - - if (st->ecnt > prev_ecnt && commands[st->state]->type == META_COMMAND) - { - fprintf(stderr, "client %d aborted in state %d; execution of meta-command failed\n", - i, st->state); - remains--; /* I've aborted */ - PQfinish(st->con); - st->con = NULL; - } + state[i].state = CSTATE_CHOOSE_SCRIPT; } + /* loop till all clients have terminated */ while (remains > 0) { fd_set input_mask; - int maxsock; /* max socket number to be waited */ - int64 now_usec = 0; + int maxsock; /* max socket number to be waited for */ int64 min_usec; + int64 now_usec = 0; /* set this only if needed */ + /* identify which client sockets should be checked for input */ FD_ZERO(&input_mask); - maxsock = -1; min_usec = PG_INT64_MAX; for (i = 0; i < nstate; i++) { CState *st = &state[i]; - Command **commands = sql_script[st->use_file].commands; - int sock; - if (st->con == NULL) + if (st->state == CSTATE_THROTTLE && timer_exceeded) { - continue; + /* interrupt client that has not started a transaction */ + st->state = CSTATE_FINISHED; + PQfinish(st->con); + st->con = NULL; + remains--; } - else if (st->sleeping) + else if (st->state == CSTATE_SLEEP || st->state == CSTATE_THROTTLE) { - if (st->throttling && timer_exceeded) - { - /* interrupt client which has not started a transaction */ - remains--; - st->sleeping = false; - st->throttling = false; - PQfinish(st->con); - st->con = NULL; - continue; - } - else /* just a nap from the script */ + /* a nap from the script, or under throttling */ + int64 this_usec; + + /* get current time if needed */ + if (now_usec == 0) { - int this_usec; + instr_time now; - if (min_usec == PG_INT64_MAX) - { - instr_time now; + INSTR_TIME_SET_CURRENT(now); + now_usec = INSTR_TIME_GET_MICROSEC(now); + } - INSTR_TIME_SET_CURRENT(now); - now_usec = INSTR_TIME_GET_MICROSEC(now); - } + /* min_usec should be the minimum delay across all clients */ + this_usec = (st->state == CSTATE_SLEEP ? + st->sleep_until : st->txn_scheduled) - now_usec; + if (min_usec > this_usec) + min_usec = this_usec; + } + else if (st->state == CSTATE_WAIT_RESULT) + { + /* + * waiting for result from server - nothing to do unless the + * socket is readable + */ + int sock = PQsocket(st->con); - this_usec = st->txn_scheduled - now_usec; - if (min_usec > this_usec) - min_usec = this_usec; + if (sock < 0) + { + fprintf(stderr, "invalid socket: %s", + PQerrorMessage(st->con)); + goto done; } + + FD_SET(sock, &input_mask); + if (maxsock < sock) + maxsock = sock; } - else if (commands[st->state]->type == META_COMMAND) + else if (st->state != CSTATE_ABORTED && + st->state != CSTATE_FINISHED) { - min_usec = 0; /* the connection is ready to run */ + /* + * This client thread is ready to do something, so we don't + * want to wait. No need to examine additional clients. + */ + min_usec = 0; break; } - - sock = PQsocket(st->con); - if (sock < 0) - { - fprintf(stderr, "invalid socket: %s", PQerrorMessage(st->con)); - goto done; - } - - FD_SET(sock, &input_mask); - - if (maxsock < sock) - maxsock = sock; } /* also wake up to print the next progress report on time */ @@ -4288,9 +4529,10 @@ threadRun(void *arg) } /* - * Sleep until we receive data from the server, or a nap-time - * specified in the script ends, or it's time to print a progress - * report. + * If no clients are ready to execute actions, sleep until we receive + * data from the server, or a nap-time specified in the script ends, + * or it's time to print a progress report. Update input_mask to show + * which client(s) received data. */ if (min_usec > 0 && maxsock != -1) { @@ -4309,22 +4551,29 @@ threadRun(void *arg) if (nsocks < 0) { if (errno == EINTR) + { + /* On EINTR, go back to top of loop */ continue; + } /* must be something wrong */ fprintf(stderr, "select() failed: %s\n", strerror(errno)); goto done; } } + else + { + /* If we didn't call select(), don't try to read any data */ + FD_ZERO(&input_mask); + } - /* ok, backend returns reply */ + /* ok, advance the state machine of each connection */ for (i = 0; i < nstate; i++) { CState *st = &state[i]; - Command **commands = sql_script[st->use_file].commands; - int prev_ecnt = st->ecnt; - if (st->con) + if (st->state == CSTATE_WAIT_RESULT) { + /* don't call doCustom unless data is available */ int sock = PQsocket(st->con); if (sock < 0) @@ -4333,25 +4582,25 @@ threadRun(void *arg) PQerrorMessage(st->con)); goto done; } - if (FD_ISSET(sock, &input_mask) || - commands[st->state]->type == META_COMMAND) - { - if (!doCustom(thread, st, &aggs)) - remains--; /* I've aborted */ - } - } - if (st->ecnt > prev_ecnt && commands[st->state]->type == META_COMMAND) + if (!FD_ISSET(sock, &input_mask)) + continue; + } + else if (st->state == CSTATE_FINISHED || + st->state == CSTATE_ABORTED) { - fprintf(stderr, "client %d aborted in state %d; execution of meta-command failed\n", - i, st->state); - remains--; /* I've aborted */ - PQfinish(st->con); - st->con = NULL; + /* this client is done, no need to consider it anymore */ + continue; } + + doCustom(thread, st, &aggs); + + /* If doCustom changed client to finished state, reduce remains */ + if (st->state == CSTATE_FINISHED || st->state == CSTATE_ABORTED) + remains--; } - /* progress report by thread 0 for all threads */ + /* progress report is made by thread 0 for all threads */ if (progress && thread->tid == 0) { instr_time now_time; @@ -4383,7 +4632,7 @@ threadRun(void *arg) * (If a read from a 64-bit integer is not atomic, you might * get a "torn" read and completely bogus latencies though!) */ - initStats(&cur, 0.0); + initStats(&cur, 0); for (i = 0; i < nthreads; i++) { mergeSimpleStats(&cur.latency, &thread[i].stats.latency); @@ -4443,12 +4692,13 @@ threadRun(void *arg) INSTR_TIME_ACCUM_DIFF(thread->conn_time, end, start); if (thread->logfile) { - if (agg_interval) + if (agg_interval > 0) { /* log aggregated but not yet reported transactions */ - doLog(thread, state, &end, &aggs, false, 0, 0); + doLog(thread, state, &aggs, false, 0, 0); } fclose(thread->logfile); + thread->logfile = NULL; } return NULL; } diff --git a/src/bin/pgbench/pgbench.h b/src/bin/pgbench/pgbench.h index ab0f822010..38b3af5ab1 100644 --- a/src/bin/pgbench/pgbench.h +++ b/src/bin/pgbench/pgbench.h @@ -2,7 +2,7 @@ * * pgbench.h * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * *------------------------------------------------------------------------- diff --git a/src/bin/pgevent/Makefile b/src/bin/pgevent/Makefile index 5ea6116516..6e6797ba13 100644 --- a/src/bin/pgevent/Makefile +++ b/src/bin/pgevent/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/pgevent # -# Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Copyright (c) 1996-2017, PostgreSQL Global Development Group # #------------------------------------------------------------------------- diff --git a/src/bin/psql/Makefile b/src/bin/psql/Makefile index 1f6a289ea0..c53733f808 100644 --- a/src/bin/psql/Makefile +++ b/src/bin/psql/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/psql # -# Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/bin/psql/Makefile diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 9c0af4e848..0c164a339c 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/command.c */ @@ -501,6 +501,22 @@ exec_command(const char *cmd, else success = PSQL_CMD_UNKNOWN; break; + case 'R': + switch (cmd[2]) + { + case 'p': + if (show_verbose) + success = describePublications(pattern); + else + success = listPublications(pattern); + break; + case 's': + success = describeSubscriptions(pattern, show_verbose); + break; + default: + status = PSQL_CMD_UNKNOWN; + } + break; case 'u': success = describeRoles(pattern, show_verbose, show_system); break; @@ -635,8 +651,11 @@ exec_command(const char *cmd, if (pset.sversion < 80400) { - psql_error("The server (version %d.%d) does not support editing function source.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support editing function source.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); status = PSQL_CMD_ERROR; } else if (!query_buf) @@ -731,8 +750,11 @@ exec_command(const char *cmd, if (pset.sversion < 70400) { - psql_error("The server (version %d.%d) does not support editing view definitions.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support editing view definitions.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); status = PSQL_CMD_ERROR; } else if (!query_buf) @@ -1083,11 +1105,11 @@ exec_command(const char *cmd, /* \password -- set user password */ else if (strcmp(cmd, "password") == 0) { - char *pw1; - char *pw2; + char pw1[100]; + char pw2[100]; - pw1 = simple_prompt("Enter new password: ", 100, false); - pw2 = simple_prompt("Enter it again: ", 100, false); + simple_prompt("Enter new password: ", pw1, sizeof(pw1), false); + simple_prompt("Enter it again: ", pw2, sizeof(pw2), false); if (strcmp(pw1, pw2) != 0) { @@ -1133,9 +1155,6 @@ exec_command(const char *cmd, if (opt0) free(opt0); } - - free(pw1); - free(pw2); } /* \prompt -- prompt and set variable */ @@ -1167,7 +1186,10 @@ exec_command(const char *cmd, opt = arg1; if (!pset.inputfile) - result = simple_prompt(prompt_text, 4096, true); + { + result = (char *) pg_malloc(4096); + simple_prompt(prompt_text, result, 4096, true); + } else { if (prompt_text) @@ -1176,15 +1198,23 @@ exec_command(const char *cmd, fflush(stdout); } result = gets_fromFile(stdin); + if (!result) + { + psql_error("\\%s: could not read value for variable\n", + cmd); + success = false; + } } - if (!SetVariable(pset.vars, opt, result)) + if (result && + !SetVariable(pset.vars, opt, result)) { psql_error("\\%s: error while setting variable\n", cmd); success = false; } - free(result); + if (result) + free(result); if (prompt_text) free(prompt_text); free(opt); @@ -1362,8 +1392,11 @@ exec_command(const char *cmd, OT_WHOLE_LINE, NULL, true); if (pset.sversion < 80400) { - psql_error("The server (version %d.%d) does not support showing function source.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support showing function source.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); status = PSQL_CMD_ERROR; } else if (!func) @@ -1441,8 +1474,11 @@ exec_command(const char *cmd, OT_WHOLE_LINE, NULL, true); if (pset.sversion < 70400) { - psql_error("The server (version %d.%d) does not support showing view definitions.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support showing view definitions.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); status = PSQL_CMD_ERROR; } else if (!view) @@ -1735,20 +1771,19 @@ exec_command(const char *cmd, static char * prompt_for_password(const char *username) { - char *result; + char buf[100]; if (username == NULL) - result = simple_prompt("Password: ", 100, false); + simple_prompt("Password: ", buf, sizeof(buf), false); else { char *prompt_text; prompt_text = psprintf(_("Password for user %s: "), username); - result = simple_prompt(prompt_text, 100, false); + simple_prompt(prompt_text, buf, sizeof(buf), false); free(prompt_text); } - - return result; + return pg_strdup(buf); } static bool @@ -2014,22 +2049,21 @@ connection_warnings(bool in_startup) if (!pset.quiet && !pset.notty) { int client_ver = PG_VERSION_NUM; + char cverbuf[32]; + char sverbuf[32]; if (pset.sversion != client_ver) { const char *server_version; - char server_ver_str[16]; /* Try to get full text form, might include "devel" etc */ server_version = PQparameterStatus(pset.db, "server_version"); + /* Otherwise fall back on pset.sversion */ if (!server_version) { - snprintf(server_ver_str, sizeof(server_ver_str), - "%d.%d.%d", - pset.sversion / 10000, - (pset.sversion / 100) % 100, - pset.sversion % 100); - server_version = server_ver_str; + formatPGVersionNumber(pset.sversion, true, + sverbuf, sizeof(sverbuf)); + server_version = sverbuf; } printf(_("%s (%s, server %s)\n"), @@ -2040,10 +2074,13 @@ connection_warnings(bool in_startup) printf("%s (%s)\n", pset.progname, PG_VERSION); if (pset.sversion / 100 > client_ver / 100) - printf(_("WARNING: %s major version %d.%d, server major version %d.%d.\n" + printf(_("WARNING: %s major version %s, server major version %s.\n" " Some psql features might not work.\n"), - pset.progname, client_ver / 10000, (client_ver / 100) % 100, - pset.sversion / 10000, (pset.sversion / 100) % 100); + pset.progname, + formatPGVersionNumber(client_ver, false, + cverbuf, sizeof(cverbuf)), + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); #ifdef WIN32 checkWin32Codepage(); diff --git a/src/bin/psql/command.h b/src/bin/psql/command.h index 8d37a3a676..d0c32645f1 100644 --- a/src/bin/psql/command.h +++ b/src/bin/psql/command.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/command.h */ diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c index 2450b9c3f8..e1b04de013 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/common.c */ @@ -10,6 +10,7 @@ #include #include +#include #include #ifndef WIN32 #include /* for write() */ @@ -18,6 +19,7 @@ #include #endif +#include "fe_utils/string_utils.h" #include "portability/instr_time.h" #include "settings.h" @@ -530,6 +532,57 @@ ClearOrSaveResult(PGresult *result) } +/* + * Print microtiming output. Always print raw milliseconds; if the interval + * is >= 1 second, also break it down into days/hours/minutes/seconds. + */ +static void +PrintTiming(double elapsed_msec) +{ + double seconds; + double minutes; + double hours; + double days; + + if (elapsed_msec < 1000.0) + { + /* This is the traditional (pre-v10) output format */ + printf(_("Time: %.3f ms\n"), elapsed_msec); + return; + } + + /* + * Note: we could print just seconds, in a format like %06.3f, when the + * total is less than 1min. But that's hard to interpret unless we tack + * on "s" or otherwise annotate it. Forcing the display to include + * minutes seems like a better solution. + */ + seconds = elapsed_msec / 1000.0; + minutes = floor(seconds / 60.0); + seconds -= 60.0 * minutes; + if (minutes < 60.0) + { + printf(_("Time: %.3f ms (%02d:%06.3f)\n"), + elapsed_msec, (int) minutes, seconds); + return; + } + + hours = floor(minutes / 60.0); + minutes -= 60.0 * hours; + if (hours < 24.0) + { + printf(_("Time: %.3f ms (%02d:%02d:%06.3f)\n"), + elapsed_msec, (int) hours, (int) minutes, seconds); + return; + } + + days = floor(hours / 24.0); + hours -= 24.0 * days; + printf(_("Time: %.3f ms (%.0f d %02d:%02d:%06.3f)\n"), + elapsed_msec, days, (int) hours, (int) minutes, seconds); +} + + /* * PSQLexec * @@ -678,7 +731,7 @@ PSQLexecWatch(const char *query, const printQueryOpt *opt) /* Possible microtiming output */ if (pset.timing) - printf(_("Time: %.3f ms\n"), elapsed_msec); + PrintTiming(elapsed_msec); return 1; } @@ -1202,8 +1255,11 @@ SendQuery(const char *query) { if (on_error_rollback_warning == false && pset.sversion < 80000) { - psql_error("The server (version %d.%d) does not support savepoints for ON_ERROR_ROLLBACK.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support savepoints for ON_ERROR_ROLLBACK.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); on_error_rollback_warning = true; } else @@ -1328,7 +1384,7 @@ SendQuery(const char *query) /* Possible microtiming output */ if (pset.timing) - printf(_("Time: %.3f ms\n"), elapsed_msec); + PrintTiming(elapsed_msec); /* check for events that may occur during query execution */ diff --git a/src/bin/psql/common.h b/src/bin/psql/common.h index bdcb58f2f3..dad0eb822a 100644 --- a/src/bin/psql/common.h +++ b/src/bin/psql/common.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/common.h */ diff --git a/src/bin/psql/copy.c b/src/bin/psql/copy.c index 942264fbf9..481031a229 100644 --- a/src/bin/psql/copy.c +++ b/src/bin/psql/copy.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/copy.c */ diff --git a/src/bin/psql/copy.h b/src/bin/psql/copy.h index 4ffe53ba9e..a79550de19 100644 --- a/src/bin/psql/copy.h +++ b/src/bin/psql/copy.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/copy.h */ diff --git a/src/bin/psql/create_help.pl b/src/bin/psql/create_help.pl index f3d8141b99..359670b6e9 100644 --- a/src/bin/psql/create_help.pl +++ b/src/bin/psql/create_help.pl @@ -3,7 +3,7 @@ ################################################################# # create_help.pl -- converts SGML docs to internal psql help # -# Copyright (c) 2000-2016, PostgreSQL Global Development Group +# Copyright (c) 2000-2017, PostgreSQL Global Development Group # # src/bin/psql/create_help.pl ################################################################# diff --git a/src/bin/psql/crosstabview.c b/src/bin/psql/crosstabview.c index b283c24e3c..bf48d2f406 100644 --- a/src/bin/psql/crosstabview.c +++ b/src/bin/psql/crosstabview.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/crosstabview.c */ @@ -352,7 +352,8 @@ printCrosstab(const PGresult *results, { int row_number; int col_number; - pivot_field *p; + pivot_field *rp, + *cp; pivot_field elt; /* Find target row */ @@ -360,13 +361,13 @@ printCrosstab(const PGresult *results, elt.name = PQgetvalue(results, rn, field_for_rows); else elt.name = NULL; - p = (pivot_field *) bsearch(&elt, - piv_rows, - num_rows, - sizeof(pivot_field), - pivotFieldCompare); - Assert(p != NULL); - row_number = p->rank; + rp = (pivot_field *) bsearch(&elt, + piv_rows, + num_rows, + sizeof(pivot_field), + pivotFieldCompare); + Assert(rp != NULL); + row_number = rp->rank; /* Find target column */ if (!PQgetisnull(results, rn, field_for_columns)) @@ -374,13 +375,13 @@ printCrosstab(const PGresult *results, else elt.name = NULL; - p = (pivot_field *) bsearch(&elt, - piv_columns, - num_columns, - sizeof(pivot_field), - pivotFieldCompare); - Assert(p != NULL); - col_number = p->rank; + cp = (pivot_field *) bsearch(&elt, + piv_columns, + num_columns, + sizeof(pivot_field), + pivotFieldCompare); + Assert(cp != NULL); + col_number = cp->rank; /* Place value into cell */ if (col_number >= 0 && row_number >= 0) @@ -396,10 +397,10 @@ printCrosstab(const PGresult *results, if (cont.cells[idx] != NULL) { psql_error("\\crosstabview: query result contains multiple data values for row \"%s\", column \"%s\"\n", - piv_rows[row_number].name ? piv_rows[row_number].name : - popt.nullPrint ? popt.nullPrint : "(null)", - piv_columns[col_number].name ? piv_columns[col_number].name : - popt.nullPrint ? popt.nullPrint : "(null)"); + rp->name ? rp->name : + (popt.nullPrint ? popt.nullPrint : "(null)"), + cp->name ? cp->name : + (popt.nullPrint ? popt.nullPrint : "(null)")); goto error; } @@ -694,8 +695,8 @@ indexOfColumn(char *arg, const PGresult *res) static int pivotFieldCompare(const void *a, const void *b) { - pivot_field *pa = (pivot_field *) a; - pivot_field *pb = (pivot_field *) b; + const pivot_field *pa = (const pivot_field *) a; + const pivot_field *pb = (const pivot_field *) b; /* test null values */ if (!pb->name) @@ -704,12 +705,11 @@ pivotFieldCompare(const void *a, const void *b) return 1; /* non-null values */ - return strcmp(((pivot_field *) a)->name, - ((pivot_field *) b)->name); + return strcmp(pa->name, pb->name); } static int rankCompare(const void *a, const void *b) { - return *((int *) a) - *((int *) b); + return *((const int *) a) - *((const int *) b); } diff --git a/src/bin/psql/crosstabview.h b/src/bin/psql/crosstabview.h index 41bf907e8f..97c72a5139 100644 --- a/src/bin/psql/crosstabview.h +++ b/src/bin/psql/crosstabview.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/crosstabview.h */ diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 27be10215b..c501168d8c 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -6,7 +6,7 @@ * with servers of versions 7.4 and up. It's okay to omit irrelevant * information for an old server, but not to fail outright. * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/describe.c */ @@ -142,8 +142,11 @@ describeAccessMethods(const char *pattern, bool verbose) if (pset.sversion < 90600) { - psql_error("The server (version %d.%d) does not support access methods.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support access methods.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -205,8 +208,11 @@ describeTablespaces(const char *pattern, bool verbose) if (pset.sversion < 80000) { - psql_error("The server (version %d.%d) does not support tablespaces.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support tablespaces.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -311,8 +317,11 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool if (showWindow && pset.sversion < 80400) { - psql_error("\\df does not take a \"w\" option with server version %d.%d\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("\\df does not take a \"w\" option with server version %s\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -856,6 +865,7 @@ permissionsList(const char *pattern) " WHEN 'm' THEN '%s'" " WHEN 'S' THEN '%s'" " WHEN 'f' THEN '%s'" + " WHEN 'P' THEN '%s'" " END as \"%s\",\n" " ", gettext_noop("Schema"), @@ -865,6 +875,7 @@ permissionsList(const char *pattern) gettext_noop("materialized view"), gettext_noop("sequence"), gettext_noop("foreign table"), + gettext_noop("table"), /* partitioned table */ gettext_noop("Type")); printACLColumn(&buf, "c.relacl"); @@ -878,7 +889,7 @@ permissionsList(const char *pattern) " ), E'\\n') AS \"%s\"", gettext_noop("Column privileges")); - if (pset.sversion >= 90500) + if (pset.sversion >= 90500 && pset.sversion < 100000) appendPQExpBuffer(&buf, ",\n pg_catalog.array_to_string(ARRAY(\n" " SELECT polname\n" @@ -909,9 +920,43 @@ permissionsList(const char *pattern) " AS \"%s\"", gettext_noop("Policies")); + if (pset.sversion >= 100000) + appendPQExpBuffer(&buf, + ",\n pg_catalog.array_to_string(ARRAY(\n" + " SELECT polname\n" + " || CASE WHEN NOT polpermissive THEN\n" + " E' (RESTRICTIVE)'\n" + " ELSE '' END\n" + " || CASE WHEN polcmd != '*' THEN\n" + " E' (' || polcmd || E'):'\n" + " ELSE E':' \n" + " END\n" + " || CASE WHEN polqual IS NOT NULL THEN\n" + " E'\\n (u): ' || pg_catalog.pg_get_expr(polqual, polrelid)\n" + " ELSE E''\n" + " END\n" + " || CASE WHEN polwithcheck IS NOT NULL THEN\n" + " E'\\n (c): ' || pg_catalog.pg_get_expr(polwithcheck, polrelid)\n" + " ELSE E''\n" + " END" + " || CASE WHEN polroles <> '{0}' THEN\n" + " E'\\n to: ' || pg_catalog.array_to_string(\n" + " ARRAY(\n" + " SELECT rolname\n" + " FROM pg_catalog.pg_roles\n" + " WHERE oid = ANY (polroles)\n" + " ORDER BY 1\n" + " ), E', ')\n" + " ELSE E''\n" + " END\n" + " FROM pg_catalog.pg_policy pol\n" + " WHERE polrelid = c.oid), E'\\n')\n" + " AS \"%s\"", + gettext_noop("Policies")); + appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_class c\n" " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n" - "WHERE c.relkind IN ('r', 'v', 'm', 'S', 'f')\n"); + "WHERE c.relkind IN ('r', 'v', 'm', 'S', 'f', 'P')\n"); /* * Unless a schema pattern is specified, we suppress system and temp @@ -962,8 +1007,11 @@ listDefaultACLs(const char *pattern) if (pset.sversion < 90000) { - psql_error("The server (version %d.%d) does not support altering default privileges.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support altering default privileges.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -1310,9 +1358,8 @@ describeOneTableDetails(const char *schemaname, bool printTableInitialized = false; int i; char *view_def = NULL; - char *headers[9]; + char *headers[11]; char **seq_values = NULL; - char **modifiers = NULL; char **ptr; PQExpBufferData title; PQExpBufferData tmpbuf; @@ -1334,7 +1381,7 @@ describeOneTableDetails(const char *schemaname, char relpersistence; char relreplident; } tableinfo; - bool show_modifiers = false; + bool show_column_details = false; bool retval; retval = false; @@ -1555,8 +1602,8 @@ describeOneTableDetails(const char *schemaname, * types, and foreign tables (c.f. CommentObject() in comment.c). */ if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v' || - tableinfo.relkind == 'm' || - tableinfo.relkind == 'f' || tableinfo.relkind == 'c') + tableinfo.relkind == 'm' || tableinfo.relkind == 'f' || + tableinfo.relkind == 'c' || tableinfo.relkind == 'P') appendPQExpBufferStr(&buf, ", pg_catalog.col_description(a.attrelid, a.attnum)"); } @@ -1621,6 +1668,14 @@ describeOneTableDetails(const char *schemaname, printfPQExpBuffer(&title, _("Foreign table \"%s.%s\""), schemaname, relationname); break; + case 'P': + if (tableinfo.relpersistence == 'u') + printfPQExpBuffer(&title, _("Unlogged table \"%s.%s\""), + schemaname, relationname); + else + printfPQExpBuffer(&title, _("Table \"%s.%s\""), + schemaname, relationname); + break; default: /* untranslated unknown relkind */ printfPQExpBuffer(&title, "?%c? \"%s.%s\"", @@ -1634,12 +1689,13 @@ describeOneTableDetails(const char *schemaname, cols = 2; if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v' || - tableinfo.relkind == 'm' || - tableinfo.relkind == 'f' || tableinfo.relkind == 'c') + tableinfo.relkind == 'm' || tableinfo.relkind == 'f' || + tableinfo.relkind == 'c' || tableinfo.relkind == 'P') { - show_modifiers = true; - headers[cols++] = gettext_noop("Modifiers"); - modifiers = pg_malloc0((numrows + 1) * sizeof(*modifiers)); + headers[cols++] = gettext_noop("Collation"); + headers[cols++] = gettext_noop("Nullable"); + headers[cols++] = gettext_noop("Default"); + show_column_details = true; } if (tableinfo.relkind == 'S') @@ -1655,12 +1711,12 @@ describeOneTableDetails(const char *schemaname, { headers[cols++] = gettext_noop("Storage"); if (tableinfo.relkind == 'r' || tableinfo.relkind == 'm' || - tableinfo.relkind == 'f') + tableinfo.relkind == 'f' || tableinfo.relkind == 'P') headers[cols++] = gettext_noop("Stats target"); /* Column comments, if the relkind supports this feature. */ if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v' || - tableinfo.relkind == 'm' || - tableinfo.relkind == 'c' || tableinfo.relkind == 'f') + tableinfo.relkind == 'm' || tableinfo.relkind == 'c' || + tableinfo.relkind == 'f' || tableinfo.relkind == 'P') headers[cols++] = gettext_noop("Description"); } @@ -1697,39 +1753,15 @@ describeOneTableDetails(const char *schemaname, /* Type */ printTableAddCell(&cont, PQgetvalue(res, i, 1), false, false); - /* Modifiers: collate, not null, default */ - if (show_modifiers) + /* Collation, Nullable, Default */ + if (show_column_details) { - resetPQExpBuffer(&tmpbuf); + printTableAddCell(&cont, PQgetvalue(res, i, 5), false, false); - if (!PQgetisnull(res, i, 5)) - { - if (tmpbuf.len > 0) - appendPQExpBufferChar(&tmpbuf, ' '); - appendPQExpBuffer(&tmpbuf, _("collate %s"), - PQgetvalue(res, i, 5)); - } - - if (strcmp(PQgetvalue(res, i, 3), "t") == 0) - { - if (tmpbuf.len > 0) - appendPQExpBufferChar(&tmpbuf, ' '); - appendPQExpBufferStr(&tmpbuf, _("not null")); - } + printTableAddCell(&cont, strcmp(PQgetvalue(res, i, 3), "t") == 0 ? "not null" : "", false, false); - /* handle "default" here */ /* (note: above we cut off the 'default' string at 128) */ - if (strlen(PQgetvalue(res, i, 2)) != 0) - { - if (tmpbuf.len > 0) - appendPQExpBufferChar(&tmpbuf, ' '); - /* translator: default values of column definitions */ - appendPQExpBuffer(&tmpbuf, _("default %s"), - PQgetvalue(res, i, 2)); - } - - modifiers[i] = pg_strdup(tmpbuf.data); - printTableAddCell(&cont, modifiers[i], false, false); + printTableAddCell(&cont, PQgetvalue(res, i, 2), false, false); } /* Value: for sequences only */ @@ -1760,7 +1792,7 @@ describeOneTableDetails(const char *schemaname, /* Statistics target, if the relkind supports this feature */ if (tableinfo.relkind == 'r' || tableinfo.relkind == 'm' || - tableinfo.relkind == 'f') + tableinfo.relkind == 'f' || tableinfo.relkind == 'P') { printTableAddCell(&cont, PQgetvalue(res, i, firstvcol + 1), false, false); @@ -1768,14 +1800,61 @@ describeOneTableDetails(const char *schemaname, /* Column comments, if the relkind supports this feature. */ if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v' || - tableinfo.relkind == 'm' || - tableinfo.relkind == 'c' || tableinfo.relkind == 'f') + tableinfo.relkind == 'm' || tableinfo.relkind == 'c' || + tableinfo.relkind == 'f' || tableinfo.relkind == 'P') printTableAddCell(&cont, PQgetvalue(res, i, firstvcol + 2), false, false); } } /* Make footers */ + if (pset.sversion >= 100000) + { + /* Get the partition information */ + PGresult *result; + char *parent_name; + char *partdef; + + printfPQExpBuffer(&buf, + "SELECT inhparent::pg_catalog.regclass, pg_get_expr(c.relpartbound, inhrelid)" + " FROM pg_catalog.pg_class c" + " JOIN pg_catalog.pg_inherits" + " ON c.oid = inhrelid" + " WHERE c.oid = '%s' AND c.relispartition;", oid); + result = PSQLexec(buf.data); + if (!result) + goto error_return; + + if (PQntuples(result) > 0) + { + parent_name = PQgetvalue(result, 0, 0); + partdef = PQgetvalue(result, 0, 1); + printfPQExpBuffer(&tmpbuf, _("Partition of: %s %s"), parent_name, + partdef); + printTableAddFooter(&cont, tmpbuf.data); + PQclear(result); + } + } + + if (tableinfo.relkind == 'P') + { + /* Get the partition key information */ + PGresult *result; + char *partkeydef; + + printfPQExpBuffer(&buf, + "SELECT pg_catalog.pg_get_partkeydef('%s'::pg_catalog.oid);", + oid); + result = PSQLexec(buf.data); + if (!result || PQntuples(result) != 1) + goto error_return; + + partkeydef = PQgetvalue(result, 0, 0); + printfPQExpBuffer(&tmpbuf, _("Partition key: %s"), partkeydef); + printTableAddFooter(&cont, tmpbuf.data); + PQclear(result); + } + if (tableinfo.relkind == 'i') { /* Footer information about an index */ @@ -1914,7 +1993,7 @@ describeOneTableDetails(const char *schemaname, PQclear(result); } else if (tableinfo.relkind == 'r' || tableinfo.relkind == 'm' || - tableinfo.relkind == 'f') + tableinfo.relkind == 'f' || tableinfo.relkind == 'P') { /* Footer information about a table */ PGresult *result = NULL; @@ -2124,21 +2203,36 @@ describeOneTableDetails(const char *schemaname, /* print any row-level policies */ if (pset.sversion >= 90500) { - printfPQExpBuffer(&buf, - "SELECT pol.polname,\n" - "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE array_to_string(array(select rolname from pg_roles where oid = any (pol.polroles) order by 1),',') END,\n" - "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid),\n" - "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid),\n" - "CASE pol.polcmd \n" - "WHEN 'r' THEN 'SELECT'\n" - "WHEN 'a' THEN 'INSERT'\n" - "WHEN 'w' THEN 'UPDATE'\n" - "WHEN 'd' THEN 'DELETE'\n" - "WHEN '*' THEN 'ALL'\n" - "END AS cmd\n" - "FROM pg_catalog.pg_policy pol\n" - "WHERE pol.polrelid = '%s' ORDER BY 1;", - oid); + if (pset.sversion >= 100000) + printfPQExpBuffer(&buf, + "SELECT pol.polname, pol.polpermissive,\n" + "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE array_to_string(array(select rolname from pg_roles where oid = any (pol.polroles) order by 1),',') END,\n" + "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid),\n" + "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid),\n" + "CASE pol.polcmd \n" + "WHEN 'r' THEN 'SELECT'\n" + "WHEN 'a' THEN 'INSERT'\n" + "WHEN 'w' THEN 'UPDATE'\n" + "WHEN 'd' THEN 'DELETE'\n" + "END AS cmd\n" + "FROM pg_catalog.pg_policy pol\n" + "WHERE pol.polrelid = '%s' ORDER BY 1;", + oid); + else + printfPQExpBuffer(&buf, + "SELECT pol.polname, 't' as polpermissive,\n" + "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE array_to_string(array(select rolname from pg_roles where oid = any (pol.polroles) order by 1),',') END,\n" + "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid),\n" + "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid),\n" + "CASE pol.polcmd \n" + "WHEN 'r' THEN 'SELECT'\n" + "WHEN 'a' THEN 'INSERT'\n" + "WHEN 'w' THEN 'UPDATE'\n" + "WHEN 'd' THEN 'DELETE'\n" + "END AS cmd\n" + "FROM pg_catalog.pg_policy pol\n" + "WHERE pol.polrelid = '%s' ORDER BY 1;", + oid); result = PSQLexec(buf.data); if (!result) @@ -2172,23 +2266,26 @@ describeOneTableDetails(const char *schemaname, printfPQExpBuffer(&buf, " POLICY \"%s\"", PQgetvalue(result, i, 0)); - if (!PQgetisnull(result, i, 4)) + if (*(PQgetvalue(result, i, 1)) == 'f') + appendPQExpBuffer(&buf, " AS RESTRICTIVE"); + + if (!PQgetisnull(result, i, 5)) appendPQExpBuffer(&buf, " FOR %s", - PQgetvalue(result, i, 4)); + PQgetvalue(result, i, 5)); - if (!PQgetisnull(result, i, 1)) + if (!PQgetisnull(result, i, 2)) { appendPQExpBuffer(&buf, "\n TO %s", - PQgetvalue(result, i, 1)); + PQgetvalue(result, i, 2)); } - if (!PQgetisnull(result, i, 2)) + if (!PQgetisnull(result, i, 3)) appendPQExpBuffer(&buf, "\n USING (%s)", - PQgetvalue(result, i, 2)); + PQgetvalue(result, i, 3)); - if (!PQgetisnull(result, i, 3)) + if (!PQgetisnull(result, i, 4)) appendPQExpBuffer(&buf, "\n WITH CHECK (%s)", - PQgetvalue(result, i, 3)); + PQgetvalue(result, i, 4)); printTableAddFooter(&cont, buf.data); @@ -2290,6 +2387,38 @@ describeOneTableDetails(const char *schemaname, } PQclear(result); } + + /* print any publications */ + if (pset.sversion >= 100000) + { + printfPQExpBuffer(&buf, + "SELECT pub.pubname\n" + " FROM pg_catalog.pg_publication pub\n" + " LEFT JOIN pg_publication_rel pr\n" + " ON (pr.prpubid = pub.oid)\n" + "WHERE pr.prrelid = '%s' OR pub.puballtables\n" + "ORDER BY 1;", + oid); + + result = PSQLexec(buf.data); + if (!result) + goto error_return; + else + tuples = PQntuples(result); + + if (tuples > 0) + printTableAddFooter(&cont, _("Publications:")); + + /* Might be an empty set - that's ok */ + for (i = 0; i < tuples; i++) + { + printfPQExpBuffer(&buf, " \"%s\"", + PQgetvalue(result, i, 0)); + + printTableAddFooter(&cont, buf.data); + } + PQclear(result); + } } if (view_def) @@ -2473,7 +2602,7 @@ describeOneTableDetails(const char *schemaname, * Finish printing the footer information about a table. */ if (tableinfo.relkind == 'r' || tableinfo.relkind == 'm' || - tableinfo.relkind == 'f') + tableinfo.relkind == 'f' || tableinfo.relkind == 'P') { PGresult *result; int tuples; @@ -2518,8 +2647,12 @@ describeOneTableDetails(const char *schemaname, PQclear(result); } - /* print inherited tables */ - printfPQExpBuffer(&buf, "SELECT c.oid::pg_catalog.regclass FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i WHERE c.oid=i.inhparent AND i.inhrelid = '%s' ORDER BY inhseqno;", oid); + /* print inherited tables (exclude, if parent is a partitioned table) */ + printfPQExpBuffer(&buf, + "SELECT c.oid::pg_catalog.regclass" + " FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i" + " WHERE c.oid=i.inhparent AND i.inhrelid = '%s'" + " AND c.relkind != 'P' ORDER BY inhseqno;", oid); result = PSQLexec(buf.data); if (!result) @@ -2548,9 +2681,23 @@ describeOneTableDetails(const char *schemaname, PQclear(result); } - /* print child tables */ - if (pset.sversion >= 80300) - printfPQExpBuffer(&buf, "SELECT c.oid::pg_catalog.regclass FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i WHERE c.oid=i.inhrelid AND i.inhparent = '%s' ORDER BY c.oid::pg_catalog.regclass::pg_catalog.text;", oid); + /* print child tables (with additional info if partitions) */ + if (pset.sversion >= 100000) + printfPQExpBuffer(&buf, + "SELECT c.oid::pg_catalog.regclass, pg_get_expr(c.relpartbound, c.oid)" + " FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i" + " WHERE c.oid=i.inhrelid AND" + " i.inhparent = '%s' AND" + " EXISTS (SELECT 1 FROM pg_class c WHERE c.oid = '%s')" + " ORDER BY c.oid::pg_catalog.regclass::pg_catalog.text;", oid, oid); + else if (pset.sversion >= 80300) + printfPQExpBuffer(&buf, + "SELECT c.oid::pg_catalog.regclass" + " FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i" + " WHERE c.oid=i.inhrelid AND" + " i.inhparent = '%s' AND" + " EXISTS (SELECT 1 FROM pg_class c WHERE c.oid = '%s')" + " ORDER BY c.oid::pg_catalog.regclass::pg_catalog.text;", oid, oid); else printfPQExpBuffer(&buf, "SELECT c.oid::pg_catalog.regclass FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i WHERE c.oid=i.inhrelid AND i.inhparent = '%s' ORDER BY c.relname;", oid); @@ -2565,24 +2712,39 @@ describeOneTableDetails(const char *schemaname, /* print the number of child tables, if any */ if (tuples > 0) { - printfPQExpBuffer(&buf, _("Number of child tables: %d (Use \\d+ to list them.)"), tuples); + if (tableinfo.relkind != 'P') + printfPQExpBuffer(&buf, _("Number of child tables: %d (Use \\d+ to list them.)"), tuples); + else + printfPQExpBuffer(&buf, _("Number of partitions: %d (Use \\d+ to list them.)"), tuples); printTableAddFooter(&cont, buf.data); } } else { /* display the list of child tables */ - const char *ct = _("Child tables"); + const char *ct = tableinfo.relkind != 'P' ? _("Child tables") : _("Partitions"); int ctw = pg_wcswidth(ct, strlen(ct), pset.encoding); for (i = 0; i < tuples; i++) { - if (i == 0) - printfPQExpBuffer(&buf, "%s: %s", - ct, PQgetvalue(result, i, 0)); + if (tableinfo.relkind != 'P') + { + if (i == 0) + printfPQExpBuffer(&buf, "%s: %s", + ct, PQgetvalue(result, i, 0)); + else + printfPQExpBuffer(&buf, "%*s %s", + ctw, "", PQgetvalue(result, i, 0)); + } else - printfPQExpBuffer(&buf, "%*s %s", - ctw, "", PQgetvalue(result, i, 0)); + { + if (i == 0) + printfPQExpBuffer(&buf, "%s: %s %s", + ct, PQgetvalue(result, i, 0), PQgetvalue(result, i, 1)); + else + printfPQExpBuffer(&buf, "%*s %s %s", + ctw, "", PQgetvalue(result, i, 0), PQgetvalue(result, i, 1)); + } if (i < tuples - 1) appendPQExpBufferChar(&buf, ','); @@ -2658,13 +2820,6 @@ describeOneTableDetails(const char *schemaname, free(seq_values); } - if (modifiers) - { - for (ptr = modifiers; *ptr; ptr++) - free(*ptr); - free(modifiers); - } - if (view_def) free(view_def); @@ -2684,7 +2839,7 @@ add_tablespace_footer(printTableContent *const cont, char relkind, Oid tablespace, const bool newline) { /* relkinds for which we support tablespaces */ - if (relkind == 'r' || relkind == 'm' || relkind == 'i') + if (relkind == 'r' || relkind == 'm' || relkind == 'i' || relkind == 'P') { /* * We ignore the database default tablespace so that users not using @@ -3018,6 +3173,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys " WHEN 'S' THEN '%s'" " WHEN 's' THEN '%s'" " WHEN 'f' THEN '%s'" + " WHEN 'P' THEN '%s'" " END as \"%s\",\n" " pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"", gettext_noop("Schema"), @@ -3029,6 +3185,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys gettext_noop("sequence"), gettext_noop("special"), gettext_noop("foreign table"), + gettext_noop("table"), /* partitioned table */ gettext_noop("Type"), gettext_noop("Owner")); @@ -3067,7 +3224,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys appendPQExpBufferStr(&buf, "\nWHERE c.relkind IN ("); if (showTables) - appendPQExpBufferStr(&buf, "'r',"); + appendPQExpBufferStr(&buf, "'r', 'P',"); if (showViews) appendPQExpBufferStr(&buf, "'v',"); if (showMatViews) @@ -3223,24 +3380,24 @@ listDomains(const char *pattern, bool verbose, bool showSystem) printfPQExpBuffer(&buf, "SELECT n.nspname as \"%s\",\n" " t.typname as \"%s\",\n" - " pg_catalog.format_type(t.typbasetype, t.typtypmod) as \"%s\",\n" - " TRIM(LEADING\n", + " pg_catalog.format_type(t.typbasetype, t.typtypmod) as \"%s\",\n", gettext_noop("Schema"), gettext_noop("Name"), gettext_noop("Type")); if (pset.sversion >= 90100) - appendPQExpBufferStr(&buf, - " COALESCE((SELECT ' collate ' || c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type bt\n" - " WHERE c.oid = t.typcollation AND bt.oid = t.typbasetype AND t.typcollation <> bt.typcollation), '') ||\n"); + appendPQExpBuffer(&buf, + " (SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type bt\n" + " WHERE c.oid = t.typcollation AND bt.oid = t.typbasetype AND t.typcollation <> bt.typcollation) as \"%s\",\n", + gettext_noop("Collation")); appendPQExpBuffer(&buf, - " CASE WHEN t.typnotnull THEN ' not null' ELSE '' END ||\n" - " CASE WHEN t.typdefault IS NOT NULL THEN ' default ' || t.typdefault ELSE '' END\n" - " ) as \"%s\",\n" + " CASE WHEN t.typnotnull THEN 'not null' END as \"%s\",\n" + " t.typdefault as \"%s\",\n" " pg_catalog.array_to_string(ARRAY(\n" " SELECT pg_catalog.pg_get_constraintdef(r.oid, true) FROM pg_catalog.pg_constraint r WHERE t.oid = r.contypid\n" " ), ' ') as \"%s\"", - gettext_noop("Modifier"), + gettext_noop("Nullable"), + gettext_noop("Default"), gettext_noop("Check")); if (verbose) @@ -3548,8 +3705,11 @@ listCollations(const char *pattern, bool verbose, bool showSystem) if (pset.sversion < 90100) { - psql_error("The server (version %d.%d) does not support collations.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support collations.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -3680,8 +3840,11 @@ listTSParsers(const char *pattern, bool verbose) if (pset.sversion < 80300) { - psql_error("The server (version %d.%d) does not support full text search.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support full text search.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -3915,8 +4078,11 @@ listTSDictionaries(const char *pattern, bool verbose) if (pset.sversion < 80300) { - psql_error("The server (version %d.%d) does not support full text search.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support full text search.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -3983,8 +4149,11 @@ listTSTemplates(const char *pattern, bool verbose) if (pset.sversion < 80300) { - psql_error("The server (version %d.%d) does not support full text search.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support full text search.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -4051,8 +4220,11 @@ listTSConfigs(const char *pattern, bool verbose) if (pset.sversion < 80300) { - psql_error("The server (version %d.%d) does not support full text search.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support full text search.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -4249,8 +4421,11 @@ listForeignDataWrappers(const char *pattern, bool verbose) if (pset.sversion < 80400) { - psql_error("The server (version %d.%d) does not support foreign-data wrappers.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support foreign-data wrappers.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -4329,8 +4504,11 @@ listForeignServers(const char *pattern, bool verbose) if (pset.sversion < 80400) { - psql_error("The server (version %d.%d) does not support foreign servers.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support foreign servers.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -4408,8 +4586,11 @@ listUserMappings(const char *pattern, bool verbose) if (pset.sversion < 80400) { - psql_error("The server (version %d.%d) does not support user mappings.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support user mappings.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -4466,8 +4647,11 @@ listForeignTables(const char *pattern, bool verbose) if (pset.sversion < 90100) { - psql_error("The server (version %d.%d) does not support foreign tables.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support foreign tables.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -4541,8 +4725,11 @@ listExtensions(const char *pattern) if (pset.sversion < 90100) { - psql_error("The server (version %d.%d) does not support extensions.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support extensions.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -4595,8 +4782,11 @@ listExtensionContents(const char *pattern) if (pset.sversion < 90100) { - psql_error("The server (version %d.%d) does not support extensions.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support extensions.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -4688,6 +4878,266 @@ listOneExtensionContents(const char *extname, const char *oid) return true; } +/* \dRp + * Lists publications. + * + * Takes an optional regexp to select particular publications + */ +bool +listPublications(const char *pattern) +{ + PQExpBufferData buf; + PGresult *res; + printQueryOpt myopt = pset.popt; + static const bool translate_columns[] = {false, false, false, false, false}; + + if (pset.sversion < 100000) + { + char sverbuf[32]; + psql_error("The server (version %s) does not support publications.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); + return true; + } + + initPQExpBuffer(&buf); + + printfPQExpBuffer(&buf, + "SELECT pubname AS \"%s\",\n" + " pg_catalog.pg_get_userbyid(pubowner) AS \"%s\",\n" + " pubinsert AS \"%s\",\n" + " pubupdate AS \"%s\",\n" + " pubdelete AS \"%s\"\n", + gettext_noop("Name"), + gettext_noop("Owner"), + gettext_noop("Inserts"), + gettext_noop("Updates"), + gettext_noop("Deletes")); + + appendPQExpBufferStr(&buf, + "\nFROM pg_catalog.pg_publication\n"); + + processSQLNamePattern(pset.db, &buf, pattern, false, false, + NULL, "pubname", NULL, + NULL); + + appendPQExpBufferStr(&buf, "ORDER BY 1;"); + + res = PSQLexec(buf.data); + termPQExpBuffer(&buf); + if (!res) + return false; + + myopt.nullPrint = NULL; + myopt.title = _("List of publications"); + myopt.translate_header = true; + myopt.translate_columns = translate_columns; + myopt.n_translate_columns = lengthof(translate_columns); + + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); + + PQclear(res); + + return true; +} + +/* \dRp+ + * Describes publications including the contents. + * + * Takes an optional regexp to select particular publications + */ +bool +describePublications(const char *pattern) +{ + PQExpBufferData buf; + int i; + PGresult *res; + + if (pset.sversion < 100000) + { + char sverbuf[32]; + psql_error("The server (version %s) does not support publications.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); + return true; + } + + initPQExpBuffer(&buf); + + printfPQExpBuffer(&buf, + "SELECT oid, pubname, puballtables, pubinsert,\n" + " pubupdate, pubdelete\n" + "FROM pg_catalog.pg_publication\n"); + + processSQLNamePattern(pset.db, &buf, pattern, false, false, + NULL, "pubname", NULL, + NULL); + + appendPQExpBufferStr(&buf, "ORDER BY 2;"); + + res = PSQLexec(buf.data); + if (!res) + { + termPQExpBuffer(&buf); + return false; + } + + for (i = 0; i < PQntuples(res); i++) + { + const char align = 'l'; + int ncols = 3; + int nrows = 1; + int tables = 0; + PGresult *tabres; + char *pubid = PQgetvalue(res, i, 0); + char *pubname = PQgetvalue(res, i, 1); + bool puballtables = strcmp(PQgetvalue(res, i, 2), "t") == 0; + int j; + PQExpBufferData title; + printTableOpt myopt = pset.popt.topt; + printTableContent cont; + + initPQExpBuffer(&title); + printfPQExpBuffer(&title, _("Publication %s"), pubname); + printTableInit(&cont, &myopt, title.data, ncols, nrows); + + printTableAddHeader(&cont, gettext_noop("Inserts"), true, align); + printTableAddHeader(&cont, gettext_noop("Updates"), true, align); + printTableAddHeader(&cont, gettext_noop("Deletes"), true, align); + + printTableAddCell(&cont, PQgetvalue(res, i, 3), false, false); + printTableAddCell(&cont, PQgetvalue(res, i, 4), false, false); + printTableAddCell(&cont, PQgetvalue(res, i, 5), false, false); + + if (puballtables) + printfPQExpBuffer(&buf, + "SELECT n.nspname, c.relname\n" + "FROM pg_catalog.pg_class c,\n" + " pg_catalog.pg_namespace n\n" + "WHERE c.relnamespace = n.oid\n" + " AND c.relkind = 'r'\n" + " AND n.nspname <> 'pg_catalog'\n" + " AND n.nspname <> 'information_schema'\n" + "ORDER BY 1,2"); + else + printfPQExpBuffer(&buf, + "SELECT n.nspname, c.relname\n" + "FROM pg_catalog.pg_class c,\n" + " pg_catalog.pg_namespace n,\n" + " pg_catalog.pg_publication_rel pr\n" + "WHERE c.relnamespace = n.oid\n" + " AND c.oid = pr.prrelid\n" + " AND pr.prpubid = '%s'\n" + "ORDER BY 1,2", pubid); + + tabres = PSQLexec(buf.data); + if (!tabres) + { + printTableCleanup(&cont); + PQclear(res); + termPQExpBuffer(&buf); + termPQExpBuffer(&title); + return false; + } + else + tables = PQntuples(tabres); + + if (tables > 0) + printTableAddFooter(&cont, _("Tables:")); + + for (j = 0; j < tables; j++) + { + printfPQExpBuffer(&buf, " \"%s.%s\"", + PQgetvalue(tabres, j, 0), + PQgetvalue(tabres, j, 1)); + + printTableAddFooter(&cont, buf.data); + } + PQclear(tabres); + + printTable(&cont, pset.queryFout, false, pset.logfile); + printTableCleanup(&cont); + + termPQExpBuffer(&title); + } + + termPQExpBuffer(&buf); + PQclear(res); + + return true; +} + +/* \dRs + * Describes subscriptions. + * + * Takes an optional regexp to select particular subscriptions + */ +bool +describeSubscriptions(const char *pattern, bool verbose) +{ + PQExpBufferData buf; + PGresult *res; + printQueryOpt myopt = pset.popt; + static const bool translate_columns[] = {false, false, false, false, false}; + + if (pset.sversion < 100000) + { + char sverbuf[32]; + psql_error("The server (version %s) does not support subscriptions.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); + return true; + } + + initPQExpBuffer(&buf); + + printfPQExpBuffer(&buf, + "SELECT subname AS \"%s\"\n" + ", pg_catalog.pg_get_userbyid(subowner) AS \"%s\"\n" + ", subenabled AS \"%s\"\n" + ", subpublications AS \"%s\"\n", + gettext_noop("Name"), + gettext_noop("Owner"), + gettext_noop("Enabled"), + gettext_noop("Publication")); + + if (verbose) + { + appendPQExpBuffer(&buf, + ", subconninfo AS \"%s\"\n", + gettext_noop("Conninfo")); + } + + /* Only display subscritpions in current database. */ + appendPQExpBufferStr(&buf, + "FROM pg_catalog.pg_subscription\n" + "WHERE subdbid = (SELECT oid\n" + " FROM pg_catalog.pg_database\n" + " WHERE datname = current_database())"); + + processSQLNamePattern(pset.db, &buf, pattern, true, false, + NULL, "subname", NULL, + NULL); + + appendPQExpBufferStr(&buf, "ORDER BY 1;"); + + res = PSQLexec(buf.data); + termPQExpBuffer(&buf); + if (!res) + return false; + + myopt.nullPrint = NULL; + myopt.title = _("List of subscriptions"); + myopt.translate_header = true; + myopt.translate_columns = translate_columns; + myopt.n_translate_columns = lengthof(translate_columns); + + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); + + PQclear(res); + return true; +} + /* * printACLColumn * diff --git a/src/bin/psql/describe.h b/src/bin/psql/describe.h index 20a650861b..074553e133 100644 --- a/src/bin/psql/describe.h +++ b/src/bin/psql/describe.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/describe.h */ @@ -102,4 +102,13 @@ extern bool listExtensionContents(const char *pattern); /* \dy */ extern bool listEventTriggers(const char *pattern, bool verbose); +/* \dRp */ +bool listPublications(const char *pattern); + +/* \dRp+ */ +bool describePublications(const char *pattern); + +/* \dRs */ +bool describeSubscriptions(const char *pattern, bool verbose); + #endif /* DESCRIBE_H */ diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index efc845414f..53656294da 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/help.c */ @@ -69,7 +69,7 @@ usage(unsigned short int pager) * Keep this line count in sync with the number of lines printed below! * Use "psql --help=options | wc" to count correctly. */ - output = PageOutput(60, pager ? &(pset.popt.topt) : NULL); + output = PageOutput(61, pager ? &(pset.popt.topt) : NULL); fprintf(output, _("psql is the PostgreSQL interactive terminal.\n\n")); fprintf(output, _("Usage:\n")); @@ -168,7 +168,7 @@ slashUsage(unsigned short int pager) * Use "psql --help=commands | wc" to count correctly. It's okay to count * the USE_READLINE line even in builds without that. */ - output = PageOutput(111, pager ? &(pset.popt.topt) : NULL); + output = PageOutput(113, pager ? &(pset.popt.topt) : NULL); fprintf(output, _("General\n")); fprintf(output, _(" \\copyright show PostgreSQL usage and distribution terms\n")); @@ -241,6 +241,8 @@ slashUsage(unsigned short int pager) fprintf(output, _(" \\dO[S+] [PATTERN] list collations\n")); fprintf(output, _(" \\dp [PATTERN] list table, view, and sequence access privileges\n")); fprintf(output, _(" \\drds [PATRN1 [PATRN2]] list per-database role settings\n")); + fprintf(output, _(" \\dRp[+] [PATTERN] list replication publications\n")); + fprintf(output, _(" \\dRs[+] [PATTERN] list replication subscriptions\n")); fprintf(output, _(" \\ds[S+] [PATTERN] list sequences\n")); fprintf(output, _(" \\dt[S+] [PATTERN] list tables\n")); fprintf(output, _(" \\dT[S+] [PATTERN] list data types\n")); @@ -325,7 +327,7 @@ helpVariables(unsigned short int pager) * Windows builds currently print one more line than non-Windows builds. * Using the larger number is fine. */ - output = PageOutput(87, pager ? &(pset.popt.topt) : NULL); + output = PageOutput(88, pager ? &(pset.popt.topt) : NULL); fprintf(output, _("List of specially treated variables\n\n")); @@ -572,7 +574,7 @@ print_copyright(void) puts( "PostgreSQL Database Management System\n" "(formerly known as Postgres, then as Postgres95)\n\n" - "Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group\n\n" + "Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group\n\n" "Portions Copyright (c) 1994, The Regents of the University of California\n\n" "Permission to use, copy, modify, and distribute this software and its\n" "documentation for any purpose, without fee, and without a written agreement\n" diff --git a/src/bin/psql/help.h b/src/bin/psql/help.h index 0c8062f72f..3ef4094476 100644 --- a/src/bin/psql/help.h +++ b/src/bin/psql/help.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/help.h */ diff --git a/src/bin/psql/input.c b/src/bin/psql/input.c index 2359b11dcd..972bea4cbf 100644 --- a/src/bin/psql/input.c +++ b/src/bin/psql/input.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/input.c */ @@ -411,7 +411,7 @@ saveHistory(char *fname, int max_lines) /* * Suppressing the write attempt when HISTFILE is set to /dev/null may - * look like a negligible optimization, but it's necessary on e.g. Darwin, + * look like a negligible optimization, but it's necessary on e.g. macOS, * where write_history will fail because it tries to chmod the target * file. */ diff --git a/src/bin/psql/input.h b/src/bin/psql/input.h index eaab08ec8b..f40561459d 100644 --- a/src/bin/psql/input.h +++ b/src/bin/psql/input.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/input.h */ diff --git a/src/bin/psql/large_obj.c b/src/bin/psql/large_obj.c index 38dea32582..2ad0a4bb83 100644 --- a/src/bin/psql/large_obj.c +++ b/src/bin/psql/large_obj.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/large_obj.c */ diff --git a/src/bin/psql/large_obj.h b/src/bin/psql/large_obj.h index 9bddbddbee..7d74d5fdb7 100644 --- a/src/bin/psql/large_obj.h +++ b/src/bin/psql/large_obj.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/large_obj.h */ diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c index 37dfa4d0e3..bb306a4327 100644 --- a/src/bin/psql/mainloop.c +++ b/src/bin/psql/mainloop.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/mainloop.c */ diff --git a/src/bin/psql/mainloop.h b/src/bin/psql/mainloop.h index fd9723a25c..228a5e085e 100644 --- a/src/bin/psql/mainloop.h +++ b/src/bin/psql/mainloop.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/mainloop.h */ diff --git a/src/bin/psql/prompt.c b/src/bin/psql/prompt.c index fb08d67390..f7930c4a83 100644 --- a/src/bin/psql/prompt.c +++ b/src/bin/psql/prompt.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/prompt.c */ diff --git a/src/bin/psql/prompt.h b/src/bin/psql/prompt.h index d7e76dc181..977e754293 100644 --- a/src/bin/psql/prompt.h +++ b/src/bin/psql/prompt.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/prompt.h */ diff --git a/src/bin/psql/psqlscanslash.h b/src/bin/psql/psqlscanslash.h index f078f698e8..266e93af44 100644 --- a/src/bin/psql/psqlscanslash.h +++ b/src/bin/psql/psqlscanslash.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/psqlscanslash.h */ diff --git a/src/bin/psql/psqlscanslash.l b/src/bin/psql/psqlscanslash.l index 86832a8653..5b7953bf7b 100644 --- a/src/bin/psql/psqlscanslash.l +++ b/src/bin/psql/psqlscanslash.l @@ -8,7 +8,7 @@ * * See fe_utils/psqlscan_int.h for additional commentary. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h index 8cfe9d207a..4c7c3b1fa3 100644 --- a/src/bin/psql/settings.h +++ b/src/bin/psql/settings.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/settings.h */ diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c index 111593cd9d..85aac4a165 100644 --- a/src/bin/psql/startup.c +++ b/src/bin/psql/startup.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/startup.c */ @@ -103,7 +103,8 @@ main(int argc, char *argv[]) { struct adhoc_opts options; int successResult; - char *password = NULL; + bool have_password = false; + char password[100]; char *password_prompt = NULL; bool new_pass; @@ -210,7 +211,10 @@ main(int argc, char *argv[]) options.username); if (pset.getPassword == TRI_YES) - password = simple_prompt(password_prompt, 100, false); + { + simple_prompt(password_prompt, password, sizeof(password), false); + have_password = true; + } /* loop until we have a password if requested by backend */ do @@ -226,7 +230,7 @@ main(int argc, char *argv[]) keywords[2] = "user"; values[2] = options.username; keywords[3] = "password"; - values[3] = password; + values[3] = have_password ? password : NULL; keywords[4] = "dbname"; /* see do_connect() */ values[4] = (options.list_dbs && options.dbname == NULL) ? "postgres" : options.dbname; @@ -244,16 +248,16 @@ main(int argc, char *argv[]) if (PQstatus(pset.db) == CONNECTION_BAD && PQconnectionNeedsPassword(pset.db) && - password == NULL && + !have_password && pset.getPassword != TRI_NO) { PQfinish(pset.db); - password = simple_prompt(password_prompt, 100, false); + simple_prompt(password_prompt, password, sizeof(password), false); + have_password = true; new_pass = true; } } while (new_pass); - free(password); free(password_prompt); if (PQstatus(pset.db) == CONNECTION_BAD) diff --git a/src/bin/psql/stringutils.c b/src/bin/psql/stringutils.c index 9c6034cf82..145069ae13 100644 --- a/src/bin/psql/stringutils.c +++ b/src/bin/psql/stringutils.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/stringutils.c */ diff --git a/src/bin/psql/stringutils.h b/src/bin/psql/stringutils.h index 8fcad3cbac..360ee030a1 100644 --- a/src/bin/psql/stringutils.h +++ b/src/bin/psql/stringutils.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/stringutils.h */ diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 8469d9ff03..d6fffcf42f 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/tab-complete.c */ @@ -202,6 +202,31 @@ do { \ matches = completion_matches(text, complete_from_query); \ } while (0) +#define COMPLETE_WITH_ENUM_VALUE(type) \ +do { \ + char *_completion_schema; \ + char *_completion_type; \ +\ + _completion_schema = strtokx(type, " \t\n\r", ".", "\"", 0, \ + false, false, pset.encoding); \ + (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \ + false, false, pset.encoding); \ + _completion_type = strtokx(NULL, " \t\n\r", ".", "\"", 0, \ + false, false, pset.encoding); \ + if (_completion_type == NULL)\ + { \ + completion_charp = Query_for_list_of_enum_values; \ + completion_info_charp = type; \ + } \ + else \ + { \ + completion_charp = Query_for_list_of_enum_values_with_schema; \ + completion_info_charp = _completion_type; \ + completion_info_charp2 = _completion_schema; \ + } \ + matches = completion_matches(text, complete_from_query); \ +} while (0) + #define COMPLETE_WITH_FUNCTION_ARG(function) \ do { \ char *_completion_schema; \ @@ -427,7 +452,7 @@ static const SchemaQuery Query_for_list_of_tables = { /* catname */ "pg_catalog.pg_class c", /* selcondition */ - "c.relkind IN ('r')", + "c.relkind IN ('r', 'P')", /* viscondition */ "pg_catalog.pg_table_is_visible(c.oid)", /* namespace */ @@ -458,7 +483,7 @@ static const SchemaQuery Query_for_list_of_updatables = { /* catname */ "pg_catalog.pg_class c", /* selcondition */ - "c.relkind IN ('r', 'f', 'v')", + "c.relkind IN ('r', 'f', 'v', 'P')", /* viscondition */ "pg_catalog.pg_table_is_visible(c.oid)", /* namespace */ @@ -488,7 +513,7 @@ static const SchemaQuery Query_for_list_of_tsvmf = { /* catname */ "pg_catalog.pg_class c", /* selcondition */ - "c.relkind IN ('r', 'S', 'v', 'm', 'f')", + "c.relkind IN ('r', 'S', 'v', 'm', 'f', 'P')", /* viscondition */ "pg_catalog.pg_table_is_visible(c.oid)", /* namespace */ @@ -598,9 +623,31 @@ static const SchemaQuery Query_for_list_of_matviews = { " AND (pg_catalog.quote_ident(nspname)='%s' "\ " OR '\"' || nspname || '\"' ='%s') " +#define Query_for_list_of_enum_values \ +"SELECT pg_catalog.quote_literal(enumlabel) "\ +" FROM pg_catalog.pg_enum e, pg_catalog.pg_type t "\ +" WHERE t.oid = e.enumtypid "\ +" AND substring(pg_catalog.quote_literal(enumlabel),1,%d)='%s' "\ +" AND (pg_catalog.quote_ident(typname)='%s' "\ +" OR '\"' || typname || '\"'='%s') "\ +" AND pg_catalog.pg_type_is_visible(t.oid)" + +#define Query_for_list_of_enum_values_with_schema \ +"SELECT pg_catalog.quote_literal(enumlabel) "\ +" FROM pg_catalog.pg_enum e, pg_catalog.pg_type t, pg_catalog.pg_namespace n "\ +" WHERE t.oid = e.enumtypid "\ +" AND n.oid = t.typnamespace "\ +" AND substring(pg_catalog.quote_literal(enumlabel),1,%d)='%s' "\ +" AND (pg_catalog.quote_ident(typname)='%s' "\ +" OR '\"' || typname || '\"'='%s') "\ +" AND (pg_catalog.quote_ident(nspname)='%s' "\ +" OR '\"' || nspname || '\"' ='%s') " + #define Query_for_list_of_template_databases \ -"SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\ -" WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s' AND datistemplate" +"SELECT pg_catalog.quote_ident(d.datname) "\ +" FROM pg_catalog.pg_database d "\ +" WHERE substring(pg_catalog.quote_ident(d.datname),1,%d)='%s' "\ +" AND (d.datistemplate OR pg_catalog.pg_has_role(d.datdba, 'USAGE'))" #define Query_for_list_of_databases \ "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\ @@ -820,6 +867,13 @@ static const SchemaQuery Query_for_list_of_matviews = { " WHERE (%d = pg_catalog.length('%s'))"\ " AND pg_catalog.quote_ident(name)='%s'" +/* the silly-looking length condition is just to eat up the current word */ +#define Query_for_list_of_available_extension_versions_with_TO \ +" SELECT 'TO ' || pg_catalog.quote_ident(version) "\ +" FROM pg_catalog.pg_available_extension_versions "\ +" WHERE (%d = pg_catalog.length('%s'))"\ +" AND pg_catalog.quote_ident(name)='%s'" + #define Query_for_list_of_prepared_statements \ " SELECT pg_catalog.quote_ident(name) "\ " FROM pg_catalog.pg_prepared_statements "\ @@ -906,11 +960,13 @@ static const pgsql_thing_t words_after_create[] = { {"OWNED", NULL, NULL, THING_NO_CREATE}, /* for DROP OWNED BY ... */ {"PARSER", Query_for_list_of_ts_parsers, NULL, THING_NO_SHOW}, {"POLICY", NULL, NULL}, + {"PUBLICATION", NULL, NULL}, {"ROLE", Query_for_list_of_roles}, {"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"}, {"SCHEMA", Query_for_list_of_schemas}, {"SEQUENCE", NULL, &Query_for_list_of_sequences}, {"SERVER", Query_for_list_of_servers}, + {"SUBSCRIPTION", NULL, NULL}, {"TABLE", NULL, &Query_for_list_of_tables}, {"TABLESPACE", Query_for_list_of_tablespaces}, {"TEMP", NULL, NULL, THING_NO_DROP}, /* for CREATE TEMP TABLE ... */ @@ -1353,8 +1409,8 @@ psql_completion(const char *text, int start, int end) {"AGGREGATE", "COLLATION", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN", "EVENT TRIGGER", "EXTENSION", "FOREIGN DATA WRAPPER", "FOREIGN TABLE", "FUNCTION", "GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "MATERIALIZED VIEW", "OPERATOR", - "POLICY", "ROLE", "RULE", "SCHEMA", "SERVER", "SEQUENCE", "SYSTEM", "TABLE", - "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE", + "POLICY", "PUBLICATION", "ROLE", "RULE", "SCHEMA", "SERVER", "SEQUENCE", + "SUBSCRIPTION", "SYSTEM", "TABLE", "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE", "USER", "USER MAPPING FOR", "VIEW", NULL}; COMPLETE_WITH_LIST(list_ALTER); @@ -1379,7 +1435,26 @@ psql_completion(const char *text, int start, int end) else COMPLETE_WITH_FUNCTION_ARG(prev2_wd); } - + /* ALTER PUBLICATION ...*/ + else if (Matches3("ALTER","PUBLICATION",MatchAny)) + { + COMPLETE_WITH_LIST5("WITH", "ADD TABLE", "SET TABLE", "DROP TABLE", "OWNER TO"); + } + /* ALTER PUBLICATION .. WITH ( ... */ + else if (HeadMatches3("ALTER", "PUBLICATION",MatchAny) && TailMatches2("WITH", "(")) + { + COMPLETE_WITH_LIST6("PUBLISH INSERT", "NOPUBLISH INSERT", "PUBLISH UPDATE", + "NOPUBLISH UPDATE", "PUBLISH DELETE", "NOPUBLISH DELETE"); + } + /* ALTER SUBSCRIPTION ... */ + else if (Matches3("ALTER","SUBSCRIPTION",MatchAny)) + { + COMPLETE_WITH_LIST6("WITH", "CONNECTION", "SET PUBLICATION", "ENABLE", "DISABLE", "OWNER TO"); + } + else if (HeadMatches3("ALTER", "SUBSCRIPTION", MatchAny) && TailMatches2("WITH", "(")) + { + COMPLETE_WITH_CONST("SLOT NAME"); + } /* ALTER SCHEMA */ else if (Matches3("ALTER", "SCHEMA", MatchAny)) COMPLETE_WITH_LIST2("OWNER TO", "RENAME TO"); @@ -1414,6 +1489,20 @@ psql_completion(const char *text, int start, int end) else if (Matches3("ALTER", "EXTENSION", MatchAny)) COMPLETE_WITH_LIST4("ADD", "DROP", "UPDATE", "SET SCHEMA"); + /* ALTER EXTENSION UPDATE */ + else if (Matches4("ALTER", "EXTENSION", MatchAny, "UPDATE")) + { + completion_info_charp = prev2_wd; + COMPLETE_WITH_QUERY(Query_for_list_of_available_extension_versions_with_TO); + } + + /* ALTER EXTENSION UPDATE TO */ + else if (Matches5("ALTER", "EXTENSION", MatchAny, "UPDATE", "TO")) + { + completion_info_charp = prev3_wd; + COMPLETE_WITH_QUERY(Query_for_list_of_available_extension_versions); + } + /* ALTER FOREIGN */ else if (Matches2("ALTER", "FOREIGN")) COMPLETE_WITH_LIST2("DATA WRAPPER", "TABLE"); @@ -1502,13 +1591,31 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_CONST("PASSWORD"); /* ALTER DEFAULT PRIVILEGES */ else if (Matches3("ALTER", "DEFAULT", "PRIVILEGES")) - COMPLETE_WITH_LIST3("FOR ROLE", "FOR USER", "IN SCHEMA"); + COMPLETE_WITH_LIST2("FOR ROLE", "IN SCHEMA"); /* ALTER DEFAULT PRIVILEGES FOR */ else if (Matches4("ALTER", "DEFAULT", "PRIVILEGES", "FOR")) - COMPLETE_WITH_LIST2("ROLE", "USER"); - /* ALTER DEFAULT PRIVILEGES { FOR ROLE ... | IN SCHEMA ... } */ - else if (Matches6("ALTER", "DEFAULT", "PRIVILEGES", "FOR", "ROLE|USER", MatchAny) || - Matches6("ALTER", "DEFAULT", "PRIVILEGES", "IN", "SCHEMA", MatchAny)) + COMPLETE_WITH_CONST("ROLE"); + /* ALTER DEFAULT PRIVILEGES IN */ + else if (Matches4("ALTER", "DEFAULT", "PRIVILEGES", "IN")) + COMPLETE_WITH_CONST("SCHEMA"); + /* ALTER DEFAULT PRIVILEGES FOR ROLE|USER ... */ + else if (Matches6("ALTER", "DEFAULT", "PRIVILEGES", "FOR", "ROLE|USER", + MatchAny)) + COMPLETE_WITH_LIST3("GRANT", "REVOKE", "IN SCHEMA"); + /* ALTER DEFAULT PRIVILEGES IN SCHEMA ... */ + else if (Matches6("ALTER", "DEFAULT", "PRIVILEGES", "IN", "SCHEMA", + MatchAny)) + COMPLETE_WITH_LIST3("GRANT", "REVOKE", "FOR ROLE"); + /* ALTER DEFAULT PRIVILEGES IN SCHEMA ... FOR */ + else if (Matches7("ALTER", "DEFAULT", "PRIVILEGES", "IN", "SCHEMA", + MatchAny, "FOR")) + COMPLETE_WITH_CONST("ROLE"); + /* ALTER DEFAULT PRIVILEGES FOR ROLE|USER ... IN SCHEMA ... */ + /* ALTER DEFAULT PRIVILEGES IN SCHEMA ... FOR ROLE|USER ... */ + else if (Matches9("ALTER", "DEFAULT", "PRIVILEGES", "FOR", "ROLE|USER", + MatchAny, "IN", "SCHEMA", MatchAny) || + Matches9("ALTER", "DEFAULT", "PRIVILEGES", "IN", "SCHEMA", + MatchAny, "FOR", "ROLE|USER", MatchAny)) COMPLETE_WITH_LIST2("GRANT", "REVOKE"); /* ALTER DOMAIN */ else if (Matches3("ALTER", "DOMAIN", MatchAny)) @@ -1736,7 +1843,7 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_LIST4("PLAIN", "EXTERNAL", "EXTENDED", "MAIN"); /* ALTER TABLE ALTER [COLUMN] DROP */ else if (Matches7("ALTER", "TABLE", MatchAny, "ALTER", "COLUMN", MatchAny, "DROP") || - Matches8("ALTER", "TABLE", MatchAny, "TABLE", MatchAny, "ALTER", MatchAny, "DROP")) + Matches6("ALTER", "TABLE", MatchAny, "ALTER", MatchAny, "DROP")) COMPLETE_WITH_LIST2("DEFAULT", "NOT NULL"); else if (Matches4("ALTER", "TABLE", MatchAny, "CLUSTER")) COMPLETE_WITH_CONST("ON"); @@ -1849,11 +1956,10 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_LIST2("ATTRIBUTE", "VALUE"); /* ALTER TYPE RENAME */ else if (Matches4("ALTER", "TYPE", MatchAny, "RENAME")) - COMPLETE_WITH_LIST2("ATTRIBUTE", "TO"); - /* ALTER TYPE xxx RENAME ATTRIBUTE yyy */ - else if (Matches6("ALTER", "TYPE", MatchAny, "RENAME", "ATTRIBUTE", MatchAny)) + COMPLETE_WITH_LIST3("ATTRIBUTE", "TO", "VALUE"); + /* ALTER TYPE xxx RENAME (ATTRIBUTE|VALUE) yyy */ + else if (Matches6("ALTER", "TYPE", MatchAny, "RENAME", "ATTRIBUTE|VALUE", MatchAny)) COMPLETE_WITH_CONST("TO"); - /* * If we have ALTER TYPE ALTER/DROP/RENAME ATTRIBUTE, provide list * of attributes @@ -1873,8 +1979,17 @@ psql_completion(const char *text, int start, int end) else if (Matches5("ALTER", "GROUP", MatchAny, "ADD|DROP", "USER")) COMPLETE_WITH_QUERY(Query_for_list_of_roles); -/* BEGIN, END, ABORT */ - else if (Matches1("BEGIN|END|ABORT")) + /* + * If we have ALTER TYPE RENAME VALUE, provide list of enum values + */ + else if (Matches5("ALTER", "TYPE", MatchAny, "RENAME", "VALUE")) + COMPLETE_WITH_ENUM_VALUE(prev3_wd); + +/* BEGIN */ + else if (Matches1("BEGIN")) + COMPLETE_WITH_LIST6("WORK", "TRANSACTION", "ISOLATION LEVEL", "READ", "DEFERRABLE", "NOT DEFERRABLE"); +/* END, ABORT */ + else if (Matches1("END|ABORT")) COMPLETE_WITH_LIST2("WORK", "TRANSACTION"); /* COMMIT */ else if (Matches1("COMMIT")) @@ -2086,9 +2201,15 @@ psql_completion(const char *text, int start, int end) /* Complete "CREATE POLICY ON " */ else if (Matches4("CREATE", "POLICY", MatchAny, "ON")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); - /* Complete "CREATE POLICY ON
FOR|TO|USING|WITH CHECK" */ + /* Complete "CREATE POLICY ON
AS|FOR|TO|USING|WITH CHECK" */ else if (Matches5("CREATE", "POLICY", MatchAny, "ON", MatchAny)) - COMPLETE_WITH_LIST4("FOR", "TO", "USING (", "WITH CHECK ("); + COMPLETE_WITH_LIST5("AS", "FOR", "TO", "USING (", "WITH CHECK ("); + /* CREATE POLICY ON
AS PERMISSIVE|RESTRICTIVE */ + else if (Matches6("CREATE", "POLICY", MatchAny, "ON", MatchAny, "AS")) + COMPLETE_WITH_LIST2("PERMISSIVE", "RESTRICTIVE"); + /* CREATE POLICY ON
AS PERMISSIVE|RESTRICTIVE FOR|TO|USING|WITH CHECK */ + else if (Matches7("CREATE", "POLICY", MatchAny, "ON", MatchAny, "AS", MatchAny)) + COMPLETE_WITH_LIST4("FOR", "TO", "USING", "WITH CHECK"); /* CREATE POLICY ON
FOR ALL|SELECT|INSERT|UPDATE|DELETE */ else if (Matches6("CREATE", "POLICY", MatchAny, "ON", MatchAny, "FOR")) COMPLETE_WITH_LIST5("ALL", "SELECT", "INSERT", "UPDATE", "DELETE"); @@ -2107,6 +2228,39 @@ psql_completion(const char *text, int start, int end) /* Complete "CREATE POLICY ON
USING (" */ else if (Matches6("CREATE", "POLICY", MatchAny, "ON", MatchAny, "USING")) COMPLETE_WITH_CONST("("); + /* CREATE POLICY ON
AS PERMISSIVE|RESTRICTIVE FOR ALL|SELECT|INSERT|UPDATE|DELETE */ + else if (Matches8("CREATE", "POLICY", MatchAny, "ON", MatchAny, "AS", MatchAny, "FOR")) + COMPLETE_WITH_LIST5("ALL", "SELECT", "INSERT", "UPDATE", "DELETE"); + /* Complete "CREATE POLICY ON
AS PERMISSIVE|RESTRICTIVE FOR INSERT TO|WITH CHECK" */ + else if (Matches9("CREATE", "POLICY", MatchAny, "ON", MatchAny, "AS", MatchAny, "FOR", "INSERT")) + COMPLETE_WITH_LIST2("TO", "WITH CHECK ("); + /* Complete "CREATE POLICY ON
AS PERMISSIVE|RESTRICTIVE FOR SELECT|DELETE TO|USING" */ + else if (Matches9("CREATE", "POLICY", MatchAny, "ON", MatchAny, "AS", MatchAny, "FOR", "SELECT|DELETE")) + COMPLETE_WITH_LIST2("TO", "USING ("); + /* CREATE POLICY ON
AS PERMISSIVE|RESTRICTIVE FOR ALL|UPDATE TO|USING|WITH CHECK */ + else if (Matches9("CREATE", "POLICY", MatchAny, "ON", MatchAny, "AS", MatchAny, "FOR", "ALL|UPDATE")) + COMPLETE_WITH_LIST3("TO", "USING (", "WITH CHECK ("); + /* Complete "CREATE POLICY ON
AS PERMISSIVE|RESTRICTIVE TO " */ + else if (Matches8("CREATE", "POLICY", MatchAny, "ON", MatchAny, "AS", MatchAny, "TO")) + COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles); + /* Complete "CREATE POLICY ON
AS PERMISSIVE|RESTRICTIVE USING (" */ + else if (Matches8("CREATE", "POLICY", MatchAny, "ON", MatchAny, "AS", MatchAny, "USING")) + COMPLETE_WITH_CONST("("); + + +/* CREATE PUBLICATION */ + else if (Matches3("CREATE", "PUBLICATION", MatchAny)) + COMPLETE_WITH_LIST3("FOR TABLE", "FOR ALL TABLES", "WITH ("); + else if (Matches4("CREATE", "PUBLICATION", MatchAny, "FOR")) + COMPLETE_WITH_LIST2("TABLE", "ALL TABLES"); + /* Complete "CREATE PUBLICATION FOR TABLE
" */ + else if (Matches4("CREATE", "PUBLICATION", MatchAny, "FOR TABLE")) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); + /* Complete "CREATE PUBLICATION [...] WITH" */ + else if (HeadMatches2("CREATE", "PUBLICATION") && TailMatches2("WITH", "(")) + COMPLETE_WITH_LIST2("PUBLISH", "NOPUBLISH"); + else if (HeadMatches2("CREATE", "PUBLICATION") && TailMatches3("WITH", "(", MatchAny)) + COMPLETE_WITH_LIST3("INSERT", "UPDATE", "DELETE"); /* CREATE RULE */ /* Complete "CREATE RULE " with "AS ON" */ @@ -2159,6 +2313,16 @@ psql_completion(const char *text, int start, int end) else if (Matches5("CREATE", "TEXT", "SEARCH", "CONFIGURATION", MatchAny)) COMPLETE_WITH_CONST("("); +/* CREATE SUBSCRIPTION */ + else if (Matches3("CREATE", "SUBSCRIPTION", MatchAny)) + COMPLETE_WITH_CONST("CONNECTION"); + else if (Matches5("CREATE", "SUBSCRIPTION", MatchAny, "CONNECTION",MatchAny)) + COMPLETE_WITH_CONST("PUBLICATION"); + /* Complete "CREATE SUBSCRIPTION ... WITH ( " */ + else if (HeadMatches2("CREATE", "SUBSCRIPTION") && TailMatches2("WITH", "(")) + COMPLETE_WITH_LIST5("ENABLED", "DISABLED", "CREATE SLOT", + "NOCREATE SLOT", "SLOT NAME"); + /* CREATE TRIGGER --- is allowed inside CREATE SCHEMA, so use TailMatches */ /* complete CREATE TRIGGER with BEFORE,AFTER,INSTEAD OF */ else if (TailMatches3("CREATE", "TRIGGER", MatchAny)) @@ -2183,9 +2347,43 @@ psql_completion(const char *text, int start, int end) /* complete CREATE TRIGGER ... INSTEAD OF event ON with a list of views */ else if (TailMatches7("CREATE", "TRIGGER", MatchAny, "INSTEAD", "OF", MatchAny, "ON")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL); + else if (HeadMatches2("CREATE", "TRIGGER") && TailMatches2("ON", MatchAny)) + COMPLETE_WITH_LIST7("NOT DEFERRABLE", "DEFERRABLE", "INITIALLY", + "REFERENCING", "FOR", "WHEN (", "EXECUTE PROCEDURE"); + else if (HeadMatches2("CREATE", "TRIGGER") && + (TailMatches1("DEFERRABLE") || TailMatches2("INITIALLY", "IMMEDIATE|DEFERRED"))) + COMPLETE_WITH_LIST4("REFERENCING", "FOR", "WHEN (", "EXECUTE PROCEDURE"); + else if (HeadMatches2("CREATE", "TRIGGER") && TailMatches1("REFERENCING")) + COMPLETE_WITH_LIST2("OLD TABLE", "NEW TABLE"); + else if (HeadMatches2("CREATE", "TRIGGER") && TailMatches2("OLD|NEW", "TABLE")) + COMPLETE_WITH_CONST("AS"); + else if (HeadMatches2("CREATE", "TRIGGER") && + (TailMatches5("REFERENCING", "OLD", "TABLE", "AS", MatchAny) || + TailMatches4("REFERENCING", "OLD", "TABLE", MatchAny))) + COMPLETE_WITH_LIST4("NEW TABLE", "FOR", "WHEN (", "EXECUTE PROCEDURE"); + else if (HeadMatches2("CREATE", "TRIGGER") && + (TailMatches5("REFERENCING", "NEW", "TABLE", "AS", MatchAny) || + TailMatches4("REFERENCING", "NEW", "TABLE", MatchAny))) + COMPLETE_WITH_LIST4("OLD TABLE", "FOR", "WHEN (", "EXECUTE PROCEDURE"); + else if (HeadMatches2("CREATE", "TRIGGER") && + (TailMatches9("REFERENCING", "OLD|NEW", "TABLE", "AS", MatchAny, "OLD|NEW", "TABLE", "AS", MatchAny) || + TailMatches8("REFERENCING", "OLD|NEW", "TABLE", MatchAny, "OLD|NEW", "TABLE", "AS", MatchAny) || + TailMatches8("REFERENCING", "OLD|NEW", "TABLE", "AS", MatchAny, "OLD|NEW", "TABLE", MatchAny) || + TailMatches7("REFERENCING", "OLD|NEW", "TABLE", MatchAny, "OLD|NEW", "TABLE", MatchAny))) + COMPLETE_WITH_LIST3("FOR", "WHEN (", "EXECUTE PROCEDURE"); + else if (HeadMatches2("CREATE", "TRIGGER") && TailMatches1("FOR")) + COMPLETE_WITH_LIST3("EACH", "ROW", "STATEMENT"); + else if (HeadMatches2("CREATE", "TRIGGER") && TailMatches2("FOR", "EACH")) + COMPLETE_WITH_LIST2("ROW", "STATEMENT"); + else if (HeadMatches2("CREATE", "TRIGGER") && + (TailMatches3("FOR", "EACH", "ROW|STATEMENT") || + TailMatches2("FOR", "ROW|STATEMENT"))) + COMPLETE_WITH_LIST2("WHEN (", "EXECUTE PROCEDURE"); /* complete CREATE TRIGGER ... EXECUTE with PROCEDURE */ else if (HeadMatches2("CREATE", "TRIGGER") && TailMatches1("EXECUTE")) COMPLETE_WITH_CONST("PROCEDURE"); + else if (HeadMatches2("CREATE", "TRIGGER") && TailMatches2("EXECUTE", "PROCEDURE")) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL); /* CREATE ROLE,USER,GROUP */ else if (Matches3("CREATE", "ROLE|GROUP|USER", MatchAny) && @@ -2285,7 +2483,7 @@ psql_completion(const char *text, int start, int end) /* DROP */ /* Complete DROP object with CASCADE / RESTRICT */ else if (Matches3("DROP", - "COLLATION|CONVERSION|DOMAIN|EXTENSION|LANGUAGE|SCHEMA|SEQUENCE|SERVER|TABLE|TYPE|VIEW", + "COLLATION|CONVERSION|DOMAIN|EXTENSION|LANGUAGE|PUBLICATION|SCHEMA|SEQUENCE|SERVER|TABLE|TYPE|VIEW", MatchAny) || Matches4("DROP", "ACCESS", "METHOD", MatchAny) || (Matches4("DROP", "AGGREGATE|FUNCTION", MatchAny, MatchAny) && @@ -2431,10 +2629,22 @@ psql_completion(const char *text, int start, int end) else if (TailMatches2("FOREIGN", "SERVER")) COMPLETE_WITH_QUERY(Query_for_list_of_servers); -/* GRANT && REVOKE --- is allowed inside CREATE SCHEMA, so use TailMatches */ +/* + * GRANT and REVOKE are allowed inside CREATE SCHEMA and + * ALTER DEFAULT PRIVILEGES, so use TailMatches + */ /* Complete GRANT/REVOKE with a list of roles and privileges */ else if (TailMatches1("GRANT|REVOKE")) - COMPLETE_WITH_QUERY(Query_for_list_of_roles + /* + * With ALTER DEFAULT PRIVILEGES, restrict completion + * to grantable privileges (can't grant roles) + */ + if (HeadMatches3("ALTER","DEFAULT","PRIVILEGES")) + COMPLETE_WITH_LIST10("SELECT", "INSERT", "UPDATE", + "DELETE", "TRUNCATE", "REFERENCES", "TRIGGER", + "EXECUTE", "USAGE", "ALL"); + else + COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'SELECT'" " UNION SELECT 'INSERT'" " UNION SELECT 'UPDATE'" @@ -2475,7 +2685,14 @@ psql_completion(const char *text, int start, int end) * privilege. */ else if (TailMatches3("GRANT|REVOKE", MatchAny, "ON")) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, + /* + * With ALTER DEFAULT PRIVILEGES, restrict completion + * to the kinds of objects supported. + */ + if (HeadMatches3("ALTER","DEFAULT","PRIVILEGES")) + COMPLETE_WITH_LIST4("TABLES", "SEQUENCES", "FUNCTIONS", "TYPES"); + else + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, " UNION SELECT 'ALL FUNCTIONS IN SCHEMA'" " UNION SELECT 'ALL SEQUENCES IN SCHEMA'" " UNION SELECT 'ALL TABLES IN SCHEMA'" @@ -2538,7 +2755,9 @@ psql_completion(const char *text, int start, int end) else if ((HeadMatches1("GRANT") && TailMatches1("TO")) || (HeadMatches1("REVOKE") && TailMatches1("FROM"))) COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles); - + /* Complete "ALTER DEFAULT PRIVILEGES ... GRANT/REVOKE ... TO/FROM */ + else if (HeadMatches3("ALTER","DEFAULT", "PRIVILEGES") && TailMatches1("TO|FROM")) + COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles); /* Complete "GRANT/REVOKE ... ON * *" with TO/FROM */ else if (HeadMatches1("GRANT") && TailMatches3("ON", MatchAny, MatchAny)) COMPLETE_WITH_CONST("TO"); @@ -2636,6 +2855,17 @@ psql_completion(const char *text, int start, int end) "SHARE ROW EXCLUSIVE MODE", "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE"); + /* Complete LOCK [TABLE]
IN ACCESS|ROW with rest of lock mode */ + else if (Matches4("LOCK", MatchAny, "IN", "ACCESS|ROW") || + Matches5("LOCK", "TABLE", MatchAny, "IN", "ACCESS|ROW")) + COMPLETE_WITH_LIST2("EXCLUSIVE MODE", "SHARE MODE"); + + /* Complete LOCK [TABLE]
IN SHARE with rest of lock mode */ + else if (Matches4("LOCK", MatchAny, "IN", "SHARE") || + Matches5("LOCK", "TABLE", MatchAny, "IN", "SHARE")) + COMPLETE_WITH_LIST3("MODE", "ROW EXCLUSIVE MODE", + "UPDATE EXCLUSIVE MODE"); + /* NOTIFY --- can be inside EXPLAIN, RULE, etc */ else if (TailMatches1("NOTIFY")) COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(channel) FROM pg_catalog.pg_listening_channels() AS channel WHERE substring(pg_catalog.quote_ident(channel),1,%d)='%s'"); @@ -2741,20 +2971,36 @@ psql_completion(const char *text, int start, int end) else if (Matches1("SHOW")) COMPLETE_WITH_QUERY(Query_for_list_of_show_vars); /* Complete "SET TRANSACTION" */ - else if (Matches2("SET|BEGIN|START", "TRANSACTION") || + else if (Matches2("SET", "TRANSACTION")) + COMPLETE_WITH_LIST5("SNAPSHOT", "ISOLATION LEVEL", "READ", "DEFERRABLE", "NOT DEFERRABLE"); + else if (Matches2("BEGIN|START", "TRANSACTION") || Matches2("BEGIN", "WORK") || + Matches1("BEGIN") || Matches5("SET", "SESSION", "CHARACTERISTICS", "AS", "TRANSACTION")) - COMPLETE_WITH_LIST2("ISOLATION LEVEL", "READ"); + COMPLETE_WITH_LIST4("ISOLATION LEVEL", "READ", "DEFERRABLE", "NOT DEFERRABLE"); + else if (Matches3("SET|BEGIN|START", "TRANSACTION|WORK", "NOT") || + Matches2("BEGIN", "NOT") || + Matches6("SET", "SESSION", "CHARACTERISTICS", "AS", "TRANSACTION", "NOT")) + COMPLETE_WITH_CONST("DEFERRABLE"); else if (Matches3("SET|BEGIN|START", "TRANSACTION|WORK", "ISOLATION") || + Matches2("BEGIN", "ISOLATION") || Matches6("SET", "SESSION", "CHARACTERISTICS", "AS", "TRANSACTION", "ISOLATION")) COMPLETE_WITH_CONST("LEVEL"); - else if (Matches4("SET|BEGIN|START", "TRANSACTION|WORK", "ISOLATION", "LEVEL")) + else if (Matches4("SET|BEGIN|START", "TRANSACTION|WORK", "ISOLATION", "LEVEL") || + Matches3("BEGIN", "ISOLATION", "LEVEL") || + Matches7("SET", "SESSION", "CHARACTERISTICS", "AS", "TRANSACTION", "ISOLATION", "LEVEL")) COMPLETE_WITH_LIST3("READ", "REPEATABLE READ", "SERIALIZABLE"); - else if (Matches5("SET|BEGIN|START", "TRANSACTION|WORK", "ISOLATION", "LEVEL", "READ")) + else if (Matches5("SET|BEGIN|START", "TRANSACTION|WORK", "ISOLATION", "LEVEL", "READ") || + Matches4("BEGIN", "ISOLATION", "LEVEL", "READ") || + Matches8("SET", "SESSION", "CHARACTERISTICS", "AS", "TRANSACTION", "ISOLATION", "LEVEL", "READ")) COMPLETE_WITH_LIST2("UNCOMMITTED", "COMMITTED"); - else if (Matches5("SET|BEGIN|START", "TRANSACTION|WORK", "ISOLATION", "LEVEL", "REPEATABLE")) + else if (Matches5("SET|BEGIN|START", "TRANSACTION|WORK", "ISOLATION", "LEVEL", "REPEATABLE") || + Matches4("BEGIN", "ISOLATION", "LEVEL", "REPEATABLE") || + Matches8("SET", "SESSION", "CHARACTERISTICS", "AS", "TRANSACTION", "ISOLATION", "LEVEL", "REPEATABLE")) COMPLETE_WITH_CONST("READ"); - else if (Matches3("SET|BEGIN|START", "TRANSACTION|WORK", "READ")) + else if (Matches3("SET|BEGIN|START", "TRANSACTION|WORK", "READ") || + Matches2("BEGIN", "READ") || + Matches6("SET", "SESSION", "CHARACTERISTICS", "AS", "TRANSACTION", "READ")) COMPLETE_WITH_LIST2("ONLY", "WRITE"); /* SET CONSTRAINTS */ else if (Matches2("SET", "CONSTRAINTS")) @@ -3012,6 +3258,8 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_QUERY(Query_for_list_of_encodings); else if (TailMatchesCS1("\\h") || TailMatchesCS1("\\help")) COMPLETE_WITH_LIST(sql_commands); + else if (TailMatchesCS1("\\l*") && !TailMatchesCS1("\\lo*")) + COMPLETE_WITH_QUERY(Query_for_list_of_databases); else if (TailMatchesCS1("\\password")) COMPLETE_WITH_QUERY(Query_for_list_of_roles); else if (TailMatchesCS1("\\pset")) diff --git a/src/bin/psql/tab-complete.h b/src/bin/psql/tab-complete.h index 6226927700..9c0309dc1e 100644 --- a/src/bin/psql/tab-complete.h +++ b/src/bin/psql/tab-complete.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/tab-complete.h */ diff --git a/src/bin/psql/variables.c b/src/bin/psql/variables.c index f43f418e87..2669572aa7 100644 --- a/src/bin/psql/variables.c +++ b/src/bin/psql/variables.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/variables.c */ diff --git a/src/bin/psql/variables.h b/src/bin/psql/variables.h index d7a05a1431..d235b1798e 100644 --- a/src/bin/psql/variables.h +++ b/src/bin/psql/variables.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/bin/psql/variables.h */ diff --git a/src/bin/scripts/Makefile b/src/bin/scripts/Makefile index 8c107b1ba4..2f911e05ba 100644 --- a/src/bin/scripts/Makefile +++ b/src/bin/scripts/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/scripts # -# Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/bin/scripts/Makefile @@ -35,7 +35,7 @@ dropuser: dropuser.o common.o | submake-libpq submake-libpgport submake-libpgfeu clusterdb: clusterdb.o common.o | submake-libpq submake-libpgport submake-libpgfeutils vacuumdb: vacuumdb.o common.o | submake-libpq submake-libpgport submake-libpgfeutils reindexdb: reindexdb.o common.o | submake-libpq submake-libpgport submake-libpgfeutils -pg_isready: pg_isready.o common.o | submake-libpq submake-libpgport +pg_isready: pg_isready.o common.o | submake-libpq submake-libpgport submake-libpgfeutils install: all installdirs $(INSTALL_PROGRAM) createdb$(X) '$(DESTDIR)$(bindir)'/createdb$(X) diff --git a/src/bin/scripts/clusterdb.c b/src/bin/scripts/clusterdb.c index 0b16f34d1e..a6640aa57b 100644 --- a/src/bin/scripts/clusterdb.c +++ b/src/bin/scripts/clusterdb.c @@ -2,7 +2,7 @@ * * clusterdb * - * Portions Copyright (c) 2002-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2002-2017, PostgreSQL Global Development Group * * src/bin/scripts/clusterdb.c * diff --git a/src/bin/scripts/common.c b/src/bin/scripts/common.c index 7c1ebe059f..0b88fa6b4d 100644 --- a/src/bin/scripts/common.c +++ b/src/bin/scripts/common.c @@ -4,7 +4,7 @@ * Common support routines for bin/scripts/ * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/scripts/common.c @@ -68,19 +68,19 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport, const char *progname, bool fail_ok, bool allow_password_reuse) { PGconn *conn; - static char *password = NULL; bool new_pass; + static bool have_password = false; + static char password[100]; if (!allow_password_reuse) + have_password = false; + + if (!have_password && prompt_password == TRI_YES) { - if (password) - free(password); - password = NULL; + simple_prompt("Password: ", password, sizeof(password), false); + have_password = true; } - if (password == NULL && prompt_password == TRI_YES) - password = simple_prompt("Password: ", 100, false); - /* * Start the connection. Loop until we have a password if requested by * backend. @@ -97,7 +97,7 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport, keywords[2] = "user"; values[2] = pguser; keywords[3] = "password"; - values[3] = password; + values[3] = have_password ? password : NULL; keywords[4] = "dbname"; values[4] = dbname; keywords[5] = "fallback_application_name"; @@ -123,9 +123,8 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport, prompt_password != TRI_NO) { PQfinish(conn); - if (password) - free(password); - password = simple_prompt("Password: ", 100, false); + simple_prompt("Password: ", password, sizeof(password), false); + have_password = true; new_pass = true; } } while (new_pass); @@ -275,22 +274,15 @@ yesno_prompt(const char *question) for (;;) { - char *resp; + char resp[10]; - resp = simple_prompt(prompt, 1, true); + simple_prompt(prompt, resp, sizeof(resp), true); if (strcmp(resp, _(PG_YESLETTER)) == 0) - { - free(resp); return true; - } - else if (strcmp(resp, _(PG_NOLETTER)) == 0) - { - free(resp); + if (strcmp(resp, _(PG_NOLETTER)) == 0) return false; - } - free(resp); printf(_("Please answer \"%s\" or \"%s\".\n"), _(PG_YESLETTER), _(PG_NOLETTER)); } diff --git a/src/bin/scripts/common.h b/src/bin/scripts/common.h index 4fa1be5d66..6532eb2372 100644 --- a/src/bin/scripts/common.h +++ b/src/bin/scripts/common.h @@ -2,7 +2,7 @@ * common.h * Common support routines for bin/scripts/ * - * Copyright (c) 2003-2016, PostgreSQL Global Development Group + * Copyright (c) 2003-2017, PostgreSQL Global Development Group * * src/bin/scripts/common.h */ diff --git a/src/bin/scripts/createdb.c b/src/bin/scripts/createdb.c index fddfde76e2..88ea401e39 100644 --- a/src/bin/scripts/createdb.c +++ b/src/bin/scripts/createdb.c @@ -2,7 +2,7 @@ * * createdb * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/scripts/createdb.c diff --git a/src/bin/scripts/createlang.c b/src/bin/scripts/createlang.c index b93eada476..5897bfe747 100644 --- a/src/bin/scripts/createlang.c +++ b/src/bin/scripts/createlang.c @@ -2,7 +2,7 @@ * * createlang * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/scripts/createlang.c diff --git a/src/bin/scripts/createuser.c b/src/bin/scripts/createuser.c index e88879dc19..3d74797a8f 100644 --- a/src/bin/scripts/createuser.c +++ b/src/bin/scripts/createuser.c @@ -2,7 +2,7 @@ * * createuser * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/scripts/createuser.c @@ -66,6 +66,8 @@ main(int argc, char *argv[]) char *conn_limit = NULL; bool pwprompt = false; char *newpassword = NULL; + char newuser_buf[128]; + char newpassword_buf[100]; /* Tri-valued variables. */ enum trivalue createdb = TRI_DEFAULT, @@ -188,7 +190,11 @@ main(int argc, char *argv[]) if (newuser == NULL) { if (interactive) - newuser = simple_prompt("Enter name of role to add: ", 128, true); + { + simple_prompt("Enter name of role to add: ", + newuser_buf, sizeof(newuser_buf), true); + newuser = newuser_buf; + } else { if (getenv("PGUSER")) @@ -200,18 +206,17 @@ main(int argc, char *argv[]) if (pwprompt) { - char *pw1, - *pw2; + char pw2[100]; - pw1 = simple_prompt("Enter password for new role: ", 100, false); - pw2 = simple_prompt("Enter it again: ", 100, false); - if (strcmp(pw1, pw2) != 0) + simple_prompt("Enter password for new role: ", + newpassword_buf, sizeof(newpassword_buf), false); + simple_prompt("Enter it again: ", pw2, sizeof(pw2), false); + if (strcmp(newpassword_buf, pw2) != 0) { fprintf(stderr, _("Passwords didn't match.\n")); exit(1); } - newpassword = pw1; - free(pw2); + newpassword = newpassword_buf; } if (superuser == 0) diff --git a/src/bin/scripts/dropdb.c b/src/bin/scripts/dropdb.c index 145beb0221..85c75a79ce 100644 --- a/src/bin/scripts/dropdb.c +++ b/src/bin/scripts/dropdb.c @@ -2,7 +2,7 @@ * * dropdb * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/scripts/dropdb.c diff --git a/src/bin/scripts/droplang.c b/src/bin/scripts/droplang.c index 1f1f7ca15a..ab0215d495 100644 --- a/src/bin/scripts/droplang.c +++ b/src/bin/scripts/droplang.c @@ -2,7 +2,7 @@ * * droplang * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/scripts/droplang.c diff --git a/src/bin/scripts/dropuser.c b/src/bin/scripts/dropuser.c index 31fa28f7cd..095c0a39ff 100644 --- a/src/bin/scripts/dropuser.c +++ b/src/bin/scripts/dropuser.c @@ -2,7 +2,7 @@ * * dropuser * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/scripts/dropuser.c @@ -46,6 +46,7 @@ main(int argc, char *argv[]) enum trivalue prompt_password = TRI_DEFAULT; bool echo = false; bool interactive = false; + char dropuser_buf[128]; PQExpBufferData sql; @@ -108,7 +109,11 @@ main(int argc, char *argv[]) if (dropuser == NULL) { if (interactive) - dropuser = simple_prompt("Enter name of role to drop: ", 128, true); + { + simple_prompt("Enter name of role to drop: ", + dropuser_buf, sizeof(dropuser_buf), true); + dropuser = dropuser_buf; + } else { fprintf(stderr, _("%s: missing required argument role name\n"), progname); diff --git a/src/bin/scripts/pg_isready.c b/src/bin/scripts/pg_isready.c index 1f44efebf9..c7c06cc6ff 100644 --- a/src/bin/scripts/pg_isready.c +++ b/src/bin/scripts/pg_isready.c @@ -2,7 +2,7 @@ * * pg_isready --- checks the status of the PostgreSQL server * - * Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Copyright (c) 2013-2017, PostgreSQL Global Development Group * * src/bin/scripts/pg_isready.c * diff --git a/src/bin/scripts/reindexdb.c b/src/bin/scripts/reindexdb.c index 293522c902..12a4528574 100644 --- a/src/bin/scripts/reindexdb.c +++ b/src/bin/scripts/reindexdb.c @@ -2,7 +2,7 @@ * * reindexdb * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * src/bin/scripts/reindexdb.c * diff --git a/src/bin/scripts/t/010_clusterdb.pl b/src/bin/scripts/t/010_clusterdb.pl index 0e677cacf1..f3de9c016c 100644 --- a/src/bin/scripts/t/010_clusterdb.pl +++ b/src/bin/scripts/t/010_clusterdb.pl @@ -3,7 +3,7 @@ use PostgresNode; use TestLib; -use Test::More tests => 13; +use Test::More tests => 14; program_help_ok('clusterdb'); program_version_ok('clusterdb'); @@ -28,3 +28,6 @@ [ 'clusterdb', '-t', 'test1' ], qr/statement: CLUSTER test1;/, 'cluster specific table'); + +$node->command_ok([qw(clusterdb --echo --verbose dbname=template1)], + 'clusterdb with connection string'); diff --git a/src/bin/scripts/t/090_reindexdb.pl b/src/bin/scripts/t/090_reindexdb.pl index d92896f34f..42d6fb4eb4 100644 --- a/src/bin/scripts/t/090_reindexdb.pl +++ b/src/bin/scripts/t/090_reindexdb.pl @@ -3,7 +3,7 @@ use PostgresNode; use TestLib; -use Test::More tests => 20; +use Test::More tests => 23; program_help_ok('reindexdb'); program_version_ok('reindexdb'); @@ -42,3 +42,10 @@ [ 'reindexdb', '-v', '-t', 'test1', 'postgres' ], qr/statement: REINDEX \(VERBOSE\) TABLE test1;/, 'reindex with verbose output'); + +$node->command_ok([qw(reindexdb --echo --table=pg_am dbname=template1)], + 'reindexdb table with connection string'); +$node->command_ok([qw(reindexdb --echo dbname=template1)], + 'reindexdb database with connection string'); +$node->command_ok([qw(reindexdb --echo --system dbname=template1)], + 'reindexdb system with connection string'); diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index c183ccb6a1..07c6e9e7ce 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -3,7 +3,7 @@ use PostgresNode; use TestLib; -use Test::More tests => 18; +use Test::More tests => 19; program_help_ok('vacuumdb'); program_version_ok('vacuumdb'); @@ -33,3 +33,5 @@ [ 'vacuumdb', '-Z', 'postgres' ], qr/statement: ANALYZE;/, 'vacuumdb -Z'); +$node->command_ok([qw(vacuumdb -Z --table=pg_am dbname=template1)], + 'vacuumdb with connection string'); diff --git a/src/bin/scripts/t/200_connstr.pl b/src/bin/scripts/t/200_connstr.pl new file mode 100644 index 0000000000..89945712d2 --- /dev/null +++ b/src/bin/scripts/t/200_connstr.pl @@ -0,0 +1,38 @@ +use strict; +use warnings; + +use PostgresNode; +use TestLib; +use Test::More tests => 3; + +# Tests to check connection string handling in utilities + +# In a SQL_ASCII database, pgwin32_message_to_UTF16() needs to +# interpret everything as UTF8. We're going to use byte sequences +# that aren't valid UTF-8 strings, so that would fail. Use LATIN1, +# which accepts any byte and has a conversion from each byte to UTF-8. +$ENV{LC_ALL} = 'C'; +$ENV{PGCLIENTENCODING} = 'LATIN1'; + +# Create database names covering the range of LATIN1 characters and +# run the utilities' --all options over them. +my $dbname1 = generate_ascii_string(1, 63); # contains '=' +my $dbname2 = generate_ascii_string(67, 129); # skip 64-66 to keep length to 62 +my $dbname3 = generate_ascii_string(130, 192); +my $dbname4 = generate_ascii_string(193, 255); + +my $node = get_new_node('main'); +$node->init(extra => ['--locale=C', '--encoding=LATIN1']); +$node->start; + +foreach my $dbname ($dbname1, $dbname2, $dbname3, $dbname4, 'CamelCase') +{ + $node->run_log(['createdb', $dbname]); +} + +$node->command_ok([qw(vacuumdb --all --echo --analyze-only)], + 'vacuumdb --all with unusual database names'); +$node->command_ok([qw(reindexdb --all --echo)], + 'reindexdb --all with unusual database names'); +$node->command_ok([qw(clusterdb --all --echo --verbose)], + 'clusterdb --all with unusual database names'); diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c index c10b58bf0f..d3fa51cf1f 100644 --- a/src/bin/scripts/vacuumdb.c +++ b/src/bin/scripts/vacuumdb.c @@ -2,7 +2,7 @@ * * vacuumdb * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/scripts/vacuumdb.c @@ -12,6 +12,10 @@ #include "postgres_fe.h" +#ifdef HAVE_SYS_SELECT_H +#include +#endif + #include "common.h" #include "fe_utils/simple_list.h" #include "fe_utils/string_utils.h" diff --git a/src/common/Makefile b/src/common/Makefile index 72b73697a8..03dfaa19c4 100644 --- a/src/common/Makefile +++ b/src/common/Makefile @@ -6,11 +6,15 @@ # This makefile generates two outputs: # # libpgcommon.a - contains object files with FRONTEND defined, -# for use by client application and libraries +# for use by client applications # # libpgcommon_srv.a - contains object files without FRONTEND defined, # for use only by the backend binaries # +# You can also symlink/copy individual source files from this directory, +# to compile with different options. (libpq does that, because it needs +# to use -fPIC on some platforms.) +# # IDENTIFICATION # src/common/Makefile # @@ -36,11 +40,11 @@ override CPPFLAGS += -DVAL_LDFLAGS_EX="\"$(LDFLAGS_EX)\"" override CPPFLAGS += -DVAL_LDFLAGS_SL="\"$(LDFLAGS_SL)\"" override CPPFLAGS += -DVAL_LIBS="\"$(LIBS)\"" -OBJS_COMMON = config_info.o controldata_utils.o exec.o keywords.o \ - pg_lzcompress.o pgfnames.o psprintf.o relpath.o rmtree.o \ +OBJS_COMMON = config_info.o controldata_utils.o exec.o ip.o keywords.o \ + md5.o pg_lzcompress.o pgfnames.o psprintf.o relpath.o rmtree.o \ string.o username.o wait_error.o -OBJS_FRONTEND = $(OBJS_COMMON) fe_memutils.o restricted_token.o +OBJS_FRONTEND = $(OBJS_COMMON) fe_memutils.o file_utils.o restricted_token.o OBJS_SRV = $(OBJS_COMMON:%.o=%_srv.o) diff --git a/src/common/config_info.c b/src/common/config_info.c index 0fab3ab527..ad506be9ca 100644 --- a/src/common/config_info.c +++ b/src/common/config_info.c @@ -4,7 +4,7 @@ * Common code for pg_config output * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/common/controldata_utils.c b/src/common/controldata_utils.c index 5592fe7039..f1a097a974 100644 --- a/src/common/controldata_utils.c +++ b/src/common/controldata_utils.c @@ -4,7 +4,7 @@ * Common code for control data file output. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -29,19 +29,24 @@ #include "port/pg_crc32c.h" /* - * get_controlfile(char *DataDir, const char *progname) + * get_controlfile(char *DataDir, const char *progname, bool *crc_ok_p) * - * Get controlfile values. The caller is responsible - * for pfreeing the result. + * 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(char *DataDir, const char *progname) +get_controlfile(const char *DataDir, const char *progname, bool *crc_ok_p) { ControlFileData *ControlFile; int fd; char ControlFilePath[MAXPGPATH]; pg_crc32c crc; + AssertArg(crc_ok_p); + ControlFile = palloc(sizeof(ControlFileData)); snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir); @@ -81,14 +86,7 @@ get_controlfile(char *DataDir, const char *progname) offsetof(ControlFileData, crc)); FIN_CRC32C(crc); - if (!EQ_CRC32C(crc, ControlFile->crc)) -#ifndef FRONTEND - elog(ERROR, _("calculated CRC checksum does not match value stored in file")); -#else - printf(_("WARNING: Calculated CRC checksum does not match value stored in file.\n" - "Either the file is corrupt, or it has a different layout than this program\n" - "is expecting. The results below are untrustworthy.\n\n")); -#endif + *crc_ok_p = EQ_CRC32C(crc, ControlFile->crc); /* Make sure the control file is valid byte order. */ if (ControlFile->pg_control_version % 65536 == 0 && diff --git a/src/common/exec.c b/src/common/exec.c index d736b02280..ff592fc170 100644 --- a/src/common/exec.c +++ b/src/common/exec.c @@ -4,7 +4,7 @@ * Functions for finding and validating executable files * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -553,6 +553,7 @@ set_pglocale_pgservice(const char *argv0, const char *app) char my_exec_path[MAXPGPATH]; char env_path[MAXPGPATH + sizeof("PGSYSCONFDIR=")]; /* longer than * PGLOCALEDIR */ + char *dup_path; /* don't set LC_ALL in the backend */ if (strcmp(app, PG_TEXTDOMAIN("postgres")) != 0) @@ -583,7 +584,9 @@ set_pglocale_pgservice(const char *argv0, const char *app) /* set for libpq to use */ snprintf(env_path, sizeof(env_path), "PGLOCALEDIR=%s", path); canonicalize_path(env_path + 12); - putenv(strdup(env_path)); + dup_path = strdup(env_path); + if (dup_path) + putenv(dup_path); } #endif @@ -594,7 +597,9 @@ set_pglocale_pgservice(const char *argv0, const char *app) /* set for libpq to use */ snprintf(env_path, sizeof(env_path), "PGSYSCONFDIR=%s", path); canonicalize_path(env_path + 13); - putenv(strdup(env_path)); + dup_path = strdup(env_path); + if (dup_path) + putenv(dup_path); } } diff --git a/src/common/fe_memutils.c b/src/common/fe_memutils.c index 58c5c4c352..fb38067d97 100644 --- a/src/common/fe_memutils.c +++ b/src/common/fe_memutils.c @@ -3,7 +3,7 @@ * fe_memutils.c * memory management support for frontend code * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/common/file_utils.c b/src/common/file_utils.c new file mode 100644 index 0000000000..a978e64f5a --- /dev/null +++ b/src/common/file_utils.c @@ -0,0 +1,384 @@ +/*------------------------------------------------------------------------- + * + * File-processing utility routines. + * + * Assorted utility functions to work on files. + * + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/common/file_utils.c + * + *------------------------------------------------------------------------- + */ +#include "postgres_fe.h" + +#include +#include +#include +#include + +#include "common/file_utils.h" + + +/* 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, + const char *progname); +#endif +static void walkdir(const char *path, + int (*action) (const char *fname, bool isdir, const char *progname), + bool process_symlinks, const char *progname); + +/* + * 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. + * + * Errors are reported but not considered fatal. + */ +void +fsync_pgdata(const char *pg_data, + const char *progname, + 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; + +#ifndef WIN32 + { + struct stat st; + + if (lstat(pg_wal, &st) < 0) + fprintf(stderr, _("%s: could not stat file \"%s\": %s\n"), + progname, pg_wal, strerror(errno)); + else if (S_ISLNK(st.st_mode)) + xlog_is_symlink = true; + } +#else + if (pgwin32_is_junction(pg_wal)) + xlog_is_symlink = true; +#endif + + /* + * 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, progname); + if (xlog_is_symlink) + walkdir(pg_wal, pre_sync_fname, false, progname); + walkdir(pg_tblspc, pre_sync_fname, true, progname); +#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, progname); + if (xlog_is_symlink) + walkdir(pg_wal, fsync_fname, false, progname); + walkdir(pg_tblspc, fsync_fname, true, progname); +} + +/* + * 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, const char *progname), + bool process_symlinks, const char *progname) +{ + DIR *dir; + struct dirent *de; + + dir = opendir(path); + if (dir == NULL) + { + fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"), + progname, path, strerror(errno)); + return; + } + + while (errno = 0, (de = readdir(dir)) != NULL) + { + char subpath[MAXPGPATH]; + struct stat fst; + int sret; + + if (strcmp(de->d_name, ".") == 0 || + strcmp(de->d_name, "..") == 0) + continue; + + snprintf(subpath, MAXPGPATH, "%s/%s", path, de->d_name); + + if (process_symlinks) + sret = stat(subpath, &fst); + else + sret = lstat(subpath, &fst); + + if (sret < 0) + { + fprintf(stderr, _("%s: could not stat file \"%s\": %s\n"), + progname, subpath, strerror(errno)); + continue; + } + + if (S_ISREG(fst.st_mode)) + (*action) (subpath, false, progname); + else if (S_ISDIR(fst.st_mode)) + walkdir(subpath, action, false, progname); + } + + if (errno) + fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"), + progname, path, strerror(errno)); + + (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, progname); +} + +/* + * 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, const char *progname) +{ + int fd; + + fd = open(fname, O_RDONLY | PG_BINARY); + + if (fd < 0) + { + if (errno == EACCES || (isdir && errno == EISDIR)) + return 0; + fprintf(stderr, _("%s: could not open file \"%s\": %s\n"), + progname, fname, strerror(errno)); + 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. Reports + * other errors non-fatally. + */ +int +fsync_fname(const char *fname, bool isdir, const char *progname) +{ + 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); + if (fd < 0) + { + if (errno == EACCES || (isdir && errno == EISDIR)) + return 0; + fprintf(stderr, _("%s: could not open file \"%s\": %s\n"), + progname, fname, strerror(errno)); + 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)) + { + fprintf(stderr, _("%s: could not fsync file \"%s\": %s\n"), + progname, fname, strerror(errno)); + (void) close(fd); + return -1; + } + + (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, const char *progname) +{ + 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, progname) != 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, const char *progname) +{ + 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, progname) != 0) + return -1; + + fd = open(newfile, PG_BINARY | O_RDWR, 0); + if (fd < 0) + { + if (errno != ENOENT) + { + fprintf(stderr, _("%s: could not open file \"%s\": %s\n"), + progname, newfile, strerror(errno)); + return -1; + } + } + else + { + if (fsync(fd) != 0) + { + fprintf(stderr, _("%s: could not fsync file \"%s\": %s\n"), + progname, newfile, strerror(errno)); + close(fd); + return -1; + } + close(fd); + } + + /* Time to do the real deal... */ + if (rename(oldfile, newfile) != 0) + { + fprintf(stderr, _("%s: could not rename file \"%s\" to \"%s\": %s\n"), + progname, oldfile, newfile, strerror(errno)); + 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, progname) != 0) + return -1; + + if (fsync_parent_path(newfile, progname) != 0) + return -1; + + return 0; +} diff --git a/src/common/ip.c b/src/common/ip.c new file mode 100644 index 0000000000..d981dbcac9 --- /dev/null +++ b/src/common/ip.c @@ -0,0 +1,260 @@ +/*------------------------------------------------------------------------- + * + * ip.c + * IPv6-aware network access. + * + * Portions Copyright (c) 1996-2017, 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 , Linux Based Systems Design + * http://www.lbsd.net. + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_NETINET_TCP_H +#include +#endif +#include +#include + +#include "common/ip.h" + + + +#ifdef HAVE_UNIX_SOCKETS +static int getaddrinfo_unix(const char *path, + const struct addrinfo * hintsp, + struct addrinfo ** result); + +static int getnameinfo_unix(const struct sockaddr_un * sa, int salen, + char *node, int nodelen, + char *service, int servicelen, + int flags); +#endif + + +/* + * pg_getaddrinfo_all - get address info for Unix, IPv4 and IPv6 sockets + */ +int +pg_getaddrinfo_all(const char *hostname, const char *servname, + const struct addrinfo * hintp, struct addrinfo ** result) +{ + int rc; + + /* not all versions of getaddrinfo() zero *result on failure */ + *result = NULL; + +#ifdef HAVE_UNIX_SOCKETS + if (hintp->ai_family == AF_UNIX) + return getaddrinfo_unix(servname, hintp, result); +#endif + + /* NULL has special meaning to getaddrinfo(). */ + rc = getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname, + servname, hintp, result); + + return rc; +} + + +/* + * pg_freeaddrinfo_all - free addrinfo structures for IPv4, IPv6, or Unix + * + * Note: the ai_family field of the original hint structure must be passed + * so that we can tell whether the addrinfo struct was built by the system's + * getaddrinfo() routine or our own getaddrinfo_unix() routine. Some versions + * of getaddrinfo() might be willing to return AF_UNIX addresses, so it's + * not safe to look at ai_family in the addrinfo itself. + */ +void +pg_freeaddrinfo_all(int hint_ai_family, struct addrinfo * ai) +{ +#ifdef HAVE_UNIX_SOCKETS + if (hint_ai_family == AF_UNIX) + { + /* struct was built by getaddrinfo_unix (see pg_getaddrinfo_all) */ + while (ai != NULL) + { + struct addrinfo *p = ai; + + ai = ai->ai_next; + free(p->ai_addr); + free(p); + } + } + else +#endif /* HAVE_UNIX_SOCKETS */ + { + /* struct was built by getaddrinfo() */ + if (ai != NULL) + freeaddrinfo(ai); + } +} + + +/* + * pg_getnameinfo_all - get name info for Unix, IPv4 and IPv6 sockets + * + * The API of this routine differs from the standard getnameinfo() definition + * in two ways: first, the addr parameter is declared as sockaddr_storage + * rather than struct sockaddr, and second, the node and service fields are + * guaranteed to be filled with something even on failure return. + */ +int +pg_getnameinfo_all(const struct sockaddr_storage * addr, int salen, + char *node, int nodelen, + char *service, int servicelen, + int flags) +{ + int rc; + +#ifdef HAVE_UNIX_SOCKETS + if (addr && addr->ss_family == AF_UNIX) + rc = getnameinfo_unix((const struct sockaddr_un *) addr, salen, + node, nodelen, + service, servicelen, + flags); + else +#endif + rc = getnameinfo((const struct sockaddr *) addr, salen, + node, nodelen, + service, servicelen, + flags); + + if (rc != 0) + { + if (node) + strlcpy(node, "???", nodelen); + if (service) + strlcpy(service, "???", servicelen); + } + + return rc; +} + + +#if defined(HAVE_UNIX_SOCKETS) + +/* ------- + * getaddrinfo_unix - get unix socket info using IPv6-compatible API + * + * Bugs: only one addrinfo is set even though hintsp is NULL or + * ai_socktype is 0 + * AI_CANONNAME is not supported. + * ------- + */ +static int +getaddrinfo_unix(const char *path, const struct addrinfo * hintsp, + struct addrinfo ** result) +{ + struct addrinfo hints; + struct addrinfo *aip; + struct sockaddr_un *unp; + + *result = NULL; + + MemSet(&hints, 0, sizeof(hints)); + + if (strlen(path) >= sizeof(unp->sun_path)) + return EAI_FAIL; + + if (hintsp == NULL) + { + hints.ai_family = AF_UNIX; + hints.ai_socktype = SOCK_STREAM; + } + else + memcpy(&hints, hintsp, sizeof(hints)); + + if (hints.ai_socktype == 0) + hints.ai_socktype = SOCK_STREAM; + + if (hints.ai_family != AF_UNIX) + { + /* shouldn't have been called */ + return EAI_FAIL; + } + + aip = calloc(1, sizeof(struct addrinfo)); + if (aip == NULL) + return EAI_MEMORY; + + unp = calloc(1, sizeof(struct sockaddr_un)); + if (unp == NULL) + { + free(aip); + return EAI_MEMORY; + } + + aip->ai_family = AF_UNIX; + aip->ai_socktype = hints.ai_socktype; + aip->ai_protocol = hints.ai_protocol; + aip->ai_next = NULL; + aip->ai_canonname = NULL; + *result = aip; + + unp->sun_family = AF_UNIX; + aip->ai_addr = (struct sockaddr *) unp; + aip->ai_addrlen = sizeof(struct sockaddr_un); + + strcpy(unp->sun_path, path); + +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN + unp->sun_len = sizeof(struct sockaddr_un); +#endif + + return 0; +} + +/* + * Convert an address to a hostname. + */ +static int +getnameinfo_unix(const struct sockaddr_un * sa, int salen, + char *node, int nodelen, + char *service, int servicelen, + int flags) +{ + int ret = -1; + + /* Invalid arguments. */ + if (sa == NULL || sa->sun_family != AF_UNIX || + (node == NULL && service == NULL)) + return EAI_FAIL; + + if (node) + { + ret = snprintf(node, nodelen, "%s", "[local]"); + if (ret == -1 || ret > nodelen) + return EAI_MEMORY; + } + + if (service) + { + ret = snprintf(service, servicelen, "%s", sa->sun_path); + if (ret == -1 || ret > servicelen) + return EAI_MEMORY; + } + + return 0; +} +#endif /* HAVE_UNIX_SOCKETS */ diff --git a/src/common/keywords.c b/src/common/keywords.c index 485dd02e89..266c29205f 100644 --- a/src/common/keywords.c +++ b/src/common/keywords.c @@ -4,7 +4,7 @@ * lexical token lookup for key words in PostgreSQL * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/libpq/md5.c b/src/common/md5.c similarity index 98% rename from src/backend/libpq/md5.c rename to src/common/md5.c index 5af54e6c56..6e70b218d2 100644 --- a/src/backend/libpq/md5.c +++ b/src/common/md5.c @@ -10,17 +10,20 @@ * * Sverre H. Huseby * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * src/backend/libpq/md5.c + * src/common/md5.c */ -/* This is intended to be used in both frontend and backend, so use c.h */ -#include "c.h" +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif -#include "libpq/md5.h" +#include "common/md5.h" /* diff --git a/src/common/pg_lzcompress.c b/src/common/pg_lzcompress.c index 985841de29..5ec93ec7a6 100644 --- a/src/common/pg_lzcompress.c +++ b/src/common/pg_lzcompress.c @@ -166,7 +166,7 @@ * * Jan Wieck * - * Copyright (c) 1999-2016, PostgreSQL Global Development Group + * Copyright (c) 1999-2017, PostgreSQL Global Development Group * * src/common/pg_lzcompress.c * ---------- diff --git a/src/common/pgfnames.c b/src/common/pgfnames.c index ab3ab800c1..e161d7dc04 100644 --- a/src/common/pgfnames.c +++ b/src/common/pgfnames.c @@ -3,7 +3,7 @@ * pgfnames.c * directory handling functions * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/common/psprintf.c b/src/common/psprintf.c index 8ca6f9cea8..8561e9aed6 100644 --- a/src/common/psprintf.c +++ b/src/common/psprintf.c @@ -4,7 +4,7 @@ * sprintf into an allocated-on-demand buffer * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/common/relpath.c b/src/common/relpath.c index 1aacb818d7..c2f36625c1 100644 --- a/src/common/relpath.c +++ b/src/common/relpath.c @@ -4,7 +4,7 @@ * * This module also contains some logic associated with fork names. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/common/restricted_token.c b/src/common/restricted_token.c index d155b5ed0e..1a00293695 100644 --- a/src/common/restricted_token.c +++ b/src/common/restricted_token.c @@ -4,7 +4,7 @@ * helper routine to ensure restricted token on Windows * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/common/rmtree.c b/src/common/rmtree.c index 8a61213e02..09824b5463 100644 --- a/src/common/rmtree.c +++ b/src/common/rmtree.c @@ -2,7 +2,7 @@ * * rmtree.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/common/string.c b/src/common/string.c index 69b26e7dbd..159d9ea7b6 100644 --- a/src/common/string.c +++ b/src/common/string.c @@ -4,7 +4,7 @@ * string handling helpers * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/common/username.c b/src/common/username.c index 5abf4a56b0..d6abac8281 100644 --- a/src/common/username.c +++ b/src/common/username.c @@ -3,7 +3,7 @@ * username.c * get user name * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/common/wait_error.c b/src/common/wait_error.c index 4aa827d066..7ac545c67a 100644 --- a/src/common/wait_error.c +++ b/src/common/wait_error.c @@ -4,7 +4,7 @@ * Convert a wait/waitpid(2) result code to a human-readable string * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/fe_utils/Makefile b/src/fe_utils/Makefile index 9da03b196b..2565924411 100644 --- a/src/fe_utils/Makefile +++ b/src/fe_utils/Makefile @@ -5,7 +5,7 @@ # This makefile generates a static library, libpgfeutils.a, # for use by client applications # -# Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # IDENTIFICATION diff --git a/src/fe_utils/mbprint.c b/src/fe_utils/mbprint.c index 97ba692724..d186fc4c91 100644 --- a/src/fe_utils/mbprint.c +++ b/src/fe_utils/mbprint.c @@ -3,7 +3,7 @@ * Multibyte character printing support for frontend code * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/fe_utils/mbprint.c diff --git a/src/fe_utils/print.c b/src/fe_utils/print.c index 1ec74f1790..5ca27a93e0 100644 --- a/src/fe_utils/print.c +++ b/src/fe_utils/print.c @@ -8,7 +8,7 @@ * pager open/close functions, all that stuff came with it. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/fe_utils/print.c @@ -2874,10 +2874,18 @@ PageOutput(int lines, const printTableOpt *topt) pagerprog = getenv("PAGER"); if (!pagerprog) pagerprog = DEFAULT_PAGER; + else + { + /* if PAGER is empty or all-white-space, don't use pager */ + if (strspn(pagerprog, " \t\r\n") == strlen(pagerprog)) + return stdout; + } disable_sigpipe_trap(); pagerpipe = popen(pagerprog, "w"); if (pagerpipe) return pagerpipe; + /* if popen fails, silently proceed without pager */ + restore_sigpipe_trap(); } } diff --git a/src/fe_utils/psqlscan.l b/src/fe_utils/psqlscan.l index 55067b450c..1b29341fa8 100644 --- a/src/fe_utils/psqlscan.l +++ b/src/fe_utils/psqlscan.l @@ -23,7 +23,7 @@ * * See psqlscan_int.h for additional commentary. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/fe_utils/simple_list.c b/src/fe_utils/simple_list.c index ed4d188516..1be8ca7598 100644 --- a/src/fe_utils/simple_list.c +++ b/src/fe_utils/simple_list.c @@ -7,7 +7,7 @@ * it's all we need in, eg, pg_dump. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/fe_utils/simple_list.c diff --git a/src/fe_utils/string_utils.c b/src/fe_utils/string_utils.c index f986dbcf39..08fe765b5a 100644 --- a/src/fe_utils/string_utils.c +++ b/src/fe_utils/string_utils.c @@ -6,7 +6,7 @@ * and interpreting backend output. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/fe_utils/string_utils.c @@ -168,6 +168,44 @@ fmtQualifiedId(int remoteVersion, const char *schema, const char *id) } +/* + * Format a Postgres version number (in the PG_VERSION_NUM integer format + * returned by PQserverVersion()) as a string. This exists mainly to + * encapsulate knowledge about two-part vs. three-part version numbers. + * + * For re-entrancy, caller must supply the buffer the string is put in. + * Recommended size of the buffer is 32 bytes. + * + * Returns address of 'buf', as a notational convenience. + */ +char * +formatPGVersionNumber(int version_number, bool include_minor, + char *buf, size_t buflen) +{ + if (version_number >= 100000) + { + /* New two-part style */ + if (include_minor) + snprintf(buf, buflen, "%d.%d", version_number / 10000, + version_number % 10000); + else + snprintf(buf, buflen, "%d", version_number / 10000); + } + else + { + /* Old three-part style */ + if (include_minor) + snprintf(buf, buflen, "%d.%d.%d", version_number / 10000, + (version_number / 100) % 100, + version_number % 100); + else + snprintf(buf, buflen, "%d.%d", version_number / 10000, + (version_number / 100) % 100); + } + return buf; +} + + /* * Convert a string value to an SQL string literal and append it to * the given buffer. We assume the specified client_encoding and @@ -380,7 +418,7 @@ appendByteaLiteral(PQExpBuffer buf, const unsigned char *str, size_t length, /* * Append the given string to the shell command being built in the buffer, - * with suitable shell-style quoting to create exactly one argument. + * with shell-style quoting as needed to create exactly one argument. * * Forbid LF or CR characters, which have scant practical use beyond designing * security breaches. The Windows command shell is unusable as a conduit for @@ -391,8 +429,22 @@ appendByteaLiteral(PQExpBuffer buf, const unsigned char *str, size_t length, void appendShellString(PQExpBuffer buf, const char *str) { +#ifdef WIN32 + int backslash_run_length = 0; +#endif const char *p; + /* + * Don't bother with adding quotes if the string is nonempty and clearly + * contains only safe characters. + */ + if (*str != '\0' && + strspn(str, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_./:") == strlen(str)) + { + appendPQExpBufferStr(buf, str); + return; + } + #ifndef WIN32 appendPQExpBufferChar(buf, '\''); for (p = str; *p; p++) @@ -412,7 +464,6 @@ appendShellString(PQExpBuffer buf, const char *str) } appendPQExpBufferChar(buf, '\''); #else /* WIN32 */ - int backslash_run_length = 0; /* * A Windows system() argument experiences two layers of interpretation. diff --git a/src/include/Makefile b/src/include/Makefile index cad8951f97..8c6e888c62 100644 --- a/src/include/Makefile +++ b/src/include/Makefile @@ -45,6 +45,7 @@ install: all installdirs $(INSTALL_DATA) pg_config_os.h '$(DESTDIR)$(includedir_server)' $(INSTALL_DATA) utils/errcodes.h '$(DESTDIR)$(includedir_server)/utils' $(INSTALL_DATA) utils/fmgroids.h '$(DESTDIR)$(includedir_server)/utils' + $(INSTALL_DATA) utils/fmgrprotos.h '$(DESTDIR)$(includedir_server)/utils' # We don't use INSTALL_DATA for performance reasons --- there are a lot of files cp $(srcdir)/*.h '$(DESTDIR)$(includedir_server)'/ || exit; \ chmod $(INSTALL_DATA_MODE) '$(DESTDIR)$(includedir_server)'/*.h || exit; \ @@ -72,7 +73,7 @@ uninstall: clean: - rm -f utils/fmgroids.h utils/errcodes.h parser/gram.h utils/probes.h catalog/schemapg.h + rm -f utils/fmgroids.h utils/fmgrprotos.h utils/errcodes.h parser/gram.h utils/probes.h catalog/schemapg.h distclean maintainer-clean: clean rm -f pg_config.h pg_config_ext.h pg_config_os.h dynloader.h stamp-h stamp-ext-h diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h index 1036cca99c..6a5f279e7f 100644 --- a/src/include/access/amapi.h +++ b/src/include/access/amapi.h @@ -3,7 +3,7 @@ * amapi.h * API for Postgres index access methods. * - * Copyright (c) 2015-2016, PostgreSQL Global Development Group + * Copyright (c) 2015-2017, PostgreSQL Global Development Group * * src/include/access/amapi.h * @@ -203,6 +203,4 @@ typedef struct IndexAmRoutine extern IndexAmRoutine *GetIndexAmRoutine(Oid amhandler); extern IndexAmRoutine *GetIndexAmRoutineByAmId(Oid amoid, bool noerror); -extern Datum amvalidate(PG_FUNCTION_ARGS); - #endif /* AMAPI_H */ diff --git a/src/include/access/amvalidate.h b/src/include/access/amvalidate.h index 7f4289a996..742c25a78d 100644 --- a/src/include/access/amvalidate.h +++ b/src/include/access/amvalidate.h @@ -3,7 +3,7 @@ * amvalidate.h * Support routines for index access methods' amvalidate functions. * - * Copyright (c) 2016, PostgreSQL Global Development Group + * Copyright (c) 2016-2017, PostgreSQL Global Development Group * * src/include/access/amvalidate.h * diff --git a/src/include/access/attnum.h b/src/include/access/attnum.h index 849634c145..7fa459fc8c 100644 --- a/src/include/access/attnum.h +++ b/src/include/access/attnum.h @@ -4,7 +4,7 @@ * POSTGRES attribute number definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/attnum.h diff --git a/src/include/access/brin.h b/src/include/access/brin.h index 99bf5330bb..896824a0cf 100644 --- a/src/include/access/brin.h +++ b/src/include/access/brin.h @@ -1,7 +1,7 @@ /* * AM-callable functions for BRIN indexes * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -15,12 +15,6 @@ #include "utils/relcache.h" -/* - * prototypes for functions in brin.c (external entry points for BRIN) - */ -extern Datum brinhandler(PG_FUNCTION_ARGS); -extern Datum brin_summarize_new_values(PG_FUNCTION_ARGS); - /* * Storage type for BRIN's reloptions */ diff --git a/src/include/access/brin_internal.h b/src/include/access/brin_internal.h index 47317af43c..40312604f8 100644 --- a/src/include/access/brin_internal.h +++ b/src/include/access/brin_internal.h @@ -2,7 +2,7 @@ * brin_internal.h * internal declarations for BRIN indexes * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/access/brin_page.h b/src/include/access/brin_page.h index b48f8f5597..e2b3b92fac 100644 --- a/src/include/access/brin_page.h +++ b/src/include/access/brin_page.h @@ -2,7 +2,7 @@ * brin_page.h * Prototypes and definitions for BRIN page layouts * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/access/brin_pageops.h b/src/include/access/brin_pageops.h index af86cc86e7..ab38093a23 100644 --- a/src/include/access/brin_pageops.h +++ b/src/include/access/brin_pageops.h @@ -2,7 +2,7 @@ * brin_pageops.h * Prototypes for operating on BRIN pages. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/access/brin_revmap.h b/src/include/access/brin_revmap.h index 89054e0128..2ec4169f6d 100644 --- a/src/include/access/brin_revmap.h +++ b/src/include/access/brin_revmap.h @@ -2,7 +2,7 @@ * brin_revmap.h * Prototypes for BRIN reverse range maps * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/access/brin_tuple.h b/src/include/access/brin_tuple.h index 2af05123aa..6927865182 100644 --- a/src/include/access/brin_tuple.h +++ b/src/include/access/brin_tuple.h @@ -2,7 +2,7 @@ * brin_tuple.h * Declarations for dealing with BRIN-specific tuples. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/access/brin_xlog.h b/src/include/access/brin_xlog.h index f6148053b4..527b2f1a22 100644 --- a/src/include/access/brin_xlog.h +++ b/src/include/access/brin_xlog.h @@ -4,7 +4,7 @@ * POSTGRES BRIN access XLOG definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/brin_xlog.h diff --git a/src/include/access/clog.h b/src/include/access/clog.h index 06c069ae3a..2894bd5620 100644 --- a/src/include/access/clog.h +++ b/src/include/access/clog.h @@ -3,7 +3,7 @@ * * PostgreSQL transaction-commit-log manager * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/clog.h diff --git a/src/include/access/commit_ts.h b/src/include/access/commit_ts.h index cf343ca8ea..f172c91d8f 100644 --- a/src/include/access/commit_ts.h +++ b/src/include/access/commit_ts.h @@ -3,7 +3,7 @@ * * PostgreSQL commit timestamp manager * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/commit_ts.h @@ -61,6 +61,14 @@ typedef struct xl_commit_ts_set #define SizeOfCommitTsSet (offsetof(xl_commit_ts_set, mainxid) + \ sizeof(TransactionId)) +typedef struct xl_commit_ts_truncate +{ + int pageno; + TransactionId oldestXid; +} xl_commit_ts_truncate; + +#define SizeOfCommitTsTruncate (offsetof(xl_commit_ts_truncate, oldestXid) + \ + sizeof(TransactionId)) extern void commit_ts_redo(XLogReaderState *record); extern void commit_ts_desc(StringInfo buf, XLogReaderState *record); diff --git a/src/include/access/genam.h b/src/include/access/genam.h index 81907d5566..b2e078aed2 100644 --- a/src/include/access/genam.h +++ b/src/include/access/genam.h @@ -4,7 +4,7 @@ * POSTGRES generalized index access method definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/genam.h diff --git a/src/include/access/generic_xlog.h b/src/include/access/generic_xlog.h index 63f2120633..187d68b3e1 100644 --- a/src/include/access/generic_xlog.h +++ b/src/include/access/generic_xlog.h @@ -4,7 +4,7 @@ * Generic xlog API definition. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/generic_xlog.h diff --git a/src/include/access/gin.h b/src/include/access/gin.h index e5b2e10a27..5629c8add7 100644 --- a/src/include/access/gin.h +++ b/src/include/access/gin.h @@ -2,7 +2,7 @@ * gin.h * Public header file for Generalized Inverted Index access method. * - * Copyright (c) 2006-2016, PostgreSQL Global Development Group + * Copyright (c) 2006-2017, PostgreSQL Global Development Group * * src/include/access/gin.h *-------------------------------------------------------------------------- diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h index 68cfe0c1ac..d46274ee85 100644 --- a/src/include/access/gin_private.h +++ b/src/include/access/gin_private.h @@ -2,7 +2,7 @@ * gin_private.h * header file for postgres inverted index access method implementation. * - * Copyright (c) 2006-2016, PostgreSQL Global Development Group + * Copyright (c) 2006-2017, PostgreSQL Global Development Group * * src/include/access/gin_private.h *-------------------------------------------------------------------------- @@ -591,7 +591,6 @@ typedef struct ginxlogDeleteListPages /* ginutil.c */ -extern Datum ginhandler(PG_FUNCTION_ARGS); extern bytea *ginoptions(Datum reloptions, bool validate); extern void initGinState(GinState *state, Relation index); extern Buffer GinNewBuffer(Relation index); @@ -880,9 +879,6 @@ extern void ginFreeScanKeys(GinScanOpaque so); /* ginget.c */ extern int64 gingetbitmap(IndexScanDesc scan, TIDBitmap *tbm); -/* ginfast.c */ -extern Datum gin_clean_pending_list(PG_FUNCTION_ARGS); - /* ginlogic.c */ extern void ginInitConsistentFunction(GinState *ginstate, GinScanKey key); @@ -919,6 +915,7 @@ typedef struct GinEntryAccumulator *entryallocator; uint32 eas_used; RBTree *tree; + RBTreeIterator tree_walk; } BuildAccumulator; extern void ginInitBA(BuildAccumulator *accum); diff --git a/src/include/access/gist.h b/src/include/access/gist.h index 4343d6f74f..5824e90bda 100644 --- a/src/include/access/gist.h +++ b/src/include/access/gist.h @@ -6,7 +6,7 @@ * changes should be made with care. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/gist.h diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 1231585017..60a770aa30 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -4,7 +4,7 @@ * private declarations for GiST -- declarations related to the * internal implementation of GiST, not the public API * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/gist_private.h @@ -107,15 +107,11 @@ typedef struct GISTSTATE * upper index pages; this rule avoids doing extra work during a search that * ends early due to LIMIT. * - * To perform an ordered search, we use an RBTree to manage the distance-order - * queue. Each GISTSearchTreeItem stores all unvisited items of the same - * distance; they are GISTSearchItems chained together via their next fields. - * - * In a non-ordered search (no order-by operators), the RBTree degenerates - * to a single item, which we use as a queue of unvisited index pages only. - * In this case matched heap items from the current index leaf page are - * remembered in GISTScanOpaqueData.pageData[] and returned directly from - * there, instead of building a separate GISTSearchItem for each one. + * To perform an ordered search, we use a pairing heap to manage the + * distance-order queue. In a non-ordered search (no order-by operators), + * we use it to return heap tuples before unvisited index pages, to + * ensure depth-first order, but all entries are otherwise considered + * equal. */ /* Individual heap tuple to be visited */ @@ -298,8 +294,8 @@ typedef struct #define GIST_ROOT_BLKNO 0 /* - * Before PostgreSQL 9.1, we used rely on so-called "invalid tuples" on inner - * pages to finish crash recovery of incomplete page splits. If a crash + * Before PostgreSQL 9.1, we used to rely on so-called "invalid tuples" on + * inner pages to finish crash recovery of incomplete page splits. If a crash * happened in the middle of a page split, so that the downlink pointers were * not yet inserted, crash recovery inserted a special downlink pointer. The * semantics of an invalid tuple was that it if you encounter one in a scan, @@ -427,7 +423,6 @@ typedef struct GiSTOptions } GiSTOptions; /* gist.c */ -extern Datum gisthandler(PG_FUNCTION_ARGS); extern void gistbuildempty(Relation index); extern bool gistinsert(Relation r, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, diff --git a/src/include/access/gistscan.h b/src/include/access/gistscan.h index 4acaebdc9e..017740d14a 100644 --- a/src/include/access/gistscan.h +++ b/src/include/access/gistscan.h @@ -4,7 +4,7 @@ * routines defined in access/gist/gistscan.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/gistscan.h diff --git a/src/include/access/hash.h b/src/include/access/hash.h index ce314180e6..69a3873fac 100644 --- a/src/include/access/hash.h +++ b/src/include/access/hash.h @@ -4,7 +4,7 @@ * header file for postgres hash access method implementation * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/hash.h @@ -20,11 +20,11 @@ #include "access/amapi.h" #include "access/itup.h" #include "access/sdir.h" -#include "access/xlogreader.h" #include "fmgr.h" #include "lib/stringinfo.h" #include "storage/bufmgr.h" #include "storage/lockdefs.h" +#include "utils/hsearch.h" #include "utils/relcache.h" /* @@ -33,6 +33,8 @@ */ typedef uint32 Bucket; +#define InvalidBucket ((Bucket) 0xFFFFFFFF) + #define BUCKET_TO_BLKNO(metap,B) \ ((BlockNumber) ((B) + ((B) ? (metap)->hashm_spares[_hash_log2((B)+1)-1] : 0)) + 1) @@ -52,6 +54,9 @@ typedef uint32 Bucket; #define LH_BUCKET_PAGE (1 << 1) #define LH_BITMAP_PAGE (1 << 2) #define LH_META_PAGE (1 << 3) +#define LH_BUCKET_BEING_POPULATED (1 << 4) +#define LH_BUCKET_BEING_SPLIT (1 << 5) +#define LH_BUCKET_NEEDS_SPLIT_CLEANUP (1 << 6) typedef struct HashPageOpaqueData { @@ -64,6 +69,10 @@ typedef struct HashPageOpaqueData typedef HashPageOpaqueData *HashPageOpaque; +#define H_NEEDS_SPLIT_CLEANUP(opaque) ((opaque)->hasho_flag & LH_BUCKET_NEEDS_SPLIT_CLEANUP) +#define H_BUCKET_BEING_SPLIT(opaque) ((opaque)->hasho_flag & LH_BUCKET_BEING_SPLIT) +#define H_BUCKET_BEING_POPULATED(opaque) ((opaque)->hasho_flag & LH_BUCKET_BEING_POPULATED) + /* * The page ID is for the convenience of pg_filedump and similar utilities, * which otherwise would have a hard time telling pages of different index @@ -80,19 +89,6 @@ typedef struct HashScanOpaqueData /* Hash value of the scan key, ie, the hash key we seek */ uint32 hashso_sk_hash; - /* - * By definition, a hash scan should be examining only one bucket. We - * record the bucket number here as soon as it is known. - */ - Bucket hashso_bucket; - bool hashso_bucket_valid; - - /* - * If we have a share lock on the bucket, we record it here. When - * hashso_bucket_blkno is zero, we have no such lock. - */ - BlockNumber hashso_bucket_blkno; - /* * We also want to remember which buffer we're currently examining in the * scan. We keep the buffer pinned (but not locked) across hashgettuple @@ -101,11 +97,30 @@ typedef struct HashScanOpaqueData */ Buffer hashso_curbuf; + /* remember the buffer associated with primary bucket */ + Buffer hashso_bucket_buf; + + /* + * remember the buffer associated with primary bucket page of bucket being + * split. it is required during the scan of the bucket which is being + * populated during split operation. + */ + Buffer hashso_split_bucket_buf; + /* Current position of the scan, as an index TID */ ItemPointerData hashso_curpos; /* Current position of the scan, as a heap TID */ ItemPointerData hashso_heappos; + + /* Whether scan starts on bucket being populated due to split */ + bool hashso_buc_populated; + + /* + * Whether scanning bucket being split? The value of this parameter is + * referred only when hashso_buc_populated is true. + */ + bool hashso_buc_split; } HashScanOpaqueData; typedef HashScanOpaqueData *HashScanOpaque; @@ -120,7 +135,7 @@ typedef HashScanOpaqueData *HashScanOpaque; #define HASH_VERSION 2 /* 2 signifies only hash key value is stored */ /* - * Spares[] holds the number of overflow pages currently allocated at or + * spares[] holds the number of overflow pages currently allocated at or * before a certain splitpoint. For example, if spares[3] = 7 then there are * 7 ovflpages before splitpoint 3 (compare BUCKET_TO_BLKNO macro). The * value in spares[ovflpoint] increases as overflow pages are added at the @@ -130,14 +145,14 @@ typedef HashScanOpaqueData *HashScanOpaque; * * ovflpages that have been recycled for reuse can be found by looking at * bitmaps that are stored within ovflpages dedicated for the purpose. - * The blknos of these bitmap pages are kept in bitmaps[]; nmaps is the + * The blknos of these bitmap pages are kept in mapp[]; nmaps is the * number of currently existing bitmaps. * * The limitation on the size of spares[] comes from the fact that there's * no point in having more than 2^32 buckets with only uint32 hashcodes. * There is no particular upper limit on the size of mapp[], other than * needing to fit into the metapage. (With 8K block size, 128 bitmaps - * limit us to 64 Gb of overflow space...) + * limit us to 64 GB of overflow space...) */ #define HASH_MAX_SPLITPOINTS 32 #define HASH_MAX_BITMAPS 128 @@ -176,6 +191,8 @@ typedef HashMetaPageData *HashMetaPage; sizeof(ItemIdData) - \ MAXALIGN(sizeof(HashPageOpaqueData))) +#define INDEX_MOVED_BY_SPLIT_MASK 0x2000 + #define HASH_MIN_FILLFACTOR 10 #define HASH_DEFAULT_FILLFACTOR 75 @@ -224,9 +241,6 @@ typedef HashMetaPageData *HashMetaPage; #define HASH_WRITE BUFFER_LOCK_EXCLUSIVE #define HASH_NOLOCK (-1) -#define HASH_SHARE ShareLock -#define HASH_EXCLUSIVE ExclusiveLock - /* * Strategy number. There's only one valid strategy for hashing: equality. */ @@ -244,7 +258,6 @@ typedef HashMetaPageData *HashMetaPage; /* public routines */ -extern Datum hashhandler(PG_FUNCTION_ARGS); extern IndexBuildResult *hashbuild(Relation heap, Relation index, struct IndexInfo *indexInfo); extern void hashbuildempty(Relation index); @@ -266,28 +279,6 @@ extern IndexBulkDeleteResult *hashvacuumcleanup(IndexVacuumInfo *info, extern bytea *hashoptions(Datum reloptions, bool validate); extern bool hashvalidate(Oid opclassoid); -/* - * Datatype-specific hash functions in hashfunc.c. - * - * These support both hash indexes and hash joins. - * - * NOTE: some of these are also used by catcache operations, without - * any direct connection to hash indexes. Also, the common hash_any - * routine is also used by dynahash tables. - */ -extern Datum hashchar(PG_FUNCTION_ARGS); -extern Datum hashint2(PG_FUNCTION_ARGS); -extern Datum hashint4(PG_FUNCTION_ARGS); -extern Datum hashint8(PG_FUNCTION_ARGS); -extern Datum hashoid(PG_FUNCTION_ARGS); -extern Datum hashenum(PG_FUNCTION_ARGS); -extern Datum hashfloat4(PG_FUNCTION_ARGS); -extern Datum hashfloat8(PG_FUNCTION_ARGS); -extern Datum hashoidvector(PG_FUNCTION_ARGS); -extern Datum hashint2vector(PG_FUNCTION_ARGS); -extern Datum hashname(PG_FUNCTION_ARGS); -extern Datum hashtext(PG_FUNCTION_ARGS); -extern Datum hashvarlena(PG_FUNCTION_ARGS); extern Datum hash_any(register const unsigned char *k, register int keylen); extern Datum hash_uint32(uint32 k); @@ -299,21 +290,21 @@ extern OffsetNumber _hash_pgaddtup(Relation rel, Buffer buf, Size itemsize, IndexTuple itup); /* hashovfl.c */ -extern Buffer _hash_addovflpage(Relation rel, Buffer metabuf, Buffer buf); -extern BlockNumber _hash_freeovflpage(Relation rel, Buffer ovflbuf, +extern Buffer _hash_addovflpage(Relation rel, Buffer metabuf, Buffer buf, bool retain_pin); +extern BlockNumber _hash_freeovflpage(Relation rel, Buffer ovflbuf, Buffer wbuf, BufferAccessStrategy bstrategy); extern void _hash_initbitmap(Relation rel, HashMetaPage metap, BlockNumber blkno, ForkNumber forkNum); extern void _hash_squeezebucket(Relation rel, Bucket bucket, BlockNumber bucket_blkno, + Buffer bucket_buf, BufferAccessStrategy bstrategy); /* hashpage.c */ -extern void _hash_getlock(Relation rel, BlockNumber whichlock, int access); -extern bool _hash_try_getlock(Relation rel, BlockNumber whichlock, int access); -extern void _hash_droplock(Relation rel, BlockNumber whichlock, int access); extern Buffer _hash_getbuf(Relation rel, BlockNumber blkno, int access, int flags); +extern Buffer _hash_getbuf_with_condlock_cleanup(Relation rel, + BlockNumber blkno, int flags); extern Buffer _hash_getinitbuf(Relation rel, BlockNumber blkno); extern Buffer _hash_getnewbuf(Relation rel, BlockNumber blkno, ForkNumber forkNum); @@ -322,19 +313,14 @@ extern Buffer _hash_getbuf_with_strategy(Relation rel, BlockNumber blkno, BufferAccessStrategy bstrategy); extern void _hash_relbuf(Relation rel, Buffer buf); extern void _hash_dropbuf(Relation rel, Buffer buf); -extern void _hash_wrtbuf(Relation rel, Buffer buf); -extern void _hash_chgbufaccess(Relation rel, Buffer buf, int from_access, - int to_access); +extern void _hash_dropscanbuf(Relation rel, HashScanOpaque so); extern uint32 _hash_metapinit(Relation rel, double num_tuples, ForkNumber forkNum); extern void _hash_pageinit(Page page, Size size); extern void _hash_expandtable(Relation rel, Buffer metabuf); - -/* hashscan.c */ -extern void _hash_regscan(IndexScanDesc scan); -extern void _hash_dropscan(IndexScanDesc scan); -extern bool _hash_has_active_scan(Relation rel, Bucket bucket); -extern void ReleaseResources_hash(void); +extern void _hash_finish_split(Relation rel, Buffer metabuf, Buffer obuf, + Bucket obucket, uint32 maxbucket, uint32 highmask, + uint32 lowmask); /* hashsearch.c */ extern bool _hash_next(IndexScanDesc scan, ScanDirection dir); @@ -364,10 +350,18 @@ extern bool _hash_convert_tuple(Relation index, Datum *index_values, bool *index_isnull); extern OffsetNumber _hash_binsearch(Page page, uint32 hash_value); extern OffsetNumber _hash_binsearch_last(Page page, uint32 hash_value); +extern BlockNumber _hash_get_oldblock_from_newbucket(Relation rel, Bucket new_bucket); +extern BlockNumber _hash_get_newblock_from_oldbucket(Relation rel, Bucket old_bucket); +extern Bucket _hash_get_newbucket_from_oldbucket(Relation rel, Bucket old_bucket, + uint32 lowmask, uint32 maxbucket); /* hash.c */ -extern void hash_redo(XLogReaderState *record); -extern void hash_desc(StringInfo buf, XLogReaderState *record); -extern const char *hash_identify(uint8 info); +extern void hashbucketcleanup(Relation rel, Bucket cur_bucket, + Buffer bucket_buf, BlockNumber bucket_blkno, + BufferAccessStrategy bstrategy, + uint32 maxbucket, uint32 highmask, uint32 lowmask, + double *tuples_removed, double *num_index_tuples, + bool bucket_has_garbage, + IndexBulkDeleteCallback callback, void *callback_state); #endif /* HASH_H */ diff --git a/src/include/access/hash_xlog.h b/src/include/access/hash_xlog.h new file mode 100644 index 0000000000..ed3c37f5db --- /dev/null +++ b/src/include/access/hash_xlog.h @@ -0,0 +1,25 @@ +/*------------------------------------------------------------------------- + * + * hash_xlog.h + * header file for Postgres hash AM implementation + * + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/hash_xlog.h + * + *------------------------------------------------------------------------- + */ +#ifndef HASH_XLOG_H +#define HASH_XLOG_H + +#include "access/hash.h" +#include "access/xlogreader.h" + + +extern void hash_redo(XLogReaderState *record); +extern void hash_desc(StringInfo buf, XLogReaderState *record); +extern const char *hash_identify(uint8 info); + +#endif /* HASH_XLOG_H */ diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h index b3a595c67e..ee7e05a3ec 100644 --- a/src/include/access/heapam.h +++ b/src/include/access/heapam.h @@ -4,7 +4,7 @@ * POSTGRES heap access method definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/heapam.h @@ -19,7 +19,7 @@ #include "nodes/lockoptions.h" #include "nodes/primnodes.h" #include "storage/bufpage.h" -#include "storage/lock.h" +#include "storage/lockdefs.h" #include "utils/relcache.h" #include "utils/snapshot.h" diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h index 06a82426bb..52f28b86cb 100644 --- a/src/include/access/heapam_xlog.h +++ b/src/include/access/heapam_xlog.h @@ -4,7 +4,7 @@ * POSTGRES heap access XLOG definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/heapam_xlog.h diff --git a/src/include/access/hio.h b/src/include/access/hio.h index a174b34c96..2824f23218 100644 --- a/src/include/access/hio.h +++ b/src/include/access/hio.h @@ -4,7 +4,7 @@ * POSTGRES heap access method input/output definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/hio.h diff --git a/src/include/access/htup.h b/src/include/access/htup.h index 474e99eb07..870adf4f77 100644 --- a/src/include/access/htup.h +++ b/src/include/access/htup.h @@ -4,7 +4,7 @@ * POSTGRES heap tuple definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/htup.h diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h index d7e5fad11e..a6c7e319a6 100644 --- a/src/include/access/htup_details.h +++ b/src/include/access/htup_details.h @@ -4,7 +4,7 @@ * POSTGRES heap tuple header definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/htup_details.h @@ -237,8 +237,8 @@ struct HeapTupleHeaderData */ #define HEAP_LOCKED_UPGRADED(infomask) \ ( \ - ((infomask) & HEAP_XMAX_IS_MULTI) && \ - ((infomask) & HEAP_XMAX_LOCK_ONLY) && \ + ((infomask) & HEAP_XMAX_IS_MULTI) != 0 && \ + ((infomask) & HEAP_XMAX_LOCK_ONLY) != 0 && \ (((infomask) & (HEAP_XMAX_EXCL_LOCK | HEAP_XMAX_KEYSHR_LOCK)) == 0) \ ) @@ -317,7 +317,7 @@ struct HeapTupleHeaderData #define HeapTupleHeaderXminCommitted(tup) \ ( \ - (tup)->t_infomask & HEAP_XMIN_COMMITTED \ + ((tup)->t_infomask & HEAP_XMIN_COMMITTED) != 0 \ ) #define HeapTupleHeaderXminInvalid(tup) \ @@ -501,7 +501,7 @@ do { \ #define HeapTupleHeaderIsHeapOnly(tup) \ ( \ - (tup)->t_infomask2 & HEAP_ONLY_TUPLE \ + ((tup)->t_infomask2 & HEAP_ONLY_TUPLE) != 0 \ ) #define HeapTupleHeaderSetHeapOnly(tup) \ @@ -516,7 +516,7 @@ do { \ #define HeapTupleHeaderHasMatch(tup) \ ( \ - (tup)->t_infomask2 & HEAP_TUPLE_HAS_MATCH \ + ((tup)->t_infomask2 & HEAP_TUPLE_HAS_MATCH) != 0 \ ) #define HeapTupleHeaderSetMatch(tup) \ @@ -805,6 +805,12 @@ extern HeapTuple heap_modify_tuple(HeapTuple tuple, Datum *replValues, bool *replIsnull, bool *doReplace); +extern HeapTuple heap_modify_tuple_by_cols(HeapTuple tuple, + TupleDesc tupleDesc, + int nCols, + int *replCols, + Datum *replValues, + bool *replIsnull); extern void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull); extern void heap_freetuple(HeapTuple htup); diff --git a/src/include/access/itup.h b/src/include/access/itup.h index 8350fa0084..e9ec8e27e2 100644 --- a/src/include/access/itup.h +++ b/src/include/access/itup.h @@ -4,7 +4,7 @@ * POSTGRES index tuple definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/itup.h @@ -63,7 +63,7 @@ typedef IndexAttributeBitMapData *IndexAttributeBitMap; * t_info manipulation macros */ #define INDEX_SIZE_MASK 0x1FFF -/* bit 0x2000 is not used at present */ +/* bit 0x2000 is reserved for index-AM specific usage */ #define INDEX_VAR_MASK 0x4000 #define INDEX_NULL_MASK 0x8000 diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h index ab5de627d2..1d01988bb8 100644 --- a/src/include/access/multixact.h +++ b/src/include/access/multixact.h @@ -3,7 +3,7 @@ * * PostgreSQL multi-transaction-log manager * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/multixact.h diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h index c580f51f7f..011a72ecf7 100644 --- a/src/include/access/nbtree.h +++ b/src/include/access/nbtree.h @@ -4,7 +4,7 @@ * header file for postgres btree access method implementation. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/nbtree.h @@ -654,7 +654,6 @@ typedef BTScanOpaqueData *BTScanOpaque; /* * prototypes for functions in nbtree.c (external entry points for btree) */ -extern Datum bthandler(PG_FUNCTION_ARGS); extern IndexBuildResult *btbuild(Relation heap, Relation index, struct IndexInfo *indexInfo); extern void btbuildempty(Relation index); diff --git a/src/include/access/parallel.h b/src/include/access/parallel.h index 2f8f36fea4..96ce4803da 100644 --- a/src/include/access/parallel.h +++ b/src/include/access/parallel.h @@ -3,7 +3,7 @@ * parallel.h * Infrastructure for launching parallel workers * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/parallel.h diff --git a/src/include/access/printtup.h b/src/include/access/printtup.h index 608c564287..0efcc6f884 100644 --- a/src/include/access/printtup.h +++ b/src/include/access/printtup.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/printtup.h @@ -26,6 +26,9 @@ extern void SendRowDescriptionMessage(TupleDesc typeinfo, List *targetlist, extern void debugStartup(DestReceiver *self, int operation, TupleDesc typeinfo); extern bool debugtup(TupleTableSlot *slot, DestReceiver *self); +extern void logStartup(DestReceiver *self, int operation, + TupleDesc typeinfo); +extern bool logtup(TupleTableSlot *slot, DestReceiver *self); /* XXX these are really in executor/spi.c */ extern void spi_dest_startup(DestReceiver *self, int operation, diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 469ac677e3..861977a608 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -9,7 +9,7 @@ * into a lot of low-level code. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/reloptions.h diff --git a/src/include/access/relscan.h b/src/include/access/relscan.h index 49c2a6f2ce..8746045d8d 100644 --- a/src/include/access/relscan.h +++ b/src/include/access/relscan.h @@ -4,7 +4,7 @@ * POSTGRES relation scan descriptor definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/relscan.h @@ -19,6 +19,7 @@ #include "access/htup_details.h" #include "access/itup.h" #include "access/tupdesc.h" +#include "storage/spin.h" /* * Shared state for parallel heap scan. diff --git a/src/include/access/rewriteheap.h b/src/include/access/rewriteheap.h index 4b87f25f4b..564c2ad0f5 100644 --- a/src/include/access/rewriteheap.h +++ b/src/include/access/rewriteheap.h @@ -3,7 +3,7 @@ * rewriteheap.h * Declarations for heap rewrite support functions * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994-5, Regents of the University of California * * src/include/access/rewriteheap.h diff --git a/src/include/access/rmgrlist.h b/src/include/access/rmgrlist.h index a7a0ae224f..5f76749dbd 100644 --- a/src/include/access/rmgrlist.h +++ b/src/include/access/rmgrlist.h @@ -6,7 +6,7 @@ * 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-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/rmgrlist.h diff --git a/src/include/access/sdir.h b/src/include/access/sdir.h index fc9d939209..347e910a41 100644 --- a/src/include/access/sdir.h +++ b/src/include/access/sdir.h @@ -4,7 +4,7 @@ * POSTGRES scan direction definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/sdir.h diff --git a/src/include/access/skey.h b/src/include/access/skey.h index c8ac001974..01cc940363 100644 --- a/src/include/access/skey.h +++ b/src/include/access/skey.h @@ -4,7 +4,7 @@ * POSTGRES scan key definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/skey.h diff --git a/src/include/access/slru.h b/src/include/access/slru.h index 5fcebc52fb..cf6edc3bdb 100644 --- a/src/include/access/slru.h +++ b/src/include/access/slru.h @@ -3,7 +3,7 @@ * slru.h * Simple LRU buffering for transaction status logfiles * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/slru.h @@ -104,7 +104,6 @@ typedef struct SlruSharedData /* LWLocks */ int lwlock_tranche_id; - LWLockTranche lwlock_tranche; char lwlock_tranche_name[SLRU_MAX_NAME_LENGTH]; LWLockPadded *buffer_locks; } SlruSharedData; diff --git a/src/include/access/spgist.h b/src/include/access/spgist.h index f39a2d6938..aaf78bca97 100644 --- a/src/include/access/spgist.h +++ b/src/include/access/spgist.h @@ -4,7 +4,7 @@ * Public header file for SP-GiST access method. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/spgist.h @@ -90,10 +90,13 @@ typedef struct spgChooseOut } addNode; struct /* results for spgSplitTuple */ { - /* Info to form new inner tuple with one node */ + /* Info to form new upper-level inner tuple with one child tuple */ bool prefixHasPrefix; /* tuple should have a prefix? */ Datum prefixPrefixDatum; /* if so, its value */ - Datum nodeLabel; /* node's label */ + int prefixNNodes; /* number of nodes */ + Datum *prefixNodeLabels; /* their labels (or NULL for + * no labels) */ + int childNodeN; /* which node gets child tuple */ /* Info to form new lower-level inner tuple with all old nodes */ bool postfixHasPrefix; /* tuple should have a prefix? */ @@ -134,7 +137,8 @@ typedef struct spgInnerConsistentIn Datum reconstructedValue; /* value reconstructed at parent */ void *traversalValue; /* opclass-specific traverse value */ - MemoryContext traversalMemoryContext; + MemoryContext traversalMemoryContext; /* put new traverse values + * here */ int level; /* current level (counting from zero) */ bool returnData; /* original data must be returned? */ @@ -163,8 +167,8 @@ typedef struct spgLeafConsistentIn ScanKey scankeys; /* array of operators and comparison values */ int nkeys; /* length of array */ - void *traversalValue; /* opclass-specific traverse value */ Datum reconstructedValue; /* value reconstructed at parent */ + void *traversalValue; /* opclass-specific traverse value */ int level; /* current level (counting from zero) */ bool returnData; /* original data must be returned? */ @@ -179,7 +183,6 @@ typedef struct spgLeafConsistentOut /* spgutils.c */ -extern Datum spghandler(PG_FUNCTION_ARGS); extern bytea *spgoptions(Datum reloptions, bool validate); /* spginsert.c */ diff --git a/src/include/access/spgist_private.h b/src/include/access/spgist_private.h index cb8fa9c0b5..b2979a9d43 100644 --- a/src/include/access/spgist_private.h +++ b/src/include/access/spgist_private.h @@ -4,7 +4,7 @@ * Private declarations for SP-GiST access method. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/spgist_private.h diff --git a/src/include/access/stratnum.h b/src/include/access/stratnum.h index eabced569c..489e5c595e 100644 --- a/src/include/access/stratnum.h +++ b/src/include/access/stratnum.h @@ -4,7 +4,7 @@ * POSTGRES strategy number definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/stratnum.h diff --git a/src/include/access/subtrans.h b/src/include/access/subtrans.h index f39c6d388f..bd30f5861f 100644 --- a/src/include/access/subtrans.h +++ b/src/include/access/subtrans.h @@ -3,7 +3,7 @@ * * PostgreSQL subtransaction-log manager * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/subtrans.h diff --git a/src/include/access/sysattr.h b/src/include/access/sysattr.h index 31b4d601a0..c03d3ffb43 100644 --- a/src/include/access/sysattr.h +++ b/src/include/access/sysattr.h @@ -4,7 +4,7 @@ * POSTGRES system attribute definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/sysattr.h diff --git a/src/include/access/timeline.h b/src/include/access/timeline.h index 2b333bc10e..05363c6842 100644 --- a/src/include/access/timeline.h +++ b/src/include/access/timeline.h @@ -3,7 +3,7 @@ * * Functions for reading and writing timeline history files. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/timeline.h diff --git a/src/include/access/transam.h b/src/include/access/transam.h index 969eff9379..522c104073 100644 --- a/src/include/access/transam.h +++ b/src/include/access/transam.h @@ -4,7 +4,7 @@ * postgres transaction access method support code * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/transam.h diff --git a/src/include/access/tsmapi.h b/src/include/access/tsmapi.h index 2e605c3406..d07b3f25a9 100644 --- a/src/include/access/tsmapi.h +++ b/src/include/access/tsmapi.h @@ -3,7 +3,7 @@ * tsmapi.h * API for tablesample methods * - * Copyright (c) 2015-2016, PostgreSQL Global Development Group + * Copyright (c) 2015-2017, PostgreSQL Global Development Group * * src/include/access/tsmapi.h * diff --git a/src/include/access/tupconvert.h b/src/include/access/tupconvert.h index 10556eec7e..e86cfd56c8 100644 --- a/src/include/access/tupconvert.h +++ b/src/include/access/tupconvert.h @@ -4,7 +4,7 @@ * Tuple conversion support. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/tupconvert.h @@ -38,6 +38,10 @@ extern TupleConversionMap *convert_tuples_by_name(TupleDesc indesc, TupleDesc outdesc, const char *msg); +extern AttrNumber *convert_tuples_by_name_map(TupleDesc indesc, + TupleDesc outdesc, + const char *msg); + extern HeapTuple do_convert_tuple(HeapTuple tuple, TupleConversionMap *map); extern void free_conversion_map(TupleConversionMap *map); diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h index de18f7488c..0012877237 100644 --- a/src/include/access/tupdesc.h +++ b/src/include/access/tupdesc.h @@ -4,7 +4,7 @@ * POSTGRES tuple descriptor definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/tupdesc.h diff --git a/src/include/access/tupmacs.h b/src/include/access/tupmacs.h index a24f1dda30..b5369108cc 100644 --- a/src/include/access/tupmacs.h +++ b/src/include/access/tupmacs.h @@ -4,7 +4,7 @@ * Tuple macros used by both index tuples and heap tuples. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/tupmacs.h diff --git a/src/include/access/tuptoaster.h b/src/include/access/tuptoaster.h index 7b5ae6245e..a6233c386d 100644 --- a/src/include/access/tuptoaster.h +++ b/src/include/access/tuptoaster.h @@ -4,7 +4,7 @@ * POSTGRES definitions for external and compressed storage * of variable size attributes. * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/include/access/tuptoaster.h * @@ -142,7 +142,7 @@ extern HeapTuple toast_insert_or_update(Relation rel, * Called by heap_delete(). * ---------- */ -extern void toast_delete(Relation rel, HeapTuple oldtup); +extern void toast_delete(Relation rel, HeapTuple oldtup, bool is_speculative); /* ---------- * heap_tuple_fetch_attr() - diff --git a/src/include/access/twophase.h b/src/include/access/twophase.h index b7ce0c69af..b2b7848fad 100644 --- a/src/include/access/twophase.h +++ b/src/include/access/twophase.h @@ -4,7 +4,7 @@ * Two-phase-commit related declarations. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/twophase.h diff --git a/src/include/access/twophase_rmgr.h b/src/include/access/twophase_rmgr.h index 55627bfcc4..32b6475dd9 100644 --- a/src/include/access/twophase_rmgr.h +++ b/src/include/access/twophase_rmgr.h @@ -4,7 +4,7 @@ * Two-phase-commit resource managers definition * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/twophase_rmgr.h diff --git a/src/include/access/valid.h b/src/include/access/valid.h index 30af9df429..72f2bb6ac2 100644 --- a/src/include/access/valid.h +++ b/src/include/access/valid.h @@ -4,7 +4,7 @@ * POSTGRES tuple qualification validity definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/valid.h diff --git a/src/include/access/visibilitymap.h b/src/include/access/visibilitymap.h index 00bbd4c2d9..7a237d7569 100644 --- a/src/include/access/visibilitymap.h +++ b/src/include/access/visibilitymap.h @@ -4,7 +4,7 @@ * visibility map interface * * - * Portions Copyright (c) 2007-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2007-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/visibilitymap.h diff --git a/src/include/access/xact.h b/src/include/access/xact.h index 503ae1b82d..4df6529ea0 100644 --- a/src/include/access/xact.h +++ b/src/include/access/xact.h @@ -4,7 +4,7 @@ * postgres transaction system definitions * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/xact.h @@ -225,7 +225,6 @@ typedef struct xl_xact_twophase { TransactionId xid; } xl_xact_twophase; -#define MinSizeOfXactInvals offsetof(xl_xact_invals, msgs) typedef struct xl_xact_origin { diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 14b7f7f459..a4255723b7 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -3,7 +3,7 @@ * * PostgreSQL transaction log manager * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/xlog.h @@ -83,6 +83,7 @@ typedef enum RECOVERY_TARGET_XID, RECOVERY_TARGET_TIME, RECOVERY_TARGET_NAME, + RECOVERY_TARGET_LSN, RECOVERY_TARGET_IMMEDIATE } RecoveryTargetType; @@ -183,6 +184,13 @@ extern bool XLOG_DEBUG; #define CHECKPOINT_CAUSE_XLOG 0x0040 /* XLOG consumption */ #define CHECKPOINT_CAUSE_TIME 0x0080 /* Elapsed time */ +/* + * Flag bits for the record being inserted, set using XLogSetRecordFlags(). + */ +#define XLOG_INCLUDE_ORIGIN 0x01 /* include the replication origin */ +#define XLOG_MARK_UNIMPORTANT 0x02 /* record not important for durability */ + + /* Checkpoint statistics */ typedef struct CheckpointStatsData { @@ -210,7 +218,9 @@ extern CheckpointStatsData CheckpointStats; struct XLogRecData; -extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn); +extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, + XLogRecPtr fpw_lsn, + uint8 flags); extern void XLogFlush(XLogRecPtr RecPtr); extern bool XLogBackgroundFlush(void); extern bool XLogNeedsFlush(XLogRecPtr RecPtr); @@ -261,6 +271,7 @@ extern void GetFullPageWriteInfo(XLogRecPtr *RedoRecPtr_p, bool *doPageWrites_p) extern XLogRecPtr GetRedoRecPtr(void); extern XLogRecPtr GetInsertRecPtr(void); extern XLogRecPtr GetFlushRecPtr(void); +extern XLogRecPtr GetLastImportantRecPtr(void); extern void GetNextXidAndEpoch(TransactionId *xid, uint32 *epoch); extern void RemovePromoteSignalFiles(void); diff --git a/src/include/access/xlog_fn.h b/src/include/access/xlog_fn.h deleted file mode 100644 index 576a4dc741..0000000000 --- a/src/include/access/xlog_fn.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * xlog_fn.h - * - * PostgreSQL transaction log SQL-callable function declarations - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * src/include/access/xlog_fn.h - */ -#ifndef XLOG_FN_H -#define XLOG_FN_H - -#include "fmgr.h" - -extern Datum pg_start_backup(PG_FUNCTION_ARGS); -extern Datum pg_stop_backup(PG_FUNCTION_ARGS); -extern Datum pg_stop_backup_v2(PG_FUNCTION_ARGS); -extern Datum pg_switch_xlog(PG_FUNCTION_ARGS); -extern Datum pg_create_restore_point(PG_FUNCTION_ARGS); -extern Datum pg_current_xlog_location(PG_FUNCTION_ARGS); -extern Datum pg_current_xlog_insert_location(PG_FUNCTION_ARGS); -extern Datum pg_current_xlog_flush_location(PG_FUNCTION_ARGS); -extern Datum pg_last_xlog_receive_location(PG_FUNCTION_ARGS); -extern Datum pg_last_xlog_replay_location(PG_FUNCTION_ARGS); -extern Datum pg_last_xact_replay_timestamp(PG_FUNCTION_ARGS); -extern Datum pg_xlogfile_name_offset(PG_FUNCTION_ARGS); -extern Datum pg_xlogfile_name(PG_FUNCTION_ARGS); -extern Datum pg_is_in_recovery(PG_FUNCTION_ARGS); -extern Datum pg_xlog_replay_pause(PG_FUNCTION_ARGS); -extern Datum pg_xlog_replay_resume(PG_FUNCTION_ARGS); -extern Datum pg_is_xlog_replay_paused(PG_FUNCTION_ARGS); -extern Datum pg_xlog_location_diff(PG_FUNCTION_ARGS); -extern Datum pg_is_in_backup(PG_FUNCTION_ARGS); -extern Datum pg_backup_start_time(PG_FUNCTION_ARGS); - -#endif /* XLOG_FN_H */ diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h index 0a595ccc48..8ad4d47d12 100644 --- a/src/include/access/xlog_internal.h +++ b/src/include/access/xlog_internal.h @@ -11,7 +11,7 @@ * Note: This file must be includable in both frontend and backend contexts, * to allow stand-alone tools like pg_receivexlog to deal with WAL files. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/xlog_internal.h @@ -31,7 +31,7 @@ /* * Each page of XLOG file has a header like this: */ -#define XLOG_PAGE_MAGIC 0xD093 /* can be used as WAL version indicator */ +#define XLOG_PAGE_MAGIC 0xD094 /* can be used as WAL version indicator */ typedef struct XLogPageHeaderData { @@ -128,7 +128,7 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader; /* * The XLog directory and control file (relative to $PGDATA) */ -#define XLOGDIR "pg_xlog" +#define XLOGDIR "pg_wal" #define XLOG_CONTROL_FILE "global/pg_control" /* @@ -283,8 +283,8 @@ extern const RmgrData RmgrTable[]; /* * Exported to support xlog switching from checkpointer */ -extern pg_time_t GetLastSegSwitchTime(void); -extern XLogRecPtr RequestXLogSwitch(void); +extern pg_time_t GetLastSegSwitchData(XLogRecPtr *lastSwitchLSN); +extern XLogRecPtr RequestXLogSwitch(bool mark_uninmportant); extern void GetOldestRestartPoint(XLogRecPtr *oldrecptr, TimeLineID *oldtli); diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h index c2c6632e63..53b60c1dcd 100644 --- a/src/include/access/xlogdefs.h +++ b/src/include/access/xlogdefs.h @@ -4,7 +4,7 @@ * Postgres transaction log manager record pointer and * timeline number definitions * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/xlogdefs.h diff --git a/src/include/access/xloginsert.h b/src/include/access/xloginsert.h index cc0177ef4e..d30786fa0d 100644 --- a/src/include/access/xloginsert.h +++ b/src/include/access/xloginsert.h @@ -3,7 +3,7 @@ * * Functions for generating WAL records * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/xloginsert.h @@ -40,7 +40,7 @@ /* prototypes for public functions in xloginsert.c: */ extern void XLogBeginInsert(void); -extern void XLogIncludeOrigin(void); +extern void XLogSetRecordFlags(uint8 flags); extern XLogRecPtr XLogInsert(RmgrId rmid, uint8 info); extern void XLogEnsureRecordSpace(int nbuffers, int ndatas); extern void XLogRegisterData(char *data, int len); diff --git a/src/include/access/xlogreader.h b/src/include/access/xlogreader.h index deaa7f5128..00102e8e0b 100644 --- a/src/include/access/xlogreader.h +++ b/src/include/access/xlogreader.h @@ -3,7 +3,7 @@ * xlogreader.h * Definitions for the generic XLog reading facility * - * Portions Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2013-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/include/access/xlogreader.h diff --git a/src/include/access/xlogrecord.h b/src/include/access/xlogrecord.h index 3dfcb494f7..0162f93e82 100644 --- a/src/include/access/xlogrecord.h +++ b/src/include/access/xlogrecord.h @@ -3,7 +3,7 @@ * * Definitions for the WAL record format. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/xlogrecord.h diff --git a/src/include/access/xlogutils.h b/src/include/access/xlogutils.h index d027ea173b..567a7f3d87 100644 --- a/src/include/access/xlogutils.h +++ b/src/include/access/xlogutils.h @@ -3,7 +3,7 @@ * * Utilities for replaying WAL records. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/xlogutils.h diff --git a/src/include/bootstrap/bootstrap.h b/src/include/bootstrap/bootstrap.h index 4438f41cf0..cb123e4d64 100644 --- a/src/include/bootstrap/bootstrap.h +++ b/src/include/bootstrap/bootstrap.h @@ -4,7 +4,7 @@ * include file for the bootstrapping code * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/bootstrap/bootstrap.h diff --git a/src/include/c.h b/src/include/c.h index 4ab3f8027a..efbb77f540 100644 --- a/src/include/c.h +++ b/src/include/c.h @@ -9,7 +9,7 @@ * polluting the namespace with lots of stuff... * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/c.h @@ -939,6 +939,22 @@ typedef NameData *Name; #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 + + /* ---------------------------------------------------------------- * Section 8: random stuff * ---------------------------------------------------------------- diff --git a/src/include/catalog/binary_upgrade.h b/src/include/catalog/binary_upgrade.h index 373498441f..98089e3c1a 100644 --- a/src/include/catalog/binary_upgrade.h +++ b/src/include/catalog/binary_upgrade.h @@ -4,7 +4,7 @@ * variables used for binary upgrades * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/binary_upgrade.h diff --git a/src/include/catalog/catalog.h b/src/include/catalog/catalog.h index 005d58181e..d0a199afde 100644 --- a/src/include/catalog/catalog.h +++ b/src/include/catalog/catalog.h @@ -4,7 +4,7 @@ * prototypes for functions in backend/catalog/catalog.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/catalog.h diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 2ca3cd911a..79a9f108a6 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -34,7 +34,7 @@ * database contents or layout, such as altering tuple headers. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201608131 +#define CATALOG_VERSION_NO 201701201 #endif diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index 09b36c5c78..10759c7c58 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -4,7 +4,7 @@ * Routines to support inter-object dependencies. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/dependency.h @@ -161,16 +161,23 @@ typedef enum ObjectClass OCLASS_EXTENSION, /* pg_extension */ OCLASS_EVENT_TRIGGER, /* pg_event_trigger */ OCLASS_POLICY, /* pg_policy */ + OCLASS_PUBLICATION, /* pg_publication */ + OCLASS_PUBLICATION_REL, /* pg_publication_rel */ + OCLASS_SUBSCRIPTION, /* pg_subscription */ OCLASS_TRANSFORM /* pg_transform */ } ObjectClass; #define LAST_OCLASS OCLASS_TRANSFORM +/* flag bits for performDeletion/performMultipleDeletions: */ +#define PERFORM_DELETION_INTERNAL 0x0001 /* internal action */ +#define PERFORM_DELETION_CONCURRENTLY 0x0002 /* concurrent drop */ +#define PERFORM_DELETION_QUIETLY 0x0004 /* suppress notices */ +#define PERFORM_DELETION_SKIP_ORIGINAL 0x0008 /* keep original obj */ +#define PERFORM_DELETION_SKIP_EXTENSIONS 0x0010 /* keep extensions */ -/* in dependency.c */ -#define PERFORM_DELETION_INTERNAL 0x0001 -#define PERFORM_DELETION_CONCURRENTLY 0x0002 +/* in dependency.c */ extern void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags); @@ -178,9 +185,6 @@ extern void performDeletion(const ObjectAddress *object, extern void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags); -extern void deleteWhatDependsOn(const ObjectAddress *object, - bool showNotices); - extern void recordDependencyOnExpr(const ObjectAddress *depender, Node *expr, List *rtable, DependencyType behavior); @@ -188,7 +192,8 @@ extern void recordDependencyOnExpr(const ObjectAddress *depender, extern void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, - DependencyType self_behavior); + DependencyType self_behavior, + bool ignore_self); extern ObjectClass getObjectClass(const ObjectAddress *object); diff --git a/src/include/catalog/genbki.h b/src/include/catalog/genbki.h index 8e81de5f6d..a522b4cd82 100644 --- a/src/include/catalog/genbki.h +++ b/src/include/catalog/genbki.h @@ -9,7 +9,7 @@ * bootstrap file from these header files.) * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/genbki.h diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h index b80d8d8b21..553958f4d2 100644 --- a/src/include/catalog/heap.h +++ b/src/include/catalog/heap.h @@ -4,7 +4,7 @@ * prototypes for functions in backend/catalog/heap.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/heap.h @@ -134,4 +134,15 @@ extern void CheckAttributeType(const char *attname, List *containing_rowtypes, bool allow_system_table_mods); +/* pg_partitioned_table catalog manipulation functions */ +extern void StorePartitionKey(Relation rel, + char strategy, + int16 partnatts, + AttrNumber *partattrs, + List *partexprs, + Oid *partopclass, + Oid *partcollation); +extern void RemovePartitionKeyByRelId(Oid relid); +extern void StorePartitionBound(Relation rel, Relation parent, Node *bound); + #endif /* HEAP_H */ diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h index 37e6ef3fa9..20bec90b9d 100644 --- a/src/include/catalog/index.h +++ b/src/include/catalog/index.h @@ -4,7 +4,7 @@ * prototypes for catalog/index.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/index.h diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h index ca5eb3d417..45605a0dfd 100644 --- a/src/include/catalog/indexing.h +++ b/src/include/catalog/indexing.h @@ -5,7 +5,7 @@ * on system catalogs * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/indexing.h @@ -209,6 +209,9 @@ DECLARE_UNIQUE_INDEX(pg_rewrite_oid_index, 2692, on pg_rewrite using btree(oid o DECLARE_UNIQUE_INDEX(pg_rewrite_rel_rulename_index, 2693, on pg_rewrite using btree(ev_class oid_ops, rulename name_ops)); #define RewriteRelRulenameIndexId 2693 +DECLARE_UNIQUE_INDEX(pg_sequence_seqrelid_index, 5002, on pg_sequence using btree(seqrelid oid_ops)); +#define SequenceRelidIndexId 5002 + DECLARE_INDEX(pg_shdepend_depender_index, 1232, on pg_shdepend using btree(dbid oid_ops, classid oid_ops, objid oid_ops, objsubid int4_ops)); #define SharedDependDependerIndexId 1232 DECLARE_INDEX(pg_shdepend_reference_index, 1233, on pg_shdepend using btree(refclassid oid_ops, refobjid oid_ops)); @@ -319,6 +322,27 @@ DECLARE_UNIQUE_INDEX(pg_replication_origin_roiident_index, 6001, on pg_replicati DECLARE_UNIQUE_INDEX(pg_replication_origin_roname_index, 6002, on pg_replication_origin using btree(roname text_pattern_ops)); #define ReplicationOriginNameIndex 6002 +DECLARE_UNIQUE_INDEX(pg_partitioned_table_partrelid_index, 3351, on pg_partitioned_table using btree(partrelid oid_ops)); +#define PartitionedRelidIndexId 3351 + +DECLARE_UNIQUE_INDEX(pg_publication_oid_index, 6110, on pg_publication using btree(oid oid_ops)); +#define PublicationObjectIndexId 6110 + +DECLARE_UNIQUE_INDEX(pg_publication_pubname_index, 6111, on pg_publication using btree(pubname name_ops)); +#define PublicationNameIndexId 6111 + +DECLARE_UNIQUE_INDEX(pg_publication_rel_oid_index, 6112, on pg_publication_rel using btree(oid oid_ops)); +#define PublicationRelObjectIndexId 6112 + +DECLARE_UNIQUE_INDEX(pg_publication_rel_map_index, 6113, on pg_publication_rel using btree(prrelid oid_ops, prpubid oid_ops)); +#define PublicationRelMapIndexId 6113 + +DECLARE_UNIQUE_INDEX(pg_subscription_oid_index, 6114, on pg_subscription using btree(oid oid_ops)); +#define SubscriptionObjectIndexId 6114 + +DECLARE_UNIQUE_INDEX(pg_subscription_subname_index, 6115, on pg_subscription using btree(subdbid oid_ops, subname name_ops)); +#define SubscriptionNameIndexId 6115 + /* last step of initialization script: build the indexes declared above */ BUILD_INDICES diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h index eee94d8622..dbeb25b1ac 100644 --- a/src/include/catalog/namespace.h +++ b/src/include/catalog/namespace.h @@ -4,7 +4,7 @@ * prototypes for functions in backend/catalog/namespace.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/namespace.h diff --git a/src/include/catalog/objectaccess.h b/src/include/catalog/objectaccess.h index 1ef7f1f16c..3a6dd596ce 100644 --- a/src/include/catalog/objectaccess.h +++ b/src/include/catalog/objectaccess.h @@ -3,7 +3,7 @@ * * Object access hooks. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California */ diff --git a/src/include/catalog/objectaddress.h b/src/include/catalog/objectaddress.h index 583a1206f3..1a5afe1bed 100644 --- a/src/include/catalog/objectaddress.h +++ b/src/include/catalog/objectaddress.h @@ -3,7 +3,7 @@ * objectaddress.h * functions for working with object addresses * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/objectaddress.h diff --git a/src/include/catalog/opfam_internal.h b/src/include/catalog/opfam_internal.h index 7eb882fd12..448ad9708b 100644 --- a/src/include/catalog/opfam_internal.h +++ b/src/include/catalog/opfam_internal.h @@ -2,7 +2,7 @@ * * opfam_internal.h * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/opfam_internal.h diff --git a/src/include/catalog/partition.h b/src/include/catalog/partition.h new file mode 100644 index 0000000000..df7dcce331 --- /dev/null +++ b/src/include/catalog/partition.h @@ -0,0 +1,92 @@ +/*------------------------------------------------------------------------- + * + * partition.h + * Header file for structures and utility functions related to + * partitioning + * + * Copyright (c) 2007-2017, PostgreSQL Global Development Group + * + * src/include/catalog/partition.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARTITION_H +#define PARTITION_H + +#include "fmgr.h" +#include "executor/tuptable.h" +#include "nodes/execnodes.h" +#include "parser/parse_node.h" +#include "utils/rel.h" + +/* + * PartitionBoundInfo encapsulates a set of partition bounds. It is usually + * associated with partitioned tables as part of its partition descriptor. + * + * The internal structure is opaque outside partition.c. + */ +typedef struct PartitionBoundInfoData *PartitionBoundInfo; + +/* + * Information about partitions of a partitioned table. + */ +typedef struct PartitionDescData +{ + int nparts; /* Number of partitions */ + Oid *oids; /* OIDs of partitions */ + PartitionBoundInfo boundinfo; /* collection of partition bounds */ +} PartitionDescData; + +typedef struct PartitionDescData *PartitionDesc; + +/*----------------------- + * PartitionDispatch - information about one partitioned table in a partition + * hiearchy required to route a tuple to one of its partitions + * + * reldesc Relation descriptor of the table + * key Partition key information of the table + * keystate Execution state required for expressions in the partition key + * partdesc Partition descriptor of the table + * tupslot A standalone TupleTableSlot initialized with this table's tuple + * descriptor + * tupmap TupleConversionMap to convert from the parent's rowtype to + * this table's rowtype (when extracting the partition key of a + * tuple just before routing it through this table) + * indexes Array with partdesc->nparts members (for details on what + * individual members represent, see how they are set in + * RelationGetPartitionDispatchInfo()) + *----------------------- + */ +typedef struct PartitionDispatchData +{ + Relation reldesc; + PartitionKey key; + List *keystate; /* list of ExprState */ + PartitionDesc partdesc; + TupleTableSlot *tupslot; + TupleConversionMap *tupmap; + int *indexes; +} PartitionDispatchData; + +typedef struct PartitionDispatchData *PartitionDispatch; + +extern void RelationBuildPartitionDesc(Relation relation); +extern bool partition_bounds_equal(PartitionKey key, + PartitionBoundInfo p1, PartitionBoundInfo p2); + +extern void check_new_partition_bound(char *relname, Relation parent, Node *bound); +extern Oid get_partition_parent(Oid relid); +extern List *get_qual_from_partbound(Relation rel, Relation parent, Node *bound); +extern List *map_partition_varattnos(List *expr, int target_varno, + Relation partrel, Relation parent); +extern List *RelationGetPartitionQual(Relation rel); + +/* For tuple routing */ +extern PartitionDispatch *RelationGetPartitionDispatchInfo(Relation rel, + int lockmode, int *num_parted, + List **leaf_part_oids); +extern int get_partition_for_tuple(PartitionDispatch *pd, + TupleTableSlot *slot, + EState *estate, + Oid *failed_at); +#endif /* PARTITION_H */ diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h index 8865bba010..1ffde6cdc5 100644 --- a/src/include/catalog/pg_aggregate.h +++ b/src/include/catalog/pg_aggregate.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_aggregate.h diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h index 1116923799..9b6dc38f64 100644 --- a/src/include/catalog/pg_am.h +++ b/src/include/catalog/pg_am.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_am.h diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h index a15b0ec309..0251664e4a 100644 --- a/src/include/catalog/pg_amop.h +++ b/src/include/catalog/pg_amop.h @@ -30,7 +30,7 @@ * intentional denormalization of the catalogs to buy lookup speed. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_amop.h @@ -573,8 +573,6 @@ DATA(insert ( 2040 1114 1114 1 s 2060 405 0 )); DATA(insert ( 2222 16 16 1 s 91 405 0 )); /* bytea_ops */ DATA(insert ( 2223 17 17 1 s 1955 405 0 )); -/* int2vector_ops */ -DATA(insert ( 2224 22 22 1 s 386 405 0 )); /* xid_ops */ DATA(insert ( 2225 28 28 1 s 352 405 0 )); /* cid_ops */ @@ -673,8 +671,7 @@ DATA(insert ( 2595 718 718 14 s 2864 783 0 )); DATA(insert ( 2595 718 600 15 o 3291 783 1970 )); /* - * gin array_ops (these anyarray operators are used with all the opclasses - * of the family) + * gin array_ops */ DATA(insert ( 2745 2277 2277 1 s 2750 2742 0 )); DATA(insert ( 2745 2277 2277 2 s 2751 2742 0 )); @@ -863,6 +860,21 @@ DATA(insert ( 3550 869 869 25 s 932 783 0 )); DATA(insert ( 3550 869 869 26 s 933 783 0 )); DATA(insert ( 3550 869 869 27 s 934 783 0 )); +/* + * SP-GiST inet_ops + */ +DATA(insert ( 3794 869 869 3 s 3552 4000 0 )); +DATA(insert ( 3794 869 869 18 s 1201 4000 0 )); +DATA(insert ( 3794 869 869 19 s 1202 4000 0 )); +DATA(insert ( 3794 869 869 20 s 1203 4000 0 )); +DATA(insert ( 3794 869 869 21 s 1204 4000 0 )); +DATA(insert ( 3794 869 869 22 s 1205 4000 0 )); +DATA(insert ( 3794 869 869 23 s 1206 4000 0 )); +DATA(insert ( 3794 869 869 24 s 931 4000 0 )); +DATA(insert ( 3794 869 869 25 s 932 4000 0 )); +DATA(insert ( 3794 869 869 26 s 933 4000 0 )); +DATA(insert ( 3794 869 869 27 s 934 4000 0 )); + /* BRIN opclasses */ /* minmax bytea */ DATA(insert ( 4064 17 17 1 s 1957 3580 0 )); diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h index 00320b4c33..f1a52ce3e0 100644 --- a/src/include/catalog/pg_amproc.h +++ b/src/include/catalog/pg_amproc.h @@ -19,7 +19,7 @@ * some don't pay attention to non-default functions at all. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_amproc.h @@ -173,7 +173,6 @@ DATA(insert ( 2001 1266 1266 1 1696 )); DATA(insert ( 2040 1114 1114 1 2039 )); DATA(insert ( 2222 16 16 1 454 )); DATA(insert ( 2223 17 17 1 456 )); -DATA(insert ( 2224 22 22 1 398 )); DATA(insert ( 2225 28 28 1 450 )); DATA(insert ( 2226 29 29 1 450 )); DATA(insert ( 2227 702 702 1 450 )); @@ -255,156 +254,10 @@ DATA(insert ( 3550 869 869 9 3573 )); /* gin */ -DATA(insert ( 2745 1007 1007 1 351 )); -DATA(insert ( 2745 1007 1007 2 2743 )); -DATA(insert ( 2745 1007 1007 3 2774 )); -DATA(insert ( 2745 1007 1007 4 2744 )); -DATA(insert ( 2745 1007 1007 6 3920 )); -DATA(insert ( 2745 1009 1009 1 360 )); -DATA(insert ( 2745 1009 1009 2 2743 )); -DATA(insert ( 2745 1009 1009 3 2774 )); -DATA(insert ( 2745 1009 1009 4 2744 )); -DATA(insert ( 2745 1009 1009 6 3920 )); -DATA(insert ( 2745 1015 1015 1 360 )); -DATA(insert ( 2745 1015 1015 2 2743 )); -DATA(insert ( 2745 1015 1015 3 2774 )); -DATA(insert ( 2745 1015 1015 4 2744 )); -DATA(insert ( 2745 1015 1015 6 3920 )); -DATA(insert ( 2745 1023 1023 1 357 )); -DATA(insert ( 2745 1023 1023 2 2743 )); -DATA(insert ( 2745 1023 1023 3 2774 )); -DATA(insert ( 2745 1023 1023 4 2744 )); -DATA(insert ( 2745 1023 1023 6 3920 )); -DATA(insert ( 2745 1561 1561 1 1596 )); -DATA(insert ( 2745 1561 1561 2 2743 )); -DATA(insert ( 2745 1561 1561 3 2774 )); -DATA(insert ( 2745 1561 1561 4 2744 )); -DATA(insert ( 2745 1561 1561 6 3920 )); -DATA(insert ( 2745 1000 1000 1 1693 )); -DATA(insert ( 2745 1000 1000 2 2743 )); -DATA(insert ( 2745 1000 1000 3 2774 )); -DATA(insert ( 2745 1000 1000 4 2744 )); -DATA(insert ( 2745 1000 1000 6 3920 )); -DATA(insert ( 2745 1014 1014 1 1078 )); -DATA(insert ( 2745 1014 1014 2 2743 )); -DATA(insert ( 2745 1014 1014 3 2774 )); -DATA(insert ( 2745 1014 1014 4 2744 )); -DATA(insert ( 2745 1014 1014 6 3920 )); -DATA(insert ( 2745 1001 1001 1 1954 )); -DATA(insert ( 2745 1001 1001 2 2743 )); -DATA(insert ( 2745 1001 1001 3 2774 )); -DATA(insert ( 2745 1001 1001 4 2744 )); -DATA(insert ( 2745 1001 1001 6 3920 )); -DATA(insert ( 2745 1002 1002 1 358 )); -DATA(insert ( 2745 1002 1002 2 2743 )); -DATA(insert ( 2745 1002 1002 3 2774 )); -DATA(insert ( 2745 1002 1002 4 2744 )); -DATA(insert ( 2745 1002 1002 6 3920 )); -DATA(insert ( 2745 1182 1182 1 1092 )); -DATA(insert ( 2745 1182 1182 2 2743 )); -DATA(insert ( 2745 1182 1182 3 2774 )); -DATA(insert ( 2745 1182 1182 4 2744 )); -DATA(insert ( 2745 1182 1182 6 3920 )); -DATA(insert ( 2745 1021 1021 1 354 )); -DATA(insert ( 2745 1021 1021 2 2743 )); -DATA(insert ( 2745 1021 1021 3 2774 )); -DATA(insert ( 2745 1021 1021 4 2744 )); -DATA(insert ( 2745 1021 1021 6 3920 )); -DATA(insert ( 2745 1022 1022 1 355 )); -DATA(insert ( 2745 1022 1022 2 2743 )); -DATA(insert ( 2745 1022 1022 3 2774 )); -DATA(insert ( 2745 1022 1022 4 2744 )); -DATA(insert ( 2745 1022 1022 6 3920 )); -DATA(insert ( 2745 1041 1041 1 926 )); -DATA(insert ( 2745 1041 1041 2 2743 )); -DATA(insert ( 2745 1041 1041 3 2774 )); -DATA(insert ( 2745 1041 1041 4 2744 )); -DATA(insert ( 2745 1041 1041 6 3920 )); -DATA(insert ( 2745 651 651 1 926 )); -DATA(insert ( 2745 651 651 2 2743 )); -DATA(insert ( 2745 651 651 3 2774 )); -DATA(insert ( 2745 651 651 4 2744 )); -DATA(insert ( 2745 651 651 6 3920 )); -DATA(insert ( 2745 1005 1005 1 350 )); -DATA(insert ( 2745 1005 1005 2 2743 )); -DATA(insert ( 2745 1005 1005 3 2774 )); -DATA(insert ( 2745 1005 1005 4 2744 )); -DATA(insert ( 2745 1005 1005 6 3920 )); -DATA(insert ( 2745 1016 1016 1 842 )); -DATA(insert ( 2745 1016 1016 2 2743 )); -DATA(insert ( 2745 1016 1016 3 2774 )); -DATA(insert ( 2745 1016 1016 4 2744 )); -DATA(insert ( 2745 1016 1016 6 3920 )); -DATA(insert ( 2745 1187 1187 1 1315 )); -DATA(insert ( 2745 1187 1187 2 2743 )); -DATA(insert ( 2745 1187 1187 3 2774 )); -DATA(insert ( 2745 1187 1187 4 2744 )); -DATA(insert ( 2745 1187 1187 6 3920 )); -DATA(insert ( 2745 1040 1040 1 836 )); -DATA(insert ( 2745 1040 1040 2 2743 )); -DATA(insert ( 2745 1040 1040 3 2774 )); -DATA(insert ( 2745 1040 1040 4 2744 )); -DATA(insert ( 2745 1040 1040 6 3920 )); -DATA(insert ( 2745 1003 1003 1 359 )); -DATA(insert ( 2745 1003 1003 2 2743 )); -DATA(insert ( 2745 1003 1003 3 2774 )); -DATA(insert ( 2745 1003 1003 4 2744 )); -DATA(insert ( 2745 1003 1003 6 3920 )); -DATA(insert ( 2745 1231 1231 1 1769 )); -DATA(insert ( 2745 1231 1231 2 2743 )); -DATA(insert ( 2745 1231 1231 3 2774 )); -DATA(insert ( 2745 1231 1231 4 2744 )); -DATA(insert ( 2745 1231 1231 6 3920 )); -DATA(insert ( 2745 1028 1028 1 356 )); -DATA(insert ( 2745 1028 1028 2 2743 )); -DATA(insert ( 2745 1028 1028 3 2774 )); -DATA(insert ( 2745 1028 1028 4 2744 )); -DATA(insert ( 2745 1028 1028 6 3920 )); -DATA(insert ( 2745 1013 1013 1 404 )); -DATA(insert ( 2745 1013 1013 2 2743 )); -DATA(insert ( 2745 1013 1013 3 2774 )); -DATA(insert ( 2745 1013 1013 4 2744 )); -DATA(insert ( 2745 1013 1013 6 3920 )); -DATA(insert ( 2745 1183 1183 1 1107 )); -DATA(insert ( 2745 1183 1183 2 2743 )); -DATA(insert ( 2745 1183 1183 3 2774 )); -DATA(insert ( 2745 1183 1183 4 2744 )); -DATA(insert ( 2745 1183 1183 6 3920 )); -DATA(insert ( 2745 1185 1185 1 1314 )); -DATA(insert ( 2745 1185 1185 2 2743 )); -DATA(insert ( 2745 1185 1185 3 2774 )); -DATA(insert ( 2745 1185 1185 4 2744 )); -DATA(insert ( 2745 1185 1185 6 3920 )); -DATA(insert ( 2745 1270 1270 1 1358 )); -DATA(insert ( 2745 1270 1270 2 2743 )); -DATA(insert ( 2745 1270 1270 3 2774 )); -DATA(insert ( 2745 1270 1270 4 2744 )); -DATA(insert ( 2745 1270 1270 6 3920 )); -DATA(insert ( 2745 1563 1563 1 1672 )); -DATA(insert ( 2745 1563 1563 2 2743 )); -DATA(insert ( 2745 1563 1563 3 2774 )); -DATA(insert ( 2745 1563 1563 4 2744 )); -DATA(insert ( 2745 1563 1563 6 3920 )); -DATA(insert ( 2745 1115 1115 1 2045 )); -DATA(insert ( 2745 1115 1115 2 2743 )); -DATA(insert ( 2745 1115 1115 3 2774 )); -DATA(insert ( 2745 1115 1115 4 2744 )); -DATA(insert ( 2745 1115 1115 6 3920 )); -DATA(insert ( 2745 791 791 1 377 )); -DATA(insert ( 2745 791 791 2 2743 )); -DATA(insert ( 2745 791 791 3 2774 )); -DATA(insert ( 2745 791 791 4 2744 )); -DATA(insert ( 2745 791 791 6 3920 )); -DATA(insert ( 2745 1024 1024 1 380 )); -DATA(insert ( 2745 1024 1024 2 2743 )); -DATA(insert ( 2745 1024 1024 3 2774 )); -DATA(insert ( 2745 1024 1024 4 2744 )); -DATA(insert ( 2745 1024 1024 6 3920 )); -DATA(insert ( 2745 1025 1025 1 381 )); -DATA(insert ( 2745 1025 1025 2 2743 )); -DATA(insert ( 2745 1025 1025 3 2774 )); -DATA(insert ( 2745 1025 1025 4 2744 )); -DATA(insert ( 2745 1025 1025 6 3920 )); +DATA(insert ( 2745 2277 2277 2 2743 )); +DATA(insert ( 2745 2277 2277 3 2774 )); +DATA(insert ( 2745 2277 2277 4 2744 )); +DATA(insert ( 2745 2277 2277 6 3920 )); DATA(insert ( 3659 3614 3614 1 3724 )); DATA(insert ( 3659 3614 3614 2 3656 )); DATA(insert ( 3659 3614 3614 3 3657 )); @@ -428,6 +281,11 @@ DATA(insert ( 3474 3831 3831 2 3470 )); DATA(insert ( 3474 3831 3831 3 3471 )); DATA(insert ( 3474 3831 3831 4 3472 )); DATA(insert ( 3474 3831 3831 5 3473 )); +DATA(insert ( 3794 869 869 1 3795 )); +DATA(insert ( 3794 869 869 2 3796 )); +DATA(insert ( 3794 869 869 3 3797 )); +DATA(insert ( 3794 869 869 4 3798 )); +DATA(insert ( 3794 869 869 5 3799 )); DATA(insert ( 4015 600 600 1 4018 )); DATA(insert ( 4015 600 600 2 4019 )); DATA(insert ( 4015 600 600 3 4020 )); diff --git a/src/include/catalog/pg_attrdef.h b/src/include/catalog/pg_attrdef.h index 59be88f7af..ff1842f53c 100644 --- a/src/include/catalog/pg_attrdef.h +++ b/src/include/catalog/pg_attrdef.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_attrdef.h diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h index 39d8eedb4e..e861f4c589 100644 --- a/src/include/catalog/pg_attribute.h +++ b/src/include/catalog/pg_attribute.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_attribute.h diff --git a/src/include/catalog/pg_auth_members.h b/src/include/catalog/pg_auth_members.h index 7257541e5b..e34a4e80a4 100644 --- a/src/include/catalog/pg_auth_members.h +++ b/src/include/catalog/pg_auth_members.h @@ -5,7 +5,7 @@ * (pg_auth_members) along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_auth_members.h diff --git a/src/include/catalog/pg_authid.h b/src/include/catalog/pg_authid.h index 533081def6..def71edaa8 100644 --- a/src/include/catalog/pg_authid.h +++ b/src/include/catalog/pg_authid.h @@ -7,7 +7,7 @@ * pg_shadow and pg_group are now publicly accessible views on pg_authid. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_authid.h diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h index ee568d836a..80a40ab128 100644 --- a/src/include/catalog/pg_cast.h +++ b/src/include/catalog/pg_cast.h @@ -8,7 +8,7 @@ * but also length coercion functions. * * - * Copyright (c) 2002-2016, PostgreSQL Global Development Group + * Copyright (c) 2002-2017, PostgreSQL Global Development Group * * src/include/catalog/pg_cast.h * @@ -59,7 +59,7 @@ typedef enum CoercionCodes /* * The allowable values for pg_cast.castmethod are specified by this enum. - * Since castcontext is stored as a "char", we use ASCII codes for human + * Since castmethod is stored as a "char", we use ASCII codes for human * convenience in reading the table. */ typedef enum CoercionMethod diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index e57b81c417..d1fa5182ea 100644 --- a/src/include/catalog/pg_class.h +++ b/src/include/catalog/pg_class.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_class.h @@ -70,6 +70,7 @@ CATALOG(pg_class,1259) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83) BKI_SCHEMA_MACRO * not */ bool relispopulated; /* matview currently holds query results */ char relreplident; /* see REPLICA_IDENTITY_xxx constants */ + bool relispartition; /* is relation a partition? */ TransactionId relfrozenxid; /* all Xids < this are frozen in this rel */ TransactionId relminmxid; /* all multixacts in this rel are >= this. * this is really a MultiXactId */ @@ -78,6 +79,7 @@ CATALOG(pg_class,1259) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83) BKI_SCHEMA_MACRO /* NOTE: These fields are not present in a relcache entry's rd_rel field. */ aclitem relacl[1]; /* access permissions */ text reloptions[1]; /* access-method-specific options */ + pg_node_tree relpartbound; /* partition bound node tree */ #endif } FormData_pg_class; @@ -97,7 +99,7 @@ typedef FormData_pg_class *Form_pg_class; * ---------------- */ -#define Natts_pg_class 31 +#define Natts_pg_class 33 #define Anum_pg_class_relname 1 #define Anum_pg_class_relnamespace 2 #define Anum_pg_class_reltype 3 @@ -125,10 +127,12 @@ typedef FormData_pg_class *Form_pg_class; #define Anum_pg_class_relforcerowsecurity 25 #define Anum_pg_class_relispopulated 26 #define Anum_pg_class_relreplident 27 -#define Anum_pg_class_relfrozenxid 28 -#define Anum_pg_class_relminmxid 29 -#define Anum_pg_class_relacl 30 -#define Anum_pg_class_reloptions 31 +#define Anum_pg_class_relispartition 28 +#define Anum_pg_class_relfrozenxid 29 +#define Anum_pg_class_relminmxid 30 +#define Anum_pg_class_relacl 31 +#define Anum_pg_class_reloptions 32 +#define Anum_pg_class_relpartbound 33 /* ---------------- * initial contents of pg_class @@ -143,13 +147,13 @@ typedef FormData_pg_class *Form_pg_class; * Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId; * similarly, "1" in relminmxid stands for FirstMultiXactId */ -DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f p r 30 0 t f f f f f f t n 3 1 _null_ _null_ )); +DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f p r 30 0 t f f f f f f t n f 3 1 _null_ _null_ _null_)); DESCR(""); -DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f p r 21 0 f f f f f f f t n 3 1 _null_ _null_ )); +DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f p r 21 0 f f f f f f f t n f 3 1 _null_ _null_ _null_)); DESCR(""); -DATA(insert OID = 1255 ( pg_proc PGNSP 81 0 PGUID 0 0 0 0 0 0 0 f f p r 29 0 t f f f f f f t n 3 1 _null_ _null_ )); +DATA(insert OID = 1255 ( pg_proc PGNSP 81 0 PGUID 0 0 0 0 0 0 0 f f p r 29 0 t f f f f f f t n f 3 1 _null_ _null_ _null_)); DESCR(""); -DATA(insert OID = 1259 ( pg_class PGNSP 83 0 PGUID 0 0 0 0 0 0 0 f f p r 31 0 t f f f f f f t n 3 1 _null_ _null_ )); +DATA(insert OID = 1259 ( pg_class PGNSP 83 0 PGUID 0 0 0 0 0 0 0 f f p r 33 0 t f f f f f f t n f 3 1 _null_ _null_ _null_)); DESCR(""); @@ -161,6 +165,7 @@ DESCR(""); #define RELKIND_COMPOSITE_TYPE 'c' /* composite type */ #define RELKIND_FOREIGN_TABLE 'f' /* foreign table */ #define RELKIND_MATVIEW 'm' /* materialized view */ +#define RELKIND_PARTITIONED_TABLE 'P' /* partitioned table */ #define RELPERSISTENCE_PERMANENT 'p' /* regular table */ #define RELPERSISTENCE_UNLOGGED 'u' /* unlogged permanent table */ diff --git a/src/include/catalog/pg_collation.h b/src/include/catalog/pg_collation.h index 636771202e..30c87e004e 100644 --- a/src/include/catalog/pg_collation.h +++ b/src/include/catalog/pg_collation.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/catalog/pg_collation_fn.h b/src/include/catalog/pg_collation_fn.h index 574b288acc..482ba7920e 100644 --- a/src/include/catalog/pg_collation_fn.h +++ b/src/include/catalog/pg_collation_fn.h @@ -4,7 +4,7 @@ * prototypes for functions in catalog/pg_collation.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_collation_fn.h @@ -17,7 +17,8 @@ extern Oid CollationCreate(const char *collname, Oid collnamespace, Oid collowner, int32 collencoding, - const char *collcollate, const char *collctype); + const char *collcollate, const char *collctype, + bool if_not_exists); extern void RemoveCollationById(Oid collationOid); #endif /* PG_COLLATION_FN_H */ diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h index 666b2304bf..e959583364 100644 --- a/src/include/catalog/pg_constraint.h +++ b/src/include/catalog/pg_constraint.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_constraint.h diff --git a/src/include/catalog/pg_constraint_fn.h b/src/include/catalog/pg_constraint_fn.h index 1f11174210..d2acb3a053 100644 --- a/src/include/catalog/pg_constraint_fn.h +++ b/src/include/catalog/pg_constraint_fn.h @@ -4,7 +4,7 @@ * prototypes for functions in catalog/pg_constraint.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_constraint_fn.h diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h index 0bc41abee5..23731e98a4 100644 --- a/src/include/catalog/pg_control.h +++ b/src/include/catalog/pg_control.h @@ -5,7 +5,7 @@ * However, we define it here so that the format is documented. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_control.h diff --git a/src/include/catalog/pg_conversion.h b/src/include/catalog/pg_conversion.h index 1cfe57ce19..88174a620a 100644 --- a/src/include/catalog/pg_conversion.h +++ b/src/include/catalog/pg_conversion.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_conversion.h diff --git a/src/include/catalog/pg_conversion_fn.h b/src/include/catalog/pg_conversion_fn.h index 9fcdde6d5b..a2c1345f01 100644 --- a/src/include/catalog/pg_conversion_fn.h +++ b/src/include/catalog/pg_conversion_fn.h @@ -4,7 +4,7 @@ * prototypes for functions in catalog/pg_conversion.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_conversion_fn.h diff --git a/src/include/catalog/pg_database.h b/src/include/catalog/pg_database.h index 6ae1b40559..55a1f6edab 100644 --- a/src/include/catalog/pg_database.h +++ b/src/include/catalog/pg_database.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_database.h diff --git a/src/include/catalog/pg_db_role_setting.h b/src/include/catalog/pg_db_role_setting.h index a1f0150d39..311258fd7b 100644 --- a/src/include/catalog/pg_db_role_setting.h +++ b/src/include/catalog/pg_db_role_setting.h @@ -4,7 +4,7 @@ * definition of configuration settings * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_db_role_setting.h diff --git a/src/include/catalog/pg_default_acl.h b/src/include/catalog/pg_default_acl.h index 06aaaba0da..42fb224f9d 100644 --- a/src/include/catalog/pg_default_acl.h +++ b/src/include/catalog/pg_default_acl.h @@ -4,7 +4,7 @@ * definition of default ACLs for new objects. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_default_acl.h diff --git a/src/include/catalog/pg_depend.h b/src/include/catalog/pg_depend.h index 3796206fa8..6c480dd7dc 100644 --- a/src/include/catalog/pg_depend.h +++ b/src/include/catalog/pg_depend.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_depend.h diff --git a/src/include/catalog/pg_description.h b/src/include/catalog/pg_description.h index c960d0e198..2f51ac33f3 100644 --- a/src/include/catalog/pg_description.h +++ b/src/include/catalog/pg_description.h @@ -19,7 +19,7 @@ * for example). * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_description.h diff --git a/src/include/catalog/pg_enum.h b/src/include/catalog/pg_enum.h index dd32443b91..faee5e6c3c 100644 --- a/src/include/catalog/pg_enum.h +++ b/src/include/catalog/pg_enum.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Copyright (c) 2006-2016, PostgreSQL Global Development Group + * Copyright (c) 2006-2017, PostgreSQL Global Development Group * * src/include/catalog/pg_enum.h * @@ -67,5 +67,7 @@ extern void EnumValuesDelete(Oid enumTypeOid); extern void AddEnumLabel(Oid enumTypeOid, const char *newVal, const char *neighbor, bool newValIsAfter, bool skipIfExists); +extern void RenameEnumLabel(Oid enumTypeOid, + const char *oldVal, const char *newVal); #endif /* PG_ENUM_H */ diff --git a/src/include/catalog/pg_event_trigger.h b/src/include/catalog/pg_event_trigger.h index 8884ef4a3e..b41cc12602 100644 --- a/src/include/catalog/pg_event_trigger.h +++ b/src/include/catalog/pg_event_trigger.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_event_trigger.h diff --git a/src/include/catalog/pg_extension.h b/src/include/catalog/pg_extension.h index e823f7b79a..41b087d8b9 100644 --- a/src/include/catalog/pg_extension.h +++ b/src/include/catalog/pg_extension.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_extension.h diff --git a/src/include/catalog/pg_foreign_data_wrapper.h b/src/include/catalog/pg_foreign_data_wrapper.h index 1e9b4775ce..47df6799c9 100644 --- a/src/include/catalog/pg_foreign_data_wrapper.h +++ b/src/include/catalog/pg_foreign_data_wrapper.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_foreign_data_wrapper.h diff --git a/src/include/catalog/pg_foreign_server.h b/src/include/catalog/pg_foreign_server.h index 06b4f6afe8..629bfc389d 100644 --- a/src/include/catalog/pg_foreign_server.h +++ b/src/include/catalog/pg_foreign_server.h @@ -3,7 +3,7 @@ * pg_foreign_server.h * definition of the system "foreign server" relation (pg_foreign_server) * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_foreign_server.h diff --git a/src/include/catalog/pg_foreign_table.h b/src/include/catalog/pg_foreign_table.h index e7b925b7c9..b62d5e948b 100644 --- a/src/include/catalog/pg_foreign_table.h +++ b/src/include/catalog/pg_foreign_table.h @@ -3,13 +3,13 @@ * pg_foreign_table.h * definition of the system "foreign table" relation (pg_foreign_table) * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_foreign_table.h * * NOTES - * the genbki.sh script reads this file and generates .bki + * the genbki.pl script reads this file and generates .bki * information from the DATA() statements. * *------------------------------------------------------------------------- diff --git a/src/include/catalog/pg_index.h b/src/include/catalog/pg_index.h index ee97c5dec8..7ca0fae707 100644 --- a/src/include/catalog/pg_index.h +++ b/src/include/catalog/pg_index.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_index.h diff --git a/src/include/catalog/pg_inherits.h b/src/include/catalog/pg_inherits.h index a117f7816a..434fa7c864 100644 --- a/src/include/catalog/pg_inherits.h +++ b/src/include/catalog/pg_inherits.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_inherits.h diff --git a/src/include/catalog/pg_inherits_fn.h b/src/include/catalog/pg_inherits_fn.h index a717108481..e33b39e71e 100644 --- a/src/include/catalog/pg_inherits_fn.h +++ b/src/include/catalog/pg_inherits_fn.h @@ -4,7 +4,7 @@ * prototypes for functions in catalog/pg_inherits.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_inherits_fn.h diff --git a/src/include/catalog/pg_init_privs.h b/src/include/catalog/pg_init_privs.h index e13edd3ff5..0d241b8a40 100644 --- a/src/include/catalog/pg_init_privs.h +++ b/src/include/catalog/pg_init_privs.h @@ -15,7 +15,7 @@ * for a table itself, so that it is distinct from any column privilege. * Currently, objsubid is unused and zero for all other kinds of objects. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_init_privs.h diff --git a/src/include/catalog/pg_language.h b/src/include/catalog/pg_language.h index 5203dfd721..46e4099485 100644 --- a/src/include/catalog/pg_language.h +++ b/src/include/catalog/pg_language.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_language.h diff --git a/src/include/catalog/pg_largeobject.h b/src/include/catalog/pg_largeobject.h index 8dae408eae..93c8c6af6e 100644 --- a/src/include/catalog/pg_largeobject.h +++ b/src/include/catalog/pg_largeobject.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_largeobject.h diff --git a/src/include/catalog/pg_largeobject_metadata.h b/src/include/catalog/pg_largeobject_metadata.h index b8e47f60f6..16cb602a6c 100644 --- a/src/include/catalog/pg_largeobject_metadata.h +++ b/src/include/catalog/pg_largeobject_metadata.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_largeobject_metadata.h diff --git a/src/include/catalog/pg_namespace.h b/src/include/catalog/pg_namespace.h index c2e9725245..cb42abf5f8 100644 --- a/src/include/catalog/pg_namespace.h +++ b/src/include/catalog/pg_namespace.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_namespace.h diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h index 6c82d94600..0cde14c25d 100644 --- a/src/include/catalog/pg_opclass.h +++ b/src/include/catalog/pg_opclass.h @@ -25,7 +25,7 @@ * AMs support this. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_opclass.h @@ -113,6 +113,7 @@ DATA(insert ( 405 float8_ops PGNSP PGUID 1971 701 t 0 )); DATA(insert ( 403 inet_ops PGNSP PGUID 1974 869 t 0 )); DATA(insert ( 405 inet_ops PGNSP PGUID 1975 869 t 0 )); DATA(insert ( 783 inet_ops PGNSP PGUID 3550 869 f 0 )); +DATA(insert ( 4000 inet_ops PGNSP PGUID 3794 869 t 0 )); DATA(insert OID = 1979 ( 403 int2_ops PGNSP PGUID 1976 21 t 0 )); #define INT2_BTREE_OPS_OID 1979 DATA(insert ( 405 int2_ops PGNSP PGUID 1977 21 t 0 )); @@ -167,7 +168,6 @@ DATA(insert ( 403 bpchar_pattern_ops PGNSP PGUID 2097 1042 f 0 )); DATA(insert ( 403 money_ops PGNSP PGUID 2099 790 t 0 )); DATA(insert ( 405 bool_ops PGNSP PGUID 2222 16 t 0 )); DATA(insert ( 405 bytea_ops PGNSP PGUID 2223 17 t 0 )); -DATA(insert ( 405 int2vector_ops PGNSP PGUID 2224 22 t 0 )); DATA(insert ( 403 tid_ops PGNSP PGUID 2789 27 t 0 )); DATA(insert ( 405 xid_ops PGNSP PGUID 2225 28 t 0 )); DATA(insert ( 405 cid_ops PGNSP PGUID 2226 29 t 0 )); @@ -183,36 +183,7 @@ DATA(insert ( 783 box_ops PGNSP PGUID 2593 603 t 0 )); DATA(insert ( 783 point_ops PGNSP PGUID 1029 600 t 603 )); DATA(insert ( 783 poly_ops PGNSP PGUID 2594 604 t 603 )); DATA(insert ( 783 circle_ops PGNSP PGUID 2595 718 t 603 )); -DATA(insert ( 2742 _int4_ops PGNSP PGUID 2745 1007 t 23 )); -DATA(insert ( 2742 _text_ops PGNSP PGUID 2745 1009 t 25 )); -DATA(insert ( 2742 _abstime_ops PGNSP PGUID 2745 1023 t 702 )); -DATA(insert ( 2742 _bit_ops PGNSP PGUID 2745 1561 t 1560 )); -DATA(insert ( 2742 _bool_ops PGNSP PGUID 2745 1000 t 16 )); -DATA(insert ( 2742 _bpchar_ops PGNSP PGUID 2745 1014 t 1042 )); -DATA(insert ( 2742 _bytea_ops PGNSP PGUID 2745 1001 t 17 )); -DATA(insert ( 2742 _char_ops PGNSP PGUID 2745 1002 t 18 )); -DATA(insert ( 2742 _cidr_ops PGNSP PGUID 2745 651 t 650 )); -DATA(insert ( 2742 _date_ops PGNSP PGUID 2745 1182 t 1082 )); -DATA(insert ( 2742 _float4_ops PGNSP PGUID 2745 1021 t 700 )); -DATA(insert ( 2742 _float8_ops PGNSP PGUID 2745 1022 t 701 )); -DATA(insert ( 2742 _inet_ops PGNSP PGUID 2745 1041 t 869 )); -DATA(insert ( 2742 _int2_ops PGNSP PGUID 2745 1005 t 21 )); -DATA(insert ( 2742 _int8_ops PGNSP PGUID 2745 1016 t 20 )); -DATA(insert ( 2742 _interval_ops PGNSP PGUID 2745 1187 t 1186 )); -DATA(insert ( 2742 _macaddr_ops PGNSP PGUID 2745 1040 t 829 )); -DATA(insert ( 2742 _name_ops PGNSP PGUID 2745 1003 t 19 )); -DATA(insert ( 2742 _numeric_ops PGNSP PGUID 2745 1231 t 1700 )); -DATA(insert ( 2742 _oid_ops PGNSP PGUID 2745 1028 t 26 )); -DATA(insert ( 2742 _oidvector_ops PGNSP PGUID 2745 1013 t 30 )); -DATA(insert ( 2742 _time_ops PGNSP PGUID 2745 1183 t 1083 )); -DATA(insert ( 2742 _timestamptz_ops PGNSP PGUID 2745 1185 t 1184 )); -DATA(insert ( 2742 _timetz_ops PGNSP PGUID 2745 1270 t 1266 )); -DATA(insert ( 2742 _varbit_ops PGNSP PGUID 2745 1563 t 1562 )); -DATA(insert ( 2742 _varchar_ops PGNSP PGUID 2745 1015 t 1043 )); -DATA(insert ( 2742 _timestamp_ops PGNSP PGUID 2745 1115 t 1114 )); -DATA(insert ( 2742 _money_ops PGNSP PGUID 2745 791 t 790 )); -DATA(insert ( 2742 _reltime_ops PGNSP PGUID 2745 1024 t 703 )); -DATA(insert ( 2742 _tinterval_ops PGNSP PGUID 2745 1025 t 704 )); +DATA(insert ( 2742 array_ops PGNSP PGUID 2745 2277 t 2283 )); DATA(insert ( 403 uuid_ops PGNSP PGUID 2968 2950 t 0 )); DATA(insert ( 405 uuid_ops PGNSP PGUID 2969 2950 t 0 )); DATA(insert ( 403 pg_lsn_ops PGNSP PGUID 3253 3220 t 0 )); diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index b8f06b3500..45feb69b93 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_operator.h @@ -156,8 +156,6 @@ DATA(insert OID = 389 ( "!!" PGNSP PGUID l f f 0 20 1700 0 0 numeric_fac DESCR("deprecated, use ! instead"); DATA(insert OID = 385 ( "=" PGNSP PGUID b f t 29 29 16 385 0 cideq eqsel eqjoinsel )); DESCR("equal"); -DATA(insert OID = 386 ( "=" PGNSP PGUID b f t 22 22 16 386 0 int2vectoreq eqsel eqjoinsel )); -DESCR("equal"); DATA(insert OID = 387 ( "=" PGNSP PGUID b t f 27 27 16 387 402 tideq eqsel eqjoinsel )); DESCR("equal"); @@ -711,6 +709,10 @@ DATA(insert OID = 908 ( "*" PGNSP PGUID b f f 790 701 790 916 0 cash_mul_ DESCR("multiply"); DATA(insert OID = 909 ( "/" PGNSP PGUID b f f 790 701 790 0 0 cash_div_flt8 - - )); DESCR("divide"); +DATA(insert OID = 3346 ( "*" PGNSP PGUID b f f 790 20 790 3349 0 cash_mul_int8 - - )); +DESCR("multiply"); +DATA(insert OID = 3347 ( "/" PGNSP PGUID b f f 790 20 790 0 0 cash_div_int8 - - )); +DESCR("divide"); DATA(insert OID = 912 ( "*" PGNSP PGUID b f f 790 23 790 917 0 cash_mul_int4 - - )); DESCR("multiply"); DATA(insert OID = 913 ( "/" PGNSP PGUID b f f 790 23 790 0 0 cash_div_int4 - - )); @@ -721,6 +723,8 @@ DATA(insert OID = 915 ( "/" PGNSP PGUID b f f 790 21 790 0 0 cash_div_ DESCR("divide"); DATA(insert OID = 916 ( "*" PGNSP PGUID b f f 701 790 790 908 0 flt8_mul_cash - - )); DESCR("multiply"); +DATA(insert OID = 3349 ( "*" PGNSP PGUID b f f 20 790 790 3346 0 int8_mul_cash - - )); +DESCR("multiply"); DATA(insert OID = 917 ( "*" PGNSP PGUID b f f 23 790 790 912 0 int4_mul_cash - - )); DESCR("multiply"); DATA(insert OID = 918 ( "*" PGNSP PGUID b f f 21 790 790 914 0 int2_mul_cash - - )); @@ -1822,6 +1826,8 @@ DATA(insert OID = 3284 ( "||" PGNSP PGUID b f f 3802 3802 3802 0 0 jsonb_con DESCR("concatenate"); DATA(insert OID = 3285 ( "-" PGNSP PGUID b f f 3802 25 3802 0 0 3302 - - )); DESCR("delete object field"); +DATA(insert OID = 3398 ( "-" PGNSP PGUID b f f 3802 1009 3802 0 0 3343 - -)); +DESCR("delete object fields"); DATA(insert OID = 3286 ( "-" PGNSP PGUID b f f 3802 23 3802 0 0 3303 - - )); DESCR("delete array element"); DATA(insert OID = 3287 ( "#-" PGNSP PGUID b f f 3802 1009 3802 0 0 jsonb_delete_path - - )); diff --git a/src/include/catalog/pg_operator_fn.h b/src/include/catalog/pg_operator_fn.h index 58814e2111..d8ea390fdf 100644 --- a/src/include/catalog/pg_operator_fn.h +++ b/src/include/catalog/pg_operator_fn.h @@ -4,7 +4,7 @@ * prototypes for functions in catalog/pg_operator.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_operator_fn.h diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h index 1499a502f3..bd673fe59b 100644 --- a/src/include/catalog/pg_opfamily.h +++ b/src/include/catalog/pg_opfamily.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_opfamily.h @@ -79,6 +79,7 @@ DATA(insert OID = 1974 ( 403 network_ops PGNSP PGUID )); #define NETWORK_BTREE_FAM_OID 1974 DATA(insert OID = 1975 ( 405 network_ops PGNSP PGUID )); DATA(insert OID = 3550 ( 783 network_ops PGNSP PGUID )); +DATA(insert OID = 3794 ( 4000 network_ops PGNSP PGUID )); DATA(insert OID = 1976 ( 403 integer_ops PGNSP PGUID )); #define INTEGER_BTREE_FAM_OID 1976 DATA(insert OID = 1977 ( 405 integer_ops PGNSP PGUID )); @@ -116,7 +117,6 @@ DATA(insert OID = 2099 ( 403 money_ops PGNSP PGUID )); DATA(insert OID = 2222 ( 405 bool_ops PGNSP PGUID )); #define BOOL_HASH_FAM_OID 2222 DATA(insert OID = 2223 ( 405 bytea_ops PGNSP PGUID )); -DATA(insert OID = 2224 ( 405 int2vector_ops PGNSP PGUID )); DATA(insert OID = 2789 ( 403 tid_ops PGNSP PGUID )); DATA(insert OID = 2225 ( 405 xid_ops PGNSP PGUID )); DATA(insert OID = 2226 ( 405 cid_ops PGNSP PGUID )); diff --git a/src/include/catalog/pg_partitioned_table.h b/src/include/catalog/pg_partitioned_table.h new file mode 100644 index 0000000000..bdff36a04b --- /dev/null +++ b/src/include/catalog/pg_partitioned_table.h @@ -0,0 +1,74 @@ +/*------------------------------------------------------------------------- + * + * pg_partitioned_table.h + * definition of the system "partitioned table" relation + * along with the relation's initial contents. + * + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group + * + * src/include/catalog/pg_partitioned_table.h + * + * NOTES + * the genbki.sh script reads this file and generates .bki + * information from the DATA() statements. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_PARTITIONED_TABLE_H +#define PG_PARTITIONED_TABLE_H + +#include "catalog/genbki.h" + +/* ---------------- + * pg_partitioned_table definition. cpp turns this into + * typedef struct FormData_pg_partitioned_table + * ---------------- + */ +#define PartitionedRelationId 3350 + +CATALOG(pg_partitioned_table,3350) BKI_WITHOUT_OIDS +{ + Oid partrelid; /* partitioned table oid */ + char partstrat; /* partitioning strategy */ + int16 partnatts; /* number of partition key columns */ + + /* + * variable-length fields start here, but we allow direct access to + * partattrs via the C struct. That's because the first variable-length + * field of a heap tuple can be reliably accessed using its C struct + * offset, as previous fields are all non-nullable fixed-length fields. + */ + int2vector partattrs; /* each member of the array is the attribute + * number of a partition key column, or 0 if + * the column is actually an expression */ + +#ifdef CATALOG_VARLEN + oidvector partclass; /* operator class to compare keys */ + oidvector partcollation; /* user-specified collation for keys */ + pg_node_tree partexprs; /* list of expressions in the partition key; + * one item for each zero entry in partattrs[] */ +#endif +} FormData_pg_partitioned_table; + +/* ---------------- + * Form_pg_partitioned_table corresponds to a pointer to a tuple with + * the format of pg_partitioned_table relation. + * ---------------- + */ +typedef FormData_pg_partitioned_table *Form_pg_partitioned_table; + +/* ---------------- + * compiler constants for pg_partitioned_table + * ---------------- + */ +#define Natts_pg_partitioned_table 7 +#define Anum_pg_partitioned_table_partrelid 1 +#define Anum_pg_partitioned_table_partstrat 2 +#define Anum_pg_partitioned_table_partnatts 3 +#define Anum_pg_partitioned_table_partattrs 4 +#define Anum_pg_partitioned_table_partclass 5 +#define Anum_pg_partitioned_table_partcollation 6 +#define Anum_pg_partitioned_table_partexprs 7 + +#endif /* PG_PARTITIONED_TABLE_H */ diff --git a/src/include/catalog/pg_pltemplate.h b/src/include/catalog/pg_pltemplate.h index 3c7388de55..6d770fbb3c 100644 --- a/src/include/catalog/pg_pltemplate.h +++ b/src/include/catalog/pg_pltemplate.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_pltemplate.h diff --git a/src/include/catalog/pg_policy.h b/src/include/catalog/pg_policy.h index d73e9c2c1a..f8dc2ccf15 100644 --- a/src/include/catalog/pg_policy.h +++ b/src/include/catalog/pg_policy.h @@ -2,7 +2,7 @@ * pg_policy.h * definition of the system "policy" relation (pg_policy) * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * */ @@ -23,6 +23,7 @@ CATALOG(pg_policy,3256) NameData polname; /* Policy name. */ Oid polrelid; /* Oid of the relation with policy. */ char polcmd; /* One of ACL_*_CHR, or '*' for all */ + bool polpermissive; /* restrictive or permissive policy */ #ifdef CATALOG_VARLEN Oid polroles[1]; /* Roles associated with policy, not-NULL */ @@ -42,12 +43,13 @@ typedef FormData_pg_policy *Form_pg_policy; * compiler constants for pg_policy * ---------------- */ -#define Natts_pg_policy 6 -#define Anum_pg_policy_polname 1 -#define Anum_pg_policy_polrelid 2 -#define Anum_pg_policy_polcmd 3 -#define Anum_pg_policy_polroles 4 -#define Anum_pg_policy_polqual 5 -#define Anum_pg_policy_polwithcheck 6 +#define Natts_pg_policy 7 +#define Anum_pg_policy_polname 1 +#define Anum_pg_policy_polrelid 2 +#define Anum_pg_policy_polcmd 3 +#define Anum_pg_policy_polpermissive 4 +#define Anum_pg_policy_polroles 5 +#define Anum_pg_policy_polqual 6 +#define Anum_pg_policy_polwithcheck 7 #endif /* PG_POLICY_H */ diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index af19c1a82b..ab12761643 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -4,7 +4,7 @@ * definition of the system "procedure" relation (pg_proc) * along with the relation's initial contents. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_proc.h @@ -540,7 +540,6 @@ DATA(insert OID = 313 ( int4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 DESCR("convert int2 to int4"); DATA(insert OID = 314 ( int2 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 21 "23" _null_ _null_ _null_ _null_ _null_ i4toi2 _null_ _null_ _null_ )); DESCR("convert int4 to int2"); -DATA(insert OID = 315 ( int2vectoreq PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 16 "22 22" _null_ _null_ _null_ _null_ _null_ int2vectoreq _null_ _null_ _null_ )); DATA(insert OID = 316 ( float8 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 701 "23" _null_ _null_ _null_ _null_ _null_ i4tod _null_ _null_ _null_ )); DESCR("convert int4 to float8"); DATA(insert OID = 317 ( int4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "701" _null_ _null_ _null_ _null_ _null_ dtoi4 _null_ _null_ _null_ )); @@ -687,8 +686,6 @@ DATA(insert OID = 457 ( hashoidvector PGNSP PGUID 12 1 0 0 0 f f f f t f i s DESCR("hash"); DATA(insert OID = 329 ( hash_aclitem PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "1033" _null_ _null_ _null_ _null_ _null_ hash_aclitem _null_ _null_ _null_ )); DESCR("hash"); -DATA(insert OID = 398 ( hashint2vector PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "22" _null_ _null_ _null_ _null_ _null_ hashint2vector _null_ _null_ _null_ )); -DESCR("hash"); DATA(insert OID = 399 ( hashmacaddr PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "829" _null_ _null_ _null_ _null_ _null_ hashmacaddr _null_ _null_ _null_ )); DESCR("hash"); DATA(insert OID = 422 ( hashinet PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "869" _null_ _null_ _null_ _null_ _null_ hashinet _null_ _null_ _null_ )); @@ -906,11 +903,11 @@ DESCR("storage manager"); DATA(insert OID = 763 ( smgrne PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 16 "210 210" _null_ _null_ _null_ _null_ _null_ smgrne _null_ _null_ _null_ )); DESCR("storage manager"); -DATA(insert OID = 764 ( lo_import PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 26 "25" _null_ _null_ _null_ _null_ _null_ lo_import _null_ _null_ _null_ )); +DATA(insert OID = 764 ( lo_import PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 26 "25" _null_ _null_ _null_ _null_ _null_ be_lo_import _null_ _null_ _null_ )); DESCR("large object import"); -DATA(insert OID = 767 ( lo_import PGNSP PGUID 12 1 0 0 0 f f f f t f v u 2 0 26 "25 26" _null_ _null_ _null_ _null_ _null_ lo_import_with_oid _null_ _null_ _null_ )); +DATA(insert OID = 767 ( lo_import PGNSP PGUID 12 1 0 0 0 f f f f t f v u 2 0 26 "25 26" _null_ _null_ _null_ _null_ _null_ be_lo_import_with_oid _null_ _null_ _null_ )); DESCR("large object import"); -DATA(insert OID = 765 ( lo_export PGNSP PGUID 12 1 0 0 0 f f f f t f v u 2 0 23 "26 25" _null_ _null_ _null_ _null_ _null_ lo_export _null_ _null_ _null_ )); +DATA(insert OID = 765 ( lo_export PGNSP PGUID 12 1 0 0 0 f f f f t f v u 2 0 23 "26 25" _null_ _null_ _null_ _null_ _null_ be_lo_export _null_ _null_ _null_ )); DESCR("large object export"); DATA(insert OID = 766 ( int4inc PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "23" _null_ _null_ _null_ _null_ _null_ int4inc _null_ _null_ _null_ )); @@ -960,8 +957,11 @@ DESCR("name of the current database"); DATA(insert OID = 817 ( current_query PGNSP PGUID 12 1 0 0 0 f f f f f f v r 0 0 25 "" _null_ _null_ _null_ _null_ _null_ current_query _null_ _null_ _null_ )); DESCR("get the currently executing query"); +DATA(insert OID = 3399 ( int8_mul_cash PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 790 "20 790" _null_ _null_ _null_ _null_ _null_ int8_mul_cash _null_ _null_ _null_ )); DATA(insert OID = 862 ( int4_mul_cash PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 790 "23 790" _null_ _null_ _null_ _null_ _null_ int4_mul_cash _null_ _null_ _null_ )); DATA(insert OID = 863 ( int2_mul_cash PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 790 "21 790" _null_ _null_ _null_ _null_ _null_ int2_mul_cash _null_ _null_ _null_ )); +DATA(insert OID = 3344 ( cash_mul_int8 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 790 "790 20" _null_ _null_ _null_ _null_ _null_ cash_mul_int8 _null_ _null_ _null_ )); +DATA(insert OID = 3345 ( cash_div_int8 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 790 "790 20" _null_ _null_ _null_ _null_ _null_ cash_div_int8 _null_ _null_ _null_ )); DATA(insert OID = 864 ( cash_mul_int4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 790 "790 23" _null_ _null_ _null_ _null_ _null_ cash_mul_int4 _null_ _null_ _null_ )); DATA(insert OID = 865 ( cash_div_int4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 790 "790 23" _null_ _null_ _null_ _null_ _null_ cash_div_int4 _null_ _null_ _null_ )); DATA(insert OID = 866 ( cash_mul_int2 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 790 "790 21" _null_ _null_ _null_ _null_ _null_ cash_mul_int2 _null_ _null_ _null_ )); @@ -1014,38 +1014,38 @@ DESCR("convert text to char"); DATA(insert OID = 946 ( text PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 25 "18" _null_ _null_ _null_ _null_ _null_ char_text _null_ _null_ _null_ )); DESCR("convert char to text"); -DATA(insert OID = 952 ( lo_open PGNSP PGUID 12 1 0 0 0 f f f f t f v u 2 0 23 "26 23" _null_ _null_ _null_ _null_ _null_ lo_open _null_ _null_ _null_ )); +DATA(insert OID = 952 ( lo_open PGNSP PGUID 12 1 0 0 0 f f f f t f v u 2 0 23 "26 23" _null_ _null_ _null_ _null_ _null_ be_lo_open _null_ _null_ _null_ )); DESCR("large object open"); -DATA(insert OID = 953 ( lo_close PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 23 "23" _null_ _null_ _null_ _null_ _null_ lo_close _null_ _null_ _null_ )); +DATA(insert OID = 953 ( lo_close PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 23 "23" _null_ _null_ _null_ _null_ _null_ be_lo_close _null_ _null_ _null_ )); DESCR("large object close"); -DATA(insert OID = 954 ( loread PGNSP PGUID 12 1 0 0 0 f f f f t f v u 2 0 17 "23 23" _null_ _null_ _null_ _null_ _null_ loread _null_ _null_ _null_ )); +DATA(insert OID = 954 ( loread PGNSP PGUID 12 1 0 0 0 f f f f t f v u 2 0 17 "23 23" _null_ _null_ _null_ _null_ _null_ be_loread _null_ _null_ _null_ )); DESCR("large object read"); -DATA(insert OID = 955 ( lowrite PGNSP PGUID 12 1 0 0 0 f f f f t f v u 2 0 23 "23 17" _null_ _null_ _null_ _null_ _null_ lowrite _null_ _null_ _null_ )); +DATA(insert OID = 955 ( lowrite PGNSP PGUID 12 1 0 0 0 f f f f t f v u 2 0 23 "23 17" _null_ _null_ _null_ _null_ _null_ be_lowrite _null_ _null_ _null_ )); DESCR("large object write"); -DATA(insert OID = 956 ( lo_lseek PGNSP PGUID 12 1 0 0 0 f f f f t f v u 3 0 23 "23 23 23" _null_ _null_ _null_ _null_ _null_ lo_lseek _null_ _null_ _null_ )); +DATA(insert OID = 956 ( lo_lseek PGNSP PGUID 12 1 0 0 0 f f f f t f v u 3 0 23 "23 23 23" _null_ _null_ _null_ _null_ _null_ be_lo_lseek _null_ _null_ _null_ )); DESCR("large object seek"); -DATA(insert OID = 3170 ( lo_lseek64 PGNSP PGUID 12 1 0 0 0 f f f f t f v u 3 0 20 "23 20 23" _null_ _null_ _null_ _null_ _null_ lo_lseek64 _null_ _null_ _null_ )); +DATA(insert OID = 3170 ( lo_lseek64 PGNSP PGUID 12 1 0 0 0 f f f f t f v u 3 0 20 "23 20 23" _null_ _null_ _null_ _null_ _null_ be_lo_lseek64 _null_ _null_ _null_ )); DESCR("large object seek (64 bit)"); -DATA(insert OID = 957 ( lo_creat PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 26 "23" _null_ _null_ _null_ _null_ _null_ lo_creat _null_ _null_ _null_ )); +DATA(insert OID = 957 ( lo_creat PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 26 "23" _null_ _null_ _null_ _null_ _null_ be_lo_creat _null_ _null_ _null_ )); DESCR("large object create"); -DATA(insert OID = 715 ( lo_create PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 26 "26" _null_ _null_ _null_ _null_ _null_ lo_create _null_ _null_ _null_ )); +DATA(insert OID = 715 ( lo_create PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 26 "26" _null_ _null_ _null_ _null_ _null_ be_lo_create _null_ _null_ _null_ )); DESCR("large object create"); -DATA(insert OID = 958 ( lo_tell PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 23 "23" _null_ _null_ _null_ _null_ _null_ lo_tell _null_ _null_ _null_ )); +DATA(insert OID = 958 ( lo_tell PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 23 "23" _null_ _null_ _null_ _null_ _null_ be_lo_tell _null_ _null_ _null_ )); DESCR("large object position"); -DATA(insert OID = 3171 ( lo_tell64 PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 20 "23" _null_ _null_ _null_ _null_ _null_ lo_tell64 _null_ _null_ _null_ )); +DATA(insert OID = 3171 ( lo_tell64 PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 20 "23" _null_ _null_ _null_ _null_ _null_ be_lo_tell64 _null_ _null_ _null_ )); DESCR("large object position (64 bit)"); -DATA(insert OID = 1004 ( lo_truncate PGNSP PGUID 12 1 0 0 0 f f f f t f v u 2 0 23 "23 23" _null_ _null_ _null_ _null_ _null_ lo_truncate _null_ _null_ _null_ )); +DATA(insert OID = 1004 ( lo_truncate PGNSP PGUID 12 1 0 0 0 f f f f t f v u 2 0 23 "23 23" _null_ _null_ _null_ _null_ _null_ be_lo_truncate _null_ _null_ _null_ )); DESCR("truncate large object"); -DATA(insert OID = 3172 ( lo_truncate64 PGNSP PGUID 12 1 0 0 0 f f f f t f v u 2 0 23 "23 20" _null_ _null_ _null_ _null_ _null_ lo_truncate64 _null_ _null_ _null_ )); +DATA(insert OID = 3172 ( lo_truncate64 PGNSP PGUID 12 1 0 0 0 f f f f t f v u 2 0 23 "23 20" _null_ _null_ _null_ _null_ _null_ be_lo_truncate64 _null_ _null_ _null_ )); DESCR("truncate large object (64 bit)"); -DATA(insert OID = 3457 ( lo_from_bytea PGNSP PGUID 12 1 0 0 0 f f f f t f v u 2 0 26 "26 17" _null_ _null_ _null_ _null_ _null_ lo_from_bytea _null_ _null_ _null_ )); +DATA(insert OID = 3457 ( lo_from_bytea PGNSP PGUID 12 1 0 0 0 f f f f t f v u 2 0 26 "26 17" _null_ _null_ _null_ _null_ _null_ be_lo_from_bytea _null_ _null_ _null_ )); DESCR("create new large object with given content"); -DATA(insert OID = 3458 ( lo_get PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 17 "26" _null_ _null_ _null_ _null_ _null_ lo_get _null_ _null_ _null_ )); +DATA(insert OID = 3458 ( lo_get PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 17 "26" _null_ _null_ _null_ _null_ _null_ be_lo_get _null_ _null_ _null_ )); DESCR("read entire large object"); -DATA(insert OID = 3459 ( lo_get PGNSP PGUID 12 1 0 0 0 f f f f t f v u 3 0 17 "26 20 23" _null_ _null_ _null_ _null_ _null_ lo_get_fragment _null_ _null_ _null_ )); +DATA(insert OID = 3459 ( lo_get PGNSP PGUID 12 1 0 0 0 f f f f t f v u 3 0 17 "26 20 23" _null_ _null_ _null_ _null_ _null_ be_lo_get_fragment _null_ _null_ _null_ )); DESCR("read large object from offset for length"); -DATA(insert OID = 3460 ( lo_put PGNSP PGUID 12 1 0 0 0 f f f f t f v u 3 0 2278 "26 20 17" _null_ _null_ _null_ _null_ _null_ lo_put _null_ _null_ _null_ )); +DATA(insert OID = 3460 ( lo_put PGNSP PGUID 12 1 0 0 0 f f f f t f v u 3 0 2278 "26 20 17" _null_ _null_ _null_ _null_ _null_ be_lo_put _null_ _null_ _null_ )); DESCR("write data at offset"); DATA(insert OID = 959 ( on_pl PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 16 "600 628" _null_ _null_ _null_ _null_ _null_ on_pl _null_ _null_ _null_ )); @@ -1054,7 +1054,7 @@ DATA(insert OID = 961 ( close_pl PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 DATA(insert OID = 962 ( close_sl PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 600 "601 628" _null_ _null_ _null_ _null_ _null_ close_sl _null_ _null_ _null_ )); DATA(insert OID = 963 ( close_lb PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 600 "628 603" _null_ _null_ _null_ _null_ _null_ close_lb _null_ _null_ _null_ )); -DATA(insert OID = 964 ( lo_unlink PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 23 "26" _null_ _null_ _null_ _null_ _null_ lo_unlink _null_ _null_ _null_ )); +DATA(insert OID = 964 ( lo_unlink PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 23 "26" _null_ _null_ _null_ _null_ _null_ be_lo_unlink _null_ _null_ _null_ )); DESCR("large object unlink (delete)"); DATA(insert OID = 973 ( path_inter PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 16 "602 602" _null_ _null_ _null_ _null_ _null_ path_inter _null_ _null_ _null_ )); @@ -1766,8 +1766,10 @@ DATA(insert OID = 1576 ( setval PGNSP PGUID 12 1 0 0 0 f f f f t f v u 2 0 20 DESCR("set sequence value"); DATA(insert OID = 1765 ( setval PGNSP PGUID 12 1 0 0 0 f f f f t f v u 3 0 20 "2205 20 16" _null_ _null_ _null_ _null_ _null_ setval3_oid _null_ _null_ _null_ )); DESCR("set sequence value and is_called status"); -DATA(insert OID = 3078 ( pg_sequence_parameters PGNSP PGUID 12 1 0 0 0 f f f f t f s s 1 0 2249 "26" "{26,20,20,20,20,16}" "{i,o,o,o,o,o}" "{sequence_oid,start_value,minimum_value,maximum_value,increment,cycle_option}" _null_ _null_ pg_sequence_parameters _null_ _null_ _null_)); +DATA(insert OID = 3078 ( pg_sequence_parameters PGNSP PGUID 12 1 0 0 0 f f f f t f s s 1 0 2249 "26" "{26,20,20,20,20,16,20}" "{i,o,o,o,o,o,o}" "{sequence_oid,start_value,minimum_value,maximum_value,increment,cycle_option,cache_size}" _null_ _null_ pg_sequence_parameters _null_ _null_ _null_)); DESCR("sequence parameters, for use by information schema"); +DATA(insert OID = 4032 ( pg_sequence_last_value PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 20 "2205" _null_ _null_ _null_ _null_ _null_ pg_sequence_last_value _null_ _null_ _null_ )); +DESCR("sequence last value"); DATA(insert OID = 1579 ( varbit_in PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 1562 "2275 26 23" _null_ _null_ _null_ _null_ _null_ varbit_in _null_ _null_ _null_ )); DESCR("I/O"); @@ -1912,10 +1914,14 @@ DATA(insert OID = 2284 ( regexp_replace PGNSP PGUID 12 1 0 0 0 f f f f t f i DESCR("replace text using regexp"); DATA(insert OID = 2285 ( regexp_replace PGNSP PGUID 12 1 0 0 0 f f f f t f i s 4 0 25 "25 25 25 25" _null_ _null_ _null_ _null_ _null_ textregexreplace _null_ _null_ _null_ )); DESCR("replace text using regexp"); +DATA(insert OID = 3396 ( regexp_match PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 1009 "25 25" _null_ _null_ _null_ _null_ _null_ regexp_match_no_flags _null_ _null_ _null_ )); +DESCR("find first match for regexp"); +DATA(insert OID = 3397 ( regexp_match PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 1009 "25 25 25" _null_ _null_ _null_ _null_ _null_ regexp_match _null_ _null_ _null_ )); +DESCR("find first match for regexp"); DATA(insert OID = 2763 ( regexp_matches PGNSP PGUID 12 1 1 0 0 f f f f t t i s 2 0 1009 "25 25" _null_ _null_ _null_ _null_ _null_ regexp_matches_no_flags _null_ _null_ _null_ )); -DESCR("find all match groups for regexp"); +DESCR("find match(es) for regexp"); DATA(insert OID = 2764 ( regexp_matches PGNSP PGUID 12 1 10 0 0 f f f f t t i s 3 0 1009 "25 25 25" _null_ _null_ _null_ _null_ _null_ regexp_matches _null_ _null_ _null_ )); -DESCR("find all match groups for regexp"); +DESCR("find match(es) for regexp"); DATA(insert OID = 2088 ( split_part PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 25 "25 25 23" _null_ _null_ _null_ _null_ _null_ split_text _null_ _null_ _null_ )); DESCR("split string by field_sep and return field_num"); DATA(insert OID = 2765 ( regexp_split_to_table PGNSP PGUID 12 1 1000 0 0 f f f f t t i s 2 0 25 "25 25" _null_ _null_ _null_ _null_ _null_ regexp_split_to_table_no_flags _null_ _null_ _null_ )); @@ -1976,6 +1982,8 @@ DATA(insert OID = 1642 ( pg_get_userbyid PGNSP PGUID 12 1 0 0 0 f f f f t f DESCR("role name by OID (with fallback)"); DATA(insert OID = 1643 ( pg_get_indexdef PGNSP PGUID 12 1 0 0 0 f f f f t f s s 1 0 25 "26" _null_ _null_ _null_ _null_ _null_ pg_get_indexdef _null_ _null_ _null_ )); DESCR("index description"); +DATA(insert OID = 3352 ( pg_get_partkeydef PGNSP PGUID 12 1 0 0 0 f f f f t f s s 1 0 25 "26" _null_ _null_ _null_ _null_ _null_ pg_get_partkeydef _null_ _null_ _null_ )); +DESCR("partition key description"); DATA(insert OID = 1662 ( pg_get_triggerdef PGNSP PGUID 12 1 0 0 0 f f f f t f s s 1 0 25 "26" _null_ _null_ _null_ _null_ _null_ pg_get_triggerdef _null_ _null_ _null_ )); DESCR("trigger description"); DATA(insert OID = 1387 ( pg_get_constraintdef PGNSP PGUID 12 1 0 0 0 f f f f t f s s 1 0 25 "26" _null_ _null_ _null_ _null_ _null_ pg_get_constraintdef _null_ _null_ _null_ )); @@ -2050,6 +2058,7 @@ DATA(insert OID = 1671 ( varbitlt PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 DATA(insert OID = 1672 ( varbitcmp PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 23 "1562 1562" _null_ _null_ _null_ _null_ _null_ bitcmp _null_ _null_ _null_ )); DESCR("less-equal-greater"); +/* avoid the C names bitand and bitor, since they are C++ keywords */ DATA(insert OID = 1673 ( bitand PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 1560 "1560 1560" _null_ _null_ _null_ _null_ _null_ bit_and _null_ _null_ _null_ )); DATA(insert OID = 1674 ( bitor PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 1560 "1560 1560" _null_ _null_ _null_ _null_ _null_ bit_or _null_ _null_ _null_ )); DATA(insert OID = 1675 ( bitxor PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 1560 "1560 1560" _null_ _null_ _null_ _null_ _null_ bitxor _null_ _null_ _null_ )); @@ -2208,6 +2217,18 @@ DESCR("GiST support"); DATA(insert OID = 3559 ( inet_gist_same PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 2281 "869 869 2281" _null_ _null_ _null_ _null_ _null_ inet_gist_same _null_ _null_ _null_ )); DESCR("GiST support"); +/* SP-GiST support for inet and cidr */ +DATA(insert OID = 3795 ( inet_spg_config PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ inet_spg_config _null_ _null_ _null_ )); +DESCR("SP-GiST support"); +DATA(insert OID = 3796 ( inet_spg_choose PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ inet_spg_choose _null_ _null_ _null_ )); +DESCR("SP-GiST support"); +DATA(insert OID = 3797 ( inet_spg_picksplit PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ inet_spg_picksplit _null_ _null_ _null_ )); +DESCR("SP-GiST support"); +DATA(insert OID = 3798 ( inet_spg_inner_consistent PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ inet_spg_inner_consistent _null_ _null_ _null_ )); +DESCR("SP-GiST support"); +DATA(insert OID = 3799 ( inet_spg_leaf_consistent PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ inet_spg_leaf_consistent _null_ _null_ _null_ )); +DESCR("SP-GiST support"); + /* Selectivity estimation for inet and cidr */ DATA(insert OID = 3560 ( networksel PGNSP PGUID 12 1 0 0 0 f f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ networksel _null_ _null_ _null_ )); DESCR("restriction selectivity for network operators"); @@ -2755,6 +2776,8 @@ DATA(insert OID = 3099 ( pg_stat_get_wal_senders PGNSP PGUID 12 1 10 0 0 f f f DESCR("statistics: information about currently active replication"); DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25}" "{o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ )); DESCR("statistics: information about WAL receiver"); +DATA(insert OID = 6118 ( pg_stat_get_subscription PGNSP PGUID 12 1 0 0 0 f f f f f f s r 1 0 2249 "26" "{26,26,23,3220,1184,1184,3220,1184}" "{i,o,o,o,o,o,o,o}" "{subid,subid,pid,received_lsn,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time}" _null_ _null_ pg_stat_get_subscription _null_ _null_ _null_ )); +DESCR("statistics: information about subscription"); DATA(insert OID = 2026 ( pg_backend_pid PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 23 "" _null_ _null_ _null_ _null_ _null_ pg_backend_pid _null_ _null_ _null_ )); DESCR("statistics: current backend PID"); DATA(insert OID = 1937 ( pg_stat_get_backend_pid PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 23 "23" _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_pid _null_ _null_ _null_ )); @@ -2820,9 +2843,9 @@ DESCR("statistics: number of temporary files written"); DATA(insert OID = 3151 ( pg_stat_get_db_temp_bytes PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 20 "26" _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_temp_bytes _null_ _null_ _null_ )); DESCR("statistics: number of bytes in temporary files written"); DATA(insert OID = 2844 ( pg_stat_get_db_blk_read_time PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 701 "26" _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_blk_read_time _null_ _null_ _null_ )); -DESCR("statistics: block read time, in msec"); +DESCR("statistics: block read time, in milliseconds"); DATA(insert OID = 2845 ( pg_stat_get_db_blk_write_time PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 701 "26" _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_blk_write_time _null_ _null_ _null_ )); -DESCR("statistics: block write time, in msec"); +DESCR("statistics: block write time, in milliseconds"); DATA(insert OID = 3195 ( pg_stat_get_archiver PGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{20,25,1184,20,25,1184,1184}" "{o,o,o,o,o,o,o}" "{archived_count,last_archived_wal,last_archived_time,failed_count,last_failed_wal,last_failed_time,stats_reset}" _null_ _null_ pg_stat_get_archiver _null_ _null_ _null_ )); DESCR("statistics: information about WAL archiver"); DATA(insert OID = 2769 ( pg_stat_get_bgwriter_timed_checkpoints PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_bgwriter_timed_checkpoints _null_ _null_ _null_ )); @@ -2838,9 +2861,9 @@ DESCR("statistics: number of times the bgwriter stopped processing when it had w DATA(insert OID = 3075 ( pg_stat_get_bgwriter_stat_reset_time PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 1184 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_bgwriter_stat_reset_time _null_ _null_ _null_ )); DESCR("statistics: last reset for the bgwriter"); DATA(insert OID = 3160 ( pg_stat_get_checkpoint_write_time PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 701 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_checkpoint_write_time _null_ _null_ _null_ )); -DESCR("statistics: checkpoint time spent writing buffers to disk, in msec"); +DESCR("statistics: checkpoint time spent writing buffers to disk, in milliseconds"); DATA(insert OID = 3161 ( pg_stat_get_checkpoint_sync_time PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 701 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_checkpoint_sync_time _null_ _null_ _null_ )); -DESCR("statistics: checkpoint time spent synchronizing buffers to disk, in msec"); +DESCR("statistics: checkpoint time spent synchronizing buffers to disk, in milliseconds"); DATA(insert OID = 2775 ( pg_stat_get_buf_written_backend PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_buf_written_backend _null_ _null_ _null_ )); DESCR("statistics: number of buffers written by backends"); DATA(insert OID = 3063 ( pg_stat_get_buf_fsync_backend PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_buf_fsync_backend _null_ _null_ _null_ )); @@ -2851,9 +2874,9 @@ DESCR("statistics: number of buffer allocations"); DATA(insert OID = 2978 ( pg_stat_get_function_calls PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 20 "26" _null_ _null_ _null_ _null_ _null_ pg_stat_get_function_calls _null_ _null_ _null_ )); DESCR("statistics: number of function calls"); DATA(insert OID = 2979 ( pg_stat_get_function_total_time PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 701 "26" _null_ _null_ _null_ _null_ _null_ pg_stat_get_function_total_time _null_ _null_ _null_ )); -DESCR("statistics: total execution time of function, in msec"); +DESCR("statistics: total execution time of function, in milliseconds"); DATA(insert OID = 2980 ( pg_stat_get_function_self_time PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 701 "26" _null_ _null_ _null_ _null_ _null_ pg_stat_get_function_self_time _null_ _null_ _null_ )); -DESCR("statistics: self execution time of function, in msec"); +DESCR("statistics: self execution time of function, in milliseconds"); DATA(insert OID = 3037 ( pg_stat_get_xact_numscans PGNSP PGUID 12 1 0 0 0 f f f f t f v r 1 0 20 "26" _null_ _null_ _null_ _null_ _null_ pg_stat_get_xact_numscans _null_ _null_ _null_ )); DESCR("statistics: number of scans done for table/index in current transaction"); @@ -2876,9 +2899,9 @@ DESCR("statistics: number of blocks found in cache in current transaction"); DATA(insert OID = 3046 ( pg_stat_get_xact_function_calls PGNSP PGUID 12 1 0 0 0 f f f f t f v r 1 0 20 "26" _null_ _null_ _null_ _null_ _null_ pg_stat_get_xact_function_calls _null_ _null_ _null_ )); DESCR("statistics: number of function calls in current transaction"); DATA(insert OID = 3047 ( pg_stat_get_xact_function_total_time PGNSP PGUID 12 1 0 0 0 f f f f t f v r 1 0 701 "26" _null_ _null_ _null_ _null_ _null_ pg_stat_get_xact_function_total_time _null_ _null_ _null_ )); -DESCR("statistics: total execution time of function in current transaction, in msec"); +DESCR("statistics: total execution time of function in current transaction, in milliseconds"); DATA(insert OID = 3048 ( pg_stat_get_xact_function_self_time PGNSP PGUID 12 1 0 0 0 f f f f t f v r 1 0 701 "26" _null_ _null_ _null_ _null_ _null_ pg_stat_get_xact_function_self_time _null_ _null_ _null_ )); -DESCR("statistics: self execution time of function in current transaction, in msec"); +DESCR("statistics: self execution time of function in current transaction, in milliseconds"); DATA(insert OID = 3788 ( pg_stat_get_snapshot_timestamp PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 1184 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_snapshot_timestamp _null_ _null_ _null_ )); DESCR("statistics: timestamp of the current statistics snapshot"); @@ -4882,6 +4905,7 @@ DESCR("GIN support"); DATA(insert OID = 3301 ( jsonb_concat PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 3802 "3802 3802" _null_ _null_ _null_ _null_ _null_ jsonb_concat _null_ _null_ _null_ )); DATA(insert OID = 3302 ( jsonb_delete PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 3802 "3802 25" _null_ _null_ _null_ _null_ _null_ jsonb_delete _null_ _null_ _null_ )); DATA(insert OID = 3303 ( jsonb_delete PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 3802 "3802 23" _null_ _null_ _null_ _null_ _null_ jsonb_delete_idx _null_ _null_ _null_ )); +DATA(insert OID = 3343 ( jsonb_delete PGNSP PGUID 12 1 0 25 0 f f f f t f i s 2 0 3802 "3802 1009" "{3802,1009}" "{i,v}" "{from_json,path_elems}" _null_ _null_ jsonb_delete_array _null_ _null_ _null_ )); DATA(insert OID = 3304 ( jsonb_delete_path PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 3802 "3802 1009" _null_ _null_ _null_ _null_ _null_ jsonb_delete_path _null_ _null_ _null_ )); DATA(insert OID = 3305 ( jsonb_set PGNSP PGUID 12 1 0 0 0 f f f f t f i s 4 0 3802 "3802 1009 3802 16" _null_ _null_ _null_ _null_ _null_ jsonb_set _null_ _null_ _null_ )); DESCR("Set part of a jsonb"); @@ -4900,6 +4924,8 @@ DATA(insert OID = 2942 ( txid_snapshot_send PGNSP PGUID 12 1 0 0 0 f f f f t DESCR("I/O"); DATA(insert OID = 2943 ( txid_current PGNSP PGUID 12 1 0 0 0 f f f f t f s u 0 0 20 "" _null_ _null_ _null_ _null_ _null_ txid_current _null_ _null_ _null_ )); DESCR("get current transaction ID"); +DATA(insert OID = 3348 ( txid_current_if_assigned PGNSP PGUID 12 1 0 0 0 f f f f t f s u 0 0 20 "" _null_ _null_ _null_ _null_ _null_ txid_current_if_assigned _null_ _null_ _null_ )); +DESCR("get current transaction ID"); DATA(insert OID = 2944 ( txid_current_snapshot PGNSP PGUID 12 1 0 0 0 f f f f t f s s 0 0 2970 "" _null_ _null_ _null_ _null_ _null_ txid_current_snapshot _null_ _null_ _null_ )); DESCR("get current snapshot"); DATA(insert OID = 2945 ( txid_snapshot_xmin PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 20 "2970" _null_ _null_ _null_ _null_ _null_ txid_snapshot_xmin _null_ _null_ _null_ )); @@ -5159,13 +5185,13 @@ DATA(insert OID = 5016 ( spg_box_quad_leaf_consistent PGNSP PGUID 12 1 0 0 0 f DESCR("SP-GiST support for quad tree over box"); /* replication slots */ -DATA(insert OID = 3779 ( pg_create_physical_replication_slot PGNSP PGUID 12 1 0 0 0 f f f f t f v u 2 0 2249 "19 16" "{19,16,19,3220}" "{i,i,o,o}" "{slot_name,immediately_reserve,slot_name,xlog_position}" _null_ _null_ pg_create_physical_replication_slot _null_ _null_ _null_ )); +DATA(insert OID = 3779 ( pg_create_physical_replication_slot PGNSP PGUID 12 1 0 0 0 f f f f t f v u 3 0 2249 "19 16 16" "{19,16,16,19,3220}" "{i,i,i,o,o}" "{slot_name,immediately_reserve,temporary,slot_name,xlog_position}" _null_ _null_ pg_create_physical_replication_slot _null_ _null_ _null_ )); DESCR("create a physical replication slot"); DATA(insert OID = 3780 ( pg_drop_replication_slot PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 2278 "19" _null_ _null_ _null_ _null_ _null_ pg_drop_replication_slot _null_ _null_ _null_ )); DESCR("drop a replication slot"); -DATA(insert OID = 3781 ( pg_get_replication_slots PGNSP PGUID 12 1 10 0 0 f f f f f t s s 0 0 2249 "" "{19,19,25,26,16,23,28,28,3220,3220}" "{o,o,o,o,o,o,o,o,o,o}" "{slot_name,plugin,slot_type,datoid,active,active_pid,xmin,catalog_xmin,restart_lsn,confirmed_flush_lsn}" _null_ _null_ pg_get_replication_slots _null_ _null_ _null_ )); +DATA(insert OID = 3781 ( pg_get_replication_slots PGNSP PGUID 12 1 10 0 0 f f f f f t s s 0 0 2249 "" "{19,19,25,26,16,16,23,28,28,3220,3220}" "{o,o,o,o,o,o,o,o,o,o,o}" "{slot_name,plugin,slot_type,datoid,temporary,active,active_pid,xmin,catalog_xmin,restart_lsn,confirmed_flush_lsn}" _null_ _null_ pg_get_replication_slots _null_ _null_ _null_ )); DESCR("information about replication slots currently in use"); -DATA(insert OID = 3786 ( pg_create_logical_replication_slot PGNSP PGUID 12 1 0 0 0 f f f f t f v u 2 0 2249 "19 19" "{19,19,25,3220}" "{i,i,o,o}" "{slot_name,plugin,slot_name,xlog_position}" _null_ _null_ pg_create_logical_replication_slot _null_ _null_ _null_ )); +DATA(insert OID = 3786 ( pg_create_logical_replication_slot PGNSP PGUID 12 1 0 0 0 f f f f t f v u 3 0 2249 "19 19 16" "{19,19,16,25,3220}" "{i,i,i,o,o}" "{slot_name,plugin,temporary,slot_name,xlog_position}" _null_ _null_ pg_create_logical_replication_slot _null_ _null_ _null_ )); DESCR("set up a logical replication slot"); DATA(insert OID = 3782 ( pg_logical_slot_get_changes PGNSP PGUID 12 1000 1000 25 0 f f f f f t v u 4 0 2249 "19 3220 23 1009" "{19,3220,23,1009,3220,28,25}" "{i,i,i,v,o,o,o}" "{slot_name,upto_lsn,upto_nchanges,options,location,xid,data}" _null_ _null_ pg_logical_slot_get_changes _null_ _null_ _null_ )); DESCR("get changes from replication slot"); @@ -5303,6 +5329,10 @@ DESCR("get an individual replication origin's replication progress"); DATA(insert OID = 6014 ( pg_show_replication_origin_status PGNSP PGUID 12 1 100 0 0 f f f f f t v r 0 0 2249 "" "{26,25,3220,3220}" "{o,o,o,o}" "{local_id, external_id, remote_lsn, local_lsn}" _null_ _null_ pg_show_replication_origin_status _null_ _null_ _null_ )); DESCR("get progress for all replication origins"); +/* publications */ +DATA(insert OID = 6119 ( pg_get_publication_tables PGNSP PGUID 12 1 1000 0 0 f f t f t t s s 1 0 26 "25" "{25,26}" "{i,o}" "{pubname,relid}" _null_ _null_ pg_get_publication_tables _null_ _null_ _null_ )); +DESCR("get OIDs of tables in a publication"); + /* rls */ DATA(insert OID = 3298 ( row_security_active PGNSP PGUID 12 1 0 0 0 f f f f t f s s 1 0 16 "26" _null_ _null_ _null_ _null_ _null_ row_security_active _null_ _null_ _null_ )); DESCR("row security for current context active on table by table oid"); @@ -5326,6 +5356,9 @@ DESCR("pg_controldata recovery state information as a function"); DATA(insert OID = 3444 ( pg_control_init PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 2249 "" "{23,23,23,23,23,23,23,23,23,16,16,16,23}" "{o,o,o,o,o,o,o,o,o,o,o,o,o}" "{max_data_alignment,database_block_size,blocks_per_segment,wal_block_size,bytes_per_wal_segment,max_identifier_length,max_index_columns,max_toast_chunk_size,large_object_chunk_size,bigint_timestamps,float4_pass_by_value,float8_pass_by_value,data_page_checksum_version}" _null_ _null_ pg_control_init _null_ _null_ _null_ )); DESCR("pg_controldata init state information as a function"); +DATA(insert OID = 3445 ( pg_import_system_collations PGNSP PGUID 12 100 0 0 0 f f f f t f v r 2 0 2278 "16 4089" _null_ _null_ "{if_not_exists,schema}" _null_ _null_ pg_import_system_collations _null_ _null_ _null_ )); +DESCR("import collations from operating system"); + /* * Symbolic values for provolatile column: these indicate whether the result * of a function is dependent *only* on the values of its explicit arguments, diff --git a/src/include/catalog/pg_proc_fn.h b/src/include/catalog/pg_proc_fn.h index 8d666d8e79..993278a91a 100644 --- a/src/include/catalog/pg_proc_fn.h +++ b/src/include/catalog/pg_proc_fn.h @@ -4,7 +4,7 @@ * prototypes for functions in catalog/pg_proc.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_proc_fn.h diff --git a/src/include/catalog/pg_publication.h b/src/include/catalog/pg_publication.h new file mode 100644 index 0000000000..f157d0f407 --- /dev/null +++ b/src/include/catalog/pg_publication.h @@ -0,0 +1,104 @@ +/*------------------------------------------------------------------------- + * + * pg_publication.h + * definition of the relation sets relation (pg_publication) + * + * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_publication.h + * + * NOTES + * the genbki.pl script reads this file and generates .bki + * information from the DATA() statements. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_PUBLICATION_H +#define PG_PUBLICATION_H + +#include "catalog/genbki.h" +#include "catalog/objectaddress.h" + +/* ---------------- + * pg_publication definition. cpp turns this into + * typedef struct FormData_pg_publication + * + * ---------------- + */ +#define PublicationRelationId 6104 + +CATALOG(pg_publication,6104) +{ + NameData pubname; /* name of the publication */ + + Oid pubowner; /* publication owner */ + + /* + * indicates that this is special publication which should encompass + * all tables in the database (except for the unlogged and temp ones) + */ + bool puballtables; + + /* true if inserts are published */ + bool pubinsert; + + /* true if updates are published */ + bool pubupdate; + + /* true if deletes are published */ + bool pubdelete; + +} FormData_pg_publication; + +/* ---------------- + * Form_pg_publication corresponds to a pointer to a tuple with + * the format of pg_publication relation. + * ---------------- + */ +typedef FormData_pg_publication *Form_pg_publication; + +/* ---------------- + * compiler constants for pg_publication + * ---------------- + */ + +#define Natts_pg_publication 6 +#define Anum_pg_publication_pubname 1 +#define Anum_pg_publication_pubowner 2 +#define Anum_pg_publication_puballtables 3 +#define Anum_pg_publication_pubinsert 4 +#define Anum_pg_publication_pubupdate 5 +#define Anum_pg_publication_pubdelete 6 + +typedef struct PublicationActions +{ + bool pubinsert; + bool pubupdate; + bool pubdelete; +} PublicationActions; + +typedef struct Publication +{ + Oid oid; + char *name; + bool alltables; + PublicationActions pubactions; +} Publication; + +extern Publication *GetPublication(Oid pubid); +extern Publication *GetPublicationByName(const char *pubname, bool missing_ok); +extern List *GetRelationPublications(Oid relid); +extern List *GetPublicationRelations(Oid pubid); +extern List *GetAllTablesPublications(void); +extern List *GetAllTablesPublicationRelations(void); + +extern ObjectAddress publication_add_relation(Oid pubid, Relation targetrel, + bool if_not_exists); + +extern Oid get_publication_oid(const char *pubname, bool missing_ok); +extern char *get_publication_name(Oid pubid); + +extern Datum pg_get_publication_tables(PG_FUNCTION_ARGS); + +#endif /* PG_PUBLICATION_H */ diff --git a/src/include/catalog/pg_publication_rel.h b/src/include/catalog/pg_publication_rel.h new file mode 100644 index 0000000000..ac09e29669 --- /dev/null +++ b/src/include/catalog/pg_publication_rel.h @@ -0,0 +1,52 @@ +/*------------------------------------------------------------------------- + * + * pg_publication_rel.h + * definition of the publication to relation map (pg_publication_rel) + * + * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_publication_rel.h + * + * NOTES + * the genbki.pl script reads this file and generates .bki + * information from the DATA() statements. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_PUBLICATION_REL_H +#define PG_PUBLICATION_REL_H + +#include "catalog/genbki.h" + +/* ---------------- + * pg_publication_rel definition. cpp turns this into + * typedef struct FormData_pg_publication_rel + * + * ---------------- + */ +#define PublicationRelRelationId 6106 + +CATALOG(pg_publication_rel,6106) +{ + Oid prpubid; /* Oid of the publication */ + Oid prrelid; /* Oid of the relation */ +} FormData_pg_publication_rel; + +/* ---------------- + * Form_pg_publication_rel corresponds to a pointer to a tuple with + * the format of pg_publication_rel relation. + * ---------------- + */ +typedef FormData_pg_publication_rel *Form_pg_publication_rel; + +/* ---------------- + * compiler constants for pg_publication_rel + * ---------------- + */ + +#define Natts_pg_publication_rel 2 +#define Anum_pg_publication_rel_prpubid 1 +#define Anum_pg_publication_rel_prrelid 2 + +#endif /* PG_PUBLICATION_REL_H */ diff --git a/src/include/catalog/pg_range.h b/src/include/catalog/pg_range.h index 14d3b12315..4ed57fe2e9 100644 --- a/src/include/catalog/pg_range.h +++ b/src/include/catalog/pg_range.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_range.h diff --git a/src/include/catalog/pg_replication_origin.h b/src/include/catalog/pg_replication_origin.h index 5f0538edb2..c22831f517 100644 --- a/src/include/catalog/pg_replication_origin.h +++ b/src/include/catalog/pg_replication_origin.h @@ -3,7 +3,7 @@ * pg_replication_origin.h * Persistent replication origin registry * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_replication_origin.h diff --git a/src/include/catalog/pg_rewrite.h b/src/include/catalog/pg_rewrite.h index c6c87f6adb..425a336755 100644 --- a/src/include/catalog/pg_rewrite.h +++ b/src/include/catalog/pg_rewrite.h @@ -8,7 +8,7 @@ * --- ie, rule names are only unique among the rules of a given table. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_rewrite.h diff --git a/src/include/catalog/pg_seclabel.h b/src/include/catalog/pg_seclabel.h index 11cda559b3..01e14e77c0 100644 --- a/src/include/catalog/pg_seclabel.h +++ b/src/include/catalog/pg_seclabel.h @@ -3,7 +3,7 @@ * pg_seclabel.h * definition of the system "security label" relation (pg_seclabel) * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * ------------------------------------------------------------------------- diff --git a/src/include/catalog/pg_sequence.h b/src/include/catalog/pg_sequence.h new file mode 100644 index 0000000000..350b286e45 --- /dev/null +++ b/src/include/catalog/pg_sequence.h @@ -0,0 +1,30 @@ +#ifndef PG_SEQUENCE_H +#define PG_SEQUENCE_H + +#include "catalog/genbki.h" + +#define SequenceRelationId 2224 + +CATALOG(pg_sequence,2224) BKI_WITHOUT_OIDS +{ + Oid seqrelid; + bool seqcycle; + int64 seqstart; + int64 seqincrement; + int64 seqmax; + int64 seqmin; + int64 seqcache; +} FormData_pg_sequence; + +typedef FormData_pg_sequence *Form_pg_sequence; + +#define Natts_pg_sequence 7 +#define Anum_pg_sequence_seqrelid 1 +#define Anum_pg_sequence_seqcycle 2 +#define Anum_pg_sequence_seqstart 3 +#define Anum_pg_sequence_seqincrement 4 +#define Anum_pg_sequence_seqmax 5 +#define Anum_pg_sequence_seqmin 6 +#define Anum_pg_sequence_seqcache 7 + +#endif /* PG_SEQUENCE_H */ diff --git a/src/include/catalog/pg_shdepend.h b/src/include/catalog/pg_shdepend.h index 92c492b296..ae1aa4f952 100644 --- a/src/include/catalog/pg_shdepend.h +++ b/src/include/catalog/pg_shdepend.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_shdepend.h diff --git a/src/include/catalog/pg_shdescription.h b/src/include/catalog/pg_shdescription.h index bf79d4a908..21086447fa 100644 --- a/src/include/catalog/pg_shdescription.h +++ b/src/include/catalog/pg_shdescription.h @@ -12,7 +12,7 @@ * across tables. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_shdescription.h diff --git a/src/include/catalog/pg_shseclabel.h b/src/include/catalog/pg_shseclabel.h index c39e11df34..a88f65c169 100644 --- a/src/include/catalog/pg_shseclabel.h +++ b/src/include/catalog/pg_shseclabel.h @@ -3,7 +3,7 @@ * pg_shseclabel.h * definition of the system "security label" relation (pg_shseclabel) * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * ------------------------------------------------------------------------- diff --git a/src/include/catalog/pg_statistic.h b/src/include/catalog/pg_statistic.h index c1a624d979..25babe7e2c 100644 --- a/src/include/catalog/pg_statistic.h +++ b/src/include/catalog/pg_statistic.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_statistic.h diff --git a/src/include/catalog/pg_subscription.h b/src/include/catalog/pg_subscription.h new file mode 100644 index 0000000000..e0af730e95 --- /dev/null +++ b/src/include/catalog/pg_subscription.h @@ -0,0 +1,84 @@ +/* ------------------------------------------------------------------------- + * + * pg_subscription.h + * Definition of the subscription catalog (pg_subscription). + * + * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * ------------------------------------------------------------------------- + */ +#ifndef PG_SUBSCRIPTION_H +#define PG_SUBSCRIPTION_H + +#include "catalog/genbki.h" +#include "nodes/pg_list.h" + +/* ---------------- + * pg_subscription definition. cpp turns this into + * typedef struct FormData_pg_subscription + * ---------------- + */ +#define SubscriptionRelationId 6100 +#define SubscriptionRelation_Rowtype_Id 6101 + +/* + * Technicaly, the subscriptions live inside the database, so a shared catalog + * seems weird, but the replication launcher process needs to access all of + * them to be able to start the workers, so we have to put them in a shared, + * nailed catalog. + */ +CATALOG(pg_subscription,6100) BKI_SHARED_RELATION BKI_ROWTYPE_OID(6101) BKI_SCHEMA_MACRO +{ + Oid subdbid; /* Database the subscription is in. */ + NameData subname; /* Name of the subscription */ + + Oid subowner; /* Owner of the subscription */ + + bool subenabled; /* True if the subsription is enabled + * (the worker should be running) */ + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + text subconninfo; /* Connection string to the publisher */ + NameData subslotname; /* Slot name on publisher */ + + text subpublications[1]; /* List of publications subscribed to */ +#endif +} FormData_pg_subscription; + +typedef FormData_pg_subscription *Form_pg_subscription; + +/* ---------------- + * compiler constants for pg_subscription + * ---------------- + */ +#define Natts_pg_subscription 7 +#define Anum_pg_subscription_subdbid 1 +#define Anum_pg_subscription_subname 2 +#define Anum_pg_subscription_subowner 3 +#define Anum_pg_subscription_subenabled 4 +#define Anum_pg_subscription_subconninfo 5 +#define Anum_pg_subscription_subslotname 6 +#define Anum_pg_subscription_subpublications 7 + + +typedef struct Subscription +{ + Oid oid; /* Oid of the subscription */ + Oid dbid; /* Oid of the database which dubscription is in */ + char *name; /* Name of the subscription */ + Oid owner; /* Oid of the subscription owner */ + bool enabled; /* Indicates if the subscription is enabled */ + char *conninfo; /* Connection string to the publisher */ + char *slotname; /* Name of the replication slot */ + List *publications; /* List of publication names to subscribe to */ +} Subscription; + +extern Subscription *GetSubscription(Oid subid, bool missing_ok); +extern void FreeSubscription(Subscription *sub); +extern Oid get_subscription_oid(const char *subname, bool missing_ok); +extern char *get_subscription_name(Oid subid); + +extern int CountDBSubscriptions(Oid dbid); + +#endif /* PG_SUBSCRIPTION_H */ diff --git a/src/include/catalog/pg_tablespace.h b/src/include/catalog/pg_tablespace.h index 61b8020b8e..d9ea4b7d63 100644 --- a/src/include/catalog/pg_tablespace.h +++ b/src/include/catalog/pg_tablespace.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_tablespace.h diff --git a/src/include/catalog/pg_transform.h b/src/include/catalog/pg_transform.h index e55c3e1bc2..3415db3bd6 100644 --- a/src/include/catalog/pg_transform.h +++ b/src/include/catalog/pg_transform.h @@ -2,7 +2,7 @@ * * pg_transform.h * - * Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Copyright (c) 2012-2017, PostgreSQL Global Development Group * * src/include/catalog/pg_transform.h * diff --git a/src/include/catalog/pg_trigger.h b/src/include/catalog/pg_trigger.h index eb39c50e63..547332fe65 100644 --- a/src/include/catalog/pg_trigger.h +++ b/src/include/catalog/pg_trigger.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_trigger.h @@ -59,6 +59,8 @@ CATALOG(pg_trigger,2620) #ifdef CATALOG_VARLEN bytea tgargs BKI_FORCE_NOT_NULL; /* first\000second\000tgnargs\000 */ pg_node_tree tgqual; /* WHEN expression, or NULL if none */ + NameData tgoldtable; /* old transition table, or NULL if none */ + NameData tgnewtable; /* new transition table, or NULL if none */ #endif } FormData_pg_trigger; @@ -73,7 +75,7 @@ typedef FormData_pg_trigger *Form_pg_trigger; * compiler constants for pg_trigger * ---------------- */ -#define Natts_pg_trigger 15 +#define Natts_pg_trigger 17 #define Anum_pg_trigger_tgrelid 1 #define Anum_pg_trigger_tgname 2 #define Anum_pg_trigger_tgfoid 3 @@ -89,6 +91,8 @@ typedef FormData_pg_trigger *Form_pg_trigger; #define Anum_pg_trigger_tgattr 13 #define Anum_pg_trigger_tgargs 14 #define Anum_pg_trigger_tgqual 15 +#define Anum_pg_trigger_tgoldtable 16 +#define Anum_pg_trigger_tgnewtable 17 /* Bits within tgtype */ #define TRIGGER_TYPE_ROW (1 << 0) @@ -142,4 +146,11 @@ typedef FormData_pg_trigger *Form_pg_trigger; #define TRIGGER_TYPE_MATCHES(type, level, timing, event) \ (((type) & (TRIGGER_TYPE_LEVEL_MASK | TRIGGER_TYPE_TIMING_MASK | (event))) == ((level) | (timing) | (event))) +/* + * Macro to determine whether tgnewtable or tgoldtable has been specified for + * a trigger. + */ +#define TRIGGER_USES_TRANSITION_TABLE(namepointer) \ + ((namepointer) != (char *) NULL) + #endif /* PG_TRIGGER_H */ diff --git a/src/include/catalog/pg_ts_config.h b/src/include/catalog/pg_ts_config.h index ad450c34de..b61cf857d9 100644 --- a/src/include/catalog/pg_ts_config.h +++ b/src/include/catalog/pg_ts_config.h @@ -4,7 +4,7 @@ * definition of configuration of tsearch * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_ts_config.h diff --git a/src/include/catalog/pg_ts_config_map.h b/src/include/catalog/pg_ts_config_map.h index c1753a346e..fc9467fd9c 100644 --- a/src/include/catalog/pg_ts_config_map.h +++ b/src/include/catalog/pg_ts_config_map.h @@ -4,7 +4,7 @@ * definition of token mappings for configurations of tsearch * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_ts_config_map.h diff --git a/src/include/catalog/pg_ts_dict.h b/src/include/catalog/pg_ts_dict.h index e3c00f9175..28b7bb7c0d 100644 --- a/src/include/catalog/pg_ts_dict.h +++ b/src/include/catalog/pg_ts_dict.h @@ -4,7 +4,7 @@ * definition of dictionaries for tsearch * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_ts_dict.h diff --git a/src/include/catalog/pg_ts_parser.h b/src/include/catalog/pg_ts_parser.h index 016ef14d12..cfb87b4d56 100644 --- a/src/include/catalog/pg_ts_parser.h +++ b/src/include/catalog/pg_ts_parser.h @@ -4,7 +4,7 @@ * definition of parsers for tsearch * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_ts_parser.h diff --git a/src/include/catalog/pg_ts_template.h b/src/include/catalog/pg_ts_template.h index 39191a2a82..5fc6eea243 100644 --- a/src/include/catalog/pg_ts_template.h +++ b/src/include/catalog/pg_ts_template.h @@ -4,7 +4,7 @@ * definition of dictionary templates for tsearch * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_ts_template.h diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index 162239c7ae..c2350f3867 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -5,7 +5,7 @@ * along with the relation's initial contents. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_type.h diff --git a/src/include/catalog/pg_type_fn.h b/src/include/catalog/pg_type_fn.h index d7bbfdb012..01f095612d 100644 --- a/src/include/catalog/pg_type_fn.h +++ b/src/include/catalog/pg_type_fn.h @@ -4,7 +4,7 @@ * prototypes for functions in catalog/pg_type.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_type_fn.h diff --git a/src/include/catalog/pg_user_mapping.h b/src/include/catalog/pg_user_mapping.h index a8bb9d9005..1ebf4611df 100644 --- a/src/include/catalog/pg_user_mapping.h +++ b/src/include/catalog/pg_user_mapping.h @@ -3,7 +3,7 @@ * pg_user_mapping.h * definition of the system "user mapping" relation (pg_user_mapping) * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_user_mapping.h diff --git a/src/include/catalog/storage.h b/src/include/catalog/storage.h index ef960da921..fea96deba3 100644 --- a/src/include/catalog/storage.h +++ b/src/include/catalog/storage.h @@ -4,7 +4,7 @@ * prototypes for functions in backend/catalog/storage.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/storage.h diff --git a/src/include/catalog/storage_xlog.h b/src/include/catalog/storage_xlog.h index 500e663b5f..fcdd0233b1 100644 --- a/src/include/catalog/storage_xlog.h +++ b/src/include/catalog/storage_xlog.h @@ -4,7 +4,7 @@ * prototypes for XLog support for backend/catalog/storage.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/storage_xlog.h diff --git a/src/include/catalog/toasting.h b/src/include/catalog/toasting.h index b7a38ced3d..db7f145b5f 100644 --- a/src/include/catalog/toasting.h +++ b/src/include/catalog/toasting.h @@ -4,7 +4,7 @@ * This file provides some definitions to support creation of toast tables * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/toasting.h diff --git a/src/include/commands/alter.h b/src/include/commands/alter.h index e116bc73b7..b7aa86cb57 100644 --- a/src/include/commands/alter.h +++ b/src/include/commands/alter.h @@ -4,7 +4,7 @@ * prototypes for commands/alter.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/alter.h diff --git a/src/include/commands/async.h b/src/include/commands/async.h index 93cb92aea6..b7842d1a0f 100644 --- a/src/include/commands/async.h +++ b/src/include/commands/async.h @@ -3,7 +3,7 @@ * async.h * Asynchronous notification: NOTIFY, LISTEN, UNLISTEN * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/async.h @@ -38,11 +38,6 @@ extern void Async_Listen(const char *channel); extern void Async_Unlisten(const char *channel); extern void Async_UnlistenAll(void); -/* notify-related SQL functions */ -extern Datum pg_listening_channels(PG_FUNCTION_ARGS); -extern Datum pg_notify(PG_FUNCTION_ARGS); -extern Datum pg_notification_queue_usage(PG_FUNCTION_ARGS); - /* perform (or cancel) outbound notify processing at transaction commit */ extern void PreCommit_Notify(void); extern void AtCommit_Notify(void); diff --git a/src/include/commands/cluster.h b/src/include/commands/cluster.h index e9222fe999..7c9d4746d9 100644 --- a/src/include/commands/cluster.h +++ b/src/include/commands/cluster.h @@ -3,7 +3,7 @@ * cluster.h * header file for postgres cluster command stuff * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994-5, Regents of the University of California * * src/include/commands/cluster.h diff --git a/src/include/commands/collationcmds.h b/src/include/commands/collationcmds.h index d1e5e0ad84..699ce2f9ee 100644 --- a/src/include/commands/collationcmds.h +++ b/src/include/commands/collationcmds.h @@ -4,7 +4,7 @@ * prototypes for collationcmds.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/collationcmds.h @@ -18,7 +18,7 @@ #include "catalog/objectaddress.h" #include "nodes/parsenodes.h" -extern ObjectAddress DefineCollation(List *names, List *parameters); +extern ObjectAddress DefineCollation(ParseState *pstate, List *names, List *parameters); extern void IsThereCollationInNamespace(const char *collname, Oid nspOid); #endif /* COLLATIONCMDS_H */ diff --git a/src/include/commands/comment.h b/src/include/commands/comment.h index 0790d9ff79..684ea8b697 100644 --- a/src/include/commands/comment.h +++ b/src/include/commands/comment.h @@ -7,7 +7,7 @@ * * Prototypes for functions in commands/comment.c * - * Copyright (c) 1999-2016, PostgreSQL Global Development Group + * Copyright (c) 1999-2017, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/include/commands/conversioncmds.h b/src/include/commands/conversioncmds.h index e1498ad888..20d7f0e9b1 100644 --- a/src/include/commands/conversioncmds.h +++ b/src/include/commands/conversioncmds.h @@ -4,7 +4,7 @@ * prototypes for conversioncmds.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/conversioncmds.h diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h index 314d1f7e27..d63ca0f5e9 100644 --- a/src/include/commands/copy.h +++ b/src/include/commands/copy.h @@ -4,7 +4,7 @@ * Definitions for using the POSTGRES copy command. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/copy.h @@ -16,16 +16,18 @@ #include "nodes/execnodes.h" #include "nodes/parsenodes.h" +#include "parser/parse_node.h" #include "tcop/dest.h" /* CopyStateData is private in commands/copy.c */ typedef struct CopyStateData *CopyState; -extern Oid DoCopy(const CopyStmt *stmt, const char *queryString, +extern void DoCopy(ParseState *state, const CopyStmt *stmt, + int stmt_location, int stmt_len, uint64 *processed); -extern void ProcessCopyOptions(CopyState cstate, bool is_from, List *options); -extern CopyState BeginCopyFrom(Relation rel, const char *filename, +extern void ProcessCopyOptions(ParseState *pstate, CopyState cstate, bool is_from, List *options); +extern CopyState BeginCopyFrom(ParseState *pstate, Relation rel, const char *filename, bool is_program, List *attnamelist, List *options); extern void EndCopyFrom(CopyState cstate); extern bool NextCopyFrom(CopyState cstate, ExprContext *econtext, diff --git a/src/include/commands/createas.h b/src/include/commands/createas.h index 3c4286417a..7b78cc4a13 100644 --- a/src/include/commands/createas.h +++ b/src/include/commands/createas.h @@ -4,7 +4,7 @@ * prototypes for createas.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/createas.h diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h index b6436f1812..52918a9f4b 100644 --- a/src/include/commands/dbcommands.h +++ b/src/include/commands/dbcommands.h @@ -4,7 +4,7 @@ * Database management commands (create/drop database). * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/dbcommands.h @@ -19,10 +19,10 @@ #include "lib/stringinfo.h" #include "nodes/parsenodes.h" -extern Oid createdb(const CreatedbStmt *stmt); +extern Oid createdb(ParseState *pstate, const CreatedbStmt *stmt); extern void dropdb(const char *dbname, bool missing_ok); extern ObjectAddress RenameDatabase(const char *oldname, const char *newname); -extern Oid AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel); +extern Oid AlterDatabase(ParseState *pstate, AlterDatabaseStmt *stmt, bool isTopLevel); extern Oid AlterDatabaseSet(AlterDatabaseSetStmt *stmt); extern ObjectAddress AlterDatabaseOwner(const char *dbname, Oid newOwnerId); diff --git a/src/include/commands/dbcommands_xlog.h b/src/include/commands/dbcommands_xlog.h index 62ed5120a0..6583d0d5bd 100644 --- a/src/include/commands/dbcommands_xlog.h +++ b/src/include/commands/dbcommands_xlog.h @@ -4,7 +4,7 @@ * Database resource manager XLOG definitions (create/drop database). * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/dbcommands_xlog.h diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index b064eb4836..faa5961e80 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -4,7 +4,7 @@ * POSTGRES define and remove utility definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/defrem.h @@ -42,13 +42,15 @@ extern bool CheckIndexCompatible(Oid oldId, List *attributeList, List *exclusionOpNames); extern Oid GetDefaultOpClass(Oid type_id, Oid am_id); +extern Oid ResolveOpClass(List *opclass, Oid attrType, + char *accessMethodName, Oid accessMethodId); /* commands/functioncmds.c */ -extern ObjectAddress CreateFunction(CreateFunctionStmt *stmt, const char *queryString); +extern ObjectAddress CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt); extern void RemoveFunctionById(Oid funcOid); extern void SetFunctionReturnType(Oid funcOid, Oid newRetType); extern void SetFunctionArgType(Oid funcOid, int argIndex, Oid newArgType); -extern ObjectAddress AlterFunction(AlterFunctionStmt *stmt); +extern ObjectAddress AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt); extern ObjectAddress CreateCast(CreateCastStmt *stmt); extern void DropCastById(Oid castOid); extern ObjectAddress CreateTransform(CreateTransformStmt *stmt); @@ -58,10 +60,10 @@ extern void IsThereFunctionInNamespace(const char *proname, int pronargs, extern void ExecuteDoStmt(DoStmt *stmt); extern Oid get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok); extern Oid get_transform_oid(Oid type_id, Oid lang_id, bool missing_ok); -extern void interpret_function_parameter_list(List *parameters, +extern void interpret_function_parameter_list(ParseState *pstate, + List *parameters, Oid languageOid, bool is_aggregate, - const char *queryString, oidvector **parameterTypes, ArrayType **allParameterTypes, ArrayType **parameterModes, @@ -76,8 +78,8 @@ extern void RemoveOperatorById(Oid operOid); extern ObjectAddress AlterOperator(AlterOperatorStmt *stmt); /* commands/aggregatecmds.c */ -extern ObjectAddress DefineAggregate(List *name, List *args, bool oldstyle, - List *parameters, const char *queryString); +extern ObjectAddress DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, + List *parameters); /* commands/opclasscmds.c */ extern ObjectAddress DefineOpClass(CreateOpClassStmt *stmt); @@ -85,6 +87,8 @@ extern ObjectAddress DefineOpFamily(CreateOpFamilyStmt *stmt); extern Oid AlterOpFamily(AlterOpFamilyStmt *stmt); extern void RemoveOpClassById(Oid opclassOid); extern void RemoveOpFamilyById(Oid opfamilyOid); +extern Oid get_family_oid(const char *opfname, const char *nspname, const char *ammth); +extern char *get_opfamily_name(Oid opfamilyOid, char **opfnamespace, char **opfmethod); extern void RemoveAmOpEntryById(Oid entryOid); extern void RemoveAmProcEntryById(Oid entryOid); extern void IsThereOpClassInNamespace(const char *opcname, Oid opcmethod, @@ -152,6 +156,6 @@ extern int64 defGetInt64(DefElem *def); extern List *defGetQualifiedName(DefElem *def); extern TypeName *defGetTypeName(DefElem *def); extern int defGetTypeLength(DefElem *def); -extern DefElem *defWithOids(bool value); +extern List *defGetStringList(DefElem *def); #endif /* DEFREM_H */ diff --git a/src/include/commands/discard.h b/src/include/commands/discard.h index 24ea786f97..b960cab51f 100644 --- a/src/include/commands/discard.h +++ b/src/include/commands/discard.h @@ -4,7 +4,7 @@ * prototypes for discard.c. * * - * Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Copyright (c) 1996-2017, PostgreSQL Global Development Group * * src/include/commands/discard.h * diff --git a/src/include/commands/event_trigger.h b/src/include/commands/event_trigger.h index 0e91bf6ada..0017bd0cd4 100644 --- a/src/include/commands/event_trigger.h +++ b/src/include/commands/event_trigger.h @@ -3,7 +3,7 @@ * event_trigger.h * Declarations for command trigger handling. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/event_trigger.h diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h index 3d0a5abbc2..9191e186c1 100644 --- a/src/include/commands/explain.h +++ b/src/include/commands/explain.h @@ -3,7 +3,7 @@ * explain.h * prototypes for explain.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994-5, Regents of the University of California * * src/include/commands/explain.h @@ -15,6 +15,7 @@ #include "executor/executor.h" #include "lib/stringinfo.h" +#include "parser/parse_node.h" typedef enum ExplainFormat { @@ -48,6 +49,7 @@ typedef struct ExplainState /* Hook for plugins to get control in ExplainOneQuery() */ typedef void (*ExplainOneQuery_hook_type) (Query *query, + int cursorOptions, IntoClause *into, ExplainState *es, const char *queryString, @@ -59,7 +61,7 @@ typedef const char *(*explain_get_index_name_hook_type) (Oid indexId); extern PGDLLIMPORT explain_get_index_name_hook_type explain_get_index_name_hook; -extern void ExplainQuery(ExplainStmt *stmt, const char *queryString, +extern void ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString, ParamListInfo params, DestReceiver *dest); extern ExplainState *NewExplainState(void); diff --git a/src/include/commands/extension.h b/src/include/commands/extension.h index 94354ab04d..3f14c90267 100644 --- a/src/include/commands/extension.h +++ b/src/include/commands/extension.h @@ -4,7 +4,7 @@ * Extension management commands (create/drop extension). * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/extension.h @@ -19,16 +19,19 @@ /* - * creating_extension is only true while running a CREATE EXTENSION command. - * It instructs recordDependencyOnCurrentExtension() to register a dependency - * on the current pg_extension object for each SQL object created by its - * installation script. + * creating_extension is only true while running a CREATE EXTENSION or ALTER + * EXTENSION UPDATE command. It instructs recordDependencyOnCurrentExtension() + * to register a dependency on the current pg_extension object for each SQL + * object created by an extension script. It also instructs performDeletion() + * to remove such dependencies without following them, so that extension + * scripts can drop member objects without having to explicitly dissociate + * them from the extension first. */ extern PGDLLIMPORT bool creating_extension; extern Oid CurrentExtensionObject; -extern ObjectAddress CreateExtension(CreateExtensionStmt *stmt); +extern ObjectAddress CreateExtension(ParseState *pstate, CreateExtensionStmt *stmt); extern void RemoveExtensionById(Oid extId); @@ -37,7 +40,7 @@ extern ObjectAddress InsertExtensionTuple(const char *extName, Oid extOwner, Datum extConfig, Datum extCondition, List *requiredExtensions); -extern ObjectAddress ExecAlterExtensionStmt(AlterExtensionStmt *stmt); +extern ObjectAddress ExecAlterExtensionStmt(ParseState *pstate, AlterExtensionStmt *stmt); extern ObjectAddress ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt, ObjectAddress *objAddress); diff --git a/src/include/commands/lockcmds.h b/src/include/commands/lockcmds.h index 8881352dd7..45ed96d4d1 100644 --- a/src/include/commands/lockcmds.h +++ b/src/include/commands/lockcmds.h @@ -4,7 +4,7 @@ * prototypes for lockcmds.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/lockcmds.h diff --git a/src/include/commands/matview.h b/src/include/commands/matview.h index 82e06c2460..129fb92f59 100644 --- a/src/include/commands/matview.h +++ b/src/include/commands/matview.h @@ -4,7 +4,7 @@ * prototypes for matview.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/matview.h diff --git a/src/include/commands/policy.h b/src/include/commands/policy.h index dbf782464b..cff93a6cb0 100644 --- a/src/include/commands/policy.h +++ b/src/include/commands/policy.h @@ -4,7 +4,7 @@ * prototypes for policy.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/policy.h diff --git a/src/include/commands/portalcmds.h b/src/include/commands/portalcmds.h index 8abd3e72bf..8f0e6c48f4 100644 --- a/src/include/commands/portalcmds.h +++ b/src/include/commands/portalcmds.h @@ -4,7 +4,7 @@ * prototypes for portalcmds.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/portalcmds.h @@ -18,7 +18,7 @@ #include "utils/portal.h" -extern void PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params, +extern void PerformCursorOpen(DeclareCursorStmt *cstmt, ParamListInfo params, const char *queryString, bool isTopLevel); extern void PerformPortalFetch(FetchStmt *stmt, DestReceiver *dest, diff --git a/src/include/commands/prepare.h b/src/include/commands/prepare.h index ba1247a557..d8d22edbbc 100644 --- a/src/include/commands/prepare.h +++ b/src/include/commands/prepare.h @@ -4,7 +4,7 @@ * PREPARE, EXECUTE and DEALLOCATE commands, and prepared-stmt storage * * - * Copyright (c) 2002-2016, PostgreSQL Global Development Group + * Copyright (c) 2002-2017, PostgreSQL Global Development Group * * src/include/commands/prepare.h * @@ -35,7 +35,8 @@ typedef struct /* Utility statements PREPARE, EXECUTE, DEALLOCATE, EXPLAIN EXECUTE */ -extern void PrepareQuery(PrepareStmt *stmt, const char *queryString); +extern void PrepareQuery(PrepareStmt *stmt, const char *queryString, + int stmt_location, int stmt_len); extern void ExecuteQuery(ExecuteStmt *stmt, IntoClause *intoClause, const char *queryString, ParamListInfo params, DestReceiver *dest, char *completionTag); diff --git a/src/include/commands/progress.h b/src/include/commands/progress.h index c48d23be2b..9472ecca63 100644 --- a/src/include/commands/progress.h +++ b/src/include/commands/progress.h @@ -7,7 +7,7 @@ * constants, you probably also need to update the views based on them * in system_views.sql. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/progress.h diff --git a/src/include/commands/publicationcmds.h b/src/include/commands/publicationcmds.h new file mode 100644 index 0000000000..cdacfa6f5b --- /dev/null +++ b/src/include/commands/publicationcmds.h @@ -0,0 +1,29 @@ +/*------------------------------------------------------------------------- + * + * publicationcmds.h + * prototypes for publicationcmds.c. + * + * + * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/publicationcmds.h + * + *------------------------------------------------------------------------- + */ + +#ifndef PUBLICATIONCMDS_H +#define PUBLICATIONCMDS_H + +#include "catalog/objectaddress.h" +#include "nodes/parsenodes.h" + +extern ObjectAddress CreatePublication(CreatePublicationStmt *stmt); +extern void AlterPublication(AlterPublicationStmt *stmt); +extern void RemovePublicationById(Oid pubid); +extern void RemovePublicationRelById(Oid proid); + +extern ObjectAddress AlterPublicationOwner(const char *name, Oid newOwnerId); +extern void AlterPublicationOwner_oid(Oid pubid, Oid newOwnerId); + +#endif /* PUBLICATIONCMDS_H */ diff --git a/src/include/commands/schemacmds.h b/src/include/commands/schemacmds.h index 97b53ecb5b..f07a389c7f 100644 --- a/src/include/commands/schemacmds.h +++ b/src/include/commands/schemacmds.h @@ -4,7 +4,7 @@ * prototypes for schemacmds.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/schemacmds.h @@ -19,7 +19,8 @@ #include "nodes/parsenodes.h" extern Oid CreateSchemaCommand(CreateSchemaStmt *parsetree, - const char *queryString); + const char *queryString, + int stmt_location, int stmt_len); extern void RemoveSchemaById(Oid schemaOid); diff --git a/src/include/commands/seclabel.h b/src/include/commands/seclabel.h index 6671bfdfee..d317f39485 100644 --- a/src/include/commands/seclabel.h +++ b/src/include/commands/seclabel.h @@ -3,7 +3,7 @@ * * Prototypes for functions in commands/seclabel.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California */ #ifndef SECLABEL_H diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h index 6af60d893b..144c3c2e6f 100644 --- a/src/include/commands/sequence.h +++ b/src/include/commands/sequence.h @@ -3,7 +3,7 @@ * sequence.h * prototypes for sequence.c. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/sequence.h @@ -18,41 +18,28 @@ #include "fmgr.h" #include "lib/stringinfo.h" #include "nodes/parsenodes.h" +#include "parser/parse_node.h" #include "storage/relfilenode.h" -typedef struct FormData_pg_sequence +typedef struct FormData_pg_sequence_data { - NameData sequence_name; int64 last_value; - int64 start_value; - int64 increment_by; - int64 max_value; - int64 min_value; - int64 cache_value; int64 log_cnt; - bool is_cycled; bool is_called; -} FormData_pg_sequence; +} FormData_pg_sequence_data; -typedef FormData_pg_sequence *Form_pg_sequence; +typedef FormData_pg_sequence_data *Form_pg_sequence_data; /* * Columns of a sequence relation */ -#define SEQ_COL_NAME 1 -#define SEQ_COL_LASTVAL 2 -#define SEQ_COL_STARTVAL 3 -#define SEQ_COL_INCBY 4 -#define SEQ_COL_MAXVALUE 5 -#define SEQ_COL_MINVALUE 6 -#define SEQ_COL_CACHE 7 -#define SEQ_COL_LOG 8 -#define SEQ_COL_CYCLE 9 -#define SEQ_COL_CALLED 10 +#define SEQ_COL_LASTVAL 1 +#define SEQ_COL_LOG 2 +#define SEQ_COL_CALLED 3 -#define SEQ_COL_FIRSTCOL SEQ_COL_NAME +#define SEQ_COL_FIRSTCOL SEQ_COL_LASTVAL #define SEQ_COL_LASTCOL SEQ_COL_CALLED /* XLOG stuff */ @@ -65,16 +52,10 @@ typedef struct xl_seq_rec } xl_seq_rec; extern Datum nextval(PG_FUNCTION_ARGS); -extern Datum nextval_oid(PG_FUNCTION_ARGS); -extern Datum currval_oid(PG_FUNCTION_ARGS); -extern Datum setval_oid(PG_FUNCTION_ARGS); -extern Datum setval3_oid(PG_FUNCTION_ARGS); -extern Datum lastval(PG_FUNCTION_ARGS); -extern Datum pg_sequence_parameters(PG_FUNCTION_ARGS); - -extern ObjectAddress DefineSequence(CreateSeqStmt *stmt); -extern ObjectAddress AlterSequence(AlterSeqStmt *stmt); +extern ObjectAddress DefineSequence(ParseState *pstate, CreateSeqStmt *stmt); +extern ObjectAddress AlterSequence(ParseState *pstate, AlterSeqStmt *stmt); +extern void DeleteSequenceTuple(Oid relid); extern void ResetSequence(Oid seq_relid); extern void ResetSequenceCaches(void); diff --git a/src/include/commands/subscriptioncmds.h b/src/include/commands/subscriptioncmds.h new file mode 100644 index 0000000000..87c1a27e14 --- /dev/null +++ b/src/include/commands/subscriptioncmds.h @@ -0,0 +1,28 @@ +/*------------------------------------------------------------------------- + * + * subscriptioncmds.h + * prototypes for subscriptioncmds.c. + * + * + * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/subscriptioncmds.h + * + *------------------------------------------------------------------------- + */ + +#ifndef SUBSCRIPTIONCMDS_H +#define SUBSCRIPTIONCMDS_H + +#include "catalog/objectaddress.h" +#include "nodes/parsenodes.h" + +extern ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt); +extern ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt); +extern void DropSubscription(DropSubscriptionStmt *stmt); + +extern ObjectAddress AlterSubscriptionOwner(const char *name, Oid newOwnerId); +extern void AlterSubscriptionOwner_oid(Oid subid, Oid newOwnerId); + +#endif /* SUBSCRIPTIONCMDS_H */ diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h index 7a770f4df5..f3a97016a1 100644 --- a/src/include/commands/tablecmds.h +++ b/src/include/commands/tablecmds.h @@ -4,7 +4,7 @@ * prototypes for tablecmds.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/tablecmds.h @@ -23,7 +23,7 @@ extern ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, - ObjectAddress *typaddress); + ObjectAddress *typaddress, const char *queryString); extern void RemoveRelations(DropStmt *drop); diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h index 9e59da24a4..3ea13bdf14 100644 --- a/src/include/commands/tablespace.h +++ b/src/include/commands/tablespace.h @@ -4,7 +4,7 @@ * Tablespace management commands (create/drop tablespace). * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/tablespace.h diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h index 0ed7c86eb2..d73969c874 100644 --- a/src/include/commands/trigger.h +++ b/src/include/commands/trigger.h @@ -3,7 +3,7 @@ * trigger.h * Declarations for trigger handling. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/trigger.h @@ -37,6 +37,8 @@ typedef struct TriggerData Trigger *tg_trigger; Buffer tg_trigtuplebuf; Buffer tg_newtuplebuf; + Tuplestorestate *tg_oldtable; + Tuplestorestate *tg_newtable; } TriggerData; /* @@ -210,6 +212,4 @@ extern bool RI_Initial_Check(Trigger *trigger, extern int RI_FKey_trigger_type(Oid tgfoid); -extern Datum pg_trigger_depth(PG_FUNCTION_ARGS); - #endif /* TRIGGER_H */ diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h index e4c86f1b1d..c18f93adb2 100644 --- a/src/include/commands/typecmds.h +++ b/src/include/commands/typecmds.h @@ -4,7 +4,7 @@ * prototypes for typecmds.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/typecmds.h @@ -21,12 +21,12 @@ #define DEFAULT_TYPDELIM ',' -extern ObjectAddress DefineType(List *names, List *parameters); +extern ObjectAddress DefineType(ParseState *pstate, List *names, List *parameters); extern void RemoveTypeById(Oid typeOid); extern ObjectAddress DefineDomain(CreateDomainStmt *stmt); extern ObjectAddress DefineEnum(CreateEnumStmt *stmt); extern ObjectAddress DefineRange(CreateRangeStmt *stmt); -extern ObjectAddress AlterEnum(AlterEnumStmt *stmt, bool isTopLevel); +extern ObjectAddress AlterEnum(AlterEnumStmt *stmt); extern ObjectAddress DefineCompositeType(RangeVar *typevar, List *coldeflist); extern Oid AssignTypeArrayOid(void); diff --git a/src/include/commands/user.h b/src/include/commands/user.h index d35cb0c90d..06b5a3de37 100644 --- a/src/include/commands/user.h +++ b/src/include/commands/user.h @@ -13,17 +13,27 @@ #include "catalog/objectaddress.h" #include "nodes/parsenodes.h" +#include "parser/parse_node.h" -/* Hook to check passwords in CreateRole() and AlterRole() */ -#define PASSWORD_TYPE_PLAINTEXT 0 -#define PASSWORD_TYPE_MD5 1 +/* + * Types of password, for Password_encryption GUC and the password_type + * argument of the check-password hook. + */ +typedef enum PasswordType +{ + PASSWORD_TYPE_PLAINTEXT = 0, + PASSWORD_TYPE_MD5 +} PasswordType; +extern int Password_encryption; /* GUC */ + +/* Hook to check passwords in CreateRole() and AlterRole() */ typedef void (*check_password_hook_type) (const char *username, const char *password, int password_type, Datum validuntil_time, bool validuntil_null); extern PGDLLIMPORT check_password_hook_type check_password_hook; -extern Oid CreateRole(CreateRoleStmt *stmt); +extern Oid CreateRole(ParseState *pstate, CreateRoleStmt *stmt); extern Oid AlterRole(AlterRoleStmt *stmt); extern Oid AlterRoleSet(AlterRoleSetStmt *stmt); extern void DropRole(DropRoleStmt *stmt); @@ -32,5 +42,7 @@ extern ObjectAddress RenameRole(const char *oldname, const char *newname); extern void DropOwnedObjects(DropOwnedStmt *stmt); extern void ReassignOwnedObjects(ReassignOwnedStmt *stmt); extern List *roleSpecsToIds(List *memberNames); +extern char *get_rolename(Oid roid); +extern Oid get_roleid(const char *rolename); #endif /* USER_H */ diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index 80cd4a86d8..541c2fa3cf 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -4,7 +4,7 @@ * header file for postgres vacuum cleaner and statistics analyzer * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/vacuum.h diff --git a/src/include/commands/variable.h b/src/include/commands/variable.h index 81059515da..247423c6fb 100644 --- a/src/include/commands/variable.h +++ b/src/include/commands/variable.h @@ -2,7 +2,7 @@ * variable.h * Routines for handling specialized SET variables. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/variable.h diff --git a/src/include/commands/view.h b/src/include/commands/view.h index 99e456449d..39763913c8 100644 --- a/src/include/commands/view.h +++ b/src/include/commands/view.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/view.h @@ -19,7 +19,8 @@ extern void validateWithCheckOption(char *value); -extern ObjectAddress DefineView(ViewStmt *stmt, const char *queryString); +extern ObjectAddress DefineView(ViewStmt *stmt, const char *queryString, + int stmt_location, int stmt_len); extern void StoreViewQuery(Oid viewOid, Query *viewParse, bool replace); diff --git a/src/include/common/config_info.h b/src/include/common/config_info.h index a695a42c0a..656e26fdb0 100644 --- a/src/include/common/config_info.h +++ b/src/include/common/config_info.h @@ -2,7 +2,7 @@ * config_info.h * Common code for pg_config output * - * Copyright (c) 2016, PostgreSQL Global Development Group + * Copyright (c) 2016-2017, PostgreSQL Global Development Group * * src/include/common/config_info.h */ diff --git a/src/include/common/controldata_utils.h b/src/include/common/controldata_utils.h index a355d2252d..82ea426afe 100644 --- a/src/include/common/controldata_utils.h +++ b/src/include/common/controldata_utils.h @@ -2,7 +2,7 @@ * controldata_utils.h * Common code for pg_controldata output * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/controldata_utils.h @@ -12,6 +12,6 @@ #include "catalog/pg_control.h" -extern ControlFileData *get_controlfile(char *DataDir, const char *progname); +extern ControlFileData *get_controlfile(const char *DataDir, const char *progname, bool *crc_ok_p); #endif /* COMMON_CONTROLDATA_UTILS_H */ diff --git a/src/include/common/fe_memutils.h b/src/include/common/fe_memutils.h index b4ce3d41ef..cb381bd9f5 100644 --- a/src/include/common/fe_memutils.h +++ b/src/include/common/fe_memutils.h @@ -2,7 +2,7 @@ * fe_memutils.h * memory management support for frontend code * - * Copyright (c) 2003-2016, PostgreSQL Global Development Group + * Copyright (c) 2003-2017, PostgreSQL Global Development Group * * src/include/common/fe_memutils.h */ diff --git a/src/include/common/file_utils.h b/src/include/common/file_utils.h new file mode 100644 index 0000000000..07c25c244d --- /dev/null +++ b/src/include/common/file_utils.h @@ -0,0 +1,26 @@ +/*------------------------------------------------------------------------- + * + * File-processing utility routines for frontend code + * + * Assorted utility functions to work on files. + * + * + * Portions Copyright (c) 1996-2017, 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 + +extern int fsync_fname(const char *fname, bool isdir, + const char *progname); +extern void fsync_pgdata(const char *pg_data, const char *progname, + int serverVersion); +extern int durable_rename(const char *oldfile, const char *newfile, + const char *progname); +extern int fsync_parent_path(const char *fname, const char *progname); + +#endif /* FILE_UTILS_H */ diff --git a/src/include/libpq/ip.h b/src/include/common/ip.h similarity index 61% rename from src/include/libpq/ip.h rename to src/include/common/ip.h index ce9bc6e225..815e6ccad3 100644 --- a/src/include/libpq/ip.h +++ b/src/include/common/ip.h @@ -3,12 +3,11 @@ * ip.h * Definitions for IPv6-aware network access. * - * These definitions are used by both frontend and backend code. Be careful - * what you include here! + * These definitions are used by both frontend and backend code. * - * Copyright (c) 2003-2016, PostgreSQL Global Development Group + * Copyright (c) 2003-2017, PostgreSQL Global Development Group * - * src/include/libpq/ip.h + * src/include/common/ip.h * *------------------------------------------------------------------------- */ @@ -25,10 +24,6 @@ #define IS_AF_UNIX(fam) (0) #endif -typedef void (*PgIfAddrCallback) (struct sockaddr * addr, - struct sockaddr * netmask, - void *cb_data); - extern int pg_getaddrinfo_all(const char *hostname, const char *servname, const struct addrinfo * hintp, struct addrinfo ** result); @@ -39,13 +34,4 @@ extern int pg_getnameinfo_all(const struct sockaddr_storage * addr, int salen, char *service, int servicelen, int flags); -extern int pg_range_sockaddr(const struct sockaddr_storage * addr, - const struct sockaddr_storage * netaddr, - const struct sockaddr_storage * netmask); - -extern int pg_sockaddr_cidr_mask(struct sockaddr_storage * mask, - char *numbits, int family); - -extern int pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data); - #endif /* IP_H */ diff --git a/src/include/common/keywords.h b/src/include/common/keywords.h index 97c830521c..34e066be6b 100644 --- a/src/include/common/keywords.h +++ b/src/include/common/keywords.h @@ -4,7 +4,7 @@ * lexical token lookup for key words in PostgreSQL * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/keywords.h diff --git a/src/include/libpq/md5.h b/src/include/common/md5.h similarity index 89% rename from src/include/libpq/md5.h rename to src/include/common/md5.h index f3eec8b4f4..58dc844390 100644 --- a/src/include/libpq/md5.h +++ b/src/include/common/md5.h @@ -6,10 +6,10 @@ * These definitions are needed by both frontend and backend code to work * with MD5-encrypted passwords. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * src/include/libpq/md5.h + * src/include/common/md5.h * *------------------------------------------------------------------------- */ diff --git a/src/include/common/relpath.h b/src/include/common/relpath.h index 8754b2f44c..df090f2da4 100644 --- a/src/include/common/relpath.h +++ b/src/include/common/relpath.h @@ -3,7 +3,7 @@ * relpath.h * Declarations for GetRelationPath() and friends * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/relpath.h diff --git a/src/include/common/restricted_token.h b/src/include/common/restricted_token.h index fb4ebd4cad..7441a55119 100644 --- a/src/include/common/restricted_token.h +++ b/src/include/common/restricted_token.h @@ -2,7 +2,7 @@ * restricted_token.h * helper routine to ensure restricted token on Windows * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/restricted_token.h diff --git a/src/include/common/string.h b/src/include/common/string.h index bb54d28fcb..ec9ee9a740 100644 --- a/src/include/common/string.h +++ b/src/include/common/string.h @@ -2,7 +2,7 @@ * string.h * string handling helpers * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/string.h diff --git a/src/include/common/username.h b/src/include/common/username.h index 0c3d754c61..114304f9e1 100644 --- a/src/include/common/username.h +++ b/src/include/common/username.h @@ -2,7 +2,7 @@ * username.h * lookup effective username * - * Copyright (c) 2003-2016, PostgreSQL Global Development Group + * Copyright (c) 2003-2017, PostgreSQL Global Development Group * * src/include/common/username.h */ diff --git a/src/include/datatype/timestamp.h b/src/include/datatype/timestamp.h index 68a41ebdc5..9ad808a851 100644 --- a/src/include/datatype/timestamp.h +++ b/src/include/datatype/timestamp.h @@ -5,7 +5,7 @@ * * Note: this file must be includable in both frontend and backend contexts. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/datatype/timestamp.h diff --git a/src/include/executor/execParallel.h b/src/include/executor/execParallel.h index f4c6d37a11..8bc4270e17 100644 --- a/src/include/executor/execParallel.h +++ b/src/include/executor/execParallel.h @@ -2,7 +2,7 @@ * execParallel.h * POSTGRES parallel execution interface * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -17,6 +17,7 @@ #include "nodes/execnodes.h" #include "nodes/parsenodes.h" #include "nodes/plannodes.h" +#include "utils/dsa.h" typedef struct SharedExecutorInstrumentation SharedExecutorInstrumentation; @@ -27,6 +28,7 @@ typedef struct ParallelExecutorInfo BufferUsage *buffer_usage; SharedExecutorInstrumentation *instrumentation; shm_mq_handle **tqueue; + dsa_area *area; bool finished; } ParallelExecutorInfo; diff --git a/src/include/executor/execdebug.h b/src/include/executor/execdebug.h index 950a0bc157..cf44c3edbb 100644 --- a/src/include/executor/execdebug.h +++ b/src/include/executor/execdebug.h @@ -7,7 +7,7 @@ * for debug printouts, because that's more flexible than printf(). * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/execdebug.h diff --git a/src/include/executor/execdesc.h b/src/include/executor/execdesc.h index d5b3fc8dbd..c99ea81815 100644 --- a/src/include/executor/execdesc.h +++ b/src/include/executor/execdesc.h @@ -5,7 +5,7 @@ * and related modules. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/execdesc.h @@ -34,8 +34,7 @@ typedef struct QueryDesc { /* These fields are provided by CreateQueryDesc */ CmdType operation; /* CMD_SELECT, CMD_UPDATE, etc. */ - PlannedStmt *plannedstmt; /* planner's output, or null if utility */ - Node *utilitystmt; /* utility statement, or null */ + PlannedStmt *plannedstmt; /* planner's output (could be utility, too) */ const char *sourceText; /* source text of the query */ Snapshot snapshot; /* snapshot to use for query */ Snapshot crosscheck_snapshot; /* crosscheck for RI update/delete */ @@ -61,12 +60,6 @@ extern QueryDesc *CreateQueryDesc(PlannedStmt *plannedstmt, ParamListInfo params, int instrument_options); -extern QueryDesc *CreateUtilityQueryDesc(Node *utilitystmt, - const char *sourceText, - Snapshot snapshot, - DestReceiver *dest, - ParamListInfo params); - extern void FreeQueryDesc(QueryDesc *qdesc); #endif /* EXECDESC_H */ diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 39521ed08e..02dbe7b228 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -4,7 +4,7 @@ * support for the POSTGRES executor module * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/executor.h @@ -14,6 +14,7 @@ #ifndef EXECUTOR_H #define EXECUTOR_H +#include "catalog/partition.h" #include "executor/execdesc.h" #include "nodes/parsenodes.h" @@ -69,8 +70,8 @@ * now it's just a macro invoking the function pointed to by an ExprState * node. Beware of double evaluation of the ExprState argument! */ -#define ExecEvalExpr(expr, econtext, isNull, isDone) \ - ((*(expr)->evalfunc) (expr, econtext, isNull, isDone)) +#define ExecEvalExpr(expr, econtext, isNull) \ + ((*(expr)->evalfunc) (expr, econtext, isNull)) /* Hook for plugins to get control in ExecutorStart() */ @@ -140,9 +141,9 @@ extern void execTuplesHashPrepare(int numCols, extern TupleHashTable BuildTupleHashTable(int numCols, AttrNumber *keyColIdx, FmgrInfo *eqfunctions, FmgrInfo *hashfunctions, - long nbuckets, Size entrysize, + long nbuckets, Size additionalsize, MemoryContext tablecxt, - MemoryContext tempcxt); + MemoryContext tempcxt, bool use_variable_hash_iv); extern TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew); @@ -188,11 +189,13 @@ extern void CheckValidResultRel(Relation resultRel, CmdType operation); extern void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, + Relation partition_root, int instrument_options); extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid); extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids); extern void ExecConstraints(ResultRelInfo *resultRelInfo, - TupleTableSlot *slot, EState *estate); + TupleTableSlot *slot, TupleTableSlot *orig_slot, + EState *estate); extern void ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate); extern LockTupleMode ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo); @@ -211,6 +214,16 @@ extern void EvalPlanQualSetPlan(EPQState *epqstate, extern void EvalPlanQualSetTuple(EPQState *epqstate, Index rti, HeapTuple tuple); extern HeapTuple EvalPlanQualGetTuple(EPQState *epqstate, Index rti); +extern void ExecSetupPartitionTupleRouting(Relation rel, + PartitionDispatch **pd, + ResultRelInfo **partitions, + TupleConversionMap ***tup_conv_maps, + TupleTableSlot **partition_tuple_slot, + int *num_parted, int *num_partitions); +extern int ExecFindPartition(ResultRelInfo *resultRelInfo, + PartitionDispatch *pd, + TupleTableSlot *slot, + EState *estate); #define EvalPlanQualSetSlot(epqstate, slot) ((epqstate)->origslot = (slot)) extern void EvalPlanQualFetchRowMarks(EPQState *epqstate); @@ -239,15 +252,18 @@ extern Tuplestorestate *ExecMakeTableFunctionResult(ExprState *funcexpr, MemoryContext argContext, TupleDesc expectedDesc, bool randomAccess); +extern Datum ExecMakeFunctionResultSet(FuncExprState *fcache, + ExprContext *econtext, + bool *isNull, + ExprDoneCond *isDone); extern Datum ExecEvalExprSwitchContext(ExprState *expression, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); extern ExprState *ExecInitExpr(Expr *node, PlanState *parent); extern ExprState *ExecPrepareExpr(Expr *node, EState *estate); extern bool ExecQual(List *qual, ExprContext *econtext, bool resultForNull); extern int ExecTargetListLength(List *targetlist); extern int ExecCleanTargetListLength(List *targetlist); -extern TupleTableSlot *ExecProject(ProjectionInfo *projInfo, - ExprDoneCond *isDone); +extern TupleTableSlot *ExecProject(ProjectionInfo *projInfo); /* * prototypes from functions in execScan.c @@ -376,5 +392,22 @@ extern void check_exclusion_constraint(Relation heap, Relation index, Datum *values, bool *isnull, EState *estate, bool newIndex); +/* + * prototypes from functions in execReplication.c + */ +extern bool RelationFindReplTupleByIndex(Relation rel, Oid idxoid, + LockTupleMode lockmode, + TupleTableSlot *searchslot, + TupleTableSlot *outslot); +extern bool RelationFindReplTupleSeq(Relation rel, LockTupleMode lockmode, + TupleTableSlot *searchslot, TupleTableSlot *outslot); + +extern void ExecSimpleRelationInsert(EState *estate, TupleTableSlot *slot); +extern void ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate, + TupleTableSlot *searchslot, TupleTableSlot *slot); +extern void ExecSimpleRelationDelete(EState *estate, EPQState *epqstate, + TupleTableSlot *searchslot); +extern void CheckCmdReplicaIdentity(Relation rel, CmdType cmd); + #endif /* EXECUTOR_H */ diff --git a/src/include/executor/functions.h b/src/include/executor/functions.h index 410f0e2c5c..7821a634f1 100644 --- a/src/include/executor/functions.h +++ b/src/include/executor/functions.h @@ -4,7 +4,7 @@ * Declarations for execution of SQL-language functions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/functions.h diff --git a/src/include/executor/hashjoin.h b/src/include/executor/hashjoin.h index 6d0e12bc5e..ac840533ee 100644 --- a/src/include/executor/hashjoin.h +++ b/src/include/executor/hashjoin.h @@ -4,7 +4,7 @@ * internal structures for hash joins * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/hashjoin.h diff --git a/src/include/executor/instrument.h b/src/include/executor/instrument.h index 8e5f0ec03b..c9e169c45c 100644 --- a/src/include/executor/instrument.h +++ b/src/include/executor/instrument.h @@ -4,7 +4,7 @@ * definitions for run-time statistics collection * * - * Copyright (c) 2001-2016, PostgreSQL Global Development Group + * Copyright (c) 2001-2017, PostgreSQL Global Development Group * * src/include/executor/instrument.h * diff --git a/src/include/executor/nodeAgg.h b/src/include/executor/nodeAgg.h index 54c75e8f31..d2fee52e12 100644 --- a/src/include/executor/nodeAgg.h +++ b/src/include/executor/nodeAgg.h @@ -4,7 +4,7 @@ * prototypes for nodeAgg.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeAgg.h diff --git a/src/include/executor/nodeAppend.h b/src/include/executor/nodeAppend.h index 51c381ee88..6fb4662c88 100644 --- a/src/include/executor/nodeAppend.h +++ b/src/include/executor/nodeAppend.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeAppend.h diff --git a/src/include/executor/nodeBitmapAnd.h b/src/include/executor/nodeBitmapAnd.h index 883ee3536f..1cb3470bcb 100644 --- a/src/include/executor/nodeBitmapAnd.h +++ b/src/include/executor/nodeBitmapAnd.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeBitmapAnd.h diff --git a/src/include/executor/nodeBitmapHeapscan.h b/src/include/executor/nodeBitmapHeapscan.h index 0ed9c7888a..d7659b94e6 100644 --- a/src/include/executor/nodeBitmapHeapscan.h +++ b/src/include/executor/nodeBitmapHeapscan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeBitmapHeapscan.h diff --git a/src/include/executor/nodeBitmapIndexscan.h b/src/include/executor/nodeBitmapIndexscan.h index 34ce521665..1fb8da01cb 100644 --- a/src/include/executor/nodeBitmapIndexscan.h +++ b/src/include/executor/nodeBitmapIndexscan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeBitmapIndexscan.h diff --git a/src/include/executor/nodeBitmapOr.h b/src/include/executor/nodeBitmapOr.h index 3885822929..a23bf77ff7 100644 --- a/src/include/executor/nodeBitmapOr.h +++ b/src/include/executor/nodeBitmapOr.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeBitmapOr.h diff --git a/src/include/executor/nodeCtescan.h b/src/include/executor/nodeCtescan.h index ef5c2bc8b7..e8bcb88b35 100644 --- a/src/include/executor/nodeCtescan.h +++ b/src/include/executor/nodeCtescan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeCtescan.h diff --git a/src/include/executor/nodeCustom.h b/src/include/executor/nodeCustom.h index 7d16c2b1fa..19d5d047b5 100644 --- a/src/include/executor/nodeCustom.h +++ b/src/include/executor/nodeCustom.h @@ -4,7 +4,7 @@ * * prototypes for CustomScan nodes * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * ------------------------------------------------------------------------ diff --git a/src/include/executor/nodeForeignscan.h b/src/include/executor/nodeForeignscan.h index 0cdec4e843..f0e942a8bc 100644 --- a/src/include/executor/nodeForeignscan.h +++ b/src/include/executor/nodeForeignscan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeForeignscan.h diff --git a/src/include/executor/nodeFunctionscan.h b/src/include/executor/nodeFunctionscan.h index d6e7a61730..efff0deaee 100644 --- a/src/include/executor/nodeFunctionscan.h +++ b/src/include/executor/nodeFunctionscan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeFunctionscan.h diff --git a/src/include/executor/nodeGather.h b/src/include/executor/nodeGather.h index f76d9be512..e19bc9b20d 100644 --- a/src/include/executor/nodeGather.h +++ b/src/include/executor/nodeGather.h @@ -4,7 +4,7 @@ * prototypes for nodeGather.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeGather.h diff --git a/src/include/executor/nodeGroup.h b/src/include/executor/nodeGroup.h index 92639f5c63..a9536a3c6f 100644 --- a/src/include/executor/nodeGroup.h +++ b/src/include/executor/nodeGroup.h @@ -4,7 +4,7 @@ * prototypes for nodeGroup.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeGroup.h diff --git a/src/include/executor/nodeHash.h b/src/include/executor/nodeHash.h index 8cf6d15c1f..fe5c2642d7 100644 --- a/src/include/executor/nodeHash.h +++ b/src/include/executor/nodeHash.h @@ -4,7 +4,7 @@ * prototypes for nodeHash.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeHash.h diff --git a/src/include/executor/nodeHashjoin.h b/src/include/executor/nodeHashjoin.h index f24127acac..ddc32b1de3 100644 --- a/src/include/executor/nodeHashjoin.h +++ b/src/include/executor/nodeHashjoin.h @@ -4,7 +4,7 @@ * prototypes for nodeHashjoin.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeHashjoin.h diff --git a/src/include/executor/nodeIndexonlyscan.h b/src/include/executor/nodeIndexonlyscan.h index d63d194a8f..4018af257d 100644 --- a/src/include/executor/nodeIndexonlyscan.h +++ b/src/include/executor/nodeIndexonlyscan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeIndexonlyscan.h diff --git a/src/include/executor/nodeIndexscan.h b/src/include/executor/nodeIndexscan.h index 194fadb386..46d6f45e83 100644 --- a/src/include/executor/nodeIndexscan.h +++ b/src/include/executor/nodeIndexscan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeIndexscan.h diff --git a/src/include/executor/nodeLimit.h b/src/include/executor/nodeLimit.h index 96166b44f2..6e4084b46d 100644 --- a/src/include/executor/nodeLimit.h +++ b/src/include/executor/nodeLimit.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeLimit.h diff --git a/src/include/executor/nodeLockRows.h b/src/include/executor/nodeLockRows.h index e828e9c6ec..c23954131b 100644 --- a/src/include/executor/nodeLockRows.h +++ b/src/include/executor/nodeLockRows.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeLockRows.h diff --git a/src/include/executor/nodeMaterial.h b/src/include/executor/nodeMaterial.h index 2b8cae197d..f6a7241ee7 100644 --- a/src/include/executor/nodeMaterial.h +++ b/src/include/executor/nodeMaterial.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeMaterial.h diff --git a/src/include/executor/nodeMergeAppend.h b/src/include/executor/nodeMergeAppend.h index 0efc489794..eafa15445c 100644 --- a/src/include/executor/nodeMergeAppend.h +++ b/src/include/executor/nodeMergeAppend.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeMergeAppend.h diff --git a/src/include/executor/nodeMergejoin.h b/src/include/executor/nodeMergejoin.h index 74d691ce2c..ffaa3af908 100644 --- a/src/include/executor/nodeMergejoin.h +++ b/src/include/executor/nodeMergejoin.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeMergejoin.h diff --git a/src/include/executor/nodeModifyTable.h b/src/include/executor/nodeModifyTable.h index 6b663537a5..0c327768e1 100644 --- a/src/include/executor/nodeModifyTable.h +++ b/src/include/executor/nodeModifyTable.h @@ -3,7 +3,7 @@ * nodeModifyTable.h * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeModifyTable.h diff --git a/src/include/executor/nodeNestloop.h b/src/include/executor/nodeNestloop.h index eeb42d6cea..4b2bf59050 100644 --- a/src/include/executor/nodeNestloop.h +++ b/src/include/executor/nodeNestloop.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeNestloop.h diff --git a/src/include/executor/nodeProjectSet.h b/src/include/executor/nodeProjectSet.h new file mode 100644 index 0000000000..30b2b7cec9 --- /dev/null +++ b/src/include/executor/nodeProjectSet.h @@ -0,0 +1,24 @@ +/*------------------------------------------------------------------------- + * + * nodeProjectSet.h + * + * + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeProjectSet.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEPROJECTSET_H +#define NODEPROJECTSET_H + +#include "nodes/execnodes.h" + +extern ProjectSetState *ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags); +extern TupleTableSlot *ExecProjectSet(ProjectSetState *node); +extern void ExecEndProjectSet(ProjectSetState *node); +extern void ExecReScanProjectSet(ProjectSetState *node); + +#endif /* NODEPROJECTSET_H */ diff --git a/src/include/executor/nodeRecursiveunion.h b/src/include/executor/nodeRecursiveunion.h index 1c087907c2..066596f773 100644 --- a/src/include/executor/nodeRecursiveunion.h +++ b/src/include/executor/nodeRecursiveunion.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeRecursiveunion.h diff --git a/src/include/executor/nodeResult.h b/src/include/executor/nodeResult.h index 356027f8cf..8e547b77e9 100644 --- a/src/include/executor/nodeResult.h +++ b/src/include/executor/nodeResult.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeResult.h diff --git a/src/include/executor/nodeSamplescan.h b/src/include/executor/nodeSamplescan.h index c8f03d8b18..8baf3a355c 100644 --- a/src/include/executor/nodeSamplescan.h +++ b/src/include/executor/nodeSamplescan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeSamplescan.h diff --git a/src/include/executor/nodeSeqscan.h b/src/include/executor/nodeSeqscan.h index f2e61ffdb3..92b305e138 100644 --- a/src/include/executor/nodeSeqscan.h +++ b/src/include/executor/nodeSeqscan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeSeqscan.h diff --git a/src/include/executor/nodeSetOp.h b/src/include/executor/nodeSetOp.h index c6e9603204..887bdc1a42 100644 --- a/src/include/executor/nodeSetOp.h +++ b/src/include/executor/nodeSetOp.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeSetOp.h diff --git a/src/include/executor/nodeSort.h b/src/include/executor/nodeSort.h index 481065fdbe..10d16b47b1 100644 --- a/src/include/executor/nodeSort.h +++ b/src/include/executor/nodeSort.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeSort.h diff --git a/src/include/executor/nodeSubplan.h b/src/include/executor/nodeSubplan.h index f05a47419d..0f821dc8f6 100644 --- a/src/include/executor/nodeSubplan.h +++ b/src/include/executor/nodeSubplan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeSubplan.h diff --git a/src/include/executor/nodeSubqueryscan.h b/src/include/executor/nodeSubqueryscan.h index 427699be0b..c2a0f707a6 100644 --- a/src/include/executor/nodeSubqueryscan.h +++ b/src/include/executor/nodeSubqueryscan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeSubqueryscan.h diff --git a/src/include/executor/nodeTidscan.h b/src/include/executor/nodeTidscan.h index 76c2a9f297..3186ca8cff 100644 --- a/src/include/executor/nodeTidscan.h +++ b/src/include/executor/nodeTidscan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeTidscan.h diff --git a/src/include/executor/nodeUnique.h b/src/include/executor/nodeUnique.h index aa8491dd3c..66ad898397 100644 --- a/src/include/executor/nodeUnique.h +++ b/src/include/executor/nodeUnique.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeUnique.h diff --git a/src/include/executor/nodeValuesscan.h b/src/include/executor/nodeValuesscan.h index 026f261c51..6c2af73b1f 100644 --- a/src/include/executor/nodeValuesscan.h +++ b/src/include/executor/nodeValuesscan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeValuesscan.h diff --git a/src/include/executor/nodeWindowAgg.h b/src/include/executor/nodeWindowAgg.h index 94ed0372e6..11d2dba2c5 100644 --- a/src/include/executor/nodeWindowAgg.h +++ b/src/include/executor/nodeWindowAgg.h @@ -4,7 +4,7 @@ * prototypes for nodeWindowAgg.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeWindowAgg.h diff --git a/src/include/executor/nodeWorktablescan.h b/src/include/executor/nodeWorktablescan.h index 217208a112..7790ca2e1b 100644 --- a/src/include/executor/nodeWorktablescan.h +++ b/src/include/executor/nodeWorktablescan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeWorktablescan.h diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h index 1792fb1217..a18ae63245 100644 --- a/src/include/executor/spi.h +++ b/src/include/executor/spi.h @@ -3,7 +3,7 @@ * spi.h * Server Programming Interface public declarations * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/spi.h @@ -59,6 +59,13 @@ typedef struct _SPI_plan *SPIPlanPtr; #define SPI_OK_UPDATE_RETURNING 13 #define SPI_OK_REWRITTEN 14 +/* These used to be functions, now just no-ops for backwards compatibility */ +#define SPI_push() ((void) 0) +#define SPI_pop() ((void) 0) +#define SPI_push_conditional() false +#define SPI_pop_conditional(pushed) ((void) 0) +#define SPI_restore_connection() ((void) 0) + extern PGDLLIMPORT uint64 SPI_processed; extern PGDLLIMPORT Oid SPI_lastoid; extern PGDLLIMPORT SPITupleTable *SPI_tuptable; @@ -66,11 +73,6 @@ extern PGDLLIMPORT int SPI_result; extern int SPI_connect(void); extern int SPI_finish(void); -extern void SPI_push(void); -extern void SPI_pop(void); -extern bool SPI_push_conditional(void); -extern void SPI_pop_conditional(bool pushed); -extern void SPI_restore_connection(void); extern int SPI_execute(const char *src, bool read_only, long tcount); extern int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only, long tcount); diff --git a/src/include/executor/spi_priv.h b/src/include/executor/spi_priv.h index e8084dff09..db8b59c387 100644 --- a/src/include/executor/spi_priv.h +++ b/src/include/executor/spi_priv.h @@ -3,7 +3,7 @@ * spi_priv.h * Server Programming Interface private declarations * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/spi_priv.h diff --git a/src/include/executor/tqueue.h b/src/include/executor/tqueue.h index 3a0aba162d..892eec812e 100644 --- a/src/include/executor/tqueue.h +++ b/src/include/executor/tqueue.h @@ -3,7 +3,7 @@ * tqueue.h * Use shm_mq to send & receive tuples between parallel backends * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/tqueue.h diff --git a/src/include/executor/tstoreReceiver.h b/src/include/executor/tstoreReceiver.h index 54e67ea367..cd15e27821 100644 --- a/src/include/executor/tstoreReceiver.h +++ b/src/include/executor/tstoreReceiver.h @@ -4,7 +4,7 @@ * prototypes for tstoreReceiver.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/tstoreReceiver.h diff --git a/src/include/executor/tuptable.h b/src/include/executor/tuptable.h index 5ac0b6a1f6..32489ef9bd 100644 --- a/src/include/executor/tuptable.h +++ b/src/include/executor/tuptable.h @@ -4,7 +4,7 @@ * tuple table support stuff * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/tuptable.h diff --git a/src/include/fe_utils/mbprint.h b/src/include/fe_utils/mbprint.h index e37eb5cb33..56626f631b 100644 --- a/src/include/fe_utils/mbprint.h +++ b/src/include/fe_utils/mbprint.h @@ -3,7 +3,7 @@ * Multibyte character printing support for frontend code * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/fe_utils/mbprint.h diff --git a/src/include/fe_utils/print.h b/src/include/fe_utils/print.h index 18aee93ecd..d89b6febcb 100644 --- a/src/include/fe_utils/print.h +++ b/src/include/fe_utils/print.h @@ -3,7 +3,7 @@ * Query-result printing support for frontend code * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/fe_utils/print.h diff --git a/src/include/fe_utils/psqlscan.h b/src/include/fe_utils/psqlscan.h index 1f10ecc2d4..21c4f227a1 100644 --- a/src/include/fe_utils/psqlscan.h +++ b/src/include/fe_utils/psqlscan.h @@ -10,7 +10,7 @@ * backslash commands. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/fe_utils/psqlscan.h diff --git a/src/include/fe_utils/psqlscan_int.h b/src/include/fe_utils/psqlscan_int.h index a52929d5ab..0fddc7a856 100644 --- a/src/include/fe_utils/psqlscan_int.h +++ b/src/include/fe_utils/psqlscan_int.h @@ -34,7 +34,7 @@ * same flex version, or if they don't use the same flex options. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/fe_utils/psqlscan_int.h diff --git a/src/include/fe_utils/simple_list.h b/src/include/fe_utils/simple_list.h index 87d32fbac9..b63f5dc061 100644 --- a/src/include/fe_utils/simple_list.h +++ b/src/include/fe_utils/simple_list.h @@ -7,7 +7,7 @@ * it's all we need in, eg, pg_dump. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/fe_utils/simple_list.h diff --git a/src/include/fe_utils/string_utils.h b/src/include/fe_utils/string_utils.h index 7bbed360a3..8f96a0b991 100644 --- a/src/include/fe_utils/string_utils.h +++ b/src/include/fe_utils/string_utils.h @@ -6,7 +6,7 @@ * assorted contexts. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/fe_utils/string_utils.h @@ -30,6 +30,9 @@ extern const char *fmtId(const char *identifier); extern const char *fmtQualifiedId(int remoteVersion, const char *schema, const char *id); +extern char *formatPGVersionNumber(int version_number, bool include_minor, + char *buf, size_t buflen); + extern void appendStringLiteral(PQExpBuffer buf, const char *str, int encoding, bool std_strings); extern void appendStringLiteralConn(PQExpBuffer buf, const char *str, diff --git a/src/include/fmgr.h b/src/include/fmgr.h index 0491e2e1d1..a671480004 100644 --- a/src/include/fmgr.h +++ b/src/include/fmgr.h @@ -8,7 +8,7 @@ * or call fmgr-callable functions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/fmgr.h @@ -344,11 +344,18 @@ typedef const Pg_finfo_record *(*PGFInfoFunction) (void); /* * Macro to build an info function associated with the given function name. - * Win32 loadable functions usually link with 'dlltool --export-all', but it - * doesn't hurt to add PGDLLIMPORT in case they don't. + * + * As a convenience, also provide an "extern" declaration for the given + * function name, so that writers of C functions need not write that too. + * + * On Windows, the function and info function must be exported. Our normal + * build processes take care of that via .DEF files or --export-all-symbols. + * Module authors using a different build process might need to manually + * declare the function PGDLLEXPORT. We do that automatically here for the + * info function, since authors shouldn't need to be explicitly aware of it. */ #define PG_FUNCTION_INFO_V1(funcname) \ -Datum funcname(PG_FUNCTION_ARGS); \ +extern Datum funcname(PG_FUNCTION_ARGS); \ extern PGDLLEXPORT const Pg_finfo_record * CppConcat(pg_finfo_,funcname)(void); \ const Pg_finfo_record * \ CppConcat(pg_finfo_,funcname) (void) \ diff --git a/src/include/foreign/fdwapi.h b/src/include/foreign/fdwapi.h index e1b0d0da7d..523d415575 100644 --- a/src/include/foreign/fdwapi.h +++ b/src/include/foreign/fdwapi.h @@ -3,7 +3,7 @@ * fdwapi.h * API for foreign-data wrappers * - * Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Copyright (c) 2010-2017, PostgreSQL Global Development Group * * src/include/foreign/fdwapi.h * diff --git a/src/include/foreign/foreign.h b/src/include/foreign/foreign.h index 5dc2c90f3c..446a071239 100644 --- a/src/include/foreign/foreign.h +++ b/src/include/foreign/foreign.h @@ -4,7 +4,7 @@ * support for foreign-data wrappers, servers and user mappings. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * src/include/foreign/foreign.h * @@ -23,7 +23,7 @@ /* * Generic option types for validation. - * NB! Thes are treated as flags, so use only powers of two here. + * NB! These are treated as flags, so use only powers of two here. */ typedef enum { diff --git a/src/include/funcapi.h b/src/include/funcapi.h index e73a82427c..30e66b6335 100644 --- a/src/include/funcapi.h +++ b/src/include/funcapi.h @@ -7,7 +7,7 @@ * or call FUNCAPI-callable functions or macros. * * - * Copyright (c) 2002-2016, PostgreSQL Global Development Group + * Copyright (c) 2002-2017, PostgreSQL Global Development Group * * src/include/funcapi.h * diff --git a/src/include/getaddrinfo.h b/src/include/getaddrinfo.h index 46aad596c7..952cd44712 100644 --- a/src/include/getaddrinfo.h +++ b/src/include/getaddrinfo.h @@ -13,7 +13,7 @@ * This code will also work on platforms where struct addrinfo is defined * in the system headers but no getaddrinfo() can be located. * - * Copyright (c) 2003-2016, PostgreSQL Global Development Group + * Copyright (c) 2003-2017, PostgreSQL Global Development Group * * src/include/getaddrinfo.h * diff --git a/src/include/getopt_long.h b/src/include/getopt_long.h index ad6c1e3ad0..a16c5f9b14 100644 --- a/src/include/getopt_long.h +++ b/src/include/getopt_long.h @@ -2,7 +2,7 @@ * Portions Copyright (c) 1987, 1993, 1994 * The Regents of the University of California. All rights reserved. * - * Portions Copyright (c) 2003-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2017, PostgreSQL Global Development Group * * src/include/getopt_long.h */ diff --git a/src/include/lib/binaryheap.h b/src/include/lib/binaryheap.h index 08a4cedc07..a4bbb390ea 100644 --- a/src/include/lib/binaryheap.h +++ b/src/include/lib/binaryheap.h @@ -3,7 +3,7 @@ * * A simple binary heap implementation * - * Portions Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2017, PostgreSQL Global Development Group * * src/include/lib/binaryheap.h */ diff --git a/src/include/lib/bipartite_match.h b/src/include/lib/bipartite_match.h index f9292f264e..d662b3821e 100644 --- a/src/include/lib/bipartite_match.h +++ b/src/include/lib/bipartite_match.h @@ -1,7 +1,7 @@ /* * bipartite_match.h * - * Copyright (c) 2015-2016, PostgreSQL Global Development Group + * Copyright (c) 2015-2017, PostgreSQL Global Development Group * * src/include/lib/bipartite_match.h */ diff --git a/src/include/lib/hyperloglog.h b/src/include/lib/hyperloglog.h index ee88f8f781..dd40fe9b00 100644 --- a/src/include/lib/hyperloglog.h +++ b/src/include/lib/hyperloglog.h @@ -3,7 +3,7 @@ * * A simple HyperLogLog cardinality estimator implementation * - * Portions Copyright (c) 2014-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2014-2017, PostgreSQL Global Development Group * * Based on Hideaki Ohno's C++ implementation. The copyright terms of Ohno's * original version (the MIT license) follow. diff --git a/src/include/lib/ilist.h b/src/include/lib/ilist.h index e189e4f377..8a44c90c4f 100644 --- a/src/include/lib/ilist.h +++ b/src/include/lib/ilist.h @@ -96,7 +96,7 @@ * } * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/lib/pairingheap.h b/src/include/lib/pairingheap.h index ee1454850c..9ee90befe5 100644 --- a/src/include/lib/pairingheap.h +++ b/src/include/lib/pairingheap.h @@ -3,7 +3,7 @@ * * A Pairing Heap implementation * - * Portions Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2017, PostgreSQL Global Development Group * * src/include/lib/pairingheap.h */ diff --git a/src/include/lib/rbtree.h b/src/include/lib/rbtree.h index 73e83c367a..7e2b7ae71b 100644 --- a/src/include/lib/rbtree.h +++ b/src/include/lib/rbtree.h @@ -3,7 +3,7 @@ * rbtree.h * interface for PostgreSQL generic Red-Black binary tree package * - * Copyright (c) 2009-2016, PostgreSQL Global Development Group + * Copyright (c) 2009-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/include/lib/rbtree.h @@ -22,7 +22,6 @@ */ typedef struct RBNode { - char iteratorState; /* workspace for iterating through tree */ char color; /* node's current color, red or black */ struct RBNode *left; /* left child, or RBNIL if none */ struct RBNode *right; /* right child, or RBNIL if none */ @@ -41,6 +40,22 @@ typedef enum RBOrderControl InvertedWalk /* postorder: left child, right child, node */ } RBOrderControl; +/* + * RBTreeIterator holds state while traversing a tree. This is declared + * here so that callers can stack-allocate this, but must otherwise be + * treated as an opaque struct. + */ +typedef struct RBTreeIterator RBTreeIterator; + +struct RBTreeIterator +{ + RBTree *rb; + RBNode *(*iterate) (RBTreeIterator *iter); + RBNode *last_visited; + char next_step; + bool is_over; +}; + /* Support functions to be provided by caller */ typedef int (*rb_comparator) (const RBNode *a, const RBNode *b, void *arg); typedef void (*rb_combiner) (RBNode *existing, const RBNode *newdata, void *arg); @@ -60,7 +75,8 @@ extern RBNode *rb_leftmost(RBTree *rb); extern RBNode *rb_insert(RBTree *rb, const RBNode *data, bool *isNew); extern void rb_delete(RBTree *rb, RBNode *node); -extern void rb_begin_iterate(RBTree *rb, RBOrderControl ctrl); -extern RBNode *rb_iterate(RBTree *rb); +extern void rb_begin_iterate(RBTree *rb, RBOrderControl ctrl, + RBTreeIterator *iter); +extern RBNode *rb_iterate(RBTreeIterator *iter); #endif /* RBTREE_H */ diff --git a/src/include/lib/simplehash.h b/src/include/lib/simplehash.h new file mode 100644 index 0000000000..12aedbc384 --- /dev/null +++ b/src/include/lib/simplehash.h @@ -0,0 +1,878 @@ +/* + * simplehash.h + * + * Hash table implementation which will be specialized to user-defined + * types, by including this file to generate the required code. It's + * probably not worthwhile to do so for hash tables that aren't performance + * or space sensitive. + * + * Usage notes: + * + * To generate a hash-table and associated functions for a use case several + * macros have to be #define'ed before this file is included. Including + * the file #undef's all those, so a new hash table can be generated + * afterwards. + * The relevant parameters are: + * - SH_PREFIX - prefix for all symbol names generated. A prefix of 'foo' + * will result in hash table type 'foo_hash' and functions like + * 'foo_insert'/'foo_lookup' and so forth. + * - SH_ELEMENT_TYPE - type of the contained elements + * - SH_KEY_TYPE - type of the hashtable's key + * - SH_DECLARE - if defined function prototypes and type declarations are + * generated + * - SH_DEFINE - if defined function definitions are generated + * - SH_SCOPE - in which scope (e.g. extern, static inline) do function + * declarations reside + * The following parameters are only relevant when SH_DEFINE is defined: + * - SH_KEY - name of the element in SH_ELEMENT_TYPE containing the hash key + * - SH_EQUAL(table, a, b) - compare two table keys + * - SH_HASH_KEY(table, key) - generate hash for the key + * - SH_STORE_HASH - if defined the hash is stored in the elements + * - SH_GET_HASH(tb, a) - return the field to store the hash in + * + * For examples of usage look at simplehash.c (file local definition) and + * execnodes.h/execGrouping.c (exposed declaration, file local + * implementation). + * + * Hash table design: + * + * The hash table design chosen is a variant of linear open-addressing. The + * reason for doing so is that linear addressing is CPU cache & pipeline + * friendly. The biggest disadvantage of simple linear addressing schemes + * are highly variable lookup times due to clustering, and deletions + * leaving a lot of tombstones around. To address these issues a variant + * of "robin hood" hashing is employed. Robin hood hashing optimizes + * chaining lengths by moving elements close to their optimal bucket + * ("rich" elements), out of the way if a to-be-inserted element is further + * away from its optimal position (i.e. it's "poor"). While that can make + * insertions slower, the average lookup performance is a lot better, and + * higher fill factors can be used in a still performant manner. To avoid + * tombstones - which normally solve the issue that a deleted node's + * presence is relevant to determine whether a lookup needs to continue + * looking or is done - buckets following a deleted element are shifted + * backwards, unless they're empty or already at their optimal position. + */ + +/* helpers */ +#define SH_MAKE_PREFIX(a) CppConcat(a,_) +#define SH_MAKE_NAME(name) SH_MAKE_NAME_(SH_MAKE_PREFIX(SH_PREFIX),name) +#define SH_MAKE_NAME_(a,b) CppConcat(a,b) + +/* name macros for: */ + +/* type declarations */ +#define SH_TYPE SH_MAKE_NAME(hash) +#define SH_STATUS SH_MAKE_NAME(status) +#define SH_STATUS_EMPTY SH_MAKE_NAME(EMPTY) +#define SH_STATUS_IN_USE SH_MAKE_NAME(IN_USE) +#define SH_ITERATOR SH_MAKE_NAME(iterator) + +/* function declarations */ +#define SH_CREATE SH_MAKE_NAME(create) +#define SH_DESTROY SH_MAKE_NAME(destroy) +#define SH_INSERT SH_MAKE_NAME(insert) +#define SH_DELETE SH_MAKE_NAME(delete) +#define SH_LOOKUP SH_MAKE_NAME(lookup) +#define SH_GROW SH_MAKE_NAME(grow) +#define SH_START_ITERATE SH_MAKE_NAME(start_iterate) +#define SH_START_ITERATE_AT SH_MAKE_NAME(start_iterate_at) +#define SH_ITERATE SH_MAKE_NAME(iterate) +#define SH_STAT SH_MAKE_NAME(stat) + +/* internal helper functions (no externally visible prototypes) */ +#define SH_COMPUTE_PARAMETERS SH_MAKE_NAME(compute_parameters) +#define SH_NEXT SH_MAKE_NAME(next) +#define SH_PREV SH_MAKE_NAME(prev) +#define SH_DISTANCE_FROM_OPTIMAL SH_MAKE_NAME(distance) +#define SH_INITIAL_BUCKET SH_MAKE_NAME(initial_bucket) +#define SH_ENTRY_HASH SH_MAKE_NAME(entry_hash) + +/* generate forward declarations necessary to use the hash table */ +#ifdef SH_DECLARE + +/* type definitions */ +typedef struct SH_TYPE +{ + /* + * Size of data / bucket array, 64 bits to handle UINT32_MAX sized hash + * tables. Note that the maximum number of elements is lower + * (SH_MAX_FILLFACTOR) + */ + uint64 size; + + /* how many elements have valid contents */ + uint32 members; + + /* mask for bucket and size calculations, based on size */ + uint32 sizemask; + + /* boundary after which to grow hashtable */ + uint32 grow_threshold; + + /* hash buckets */ + SH_ELEMENT_TYPE *data; + + /* memory context to use for allocations */ + MemoryContext ctx; + + /* user defined data, useful for callbacks */ + void *private_data; +} SH_TYPE; + +typedef enum SH_STATUS +{ + SH_STATUS_EMPTY = 0x00, + SH_STATUS_IN_USE = 0x01 +} SH_STATUS; + +typedef struct SH_ITERATOR +{ + uint32 cur; /* current element */ + uint32 end; + bool done; /* iterator exhausted? */ +} SH_ITERATOR; + +/* externally visible function prototypes */ +SH_SCOPE SH_TYPE *SH_CREATE(MemoryContext ctx, uint32 nelements); +SH_SCOPE void SH_DESTROY(SH_TYPE *tb); +SH_SCOPE void SH_GROW(SH_TYPE *tb, uint32 newsize); +SH_SCOPE SH_ELEMENT_TYPE *SH_INSERT(SH_TYPE *tb, SH_KEY_TYPE key, bool *found); +SH_SCOPE SH_ELEMENT_TYPE *SH_LOOKUP(SH_TYPE *tb, SH_KEY_TYPE key); +SH_SCOPE bool SH_DELETE(SH_TYPE *tb, SH_KEY_TYPE key); +SH_SCOPE void SH_START_ITERATE(SH_TYPE *tb, SH_ITERATOR *iter); +SH_SCOPE void SH_START_ITERATE_AT(SH_TYPE *tb, SH_ITERATOR *iter, uint32 at); +SH_SCOPE SH_ELEMENT_TYPE *SH_ITERATE(SH_TYPE *tb, SH_ITERATOR *iter); +SH_SCOPE void SH_STAT(SH_TYPE *tb); + +#endif /* SH_DECLARE */ + + +/* generate implementation of the hash table */ +#ifdef SH_DEFINE + +#include "utils/memutils.h" + +/* conservative fillfactor for a robin hood table, might want to adjust */ +#define SH_FILLFACTOR (0.8) +/* increase fillfactor if we otherwise would error out */ +#define SH_MAX_FILLFACTOR (0.95) +/* max data array size,we allow up to PG_UINT32_MAX buckets, including 0 */ +#define SH_MAX_SIZE (((uint64) PG_UINT32_MAX) + 1) + +#ifdef SH_STORE_HASH +#define SH_COMPARE_KEYS(tb, ahash, akey, b) (ahash == SH_GET_HASH(tb, b) && SH_EQUAL(tb, b->SH_KEY, akey)) +#else +#define SH_COMPARE_KEYS(tb, ahash, akey, b) (SH_EQUAL(tb, b->SH_KEY, akey)) +#endif + +/* FIXME: can we move these to a central location? */ + +/* calculate ceil(log base 2) of num */ +static inline uint64 +sh_log2(uint64 num) +{ + int i; + uint64 limit; + + for (i = 0, limit = 1; limit < num; i++, limit <<= 1) + ; + return i; +} + +/* calculate first power of 2 >= num */ +static inline uint64 +sh_pow2(uint64 num) +{ + return ((uint64) 1) << sh_log2(num); +} + +/* + * Compute sizing parameters for hashtable. Called when creating and growing + * the hashtable. + */ +static inline void +SH_COMPUTE_PARAMETERS(SH_TYPE *tb, uint32 newsize) +{ + uint64 size; + + /* supporting zero sized hashes would complicate matters */ + size = Max(newsize, 2); + + /* round up size to the next power of 2, that's the bucketing works */ + size = sh_pow2(size); + Assert(size <= SH_MAX_SIZE); + + /* + * Verify allocation of ->data is possible on platform, without + * overflowing Size. + */ + if ((((uint64) sizeof(SH_ELEMENT_TYPE)) * size) >= MaxAllocHugeSize) + elog(ERROR, "hash table too large"); + + /* now set size */ + tb->size = size; + + if (tb->size == SH_MAX_SIZE) + tb->sizemask = 0; + else + tb->sizemask = tb->size - 1; + + /* + * Compute growth threshold here and after growing the table, to make + * computations during insert cheaper. + */ + if (tb->size == SH_MAX_SIZE) + tb->grow_threshold = ((double) tb->size) * SH_MAX_FILLFACTOR; + else + tb->grow_threshold = ((double) tb->size) * SH_FILLFACTOR; +} + +/* return the optimal bucket for the hash */ +static inline uint32 +SH_INITIAL_BUCKET(SH_TYPE *tb, uint32 hash) +{ + return hash & tb->sizemask; +} + +/* return next bucket after the current, handling wraparound */ +static inline uint32 +SH_NEXT(SH_TYPE *tb, uint32 curelem, uint32 startelem) +{ + curelem = (curelem + 1) & tb->sizemask; + + Assert(curelem != startelem); + + return curelem; +} + +/* return bucket before the current, handling wraparound */ +static inline uint32 +SH_PREV(SH_TYPE *tb, uint32 curelem, uint32 startelem) +{ + curelem = (curelem - 1) & tb->sizemask; + + Assert(curelem != startelem); + + return curelem; +} + +/* return distance between bucket and its optimal position */ +static inline uint32 +SH_DISTANCE_FROM_OPTIMAL(SH_TYPE *tb, uint32 optimal, uint32 bucket) +{ + if (optimal <= bucket) + return bucket - optimal; + else + return (tb->size + bucket) - optimal; +} + +static inline uint32 +SH_ENTRY_HASH(SH_TYPE *tb, SH_ELEMENT_TYPE * entry) +{ +#ifdef SH_STORE_HASH + return SH_GET_HASH(tb, entry); +#else + return SH_HASH_KEY(tb, entry->SH_KEY); +#endif +} + +/* + * Create a hash table with enough space for `nelements` distinct members, + * allocating required memory in the passed-in context. + */ +SH_SCOPE SH_TYPE * +SH_CREATE(MemoryContext ctx, uint32 nelements) +{ + SH_TYPE *tb; + uint64 size; + + tb = MemoryContextAllocZero(ctx, sizeof(SH_TYPE)); + tb->ctx = ctx; + + /* increase nelements by fillfactor, want to store nelements elements */ + size = Min((double) SH_MAX_SIZE, ((double) nelements) / SH_FILLFACTOR); + + SH_COMPUTE_PARAMETERS(tb, size); + + tb->data = MemoryContextAllocExtended(tb->ctx, + sizeof(SH_ELEMENT_TYPE) * tb->size, + MCXT_ALLOC_HUGE | MCXT_ALLOC_ZERO); + + return tb; +} + +/* destroy a previously created hash table */ +SH_SCOPE void +SH_DESTROY(SH_TYPE *tb) +{ + pfree(tb->data); + pfree(tb); +} + +/* + * Grow a hash table to at least `newsize` buckets. + * + * Usually this will automatically be called by insertions/deletions, when + * necessary. But resizing to the exact input size can be advantageous + * performance-wise, when known at some point. + */ +SH_SCOPE void +SH_GROW(SH_TYPE *tb, uint32 newsize) +{ + uint64 oldsize = tb->size; + SH_ELEMENT_TYPE *olddata = tb->data; + SH_ELEMENT_TYPE *newdata; + uint32 i; + uint32 startelem = 0; + uint32 copyelem; + + Assert(oldsize == sh_pow2(oldsize)); + Assert(oldsize != SH_MAX_SIZE); + Assert(oldsize < newsize); + + /* compute parameters for new table */ + SH_COMPUTE_PARAMETERS(tb, newsize); + + tb->data = MemoryContextAllocExtended( + tb->ctx, sizeof(SH_ELEMENT_TYPE) * tb->size, + MCXT_ALLOC_HUGE | MCXT_ALLOC_ZERO); + + newdata = tb->data; + + /* + * Copy entries from the old data to newdata. We theoretically could use + * SH_INSERT here, to avoid code duplication, but that's more general than + * we need. We neither want tb->members increased, nor do we need to do + * deal with deleted elements, nor do we need to compare keys. So a + * special-cased implementation is lot faster. As resizing can be time + * consuming and frequent, that's worthwile to optimize. + * + * To be able to simply move entries over, we have to start not at the + * first bucket (i.e olddata[0]), but find the first bucket that's either + * empty, or is occupied by an entry at its optimal position. Such a + * bucket has to exist in any table with a load factor under 1, as not all + * buckets are occupied, i.e. there always has to be an empty bucket. By + * starting at such a bucket we can move the entries to the larger table, + * without having to deal with conflicts. + */ + + /* search for the first element in the hash that's not wrapped around */ + for (i = 0; i < oldsize; i++) + { + SH_ELEMENT_TYPE *oldentry = &olddata[i]; + uint32 hash; + uint32 optimal; + + if (oldentry->status != SH_STATUS_IN_USE) + { + startelem = i; + break; + } + + hash = SH_ENTRY_HASH(tb, oldentry); + optimal = SH_INITIAL_BUCKET(tb, hash); + + if (optimal == i) + { + startelem = i; + break; + } + } + + /* and copy all elements in the old table */ + copyelem = startelem; + for (i = 0; i < oldsize; i++) + { + SH_ELEMENT_TYPE *oldentry = &olddata[copyelem]; + + if (oldentry->status == SH_STATUS_IN_USE) + { + uint32 hash; + uint32 startelem; + uint32 curelem; + SH_ELEMENT_TYPE *newentry; + + hash = SH_ENTRY_HASH(tb, oldentry); + startelem = SH_INITIAL_BUCKET(tb, hash); + curelem = startelem; + + /* find empty element to put data into */ + while (true) + { + newentry = &newdata[curelem]; + + if (newentry->status == SH_STATUS_EMPTY) + { + break; + } + + curelem = SH_NEXT(tb, curelem, startelem); + } + + /* copy entry to new slot */ + memcpy(newentry, oldentry, sizeof(SH_ELEMENT_TYPE)); + } + + /* can't use SH_NEXT here, would use new size */ + copyelem++; + if (copyelem >= oldsize) + { + copyelem = 0; + } + } + + pfree(olddata); +} + +/* + * Insert the key key into the hash-table, set *found to true if the key + * already exists, false otherwise. Returns the hash-table entry in either + * case. + */ +SH_SCOPE SH_ELEMENT_TYPE * +SH_INSERT(SH_TYPE *tb, SH_KEY_TYPE key, bool *found) +{ + uint32 hash = SH_HASH_KEY(tb, key); + uint32 startelem; + uint32 curelem; + SH_ELEMENT_TYPE *data; + uint32 insertdist = 0; + + /* + * We do the grow check even if the key is actually present, to avoid + * doing the check inside the loop. This also lets us avoid having to + * re-find our position in the hashtable after resizing. + */ + if (unlikely(tb->members >= tb->grow_threshold)) + { + if (tb->size == SH_MAX_SIZE) + { + elog(ERROR, "hash table size exceeded"); + } + + /* + * When optimizing, it can be very useful to print these out. + */ + /* SH_STAT(tb); */ + SH_GROW(tb, tb->size * 2); + /* SH_STAT(tb); */ + } + + /* perform insert, start bucket search at optimal location */ + data = tb->data; + startelem = SH_INITIAL_BUCKET(tb, hash); + curelem = startelem; + while (true) + { + uint32 curdist; + uint32 curhash; + uint32 curoptimal; + SH_ELEMENT_TYPE *entry = &data[curelem]; + + /* any empty bucket can directly be used */ + if (entry->status == SH_STATUS_EMPTY) + { + tb->members++; + entry->SH_KEY = key; +#ifdef SH_STORE_HASH + SH_GET_HASH(tb, entry) = hash; +#endif + entry->status = SH_STATUS_IN_USE; + *found = false; + return entry; + } + + /* + * If the bucket is not empty, we either found a match (in which case + * we're done), or we have to decide whether to skip over or move the + * colliding entry. When the colliding element's distance to its + * optimal position is smaller than the to-be-inserted entry's, we + * shift the colliding entry (and its followers) forward by one. + */ + + if (SH_COMPARE_KEYS(tb, hash, key, entry)) + { + Assert(entry->status == SH_STATUS_IN_USE); + *found = true; + return entry; + } + + curhash = SH_ENTRY_HASH(tb, entry); + curoptimal = SH_INITIAL_BUCKET(tb, curhash); + curdist = SH_DISTANCE_FROM_OPTIMAL(tb, curoptimal, curelem); + + if (insertdist > curdist) + { + SH_ELEMENT_TYPE *lastentry = entry; + uint32 emptyelem = curelem; + uint32 moveelem; + + /* find next empty bucket */ + while (true) + { + SH_ELEMENT_TYPE *emptyentry; + + emptyelem = SH_NEXT(tb, emptyelem, startelem); + emptyentry = &data[emptyelem]; + + if (emptyentry->status == SH_STATUS_EMPTY) + { + lastentry = emptyentry; + break; + } + } + + /* shift forward, starting at last occupied element */ + + /* + * TODO: This could be optimized to be one memcpy in may cases, + * excepting wrapping around at the end of ->data. Hasn't shown up + * in profiles so far though. + */ + moveelem = emptyelem; + while (moveelem != curelem) + { + SH_ELEMENT_TYPE *moveentry; + + moveelem = SH_PREV(tb, moveelem, startelem); + moveentry = &data[moveelem]; + + memcpy(lastentry, moveentry, sizeof(SH_ELEMENT_TYPE)); + lastentry = moveentry; + } + + /* and fill the now empty spot */ + tb->members++; + + entry->SH_KEY = key; +#ifdef SH_STORE_HASH + SH_GET_HASH(tb, entry) = hash; +#endif + entry->status = SH_STATUS_IN_USE; + *found = false; + return entry; + } + + curelem = SH_NEXT(tb, curelem, startelem); + insertdist++; + } +} + +/* + * Lookup up entry in hash table. Returns NULL if key not present. + */ +SH_SCOPE SH_ELEMENT_TYPE * +SH_LOOKUP(SH_TYPE *tb, SH_KEY_TYPE key) +{ + uint32 hash = SH_HASH_KEY(tb, key); + const uint32 startelem = SH_INITIAL_BUCKET(tb, hash); + uint32 curelem = startelem; + + while (true) + { + SH_ELEMENT_TYPE *entry = &tb->data[curelem]; + + if (entry->status == SH_STATUS_EMPTY) + { + return NULL; + } + + Assert(entry->status == SH_STATUS_IN_USE); + + if (SH_COMPARE_KEYS(tb, hash, key, entry)) + return entry; + + /* + * TODO: we could stop search based on distance. If the current + * buckets's distance-from-optimal is smaller than what we've skipped + * already, the entry doesn't exist. Probably only do so if + * SH_STORE_HASH is defined, to avoid re-computing hashes? + */ + + curelem = SH_NEXT(tb, curelem, startelem); + } +} + +/* + * Delete entry from hash table. Returns whether to-be-deleted key was + * present. + */ +SH_SCOPE bool +SH_DELETE(SH_TYPE *tb, SH_KEY_TYPE key) +{ + uint32 hash = SH_HASH_KEY(tb, key); + uint32 startelem = SH_INITIAL_BUCKET(tb, hash); + uint32 curelem = startelem; + + while (true) + { + SH_ELEMENT_TYPE *entry = &tb->data[curelem]; + + if (entry->status == SH_STATUS_EMPTY) + return false; + + if (entry->status == SH_STATUS_IN_USE && + SH_COMPARE_KEYS(tb, hash, key, entry)) + { + SH_ELEMENT_TYPE *lastentry = entry; + + tb->members--; + + /* + * Backward shift following elements till either an empty element + * or an element at its optimal position is encounterered. + * + * While that sounds expensive, the average chain length is short, + * and deletions would otherwise require toombstones. + */ + while (true) + { + SH_ELEMENT_TYPE *curentry; + uint32 curhash; + uint32 curoptimal; + + curelem = SH_NEXT(tb, curelem, startelem); + curentry = &tb->data[curelem]; + + if (curentry->status != SH_STATUS_IN_USE) + { + lastentry->status = SH_STATUS_EMPTY; + break; + } + + curhash = SH_ENTRY_HASH(tb, curentry); + curoptimal = SH_INITIAL_BUCKET(tb, curhash); + + /* current is at optimal position, done */ + if (curoptimal == curelem) + { + lastentry->status = SH_STATUS_EMPTY; + break; + } + + /* shift */ + memcpy(lastentry, curentry, sizeof(SH_ELEMENT_TYPE)); + + lastentry = curentry; + } + + return true; + } + + /* TODO: return false; if distance too big */ + + curelem = SH_NEXT(tb, curelem, startelem); + } +} + +/* + * Initialize iterator. + */ +SH_SCOPE void +SH_START_ITERATE(SH_TYPE *tb, SH_ITERATOR *iter) +{ + int i; + uint64 startelem = PG_UINT64_MAX; + + /* + * Search for the first empty element. As deletions during iterations are + * supported, we want to start/end at an element that cannot be affected + * by elements being shifted. + */ + for (i = 0; i < tb->size; i++) + { + SH_ELEMENT_TYPE *entry = &tb->data[i]; + + if (entry->status != SH_STATUS_IN_USE) + { + startelem = i; + break; + } + } + + Assert(startelem < SH_MAX_SIZE); + + /* + * Iterate backwards, that allows the current element to be deleted, even + * if there are backward shifts + */ + iter->cur = startelem; + iter->end = iter->cur; + iter->done = false; +} + +/* + * Initialize iterator to a specific bucket. That's really only useful for + * cases where callers are partially iterating over the hashspace, and that + * iteration deletes and inserts elements based on visited entries. Doing that + * repeatedly could lead to an unbalanced keyspace when always starting at the + * same position. + */ +SH_SCOPE void +SH_START_ITERATE_AT(SH_TYPE *tb, SH_ITERATOR *iter, uint32 at) +{ + /* + * Iterate backwards, that allows the current element to be deleted, even + * if there are backward shifts. + */ + iter->cur = at & tb->sizemask; /* ensure at is within a valid range */ + iter->end = iter->cur; + iter->done = false; +} + +/* + * Iterate over all entries in the hash-table. Return the next occupied entry, + * or NULL if done. + * + * During iteration the current entry in the hash table may be deleted, + * without leading to elements being skipped or returned twice. Additionally + * the rest of the table may be modified (i.e. there can be insertions or + * deletions), but if so, there's neither a guarantee that all nodes are + * visited at least once, nor a guarantee that a node is visited at most once. + */ +SH_SCOPE SH_ELEMENT_TYPE * +SH_ITERATE(SH_TYPE *tb, SH_ITERATOR *iter) +{ + while (!iter->done) + { + SH_ELEMENT_TYPE *elem; + + elem = &tb->data[iter->cur]; + + /* next element in backward direction */ + iter->cur = (iter->cur - 1) & tb->sizemask; + + if ((iter->cur & tb->sizemask) == (iter->end & tb->sizemask)) + iter->done = true; + if (elem->status == SH_STATUS_IN_USE) + { + return elem; + } + } + + return NULL; +} + +/* + * Report some statistics about the state of the hashtable. For + * debugging/profiling purposes only. + */ +SH_SCOPE void +SH_STAT(SH_TYPE *tb) +{ + uint32 max_chain_length = 0; + uint32 total_chain_length = 0; + double avg_chain_length; + double fillfactor; + uint32 i; + + uint32 *collisions = palloc0(tb->size * sizeof(uint32)); + uint32 total_collisions = 0; + uint32 max_collisions = 0; + double avg_collisions; + + for (i = 0; i < tb->size; i++) + { + uint32 hash; + uint32 optimal; + uint32 dist; + SH_ELEMENT_TYPE *elem; + + elem = &tb->data[i]; + + if (elem->status != SH_STATUS_IN_USE) + continue; + + hash = SH_ENTRY_HASH(tb, elem); + optimal = SH_INITIAL_BUCKET(tb, hash); + dist = SH_DISTANCE_FROM_OPTIMAL(tb, optimal, i); + + if (dist > max_chain_length) + max_chain_length = dist; + total_chain_length += dist; + + collisions[optimal]++; + } + + for (i = 0; i < tb->size; i++) + { + uint32 curcoll = collisions[i]; + + if (curcoll == 0) + continue; + + /* single contained element is not a collision */ + curcoll--; + total_collisions += curcoll; + if (curcoll > max_collisions) + max_collisions = curcoll; + } + + if (tb->members > 0) + { + fillfactor = tb->members / ((double) tb->size); + avg_chain_length = ((double) total_chain_length) / tb->members; + avg_collisions = ((double) total_collisions) / tb->members; + } + else + { + fillfactor = 0; + avg_chain_length = 0; + avg_collisions = 0; + } + + elog(LOG, "size: " UINT64_FORMAT ", members: %u, filled: %f, total chain: %u, max chain: %u, avg chain: %f, total_collisions: %u, max_collisions: %i, avg_collisions: %f", + tb->size, tb->members, fillfactor, total_chain_length, max_chain_length, avg_chain_length, + total_collisions, max_collisions, avg_collisions); +} + +#endif /* SH_DEFINE */ + + +/* undefine external paramters, so next hash table can be defined */ +#undef SH_PREFIX +#undef SH_KEY_TYPE +#undef SH_KEY +#undef SH_ELEMENT_TYPE +#undef SH_HASH_KEY +#undef SH_SCOPE +#undef SH_DECLARE +#undef SH_DEFINE +#undef SH_GET_HASH +#undef SH_STORE_HASH + +/* undefine locally declared macros */ +#undef SH_MAKE_PREFIX +#undef SH_MAKE_NAME +#undef SH_MAKE_NAME_ +#undef SH_FILLFACTOR +#undef SH_MAX_FILLFACTOR +#undef SH_MAX_SIZE + +/* types */ +#undef SH_TYPE +#undef SH_STATUS +#undef SH_STATUS_EMPTY +#undef SH_STATUS_IN_USE +#undef SH_ITERTOR + +/* external function names */ +#undef SH_CREATE +#undef SH_DESTROY +#undef SH_INSERT +#undef SH_DELETE +#undef SH_LOOKUP +#undef SH_GROW +#undef SH_START_ITERATE +#undef SH_START_ITERATE_AT +#undef SH_ITERATE +#undef SH_STAT + +/* internal function names */ +#undef SH_COMPUTE_PARAMETERS +#undef SH_COMPARE_KEYS +#undef SH_INITIAL_BUCKET +#undef SH_NEXT +#undef SH_PREV +#undef SH_DISTANCE_FROM_OPTIMAL +#undef SH_ENTRY_HASH diff --git a/src/include/lib/stringinfo.h b/src/include/lib/stringinfo.h index f64406710e..75ff5041bb 100644 --- a/src/include/lib/stringinfo.h +++ b/src/include/lib/stringinfo.h @@ -7,7 +7,7 @@ * It can be used to buffer either ordinary C strings (null-terminated text) * or arbitrary binary data. All storage is allocated with palloc(). * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/lib/stringinfo.h @@ -30,6 +30,8 @@ * 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. + * long_ok whether this StringInfo can allocate more than MaxAllocSize + * bytes (but still up to 2GB). *------------------------- */ typedef struct StringInfoData @@ -38,6 +40,7 @@ typedef struct StringInfoData int len; int maxlen; int cursor; + bool long_ok; } StringInfoData; typedef StringInfoData *StringInfo; @@ -46,11 +49,11 @@ typedef StringInfoData *StringInfo; /*------------------------ * There are two ways to create a StringInfo object initially: * - * StringInfo stringptr = makeStringInfo(); + * StringInfo stringptr = makeStringInfo(); // or makeLongStringInfo(); * Both the StringInfoData and the data buffer are palloc'd. * * StringInfoData string; - * initStringInfo(&string); + * initStringInfo(&string); // or initLongStringInfo(); * 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. @@ -67,21 +70,26 @@ typedef StringInfoData *StringInfo; /*------------------------ * makeStringInfo - * Create an empty 'StringInfoData' & return a pointer to it. + * makeLongStringInfo + * Create an empty 'StringInfoData' & return a pointer to it. The former + * allows up to 1 GB in size, per palloc(); the latter allows up to 2 GB. */ extern StringInfo makeStringInfo(void); +extern StringInfo makeLongStringInfo(void); /*------------------------ * initStringInfo + * initLongStringInfo * Initialize a StringInfoData struct (with previously undefined contents) - * to describe an empty string. + * to describe an empty string. Size limits as above. */ extern void initStringInfo(StringInfo str); +extern void initLongStringInfo(StringInfo str); /*------------------------ * resetStringInfo * Clears the current content of the StringInfo, if any. The - * StringInfo remains valid. + * StringInfo remains valid. The long_ok flag is not reset. */ extern void resetStringInfo(StringInfo str); diff --git a/src/include/libpq/auth.h b/src/include/libpq/auth.h index 3cd06b75c8..601dc5d71a 100644 --- a/src/include/libpq/auth.h +++ b/src/include/libpq/auth.h @@ -4,7 +4,7 @@ * Definitions for network authentication routines * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/auth.h diff --git a/src/include/libpq/be-fsstubs.h b/src/include/libpq/be-fsstubs.h index 3959bf1d96..641124cd21 100644 --- a/src/include/libpq/be-fsstubs.h +++ b/src/include/libpq/be-fsstubs.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/be-fsstubs.h @@ -14,37 +14,6 @@ #ifndef BE_FSSTUBS_H #define BE_FSSTUBS_H -#include "fmgr.h" - -/* - * LO functions available via pg_proc entries - */ -extern Datum lo_import(PG_FUNCTION_ARGS); -extern Datum lo_import_with_oid(PG_FUNCTION_ARGS); -extern Datum lo_export(PG_FUNCTION_ARGS); - -extern Datum lo_creat(PG_FUNCTION_ARGS); -extern Datum lo_create(PG_FUNCTION_ARGS); -extern Datum lo_from_bytea(PG_FUNCTION_ARGS); - -extern Datum lo_open(PG_FUNCTION_ARGS); -extern Datum lo_close(PG_FUNCTION_ARGS); - -extern Datum loread(PG_FUNCTION_ARGS); -extern Datum lowrite(PG_FUNCTION_ARGS); - -extern Datum lo_get(PG_FUNCTION_ARGS); -extern Datum lo_get_fragment(PG_FUNCTION_ARGS); -extern Datum lo_put(PG_FUNCTION_ARGS); - -extern Datum lo_lseek(PG_FUNCTION_ARGS); -extern Datum lo_tell(PG_FUNCTION_ARGS); -extern Datum lo_lseek64(PG_FUNCTION_ARGS); -extern Datum lo_tell64(PG_FUNCTION_ARGS); -extern Datum lo_unlink(PG_FUNCTION_ARGS); -extern Datum lo_truncate(PG_FUNCTION_ARGS); -extern Datum lo_truncate64(PG_FUNCTION_ARGS); - /* * compatibility option for access control */ diff --git a/src/include/libpq/crypt.h b/src/include/libpq/crypt.h index 5725bb409e..dce83a2a3b 100644 --- a/src/include/libpq/crypt.h +++ b/src/include/libpq/crypt.h @@ -3,7 +3,7 @@ * crypt.h * Interface to libpq/crypt.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/crypt.h @@ -13,9 +13,14 @@ #ifndef PG_CRYPT_H #define PG_CRYPT_H -#include "libpq/libpq-be.h" +#include "datatype/timestamp.h" -extern int md5_crypt_verify(const Port *port, const char *role, - char *client_pass, char **logdetail); +extern int get_role_password(const char *role, char **shadow_pass, char **logdetail); + +extern int md5_crypt_verify(const char *role, const char *shadow_pass, + const char *client_pass, const char *md5_salt, + int md5_salt_len, char **logdetail); +extern int plain_crypt_verify(const char *role, const char *shadow_pass, + const char *client_pass, char **logdetail); #endif diff --git a/src/include/libpq/ifaddr.h b/src/include/libpq/ifaddr.h new file mode 100644 index 0000000000..5f6f48598f --- /dev/null +++ b/src/include/libpq/ifaddr.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------- + * + * ifaddr.h + * IP netmask calculations, and enumerating network interfaces. + * + * Copyright (c) 2003-2017, PostgreSQL Global Development Group + * + * src/include/libpq/ifaddr.h + * + *------------------------------------------------------------------------- + */ +#ifndef IFADDR_H +#define IFADDR_H + +#include "libpq/pqcomm.h" /* pgrminclude ignore */ + +typedef void (*PgIfAddrCallback) (struct sockaddr * addr, + struct sockaddr * netmask, + void *cb_data); + +extern int pg_range_sockaddr(const struct sockaddr_storage * addr, + const struct sockaddr_storage * netaddr, + const struct sockaddr_storage * netmask); + +extern int pg_sockaddr_cidr_mask(struct sockaddr_storage * mask, + char *numbits, int family); + +extern int pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data); + +#endif /* IFADDR_H */ diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h index 5d07b78223..79d38cedd7 100644 --- a/src/include/libpq/libpq-be.h +++ b/src/include/libpq/libpq-be.h @@ -1,6 +1,6 @@ /*------------------------------------------------------------------------- * - * libpq_be.h + * libpq-be.h * This file contains definitions for structures and externs used * by the postmaster during client authentication. * @@ -8,7 +8,7 @@ * Structs that need to be client-visible are in pqcomm.h. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/libpq-be.h @@ -144,7 +144,6 @@ typedef struct Port * Information that needs to be held during the authentication cycle. */ HbaLine *hba; - char md5Salt[4]; /* Password salt */ /* * Information that really has no business at all being in struct Port, @@ -192,7 +191,6 @@ typedef struct Port #ifdef USE_OPENSSL SSL *ssl; X509 *peer; - unsigned long count; #endif } Port; @@ -201,7 +199,8 @@ typedef struct Port * These functions are implemented by the glue code specific to each * SSL implementation (e.g. be-secure-openssl.c) */ -extern void be_tls_init(void); +extern int be_tls_init(bool isServerStart); +extern void be_tls_destroy(void); extern int be_tls_open_server(Port *port); extern void be_tls_close(Port *port); extern ssize_t be_tls_read(Port *port, void *ptr, size_t len, int *waitfor); diff --git a/src/include/libpq/libpq-fs.h b/src/include/libpq/libpq-fs.h index 5134ce6aba..afe32706f4 100644 --- a/src/include/libpq/libpq-fs.h +++ b/src/include/libpq/libpq-fs.h @@ -4,7 +4,7 @@ * definitions for using Inversion file system routines (ie, large objects) * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/libpq-fs.h diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h index 18052cbfef..538066e106 100644 --- a/src/include/libpq/libpq.h +++ b/src/include/libpq/libpq.h @@ -4,7 +4,7 @@ * POSTGRES LIBPQ buffer structure definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/libpq.h @@ -81,10 +81,7 @@ extern char *ssl_key_file; extern char *ssl_ca_file; extern char *ssl_crl_file; -extern int (*pq_putmessage_hook) (char msgtype, const char *s, size_t len); -extern int (*pq_flush_hook) (void); - -extern int secure_initialize(void); +extern int secure_initialize(bool isServerStart); extern bool secure_loaded_verify_locations(void); extern void secure_destroy(void); extern int secure_open_server(Port *port); diff --git a/src/include/libpq/pqcomm.h b/src/include/libpq/pqcomm.h index c6bbfc2377..de9ccc63b1 100644 --- a/src/include/libpq/pqcomm.h +++ b/src/include/libpq/pqcomm.h @@ -6,7 +6,7 @@ * NOTE: for historical reasons, this does not correspond to pqcomm.c. * pqcomm.c's routines are declared in libpq.h. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/pqcomm.h @@ -107,7 +107,7 @@ typedef struct /* The earliest and latest frontend/backend protocol version supported. */ -#define PG_PROTOCOL_EARLIEST PG_PROTOCOL(1,0) +#define PG_PROTOCOL_EARLIEST PG_PROTOCOL(2,0) #define PG_PROTOCOL_LATEST PG_PROTOCOL(3,0) typedef uint32 ProtocolVersion; /* FE/BE protocol version number */ diff --git a/src/include/libpq/pqformat.h b/src/include/libpq/pqformat.h index 3c0d4b2622..4df87ec8a2 100644 --- a/src/include/libpq/pqformat.h +++ b/src/include/libpq/pqformat.h @@ -3,7 +3,7 @@ * pqformat.h * Definitions for formatting and parsing frontend/backend messages * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/pqformat.h diff --git a/src/include/libpq/pqmq.h b/src/include/libpq/pqmq.h index 8c03acb308..e356bd60f4 100644 --- a/src/include/libpq/pqmq.h +++ b/src/include/libpq/pqmq.h @@ -3,7 +3,7 @@ * pqmq.h * Use the frontend/backend protocol for communication over a shm_mq * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/pqmq.h diff --git a/src/include/libpq/pqsignal.h b/src/include/libpq/pqsignal.h index c77553c7aa..a9dbce49d1 100644 --- a/src/include/libpq/pqsignal.h +++ b/src/include/libpq/pqsignal.h @@ -3,7 +3,7 @@ * pqsignal.h * Backend signal(2) support (see also src/port/pqsignal.c) * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/pqsignal.h diff --git a/src/include/mb/pg_wchar.h b/src/include/mb/pg_wchar.h index 24e8d0dc54..ceb5695924 100644 --- a/src/include/mb/pg_wchar.h +++ b/src/include/mb/pg_wchar.h @@ -3,7 +3,7 @@ * pg_wchar.h * multibyte-character support * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/mb/pg_wchar.h diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 78545daece..4c607b299c 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -10,7 +10,7 @@ * Over time, this has also become the preferred place for widely known * resource-limitation stuff, such as work_mem and check_stack_depth(). * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/miscadmin.h @@ -144,9 +144,9 @@ do { \ * from utils/init/globals.c */ extern PGDLLIMPORT pid_t PostmasterPid; -extern bool IsPostmasterEnvironment; +extern PGDLLIMPORT bool IsPostmasterEnvironment; extern PGDLLIMPORT bool IsUnderPostmaster; -extern bool IsBackgroundWorker; +extern PGDLLIMPORT bool IsBackgroundWorker; extern PGDLLIMPORT bool IsBinaryUpgrade; extern bool ExitOnAnyError; @@ -157,12 +157,13 @@ extern PGDLLIMPORT int NBuffers; extern int MaxBackends; extern int MaxConnections; extern int max_worker_processes; +extern int max_parallel_workers; extern PGDLLIMPORT int MyProcPid; extern PGDLLIMPORT pg_time_t MyStartTime; extern PGDLLIMPORT struct Port *MyProcPort; extern PGDLLIMPORT struct Latch *MyLatch; -extern long MyCancelKey; +extern int32 MyCancelKey; extern int MyPMChildSlot; extern char OutputFileName[]; diff --git a/src/include/nodes/bitmapset.h b/src/include/nodes/bitmapset.h index 31b4dfea0c..4f1910e5a9 100644 --- a/src/include/nodes/bitmapset.h +++ b/src/include/nodes/bitmapset.h @@ -11,7 +11,7 @@ * bms_is_empty() in preference to testing for NULL.) * * - * Copyright (c) 2003-2016, PostgreSQL Global Development Group + * Copyright (c) 2003-2017, PostgreSQL Global Development Group * * src/include/nodes/bitmapset.h * diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index e7fd7bd08e..f9bcdd63de 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -4,7 +4,7 @@ * definitions for executor state nodes * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/execnodes.h @@ -16,10 +16,12 @@ #include "access/genam.h" #include "access/heapam.h" +#include "access/tupconvert.h" #include "executor/instrument.h" #include "lib/pairingheap.h" #include "nodes/params.h" #include "nodes/plannodes.h" +#include "utils/hsearch.h" #include "utils/reltrigger.h" #include "utils/sortsupport.h" #include "utils/tuplestore.h" @@ -154,7 +156,8 @@ typedef struct ExprContext } ExprContext; /* - * Set-result status returned by ExecEvalExpr() + * Set-result status used when evaluating functions potentially returning a + * set. */ typedef enum { @@ -226,7 +229,6 @@ typedef struct ReturnSetInfo * targetlist target list for projection (non-Var expressions only) * exprContext expression context in which to evaluate targetlist * slot slot to place projection result in - * itemIsDone workspace array for ExecProject * directMap true if varOutputCols[] is an identity map * numSimpleVars number of simple Vars found in original tlist * varSlotOffsets array indicating which slot each simple Var is from @@ -243,7 +245,6 @@ typedef struct ProjectionInfo List *pi_targetlist; ExprContext *pi_exprContext; TupleTableSlot *pi_slot; - ExprDoneCond *pi_itemIsDone; bool pi_directMap; int pi_numSimpleVars; int *pi_varSlotOffsets; @@ -319,6 +320,8 @@ typedef struct JunkFilter * projectReturning for computing a RETURNING list * onConflictSetProj for computing ON CONFLICT DO UPDATE SET * onConflictSetWhere list of ON CONFLICT DO UPDATE exprs (qual) + * PartitionCheck partition check expression + * PartitionCheckExpr partition check expression state * ---------------- */ typedef struct ResultRelInfo @@ -343,6 +346,9 @@ typedef struct ResultRelInfo ProjectionInfo *ri_projectReturning; ProjectionInfo *ri_onConflictSetProj; List *ri_onConflictSetWhere; + List *ri_PartitionCheck; + List *ri_PartitionCheckExpr; + Relation ri_PartitionRoot; } ResultRelInfo; /* ---------------- @@ -421,6 +427,9 @@ typedef struct EState HeapTuple *es_epqTuple; /* array of EPQ substitute tuples */ bool *es_epqTupleSet; /* true if EPQ tuple is provided */ bool *es_epqScanDone; /* true if EPQ tuple has been fetched */ + + /* The per-query shared memory area to use for parallel execution. */ + struct dsa_area *es_query_dsa; } EState; @@ -498,14 +507,23 @@ typedef struct TupleHashTableData *TupleHashTable; typedef struct TupleHashEntryData { - /* firstTuple must be the first field in this struct! */ MinimalTuple firstTuple; /* copy of first tuple in this group */ - /* there may be additional data beyond the end of this struct */ -} TupleHashEntryData; /* VARIABLE LENGTH STRUCT */ + void *additional; /* user data */ + uint32 status; /* hash status */ + uint32 hash; /* hash value (cached) */ +} TupleHashEntryData; + +/* define paramters necessary to generate the tuple hash table interface */ +#define SH_PREFIX tuplehash +#define SH_ELEMENT_TYPE TupleHashEntryData +#define SH_KEY_TYPE MinimalTuple +#define SH_SCOPE extern +#define SH_DECLARE +#include "lib/simplehash.h" typedef struct TupleHashTableData { - HTAB *hashtab; /* underlying dynahash table */ + tuplehash_hash *hashtab; /* underlying hash table */ int numCols; /* number of columns in lookup key */ AttrNumber *keyColIdx; /* attr numbers of key columns */ FmgrInfo *tab_hash_funcs; /* hash functions for table datatype(s) */ @@ -518,9 +536,10 @@ typedef struct TupleHashTableData TupleTableSlot *inputslot; /* current input tuple's slot */ FmgrInfo *in_hash_funcs; /* hash functions for input datatype(s) */ FmgrInfo *cur_eq_funcs; /* equality functions for input vs. table */ + uint32 hash_iv; /* hash-function IV */ } TupleHashTableData; -typedef HASH_SEQ_STATUS TupleHashIterator; +typedef tuplehash_iterator TupleHashIterator; /* * Use InitTupleHashIterator/TermTupleHashIterator for a read/write scan. @@ -528,16 +547,13 @@ typedef HASH_SEQ_STATUS TupleHashIterator; * explicit scan termination is needed). */ #define InitTupleHashIterator(htable, iter) \ - hash_seq_init(iter, (htable)->hashtab) + tuplehash_start_iterate(htable->hashtab, iter) #define TermTupleHashIterator(iter) \ - hash_seq_term(iter) + ((void) 0) #define ResetTupleHashIterator(htable, iter) \ - do { \ - hash_freeze((htable)->hashtab); \ - hash_seq_init(iter, (htable)->hashtab); \ - } while (0) -#define ScanTupleHashTable(iter) \ - ((TupleHashEntry) hash_seq_search(iter)) + InitTupleHashIterator(htable, iter) +#define ScanTupleHashTable(htable, iter) \ + tuplehash_iterate(htable->hashtab, iter) /* ---------------------------------------------------------------- @@ -569,8 +585,7 @@ typedef struct ExprState ExprState; typedef Datum (*ExprStateEvalFunc) (ExprState *expression, ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone); + bool *isNull); struct ExprState { @@ -679,7 +694,7 @@ typedef struct FuncExprState /* * Function manager's lookup info for the target function. If func.fn_oid * is InvalidOid, we haven't initialized it yet (nor any of the following - * fields). + * fields, except funcReturnsSet). */ FmgrInfo func; @@ -699,6 +714,12 @@ typedef struct FuncExprState bool funcReturnsTuple; /* valid when funcResultDesc isn't * NULL */ + /* + * Remember whether the function is declared to return a set. This is set + * by ExecInitExpr, and is valid even before the FmgrInfo is set up. + */ + bool funcReturnsSet; + /* * setArgsValid is true when we are evaluating a set-returning function * that uses value-per-call mode and we are in the middle of a call @@ -708,13 +729,6 @@ typedef struct FuncExprState */ bool setArgsValid; - /* - * Flag to remember whether we found a set-valued argument to the - * function. This causes the function result to be a set as well. Valid - * only when setArgsValid is true or funcResultStore isn't NULL. - */ - bool setHasSetArg; /* some argument returns a set */ - /* * Flag to remember whether we have registered a shutdown callback for * this FuncExprState. We do so only if funcResultStore or setArgsValid @@ -873,6 +887,7 @@ typedef struct CaseExprState ExprState *arg; /* implicit equality comparison argument */ List *args; /* the arguments (list of WHEN clauses) */ ExprState *defresult; /* the default result (ELSE clause) */ + int16 argtyplen; /* if arg is provided, its typlen */ } CaseExprState; /* ---------------- @@ -1057,8 +1072,6 @@ typedef struct PlanState TupleTableSlot *ps_ResultTupleSlot; /* slot for my result tuples */ ExprContext *ps_ExprContext; /* node's expression-evaluation context */ ProjectionInfo *ps_ProjInfo; /* info for doing tuple projection */ - bool ps_TupFromTlist;/* state flag for processing set-valued - * functions in targetlist */ } PlanState; /* ---------------- @@ -1111,6 +1124,18 @@ typedef struct ResultState bool rs_checkqual; /* do we need to check the qual? */ } ResultState; +/* ---------------- + * ProjectSetState information + * ---------------- + */ +typedef struct ProjectSetState +{ + PlanState ps; /* its first field is NodeTag */ + ExprDoneCond *elemdone; /* array of per-SRF is-done states */ + int nelems; /* length of elemdone[] array */ + bool pending_srf_tuples; /* still evaluating srfs in tlist? */ +} ProjectSetState; + /* ---------------- * ModifyTableState information * ---------------- @@ -1136,6 +1161,16 @@ typedef struct ModifyTableState * tlist */ TupleTableSlot *mt_conflproj; /* CONFLICT ... SET ... projection * target */ + struct PartitionDispatchData **mt_partition_dispatch_info; + /* Tuple-routing support info */ + int mt_num_dispatch; /* Number of entries in the above + * array */ + int mt_num_partitions; /* Number of members in the + * following arrays */ + ResultRelInfo *mt_partitions; /* Per partition result relation */ + TupleConversionMap **mt_partition_tupconv_maps; + /* Per partition tuple conversion map */ + TupleTableSlot *mt_partition_tuple_slot; } ModifyTableState; /* ---------------- @@ -1611,7 +1646,8 @@ struct CustomExecMethods; typedef struct CustomScanState { ScanState ss; - uint32 flags; /* mask of CUSTOMPATH_* flags, see relation.h */ + uint32 flags; /* mask of CUSTOMPATH_* flags, see + * nodes/extensible.h */ List *custom_ps; /* list of child PlanState nodes, if any */ Size pscan_len; /* size of parallel coordination information */ const struct CustomExecMethods *methods; @@ -1790,7 +1826,7 @@ typedef struct SortState /* --------------------- * GroupState information - * ------------------------- + * --------------------- */ typedef struct GroupState { @@ -1809,7 +1845,7 @@ typedef struct GroupState * input group during evaluation of an Agg node's output tuple(s). We * create a second ExprContext, tmpcontext, in which to evaluate input * expressions and run the aggregate transition functions. - * ------------------------- + * --------------------- */ /* these structs are private in nodeAgg.c: */ typedef struct AggStatePerAggData *AggStatePerAgg; @@ -1852,9 +1888,16 @@ typedef struct AggState /* these fields are used in AGG_HASHED mode: */ TupleHashTable hashtable; /* hash table with one entry per group */ TupleTableSlot *hashslot; /* slot for loading hash table */ - List *hash_needed; /* list of columns needed in hash table */ + int numhashGrpCols; /* number of columns in hash table */ + int largestGrpColIdx; /* largest column required for hashing */ + AttrNumber *hashGrpColIdxInput; /* and their indices in input slot */ + AttrNumber *hashGrpColIdxHash; /* indices for execGrouping in hashtbl */ bool table_filled; /* hash table filled yet? */ TupleHashIterator hashiter; /* for iterating through hash table */ + /* support for evaluation of agg inputs */ + TupleTableSlot *evalslot; /* slot for agg inputs */ + ProjectionInfo *evalproj; /* projection machinery */ + TupleDesc evaldesc; /* descriptor of input tuples */ } AggState; /* ---------------- diff --git a/src/include/nodes/extensible.h b/src/include/nodes/extensible.h index 17afe5897c..7e860b0dca 100644 --- a/src/include/nodes/extensible.h +++ b/src/include/nodes/extensible.h @@ -4,7 +4,7 @@ * Definitions for extensible nodes and custom scans * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/extensible.h diff --git a/src/include/nodes/lockoptions.h b/src/include/nodes/lockoptions.h index 1c2f00f65b..4f8affd930 100644 --- a/src/include/nodes/lockoptions.h +++ b/src/include/nodes/lockoptions.h @@ -4,7 +4,7 @@ * Common header for some locking-related declarations. * * - * Copyright (c) 2014-2016, PostgreSQL Global Development Group + * Copyright (c) 2014-2017, PostgreSQL Global Development Group * * src/include/nodes/lockoptions.h * diff --git a/src/include/nodes/makefuncs.h b/src/include/nodes/makefuncs.h index 01c5cb45d5..1f4bad7df6 100644 --- a/src/include/nodes/makefuncs.h +++ b/src/include/nodes/makefuncs.h @@ -4,7 +4,7 @@ * prototypes for the creator functions (for primitive nodes) * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/makefuncs.h @@ -80,9 +80,9 @@ extern FuncExpr *makeFuncExpr(Oid funcid, Oid rettype, List *args, extern FuncCall *makeFuncCall(List *name, List *args, int location); -extern DefElem *makeDefElem(char *name, Node *arg); +extern DefElem *makeDefElem(char *name, Node *arg, int location); extern DefElem *makeDefElemExtended(char *nameSpace, char *name, Node *arg, - DefElemAction defaction); + DefElemAction defaction, int location); extern GroupingSet *makeGroupingSet(GroupingSetKind kind, List *content, int location); diff --git a/src/include/nodes/memnodes.h b/src/include/nodes/memnodes.h index ba069cc130..e487d172fc 100644 --- a/src/include/nodes/memnodes.h +++ b/src/include/nodes/memnodes.h @@ -4,7 +4,7 @@ * POSTGRES memory context node definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/memnodes.h diff --git a/src/include/nodes/nodeFuncs.h b/src/include/nodes/nodeFuncs.h index 97af142929..b6c9b48ee6 100644 --- a/src/include/nodes/nodeFuncs.h +++ b/src/include/nodes/nodeFuncs.h @@ -3,7 +3,7 @@ * nodeFuncs.h * Various general-purpose manipulations of Node trees * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/nodeFuncs.h diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 6b850e4bc4..942bd6cacc 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -4,7 +4,7 @@ * Definitions for tagged nodes. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/nodes.h @@ -18,10 +18,10 @@ * The first field of every node is NodeTag. Each node created (with makeNode) * will have one of the following tags as the value of its first field. * - * Note that the numbers of the node tags are not contiguous. We left holes - * here so that we can add more tags without changing the existing enum's. - * (Since node tag numbers never exist outside backend memory, there's no - * real harm in renumbering, it just costs a full rebuild ...) + * Note that inserting or deleting node types changes the numbers of other + * node types later in the list. This is no problem during development, since + * the node numbers are never stored on disk. But don't do it in a released + * branch, because that would represent an ABI break for extensions. */ typedef enum NodeTag { @@ -30,7 +30,7 @@ typedef enum NodeTag /* * TAGS FOR EXECUTOR NODES (execnodes.h) */ - T_IndexInfo = 10, + T_IndexInfo, T_ExprContext, T_ProjectionInfo, T_JunkFilter, @@ -41,8 +41,9 @@ typedef enum NodeTag /* * TAGS FOR PLAN NODES (plannodes.h) */ - T_Plan = 100, + T_Plan, T_Result, + T_ProjectSet, T_ModifyTable, T_Append, T_MergeAppend, @@ -89,8 +90,9 @@ typedef enum NodeTag * * These should correspond one-to-one with Plan node types. */ - T_PlanState = 200, + T_PlanState, T_ResultState, + T_ProjectSetState, T_ModifyTableState, T_AppendState, T_MergeAppendState, @@ -131,7 +133,7 @@ typedef enum NodeTag /* * TAGS FOR PRIMITIVE NODES (primnodes.h) */ - T_Alias = 300, + T_Alias, T_RangeVar, T_Expr, T_Var, @@ -166,6 +168,7 @@ typedef enum NodeTag T_RowCompareExpr, T_CoalesceExpr, T_MinMaxExpr, + T_SQLValueFunction, T_XmlExpr, T_NullTest, T_BooleanTest, @@ -187,7 +190,7 @@ typedef enum NodeTag * These correspond (not always one-for-one) to primitive nodes derived * from Expr. */ - T_ExprState = 400, + T_ExprState, T_GenericExprState, T_WholeRowVarExprState, T_AggrefExprState, @@ -219,7 +222,7 @@ typedef enum NodeTag /* * TAGS FOR PLANNER NODES (relation.h) */ - T_PlannerInfo = 500, + T_PlannerInfo, T_PlannerGlobal, T_RelOptInfo, T_IndexOptInfo, @@ -244,6 +247,7 @@ typedef enum NodeTag T_UniquePath, T_GatherPath, T_ProjectionPath, + T_ProjectSetPath, T_SortPath, T_GroupPath, T_UpperUniquePath, @@ -272,13 +276,13 @@ typedef enum NodeTag /* * TAGS FOR MEMORY NODES (memnodes.h) */ - T_MemoryContext = 600, + T_MemoryContext, T_AllocSetContext, /* * TAGS FOR VALUE NODES (value.h) */ - T_Value = 650, + T_Value, T_Integer, T_Float, T_String, @@ -300,7 +304,8 @@ typedef enum NodeTag /* * TAGS FOR STATEMENT NODES (mostly in parsenodes.h) */ - T_Query = 700, + T_RawStmt, + T_Query, T_PlannedStmt, T_InsertStmt, T_DeleteStmt, @@ -405,11 +410,17 @@ typedef enum NodeTag T_AlterPolicyStmt, T_CreateTransformStmt, T_CreateAmStmt, + T_PartitionCmd, + T_CreatePublicationStmt, + T_AlterPublicationStmt, + T_CreateSubscriptionStmt, + T_AlterSubscriptionStmt, + T_DropSubscriptionStmt, /* * TAGS FOR PARSE TREE NODES (parsenodes.h) */ - T_A_Expr = 900, + T_A_Expr, T_ColumnRef, T_ParamRef, T_A_Const, @@ -452,6 +463,11 @@ typedef enum NodeTag T_OnConflictClause, T_CommonTableExpr, T_RoleSpec, + T_TriggerTransition, + T_PartitionElem, + T_PartitionSpec, + T_PartitionBoundSpec, + T_PartitionRangeDatum, /* * TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h) @@ -471,7 +487,7 @@ typedef enum NodeTag * purposes (usually because they are involved in APIs where we want to * pass multiple object types through the same pointer). */ - T_TriggerData = 950, /* in commands/trigger.h */ + T_TriggerData, /* in commands/trigger.h */ T_EventTriggerData, /* in commands/event_trigger.h */ T_ReturnSetInfo, /* in nodes/execnodes.h */ T_WindowObjectData, /* private in nodeWindowAgg.c */ @@ -550,10 +566,9 @@ extern PGDLLIMPORT Node *newNodeMacroHolder; /* * nodes/{outfuncs.c,print.c} */ -extern char *nodeToString(const void *obj); - struct Bitmapset; /* not to include bitmapset.h here */ struct StringInfoData; /* not to include stringinfo.h here */ + extern void outNode(struct StringInfoData *str, const void *obj); extern void outToken(struct StringInfoData *str, const char *s); extern void outBitmapset(struct StringInfoData *str, @@ -561,6 +576,11 @@ extern void outBitmapset(struct StringInfoData *str, extern void outDatum(struct StringInfoData *str, uintptr_t value, int typlen, bool typbyval); +extern void set_portable_input(bool value); +extern void set_portable_output(bool value); +extern char *nodeToString(const void *obj); +extern char *bmsToString(const struct Bitmapset *bms); + /* * nodes/{readfuncs.c,read.c} */ diff --git a/src/include/nodes/params.h b/src/include/nodes/params.h index a8aa530b74..e19ac24582 100644 --- a/src/include/nodes/params.h +++ b/src/include/nodes/params.h @@ -4,7 +4,7 @@ * Support for finding the values associated with Param nodes. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/params.h diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 1481fff57d..aad4699f48 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -7,10 +7,12 @@ * This is a byte (not character) offset in the original source text, to be * used for positioning an error cursor when there is an error related to * the node. Access to the original source text is needed to make use of - * the location. + * the location. At the topmost (statement) level, we also provide a + * statement length, likewise measured in bytes, for convenience in + * identifying statement boundaries in multi-statement source strings. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/parsenodes.h @@ -89,9 +91,7 @@ typedef uint32 AclMode; /* a bitmask of privilege bits */ * for further processing by the rewriter and planner. * * Utility statements (i.e. non-optimizable statements) have the - * utilityStmt field set, and the Query itself is mostly dummy. - * DECLARE CURSOR is a special case: it is represented like a SELECT, - * but the original DeclareCursorStmt is stored in utilityStmt. + * utilityStmt field set, and the rest of the Query is mostly dummy. * * Planning converts a Query tree into a Plan tree headed by a PlannedStmt * node --- the Query structure is not used by the executor. @@ -108,14 +108,14 @@ typedef struct Query bool canSetTag; /* do I set the command result tag? */ - Node *utilityStmt; /* non-null if this is DECLARE CURSOR or a - * non-optimizable statement */ + Node *utilityStmt; /* non-null if commandType == CMD_UTILITY */ int resultRelation; /* rtable index of target relation for * INSERT/UPDATE/DELETE; 0 for SELECT */ bool hasAggs; /* has aggregates in tlist or havingQual */ bool hasWindowFuncs; /* has window functions in tlist */ + bool hasTargetSRFs; /* has set-returning functions in tlist */ bool hasSubLinks; /* has subquery SubLink */ bool hasDistinctOn; /* distinctClause is from DISTINCT ON */ bool hasRecursive; /* WITH RECURSIVE was specified */ @@ -161,6 +161,15 @@ typedef struct Query * are only added during rewrite and * therefore are not written out as * part of Query. */ + + /* + * The following two fields identify the portion of the source text string + * containing this query. They are typically only populated in top-level + * Queries, not in sub-queries. When not set, they might both be zero, or + * both be -1 meaning "unknown". + */ + int stmt_location; /* start location, or -1 if unknown */ + int stmt_len; /* length in bytes; 0 means "rest of string" */ } Query; @@ -666,6 +675,7 @@ typedef struct DefElem char *defname; Node *arg; /* a (Value *) or a (TypeName *) */ DefElemAction defaction; /* unspecified action, or SET/ADD/DROP */ + int location; /* token location, or -1 if unknown */ } DefElem; /* @@ -697,6 +707,79 @@ typedef struct XmlSerialize int location; /* token location, or -1 if unknown */ } XmlSerialize; +/* Partitioning related definitions */ + +/* + * PartitionElem - a column in the partition key + */ +typedef struct PartitionElem +{ + NodeTag type; + char *name; /* name of column to partition on, or NULL */ + Node *expr; /* expression to partition on, or NULL */ + List *collation; /* name of collation; NIL = default */ + List *opclass; /* name of desired opclass; NIL = default */ + int location; /* token location, or -1 if unknown */ +} PartitionElem; + +/* + * PartitionSpec - partition key specification + */ +typedef struct PartitionSpec +{ + NodeTag type; + char *strategy; /* partitioning strategy ('list' or 'range') */ + List *partParams; /* List of PartitionElems */ + int location; /* token location, or -1 if unknown */ +} PartitionSpec; + +#define PARTITION_STRATEGY_LIST 'l' +#define PARTITION_STRATEGY_RANGE 'r' + +/* + * PartitionBoundSpec - a partition bound specification + */ +typedef struct PartitionBoundSpec +{ + NodeTag type; + + char strategy; + + /* List partition values */ + List *listdatums; + + /* + * Range partition lower and upper bounds; each member of the lists + * is a PartitionRangeDatum (see below). + */ + List *lowerdatums; + List *upperdatums; + + int location; +} PartitionBoundSpec; + +/* + * PartitionRangeDatum + */ +typedef struct PartitionRangeDatum +{ + NodeTag type; + + bool infinite; + Node *value; + + int location; +} PartitionRangeDatum; + +/* + * PartitionCmd - ALTER TABLE partition commands + */ +typedef struct PartitionCmd +{ + NodeTag type; + RangeVar *name; + Node *bound; +} PartitionCmd; /**************************************************************************** * Nodes for a Query tree @@ -773,6 +856,13 @@ typedef struct XmlSerialize * FirstLowInvalidHeapAttributeNumber from column numbers before storing * them in these fields. A whole-row Var reference is represented by * setting the bit for InvalidAttrNumber. + * + * securityQuals is a list of security barrier quals (boolean expressions), + * to be tested in the listed order before returning a row from the + * relation. It is always NIL in parser output. Entries are added by the + * rewriter to implement security-barrier views and/or row-level security. + * Note that the planner turns each boolean expression into an implicitly + * AND'ed sublist, as is its usual habit with qualification expressions. *-------------------- */ typedef enum RTEKind @@ -845,7 +935,6 @@ typedef struct RangeTblEntry * Fields valid for a values RTE (else NIL): */ List *values_lists; /* list of expression lists */ - List *values_collations; /* OID list of column collation OIDs */ /* * Fields valid for a CTE RTE (else NULL/zero): @@ -853,9 +942,17 @@ typedef struct RangeTblEntry char *ctename; /* name of the WITH list item */ Index ctelevelsup; /* number of query levels up */ bool self_reference; /* is this a recursive self-reference? */ - List *ctecoltypes; /* OID list of column type OIDs */ - List *ctecoltypmods; /* integer list of column typmods */ - List *ctecolcollations; /* OID list of column collation OIDs */ + + /* + * Fields valid for values and CTE RTEs (else NIL): + * + * We need these for CTE RTEs so that the types of self-referential + * columns are well-defined. For VALUES RTEs, storing these explicitly + * saves having to re-determine the info by scanning the values_lists. + */ + List *coltypes; /* OID list of column type OIDs */ + List *coltypmods; /* integer list of column typmods */ + List *colcollations; /* OID list of column collation OIDs */ /* * Fields valid in all RTEs: @@ -870,7 +967,7 @@ typedef struct RangeTblEntry Bitmapset *selectedCols; /* columns needing SELECT permission */ Bitmapset *insertedCols; /* columns needing INSERT permission */ Bitmapset *updatedCols; /* columns needing UPDATE permission */ - List *securityQuals; /* any security barrier quals to apply */ + List *securityQuals; /* security barrier quals to apply, if any */ } RangeTblEntry; /* @@ -1202,6 +1299,45 @@ typedef struct CommonTableExpr ((Query *) (cte)->ctequery)->targetList : \ ((Query *) (cte)->ctequery)->returningList) +/* + * TriggerTransition - + * representation of transition row or table naming clause + * + * Only transition tables are initially supported in the syntax, and only for + * AFTER triggers, but other permutations are accepted by the parser so we can + * give a meaningful message from C code. + */ +typedef struct TriggerTransition +{ + NodeTag type; + char *name; + bool isNew; + bool isTable; +} TriggerTransition; + +/***************************************************************************** + * Raw Grammar Output Statements + *****************************************************************************/ + +/* + * RawStmt --- container for any one statement's raw parse tree + * + * Parse analysis converts a raw parse tree headed by a RawStmt node into + * an analyzed statement headed by a Query node. For optimizable statements, + * the conversion is complex. For utility statements, the parser usually just + * transfers the raw parse tree (sans RawStmt) into the utilityStmt field of + * the Query node, and all the useful work happens at execution time. + * + * stmt_location/stmt_len identify the portion of the source text string + * containing this raw statement (useful for multi-statement strings). + */ +typedef struct RawStmt +{ + NodeTag type; + Node *stmt; /* raw parse tree */ + int stmt_location; /* start location, or -1 if unknown */ + int stmt_len; /* length in bytes; 0 means "rest of string" */ +} RawStmt; /***************************************************************************** * Optimizable Statements @@ -1370,6 +1506,9 @@ typedef struct SetOperationStmt * statements do need attention from parse analysis, and this is * done by routines in parser/parse_utilcmd.c after ProcessUtility * receives the command for execution. + * DECLARE CURSOR, EXPLAIN, and CREATE TABLE AS are special cases: + * they contain optimizable statements, which get processed normally + * by parser/analyze.c. *****************************************************************************/ /* @@ -1408,10 +1547,13 @@ typedef enum ObjectType OBJECT_OPERATOR, OBJECT_OPFAMILY, OBJECT_POLICY, + OBJECT_PUBLICATION, + OBJECT_PUBLICATION_REL, OBJECT_ROLE, OBJECT_RULE, OBJECT_SCHEMA, OBJECT_SEQUENCE, + OBJECT_SUBSCRIPTION, OBJECT_TABCONSTRAINT, OBJECT_TABLE, OBJECT_TABLESPACE, @@ -1438,7 +1580,7 @@ typedef struct CreateSchemaStmt { NodeTag type; char *schemaname; /* the name of the schema to create */ - Node *authrole; /* the owner of the created schema */ + RoleSpec *authrole; /* the owner of the created schema */ List *schemaElts; /* schema components (list of parsenodes) */ bool if_not_exists; /* just do nothing if schema already exists? */ } CreateSchemaStmt; @@ -1525,7 +1667,9 @@ typedef enum AlterTableType AT_DisableRowSecurity, /* DISABLE ROW SECURITY */ AT_ForceRowSecurity, /* FORCE ROW SECURITY */ AT_NoForceRowSecurity, /* NO FORCE ROW SECURITY */ - AT_GenericOptions /* OPTIONS (...) */ + AT_GenericOptions, /* OPTIONS (...) */ + AT_AttachPartition, /* ATTACH PARTITION */ + AT_DetachPartition /* DETACH PARTITION */ } AlterTableType; typedef struct ReplicaIdentityStmt @@ -1541,7 +1685,7 @@ typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */ AlterTableType subtype; /* Type of table alteration to apply */ char *name; /* column, constraint, or trigger to act on, * or tablespace */ - Node *newowner; /* RoleSpec */ + RoleSpec *newowner; Node *def; /* definition of new column, index, * constraint, or parent table */ DropBehavior behavior; /* RESTRICT or CASCADE for DROP cases */ @@ -1660,7 +1804,7 @@ typedef struct GrantRoleStmt List *grantee_roles; /* list of member roles to add/delete */ bool is_grant; /* true = GRANT, false = REVOKE */ bool admin_opt; /* with admin option */ - Node *grantor; /* set grantor to other than current role */ + RoleSpec *grantor; /* set grantor to other than current role */ DropBehavior behavior; /* drop behavior (for REVOKE) */ } GrantRoleStmt; @@ -1688,7 +1832,7 @@ typedef struct CopyStmt NodeTag type; RangeVar *relation; /* the relation to copy */ Node *query; /* the query (SELECT or DML statement with - * RETURNING) to copy */ + * RETURNING) to copy, as a raw parse tree */ List *attlist; /* List of column names (as Strings), or NIL * for all columns */ bool is_from; /* TO or FROM */ @@ -1751,6 +1895,8 @@ typedef struct CreateStmt List *tableElts; /* column definitions (list of ColumnDef) */ List *inhRelations; /* relations to inherit from (list of * inhRelation) */ + Node *partbound; /* FOR VALUES clause */ + PartitionSpec *partspec; /* PARTITION BY clause */ TypeName *ofTypename; /* OF typename */ List *constraints; /* constraints (list of Constraint nodes) */ List *options; /* options from WITH clause */ @@ -1873,7 +2019,7 @@ typedef struct CreateTableSpaceStmt { NodeTag type; char *tablespacename; - Node *owner; + RoleSpec *owner; char *location; List *options; } CreateTableSpaceStmt; @@ -1999,7 +2145,7 @@ typedef struct CreateForeignTableStmt typedef struct CreateUserMappingStmt { NodeTag type; - Node *user; /* user role */ + RoleSpec *user; /* user role */ char *servername; /* server name */ List *options; /* generic options to server */ } CreateUserMappingStmt; @@ -2007,7 +2153,7 @@ typedef struct CreateUserMappingStmt typedef struct AlterUserMappingStmt { NodeTag type; - Node *user; /* user role */ + RoleSpec *user; /* user role */ char *servername; /* server name */ List *options; /* generic options to server */ } AlterUserMappingStmt; @@ -2015,7 +2161,7 @@ typedef struct AlterUserMappingStmt typedef struct DropUserMappingStmt { NodeTag type; - Node *user; /* user role */ + RoleSpec *user; /* user role */ char *servername; /* server name */ bool missing_ok; /* ignore missing mappings */ } DropUserMappingStmt; @@ -2053,6 +2199,7 @@ typedef struct CreatePolicyStmt char *policy_name; /* Policy's name */ RangeVar *table; /* the table name the policy applies to */ char *cmd_name; /* the command name the policy applies to */ + bool permissive; /* restrictive or permissive policy */ List *roles; /* the roles associated with the policy */ Node *qual; /* the policy's condition */ Node *with_check; /* the policy's WITH CHECK condition. */ @@ -2103,6 +2250,8 @@ typedef struct CreateTrigStmt List *columns; /* column names, or NIL for all columns */ Node *whenClause; /* qual expression, or NULL if none */ bool isconstraint; /* This is a constraint trigger */ + /* explicitly named transition data */ + List *transitionRels; /* TriggerTransition nodes, or NIL if none */ /* The remaining fields are only used for constraint triggers */ bool deferrable; /* [NOT] DEFERRABLE */ bool initdeferred; /* INITIALLY {DEFERRED|IMMEDIATE} */ @@ -2177,7 +2326,7 @@ typedef struct CreateRoleStmt typedef struct AlterRoleStmt { NodeTag type; - Node *role; /* role */ + RoleSpec *role; /* role */ List *options; /* List of DefElem nodes */ int action; /* +1 = add members, -1 = drop members */ } AlterRoleStmt; @@ -2185,7 +2334,7 @@ typedef struct AlterRoleStmt typedef struct AlterRoleSetStmt { NodeTag type; - Node *role; /* role */ + RoleSpec *role; /* role */ char *database; /* database name, or NULL */ VariableSetStmt *setstmt; /* SET or RESET subcommand */ } AlterRoleSetStmt; @@ -2361,9 +2510,9 @@ typedef struct SecLabelStmt /* ---------------------- * Declare Cursor Statement * - * Note: the "query" field of DeclareCursorStmt is only used in the raw grammar - * output. After parse analysis it's set to null, and the Query points to the - * DeclareCursorStmt, not vice versa. + * The "query" field is initially a raw parse tree, and is converted to a + * Query node during parse analysis. Note that rewriting and planning + * of the query are always postponed until execution. * ---------------------- */ #define CURSOR_OPT_BINARY 0x0001 /* BINARY */ @@ -2382,7 +2531,7 @@ typedef struct DeclareCursorStmt NodeTag type; char *portalname; /* name of the portal (cursor) */ int options; /* bitmask of options (see above) */ - Node *query; /* the raw SELECT query */ + Node *query; /* the query (see comments above) */ } DeclareCursorStmt; /* ---------------------- @@ -2576,7 +2725,7 @@ typedef struct AlterOwnerStmt RangeVar *relation; /* in case it's a table */ List *object; /* in case it's some other object */ List *objarg; /* argument types, if applicable */ - Node *newowner; /* the new owner */ + RoleSpec *newowner; /* the new owner */ } AlterOwnerStmt; @@ -2707,10 +2856,11 @@ typedef struct AlterEnumStmt { NodeTag type; List *typeName; /* qualified name (list of Value strings) */ + char *oldVal; /* old enum value's name, if renaming */ char *newVal; /* new enum value's name */ char *newValNeighbor; /* neighboring enum value, if specified */ bool newValIsAfter; /* place new enum value after neighbor? */ - bool skipIfExists; /* no error if label already exists */ + bool skipIfNewValExists; /* no error if new already exists? */ } AlterEnumStmt; /* ---------------------- @@ -2729,7 +2879,7 @@ typedef struct ViewStmt NodeTag type; RangeVar *view; /* the view to be created */ List *aliases; /* target column names */ - Node *query; /* the SELECT query */ + Node *query; /* the SELECT query (as a raw parse tree) */ bool replace; /* replace an existing view? */ List *options; /* options from WITH clause */ ViewCheckOption withCheckOption; /* WITH CHECK OPTION */ @@ -2838,9 +2988,9 @@ typedef struct VacuumStmt /* ---------------------- * Explain Statement * - * The "query" field is either a raw parse tree (SelectStmt, InsertStmt, etc) - * or a Query node if parse analysis has been done. Note that rewriting and - * planning of the query are always postponed until execution of EXPLAIN. + * The "query" field is initially a raw parse tree, and is converted to a + * Query node during parse analysis. Note that rewriting and planning + * of the query are always postponed until execution. * ---------------------- */ typedef struct ExplainStmt @@ -3059,7 +3209,7 @@ typedef struct ReassignOwnedStmt { NodeTag type; List *roles; - Node *newrole; + RoleSpec *newrole; } ReassignOwnedStmt; /* @@ -3101,4 +3251,52 @@ typedef struct AlterTSConfigurationStmt bool missing_ok; /* for DROP - skip error if missing? */ } AlterTSConfigurationStmt; + +typedef struct CreatePublicationStmt +{ + NodeTag type; + char *pubname; /* Name of of the publication */ + List *options; /* List of DefElem nodes */ + List *tables; /* Optional list of tables to add */ + bool for_all_tables; /* Special publication for all tables in db */ +} CreatePublicationStmt; + +typedef struct AlterPublicationStmt +{ + NodeTag type; + char *pubname; /* Name of of the publication */ + + /* parameters used for ALTER PUBLICATION ... WITH */ + List *options; /* List of DefElem nodes */ + + /* parameters used for ALTER PUBLICATION ... ADD/DROP TABLE */ + List *tables; /* List of tables to add/drop */ + bool for_all_tables; /* Special publication for all tables in db */ + DefElemAction tableAction; /* What action to perform with the tables */ +} AlterPublicationStmt; + +typedef struct CreateSubscriptionStmt +{ + NodeTag type; + char *subname; /* Name of of the subscription */ + char *conninfo; /* Connection string to publisher */ + List *publication; /* One or more publication to subscribe to */ + List *options; /* List of DefElem nodes */ +} CreateSubscriptionStmt; + +typedef struct AlterSubscriptionStmt +{ + NodeTag type; + char *subname; /* Name of of the subscription */ + List *options; /* List of DefElem nodes */ +} AlterSubscriptionStmt; + +typedef struct DropSubscriptionStmt +{ + NodeTag type; + char *subname; /* Name of of the subscription */ + bool drop_slot; /* Should we drop the slot on remote side? */ + bool missing_ok; /* Skip error if missing? */ +} DropSubscriptionStmt; + #endif /* PARSENODES_H */ diff --git a/src/include/nodes/pg_list.h b/src/include/nodes/pg_list.h index 77b50ff1c7..90e84bcb60 100644 --- a/src/include/nodes/pg_list.h +++ b/src/include/nodes/pg_list.h @@ -27,7 +27,7 @@ * always be so; try to be careful to maintain the distinction.) * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/pg_list.h diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 369179f291..f72f7a8978 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -4,7 +4,7 @@ * definitions for query plan nodes * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/plannodes.h @@ -31,13 +31,18 @@ * * The output of the planner is a Plan tree headed by a PlannedStmt node. * PlannedStmt holds the "one time" information needed by the executor. + * + * For simplicity in APIs, we also wrap utility statements in PlannedStmt + * nodes; in such cases, commandType == CMD_UTILITY, the statement itself + * is in the utilityStmt field, and the rest of the struct is mostly dummy. + * (We do use canSetTag, stmt_location, stmt_len, and possibly queryId.) * ---------------- */ typedef struct PlannedStmt { NodeTag type; - CmdType commandType; /* select|insert|update|delete */ + CmdType commandType; /* select|insert|update|delete|utility */ uint32 queryId; /* query identifier (copied from Query) */ @@ -60,8 +65,6 @@ typedef struct PlannedStmt /* rtable indexes of target relations for INSERT/UPDATE/DELETE */ List *resultRelations; /* integer list of RT indexes, or NIL */ - Node *utilityStmt; /* non-null if this is DECLARE CURSOR */ - List *subplans; /* Plan trees for SubPlan expressions */ Bitmapset *rewindPlanIDs; /* indices of subplans that require REWIND */ @@ -73,6 +76,12 @@ typedef struct PlannedStmt List *invalItems; /* other dependencies, as PlanInvalItems */ int nParamExec; /* number of PARAM_EXEC Params used */ + + Node *utilityStmt; /* non-null if this is utility stmt */ + + /* statement location in source string (copied from Query) */ + int stmt_location; /* start location, or -1 if unknown */ + int stmt_len; /* length in bytes; 0 means "rest of string" */ } PlannedStmt; /* macro for fetching the Plan associated with a SubPlan node */ @@ -167,6 +176,17 @@ typedef struct Result Node *resconstantqual; } Result; +/* ---------------- + * ProjectSet node - + * Apply a projection that includes set-returning functions to the + * output tuples of the outer plan. + * ---------------- + */ +typedef struct ProjectSet +{ + Plan plan; +} ProjectSet; + /* ---------------- * ModifyTable node - * Apply rows produced by subplan(s) to result table(s), @@ -560,7 +580,8 @@ struct CustomScanMethods; typedef struct CustomScan { Scan scan; - uint32 flags; /* mask of CUSTOMPATH_* flags, see relation.h */ + uint32 flags; /* mask of CUSTOMPATH_* flags, see + * nodes/extensible.h */ List *custom_plans; /* list of Plan nodes, if any */ List *custom_exprs; /* expressions that custom code may evaluate */ List *custom_private; /* private data for custom code */ @@ -715,7 +736,8 @@ typedef struct Agg AttrNumber *grpColIdx; /* their indexes in the target list */ Oid *grpOperators; /* equality operators to compare with */ long numGroups; /* estimated number of groups in input */ - /* Note: the planner only provides numGroups in AGG_HASHED case */ + Bitmapset *aggParams; /* IDs of Params used in Aggref inputs */ + /* Note: planner provides numGroups & aggParams only in AGG_HASHED case */ List *groupingSets; /* grouping sets to use */ List *chain; /* chained Agg/Sort nodes */ } Agg; diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index df2d27d77c..f72ec247ff 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -7,7 +7,7 @@ * and join trees. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/primnodes.h @@ -42,13 +42,6 @@ typedef struct Alias List *colnames; /* optional list of column aliases */ } Alias; -typedef enum InhOption -{ - INH_NO, /* Do NOT scan child tables */ - INH_YES, /* DO scan child tables */ - INH_DEFAULT /* Use current SQL_inheritance option */ -} InhOption; - /* What to do at commit time for temporary relations */ typedef enum OnCommitAction { @@ -62,7 +55,7 @@ typedef enum OnCommitAction * RangeVar - range variable, used in FROM clauses * * Also used to represent table names in utility statements; there, the alias - * field is not used, and inhOpt shows whether to apply the operation + * field is not used, and inh tells whether to apply the operation * recursively to child tables. In some contexts it is also useful to carry * a TEMP table indication here. */ @@ -72,7 +65,7 @@ typedef struct RangeVar char *catalogname; /* the catalog (database) name, or NULL */ char *schemaname; /* the schema name, or NULL */ char *relname; /* the relation/sequence name */ - InhOption inhOpt; /* expand rel by inheritance? recursively act + bool inh; /* expand rel by inheritance? recursively act * on children? */ char relpersistence; /* see RELPERSISTENCE_* in pg_class.h */ Alias *alias; /* table alias & optional column aliases */ @@ -1050,6 +1043,45 @@ typedef struct MinMaxExpr int location; /* token location, or -1 if unknown */ } MinMaxExpr; +/* + * SQLValueFunction - parameterless functions with special grammar productions + * + * The SQL standard categorizes some of these as + * and others as . We call 'em SQLValueFunctions + * for lack of a better term. We store type and typmod of the result so that + * some code doesn't need to know each function individually, and because + * we would need to store typmod anyway for some of the datetime functions. + * Note that currently, all variants return non-collating datatypes, so we do + * not need a collation field; also, all these functions are stable. + */ +typedef enum SQLValueFunctionOp +{ + SVFOP_CURRENT_DATE, + SVFOP_CURRENT_TIME, + SVFOP_CURRENT_TIME_N, + SVFOP_CURRENT_TIMESTAMP, + SVFOP_CURRENT_TIMESTAMP_N, + SVFOP_LOCALTIME, + SVFOP_LOCALTIME_N, + SVFOP_LOCALTIMESTAMP, + SVFOP_LOCALTIMESTAMP_N, + SVFOP_CURRENT_ROLE, + SVFOP_CURRENT_USER, + SVFOP_USER, + SVFOP_SESSION_USER, + SVFOP_CURRENT_CATALOG, + SVFOP_CURRENT_SCHEMA +} SQLValueFunctionOp; + +typedef struct SQLValueFunction +{ + Expr xpr; + SQLValueFunctionOp op; /* which function this is */ + Oid type; /* result type/typmod */ + int32 typmod; + int location; /* token location, or -1 if unknown */ +} SQLValueFunction; + /* * XmlExpr - various SQL/XML functions requiring special grammar productions * diff --git a/src/include/nodes/print.h b/src/include/nodes/print.h index 431d72d6f6..4c94a3afe5 100644 --- a/src/include/nodes/print.h +++ b/src/include/nodes/print.h @@ -4,7 +4,7 @@ * definitions for nodes/print.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/print.h diff --git a/src/include/nodes/readfuncs.h b/src/include/nodes/readfuncs.h index 1b38da112b..ca540baf02 100644 --- a/src/include/nodes/readfuncs.h +++ b/src/include/nodes/readfuncs.h @@ -4,7 +4,7 @@ * header file for read.c and readfuncs.c. These functions are internal * to the stringToNode interface and should not be used by anyone else. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/readfuncs.h diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 2be8908445..643be54d40 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -4,7 +4,7 @@ * Definitions for planner's internal data structures. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/relation.h @@ -126,6 +126,8 @@ typedef struct PlannerGlobal bool parallelModeOK; /* parallel mode potentially OK? */ bool parallelModeNeeded; /* parallel mode actually required? */ + + char maxParallelHazard; /* worst PROPARALLEL hazard level */ } PlannerGlobal; /* macro for fetching the Plan associated with a SubPlan node */ @@ -284,6 +286,9 @@ typedef struct PlannerInfo double tuple_fraction; /* tuple_fraction passed to query_planner */ double limit_tuples; /* limit_tuples passed to query_planner */ + Index qual_security_level; /* minimum security_level for quals */ + /* Note: qual_security_level is zero if there are no securityQuals */ + bool hasInheritedTarget; /* true if parse->resultRelation is an * inheritance child rel */ bool hasJoinRTEs; /* true if any RTEs are RTE_JOIN kind */ @@ -441,6 +446,8 @@ typedef struct PlannerInfo * participates (only used for base rels) * baserestrictcost - Estimated cost of evaluating the baserestrictinfo * clauses at a single tuple (only used for base rels) + * baserestrict_min_security - Smallest security_level found among + * clauses in baserestrictinfo * joininfo - List of RestrictInfo nodes, containing info about each * join clause in which this relation participates (but * note this excludes clauses that might be derivable from @@ -537,6 +544,8 @@ typedef struct RelOptInfo List *baserestrictinfo; /* RestrictInfo structures (if base * rel) */ QualCost baserestrictcost; /* cost of evaluating the above */ + Index baserestrict_min_security; /* min security_level found in + * baserestrictinfo */ List *joininfo; /* RestrictInfo structures for join clauses * involving this rel */ bool has_eclass_joins; /* T means joininfo is incomplete */ @@ -711,6 +720,8 @@ typedef struct EquivalenceClass bool ec_below_outer_join; /* equivalence applies below an OJ */ bool ec_broken; /* failed to generate needed clauses? */ Index ec_sortref; /* originating sortclause label, or 0 */ + Index ec_min_security; /* minimum security_level in ec_sources */ + Index ec_max_security; /* maximum security_level in ec_sources */ struct EquivalenceClass *ec_merged; /* set if merged into another EC */ } EquivalenceClass; @@ -1085,7 +1096,8 @@ struct CustomPathMethods; typedef struct CustomPath { Path path; - uint32 flags; /* mask of CUSTOMPATH_* flags, see above */ + uint32 flags; /* mask of CUSTOMPATH_* flags, see + * nodes/extensible.h */ List *custom_paths; /* list of child Path nodes, if any */ List *custom_private; const struct CustomPathMethods *methods; @@ -1187,7 +1199,7 @@ typedef struct GatherPath { Path path; Path *subpath; /* path for each worker */ - bool single_copy; /* path must not be executed >1x */ + bool single_copy; /* don't execute path more than once */ } GatherPath; /* @@ -1292,6 +1304,17 @@ typedef struct ProjectionPath bool dummypp; /* true if no separate Result is needed */ } ProjectionPath; +/* + * ProjectSetPath represents evaluation of a targetlist that includes + * set-returning function(s), which will need to be implemented by a + * ProjectSet plan node. + */ +typedef struct ProjectSetPath +{ + Path path; + Path *subpath; /* path representing input source */ +} ProjectSetPath; + /* * SortPath represents an explicit sort step * @@ -1557,6 +1580,15 @@ typedef struct LimitPath * outer join(s). A clause that is not outerjoin_delayed can be enforced * anywhere it is computable. * + * To handle security-barrier conditions efficiently, we mark RestrictInfo + * nodes with a security_level field, in which higher values identify clauses + * coming from less-trusted sources. The exact semantics are that a clause + * cannot be evaluated before another clause with a lower security_level value + * unless the first clause is leakproof. As with outer-join clauses, this + * creates a reason for clauses to sometimes need to be evaluated higher in + * the join tree than their contents would suggest; and even at a single plan + * node, this rule constrains the order of application of clauses. + * * In general, the referenced clause might be arbitrarily complex. The * kinds of clauses we can handle as indexscan quals, mergejoin clauses, * or hashjoin clauses are limited (e.g., no volatile functions). The code @@ -1611,6 +1643,10 @@ typedef struct RestrictInfo bool pseudoconstant; /* see comment above */ + bool leakproof; /* TRUE if known to contain no leaked Vars */ + + Index security_level; /* see comment above */ + /* The set of relids (varnos) actually referenced in the clause: */ Relids clause_relids; diff --git a/src/include/nodes/replnodes.h b/src/include/nodes/replnodes.h index d2f1edbf0d..f27354faaf 100644 --- a/src/include/nodes/replnodes.h +++ b/src/include/nodes/replnodes.h @@ -4,7 +4,7 @@ * definitions for replication grammar parse nodes * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/replnodes.h @@ -55,6 +55,7 @@ typedef struct CreateReplicationSlotCmd char *slotname; ReplicationKind kind; char *plugin; + bool temporary; bool reserve_wal; } CreateReplicationSlotCmd; diff --git a/src/include/nodes/tidbitmap.h b/src/include/nodes/tidbitmap.h index 930329988d..14992e09f8 100644 --- a/src/include/nodes/tidbitmap.h +++ b/src/include/nodes/tidbitmap.h @@ -13,7 +13,7 @@ * fact that a particular page needs to be visited. * * - * Copyright (c) 2003-2016, PostgreSQL Global Development Group + * Copyright (c) 2003-2017, PostgreSQL Global Development Group * * src/include/nodes/tidbitmap.h * diff --git a/src/include/nodes/value.h b/src/include/nodes/value.h index 31ede000c1..ede97b7bcd 100644 --- a/src/include/nodes/value.h +++ b/src/include/nodes/value.h @@ -4,7 +4,7 @@ * interface for Value nodes * * - * Copyright (c) 2003-2016, PostgreSQL Global Development Group + * Copyright (c) 2003-2017, PostgreSQL Global Development Group * * src/include/nodes/value.h * diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h index be7c639f7b..cc0d7b0a26 100644 --- a/src/include/optimizer/clauses.h +++ b/src/include/optimizer/clauses.h @@ -4,7 +4,7 @@ * prototypes for clauses.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/clauses.h @@ -54,14 +54,14 @@ extern bool contain_window_function(Node *clause); extern WindowFuncLists *find_window_functions(Node *clause, Index maxWinRef); extern double expression_returns_set_rows(Node *clause); -extern double tlist_returns_set_rows(List *tlist); extern bool contain_subplans(Node *clause); extern bool contain_mutable_functions(Node *clause); extern bool contain_volatile_functions(Node *clause); extern bool contain_volatile_functions_not_nextval(Node *clause); -extern bool has_parallel_hazard(Node *node, bool allow_restricted); +extern char max_parallel_hazard(Query *parse); +extern bool is_parallel_safe(PlannerInfo *root, Node *node); extern bool contain_nonstrict_functions(Node *clause); extern bool contain_leaked_vars(Node *clause); diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h index 2a4df2fc16..39376ec10c 100644 --- a/src/include/optimizer/cost.h +++ b/src/include/optimizer/cost.h @@ -4,7 +4,7 @@ * prototypes for costsize.c and clausesel.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/cost.h diff --git a/src/include/optimizer/geqo.h b/src/include/optimizer/geqo.h index 094d572fa4..6b09c4e195 100644 --- a/src/include/optimizer/geqo.h +++ b/src/include/optimizer/geqo.h @@ -3,7 +3,7 @@ * geqo.h * prototypes for various files in optimizer/geqo * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/geqo.h diff --git a/src/include/optimizer/geqo_copy.h b/src/include/optimizer/geqo_copy.h index 0892e7993e..3cbaf3e4ca 100644 --- a/src/include/optimizer/geqo_copy.h +++ b/src/include/optimizer/geqo_copy.h @@ -3,7 +3,7 @@ * geqo_copy.h * prototypes for copy functions in optimizer/geqo * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/geqo_copy.h diff --git a/src/include/optimizer/geqo_gene.h b/src/include/optimizer/geqo_gene.h index f4e5d5064a..f936ebdd89 100644 --- a/src/include/optimizer/geqo_gene.h +++ b/src/include/optimizer/geqo_gene.h @@ -3,7 +3,7 @@ * geqo_gene.h * genome representation in optimizer/geqo * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/geqo_gene.h diff --git a/src/include/optimizer/geqo_misc.h b/src/include/optimizer/geqo_misc.h index 7b0a052ad5..880bd0e140 100644 --- a/src/include/optimizer/geqo_misc.h +++ b/src/include/optimizer/geqo_misc.h @@ -3,7 +3,7 @@ * geqo_misc.h * prototypes for printout routines in optimizer/geqo * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/geqo_misc.h diff --git a/src/include/optimizer/geqo_mutation.h b/src/include/optimizer/geqo_mutation.h index 940d05a3ce..85781c3c31 100644 --- a/src/include/optimizer/geqo_mutation.h +++ b/src/include/optimizer/geqo_mutation.h @@ -3,7 +3,7 @@ * geqo_mutation.h * prototypes for mutation functions in optimizer/geqo * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/geqo_mutation.h diff --git a/src/include/optimizer/geqo_pool.h b/src/include/optimizer/geqo_pool.h index 798d72c858..7947b6e5bb 100644 --- a/src/include/optimizer/geqo_pool.h +++ b/src/include/optimizer/geqo_pool.h @@ -3,7 +3,7 @@ * geqo_pool.h * pool representation in optimizer/geqo * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/geqo_pool.h diff --git a/src/include/optimizer/geqo_random.h b/src/include/optimizer/geqo_random.h index 782ac6d026..5312589387 100644 --- a/src/include/optimizer/geqo_random.h +++ b/src/include/optimizer/geqo_random.h @@ -3,7 +3,7 @@ * geqo_random.h * random number generator * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/geqo_random.h diff --git a/src/include/optimizer/geqo_recombination.h b/src/include/optimizer/geqo_recombination.h index 0906833334..8ddde22296 100644 --- a/src/include/optimizer/geqo_recombination.h +++ b/src/include/optimizer/geqo_recombination.h @@ -3,7 +3,7 @@ * geqo_recombination.h * prototypes for recombination in the genetic query optimizer * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/geqo_recombination.h diff --git a/src/include/optimizer/geqo_selection.h b/src/include/optimizer/geqo_selection.h index c02d5c2918..1aecf14ac1 100644 --- a/src/include/optimizer/geqo_selection.h +++ b/src/include/optimizer/geqo_selection.h @@ -3,7 +3,7 @@ * geqo_selection.h * prototypes for selection routines in optimizer/geqo * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/geqo_selection.h diff --git a/src/include/optimizer/joininfo.h b/src/include/optimizer/joininfo.h index 9261f065a2..c9a8b53f1f 100644 --- a/src/include/optimizer/joininfo.h +++ b/src/include/optimizer/joininfo.h @@ -4,7 +4,7 @@ * prototypes for joininfo.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/joininfo.h diff --git a/src/include/optimizer/orclauses.h b/src/include/optimizer/orclauses.h index f1c7a0bff4..2512ddee8f 100644 --- a/src/include/optimizer/orclauses.h +++ b/src/include/optimizer/orclauses.h @@ -4,7 +4,7 @@ * prototypes for orclauses.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/orclauses.h diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h index 71d9154a5c..7b41317621 100644 --- a/src/include/optimizer/pathnode.h +++ b/src/include/optimizer/pathnode.h @@ -4,7 +4,7 @@ * prototypes for pathnode.c, relnode.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/pathnode.h @@ -144,6 +144,10 @@ extern Path *apply_projection_to_path(PlannerInfo *root, RelOptInfo *rel, Path *path, PathTarget *target); +extern ProjectSetPath *create_set_projection_path(PlannerInfo *root, + RelOptInfo *rel, + Path *subpath, + PathTarget *target); extern SortPath *create_sort_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h index 44abe8336a..81a9be7c67 100644 --- a/src/include/optimizer/paths.h +++ b/src/include/optimizer/paths.h @@ -4,7 +4,7 @@ * prototypes for various files in optimizer/path * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/paths.h @@ -66,6 +66,8 @@ extern void create_index_paths(PlannerInfo *root, RelOptInfo *rel); extern bool relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel, List *restrictlist, List *exprlist, List *oprlist); +extern bool indexcol_is_bool_constant_for_query(IndexOptInfo *index, + int indexcol); extern bool match_index_to_operand(Node *operand, int indexcol, IndexOptInfo *index); extern void expand_indexqual_conditions(IndexOptInfo *index, diff --git a/src/include/optimizer/placeholder.h b/src/include/optimizer/placeholder.h index 54d0216ef8..11e6403aa3 100644 --- a/src/include/optimizer/placeholder.h +++ b/src/include/optimizer/placeholder.h @@ -4,7 +4,7 @@ * prototypes for optimizer/util/placeholder.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/placeholder.h diff --git a/src/include/optimizer/plancat.h b/src/include/optimizer/plancat.h index 125274e490..68fd713b09 100644 --- a/src/include/optimizer/plancat.h +++ b/src/include/optimizer/plancat.h @@ -4,7 +4,7 @@ * prototypes for plancat.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/plancat.h diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h index 4fbb6cc3e7..94ef84bca9 100644 --- a/src/include/optimizer/planmain.h +++ b/src/include/optimizer/planmain.h @@ -4,7 +4,7 @@ * prototypes for various files in optimizer/plan * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/planmain.h @@ -87,6 +87,7 @@ extern void process_implied_equality(PlannerInfo *root, Expr *item2, Relids qualscope, Relids nullable_relids, + Index security_level, bool below_outer_join, bool both_const); extern RestrictInfo *build_implied_join_equality(Oid opno, @@ -94,7 +95,8 @@ extern RestrictInfo *build_implied_join_equality(Oid opno, Expr *item1, Expr *item2, Relids qualscope, - Relids nullable_relids); + Relids nullable_relids, + Index security_level); extern void match_foreign_keys_to_quals(PlannerInfo *root); /* diff --git a/src/include/optimizer/planner.h b/src/include/optimizer/planner.h index d9790d7a97..6922933e36 100644 --- a/src/include/optimizer/planner.h +++ b/src/include/optimizer/planner.h @@ -4,7 +4,7 @@ * prototypes for planner.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/planner.h diff --git a/src/include/optimizer/predtest.h b/src/include/optimizer/predtest.h index f0a1c12c14..658a86cc15 100644 --- a/src/include/optimizer/predtest.h +++ b/src/include/optimizer/predtest.h @@ -4,7 +4,7 @@ * prototypes for predtest.c * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/predtest.h diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h index fb35b689bb..2b20b36f74 100644 --- a/src/include/optimizer/prep.h +++ b/src/include/optimizer/prep.h @@ -4,7 +4,7 @@ * prototypes for files in optimizer/prep/ * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/prep.h @@ -35,11 +35,6 @@ extern Relids get_relids_for_join(PlannerInfo *root, int joinrelid); extern Node *negate_clause(Node *node); extern Expr *canonicalize_qual(Expr *qual); -/* - * prototypes for prepsecurity.c - */ -extern void expand_security_quals(PlannerInfo *root, List *tlist); - /* * prototypes for preptlist.c */ diff --git a/src/include/optimizer/restrictinfo.h b/src/include/optimizer/restrictinfo.h index fa8a5b145b..31b9a79285 100644 --- a/src/include/optimizer/restrictinfo.h +++ b/src/include/optimizer/restrictinfo.h @@ -4,7 +4,7 @@ * prototypes for restrictinfo.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/restrictinfo.h @@ -19,20 +19,20 @@ /* Convenience macro for the common case of a valid-everywhere qual */ #define make_simple_restrictinfo(clause) \ - make_restrictinfo(clause, true, false, false, NULL, NULL, NULL) + make_restrictinfo(clause, true, false, false, 0, NULL, NULL, NULL) extern RestrictInfo *make_restrictinfo(Expr *clause, bool is_pushed_down, bool outerjoin_delayed, bool pseudoconstant, + Index security_level, Relids required_relids, Relids outer_relids, Relids nullable_relids); -extern List *make_restrictinfos_from_actual_clauses(PlannerInfo *root, - List *clause_list); extern bool restriction_is_or_clause(RestrictInfo *restrictinfo); +extern bool restriction_is_securely_promotable(RestrictInfo *restrictinfo, + RelOptInfo *rel); extern List *get_actual_clauses(List *restrictinfo_list); -extern List *get_all_actual_clauses(List *restrictinfo_list); extern List *extract_actual_clauses(List *restrictinfo_list, bool pseudoconstant); extern void extract_actual_join_clauses(List *restrictinfo_list, diff --git a/src/include/optimizer/subselect.h b/src/include/optimizer/subselect.h index f100d02940..56dc237b51 100644 --- a/src/include/optimizer/subselect.h +++ b/src/include/optimizer/subselect.h @@ -2,7 +2,7 @@ * * subselect.h * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/subselect.h diff --git a/src/include/optimizer/tlist.h b/src/include/optimizer/tlist.h index 0d745a0891..976024a164 100644 --- a/src/include/optimizer/tlist.h +++ b/src/include/optimizer/tlist.h @@ -4,7 +4,7 @@ * prototypes for tlist.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/tlist.h @@ -61,6 +61,9 @@ extern void add_column_to_pathtarget(PathTarget *target, extern void add_new_column_to_pathtarget(PathTarget *target, Expr *expr); extern void add_new_columns_to_pathtarget(PathTarget *target, List *exprs); extern void apply_pathtarget_labeling_to_tlist(List *tlist, PathTarget *target); +extern void split_pathtarget_at_srfs(PlannerInfo *root, + PathTarget *target, PathTarget *input_target, + List **targets, List **targets_contain_srfs); /* Convenience macro to get a PathTarget with valid cost/width fields */ #define create_pathtarget(root, tlist) \ diff --git a/src/include/optimizer/var.h b/src/include/optimizer/var.h index 463e75b828..ae1f856933 100644 --- a/src/include/optimizer/var.h +++ b/src/include/optimizer/var.h @@ -4,7 +4,7 @@ * prototypes for optimizer/util/var.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/var.h diff --git a/src/include/parser/analyze.h b/src/include/parser/analyze.h index 5ba322a262..a7e5c55ab4 100644 --- a/src/include/parser/analyze.h +++ b/src/include/parser/analyze.h @@ -4,7 +4,7 @@ * parse analysis for optimizable statements * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/analyze.h @@ -22,19 +22,19 @@ typedef void (*post_parse_analyze_hook_type) (ParseState *pstate, extern PGDLLIMPORT post_parse_analyze_hook_type post_parse_analyze_hook; -extern Query *parse_analyze(Node *parseTree, const char *sourceText, +extern Query *parse_analyze(RawStmt *parseTree, const char *sourceText, Oid *paramTypes, int numParams); -extern Query *parse_analyze_varparams(Node *parseTree, const char *sourceText, +extern Query *parse_analyze_varparams(RawStmt *parseTree, const char *sourceText, Oid **paramTypes, int *numParams); extern Query *parse_sub_analyze(Node *parseTree, ParseState *parentParseState, CommonTableExpr *parentCTE, bool locked_from_parent); -extern Query *transformTopLevelStmt(ParseState *pstate, Node *parseTree); +extern Query *transformTopLevelStmt(ParseState *pstate, RawStmt *parseTree); extern Query *transformStmt(ParseState *pstate, Node *parseTree); -extern bool analyze_requires_snapshot(Node *parseTree); +extern bool analyze_requires_snapshot(RawStmt *parseTree); extern const char *LCS_asString(LockClauseStrength strength); extern void CheckSelectLocking(Query *qry, LockClauseStrength strength); diff --git a/src/include/parser/gramparse.h b/src/include/parser/gramparse.h index 6d8e4937ee..2da98f67f3 100644 --- a/src/include/parser/gramparse.h +++ b/src/include/parser/gramparse.h @@ -8,7 +8,7 @@ * Definitions that are needed outside the core parser should be in parser.h. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/gramparse.h diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index 17ffef53a7..985d6505ec 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -7,7 +7,7 @@ * 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-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -49,6 +49,7 @@ PG_KEYWORD("assertion", ASSERTION, UNRESERVED_KEYWORD) PG_KEYWORD("assignment", ASSIGNMENT, UNRESERVED_KEYWORD) PG_KEYWORD("asymmetric", ASYMMETRIC, RESERVED_KEYWORD) PG_KEYWORD("at", AT, UNRESERVED_KEYWORD) +PG_KEYWORD("attach", ATTACH, UNRESERVED_KEYWORD) PG_KEYWORD("attribute", ATTRIBUTE, UNRESERVED_KEYWORD) PG_KEYWORD("authorization", AUTHORIZATION, TYPE_FUNC_NAME_KEYWORD) PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD) @@ -127,6 +128,7 @@ PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD) PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD) PG_KEYWORD("depends", DEPENDS, UNRESERVED_KEYWORD) PG_KEYWORD("desc", DESC, RESERVED_KEYWORD) +PG_KEYWORD("detach", DETACH, UNRESERVED_KEYWORD) PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD) PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD) PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD) @@ -251,6 +253,7 @@ PG_KEYWORD("names", NAMES, UNRESERVED_KEYWORD) PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD) PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD) PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD) +PG_KEYWORD("new", NEW, UNRESERVED_KEYWORD) PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD) PG_KEYWORD("no", NO, UNRESERVED_KEYWORD) PG_KEYWORD("none", NONE, COL_NAME_KEYWORD) @@ -268,6 +271,7 @@ PG_KEYWORD("of", OF, UNRESERVED_KEYWORD) PG_KEYWORD("off", OFF, UNRESERVED_KEYWORD) PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD) PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD) +PG_KEYWORD("old", OLD, UNRESERVED_KEYWORD) PG_KEYWORD("on", ON, RESERVED_KEYWORD) PG_KEYWORD("only", ONLY, RESERVED_KEYWORD) PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD) @@ -304,6 +308,7 @@ PG_KEYWORD("privileges", PRIVILEGES, UNRESERVED_KEYWORD) PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD) PG_KEYWORD("procedure", PROCEDURE, UNRESERVED_KEYWORD) PG_KEYWORD("program", PROGRAM, UNRESERVED_KEYWORD) +PG_KEYWORD("publication", PUBLICATION, UNRESERVED_KEYWORD) PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD) PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD) PG_KEYWORD("read", READ, UNRESERVED_KEYWORD) @@ -313,6 +318,7 @@ PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD) PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD) PG_KEYWORD("ref", REF, UNRESERVED_KEYWORD) PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD) +PG_KEYWORD("referencing", REFERENCING, UNRESERVED_KEYWORD) PG_KEYWORD("refresh", REFRESH, UNRESERVED_KEYWORD) PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD) PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD) @@ -355,6 +361,7 @@ PG_KEYWORD("show", SHOW, UNRESERVED_KEYWORD) PG_KEYWORD("similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD) PG_KEYWORD("simple", SIMPLE, UNRESERVED_KEYWORD) PG_KEYWORD("skip", SKIP, UNRESERVED_KEYWORD) +PG_KEYWORD("slot", SLOT, UNRESERVED_KEYWORD) PG_KEYWORD("smallint", SMALLINT, COL_NAME_KEYWORD) PG_KEYWORD("snapshot", SNAPSHOT, UNRESERVED_KEYWORD) PG_KEYWORD("some", SOME, RESERVED_KEYWORD) @@ -369,6 +376,7 @@ PG_KEYWORD("stdout", STDOUT, UNRESERVED_KEYWORD) PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD) PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD) PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD) +PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD) PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD) PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD) PG_KEYWORD("sysid", SYSID, UNRESERVED_KEYWORD) diff --git a/src/include/parser/parse_agg.h b/src/include/parser/parse_agg.h index 28fc354a42..8a54d59d6f 100644 --- a/src/include/parser/parse_agg.h +++ b/src/include/parser/parse_agg.h @@ -3,7 +3,7 @@ * parse_agg.h * handle aggregates and window functions in parser * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_agg.h diff --git a/src/include/parser/parse_clause.h b/src/include/parser/parse_clause.h index d04ce1125c..3cdb261343 100644 --- a/src/include/parser/parse_clause.h +++ b/src/include/parser/parse_clause.h @@ -4,7 +4,7 @@ * handle clauses in parser * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_clause.h @@ -19,7 +19,6 @@ extern void transformFromClause(ParseState *pstate, List *frmList); extern int setTargetTable(ParseState *pstate, RangeVar *relation, bool inh, bool alsoSource, AclMode requiredPerms); -extern bool interpretInhOption(InhOption inhOpt); extern bool interpretOidsOption(List *defList, bool allowOids); extern Node *transformWhereClause(ParseState *pstate, Node *clause, diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h index 66519e67a2..b50992cfd9 100644 --- a/src/include/parser/parse_coerce.h +++ b/src/include/parser/parse_coerce.h @@ -4,7 +4,7 @@ * Routines for type coercion. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_coerce.h diff --git a/src/include/parser/parse_collate.h b/src/include/parser/parse_collate.h index d1b599777b..e42971dfde 100644 --- a/src/include/parser/parse_collate.h +++ b/src/include/parser/parse_collate.h @@ -4,7 +4,7 @@ * Routines for assigning collation information. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_collate.h diff --git a/src/include/parser/parse_cte.h b/src/include/parser/parse_cte.h index 11a16ffa1c..9130612312 100644 --- a/src/include/parser/parse_cte.h +++ b/src/include/parser/parse_cte.h @@ -4,7 +4,7 @@ * handle CTEs (common table expressions) in parser * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_cte.h diff --git a/src/include/parser/parse_expr.h b/src/include/parser/parse_expr.h index 539b6058e2..2101eaefda 100644 --- a/src/include/parser/parse_expr.h +++ b/src/include/parser/parse_expr.h @@ -3,7 +3,7 @@ * parse_expr.h * handle expressions in parser * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_expr.h diff --git a/src/include/parser/parse_func.h b/src/include/parser/parse_func.h index 0cefdf1b60..1c914065c0 100644 --- a/src/include/parser/parse_func.h +++ b/src/include/parser/parse_func.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_func.h @@ -67,4 +67,6 @@ extern Oid LookupFuncNameTypeNames(List *funcname, List *argtypes, extern Oid LookupAggNameTypeNames(List *aggname, List *argtypes, bool noError); +extern void check_srf_call_placement(ParseState *pstate, int location); + #endif /* PARSE_FUNC_H */ diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h index e3e359c021..bc3eea9ba5 100644 --- a/src/include/parser/parse_node.h +++ b/src/include/parser/parse_node.h @@ -4,7 +4,7 @@ * Internal definitions for parser * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_node.h @@ -27,7 +27,7 @@ * by extension code that might need to call transformExpr(). The core code * will not enforce any context-driven restrictions on EXPR_KIND_OTHER * expressions, so the caller would have to check for sub-selects, aggregates, - * and window functions if those need to be disallowed. + * window functions, SRFs, etc if those need to be disallowed. */ typedef enum ParseExprKind { @@ -55,6 +55,7 @@ typedef enum ParseExprKind EXPR_KIND_OFFSET, /* OFFSET */ EXPR_KIND_RETURNING, /* RETURNING */ EXPR_KIND_VALUES, /* VALUES */ + EXPR_KIND_VALUES_SINGLE, /* single-row VALUES (in INSERT only) */ EXPR_KIND_CHECK_CONSTRAINT, /* CHECK constraint for a table */ EXPR_KIND_DOMAIN_CHECK, /* CHECK constraint for a domain */ EXPR_KIND_COLUMN_DEFAULT, /* default value for a table column */ @@ -64,7 +65,8 @@ typedef enum ParseExprKind EXPR_KIND_ALTER_COL_TRANSFORM, /* transform expr in ALTER COLUMN TYPE */ EXPR_KIND_EXECUTE_PARAMETER, /* parameter value in EXECUTE */ EXPR_KIND_TRIGGER_WHEN, /* WHEN condition in CREATE TRIGGER */ - EXPR_KIND_POLICY /* USING or WITH CHECK expr in policy */ + EXPR_KIND_POLICY, /* USING or WITH CHECK expr in policy */ + EXPR_KIND_PARTITION_EXPRESSION /* PARTITION BY expression */ } ParseExprKind; @@ -122,11 +124,39 @@ typedef Node *(*CoerceParamHook) (ParseState *pstate, Param *param, * p_parent_cte: CommonTableExpr that immediately contains the current query, * if any. * + * p_target_relation: target relation, if query is INSERT, UPDATE, or DELETE. + * + * p_target_rangetblentry: target relation's entry in the rtable list. + * + * p_is_insert: true to process assignment expressions like INSERT, false + * to process them like UPDATE. (Note this can change intra-statement, for + * cases like INSERT ON CONFLICT UPDATE.) + * * p_windowdefs: list of WindowDefs representing WINDOW and OVER clauses. * We collect these while transforming expressions and then transform them * afterwards (so that any resjunk tlist items needed for the sort/group * clauses end up at the end of the query tlist). A WindowDef's location in * this list, counting from 1, is the winref number to use to reference it. + * + * p_expr_kind: kind of expression we're currently parsing, as per enum above; + * EXPR_KIND_NONE when not in an expression. + * + * p_next_resno: next TargetEntry.resno to assign, starting from 1. + * + * p_multiassign_exprs: partially-processed MultiAssignRef source expressions. + * + * p_locking_clause: query's FOR UPDATE/FOR SHARE clause, if any. + * + * p_locked_from_parent: true if parent query level applies FOR UPDATE/SHARE + * to this subquery as a whole. + * + * p_hasAggs, p_hasWindowFuncs, etc: true if we've found any of the indicated + * constructs in the query. + * + * p_pre_columnref_hook, etc: optional parser hook functions for modifying the + * interpretation of ColumnRefs and ParamRefs. + * + * p_ref_hook_state: passthrough state for the parser hook functions. */ struct ParseState { @@ -142,20 +172,23 @@ struct ParseState List *p_ctenamespace; /* current namespace for common table exprs */ List *p_future_ctes; /* common table exprs not yet in namespace */ CommonTableExpr *p_parent_cte; /* this query's containing CTE */ + Relation p_target_relation; /* INSERT/UPDATE/DELETE target rel */ + RangeTblEntry *p_target_rangetblentry; /* target rel's RTE */ + bool p_is_insert; /* process assignment like INSERT not UPDATE */ List *p_windowdefs; /* raw representations of window clauses */ ParseExprKind p_expr_kind; /* what kind of expression we're parsing */ int p_next_resno; /* next targetlist resno to assign */ List *p_multiassign_exprs; /* junk tlist entries for multiassign */ List *p_locking_clause; /* raw FOR UPDATE/FOR SHARE info */ - Node *p_value_substitute; /* what to replace VALUE with, if any */ + bool p_locked_from_parent; /* parent has marked this subquery + * with FOR UPDATE/FOR SHARE */ + + /* Flags telling about things found in the query: */ bool p_hasAggs; bool p_hasWindowFuncs; + bool p_hasTargetSRFs; bool p_hasSubLinks; bool p_hasModifyingCTE; - bool p_is_insert; - bool p_locked_from_parent; - Relation p_target_relation; - RangeTblEntry *p_target_rangetblentry; /* * Optional hook functions for parser callbacks. These are null unless diff --git a/src/include/parser/parse_oper.h b/src/include/parser/parse_oper.h index 03bb5b9a14..b8d46637be 100644 --- a/src/include/parser/parse_oper.h +++ b/src/include/parser/parse_oper.h @@ -4,7 +4,7 @@ * handle operator things for parser * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_oper.h diff --git a/src/include/parser/parse_param.h b/src/include/parser/parse_param.h index bbf608a2a9..68f3ddaffa 100644 --- a/src/include/parser/parse_param.h +++ b/src/include/parser/parse_param.h @@ -3,7 +3,7 @@ * parse_param.h * handle parameters in parser * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_param.h diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h index 3ef3d7bae5..cfb2e5b88c 100644 --- a/src/include/parser/parse_relation.h +++ b/src/include/parser/parse_relation.h @@ -4,7 +4,7 @@ * prototypes for parse_relation.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_relation.h @@ -85,7 +85,9 @@ extern RangeTblEntry *addRangeTableEntryForFunction(ParseState *pstate, bool inFromCl); extern RangeTblEntry *addRangeTableEntryForValues(ParseState *pstate, List *exprs, - List *collations, + List *coltypes, + List *coltypmods, + List *colcollations, Alias *alias, bool lateral, bool inFromCl); diff --git a/src/include/parser/parse_target.h b/src/include/parser/parse_target.h index 8d4ad60026..e035aacbf4 100644 --- a/src/include/parser/parse_target.h +++ b/src/include/parser/parse_target.h @@ -4,7 +4,7 @@ * handle target lists * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_target.h @@ -20,7 +20,7 @@ extern List *transformTargetList(ParseState *pstate, List *targetlist, ParseExprKind exprKind); extern List *transformExpressionList(ParseState *pstate, List *exprlist, - ParseExprKind exprKind); + ParseExprKind exprKind, bool allowDefault); extern void markTargetListOrigins(ParseState *pstate, List *targetlist); extern TargetEntry *transformTargetEntry(ParseState *pstate, Node *node, Node *expr, ParseExprKind exprKind, diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h index ba580beda3..db0cd56ecc 100644 --- a/src/include/parser/parse_type.h +++ b/src/include/parser/parse_type.h @@ -3,7 +3,7 @@ * parse_type.h * handle type operations for parser * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_type.h diff --git a/src/include/parser/parse_utilcmd.h b/src/include/parser/parse_utilcmd.h index be3b6f70c1..41ab44e5c7 100644 --- a/src/include/parser/parse_utilcmd.h +++ b/src/include/parser/parse_utilcmd.h @@ -4,7 +4,7 @@ * parse analysis for utility commands * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_utilcmd.h @@ -25,5 +25,7 @@ extern IndexStmt *transformIndexStmt(Oid relid, IndexStmt *stmt, extern void transformRuleStmt(RuleStmt *stmt, const char *queryString, List **actions, Node **whereClause); extern List *transformCreateSchemaStmt(CreateSchemaStmt *stmt); +extern Node *transformPartitionBound(ParseState *pstate, Relation parent, + Node *bound); #endif /* PARSE_UTILCMD_H */ diff --git a/src/include/parser/parser.h b/src/include/parser/parser.h index 5e9636ddfb..c8ad710dac 100644 --- a/src/include/parser/parser.h +++ b/src/include/parser/parser.h @@ -5,7 +5,7 @@ * * This is the external API for the raw lexing/parsing functions. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parser.h diff --git a/src/include/parser/parsetree.h b/src/include/parser/parsetree.h index 465989b526..951ff0a254 100644 --- a/src/include/parser/parsetree.h +++ b/src/include/parser/parsetree.h @@ -5,7 +5,7 @@ * parse trees. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parsetree.h diff --git a/src/include/parser/scanner.h b/src/include/parser/scanner.h index b885e67a83..7ca924cff3 100644 --- a/src/include/parser/scanner.h +++ b/src/include/parser/scanner.h @@ -8,7 +8,7 @@ * higher-level API provided by parser.h. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/scanner.h diff --git a/src/include/parser/scansup.h b/src/include/parser/scansup.h index 7f482b6067..3464eb4c0e 100644 --- a/src/include/parser/scansup.h +++ b/src/include/parser/scansup.h @@ -4,7 +4,7 @@ * scanner support routines. used by both the bootstrap lexer * as well as the normal lexer * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/scansup.h diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index b621ff2af5..b9dfdd41c1 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -84,24 +84,39 @@ /* Define to 1 if you have the `append_history' function. */ #undef HAVE_APPEND_HISTORY +/* Define to 1 if you have the `ASN1_STRING_get0_data' function. */ +#undef HAVE_ASN1_STRING_GET0_DATA + /* Define to 1 if you want to use atomics if available. */ #undef HAVE_ATOMICS /* Define to 1 if you have the header file. */ #undef HAVE_ATOMIC_H +/* Define to 1 if you have the `BIO_get_data' function. */ +#undef HAVE_BIO_GET_DATA + +/* Define to 1 if you have the `BIO_meth_new' function. */ +#undef HAVE_BIO_METH_NEW + /* Define to 1 if you have the `cbrt' function. */ #undef HAVE_CBRT /* Define to 1 if you have the `class' function. */ #undef HAVE_CLASS +/* Define to 1 if you have the `clock_gettime' function. */ +#undef HAVE_CLOCK_GETTIME + /* Define to 1 if you have the header file. */ #undef HAVE_CRTDEFS_H /* Define to 1 if you have the `crypt' function. */ #undef HAVE_CRYPT +/* Define to 1 if you have the `CRYPTO_lock' function. */ +#undef HAVE_CRYPTO_LOCK + /* Define to 1 if you have the header file. */ #undef HAVE_CRYPT_H @@ -364,6 +379,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_NET_IF_H +/* Define to 1 if you have the `OPENSSL_init_ssl' function. */ +#undef HAVE_OPENSSL_INIT_SSL + /* Define to 1 if you have the header file. */ #undef HAVE_OSSP_UUID_H @@ -403,6 +421,9 @@ /* Define to 1 if you have the `random' function. */ #undef HAVE_RANDOM +/* Define to 1 if you have the `RAND_OpenSSL' function. */ +#undef HAVE_RAND_OPENSSL + /* Define to 1 if you have the header file. */ #undef HAVE_READLINE_H @@ -479,6 +500,9 @@ /* Define to 1 if you have the `strlcpy' function. */ #undef HAVE_STRLCPY +/* Define to use have a strong random number source */ +#undef HAVE_STRONG_RANDOM + /* Define to 1 if you have the `strtoll' function. */ #undef HAVE_STRTOLL @@ -796,6 +820,9 @@ /* Define to 1 to build with BSD Authentication support. (--with-bsd-auth) */ #undef USE_BSD_AUTH +/* Define to use /dev/urandom for random number generation */ +#undef USE_DEV_URANDOM + /* Define to 1 if you want float4 values to be passed by value. (--enable-float4-byval) */ #undef USE_FLOAT4_BYVAL @@ -824,6 +851,9 @@ /* Define to build with OpenSSL support. (--with-openssl) */ #undef USE_OPENSSL +/* Define to use OpenSSL for random number generation */ +#undef USE_OPENSSL_RANDOM + /* Define to 1 to build with PAM support. (--with-pam) */ #undef USE_PAM @@ -851,6 +881,9 @@ /* Define to select unnamed POSIX semaphores. */ #undef USE_UNNAMED_POSIX_SEMAPHORES +/* Define to use native Windows API for random number generation */ +#undef USE_WIN32_RANDOM + /* Define to select Win32-style semaphores. */ #undef USE_WIN32_SEMAPHORES diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32 index b6b88fcf0d..199668c187 100644 --- a/src/include/pg_config.h.win32 +++ b/src/include/pg_config.h.win32 @@ -75,6 +75,9 @@ /* Define to 1 if you have the `class' function. */ /* #undef HAVE_CLASS */ +/* Define to 1 if you have the `clock_gettime' function. */ +/* #undef HAVE_CLOCK_GETTIME */ + /* Define to 1 if you have the `crypt' function. */ /* #undef HAVE_CRYPT */ @@ -348,6 +351,9 @@ /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 +/* Define to use have a strong random number source */ +#define HAVE_STRONG_RANDOM 1 + /* Define to 1 if you have the `strtoll' function. */ //#define HAVE_STRTOLL 1 @@ -554,10 +560,10 @@ #define PACKAGE_NAME "PostgreSQL" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "PostgreSQL 9.6beta4" +#define PACKAGE_STRING "PostgreSQL 10devel" /* Define to the version of this package. */ -#define PACKAGE_VERSION "9.6beta4" +#define PACKAGE_VERSION "10devel" /* Define to the name of a signed 128-bit integer type. */ #undef PG_INT128_TYPE @@ -566,10 +572,10 @@ #define PG_INT64_TYPE long long int /* PostgreSQL version as a string */ -#define PG_VERSION "9.6beta4" +#define PG_VERSION "10devel" /* PostgreSQL version as a number */ -#define PG_VERSION_NUM 90600 +#define PG_VERSION_NUM 100000 /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "postgresql" @@ -616,6 +622,9 @@ /* Define to 1 to build with BSD Authentication support. (--with-bsd-auth) */ /* #undef USE_BSD_AUTH */ +/* Define to use /dev/urandom for random number generation */ +/* #undef USE_DEV_URANDOM */ + /* Define to 1 if you want 64-bit integer timestamp and interval support. (--enable-integer-datetimes) */ /* #undef USE_INTEGER_DATETIMES */ @@ -629,6 +638,9 @@ /* Define to build with OpenSSL support. (--with-openssl) */ /* #undef USE_OPENSSL */ +/* Define to use OpenSSL for random number generation */ +/* #undef USE_OPENSSL_RANDOM */ + /* Define to 1 to build with PAM support. (--with-pam) */ /* #undef USE_PAM */ @@ -657,6 +669,9 @@ /* 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 diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.h index a2b2b614be..c07907145a 100644 --- a/src/include/pg_config_manual.h +++ b/src/include/pg_config_manual.h @@ -6,7 +6,7 @@ * for developers. If you edit any of these, be sure to do a *full* * rebuild (and an initdb if noted). * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/pg_config_manual.h @@ -45,6 +45,11 @@ */ #define INDEX_MAX_KEYS 32 +/* + * Maximum number of columns in a partition key + */ +#define PARTITION_MAX_KEYS 32 + /* * Set the upper and lower bounds of sequence values. */ @@ -147,6 +152,24 @@ #define USE_PREFETCH #endif +/* + * Default and maximum values for backend_flush_after, bgwriter_flush_after + * and checkpoint_flush_after; measured in blocks. Currently, these are + * enabled by default if sync_file_range() exists, ie, only on Linux. Perhaps + * we could also enable by default if we have mmap and msync(MS_ASYNC)? + */ +#ifdef HAVE_SYNC_FILE_RANGE +#define DEFAULT_BACKEND_FLUSH_AFTER 0 /* never enabled by default */ +#define DEFAULT_BGWRITER_FLUSH_AFTER 64 +#define DEFAULT_CHECKPOINT_FLUSH_AFTER 32 +#else +#define DEFAULT_BACKEND_FLUSH_AFTER 0 +#define DEFAULT_BGWRITER_FLUSH_AFTER 0 +#define DEFAULT_CHECKPOINT_FLUSH_AFTER 0 +#endif +/* upper limit for all three variables */ +#define WRITEBACK_MAX_PENDING_FLUSHES 256 + /* * USE_SSL code should be compiled only when compiling with an SSL * implementation. (Currently, only OpenSSL is supported, but we might add diff --git a/src/include/pg_getopt.h b/src/include/pg_getopt.h index 82532d5b95..2e25576499 100644 --- a/src/include/pg_getopt.h +++ b/src/include/pg_getopt.h @@ -2,7 +2,7 @@ * Portions Copyright (c) 1987, 1993, 1994 * The Regents of the University of California. All rights reserved. * - * Portions Copyright (c) 2003-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2017, PostgreSQL Global Development Group * * src/include/pg_getopt.h */ diff --git a/src/include/pg_trace.h b/src/include/pg_trace.h index 6bb73864e5..1fe95e6403 100644 --- a/src/include/pg_trace.h +++ b/src/include/pg_trace.h @@ -3,7 +3,7 @@ * * Definitions for the PostgreSQL tracing framework * - * Copyright (c) 2006-2016, PostgreSQL Global Development Group + * Copyright (c) 2006-2017, PostgreSQL Global Development Group * * src/include/pg_trace.h * ---------- diff --git a/src/include/pgstat.h b/src/include/pgstat.h index dc3320d091..de8225b989 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -3,7 +3,7 @@ * * Definitions for the PostgreSQL statistics collector daemon. * - * Copyright (c) 2001-2016, PostgreSQL Global Development Group + * Copyright (c) 2001-2017, PostgreSQL Global Development Group * * src/include/pgstat.h * ---------- @@ -14,9 +14,9 @@ #include "datatype/timestamp.h" #include "fmgr.h" #include "libpq/pqcomm.h" +#include "port/atomics.h" #include "portability/instr_time.h" #include "postmaster/pgarch.h" -#include "storage/barrier.h" #include "storage/proc.h" #include "utils/hsearch.h" #include "utils/relcache.h" @@ -715,15 +715,93 @@ typedef enum BackendState * Wait Classes * ---------- */ -typedef enum WaitClass +#define PG_WAIT_LWLOCK 0x01000000U +#define PG_WAIT_LOCK 0x03000000U +#define PG_WAIT_BUFFER_PIN 0x04000000U +#define PG_WAIT_ACTIVITY 0x05000000U +#define PG_WAIT_CLIENT 0x06000000U +#define PG_WAIT_EXTENSION 0x07000000U +#define PG_WAIT_IPC 0x08000000U +#define PG_WAIT_TIMEOUT 0x09000000U + +/* ---------- + * Wait Events - Activity + * + * Use this category when a process is waiting because it has no work to do, + * unless the "Client" or "Timeout" category describes the situation better. + * Typically, this should only be used for background processes. + * ---------- + */ +typedef enum { - WAIT_UNDEFINED, - WAIT_LWLOCK_NAMED, - WAIT_LWLOCK_TRANCHE, - WAIT_LOCK, - WAIT_BUFFER_PIN -} WaitClass; + WAIT_EVENT_ARCHIVER_MAIN = PG_WAIT_ACTIVITY, + WAIT_EVENT_AUTOVACUUM_MAIN, + WAIT_EVENT_BGWRITER_HIBERNATE, + WAIT_EVENT_BGWRITER_MAIN, + WAIT_EVENT_CHECKPOINTER_MAIN, + WAIT_EVENT_PGSTAT_MAIN, + WAIT_EVENT_RECOVERY_WAL_ALL, + WAIT_EVENT_RECOVERY_WAL_STREAM, + WAIT_EVENT_SYSLOGGER_MAIN, + WAIT_EVENT_WAL_RECEIVER_MAIN, + WAIT_EVENT_WAL_SENDER_MAIN, + WAIT_EVENT_WAL_WRITER_MAIN, + WAIT_EVENT_LOGICAL_LAUNCHER_MAIN, + WAIT_EVENT_LOGICAL_APPLY_MAIN +} WaitEventActivity; +/* ---------- + * Wait Events - Client + * + * Use this category when a process is waiting to send data to or receive data + * from the frontend process to which it is connected. This is never used for + * a background process, which has no client connection. + * ---------- + */ +typedef enum +{ + WAIT_EVENT_CLIENT_READ = PG_WAIT_CLIENT, + WAIT_EVENT_CLIENT_WRITE, + WAIT_EVENT_SSL_OPEN_SERVER, + WAIT_EVENT_WAL_RECEIVER_WAIT_START, + WAIT_EVENT_LIBPQWALRECEIVER_READ, + WAIT_EVENT_WAL_SENDER_WAIT_WAL, + WAIT_EVENT_WAL_SENDER_WRITE_DATA +} WaitEventClient; + +/* ---------- + * Wait Events - IPC + * + * Use this category when a process cannot complete the work it is doing because + * it is waiting for a notification from another process. + * ---------- + */ +typedef enum +{ + WAIT_EVENT_BGWORKER_SHUTDOWN = PG_WAIT_IPC, + WAIT_EVENT_BGWORKER_STARTUP, + WAIT_EVENT_EXECUTE_GATHER, + WAIT_EVENT_MQ_INTERNAL, + WAIT_EVENT_MQ_PUT_MESSAGE, + WAIT_EVENT_MQ_RECEIVE, + WAIT_EVENT_MQ_SEND, + WAIT_EVENT_PARALLEL_FINISH, + WAIT_EVENT_SAFE_SNAPSHOT, + WAIT_EVENT_SYNC_REP +} WaitEventIPC; + +/* ---------- + * Wait Events - Timeout + * + * Use this category when a process is waiting for a timeout to expire. + * ---------- + */ +typedef enum +{ + WAIT_EVENT_BASE_BACKUP_THROTTLE = PG_WAIT_TIMEOUT, + WAIT_EVENT_PG_SLEEP, + WAIT_EVENT_RECOVERY_APPLY_DELAY +} WaitEventTimeout; /* ---------- * Command type for progress reporting purposes @@ -819,7 +897,7 @@ typedef struct PgBackendStatus /* * Command progress reporting. Any command which wishes can advertise * that it is running by setting st_progress_command, - * st_progress_command_target, and st_progress_command[]. + * st_progress_command_target, and st_progress_param[]. * st_progress_command_target should be the OID of the relation which the * command targets (we assume there's just one, as this is meant for * utility commands), but the meaning of each element in the @@ -1007,9 +1085,9 @@ extern void pgstat_initstats(Relation rel); * * Called from places where server process needs to wait. This is called * to report wait event information. The wait information is stored - * as 4-bytes where first byte repersents the wait event class (type of + * as 4-bytes where first byte represents the wait event class (type of * wait, for different types of wait, refer WaitClass) and the next - * 3-bytes repersent the actual wait event. Currently 2-bytes are used + * 3-bytes represent the actual wait event. Currently 2-bytes are used * for wait event which is sufficient for current usage, 1-byte is * reserved for future usage. * @@ -1018,23 +1096,18 @@ extern void pgstat_initstats(Relation rel); * ---------- */ static inline void -pgstat_report_wait_start(uint8 classId, uint16 eventId) +pgstat_report_wait_start(uint32 wait_event_info) { volatile PGPROC *proc = MyProc; - uint32 wait_event_val; if (!pgstat_track_activities || !proc) return; - wait_event_val = classId; - wait_event_val <<= 24; - wait_event_val |= eventId; - /* * Since this is a four-byte field which is always read and written as * four-bytes, updates are atomic. */ - proc->wait_event_info = wait_event_val; + proc->wait_event_info = wait_event_info; } /* ---------- diff --git a/src/include/pgtar.h b/src/include/pgtar.h index 45ca400f98..d0188efaa6 100644 --- a/src/include/pgtar.h +++ b/src/include/pgtar.h @@ -4,7 +4,7 @@ * Functions for manipulating tarfile datastructures (src/port/tar.c) * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/pgtar.h @@ -22,4 +22,5 @@ enum tarError 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); diff --git a/src/include/pgtime.h b/src/include/pgtime.h index 182da3e645..dcd073076e 100644 --- a/src/include/pgtime.h +++ b/src/include/pgtime.h @@ -3,7 +3,7 @@ * pgtime.h * PostgreSQL internal timezone library * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/include/pgtime.h diff --git a/src/include/port.h b/src/include/port.h index 455f72338c..f4546016e7 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -3,7 +3,7 @@ * port.h * Header for src/port/ compatibility functions. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/port.h @@ -203,7 +203,8 @@ extern char *pgwin32_setlocale(int category, const char *locale); #endif /* WIN32 */ /* Portable prompt handling */ -extern char *simple_prompt(const char *prompt, int maxlen, bool echo); +extern void simple_prompt(const char *prompt, char *destination, size_t destlen, + bool echo); #ifdef WIN32 #define PG_SIGNAL_COUNT 32 @@ -250,7 +251,7 @@ extern int pgunlink(const char *path); #if defined(WIN32) && !defined(__CYGWIN__) extern int pgsymlink(const char *oldpath, const char *newpath); extern int pgreadlink(const char *path, char *buf, size_t size); -extern bool pgwin32_is_junction(char *path); +extern bool pgwin32_is_junction(const char *path); #define symlink(oldpath, newpath) pgsymlink(oldpath, newpath) #define readlink(path, buf, size) pgreadlink(path, buf, size) @@ -360,6 +361,7 @@ extern off_t ftello(FILE *stream); extern double pg_erand48(unsigned short xseed[3]); extern long pg_lrand48(void); +extern long pg_jrand48(unsigned short xseed[3]); extern void pg_srand48(long seed); #ifndef HAVE_FLS @@ -453,6 +455,11 @@ extern int pg_codepage_to_encoding(UINT cp); extern char *inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size); +/* port/pg_strong_random.c */ +#ifdef HAVE_STRONG_RANDOM +extern bool pg_strong_random(void *buf, size_t len); +#endif + /* port/pgcheckdir.c */ extern int pg_check_dir(const char *dir); diff --git a/src/include/port/atomics.h b/src/include/port/atomics.h index f7884d72c6..2e2ec27639 100644 --- a/src/include/port/atomics.h +++ b/src/include/port/atomics.h @@ -27,7 +27,7 @@ * For an introduction to using memory barriers within the PostgreSQL backend, * see src/backend/storage/lmgr/README.barrier * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/port/atomics.h @@ -255,10 +255,12 @@ pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr) } /* - * pg_atomic_write_u32 - unlocked write to atomic variable. + * pg_atomic_write_u32 - write to atomic variable. * * The write is guaranteed to succeed as a whole, i.e. it's not possible to - * observe a partial write for any reader. + * observe a partial write for any reader. Note that this correctly interacts + * with pg_atomic_compare_exchange_u32, in contrast to + * pg_atomic_unlocked_write_u32(). * * No barrier semantics. */ @@ -270,6 +272,25 @@ pg_atomic_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val) pg_atomic_write_u32_impl(ptr, val); } +/* + * pg_atomic_unlocked_write_u32 - unlocked write to atomic variable. + * + * The write is guaranteed to succeed as a whole, i.e. it's not possible to + * observe a partial write for any reader. But note that writing this way is + * not guaranteed to correctly interact with read-modify-write operations like + * pg_atomic_compare_exchange_u32. This should only be used in cases where + * minor performance regressions due to atomics emulation are unacceptable. + * + * No barrier semantics. + */ +static inline void +pg_atomic_unlocked_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val) +{ + AssertPointerAlignment(ptr, 4); + + pg_atomic_unlocked_write_u32_impl(ptr, val); +} + /* * pg_atomic_exchange_u32 - exchange newval with current value * diff --git a/src/include/port/atomics/arch-arm.h b/src/include/port/atomics/arch-arm.h index 78b211b651..563531c2d6 100644 --- a/src/include/port/atomics/arch-arm.h +++ b/src/include/port/atomics/arch-arm.h @@ -3,7 +3,7 @@ * arch-arm.h * Atomic operations considerations specific to ARM * - * Portions Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2013-2017, PostgreSQL Global Development Group * * NOTES: * diff --git a/src/include/port/atomics/arch-hppa.h b/src/include/port/atomics/arch-hppa.h index b50e339c7e..c4176c6f42 100644 --- a/src/include/port/atomics/arch-hppa.h +++ b/src/include/port/atomics/arch-hppa.h @@ -3,7 +3,7 @@ * arch-hppa.h * Atomic operations considerations specific to HPPA * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES: diff --git a/src/include/port/atomics/arch-ia64.h b/src/include/port/atomics/arch-ia64.h index 03cc8a006f..61224d63d5 100644 --- a/src/include/port/atomics/arch-ia64.h +++ b/src/include/port/atomics/arch-ia64.h @@ -3,7 +3,7 @@ * arch-ia64.h * Atomic operations considerations specific to intel itanium * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES: diff --git a/src/include/port/atomics/arch-ppc.h b/src/include/port/atomics/arch-ppc.h index 2b54c42645..ed1cd9d1b9 100644 --- a/src/include/port/atomics/arch-ppc.h +++ b/src/include/port/atomics/arch-ppc.h @@ -3,7 +3,7 @@ * arch-ppc.h * Atomic operations considerations specific to PowerPC * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES: diff --git a/src/include/port/atomics/arch-x86.h b/src/include/port/atomics/arch-x86.h index 3dbababa5f..70b991f725 100644 --- a/src/include/port/atomics/arch-x86.h +++ b/src/include/port/atomics/arch-x86.h @@ -7,7 +7,7 @@ * support for xadd and cmpxchg. Given that the 386 isn't supported anywhere * anymore that's not much of a restriction luckily. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES: diff --git a/src/include/port/atomics/fallback.h b/src/include/port/atomics/fallback.h index bdaa795abe..65d3d8c658 100644 --- a/src/include/port/atomics/fallback.h +++ b/src/include/port/atomics/fallback.h @@ -4,7 +4,7 @@ * Fallback for platforms without spinlock and/or atomics support. Slower * than native atomics support, but not unusably slow. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/port/atomics/fallback.h @@ -133,6 +133,9 @@ pg_atomic_unlocked_test_flag_impl(volatile pg_atomic_flag *ptr) #define PG_HAVE_ATOMIC_INIT_U32 extern void pg_atomic_init_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val_); +#define PG_HAVE_ATOMIC_WRITE_U32 +extern void pg_atomic_write_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val); + #define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32 extern bool pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 *expected, uint32 newval); diff --git a/src/include/port/atomics/generic-acc.h b/src/include/port/atomics/generic-acc.h index fa978498c3..4ea3ed3fc7 100644 --- a/src/include/port/atomics/generic-acc.h +++ b/src/include/port/atomics/generic-acc.h @@ -3,7 +3,7 @@ * generic-acc.h * Atomic operations support when using HPs acc on HPUX * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES: diff --git a/src/include/port/atomics/generic-gcc.h b/src/include/port/atomics/generic-gcc.h index a3abc8a1a9..7efc0861e7 100644 --- a/src/include/port/atomics/generic-gcc.h +++ b/src/include/port/atomics/generic-gcc.h @@ -3,7 +3,7 @@ * generic-gcc.h * Atomic operations, implemented using gcc (or compatible) intrinsics. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES: @@ -62,12 +62,15 @@ #define PG_HAVE_ATOMIC_FLAG_SUPPORT typedef struct pg_atomic_flag { - /* some platforms only have a 8 bit wide TAS */ -#ifdef HAVE_GCC__SYNC_CHAR_TAS - volatile char value; -#else - /* but an int works on more platforms */ + /* + * If we have a choice, use int-width TAS, because that is more efficient + * and/or more reliably implemented on most non-Intel platforms. (Note + * that this code isn't used on x86[_64]; see arch-x86.h for that.) + */ +#ifdef HAVE_GCC__SYNC_INT32_TAS volatile int value; +#else + volatile char value; #endif } pg_atomic_flag; diff --git a/src/include/port/atomics/generic-msvc.h b/src/include/port/atomics/generic-msvc.h index aeac2cd240..c7caf04d57 100644 --- a/src/include/port/atomics/generic-msvc.h +++ b/src/include/port/atomics/generic-msvc.h @@ -3,7 +3,7 @@ * generic-msvc.h * Atomic operations support when using MSVC * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES: diff --git a/src/include/port/atomics/generic-sunpro.h b/src/include/port/atomics/generic-sunpro.h index f5dd9ffcec..a58e8e3bad 100644 --- a/src/include/port/atomics/generic-sunpro.h +++ b/src/include/port/atomics/generic-sunpro.h @@ -3,7 +3,7 @@ * generic-sunpro.h * Atomic operations for solaris' CC * - * Portions Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2013-2017, PostgreSQL Global Development Group * * NOTES: * diff --git a/src/include/port/atomics/generic-xlc.h b/src/include/port/atomics/generic-xlc.h index f4fd2f3d43..f854612d39 100644 --- a/src/include/port/atomics/generic-xlc.h +++ b/src/include/port/atomics/generic-xlc.h @@ -3,7 +3,7 @@ * generic-xlc.h * Atomic operations for IBM's CC * - * Portions Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2013-2017, PostgreSQL Global Development Group * * NOTES: * diff --git a/src/include/port/atomics/generic.h b/src/include/port/atomics/generic.h index 32a01136e6..a5b29d83f7 100644 --- a/src/include/port/atomics/generic.h +++ b/src/include/port/atomics/generic.h @@ -4,7 +4,7 @@ * Implement higher level operations based on some lower level atomic * operations. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/port/atomics/generic.h @@ -58,6 +58,15 @@ pg_atomic_write_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val) } #endif +#ifndef PG_HAVE_ATOMIC_UNLOCKED_WRITE_U32 +#define PG_HAVE_ATOMIC_UNLOCKED_WRITE_U32 +static inline void +pg_atomic_unlocked_write_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val) +{ + ptr->value = val; +} +#endif + /* * provide fallback for test_and_set using atomic_exchange if available */ diff --git a/src/include/port/darwin.h b/src/include/port/darwin.h index 29c4b91d8c..15fb69d6db 100644 --- a/src/include/port/darwin.h +++ b/src/include/port/darwin.h @@ -2,7 +2,7 @@ #define __darwin__ 1 -#if HAVE_DECL_F_FULLFSYNC /* not present before OS X 10.3 */ +#if HAVE_DECL_F_FULLFSYNC /* not present before macOS 10.3 */ #define HAVE_FSYNC_WRITETHROUGH #endif diff --git a/src/include/port/pg_bswap.h b/src/include/port/pg_bswap.h index a42f757af2..c5dcf77568 100644 --- a/src/include/port/pg_bswap.h +++ b/src/include/port/pg_bswap.h @@ -12,7 +12,7 @@ * uint32_t and uint64_t respectively (these are also the respective return * types). Use caution when using these wrapper macros with signed integers. * - * Copyright (c) 2015-2016, PostgreSQL Global Development Group + * Copyright (c) 2015-2017, PostgreSQL Global Development Group * * src/include/port/pg_bswap.h * diff --git a/src/include/port/pg_crc32c.h b/src/include/port/pg_crc32c.h index 57bdacb884..aa35fa89d2 100644 --- a/src/include/port/pg_crc32c.h +++ b/src/include/port/pg_crc32c.h @@ -23,7 +23,7 @@ * EQ_CRC32C(c1, c2) * Check for equality of two CRCs. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/port/pg_crc32c.h diff --git a/src/include/port/sco.h b/src/include/port/sco.h deleted file mode 100644 index 30811450c9..0000000000 --- a/src/include/port/sco.h +++ /dev/null @@ -1,7 +0,0 @@ -/* - * src/include/port/sco.h - * - * see src/backend/libpq/pqcomm.c */ -#define SCO_ACCEPT_BUG - -#define USE_UNIVEL_CC diff --git a/src/include/port/unixware.h b/src/include/port/unixware.h deleted file mode 100644 index e068820957..0000000000 --- a/src/include/port/unixware.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * src/include/port/unixware.h - * - * see src/backend/libpq/pqcomm.c */ -#define SCO_ACCEPT_BUG - -/*************************************** - * Define this if you are compiling with - * the native UNIXWARE C compiler. - ***************************************/ -#define USE_UNIVEL_CC diff --git a/src/include/portability/instr_time.h b/src/include/portability/instr_time.h index 16caf6eee3..9eb4bb7eac 100644 --- a/src/include/portability/instr_time.h +++ b/src/include/portability/instr_time.h @@ -4,10 +4,10 @@ * portable high-precision interval timing * * This file provides an abstraction layer to hide portability issues in - * interval timing. On Unix we use gettimeofday(), but on Windows that - * gives a low-precision result so we must use QueryPerformanceCounter() - * instead. These macros also give some breathing room to use other - * high-precision-timing APIs on yet other platforms. + * interval timing. On Unix we use clock_gettime() if available, else + * gettimeofday(). On Windows, gettimeofday() gives a low-precision result + * so we must use QueryPerformanceCounter() instead. These macros also give + * some breathing room to use other high-precision-timing APIs. * * The basic data type is instr_time, which all callers should treat as an * opaque typedef. instr_time can store either an absolute time (of @@ -43,7 +43,7 @@ * Beware of multiple evaluations of the macro arguments. * * - * Copyright (c) 2001-2016, PostgreSQL Global Development Group + * Copyright (c) 2001-2017, PostgreSQL Global Development Group * * src/include/portability/instr_time.h * @@ -54,6 +54,94 @@ #ifndef WIN32 +#ifdef HAVE_CLOCK_GETTIME + +/* Use clock_gettime() */ + +#include + +/* + * The best clockid to use according to the POSIX spec is CLOCK_MONOTONIC, + * since that will give reliable interval timing even in the face of changes + * to the system clock. However, POSIX doesn't require implementations to + * provide anything except CLOCK_REALTIME, so fall back to that if we don't + * find CLOCK_MONOTONIC. + * + * Also, some implementations have nonstandard clockids with better properties + * than CLOCK_MONOTONIC. In particular, as of macOS 10.12, Apple provides + * CLOCK_MONOTONIC_RAW which is both faster to read and higher resolution than + * their version of CLOCK_MONOTONIC. + */ +#if defined(__darwin__) && defined(CLOCK_MONOTONIC_RAW) +#define PG_INSTR_CLOCK CLOCK_MONOTONIC_RAW +#elif defined(CLOCK_MONOTONIC) +#define PG_INSTR_CLOCK CLOCK_MONOTONIC +#else +#define PG_INSTR_CLOCK CLOCK_REALTIME +#endif + +typedef struct timespec instr_time; + +#define INSTR_TIME_IS_ZERO(t) ((t).tv_nsec == 0 && (t).tv_sec == 0) + +#define INSTR_TIME_SET_ZERO(t) ((t).tv_sec = 0, (t).tv_nsec = 0) + +#define INSTR_TIME_SET_CURRENT(t) ((void) clock_gettime(PG_INSTR_CLOCK, &(t))) + +#define INSTR_TIME_ADD(x,y) \ + do { \ + (x).tv_sec += (y).tv_sec; \ + (x).tv_nsec += (y).tv_nsec; \ + /* Normalize */ \ + while ((x).tv_nsec >= 1000000000) \ + { \ + (x).tv_nsec -= 1000000000; \ + (x).tv_sec++; \ + } \ + } while (0) + +#define INSTR_TIME_SUBTRACT(x,y) \ + do { \ + (x).tv_sec -= (y).tv_sec; \ + (x).tv_nsec -= (y).tv_nsec; \ + /* Normalize */ \ + while ((x).tv_nsec < 0) \ + { \ + (x).tv_nsec += 1000000000; \ + (x).tv_sec--; \ + } \ + } while (0) + +#define INSTR_TIME_ACCUM_DIFF(x,y,z) \ + do { \ + (x).tv_sec += (y).tv_sec - (z).tv_sec; \ + (x).tv_nsec += (y).tv_nsec - (z).tv_nsec; \ + /* Normalize after each add to avoid overflow/underflow of tv_nsec */ \ + while ((x).tv_nsec < 0) \ + { \ + (x).tv_nsec += 1000000000; \ + (x).tv_sec--; \ + } \ + while ((x).tv_nsec >= 1000000000) \ + { \ + (x).tv_nsec -= 1000000000; \ + (x).tv_sec++; \ + } \ + } while (0) + +#define INSTR_TIME_GET_DOUBLE(t) \ + (((double) (t).tv_sec) + ((double) (t).tv_nsec) / 1000000000.0) + +#define INSTR_TIME_GET_MILLISEC(t) \ + (((double) (t).tv_sec * 1000.0) + ((double) (t).tv_nsec) / 1000000.0) + +#define INSTR_TIME_GET_MICROSEC(t) \ + (((uint64) (t).tv_sec * (uint64) 1000000) + (uint64) ((t).tv_nsec / 1000)) + +#else /* !HAVE_CLOCK_GETTIME */ + +/* Use gettimeofday() */ + #include typedef struct timeval instr_time; @@ -113,8 +201,13 @@ typedef struct timeval instr_time; #define INSTR_TIME_GET_MICROSEC(t) \ (((uint64) (t).tv_sec * (uint64) 1000000) + (uint64) (t).tv_usec) + +#endif /* HAVE_CLOCK_GETTIME */ + #else /* WIN32 */ +/* Use QueryPerformanceCounter() */ + typedef LARGE_INTEGER instr_time; #define INSTR_TIME_IS_ZERO(t) ((t).QuadPart == 0) @@ -149,6 +242,7 @@ GetTimerFrequency(void) QueryPerformanceFrequency(&f); return (double) f.QuadPart; } + #endif /* WIN32 */ #endif /* INSTR_TIME_H */ diff --git a/src/include/portability/mem.h b/src/include/portability/mem.h index 9f055e19ed..d560c3ce56 100644 --- a/src/include/portability/mem.h +++ b/src/include/portability/mem.h @@ -3,7 +3,7 @@ * mem.h * portability definitions for various memory operations * - * Copyright (c) 2001-2016, PostgreSQL Global Development Group + * Copyright (c) 2001-2017, PostgreSQL Global Development Group * * src/include/portability/mem.h * diff --git a/src/include/postgres.h b/src/include/postgres.h index fb1933f8f2..ff2c5c051e 100644 --- a/src/include/postgres.h +++ b/src/include/postgres.h @@ -7,7 +7,7 @@ * Client-side code should include postgres_fe.h instead. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1995, Regents of the University of California * * src/include/postgres.h @@ -600,7 +600,7 @@ typedef Datum *DatumPtr; * value has adequate lifetime. */ -#define NameGetDatum(X) PointerGetDatum(X) +#define NameGetDatum(X) CStringGetDatum(NameStr(*(X))) /* * DatumGetInt64 @@ -656,6 +656,14 @@ extern Datum Int64GetDatum(int64 X); #define UInt64GetDatum(X) 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. @@ -664,7 +672,18 @@ extern Datum Int64GetDatum(int64 X); */ #ifdef USE_FLOAT4_BYVAL -extern float4 DatumGetFloat4(Datum X); +static inline float4 +DatumGetFloat4(Datum X) +{ + union + { + int32 value; + float4 retval; + } myunion; + + myunion.value = GET_4_BYTES(X); + return myunion.retval; +} #else #define DatumGetFloat4(X) (* ((float4 *) DatumGetPointer(X))) #endif @@ -676,8 +695,22 @@ extern float4 DatumGetFloat4(Datum X); * Note: if float4 is pass by reference, this function returns a reference * to palloc'd space. */ +#ifdef USE_FLOAT4_BYVAL +static inline Datum +Float4GetDatum(float4 X) +{ + union + { + float4 value; + int32 retval; + } myunion; + myunion.value = X; + return SET_4_BYTES(myunion.retval); +} +#else extern Datum Float4GetDatum(float4 X); +#endif /* * DatumGetFloat8 @@ -687,7 +720,18 @@ extern Datum Float4GetDatum(float4 X); */ #ifdef USE_FLOAT8_BYVAL -extern float8 DatumGetFloat8(Datum X); +static inline float8 +DatumGetFloat8(Datum X) +{ + union + { + int64 value; + float8 retval; + } myunion; + + myunion.value = GET_8_BYTES(X); + return myunion.retval; +} #else #define DatumGetFloat8(X) (* ((float8 *) DatumGetPointer(X))) #endif @@ -700,7 +744,22 @@ extern float8 DatumGetFloat8(Datum X); * to palloc'd space. */ +#ifdef USE_FLOAT8_BYVAL +static inline Datum +Float8GetDatum(float8 X) +{ + union + { + float8 value; + int64 retval; + } myunion; + + myunion.value = X; + return SET_8_BYTES(myunion.retval); +} +#else extern Datum Float8GetDatum(float8 X); +#endif /* diff --git a/src/include/postgres_ext.h b/src/include/postgres_ext.h index 74c344c704..ae2f087798 100644 --- a/src/include/postgres_ext.h +++ b/src/include/postgres_ext.h @@ -49,6 +49,7 @@ typedef PG_INT64_TYPE pg_int64; * 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' diff --git a/src/include/postgres_fe.h b/src/include/postgres_fe.h index 69c0ad8eaa..f49e33bc35 100644 --- a/src/include/postgres_fe.h +++ b/src/include/postgres_fe.h @@ -8,7 +8,7 @@ * postgres.h. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1995, Regents of the University of California * * src/include/postgres_fe.h diff --git a/src/include/postmaster/autovacuum.h b/src/include/postmaster/autovacuum.h index b5000b0822..99d7f09ef9 100644 --- a/src/include/postmaster/autovacuum.h +++ b/src/include/postmaster/autovacuum.h @@ -4,7 +4,7 @@ * header file for integrated autovacuum daemon * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/postmaster/autovacuum.h diff --git a/src/include/postmaster/bgworker.h b/src/include/postmaster/bgworker.h index b6889a3320..128e92cea1 100644 --- a/src/include/postmaster/bgworker.h +++ b/src/include/postmaster/bgworker.h @@ -31,7 +31,7 @@ * different) code. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -58,6 +58,15 @@ */ #define BGWORKER_BACKEND_DATABASE_CONNECTION 0x0002 +/* + * This class is used internally for parallel queries, to keep track of the + * number of active parallel workers and make sure we never launch more than + * max_parallel_workers parallel workers at the same time. Third party + * background workers should not use this class. + */ +#define BGWORKER_CLASS_PARALLEL 0x0010 +/* add additional bgworker classes here */ + typedef void (*bgworker_main_type) (Datum main_arg); diff --git a/src/include/postmaster/bgworker_internals.h b/src/include/postmaster/bgworker_internals.h index cd6cd44ef2..4c94b815b1 100644 --- a/src/include/postmaster/bgworker_internals.h +++ b/src/include/postmaster/bgworker_internals.h @@ -2,7 +2,7 @@ * bgworker_internals.h * POSTGRES pluggable background workers internals * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/postmaster/bgwriter.h b/src/include/postmaster/bgwriter.h index b162b0dea9..359b3ef5a5 100644 --- a/src/include/postmaster/bgwriter.h +++ b/src/include/postmaster/bgwriter.h @@ -6,7 +6,7 @@ * The bgwriter process used to handle checkpointing duties too. Now * there is a separate process, but we did not bother to split this header. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * src/include/postmaster/bgwriter.h * diff --git a/src/include/postmaster/fork_process.h b/src/include/postmaster/fork_process.h index c1cad6e83d..c2bfd44ea0 100644 --- a/src/include/postmaster/fork_process.h +++ b/src/include/postmaster/fork_process.h @@ -3,7 +3,7 @@ * fork_process.h * Exports from postmaster/fork_process.c. * - * Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Copyright (c) 1996-2017, PostgreSQL Global Development Group * * src/include/postmaster/fork_process.h * diff --git a/src/include/postmaster/pgarch.h b/src/include/postmaster/pgarch.h index f2cbfb3952..6a4e0f43b8 100644 --- a/src/include/postmaster/pgarch.h +++ b/src/include/postmaster/pgarch.h @@ -3,7 +3,7 @@ * pgarch.h * Exports from postmaster/pgarch.c. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/postmaster/pgarch.h @@ -16,7 +16,7 @@ /* ---------- * Archiver control info. * - * We expect that archivable files within pg_xlog will have names between + * We expect that archivable files within pg_wal will have names between * MIN_XFN_CHARS and MAX_XFN_CHARS in length, consisting only of characters * appearing in VALID_XFN_CHARS. The status files in archive_status have * corresponding names with ".ready" or ".done" appended. diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h index b2d7776f2a..95231bf768 100644 --- a/src/include/postmaster/postmaster.h +++ b/src/include/postmaster/postmaster.h @@ -3,7 +3,7 @@ * postmaster.h * Exports from postmaster/postmaster.c. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/postmaster/postmaster.h diff --git a/src/include/postmaster/startup.h b/src/include/postmaster/startup.h index 8cd6335719..ce76d94991 100644 --- a/src/include/postmaster/startup.h +++ b/src/include/postmaster/startup.h @@ -3,7 +3,7 @@ * startup.h * Exports from postmaster/startup.c. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * src/include/postmaster/startup.h * diff --git a/src/include/postmaster/syslogger.h b/src/include/postmaster/syslogger.h index 66c21119de..c187a5f23e 100644 --- a/src/include/postmaster/syslogger.h +++ b/src/include/postmaster/syslogger.h @@ -3,7 +3,7 @@ * syslogger.h * Exports from postmaster/syslogger.c. * - * Copyright (c) 2004-2016, PostgreSQL Global Development Group + * Copyright (c) 2004-2017, PostgreSQL Global Development Group * * src/include/postmaster/syslogger.h * diff --git a/src/include/postmaster/walwriter.h b/src/include/postmaster/walwriter.h index 49c5c1d016..fb91385e0b 100644 --- a/src/include/postmaster/walwriter.h +++ b/src/include/postmaster/walwriter.h @@ -3,7 +3,7 @@ * walwriter.h * Exports from postmaster/walwriter.c. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * src/include/postmaster/walwriter.h * diff --git a/src/include/regex/regcustom.h b/src/include/regex/regcustom.h index 60034daee8..04a1893c80 100644 --- a/src/include/regex/regcustom.h +++ b/src/include/regex/regcustom.h @@ -58,15 +58,13 @@ /* internal character type and related */ typedef pg_wchar chr; /* the type itself */ typedef unsigned uchr; /* unsigned type that will hold a chr */ -typedef int celt; /* type to hold chr, or NOCELT */ -#define NOCELT (-1) /* celt value which is not valid chr */ #define CHR(c) ((unsigned char) (c)) /* turn char literal into chr literal */ #define DIGITVAL(c) ((c)-'0') /* turn chr digit into its value */ #define CHRBITS 32 /* bits in a chr; must not use sizeof */ #define CHR_MIN 0x00000000 /* smallest and largest chr; the value */ #define CHR_MAX 0x7ffffffe /* CHR_MAX-CHR_MIN+1 must fit in an int, and - * CHR_MAX+1 must fit in both chr and celt */ + * CHR_MAX+1 must fit in a chr variable */ /* * Check if a chr value is in range. Ideally we'd just write this as @@ -79,6 +77,16 @@ typedef int celt; /* type to hold chr, or NOCELT */ */ #define CHR_IS_IN_RANGE(c) ((c) <= CHR_MAX) +/* + * MAX_SIMPLE_CHR is the cutoff between "simple" and "complicated" processing + * in the color map logic. It should usually be chosen high enough to ensure + * that all common characters are <= MAX_SIMPLE_CHR. However, very large + * values will be counterproductive since they cause more regex setup time. + * Also, small values can be helpful for testing the high-color-map logic + * with plain old ASCII input. + */ +#define MAX_SIMPLE_CHR 0x7FF /* suitable value for Unicode */ + /* functions operating on chr */ #define iscalnum(x) pg_wc_isalnum(x) #define iscalpha(x) pg_wc_isalpha(x) diff --git a/src/include/regex/regex.h b/src/include/regex/regex.h index 2f89dc9326..cc73db2547 100644 --- a/src/include/regex/regex.h +++ b/src/include/regex/regex.h @@ -172,6 +172,5 @@ extern int pg_regexec(regex_t *, const pg_wchar *, size_t, size_t, rm_detail_t * extern int pg_regprefix(regex_t *, pg_wchar **, size_t *); extern void pg_regfree(regex_t *); extern size_t pg_regerror(int, const regex_t *, char *, size_t); -extern void pg_set_regex_collation(Oid collation); #endif /* _REGEX_H_ */ diff --git a/src/include/regex/regexport.h b/src/include/regex/regexport.h index b7da613c95..091c568e63 100644 --- a/src/include/regex/regexport.h +++ b/src/include/regex/regexport.h @@ -17,7 +17,7 @@ * line and start/end of string. Colors are numbered 0..C-1, but note that * color 0 is "white" (all unused characters) and can generally be ignored. * - * Portions Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2013-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1998, 1999 Henry Spencer * * IDENTIFICATION diff --git a/src/include/regex/regguts.h b/src/include/regex/regguts.h index 2ceffa6563..69816f1449 100644 --- a/src/include/regex/regguts.h +++ b/src/include/regex/regguts.h @@ -127,69 +127,18 @@ #define ISBSET(uv, sn) ((uv)[(sn)/UBITS] & ((unsigned)1 << ((sn)%UBITS))) - -/* - * We dissect a chr into byts for colormap table indexing. Here we define - * a byt, which will be the same as a byte on most machines... The exact - * size of a byt is not critical, but about 8 bits is good, and extraction - * of 8-bit chunks is sometimes especially fast. - */ -#ifndef BYTBITS -#define BYTBITS 8 /* bits in a byt */ -#endif -#define BYTTAB (1<flags & FREECOL) - union tree *block; /* block of solid color, if any */ }; /* * The color map itself * - * Much of the data in the colormap struct is only used at compile time. - * However, the bulk of the space usage is in the "tree" structure, so it's - * not clear that there's much point in converting the rest to a more compact - * form when compilation is finished. + * This struct holds both data used only at compile time, and the chr to + * color mapping information, used at both compile and run time. The latter + * is the bulk of the space, so it's not really worth separating out the + * compile-only portion. + * + * Ideally, the mapping data would just be an array of colors indexed by + * chr codes; but for large character sets that's impractical. Fortunately, + * common characters have smaller codes, so we can use a simple array for chr + * codes up to MAX_SIMPLE_CHR, and do something more complex for codes above + * that, without much loss of performance. The "something more complex" is a + * 2-D array of color entries, where row indexes correspond to individual chrs + * or chr ranges that have been mentioned in the regex (with row zero + * representing all other chrs), and column indexes correspond to different + * sets of locale-dependent character classes such as "isalpha". The + * classbits[k] entry is zero if we do not care about the k'th character class + * in this regex, and otherwise it is the bit to be OR'd into the column index + * if the character in question is a member of that class. We find the color + * of a high-valued chr by identifying which colormaprange it is in to get + * the row index (use row zero if it's in none of them), identifying which of + * the interesting cclasses it's in to get the column index, and then indexing + * into the 2-D hicolormap array. + * + * The colormapranges are required to be nonempty, nonoverlapping, and to + * appear in increasing chr-value order. */ + +#define NUM_CCLASSES 13 /* must match data in regc_locale.c */ + +typedef struct colormaprange +{ + chr cmin; /* range represents cmin..cmax inclusive */ + chr cmax; + int rownum; /* row index in hicolormap array (>= 1) */ +} colormaprange; + struct colormap { int magic; @@ -234,27 +213,27 @@ struct colormap color free; /* beginning of free chain (if non-0) */ struct colordesc *cd; /* pointer to array of colordescs */ #define CDEND(cm) (&(cm)->cd[(cm)->max + 1]) + + /* mapping data for chrs <= MAX_SIMPLE_CHR: */ + color *locolormap; /* simple array indexed by chr code */ + + /* mapping data for chrs > MAX_SIMPLE_CHR: */ + int classbits[NUM_CCLASSES]; /* see comment above */ + int numcmranges; /* number of colormapranges */ + colormaprange *cmranges; /* ranges of high chrs */ + color *hicolormap; /* 2-D array of color entries */ + int maxarrayrows; /* number of array rows allocated */ + int hiarrayrows; /* number of array rows in use */ + int hiarraycols; /* number of array columns (2^N) */ + /* If we need up to NINLINECDS, we store them here to save a malloc */ -#define NINLINECDS ((size_t)10) +#define NINLINECDS ((size_t) 10) struct colordesc cdspace[NINLINECDS]; - union tree tree[NBYTS]; /* tree top, plus lower-level fill blocks */ }; -/* optimization magic to do fast chr->color mapping */ -#define B0(c) ((c) & BYTMASK) -#define B1(c) (((c)>>BYTBITS) & BYTMASK) -#define B2(c) (((c)>>(2*BYTBITS)) & BYTMASK) -#define B3(c) (((c)>>(3*BYTBITS)) & BYTMASK) -#if NBYTS == 1 -#define GETCOLOR(cm, c) ((cm)->tree->tcolor[B0(c)]) -#endif -/* beware, for NBYTS>1, GETCOLOR() is unsafe -- 2nd arg used repeatedly */ -#if NBYTS == 2 -#define GETCOLOR(cm, c) ((cm)->tree->tptr[B1(c)]->tcolor[B0(c)]) -#endif -#if NBYTS == 4 -#define GETCOLOR(cm, c) ((cm)->tree->tptr[B3(c)]->tptr[B2(c)]->tptr[B1(c)]->tcolor[B0(c)]) -#endif +/* fetch color for chr; beware of multiple evaluation of c argument */ +#define GETCOLOR(cm, c) \ + ((c) <= MAX_SIMPLE_CHR ? (cm)->locolormap[(c) - CHR_MIN] : pg_reg_getcolor(cm, c)) /* @@ -265,6 +244,11 @@ struct colormap * Representation of a set of characters. chrs[] represents individual * code points, ranges[] represents ranges in the form min..max inclusive. * + * If the cvec represents a locale-specific character class, eg [[:alpha:]], + * then the chrs[] and ranges[] arrays contain only members of that class + * up to MAX_SIMPLE_CHR (inclusive). cclasscode is set to regc_locale.c's + * code for the class, rather than being -1 as it is in an ordinary cvec. + * * Note that in cvecs gotten from newcvec() and intended to be freed by * freecvec(), both arrays of chrs are after the end of the struct, not * separately malloc'd; so chrspace and rangespace are effectively immutable. @@ -277,6 +261,7 @@ struct cvec int nranges; /* number of ranges (chr pairs) */ int rangespace; /* number of ranges allocated in ranges[] */ chr *ranges; /* pointer to vector of chr pairs */ + int cclasscode; /* value of "enum classes", or -1 */ }; @@ -490,3 +475,8 @@ struct guts int nlacons; /* size of lacons[]; note that only slots * numbered 1 .. nlacons-1 are used */ }; + + +/* prototypes for functions that are exported from regcomp.c to regexec.c */ +extern void pg_set_regex_collation(Oid collation); +extern color pg_reg_getcolor(struct colormap * cm, chr c); diff --git a/src/include/replication/basebackup.h b/src/include/replication/basebackup.h index c0a1edd397..bbd446904f 100644 --- a/src/include/replication/basebackup.h +++ b/src/include/replication/basebackup.h @@ -3,7 +3,7 @@ * basebackup.h * Exports from replication/basebackup.c. * - * Portions Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2017, PostgreSQL Global Development Group * * src/include/replication/basebackup.h * diff --git a/src/include/replication/decode.h b/src/include/replication/decode.h index 0561abfd73..f9d81d77d0 100644 --- a/src/include/replication/decode.h +++ b/src/include/replication/decode.h @@ -2,7 +2,7 @@ * decode.h * PostgreSQL WAL to logical transformation * - * Portions Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2017, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/include/replication/logical.h b/src/include/replication/logical.h index 947000e63f..fd34964bad 100644 --- a/src/include/replication/logical.h +++ b/src/include/replication/logical.h @@ -2,7 +2,7 @@ * logical.h * PostgreSQL logical decoding coordination * - * Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Copyright (c) 2012-2017, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/include/replication/logicalfuncs.h b/src/include/replication/logicalfuncs.h index 554041405c..71faee18cf 100644 --- a/src/include/replication/logicalfuncs.h +++ b/src/include/replication/logicalfuncs.h @@ -2,7 +2,7 @@ * logicalfuncs.h * PostgreSQL WAL to logical transformation support functions * - * Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Copyright (c) 2012-2017, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ @@ -16,11 +16,4 @@ extern int logical_read_local_xlog_page(XLogReaderState *state, int reqLen, XLogRecPtr targetRecPtr, char *cur_page, TimeLineID *pageTLI); -extern Datum pg_logical_slot_get_changes(PG_FUNCTION_ARGS); -extern Datum pg_logical_slot_get_binary_changes(PG_FUNCTION_ARGS); -extern Datum pg_logical_slot_peek_changes(PG_FUNCTION_ARGS); -extern Datum pg_logical_slot_peek_binary_changes(PG_FUNCTION_ARGS); - -extern Datum pg_logical_emit_message_bytea(PG_FUNCTION_ARGS); -extern Datum pg_logical_emit_message_text(PG_FUNCTION_ARGS); #endif diff --git a/src/include/replication/logicallauncher.h b/src/include/replication/logicallauncher.h new file mode 100644 index 0000000000..715ac7f24c --- /dev/null +++ b/src/include/replication/logicallauncher.h @@ -0,0 +1,27 @@ +/*------------------------------------------------------------------------- + * + * logicallauncher.h + * Exports for logical replication launcher. + * + * Portions Copyright (c) 2010-2016, PostgreSQL Global Development Group + * + * src/include/replication/logicallauncher.h + * + *------------------------------------------------------------------------- + */ +#ifndef LOGICALLAUNCHER_H +#define LOGICALLAUNCHER_H + +extern int max_logical_replication_workers; + +extern void ApplyLauncherRegister(void); +extern void ApplyLauncherMain(Datum main_arg); + +extern Size ApplyLauncherShmemSize(void); +extern void ApplyLauncherShmemInit(void); + +extern void ApplyLauncherWakeup(void); +extern void ApplyLauncherWakeupAtCommit(void); +extern void AtCommit_ApplyLauncher(void); + +#endif /* LOGICALLAUNCHER_H */ diff --git a/src/include/replication/logicalproto.h b/src/include/replication/logicalproto.h new file mode 100644 index 0000000000..0d8153c39d --- /dev/null +++ b/src/include/replication/logicalproto.h @@ -0,0 +1,104 @@ +/*------------------------------------------------------------------------- + * + * logicalproto.h + * logical replication protocol + * + * Copyright (c) 2015, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/replication/logicalproto.h + * + *------------------------------------------------------------------------- + */ +#ifndef LOGICAL_PROTO_H +#define LOGICAL_PROTO_H + +#include "replication/reorderbuffer.h" +#include "utils/rel.h" + +/* + * Protocol capabilities + * + * LOGICAL_PROTO_VERSION_NUM is our native protocol and the greatest version + * we can support. PGLOGICAL_PROTO_MIN_VERSION_NUM is the oldest version we + * have backwards compatibility for. The client requests protocol version at + * connect time. + */ +#define LOGICALREP_PROTO_MIN_VERSION_NUM 1 +#define LOGICALREP_PROTO_VERSION_NUM 1 + +/* Tuple coming via logical replication. */ +typedef struct LogicalRepTupleData +{ + char *values[MaxTupleAttributeNumber]; /* value in out function format or NULL if values is NULL */ + bool changed[MaxTupleAttributeNumber]; /* marker for changed/unchanged values */ +} LogicalRepTupleData; + +typedef uint32 LogicalRepRelId; + +/* Relation information */ +typedef struct LogicalRepRelation +{ + /* Info coming from the remote side. */ + LogicalRepRelId remoteid; /* unique id of the relation */ + char *nspname; /* schema name */ + char *relname; /* relation name */ + int natts; /* number of columns */ + char **attnames; /* column names */ + Oid *atttyps; /* column types */ + char replident; /* replica identity */ + Bitmapset *attkeys; /* Bitmap of key columns */ +} LogicalRepRelation; + +/* Type mapping info */ +typedef struct LogicalRepTyp +{ + Oid remoteid; /* unique id of the type */ + char *nspname; /* schema name */ + char *typname; /* name of the type */ + Oid typoid; /* local type Oid */ +} LogicalRepTyp; + +/* Transaction info */ +typedef struct LogicalRepBeginData +{ + XLogRecPtr final_lsn; + TimestampTz committime; + TransactionId xid; +} LogicalRepBeginData; + +typedef struct LogicalRepCommitData +{ + XLogRecPtr commit_lsn; + XLogRecPtr end_lsn; + TimestampTz committime; +} LogicalRepCommitData; + +extern void logicalrep_write_begin(StringInfo out, ReorderBufferTXN *txn); +extern void logicalrep_read_begin(StringInfo in, + LogicalRepBeginData *begin_data); +extern void logicalrep_write_commit(StringInfo out, ReorderBufferTXN *txn, + XLogRecPtr commit_lsn); +extern void logicalrep_read_commit(StringInfo in, + LogicalRepCommitData *commit_data); +extern void logicalrep_write_origin(StringInfo out, const char *origin, + XLogRecPtr origin_lsn); +extern char *logicalrep_read_origin(StringInfo in, XLogRecPtr *origin_lsn); +extern void logicalrep_write_insert(StringInfo out, Relation rel, + HeapTuple newtuple); +extern LogicalRepRelId logicalrep_read_insert(StringInfo in, LogicalRepTupleData *newtup); +extern void logicalrep_write_update(StringInfo out, Relation rel, HeapTuple oldtuple, + HeapTuple newtuple); +extern LogicalRepRelId logicalrep_read_update(StringInfo in, + bool *has_oldtuple, LogicalRepTupleData *oldtup, + LogicalRepTupleData *newtup); +extern void logicalrep_write_delete(StringInfo out, Relation rel, + HeapTuple oldtuple); +extern LogicalRepRelId logicalrep_read_delete(StringInfo in, + LogicalRepTupleData *oldtup); +extern void logicalrep_write_rel(StringInfo out, Relation rel); +extern LogicalRepRelation *logicalrep_read_rel(StringInfo in); +extern void logicalrep_write_typ(StringInfo out, Oid typoid); +extern void logicalrep_read_typ(StringInfo out, LogicalRepTyp *ltyp); + +#endif /* LOGICALREP_PROTO_H */ diff --git a/src/include/replication/logicalrelation.h b/src/include/replication/logicalrelation.h new file mode 100644 index 0000000000..8f9f4a094d --- /dev/null +++ b/src/include/replication/logicalrelation.h @@ -0,0 +1,43 @@ +/*------------------------------------------------------------------------- + * + * logicalrelation.h + * Relation definitions for logical replication relation mapping. + * + * Portions Copyright (c) 2010-2016, PostgreSQL Global Development Group + * + * src/include/replication/logicalrelation.h + * + *------------------------------------------------------------------------- + */ +#ifndef LOGICALRELATION_H +#define LOGICALRELATION_H + +#include "replication/logicalproto.h" + +typedef struct LogicalRepRelMapEntry +{ + LogicalRepRelation remoterel; /* key is remoterel.remoteid */ + + /* Mapping to local relation, filled as needed. */ + Oid localreloid; /* local relation id */ + Relation localrel; /* relcache entry */ + AttrNumber *attrmap; /* map of local attributes to + * remote ones */ + bool updatable; /* Can apply updates/detetes? */ + + /* Sync state. */ + char state; + XLogRecPtr statelsn; +} LogicalRepRelMapEntry; + +extern void logicalrep_relmap_update(LogicalRepRelation *remoterel); + +extern LogicalRepRelMapEntry *logicalrep_rel_open(LogicalRepRelId remoteid, + LOCKMODE lockmode); +extern void logicalrep_rel_close(LogicalRepRelMapEntry *rel, + LOCKMODE lockmode); + +extern void logicalrep_typmap_update(LogicalRepTyp *remotetyp); +extern Oid logicalrep_typmap_getid(Oid remoteid); + +#endif /* LOGICALRELATION_H */ diff --git a/src/include/replication/logicalworker.h b/src/include/replication/logicalworker.h new file mode 100644 index 0000000000..93cb25f438 --- /dev/null +++ b/src/include/replication/logicalworker.h @@ -0,0 +1,17 @@ +/*------------------------------------------------------------------------- + * + * logicalworker.h + * Exports for logical replication workers. + * + * Portions Copyright (c) 2010-2016, PostgreSQL Global Development Group + * + * src/include/replication/logicalworker.h + * + *------------------------------------------------------------------------- + */ +#ifndef LOGICALWORKER_H +#define LOGICALWORKER_H + +extern void ApplyWorkerMain(Datum main_arg); + +#endif /* LOGICALWORKER_H */ diff --git a/src/include/replication/message.h b/src/include/replication/message.h index 9aff9273bf..b016af7bd7 100644 --- a/src/include/replication/message.h +++ b/src/include/replication/message.h @@ -2,7 +2,7 @@ * message.h * Exports from replication/logical/message.c * - * Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Copyright (c) 2013-2017, PostgreSQL Global Development Group * * src/include/replication/message.h *------------------------------------------------------------------------- diff --git a/src/include/replication/origin.h b/src/include/replication/origin.h index 22d4643bf9..d6b8eb9d80 100644 --- a/src/include/replication/origin.h +++ b/src/include/replication/origin.h @@ -2,7 +2,7 @@ * origin.h * Exports from replication/logical/origin.c * - * Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Copyright (c) 2013-2017, PostgreSQL Global Development Group * * src/include/replication/origin.h *------------------------------------------------------------------------- @@ -71,18 +71,4 @@ const char *replorigin_identify(uint8 info); extern Size ReplicationOriginShmemSize(void); extern void ReplicationOriginShmemInit(void); -/* SQL callable functions */ -extern Datum pg_replication_origin_create(PG_FUNCTION_ARGS); -extern Datum pg_replication_origin_drop(PG_FUNCTION_ARGS); -extern Datum pg_replication_origin_oid(PG_FUNCTION_ARGS); -extern Datum pg_replication_origin_session_setup(PG_FUNCTION_ARGS); -extern Datum pg_replication_origin_session_reset(PG_FUNCTION_ARGS); -extern Datum pg_replication_origin_session_is_setup(PG_FUNCTION_ARGS); -extern Datum pg_replication_origin_session_progress(PG_FUNCTION_ARGS); -extern Datum pg_replication_origin_xact_setup(PG_FUNCTION_ARGS); -extern Datum pg_replication_origin_xact_reset(PG_FUNCTION_ARGS); -extern Datum pg_replication_origin_advance(PG_FUNCTION_ARGS); -extern Datum pg_replication_origin_progress(PG_FUNCTION_ARGS); -extern Datum pg_show_replication_origin_status(PG_FUNCTION_ARGS); - #endif /* PG_ORIGIN_H */ diff --git a/src/include/replication/output_plugin.h b/src/include/replication/output_plugin.h index 7911cc0a29..7b5870a744 100644 --- a/src/include/replication/output_plugin.h +++ b/src/include/replication/output_plugin.h @@ -2,7 +2,7 @@ * output_plugin.h * PostgreSQL Logical Decode Plugin Interface * - * Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Copyright (c) 2012-2017, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/include/replication/pgoutput.h b/src/include/replication/pgoutput.h new file mode 100644 index 0000000000..83e395823e --- /dev/null +++ b/src/include/replication/pgoutput.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------- + * + * pgoutput.h + * Logical Replication output plugin + * + * Copyright (c) 2015, PostgreSQL Global Development Group + * + * IDENTIFICATION + * pgoutput.h + * + *------------------------------------------------------------------------- + */ +#ifndef PGOUTPUT_H +#define PGOUTPUT_H + +#include "nodes/pg_list.h" + +typedef struct PGOutputData +{ + MemoryContext context; /* private memory context for transient + * allocations */ + + /* client info */ + uint32 protocol_version; + + List *publication_names; + List *publications; +} PGOutputData; + +#endif /* PGOUTPUT_H */ diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h index 9e209aef4f..25b0fc8c0a 100644 --- a/src/include/replication/reorderbuffer.h +++ b/src/include/replication/reorderbuffer.h @@ -2,7 +2,7 @@ * reorderbuffer.h * PostgreSQL logical replay/reorder buffer management. * - * Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Copyright (c) 2012-2017, PostgreSQL Global Development Group * * src/include/replication/reorderbuffer.h */ diff --git a/src/include/replication/slot.h b/src/include/replication/slot.h index e00562d274..62cacdb384 100644 --- a/src/include/replication/slot.h +++ b/src/include/replication/slot.h @@ -2,7 +2,7 @@ * slot.h * Replication slot management. * - * Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Copyright (c) 2012-2017, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ @@ -28,7 +28,8 @@ typedef enum ReplicationSlotPersistency { RS_PERSISTENT, - RS_EPHEMERAL + RS_EPHEMERAL, + RS_TEMPORARY } ReplicationSlotPersistency; /* @@ -165,6 +166,7 @@ extern void ReplicationSlotDrop(const char *name); extern void ReplicationSlotAcquire(const char *name); extern void ReplicationSlotRelease(void); +extern void ReplicationSlotCleanup(void); extern void ReplicationSlotSave(void); extern void ReplicationSlotMarkDirty(void); @@ -181,10 +183,4 @@ extern void CheckPointReplicationSlots(void); extern void CheckSlotRequirements(void); -/* SQL callable functions */ -extern Datum pg_create_physical_replication_slot(PG_FUNCTION_ARGS); -extern Datum pg_create_logical_replication_slot(PG_FUNCTION_ARGS); -extern Datum pg_drop_replication_slot(PG_FUNCTION_ARGS); -extern Datum pg_get_replication_slots(PG_FUNCTION_ARGS); - #endif /* SLOT_H */ diff --git a/src/include/replication/snapbuild.h b/src/include/replication/snapbuild.h index df229a895c..5e824ae6fc 100644 --- a/src/include/replication/snapbuild.h +++ b/src/include/replication/snapbuild.h @@ -3,7 +3,7 @@ * snapbuild.h * Exports from replication/logical/snapbuild.c. * - * Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Copyright (c) 2012-2017, PostgreSQL Global Development Group * * src/include/replication/snapbuild.h * diff --git a/src/include/replication/syncrep.h b/src/include/replication/syncrep.h index e4e0e27371..55b94f3392 100644 --- a/src/include/replication/syncrep.h +++ b/src/include/replication/syncrep.h @@ -3,7 +3,7 @@ * syncrep.h * Exports from replication/syncrep.c. * - * Portions Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/include/replication/syncrep.h @@ -32,6 +32,10 @@ #define SYNC_REP_WAITING 1 #define SYNC_REP_WAIT_COMPLETE 2 +/* syncrep_method of SyncRepConfigData */ +#define SYNC_REP_PRIORITY 0 +#define SYNC_REP_QUORUM 1 + /* * Struct for the configuration of synchronous replication. * @@ -44,11 +48,14 @@ typedef struct SyncRepConfigData int config_size; /* total size of this struct, in bytes */ int num_sync; /* number of sync standbys that we need to * wait for */ + uint8 syncrep_method; /* method to choose sync standbys */ int nmembers; /* number of members in the following list */ /* member_names contains nmembers consecutive nul-terminated C strings */ char member_names[FLEXIBLE_ARRAY_MEMBER]; } SyncRepConfigData; +extern SyncRepConfigData *SyncRepConfig; + /* communication variables for parsing synchronous_standby_names GUC */ extern SyncRepConfigData *syncrep_parse_result; extern char *syncrep_parse_error_msg; diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h index cd787c92b3..0857bdc556 100644 --- a/src/include/replication/walreceiver.h +++ b/src/include/replication/walreceiver.h @@ -3,7 +3,7 @@ * walreceiver.h * Exports from replication/walreceiverfuncs.c. * - * Portions Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2017, PostgreSQL Global Development Group * * src/include/replication/walreceiver.h * @@ -127,43 +127,112 @@ typedef struct * where to start streaming (after setting receiveStart and * receiveStartTLI), and also to tell it to send apply feedback to the * primary whenever specially marked commit records are applied. + * This is normally mapped to procLatch when walreceiver is running. */ - Latch latch; + Latch *latch; } WalRcvData; extern WalRcvData *WalRcv; -/* libpqwalreceiver hooks */ -typedef void (*walrcv_connect_type) (char *conninfo); -extern PGDLLIMPORT walrcv_connect_type walrcv_connect; - -typedef char *(*walrcv_get_conninfo_type) (void); -extern PGDLLIMPORT walrcv_get_conninfo_type walrcv_get_conninfo; - -typedef void (*walrcv_identify_system_type) (TimeLineID *primary_tli); -extern PGDLLIMPORT walrcv_identify_system_type walrcv_identify_system; - -typedef void (*walrcv_readtimelinehistoryfile_type) (TimeLineID tli, char **filename, char **content, int *size); -extern PGDLLIMPORT walrcv_readtimelinehistoryfile_type walrcv_readtimelinehistoryfile; - -typedef bool (*walrcv_startstreaming_type) (TimeLineID tli, XLogRecPtr startpoint, char *slotname); -extern PGDLLIMPORT walrcv_startstreaming_type walrcv_startstreaming; - -typedef void (*walrcv_endstreaming_type) (TimeLineID *next_tli); -extern PGDLLIMPORT walrcv_endstreaming_type walrcv_endstreaming; - -typedef int (*walrcv_receive_type) (char **buffer, pgsocket *wait_fd); -extern PGDLLIMPORT walrcv_receive_type walrcv_receive; - -typedef void (*walrcv_send_type) (const char *buffer, int nbytes); -extern PGDLLIMPORT walrcv_send_type walrcv_send; +typedef struct +{ + bool logical; /* True if this is logical + replication stream, false if + physical stream. */ + char *slotname; /* Name of the replication slot + or NULL. */ + XLogRecPtr startpoint; /* LSN of starting point. */ + + union + { + struct + { + TimeLineID startpointTLI; /* Starting timeline */ + } physical; + struct + { + uint32 proto_version; /* Logical protocol version */ + List *publication_names; /* String list of publications */ + } logical; + } proto; +} WalRcvStreamOptions; + +struct WalReceiverConn; +typedef struct WalReceiverConn WalReceiverConn; -typedef void (*walrcv_disconnect_type) (void); -extern PGDLLIMPORT walrcv_disconnect_type walrcv_disconnect; +/* libpqwalreceiver hooks */ +typedef WalReceiverConn *(*walrcv_connect_fn) (const char *conninfo, bool logical, + const char *appname, + char **err); +typedef void (*walrcv_check_conninfo_fn) (const char *conninfo); +typedef char *(*walrcv_get_conninfo_fn) (WalReceiverConn *conn); +typedef char *(*walrcv_identify_system_fn) (WalReceiverConn *conn, + TimeLineID *primary_tli, + int *server_version); +typedef void (*walrcv_readtimelinehistoryfile_fn) (WalReceiverConn *conn, + TimeLineID tli, + char **filename, + char **content, int *size); +typedef bool (*walrcv_startstreaming_fn) (WalReceiverConn *conn, + const WalRcvStreamOptions *options); +typedef void (*walrcv_endstreaming_fn) (WalReceiverConn *conn, + TimeLineID *next_tli); +typedef int (*walrcv_receive_fn) (WalReceiverConn *conn, char **buffer, + pgsocket *wait_fd); +typedef void (*walrcv_send_fn) (WalReceiverConn *conn, const char *buffer, + int nbytes); +typedef char *(*walrcv_create_slot_fn) (WalReceiverConn *conn, + const char *slotname, bool temporary, + XLogRecPtr *lsn); +typedef bool (*walrcv_command_fn) (WalReceiverConn *conn, const char *cmd, + char **err); +typedef void (*walrcv_disconnect_fn) (WalReceiverConn *conn); + +typedef struct WalReceiverFunctionsType +{ + walrcv_connect_fn walrcv_connect; + walrcv_check_conninfo_fn walrcv_check_conninfo; + walrcv_get_conninfo_fn walrcv_get_conninfo; + walrcv_identify_system_fn walrcv_identify_system; + walrcv_readtimelinehistoryfile_fn walrcv_readtimelinehistoryfile; + walrcv_startstreaming_fn walrcv_startstreaming; + walrcv_endstreaming_fn walrcv_endstreaming; + walrcv_receive_fn walrcv_receive; + walrcv_send_fn walrcv_send; + walrcv_create_slot_fn walrcv_create_slot; + walrcv_command_fn walrcv_command; + walrcv_disconnect_fn walrcv_disconnect; +} WalReceiverFunctionsType; + +extern PGDLLIMPORT WalReceiverFunctionsType *WalReceiverFunctions; + +#define walrcv_connect(conninfo, logical, appname, err) \ + WalReceiverFunctions->walrcv_connect(conninfo, logical, appname, err) +#define walrcv_check_conninfo(conninfo) \ + WalReceiverFunctions->walrcv_check_conninfo(conninfo) +#define walrcv_get_conninfo(conn) \ + WalReceiverFunctions->walrcv_get_conninfo(conn) +#define walrcv_identify_system(conn, primary_tli, server_version) \ + WalReceiverFunctions->walrcv_identify_system(conn, primary_tli, server_version) +#define walrcv_readtimelinehistoryfile(conn, tli, filename, content, size) \ + WalReceiverFunctions->walrcv_readtimelinehistoryfile(conn, tli, filename, content, size) +#define walrcv_startstreaming(conn, options) \ + WalReceiverFunctions->walrcv_startstreaming(conn, options) +#define walrcv_endstreaming(conn, next_tli) \ + WalReceiverFunctions->walrcv_endstreaming(conn, next_tli) +#define walrcv_receive(conn, buffer, wait_fd) \ + WalReceiverFunctions->walrcv_receive(conn, buffer, wait_fd) +#define walrcv_send(conn, buffer, nbytes) \ + WalReceiverFunctions->walrcv_send(conn, buffer, nbytes) +#define walrcv_create_slot(conn, slotname, temporary, lsn) \ + WalReceiverFunctions->walrcv_create_slot(conn, slotname, temporary, lsn) +#define walrcv_command(conn, cmd, err) \ + WalReceiverFunctions->walrcv_command(conn, cmd, err) +#define walrcv_disconnect(conn) \ + WalReceiverFunctions->walrcv_disconnect(conn) /* prototypes for functions in walreceiver.c */ extern void WalReceiverMain(void) pg_attribute_noreturn(); -extern Datum pg_stat_get_wal_receiver(PG_FUNCTION_ARGS); /* prototypes for functions in walreceiverfuncs.c */ extern Size WalRcvShmemSize(void); diff --git a/src/include/replication/walsender.h b/src/include/replication/walsender.h index de7338638e..fe23f6619f 100644 --- a/src/include/replication/walsender.h +++ b/src/include/replication/walsender.h @@ -3,7 +3,7 @@ * walsender.h * Exports from replication/walsender.c. * - * Portions Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2017, PostgreSQL Global Development Group * * src/include/replication/walsender.h * @@ -36,8 +36,6 @@ extern void WalSndShmemInit(void); extern void WalSndWakeup(void); extern void WalSndRqstFileReload(void); -extern Datum pg_stat_get_wal_senders(PG_FUNCTION_ARGS); - /* * Remember that we want to wakeup walsenders later * diff --git a/src/include/replication/walsender_private.h b/src/include/replication/walsender_private.h index 7794aa567e..5e6ccfc57b 100644 --- a/src/include/replication/walsender_private.h +++ b/src/include/replication/walsender_private.h @@ -3,7 +3,7 @@ * walsender_private.h * Private definitions from replication/walsender.c. * - * Portions Copyright (c) 2010-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2017, PostgreSQL Global Development Group * * src/include/replication/walsender_private.h * diff --git a/src/include/replication/worker_internal.h b/src/include/replication/worker_internal.h new file mode 100644 index 0000000000..29c43fc92a --- /dev/null +++ b/src/include/replication/worker_internal.h @@ -0,0 +1,64 @@ +/*------------------------------------------------------------------------- + * + * worker_internal.h + * Internal headers shared by logical replication workers. + * + * Portions Copyright (c) 2010-2016, PostgreSQL Global Development Group + * + * src/include/replication/worker_internal.h + * + *------------------------------------------------------------------------- + */ +#ifndef WORKER_INTERNAL_H +#define WORKER_INTERNAL_H + +#include "access/xlogdefs.h" +#include "catalog/pg_subscription.h" +#include "datatype/timestamp.h" +#include "storage/lock.h" + +typedef struct LogicalRepWorker +{ + /* Pointer to proc array. NULL if not running. */ + PGPROC *proc; + + /* Database id to connect to. */ + Oid dbid; + + /* User to use for connection (will be same as owner of subscription). */ + Oid userid; + + /* Subscription id for the worker. */ + Oid subid; + + /* Used for initial table synchronization. */ + Oid relid; + + /* Stats. */ + XLogRecPtr last_lsn; + TimestampTz last_send_time; + TimestampTz last_recv_time; + XLogRecPtr reply_lsn; + TimestampTz reply_time; +} LogicalRepWorker; + +/* libpqreceiver connection */ +extern struct WalReceiverConn *wrconn; + +/* Worker and subscription objects. */ +extern Subscription *MySubscription; +extern LogicalRepWorker *MyLogicalRepWorker; + +extern bool in_remote_transaction; +extern bool got_SIGTERM; + +extern void logicalrep_worker_attach(int slot); +extern LogicalRepWorker *logicalrep_worker_find(Oid subid); +extern int logicalrep_worker_count(Oid subid); +extern void logicalrep_worker_launch(Oid dbid, Oid subid, const char *subname, Oid userid); +extern void logicalrep_worker_stop(Oid subid); +extern void logicalrep_worker_wakeup(Oid subid); + +extern void logicalrep_worker_sigterm(SIGNAL_ARGS); + +#endif /* WORKER_INTERNAL_H */ diff --git a/src/include/rewrite/prs2lock.h b/src/include/rewrite/prs2lock.h index bb91708beb..36dca02a7e 100644 --- a/src/include/rewrite/prs2lock.h +++ b/src/include/rewrite/prs2lock.h @@ -3,7 +3,7 @@ * prs2lock.h * data structures for POSTGRES Rule System II (rewrite rules only) * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/rewrite/prs2lock.h diff --git a/src/include/rewrite/rewriteDefine.h b/src/include/rewrite/rewriteDefine.h index c08acb4a71..5495700970 100644 --- a/src/include/rewrite/rewriteDefine.h +++ b/src/include/rewrite/rewriteDefine.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/rewrite/rewriteDefine.h diff --git a/src/include/rewrite/rewriteHandler.h b/src/include/rewrite/rewriteHandler.h index 2d5f6c2a27..9857b4823b 100644 --- a/src/include/rewrite/rewriteHandler.h +++ b/src/include/rewrite/rewriteHandler.h @@ -4,7 +4,7 @@ * External interface to query rewriter. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/rewrite/rewriteHandler.h diff --git a/src/include/rewrite/rewriteManip.h b/src/include/rewrite/rewriteManip.h index f941299814..3910bceb2a 100644 --- a/src/include/rewrite/rewriteManip.h +++ b/src/include/rewrite/rewriteManip.h @@ -4,7 +4,7 @@ * Querytree manipulation subroutines for query rewriter. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/rewrite/rewriteManip.h diff --git a/src/include/rewrite/rewriteRemove.h b/src/include/rewrite/rewriteRemove.h index 0274dfad56..28c9be72db 100644 --- a/src/include/rewrite/rewriteRemove.h +++ b/src/include/rewrite/rewriteRemove.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/rewrite/rewriteRemove.h diff --git a/src/include/rewrite/rewriteSupport.h b/src/include/rewrite/rewriteSupport.h index 1841aa9c55..36e5296295 100644 --- a/src/include/rewrite/rewriteSupport.h +++ b/src/include/rewrite/rewriteSupport.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/rewrite/rewriteSupport.h diff --git a/src/include/rewrite/rowsecurity.h b/src/include/rewrite/rowsecurity.h index fd0cbaff59..0e739fd334 100644 --- a/src/include/rewrite/rowsecurity.h +++ b/src/include/rewrite/rowsecurity.h @@ -5,7 +5,7 @@ * prototypes for rewrite/rowsecurity.c and the structures for managing * the row security policies for relations in relcache. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * ------------------------------------------------------------------------- @@ -22,6 +22,7 @@ typedef struct RowSecurityPolicy char *policy_name; /* Name of the policy */ char polcmd; /* Type of command policy is for */ ArrayType *roles; /* Array of roles policy is for */ + bool permissive; /* restrictive or permissive policy */ Expr *qual; /* Expression to filter rows */ Expr *with_check_qual; /* Expression to limit rows allowed */ bool hassublinks; /* If either expression has sublinks */ diff --git a/src/include/rusagestub.h b/src/include/rusagestub.h index 077d5c218d..0e366cab10 100644 --- a/src/include/rusagestub.h +++ b/src/include/rusagestub.h @@ -4,7 +4,7 @@ * Stubs for getrusage(3). * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/rusagestub.h diff --git a/src/include/snowball/header.h b/src/include/snowball/header.h index 025c146afe..9501f77ac1 100644 --- a/src/include/snowball/header.h +++ b/src/include/snowball/header.h @@ -13,7 +13,7 @@ * * NOTE: this file should not be included into any non-snowball sources! * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * src/include/snowball/header.h * diff --git a/src/include/storage/backendid.h b/src/include/storage/backendid.h index dec8a97271..9d1fc50082 100644 --- a/src/include/storage/backendid.h +++ b/src/include/storage/backendid.h @@ -4,7 +4,7 @@ * POSTGRES backend id communication definitions * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/backendid.h diff --git a/src/include/storage/barrier.h b/src/include/storage/barrier.h deleted file mode 100644 index 6202e57608..0000000000 --- a/src/include/storage/barrier.h +++ /dev/null @@ -1,23 +0,0 @@ -/*------------------------------------------------------------------------- - * - * barrier.h - * Memory barrier operations. - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * src/include/storage/barrier.h - * - *------------------------------------------------------------------------- - */ -#ifndef BARRIER_H -#define BARRIER_H - -/* - * This used to be a separate file, full of compiler/architecture - * dependent defines, but it's not included in the atomics.h - * infrastructure and just kept for backward compatibility. - */ -#include "port/atomics.h" - -#endif /* BARRIER_H */ diff --git a/src/include/storage/block.h b/src/include/storage/block.h index 1bfad18ddd..ec847bbb7a 100644 --- a/src/include/storage/block.h +++ b/src/include/storage/block.h @@ -4,7 +4,7 @@ * POSTGRES disk block definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/block.h diff --git a/src/include/storage/buf.h b/src/include/storage/buf.h index e641c4504c..ac33b83b4b 100644 --- a/src/include/storage/buf.h +++ b/src/include/storage/buf.h @@ -4,7 +4,7 @@ * Basic buffer manager data types. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/buf.h diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h index e0dfb2f5b0..d117b66537 100644 --- a/src/include/storage/buf_internals.h +++ b/src/include/storage/buf_internals.h @@ -5,7 +5,7 @@ * strategy. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/buf_internals.h @@ -168,7 +168,8 @@ typedef struct buftag * We use this same struct for local buffer headers, but the locks are not * used and not all of the flag bits are useful either. To avoid unnecessary * overhead, manipulations of the state field should be done without actual - * atomic operations (i.e. only pg_atomic_read/write). + * atomic operations (i.e. only pg_atomic_read_u32() and + * pg_atomic_unlocked_write_u32()). * * Be careful to avoid increasing the size of the struct when adding or * reordering members. Keeping it below 64 bytes (the most common CPU diff --git a/src/include/storage/buffile.h b/src/include/storage/buffile.h index 809e5962e4..fe00bf0c31 100644 --- a/src/include/storage/buffile.h +++ b/src/include/storage/buffile.h @@ -15,7 +15,7 @@ * but currently we have no need for oversize temp files without buffered * access. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/buffile.h diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h index fcd0c75b1c..4c697e276c 100644 --- a/src/include/storage/bufmgr.h +++ b/src/include/storage/bufmgr.h @@ -4,7 +4,7 @@ * POSTGRES buffer manager definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/bufmgr.h @@ -14,7 +14,6 @@ #ifndef BUFMGR_H #define BUFMGR_H -#include "catalog/catalog.h" #include "storage/block.h" #include "storage/buf.h" #include "storage/bufpage.h" @@ -55,17 +54,6 @@ struct WritebackContext; extern PGDLLIMPORT int NBuffers; /* in bufmgr.c */ -#define WRITEBACK_MAX_PENDING_FLUSHES 256 - -/* FIXME: Also default to on for mmap && msync(MS_ASYNC)? */ -#ifdef HAVE_SYNC_FILE_RANGE -#define DEFAULT_CHECKPOINT_FLUSH_AFTER 32 -#define DEFAULT_BGWRITER_FLUSH_AFTER 64 -#else -#define DEFAULT_CHECKPOINT_FLUSH_AFTER 0 -#define DEFAULT_BGWRITER_FLUSH_AFTER 0 -#endif /* HAVE_SYNC_FILE_RANGE */ - extern bool zero_damaged_pages; extern int bgwriter_lru_maxpages; extern double bgwriter_lru_multiplier; @@ -228,6 +216,7 @@ extern void LockBuffer(Buffer buffer, int mode); extern bool ConditionalLockBuffer(Buffer buffer); extern void LockBufferForCleanup(Buffer buffer); extern bool ConditionalLockBufferForCleanup(Buffer buffer); +extern bool IsBufferCleanupOK(Buffer buffer); extern bool HoldingBufferPinThatDelaysRecovery(void); extern void AbortBufferIO(void); diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h index 15cebfc60d..294f9cb85a 100644 --- a/src/include/storage/bufpage.h +++ b/src/include/storage/bufpage.h @@ -4,7 +4,7 @@ * Standard POSTGRES buffer page definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/bufpage.h @@ -409,12 +409,14 @@ do { \ */ #define PAI_OVERWRITE (1 << 0) #define PAI_IS_HEAP (1 << 1) -#define PAI_ALLOW_FAR_OFFSET (1 << 2) + +#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap) \ + PageAddItemExtended(page, item, size, offsetNumber, \ + ((overwrite) ? PAI_OVERWRITE : 0) | \ + ((is_heap) ? PAI_IS_HEAP : 0)) extern void PageInit(Page page, Size pageSize, Size specialSize); extern bool PageIsVerified(Page page, BlockNumber blkno); -extern OffsetNumber PageAddItem(Page page, Item item, Size size, - OffsetNumber offsetNumber, bool overwrite, bool is_heap); extern OffsetNumber PageAddItemExtended(Page page, Item item, Size size, OffsetNumber offsetNumber, int flags); extern Page PageGetTempPage(Page page); @@ -427,8 +429,9 @@ extern Size PageGetExactFreeSpace(Page page); extern Size PageGetHeapFreeSpace(Page page); extern void PageIndexTupleDelete(Page page, OffsetNumber offset); extern void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems); -extern void PageIndexDeleteNoCompact(Page page, OffsetNumber *itemnos, - int nitems); +extern void PageIndexTupleDeleteNoCompact(Page page, OffsetNumber offset); +extern bool PageIndexTupleOverwrite(Page page, OffsetNumber offnum, + Item newtup, Size newsize); extern char *PageSetChecksumCopy(Page page, BlockNumber blkno); extern void PageSetChecksumInplace(Page page, BlockNumber blkno); diff --git a/src/include/storage/checksum.h b/src/include/storage/checksum.h index 5afc23f607..682043f8e7 100644 --- a/src/include/storage/checksum.h +++ b/src/include/storage/checksum.h @@ -3,7 +3,7 @@ * checksum.h * Checksum implementation for data pages. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/checksum.h diff --git a/src/include/storage/checksum_impl.h b/src/include/storage/checksum_impl.h index ce141258c9..bffd061de8 100644 --- a/src/include/storage/checksum_impl.h +++ b/src/include/storage/checksum_impl.h @@ -8,7 +8,7 @@ * referenced by storage/checksum.h. (Note: you may need to redefine * Assert() as empty to compile this successfully externally.) * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/checksum_impl.h diff --git a/src/include/storage/condition_variable.h b/src/include/storage/condition_variable.h new file mode 100644 index 0000000000..e57cec7105 --- /dev/null +++ b/src/include/storage/condition_variable.h @@ -0,0 +1,59 @@ +/*------------------------------------------------------------------------- + * + * condition_variable.h + * Condition variables + * + * A condition variable is a method of waiting until a certain condition + * becomes true. Conventionally, a condition variable supports three + * operations: (1) sleep; (2) signal, which wakes up one process sleeping + * on the condition variable; and (3) broadcast, which wakes up every + * process sleeping on the condition variable. In our implementation, + * condition variables put a process into an interruptible sleep (so it + * can be cancelled prior to the fulfillment of the condition) and do not + * use pointers internally (so that they are safe to use within DSMs). + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/condition_variable.h + * + *------------------------------------------------------------------------- + */ +#ifndef CONDITION_VARIABLE_H +#define CONDITION_VARIABLE_H + +#include "storage/s_lock.h" +#include "storage/proclist_types.h" + +typedef struct +{ + slock_t mutex; + proclist_head wakeup; +} ConditionVariable; + +/* Initialize a condition variable. */ +extern void ConditionVariableInit(ConditionVariable *); + +/* + * To sleep on a condition variable, a process should use a loop which first + * checks the condition, exiting the loop if it is met, and then calls + * ConditionVariableSleep. Spurious wakeups are possible, but should be + * infrequent. After exiting the loop, ConditionVariableCancelSleep should + * be called to ensure that the process is no longer in the wait list for + * the condition variable. + */ +extern void ConditionVariableSleep(ConditionVariable *, uint32 wait_event_info); +extern void ConditionVariableCancelSleep(void); + +/* + * The use of this function is optional and not necessary for correctness; + * for efficiency, it should be called prior entering the loop described above + * if it is thought that the condition is unlikely to hold immediately. + */ +extern void ConditionVariablePrepareToSleep(ConditionVariable *); + +/* Wake up a single waiter (via signal) or all waiters (via broadcast). */ +extern bool ConditionVariableSignal(ConditionVariable *); +extern int ConditionVariableBroadcast(ConditionVariable *); + +#endif /* CONDITION_VARIABLE_H */ diff --git a/src/include/storage/copydir.h b/src/include/storage/copydir.h index 4b7b813e7e..c3722b4033 100644 --- a/src/include/storage/copydir.h +++ b/src/include/storage/copydir.h @@ -3,7 +3,7 @@ * copydir.h * Copy a directory. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/copydir.h diff --git a/src/include/storage/dsm.h b/src/include/storage/dsm.h index 86ede7a7e7..7d1250c1e0 100644 --- a/src/include/storage/dsm.h +++ b/src/include/storage/dsm.h @@ -3,7 +3,7 @@ * dsm.h * manage dynamic shared memory segments * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/dsm.h @@ -19,6 +19,9 @@ typedef struct dsm_segment dsm_segment; #define DSM_CREATE_NULL_IF_MAXSEGMENTS 0x0001 +/* A sentinel value for an invalid DSM handle. */ +#define DSM_HANDLE_INVALID 0 + /* Startup and shutdown functions. */ struct PGShmemHeader; /* avoid including pg_shmem.h */ extern void dsm_cleanup_using_control_segment(dsm_handle old_control_handle); @@ -41,6 +44,7 @@ extern void dsm_detach(dsm_segment *seg); extern void dsm_pin_mapping(dsm_segment *seg); extern void dsm_unpin_mapping(dsm_segment *seg); extern void dsm_pin_segment(dsm_segment *seg); +extern void dsm_unpin_segment(dsm_handle h); extern dsm_segment *dsm_find_mapping(dsm_handle h); /* Informational functions. */ diff --git a/src/include/storage/dsm_impl.h b/src/include/storage/dsm_impl.h index ec05e22a6b..51c217899d 100644 --- a/src/include/storage/dsm_impl.h +++ b/src/include/storage/dsm_impl.h @@ -3,7 +3,7 @@ * dsm_impl.h * low-level dynamic shared memory primitives * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/dsm_impl.h @@ -73,6 +73,8 @@ extern bool dsm_impl_op(dsm_op op, dsm_handle handle, Size request_size, extern bool dsm_impl_can_resize(void); /* Implementation-dependent actions required to keep segment until shutdown. */ -extern void dsm_impl_pin_segment(dsm_handle handle, void *impl_private); +extern void dsm_impl_pin_segment(dsm_handle handle, void *impl_private, + void **impl_private_pm_handle); +extern void dsm_impl_unpin_segment(dsm_handle handle, void **impl_private); #endif /* DSM_IMPL_H */ diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h index cbc2224685..1a43a2c844 100644 --- a/src/include/storage/fd.h +++ b/src/include/storage/fd.h @@ -4,7 +4,7 @@ * Virtual file descriptor definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/fd.h diff --git a/src/include/storage/freespace.h b/src/include/storage/freespace.h index 77b3bc3dc7..9a5c9f4be4 100644 --- a/src/include/storage/freespace.h +++ b/src/include/storage/freespace.h @@ -4,7 +4,7 @@ * POSTGRES free space map for quickly finding free space in relations * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/freespace.h diff --git a/src/include/storage/fsm_internals.h b/src/include/storage/fsm_internals.h index 58383eed1f..4eb3fc12b1 100644 --- a/src/include/storage/fsm_internals.h +++ b/src/include/storage/fsm_internals.h @@ -4,7 +4,7 @@ * internal functions for free space map * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/fsm_internals.h diff --git a/src/include/storage/indexfsm.h b/src/include/storage/indexfsm.h index 3cb2fc857d..b256ee6aef 100644 --- a/src/include/storage/indexfsm.h +++ b/src/include/storage/indexfsm.h @@ -4,7 +4,7 @@ * POSTGRES free space map for quickly finding an unused page in index * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/indexfsm.h diff --git a/src/include/storage/ipc.h b/src/include/storage/ipc.h index 7a07bd29ce..8d5a6b2698 100644 --- a/src/include/storage/ipc.h +++ b/src/include/storage/ipc.h @@ -8,7 +8,7 @@ * exit-time cleanup for either a postmaster or a backend. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/ipc.h diff --git a/src/include/storage/item.h b/src/include/storage/item.h index e10448c343..d19e19e01b 100644 --- a/src/include/storage/item.h +++ b/src/include/storage/item.h @@ -4,7 +4,7 @@ * POSTGRES disk item definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/item.h diff --git a/src/include/storage/itemid.h b/src/include/storage/itemid.h index 509c577926..af77852cc0 100644 --- a/src/include/storage/itemid.h +++ b/src/include/storage/itemid.h @@ -4,7 +4,7 @@ * Standard POSTGRES buffer page item identifier definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/itemid.h diff --git a/src/include/storage/itemptr.h b/src/include/storage/itemptr.h index 7ec7ed30c9..576aaa890b 100644 --- a/src/include/storage/itemptr.h +++ b/src/include/storage/itemptr.h @@ -4,7 +4,7 @@ * POSTGRES disk item pointer definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/itemptr.h @@ -30,9 +30,8 @@ * structure padding bytes. The struct is designed to be six bytes long * (it contains three int16 fields) but a few compilers will pad it to * eight bytes unless coerced. We apply appropriate persuasion where - * possible, and to cope with unpersuadable compilers, we try to use - * "SizeOfIptrData" rather than "sizeof(ItemPointerData)" when computing - * on-disk sizes. + * possible. If your compiler can't be made to play along, you'll waste + * lots of space. */ typedef struct ItemPointerData { @@ -46,9 +45,6 @@ pg_attribute_aligned(2) #endif ItemPointerData; -#define SizeOfIptrData \ - (offsetof(ItemPointerData, ip_posid) + sizeof(OffsetNumber)) - typedef ItemPointerData *ItemPointer; /* ---------------- diff --git a/src/include/storage/large_object.h b/src/include/storage/large_object.h index 6a4f3f6d1f..fc55019b98 100644 --- a/src/include/storage/large_object.h +++ b/src/include/storage/large_object.h @@ -5,7 +5,7 @@ * zillions of large objects (internal, external, jaquith, inversion). * Now we only support inversion. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/large_object.h diff --git a/src/include/storage/latch.h b/src/include/storage/latch.h index 5179ecc0db..3158d7bec6 100644 --- a/src/include/storage/latch.h +++ b/src/include/storage/latch.h @@ -90,7 +90,7 @@ * efficient than using WaitLatch or WaitLatchOrSocket. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/latch.h @@ -133,6 +133,9 @@ typedef struct WaitEvent uint32 events; /* triggered events */ pgsocket fd; /* socket fd associated with event */ void *user_data; /* pointer provided in AddWaitEventToSet */ +#ifdef WIN32 + bool reset; /* Is reset of the event required? */ +#endif } WaitEvent; /* forward declaration to avoid exposing latch.c implementation details */ @@ -155,10 +158,13 @@ extern int AddWaitEventToSet(WaitEventSet *set, uint32 events, pgsocket fd, Latch *latch, void *user_data); extern void ModifyWaitEvent(WaitEventSet *set, int pos, uint32 events, Latch *latch); -extern int WaitEventSetWait(WaitEventSet *set, long timeout, WaitEvent *occurred_events, int nevents); -extern int WaitLatch(volatile Latch *latch, int wakeEvents, long timeout); +extern int WaitEventSetWait(WaitEventSet *set, long timeout, + WaitEvent *occurred_events, int nevents, + uint32 wait_event_info); +extern int WaitLatch(volatile Latch *latch, int wakeEvents, long timeout, + uint32 wait_event_info); extern int WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, - pgsocket sock, long timeout); + pgsocket sock, long timeout, uint32 wait_event_info); /* * Unix implementation uses SIGUSR1 for inter-process signaling. diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h index 8288e7d505..2a1244c836 100644 --- a/src/include/storage/lmgr.h +++ b/src/include/storage/lmgr.h @@ -4,7 +4,7 @@ * POSTGRES lock manager definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/lmgr.h diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h index efa75ecca9..7a9c105519 100644 --- a/src/include/storage/lock.h +++ b/src/include/storage/lock.h @@ -4,7 +4,7 @@ * POSTGRES low-level lock mechanism * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/lock.h diff --git a/src/include/storage/lockdefs.h b/src/include/storage/lockdefs.h index dd7cb164c8..bfeb8779f7 100644 --- a/src/include/storage/lockdefs.h +++ b/src/include/storage/lockdefs.h @@ -7,7 +7,7 @@ * contains definition that have to (indirectly) be available when included by * FRONTEND code. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/lockdefs.h diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h index 3db11e43f0..8bd93c3b81 100644 --- a/src/include/storage/lwlock.h +++ b/src/include/storage/lwlock.h @@ -4,7 +4,7 @@ * Lightweight lock manager * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/lwlock.h @@ -18,38 +18,12 @@ #error "lwlock.h may not be included from frontend code" #endif -#include "lib/ilist.h" +#include "storage/proclist_types.h" #include "storage/s_lock.h" #include "port/atomics.h" struct PGPROC; -/* - * Prior to PostgreSQL 9.4, every lightweight lock in the system was stored - * in a single array. For convenience and for compatibility with past - * releases, we still have a main array, but it's now also permissible to - * store LWLocks elsewhere in the main shared memory segment or in a dynamic - * shared memory segment. Each array of lwlocks forms a separate "tranche". - * - * It's occasionally necessary to identify a particular LWLock "by name"; e.g. - * because we wish to report the lock to dtrace. We could store a name or - * other identifying information in the lock itself, but since it's common - * to have many nearly-identical locks (e.g. one per buffer) this would end - * up wasting significant amounts of memory. Instead, each lwlock stores a - * tranche ID which tells us which array it's part of. Based on that, we can - * figure out where the lwlock lies within the array using the data structure - * shown below; the lock is then identified based on the tranche name and - * computed array index. We need the array stride because the array might not - * be an array of lwlocks, but rather some larger data structure that includes - * one or more lwlocks per element. - */ -typedef struct LWLockTranche -{ - const char *name; - void *array_base; - Size array_stride; -} LWLockTranche; - /* * Code outside of lwlock.c should not manipulate the contents of this * structure directly, but we have to declare it here to allow LWLocks to be @@ -59,7 +33,7 @@ typedef struct LWLock { uint16 tranche; /* tranche ID */ pg_atomic_uint32 state; /* state of exclusive/nonexclusive lockers */ - dlist_head waiters; /* list of waiting PGPROCs */ + proclist_head waiters; /* list of waiting PGPROCs */ #ifdef LOCK_DEBUG pg_atomic_uint32 nwaiters; /* number of waiters */ struct PGPROC *owner; /* last exclusive owner of the lock */ @@ -84,16 +58,17 @@ typedef struct LWLock * LWLockPadded can be used for cases where we want each lock to be an entire * cache line. * - * On 32-bit platforms, an LWLockMinimallyPadded might actually contain more - * than the absolute minimum amount of padding required to keep a lock from - * crossing a cache line boundary, because an unpadded LWLock might fit into - * 16 bytes. We ignore that possibility when determining the minimal amount - * of padding. Older releases had larger LWLocks, so 32 really was the - * minimum, and packing them in tighter might hurt performance. + * An LWLockMinimallyPadded might contain more than the absolute minimum amount + * of padding required to keep a lock from crossing a cache line boundary, + * because an unpadded LWLock will normally fit into 16 bytes. We ignore that + * possibility when determining the minimal amount of padding. Older releases + * had larger LWLocks, so 32 really was the minimum, and packing them in + * tighter might hurt performance. * * LWLOCK_MINIMAL_SIZE should be 32 on basically all common platforms, but - * because slock_t is more than 2 bytes on some obscure platforms, we allow - * for the possibility that it might be 64. + * because pg_atomic_uint32 is more than 4 bytes on some obscure platforms, we + * allow for the possibility that it might be 64. Even on those platforms, + * we probably won't exceed 32 bytes unless LOCK_DEBUG is defined. */ #define LWLOCK_PADDED_SIZE PG_CACHE_LINE_SIZE #define LWLOCK_MINIMAL_SIZE (sizeof(LWLock) <= 32 ? 32 : 64) @@ -118,8 +93,8 @@ extern char *MainLWLockNames[]; /* struct for storing named tranche information */ typedef struct NamedLWLockTranche { - LWLockTranche lwLockTranche; int trancheId; + char *trancheName; } NamedLWLockTranche; extern PGDLLIMPORT NamedLWLockTranche *NamedLWLockTrancheArray; @@ -175,6 +150,7 @@ extern void LWLockRelease(LWLock *lock); extern void LWLockReleaseClearVar(LWLock *lock, uint64 *valptr, uint64 val); extern void LWLockReleaseAll(void); extern bool LWLockHeldByMe(LWLock *lock); +extern bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode); extern bool LWLockWaitForVar(LWLock *lock, uint64 *valptr, uint64 oldval, uint64 *newval); extern void LWLockUpdateVar(LWLock *lock, uint64 *valptr, uint64 value); @@ -183,7 +159,7 @@ extern Size LWLockShmemSize(void); extern void CreateLWLocks(void); extern void InitLWLockAccess(void); -extern const char *GetLWLockIdentifier(uint8 classId, uint16 eventId); +extern const char *GetLWLockIdentifier(uint32 classId, uint16 eventId); /* * Extensions (or core code) can obtain an LWLocks by calling @@ -198,9 +174,9 @@ extern LWLockPadded *GetNamedLWLockTranche(const char *tranche_name); * There is another, more flexible method of obtaining lwlocks. First, call * LWLockNewTrancheId just once to obtain a tranche ID; this allocates from * a shared counter. Next, each individual process using the tranche should - * call LWLockRegisterTranche() to associate that tranche ID with appropriate - * metadata. Finally, LWLockInitialize should be called just once per lwlock, - * passing the tranche ID as an argument. + * call LWLockRegisterTranche() to associate that tranche ID with a name. + * Finally, LWLockInitialize should be called just once per lwlock, passing + * the tranche ID as an argument. * * It may seem strange that each process using the tranche must register it * separately, but dynamic shared memory segments aren't guaranteed to be @@ -208,17 +184,18 @@ extern LWLockPadded *GetNamedLWLockTranche(const char *tranche_name); * registration in the main shared memory segment wouldn't work for that case. */ extern int LWLockNewTrancheId(void); -extern void LWLockRegisterTranche(int tranche_id, LWLockTranche *tranche); +extern void LWLockRegisterTranche(int tranche_id, char *tranche_name); extern void LWLockInitialize(LWLock *lock, int tranche_id); /* - * We reserve a few predefined tranche IDs. A call to LWLockNewTrancheId - * will never return a value less than LWTRANCHE_FIRST_USER_DEFINED. + * Every tranche ID less than NUM_INDIVIDUAL_LWLOCKS is reserved; also, + * we reserve additional tranche IDs for builtin tranches not included in + * the set of individual LWLocks. A call to LWLockNewTrancheId will never + * return a value less than LWTRANCHE_FIRST_USER_DEFINED. */ typedef enum BuiltinTrancheIds { - LWTRANCHE_MAIN, - LWTRANCHE_CLOG_BUFFERS, + LWTRANCHE_CLOG_BUFFERS = NUM_INDIVIDUAL_LWLOCKS, LWTRANCHE_COMMITTS_BUFFERS, LWTRANCHE_SUBTRANS_BUFFERS, LWTRANCHE_MXACTOFFSET_BUFFERS, @@ -234,6 +211,7 @@ typedef enum BuiltinTrancheIds LWTRANCHE_BUFFER_MAPPING, LWTRANCHE_LOCK_MANAGER, LWTRANCHE_PREDICATE_LOCK_MANAGER, + LWTRANCHE_PARALLEL_QUERY_DSA, LWTRANCHE_FIRST_USER_DEFINED } BuiltinTrancheIds; diff --git a/src/include/storage/off.h b/src/include/storage/off.h index 9f707930d7..fe8638fe15 100644 --- a/src/include/storage/off.h +++ b/src/include/storage/off.h @@ -4,7 +4,7 @@ * POSTGRES disk "offset" definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/off.h diff --git a/src/include/storage/pg_sema.h b/src/include/storage/pg_sema.h index 2c9418320e..b819f41d19 100644 --- a/src/include/storage/pg_sema.h +++ b/src/include/storage/pg_sema.h @@ -10,7 +10,7 @@ * be provided by each port. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/pg_sema.h @@ -21,52 +21,30 @@ #define PG_SEMA_H /* - * PGSemaphoreData and pointer type PGSemaphore are the data structure - * representing an individual semaphore. The contents of PGSemaphoreData - * vary across implementations and must never be touched by platform- - * independent code. PGSemaphoreData structures are always allocated - * in shared memory (to support implementations where the data changes during - * lock/unlock). + * struct PGSemaphoreData and pointer type PGSemaphore are the data structure + * representing an individual semaphore. The contents of PGSemaphoreData vary + * across implementations and must never be touched by platform-independent + * code; hence, PGSemaphoreData is declared as an opaque struct here. * - * pg_config.h must define exactly one of the USE_xxx_SEMAPHORES symbols. + * However, Windows is sufficiently unlike our other ports that it doesn't + * seem worth insisting on ABI compatibility for Windows too. Hence, on + * that platform just define PGSemaphore as HANDLE. */ - -#ifdef USE_NAMED_POSIX_SEMAPHORES - -#include - -typedef sem_t *PGSemaphoreData; -#endif - -#ifdef USE_UNNAMED_POSIX_SEMAPHORES - -#include - -typedef sem_t PGSemaphoreData; -#endif - -#ifdef USE_SYSV_SEMAPHORES - -typedef struct PGSemaphoreData -{ - int semId; /* semaphore set identifier */ - int semNum; /* semaphore number within set */ -} PGSemaphoreData; -#endif - -#ifdef USE_WIN32_SEMAPHORES - -typedef HANDLE PGSemaphoreData; +#ifndef USE_WIN32_SEMAPHORES +typedef struct PGSemaphoreData *PGSemaphore; +#else +typedef HANDLE PGSemaphore; #endif -typedef PGSemaphoreData *PGSemaphore; +/* Report amount of shared memory needed */ +extern Size PGSemaphoreShmemSize(int maxSemas); /* Module initialization (called during postmaster start or shmem reinit) */ extern void PGReserveSemaphores(int maxSemas, int port); -/* Initialize a PGSemaphore structure to represent a sema with count 1 */ -extern void PGSemaphoreCreate(PGSemaphore sema); +/* Allocate a PGSemaphore structure with initial count 1 */ +extern PGSemaphore PGSemaphoreCreate(void); /* Reset a previously-initialized PGSemaphore to have count 0 */ extern void PGSemaphoreReset(PGSemaphore sema); diff --git a/src/include/storage/pg_shmem.h b/src/include/storage/pg_shmem.h index 6bf803ab88..a329c81899 100644 --- a/src/include/storage/pg_shmem.h +++ b/src/include/storage/pg_shmem.h @@ -14,7 +14,7 @@ * only one ID number. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/pg_shmem.h diff --git a/src/include/storage/pmsignal.h b/src/include/storage/pmsignal.h index b53504ae50..90ddfa3b31 100644 --- a/src/include/storage/pmsignal.h +++ b/src/include/storage/pmsignal.h @@ -4,7 +4,7 @@ * routines for signaling the postmaster from its child processes * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/pmsignal.h diff --git a/src/include/storage/pos.h b/src/include/storage/pos.h deleted file mode 100644 index 9f9ba6d264..0000000000 --- a/src/include/storage/pos.h +++ /dev/null @@ -1,64 +0,0 @@ -/*------------------------------------------------------------------------- - * - * pos.h - * POSTGRES "position" definitions. - * - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * src/include/storage/pos.h - * - *------------------------------------------------------------------------- - */ -#ifndef POS_H -#define POS_H - - -/* - * a 'position' used to be in postgres. this has - * been changed to just as the notion of having multiple pages - * within a block has been removed. - * - * the 'offset' abstraction is somewhat confusing. it is NOT a byte - * offset within the page; instead, it is an offset into the line - * pointer array contained on every page that store (heap or index) - * tuples. - */ -typedef bits16 PositionIdData; -typedef PositionIdData *PositionId; - -/* ---------------- - * support macros - * ---------------- - */ - -/* - * PositionIdIsValid - * True iff the position identifier is valid. - */ -#define PositionIdIsValid(positionId) \ - PointerIsValid(positionId) - -/* - * PositionIdSetInvalid - * Make an invalid position. - */ -#define PositionIdSetInvalid(positionId) \ - *(positionId) = (bits16) 0 - -/* - * PositionIdSet - * Sets a position identifier to the specified value. - */ -#define PositionIdSet(positionId, offsetNumber) \ - *(positionId) = (offsetNumber) - -/* - * PositionIdGetOffsetNumber - * Retrieve the offset number from a position identifier. - */ -#define PositionIdGetOffsetNumber(positionId) \ - ((OffsetNumber) *(positionId)) - -#endif /* POS_H */ diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h index a66b5b7134..f996d8e818 100644 --- a/src/include/storage/predicate.h +++ b/src/include/storage/predicate.h @@ -4,7 +4,7 @@ * POSTGRES public predicate locking definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/predicate.h diff --git a/src/include/storage/predicate_internals.h b/src/include/storage/predicate_internals.h index 3175d286d3..408d94cc7a 100644 --- a/src/include/storage/predicate_internals.h +++ b/src/include/storage/predicate_internals.h @@ -4,7 +4,7 @@ * POSTGRES internal predicate locking definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/predicate_internals.h diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 775c66a197..398fa8afde 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -4,7 +4,7 @@ * per-process shared memory data structures * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/proc.h @@ -19,6 +19,7 @@ #include "storage/latch.h" #include "storage/lock.h" #include "storage/pg_sema.h" +#include "storage/proclist_types.h" /* * Each backend advertises up to PGPROC_MAX_CACHED_SUBXIDS TransactionIds @@ -86,7 +87,7 @@ struct PGPROC SHM_QUEUE links; /* list link if process is in a list */ PGPROC **procgloballist; /* procglobal list that owns this PGPROC */ - PGSemaphoreData sem; /* ONE semaphore to sleep on */ + PGSemaphore sem; /* ONE semaphore to sleep on */ int waitStatus; /* STATUS_WAITING, STATUS_OK or STATUS_ERROR */ Latch procLatch; /* generic latch for process */ @@ -112,7 +113,10 @@ struct PGPROC /* Info about LWLock the process is currently waiting for, if any. */ bool lwWaiting; /* true if waiting for an LW lock */ uint8 lwWaitMode; /* lwlock mode being waited for */ - dlist_node lwWaitLink; /* position in LW lock wait list */ + proclist_node lwWaitLink; /* position in LW lock wait list */ + + /* Support for condition variables. */ + proclist_node cvWaitLink; /* position in CV wait list */ /* Info about lock the process is currently waiting for, if any. */ /* waitLock and waitProcLock are NULL if not currently waiting. */ @@ -243,6 +247,9 @@ extern PROC_HDR *ProcGlobal; extern PGPROC *PreparedXactProcs; +/* Accessor for PGPROC given a pgprocno. */ +#define GetPGProcByNumber(n) (&ProcGlobal->allProcs[(n)]) + /* * We set aside some extra PGPROC structures for auxiliary processes, * ie things that aren't full-fledged backends but need shmem access. @@ -287,7 +294,7 @@ extern void CheckDeadLockAlert(void); extern bool IsWaitingForLock(void); extern void LockErrorCleanup(void); -extern void ProcWaitForSignal(void); +extern void ProcWaitForSignal(uint32 wait_event_info); extern void ProcSendSignal(int pid); extern void BecomeLockGroupLeader(void); diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h index dd37c0cb07..0d5027fa64 100644 --- a/src/include/storage/procarray.h +++ b/src/include/storage/procarray.h @@ -4,7 +4,7 @@ * POSTGRES process array definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/procarray.h diff --git a/src/include/storage/proclist.h b/src/include/storage/proclist.h new file mode 100644 index 0000000000..9f22f3fd48 --- /dev/null +++ b/src/include/storage/proclist.h @@ -0,0 +1,208 @@ +/*------------------------------------------------------------------------- + * + * proclist.h + * operations on doubly-linked lists of pgprocnos + * + * The interface is similar to dlist from ilist.h, but uses pgprocno instead + * of pointers. This allows proclist_head to be mapped at different addresses + * in different backends. + * + * See proclist_types.h for the structs that these functions operate on. They + * are separated to break a header dependency cycle with proc.h. + * + * Portions Copyright (c) 2016-2017, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/storage/proclist.h + *------------------------------------------------------------------------- + */ +#ifndef PROCLIST_H +#define PROCLIST_H + +#include "storage/proc.h" +#include "storage/proclist_types.h" + +/* + * Initialize a proclist. + */ +static inline void +proclist_init(proclist_head *list) +{ + list->head = list->tail = INVALID_PGPROCNO; +} + +/* + * Is the list empty? + */ +static inline bool +proclist_is_empty(proclist_head *list) +{ + return list->head == INVALID_PGPROCNO; +} + +/* + * Get a pointer to a proclist_node inside a given PGPROC, given a procno and + * an offset. + */ +static inline proclist_node * +proclist_node_get(int procno, size_t node_offset) +{ + char *entry = (char *) GetPGProcByNumber(procno); + + return (proclist_node *) (entry + node_offset); +} + +/* + * Insert a node at the beginning of a list. + */ +static inline void +proclist_push_head_offset(proclist_head *list, int procno, size_t node_offset) +{ + proclist_node *node = proclist_node_get(procno, node_offset); + + if (list->head == INVALID_PGPROCNO) + { + Assert(list->tail == INVALID_PGPROCNO); + node->next = node->prev = INVALID_PGPROCNO; + list->head = list->tail = procno; + } + else + { + Assert(list->tail != INVALID_PGPROCNO); + Assert(list->head != procno); + Assert(list->tail != procno); + node->next = list->head; + proclist_node_get(node->next, node_offset)->prev = procno; + node->prev = INVALID_PGPROCNO; + list->head = procno; + } +} + +/* + * Insert a node at the end of a list. + */ +static inline void +proclist_push_tail_offset(proclist_head *list, int procno, size_t node_offset) +{ + proclist_node *node = proclist_node_get(procno, node_offset); + + if (list->tail == INVALID_PGPROCNO) + { + Assert(list->head == INVALID_PGPROCNO); + node->next = node->prev = INVALID_PGPROCNO; + list->head = list->tail = procno; + } + else + { + Assert(list->head != INVALID_PGPROCNO); + Assert(list->head != procno); + Assert(list->tail != procno); + node->prev = list->tail; + proclist_node_get(node->prev, node_offset)->next = procno; + node->next = INVALID_PGPROCNO; + list->tail = procno; + } +} + +/* + * Delete a node. The node must be in the list. + */ +static inline void +proclist_delete_offset(proclist_head *list, int procno, size_t node_offset) +{ + proclist_node *node = proclist_node_get(procno, node_offset); + + if (node->prev == INVALID_PGPROCNO) + list->head = node->next; + else + proclist_node_get(node->prev, node_offset)->next = node->next; + + if (node->next == INVALID_PGPROCNO) + list->tail = node->prev; + else + proclist_node_get(node->next, node_offset)->prev = node->prev; + + node->next = node->prev = INVALID_PGPROCNO; +} + +/* + * Check if a node is currently in a list. It must be known that the node is + * not in any _other_ proclist that uses the same proclist_node, so that the + * only possibilities are that it is in this list or none. + */ +static inline bool +proclist_contains_offset(proclist_head *list, int procno, + size_t node_offset) +{ + proclist_node *node = proclist_node_get(procno, node_offset); + + /* + * If this is not a member of a proclist, then the next and prev pointers + * should be 0. Circular lists are not allowed so this condition is not + * confusable with a real pgprocno 0. + */ + if (node->prev == 0 && node->next == 0) + return false; + + /* If there is a previous node, then this node must be in the list. */ + if (node->prev != INVALID_PGPROCNO) + return true; + + /* + * There is no previous node, so the only way this node can be in the list + * is if it's the head node. + */ + return list->head == procno; +} + +/* + * Remove and return the first node from a list (there must be one). + */ +static inline PGPROC * +proclist_pop_head_node_offset(proclist_head *list, size_t node_offset) +{ + PGPROC *proc; + + Assert(!proclist_is_empty(list)); + proc = GetPGProcByNumber(list->head); + proclist_delete_offset(list, list->head, node_offset); + return proc; +} + +/* + * Helper macros to avoid repetition of offsetof(PGPROC, ). + * 'link_member' is the name of a proclist_node member in PGPROC. + */ +#define proclist_delete(list, procno, link_member) \ + proclist_delete_offset((list), (procno), offsetof(PGPROC, link_member)) +#define proclist_push_head(list, procno, link_member) \ + proclist_push_head_offset((list), (procno), offsetof(PGPROC, link_member)) +#define proclist_push_tail(list, procno, link_member) \ + proclist_push_tail_offset((list), (procno), offsetof(PGPROC, link_member)) +#define proclist_pop_head_node(list, link_member) \ + proclist_pop_head_node_offset((list), offsetof(PGPROC, link_member)) +#define proclist_contains(list, procno, link_member) \ + proclist_contains_offset((list), (procno), offsetof(PGPROC, link_member)) + +/* + * Iterate through the list pointed at by 'lhead', storing the current + * position in 'iter'. 'link_member' is the name of a proclist_node member in + * PGPROC. Access the current position with iter.cur. + * + * The only list modification allowed while iterating is deleting the current + * node with proclist_delete(list, iter.cur, node_offset). + */ +#define proclist_foreach_modify(iter, lhead, link_member) \ + for (AssertVariableIsOfTypeMacro(iter, proclist_mutable_iter), \ + AssertVariableIsOfTypeMacro(lhead, proclist_head *), \ + (iter).cur = (lhead)->head, \ + (iter).next = (iter).cur == INVALID_PGPROCNO ? INVALID_PGPROCNO : \ + proclist_node_get((iter).cur, \ + offsetof(PGPROC, link_member))->next; \ + (iter).cur != INVALID_PGPROCNO; \ + (iter).cur = (iter).next, \ + (iter).next = (iter).cur == INVALID_PGPROCNO ? INVALID_PGPROCNO : \ + proclist_node_get((iter).cur, \ + offsetof(PGPROC, link_member))->next) + +#endif diff --git a/src/include/storage/proclist_types.h b/src/include/storage/proclist_types.h new file mode 100644 index 0000000000..716c4498d5 --- /dev/null +++ b/src/include/storage/proclist_types.h @@ -0,0 +1,45 @@ +/*------------------------------------------------------------------------- + * + * proclist_types.h + * doubly-linked lists of pgprocnos + * + * See proclist.h for functions that operate on these types. + * + * Portions Copyright (c) 2016-2017, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/storage/proclist_types.h + *------------------------------------------------------------------------- + */ + +#ifndef PROCLIST_TYPES_H +#define PROCLIST_TYPES_H + +/* + * A node in a list of processes. + */ +typedef struct proclist_node +{ + int next; /* pgprocno of the next PGPROC */ + int prev; /* pgprocno of the prev PGPROC */ +} proclist_node; + +/* + * Head of a doubly-linked list of PGPROCs, identified by pgprocno. + */ +typedef struct proclist_head +{ + int head; /* pgprocno of the head PGPROC */ + int tail; /* pgprocno of the tail PGPROC */ +} proclist_head; + +/* + * List iterator allowing some modifications while iterating. + */ +typedef struct proclist_mutable_iter +{ + int cur; /* pgprocno of the current PGPROC */ + int next; /* pgprocno of the next PGPROC */ +} proclist_mutable_iter; + +#endif diff --git a/src/include/storage/procsignal.h b/src/include/storage/procsignal.h index f67b9821f2..d068dde5d7 100644 --- a/src/include/storage/procsignal.h +++ b/src/include/storage/procsignal.h @@ -4,7 +4,7 @@ * Routines for interprocess signalling * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/procsignal.h diff --git a/src/include/storage/reinit.h b/src/include/storage/reinit.h index a228434dc4..8c1b178de4 100644 --- a/src/include/storage/reinit.h +++ b/src/include/storage/reinit.h @@ -4,7 +4,7 @@ * Reinitialization of unlogged relations * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/reinit.h diff --git a/src/include/storage/relfilenode.h b/src/include/storage/relfilenode.h index 130c73aaa2..4dc04092d7 100644 --- a/src/include/storage/relfilenode.h +++ b/src/include/storage/relfilenode.h @@ -4,7 +4,7 @@ * Physical access information for relations. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/relfilenode.h diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h index 7aad2de43d..f46cd49bab 100644 --- a/src/include/storage/s_lock.h +++ b/src/include/storage/s_lock.h @@ -86,7 +86,7 @@ * when using the SysV semaphore code. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/s_lock.h @@ -706,29 +706,6 @@ typedef unsigned char slock_t; #if !defined(HAS_TEST_AND_SET) /* We didn't trigger above, let's try here */ -#if defined(USE_UNIVEL_CC) /* Unixware compiler */ -#define HAS_TEST_AND_SET - -typedef unsigned char slock_t; - -#define TAS(lock) tas(lock) - -asm int -tas(volatile slock_t *s_lock) -{ -/* UNIVEL wants %mem in column 1, so we don't pgindent this file */ -%mem s_lock - pushl %ebx - movl s_lock, %ebx - movl $255, %eax - lock - xchgb %al, (%ebx) - popl %ebx -} - -#endif /* defined(USE_UNIVEL_CC) */ - - #if defined(__hppa) || defined(__hppa__) /* HP PA-RISC, GCC and HP compilers */ /* * HP's PA-RISC diff --git a/src/include/storage/shm_mq.h b/src/include/storage/shm_mq.h index 7ea25397b9..7a37535ab3 100644 --- a/src/include/storage/shm_mq.h +++ b/src/include/storage/shm_mq.h @@ -3,7 +3,7 @@ * shm_mq.h * single-reader, single-writer shared memory message queue * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/shm_mq.h diff --git a/src/include/storage/shm_toc.h b/src/include/storage/shm_toc.h index 6822f919c4..ae0a3878fe 100644 --- a/src/include/storage/shm_toc.h +++ b/src/include/storage/shm_toc.h @@ -12,7 +12,7 @@ * other data structure within the segment and only put the pointer to * the data structure itself in the table of contents. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/shm_toc.h diff --git a/src/include/storage/shmem.h b/src/include/storage/shmem.h index 6468e6627a..1961832c0f 100644 --- a/src/include/storage/shmem.h +++ b/src/include/storage/shmem.h @@ -11,7 +11,7 @@ * at the same address. This means shared memory pointers can be passed * around directly between different processes. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/shmem.h @@ -35,6 +35,8 @@ typedef struct SHM_QUEUE extern void InitShmemAccess(void *seghdr); extern void InitShmemAllocation(void); extern void *ShmemAlloc(Size size); +extern void *ShmemAllocNoError(Size size); +extern void *ShmemAllocUnlocked(Size size); extern bool ShmemAddrIsValid(const void *addr); extern void InitShmemIndex(void); extern HTAB *ShmemInitHash(const char *name, long init_size, long max_size, diff --git a/src/include/storage/sinval.h b/src/include/storage/sinval.h index 8d019dc0e7..6a3db9580f 100644 --- a/src/include/storage/sinval.h +++ b/src/include/storage/sinval.h @@ -4,7 +4,7 @@ * POSTGRES shared cache invalidation communication definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/sinval.h @@ -23,6 +23,7 @@ * * invalidate a specific tuple in a specific catcache * * invalidate all catcache entries from a given system catalog * * invalidate a relcache entry for a specific logical relation + * * invalidate all relcache entries * * invalidate an smgr cache entry for a specific physical relation * * invalidate the mapped-relation mapping for a given database * * invalidate any saved snapshot that might be used to scan a given relation @@ -78,7 +79,7 @@ typedef struct { int8 id; /* type field --- must be first */ Oid dbId; /* database ID, or 0 if a shared relation */ - Oid relId; /* relation ID */ + Oid relId; /* relation ID, or 0 if whole relcache */ } SharedInvalRelcacheMsg; #define SHAREDINVALSMGR_ID (-3) diff --git a/src/include/storage/sinvaladt.h b/src/include/storage/sinvaladt.h index b27f7e806b..07ac2f8c85 100644 --- a/src/include/storage/sinvaladt.h +++ b/src/include/storage/sinvaladt.h @@ -12,7 +12,7 @@ * The struct type SharedInvalidationMessage, defining the contents of * a single message, is defined in sinval.h. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/sinvaladt.h diff --git a/src/include/storage/smgr.h b/src/include/storage/smgr.h index a8e7877f70..9ce6829655 100644 --- a/src/include/storage/smgr.h +++ b/src/include/storage/smgr.h @@ -4,7 +4,7 @@ * storage manager switch public interface declarations. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/smgr.h @@ -64,8 +64,12 @@ typedef struct SMgrRelationData */ int smgr_which; /* storage manager selector */ - /* for md.c; NULL for forks that are not open */ - struct _MdfdVec *md_fd[MAX_FORKNUM + 1]; + /* + * for md.c; per-fork arrays of the number of open segments + * (md_num_open_segs) and the segments themselves (md_seg_fds). + */ + int md_num_open_segs[MAX_FORKNUM + 1]; + struct _MdfdVec *md_seg_fds[MAX_FORKNUM + 1]; /* if unowned, list link in list of all unowned SMgrRelations */ struct SMgrRelationData *next_unowned_reln; @@ -140,10 +144,4 @@ extern void RememberFsyncRequest(RelFileNode rnode, ForkNumber forknum, extern void ForgetRelationFsyncRequests(RelFileNode rnode, ForkNumber forknum); extern void ForgetDatabaseFsyncRequests(Oid dbid); -/* smgrtype.c */ -extern Datum smgrout(PG_FUNCTION_ARGS); -extern Datum smgrin(PG_FUNCTION_ARGS); -extern Datum smgreq(PG_FUNCTION_ARGS); -extern Datum smgrne(PG_FUNCTION_ARGS); - #endif /* SMGR_H */ diff --git a/src/include/storage/spin.h b/src/include/storage/spin.h index 50412258b9..8987c90537 100644 --- a/src/include/storage/spin.h +++ b/src/include/storage/spin.h @@ -41,7 +41,7 @@ * be again. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/spin.h @@ -70,8 +70,8 @@ extern int SpinlockSemas(void); extern Size SpinlockSemaSize(void); #ifndef HAVE_SPINLOCKS -extern void SpinlockSemaInit(PGSemaphore); -extern PGSemaphore SpinlockSemaArray; +extern void SpinlockSemaInit(void); +extern PGSemaphore *SpinlockSemaArray; #endif #endif /* SPIN_H */ diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h index dcebf72f85..3ecc446083 100644 --- a/src/include/storage/standby.h +++ b/src/include/storage/standby.h @@ -4,7 +4,7 @@ * Definitions for hot standby mode. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/standby.h diff --git a/src/include/storage/standbydefs.h b/src/include/storage/standbydefs.h index ea22d77e07..f8444c787a 100644 --- a/src/include/storage/standbydefs.h +++ b/src/include/storage/standbydefs.h @@ -4,7 +4,7 @@ * Frontend exposed definitions for hot standby mode. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/standbydefs.h diff --git a/src/include/tcop/deparse_utility.h b/src/include/tcop/deparse_utility.h index 046184d142..f0b25bea90 100644 --- a/src/include/tcop/deparse_utility.h +++ b/src/include/tcop/deparse_utility.h @@ -2,7 +2,7 @@ * * deparse_utility.h * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/tcop/deparse_utility.h diff --git a/src/include/tcop/dest.h b/src/include/tcop/dest.h index dd80433f74..4b43b118d3 100644 --- a/src/include/tcop/dest.h +++ b/src/include/tcop/dest.h @@ -57,7 +57,7 @@ * calls in portal and cursor manipulations. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/tcop/dest.h @@ -87,6 +87,7 @@ typedef enum { DestNone, /* results are discarded */ DestDebug, /* results go to debugging output */ + DestLog, /* introduced temporarily for test purposes */ DestRemote, /* results sent to frontend process */ DestRemoteExecute, /* sent to frontend, in Execute command */ DestSPI, /* results sent to SPI manager */ diff --git a/src/include/tcop/fastpath.h b/src/include/tcop/fastpath.h index df6234be89..af1e330f18 100644 --- a/src/include/tcop/fastpath.h +++ b/src/include/tcop/fastpath.h @@ -3,7 +3,7 @@ * fastpath.h * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/tcop/fastpath.h diff --git a/src/include/tcop/pquery.h b/src/include/tcop/pquery.h index e04fc4330d..61c0b3447e 100644 --- a/src/include/tcop/pquery.h +++ b/src/include/tcop/pquery.h @@ -4,7 +4,7 @@ * prototypes for pquery.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/tcop/pquery.h diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h index 7254355862..1958be85b7 100644 --- a/src/include/tcop/tcopprot.h +++ b/src/include/tcop/tcopprot.h @@ -4,7 +4,7 @@ * prototypes for postgres.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/tcop/tcopprot.h @@ -47,9 +47,10 @@ typedef enum extern int log_statement; extern List *pg_parse_query(const char *query_string); -extern List *pg_analyze_and_rewrite(Node *parsetree, const char *query_string, +extern List *pg_analyze_and_rewrite(RawStmt *parsetree, + const char *query_string, Oid *paramTypes, int numParams); -extern List *pg_analyze_and_rewrite_params(Node *parsetree, +extern List *pg_analyze_and_rewrite_params(RawStmt *parsetree, const char *query_string, ParserSetupHook parserSetup, void *parserSetupArg); diff --git a/src/include/tcop/utility.h b/src/include/tcop/utility.h index dad8246f46..4f8d353900 100644 --- a/src/include/tcop/utility.h +++ b/src/include/tcop/utility.h @@ -4,7 +4,7 @@ * prototypes for utility.c. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/tcop/utility.h @@ -24,16 +24,16 @@ typedef enum } ProcessUtilityContext; /* Hook for plugins to get control in ProcessUtility() */ -typedef void (*ProcessUtility_hook_type) (Node *parsetree, +typedef void (*ProcessUtility_hook_type) (PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag); extern PGDLLIMPORT ProcessUtility_hook_type ProcessUtility_hook; -extern void ProcessUtility(Node *parsetree, const char *queryString, +extern void ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag); -extern void standard_ProcessUtility(Node *parsetree, const char *queryString, +extern void standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag); @@ -47,6 +47,6 @@ extern const char *CreateCommandTag(Node *parsetree); extern LogStmtLevel GetCommandLogLevel(Node *parsetree); -extern bool CommandIsReadOnly(Node *parsetree); +extern bool CommandIsReadOnly(PlannedStmt *pstmt); #endif /* UTILITY_H */ diff --git a/src/include/tsearch/dicts/regis.h b/src/include/tsearch/dicts/regis.h index 5bbfad1d95..7fdf82af65 100644 --- a/src/include/tsearch/dicts/regis.h +++ b/src/include/tsearch/dicts/regis.h @@ -4,7 +4,7 @@ * * Declarations for fast regex subset, used by ISpell * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * src/include/tsearch/dicts/regis.h * diff --git a/src/include/tsearch/dicts/spell.h b/src/include/tsearch/dicts/spell.h index d1df1f9f4b..8cba645540 100644 --- a/src/include/tsearch/dicts/spell.h +++ b/src/include/tsearch/dicts/spell.h @@ -4,7 +4,7 @@ * * Declarations for ISpell dictionary * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * src/include/tsearch/dicts/spell.h * diff --git a/src/include/tsearch/ts_cache.h b/src/include/tsearch/ts_cache.h index 379893365f..80b8a079ed 100644 --- a/src/include/tsearch/ts_cache.h +++ b/src/include/tsearch/ts_cache.h @@ -3,7 +3,7 @@ * ts_cache.h * Tsearch related object caches. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/tsearch/ts_cache.h diff --git a/src/include/tsearch/ts_locale.h b/src/include/tsearch/ts_locale.h index 36cb4de40d..afcf2b93de 100644 --- a/src/include/tsearch/ts_locale.h +++ b/src/include/tsearch/ts_locale.h @@ -3,7 +3,7 @@ * ts_locale.h * locale compatibility layer for tsearch * - * Copyright (c) 1998-2016, PostgreSQL Global Development Group + * Copyright (c) 1998-2017, PostgreSQL Global Development Group * * src/include/tsearch/ts_locale.h * diff --git a/src/include/tsearch/ts_public.h b/src/include/tsearch/ts_public.h index b75a078ec5..4c190b22e8 100644 --- a/src/include/tsearch/ts_public.h +++ b/src/include/tsearch/ts_public.h @@ -4,7 +4,7 @@ * Public interface to various tsearch modules, such as * parsers and dictionaries. * - * Copyright (c) 1998-2016, PostgreSQL Global Development Group + * Copyright (c) 1998-2017, PostgreSQL Global Development Group * * src/include/tsearch/ts_public.h * diff --git a/src/include/tsearch/ts_type.h b/src/include/tsearch/ts_type.h index 5062aaafee..155650c6f3 100644 --- a/src/include/tsearch/ts_type.h +++ b/src/include/tsearch/ts_type.h @@ -3,7 +3,7 @@ * ts_type.h * Definitions for the tsvector and tsquery types * - * Copyright (c) 1998-2016, PostgreSQL Global Development Group + * Copyright (c) 1998-2017, PostgreSQL Global Development Group * * src/include/tsearch/ts_type.h * @@ -121,61 +121,6 @@ typedef TSVectorData *TSVector; #define PG_GETARG_TSVECTOR_COPY(n) DatumGetTSVectorCopy(PG_GETARG_DATUM(n)) #define PG_RETURN_TSVECTOR(x) return TSVectorGetDatum(x) -/* - * I/O - */ -extern Datum tsvectorin(PG_FUNCTION_ARGS); -extern Datum tsvectorout(PG_FUNCTION_ARGS); -extern Datum tsvectorsend(PG_FUNCTION_ARGS); -extern Datum tsvectorrecv(PG_FUNCTION_ARGS); - -/* - * operations with tsvector - */ -extern Datum tsvector_lt(PG_FUNCTION_ARGS); -extern Datum tsvector_le(PG_FUNCTION_ARGS); -extern Datum tsvector_eq(PG_FUNCTION_ARGS); -extern Datum tsvector_ne(PG_FUNCTION_ARGS); -extern Datum tsvector_ge(PG_FUNCTION_ARGS); -extern Datum tsvector_gt(PG_FUNCTION_ARGS); -extern Datum tsvector_cmp(PG_FUNCTION_ARGS); - -extern Datum tsvector_length(PG_FUNCTION_ARGS); -extern Datum tsvector_strip(PG_FUNCTION_ARGS); -extern Datum tsvector_setweight(PG_FUNCTION_ARGS); -extern Datum tsvector_setweight_by_filter(PG_FUNCTION_ARGS); -extern Datum tsvector_concat(PG_FUNCTION_ARGS); -extern Datum tsvector_delete_str(PG_FUNCTION_ARGS); -extern Datum tsvector_delete_arr(PG_FUNCTION_ARGS); -extern Datum tsvector_unnest(PG_FUNCTION_ARGS); -extern Datum tsvector_to_array(PG_FUNCTION_ARGS); -extern Datum array_to_tsvector(PG_FUNCTION_ARGS); -extern Datum tsvector_filter(PG_FUNCTION_ARGS); -extern Datum tsvector_update_trigger_byid(PG_FUNCTION_ARGS); -extern Datum tsvector_update_trigger_bycolumn(PG_FUNCTION_ARGS); - -extern Datum ts_match_vq(PG_FUNCTION_ARGS); -extern Datum ts_match_qv(PG_FUNCTION_ARGS); -extern Datum ts_match_tt(PG_FUNCTION_ARGS); -extern Datum ts_match_tq(PG_FUNCTION_ARGS); - -extern Datum ts_stat1(PG_FUNCTION_ARGS); -extern Datum ts_stat2(PG_FUNCTION_ARGS); - -extern Datum ts_rank_tt(PG_FUNCTION_ARGS); -extern Datum ts_rank_wtt(PG_FUNCTION_ARGS); -extern Datum ts_rank_ttf(PG_FUNCTION_ARGS); -extern Datum ts_rank_wttf(PG_FUNCTION_ARGS); -extern Datum ts_rankcd_tt(PG_FUNCTION_ARGS); -extern Datum ts_rankcd_wtt(PG_FUNCTION_ARGS); -extern Datum ts_rankcd_ttf(PG_FUNCTION_ARGS); -extern Datum ts_rankcd_wttf(PG_FUNCTION_ARGS); - -extern Datum tsmatchsel(PG_FUNCTION_ARGS); -extern Datum tsmatchjoinsel(PG_FUNCTION_ARGS); - -extern Datum ts_typanalyze(PG_FUNCTION_ARGS); - /* * TSQuery @@ -294,38 +239,4 @@ typedef TSQueryData *TSQuery; #define PG_GETARG_TSQUERY_COPY(n) DatumGetTSQueryCopy(PG_GETARG_DATUM(n)) #define PG_RETURN_TSQUERY(x) return TSQueryGetDatum(x) -/* - * I/O - */ -extern Datum tsqueryin(PG_FUNCTION_ARGS); -extern Datum tsqueryout(PG_FUNCTION_ARGS); -extern Datum tsquerysend(PG_FUNCTION_ARGS); -extern Datum tsqueryrecv(PG_FUNCTION_ARGS); - -/* - * operations with tsquery - */ -extern Datum tsquery_lt(PG_FUNCTION_ARGS); -extern Datum tsquery_le(PG_FUNCTION_ARGS); -extern Datum tsquery_eq(PG_FUNCTION_ARGS); -extern Datum tsquery_ne(PG_FUNCTION_ARGS); -extern Datum tsquery_ge(PG_FUNCTION_ARGS); -extern Datum tsquery_gt(PG_FUNCTION_ARGS); -extern Datum tsquery_cmp(PG_FUNCTION_ARGS); - -extern Datum tsquerytree(PG_FUNCTION_ARGS); -extern Datum tsquery_numnode(PG_FUNCTION_ARGS); - -extern Datum tsquery_and(PG_FUNCTION_ARGS); -extern Datum tsquery_or(PG_FUNCTION_ARGS); -extern Datum tsquery_phrase(PG_FUNCTION_ARGS); -extern Datum tsquery_phrase_distance(PG_FUNCTION_ARGS); -extern Datum tsquery_not(PG_FUNCTION_ARGS); - -extern Datum tsquery_rewrite(PG_FUNCTION_ARGS); -extern Datum tsquery_rewrite_query(PG_FUNCTION_ARGS); - -extern Datum tsq_mcontains(PG_FUNCTION_ARGS); -extern Datum tsq_mcontained(PG_FUNCTION_ARGS); - #endif /* _PG_TSTYPE_H_ */ diff --git a/src/include/tsearch/ts_utils.h b/src/include/tsearch/ts_utils.h index e09a9c636f..20d90b12fd 100644 --- a/src/include/tsearch/ts_utils.h +++ b/src/include/tsearch/ts_utils.h @@ -3,7 +3,7 @@ * ts_utils.h * helper utilities for tsearch * - * Copyright (c) 1998-2016, PostgreSQL Global Development Group + * Copyright (c) 1998-2017, PostgreSQL Global Development Group * * src/include/tsearch/ts_utils.h * @@ -12,9 +12,9 @@ #ifndef _PG_TS_UTILS_H_ #define _PG_TS_UTILS_H_ -#include "tsearch/ts_type.h" -#include "tsearch/ts_public.h" #include "nodes/pg_list.h" +#include "tsearch/ts_public.h" +#include "tsearch/ts_type.h" /* * Common parse definitions for tsvector and tsquery @@ -102,34 +102,80 @@ extern void hlparsetext(Oid cfgId, HeadlineParsedText *prs, TSQuery query, extern text *generateHeadline(HeadlineParsedText *prs); /* - * Common check function for tsvector @@ tsquery + * TSQuery execution support + * + * TS_execute() executes a tsquery against data that can be represented in + * various forms. The TSExecuteCallback callback function is called to check + * whether a given primitive tsquery value is matched in the data. + */ + +/* + * struct ExecPhraseData is passed to a TSExecuteCallback function if we need + * lexeme position data (because of a phrase-match operator in the tsquery). + * The callback should fill in position data when it returns true (success). + * If it cannot return position data, it may leave "data" unchanged, but + * then the caller of TS_execute() must pass the TS_EXEC_PHRASE_NO_POS flag + * and must arrange for a later recheck with position data available. + * + * The reported lexeme positions must be sorted and unique. Callers must only + * consult the position bits of the pos array, ie, WEP_GETPOS(data->pos[i]). + * This allows the returned "pos" to point directly to the WordEntryPos + * portion of a tsvector value. If "allocated" is true then the pos array + * is palloc'd workspace and caller may free it when done. + * + * "negate" means that the pos array contains positions where the query does + * not match, rather than positions where it does. "width" is positive when + * the match is wider than one lexeme. Neither of these fields normally need + * to be touched by TSExecuteCallback functions; they are used for + * phrase-search processing within TS_execute. + * + * All fields of the ExecPhraseData struct are initially zeroed by caller. */ typedef struct ExecPhraseData { - int npos; - bool allocated; - WordEntryPos *pos; + int npos; /* number of positions reported */ + bool allocated; /* pos points to palloc'd data? */ + bool negate; /* positions are where query is NOT matched */ + WordEntryPos *pos; /* ordered, non-duplicate lexeme positions */ + int width; /* width of match in lexemes, less 1 */ } ExecPhraseData; /* - * Evaluates tsquery, flags are followe below + * Signature for TSQuery lexeme check functions + * + * arg: opaque value passed through from caller of TS_execute + * val: lexeme to test for presence of + * data: to be filled with lexeme positions; NULL if position data not needed + * + * Return TRUE if lexeme is present in data, else FALSE. If data is not + * NULL, it should be filled with lexeme positions, but function can leave + * it as zeroes if position data is not available. */ -extern bool TS_execute(QueryItem *curitem, void *checkval, uint32 flags, - bool (*chkcond) (void *, QueryOperand *, ExecPhraseData *)); +typedef bool (*TSExecuteCallback) (void *arg, QueryOperand *val, + ExecPhraseData *data); +/* + * Flag bits for TS_execute + */ #define TS_EXEC_EMPTY (0x00) /* - * if TS_EXEC_CALC_NOT is not set then NOT expression evaluated to be true, - * used in cases where NOT cannot be accurately computed (GiST) or - * it isn't important (ranking) + * If TS_EXEC_CALC_NOT is not set, then NOT expressions are automatically + * evaluated to be true. Useful in cases where NOT cannot be accurately + * computed (GiST) or it isn't important (ranking). From TS_execute's + * perspective, !CALC_NOT means that the TSExecuteCallback function might + * return false-positive indications of a lexeme's presence. */ #define TS_EXEC_CALC_NOT (0x01) /* - * Treat OP_PHRASE as OP_AND. Used when posiotional information is not - * accessible, like in consistent methods of GIN/GiST indexes + * If TS_EXEC_PHRASE_NO_POS is set, allow OP_PHRASE to be executed lossily + * in the absence of position information: a TRUE result indicates that the + * phrase might be present. Without this flag, OP_PHRASE always returns + * false if lexeme position information is not available. */ -#define TS_EXEC_PHRASE_AS_AND (0x02) +#define TS_EXEC_PHRASE_NO_POS (0x02) +extern bool TS_execute(QueryItem *curitem, void *arg, uint32 flags, + TSExecuteCallback chkcond); extern bool tsquery_requires_match(QueryItem *curitem); /* @@ -138,51 +184,6 @@ extern bool tsquery_requires_match(QueryItem *curitem); extern TSVector make_tsvector(ParsedText *prs); extern int32 tsCompareString(char *a, int lena, char *b, int lenb, bool prefix); -extern Datum to_tsvector_byid(PG_FUNCTION_ARGS); -extern Datum to_tsvector(PG_FUNCTION_ARGS); -extern Datum to_tsquery_byid(PG_FUNCTION_ARGS); -extern Datum to_tsquery(PG_FUNCTION_ARGS); -extern Datum plainto_tsquery_byid(PG_FUNCTION_ARGS); -extern Datum plainto_tsquery(PG_FUNCTION_ARGS); -extern Datum phraseto_tsquery_byid(PG_FUNCTION_ARGS); -extern Datum phraseto_tsquery(PG_FUNCTION_ARGS); - -/* - * GiST support function - */ - -extern Datum gtsvector_compress(PG_FUNCTION_ARGS); -extern Datum gtsvector_decompress(PG_FUNCTION_ARGS); -extern Datum gtsvector_consistent(PG_FUNCTION_ARGS); -extern Datum gtsvector_union(PG_FUNCTION_ARGS); -extern Datum gtsvector_same(PG_FUNCTION_ARGS); -extern Datum gtsvector_penalty(PG_FUNCTION_ARGS); -extern Datum gtsvector_picksplit(PG_FUNCTION_ARGS); -extern Datum gtsvector_consistent_oldsig(PG_FUNCTION_ARGS); - -/* - * IO functions for pseudotype gtsvector - * used internally in tsvector GiST opclass - */ -extern Datum gtsvectorin(PG_FUNCTION_ARGS); -extern Datum gtsvectorout(PG_FUNCTION_ARGS); - -/* - * GIN support function - */ - -extern Datum gin_extract_tsvector(PG_FUNCTION_ARGS); -extern Datum gin_cmp_tslexeme(PG_FUNCTION_ARGS); -extern Datum gin_cmp_prefix(PG_FUNCTION_ARGS); -extern Datum gin_extract_tsquery(PG_FUNCTION_ARGS); -extern Datum gin_tsquery_consistent(PG_FUNCTION_ARGS); -extern Datum gin_tsquery_triconsistent(PG_FUNCTION_ARGS); -extern Datum gin_extract_tsvector_2args(PG_FUNCTION_ARGS); -extern Datum gin_extract_tsquery_5args(PG_FUNCTION_ARGS); -extern Datum gin_tsquery_consistent_6args(PG_FUNCTION_ARGS); -extern Datum gin_extract_tsquery_oldsig(PG_FUNCTION_ARGS); -extern Datum gin_tsquery_consistent_oldsig(PG_FUNCTION_ARGS); - /* * Possible strategy numbers for indexes * TSearchStrategyNumber - (tsvector|text) @@ tsquery @@ -195,7 +196,7 @@ extern Datum gin_tsquery_consistent_oldsig(PG_FUNCTION_ARGS); * TSQuery Utilities */ extern QueryItem *clean_NOT(QueryItem *ptr, int32 *len); -extern TSQuery cleanup_fakeval_and_phrase(TSQuery in); +extern TSQuery cleanup_tsquery_stopwords(TSQuery in); typedef struct QTNode { @@ -236,76 +237,4 @@ extern TSQuerySign makeTSQuerySign(TSQuery a); extern QTNode *findsubquery(QTNode *root, QTNode *ex, QTNode *subs, bool *isfind); -/* - * TSQuery GiST support - */ -extern Datum gtsquery_compress(PG_FUNCTION_ARGS); -extern Datum gtsquery_decompress(PG_FUNCTION_ARGS); -extern Datum gtsquery_consistent(PG_FUNCTION_ARGS); -extern Datum gtsquery_union(PG_FUNCTION_ARGS); -extern Datum gtsquery_same(PG_FUNCTION_ARGS); -extern Datum gtsquery_penalty(PG_FUNCTION_ARGS); -extern Datum gtsquery_picksplit(PG_FUNCTION_ARGS); -extern Datum gtsquery_consistent_oldsig(PG_FUNCTION_ARGS); - -/* - * Parser interface to SQL - */ -extern Datum ts_token_type_byid(PG_FUNCTION_ARGS); -extern Datum ts_token_type_byname(PG_FUNCTION_ARGS); -extern Datum ts_parse_byid(PG_FUNCTION_ARGS); -extern Datum ts_parse_byname(PG_FUNCTION_ARGS); - -/* - * Default word parser - */ - -extern Datum prsd_start(PG_FUNCTION_ARGS); -extern Datum prsd_nexttoken(PG_FUNCTION_ARGS); -extern Datum prsd_end(PG_FUNCTION_ARGS); -extern Datum prsd_headline(PG_FUNCTION_ARGS); -extern Datum prsd_lextype(PG_FUNCTION_ARGS); - -/* - * Dictionary interface to SQL - */ -extern Datum ts_lexize(PG_FUNCTION_ARGS); - -/* - * Simple built-in dictionary - */ -extern Datum dsimple_init(PG_FUNCTION_ARGS); -extern Datum dsimple_lexize(PG_FUNCTION_ARGS); - -/* - * Synonym built-in dictionary - */ -extern Datum dsynonym_init(PG_FUNCTION_ARGS); -extern Datum dsynonym_lexize(PG_FUNCTION_ARGS); - -/* - * ISpell dictionary - */ -extern Datum dispell_init(PG_FUNCTION_ARGS); -extern Datum dispell_lexize(PG_FUNCTION_ARGS); - -/* - * Thesaurus - */ -extern Datum thesaurus_init(PG_FUNCTION_ARGS); -extern Datum thesaurus_lexize(PG_FUNCTION_ARGS); - -/* - * headline - */ -extern Datum ts_headline_byid_opt(PG_FUNCTION_ARGS); -extern Datum ts_headline_byid(PG_FUNCTION_ARGS); -extern Datum ts_headline(PG_FUNCTION_ARGS); -extern Datum ts_headline_opt(PG_FUNCTION_ARGS); - -/* - * current cfg - */ -extern Datum get_current_ts_config(PG_FUNCTION_ARGS); - #endif /* _PG_TS_UTILS_H_ */ diff --git a/src/include/utils/.gitignore b/src/include/utils/.gitignore index 808826d147..25db658da5 100644 --- a/src/include/utils/.gitignore +++ b/src/include/utils/.gitignore @@ -1,3 +1,4 @@ /fmgroids.h +/fmgrprotos.h /probes.h /errcodes.h diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index 4cc49f0c0c..686141b5f9 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -4,7 +4,7 @@ * Definition of (and support for) access control list data structures. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/acl.h @@ -26,6 +26,7 @@ #include "access/htup.h" #include "nodes/parsenodes.h" +#include "parser/parse_node.h" #include "utils/array.h" #include "utils/snapshot.h" @@ -198,6 +199,8 @@ typedef enum AclObjectKind ACL_KIND_FOREIGN_SERVER, /* pg_foreign_server */ ACL_KIND_EVENT_TRIGGER, /* pg_event_trigger */ ACL_KIND_EXTENSION, /* pg_extension */ + ACL_KIND_PUBLICATION, /* pg_publication */ + ACL_KIND_SUBSCRIPTION, /* pg_subscription */ MAX_ACL_KIND /* MUST BE LAST */ } AclObjectKind; @@ -230,10 +233,10 @@ extern bool is_admin_of_role(Oid member, Oid role); extern void check_is_member_of_role(Oid member, Oid role); extern Oid get_role_oid(const char *rolename, bool missing_ok); extern Oid get_role_oid_or_public(const char *rolename); -extern Oid get_rolespec_oid(const Node *node, bool missing_ok); -extern void check_rolespec_name(const Node *node, const char *detail_msg); -extern HeapTuple get_rolespec_tuple(const Node *node); -extern char *get_rolespec_name(const Node *node); +extern Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok); +extern void check_rolespec_name(const RoleSpec *role, const char *detail_msg); +extern HeapTuple get_rolespec_tuple(const RoleSpec *role); +extern char *get_rolespec_name(const RoleSpec *role); extern void select_best_grantor(Oid roleId, AclMode privileges, const Acl *acl, Oid ownerId, @@ -241,25 +244,11 @@ extern void select_best_grantor(Oid roleId, AclMode privileges, extern void initialize_acl(void); -/* - * SQL functions (from acl.c) - */ -extern Datum aclitemin(PG_FUNCTION_ARGS); -extern Datum aclitemout(PG_FUNCTION_ARGS); -extern Datum aclinsert(PG_FUNCTION_ARGS); -extern Datum aclremove(PG_FUNCTION_ARGS); -extern Datum aclcontains(PG_FUNCTION_ARGS); -extern Datum makeaclitem(PG_FUNCTION_ARGS); -extern Datum aclitem_eq(PG_FUNCTION_ARGS); -extern Datum hash_aclitem(PG_FUNCTION_ARGS); -extern Datum acldefault_sql(PG_FUNCTION_ARGS); -extern Datum aclexplode(PG_FUNCTION_ARGS); - /* * prototypes for functions in aclchk.c */ extern void ExecuteGrantStmt(GrantStmt *stmt); -extern void ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt); +extern void ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *stmt); extern void RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid); extern void RemoveDefaultACLById(Oid defaclOid); @@ -331,6 +320,8 @@ extern bool pg_foreign_data_wrapper_ownercheck(Oid srv_oid, Oid roleid); extern bool pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid); extern bool pg_event_trigger_ownercheck(Oid et_oid, Oid roleid); extern bool pg_extension_ownercheck(Oid ext_oid, Oid roleid); +extern bool pg_publication_ownercheck(Oid pub_oid, Oid roleid); +extern bool pg_subscription_ownercheck(Oid sub_oid, Oid roleid); extern bool has_createrole_privilege(Oid roleid); extern bool has_bypassrls_privilege(Oid roleid); diff --git a/src/include/utils/aclchk_internal.h b/src/include/utils/aclchk_internal.h index 319a391246..0e50f73aab 100644 --- a/src/include/utils/aclchk_internal.h +++ b/src/include/utils/aclchk_internal.h @@ -2,7 +2,7 @@ * * aclchk_internal.h * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/aclchk_internal.h diff --git a/src/include/utils/array.h b/src/include/utils/array.h index b62b08c482..b0ff73b7e0 100644 --- a/src/include/utils/array.h +++ b/src/include/utils/array.h @@ -36,7 +36,7 @@ * * The OIDVECTOR and INT2VECTOR datatypes are storage-compatible with * generic arrays, but they support only one-dimensional arrays with no - * nulls (and no null bitmap). + * nulls (and no null bitmap). They don't support being toasted, either. * * There are also some "fixed-length array" datatypes, such as NAME and * POINT. These are simply a sequence of a fixed number of items each @@ -51,7 +51,7 @@ * arrays holding the elements. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/array.h @@ -328,38 +328,6 @@ extern bool Array_nulls; /* * prototypes for functions defined in arrayfuncs.c */ -extern Datum array_in(PG_FUNCTION_ARGS); -extern Datum array_out(PG_FUNCTION_ARGS); -extern Datum array_recv(PG_FUNCTION_ARGS); -extern Datum array_send(PG_FUNCTION_ARGS); -extern Datum array_eq(PG_FUNCTION_ARGS); -extern Datum array_ne(PG_FUNCTION_ARGS); -extern Datum array_lt(PG_FUNCTION_ARGS); -extern Datum array_gt(PG_FUNCTION_ARGS); -extern Datum array_le(PG_FUNCTION_ARGS); -extern Datum array_ge(PG_FUNCTION_ARGS); -extern Datum btarraycmp(PG_FUNCTION_ARGS); -extern Datum hash_array(PG_FUNCTION_ARGS); -extern Datum arrayoverlap(PG_FUNCTION_ARGS); -extern Datum arraycontains(PG_FUNCTION_ARGS); -extern Datum arraycontained(PG_FUNCTION_ARGS); -extern Datum array_ndims(PG_FUNCTION_ARGS); -extern Datum array_dims(PG_FUNCTION_ARGS); -extern Datum array_lower(PG_FUNCTION_ARGS); -extern Datum array_upper(PG_FUNCTION_ARGS); -extern Datum array_length(PG_FUNCTION_ARGS); -extern Datum array_cardinality(PG_FUNCTION_ARGS); -extern Datum array_larger(PG_FUNCTION_ARGS); -extern Datum array_smaller(PG_FUNCTION_ARGS); -extern Datum generate_subscripts(PG_FUNCTION_ARGS); -extern Datum generate_subscripts_nodir(PG_FUNCTION_ARGS); -extern Datum array_fill(PG_FUNCTION_ARGS); -extern Datum array_fill_with_lower_bounds(PG_FUNCTION_ARGS); -extern Datum array_unnest(PG_FUNCTION_ARGS); -extern Datum array_remove(PG_FUNCTION_ARGS); -extern Datum array_replace(PG_FUNCTION_ARGS); -extern Datum width_bucket_array(PG_FUNCTION_ARGS); - extern void CopyArrayEls(ArrayType *array, Datum *values, bool *nulls, @@ -478,28 +446,10 @@ extern void deconstruct_expanded_array(ExpandedArrayHeader *eah); /* * prototypes for functions defined in array_userfuncs.c */ -extern Datum array_append(PG_FUNCTION_ARGS); -extern Datum array_prepend(PG_FUNCTION_ARGS); -extern Datum array_cat(PG_FUNCTION_ARGS); - extern ArrayType *create_singleton_array(FunctionCallInfo fcinfo, Oid element_type, Datum element, bool isNull, int ndims); -extern Datum array_agg_transfn(PG_FUNCTION_ARGS); -extern Datum array_agg_finalfn(PG_FUNCTION_ARGS); -extern Datum array_agg_array_transfn(PG_FUNCTION_ARGS); -extern Datum array_agg_array_finalfn(PG_FUNCTION_ARGS); - -extern Datum array_position(PG_FUNCTION_ARGS); -extern Datum array_position_start(PG_FUNCTION_ARGS); -extern Datum array_positions(PG_FUNCTION_ARGS); - -/* - * prototypes for functions defined in array_typanalyze.c - */ -extern Datum array_typanalyze(PG_FUNCTION_ARGS); - #endif /* ARRAY_H */ diff --git a/src/include/utils/arrayaccess.h b/src/include/utils/arrayaccess.h index 3ff49f12bc..6148bdf834 100644 --- a/src/include/utils/arrayaccess.h +++ b/src/include/utils/arrayaccess.h @@ -4,7 +4,7 @@ * Declarations for element-by-element access to Postgres arrays. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/arrayaccess.h diff --git a/src/include/utils/ascii.h b/src/include/utils/ascii.h index 1006d0d63e..3771e1acab 100644 --- a/src/include/utils/ascii.h +++ b/src/include/utils/ascii.h @@ -1,7 +1,7 @@ /*----------------------------------------------------------------------- * ascii.h * - * Portions Copyright (c) 1999-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1999-2017, PostgreSQL Global Development Group * * src/include/utils/ascii.h * @@ -11,12 +11,6 @@ #ifndef _ASCII_H_ #define _ASCII_H_ -#include "fmgr.h" - -extern Datum to_ascii_encname(PG_FUNCTION_ARGS); -extern Datum to_ascii_enc(PG_FUNCTION_ARGS); -extern Datum to_ascii_default(PG_FUNCTION_ARGS); - extern void ascii_safe_strlcpy(char *dest, const char *src, size_t destsiz); #endif /* _ASCII_H_ */ diff --git a/src/include/utils/attoptcache.h b/src/include/utils/attoptcache.h index cf8ead006d..7f2334b4cd 100644 --- a/src/include/utils/attoptcache.h +++ b/src/include/utils/attoptcache.h @@ -3,7 +3,7 @@ * attoptcache.h * Attribute options cache. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/attoptcache.h diff --git a/src/include/utils/backend_random.h b/src/include/utils/backend_random.h new file mode 100644 index 0000000000..31602f250d --- /dev/null +++ b/src/include/utils/backend_random.h @@ -0,0 +1,19 @@ +/*------------------------------------------------------------------------- + * + * backend_random.h + * Declarations for backend random number generation + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group + * + * src/include/utils/backend_random.h + * + *------------------------------------------------------------------------- + */ +#ifndef BACKEND_RANDOM_H +#define BACKEND_RANDOM_H + +extern Size BackendRandomShmemSize(void); +extern void BackendRandomShmemInit(void); +extern bool pg_backend_random(char *dst, int len); + +#endif /* BACKEND_RANDOM_H */ diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index a91be981b9..3d82bf14e6 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -4,7 +4,7 @@ * Declarations for operations on built-in types. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/builtins.h @@ -15,280 +15,35 @@ #define BUILTINS_H #include "fmgr.h" -#include "nodes/parsenodes.h" -#include "utils/sortsupport.h" +#include "nodes/nodes.h" +#include "utils/fmgrprotos.h" -/* - * Defined in adt/ - */ - -/* acl.c */ -extern Datum has_any_column_privilege_name_name(PG_FUNCTION_ARGS); -extern Datum has_any_column_privilege_name_id(PG_FUNCTION_ARGS); -extern Datum has_any_column_privilege_id_name(PG_FUNCTION_ARGS); -extern Datum has_any_column_privilege_id_id(PG_FUNCTION_ARGS); -extern Datum has_any_column_privilege_name(PG_FUNCTION_ARGS); -extern Datum has_any_column_privilege_id(PG_FUNCTION_ARGS); -extern Datum has_column_privilege_name_name_name(PG_FUNCTION_ARGS); -extern Datum has_column_privilege_name_name_attnum(PG_FUNCTION_ARGS); -extern Datum has_column_privilege_name_id_name(PG_FUNCTION_ARGS); -extern Datum has_column_privilege_name_id_attnum(PG_FUNCTION_ARGS); -extern Datum has_column_privilege_id_name_name(PG_FUNCTION_ARGS); -extern Datum has_column_privilege_id_name_attnum(PG_FUNCTION_ARGS); -extern Datum has_column_privilege_id_id_name(PG_FUNCTION_ARGS); -extern Datum has_column_privilege_id_id_attnum(PG_FUNCTION_ARGS); -extern Datum has_column_privilege_name_name(PG_FUNCTION_ARGS); -extern Datum has_column_privilege_name_attnum(PG_FUNCTION_ARGS); -extern Datum has_column_privilege_id_name(PG_FUNCTION_ARGS); -extern Datum has_column_privilege_id_attnum(PG_FUNCTION_ARGS); -extern Datum has_table_privilege_name_name(PG_FUNCTION_ARGS); -extern Datum has_table_privilege_name_id(PG_FUNCTION_ARGS); -extern Datum has_table_privilege_id_name(PG_FUNCTION_ARGS); -extern Datum has_table_privilege_id_id(PG_FUNCTION_ARGS); -extern Datum has_table_privilege_name(PG_FUNCTION_ARGS); -extern Datum has_table_privilege_id(PG_FUNCTION_ARGS); -extern Datum has_sequence_privilege_name_name(PG_FUNCTION_ARGS); -extern Datum has_sequence_privilege_name_id(PG_FUNCTION_ARGS); -extern Datum has_sequence_privilege_id_name(PG_FUNCTION_ARGS); -extern Datum has_sequence_privilege_id_id(PG_FUNCTION_ARGS); -extern Datum has_sequence_privilege_name(PG_FUNCTION_ARGS); -extern Datum has_sequence_privilege_id(PG_FUNCTION_ARGS); -extern Datum has_database_privilege_name_name(PG_FUNCTION_ARGS); -extern Datum has_database_privilege_name_id(PG_FUNCTION_ARGS); -extern Datum has_database_privilege_id_name(PG_FUNCTION_ARGS); -extern Datum has_database_privilege_id_id(PG_FUNCTION_ARGS); -extern Datum has_database_privilege_name(PG_FUNCTION_ARGS); -extern Datum has_database_privilege_id(PG_FUNCTION_ARGS); -extern Datum has_foreign_data_wrapper_privilege_name_name(PG_FUNCTION_ARGS); -extern Datum has_foreign_data_wrapper_privilege_name_id(PG_FUNCTION_ARGS); -extern Datum has_foreign_data_wrapper_privilege_id_name(PG_FUNCTION_ARGS); -extern Datum has_foreign_data_wrapper_privilege_id_id(PG_FUNCTION_ARGS); -extern Datum has_foreign_data_wrapper_privilege_name(PG_FUNCTION_ARGS); -extern Datum has_foreign_data_wrapper_privilege_id(PG_FUNCTION_ARGS); -extern Datum has_function_privilege_name_name(PG_FUNCTION_ARGS); -extern Datum has_function_privilege_name_id(PG_FUNCTION_ARGS); -extern Datum has_function_privilege_id_name(PG_FUNCTION_ARGS); -extern Datum has_function_privilege_id_id(PG_FUNCTION_ARGS); -extern Datum has_function_privilege_name(PG_FUNCTION_ARGS); -extern Datum has_function_privilege_id(PG_FUNCTION_ARGS); -extern Datum has_language_privilege_name_name(PG_FUNCTION_ARGS); -extern Datum has_language_privilege_name_id(PG_FUNCTION_ARGS); -extern Datum has_language_privilege_id_name(PG_FUNCTION_ARGS); -extern Datum has_language_privilege_id_id(PG_FUNCTION_ARGS); -extern Datum has_language_privilege_name(PG_FUNCTION_ARGS); -extern Datum has_language_privilege_id(PG_FUNCTION_ARGS); -extern Datum has_schema_privilege_name_name(PG_FUNCTION_ARGS); -extern Datum has_schema_privilege_name_id(PG_FUNCTION_ARGS); -extern Datum has_schema_privilege_id_name(PG_FUNCTION_ARGS); -extern Datum has_schema_privilege_id_id(PG_FUNCTION_ARGS); -extern Datum has_schema_privilege_name(PG_FUNCTION_ARGS); -extern Datum has_schema_privilege_id(PG_FUNCTION_ARGS); -extern Datum has_server_privilege_name_name(PG_FUNCTION_ARGS); -extern Datum has_server_privilege_name_id(PG_FUNCTION_ARGS); -extern Datum has_server_privilege_id_name(PG_FUNCTION_ARGS); -extern Datum has_server_privilege_id_id(PG_FUNCTION_ARGS); -extern Datum has_server_privilege_name(PG_FUNCTION_ARGS); -extern Datum has_server_privilege_id(PG_FUNCTION_ARGS); -extern Datum has_tablespace_privilege_name_name(PG_FUNCTION_ARGS); -extern Datum has_tablespace_privilege_name_id(PG_FUNCTION_ARGS); -extern Datum has_tablespace_privilege_id_name(PG_FUNCTION_ARGS); -extern Datum has_tablespace_privilege_id_id(PG_FUNCTION_ARGS); -extern Datum has_tablespace_privilege_name(PG_FUNCTION_ARGS); -extern Datum has_tablespace_privilege_id(PG_FUNCTION_ARGS); -extern Datum has_type_privilege_name_name(PG_FUNCTION_ARGS); -extern Datum has_type_privilege_name_id(PG_FUNCTION_ARGS); -extern Datum has_type_privilege_id_name(PG_FUNCTION_ARGS); -extern Datum has_type_privilege_id_id(PG_FUNCTION_ARGS); -extern Datum has_type_privilege_name(PG_FUNCTION_ARGS); -extern Datum has_type_privilege_id(PG_FUNCTION_ARGS); -extern Datum pg_has_role_name_name(PG_FUNCTION_ARGS); -extern Datum pg_has_role_name_id(PG_FUNCTION_ARGS); -extern Datum pg_has_role_id_name(PG_FUNCTION_ARGS); -extern Datum pg_has_role_id_id(PG_FUNCTION_ARGS); -extern Datum pg_has_role_name(PG_FUNCTION_ARGS); -extern Datum pg_has_role_id(PG_FUNCTION_ARGS); - -/* amutils.c */ -extern Datum pg_indexam_has_property(PG_FUNCTION_ARGS); -extern Datum pg_index_has_property(PG_FUNCTION_ARGS); -extern Datum pg_index_column_has_property(PG_FUNCTION_ARGS); /* bool.c */ -extern Datum boolin(PG_FUNCTION_ARGS); -extern Datum boolout(PG_FUNCTION_ARGS); -extern Datum boolrecv(PG_FUNCTION_ARGS); -extern Datum boolsend(PG_FUNCTION_ARGS); -extern Datum booltext(PG_FUNCTION_ARGS); -extern Datum booleq(PG_FUNCTION_ARGS); -extern Datum boolne(PG_FUNCTION_ARGS); -extern Datum boollt(PG_FUNCTION_ARGS); -extern Datum boolgt(PG_FUNCTION_ARGS); -extern Datum boolle(PG_FUNCTION_ARGS); -extern Datum boolge(PG_FUNCTION_ARGS); -extern Datum booland_statefunc(PG_FUNCTION_ARGS); -extern Datum boolor_statefunc(PG_FUNCTION_ARGS); -extern Datum bool_accum(PG_FUNCTION_ARGS); -extern Datum bool_accum_inv(PG_FUNCTION_ARGS); -extern Datum bool_alltrue(PG_FUNCTION_ARGS); -extern Datum bool_anytrue(PG_FUNCTION_ARGS); extern bool parse_bool(const char *value, bool *result); extern bool parse_bool_with_len(const char *value, size_t len, bool *result); -/* char.c */ -extern Datum charin(PG_FUNCTION_ARGS); -extern Datum charout(PG_FUNCTION_ARGS); -extern Datum charrecv(PG_FUNCTION_ARGS); -extern Datum charsend(PG_FUNCTION_ARGS); -extern Datum chareq(PG_FUNCTION_ARGS); -extern Datum charne(PG_FUNCTION_ARGS); -extern Datum charlt(PG_FUNCTION_ARGS); -extern Datum charle(PG_FUNCTION_ARGS); -extern Datum chargt(PG_FUNCTION_ARGS); -extern Datum charge(PG_FUNCTION_ARGS); -extern Datum chartoi4(PG_FUNCTION_ARGS); -extern Datum i4tochar(PG_FUNCTION_ARGS); -extern Datum text_char(PG_FUNCTION_ARGS); -extern Datum char_text(PG_FUNCTION_ARGS); - /* domains.c */ -extern Datum domain_in(PG_FUNCTION_ARGS); -extern Datum domain_recv(PG_FUNCTION_ARGS); extern void domain_check(Datum value, bool isnull, Oid domainType, void **extra, MemoryContext mcxt); extern int errdatatype(Oid datatypeOid); extern int errdomainconstraint(Oid datatypeOid, const char *conname); /* encode.c */ -extern Datum binary_encode(PG_FUNCTION_ARGS); -extern Datum binary_decode(PG_FUNCTION_ARGS); extern unsigned hex_encode(const char *src, unsigned len, char *dst); extern unsigned hex_decode(const char *src, unsigned len, char *dst); -/* enum.c */ -extern Datum enum_in(PG_FUNCTION_ARGS); -extern Datum enum_out(PG_FUNCTION_ARGS); -extern Datum enum_recv(PG_FUNCTION_ARGS); -extern Datum enum_send(PG_FUNCTION_ARGS); -extern Datum enum_lt(PG_FUNCTION_ARGS); -extern Datum enum_le(PG_FUNCTION_ARGS); -extern Datum enum_eq(PG_FUNCTION_ARGS); -extern Datum enum_ne(PG_FUNCTION_ARGS); -extern Datum enum_ge(PG_FUNCTION_ARGS); -extern Datum enum_gt(PG_FUNCTION_ARGS); -extern Datum enum_cmp(PG_FUNCTION_ARGS); -extern Datum enum_smaller(PG_FUNCTION_ARGS); -extern Datum enum_larger(PG_FUNCTION_ARGS); -extern Datum enum_first(PG_FUNCTION_ARGS); -extern Datum enum_last(PG_FUNCTION_ARGS); -extern Datum enum_range_bounds(PG_FUNCTION_ARGS); -extern Datum enum_range_all(PG_FUNCTION_ARGS); - +extern unsigned b64_encode(const char *src, unsigned len, char *dst); +extern unsigned b64_decode(const char *src, unsigned len, char *dst); +extern unsigned b64_enc_len(const char *src, unsigned srclen); +extern unsigned b64_dec_len(const char *src, unsigned srclen); /* int.c */ -extern Datum int2in(PG_FUNCTION_ARGS); -extern Datum int2out(PG_FUNCTION_ARGS); -extern Datum int2recv(PG_FUNCTION_ARGS); -extern Datum int2send(PG_FUNCTION_ARGS); -extern Datum int2vectorin(PG_FUNCTION_ARGS); -extern Datum int2vectorout(PG_FUNCTION_ARGS); -extern Datum int2vectorrecv(PG_FUNCTION_ARGS); -extern Datum int2vectorsend(PG_FUNCTION_ARGS); -extern Datum int2vectoreq(PG_FUNCTION_ARGS); -extern Datum int4in(PG_FUNCTION_ARGS); -extern Datum int4out(PG_FUNCTION_ARGS); -extern Datum int4recv(PG_FUNCTION_ARGS); -extern Datum int4send(PG_FUNCTION_ARGS); -extern Datum i2toi4(PG_FUNCTION_ARGS); -extern Datum i4toi2(PG_FUNCTION_ARGS); -extern Datum int4_bool(PG_FUNCTION_ARGS); -extern Datum bool_int4(PG_FUNCTION_ARGS); -extern Datum int4eq(PG_FUNCTION_ARGS); -extern Datum int4ne(PG_FUNCTION_ARGS); -extern Datum int4lt(PG_FUNCTION_ARGS); -extern Datum int4le(PG_FUNCTION_ARGS); -extern Datum int4gt(PG_FUNCTION_ARGS); -extern Datum int4ge(PG_FUNCTION_ARGS); -extern Datum int2eq(PG_FUNCTION_ARGS); -extern Datum int2ne(PG_FUNCTION_ARGS); -extern Datum int2lt(PG_FUNCTION_ARGS); -extern Datum int2le(PG_FUNCTION_ARGS); -extern Datum int2gt(PG_FUNCTION_ARGS); -extern Datum int2ge(PG_FUNCTION_ARGS); -extern Datum int24eq(PG_FUNCTION_ARGS); -extern Datum int24ne(PG_FUNCTION_ARGS); -extern Datum int24lt(PG_FUNCTION_ARGS); -extern Datum int24le(PG_FUNCTION_ARGS); -extern Datum int24gt(PG_FUNCTION_ARGS); -extern Datum int24ge(PG_FUNCTION_ARGS); -extern Datum int42eq(PG_FUNCTION_ARGS); -extern Datum int42ne(PG_FUNCTION_ARGS); -extern Datum int42lt(PG_FUNCTION_ARGS); -extern Datum int42le(PG_FUNCTION_ARGS); -extern Datum int42gt(PG_FUNCTION_ARGS); -extern Datum int42ge(PG_FUNCTION_ARGS); -extern Datum int4um(PG_FUNCTION_ARGS); -extern Datum int4up(PG_FUNCTION_ARGS); -extern Datum int4pl(PG_FUNCTION_ARGS); -extern Datum int4mi(PG_FUNCTION_ARGS); -extern Datum int4mul(PG_FUNCTION_ARGS); -extern Datum int4div(PG_FUNCTION_ARGS); -extern Datum int4abs(PG_FUNCTION_ARGS); -extern Datum int4inc(PG_FUNCTION_ARGS); -extern Datum int2um(PG_FUNCTION_ARGS); -extern Datum int2up(PG_FUNCTION_ARGS); -extern Datum int2pl(PG_FUNCTION_ARGS); -extern Datum int2mi(PG_FUNCTION_ARGS); -extern Datum int2mul(PG_FUNCTION_ARGS); -extern Datum int2div(PG_FUNCTION_ARGS); -extern Datum int2abs(PG_FUNCTION_ARGS); -extern Datum int24pl(PG_FUNCTION_ARGS); -extern Datum int24mi(PG_FUNCTION_ARGS); -extern Datum int24mul(PG_FUNCTION_ARGS); -extern Datum int24div(PG_FUNCTION_ARGS); -extern Datum int42pl(PG_FUNCTION_ARGS); -extern Datum int42mi(PG_FUNCTION_ARGS); -extern Datum int42mul(PG_FUNCTION_ARGS); -extern Datum int42div(PG_FUNCTION_ARGS); -extern Datum int4mod(PG_FUNCTION_ARGS); -extern Datum int2mod(PG_FUNCTION_ARGS); -extern Datum int2larger(PG_FUNCTION_ARGS); -extern Datum int2smaller(PG_FUNCTION_ARGS); -extern Datum int4larger(PG_FUNCTION_ARGS); -extern Datum int4smaller(PG_FUNCTION_ARGS); - -extern Datum int4and(PG_FUNCTION_ARGS); -extern Datum int4or(PG_FUNCTION_ARGS); -extern Datum int4xor(PG_FUNCTION_ARGS); -extern Datum int4not(PG_FUNCTION_ARGS); -extern Datum int4shl(PG_FUNCTION_ARGS); -extern Datum int4shr(PG_FUNCTION_ARGS); -extern Datum int2and(PG_FUNCTION_ARGS); -extern Datum int2or(PG_FUNCTION_ARGS); -extern Datum int2xor(PG_FUNCTION_ARGS); -extern Datum int2not(PG_FUNCTION_ARGS); -extern Datum int2shl(PG_FUNCTION_ARGS); -extern Datum int2shr(PG_FUNCTION_ARGS); -extern Datum generate_series_int4(PG_FUNCTION_ARGS); -extern Datum generate_series_step_int4(PG_FUNCTION_ARGS); extern int2vector *buildint2vector(const int16 *int2s, int n); /* name.c */ -extern Datum namein(PG_FUNCTION_ARGS); -extern Datum nameout(PG_FUNCTION_ARGS); -extern Datum namerecv(PG_FUNCTION_ARGS); -extern Datum namesend(PG_FUNCTION_ARGS); -extern Datum nameeq(PG_FUNCTION_ARGS); -extern Datum namene(PG_FUNCTION_ARGS); -extern Datum namelt(PG_FUNCTION_ARGS); -extern Datum namele(PG_FUNCTION_ARGS); -extern Datum namegt(PG_FUNCTION_ARGS); -extern Datum namege(PG_FUNCTION_ARGS); extern int namecpy(Name n1, Name n2); extern int namestrcpy(Name name, const char *str); extern int namestrcmp(Name name, const char *str); -extern Datum current_user(PG_FUNCTION_ARGS); -extern Datum session_user(PG_FUNCTION_ARGS); -extern Datum current_schema(PG_FUNCTION_ARGS); -extern Datum current_schemas(PG_FUNCTION_ARGS); /* numutils.c */ extern int32 pg_atoi(const char *s, int size, int c); @@ -299,47 +54,6 @@ extern char *pg_ltostr_zeropad(char *str, int32 value, int32 minwidth); extern char *pg_ltostr(char *str, int32 value); extern uint64 pg_strtouint64(const char *str, char **endptr, int base); -/* - * Per-opclass comparison functions for new btrees. These are - * stored in pg_amproc; most are defined in access/nbtree/nbtcompare.c - */ -extern Datum btboolcmp(PG_FUNCTION_ARGS); -extern Datum btint2cmp(PG_FUNCTION_ARGS); -extern Datum btint4cmp(PG_FUNCTION_ARGS); -extern Datum btint8cmp(PG_FUNCTION_ARGS); -extern Datum btfloat4cmp(PG_FUNCTION_ARGS); -extern Datum btfloat8cmp(PG_FUNCTION_ARGS); -extern Datum btint48cmp(PG_FUNCTION_ARGS); -extern Datum btint84cmp(PG_FUNCTION_ARGS); -extern Datum btint24cmp(PG_FUNCTION_ARGS); -extern Datum btint42cmp(PG_FUNCTION_ARGS); -extern Datum btint28cmp(PG_FUNCTION_ARGS); -extern Datum btint82cmp(PG_FUNCTION_ARGS); -extern Datum btfloat48cmp(PG_FUNCTION_ARGS); -extern Datum btfloat84cmp(PG_FUNCTION_ARGS); -extern Datum btoidcmp(PG_FUNCTION_ARGS); -extern Datum btoidvectorcmp(PG_FUNCTION_ARGS); -extern Datum btabstimecmp(PG_FUNCTION_ARGS); -extern Datum btreltimecmp(PG_FUNCTION_ARGS); -extern Datum bttintervalcmp(PG_FUNCTION_ARGS); -extern Datum btcharcmp(PG_FUNCTION_ARGS); -extern Datum btnamecmp(PG_FUNCTION_ARGS); -extern Datum bttextcmp(PG_FUNCTION_ARGS); -extern Datum bttextsortsupport(PG_FUNCTION_ARGS); - -/* - * Per-opclass sort support functions for new btrees. Like the - * functions above, these are stored in pg_amproc; most are defined in - * access/nbtree/nbtcompare.c - */ -extern Datum btint2sortsupport(PG_FUNCTION_ARGS); -extern Datum btint4sortsupport(PG_FUNCTION_ARGS); -extern Datum btint8sortsupport(PG_FUNCTION_ARGS); -extern Datum btfloat4sortsupport(PG_FUNCTION_ARGS); -extern Datum btfloat8sortsupport(PG_FUNCTION_ARGS); -extern Datum btoidsortsupport(PG_FUNCTION_ARGS); -extern Datum btnamesortsupport(PG_FUNCTION_ARGS); - /* float.c */ extern PGDLLIMPORT int extra_float_digits; @@ -354,457 +68,24 @@ extern char *float8out_internal(double num); extern int float4_cmp_internal(float4 a, float4 b); extern int float8_cmp_internal(float8 a, float8 b); -extern Datum float4in(PG_FUNCTION_ARGS); -extern Datum float4out(PG_FUNCTION_ARGS); -extern Datum float4recv(PG_FUNCTION_ARGS); -extern Datum float4send(PG_FUNCTION_ARGS); -extern Datum float8in(PG_FUNCTION_ARGS); -extern Datum float8out(PG_FUNCTION_ARGS); -extern Datum float8recv(PG_FUNCTION_ARGS); -extern Datum float8send(PG_FUNCTION_ARGS); -extern Datum float4abs(PG_FUNCTION_ARGS); -extern Datum float4um(PG_FUNCTION_ARGS); -extern Datum float4up(PG_FUNCTION_ARGS); -extern Datum float4larger(PG_FUNCTION_ARGS); -extern Datum float4smaller(PG_FUNCTION_ARGS); -extern Datum float8abs(PG_FUNCTION_ARGS); -extern Datum float8um(PG_FUNCTION_ARGS); -extern Datum float8up(PG_FUNCTION_ARGS); -extern Datum float8larger(PG_FUNCTION_ARGS); -extern Datum float8smaller(PG_FUNCTION_ARGS); -extern Datum float4pl(PG_FUNCTION_ARGS); -extern Datum float4mi(PG_FUNCTION_ARGS); -extern Datum float4mul(PG_FUNCTION_ARGS); -extern Datum float4div(PG_FUNCTION_ARGS); -extern Datum float8pl(PG_FUNCTION_ARGS); -extern Datum float8mi(PG_FUNCTION_ARGS); -extern Datum float8mul(PG_FUNCTION_ARGS); -extern Datum float8div(PG_FUNCTION_ARGS); -extern Datum float4eq(PG_FUNCTION_ARGS); -extern Datum float4ne(PG_FUNCTION_ARGS); -extern Datum float4lt(PG_FUNCTION_ARGS); -extern Datum float4le(PG_FUNCTION_ARGS); -extern Datum float4gt(PG_FUNCTION_ARGS); -extern Datum float4ge(PG_FUNCTION_ARGS); -extern Datum float8eq(PG_FUNCTION_ARGS); -extern Datum float8ne(PG_FUNCTION_ARGS); -extern Datum float8lt(PG_FUNCTION_ARGS); -extern Datum float8le(PG_FUNCTION_ARGS); -extern Datum float8gt(PG_FUNCTION_ARGS); -extern Datum float8ge(PG_FUNCTION_ARGS); -extern Datum ftod(PG_FUNCTION_ARGS); -extern Datum i4tod(PG_FUNCTION_ARGS); -extern Datum i2tod(PG_FUNCTION_ARGS); -extern Datum dtof(PG_FUNCTION_ARGS); -extern Datum dtoi4(PG_FUNCTION_ARGS); -extern Datum dtoi2(PG_FUNCTION_ARGS); -extern Datum i4tof(PG_FUNCTION_ARGS); -extern Datum i2tof(PG_FUNCTION_ARGS); -extern Datum ftoi4(PG_FUNCTION_ARGS); -extern Datum ftoi2(PG_FUNCTION_ARGS); -extern Datum dround(PG_FUNCTION_ARGS); -extern Datum dceil(PG_FUNCTION_ARGS); -extern Datum dfloor(PG_FUNCTION_ARGS); -extern Datum dsign(PG_FUNCTION_ARGS); -extern Datum dtrunc(PG_FUNCTION_ARGS); -extern Datum dsqrt(PG_FUNCTION_ARGS); -extern Datum dcbrt(PG_FUNCTION_ARGS); -extern Datum dpow(PG_FUNCTION_ARGS); -extern Datum dexp(PG_FUNCTION_ARGS); -extern Datum dlog1(PG_FUNCTION_ARGS); -extern Datum dlog10(PG_FUNCTION_ARGS); -extern Datum dacos(PG_FUNCTION_ARGS); -extern Datum dasin(PG_FUNCTION_ARGS); -extern Datum datan(PG_FUNCTION_ARGS); -extern Datum datan2(PG_FUNCTION_ARGS); -extern Datum dcos(PG_FUNCTION_ARGS); -extern Datum dcot(PG_FUNCTION_ARGS); -extern Datum dsin(PG_FUNCTION_ARGS); -extern Datum dtan(PG_FUNCTION_ARGS); -extern Datum dacosd(PG_FUNCTION_ARGS); -extern Datum dasind(PG_FUNCTION_ARGS); -extern Datum datand(PG_FUNCTION_ARGS); -extern Datum datan2d(PG_FUNCTION_ARGS); -extern Datum dcosd(PG_FUNCTION_ARGS); -extern Datum dcotd(PG_FUNCTION_ARGS); -extern Datum dsind(PG_FUNCTION_ARGS); -extern Datum dtand(PG_FUNCTION_ARGS); -extern Datum degrees(PG_FUNCTION_ARGS); -extern Datum dpi(PG_FUNCTION_ARGS); -extern Datum radians(PG_FUNCTION_ARGS); -extern Datum drandom(PG_FUNCTION_ARGS); -extern Datum setseed(PG_FUNCTION_ARGS); -extern Datum float8_combine(PG_FUNCTION_ARGS); -extern Datum float8_accum(PG_FUNCTION_ARGS); -extern Datum float4_accum(PG_FUNCTION_ARGS); -extern Datum float8_avg(PG_FUNCTION_ARGS); -extern Datum float8_var_pop(PG_FUNCTION_ARGS); -extern Datum float8_var_samp(PG_FUNCTION_ARGS); -extern Datum float8_stddev_pop(PG_FUNCTION_ARGS); -extern Datum float8_stddev_samp(PG_FUNCTION_ARGS); -extern Datum float8_regr_accum(PG_FUNCTION_ARGS); -extern Datum float8_regr_combine(PG_FUNCTION_ARGS); -extern Datum float8_regr_sxx(PG_FUNCTION_ARGS); -extern Datum float8_regr_syy(PG_FUNCTION_ARGS); -extern Datum float8_regr_sxy(PG_FUNCTION_ARGS); -extern Datum float8_regr_avgx(PG_FUNCTION_ARGS); -extern Datum float8_regr_avgy(PG_FUNCTION_ARGS); -extern Datum float8_covar_pop(PG_FUNCTION_ARGS); -extern Datum float8_covar_samp(PG_FUNCTION_ARGS); -extern Datum float8_corr(PG_FUNCTION_ARGS); -extern Datum float8_regr_r2(PG_FUNCTION_ARGS); -extern Datum float8_regr_slope(PG_FUNCTION_ARGS); -extern Datum float8_regr_intercept(PG_FUNCTION_ARGS); -extern Datum float48pl(PG_FUNCTION_ARGS); -extern Datum float48mi(PG_FUNCTION_ARGS); -extern Datum float48mul(PG_FUNCTION_ARGS); -extern Datum float48div(PG_FUNCTION_ARGS); -extern Datum float84pl(PG_FUNCTION_ARGS); -extern Datum float84mi(PG_FUNCTION_ARGS); -extern Datum float84mul(PG_FUNCTION_ARGS); -extern Datum float84div(PG_FUNCTION_ARGS); -extern Datum float48eq(PG_FUNCTION_ARGS); -extern Datum float48ne(PG_FUNCTION_ARGS); -extern Datum float48lt(PG_FUNCTION_ARGS); -extern Datum float48le(PG_FUNCTION_ARGS); -extern Datum float48gt(PG_FUNCTION_ARGS); -extern Datum float48ge(PG_FUNCTION_ARGS); -extern Datum float84eq(PG_FUNCTION_ARGS); -extern Datum float84ne(PG_FUNCTION_ARGS); -extern Datum float84lt(PG_FUNCTION_ARGS); -extern Datum float84le(PG_FUNCTION_ARGS); -extern Datum float84gt(PG_FUNCTION_ARGS); -extern Datum float84ge(PG_FUNCTION_ARGS); -extern Datum width_bucket_float8(PG_FUNCTION_ARGS); - -/* dbsize.c */ -extern Datum pg_tablespace_size_oid(PG_FUNCTION_ARGS); -extern Datum pg_tablespace_size_name(PG_FUNCTION_ARGS); -extern Datum pg_database_size_oid(PG_FUNCTION_ARGS); -extern Datum pg_database_size_name(PG_FUNCTION_ARGS); -extern Datum pg_relation_size(PG_FUNCTION_ARGS); -extern Datum pg_total_relation_size(PG_FUNCTION_ARGS); -extern Datum pg_size_pretty(PG_FUNCTION_ARGS); -extern Datum pg_size_pretty_numeric(PG_FUNCTION_ARGS); -extern Datum pg_size_bytes(PG_FUNCTION_ARGS); -extern Datum pg_table_size(PG_FUNCTION_ARGS); -extern Datum pg_indexes_size(PG_FUNCTION_ARGS); -extern Datum pg_relation_filenode(PG_FUNCTION_ARGS); -extern Datum pg_filenode_relation(PG_FUNCTION_ARGS); -extern Datum pg_relation_filepath(PG_FUNCTION_ARGS); - -/* genfile.c */ -extern Datum pg_stat_file(PG_FUNCTION_ARGS); -extern Datum pg_stat_file_1arg(PG_FUNCTION_ARGS); -extern Datum pg_read_file(PG_FUNCTION_ARGS); -extern Datum pg_read_file_off_len(PG_FUNCTION_ARGS); -extern Datum pg_read_file_all(PG_FUNCTION_ARGS); -extern Datum pg_read_binary_file(PG_FUNCTION_ARGS); -extern Datum pg_read_binary_file_off_len(PG_FUNCTION_ARGS); -extern Datum pg_read_binary_file_all(PG_FUNCTION_ARGS); -extern Datum pg_ls_dir(PG_FUNCTION_ARGS); -extern Datum pg_ls_dir_1arg(PG_FUNCTION_ARGS); - -/* misc.c */ -extern Datum pg_num_nulls(PG_FUNCTION_ARGS); -extern Datum pg_num_nonnulls(PG_FUNCTION_ARGS); -extern Datum current_database(PG_FUNCTION_ARGS); -extern Datum current_query(PG_FUNCTION_ARGS); -extern Datum pg_cancel_backend(PG_FUNCTION_ARGS); -extern Datum pg_terminate_backend(PG_FUNCTION_ARGS); -extern Datum pg_reload_conf(PG_FUNCTION_ARGS); -extern Datum pg_tablespace_databases(PG_FUNCTION_ARGS); -extern Datum pg_tablespace_location(PG_FUNCTION_ARGS); -extern Datum pg_rotate_logfile(PG_FUNCTION_ARGS); -extern Datum pg_sleep(PG_FUNCTION_ARGS); -extern Datum pg_get_keywords(PG_FUNCTION_ARGS); -extern Datum pg_typeof(PG_FUNCTION_ARGS); -extern Datum pg_collation_for(PG_FUNCTION_ARGS); -extern Datum pg_relation_is_updatable(PG_FUNCTION_ARGS); -extern Datum pg_column_is_updatable(PG_FUNCTION_ARGS); -extern Datum parse_ident(PG_FUNCTION_ARGS); - /* oid.c */ -extern Datum oidin(PG_FUNCTION_ARGS); -extern Datum oidout(PG_FUNCTION_ARGS); -extern Datum oidrecv(PG_FUNCTION_ARGS); -extern Datum oidsend(PG_FUNCTION_ARGS); -extern Datum oideq(PG_FUNCTION_ARGS); -extern Datum oidne(PG_FUNCTION_ARGS); -extern Datum oidlt(PG_FUNCTION_ARGS); -extern Datum oidle(PG_FUNCTION_ARGS); -extern Datum oidge(PG_FUNCTION_ARGS); -extern Datum oidgt(PG_FUNCTION_ARGS); -extern Datum oidlarger(PG_FUNCTION_ARGS); -extern Datum oidsmaller(PG_FUNCTION_ARGS); -extern Datum oidvectorin(PG_FUNCTION_ARGS); -extern Datum oidvectorout(PG_FUNCTION_ARGS); -extern Datum oidvectorrecv(PG_FUNCTION_ARGS); -extern Datum oidvectorsend(PG_FUNCTION_ARGS); -extern Datum oidvectoreq(PG_FUNCTION_ARGS); -extern Datum oidvectorne(PG_FUNCTION_ARGS); -extern Datum oidvectorlt(PG_FUNCTION_ARGS); -extern Datum oidvectorle(PG_FUNCTION_ARGS); -extern Datum oidvectorge(PG_FUNCTION_ARGS); -extern Datum oidvectorgt(PG_FUNCTION_ARGS); extern oidvector *buildoidvector(const Oid *oids, int n); extern Oid oidparse(Node *node); -/* orderedsetaggs.c */ -extern Datum ordered_set_transition(PG_FUNCTION_ARGS); -extern Datum ordered_set_transition_multi(PG_FUNCTION_ARGS); -extern Datum percentile_disc_final(PG_FUNCTION_ARGS); -extern Datum percentile_cont_float8_final(PG_FUNCTION_ARGS); -extern Datum percentile_cont_interval_final(PG_FUNCTION_ARGS); -extern Datum percentile_disc_multi_final(PG_FUNCTION_ARGS); -extern Datum percentile_cont_float8_multi_final(PG_FUNCTION_ARGS); -extern Datum percentile_cont_interval_multi_final(PG_FUNCTION_ARGS); -extern Datum mode_final(PG_FUNCTION_ARGS); -extern Datum hypothetical_rank_final(PG_FUNCTION_ARGS); -extern Datum hypothetical_percent_rank_final(PG_FUNCTION_ARGS); -extern Datum hypothetical_cume_dist_final(PG_FUNCTION_ARGS); -extern Datum hypothetical_dense_rank_final(PG_FUNCTION_ARGS); - -/* pseudotypes.c */ -extern Datum cstring_in(PG_FUNCTION_ARGS); -extern Datum cstring_out(PG_FUNCTION_ARGS); -extern Datum cstring_recv(PG_FUNCTION_ARGS); -extern Datum cstring_send(PG_FUNCTION_ARGS); -extern Datum any_in(PG_FUNCTION_ARGS); -extern Datum any_out(PG_FUNCTION_ARGS); -extern Datum anyarray_in(PG_FUNCTION_ARGS); -extern Datum anyarray_out(PG_FUNCTION_ARGS); -extern Datum anyarray_recv(PG_FUNCTION_ARGS); -extern Datum anyarray_send(PG_FUNCTION_ARGS); -extern Datum anynonarray_in(PG_FUNCTION_ARGS); -extern Datum anynonarray_out(PG_FUNCTION_ARGS); -extern Datum anyenum_in(PG_FUNCTION_ARGS); -extern Datum anyenum_out(PG_FUNCTION_ARGS); -extern Datum anyrange_in(PG_FUNCTION_ARGS); -extern Datum anyrange_out(PG_FUNCTION_ARGS); -extern Datum void_in(PG_FUNCTION_ARGS); -extern Datum void_out(PG_FUNCTION_ARGS); -extern Datum void_recv(PG_FUNCTION_ARGS); -extern Datum void_send(PG_FUNCTION_ARGS); -extern Datum trigger_in(PG_FUNCTION_ARGS); -extern Datum trigger_out(PG_FUNCTION_ARGS); -extern Datum event_trigger_in(PG_FUNCTION_ARGS); -extern Datum event_trigger_out(PG_FUNCTION_ARGS); -extern Datum language_handler_in(PG_FUNCTION_ARGS); -extern Datum language_handler_out(PG_FUNCTION_ARGS); -extern Datum fdw_handler_in(PG_FUNCTION_ARGS); -extern Datum fdw_handler_out(PG_FUNCTION_ARGS); -extern Datum index_am_handler_in(PG_FUNCTION_ARGS); -extern Datum index_am_handler_out(PG_FUNCTION_ARGS); -extern Datum tsm_handler_in(PG_FUNCTION_ARGS); -extern Datum tsm_handler_out(PG_FUNCTION_ARGS); -extern Datum internal_in(PG_FUNCTION_ARGS); -extern Datum internal_out(PG_FUNCTION_ARGS); -extern Datum opaque_in(PG_FUNCTION_ARGS); -extern Datum opaque_out(PG_FUNCTION_ARGS); -extern Datum anyelement_in(PG_FUNCTION_ARGS); -extern Datum anyelement_out(PG_FUNCTION_ARGS); -extern Datum shell_in(PG_FUNCTION_ARGS); -extern Datum shell_out(PG_FUNCTION_ARGS); -extern Datum pg_node_tree_in(PG_FUNCTION_ARGS); -extern Datum pg_node_tree_out(PG_FUNCTION_ARGS); -extern Datum pg_node_tree_recv(PG_FUNCTION_ARGS); -extern Datum pg_node_tree_send(PG_FUNCTION_ARGS); -extern Datum pg_ddl_command_in(PG_FUNCTION_ARGS); -extern Datum pg_ddl_command_out(PG_FUNCTION_ARGS); -extern Datum pg_ddl_command_recv(PG_FUNCTION_ARGS); -extern Datum pg_ddl_command_send(PG_FUNCTION_ARGS); - /* regexp.c */ -extern Datum nameregexeq(PG_FUNCTION_ARGS); -extern Datum nameregexne(PG_FUNCTION_ARGS); -extern Datum textregexeq(PG_FUNCTION_ARGS); -extern Datum textregexne(PG_FUNCTION_ARGS); -extern Datum nameicregexeq(PG_FUNCTION_ARGS); -extern Datum nameicregexne(PG_FUNCTION_ARGS); -extern Datum texticregexeq(PG_FUNCTION_ARGS); -extern Datum texticregexne(PG_FUNCTION_ARGS); -extern Datum textregexsubstr(PG_FUNCTION_ARGS); -extern Datum textregexreplace_noopt(PG_FUNCTION_ARGS); -extern Datum textregexreplace(PG_FUNCTION_ARGS); -extern Datum similar_escape(PG_FUNCTION_ARGS); -extern Datum regexp_matches(PG_FUNCTION_ARGS); -extern Datum regexp_matches_no_flags(PG_FUNCTION_ARGS); -extern Datum regexp_split_to_table(PG_FUNCTION_ARGS); -extern Datum regexp_split_to_table_no_flags(PG_FUNCTION_ARGS); -extern Datum regexp_split_to_array(PG_FUNCTION_ARGS); -extern Datum regexp_split_to_array_no_flags(PG_FUNCTION_ARGS); extern char *regexp_fixed_prefix(text *text_re, bool case_insensitive, Oid collation, bool *exact); -/* regproc.c */ -extern Datum regprocin(PG_FUNCTION_ARGS); -extern Datum regprocout(PG_FUNCTION_ARGS); -extern Datum to_regproc(PG_FUNCTION_ARGS); -extern Datum to_regprocedure(PG_FUNCTION_ARGS); -extern Datum regprocrecv(PG_FUNCTION_ARGS); -extern Datum regprocsend(PG_FUNCTION_ARGS); -extern Datum regprocedurein(PG_FUNCTION_ARGS); -extern Datum regprocedureout(PG_FUNCTION_ARGS); -extern Datum regprocedurerecv(PG_FUNCTION_ARGS); -extern Datum regproceduresend(PG_FUNCTION_ARGS); -extern Datum regoperin(PG_FUNCTION_ARGS); -extern Datum regoperout(PG_FUNCTION_ARGS); -extern Datum regoperrecv(PG_FUNCTION_ARGS); -extern Datum regopersend(PG_FUNCTION_ARGS); -extern Datum to_regoper(PG_FUNCTION_ARGS); -extern Datum to_regoperator(PG_FUNCTION_ARGS); -extern Datum regoperatorin(PG_FUNCTION_ARGS); -extern Datum regoperatorout(PG_FUNCTION_ARGS); -extern Datum regoperatorrecv(PG_FUNCTION_ARGS); -extern Datum regoperatorsend(PG_FUNCTION_ARGS); -extern Datum regclassin(PG_FUNCTION_ARGS); -extern Datum regclassout(PG_FUNCTION_ARGS); -extern Datum regclassrecv(PG_FUNCTION_ARGS); -extern Datum regclasssend(PG_FUNCTION_ARGS); -extern Datum to_regclass(PG_FUNCTION_ARGS); -extern Datum regtypein(PG_FUNCTION_ARGS); -extern Datum regtypeout(PG_FUNCTION_ARGS); -extern Datum regtyperecv(PG_FUNCTION_ARGS); -extern Datum regtypesend(PG_FUNCTION_ARGS); -extern Datum to_regtype(PG_FUNCTION_ARGS); -extern Datum regrolein(PG_FUNCTION_ARGS); -extern Datum regroleout(PG_FUNCTION_ARGS); -extern Datum regrolerecv(PG_FUNCTION_ARGS); -extern Datum regrolesend(PG_FUNCTION_ARGS); -extern Datum to_regrole(PG_FUNCTION_ARGS); -extern Datum regnamespacein(PG_FUNCTION_ARGS); -extern Datum regnamespaceout(PG_FUNCTION_ARGS); -extern Datum regnamespacerecv(PG_FUNCTION_ARGS); -extern Datum regnamespacesend(PG_FUNCTION_ARGS); -extern Datum to_regnamespace(PG_FUNCTION_ARGS); -extern Datum regconfigin(PG_FUNCTION_ARGS); -extern Datum regconfigout(PG_FUNCTION_ARGS); -extern Datum regconfigrecv(PG_FUNCTION_ARGS); -extern Datum regconfigsend(PG_FUNCTION_ARGS); -extern Datum regdictionaryin(PG_FUNCTION_ARGS); -extern Datum regdictionaryout(PG_FUNCTION_ARGS); -extern Datum regdictionaryrecv(PG_FUNCTION_ARGS); -extern Datum regdictionarysend(PG_FUNCTION_ARGS); -extern Datum text_regclass(PG_FUNCTION_ARGS); -extern List *stringToQualifiedNameList(const char *string); -extern char *format_procedure(Oid procedure_oid); -extern char *format_procedure_qualified(Oid procedure_oid); -extern void format_procedure_parts(Oid operator_oid, List **objnames, - List **objargs); -extern char *format_operator(Oid operator_oid); -extern char *format_operator_qualified(Oid operator_oid); -extern void format_operator_parts(Oid operator_oid, List **objnames, - List **objargs); - -/* rowtypes.c */ -extern Datum record_in(PG_FUNCTION_ARGS); -extern Datum record_out(PG_FUNCTION_ARGS); -extern Datum record_recv(PG_FUNCTION_ARGS); -extern Datum record_send(PG_FUNCTION_ARGS); -extern Datum record_eq(PG_FUNCTION_ARGS); -extern Datum record_ne(PG_FUNCTION_ARGS); -extern Datum record_lt(PG_FUNCTION_ARGS); -extern Datum record_gt(PG_FUNCTION_ARGS); -extern Datum record_le(PG_FUNCTION_ARGS); -extern Datum record_ge(PG_FUNCTION_ARGS); -extern Datum btrecordcmp(PG_FUNCTION_ARGS); -extern Datum record_image_eq(PG_FUNCTION_ARGS); -extern Datum record_image_ne(PG_FUNCTION_ARGS); -extern Datum record_image_lt(PG_FUNCTION_ARGS); -extern Datum record_image_gt(PG_FUNCTION_ARGS); -extern Datum record_image_le(PG_FUNCTION_ARGS); -extern Datum record_image_ge(PG_FUNCTION_ARGS); -extern Datum btrecordimagecmp(PG_FUNCTION_ARGS); - /* ruleutils.c */ extern bool quote_all_identifiers; -extern Datum pg_get_ruledef(PG_FUNCTION_ARGS); -extern Datum pg_get_ruledef_ext(PG_FUNCTION_ARGS); -extern Datum pg_get_viewdef(PG_FUNCTION_ARGS); -extern Datum pg_get_viewdef_ext(PG_FUNCTION_ARGS); -extern Datum pg_get_viewdef_wrap(PG_FUNCTION_ARGS); -extern Datum pg_get_viewdef_name(PG_FUNCTION_ARGS); -extern Datum pg_get_viewdef_name_ext(PG_FUNCTION_ARGS); -extern Datum pg_get_indexdef(PG_FUNCTION_ARGS); -extern Datum pg_get_indexdef_ext(PG_FUNCTION_ARGS); -extern Datum pg_get_triggerdef(PG_FUNCTION_ARGS); -extern Datum pg_get_triggerdef_ext(PG_FUNCTION_ARGS); -extern Datum pg_get_constraintdef(PG_FUNCTION_ARGS); -extern Datum pg_get_constraintdef_ext(PG_FUNCTION_ARGS); -extern Datum pg_get_expr(PG_FUNCTION_ARGS); -extern Datum pg_get_expr_ext(PG_FUNCTION_ARGS); -extern Datum pg_get_userbyid(PG_FUNCTION_ARGS); -extern Datum pg_get_serial_sequence(PG_FUNCTION_ARGS); -extern Datum pg_get_functiondef(PG_FUNCTION_ARGS); -extern Datum pg_get_function_arguments(PG_FUNCTION_ARGS); -extern Datum pg_get_function_identity_arguments(PG_FUNCTION_ARGS); -extern Datum pg_get_function_result(PG_FUNCTION_ARGS); -extern Datum pg_get_function_arg_default(PG_FUNCTION_ARGS); extern const char *quote_identifier(const char *ident); extern char *quote_qualified_identifier(const char *qualifier, const char *ident); - -/* tid.c */ -extern Datum tidin(PG_FUNCTION_ARGS); -extern Datum tidout(PG_FUNCTION_ARGS); -extern Datum tidrecv(PG_FUNCTION_ARGS); -extern Datum tidsend(PG_FUNCTION_ARGS); -extern Datum tideq(PG_FUNCTION_ARGS); -extern Datum tidne(PG_FUNCTION_ARGS); -extern Datum tidlt(PG_FUNCTION_ARGS); -extern Datum tidle(PG_FUNCTION_ARGS); -extern Datum tidgt(PG_FUNCTION_ARGS); -extern Datum tidge(PG_FUNCTION_ARGS); -extern Datum bttidcmp(PG_FUNCTION_ARGS); -extern Datum tidlarger(PG_FUNCTION_ARGS); -extern Datum tidsmaller(PG_FUNCTION_ARGS); -extern Datum currtid_byreloid(PG_FUNCTION_ARGS); -extern Datum currtid_byrelname(PG_FUNCTION_ARGS); - /* varchar.c */ -extern Datum bpcharin(PG_FUNCTION_ARGS); -extern Datum bpcharout(PG_FUNCTION_ARGS); -extern Datum bpcharrecv(PG_FUNCTION_ARGS); -extern Datum bpcharsend(PG_FUNCTION_ARGS); -extern Datum bpchartypmodin(PG_FUNCTION_ARGS); -extern Datum bpchartypmodout(PG_FUNCTION_ARGS); -extern Datum bpchar(PG_FUNCTION_ARGS); -extern Datum char_bpchar(PG_FUNCTION_ARGS); -extern Datum name_bpchar(PG_FUNCTION_ARGS); -extern Datum bpchar_name(PG_FUNCTION_ARGS); -extern Datum bpchareq(PG_FUNCTION_ARGS); -extern Datum bpcharne(PG_FUNCTION_ARGS); -extern Datum bpcharlt(PG_FUNCTION_ARGS); -extern Datum bpcharle(PG_FUNCTION_ARGS); -extern Datum bpchargt(PG_FUNCTION_ARGS); -extern Datum bpcharge(PG_FUNCTION_ARGS); -extern Datum bpcharcmp(PG_FUNCTION_ARGS); -extern Datum bpchar_sortsupport(PG_FUNCTION_ARGS); -extern Datum bpchar_larger(PG_FUNCTION_ARGS); -extern Datum bpchar_smaller(PG_FUNCTION_ARGS); extern int bpchartruelen(char *s, int len); -extern Datum bpcharlen(PG_FUNCTION_ARGS); -extern Datum bpcharoctetlen(PG_FUNCTION_ARGS); -extern Datum hashbpchar(PG_FUNCTION_ARGS); -extern Datum bpchar_pattern_lt(PG_FUNCTION_ARGS); -extern Datum bpchar_pattern_le(PG_FUNCTION_ARGS); -extern Datum bpchar_pattern_gt(PG_FUNCTION_ARGS); -extern Datum bpchar_pattern_ge(PG_FUNCTION_ARGS); -extern Datum btbpchar_pattern_cmp(PG_FUNCTION_ARGS); -extern Datum btbpchar_pattern_sortsupport(PG_FUNCTION_ARGS); - -extern Datum varcharin(PG_FUNCTION_ARGS); -extern Datum varcharout(PG_FUNCTION_ARGS); -extern Datum varcharrecv(PG_FUNCTION_ARGS); -extern Datum varcharsend(PG_FUNCTION_ARGS); -extern Datum varchartypmodin(PG_FUNCTION_ARGS); -extern Datum varchartypmodout(PG_FUNCTION_ARGS); -extern Datum varchar_transform(PG_FUNCTION_ARGS); -extern Datum varchar(PG_FUNCTION_ARGS); -/* varlena.c */ +/* popular functions from varlena.c */ extern text *cstring_to_text(const char *s); extern text *cstring_to_text_with_len(const char *s, int len); extern char *text_to_cstring(const text *t); @@ -813,132 +94,8 @@ extern void text_to_cstring_buffer(const text *src, char *dst, size_t dst_len); #define CStringGetTextDatum(s) PointerGetDatum(cstring_to_text(s)) #define TextDatumGetCString(d) text_to_cstring((text *) DatumGetPointer(d)) -extern Datum textin(PG_FUNCTION_ARGS); -extern Datum textout(PG_FUNCTION_ARGS); -extern Datum textrecv(PG_FUNCTION_ARGS); -extern Datum textsend(PG_FUNCTION_ARGS); -extern Datum textcat(PG_FUNCTION_ARGS); -extern Datum texteq(PG_FUNCTION_ARGS); -extern Datum textne(PG_FUNCTION_ARGS); -extern Datum text_lt(PG_FUNCTION_ARGS); -extern Datum text_le(PG_FUNCTION_ARGS); -extern Datum text_gt(PG_FUNCTION_ARGS); -extern Datum text_ge(PG_FUNCTION_ARGS); -extern Datum text_larger(PG_FUNCTION_ARGS); -extern Datum text_smaller(PG_FUNCTION_ARGS); -extern Datum text_pattern_lt(PG_FUNCTION_ARGS); -extern Datum text_pattern_le(PG_FUNCTION_ARGS); -extern Datum text_pattern_gt(PG_FUNCTION_ARGS); -extern Datum text_pattern_ge(PG_FUNCTION_ARGS); -extern Datum bttext_pattern_cmp(PG_FUNCTION_ARGS); -extern Datum bttext_pattern_sortsupport(PG_FUNCTION_ARGS); -extern Datum textlen(PG_FUNCTION_ARGS); -extern Datum textoctetlen(PG_FUNCTION_ARGS); -extern Datum textpos(PG_FUNCTION_ARGS); -extern Datum text_substr(PG_FUNCTION_ARGS); -extern Datum text_substr_no_len(PG_FUNCTION_ARGS); -extern Datum textoverlay(PG_FUNCTION_ARGS); -extern Datum textoverlay_no_len(PG_FUNCTION_ARGS); -extern Datum name_text(PG_FUNCTION_ARGS); -extern Datum text_name(PG_FUNCTION_ARGS); -extern int varstr_cmp(char *arg1, int len1, char *arg2, int len2, Oid collid); -extern void varstr_sortsupport(SortSupport ssup, Oid collid, bool bpchar); -extern int varstr_levenshtein(const char *source, int slen, - const char *target, int tlen, - int ins_c, int del_c, int sub_c, - bool trusted); -extern int varstr_levenshtein_less_equal(const char *source, int slen, - const char *target, int tlen, - int ins_c, int del_c, int sub_c, - int max_d, bool trusted); -extern List *textToQualifiedNameList(text *textval); -extern bool SplitIdentifierString(char *rawstring, char separator, - List **namelist); -extern bool SplitDirectoriesString(char *rawstring, char separator, - List **namelist); -extern Datum replace_text(PG_FUNCTION_ARGS); -extern text *replace_text_regexp(text *src_text, void *regexp, - text *replace_text, bool glob); -extern Datum split_text(PG_FUNCTION_ARGS); -extern Datum text_to_array(PG_FUNCTION_ARGS); -extern Datum array_to_text(PG_FUNCTION_ARGS); -extern Datum text_to_array_null(PG_FUNCTION_ARGS); -extern Datum array_to_text_null(PG_FUNCTION_ARGS); -extern Datum to_hex32(PG_FUNCTION_ARGS); -extern Datum to_hex64(PG_FUNCTION_ARGS); -extern Datum md5_text(PG_FUNCTION_ARGS); -extern Datum md5_bytea(PG_FUNCTION_ARGS); - -extern Datum unknownin(PG_FUNCTION_ARGS); -extern Datum unknownout(PG_FUNCTION_ARGS); -extern Datum unknownrecv(PG_FUNCTION_ARGS); -extern Datum unknownsend(PG_FUNCTION_ARGS); - -extern Datum pg_column_size(PG_FUNCTION_ARGS); - -extern Datum bytea_string_agg_transfn(PG_FUNCTION_ARGS); -extern Datum bytea_string_agg_finalfn(PG_FUNCTION_ARGS); -extern Datum string_agg_transfn(PG_FUNCTION_ARGS); -extern Datum string_agg_finalfn(PG_FUNCTION_ARGS); - -extern Datum text_concat(PG_FUNCTION_ARGS); -extern Datum text_concat_ws(PG_FUNCTION_ARGS); -extern Datum text_left(PG_FUNCTION_ARGS); -extern Datum text_right(PG_FUNCTION_ARGS); -extern Datum text_reverse(PG_FUNCTION_ARGS); -extern Datum text_format(PG_FUNCTION_ARGS); -extern Datum text_format_nv(PG_FUNCTION_ARGS); - -/* version.c */ -extern Datum pgsql_version(PG_FUNCTION_ARGS); - /* xid.c */ -extern Datum xidin(PG_FUNCTION_ARGS); -extern Datum xidout(PG_FUNCTION_ARGS); -extern Datum xidrecv(PG_FUNCTION_ARGS); -extern Datum xidsend(PG_FUNCTION_ARGS); -extern Datum xideq(PG_FUNCTION_ARGS); -extern Datum xidneq(PG_FUNCTION_ARGS); -extern Datum xid_age(PG_FUNCTION_ARGS); -extern Datum mxid_age(PG_FUNCTION_ARGS); extern int xidComparator(const void *arg1, const void *arg2); -extern Datum cidin(PG_FUNCTION_ARGS); -extern Datum cidout(PG_FUNCTION_ARGS); -extern Datum cidrecv(PG_FUNCTION_ARGS); -extern Datum cidsend(PG_FUNCTION_ARGS); -extern Datum cideq(PG_FUNCTION_ARGS); - -/* like.c */ -extern Datum namelike(PG_FUNCTION_ARGS); -extern Datum namenlike(PG_FUNCTION_ARGS); -extern Datum nameiclike(PG_FUNCTION_ARGS); -extern Datum nameicnlike(PG_FUNCTION_ARGS); -extern Datum textlike(PG_FUNCTION_ARGS); -extern Datum textnlike(PG_FUNCTION_ARGS); -extern Datum texticlike(PG_FUNCTION_ARGS); -extern Datum texticnlike(PG_FUNCTION_ARGS); -extern Datum bytealike(PG_FUNCTION_ARGS); -extern Datum byteanlike(PG_FUNCTION_ARGS); -extern Datum like_escape(PG_FUNCTION_ARGS); -extern Datum like_escape_bytea(PG_FUNCTION_ARGS); - -/* oracle_compat.c */ -extern Datum lower(PG_FUNCTION_ARGS); -extern Datum upper(PG_FUNCTION_ARGS); -extern Datum initcap(PG_FUNCTION_ARGS); -extern Datum lpad(PG_FUNCTION_ARGS); -extern Datum rpad(PG_FUNCTION_ARGS); -extern Datum btrim(PG_FUNCTION_ARGS); -extern Datum btrim1(PG_FUNCTION_ARGS); -extern Datum byteatrim(PG_FUNCTION_ARGS); -extern Datum ltrim(PG_FUNCTION_ARGS); -extern Datum ltrim1(PG_FUNCTION_ARGS); -extern Datum rtrim(PG_FUNCTION_ARGS); -extern Datum rtrim1(PG_FUNCTION_ARGS); -extern Datum translate(PG_FUNCTION_ARGS); -extern Datum chr (PG_FUNCTION_ARGS); -extern Datum repeat(PG_FUNCTION_ARGS); -extern Datum ascii(PG_FUNCTION_ARGS); /* inet_cidr_ntop.c */ extern char *inet_cidr_ntop(int af, const void *src, int bits, @@ -949,384 +106,22 @@ extern int inet_net_pton(int af, const char *src, void *dst, size_t size); /* network.c */ -extern Datum inet_in(PG_FUNCTION_ARGS); -extern Datum inet_out(PG_FUNCTION_ARGS); -extern Datum inet_recv(PG_FUNCTION_ARGS); -extern Datum inet_send(PG_FUNCTION_ARGS); -extern Datum cidr_in(PG_FUNCTION_ARGS); -extern Datum cidr_out(PG_FUNCTION_ARGS); -extern Datum cidr_recv(PG_FUNCTION_ARGS); -extern Datum cidr_send(PG_FUNCTION_ARGS); -extern Datum network_cmp(PG_FUNCTION_ARGS); -extern Datum network_lt(PG_FUNCTION_ARGS); -extern Datum network_le(PG_FUNCTION_ARGS); -extern Datum network_eq(PG_FUNCTION_ARGS); -extern Datum network_ge(PG_FUNCTION_ARGS); -extern Datum network_gt(PG_FUNCTION_ARGS); -extern Datum network_ne(PG_FUNCTION_ARGS); -extern Datum network_smaller(PG_FUNCTION_ARGS); -extern Datum network_larger(PG_FUNCTION_ARGS); -extern Datum hashinet(PG_FUNCTION_ARGS); -extern Datum network_sub(PG_FUNCTION_ARGS); -extern Datum network_subeq(PG_FUNCTION_ARGS); -extern Datum network_sup(PG_FUNCTION_ARGS); -extern Datum network_supeq(PG_FUNCTION_ARGS); -extern Datum network_overlap(PG_FUNCTION_ARGS); -extern Datum network_network(PG_FUNCTION_ARGS); -extern Datum network_netmask(PG_FUNCTION_ARGS); -extern Datum network_hostmask(PG_FUNCTION_ARGS); -extern Datum network_masklen(PG_FUNCTION_ARGS); -extern Datum network_family(PG_FUNCTION_ARGS); -extern Datum network_broadcast(PG_FUNCTION_ARGS); -extern Datum network_host(PG_FUNCTION_ARGS); -extern Datum network_show(PG_FUNCTION_ARGS); -extern Datum inet_abbrev(PG_FUNCTION_ARGS); -extern Datum cidr_abbrev(PG_FUNCTION_ARGS); extern double convert_network_to_scalar(Datum value, Oid typid); -extern Datum inet_to_cidr(PG_FUNCTION_ARGS); -extern Datum inet_set_masklen(PG_FUNCTION_ARGS); -extern Datum cidr_set_masklen(PG_FUNCTION_ARGS); extern Datum network_scan_first(Datum in); extern Datum network_scan_last(Datum in); -extern Datum inet_client_addr(PG_FUNCTION_ARGS); -extern Datum inet_client_port(PG_FUNCTION_ARGS); -extern Datum inet_server_addr(PG_FUNCTION_ARGS); -extern Datum inet_server_port(PG_FUNCTION_ARGS); -extern Datum inetnot(PG_FUNCTION_ARGS); -extern Datum inetand(PG_FUNCTION_ARGS); -extern Datum inetor(PG_FUNCTION_ARGS); -extern Datum inetpl(PG_FUNCTION_ARGS); -extern Datum inetmi_int8(PG_FUNCTION_ARGS); -extern Datum inetmi(PG_FUNCTION_ARGS); extern void clean_ipv6_addr(int addr_family, char *addr); -extern Datum inet_same_family(PG_FUNCTION_ARGS); -extern Datum inet_merge(PG_FUNCTION_ARGS); - -/* mac.c */ -extern Datum macaddr_in(PG_FUNCTION_ARGS); -extern Datum macaddr_out(PG_FUNCTION_ARGS); -extern Datum macaddr_recv(PG_FUNCTION_ARGS); -extern Datum macaddr_send(PG_FUNCTION_ARGS); -extern Datum macaddr_cmp(PG_FUNCTION_ARGS); -extern Datum macaddr_lt(PG_FUNCTION_ARGS); -extern Datum macaddr_le(PG_FUNCTION_ARGS); -extern Datum macaddr_eq(PG_FUNCTION_ARGS); -extern Datum macaddr_ge(PG_FUNCTION_ARGS); -extern Datum macaddr_gt(PG_FUNCTION_ARGS); -extern Datum macaddr_ne(PG_FUNCTION_ARGS); -extern Datum macaddr_not(PG_FUNCTION_ARGS); -extern Datum macaddr_and(PG_FUNCTION_ARGS); -extern Datum macaddr_or(PG_FUNCTION_ARGS); -extern Datum macaddr_trunc(PG_FUNCTION_ARGS); -extern Datum hashmacaddr(PG_FUNCTION_ARGS); /* numeric.c */ -extern Datum numeric_in(PG_FUNCTION_ARGS); -extern Datum numeric_out(PG_FUNCTION_ARGS); -extern Datum numeric_recv(PG_FUNCTION_ARGS); -extern Datum numeric_send(PG_FUNCTION_ARGS); -extern Datum numerictypmodin(PG_FUNCTION_ARGS); -extern Datum numerictypmodout(PG_FUNCTION_ARGS); -extern Datum numeric_transform(PG_FUNCTION_ARGS); -extern Datum numeric (PG_FUNCTION_ARGS); -extern Datum numeric_abs(PG_FUNCTION_ARGS); -extern Datum numeric_uminus(PG_FUNCTION_ARGS); -extern Datum numeric_uplus(PG_FUNCTION_ARGS); -extern Datum numeric_sign(PG_FUNCTION_ARGS); -extern Datum numeric_round(PG_FUNCTION_ARGS); -extern Datum numeric_trunc(PG_FUNCTION_ARGS); -extern Datum numeric_ceil(PG_FUNCTION_ARGS); -extern Datum numeric_floor(PG_FUNCTION_ARGS); -extern Datum numeric_sortsupport(PG_FUNCTION_ARGS); -extern Datum numeric_cmp(PG_FUNCTION_ARGS); -extern Datum numeric_eq(PG_FUNCTION_ARGS); -extern Datum numeric_ne(PG_FUNCTION_ARGS); -extern Datum numeric_gt(PG_FUNCTION_ARGS); -extern Datum numeric_ge(PG_FUNCTION_ARGS); -extern Datum numeric_lt(PG_FUNCTION_ARGS); -extern Datum numeric_le(PG_FUNCTION_ARGS); -extern Datum numeric_add(PG_FUNCTION_ARGS); -extern Datum numeric_sub(PG_FUNCTION_ARGS); -extern Datum numeric_mul(PG_FUNCTION_ARGS); -extern Datum numeric_div(PG_FUNCTION_ARGS); -extern Datum numeric_div_trunc(PG_FUNCTION_ARGS); -extern Datum numeric_mod(PG_FUNCTION_ARGS); -extern Datum numeric_inc(PG_FUNCTION_ARGS); -extern Datum numeric_smaller(PG_FUNCTION_ARGS); -extern Datum numeric_larger(PG_FUNCTION_ARGS); -extern Datum numeric_fac(PG_FUNCTION_ARGS); -extern Datum numeric_sqrt(PG_FUNCTION_ARGS); -extern Datum numeric_exp(PG_FUNCTION_ARGS); -extern Datum numeric_ln(PG_FUNCTION_ARGS); -extern Datum numeric_log(PG_FUNCTION_ARGS); -extern Datum numeric_power(PG_FUNCTION_ARGS); -extern Datum numeric_scale(PG_FUNCTION_ARGS); -extern Datum int4_numeric(PG_FUNCTION_ARGS); -extern Datum numeric_int4(PG_FUNCTION_ARGS); -extern Datum int8_numeric(PG_FUNCTION_ARGS); -extern Datum numeric_int8(PG_FUNCTION_ARGS); -extern Datum int2_numeric(PG_FUNCTION_ARGS); -extern Datum numeric_int2(PG_FUNCTION_ARGS); -extern Datum float8_numeric(PG_FUNCTION_ARGS); -extern Datum numeric_float8(PG_FUNCTION_ARGS); extern Datum numeric_float8_no_overflow(PG_FUNCTION_ARGS); -extern Datum float4_numeric(PG_FUNCTION_ARGS); -extern Datum numeric_float4(PG_FUNCTION_ARGS); -extern Datum numeric_accum(PG_FUNCTION_ARGS); -extern Datum numeric_combine(PG_FUNCTION_ARGS); -extern Datum numeric_avg_accum(PG_FUNCTION_ARGS); -extern Datum numeric_avg_combine(PG_FUNCTION_ARGS); -extern Datum numeric_avg_serialize(PG_FUNCTION_ARGS); -extern Datum numeric_avg_deserialize(PG_FUNCTION_ARGS); -extern Datum numeric_serialize(PG_FUNCTION_ARGS); -extern Datum numeric_deserialize(PG_FUNCTION_ARGS); -extern Datum numeric_accum_inv(PG_FUNCTION_ARGS); -extern Datum int2_accum(PG_FUNCTION_ARGS); -extern Datum int4_accum(PG_FUNCTION_ARGS); -extern Datum int8_accum(PG_FUNCTION_ARGS); -extern Datum numeric_poly_combine(PG_FUNCTION_ARGS); -extern Datum numeric_poly_serialize(PG_FUNCTION_ARGS); -extern Datum numeric_poly_deserialize(PG_FUNCTION_ARGS); -extern Datum int2_accum_inv(PG_FUNCTION_ARGS); -extern Datum int4_accum_inv(PG_FUNCTION_ARGS); -extern Datum int8_accum_inv(PG_FUNCTION_ARGS); -extern Datum int8_avg_accum(PG_FUNCTION_ARGS); -extern Datum int8_avg_combine(PG_FUNCTION_ARGS); -extern Datum int8_avg_serialize(PG_FUNCTION_ARGS); -extern Datum int8_avg_deserialize(PG_FUNCTION_ARGS); -extern Datum numeric_avg(PG_FUNCTION_ARGS); -extern Datum numeric_sum(PG_FUNCTION_ARGS); -extern Datum numeric_var_pop(PG_FUNCTION_ARGS); -extern Datum numeric_var_samp(PG_FUNCTION_ARGS); -extern Datum numeric_stddev_pop(PG_FUNCTION_ARGS); -extern Datum numeric_stddev_samp(PG_FUNCTION_ARGS); -extern Datum numeric_poly_sum(PG_FUNCTION_ARGS); -extern Datum numeric_poly_avg(PG_FUNCTION_ARGS); -extern Datum numeric_poly_var_pop(PG_FUNCTION_ARGS); -extern Datum numeric_poly_var_samp(PG_FUNCTION_ARGS); -extern Datum numeric_poly_stddev_pop(PG_FUNCTION_ARGS); -extern Datum numeric_poly_stddev_samp(PG_FUNCTION_ARGS); -extern Datum int2_sum(PG_FUNCTION_ARGS); -extern Datum int4_sum(PG_FUNCTION_ARGS); -extern Datum int8_sum(PG_FUNCTION_ARGS); -extern Datum int2_avg_accum(PG_FUNCTION_ARGS); -extern Datum int4_avg_accum(PG_FUNCTION_ARGS); -extern Datum int4_avg_combine(PG_FUNCTION_ARGS); -extern Datum int2_avg_accum_inv(PG_FUNCTION_ARGS); -extern Datum int4_avg_accum_inv(PG_FUNCTION_ARGS); -extern Datum int8_avg_accum_inv(PG_FUNCTION_ARGS); -extern Datum int8_avg(PG_FUNCTION_ARGS); -extern Datum int2int4_sum(PG_FUNCTION_ARGS); -extern Datum width_bucket_numeric(PG_FUNCTION_ARGS); -extern Datum hash_numeric(PG_FUNCTION_ARGS); -extern Datum generate_series_numeric(PG_FUNCTION_ARGS); -extern Datum generate_series_step_numeric(PG_FUNCTION_ARGS); - -/* ri_triggers.c */ -extern Datum RI_FKey_check_ins(PG_FUNCTION_ARGS); -extern Datum RI_FKey_check_upd(PG_FUNCTION_ARGS); -extern Datum RI_FKey_noaction_del(PG_FUNCTION_ARGS); -extern Datum RI_FKey_noaction_upd(PG_FUNCTION_ARGS); -extern Datum RI_FKey_cascade_del(PG_FUNCTION_ARGS); -extern Datum RI_FKey_cascade_upd(PG_FUNCTION_ARGS); -extern Datum RI_FKey_restrict_del(PG_FUNCTION_ARGS); -extern Datum RI_FKey_restrict_upd(PG_FUNCTION_ARGS); -extern Datum RI_FKey_setnull_del(PG_FUNCTION_ARGS); -extern Datum RI_FKey_setnull_upd(PG_FUNCTION_ARGS); -extern Datum RI_FKey_setdefault_del(PG_FUNCTION_ARGS); -extern Datum RI_FKey_setdefault_upd(PG_FUNCTION_ARGS); - -/* trigfuncs.c */ -extern Datum suppress_redundant_updates_trigger(PG_FUNCTION_ARGS); - -/* encoding support functions */ -extern Datum getdatabaseencoding(PG_FUNCTION_ARGS); -extern Datum database_character_set(PG_FUNCTION_ARGS); -extern Datum pg_client_encoding(PG_FUNCTION_ARGS); -extern Datum PG_encoding_to_char(PG_FUNCTION_ARGS); -extern Datum PG_char_to_encoding(PG_FUNCTION_ARGS); -extern Datum PG_character_set_name(PG_FUNCTION_ARGS); -extern Datum PG_character_set_id(PG_FUNCTION_ARGS); -extern Datum pg_convert(PG_FUNCTION_ARGS); -extern Datum pg_convert_to(PG_FUNCTION_ARGS); -extern Datum pg_convert_from(PG_FUNCTION_ARGS); -extern Datum length_in_encoding(PG_FUNCTION_ARGS); -extern Datum pg_encoding_max_length_sql(PG_FUNCTION_ARGS); /* format_type.c */ -extern Datum format_type(PG_FUNCTION_ARGS); extern char *format_type_be(Oid type_oid); extern char *format_type_be_qualified(Oid type_oid); extern char *format_type_with_typemod(Oid type_oid, int32 typemod); extern char *format_type_with_typemod_qualified(Oid type_oid, int32 typemod); -extern Datum oidvectortypes(PG_FUNCTION_ARGS); extern int32 type_maximum_size(Oid type_oid, int32 typemod); /* quote.c */ -extern Datum quote_ident(PG_FUNCTION_ARGS); -extern Datum quote_literal(PG_FUNCTION_ARGS); extern char *quote_literal_cstr(const char *rawstr); -extern Datum quote_nullable(PG_FUNCTION_ARGS); - -/* guc.c */ -extern Datum show_config_by_name(PG_FUNCTION_ARGS); -extern Datum show_config_by_name_missing_ok(PG_FUNCTION_ARGS); -extern Datum set_config_by_name(PG_FUNCTION_ARGS); -extern Datum show_all_settings(PG_FUNCTION_ARGS); -extern Datum show_all_file_settings(PG_FUNCTION_ARGS); - -/* pg_config.c */ -extern Datum pg_config(PG_FUNCTION_ARGS); - -/* pg_controldata.c */ -extern Datum pg_control_checkpoint(PG_FUNCTION_ARGS); -extern Datum pg_control_system(PG_FUNCTION_ARGS); -extern Datum pg_control_init(PG_FUNCTION_ARGS); -extern Datum pg_control_recovery(PG_FUNCTION_ARGS); - -/* rls.c */ -extern Datum row_security_active(PG_FUNCTION_ARGS); -extern Datum row_security_active_name(PG_FUNCTION_ARGS); - -/* lockfuncs.c */ -extern Datum pg_lock_status(PG_FUNCTION_ARGS); -extern Datum pg_blocking_pids(PG_FUNCTION_ARGS); -extern Datum pg_advisory_lock_int8(PG_FUNCTION_ARGS); -extern Datum pg_advisory_xact_lock_int8(PG_FUNCTION_ARGS); -extern Datum pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS); -extern Datum pg_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS); -extern Datum pg_try_advisory_lock_int8(PG_FUNCTION_ARGS); -extern Datum pg_try_advisory_xact_lock_int8(PG_FUNCTION_ARGS); -extern Datum pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS); -extern Datum pg_try_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS); -extern Datum pg_advisory_unlock_int8(PG_FUNCTION_ARGS); -extern Datum pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS); -extern Datum pg_advisory_lock_int4(PG_FUNCTION_ARGS); -extern Datum pg_advisory_xact_lock_int4(PG_FUNCTION_ARGS); -extern Datum pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS); -extern Datum pg_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS); -extern Datum pg_try_advisory_lock_int4(PG_FUNCTION_ARGS); -extern Datum pg_try_advisory_xact_lock_int4(PG_FUNCTION_ARGS); -extern Datum pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS); -extern Datum pg_try_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS); -extern Datum pg_advisory_unlock_int4(PG_FUNCTION_ARGS); -extern Datum pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS); -extern Datum pg_advisory_unlock_all(PG_FUNCTION_ARGS); - -/* txid.c */ -extern Datum txid_snapshot_in(PG_FUNCTION_ARGS); -extern Datum txid_snapshot_out(PG_FUNCTION_ARGS); -extern Datum txid_snapshot_recv(PG_FUNCTION_ARGS); -extern Datum txid_snapshot_send(PG_FUNCTION_ARGS); -extern Datum txid_current(PG_FUNCTION_ARGS); -extern Datum txid_current_snapshot(PG_FUNCTION_ARGS); -extern Datum txid_snapshot_xmin(PG_FUNCTION_ARGS); -extern Datum txid_snapshot_xmax(PG_FUNCTION_ARGS); -extern Datum txid_snapshot_xip(PG_FUNCTION_ARGS); -extern Datum txid_visible_in_snapshot(PG_FUNCTION_ARGS); - -/* uuid.c */ -extern Datum uuid_in(PG_FUNCTION_ARGS); -extern Datum uuid_out(PG_FUNCTION_ARGS); -extern Datum uuid_send(PG_FUNCTION_ARGS); -extern Datum uuid_recv(PG_FUNCTION_ARGS); -extern Datum uuid_lt(PG_FUNCTION_ARGS); -extern Datum uuid_le(PG_FUNCTION_ARGS); -extern Datum uuid_eq(PG_FUNCTION_ARGS); -extern Datum uuid_ge(PG_FUNCTION_ARGS); -extern Datum uuid_gt(PG_FUNCTION_ARGS); -extern Datum uuid_ne(PG_FUNCTION_ARGS); -extern Datum uuid_cmp(PG_FUNCTION_ARGS); -extern Datum uuid_sortsupport(PG_FUNCTION_ARGS); -extern Datum uuid_hash(PG_FUNCTION_ARGS); - -/* windowfuncs.c */ -extern Datum window_row_number(PG_FUNCTION_ARGS); -extern Datum window_rank(PG_FUNCTION_ARGS); -extern Datum window_dense_rank(PG_FUNCTION_ARGS); -extern Datum window_percent_rank(PG_FUNCTION_ARGS); -extern Datum window_cume_dist(PG_FUNCTION_ARGS); -extern Datum window_ntile(PG_FUNCTION_ARGS); -extern Datum window_lag(PG_FUNCTION_ARGS); -extern Datum window_lag_with_offset(PG_FUNCTION_ARGS); -extern Datum window_lag_with_offset_and_default(PG_FUNCTION_ARGS); -extern Datum window_lead(PG_FUNCTION_ARGS); -extern Datum window_lead_with_offset(PG_FUNCTION_ARGS); -extern Datum window_lead_with_offset_and_default(PG_FUNCTION_ARGS); -extern Datum window_first_value(PG_FUNCTION_ARGS); -extern Datum window_last_value(PG_FUNCTION_ARGS); -extern Datum window_nth_value(PG_FUNCTION_ARGS); - -/* access/spgist/spgquadtreeproc.c */ -extern Datum spg_quad_config(PG_FUNCTION_ARGS); -extern Datum spg_quad_choose(PG_FUNCTION_ARGS); -extern Datum spg_quad_picksplit(PG_FUNCTION_ARGS); -extern Datum spg_quad_inner_consistent(PG_FUNCTION_ARGS); -extern Datum spg_quad_leaf_consistent(PG_FUNCTION_ARGS); - -/* access/spgist/spgkdtreeproc.c */ -extern Datum spg_kd_config(PG_FUNCTION_ARGS); -extern Datum spg_kd_choose(PG_FUNCTION_ARGS); -extern Datum spg_kd_picksplit(PG_FUNCTION_ARGS); -extern Datum spg_kd_inner_consistent(PG_FUNCTION_ARGS); - -/* access/spgist/spgtextproc.c */ -extern Datum spg_text_config(PG_FUNCTION_ARGS); -extern Datum spg_text_choose(PG_FUNCTION_ARGS); -extern Datum spg_text_picksplit(PG_FUNCTION_ARGS); -extern Datum spg_text_inner_consistent(PG_FUNCTION_ARGS); -extern Datum spg_text_leaf_consistent(PG_FUNCTION_ARGS); - -/* access/gin/ginarrayproc.c */ -extern Datum ginarrayextract(PG_FUNCTION_ARGS); -extern Datum ginarrayextract_2args(PG_FUNCTION_ARGS); -extern Datum ginqueryarrayextract(PG_FUNCTION_ARGS); -extern Datum ginarrayconsistent(PG_FUNCTION_ARGS); -extern Datum ginarraytriconsistent(PG_FUNCTION_ARGS); - -/* access/tablesample/bernoulli.c */ -extern Datum tsm_bernoulli_handler(PG_FUNCTION_ARGS); - -/* access/tablesample/system.c */ -extern Datum tsm_system_handler(PG_FUNCTION_ARGS); - -/* access/transam/twophase.c */ -extern Datum pg_prepared_xact(PG_FUNCTION_ARGS); - -/* access/transam/multixact.c */ -extern Datum pg_get_multixact_members(PG_FUNCTION_ARGS); - -/* access/transam/committs.c */ -extern Datum pg_xact_commit_timestamp(PG_FUNCTION_ARGS); -extern Datum pg_last_committed_xact(PG_FUNCTION_ARGS); - -/* catalogs/dependency.c */ -extern Datum pg_describe_object(PG_FUNCTION_ARGS); -extern Datum pg_identify_object(PG_FUNCTION_ARGS); -extern Datum pg_identify_object_as_address(PG_FUNCTION_ARGS); - -/* catalog/objectaddress.c */ -extern Datum pg_get_object_address(PG_FUNCTION_ARGS); - -/* commands/constraint.c */ -extern Datum unique_key_recheck(PG_FUNCTION_ARGS); - -/* commands/event_trigger.c */ -extern Datum pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS); -extern Datum pg_event_trigger_table_rewrite_oid(PG_FUNCTION_ARGS); -extern Datum pg_event_trigger_table_rewrite_reason(PG_FUNCTION_ARGS); -extern Datum pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS); - -/* commands/extension.c */ -extern Datum pg_available_extensions(PG_FUNCTION_ARGS); -extern Datum pg_available_extension_versions(PG_FUNCTION_ARGS); -extern Datum pg_extension_update_paths(PG_FUNCTION_ARGS); -extern Datum pg_extension_config_dump(PG_FUNCTION_ARGS); - -/* commands/prepare.c */ -extern Datum pg_prepared_statement(PG_FUNCTION_ARGS); - -/* utils/mmgr/portalmem.c */ -extern Datum pg_cursor(PG_FUNCTION_ARGS); #endif /* BUILTINS_H */ diff --git a/src/include/utils/bytea.h b/src/include/utils/bytea.h index c41e6b4b7a..818e65707f 100644 --- a/src/include/utils/bytea.h +++ b/src/include/utils/bytea.h @@ -4,7 +4,7 @@ * Declarations for BYTEA data type support. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/bytea.h @@ -25,29 +25,4 @@ typedef enum extern int bytea_output; /* ByteaOutputType, but int for GUC enum */ -/* functions are in utils/adt/varlena.c */ -extern Datum byteain(PG_FUNCTION_ARGS); -extern Datum byteaout(PG_FUNCTION_ARGS); -extern Datum bytearecv(PG_FUNCTION_ARGS); -extern Datum byteasend(PG_FUNCTION_ARGS); -extern Datum byteaoctetlen(PG_FUNCTION_ARGS); -extern Datum byteaGetByte(PG_FUNCTION_ARGS); -extern Datum byteaGetBit(PG_FUNCTION_ARGS); -extern Datum byteaSetByte(PG_FUNCTION_ARGS); -extern Datum byteaSetBit(PG_FUNCTION_ARGS); -extern Datum byteaeq(PG_FUNCTION_ARGS); -extern Datum byteane(PG_FUNCTION_ARGS); -extern Datum bytealt(PG_FUNCTION_ARGS); -extern Datum byteale(PG_FUNCTION_ARGS); -extern Datum byteagt(PG_FUNCTION_ARGS); -extern Datum byteage(PG_FUNCTION_ARGS); -extern Datum byteacmp(PG_FUNCTION_ARGS); -extern Datum bytea_sortsupport(PG_FUNCTION_ARGS); -extern Datum byteacat(PG_FUNCTION_ARGS); -extern Datum byteapos(PG_FUNCTION_ARGS); -extern Datum bytea_substr(PG_FUNCTION_ARGS); -extern Datum bytea_substr_no_len(PG_FUNCTION_ARGS); -extern Datum byteaoverlay(PG_FUNCTION_ARGS); -extern Datum byteaoverlay_no_len(PG_FUNCTION_ARGS); - #endif /* BYTEA_H */ diff --git a/src/include/utils/cash.h b/src/include/utils/cash.h index 3a491f9231..84083677e1 100644 --- a/src/include/utils/cash.h +++ b/src/include/utils/cash.h @@ -22,52 +22,4 @@ typedef int64 Cash; #define PG_GETARG_CASH(n) DatumGetCash(PG_GETARG_DATUM(n)) #define PG_RETURN_CASH(x) return CashGetDatum(x) -extern Datum cash_in(PG_FUNCTION_ARGS); -extern Datum cash_out(PG_FUNCTION_ARGS); -extern Datum cash_recv(PG_FUNCTION_ARGS); -extern Datum cash_send(PG_FUNCTION_ARGS); - -extern Datum cash_eq(PG_FUNCTION_ARGS); -extern Datum cash_ne(PG_FUNCTION_ARGS); -extern Datum cash_lt(PG_FUNCTION_ARGS); -extern Datum cash_le(PG_FUNCTION_ARGS); -extern Datum cash_gt(PG_FUNCTION_ARGS); -extern Datum cash_ge(PG_FUNCTION_ARGS); -extern Datum cash_cmp(PG_FUNCTION_ARGS); - -extern Datum cash_pl(PG_FUNCTION_ARGS); -extern Datum cash_mi(PG_FUNCTION_ARGS); -extern Datum cash_div_cash(PG_FUNCTION_ARGS); - -extern Datum cash_mul_flt8(PG_FUNCTION_ARGS); -extern Datum flt8_mul_cash(PG_FUNCTION_ARGS); -extern Datum cash_div_flt8(PG_FUNCTION_ARGS); - -extern Datum cash_mul_flt4(PG_FUNCTION_ARGS); -extern Datum flt4_mul_cash(PG_FUNCTION_ARGS); -extern Datum cash_div_flt4(PG_FUNCTION_ARGS); - -extern Datum cash_mul_int8(PG_FUNCTION_ARGS); -extern Datum int8_mul_cash(PG_FUNCTION_ARGS); -extern Datum cash_div_int8(PG_FUNCTION_ARGS); - -extern Datum cash_mul_int4(PG_FUNCTION_ARGS); -extern Datum int4_mul_cash(PG_FUNCTION_ARGS); -extern Datum cash_div_int4(PG_FUNCTION_ARGS); - -extern Datum cash_mul_int2(PG_FUNCTION_ARGS); -extern Datum int2_mul_cash(PG_FUNCTION_ARGS); -extern Datum cash_div_int2(PG_FUNCTION_ARGS); - -extern Datum cashlarger(PG_FUNCTION_ARGS); -extern Datum cashsmaller(PG_FUNCTION_ARGS); - -extern Datum cash_words(PG_FUNCTION_ARGS); - -extern Datum cash_numeric(PG_FUNCTION_ARGS); -extern Datum numeric_cash(PG_FUNCTION_ARGS); - -extern Datum int4_cash(PG_FUNCTION_ARGS); -extern Datum int8_cash(PG_FUNCTION_ARGS); - #endif /* CASH_H */ diff --git a/src/include/utils/catcache.h b/src/include/utils/catcache.h index 253c7b53ed..299d246585 100644 --- a/src/include/utils/catcache.h +++ b/src/include/utils/catcache.h @@ -10,7 +10,7 @@ * guarantee that there can only be one matching row for a key combination. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/catcache.h @@ -52,6 +52,12 @@ typedef struct catcache * heap scans */ bool cc_isname[CATCACHE_MAXKEYS]; /* flag "name" key columns */ dlist_head cc_lists; /* list of CatCList structs */ + dlist_head *cc_bucket; /* hash buckets */ + + /* + * Keep these at the end, so that compiling catcache.c with CATCACHE_STATS + * doesn't break ABI for other modules + */ #ifdef CATCACHE_STATS long cc_searches; /* total # searches against this cache */ long cc_hits; /* # of matches against existing entry */ @@ -66,7 +72,6 @@ typedef struct catcache long cc_lsearches; /* total # list-searches */ long cc_lhits; /* # of matches against existing lists */ #endif - dlist_head *cc_bucket; /* hash buckets */ } CatCache; diff --git a/src/include/utils/combocid.h b/src/include/utils/combocid.h index 299b2edbfc..1cb0e74275 100644 --- a/src/include/utils/combocid.h +++ b/src/include/utils/combocid.h @@ -4,7 +4,7 @@ * Combo command ID support routines * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/combocid.h diff --git a/src/include/utils/date.h b/src/include/utils/date.h index 1b962af7d8..e5c44b98cb 100644 --- a/src/include/utils/date.h +++ b/src/include/utils/date.h @@ -4,7 +4,7 @@ * Definitions for the SQL "date" and "time" types. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/date.h @@ -89,120 +89,11 @@ typedef struct /* date.c */ +extern int32 anytime_typmod_check(bool istz, int32 typmod); extern double date2timestamp_no_overflow(DateADT dateVal); extern void EncodeSpecialDate(DateADT dt, char *str); - -extern Datum date_in(PG_FUNCTION_ARGS); -extern Datum date_out(PG_FUNCTION_ARGS); -extern Datum date_recv(PG_FUNCTION_ARGS); -extern Datum date_send(PG_FUNCTION_ARGS); -extern Datum make_date(PG_FUNCTION_ARGS); -extern Datum date_eq(PG_FUNCTION_ARGS); -extern Datum date_ne(PG_FUNCTION_ARGS); -extern Datum date_lt(PG_FUNCTION_ARGS); -extern Datum date_le(PG_FUNCTION_ARGS); -extern Datum date_gt(PG_FUNCTION_ARGS); -extern Datum date_ge(PG_FUNCTION_ARGS); -extern Datum date_cmp(PG_FUNCTION_ARGS); -extern Datum date_sortsupport(PG_FUNCTION_ARGS); -extern Datum date_finite(PG_FUNCTION_ARGS); -extern Datum date_larger(PG_FUNCTION_ARGS); -extern Datum date_smaller(PG_FUNCTION_ARGS); -extern Datum date_mi(PG_FUNCTION_ARGS); -extern Datum date_pli(PG_FUNCTION_ARGS); -extern Datum date_mii(PG_FUNCTION_ARGS); -extern Datum date_eq_timestamp(PG_FUNCTION_ARGS); -extern Datum date_ne_timestamp(PG_FUNCTION_ARGS); -extern Datum date_lt_timestamp(PG_FUNCTION_ARGS); -extern Datum date_le_timestamp(PG_FUNCTION_ARGS); -extern Datum date_gt_timestamp(PG_FUNCTION_ARGS); -extern Datum date_ge_timestamp(PG_FUNCTION_ARGS); -extern Datum date_cmp_timestamp(PG_FUNCTION_ARGS); -extern Datum date_eq_timestamptz(PG_FUNCTION_ARGS); -extern Datum date_ne_timestamptz(PG_FUNCTION_ARGS); -extern Datum date_lt_timestamptz(PG_FUNCTION_ARGS); -extern Datum date_le_timestamptz(PG_FUNCTION_ARGS); -extern Datum date_gt_timestamptz(PG_FUNCTION_ARGS); -extern Datum date_ge_timestamptz(PG_FUNCTION_ARGS); -extern Datum date_cmp_timestamptz(PG_FUNCTION_ARGS); -extern Datum timestamp_eq_date(PG_FUNCTION_ARGS); -extern Datum timestamp_ne_date(PG_FUNCTION_ARGS); -extern Datum timestamp_lt_date(PG_FUNCTION_ARGS); -extern Datum timestamp_le_date(PG_FUNCTION_ARGS); -extern Datum timestamp_gt_date(PG_FUNCTION_ARGS); -extern Datum timestamp_ge_date(PG_FUNCTION_ARGS); -extern Datum timestamp_cmp_date(PG_FUNCTION_ARGS); -extern Datum timestamptz_eq_date(PG_FUNCTION_ARGS); -extern Datum timestamptz_ne_date(PG_FUNCTION_ARGS); -extern Datum timestamptz_lt_date(PG_FUNCTION_ARGS); -extern Datum timestamptz_le_date(PG_FUNCTION_ARGS); -extern Datum timestamptz_gt_date(PG_FUNCTION_ARGS); -extern Datum timestamptz_ge_date(PG_FUNCTION_ARGS); -extern Datum timestamptz_cmp_date(PG_FUNCTION_ARGS); -extern Datum date_pl_interval(PG_FUNCTION_ARGS); -extern Datum date_mi_interval(PG_FUNCTION_ARGS); -extern Datum date_timestamp(PG_FUNCTION_ARGS); -extern Datum timestamp_date(PG_FUNCTION_ARGS); -extern Datum date_timestamptz(PG_FUNCTION_ARGS); -extern Datum timestamptz_date(PG_FUNCTION_ARGS); -extern Datum datetime_timestamp(PG_FUNCTION_ARGS); -extern Datum abstime_date(PG_FUNCTION_ARGS); - -extern Datum time_in(PG_FUNCTION_ARGS); -extern Datum time_out(PG_FUNCTION_ARGS); -extern Datum time_recv(PG_FUNCTION_ARGS); -extern Datum time_send(PG_FUNCTION_ARGS); -extern Datum timetypmodin(PG_FUNCTION_ARGS); -extern Datum timetypmodout(PG_FUNCTION_ARGS); -extern Datum make_time(PG_FUNCTION_ARGS); -extern Datum time_transform(PG_FUNCTION_ARGS); -extern Datum time_scale(PG_FUNCTION_ARGS); -extern Datum time_eq(PG_FUNCTION_ARGS); -extern Datum time_ne(PG_FUNCTION_ARGS); -extern Datum time_lt(PG_FUNCTION_ARGS); -extern Datum time_le(PG_FUNCTION_ARGS); -extern Datum time_gt(PG_FUNCTION_ARGS); -extern Datum time_ge(PG_FUNCTION_ARGS); -extern Datum time_cmp(PG_FUNCTION_ARGS); -extern Datum time_hash(PG_FUNCTION_ARGS); -extern Datum overlaps_time(PG_FUNCTION_ARGS); -extern Datum time_larger(PG_FUNCTION_ARGS); -extern Datum time_smaller(PG_FUNCTION_ARGS); -extern Datum time_mi_time(PG_FUNCTION_ARGS); -extern Datum timestamp_time(PG_FUNCTION_ARGS); -extern Datum timestamptz_time(PG_FUNCTION_ARGS); -extern Datum time_interval(PG_FUNCTION_ARGS); -extern Datum interval_time(PG_FUNCTION_ARGS); -extern Datum time_pl_interval(PG_FUNCTION_ARGS); -extern Datum time_mi_interval(PG_FUNCTION_ARGS); -extern Datum time_part(PG_FUNCTION_ARGS); - -extern Datum timetz_in(PG_FUNCTION_ARGS); -extern Datum timetz_out(PG_FUNCTION_ARGS); -extern Datum timetz_recv(PG_FUNCTION_ARGS); -extern Datum timetz_send(PG_FUNCTION_ARGS); -extern Datum timetztypmodin(PG_FUNCTION_ARGS); -extern Datum timetztypmodout(PG_FUNCTION_ARGS); -extern Datum timetz_scale(PG_FUNCTION_ARGS); -extern Datum timetz_eq(PG_FUNCTION_ARGS); -extern Datum timetz_ne(PG_FUNCTION_ARGS); -extern Datum timetz_lt(PG_FUNCTION_ARGS); -extern Datum timetz_le(PG_FUNCTION_ARGS); -extern Datum timetz_gt(PG_FUNCTION_ARGS); -extern Datum timetz_ge(PG_FUNCTION_ARGS); -extern Datum timetz_cmp(PG_FUNCTION_ARGS); -extern Datum timetz_hash(PG_FUNCTION_ARGS); -extern Datum overlaps_timetz(PG_FUNCTION_ARGS); -extern Datum timetz_larger(PG_FUNCTION_ARGS); -extern Datum timetz_smaller(PG_FUNCTION_ARGS); -extern Datum timetz_time(PG_FUNCTION_ARGS); -extern Datum time_timetz(PG_FUNCTION_ARGS); -extern Datum timestamptz_timetz(PG_FUNCTION_ARGS); -extern Datum datetimetz_timestamptz(PG_FUNCTION_ARGS); -extern Datum timetz_part(PG_FUNCTION_ARGS); -extern Datum timetz_zone(PG_FUNCTION_ARGS); -extern Datum timetz_izone(PG_FUNCTION_ARGS); -extern Datum timetz_pl_interval(PG_FUNCTION_ARGS); -extern Datum timetz_mi_interval(PG_FUNCTION_ARGS); +extern DateADT GetSQLCurrentDate(void); +extern TimeTzADT *GetSQLCurrentTime(int32 typmod); +extern TimeADT GetSQLLocalTime(int32 typmod); #endif /* DATE_H */ diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h index c57dc05ff8..f0e77982ce 100644 --- a/src/include/utils/datetime.h +++ b/src/include/utils/datetime.h @@ -6,7 +6,7 @@ * including abstime, reltime, date, and time. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/datetime.h @@ -346,7 +346,4 @@ extern TimeZoneAbbrevTable *ConvertTimeZoneAbbrevs(struct tzEntry *abbrevs, int n); extern void InstallTimeZoneAbbrevs(TimeZoneAbbrevTable *tbl); -extern Datum pg_timezone_abbrevs(PG_FUNCTION_ARGS); -extern Datum pg_timezone_names(PG_FUNCTION_ARGS); - #endif /* DATETIME_H */ diff --git a/src/include/utils/datum.h b/src/include/utils/datum.h index 73ec689d3c..a8a9ea6d19 100644 --- a/src/include/utils/datum.h +++ b/src/include/utils/datum.h @@ -8,7 +8,7 @@ * of the Datum. (We do it this way because in most situations the caller * can look up the info just once and use it for many per-datum operations.) * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/datum.h diff --git a/src/include/utils/dsa.h b/src/include/utils/dsa.h new file mode 100644 index 0000000000..bb634e77cd --- /dev/null +++ b/src/include/utils/dsa.h @@ -0,0 +1,114 @@ +/*------------------------------------------------------------------------- + * + * dsa.h + * Dynamic shared memory areas. + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/utils/dsa.h + * + *------------------------------------------------------------------------- + */ +#ifndef DSA_H +#define DSA_H + +#include "postgres.h" + +#include "port/atomics.h" +#include "storage/dsm.h" + +/* The opaque type used for an area. */ +struct dsa_area; +typedef struct dsa_area dsa_area; + +/* + * If this system only uses a 32-bit value for Size, then use the 32-bit + * implementation of DSA. This limits the amount of DSA that can be created + * to something significantly less than the entire 4GB address space because + * the DSA pointer must encode both a segment identifier and an offset, but + * that shouldn't be a significant limitation in practice. + * + * If this system doesn't support atomic operations on 64-bit values, then + * we fall back to 32-bit dsa_pointer for lack of other options. + * + * For testing purposes, USE_SMALL_DSA_POINTER can be defined to force the use + * of 32-bit dsa_pointer even on systems capable of supporting a 64-bit + * dsa_pointer. + */ +#if SIZEOF_SIZE_T == 4 || !defined(PG_HAVE_ATOMIC_U64_SUPPORT) || \ + defined(USE_SMALL_DSA_POINTER) +#define SIZEOF_DSA_POINTER 4 +#else +#define SIZEOF_DSA_POINTER 8 +#endif + +/* + * The type of 'relative pointers' to memory allocated by a dynamic shared + * area. dsa_pointer values can be shared with other processes, but must be + * converted to backend-local pointers before they can be dereferenced. See + * dsa_get_address. Also, an atomic version and appropriately sized atomic + * operations. + */ +#if SIZEOF_DSA_POINTER == 4 +typedef uint32 dsa_pointer; +typedef pg_atomic_uint32 dsa_pointer_atomic; +#define dsa_pointer_atomic_init pg_atomic_init_u32 +#define dsa_pointer_atomic_read pg_atomic_read_u32 +#define dsa_pointer_atomic_write pg_atomic_write_u32 +#define dsa_pointer_atomic_fetch_add pg_atomic_fetch_add_u32 +#define dsa_pointer_atomic_compare_exchange pg_atomic_compare_exchange_u32 +#define DSA_POINTER_FORMAT "%08x" +#else +typedef uint64 dsa_pointer; +typedef pg_atomic_uint64 dsa_pointer_atomic; +#define dsa_pointer_atomic_init pg_atomic_init_u64 +#define dsa_pointer_atomic_read pg_atomic_read_u64 +#define dsa_pointer_atomic_write pg_atomic_write_u64 +#define dsa_pointer_atomic_fetch_add pg_atomic_fetch_add_u64 +#define dsa_pointer_atomic_compare_exchange pg_atomic_compare_exchange_u64 +#define DSA_POINTER_FORMAT "%016" INT64_MODIFIER "x" +#endif + +/* A sentinel value for dsa_pointer used to indicate failure to allocate. */ +#define InvalidDsaPointer ((dsa_pointer) 0) + +/* Check if a dsa_pointer value is valid. */ +#define DsaPointerIsValid(x) ((x) != InvalidDsaPointer) + +/* + * The type used for dsa_area handles. dsa_handle values can be shared with + * other processes, so that they can attach to them. This provides a way to + * share allocated storage with other processes. + * + * The handle for a dsa_area is currently implemented as the dsm_handle + * for the first DSM segment backing this dynamic storage area, but client + * code shouldn't assume that is true. + */ +typedef dsm_handle dsa_handle; + +extern void dsa_startup(void); + +extern dsa_area *dsa_create(int tranche_id); +extern dsa_area *dsa_create_in_place(void *place, Size size, + int tranche_id, dsm_segment *segment); +extern dsa_area *dsa_attach(dsa_handle handle); +extern dsa_area *dsa_attach_in_place(void *place, dsm_segment *segment); +extern void dsa_release_in_place(void *place); +extern void dsa_on_dsm_detach_release_in_place(dsm_segment *, Datum); +extern void dsa_on_shmem_exit_release_in_place(int, Datum); +extern void dsa_pin_mapping(dsa_area *area); +extern void dsa_detach(dsa_area *area); +extern void dsa_pin(dsa_area *area); +extern void dsa_unpin(dsa_area *area); +extern void dsa_set_size_limit(dsa_area *area, Size limit); +extern Size dsa_minimum_size(void); +extern dsa_handle dsa_get_handle(dsa_area *area); +extern dsa_pointer dsa_allocate(dsa_area *area, Size size); +extern void dsa_free(dsa_area *area, dsa_pointer dp); +extern void *dsa_get_address(dsa_area *area, dsa_pointer dp); +extern void dsa_trim(dsa_area *area); +extern void dsa_dump(dsa_area *area); + +#endif /* DSA_H */ diff --git a/src/include/utils/dynahash.h b/src/include/utils/dynahash.h index a0352eb7a7..eee5cce928 100644 --- a/src/include/utils/dynahash.h +++ b/src/include/utils/dynahash.h @@ -4,7 +4,7 @@ * POSTGRES dynahash.h file definitions * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/dynahash.h diff --git a/src/include/utils/dynamic_loader.h b/src/include/utils/dynamic_loader.h index 89c24b789a..987f21a362 100644 --- a/src/include/utils/dynamic_loader.h +++ b/src/include/utils/dynamic_loader.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/dynamic_loader.h diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h index f4ff03ec8a..9b469b9bfc 100644 --- a/src/include/utils/elog.h +++ b/src/include/utils/elog.h @@ -4,7 +4,7 @@ * POSTGRES error reporting/logging definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/elog.h @@ -206,12 +206,13 @@ extern int getinternalerrposition(void); #else /* !HAVE__BUILTIN_CONSTANT_P */ #define elog(elevel, ...) \ do { \ - int elevel_; \ elog_start(__FILE__, __LINE__, PG_FUNCNAME_MACRO); \ - elevel_ = (elevel); \ - elog_finish(elevel_, __VA_ARGS__); \ - if (elevel_ >= ERROR) \ - pg_unreachable(); \ + { \ + const int elevel_ = (elevel); \ + elog_finish(elevel_, __VA_ARGS__); \ + if (elevel_ >= ERROR) \ + pg_unreachable(); \ + } \ } while(0) #endif /* HAVE__BUILTIN_CONSTANT_P */ #else /* !HAVE__VA_ARGS */ diff --git a/src/include/utils/evtcache.h b/src/include/utils/evtcache.h index 7c8da746fd..f6ea163df3 100644 --- a/src/include/utils/evtcache.h +++ b/src/include/utils/evtcache.h @@ -3,7 +3,7 @@ * evtcache.c * Special-purpose cache for event trigger data. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/utils/expandeddatum.h b/src/include/utils/expandeddatum.h index 47989a8cf2..f853a13e6e 100644 --- a/src/include/utils/expandeddatum.h +++ b/src/include/utils/expandeddatum.h @@ -34,7 +34,7 @@ * value if they fail partway through. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/expandeddatum.h diff --git a/src/include/utils/fmgrtab.h b/src/include/utils/fmgrtab.h index 81e844c392..414cd03952 100644 --- a/src/include/utils/fmgrtab.h +++ b/src/include/utils/fmgrtab.h @@ -3,7 +3,7 @@ * fmgrtab.h * The function manager's table of internal functions. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/fmgrtab.h diff --git a/src/include/utils/formatting.h b/src/include/utils/formatting.h index 1f40f97d8e..8eaf2c3052 100644 --- a/src/include/utils/formatting.h +++ b/src/include/utils/formatting.h @@ -4,7 +4,7 @@ * src/include/utils/formatting.h * * - * Portions Copyright (c) 1999-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1999-2017, PostgreSQL Global Development Group * * The PostgreSQL routines for a DateTime/int/float/numeric formatting, * inspire with Oracle TO_CHAR() / TO_DATE() / TO_NUMBER() routines. @@ -28,16 +28,4 @@ extern char *asc_tolower(const char *buff, size_t nbytes); extern char *asc_toupper(const char *buff, size_t nbytes); extern char *asc_initcap(const char *buff, size_t nbytes); -extern Datum timestamp_to_char(PG_FUNCTION_ARGS); -extern Datum timestamptz_to_char(PG_FUNCTION_ARGS); -extern Datum interval_to_char(PG_FUNCTION_ARGS); -extern Datum to_timestamp(PG_FUNCTION_ARGS); -extern Datum to_date(PG_FUNCTION_ARGS); -extern Datum numeric_to_number(PG_FUNCTION_ARGS); -extern Datum numeric_to_char(PG_FUNCTION_ARGS); -extern Datum int4_to_char(PG_FUNCTION_ARGS); -extern Datum int8_to_char(PG_FUNCTION_ARGS); -extern Datum float4_to_char(PG_FUNCTION_ARGS); -extern Datum float8_to_char(PG_FUNCTION_ARGS); - #endif diff --git a/src/include/utils/freepage.h b/src/include/utils/freepage.h new file mode 100644 index 0000000000..78caa5369b --- /dev/null +++ b/src/include/utils/freepage.h @@ -0,0 +1,99 @@ +/*------------------------------------------------------------------------- + * + * freepage.h + * Management of page-organized free memory. + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/freepage.h + * + *------------------------------------------------------------------------- + */ + +#ifndef FREEPAGE_H +#define FREEPAGE_H + +#include "storage/lwlock.h" +#include "utils/relptr.h" + +/* Forward declarations. */ +typedef struct FreePageSpanLeader FreePageSpanLeader; +typedef struct FreePageBtree FreePageBtree; +typedef struct FreePageManager FreePageManager; + +/* + * PostgreSQL normally uses 8kB pages for most things, but many common + * architecture/operating system pairings use a 4kB page size for memory + * allocation, so we do that here also. + */ +#define FPM_PAGE_SIZE 4096 + +/* + * Each freelist except for the last contains only spans of one particular + * size. Everything larger goes on the last one. In some sense this seems + * like a waste since most allocations are in a few common sizes, but it + * means that small allocations can simply pop the head of the relevant list + * without needing to worry about whether the object we find there is of + * precisely the correct size (because we know it must be). + */ +#define FPM_NUM_FREELISTS 129 + +/* Define relative pointer types. */ +relptr_declare(FreePageBtree, RelptrFreePageBtree); +relptr_declare(FreePageManager, RelptrFreePageManager); +relptr_declare(FreePageSpanLeader, RelptrFreePageSpanLeader); + +/* Everything we need in order to manage free pages (see freepage.c) */ +struct FreePageManager +{ + RelptrFreePageManager self; + RelptrFreePageBtree btree_root; + RelptrFreePageSpanLeader btree_recycle; + unsigned btree_depth; + unsigned btree_recycle_count; + Size singleton_first_page; + Size singleton_npages; + Size contiguous_pages; + bool contiguous_pages_dirty; + RelptrFreePageSpanLeader freelist[FPM_NUM_FREELISTS]; +#ifdef FPM_EXTRA_ASSERTS + /* For debugging only, pages put minus pages gotten. */ + Size free_pages; +#endif +}; + +/* Macros to convert between page numbers (expressed as Size) and pointers. */ +#define fpm_page_to_pointer(base, page) \ + (AssertVariableIsOfTypeMacro(page, Size), \ + (base) + FPM_PAGE_SIZE * (page)) +#define fpm_pointer_to_page(base, ptr) \ + (((Size) (((char *) (ptr)) - (base))) / FPM_PAGE_SIZE) + +/* Macro to convert an allocation size to a number of pages. */ +#define fpm_size_to_pages(sz) \ + (((sz) + FPM_PAGE_SIZE - 1) / FPM_PAGE_SIZE) + +/* Macros to check alignment of absolute and relative pointers. */ +#define fpm_pointer_is_page_aligned(base, ptr) \ + (((Size) (((char *) (ptr)) - (base))) % FPM_PAGE_SIZE == 0) +#define fpm_relptr_is_page_aligned(base, relptr) \ + ((relptr).relptr_off % FPM_PAGE_SIZE == 0) + +/* Macro to find base address of the segment containing a FreePageManager. */ +#define fpm_segment_base(fpm) \ + (((char *) fpm) - fpm->self.relptr_off) + +/* Macro to access a FreePageManager's largest consecutive run of pages. */ +#define fpm_largest(fpm) \ + (fpm->contiguous_pages) + +/* Functions to manipulate the free page map. */ +extern void FreePageManagerInitialize(FreePageManager *fpm, char *base); +extern bool FreePageManagerGet(FreePageManager *fpm, Size npages, + Size *first_page); +extern void FreePageManagerPut(FreePageManager *fpm, Size first_page, + Size npages); +extern char *FreePageManagerDump(FreePageManager *fpm); + +#endif /* FREEPAGE_H */ diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h index fe9bc60782..9b530dbe3d 100644 --- a/src/include/utils/geo_decls.h +++ b/src/include/utils/geo_decls.h @@ -3,7 +3,7 @@ * geo_decls.h - Declarations for various 2D constructs. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/geo_decls.h @@ -175,270 +175,12 @@ typedef struct /* - * in geo_ops.h + * in geo_ops.c */ -/* public point routines */ -extern Datum point_in(PG_FUNCTION_ARGS); -extern Datum point_out(PG_FUNCTION_ARGS); -extern Datum point_recv(PG_FUNCTION_ARGS); -extern Datum point_send(PG_FUNCTION_ARGS); -extern Datum construct_point(PG_FUNCTION_ARGS); -extern Datum point_left(PG_FUNCTION_ARGS); -extern Datum point_right(PG_FUNCTION_ARGS); -extern Datum point_above(PG_FUNCTION_ARGS); -extern Datum point_below(PG_FUNCTION_ARGS); -extern Datum point_vert(PG_FUNCTION_ARGS); -extern Datum point_horiz(PG_FUNCTION_ARGS); -extern Datum point_eq(PG_FUNCTION_ARGS); -extern Datum point_ne(PG_FUNCTION_ARGS); -extern Datum point_distance(PG_FUNCTION_ARGS); -extern Datum point_slope(PG_FUNCTION_ARGS); -extern Datum point_add(PG_FUNCTION_ARGS); -extern Datum point_sub(PG_FUNCTION_ARGS); -extern Datum point_mul(PG_FUNCTION_ARGS); -extern Datum point_div(PG_FUNCTION_ARGS); - -/* private routines */ +/* private point routines */ extern double point_dt(Point *pt1, Point *pt2); extern double point_sl(Point *pt1, Point *pt2); extern double pg_hypot(double x, double y); -/* public lseg routines */ -extern Datum lseg_in(PG_FUNCTION_ARGS); -extern Datum lseg_out(PG_FUNCTION_ARGS); -extern Datum lseg_recv(PG_FUNCTION_ARGS); -extern Datum lseg_send(PG_FUNCTION_ARGS); -extern Datum lseg_intersect(PG_FUNCTION_ARGS); -extern Datum lseg_parallel(PG_FUNCTION_ARGS); -extern Datum lseg_perp(PG_FUNCTION_ARGS); -extern Datum lseg_vertical(PG_FUNCTION_ARGS); -extern Datum lseg_horizontal(PG_FUNCTION_ARGS); -extern Datum lseg_eq(PG_FUNCTION_ARGS); -extern Datum lseg_ne(PG_FUNCTION_ARGS); -extern Datum lseg_lt(PG_FUNCTION_ARGS); -extern Datum lseg_le(PG_FUNCTION_ARGS); -extern Datum lseg_gt(PG_FUNCTION_ARGS); -extern Datum lseg_ge(PG_FUNCTION_ARGS); -extern Datum lseg_construct(PG_FUNCTION_ARGS); -extern Datum lseg_length(PG_FUNCTION_ARGS); -extern Datum lseg_distance(PG_FUNCTION_ARGS); -extern Datum lseg_center(PG_FUNCTION_ARGS); -extern Datum lseg_interpt(PG_FUNCTION_ARGS); -extern Datum dist_pl(PG_FUNCTION_ARGS); -extern Datum dist_ps(PG_FUNCTION_ARGS); -extern Datum dist_ppath(PG_FUNCTION_ARGS); -extern Datum dist_pb(PG_FUNCTION_ARGS); -extern Datum dist_sl(PG_FUNCTION_ARGS); -extern Datum dist_sb(PG_FUNCTION_ARGS); -extern Datum dist_lb(PG_FUNCTION_ARGS); -extern Datum close_lseg(PG_FUNCTION_ARGS); -extern Datum close_pl(PG_FUNCTION_ARGS); -extern Datum close_ps(PG_FUNCTION_ARGS); -extern Datum close_pb(PG_FUNCTION_ARGS); -extern Datum close_sl(PG_FUNCTION_ARGS); -extern Datum close_sb(PG_FUNCTION_ARGS); -extern Datum close_ls(PG_FUNCTION_ARGS); -extern Datum close_lb(PG_FUNCTION_ARGS); -extern Datum on_pl(PG_FUNCTION_ARGS); -extern Datum on_ps(PG_FUNCTION_ARGS); -extern Datum on_pb(PG_FUNCTION_ARGS); -extern Datum on_ppath(PG_FUNCTION_ARGS); -extern Datum on_sl(PG_FUNCTION_ARGS); -extern Datum on_sb(PG_FUNCTION_ARGS); -extern Datum inter_sl(PG_FUNCTION_ARGS); -extern Datum inter_sb(PG_FUNCTION_ARGS); -extern Datum inter_lb(PG_FUNCTION_ARGS); - -/* public line routines */ -extern Datum line_in(PG_FUNCTION_ARGS); -extern Datum line_out(PG_FUNCTION_ARGS); -extern Datum line_recv(PG_FUNCTION_ARGS); -extern Datum line_send(PG_FUNCTION_ARGS); -extern Datum line_interpt(PG_FUNCTION_ARGS); -extern Datum line_distance(PG_FUNCTION_ARGS); -extern Datum line_construct_pp(PG_FUNCTION_ARGS); -extern Datum line_intersect(PG_FUNCTION_ARGS); -extern Datum line_parallel(PG_FUNCTION_ARGS); -extern Datum line_perp(PG_FUNCTION_ARGS); -extern Datum line_vertical(PG_FUNCTION_ARGS); -extern Datum line_horizontal(PG_FUNCTION_ARGS); -extern Datum line_eq(PG_FUNCTION_ARGS); - -/* public box routines */ -extern Datum box_in(PG_FUNCTION_ARGS); -extern Datum box_out(PG_FUNCTION_ARGS); -extern Datum box_recv(PG_FUNCTION_ARGS); -extern Datum box_send(PG_FUNCTION_ARGS); -extern Datum box_same(PG_FUNCTION_ARGS); -extern Datum box_overlap(PG_FUNCTION_ARGS); -extern Datum box_left(PG_FUNCTION_ARGS); -extern Datum box_overleft(PG_FUNCTION_ARGS); -extern Datum box_right(PG_FUNCTION_ARGS); -extern Datum box_overright(PG_FUNCTION_ARGS); -extern Datum box_below(PG_FUNCTION_ARGS); -extern Datum box_overbelow(PG_FUNCTION_ARGS); -extern Datum box_above(PG_FUNCTION_ARGS); -extern Datum box_overabove(PG_FUNCTION_ARGS); -extern Datum box_contained(PG_FUNCTION_ARGS); -extern Datum box_contain(PG_FUNCTION_ARGS); -extern Datum box_contain_pt(PG_FUNCTION_ARGS); -extern Datum box_below_eq(PG_FUNCTION_ARGS); -extern Datum box_above_eq(PG_FUNCTION_ARGS); -extern Datum box_lt(PG_FUNCTION_ARGS); -extern Datum box_gt(PG_FUNCTION_ARGS); -extern Datum box_eq(PG_FUNCTION_ARGS); -extern Datum box_le(PG_FUNCTION_ARGS); -extern Datum box_ge(PG_FUNCTION_ARGS); -extern Datum box_area(PG_FUNCTION_ARGS); -extern Datum box_width(PG_FUNCTION_ARGS); -extern Datum box_height(PG_FUNCTION_ARGS); -extern Datum box_distance(PG_FUNCTION_ARGS); -extern Datum box_center(PG_FUNCTION_ARGS); -extern Datum box_intersect(PG_FUNCTION_ARGS); -extern Datum box_diagonal(PG_FUNCTION_ARGS); -extern Datum points_box(PG_FUNCTION_ARGS); -extern Datum box_add(PG_FUNCTION_ARGS); -extern Datum box_sub(PG_FUNCTION_ARGS); -extern Datum box_mul(PG_FUNCTION_ARGS); -extern Datum box_div(PG_FUNCTION_ARGS); -extern Datum point_box(PG_FUNCTION_ARGS); -extern Datum boxes_bound_box(PG_FUNCTION_ARGS); - -/* public path routines */ -extern Datum path_area(PG_FUNCTION_ARGS); -extern Datum path_in(PG_FUNCTION_ARGS); -extern Datum path_out(PG_FUNCTION_ARGS); -extern Datum path_recv(PG_FUNCTION_ARGS); -extern Datum path_send(PG_FUNCTION_ARGS); -extern Datum path_n_lt(PG_FUNCTION_ARGS); -extern Datum path_n_gt(PG_FUNCTION_ARGS); -extern Datum path_n_eq(PG_FUNCTION_ARGS); -extern Datum path_n_le(PG_FUNCTION_ARGS); -extern Datum path_n_ge(PG_FUNCTION_ARGS); -extern Datum path_inter(PG_FUNCTION_ARGS); -extern Datum path_distance(PG_FUNCTION_ARGS); -extern Datum path_length(PG_FUNCTION_ARGS); - -extern Datum path_isclosed(PG_FUNCTION_ARGS); -extern Datum path_isopen(PG_FUNCTION_ARGS); -extern Datum path_npoints(PG_FUNCTION_ARGS); - -extern Datum path_close(PG_FUNCTION_ARGS); -extern Datum path_open(PG_FUNCTION_ARGS); -extern Datum path_add(PG_FUNCTION_ARGS); -extern Datum path_add_pt(PG_FUNCTION_ARGS); -extern Datum path_sub_pt(PG_FUNCTION_ARGS); -extern Datum path_mul_pt(PG_FUNCTION_ARGS); -extern Datum path_div_pt(PG_FUNCTION_ARGS); - -extern Datum path_center(PG_FUNCTION_ARGS); -extern Datum path_poly(PG_FUNCTION_ARGS); - -/* public polygon routines */ -extern Datum poly_in(PG_FUNCTION_ARGS); -extern Datum poly_out(PG_FUNCTION_ARGS); -extern Datum poly_recv(PG_FUNCTION_ARGS); -extern Datum poly_send(PG_FUNCTION_ARGS); -extern Datum poly_left(PG_FUNCTION_ARGS); -extern Datum poly_overleft(PG_FUNCTION_ARGS); -extern Datum poly_right(PG_FUNCTION_ARGS); -extern Datum poly_overright(PG_FUNCTION_ARGS); -extern Datum poly_below(PG_FUNCTION_ARGS); -extern Datum poly_overbelow(PG_FUNCTION_ARGS); -extern Datum poly_above(PG_FUNCTION_ARGS); -extern Datum poly_overabove(PG_FUNCTION_ARGS); -extern Datum poly_same(PG_FUNCTION_ARGS); -extern Datum poly_overlap(PG_FUNCTION_ARGS); -extern Datum poly_contain(PG_FUNCTION_ARGS); -extern Datum poly_contained(PG_FUNCTION_ARGS); -extern Datum poly_contain_pt(PG_FUNCTION_ARGS); -extern Datum pt_contained_poly(PG_FUNCTION_ARGS); -extern Datum poly_distance(PG_FUNCTION_ARGS); -extern Datum poly_npoints(PG_FUNCTION_ARGS); -extern Datum poly_center(PG_FUNCTION_ARGS); -extern Datum poly_box(PG_FUNCTION_ARGS); -extern Datum poly_path(PG_FUNCTION_ARGS); -extern Datum box_poly(PG_FUNCTION_ARGS); - -/* public circle routines */ -extern Datum circle_in(PG_FUNCTION_ARGS); -extern Datum circle_out(PG_FUNCTION_ARGS); -extern Datum circle_recv(PG_FUNCTION_ARGS); -extern Datum circle_send(PG_FUNCTION_ARGS); -extern Datum circle_same(PG_FUNCTION_ARGS); -extern Datum circle_overlap(PG_FUNCTION_ARGS); -extern Datum circle_overleft(PG_FUNCTION_ARGS); -extern Datum circle_left(PG_FUNCTION_ARGS); -extern Datum circle_right(PG_FUNCTION_ARGS); -extern Datum circle_overright(PG_FUNCTION_ARGS); -extern Datum circle_contained(PG_FUNCTION_ARGS); -extern Datum circle_contain(PG_FUNCTION_ARGS); -extern Datum circle_below(PG_FUNCTION_ARGS); -extern Datum circle_above(PG_FUNCTION_ARGS); -extern Datum circle_overbelow(PG_FUNCTION_ARGS); -extern Datum circle_overabove(PG_FUNCTION_ARGS); -extern Datum circle_eq(PG_FUNCTION_ARGS); -extern Datum circle_ne(PG_FUNCTION_ARGS); -extern Datum circle_lt(PG_FUNCTION_ARGS); -extern Datum circle_gt(PG_FUNCTION_ARGS); -extern Datum circle_le(PG_FUNCTION_ARGS); -extern Datum circle_ge(PG_FUNCTION_ARGS); -extern Datum circle_contain_pt(PG_FUNCTION_ARGS); -extern Datum pt_contained_circle(PG_FUNCTION_ARGS); -extern Datum circle_add_pt(PG_FUNCTION_ARGS); -extern Datum circle_sub_pt(PG_FUNCTION_ARGS); -extern Datum circle_mul_pt(PG_FUNCTION_ARGS); -extern Datum circle_div_pt(PG_FUNCTION_ARGS); -extern Datum circle_diameter(PG_FUNCTION_ARGS); -extern Datum circle_radius(PG_FUNCTION_ARGS); -extern Datum circle_distance(PG_FUNCTION_ARGS); -extern Datum dist_pc(PG_FUNCTION_ARGS); -extern Datum dist_cpoint(PG_FUNCTION_ARGS); -extern Datum dist_cpoly(PG_FUNCTION_ARGS); -extern Datum dist_ppoly(PG_FUNCTION_ARGS); -extern Datum dist_polyp(PG_FUNCTION_ARGS); -extern Datum circle_center(PG_FUNCTION_ARGS); -extern Datum cr_circle(PG_FUNCTION_ARGS); -extern Datum box_circle(PG_FUNCTION_ARGS); -extern Datum circle_box(PG_FUNCTION_ARGS); -extern Datum poly_circle(PG_FUNCTION_ARGS); -extern Datum circle_poly(PG_FUNCTION_ARGS); -extern Datum circle_area(PG_FUNCTION_ARGS); - -/* support routines for the GiST access method (access/gist/gistproc.c) */ -extern Datum gist_box_compress(PG_FUNCTION_ARGS); -extern Datum gist_box_decompress(PG_FUNCTION_ARGS); -extern Datum gist_box_union(PG_FUNCTION_ARGS); -extern Datum gist_box_picksplit(PG_FUNCTION_ARGS); -extern Datum gist_box_consistent(PG_FUNCTION_ARGS); -extern Datum gist_box_penalty(PG_FUNCTION_ARGS); -extern Datum gist_box_same(PG_FUNCTION_ARGS); -extern Datum gist_box_fetch(PG_FUNCTION_ARGS); -extern Datum gist_poly_compress(PG_FUNCTION_ARGS); -extern Datum gist_poly_consistent(PG_FUNCTION_ARGS); -extern Datum gist_poly_distance(PG_FUNCTION_ARGS); -extern Datum gist_circle_compress(PG_FUNCTION_ARGS); -extern Datum gist_circle_consistent(PG_FUNCTION_ARGS); -extern Datum gist_circle_distance(PG_FUNCTION_ARGS); -extern Datum gist_point_compress(PG_FUNCTION_ARGS); -extern Datum gist_point_consistent(PG_FUNCTION_ARGS); -extern Datum gist_point_distance(PG_FUNCTION_ARGS); -extern Datum gist_point_fetch(PG_FUNCTION_ARGS); - -/* utils/adt/geo_spgist.c */ -Datum spg_box_quad_config(PG_FUNCTION_ARGS); -Datum spg_box_quad_choose(PG_FUNCTION_ARGS); -Datum spg_box_quad_picksplit(PG_FUNCTION_ARGS); -Datum spg_box_quad_inner_consistent(PG_FUNCTION_ARGS); -Datum spg_box_quad_leaf_consistent(PG_FUNCTION_ARGS); - -/* geo_selfuncs.c */ -extern Datum areasel(PG_FUNCTION_ARGS); -extern Datum areajoinsel(PG_FUNCTION_ARGS); -extern Datum positionsel(PG_FUNCTION_ARGS); -extern Datum positionjoinsel(PG_FUNCTION_ARGS); -extern Datum contsel(PG_FUNCTION_ARGS); -extern Datum contjoinsel(PG_FUNCTION_ARGS); - #endif /* GEO_DECLS_H */ diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index e1de1a5d06..7dd378026a 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -4,7 +4,7 @@ * External declarations pertaining to backend/utils/misc/guc.c and * backend/utils/misc/guc-file.l * - * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Copyright (c) 2000-2017, PostgreSQL Global Development Group * Written by Peter Eisentraut . * * src/include/utils/guc.h @@ -219,12 +219,12 @@ typedef enum #define GUC_UNIT_BLOCKS 0x2000 /* value is in blocks */ #define GUC_UNIT_XBLOCKS 0x3000 /* value is in xlog blocks */ #define GUC_UNIT_XSEGS 0x4000 /* value is in xlog segments */ -#define GUC_UNIT_MEMORY 0xF000 /* mask for KB, BLOCKS, XBLOCKS */ +#define GUC_UNIT_MEMORY 0xF000 /* mask for size-related units */ #define GUC_UNIT_MS 0x10000 /* value is in milliseconds */ #define GUC_UNIT_S 0x20000 /* value is in seconds */ #define GUC_UNIT_MIN 0x30000 /* value is in minutes */ -#define GUC_UNIT_TIME 0xF0000 /* mask for MS, S, MIN */ +#define GUC_UNIT_TIME 0xF0000 /* mask for time-related units */ #define GUC_UNIT (GUC_UNIT_MEMORY | GUC_UNIT_TIME) @@ -244,7 +244,6 @@ extern bool log_btree_build_stats; extern PGDLLIMPORT bool check_function_bodies; extern bool default_with_oids; -extern bool SQL_inheritance; extern int log_min_error_statement; extern int log_min_messages; diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h index b695f61f63..2da9115429 100644 --- a/src/include/utils/guc_tables.h +++ b/src/include/utils/guc_tables.h @@ -5,7 +5,7 @@ * * See src/backend/utils/misc/README for design notes. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * src/include/utils/guc_tables.h * diff --git a/src/include/utils/help_config.h b/src/include/utils/help_config.h index 565fdd96fc..3f433d10d7 100644 --- a/src/include/utils/help_config.h +++ b/src/include/utils/help_config.h @@ -3,7 +3,7 @@ * help_config.h * Interface to the --help-config option of main.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * src/include/utils/help_config.h * diff --git a/src/include/utils/hsearch.h b/src/include/utils/hsearch.h index 007ba2c69b..7964087161 100644 --- a/src/include/utils/hsearch.h +++ b/src/include/utils/hsearch.h @@ -4,7 +4,7 @@ * exported definitions for utils/hash/dynahash.c; see notes therein * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/hsearch.h diff --git a/src/include/utils/index_selfuncs.h b/src/include/utils/index_selfuncs.h index a03e12f518..d3172420f9 100644 --- a/src/include/utils/index_selfuncs.h +++ b/src/include/utils/index_selfuncs.h @@ -9,7 +9,7 @@ * If you make it depend on anything besides access/amapi.h, that's likely * a mistake. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/index_selfuncs.h diff --git a/src/include/utils/inet.h b/src/include/utils/inet.h index 2fe3ca8c3c..577b34dbf9 100644 --- a/src/include/utils/inet.h +++ b/src/include/utils/inet.h @@ -4,7 +4,7 @@ * Declarations for operations on INET datatypes. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/inet.h @@ -28,10 +28,12 @@ typedef struct } inet_struct; /* + * We use these values for the "family" field. + * * Referencing all of the non-AF_INET types to AF_INET lets us work on * machines which may not have the appropriate address family (like * inet6 addresses when AF_INET6 isn't present) but doesn't cause a - * dump/reload requirement. Existing databases used AF_INET for the family + * dump/reload requirement. Pre-7.4 databases used AF_INET for the family * type on disk. */ #define PGSQL_AF_INET (AF_INET + 0) @@ -117,25 +119,8 @@ typedef struct macaddr /* * Support functions in network.c */ +extern inet *cidr_set_masklen_internal(const inet *src, int bits); extern int bitncmp(const unsigned char *l, const unsigned char *r, int n); extern int bitncommon(const unsigned char *l, const unsigned char *r, int n); -/* - * GiST support functions in network_gist.c - */ -extern Datum inet_gist_fetch(PG_FUNCTION_ARGS); -extern Datum inet_gist_consistent(PG_FUNCTION_ARGS); -extern Datum inet_gist_union(PG_FUNCTION_ARGS); -extern Datum inet_gist_compress(PG_FUNCTION_ARGS); -extern Datum inet_gist_decompress(PG_FUNCTION_ARGS); -extern Datum inet_gist_penalty(PG_FUNCTION_ARGS); -extern Datum inet_gist_picksplit(PG_FUNCTION_ARGS); -extern Datum inet_gist_same(PG_FUNCTION_ARGS); - -/* - * Estimation functions in network_selfuncs.c - */ -extern Datum networksel(PG_FUNCTION_ARGS); -extern Datum networkjoinsel(PG_FUNCTION_ARGS); - #endif /* INET_H */ diff --git a/src/include/utils/int8.h b/src/include/utils/int8.h index 2bafa2dc2d..c58ee048cf 100644 --- a/src/include/utils/int8.h +++ b/src/include/utils/int8.h @@ -4,7 +4,7 @@ * Declarations for operations on 64-bit integers. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/int8.h @@ -20,110 +20,6 @@ #ifndef INT8_H #define INT8_H -#include "fmgr.h" - - extern bool scanint8(const char *str, bool errorOK, int64 *result); -extern Datum int8in(PG_FUNCTION_ARGS); -extern Datum int8out(PG_FUNCTION_ARGS); -extern Datum int8recv(PG_FUNCTION_ARGS); -extern Datum int8send(PG_FUNCTION_ARGS); - -extern Datum int8eq(PG_FUNCTION_ARGS); -extern Datum int8ne(PG_FUNCTION_ARGS); -extern Datum int8lt(PG_FUNCTION_ARGS); -extern Datum int8gt(PG_FUNCTION_ARGS); -extern Datum int8le(PG_FUNCTION_ARGS); -extern Datum int8ge(PG_FUNCTION_ARGS); - -extern Datum int84eq(PG_FUNCTION_ARGS); -extern Datum int84ne(PG_FUNCTION_ARGS); -extern Datum int84lt(PG_FUNCTION_ARGS); -extern Datum int84gt(PG_FUNCTION_ARGS); -extern Datum int84le(PG_FUNCTION_ARGS); -extern Datum int84ge(PG_FUNCTION_ARGS); - -extern Datum int48eq(PG_FUNCTION_ARGS); -extern Datum int48ne(PG_FUNCTION_ARGS); -extern Datum int48lt(PG_FUNCTION_ARGS); -extern Datum int48gt(PG_FUNCTION_ARGS); -extern Datum int48le(PG_FUNCTION_ARGS); -extern Datum int48ge(PG_FUNCTION_ARGS); - -extern Datum int82eq(PG_FUNCTION_ARGS); -extern Datum int82ne(PG_FUNCTION_ARGS); -extern Datum int82lt(PG_FUNCTION_ARGS); -extern Datum int82gt(PG_FUNCTION_ARGS); -extern Datum int82le(PG_FUNCTION_ARGS); -extern Datum int82ge(PG_FUNCTION_ARGS); - -extern Datum int28eq(PG_FUNCTION_ARGS); -extern Datum int28ne(PG_FUNCTION_ARGS); -extern Datum int28lt(PG_FUNCTION_ARGS); -extern Datum int28gt(PG_FUNCTION_ARGS); -extern Datum int28le(PG_FUNCTION_ARGS); -extern Datum int28ge(PG_FUNCTION_ARGS); - -extern Datum int8um(PG_FUNCTION_ARGS); -extern Datum int8up(PG_FUNCTION_ARGS); -extern Datum int8pl(PG_FUNCTION_ARGS); -extern Datum int8mi(PG_FUNCTION_ARGS); -extern Datum int8mul(PG_FUNCTION_ARGS); -extern Datum int8div(PG_FUNCTION_ARGS); -extern Datum int8abs(PG_FUNCTION_ARGS); -extern Datum int8mod(PG_FUNCTION_ARGS); -extern Datum int8inc(PG_FUNCTION_ARGS); -extern Datum int8dec(PG_FUNCTION_ARGS); -extern Datum int8inc_any(PG_FUNCTION_ARGS); -extern Datum int8inc_float8_float8(PG_FUNCTION_ARGS); -extern Datum int8dec_any(PG_FUNCTION_ARGS); -extern Datum int8larger(PG_FUNCTION_ARGS); -extern Datum int8smaller(PG_FUNCTION_ARGS); - -extern Datum int8and(PG_FUNCTION_ARGS); -extern Datum int8or(PG_FUNCTION_ARGS); -extern Datum int8xor(PG_FUNCTION_ARGS); -extern Datum int8not(PG_FUNCTION_ARGS); -extern Datum int8shl(PG_FUNCTION_ARGS); -extern Datum int8shr(PG_FUNCTION_ARGS); - -extern Datum int84pl(PG_FUNCTION_ARGS); -extern Datum int84mi(PG_FUNCTION_ARGS); -extern Datum int84mul(PG_FUNCTION_ARGS); -extern Datum int84div(PG_FUNCTION_ARGS); - -extern Datum int48pl(PG_FUNCTION_ARGS); -extern Datum int48mi(PG_FUNCTION_ARGS); -extern Datum int48mul(PG_FUNCTION_ARGS); -extern Datum int48div(PG_FUNCTION_ARGS); - -extern Datum int82pl(PG_FUNCTION_ARGS); -extern Datum int82mi(PG_FUNCTION_ARGS); -extern Datum int82mul(PG_FUNCTION_ARGS); -extern Datum int82div(PG_FUNCTION_ARGS); - -extern Datum int28pl(PG_FUNCTION_ARGS); -extern Datum int28mi(PG_FUNCTION_ARGS); -extern Datum int28mul(PG_FUNCTION_ARGS); -extern Datum int28div(PG_FUNCTION_ARGS); - -extern Datum int48(PG_FUNCTION_ARGS); -extern Datum int84(PG_FUNCTION_ARGS); - -extern Datum int28(PG_FUNCTION_ARGS); -extern Datum int82(PG_FUNCTION_ARGS); - -extern Datum i8tod(PG_FUNCTION_ARGS); -extern Datum dtoi8(PG_FUNCTION_ARGS); - -extern Datum i8tof(PG_FUNCTION_ARGS); -extern Datum ftoi8(PG_FUNCTION_ARGS); - -extern Datum i8tooid(PG_FUNCTION_ARGS); -extern Datum oidtoi8(PG_FUNCTION_ARGS); - -extern Datum generate_series_int8(PG_FUNCTION_ARGS); -extern Datum generate_series_step_int8(PG_FUNCTION_ARGS); - #endif /* INT8_H */ diff --git a/src/include/utils/inval.h b/src/include/utils/inval.h index 122fef29c8..afbe354b4d 100644 --- a/src/include/utils/inval.h +++ b/src/include/utils/inval.h @@ -4,7 +4,7 @@ * POSTGRES cache invalidation dispatcher definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/inval.h @@ -43,6 +43,8 @@ extern void CacheInvalidateCatalog(Oid catalogId); extern void CacheInvalidateRelcache(Relation relation); +extern void CacheInvalidateRelcacheAll(void); + extern void CacheInvalidateRelcacheByTuple(HeapTuple classTuple); extern void CacheInvalidateRelcacheByRelid(Oid relid); diff --git a/src/include/utils/json.h b/src/include/utils/json.h index 9dd9dff2f6..0a749b90c8 100644 --- a/src/include/utils/json.h +++ b/src/include/utils/json.h @@ -3,7 +3,7 @@ * json.h * Declarations for JSON data type support. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/json.h @@ -14,73 +14,9 @@ #ifndef JSON_H #define JSON_H -#include "fmgr.h" #include "lib/stringinfo.h" /* functions in json.c */ -extern Datum json_in(PG_FUNCTION_ARGS); -extern Datum json_out(PG_FUNCTION_ARGS); -extern Datum json_recv(PG_FUNCTION_ARGS); -extern Datum json_send(PG_FUNCTION_ARGS); -extern Datum array_to_json(PG_FUNCTION_ARGS); -extern Datum array_to_json_pretty(PG_FUNCTION_ARGS); -extern Datum row_to_json(PG_FUNCTION_ARGS); -extern Datum row_to_json_pretty(PG_FUNCTION_ARGS); -extern Datum to_json(PG_FUNCTION_ARGS); - -extern Datum json_agg_transfn(PG_FUNCTION_ARGS); -extern Datum json_agg_finalfn(PG_FUNCTION_ARGS); - -extern Datum json_object_agg_finalfn(PG_FUNCTION_ARGS); -extern Datum json_object_agg_transfn(PG_FUNCTION_ARGS); - -extern Datum json_build_object(PG_FUNCTION_ARGS); -extern Datum json_build_object_noargs(PG_FUNCTION_ARGS); -extern Datum json_build_array(PG_FUNCTION_ARGS); -extern Datum json_build_array_noargs(PG_FUNCTION_ARGS); - -extern Datum json_object(PG_FUNCTION_ARGS); -extern Datum json_object_two_arg(PG_FUNCTION_ARGS); - extern void escape_json(StringInfo buf, const char *str); -extern Datum json_typeof(PG_FUNCTION_ARGS); - -/* functions in jsonfuncs.c */ -extern Datum json_object_field(PG_FUNCTION_ARGS); -extern Datum json_object_field_text(PG_FUNCTION_ARGS); -extern Datum json_array_element(PG_FUNCTION_ARGS); -extern Datum json_array_element_text(PG_FUNCTION_ARGS); -extern Datum json_extract_path(PG_FUNCTION_ARGS); -extern Datum json_extract_path_text(PG_FUNCTION_ARGS); -extern Datum json_object_keys(PG_FUNCTION_ARGS); -extern Datum json_array_length(PG_FUNCTION_ARGS); -extern Datum json_each(PG_FUNCTION_ARGS); -extern Datum json_each_text(PG_FUNCTION_ARGS); -extern Datum json_array_elements(PG_FUNCTION_ARGS); -extern Datum json_array_elements_text(PG_FUNCTION_ARGS); -extern Datum json_populate_record(PG_FUNCTION_ARGS); -extern Datum json_populate_recordset(PG_FUNCTION_ARGS); -extern Datum json_to_record(PG_FUNCTION_ARGS); -extern Datum json_to_recordset(PG_FUNCTION_ARGS); -extern Datum json_strip_nulls(PG_FUNCTION_ARGS); - -extern Datum jsonb_object_field(PG_FUNCTION_ARGS); -extern Datum jsonb_object_field_text(PG_FUNCTION_ARGS); -extern Datum jsonb_array_element(PG_FUNCTION_ARGS); -extern Datum jsonb_array_element_text(PG_FUNCTION_ARGS); -extern Datum jsonb_extract_path(PG_FUNCTION_ARGS); -extern Datum jsonb_extract_path_text(PG_FUNCTION_ARGS); -extern Datum jsonb_object_keys(PG_FUNCTION_ARGS); -extern Datum jsonb_array_length(PG_FUNCTION_ARGS); -extern Datum jsonb_each(PG_FUNCTION_ARGS); -extern Datum jsonb_each_text(PG_FUNCTION_ARGS); -extern Datum jsonb_array_elements_text(PG_FUNCTION_ARGS); -extern Datum jsonb_array_elements(PG_FUNCTION_ARGS); -extern Datum jsonb_populate_record(PG_FUNCTION_ARGS); -extern Datum jsonb_populate_recordset(PG_FUNCTION_ARGS); -extern Datum jsonb_to_record(PG_FUNCTION_ARGS); -extern Datum jsonb_to_recordset(PG_FUNCTION_ARGS); -extern Datum jsonb_strip_nulls(PG_FUNCTION_ARGS); - #endif /* JSON_H */ diff --git a/src/include/utils/jsonapi.h b/src/include/utils/jsonapi.h index b041fa4ed3..6962f1a6be 100644 --- a/src/include/utils/jsonapi.h +++ b/src/include/utils/jsonapi.h @@ -3,7 +3,7 @@ * jsonapi.h * Declarations for JSON API support. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/jsonapi.h diff --git a/src/include/utils/jsonb.h b/src/include/utils/jsonb.h index fa52afcb5c..e402b9e3a7 100644 --- a/src/include/utils/jsonb.h +++ b/src/include/utils/jsonb.h @@ -3,7 +3,7 @@ * jsonb.h * Declarations for jsonb data type support. * - * Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Copyright (c) 1996-2017, PostgreSQL Global Development Group * * src/include/utils/jsonb.h * @@ -219,6 +219,20 @@ typedef struct #define JB_ROOT_IS_ARRAY(jbp_) ( *(uint32*) VARDATA(jbp_) & JB_FARRAY) +enum jbvType +{ + /* Scalar types */ + jbvNull = 0x0, + jbvString, + jbvNumeric, + jbvBool, + /* Composite types */ + jbvArray = 0x10, + jbvObject, + /* Binary (i.e. struct Jsonb) jbvArray/jbvObject */ + jbvBinary +}; + /* * JsonbValue: In-memory representation of Jsonb. This is a convenient * deserialized representation, that can easily support using the "val" @@ -227,19 +241,7 @@ typedef struct */ struct JsonbValue { - enum - { - /* Scalar types */ - jbvNull = 0x0, - jbvString, - jbvNumeric, - jbvBool, - /* Composite types */ - jbvArray = 0x10, - jbvObject, - /* Binary (i.e. struct Jsonb) jbvArray/jbvObject */ - jbvBinary - } type; /* Influences sort order */ + enum jbvType type; /* Influences sort order */ union { @@ -343,73 +345,6 @@ typedef struct JsonbIterator struct JsonbIterator *parent; } JsonbIterator; -/* I/O routines */ -extern Datum jsonb_in(PG_FUNCTION_ARGS); -extern Datum jsonb_out(PG_FUNCTION_ARGS); -extern Datum jsonb_recv(PG_FUNCTION_ARGS); -extern Datum jsonb_send(PG_FUNCTION_ARGS); -extern Datum jsonb_typeof(PG_FUNCTION_ARGS); - -/* generator routines */ -extern Datum to_jsonb(PG_FUNCTION_ARGS); - -extern Datum jsonb_build_object(PG_FUNCTION_ARGS); -extern Datum jsonb_build_object_noargs(PG_FUNCTION_ARGS); -extern Datum jsonb_build_array(PG_FUNCTION_ARGS); -extern Datum jsonb_build_array_noargs(PG_FUNCTION_ARGS); -extern Datum jsonb_object(PG_FUNCTION_ARGS); -extern Datum jsonb_object_two_arg(PG_FUNCTION_ARGS); - -/* jsonb_agg, json_object_agg functions */ -extern Datum jsonb_agg_transfn(PG_FUNCTION_ARGS); -extern Datum jsonb_agg_finalfn(PG_FUNCTION_ARGS); -extern Datum jsonb_object_agg_transfn(PG_FUNCTION_ARGS); -extern Datum jsonb_object_agg_finalfn(PG_FUNCTION_ARGS); - -/* Indexing-related ops */ -extern Datum jsonb_exists(PG_FUNCTION_ARGS); -extern Datum jsonb_exists_any(PG_FUNCTION_ARGS); -extern Datum jsonb_exists_all(PG_FUNCTION_ARGS); -extern Datum jsonb_contains(PG_FUNCTION_ARGS); -extern Datum jsonb_contained(PG_FUNCTION_ARGS); -extern Datum jsonb_ne(PG_FUNCTION_ARGS); -extern Datum jsonb_lt(PG_FUNCTION_ARGS); -extern Datum jsonb_gt(PG_FUNCTION_ARGS); -extern Datum jsonb_le(PG_FUNCTION_ARGS); -extern Datum jsonb_ge(PG_FUNCTION_ARGS); -extern Datum jsonb_eq(PG_FUNCTION_ARGS); -extern Datum jsonb_cmp(PG_FUNCTION_ARGS); -extern Datum jsonb_hash(PG_FUNCTION_ARGS); - -/* GIN support functions for jsonb_ops */ -extern Datum gin_compare_jsonb(PG_FUNCTION_ARGS); -extern Datum gin_extract_jsonb(PG_FUNCTION_ARGS); -extern Datum gin_extract_jsonb_query(PG_FUNCTION_ARGS); -extern Datum gin_consistent_jsonb(PG_FUNCTION_ARGS); -extern Datum gin_triconsistent_jsonb(PG_FUNCTION_ARGS); - -/* GIN support functions for jsonb_path_ops */ -extern Datum gin_extract_jsonb_path(PG_FUNCTION_ARGS); -extern Datum gin_extract_jsonb_query_path(PG_FUNCTION_ARGS); -extern Datum gin_consistent_jsonb_path(PG_FUNCTION_ARGS); -extern Datum gin_triconsistent_jsonb_path(PG_FUNCTION_ARGS); - -/* pretty printer, returns text */ -extern Datum jsonb_pretty(PG_FUNCTION_ARGS); - -/* concatenation */ -extern Datum jsonb_concat(PG_FUNCTION_ARGS); - -/* deletion */ -extern Datum jsonb_delete(PG_FUNCTION_ARGS); -extern Datum jsonb_delete_idx(PG_FUNCTION_ARGS); -extern Datum jsonb_delete_path(PG_FUNCTION_ARGS); - -/* replacement */ -extern Datum jsonb_set(PG_FUNCTION_ARGS); - -/* insert after or before (for arrays) */ -extern Datum jsonb_insert(PG_FUNCTION_ARGS); /* Support functions */ extern uint32 getJsonbOffset(const JsonbContainer *jc, int index); diff --git a/src/include/utils/logtape.h b/src/include/utils/logtape.h index fa1e992082..e802c4b213 100644 --- a/src/include/utils/logtape.h +++ b/src/include/utils/logtape.h @@ -5,7 +5,7 @@ * * See logtape.c for explanations. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/logtape.h @@ -31,11 +31,13 @@ extern size_t LogicalTapeRead(LogicalTapeSet *lts, int tapenum, void *ptr, size_t size); extern void LogicalTapeWrite(LogicalTapeSet *lts, int tapenum, void *ptr, size_t size); -extern void LogicalTapeRewind(LogicalTapeSet *lts, int tapenum, bool forWrite); +extern void LogicalTapeRewindForRead(LogicalTapeSet *lts, int tapenum, + size_t buffer_size); +extern void LogicalTapeRewindForWrite(LogicalTapeSet *lts, int tapenum); extern void LogicalTapeFreeze(LogicalTapeSet *lts, int tapenum); -extern bool LogicalTapeBackspace(LogicalTapeSet *lts, int tapenum, +extern size_t LogicalTapeBackspace(LogicalTapeSet *lts, int tapenum, size_t size); -extern bool LogicalTapeSeek(LogicalTapeSet *lts, int tapenum, +extern void LogicalTapeSeek(LogicalTapeSet *lts, int tapenum, long blocknum, int offset); extern void LogicalTapeTell(LogicalTapeSet *lts, int tapenum, long *blocknum, int *offset); diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h index dcb89807e9..7a49eb78ab 100644 --- a/src/include/utils/lsyscache.h +++ b/src/include/utils/lsyscache.h @@ -3,7 +3,7 @@ * lsyscache.h * Convenience routines for common queries in the system catalog cache. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/lsyscache.h @@ -17,6 +17,8 @@ #include "access/htup.h" #include "nodes/pg_list.h" +#define RULEOID (USERMAPPINGUSERSERVER + 1) /* Fake cache id for rule oid*/ + /* Result list element for get_op_btree_interpretation */ typedef struct OpBtreeInterpretation { @@ -159,6 +161,16 @@ extern void free_attstatsslot(Oid atttype, extern char *get_namespace_name(Oid nspid); extern char *get_namespace_name_or_temp(Oid nspid); extern Oid get_range_subtype(Oid rangeOid); +extern char *get_typ_name(Oid typid); +extern Oid get_typ_namespace(Oid typid); +extern Oid get_typname_typid(const char *typname, Oid typnamespace); +extern Oid get_funcid(const char *funcname, oidvector *argtypes, Oid funcnsp); +extern Oid get_collation_namespace(Oid colloid); +extern int32 get_collation_encoding(Oid colloid); +extern Oid get_collid(const char *collname, int32 collencoding, Oid collnsp); +extern Oid get_opnamespace(Oid opno); +extern Oid get_operid(const char *oprname, Oid oprleft, Oid oprright, Oid oprnsp); +extern char *get_rule_name(Oid ruleoid, Oid *ev_class); #define type_is_array(typid) (get_element_type(typid) != InvalidOid) /* type_is_array_domain accepts both plain arrays and domains over arrays */ diff --git a/src/include/utils/memdebug.h b/src/include/utils/memdebug.h index 96b5baf5a0..90eb926ddf 100644 --- a/src/include/utils/memdebug.h +++ b/src/include/utils/memdebug.h @@ -7,7 +7,7 @@ * empty definitions for Valgrind client request macros we use. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/memdebug.h diff --git a/src/include/utils/memutils.h b/src/include/utils/memutils.h index ae07705b6b..1d1035e374 100644 --- a/src/include/utils/memutils.h +++ b/src/include/utils/memutils.h @@ -7,7 +7,7 @@ * of the API of the memory management subsystem. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/memutils.h @@ -142,14 +142,26 @@ extern MemoryContext AllocSetContextCreate(MemoryContext parent, #define ALLOCSET_DEFAULT_MINSIZE 0 #define ALLOCSET_DEFAULT_INITSIZE (8 * 1024) #define ALLOCSET_DEFAULT_MAXSIZE (8 * 1024 * 1024) +#define ALLOCSET_DEFAULT_SIZES \ + ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE /* - * Recommended alloc parameters for "small" contexts that are not expected + * Recommended alloc parameters for "small" contexts that are never expected * to contain much data (for example, a context to contain a query plan). */ #define ALLOCSET_SMALL_MINSIZE 0 #define ALLOCSET_SMALL_INITSIZE (1 * 1024) #define ALLOCSET_SMALL_MAXSIZE (8 * 1024) +#define ALLOCSET_SMALL_SIZES \ + ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE + +/* + * Recommended alloc parameters for contexts that should start out small, + * but might sometimes grow big. + */ +#define ALLOCSET_START_SMALL_SIZES \ + ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE + /* * Threshold above which a request in an AllocSet context is certain to be diff --git a/src/include/utils/nabstime.h b/src/include/utils/nabstime.h index d06f6f82e7..4b0706a316 100644 --- a/src/include/utils/nabstime.h +++ b/src/include/utils/nabstime.h @@ -4,7 +4,7 @@ * Definitions for the "new" abstime code. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/nabstime.h @@ -96,69 +96,6 @@ typedef TimeIntervalData *TimeInterval; ((bool) (((RelativeTime) (time)) != INVALID_RELTIME)) -/* - * nabstime.c prototypes - */ -extern Datum abstimein(PG_FUNCTION_ARGS); -extern Datum abstimeout(PG_FUNCTION_ARGS); -extern Datum abstimerecv(PG_FUNCTION_ARGS); -extern Datum abstimesend(PG_FUNCTION_ARGS); - -extern Datum abstimeeq(PG_FUNCTION_ARGS); -extern Datum abstimene(PG_FUNCTION_ARGS); -extern Datum abstimelt(PG_FUNCTION_ARGS); -extern Datum abstimegt(PG_FUNCTION_ARGS); -extern Datum abstimele(PG_FUNCTION_ARGS); -extern Datum abstimege(PG_FUNCTION_ARGS); -extern Datum abstime_finite(PG_FUNCTION_ARGS); - -extern Datum timestamp_abstime(PG_FUNCTION_ARGS); -extern Datum abstime_timestamp(PG_FUNCTION_ARGS); -extern Datum timestamptz_abstime(PG_FUNCTION_ARGS); -extern Datum abstime_timestamptz(PG_FUNCTION_ARGS); - -extern Datum reltimein(PG_FUNCTION_ARGS); -extern Datum reltimeout(PG_FUNCTION_ARGS); -extern Datum reltimerecv(PG_FUNCTION_ARGS); -extern Datum reltimesend(PG_FUNCTION_ARGS); -extern Datum tintervalin(PG_FUNCTION_ARGS); -extern Datum tintervalout(PG_FUNCTION_ARGS); -extern Datum tintervalrecv(PG_FUNCTION_ARGS); -extern Datum tintervalsend(PG_FUNCTION_ARGS); -extern Datum interval_reltime(PG_FUNCTION_ARGS); -extern Datum reltime_interval(PG_FUNCTION_ARGS); -extern Datum mktinterval(PG_FUNCTION_ARGS); -extern Datum timepl(PG_FUNCTION_ARGS); -extern Datum timemi(PG_FUNCTION_ARGS); - -extern Datum intinterval(PG_FUNCTION_ARGS); -extern Datum tintervalrel(PG_FUNCTION_ARGS); -extern Datum timenow(PG_FUNCTION_ARGS); -extern Datum reltimeeq(PG_FUNCTION_ARGS); -extern Datum reltimene(PG_FUNCTION_ARGS); -extern Datum reltimelt(PG_FUNCTION_ARGS); -extern Datum reltimegt(PG_FUNCTION_ARGS); -extern Datum reltimele(PG_FUNCTION_ARGS); -extern Datum reltimege(PG_FUNCTION_ARGS); -extern Datum tintervalsame(PG_FUNCTION_ARGS); -extern Datum tintervaleq(PG_FUNCTION_ARGS); -extern Datum tintervalne(PG_FUNCTION_ARGS); -extern Datum tintervallt(PG_FUNCTION_ARGS); -extern Datum tintervalgt(PG_FUNCTION_ARGS); -extern Datum tintervalle(PG_FUNCTION_ARGS); -extern Datum tintervalge(PG_FUNCTION_ARGS); -extern Datum tintervalleneq(PG_FUNCTION_ARGS); -extern Datum tintervallenne(PG_FUNCTION_ARGS); -extern Datum tintervallenlt(PG_FUNCTION_ARGS); -extern Datum tintervallengt(PG_FUNCTION_ARGS); -extern Datum tintervallenle(PG_FUNCTION_ARGS); -extern Datum tintervallenge(PG_FUNCTION_ARGS); -extern Datum tintervalct(PG_FUNCTION_ARGS); -extern Datum tintervalov(PG_FUNCTION_ARGS); -extern Datum tintervalstart(PG_FUNCTION_ARGS); -extern Datum tintervalend(PG_FUNCTION_ARGS); -extern Datum timeofday(PG_FUNCTION_ARGS); - /* non-fmgr-callable support routines */ extern AbsoluteTime GetCurrentAbsoluteTime(void); extern void abstime2tm(AbsoluteTime time, int *tzp, struct pg_tm * tm, char **tzn); diff --git a/src/include/utils/numeric.h b/src/include/utils/numeric.h index 6c1808ec71..0ab57d7025 100644 --- a/src/include/utils/numeric.h +++ b/src/include/utils/numeric.h @@ -5,7 +5,7 @@ * * Original coding 1998, Jan Wieck. Heavily revised 2003, Tom Lane. * - * Copyright (c) 1998-2016, PostgreSQL Global Development Group + * Copyright (c) 1998-2017, PostgreSQL Global Development Group * * src/include/utils/numeric.h * diff --git a/src/include/utils/palloc.h b/src/include/utils/palloc.h index 9be59d1055..b72fe4aee8 100644 --- a/src/include/utils/palloc.h +++ b/src/include/utils/palloc.h @@ -18,7 +18,7 @@ * everything that should be freed. See utils/mmgr/README for more info. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/palloc.h diff --git a/src/include/utils/pg_crc.h b/src/include/utils/pg_crc.h index a9401f9bd7..2fe083850a 100644 --- a/src/include/utils/pg_crc.h +++ b/src/include/utils/pg_crc.h @@ -26,7 +26,7 @@ * * The CRC-32C variant is in port/pg_crc32c.h. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/pg_crc.h diff --git a/src/include/utils/pg_locale.h b/src/include/utils/pg_locale.h index 0a4b9f7bd2..be91f9b88c 100644 --- a/src/include/utils/pg_locale.h +++ b/src/include/utils/pg_locale.h @@ -4,7 +4,7 @@ * * src/include/utils/pg_locale.h * - * Copyright (c) 2002-2016, PostgreSQL Global Development Group + * Copyright (c) 2002-2017, PostgreSQL Global Development Group * *----------------------------------------------------------------------- */ diff --git a/src/include/utils/pg_lsn.h b/src/include/utils/pg_lsn.h index 772fd6adf5..6f038e9e14 100644 --- a/src/include/utils/pg_lsn.h +++ b/src/include/utils/pg_lsn.h @@ -5,7 +5,7 @@ * PostgreSQL. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/pg_lsn.h @@ -18,22 +18,6 @@ #include "fmgr.h" #include "access/xlogdefs.h" -extern Datum pg_lsn_in(PG_FUNCTION_ARGS); -extern Datum pg_lsn_out(PG_FUNCTION_ARGS); -extern Datum pg_lsn_recv(PG_FUNCTION_ARGS); -extern Datum pg_lsn_send(PG_FUNCTION_ARGS); - -extern Datum pg_lsn_eq(PG_FUNCTION_ARGS); -extern Datum pg_lsn_ne(PG_FUNCTION_ARGS); -extern Datum pg_lsn_lt(PG_FUNCTION_ARGS); -extern Datum pg_lsn_gt(PG_FUNCTION_ARGS); -extern Datum pg_lsn_le(PG_FUNCTION_ARGS); -extern Datum pg_lsn_ge(PG_FUNCTION_ARGS); -extern Datum pg_lsn_cmp(PG_FUNCTION_ARGS); -extern Datum pg_lsn_hash(PG_FUNCTION_ARGS); - -extern Datum pg_lsn_mi(PG_FUNCTION_ARGS); - #define DatumGetLSN(X) ((XLogRecPtr) DatumGetInt64(X)) #define LSNGetDatum(X) (Int64GetDatum((int64) (X))) diff --git a/src/include/utils/pg_rusage.h b/src/include/utils/pg_rusage.h index 7c264eb6b1..48a74e90ba 100644 --- a/src/include/utils/pg_rusage.h +++ b/src/include/utils/pg_rusage.h @@ -4,7 +4,7 @@ * header file for resource usage measurement support routines * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/pg_rusage.h diff --git a/src/include/utils/plancache.h b/src/include/utils/plancache.h index 938c4afc8b..6ffb403702 100644 --- a/src/include/utils/plancache.h +++ b/src/include/utils/plancache.h @@ -5,7 +5,7 @@ * * See plancache.c for comments. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/plancache.h @@ -17,6 +17,10 @@ #include "access/tupdesc.h" #include "nodes/params.h" +#include "nodes/plannodes.h" + +/* Forward declaration, to avoid including parsenodes.h here */ +struct RawStmt; #define CACHEDPLANSOURCE_MAGIC 195726186 #define CACHEDPLAN_MAGIC 953717834 @@ -76,7 +80,7 @@ typedef struct CachedPlanSource { int magic; /* should equal CACHEDPLANSOURCE_MAGIC */ - Node *raw_parse_tree; /* output of raw_parser(), or NULL */ + struct RawStmt *raw_parse_tree; /* output of raw_parser(), or NULL */ const char *query_string; /* source text of query */ const char *commandTag; /* command tag (a constant!), or NULL */ Oid *param_types; /* array of parameter type OIDs, or NULL */ @@ -126,8 +130,7 @@ typedef struct CachedPlanSource typedef struct CachedPlan { int magic; /* should equal CACHEDPLAN_MAGIC */ - List *stmt_list; /* list of statement nodes (PlannedStmts and - * bare utility statements) */ + List *stmt_list; /* list of PlannedStmts */ bool is_oneshot; /* is it a "oneshot" plan? */ bool is_saved; /* is CachedPlan in a long-lived context? */ bool is_valid; /* is the stmt_list currently valid? */ @@ -144,10 +147,10 @@ typedef struct CachedPlan extern void InitPlanCache(void); extern void ResetPlanCache(void); -extern CachedPlanSource *CreateCachedPlan(Node *raw_parse_tree, +extern CachedPlanSource *CreateCachedPlan(struct RawStmt *raw_parse_tree, const char *query_string, const char *commandTag); -extern CachedPlanSource *CreateOneShotCachedPlan(Node *raw_parse_tree, +extern CachedPlanSource *CreateOneShotCachedPlan(struct RawStmt *raw_parse_tree, const char *query_string, const char *commandTag); extern void CompleteCachedPlan(CachedPlanSource *plansource, @@ -176,5 +179,6 @@ extern CachedPlan *GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams, bool useResOwner); extern void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner); +extern void SetRemoteSubplan(CachedPlanSource *plansource, PlannedStmt *rstmt); #endif /* PLANCACHE_H */ diff --git a/src/include/utils/portal.h b/src/include/utils/portal.h index c1d93a96bb..dc76acd0a4 100644 --- a/src/include/utils/portal.h +++ b/src/include/utils/portal.h @@ -36,7 +36,7 @@ * to look like NO SCROLL cursors. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/portal.h @@ -133,7 +133,7 @@ typedef struct PortalData /* The query or queries the portal will execute */ const char *sourceText; /* text of query (as of 8.4, never NULL) */ const char *commandTag; /* command tag for original query */ - List *stmts; /* PlannedStmts and/or utility statements */ + List *stmts; /* list of PlannedStmts */ CachedPlan *cplan; /* CachedPlan, if stmts are from one */ ParamListInfo portalParams; /* params to pass to query */ @@ -201,7 +201,6 @@ typedef struct PortalData */ #define PortalGetQueryDesc(portal) ((portal)->queryDesc) #define PortalGetHeapMemory(portal) ((portal)->heap) -#define PortalGetPrimaryStmt(portal) PortalListGetPrimaryStmt((portal)->stmts) /* Prototypes for functions in utils/mmgr/portalmem.c */ @@ -232,7 +231,7 @@ extern void PortalDefineQuery(Portal portal, const char *commandTag, List *stmts, CachedPlan *cplan); -extern Node *PortalListGetPrimaryStmt(List *stmts); +extern PlannedStmt *PortalGetPrimaryStmt(Portal portal); extern void PortalCreateHoldStore(Portal portal); extern void PortalHashTableDeleteAll(void); extern bool ThereAreNoReadyPortals(void); diff --git a/src/include/utils/rangetypes.h b/src/include/utils/rangetypes.h index a774ca0e80..abb2223ec5 100644 --- a/src/include/utils/rangetypes.h +++ b/src/include/utils/rangetypes.h @@ -4,7 +4,7 @@ * Declarations for Postgres range types. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/rangetypes.h @@ -92,45 +92,8 @@ typedef struct * prototypes for functions defined in rangetypes.c */ -/* I/O */ -extern Datum range_in(PG_FUNCTION_ARGS); -extern Datum range_out(PG_FUNCTION_ARGS); -extern Datum range_recv(PG_FUNCTION_ARGS); -extern Datum range_send(PG_FUNCTION_ARGS); - -/* constructors */ -extern Datum range_constructor2(PG_FUNCTION_ARGS); -extern Datum range_constructor3(PG_FUNCTION_ARGS); - -/* range -> subtype */ -extern Datum range_lower(PG_FUNCTION_ARGS); -extern Datum range_upper(PG_FUNCTION_ARGS); - -/* range -> bool */ -extern Datum range_empty(PG_FUNCTION_ARGS); -extern Datum range_lower_inc(PG_FUNCTION_ARGS); -extern Datum range_upper_inc(PG_FUNCTION_ARGS); -extern Datum range_lower_inf(PG_FUNCTION_ARGS); -extern Datum range_upper_inf(PG_FUNCTION_ARGS); - -/* range, element -> bool */ -extern Datum range_contains_elem(PG_FUNCTION_ARGS); -extern Datum elem_contained_by_range(PG_FUNCTION_ARGS); - extern bool range_contains_elem_internal(TypeCacheEntry *typcache, RangeType *r, Datum val); -/* range, range -> bool */ -extern Datum range_eq(PG_FUNCTION_ARGS); -extern Datum range_ne(PG_FUNCTION_ARGS); -extern Datum range_contains(PG_FUNCTION_ARGS); -extern Datum range_contained_by(PG_FUNCTION_ARGS); -extern Datum range_before(PG_FUNCTION_ARGS); -extern Datum range_after(PG_FUNCTION_ARGS); -extern Datum range_adjacent(PG_FUNCTION_ARGS); -extern Datum range_overlaps(PG_FUNCTION_ARGS); -extern Datum range_overleft(PG_FUNCTION_ARGS); -extern Datum range_overright(PG_FUNCTION_ARGS); - /* internal versions of the above */ extern bool range_eq_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2); @@ -153,38 +116,6 @@ extern bool range_overleft_internal(TypeCacheEntry *typcache, RangeType *r1, extern bool range_overright_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2); -/* range, range -> range */ -extern Datum range_minus(PG_FUNCTION_ARGS); -extern Datum range_union(PG_FUNCTION_ARGS); -extern Datum range_intersect(PG_FUNCTION_ARGS); - -/* BTree support */ -extern Datum range_cmp(PG_FUNCTION_ARGS); -extern Datum range_lt(PG_FUNCTION_ARGS); -extern Datum range_le(PG_FUNCTION_ARGS); -extern Datum range_ge(PG_FUNCTION_ARGS); -extern Datum range_gt(PG_FUNCTION_ARGS); - -/* Hash support */ -extern Datum hash_range(PG_FUNCTION_ARGS); - -/* ANALYZE support */ -extern Datum range_typanalyze(PG_FUNCTION_ARGS); -extern Datum rangesel(PG_FUNCTION_ARGS); - -/* Canonical functions */ -extern Datum int4range_canonical(PG_FUNCTION_ARGS); -extern Datum int8range_canonical(PG_FUNCTION_ARGS); -extern Datum daterange_canonical(PG_FUNCTION_ARGS); - -/* Subtype Difference functions */ -extern Datum int4range_subdiff(PG_FUNCTION_ARGS); -extern Datum int8range_subdiff(PG_FUNCTION_ARGS); -extern Datum numrange_subdiff(PG_FUNCTION_ARGS); -extern Datum daterange_subdiff(PG_FUNCTION_ARGS); -extern Datum tsrange_subdiff(PG_FUNCTION_ARGS); -extern Datum tstzrange_subdiff(PG_FUNCTION_ARGS); - /* assorted support functions */ extern TypeCacheEntry *range_get_typcache(FunctionCallInfo fcinfo, Oid rngtypid); @@ -205,15 +136,4 @@ extern bool bounds_adjacent(TypeCacheEntry *typcache, RangeBound bound1, RangeBound bound2); extern RangeType *make_empty_range(TypeCacheEntry *typcache); -/* GiST support (in rangetypes_gist.c) */ -extern Datum range_gist_consistent(PG_FUNCTION_ARGS); -extern Datum range_gist_compress(PG_FUNCTION_ARGS); -extern Datum range_gist_decompress(PG_FUNCTION_ARGS); -extern Datum range_gist_fetch(PG_FUNCTION_ARGS); -extern Datum range_gist_union(PG_FUNCTION_ARGS); -extern Datum range_merge(PG_FUNCTION_ARGS); -extern Datum range_gist_penalty(PG_FUNCTION_ARGS); -extern Datum range_gist_picksplit(PG_FUNCTION_ARGS); -extern Datum range_gist_same(PG_FUNCTION_ARGS); - #endif /* RANGETYPES_H */ diff --git a/src/include/utils/regproc.h b/src/include/utils/regproc.h new file mode 100644 index 0000000000..70f47922cc --- /dev/null +++ b/src/include/utils/regproc.h @@ -0,0 +1,28 @@ +/*------------------------------------------------------------------------- + * + * regproc.h + * Functions for the built-in types regproc, regclass, regtype, etc. + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/regproc.h + * + *------------------------------------------------------------------------- + */ +#ifndef REGPROC_H +#define REGPROC_H + +#include "nodes/pg_list.h" + +extern List *stringToQualifiedNameList(const char *string); +extern char *format_procedure(Oid procedure_oid); +extern char *format_procedure_qualified(Oid procedure_oid); +extern void format_procedure_parts(Oid operator_oid, List **objnames, + List **objargs); +extern char *format_operator(Oid operator_oid); +extern char *format_operator_qualified(Oid operator_oid); +extern void format_operator_parts(Oid operator_oid, List **objnames, + List **objargs); + +#endif diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index ed14442cfe..a1750accc2 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -4,7 +4,7 @@ * POSTGRES relation descriptor (a/k/a relcache entry) definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/rel.h @@ -18,6 +18,7 @@ #include "access/xlog.h" #include "catalog/pg_class.h" #include "catalog/pg_index.h" +#include "catalog/pg_publication.h" #include "fmgr.h" #include "nodes/bitmapset.h" #include "rewrite/prs2lock.h" @@ -45,6 +46,35 @@ typedef struct LockInfoData typedef LockInfoData *LockInfo; +/* + * Information about the partition key of a relation + */ +typedef struct PartitionKeyData +{ + char strategy; /* partitioning strategy */ + int16 partnatts; /* number of columns in the partition key */ + AttrNumber *partattrs; /* attribute numbers of columns in the + * partition key */ + List *partexprs; /* list of expressions in the partitioning + * key, or NIL */ + + Oid *partopfamily; /* OIDs of operator families */ + Oid *partopcintype; /* OIDs of opclass declared input data types */ + FmgrInfo *partsupfunc; /* lookup info for support funcs */ + + /* Partitioning collation per attribute */ + Oid *partcollation; + + /* Type information per attribute */ + Oid *parttypid; + int32 *parttypmod; + int16 *parttyplen; + bool *parttypbyval; + char *parttypalign; + Oid *parttypcoll; +} PartitionKeyData; + +typedef struct PartitionKeyData *PartitionKey; /* * Here are the contents of a relation cache entry. @@ -94,16 +124,26 @@ typedef struct RelationData List *rd_fkeylist; /* list of ForeignKeyCacheInfo (see below) */ bool rd_fkeyvalid; /* true if list has been computed */ + MemoryContext rd_partkeycxt; /* private memory cxt for the below */ + struct PartitionKeyData *rd_partkey; /* partition key, or NULL */ + MemoryContext rd_pdcxt; /* private context for partdesc */ + struct PartitionDescData *rd_partdesc; /* partitions, or NULL */ + List *rd_partcheck; /* partition CHECK quals */ + /* data managed by RelationGetIndexList: */ List *rd_indexlist; /* list of OIDs of indexes on relation */ Oid rd_oidindex; /* OID of unique index on OID, if any */ + Oid rd_pkindex; /* OID of primary key, if any */ Oid rd_replidindex; /* OID of replica identity index, if any */ /* data managed by RelationGetIndexAttrBitmap: */ Bitmapset *rd_indexattr; /* identifies columns used in indexes */ Bitmapset *rd_keyattr; /* cols that can be ref'd by foreign keys */ + Bitmapset *rd_pkattr; /* cols included in primary key */ Bitmapset *rd_idattr; /* included in replica identity index */ + PublicationActions *rd_pubactions; /* publication actions */ + /* * rd_options is set whenever rd_rel is loaded into the relcache entry. * Note that you can NOT look into rd_rel for this data. NULL means "use @@ -270,7 +310,9 @@ typedef struct StdRdOptions * from the pov of logical decoding. Note multiple eval of argument! */ #define RelationIsUsedAsCatalogTable(relation) \ - ((relation)->rd_options ? \ + ((relation)->rd_options && \ + ((relation)->rd_rel->relkind == RELKIND_RELATION || \ + (relation)->rd_rel->relkind == RELKIND_MATVIEW) ? \ ((StdRdOptions *) (relation)->rd_options)->user_catalog_table : false) /* @@ -532,9 +574,64 @@ typedef struct ViewOptions RelationNeedsWAL(relation) && \ !IsCatalogRelation(relation)) +/* + * RelationGetPartitionKey + * Returns the PartitionKey of a relation + */ +#define RelationGetPartitionKey(relation) ((relation)->rd_partkey) + +/* + * PartitionKey inquiry functions + */ +static inline int +get_partition_strategy(PartitionKey key) +{ + return key->strategy; +} + +static inline int +get_partition_natts(PartitionKey key) +{ + return key->partnatts; +} + +static inline List * +get_partition_exprs(PartitionKey key) +{ + return key->partexprs; +} + +/* + * PartitionKey inquiry functions - one column + */ +static inline int16 +get_partition_col_attnum(PartitionKey key, int col) +{ + return key->partattrs[col]; +} + +static inline Oid +get_partition_col_typid(PartitionKey key, int col) +{ + return key->parttypid[col]; +} + +static inline int32 +get_partition_col_typmod(PartitionKey key, int col) +{ + return key->parttypmod[col]; +} + +/* + * RelationGetPartitionDesc + * Returns partition descriptor for a relation. + */ +#define RelationGetPartitionDesc(relation) ((relation)->rd_partdesc) + /* routines in utils/cache/relcache.c */ extern void RelationIncrementReferenceCount(Relation rel); extern void RelationDecrementReferenceCount(Relation rel); extern bool RelationHasUnloggedIndex(Relation rel); +extern List *RelationGetRepsetList(Relation rel); #endif /* REL_H */ diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h index 6ea7dd2510..da36b6774f 100644 --- a/src/include/utils/relcache.h +++ b/src/include/utils/relcache.h @@ -4,7 +4,7 @@ * Relation descriptor cache definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/relcache.h @@ -40,6 +40,7 @@ extern void RelationClose(Relation relation); extern List *RelationGetFKeyList(Relation relation); extern List *RelationGetIndexList(Relation relation); extern Oid RelationGetOidIndex(Relation relation); +extern Oid RelationGetPrimaryKeyIndex(Relation relation); extern Oid RelationGetReplicaIndex(Relation relation); extern List *RelationGetIndexExpressions(Relation relation); extern List *RelationGetIndexPredicate(Relation relation); @@ -48,6 +49,7 @@ typedef enum IndexAttrBitmapKind { INDEX_ATTR_BITMAP_ALL, INDEX_ATTR_BITMAP_KEY, + INDEX_ATTR_BITMAP_PRIMARY_KEY, INDEX_ATTR_BITMAP_IDENTITY_KEY } IndexAttrBitmapKind; @@ -64,6 +66,10 @@ extern void RelationSetIndexList(Relation relation, extern void RelationInitIndexAccessInfo(Relation relation); +/* caller must include pg_publication.h */ +struct PublicationActions; +extern struct PublicationActions *GetRelationPublicationActions(Relation relation); + /* * Routines to support ereport() reports of relation-related errors */ diff --git a/src/include/utils/relfilenodemap.h b/src/include/utils/relfilenodemap.h index e3e14feea5..0827ff3db8 100644 --- a/src/include/utils/relfilenodemap.h +++ b/src/include/utils/relfilenodemap.h @@ -3,7 +3,7 @@ * relfilenodemap.h * relfilenode to oid mapping cache. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/relfilenodemap.h diff --git a/src/include/utils/relmapper.h b/src/include/utils/relmapper.h index 22c5118ded..8fb2879ff9 100644 --- a/src/include/utils/relmapper.h +++ b/src/include/utils/relmapper.h @@ -4,7 +4,7 @@ * Catalog-to-filenode mapping * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/relmapper.h diff --git a/src/include/utils/relptr.h b/src/include/utils/relptr.h new file mode 100644 index 0000000000..1e5e622150 --- /dev/null +++ b/src/include/utils/relptr.h @@ -0,0 +1,77 @@ +/*------------------------------------------------------------------------- + * + * relptr.h + * This file contains basic declarations for relative pointers. + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/relptr.h + * + *------------------------------------------------------------------------- + */ + +#ifndef RELPTR_H +#define RELPTR_H + +/* + * Relative pointers are intended to be used when storing an address that may + * be relative either to the base of the process's address space or some + * dynamic shared memory segment mapped therein. + * + * The idea here is that you declare a relative pointer as relptr(type) + * and then use relptr_access to dereference it and relptr_store to change + * it. The use of a union here is a hack, because what's stored in the + * relptr is always a Size, never an actual pointer. But including a pointer + * in the union allows us to use stupid macro tricks to provide some measure + * of type-safety. + */ +#define relptr(type) union { type *relptr_type; Size relptr_off; } + +/* + * pgindent gets confused by declarations that use "relptr(type)" directly, + * so preferred style is to write + * typedef struct ... SomeStruct; + * relptr_declare(SomeStruct, RelptrSomeStruct); + * and then declare pointer variables as "RelptrSomeStruct someptr". + */ +#define relptr_declare(type, relptrtype) \ + typedef relptr(type) relptrtype + +#ifdef HAVE__BUILTIN_TYPES_COMPATIBLE_P +#define relptr_access(base, rp) \ + (AssertVariableIsOfTypeMacro(base, char *), \ + (__typeof__((rp).relptr_type)) ((rp).relptr_off == 0 ? NULL : \ + (base + (rp).relptr_off))) +#else +/* + * If we don't have __builtin_types_compatible_p, assume we might not have + * __typeof__ either. + */ +#define relptr_access(base, rp) \ + (AssertVariableIsOfTypeMacro(base, char *), \ + (void *) ((rp).relptr_off == 0 ? NULL : (base + (rp).relptr_off))) +#endif + +#define relptr_is_null(rp) \ + ((rp).relptr_off == 0) + +#ifdef HAVE__BUILTIN_TYPES_COMPATIBLE_P +#define relptr_store(base, rp, val) \ + (AssertVariableIsOfTypeMacro(base, char *), \ + AssertVariableIsOfTypeMacro(val, __typeof__((rp).relptr_type)), \ + (rp).relptr_off = ((val) == NULL ? 0 : ((char *) (val)) - (base))) +#else +/* + * If we don't have __builtin_types_compatible_p, assume we might not have + * __typeof__ either. + */ +#define relptr_store(base, rp, val) \ + (AssertVariableIsOfTypeMacro(base, char *), \ + (rp).relptr_off = ((val) == NULL ? 0 : ((char *) (val)) - (base))) +#endif + +#define relptr_copy(rp1, rp2) \ + ((rp1).relptr_off = (rp2).relptr_off) + +#endif /* RELPTR_H */ diff --git a/src/include/utils/reltrigger.h b/src/include/utils/reltrigger.h index e87f2283ec..65d6ecb30a 100644 --- a/src/include/utils/reltrigger.h +++ b/src/include/utils/reltrigger.h @@ -4,7 +4,7 @@ * POSTGRES relation trigger definitions. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/reltrigger.h @@ -39,6 +39,8 @@ typedef struct Trigger int16 *tgattr; char **tgargs; char *tgqual; + char *tgoldtable; + char *tgnewtable; } Trigger; typedef struct TriggerDesc @@ -68,6 +70,11 @@ typedef struct TriggerDesc /* there are no row-level truncate triggers */ bool trig_truncate_before_statement; bool trig_truncate_after_statement; + /* Is there at least one trigger specifying each transition relation? */ + bool trig_insert_new_table; + bool trig_update_old_table; + bool trig_update_new_table; + bool trig_delete_old_table; } TriggerDesc; #endif /* RELTRIGGER_H */ diff --git a/src/include/utils/resowner.h b/src/include/utils/resowner.h index c5abac23a7..ff785e3a3e 100644 --- a/src/include/utils/resowner.h +++ b/src/include/utils/resowner.h @@ -9,7 +9,7 @@ * See utils/resowner/README for more info. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/resowner.h diff --git a/src/include/utils/resowner_private.h b/src/include/utils/resowner_private.h index fd320909bb..411d08ff0b 100644 --- a/src/include/utils/resowner_private.h +++ b/src/include/utils/resowner_private.h @@ -6,7 +6,7 @@ * See utils/resowner/README for more info. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/resowner_private.h diff --git a/src/include/utils/rls.h b/src/include/utils/rls.h index 29d17a4bf5..fa2c44e160 100644 --- a/src/include/utils/rls.h +++ b/src/include/utils/rls.h @@ -4,7 +4,7 @@ * Header file for Row Level Security (RLS) utility commands to be used * with the rowsecurity feature. * - * Copyright (c) 2007-2016, PostgreSQL Global Development Group + * Copyright (c) 2007-2017, PostgreSQL Global Development Group * * src/include/utils/rls.h * diff --git a/src/include/utils/ruleutils.h b/src/include/utils/ruleutils.h index cec24184b0..3e8aad97e2 100644 --- a/src/include/utils/ruleutils.h +++ b/src/include/utils/ruleutils.h @@ -3,7 +3,7 @@ * ruleutils.h * Declarations for ruleutils.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/ruleutils.h diff --git a/src/include/utils/sampling.h b/src/include/utils/sampling.h index 2b914ebc3e..7edfc4a44d 100644 --- a/src/include/utils/sampling.h +++ b/src/include/utils/sampling.h @@ -3,7 +3,7 @@ * sampling.h * definitions for sampling functions * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/sampling.h diff --git a/src/include/utils/selfuncs.h b/src/include/utils/selfuncs.h index 8e0d317468..9f9d2dcb2b 100644 --- a/src/include/utils/selfuncs.h +++ b/src/include/utils/selfuncs.h @@ -5,7 +5,7 @@ * infrastructure for selectivity and cost estimation. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/selfuncs.h @@ -180,32 +180,6 @@ extern Pattern_Prefix_Status pattern_fixed_prefix(Const *patt, extern Const *make_greater_string(const Const *str_const, FmgrInfo *ltproc, Oid collation); -extern Datum eqsel(PG_FUNCTION_ARGS); -extern Datum neqsel(PG_FUNCTION_ARGS); -extern Datum scalarltsel(PG_FUNCTION_ARGS); -extern Datum scalargtsel(PG_FUNCTION_ARGS); -extern Datum regexeqsel(PG_FUNCTION_ARGS); -extern Datum icregexeqsel(PG_FUNCTION_ARGS); -extern Datum likesel(PG_FUNCTION_ARGS); -extern Datum iclikesel(PG_FUNCTION_ARGS); -extern Datum regexnesel(PG_FUNCTION_ARGS); -extern Datum icregexnesel(PG_FUNCTION_ARGS); -extern Datum nlikesel(PG_FUNCTION_ARGS); -extern Datum icnlikesel(PG_FUNCTION_ARGS); - -extern Datum eqjoinsel(PG_FUNCTION_ARGS); -extern Datum neqjoinsel(PG_FUNCTION_ARGS); -extern Datum scalarltjoinsel(PG_FUNCTION_ARGS); -extern Datum scalargtjoinsel(PG_FUNCTION_ARGS); -extern Datum regexeqjoinsel(PG_FUNCTION_ARGS); -extern Datum icregexeqjoinsel(PG_FUNCTION_ARGS); -extern Datum likejoinsel(PG_FUNCTION_ARGS); -extern Datum iclikejoinsel(PG_FUNCTION_ARGS); -extern Datum regexnejoinsel(PG_FUNCTION_ARGS); -extern Datum icregexnejoinsel(PG_FUNCTION_ARGS); -extern Datum nlikejoinsel(PG_FUNCTION_ARGS); -extern Datum icnlikejoinsel(PG_FUNCTION_ARGS); - extern Selectivity boolvarsel(PlannerInfo *root, Node *arg, int varRelid); extern Selectivity booltestsel(PlannerInfo *root, BoolTestType booltesttype, Node *arg, int varRelid, @@ -245,7 +219,5 @@ extern Selectivity scalararraysel_containment(PlannerInfo *root, Node *leftop, Node *rightop, Oid elemtype, bool isEquality, bool useOr, int varRelid); -extern Datum arraycontsel(PG_FUNCTION_ARGS); -extern Datum arraycontjoinsel(PG_FUNCTION_ARGS); #endif /* SELFUNCS_H */ diff --git a/src/include/utils/snapmgr.h b/src/include/utils/snapmgr.h index 9e3827249e..2618cc4546 100644 --- a/src/include/utils/snapmgr.h +++ b/src/include/utils/snapmgr.h @@ -3,7 +3,7 @@ * snapmgr.h * POSTGRES snapshot manager * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/snapmgr.h @@ -69,6 +69,7 @@ extern Snapshot GetOldestSnapshot(void); extern Snapshot GetCatalogSnapshot(Oid relid); extern Snapshot GetNonHistoricCatalogSnapshot(Oid relid); extern void InvalidateCatalogSnapshot(void); +extern void InvalidateCatalogSnapshotConditionally(void); extern void PushActiveSnapshot(Snapshot snapshot); extern void PushCopiedSnapshot(Snapshot snapshot); @@ -86,7 +87,6 @@ extern void AtSubCommit_Snapshot(int level); extern void AtSubAbort_Snapshot(int level); extern void AtEOXact_Snapshot(bool isCommit); -extern Datum pg_export_snapshot(PG_FUNCTION_ARGS); extern void ImportSnapshot(const char *idstr); extern bool XactHasExportedSnapshots(void); extern void DeleteAllExportedSnapshotFiles(void); diff --git a/src/include/utils/snapshot.h b/src/include/utils/snapshot.h index 998e2e593d..ebd5d5a85c 100644 --- a/src/include/utils/snapshot.h +++ b/src/include/utils/snapshot.h @@ -3,7 +3,7 @@ * snapshot.h * POSTGRES snapshot definition * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/snapshot.h diff --git a/src/include/utils/sortsupport.h b/src/include/utils/sortsupport.h index 0ef76c8ccf..9ca8fe86ae 100644 --- a/src/include/utils/sortsupport.h +++ b/src/include/utils/sortsupport.h @@ -42,7 +42,7 @@ * function for such cases, but probably not any other acceleration method. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/sortsupport.h diff --git a/src/include/utils/spccache.h b/src/include/utils/spccache.h index e0e42e99c8..26f88da0b2 100644 --- a/src/include/utils/spccache.h +++ b/src/include/utils/spccache.h @@ -3,7 +3,7 @@ * spccache.h * Tablespace cache. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/spccache.h diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h index 256615b671..66f60d271e 100644 --- a/src/include/utils/syscache.h +++ b/src/include/utils/syscache.h @@ -6,7 +6,7 @@ * See also lsyscache.h, which provides convenience routines for * common cache-lookup operations. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/syscache.h @@ -72,6 +72,7 @@ enum SysCacheIdentifier OPEROID, OPFAMILYAMNAMENSP, OPFAMILYOID, + PARTRELID, PROCNAMEARGSNSP, PROCOID, RANGETYPE, @@ -79,8 +80,15 @@ enum SysCacheIdentifier RELOID, REPLORIGIDENT, REPLORIGNAME, + PUBLICATIONOID, + PUBLICATIONNAME, + PUBLICATIONREL, + PUBLICATIONRELMAP, RULERELNAME, + SEQRELID, STATRELATTINH, + SUBSCRIPTIONOID, + SUBSCRIPTIONNAME, TABLESPACEOID, TRFOID, TRFTYPELANG, diff --git a/src/include/utils/timeout.h b/src/include/utils/timeout.h index 260c013960..aa816334c0 100644 --- a/src/include/utils/timeout.h +++ b/src/include/utils/timeout.h @@ -4,7 +4,7 @@ * Routines to multiplex SIGALRM interrupts for multiple timeout reasons. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/timeout.h diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h index 85cc7ce1fe..21651b1c85 100644 --- a/src/include/utils/timestamp.h +++ b/src/include/utils/timestamp.h @@ -3,7 +3,7 @@ * timestamp.h * Definitions for the SQL "timestamp" and "interval" types. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/timestamp.h @@ -88,134 +88,13 @@ extern TimestampTz PgStartTime; extern TimestampTz PgReloadTime; -/* - * timestamp.c prototypes - */ - -extern Datum timestamp_in(PG_FUNCTION_ARGS); -extern Datum timestamp_out(PG_FUNCTION_ARGS); -extern Datum timestamp_recv(PG_FUNCTION_ARGS); -extern Datum timestamp_send(PG_FUNCTION_ARGS); -extern Datum timestamptypmodin(PG_FUNCTION_ARGS); -extern Datum timestamptypmodout(PG_FUNCTION_ARGS); -extern Datum timestamp_transform(PG_FUNCTION_ARGS); -extern Datum timestamp_scale(PG_FUNCTION_ARGS); -extern Datum timestamp_eq(PG_FUNCTION_ARGS); -extern Datum timestamp_ne(PG_FUNCTION_ARGS); -extern Datum timestamp_lt(PG_FUNCTION_ARGS); -extern Datum timestamp_le(PG_FUNCTION_ARGS); -extern Datum timestamp_ge(PG_FUNCTION_ARGS); -extern Datum timestamp_gt(PG_FUNCTION_ARGS); -extern Datum timestamp_finite(PG_FUNCTION_ARGS); -extern Datum timestamp_cmp(PG_FUNCTION_ARGS); -extern Datum timestamp_sortsupport(PG_FUNCTION_ARGS); -extern Datum timestamp_hash(PG_FUNCTION_ARGS); -extern Datum timestamp_smaller(PG_FUNCTION_ARGS); -extern Datum timestamp_larger(PG_FUNCTION_ARGS); - -extern Datum timestamp_eq_timestamptz(PG_FUNCTION_ARGS); -extern Datum timestamp_ne_timestamptz(PG_FUNCTION_ARGS); -extern Datum timestamp_lt_timestamptz(PG_FUNCTION_ARGS); -extern Datum timestamp_le_timestamptz(PG_FUNCTION_ARGS); -extern Datum timestamp_gt_timestamptz(PG_FUNCTION_ARGS); -extern Datum timestamp_ge_timestamptz(PG_FUNCTION_ARGS); -extern Datum timestamp_cmp_timestamptz(PG_FUNCTION_ARGS); - -extern Datum make_timestamp(PG_FUNCTION_ARGS); -extern Datum make_timestamptz(PG_FUNCTION_ARGS); -extern Datum make_timestamptz_at_timezone(PG_FUNCTION_ARGS); -extern Datum float8_timestamptz(PG_FUNCTION_ARGS); - -extern Datum timestamptz_eq_timestamp(PG_FUNCTION_ARGS); -extern Datum timestamptz_ne_timestamp(PG_FUNCTION_ARGS); -extern Datum timestamptz_lt_timestamp(PG_FUNCTION_ARGS); -extern Datum timestamptz_le_timestamp(PG_FUNCTION_ARGS); -extern Datum timestamptz_gt_timestamp(PG_FUNCTION_ARGS); -extern Datum timestamptz_ge_timestamp(PG_FUNCTION_ARGS); -extern Datum timestamptz_cmp_timestamp(PG_FUNCTION_ARGS); - -extern Datum interval_in(PG_FUNCTION_ARGS); -extern Datum interval_out(PG_FUNCTION_ARGS); -extern Datum interval_recv(PG_FUNCTION_ARGS); -extern Datum interval_send(PG_FUNCTION_ARGS); -extern Datum intervaltypmodin(PG_FUNCTION_ARGS); -extern Datum intervaltypmodout(PG_FUNCTION_ARGS); -extern Datum interval_transform(PG_FUNCTION_ARGS); -extern Datum interval_scale(PG_FUNCTION_ARGS); -extern Datum interval_eq(PG_FUNCTION_ARGS); -extern Datum interval_ne(PG_FUNCTION_ARGS); -extern Datum interval_lt(PG_FUNCTION_ARGS); -extern Datum interval_le(PG_FUNCTION_ARGS); -extern Datum interval_ge(PG_FUNCTION_ARGS); -extern Datum interval_gt(PG_FUNCTION_ARGS); -extern Datum interval_finite(PG_FUNCTION_ARGS); -extern Datum interval_cmp(PG_FUNCTION_ARGS); -extern Datum interval_hash(PG_FUNCTION_ARGS); -extern Datum interval_smaller(PG_FUNCTION_ARGS); -extern Datum interval_larger(PG_FUNCTION_ARGS); -extern Datum interval_justify_interval(PG_FUNCTION_ARGS); -extern Datum interval_justify_hours(PG_FUNCTION_ARGS); -extern Datum interval_justify_days(PG_FUNCTION_ARGS); -extern Datum make_interval(PG_FUNCTION_ARGS); - -extern Datum timestamp_trunc(PG_FUNCTION_ARGS); -extern Datum interval_trunc(PG_FUNCTION_ARGS); -extern Datum timestamp_part(PG_FUNCTION_ARGS); -extern Datum interval_part(PG_FUNCTION_ARGS); -extern Datum timestamp_zone_transform(PG_FUNCTION_ARGS); -extern Datum timestamp_zone(PG_FUNCTION_ARGS); -extern Datum timestamp_izone_transform(PG_FUNCTION_ARGS); -extern Datum timestamp_izone(PG_FUNCTION_ARGS); -extern Datum timestamp_timestamptz(PG_FUNCTION_ARGS); - -extern Datum timestamptz_in(PG_FUNCTION_ARGS); -extern Datum timestamptz_out(PG_FUNCTION_ARGS); -extern Datum timestamptz_recv(PG_FUNCTION_ARGS); -extern Datum timestamptz_send(PG_FUNCTION_ARGS); -extern Datum timestamptztypmodin(PG_FUNCTION_ARGS); -extern Datum timestamptztypmodout(PG_FUNCTION_ARGS); -extern Datum timestamptz_scale(PG_FUNCTION_ARGS); -extern Datum timestamptz_timestamp(PG_FUNCTION_ARGS); -extern Datum timestamptz_zone(PG_FUNCTION_ARGS); -extern Datum timestamptz_izone(PG_FUNCTION_ARGS); -extern Datum timestamptz_timestamptz(PG_FUNCTION_ARGS); - -extern Datum interval_um(PG_FUNCTION_ARGS); -extern Datum interval_pl(PG_FUNCTION_ARGS); -extern Datum interval_mi(PG_FUNCTION_ARGS); -extern Datum interval_mul(PG_FUNCTION_ARGS); -extern Datum mul_d_interval(PG_FUNCTION_ARGS); -extern Datum interval_div(PG_FUNCTION_ARGS); -extern Datum interval_accum(PG_FUNCTION_ARGS); -extern Datum interval_combine(PG_FUNCTION_ARGS); -extern Datum interval_accum_inv(PG_FUNCTION_ARGS); -extern Datum interval_avg(PG_FUNCTION_ARGS); - -extern Datum timestamp_mi(PG_FUNCTION_ARGS); -extern Datum timestamp_pl_interval(PG_FUNCTION_ARGS); -extern Datum timestamp_mi_interval(PG_FUNCTION_ARGS); -extern Datum timestamp_age(PG_FUNCTION_ARGS); -extern Datum overlaps_timestamp(PG_FUNCTION_ARGS); - -extern Datum timestamptz_pl_interval(PG_FUNCTION_ARGS); -extern Datum timestamptz_mi_interval(PG_FUNCTION_ARGS); -extern Datum timestamptz_age(PG_FUNCTION_ARGS); -extern Datum timestamptz_trunc(PG_FUNCTION_ARGS); -extern Datum timestamptz_part(PG_FUNCTION_ARGS); - -extern Datum now(PG_FUNCTION_ARGS); -extern Datum statement_timestamp(PG_FUNCTION_ARGS); -extern Datum clock_timestamp(PG_FUNCTION_ARGS); - -extern Datum pg_postmaster_start_time(PG_FUNCTION_ARGS); -extern Datum pg_conf_load_time(PG_FUNCTION_ARGS); - -extern Datum generate_series_timestamp(PG_FUNCTION_ARGS); -extern Datum generate_series_timestamptz(PG_FUNCTION_ARGS); - /* Internal routines (not fmgr-callable) */ +extern int32 anytimestamp_typmod_check(bool istz, int32 typmod); + extern TimestampTz GetCurrentTimestamp(void); +extern TimestampTz GetSQLCurrentTimestamp(int32 typmod); +extern Timestamp GetSQLLocalTimestamp(int32 typmod); extern void TimestampDifference(TimestampTz start_time, TimestampTz stop_time, long *secs, int *microsecs); extern bool TimestampDifferenceExceeds(TimestampTz start_time, diff --git a/src/include/utils/tqual.h b/src/include/utils/tqual.h index fafe1bd862..f39f21bb64 100644 --- a/src/include/utils/tqual.h +++ b/src/include/utils/tqual.h @@ -5,7 +5,7 @@ * * Should be moved/renamed... - vadim 07/28/98 * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/tqual.h diff --git a/src/include/utils/tuplesort.h b/src/include/utils/tuplesort.h index 5cecd6d1b8..5b3f4752f4 100644 --- a/src/include/utils/tuplesort.h +++ b/src/include/utils/tuplesort.h @@ -10,7 +10,7 @@ * amounts are sorted using temporary files and a standard external sort * algorithm. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/tuplesort.h @@ -94,10 +94,8 @@ extern void tuplesort_performsort(Tuplesortstate *state); extern bool tuplesort_gettupleslot(Tuplesortstate *state, bool forward, TupleTableSlot *slot, Datum *abbrev); -extern HeapTuple tuplesort_getheaptuple(Tuplesortstate *state, bool forward, - bool *should_free); -extern IndexTuple tuplesort_getindextuple(Tuplesortstate *state, bool forward, - bool *should_free); +extern HeapTuple tuplesort_getheaptuple(Tuplesortstate *state, bool forward); +extern IndexTuple tuplesort_getindextuple(Tuplesortstate *state, bool forward); extern bool tuplesort_getdatum(Tuplesortstate *state, bool forward, Datum *val, bool *isNull, Datum *abbrev); diff --git a/src/include/utils/tuplestore.h b/src/include/utils/tuplestore.h index e864a6d8b7..a52a547037 100644 --- a/src/include/utils/tuplestore.h +++ b/src/include/utils/tuplestore.h @@ -21,7 +21,7 @@ * Also, we have changed the API to return tuples in TupleTableSlots, * so that there is a check to prevent attempted access to system columns. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/tuplestore.h diff --git a/src/include/utils/typcache.h b/src/include/utils/typcache.h index c72efcccb1..90a1f6347a 100644 --- a/src/include/utils/typcache.h +++ b/src/include/utils/typcache.h @@ -6,7 +6,7 @@ * The type cache exists to speed lookup of certain information about data * types that is not directly available from a type's pg_type row. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/typcache.h @@ -131,9 +131,9 @@ typedef struct DomainConstraintRef { List *constraints; /* list of DomainConstraintState nodes */ MemoryContext refctx; /* context holding DomainConstraintRef */ + TypeCacheEntry *tcache; /* typcache entry for domain type */ /* Management data --- treat these fields as private to typcache.c */ - TypeCacheEntry *tcache; /* owning typcache entry */ DomainConstraintCache *dcc; /* current constraints, or NULL if none */ MemoryContextCallback callback; /* used to release refcount when done */ } DomainConstraintRef; diff --git a/src/include/utils/tzparser.h b/src/include/utils/tzparser.h index eea8ffcfa4..c22467de1a 100644 --- a/src/include/utils/tzparser.h +++ b/src/include/utils/tzparser.h @@ -3,7 +3,7 @@ * tzparser.h * Timezone offset file parsing definitions. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/tzparser.h diff --git a/src/include/utils/uuid.h b/src/include/utils/uuid.h index 897382f2e5..9e62d81c3d 100644 --- a/src/include/utils/uuid.h +++ b/src/include/utils/uuid.h @@ -5,7 +5,7 @@ * to avoid conflicts with any uuid_t type that might be defined by * the system headers. * - * Copyright (c) 2007-2016, PostgreSQL Global Development Group + * Copyright (c) 2007-2017, PostgreSQL Global Development Group * * src/include/utils/uuid.h * @@ -14,11 +14,13 @@ #ifndef UUID_H #define UUID_H -/* guid size in bytes */ +/* uuid size in bytes */ #define UUID_LEN 16 -/* opaque struct; defined in uuid.c */ -typedef struct pg_uuid_t pg_uuid_t; +typedef struct pg_uuid_t +{ + unsigned char data[UUID_LEN]; +} pg_uuid_t; /* fmgr interface macros */ #define UUIDPGetDatum(X) PointerGetDatum(X) diff --git a/src/include/utils/varbit.h b/src/include/utils/varbit.h index 5d5c9f38fa..2a4ec67698 100644 --- a/src/include/utils/varbit.h +++ b/src/include/utils/varbit.h @@ -5,7 +5,7 @@ * * Code originally contributed by Adriaan Joubert. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/varbit.h @@ -66,50 +66,4 @@ typedef struct /* Mask that will cover exactly one byte, i.e. BITS_PER_BYTE bits */ #define BITMASK 0xFF - -extern Datum bit_in(PG_FUNCTION_ARGS); -extern Datum bit_out(PG_FUNCTION_ARGS); -extern Datum bit_recv(PG_FUNCTION_ARGS); -extern Datum bit_send(PG_FUNCTION_ARGS); -extern Datum bittypmodin(PG_FUNCTION_ARGS); -extern Datum bittypmodout(PG_FUNCTION_ARGS); -extern Datum varbit_in(PG_FUNCTION_ARGS); -extern Datum varbit_out(PG_FUNCTION_ARGS); -extern Datum varbit_recv(PG_FUNCTION_ARGS); -extern Datum varbit_send(PG_FUNCTION_ARGS); -extern Datum varbittypmodin(PG_FUNCTION_ARGS); -extern Datum varbittypmodout(PG_FUNCTION_ARGS); -extern Datum bit(PG_FUNCTION_ARGS); -extern Datum varbit_transform(PG_FUNCTION_ARGS); -extern Datum varbit(PG_FUNCTION_ARGS); -extern Datum biteq(PG_FUNCTION_ARGS); -extern Datum bitne(PG_FUNCTION_ARGS); -extern Datum bitlt(PG_FUNCTION_ARGS); -extern Datum bitle(PG_FUNCTION_ARGS); -extern Datum bitgt(PG_FUNCTION_ARGS); -extern Datum bitge(PG_FUNCTION_ARGS); -extern Datum bitcmp(PG_FUNCTION_ARGS); - -/* avoid the names bitand and bitor, since they are C++ keywords */ -extern Datum bit_and(PG_FUNCTION_ARGS); -extern Datum bit_or(PG_FUNCTION_ARGS); -extern Datum bitxor(PG_FUNCTION_ARGS); -extern Datum bitnot(PG_FUNCTION_ARGS); -extern Datum bitshiftleft(PG_FUNCTION_ARGS); -extern Datum bitshiftright(PG_FUNCTION_ARGS); -extern Datum bitcat(PG_FUNCTION_ARGS); -extern Datum bitsubstr(PG_FUNCTION_ARGS); -extern Datum bitsubstr_no_len(PG_FUNCTION_ARGS); -extern Datum bitoverlay(PG_FUNCTION_ARGS); -extern Datum bitoverlay_no_len(PG_FUNCTION_ARGS); -extern Datum bitlength(PG_FUNCTION_ARGS); -extern Datum bitoctetlength(PG_FUNCTION_ARGS); -extern Datum bitfromint4(PG_FUNCTION_ARGS); -extern Datum bittoint4(PG_FUNCTION_ARGS); -extern Datum bitfromint8(PG_FUNCTION_ARGS); -extern Datum bittoint8(PG_FUNCTION_ARGS); -extern Datum bitposition(PG_FUNCTION_ARGS); -extern Datum bitsetbit(PG_FUNCTION_ARGS); -extern Datum bitgetbit(PG_FUNCTION_ARGS); - #endif diff --git a/src/include/utils/varlena.h b/src/include/utils/varlena.h new file mode 100644 index 0000000000..b5994a1c72 --- /dev/null +++ b/src/include/utils/varlena.h @@ -0,0 +1,37 @@ +/*------------------------------------------------------------------------- + * + * varlena.h + * Functions for the variable-length built-in types. + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/varlena.h + * + *------------------------------------------------------------------------- + */ +#ifndef VARLENA_H +#define VARLENA_H + +#include "nodes/pg_list.h" +#include "utils/sortsupport.h" + +extern int varstr_cmp(char *arg1, int len1, char *arg2, int len2, Oid collid); +extern void varstr_sortsupport(SortSupport ssup, Oid collid, bool bpchar); +extern int varstr_levenshtein(const char *source, int slen, + const char *target, int tlen, + int ins_c, int del_c, int sub_c, + bool trusted); +extern int varstr_levenshtein_less_equal(const char *source, int slen, + const char *target, int tlen, + int ins_c, int del_c, int sub_c, + int max_d, bool trusted); +extern List *textToQualifiedNameList(text *textval); +extern bool SplitIdentifierString(char *rawstring, char separator, + List **namelist); +extern bool SplitDirectoriesString(char *rawstring, char separator, + List **namelist); +extern text *replace_text_regexp(text *src_text, void *regexp, + text *replace_text, bool glob); + +#endif diff --git a/src/include/utils/xml.h b/src/include/utils/xml.h index 2eab8a5c2d..cc1fc390e8 100644 --- a/src/include/utils/xml.h +++ b/src/include/utils/xml.h @@ -4,7 +4,7 @@ * Declarations for XML data type support. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/xml.h @@ -52,39 +52,6 @@ typedef struct PgXmlErrorContext PgXmlErrorContext; #define PG_GETARG_XML_P(n) DatumGetXmlP(PG_GETARG_DATUM(n)) #define PG_RETURN_XML_P(x) PG_RETURN_POINTER(x) -extern Datum xml_in(PG_FUNCTION_ARGS); -extern Datum xml_out(PG_FUNCTION_ARGS); -extern Datum xml_recv(PG_FUNCTION_ARGS); -extern Datum xml_send(PG_FUNCTION_ARGS); -extern Datum xmlcomment(PG_FUNCTION_ARGS); -extern Datum xmlconcat2(PG_FUNCTION_ARGS); -extern Datum texttoxml(PG_FUNCTION_ARGS); -extern Datum xmltotext(PG_FUNCTION_ARGS); -extern Datum xmlvalidate(PG_FUNCTION_ARGS); -extern Datum xpath(PG_FUNCTION_ARGS); -extern Datum xpath_exists(PG_FUNCTION_ARGS); -extern Datum xmlexists(PG_FUNCTION_ARGS); -extern Datum xml_is_well_formed(PG_FUNCTION_ARGS); -extern Datum xml_is_well_formed_document(PG_FUNCTION_ARGS); -extern Datum xml_is_well_formed_content(PG_FUNCTION_ARGS); - -extern Datum table_to_xml(PG_FUNCTION_ARGS); -extern Datum query_to_xml(PG_FUNCTION_ARGS); -extern Datum cursor_to_xml(PG_FUNCTION_ARGS); -extern Datum table_to_xmlschema(PG_FUNCTION_ARGS); -extern Datum query_to_xmlschema(PG_FUNCTION_ARGS); -extern Datum cursor_to_xmlschema(PG_FUNCTION_ARGS); -extern Datum table_to_xml_and_xmlschema(PG_FUNCTION_ARGS); -extern Datum query_to_xml_and_xmlschema(PG_FUNCTION_ARGS); - -extern Datum schema_to_xml(PG_FUNCTION_ARGS); -extern Datum schema_to_xmlschema(PG_FUNCTION_ARGS); -extern Datum schema_to_xml_and_xmlschema(PG_FUNCTION_ARGS); - -extern Datum database_to_xml(PG_FUNCTION_ARGS); -extern Datum database_to_xmlschema(PG_FUNCTION_ARGS); -extern Datum database_to_xml_and_xmlschema(PG_FUNCTION_ARGS); - extern void pg_xml_init_library(void); extern PgXmlErrorContext *pg_xml_init(PgXmlStrictness strictness); extern void pg_xml_done(PgXmlErrorContext *errcxt, bool isError); diff --git a/src/include/windowapi.h b/src/include/windowapi.h index dc693cc13c..481ebe06cf 100644 --- a/src/include/windowapi.h +++ b/src/include/windowapi.h @@ -19,7 +19,7 @@ * function in nodeWindowAgg.c for details. * * - * Portions Copyright (c) 2000-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2000-2017, PostgreSQL Global Development Group * * src/include/windowapi.h * diff --git a/src/interfaces/ecpg/compatlib/Makefile b/src/interfaces/ecpg/compatlib/Makefile index 0a04a7310f..04ddcfeab2 100644 --- a/src/interfaces/ecpg/compatlib/Makefile +++ b/src/interfaces/ecpg/compatlib/Makefile @@ -2,7 +2,7 @@ # # Makefile for ecpg compatibility library # -# Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/interfaces/ecpg/compatlib/Makefile @@ -16,7 +16,7 @@ include $(top_builddir)/src/Makefile.global PGFILEDESC = "ECPG compat - compatibility library for ECPG" NAME= ecpg_compat SO_MAJOR_VERSION= 3 -SO_MINOR_VERSION= 8 +SO_MINOR_VERSION= $(MAJORVERSION) override CPPFLAGS := -I../include -I$(top_srcdir)/src/interfaces/ecpg/include \ -I$(libpq_srcdir) -DFRONTEND $(CPPFLAGS) diff --git a/src/interfaces/ecpg/ecpglib/Makefile b/src/interfaces/ecpg/ecpglib/Makefile index 39c4232580..fbb14073ce 100644 --- a/src/interfaces/ecpg/ecpglib/Makefile +++ b/src/interfaces/ecpg/ecpglib/Makefile @@ -2,7 +2,7 @@ # # Makefile for ecpg library # -# Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/interfaces/ecpg/ecpglib/Makefile @@ -16,7 +16,7 @@ include $(top_builddir)/src/Makefile.global PGFILEDESC = "ECPG - embedded SQL in C" NAME= ecpg SO_MAJOR_VERSION= 6 -SO_MINOR_VERSION= 8 +SO_MINOR_VERSION= $(MAJORVERSION) override CPPFLAGS := -I../include -I$(top_srcdir)/src/interfaces/ecpg/include \ -I$(libpq_srcdir) -I$(top_builddir)/src/port -DFRONTEND $(CPPFLAGS) diff --git a/src/interfaces/ecpg/ecpglib/pg_type.h b/src/interfaces/ecpg/ecpglib/pg_type.h index 79daedaf17..c86af256dc 100644 --- a/src/interfaces/ecpg/ecpglib/pg_type.h +++ b/src/interfaces/ecpg/ecpglib/pg_type.h @@ -5,7 +5,7 @@ * * XXX keep this in sync with src/include/catalog/pg_type.h * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/ecpg/ecpglib/pg_type.h diff --git a/src/interfaces/ecpg/pgtypeslib/Makefile b/src/interfaces/ecpg/pgtypeslib/Makefile index 1c1a42fa8f..9fc75661b5 100644 --- a/src/interfaces/ecpg/pgtypeslib/Makefile +++ b/src/interfaces/ecpg/pgtypeslib/Makefile @@ -2,7 +2,7 @@ # # Makefile for ecpg pgtypes library # -# Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/interfaces/ecpg/pgtypeslib/Makefile @@ -16,7 +16,7 @@ include $(top_builddir)/src/Makefile.global PGFILEDESC = "pgtypes - library for data type mapping" NAME= pgtypes SO_MAJOR_VERSION= 3 -SO_MINOR_VERSION= 7 +SO_MINOR_VERSION= $(MAJORVERSION) override CPPFLAGS := -I../include -I$(top_srcdir)/src/interfaces/ecpg/include \ -DFRONTEND $(CPPFLAGS) diff --git a/src/interfaces/ecpg/preproc/Makefile b/src/interfaces/ecpg/preproc/Makefile index 30db5a049a..02a6e65daf 100644 --- a/src/interfaces/ecpg/preproc/Makefile +++ b/src/interfaces/ecpg/preproc/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/interfaces/ecpg/preproc # -# Copyright (c) 1998-2016, PostgreSQL Global Development Group +# Copyright (c) 1998-2017, PostgreSQL Global Development Group # # src/interfaces/ecpg/preproc/Makefile # @@ -15,16 +15,11 @@ subdir = src/interfaces/ecpg/preproc top_builddir = ../../../.. include $(top_builddir)/src/Makefile.global -MAJOR_VERSION= 4 -MINOR_VERSION= 12 -PATCHLEVEL=0 - override CPPFLAGS := -I../include -I$(top_srcdir)/src/interfaces/ecpg/include \ - -I. -I$(srcdir) -DMAJOR_VERSION=$(MAJOR_VERSION) \ - -DMINOR_VERSION=$(MINOR_VERSION) -DPATCHLEVEL=$(PATCHLEVEL) \ + -I. -I$(srcdir) -DECPG_COMPILE \ $(CPPFLAGS) -override CFLAGS += $(PTHREAD_CFLAGS) -DECPG_COMPILE +override CFLAGS += $(PTHREAD_CFLAGS) OBJS= preproc.o pgc.o type.o ecpg.o output.o parser.o \ keywords.o c_keywords.o ecpg_keywords.o ../ecpglib/typename.o descriptor.o variable.o \ diff --git a/src/interfaces/ecpg/preproc/check_rules.pl b/src/interfaces/ecpg/preproc/check_rules.pl index 4c981e0dea..dce4bc6a02 100644 --- a/src/interfaces/ecpg/preproc/check_rules.pl +++ b/src/interfaces/ecpg/preproc/check_rules.pl @@ -3,7 +3,7 @@ # test parser generater for ecpg # call with backend parser as stdin # -# Copyright (c) 2009-2016, PostgreSQL Global Development Group +# Copyright (c) 2009-2017, PostgreSQL Global Development Group # # Written by Michael Meskes # Andy Colson diff --git a/src/interfaces/ecpg/preproc/descriptor.c b/src/interfaces/ecpg/preproc/descriptor.c index 9b4eb630a9..c6442c1805 100644 --- a/src/interfaces/ecpg/preproc/descriptor.c +++ b/src/interfaces/ecpg/preproc/descriptor.c @@ -58,7 +58,7 @@ ECPGnumeric_lvalue(char *name) case ECPGt_unsigned_long: case ECPGt_unsigned_long_long: case ECPGt_const: - fputs(name, yyout); + fputs(name, base_yyout); break; default: mmerror(PARSE_ERROR, ET_ERROR, "variable \"%s\" must have a numeric type", name); @@ -152,7 +152,7 @@ output_get_descr_header(char *desc_name) { struct assignment *results; - fprintf(yyout, "{ ECPGget_desc_header(__LINE__, %s, &(", desc_name); + fprintf(base_yyout, "{ ECPGget_desc_header(__LINE__, %s, &(", desc_name); for (results = assignments; results != NULL; results = results->next) { if (results->value == ECPGd_count) @@ -162,7 +162,7 @@ output_get_descr_header(char *desc_name) } drop_assignments(); - fprintf(yyout, "));\n"); + fprintf(base_yyout, "));\n"); whenever_action(3); } @@ -171,7 +171,7 @@ output_get_descr(char *desc_name, char *index) { struct assignment *results; - fprintf(yyout, "{ ECPGget_desc(__LINE__, %s, %s,", desc_name, index); + fprintf(base_yyout, "{ ECPGget_desc(__LINE__, %s, %s,", desc_name, index); for (results = assignments; results != NULL; results = results->next) { const struct variable *v = find_variable(results->variable); @@ -188,12 +188,13 @@ output_get_descr(char *desc_name, char *index) default: break; } - fprintf(yyout, "%s,", get_dtype(results->value)); - ECPGdump_a_type(yyout, v->name, v->type, v->brace_level, NULL, NULL, -1, NULL, NULL, str_zero, NULL, NULL); + fprintf(base_yyout, "%s,", get_dtype(results->value)); + ECPGdump_a_type(base_yyout, v->name, v->type, v->brace_level, + NULL, NULL, -1, NULL, NULL, str_zero, NULL, NULL); free(str_zero); } drop_assignments(); - fputs("ECPGd_EODT);\n", yyout); + fputs("ECPGd_EODT);\n", base_yyout); whenever_action(2 | 1); } @@ -203,7 +204,7 @@ output_set_descr_header(char *desc_name) { struct assignment *results; - fprintf(yyout, "{ ECPGset_desc_header(__LINE__, %s, (int)(", desc_name); + fprintf(base_yyout, "{ ECPGset_desc_header(__LINE__, %s, (int)(", desc_name); for (results = assignments; results != NULL; results = results->next) { if (results->value == ECPGd_count) @@ -213,7 +214,7 @@ output_set_descr_header(char *desc_name) } drop_assignments(); - fprintf(yyout, "));\n"); + fprintf(base_yyout, "));\n"); whenever_action(3); } @@ -264,7 +265,7 @@ output_set_descr(char *desc_name, char *index) { struct assignment *results; - fprintf(yyout, "{ ECPGset_desc(__LINE__, %s, %s,", desc_name, index); + fprintf(base_yyout, "{ ECPGset_desc(__LINE__, %s, %s,", desc_name, index); for (results = assignments; results != NULL; results = results->next) { const struct variable *v = find_variable(results->variable); @@ -297,8 +298,9 @@ output_set_descr(char *desc_name, char *index) { char *str_zero = mm_strdup("0"); - fprintf(yyout, "%s,", get_dtype(results->value)); - ECPGdump_a_type(yyout, v->name, v->type, v->brace_level, NULL, NULL, -1, NULL, NULL, str_zero, NULL, NULL); + fprintf(base_yyout, "%s,", get_dtype(results->value)); + ECPGdump_a_type(base_yyout, v->name, v->type, v->brace_level, + NULL, NULL, -1, NULL, NULL, str_zero, NULL, NULL); free(str_zero); } break; @@ -308,7 +310,7 @@ output_set_descr(char *desc_name, char *index) } } drop_assignments(); - fputs("ECPGd_EODT);\n", yyout); + fputs("ECPGd_EODT);\n", base_yyout); whenever_action(2 | 1); } diff --git a/src/interfaces/ecpg/preproc/ecpg.addons b/src/interfaces/ecpg/preproc/ecpg.addons index b3b36cf72d..ca3efadc48 100644 --- a/src/interfaces/ecpg/preproc/ecpg.addons +++ b/src/interfaces/ecpg/preproc/ecpg.addons @@ -8,7 +8,7 @@ ECPG: stmtClosePortalStmt block if (connection) mmerror(PARSE_ERROR, ET_ERROR, "AT option not allowed in CLOSE DATABASE statement"); - fprintf(yyout, "{ ECPGdisconnect(__LINE__, \"CURRENT\");"); + fprintf(base_yyout, "{ ECPGdisconnect(__LINE__, \"CURRENT\");"); whenever_action(2); free($1); break; @@ -42,14 +42,14 @@ ECPG: stmtPrepareStmt block } ECPG: stmtTransactionStmt block { - fprintf(yyout, "{ ECPGtrans(__LINE__, %s, \"%s\");", connection ? connection : "NULL", $1); + fprintf(base_yyout, "{ ECPGtrans(__LINE__, %s, \"%s\");", connection ? connection : "NULL", $1); whenever_action(2); free($1); } ECPG: stmtViewStmt rule | ECPGAllocateDescr { - fprintf(yyout,"ECPGallocate_desc(__LINE__, %s);",$1); + fprintf(base_yyout,"ECPGallocate_desc(__LINE__, %s);",$1); whenever_action(0); free($1); } @@ -58,7 +58,7 @@ ECPG: stmtViewStmt rule if (connection) mmerror(PARSE_ERROR, ET_ERROR, "AT option not allowed in CONNECT statement"); - fprintf(yyout, "{ ECPGconnect(__LINE__, %d, %s, %d); ", compat, $1, autocommit); + fprintf(base_yyout, "{ ECPGconnect(__LINE__, %d, %s, %d); ", compat, $1, autocommit); reset_variables(); whenever_action(2); free($1); @@ -69,7 +69,7 @@ ECPG: stmtViewStmt rule } | ECPGDeallocateDescr { - fprintf(yyout,"ECPGdeallocate_desc(__LINE__, %s);",$1); + fprintf(base_yyout,"ECPGdeallocate_desc(__LINE__, %s);",$1); whenever_action(0); free($1); } @@ -79,10 +79,10 @@ ECPG: stmtViewStmt rule } | ECPGDescribe { - fprintf(yyout, "{ ECPGdescribe(__LINE__, %d, %s,", compat, $1); + fprintf(base_yyout, "{ ECPGdescribe(__LINE__, %d, %s,", compat, $1); dump_variables(argsresult, 1); - fputs("ECPGt_EORT);", yyout); - fprintf(yyout, "}"); + fputs("ECPGt_EORT);", base_yyout); + fprintf(base_yyout, "}"); output_line_number(); free($1); @@ -92,7 +92,7 @@ ECPG: stmtViewStmt rule if (connection) mmerror(PARSE_ERROR, ET_ERROR, "AT option not allowed in DISCONNECT statement"); - fprintf(yyout, "{ ECPGdisconnect(__LINE__, %s);", + fprintf(base_yyout, "{ ECPGdisconnect(__LINE__, %s);", $1 ? $1 : "\"CURRENT\""); whenever_action(2); free($1); @@ -103,11 +103,11 @@ ECPG: stmtViewStmt rule const char *con = connection ? connection : "NULL"; if (strcmp($1, "all") == 0) - fprintf(yyout, "{ ECPGdeallocate_all(__LINE__, %d, %s);", compat, con); + fprintf(base_yyout, "{ ECPGdeallocate_all(__LINE__, %d, %s);", compat, con); else if ($1[0] == ':') - fprintf(yyout, "{ ECPGdeallocate(__LINE__, %d, %s, %s);", compat, con, $1+1); + fprintf(base_yyout, "{ ECPGdeallocate(__LINE__, %d, %s, %s);", compat, con, $1+1); else - fprintf(yyout, "{ ECPGdeallocate(__LINE__, %d, %s, \"%s\");", compat, con, $1); + fprintf(base_yyout, "{ ECPGdeallocate(__LINE__, %d, %s, \"%s\");", compat, con, $1); whenever_action(2); free($1); @@ -138,7 +138,7 @@ ECPG: stmtViewStmt rule } | ECPGSetAutocommit { - fprintf(yyout, "{ ECPGsetcommit(__LINE__, \"%s\", %s);", $1, connection ? connection : "NULL"); + fprintf(base_yyout, "{ ECPGsetcommit(__LINE__, \"%s\", %s);", $1, connection ? connection : "NULL"); whenever_action(2); free($1); } @@ -147,7 +147,7 @@ ECPG: stmtViewStmt rule if (connection) mmerror(PARSE_ERROR, ET_ERROR, "AT option not allowed in SET CONNECTION statement"); - fprintf(yyout, "{ ECPGsetconn(__LINE__, %s);", $1); + fprintf(base_yyout, "{ ECPGsetconn(__LINE__, %s);", $1); whenever_action(2); free($1); } @@ -169,7 +169,7 @@ ECPG: stmtViewStmt rule if (connection) mmerror(PARSE_ERROR, ET_ERROR, "AT option not allowed in TYPE statement"); - fprintf(yyout, "%s", $1); + fprintf(base_yyout, "%s", $1); free($1); output_line_number(); } diff --git a/src/interfaces/ecpg/preproc/ecpg.c b/src/interfaces/ecpg/preproc/ecpg.c index c7fd034bc1..fa80bb289e 100644 --- a/src/interfaces/ecpg/preproc/ecpg.c +++ b/src/interfaces/ecpg/preproc/ecpg.c @@ -1,7 +1,7 @@ /* src/interfaces/ecpg/preproc/ecpg.c */ /* Main for ecpg, the PostgreSQL embedded SQL precompiler. */ -/* Copyright (c) 1996-2016, PostgreSQL Global Development Group */ +/* Copyright (c) 1996-2017, PostgreSQL Global Development Group */ #include "postgres_fe.h" @@ -54,7 +54,7 @@ help(const char *progname) " \"no_indicator\", \"prepare\", \"questionmarks\"\n")); printf(_(" --regression run in regression testing mode\n")); printf(_(" -t turn on autocommit of transactions\n")); - printf(_(" --version output version information, then exit\n")); + printf(_(" -V, --version output version information, then exit\n")); printf(_(" -?, --help show this help, then exit\n")); printf(_("\nIf no output file is specified, the name is formed by adding .c to the\n" "input file name, after stripping off .pgc if present.\n")); @@ -111,15 +111,11 @@ add_preprocessor_define(char *define) defines->next = pd; } -#define ECPG_GETOPT_LONG_HELP 1 -#define ECPG_GETOPT_LONG_VERSION 2 -#define ECPG_GETOPT_LONG_REGRESSION 3 +#define ECPG_GETOPT_LONG_REGRESSION 1 int main(int argc, char *const argv[]) { static struct option ecpg_options[] = { - {"help", no_argument, NULL, ECPG_GETOPT_LONG_HELP}, - {"version", no_argument, NULL, ECPG_GETOPT_LONG_VERSION}, {"regression", no_argument, NULL, ECPG_GETOPT_LONG_REGRESSION}, {NULL, 0, NULL, 0} }; @@ -144,44 +140,36 @@ main(int argc, char *const argv[]) return (ILLEGAL_OPTION); } + if (argc > 1) + { + if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) + { + help(progname); + exit(0); + } + if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) + { + printf("ecpg %s\n", PG_VERSION); + exit(0); + } + } + output_filename = NULL; - while ((c = getopt_long(argc, argv, "vcio:I:tD:dC:r:h?", ecpg_options, NULL)) != -1) + while ((c = getopt_long(argc, argv, "vcio:I:tD:dC:r:h", ecpg_options, NULL)) != -1) { switch (c) { - case ECPG_GETOPT_LONG_VERSION: - printf("ecpg (PostgreSQL %s) %d.%d.%d\n", PG_VERSION, - MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL); - exit(0); - case ECPG_GETOPT_LONG_HELP: - help(progname); - exit(0); - - /* - * -? is an alternative spelling of --help. However it is also - * returned by getopt_long for unknown options. We can - * distinguish both cases by means of the optopt variable - * which is set to 0 if it was really -? and not an unknown - * option character. - */ - case '?': - if (optopt == 0) - { - help(progname); - exit(0); - } - break; case ECPG_GETOPT_LONG_REGRESSION: regression_mode = true; break; case 'o': output_filename = mm_strdup(optarg); if (strcmp(output_filename, "-") == 0) - yyout = stdout; + base_yyout = stdout; else - yyout = fopen(output_filename, PG_BINARY_W); + base_yyout = fopen(output_filename, PG_BINARY_W); - if (yyout == NULL) + if (base_yyout == NULL) { fprintf(stderr, _("%s: could not open file \"%s\": %s\n"), progname, output_filename, strerror(errno)); @@ -244,7 +232,7 @@ main(int argc, char *const argv[]) break; case 'd': #ifdef YYDEBUG - yydebug = 1; + base_yydebug = 1; #else fprintf(stderr, _("%s: parser debug support (-d) not available\n"), progname); @@ -264,8 +252,9 @@ main(int argc, char *const argv[]) if (verbose) { - fprintf(stderr, _("%s, the PostgreSQL embedded C preprocessor, version %d.%d.%d\n"), - progname, MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL); + fprintf(stderr, + _("%s, the PostgreSQL embedded C preprocessor, version %s\n"), + progname, PG_VERSION); fprintf(stderr, _("EXEC SQL INCLUDE ... search starts here:\n")); for (ip = include_paths; ip != NULL; ip = ip->next) fprintf(stderr, " %s\n", ip->path); @@ -291,7 +280,7 @@ main(int argc, char *const argv[]) { input_filename = mm_alloc(strlen("stdin") + 1); strcpy(input_filename, "stdin"); - yyin = stdin; + base_yyin = stdin; } else { @@ -315,24 +304,25 @@ main(int argc, char *const argv[]) ptr2ext[4] = '\0'; } - yyin = fopen(input_filename, PG_BINARY_R); + base_yyin = fopen(input_filename, PG_BINARY_R); } if (out_option == 0) /* calculate the output name */ { if (strcmp(input_filename, "stdin") == 0) - yyout = stdout; + base_yyout = stdout; else { - output_filename = mm_strdup(input_filename); + output_filename = mm_alloc(strlen(input_filename) + 3); + strcpy(output_filename, input_filename); ptr2ext = strrchr(output_filename, '.'); /* make extension = .c resp. .h */ ptr2ext[1] = (header_mode == true) ? 'h' : 'c'; ptr2ext[2] = '\0'; - yyout = fopen(output_filename, PG_BINARY_W); - if (yyout == NULL) + base_yyout = fopen(output_filename, PG_BINARY_W); + if (base_yyout == NULL) { fprintf(stderr, _("%s: could not open file \"%s\": %s\n"), progname, output_filename, strerror(errno)); @@ -343,7 +333,7 @@ main(int argc, char *const argv[]) } } - if (yyin == NULL) + if (base_yyin == NULL) fprintf(stderr, _("%s: could not open file \"%s\": %s\n"), progname, argv[fnr], strerror(errno)); else @@ -438,23 +428,23 @@ main(int argc, char *const argv[]) /* we need several includes */ /* but not if we are in header mode */ if (regression_mode) - fprintf(yyout, "/* Processed by ecpg (regression mode) */\n"); + fprintf(base_yyout, "/* Processed by ecpg (regression mode) */\n"); else - fprintf(yyout, "/* Processed by ecpg (%d.%d.%d) */\n", MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL); + fprintf(base_yyout, "/* Processed by ecpg (%s) */\n", PG_VERSION); if (header_mode == false) { - fprintf(yyout, "/* These include files are added by the preprocessor */\n#include \n#include \n#include \n"); + fprintf(base_yyout, "/* These include files are added by the preprocessor */\n#include \n#include \n#include \n"); /* add some compatibility headers */ if (INFORMIX_MODE) - fprintf(yyout, "/* Needed for informix compatibility */\n#include \n"); + fprintf(base_yyout, "/* Needed for informix compatibility */\n#include \n"); - fprintf(yyout, "/* End of automatic include section */\n"); + fprintf(base_yyout, "/* End of automatic include section */\n"); } if (regression_mode) - fprintf(yyout, "#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))\n"); + fprintf(base_yyout, "#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))\n"); output_line_number(); @@ -469,10 +459,10 @@ main(int argc, char *const argv[]) if (!(ptr->opened)) mmerror(PARSE_ERROR, ET_WARNING, "cursor \"%s\" has been declared but not opened", ptr->name); - if (yyin != NULL && yyin != stdin) - fclose(yyin); - if (out_option == 0 && yyout != stdout) - fclose(yyout); + if (base_yyin != NULL && base_yyin != stdin) + fclose(base_yyin); + if (out_option == 0 && base_yyout != stdout) + fclose(base_yyout); /* * If there was an error, delete the output file. diff --git a/src/interfaces/ecpg/preproc/ecpg.header b/src/interfaces/ecpg/preproc/ecpg.header index f41999a86f..672f0b45d4 100644 --- a/src/interfaces/ecpg/preproc/ecpg.header +++ b/src/interfaces/ecpg/preproc/ecpg.header @@ -72,7 +72,7 @@ vmmerror(int error_code, enum errortype type, const char *error, va_list ap) /* localize the error message string */ error = _(error); - fprintf(stderr, "%s:%d: ", input_filename, yylineno); + fprintf(stderr, "%s:%d: ", input_filename, base_yylineno); switch(type) { @@ -117,10 +117,10 @@ mmfatal(int error_code, const char *error, ...) vmmerror(error_code, ET_ERROR, error, ap); va_end(ap); - if (yyin) - fclose(yyin); - if (yyout) - fclose(yyout); + if (base_yyin) + fclose(base_yyin); + if (base_yyout) + fclose(base_yyout); if (strcmp(output_filename, "-") != 0 && unlink(output_filename) != 0) fprintf(stderr, _("could not remove output file \"%s\"\n"), output_filename); @@ -195,7 +195,7 @@ make3_str(char *str1, char *str2, char *str3) static char * make_name(void) { - return mm_strdup(yytext); + return mm_strdup(base_yytext); } static char * diff --git a/src/interfaces/ecpg/preproc/ecpg.trailer b/src/interfaces/ecpg/preproc/ecpg.trailer index de0df7440f..31e765ccd3 100644 --- a/src/interfaces/ecpg/preproc/ecpg.trailer +++ b/src/interfaces/ecpg/preproc/ecpg.trailer @@ -8,14 +8,14 @@ statement: ecpgstart at stmt ';' { connection = NULL; } | ecpgstart stmt ';' | ecpgstart ECPGVarDeclaration { - fprintf(yyout, "%s", $2); + fprintf(base_yyout, "%s", $2); free($2); output_line_number(); } | ECPGDeclaration - | c_thing { fprintf(yyout, "%s", $1); free($1); } - | CPP_LINE { fprintf(yyout, "%s", $1); free($1); } - | '{' { braces_open++; fputs("{", yyout); } + | c_thing { fprintf(base_yyout, "%s", $1); free($1); } + | CPP_LINE { fprintf(base_yyout, "%s", $1); free($1); } + | '{' { braces_open++; fputs("{", base_yyout); } | '}' { remove_typedefs(braces_open); @@ -25,7 +25,7 @@ statement: ecpgstart at stmt ';' { connection = NULL; } free(current_function); current_function = NULL; } - fputs("}", yyout); + fputs("}", base_yyout); } ; @@ -380,10 +380,10 @@ ecpg_interval: opt_interval { $$ = $1; } * variable declaration inside exec sql declare block */ ECPGDeclaration: sql_startdeclare - { fputs("/* exec sql begin declare section */", yyout); } + { fputs("/* exec sql begin declare section */", base_yyout); } var_type_declarations sql_enddeclare { - fprintf(yyout, "%s/* exec sql end declare section */", $3); + fprintf(base_yyout, "%s/* exec sql end declare section */", $3); free($3); output_line_number(); } @@ -417,7 +417,7 @@ type_declaration: S_TYPEDEF { add_typedef($5, $6.index1, $6.index2, $3.type_enum, $3.type_dimension, $3.type_index, initializer, *$4 ? 1 : 0); - fprintf(yyout, "typedef %s %s %s %s;\n", $3.type_str, *$4 ? "*" : "", $5, $6.str); + fprintf(base_yyout, "typedef %s %s %s %s;\n", $3.type_str, *$4 ? "*" : "", $5, $6.str); output_line_number(); $$ = mm_strdup(""); }; @@ -1909,7 +1909,7 @@ void base_yyerror(const char *error) { /* translator: %s is typically the translation of "syntax error" */ mmerror(PARSE_ERROR, ET_ERROR, "%s at or near \"%s\"", - _(error), token_start ? token_start : yytext); + _(error), token_start ? token_start : base_yytext); } void parser_init(void) diff --git a/src/interfaces/ecpg/preproc/extern.h b/src/interfaces/ecpg/preproc/extern.h index f6841726e4..0ce3a6e424 100644 --- a/src/interfaces/ecpg/preproc/extern.h +++ b/src/interfaces/ecpg/preproc/extern.h @@ -35,15 +35,15 @@ extern char *descriptor_index; extern char *descriptor_name; extern char *connection; extern char *input_filename; -extern char *yytext, +extern char *base_yytext, *token_start; #ifdef YYDEBUG -extern int yydebug; +extern int base_yydebug; #endif -extern int yylineno; -extern FILE *yyin, - *yyout; +extern int base_yylineno; +extern FILE *base_yyin, + *base_yyout; extern char *output_filename; extern struct _include_path *include_paths; diff --git a/src/interfaces/ecpg/preproc/keywords.c b/src/interfaces/ecpg/preproc/keywords.c index cffdaed67b..f016d7fc6f 100644 --- a/src/interfaces/ecpg/preproc/keywords.c +++ b/src/interfaces/ecpg/preproc/keywords.c @@ -4,7 +4,7 @@ * lexical token lookup for key words in PostgreSQL * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/interfaces/ecpg/preproc/output.c b/src/interfaces/ecpg/preproc/output.c index c1ba55d517..59d5d30df4 100644 --- a/src/interfaces/ecpg/preproc/output.c +++ b/src/interfaces/ecpg/preproc/output.c @@ -11,7 +11,7 @@ output_line_number(void) { char *line = hashline_number(); - fprintf(yyout, "%s", line); + fprintf(base_yyout, "%s", line); free(line); } @@ -37,22 +37,22 @@ print_action(struct when * w) switch (w->code) { case W_SQLPRINT: - fprintf(yyout, "sqlprint();"); + fprintf(base_yyout, "sqlprint();"); break; case W_GOTO: - fprintf(yyout, "goto %s;", w->command); + fprintf(base_yyout, "goto %s;", w->command); break; case W_DO: - fprintf(yyout, "%s;", w->command); + fprintf(base_yyout, "%s;", w->command); break; case W_STOP: - fprintf(yyout, "exit (1);"); + fprintf(base_yyout, "exit (1);"); break; case W_BREAK: - fprintf(yyout, "break;"); + fprintf(base_yyout, "break;"); break; default: - fprintf(yyout, "{/* %d not implemented yet */}", w->code); + fprintf(base_yyout, "{/* %d not implemented yet */}", w->code); break; } } @@ -63,24 +63,24 @@ whenever_action(int mode) if ((mode & 1) == 1 && when_nf.code != W_NOTHING) { output_line_number(); - fprintf(yyout, "\nif (sqlca.sqlcode == ECPG_NOT_FOUND) "); + fprintf(base_yyout, "\nif (sqlca.sqlcode == ECPG_NOT_FOUND) "); print_action(&when_nf); } if (when_warn.code != W_NOTHING) { output_line_number(); - fprintf(yyout, "\nif (sqlca.sqlwarn[0] == 'W') "); + fprintf(base_yyout, "\nif (sqlca.sqlwarn[0] == 'W') "); print_action(&when_warn); } if (when_error.code != W_NOTHING) { output_line_number(); - fprintf(yyout, "\nif (sqlca.sqlcode < 0) "); + fprintf(base_yyout, "\nif (sqlca.sqlcode < 0) "); print_action(&when_error); } if ((mode & 2) == 2) - fputc('}', yyout); + fputc('}', base_yyout); output_line_number(); } @@ -91,7 +91,7 @@ hashline_number(void) /* do not print line numbers if we are in debug mode */ if (input_filename #ifdef YYDEBUG - && !yydebug + && !base_yydebug #endif ) { @@ -100,7 +100,7 @@ hashline_number(void) char *src, *dest; - sprintf(line, "\n#line %d \"", yylineno); + sprintf(line, "\n#line %d \"", base_yylineno); src = input_filename; dest = line + strlen(line); while (*src) @@ -128,27 +128,27 @@ static char *ecpg_statement_type_name[] = { void output_statement(char *stmt, int whenever_mode, enum ECPG_statement_type st) { - fprintf(yyout, "{ ECPGdo(__LINE__, %d, %d, %s, %d, ", compat, force_indicator, connection ? connection : "NULL", questionmarks); + fprintf(base_yyout, "{ ECPGdo(__LINE__, %d, %d, %s, %d, ", compat, force_indicator, connection ? connection : "NULL", questionmarks); if (st == ECPGst_execute || st == ECPGst_exec_immediate) { - fprintf(yyout, "%s, %s, ", ecpg_statement_type_name[st], stmt); + fprintf(base_yyout, "%s, %s, ", ecpg_statement_type_name[st], stmt); } else { if (st == ECPGst_prepnormal && auto_prepare) - fputs("ECPGst_prepnormal, \"", yyout); + fputs("ECPGst_prepnormal, \"", base_yyout); else - fputs("ECPGst_normal, \"", yyout); + fputs("ECPGst_normal, \"", base_yyout); output_escaped_str(stmt, false); - fputs("\", ", yyout); + fputs("\", ", base_yyout); } /* dump variables to C file */ dump_variables(argsinsert, 1); - fputs("ECPGt_EOIT, ", yyout); + fputs("ECPGt_EOIT, ", base_yyout); dump_variables(argsresult, 1); - fputs("ECPGt_EORT);", yyout); + fputs("ECPGt_EORT);", base_yyout); reset_variables(); whenever_action(whenever_mode | 2); @@ -160,11 +160,11 @@ output_statement(char *stmt, int whenever_mode, enum ECPG_statement_type st) void output_prepare_statement(char *name, char *stmt) { - fprintf(yyout, "{ ECPGprepare(__LINE__, %s, %d, ", connection ? connection : "NULL", questionmarks); + fprintf(base_yyout, "{ ECPGprepare(__LINE__, %s, %d, ", connection ? connection : "NULL", questionmarks); output_escaped_str(name, true); - fputs(", ", yyout); + fputs(", ", base_yyout); output_escaped_str(stmt, true); - fputs(");", yyout); + fputs(");", base_yyout); whenever_action(2); free(name); if (connection != NULL) @@ -178,12 +178,12 @@ output_deallocate_prepare_statement(char *name) if (strcmp(name, "all") != 0) { - fprintf(yyout, "{ ECPGdeallocate(__LINE__, %d, %s, ", compat, con); + fprintf(base_yyout, "{ ECPGdeallocate(__LINE__, %d, %s, ", compat, con); output_escaped_str(name, true); - fputs(");", yyout); + fputs(");", base_yyout); } else - fprintf(yyout, "{ ECPGdeallocate_all(__LINE__, %d, %s);", compat, con); + fprintf(base_yyout, "{ ECPGdeallocate_all(__LINE__, %d, %s);", compat, con); whenever_action(2); free(name); @@ -203,16 +203,16 @@ output_escaped_str(char *str, bool quoted) { i = 1; len--; - fputs("\"", yyout); + fputs("\"", base_yyout); } /* output this char by char as we have to filter " and \n */ for (; i < len; i++) { if (str[i] == '"') - fputs("\\\"", yyout); + fputs("\\\"", base_yyout); else if (str[i] == '\n') - fputs("\\\n", yyout); + fputs("\\\n", base_yyout); else if (str[i] == '\\') { int j = i; @@ -230,17 +230,17 @@ output_escaped_str(char *str, bool quoted) if ((str[j] != '\n') && (str[j] != '\r' || str[j + 1] != '\n')) /* not followed by a * newline */ - fputs("\\\\", yyout); + fputs("\\\\", base_yyout); } else if (str[i] == '\r' && str[i + 1] == '\n') { - fputs("\\\r\n", yyout); + fputs("\\\r\n", base_yyout); i++; } else - fputc(str[i], yyout); + fputc(str[i], base_yyout); } if (quoted && str[0] == '"' && str[len] == '"') - fputs("\"", yyout); + fputs("\"", base_yyout); } diff --git a/src/interfaces/ecpg/preproc/parse.pl b/src/interfaces/ecpg/preproc/parse.pl index cc17ea8218..ea661d3694 100644 --- a/src/interfaces/ecpg/preproc/parse.pl +++ b/src/interfaces/ecpg/preproc/parse.pl @@ -3,7 +3,7 @@ # parser generater for ecpg version 2 # call with backend parser as stdin # -# Copyright (c) 2007-2016, PostgreSQL Global Development Group +# Copyright (c) 2007-2017, PostgreSQL Global Development Group # # Written by Mike Aubury # Michael Meskes diff --git a/src/interfaces/ecpg/preproc/parser.c b/src/interfaces/ecpg/preproc/parser.c index 40830f6226..0c2705cd2b 100644 --- a/src/interfaces/ecpg/preproc/parser.c +++ b/src/interfaces/ecpg/preproc/parser.c @@ -7,7 +7,7 @@ * need to bother with re-entrant interfaces. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -60,7 +60,7 @@ filtered_base_yylex(void) cur_token = lookahead_token; base_yylval = lookahead_yylval; base_yylloc = lookahead_yylloc; - yytext = lookahead_yytext; + base_yytext = lookahead_yytext; *lookahead_end = lookahead_hold_char; have_lookahead = false; } @@ -93,13 +93,13 @@ filtered_base_yylex(void) * '\0' here, and will undo that when we call it again. We need to redo * it to fully revert the lookahead call for error reporting purposes. */ - lookahead_end = yytext + cur_token_length; + lookahead_end = base_yytext + cur_token_length; Assert(*lookahead_end == '\0'); /* Save and restore lexer output variables around the call */ cur_yylval = base_yylval; cur_yylloc = base_yylloc; - cur_yytext = yytext; + cur_yytext = base_yytext; /* Get next token, saving outputs into lookahead variables */ next_token = base_yylex(); @@ -107,11 +107,11 @@ filtered_base_yylex(void) lookahead_token = next_token; lookahead_yylval = base_yylval; lookahead_yylloc = base_yylloc; - lookahead_yytext = yytext; + lookahead_yytext = base_yytext; base_yylval = cur_yylval; base_yylloc = cur_yylloc; - yytext = cur_yytext; + base_yytext = cur_yytext; /* Now revert the un-truncation of the current token */ lookahead_hold_char = *lookahead_end; diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l index 222049624d..b894a33e53 100644 --- a/src/interfaces/ecpg/preproc/pgc.l +++ b/src/interfaces/ecpg/preproc/pgc.l @@ -7,7 +7,7 @@ * This is a modified version of src/backend/parser/scan.l * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -24,19 +24,10 @@ #include "extern.h" #include "preproc.h" - -/* - * Change symbol names as expected by preproc.y. It'd be better to do this - * with %option prefix="base_yy", but that affects some other names that - * various files expect *not* to be prefixed with "base_". Cleaning it up - * is not worth the trouble right now. - */ -#define yylex base_yylex -#define yylval base_yylval } %{ -extern YYSTYPE yylval; +extern YYSTYPE base_yylval; static int xcdepth = 0; /* depth of nesting in slash-star comments */ static char *dolqstart = NULL; /* current $foo$ quote start string */ @@ -97,6 +88,7 @@ static struct _if_value %option noinput %option noyywrap %option warn +%option prefix="base_yy" %option yylineno @@ -451,7 +443,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ BEGIN(SQL); if (literalbuf[strspn(literalbuf, "01") + 1] != '\0') mmerror(PARSE_ERROR, ET_ERROR, "invalid bit string literal"); - yylval.str = mm_strdup(literalbuf); + base_yylval.str = mm_strdup(literalbuf); return BCONST; } @@ -471,7 +463,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ {quotefail} { yyless(1); BEGIN(SQL); - yylval.str = mm_strdup(literalbuf); + base_yylval.str = mm_strdup(literalbuf); return XCONST; } @@ -514,27 +506,27 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ {quotefail} { yyless(1); BEGIN(state_before); - yylval.str = mm_strdup(literalbuf); + base_yylval.str = mm_strdup(literalbuf); return SCONST; } {quotestop} | {quotefail} { yyless(1); BEGIN(state_before); - yylval.str = mm_strdup(literalbuf); + base_yylval.str = mm_strdup(literalbuf); return ECONST; } {quotestop} | {quotefail} { yyless(1); BEGIN(state_before); - yylval.str = mm_strdup(literalbuf); + base_yylval.str = mm_strdup(literalbuf); return NCONST; } {xusstop} { addlit(yytext, yyleng); BEGIN(state_before); - yylval.str = mm_strdup(literalbuf); + base_yylval.str = mm_strdup(literalbuf); return UCONST; } {xqdouble} { addlitchar('\''); } @@ -575,7 +567,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ addlit(yytext, yyleng); free(dolqstart); BEGIN(SQL); - yylval.str = mm_strdup(literalbuf); + base_yylval.str = mm_strdup(literalbuf); return DOLCONST; } else @@ -612,12 +604,12 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ if (literallen == 0) mmerror(PARSE_ERROR, ET_ERROR, "zero-length delimited identifier"); /* The backend will truncate the identifier here. We do not as it does not change the result. */ - yylval.str = mm_strdup(literalbuf); + base_yylval.str = mm_strdup(literalbuf); return CSTRING; } {xdstop} { BEGIN(state_before); - yylval.str = mm_strdup(literalbuf); + base_yylval.str = mm_strdup(literalbuf); return CSTRING; } {xuistop} { @@ -626,7 +618,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ mmerror(PARSE_ERROR, ET_ERROR, "zero-length delimited identifier"); /* The backend will truncate the identifier here. We do not as it does not change the result. */ addlit(yytext, yyleng); - yylval.str = mm_strdup(literalbuf); + base_yylval.str = mm_strdup(literalbuf); return UIDENT; } {xddouble} { addlitchar('"'); } @@ -725,11 +717,11 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ return yytext[0]; } - yylval.str = mm_strdup(yytext); + base_yylval.str = mm_strdup(yytext); return Op; } {param} { - yylval.ival = atol(yytext+1); + base_yylval.ival = atol(yytext+1); return PARAM; } {integer} { @@ -746,36 +738,36 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ ) { errno = 0; - yylval.str = mm_strdup(yytext); + base_yylval.str = mm_strdup(yytext); return FCONST; } - yylval.ival = val; + base_yylval.ival = val; return ICONST; } {ip} { - yylval.str = mm_strdup(yytext); + base_yylval.str = mm_strdup(yytext); return IP; } {decimal} { - yylval.str = mm_strdup(yytext); + base_yylval.str = mm_strdup(yytext); return FCONST; } {real} { - yylval.str = mm_strdup(yytext); + base_yylval.str = mm_strdup(yytext); return FCONST; } {realfail1} { yyless(yyleng-1); - yylval.str = mm_strdup(yytext); + base_yylval.str = mm_strdup(yytext); return FCONST; } {realfail2} { yyless(yyleng-2); - yylval.str = mm_strdup(yytext); + base_yylval.str = mm_strdup(yytext); return FCONST; } :{identifier}((("->"|\.){identifier})|(\[{array}\]))* { - yylval.str = mm_strdup(yytext+1); + base_yylval.str = mm_strdup(yytext+1); return(CVARIABLE); } {identifier} { @@ -801,7 +793,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ * to do so; that's just another way that ecpg could get * out of step with the backend. */ - yylval.str = mm_strdup(yytext); + base_yylval.str = mm_strdup(yytext); return IDENT; } } @@ -822,11 +814,11 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ char* endptr; errno = 0; - yylval.ival = strtoul((char *)yytext,&endptr,16); + base_yylval.ival = strtoul((char *)yytext,&endptr,16); if (*endptr != '\0' || errno == ERANGE) { errno = 0; - yylval.str = mm_strdup(yytext); + base_yylval.str = mm_strdup(yytext); return SCONST; } return ICONST; @@ -839,7 +831,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ } else { - yylval.str = mm_strdup(yytext); + base_yylval.str = mm_strdup(yytext); return(CPP_LINE); } } @@ -851,12 +843,12 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ } else { - yylval.str = mm_strdup(yytext); + base_yylval.str = mm_strdup(yytext); return(CPP_LINE); } } {cppline} { - yylval.str = mm_strdup(yytext); + base_yylval.str = mm_strdup(yytext); return(CPP_LINE); } {identifier} { @@ -881,7 +873,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ return keyword->value; else { - yylval.str = mm_strdup(yytext); + base_yylval.str = mm_strdup(yytext); return IDENT; } } diff --git a/src/interfaces/ecpg/preproc/variable.c b/src/interfaces/ecpg/preproc/variable.c index bb4b664b85..232b940938 100644 --- a/src/interfaces/ecpg/preproc/variable.c +++ b/src/interfaces/ecpg/preproc/variable.c @@ -452,7 +452,7 @@ dump_variables(struct arguments * list, int mode) dump_variables(list->next, mode); /* Then the current element and its indicator */ - ECPGdump_a_type(yyout, list->variable->name, list->variable->type, list->variable->brace_level, + ECPGdump_a_type(base_yyout, list->variable->name, list->variable->type, list->variable->brace_level, list->indicator->name, list->indicator->type, list->indicator->brace_level, NULL, NULL, str_zero, NULL, NULL); diff --git a/src/interfaces/ecpg/test/compat_informix/test_informix2.pgc b/src/interfaces/ecpg/test/compat_informix/test_informix2.pgc index 69ab99a253..0386093d70 100644 --- a/src/interfaces/ecpg/test/compat_informix/test_informix2.pgc +++ b/src/interfaces/ecpg/test/compat_informix/test_informix2.pgc @@ -113,8 +113,8 @@ int main(void) /* Table "public.history" - Column | Type | Modifiers ---------------+-----------------------------+----------- + Column | Type | Nullable +--------------+-----------------------------+---------- customerid | integer | not null timestamp | timestamp without time zone | not null action_taken | character(5) | not null diff --git a/src/interfaces/ecpg/test/expected/compat_informix-test_informix2.c b/src/interfaces/ecpg/test/expected/compat_informix-test_informix2.c index ba2f75d548..4476130689 100644 --- a/src/interfaces/ecpg/test/expected/compat_informix-test_informix2.c +++ b/src/interfaces/ecpg/test/expected/compat_informix-test_informix2.c @@ -281,8 +281,8 @@ if (sqlca.sqlcode < 0) sqlprint();} /* Table "public.history" - Column | Type | Modifiers ---------------+-----------------------------+----------- + Column | Type | Nullable +--------------+-----------------------------+---------- customerid | integer | not null timestamp | timestamp without time zone | not null action_taken | character(5) | not null diff --git a/src/interfaces/ecpg/test/pg_regress_ecpg.c b/src/interfaces/ecpg/test/pg_regress_ecpg.c index e1dee6d8ee..b3ff76c446 100644 --- a/src/interfaces/ecpg/test/pg_regress_ecpg.c +++ b/src/interfaces/ecpg/test/pg_regress_ecpg.c @@ -8,7 +8,7 @@ * * This code is released under the terms of the PostgreSQL License. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/ecpg/test/pg_regress_ecpg.c diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile index 1b292d2cf2..4b1e552d16 100644 --- a/src/interfaces/libpq/Makefile +++ b/src/interfaces/libpq/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/interfaces/libpq library # -# Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/interfaces/libpq/Makefile @@ -17,7 +17,7 @@ include $(top_builddir)/src/Makefile.global # shared library parameters NAME= pq SO_MAJOR_VERSION= 5 -SO_MINOR_VERSION= 9 +SO_MINOR_VERSION= $(MAJORVERSION) override CPPFLAGS := -DFRONTEND -DUNSAFE_STAT_OK -I$(srcdir) $(CPPFLAGS) -I$(top_builddir)/src/port -I$(top_srcdir)/src/port ifneq ($(PORTNAME), win32) @@ -39,10 +39,10 @@ OBJS += chklocale.o inet_net_ntop.o noblock.o pgstrcasecmp.o pqsignal.o \ thread.o # libpgport C files that are needed if identified by configure OBJS += $(filter crypt.o getaddrinfo.o getpeereid.o inet_aton.o open.o system.o snprintf.o strerror.o strlcpy.o win32error.o win32setlocale.o, $(LIBOBJS)) -# backend/libpq -OBJS += ip.o md5.o -# utils/mb +# src/backend/utils/mb OBJS += encnames.o wchar.o +# src/common +OBJS += ip.o md5.o ifeq ($(with_openssl),yes) OBJS += fe-secure-openssl.o @@ -96,7 +96,7 @@ backend_src = $(top_srcdir)/src/backend chklocale.c crypt.c getaddrinfo.c getpeereid.c inet_aton.c inet_net_ntop.c noblock.c open.c system.c pgsleep.c pgstrcasecmp.c pqsignal.c snprintf.c strerror.c strlcpy.c thread.c win32error.c win32setlocale.c: % : $(top_srcdir)/src/port/% rm -f $@ && $(LN_S) $< . -ip.c md5.c: % : $(backend_src)/libpq/% +ip.c md5.c: % : $(top_srcdir)/src/common/% rm -f $@ && $(LN_S) $< . encnames.c wchar.c: % : $(backend_src)/utils/mb/% diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c index d23726215b..fe1e276f56 100644 --- a/src/interfaces/libpq/fe-auth.c +++ b/src/interfaces/libpq/fe-auth.c @@ -3,7 +3,7 @@ * fe-auth.c * The front-end (client) authorization routines * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -38,9 +38,9 @@ #include #endif +#include "common/md5.h" #include "libpq-fe.h" #include "fe-auth.h" -#include "libpq/md5.h" #ifdef ENABLE_GSS @@ -170,8 +170,9 @@ pg_GSS_startup(PGconn *conn) min_stat; int maxlen; gss_buffer_desc temp_gbuf; + char *host = PQhost(conn); - if (!(conn->pghost && conn->pghost[0] != '\0')) + if (!(host && host[0] != '\0')) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("host name must be specified\n")); @@ -198,7 +199,7 @@ pg_GSS_startup(PGconn *conn) return STATUS_ERROR; } snprintf(temp_gbuf.value, maxlen, "%s@%s", - conn->krbsrvname, conn->pghost); + conn->krbsrvname, host); temp_gbuf.length = strlen(temp_gbuf.value); maj_stat = gss_import_name(&min_stat, &temp_gbuf, @@ -371,6 +372,7 @@ pg_SSPI_startup(PGconn *conn, int use_negotiate) { SECURITY_STATUS r; TimeStamp expire; + char *host = PQhost(conn); conn->sspictx = NULL; @@ -406,19 +408,19 @@ pg_SSPI_startup(PGconn *conn, int use_negotiate) * but not more complex. We can skip the @REALM part, because Windows will * fill that in for us automatically. */ - if (!(conn->pghost && conn->pghost[0] != '\0')) + if (!(host && host[0] != '\0')) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("host name must be specified\n")); return STATUS_ERROR; } - conn->sspitarget = malloc(strlen(conn->krbsrvname) + strlen(conn->pghost) + 2); + conn->sspitarget = malloc(strlen(conn->krbsrvname) + strlen(host) + 2); if (!conn->sspitarget) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); return STATUS_ERROR; } - sprintf(conn->sspitarget, "%s/%s", conn->krbsrvname, conn->pghost); + sprintf(conn->sspitarget, "%s/%s", conn->krbsrvname, host); /* * Indicate that we're in SSPI authentication mode to make sure that @@ -683,20 +685,26 @@ pg_fe_sendauth(AuthRequest areq, PGconn *conn) case AUTH_REQ_MD5: case AUTH_REQ_PASSWORD: - conn->password_needed = true; - if (conn->pgpass == NULL || conn->pgpass[0] == '\0') { - printfPQExpBuffer(&conn->errorMessage, - PQnoPasswordSupplied); - return STATUS_ERROR; - } - if (pg_password_sendauth(conn, conn->pgpass, areq) != STATUS_OK) - { - printfPQExpBuffer(&conn->errorMessage, + char *password = conn->connhost[conn->whichhost].password; + + if (password == NULL) + password = conn->pgpass; + conn->password_needed = true; + if (password == NULL || password[0] == '\0') + { + printfPQExpBuffer(&conn->errorMessage, + PQnoPasswordSupplied); + return STATUS_ERROR; + } + if (pg_password_sendauth(conn, password, areq) != STATUS_OK) + { + printfPQExpBuffer(&conn->errorMessage, "fe_sendauth: error sending password authentication\n"); - return STATUS_ERROR; + return STATUS_ERROR; + } + break; } - break; case AUTH_REQ_SCM_CREDS: if (pg_local_sendauth(conn) != STATUS_OK) diff --git a/src/interfaces/libpq/fe-auth.h b/src/interfaces/libpq/fe-auth.h index 9d11654dd1..0aa6a28768 100644 --- a/src/interfaces/libpq/fe-auth.h +++ b/src/interfaces/libpq/fe-auth.h @@ -4,7 +4,7 @@ * * Definitions for network authentication routines * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/libpq/fe-auth.h diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 76b61bdc25..e13fc98249 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -3,7 +3,7 @@ * fe-connect.c * functions related to setting up a connection to the backend * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -72,7 +72,7 @@ static int ldapServiceLookup(const char *purl, PQconninfoOption *options, PQExpBuffer errorMessage); #endif -#include "libpq/ip.h" +#include "common/ip.h" #include "mb/pg_wchar.h" #ifndef FD_CLOEXEC @@ -108,6 +108,7 @@ static int ldapServiceLookup(const char *purl, PQconninfoOption *options, #define DefaultOption "" #define DefaultAuthtype "" #define DefaultPassword "" +#define DefaultTargetSessionAttrs "any" #ifdef USE_SSL #define DefaultSSLMode "prefer" #else @@ -300,6 +301,11 @@ static const internalPQconninfoOption PQconninfoOptions[] = { "Replication", "D", 5, offsetof(struct pg_conn, replication)}, + {"target_session_attrs", "PGTARGETSESSIONATTRS", + DefaultTargetSessionAttrs, NULL, + "Target-Session-Attrs", "", 11, /* sizeof("read-write") = 11 */ + offsetof(struct pg_conn, target_session_attrs)}, + /* Terminating entry --- MUST BE LAST */ {NULL, NULL, NULL, NULL, NULL, NULL, 0} @@ -336,6 +342,8 @@ static PGconn *makeEmptyPGconn(void); static bool fillPGconn(PGconn *conn, PQconninfoOption *connOptions); static void freePGconn(PGconn *conn); static void closePGconn(PGconn *conn); +static void release_all_addrinfo(PGconn *conn); +static void sendTerminateConn(PGconn *conn); static PQconninfoOption *conninfo_init(PQExpBuffer errorMessage); static PQconninfoOption *parse_connection_string(const char *conninfo, PQExpBuffer errorMessage, bool use_defaults); @@ -770,6 +778,148 @@ connectOptions1(PGconn *conn, const char *conninfo) static bool connectOptions2(PGconn *conn) { + /* + * Allocate memory for details about each host to which we might possibly + * try to connect. If pghostaddr is set, we're only going to try to + * connect to that one particular address. If it's not, we'll use pghost, + * which may contain multiple, comma-separated names. + */ + conn->nconnhost = 1; + conn->whichhost = 0; + if ((conn->pghostaddr == NULL || conn->pghostaddr[0] == '\0') + && conn->pghost != NULL) + { + char *s; + + for (s = conn->pghost; *s != '\0'; ++s) + if (*s == ',') + conn->nconnhost++; + } + 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 details for each one. + */ + if (conn->pghostaddr != NULL && conn->pghostaddr[0] != '\0') + { + conn->connhost[0].host = strdup(conn->pghostaddr); + if (conn->connhost[0].host == NULL) + goto oom_error; + conn->connhost[0].type = CHT_HOST_ADDRESS; + } + else if (conn->pghost != NULL && conn->pghost[0] != '\0') + { + int i = 0; + char *s = conn->pghost; + + while (1) + { + char *e = s; + + /* + * Search for the end of the current hostname; a comma or + * end-of-string acts as a terminator. + */ + while (*e != '\0' && *e != ',') + ++e; + + /* Copy the hostname whose bounds we just identified. */ + conn->connhost[i].host = + (char *) malloc(sizeof(char) * (e - s + 1)); + if (conn->connhost[i].host == NULL) + goto oom_error; + memcpy(conn->connhost[i].host, s, e - s); + conn->connhost[i].host[e - s] = '\0'; + + /* Identify the type of host. */ + conn->connhost[i].type = CHT_HOST_NAME; +#ifdef HAVE_UNIX_SOCKETS + if (is_absolute_path(conn->connhost[i].host)) + conn->connhost[i].type = CHT_UNIX_SOCKET; +#endif + + /* Prepare to find the next host (if any). */ + if (*e == '\0') + break; + s = e + 1; + i++; + } + } + else + { +#ifdef HAVE_UNIX_SOCKETS + conn->connhost[0].host = strdup(DEFAULT_PGSOCKET_DIR); + conn->connhost[0].type = CHT_UNIX_SOCKET; +#else + conn->connhost[0].host = strdup(DefaultHost); + conn->connhost[0].type = CHT_HOST_NAME; +#endif + if (conn->connhost[0].host == NULL) + goto oom_error; + } + + /* + * Next, work out the port number corresponding to each host name. + */ + if (conn->pgport != NULL && conn->pgport[0] != '\0') + { + int i = 0; + char *s = conn->pgport; + int nports = 1; + + for (i = 0; i < conn->nconnhost; ++i) + { + char *e = s; + + /* Search for the end of the current port number. */ + while (*e != '\0' && *e != ',') + ++e; + + /* + * If we found a port number of non-zero length, copy it. + * Otherwise, insert the default port number. + */ + if (e > s) + { + conn->connhost[i].port = + (char *) malloc(sizeof(char) * (e - s + 1)); + if (conn->connhost[i].port == NULL) + goto oom_error; + memcpy(conn->connhost[i].port, s, e - s); + conn->connhost[i].port[e - s] = '\0'; + } + + /* + * Move on to the next port number, unless there are no more. + * (If only one part number is specified, we reuse it for every + * host.) + */ + if (*e != '\0') + { + s = e + 1; + ++nports; + } + } + + /* + * If multiple ports were specified, there must be exactly as many + * ports as there were hosts. Otherwise, we do not know how to match + * them up. + */ + if (nports != 1 && nports != conn->nconnhost) + { + conn->status = CONNECTION_BAD; + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("could not match %d port numbers to %d hosts\n"), + nports, 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 @@ -800,33 +950,27 @@ connectOptions2(PGconn *conn) } /* - * Supply default password if none given + * Supply default password if none given. Note that the password might + * be different for each host/port pair. */ if (conn->pgpass == NULL || conn->pgpass[0] == '\0') { + int i; + if (conn->pgpass) free(conn->pgpass); - conn->pgpass = PasswordFromFile(conn->pghost, conn->pgport, - conn->dbName, conn->pguser); - if (conn->pgpass == NULL) + conn->pgpass = strdup(DefaultPassword); + if (!conn->pgpass) + goto oom_error; + for (i = 0; i < conn->nconnhost; ++i) { - conn->pgpass = strdup(DefaultPassword); - if (!conn->pgpass) - goto oom_error; + conn->connhost[i].password = + PasswordFromFile(conn->connhost[i].host, + conn->connhost[i].port, + conn->dbName, conn->pguser); + if (conn->connhost[i].password != NULL) + conn->dot_pgpass_used = true; } - else - conn->dot_pgpass_used = true; - } - - /* - * Allow unix socket specification in the host name - */ - if (conn->pghost && is_absolute_path(conn->pghost)) - { - if (conn->pgunixsocket) - free(conn->pgunixsocket); - conn->pgunixsocket = conn->pghost; - conn->pghost = NULL; } /* @@ -889,6 +1033,22 @@ connectOptions2(PGconn *conn) goto oom_error; } + /* + * Validate target_session_attrs option. + */ + if (conn->target_session_attrs) + { + if (strcmp(conn->target_session_attrs, "any") != 0 + && strcmp(conn->target_session_attrs, "read-write") != 0) + { + conn->status = CONNECTION_BAD; + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("invalid target_session_attrs value: \"%s\"\n"), + conn->target_session_attrs); + return false; + } + } + /* * 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 @@ -1142,6 +1302,7 @@ connectFailureMessage(PGconn *conn, int errorno) { char host_addr[NI_MAXHOST]; const char *displayed_host; + const char *displayed_port; struct sockaddr_storage *addr = &conn->raddr.addr; /* @@ -1171,12 +1332,11 @@ connectFailureMessage(PGconn *conn, int errorno) else strcpy(host_addr, "???"); - if (conn->pghostaddr && conn->pghostaddr[0] != '\0') - displayed_host = conn->pghostaddr; - else if (conn->pghost && conn->pghost[0] != '\0') - displayed_host = conn->pghost; - else - displayed_host = DefaultHost; + /* To which host and port were we actually connecting? */ + 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 @@ -1192,7 +1352,7 @@ connectFailureMessage(PGconn *conn, int errorno) SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)), displayed_host, host_addr, - conn->pgport); + displayed_port); else appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not connect to server: %s\n" @@ -1200,7 +1360,7 @@ connectFailureMessage(PGconn *conn, int errorno) "\tTCP/IP connections on port %s?\n"), SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)), displayed_host, - conn->pgport); + displayed_port); } } @@ -1252,7 +1412,7 @@ setKeepalivesIdle(PGconn *conn) } #else #ifdef TCP_KEEPALIVE - /* Darwin uses TCP_KEEPALIVE rather than TCP_KEEPIDLE */ + /* macOS uses TCP_KEEPALIVE rather than TCP_KEEPIDLE */ if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPALIVE, (char *) &idle, sizeof(idle)) < 0) { @@ -1390,12 +1550,9 @@ setKeepalivesWin32(PGconn *conn) static int connectDBStart(PGconn *conn) { - int portnum; char portstr[MAXPGPATH]; - struct addrinfo *addrs = NULL; - struct addrinfo hint; - const char *node; int ret; + int i; if (!conn) return 0; @@ -1408,83 +1565,86 @@ connectDBStart(PGconn *conn) conn->outCount = 0; /* - * Determine the parameters to pass to pg_getaddrinfo_all. + * Look up socket addresses for each possible host using + * pg_getaddrinfo_all. */ + for (i = 0; i < conn->nconnhost; ++i) + { + pg_conn_host *ch = &conn->connhost[i]; + char *node = ch->host; + struct addrinfo hint; + int thisport; - /* Initialize hint structure */ - MemSet(&hint, 0, sizeof(hint)); - hint.ai_socktype = SOCK_STREAM; - hint.ai_family = AF_UNSPEC; + /* Initialize hint structure */ + MemSet(&hint, 0, sizeof(hint)); + hint.ai_socktype = SOCK_STREAM; + hint.ai_family = AF_UNSPEC; - /* Set up port number as a string */ - if (conn->pgport != NULL && conn->pgport[0] != '\0') - { - portnum = atoi(conn->pgport); - if (portnum < 1 || portnum > 65535) + /* Figure out the port number we're going to use. */ + if (ch->port == NULL) + thisport = DEF_PGPORT; + else { - appendPQExpBuffer(&conn->errorMessage, + thisport = atoi(ch->port); + if (thisport < 1 || thisport > 65535) + { + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid port number: \"%s\"\n"), - conn->pgport); - conn->options_valid = false; - goto connect_errReturn; + ch->port); + conn->options_valid = false; + goto connect_errReturn; + } } - } - else - portnum = DEF_PGPORT; - snprintf(portstr, sizeof(portstr), "%d", portnum); + snprintf(portstr, sizeof(portstr), "%d", thisport); - if (conn->pghostaddr != NULL && conn->pghostaddr[0] != '\0') - { - /* Using pghostaddr avoids a hostname lookup */ - node = conn->pghostaddr; - hint.ai_family = AF_UNSPEC; - hint.ai_flags = AI_NUMERICHOST; - } - else if (conn->pghost != NULL && conn->pghost[0] != '\0') - { - /* Using pghost, so we have to look-up the hostname */ - node = conn->pghost; - hint.ai_family = AF_UNSPEC; - } - else - { + /* Set up for name resolution. */ + switch (ch->type) + { + case CHT_HOST_NAME: + break; + case CHT_HOST_ADDRESS: + hint.ai_flags = AI_NUMERICHOST; + break; + case CHT_UNIX_SOCKET: #ifdef HAVE_UNIX_SOCKETS - /* pghostaddr and pghost are NULL, so use Unix domain socket */ - node = NULL; - hint.ai_family = AF_UNIX; - UNIXSOCK_PATH(portstr, portnum, conn->pgunixsocket); - if (strlen(portstr) >= UNIXSOCK_PATH_BUFLEN) + node = NULL; + hint.ai_family = AF_UNIX; + UNIXSOCK_PATH(portstr, thisport, ch->host); + if (strlen(portstr) >= UNIXSOCK_PATH_BUFLEN) + { + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("Unix-domain socket path \"%s\" is too long (maximum %d bytes)\n"), + portstr, + (int) (UNIXSOCK_PATH_BUFLEN - 1)); + conn->options_valid = false; + goto connect_errReturn; + } +#else + Assert(false); +#endif + break; + } + + /* Use pg_getaddrinfo_all() to resolve the address */ + ret = pg_getaddrinfo_all(node, portstr, &hint, &ch->addrlist); + if (ret || !ch->addrlist) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("Unix-domain socket path \"%s\" is too long (maximum %d bytes)\n"), - portstr, - (int) (UNIXSOCK_PATH_BUFLEN - 1)); + if (node) + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("could not translate host name \"%s\" to address: %s\n"), + node, gai_strerror(ret)); + else + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("could not translate Unix-domain socket path \"%s\" to address: %s\n"), + portstr, gai_strerror(ret)); + if (ch->addrlist) + { + pg_freeaddrinfo_all(hint.ai_family, ch->addrlist); + ch->addrlist = NULL; + } conn->options_valid = false; goto connect_errReturn; } -#else - /* Without Unix sockets, default to localhost instead */ - node = DefaultHost; - hint.ai_family = AF_UNSPEC; -#endif /* HAVE_UNIX_SOCKETS */ - } - - /* Use pg_getaddrinfo_all() to resolve the address */ - ret = pg_getaddrinfo_all(node, portstr, &hint, &addrs); - if (ret || !addrs) - { - if (node) - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not translate host name \"%s\" to address: %s\n"), - node, gai_strerror(ret)); - else - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not translate Unix-domain socket path \"%s\" to address: %s\n"), - portstr, gai_strerror(ret)); - if (addrs) - pg_freeaddrinfo_all(hint.ai_family, addrs); - conn->options_valid = false; - goto connect_errReturn; } #ifdef USE_SSL @@ -1498,9 +1658,8 @@ connectDBStart(PGconn *conn) /* * Set up to try to connect, with protocol 3.0 as the first attempt. */ - conn->addrlist = addrs; - conn->addr_cur = addrs; - conn->addrlist_family = hint.ai_family; + conn->whichhost = 0; + conn->addr_cur = conn->connhost[0].addrlist; conn->pversion = PG_PROTOCOL(3, 0); conn->send_appname = true; conn->status = CONNECTION_NEEDED; @@ -1603,6 +1762,39 @@ connectDBComplete(PGconn *conn) } } +/* + * This subroutine saves conn->errorMessage, which will be restored back by + * restoreErrorMessage subroutine. + */ +static bool +saveErrorMessage(PGconn *conn, PQExpBuffer savedMessage) +{ + initPQExpBuffer(savedMessage); + if (PQExpBufferBroken(savedMessage)) + { + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("out of memory\n")); + return false; + } + + appendPQExpBufferStr(savedMessage, + conn->errorMessage.data); + resetPQExpBuffer(&conn->errorMessage); + return true; +} + +/* + * Restores saved error messages back to conn->errorMessage. + */ +static void +restoreErrorMessage(PGconn *conn, PQExpBuffer savedMessage) +{ + appendPQExpBufferStr(savedMessage, conn->errorMessage.data); + resetPQExpBuffer(&conn->errorMessage); + appendPQExpBufferStr(&conn->errorMessage, savedMessage->data); + termPQExpBuffer(savedMessage); +} + /* ---------------- * PQconnectPoll * @@ -1636,6 +1828,7 @@ PQconnectPoll(PGconn *conn) PGresult *res; char sebuf[256]; int optval; + PQExpBufferData savedMessage; if (conn == NULL) return PGRES_POLLING_FAILED; @@ -1679,6 +1872,7 @@ PQconnectPoll(PGconn *conn) /* Special cases: proceed without waiting. */ case CONNECTION_SSL_STARTUP: case CONNECTION_NEEDED: + case CONNECTION_CHECK_WRITABLE: break; default: @@ -1702,11 +1896,27 @@ PQconnectPoll(PGconn *conn) * returned by pg_getaddrinfo_all(). conn->addr_cur is the * next one to try. We fail when we run out of addresses. */ - while (conn->addr_cur != NULL) + for (;;) { - struct addrinfo *addr_cur = conn->addr_cur; + struct addrinfo *addr_cur; + + /* + * Advance to next possible host, if we've tried all of + * the addresses for the current host. + */ + if (conn->addr_cur == NULL) + { + if (++conn->whichhost >= conn->nconnhost) + { + conn->whichhost = 0; + break; + } + conn->addr_cur = + conn->connhost[conn->whichhost].addrlist; + } /* Remember current address for possible error msg */ + addr_cur = conn->addr_cur; memcpy(&conn->raddr.addr, addr_cur->ai_addr, addr_cur->ai_addrlen); conn->raddr.salen = addr_cur->ai_addrlen; @@ -1718,7 +1928,8 @@ PQconnectPoll(PGconn *conn) * ignore socket() failure if we have more addresses * to try */ - if (addr_cur->ai_next != NULL) + if (addr_cur->ai_next != NULL || + conn->whichhost + 1 < conn->nconnhost) { conn->addr_cur = addr_cur->ai_next; continue; @@ -1944,7 +2155,8 @@ PQconnectPoll(PGconn *conn) * If more addresses remain, keep trying, just as in the * case where connect() returned failure immediately. */ - if (conn->addr_cur->ai_next != NULL) + if (conn->addr_cur->ai_next != NULL || + conn->whichhost + 1 < conn->nconnhost) { conn->addr_cur = conn->addr_cur->ai_next; conn->status = CONNECTION_NEEDED; @@ -2599,11 +2811,6 @@ PQconnectPoll(PGconn *conn) goto error_return; } - /* We can release the address list now. */ - pg_freeaddrinfo_all(conn->addrlist_family, conn->addrlist); - conn->addrlist = NULL; - conn->addr_cur = NULL; - /* Fire up post-connection housekeeping if needed */ if (PG_PROTOCOL_MAJOR(conn->pversion) < 3) { @@ -2613,7 +2820,39 @@ PQconnectPoll(PGconn *conn) return PGRES_POLLING_WRITING; } - /* Otherwise, we are open for business! */ + /* + * If a read-write connection is required, see if we have one. + */ + if (conn->target_session_attrs != NULL && + strcmp(conn->target_session_attrs, "read-write") == 0) + { + /* + * We are yet to make a connection. Save all existing error + * messages until we make a successful connection state. + * This is important because PQsendQuery is going to reset + * conn->errorMessage and we will loose error messages + * related to previous hosts we have tried to connect and + * failed. + */ + if (!saveErrorMessage(conn, &savedMessage)) + goto error_return; + + conn->status = CONNECTION_OK; + if (!PQsendQuery(conn, + "show transaction_read_only")) + { + restoreErrorMessage(conn, &savedMessage); + goto error_return; + } + conn->status = CONNECTION_CHECK_WRITABLE; + restoreErrorMessage(conn, &savedMessage); + return PGRES_POLLING_READING; + } + + /* We can release the address lists now. */ + release_all_addrinfo(conn); + + /* We are open for business! */ conn->status = CONNECTION_OK; return PGRES_POLLING_OK; } @@ -2645,10 +2884,126 @@ PQconnectPoll(PGconn *conn) goto error_return; } + /* + * If a read-write connection is requisted check for same. + */ + if (conn->target_session_attrs != NULL && + strcmp(conn->target_session_attrs, "read-write") == 0) + { + if (!saveErrorMessage(conn, &savedMessage)) + goto error_return; + + conn->status = CONNECTION_OK; + if (!PQsendQuery(conn, + "show transaction_read_only")) + { + restoreErrorMessage(conn, &savedMessage); + goto error_return; + } + conn->status = CONNECTION_CHECK_WRITABLE; + restoreErrorMessage(conn, &savedMessage); + return PGRES_POLLING_READING; + } + + /* We can release the address lists now. */ + release_all_addrinfo(conn); + /* We are open for business! */ conn->status = CONNECTION_OK; return PGRES_POLLING_OK; + case CONNECTION_CHECK_WRITABLE: + { + if (!saveErrorMessage(conn, &savedMessage)) + goto error_return; + + conn->status = CONNECTION_OK; + if (!PQconsumeInput(conn)) + { + restoreErrorMessage(conn, &savedMessage); + goto error_return; + } + + if (PQisBusy(conn)) + { + conn->status = CONNECTION_CHECK_WRITABLE; + restoreErrorMessage(conn, &savedMessage); + return PGRES_POLLING_READING; + } + + res = PQgetResult(conn); + if (res && (PQresultStatus(res) == PGRES_TUPLES_OK) && + PQntuples(res) == 1) + { + char *val; + + val = PQgetvalue(res, 0, 0); + if (strncmp(val, "on", 2) == 0) + { + PQclear(res); + restoreErrorMessage(conn, &savedMessage); + + /* Not writable; close connection. */ + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("could not make a writable " + "connection to server " + "\"%s:%s\"\n"), + conn->connhost[conn->whichhost].host, + conn->connhost[conn->whichhost].port); + conn->status = CONNECTION_OK; + sendTerminateConn(conn); + pqDropConnection(conn, true); + + /* Skip any remaining addresses for this host. */ + conn->addr_cur = NULL; + if (conn->whichhost + 1 < conn->nconnhost) + { + conn->status = CONNECTION_NEEDED; + goto keep_going; + } + + /* No more addresses to try. So we fail. */ + goto error_return; + } + PQclear(res); + termPQExpBuffer(&savedMessage); + + /* We can release the address lists now. */ + release_all_addrinfo(conn); + + /* We are open for business! */ + conn->status = CONNECTION_OK; + return PGRES_POLLING_OK; + } + + /* + * Something went wrong with "show transaction_read_only". We + * should try next addresses. + */ + if (res) + PQclear(res); + restoreErrorMessage(conn, &savedMessage); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("test \"show transaction_read_only\" failed " + " on \"%s:%s\" \n"), + conn->connhost[conn->whichhost].host, + conn->connhost[conn->whichhost].port); + conn->status = CONNECTION_OK; + sendTerminateConn(conn); + pqDropConnection(conn, true); + + if (conn->addr_cur->ai_next != NULL || + conn->whichhost + 1 < conn->nconnhost) + { + conn->addr_cur = conn->addr_cur->ai_next; + conn->status = CONNECTION_NEEDED; + goto keep_going; + } + + /* No more addresses to try. So we fail. */ + goto error_return; + } + default: appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid connection state %d, " @@ -2858,6 +3213,21 @@ freePGconn(PGconn *conn) free(conn->events[i].name); } + /* clean up pg_conn_host structures */ + if (conn->connhost != NULL) + { + for (i = 0; i < conn->nconnhost; ++i) + { + if (conn->connhost[i].host != NULL) + free(conn->connhost[i].host); + if (conn->connhost[i].port != NULL) + free(conn->connhost[i].port); + if (conn->connhost[i].password != NULL) + free(conn->connhost[i].password); + } + free(conn->connhost); + } + if (conn->client_encoding_initial) free(conn->client_encoding_initial); if (conn->events) @@ -2868,8 +3238,6 @@ freePGconn(PGconn *conn) free(conn->pghostaddr); if (conn->pgport) free(conn->pgport); - if (conn->pgunixsocket) - free(conn->pgunixsocket); if (conn->pgtty) free(conn->pgtty); if (conn->connect_timeout) @@ -2927,6 +3295,8 @@ freePGconn(PGconn *conn) free(conn->outBuffer); if (conn->rowBuf) free(conn->rowBuf); + if (conn->target_session_attrs) + free(conn->target_session_attrs); termPQExpBuffer(&conn->errorMessage); termPQExpBuffer(&conn->workBuffer); @@ -2938,19 +3308,41 @@ freePGconn(PGconn *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()). + * release_all_addrinfo + * - free addrinfo of all hostconn elements. */ + static void -closePGconn(PGconn *conn) +release_all_addrinfo(PGconn *conn) { - PGnotify *notify; - pgParameterStatus *pstatus; + if (conn->connhost != NULL) + { + int i; + + for (i = 0; i < conn->nconnhost; ++i) + { + int family = AF_UNSPEC; + +#ifdef HAVE_UNIX_SOCKETS + if (conn->connhost[i].type == CHT_UNIX_SOCKET) + family = AF_UNIX; +#endif + + pg_freeaddrinfo_all(family, + conn->connhost[i].addrlist); + conn->connhost[i].addrlist = NULL; + } + } + conn->addr_cur = 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. @@ -2965,6 +3357,23 @@ closePGconn(PGconn *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) +{ + PGnotify *notify; + pgParameterStatus *pstatus; + + sendTerminateConn(conn); /* * Must reset the blocking status so a possible reconnect will work. @@ -2983,9 +3392,8 @@ closePGconn(PGconn *conn) conn->asyncStatus = PGASYNC_IDLE; pqClearAsyncResult(conn); /* deallocate result */ resetPQExpBuffer(&conn->errorMessage); - pg_freeaddrinfo_all(conn->addrlist_family, conn->addrlist); - conn->addrlist = NULL; - conn->addr_cur = NULL; + release_all_addrinfo(conn); + notify = conn->notifyHead; while (notify != NULL) { @@ -4720,7 +5128,10 @@ conninfo_uri_parse(const char *uri, PQExpBuffer errorMessage, * 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. + * 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). */ @@ -4730,12 +5141,23 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri, { int prefix_len; char *p; - char *buf; + 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)) + { + printfPQExpBuffer(errorMessage, + libpq_gettext("out of memory\n")); + goto cleanup; + } /* need a modifiable copy of the input URI */ buf = strdup(uri); @@ -4743,7 +5165,7 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri, { printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); - return false; + goto cleanup; } start = buf; @@ -4810,85 +5232,104 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri, } /* - * "p" has been incremented past optional URI credential information at - * this point and now points at the "netloc" part of the URI. - * - * Look for IPv6 address. + * 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". */ - if (*p == '[') + for (;;) { - host = ++p; - while (*p && *p != ']') - ++p; - if (!*p) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("end of string reached when looking for matching \"]\" in IPv6 host address in URI: \"%s\"\n"), - uri); - goto cleanup; - } - if (p == host) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("IPv6 host address may not be empty in URI: \"%s\"\n"), - uri); - goto cleanup; - } - - /* Cut off the bracket and advance */ - *(p++) = '\0'; - /* - * The address may be followed by a port specifier or a slash or a - * query. + * Look for IPv6 address. */ - if (*p && *p != ':' && *p != '/' && *p != '?') + if (*p == '[') { - printfPQExpBuffer(errorMessage, - libpq_gettext("unexpected character \"%c\" at position %d in URI (expected \":\" or \"/\"): \"%s\"\n"), - *p, (int) (p - buf + 1), uri); - goto cleanup; + host = ++p; + while (*p && *p != ']') + ++p; + if (!*p) + { + printfPQExpBuffer(errorMessage, + libpq_gettext("end of string reached when looking for matching \"]\" in IPv6 host address in URI: \"%s\"\n"), + uri); + goto cleanup; + } + if (p == host) + { + printfPQExpBuffer(errorMessage, + libpq_gettext("IPv6 host address may not be empty in URI: \"%s\"\n"), + uri); + goto cleanup; + } + + /* Cut off the bracket and advance */ + *(p++) = '\0'; + + /* + * The address may be followed by a port specifier or a slash or a + * query or a separator comma. + */ + if (*p && *p != ':' && *p != '/' && *p != '?' && *p != ',') + { + printfPQExpBuffer(errorMessage, + libpq_gettext("unexpected character \"%c\" at position %d in URI (expected \":\" or \"/\"): \"%s\"\n"), + *p, (int) (p - buf + 1), uri); + goto cleanup; + } } - } - else - { - /* not an IPv6 address: DNS-named or IPv4 netloc */ - host = p; + else + { + /* not an IPv6 address: DNS-named or IPv4 netloc */ + host = p; - /* - * Look for port specifier (colon) or end of host specifier (slash), - * or query (question mark). - */ - while (*p && *p != ':' && *p != '/' && *p != '?') - ++p; - } + /* + * 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'; + /* Save the hostname terminator before we null it */ + prevchar = *p; + *p = '\0'; - if (*host && - !conninfo_storeval(options, "host", host, - errorMessage, false, true)) - goto cleanup; + appendPQExpBufferStr(&hostbuf, host); + if (prevchar == ':') + { + const char *port = ++p; /* advance past host terminator */ - if (prevchar == ':') - { - const char *port = ++p; /* advance past host terminator */ + while (*p && *p != '/' && *p != '?' && *p != ',') + ++p; - while (*p && *p != '/' && *p != '?') - ++p; + prevchar = *p; + *p = '\0'; - prevchar = *p; - *p = '\0'; + appendPQExpBufferStr(&portbuf, port); + } - if (*port && - !conninfo_storeval(options, "port", port, - errorMessage, false, true)) - goto cleanup; + if (prevchar != ',') + break; + ++p; /* advance past comma separator */ + appendPQExpBufferStr(&hostbuf, ","); + appendPQExpBufferStr(&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 */ @@ -4923,7 +5364,10 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri, retval = true; cleanup: - free(buf); + termPQExpBuffer(&hostbuf); + termPQExpBuffer(&portbuf); + if (buf) + free(buf); return retval; } @@ -5342,9 +5786,15 @@ PQuser(const PGconn *conn) char * PQpass(const PGconn *conn) { + char *password = NULL; + if (!conn) return NULL; - return conn->pgpass; + if (conn->connhost != NULL) + password = conn->connhost[conn->whichhost].password; + if (password == NULL) + password = conn->pgpass; + return password; } char * @@ -5352,15 +5802,15 @@ PQhost(const PGconn *conn) { if (!conn) return NULL; - if (conn->pghost != NULL && conn->pghost[0] != '\0') + if (conn->connhost != NULL && + conn->connhost[conn->whichhost].type != CHT_HOST_ADDRESS) + return conn->connhost[conn->whichhost].host; + else if (conn->pghost != NULL && conn->pghost[0] != '\0') return conn->pghost; else { #ifdef HAVE_UNIX_SOCKETS - if (conn->pgunixsocket != NULL && conn->pgunixsocket[0] != '\0') - return conn->pgunixsocket; - else - return DEFAULT_PGSOCKET_DIR; + return DEFAULT_PGSOCKET_DIR; #else return DefaultHost; #endif @@ -5372,6 +5822,8 @@ PQport(const PGconn *conn) { if (!conn) return NULL; + if (conn->connhost != NULL) + return conn->connhost[conn->whichhost].port; return conn->pgport; } @@ -5481,10 +5933,13 @@ PQbackendPID(const PGconn *conn) int PQconnectionNeedsPassword(const PGconn *conn) { + char *password; + if (!conn) return false; + password = PQpass(conn); if (conn->password_needed && - (conn->pgpass == NULL || conn->pgpass[0] == '\0')) + (password == NULL || password[0] == '\0')) return true; else return false; @@ -5783,18 +6238,26 @@ PasswordFromFile(char *hostname, char *port, char *dbname, char *username) break; len = strlen(buf); - if (len == 0) - continue; /* Remove trailing newline */ - if (buf[len - 1] == '\n') - buf[len - 1] = 0; + if (len > 0 && buf[len - 1] == '\n') + { + buf[--len] = '\0'; + /* Handle DOS-style line endings, too, even when not on Windows */ + if (len > 0 && buf[len - 1] == '\r') + buf[--len] = '\0'; + } + + if (len == 0) + continue; if ((t = pwdfMatchesString(t, hostname)) == NULL || (t = pwdfMatchesString(t, port)) == NULL || (t = pwdfMatchesString(t, dbname)) == NULL || (t = pwdfMatchesString(t, username)) == NULL) continue; + + /* Found a match. */ ret = strdup(t); fclose(fp); diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index d1b91c841c..b5518757ec 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -3,7 +3,7 @@ * fe-exec.c * functions related to sending a query down to the backend * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -824,6 +824,7 @@ pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt,...) */ 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? */ /* @@ -1385,8 +1386,7 @@ PQsendQueryStart(PGconn *conn) } /* initialize async result-accumulation state */ - conn->result = NULL; - conn->next_result = NULL; + pqClearAsyncResult(conn); /* reset single-row processing mode */ conn->singleRowMode = false; diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c index 3b08768d98..71c9ff650e 100644 --- a/src/interfaces/libpq/fe-lobj.c +++ b/src/interfaces/libpq/fe-lobj.c @@ -3,7 +3,7 @@ * fe-lobj.c * Front-end large object interface * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c index 32da8ca461..ba7400b425 100644 --- a/src/interfaces/libpq/fe-misc.c +++ b/src/interfaces/libpq/fe-misc.c @@ -19,7 +19,7 @@ * routines. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/interfaces/libpq/fe-print.c b/src/interfaces/libpq/fe-print.c index c33dc42a83..fa974540f5 100644 --- a/src/interfaces/libpq/fe-print.c +++ b/src/interfaces/libpq/fe-print.c @@ -3,7 +3,7 @@ * fe-print.c * functions for pretty-printing query results * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, 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 @@ -166,8 +166,9 @@ PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po) screen_size.ws_col = 80; #endif pagerenv = getenv("PAGER"); + /* if PAGER is unset, empty or all-white-space, don't use pager */ if (pagerenv != NULL && - pagerenv[0] != '\0' && + strspn(pagerenv, " \t\r\n") != strlen(pagerenv) && !po->html3 && ((po->expanded && nTups * (nFields + 1) >= screen_size.ws_row) || diff --git a/src/interfaces/libpq/fe-protocol2.c b/src/interfaces/libpq/fe-protocol2.c index f1b90f32d4..3b0500fa52 100644 --- a/src/interfaces/libpq/fe-protocol2.c +++ b/src/interfaces/libpq/fe-protocol2.c @@ -3,7 +3,7 @@ * fe-protocol2.c * functions that are specific to frontend/backend protocol version 2 * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c index a8a987aa92..53776e27b5 100644 --- a/src/interfaces/libpq/fe-protocol3.c +++ b/src/interfaces/libpq/fe-protocol3.c @@ -3,7 +3,7 @@ * fe-protocol3.c * functions that are specific to frontend/backend protocol version 3 * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c index f6ce1c7a13..101d63899c 100644 --- a/src/interfaces/libpq/fe-secure-openssl.c +++ b/src/interfaces/libpq/fe-secure-openssl.c @@ -4,7 +4,7 @@ * OpenSSL support * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -54,9 +54,7 @@ #endif #include -#if (SSLEAY_VERSION_NUMBER >= 0x00907000L) #include -#endif #ifdef USE_SSL_ENGINE #include #endif @@ -82,12 +80,7 @@ static int my_SSL_set_fd(PGconn *conn, int fd); static bool pq_init_ssl_lib = true; static bool pq_init_crypto_lib = true; -/* - * SSL_context is currently shared between threads and therefore we need to be - * careful to lock around any usage of it when providing thread safety. - * ssl_config_mutex is the mutex that we use to protect it. - */ -static SSL_CTX *SSL_context = NULL; +static bool ssl_lib_initialized = false; #ifdef ENABLE_THREAD_SAFETY static long ssl_open_connections = 0; @@ -135,44 +128,9 @@ pgtls_open_client(PGconn *conn) /* First time through? */ if (conn->ssl == NULL) { -#ifdef ENABLE_THREAD_SAFETY - int rc; -#endif - -#ifdef ENABLE_THREAD_SAFETY - if ((rc = pthread_mutex_lock(&ssl_config_mutex))) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not acquire mutex: %s\n"), strerror(rc)); - return PGRES_POLLING_FAILED; - } -#endif - /* Create a connection-specific SSL object */ - 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()); - - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not establish SSL connection: %s\n"), - err); - SSLerrfree(err); -#ifdef ENABLE_THREAD_SAFETY - pthread_mutex_unlock(&ssl_config_mutex); -#endif - pgtls_close(conn); - - return PGRES_POLLING_FAILED; - } - conn->ssl_in_use = true; - -#ifdef ENABLE_THREAD_SAFETY - pthread_mutex_unlock(&ssl_config_mutex); -#endif - /* - * Load client certificate, private key, and trusted CA certs. + * Create a connection-specific SSL object, and load client certificate, + * private key, and trusted CA certs. */ if (initialize_SSL(conn) != 0) { @@ -508,7 +466,6 @@ wildcard_certificate_match(const char *pattern, const char *string) return 1; } - /* * Check if a name from a server's certificate matches the peer's hostname. * @@ -524,8 +481,9 @@ verify_peer_name_matches_certificate_name(PGconn *conn, ASN1_STRING *name_entry, { int len; char *name; - unsigned char *namedata; + const unsigned char *namedata; int result; + char *host = PQhost(conn); *store_name = NULL; @@ -543,7 +501,11 @@ verify_peer_name_matches_certificate_name(PGconn *conn, ASN1_STRING *name_entry, * There is no guarantee the string returned from the certificate is * NULL-terminated, so make a copy that is. */ +#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); name = malloc(len + 1); if (name == NULL) @@ -567,12 +529,12 @@ verify_peer_name_matches_certificate_name(PGconn *conn, ASN1_STRING *name_entry, return -1; } - if (pg_strcasecmp(name, conn->pghost) == 0) + if (pg_strcasecmp(name, host) == 0) { /* Exact name match */ result = 1; } - else if (wildcard_certificate_match(name, conn->pghost)) + else if (wildcard_certificate_match(name, host)) { /* Matched wildcard name */ result = 1; @@ -602,6 +564,7 @@ verify_peer_name_matches_certificate(PGconn *conn) STACK_OF(GENERAL_NAME) *peer_san; int i; int rc; + char *host = PQhost(conn); /* * If told not to verify the peer name, don't do it. Return true @@ -611,7 +574,7 @@ verify_peer_name_matches_certificate(PGconn *conn) return true; /* Check that we have a hostname to compare with. */ - if (!(conn->pghost && conn->pghost[0] != '\0')) + if (!(host && host[0] != '\0')) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("host name must be specified for a verified SSL connection\n")); @@ -709,13 +672,13 @@ verify_peer_name_matches_certificate(PGconn *conn) libpq_ngettext("server certificate for \"%s\" (and %d other name) does not match host name \"%s\"\n", "server certificate for \"%s\" (and %d other names) does not match host name \"%s\"\n", names_examined - 1), - first_name, names_examined - 1, conn->pghost); + first_name, names_examined - 1, host); } else if (names_examined == 1) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("server certificate for \"%s\" does not match host name \"%s\"\n"), - first_name, conn->pghost); + first_name, host); } else { @@ -731,9 +694,13 @@ verify_peer_name_matches_certificate(PGconn *conn) return found_match && !got_error; } -#ifdef ENABLE_THREAD_SAFETY +#if defined(ENABLE_THREAD_SAFETY) && defined(HAVE_CRYPTO_LOCK) /* - * Callback functions for OpenSSL internal locking + * 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 @@ -763,11 +730,10 @@ pq_lockingcallback(int mode, int n, const char *file, int line) PGTHREAD_ERROR("failed to unlock mutex"); } } -#endif /* ENABLE_THREAD_SAFETY */ +#endif /* ENABLE_THREAD_SAFETY && HAVE_CRYPTO_LOCK */ /* - * Initialize SSL system, in particular creating the SSL_context object - * that will be shared by all SSL-using connections in this process. + * Initialize SSL library. * * In threadsafe mode, this includes setting up libcrypto callback functions * to do thread locking. @@ -802,6 +768,7 @@ pgtls_init(PGconn *conn) if (pthread_mutex_lock(&ssl_config_mutex)) return -1; +#ifdef HAVE_CRYPTO_LOCK if (pq_init_crypto_lib) { /* @@ -842,48 +809,22 @@ pgtls_init(PGconn *conn) CRYPTO_set_locking_callback(pq_lockingcallback); } } +#endif /* HAVE_CRYPTO_LOCK */ #endif /* ENABLE_THREAD_SAFETY */ - if (!SSL_context) + if (!ssl_lib_initialized) { if (pq_init_ssl_lib) { -#if SSLEAY_VERSION_NUMBER >= 0x00907000L +#ifdef HAVE_OPENSSL_INIT_SSL + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL); +#else OPENSSL_config(NULL); -#endif SSL_library_init(); SSL_load_error_strings(); - } - - /* - * We use SSLv23_method() because it can negotiate use of the highest - * mutually supported protocol version, while alternatives like - * TLSv1_2_method() permit only one specific version. Note that we - * don't actually allow SSL v2 or v3, only TLS protocols (see below). - */ - SSL_context = SSL_CTX_new(SSLv23_method()); - if (!SSL_context) - { - char *err = SSLerrmessage(ERR_get_error()); - - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not create SSL context: %s\n"), - err); - SSLerrfree(err); -#ifdef ENABLE_THREAD_SAFETY - pthread_mutex_unlock(&ssl_config_mutex); #endif - return -1; } - - /* Disable old protocol versions */ - SSL_CTX_set_options(SSL_context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); - - /* - * 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); + ssl_lib_initialized = true; } #ifdef ENABLE_THREAD_SAFETY @@ -901,12 +842,13 @@ pgtls_init(PGconn *conn) * 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. + * 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) { -#ifdef ENABLE_THREAD_SAFETY +#if defined(ENABLE_THREAD_SAFETY) && defined(HAVE_CRYPTO_LOCK) /* Mutex is created in initialize_ssl_system() */ if (pthread_mutex_lock(&ssl_config_mutex)) return; @@ -926,9 +868,8 @@ destroy_ssl_system(void) CRYPTO_set_id_callback(NULL); /* - * We don't free the lock array or the SSL_context. If we get another - * connection in this process, we will just re-use them with the - * existing mutexes. + * 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. @@ -940,26 +881,22 @@ destroy_ssl_system(void) } /* - * Initialize (potentially) per-connection SSL data, namely the - * client certificate, private key, and trusted CA certs. - * - * conn->ssl must already be created. It receives the connection's client - * certificate and private key. Note however that certificates also get - * loaded into the SSL_context object, and are therefore accessible to all - * connections in this process. This should be OK as long as there aren't - * any hash collisions among the certs. + * 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[256]; bool have_homedir; bool have_cert; + bool have_rootcert; EVP_PKEY *pkey = NULL; /* @@ -975,6 +912,124 @@ initialize_SSL(PGconn *conn) 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()); + + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("could not create SSL context: %s\n"), + err); + SSLerrfree(err); + return -1; + } + + /* Disable old protocol versions */ + SSL_CTX_set_options(SSL_context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); + + /* + * 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 (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()); + + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("could not read root certificate file \"%s\": %s\n"), + fnbuf, err); + SSLerrfree(err); + SSL_CTX_free(SSL_context); + return -1; + } + + if ((cvstore = SSL_CTX_get_cert_store(SSL_context)) != NULL) + { + if (conn->sslcrl && strlen(conn->sslcrl) > 0) + strlcpy(fnbuf, conn->sslcrl, sizeof(fnbuf)); + else if (have_homedir) + snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, ROOT_CRL_FILE); + else + fnbuf[0] = '\0'; + + /* Set the flags to check against the complete CRL chain */ + if (fnbuf[0] != '\0' && + X509_STORE_load_locations(cvstore, fnbuf, NULL) == 1) + { + /* OpenSSL 0.96 does not support X509_V_FLAG_CRL_CHECK */ +#ifdef X509_V_FLAG_CRL_CHECK + X509_STORE_set_flags(cvstore, + X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); +#else + char *err = SSLerrmessage(ERR_get_error()); + + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("SSL library does not support CRL certificates (file \"%s\")\n"), + fnbuf); + SSLerrfree(err); + SSL_CTX_free(SSL_context); + return -1; +#endif + } + /* 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') + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("could not get home directory to locate root certificate file\n" + "Either provide the file or change sslmode to disable server certificate verification.\n")); + else + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("root certificate file \"%s\" does not exist\n" + "Either provide the file or change sslmode to disable server certificate verification.\n"), 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)); @@ -1000,6 +1055,7 @@ initialize_SSL(PGconn *conn) printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open certificate file \"%s\": %s\n"), fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf))); + SSL_CTX_free(SSL_context); return -1; } have_cert = false; @@ -1007,31 +1063,10 @@ initialize_SSL(PGconn *conn) else { /* - * Cert file exists, so load it. Since OpenSSL doesn't provide the - * equivalent of "SSL_use_certificate_chain_file", we actually have to - * load the file twice. The first call loads any extra certs after - * the first one into chain-cert storage associated with the - * SSL_context. The second call loads the first cert (only) into the - * SSL object, where it will be correctly paired with the private key - * we load below. We do it this way so that each connection - * understands which subject cert to present, in case different - * sslcert settings are used for different connections in the same - * process. - * - * NOTE: This function may also modify our SSL_context and therefore - * we have to lock around this call and any places where we use the - * SSL_context struct. + * 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. */ -#ifdef ENABLE_THREAD_SAFETY - int rc; - - if ((rc = pthread_mutex_lock(&ssl_config_mutex))) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not acquire mutex: %s\n"), strerror(rc)); - return -1; - } -#endif if (SSL_CTX_use_certificate_chain_file(SSL_context, fnbuf) != 1) { char *err = SSLerrmessage(ERR_get_error()); @@ -1040,34 +1075,42 @@ initialize_SSL(PGconn *conn) libpq_gettext("could not read certificate file \"%s\": %s\n"), fnbuf, err); SSLerrfree(err); - -#ifdef ENABLE_THREAD_SAFETY - pthread_mutex_unlock(&ssl_config_mutex); -#endif - return -1; - } - - if (SSL_use_certificate_file(conn->ssl, fnbuf, SSL_FILETYPE_PEM) != 1) - { - char *err = SSLerrmessage(ERR_get_error()); - - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not read certificate file \"%s\": %s\n"), - fnbuf, err); - SSLerrfree(err); -#ifdef ENABLE_THREAD_SAFETY - pthread_mutex_unlock(&ssl_config_mutex); -#endif + SSL_CTX_free(SSL_context); return -1; } /* need to load the associated private key, too */ have_cert = true; + } -#ifdef ENABLE_THREAD_SAFETY - pthread_mutex_unlock(&ssl_config_mutex); -#endif + /* + * 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()); + + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("could not establish SSL connection: %s\n"), + 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; /* * Read the SSL key. If a key is specified, treat it as an engine:key @@ -1226,109 +1269,10 @@ initialize_SSL(PGconn *conn) } /* - * 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 a root cert was loaded, also set our certificate verification callback. */ - 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 (fnbuf[0] != '\0' && - stat(fnbuf, &buf) == 0) - { - X509_STORE *cvstore; - -#ifdef ENABLE_THREAD_SAFETY - int rc; - - if ((rc = pthread_mutex_lock(&ssl_config_mutex))) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not acquire mutex: %s\n"), strerror(rc)); - return -1; - } -#endif - if (SSL_CTX_load_verify_locations(SSL_context, fnbuf, NULL) != 1) - { - char *err = SSLerrmessage(ERR_get_error()); - - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not read root certificate file \"%s\": %s\n"), - fnbuf, err); - SSLerrfree(err); -#ifdef ENABLE_THREAD_SAFETY - pthread_mutex_unlock(&ssl_config_mutex); -#endif - return -1; - } - - if ((cvstore = SSL_CTX_get_cert_store(SSL_context)) != NULL) - { - if (conn->sslcrl && strlen(conn->sslcrl) > 0) - strlcpy(fnbuf, conn->sslcrl, sizeof(fnbuf)); - else if (have_homedir) - snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, ROOT_CRL_FILE); - else - fnbuf[0] = '\0'; - - /* Set the flags to check against the complete CRL chain */ - if (fnbuf[0] != '\0' && - X509_STORE_load_locations(cvstore, fnbuf, NULL) == 1) - { - /* OpenSSL 0.96 does not support X509_V_FLAG_CRL_CHECK */ -#ifdef X509_V_FLAG_CRL_CHECK - X509_STORE_set_flags(cvstore, - X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); -#else - char *err = SSLerrmessage(ERR_get_error()); - - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("SSL library does not support CRL certificates (file \"%s\")\n"), - fnbuf); - SSLerrfree(err); -#ifdef ENABLE_THREAD_SAFETY - pthread_mutex_unlock(&ssl_config_mutex); -#endif - return -1; -#endif - } - /* if not found, silently ignore; we do not require CRL */ - } -#ifdef ENABLE_THREAD_SAFETY - pthread_mutex_unlock(&ssl_config_mutex); -#endif - + if (have_rootcert) SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, verify_cb); - } - 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') - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not get home directory to locate root certificate file\n" - "Either provide the file or change sslmode to disable server certificate verification.\n")); - else - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("root certificate file \"%s\" does not exist\n" - "Either provide the file or change sslmode to disable server certificate verification.\n"), fnbuf); - return -1; - } - } /* * If the OpenSSL version used supports it (from 1.0.0 on) and the user @@ -1621,15 +1565,19 @@ PQsslAttribute(PGconn *conn, const char *attribute_name) * to retry; do we need to adopt their logic for that? */ -static bool my_bio_initialized = false; -static BIO_METHOD my_bio_methods; +#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 *) h->ptr, buf, size); + res = pqsecure_raw_read((PGconn *) BIO_get_data(h), buf, size); BIO_clear_retry_flags(h); if (res < 0) { @@ -1659,7 +1607,7 @@ my_sock_write(BIO *h, const char *buf, int size) { int res; - res = pqsecure_raw_write((PGconn *) h->ptr, buf, size); + res = pqsecure_raw_write((PGconn *) BIO_get_data(h), buf, size); BIO_clear_retry_flags(h); if (res <= 0) { @@ -1687,14 +1635,45 @@ my_sock_write(BIO *h, const char *buf, int size) static BIO_METHOD * my_BIO_s_socket(void) { - if (!my_bio_initialized) + if (!my_bio_methods) { - memcpy(&my_bio_methods, BIO_s_socket(), sizeof(BIO_METHOD)); - my_bio_methods.bread = my_sock_read; - my_bio_methods.bwrite = my_sock_write; - my_bio_initialized = true; + 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_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; + return my_bio_methods; } /* This should exactly match openssl's SSL_set_fd except for using my BIO */ @@ -1702,16 +1681,22 @@ static int my_SSL_set_fd(PGconn *conn, int fd) { int ret = 0; - BIO *bio = NULL; + BIO *bio; + BIO_METHOD *bio_method; - bio = BIO_new(my_BIO_s_socket()); + 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; } - /* Use 'ptr' to store pointer to PGconn */ - bio->ptr = conn; + BIO_set_data(bio, conn); SSL_set_bio(conn->ssl, bio, bio); BIO_set_fd(bio, fd, BIO_NOCLOSE); diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c index 94e47a50ed..8f0d892a34 100644 --- a/src/interfaces/libpq/fe-secure.c +++ b/src/interfaces/libpq/fe-secure.c @@ -6,7 +6,7 @@ * message integrity and endpoint authentication. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/interfaces/libpq/libpq-events.c b/src/interfaces/libpq/libpq-events.c index 6db3e943fd..e533017a03 100644 --- a/src/interfaces/libpq/libpq-events.c +++ b/src/interfaces/libpq/libpq-events.c @@ -3,7 +3,7 @@ * libpq-events.c * functions for supporting the libpq "events" API * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/interfaces/libpq/libpq-events.h b/src/interfaces/libpq/libpq-events.h index e2bdb280ec..b7cd472dea 100644 --- a/src/interfaces/libpq/libpq-events.h +++ b/src/interfaces/libpq/libpq-events.h @@ -5,7 +5,7 @@ * that invoke the libpq "events" API, but are not interesting to * ordinary users of libpq. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/libpq/libpq-events.h diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index 9ca0756c4b..1b53d0ed16 100644 --- a/src/interfaces/libpq/libpq-fe.h +++ b/src/interfaces/libpq/libpq-fe.h @@ -4,7 +4,7 @@ * This file contains definitions for structures and * externs for functions used by frontend postgres applications. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/libpq/libpq-fe.h @@ -62,7 +62,9 @@ typedef enum * backend startup. */ CONNECTION_SETENV, /* Negotiating environment. */ CONNECTION_SSL_STARTUP, /* Negotiating SSL. */ - CONNECTION_NEEDED /* Internal state: connect() needed */ + CONNECTION_NEEDED, /* Internal state: connect() needed */ + CONNECTION_CHECK_WRITABLE /* Check if we could make a writable + * connection. */ } ConnStatusType; typedef enum diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 1183323a44..7289bd15c0 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -9,7 +9,7 @@ * more likely to break across PostgreSQL releases than code that uses * only the official API. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/libpq/libpq-int.h @@ -77,7 +77,7 @@ typedef struct #include #include -#if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE) +#ifndef OPENSSL_NO_ENGINE #define USE_SSL_ENGINE #endif #endif /* USE_OPENSSL */ @@ -292,6 +292,30 @@ typedef struct pgDataValue const char *value; /* data value, without zero-termination */ } PGdataValue; +typedef enum pg_conn_host_type +{ + CHT_HOST_NAME, + CHT_HOST_ADDRESS, + CHT_UNIX_SOCKET +} pg_conn_host_type; + +/* + * pg_conn_host stores all information about one of possibly several hosts + * mentioned in the connection string. Derived by splitting the pghost + * on the comma character and then parsing each segment. + */ +typedef struct pg_conn_host +{ + char *host; /* host name or address, or socket path */ + pg_conn_host_type type; /* type of host */ + char *port; /* port number for this host; if not NULL, + * overrrides the PGConn's pgport */ + char *password; /* password for this host, read from the + * password file. only set if the PGconn's + * pgpass field is NULL. */ + struct addrinfo *addrlist; /* list of possible backend addresses */ +} pg_conn_host; + /* * PGconn stores all the state data associated with a single connection * to a backend. @@ -299,13 +323,15 @@ typedef struct pgDataValue struct pg_conn { /* Saved values of connection options */ - char *pghost; /* the machine on which the server is running */ + 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, optionally with port suffixes; if + * NULL, use DEFAULT_PGSOCKET_DIR */ char *pghostaddr; /* the numeric IP address of the machine on * which the server is running. Takes * precedence over above. */ char *pgport; /* the server's communication port number */ - char *pgunixsocket; /* the directory of the server's Unix-domain - * socket; if NULL, use DEFAULT_PGSOCKET_DIR */ char *pgtty; /* tty on which the backend messages is * displayed (OBSOLETE, NOT USED) */ char *connect_timeout; /* connection timeout (numeric string) */ @@ -335,6 +361,9 @@ struct pg_conn char *krbsrvname; /* Kerberos service name */ #endif + char *target_session_attrs; /* Type of connection to make + * Possible values any, read-write. */ + /* Optional file to write trace info to */ FILE *Pfdebug; @@ -363,8 +392,12 @@ struct pg_conn PGnotify *notifyHead; /* oldest unreported Notify msg */ PGnotify *notifyTail; /* newest unreported Notify msg */ + /* Support for multiple hosts in connection string */ + int nconnhost; /* # of possible hosts */ + int whichhost; /* host we're currently considering */ + pg_conn_host *connhost; /* details about each possible host */ + /* Connection data */ - /* See PQconnectPoll() for how we use 'int' and not 'pgsocket'. */ pgsocket sock; /* FD for socket, PGINVALID_SOCKET if * unconnected */ SockAddr laddr; /* Local address */ @@ -379,9 +412,7 @@ struct pg_conn bool sigpipe_flag; /* can we mask SIGPIPE via MSG_NOSIGNAL? */ /* Transient state needed while establishing connection */ - struct addrinfo *addrlist; /* list of possible backend addresses */ - struct addrinfo *addr_cur; /* the one currently being tried */ - int addrlist_family; /* needed to know how to free addrlist */ + struct addrinfo *addr_cur; /* backend address currently being tried */ PGSetenvStatusType setenv_state; /* for 2.0 protocol only */ const PQEnvironmentOption *next_eo; bool send_appname; /* okay to send application_name? */ @@ -452,7 +483,7 @@ struct pg_conn #ifndef ENABLE_GSS gss_buffer_desc ginbuf; /* GSS input token */ #else - char *gsslib; /* What GSS librart to use ("gssapi" or + char *gsslib; /* What GSS library to use ("gssapi" or * "sspi") */ #endif CredHandle *sspicred; /* SSPI credentials handle */ diff --git a/src/interfaces/libpq/libpq.rc.in b/src/interfaces/libpq/libpq.rc.in index e41a1a27f4..761acd4608 100644 --- a/src/interfaces/libpq/libpq.rc.in +++ b/src/interfaces/libpq/libpq.rc.in @@ -1,8 +1,8 @@ #include VS_VERSION_INFO VERSIONINFO - FILEVERSION 9,6,0,0 - PRODUCTVERSION 9,6,0,0 + FILEVERSION 10,0,0,0 + PRODUCTVERSION 10,0,0,0 FILEFLAGSMASK 0x3fL FILEFLAGS 0 FILEOS VOS__WINDOWS32 @@ -15,13 +15,13 @@ BEGIN BEGIN VALUE "CompanyName", "\0" VALUE "FileDescription", "PostgreSQL Access Library\0" - VALUE "FileVersion", "9.6.0\0" + VALUE "FileVersion", "10.0\0" VALUE "InternalName", "libpq\0" - VALUE "LegalCopyright", "Copyright (C) 2016\0" + VALUE "LegalCopyright", "Copyright (C) 2017\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "libpq.dll\0" VALUE "ProductName", "PostgreSQL\0" - VALUE "ProductVersion", "9.6.0\0" + VALUE "ProductVersion", "10.0\0" END END BLOCK "VarFileInfo" diff --git a/src/interfaces/libpq/pqexpbuffer.c b/src/interfaces/libpq/pqexpbuffer.c index 8d82d5c3ae..fd62cde99f 100644 --- a/src/interfaces/libpq/pqexpbuffer.c +++ b/src/interfaces/libpq/pqexpbuffer.c @@ -15,7 +15,7 @@ * a usable vsnprintf(), then a copy of our own implementation of it will * be linked into libpq. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/libpq/pqexpbuffer.c diff --git a/src/interfaces/libpq/pqexpbuffer.h b/src/interfaces/libpq/pqexpbuffer.h index ce87cd5b1e..239def42b7 100644 --- a/src/interfaces/libpq/pqexpbuffer.h +++ b/src/interfaces/libpq/pqexpbuffer.h @@ -15,7 +15,7 @@ * a usable vsnprintf(), then a copy of our own implementation of it will * be linked into libpq. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/libpq/pqexpbuffer.h diff --git a/src/interfaces/libpq/pthread-win32.c b/src/interfaces/libpq/pthread-win32.c index 68dfefc3b9..e63432d822 100644 --- a/src/interfaces/libpq/pthread-win32.c +++ b/src/interfaces/libpq/pthread-win32.c @@ -3,7 +3,7 @@ * pthread-win32.c * partial pthread implementation for win32 * -* Copyright (c) 2004-2016, PostgreSQL Global Development Group +* Copyright (c) 2004-2017, PostgreSQL Global Development Group * IDENTIFICATION * src/interfaces/libpq/pthread-win32.c * diff --git a/src/interfaces/libpq/test/uri-regress.c b/src/interfaces/libpq/test/uri-regress.c index bf1d9704c3..fac849bab2 100644 --- a/src/interfaces/libpq/test/uri-regress.c +++ b/src/interfaces/libpq/test/uri-regress.c @@ -7,7 +7,7 @@ * prints out the values from the parsed PQconninfoOption struct that differ * from the defaults (obtained from PQconndefaults). * - * Portions Copyright (c) 2012-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/interfaces/libpq/test/uri-regress.c diff --git a/src/interfaces/libpq/win32.c b/src/interfaces/libpq/win32.c index 06a39211e9..d6ecca3859 100644 --- a/src/interfaces/libpq/win32.c +++ b/src/interfaces/libpq/win32.c @@ -15,7 +15,7 @@ * The error constants are taken from the Frambak Bakfram LGSOCKET * library guys who in turn took them from the Winsock FAQ. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * */ diff --git a/src/makefiles/Makefile.cygwin b/src/makefiles/Makefile.cygwin index bb2efed3ce..3aaa8a9f04 100644 --- a/src/makefiles/Makefile.cygwin +++ b/src/makefiles/Makefile.cygwin @@ -16,13 +16,15 @@ CFLAGS_SL = ifneq (,$(findstring backend,$(subdir))) ifeq (,$(findstring conversion_procs,$(subdir))) -ifeq (,$(findstring snowball,$(subdir))) ifeq (,$(findstring libpqwalreceiver,$(subdir))) +ifeq (,$(findstring replication/pgoutput,$(subdir))) +ifeq (,$(findstring snowball,$(subdir))) override CPPFLAGS+= -DBUILDING_DLL endif endif endif endif +endif ifneq (,$(findstring src/common,$(subdir))) override CPPFLAGS+= -DBUILDING_DLL diff --git a/src/makefiles/Makefile.sco b/src/makefiles/Makefile.sco deleted file mode 100644 index 993861570a..0000000000 --- a/src/makefiles/Makefile.sco +++ /dev/null @@ -1,13 +0,0 @@ -AROPT = cr -export_dynamic = -Wl,-Bexport - -DLSUFFIX = .so -ifeq ($(GCC), yes) -CFLAGS_SL = -fpic -else -CFLAGS_SL = -K PIC -endif - -# Rule for building a shared library from a single .o file -%.so: %.o - $(LD) -G -Bdynamic -o $@ $< diff --git a/src/makefiles/Makefile.unixware b/src/makefiles/Makefile.unixware deleted file mode 100644 index a52717b268..0000000000 --- a/src/makefiles/Makefile.unixware +++ /dev/null @@ -1,35 +0,0 @@ -AROPT = crs -ifeq ($(with_gnu_ld), yes) - export_dynamic = -Wl,-E -else - export_dynamic = -Wl,-Bexport -endif - -ifeq ($(ld_R_works), yes) -ifeq ($(with_gnu_ld), yes) - rpath = -Wl,-rpath,'$(rpathdir)' -else - rpath = -Wl,-R'$(rpathdir)' -endif -endif - -# Unixware needs threads for everything that uses libpq -CFLAGS += $(PTHREAD_CFLAGS) - -DLSUFFIX = .so -ifeq ($(GCC), yes) -CFLAGS_SL = -fpic -else -CFLAGS_SL = -K PIC -endif -ifeq ($(GCC), yes) -SO_FLAGS = -shared -else -SO_FLAGS = -G -endif - -# Rule for building a shared library from a single .o file -%.so: %.o - $(CC) $(CFLAGS) $(LDFLAGS) $(LDFLAGS_SL) $(SO_FLAGS) -o $@ $< - -sqlmansect = 5sql diff --git a/src/makefiles/Makefile.win32 b/src/makefiles/Makefile.win32 index 5f26a091d2..7abbd01971 100644 --- a/src/makefiles/Makefile.win32 +++ b/src/makefiles/Makefile.win32 @@ -14,13 +14,15 @@ CFLAGS_SL = ifneq (,$(findstring backend,$(subdir))) ifeq (,$(findstring conversion_procs,$(subdir))) -ifeq (,$(findstring snowball,$(subdir))) ifeq (,$(findstring libpqwalreceiver,$(subdir))) +ifeq (,$(findstring replication/pgoutput,$(subdir))) +ifeq (,$(findstring snowball,$(subdir))) override CPPFLAGS+= -DBUILDING_DLL endif endif endif endif +endif ifneq (,$(findstring src/common,$(subdir))) override CPPFLAGS+= -DBUILDING_DLL diff --git a/src/makefiles/pgxs.mk b/src/makefiles/pgxs.mk index 2b4d684e8e..c27004ecfb 100644 --- a/src/makefiles/pgxs.mk +++ b/src/makefiles/pgxs.mk @@ -40,6 +40,8 @@ # which need to be built first # REGRESS -- list of regression test cases (without suffix) # REGRESS_OPTS -- additional switches to pass to pg_regress +# NO_INSTALLCHECK -- don't define an installcheck target, useful e.g. if +# tests require special configuration, or don't use pg_regress # EXTRA_CLEAN -- extra files to remove in 'make clean' # PG_CPPFLAGS -- will be added to CPPFLAGS # PG_LIBS -- will be added to PROGRAM link line @@ -268,8 +270,10 @@ ifndef PGXS endif # against installed postmaster +ifndef NO_INSTALLCHECK installcheck: submake $(REGRESS_PREP) $(pg_regress_installcheck) $(REGRESS_OPTS) $(REGRESS) +endif ifdef PGXS check: diff --git a/src/pl/plperl/plc_perlboot.pl b/src/pl/plperl/plc_perlboot.pl index d506d01163..bb2d009be0 100644 --- a/src/pl/plperl/plc_perlboot.pl +++ b/src/pl/plperl/plc_perlboot.pl @@ -1,5 +1,7 @@ # src/pl/plperl/plc_perlboot.pl +use strict; + use 5.008001; use vars qw(%_SHARED $_TD); diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c index 82bde6e442..9a2d0527f8 100644 --- a/src/pl/plperl/plperl.c +++ b/src/pl/plperl/plperl.c @@ -98,17 +98,19 @@ typedef struct plperl_interp_desc /********************************************************************** * The information we cache about loaded procedures * - * The refcount field counts the struct's reference from the hash table shown - * below, plus one reference for each function call level that is using the - * struct. We can release the struct, and the associated Perl sub, when the - * refcount goes to zero. + * The fn_refcount field counts the struct's reference from the hash table + * shown below, plus one reference for each function call level that is using + * the struct. We can release the struct, and the associated Perl sub, when + * the fn_refcount goes to zero. Releasing the struct itself is done by + * deleting the fn_cxt, which also gets rid of all subsidiary data. **********************************************************************/ typedef struct plperl_proc_desc { char *proname; /* user name of procedure */ + MemoryContext fn_cxt; /* memory context for this procedure */ + unsigned long fn_refcount; /* number of active references */ TransactionId fn_xmin; /* xmin/TID of procedure's pg_proc tuple */ ItemPointerData fn_tid; - int refcount; /* reference count of this struct */ SV *reference; /* CODE reference for Perl sub */ plperl_interp_desc *interp; /* interpreter it's created in */ bool fn_readonly; /* is function readonly (not volatile)? */ @@ -122,18 +124,19 @@ typedef struct plperl_proc_desc Oid result_oid; /* Oid of result type */ FmgrInfo result_in_func; /* I/O function and arg for result type */ Oid result_typioparam; - /* Conversion info for function's argument types: */ + /* Per-argument info for function's argument types: */ int nargs; - FmgrInfo arg_out_func[FUNC_MAX_ARGS]; - bool arg_is_rowtype[FUNC_MAX_ARGS]; - Oid arg_arraytype[FUNC_MAX_ARGS]; /* InvalidOid if not an array */ + FmgrInfo *arg_out_func; /* output fns for arg types */ + bool *arg_is_rowtype; /* is each arg composite? */ + Oid *arg_arraytype; /* InvalidOid if not an array */ } plperl_proc_desc; #define increment_prodesc_refcount(prodesc) \ - ((prodesc)->refcount++) + ((prodesc)->fn_refcount++) #define decrement_prodesc_refcount(prodesc) \ do { \ - if (--((prodesc)->refcount) <= 0) \ + Assert((prodesc)->fn_refcount > 0); \ + if (--((prodesc)->fn_refcount) == 0) \ free_plperl_function(prodesc); \ } while(0) @@ -353,23 +356,6 @@ hek2cstr(HE *he) return ret; } -/* - * This routine is a crock, and so is everyplace that calls it. The problem - * is that the cached form of plperl functions/queries is allocated permanently - * (mostly via malloc()) and never released until backend exit. Subsidiary - * data structures such as fmgr info records therefore must live forever - * as well. A better implementation would store all this stuff in a per- - * function memory context that could be reclaimed at need. In the meantime, - * fmgr_info_cxt must be called specifying TopMemoryContext so that whatever - * it might allocate, and whatever the eventual function might allocate using - * fn_mcxt, will live forever too. - */ -static void -perm_fmgr_info(Oid functionId, FmgrInfo *finfo) -{ - fmgr_info_cxt(functionId, finfo, TopMemoryContext); -} - /* * _PG_init() - library load-time initialization @@ -1076,11 +1062,16 @@ plperl_build_tuple_result(HV *perlhash, TupleDesc td) char *key = hek2cstr(he); int attn = SPI_fnumber(td, key); - if (attn <= 0 || td->attrs[attn - 1]->attisdropped) + if (attn == SPI_ERROR_NOATTRIBUTE) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("Perl hash contains nonexistent column \"%s\"", key))); + if (attn <= 0) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot set system attribute \"%s\"", + key))); values[attn - 1] = plperl_sv_to_datum(val, td->attrs[attn - 1]->atttypid, @@ -1433,6 +1424,10 @@ plperl_ref_from_pg_array(Datum arg, Oid typid) SV *av; HV *hv; + /* + * Currently we make no effort to cache any of the stuff we look up here, + * which is bad. + */ info = palloc0(sizeof(plperl_array_info)); /* get element type information, including output conversion function */ @@ -1440,10 +1435,16 @@ plperl_ref_from_pg_array(Datum arg, Oid typid) &typlen, &typbyval, &typalign, &typdelim, &typioparam, &typoutputfunc); - if ((transform_funcid = get_transform_fromsql(elementtype, current_call_data->prodesc->lang_oid, current_call_data->prodesc->trftypes))) - perm_fmgr_info(transform_funcid, &info->transform_proc); + /* Check for a transform function */ + transform_funcid = get_transform_fromsql(elementtype, + current_call_data->prodesc->lang_oid, + current_call_data->prodesc->trftypes); + + /* Look up transform or output function as appropriate */ + if (OidIsValid(transform_funcid)) + fmgr_info(transform_funcid, &info->transform_proc); else - perm_fmgr_info(typoutputfunc, &info->proc); + fmgr_info(typoutputfunc, &info->proc); info->elem_is_rowtype = type_is_rowtype(elementtype); @@ -1674,8 +1675,7 @@ plperl_event_trigger_build_args(FunctionCallInfo fcinfo) return newRV_noinc((SV *) hv); } -/* Set up the new tuple returned from a trigger. */ - +/* Construct the modified new tuple to be returned from a trigger. */ static HeapTuple plperl_modify_tuple(HV *hvTD, TriggerData *tdata, HeapTuple otup) { @@ -1683,14 +1683,11 @@ plperl_modify_tuple(HV *hvTD, TriggerData *tdata, HeapTuple otup) HV *hvNew; HE *he; HeapTuple rtup; - int slotsused; - int *modattrs; - Datum *modvalues; - char *modnulls; - TupleDesc tupdesc; - - tupdesc = tdata->tg_relation->rd_att; + int natts; + Datum *modvalues; + bool *modnulls; + bool *modrepls; svp = hv_fetch_string(hvTD, "new"); if (!svp) @@ -1703,51 +1700,49 @@ plperl_modify_tuple(HV *hvTD, TriggerData *tdata, HeapTuple otup) errmsg("$_TD->{new} is not a hash reference"))); hvNew = (HV *) SvRV(*svp); - modattrs = palloc(tupdesc->natts * sizeof(int)); - modvalues = palloc(tupdesc->natts * sizeof(Datum)); - modnulls = palloc(tupdesc->natts * sizeof(char)); - slotsused = 0; + tupdesc = tdata->tg_relation->rd_att; + natts = tupdesc->natts; + + modvalues = (Datum *) palloc0(natts * sizeof(Datum)); + modnulls = (bool *) palloc0(natts * sizeof(bool)); + modrepls = (bool *) palloc0(natts * sizeof(bool)); hv_iterinit(hvNew); while ((he = hv_iternext(hvNew))) { - bool isnull; char *key = hek2cstr(he); SV *val = HeVAL(he); int attn = SPI_fnumber(tupdesc, key); - if (attn <= 0 || tupdesc->attrs[attn - 1]->attisdropped) + if (attn == SPI_ERROR_NOATTRIBUTE) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("Perl hash contains nonexistent column \"%s\"", key))); + if (attn <= 0) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot set system attribute \"%s\"", + key))); - modvalues[slotsused] = plperl_sv_to_datum(val, + modvalues[attn - 1] = plperl_sv_to_datum(val, tupdesc->attrs[attn - 1]->atttypid, tupdesc->attrs[attn - 1]->atttypmod, - NULL, - NULL, - InvalidOid, - &isnull); - - modnulls[slotsused] = isnull ? 'n' : ' '; - modattrs[slotsused] = attn; - slotsused++; + NULL, + NULL, + InvalidOid, + &modnulls[attn - 1]); + modrepls[attn - 1] = true; pfree(key); } hv_iterinit(hvNew); - rtup = SPI_modifytuple(tdata->tg_relation, otup, slotsused, - modattrs, modvalues, modnulls); + rtup = heap_modify_tuple(otup, tupdesc, modvalues, modnulls, modrepls); - pfree(modattrs); pfree(modvalues); pfree(modnulls); - - if (rtup == NULL) - elog(ERROR, "SPI_modifytuple failed: %s", - SPI_result_code_string(SPI_result)); + pfree(modrepls); return rtup; } @@ -1791,18 +1786,18 @@ plperl_call_handler(PG_FUNCTION_ARGS) } PG_CATCH(); { - if (this_call_data.prodesc) - decrement_prodesc_refcount(this_call_data.prodesc); current_call_data = save_call_data; activate_interpreter(oldinterp); + if (this_call_data.prodesc) + decrement_prodesc_refcount(this_call_data.prodesc); PG_RE_THROW(); } PG_END_TRY(); - if (this_call_data.prodesc) - decrement_prodesc_refcount(this_call_data.prodesc); current_call_data = save_call_data; activate_interpreter(oldinterp); + if (this_call_data.prodesc) + decrement_prodesc_refcount(this_call_data.prodesc); return retval; } @@ -2616,7 +2611,7 @@ validate_plperl_function(plperl_proc_ptr *proc_ptr, HeapTuple procTup) static void free_plperl_function(plperl_proc_desc *prodesc) { - Assert(prodesc->refcount <= 0); + Assert(prodesc->fn_refcount == 0); /* Release CODE reference, if we have one, from the appropriate interp */ if (prodesc->reference) { @@ -2626,12 +2621,8 @@ free_plperl_function(plperl_proc_desc *prodesc) SvREFCNT_dec(prodesc->reference); activate_interpreter(oldinterp); } - /* Get rid of what we conveniently can of our own structs */ - /* (FmgrInfo subsidiary info will get leaked ...) */ - if (prodesc->proname) - free(prodesc->proname); - list_free(prodesc->trftypes); - free(prodesc); + /* Release all PG-owned data for this proc */ + MemoryContextDelete(prodesc->fn_cxt); } @@ -2642,8 +2633,8 @@ compile_plperl_function(Oid fn_oid, bool is_trigger, bool is_event_trigger) Form_pg_proc procStruct; plperl_proc_key proc_key; plperl_proc_ptr *proc_ptr; - plperl_proc_desc *prodesc = NULL; - int i; + plperl_proc_desc *volatile prodesc = NULL; + volatile MemoryContext proc_cxt = NULL; plperl_interp_desc *oldinterp = plperl_active_interp; ErrorContextCallback plperl_error_context; @@ -2653,41 +2644,50 @@ compile_plperl_function(Oid fn_oid, bool is_trigger, bool is_event_trigger) elog(ERROR, "cache lookup failed for function %u", fn_oid); procStruct = (Form_pg_proc) GETSTRUCT(procTup); - /* Set a callback for reporting compilation errors */ - plperl_error_context.callback = plperl_compile_callback; - plperl_error_context.previous = error_context_stack; - plperl_error_context.arg = NameStr(procStruct->proname); - error_context_stack = &plperl_error_context; - - /* Try to find function in plperl_proc_hash */ + /* + * Try to find function in plperl_proc_hash. The reason for this + * overcomplicated-seeming lookup procedure is that we don't know whether + * it's plperl or plperlu, and don't want to spend a lookup in pg_language + * to find out. + */ proc_key.proc_id = fn_oid; proc_key.is_trigger = is_trigger; proc_key.user_id = GetUserId(); - proc_ptr = hash_search(plperl_proc_hash, &proc_key, HASH_FIND, NULL); + if (validate_plperl_function(proc_ptr, procTup)) + { + /* Found valid plperl entry */ + ReleaseSysCache(procTup); + return proc_ptr->proc_ptr; + } + /* If not found or obsolete, maybe it's plperlu */ + proc_key.user_id = InvalidOid; + proc_ptr = hash_search(plperl_proc_hash, &proc_key, + HASH_FIND, NULL); if (validate_plperl_function(proc_ptr, procTup)) - prodesc = proc_ptr->proc_ptr; - else { - /* If not found or obsolete, maybe it's plperlu */ - proc_key.user_id = InvalidOid; - proc_ptr = hash_search(plperl_proc_hash, &proc_key, - HASH_FIND, NULL); - if (validate_plperl_function(proc_ptr, procTup)) - prodesc = proc_ptr->proc_ptr; + /* Found valid plperlu entry */ + ReleaseSysCache(procTup); + return proc_ptr->proc_ptr; } /************************************************************ * If we haven't found it in the hashtable, we analyze * the function's arguments and return type and store - * the in-/out-functions in the prodesc block and create - * a new hashtable entry for it. - * - * Then we load the procedure into the Perl interpreter. + * the in-/out-functions in the prodesc block, + * then we load the procedure into the Perl interpreter, + * and last we create a new hashtable entry for it. ************************************************************/ - if (prodesc == NULL) + + /* Set a callback for reporting compilation errors */ + plperl_error_context.callback = plperl_compile_callback; + plperl_error_context.previous = error_context_stack; + plperl_error_context.arg = NameStr(procStruct->proname); + error_context_stack = &plperl_error_context; + + PG_TRY(); { HeapTuple langTup; HeapTuple typeTup; @@ -2697,42 +2697,42 @@ compile_plperl_function(Oid fn_oid, bool is_trigger, bool is_event_trigger) Datum prosrcdatum; bool isnull; char *proc_source; + MemoryContext oldcontext; /************************************************************ - * Allocate a new procedure description block + * Allocate a context that will hold all PG data for the procedure. ************************************************************/ - prodesc = (plperl_proc_desc *) malloc(sizeof(plperl_proc_desc)); - if (prodesc == NULL) - ereport(ERROR, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); - /* Initialize all fields to 0 so free_plperl_function is safe */ - MemSet(prodesc, 0, sizeof(plperl_proc_desc)); + proc_cxt = AllocSetContextCreate(TopMemoryContext, + NameStr(procStruct->proname), + ALLOCSET_SMALL_SIZES); - prodesc->proname = strdup(NameStr(procStruct->proname)); - if (prodesc->proname == NULL) - { - free_plperl_function(prodesc); - ereport(ERROR, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); - } + /************************************************************ + * Allocate and fill a new procedure description block. + * struct prodesc and subsidiary data must all live in proc_cxt. + ************************************************************/ + oldcontext = MemoryContextSwitchTo(proc_cxt); + prodesc = (plperl_proc_desc *) palloc0(sizeof(plperl_proc_desc)); + prodesc->proname = pstrdup(NameStr(procStruct->proname)); + prodesc->fn_cxt = proc_cxt; + prodesc->fn_refcount = 0; prodesc->fn_xmin = HeapTupleHeaderGetRawXmin(procTup->t_data); prodesc->fn_tid = procTup->t_self; + prodesc->nargs = procStruct->pronargs; + prodesc->arg_out_func = (FmgrInfo *) palloc0(prodesc->nargs * sizeof(FmgrInfo)); + prodesc->arg_is_rowtype = (bool *) palloc0(prodesc->nargs * sizeof(bool)); + prodesc->arg_arraytype = (Oid *) palloc0(prodesc->nargs * sizeof(Oid)); + MemoryContextSwitchTo(oldcontext); /* Remember if function is STABLE/IMMUTABLE */ prodesc->fn_readonly = (procStruct->provolatile != PROVOLATILE_VOLATILE); - { - MemoryContext oldcxt; - - protrftypes_datum = SysCacheGetAttr(PROCOID, procTup, + /* Fetch protrftypes */ + protrftypes_datum = SysCacheGetAttr(PROCOID, procTup, Anum_pg_proc_protrftypes, &isnull); - oldcxt = MemoryContextSwitchTo(TopMemoryContext); - prodesc->trftypes = isnull ? NIL : oid_array_to_list(protrftypes_datum); - MemoryContextSwitchTo(oldcxt); - } + MemoryContextSwitchTo(proc_cxt); + prodesc->trftypes = isnull ? NIL : oid_array_to_list(protrftypes_datum); + MemoryContextSwitchTo(oldcontext); /************************************************************ * Lookup the pg_language tuple by Oid @@ -2740,11 +2740,8 @@ compile_plperl_function(Oid fn_oid, bool is_trigger, bool is_event_trigger) langTup = SearchSysCache1(LANGOID, ObjectIdGetDatum(procStruct->prolang)); if (!HeapTupleIsValid(langTup)) - { - free_plperl_function(prodesc); elog(ERROR, "cache lookup failed for language %u", procStruct->prolang); - } langStruct = (Form_pg_language) GETSTRUCT(langTup); prodesc->lang_oid = HeapTupleGetOid(langTup); prodesc->lanpltrusted = langStruct->lanpltrusted; @@ -2760,11 +2757,8 @@ compile_plperl_function(Oid fn_oid, bool is_trigger, bool is_event_trigger) SearchSysCache1(TYPEOID, ObjectIdGetDatum(procStruct->prorettype)); if (!HeapTupleIsValid(typeTup)) - { - free_plperl_function(prodesc); elog(ERROR, "cache lookup failed for type %u", procStruct->prorettype); - } typeStruct = (Form_pg_type) GETSTRUCT(typeTup); /* Disallow pseudotype result, except VOID or RECORD */ @@ -2775,21 +2769,15 @@ compile_plperl_function(Oid fn_oid, bool is_trigger, bool is_event_trigger) /* okay */ ; else if (procStruct->prorettype == TRIGGEROID || procStruct->prorettype == EVTTRIGGEROID) - { - free_plperl_function(prodesc); ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("trigger functions can only be called " "as triggers"))); - } else - { - free_plperl_function(prodesc); ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("PL/Perl functions cannot return type %s", format_type_be(procStruct->prorettype)))); - } } prodesc->result_oid = procStruct->prorettype; @@ -2800,7 +2788,9 @@ compile_plperl_function(Oid fn_oid, bool is_trigger, bool is_event_trigger) prodesc->fn_retisarray = (typeStruct->typlen == -1 && typeStruct->typelem); - perm_fmgr_info(typeStruct->typinput, &(prodesc->result_in_func)); + fmgr_info_cxt(typeStruct->typinput, + &(prodesc->result_in_func), + proc_cxt); prodesc->result_typioparam = getTypeIOParam(typeTup); ReleaseSysCache(typeTup); @@ -2812,29 +2802,24 @@ compile_plperl_function(Oid fn_oid, bool is_trigger, bool is_event_trigger) ************************************************************/ if (!is_trigger && !is_event_trigger) { - prodesc->nargs = procStruct->pronargs; + int i; + for (i = 0; i < prodesc->nargs; i++) { typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(procStruct->proargtypes.values[i])); if (!HeapTupleIsValid(typeTup)) - { - free_plperl_function(prodesc); elog(ERROR, "cache lookup failed for type %u", procStruct->proargtypes.values[i]); - } typeStruct = (Form_pg_type) GETSTRUCT(typeTup); /* Disallow pseudotype argument */ if (typeStruct->typtype == TYPTYPE_PSEUDO && procStruct->proargtypes.values[i] != RECORDOID) - { - free_plperl_function(prodesc); ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("PL/Perl functions cannot accept type %s", format_type_be(procStruct->proargtypes.values[i])))); - } if (typeStruct->typtype == TYPTYPE_COMPOSITE || procStruct->proargtypes.values[i] == RECORDOID) @@ -2842,8 +2827,9 @@ compile_plperl_function(Oid fn_oid, bool is_trigger, bool is_event_trigger) else { prodesc->arg_is_rowtype[i] = false; - perm_fmgr_info(typeStruct->typoutput, - &(prodesc->arg_out_func[i])); + fmgr_info_cxt(typeStruct->typoutput, + &(prodesc->arg_out_func[i]), + proc_cxt); } /* Identify array attributes */ @@ -2880,22 +2866,42 @@ compile_plperl_function(Oid fn_oid, bool is_trigger, bool is_event_trigger) activate_interpreter(oldinterp); pfree(proc_source); + if (!prodesc->reference) /* can this happen? */ - { - free_plperl_function(prodesc); elog(ERROR, "could not create PL/Perl internal procedure"); - } /************************************************************ - * OK, link the procedure into the correct hashtable entry + * OK, link the procedure into the correct hashtable entry. + * Note we assume that the hashtable entry either doesn't exist yet, + * or we already cleared its proc_ptr during the validation attempts + * above. So no need to decrement an old refcount here. ************************************************************/ proc_key.user_id = prodesc->lanpltrusted ? GetUserId() : InvalidOid; proc_ptr = hash_search(plperl_proc_hash, &proc_key, HASH_ENTER, NULL); + /* We assume these two steps can't throw an error: */ proc_ptr->proc_ptr = prodesc; increment_prodesc_refcount(prodesc); } + PG_CATCH(); + { + /* + * If we got as far as creating a reference, we should be able to use + * free_plperl_function() to clean up. If not, then at most we have + * some PG memory resources in proc_cxt, which we can just delete. + */ + if (prodesc && prodesc->reference) + free_plperl_function(prodesc); + else if (proc_cxt) + MemoryContextDelete(proc_cxt); + + /* Be sure to restore the previous interpreter, too, for luck */ + activate_interpreter(oldinterp); + + PG_RE_THROW(); + } + PG_END_TRY(); /* restore previous error callback */ error_context_stack = plperl_error_context.previous; @@ -3051,12 +3057,6 @@ plperl_spi_exec(char *query, int limit) ReleaseCurrentSubTransaction(); MemoryContextSwitchTo(oldcontext); CurrentResourceOwner = oldowner; - - /* - * AtEOSubXact_SPI() should not have popped any SPI context, but just - * in case it did, make sure we remain connected. - */ - SPI_restore_connection(); } PG_CATCH(); { @@ -3072,13 +3072,6 @@ plperl_spi_exec(char *query, int limit) MemoryContextSwitchTo(oldcontext); CurrentResourceOwner = oldowner; - /* - * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will - * have left us in a disconnected state. We need this hack to return - * to connected state. - */ - SPI_restore_connection(); - /* Punt the error to Perl */ croak_cstr(edata->message); @@ -3205,9 +3198,7 @@ plperl_return_next(SV *sv) current_call_data->tmp_cxt = AllocSetContextCreate(CurrentMemoryContext, "PL/Perl return_next temporary cxt", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); } old_cxt = MemoryContextSwitchTo(current_call_data->tmp_cxt); @@ -3292,12 +3283,6 @@ plperl_spi_query(char *query) ReleaseCurrentSubTransaction(); MemoryContextSwitchTo(oldcontext); CurrentResourceOwner = oldowner; - - /* - * AtEOSubXact_SPI() should not have popped any SPI context, but just - * in case it did, make sure we remain connected. - */ - SPI_restore_connection(); } PG_CATCH(); { @@ -3313,13 +3298,6 @@ plperl_spi_query(char *query) MemoryContextSwitchTo(oldcontext); CurrentResourceOwner = oldowner; - /* - * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will - * have left us in a disconnected state. We need this hack to return - * to connected state. - */ - SPI_restore_connection(); - /* Punt the error to Perl */ croak_cstr(edata->message); @@ -3378,12 +3356,6 @@ plperl_spi_fetchrow(char *cursor) ReleaseCurrentSubTransaction(); MemoryContextSwitchTo(oldcontext); CurrentResourceOwner = oldowner; - - /* - * AtEOSubXact_SPI() should not have popped any SPI context, but just - * in case it did, make sure we remain connected. - */ - SPI_restore_connection(); } PG_CATCH(); { @@ -3399,13 +3371,6 @@ plperl_spi_fetchrow(char *cursor) MemoryContextSwitchTo(oldcontext); CurrentResourceOwner = oldowner; - /* - * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will - * have left us in a disconnected state. We need this hack to return - * to connected state. - */ - SPI_restore_connection(); - /* Punt the error to Perl */ croak_cstr(edata->message); @@ -3460,9 +3425,7 @@ plperl_spi_prepare(char *query, int argc, SV **argv) ************************************************************/ plan_cxt = AllocSetContextCreate(TopMemoryContext, "PL/Perl spi_prepare query", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MAXSIZE); + ALLOCSET_SMALL_SIZES); MemoryContextSwitchTo(plan_cxt); qdesc = (plperl_query_desc *) palloc0(sizeof(plperl_query_desc)); snprintf(qdesc->qname, sizeof(qdesc->qname), "%p", qdesc); @@ -3479,9 +3442,7 @@ plperl_spi_prepare(char *query, int argc, SV **argv) ************************************************************/ work_cxt = AllocSetContextCreate(CurrentMemoryContext, "PL/Perl spi_prepare workspace", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); MemoryContextSwitchTo(work_cxt); /************************************************************ @@ -3543,12 +3504,6 @@ plperl_spi_prepare(char *query, int argc, SV **argv) ReleaseCurrentSubTransaction(); MemoryContextSwitchTo(oldcontext); CurrentResourceOwner = oldowner; - - /* - * AtEOSubXact_SPI() should not have popped any SPI context, but just - * in case it did, make sure we remain connected. - */ - SPI_restore_connection(); } PG_CATCH(); { @@ -3574,13 +3529,6 @@ plperl_spi_prepare(char *query, int argc, SV **argv) MemoryContextSwitchTo(oldcontext); CurrentResourceOwner = oldowner; - /* - * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will - * have left us in a disconnected state. We need this hack to return - * to connected state. - */ - SPI_restore_connection(); - /* Punt the error to Perl */ croak_cstr(edata->message); @@ -3694,12 +3642,6 @@ plperl_spi_exec_prepared(char *query, HV *attr, int argc, SV **argv) ReleaseCurrentSubTransaction(); MemoryContextSwitchTo(oldcontext); CurrentResourceOwner = oldowner; - - /* - * AtEOSubXact_SPI() should not have popped any SPI context, but just - * in case it did, make sure we remain connected. - */ - SPI_restore_connection(); } PG_CATCH(); { @@ -3715,13 +3657,6 @@ plperl_spi_exec_prepared(char *query, HV *attr, int argc, SV **argv) MemoryContextSwitchTo(oldcontext); CurrentResourceOwner = oldowner; - /* - * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will - * have left us in a disconnected state. We need this hack to return - * to connected state. - */ - SPI_restore_connection(); - /* Punt the error to Perl */ croak_cstr(edata->message); @@ -3823,12 +3758,6 @@ plperl_spi_query_prepared(char *query, int argc, SV **argv) ReleaseCurrentSubTransaction(); MemoryContextSwitchTo(oldcontext); CurrentResourceOwner = oldowner; - - /* - * AtEOSubXact_SPI() should not have popped any SPI context, but just - * in case it did, make sure we remain connected. - */ - SPI_restore_connection(); } PG_CATCH(); { @@ -3844,13 +3773,6 @@ plperl_spi_query_prepared(char *query, int argc, SV **argv) MemoryContextSwitchTo(oldcontext); CurrentResourceOwner = oldowner; - /* - * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will - * have left us in a disconnected state. We need this hack to return - * to connected state. - */ - SPI_restore_connection(); - /* Punt the error to Perl */ croak_cstr(edata->message); diff --git a/src/pl/plperl/plperl.h b/src/pl/plperl/plperl.h index 0146d60a11..ae367b0fc1 100644 --- a/src/pl/plperl/plperl.h +++ b/src/pl/plperl/plperl.h @@ -5,7 +5,7 @@ * * This should be included _AFTER_ postgres.h and system include files * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1995, Regents of the University of California * * src/pl/plperl/plperl.h diff --git a/src/pl/plpgsql/src/generate-plerrcodes.pl b/src/pl/plpgsql/src/generate-plerrcodes.pl index 6a60a13d81..6a676c0953 100644 --- a/src/pl/plpgsql/src/generate-plerrcodes.pl +++ b/src/pl/plpgsql/src/generate-plerrcodes.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl # # Generate the plerrcodes.h header from errcodes.txt -# Copyright (c) 2000-2016, PostgreSQL Global Development Group +# Copyright (c) 2000-2017, PostgreSQL Global Development Group use warnings; use strict; diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index b628c2811b..b25b3f1de0 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -3,7 +3,7 @@ * pl_comp.c - Compiler part of the PL/pgSQL * procedural language * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -29,6 +29,7 @@ #include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/memutils.h" +#include "utils/regproc.h" #include "utils/rel.h" #include "utils/syscache.h" @@ -93,7 +94,7 @@ static PLpgSQL_function *do_compile(FunctionCallInfo fcinfo, PLpgSQL_func_hashkey *hashkey, bool forValidator); static void plpgsql_compile_error_callback(void *arg); -static void add_parameter_name(int itemtype, int itemno, const char *name); +static void add_parameter_name(PLpgSQL_nsitem_type itemtype, int itemno, const char *name); static void add_dummy_return(PLpgSQL_function *function); static Node *plpgsql_pre_column_ref(ParseState *pstate, ColumnRef *cref); static Node *plpgsql_post_column_ref(ParseState *pstate, ColumnRef *cref, Node *var); @@ -340,9 +341,7 @@ do_compile(FunctionCallInfo fcinfo, */ func_cxt = AllocSetContextCreate(TopMemoryContext, "PL/pgSQL function context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); plpgsql_compile_tmp_cxt = MemoryContextSwitchTo(func_cxt); function->fn_signature = format_procedure(fcinfo->flinfo->fn_oid); @@ -412,7 +411,7 @@ do_compile(FunctionCallInfo fcinfo, char argmode = argmodes ? argmodes[i] : PROARGMODE_IN; PLpgSQL_type *argdtype; PLpgSQL_variable *argvariable; - int argitemtype; + PLpgSQL_nsitem_type argitemtype; /* Create $n name for variable */ snprintf(buf, sizeof(buf), "$%d", i + 1); @@ -829,10 +828,8 @@ plpgsql_compile_inline(char *proc_source) * its own memory context, so it can be reclaimed easily. */ func_cxt = AllocSetContextCreate(CurrentMemoryContext, - "PL/pgSQL function context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + "PL/pgSQL inline code context", + ALLOCSET_DEFAULT_SIZES); plpgsql_compile_tmp_cxt = MemoryContextSwitchTo(func_cxt); function->fn_signature = pstrdup(func_name); @@ -950,7 +947,7 @@ plpgsql_compile_error_callback(void *arg) * Add a name for a function parameter to the function's namespace */ static void -add_parameter_name(int itemtype, int itemno, const char *name) +add_parameter_name(PLpgSQL_nsitem_type itemtype, int itemno, const char *name) { /* * Before adding the name, check for duplicates. We need this even though @@ -2192,14 +2189,19 @@ build_datatype(HeapTuple typeTup, int32 typmod, Oid collation) /* NB: this is only used to decide whether to apply expand_array */ if (typeStruct->typtype == TYPTYPE_BASE) { - /* this test should match what get_element_type() checks */ + /* + * This test should include what get_element_type() checks. We also + * disallow non-toastable array types (i.e. oidvector and int2vector). + */ typ->typisarray = (typeStruct->typlen == -1 && - OidIsValid(typeStruct->typelem)); + OidIsValid(typeStruct->typelem) && + typeStruct->typstorage != 'p'); } else if (typeStruct->typtype == TYPTYPE_DOMAIN) { /* we can short-circuit looking up base types if it's not varlena */ typ->typisarray = (typeStruct->typlen == -1 && + typeStruct->typstorage != 'p' && OidIsValid(get_base_element_type(typeStruct->typbasetype))); } else diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 586ff1f329..b48146a362 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -3,7 +3,7 @@ * pl_exec.c - Executor for the PL/pgSQL * procedural language * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -48,7 +48,6 @@ typedef struct Oid *types; /* types of arguments */ Datum *values; /* evaluated argument values */ char *nulls; /* null markers (' '/'n' style) */ - bool *freevals; /* which arguments are pfree-able */ } PreparedParamsData; /* @@ -87,6 +86,36 @@ typedef struct SimpleEcontextStackEntry static EState *shared_simple_eval_estate = NULL; static SimpleEcontextStackEntry *simple_econtext_stack = NULL; +/* + * Memory management within a plpgsql function generally works with three + * contexts: + * + * 1. Function-call-lifespan data, such as variable values, is kept in the + * "main" context, a/k/a the "SPI Proc" context established by SPI_connect(). + * This is usually the CurrentMemoryContext while running code in this module + * (which is not good, because careless coding can easily cause + * function-lifespan memory leaks, but we live with it for now). + * + * 2. Some statement-execution routines need statement-lifespan workspace. + * A suitable context is created on-demand by get_stmt_mcontext(), and must + * be reset at the end of the requesting routine. Error recovery will clean + * it up automatically. Nested statements requiring statement-lifespan + * workspace will result in a stack of such contexts, see push_stmt_mcontext(). + * + * 3. We use the eval_econtext's per-tuple memory context for expression + * evaluation, and as a general-purpose workspace for short-lived allocations. + * Such allocations usually aren't explicitly freed, but are left to be + * cleaned up by a context reset, typically done by exec_eval_cleanup(). + * + * These macros are for use in making short-lived allocations: + */ +#define get_eval_mcontext(estate) \ + ((estate)->eval_econtext->ecxt_per_tuple_memory) +#define eval_mcontext_alloc(estate, sz) \ + MemoryContextAlloc(get_eval_mcontext(estate), sz) +#define eval_mcontext_alloc0(estate, sz) \ + MemoryContextAllocZero(get_eval_mcontext(estate), sz) + /* * We use a session-wide hash table for caching cast information. * @@ -128,6 +157,9 @@ static HTAB *shared_cast_hash = NULL; ************************************************************/ static void plpgsql_exec_error_callback(void *arg); static PLpgSQL_datum *copy_plpgsql_datum(PLpgSQL_datum *datum); +static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate); +static void push_stmt_mcontext(PLpgSQL_execstate *estate); +static void pop_stmt_mcontext(PLpgSQL_execstate *estate); static int exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block); @@ -191,7 +223,7 @@ static void exec_eval_cleanup(PLpgSQL_execstate *estate); static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions); static bool exec_simple_check_node(Node *node); -static void exec_simple_check_plan(PLpgSQL_expr *expr); +static void exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr); static void exec_simple_recheck_plan(PLpgSQL_expr *expr, CachedPlan *cplan); static void exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno); static bool contains_target_param(Node *node, int *target_dno); @@ -271,11 +303,9 @@ static void assign_text_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, const char *str); static PreparedParamsData *exec_eval_using_params(PLpgSQL_execstate *estate, List *params); -static void free_params_data(PreparedParamsData *ppd); static Portal exec_dynquery_with_params(PLpgSQL_execstate *estate, PLpgSQL_expr *dynquery, List *params, const char *portalname, int cursorOptions); - static char *format_expr_params(PLpgSQL_execstate *estate, const PLpgSQL_expr *expr); static char *format_preparedparamsdata(PLpgSQL_execstate *estate, @@ -562,6 +592,7 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo, /* Clean up any leftover temporary memory */ plpgsql_destroy_econtext(&estate); exec_eval_cleanup(&estate); + /* stmt_mcontext will be destroyed when function's main context is */ /* * Pop the error context stack @@ -832,6 +863,7 @@ plpgsql_exec_trigger(PLpgSQL_function *func, /* Clean up any leftover temporary memory */ plpgsql_destroy_econtext(&estate); exec_eval_cleanup(&estate); + /* stmt_mcontext will be destroyed when function's main context is */ /* * Pop the error context stack @@ -844,6 +876,11 @@ plpgsql_exec_trigger(PLpgSQL_function *func, return rettup; } +/* ---------- + * plpgsql_exec_event_trigger Called by the call handler for + * event trigger execution. + * ---------- + */ void plpgsql_exec_event_trigger(PLpgSQL_function *func, EventTriggerData *trigdata) { @@ -915,6 +952,7 @@ plpgsql_exec_event_trigger(PLpgSQL_function *func, EventTriggerData *trigdata) /* Clean up any leftover temporary memory */ plpgsql_destroy_econtext(&estate); exec_eval_cleanup(&estate); + /* stmt_mcontext will be destroyed when function's main context is */ /* * Pop the error context stack @@ -1041,7 +1079,62 @@ copy_plpgsql_datum(PLpgSQL_datum *datum) return result; } +/* + * Create a memory context for statement-lifespan variables, if we don't + * have one already. It will be a child of stmt_mcontext_parent, which is + * either the function's main context or a pushed-down outer stmt_mcontext. + */ +static MemoryContext +get_stmt_mcontext(PLpgSQL_execstate *estate) +{ + if (estate->stmt_mcontext == NULL) + { + estate->stmt_mcontext = + AllocSetContextCreate(estate->stmt_mcontext_parent, + "PLpgSQL per-statement data", + ALLOCSET_DEFAULT_SIZES); + } + return estate->stmt_mcontext; +} + +/* + * Push down the current stmt_mcontext so that called statements won't use it. + * This is needed by statements that have statement-lifespan data and need to + * preserve it across some inner statements. The caller should eventually do + * pop_stmt_mcontext(). + */ +static void +push_stmt_mcontext(PLpgSQL_execstate *estate) +{ + /* Should have done get_stmt_mcontext() first */ + Assert(estate->stmt_mcontext != NULL); + /* Assert we've not messed up the stack linkage */ + Assert(MemoryContextGetParent(estate->stmt_mcontext) == estate->stmt_mcontext_parent); + /* Push it down to become the parent of any nested stmt mcontext */ + estate->stmt_mcontext_parent = estate->stmt_mcontext; + /* And make it not available for use directly */ + estate->stmt_mcontext = NULL; +} +/* + * Undo push_stmt_mcontext(). We assume this is done just before or after + * resetting the caller's stmt_mcontext; since that action will also delete + * any child contexts, there's no need to explicitly delete whatever context + * might currently be estate->stmt_mcontext. + */ +static void +pop_stmt_mcontext(PLpgSQL_execstate *estate) +{ + /* We need only pop the stack */ + estate->stmt_mcontext = estate->stmt_mcontext_parent; + estate->stmt_mcontext_parent = MemoryContextGetParent(estate->stmt_mcontext); +} + + +/* + * Subroutine for exec_stmt_block: does any condition in the condition list + * match the current exception? + */ static bool exception_matches_conditions(ErrorData *edata, PLpgSQL_condition *cond) { @@ -1174,9 +1267,21 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block) ResourceOwner oldowner = CurrentResourceOwner; ExprContext *old_eval_econtext = estate->eval_econtext; ErrorData *save_cur_error = estate->cur_error; + MemoryContext stmt_mcontext; estate->err_text = gettext_noop("during statement block entry"); + /* + * We will need a stmt_mcontext to hold the error data if an error + * occurs. It seems best to force it to exist before entering the + * subtransaction, so that we reduce the risk of out-of-memory during + * error recovery, and because this greatly simplifies restoring the + * stmt_mcontext stack to the correct state after an error. We can + * ameliorate the cost of this by allowing the called statements to + * use this mcontext too; so we don't push it down here. + */ + stmt_mcontext = get_stmt_mcontext(estate); + BeginInternalSubTransaction(NULL); /* Want to run statements inside function's memory context */ MemoryContextSwitchTo(oldcontext); @@ -1202,7 +1307,9 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block) * If the block ended with RETURN, we may need to copy the return * value out of the subtransaction eval_context. This is * currently only needed for scalar result types --- rowtype - * values will always exist in the function's own memory context. + * values will always exist in the function's main memory context, + * cf. exec_stmt_return(). We can avoid a physical copy if the + * value happens to be a R/W expanded object. */ if (rc == PLPGSQL_RC_RETURN && !estate->retisset && @@ -1213,8 +1320,8 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block) bool resTypByVal; get_typlenbyval(estate->rettype, &resTypLen, &resTypByVal); - estate->retval = datumCopy(estate->retval, - resTypByVal, resTypLen); + estate->retval = datumTransfer(estate->retval, + resTypByVal, resTypLen); } /* Commit the inner transaction, return to outer xact context */ @@ -1222,17 +1329,14 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block) MemoryContextSwitchTo(oldcontext); CurrentResourceOwner = oldowner; + /* Assert that the stmt_mcontext stack is unchanged */ + Assert(stmt_mcontext == estate->stmt_mcontext); + /* * Revert to outer eval_econtext. (The inner one was * automatically cleaned up during subxact exit.) */ estate->eval_econtext = old_eval_econtext; - - /* - * AtEOSubXact_SPI() should not have popped any SPI context, but - * just in case it did, make sure we remain connected. - */ - SPI_restore_connection(); } PG_CATCH(); { @@ -1241,8 +1345,8 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block) estate->err_text = gettext_noop("during exception cleanup"); - /* Save error info */ - MemoryContextSwitchTo(oldcontext); + /* Save error info in our stmt_mcontext */ + MemoryContextSwitchTo(stmt_mcontext); edata = CopyErrorData(); FlushErrorState(); @@ -1251,15 +1355,28 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block) MemoryContextSwitchTo(oldcontext); CurrentResourceOwner = oldowner; - /* Revert to outer eval_econtext */ - estate->eval_econtext = old_eval_econtext; + /* + * Set up the stmt_mcontext stack as though we had restored our + * previous state and then done push_stmt_mcontext(). The push is + * needed so that statements in the exception handler won't + * clobber the error data that's in our stmt_mcontext. + */ + estate->stmt_mcontext_parent = stmt_mcontext; + estate->stmt_mcontext = NULL; /* - * If AtEOSubXact_SPI() popped any SPI context of the subxact, it - * will have left us in a disconnected state. We need this hack - * to return to connected state. + * Now we can delete any nested stmt_mcontexts that might have + * been created as children of ours. (Note: we do not immediately + * release any statement-lifespan data that might have been left + * behind in stmt_mcontext itself. We could attempt that by doing + * a MemoryContextReset on it before collecting the error data + * above, but it seems too risky to do any significant amount of + * work before collecting the error.) */ - SPI_restore_connection(); + MemoryContextDeleteChildren(stmt_mcontext); + + /* Revert to outer eval_econtext */ + estate->eval_econtext = old_eval_econtext; /* * Must clean up the econtext too. However, any tuple table made @@ -1319,8 +1436,10 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block) /* If no match found, re-throw the error */ if (e == NULL) ReThrowError(edata); - else - FreeErrorData(edata); + + /* Restore stmt_mcontext stack and release the error data */ + pop_stmt_mcontext(estate); + MemoryContextReset(stmt_mcontext); } PG_END_TRY(); @@ -1425,7 +1544,7 @@ exec_stmt(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt) CHECK_FOR_INTERRUPTS(); - switch ((enum PLpgSQL_stmt_types) stmt->cmd_type) + switch (stmt->cmd_type) { case PLPGSQL_STMT_BLOCK: rc = exec_stmt_block(estate, (PLpgSQL_stmt_block *) stmt); @@ -1663,11 +1782,15 @@ exec_stmt_getdiag(PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt) case PLPGSQL_GETDIAG_CONTEXT: { - char *contextstackstr = GetErrorContextStack(); + char *contextstackstr; + MemoryContext oldcontext; - exec_assign_c_string(estate, var, contextstackstr); + /* Use eval_mcontext for short-lived string */ + oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); + contextstackstr = GetErrorContextStack(); + MemoryContextSwitchTo(oldcontext); - pfree(contextstackstr); + exec_assign_c_string(estate, var, contextstackstr); } break; @@ -1677,6 +1800,8 @@ exec_stmt_getdiag(PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt) } } + exec_eval_cleanup(estate); + return PLPGSQL_RC_OK; } @@ -1738,7 +1863,10 @@ exec_stmt_case(PLpgSQL_execstate *estate, PLpgSQL_stmt_case *stmt) /* * When expected datatype is different from real, change it. Note that * what we're modifying here is an execution copy of the datum, so - * this doesn't affect the originally stored function parse tree. + * this doesn't affect the originally stored function parse tree. (In + * theory, if the expression datatype keeps changing during execution, + * this could cause a function-lifespan memory leak. Doesn't seem + * worth worrying about though.) */ if (t_var->datatype->typoid != t_typoid || t_var->datatype->atttypmod != t_typmod) @@ -2132,6 +2260,7 @@ static int exec_stmt_forc(PLpgSQL_execstate *estate, PLpgSQL_stmt_forc *stmt) { PLpgSQL_var *curvar; + MemoryContext stmt_mcontext = NULL; char *curname = NULL; PLpgSQL_expr *query; ParamListInfo paramLI; @@ -2146,7 +2275,14 @@ exec_stmt_forc(PLpgSQL_execstate *estate, PLpgSQL_stmt_forc *stmt) curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]); if (!curvar->isnull) { + MemoryContext oldcontext; + + /* We only need stmt_mcontext to hold the cursor name string */ + stmt_mcontext = get_stmt_mcontext(estate); + oldcontext = MemoryContextSwitchTo(stmt_mcontext); curname = TextDatumGetCString(curvar->value); + MemoryContextSwitchTo(oldcontext); + if (SPI_cursor_find(curname) != NULL) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_CURSOR), @@ -2216,16 +2352,19 @@ exec_stmt_forc(PLpgSQL_execstate *estate, PLpgSQL_stmt_forc *stmt) elog(ERROR, "could not open cursor: %s", SPI_result_code_string(SPI_result)); - /* don't need paramlist any more */ - if (paramLI) - pfree(paramLI); - /* * If cursor variable was NULL, store the generated portal name in it */ if (curname == NULL) assign_text_var(estate, curvar, portal->name); + /* + * Clean up before entering exec_for_query + */ + exec_eval_cleanup(estate); + if (stmt_mcontext) + MemoryContextReset(stmt_mcontext); + /* * Execute the loop. We can't prefetch because the cursor is accessible * to the user, for instance via UPDATE WHERE CURRENT OF within the loop. @@ -2241,9 +2380,6 @@ exec_stmt_forc(PLpgSQL_execstate *estate, PLpgSQL_stmt_forc *stmt) if (curname == NULL) assign_simple_var(estate, curvar, (Datum) 0, true, false); - if (curname) - pfree(curname); - return rc; } @@ -2266,6 +2402,8 @@ exec_stmt_foreach_a(PLpgSQL_execstate *estate, PLpgSQL_stmt_foreach_a *stmt) Oid loop_var_elem_type; bool found = false; int rc = PLPGSQL_RC_OK; + MemoryContext stmt_mcontext; + MemoryContext oldcontext; ArrayIterator array_iterator; Oid iterator_result_type; int32 iterator_result_typmod; @@ -2279,6 +2417,15 @@ exec_stmt_foreach_a(PLpgSQL_execstate *estate, PLpgSQL_stmt_foreach_a *stmt) (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("FOREACH expression must not be null"))); + /* + * Do as much as possible of the code below in stmt_mcontext, to avoid any + * leaks from called subroutines. We need a private stmt_mcontext since + * we'll be calling arbitrary statement code. + */ + stmt_mcontext = get_stmt_mcontext(estate); + push_stmt_mcontext(estate); + oldcontext = MemoryContextSwitchTo(stmt_mcontext); + /* check the type of the expression - must be an array */ if (!OidIsValid(get_element_type(arrtype))) ereport(ERROR, @@ -2287,9 +2434,9 @@ exec_stmt_foreach_a(PLpgSQL_execstate *estate, PLpgSQL_stmt_foreach_a *stmt) format_type_be(arrtype)))); /* - * We must copy the array, else it will disappear in exec_eval_cleanup. - * This is annoying, but cleanup will certainly happen while running the - * loop body, so we have little choice. + * We must copy the array into stmt_mcontext, else it will disappear in + * exec_eval_cleanup. This is annoying, but cleanup will certainly happen + * while running the loop body, so we have little choice. */ arr = DatumGetArrayTypePCopy(value); @@ -2355,6 +2502,9 @@ exec_stmt_foreach_a(PLpgSQL_execstate *estate, PLpgSQL_stmt_foreach_a *stmt) { found = true; /* looped at least once */ + /* exec_assign_value and exec_stmts must run in the main context */ + MemoryContextSwitchTo(oldcontext); + /* Assign current element/slice to the loop variable */ exec_assign_value(estate, loop_var, value, isnull, iterator_result_type, iterator_result_typmod); @@ -2413,11 +2563,16 @@ exec_stmt_foreach_a(PLpgSQL_execstate *estate, PLpgSQL_stmt_foreach_a *stmt) break; } } + + MemoryContextSwitchTo(stmt_mcontext); } + /* Restore memory context state */ + MemoryContextSwitchTo(oldcontext); + pop_stmt_mcontext(estate); + /* Release temporary memory, including the array value */ - array_free_iterator(array_iterator); - pfree(arr); + MemoryContextReset(stmt_mcontext); /* * Set the FOUND variable to indicate the result of executing the loop @@ -2465,6 +2620,13 @@ exec_stmt_exit(PLpgSQL_execstate *estate, PLpgSQL_stmt_exit *stmt) /* ---------- * exec_stmt_return Evaluate an expression and start * returning from the function. + * + * Note: in the retistuple code paths, the returned tuple is always in the + * function's main context, whereas for non-tuple data types the result may + * be in the eval_mcontext. The former case is not a memory leak since we're + * about to exit the function anyway. (If you want to change it, note that + * exec_stmt_block() knows about this behavior.) The latter case means that + * we must not do exec_eval_cleanup while unwinding the control stack. * ---------- */ static int @@ -2639,8 +2801,8 @@ exec_stmt_return_next(PLpgSQL_execstate *estate, { TupleDesc tupdesc; int natts; - HeapTuple tuple = NULL; - bool free_tuple = false; + HeapTuple tuple; + MemoryContext oldcontext; if (!estate->retisset) ereport(ERROR, @@ -2712,17 +2874,17 @@ exec_stmt_return_next(PLpgSQL_execstate *estate, rec->refname), errdetail("The tuple structure of a not-yet-assigned" " record is indeterminate."))); + + /* Use eval_mcontext for tuple conversion work */ + oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); tupmap = convert_tuples_by_position(rec->tupdesc, tupdesc, gettext_noop("wrong record type supplied in RETURN NEXT")); tuple = rec->tup; - /* it might need conversion */ if (tupmap) - { tuple = do_convert_tuple(tuple, tupmap); - free_conversion_map(tupmap); - free_tuple = true; - } + tuplestore_puttuple(estate->tuple_store, tuple); + MemoryContextSwitchTo(oldcontext); } break; @@ -2730,12 +2892,15 @@ exec_stmt_return_next(PLpgSQL_execstate *estate, { PLpgSQL_row *row = (PLpgSQL_row *) retvar; + /* Use eval_mcontext for tuple conversion work */ + oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); tuple = make_tuple_from_row(estate, row, tupdesc); if (tuple == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("wrong record type supplied in RETURN NEXT"))); - free_tuple = true; + tuplestore_puttuple(estate->tuple_store, tuple); + MemoryContextSwitchTo(oldcontext); } break; @@ -2770,24 +2935,17 @@ exec_stmt_return_next(PLpgSQL_execstate *estate, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("cannot return non-composite value from function returning composite type"))); + /* Use eval_mcontext for tuple conversion work */ + oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); tuple = get_tuple_from_datum(retval); - free_tuple = true; /* tuple is always freshly palloc'd */ - - /* it might need conversion */ retvaldesc = get_tupdesc_from_datum(retval); tupmap = convert_tuples_by_position(retvaldesc, tupdesc, gettext_noop("returned record type does not match expected record type")); if (tupmap) - { - HeapTuple newtuple; - - newtuple = do_convert_tuple(tuple, tupmap); - free_conversion_map(tupmap); - heap_freetuple(tuple); - tuple = newtuple; - } + tuple = do_convert_tuple(tuple, tupmap); + tuplestore_puttuple(estate->tuple_store, tuple); ReleaseTupleDesc(retvaldesc); - /* tuple will be stored into tuplestore below */ + MemoryContextSwitchTo(oldcontext); } else { @@ -2795,13 +2953,13 @@ exec_stmt_return_next(PLpgSQL_execstate *estate, Datum *nulldatums; bool *nullflags; - nulldatums = (Datum *) palloc0(natts * sizeof(Datum)); - nullflags = (bool *) palloc(natts * sizeof(bool)); + nulldatums = (Datum *) + eval_mcontext_alloc0(estate, natts * sizeof(Datum)); + nullflags = (bool *) + eval_mcontext_alloc(estate, natts * sizeof(bool)); memset(nullflags, true, natts * sizeof(bool)); tuplestore_putvalues(estate->tuple_store, tupdesc, nulldatums, nullflags); - pfree(nulldatums); - pfree(nullflags); } } else @@ -2832,14 +2990,6 @@ exec_stmt_return_next(PLpgSQL_execstate *estate, errmsg("RETURN NEXT must have a parameter"))); } - if (HeapTupleIsValid(tuple)) - { - tuplestore_puttuple(estate->tuple_store, tuple); - - if (free_tuple) - heap_freetuple(tuple); - } - exec_eval_cleanup(estate); return PLPGSQL_RC_OK; @@ -2858,6 +3008,7 @@ exec_stmt_return_query(PLpgSQL_execstate *estate, Portal portal; uint64 processed = 0; TupleConversionMap *tupmap; + MemoryContext oldcontext; if (!estate->retisset) ereport(ERROR, @@ -2881,6 +3032,9 @@ exec_stmt_return_query(PLpgSQL_execstate *estate, CURSOR_OPT_PARALLEL_OK); } + /* Use eval_mcontext for tuple conversion work */ + oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); + tupmap = convert_tuples_by_position(portal->tupDesc, estate->rettupdesc, gettext_noop("structure of query does not match function result type")); @@ -2890,6 +3044,10 @@ exec_stmt_return_query(PLpgSQL_execstate *estate, uint64 i; SPI_cursor_fetch(portal, true, 50); + + /* SPI will have changed CurrentMemoryContext */ + MemoryContextSwitchTo(get_eval_mcontext(estate)); + if (SPI_processed == 0) break; @@ -2908,12 +3066,12 @@ exec_stmt_return_query(PLpgSQL_execstate *estate, SPI_freetuptable(SPI_tuptable); } - if (tupmap) - free_conversion_map(tupmap); - SPI_freetuptable(SPI_tuptable); SPI_cursor_close(portal); + MemoryContextSwitchTo(oldcontext); + exec_eval_cleanup(estate); + estate->eval_processed = processed; exec_set_found(estate, processed != 0); @@ -2965,7 +3123,7 @@ do { \ (errcode(ERRCODE_SYNTAX_ERROR), \ errmsg("RAISE option already specified: %s", \ name))); \ - opt = pstrdup(extval); \ + opt = MemoryContextStrdup(stmt_mcontext, extval); \ } while (0) /* ---------- @@ -2985,6 +3143,7 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt) char *err_datatype = NULL; char *err_table = NULL; char *err_schema = NULL; + MemoryContext stmt_mcontext; ListCell *lc; /* RAISE with no parameters: re-throw current exception */ @@ -2999,10 +3158,13 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt) errmsg("RAISE without parameters cannot be used outside an exception handler"))); } + /* We'll need to accumulate the various strings in stmt_mcontext */ + stmt_mcontext = get_stmt_mcontext(estate); + if (stmt->condname) { err_code = plpgsql_recognize_err_condition(stmt->condname, true); - condname = pstrdup(stmt->condname); + condname = MemoryContextStrdup(stmt_mcontext, stmt->condname); } if (stmt->message) @@ -3010,8 +3172,13 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt) StringInfoData ds; ListCell *current_param; char *cp; + MemoryContext oldcontext; + /* build string in stmt_mcontext */ + oldcontext = MemoryContextSwitchTo(stmt_mcontext); initStringInfo(&ds); + MemoryContextSwitchTo(oldcontext); + current_param = list_head(stmt->params); for (cp = stmt->message; *cp; cp++) @@ -3064,7 +3231,6 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt) elog(ERROR, "unexpected RAISE parameter list length"); err_message = ds.data; - /* No pfree(ds.data), the pfree(err_message) does it */ } foreach(lc, stmt->options) @@ -3096,7 +3262,7 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt) errmsg("RAISE option already specified: %s", "ERRCODE"))); err_code = plpgsql_recognize_err_condition(extval, true); - condname = pstrdup(extval); + condname = MemoryContextStrdup(stmt_mcontext, extval); break; case PLPGSQL_RAISEOPTION_MESSAGE: SET_RAISE_OPTION_TEXT(err_message, "MESSAGE"); @@ -3142,7 +3308,8 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt) condname = NULL; } else - err_message = pstrdup(unpack_sql_state(err_code)); + err_message = MemoryContextStrdup(stmt_mcontext, + unpack_sql_state(err_code)); } /* @@ -3164,24 +3331,8 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt) (err_schema != NULL) ? err_generic_string(PG_DIAG_SCHEMA_NAME, err_schema) : 0)); - if (condname != NULL) - pfree(condname); - if (err_message != NULL) - pfree(err_message); - if (err_detail != NULL) - pfree(err_detail); - if (err_hint != NULL) - pfree(err_hint); - if (err_column != NULL) - pfree(err_column); - if (err_constraint != NULL) - pfree(err_constraint); - if (err_datatype != NULL) - pfree(err_datatype); - if (err_table != NULL) - pfree(err_table); - if (err_schema != NULL) - pfree(err_schema); + /* Clean up transient strings */ + MemoryContextReset(stmt_mcontext); return PLPGSQL_RC_OK; } @@ -3313,9 +3464,7 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate, { shared_cast_context = AllocSetContextCreate(TopMemoryContext, "PLpgSQL cast info", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); memset(&ctl, 0, sizeof(ctl)); ctl.keysize = sizeof(plpgsql_CastHashKey); ctl.entrysize = sizeof(plpgsql_CastHashEntry); @@ -3329,6 +3478,14 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate, estate->cast_hash_context = shared_cast_context; } + /* + * We start with no stmt_mcontext; one will be created only if needed. + * That context will be a direct child of the function's main execution + * context. Additional stmt_mcontexts might be created as children of it. + */ + estate->stmt_mcontext = NULL; + estate->stmt_mcontext_parent = CurrentMemoryContext; + estate->eval_tuptable = NULL; estate->eval_processed = 0; estate->eval_lastoid = InvalidOid; @@ -3378,7 +3535,10 @@ exec_eval_cleanup(PLpgSQL_execstate *estate) SPI_freetuptable(estate->eval_tuptable); estate->eval_tuptable = NULL; - /* Clear result of exec_eval_simple_expr (but keep the econtext) */ + /* + * Clear result of exec_eval_simple_expr (but keep the econtext). This + * also clears any short-lived allocations done via get_eval_mcontext. + */ if (estate->eval_econtext != NULL) ResetExprContext(estate->eval_econtext); } @@ -3430,7 +3590,7 @@ exec_prepare_plan(PLpgSQL_execstate *estate, expr->plan = plan; /* Check to see if it's a simple expression */ - exec_simple_check_plan(expr); + exec_simple_check_plan(estate, expr); /* * Mark expression as not using a read-write param. exec_assign_value has @@ -3443,6 +3603,9 @@ exec_prepare_plan(PLpgSQL_execstate *estate, /* ---------- * exec_stmt_execsql Execute an SQL statement (possibly with INTO). + * + * Note: some callers rely on this not touching stmt_mcontext. If it ever + * needs to use that, fix those callers to push/pop stmt_mcontext. * ---------- */ static int @@ -3675,6 +3838,7 @@ exec_stmt_dynexecute(PLpgSQL_execstate *estate, char *querystr; int exec_res; PreparedParamsData *ppd = NULL; + MemoryContext stmt_mcontext = get_stmt_mcontext(estate); /* * First we evaluate the string expression after the EXECUTE keyword. Its @@ -3689,8 +3853,8 @@ exec_stmt_dynexecute(PLpgSQL_execstate *estate, /* Get the C-String representation */ querystr = convert_value_to_string(estate, query, restype); - /* copy it out of the temporary context before we clean up */ - querystr = pstrdup(querystr); + /* copy it into the stmt_mcontext before we clean up */ + querystr = MemoryContextStrdup(stmt_mcontext, querystr); exec_eval_cleanup(estate); @@ -3843,12 +4007,9 @@ exec_stmt_dynexecute(PLpgSQL_execstate *estate, */ } - if (ppd) - free_params_data(ppd); - - /* Release any result from SPI_execute, as well as the querystring */ + /* Release any result from SPI_execute, as well as transient data */ SPI_freetuptable(SPI_tuptable); - pfree(querystr); + MemoryContextReset(stmt_mcontext); return PLPGSQL_RC_OK; } @@ -3892,6 +4053,7 @@ static int exec_stmt_open(PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt) { PLpgSQL_var *curvar; + MemoryContext stmt_mcontext = NULL; char *curname = NULL; PLpgSQL_expr *query; Portal portal; @@ -3905,7 +4067,14 @@ exec_stmt_open(PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt) curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]); if (!curvar->isnull) { + MemoryContext oldcontext; + + /* We only need stmt_mcontext to hold the cursor name string */ + stmt_mcontext = get_stmt_mcontext(estate); + oldcontext = MemoryContextSwitchTo(stmt_mcontext); curname = TextDatumGetCString(curvar->value); + MemoryContextSwitchTo(oldcontext); + if (SPI_cursor_find(curname) != NULL) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_CURSOR), @@ -3942,7 +4111,10 @@ exec_stmt_open(PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt) stmt->cursor_options); /* - * If cursor variable was NULL, store the generated portal name in it + * If cursor variable was NULL, store the generated portal name in it. + * Note: exec_dynquery_with_params already reset the stmt_mcontext, so + * curname is a dangling pointer here; but testing it for nullness is + * OK. */ if (curname == NULL) assign_text_var(estate, curvar, portal->name); @@ -4019,10 +4191,10 @@ exec_stmt_open(PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt) if (curname == NULL) assign_text_var(estate, curvar, portal->name); - if (curname) - pfree(curname); - if (paramLI) - pfree(paramLI); + /* If we had any transient data, clean it up */ + exec_eval_cleanup(estate); + if (stmt_mcontext) + MemoryContextReset(stmt_mcontext); return PLPGSQL_RC_OK; } @@ -4036,7 +4208,7 @@ exec_stmt_open(PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt) static int exec_stmt_fetch(PLpgSQL_execstate *estate, PLpgSQL_stmt_fetch *stmt) { - PLpgSQL_var *curvar = NULL; + PLpgSQL_var *curvar; PLpgSQL_rec *rec = NULL; PLpgSQL_row *row = NULL; long how_many = stmt->how_many; @@ -4044,6 +4216,7 @@ exec_stmt_fetch(PLpgSQL_execstate *estate, PLpgSQL_stmt_fetch *stmt) Portal portal; char *curname; uint64 n; + MemoryContext oldcontext; /* ---------- * Get the portal of the cursor by name @@ -4054,14 +4227,17 @@ exec_stmt_fetch(PLpgSQL_execstate *estate, PLpgSQL_stmt_fetch *stmt) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("cursor variable \"%s\" is null", curvar->refname))); + + /* Use eval_mcontext for short-lived string */ + oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); curname = TextDatumGetCString(curvar->value); + MemoryContextSwitchTo(oldcontext); portal = SPI_cursor_find(curname); if (portal == NULL) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_CURSOR), errmsg("cursor \"%s\" does not exist", curname))); - pfree(curname); /* Calculate position for FETCH_RELATIVE or FETCH_ABSOLUTE */ if (stmt->expr) @@ -4133,9 +4309,10 @@ exec_stmt_fetch(PLpgSQL_execstate *estate, PLpgSQL_stmt_fetch *stmt) static int exec_stmt_close(PLpgSQL_execstate *estate, PLpgSQL_stmt_close *stmt) { - PLpgSQL_var *curvar = NULL; + PLpgSQL_var *curvar; Portal portal; char *curname; + MemoryContext oldcontext; /* ---------- * Get the portal of the cursor by name @@ -4146,14 +4323,17 @@ exec_stmt_close(PLpgSQL_execstate *estate, PLpgSQL_stmt_close *stmt) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("cursor variable \"%s\" is null", curvar->refname))); + + /* Use eval_mcontext for short-lived string */ + oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); curname = TextDatumGetCString(curvar->value); + MemoryContextSwitchTo(oldcontext); portal = SPI_cursor_find(curname); if (portal == NULL) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_CURSOR), errmsg("cursor \"%s\" does not exist", curname))); - pfree(curname); /* ---------- * And close it. @@ -4201,6 +4381,9 @@ exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target, * exec_assign_c_string Put a C string into a text variable. * * We take a NULL pointer as signifying empty string, not SQL null. + * + * As with the underlying exec_assign_value, caller is expected to do + * exec_eval_cleanup later. * ---------- */ static void @@ -4208,21 +4391,25 @@ exec_assign_c_string(PLpgSQL_execstate *estate, PLpgSQL_datum *target, const char *str) { text *value; + MemoryContext oldcontext; + /* Use eval_mcontext for short-lived text value */ + oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); if (str != NULL) value = cstring_to_text(str); else value = cstring_to_text(""); + MemoryContextSwitchTo(oldcontext); + exec_assign_value(estate, target, PointerGetDatum(value), false, TEXTOID, -1); - pfree(value); } /* ---------- * exec_assign_value Put a value into a target datum * - * Note: in some code paths, this will leak memory in the eval_econtext; + * Note: in some code paths, this will leak memory in the eval_mcontext; * we assume that will be cleaned up later by exec_eval_cleanup. We cannot * call exec_eval_cleanup here for fear of destroying the input Datum value. * ---------- @@ -4259,10 +4446,10 @@ exec_assign_value(PLpgSQL_execstate *estate, /* * If type is by-reference, copy the new value (which is - * probably in the eval_econtext) into the procedure's memory - * context. But if it's a read/write reference to an expanded - * object, no physical copy needs to happen; at most we need - * to reparent the object's memory context. + * probably in the eval_mcontext) into the procedure's main + * memory context. But if it's a read/write reference to an + * expanded object, no physical copy needs to happen; at most + * we need to reparent the object's memory context. * * If it's an array, we force the value to be stored in R/W * expanded form. This wins if the function later does, say, @@ -4362,10 +4549,9 @@ exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_rec *rec; int fno; HeapTuple newtup; - int natts; - Datum *values; - bool *nulls; - bool *replaces; + int colnums[1]; + Datum values[1]; + bool nulls[1]; Oid atttype; int32 atttypmod; @@ -4384,9 +4570,8 @@ exec_assign_value(PLpgSQL_execstate *estate, errdetail("The tuple structure of a not-yet-assigned record is indeterminate."))); /* - * Get the number of the records field to change and the - * number of attributes in the tuple. Note: disallow system - * column names because the code below won't cope. + * Get the number of the record field to change. Disallow + * system columns because the code below won't cope. */ fno = SPI_fnumber(rec->tupdesc, recfield->fieldname); if (fno <= 0) @@ -4394,42 +4579,25 @@ exec_assign_value(PLpgSQL_execstate *estate, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("record \"%s\" has no field \"%s\"", rec->refname, recfield->fieldname))); - fno--; - natts = rec->tupdesc->natts; - - /* - * Set up values/control arrays for heap_modify_tuple. For all - * the attributes except the one we want to replace, use the - * value that's in the old tuple. - */ - values = palloc(sizeof(Datum) * natts); - nulls = palloc(sizeof(bool) * natts); - replaces = palloc(sizeof(bool) * natts); - - memset(replaces, false, sizeof(bool) * natts); - replaces[fno] = true; + colnums[0] = fno; /* * Now insert the new value, being careful to cast it to the * right type. */ - atttype = rec->tupdesc->attrs[fno]->atttypid; - atttypmod = rec->tupdesc->attrs[fno]->atttypmod; - values[fno] = exec_cast_value(estate, - value, - &isNull, - valtype, - valtypmod, - atttype, - atttypmod); - nulls[fno] = isNull; - - /* - * Now call heap_modify_tuple() to create a new tuple that - * replaces the old one in the record. - */ - newtup = heap_modify_tuple(rec->tup, rec->tupdesc, - values, nulls, replaces); + atttype = rec->tupdesc->attrs[fno - 1]->atttypid; + atttypmod = rec->tupdesc->attrs[fno - 1]->atttypmod; + values[0] = exec_cast_value(estate, + value, + &isNull, + valtype, + valtypmod, + atttype, + atttypmod); + nulls[0] = isNull; + + newtup = heap_modify_tuple_by_cols(rec->tup, rec->tupdesc, + 1, colnums, values, nulls); if (rec->freetup) heap_freetuple(rec->tup); @@ -4437,10 +4605,6 @@ exec_assign_value(PLpgSQL_execstate *estate, rec->tup = newtup; rec->freetup = true; - pfree(values); - pfree(nulls); - pfree(replaces); - break; } @@ -4601,7 +4765,7 @@ exec_assign_value(PLpgSQL_execstate *estate, return; /* empty array, if any, and newarraydatum are short-lived */ - oldcontext = MemoryContextSwitchTo(estate->eval_econtext->ecxt_per_tuple_memory); + oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); if (oldarrayisnull) oldarraydatum = PointerGetDatum(construct_empty_array(arrayelem->elemtypoid)); @@ -4655,7 +4819,7 @@ exec_assign_value(PLpgSQL_execstate *estate, * responsibility that the results are semantically OK. * * In some cases we have to palloc a return value, and in such cases we put - * it into the estate's short-term memory context. + * it into the estate's eval_mcontext. */ static void exec_eval_datum(PLpgSQL_execstate *estate, @@ -4689,7 +4853,7 @@ exec_eval_datum(PLpgSQL_execstate *estate, elog(ERROR, "row variable has no tupdesc"); /* Make sure we have a valid type/typmod setting */ BlessTupleDesc(row->rowtupdesc); - oldcontext = MemoryContextSwitchTo(estate->eval_econtext->ecxt_per_tuple_memory); + oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); tup = make_tuple_from_row(estate, row, row->rowtupdesc); if (tup == NULL) /* should not happen */ elog(ERROR, "row not compatible with its own tupdesc"); @@ -4715,7 +4879,7 @@ exec_eval_datum(PLpgSQL_execstate *estate, /* Make sure we have a valid type/typmod setting */ BlessTupleDesc(rec->tupdesc); - oldcontext = MemoryContextSwitchTo(estate->eval_econtext->ecxt_per_tuple_memory); + oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); *typeid = rec->tupdesc->tdtypeid; *typetypmod = rec->tupdesc->tdtypmod; *value = heap_copy_tuple_as_datum(rec->tup, rec->tupdesc); @@ -5107,8 +5271,7 @@ exec_run_select(PLpgSQL_execstate *estate, if (*portalP == NULL) elog(ERROR, "could not open implicit cursor for query \"%s\": %s", expr->query, SPI_result_code_string(SPI_result)); - if (paramLI) - pfree(paramLI); + exec_eval_cleanup(estate); return SPI_OK_CURSOR; } @@ -5323,9 +5486,8 @@ exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt, * give correct results if that happens, and it's unlikely to be worth the * cycles to check. * - * Note: if pass-by-reference, the result is in the eval_econtext's - * temporary memory context. It will be freed when exec_eval_cleanup - * is done. + * Note: if pass-by-reference, the result is in the eval_mcontext. + * It will be freed when exec_eval_cleanup is done. * ---------- */ static bool @@ -5357,9 +5519,12 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate, /* * Revalidate cached plan, so that we will notice if it became stale. (We - * need to hold a refcount while using the plan, anyway.) + * need to hold a refcount while using the plan, anyway.) If replanning + * is needed, do that work in the eval_mcontext. */ + oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); cplan = SPI_plan_get_cached_plan(expr->plan); + MemoryContextSwitchTo(oldcontext); /* * We can't get a failure here, because the number of CachedPlanSources in @@ -5409,9 +5574,7 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate, * Without this, stable functions within the expression would fail to see * updates made so far by our own function. */ - SPI_push(); - - oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); + oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); if (!estate->readonly_func) { CommandCounterIncrement(); @@ -5443,14 +5606,12 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate, */ *result = ExecEvalExpr(expr->expr_simple_state, econtext, - isNull, - NULL); + isNull); /* Assorted cleanup */ expr->expr_simple_in_use = false; - if (paramLI && paramLI != estate->paramLI) - pfree(paramLI); + econtext->ecxt_param_list_info = NULL; estate->paramLI->parserSetupArg = save_setup_arg; @@ -5459,8 +5620,6 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate, MemoryContextSwitchTo(oldcontext); - SPI_pop(); - /* * Now we can release our refcount on the cached plan. */ @@ -5498,8 +5657,8 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate, * throw errors (for example "no such record field") and we do not want that * to happen in a part of the expression that might never be evaluated at * runtime. For another thing, exec_eval_datum() may return short-lived - * values stored in the estate's short-term memory context, which will not - * necessarily survive to the next SPI operation. And for a third thing, ROW + * values stored in the estate's eval_mcontext, which will not necessarily + * survive to the next SPI operation. And for a third thing, ROW * and RECFIELD datums' values depend on other datums, and we don't have a * cheap way to track that. Therefore, param slots for non-VAR datum types * are always reset here and then filled on-demand by plpgsql_param_fetch(). @@ -5598,7 +5757,7 @@ setup_param_list(PLpgSQL_execstate *estate, PLpgSQL_expr *expr) * to some trusted function. We don't want the R/W pointer to get into the * shared param list, where it could get passed to some less-trusted function. * - * Caller should pfree the result after use, if it's not NULL. + * The result, if not NULL, is in the estate's eval_mcontext. * * XXX. Could we use ParamListInfo's new paramMask to avoid creating unshared * parameter lists? @@ -5626,8 +5785,9 @@ setup_unshared_param_list(PLpgSQL_execstate *estate, PLpgSQL_expr *expr) /* initialize ParamListInfo with one entry per datum, all invalid */ paramLI = (ParamListInfo) - palloc0(offsetof(ParamListInfoData, params) + - estate->ndatums * sizeof(ParamExternData)); + eval_mcontext_alloc0(estate, + offsetof(ParamListInfoData, params) + + estate->ndatums * sizeof(ParamExternData)); paramLI->paramFetch = plpgsql_param_fetch; paramLI->paramFetchArg = (void *) estate; paramLI->parserSetup = (ParserSetupHook) plpgsql_parser_setup; @@ -5784,12 +5944,11 @@ exec_move_row(PLpgSQL_execstate *estate, /* If we have a tupdesc but no data, form an all-nulls tuple */ bool *nulls; - nulls = (bool *) palloc(tupdesc->natts * sizeof(bool)); + nulls = (bool *) + eval_mcontext_alloc(estate, tupdesc->natts * sizeof(bool)); memset(nulls, true, tupdesc->natts * sizeof(bool)); tup = heap_form_tuple(tupdesc, NULL, nulls); - - pfree(nulls); } if (tupdesc) @@ -5907,6 +6066,9 @@ exec_move_row(PLpgSQL_execstate *estate, * make_tuple_from_row Make a tuple from the values of a row object * * A NULL return indicates rowtype mismatch; caller must raise suitable error + * + * The result tuple is freshly palloc'd in caller's context. Some junk + * may be left behind in eval_mcontext, too. * ---------- */ static HeapTuple @@ -5923,8 +6085,8 @@ make_tuple_from_row(PLpgSQL_execstate *estate, if (natts != row->nfields) return NULL; - dvalues = (Datum *) palloc0(natts * sizeof(Datum)); - nulls = (bool *) palloc(natts * sizeof(bool)); + dvalues = (Datum *) eval_mcontext_alloc0(estate, natts * sizeof(Datum)); + nulls = (bool *) eval_mcontext_alloc(estate, natts * sizeof(bool)); for (i = 0; i < natts; i++) { @@ -5949,16 +6111,13 @@ make_tuple_from_row(PLpgSQL_execstate *estate, tuple = heap_form_tuple(tupdesc, dvalues, nulls); - pfree(dvalues); - pfree(nulls); - return tuple; } /* ---------- * get_tuple_from_datum extract a tuple from a composite Datum * - * Returns a freshly palloc'd HeapTuple. + * Returns a HeapTuple, freshly palloc'd in caller's context. * * Note: it's caller's responsibility to be sure value is of composite type. * ---------- @@ -6041,7 +6200,7 @@ exec_move_row_from_datum(PLpgSQL_execstate *estate, /* ---------- * convert_value_to_string Convert a non-null Datum to C string * - * Note: the result is in the estate's eval_econtext, and will be cleared + * Note: the result is in the estate's eval_mcontext, and will be cleared * by the next exec_eval_cleanup() call. The invoked output function might * leave additional cruft there as well, so just pfree'ing the result string * would not be enough to avoid memory leaks if we did not do it like this. @@ -6061,7 +6220,7 @@ convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype) Oid typoutput; bool typIsVarlena; - oldcontext = MemoryContextSwitchTo(estate->eval_econtext->ecxt_per_tuple_memory); + oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); getTypeOutputInfo(valtype, &typoutput, &typIsVarlena); result = OidOutputFunctionCall(typoutput, value); MemoryContextSwitchTo(oldcontext); @@ -6076,7 +6235,7 @@ convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype) * unlikely that a cast operation would produce null from non-null or vice * versa, that could happen in principle. * - * Note: the estate's eval_econtext is used for temporary storage, and may + * Note: the estate's eval_mcontext is used for temporary storage, and may * also contain the result Datum if we have to do a conversion to a pass- * by-reference data type. Be sure to do an exec_eval_cleanup() call when * done with the result. @@ -6104,7 +6263,7 @@ exec_cast_value(PLpgSQL_execstate *estate, ExprContext *econtext = estate->eval_econtext; MemoryContext oldcontext; - oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); + oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); econtext->caseValue_datum = value; econtext->caseValue_isNull = *isnull; @@ -6112,7 +6271,7 @@ exec_cast_value(PLpgSQL_execstate *estate, cast_entry->cast_in_use = true; value = ExecEvalExpr(cast_entry->cast_exprstate, econtext, - isnull, NULL); + isnull); cast_entry->cast_in_use = false; @@ -6161,10 +6320,10 @@ get_cast_hashentry(PLpgSQL_execstate *estate, /* * Since we could easily fail (no such coercion), construct a - * temporary coercion expression tree in a short-lived context, then - * if successful copy it to cast_hash_context. + * temporary coercion expression tree in the short-lived + * eval_mcontext, then if successful copy it to cast_hash_context. */ - oldcontext = MemoryContextSwitchTo(estate->eval_econtext->ecxt_per_tuple_memory); + oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); /* * We use a CaseTestExpr as the base of the coercion tree, since it's @@ -6494,6 +6653,9 @@ exec_simple_check_node(Node *node) return TRUE; } + case T_SQLValueFunction: + return TRUE; + case T_XmlExpr: { XmlExpr *expr = (XmlExpr *) node; @@ -6545,12 +6707,13 @@ exec_simple_check_node(Node *node) * ---------- */ static void -exec_simple_check_plan(PLpgSQL_expr *expr) +exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr) { List *plansources; CachedPlanSource *plansource; Query *query; CachedPlan *cplan; + MemoryContext oldcontext; /* * Initialize to "not simple", and remember the plan generation number we @@ -6599,6 +6762,7 @@ exec_simple_check_plan(PLpgSQL_expr *expr) */ if (query->hasAggs || query->hasWindowFuncs || + query->hasTargetSRFs || query->hasSubLinks || query->hasForUpdate || query->cteList || @@ -6621,10 +6785,13 @@ exec_simple_check_plan(PLpgSQL_expr *expr) /* * OK, it seems worth constructing a plan for more careful checking. + * + * Get the generic plan for the query. If replanning is needed, do that + * work in the eval_mcontext. */ - - /* Get the generic plan for the query */ + oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); cplan = SPI_plan_get_cached_plan(expr->plan); + MemoryContextSwitchTo(oldcontext); /* Can't fail, because we checked for a single CachedPlanSource above */ Assert(cplan != NULL); @@ -6659,12 +6826,11 @@ exec_simple_recheck_plan(PLpgSQL_expr *expr, CachedPlan *cplan) if (list_length(cplan->stmt_list) != 1) return; stmt = (PlannedStmt *) linitial(cplan->stmt_list); + Assert(IsA(stmt, PlannedStmt)); /* * 2. It must be a RESULT plan --> no scan's required */ - if (!IsA(stmt, PlannedStmt)) - return; if (stmt->commandType != CMD_SELECT) return; plan = stmt->planTree; @@ -7008,23 +7174,30 @@ assign_text_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, const char *str) /* * exec_eval_using_params --- evaluate params of USING clause + * + * The result data structure is created in the stmt_mcontext, and should + * be freed by resetting that context. */ static PreparedParamsData * exec_eval_using_params(PLpgSQL_execstate *estate, List *params) { PreparedParamsData *ppd; + MemoryContext stmt_mcontext = get_stmt_mcontext(estate); int nargs; int i; ListCell *lc; - ppd = (PreparedParamsData *) palloc(sizeof(PreparedParamsData)); + ppd = (PreparedParamsData *) + MemoryContextAlloc(stmt_mcontext, sizeof(PreparedParamsData)); nargs = list_length(params); ppd->nargs = nargs; - ppd->types = (Oid *) palloc(nargs * sizeof(Oid)); - ppd->values = (Datum *) palloc(nargs * sizeof(Datum)); - ppd->nulls = (char *) palloc(nargs * sizeof(char)); - ppd->freevals = (bool *) palloc(nargs * sizeof(bool)); + ppd->types = (Oid *) + MemoryContextAlloc(stmt_mcontext, nargs * sizeof(Oid)); + ppd->values = (Datum *) + MemoryContextAlloc(stmt_mcontext, nargs * sizeof(Datum)); + ppd->nulls = (char *) + MemoryContextAlloc(stmt_mcontext, nargs * sizeof(char)); i = 0; foreach(lc, params) @@ -7032,13 +7205,15 @@ exec_eval_using_params(PLpgSQL_execstate *estate, List *params) PLpgSQL_expr *param = (PLpgSQL_expr *) lfirst(lc); bool isnull; int32 ppdtypmod; + MemoryContext oldcontext; ppd->values[i] = exec_eval_expr(estate, param, &isnull, &ppd->types[i], &ppdtypmod); ppd->nulls[i] = isnull ? 'n' : ' '; - ppd->freevals[i] = false; + + oldcontext = MemoryContextSwitchTo(stmt_mcontext); if (ppd->types[i] == UNKNOWNOID) { @@ -7051,12 +7226,9 @@ exec_eval_using_params(PLpgSQL_execstate *estate, List *params) */ ppd->types[i] = TEXTOID; if (!isnull) - { ppd->values[i] = CStringGetTextDatum(DatumGetCString(ppd->values[i])); - ppd->freevals[i] = true; - } } - /* pass-by-ref non null values must be copied into plpgsql context */ + /* pass-by-ref non null values must be copied into stmt_mcontext */ else if (!isnull) { int16 typLen; @@ -7064,12 +7236,11 @@ exec_eval_using_params(PLpgSQL_execstate *estate, List *params) get_typlenbyval(ppd->types[i], &typLen, &typByVal); if (!typByVal) - { ppd->values[i] = datumCopy(ppd->values[i], typByVal, typLen); - ppd->freevals[i] = true; - } } + MemoryContextSwitchTo(oldcontext); + exec_eval_cleanup(estate); i++; @@ -7078,30 +7249,13 @@ exec_eval_using_params(PLpgSQL_execstate *estate, List *params) return ppd; } -/* - * free_params_data --- pfree all pass-by-reference values used in USING clause - */ -static void -free_params_data(PreparedParamsData *ppd) -{ - int i; - - for (i = 0; i < ppd->nargs; i++) - { - if (ppd->freevals[i]) - pfree(DatumGetPointer(ppd->values[i])); - } - - pfree(ppd->types); - pfree(ppd->values); - pfree(ppd->nulls); - pfree(ppd->freevals); - - pfree(ppd); -} - /* * Open portal for dynamic query + * + * Caution: this resets the stmt_mcontext at exit. We might eventually need + * to move that responsibility to the callers, but currently no caller needs + * to have statement-lifetime temp data that survives past this, so it's + * simpler to do it here. */ static Portal exec_dynquery_with_params(PLpgSQL_execstate *estate, @@ -7116,6 +7270,7 @@ exec_dynquery_with_params(PLpgSQL_execstate *estate, Oid restype; int32 restypmod; char *querystr; + MemoryContext stmt_mcontext = get_stmt_mcontext(estate); /* * Evaluate the string expression after the EXECUTE keyword. Its result is @@ -7130,8 +7285,8 @@ exec_dynquery_with_params(PLpgSQL_execstate *estate, /* Get the C-String representation */ querystr = convert_value_to_string(estate, query, restype); - /* copy it out of the temporary context before we clean up */ - querystr = pstrdup(querystr); + /* copy it into the stmt_mcontext before we clean up */ + querystr = MemoryContextStrdup(stmt_mcontext, querystr); exec_eval_cleanup(estate); @@ -7151,7 +7306,6 @@ exec_dynquery_with_params(PLpgSQL_execstate *estate, ppd->values, ppd->nulls, estate->readonly_func, cursorOptions); - free_params_data(ppd); } else { @@ -7166,7 +7320,9 @@ exec_dynquery_with_params(PLpgSQL_execstate *estate, if (portal == NULL) elog(ERROR, "could not open implicit cursor for query \"%s\": %s", querystr, SPI_result_code_string(SPI_result)); - pfree(querystr); + + /* Release transient data */ + MemoryContextReset(stmt_mcontext); return portal; } @@ -7174,6 +7330,7 @@ exec_dynquery_with_params(PLpgSQL_execstate *estate, /* * Return a formatted string with information about an expression's parameters, * or NULL if the expression does not take any parameters. + * The result is in the eval_mcontext. */ static char * format_expr_params(PLpgSQL_execstate *estate, @@ -7182,10 +7339,13 @@ format_expr_params(PLpgSQL_execstate *estate, int paramno; int dno; StringInfoData paramstr; + MemoryContext oldcontext; if (!expr->paramnos) return NULL; + oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); + initStringInfo(¶mstr); paramno = 0; dno = -1; @@ -7227,12 +7387,15 @@ format_expr_params(PLpgSQL_execstate *estate, paramno++; } + MemoryContextSwitchTo(oldcontext); + return paramstr.data; } /* * Return a formatted string with information about PreparedParamsData, or NULL * if there are no parameters. + * The result is in the eval_mcontext. */ static char * format_preparedparamsdata(PLpgSQL_execstate *estate, @@ -7240,10 +7403,13 @@ format_preparedparamsdata(PLpgSQL_execstate *estate, { int paramno; StringInfoData paramstr; + MemoryContext oldcontext; if (!ppd) return NULL; + oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); + initStringInfo(¶mstr); for (paramno = 0; paramno < ppd->nargs; paramno++) { @@ -7269,5 +7435,7 @@ format_preparedparamsdata(PLpgSQL_execstate *estate, } } + MemoryContextSwitchTo(oldcontext); + return paramstr.data; } diff --git a/src/pl/plpgsql/src/pl_funcs.c b/src/pl/plpgsql/src/pl_funcs.c index 27ebebce1e..906fe0148d 100644 --- a/src/pl/plpgsql/src/pl_funcs.c +++ b/src/pl/plpgsql/src/pl_funcs.c @@ -3,7 +3,7 @@ * pl_funcs.c - Misc functions for the PL/pgSQL * procedural language * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -51,7 +51,7 @@ plpgsql_ns_init(void) * ---------- */ void -plpgsql_ns_push(const char *label, enum PLpgSQL_label_types label_type) +plpgsql_ns_push(const char *label, PLpgSQL_label_type label_type) { if (label == NULL) label = ""; @@ -89,7 +89,7 @@ plpgsql_ns_top(void) * ---------- */ void -plpgsql_ns_additem(int itemtype, int itemno, const char *name) +plpgsql_ns_additem(PLpgSQL_nsitem_type itemtype, int itemno, const char *name) { PLpgSQL_nsitem *nse; @@ -231,7 +231,7 @@ plpgsql_ns_find_nearest_loop(PLpgSQL_nsitem *ns_cur) const char * plpgsql_stmt_typename(PLpgSQL_stmt *stmt) { - switch ((enum PLpgSQL_stmt_types) stmt->cmd_type) + switch (stmt->cmd_type) { case PLPGSQL_STMT_BLOCK: return _("statement block"); @@ -291,7 +291,7 @@ plpgsql_stmt_typename(PLpgSQL_stmt *stmt) * GET DIAGNOSTICS item name as a string, for use in error messages etc. */ const char * -plpgsql_getdiag_kindname(int kind) +plpgsql_getdiag_kindname(PLpgSQL_getdiag_kind kind) { switch (kind) { @@ -367,7 +367,7 @@ static void free_expr(PLpgSQL_expr *expr); static void free_stmt(PLpgSQL_stmt *stmt) { - switch ((enum PLpgSQL_stmt_types) stmt->cmd_type) + switch (stmt->cmd_type) { case PLPGSQL_STMT_BLOCK: free_block((PLpgSQL_stmt_block *) stmt); @@ -791,7 +791,7 @@ static void dump_stmt(PLpgSQL_stmt *stmt) { printf("%3d:", stmt->lineno); - switch ((enum PLpgSQL_stmt_types) stmt->cmd_type) + switch (stmt->cmd_type) { case PLPGSQL_STMT_BLOCK: dump_block((PLpgSQL_stmt_block *) stmt); diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y index 0b41e3acb6..4a4cd6ae26 100644 --- a/src/pl/plpgsql/src/pl_gram.y +++ b/src/pl/plpgsql/src/pl_gram.y @@ -3,7 +3,7 @@ * * pl_gram.y - Parser for the PL/pgSQL procedural language * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -180,10 +180,11 @@ static void check_raise_parameters(PLpgSQL_stmt_raise *stmt); %type expr_until_then expr_until_loop opt_expr_until_when %type opt_exitcond -%type assign_var foreach_slice +%type assign_var %type cursor_variable %type decl_cursor_arg %type for_variable +%type foreach_slice %type for_control %type any_identifier opt_block_label opt_loop_label opt_label @@ -209,7 +210,8 @@ static void check_raise_parameters(PLpgSQL_stmt_raise *stmt); %type getdiag_area_opt %type getdiag_list %type getdiag_list_item -%type getdiag_item getdiag_target +%type getdiag_target +%type getdiag_item %type opt_scrollable %type opt_fetch_direction @@ -916,7 +918,7 @@ stmt_assign : assign_var assign_operator expr_until_semi new = palloc0(sizeof(PLpgSQL_stmt_assign)); new->cmd_type = PLPGSQL_STMT_ASSIGN; new->lineno = plpgsql_location_to_lineno(@1); - new->varno = $1; + new->varno = $1->dno; new->expr = $3; $$ = (PLpgSQL_stmt *)new; @@ -1014,7 +1016,7 @@ getdiag_list_item : getdiag_target assign_operator getdiag_item PLpgSQL_diag_item *new; new = palloc(sizeof(PLpgSQL_diag_item)); - new->target = $1; + new->target = $1->dno; new->kind = $3; $$ = new; @@ -1069,17 +1071,16 @@ getdiag_item : } ; -getdiag_target : T_DATUM +getdiag_target : assign_var { - check_assignable($1.datum, @1); - if ($1.datum->dtype == PLPGSQL_DTYPE_ROW || - $1.datum->dtype == PLPGSQL_DTYPE_REC) + if ($1->dtype == PLPGSQL_DTYPE_ROW || + $1->dtype == PLPGSQL_DTYPE_REC) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("\"%s\" is not a scalar variable", - NameOfDatum(&($1))), + ((PLpgSQL_variable *) $1)->refname), parser_errposition(@1))); - $$ = $1.datum->dno; + $$ = $1; } | T_WORD { @@ -1097,7 +1098,7 @@ getdiag_target : T_DATUM assign_var : T_DATUM { check_assignable($1.datum, @1); - $$ = $1.datum->dno; + $$ = $1.datum; } | assign_var '[' expr_until_rightbracket { @@ -1106,13 +1107,13 @@ assign_var : T_DATUM new = palloc0(sizeof(PLpgSQL_arrayelem)); new->dtype = PLPGSQL_DTYPE_ARRAYELEM; new->subscript = $3; - new->arrayparentno = $1; + new->arrayparentno = $1->dno; /* initialize cached type data to "not valid" */ new->parenttypoid = InvalidOid; plpgsql_adddatum((PLpgSQL_datum *) new); - $$ = new->dno; + $$ = (PLpgSQL_datum *) new; } ; @@ -2173,7 +2174,13 @@ stmt_null : K_NULL ';' cursor_variable : T_DATUM { - if ($1.datum->dtype != PLPGSQL_DTYPE_VAR) + /* + * In principle we should support a cursor_variable + * that is an array element, but for now we don't, so + * just throw an error if next token is '['. + */ + if ($1.datum->dtype != PLPGSQL_DTYPE_VAR || + plpgsql_peek() == '[') ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("cursor variable must be a simple variable"), diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c index 36868fb273..e15be5d9ac 100644 --- a/src/pl/plpgsql/src/pl_handler.c +++ b/src/pl/plpgsql/src/pl_handler.c @@ -3,7 +3,7 @@ * pl_handler.c - Handler for the PL/pgSQL * procedural language * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -24,6 +24,7 @@ #include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/syscache.h" +#include "utils/varlena.h" static bool plpgsql_extra_checks_check_hook(char **newvalue, void **extra, GucSource source); diff --git a/src/pl/plpgsql/src/pl_scanner.c b/src/pl/plpgsql/src/pl_scanner.c index 2737fff3fb..c40121308b 100644 --- a/src/pl/plpgsql/src/pl_scanner.c +++ b/src/pl/plpgsql/src/pl_scanner.c @@ -4,7 +4,7 @@ * lexical scanning for PL/pgSQL * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index 140bf4badd..3421eed74f 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -3,7 +3,7 @@ * plpgsql.h - Definitions for the PL/pgSQL * procedural language * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -34,34 +34,31 @@ #undef _ #define _(x) dgettext(TEXTDOMAIN, x) -/* ---------- +/* * Compiler's namespace item types - * ---------- */ -enum +typedef enum PLpgSQL_nsitem_type { PLPGSQL_NSTYPE_LABEL, PLPGSQL_NSTYPE_VAR, PLPGSQL_NSTYPE_ROW, PLPGSQL_NSTYPE_REC -}; +} PLpgSQL_nsitem_type; -/* ---------- +/* * A PLPGSQL_NSTYPE_LABEL stack entry must be one of these types - * ---------- */ -enum PLpgSQL_label_types +typedef enum PLpgSQL_label_type { PLPGSQL_LABEL_BLOCK, /* DECLARE/BEGIN block */ PLPGSQL_LABEL_LOOP, /* looping construct */ PLPGSQL_LABEL_OTHER /* anything else */ -}; +} PLpgSQL_label_type; -/* ---------- +/* * Datum array node types - * ---------- */ -enum +typedef enum PLpgSQL_datum_type { PLPGSQL_DTYPE_VAR, PLPGSQL_DTYPE_ROW, @@ -69,25 +66,23 @@ enum PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_ARRAYELEM, PLPGSQL_DTYPE_EXPR -}; +} PLpgSQL_datum_type; -/* ---------- +/* * Variants distinguished in PLpgSQL_type structs - * ---------- */ -enum +typedef enum PLpgSQL_type_type { PLPGSQL_TTYPE_SCALAR, /* scalar types and domains */ PLPGSQL_TTYPE_ROW, /* composite types */ PLPGSQL_TTYPE_REC, /* RECORD pseudotype */ PLPGSQL_TTYPE_PSEUDO /* other pseudotypes */ -}; +} PLpgSQL_type_type; -/* ---------- +/* * Execution tree node types - * ---------- */ -enum PLpgSQL_stmt_types +typedef enum PLpgSQL_stmt_type { PLPGSQL_STMT_BLOCK, PLPGSQL_STMT_ASSIGN, @@ -113,12 +108,10 @@ enum PLpgSQL_stmt_types PLPGSQL_STMT_FETCH, PLPGSQL_STMT_CLOSE, PLPGSQL_STMT_PERFORM -}; +} PLpgSQL_stmt_type; - -/* ---------- +/* * Execution node return codes - * ---------- */ enum { @@ -128,11 +121,10 @@ enum PLPGSQL_RC_CONTINUE }; -/* ---------- +/* * GET DIAGNOSTICS information items - * ---------- */ -enum +typedef enum PLpgSQL_getdiag_kind { PLPGSQL_GETDIAG_ROW_COUNT, PLPGSQL_GETDIAG_RESULT_OID, @@ -147,13 +139,12 @@ enum PLPGSQL_GETDIAG_MESSAGE_TEXT, PLPGSQL_GETDIAG_TABLE_NAME, PLPGSQL_GETDIAG_SCHEMA_NAME -}; +} PLpgSQL_getdiag_kind; -/* -------- +/* * RAISE statement options - * -------- */ -enum +typedef enum PLpgSQL_raise_option_type { PLPGSQL_RAISEOPTION_ERRCODE, PLPGSQL_RAISEOPTION_MESSAGE, @@ -164,13 +155,12 @@ enum PLPGSQL_RAISEOPTION_DATATYPE, PLPGSQL_RAISEOPTION_TABLE, PLPGSQL_RAISEOPTION_SCHEMA -}; +} PLpgSQL_raise_option_type; -/* -------- +/* * Behavioral modes for plpgsql variable resolution - * -------- */ -typedef enum +typedef enum PLpgSQL_resolve_option { PLPGSQL_RESOLVE_ERROR, /* throw error if ambiguous */ PLPGSQL_RESOLVE_VARIABLE, /* prefer plpgsql var to table column */ @@ -182,12 +172,14 @@ typedef enum * Node and structure definitions **********************************************************************/ - -typedef struct -{ /* Postgres data type */ +/* + * Postgres data type + */ +typedef struct PLpgSQL_type +{ char *typname; /* (simple) name of the type */ Oid typoid; /* OID of the data type */ - int ttype; /* PLPGSQL_TTYPE_ code */ + PLpgSQL_type_type ttype; /* PLPGSQL_TTYPE_ code */ int16 typlen; /* stuff copied from its pg_type entry */ bool typbyval; char typtype; @@ -197,32 +189,38 @@ typedef struct int32 atttypmod; /* typmod (taken from someplace else) */ } PLpgSQL_type; - /* + * Generic datum array item + * * PLpgSQL_datum is the common supertype for PLpgSQL_expr, PLpgSQL_var, * PLpgSQL_row, PLpgSQL_rec, PLpgSQL_recfield, and PLpgSQL_arrayelem */ -typedef struct -{ /* Generic datum array item */ - int dtype; +typedef struct PLpgSQL_datum +{ + PLpgSQL_datum_type dtype; int dno; } PLpgSQL_datum; /* + * Scalar or composite variable + * * The variants PLpgSQL_var, PLpgSQL_row, and PLpgSQL_rec share these * fields */ -typedef struct -{ /* Scalar or composite variable */ - int dtype; +typedef struct PLpgSQL_variable +{ + PLpgSQL_datum_type dtype; int dno; char *refname; int lineno; } PLpgSQL_variable; +/* + * SQL Query to plan and execute + */ typedef struct PLpgSQL_expr -{ /* SQL Query to plan and execute */ - int dtype; +{ + PLpgSQL_datum_type dtype; int dno; char *query; SPIPlanPtr plan; @@ -252,10 +250,12 @@ typedef struct PLpgSQL_expr LocalTransactionId expr_simple_lxid; } PLpgSQL_expr; - -typedef struct -{ /* Scalar variable */ - int dtype; +/* + * Scalar variable + */ +typedef struct PLpgSQL_var +{ + PLpgSQL_datum_type dtype; int dno; char *refname; int lineno; @@ -273,19 +273,20 @@ typedef struct bool freeval; } PLpgSQL_var; - -typedef struct -{ /* Row variable */ - int dtype; +/* + * Row variable + */ +typedef struct PLpgSQL_row +{ + PLpgSQL_datum_type dtype; int dno; char *refname; int lineno; + /* Note: TupleDesc is only set up for named rowtypes, else it is NULL. */ TupleDesc rowtupdesc; /* - * Note: TupleDesc is only set up for named rowtypes, else it is NULL. - * * Note: if the underlying rowtype contains a dropped column, the * corresponding fieldnames[] entry will be NULL, and there is no * corresponding var (varnos[] will be -1). @@ -295,10 +296,12 @@ typedef struct int *varnos; } PLpgSQL_row; - -typedef struct -{ /* Record variable (non-fixed structure) */ - int dtype; +/* + * Record variable (non-fixed structure) + */ +typedef struct PLpgSQL_rec +{ + PLpgSQL_datum_type dtype; int dno; char *refname; int lineno; @@ -309,22 +312,27 @@ typedef struct bool freetupdesc; } PLpgSQL_rec; - -typedef struct -{ /* Field in record */ - int dtype; +/* + * Field in record + */ +typedef struct PLpgSQL_recfield +{ + PLpgSQL_datum_type dtype; int dno; char *fieldname; int recparentno; /* dno of parent record */ } PLpgSQL_recfield; - -typedef struct -{ /* Element of array variable */ - int dtype; +/* + * Element of array variable + */ +typedef struct PLpgSQL_arrayelem +{ + PLpgSQL_datum_type dtype; int dno; PLpgSQL_expr *subscript; int arrayparentno; /* dno of parent array variable */ + /* Remaining fields are cached info about the array variable's type */ Oid parenttypoid; /* type of array variable; 0 if not yet set */ int32 parenttypmod; /* typmod of array variable */ @@ -337,50 +345,66 @@ typedef struct char elemtypalign; /* typalign of element type */ } PLpgSQL_arrayelem; - +/* + * Item in the compilers namespace tree + */ typedef struct PLpgSQL_nsitem -{ /* Item in the compilers namespace tree */ - int itemtype; +{ + PLpgSQL_nsitem_type itemtype; + /* + * For labels, itemno is a value of enum PLpgSQL_label_type. For other + * itemtypes, itemno is the associated PLpgSQL_datum's dno. + */ int itemno; - /* For labels, itemno is a value of enum PLpgSQL_label_types. */ - /* For other itemtypes, itemno is the associated PLpgSQL_datum's dno. */ struct PLpgSQL_nsitem *prev; char name[FLEXIBLE_ARRAY_MEMBER]; /* nul-terminated string */ } PLpgSQL_nsitem; - -typedef struct -{ /* Generic execution node */ - int cmd_type; +/* + * Generic execution node + */ +typedef struct PLpgSQL_stmt +{ + PLpgSQL_stmt_type cmd_type; int lineno; } PLpgSQL_stmt; - +/* + * One EXCEPTION condition name + */ typedef struct PLpgSQL_condition -{ /* One EXCEPTION condition name */ +{ int sqlerrstate; /* SQLSTATE code */ char *condname; /* condition name (for debugging) */ struct PLpgSQL_condition *next; } PLpgSQL_condition; -typedef struct +/* + * EXCEPTION block + */ +typedef struct PLpgSQL_exception_block { int sqlstate_varno; int sqlerrm_varno; List *exc_list; /* List of WHEN clauses */ } PLpgSQL_exception_block; -typedef struct -{ /* One EXCEPTION ... WHEN clause */ +/* + * One EXCEPTION ... WHEN clause + */ +typedef struct PLpgSQL_exception +{ int lineno; PLpgSQL_condition *conditions; List *action; /* List of statements */ } PLpgSQL_exception; - -typedef struct -{ /* Block of statements */ - int cmd_type; +/* + * Block of statements + */ +typedef struct PLpgSQL_stmt_block +{ + PLpgSQL_stmt_type cmd_type; int lineno; char *label; List *body; /* List of statements */ @@ -389,40 +413,53 @@ typedef struct PLpgSQL_exception_block *exceptions; } PLpgSQL_stmt_block; - -typedef struct -{ /* Assign statement */ - int cmd_type; +/* + * Assign statement + */ +typedef struct PLpgSQL_stmt_assign +{ + PLpgSQL_stmt_type cmd_type; int lineno; int varno; PLpgSQL_expr *expr; } PLpgSQL_stmt_assign; -typedef struct -{ /* PERFORM statement */ - int cmd_type; +/* + * PERFORM statement + */ +typedef struct PLpgSQL_stmt_perform +{ + PLpgSQL_stmt_type cmd_type; int lineno; PLpgSQL_expr *expr; } PLpgSQL_stmt_perform; -typedef struct -{ /* Get Diagnostics item */ - int kind; /* id for diagnostic value desired */ +/* + * GET DIAGNOSTICS item + */ +typedef struct PLpgSQL_diag_item +{ + PLpgSQL_getdiag_kind kind; /* id for diagnostic value desired */ int target; /* where to assign it */ } PLpgSQL_diag_item; -typedef struct -{ /* Get Diagnostics statement */ - int cmd_type; +/* + * GET DIAGNOSTICS statement + */ +typedef struct PLpgSQL_stmt_getdiag +{ + PLpgSQL_stmt_type cmd_type; int lineno; bool is_stacked; /* STACKED or CURRENT diagnostics area? */ List *diag_items; /* List of PLpgSQL_diag_item */ } PLpgSQL_stmt_getdiag; - -typedef struct -{ /* IF statement */ - int cmd_type; +/* + * IF statement + */ +typedef struct PLpgSQL_stmt_if +{ + PLpgSQL_stmt_type cmd_type; int lineno; PLpgSQL_expr *cond; /* boolean expression for THEN */ List *then_body; /* List of statements */ @@ -430,17 +467,22 @@ typedef struct List *else_body; /* List of statements */ } PLpgSQL_stmt_if; -typedef struct /* one ELSIF arm of IF statement */ +/* + * one ELSIF arm of IF statement + */ +typedef struct PLpgSQL_if_elsif { int lineno; PLpgSQL_expr *cond; /* boolean expression for this case */ List *stmts; /* List of statements */ } PLpgSQL_if_elsif; - -typedef struct /* CASE statement */ +/* + * CASE statement + */ +typedef struct PLpgSQL_stmt_case { - int cmd_type; + PLpgSQL_stmt_type cmd_type; int lineno; PLpgSQL_expr *t_expr; /* test expression, or NULL if none */ int t_varno; /* var to store test expression value into */ @@ -449,36 +491,45 @@ typedef struct /* CASE statement */ List *else_stmts; /* List of statements */ } PLpgSQL_stmt_case; -typedef struct /* one arm of CASE statement */ +/* + * one arm of CASE statement + */ +typedef struct PLpgSQL_case_when { int lineno; PLpgSQL_expr *expr; /* boolean expression for this case */ List *stmts; /* List of statements */ } PLpgSQL_case_when; - -typedef struct -{ /* Unconditional LOOP statement */ - int cmd_type; +/* + * Unconditional LOOP statement + */ +typedef struct PLpgSQL_stmt_loop +{ + PLpgSQL_stmt_type cmd_type; int lineno; char *label; List *body; /* List of statements */ } PLpgSQL_stmt_loop; - -typedef struct -{ /* WHILE cond LOOP statement */ - int cmd_type; +/* + * WHILE cond LOOP statement + */ +typedef struct PLpgSQL_stmt_while +{ + PLpgSQL_stmt_type cmd_type; int lineno; char *label; PLpgSQL_expr *cond; List *body; /* List of statements */ } PLpgSQL_stmt_while; - -typedef struct -{ /* FOR statement with integer loopvar */ - int cmd_type; +/* + * FOR statement with integer loopvar + */ +typedef struct PLpgSQL_stmt_fori +{ + PLpgSQL_stmt_type cmd_type; int lineno; char *label; PLpgSQL_var *var; @@ -489,15 +540,14 @@ typedef struct List *body; /* List of statements */ } PLpgSQL_stmt_fori; - /* * PLpgSQL_stmt_forq represents a FOR statement running over a SQL query. * It is the common supertype of PLpgSQL_stmt_fors, PLpgSQL_stmt_forc * and PLpgSQL_dynfors. */ -typedef struct +typedef struct PLpgSQL_stmt_forq { - int cmd_type; + PLpgSQL_stmt_type cmd_type; int lineno; char *label; PLpgSQL_rec *rec; @@ -505,9 +555,12 @@ typedef struct List *body; /* List of statements */ } PLpgSQL_stmt_forq; -typedef struct -{ /* FOR statement running over SELECT */ - int cmd_type; +/* + * FOR statement running over SELECT + */ +typedef struct PLpgSQL_stmt_fors +{ + PLpgSQL_stmt_type cmd_type; int lineno; char *label; PLpgSQL_rec *rec; @@ -517,9 +570,12 @@ typedef struct PLpgSQL_expr *query; } PLpgSQL_stmt_fors; -typedef struct -{ /* FOR statement running over cursor */ - int cmd_type; +/* + * FOR statement running over cursor + */ +typedef struct PLpgSQL_stmt_forc +{ + PLpgSQL_stmt_type cmd_type; int lineno; char *label; PLpgSQL_rec *rec; @@ -530,9 +586,12 @@ typedef struct PLpgSQL_expr *argquery; /* cursor arguments if any */ } PLpgSQL_stmt_forc; -typedef struct -{ /* FOR statement running over EXECUTE */ - int cmd_type; +/* + * FOR statement running over EXECUTE + */ +typedef struct PLpgSQL_stmt_dynfors +{ + PLpgSQL_stmt_type cmd_type; int lineno; char *label; PLpgSQL_rec *rec; @@ -543,10 +602,12 @@ typedef struct List *params; /* USING expressions */ } PLpgSQL_stmt_dynfors; - -typedef struct -{ /* FOREACH item in array loop */ - int cmd_type; +/* + * FOREACH item in array loop + */ +typedef struct PLpgSQL_stmt_foreach_a +{ + PLpgSQL_stmt_type cmd_type; int lineno; char *label; int varno; /* loop target variable */ @@ -555,10 +616,12 @@ typedef struct List *body; /* List of statements */ } PLpgSQL_stmt_foreach_a; - -typedef struct -{ /* OPEN a curvar */ - int cmd_type; +/* + * OPEN a curvar + */ +typedef struct PLpgSQL_stmt_open +{ + PLpgSQL_stmt_type cmd_type; int lineno; int curvar; int cursor_options; @@ -569,10 +632,12 @@ typedef struct List *params; /* USING expressions */ } PLpgSQL_stmt_open; - -typedef struct -{ /* FETCH or MOVE statement */ - int cmd_type; +/* + * FETCH or MOVE statement + */ +typedef struct PLpgSQL_stmt_fetch +{ + PLpgSQL_stmt_type cmd_type; int lineno; PLpgSQL_rec *rec; /* target, as record or row */ PLpgSQL_row *row; @@ -584,53 +649,68 @@ typedef struct bool returns_multiple_rows; /* can return more than one row? */ } PLpgSQL_stmt_fetch; - -typedef struct -{ /* CLOSE curvar */ - int cmd_type; +/* + * CLOSE curvar + */ +typedef struct PLpgSQL_stmt_close +{ + PLpgSQL_stmt_type cmd_type; int lineno; int curvar; } PLpgSQL_stmt_close; - -typedef struct -{ /* EXIT or CONTINUE statement */ - int cmd_type; +/* + * EXIT or CONTINUE statement + */ +typedef struct PLpgSQL_stmt_exit +{ + PLpgSQL_stmt_type cmd_type; int lineno; bool is_exit; /* Is this an exit or a continue? */ char *label; /* NULL if it's an unlabelled EXIT/CONTINUE */ PLpgSQL_expr *cond; } PLpgSQL_stmt_exit; - -typedef struct -{ /* RETURN statement */ - int cmd_type; +/* + * RETURN statement + */ +typedef struct PLpgSQL_stmt_return +{ + PLpgSQL_stmt_type cmd_type; int lineno; PLpgSQL_expr *expr; int retvarno; } PLpgSQL_stmt_return; -typedef struct -{ /* RETURN NEXT statement */ - int cmd_type; +/* + * RETURN NEXT statement + */ +typedef struct PLpgSQL_stmt_return_next +{ + PLpgSQL_stmt_type cmd_type; int lineno; PLpgSQL_expr *expr; int retvarno; } PLpgSQL_stmt_return_next; -typedef struct -{ /* RETURN QUERY statement */ - int cmd_type; +/* + * RETURN QUERY statement + */ +typedef struct PLpgSQL_stmt_return_query +{ + PLpgSQL_stmt_type cmd_type; int lineno; PLpgSQL_expr *query; /* if static query */ PLpgSQL_expr *dynquery; /* if dynamic query (RETURN QUERY EXECUTE) */ List *params; /* USING arguments for dynamic query */ } PLpgSQL_stmt_return_query; -typedef struct -{ /* RAISE statement */ - int cmd_type; +/* + * RAISE statement + */ +typedef struct PLpgSQL_stmt_raise +{ + PLpgSQL_stmt_type cmd_type; int lineno; int elog_level; char *condname; /* condition name, SQLSTATE, or NULL */ @@ -639,37 +719,48 @@ typedef struct List *options; /* list of PLpgSQL_raise_option */ } PLpgSQL_stmt_raise; -typedef struct -{ /* RAISE statement option */ - int opt_type; +/* + * RAISE statement option + */ +typedef struct PLpgSQL_raise_option +{ + PLpgSQL_raise_option_type opt_type; PLpgSQL_expr *expr; } PLpgSQL_raise_option; -typedef struct -{ /* ASSERT statement */ - int cmd_type; +/* + * ASSERT statement + */ +typedef struct PLpgSQL_stmt_assert +{ + PLpgSQL_stmt_type cmd_type; int lineno; PLpgSQL_expr *cond; PLpgSQL_expr *message; } PLpgSQL_stmt_assert; -typedef struct -{ /* Generic SQL statement to execute */ - int cmd_type; +/* + * Generic SQL statement to execute + */ +typedef struct PLpgSQL_stmt_execsql +{ + PLpgSQL_stmt_type cmd_type; int lineno; PLpgSQL_expr *sqlstmt; - bool mod_stmt; /* is the stmt INSERT/UPDATE/DELETE? */ - /* note: mod_stmt is set when we plan the query */ + bool mod_stmt; /* is the stmt INSERT/UPDATE/DELETE? Note: + mod_stmt is set when we plan the query */ bool into; /* INTO supplied? */ bool strict; /* INTO STRICT flag */ PLpgSQL_rec *rec; /* INTO target, if record */ PLpgSQL_row *row; /* INTO target, if row */ } PLpgSQL_stmt_execsql; - -typedef struct -{ /* Dynamic SQL string to execute */ - int cmd_type; +/* + * Dynamic SQL string to execute + */ +typedef struct PLpgSQL_stmt_dynexecute +{ + PLpgSQL_stmt_type cmd_type; int lineno; PLpgSQL_expr *query; /* string expression */ bool into; /* INTO supplied? */ @@ -679,9 +770,11 @@ typedef struct List *params; /* USING expressions */ } PLpgSQL_stmt_dynexecute; - +/* + * Hash lookup key for functions + */ typedef struct PLpgSQL_func_hashkey -{ /* Hash lookup key for functions */ +{ Oid funcOid; bool isTrigger; /* true if called as a trigger */ @@ -710,6 +803,9 @@ typedef struct PLpgSQL_func_hashkey Oid argtypes[FUNC_MAX_ARGS]; } PLpgSQL_func_hashkey; +/* + * Trigger type + */ typedef enum PLpgSQL_trigtype { PLPGSQL_DML_TRIGGER, @@ -717,8 +813,11 @@ typedef enum PLpgSQL_trigtype PLPGSQL_NOT_TRIGGER } PLpgSQL_trigtype; +/* + * Complete compiled function + */ typedef struct PLpgSQL_function -{ /* Complete compiled function */ +{ char *fn_signature; Oid fn_oid; TransactionId fn_xmin; @@ -777,9 +876,11 @@ typedef struct PLpgSQL_function unsigned long use_count; } PLpgSQL_function; - +/* + * Runtime execution data + */ typedef struct PLpgSQL_execstate -{ /* Runtime execution data */ +{ PLpgSQL_function *func; /* function being executed */ Datum retval; @@ -814,10 +915,14 @@ typedef struct PLpgSQL_execstate /* EState to use for "simple" expression evaluation */ EState *simple_eval_estate; - /* Lookup table to use for executing type casts */ + /* lookup table to use for executing type casts */ HTAB *cast_hash; MemoryContext cast_hash_context; + /* memory context for statement-lifespan temporary values */ + MemoryContext stmt_mcontext; /* current stmt context, or NULL if none */ + MemoryContext stmt_mcontext_parent; /* parent of current context */ + /* temporary state for results from evaluation of query or expr */ SPITupleTable *eval_tuptable; uint64 eval_processed; @@ -831,7 +936,6 @@ typedef struct PLpgSQL_execstate void *plugin_info; /* reserved for use by optional plugin */ } PLpgSQL_execstate; - /* * A PLpgSQL_plugin structure represents an instrumentation plugin. * To instrument PL/pgSQL, a plugin library must access the rendezvous @@ -846,24 +950,23 @@ typedef struct PLpgSQL_execstate * (if the pointers are non-NULL) to give the plugin a chance to watch * what we are doing. * - * func_setup is called when we start a function, before we've initialized - * the local variables defined by the function. + * func_setup is called when we start a function, before we've initialized + * the local variables defined by the function. * - * func_beg is called when we start a function, after we've initialized - * the local variables. + * func_beg is called when we start a function, after we've initialized + * the local variables. * - * func_end is called at the end of a function. + * func_end is called at the end of a function. * - * stmt_beg and stmt_end are called before and after (respectively) each - * statement. + * stmt_beg and stmt_end are called before and after (respectively) each + * statement. * * Also, immediately before any call to func_setup, PL/pgSQL fills in the * error_callback and assign_expr fields with pointers to its own * plpgsql_exec_error_callback and exec_assign_expr functions. This is * a somewhat ad-hoc expedient to simplify life for debugger plugins. */ - -typedef struct +typedef struct PLpgSQL_plugin { /* Function pointers set up by the plugin */ void (*func_setup) (PLpgSQL_execstate *estate, PLpgSQL_function *func); @@ -878,21 +981,22 @@ typedef struct PLpgSQL_expr *expr); } PLpgSQL_plugin; +/* + * Struct types used during parsing + */ -/* Struct types used during parsing */ - -typedef struct +typedef struct PLword { char *ident; /* palloc'd converted identifier */ bool quoted; /* Was it double-quoted? */ } PLword; -typedef struct +typedef struct PLcword { List *idents; /* composite identifiers (list of String) */ } PLcword; -typedef struct +typedef struct PLwdatum { PLpgSQL_datum *datum; /* referenced variable */ char *ident; /* valid if simple name */ @@ -946,9 +1050,8 @@ extern PLpgSQL_plugin **plpgsql_plugin_ptr; * Function declarations **********************************************************************/ -/* ---------- +/* * Functions in pl_comp.c - * ---------- */ extern PLpgSQL_function *plpgsql_compile(FunctionCallInfo fcinfo, bool forValidator); @@ -979,15 +1082,13 @@ extern void plpgsql_adddatum(PLpgSQL_datum *new); extern int plpgsql_add_initdatums(int **varnos); extern void plpgsql_HashTableInit(void); -/* ---------- +/* * Functions in pl_handler.c - * ---------- */ extern void _PG_init(void); -/* ---------- +/* * Functions in pl_exec.c - * ---------- */ extern Datum plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo, @@ -1005,16 +1106,15 @@ extern void plpgsql_exec_get_datum_type_info(PLpgSQL_execstate *estate, PLpgSQL_datum *datum, Oid *typeid, int32 *typmod, Oid *collation); -/* ---------- +/* * Functions for namespace handling in pl_funcs.c - * ---------- */ extern void plpgsql_ns_init(void); extern void plpgsql_ns_push(const char *label, - enum PLpgSQL_label_types label_type); + PLpgSQL_label_type label_type); extern void plpgsql_ns_pop(void); extern PLpgSQL_nsitem *plpgsql_ns_top(void); -extern void plpgsql_ns_additem(int itemtype, int itemno, const char *name); +extern void plpgsql_ns_additem(PLpgSQL_nsitem_type itemtype, int itemno, const char *name); extern PLpgSQL_nsitem *plpgsql_ns_lookup(PLpgSQL_nsitem *ns_cur, bool localmode, const char *name1, const char *name2, const char *name3, int *names_used); @@ -1022,18 +1122,16 @@ extern PLpgSQL_nsitem *plpgsql_ns_lookup_label(PLpgSQL_nsitem *ns_cur, const char *name); extern PLpgSQL_nsitem *plpgsql_ns_find_nearest_loop(PLpgSQL_nsitem *ns_cur); -/* ---------- +/* * Other functions in pl_funcs.c - * ---------- */ extern const char *plpgsql_stmt_typename(PLpgSQL_stmt *stmt); -extern const char *plpgsql_getdiag_kindname(int kind); +extern const char *plpgsql_getdiag_kindname(PLpgSQL_getdiag_kind kind); extern void plpgsql_free_function_memory(PLpgSQL_function *func); extern void plpgsql_dumptree(PLpgSQL_function *func); -/* ---------- +/* * Scanner functions in pl_scanner.c - * ---------- */ extern int plpgsql_base_yylex(void); extern int plpgsql_yylex(void); @@ -1051,9 +1149,8 @@ extern int plpgsql_latest_lineno(void); extern void plpgsql_scanner_init(const char *str); extern void plpgsql_scanner_finish(void); -/* ---------- +/* * Externs in gram.y - * ---------- */ extern int plpgsql_yyparse(void); diff --git a/src/pl/plpython/Makefile b/src/pl/plpython/Makefile index 647b4b1b96..7680d49cb6 100644 --- a/src/pl/plpython/Makefile +++ b/src/pl/plpython/Makefile @@ -95,7 +95,9 @@ REGRESS_PLPYTHON3_MANGLE := $(REGRESS) include $(top_srcdir)/src/Makefile.shlib -all: submake-generated-headers all-lib +all: all-lib + +$(OBJS): | submake-generated-headers install: all install-lib install-data diff --git a/src/pl/plpython/expected/plpython_composite.out b/src/pl/plpython/expected/plpython_composite.out index 0ef0c21235..7fc6a928e7 100644 --- a/src/pl/plpython/expected/plpython_composite.out +++ b/src/pl/plpython/expected/plpython_composite.out @@ -465,13 +465,13 @@ SELECT * FROM changing_test(); -- tables of composite types CREATE FUNCTION composite_types_table(OUT tab table_record[], OUT typ type_record[] ) RETURNS SETOF record AS $$ -yield {'tab': [['first', 1], ['second', 2]], +yield {'tab': [('first', 1), ('second', 2)], 'typ': [{'first': 'third', 'second': 3}, {'first': 'fourth', 'second': 4}]} -yield {'tab': [['first', 1], ['second', 2]], +yield {'tab': [('first', 1), ('second', 2)], 'typ': [{'first': 'third', 'second': 3}, {'first': 'fourth', 'second': 4}]} -yield {'tab': [['first', 1], ['second', 2]], +yield {'tab': [('first', 1), ('second', 2)], 'typ': [{'first': 'third', 'second': 3}, {'first': 'fourth', 'second': 4}]} $$ LANGUAGE plpythonu; @@ -569,3 +569,26 @@ SELECT * FROM return_record_2('v3') AS (v1 int, v2 int, v3 int); 1 | 2 | 3 (1 row) +-- multi-dimensional array of composite types. +CREATE FUNCTION composite_type_as_list() RETURNS type_record[] AS $$ + return [[('first', 1), ('second', 1)], [('first', 2), ('second', 2)], [('first', 3), ('second', 3)]]; +$$ LANGUAGE plpythonu; +SELECT * FROM composite_type_as_list(); + composite_type_as_list +------------------------------------------------------------------------------------ + {{"(first,1)","(second,1)"},{"(first,2)","(second,2)"},{"(first,3)","(second,3)"}} +(1 row) + +-- Starting with PostgreSQL 10, a composite type in an array cannot be +-- represented as a Python list, because it's ambiguous with multi-dimensional +-- arrays. So this throws an error now. The error should contain a useful hint +-- on the issue. +CREATE FUNCTION composite_type_as_list_broken() RETURNS type_record[] AS $$ + return [['first', 1]]; +$$ LANGUAGE plpythonu; +SELECT * FROM composite_type_as_list_broken(); +ERROR: malformed record literal: "first" +DETAIL: Missing left parenthesis. +HINT: To return a composite type in an array, return the composite type as a Python tuple, e.g. "[('foo')]" +CONTEXT: while creating return value +PL/Python function "composite_type_as_list_broken" diff --git a/src/pl/plpython/expected/plpython_setof.out b/src/pl/plpython/expected/plpython_setof.out index 308d2abb7f..170dbc394d 100644 --- a/src/pl/plpython/expected/plpython_setof.out +++ b/src/pl/plpython/expected/plpython_setof.out @@ -147,11 +147,8 @@ SELECT ugly(1,3), ugly(7,8); ------+------ 1 | 7 2 | 8 - 3 | 7 - 1 | 8 - 2 | 7 - 3 | 8 -(6 rows) + 3 | +(3 rows) -- returns set of named-composite-type tuples CREATE OR REPLACE FUNCTION get_user_records() diff --git a/src/pl/plpython/expected/plpython_spi.out b/src/pl/plpython/expected/plpython_spi.out index dbde36f841..0d78ca1de4 100644 --- a/src/pl/plpython/expected/plpython_spi.out +++ b/src/pl/plpython/expected/plpython_spi.out @@ -220,8 +220,8 @@ SELECT result_len_test($$UPDATE foo3 SET b= '' WHERE a = 2$$); CREATE FUNCTION result_subscript_test() RETURNS void AS $$ -result = plpy.execute("SELECT 1 AS c UNION SELECT 2 " - "UNION SELECT 3 UNION SELECT 4") +result = plpy.execute("SELECT 1 AS c UNION ALL SELECT 2 " + "UNION ALL SELECT 3 UNION ALL SELECT 4") plpy.info(result[1]['c']) plpy.info(result[-1]['c']) diff --git a/src/pl/plpython/expected/plpython_test.out b/src/pl/plpython/expected/plpython_test.out index adb82a89d6..847e4cc412 100644 --- a/src/pl/plpython/expected/plpython_test.out +++ b/src/pl/plpython/expected/plpython_test.out @@ -36,17 +36,34 @@ select "Argument test #1"(users, fname, lname) from users where lname = 'doe' or (3 rows) -- check module contents -CREATE FUNCTION module_contents() RETURNS text AS +CREATE FUNCTION module_contents() RETURNS SETOF text AS $$ contents = list(filter(lambda x: not x.startswith("__"), dir(plpy))) contents.sort() -return ", ".join(contents) +return contents $$ LANGUAGE plpythonu; select module_contents(); - module_contents ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Error, Fatal, SPIError, cursor, debug, error, execute, fatal, info, log, notice, prepare, quote_ident, quote_literal, quote_nullable, spiexceptions, subtransaction, warning -(1 row) + module_contents +----------------- + Error + Fatal + SPIError + cursor + debug + error + execute + fatal + info + log + notice + prepare + quote_ident + quote_literal + quote_nullable + spiexceptions + subtransaction + warning +(18 rows) CREATE FUNCTION elog_test_basic() RETURNS void AS $$ diff --git a/src/pl/plpython/expected/plpython_types.out b/src/pl/plpython/expected/plpython_types.out index f0b6abd274..10f7125d84 100644 --- a/src/pl/plpython/expected/plpython_types.out +++ b/src/pl/plpython/expected/plpython_types.out @@ -537,9 +537,111 @@ INFO: (None, ) (1 row) SELECT * FROM test_type_conversion_array_int4(ARRAY[[1,2,3],[4,5,6]]); -ERROR: cannot convert multidimensional array to Python list -DETAIL: PL/Python only supports one-dimensional arrays. -CONTEXT: PL/Python function "test_type_conversion_array_int4" +INFO: ([[1, 2, 3], [4, 5, 6]], ) + test_type_conversion_array_int4 +--------------------------------- + {{1,2,3},{4,5,6}} +(1 row) + +SELECT * FROM test_type_conversion_array_int4(ARRAY[[[1,2,NULL],[NULL,5,6]],[[NULL,8,9],[10,11,12]]]); +INFO: ([[[1, 2, None], [None, 5, 6]], [[None, 8, 9], [10, 11, 12]]], ) + test_type_conversion_array_int4 +--------------------------------------------------- + {{{1,2,NULL},{NULL,5,6}},{{NULL,8,9},{10,11,12}}} +(1 row) + +SELECT * FROM test_type_conversion_array_int4('[2:4]={1,2,3}'); +INFO: ([1, 2, 3], ) + test_type_conversion_array_int4 +--------------------------------- + {1,2,3} +(1 row) + +CREATE FUNCTION test_type_conversion_array_int8(x int8[]) RETURNS int8[] AS $$ +plpy.info(x, type(x)) +return x +$$ LANGUAGE plpythonu; +SELECT * FROM test_type_conversion_array_int8(ARRAY[[[1,2,NULL],[NULL,5,6]],[[NULL,8,9],[10,11,12]]]::int8[]); +INFO: ([[[1L, 2L, None], [None, 5L, 6L]], [[None, 8L, 9L], [10L, 11L, 12L]]], ) + test_type_conversion_array_int8 +--------------------------------------------------- + {{{1,2,NULL},{NULL,5,6}},{{NULL,8,9},{10,11,12}}} +(1 row) + +CREATE FUNCTION test_type_conversion_array_date(x date[]) RETURNS date[] AS $$ +plpy.info(x, type(x)) +return x +$$ LANGUAGE plpythonu; +SELECT * FROM test_type_conversion_array_date(ARRAY[[['2016-09-21','2016-09-22',NULL],[NULL,'2016-10-21','2016-10-22']], + [[NULL,'2016-11-21','2016-10-21'],['2015-09-21','2015-09-22','2014-09-21']]]::date[]); +INFO: ([[['09-21-2016', '09-22-2016', None], [None, '10-21-2016', '10-22-2016']], [[None, '11-21-2016', '10-21-2016'], ['09-21-2015', '09-22-2015', '09-21-2014']]], ) + test_type_conversion_array_date +--------------------------------------------------------------------------------------------------------------------------------- + {{{09-21-2016,09-22-2016,NULL},{NULL,10-21-2016,10-22-2016}},{{NULL,11-21-2016,10-21-2016},{09-21-2015,09-22-2015,09-21-2014}}} +(1 row) + +CREATE FUNCTION test_type_conversion_array_timestamp(x timestamp[]) RETURNS timestamp[] AS $$ +plpy.info(x, type(x)) +return x +$$ LANGUAGE plpythonu; +SELECT * FROM test_type_conversion_array_timestamp(ARRAY[[['2016-09-21 15:34:24.078792-04','2016-10-22 11:34:24.078795-04',NULL], + [NULL,'2016-10-21 11:34:25.078792-04','2016-10-21 11:34:24.098792-04']], + [[NULL,'2016-01-21 11:34:24.078792-04','2016-11-21 11:34:24.108792-04'], + ['2015-09-21 11:34:24.079792-04','2014-09-21 11:34:24.078792-04','2013-09-21 11:34:24.078792-04']]]::timestamp[]); +INFO: ([[['Wed Sep 21 15:34:24.078792 2016', 'Sat Oct 22 11:34:24.078795 2016', None], [None, 'Fri Oct 21 11:34:25.078792 2016', 'Fri Oct 21 11:34:24.098792 2016']], [[None, 'Thu Jan 21 11:34:24.078792 2016', 'Mon Nov 21 11:34:24.108792 2016'], ['Mon Sep 21 11:34:24.079792 2015', 'Sun Sep 21 11:34:24.078792 2014', 'Sat Sep 21 11:34:24.078792 2013']]], ) + test_type_conversion_array_timestamp +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + {{{"Wed Sep 21 15:34:24.078792 2016","Sat Oct 22 11:34:24.078795 2016",NULL},{NULL,"Fri Oct 21 11:34:25.078792 2016","Fri Oct 21 11:34:24.098792 2016"}},{{NULL,"Thu Jan 21 11:34:24.078792 2016","Mon Nov 21 11:34:24.108792 2016"},{"Mon Sep 21 11:34:24.079792 2015","Sun Sep 21 11:34:24.078792 2014","Sat Sep 21 11:34:24.078792 2013"}}} +(1 row) + +CREATE OR REPLACE FUNCTION pyreturnmultidemint4(h int4, i int4, j int4, k int4 ) RETURNS int4[] AS $BODY$ +m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] for w in range(k)] +plpy.info(m, type(m)) +return m +$BODY$ LANGUAGE plpythonu; +select pyreturnmultidemint4(8,5,3,2); +INFO: ([[[[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]], [[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]], [[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]]], [[[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]], [[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]], [[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]]]], ) + pyreturnmultidemint4 +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + {{{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7}},{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7}},{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7}}},{{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7}},{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7}},{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7}}}} +(1 row) + +CREATE OR REPLACE FUNCTION pyreturnmultidemint8(h int4, i int4, j int4, k int4 ) RETURNS int8[] AS $BODY$ +m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] for w in range(k)] +plpy.info(m, type(m)) +return m +$BODY$ LANGUAGE plpythonu; +select pyreturnmultidemint8(5,5,3,2); +INFO: ([[[[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]], [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]], [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]]], [[[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]], [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]], [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]]]], ) + pyreturnmultidemint8 +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + {{{{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4}},{{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4}},{{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4}}},{{{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4}},{{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4}},{{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4}}}} +(1 row) + +CREATE OR REPLACE FUNCTION pyreturnmultidemfloat4(h int4, i int4, j int4, k int4 ) RETURNS float4[] AS $BODY$ +m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] for w in range(k)] +plpy.info(m, type(m)) +return m +$BODY$ LANGUAGE plpythonu; +select pyreturnmultidemfloat4(6,5,3,2); +INFO: ([[[[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]], [[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]], [[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]]], [[[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]], [[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]], [[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]]]], ) + pyreturnmultidemfloat4 +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + {{{{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5}},{{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5}},{{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5}}},{{{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5}},{{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5}},{{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5}}}} +(1 row) + +CREATE OR REPLACE FUNCTION pyreturnmultidemfloat8(h int4, i int4, j int4, k int4 ) RETURNS float8[] AS $BODY$ +m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] for w in range(k)] +plpy.info(m, type(m)) +return m +$BODY$ LANGUAGE plpythonu; +select pyreturnmultidemfloat8(7,5,3,2); +INFO: ([[[[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]], [[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]], [[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]]], [[[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]], [[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]], [[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]]]], ) + pyreturnmultidemfloat8 +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + {{{{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}},{{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}},{{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}}},{{{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}},{{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}},{{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}}}} +(1 row) + CREATE FUNCTION test_type_conversion_array_text(x text[]) RETURNS text[] AS $$ plpy.info(x, type(x)) return x @@ -551,6 +653,13 @@ INFO: (['foo', 'bar'], ) {foo,bar} (1 row) +SELECT * FROM test_type_conversion_array_text(ARRAY[['foo', 'bar'],['foo2', 'bar2']]); +INFO: ([['foo', 'bar'], ['foo2', 'bar2']], ) + test_type_conversion_array_text +--------------------------------- + {{foo,bar},{foo2,bar2}} +(1 row) + CREATE FUNCTION test_type_conversion_array_bytea(x bytea[]) RETURNS bytea[] AS $$ plpy.info(x, type(x)) return x @@ -578,6 +687,20 @@ SELECT * FROM test_type_conversion_array_mixed2(); ERROR: invalid input syntax for integer: "abc" CONTEXT: while creating return value PL/Python function "test_type_conversion_array_mixed2" +CREATE FUNCTION test_type_conversion_mdarray_malformed() RETURNS int[] AS $$ +return [[1,2,3],[4,5]] +$$ LANGUAGE plpythonu; +SELECT * FROM test_type_conversion_mdarray_malformed(); +ERROR: multidimensional arrays must have array expressions with matching dimensions. PL/Python function return value has sequence length 2 while expected 3 +CONTEXT: while creating return value +PL/Python function "test_type_conversion_mdarray_malformed" +CREATE FUNCTION test_type_conversion_mdarray_toodeep() RETURNS int[] AS $$ +return [[[[[[[1]]]]]]] +$$ LANGUAGE plpythonu; +SELECT * FROM test_type_conversion_mdarray_toodeep(); +ERROR: number of array dimensions exceeds the maximum allowed (6) +CONTEXT: while creating return value +PL/Python function "test_type_conversion_mdarray_toodeep" CREATE FUNCTION test_type_conversion_array_record() RETURNS type_record[] AS $$ return [{'first': 'one', 'second': 42}, {'first': 'two', 'second': 11}] $$ LANGUAGE plpythonu; diff --git a/src/pl/plpython/expected/plpython_types_3.out b/src/pl/plpython/expected/plpython_types_3.out index 56b78e1a5f..f7f0d31fef 100644 --- a/src/pl/plpython/expected/plpython_types_3.out +++ b/src/pl/plpython/expected/plpython_types_3.out @@ -537,9 +537,111 @@ INFO: (None, ) (1 row) SELECT * FROM test_type_conversion_array_int4(ARRAY[[1,2,3],[4,5,6]]); -ERROR: cannot convert multidimensional array to Python list -DETAIL: PL/Python only supports one-dimensional arrays. -CONTEXT: PL/Python function "test_type_conversion_array_int4" +INFO: ([[1, 2, 3], [4, 5, 6]], ) + test_type_conversion_array_int4 +--------------------------------- + {{1,2,3},{4,5,6}} +(1 row) + +SELECT * FROM test_type_conversion_array_int4(ARRAY[[[1,2,NULL],[NULL,5,6]],[[NULL,8,9],[10,11,12]]]); +INFO: ([[[1, 2, None], [None, 5, 6]], [[None, 8, 9], [10, 11, 12]]], ) + test_type_conversion_array_int4 +--------------------------------------------------- + {{{1,2,NULL},{NULL,5,6}},{{NULL,8,9},{10,11,12}}} +(1 row) + +SELECT * FROM test_type_conversion_array_int4('[2:4]={1,2,3}'); +INFO: ([1, 2, 3], ) + test_type_conversion_array_int4 +--------------------------------- + {1,2,3} +(1 row) + +CREATE FUNCTION test_type_conversion_array_int8(x int8[]) RETURNS int8[] AS $$ +plpy.info(x, type(x)) +return x +$$ LANGUAGE plpython3u; +SELECT * FROM test_type_conversion_array_int8(ARRAY[[[1,2,NULL],[NULL,5,6]],[[NULL,8,9],[10,11,12]]]::int8[]); +INFO: ([[[1, 2, None], [None, 5, 6]], [[None, 8, 9], [10, 11, 12]]], ) + test_type_conversion_array_int8 +--------------------------------------------------- + {{{1,2,NULL},{NULL,5,6}},{{NULL,8,9},{10,11,12}}} +(1 row) + +CREATE FUNCTION test_type_conversion_array_date(x date[]) RETURNS date[] AS $$ +plpy.info(x, type(x)) +return x +$$ LANGUAGE plpython3u; +SELECT * FROM test_type_conversion_array_date(ARRAY[[['2016-09-21','2016-09-22',NULL],[NULL,'2016-10-21','2016-10-22']], + [[NULL,'2016-11-21','2016-10-21'],['2015-09-21','2015-09-22','2014-09-21']]]::date[]); +INFO: ([[['09-21-2016', '09-22-2016', None], [None, '10-21-2016', '10-22-2016']], [[None, '11-21-2016', '10-21-2016'], ['09-21-2015', '09-22-2015', '09-21-2014']]], ) + test_type_conversion_array_date +--------------------------------------------------------------------------------------------------------------------------------- + {{{09-21-2016,09-22-2016,NULL},{NULL,10-21-2016,10-22-2016}},{{NULL,11-21-2016,10-21-2016},{09-21-2015,09-22-2015,09-21-2014}}} +(1 row) + +CREATE FUNCTION test_type_conversion_array_timestamp(x timestamp[]) RETURNS timestamp[] AS $$ +plpy.info(x, type(x)) +return x +$$ LANGUAGE plpython3u; +SELECT * FROM test_type_conversion_array_timestamp(ARRAY[[['2016-09-21 15:34:24.078792-04','2016-10-22 11:34:24.078795-04',NULL], + [NULL,'2016-10-21 11:34:25.078792-04','2016-10-21 11:34:24.098792-04']], + [[NULL,'2016-01-21 11:34:24.078792-04','2016-11-21 11:34:24.108792-04'], + ['2015-09-21 11:34:24.079792-04','2014-09-21 11:34:24.078792-04','2013-09-21 11:34:24.078792-04']]]::timestamp[]); +INFO: ([[['Wed Sep 21 15:34:24.078792 2016', 'Sat Oct 22 11:34:24.078795 2016', None], [None, 'Fri Oct 21 11:34:25.078792 2016', 'Fri Oct 21 11:34:24.098792 2016']], [[None, 'Thu Jan 21 11:34:24.078792 2016', 'Mon Nov 21 11:34:24.108792 2016'], ['Mon Sep 21 11:34:24.079792 2015', 'Sun Sep 21 11:34:24.078792 2014', 'Sat Sep 21 11:34:24.078792 2013']]], ) + test_type_conversion_array_timestamp +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + {{{"Wed Sep 21 15:34:24.078792 2016","Sat Oct 22 11:34:24.078795 2016",NULL},{NULL,"Fri Oct 21 11:34:25.078792 2016","Fri Oct 21 11:34:24.098792 2016"}},{{NULL,"Thu Jan 21 11:34:24.078792 2016","Mon Nov 21 11:34:24.108792 2016"},{"Mon Sep 21 11:34:24.079792 2015","Sun Sep 21 11:34:24.078792 2014","Sat Sep 21 11:34:24.078792 2013"}}} +(1 row) + +CREATE OR REPLACE FUNCTION pyreturnmultidemint4(h int4, i int4, j int4, k int4 ) RETURNS int4[] AS $BODY$ +m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] for w in range(k)] +plpy.info(m, type(m)) +return m +$BODY$ LANGUAGE plpython3u; +select pyreturnmultidemint4(8,5,3,2); +INFO: ([[[[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]], [[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]], [[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]]], [[[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]], [[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]], [[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]]]], ) + pyreturnmultidemint4 +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + {{{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7}},{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7}},{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7}}},{{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7}},{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7}},{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7}}}} +(1 row) + +CREATE OR REPLACE FUNCTION pyreturnmultidemint8(h int4, i int4, j int4, k int4 ) RETURNS int8[] AS $BODY$ +m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] for w in range(k)] +plpy.info(m, type(m)) +return m +$BODY$ LANGUAGE plpython3u; +select pyreturnmultidemint8(5,5,3,2); +INFO: ([[[[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]], [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]], [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]]], [[[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]], [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]], [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]]]], ) + pyreturnmultidemint8 +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + {{{{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4}},{{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4}},{{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4}}},{{{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4}},{{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4}},{{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4}}}} +(1 row) + +CREATE OR REPLACE FUNCTION pyreturnmultidemfloat4(h int4, i int4, j int4, k int4 ) RETURNS float4[] AS $BODY$ +m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] for w in range(k)] +plpy.info(m, type(m)) +return m +$BODY$ LANGUAGE plpython3u; +select pyreturnmultidemfloat4(6,5,3,2); +INFO: ([[[[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]], [[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]], [[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]]], [[[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]], [[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]], [[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]]]], ) + pyreturnmultidemfloat4 +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + {{{{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5}},{{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5}},{{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5}}},{{{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5}},{{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5}},{{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5}}}} +(1 row) + +CREATE OR REPLACE FUNCTION pyreturnmultidemfloat8(h int4, i int4, j int4, k int4 ) RETURNS float8[] AS $BODY$ +m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] for w in range(k)] +plpy.info(m, type(m)) +return m +$BODY$ LANGUAGE plpython3u; +select pyreturnmultidemfloat8(7,5,3,2); +INFO: ([[[[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]], [[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]], [[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]]], [[[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]], [[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]], [[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]]]], ) + pyreturnmultidemfloat8 +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + {{{{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}},{{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}},{{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}}},{{{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}},{{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}},{{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}}}} +(1 row) + CREATE FUNCTION test_type_conversion_array_text(x text[]) RETURNS text[] AS $$ plpy.info(x, type(x)) return x @@ -551,6 +653,13 @@ INFO: (['foo', 'bar'], ) {foo,bar} (1 row) +SELECT * FROM test_type_conversion_array_text(ARRAY[['foo', 'bar'],['foo2', 'bar2']]); +INFO: ([['foo', 'bar'], ['foo2', 'bar2']], ) + test_type_conversion_array_text +--------------------------------- + {{foo,bar},{foo2,bar2}} +(1 row) + CREATE FUNCTION test_type_conversion_array_bytea(x bytea[]) RETURNS bytea[] AS $$ plpy.info(x, type(x)) return x @@ -578,6 +687,20 @@ SELECT * FROM test_type_conversion_array_mixed2(); ERROR: invalid input syntax for integer: "abc" CONTEXT: while creating return value PL/Python function "test_type_conversion_array_mixed2" +CREATE FUNCTION test_type_conversion_mdarray_malformed() RETURNS int[] AS $$ +return [[1,2,3],[4,5]] +$$ LANGUAGE plpython3u; +SELECT * FROM test_type_conversion_mdarray_malformed(); +ERROR: multidimensional arrays must have array expressions with matching dimensions. PL/Python function return value has sequence length 2 while expected 3 +CONTEXT: while creating return value +PL/Python function "test_type_conversion_mdarray_malformed" +CREATE FUNCTION test_type_conversion_mdarray_toodeep() RETURNS int[] AS $$ +return [[[[[[[1]]]]]]] +$$ LANGUAGE plpython3u; +SELECT * FROM test_type_conversion_mdarray_toodeep(); +ERROR: number of array dimensions exceeds the maximum allowed (6) +CONTEXT: while creating return value +PL/Python function "test_type_conversion_mdarray_toodeep" CREATE FUNCTION test_type_conversion_array_record() RETURNS type_record[] AS $$ return [{'first': 'one', 'second': 42}, {'first': 'two', 'second': 11}] $$ LANGUAGE plpython3u; diff --git a/src/pl/plpython/generate-spiexceptions.pl b/src/pl/plpython/generate-spiexceptions.pl index f424160c47..ab0fa4aeaa 100644 --- a/src/pl/plpython/generate-spiexceptions.pl +++ b/src/pl/plpython/generate-spiexceptions.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl # # Generate the spiexceptions.h header from errcodes.txt -# Copyright (c) 2000-2016, PostgreSQL Global Development Group +# Copyright (c) 2000-2017, PostgreSQL Global Development Group use warnings; use strict; diff --git a/src/pl/plpython/plpy_cursorobject.c b/src/pl/plpython/plpy_cursorobject.c index 44ba76e765..7bb8992148 100644 --- a/src/pl/plpython/plpy_cursorobject.c +++ b/src/pl/plpython/plpy_cursorobject.c @@ -116,9 +116,7 @@ PLy_cursor_query(const char *query) cursor->closed = false; cursor->mcxt = AllocSetContextCreate(TopMemoryContext, "PL/Python cursor context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); PLy_typeinfo_init(&cursor->result, cursor->mcxt); oldcontext = CurrentMemoryContext; @@ -210,9 +208,7 @@ PLy_cursor_plan(PyObject *ob, PyObject *args) cursor->closed = false; cursor->mcxt = AllocSetContextCreate(TopMemoryContext, "PL/Python cursor context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); PLy_typeinfo_init(&cursor->result, cursor->mcxt); oldcontext = CurrentMemoryContext; @@ -244,7 +240,8 @@ PLy_cursor_plan(PyObject *ob, PyObject *args) plan->values[j] = plan->args[j].out.d.func(&(plan->args[j].out.d), -1, - elem); + elem, + false); } PG_CATCH(); { @@ -409,7 +406,7 @@ PLy_cursor_fetch(PyObject *self, PyObject *args) volatile ResourceOwner oldowner; Portal portal; - if (!PyArg_ParseTuple(args, "i", &count)) + if (!PyArg_ParseTuple(args, "i:fetch", &count)) return NULL; cursor = (PLyCursorObject *) self; diff --git a/src/pl/plpython/plpy_exec.c b/src/pl/plpython/plpy_exec.c index 25e4744c7d..697a0e1cc0 100644 --- a/src/pl/plpython/plpy_exec.c +++ b/src/pl/plpython/plpy_exec.c @@ -245,7 +245,7 @@ PLy_exec_function(FunctionCallInfo fcinfo, PLyProcedure *proc) desc = lookup_rowtype_tupdesc(proc->result.out.d.typoid, proc->result.out.d.typmod); - rv = PLyObject_ToCompositeDatum(&proc->result, desc, plrv); + rv = PLyObject_ToCompositeDatum(&proc->result, desc, plrv, false); fcinfo->isnull = (rv == (Datum) NULL); ReleaseTupleDesc(desc); @@ -253,7 +253,7 @@ PLy_exec_function(FunctionCallInfo fcinfo, PLyProcedure *proc) else { fcinfo->isnull = false; - rv = (proc->result.out.d.func) (&proc->result.out.d, -1, plrv); + rv = (proc->result.out.d.func) (&proc->result.out.d, -1, plrv, false); } } PG_CATCH(); @@ -896,18 +896,13 @@ static HeapTuple PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata, HeapTuple otup) { + HeapTuple rtup; PyObject *volatile plntup; PyObject *volatile plkeys; PyObject *volatile plval; - HeapTuple rtup; - int natts, - i, - attn, - atti; - int *volatile modattrs; Datum *volatile modvalues; - char *volatile modnulls; - TupleDesc tupdesc; + bool *volatile modnulls; + bool *volatile modrepls; ErrorContextCallback plerrcontext; plerrcontext.callback = plpython_trigger_error_callback; @@ -915,12 +910,16 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata, error_context_stack = &plerrcontext; plntup = plkeys = plval = NULL; - modattrs = NULL; modvalues = NULL; modnulls = NULL; + modrepls = NULL; PG_TRY(); { + TupleDesc tupdesc; + int nkeys, + i; + if ((plntup = PyDict_GetItemString(pltd, "new")) == NULL) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), @@ -932,18 +931,20 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata, errmsg("TD[\"new\"] is not a dictionary"))); plkeys = PyDict_Keys(plntup); - natts = PyList_Size(plkeys); - - modattrs = (int *) palloc(natts * sizeof(int)); - modvalues = (Datum *) palloc(natts * sizeof(Datum)); - modnulls = (char *) palloc(natts * sizeof(char)); + nkeys = PyList_Size(plkeys); tupdesc = tdata->tg_relation->rd_att; - for (i = 0; i < natts; i++) + modvalues = (Datum *) palloc0(tupdesc->natts * sizeof(Datum)); + modnulls = (bool *) palloc0(tupdesc->natts * sizeof(bool)); + modrepls = (bool *) palloc0(tupdesc->natts * sizeof(bool)); + + for (i = 0; i < nkeys; i++) { PyObject *platt; char *plattstr; + int attn; + PLyObToDatum *att; platt = PyList_GetItem(plkeys, i); if (PyString_Check(platt)) @@ -963,7 +964,12 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("key \"%s\" found in TD[\"new\"] does not exist as a column in the triggering row", plattstr))); - atti = attn - 1; + if (attn <= 0) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot set system attribute \"%s\"", + plattstr))); + att = &proc->result.out.r.atts[attn - 1]; plval = PyDict_GetItem(plntup, platt); if (plval == NULL) @@ -971,40 +977,31 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata, Py_INCREF(plval); - modattrs[i] = attn; - - if (tupdesc->attrs[atti]->attisdropped) + if (plval != Py_None) { - modvalues[i] = (Datum) 0; - modnulls[i] = 'n'; - } - else if (plval != Py_None) - { - PLyObToDatum *att = &proc->result.out.r.atts[atti]; - - modvalues[i] = (att->func) (att, - tupdesc->attrs[atti]->atttypmod, - plval); - modnulls[i] = ' '; + modvalues[attn - 1] = + (att->func) (att, + tupdesc->attrs[attn - 1]->atttypmod, + plval, + false); + modnulls[attn - 1] = false; } else { - modvalues[i] = - InputFunctionCall(&proc->result.out.r.atts[atti].typfunc, + modvalues[attn - 1] = + InputFunctionCall(&att->typfunc, NULL, - proc->result.out.r.atts[atti].typioparam, - tupdesc->attrs[atti]->atttypmod); - modnulls[i] = 'n'; + att->typioparam, + tupdesc->attrs[attn - 1]->atttypmod); + modnulls[attn - 1] = true; } + modrepls[attn - 1] = true; Py_DECREF(plval); plval = NULL; } - rtup = SPI_modifytuple(tdata->tg_relation, otup, natts, - modattrs, modvalues, modnulls); - if (rtup == NULL) - elog(ERROR, "SPI_modifytuple failed: error %d", SPI_result); + rtup = heap_modify_tuple(otup, tupdesc, modvalues, modnulls, modrepls); } PG_CATCH(); { @@ -1012,12 +1009,12 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata, Py_XDECREF(plkeys); Py_XDECREF(plval); - if (modnulls) - pfree(modnulls); if (modvalues) pfree(modvalues); - if (modattrs) - pfree(modattrs); + if (modnulls) + pfree(modnulls); + if (modrepls) + pfree(modrepls); PG_RE_THROW(); } @@ -1026,9 +1023,9 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata, Py_DECREF(plntup); Py_DECREF(plkeys); - pfree(modattrs); pfree(modvalues); pfree(modnulls); + pfree(modrepls); error_context_stack = plerrcontext.previous; @@ -1106,8 +1103,6 @@ PLy_abort_open_subtransactions(int save_subxact_level) RollbackAndReleaseCurrentSubTransaction(); - SPI_restore_connection(); - subtransactiondata = (PLySubtransactionData *) linitial(explicit_subtransactions); explicit_subtransactions = list_delete_first(explicit_subtransactions); diff --git a/src/pl/plpython/plpy_main.c b/src/pl/plpython/plpy_main.c index f95039406a..860b804e54 100644 --- a/src/pl/plpython/plpy_main.c +++ b/src/pl/plpython/plpy_main.c @@ -315,9 +315,7 @@ plpython_inline_handler(PG_FUNCTION_ARGS) MemSet(&proc, 0, sizeof(PLyProcedure)); proc.mcxt = AllocSetContextCreate(TopMemoryContext, "__plpython_inline_block", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); proc.pyname = MemoryContextStrdup(proc.mcxt, "__plpython_inline_block"); proc.langid = codeblock->langOid; proc.result.out.d.typoid = VOIDOID; @@ -416,9 +414,7 @@ PLy_get_scratch_context(PLyExecutionContext *context) context->scratch_ctx = AllocSetContextCreate(TopTransactionContext, "PL/Python scratch context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); return context->scratch_ctx; } diff --git a/src/pl/plpython/plpy_planobject.c b/src/pl/plpython/plpy_planobject.c index a9040efb50..16c39a05dd 100644 --- a/src/pl/plpython/plpy_planobject.c +++ b/src/pl/plpython/plpy_planobject.c @@ -114,12 +114,11 @@ PLy_plan_dealloc(PyObject *arg) static PyObject * PLy_plan_status(PyObject *self, PyObject *args) { - if (PyArg_ParseTuple(args, "")) + if (PyArg_ParseTuple(args, ":status")) { Py_INCREF(Py_True); return Py_True; /* return PyInt_FromLong(self->status); */ } - PLy_exception_set(PLy_exc_error, "plan.status takes no arguments"); return NULL; } diff --git a/src/pl/plpython/plpy_plpymodule.c b/src/pl/plpython/plpy_plpymodule.c index f520e7725f..0cf2ad29cb 100644 --- a/src/pl/plpython/plpy_plpymodule.c +++ b/src/pl/plpython/plpy_plpymodule.c @@ -25,6 +25,9 @@ HTAB *PLy_spi_exceptions = NULL; static void PLy_add_exceptions(PyObject *plpy); +static PyObject *PLy_create_exception(char *name, + PyObject *base, PyObject *dict, + const char *modname, PyObject *mod); static void PLy_generate_spi_exceptions(PyObject *mod, PyObject *base); /* module functions */ @@ -192,46 +195,62 @@ PLy_add_exceptions(PyObject *plpy) #else excmod = PyModule_Create(&PLy_exc_module); #endif - if (PyModule_AddObject(plpy, "spiexceptions", excmod) < 0) - PLy_elog(ERROR, "could not add the spiexceptions module"); + if (excmod == NULL) + PLy_elog(ERROR, "could not create the spiexceptions module"); /* - * XXX it appears that in some circumstances the reference count of the - * spiexceptions module drops to zero causing a Python assert failure when - * the garbage collector visits the module. This has been observed on the - * buildfarm. To fix this, add an additional ref for the module here. - * - * This shouldn't cause a memory leak - we don't want this garbage - * collected, and this function shouldn't be called more than once per - * backend. + * PyModule_AddObject does not add a refcount to the object, for some odd + * reason; we must do that. */ Py_INCREF(excmod); + if (PyModule_AddObject(plpy, "spiexceptions", excmod) < 0) + PLy_elog(ERROR, "could not add the spiexceptions module"); - PLy_exc_error = PyErr_NewException("plpy.Error", NULL, NULL); - PLy_exc_fatal = PyErr_NewException("plpy.Fatal", NULL, NULL); - PLy_exc_spi_error = PyErr_NewException("plpy.SPIError", NULL, NULL); - - if (PLy_exc_error == NULL || - PLy_exc_fatal == NULL || - PLy_exc_spi_error == NULL) - PLy_elog(ERROR, "could not create the base SPI exceptions"); - - Py_INCREF(PLy_exc_error); - PyModule_AddObject(plpy, "Error", PLy_exc_error); - Py_INCREF(PLy_exc_fatal); - PyModule_AddObject(plpy, "Fatal", PLy_exc_fatal); - Py_INCREF(PLy_exc_spi_error); - PyModule_AddObject(plpy, "SPIError", PLy_exc_spi_error); + PLy_exc_error = PLy_create_exception("plpy.Error", NULL, NULL, + "Error", plpy); + PLy_exc_fatal = PLy_create_exception("plpy.Fatal", NULL, NULL, + "Fatal", plpy); + PLy_exc_spi_error = PLy_create_exception("plpy.SPIError", NULL, NULL, + "SPIError", plpy); memset(&hash_ctl, 0, sizeof(hash_ctl)); hash_ctl.keysize = sizeof(int); hash_ctl.entrysize = sizeof(PLyExceptionEntry); - PLy_spi_exceptions = hash_create("SPI exceptions", 256, + PLy_spi_exceptions = hash_create("PL/Python SPI exceptions", 256, &hash_ctl, HASH_ELEM | HASH_BLOBS); PLy_generate_spi_exceptions(excmod, PLy_exc_spi_error); } +/* + * Create an exception object and add it to the module + */ +static PyObject * +PLy_create_exception(char *name, PyObject *base, PyObject *dict, + const char *modname, PyObject *mod) +{ + PyObject *exc; + + exc = PyErr_NewException(name, base, dict); + if (exc == NULL) + PLy_elog(ERROR, "could not create exception \"%s\"", name); + + /* + * PyModule_AddObject does not add a refcount to the object, for some odd + * reason; we must do that. + */ + Py_INCREF(exc); + PyModule_AddObject(mod, modname, exc); + + /* + * The caller will also store a pointer to the exception object in some + * permanent variable, so add another ref to account for that. This is + * probably excessively paranoid, but let's be sure. + */ + Py_INCREF(exc); + return exc; +} + /* * Add all the autogenerated exceptions as subclasses of SPIError */ @@ -257,12 +276,14 @@ PLy_generate_spi_exceptions(PyObject *mod, PyObject *base) PyDict_SetItemString(dict, "sqlstate", sqlstate); Py_DECREF(sqlstate); - exc = PyErr_NewException(exception_map[i].name, base, dict); - PyModule_AddObject(mod, exception_map[i].classname, exc); + + exc = PLy_create_exception(exception_map[i].name, base, dict, + exception_map[i].classname, mod); + entry = hash_search(PLy_spi_exceptions, &exception_map[i].sqlstate, HASH_ENTER, &found); - entry->exc = exc; Assert(!found); + entry->exc = exc; } } @@ -323,7 +344,7 @@ PLy_quote_literal(PyObject *self, PyObject *args) char *quoted; PyObject *ret; - if (!PyArg_ParseTuple(args, "s", &str)) + if (!PyArg_ParseTuple(args, "s:quote_literal", &str)) return NULL; quoted = quote_literal_cstr(str); @@ -340,7 +361,7 @@ PLy_quote_nullable(PyObject *self, PyObject *args) char *quoted; PyObject *ret; - if (!PyArg_ParseTuple(args, "z", &str)) + if (!PyArg_ParseTuple(args, "z:quote_nullable", &str)) return NULL; if (str == NULL) @@ -360,7 +381,7 @@ PLy_quote_ident(PyObject *self, PyObject *args) const char *quoted; PyObject *ret; - if (!PyArg_ParseTuple(args, "s", &str)) + if (!PyArg_ParseTuple(args, "s:quote_ident", &str)) return NULL; quoted = quote_identifier(str); diff --git a/src/pl/plpython/plpy_procedure.c b/src/pl/plpython/plpy_procedure.c index 70b75f5d95..2b249b029d 100644 --- a/src/pl/plpython/plpy_procedure.c +++ b/src/pl/plpython/plpy_procedure.c @@ -167,9 +167,7 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) cxt = AllocSetContextCreate(TopMemoryContext, procName, - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldcxt = MemoryContextSwitchTo(cxt); diff --git a/src/pl/plpython/plpy_spi.c b/src/pl/plpython/plpy_spi.c index 1e965cf85f..07ab6a087e 100644 --- a/src/pl/plpython/plpy_spi.c +++ b/src/pl/plpython/plpy_spi.c @@ -51,7 +51,7 @@ PLy_spi_prepare(PyObject *self, PyObject *args) volatile ResourceOwner oldowner; volatile int nargs; - if (!PyArg_ParseTuple(args, "s|O", &query, &list)) + if (!PyArg_ParseTuple(args, "s|O:prepare", &query, &list)) return NULL; if (list && (!PySequence_Check(list))) @@ -66,9 +66,7 @@ PLy_spi_prepare(PyObject *self, PyObject *args) plan->mcxt = AllocSetContextCreate(TopMemoryContext, "PL/Python plan context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); oldcontext = MemoryContextSwitchTo(plan->mcxt); nargs = list ? PySequence_Length(list) : 0; @@ -266,7 +264,8 @@ PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit) plan->values[j] = plan->args[j].out.d.func(&(plan->args[j].out.d), -1, - elem); + elem, + false); } PG_CATCH(); { @@ -413,9 +412,7 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, uint64 rows, int status) cxt = AllocSetContextCreate(CurrentMemoryContext, "PL/Python temp context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); PLy_typeinfo_init(&args, cxt); oldcontext = CurrentMemoryContext; @@ -519,12 +516,6 @@ PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner) ReleaseCurrentSubTransaction(); MemoryContextSwitchTo(oldcontext); CurrentResourceOwner = oldowner; - - /* - * AtEOSubXact_SPI() should not have popped any SPI context, but just in - * case it did, make sure we remain connected. - */ - SPI_restore_connection(); } void @@ -544,13 +535,6 @@ PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner) MemoryContextSwitchTo(oldcontext); CurrentResourceOwner = oldowner; - /* - * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will - * have left us in a disconnected state. We need this hack to return to - * connected state. - */ - SPI_restore_connection(); - /* Look up the correct exception */ entry = hash_search(PLy_spi_exceptions, &(edata->sqlerrcode), HASH_FIND, NULL); diff --git a/src/pl/plpython/plpy_subxactobject.c b/src/pl/plpython/plpy_subxactobject.c index 81fb3a3a4a..9f1caa87d9 100644 --- a/src/pl/plpython/plpy_subxactobject.c +++ b/src/pl/plpython/plpy_subxactobject.c @@ -7,7 +7,6 @@ #include "postgres.h" #include "access/xact.h" -#include "executor/spi.h" #include "utils/memutils.h" #include "plpython.h" @@ -213,12 +212,6 @@ PLy_subtransaction_exit(PyObject *self, PyObject *args) CurrentResourceOwner = subxactdata->oldowner; pfree(subxactdata); - /* - * AtEOSubXact_SPI() should not have popped any SPI context, but just in - * case it did, make sure we remain connected. - */ - SPI_restore_connection(); - Py_INCREF(Py_None); return Py_None; } diff --git a/src/pl/plpython/plpy_typeio.c b/src/pl/plpython/plpy_typeio.c index 7ad7a4400a..b9c6d64baa 100644 --- a/src/pl/plpython/plpy_typeio.c +++ b/src/pl/plpython/plpy_typeio.c @@ -14,6 +14,7 @@ #include "parser/parse_type.h" #include "utils/array.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/numeric.h" @@ -45,20 +46,25 @@ static PyObject *PLyBytes_FromBytea(PLyDatumToOb *arg, Datum d); static PyObject *PLyString_FromDatum(PLyDatumToOb *arg, Datum d); static PyObject *PLyObject_FromTransform(PLyDatumToOb *arg, Datum d); static PyObject *PLyList_FromArray(PLyDatumToOb *arg, Datum d); +static PyObject *PLyList_FromArray_recurse(PLyDatumToOb *elm, int *dims, int ndim, int dim, + char **dataptr_p, bits8 **bitmap_p, int *bitmask_p); /* conversion from Python objects to Datums */ -static Datum PLyObject_ToBool(PLyObToDatum *arg, int32 typmod, PyObject *plrv); -static Datum PLyObject_ToBytea(PLyObToDatum *arg, int32 typmod, PyObject *plrv); -static Datum PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv); -static Datum PLyObject_ToDatum(PLyObToDatum *arg, int32 typmod, PyObject *plrv); -static Datum PLyObject_ToTransform(PLyObToDatum *arg, int32 typmod, PyObject *plrv); -static Datum PLySequence_ToArray(PLyObToDatum *arg, int32 typmod, PyObject *plrv); +static Datum PLyObject_ToBool(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray); +static Datum PLyObject_ToBytea(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray); +static Datum PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray); +static Datum PLyObject_ToDatum(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray); +static Datum PLyObject_ToTransform(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray); +static Datum PLySequence_ToArray(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray); +static void PLySequence_ToArray_recurse(PLyObToDatum *elm, PyObject *list, + int *dims, int ndim, int dim, + Datum *elems, bool *nulls, int *currelem); /* conversion from Python objects to composite Datums (used by triggers and SRFs) */ -static Datum PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string); +static Datum PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string, bool inarray); static Datum PLyMapping_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *mapping); static Datum PLySequence_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *sequence); -static Datum PLyGenericObject_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *object); +static Datum PLyGenericObject_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *object, bool inarray); void PLy_typeinfo_init(PLyTypeInfo *arg, MemoryContext mcxt) @@ -336,12 +342,12 @@ PLyDict_FromTuple(PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc) * as an object that has __getattr__ support. */ Datum -PLyObject_ToCompositeDatum(PLyTypeInfo *info, TupleDesc desc, PyObject *plrv) +PLyObject_ToCompositeDatum(PLyTypeInfo *info, TupleDesc desc, PyObject *plrv, bool inarray) { Datum datum; if (PyString_Check(plrv) || PyUnicode_Check(plrv)) - datum = PLyString_ToComposite(info, desc, plrv); + datum = PLyString_ToComposite(info, desc, plrv, inarray); else if (PySequence_Check(plrv)) /* composite type as sequence (tuple, list etc) */ datum = PLySequence_ToComposite(info, desc, plrv); @@ -350,7 +356,7 @@ PLyObject_ToCompositeDatum(PLyTypeInfo *info, TupleDesc desc, PyObject *plrv) datum = PLyMapping_ToComposite(info, desc, plrv); else /* returned as smth, must provide method __getattr__(name) */ - datum = PLyGenericObject_ToComposite(info, desc, plrv); + datum = PLyGenericObject_ToComposite(info, desc, plrv, inarray); return datum; } @@ -631,43 +637,104 @@ PLyList_FromArray(PLyDatumToOb *arg, Datum d) { ArrayType *array = DatumGetArrayTypeP(d); PLyDatumToOb *elm = arg->elm; - PyObject *list; - int length; - int lbound; - int i; + int ndim; + int *dims; + char *dataptr; + bits8 *bitmap; + int bitmask; if (ARR_NDIM(array) == 0) return PyList_New(0); - if (ARR_NDIM(array) != 1) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot convert multidimensional array to Python list"), - errdetail("PL/Python only supports one-dimensional arrays."))); + /* Array dimensions and left bounds */ + ndim = ARR_NDIM(array); + dims = ARR_DIMS(array); + Assert(ndim < MAXDIM); + + /* + * We iterate the SQL array in the physical order it's stored in the + * datum. For example, for a 3-dimensional array the order of iteration would + * be the following: [0,0,0] elements through [0,0,k], then [0,1,0] through + * [0,1,k] till [0,m,k], then [1,0,0] through [1,0,k] till [1,m,k], and so on. + * + * In Python, there are no multi-dimensional lists as such, but they are + * represented as a list of lists. So a 3-d array of [n,m,k] elements is a + * list of n m-element arrays, each element of which is k-element array. + * PLyList_FromArray_recurse() builds the Python list for a single + * dimension, and recurses for the next inner dimension. + */ + dataptr = ARR_DATA_PTR(array); + bitmap = ARR_NULLBITMAP(array); + bitmask = 1; + + return PLyList_FromArray_recurse(elm, dims, ndim, 0, + &dataptr, &bitmap, &bitmask); +} + +static PyObject * +PLyList_FromArray_recurse(PLyDatumToOb *elm, int *dims, int ndim, int dim, + char **dataptr_p, bits8 **bitmap_p, int *bitmask_p) +{ + int i; + PyObject *list; - length = ARR_DIMS(array)[0]; - lbound = ARR_LBOUND(array)[0]; - list = PyList_New(length); - if (list == NULL) - PLy_elog(ERROR, "could not create new Python list"); + list = PyList_New(dims[dim]); - for (i = 0; i < length; i++) + if (dim < ndim - 1) { - Datum elem; - bool isnull; - int offset; - - offset = lbound + i; - elem = array_ref(array, 1, &offset, arg->typlen, - elm->typlen, elm->typbyval, elm->typalign, - &isnull); - if (isnull) + /* Outer dimension. Recurse for each inner slice. */ + for (i = 0; i < dims[dim]; i++) + { + PyObject *sublist; + + sublist = PLyList_FromArray_recurse(elm, dims, ndim, dim + 1, + dataptr_p, bitmap_p, bitmask_p); + PyList_SET_ITEM(list, i, sublist); + } + } + else + { + /* + * Innermost dimension. Fill the list with the values from the array + * for this slice. + */ + char *dataptr = *dataptr_p; + bits8 *bitmap = *bitmap_p; + int bitmask = *bitmask_p; + + for (i = 0; i < dims[dim]; i++) { - Py_INCREF(Py_None); - PyList_SET_ITEM(list, i, Py_None); + /* checking for NULL */ + if (bitmap && (*bitmap & bitmask) == 0) + { + Py_INCREF(Py_None); + PyList_SET_ITEM(list, i, Py_None); + } + else + { + Datum itemvalue; + + itemvalue = fetch_att(dataptr, elm->typbyval, elm->typlen); + PyList_SET_ITEM(list, i, elm->func(elm, itemvalue)); + dataptr = att_addlength_pointer(dataptr, elm->typlen, dataptr); + dataptr = (char *) att_align_nominal(dataptr, elm->typalign); + } + + /* advance bitmap pointer if any */ + if (bitmap) + { + bitmask <<= 1; + if (bitmask == 0x100 /* (1<<8) */ ) + { + bitmap++; + bitmask = 1; + } + } } - else - PyList_SET_ITEM(list, i, elm->func(elm, elem)); + + *dataptr_p = dataptr; + *bitmap_p = bitmap; + *bitmask_p = bitmask; } return list; @@ -680,7 +747,7 @@ PLyList_FromArray(PLyDatumToOb *arg, Datum d) * type can parse. */ static Datum -PLyObject_ToBool(PLyObToDatum *arg, int32 typmod, PyObject *plrv) +PLyObject_ToBool(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray) { Datum rv; @@ -699,7 +766,7 @@ PLyObject_ToBool(PLyObToDatum *arg, int32 typmod, PyObject *plrv) * with embedded nulls. And it's faster this way. */ static Datum -PLyObject_ToBytea(PLyObToDatum *arg, int32 typmod, PyObject *plrv) +PLyObject_ToBytea(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray) { PyObject *volatile plrv_so = NULL; Datum rv; @@ -743,7 +810,7 @@ PLyObject_ToBytea(PLyObToDatum *arg, int32 typmod, PyObject *plrv) * for obtaining PostgreSQL tuples. */ static Datum -PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv) +PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray) { Datum rv; PLyTypeInfo info; @@ -756,9 +823,7 @@ PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv) /* Create a dummy PLyTypeInfo */ cxt = AllocSetContextCreate(CurrentMemoryContext, "PL/Python temp context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); MemSet(&info, 0, sizeof(PLyTypeInfo)); PLy_typeinfo_init(&info, cxt); /* Mark it as needing output routines lookup */ @@ -772,7 +837,7 @@ PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv) * that info instead of looking it up every time a tuple is returned from * the function. */ - rv = PLyObject_ToCompositeDatum(&info, desc, plrv); + rv = PLyObject_ToCompositeDatum(&info, desc, plrv, inarray); ReleaseTupleDesc(desc); @@ -844,61 +909,166 @@ PLyObject_AsString(PyObject *plrv) * cstring into PostgreSQL type. */ static Datum -PLyObject_ToDatum(PLyObToDatum *arg, int32 typmod, PyObject *plrv) +PLyObject_ToDatum(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray) { + char *str; + Assert(plrv != Py_None); + str = PLyObject_AsString(plrv); + + /* + * If we are parsing a composite type within an array, and the string + * isn't a valid record literal, there's a high chance that the function + * did something like: + * + * CREATE FUNCTION .. RETURNS comptype[] AS $$ return [['foo', 'bar']] $$ + * LANGUAGE plpython; + * + * Before PostgreSQL 10, that was interpreted as a single-dimensional + * array, containing record ('foo', 'bar'). PostgreSQL 10 added support + * for multi-dimensional arrays, and it is now interpreted as a + * two-dimensional array, containing two records, 'foo', and 'bar'. + * record_in() will throw an error, because "foo" is not a valid record + * literal. + * + * To make that less confusing to users who are upgrading from older + * versions, try to give a hint in the typical instances of that. If we are + * parsing an array of composite types, and we see a string literal that + * is not a valid record literal, give a hint. We only want to give the + * hint in the narrow case of a malformed string literal, not any error + * from record_in(), so check for that case here specifically. + * + * This check better match the one in record_in(), so that we don't forbid + * literals that are actually valid! + */ + if (inarray && arg->typfunc.fn_oid == F_RECORD_IN) + { + char *ptr = str; + + /* Allow leading whitespace */ + while (*ptr && isspace((unsigned char) *ptr)) + ptr++; + if (*ptr++ != '(') + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("malformed record literal: \"%s\"", str), + errdetail("Missing left parenthesis."), + errhint("To return a composite type in an array, return the composite type as a Python tuple, e.g. \"[('foo')]\""))); + } + return InputFunctionCall(&arg->typfunc, - PLyObject_AsString(plrv), + str, arg->typioparam, typmod); } static Datum -PLyObject_ToTransform(PLyObToDatum *arg, int32 typmod, PyObject *plrv) +PLyObject_ToTransform(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray) { return FunctionCall1(&arg->typtransform, PointerGetDatum(plrv)); } static Datum -PLySequence_ToArray(PLyObToDatum *arg, int32 typmod, PyObject *plrv) +PLySequence_ToArray(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarray) { ArrayType *array; - Datum rv; int i; Datum *elems; bool *nulls; - int len; - int lbs; + int64 len; + int ndim; + int dims[MAXDIM]; + int lbs[MAXDIM]; + int currelem; + Datum rv; + PyObject *pyptr = plrv; + PyObject *next; Assert(plrv != Py_None); - if (!PySequence_Check(plrv)) - PLy_elog(ERROR, "return value of function with array return type is not a Python sequence"); + /* + * Determine the number of dimensions, and their sizes. + */ + ndim = 0; + len = 1; - len = PySequence_Length(plrv); - elems = palloc(sizeof(*elems) * len); - nulls = palloc(sizeof(*nulls) * len); + Py_INCREF(plrv); - for (i = 0; i < len; i++) + for (;;) { - PyObject *obj = PySequence_GetItem(plrv, i); + if (!PyList_Check(pyptr)) + break; - if (obj == Py_None) - nulls[i] = true; - else + if (ndim == MAXDIM) + PLy_elog(ERROR, "number of array dimensions exceeds the maximum allowed (%d)", MAXDIM); + + dims[ndim] = PySequence_Length(pyptr); + if (dims[ndim] < 0) + PLy_elog(ERROR, "cannot determine sequence length for function return value"); + + if (dims[ndim] > MaxAllocSize) + PLy_elog(ERROR, "array size exceeds the maximum allowed"); + + len *= dims[ndim]; + if (len > MaxAllocSize) + PLy_elog(ERROR, "array size exceeds the maximum allowed"); + + if (dims[ndim] == 0) { - nulls[i] = false; - elems[i] = arg->elm->func(arg->elm, -1, obj); + /* empty sequence */ + break; } - Py_XDECREF(obj); + + ndim++; + + next = PySequence_GetItem(pyptr, 0); + Py_XDECREF(pyptr); + pyptr = next; + } + Py_XDECREF(pyptr); + + /* + * Check for zero dimensions. This happens if the object is a tuple or a + * string, rather than a list, or is not a sequence at all. We don't map + * tuples or strings to arrays in general, but in the first level, be + * lenient, for historical reasons. So if the object is a sequence of any + * kind, treat it as a one-dimensional array. + */ + if (ndim == 0) + { + if (!PySequence_Check(plrv)) + PLy_elog(ERROR, "return value of function with array return type is not a Python sequence"); + + ndim = 1; + len = dims[0] = PySequence_Length(plrv); } - lbs = 1; - array = construct_md_array(elems, nulls, 1, &len, &lbs, - get_base_element_type(arg->typoid), arg->elm->typlen, arg->elm->typbyval, arg->elm->typalign); + /* + * Traverse the Python lists, in depth-first order, and collect all the + * elements at the bottom level into 'elems'/'nulls' arrays. + */ + elems = palloc(sizeof(Datum) * len); + nulls = palloc(sizeof(bool) * len); + currelem = 0; + PLySequence_ToArray_recurse(arg->elm, plrv, + dims, ndim, 0, + elems, nulls, &currelem); + + for (i = 0; i < ndim; i++) + lbs[i] = 1; + + array = construct_md_array(elems, + nulls, + ndim, + dims, + lbs, + get_base_element_type(arg->typoid), + arg->elm->typlen, + arg->elm->typbyval, + arg->elm->typalign); /* * If the result type is a domain of array, the resulting array must be @@ -910,9 +1080,59 @@ PLySequence_ToArray(PLyObToDatum *arg, int32 typmod, PyObject *plrv) return rv; } +/* + * Helper function for PLySequence_ToArray. Traverse a Python list of lists in + * depth-first order, storing the elements in 'elems'. + */ +static void +PLySequence_ToArray_recurse(PLyObToDatum *elm, PyObject *list, + int *dims, int ndim, int dim, + Datum *elems, bool *nulls, int *currelem) +{ + int i; + + if (PySequence_Length(list) != dims[dim]) + PLy_elog(ERROR, + "multidimensional arrays must have array expressions with matching dimensions. " + "PL/Python function return value has sequence length %d while expected %d", + (int) PySequence_Length(list), dims[dim]); + + if (dim < ndim - 1) + { + for (i = 0; i < dims[dim]; i++) + { + PyObject *sublist = PySequence_GetItem(list, i); + + PLySequence_ToArray_recurse(elm, sublist, dims, ndim, dim + 1, + elems, nulls, currelem); + Py_XDECREF(sublist); + } + } + else + { + for (i = 0; i < dims[dim]; i++) + { + PyObject *obj = PySequence_GetItem(list, i); + + if (obj == Py_None) + { + nulls[*currelem] = true; + elems[*currelem] = (Datum) 0; + } + else + { + nulls[*currelem] = false; + elems[*currelem] = elm->func(elm, -1, obj, true); + } + Py_XDECREF(obj); + (*currelem)++; + } + } +} + static Datum -PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string) +PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string, bool inarray) { Datum result; HeapTuple typeTup; @@ -923,9 +1143,7 @@ PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string) /* Create a dummy PLyTypeInfo */ cxt = AllocSetContextCreate(CurrentMemoryContext, "PL/Python temp context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_DEFAULT_SIZES); MemSet(&locinfo, 0, sizeof(PLyTypeInfo)); PLy_typeinfo_init(&locinfo, cxt); @@ -939,7 +1157,7 @@ PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string) ReleaseSysCache(typeTup); - result = PLyObject_ToDatum(&locinfo.out.d, desc->tdtypmod, string); + result = PLyObject_ToDatum(&locinfo.out.d, desc->tdtypmod, string, inarray); MemoryContextDelete(cxt); @@ -991,7 +1209,7 @@ PLyMapping_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *mapping) } else if (value) { - values[i] = (att->func) (att, -1, value); + values[i] = (att->func) (att, -1, value, false); nulls[i] = false; } else @@ -1084,7 +1302,7 @@ PLySequence_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *sequence) } else if (value) { - values[i] = (att->func) (att, -1, value); + values[i] = (att->func) (att, -1, value, false); nulls[i] = false; } @@ -1113,7 +1331,7 @@ PLySequence_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *sequence) static Datum -PLyGenericObject_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *object) +PLyGenericObject_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *object, bool inarray) { Datum result; HeapTuple tuple; @@ -1154,16 +1372,29 @@ PLyGenericObject_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *object } else if (value) { - values[i] = (att->func) (att, -1, value); + values[i] = (att->func) (att, -1, value, false); nulls[i] = false; } else + { + /* + * No attribute for this column in the object. + * + * If we are parsing a composite type in an array, a likely + * cause is that the function contained something like "[[123, + * 'foo']]". Before PostgreSQL 10, that was interpreted as an + * array, with a composite type (123, 'foo') in it. But now + * it's interpreted as a two-dimensional array, and we try to + * interpret "123" as the composite type. See also similar + * heuristic in PLyObject_ToDatum(). + */ ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("attribute \"%s\" does not exist in Python object", key), - errhint("To return null in a column, " - "let the returned object have an attribute named " - "after column with value None."))); + inarray ? + errhint("To return a composite type in an array, return the composite type as a Python tuple, e.g. \"[('foo')]\"") : + errhint("To return null in a column, let the returned object have an attribute named after column with value None."))); + } Py_XDECREF(value); value = NULL; diff --git a/src/pl/plpython/plpy_typeio.h b/src/pl/plpython/plpy_typeio.h index 29fff61dc5..5f5c1ad5c6 100644 --- a/src/pl/plpython/plpy_typeio.h +++ b/src/pl/plpython/plpy_typeio.h @@ -10,8 +10,11 @@ #include "fmgr.h" #include "storage/itemptr.h" +/* + * Conversion from PostgreSQL Datum to a Python object. + */ struct PLyDatumToOb; -typedef PyObject *(*PLyDatumToObFunc) (struct PLyDatumToOb *, Datum); +typedef PyObject *(*PLyDatumToObFunc) (struct PLyDatumToOb *arg, Datum val); typedef struct PLyDatumToOb { @@ -39,11 +42,15 @@ typedef union PLyTypeInput PLyTupleToOb r; } PLyTypeInput; -/* convert PyObject to a Postgresql Datum or tuple. - * output from Python +/* + * Conversion from Python object to a Postgresql Datum. + * + * The 'inarray' argument to the conversion function is true, if the + * converted value was in an array (Python list). It is used to give a + * better error message in some cases. */ struct PLyObToDatum; -typedef Datum (*PLyObToDatumFunc) (struct PLyObToDatum *, int32, PyObject *); +typedef Datum (*PLyObToDatumFunc) (struct PLyObToDatum *arg, int32 typmod, PyObject *val, bool inarray); typedef struct PLyObToDatum { @@ -104,7 +111,7 @@ extern void PLy_output_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc); extern void PLy_output_record_funcs(PLyTypeInfo *arg, TupleDesc desc); /* conversion from Python objects to composite Datums */ -extern Datum PLyObject_ToCompositeDatum(PLyTypeInfo *info, TupleDesc desc, PyObject *plrv); +extern Datum PLyObject_ToCompositeDatum(PLyTypeInfo *info, TupleDesc desc, PyObject *plrv, bool isarray); /* conversion from heap tuples to Python dictionaries */ extern PyObject *PLyDict_FromTuple(PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc); diff --git a/src/pl/plpython/plpython.h b/src/pl/plpython/plpython.h index a5d0988f68..d687860ab2 100644 --- a/src/pl/plpython/plpython.h +++ b/src/pl/plpython/plpython.h @@ -2,7 +2,7 @@ * * plpython.h - Python as a procedural language for PostgreSQL * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/pl/plpython/plpython.h diff --git a/src/pl/plpython/sql/plpython_composite.sql b/src/pl/plpython/sql/plpython_composite.sql index 473342c2f4..0fd2f5d5e3 100644 --- a/src/pl/plpython/sql/plpython_composite.sql +++ b/src/pl/plpython/sql/plpython_composite.sql @@ -169,13 +169,13 @@ SELECT * FROM changing_test(); -- tables of composite types CREATE FUNCTION composite_types_table(OUT tab table_record[], OUT typ type_record[] ) RETURNS SETOF record AS $$ -yield {'tab': [['first', 1], ['second', 2]], +yield {'tab': [('first', 1), ('second', 2)], 'typ': [{'first': 'third', 'second': 3}, {'first': 'fourth', 'second': 4}]} -yield {'tab': [['first', 1], ['second', 2]], +yield {'tab': [('first', 1), ('second', 2)], 'typ': [{'first': 'third', 'second': 3}, {'first': 'fourth', 'second': 4}]} -yield {'tab': [['first', 1], ['second', 2]], +yield {'tab': [('first', 1), ('second', 2)], 'typ': [{'first': 'third', 'second': 3}, {'first': 'fourth', 'second': 4}]} $$ LANGUAGE plpythonu; @@ -207,3 +207,18 @@ SELECT * FROM return_record_2('v4') AS (v1 int, v3 int, v2 int); -- works SELECT * FROM return_record_2('v3') AS (v1 int, v3 int, v2 int); SELECT * FROM return_record_2('v3') AS (v1 int, v2 int, v3 int); + +-- multi-dimensional array of composite types. +CREATE FUNCTION composite_type_as_list() RETURNS type_record[] AS $$ + return [[('first', 1), ('second', 1)], [('first', 2), ('second', 2)], [('first', 3), ('second', 3)]]; +$$ LANGUAGE plpythonu; +SELECT * FROM composite_type_as_list(); + +-- Starting with PostgreSQL 10, a composite type in an array cannot be +-- represented as a Python list, because it's ambiguous with multi-dimensional +-- arrays. So this throws an error now. The error should contain a useful hint +-- on the issue. +CREATE FUNCTION composite_type_as_list_broken() RETURNS type_record[] AS $$ + return [['first', 1]]; +$$ LANGUAGE plpythonu; +SELECT * FROM composite_type_as_list_broken(); diff --git a/src/pl/plpython/sql/plpython_spi.sql b/src/pl/plpython/sql/plpython_spi.sql index 87170609da..7427de824b 100644 --- a/src/pl/plpython/sql/plpython_spi.sql +++ b/src/pl/plpython/sql/plpython_spi.sql @@ -135,8 +135,8 @@ SELECT result_len_test($$UPDATE foo3 SET b= '' WHERE a = 2$$); CREATE FUNCTION result_subscript_test() RETURNS void AS $$ -result = plpy.execute("SELECT 1 AS c UNION SELECT 2 " - "UNION SELECT 3 UNION SELECT 4") +result = plpy.execute("SELECT 1 AS c UNION ALL SELECT 2 " + "UNION ALL SELECT 3 UNION ALL SELECT 4") plpy.info(result[1]['c']) plpy.info(result[-1]['c']) diff --git a/src/pl/plpython/sql/plpython_test.sql b/src/pl/plpython/sql/plpython_test.sql index fa3c465ef8..5f1be9c94a 100644 --- a/src/pl/plpython/sql/plpython_test.sql +++ b/src/pl/plpython/sql/plpython_test.sql @@ -27,11 +27,11 @@ select "Argument test #1"(users, fname, lname) from users where lname = 'doe' or -- check module contents -CREATE FUNCTION module_contents() RETURNS text AS +CREATE FUNCTION module_contents() RETURNS SETOF text AS $$ contents = list(filter(lambda x: not x.startswith("__"), dir(plpy))) contents.sort() -return ", ".join(contents) +return contents $$ LANGUAGE plpythonu; select module_contents(); diff --git a/src/pl/plpython/sql/plpython_types.sql b/src/pl/plpython/sql/plpython_types.sql index 19d920d3c7..8c57297c24 100644 --- a/src/pl/plpython/sql/plpython_types.sql +++ b/src/pl/plpython/sql/plpython_types.sql @@ -237,14 +237,74 @@ SELECT * FROM test_type_conversion_array_int4(ARRAY[NULL,1]); SELECT * FROM test_type_conversion_array_int4(ARRAY[]::integer[]); SELECT * FROM test_type_conversion_array_int4(NULL); SELECT * FROM test_type_conversion_array_int4(ARRAY[[1,2,3],[4,5,6]]); +SELECT * FROM test_type_conversion_array_int4(ARRAY[[[1,2,NULL],[NULL,5,6]],[[NULL,8,9],[10,11,12]]]); +SELECT * FROM test_type_conversion_array_int4('[2:4]={1,2,3}'); + +CREATE FUNCTION test_type_conversion_array_int8(x int8[]) RETURNS int8[] AS $$ +plpy.info(x, type(x)) +return x +$$ LANGUAGE plpythonu; + +SELECT * FROM test_type_conversion_array_int8(ARRAY[[[1,2,NULL],[NULL,5,6]],[[NULL,8,9],[10,11,12]]]::int8[]); + +CREATE FUNCTION test_type_conversion_array_date(x date[]) RETURNS date[] AS $$ +plpy.info(x, type(x)) +return x +$$ LANGUAGE plpythonu; + +SELECT * FROM test_type_conversion_array_date(ARRAY[[['2016-09-21','2016-09-22',NULL],[NULL,'2016-10-21','2016-10-22']], + [[NULL,'2016-11-21','2016-10-21'],['2015-09-21','2015-09-22','2014-09-21']]]::date[]); + +CREATE FUNCTION test_type_conversion_array_timestamp(x timestamp[]) RETURNS timestamp[] AS $$ +plpy.info(x, type(x)) +return x +$$ LANGUAGE plpythonu; + +SELECT * FROM test_type_conversion_array_timestamp(ARRAY[[['2016-09-21 15:34:24.078792-04','2016-10-22 11:34:24.078795-04',NULL], + [NULL,'2016-10-21 11:34:25.078792-04','2016-10-21 11:34:24.098792-04']], + [[NULL,'2016-01-21 11:34:24.078792-04','2016-11-21 11:34:24.108792-04'], + ['2015-09-21 11:34:24.079792-04','2014-09-21 11:34:24.078792-04','2013-09-21 11:34:24.078792-04']]]::timestamp[]); +CREATE OR REPLACE FUNCTION pyreturnmultidemint4(h int4, i int4, j int4, k int4 ) RETURNS int4[] AS $BODY$ +m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] for w in range(k)] +plpy.info(m, type(m)) +return m +$BODY$ LANGUAGE plpythonu; + +select pyreturnmultidemint4(8,5,3,2); + +CREATE OR REPLACE FUNCTION pyreturnmultidemint8(h int4, i int4, j int4, k int4 ) RETURNS int8[] AS $BODY$ +m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] for w in range(k)] +plpy.info(m, type(m)) +return m +$BODY$ LANGUAGE plpythonu; + +select pyreturnmultidemint8(5,5,3,2); + +CREATE OR REPLACE FUNCTION pyreturnmultidemfloat4(h int4, i int4, j int4, k int4 ) RETURNS float4[] AS $BODY$ +m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] for w in range(k)] +plpy.info(m, type(m)) +return m +$BODY$ LANGUAGE plpythonu; + +select pyreturnmultidemfloat4(6,5,3,2); + +CREATE OR REPLACE FUNCTION pyreturnmultidemfloat8(h int4, i int4, j int4, k int4 ) RETURNS float8[] AS $BODY$ +m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] for w in range(k)] +plpy.info(m, type(m)) +return m +$BODY$ LANGUAGE plpythonu; + +select pyreturnmultidemfloat8(7,5,3,2); + CREATE FUNCTION test_type_conversion_array_text(x text[]) RETURNS text[] AS $$ plpy.info(x, type(x)) return x $$ LANGUAGE plpythonu; SELECT * FROM test_type_conversion_array_text(ARRAY['foo', 'bar']); +SELECT * FROM test_type_conversion_array_text(ARRAY[['foo', 'bar'],['foo2', 'bar2']]); CREATE FUNCTION test_type_conversion_array_bytea(x bytea[]) RETURNS bytea[] AS $$ @@ -268,6 +328,18 @@ $$ LANGUAGE plpythonu; SELECT * FROM test_type_conversion_array_mixed2(); +CREATE FUNCTION test_type_conversion_mdarray_malformed() RETURNS int[] AS $$ +return [[1,2,3],[4,5]] +$$ LANGUAGE plpythonu; + +SELECT * FROM test_type_conversion_mdarray_malformed(); + +CREATE FUNCTION test_type_conversion_mdarray_toodeep() RETURNS int[] AS $$ +return [[[[[[[1]]]]]]] +$$ LANGUAGE plpythonu; + +SELECT * FROM test_type_conversion_mdarray_toodeep(); + CREATE FUNCTION test_type_conversion_array_record() RETURNS type_record[] AS $$ return [{'first': 'one', 'second': 42}, {'first': 'two', 'second': 11}] diff --git a/src/pl/tcl/expected/pltcl_queries.out b/src/pl/tcl/expected/pltcl_queries.out index 6cb1fdbb61..7300b315d6 100644 --- a/src/pl/tcl/expected/pltcl_queries.out +++ b/src/pl/tcl/expected/pltcl_queries.out @@ -185,12 +185,23 @@ select * from T_pkey2 order by key1 using @<, key2 collate "C"; -- show dump of trigger data insert into trigger_test values(1,'insert'); -NOTICE: NEW: {i: 1, v: insert} +NOTICE: NEW: {} +NOTICE: OLD: {} +NOTICE: TG_level: STATEMENT +NOTICE: TG_name: statement_trigger +NOTICE: TG_op: INSERT +NOTICE: TG_relatts: {{} i v {} test_skip test_return_null test_argisnull} +NOTICE: TG_relid: bogus:12345 +NOTICE: TG_table_name: trigger_test +NOTICE: TG_table_schema: public +NOTICE: TG_when: BEFORE +NOTICE: args: {42 {statement trigger}} +NOTICE: NEW: {i: 1, test_argisnull: f, test_return_null: f, test_skip: f, v: insert} NOTICE: OLD: {} NOTICE: TG_level: ROW NOTICE: TG_name: show_trigger_data_trig NOTICE: TG_op: INSERT -NOTICE: TG_relatts: {{} i v} +NOTICE: TG_relatts: {{} i v {} test_skip test_return_null test_argisnull} NOTICE: TG_relid: bogus:12345 NOTICE: TG_table_name: trigger_test NOTICE: TG_table_schema: public @@ -232,13 +243,37 @@ NOTICE: TG_table_name: trigger_test_view NOTICE: TG_table_schema: public NOTICE: TG_when: {INSTEAD OF} NOTICE: args: {24 {skidoo view}} +update trigger_test set v = 'update', test_skip=true where i = 1; +NOTICE: NEW: {} +NOTICE: OLD: {} +NOTICE: TG_level: STATEMENT +NOTICE: TG_name: statement_trigger +NOTICE: TG_op: UPDATE +NOTICE: TG_relatts: {{} i v {} test_skip test_return_null test_argisnull} +NOTICE: TG_relid: bogus:12345 +NOTICE: TG_table_name: trigger_test +NOTICE: TG_table_schema: public +NOTICE: TG_when: BEFORE +NOTICE: args: {42 {statement trigger}} +NOTICE: SKIPPING OPERATION UPDATE update trigger_test set v = 'update' where i = 1; -NOTICE: NEW: {i: 1, v: update} -NOTICE: OLD: {i: 1, v: insert} +NOTICE: NEW: {} +NOTICE: OLD: {} +NOTICE: TG_level: STATEMENT +NOTICE: TG_name: statement_trigger +NOTICE: TG_op: UPDATE +NOTICE: TG_relatts: {{} i v {} test_skip test_return_null test_argisnull} +NOTICE: TG_relid: bogus:12345 +NOTICE: TG_table_name: trigger_test +NOTICE: TG_table_schema: public +NOTICE: TG_when: BEFORE +NOTICE: args: {42 {statement trigger}} +NOTICE: NEW: {i: 1, test_argisnull: f, test_return_null: f, test_skip: f, v: update} +NOTICE: OLD: {i: 1, test_argisnull: f, test_return_null: f, test_skip: f, v: insert} NOTICE: TG_level: ROW NOTICE: TG_name: show_trigger_data_trig NOTICE: TG_op: UPDATE -NOTICE: TG_relatts: {{} i v} +NOTICE: TG_relatts: {{} i v {} test_skip test_return_null test_argisnull} NOTICE: TG_relid: bogus:12345 NOTICE: TG_table_name: trigger_test NOTICE: TG_table_schema: public @@ -246,16 +281,39 @@ NOTICE: TG_when: BEFORE NOTICE: args: {23 skidoo} delete from trigger_test; NOTICE: NEW: {} -NOTICE: OLD: {i: 1, v: update} +NOTICE: OLD: {} +NOTICE: TG_level: STATEMENT +NOTICE: TG_name: statement_trigger +NOTICE: TG_op: DELETE +NOTICE: TG_relatts: {{} i v {} test_skip test_return_null test_argisnull} +NOTICE: TG_relid: bogus:12345 +NOTICE: TG_table_name: trigger_test +NOTICE: TG_table_schema: public +NOTICE: TG_when: BEFORE +NOTICE: args: {42 {statement trigger}} +NOTICE: NEW: {} +NOTICE: OLD: {i: 1, test_argisnull: f, test_return_null: f, test_skip: f, v: update} NOTICE: TG_level: ROW NOTICE: TG_name: show_trigger_data_trig NOTICE: TG_op: DELETE -NOTICE: TG_relatts: {{} i v} +NOTICE: TG_relatts: {{} i v {} test_skip test_return_null test_argisnull} NOTICE: TG_relid: bogus:12345 NOTICE: TG_table_name: trigger_test NOTICE: TG_table_schema: public NOTICE: TG_when: BEFORE NOTICE: args: {23 skidoo} +truncate trigger_test; +NOTICE: NEW: {} +NOTICE: OLD: {} +NOTICE: TG_level: STATEMENT +NOTICE: TG_name: statement_trigger +NOTICE: TG_op: TRUNCATE +NOTICE: TG_relatts: {{} i v {} test_skip test_return_null test_argisnull} +NOTICE: TG_relid: bogus:12345 +NOTICE: TG_table_name: trigger_test +NOTICE: TG_table_schema: public +NOTICE: TG_when: BEFORE +NOTICE: args: {42 {statement trigger}} -- Test composite-type arguments select tcl_composite_arg_ref1(row('tkey', 42, 'ref2')); tcl_composite_arg_ref1 @@ -288,6 +346,22 @@ select tcl_argisnull(null); t (1 row) +-- should error +insert into trigger_test(test_argisnull) values(true); +NOTICE: NEW: {} +NOTICE: OLD: {} +NOTICE: TG_level: STATEMENT +NOTICE: TG_name: statement_trigger +NOTICE: TG_op: INSERT +NOTICE: TG_relatts: {{} i v {} test_skip test_return_null test_argisnull} +NOTICE: TG_relid: bogus:12345 +NOTICE: TG_table_name: trigger_test +NOTICE: TG_table_schema: public +NOTICE: TG_when: BEFORE +NOTICE: args: {42 {statement trigger}} +ERROR: argisnull cannot be used in triggers +select trigger_data(); +ERROR: trigger functions can only be called as triggers -- Test spi_lastoid primitive create temp table t1 (f1 int); select tcl_lastoid('t1'); @@ -303,3 +377,286 @@ select tcl_lastoid('t2') > 0; t (1 row) +-- test some error cases +create function tcl_error(out a int, out b int) as $$return {$$ language pltcl; +select tcl_error(); +ERROR: missing close-brace +create function bad_record(out a text, out b text) as $$return [list a]$$ language pltcl; +select bad_record(); +ERROR: column name/value list must have even number of elements +create function bad_field(out a text, out b text) as $$return [list a 1 b 2 cow 3]$$ language pltcl; +select bad_field(); +ERROR: column name/value list contains nonexistent column name "cow" +-- test compound return +select * from tcl_test_cube_squared(5); + squared | cubed +---------+------- + 25 | 125 +(1 row) + +-- test SRF +select * from tcl_test_squared_rows(0,5); + x | y +---+---- + 0 | 0 + 1 | 1 + 2 | 4 + 3 | 9 + 4 | 16 +(5 rows) + +select * from tcl_test_sequence(0,5) as a; + a +--- + 0 + 1 + 2 + 3 + 4 +(5 rows) + +select 1, tcl_test_sequence(0,5); + ?column? | tcl_test_sequence +----------+------------------- + 1 | 0 + 1 | 1 + 1 | 2 + 1 | 3 + 1 | 4 +(5 rows) + +create function non_srf() returns int as $$return_next 1$$ language pltcl; +select non_srf(); +ERROR: return_next cannot be used in non-set-returning functions +create function bad_record_srf(out a text, out b text) returns setof record as $$ +return_next [list a] +$$ language pltcl; +select bad_record_srf(); +ERROR: column name/value list must have even number of elements +create function bad_field_srf(out a text, out b text) returns setof record as $$ +return_next [list a 1 b 2 cow 3] +$$ language pltcl; +select bad_field_srf(); +ERROR: column name/value list contains nonexistent column name "cow" +-- test quote +select tcl_eval('quote foo bar'); +ERROR: wrong # args: should be "quote string" +select tcl_eval('quote [format %c 39]'); + tcl_eval +---------- + '' +(1 row) + +select tcl_eval('quote [format %c 92]'); + tcl_eval +---------- + \\ +(1 row) + +-- Test argisnull +select tcl_eval('argisnull'); +ERROR: wrong # args: should be "argisnull argno" +select tcl_eval('argisnull 14'); +ERROR: argno out of range +select tcl_eval('argisnull abc'); +ERROR: expected integer but got "abc" +-- Test return_null +select tcl_eval('return_null 14'); +ERROR: wrong # args: should be "return_null " +-- should error +insert into trigger_test(test_return_null) values(true); +NOTICE: NEW: {} +NOTICE: OLD: {} +NOTICE: TG_level: STATEMENT +NOTICE: TG_name: statement_trigger +NOTICE: TG_op: INSERT +NOTICE: TG_relatts: {{} i v {} test_skip test_return_null test_argisnull} +NOTICE: TG_relid: bogus:12345 +NOTICE: TG_table_name: trigger_test +NOTICE: TG_table_schema: public +NOTICE: TG_when: BEFORE +NOTICE: args: {42 {statement trigger}} +ERROR: return_null cannot be used in triggers +-- Test spi_exec +select tcl_eval('spi_exec'); +ERROR: wrong # args: should be "spi_exec ?-count n? ?-array name? query ?loop body?" +select tcl_eval('spi_exec -count'); +ERROR: missing argument to -count or -array +select tcl_eval('spi_exec -array'); +ERROR: missing argument to -count or -array +select tcl_eval('spi_exec -count abc'); +ERROR: expected integer but got "abc" +select tcl_eval('spi_exec query loop body toomuch'); +ERROR: wrong # args: should be "query ?loop body?" +select tcl_eval('spi_exec "begin; rollback;"'); +ERROR: pltcl: SPI_execute failed: SPI_ERROR_TRANSACTION +-- Test spi_execp +select tcl_eval('spi_execp'); +ERROR: missing argument to -count or -array +select tcl_eval('spi_execp -count'); +ERROR: missing argument to -array, -count or -nulls +select tcl_eval('spi_execp -array'); +ERROR: missing argument to -array, -count or -nulls +select tcl_eval('spi_execp -count abc'); +ERROR: expected integer but got "abc" +select tcl_eval('spi_execp -nulls'); +ERROR: missing argument to -array, -count or -nulls +select tcl_eval('spi_execp ""'); +ERROR: invalid queryid '' +-- test spi_prepare +select tcl_eval('spi_prepare'); +ERROR: wrong # args: should be "spi_prepare query argtypes" +select tcl_eval('spi_prepare a b'); +ERROR: type "b" does not exist +select tcl_eval('spi_prepare a "b {"'); +ERROR: unmatched open brace in list +select tcl_error_handling_test($tcl$spi_prepare "select moo" []$tcl$); + tcl_error_handling_test +-------------------------------------- + SQLSTATE: 42703 + + condition: undefined_column + + cursor_position: 8 + + message: column "moo" does not exist+ + statement: select moo +(1 row) + +-- test full error text +select tcl_error_handling_test($tcl$ +spi_exec "DO $$ +BEGIN +RAISE 'my message' + USING HINT = 'my hint' + , DETAIL = 'my detail' + , SCHEMA = 'my schema' + , TABLE = 'my table' + , COLUMN = 'my column' + , CONSTRAINT = 'my constraint' + , DATATYPE = 'my datatype' +; +END$$;" +$tcl$); + tcl_error_handling_test +-------------------------------------------------------------- + SQLSTATE: P0001 + + column: my column + + condition: raise_exception + + constraint: my constraint + + context: PL/pgSQL function inline_code_block line 3 at RAISE+ + SQL statement "DO $$ + + BEGIN + + RAISE 'my message' + + USING HINT = 'my hint' + + , DETAIL = 'my detail' + + , SCHEMA = 'my schema' + + , TABLE = 'my table' + + , COLUMN = 'my column' + + , CONSTRAINT = 'my constraint' + + , DATATYPE = 'my datatype' + + ; + + END$$;" + + datatype: my datatype + + detail: my detail + + hint: my hint + + message: my message + + schema: my schema + + table: my table +(1 row) + +-- verify tcl_error_handling_test() properly reports non-postgres errors +select tcl_error_handling_test('moo'); + tcl_error_handling_test +---------------------------- + invalid command name "moo" +(1 row) + +-- test elog +select tcl_eval('elog'); +ERROR: wrong # args: should be "elog level msg" +select tcl_eval('elog foo bar'); +ERROR: bad priority "foo": must be DEBUG, LOG, INFO, NOTICE, WARNING, ERROR, or FATAL +-- test forced error +select tcl_eval('error "forced error"'); +ERROR: forced error +-- test loop control in spi_exec[p] +select tcl_spi_exec(true, 'break'); +NOTICE: col1 1, col2 foo +NOTICE: col1 2, col2 bar +NOTICE: action: break +NOTICE: end of function + tcl_spi_exec +-------------- + +(1 row) + +select tcl_spi_exec(true, 'continue'); +NOTICE: col1 1, col2 foo +NOTICE: col1 2, col2 bar +NOTICE: action: continue +NOTICE: col1 3, col2 baz +NOTICE: end of function + tcl_spi_exec +-------------- + +(1 row) + +select tcl_spi_exec(true, 'error'); +NOTICE: col1 1, col2 foo +NOTICE: col1 2, col2 bar +NOTICE: action: error +ERROR: error message +select tcl_spi_exec(true, 'return'); +NOTICE: col1 1, col2 foo +NOTICE: col1 2, col2 bar +NOTICE: action: return + tcl_spi_exec +-------------- + +(1 row) + +select tcl_spi_exec(false, 'break'); +NOTICE: col1 1, col2 foo +NOTICE: col1 2, col2 bar +NOTICE: action: break +NOTICE: end of function + tcl_spi_exec +-------------- + +(1 row) + +select tcl_spi_exec(false, 'continue'); +NOTICE: col1 1, col2 foo +NOTICE: col1 2, col2 bar +NOTICE: action: continue +NOTICE: col1 3, col2 baz +NOTICE: end of function + tcl_spi_exec +-------------- + +(1 row) + +select tcl_spi_exec(false, 'error'); +NOTICE: col1 1, col2 foo +NOTICE: col1 2, col2 bar +NOTICE: action: error +ERROR: error message +select tcl_spi_exec(false, 'return'); +NOTICE: col1 1, col2 foo +NOTICE: col1 2, col2 bar +NOTICE: action: return + tcl_spi_exec +-------------- + +(1 row) + +-- forcibly run the Tcl event loop for awhile, to check that we have not +-- messed things up too badly by disabling the Tcl notifier subsystem +select tcl_eval($$ + unset -nocomplain ::tcl_vwait + after 100 {set ::tcl_vwait 1} + vwait ::tcl_vwait + unset -nocomplain ::tcl_vwait$$); + tcl_eval +---------- + +(1 row) + diff --git a/src/pl/tcl/expected/pltcl_setup.out b/src/pl/tcl/expected/pltcl_setup.out index e65e9e3ff7..e213b94225 100644 --- a/src/pl/tcl/expected/pltcl_setup.out +++ b/src/pl/tcl/expected/pltcl_setup.out @@ -49,10 +49,31 @@ create function check_pkey1_exists(int4, bpchar) returns bool as E' return "f" ' language pltcl; -- dump trigger data -CREATE TABLE trigger_test - (i int, v text ); -CREATE VIEW trigger_test_view AS SELECT * FROM trigger_test; +CREATE TABLE trigger_test ( + i int, + v text, + dropme text, + test_skip boolean DEFAULT false, + test_return_null boolean DEFAULT false, + test_argisnull boolean DEFAULT false +); +-- Make certain dropped attributes are handled correctly +ALTER TABLE trigger_test DROP dropme; +CREATE VIEW trigger_test_view AS SELECT i, v FROM trigger_test; CREATE FUNCTION trigger_data() returns trigger language pltcl as $_$ + if {$TG_table_name eq "trigger_test" && $TG_level eq "ROW" && $TG_op ne "DELETE"} { + # Special case tests + if {$NEW(test_return_null) eq "t" } { + return_null + } + if {$NEW(test_argisnull) eq "t" } { + set should_error [argisnull 1] + } + if {$NEW(test_skip) eq "t" } { + elog NOTICE "SKIPPING OPERATION $TG_op" + return SKIP + } + } if { [info exists TG_relid] } { set TG_relid "bogus:12345" @@ -86,6 +107,9 @@ $_$; CREATE TRIGGER show_trigger_data_trig BEFORE INSERT OR UPDATE OR DELETE ON trigger_test FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo'); +CREATE TRIGGER statement_trigger +BEFORE INSERT OR UPDATE OR DELETE OR TRUNCATE ON trigger_test +FOR EACH STATEMENT EXECUTE PROCEDURE trigger_data(42,'statement trigger'); CREATE TRIGGER show_trigger_data_view_trig INSTEAD OF INSERT OR UPDATE OR DELETE ON trigger_test_view FOR EACH ROW EXECUTE PROCEDURE trigger_data(24,'skidoo view'); @@ -533,12 +557,12 @@ select tcl_date_week(2001,10,24); (1 row) -- test pltcl event triggers -create or replace function tclsnitch() returns event_trigger language pltcl as $$ +create function tclsnitch() returns event_trigger language pltcl as $$ elog NOTICE "tclsnitch: $TG_event $TG_tag" $$; create event trigger tcl_a_snitch on ddl_command_start execute procedure tclsnitch(); create event trigger tcl_b_snitch on ddl_command_end execute procedure tclsnitch(); -create or replace function foobar() returns int language sql as $$select 1;$$; +create function foobar() returns int language sql as $$select 1;$$; NOTICE: tclsnitch: ddl_command_start CREATE FUNCTION NOTICE: tclsnitch: ddl_command_end CREATE FUNCTION alter function foobar() cost 77; @@ -555,31 +579,108 @@ NOTICE: tclsnitch: ddl_command_start DROP TABLE NOTICE: tclsnitch: ddl_command_end DROP TABLE drop event trigger tcl_a_snitch; drop event trigger tcl_b_snitch; +create function tcl_test_cube_squared(in int, out squared int, out cubed int) as $$ + return [list squared [expr {$1 * $1}] cubed [expr {$1 * $1 * $1}]] +$$ language pltcl; +create function tcl_test_squared_rows(int,int) returns table (x int, y int) as $$ + for {set i $1} {$i < $2} {incr i} { + return_next [list y [expr {$i * $i}] x $i] + } +$$ language pltcl; +create function tcl_test_sequence(int,int) returns setof int as $$ + for {set i $1} {$i < $2} {incr i} { + return_next $i + } +$$ language pltcl; +create function tcl_eval(string text) returns text as $$ + eval $1 +$$ language pltcl; -- test use of errorCode in error handling -create function tcl_error_handling_test() returns text as $$ - global errorCode - if {[catch { spi_exec "select no_such_column from foo;" }]} { - array set errArray $errorCode - if {$errArray(condition) == "undefined_table"} { - return "expected error: $errArray(message)" - } else { - return "unexpected error: $errArray(condition) $errArray(message)" +create function tcl_error_handling_test(text) returns text +language pltcl +as $function$ + if {[catch $1 err]} { + # If not a Postgres error, just return the basic error message + if {[lindex $::errorCode 0] != "POSTGRES"} { + return $err } + + # Get rid of keys that can't be expected to remain constant + array set myArray $::errorCode + unset myArray(POSTGRES) + unset -nocomplain myArray(funcname) + unset -nocomplain myArray(filename) + unset -nocomplain myArray(lineno) + + # Format into something nicer + set vals [] + foreach {key} [lsort [array names myArray]] { + set value [string map {"\n" "\n\t"} $myArray($key)] + lappend vals "$key: $value" + } + return [join $vals "\n"] } else { return "no error" } -$$ language pltcl; -select tcl_error_handling_test(); - tcl_error_handling_test ------------------------------------------------ - expected error: relation "foo" does not exist -(1 row) - -create temp table foo(f1 int); -select tcl_error_handling_test(); - tcl_error_handling_test ---------------------------------------------------------------------------- - unexpected error: undefined_column column "no_such_column" does not exist -(1 row) - -drop table foo; +$function$; +-- test spi_exec and spi_execp with -array +create function tcl_spi_exec( + prepare boolean, + action text +) +returns void language pltcl AS $function$ +set query "select * from (values (1,'foo'),(2,'bar'),(3,'baz')) v(col1,col2)" +if {$1 == "t"} { + set prep [spi_prepare $query {}] + spi_execp -array A $prep { + elog NOTICE "col1 $A(col1), col2 $A(col2)" + + switch $A(col1) { + 2 { + elog NOTICE "action: $2" + switch $2 { + break { + break + } + continue { + continue + } + return { + return + } + error { + error "error message" + } + } + error "should not get here" + } + } + } +} else { + spi_exec -array A $query { + elog NOTICE "col1 $A(col1), col2 $A(col2)" + + switch $A(col1) { + 2 { + elog NOTICE "action: $2" + switch $2 { + break { + break + } + continue { + continue + } + return { + return + } + error { + error "error message" + } + } + error "should not get here" + } + } + } +} +elog NOTICE "end of function" +$function$; diff --git a/src/pl/tcl/generate-pltclerrcodes.pl b/src/pl/tcl/generate-pltclerrcodes.pl index 144e159909..e20a0aff4a 100644 --- a/src/pl/tcl/generate-pltclerrcodes.pl +++ b/src/pl/tcl/generate-pltclerrcodes.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl # # Generate the pltclerrcodes.h header from errcodes.txt -# Copyright (c) 2000-2016, PostgreSQL Global Development Group +# Copyright (c) 2000-2017, PostgreSQL Global Development Group use warnings; use strict; diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c index 6ee4153ae6..ec5b54ab32 100644 --- a/src/pl/tcl/pltcl.c +++ b/src/pl/tcl/pltcl.c @@ -21,6 +21,7 @@ #include "commands/trigger.h" #include "executor/spi.h" #include "fmgr.h" +#include "funcapi.h" #include "mb/pg_wchar.h" #include "miscadmin.h" #include "nodes/makefuncs.h" @@ -114,21 +115,38 @@ typedef struct pltcl_interp_desc /********************************************************************** * The information we cache about loaded procedures + * + * The pltcl_proc_desc struct itself, as well as all subsidiary data, + * is stored in the memory context identified by the fn_cxt field. + * We can reclaim all the data by deleting that context, and should do so + * when the fn_refcount goes to zero. (But note that we do not bother + * trying to clean up Tcl's copy of the procedure definition: it's Tcl's + * problem to manage its memory when we replace a proc definition. We do + * not clean up pltcl_proc_descs when a pg_proc row is deleted, only when + * it is updated, and the same policy applies to Tcl's copy as well.) + * + * Note that the data in this struct is shared across all active calls; + * nothing except the fn_refcount should be changed by a call instance. **********************************************************************/ typedef struct pltcl_proc_desc { - char *user_proname; - char *internal_proname; - TransactionId fn_xmin; - ItemPointerData fn_tid; - bool fn_readonly; - bool lanpltrusted; - pltcl_interp_desc *interp_desc; - FmgrInfo result_in_func; - Oid result_typioparam; - int nargs; - FmgrInfo arg_out_func[FUNC_MAX_ARGS]; - bool arg_is_rowtype[FUNC_MAX_ARGS]; + char *user_proname; /* user's name (from pg_proc.proname) */ + char *internal_proname; /* Tcl name (based on function OID) */ + MemoryContext fn_cxt; /* memory context for this procedure */ + unsigned long fn_refcount; /* number of active references */ + TransactionId fn_xmin; /* xmin of pg_proc row */ + ItemPointerData fn_tid; /* TID of pg_proc row */ + bool fn_readonly; /* is function readonly? */ + bool lanpltrusted; /* is it pltcl (vs. pltclu)? */ + pltcl_interp_desc *interp_desc; /* interpreter to use */ + FmgrInfo result_in_func; /* input function for fn's result type */ + Oid result_typioparam; /* param to pass to same */ + bool fn_retisset; /* true if function returns a set */ + bool fn_retistuple; /* true if function returns composite */ + int nargs; /* number of arguments */ + /* these arrays have nargs entries: */ + FmgrInfo *arg_out_func; /* output fns for arg types */ + bool *arg_is_rowtype; /* is each arg composite? */ } pltcl_proc_desc; @@ -176,6 +194,35 @@ typedef struct pltcl_proc_ptr } pltcl_proc_ptr; +/********************************************************************** + * Per-call state + **********************************************************************/ +typedef struct pltcl_call_state +{ + /* Call info struct, or NULL in a trigger */ + FunctionCallInfo fcinfo; + + /* Trigger data, if we're in a normal (not event) trigger; else NULL */ + TriggerData *trigdata; + + /* Function we're executing (NULL if not yet identified) */ + pltcl_proc_desc *prodesc; + + /* + * Information for SRFs and functions returning composite types. + * ret_tupdesc and attinmeta are set up if either fn_retistuple or + * fn_retisset, since even a scalar-returning SRF needs a tuplestore. + */ + TupleDesc ret_tupdesc; /* return rowtype, if retistuple or retisset */ + AttInMetadata *attinmeta; /* metadata for building tuples of that type */ + + ReturnSetInfo *rsi; /* passed-in ReturnSetInfo, if any */ + Tuplestorestate *tuple_store; /* SRFs accumulate result here */ + MemoryContext tuple_store_cxt; /* context and resowner for tuplestore */ + ResourceOwner tuple_store_owner; +} pltcl_call_state; + + /********************************************************************** * Global data **********************************************************************/ @@ -184,9 +231,8 @@ static Tcl_Interp *pltcl_hold_interp = NULL; static HTAB *pltcl_interp_htab = NULL; static HTAB *pltcl_proc_htab = NULL; -/* these are saved and restored by pltcl_handler */ -static FunctionCallInfo pltcl_current_fcinfo = NULL; -static pltcl_proc_desc *pltcl_current_prodesc = NULL; +/* this is saved and restored by pltcl_handler */ +static pltcl_call_state *pltcl_current_call_state = NULL; /********************************************************************** * Lookup table for SQLSTATE condition names @@ -213,10 +259,12 @@ static void pltcl_init_load_unknown(Tcl_Interp *interp); static Datum pltcl_handler(PG_FUNCTION_ARGS, bool pltrusted); -static Datum pltcl_func_handler(PG_FUNCTION_ARGS, bool pltrusted); - -static HeapTuple pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted); -static void pltcl_event_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted); +static Datum pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state, + bool pltrusted); +static HeapTuple pltcl_trigger_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state, + bool pltrusted); +static void pltcl_event_trigger_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state, + bool pltrusted); static void throw_tcl_error(Tcl_Interp *interp, const char *proname); @@ -234,7 +282,8 @@ static int pltcl_argisnull(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static int pltcl_returnnull(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); - +static int pltcl_returnnext(ClientData cdata, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]); static int pltcl_SPI_execute(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static int pltcl_process_SPI_result(Tcl_Interp *interp, @@ -250,9 +299,21 @@ static int pltcl_SPI_execute_plan(ClientData cdata, Tcl_Interp *interp, static int pltcl_SPI_lastoid(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); +static void pltcl_subtrans_begin(MemoryContext oldcontext, + ResourceOwner oldowner); +static void pltcl_subtrans_commit(MemoryContext oldcontext, + ResourceOwner oldowner); +static void pltcl_subtrans_abort(Tcl_Interp *interp, + MemoryContext oldcontext, + ResourceOwner oldowner); + static void pltcl_set_tuple_values(Tcl_Interp *interp, const char *arrayname, uint64 tupno, HeapTuple tuple, TupleDesc tupdesc); static Tcl_Obj *pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc); +static HeapTuple pltcl_build_tuple_result(Tcl_Interp *interp, + Tcl_Obj **kvObjv, int kvObjc, + pltcl_call_state *call_state); +static void pltcl_init_tuple_store(pltcl_call_state *call_state); /* @@ -312,23 +373,6 @@ pltcl_WaitForEvent(CONST86 Tcl_Time *timePtr) } -/* - * This routine is a crock, and so is everyplace that calls it. The problem - * is that the cached form of pltcl functions/queries is allocated permanently - * (mostly via malloc()) and never released until backend exit. Subsidiary - * data structures such as fmgr info records therefore must live forever - * as well. A better implementation would store all this stuff in a per- - * function memory context that could be reclaimed at need. In the meantime, - * fmgr_info_cxt must be called specifying TopMemoryContext so that whatever - * it might allocate, and whatever the eventual function might allocate using - * fn_mcxt, will live forever too. - */ -static void -perm_fmgr_info(Oid functionId, FmgrInfo *finfo) -{ - fmgr_info_cxt(functionId, finfo, TopMemoryContext); -} - /* * _PG_init() - library load-time initialization * @@ -437,7 +481,8 @@ pltcl_init_interp(pltcl_interp_desc *interp_desc, bool pltrusted) pltcl_argisnull, NULL, NULL); Tcl_CreateObjCommand(interp, "return_null", pltcl_returnnull, NULL, NULL); - + Tcl_CreateObjCommand(interp, "return_next", + pltcl_returnnext, NULL, NULL); Tcl_CreateObjCommand(interp, "spi_exec", pltcl_SPI_execute, NULL, NULL); Tcl_CreateObjCommand(interp, "spi_prepare", @@ -569,6 +614,7 @@ pltcl_init_load_unknown(Tcl_Interp *interp) * leave this code as DString - it's only executed once per session ************************************************************/ fno = SPI_fnumber(SPI_tuptable->tupdesc, "modsrc"); + Assert(fno > 0); Tcl_DStringInit(&unknown_src); @@ -630,18 +676,33 @@ pltclu_call_handler(PG_FUNCTION_ARGS) } +/********************************************************************** + * pltcl_handler() - Handler for function and trigger calls, for + * both trusted and untrusted interpreters. + **********************************************************************/ static Datum pltcl_handler(PG_FUNCTION_ARGS, bool pltrusted) { Datum retval; - FunctionCallInfo save_fcinfo; - pltcl_proc_desc *save_prodesc; + pltcl_call_state current_call_state; + pltcl_call_state *save_call_state; + + /* + * Initialize current_call_state to nulls/zeroes; in particular, set its + * prodesc pointer to null. Anything that sets it non-null should + * increase the prodesc's fn_refcount at the same time. We'll decrease + * the refcount, and then delete the prodesc if it's no longer referenced, + * on the way out of this function. This ensures that prodescs live as + * long as needed even if somebody replaces the originating pg_proc row + * while they're executing. + */ + memset(¤t_call_state, 0, sizeof(current_call_state)); /* - * Ensure that static pointers are saved/restored properly + * Ensure that static pointer is saved/restored properly */ - save_fcinfo = pltcl_current_fcinfo; - save_prodesc = pltcl_current_prodesc; + save_call_state = pltcl_current_call_state; + pltcl_current_call_state = ¤t_call_state; PG_TRY(); { @@ -651,31 +712,47 @@ pltcl_handler(PG_FUNCTION_ARGS, bool pltrusted) */ if (CALLED_AS_TRIGGER(fcinfo)) { - pltcl_current_fcinfo = NULL; - retval = PointerGetDatum(pltcl_trigger_handler(fcinfo, pltrusted)); + /* invoke the trigger handler */ + retval = PointerGetDatum(pltcl_trigger_handler(fcinfo, + ¤t_call_state, + pltrusted)); } else if (CALLED_AS_EVENT_TRIGGER(fcinfo)) { - pltcl_current_fcinfo = NULL; - pltcl_event_trigger_handler(fcinfo, pltrusted); + /* invoke the event trigger handler */ + pltcl_event_trigger_handler(fcinfo, ¤t_call_state, pltrusted); retval = (Datum) 0; } else { - pltcl_current_fcinfo = fcinfo; - retval = pltcl_func_handler(fcinfo, pltrusted); + /* invoke the regular function handler */ + current_call_state.fcinfo = fcinfo; + retval = pltcl_func_handler(fcinfo, ¤t_call_state, pltrusted); } } PG_CATCH(); { - pltcl_current_fcinfo = save_fcinfo; - pltcl_current_prodesc = save_prodesc; + /* Restore static pointer, then clean up the prodesc refcount if any */ + pltcl_current_call_state = save_call_state; + if (current_call_state.prodesc != NULL) + { + Assert(current_call_state.prodesc->fn_refcount > 0); + if (--current_call_state.prodesc->fn_refcount == 0) + MemoryContextDelete(current_call_state.prodesc->fn_cxt); + } PG_RE_THROW(); } PG_END_TRY(); - pltcl_current_fcinfo = save_fcinfo; - pltcl_current_prodesc = save_prodesc; + /* Restore static pointer, then clean up the prodesc refcount if any */ + /* (We're being paranoid in case an error is thrown in context deletion) */ + pltcl_current_call_state = save_call_state; + if (current_call_state.prodesc != NULL) + { + Assert(current_call_state.prodesc->fn_refcount > 0); + if (--current_call_state.prodesc->fn_refcount == 0) + MemoryContextDelete(current_call_state.prodesc->fn_cxt); + } return retval; } @@ -685,7 +762,8 @@ pltcl_handler(PG_FUNCTION_ARGS, bool pltrusted) * pltcl_func_handler() - Handler for regular function calls **********************************************************************/ static Datum -pltcl_func_handler(PG_FUNCTION_ARGS, bool pltrusted) +pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state, + bool pltrusted) { pltcl_proc_desc *prodesc; Tcl_Interp *volatile interp; @@ -702,10 +780,32 @@ pltcl_func_handler(PG_FUNCTION_ARGS, bool pltrusted) prodesc = compile_pltcl_function(fcinfo->flinfo->fn_oid, InvalidOid, false, pltrusted); - pltcl_current_prodesc = prodesc; + call_state->prodesc = prodesc; + prodesc->fn_refcount++; interp = prodesc->interp_desc->interp; + /* + * If we're a SRF, check caller can handle materialize mode, and save + * relevant info into call_state. We must ensure that the returned + * tuplestore is owned by the caller's context, even if we first create it + * inside a subtransaction. + */ + if (prodesc->fn_retisset) + { + ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo; + + if (!rsi || !IsA(rsi, ReturnSetInfo) || + (rsi->allowedModes & SFRM_Materialize) == 0) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("set-valued function called in context that cannot accept a set"))); + + call_state->rsi = rsi; + call_state->tuple_store_cxt = rsi->econtext->ecxt_per_query_memory; + call_state->tuple_store_owner = CurrentResourceOwner; + } + /************************************************************ * Create the tcl command to call the internal * proc in the Tcl interpreter @@ -814,11 +914,72 @@ pltcl_func_handler(PG_FUNCTION_ARGS, bool pltrusted) if (SPI_finish() != SPI_OK_FINISH) elog(ERROR, "SPI_finish() failed"); - if (fcinfo->isnull) + if (prodesc->fn_retisset) + { + ReturnSetInfo *rsi = call_state->rsi; + + /* We already checked this is OK */ + rsi->returnMode = SFRM_Materialize; + + /* If we produced any tuples, send back the result */ + if (call_state->tuple_store) + { + rsi->setResult = call_state->tuple_store; + if (call_state->ret_tupdesc) + { + MemoryContext oldcxt; + + oldcxt = MemoryContextSwitchTo(call_state->tuple_store_cxt); + rsi->setDesc = CreateTupleDescCopy(call_state->ret_tupdesc); + MemoryContextSwitchTo(oldcxt); + } + } + retval = (Datum) 0; + fcinfo->isnull = true; + } + else if (fcinfo->isnull) + { retval = InputFunctionCall(&prodesc->result_in_func, NULL, prodesc->result_typioparam, -1); + } + else if (prodesc->fn_retistuple) + { + TupleDesc td; + HeapTuple tup; + Tcl_Obj *resultObj; + Tcl_Obj **resultObjv; + int resultObjc; + + /* + * Set up data about result type. XXX it's tempting to consider + * caching this in the prodesc, in the common case where the rowtype + * is determined by the function not the calling query. But we'd have + * to be able to deal with ADD/DROP/ALTER COLUMN events when the + * result type is a named composite type, so it's not exactly trivial. + * Maybe worth improving someday. + */ + if (get_call_result_type(fcinfo, NULL, &td) != TYPEFUNC_COMPOSITE) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("function returning record called in context " + "that cannot accept type record"))); + + Assert(!call_state->ret_tupdesc); + Assert(!call_state->attinmeta); + call_state->ret_tupdesc = td; + call_state->attinmeta = TupleDescGetAttInMetadata(td); + + /* Convert function result to tuple */ + resultObj = Tcl_GetObjResult(interp); + if (Tcl_ListObjGetElements(interp, resultObj, &resultObjc, &resultObjv) == TCL_ERROR) + throw_tcl_error(interp, prodesc->user_proname); + + tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc, + call_state); + retval = HeapTupleGetDatum(tup); + } else retval = InputFunctionCall(&prodesc->result_in_func, utf_u2e(Tcl_GetStringResult(interp)), @@ -833,7 +994,8 @@ pltcl_func_handler(PG_FUNCTION_ARGS, bool pltrusted) * pltcl_trigger_handler() - Handler for trigger calls **********************************************************************/ static HeapTuple -pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted) +pltcl_trigger_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state, + bool pltrusted) { pltcl_proc_desc *prodesc; Tcl_Interp *volatile interp; @@ -846,12 +1008,11 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted) Tcl_Obj *tcl_newtup; int tcl_rc; int i; - int *modattrs; - Datum *modvalues; - char *modnulls; - int ret_numvals; const char *result; - const char **ret_values; + int result_Objc; + Tcl_Obj **result_Objv; + + call_state->trigdata = trigdata; /* Connect to SPI manager */ if (SPI_connect() != SPI_OK_CONNECT) @@ -863,11 +1024,12 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted) false, /* not an event trigger */ pltrusted); - pltcl_current_prodesc = prodesc; + call_state->prodesc = prodesc; + prodesc->fn_refcount++; interp = prodesc->interp_desc->interp; - tupdesc = trigdata->tg_relation->rd_att; + tupdesc = RelationGetDescr(trigdata->tg_relation); /************************************************************ * Create the tcl command to call the internal @@ -1040,13 +1202,16 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted) throw_tcl_error(interp, prodesc->user_proname); /************************************************************ - * The return value from the procedure might be one of - * the magic strings OK or SKIP or a list from array get. - * We can check for OK or SKIP without worrying about encoding. + * Exit SPI environment. ************************************************************/ if (SPI_finish() != SPI_OK_FINISH) elog(ERROR, "SPI_finish() failed"); + /************************************************************ + * The return value from the procedure might be one of + * the magic strings OK or SKIP, or a list from array get. + * We can check for OK or SKIP without worrying about encoding. + ************************************************************/ result = Tcl_GetStringResult(interp); if (strcmp(result, "OK") == 0) @@ -1055,106 +1220,19 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted) return (HeapTuple) NULL; /************************************************************ - * Convert the result value from the Tcl interpreter - * and setup structures for SPI_modifytuple(); + * Otherwise, the return value should be a column name/value list + * specifying the modified tuple to return. ************************************************************/ - if (Tcl_SplitList(interp, result, - &ret_numvals, &ret_values) != TCL_OK) + if (Tcl_ListObjGetElements(interp, Tcl_GetObjResult(interp), + &result_Objc, &result_Objv) != TCL_OK) ereport(ERROR, (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), errmsg("could not split return value from trigger: %s", utf_u2e(Tcl_GetStringResult(interp))))); - /* Use a TRY to ensure ret_values will get freed */ - PG_TRY(); - { - if (ret_numvals % 2 != 0) - ereport(ERROR, - (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), - errmsg("trigger's return list must have even number of elements"))); - - modattrs = (int *) palloc(tupdesc->natts * sizeof(int)); - modvalues = (Datum *) palloc(tupdesc->natts * sizeof(Datum)); - for (i = 0; i < tupdesc->natts; i++) - { - modattrs[i] = i + 1; - modvalues[i] = (Datum) NULL; - } - - modnulls = palloc(tupdesc->natts); - memset(modnulls, 'n', tupdesc->natts); - - for (i = 0; i < ret_numvals; i += 2) - { - char *ret_name = utf_u2e(ret_values[i]); - char *ret_value = utf_u2e(ret_values[i + 1]); - int attnum; - Oid typinput; - Oid typioparam; - FmgrInfo finfo; - - /************************************************************ - * Ignore ".tupno" pseudo elements (see pltcl_set_tuple_values) - ************************************************************/ - if (strcmp(ret_name, ".tupno") == 0) - continue; - - /************************************************************ - * Get the attribute number - ************************************************************/ - attnum = SPI_fnumber(tupdesc, ret_name); - if (attnum == SPI_ERROR_NOATTRIBUTE) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_COLUMN), - errmsg("unrecognized attribute \"%s\"", - ret_name))); - if (attnum <= 0) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot set system attribute \"%s\"", - ret_name))); - - /************************************************************ - * Ignore dropped columns - ************************************************************/ - if (tupdesc->attrs[attnum - 1]->attisdropped) - continue; - - /************************************************************ - * Lookup the attribute type in the syscache - * for the input function - ************************************************************/ - getTypeInputInfo(tupdesc->attrs[attnum - 1]->atttypid, - &typinput, &typioparam); - fmgr_info(typinput, &finfo); - - /************************************************************ - * Set the attribute to NOT NULL and convert the contents - ************************************************************/ - modvalues[attnum - 1] = InputFunctionCall(&finfo, - ret_value, - typioparam, - tupdesc->attrs[attnum - 1]->atttypmod); - modnulls[attnum - 1] = ' '; - } - - rettup = SPI_modifytuple(trigdata->tg_relation, rettup, tupdesc->natts, - modattrs, modvalues, modnulls); - - pfree(modattrs); - pfree(modvalues); - pfree(modnulls); - - if (rettup == NULL) - elog(ERROR, "SPI_modifytuple() failed - RC = %d", SPI_result); - } - PG_CATCH(); - { - ckfree((char *) ret_values); - PG_RE_THROW(); - } - PG_END_TRY(); - ckfree((char *) ret_values); + /* Convert function result to tuple */ + rettup = pltcl_build_tuple_result(interp, result_Objv, result_Objc, + call_state); return rettup; } @@ -1163,7 +1241,8 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted) * pltcl_event_trigger_handler() - Handler for event trigger calls **********************************************************************/ static void -pltcl_event_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted) +pltcl_event_trigger_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state, + bool pltrusted) { pltcl_proc_desc *prodesc; Tcl_Interp *volatile interp; @@ -1179,7 +1258,8 @@ pltcl_event_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted) prodesc = compile_pltcl_function(fcinfo->flinfo->fn_oid, InvalidOid, true, pltrusted); - pltcl_current_prodesc = prodesc; + call_state->prodesc = prodesc; + prodesc->fn_refcount++; interp = prodesc->interp_desc->interp; @@ -1249,6 +1329,10 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, pltcl_proc_ptr *proc_ptr; bool found; pltcl_proc_desc *prodesc; + pltcl_proc_desc *old_prodesc; + volatile MemoryContext proc_cxt = NULL; + Tcl_DString proc_internal_def; + Tcl_DString proc_internal_body; /* We'll need the pg_proc tuple in any case... */ procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(fn_oid)); @@ -1256,7 +1340,10 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, elog(ERROR, "cache lookup failed for function %u", fn_oid); procStruct = (Form_pg_proc) GETSTRUCT(procTup); - /* Try to find function in pltcl_proc_htab */ + /* + * Look up function in pltcl_proc_htab; if it's not there, create an entry + * and set the entry's proc_ptr to NULL. + */ proc_key.proc_id = fn_oid; proc_key.is_trigger = OidIsValid(tgreloid); proc_key.user_id = pltrusted ? GetUserId() : InvalidOid; @@ -1274,18 +1361,13 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, * This is needed because CREATE OR REPLACE FUNCTION can modify the * function's pg_proc entry without changing its OID. ************************************************************/ - if (prodesc != NULL) + if (prodesc != NULL && + prodesc->fn_xmin == HeapTupleHeaderGetRawXmin(procTup->t_data) && + ItemPointerEquals(&prodesc->fn_tid, &procTup->t_self)) { - bool uptodate; - - uptodate = (prodesc->fn_xmin == HeapTupleHeaderGetRawXmin(procTup->t_data) && - ItemPointerEquals(&prodesc->fn_tid, &procTup->t_self)); - - if (!uptodate) - { - proc_ptr->proc_ptr = NULL; - prodesc = NULL; - } + /* It's still up-to-date, so we can use it */ + ReleaseSysCache(procTup); + return prodesc; } /************************************************************ @@ -1296,14 +1378,14 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, * * Then we load the procedure into the Tcl interpreter. ************************************************************/ - if (prodesc == NULL) + Tcl_DStringInit(&proc_internal_def); + Tcl_DStringInit(&proc_internal_body); + PG_TRY(); { bool is_trigger = OidIsValid(tgreloid); char internal_proname[128]; HeapTuple typeTup; Form_pg_type typeStruct; - Tcl_DString proc_internal_def; - Tcl_DString proc_internal_body; char proc_internal_args[33 * FUNC_MAX_ARGS]; Datum prosrcdatum; bool isnull; @@ -1312,39 +1394,47 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, Tcl_Interp *interp; int i; int tcl_rc; + MemoryContext oldcontext; /************************************************************ * Build our internal proc name from the function's Oid. Append * "_trigger" when appropriate to ensure the normal and trigger * cases are kept separate. Note name must be all-ASCII. ************************************************************/ - if (!is_trigger && !is_event_trigger) - snprintf(internal_proname, sizeof(internal_proname), - "__PLTcl_proc_%u", fn_oid); - else if (is_event_trigger) + if (is_event_trigger) snprintf(internal_proname, sizeof(internal_proname), "__PLTcl_proc_%u_evttrigger", fn_oid); else if (is_trigger) snprintf(internal_proname, sizeof(internal_proname), "__PLTcl_proc_%u_trigger", fn_oid); + else + snprintf(internal_proname, sizeof(internal_proname), + "__PLTcl_proc_%u", fn_oid); /************************************************************ - * Allocate a new procedure description block + * Allocate a context that will hold all PG data for the procedure. + * We use the internal proc name as the context name. ************************************************************/ - prodesc = (pltcl_proc_desc *) malloc(sizeof(pltcl_proc_desc)); - if (prodesc == NULL) - ereport(ERROR, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); - MemSet(prodesc, 0, sizeof(pltcl_proc_desc)); - prodesc->user_proname = strdup(NameStr(procStruct->proname)); - prodesc->internal_proname = strdup(internal_proname); - if (prodesc->user_proname == NULL || prodesc->internal_proname == NULL) - ereport(ERROR, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); + proc_cxt = AllocSetContextCreate(TopMemoryContext, + internal_proname, + ALLOCSET_SMALL_SIZES); + + /************************************************************ + * Allocate and fill a new procedure description block. + * struct prodesc and subsidiary data must all live in proc_cxt. + ************************************************************/ + oldcontext = MemoryContextSwitchTo(proc_cxt); + prodesc = (pltcl_proc_desc *) palloc0(sizeof(pltcl_proc_desc)); + prodesc->user_proname = pstrdup(NameStr(procStruct->proname)); + prodesc->internal_proname = pstrdup(internal_proname); + prodesc->fn_cxt = proc_cxt; + prodesc->fn_refcount = 0; prodesc->fn_xmin = HeapTupleHeaderGetRawXmin(procTup->t_data); prodesc->fn_tid = procTup->t_self; + prodesc->nargs = procStruct->pronargs; + prodesc->arg_out_func = (FmgrInfo *) palloc0(prodesc->nargs * sizeof(FmgrInfo)); + prodesc->arg_is_rowtype = (bool *) palloc0(prodesc->nargs * sizeof(bool)); + MemoryContextSwitchTo(oldcontext); /* Remember if function is STABLE/IMMUTABLE */ prodesc->fn_readonly = @@ -1368,91 +1458,62 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, SearchSysCache1(TYPEOID, ObjectIdGetDatum(procStruct->prorettype)); if (!HeapTupleIsValid(typeTup)) - { - free(prodesc->user_proname); - free(prodesc->internal_proname); - free(prodesc); elog(ERROR, "cache lookup failed for type %u", procStruct->prorettype); - } typeStruct = (Form_pg_type) GETSTRUCT(typeTup); - /* Disallow pseudotype result, except VOID */ + /* Disallow pseudotype result, except VOID and RECORD */ if (typeStruct->typtype == TYPTYPE_PSEUDO) { - if (procStruct->prorettype == VOIDOID) + if (procStruct->prorettype == VOIDOID || + procStruct->prorettype == RECORDOID) /* okay */ ; else if (procStruct->prorettype == TRIGGEROID || procStruct->prorettype == EVTTRIGGEROID) - { - free(prodesc->user_proname); - free(prodesc->internal_proname); - free(prodesc); ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("trigger functions can only be called as triggers"))); - } else - { - free(prodesc->user_proname); - free(prodesc->internal_proname); - free(prodesc); ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("PL/Tcl functions cannot return type %s", format_type_be(procStruct->prorettype)))); - } - } - - if (typeStruct->typtype == TYPTYPE_COMPOSITE) - { - free(prodesc->user_proname); - free(prodesc->internal_proname); - free(prodesc); - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("PL/Tcl functions cannot return composite types"))); } - perm_fmgr_info(typeStruct->typinput, &(prodesc->result_in_func)); + fmgr_info_cxt(typeStruct->typinput, + &(prodesc->result_in_func), + proc_cxt); prodesc->result_typioparam = getTypeIOParam(typeTup); + prodesc->fn_retisset = procStruct->proretset; + prodesc->fn_retistuple = (procStruct->prorettype == RECORDOID || + typeStruct->typtype == TYPTYPE_COMPOSITE); + ReleaseSysCache(typeTup); } /************************************************************ * Get the required information for output conversion - * of all procedure arguments + * of all procedure arguments, and set up argument naming info. ************************************************************/ if (!is_trigger && !is_event_trigger) { - prodesc->nargs = procStruct->pronargs; proc_internal_args[0] = '\0'; for (i = 0; i < prodesc->nargs; i++) { typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(procStruct->proargtypes.values[i])); if (!HeapTupleIsValid(typeTup)) - { - free(prodesc->user_proname); - free(prodesc->internal_proname); - free(prodesc); elog(ERROR, "cache lookup failed for type %u", procStruct->proargtypes.values[i]); - } typeStruct = (Form_pg_type) GETSTRUCT(typeTup); /* Disallow pseudotype argument */ if (typeStruct->typtype == TYPTYPE_PSEUDO) - { - free(prodesc->user_proname); - free(prodesc->internal_proname); - free(prodesc); ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("PL/Tcl functions cannot accept type %s", format_type_be(procStruct->proargtypes.values[i])))); - } if (typeStruct->typtype == TYPTYPE_COMPOSITE) { @@ -1462,8 +1523,9 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, else { prodesc->arg_is_rowtype[i] = false; - perm_fmgr_info(typeStruct->typoutput, - &(prodesc->arg_out_func[i])); + fmgr_info_cxt(typeStruct->typoutput, + &(prodesc->arg_out_func[i]), + proc_cxt); snprintf(buf, sizeof(buf), "%d", i + 1); } @@ -1490,12 +1552,10 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, * Create the tcl command to define the internal * procedure * - * leave this code as DString - it's a text processing function - * that only gets invoked when the tcl function is invoked - * for the first time + * Leave this code as DString - performance is not critical here, + * and we don't want to duplicate the knowledge of the Tcl quoting + * rules that's embedded in Tcl_DStringAppendElement. ************************************************************/ - Tcl_DStringInit(&proc_internal_def); - Tcl_DStringInit(&proc_internal_body); Tcl_DStringAppendElement(&proc_internal_def, "proc"); Tcl_DStringAppendElement(&proc_internal_def, internal_proname); Tcl_DStringAppendElement(&proc_internal_def, proc_internal_args); @@ -1514,7 +1574,6 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, "array set NEW $__PLTcl_Tup_NEW\n", -1); Tcl_DStringAppend(&proc_internal_body, "array set OLD $__PLTcl_Tup_OLD\n", -1); - Tcl_DStringAppend(&proc_internal_body, "set i 0\n" "set v 0\n" @@ -1556,7 +1615,6 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, pfree(proc_source); Tcl_DStringAppendElement(&proc_internal_def, Tcl_DStringValue(&proc_internal_body)); - Tcl_DStringFree(&proc_internal_body); /************************************************************ * Create the procedure in the interpreter @@ -1565,28 +1623,52 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, Tcl_DStringValue(&proc_internal_def), Tcl_DStringLength(&proc_internal_def), TCL_EVAL_GLOBAL); - Tcl_DStringFree(&proc_internal_def); if (tcl_rc != TCL_OK) - { - free(prodesc->user_proname); - free(prodesc->internal_proname); - free(prodesc); ereport(ERROR, (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), errmsg("could not create internal procedure \"%s\": %s", internal_proname, utf_u2e(Tcl_GetStringResult(interp))))); - } + } + PG_CATCH(); + { + /* + * If we failed anywhere above, clean up whatever got allocated. It + * should all be in the proc_cxt, except for the DStrings. + */ + if (proc_cxt) + MemoryContextDelete(proc_cxt); + Tcl_DStringFree(&proc_internal_def); + Tcl_DStringFree(&proc_internal_body); + PG_RE_THROW(); + } + PG_END_TRY(); - /************************************************************ - * Add the proc description block to the hashtable. Note we do not - * attempt to free any previously existing prodesc block. This is - * annoying, but necessary since there could be active calls using - * the old prodesc. - ************************************************************/ - proc_ptr->proc_ptr = prodesc; + /* + * Install the new proc description block in the hashtable, incrementing + * its refcount (the hashtable link counts as a reference). Then, if + * there was a previous definition of the function, decrement that one's + * refcount, and delete it if no longer referenced. The order of + * operations here is important: if something goes wrong during the + * MemoryContextDelete, leaking some memory for the old definition is OK, + * but we don't want to corrupt the live hashtable entry. (Likewise, + * freeing the DStrings is pretty low priority if that happens.) + */ + old_prodesc = proc_ptr->proc_ptr; + + proc_ptr->proc_ptr = prodesc; + prodesc->fn_refcount++; + + if (old_prodesc != NULL) + { + Assert(old_prodesc->fn_refcount > 0); + if (--old_prodesc->fn_refcount == 0) + MemoryContextDelete(old_prodesc->fn_cxt); } + Tcl_DStringFree(&proc_internal_def); + Tcl_DStringFree(&proc_internal_body); + ReleaseSysCache(procTup); return prodesc; @@ -1905,7 +1987,7 @@ pltcl_argisnull(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { int argno; - FunctionCallInfo fcinfo = pltcl_current_fcinfo; + FunctionCallInfo fcinfo = pltcl_current_call_state->fcinfo; /************************************************************ * Check call syntax @@ -1958,7 +2040,7 @@ static int pltcl_returnnull(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { - FunctionCallInfo fcinfo = pltcl_current_fcinfo; + FunctionCallInfo fcinfo = pltcl_current_call_state->fcinfo; /************************************************************ * Check call syntax @@ -1989,6 +2071,108 @@ pltcl_returnnull(ClientData cdata, Tcl_Interp *interp, } +/********************************************************************** + * pltcl_returnnext() - Add a row to the result tuplestore in a SRF. + **********************************************************************/ +static int +pltcl_returnnext(ClientData cdata, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + pltcl_call_state *call_state = pltcl_current_call_state; + FunctionCallInfo fcinfo = call_state->fcinfo; + pltcl_proc_desc *prodesc = call_state->prodesc; + MemoryContext oldcontext = CurrentMemoryContext; + ResourceOwner oldowner = CurrentResourceOwner; + volatile int result = TCL_OK; + + /* + * Check that we're called as a set-returning function + */ + if (fcinfo == NULL) + { + Tcl_SetObjResult(interp, + Tcl_NewStringObj("return_next cannot be used in triggers", -1)); + return TCL_ERROR; + } + + if (!prodesc->fn_retisset) + { + Tcl_SetObjResult(interp, + Tcl_NewStringObj("return_next cannot be used in non-set-returning functions", -1)); + return TCL_ERROR; + } + + /* + * Check call syntax + */ + if (objc != 2) + { + Tcl_WrongNumArgs(interp, 1, objv, "result"); + return TCL_ERROR; + } + + /* + * The rest might throw elog(ERROR), so must run in a subtransaction. + * + * A small advantage of using a subtransaction is that it provides a + * short-lived memory context for free, so we needn't worry about leaking + * memory here. To use that context, call BeginInternalSubTransaction + * directly instead of going through pltcl_subtrans_begin. + */ + BeginInternalSubTransaction(NULL); + PG_TRY(); + { + /* Set up tuple store if first output row */ + if (call_state->tuple_store == NULL) + pltcl_init_tuple_store(call_state); + + if (prodesc->fn_retistuple) + { + Tcl_Obj **rowObjv; + int rowObjc; + + /* result should be a list, so break it down */ + if (Tcl_ListObjGetElements(interp, objv[1], &rowObjc, &rowObjv) == TCL_ERROR) + result = TCL_ERROR; + else + { + HeapTuple tuple; + + tuple = pltcl_build_tuple_result(interp, rowObjv, rowObjc, + call_state); + tuplestore_puttuple(call_state->tuple_store, tuple); + } + } + else + { + Datum retval; + bool isNull = false; + + /* for paranoia's sake, check that tupdesc has exactly one column */ + if (call_state->ret_tupdesc->natts != 1) + elog(ERROR, "wrong result type supplied in return_next"); + + retval = InputFunctionCall(&prodesc->result_in_func, + utf_u2e((char *) Tcl_GetString(objv[1])), + prodesc->result_typioparam, + -1); + tuplestore_putvalues(call_state->tuple_store, call_state->ret_tupdesc, + &retval, &isNull); + } + + pltcl_subtrans_commit(oldcontext, oldowner); + } + PG_CATCH(); + { + pltcl_subtrans_abort(interp, oldcontext, oldowner); + return TCL_ERROR; + } + PG_END_TRY(); + + return result; +} + + /*---------- * Support for running SPI operations inside subtransactions * @@ -2029,12 +2213,6 @@ pltcl_subtrans_commit(MemoryContext oldcontext, ResourceOwner oldowner) ReleaseCurrentSubTransaction(); MemoryContextSwitchTo(oldcontext); CurrentResourceOwner = oldowner; - - /* - * AtEOSubXact_SPI() should not have popped any SPI context, but just in - * case it did, make sure we remain connected. - */ - SPI_restore_connection(); } static void @@ -2053,13 +2231,6 @@ pltcl_subtrans_abort(Tcl_Interp *interp, MemoryContextSwitchTo(oldcontext); CurrentResourceOwner = oldowner; - /* - * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will - * have left us in a disconnected state. We need this hack to return to - * connected state. - */ - SPI_restore_connection(); - /* Pass the error data to Tcl */ pltcl_construct_errorCode(interp, edata); UTF_BEGIN; @@ -2110,7 +2281,7 @@ pltcl_SPI_execute(ClientData cdata, Tcl_Interp *interp, i = 1; while (i < objc) { - if (Tcl_GetIndexFromObj(interp, objv[i], options, "option", + if (Tcl_GetIndexFromObj(NULL, objv[i], options, NULL, TCL_EXACT, &optIndex) != TCL_OK) break; @@ -2155,7 +2326,7 @@ pltcl_SPI_execute(ClientData cdata, Tcl_Interp *interp, { UTF_BEGIN; spi_rc = SPI_execute(UTF_U2E(Tcl_GetString(objv[query_idx])), - pltcl_current_prodesc->fn_readonly, count); + pltcl_current_call_state->prodesc->fn_readonly, count); UTF_END; my_rc = pltcl_process_SPI_result(interp, @@ -2331,9 +2502,7 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp, ************************************************************/ plan_cxt = AllocSetContextCreate(TopMemoryContext, "PL/TCL spi_prepare query", - ALLOCSET_SMALL_MINSIZE, - ALLOCSET_SMALL_INITSIZE, - ALLOCSET_SMALL_MAXSIZE); + ALLOCSET_SMALL_SIZES); MemoryContextSwitchTo(plan_cxt); qdesc = (pltcl_query_desc *) palloc0(sizeof(pltcl_query_desc)); snprintf(qdesc->qname, sizeof(qdesc->qname), "%p", qdesc); @@ -2407,7 +2576,7 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp, * Insert a hashtable entry for the plan and return * the key to the caller ************************************************************/ - query_hash = &pltcl_current_prodesc->interp_desc->query_hash; + query_hash = &pltcl_current_call_state->prodesc->interp_desc->query_hash; hashent = Tcl_CreateHashEntry(query_hash, qdesc->qname, &hashnew); Tcl_SetHashValue(hashent, (ClientData) qdesc); @@ -2458,7 +2627,7 @@ pltcl_SPI_execute_plan(ClientData cdata, Tcl_Interp *interp, i = 1; while (i < objc) { - if (Tcl_GetIndexFromObj(interp, objv[i], options, "option", + if (Tcl_GetIndexFromObj(NULL, objv[i], options, NULL, TCL_EXACT, &optIndex) != TCL_OK) break; @@ -2496,7 +2665,7 @@ pltcl_SPI_execute_plan(ClientData cdata, Tcl_Interp *interp, return TCL_ERROR; } - query_hash = &pltcl_current_prodesc->interp_desc->query_hash; + query_hash = &pltcl_current_call_state->prodesc->interp_desc->query_hash; hashent = Tcl_FindHashEntry(query_hash, Tcl_GetString(objv[i])); if (hashent == NULL) @@ -2611,7 +2780,8 @@ pltcl_SPI_execute_plan(ClientData cdata, Tcl_Interp *interp, * Execute the plan ************************************************************/ spi_rc = SPI_execute_plan(qdesc->plan, argvalues, nulls, - pltcl_current_prodesc->fn_readonly, count); + pltcl_current_call_state->prodesc->fn_readonly, + count); my_rc = pltcl_process_SPI_result(interp, arrayname, @@ -2641,6 +2811,15 @@ static int pltcl_SPI_lastoid(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { + /* + * Check call syntax + */ + if (objc != 1) + { + Tcl_WrongNumArgs(interp, 1, objv, ""); + return TCL_ERROR; + } + Tcl_SetObjResult(interp, Tcl_NewWideIntObj(SPI_lastoid)); return TCL_OK; } @@ -2668,8 +2847,7 @@ pltcl_set_tuple_values(Tcl_Interp *interp, const char *arrayname, const char *nullname = NULL; /************************************************************ - * Prepare pointers for Tcl_SetVar2() below and in array - * mode set the .tupno element + * Prepare pointers for Tcl_SetVar2() below ************************************************************/ if (arrayname == NULL) { @@ -2680,6 +2858,12 @@ pltcl_set_tuple_values(Tcl_Interp *interp, const char *arrayname, { arrptr = &arrayname; nameptr = &attname; + + /* + * When outputting to an array, fill the ".tupno" element with the + * current tuple number. This will be overridden below if ".tupno" is + * in use as an actual field name in the rowtype. + */ Tcl_SetVar2Ex(interp, arrayname, ".tupno", Tcl_NewWideIntObj(tupno), 0); } @@ -2787,3 +2971,121 @@ pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc) return retobj; } + +/********************************************************************** + * pltcl_build_tuple_result() - Build a tuple of function's result rowtype + * from a Tcl list of column names and values + * + * In a trigger function, we build a tuple of the trigger table's rowtype. + * + * Note: this function leaks memory. Even if we made it clean up its own + * mess, there's no way to prevent the datatype input functions it calls + * from leaking. Run it in a short-lived context, unless we're about to + * exit the procedure anyway. + **********************************************************************/ +static HeapTuple +pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc, + pltcl_call_state *call_state) +{ + TupleDesc tupdesc; + AttInMetadata *attinmeta; + char **values; + int i; + + if (call_state->ret_tupdesc) + { + tupdesc = call_state->ret_tupdesc; + attinmeta = call_state->attinmeta; + } + else if (call_state->trigdata) + { + tupdesc = RelationGetDescr(call_state->trigdata->tg_relation); + attinmeta = TupleDescGetAttInMetadata(tupdesc); + } + else + { + elog(ERROR, "PL/Tcl function does not return a tuple"); + tupdesc = NULL; /* keep compiler quiet */ + attinmeta = NULL; + } + + values = (char **) palloc0(tupdesc->natts * sizeof(char *)); + + if (kvObjc % 2 != 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("column name/value list must have even number of elements"))); + + for (i = 0; i < kvObjc; i += 2) + { + char *fieldName = utf_u2e(Tcl_GetString(kvObjv[i])); + int attn = SPI_fnumber(tupdesc, fieldName); + + /* + * We silently ignore ".tupno", if it's present but doesn't match any + * actual output column. This allows direct use of a row returned by + * pltcl_set_tuple_values(). + */ + if (attn == SPI_ERROR_NOATTRIBUTE) + { + if (strcmp(fieldName, ".tupno") == 0) + continue; + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column name/value list contains nonexistent column name \"%s\"", + fieldName))); + } + + if (attn <= 0) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot set system attribute \"%s\"", + fieldName))); + + values[attn - 1] = utf_u2e(Tcl_GetString(kvObjv[i + 1])); + } + + return BuildTupleFromCStrings(attinmeta, values); +} + +/********************************************************************** + * pltcl_init_tuple_store() - Initialize the result tuplestore for a SRF + **********************************************************************/ +static void +pltcl_init_tuple_store(pltcl_call_state *call_state) +{ + ReturnSetInfo *rsi = call_state->rsi; + MemoryContext oldcxt; + ResourceOwner oldowner; + + /* Should be in a SRF */ + Assert(rsi); + /* Should be first time through */ + Assert(!call_state->tuple_store); + Assert(!call_state->attinmeta); + + /* We expect caller to provide an appropriate result tupdesc */ + Assert(rsi->expectedDesc); + call_state->ret_tupdesc = rsi->expectedDesc; + + /* + * Switch to the right memory context and resource owner for storing the + * tuplestore. If we're within a subtransaction opened for an exception + * block, for example, we must still create the tuplestore in the resource + * owner that was active when this function was entered, and not in the + * subtransaction's resource owner. + */ + oldcxt = MemoryContextSwitchTo(call_state->tuple_store_cxt); + oldowner = CurrentResourceOwner; + CurrentResourceOwner = call_state->tuple_store_owner; + + call_state->tuple_store = + tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random, + false, work_mem); + + /* Build attinmeta in this context, too */ + call_state->attinmeta = TupleDescGetAttInMetadata(call_state->ret_tupdesc); + + CurrentResourceOwner = oldowner; + MemoryContextSwitchTo(oldcxt); +} diff --git a/src/pl/tcl/sql/pltcl_queries.sql b/src/pl/tcl/sql/pltcl_queries.sql index a0a9619a9b..29ed616cd0 100644 --- a/src/pl/tcl/sql/pltcl_queries.sql +++ b/src/pl/tcl/sql/pltcl_queries.sql @@ -80,8 +80,10 @@ insert into trigger_test_view values(2,'insert'); update trigger_test_view set v = 'update' where i=1; delete from trigger_test_view; +update trigger_test set v = 'update', test_skip=true where i = 1; update trigger_test set v = 'update' where i = 1; delete from trigger_test; +truncate trigger_test; -- Test composite-type arguments select tcl_composite_arg_ref1(row('tkey', 42, 'ref2')); @@ -91,9 +93,126 @@ select tcl_composite_arg_ref2(row('tkey', 42, 'ref2')); select tcl_argisnull('foo'); select tcl_argisnull(''); select tcl_argisnull(null); +-- should error +insert into trigger_test(test_argisnull) values(true); +select trigger_data(); -- Test spi_lastoid primitive create temp table t1 (f1 int); select tcl_lastoid('t1'); create temp table t2 (f1 int) with oids; select tcl_lastoid('t2') > 0; + +-- test some error cases +create function tcl_error(out a int, out b int) as $$return {$$ language pltcl; +select tcl_error(); + +create function bad_record(out a text, out b text) as $$return [list a]$$ language pltcl; +select bad_record(); + +create function bad_field(out a text, out b text) as $$return [list a 1 b 2 cow 3]$$ language pltcl; +select bad_field(); + +-- test compound return +select * from tcl_test_cube_squared(5); + +-- test SRF +select * from tcl_test_squared_rows(0,5); + +select * from tcl_test_sequence(0,5) as a; + +select 1, tcl_test_sequence(0,5); + +create function non_srf() returns int as $$return_next 1$$ language pltcl; +select non_srf(); + +create function bad_record_srf(out a text, out b text) returns setof record as $$ +return_next [list a] +$$ language pltcl; +select bad_record_srf(); + +create function bad_field_srf(out a text, out b text) returns setof record as $$ +return_next [list a 1 b 2 cow 3] +$$ language pltcl; +select bad_field_srf(); + +-- test quote +select tcl_eval('quote foo bar'); +select tcl_eval('quote [format %c 39]'); +select tcl_eval('quote [format %c 92]'); + +-- Test argisnull +select tcl_eval('argisnull'); +select tcl_eval('argisnull 14'); +select tcl_eval('argisnull abc'); + +-- Test return_null +select tcl_eval('return_null 14'); +-- should error +insert into trigger_test(test_return_null) values(true); + +-- Test spi_exec +select tcl_eval('spi_exec'); +select tcl_eval('spi_exec -count'); +select tcl_eval('spi_exec -array'); +select tcl_eval('spi_exec -count abc'); +select tcl_eval('spi_exec query loop body toomuch'); +select tcl_eval('spi_exec "begin; rollback;"'); + +-- Test spi_execp +select tcl_eval('spi_execp'); +select tcl_eval('spi_execp -count'); +select tcl_eval('spi_execp -array'); +select tcl_eval('spi_execp -count abc'); +select tcl_eval('spi_execp -nulls'); +select tcl_eval('spi_execp ""'); + +-- test spi_prepare +select tcl_eval('spi_prepare'); +select tcl_eval('spi_prepare a b'); +select tcl_eval('spi_prepare a "b {"'); +select tcl_error_handling_test($tcl$spi_prepare "select moo" []$tcl$); + +-- test full error text +select tcl_error_handling_test($tcl$ +spi_exec "DO $$ +BEGIN +RAISE 'my message' + USING HINT = 'my hint' + , DETAIL = 'my detail' + , SCHEMA = 'my schema' + , TABLE = 'my table' + , COLUMN = 'my column' + , CONSTRAINT = 'my constraint' + , DATATYPE = 'my datatype' +; +END$$;" +$tcl$); + +-- verify tcl_error_handling_test() properly reports non-postgres errors +select tcl_error_handling_test('moo'); + +-- test elog +select tcl_eval('elog'); +select tcl_eval('elog foo bar'); + +-- test forced error +select tcl_eval('error "forced error"'); + +-- test loop control in spi_exec[p] +select tcl_spi_exec(true, 'break'); +select tcl_spi_exec(true, 'continue'); +select tcl_spi_exec(true, 'error'); +select tcl_spi_exec(true, 'return'); +select tcl_spi_exec(false, 'break'); +select tcl_spi_exec(false, 'continue'); +select tcl_spi_exec(false, 'error'); +select tcl_spi_exec(false, 'return'); + +-- forcibly run the Tcl event loop for awhile, to check that we have not +-- messed things up too badly by disabling the Tcl notifier subsystem +select tcl_eval($$ + unset -nocomplain ::tcl_vwait + after 100 {set ::tcl_vwait 1} + vwait ::tcl_vwait + unset -nocomplain ::tcl_vwait$$); diff --git a/src/pl/tcl/sql/pltcl_setup.sql b/src/pl/tcl/sql/pltcl_setup.sql index 8df65a5816..a8eaba6243 100644 --- a/src/pl/tcl/sql/pltcl_setup.sql +++ b/src/pl/tcl/sql/pltcl_setup.sql @@ -57,12 +57,33 @@ create function check_pkey1_exists(int4, bpchar) returns bool as E' -- dump trigger data -CREATE TABLE trigger_test - (i int, v text ); +CREATE TABLE trigger_test ( + i int, + v text, + dropme text, + test_skip boolean DEFAULT false, + test_return_null boolean DEFAULT false, + test_argisnull boolean DEFAULT false +); +-- Make certain dropped attributes are handled correctly +ALTER TABLE trigger_test DROP dropme; -CREATE VIEW trigger_test_view AS SELECT * FROM trigger_test; +CREATE VIEW trigger_test_view AS SELECT i, v FROM trigger_test; CREATE FUNCTION trigger_data() returns trigger language pltcl as $_$ + if {$TG_table_name eq "trigger_test" && $TG_level eq "ROW" && $TG_op ne "DELETE"} { + # Special case tests + if {$NEW(test_return_null) eq "t" } { + return_null + } + if {$NEW(test_argisnull) eq "t" } { + set should_error [argisnull 1] + } + if {$NEW(test_skip) eq "t" } { + elog NOTICE "SKIPPING OPERATION $TG_op" + return SKIP + } + } if { [info exists TG_relid] } { set TG_relid "bogus:12345" @@ -97,6 +118,9 @@ $_$; CREATE TRIGGER show_trigger_data_trig BEFORE INSERT OR UPDATE OR DELETE ON trigger_test FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo'); +CREATE TRIGGER statement_trigger +BEFORE INSERT OR UPDATE OR DELETE OR TRUNCATE ON trigger_test +FOR EACH STATEMENT EXECUTE PROCEDURE trigger_data(42,'statement trigger'); CREATE TRIGGER show_trigger_data_view_trig INSTEAD OF INSERT OR UPDATE OR DELETE ON trigger_test_view @@ -579,14 +603,14 @@ select tcl_date_week(2010,1,24); select tcl_date_week(2001,10,24); -- test pltcl event triggers -create or replace function tclsnitch() returns event_trigger language pltcl as $$ +create function tclsnitch() returns event_trigger language pltcl as $$ elog NOTICE "tclsnitch: $TG_event $TG_tag" $$; create event trigger tcl_a_snitch on ddl_command_start execute procedure tclsnitch(); create event trigger tcl_b_snitch on ddl_command_end execute procedure tclsnitch(); -create or replace function foobar() returns int language sql as $$select 1;$$; +create function foobar() returns int language sql as $$select 1;$$; alter function foobar() cost 77; drop function foobar(); @@ -596,26 +620,113 @@ drop table foo; drop event trigger tcl_a_snitch; drop event trigger tcl_b_snitch; --- test use of errorCode in error handling +create function tcl_test_cube_squared(in int, out squared int, out cubed int) as $$ + return [list squared [expr {$1 * $1}] cubed [expr {$1 * $1 * $1}]] +$$ language pltcl; -create function tcl_error_handling_test() returns text as $$ - global errorCode - if {[catch { spi_exec "select no_such_column from foo;" }]} { - array set errArray $errorCode - if {$errArray(condition) == "undefined_table"} { - return "expected error: $errArray(message)" - } else { - return "unexpected error: $errArray(condition) $errArray(message)" - } - } else { - return "no error" +create function tcl_test_squared_rows(int,int) returns table (x int, y int) as $$ + for {set i $1} {$i < $2} {incr i} { + return_next [list y [expr {$i * $i}] x $i] } $$ language pltcl; -select tcl_error_handling_test(); +create function tcl_test_sequence(int,int) returns setof int as $$ + for {set i $1} {$i < $2} {incr i} { + return_next $i + } +$$ language pltcl; -create temp table foo(f1 int); +create function tcl_eval(string text) returns text as $$ + eval $1 +$$ language pltcl; -select tcl_error_handling_test(); +-- test use of errorCode in error handling +create function tcl_error_handling_test(text) returns text +language pltcl +as $function$ + if {[catch $1 err]} { + # If not a Postgres error, just return the basic error message + if {[lindex $::errorCode 0] != "POSTGRES"} { + return $err + } -drop table foo; + # Get rid of keys that can't be expected to remain constant + array set myArray $::errorCode + unset myArray(POSTGRES) + unset -nocomplain myArray(funcname) + unset -nocomplain myArray(filename) + unset -nocomplain myArray(lineno) + + # Format into something nicer + set vals [] + foreach {key} [lsort [array names myArray]] { + set value [string map {"\n" "\n\t"} $myArray($key)] + lappend vals "$key: $value" + } + return [join $vals "\n"] + } else { + return "no error" + } +$function$; + +-- test spi_exec and spi_execp with -array +create function tcl_spi_exec( + prepare boolean, + action text +) +returns void language pltcl AS $function$ +set query "select * from (values (1,'foo'),(2,'bar'),(3,'baz')) v(col1,col2)" +if {$1 == "t"} { + set prep [spi_prepare $query {}] + spi_execp -array A $prep { + elog NOTICE "col1 $A(col1), col2 $A(col2)" + + switch $A(col1) { + 2 { + elog NOTICE "action: $2" + switch $2 { + break { + break + } + continue { + continue + } + return { + return + } + error { + error "error message" + } + } + error "should not get here" + } + } + } +} else { + spi_exec -array A $query { + elog NOTICE "col1 $A(col1), col2 $A(col2)" + + switch $A(col1) { + 2 { + elog NOTICE "action: $2" + switch $2 { + break { + break + } + continue { + continue + } + return { + return + } + error { + error "error message" + } + } + error "should not get here" + } + } + } +} +elog NOTICE "end of function" +$function$; diff --git a/src/port/Makefile b/src/port/Makefile index bc9b63add0..81f01b25bb 100644 --- a/src/port/Makefile +++ b/src/port/Makefile @@ -35,6 +35,10 @@ OBJS = $(LIBOBJS) $(PG_CRC32C_OBJS) chklocale.o erand48.o inet_net_ntop.o \ pgstrcasecmp.o pqsignal.o \ qsort.o qsort_arg.o quotes.o sprompt.o tar.o thread.o +ifeq ($(enable_strong_random), yes) +OBJS += pg_strong_random.o +endif + # foo_srv.o and foo.o are both built from foo.c, but only foo.o has -DFRONTEND OBJS_SRV = $(OBJS:%.o=%_srv.o) diff --git a/src/port/README b/src/port/README index 58fb32d9f9..4ae96da015 100644 --- a/src/port/README +++ b/src/port/README @@ -28,5 +28,5 @@ applications. 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. Win32, Linux, and Darwin use an export list to +dependency is a problem. Windows, Linux, and macOS use an export list to control the symbols exported by libpq. diff --git a/src/port/chklocale.c b/src/port/chklocale.c index 3c0ef6a253..54ce9410f0 100644 --- a/src/port/chklocale.c +++ b/src/port/chklocale.c @@ -4,7 +4,7 @@ * Functions for handling locale-related info * * - * Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION @@ -290,8 +290,7 @@ pg_codepage_to_encoding(UINT cp) return encoding_match_list[i].pg_enc_code; ereport(WARNING, - (errmsg("could not determine encoding for codeset \"%s\"", sys), - errdetail("Please report this to ."))); + (errmsg("could not determine encoding for codeset \"%s\"", sys))); return -1; } @@ -395,7 +394,7 @@ pg_get_encoding_from_locale(const char *ctype, bool write_message) #ifdef __darwin__ /* - * Current OS X has many locales that report an empty string for CODESET, + * 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) @@ -419,8 +418,7 @@ pg_get_encoding_from_locale(const char *ctype, bool write_message) #else ereport(WARNING, (errmsg("could not determine encoding for locale \"%s\": codeset is \"%s\"", - ctype, sys), - errdetail("Please report this to ."))); + ctype, sys))); #endif } diff --git a/src/port/dirent.c b/src/port/dirent.c index f97227ef1f..269f7429f8 100644 --- a/src/port/dirent.c +++ b/src/port/dirent.c @@ -3,7 +3,7 @@ * dirent.c * opendir/readdir/closedir for win32/msvc * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/dirmod.c b/src/port/dirmod.c index fe2b815ff6..08835962be 100644 --- a/src/port/dirmod.c +++ b/src/port/dirmod.c @@ -3,7 +3,7 @@ * dirmod.c * directory handling functions * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * This includes replacement versions of functions that work on @@ -338,10 +338,10 @@ pgreadlink(const char *path, char *buf, size_t size) /* * Assumes the file exists, so will return false if it doesn't - * (since a nonexistant file is not a junction) + * (since a nonexistent file is not a junction) */ bool -pgwin32_is_junction(char *path) +pgwin32_is_junction(const char *path) { DWORD attr = GetFileAttributes(path); @@ -372,7 +372,22 @@ pgwin32_safestat(const char *path, struct stat * buf) r = stat(path, buf); if (r < 0) + { + if (GetLastError() == ERROR_DELETE_PENDING) + { + /* + * File has been deleted, but is not gone from the filesystem + * yet. This can happen when some process with FILE_SHARE_DELETE + * has it open and it will be fully removed once that handle + * is closed. Meanwhile, we can't open it, so indicate that + * the file just doesn't exist. + */ + errno = ENOENT; + return -1; + } + return r; + } if (!GetFileAttributesEx(path, GetFileExInfoStandard, &attr)) { diff --git a/src/port/erand48.c b/src/port/erand48.c index 9d471197c3..716816bc36 100644 --- a/src/port/erand48.c +++ b/src/port/erand48.c @@ -91,6 +91,13 @@ pg_lrand48(void) return ((long) _rand48_seed[2] << 15) + ((long) _rand48_seed[1] >> 1); } +long +pg_jrand48(unsigned short xseed[3]) +{ + _dorand48(xseed); + return ((long) xseed[2] << 16) + ((long) xseed[1]); +} + void pg_srand48(long seed) { diff --git a/src/port/fls.c b/src/port/fls.c index 1ed1301398..ddd18f17f5 100644 --- a/src/port/fls.c +++ b/src/port/fls.c @@ -3,7 +3,7 @@ * fls.c * finds the last (most significant) bit that is set * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/port/fseeko.c b/src/port/fseeko.c index a75dfb7171..e9c0b07f0b 100644 --- a/src/port/fseeko.c +++ b/src/port/fseeko.c @@ -3,7 +3,7 @@ * fseeko.c * 64-bit versions of fseeko/ftello() * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/getaddrinfo.c b/src/port/getaddrinfo.c index 90c1b877eb..c0e4b33e20 100644 --- a/src/port/getaddrinfo.c +++ b/src/port/getaddrinfo.c @@ -13,7 +13,7 @@ * use the Windows native routines, but if not, we use our own. * * - * Copyright (c) 2003-2016, PostgreSQL Global Development Group + * Copyright (c) 2003-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/port/getaddrinfo.c diff --git a/src/port/getpeereid.c b/src/port/getpeereid.c index 5f8c0beaa9..53fa663122 100644 --- a/src/port/getpeereid.c +++ b/src/port/getpeereid.c @@ -3,7 +3,7 @@ * getpeereid.c * get peer userid for UNIX-domain socket connection * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/port/getrusage.c b/src/port/getrusage.c index a6f1ef2681..71fce75722 100644 --- a/src/port/getrusage.c +++ b/src/port/getrusage.c @@ -3,7 +3,7 @@ * getrusage.c * get information about resource utilisation * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -18,7 +18,6 @@ #include "rusagestub.h" /* This code works on: - * sco * solaris_i386 * solaris_sparc * hpux 9.* diff --git a/src/port/isinf.c b/src/port/isinf.c index 7e8aabcc77..570aa40fa2 100644 --- a/src/port/isinf.c +++ b/src/port/isinf.c @@ -2,7 +2,7 @@ * * isinf.c * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/kill.c b/src/port/kill.c index a5ca2e7d98..58343c4152 100644 --- a/src/port/kill.c +++ b/src/port/kill.c @@ -3,7 +3,7 @@ * kill.c * kill() * - * Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Copyright (c) 1996-2017, PostgreSQL Global Development Group * * This is a replacement version of kill for Win32 which sends * signals that the backend can recognize. diff --git a/src/port/mkdtemp.c b/src/port/mkdtemp.c index 8214145535..f6316562e8 100644 --- a/src/port/mkdtemp.c +++ b/src/port/mkdtemp.c @@ -3,7 +3,7 @@ * mkdtemp.c * create a mode-0700 temporary directory * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/port/noblock.c b/src/port/noblock.c index 52e1d71d9d..7e70319bd4 100644 --- a/src/port/noblock.c +++ b/src/port/noblock.c @@ -3,7 +3,7 @@ * noblock.c * set a file descriptor as non-blocking * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/port/open.c b/src/port/open.c index 717375dd64..db7abdbe03 100644 --- a/src/port/open.c +++ b/src/port/open.c @@ -4,7 +4,7 @@ * Win32 open() replacement * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * src/port/open.c * diff --git a/src/port/path.c b/src/port/path.c index 7bf7cbc9b3..46f20b1ef8 100644 --- a/src/port/path.c +++ b/src/port/path.c @@ -3,7 +3,7 @@ * path.c * portable path handling routines * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/pg_crc32c_choose.c b/src/port/pg_crc32c_choose.c index ab9f8f9e35..e82c9c4b27 100644 --- a/src/port/pg_crc32c_choose.c +++ b/src/port/pg_crc32c_choose.c @@ -7,7 +7,7 @@ * if available on the platform we're running on, but fall back to the * slicing-by-8 implementation otherwise. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/pg_crc32c_sb8.c b/src/port/pg_crc32c_sb8.c index 2680e365ab..eff7043202 100644 --- a/src/port/pg_crc32c_sb8.c +++ b/src/port/pg_crc32c_sb8.c @@ -8,7 +8,7 @@ * Generation", IEEE Transactions on Computers, vol.57, no. 11, * pp. 1550-1560, November 2008, doi:10.1109/TC.2008.85 * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/pg_crc32c_sse42.c b/src/port/pg_crc32c_sse42.c index a7f96bb0f8..75b4d96c69 100644 --- a/src/port/pg_crc32c_sse42.c +++ b/src/port/pg_crc32c_sse42.c @@ -3,7 +3,7 @@ * pg_crc32c_sse42.c * Compute CRC-32C checksum using Intel SSE 4.2 instructions. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/pg_strong_random.c b/src/port/pg_strong_random.c new file mode 100644 index 0000000000..ac5c5d5df5 --- /dev/null +++ b/src/port/pg_strong_random.c @@ -0,0 +1,149 @@ +/*------------------------------------------------------------------------- + * + * 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. + * + * Copyright (c) 1996-2017, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/port/pg_strong_random.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include +#include +#include + +#ifdef USE_OPENSSL +#include +#endif +#ifdef WIN32 +#include +#endif + +#ifdef WIN32 +/* + * 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; +#endif + +#if defined(USE_DEV_URANDOM) +/* + * Read (random) bytes from a file. + */ +static bool +random_from_file(char *filename, void *buf, size_t len) +{ + int f; + char *p = buf; + ssize_t res; + + f = open(filename, 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 + +/* + * pg_strong_random + * + * Generate requested number of random bytes. The returned bytes are + * cryptographically secure, suitable for use e.g. in authentication. + * + * 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 + * + * The configure script will choose which one to use, and set + * a USE_*_RANDOM flag accordingly. + * + * 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. + */ +bool +pg_strong_random(void *buf, size_t len) +{ + /* + * When built with OpenSSL, use OpenSSL's RAND_bytes function. + */ +#if defined(USE_OPENSSL_RANDOM) + if (RAND_bytes(buf, len) == 1) + return true; + return false; + + /* + * Windows has CryptoAPI for strong cryptographic numbers. + */ +#elif defined(USE_WIN32_RANDOM) + 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; + + /* + * Read /dev/urandom ourselves. + */ +#elif defined(USE_DEV_URANDOM) + if (random_from_file("/dev/urandom", buf, len)) + return true; + return false; + +#else + /* The autoconf script should not have allowed this */ +#error no source of random numbers configured +#endif +} diff --git a/src/port/pgcheckdir.c b/src/port/pgcheckdir.c index 15760dd92a..965249eeaa 100644 --- a/src/port/pgcheckdir.c +++ b/src/port/pgcheckdir.c @@ -5,7 +5,7 @@ * 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-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * *------------------------------------------------------------------------- diff --git a/src/port/pgsleep.c b/src/port/pgsleep.c index ef7f7aba6b..9f01b73b0f 100644 --- a/src/port/pgsleep.c +++ b/src/port/pgsleep.c @@ -4,7 +4,7 @@ * Portable delay handling. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * src/port/pgsleep.c * @@ -14,6 +14,9 @@ #include #include +#ifdef HAVE_SYS_SELECT_H +#include +#endif /* * In a Windows backend, we don't use this implementation, but rather diff --git a/src/port/pgstrcasecmp.c b/src/port/pgstrcasecmp.c index ee87a65fb9..d12778da8d 100644 --- a/src/port/pgstrcasecmp.c +++ b/src/port/pgstrcasecmp.c @@ -18,7 +18,7 @@ * C library thinks the locale is. * * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * src/port/pgstrcasecmp.c * diff --git a/src/port/pqsignal.c b/src/port/pqsignal.c index e5a73f2274..5d366da11e 100644 --- a/src/port/pqsignal.c +++ b/src/port/pqsignal.c @@ -4,7 +4,7 @@ * reliable BSD-style signal(2) routine stolen from RWW who stole it * from Stevens... * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/quotes.c b/src/port/quotes.c index 5bab8e7e3d..d7ea934c8b 100644 --- a/src/port/quotes.c +++ b/src/port/quotes.c @@ -3,7 +3,7 @@ * quotes.c * string quoting and escaping functions * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/random.c b/src/port/random.c index 8786f8f1fe..5071b31b5d 100644 --- a/src/port/random.c +++ b/src/port/random.c @@ -3,7 +3,7 @@ * random.c * random() wrapper * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/sprompt.c b/src/port/sprompt.c index fd6f16ed30..47cd9781fd 100644 --- a/src/port/sprompt.c +++ b/src/port/sprompt.c @@ -3,7 +3,7 @@ * sprompt.c * simple_prompt() routine * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -12,33 +12,31 @@ * *------------------------------------------------------------------------- */ +#include "c.h" + +#ifdef HAVE_TERMIOS_H +#include +#endif /* * simple_prompt * * Generalized function especially intended for reading in usernames and - * password interactively. Reads from /dev/tty or stdin/stderr. + * passwords interactively. Reads from /dev/tty or stdin/stderr. * - * prompt: The prompt to print - * maxlen: How many characters to accept + * prompt: The prompt to print, or NULL if none (automatically localized) + * destination: buffer in which to store result + * destlen: allocated length of destination * echo: Set to false if you want to hide what is entered (for passwords) * - * Returns a malloc()'ed string with the input (w/o trailing newline). + * The input (without trailing newline) is returned in the destination buffer, + * with a '\0' appended. */ -#include "c.h" - -#ifdef HAVE_TERMIOS_H -#include -#endif - -extern char *simple_prompt(const char *prompt, int maxlen, bool echo); - -char * -simple_prompt(const char *prompt, int maxlen, bool echo) +void +simple_prompt(const char *prompt, char *destination, size_t destlen, bool echo) { int length; - char *destination; FILE *termin, *termout; @@ -48,14 +46,10 @@ simple_prompt(const char *prompt, int maxlen, bool echo) #else #ifdef WIN32 HANDLE t = NULL; - LPDWORD t_orig = NULL; + DWORD t_orig = 0; #endif #endif - destination = (char *) malloc(maxlen + 1); - if (!destination) - return NULL; - #ifdef WIN32 /* @@ -118,11 +112,10 @@ simple_prompt(const char *prompt, int maxlen, bool echo) if (!echo) { /* get a new handle to turn echo off */ - t_orig = (LPDWORD) malloc(sizeof(DWORD)); t = GetStdHandle(STD_INPUT_HANDLE); /* save the old configuration first */ - GetConsoleMode(t, t_orig); + GetConsoleMode(t, &t_orig); /* set to the new mode */ SetConsoleMode(t, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT); @@ -136,7 +129,7 @@ simple_prompt(const char *prompt, int maxlen, bool echo) fflush(termout); } - if (fgets(destination, maxlen + 1, termin) == NULL) + if (fgets(destination, destlen, termin) == NULL) destination[0] = '\0'; length = strlen(destination); @@ -170,10 +163,9 @@ simple_prompt(const char *prompt, int maxlen, bool echo) if (!echo) { /* reset to the original console mode */ - SetConsoleMode(t, *t_orig); + SetConsoleMode(t, t_orig); fputs("\n", termout); fflush(termout); - free(t_orig); } #endif #endif @@ -183,6 +175,4 @@ simple_prompt(const char *prompt, int maxlen, bool echo) fclose(termin); fclose(termout); } - - return destination; } diff --git a/src/port/srandom.c b/src/port/srandom.c index af00eb8dd1..867c71858c 100644 --- a/src/port/srandom.c +++ b/src/port/srandom.c @@ -3,7 +3,7 @@ * srandom.c * srandom() wrapper * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/strlcpy.c b/src/port/strlcpy.c index 6aff65c190..29c14da0b6 100644 --- a/src/port/strlcpy.c +++ b/src/port/strlcpy.c @@ -3,7 +3,7 @@ * strlcpy.c * strncpy done right * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/port/system.c b/src/port/system.c index b0f98efae6..8651187890 100644 --- a/src/port/system.c +++ b/src/port/system.c @@ -29,7 +29,7 @@ * quote character on the command line, preserving any text after the last * quote character. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * src/port/system.c * diff --git a/src/port/tar.c b/src/port/tar.c index 52a2113a47..f1da959dac 100644 --- a/src/port/tar.c +++ b/src/port/tar.c @@ -16,7 +16,7 @@ * support only non-negative numbers, so we don't worry about the GNU rules * for handling negative numbers.) */ -static void +void print_tar_number(char *s, int len, uint64 val) { if (val < (((uint64) 1) << ((len - 1) * 3))) diff --git a/src/port/thread.c b/src/port/thread.c index ed908bab36..b54c871b00 100644 --- a/src/port/thread.c +++ b/src/port/thread.c @@ -5,7 +5,7 @@ * Prototypes and macros around system calls, used to help make * threaded libraries reentrant and safe to use from threaded applications. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * src/port/thread.c * diff --git a/src/port/unsetenv.c b/src/port/unsetenv.c index bb7ab4300b..83b04d2641 100644 --- a/src/port/unsetenv.c +++ b/src/port/unsetenv.c @@ -3,7 +3,7 @@ * unsetenv.c * unsetenv() emulation for machines without it * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/win32env.c b/src/port/win32env.c index e64065ca29..5480525fa2 100644 --- a/src/port/win32env.c +++ b/src/port/win32env.c @@ -1,11 +1,10 @@ /*------------------------------------------------------------------------- * * win32env.c - * putenv() and unsetenv() for win32, that updates both process - * environment and the cached versions in (potentially multiple) - * MSVCRT. + * putenv() and unsetenv() for win32, which update both process environment + * and caches in (potentially multiple) C run-time library (CRT) versions. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -22,107 +21,35 @@ pgwin32_putenv(const char *envval) { char *envcpy; char *cp; - - /* - * Each version of MSVCRT has its own _putenv() call in the runtime - * library. - * - * mingw always uses MSVCRT.DLL, but if we are in a Visual C++ - * environment, attempt to update the environment in all MSVCRT modules - * that are currently loaded, to work properly with any third party - * libraries linked against a different MSVCRT but still relying on - * environment variables. - * - * Also separately update the system environment that gets inherited by - * subprocesses. - */ -#ifdef _MSC_VER typedef int (_cdecl * PUTENVPROC) (const char *); - static struct - { - char *modulename; - HMODULE hmodule; - PUTENVPROC putenvFunc; - } rtmodules[] = - { - { - "msvcrt", 0, NULL - }, /* Visual Studio 6.0 / mingw */ - { - "msvcr70", 0, NULL - }, /* Visual Studio 2002 */ - { - "msvcr71", 0, NULL - }, /* Visual Studio 2003 */ - { - "msvcr80", 0, NULL - }, /* Visual Studio 2005 */ - { - "msvcr90", 0, NULL - }, /* Visual Studio 2008 */ - { - "msvcr100", 0, NULL - }, /* Visual Studio 2010 */ - { - "msvcr110", 0, NULL - }, /* Visual Studio 2012 */ - { - "msvcr120", 0, NULL - }, /* Visual Studio 2013 */ - { - "ucrtbase", 0, NULL - }, /* Visual Studio 2015 and later */ - { - NULL, 0, NULL - } + static const char *const modulenames[] = { + "msvcrt", /* Visual Studio 6.0 / MinGW */ + "msvcrtd", + "msvcr70", /* Visual Studio 2002 */ + "msvcr70d", + "msvcr71", /* Visual Studio 2003 */ + "msvcr71d", + "msvcr80", /* Visual Studio 2005 */ + "msvcr80d", + "msvcr90", /* Visual Studio 2008 */ + "msvcr90d", + "msvcr100", /* Visual Studio 2010 */ + "msvcr100d", + "msvcr110", /* Visual Studio 2012 */ + "msvcr110d", + "msvcr120", /* Visual Studio 2013 */ + "msvcr120d", + "ucrtbase", /* Visual Studio 2015 and later */ + "ucrtbased", + NULL }; int i; - for (i = 0; rtmodules[i].modulename; i++) - { - if (rtmodules[i].putenvFunc == NULL) - { - if (rtmodules[i].hmodule == 0) - { - /* Not attempted before, so try to find this DLL */ - rtmodules[i].hmodule = GetModuleHandle(rtmodules[i].modulename); - if (rtmodules[i].hmodule == NULL) - { - /* - * Set to INVALID_HANDLE_VALUE so we know we have tried - * this one before, and won't try again. - */ - rtmodules[i].hmodule = INVALID_HANDLE_VALUE; - continue; - } - else - { - rtmodules[i].putenvFunc = (PUTENVPROC) GetProcAddress(rtmodules[i].hmodule, "_putenv"); - if (rtmodules[i].putenvFunc == NULL) - { - CloseHandle(rtmodules[i].hmodule); - rtmodules[i].hmodule = INVALID_HANDLE_VALUE; - continue; - } - } - } - else - { - /* - * Module loaded, but we did not find the function last time. - * We're not going to find it this time either... - */ - continue; - } - } - /* At this point, putenvFunc is set or we have exited the loop */ - rtmodules[i].putenvFunc(envval); - } -#endif /* _MSC_VER */ - /* - * Update the process environment - to make modifications visible to child - * processes. + * Update process environment, making this change visible to child + * processes and to CRTs initializing in the future. Do this before the + * _putenv() loop, for the benefit of any CRT that initializes during this + * pgwin32_putenv() execution, after the loop checks that CRT. * * Need a copy of the string so we can modify it. */ @@ -142,7 +69,7 @@ pgwin32_putenv(const char *envval) /* * Only call SetEnvironmentVariable() when we are adding a variable, * not when removing it. Calling it on both crashes on at least - * certain versions of MingW. + * certain versions of MinGW. */ if (!SetEnvironmentVariable(envcpy, cp)) { @@ -152,7 +79,34 @@ pgwin32_putenv(const char *envval) } free(envcpy); - /* Finally, update our "own" cache */ + /* + * Each CRT has its own _putenv() symbol and copy of the environment. + * Update the environment in each CRT module currently loaded, so every + * third-party library sees this change regardless of the CRT it links + * against. Addresses within these modules may become invalid the moment + * we call FreeLibrary(), so don't cache them. + */ + for (i = 0; modulenames[i]; i++) + { + HMODULE hmodule = NULL; + BOOL res = GetModuleHandleEx(0, modulenames[i], &hmodule); + + if (res != 0 && hmodule != NULL) + { + PUTENVPROC putenvFunc; + + putenvFunc = (PUTENVPROC) GetProcAddress(hmodule, "_putenv"); + if (putenvFunc) + putenvFunc(envval); + FreeLibrary(hmodule); + } + } + + /* + * Finally, update our "own" cache. This is redundant with the loop + * above, except when PostgreSQL itself links to a CRT not listed above. + * Ideally, the loop does visit all possible CRTs, making this redundant. + */ return _putenv(envval); } diff --git a/src/port/win32error.c b/src/port/win32error.c index cf6522547e..40655962a8 100644 --- a/src/port/win32error.c +++ b/src/port/win32error.c @@ -3,7 +3,7 @@ * win32error.c * Map win32 error codes to errno values * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/port/win32error.c @@ -161,6 +161,9 @@ static const struct }, { ERROR_NOT_ENOUGH_QUOTA, ENOMEM + }, + { + ERROR_DELETE_PENDING, ENOENT } }; diff --git a/src/port/win32security.c b/src/port/win32security.c index ab9cd67748..777a2e5b99 100644 --- a/src/port/win32security.c +++ b/src/port/win32security.c @@ -3,7 +3,7 @@ * win32security.c * Microsoft Windows Win32 Security Support Functions * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/port/win32security.c @@ -65,7 +65,7 @@ pgwin32_is_admin(void) if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken)) { - log_error("could not open process token: error code %lu\n", + log_error(_("could not open process token: error code %lu\n"), GetLastError()); exit(1); } @@ -86,7 +86,7 @@ pgwin32_is_admin(void) DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdministratorsSid)) { - log_error("could not get SID for Administrators group: error code %lu\n", + log_error(_("could not get SID for Administrators group: error code %lu\n"), GetLastError()); exit(1); } @@ -96,7 +96,7 @@ pgwin32_is_admin(void) DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0, &PowerUsersSid)) { - log_error("could not get SID for PowerUsers group: error code %lu\n", + log_error(_("could not get SID for PowerUsers group: error code %lu\n"), GetLastError()); exit(1); } diff --git a/src/port/win32setlocale.c b/src/port/win32setlocale.c index 4abc7aa270..cbf109836b 100644 --- a/src/port/win32setlocale.c +++ b/src/port/win32setlocale.c @@ -3,7 +3,7 @@ * win32setlocale.c * Wrapper to work around bugs in Windows setlocale() implementation * - * Copyright (c) 2011-2016, PostgreSQL Global Development Group + * Copyright (c) 2011-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/port/win32setlocale.c diff --git a/src/port/win32ver.rc b/src/port/win32ver.rc index c21b74c017..4bd0736f47 100644 --- a/src/port/win32ver.rc +++ b/src/port/win32ver.rc @@ -2,8 +2,8 @@ #include "pg_config.h" VS_VERSION_INFO VERSIONINFO - FILEVERSION 9,6,0,0 - PRODUCTVERSION 9,6,0,0 + FILEVERSION 10,0,0,0 + PRODUCTVERSION 10,0,0,0 FILEFLAGSMASK 0x17L FILEFLAGS 0x0L FILEOS VOS_NT_WINDOWS32 @@ -17,7 +17,7 @@ BEGIN VALUE "CompanyName", "PostgreSQL Global Development Group" VALUE "FileDescription", FILEDESC VALUE "FileVersion", PG_VERSION - VALUE "LegalCopyright", "Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group. Portions Copyright (c) 1994, Regents of the University of California." + VALUE "LegalCopyright", "Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group. Portions Copyright (c) 1994, Regents of the University of California." VALUE "ProductName", "PostgreSQL" VALUE "ProductVersion", PG_VERSION END diff --git a/src/template/darwin b/src/template/darwin index 542f706b0f..ea6d3b0b04 100644 --- a/src/template/darwin +++ b/src/template/darwin @@ -1,9 +1,12 @@ # src/template/darwin -# Select appropriate semaphore support. Darwin 6.0 (Mac OS X 10.2) and up -# support System V semaphores; before that we have to use POSIX semaphores, -# which are less good for our purposes because they eat a file descriptor -# per backend per max_connection slot. +# Note: Darwin is the original code name for macOS, also known as OS X. +# We still use "darwin" as the port name, partly because config.guess does. + +# Select appropriate semaphore support. Darwin 6.0 (macOS 10.2) and up +# support System V semaphores; before that we have to use named POSIX +# semaphores, which are less good for our purposes because they eat a +# file descriptor per backend per max_connection slot. case $host_os in darwin[015].*) USE_NAMED_POSIX_SEMAPHORES=1 diff --git a/src/template/freebsd b/src/template/freebsd index 772e2f1a5f..a82d5a494c 100644 --- a/src/template/freebsd +++ b/src/template/freebsd @@ -1 +1,6 @@ # src/template/freebsd + +# Prefer unnamed POSIX semaphores if available, unless user overrides choice +if test x"$PREFERRED_SEMAPHORES" = x"" ; then + PREFERRED_SEMAPHORES=UNNAMED_POSIX +fi diff --git a/src/template/linux b/src/template/linux index 3eb5ad2428..f820bf7280 100644 --- a/src/template/linux +++ b/src/template/linux @@ -1,5 +1,10 @@ # src/template/linux +# Prefer unnamed POSIX semaphores if available, unless user overrides choice +if test x"$PREFERRED_SEMAPHORES" = x"" ; then + PREFERRED_SEMAPHORES=UNNAMED_POSIX +fi + # Force _GNU_SOURCE on; plperl is broken with Perl 5.8.0 otherwise CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" diff --git a/src/template/sco b/src/template/sco deleted file mode 100644 index 9a736da8be..0000000000 --- a/src/template/sco +++ /dev/null @@ -1 +0,0 @@ -CC="$CC -b elf" diff --git a/src/template/unixware b/src/template/unixware deleted file mode 100644 index d08fca1e6b..0000000000 --- a/src/template/unixware +++ /dev/null @@ -1,41 +0,0 @@ -if test "$GCC" != yes; then - # The -Kno_host is for a bug in the compiler. See -hackers - # discussion on 7-8/Aug/2003. - cat >conftest.c <<__EOF__ -extern char *strcpy(char *, const char *); - -static void f(char *p, int n){ - strcpy(p+n,""); -} -void g(void){ - f(0, 0); -} -__EOF__ - - # Debugging and optimization are mutually exclusive - if test "$enable_debug" != yes; then - CFLAGS="-O" - fi - if $CC -c -O -Kinline conftest.c >conftest.err 2>&1; then - CFLAGS="$CFLAGS -Kinline" - else - CFLAGS="$CFLAGS -Kinline,no_host" - fi - rm -f conftest.* - - PTHREAD_CFLAGS="-Kpthread" - -# The effect of doing threading for the backend does not work -# because of a threading bug that appears in the regression tests: -# -# in make check, the plpgsql test (plpgsql.sql) -# set statement_timeout to 1000; -# select blockme(); -# reset statement_timeout; -# -# per report from Olivier PRENANT - -fi - -# Unixware's ldap library reportedly needs these too -EXTRA_LDAP_LIBS="-llber -lresolv" diff --git a/src/test/Makefile b/src/test/Makefile index 7f7754f3ee..3c2215849e 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -12,7 +12,7 @@ subdir = src/test top_builddir = ../.. include $(top_builddir)/src/Makefile.global -SUBDIRS = regress isolation modules recovery +SUBDIRS = perl regress isolation modules recovery subscription # We don't build or execute examples/, locale/, or thread/ by default, # but we do want "make clean" etc to recurse into them. Likewise for ssl/, diff --git a/src/test/examples/testlibpq2.c b/src/test/examples/testlibpq2.c index 850993f6e8..07c6317a21 100644 --- a/src/test/examples/testlibpq2.c +++ b/src/test/examples/testlibpq2.c @@ -34,6 +34,10 @@ #include #include #include +#ifdef HAVE_SYS_SELECT_H +#include +#endif + #include "libpq-fe.h" static void diff --git a/src/test/examples/testlo.c b/src/test/examples/testlo.c index 557a673076..b7470385eb 100644 --- a/src/test/examples/testlo.c +++ b/src/test/examples/testlo.c @@ -3,7 +3,7 @@ * testlo.c * test using large objects with libpq * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/test/examples/testlo64.c b/src/test/examples/testlo64.c index 2b970d91a4..76558f4797 100644 --- a/src/test/examples/testlo64.c +++ b/src/test/examples/testlo64.c @@ -3,7 +3,7 @@ * testlo64.c * test using large objects with libpq using 64-bit APIs * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/test/isolation/expected/eval-plan-qual.out b/src/test/isolation/expected/eval-plan-qual.out index 5898d94ff1..10c784a05f 100644 --- a/src/test/isolation/expected/eval-plan-qual.out +++ b/src/test/isolation/expected/eval-plan-qual.out @@ -163,3 +163,24 @@ ta_id ta_value tb_row 1 newTableAValue (1,tableBValue) step c2: COMMIT; + +starting permutation: wrtwcte readwcte c1 c2 +step wrtwcte: UPDATE table_a SET value = 'tableAValue2' WHERE id = 1; +step readwcte: + WITH + cte1 AS ( + SELECT id FROM table_b WHERE value = 'tableBValue' + ), + cte2 AS ( + SELECT * FROM table_a + WHERE id = (SELECT id FROM cte1) + FOR UPDATE + ) + SELECT * FROM cte2; + +step c1: COMMIT; +step c2: COMMIT; +step readwcte: <... completed> +id value + +1 tableAValue2 diff --git a/src/test/isolation/expected/insert-conflict-do-nothing-2.out b/src/test/isolation/expected/insert-conflict-do-nothing-2.out new file mode 100644 index 0000000000..2332f96978 --- /dev/null +++ b/src/test/isolation/expected/insert-conflict-do-nothing-2.out @@ -0,0 +1,105 @@ +Parsed test spec with 2 sessions + +starting permutation: beginrr1 beginrr2 donothing1 c1 donothing2 c2 show +step beginrr1: BEGIN ISOLATION LEVEL REPEATABLE READ; +step beginrr2: BEGIN ISOLATION LEVEL REPEATABLE READ; +step donothing1: INSERT INTO ints(key, val) VALUES(1, 'donothing1') ON CONFLICT DO NOTHING; +step c1: COMMIT; +step donothing2: INSERT INTO ints(key, val) VALUES(1, 'donothing2'), (1, 'donothing3') ON CONFLICT DO NOTHING; +step c2: COMMIT; +step show: SELECT * FROM ints; +key val + +1 donothing1 + +starting permutation: beginrr1 beginrr2 donothing2 c2 donothing1 c1 show +step beginrr1: BEGIN ISOLATION LEVEL REPEATABLE READ; +step beginrr2: BEGIN ISOLATION LEVEL REPEATABLE READ; +step donothing2: INSERT INTO ints(key, val) VALUES(1, 'donothing2'), (1, 'donothing3') ON CONFLICT DO NOTHING; +step c2: COMMIT; +step donothing1: INSERT INTO ints(key, val) VALUES(1, 'donothing1') ON CONFLICT DO NOTHING; +step c1: COMMIT; +step show: SELECT * FROM ints; +key val + +1 donothing2 + +starting permutation: beginrr1 beginrr2 donothing1 donothing2 c1 c2 show +step beginrr1: BEGIN ISOLATION LEVEL REPEATABLE READ; +step beginrr2: BEGIN ISOLATION LEVEL REPEATABLE READ; +step donothing1: INSERT INTO ints(key, val) VALUES(1, 'donothing1') ON CONFLICT DO NOTHING; +step donothing2: INSERT INTO ints(key, val) VALUES(1, 'donothing2'), (1, 'donothing3') ON CONFLICT DO NOTHING; +step c1: COMMIT; +step donothing2: <... completed> +error in steps c1 donothing2: ERROR: could not serialize access due to concurrent update +step c2: COMMIT; +step show: SELECT * FROM ints; +key val + +1 donothing1 + +starting permutation: beginrr1 beginrr2 donothing2 donothing1 c2 c1 show +step beginrr1: BEGIN ISOLATION LEVEL REPEATABLE READ; +step beginrr2: BEGIN ISOLATION LEVEL REPEATABLE READ; +step donothing2: INSERT INTO ints(key, val) VALUES(1, 'donothing2'), (1, 'donothing3') ON CONFLICT DO NOTHING; +step donothing1: INSERT INTO ints(key, val) VALUES(1, 'donothing1') ON CONFLICT DO NOTHING; +step c2: COMMIT; +step donothing1: <... completed> +error in steps c2 donothing1: ERROR: could not serialize access due to concurrent update +step c1: COMMIT; +step show: SELECT * FROM ints; +key val + +1 donothing2 + +starting permutation: begins1 begins2 donothing1 c1 donothing2 c2 show +step begins1: BEGIN ISOLATION LEVEL SERIALIZABLE; +step begins2: BEGIN ISOLATION LEVEL SERIALIZABLE; +step donothing1: INSERT INTO ints(key, val) VALUES(1, 'donothing1') ON CONFLICT DO NOTHING; +step c1: COMMIT; +step donothing2: INSERT INTO ints(key, val) VALUES(1, 'donothing2'), (1, 'donothing3') ON CONFLICT DO NOTHING; +step c2: COMMIT; +step show: SELECT * FROM ints; +key val + +1 donothing1 + +starting permutation: begins1 begins2 donothing2 c2 donothing1 c1 show +step begins1: BEGIN ISOLATION LEVEL SERIALIZABLE; +step begins2: BEGIN ISOLATION LEVEL SERIALIZABLE; +step donothing2: INSERT INTO ints(key, val) VALUES(1, 'donothing2'), (1, 'donothing3') ON CONFLICT DO NOTHING; +step c2: COMMIT; +step donothing1: INSERT INTO ints(key, val) VALUES(1, 'donothing1') ON CONFLICT DO NOTHING; +step c1: COMMIT; +step show: SELECT * FROM ints; +key val + +1 donothing2 + +starting permutation: begins1 begins2 donothing1 donothing2 c1 c2 show +step begins1: BEGIN ISOLATION LEVEL SERIALIZABLE; +step begins2: BEGIN ISOLATION LEVEL SERIALIZABLE; +step donothing1: INSERT INTO ints(key, val) VALUES(1, 'donothing1') ON CONFLICT DO NOTHING; +step donothing2: INSERT INTO ints(key, val) VALUES(1, 'donothing2'), (1, 'donothing3') ON CONFLICT DO NOTHING; +step c1: COMMIT; +step donothing2: <... completed> +error in steps c1 donothing2: ERROR: could not serialize access due to concurrent update +step c2: COMMIT; +step show: SELECT * FROM ints; +key val + +1 donothing1 + +starting permutation: begins1 begins2 donothing2 donothing1 c2 c1 show +step begins1: BEGIN ISOLATION LEVEL SERIALIZABLE; +step begins2: BEGIN ISOLATION LEVEL SERIALIZABLE; +step donothing2: INSERT INTO ints(key, val) VALUES(1, 'donothing2'), (1, 'donothing3') ON CONFLICT DO NOTHING; +step donothing1: INSERT INTO ints(key, val) VALUES(1, 'donothing1') ON CONFLICT DO NOTHING; +step c2: COMMIT; +step donothing1: <... completed> +error in steps c2 donothing1: ERROR: could not serialize access due to concurrent update +step c1: COMMIT; +step show: SELECT * FROM ints; +key val + +1 donothing2 diff --git a/src/test/isolation/expected/insert-conflict-toast.out b/src/test/isolation/expected/insert-conflict-toast.out new file mode 100644 index 0000000000..e86b98020f --- /dev/null +++ b/src/test/isolation/expected/insert-conflict-toast.out @@ -0,0 +1,15 @@ +Parsed test spec with 3 sessions + +starting permutation: s2insert s3insert s1commit +pg_advisory_xact_lock + + +step s2insert: + INSERT INTO ctoast (key, val) VALUES (1, ctoast_large_val()) ON CONFLICT DO NOTHING; + +step s3insert: + INSERT INTO ctoast (key, val) VALUES (1, ctoast_large_val()) ON CONFLICT DO NOTHING; + +step s1commit: COMMIT; +step s2insert: <... completed> +step s3insert: <... completed> diff --git a/src/test/isolation/expected/insert-conflict-toast_1.out b/src/test/isolation/expected/insert-conflict-toast_1.out new file mode 100644 index 0000000000..18346162b7 --- /dev/null +++ b/src/test/isolation/expected/insert-conflict-toast_1.out @@ -0,0 +1,15 @@ +Parsed test spec with 3 sessions + +starting permutation: s2insert s3insert s1commit +pg_advisory_xact_lock + + +step s2insert: + INSERT INTO ctoast (key, val) VALUES (1, ctoast_large_val()) ON CONFLICT DO NOTHING; + +step s3insert: + INSERT INTO ctoast (key, val) VALUES (1, ctoast_large_val()) ON CONFLICT DO NOTHING; + +step s1commit: COMMIT; +step s3insert: <... completed> +step s2insert: <... completed> diff --git a/src/test/isolation/isolation_main.c b/src/test/isolation/isolation_main.c index a0bd92f374..46b48ee855 100644 --- a/src/test/isolation/isolation_main.c +++ b/src/test/isolation/isolation_main.c @@ -2,7 +2,7 @@ * * isolation_main --- pg_regress test launcher for isolation tests * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/test/isolation/isolation_main.c diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule index 87ab7742fc..2606a27624 100644 --- a/src/test/isolation/isolation_schedule +++ b/src/test/isolation/isolation_schedule @@ -25,9 +25,11 @@ test: eval-plan-qual test: lock-update-delete test: lock-update-traversal test: insert-conflict-do-nothing +test: insert-conflict-do-nothing-2 test: insert-conflict-do-update test: insert-conflict-do-update-2 test: insert-conflict-do-update-3 +test: insert-conflict-toast test: delete-abort-savept test: delete-abort-savept-2 test: aborted-keyrevoke diff --git a/src/test/isolation/isolationtester.c b/src/test/isolation/isolationtester.c index 908a7ce800..db2b55982b 100644 --- a/src/test/isolation/isolationtester.c +++ b/src/test/isolation/isolationtester.c @@ -119,7 +119,7 @@ main(int argc, char **argv) for (i = 0; i < testspec->nsessions; i++) nallsteps += testspec->sessions[i]->nsteps; - allsteps = malloc(nallsteps * sizeof(Step *)); + allsteps = pg_malloc(nallsteps * sizeof(Step *)); n = 0; for (i = 0; i < testspec->nsessions; i++) @@ -190,7 +190,7 @@ main(int argc, char **argv) if (PQresultStatus(res) == PGRES_TUPLES_OK) { if (PQntuples(res) == 1 && PQnfields(res) == 1) - backend_pids[i] = strdup(PQgetvalue(res, 0, 0)); + backend_pids[i] = pg_strdup(PQgetvalue(res, 0, 0)); else { fprintf(stderr, "backend pid query returned %d rows and %d columns, expected 1 row and 1 column", @@ -286,7 +286,7 @@ run_all_permutations(TestSpec *testspec) for (i = 0; i < testspec->nsessions; i++) nsteps += testspec->sessions[i]->nsteps; - steps = malloc(sizeof(Step *) * nsteps); + steps = pg_malloc(sizeof(Step *) * nsteps); /* * To generate the permutations, we conceptually put the steps of each @@ -297,7 +297,7 @@ run_all_permutations(TestSpec *testspec) * A pile is actually just an integer which tells how many steps we've * already picked from this pile. */ - piles = malloc(sizeof(int) * testspec->nsessions); + piles = pg_malloc(sizeof(int) * testspec->nsessions); for (i = 0; i < testspec->nsessions; i++) piles[i] = 0; @@ -345,7 +345,7 @@ run_named_permutations(TestSpec *testspec) Permutation *p = testspec->permutations[i]; Step **steps; - steps = malloc(p->nsteps * sizeof(Step *)); + steps = pg_malloc(p->nsteps * sizeof(Step *)); /* Find all the named steps using the lookup table */ for (j = 0; j < p->nsteps; j++) @@ -476,8 +476,8 @@ run_permutation(TestSpec *testspec, int nsteps, Step **steps) return; } - waiting = malloc(sizeof(Step *) * testspec->nsessions); - errorstep = malloc(sizeof(Step *) * testspec->nsessions); + waiting = pg_malloc(sizeof(Step *) * testspec->nsessions); + errorstep = pg_malloc(sizeof(Step *) * testspec->nsessions); printf("\nstarting permutation:"); for (i = 0; i < nsteps; i++) diff --git a/src/test/isolation/isolationtester.h b/src/test/isolation/isolationtester.h index 0a213edabe..a15d5be897 100644 --- a/src/test/isolation/isolationtester.h +++ b/src/test/isolation/isolationtester.h @@ -3,7 +3,7 @@ * isolationtester.h * include file for isolation tests * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/test/isolation/specparse.y b/src/test/isolation/specparse.y index fce6cc6c94..759b9b456c 100644 --- a/src/test/isolation/specparse.y +++ b/src/test/isolation/specparse.y @@ -4,7 +4,7 @@ * specparse.y * bison grammar for the isolation test file format * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * *------------------------------------------------------------------------- @@ -73,8 +73,8 @@ setup_list: } | setup_list setup { - $$.elements = realloc($1.elements, - ($1.nelements + 1) * sizeof(void *)); + $$.elements = pg_realloc($1.elements, + ($1.nelements + 1) * sizeof(void *)); $$.elements[$1.nelements] = $2; $$.nelements = $1.nelements + 1; } @@ -97,15 +97,15 @@ opt_teardown: session_list: session_list session { - $$.elements = realloc($1.elements, - ($1.nelements + 1) * sizeof(void *)); + $$.elements = pg_realloc($1.elements, + ($1.nelements + 1) * sizeof(void *)); $$.elements[$1.nelements] = $2; $$.nelements = $1.nelements + 1; } | session { $$.nelements = 1; - $$.elements = malloc(sizeof(void *)); + $$.elements = pg_malloc(sizeof(void *)); $$.elements[0] = $1; } ; @@ -113,7 +113,7 @@ session_list: session: SESSION string_literal opt_setup step_list opt_teardown { - $$ = malloc(sizeof(Session)); + $$ = pg_malloc(sizeof(Session)); $$->name = $2; $$->setupsql = $3; $$->steps = (Step **) $4.elements; @@ -125,15 +125,15 @@ session: step_list: step_list step { - $$.elements = realloc($1.elements, - ($1.nelements + 1) * sizeof(void *)); + $$.elements = pg_realloc($1.elements, + ($1.nelements + 1) * sizeof(void *)); $$.elements[$1.nelements] = $2; $$.nelements = $1.nelements + 1; } | step { $$.nelements = 1; - $$.elements = malloc(sizeof(void *)); + $$.elements = pg_malloc(sizeof(void *)); $$.elements[0] = $1; } ; @@ -142,7 +142,7 @@ step_list: step: STEP string_literal sqlblock { - $$ = malloc(sizeof(Step)); + $$ = pg_malloc(sizeof(Step)); $$->name = $2; $$->sql = $3; $$->errormsg = NULL; @@ -164,15 +164,15 @@ opt_permutation_list: permutation_list: permutation_list permutation { - $$.elements = realloc($1.elements, - ($1.nelements + 1) * sizeof(void *)); + $$.elements = pg_realloc($1.elements, + ($1.nelements + 1) * sizeof(void *)); $$.elements[$1.nelements] = $2; $$.nelements = $1.nelements + 1; } | permutation { $$.nelements = 1; - $$.elements = malloc(sizeof(void *)); + $$.elements = pg_malloc(sizeof(void *)); $$.elements[0] = $1; } ; @@ -181,7 +181,7 @@ permutation_list: permutation: PERMUTATION string_literal_list { - $$ = malloc(sizeof(Permutation)); + $$ = pg_malloc(sizeof(Permutation)); $$->stepnames = (char **) $2.elements; $$->nsteps = $2.nelements; } @@ -190,15 +190,15 @@ permutation: string_literal_list: string_literal_list string_literal { - $$.elements = realloc($1.elements, - ($1.nelements + 1) * sizeof(void *)); + $$.elements = pg_realloc($1.elements, + ($1.nelements + 1) * sizeof(void *)); $$.elements[$1.nelements] = $2; $$.nelements = $1.nelements + 1; } | string_literal { $$.nelements = 1; - $$.elements = malloc(sizeof(void *)); + $$.elements = pg_malloc(sizeof(void *)); $$.elements[0] = $1; } ; diff --git a/src/test/isolation/specs/eval-plan-qual.spec b/src/test/isolation/specs/eval-plan-qual.spec index de481a3cec..7ff6f6b8cc 100644 --- a/src/test/isolation/specs/eval-plan-qual.spec +++ b/src/test/isolation/specs/eval-plan-qual.spec @@ -103,11 +103,27 @@ step "readforss" { FROM table_a ta WHERE ta.id = 1 FOR UPDATE OF ta; } +step "wrtwcte" { UPDATE table_a SET value = 'tableAValue2' WHERE id = 1; } step "c2" { COMMIT; } session "s3" setup { BEGIN ISOLATION LEVEL READ COMMITTED; } step "read" { SELECT * FROM accounts ORDER BY accountid; } + +# this test exercises EvalPlanQual with a CTE, cf bug #14328 +step "readwcte" { + WITH + cte1 AS ( + SELECT id FROM table_b WHERE value = 'tableBValue' + ), + cte2 AS ( + SELECT * FROM table_a + WHERE id = (SELECT id FROM cte1) + FOR UPDATE + ) + SELECT * FROM cte2; +} + teardown { COMMIT; } permutation "wx1" "wx2" "c1" "c2" "read" @@ -118,3 +134,4 @@ permutation "writep2" "returningp1" "c1" "c2" permutation "wx2" "partiallock" "c2" "c1" "read" permutation "wx2" "lockwithvalues" "c2" "c1" "read" permutation "updateforss" "readforss" "c1" "c2" +permutation "wrtwcte" "readwcte" "c1" "c2" diff --git a/src/test/isolation/specs/insert-conflict-do-nothing-2.spec b/src/test/isolation/specs/insert-conflict-do-nothing-2.spec new file mode 100644 index 0000000000..f1e5bde357 --- /dev/null +++ b/src/test/isolation/specs/insert-conflict-do-nothing-2.spec @@ -0,0 +1,34 @@ +# INSERT...ON CONFLICT DO NOTHING test with multiple rows +# in higher isolation levels + +setup +{ + CREATE TABLE ints (key int primary key, val text); +} + +teardown +{ + DROP TABLE ints; +} + +session "s1" +step "beginrr1" { BEGIN ISOLATION LEVEL REPEATABLE READ; } +step "begins1" { BEGIN ISOLATION LEVEL SERIALIZABLE; } +step "donothing1" { INSERT INTO ints(key, val) VALUES(1, 'donothing1') ON CONFLICT DO NOTHING; } +step "c1" { COMMIT; } +step "show" { SELECT * FROM ints; } + +session "s2" +step "beginrr2" { BEGIN ISOLATION LEVEL REPEATABLE READ; } +step "begins2" { BEGIN ISOLATION LEVEL SERIALIZABLE; } +step "donothing2" { INSERT INTO ints(key, val) VALUES(1, 'donothing2'), (1, 'donothing3') ON CONFLICT DO NOTHING; } +step "c2" { COMMIT; } + +permutation "beginrr1" "beginrr2" "donothing1" "c1" "donothing2" "c2" "show" +permutation "beginrr1" "beginrr2" "donothing2" "c2" "donothing1" "c1" "show" +permutation "beginrr1" "beginrr2" "donothing1" "donothing2" "c1" "c2" "show" +permutation "beginrr1" "beginrr2" "donothing2" "donothing1" "c2" "c1" "show" +permutation "begins1" "begins2" "donothing1" "c1" "donothing2" "c2" "show" +permutation "begins1" "begins2" "donothing2" "c2" "donothing1" "c1" "show" +permutation "begins1" "begins2" "donothing1" "donothing2" "c1" "c2" "show" +permutation "begins1" "begins2" "donothing2" "donothing1" "c2" "c1" "show" diff --git a/src/test/isolation/specs/insert-conflict-toast.spec b/src/test/isolation/specs/insert-conflict-toast.spec new file mode 100644 index 0000000000..c5e39ef9e3 --- /dev/null +++ b/src/test/isolation/specs/insert-conflict-toast.spec @@ -0,0 +1,51 @@ +# INSERT...ON CONFLICT test on table with TOAST +# +# This test verifies that speculatively inserted toast rows do not +# cause conflicts. It does so by using expression index over a +# function which acquires an advisory lock, triggering two index +# insertions to happen almost at the same time. This is not guaranteed +# to lead to a failed speculative insertion, but makes one quite +# likely. + +setup +{ + CREATE TABLE ctoast (key int primary key, val text); + CREATE OR REPLACE FUNCTION ctoast_lock_func(int) RETURNS INT IMMUTABLE LANGUAGE SQL AS 'select pg_advisory_xact_lock_shared(1); select $1;'; + CREATE OR REPLACE FUNCTION ctoast_large_val() RETURNS TEXT LANGUAGE SQL AS 'select array_agg(md5(g::text))::text from generate_series(1, 256) g'; + CREATE UNIQUE INDEX ctoast_lock_idx ON ctoast (ctoast_lock_func(key)); +} + +teardown +{ + DROP TABLE ctoast; + DROP FUNCTION ctoast_lock_func(int); + DROP FUNCTION ctoast_large_val(); +} + +session "s1" +setup +{ + BEGIN ISOLATION LEVEL READ COMMITTED; + SELECT pg_advisory_xact_lock(1); +} +step "s1commit" { COMMIT; } + +session "s2" +setup +{ + SET default_transaction_isolation = 'read committed'; +} +step "s2insert" { + INSERT INTO ctoast (key, val) VALUES (1, ctoast_large_val()) ON CONFLICT DO NOTHING; +} + +session "s3" +setup +{ + SET default_transaction_isolation = 'read committed'; +} +step "s3insert" { + INSERT INTO ctoast (key, val) VALUES (1, ctoast_large_val()) ON CONFLICT DO NOTHING; +} + +permutation "s2insert" "s3insert" "s1commit" diff --git a/src/test/isolation/specscanner.l b/src/test/isolation/specscanner.l index 675bd21f17..aed9269c63 100644 --- a/src/test/isolation/specscanner.l +++ b/src/test/isolation/specscanner.l @@ -4,7 +4,7 @@ * specscanner.l * a lexical scanner for an isolation test specification * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * *------------------------------------------------------------------------- @@ -56,7 +56,7 @@ teardown { return(TEARDOWN); } } \" { litbuf[litbufpos] = '\0'; - yylval.str = strdup(litbuf); + yylval.str = pg_strdup(litbuf); BEGIN(INITIAL); return(string_literal); } @@ -72,7 +72,7 @@ teardown { return(TEARDOWN); } } {space}*"}" { litbuf[litbufpos] = '\0'; - yylval.str = strdup(litbuf); + yylval.str = pg_strdup(litbuf); BEGIN(INITIAL); return(sqlblock); } diff --git a/src/test/locale/sort-test.pl b/src/test/locale/sort-test.pl index ce7b93c571..cb7e4934e4 100755 --- a/src/test/locale/sort-test.pl +++ b/src/test/locale/sort-test.pl @@ -1,4 +1,6 @@ #! /usr/bin/perl + +use strict; use locale; open(INFILE, "<$ARGV[0]"); diff --git a/src/test/modules/commit_ts/Makefile b/src/test/modules/commit_ts/Makefile index f814f767c4..86b93b5e76 100644 --- a/src/test/modules/commit_ts/Makefile +++ b/src/test/modules/commit_ts/Makefile @@ -3,11 +3,6 @@ REGRESS = commit_timestamp REGRESS_OPTS = --temp-config=$(top_srcdir)/src/test/modules/commit_ts/commit_ts.conf -check: prove-check - -prove-check: - $(prove_check) - ifdef USE_PGXS PG_CONFIG = pg_config PGXS := $(shell $(PG_CONFIG) --pgxs) @@ -18,3 +13,8 @@ top_builddir = ../../../.. include $(top_builddir)/src/Makefile.global include $(top_srcdir)/contrib/contrib-global.mk endif + +check: prove-check + +prove-check: + $(prove_check) diff --git a/src/test/modules/commit_ts/expected/commit_timestamp.out b/src/test/modules/commit_ts/expected/commit_timestamp.out index 99f3322c42..5b7783b58f 100644 --- a/src/test/modules/commit_ts/expected/commit_timestamp.out +++ b/src/test/modules/commit_ts/expected/commit_timestamp.out @@ -28,9 +28,17 @@ DROP TABLE committs_test; SELECT pg_xact_commit_timestamp('0'::xid); ERROR: cannot retrieve commit timestamp for transaction 0 SELECT pg_xact_commit_timestamp('1'::xid); -ERROR: cannot retrieve commit timestamp for transaction 1 + pg_xact_commit_timestamp +-------------------------- + +(1 row) + SELECT pg_xact_commit_timestamp('2'::xid); -ERROR: cannot retrieve commit timestamp for transaction 2 + pg_xact_commit_timestamp +-------------------------- + +(1 row) + SELECT x.xid::text::bigint > 0, x.timestamp > '-infinity'::timestamptz, x.timestamp <= now() FROM pg_last_committed_xact() x; ?column? | ?column? | ?column? ----------+----------+---------- diff --git a/src/test/modules/commit_ts/expected/commit_timestamp_1.out b/src/test/modules/commit_ts/expected/commit_timestamp_1.out index 2f1f41d209..c10b0abc2b 100644 --- a/src/test/modules/commit_ts/expected/commit_timestamp_1.out +++ b/src/test/modules/commit_ts/expected/commit_timestamp_1.out @@ -23,9 +23,17 @@ DROP TABLE committs_test; SELECT pg_xact_commit_timestamp('0'::xid); ERROR: cannot retrieve commit timestamp for transaction 0 SELECT pg_xact_commit_timestamp('1'::xid); -ERROR: cannot retrieve commit timestamp for transaction 1 + pg_xact_commit_timestamp +-------------------------- + +(1 row) + SELECT pg_xact_commit_timestamp('2'::xid); -ERROR: cannot retrieve commit timestamp for transaction 2 + pg_xact_commit_timestamp +-------------------------- + +(1 row) + SELECT x.xid::text::bigint > 0, x.timestamp > '-infinity'::timestamptz, x.timestamp <= now() FROM pg_last_committed_xact() x; ERROR: could not get commit timestamp data HINT: Make sure the configuration parameter "track_commit_timestamp" is set. diff --git a/src/test/modules/commit_ts/t/002_standby.pl b/src/test/modules/commit_ts/t/002_standby.pl index 4dbde2978e..ff60044540 100644 --- a/src/test/modules/commit_ts/t/002_standby.pl +++ b/src/test/modules/commit_ts/t/002_standby.pl @@ -15,7 +15,6 @@ 'postgresql.conf', qq{ track_commit_timestamp = on max_wal_senders = 5 - wal_level = hot_standby }); $master->start; $master->backup($bkplabel); diff --git a/src/test/modules/commit_ts/t/003_standby_2.pl b/src/test/modules/commit_ts/t/003_standby_2.pl index d37ff182c4..1775b22dad 100644 --- a/src/test/modules/commit_ts/t/003_standby_2.pl +++ b/src/test/modules/commit_ts/t/003_standby_2.pl @@ -14,7 +14,6 @@ 'postgresql.conf', qq{ track_commit_timestamp = on max_wal_senders = 5 - wal_level = hot_standby }); $master->start; $master->backup($bkplabel); @@ -55,7 +54,7 @@ $master->append_conf('postgresql.conf', 'track_commit_timestamp = off'); $master->restart; -system_or_bail('pg_ctl', '-w', '-D', $standby->data_dir, 'promote'); +system_or_bail('pg_ctl', '-D', $standby->data_dir, 'promote'); $standby->poll_query_until('postgres', "SELECT pg_is_in_recovery() <> true"); $standby->safe_psql('postgres', "create table t11()"); diff --git a/src/test/modules/commit_ts/t/004_restart.pl b/src/test/modules/commit_ts/t/004_restart.pl new file mode 100644 index 0000000000..a0a24971d2 --- /dev/null +++ b/src/test/modules/commit_ts/t/004_restart.pl @@ -0,0 +1,131 @@ +# Testing of commit timestamps preservation across clean restarts +use strict; +use warnings; +use PostgresNode; +use TestLib; +use Test::More tests => 16; + +my $node_master = get_new_node('master'); +$node_master->init(allows_streaming => 1); +$node_master->append_conf( + 'postgresql.conf', qq( +track_commit_timestamp = on +)); +$node_master->start; + +my ($ret, $stdout, $stderr); + +($ret, $stdout, $stderr) = + $node_master->psql('postgres', qq[SELECT pg_xact_commit_timestamp('0');]); +is($ret, 3, 'getting ts of InvalidTransactionId reports error'); +like( + $stderr, + qr/cannot retrieve commit timestamp for transaction/, + 'expected error from InvalidTransactionId'); + +($ret, $stdout, $stderr) = + $node_master->psql('postgres', qq[SELECT pg_xact_commit_timestamp('1');]); +is($ret, 0, 'getting ts of BootstrapTransactionId succeeds'); +is($stdout, '', 'timestamp of BootstrapTransactionId is null'); + +($ret, $stdout, $stderr) = + $node_master->psql('postgres', qq[SELECT pg_xact_commit_timestamp('2');]); +is($ret, 0, 'getting ts of FrozenTransactionId succeeds'); +is($stdout, '', 'timestamp of FrozenTransactionId is null'); + +# Since FirstNormalTransactionId will've occurred during initdb, long before we +# enabled commit timestamps, it'll be null since we have no cts data for it but +# cts are enabled. +is( $node_master->safe_psql( + 'postgres', qq[SELECT pg_xact_commit_timestamp('3');]), + '', + 'committs for FirstNormalTransactionId is null'); + +$node_master->safe_psql('postgres', + qq[CREATE TABLE committs_test(x integer, y timestamp with time zone);]); + +my $xid = $node_master->safe_psql( + 'postgres', qq[ + BEGIN; + INSERT INTO committs_test(x, y) VALUES (1, current_timestamp); + SELECT txid_current(); + COMMIT; +]); + +my $before_restart_ts = $node_master->safe_psql('postgres', + qq[SELECT pg_xact_commit_timestamp('$xid');]); +ok($before_restart_ts ne '' && $before_restart_ts ne 'null', + 'commit timestamp recorded'); + +$node_master->stop('immediate'); +$node_master->start; + +my $after_crash_ts = $node_master->safe_psql('postgres', + qq[SELECT pg_xact_commit_timestamp('$xid');]); +is($after_crash_ts, $before_restart_ts, + 'timestamps before and after crash are equal'); + +$node_master->stop('fast'); +$node_master->start; + +my $after_restart_ts = $node_master->safe_psql('postgres', + qq[SELECT pg_xact_commit_timestamp('$xid');]); +is($after_restart_ts, $before_restart_ts, + 'timestamps before and after restart are equal'); + +# Now disable commit timestamps + +$node_master->append_conf( + 'postgresql.conf', qq( +track_commit_timestamp = off +)); + +$node_master->stop('fast'); +$node_master->start; + +($ret, $stdout, $stderr) = $node_master->psql('postgres', + qq[SELECT pg_xact_commit_timestamp('$xid');]); +is($ret, 3, 'no commit timestamp from enable tx when cts disabled'); +like( + $stderr, + qr/could not get commit timestamp data/, + 'expected error from enabled tx when committs disabled'); + +# Do a tx while cts disabled +my $xid_disabled = $node_master->safe_psql( + 'postgres', qq[ + BEGIN; + INSERT INTO committs_test(x, y) VALUES (2, current_timestamp); + SELECT txid_current(); + COMMIT; +]); + +# Should be inaccessible +($ret, $stdout, $stderr) = $node_master->psql('postgres', + qq[SELECT pg_xact_commit_timestamp('$xid_disabled');]); +is($ret, 3, 'no commit timestamp when disabled'); +like( + $stderr, + qr/could not get commit timestamp data/, + 'expected error from disabled tx when committs disabled'); + +# Re-enable, restart and ensure we can still get the old timestamps +$node_master->append_conf( + 'postgresql.conf', qq( +track_commit_timestamp = on +)); + +$node_master->stop('fast'); +$node_master->start; + + +my $after_enable_ts = $node_master->safe_psql('postgres', + qq[SELECT pg_xact_commit_timestamp('$xid');]); +is($after_enable_ts, '', 'timestamp of enabled tx null after re-enable'); + +my $after_enable_disabled_ts = $node_master->safe_psql('postgres', + qq[SELECT pg_xact_commit_timestamp('$xid_disabled');]); +is($after_enable_disabled_ts, '', + 'timestamp of disabled tx null after re-enable'); + +$node_master->stop; diff --git a/src/test/modules/dummy_seclabel/dummy_seclabel.c b/src/test/modules/dummy_seclabel/dummy_seclabel.c index b3ef636c4e..7fd78f05c7 100644 --- a/src/test/modules/dummy_seclabel/dummy_seclabel.c +++ b/src/test/modules/dummy_seclabel/dummy_seclabel.c @@ -7,7 +7,7 @@ * perspective, but allows regression testing independent of platform-specific * features like SELinux. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California */ #include "postgres.h" diff --git a/src/test/modules/test_ddl_deparse/Makefile b/src/test/modules/test_ddl_deparse/Makefile index 8ea6f39afd..3a57a95c84 100644 --- a/src/test/modules/test_ddl_deparse/Makefile +++ b/src/test/modules/test_ddl_deparse/Makefile @@ -23,6 +23,7 @@ REGRESS = test_ddl_deparse \ comment_on \ alter_function \ alter_sequence \ + alter_ts_config \ alter_type_enum \ opfamily \ defprivs \ diff --git a/src/test/modules/test_ddl_deparse/expected/alter_ts_config.out b/src/test/modules/test_ddl_deparse/expected/alter_ts_config.out new file mode 100644 index 0000000000..afc352fc5f --- /dev/null +++ b/src/test/modules/test_ddl_deparse/expected/alter_ts_config.out @@ -0,0 +1,8 @@ +-- +-- ALTER TEXT SEARCH CONFIGURATION +-- +CREATE TEXT SEARCH CONFIGURATION en (copy=english); +NOTICE: DDL test: type simple, tag CREATE TEXT SEARCH CONFIGURATION +ALTER TEXT SEARCH CONFIGURATION en + ALTER MAPPING FOR host, email, url, sfloat WITH simple; +NOTICE: DDL test: type alter text search configuration, tag ALTER TEXT SEARCH CONFIGURATION diff --git a/src/test/modules/test_ddl_deparse/sql/alter_ts_config.sql b/src/test/modules/test_ddl_deparse/sql/alter_ts_config.sql new file mode 100644 index 0000000000..ac13e21dda --- /dev/null +++ b/src/test/modules/test_ddl_deparse/sql/alter_ts_config.sql @@ -0,0 +1,8 @@ +-- +-- ALTER TEXT SEARCH CONFIGURATION +-- + +CREATE TEXT SEARCH CONFIGURATION en (copy=english); + +ALTER TEXT SEARCH CONFIGURATION en + ALTER MAPPING FOR host, email, url, sfloat WITH simple; diff --git a/src/test/modules/test_ddl_deparse/test_ddl_deparse.c b/src/test/modules/test_ddl_deparse/test_ddl_deparse.c index 739daa6b90..2fe6903ba3 100644 --- a/src/test/modules/test_ddl_deparse/test_ddl_deparse.c +++ b/src/test/modules/test_ddl_deparse/test_ddl_deparse.c @@ -2,7 +2,7 @@ * test_ddl_deparse.c * Support functions for the test_ddl_deparse module * - * Copyright (c) 2014-2016, PostgreSQL Global Development Group + * Copyright (c) 2014-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/test_ddl_deparse/test_ddl_deparse.c diff --git a/src/test/modules/test_extensions/Makefile b/src/test/modules/test_extensions/Makefile index 8f0eeb7d3c..d18108e4e5 100644 --- a/src/test/modules/test_extensions/Makefile +++ b/src/test/modules/test_extensions/Makefile @@ -4,10 +4,11 @@ MODULE = test_extensions PGFILEDESC = "test_extensions - regression testing for EXTENSION support" EXTENSION = test_ext1 test_ext2 test_ext3 test_ext4 test_ext5 test_ext6 \ - test_ext_cyclic1 test_ext_cyclic2 + test_ext7 test_ext8 test_ext_cyclic1 test_ext_cyclic2 DATA = test_ext1--1.0.sql test_ext2--1.0.sql test_ext3--1.0.sql \ - test_ext4--1.0.sql test_ext5--1.0.sql test_ext6--1.0.sql \ - test_ext_cyclic1--1.0.sql test_ext_cyclic2--1.0.sql + test_ext4--1.0.sql test_ext5--1.0.sql test_ext6--1.0.sql \ + test_ext7--1.0.sql test_ext7--1.0--2.0.sql test_ext8--1.0.sql \ + test_ext_cyclic1--1.0.sql test_ext_cyclic2--1.0.sql REGRESS = test_extensions test_extdepend diff --git a/src/test/modules/test_extensions/expected/test_extensions.out b/src/test/modules/test_extensions/expected/test_extensions.out index c3360c97cc..ba8b90e742 100644 --- a/src/test/modules/test_extensions/expected/test_extensions.out +++ b/src/test/modules/test_extensions/expected/test_extensions.out @@ -38,3 +38,86 @@ drop cascades to extension test_ext1 CREATE EXTENSION test_ext6; DROP EXTENSION test_ext6; CREATE EXTENSION test_ext6; +-- test dropping of member tables that own extensions: +-- this table will be absorbed into test_ext7 +create table old_table1 (col1 serial primary key); +create extension test_ext7; +\dx+ test_ext7 +Objects in extension "test_ext7" + Object Description +------------------------------- + sequence ext7_table1_col1_seq + sequence ext7_table2_col2_seq + sequence old_table1_col1_seq + table ext7_table1 + table ext7_table2 + table old_table1 +(6 rows) + +alter extension test_ext7 update to '2.0'; +\dx+ test_ext7 +Objects in extension "test_ext7" + Object Description +------------------------------- + sequence ext7_table2_col2_seq + table ext7_table2 +(2 rows) + +-- test handling of temp objects created by extensions +create extension test_ext8; +-- \dx+ would expose a variable pg_temp_nn schema name, so we can't use it here +select regexp_replace(pg_describe_object(classid, objid, objsubid), + 'pg_temp_\d+', 'pg_temp', 'g') as "Object Description" +from pg_depend +where refclassid = 'pg_extension'::regclass and deptype = 'e' and + refobjid = (select oid from pg_extension where extname = 'test_ext8') +order by 1; + Object Description +----------------------------------------- + function ext8_even(posint) + function pg_temp.ext8_temp_even(posint) + table ext8_table1 + table ext8_temp_table1 + type posint +(5 rows) + +-- Should be possible to drop and recreate this extension +drop extension test_ext8; +create extension test_ext8; +select regexp_replace(pg_describe_object(classid, objid, objsubid), + 'pg_temp_\d+', 'pg_temp', 'g') as "Object Description" +from pg_depend +where refclassid = 'pg_extension'::regclass and deptype = 'e' and + refobjid = (select oid from pg_extension where extname = 'test_ext8') +order by 1; + Object Description +----------------------------------------- + function ext8_even(posint) + function pg_temp.ext8_temp_even(posint) + table ext8_table1 + table ext8_temp_table1 + type posint +(5 rows) + +-- here we want to start a new session and wait till old one is gone +select pg_backend_pid() as oldpid \gset +\c - +do 'declare c int = 0; +begin + while (select count(*) from pg_stat_activity where pid = ' + :'oldpid' + ') > 0 loop c := c + 1; perform pg_stat_clear_snapshot(); end loop; + raise log ''test_extensions looped % times'', c; +end'; +-- extension should now contain no temp objects +\dx+ test_ext8 +Objects in extension "test_ext8" + Object Description +---------------------------- + function ext8_even(posint) + table ext8_table1 + type posint +(3 rows) + +-- dropping it should still work +drop extension test_ext8; diff --git a/src/test/modules/test_extensions/sql/test_extensions.sql b/src/test/modules/test_extensions/sql/test_extensions.sql index 2ab8b599dc..0bfc559295 100644 --- a/src/test/modules/test_extensions/sql/test_extensions.sql +++ b/src/test/modules/test_extensions/sql/test_extensions.sql @@ -17,3 +17,50 @@ DROP SCHEMA test_ext CASCADE; CREATE EXTENSION test_ext6; DROP EXTENSION test_ext6; CREATE EXTENSION test_ext6; + +-- test dropping of member tables that own extensions: +-- this table will be absorbed into test_ext7 +create table old_table1 (col1 serial primary key); +create extension test_ext7; +\dx+ test_ext7 +alter extension test_ext7 update to '2.0'; +\dx+ test_ext7 + +-- test handling of temp objects created by extensions +create extension test_ext8; + +-- \dx+ would expose a variable pg_temp_nn schema name, so we can't use it here +select regexp_replace(pg_describe_object(classid, objid, objsubid), + 'pg_temp_\d+', 'pg_temp', 'g') as "Object Description" +from pg_depend +where refclassid = 'pg_extension'::regclass and deptype = 'e' and + refobjid = (select oid from pg_extension where extname = 'test_ext8') +order by 1; + +-- Should be possible to drop and recreate this extension +drop extension test_ext8; +create extension test_ext8; + +select regexp_replace(pg_describe_object(classid, objid, objsubid), + 'pg_temp_\d+', 'pg_temp', 'g') as "Object Description" +from pg_depend +where refclassid = 'pg_extension'::regclass and deptype = 'e' and + refobjid = (select oid from pg_extension where extname = 'test_ext8') +order by 1; + +-- here we want to start a new session and wait till old one is gone +select pg_backend_pid() as oldpid \gset +\c - +do 'declare c int = 0; +begin + while (select count(*) from pg_stat_activity where pid = ' + :'oldpid' + ') > 0 loop c := c + 1; perform pg_stat_clear_snapshot(); end loop; + raise log ''test_extensions looped % times'', c; +end'; + +-- extension should now contain no temp objects +\dx+ test_ext8 + +-- dropping it should still work +drop extension test_ext8; diff --git a/src/test/modules/test_extensions/test_ext7--1.0--2.0.sql b/src/test/modules/test_extensions/test_ext7--1.0--2.0.sql new file mode 100644 index 0000000000..50e3dca9cf --- /dev/null +++ b/src/test/modules/test_extensions/test_ext7--1.0--2.0.sql @@ -0,0 +1,8 @@ +/* src/test/modules/test_extensions/test_ext7--1.0--2.0.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION test_ext7 UPDATE TO '2.0'" to load this file. \quit + +-- drop some tables with serial columns +drop table ext7_table1; +drop table old_table1; diff --git a/src/test/modules/test_extensions/test_ext7--1.0.sql b/src/test/modules/test_extensions/test_ext7--1.0.sql new file mode 100644 index 0000000000..0c2d72ab80 --- /dev/null +++ b/src/test/modules/test_extensions/test_ext7--1.0.sql @@ -0,0 +1,13 @@ +/* src/test/modules/test_extensions/test_ext7--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION test_ext7" to load this file. \quit + +-- link some existing serial-owning table to the extension +alter extension test_ext7 add table old_table1; +alter extension test_ext7 add sequence old_table1_col1_seq; + +-- ordinary member tables with serial columns +create table ext7_table1 (col1 serial primary key); + +create table ext7_table2 (col2 serial primary key); diff --git a/src/test/modules/test_extensions/test_ext7.control b/src/test/modules/test_extensions/test_ext7.control new file mode 100644 index 0000000000..b58df53c11 --- /dev/null +++ b/src/test/modules/test_extensions/test_ext7.control @@ -0,0 +1,4 @@ +comment = 'Test extension 7' +default_version = '1.0' +schema = 'public' +relocatable = false diff --git a/src/test/modules/test_extensions/test_ext8--1.0.sql b/src/test/modules/test_extensions/test_ext8--1.0.sql new file mode 100644 index 0000000000..1561ffefaa --- /dev/null +++ b/src/test/modules/test_extensions/test_ext8--1.0.sql @@ -0,0 +1,21 @@ +/* src/test/modules/test_extensions/test_ext8--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION test_ext8" to load this file. \quit + +-- create some random data type +create domain posint as int check (value > 0); + +-- use it in regular and temporary tables and functions + +create table ext8_table1 (f1 posint); + +create temp table ext8_temp_table1 (f1 posint); + +create function ext8_even (posint) returns bool as + 'select ($1 % 2) = 0' language sql; + +create function pg_temp.ext8_temp_even (posint) returns bool as + 'select ($1 % 2) = 0' language sql; + +-- we intentionally don't drop the temp objects before exiting diff --git a/src/test/modules/test_extensions/test_ext8.control b/src/test/modules/test_extensions/test_ext8.control new file mode 100644 index 0000000000..70f8caaf30 --- /dev/null +++ b/src/test/modules/test_extensions/test_ext8.control @@ -0,0 +1,4 @@ +comment = 'Test extension 8' +default_version = '1.0' +schema = 'public' +relocatable = false diff --git a/src/test/modules/test_parser/test_parser.c b/src/test/modules/test_parser/test_parser.c index ce637f19ba..43b96120de 100644 --- a/src/test/modules/test_parser/test_parser.c +++ b/src/test/modules/test_parser/test_parser.c @@ -3,7 +3,7 @@ * test_parser.c * Simple example of a text search parser * - * Copyright (c) 2007-2016, PostgreSQL Global Development Group + * Copyright (c) 2007-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/test_parser/test_parser.c diff --git a/src/test/modules/test_pg_dump/Makefile b/src/test/modules/test_pg_dump/Makefile index 08d8903e72..5050572777 100644 --- a/src/test/modules/test_pg_dump/Makefile +++ b/src/test/modules/test_pg_dump/Makefile @@ -1,4 +1,4 @@ -# src/test/modules/test_rls_hooks/Makefile +# src/test/modules/test_pg_dump/Makefile MODULE = test_pg_dump PGFILEDESC = "test_pg_dump - Test pg_dump with an extension" @@ -8,11 +8,6 @@ DATA = test_pg_dump--1.0.sql REGRESS = test_pg_dump -check: prove-check - -prove-check: - $(prove_check) - ifdef USE_PGXS PG_CONFIG = pg_config PGXS := $(shell $(PG_CONFIG) --pgxs) @@ -23,3 +18,8 @@ top_builddir = ../../../.. include $(top_builddir)/src/Makefile.global include $(top_srcdir)/contrib/contrib-global.mk endif + +check: prove-check + +prove-check: + $(prove_check) diff --git a/src/test/modules/test_pg_dump/t/001_base.pl b/src/test/modules/test_pg_dump/t/001_base.pl index f02beb3d9c..70719a36a7 100644 --- a/src/test/modules/test_pg_dump/t/001_base.pl +++ b/src/test/modules/test_pg_dump/t/001_base.pl @@ -193,7 +193,7 @@ create_sql => 'CREATE EXTENSION test_pg_dump;', regexp => qr/^ \QCREATE EXTENSION IF NOT EXISTS test_pg_dump WITH SCHEMA public;\E - $/xm, + \n/xm, like => { clean => 1, clean_if_exists => 1, @@ -210,7 +210,7 @@ 'CREATE ROLE regress_dump_test_role' => { create_order => 1, create_sql => 'CREATE ROLE regress_dump_test_role;', - regexp => qr/^CREATE ROLE regress_dump_test_role;$/m, + regexp => qr/^CREATE ROLE regress_dump_test_role;\n/m, like => { pg_dumpall_globals => 1, }, unlike => { binary_upgrade => 1, @@ -231,7 +231,7 @@ \n\s+\QNO MINVALUE\E \n\s+\QNO MAXVALUE\E \n\s+\QCACHE 1;\E - $/xm, + \n/xm, like => { binary_upgrade => 1, }, unlike => { clean => 1, @@ -252,7 +252,7 @@ \n\s+\QNO MINVALUE\E \n\s+\QNO MAXVALUE\E \n\s+\QCACHE 1;\E - $/xm, + \n/xm, like => { binary_upgrade => 1, }, unlike => { clean => 1, @@ -265,12 +265,31 @@ schema_only => 1, section_pre_data => 1, section_post_data => 1, }, }, + 'SETVAL SEQUENCE regress_seq_dumpable' => { + create_order => 6, + create_sql => qq{SELECT nextval('regress_seq_dumpable');}, + regexp => qr/^ + \QSELECT pg_catalog.setval('regress_seq_dumpable', 1, true);\E + \n/xm, + like => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + data_only => 1, + defaults => 1, + no_owner => 1, + no_privs => 1, }, + unlike => { + pg_dumpall_globals => 1, + schema_only => 1, + section_pre_data => 1, + section_post_data => 1, }, }, 'CREATE TABLE regress_pg_dump_table' => { regexp => qr/^ \QCREATE TABLE regress_pg_dump_table (\E \n\s+\Qcol1 integer NOT NULL,\E \n\s+\Qcol2 integer\E - \n\);$/xm, + \n\);\n/xm, like => { binary_upgrade => 1, }, unlike => { clean => 1, @@ -286,7 +305,7 @@ 'CREATE ACCESS METHOD regress_test_am' => { regexp => qr/^ \QCREATE ACCESS METHOD regress_test_am TYPE INDEX HANDLER bthandler;\E - $/xm, + \n/xm, like => { binary_upgrade => 1, }, unlike => { clean => 1, @@ -303,7 +322,7 @@ regexp => qr/^ \QCOMMENT ON EXTENSION test_pg_dump \E \QIS 'Test pg_dump with an extension';\E - $/xm, + \n/xm, like => { binary_upgrade => 1, clean => 1, @@ -322,7 +341,7 @@ \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\E\n \QGRANT SELECT ON TABLE regress_pg_dump_table TO regress_dump_test_role;\E\n \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\E - $/xms, + \n/xms, like => { binary_upgrade => 1, }, unlike => { clean => 1, @@ -340,7 +359,7 @@ \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\E\n \QGRANT SELECT(col1) ON TABLE regress_pg_dump_table TO PUBLIC;\E\n \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\E - $/xms, + \n/xms, like => { binary_upgrade => 1, }, unlike => { clean => 1, @@ -359,7 +378,7 @@ TO regress_dump_test_role;', regexp => qr/^ \QGRANT SELECT(col2) ON TABLE regress_pg_dump_table TO regress_dump_test_role;\E - $/xm, + \n/xm, like => { binary_upgrade => 1, clean => 1, @@ -380,7 +399,7 @@ TO regress_dump_test_role;', regexp => qr/^ \QGRANT USAGE ON SEQUENCE regress_pg_dump_table_col1_seq TO regress_dump_test_role;\E - $/xm, + \n/xm, like => { binary_upgrade => 1, clean => 1, @@ -397,7 +416,7 @@ 'GRANT USAGE ON regress_pg_dump_seq TO regress_dump_test_role' => { regexp => qr/^ \QGRANT USAGE ON SEQUENCE regress_pg_dump_seq TO regress_dump_test_role;\E - $/xm, + \n/xm, like => { binary_upgrade => 1, }, unlike => { clean => 1, @@ -416,7 +435,7 @@ FROM PUBLIC;', regexp => qr/^ \QREVOKE SELECT(col1) ON TABLE regress_pg_dump_table FROM PUBLIC;\E - $/xm, + \n/xm, like => { binary_upgrade => 1, clean => 1, @@ -429,7 +448,211 @@ unlike => { no_privs => 1, pg_dumpall_globals => 1, - section_post_data => 1, }, },); + section_post_data => 1, }, }, + # Objects included in extension part of a schema created by this extension */ + 'CREATE TABLE regress_pg_dump_schema.test_table' => { + regexp => qr/^ + \QCREATE TABLE test_table (\E + \n\s+\Qcol1 integer,\E + \n\s+\Qcol2 integer\E + \n\);\n/xm, + like => { binary_upgrade => 1, }, + unlike => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + no_privs => 1, + no_owner => 1, + pg_dumpall_globals => 1, + schema_only => 1, + section_pre_data => 1, + section_post_data => 1, }, }, + 'GRANT SELECT ON regress_pg_dump_schema.test_table' => { + regexp => qr/^ + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\E\n + \QGRANT SELECT ON TABLE test_table TO regress_dump_test_role;\E\n + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\E + \n/xms, + like => { binary_upgrade => 1, }, + unlike => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + no_owner => 1, + no_privs => 1, + pg_dumpall_globals => 1, + schema_only => 1, + section_pre_data => 1, + section_post_data => 1, }, }, + 'CREATE SEQUENCE regress_pg_dump_schema.test_seq' => { + regexp => qr/^ + \QCREATE SEQUENCE test_seq\E + \n\s+\QSTART WITH 1\E + \n\s+\QINCREMENT BY 1\E + \n\s+\QNO MINVALUE\E + \n\s+\QNO MAXVALUE\E + \n\s+\QCACHE 1;\E + \n/xm, + like => { binary_upgrade => 1, }, + unlike => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + no_privs => 1, + no_owner => 1, + pg_dumpall_globals => 1, + schema_only => 1, + section_pre_data => 1, + section_post_data => 1, }, }, + 'GRANT USAGE ON regress_pg_dump_schema.test_seq' => { + regexp => qr/^ + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\E\n + \QGRANT USAGE ON SEQUENCE test_seq TO regress_dump_test_role;\E\n + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\E + \n/xms, + like => { binary_upgrade => 1, }, + unlike => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + no_owner => 1, + no_privs => 1, + pg_dumpall_globals => 1, + schema_only => 1, + section_pre_data => 1, + section_post_data => 1, }, }, + 'CREATE TYPE regress_pg_dump_schema.test_type' => { + regexp => qr/^ + \QCREATE TYPE test_type AS (\E + \n\s+\Qcol1 integer\E + \n\);\n/xm, + like => { binary_upgrade => 1, }, + unlike => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + no_privs => 1, + no_owner => 1, + pg_dumpall_globals => 1, + schema_only => 1, + section_pre_data => 1, + section_post_data => 1, }, }, + 'GRANT USAGE ON regress_pg_dump_schema.test_type' => { + regexp => qr/^ + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\E\n + \QGRANT ALL ON TYPE test_type TO regress_dump_test_role;\E\n + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\E + \n/xms, + like => { binary_upgrade => 1, }, + unlike => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + no_owner => 1, + no_privs => 1, + pg_dumpall_globals => 1, + schema_only => 1, + section_pre_data => 1, + section_post_data => 1, }, }, + 'CREATE FUNCTION regress_pg_dump_schema.test_func' => { + regexp => qr/^ + \QCREATE FUNCTION test_func() RETURNS integer\E + \n\s+\QLANGUAGE sql\E + \n/xm, + like => { binary_upgrade => 1, }, + unlike => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + no_privs => 1, + no_owner => 1, + pg_dumpall_globals => 1, + schema_only => 1, + section_pre_data => 1, + section_post_data => 1, }, }, + 'GRANT ALL ON regress_pg_dump_schema.test_func' => { + regexp => qr/^ + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\E\n + \QGRANT ALL ON FUNCTION test_func() TO regress_dump_test_role;\E\n + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\E + \n/xms, + like => { binary_upgrade => 1, }, + unlike => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + no_owner => 1, + no_privs => 1, + pg_dumpall_globals => 1, + schema_only => 1, + section_pre_data => 1, + section_post_data => 1, }, }, + 'CREATE AGGREGATE regress_pg_dump_schema.test_agg' => { + regexp => qr/^ + \QCREATE AGGREGATE test_agg(smallint) (\E + \n\s+\QSFUNC = int2_sum,\E + \n\s+\QSTYPE = bigint\E + \n\);\n/xm, + like => { binary_upgrade => 1, }, + unlike => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + no_privs => 1, + no_owner => 1, + pg_dumpall_globals => 1, + schema_only => 1, + section_pre_data => 1, + section_post_data => 1, }, }, + 'GRANT ALL ON regress_pg_dump_schema.test_agg' => { + regexp => qr/^ + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\E\n + \QGRANT ALL ON FUNCTION test_agg(smallint) TO regress_dump_test_role;\E\n + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\E + \n/xms, + like => { binary_upgrade => 1, }, + unlike => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + no_owner => 1, + no_privs => 1, + pg_dumpall_globals => 1, + schema_only => 1, + section_pre_data => 1, + section_post_data => 1, }, }, + # Objects not included in extension, part of schema created by extension + 'CREATE TABLE regress_pg_dump_schema.external_tab' => { + create_order => 4, + create_sql => 'CREATE TABLE regress_pg_dump_schema.external_tab + (col1 int);', + regexp => qr/^ + \QCREATE TABLE external_tab (\E + \n\s+\Qcol1 integer\E + \n\);\n/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + no_owner => 1, + no_privs => 1, + schema_only => 1, + section_pre_data => 1, }, + unlike => { + pg_dumpall_globals => 1, + section_post_data => 1, }, }, ); ######################################### # Create a PG instance to test actually dumping from diff --git a/src/test/modules/test_pg_dump/test_pg_dump--1.0.sql b/src/test/modules/test_pg_dump/test_pg_dump--1.0.sql index c2fe90d5ab..3ed007a7b1 100644 --- a/src/test/modules/test_pg_dump/test_pg_dump--1.0.sql +++ b/src/test/modules/test_pg_dump/test_pg_dump--1.0.sql @@ -10,6 +10,11 @@ CREATE TABLE regress_pg_dump_table ( CREATE SEQUENCE regress_pg_dump_seq; +CREATE SEQUENCE regress_seq_dumpable; +SELECT pg_catalog.pg_extension_config_dump('regress_seq_dumpable', ''); + +CREATE SCHEMA regress_pg_dump_schema; + GRANT USAGE ON regress_pg_dump_seq TO regress_dump_test_role; GRANT SELECT ON regress_pg_dump_table TO regress_dump_test_role; @@ -19,3 +24,25 @@ GRANT SELECT(col2) ON regress_pg_dump_table TO regress_dump_test_role; REVOKE SELECT(col2) ON regress_pg_dump_table FROM regress_dump_test_role; CREATE ACCESS METHOD regress_test_am TYPE INDEX HANDLER bthandler; + +-- Create a set of objects that are part of the schema created by +-- this extension. +CREATE TABLE regress_pg_dump_schema.test_table ( + col1 int, + col2 int +); +GRANT SELECT ON regress_pg_dump_schema.test_table TO regress_dump_test_role; + +CREATE SEQUENCE regress_pg_dump_schema.test_seq; +GRANT USAGE ON regress_pg_dump_schema.test_seq TO regress_dump_test_role; + +CREATE TYPE regress_pg_dump_schema.test_type AS (col1 int); +GRANT USAGE ON TYPE regress_pg_dump_schema.test_type TO regress_dump_test_role; + +CREATE FUNCTION regress_pg_dump_schema.test_func () RETURNS int +AS 'SELECT 1;' LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION regress_pg_dump_schema.test_func() TO regress_dump_test_role; + +CREATE AGGREGATE regress_pg_dump_schema.test_agg(int2) +(SFUNC = int2_sum, STYPE = int8); +GRANT EXECUTE ON FUNCTION regress_pg_dump_schema.test_agg(int2) TO regress_dump_test_role; diff --git a/src/test/modules/test_rls_hooks/expected/test_rls_hooks.out b/src/test/modules/test_rls_hooks/expected/test_rls_hooks.out index 19284c18d4..b8c6d38581 100644 --- a/src/test/modules/test_rls_hooks/expected/test_rls_hooks.out +++ b/src/test/modules/test_rls_hooks/expected/test_rls_hooks.out @@ -145,13 +145,11 @@ ERROR: new row violates row-level security policy for table "rls_test_permissiv SET ROLE regress_s1; -- With both internal and hook policies, restrictive EXPLAIN (costs off) SELECT * FROM rls_test_restrictive; - QUERY PLAN ---------------------------------------------------------------- - Subquery Scan on rls_test_restrictive - Filter: ((rls_test_restrictive.data % 2) = 0) - -> Seq Scan on rls_test_restrictive rls_test_restrictive_1 - Filter: ("current_user"() = supervisor) -(4 rows) + QUERY PLAN +------------------------------------------------------------------ + Seq Scan on rls_test_restrictive + Filter: (("current_user"() = supervisor) AND ((data % 2) = 0)) +(2 rows) SELECT * FROM rls_test_restrictive; username | supervisor | data @@ -173,13 +171,11 @@ ERROR: new row violates row-level security policy for table "rls_test_restricti -- With both internal and hook policies, both permissive -- and restrictive hook policies EXPLAIN (costs off) SELECT * FROM rls_test_both; - QUERY PLAN -------------------------------------------------------------------------------------------- - Subquery Scan on rls_test_both - Filter: (((rls_test_both.data % 2) = 0) OR ("current_user"() = rls_test_both.username)) - -> Seq Scan on rls_test_both rls_test_both_1 - Filter: ("current_user"() = supervisor) -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------------- + Seq Scan on rls_test_both + Filter: (("current_user"() = supervisor) AND (((data % 2) = 0) OR ("current_user"() = username))) +(2 rows) SELECT * FROM rls_test_both; username | supervisor | data diff --git a/src/test/modules/test_rls_hooks/test_rls_hooks.c b/src/test/modules/test_rls_hooks/test_rls_hooks.c index 7b4fa7ef4a..65bf3e33c9 100644 --- a/src/test/modules/test_rls_hooks/test_rls_hooks.c +++ b/src/test/modules/test_rls_hooks/test_rls_hooks.c @@ -3,7 +3,7 @@ * test_rls_hooks.c * Code for testing RLS hooks. * - * Copyright (c) 2015-2016, PostgreSQL Global Development Group + * Copyright (c) 2015-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/test_rls_hooks/test_rls_hooks.c diff --git a/src/test/modules/test_rls_hooks/test_rls_hooks.h b/src/test/modules/test_rls_hooks/test_rls_hooks.h index 11614e4e12..81f7b18090 100644 --- a/src/test/modules/test_rls_hooks/test_rls_hooks.h +++ b/src/test/modules/test_rls_hooks/test_rls_hooks.h @@ -3,7 +3,7 @@ * test_rls_hooks.h * Definitions for RLS hooks * - * Copyright (c) 2015-2016, PostgreSQL Global Development Group + * Copyright (c) 2015-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/test_rls_hooks/test_rls_hooks.h diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c index 143df4eb65..e3c024ecb4 100644 --- a/src/test/modules/test_shm_mq/setup.c +++ b/src/test/modules/test_shm_mq/setup.c @@ -5,7 +5,7 @@ * number of background workers for shared memory message queue * testing. * - * Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Copyright (c) 2013-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/test_shm_mq/setup.c @@ -16,6 +16,7 @@ #include "postgres.h" #include "miscadmin.h" +#include "pgstat.h" #include "postmaster/bgworker.h" #include "storage/procsignal.h" #include "storage/shm_toc.h" @@ -279,7 +280,7 @@ wait_for_workers_to_become_ready(worker_state *wstate, } /* Wait to be signalled. */ - WaitLatch(MyLatch, WL_LATCH_SET, 0); + WaitLatch(MyLatch, WL_LATCH_SET, 0, PG_WAIT_EXTENSION); /* Reset the latch so we don't spin. */ ResetLatch(MyLatch); diff --git a/src/test/modules/test_shm_mq/test.c b/src/test/modules/test_shm_mq/test.c index dd34bc7e7f..ea3657d5f0 100644 --- a/src/test/modules/test_shm_mq/test.c +++ b/src/test/modules/test_shm_mq/test.c @@ -3,7 +3,7 @@ * test.c * Test harness code for shared memory message queues. * - * Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Copyright (c) 2013-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/test_shm_mq/test.c @@ -15,6 +15,7 @@ #include "fmgr.h" #include "miscadmin.h" +#include "pgstat.h" #include "test_shm_mq.h" @@ -230,7 +231,7 @@ test_shm_mq_pipelined(PG_FUNCTION_ARGS) * have read or written data and therefore there may now be work * for us to do. */ - WaitLatch(MyLatch, WL_LATCH_SET, 0); + WaitLatch(MyLatch, WL_LATCH_SET, 0, PG_WAIT_EXTENSION); ResetLatch(MyLatch); CHECK_FOR_INTERRUPTS(); } diff --git a/src/test/modules/test_shm_mq/test_shm_mq.h b/src/test/modules/test_shm_mq/test_shm_mq.h index d398e860e3..e76ecab891 100644 --- a/src/test/modules/test_shm_mq/test_shm_mq.h +++ b/src/test/modules/test_shm_mq/test_shm_mq.h @@ -3,7 +3,7 @@ * test_shm_mq.h * Definitions for shared memory message queues * - * Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Copyright (c) 2013-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/test_shm_mq/test_shm_mq.h diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c index 638649b497..3e45c75dc0 100644 --- a/src/test/modules/test_shm_mq/worker.c +++ b/src/test/modules/test_shm_mq/worker.c @@ -9,7 +9,7 @@ * but it should be possible to use much of the control logic just * as presented here. * - * Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Copyright (c) 2013-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/test_shm_mq/worker.c diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c index 314e371b7f..72ab8464e1 100644 --- a/src/test/modules/worker_spi/worker_spi.c +++ b/src/test/modules/worker_spi/worker_spi.c @@ -13,7 +13,7 @@ * "delta" type. Delta rows will be deleted by this worker and their values * aggregated into the total. * - * Copyright (c) 2013-2016, PostgreSQL Global Development Group + * Copyright (c) 2013-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/worker_spi/worker_spi.c @@ -227,7 +227,8 @@ worker_spi_main(Datum main_arg) */ rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - worker_spi_naptime * 1000L); + worker_spi_naptime * 1000L, + PG_WAIT_EXTENSION); ResetLatch(MyLatch); /* emergency bailout if postmaster has died */ @@ -292,6 +293,7 @@ worker_spi_main(Datum main_arg) SPI_finish(); PopActiveSnapshot(); CommitTransactionCommand(); + pgstat_report_stat(false); pgstat_report_activity(STATE_IDLE, NULL); } diff --git a/src/test/perl/Makefile b/src/test/perl/Makefile new file mode 100644 index 0000000000..a974f358fd --- /dev/null +++ b/src/test/perl/Makefile @@ -0,0 +1,33 @@ +#------------------------------------------------------------------------- +# +# Makefile for src/test/perl +# +# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/test/perl/Makefile +# +#------------------------------------------------------------------------- + +subdir = src/test/perl +top_builddir = ../../.. +include $(top_builddir)/src/Makefile.global + +ifeq ($(enable_tap_tests),yes) + +installdirs: + $(MKDIR_P) '$(DESTDIR)$(pgxsdir)/$(subdir)' + +install: all installdirs + $(INSTALL_DATA) $(srcdir)/TestLib.pm '$(DESTDIR)$(pgxsdir)/$(subdir)/TestLib.pm' + $(INSTALL_DATA) $(srcdir)/SimpleTee.pm '$(DESTDIR)$(pgxsdir)/$(subdir)/SimpleTee.pm' + $(INSTALL_DATA) $(srcdir)/RecursiveCopy.pm '$(DESTDIR)$(pgxsdir)/$(subdir)/RecursiveCopy.pm' + $(INSTALL_DATA) $(srcdir)/PostgresNode.pm '$(DESTDIR)$(pgxsdir)/$(subdir)/PostgresNode.pm' + +uninstall: + rm -f '$(DESTDIR)$(pgxsdir)/$(subdir)/TestLib.pm' + rm -f '$(DESTDIR)$(pgxsdir)/$(subdir)/SimpleTee.pm' + rm -f '$(DESTDIR)$(pgxsdir)/$(subdir)/RecursiveCopy.pm' + rm -f '$(DESTDIR)$(pgxsdir)/$(subdir)/PostgresNode.pm' + +endif diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm index fede1e601b..18d5d12454 100644 --- a/src/test/perl/PostgresNode.pm +++ b/src/test/perl/PostgresNode.pm @@ -19,7 +19,7 @@ PostgresNode - class representing PostgreSQL server instance # Change a setting and restart $node->append_conf('postgresql.conf', 'hot_standby = on'); - $node->restart('fast'); + $node->restart(); # run a query with psql, like: # echo 'SELECT 1' | psql -qAXt postgres -v ON_ERROR_STOP=1 @@ -243,7 +243,13 @@ sub connstr { return "port=$pgport host=$pghost"; } - return "port=$pgport host=$pghost dbname=$dbname"; + + # Escape properly the database string before using it, only + # single quotes and backslashes need to be treated this way. + $dbname =~ s#\\#\\\\#g; + $dbname =~ s#\'#\\\'#g; + + return "port=$pgport host=$pghost dbname='$dbname'"; } =pod @@ -374,7 +380,9 @@ WAL archiving can be enabled on this node by passing the keyword parameter has_archiving => 1. This is disabled by default. postgresql.conf can be set up for replication by passing the keyword -parameter allows_streaming => 1. This is disabled by default. +parameter allows_streaming => 'logical' or 'physical' (passing 1 will also +suffice for physical replication) depending on type of replication that +should be enabled. This is disabled by default. The new node is set up in a fast but unsafe configuration where fsync is disabled. @@ -396,19 +404,29 @@ sub init mkdir $self->backup_dir; mkdir $self->archive_dir; - TestLib::system_or_bail('initdb', '-D', $pgdata, '-A', 'trust', '-N'); + TestLib::system_or_bail('initdb', '-D', $pgdata, '-A', 'trust', '-N', + @{ $params{extra} }); TestLib::system_or_bail($ENV{PG_REGRESS}, '--config-auth', $pgdata); open my $conf, ">>$pgdata/postgresql.conf"; print $conf "\n# Added by PostgresNode.pm\n"; print $conf "fsync = off\n"; + print $conf "log_line_prefix = '%m [%p] %q%a '\n"; print $conf "log_statement = all\n"; print $conf "port = $port\n"; if ($params{allows_streaming}) { - print $conf "wal_level = replica\n"; + if ($params{allows_streaming} eq "logical") + { + print $conf "wal_level = logical\n"; + } + else + { + print $conf "wal_level = replica\n"; + } print $conf "max_wal_senders = 5\n"; + print $conf "max_replication_slots = 5\n"; print $conf "wal_keep_segments = 20\n"; print $conf "max_wal_size = 128MB\n"; print $conf "shared_buffers = 1MB\n"; @@ -416,6 +434,11 @@ sub init print $conf "hot_standby = on\n"; print $conf "max_connections = 10\n"; } + else + { + print $conf "wal_level = minimal\n"; + print $conf "max_wal_senders = 0\n"; + } if ($TestLib::windows_os) { @@ -476,7 +499,7 @@ sub backup print "# Taking pg_basebackup $backup_name from node \"$name\"\n"; TestLib::system_or_bail('pg_basebackup', '-D', $backup_path, '-p', $port, - '-x'); + '--no-sync'); print "# Backup finished\n"; } @@ -624,7 +647,7 @@ port = $port =item $node->start() -Wrapper for pg_ctl -w start +Wrapper for pg_ctl start Start the node and wait until it is ready to accept connections. @@ -637,7 +660,7 @@ sub start my $pgdata = $self->data_dir; my $name = $self->name; print("### Starting node \"$name\"\n"); - my $ret = TestLib::system_log('pg_ctl', '-w', '-D', $self->data_dir, '-l', + my $ret = TestLib::system_log('pg_ctl', '-D', $self->data_dir, '-l', $self->logfile, 'start'); if ($ret != 0) @@ -694,7 +717,7 @@ sub reload =item $node->restart() -Wrapper for pg_ctl -w restart +Wrapper for pg_ctl restart =cut @@ -706,7 +729,7 @@ sub restart my $logfile = $self->logfile; my $name = $self->name; print "### Restarting node \"$name\"\n"; - TestLib::system_log('pg_ctl', '-D', $pgdata, '-w', '-l', $logfile, + TestLib::system_log('pg_ctl', '-D', $pgdata, '-l', $logfile, 'restart'); $self->_update_pid; } @@ -727,7 +750,8 @@ sub promote my $logfile = $self->logfile; my $name = $self->name; print "### Promoting node \"$name\"\n"; - TestLib::system_log('pg_ctl', '-D', $pgdata, '-l', $logfile, 'promote'); + TestLib::system_log('pg_ctl', '-D', $pgdata, '-l', $logfile, + 'promote'); } # Internal routine to enable streaming replication on a standby node. @@ -1112,7 +1136,6 @@ sub psql my $exc_save = $@; if ($exc_save) { - # IPC::Run::run threw an exception. re-throw unless it's a # timeout, which we'll handle by testing is_expired die $exc_save @@ -1164,7 +1187,7 @@ sub psql if $ret == 1; die "connection error: '$$stderr'\nwhile running '@psql_params'" if $ret == 2; - die "error running SQL: '$$stderr'\nwhile running '@psql_params'" + die "error running SQL: '$$stderr'\nwhile running '@psql_params' with sql '$sql'" if $ret == 3; die "psql returns $ret: '$$stderr'\nwhile running '@psql_params'"; } @@ -1184,7 +1207,7 @@ sub psql =item $node->poll_query_until(dbname, query) Run a query once a second, until it returns 't' (i.e. SQL boolean true). -Continues polling if psql returns an error result. Times out after 90 seconds. +Continues polling if psql returns an error result. Times out after 180 seconds. =cut @@ -1214,7 +1237,7 @@ sub poll_query_until $attempts++; } - # The query result didn't change in 90 seconds. Give up. Print the stderr + # The query result didn't change in 180 seconds. Give up. Print the stderr # from the last attempt, hopefully that's useful for debugging. diag $stderr; return 0; @@ -1300,6 +1323,203 @@ sub issues_sql_like =pod +=item $node->run_log(...) + +Runs a shell command like TestLib::run_log, but with PGPORT set so +that the command will default to connecting to this PostgresNode. + +=cut + +sub run_log +{ + my $self = shift; + + local $ENV{PGPORT} = $self->port; + + TestLib::run_log(@_); +} + +=pod + +=item $node->lsn(mode) + +Look up WAL positions on the server: + + * insert position (master only, error on replica) + * write position (master only, error on replica) + * flush position (master only, error on replica) + * receive position (always undef on master) + * replay position (always undef on master) + +mode must be specified. + +=cut + +sub lsn +{ + my ($self, $mode) = @_; + my %modes = ('insert' => 'pg_current_xlog_insert_location()', + 'flush' => 'pg_current_xlog_flush_location()', + 'write' => 'pg_current_xlog_location()', + 'receive' => 'pg_last_xlog_receive_location()', + 'replay' => 'pg_last_xlog_replay_location()'); + + $mode = '' if !defined($mode); + die "unknown mode for 'lsn': '$mode', valid modes are " . join(', ', keys %modes) + if !defined($modes{$mode}); + + my $result = $self->safe_psql('postgres', "SELECT $modes{$mode}"); + chomp($result); + if ($result eq '') + { + return undef; + } + else + { + return $result; + } +} + +=pod + +=item $node->wait_for_catchup(standby_name, mode, target_lsn) + +Wait for the node with application_name standby_name (usually from node->name) +until its replication position in pg_stat_replication equals or passes the +upstream's WAL insert point at the time this function is called. By default +the replay_location is waited for, but 'mode' may be specified to wait for any +of sent|write|flush|replay. + +If there is no active replication connection from this peer, waits until +poll_query_until timeout. + +Requires that the 'postgres' db exists and is accessible. + +target_lsn may be any arbitrary lsn, but is typically $master_node->lsn('insert'). + +This is not a test. It die()s on failure. + +=cut + +sub wait_for_catchup +{ + my ($self, $standby_name, $mode, $target_lsn) = @_; + $mode = defined($mode) ? $mode : 'replay'; + my %valid_modes = ( 'sent' => 1, 'write' => 1, 'flush' => 1, 'replay' => 1 ); + die "unknown mode $mode for 'wait_for_catchup', valid modes are " . join(', ', keys(%valid_modes)) unless exists($valid_modes{$mode}); + # Allow passing of a PostgresNode instance as shorthand + if ( blessed( $standby_name ) && $standby_name->isa("PostgresNode") ) + { + $standby_name = $standby_name->name; + } + die 'target_lsn must be specified' unless defined($target_lsn); + print "Waiting for replication conn " . $standby_name . "'s " . $mode . "_location to pass " . $target_lsn . " on " . $self->name . "\n"; + my $query = qq[SELECT '$target_lsn' <= ${mode}_location FROM pg_catalog.pg_stat_replication WHERE application_name = '$standby_name';]; + $self->poll_query_until('postgres', $query) + or die "timed out waiting for catchup, current position is " . ($self->safe_psql('postgres', $query) || '(unknown)'); + print "done\n"; +} + +=pod + +=item $node->wait_for_slot_catchup(slot_name, mode, target_lsn) + +Wait for the named replication slot to equal or pass the supplied target_lsn. +The position used is the restart_lsn unless mode is given, in which case it may +be 'restart' or 'confirmed_flush'. + +Requires that the 'postgres' db exists and is accessible. + +This is not a test. It die()s on failure. + +If the slot is not active, will time out after poll_query_until's timeout. + +target_lsn may be any arbitrary lsn, but is typically $master_node->lsn('insert'). + +Note that for logical slots, restart_lsn is held down by the oldest in-progress tx. + +=cut + +sub wait_for_slot_catchup +{ + my ($self, $slot_name, $mode, $target_lsn) = @_; + $mode = defined($mode) ? $mode : 'restart'; + if (!($mode eq 'restart' || $mode eq 'confirmed_flush')) + { + die "valid modes are restart, confirmed_flush"; + } + die 'target lsn must be specified' unless defined($target_lsn); + print "Waiting for replication slot " . $slot_name . "'s " . $mode . "_lsn to pass " . $target_lsn . " on " . $self->name . "\n"; + my $query = qq[SELECT '$target_lsn' <= ${mode}_lsn FROM pg_catalog.pg_replication_slots WHERE slot_name = '$slot_name';]; + $self->poll_query_until('postgres', $query) + or die "timed out waiting for catchup, current position is " . ($self->safe_psql('postgres', $query) || '(unknown)'); + print "done\n"; +} + +=pod + +=item $node->query_hash($dbname, $query, @columns) + +Execute $query on $dbname, replacing any appearance of the string __COLUMNS__ +within the query with a comma-separated list of @columns. + +If __COLUMNS__ does not appear in the query, its result columns must EXACTLY +match the order and number (but not necessarily alias) of supplied @columns. + +The query must return zero or one rows. + +Return a hash-ref representation of the results of the query, with any empty +or null results as defined keys with an empty-string value. There is no way +to differentiate between null and empty-string result fields. + +If the query returns zero rows, return a hash with all columns empty. There +is no way to differentiate between zero rows returned and a row with only +null columns. + +=cut + +sub query_hash +{ + my ($self, $dbname, $query, @columns) = @_; + die 'calls in array context for multi-row results not supported yet' if (wantarray); + # Replace __COLUMNS__ if found + substr($query, index($query, '__COLUMNS__'), length('__COLUMNS__')) = join(', ', @columns) + if index($query, '__COLUMNS__') >= 0; + my $result = $self->safe_psql($dbname, $query); + # hash slice, see http://stackoverflow.com/a/16755894/398670 . + # + # Fills the hash with empty strings produced by x-operator element + # duplication if result is an empty row + # + my %val; + @val{@columns} = $result ne '' ? split(qr/\|/, $result) : ('',) x scalar(@columns); + return \%val; +} + +=pod + +=item $node->slot(slot_name) + +Return hash-ref of replication slot data for the named slot, or a hash-ref with +all values '' if not found. Does not differentiate between null and empty string +for fields, no field is ever undef. + +The restart_lsn and confirmed_flush_lsn fields are returned verbatim, and also +as a 2-list of [highword, lowword] integer. Since we rely on Perl 5.8.8 we can't +"use bigint", it's from 5.20, and we can't assume we have Math::Bigint from CPAN +either. + +=cut + +sub slot +{ + my ($self, $slot_name) = @_; + my @columns = ('plugin', 'slot_type', 'datoid', 'database', 'active', 'active_pid', 'xmin', 'catalog_xmin', 'restart_lsn'); + return $self->query_hash('postgres', "SELECT __COLUMNS__ FROM pg_catalog.pg_replication_slots WHERE slot_name = '$slot_name'", @columns); +} + +=pod + =back =cut diff --git a/src/test/perl/README b/src/test/perl/README index 36d41203ce..f28e3ce469 100644 --- a/src/test/perl/README +++ b/src/test/perl/README @@ -6,6 +6,12 @@ across the source tree, particularly tests in src/bin and src/test. It's used to drive tests for backup and restore, replication, etc - anything that can't really be expressed using pg_regress or the isolation test framework. +The tests are invoked via perl's 'prove' command, wrapped in PostgreSQL +makefiles to handle instance setup etc. See the $(prove_check) and +$(prove_installcheck) targets in Makefile.global. By default every test in the +t/ subdirectory is run. Individual test(s) can be run instead by passing +something like PROVE_TESTS="t/001_testname.pl t/002_othertestname.pl" to make. + You should prefer to write tests using pg_regress in src/test/regress, or isolation tester specs in src/test/isolation, if possible. If not, check to see if your new tests make sense under an existing tree in src/test, like @@ -46,6 +52,10 @@ against them and evaluate the results. For example: $node->stop('fast'); +Test::More::like entails use of the qr// operator. Avoid Perl 5.8.8 bug +#39185 by not using the "$" regular expression metacharacter in qr// when also +using the "/m" modifier. Instead of "$", use "\n" or "(?=\n|\z)". + Read the Test::More documentation for more on how to write tests: perldoc Test::More @@ -54,3 +64,21 @@ For available PostgreSQL-specific test methods and some example tests read the perldoc for the test modules, e.g.: perldoc src/test/perl/PostgresNode.pm + +Required Perl +------------- + +Tests must run on perl 5.8.0 and newer. perlbrew is a good way to obtain such +a Perl; see http://perlbrew.pl . + +Just install and + + perlbrew --force install 5.8.0 + perlbrew use 5.8.0 + perlbrew install-cpanm + cpanm install IPC::Run + +then re-run configure to ensure the correct Perl is used when running +tests. To verify that the right Perl was found: + + grep ^PERL= config.log diff --git a/src/test/perl/TestLib.pm b/src/test/perl/TestLib.pm index 649fd82173..d22957ceb0 100644 --- a/src/test/perl/TestLib.pm +++ b/src/test/perl/TestLib.pm @@ -20,6 +20,7 @@ use SimpleTee; use Test::More; our @EXPORT = qw( + generate_ascii_string slurp_dir slurp_file append_to_file @@ -34,6 +35,7 @@ our @EXPORT = qw( program_version_ok program_options_handling_ok command_like + command_fails_like $windows_os ); @@ -60,6 +62,8 @@ BEGIN delete $ENV{PGPORT}; delete $ENV{PGHOST}; + $ENV{PGAPPNAME} = $0; + # Must be set early $windows_os = $Config{osname} eq 'MSWin32' || $Config{osname} eq 'msys'; } @@ -165,6 +169,19 @@ sub run_log return IPC::Run::run(@_); } +# Generate a string made of the given range of ASCII characters +sub generate_ascii_string +{ + my ($from_char, $to_char) = @_; + my $res; + + for my $i ($from_char .. $to_char) + { + $res .= sprintf("%c", $i); + } + return $res; +} + sub slurp_dir { my ($dir) = @_; @@ -276,9 +293,19 @@ sub command_like my ($stdout, $stderr); print("# Running: " . join(" ", @{$cmd}) . "\n"); my $result = IPC::Run::run $cmd, '>', \$stdout, '2>', \$stderr; - ok($result, "@$cmd exit code 0"); - is($stderr, '', "@$cmd no stderr"); + ok($result, "$test_name: exit code 0"); + is($stderr, '', "$test_name: no stderr"); like($stdout, $expected_stdout, "$test_name: matches"); } +sub command_fails_like +{ + my ($cmd, $expected_stderr, $test_name) = @_; + my ($stdout, $stderr); + print("# Running: " . join(" ", @{$cmd}) . "\n"); + my $result = IPC::Run::run $cmd, '>', \$stdout, '2>', \$stderr; + ok(!$result, "$test_name: exit code not 0"); + like($stderr, $expected_stderr, "$test_name: matches"); +} + 1; diff --git a/src/test/recovery/Makefile b/src/test/recovery/Makefile index 929071909a..9d03d337d5 100644 --- a/src/test/recovery/Makefile +++ b/src/test/recovery/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/test/recovery # -# Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/test/recovery/Makefile @@ -18,3 +18,5 @@ check: clean distclean maintainer-clean: rm -rf tmp_check + +EXTRA_INSTALL = contrib/test_decoding diff --git a/src/test/recovery/t/001_stream_rep.pl b/src/test/recovery/t/001_stream_rep.pl index fd71095f06..eef512d871 100644 --- a/src/test/recovery/t/001_stream_rep.pl +++ b/src/test/recovery/t/001_stream_rep.pl @@ -3,7 +3,7 @@ use warnings; use PostgresNode; use TestLib; -use Test::More tests => 4; +use Test::More tests => 22; # Initialize master node my $node_master = get_new_node('master'); @@ -24,6 +24,11 @@ # pg_basebackup works on a standby). $node_standby_1->backup($backup_name); +# Take a second backup of the standby while the master is offline. +$node_master->stop; +$node_standby_1->backup('my_backup_2'); +$node_master->start; + # Create second standby node linking to standby 1 my $node_standby_2 = get_new_node('standby_2'); $node_standby_2->init_from_backup($node_standby_1, $backup_name, @@ -35,16 +40,8 @@ "CREATE TABLE tab_int AS SELECT generate_series(1,1002) AS a"); # Wait for standbys to catch up -my $applname_1 = $node_standby_1->name; -my $applname_2 = $node_standby_2->name; -my $caughtup_query = -"SELECT pg_current_xlog_location() <= replay_location FROM pg_stat_replication WHERE application_name = '$applname_1';"; -$node_master->poll_query_until('postgres', $caughtup_query) - or die "Timed out while waiting for standby 1 to catch up"; -$caughtup_query = -"SELECT pg_last_xlog_replay_location() <= replay_location FROM pg_stat_replication WHERE application_name = '$applname_2';"; -$node_standby_1->poll_query_until('postgres', $caughtup_query) - or die "Timed out while waiting for standby 2 to catch up"; +$node_master->wait_for_catchup($node_standby_1, 'replay', $node_master->lsn('insert')); +$node_standby_1->wait_for_catchup($node_standby_2, 'replay', $node_standby_1->lsn('replay')); my $result = $node_standby_1->safe_psql('postgres', "SELECT count(*) FROM tab_int"); @@ -61,3 +58,106 @@ 3, 'read-only queries on standby 1'); is($node_standby_2->psql('postgres', 'INSERT INTO tab_int VALUES (1)'), 3, 'read-only queries on standby 2'); + +diag "switching to physical replication slot"; +# Switch to using a physical replication slot. We can do this without a new +# backup since physical slots can go backwards if needed. Do so on both +# standbys. Since we're going to be testing things that affect the slot state, +# also increase the standby feedback interval to ensure timely updates. +my ($slotname_1, $slotname_2) = ('standby_1', 'standby_2'); +$node_master->append_conf('postgresql.conf', "max_replication_slots = 4\n"); +$node_master->restart; +is($node_master->psql('postgres', qq[SELECT pg_create_physical_replication_slot('$slotname_1');]), 0, 'physical slot created on master'); +$node_standby_1->append_conf('recovery.conf', "primary_slot_name = $slotname_1\n"); +$node_standby_1->append_conf('postgresql.conf', "wal_receiver_status_interval = 1\n"); +$node_standby_1->append_conf('postgresql.conf', "max_replication_slots = 4\n"); +$node_standby_1->restart; +is($node_standby_1->psql('postgres', qq[SELECT pg_create_physical_replication_slot('$slotname_2');]), 0, 'physical slot created on intermediate replica'); +$node_standby_2->append_conf('recovery.conf', "primary_slot_name = $slotname_2\n"); +$node_standby_2->append_conf('postgresql.conf', "wal_receiver_status_interval = 1\n"); +$node_standby_2->restart; + +sub get_slot_xmins +{ + my ($node, $slotname) = @_; + my $slotinfo = $node->slot($slotname); + return ($slotinfo->{'xmin'}, $slotinfo->{'catalog_xmin'}); +} + +# There's no hot standby feedback and there are no logical slots on either peer +# so xmin and catalog_xmin should be null on both slots. +my ($xmin, $catalog_xmin) = get_slot_xmins($node_master, $slotname_1); +is($xmin, '', 'non-cascaded slot xmin null with no hs_feedback'); +is($catalog_xmin, '', 'non-cascaded slot xmin null with no hs_feedback'); + +($xmin, $catalog_xmin) = get_slot_xmins($node_standby_1, $slotname_2); +is($xmin, '', 'cascaded slot xmin null with no hs_feedback'); +is($catalog_xmin, '', 'cascaded slot xmin null with no hs_feedback'); + +# Replication still works? +$node_master->safe_psql('postgres', 'CREATE TABLE replayed(val integer);'); + +sub replay_check +{ + my $newval = $node_master->safe_psql('postgres', 'INSERT INTO replayed(val) SELECT coalesce(max(val),0) + 1 AS newval FROM replayed RETURNING val'); + $node_master->wait_for_catchup($node_standby_1, 'replay', $node_master->lsn('insert')); + $node_standby_1->wait_for_catchup($node_standby_2, 'replay', $node_standby_1->lsn('replay')); + $node_standby_1->safe_psql('postgres', qq[SELECT 1 FROM replayed WHERE val = $newval]) + or die "standby_1 didn't replay master value $newval"; + $node_standby_2->safe_psql('postgres', qq[SELECT 1 FROM replayed WHERE val = $newval]) + or die "standby_2 didn't replay standby_1 value $newval"; +} + +replay_check(); + +diag "enabling hot_standby_feedback"; +# Enable hs_feedback. The slot should gain an xmin. We set the status interval +# so we'll see the results promptly. +$node_standby_1->safe_psql('postgres', 'ALTER SYSTEM SET hot_standby_feedback = on;'); +$node_standby_1->reload; +$node_standby_2->safe_psql('postgres', 'ALTER SYSTEM SET hot_standby_feedback = on;'); +$node_standby_2->reload; +replay_check(); +sleep(2); + +($xmin, $catalog_xmin) = get_slot_xmins($node_master, $slotname_1); +isnt($xmin, '', 'non-cascaded slot xmin non-null with hs feedback'); +is($catalog_xmin, '', 'non-cascaded slot xmin still null with hs_feedback'); + +($xmin, $catalog_xmin) = get_slot_xmins($node_standby_1, $slotname_2); +isnt($xmin, '', 'cascaded slot xmin non-null with hs feedback'); +is($catalog_xmin, '', 'cascaded slot xmin still null with hs_feedback'); + +diag "doing some work to advance xmin"; +for my $i (10000..11000) { + $node_master->safe_psql('postgres', qq[INSERT INTO tab_int VALUES ($i);]); +} +$node_master->safe_psql('postgres', 'VACUUM;'); +$node_master->safe_psql('postgres', 'CHECKPOINT;'); + +my ($xmin2, $catalog_xmin2) = get_slot_xmins($node_master, $slotname_1); +diag "new xmin $xmin2, old xmin $xmin"; +isnt($xmin2, $xmin, 'non-cascaded slot xmin with hs feedback has changed'); +is($catalog_xmin2, '', 'non-cascaded slot xmin still null with hs_feedback unchanged'); + +($xmin2, $catalog_xmin2) = get_slot_xmins($node_standby_1, $slotname_2); +diag "new xmin $xmin2, old xmin $xmin"; +isnt($xmin2, $xmin, 'cascaded slot xmin with hs feedback has changed'); +is($catalog_xmin2, '', 'cascaded slot xmin still null with hs_feedback unchanged'); + +diag "disabling hot_standby_feedback"; +# Disable hs_feedback. Xmin should be cleared. +$node_standby_1->safe_psql('postgres', 'ALTER SYSTEM SET hot_standby_feedback = off;'); +$node_standby_1->reload; +$node_standby_2->safe_psql('postgres', 'ALTER SYSTEM SET hot_standby_feedback = off;'); +$node_standby_2->reload; +replay_check(); +sleep(2); + +($xmin, $catalog_xmin) = get_slot_xmins($node_master, $slotname_1); +is($xmin, '', 'non-cascaded slot xmin null with hs feedback reset'); +is($catalog_xmin, '', 'non-cascaded slot xmin still null with hs_feedback reset'); + +($xmin, $catalog_xmin) = get_slot_xmins($node_standby_1, $slotname_2); +is($xmin, '', 'cascaded slot xmin null with hs feedback reset'); +is($catalog_xmin, '', 'cascaded slot xmin still null with hs_feedback reset'); diff --git a/src/test/recovery/t/003_recovery_targets.pl b/src/test/recovery/t/003_recovery_targets.pl index d1f6d78388..a82545bf6f 100644 --- a/src/test/recovery/t/003_recovery_targets.pl +++ b/src/test/recovery/t/003_recovery_targets.pl @@ -3,7 +3,7 @@ use warnings; use PostgresNode; use TestLib; -use Test::More tests => 7; +use Test::More tests => 9; # Create and test a standby from given backup, with a certain # recovery target. @@ -86,6 +86,16 @@ sub test_recovery_standby $node_master->safe_psql('postgres', "SELECT pg_create_restore_point('$recovery_name');"); +# And now for a recovery target LSN +$node_master->safe_psql('postgres', + "INSERT INTO tab_int VALUES (generate_series(4001,5000))"); +my $recovery_lsn = $node_master->safe_psql('postgres', "SELECT pg_current_xlog_location()"); +my $lsn5 = + $node_master->safe_psql('postgres', "SELECT pg_current_xlog_location();"); + +$node_master->safe_psql('postgres', + "INSERT INTO tab_int VALUES (generate_series(5001,6000))"); + # Force archiving of WAL file $node_master->safe_psql('postgres', "SELECT pg_switch_xlog()"); @@ -102,6 +112,9 @@ sub test_recovery_standby @recovery_params = ("recovery_target_name = '$recovery_name'"); test_recovery_standby('name', 'standby_4', $node_master, \@recovery_params, "4000", $lsn4); +@recovery_params = ("recovery_target_lsn = '$recovery_lsn'"); +test_recovery_standby('LSN', 'standby_5', $node_master, \@recovery_params, + "5000", $lsn5); # Multiple targets # Last entry has priority (note that an array respects the order of items @@ -111,16 +124,23 @@ sub test_recovery_standby "recovery_target_xid = '$recovery_txid'", "recovery_target_time = '$recovery_time'"); test_recovery_standby('name + XID + time', - 'standby_5', $node_master, \@recovery_params, "3000", $lsn3); + 'standby_6', $node_master, \@recovery_params, "3000", $lsn3); @recovery_params = ( "recovery_target_time = '$recovery_time'", "recovery_target_name = '$recovery_name'", "recovery_target_xid = '$recovery_txid'"); test_recovery_standby('time + name + XID', - 'standby_6', $node_master, \@recovery_params, "2000", $lsn2); + 'standby_7', $node_master, \@recovery_params, "2000", $lsn2); @recovery_params = ( "recovery_target_xid = '$recovery_txid'", "recovery_target_time = '$recovery_time'", "recovery_target_name = '$recovery_name'"); test_recovery_standby('XID + time + name', - 'standby_7', $node_master, \@recovery_params, "4000", $lsn4); + 'standby_8', $node_master, \@recovery_params, "4000", $lsn4); +@recovery_params = ( + "recovery_target_xid = '$recovery_txid'", + "recovery_target_time = '$recovery_time'", + "recovery_target_name = '$recovery_name'", + "recovery_target_lsn = '$recovery_lsn'",); +test_recovery_standby('XID + time + name + LSN', + 'standby_9', $node_master, \@recovery_params, "5000", $lsn5); diff --git a/src/test/recovery/t/004_timeline_switch.pl b/src/test/recovery/t/004_timeline_switch.pl index 3ee8df2cdc..7c6587a961 100644 --- a/src/test/recovery/t/004_timeline_switch.pl +++ b/src/test/recovery/t/004_timeline_switch.pl @@ -32,14 +32,9 @@ # Create some content on master $node_master->safe_psql('postgres', "CREATE TABLE tab_int AS SELECT generate_series(1,1000) AS a"); -my $until_lsn = - $node_master->safe_psql('postgres', "SELECT pg_current_xlog_location();"); # Wait until standby has replayed enough data on standby 1 -my $caughtup_query = - "SELECT '$until_lsn'::pg_lsn <= pg_last_xlog_replay_location()"; -$node_standby_1->poll_query_until('postgres', $caughtup_query) - or die "Timed out while waiting for standby to catch up"; +$node_master->wait_for_catchup($node_standby_1, 'replay', $node_master->lsn('write')); # Stop and remove master, and promote standby 1, switching it to a new timeline $node_master->teardown_node; @@ -50,25 +45,17 @@ my $connstr_1 = $node_standby_1->connstr; $node_standby_2->append_conf( 'recovery.conf', qq( -primary_conninfo='$connstr_1' +primary_conninfo='$connstr_1 application_name=@{[$node_standby_2->name]}' standby_mode=on recovery_target_timeline='latest' )); $node_standby_2->restart; # Insert some data in standby 1 and check its presence in standby 2 -# to ensure that the timeline switch has been done. Standby 1 needs -# to exit recovery first before moving on with the test. -$node_standby_1->poll_query_until('postgres', - "SELECT pg_is_in_recovery() <> true"); +# to ensure that the timeline switch has been done. $node_standby_1->safe_psql('postgres', "INSERT INTO tab_int VALUES (generate_series(1001,2000))"); -$until_lsn = $node_standby_1->safe_psql('postgres', - "SELECT pg_current_xlog_location();"); -$caughtup_query = - "SELECT '$until_lsn'::pg_lsn <= pg_last_xlog_replay_location()"; -$node_standby_2->poll_query_until('postgres', $caughtup_query) - or die "Timed out while waiting for standby to catch up"; +$node_standby_1->wait_for_catchup($node_standby_2, 'replay', $node_standby_1->lsn('write')); my $result = $node_standby_2->safe_psql('postgres', "SELECT count(*) FROM tab_int"); diff --git a/src/test/recovery/t/006_logical_decoding.pl b/src/test/recovery/t/006_logical_decoding.pl new file mode 100644 index 0000000000..1716360a17 --- /dev/null +++ b/src/test/recovery/t/006_logical_decoding.pl @@ -0,0 +1,39 @@ +# Testing of logical decoding using SQL interface and/or pg_recvlogical +use strict; +use warnings; +use PostgresNode; +use TestLib; +use Test::More tests => 2; + +# Initialize master node +my $node_master = get_new_node('master'); +$node_master->init(allows_streaming => 1); +$node_master->append_conf( + 'postgresql.conf', qq( +wal_level = logical +)); +$node_master->start; +my $backup_name = 'master_backup'; + +$node_master->safe_psql('postgres', qq[CREATE TABLE decoding_test(x integer, y text);]); + +$node_master->safe_psql('postgres', qq[SELECT pg_create_logical_replication_slot('test_slot', 'test_decoding');]); + +$node_master->safe_psql('postgres', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(1,10) s;]); + +# Basic decoding works +my($result) = $node_master->safe_psql('postgres', qq[SELECT pg_logical_slot_get_changes('test_slot', NULL, NULL);]); +is(scalar(split /^/m, $result), 12, 'Decoding produced 12 rows inc BEGIN/COMMIT'); + +# If we immediately crash the server we might lose the progress we just made +# and replay the same changes again. But a clean shutdown should never repeat +# the same changes when we use the SQL decoding interface. +$node_master->restart('fast'); + +# There are no new writes, so the result should be empty. +$result = $node_master->safe_psql('postgres', qq[SELECT pg_logical_slot_get_changes('test_slot', NULL, NULL);]); +chomp($result); +is($result, '', 'Decoding after fast restart repeats no rows'); + +# done with the node +$node_master->stop; diff --git a/src/test/recovery/t/007_sync_rep.pl b/src/test/recovery/t/007_sync_rep.pl index 0c872263ea..e11b4289d5 100644 --- a/src/test/recovery/t/007_sync_rep.pl +++ b/src/test/recovery/t/007_sync_rep.pl @@ -3,7 +3,7 @@ use warnings; use PostgresNode; use TestLib; -use Test::More tests => 8; +use Test::More tests => 11; # Query checking sync_priority and sync_state of each standby my $check_sql = @@ -172,3 +172,34 @@ sub test_sync_state standby2|1|sync standby4|1|potential), 'potential standby found earlier in array is promoted to sync'); + +# Check that standby1 and standby2 are chosen as sync standbys +# based on their priorities. +test_sync_state( +$node_master, qq(standby1|1|sync +standby2|2|sync +standby4|0|async), +'priority-based sync replication specified by FIRST keyword', +'FIRST 2(standby1, standby2)'); + +# Check that all the listed standbys are considered as candidates +# for sync standbys in a quorum-based sync replication. +test_sync_state( +$node_master, qq(standby1|1|quorum +standby2|2|quorum +standby4|0|async), +'2 quorum and 1 async', +'ANY 2(standby1, standby2)'); + +# Start Standby3 which will be considered in 'quorum' state. +$node_standby_3->start; + +# Check that the setting of 'ANY 2(*)' chooses all standbys as +# candidates for quorum sync standbys. +test_sync_state( +$node_master, qq(standby1|1|quorum +standby2|1|quorum +standby3|1|quorum +standby4|1|quorum), +'all standbys are considered as candidates for quorum sync standbys', +'ANY 2(*)'); diff --git a/src/test/recovery/t/008_fsm_truncation.pl b/src/test/recovery/t/008_fsm_truncation.pl new file mode 100644 index 0000000000..5220611e44 --- /dev/null +++ b/src/test/recovery/t/008_fsm_truncation.pl @@ -0,0 +1,92 @@ +# Test WAL replay of FSM changes. +# +# FSM changes don't normally need to be WAL-logged, except for truncation. +# The FSM mustn't return a page that doesn't exist (anymore). +use strict; +use warnings; + +use PostgresNode; +use TestLib; +use Test::More tests => 1; + +my $node_master = get_new_node('master'); +$node_master->init(allows_streaming => 1); + +$node_master->append_conf('postgresql.conf', qq{ +fsync = on +wal_log_hints = on +max_prepared_transactions = 5 +autovacuum = off +}); + +# Create a master node and its standby, initializing both with some data +# at the same time. +$node_master->start; + +$node_master->backup('master_backup'); +my $node_standby = get_new_node('standby'); +$node_standby->init_from_backup($node_master, 'master_backup', + has_streaming => 1); +$node_standby->start; + +$node_master->psql('postgres', qq{ +create table testtab (a int, b char(100)); +insert into testtab select generate_series(1,1000), 'foo'; +insert into testtab select generate_series(1,1000), 'foo'; +delete from testtab where ctid > '(8,0)'; +}); + +# Take a lock on the table to prevent following vacuum from truncating it +$node_master->psql('postgres', qq{ +begin; +lock table testtab in row share mode; +prepare transaction 'p1'; +}); + +# Vacuum, update FSM without truncation +$node_master->psql('postgres', 'vacuum verbose testtab'); + +# Force a checkpoint +$node_master->psql('postgres', 'checkpoint'); + +# Now do some more insert/deletes, another vacuum to ensure full-page writes +# are done +$node_master->psql('postgres', qq{ +insert into testtab select generate_series(1,1000), 'foo'; +delete from testtab where ctid > '(8,0)'; +vacuum verbose testtab; +}); + +# Ensure all buffers are now clean on the standby +$node_standby->psql('postgres', 'checkpoint'); + +# Release the lock, vacuum again which should lead to truncation +$node_master->psql('postgres', qq{ +rollback prepared 'p1'; +vacuum verbose testtab; +}); + +$node_master->psql('postgres', 'checkpoint'); +my $until_lsn = + $node_master->safe_psql('postgres', "SELECT pg_current_xlog_location();"); + +# Wait long enough for standby to receive and apply all WAL +my $caughtup_query = + "SELECT '$until_lsn'::pg_lsn <= pg_last_xlog_replay_location()"; +$node_standby->poll_query_until('postgres', $caughtup_query) + or die "Timed out while waiting for standby to catch up"; + +# Promote the standby +$node_standby->promote; +$node_standby->poll_query_until('postgres', + "SELECT NOT pg_is_in_recovery()") + or die "Timed out while waiting for promotion of standby"; +$node_standby->psql('postgres', 'checkpoint'); + +# Restart to discard in-memory copy of FSM +$node_standby->restart; + +# Insert should work on standby +is($node_standby->psql('postgres', + qq{insert into testtab select generate_series(1,1000), 'foo';}), + 0, 'INSERT succeeds with truncated relation FSM'); diff --git a/src/test/regress/GNUmakefile b/src/test/regress/GNUmakefile index 6a275cb729..b923ea1420 100644 --- a/src/test/regress/GNUmakefile +++ b/src/test/regress/GNUmakefile @@ -3,7 +3,7 @@ # GNUmakefile-- # Makefile for src/test/regress (the regression tests) # -# Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/test/regress/GNUmakefile @@ -36,7 +36,7 @@ EXTRADEFS = '-DHOST_TUPLE="$(host_tuple)"' \ all: pg_regress$(X) -pg_regress$(X): pg_regress.o pg_regress_main.o $(WIN32RES) | submake-libpgport submake-generated-headers +pg_regress$(X): pg_regress.o pg_regress_main.o $(WIN32RES) | submake-libpgport $(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@ # dependencies ensure that path changes propagate @@ -65,6 +65,8 @@ include $(top_srcdir)/src/Makefile.shlib all: all-lib +$(OBJS): | submake-generated-headers + # Test input and expected files. These are created by pg_regress itself, so we # don't have a rule to create them. We do need rules to clean them however. input_files = $(patsubst $(srcdir)/input/%.source,sql/%.sql, $(wildcard $(srcdir)/input/*.source)) diff --git a/src/test/regress/expected/aggregates.out b/src/test/regress/expected/aggregates.out index 14646c6397..0ff80620cc 100644 --- a/src/test/regress/expected/aggregates.out +++ b/src/test/regress/expected/aggregates.out @@ -366,6 +366,81 @@ from tenk1 o; 9999 (1 row) +-- Test handling of Params within aggregate arguments in hashed aggregation. +-- Per bug report from Jeevan Chalke. +explain (verbose, costs off) +select s1, s2, sm +from generate_series(1, 3) s1, + lateral (select s2, sum(s1 + s2) sm + from generate_series(1, 3) s2 group by s2) ss +order by 1, 2; + QUERY PLAN +------------------------------------------------------------------ + Sort + Output: s1.s1, s2.s2, (sum((s1.s1 + s2.s2))) + Sort Key: s1.s1, s2.s2 + -> Nested Loop + Output: s1.s1, s2.s2, (sum((s1.s1 + s2.s2))) + -> Function Scan on pg_catalog.generate_series s1 + Output: s1.s1 + Function Call: generate_series(1, 3) + -> HashAggregate + Output: s2.s2, sum((s1.s1 + s2.s2)) + Group Key: s2.s2 + -> Function Scan on pg_catalog.generate_series s2 + Output: s2.s2 + Function Call: generate_series(1, 3) +(14 rows) + +select s1, s2, sm +from generate_series(1, 3) s1, + lateral (select s2, sum(s1 + s2) sm + from generate_series(1, 3) s2 group by s2) ss +order by 1, 2; + s1 | s2 | sm +----+----+---- + 1 | 1 | 2 + 1 | 2 | 3 + 1 | 3 | 4 + 2 | 1 | 3 + 2 | 2 | 4 + 2 | 3 | 5 + 3 | 1 | 4 + 3 | 2 | 5 + 3 | 3 | 6 +(9 rows) + +explain (verbose, costs off) +select array(select sum(x+y) s + from generate_series(1,3) y group by y order by s) + from generate_series(1,3) x; + QUERY PLAN +------------------------------------------------------------------- + Function Scan on pg_catalog.generate_series x + Output: (SubPlan 1) + Function Call: generate_series(1, 3) + SubPlan 1 + -> Sort + Output: (sum((x.x + y.y))), y.y + Sort Key: (sum((x.x + y.y))) + -> HashAggregate + Output: sum((x.x + y.y)), y.y + Group Key: y.y + -> Function Scan on pg_catalog.generate_series y + Output: y.y + Function Call: generate_series(1, 3) +(13 rows) + +select array(select sum(x+y) s + from generate_series(1,3) y group by y order by s) + from generate_series(1,3) x; + array +--------- + {2,3,4} + {3,4,5} + {4,5,6} +(3 rows) + -- -- test for bitwise integer aggregates -- @@ -747,8 +822,9 @@ explain (costs off) -> Limit -> Index Only Scan Backward using tenk1_unique2 on tenk1 Index Cond: (unique2 IS NOT NULL) - -> Result -(7 rows) + -> ProjectSet + -> Result +(8 rows) select max(unique2), generate_series(1,3) as g from tenk1 order by g desc; max | g @@ -1741,6 +1817,15 @@ NOTICE: avg_transfn called with 3 2 | 4 (1 row) +-- same as previous one, but with DISTINCT, which requires sorting the input. +select my_avg(distinct one),my_sum(distinct one) from (values(1),(3),(1)) t(one); +NOTICE: avg_transfn called with 1 +NOTICE: avg_transfn called with 3 + my_avg | my_sum +--------+-------- + 2 | 4 +(1 row) + -- shouldn't share states due to the distinctness not matching. select my_avg(distinct one),my_sum(one) from (values(1),(3)) t(one); NOTICE: avg_transfn called with 1 diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 3232cda023..76b9c2d372 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -180,12 +180,12 @@ ALTER TABLE onek DROP CONSTRAINT onek_unique1_constraint_foo; -- renaming constraints vs. inheritance CREATE TABLE constraint_rename_test (a int CONSTRAINT con1 CHECK (a > 0), b int, c int); \d constraint_rename_test -Table "public.constraint_rename_test" - Column | Type | Modifiers ---------+---------+----------- - a | integer | - b | integer | - c | integer | + Table "public.constraint_rename_test" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + b | integer | | | + c | integer | | | Check constraints: "con1" CHECK (a > 0) @@ -193,13 +193,13 @@ CREATE TABLE constraint_rename_test2 (a int CONSTRAINT con1 CHECK (a > 0), d int NOTICE: merging column "a" with inherited definition NOTICE: merging constraint "con1" with inherited definition \d constraint_rename_test2 -Table "public.constraint_rename_test2" - Column | Type | Modifiers ---------+---------+----------- - a | integer | - b | integer | - c | integer | - d | integer | + Table "public.constraint_rename_test2" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + b | integer | | | + c | integer | | | + d | integer | | | Check constraints: "con1" CHECK (a > 0) Inherits: constraint_rename_test @@ -210,24 +210,24 @@ ALTER TABLE ONLY constraint_rename_test RENAME CONSTRAINT con1 TO con1foo; -- fa ERROR: inherited constraint "con1" must be renamed in child tables too ALTER TABLE constraint_rename_test RENAME CONSTRAINT con1 TO con1foo; -- ok \d constraint_rename_test -Table "public.constraint_rename_test" - Column | Type | Modifiers ---------+---------+----------- - a | integer | - b | integer | - c | integer | + Table "public.constraint_rename_test" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + b | integer | | | + c | integer | | | Check constraints: "con1foo" CHECK (a > 0) Number of child tables: 1 (Use \d+ to list them.) \d constraint_rename_test2 -Table "public.constraint_rename_test2" - Column | Type | Modifiers ---------+---------+----------- - a | integer | - b | integer | - c | integer | - d | integer | + Table "public.constraint_rename_test2" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + b | integer | | | + c | integer | | | + d | integer | | | Check constraints: "con1foo" CHECK (a > 0) Inherits: constraint_rename_test @@ -236,25 +236,25 @@ ALTER TABLE constraint_rename_test ADD CONSTRAINT con2 CHECK (b > 0) NO INHERIT; ALTER TABLE ONLY constraint_rename_test RENAME CONSTRAINT con2 TO con2foo; -- ok ALTER TABLE constraint_rename_test RENAME CONSTRAINT con2foo TO con2bar; -- ok \d constraint_rename_test -Table "public.constraint_rename_test" - Column | Type | Modifiers ---------+---------+----------- - a | integer | - b | integer | - c | integer | + Table "public.constraint_rename_test" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + b | integer | | | + c | integer | | | Check constraints: "con1foo" CHECK (a > 0) "con2bar" CHECK (b > 0) NO INHERIT Number of child tables: 1 (Use \d+ to list them.) \d constraint_rename_test2 -Table "public.constraint_rename_test2" - Column | Type | Modifiers ---------+---------+----------- - a | integer | - b | integer | - c | integer | - d | integer | + Table "public.constraint_rename_test2" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + b | integer | | | + c | integer | | | + d | integer | | | Check constraints: "con1foo" CHECK (a > 0) Inherits: constraint_rename_test @@ -262,12 +262,12 @@ Inherits: constraint_rename_test ALTER TABLE constraint_rename_test ADD CONSTRAINT con3 PRIMARY KEY (a); ALTER TABLE constraint_rename_test RENAME CONSTRAINT con3 TO con3foo; -- ok \d constraint_rename_test -Table "public.constraint_rename_test" - Column | Type | Modifiers ---------+---------+----------- - a | integer | not null - b | integer | - c | integer | + Table "public.constraint_rename_test" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | not null | + b | integer | | | + c | integer | | | Indexes: "con3foo" PRIMARY KEY, btree (a) Check constraints: @@ -276,13 +276,13 @@ Check constraints: Number of child tables: 1 (Use \d+ to list them.) \d constraint_rename_test2 -Table "public.constraint_rename_test2" - Column | Type | Modifiers ---------+---------+----------- - a | integer | - b | integer | - c | integer | - d | integer | + Table "public.constraint_rename_test2" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + b | integer | | | + c | integer | | | + d | integer | | | Check constraints: "con1foo" CHECK (a > 0) Inherits: constraint_rename_test @@ -383,10 +383,10 @@ set constraint_exclusion TO 'partition'; create table nv_parent (d date, check (false) no inherit not valid); -- not valid constraint added at creation time should automatically become valid \d nv_parent - Table "public.nv_parent" - Column | Type | Modifiers ---------+------+----------- - d | date | + Table "public.nv_parent" + Column | Type | Collation | Nullable | Default +--------+------+-----------+----------+--------- + d | date | | | Check constraints: "nv_parent_check" CHECK (false) NO INHERIT @@ -450,10 +450,10 @@ explain (costs off) select * from nv_parent where d between '2009-08-01'::date a -- add an inherited NOT VALID constraint alter table nv_parent add check (d between '2001-01-01'::date and '2099-12-31'::date) not valid; \d nv_child_2009 -Table "public.nv_child_2009" - Column | Type | Modifiers ---------+------+----------- - d | date | + Table "public.nv_child_2009" + Column | Type | Collation | Nullable | Default +--------+------+-----------+----------+--------- + d | date | | | Check constraints: "nv_child_2009_d_check" CHECK (d >= '01-01-2009'::date AND d <= '12-31-2009'::date) "nv_parent_d_check" CHECK (d >= '01-01-2001'::date AND d <= '12-31-2099'::date) NOT VALID @@ -534,6 +534,66 @@ ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest2, ftest1) references pktable(ptest1, ptest2); ERROR: foreign key constraint "fktable_ftest2_fkey" cannot be implemented DETAIL: Key columns "ftest2" and "ptest1" are of incompatible types: inet and integer. +DROP TABLE FKTABLE; +DROP TABLE PKTABLE; +-- Test that ALTER CONSTRAINT updates trigger deferrability properly +CREATE TEMP TABLE PKTABLE (ptest1 int primary key); +CREATE TEMP TABLE FKTABLE (ftest1 int); +ALTER TABLE FKTABLE ADD CONSTRAINT fknd FOREIGN KEY(ftest1) REFERENCES pktable + ON DELETE CASCADE ON UPDATE NO ACTION NOT DEFERRABLE; +ALTER TABLE FKTABLE ADD CONSTRAINT fkdd FOREIGN KEY(ftest1) REFERENCES pktable + ON DELETE CASCADE ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED; +ALTER TABLE FKTABLE ADD CONSTRAINT fkdi FOREIGN KEY(ftest1) REFERENCES pktable + ON DELETE CASCADE ON UPDATE NO ACTION DEFERRABLE INITIALLY IMMEDIATE; +ALTER TABLE FKTABLE ADD CONSTRAINT fknd2 FOREIGN KEY(ftest1) REFERENCES pktable + ON DELETE CASCADE ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED; +ALTER TABLE FKTABLE ALTER CONSTRAINT fknd2 NOT DEFERRABLE; +ALTER TABLE FKTABLE ADD CONSTRAINT fkdd2 FOREIGN KEY(ftest1) REFERENCES pktable + ON DELETE CASCADE ON UPDATE NO ACTION NOT DEFERRABLE; +ALTER TABLE FKTABLE ALTER CONSTRAINT fkdd2 DEFERRABLE INITIALLY DEFERRED; +ALTER TABLE FKTABLE ADD CONSTRAINT fkdi2 FOREIGN KEY(ftest1) REFERENCES pktable + ON DELETE CASCADE ON UPDATE NO ACTION NOT DEFERRABLE; +ALTER TABLE FKTABLE ALTER CONSTRAINT fkdi2 DEFERRABLE INITIALLY IMMEDIATE; +SELECT conname, tgfoid::regproc, tgtype, tgdeferrable, tginitdeferred +FROM pg_trigger JOIN pg_constraint con ON con.oid = tgconstraint +WHERE tgrelid = 'pktable'::regclass +ORDER BY 1,2,3; + conname | tgfoid | tgtype | tgdeferrable | tginitdeferred +---------+------------------------+--------+--------------+---------------- + fkdd | "RI_FKey_cascade_del" | 9 | f | f + fkdd | "RI_FKey_noaction_upd" | 17 | t | t + fkdd2 | "RI_FKey_cascade_del" | 9 | f | f + fkdd2 | "RI_FKey_noaction_upd" | 17 | t | t + fkdi | "RI_FKey_cascade_del" | 9 | f | f + fkdi | "RI_FKey_noaction_upd" | 17 | t | f + fkdi2 | "RI_FKey_cascade_del" | 9 | f | f + fkdi2 | "RI_FKey_noaction_upd" | 17 | t | f + fknd | "RI_FKey_cascade_del" | 9 | f | f + fknd | "RI_FKey_noaction_upd" | 17 | f | f + fknd2 | "RI_FKey_cascade_del" | 9 | f | f + fknd2 | "RI_FKey_noaction_upd" | 17 | f | f +(12 rows) + +SELECT conname, tgfoid::regproc, tgtype, tgdeferrable, tginitdeferred +FROM pg_trigger JOIN pg_constraint con ON con.oid = tgconstraint +WHERE tgrelid = 'fktable'::regclass +ORDER BY 1,2,3; + conname | tgfoid | tgtype | tgdeferrable | tginitdeferred +---------+---------------------+--------+--------------+---------------- + fkdd | "RI_FKey_check_ins" | 5 | t | t + fkdd | "RI_FKey_check_upd" | 17 | t | t + fkdd2 | "RI_FKey_check_ins" | 5 | t | t + fkdd2 | "RI_FKey_check_upd" | 17 | t | t + fkdi | "RI_FKey_check_ins" | 5 | t | f + fkdi | "RI_FKey_check_upd" | 17 | t | f + fkdi2 | "RI_FKey_check_ins" | 5 | t | f + fkdi2 | "RI_FKey_check_upd" | 17 | t | f + fknd | "RI_FKey_check_ins" | 5 | f | f + fknd | "RI_FKey_check_upd" | 17 | f | f + fknd2 | "RI_FKey_check_ins" | 5 | f | f + fknd2 | "RI_FKey_check_upd" | 17 | f | f +(12 rows) + -- temp tables should go away by themselves, need not drop them. -- test check constraint adding create table atacc1 ( test int ); @@ -1844,21 +1904,21 @@ where oid = 'test_storage'::regclass; CREATE TABLE test_inh_check (a float check (a > 10.2), b float); CREATE TABLE test_inh_check_child() INHERITS(test_inh_check); \d test_inh_check - Table "public.test_inh_check" - Column | Type | Modifiers ---------+------------------+----------- - a | double precision | - b | double precision | + Table "public.test_inh_check" + Column | Type | Collation | Nullable | Default +--------+------------------+-----------+----------+--------- + a | double precision | | | + b | double precision | | | Check constraints: "test_inh_check_a_check" CHECK (a > 10.2::double precision) Number of child tables: 1 (Use \d+ to list them.) \d test_inh_check_child - Table "public.test_inh_check_child" - Column | Type | Modifiers ---------+------------------+----------- - a | double precision | - b | double precision | + Table "public.test_inh_check_child" + Column | Type | Collation | Nullable | Default +--------+------------------+-----------+----------+--------- + a | double precision | | | + b | double precision | | | Check constraints: "test_inh_check_a_check" CHECK (a > 10.2::double precision) Inherits: test_inh_check @@ -1875,21 +1935,21 @@ select relname, conname, coninhcount, conislocal, connoinherit ALTER TABLE test_inh_check ALTER COLUMN a TYPE numeric; \d test_inh_check - Table "public.test_inh_check" - Column | Type | Modifiers ---------+------------------+----------- - a | numeric | - b | double precision | + Table "public.test_inh_check" + Column | Type | Collation | Nullable | Default +--------+------------------+-----------+----------+--------- + a | numeric | | | + b | double precision | | | Check constraints: "test_inh_check_a_check" CHECK (a::double precision > 10.2::double precision) Number of child tables: 1 (Use \d+ to list them.) \d test_inh_check_child - Table "public.test_inh_check_child" - Column | Type | Modifiers ---------+------------------+----------- - a | numeric | - b | double precision | + Table "public.test_inh_check_child" + Column | Type | Collation | Nullable | Default +--------+------------------+-----------+----------+--------- + a | numeric | | | + b | double precision | | | Check constraints: "test_inh_check_a_check" CHECK (a::double precision > 10.2::double precision) Inherits: test_inh_check @@ -1911,11 +1971,11 @@ ALTER TABLE test_inh_check_child ADD CONSTRAINT bmerged CHECK (b > 1); ALTER TABLE test_inh_check ADD CONSTRAINT bmerged CHECK (b > 1); NOTICE: merging constraint "bmerged" with inherited definition \d test_inh_check - Table "public.test_inh_check" - Column | Type | Modifiers ---------+------------------+----------- - a | numeric | - b | double precision | + Table "public.test_inh_check" + Column | Type | Collation | Nullable | Default +--------+------------------+-----------+----------+--------- + a | numeric | | | + b | double precision | | | Check constraints: "bmerged" CHECK (b > 1::double precision) "bnoinherit" CHECK (b > 100::double precision) NO INHERIT @@ -1923,11 +1983,11 @@ Check constraints: Number of child tables: 1 (Use \d+ to list them.) \d test_inh_check_child - Table "public.test_inh_check_child" - Column | Type | Modifiers ---------+------------------+----------- - a | numeric | - b | double precision | + Table "public.test_inh_check_child" + Column | Type | Collation | Nullable | Default +--------+------------------+-----------+----------+--------- + a | numeric | | | + b | double precision | | | Check constraints: "blocal" CHECK (b < 1000::double precision) "bmerged" CHECK (b > 1::double precision) @@ -1951,11 +2011,11 @@ select relname, conname, coninhcount, conislocal, connoinherit ALTER TABLE test_inh_check ALTER COLUMN b TYPE numeric; NOTICE: merging constraint "bmerged" with inherited definition \d test_inh_check -Table "public.test_inh_check" - Column | Type | Modifiers ---------+---------+----------- - a | numeric | - b | numeric | + Table "public.test_inh_check" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | numeric | | | + b | numeric | | | Check constraints: "bmerged" CHECK (b::double precision > 1::double precision) "bnoinherit" CHECK (b::double precision > 100::double precision) NO INHERIT @@ -1963,11 +2023,11 @@ Check constraints: Number of child tables: 1 (Use \d+ to list them.) \d test_inh_check_child -Table "public.test_inh_check_child" - Column | Type | Modifiers ---------+---------+----------- - a | numeric | - b | numeric | + Table "public.test_inh_check_child" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | numeric | | | + b | numeric | | | Check constraints: "blocal" CHECK (b::double precision < 1000::double precision) "bmerged" CHECK (b::double precision > 1::double precision) @@ -1988,6 +2048,28 @@ select relname, conname, coninhcount, conislocal, connoinherit test_inh_check_child | test_inh_check_a_check | 1 | f | f (6 rows) +-- ALTER COLUMN TYPE with different schema in children +-- Bug at https://postgr.es/m/20170102225618.GA10071@telsasoft.com +CREATE TABLE test_type_diff (f1 int); +CREATE TABLE test_type_diff_c (extra smallint) INHERITS (test_type_diff); +ALTER TABLE test_type_diff ADD COLUMN f2 int; +INSERT INTO test_type_diff_c VALUES (1, 2, 3); +ALTER TABLE test_type_diff ALTER COLUMN f2 TYPE bigint USING f2::bigint; +CREATE TABLE test_type_diff2 (int_two int2, int_four int4, int_eight int8); +CREATE TABLE test_type_diff2_c1 (int_four int4, int_eight int8, int_two int2); +CREATE TABLE test_type_diff2_c2 (int_eight int8, int_two int2, int_four int4); +CREATE TABLE test_type_diff2_c3 (int_two int2, int_four int4, int_eight int8); +ALTER TABLE test_type_diff2_c1 INHERIT test_type_diff2; +ALTER TABLE test_type_diff2_c2 INHERIT test_type_diff2; +ALTER TABLE test_type_diff2_c3 INHERIT test_type_diff2; +INSERT INTO test_type_diff2_c1 VALUES (1, 2, 3); +INSERT INTO test_type_diff2_c2 VALUES (4, 5, 6); +INSERT INTO test_type_diff2_c3 VALUES (7, 8, 9); +ALTER TABLE test_type_diff2 ALTER COLUMN int_four TYPE int8 USING int_four::int8; +-- whole-row references are disallowed +ALTER TABLE test_type_diff2 ALTER COLUMN int_four TYPE int4 USING (pg_column_size(test_type_diff2)); +ERROR: cannot convert whole-row table reference +DETAIL: USING expression contains a whole-row table reference. -- check for rollback of ANALYZE corrupting table property flags (bug #11638) CREATE TABLE check_fk_presence_1 (id int PRIMARY KEY, t text); CREATE TABLE check_fk_presence_2 (id int REFERENCES check_fk_presence_1, t text); @@ -1996,11 +2078,11 @@ ALTER TABLE check_fk_presence_2 DROP CONSTRAINT check_fk_presence_2_id_fkey; ANALYZE check_fk_presence_2; ROLLBACK; \d check_fk_presence_2 -Table "public.check_fk_presence_2" - Column | Type | Modifiers ---------+---------+----------- - id | integer | - t | text | + Table "public.check_fk_presence_2" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + id | integer | | | + t | text | | | Foreign-key constraints: "check_fk_presence_2_id_fkey" FOREIGN KEY (id) REFERENCES check_fk_presence_1(id) @@ -2354,45 +2436,45 @@ drop cascades to text search dictionary dict -- CREATE TYPE test_type AS (a int); \d test_type -Composite type "public.test_type" - Column | Type | Modifiers ---------+---------+----------- - a | integer | + Composite type "public.test_type" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | ALTER TYPE nosuchtype ADD ATTRIBUTE b text; -- fails ERROR: relation "nosuchtype" does not exist ALTER TYPE test_type ADD ATTRIBUTE b text; \d test_type -Composite type "public.test_type" - Column | Type | Modifiers ---------+---------+----------- - a | integer | - b | text | + Composite type "public.test_type" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + b | text | | | ALTER TYPE test_type ADD ATTRIBUTE b text; -- fails ERROR: column "b" of relation "test_type" already exists ALTER TYPE test_type ALTER ATTRIBUTE b SET DATA TYPE varchar; \d test_type - Composite type "public.test_type" - Column | Type | Modifiers ---------+-------------------+----------- - a | integer | - b | character varying | + Composite type "public.test_type" + Column | Type | Collation | Nullable | Default +--------+-------------------+-----------+----------+--------- + a | integer | | | + b | character varying | | | ALTER TYPE test_type ALTER ATTRIBUTE b SET DATA TYPE integer; \d test_type -Composite type "public.test_type" - Column | Type | Modifiers ---------+---------+----------- - a | integer | - b | integer | + Composite type "public.test_type" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + b | integer | | | ALTER TYPE test_type DROP ATTRIBUTE b; \d test_type -Composite type "public.test_type" - Column | Type | Modifiers ---------+---------+----------- - a | integer | + Composite type "public.test_type" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | ALTER TYPE test_type DROP ATTRIBUTE c; -- fails ERROR: column "c" of relation "test_type" does not exist @@ -2400,19 +2482,19 @@ ALTER TYPE test_type DROP ATTRIBUTE IF EXISTS c; NOTICE: column "c" of relation "test_type" does not exist, skipping ALTER TYPE test_type DROP ATTRIBUTE a, ADD ATTRIBUTE d boolean; \d test_type -Composite type "public.test_type" - Column | Type | Modifiers ---------+---------+----------- - d | boolean | + Composite type "public.test_type" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + d | boolean | | | ALTER TYPE test_type RENAME ATTRIBUTE a TO aa; ERROR: column "a" does not exist ALTER TYPE test_type RENAME ATTRIBUTE d TO dd; \d test_type -Composite type "public.test_type" - Column | Type | Modifiers ---------+---------+----------- - dd | boolean | + Composite type "public.test_type" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + dd | boolean | | | DROP TYPE test_type; CREATE TYPE test_type1 AS (a int, b text); @@ -2423,18 +2505,18 @@ CREATE TYPE test_type2 AS (a int, b text); CREATE TABLE test_tbl2 OF test_type2; CREATE TABLE test_tbl2_subclass () INHERITS (test_tbl2); \d test_type2 -Composite type "public.test_type2" - Column | Type | Modifiers ---------+---------+----------- - a | integer | - b | text | + Composite type "public.test_type2" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + b | text | | | \d test_tbl2 - Table "public.test_tbl2" - Column | Type | Modifiers ---------+---------+----------- - a | integer | - b | text | + Table "public.test_tbl2" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + b | text | | | Number of child tables: 1 (Use \d+ to list them.) Typed table of type: test_type2 @@ -2443,20 +2525,20 @@ ERROR: cannot alter type "test_type2" because it is the type of a typed table HINT: Use ALTER ... CASCADE to alter the typed tables too. ALTER TYPE test_type2 ADD ATTRIBUTE c text CASCADE; \d test_type2 -Composite type "public.test_type2" - Column | Type | Modifiers ---------+---------+----------- - a | integer | - b | text | - c | text | + Composite type "public.test_type2" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + b | text | | | + c | text | | | \d test_tbl2 - Table "public.test_tbl2" - Column | Type | Modifiers ---------+---------+----------- - a | integer | - b | text | - c | text | + Table "public.test_tbl2" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + b | text | | | + c | text | | | Number of child tables: 1 (Use \d+ to list them.) Typed table of type: test_type2 @@ -2465,20 +2547,20 @@ ERROR: cannot alter type "test_type2" because it is the type of a typed table HINT: Use ALTER ... CASCADE to alter the typed tables too. ALTER TYPE test_type2 ALTER ATTRIBUTE b TYPE varchar CASCADE; \d test_type2 - Composite type "public.test_type2" - Column | Type | Modifiers ---------+-------------------+----------- - a | integer | - b | character varying | - c | text | + Composite type "public.test_type2" + Column | Type | Collation | Nullable | Default +--------+-------------------+-----------+----------+--------- + a | integer | | | + b | character varying | | | + c | text | | | \d test_tbl2 - Table "public.test_tbl2" - Column | Type | Modifiers ---------+-------------------+----------- - a | integer | - b | character varying | - c | text | + Table "public.test_tbl2" + Column | Type | Collation | Nullable | Default +--------+-------------------+-----------+----------+--------- + a | integer | | | + b | character varying | | | + c | text | | | Number of child tables: 1 (Use \d+ to list them.) Typed table of type: test_type2 @@ -2487,18 +2569,18 @@ ERROR: cannot alter type "test_type2" because it is the type of a typed table HINT: Use ALTER ... CASCADE to alter the typed tables too. ALTER TYPE test_type2 DROP ATTRIBUTE b CASCADE; \d test_type2 -Composite type "public.test_type2" - Column | Type | Modifiers ---------+---------+----------- - a | integer | - c | text | + Composite type "public.test_type2" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + c | text | | | \d test_tbl2 - Table "public.test_tbl2" - Column | Type | Modifiers ---------+---------+----------- - a | integer | - c | text | + Table "public.test_tbl2" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + c | text | | | Number of child tables: 1 (Use \d+ to list them.) Typed table of type: test_type2 @@ -2507,27 +2589,27 @@ ERROR: cannot alter type "test_type2" because it is the type of a typed table HINT: Use ALTER ... CASCADE to alter the typed tables too. ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa CASCADE; \d test_type2 -Composite type "public.test_type2" - Column | Type | Modifiers ---------+---------+----------- - aa | integer | - c | text | + Composite type "public.test_type2" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + aa | integer | | | + c | text | | | \d test_tbl2 - Table "public.test_tbl2" - Column | Type | Modifiers ---------+---------+----------- - aa | integer | - c | text | + Table "public.test_tbl2" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + aa | integer | | | + c | text | | | Number of child tables: 1 (Use \d+ to list them.) Typed table of type: test_type2 \d test_tbl2_subclass -Table "public.test_tbl2_subclass" - Column | Type | Modifiers ---------+---------+----------- - aa | integer | - c | text | + Table "public.test_tbl2_subclass" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + aa | integer | | | + c | text | | | Inherits: test_tbl2 DROP TABLE test_tbl2_subclass; @@ -2571,11 +2653,11 @@ CREATE TYPE tt_t1 AS (x int, y numeric(8,2)); ALTER TABLE tt7 OF tt_t1; -- reassign an already-typed table ALTER TABLE tt7 NOT OF; \d tt7 - Table "public.tt7" - Column | Type | Modifiers ---------+--------------+----------- - x | integer | - y | numeric(8,2) | + Table "public.tt7" + Column | Type | Collation | Nullable | Default +--------+--------------+-----------+----------+--------- + x | integer | | | + y | numeric(8,2) | | | -- make sure we can drop a constraint on the parent but it remains on the child CREATE TABLE test_drop_constr_parent (c text CHECK (c IS NOT NULL)); @@ -2611,11 +2693,11 @@ ALTER TABLE IF EXISTS tt8 ALTER COLUMN f SET DEFAULT 0; ALTER TABLE IF EXISTS tt8 RENAME COLUMN f TO f1; ALTER TABLE IF EXISTS tt8 SET SCHEMA alter2; \d alter2.tt8 - Table "alter2.tt8" - Column | Type | Modifiers ---------+---------+-------------------- - a | integer | - f1 | integer | not null default 0 + Table "alter2.tt8" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + f1 | integer | | not null | 0 Indexes: "xxx" PRIMARY KEY, btree (f1) Check constraints: @@ -2828,62 +2910,62 @@ DROP TABLE logged1; -- test ADD COLUMN IF NOT EXISTS CREATE TABLE test_add_column(c1 integer); \d test_add_column -Table "public.test_add_column" - Column | Type | Modifiers ---------+---------+----------- - c1 | integer | + Table "public.test_add_column" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + c1 | integer | | | ALTER TABLE test_add_column ADD COLUMN c2 integer; \d test_add_column -Table "public.test_add_column" - Column | Type | Modifiers ---------+---------+----------- - c1 | integer | - c2 | integer | + Table "public.test_add_column" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + c1 | integer | | | + c2 | integer | | | ALTER TABLE test_add_column ADD COLUMN c2 integer; -- fail because c2 already exists ERROR: column "c2" of relation "test_add_column" already exists \d test_add_column -Table "public.test_add_column" - Column | Type | Modifiers ---------+---------+----------- - c1 | integer | - c2 | integer | + Table "public.test_add_column" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + c1 | integer | | | + c2 | integer | | | ALTER TABLE test_add_column ADD COLUMN IF NOT EXISTS c2 integer; -- skipping because c2 already exists NOTICE: column "c2" of relation "test_add_column" already exists, skipping \d test_add_column -Table "public.test_add_column" - Column | Type | Modifiers ---------+---------+----------- - c1 | integer | - c2 | integer | + Table "public.test_add_column" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + c1 | integer | | | + c2 | integer | | | ALTER TABLE test_add_column ADD COLUMN c2 integer, -- fail because c2 already exists ADD COLUMN c3 integer; ERROR: column "c2" of relation "test_add_column" already exists \d test_add_column -Table "public.test_add_column" - Column | Type | Modifiers ---------+---------+----------- - c1 | integer | - c2 | integer | + Table "public.test_add_column" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + c1 | integer | | | + c2 | integer | | | ALTER TABLE test_add_column ADD COLUMN IF NOT EXISTS c2 integer, -- skipping because c2 already exists ADD COLUMN c3 integer; -- fail because c3 already exists NOTICE: column "c2" of relation "test_add_column" already exists, skipping \d test_add_column -Table "public.test_add_column" - Column | Type | Modifiers ---------+---------+----------- - c1 | integer | - c2 | integer | - c3 | integer | + Table "public.test_add_column" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + c1 | integer | | | + c2 | integer | | | + c3 | integer | | | ALTER TABLE test_add_column ADD COLUMN IF NOT EXISTS c2 integer, -- skipping because c2 already exists @@ -2891,12 +2973,12 @@ ALTER TABLE test_add_column NOTICE: column "c2" of relation "test_add_column" already exists, skipping NOTICE: column "c3" of relation "test_add_column" already exists, skipping \d test_add_column -Table "public.test_add_column" - Column | Type | Modifiers ---------+---------+----------- - c1 | integer | - c2 | integer | - c3 | integer | + Table "public.test_add_column" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + c1 | integer | | | + c2 | integer | | | + c3 | integer | | | ALTER TABLE test_add_column ADD COLUMN IF NOT EXISTS c2 integer, -- skipping because c2 already exists @@ -2905,12 +2987,380 @@ ALTER TABLE test_add_column NOTICE: column "c2" of relation "test_add_column" already exists, skipping NOTICE: column "c3" of relation "test_add_column" already exists, skipping \d test_add_column -Table "public.test_add_column" - Column | Type | Modifiers ---------+---------+----------- - c1 | integer | - c2 | integer | - c3 | integer | - c4 | integer | + Table "public.test_add_column" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + c1 | integer | | | + c2 | integer | | | + c3 | integer | | | + c4 | integer | | | DROP TABLE test_add_column; +-- unsupported constraint types for partitioned tables +CREATE TABLE partitioned ( + a int, + b int +) PARTITION BY RANGE (a, (a+b+1)); +ALTER TABLE partitioned ADD UNIQUE (a); +ERROR: unique constraints are not supported on partitioned tables +LINE 1: ALTER TABLE partitioned ADD UNIQUE (a); + ^ +ALTER TABLE partitioned ADD PRIMARY KEY (a); +ERROR: primary key constraints are not supported on partitioned tables +LINE 1: ALTER TABLE partitioned ADD PRIMARY KEY (a); + ^ +ALTER TABLE partitioned ADD FOREIGN KEY (a) REFERENCES blah; +ERROR: foreign key constraints are not supported on partitioned tables +LINE 1: ALTER TABLE partitioned ADD FOREIGN KEY (a) REFERENCES blah; + ^ +ALTER TABLE partitioned ADD EXCLUDE USING gist (a WITH &&); +ERROR: exclusion constraints are not supported on partitioned tables +LINE 1: ALTER TABLE partitioned ADD EXCLUDE USING gist (a WITH &&); + ^ +-- cannot drop column that is part of the partition key +ALTER TABLE partitioned DROP COLUMN a; +ERROR: cannot drop column named in partition key +ALTER TABLE partitioned ALTER COLUMN a TYPE char(5); +ERROR: cannot alter type of column named in partition key +ALTER TABLE partitioned DROP COLUMN b; +ERROR: cannot drop column referenced in partition key expression +ALTER TABLE partitioned ALTER COLUMN b TYPE char(5); +ERROR: cannot alter type of column referenced in partition key expression +-- cannot drop NOT NULL on columns in the range partition key +ALTER TABLE partitioned ALTER COLUMN a DROP NOT NULL; +ERROR: column "a" is in range partition key +-- partitioned table cannot partiticipate in regular inheritance +CREATE TABLE foo ( + a int, + b int +); +ALTER TABLE partitioned INHERIT foo; +ERROR: cannot change inheritance of partitioned table +ALTER TABLE foo INHERIT partitioned; +ERROR: cannot inherit from partitioned table "partitioned" +-- cannot add NO INHERIT constraint to partitioned tables +ALTER TABLE partitioned ADD CONSTRAINT chk_a CHECK (a > 0) NO INHERIT; +ERROR: cannot add NO INHERIT constraint to partitioned table "partitioned" +DROP TABLE partitioned, foo; +-- +-- ATTACH PARTITION +-- +-- check that target table is partitioned +CREATE TABLE unparted ( + a int +); +CREATE TABLE fail_part (like unparted); +ALTER TABLE unparted ATTACH PARTITION fail_part FOR VALUES IN ('a'); +ERROR: "unparted" is not partitioned +DROP TABLE unparted, fail_part; +-- check that partition bound is compatible +CREATE TABLE list_parted ( + a int NOT NULL, + b char(2) COLLATE "C", + CONSTRAINT check_a CHECK (a > 0) +) PARTITION BY LIST (a); +CREATE TABLE fail_part (LIKE list_parted); +ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES FROM (1) TO (10); +ERROR: invalid bound specification for a list partition +LINE 1: ...list_parted ATTACH PARTITION fail_part FOR VALUES FROM (1) T... + ^ +DROP TABLE fail_part; +-- check that the table being attached exists +ALTER TABLE list_parted ATTACH PARTITION nonexistant FOR VALUES IN (1); +ERROR: relation "nonexistant" does not exist +-- check ownership of the source table +CREATE ROLE regress_test_me; +CREATE ROLE regress_test_not_me; +CREATE TABLE not_owned_by_me (LIKE list_parted); +ALTER TABLE not_owned_by_me OWNER TO regress_test_not_me; +SET SESSION AUTHORIZATION regress_test_me; +CREATE TABLE owned_by_me ( + a int +) PARTITION BY LIST (a); +ALTER TABLE owned_by_me ATTACH PARTITION not_owned_by_me FOR VALUES IN (1); +ERROR: must be owner of relation not_owned_by_me +RESET SESSION AUTHORIZATION; +DROP TABLE owned_by_me, not_owned_by_me; +DROP ROLE regress_test_not_me; +DROP ROLE regress_test_me; +-- check that the table being attached is not part of regular inheritance +CREATE TABLE parent (LIKE list_parted); +CREATE TABLE child () INHERITS (parent); +ALTER TABLE list_parted ATTACH PARTITION child FOR VALUES IN (1); +ERROR: cannot attach inheritance child as partition +ALTER TABLE list_parted ATTACH PARTITION parent FOR VALUES IN (1); +ERROR: cannot attach inheritance parent as partition +DROP TABLE parent CASCADE; +NOTICE: drop cascades to table child +-- check any TEMP-ness +CREATE TEMP TABLE temp_parted (a int) PARTITION BY LIST (a); +CREATE TABLE perm_part (a int); +ALTER TABLE temp_parted ATTACH PARTITION perm_part FOR VALUES IN (1); +ERROR: cannot attach a permanent relation as partition of temporary relation "temp_parted" +DROP TABLE temp_parted, perm_part; +-- check that the table being attached is not a typed table +CREATE TYPE mytype AS (a int); +CREATE TABLE fail_part OF mytype; +ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1); +ERROR: cannot attach a typed table as partition +DROP TYPE mytype CASCADE; +NOTICE: drop cascades to table fail_part +-- check existence (or non-existence) of oid column +ALTER TABLE list_parted SET WITH OIDS; +CREATE TABLE fail_part (a int); +ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1); +ERROR: cannot attach table "fail_part" without OIDs as partition of table "list_parted" with OIDs +ALTER TABLE list_parted SET WITHOUT OIDS; +ALTER TABLE fail_part SET WITH OIDS; +ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1); +ERROR: cannot attach table "fail_part" with OIDs as partition of table "list_parted" without OIDs +DROP TABLE fail_part; +-- check that the table being attached has only columns present in the parent +CREATE TABLE fail_part (like list_parted, c int); +ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1); +ERROR: table "fail_part" contains column "c" not found in parent "list_parted" +DETAIL: New partition should contain only the columns present in parent. +DROP TABLE fail_part; +-- check that the table being attached has every column of the parent +CREATE TABLE fail_part (a int NOT NULL); +ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1); +ERROR: child table is missing column "b" +DROP TABLE fail_part; +-- check that columns match in type, collation and NOT NULL status +CREATE TABLE fail_part ( + b char(3), + a int NOT NULL +); +ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1); +ERROR: child table "fail_part" has different type for column "b" +ALTER TABLE fail_part ALTER b TYPE char (2) COLLATE "POSIX"; +ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1); +ERROR: child table "fail_part" has different collation for column "b" +DROP TABLE fail_part; +-- check that the table being attached has all constraints of the parent +CREATE TABLE fail_part ( + b char(2) COLLATE "C", + a int NOT NULL +); +ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1); +ERROR: child table is missing constraint "check_a" +-- check that the constraint matches in definition with parent's constraint +ALTER TABLE fail_part ADD CONSTRAINT check_a CHECK (a >= 0); +ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1); +ERROR: child table "fail_part" has different definition for check constraint "check_a" +DROP TABLE fail_part; +-- check the attributes and constraints after partition is attached +CREATE TABLE part_1 ( + a int NOT NULL, + b char(2) COLLATE "C", + CONSTRAINT check_a CHECK (a > 0) +); +ALTER TABLE list_parted ATTACH PARTITION part_1 FOR VALUES IN (1); +-- attislocal and conislocal are always false for merged attributes and constraints respectively. +SELECT attislocal, attinhcount FROM pg_attribute WHERE attrelid = 'part_1'::regclass AND attnum > 0; + attislocal | attinhcount +------------+------------- + f | 1 + f | 1 +(2 rows) + +SELECT conislocal, coninhcount FROM pg_constraint WHERE conrelid = 'part_1'::regclass AND conname = 'check_a'; + conislocal | coninhcount +------------+------------- + f | 1 +(1 row) + +-- check that the new partition won't overlap with an existing partition +CREATE TABLE fail_part (LIKE part_1 INCLUDING CONSTRAINTS); +ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1); +ERROR: partition "fail_part" would overlap partition "part_1" +-- check validation when attaching list partitions +CREATE TABLE list_parted2 ( + a int, + b char +) PARTITION BY LIST (a); +-- check that violating rows are correctly reported +CREATE TABLE part_2 (LIKE list_parted2); +INSERT INTO part_2 VALUES (3, 'a'); +ALTER TABLE list_parted2 ATTACH PARTITION part_2 FOR VALUES IN (2); +ERROR: partition constraint is violated by some row +-- should be ok after deleting the bad row +DELETE FROM part_2; +ALTER TABLE list_parted2 ATTACH PARTITION part_2 FOR VALUES IN (2); +-- adding constraints that describe the desired partition constraint +-- (or more restrictive) will help skip the validation scan +CREATE TABLE part_3_4 ( + LIKE list_parted2, + CONSTRAINT check_a CHECK (a IN (3)) +); +-- however, if a list partition does not accept nulls, there should be +-- an explicit NOT NULL constraint on the partition key column for the +-- validation scan to be skipped; +ALTER TABLE list_parted2 ATTACH PARTITION part_3_4 FOR VALUES IN (3, 4); +-- adding a NOT NULL constraint will cause the scan to be skipped +ALTER TABLE list_parted2 DETACH PARTITION part_3_4; +ALTER TABLE part_3_4 ALTER a SET NOT NULL; +ALTER TABLE list_parted2 ATTACH PARTITION part_3_4 FOR VALUES IN (3, 4); +INFO: partition constraint for table "part_3_4" is implied by existing constraints +-- check validation when attaching range partitions +CREATE TABLE range_parted ( + a int, + b int +) PARTITION BY RANGE (a, b); +-- check that violating rows are correctly reported +CREATE TABLE part1 ( + a int NOT NULL CHECK (a = 1), + b int NOT NULL CHECK (b >= 1 AND b <= 10) +); +INSERT INTO part1 VALUES (1, 10); +-- Remember the TO bound is exclusive +ALTER TABLE range_parted ATTACH PARTITION part1 FOR VALUES FROM (1, 1) TO (1, 10); +ERROR: partition constraint is violated by some row +-- should be ok after deleting the bad row +DELETE FROM part1; +ALTER TABLE range_parted ATTACH PARTITION part1 FOR VALUES FROM (1, 1) TO (1, 10); +-- adding constraints that describe the desired partition constraint +-- (or more restrictive) will help skip the validation scan +CREATE TABLE part2 ( + a int NOT NULL CHECK (a = 1), + b int NOT NULL CHECK (b >= 10 AND b < 18) +); +ALTER TABLE range_parted ATTACH PARTITION part2 FOR VALUES FROM (1, 10) TO (1, 20); +INFO: partition constraint for table "part2" is implied by existing constraints +-- check that leaf partitions are scanned when attaching a partitioned +-- table +CREATE TABLE part_5 ( + LIKE list_parted2 +) PARTITION BY LIST (b); +-- check that violating rows are correctly reported +CREATE TABLE part_5_a PARTITION OF part_5 FOR VALUES IN ('a'); +INSERT INTO part_5_a (a, b) VALUES (6, 'a'); +ALTER TABLE list_parted2 ATTACH PARTITION part_5 FOR VALUES IN (5); +ERROR: partition constraint is violated by some row +-- delete the faulting row and also add a constraint to skip the scan +DELETE FROM part_5_a WHERE a NOT IN (3); +ALTER TABLE part_5 ADD CONSTRAINT check_a CHECK (a IN (5)), ALTER a SET NOT NULL; +ALTER TABLE list_parted2 ATTACH PARTITION part_5 FOR VALUES IN (5); +INFO: partition constraint for table "part_5" is implied by existing constraints +-- check that the table being attached is not already a partition +ALTER TABLE list_parted2 ATTACH PARTITION part_2 FOR VALUES IN (2); +ERROR: "part_2" is already a partition +-- check that circular inheritance is not allowed +ALTER TABLE part_5 ATTACH PARTITION list_parted2 FOR VALUES IN ('b'); +ERROR: circular inheritance not allowed +DETAIL: "part_5" is already a child of "list_parted2". +ALTER TABLE list_parted2 ATTACH PARTITION list_parted2 FOR VALUES IN (0); +ERROR: circular inheritance not allowed +DETAIL: "list_parted2" is already a child of "list_parted2". +-- +-- DETACH PARTITION +-- +-- check that the partition being detached exists at all +ALTER TABLE list_parted2 DETACH PARTITION part_4; +ERROR: relation "part_4" does not exist +-- check that the partition being detached is actually a partition of the parent +CREATE TABLE not_a_part (a int); +ALTER TABLE list_parted2 DETACH PARTITION not_a_part; +ERROR: relation "not_a_part" is not a partition of relation "list_parted2" +ALTER TABLE list_parted2 DETACH PARTITION part_1; +ERROR: relation "part_1" is not a partition of relation "list_parted2" +-- check that, after being detached, attinhcount/coninhcount is dropped to 0 and +-- attislocal/conislocal is set to true +ALTER TABLE list_parted2 DETACH PARTITION part_3_4; +SELECT attinhcount, attislocal FROM pg_attribute WHERE attrelid = 'part_3_4'::regclass AND attnum > 0; + attinhcount | attislocal +-------------+------------ + 0 | t + 0 | t +(2 rows) + +SELECT coninhcount, conislocal FROM pg_constraint WHERE conrelid = 'part_3_4'::regclass AND conname = 'check_a'; + coninhcount | conislocal +-------------+------------ + 0 | t +(1 row) + +DROP TABLE part_3_4; +-- Check ALTER TABLE commands for partitioned tables and partitions +-- cannot add/drop column to/from *only* the parent +ALTER TABLE ONLY list_parted2 ADD COLUMN c int; +ERROR: column must be added to child tables too +ALTER TABLE ONLY list_parted2 DROP COLUMN b; +ERROR: column must be dropped from child tables too +-- cannot add a column to partition or drop an inherited one +ALTER TABLE part_2 ADD COLUMN c text; +ERROR: cannot add column to a partition +ALTER TABLE part_2 DROP COLUMN b; +ERROR: cannot drop inherited column "b" +-- Nor rename, alter type +ALTER TABLE part_2 RENAME COLUMN b to c; +ERROR: cannot rename inherited column "b" +ALTER TABLE part_2 ALTER COLUMN b TYPE text; +ERROR: cannot alter inherited column "b" +-- cannot add NOT NULL or check constraints to *only* the parent (ie, non-inherited) +ALTER TABLE ONLY list_parted2 ALTER b SET NOT NULL; +ERROR: constraint must be added to child tables too +ALTER TABLE ONLY list_parted2 add constraint check_b check (b <> 'zz'); +ERROR: constraint must be added to child tables too +ALTER TABLE list_parted2 add constraint check_b check (b <> 'zz') NO INHERIT; +ERROR: cannot add NO INHERIT constraint to partitioned table "list_parted2" +-- cannot drop inherited NOT NULL or check constraints from partition +ALTER TABLE list_parted2 ALTER b SET NOT NULL, ADD CONSTRAINT check_a2 CHECK (a > 0); +ALTER TABLE part_2 ALTER b DROP NOT NULL; +ERROR: column "b" is marked NOT NULL in parent table +ALTER TABLE part_2 DROP CONSTRAINT check_a2; +ERROR: cannot drop inherited constraint "check_a2" of relation "part_2" +-- cannot drop NOT NULL or check constraints from *only* the parent +ALTER TABLE ONLY list_parted2 ALTER a DROP NOT NULL; +ERROR: constraint must be dropped from child tables too +ALTER TABLE ONLY list_parted2 DROP CONSTRAINT check_a2; +ERROR: constraint must be dropped from child tables too +-- check that a partition cannot participate in regular inheritance +CREATE TABLE inh_test () INHERITS (part_2); +ERROR: cannot inherit from partition "part_2" +CREATE TABLE inh_test (LIKE part_2); +ALTER TABLE inh_test INHERIT part_2; +ERROR: cannot inherit from a partition +ALTER TABLE part_2 INHERIT inh_test; +ERROR: cannot change inheritance of a partition +-- cannot drop or alter type of partition key columns of lower level +-- partitioned tables; for example, part_5, which is list_parted2's +-- partition, is partitioned on b; +ALTER TABLE list_parted2 DROP COLUMN b; +ERROR: cannot drop column named in partition key +ALTER TABLE list_parted2 ALTER COLUMN b TYPE text; +ERROR: cannot alter type of column named in partition key +-- cleanup: avoid using CASCADE +DROP TABLE list_parted, part_1; +DROP TABLE list_parted2, part_2, part_5, part_5_a; +DROP TABLE range_parted, part1, part2; +-- more tests for certain multi-level partitioning scenarios +create table p (a int, b int) partition by range (a, b); +create table p1 (b int, a int not null) partition by range (b); +create table p11 (like p1); +alter table p11 drop a; +alter table p11 add a int; +alter table p11 drop a; +alter table p11 add a int not null; +-- attnum for key attribute 'a' is different in p, p1, and p11 +select attrelid::regclass, attname, attnum +from pg_attribute +where attname = 'a' + and (attrelid = 'p'::regclass + or attrelid = 'p1'::regclass + or attrelid = 'p11'::regclass) +order by attrelid::regclass::text; + attrelid | attname | attnum +----------+---------+-------- + p | a | 1 + p1 | a | 2 + p11 | a | 4 +(3 rows) + +alter table p1 attach partition p11 for values from (2) to (5); +insert into p1 (a, b) values (2, 3); +-- check that partition validation scan correctly detects violating rows +alter table p attach partition p1 for values from (1, 2) to (1, 10); +ERROR: partition constraint is violated by some row +-- cleanup: avoid using CASCADE +drop table p, p1, p11; diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out index baccca14af..8c5050577b 100644 --- a/src/test/regress/expected/arrays.out +++ b/src/test/regress/expected/arrays.out @@ -589,6 +589,20 @@ SELECT array_positions('[2:4]={1,2,3}'::int[], 1); {2} (1 row) +SELECT + array_position(ids, (1, 1)), + array_positions(ids, (1, 1)) + FROM +(VALUES + (ARRAY[(0, 0), (1, 1)]), + (ARRAY[(1, 1)]) +) AS f (ids); + array_position | array_positions +----------------+----------------- + 2 | {2} + 1 | {1} +(2 rows) + -- operators SELECT a FROM arrtest WHERE b = ARRAY[[[113,142],[1,147]]]; a @@ -1539,16 +1553,43 @@ select array_fill('juhu'::text, array[3,3]); {{juhu,juhu,juhu},{juhu,juhu,juhu},{juhu,juhu,juhu}} (1 row) +select a, a = '{}' as is_eq, array_dims(a) + from (select array_fill(42, array[0]) as a) ss; + a | is_eq | array_dims +----+-------+------------ + {} | t | +(1 row) + +select a, a = '{}' as is_eq, array_dims(a) + from (select array_fill(42, '{}') as a) ss; + a | is_eq | array_dims +----+-------+------------ + {} | t | +(1 row) + +select a, a = '{}' as is_eq, array_dims(a) + from (select array_fill(42, '{}', '{}') as a) ss; + a | is_eq | array_dims +----+-------+------------ + {} | t | +(1 row) + -- raise exception select array_fill(1, null, array[2,2]); ERROR: dimension array or low bound array cannot be null select array_fill(1, array[2,2], null); ERROR: dimension array or low bound array cannot be null +select array_fill(1, array[2,2], '{}'); +ERROR: wrong number of array subscripts +DETAIL: Low bound array has different size than dimensions array. select array_fill(1, array[3,3], array[1,1,1]); ERROR: wrong number of array subscripts DETAIL: Low bound array has different size than dimensions array. select array_fill(1, array[1,2,null]); ERROR: dimension values cannot be null +select array_fill(1, array[[1,2],[3,4]]); +ERROR: wrong number of array subscripts +DETAIL: Dimension array must be one dimensional. select string_to_array('1|2|3', '|'); string_to_array ----------------- diff --git a/src/test/regress/expected/case.out b/src/test/regress/expected/case.out index 35b6476e50..09d5516fb5 100644 --- a/src/test/regress/expected/case.out +++ b/src/test/regress/expected/case.out @@ -305,6 +305,9 @@ SELECT * FROM CASE_TBL; -- the isNull flag for the case test value incorrectly became true, causing -- the third WHEN-clause not to match. The volatile function calls are needed -- to prevent constant-folding in the planner, which would hide the bug. +-- Wrap this in a single transaction so the transient '=' operator doesn't +-- cause problems in concurrent sessions +BEGIN; CREATE FUNCTION vol(text) returns text as 'begin return $1; end' language plpgsql volatile; SELECT CASE @@ -335,13 +338,35 @@ SELECT CASE volfoo('bar') WHEN 'foo'::foodomain THEN 'is foo' ELSE 'is not foo' is not foo (1 row) +ROLLBACK; +-- Test multiple evaluation of a CASE arg that is a read/write object (#14472) +-- Wrap this in a single transaction so the transient '=' operator doesn't +-- cause problems in concurrent sessions +BEGIN; +CREATE DOMAIN arrdomain AS int[]; +CREATE FUNCTION make_ad(int,int) returns arrdomain as + 'declare x arrdomain; + begin + x := array[$1,$2]; + return x; + end' language plpgsql volatile; +CREATE FUNCTION ad_eq(arrdomain, arrdomain) returns boolean as + 'begin return array_eq($1, $2); end' language plpgsql; +CREATE OPERATOR = (procedure = ad_eq, + leftarg = arrdomain, rightarg = arrdomain); +SELECT CASE make_ad(1,2) + WHEN array[2,4]::arrdomain THEN 'wrong' + WHEN array[2,5]::arrdomain THEN 'still wrong' + WHEN array[1,2]::arrdomain THEN 'right' + END; + case +------- + right +(1 row) + +ROLLBACK; -- -- Clean up -- DROP TABLE CASE_TBL; DROP TABLE CASE2_TBL; -DROP OPERATOR = (foodomain, foodomain); -DROP FUNCTION inline_eq(foodomain, foodomain); -DROP FUNCTION volfoo(text); -DROP DOMAIN foodomain; -DROP FUNCTION vol(text); diff --git a/src/test/regress/expected/collate.linux.utf8.out b/src/test/regress/expected/collate.linux.utf8.out index 495e4ad448..286c972fbb 100644 --- a/src/test/regress/expected/collate.linux.utf8.out +++ b/src/test/regress/expected/collate.linux.utf8.out @@ -9,11 +9,11 @@ CREATE TABLE collate_test1 ( b text COLLATE "en_US" NOT NULL ); \d collate_test1 - Table "public.collate_test1" - Column | Type | Modifiers ---------+---------+------------------------ - a | integer | - b | text | collate en_US not null + Table "public.collate_test1" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + b | text | en_US | not null | CREATE TABLE collate_test_fail ( a int, @@ -40,11 +40,11 @@ CREATE TABLE collate_test_like ( LIKE collate_test1 ); \d collate_test_like - Table "public.collate_test_like" - Column | Type | Modifiers ---------+---------+------------------------ - a | integer | - b | text | collate en_US not null + Table "public.collate_test_like" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + b | text | en_US | not null | CREATE TABLE collate_test2 ( a int, @@ -1044,16 +1044,16 @@ drop cascades to composite type collate_dep_test2 column y drop cascades to view collate_dep_test3 drop cascades to index collate_dep_test4i \d collate_dep_test1 -Table "public.collate_dep_test1" - Column | Type | Modifiers ---------+---------+----------- - a | integer | + Table "public.collate_dep_test1" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | \d collate_dep_test2 -Composite type "public.collate_dep_test2" - Column | Type | Modifiers ---------+---------+----------- - x | integer | + Composite type "public.collate_dep_test2" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + x | integer | | | DROP TABLE collate_dep_test1, collate_dep_test4t; DROP TYPE collate_dep_test2; diff --git a/src/test/regress/expected/collate.out b/src/test/regress/expected/collate.out index f076a4dbae..d667ae1714 100644 --- a/src/test/regress/expected/collate.out +++ b/src/test/regress/expected/collate.out @@ -16,11 +16,11 @@ CREATE TABLE collate_test1 ( b text COLLATE "C" NOT NULL ); \d collate_test1 - Table "collate_tests.collate_test1" - Column | Type | Modifiers ---------+---------+-------------------- - a | integer | - b | text | collate C not null + Table "collate_tests.collate_test1" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + b | text | C | not null | CREATE TABLE collate_test_fail ( a int COLLATE "C", @@ -33,11 +33,11 @@ CREATE TABLE collate_test_like ( LIKE collate_test1 ); \d collate_test_like -Table "collate_tests.collate_test_like" - Column | Type | Modifiers ---------+---------+-------------------- - a | integer | - b | text | collate C not null + Table "collate_tests.collate_test_like" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + b | text | C | not null | CREATE TABLE collate_test2 ( a int, diff --git a/src/test/regress/expected/combocid.out b/src/test/regress/expected/combocid.out index b63894c283..17eb94a8ff 100644 --- a/src/test/regress/expected/combocid.out +++ b/src/test/regress/expected/combocid.out @@ -140,3 +140,30 @@ SELECT ctid,cmin,* FROM combocidtest; (0,6) | 0 | 444 (3 rows) +-- test for bug reported in +-- CABRT9RC81YUf1=jsmWopcKJEro=VoeG2ou6sPwyOUTx_qteRsg@mail.gmail.com +CREATE TABLE IF NOT EXISTS testcase( + id int PRIMARY KEY, + balance numeric +); +INSERT INTO testcase VALUES (1, 0); +BEGIN; +SELECT * FROM testcase WHERE testcase.id = 1 FOR UPDATE; + id | balance +----+--------- + 1 | 0 +(1 row) + +UPDATE testcase SET balance = balance + 400 WHERE id=1; +SAVEPOINT subxact; +UPDATE testcase SET balance = balance - 100 WHERE id=1; +ROLLBACK TO SAVEPOINT subxact; +-- should return one tuple +SELECT * FROM testcase WHERE id = 1 FOR UPDATE; + id | balance +----+--------- + 1 | 400 +(1 row) + +ROLLBACK; +DROP TABLE testcase; diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out index 5f6260a8f1..65e9c626b3 100644 --- a/src/test/regress/expected/copy2.out +++ b/src/test/regress/expected/copy2.out @@ -438,10 +438,10 @@ begin end $$ language plpgsql immutable; alter table check_con_tbl add check (check_con_function(check_con_tbl.*)); \d+ check_con_tbl - Table "public.check_con_tbl" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+---------+--------------+------------- - f1 | integer | | plain | | + Table "public.check_con_tbl" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+---------+--------------+------------- + f1 | integer | | | | plain | | Check constraints: "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*)) @@ -460,9 +460,113 @@ select * from check_con_tbl; (2 rows) +-- test with RLS enabled. +CREATE ROLE regress_rls_copy_user; +CREATE ROLE regress_rls_copy_user_colperms; +CREATE TABLE rls_t1 (a int, b int, c int); +COPY rls_t1 (a, b, c) from stdin; +CREATE POLICY p1 ON rls_t1 FOR SELECT USING (a % 2 = 0); +ALTER TABLE rls_t1 ENABLE ROW LEVEL SECURITY; +ALTER TABLE rls_t1 FORCE ROW LEVEL SECURITY; +GRANT SELECT ON TABLE rls_t1 TO regress_rls_copy_user; +GRANT SELECT (a, b) ON TABLE rls_t1 TO regress_rls_copy_user_colperms; +-- all columns +COPY rls_t1 TO stdout; +1 4 1 +2 3 2 +3 2 3 +4 1 4 +COPY rls_t1 (a, b, c) TO stdout; +1 4 1 +2 3 2 +3 2 3 +4 1 4 +-- subset of columns +COPY rls_t1 (a) TO stdout; +1 +2 +3 +4 +COPY rls_t1 (a, b) TO stdout; +1 4 +2 3 +3 2 +4 1 +-- column reordering +COPY rls_t1 (b, a) TO stdout; +4 1 +3 2 +2 3 +1 4 +SET SESSION AUTHORIZATION regress_rls_copy_user; +-- all columns +COPY rls_t1 TO stdout; +2 3 2 +4 1 4 +COPY rls_t1 (a, b, c) TO stdout; +2 3 2 +4 1 4 +-- subset of columns +COPY rls_t1 (a) TO stdout; +2 +4 +COPY rls_t1 (a, b) TO stdout; +2 3 +4 1 +-- column reordering +COPY rls_t1 (b, a) TO stdout; +3 2 +1 4 +RESET SESSION AUTHORIZATION; +SET SESSION AUTHORIZATION regress_rls_copy_user_colperms; +-- attempt all columns (should fail) +COPY rls_t1 TO stdout; +ERROR: permission denied for relation rls_t1 +COPY rls_t1 (a, b, c) TO stdout; +ERROR: permission denied for relation rls_t1 +-- try to copy column with no privileges (should fail) +COPY rls_t1 (c) TO stdout; +ERROR: permission denied for relation rls_t1 +-- subset of columns (should succeed) +COPY rls_t1 (a) TO stdout; +2 +4 +COPY rls_t1 (a, b) TO stdout; +2 3 +4 1 +RESET SESSION AUTHORIZATION; +-- test with INSTEAD OF INSERT trigger on a view +CREATE TABLE instead_of_insert_tbl(id serial, name text); +CREATE VIEW instead_of_insert_tbl_view AS SELECT ''::text AS str; +COPY instead_of_insert_tbl_view FROM stdin; -- fail +ERROR: cannot copy to view "instead_of_insert_tbl_view" +HINT: To enable copying to a view, provide an INSTEAD OF INSERT trigger. +CREATE FUNCTION fun_instead_of_insert_tbl() RETURNS trigger AS $$ +BEGIN + INSERT INTO instead_of_insert_tbl (name) VALUES (NEW.str); + RETURN NULL; +END; +$$ LANGUAGE plpgsql; +CREATE TRIGGER trig_instead_of_insert_tbl_view + INSTEAD OF INSERT ON instead_of_insert_tbl_view + FOR EACH ROW EXECUTE PROCEDURE fun_instead_of_insert_tbl(); +COPY instead_of_insert_tbl_view FROM stdin; +SELECT * FROM instead_of_insert_tbl; + id | name +----+------- + 1 | test1 +(1 row) + +-- clean up DROP TABLE forcetest; DROP TABLE vistest; DROP FUNCTION truncate_in_subxact(); DROP TABLE x, y; +DROP TABLE rls_t1 CASCADE; +DROP ROLE regress_rls_copy_user; +DROP ROLE regress_rls_copy_user_colperms; DROP FUNCTION fn_x_before(); DROP FUNCTION fn_x_after(); +DROP TABLE instead_of_insert_tbl; +DROP VIEW instead_of_insert_tbl_view; +DROP FUNCTION fun_instead_of_insert_tbl(); diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index 76593e1e06..e519fdb0f6 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -2452,11 +2452,11 @@ DETAIL: Key (f2)=(b) is duplicated. DELETE FROM concur_heap WHERE f1 = 'b'; VACUUM FULL concur_heap; \d concur_heap -Table "public.concur_heap" - Column | Type | Modifiers ---------+------+----------- - f1 | text | - f2 | text | + Table "public.concur_heap" + Column | Type | Collation | Nullable | Default +--------+------+-----------+----------+--------- + f1 | text | | | + f2 | text | | | Indexes: "concur_index2" UNIQUE, btree (f1) "concur_index3" UNIQUE, btree (f2) INVALID @@ -2468,11 +2468,11 @@ Indexes: REINDEX TABLE concur_heap; \d concur_heap -Table "public.concur_heap" - Column | Type | Modifiers ---------+------+----------- - f1 | text | - f2 | text | + Table "public.concur_heap" + Column | Type | Collation | Nullable | Default +--------+------+-----------+----------+--------- + f1 | text | | | + f2 | text | | | Indexes: "concur_index2" UNIQUE, btree (f1) "concur_index3" UNIQUE, btree (f2) @@ -2502,11 +2502,11 @@ DROP INDEX CONCURRENTLY "concur_index5"; DROP INDEX CONCURRENTLY "concur_index1"; DROP INDEX CONCURRENTLY "concur_heap_expr_idx"; \d concur_heap -Table "public.concur_heap" - Column | Type | Modifiers ---------+------+----------- - f1 | text | - f2 | text | + Table "public.concur_heap" + Column | Type | Collation | Nullable | Default +--------+------+-----------+----------+--------- + f1 | text | | | + f2 | text | | | Indexes: "std_index" btree (f2) @@ -2520,12 +2520,12 @@ INSERT INTO cwi_test VALUES(1, 2), (3, 4), (5, 6); CREATE UNIQUE INDEX cwi_uniq_idx ON cwi_test(a , b); ALTER TABLE cwi_test ADD primary key USING INDEX cwi_uniq_idx; \d cwi_test - Table "public.cwi_test" - Column | Type | Modifiers ---------+-----------------------+----------- - a | integer | not null - b | character varying(10) | not null - c | character(1) | + Table "public.cwi_test" + Column | Type | Collation | Nullable | Default +--------+-----------------------+-----------+----------+--------- + a | integer | | not null | + b | character varying(10) | | not null | + c | character(1) | | | Indexes: "cwi_uniq_idx" PRIMARY KEY, btree (a, b) @@ -2543,12 +2543,12 @@ ALTER TABLE cwi_test DROP CONSTRAINT cwi_uniq_idx, USING INDEX cwi_uniq2_idx; NOTICE: ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index "cwi_uniq2_idx" to "cwi_replaced_pkey" \d cwi_test - Table "public.cwi_test" - Column | Type | Modifiers ---------+-----------------------+----------- - a | integer | not null - b | character varying(10) | not null - c | character(1) | + Table "public.cwi_test" + Column | Type | Collation | Nullable | Default +--------+-----------------------+-----------+----------+--------- + a | integer | | not null | + b | character varying(10) | | not null | + c | character(1) | | | Indexes: "cwi_replaced_pkey" PRIMARY KEY, btree (b, a) @@ -2940,7 +2940,7 @@ ORDER BY thousand; 1 | 1001 (2 rows) -RESET enable_indexscan; +RESET enable_indexonlyscan; -- -- Check elimination of constant-NULL subexpressions -- @@ -2952,6 +2952,48 @@ explain (costs off) Index Cond: ((thousand = 1) AND (tenthous = 1001)) (2 rows) +-- +-- Check matching of boolean index columns to WHERE conditions and sort keys +-- +create temp table boolindex (b bool, i int, unique(b, i), junk float); +explain (costs off) + select * from boolindex order by b, i limit 10; + QUERY PLAN +------------------------------------------------------- + Limit + -> Index Scan using boolindex_b_i_key on boolindex +(2 rows) + +explain (costs off) + select * from boolindex where b order by i limit 10; + QUERY PLAN +------------------------------------------------------- + Limit + -> Index Scan using boolindex_b_i_key on boolindex + Index Cond: (b = true) + Filter: b +(4 rows) + +explain (costs off) + select * from boolindex where b = true order by i desc limit 10; + QUERY PLAN +---------------------------------------------------------------- + Limit + -> Index Scan Backward using boolindex_b_i_key on boolindex + Index Cond: (b = true) + Filter: b +(4 rows) + +explain (costs off) + select * from boolindex where not b order by i limit 10; + QUERY PLAN +------------------------------------------------------- + Limit + -> Index Scan using boolindex_b_i_key on boolindex + Index Cond: (b = false) + Filter: (NOT b) +(4 rows) + -- -- REINDEX (VERBOSE) -- diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out index 41ceb874e8..6caa9c2407 100644 --- a/src/test/regress/expected/create_table.out +++ b/src/test/regress/expected/create_table.out @@ -253,3 +253,408 @@ DROP TABLE as_select1; -- check that the oid column is added before the primary key is checked CREATE TABLE oid_pk (f1 INT, PRIMARY KEY(oid)) WITH OIDS; DROP TABLE oid_pk; +-- +-- Partitioned tables +-- +-- cannot combine INHERITS and PARTITION BY (although grammar allows) +CREATE TABLE partitioned ( + a int +) INHERITS (some_table) PARTITION BY LIST (a); +ERROR: cannot create partitioned table as inheritance child +-- cannot use more than 1 column as partition key for list partitioned table +CREATE TABLE partitioned ( + a1 int, + a2 int +) PARTITION BY LIST (a1, a2); -- fail +ERROR: cannot list partition using more than one column +-- unsupported constraint type for partitioned tables +CREATE TABLE partitioned ( + a int PRIMARY KEY +) PARTITION BY RANGE (a); +ERROR: primary key constraints are not supported on partitioned tables +LINE 2: a int PRIMARY KEY + ^ +CREATE TABLE pkrel ( + a int PRIMARY KEY +); +CREATE TABLE partitioned ( + a int REFERENCES pkrel(a) +) PARTITION BY RANGE (a); +ERROR: foreign key constraints are not supported on partitioned tables +LINE 2: a int REFERENCES pkrel(a) + ^ +DROP TABLE pkrel; +CREATE TABLE partitioned ( + a int UNIQUE +) PARTITION BY RANGE (a); +ERROR: unique constraints are not supported on partitioned tables +LINE 2: a int UNIQUE + ^ +CREATE TABLE partitioned ( + a int, + EXCLUDE USING gist (a WITH &&) +) PARTITION BY RANGE (a); +ERROR: exclusion constraints are not supported on partitioned tables +LINE 3: EXCLUDE USING gist (a WITH &&) + ^ +-- prevent column from being used twice in the partition key +CREATE TABLE partitioned ( + a int +) PARTITION BY RANGE (a, a); +ERROR: column "a" appears more than once in partition key +-- prevent using prohibited expressions in the key +CREATE FUNCTION retset (a int) RETURNS SETOF int AS $$ SELECT 1; $$ LANGUAGE SQL IMMUTABLE; +CREATE TABLE partitioned ( + a int +) PARTITION BY RANGE (retset(a)); +ERROR: set-returning functions are not allowed in partition key expression +DROP FUNCTION retset(int); +CREATE TABLE partitioned ( + a int +) PARTITION BY RANGE ((avg(a))); +ERROR: aggregate functions are not allowed in partition key expression +CREATE TABLE partitioned ( + a int, + b int +) PARTITION BY RANGE ((avg(a) OVER (PARTITION BY b))); +ERROR: window functions are not allowed in partition key expression +CREATE TABLE partitioned ( + a int +) PARTITION BY LIST ((a LIKE (SELECT 1))); +ERROR: cannot use subquery in partition key expression +CREATE TABLE partitioned ( + a int +) PARTITION BY RANGE (('a')); +ERROR: cannot use constant expression as partition key +CREATE FUNCTION const_func () RETURNS int AS $$ SELECT 1; $$ LANGUAGE SQL IMMUTABLE; +CREATE TABLE partitioned ( + a int +) PARTITION BY RANGE (const_func()); +ERROR: cannot use constant expression as partition key +DROP FUNCTION const_func(); +-- only accept "list" and "range" as partitioning strategy +CREATE TABLE partitioned ( + a int +) PARTITION BY HASH (a); +ERROR: unrecognized partitioning strategy "hash" +-- specified column must be present in the table +CREATE TABLE partitioned ( + a int +) PARTITION BY RANGE (b); +ERROR: column "b" named in partition key does not exist +-- cannot use system columns in partition key +CREATE TABLE partitioned ( + a int +) PARTITION BY RANGE (xmin); +ERROR: cannot use system column "xmin" in partition key +-- functions in key must be immutable +CREATE FUNCTION immut_func (a int) RETURNS int AS $$ SELECT a + random()::int; $$ LANGUAGE SQL; +CREATE TABLE partitioned ( + a int +) PARTITION BY RANGE (immut_func(a)); +ERROR: functions in partition key expression must be marked IMMUTABLE +DROP FUNCTION immut_func(int); +-- cannot contain whole-row references +CREATE TABLE partitioned ( + a int +) PARTITION BY RANGE ((partitioned)); +ERROR: partition key expressions cannot contain whole-row references +-- prevent using columns of unsupported types in key (type must have a btree operator class) +CREATE TABLE partitioned ( + a point +) PARTITION BY LIST (a); +ERROR: data type point has no default btree operator class +HINT: You must specify a btree operator class or define a default btree operator class for the data type. +CREATE TABLE partitioned ( + a point +) PARTITION BY LIST (a point_ops); +ERROR: operator class "point_ops" does not exist for access method "btree" +CREATE TABLE partitioned ( + a point +) PARTITION BY RANGE (a); +ERROR: data type point has no default btree operator class +HINT: You must specify a btree operator class or define a default btree operator class for the data type. +CREATE TABLE partitioned ( + a point +) PARTITION BY RANGE (a point_ops); +ERROR: operator class "point_ops" does not exist for access method "btree" +-- cannot add NO INHERIT constraints to partitioned tables +CREATE TABLE partitioned ( + a int, + CONSTRAINT check_a CHECK (a > 0) NO INHERIT +) PARTITION BY RANGE (a); +ERROR: cannot add NO INHERIT constraint to partitioned table "partitioned" +-- some checks after successful creation of a partitioned table +CREATE FUNCTION plusone(a int) RETURNS INT AS $$ SELECT a+1; $$ LANGUAGE SQL; +CREATE TABLE partitioned ( + a int, + b int, + c text, + d text +) PARTITION BY RANGE (a oid_ops, plusone(b), c collate "default", d collate "C"); +-- check relkind +SELECT relkind FROM pg_class WHERE relname = 'partitioned'; + relkind +--------- + P +(1 row) + +-- check that range partition key columns are marked NOT NULL +SELECT attname, attnotnull FROM pg_attribute + WHERE attrelid = 'partitioned'::regclass AND attnum > 0 + ORDER BY attnum; + attname | attnotnull +---------+------------ + a | t + b | f + c | t + d | t +(4 rows) + +-- prevent a function referenced in partition key from being dropped +DROP FUNCTION plusone(int); +ERROR: cannot drop function plusone(integer) because other objects depend on it +DETAIL: table partitioned depends on function plusone(integer) +HINT: Use DROP ... CASCADE to drop the dependent objects too. +-- partitioned table cannot partiticipate in regular inheritance +CREATE TABLE partitioned2 ( + a int +) PARTITION BY LIST ((a+1)); +CREATE TABLE fail () INHERITS (partitioned2); +ERROR: cannot inherit from partitioned table "partitioned2" +-- Partition key in describe output +\d partitioned + Table "public.partitioned" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | not null | + b | integer | | | + c | text | | not null | + d | text | | not null | +Partition key: RANGE (a oid_ops, plusone(b), c, d COLLATE "C") + +\d partitioned2 + Table "public.partitioned2" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | +Partition key: LIST ((a + 1)) + +DROP TABLE partitioned, partitioned2; +-- +-- Partitions +-- +-- check partition bound syntax +CREATE TABLE list_parted ( + a int +) PARTITION BY LIST (a); +-- syntax allows only string literal, numeric literal and null to be +-- specified for a partition bound value +CREATE TABLE part_1 PARTITION OF list_parted FOR VALUES IN ('1'); +CREATE TABLE part_2 PARTITION OF list_parted FOR VALUES IN (2); +CREATE TABLE part_null PARTITION OF list_parted FOR VALUES IN (null); +CREATE TABLE fail_part PARTITION OF list_parted FOR VALUES IN (int '1'); +ERROR: syntax error at or near "int" +LINE 1: ... fail_part PARTITION OF list_parted FOR VALUES IN (int '1'); + ^ +CREATE TABLE fail_part PARTITION OF list_parted FOR VALUES IN ('1'::int); +ERROR: syntax error at or near "::" +LINE 1: ...fail_part PARTITION OF list_parted FOR VALUES IN ('1'::int); + ^ +-- syntax does not allow empty list of values for list partitions +CREATE TABLE fail_part PARTITION OF list_parted FOR VALUES IN (); +ERROR: syntax error at or near ")" +LINE 1: ...E TABLE fail_part PARTITION OF list_parted FOR VALUES IN (); + ^ +-- trying to specify range for list partitioned table +CREATE TABLE fail_part PARTITION OF list_parted FOR VALUES FROM (1) TO (2); +ERROR: invalid bound specification for a list partition +LINE 1: ...BLE fail_part PARTITION OF list_parted FOR VALUES FROM (1) T... + ^ +-- specified literal can't be cast to the partition column data type +CREATE TABLE bools ( + a bool +) PARTITION BY LIST (a); +CREATE TABLE bools_true PARTITION OF bools FOR VALUES IN (1); +ERROR: specified value cannot be cast to type "boolean" of column "a" +LINE 1: ...REATE TABLE bools_true PARTITION OF bools FOR VALUES IN (1); + ^ +DROP TABLE bools; +CREATE TABLE range_parted ( + a date +) PARTITION BY RANGE (a); +-- trying to specify list for range partitioned table +CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES IN ('a'); +ERROR: invalid bound specification for a range partition +LINE 1: ...BLE fail_part PARTITION OF range_parted FOR VALUES IN ('a'); + ^ +-- each of start and end bounds must have same number of values as the +-- length of the partition key +CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES FROM ('a', 1) TO ('z'); +ERROR: FROM must specify exactly one value per partitioning column +CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES FROM ('a') TO ('z', 1); +ERROR: TO must specify exactly one value per partitioning column +-- cannot specify null values in range bounds +CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES FROM (null) TO (unbounded); +ERROR: cannot specify NULL in range bound +-- check if compatible with the specified parent +-- cannot create as partition of a non-partitioned table +CREATE TABLE unparted ( + a int +); +CREATE TABLE fail_part PARTITION OF unparted FOR VALUES IN ('a'); +ERROR: "unparted" is not partitioned +DROP TABLE unparted; +-- cannot create a permanent rel as partition of a temp rel +CREATE TEMP TABLE temp_parted ( + a int +) PARTITION BY LIST (a); +CREATE TABLE fail_part PARTITION OF temp_parted FOR VALUES IN ('a'); +ERROR: cannot create a permanent relation as partition of temporary relation "temp_parted" +DROP TABLE temp_parted; +-- cannot create a table with oids as partition of table without oids +CREATE TABLE no_oids_parted ( + a int +) PARTITION BY RANGE (a) WITHOUT OIDS; +CREATE TABLE fail_part PARTITION OF no_oids_parted FOR VALUES FROM (1) TO (10 )WITH OIDS; +ERROR: cannot create table with OIDs as partition of table without OIDs +DROP TABLE no_oids_parted; +-- likewise, the reverse if also true +CREATE TABLE oids_parted ( + a int +) PARTITION BY RANGE (a) WITH OIDS; +CREATE TABLE fail_part PARTITION OF oids_parted FOR VALUES FROM (1) TO (10 ) WITHOUT OIDS; +ERROR: cannot create table without OIDs as partition of table with OIDs +DROP TABLE oids_parted; +-- check for partition bound overlap and other invalid specifications +CREATE TABLE list_parted2 ( + a varchar +) PARTITION BY LIST (a); +CREATE TABLE part_null_z PARTITION OF list_parted2 FOR VALUES IN (null, 'z'); +CREATE TABLE part_ab PARTITION OF list_parted2 FOR VALUES IN ('a', 'b'); +CREATE TABLE fail_part PARTITION OF list_parted2 FOR VALUES IN (null); +ERROR: partition "fail_part" would overlap partition "part_null_z" +CREATE TABLE fail_part PARTITION OF list_parted2 FOR VALUES IN ('b', 'c'); +ERROR: partition "fail_part" would overlap partition "part_ab" +CREATE TABLE range_parted2 ( + a int +) PARTITION BY RANGE (a); +-- trying to create range partition with empty range +CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (1) TO (0); +ERROR: cannot create range partition with empty range +-- note that the range '[1, 1)' has no elements +CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (1) TO (1); +ERROR: cannot create range partition with empty range +CREATE TABLE part0 PARTITION OF range_parted2 FOR VALUES FROM (unbounded) TO (1); +CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (unbounded) TO (2); +ERROR: partition "fail_part" would overlap partition "part0" +CREATE TABLE part1 PARTITION OF range_parted2 FOR VALUES FROM (1) TO (10); +CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (9) TO (unbounded); +ERROR: partition "fail_part" would overlap partition "part1" +CREATE TABLE part2 PARTITION OF range_parted2 FOR VALUES FROM (20) TO (30); +CREATE TABLE part3 PARTITION OF range_parted2 FOR VALUES FROM (30) TO (40); +CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (10) TO (30); +ERROR: partition "fail_part" would overlap partition "part2" +CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (10) TO (50); +ERROR: partition "fail_part" would overlap partition "part3" +-- now check for multi-column range partition key +CREATE TABLE range_parted3 ( + a int, + b int +) PARTITION BY RANGE (a, (b+1)); +CREATE TABLE part00 PARTITION OF range_parted3 FOR VALUES FROM (0, unbounded) TO (0, unbounded); +CREATE TABLE fail_part PARTITION OF range_parted3 FOR VALUES FROM (0, unbounded) TO (0, 1); +ERROR: partition "fail_part" would overlap partition "part00" +CREATE TABLE part10 PARTITION OF range_parted3 FOR VALUES FROM (1, unbounded) TO (1, 1); +CREATE TABLE part11 PARTITION OF range_parted3 FOR VALUES FROM (1, 1) TO (1, 10); +CREATE TABLE part12 PARTITION OF range_parted3 FOR VALUES FROM (1, 10) TO (1, unbounded); +CREATE TABLE fail_part PARTITION OF range_parted3 FOR VALUES FROM (1, 10) TO (1, 20); +ERROR: partition "fail_part" would overlap partition "part12" +-- cannot create a partition that says column b is allowed to range +-- from -infinity to +infinity, while there exist partitions that have +-- more specific ranges +CREATE TABLE fail_part PARTITION OF range_parted3 FOR VALUES FROM (1, unbounded) TO (1, unbounded); +ERROR: partition "fail_part" would overlap partition "part10" +-- check schema propagation from parent +CREATE TABLE parted ( + a text, + b int NOT NULL DEFAULT 0, + CONSTRAINT check_a CHECK (length(a) > 0) +) PARTITION BY LIST (a); +CREATE TABLE part_a PARTITION OF parted FOR VALUES IN ('a'); +-- only inherited attributes (never local ones) +SELECT attname, attislocal, attinhcount FROM pg_attribute + WHERE attrelid = 'part_a'::regclass and attnum > 0 + ORDER BY attnum; + attname | attislocal | attinhcount +---------+------------+------------- + a | f | 1 + b | f | 1 +(2 rows) + +-- able to specify column default, column constraint, and table constraint +CREATE TABLE part_b PARTITION OF parted ( + b NOT NULL DEFAULT 1 CHECK (b >= 0), + CONSTRAINT check_a CHECK (length(a) > 0) +) FOR VALUES IN ('b'); +NOTICE: merging constraint "check_a" with inherited definition +-- conislocal should be false for any merged constraints +SELECT conislocal, coninhcount FROM pg_constraint WHERE conrelid = 'part_b'::regclass AND conname = 'check_a'; + conislocal | coninhcount +------------+------------- + f | 1 +(1 row) + +-- specify PARTITION BY for a partition +CREATE TABLE fail_part_col_not_found PARTITION OF parted FOR VALUES IN ('c') PARTITION BY RANGE (c); +ERROR: column "c" named in partition key does not exist +CREATE TABLE part_c PARTITION OF parted FOR VALUES IN ('c') PARTITION BY RANGE ((b)); +-- create a level-2 partition +CREATE TABLE part_c_1_10 PARTITION OF part_c FOR VALUES FROM (1) TO (10); +-- Partition bound in describe output +\d part_b + Table "public.part_b" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | text | | | + b | integer | | not null | 1 +Partition of: parted FOR VALUES IN ('b') +Check constraints: + "check_a" CHECK (length(a) > 0) + "part_b_b_check" CHECK (b >= 0) + +-- Both partition bound and partition key in describe output +\d part_c + Table "public.part_c" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | text | | | + b | integer | | not null | 0 +Partition of: parted FOR VALUES IN ('c') +Partition key: RANGE (b) +Check constraints: + "check_a" CHECK (length(a) > 0) +Number of partitions: 1 (Use \d+ to list them.) + +-- Show partition count in the parent's describe output +-- Tempted to include \d+ output listing partitions with bound info but +-- output could vary depending on the order in which partition oids are +-- returned. +\d parted + Table "public.parted" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | text | | | + b | integer | | not null | 0 +Partition key: LIST (a) +Check constraints: + "check_a" CHECK (length(a) > 0) +Number of partitions: 3 (Use \d+ to list them.) + +-- cleanup: avoid using CASCADE +DROP TABLE parted, part_a, part_b, part_c, part_c_1_10; +DROP TABLE list_parted, part_1, part_2, part_null; +DROP TABLE range_parted; +DROP TABLE list_parted2, part_ab, part_null_z; +DROP TABLE range_parted2, part0, part1, part2, part3; +DROP TABLE range_parted3, part00, part10, part11, part12; diff --git a/src/test/regress/expected/create_table_like.out b/src/test/regress/expected/create_table_like.out index 97edde17cf..a25b221703 100644 --- a/src/test/regress/expected/create_table_like.out +++ b/src/test/regress/expected/create_table_like.out @@ -109,32 +109,32 @@ CREATE TABLE ctlt4 (a text, c text); ALTER TABLE ctlt4 ALTER COLUMN c SET STORAGE EXTERNAL; CREATE TABLE ctlt12_storage (LIKE ctlt1 INCLUDING STORAGE, LIKE ctlt2 INCLUDING STORAGE); \d+ ctlt12_storage - Table "public.ctlt12_storage" - Column | Type | Modifiers | Storage | Stats target | Description ---------+------+-----------+----------+--------------+------------- - a | text | not null | main | | - b | text | | extended | | - c | text | | external | | + Table "public.ctlt12_storage" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+------+-----------+----------+---------+----------+--------------+------------- + a | text | | not null | | main | | + b | text | | | | extended | | + c | text | | | | external | | CREATE TABLE ctlt12_comments (LIKE ctlt1 INCLUDING COMMENTS, LIKE ctlt2 INCLUDING COMMENTS); \d+ ctlt12_comments - Table "public.ctlt12_comments" - Column | Type | Modifiers | Storage | Stats target | Description ---------+------+-----------+----------+--------------+------------- - a | text | not null | extended | | A - b | text | | extended | | B - c | text | | extended | | C + Table "public.ctlt12_comments" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+------+-----------+----------+---------+----------+--------------+------------- + a | text | | not null | | extended | | A + b | text | | | | extended | | B + c | text | | | | extended | | C CREATE TABLE ctlt1_inh (LIKE ctlt1 INCLUDING CONSTRAINTS INCLUDING COMMENTS) INHERITS (ctlt1); NOTICE: merging column "a" with inherited definition NOTICE: merging column "b" with inherited definition NOTICE: merging constraint "ctlt1_a_check" with inherited definition \d+ ctlt1_inh - Table "public.ctlt1_inh" - Column | Type | Modifiers | Storage | Stats target | Description ---------+------+-----------+----------+--------------+------------- - a | text | not null | main | | A - b | text | | extended | | B + Table "public.ctlt1_inh" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+------+-----------+----------+---------+----------+--------------+------------- + a | text | | not null | | main | | A + b | text | | | | extended | | B Check constraints: "ctlt1_a_check" CHECK (length(a) > 2) Inherits: ctlt1 @@ -148,12 +148,12 @@ SELECT description FROM pg_description, pg_constraint c WHERE classoid = 'pg_con CREATE TABLE ctlt13_inh () INHERITS (ctlt1, ctlt3); NOTICE: merging multiple inherited definitions of column "a" \d+ ctlt13_inh - Table "public.ctlt13_inh" - Column | Type | Modifiers | Storage | Stats target | Description ---------+------+-----------+----------+--------------+------------- - a | text | not null | main | | - b | text | | extended | | - c | text | | external | | + Table "public.ctlt13_inh" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+------+-----------+----------+---------+----------+--------------+------------- + a | text | | not null | | main | | + b | text | | | | extended | | + c | text | | | | external | | Check constraints: "ctlt1_a_check" CHECK (length(a) > 2) "ctlt3_a_check" CHECK (length(a) < 5) @@ -163,12 +163,12 @@ Inherits: ctlt1, CREATE TABLE ctlt13_like (LIKE ctlt3 INCLUDING CONSTRAINTS INCLUDING COMMENTS INCLUDING STORAGE) INHERITS (ctlt1); NOTICE: merging column "a" with inherited definition \d+ ctlt13_like - Table "public.ctlt13_like" - Column | Type | Modifiers | Storage | Stats target | Description ---------+------+-----------+----------+--------------+------------- - a | text | not null | main | | A3 - b | text | | extended | | - c | text | | external | | C + Table "public.ctlt13_like" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+------+-----------+----------+---------+----------+--------------+------------- + a | text | | not null | | main | | A3 + b | text | | | | extended | | + c | text | | | | external | | C Check constraints: "ctlt1_a_check" CHECK (length(a) > 2) "ctlt3_a_check" CHECK (length(a) < 5) @@ -182,11 +182,11 @@ SELECT description FROM pg_description, pg_constraint c WHERE classoid = 'pg_con CREATE TABLE ctlt_all (LIKE ctlt1 INCLUDING ALL); \d+ ctlt_all - Table "public.ctlt_all" - Column | Type | Modifiers | Storage | Stats target | Description ---------+------+-----------+----------+--------------+------------- - a | text | not null | main | | A - b | text | | extended | | B + Table "public.ctlt_all" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+------+-----------+----------+---------+----------+--------------+------------- + a | text | | not null | | main | | A + b | text | | | | extended | | B Indexes: "ctlt_all_pkey" PRIMARY KEY, btree (a) "ctlt_all_b_idx" btree (b) @@ -254,4 +254,11 @@ SELECT oid FROM like_test4; ----- (0 rows) -DROP TABLE has_oid, no_oid, like_test, like_test2, like_test3, like_test4; +CREATE TABLE like_test5 (z INTEGER, LIKE no_oid) WITH OIDS; +SELECT oid FROM like_test5; + oid +----- +(0 rows) + +DROP TABLE has_oid, no_oid, like_test, like_test2, like_test3, + like_test4, like_test5; diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out index 81b4e8d42b..096bfc30c9 100644 --- a/src/test/regress/expected/create_view.out +++ b/src/test/regress/expected/create_view.out @@ -288,6 +288,43 @@ SELECT relname, relkind, reloptions FROM pg_class mysecview4 | v | {security_barrier=false} (4 rows) +-- This test checks that proper typmods are assigned in a multi-row VALUES +CREATE VIEW tt1 AS + SELECT * FROM ( + VALUES + ('abc'::varchar(3), '0123456789', 42, 'abcd'::varchar(4)), + ('0123456789', 'abc'::varchar(3), 42.12, 'abc'::varchar(4)) + ) vv(a,b,c,d); +\d+ tt1 + View "testviewschm2.tt1" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+----------------------+-----------+----------+---------+----------+------------- + a | character varying | | | | extended | + b | character varying | | | | extended | + c | numeric | | | | main | + d | character varying(4) | | | | extended | +View definition: + SELECT vv.a, + vv.b, + vv.c, + vv.d + FROM ( VALUES ('abc'::character varying(3),'0123456789'::character varying,42,'abcd'::character varying(4)), ('0123456789'::character varying,'abc'::character varying(3),42.12,'abc'::character varying(4))) vv(a, b, c, d); + +SELECT * FROM tt1; + a | b | c | d +------------+------------+-------+------ + abc | 0123456789 | 42 | abcd + 0123456789 | abc | 42.12 | abc +(2 rows) + +SELECT a::varchar(3) FROM tt1; + a +----- + abc + 012 +(2 rows) + +DROP VIEW tt1; -- Test view decompilation in the face of relation renaming conflicts CREATE TABLE tt1 (f1 int, f2 int, f3 text); CREATE TABLE tx1 (x1 int, x2 int, x3 text); @@ -305,12 +342,12 @@ CREATE VIEW aliased_view_4 AS select * from temp_view_test.tt1 where exists (select 1 from tt1 where temp_view_test.tt1.y1 = tt1.f1); \d+ aliased_view_1 - View "testviewschm2.aliased_view_1" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - f1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_1" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + f1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT tt1.f1, tt1.f2, @@ -321,12 +358,12 @@ View definition: WHERE tt1.f1 = tx1.x1)); \d+ aliased_view_2 - View "testviewschm2.aliased_view_2" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - f1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_2" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + f1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT a1.f1, a1.f2, @@ -337,12 +374,12 @@ View definition: WHERE a1.f1 = tx1.x1)); \d+ aliased_view_3 - View "testviewschm2.aliased_view_3" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - f1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_3" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + f1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT tt1.f1, tt1.f2, @@ -353,12 +390,12 @@ View definition: WHERE tt1.f1 = a2.x1)); \d+ aliased_view_4 - View "testviewschm2.aliased_view_4" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - y1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_4" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + y1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT tt1.y1, tt1.f2, @@ -370,12 +407,12 @@ View definition: ALTER TABLE tx1 RENAME TO a1; \d+ aliased_view_1 - View "testviewschm2.aliased_view_1" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - f1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_1" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + f1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT tt1.f1, tt1.f2, @@ -386,12 +423,12 @@ View definition: WHERE tt1.f1 = a1.x1)); \d+ aliased_view_2 - View "testviewschm2.aliased_view_2" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - f1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_2" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + f1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT a1.f1, a1.f2, @@ -402,12 +439,12 @@ View definition: WHERE a1.f1 = a1_1.x1)); \d+ aliased_view_3 - View "testviewschm2.aliased_view_3" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - f1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_3" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + f1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT tt1.f1, tt1.f2, @@ -418,12 +455,12 @@ View definition: WHERE tt1.f1 = a2.x1)); \d+ aliased_view_4 - View "testviewschm2.aliased_view_4" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - y1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_4" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + y1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT tt1.y1, tt1.f2, @@ -435,12 +472,12 @@ View definition: ALTER TABLE tt1 RENAME TO a2; \d+ aliased_view_1 - View "testviewschm2.aliased_view_1" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - f1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_1" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + f1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT a2.f1, a2.f2, @@ -451,12 +488,12 @@ View definition: WHERE a2.f1 = a1.x1)); \d+ aliased_view_2 - View "testviewschm2.aliased_view_2" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - f1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_2" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + f1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT a1.f1, a1.f2, @@ -467,12 +504,12 @@ View definition: WHERE a1.f1 = a1_1.x1)); \d+ aliased_view_3 - View "testviewschm2.aliased_view_3" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - f1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_3" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + f1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT a2.f1, a2.f2, @@ -483,12 +520,12 @@ View definition: WHERE a2.f1 = a2_1.x1)); \d+ aliased_view_4 - View "testviewschm2.aliased_view_4" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - y1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_4" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + y1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT tt1.y1, tt1.f2, @@ -500,12 +537,12 @@ View definition: ALTER TABLE a1 RENAME TO tt1; \d+ aliased_view_1 - View "testviewschm2.aliased_view_1" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - f1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_1" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + f1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT a2.f1, a2.f2, @@ -516,12 +553,12 @@ View definition: WHERE a2.f1 = tt1.x1)); \d+ aliased_view_2 - View "testviewschm2.aliased_view_2" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - f1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_2" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + f1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT a1.f1, a1.f2, @@ -532,12 +569,12 @@ View definition: WHERE a1.f1 = tt1.x1)); \d+ aliased_view_3 - View "testviewschm2.aliased_view_3" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - f1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_3" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + f1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT a2.f1, a2.f2, @@ -548,12 +585,12 @@ View definition: WHERE a2.f1 = a2_1.x1)); \d+ aliased_view_4 - View "testviewschm2.aliased_view_4" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - y1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_4" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + y1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT tt1.y1, tt1.f2, @@ -566,12 +603,12 @@ View definition: ALTER TABLE a2 RENAME TO tx1; ALTER TABLE tx1 SET SCHEMA temp_view_test; \d+ aliased_view_1 - View "testviewschm2.aliased_view_1" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - f1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_1" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + f1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT tx1.f1, tx1.f2, @@ -582,12 +619,12 @@ View definition: WHERE tx1.f1 = tt1.x1)); \d+ aliased_view_2 - View "testviewschm2.aliased_view_2" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - f1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_2" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + f1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT a1.f1, a1.f2, @@ -598,12 +635,12 @@ View definition: WHERE a1.f1 = tt1.x1)); \d+ aliased_view_3 - View "testviewschm2.aliased_view_3" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - f1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_3" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + f1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT tx1.f1, tx1.f2, @@ -614,12 +651,12 @@ View definition: WHERE tx1.f1 = a2.x1)); \d+ aliased_view_4 - View "testviewschm2.aliased_view_4" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - y1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_4" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + y1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT tt1.y1, tt1.f2, @@ -633,12 +670,12 @@ ALTER TABLE temp_view_test.tt1 RENAME TO tmp1; ALTER TABLE temp_view_test.tmp1 SET SCHEMA testviewschm2; ALTER TABLE tmp1 RENAME TO tx1; \d+ aliased_view_1 - View "testviewschm2.aliased_view_1" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - f1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_1" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + f1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT tx1.f1, tx1.f2, @@ -649,12 +686,12 @@ View definition: WHERE tx1.f1 = tt1.x1)); \d+ aliased_view_2 - View "testviewschm2.aliased_view_2" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - f1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_2" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + f1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT a1.f1, a1.f2, @@ -665,12 +702,12 @@ View definition: WHERE a1.f1 = tt1.x1)); \d+ aliased_view_3 - View "testviewschm2.aliased_view_3" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - f1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_3" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + f1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT tx1.f1, tx1.f2, @@ -681,12 +718,12 @@ View definition: WHERE tx1.f1 = a2.x1)); \d+ aliased_view_4 - View "testviewschm2.aliased_view_4" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+----------+------------- - y1 | integer | | plain | - f2 | integer | | plain | - f3 | text | | extended | + View "testviewschm2.aliased_view_4" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+----------+------------- + y1 | integer | | | | plain | + f2 | integer | | | | plain | + f3 | text | | | | extended | View definition: SELECT tx1.y1, tx1.f2, diff --git a/src/test/regress/expected/date.out b/src/test/regress/expected/date.out index 418b146425..1bcc9465a9 100644 --- a/src/test/regress/expected/date.out +++ b/src/test/regress/expected/date.out @@ -1454,6 +1454,12 @@ select make_date(2013, 7, 15); 07-15-2013 (1 row) +select make_date(-44, 3, 15); + make_date +--------------- + 03-15-0044 BC +(1 row) + select make_time(8, 20, 0.0); make_time ----------- @@ -1467,8 +1473,6 @@ select make_date(2013, 13, 1); ERROR: date field value out of range: 2013-13-01 select make_date(2013, 11, -1); ERROR: date field value out of range: 2013-11--1 -select make_date(-44, 3, 15); -- perhaps we should allow this sometime? -ERROR: date field value out of range: -44-03-15 select make_time(10, 55, 100.1); ERROR: time field value out of range: 10:55:100.1 select make_time(24, 0, 2.1); diff --git a/src/test/regress/expected/enum.out b/src/test/regress/expected/enum.out index 1a61a5b0df..514d1d01a1 100644 --- a/src/test/regress/expected/enum.out +++ b/src/test/regress/expected/enum.out @@ -556,29 +556,98 @@ CREATE TABLE enumtest_bogus_child(parent bogus REFERENCES enumtest_parent); ERROR: foreign key constraint "enumtest_bogus_child_parent_fkey" cannot be implemented DETAIL: Key columns "parent" and "id" are of incompatible types: bogus and rainbow. DROP TYPE bogus; +-- check renaming a value +ALTER TYPE rainbow RENAME VALUE 'red' TO 'crimson'; +SELECT enumlabel, enumsortorder +FROM pg_enum +WHERE enumtypid = 'rainbow'::regtype +ORDER BY 2; + enumlabel | enumsortorder +-----------+--------------- + crimson | 1 + orange | 2 + yellow | 3 + green | 4 + blue | 5 + purple | 6 +(6 rows) + +-- check that renaming a non-existent value fails +ALTER TYPE rainbow RENAME VALUE 'red' TO 'crimson'; +ERROR: "red" is not an existing enum label +-- check that renaming to an existent value fails +ALTER TYPE rainbow RENAME VALUE 'blue' TO 'green'; +ERROR: enum label "green" already exists -- -- check transactional behaviour of ALTER TYPE ... ADD VALUE -- CREATE TYPE bogus AS ENUM('good'); --- check that we can't add new values to existing enums in a transaction +-- check that we can add new values to existing enums in a transaction +-- but we can't use them BEGIN; -ALTER TYPE bogus ADD VALUE 'bad'; -ERROR: ALTER TYPE ... ADD cannot run inside a transaction block +ALTER TYPE bogus ADD VALUE 'new'; +SAVEPOINT x; +SELECT 'new'::bogus; -- unsafe +ERROR: unsafe use of new value "new" of enum type bogus +LINE 1: SELECT 'new'::bogus; + ^ +HINT: New enum values must be committed before they can be used. +ROLLBACK TO x; +SELECT enum_first(null::bogus); -- safe + enum_first +------------ + good +(1 row) + +SELECT enum_last(null::bogus); -- unsafe +ERROR: unsafe use of new value "new" of enum type bogus +HINT: New enum values must be committed before they can be used. +ROLLBACK TO x; +SELECT enum_range(null::bogus); -- unsafe +ERROR: unsafe use of new value "new" of enum type bogus +HINT: New enum values must be committed before they can be used. +ROLLBACK TO x; COMMIT; +SELECT 'new'::bogus; -- now safe + bogus +------- + new +(1 row) + +SELECT enumlabel, enumsortorder +FROM pg_enum +WHERE enumtypid = 'bogus'::regtype +ORDER BY 2; + enumlabel | enumsortorder +-----------+--------------- + good | 1 + new | 2 +(2 rows) + -- check that we recognize the case where the enum already existed but was --- modified in the current txn +-- modified in the current txn; this should not be considered safe BEGIN; ALTER TYPE bogus RENAME TO bogon; ALTER TYPE bogon ADD VALUE 'bad'; -ERROR: ALTER TYPE ... ADD cannot run inside a transaction block +SELECT 'bad'::bogon; +ERROR: unsafe use of new value "bad" of enum type bogon +LINE 1: SELECT 'bad'::bogon; + ^ +HINT: New enum values must be committed before they can be used. ROLLBACK; DROP TYPE bogus; --- check that we *can* add new values to existing enums in a transaction, --- if the type is new as well +-- check that we can add new values to existing enums in a transaction +-- and use them, if the type is new as well BEGIN; -CREATE TYPE bogus AS ENUM(); -ALTER TYPE bogus ADD VALUE 'good'; +CREATE TYPE bogus AS ENUM('good'); +ALTER TYPE bogus ADD VALUE 'bad'; ALTER TYPE bogus ADD VALUE 'ugly'; +SELECT enum_range(null::bogus); + enum_range +----------------- + {good,bad,ugly} +(1 row) + ROLLBACK; -- -- Cleanup diff --git a/src/test/regress/expected/equivclass.out b/src/test/regress/expected/equivclass.out index 0391b8eec1..564218b767 100644 --- a/src/test/regress/expected/equivclass.out +++ b/src/test/regress/expected/equivclass.out @@ -381,3 +381,45 @@ explain (costs off) Index Cond: (ff = '42'::bigint) (14 rows) +-- check effects of row-level security +set enable_nestloop = on; +set enable_mergejoin = off; +alter table ec1 enable row level security; +create policy p1 on ec1 using (f1 < '5'::int8alias1); +create user regress_user_ectest; +grant select on ec0 to regress_user_ectest; +grant select on ec1 to regress_user_ectest; +-- without any RLS, we'll treat {a.ff, b.ff, 43} as an EquivalenceClass +explain (costs off) + select * from ec0 a, ec1 b + where a.ff = b.ff and a.ff = 43::bigint::int8alias1; + QUERY PLAN +--------------------------------------------- + Nested Loop + -> Index Scan using ec0_pkey on ec0 a + Index Cond: (ff = '43'::int8alias1) + -> Index Scan using ec1_pkey on ec1 b + Index Cond: (ff = '43'::int8alias1) +(5 rows) + +set session authorization regress_user_ectest; +-- with RLS active, the non-leakproof a.ff = 43 clause is not treated +-- as a suitable source for an EquivalenceClass; currently, this is true +-- even though the RLS clause has nothing to do directly with the EC +explain (costs off) + select * from ec0 a, ec1 b + where a.ff = b.ff and a.ff = 43::bigint::int8alias1; + QUERY PLAN +--------------------------------------------- + Nested Loop + -> Index Scan using ec0_pkey on ec0 a + Index Cond: (ff = '43'::int8alias1) + -> Index Scan using ec1_pkey on ec1 b + Index Cond: (ff = a.ff) + Filter: (f1 < '5'::int8alias1) +(6 rows) + +reset session authorization; +revoke select on ec0 from regress_user_ectest; +revoke select on ec1 from regress_user_ectest; +drop user regress_user_ectest; diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out index d6c1900c32..3a9fb8f558 100644 --- a/src/test/regress/expected/foreign_data.out +++ b/src/test/regress/expected/foreign_data.out @@ -702,12 +702,12 @@ CREATE FOREIGN TABLE ft1 ( COMMENT ON FOREIGN TABLE ft1 IS 'ft1'; COMMENT ON COLUMN ft1.c1 IS 'ft1.c1'; \d+ ft1 - Foreign table "public.ft1" - Column | Type | Modifiers | FDW Options | Storage | Stats target | Description ---------+---------+-----------+--------------------------------+----------+--------------+------------- - c1 | integer | not null | ("param 1" 'val1') | plain | | ft1.c1 - c2 | text | | (param2 'val2', param3 'val3') | extended | | - c3 | date | | | plain | | + Foreign table "public.ft1" + Column | Type | Collation | Nullable | Default | FDW Options | Storage | Stats target | Description +--------+---------+-----------+----------+---------+--------------------------------+----------+--------------+------------- + c1 | integer | | not null | | ("param 1" 'val1') | plain | | ft1.c1 + c2 | text | | | | (param2 'val2', param3 'val3') | extended | | + c3 | date | | | | | plain | | Check constraints: "ft1_c2_check" CHECK (c2 <> ''::text) "ft1_c3_check" CHECK (c3 >= '01-01-1994'::date AND c3 <= '01-31-1994'::date) @@ -757,19 +757,19 @@ ALTER FOREIGN TABLE ft1 ALTER COLUMN c1 SET (n_distinct = 100); ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET STATISTICS -1; ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET STORAGE PLAIN; \d+ ft1 - Foreign table "public.ft1" - Column | Type | Modifiers | FDW Options | Storage | Stats target | Description ---------+---------+-----------+--------------------------------+----------+--------------+------------- - c1 | integer | not null | ("param 1" 'val1') | plain | 10000 | - c2 | text | | (param2 'val2', param3 'val3') | extended | | - c3 | date | | | plain | | - c4 | integer | default 0 | | plain | | - c5 | integer | | | plain | | - c6 | integer | not null | | plain | | - c7 | integer | | (p1 'v1', p2 'v2') | plain | | - c8 | text | | (p2 'V2') | plain | | - c9 | integer | | | plain | | - c10 | integer | | (p1 'v1') | plain | | + Foreign table "public.ft1" + Column | Type | Collation | Nullable | Default | FDW Options | Storage | Stats target | Description +--------+---------+-----------+----------+---------+--------------------------------+----------+--------------+------------- + c1 | integer | | not null | | ("param 1" 'val1') | plain | 10000 | + c2 | text | | | | (param2 'val2', param3 'val3') | extended | | + c3 | date | | | | | plain | | + c4 | integer | | | 0 | | plain | | + c5 | integer | | | | | plain | | + c6 | integer | | not null | | | plain | | + c7 | integer | | | | (p1 'v1', p2 'v2') | plain | | + c8 | text | | | | (p2 'V2') | plain | | + c9 | integer | | | | | plain | | + c10 | integer | | | | (p1 'v1') | plain | | Check constraints: "ft1_c2_check" CHECK (c2 <> ''::text) "ft1_c3_check" CHECK (c3 >= '01-01-1994'::date AND c3 <= '01-31-1994'::date) @@ -807,18 +807,18 @@ ERROR: relation "ft1" does not exist ALTER FOREIGN TABLE foreign_schema.ft1 RENAME c1 TO foreign_column_1; ALTER FOREIGN TABLE foreign_schema.ft1 RENAME TO foreign_table_1; \d foreign_schema.foreign_table_1 - Foreign table "foreign_schema.foreign_table_1" - Column | Type | Modifiers | FDW Options -------------------+---------+-----------+-------------------------------- - foreign_column_1 | integer | not null | ("param 1" 'val1') - c2 | text | | (param2 'val2', param3 'val3') - c3 | date | | - c4 | integer | default 0 | - c5 | integer | | - c6 | integer | not null | - c7 | integer | | (p1 'v1', p2 'v2') - c8 | text | | (p2 'V2') - c10 | integer | | (p1 'v1') + Foreign table "foreign_schema.foreign_table_1" + Column | Type | Collation | Nullable | Default | FDW Options +------------------+---------+-----------+----------+---------+-------------------------------- + foreign_column_1 | integer | | not null | | ("param 1" 'val1') + c2 | text | | | | (param2 'val2', param3 'val3') + c3 | date | | | | + c4 | integer | | | 0 | + c5 | integer | | | | + c6 | integer | | not null | | + c7 | integer | | | | (p1 'v1', p2 'v2') + c8 | text | | | | (p2 'V2') + c10 | integer | | | | (p1 'v1') Check constraints: "ft1_c2_check" CHECK (c2 <> ''::text) "ft1_c3_check" CHECK (c3 >= '01-01-1994'::date AND c3 <= '01-31-1994'::date) @@ -1241,33 +1241,33 @@ CREATE TABLE pt1 ( CREATE FOREIGN TABLE ft2 () INHERITS (pt1) SERVER s0 OPTIONS (delimiter ',', quote '"', "be quoted" 'value'); \d+ pt1 - Table "public.pt1" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- - c1 | integer | not null | plain | | - c2 | text | | extended | | - c3 | date | | plain | | + Table "public.pt1" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+----------+--------------+------------- + c1 | integer | | not null | | plain | | + c2 | text | | | | extended | | + c3 | date | | | | plain | | Child tables: ft2 \d+ ft2 - Foreign table "public.ft2" - Column | Type | Modifiers | FDW Options | Storage | Stats target | Description ---------+---------+-----------+-------------+----------+--------------+------------- - c1 | integer | not null | | plain | | - c2 | text | | | extended | | - c3 | date | | | plain | | + Foreign table "public.ft2" + Column | Type | Collation | Nullable | Default | FDW Options | Storage | Stats target | Description +--------+---------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | integer | | not null | | | plain | | + c2 | text | | | | | extended | | + c3 | date | | | | | plain | | Server: s0 FDW Options: (delimiter ',', quote '"', "be quoted" 'value') Inherits: pt1 DROP FOREIGN TABLE ft2; \d+ pt1 - Table "public.pt1" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- - c1 | integer | not null | plain | | - c2 | text | | extended | | - c3 | date | | plain | | + Table "public.pt1" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+----------+--------------+------------- + c1 | integer | | not null | | plain | | + c2 | text | | | | extended | | + c3 | date | | | | plain | | CREATE FOREIGN TABLE ft2 ( c1 integer NOT NULL, @@ -1275,32 +1275,32 @@ CREATE FOREIGN TABLE ft2 ( c3 date ) SERVER s0 OPTIONS (delimiter ',', quote '"', "be quoted" 'value'); \d+ ft2 - Foreign table "public.ft2" - Column | Type | Modifiers | FDW Options | Storage | Stats target | Description ---------+---------+-----------+-------------+----------+--------------+------------- - c1 | integer | not null | | plain | | - c2 | text | | | extended | | - c3 | date | | | plain | | + Foreign table "public.ft2" + Column | Type | Collation | Nullable | Default | FDW Options | Storage | Stats target | Description +--------+---------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | integer | | not null | | | plain | | + c2 | text | | | | | extended | | + c3 | date | | | | | plain | | Server: s0 FDW Options: (delimiter ',', quote '"', "be quoted" 'value') ALTER FOREIGN TABLE ft2 INHERIT pt1; \d+ pt1 - Table "public.pt1" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- - c1 | integer | not null | plain | | - c2 | text | | extended | | - c3 | date | | plain | | + Table "public.pt1" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+----------+--------------+------------- + c1 | integer | | not null | | plain | | + c2 | text | | | | extended | | + c3 | date | | | | plain | | Child tables: ft2 \d+ ft2 - Foreign table "public.ft2" - Column | Type | Modifiers | FDW Options | Storage | Stats target | Description ---------+---------+-----------+-------------+----------+--------------+------------- - c1 | integer | not null | | plain | | - c2 | text | | | extended | | - c3 | date | | | plain | | + Foreign table "public.ft2" + Column | Type | Collation | Nullable | Default | FDW Options | Storage | Stats target | Description +--------+---------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | integer | | not null | | | plain | | + c2 | text | | | | | extended | | + c3 | date | | | | | plain | | Server: s0 FDW Options: (delimiter ',', quote '"', "be quoted" 'value') Inherits: pt1 @@ -1316,12 +1316,12 @@ NOTICE: merging column "c1" with inherited definition NOTICE: merging column "c2" with inherited definition NOTICE: merging column "c3" with inherited definition \d+ ft2 - Foreign table "public.ft2" - Column | Type | Modifiers | FDW Options | Storage | Stats target | Description ---------+---------+-----------+-------------+----------+--------------+------------- - c1 | integer | not null | | plain | | - c2 | text | | | extended | | - c3 | date | | | plain | | + Foreign table "public.ft2" + Column | Type | Collation | Nullable | Default | FDW Options | Storage | Stats target | Description +--------+---------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | integer | | not null | | | plain | | + c2 | text | | | | | extended | | + c3 | date | | | | | plain | | Server: s0 FDW Options: (delimiter ',', quote '"', "be quoted" 'value') Inherits: pt1 @@ -1329,21 +1329,21 @@ Child tables: ct3, ft3 \d+ ct3 - Table "public.ct3" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- - c1 | integer | not null | plain | | - c2 | text | | extended | | - c3 | date | | plain | | + Table "public.ct3" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+----------+--------------+------------- + c1 | integer | | not null | | plain | | + c2 | text | | | | extended | | + c3 | date | | | | plain | | Inherits: ft2 \d+ ft3 - Foreign table "public.ft3" - Column | Type | Modifiers | FDW Options | Storage | Stats target | Description ---------+---------+-----------+-------------+----------+--------------+------------- - c1 | integer | not null | | plain | | - c2 | text | | | extended | | - c3 | date | | | plain | | + Foreign table "public.ft3" + Column | Type | Collation | Nullable | Default | FDW Options | Storage | Stats target | Description +--------+---------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | integer | | not null | | | plain | | + c2 | text | | | | | extended | | + c3 | date | | | | | plain | | Server: s0 Inherits: ft2 @@ -1354,31 +1354,31 @@ ALTER TABLE pt1 ADD COLUMN c6 integer; ALTER TABLE pt1 ADD COLUMN c7 integer NOT NULL; ALTER TABLE pt1 ADD COLUMN c8 integer; \d+ pt1 - Table "public.pt1" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- - c1 | integer | not null | plain | | - c2 | text | | extended | | - c3 | date | | plain | | - c4 | integer | | plain | | - c5 | integer | default 0 | plain | | - c6 | integer | | plain | | - c7 | integer | not null | plain | | - c8 | integer | | plain | | + Table "public.pt1" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+----------+--------------+------------- + c1 | integer | | not null | | plain | | + c2 | text | | | | extended | | + c3 | date | | | | plain | | + c4 | integer | | | | plain | | + c5 | integer | | | 0 | plain | | + c6 | integer | | | | plain | | + c7 | integer | | not null | | plain | | + c8 | integer | | | | plain | | Child tables: ft2 \d+ ft2 - Foreign table "public.ft2" - Column | Type | Modifiers | FDW Options | Storage | Stats target | Description ---------+---------+-----------+-------------+----------+--------------+------------- - c1 | integer | not null | | plain | | - c2 | text | | | extended | | - c3 | date | | | plain | | - c4 | integer | | | plain | | - c5 | integer | default 0 | | plain | | - c6 | integer | | | plain | | - c7 | integer | not null | | plain | | - c8 | integer | | | plain | | + Foreign table "public.ft2" + Column | Type | Collation | Nullable | Default | FDW Options | Storage | Stats target | Description +--------+---------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | integer | | not null | | | plain | | + c2 | text | | | | | extended | | + c3 | date | | | | | plain | | + c4 | integer | | | | | plain | | + c5 | integer | | | 0 | | plain | | + c6 | integer | | | | | plain | | + c7 | integer | | not null | | | plain | | + c8 | integer | | | | | plain | | Server: s0 FDW Options: (delimiter ',', quote '"', "be quoted" 'value') Inherits: pt1 @@ -1386,31 +1386,31 @@ Child tables: ct3, ft3 \d+ ct3 - Table "public.ct3" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- - c1 | integer | not null | plain | | - c2 | text | | extended | | - c3 | date | | plain | | - c4 | integer | | plain | | - c5 | integer | default 0 | plain | | - c6 | integer | | plain | | - c7 | integer | not null | plain | | - c8 | integer | | plain | | + Table "public.ct3" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+----------+--------------+------------- + c1 | integer | | not null | | plain | | + c2 | text | | | | extended | | + c3 | date | | | | plain | | + c4 | integer | | | | plain | | + c5 | integer | | | 0 | plain | | + c6 | integer | | | | plain | | + c7 | integer | | not null | | plain | | + c8 | integer | | | | plain | | Inherits: ft2 \d+ ft3 - Foreign table "public.ft3" - Column | Type | Modifiers | FDW Options | Storage | Stats target | Description ---------+---------+-----------+-------------+----------+--------------+------------- - c1 | integer | not null | | plain | | - c2 | text | | | extended | | - c3 | date | | | plain | | - c4 | integer | | | plain | | - c5 | integer | default 0 | | plain | | - c6 | integer | | | plain | | - c7 | integer | not null | | plain | | - c8 | integer | | | plain | | + Foreign table "public.ft3" + Column | Type | Collation | Nullable | Default | FDW Options | Storage | Stats target | Description +--------+---------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | integer | | not null | | | plain | | + c2 | text | | | | | extended | | + c3 | date | | | | | plain | | + c4 | integer | | | | | plain | | + c5 | integer | | | 0 | | plain | | + c6 | integer | | | | | plain | | + c7 | integer | | not null | | | plain | | + c8 | integer | | | | | plain | | Server: s0 Inherits: ft2 @@ -1428,31 +1428,31 @@ ALTER TABLE pt1 ALTER COLUMN c1 SET (n_distinct = 100); ALTER TABLE pt1 ALTER COLUMN c8 SET STATISTICS -1; ALTER TABLE pt1 ALTER COLUMN c8 SET STORAGE EXTERNAL; \d+ pt1 - Table "public.pt1" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- - c1 | integer | not null | plain | 10000 | - c2 | text | | extended | | - c3 | date | | plain | | - c4 | integer | default 0 | plain | | - c5 | integer | | plain | | - c6 | integer | not null | plain | | - c7 | integer | | plain | | - c8 | text | | external | | + Table "public.pt1" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+----------+--------------+------------- + c1 | integer | | not null | | plain | 10000 | + c2 | text | | | | extended | | + c3 | date | | | | plain | | + c4 | integer | | | 0 | plain | | + c5 | integer | | | | plain | | + c6 | integer | | not null | | plain | | + c7 | integer | | | | plain | | + c8 | text | | | | external | | Child tables: ft2 \d+ ft2 - Foreign table "public.ft2" - Column | Type | Modifiers | FDW Options | Storage | Stats target | Description ---------+---------+-----------+-------------+----------+--------------+------------- - c1 | integer | not null | | plain | 10000 | - c2 | text | | | extended | | - c3 | date | | | plain | | - c4 | integer | default 0 | | plain | | - c5 | integer | | | plain | | - c6 | integer | not null | | plain | | - c7 | integer | | | plain | | - c8 | text | | | external | | + Foreign table "public.ft2" + Column | Type | Collation | Nullable | Default | FDW Options | Storage | Stats target | Description +--------+---------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | integer | | not null | | | plain | 10000 | + c2 | text | | | | | extended | | + c3 | date | | | | | plain | | + c4 | integer | | | 0 | | plain | | + c5 | integer | | | | | plain | | + c6 | integer | | not null | | | plain | | + c7 | integer | | | | | plain | | + c8 | text | | | | | external | | Server: s0 FDW Options: (delimiter ',', quote '"', "be quoted" 'value') Inherits: pt1 @@ -1466,21 +1466,21 @@ ALTER TABLE pt1 DROP COLUMN c6; ALTER TABLE pt1 DROP COLUMN c7; ALTER TABLE pt1 DROP COLUMN c8; \d+ pt1 - Table "public.pt1" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- - c1 | integer | not null | plain | 10000 | - c2 | text | | extended | | - c3 | date | | plain | | + Table "public.pt1" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+----------+--------------+------------- + c1 | integer | | not null | | plain | 10000 | + c2 | text | | | | extended | | + c3 | date | | | | plain | | Child tables: ft2 \d+ ft2 - Foreign table "public.ft2" - Column | Type | Modifiers | FDW Options | Storage | Stats target | Description ---------+---------+-----------+-------------+----------+--------------+------------- - c1 | integer | not null | | plain | 10000 | - c2 | text | | | extended | | - c3 | date | | | plain | | + Foreign table "public.ft2" + Column | Type | Collation | Nullable | Default | FDW Options | Storage | Stats target | Description +--------+---------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | integer | | not null | | | plain | 10000 | + c2 | text | | | | | extended | | + c3 | date | | | | | plain | | Server: s0 FDW Options: (delimiter ',', quote '"', "be quoted" 'value') Inherits: pt1 @@ -1503,24 +1503,24 @@ SELECT relname, conname, contype, conislocal, coninhcount, connoinherit -- child does not inherit NO INHERIT constraints \d+ pt1 - Table "public.pt1" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- - c1 | integer | not null | plain | 10000 | - c2 | text | | extended | | - c3 | date | | plain | | + Table "public.pt1" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+----------+--------------+------------- + c1 | integer | | not null | | plain | 10000 | + c2 | text | | | | extended | | + c3 | date | | | | plain | | Check constraints: "pt1chk1" CHECK (c1 > 0) NO INHERIT "pt1chk2" CHECK (c2 <> ''::text) Child tables: ft2 \d+ ft2 - Foreign table "public.ft2" - Column | Type | Modifiers | FDW Options | Storage | Stats target | Description ---------+---------+-----------+-------------+----------+--------------+------------- - c1 | integer | not null | | plain | 10000 | - c2 | text | | | extended | | - c3 | date | | | plain | | + Foreign table "public.ft2" + Column | Type | Collation | Nullable | Default | FDW Options | Storage | Stats target | Description +--------+---------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | integer | | not null | | | plain | 10000 | + c2 | text | | | | | extended | | + c3 | date | | | | | plain | | Check constraints: "pt1chk2" CHECK (c2 <> ''::text) Server: s0 @@ -1550,24 +1550,24 @@ ALTER FOREIGN TABLE ft2 ADD CONSTRAINT pt1chk2 CHECK (c2 <> ''); ALTER FOREIGN TABLE ft2 INHERIT pt1; -- child does not inherit NO INHERIT constraints \d+ pt1 - Table "public.pt1" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- - c1 | integer | not null | plain | 10000 | - c2 | text | | extended | | - c3 | date | | plain | | + Table "public.pt1" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+----------+--------------+------------- + c1 | integer | | not null | | plain | 10000 | + c2 | text | | | | extended | | + c3 | date | | | | plain | | Check constraints: "pt1chk1" CHECK (c1 > 0) NO INHERIT "pt1chk2" CHECK (c2 <> ''::text) Child tables: ft2 \d+ ft2 - Foreign table "public.ft2" - Column | Type | Modifiers | FDW Options | Storage | Stats target | Description ---------+---------+-----------+-------------+----------+--------------+------------- - c1 | integer | not null | | plain | | - c2 | text | | | extended | | - c3 | date | | | plain | | + Foreign table "public.ft2" + Column | Type | Collation | Nullable | Default | FDW Options | Storage | Stats target | Description +--------+---------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | integer | | not null | | | plain | | + c2 | text | | | | | extended | | + c3 | date | | | | | plain | | Check constraints: "pt1chk2" CHECK (c2 <> ''::text) Server: s0 @@ -1581,23 +1581,23 @@ ALTER TABLE pt1 DROP CONSTRAINT pt1chk2 CASCADE; INSERT INTO pt1 VALUES (1, 'pt1'::text, '1994-01-01'::date); ALTER TABLE pt1 ADD CONSTRAINT pt1chk3 CHECK (c2 <> '') NOT VALID; \d+ pt1 - Table "public.pt1" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- - c1 | integer | not null | plain | 10000 | - c2 | text | | extended | | - c3 | date | | plain | | + Table "public.pt1" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+----------+--------------+------------- + c1 | integer | | not null | | plain | 10000 | + c2 | text | | | | extended | | + c3 | date | | | | plain | | Check constraints: "pt1chk3" CHECK (c2 <> ''::text) NOT VALID Child tables: ft2 \d+ ft2 - Foreign table "public.ft2" - Column | Type | Modifiers | FDW Options | Storage | Stats target | Description ---------+---------+-----------+-------------+----------+--------------+------------- - c1 | integer | not null | | plain | | - c2 | text | | | extended | | - c3 | date | | | plain | | + Foreign table "public.ft2" + Column | Type | Collation | Nullable | Default | FDW Options | Storage | Stats target | Description +--------+---------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | integer | | not null | | | plain | | + c2 | text | | | | | extended | | + c3 | date | | | | | plain | | Check constraints: "pt1chk2" CHECK (c2 <> ''::text) "pt1chk3" CHECK (c2 <> ''::text) NOT VALID @@ -1608,23 +1608,23 @@ Inherits: pt1 -- VALIDATE CONSTRAINT need do nothing on foreign tables ALTER TABLE pt1 VALIDATE CONSTRAINT pt1chk3; \d+ pt1 - Table "public.pt1" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- - c1 | integer | not null | plain | 10000 | - c2 | text | | extended | | - c3 | date | | plain | | + Table "public.pt1" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+----------+--------------+------------- + c1 | integer | | not null | | plain | 10000 | + c2 | text | | | | extended | | + c3 | date | | | | plain | | Check constraints: "pt1chk3" CHECK (c2 <> ''::text) Child tables: ft2 \d+ ft2 - Foreign table "public.ft2" - Column | Type | Modifiers | FDW Options | Storage | Stats target | Description ---------+---------+-----------+-------------+----------+--------------+------------- - c1 | integer | not null | | plain | | - c2 | text | | | extended | | - c3 | date | | | plain | | + Foreign table "public.ft2" + Column | Type | Collation | Nullable | Default | FDW Options | Storage | Stats target | Description +--------+---------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | integer | | not null | | | plain | | + c2 | text | | | | | extended | | + c3 | date | | | | | plain | | Check constraints: "pt1chk2" CHECK (c2 <> ''::text) "pt1chk3" CHECK (c2 <> ''::text) @@ -1635,24 +1635,24 @@ Inherits: pt1 -- OID system column ALTER TABLE pt1 SET WITH OIDS; \d+ pt1 - Table "public.pt1" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- - c1 | integer | not null | plain | 10000 | - c2 | text | | extended | | - c3 | date | | plain | | + Table "public.pt1" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+----------+--------------+------------- + c1 | integer | | not null | | plain | 10000 | + c2 | text | | | | extended | | + c3 | date | | | | plain | | Check constraints: "pt1chk3" CHECK (c2 <> ''::text) Child tables: ft2 Has OIDs: yes \d+ ft2 - Foreign table "public.ft2" - Column | Type | Modifiers | FDW Options | Storage | Stats target | Description ---------+---------+-----------+-------------+----------+--------------+------------- - c1 | integer | not null | | plain | | - c2 | text | | | extended | | - c3 | date | | | plain | | + Foreign table "public.ft2" + Column | Type | Collation | Nullable | Default | FDW Options | Storage | Stats target | Description +--------+---------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | integer | | not null | | | plain | | + c2 | text | | | | | extended | | + c3 | date | | | | | plain | | Check constraints: "pt1chk2" CHECK (c2 <> ''::text) "pt1chk3" CHECK (c2 <> ''::text) @@ -1665,23 +1665,23 @@ ALTER TABLE ft2 SET WITHOUT OIDS; -- ERROR ERROR: cannot drop inherited column "oid" ALTER TABLE pt1 SET WITHOUT OIDS; \d+ pt1 - Table "public.pt1" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- - c1 | integer | not null | plain | 10000 | - c2 | text | | extended | | - c3 | date | | plain | | + Table "public.pt1" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+----------+--------------+------------- + c1 | integer | | not null | | plain | 10000 | + c2 | text | | | | extended | | + c3 | date | | | | plain | | Check constraints: "pt1chk3" CHECK (c2 <> ''::text) Child tables: ft2 \d+ ft2 - Foreign table "public.ft2" - Column | Type | Modifiers | FDW Options | Storage | Stats target | Description ---------+---------+-----------+-------------+----------+--------------+------------- - c1 | integer | not null | | plain | | - c2 | text | | | extended | | - c3 | date | | | plain | | + Foreign table "public.ft2" + Column | Type | Collation | Nullable | Default | FDW Options | Storage | Stats target | Description +--------+---------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | integer | | not null | | | plain | | + c2 | text | | | | | extended | | + c3 | date | | | | | plain | | Check constraints: "pt1chk2" CHECK (c2 <> ''::text) "pt1chk3" CHECK (c2 <> ''::text) @@ -1696,23 +1696,23 @@ ALTER TABLE pt1 RENAME COLUMN c3 TO f3; -- changes name of a constraint recursively ALTER TABLE pt1 RENAME CONSTRAINT pt1chk3 TO f2_check; \d+ pt1 - Table "public.pt1" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- - f1 | integer | not null | plain | 10000 | - f2 | text | | extended | | - f3 | date | | plain | | + Table "public.pt1" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+----------+--------------+------------- + f1 | integer | | not null | | plain | 10000 | + f2 | text | | | | extended | | + f3 | date | | | | plain | | Check constraints: "f2_check" CHECK (f2 <> ''::text) Child tables: ft2 \d+ ft2 - Foreign table "public.ft2" - Column | Type | Modifiers | FDW Options | Storage | Stats target | Description ---------+---------+-----------+-------------+----------+--------------+------------- - f1 | integer | not null | | plain | | - f2 | text | | | extended | | - f3 | date | | | plain | | + Foreign table "public.ft2" + Column | Type | Collation | Nullable | Default | FDW Options | Storage | Stats target | Description +--------+---------+-----------+----------+---------+-------------+----------+--------------+------------- + f1 | integer | | not null | | | plain | | + f2 | text | | | | | extended | | + f3 | date | | | | | plain | | Check constraints: "f2_check" CHECK (f2 <> ''::text) "pt1chk2" CHECK (f2 <> ''::text) diff --git a/src/test/regress/expected/foreign_key.out b/src/test/regress/expected/foreign_key.out index 044881af71..fef072eddf 100644 --- a/src/test/regress/expected/foreign_key.out +++ b/src/test/regress/expected/foreign_key.out @@ -1381,3 +1381,37 @@ explain (costs off) delete from t1 where a = 1; (10 rows) delete from t1 where a = 1; +-- +-- Test deferred FK check on a tuple deleted by a rolled-back subtransaction +-- +create table pktable2(f1 int primary key); +create table fktable2(f1 int references pktable2 deferrable initially deferred); +insert into pktable2 values(1); +begin; +insert into fktable2 values(1); +savepoint x; +delete from fktable2; +rollback to x; +commit; +begin; +insert into fktable2 values(2); +savepoint x; +delete from fktable2; +rollback to x; +commit; -- fail +ERROR: insert or update on table "fktable2" violates foreign key constraint "fktable2_f1_fkey" +DETAIL: Key (f1)=(2) is not present in table "pktable2". +-- +-- Test that we prevent dropping FK constraint with pending trigger events +-- +begin; +insert into fktable2 values(2); +alter table fktable2 drop constraint fktable2_f1_fkey; +ERROR: cannot ALTER TABLE "fktable2" because it has pending trigger events +commit; +begin; +delete from pktable2 where f1 = 1; +alter table fktable2 drop constraint fktable2_f1_fkey; +ERROR: cannot ALTER TABLE "pktable2" because it has pending trigger events +commit; +drop table pktable2, fktable2; diff --git a/src/test/regress/expected/hash_index.out b/src/test/regress/expected/hash_index.out index 22835f8ea4..f8b9f029b2 100644 --- a/src/test/regress/expected/hash_index.out +++ b/src/test/regress/expected/hash_index.out @@ -196,3 +196,39 @@ SELECT h.seqno AS f20000 -- WHERE x = 90; -- SELECT count(*) AS i988 FROM hash_ovfl_heap -- WHERE x = 1000; +-- +-- Cause some overflow insert and splits. +-- +CREATE TABLE hash_split_heap (keycol INT); +CREATE INDEX hash_split_index on hash_split_heap USING HASH (keycol); +WARNING: hash indexes are not WAL-logged and their use is discouraged +INSERT INTO hash_split_heap SELECT 1 FROM generate_series(1, 70000) a; +VACUUM FULL hash_split_heap; +-- Let's do a backward scan. +BEGIN; +SET enable_seqscan = OFF; +SET enable_bitmapscan = OFF; +DECLARE c CURSOR FOR SELECT * from hash_split_heap WHERE keycol = 1; +MOVE FORWARD ALL FROM c; +MOVE BACKWARD 10000 FROM c; +MOVE BACKWARD ALL FROM c; +CLOSE c; +END; +-- DELETE, INSERT, REBUILD INDEX. +DELETE FROM hash_split_heap WHERE keycol = 1; +INSERT INTO hash_split_heap SELECT a/2 FROM generate_series(1, 50000) a; +VACUUM hash_split_heap; +REINDEX INDEX hash_split_index; +-- Clean up. +DROP TABLE hash_split_heap; +-- Index on temp table. +CREATE TEMP TABLE hash_temp_heap (x int, y int); +INSERT INTO hash_temp_heap VALUES (1,1); +CREATE INDEX hash_idx ON hash_temp_heap USING hash (x); +DROP TABLE hash_temp_heap CASCADE; +-- Float4 type. +CREATE TABLE hash_heap_float4 (x float4, y int); +INSERT INTO hash_heap_float4 VALUES (1.1,1); +CREATE INDEX hash_idx ON hash_heap_float4 USING hash (x); +WARNING: hash indexes are not WAL-logged and their use is discouraged +DROP TABLE hash_heap_float4 CASCADE; diff --git a/src/test/regress/expected/horology.out b/src/test/regress/expected/horology.out index 1fe02be093..f9d12e0f8a 100644 --- a/src/test/regress/expected/horology.out +++ b/src/test/regress/expected/horology.out @@ -2822,6 +2822,18 @@ SELECT to_timestamp('20000-1116', 'YYYY-MMDD'); Thu Nov 16 00:00:00 20000 PST (1 row) +SELECT to_timestamp('1997 AD 11 16', 'YYYY BC MM DD'); + to_timestamp +------------------------------ + Sun Nov 16 00:00:00 1997 PST +(1 row) + +SELECT to_timestamp('1997 BC 11 16', 'YYYY BC MM DD'); + to_timestamp +--------------------------------- + Tue Nov 16 00:00:00 1997 PST BC +(1 row) + SELECT to_timestamp('9-1116', 'Y-MMDD'); to_timestamp ------------------------------ @@ -2906,6 +2918,18 @@ SELECT to_timestamp(' 20050302', 'YYYYMMDD'); Wed Mar 02 00:00:00 2005 PST (1 row) +SELECT to_timestamp('2011-12-18 11:38 AM', 'YYYY-MM-DD HH12:MI PM'); + to_timestamp +------------------------------ + Sun Dec 18 11:38:00 2011 PST +(1 row) + +SELECT to_timestamp('2011-12-18 11:38 PM', 'YYYY-MM-DD HH12:MI PM'); + to_timestamp +------------------------------ + Sun Dec 18 23:38:00 2011 PST +(1 row) + -- -- Check handling of multiple spaces in format and/or input -- @@ -2982,7 +3006,7 @@ SELECT to_date('2011 12 18', 'YYYY MM DD'); (1 row) -- --- Check errors for some incorrect usages of to_timestamp() +-- Check errors for some incorrect usages of to_timestamp() and to_date() -- -- Mixture of date conventions (ISO week and Gregorian): SELECT to_timestamp('2005527', 'YYYYIWID'); @@ -3010,6 +3034,76 @@ DETAIL: Value must be an integer. SELECT to_timestamp('10000000000', 'FMYYYY'); ERROR: value for "YYYY" in source string is out of range DETAIL: Value must be in the range -2147483648 to 2147483647. +-- Out-of-range and not-quite-out-of-range fields: +SELECT to_timestamp('2016-06-13 25:00:00', 'YYYY-MM-DD HH24:MI:SS'); +ERROR: date/time field value out of range: "2016-06-13 25:00:00" +SELECT to_timestamp('2016-06-13 15:60:00', 'YYYY-MM-DD HH24:MI:SS'); +ERROR: date/time field value out of range: "2016-06-13 15:60:00" +SELECT to_timestamp('2016-06-13 15:50:60', 'YYYY-MM-DD HH24:MI:SS'); +ERROR: date/time field value out of range: "2016-06-13 15:50:60" +SELECT to_timestamp('2016-06-13 15:50:55', 'YYYY-MM-DD HH24:MI:SS'); -- ok + to_timestamp +------------------------------ + Mon Jun 13 15:50:55 2016 PDT +(1 row) + +SELECT to_timestamp('2016-06-13 15:50:55', 'YYYY-MM-DD HH:MI:SS'); +ERROR: hour "15" is invalid for the 12-hour clock +HINT: Use the 24-hour clock, or give an hour between 1 and 12. +SELECT to_timestamp('2016-13-01 15:50:55', 'YYYY-MM-DD HH24:MI:SS'); +ERROR: date/time field value out of range: "2016-13-01 15:50:55" +SELECT to_timestamp('2016-02-30 15:50:55', 'YYYY-MM-DD HH24:MI:SS'); +ERROR: date/time field value out of range: "2016-02-30 15:50:55" +SELECT to_timestamp('2016-02-29 15:50:55', 'YYYY-MM-DD HH24:MI:SS'); -- ok + to_timestamp +------------------------------ + Mon Feb 29 15:50:55 2016 PST +(1 row) + +SELECT to_timestamp('2015-02-29 15:50:55', 'YYYY-MM-DD HH24:MI:SS'); +ERROR: date/time field value out of range: "2015-02-29 15:50:55" +SELECT to_timestamp('2015-02-11 86000', 'YYYY-MM-DD SSSS'); -- ok + to_timestamp +------------------------------ + Wed Feb 11 23:53:20 2015 PST +(1 row) + +SELECT to_timestamp('2015-02-11 86400', 'YYYY-MM-DD SSSS'); +ERROR: date/time field value out of range: "2015-02-11 86400" +SELECT to_date('2016-13-10', 'YYYY-MM-DD'); +ERROR: date/time field value out of range: "2016-13-10" +SELECT to_date('2016-02-30', 'YYYY-MM-DD'); +ERROR: date/time field value out of range: "2016-02-30" +SELECT to_date('2016-02-29', 'YYYY-MM-DD'); -- ok + to_date +------------ + 02-29-2016 +(1 row) + +SELECT to_date('2015-02-29', 'YYYY-MM-DD'); +ERROR: date/time field value out of range: "2015-02-29" +SELECT to_date('2015 365', 'YYYY DDD'); -- ok + to_date +------------ + 12-31-2015 +(1 row) + +SELECT to_date('2015 366', 'YYYY DDD'); +ERROR: date/time field value out of range: "2015 366" +SELECT to_date('2016 365', 'YYYY DDD'); -- ok + to_date +------------ + 12-30-2016 +(1 row) + +SELECT to_date('2016 366', 'YYYY DDD'); -- ok + to_date +------------ + 12-31-2016 +(1 row) + +SELECT to_date('2016 367', 'YYYY DDD'); +ERROR: date/time field value out of range: "2016 367" -- -- Check behavior with SQL-style fixed-GMT-offset time zone (cf bug #8572) -- diff --git a/src/test/regress/expected/hs_standby_allowed.out b/src/test/regress/expected/hs_standby_allowed.out index c26c9822f6..526f88f2be 100644 --- a/src/test/regress/expected/hs_standby_allowed.out +++ b/src/test/regress/expected/hs_standby_allowed.out @@ -26,10 +26,10 @@ COPY hs1 TO '/tmp/copy_test'; \! cat /tmp/copy_test 1 -- Access sequence directly -select min_value as sequence_min_value from hsseq; - sequence_min_value --------------------- - 1 +select is_called from hsseq; + is_called +----------- + f (1 row) -- Transactions diff --git a/src/test/regress/expected/inet.out b/src/test/regress/expected/inet.out index 9447e03ab5..be9427eb6b 100644 --- a/src/test/regress/expected/inet.out +++ b/src/test/regress/expected/inet.out @@ -411,6 +411,154 @@ SELECT i FROM inet_tbl WHERE i << '192.168.1.0/24'::cidr ORDER BY i; SET enable_seqscan TO on; DROP INDEX inet_idx2; +-- check that spgist index works correctly +CREATE INDEX inet_idx3 ON inet_tbl using spgist (i); +SET enable_seqscan TO off; +SELECT * FROM inet_tbl WHERE i << '192.168.1.0/24'::cidr ORDER BY i; + c | i +----------------+------------------ + 192.168.1.0/24 | 192.168.1.0/25 + 192.168.1.0/24 | 192.168.1.255/25 + 192.168.1.0/26 | 192.168.1.226 +(3 rows) + +SELECT * FROM inet_tbl WHERE i <<= '192.168.1.0/24'::cidr ORDER BY i; + c | i +----------------+------------------ + 192.168.1.0/24 | 192.168.1.0/24 + 192.168.1.0/24 | 192.168.1.226/24 + 192.168.1.0/24 | 192.168.1.255/24 + 192.168.1.0/24 | 192.168.1.0/25 + 192.168.1.0/24 | 192.168.1.255/25 + 192.168.1.0/26 | 192.168.1.226 +(6 rows) + +SELECT * FROM inet_tbl WHERE i && '192.168.1.0/24'::cidr ORDER BY i; + c | i +----------------+------------------ + 192.168.1.0/24 | 192.168.1.0/24 + 192.168.1.0/24 | 192.168.1.226/24 + 192.168.1.0/24 | 192.168.1.255/24 + 192.168.1.0/24 | 192.168.1.0/25 + 192.168.1.0/24 | 192.168.1.255/25 + 192.168.1.0/26 | 192.168.1.226 +(6 rows) + +SELECT * FROM inet_tbl WHERE i >>= '192.168.1.0/24'::cidr ORDER BY i; + c | i +----------------+------------------ + 192.168.1.0/24 | 192.168.1.0/24 + 192.168.1.0/24 | 192.168.1.226/24 + 192.168.1.0/24 | 192.168.1.255/24 +(3 rows) + +SELECT * FROM inet_tbl WHERE i >> '192.168.1.0/24'::cidr ORDER BY i; + c | i +---+--- +(0 rows) + +SELECT * FROM inet_tbl WHERE i < '192.168.1.0/24'::cidr ORDER BY i; + c | i +-------------+------------- + 10.0.0.0/8 | 9.1.2.3/8 + 10.0.0.0/32 | 10.1.2.3/8 + 10.0.0.0/8 | 10.1.2.3/8 + 10.0.0.0/8 | 10.1.2.3/8 + 10.1.0.0/16 | 10.1.2.3/16 + 10.1.2.0/24 | 10.1.2.3/24 + 10.1.2.3/32 | 10.1.2.3 + 10.0.0.0/8 | 11.1.2.3/8 +(8 rows) + +SELECT * FROM inet_tbl WHERE i <= '192.168.1.0/24'::cidr ORDER BY i; + c | i +----------------+---------------- + 10.0.0.0/8 | 9.1.2.3/8 + 10.0.0.0/8 | 10.1.2.3/8 + 10.0.0.0/32 | 10.1.2.3/8 + 10.0.0.0/8 | 10.1.2.3/8 + 10.1.0.0/16 | 10.1.2.3/16 + 10.1.2.0/24 | 10.1.2.3/24 + 10.1.2.3/32 | 10.1.2.3 + 10.0.0.0/8 | 11.1.2.3/8 + 192.168.1.0/24 | 192.168.1.0/24 +(9 rows) + +SELECT * FROM inet_tbl WHERE i = '192.168.1.0/24'::cidr ORDER BY i; + c | i +----------------+---------------- + 192.168.1.0/24 | 192.168.1.0/24 +(1 row) + +SELECT * FROM inet_tbl WHERE i >= '192.168.1.0/24'::cidr ORDER BY i; + c | i +--------------------+------------------ + 192.168.1.0/24 | 192.168.1.0/24 + 192.168.1.0/24 | 192.168.1.226/24 + 192.168.1.0/24 | 192.168.1.255/24 + 192.168.1.0/24 | 192.168.1.0/25 + 192.168.1.0/24 | 192.168.1.255/25 + 192.168.1.0/26 | 192.168.1.226 + ::ffff:1.2.3.4/128 | ::4.3.2.1/24 + 10:23::f1/128 | 10:23::f1/64 + 10:23::8000/113 | 10:23::ffff +(9 rows) + +SELECT * FROM inet_tbl WHERE i > '192.168.1.0/24'::cidr ORDER BY i; + c | i +--------------------+------------------ + 192.168.1.0/24 | 192.168.1.226/24 + 192.168.1.0/24 | 192.168.1.255/24 + 192.168.1.0/24 | 192.168.1.0/25 + 192.168.1.0/24 | 192.168.1.255/25 + 192.168.1.0/26 | 192.168.1.226 + ::ffff:1.2.3.4/128 | ::4.3.2.1/24 + 10:23::f1/128 | 10:23::f1/64 + 10:23::8000/113 | 10:23::ffff +(8 rows) + +SELECT * FROM inet_tbl WHERE i <> '192.168.1.0/24'::cidr ORDER BY i; + c | i +--------------------+------------------ + 10.0.0.0/8 | 9.1.2.3/8 + 10.0.0.0/8 | 10.1.2.3/8 + 10.0.0.0/32 | 10.1.2.3/8 + 10.0.0.0/8 | 10.1.2.3/8 + 10.1.0.0/16 | 10.1.2.3/16 + 10.1.2.0/24 | 10.1.2.3/24 + 10.1.2.3/32 | 10.1.2.3 + 10.0.0.0/8 | 11.1.2.3/8 + 192.168.1.0/24 | 192.168.1.226/24 + 192.168.1.0/24 | 192.168.1.255/24 + 192.168.1.0/24 | 192.168.1.0/25 + 192.168.1.0/24 | 192.168.1.255/25 + 192.168.1.0/26 | 192.168.1.226 + ::ffff:1.2.3.4/128 | ::4.3.2.1/24 + 10:23::f1/128 | 10:23::f1/64 + 10:23::8000/113 | 10:23::ffff +(16 rows) + +-- test index-only scans +EXPLAIN (COSTS OFF) +SELECT i FROM inet_tbl WHERE i << '192.168.1.0/24'::cidr ORDER BY i; + QUERY PLAN +--------------------------------------------------- + Sort + Sort Key: i + -> Index Only Scan using inet_idx3 on inet_tbl + Index Cond: (i << '192.168.1.0/24'::inet) +(4 rows) + +SELECT i FROM inet_tbl WHERE i << '192.168.1.0/24'::cidr ORDER BY i; + i +------------------ + 192.168.1.0/25 + 192.168.1.255/25 + 192.168.1.226 +(3 rows) + +SET enable_seqscan TO on; +DROP INDEX inet_idx3; -- simple tests of inet boolean and arithmetic operators SELECT i, ~i AS "~i" FROM inet_tbl; i | ~i diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out index d8b5b1d44e..a8c8b28a75 100644 --- a/src/test/regress/expected/inherit.out +++ b/src/test/regress/expected/inherit.out @@ -612,6 +612,55 @@ select * from d; 32 | one | two | three (1 row) +-- check that oid column is handled properly during alter table inherit +create table oid_parent (a int) with oids; +create table oid_child () inherits (oid_parent); +select attinhcount, attislocal from pg_attribute + where attrelid = 'oid_child'::regclass and attname = 'oid'; + attinhcount | attislocal +-------------+------------ + 1 | f +(1 row) + +drop table oid_child; +create table oid_child (a int) without oids; +alter table oid_child inherit oid_parent; -- fail +ERROR: table "oid_child" without OIDs cannot inherit from table "oid_parent" with OIDs +alter table oid_child set with oids; +select attinhcount, attislocal from pg_attribute + where attrelid = 'oid_child'::regclass and attname = 'oid'; + attinhcount | attislocal +-------------+------------ + 0 | t +(1 row) + +alter table oid_child inherit oid_parent; +select attinhcount, attislocal from pg_attribute + where attrelid = 'oid_child'::regclass and attname = 'oid'; + attinhcount | attislocal +-------------+------------ + 1 | t +(1 row) + +alter table oid_child set without oids; -- fail +ERROR: cannot drop inherited column "oid" +alter table oid_parent set without oids; +select attinhcount, attislocal from pg_attribute + where attrelid = 'oid_child'::regclass and attname = 'oid'; + attinhcount | attislocal +-------------+------------ + 0 | t +(1 row) + +alter table oid_child set without oids; +select attinhcount, attislocal from pg_attribute + where attrelid = 'oid_child'::regclass and attname = 'oid'; + attinhcount | attislocal +-------------+------------ +(0 rows) + +drop table oid_parent cascade; +NOTICE: drop cascades to table oid_child -- Test non-inheritable parent constraints create table p1(ff1 int); alter table p1 add constraint p1chk check (ff1 > 0) no inherit; @@ -627,24 +676,27 @@ select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pg -- Test that child does not inherit NO INHERIT constraints create table c1 () inherits (p1); \d p1 - Table "public.p1" - Column | Type | Modifiers ---------+---------+----------- - ff1 | integer | + Table "public.p1" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + ff1 | integer | | | Check constraints: "p1chk" CHECK (ff1 > 0) NO INHERIT "p2chk" CHECK (ff1 > 10) Number of child tables: 1 (Use \d+ to list them.) \d c1 - Table "public.c1" - Column | Type | Modifiers ---------+---------+----------- - ff1 | integer | + Table "public.c1" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + ff1 | integer | | | Check constraints: "p2chk" CHECK (ff1 > 10) Inherits: p1 +-- Test that child does not override inheritable constraints of the parent +create table c2 (constraint p2chk check (ff1 > 10) no inherit) inherits (p1); --fails +ERROR: constraint "p2chk" conflicts with inherited constraint on relation "c2" drop table p1 cascade; NOTICE: drop cascades to table c1 -- Tests for casting between the rowtypes of parent and child @@ -803,12 +855,12 @@ ERROR: new row for relation "c1" violates check constraint "p2_f2_check" DETAIL: Failing row contains (1, -1, 2). create table c2(f3 int) inherits(p1,p2); \d c2 - Table "public.c2" - Column | Type | Modifiers ---------+---------+----------- - f1 | integer | - f2 | integer | - f3 | integer | + Table "public.c2" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + f1 | integer | | | + f2 | integer | | | + f3 | integer | | | Check constraints: "p2_f2_check" CHECK (f2 > 0) Inherits: p1, @@ -819,13 +871,13 @@ NOTICE: merging multiple inherited definitions of column "f1" NOTICE: merging multiple inherited definitions of column "f2" NOTICE: merging multiple inherited definitions of column "f3" \d c3 - Table "public.c3" - Column | Type | Modifiers ---------+---------+----------- - f1 | integer | - f2 | integer | - f3 | integer | - f4 | integer | + Table "public.c3" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + f1 | integer | | | + f2 | integer | | | + f3 | integer | | | + f4 | integer | | | Check constraints: "p2_f2_check" CHECK (f2 > 0) Inherits: c1, @@ -841,13 +893,13 @@ create table pp1 (f1 int); create table cc1 (f2 text, f3 int) inherits (pp1); alter table pp1 add column a1 int check (a1 > 0); \d cc1 - Table "public.cc1" - Column | Type | Modifiers ---------+---------+----------- - f1 | integer | - f2 | text | - f3 | integer | - a1 | integer | + Table "public.cc1" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + f1 | integer | | | + f2 | text | | | + f3 | integer | | | + a1 | integer | | | Check constraints: "pp1_a1_check" CHECK (a1 > 0) Inherits: pp1 @@ -856,14 +908,14 @@ create table cc2(f4 float) inherits(pp1,cc1); NOTICE: merging multiple inherited definitions of column "f1" NOTICE: merging multiple inherited definitions of column "a1" \d cc2 - Table "public.cc2" - Column | Type | Modifiers ---------+------------------+----------- - f1 | integer | - a1 | integer | - f2 | text | - f3 | integer | - f4 | double precision | + Table "public.cc2" + Column | Type | Collation | Nullable | Default +--------+------------------+-----------+----------+--------- + f1 | integer | | | + a1 | integer | | | + f2 | text | | | + f3 | integer | | | + f4 | double precision | | | Check constraints: "pp1_a1_check" CHECK (a1 > 0) Inherits: pp1, @@ -873,15 +925,15 @@ alter table pp1 add column a2 int check (a2 > 0); NOTICE: merging definition of column "a2" for child "cc2" NOTICE: merging constraint "pp1_a2_check" with inherited definition \d cc2 - Table "public.cc2" - Column | Type | Modifiers ---------+------------------+----------- - f1 | integer | - a1 | integer | - f2 | text | - f3 | integer | - f4 | double precision | - a2 | integer | + Table "public.cc2" + Column | Type | Collation | Nullable | Default +--------+------------------+-----------+----------+--------- + f1 | integer | | | + a1 | integer | | | + f2 | text | | | + f3 | integer | | | + f4 | double precision | | | + a2 | integer | | | Check constraints: "pp1_a1_check" CHECK (a1 > 0) "pp1_a2_check" CHECK (a2 > 0) @@ -904,13 +956,13 @@ ALTER TABLE inhts RENAME aa TO aaa; -- to be failed ERROR: cannot rename inherited column "aa" ALTER TABLE inhts RENAME d TO dd; \d+ inhts - Table "public.inhts" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+---------+--------------+------------- - aa | integer | | plain | | - b | integer | | plain | | - c | integer | | plain | | - dd | integer | | plain | | + Table "public.inhts" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+---------+--------------+------------- + aa | integer | | | | plain | | + b | integer | | | | plain | | + c | integer | | | | plain | | + dd | integer | | | | plain | | Inherits: inht1, inhs1 @@ -923,14 +975,14 @@ NOTICE: merging multiple inherited definitions of column "aa" NOTICE: merging multiple inherited definitions of column "b" ALTER TABLE inht1 RENAME aa TO aaa; \d+ inht4 - Table "public.inht4" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+---------+--------------+------------- - aaa | integer | | plain | | - b | integer | | plain | | - x | integer | | plain | | - y | integer | | plain | | - z | integer | | plain | | + Table "public.inht4" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+---------+--------------+------------- + aaa | integer | | | | plain | | + b | integer | | | | plain | | + x | integer | | | | plain | | + y | integer | | | | plain | | + z | integer | | | | plain | | Inherits: inht2, inht3 @@ -940,14 +992,14 @@ ALTER TABLE inht1 RENAME aaa TO aaaa; ALTER TABLE inht1 RENAME b TO bb; -- to be failed ERROR: cannot rename inherited column "b" \d+ inhts - Table "public.inhts" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+---------+--------------+------------- - aaaa | integer | | plain | | - b | integer | | plain | | - x | integer | | plain | | - c | integer | | plain | | - d | integer | | plain | | + Table "public.inhts" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+---------+--------------+------------- + aaaa | integer | | | | plain | | + b | integer | | | | plain | | + x | integer | | | | plain | | + c | integer | | | | plain | | + d | integer | | | | plain | | Inherits: inht2, inhs1 @@ -987,33 +1039,33 @@ drop cascades to table inht4 CREATE TABLE test_constraints (id int, val1 varchar, val2 int, UNIQUE(val1, val2)); CREATE TABLE test_constraints_inh () INHERITS (test_constraints); \d+ test_constraints - Table "public.test_constraints" - Column | Type | Modifiers | Storage | Stats target | Description ---------+-------------------+-----------+----------+--------------+------------- - id | integer | | plain | | - val1 | character varying | | extended | | - val2 | integer | | plain | | + Table "public.test_constraints" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+-------------------+-----------+----------+---------+----------+--------------+------------- + id | integer | | | | plain | | + val1 | character varying | | | | extended | | + val2 | integer | | | | plain | | Indexes: "test_constraints_val1_val2_key" UNIQUE CONSTRAINT, btree (val1, val2) Child tables: test_constraints_inh ALTER TABLE ONLY test_constraints DROP CONSTRAINT test_constraints_val1_val2_key; \d+ test_constraints - Table "public.test_constraints" - Column | Type | Modifiers | Storage | Stats target | Description ---------+-------------------+-----------+----------+--------------+------------- - id | integer | | plain | | - val1 | character varying | | extended | | - val2 | integer | | plain | | + Table "public.test_constraints" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+-------------------+-----------+----------+---------+----------+--------------+------------- + id | integer | | | | plain | | + val1 | character varying | | | | extended | | + val2 | integer | | | | plain | | Child tables: test_constraints_inh \d+ test_constraints_inh - Table "public.test_constraints_inh" - Column | Type | Modifiers | Storage | Stats target | Description ---------+-------------------+-----------+----------+--------------+------------- - id | integer | | plain | | - val1 | character varying | | extended | | - val2 | integer | | plain | | + Table "public.test_constraints_inh" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+-------------------+-----------+----------+---------+----------+--------------+------------- + id | integer | | | | plain | | + val1 | character varying | | | | extended | | + val2 | integer | | | | plain | | Inherits: test_constraints DROP TABLE test_constraints_inh; @@ -1024,27 +1076,27 @@ CREATE TABLE test_ex_constraints ( ); CREATE TABLE test_ex_constraints_inh () INHERITS (test_ex_constraints); \d+ test_ex_constraints - Table "public.test_ex_constraints" - Column | Type | Modifiers | Storage | Stats target | Description ---------+--------+-----------+---------+--------------+------------- - c | circle | | plain | | + Table "public.test_ex_constraints" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+--------+-----------+----------+---------+---------+--------------+------------- + c | circle | | | | plain | | Indexes: "test_ex_constraints_c_excl" EXCLUDE USING gist (c WITH &&) Child tables: test_ex_constraints_inh ALTER TABLE test_ex_constraints DROP CONSTRAINT test_ex_constraints_c_excl; \d+ test_ex_constraints - Table "public.test_ex_constraints" - Column | Type | Modifiers | Storage | Stats target | Description ---------+--------+-----------+---------+--------------+------------- - c | circle | | plain | | + Table "public.test_ex_constraints" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+--------+-----------+----------+---------+---------+--------------+------------- + c | circle | | | | plain | | Child tables: test_ex_constraints_inh \d+ test_ex_constraints_inh - Table "public.test_ex_constraints_inh" - Column | Type | Modifiers | Storage | Stats target | Description ---------+--------+-----------+---------+--------------+------------- - c | circle | | plain | | + Table "public.test_ex_constraints_inh" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+--------+-----------+----------+---------+---------+--------------+------------- + c | circle | | | | plain | | Inherits: test_ex_constraints DROP TABLE test_ex_constraints_inh; @@ -1054,42 +1106,92 @@ CREATE TABLE test_primary_constraints(id int PRIMARY KEY); CREATE TABLE test_foreign_constraints(id1 int REFERENCES test_primary_constraints(id)); CREATE TABLE test_foreign_constraints_inh () INHERITS (test_foreign_constraints); \d+ test_primary_constraints - Table "public.test_primary_constraints" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+---------+--------------+------------- - id | integer | not null | plain | | + Table "public.test_primary_constraints" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+---------+--------------+------------- + id | integer | | not null | | plain | | Indexes: "test_primary_constraints_pkey" PRIMARY KEY, btree (id) Referenced by: TABLE "test_foreign_constraints" CONSTRAINT "test_foreign_constraints_id1_fkey" FOREIGN KEY (id1) REFERENCES test_primary_constraints(id) \d+ test_foreign_constraints - Table "public.test_foreign_constraints" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+---------+--------------+------------- - id1 | integer | | plain | | + Table "public.test_foreign_constraints" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+---------+--------------+------------- + id1 | integer | | | | plain | | Foreign-key constraints: "test_foreign_constraints_id1_fkey" FOREIGN KEY (id1) REFERENCES test_primary_constraints(id) Child tables: test_foreign_constraints_inh ALTER TABLE test_foreign_constraints DROP CONSTRAINT test_foreign_constraints_id1_fkey; \d+ test_foreign_constraints - Table "public.test_foreign_constraints" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+---------+--------------+------------- - id1 | integer | | plain | | + Table "public.test_foreign_constraints" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+---------+--------------+------------- + id1 | integer | | | | plain | | Child tables: test_foreign_constraints_inh \d+ test_foreign_constraints_inh - Table "public.test_foreign_constraints_inh" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+---------+--------------+------------- - id1 | integer | | plain | | + Table "public.test_foreign_constraints_inh" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+---------+--------------+------------- + id1 | integer | | | | plain | | Inherits: test_foreign_constraints DROP TABLE test_foreign_constraints_inh; DROP TABLE test_foreign_constraints; DROP TABLE test_primary_constraints; +-- Test that parent and child CHECK constraints can be created in either order +create table p1(f1 int); +create table p1_c1() inherits(p1); +alter table p1 add constraint inh_check_constraint1 check (f1 > 0); +alter table p1_c1 add constraint inh_check_constraint1 check (f1 > 0); +NOTICE: merging constraint "inh_check_constraint1" with inherited definition +alter table p1_c1 add constraint inh_check_constraint2 check (f1 < 10); +alter table p1 add constraint inh_check_constraint2 check (f1 < 10); +NOTICE: merging constraint "inh_check_constraint2" with inherited definition +select conrelid::regclass::text as relname, conname, conislocal, coninhcount +from pg_constraint where conname like 'inh\_check\_constraint%' +order by 1, 2; + relname | conname | conislocal | coninhcount +---------+-----------------------+------------+------------- + p1 | inh_check_constraint1 | t | 0 + p1 | inh_check_constraint2 | t | 0 + p1_c1 | inh_check_constraint1 | t | 1 + p1_c1 | inh_check_constraint2 | t | 1 +(4 rows) + +drop table p1 cascade; +NOTICE: drop cascades to table p1_c1 +-- Test that a valid child can have not-valid parent, but not vice versa +create table invalid_check_con(f1 int); +create table invalid_check_con_child() inherits(invalid_check_con); +alter table invalid_check_con_child add constraint inh_check_constraint check(f1 > 0) not valid; +alter table invalid_check_con add constraint inh_check_constraint check(f1 > 0); -- fail +ERROR: constraint "inh_check_constraint" conflicts with NOT VALID constraint on relation "invalid_check_con_child" +alter table invalid_check_con_child drop constraint inh_check_constraint; +insert into invalid_check_con values(0); +alter table invalid_check_con_child add constraint inh_check_constraint check(f1 > 0); +alter table invalid_check_con add constraint inh_check_constraint check(f1 > 0) not valid; +NOTICE: merging constraint "inh_check_constraint" with inherited definition +insert into invalid_check_con values(0); -- fail +ERROR: new row for relation "invalid_check_con" violates check constraint "inh_check_constraint" +DETAIL: Failing row contains (0). +insert into invalid_check_con_child values(0); -- fail +ERROR: new row for relation "invalid_check_con_child" violates check constraint "inh_check_constraint" +DETAIL: Failing row contains (0). +select conrelid::regclass::text as relname, conname, + convalidated, conislocal, coninhcount, connoinherit +from pg_constraint where conname like 'inh\_check\_constraint%' +order by 1, 2; + relname | conname | convalidated | conislocal | coninhcount | connoinherit +-------------------------+----------------------+--------------+------------+-------------+-------------- + invalid_check_con | inh_check_constraint | f | t | 0 | f + invalid_check_con_child | inh_check_constraint | t | t | 1 | f +(2 rows) + +-- We don't drop the invalid_check_con* tables, to test dump/reload with -- -- Test parameterized append plans for inheritance trees -- @@ -1373,7 +1475,7 @@ ORDER BY thousand, tenthous; Sort Key: tenk1.thousand, tenk1.tenthous -> Index Only Scan using tenk1_thous_tenthous on tenk1 -> Sort - Sort Key: (42), (42) + Sort Key: 42, 42 -> Index Only Scan using tenk1_hundred on tenk1 tenk1_1 (6 rows) @@ -1489,3 +1591,275 @@ FROM generate_series(1, 3) g(i); reset enable_seqscan; reset enable_indexscan; reset enable_bitmapscan; +-- +-- Check that constraint exclusion works correctly with partitions using +-- implicit constraints generated from the partition bound information. +-- +create table list_parted ( + a varchar +) partition by list (a); +create table part_ab_cd partition of list_parted for values in ('ab', 'cd'); +create table part_ef_gh partition of list_parted for values in ('ef', 'gh'); +create table part_null_xy partition of list_parted for values in (null, 'xy'); +explain (costs off) select * from list_parted; + QUERY PLAN +-------------------------------- + Append + -> Seq Scan on list_parted + -> Seq Scan on part_ab_cd + -> Seq Scan on part_ef_gh + -> Seq Scan on part_null_xy +(5 rows) + +explain (costs off) select * from list_parted where a is null; + QUERY PLAN +-------------------------------- + Append + -> Seq Scan on list_parted + Filter: (a IS NULL) + -> Seq Scan on part_null_xy + Filter: (a IS NULL) +(5 rows) + +explain (costs off) select * from list_parted where a is not null; + QUERY PLAN +--------------------------------- + Append + -> Seq Scan on list_parted + Filter: (a IS NOT NULL) + -> Seq Scan on part_ab_cd + Filter: (a IS NOT NULL) + -> Seq Scan on part_ef_gh + Filter: (a IS NOT NULL) + -> Seq Scan on part_null_xy + Filter: (a IS NOT NULL) +(9 rows) + +explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef'); + QUERY PLAN +---------------------------------------------------------- + Append + -> Seq Scan on list_parted + Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[])) + -> Seq Scan on part_ab_cd + Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[])) + -> Seq Scan on part_ef_gh + Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[])) +(7 rows) + +explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd'); + QUERY PLAN +--------------------------------------------------------------------------------------- + Append + -> Seq Scan on list_parted + Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[]))) + -> Seq Scan on part_ab_cd + Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[]))) + -> Seq Scan on part_ef_gh + Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[]))) + -> Seq Scan on part_null_xy + Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[]))) +(9 rows) + +explain (costs off) select * from list_parted where a = 'ab'; + QUERY PLAN +------------------------------------------ + Append + -> Seq Scan on list_parted + Filter: ((a)::text = 'ab'::text) + -> Seq Scan on part_ab_cd + Filter: ((a)::text = 'ab'::text) +(5 rows) + +create table range_list_parted ( + a int, + b char(2) +) partition by range (a); +create table part_1_10 partition of range_list_parted for values from (1) to (10) partition by list (b); +create table part_1_10_ab partition of part_1_10 for values in ('ab'); +create table part_1_10_cd partition of part_1_10 for values in ('cd'); +create table part_10_20 partition of range_list_parted for values from (10) to (20) partition by list (b); +create table part_10_20_ab partition of part_10_20 for values in ('ab'); +create table part_10_20_cd partition of part_10_20 for values in ('cd'); +create table part_21_30 partition of range_list_parted for values from (21) to (30) partition by list (b); +create table part_21_30_ab partition of part_21_30 for values in ('ab'); +create table part_21_30_cd partition of part_21_30 for values in ('cd'); +create table part_40_inf partition of range_list_parted for values from (40) to (unbounded) partition by list (b); +create table part_40_inf_ab partition of part_40_inf for values in ('ab'); +create table part_40_inf_cd partition of part_40_inf for values in ('cd'); +create table part_40_inf_null partition of part_40_inf for values in (null); +explain (costs off) select * from range_list_parted; + QUERY PLAN +------------------------------------- + Append + -> Seq Scan on range_list_parted + -> Seq Scan on part_1_10 + -> Seq Scan on part_10_20 + -> Seq Scan on part_21_30 + -> Seq Scan on part_40_inf + -> Seq Scan on part_1_10_ab + -> Seq Scan on part_1_10_cd + -> Seq Scan on part_10_20_ab + -> Seq Scan on part_10_20_cd + -> Seq Scan on part_21_30_ab + -> Seq Scan on part_21_30_cd + -> Seq Scan on part_40_inf_ab + -> Seq Scan on part_40_inf_cd + -> Seq Scan on part_40_inf_null +(15 rows) + +explain (costs off) select * from range_list_parted where a = 5; + QUERY PLAN +------------------------------------- + Append + -> Seq Scan on range_list_parted + Filter: (a = 5) + -> Seq Scan on part_1_10 + Filter: (a = 5) + -> Seq Scan on part_1_10_ab + Filter: (a = 5) + -> Seq Scan on part_1_10_cd + Filter: (a = 5) +(9 rows) + +explain (costs off) select * from range_list_parted where b = 'ab'; + QUERY PLAN +------------------------------------- + Append + -> Seq Scan on range_list_parted + Filter: (b = 'ab'::bpchar) + -> Seq Scan on part_1_10 + Filter: (b = 'ab'::bpchar) + -> Seq Scan on part_10_20 + Filter: (b = 'ab'::bpchar) + -> Seq Scan on part_21_30 + Filter: (b = 'ab'::bpchar) + -> Seq Scan on part_40_inf + Filter: (b = 'ab'::bpchar) + -> Seq Scan on part_1_10_ab + Filter: (b = 'ab'::bpchar) + -> Seq Scan on part_10_20_ab + Filter: (b = 'ab'::bpchar) + -> Seq Scan on part_21_30_ab + Filter: (b = 'ab'::bpchar) + -> Seq Scan on part_40_inf_ab + Filter: (b = 'ab'::bpchar) +(19 rows) + +explain (costs off) select * from range_list_parted where a between 3 and 23 and b in ('ab'); + QUERY PLAN +----------------------------------------------------------------- + Append + -> Seq Scan on range_list_parted + Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar)) + -> Seq Scan on part_1_10 + Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar)) + -> Seq Scan on part_10_20 + Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar)) + -> Seq Scan on part_21_30 + Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar)) + -> Seq Scan on part_1_10_ab + Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar)) + -> Seq Scan on part_10_20_ab + Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar)) + -> Seq Scan on part_21_30_ab + Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar)) +(15 rows) + +/* Should select no rows because range partition key cannot be null */ +explain (costs off) select * from range_list_parted where a is null; + QUERY PLAN +-------------------------- + Result + One-Time Filter: false +(2 rows) + +/* Should only select rows from the null-accepting partition */ +explain (costs off) select * from range_list_parted where b is null; + QUERY PLAN +------------------------------------- + Append + -> Seq Scan on range_list_parted + Filter: (b IS NULL) + -> Seq Scan on part_1_10 + Filter: (b IS NULL) + -> Seq Scan on part_10_20 + Filter: (b IS NULL) + -> Seq Scan on part_21_30 + Filter: (b IS NULL) + -> Seq Scan on part_40_inf + Filter: (b IS NULL) + -> Seq Scan on part_40_inf_null + Filter: (b IS NULL) +(13 rows) + +explain (costs off) select * from range_list_parted where a is not null and a < 67; + QUERY PLAN +------------------------------------------------ + Append + -> Seq Scan on range_list_parted + Filter: ((a IS NOT NULL) AND (a < 67)) + -> Seq Scan on part_1_10 + Filter: ((a IS NOT NULL) AND (a < 67)) + -> Seq Scan on part_10_20 + Filter: ((a IS NOT NULL) AND (a < 67)) + -> Seq Scan on part_21_30 + Filter: ((a IS NOT NULL) AND (a < 67)) + -> Seq Scan on part_40_inf + Filter: ((a IS NOT NULL) AND (a < 67)) + -> Seq Scan on part_1_10_ab + Filter: ((a IS NOT NULL) AND (a < 67)) + -> Seq Scan on part_1_10_cd + Filter: ((a IS NOT NULL) AND (a < 67)) + -> Seq Scan on part_10_20_ab + Filter: ((a IS NOT NULL) AND (a < 67)) + -> Seq Scan on part_10_20_cd + Filter: ((a IS NOT NULL) AND (a < 67)) + -> Seq Scan on part_21_30_ab + Filter: ((a IS NOT NULL) AND (a < 67)) + -> Seq Scan on part_21_30_cd + Filter: ((a IS NOT NULL) AND (a < 67)) + -> Seq Scan on part_40_inf_ab + Filter: ((a IS NOT NULL) AND (a < 67)) + -> Seq Scan on part_40_inf_cd + Filter: ((a IS NOT NULL) AND (a < 67)) + -> Seq Scan on part_40_inf_null + Filter: ((a IS NOT NULL) AND (a < 67)) +(29 rows) + +explain (costs off) select * from range_list_parted where a >= 30; + QUERY PLAN +------------------------------------- + Append + -> Seq Scan on range_list_parted + Filter: (a >= 30) + -> Seq Scan on part_40_inf + Filter: (a >= 30) + -> Seq Scan on part_40_inf_ab + Filter: (a >= 30) + -> Seq Scan on part_40_inf_cd + Filter: (a >= 30) + -> Seq Scan on part_40_inf_null + Filter: (a >= 30) +(11 rows) + +drop table list_parted cascade; +NOTICE: drop cascades to 3 other objects +DETAIL: drop cascades to table part_ab_cd +drop cascades to table part_ef_gh +drop cascades to table part_null_xy +drop table range_list_parted cascade; +NOTICE: drop cascades to 13 other objects +DETAIL: drop cascades to table part_1_10 +drop cascades to table part_1_10_ab +drop cascades to table part_1_10_cd +drop cascades to table part_10_20 +drop cascades to table part_10_20_ab +drop cascades to table part_10_20_cd +drop cascades to table part_21_30 +drop cascades to table part_21_30_ab +drop cascades to table part_21_30_cd +drop cascades to table part_40_inf +drop cascades to table part_40_inf_ab +drop cascades to table part_40_inf_cd +drop cascades to table part_40_inf_null diff --git a/src/test/regress/expected/insert.out b/src/test/regress/expected/insert.out index 70107b5bf2..538fe5b181 100644 --- a/src/test/regress/expected/insert.out +++ b/src/test/regress/expected/insert.out @@ -142,11 +142,11 @@ create rule irule3 as on insert to inserttest2 do also insert into inserttest (f4[1].if1, f4[1].if2[2]) select new.f1, new.f2; \d+ inserttest2 - Table "public.inserttest2" - Column | Type | Modifiers | Storage | Stats target | Description ---------+--------+-----------+----------+--------------+------------- - f1 | bigint | | plain | | - f2 | text | | extended | | + Table "public.inserttest2" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+--------+-----------+----------+---------+----------+--------------+------------- + f1 | bigint | | | | plain | | + f2 | text | | | | extended | | Rules: irule1 AS ON INSERT TO inserttest2 DO INSERT INTO inserttest (f3.if2[1], f3.if2[2]) @@ -160,3 +160,231 @@ Rules: drop table inserttest2; drop table inserttest; drop type insert_test_type; +-- direct partition inserts should check partition bound constraint +create table range_parted ( + a text, + b int +) partition by range (a, (b+0)); +create table part1 partition of range_parted for values from ('a', 1) to ('a', 10); +create table part2 partition of range_parted for values from ('a', 10) to ('a', 20); +create table part3 partition of range_parted for values from ('b', 1) to ('b', 10); +create table part4 partition of range_parted for values from ('b', 10) to ('b', 20); +-- fail +insert into part1 values ('a', 11); +ERROR: new row for relation "part1" violates partition constraint +DETAIL: Failing row contains (a, 11). +insert into part1 values ('b', 1); +ERROR: new row for relation "part1" violates partition constraint +DETAIL: Failing row contains (b, 1). +-- ok +insert into part1 values ('a', 1); +-- fail +insert into part4 values ('b', 21); +ERROR: new row for relation "part4" violates partition constraint +DETAIL: Failing row contains (b, 21). +insert into part4 values ('a', 10); +ERROR: new row for relation "part4" violates partition constraint +DETAIL: Failing row contains (a, 10). +-- ok +insert into part4 values ('b', 10); +-- fail (partition key a has a NOT NULL constraint) +insert into part1 values (null); +ERROR: null value in column "a" violates not-null constraint +DETAIL: Failing row contains (null, null). +-- fail (expression key (b+0) cannot be null either) +insert into part1 values (1); +ERROR: new row for relation "part1" violates partition constraint +DETAIL: Failing row contains (1, null). +create table list_parted ( + a text, + b int +) partition by list (lower(a)); +create table part_aa_bb partition of list_parted FOR VALUES IN ('aa', 'bb'); +create table part_cc_dd partition of list_parted FOR VALUES IN ('cc', 'dd'); +create table part_null partition of list_parted FOR VALUES IN (null); +-- fail +insert into part_aa_bb values ('cc', 1); +ERROR: new row for relation "part_aa_bb" violates partition constraint +DETAIL: Failing row contains (cc, 1). +insert into part_aa_bb values ('AAa', 1); +ERROR: new row for relation "part_aa_bb" violates partition constraint +DETAIL: Failing row contains (AAa, 1). +insert into part_aa_bb values (null); +ERROR: new row for relation "part_aa_bb" violates partition constraint +DETAIL: Failing row contains (null, null). +-- ok +insert into part_cc_dd values ('cC', 1); +insert into part_null values (null, 0); +-- check in case of multi-level partitioned table +create table part_ee_ff partition of list_parted for values in ('ee', 'ff') partition by range (b); +create table part_ee_ff1 partition of part_ee_ff for values from (1) to (10); +create table part_ee_ff2 partition of part_ee_ff for values from (10) to (20); +-- fail +insert into part_ee_ff1 values ('EE', 11); +ERROR: new row for relation "part_ee_ff1" violates partition constraint +DETAIL: Failing row contains (EE, 11). +-- fail (even the parent's, ie, part_ee_ff's partition constraint applies) +insert into part_ee_ff1 values ('cc', 1); +ERROR: new row for relation "part_ee_ff1" violates partition constraint +DETAIL: Failing row contains (cc, 1). +-- ok +insert into part_ee_ff1 values ('ff', 1); +insert into part_ee_ff2 values ('ff', 11); +-- Check tuple routing for partitioned tables +-- fail +insert into range_parted values ('a', 0); +ERROR: no partition of relation "range_parted" found for row +DETAIL: Failing row contains (a, 0). +-- ok +insert into range_parted values ('a', 1); +insert into range_parted values ('a', 10); +-- fail +insert into range_parted values ('a', 20); +ERROR: no partition of relation "range_parted" found for row +DETAIL: Failing row contains (a, 20). +-- ok +insert into range_parted values ('b', 1); +insert into range_parted values ('b', 10); +-- fail (partition key (b+0) is null) +insert into range_parted values ('a'); +ERROR: range partition key of row contains null +select tableoid::regclass, * from range_parted; + tableoid | a | b +----------+---+---- + part1 | a | 1 + part1 | a | 1 + part2 | a | 10 + part3 | b | 1 + part4 | b | 10 + part4 | b | 10 +(6 rows) + +-- ok +insert into list_parted values (null, 1); +insert into list_parted (a) values ('aA'); +-- fail (partition of part_ee_ff not found in both cases) +insert into list_parted values ('EE', 0); +ERROR: no partition of relation "part_ee_ff" found for row +DETAIL: Failing row contains (EE, 0). +insert into part_ee_ff values ('EE', 0); +ERROR: no partition of relation "part_ee_ff" found for row +DETAIL: Failing row contains (EE, 0). +-- ok +insert into list_parted values ('EE', 1); +insert into part_ee_ff values ('EE', 10); +select tableoid::regclass, * from list_parted; + tableoid | a | b +-------------+----+---- + part_aa_bb | aA | + part_cc_dd | cC | 1 + part_null | | 0 + part_null | | 1 + part_ee_ff1 | ff | 1 + part_ee_ff1 | EE | 1 + part_ee_ff2 | ff | 11 + part_ee_ff2 | EE | 10 +(8 rows) + +-- some more tests to exercise tuple-routing with multi-level partitioning +create table part_gg partition of list_parted for values in ('gg') partition by range (b); +create table part_gg1 partition of part_gg for values from (unbounded) to (1); +create table part_gg2 partition of part_gg for values from (1) to (10) partition by range (b); +create table part_gg2_1 partition of part_gg2 for values from (1) to (5); +create table part_gg2_2 partition of part_gg2 for values from (5) to (10); +create table part_ee_ff3 partition of part_ee_ff for values from (20) to (30) partition by range (b); +create table part_ee_ff3_1 partition of part_ee_ff3 for values from (20) to (25); +create table part_ee_ff3_2 partition of part_ee_ff3 for values from (25) to (30); +truncate list_parted; +insert into list_parted values ('aa'), ('cc'); +insert into list_parted select 'Ff', s.a from generate_series(1, 29) s(a); +insert into list_parted select 'gg', s.a from generate_series(1, 9) s(a); +insert into list_parted (b) values (1); +select tableoid::regclass::text, a, min(b) as min_b, max(b) as max_b from list_parted group by 1, 2 order by 1; + tableoid | a | min_b | max_b +---------------+----+-------+------- + part_aa_bb | aa | | + part_cc_dd | cc | | + part_ee_ff1 | Ff | 1 | 9 + part_ee_ff2 | Ff | 10 | 19 + part_ee_ff3_1 | Ff | 20 | 24 + part_ee_ff3_2 | Ff | 25 | 29 + part_gg2_1 | gg | 1 | 4 + part_gg2_2 | gg | 5 | 9 + part_null | | 1 | 1 +(9 rows) + +-- cleanup +drop table part1, part2, part3, part4, range_parted; +drop table part_ee_ff3_1, part_ee_ff3_2, part_ee_ff1, part_ee_ff2, part_ee_ff3; +drop table part_ee_ff, part_gg2_2, part_gg2_1, part_gg2, part_gg1, part_gg; +drop table part_aa_bb, part_cc_dd, part_null, list_parted; +-- more tests for certain multi-level partitioning scenarios +create table p (a int, b int) partition by range (a, b); +create table p1 (b int, a int not null) partition by range (b); +create table p11 (like p1); +alter table p11 drop a; +alter table p11 add a int; +alter table p11 drop a; +alter table p11 add a int not null; +-- attnum for key attribute 'a' is different in p, p1, and p11 +select attrelid::regclass, attname, attnum +from pg_attribute +where attname = 'a' + and (attrelid = 'p'::regclass + or attrelid = 'p1'::regclass + or attrelid = 'p11'::regclass) +order by attrelid::regclass::text; + attrelid | attname | attnum +----------+---------+-------- + p | a | 1 + p1 | a | 2 + p11 | a | 4 +(3 rows) + +alter table p1 attach partition p11 for values from (2) to (5); +alter table p attach partition p1 for values from (1, 2) to (1, 10); +-- check that "(1, 2)" is correctly routed to p11. +insert into p values (1, 2); +select tableoid::regclass, * from p; + tableoid | a | b +----------+---+--- + p11 | 1 | 2 +(1 row) + +truncate p; +alter table p add constraint check_b check (b = 3); +-- check that correct input row is shown when constraint check_b fails on p11 +-- after "(1, 2)" is routed to it +insert into p values (1, 2); +ERROR: new row for relation "p11" violates check constraint "check_b" +DETAIL: Failing row contains (1, 2). +-- check that inserting into an internal partition successfully results in +-- checking its partition constraint before inserting into the leaf partition +-- selected by tuple-routing +insert into p1 (a, b) values (2, 3); +ERROR: new row for relation "p11" violates partition constraint +DETAIL: Failing row contains (3, 2). +-- check that RETURNING works correctly with tuple-routing +alter table p drop constraint check_b; +create table p12 partition of p1 for values from (5) to (10); +create table p2 (b int not null, a int not null); +alter table p attach partition p2 for values from (1, 10) to (1, 20); +create table p3 partition of p for values from (1, 20) to (1, 30); +create table p4 (like p); +alter table p4 drop a; +alter table p4 add a int not null; +alter table p attach partition p4 for values from (1, 30) to (1, 40); +with ins (a, b, c) as + (insert into p (b, a) select s.a, 1 from generate_series(2, 39) s(a) returning tableoid::regclass, *) + select a, b, min(c), max(c) from ins group by a, b order by 1; + a | b | min | max +-----+---+-----+----- + p11 | 1 | 2 | 4 + p12 | 1 | 5 | 9 + p2 | 1 | 10 | 19 + p3 | 1 | 20 | 29 + p4 | 1 | 30 | 39 +(5 rows) + +-- cleanup +drop table p, p1, p11, p12, p2, p3, p4; diff --git a/src/test/regress/expected/insert_conflict.out b/src/test/regress/expected/insert_conflict.out index 155774ecfa..63859c53ac 100644 --- a/src/test/regress/expected/insert_conflict.out +++ b/src/test/regress/expected/insert_conflict.out @@ -471,6 +471,30 @@ on conflict (b) where coalesce(a, 1) > 0 do nothing; insert into insertconflict values (1, 2) on conflict (b) where coalesce(a, 1) > 1 do nothing; drop table insertconflict; +-- +-- test insertion through view +-- +create table insertconflict (f1 int primary key, f2 text); +create view insertconflictv as + select * from insertconflict with cascaded check option; +insert into insertconflictv values (1,'foo') + on conflict (f1) do update set f2 = excluded.f2; +select * from insertconflict; + f1 | f2 +----+----- + 1 | foo +(1 row) + +insert into insertconflictv values (1,'bar') + on conflict (f1) do update set f2 = excluded.f2; +select * from insertconflict; + f1 | f2 +----+----- + 1 | bar +(1 row) + +drop view insertconflictv; +drop table insertconflict; -- ****************************************************************** -- * * -- * Test inheritance (example taken from tutorial) * @@ -727,3 +751,38 @@ select * from twoconstraints; (1 row) drop table twoconstraints; +-- check handling of self-conflicts at various isolation levels +create table selfconflict (f1 int primary key, f2 int); +begin transaction isolation level read committed; +insert into selfconflict values (1,1), (1,2) on conflict do nothing; +commit; +begin transaction isolation level repeatable read; +insert into selfconflict values (2,1), (2,2) on conflict do nothing; +commit; +begin transaction isolation level serializable; +insert into selfconflict values (3,1), (3,2) on conflict do nothing; +commit; +begin transaction isolation level read committed; +insert into selfconflict values (4,1), (4,2) on conflict(f1) do update set f2 = 0; +ERROR: ON CONFLICT DO UPDATE command cannot affect row a second time +HINT: Ensure that no rows proposed for insertion within the same command have duplicate constrained values. +commit; +begin transaction isolation level repeatable read; +insert into selfconflict values (5,1), (5,2) on conflict(f1) do update set f2 = 0; +ERROR: ON CONFLICT DO UPDATE command cannot affect row a second time +HINT: Ensure that no rows proposed for insertion within the same command have duplicate constrained values. +commit; +begin transaction isolation level serializable; +insert into selfconflict values (6,1), (6,2) on conflict(f1) do update set f2 = 0; +ERROR: ON CONFLICT DO UPDATE command cannot affect row a second time +HINT: Ensure that no rows proposed for insertion within the same command have duplicate constrained values. +commit; +select * from selfconflict; + f1 | f2 +----+---- + 1 | 1 + 2 | 1 + 3 | 1 +(3 rows) + +drop table selfconflict; diff --git a/src/test/regress/expected/interval.out b/src/test/regress/expected/interval.out index c873a99bd9..946c97ad92 100644 --- a/src/test/regress/expected/interval.out +++ b/src/test/regress/expected/interval.out @@ -682,6 +682,24 @@ SELECT interval '1 2:03:04.5678' minute to second(2); 1 day 02:03:04.57 (1 row) +-- test casting to restricted precision (bug #14479) +SELECT f1, f1::INTERVAL DAY TO MINUTE AS "minutes", + (f1 + INTERVAL '1 month')::INTERVAL MONTH::INTERVAL YEAR AS "years" + FROM interval_tbl; + f1 | minutes | years +-----------------+-----------------+---------- + 00:01:00 | 00:01:00 | 00:00:00 + 05:00:00 | 05:00:00 | 00:00:00 + 10 days | 10 days | 00:00:00 + 34 years | 34 years | 34 years + 3 mons | 3 mons | 00:00:00 + -00:00:14 | 00:00:00 | 00:00:00 + 1 day 02:03:04 | 1 day 02:03:00 | 00:00:00 + 6 years | 6 years | 6 years + 5 mons | 5 mons | 00:00:00 + 5 mons 12:00:00 | 5 mons 12:00:00 | 00:00:00 +(10 rows) + -- test inputting and outputting SQL standard interval literals SET IntervalStyle TO sql_standard; SELECT interval '0' AS "zero", diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out index a6d25defb0..ba9b1d711e 100644 --- a/src/test/regress/expected/jsonb.out +++ b/src/test/regress/expected/jsonb.out @@ -3095,6 +3095,24 @@ select '["a","b","c"]'::jsonb - -4; ["a", "b", "c"] (1 row) +select '{"a":1 , "b":2, "c":3}'::jsonb - '{b}'::text[]; + ?column? +------------------ + {"a": 1, "c": 3} +(1 row) + +select '{"a":1 , "b":2, "c":3}'::jsonb - '{c,b}'::text[]; + ?column? +---------- + {"a": 1} +(1 row) + +select '{"a":1 , "b":2, "c":3}'::jsonb - '{}'::text[]; + ?column? +-------------------------- + {"a": 1, "b": 2, "c": 3} +(1 row) + select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb, '{n}', '[1,2,3]'); jsonb_set -------------------------------------------------------------------------- @@ -3238,6 +3256,12 @@ select jsonb_set('[]','{1}','"b"', false); [] (1 row) +select jsonb_set('[{"f1":1,"f2":null},2,null,3]', '{0}','[2,3,4]', false); + jsonb_set +------------------------- + [[2, 3, 4], 2, null, 3] +(1 row) + -- jsonb_set adding instead of replacing -- prepend to array select jsonb_set('{"a":1,"b":[0,1,2],"c":{"d":4}}','{b,-33}','{"foo":123}'); diff --git a/src/test/regress/expected/limit.out b/src/test/regress/expected/limit.out index 9c3eecfc3b..65c8c44a9a 100644 --- a/src/test/regress/expected/limit.out +++ b/src/test/regress/expected/limit.out @@ -208,13 +208,15 @@ select currval('testseq'); explain (verbose, costs off) select unique1, unique2, generate_series(1,10) from tenk1 order by unique2 limit 7; - QUERY PLAN ----------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------- Limit Output: unique1, unique2, (generate_series(1, 10)) - -> Index Scan using tenk1_unique2 on public.tenk1 + -> ProjectSet Output: unique1, unique2, generate_series(1, 10) -(4 rows) + -> Index Scan using tenk1_unique2 on public.tenk1 + Output: unique1, unique2, two, four, ten, twenty, hundred, thousand, twothousand, fivethous, tenthous, odd, even, stringu1, stringu2, string4 +(6 rows) select unique1, unique2, generate_series(1,10) from tenk1 order by unique2 limit 7; @@ -236,7 +238,7 @@ select unique1, unique2, generate_series(1,10) -------------------------------------------------------------------- Limit Output: unique1, unique2, (generate_series(1, 10)), tenthous - -> Result + -> ProjectSet Output: unique1, unique2, generate_series(1, 10), tenthous -> Sort Output: unique1, unique2, tenthous @@ -263,9 +265,10 @@ explain (verbose, costs off) select generate_series(0,2) as s1, generate_series((random()*.1)::int,2) as s2; QUERY PLAN ------------------------------------------------------------------------------------------------------ - Result + ProjectSet Output: generate_series(0, 2), generate_series(((random() * '0.1'::double precision))::integer, 2) -(2 rows) + -> Result +(3 rows) select generate_series(0,2) as s1, generate_series((random()*.1)::int,2) as s2; s1 | s2 @@ -283,9 +286,10 @@ order by s2 desc; Sort Output: (generate_series(0, 2)), (generate_series(((random() * '0.1'::double precision))::integer, 2)) Sort Key: (generate_series(((random() * '0.1'::double precision))::integer, 2)) DESC - -> Result + -> ProjectSet Output: generate_series(0, 2), generate_series(((random() * '0.1'::double precision))::integer, 2) -(5 rows) + -> Result +(6 rows) select generate_series(0,2) as s1, generate_series((random()*.1)::int,2) as s2 order by s2 desc; diff --git a/src/test/regress/expected/matview.out b/src/test/regress/expected/matview.out index e7d0ad1d86..7a2eaa0c4a 100644 --- a/src/test/regress/expected/matview.out +++ b/src/test/regress/expected/matview.out @@ -33,7 +33,7 @@ SELECT relispopulated FROM pg_class WHERE oid = 'mvtest_tm'::regclass; f (1 row) -SELECT * FROM mvtest_tm; +SELECT * FROM mvtest_tm ORDER BY type; ERROR: materialized view "mvtest_tm" has not been populated HINT: Use the REFRESH MATERIALIZED VIEW command. REFRESH MATERIALIZED VIEW mvtest_tm; @@ -44,12 +44,12 @@ SELECT relispopulated FROM pg_class WHERE oid = 'mvtest_tm'::regclass; (1 row) CREATE UNIQUE INDEX mvtest_tm_type ON mvtest_tm (type); -SELECT * FROM mvtest_tm; +SELECT * FROM mvtest_tm ORDER BY type; type | totamt ------+-------- + x | 5 y | 12 z | 11 - x | 5 (3 rows) -- create various views @@ -94,11 +94,11 @@ CREATE MATERIALIZED VIEW mvtest_bb AS SELECT * FROM mvtest_tvvmv; CREATE INDEX mvtest_aa ON mvtest_bb (grandtot); -- check that plans seem reasonable \d+ mvtest_tvm - Materialized view "public.mvtest_tvm" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- - type | text | | extended | | - totamt | numeric | | main | | + Materialized view "public.mvtest_tvm" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+----------+--------------+------------- + type | text | | | | extended | | + totamt | numeric | | | | main | | View definition: SELECT mvtest_tv.type, mvtest_tv.totamt @@ -106,11 +106,11 @@ View definition: ORDER BY mvtest_tv.type; \d+ mvtest_tvm - Materialized view "public.mvtest_tvm" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- - type | text | | extended | | - totamt | numeric | | main | | + Materialized view "public.mvtest_tvm" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+----------+--------------+------------- + type | text | | | | extended | | + totamt | numeric | | | | main | | View definition: SELECT mvtest_tv.type, mvtest_tv.totamt @@ -118,19 +118,19 @@ View definition: ORDER BY mvtest_tv.type; \d+ mvtest_tvvm - Materialized view "public.mvtest_tvvm" - Column | Type | Modifiers | Storage | Stats target | Description -----------+---------+-----------+---------+--------------+------------- - grandtot | numeric | | main | | + Materialized view "public.mvtest_tvvm" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +----------+---------+-----------+----------+---------+---------+--------------+------------- + grandtot | numeric | | | | main | | View definition: SELECT mvtest_tvv.grandtot FROM mvtest_tvv; \d+ mvtest_bb - Materialized view "public.mvtest_bb" - Column | Type | Modifiers | Storage | Stats target | Description -----------+---------+-----------+---------+--------------+------------- - grandtot | numeric | | main | | + Materialized view "public.mvtest_bb" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +----------+---------+-----------+----------+---------+---------+--------------+------------- + grandtot | numeric | | | | main | | Indexes: "mvtest_aa" btree (grandtot) View definition: @@ -142,10 +142,10 @@ CREATE SCHEMA mvtest_mvschema; ALTER MATERIALIZED VIEW mvtest_tvm SET SCHEMA mvtest_mvschema; \d+ mvtest_tvm \d+ mvtest_tvmm - Materialized view "public.mvtest_tvmm" - Column | Type | Modifiers | Storage | Stats target | Description -----------+---------+-----------+---------+--------------+------------- - grandtot | numeric | | main | | + Materialized view "public.mvtest_tvmm" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +----------+---------+-----------+----------+---------+---------+--------------+------------- + grandtot | numeric | | | | main | | Indexes: "mvtest_tvmm_expr" UNIQUE, btree ((grandtot > 0::numeric)) "mvtest_tvmm_pred" UNIQUE, btree (grandtot) WHERE grandtot < 0::numeric @@ -155,11 +155,11 @@ View definition: SET search_path = mvtest_mvschema, public; \d+ mvtest_tvm - Materialized view "mvtest_mvschema.mvtest_tvm" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- - type | text | | extended | | - totamt | numeric | | main | | + Materialized view "mvtest_mvschema.mvtest_tvm" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+----------+--------------+------------- + type | text | | | | extended | | + totamt | numeric | | | | main | | View definition: SELECT mvtest_tv.type, mvtest_tv.totamt @@ -340,11 +340,11 @@ ROLLBACK; CREATE VIEW mvtest_vt1 AS SELECT 1 moo; CREATE VIEW mvtest_vt2 AS SELECT moo, 2*moo FROM mvtest_vt1 UNION ALL SELECT moo, 3*moo FROM mvtest_vt1; \d+ mvtest_vt2 - View "public.mvtest_vt2" - Column | Type | Modifiers | Storage | Description -----------+---------+-----------+---------+------------- - moo | integer | | plain | - ?column? | integer | | plain | + View "public.mvtest_vt2" + Column | Type | Collation | Nullable | Default | Storage | Description +----------+---------+-----------+----------+---------+---------+------------- + moo | integer | | | | plain | + ?column? | integer | | | | plain | View definition: SELECT mvtest_vt1.moo, 2 * mvtest_vt1.moo @@ -356,11 +356,11 @@ UNION ALL CREATE MATERIALIZED VIEW mv_test2 AS SELECT moo, 2*moo FROM mvtest_vt2 UNION ALL SELECT moo, 3*moo FROM mvtest_vt2; \d+ mv_test2 - Materialized view "public.mv_test2" - Column | Type | Modifiers | Storage | Stats target | Description -----------+---------+-----------+---------+--------------+------------- - moo | integer | | plain | | - ?column? | integer | | plain | | + Materialized view "public.mv_test2" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +----------+---------+-----------+----------+---------+---------+--------------+------------- + moo | integer | | | | plain | | + ?column? | integer | | | | plain | | View definition: SELECT mvtest_vt2.moo, 2 * mvtest_vt2.moo diff --git a/src/test/regress/expected/money.out b/src/test/regress/expected/money.out index 538235c4cc..0cc69f925f 100644 --- a/src/test/regress/expected/money.out +++ b/src/test/regress/expected/money.out @@ -27,18 +27,102 @@ SELECT m - '123.45' FROM money_data; -$0.45 (1 row) +SELECT m / '2'::money FROM money_data; + ?column? +---------- + 61.5 +(1 row) + SELECT m * 2 FROM money_data; ?column? ---------- $246.00 (1 row) +SELECT 2 * m FROM money_data; + ?column? +---------- + $246.00 +(1 row) + SELECT m / 2 FROM money_data; ?column? ---------- $61.50 (1 row) +SELECT m * 2::int2 FROM money_data; + ?column? +---------- + $246.00 +(1 row) + +SELECT 2::int2 * m FROM money_data; + ?column? +---------- + $246.00 +(1 row) + +SELECT m / 2::int2 FROM money_data; + ?column? +---------- + $61.50 +(1 row) + +SELECT m * 2::int8 FROM money_data; + ?column? +---------- + $246.00 +(1 row) + +SELECT 2::int8 * m FROM money_data; + ?column? +---------- + $246.00 +(1 row) + +SELECT m / 2::int8 FROM money_data; + ?column? +---------- + $61.50 +(1 row) + +SELECT m * 2::float8 FROM money_data; + ?column? +---------- + $246.00 +(1 row) + +SELECT 2::float8 * m FROM money_data; + ?column? +---------- + $246.00 +(1 row) + +SELECT m / 2::float8 FROM money_data; + ?column? +---------- + $61.50 +(1 row) + +SELECT m * 2::float4 FROM money_data; + ?column? +---------- + $246.00 +(1 row) + +SELECT 2::float4 * m FROM money_data; + ?column? +---------- + $246.00 +(1 row) + +SELECT m / 2::float4 FROM money_data; + ?column? +---------- + $61.50 +(1 row) + -- All true SELECT m = '$123.00' FROM money_data; ?column? @@ -185,7 +269,97 @@ SELECT * FROM money_data; $123.46 (1 row) --- Cast int4/int8 to money +-- input checks +SELECT '1234567890'::money; + money +------------------- + $1,234,567,890.00 +(1 row) + +SELECT '12345678901234567'::money; + money +---------------------------- + $12,345,678,901,234,567.00 +(1 row) + +SELECT '123456789012345678'::money; +ERROR: value "123456789012345678" is out of range for type money +LINE 1: SELECT '123456789012345678'::money; + ^ +SELECT '9223372036854775807'::money; +ERROR: value "9223372036854775807" is out of range for type money +LINE 1: SELECT '9223372036854775807'::money; + ^ +SELECT '-12345'::money; + money +------------- + -$12,345.00 +(1 row) + +SELECT '-1234567890'::money; + money +-------------------- + -$1,234,567,890.00 +(1 row) + +SELECT '-12345678901234567'::money; + money +----------------------------- + -$12,345,678,901,234,567.00 +(1 row) + +SELECT '-123456789012345678'::money; +ERROR: value "-123456789012345678" is out of range for type money +LINE 1: SELECT '-123456789012345678'::money; + ^ +SELECT '-9223372036854775808'::money; +ERROR: value "-9223372036854775808" is out of range for type money +LINE 1: SELECT '-9223372036854775808'::money; + ^ +-- special characters +SELECT '(1)'::money; + money +-------- + -$1.00 +(1 row) + +SELECT '($123,456.78)'::money; + money +-------------- + -$123,456.78 +(1 row) + +-- documented minimums and maximums +SELECT '-92233720368547758.08'::money; + money +----------------------------- + -$92,233,720,368,547,758.08 +(1 row) + +SELECT '92233720368547758.07'::money; + money +---------------------------- + $92,233,720,368,547,758.07 +(1 row) + +SELECT '-92233720368547758.09'::money; +ERROR: value "-92233720368547758.09" is out of range for type money +LINE 1: SELECT '-92233720368547758.09'::money; + ^ +SELECT '92233720368547758.08'::money; +ERROR: value "92233720368547758.08" is out of range for type money +LINE 1: SELECT '92233720368547758.08'::money; + ^ +-- rounding +SELECT '-92233720368547758.085'::money; +ERROR: value "-92233720368547758.085" is out of range for type money +LINE 1: SELECT '-92233720368547758.085'::money; + ^ +SELECT '92233720368547758.075'::money; +ERROR: value "92233720368547758.075" is out of range for type money +LINE 1: SELECT '92233720368547758.075'::money; + ^ +-- Cast int4/int8/numeric to money SELECT 1234567890::money; money ------------------- @@ -198,10 +372,6 @@ SELECT 12345678901234567::money; $12,345,678,901,234,567.00 (1 row) -SELECT 123456789012345678::money; -ERROR: bigint out of range -SELECT 9223372036854775807::money; -ERROR: bigint out of range SELECT (-12345)::money; money ------------- @@ -220,10 +390,6 @@ SELECT (-12345678901234567)::money; -$12,345,678,901,234,567.00 (1 row) -SELECT (-123456789012345678)::money; -ERROR: bigint out of range -SELECT (-9223372036854775808)::money; -ERROR: bigint out of range SELECT 1234567890::int4::money; money ------------------- @@ -236,6 +402,12 @@ SELECT 12345678901234567::int8::money; $12,345,678,901,234,567.00 (1 row) +SELECT 12345678901234567::numeric::money; + money +---------------------------- + $12,345,678,901,234,567.00 +(1 row) + SELECT (-1234567890)::int4::money; money -------------------- @@ -248,3 +420,22 @@ SELECT (-12345678901234567)::int8::money; -$12,345,678,901,234,567.00 (1 row) +SELECT (-12345678901234567)::numeric::money; + money +----------------------------- + -$12,345,678,901,234,567.00 +(1 row) + +-- Cast from money +SELECT '12345678901234567'::money::numeric; + numeric +---------------------- + 12345678901234567.00 +(1 row) + +SELECT '-12345678901234567'::money::numeric; + numeric +----------------------- + -12345678901234567.00 +(1 row) + diff --git a/src/test/regress/expected/numeric.out b/src/test/regress/expected/numeric.out index f1f50560ee..ae0beb9b68 100644 --- a/src/test/regress/expected/numeric.out +++ b/src/test/regress/expected/numeric.out @@ -1909,3 +1909,19 @@ select scale(-13.000000000000000); 15 (1 row) +-- +-- Tests for SUM() +-- +-- cases that need carry propagation +SELECT SUM(9999::numeric) FROM generate_series(1, 100000); + sum +----------- + 999900000 +(1 row) + +SELECT SUM((-9999)::numeric) FROM generate_series(1, 100000); + sum +------------ + -999900000 +(1 row) + diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index 826441442b..0bcec136c5 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -1819,7 +1819,16 @@ ORDER BY 1, 2, 3; 4000 | 15 | > 4000 | 16 | @> 4000 | 18 | = -(112 rows) + 4000 | 19 | <> + 4000 | 20 | < + 4000 | 21 | <= + 4000 | 22 | > + 4000 | 23 | >= + 4000 | 24 | << + 4000 | 25 | <<= + 4000 | 26 | >> + 4000 | 27 | >>= +(121 rows) -- Check that all opclass search operators have selectivity estimators. -- This is not absolutely required, but it seems a reasonable thing diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out index a2c36e44ba..79513e4598 100644 --- a/src/test/regress/expected/plpgsql.out +++ b/src/test/regress/expected/plpgsql.out @@ -4623,6 +4623,7 @@ drop function tftest(int); create or replace function rttest() returns setof int as $$ declare rc int; + rca int[]; begin return query values(10),(20); get diagnostics rc = row_count; @@ -4631,11 +4632,12 @@ begin get diagnostics rc = row_count; raise notice '% %', found, rc; return query execute 'values(10),(20)'; - get diagnostics rc = row_count; - raise notice '% %', found, rc; + -- just for fun, let's use array elements as targets + get diagnostics rca[1] = row_count; + raise notice '% %', found, rca[1]; return query execute 'select * from (values(10),(20)) f(a) where false'; - get diagnostics rc = row_count; - raise notice '% %', found, rc; + get diagnostics rca[2] = row_count; + raise notice '% %', found, rca[2]; end; $$ language plpgsql; select * from rttest(); @@ -5643,3 +5645,42 @@ end; $$; ERROR: unhandled assertion CONTEXT: PL/pgSQL function inline_code_block line 3 at ASSERT +-- Test use of plpgsql in a domain check constraint (cf. bug #14414) +create function plpgsql_domain_check(val int) returns boolean as $$ +begin return val > 0; end +$$ language plpgsql immutable; +create domain plpgsql_domain as integer check(plpgsql_domain_check(value)); +do $$ +declare v_test plpgsql_domain; +begin + v_test := 1; +end; +$$; +do $$ +declare v_test plpgsql_domain := 1; +begin + v_test := 0; -- fail +end; +$$; +ERROR: value for domain plpgsql_domain violates check constraint "plpgsql_domain_check" +CONTEXT: PL/pgSQL function inline_code_block line 4 at assignment +-- Test handling of expanded array passed to a domain constraint (bug #14472) +create function plpgsql_arr_domain_check(val int[]) returns boolean as $$ +begin return val[1] > 0; end +$$ language plpgsql immutable; +create domain plpgsql_arr_domain as int[] check(plpgsql_arr_domain_check(value)); +do $$ +declare v_test plpgsql_arr_domain; +begin + v_test := array[1]; + v_test := v_test || 2; +end; +$$; +do $$ +declare v_test plpgsql_arr_domain := array[1]; +begin + v_test := 0 || v_test; -- fail +end; +$$; +ERROR: value for domain plpgsql_arr_domain violates check constraint "plpgsql_arr_domain_check" +CONTEXT: PL/pgSQL function inline_code_block line 4 at assignment diff --git a/src/test/regress/expected/polymorphism.out b/src/test/regress/expected/polymorphism.out index ddf45cf597..91cfb743b6 100644 --- a/src/test/regress/expected/polymorphism.out +++ b/src/test/regress/expected/polymorphism.out @@ -635,6 +635,61 @@ create aggregate build_group(int8, integer) ( SFUNC = add_group, STYPE = int8[] ); +-- check proper resolution of data types for polymorphic transfn/finalfn +create function first_el(anyarray) returns anyelement as +'select $1[1]' language sql strict immutable; +create aggregate first_el_agg_f8(float8) ( + SFUNC = array_append, + STYPE = float8[], + FINALFUNC = first_el +); +create aggregate first_el_agg_any(anyelement) ( + SFUNC = array_append, + STYPE = anyarray, + FINALFUNC = first_el +); +select first_el_agg_f8(x::float8) from generate_series(1,10) x; + first_el_agg_f8 +----------------- + 1 +(1 row) + +select first_el_agg_any(x) from generate_series(1,10) x; + first_el_agg_any +------------------ + 1 +(1 row) + +select first_el_agg_f8(x::float8) over(order by x) from generate_series(1,10) x; + first_el_agg_f8 +----------------- + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 +(10 rows) + +select first_el_agg_any(x) over(order by x) from generate_series(1,10) x; + first_el_agg_any +------------------ + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 +(10 rows) + -- check that we can apply functions taking ANYARRAY to pg_stats select distinct array_ndims(histogram_bounds) from pg_stats where histogram_bounds is not null; @@ -1440,13 +1495,13 @@ select * from dfview; (5 rows) \d+ dfview - View "public.dfview" - Column | Type | Modifiers | Storage | Description ---------+--------+-----------+---------+------------- - q1 | bigint | | plain | - q2 | bigint | | plain | - c3 | bigint | | plain | - c4 | bigint | | plain | + View "public.dfview" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+--------+-----------+----------+---------+---------+------------- + q1 | bigint | | | | plain | + q2 | bigint | | | | plain | + c3 | bigint | | | | plain | + c4 | bigint | | | | plain | View definition: SELECT int8_tbl.q1, int8_tbl.q2, diff --git a/src/test/regress/expected/portals.out b/src/test/regress/expected/portals.out index 3ae918a63c..1b8f7b69d1 100644 --- a/src/test/regress/expected/portals.out +++ b/src/test/regress/expected/portals.out @@ -1320,18 +1320,20 @@ fetch backward all in c1; rollback; begin; explain (costs off) declare c2 cursor for select generate_series(1,3) as g; - QUERY PLAN ------------- - Result -(1 row) - -explain (costs off) declare c2 scroll cursor for select generate_series(1,3) as g; QUERY PLAN -------------- - Materialize + ProjectSet -> Result (2 rows) +explain (costs off) declare c2 scroll cursor for select generate_series(1,3) as g; + QUERY PLAN +-------------------- + Materialize + -> ProjectSet + -> Result +(3 rows) + declare c2 scroll cursor for select generate_series(1,3) as g; fetch all in c2; g diff --git a/src/test/regress/expected/prepared_xacts.out b/src/test/regress/expected/prepared_xacts.out index ef7034b588..3a2c533f78 100644 --- a/src/test/regress/expected/prepared_xacts.out +++ b/src/test/regress/expected/prepared_xacts.out @@ -218,10 +218,10 @@ rollback; -- Commit table creation COMMIT PREPARED 'regress-one'; \d pxtest2 - Table "public.pxtest2" - Column | Type | Modifiers ---------+---------+----------- - a | integer | + Table "public.pxtest2" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | SELECT * FROM pxtest2; a diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out index 996ebcdca2..f66b4432a1 100644 --- a/src/test/regress/expected/privileges.out +++ b/src/test/regress/expected/privileges.out @@ -390,7 +390,7 @@ INSERT INTO atest5(two) VALUES (6) ON CONFLICT (two) DO UPDATE set one = 8; -- f ERROR: permission denied for relation atest5 INSERT INTO atest5(three) VALUES (4) ON CONFLICT (two) DO UPDATE set three = 10; -- fails (due to INSERT) ERROR: permission denied for relation atest5 --- Check that the the columns in the inference require select privileges +-- Check that the columns in the inference require select privileges -- Error. No privs on four INSERT INTO atest5(three) VALUES (4) ON CONFLICT (four) DO UPDATE set three = 10; ERROR: permission denied for relation atest5 diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out index 017b79ea9c..464436ab3b 100644 --- a/src/test/regress/expected/psql.out +++ b/src/test/regress/expected/psql.out @@ -123,7 +123,7 @@ unicode_header_linestyle single prepare q as select array_to_string(array_agg(repeat('x',2*n)),E'\n') as "ab c", array_to_string(array_agg(repeat('y',20-2*n)),E'\n') as "a -bc" from generate_series(1,10) as n(n) group by n>1 ; +bc" from generate_series(1,10) as n(n) group by n>1 order by n>1; \pset linestyle ascii \pset expanded off \pset columns 40 diff --git a/src/test/regress/expected/psql_crosstab.out b/src/test/regress/expected/psql_crosstab.out index b583323a9e..eae6fbd051 100644 --- a/src/test/regress/expected/psql_crosstab.out +++ b/src/test/regress/expected/psql_crosstab.out @@ -201,3 +201,16 @@ SELECT a,a,1 FROM generate_series(1,3000) AS a SELECT 1 \crosstabview \crosstabview: query must return at least three columns DROP TABLE ctv_data; +-- check error reporting (bug #14476) +CREATE TABLE ctv_data (x int, y int, v text); +INSERT INTO ctv_data SELECT 1, x, '*' || x FROM generate_series(1,10) x; +SELECT * FROM ctv_data \crosstabview + x | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 +---+----+----+----+----+----+----+----+----+----+----- + 1 | *1 | *2 | *3 | *4 | *5 | *6 | *7 | *8 | *9 | *10 +(1 row) + +INSERT INTO ctv_data VALUES (1, 10, '*'); -- duplicate data to cause error +SELECT * FROM ctv_data \crosstabview +\crosstabview: query result contains multiple data values for row "1", column "10" +DROP TABLE ctv_data; diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out new file mode 100644 index 0000000000..5784b0fded --- /dev/null +++ b/src/test/regress/expected/publication.out @@ -0,0 +1,157 @@ +-- +-- PUBLICATION +-- +CREATE ROLE regress_publication_user LOGIN SUPERUSER; +SET SESSION AUTHORIZATION 'regress_publication_user'; +CREATE PUBLICATION testpub_default; +CREATE PUBLICATION testpib_ins_trunct WITH (nopublish delete, nopublish update); +ALTER PUBLICATION testpub_default WITH (nopublish insert, nopublish delete); +\dRp + List of publications + Name | Owner | Inserts | Updates | Deletes +--------------------+--------------------------+---------+---------+--------- + testpib_ins_trunct | regress_publication_user | t | f | f + testpub_default | regress_publication_user | f | t | f +(2 rows) + +ALTER PUBLICATION testpub_default WITH (publish insert, publish delete); +\dRp + List of publications + Name | Owner | Inserts | Updates | Deletes +--------------------+--------------------------+---------+---------+--------- + testpib_ins_trunct | regress_publication_user | t | f | f + testpub_default | regress_publication_user | t | t | t +(2 rows) + +--- adding tables +CREATE SCHEMA pub_test; +CREATE TABLE testpub_tbl1 (id serial primary key, data text); +CREATE TABLE pub_test.testpub_nopk (foo int, bar int); +CREATE VIEW testpub_view AS SELECT 1; +CREATE PUBLICATION testpub_foralltables FOR ALL TABLES WITH (nopublish delete, nopublish update); +ALTER PUBLICATION testpub_foralltables WITH (publish update); +CREATE TABLE testpub_tbl2 (id serial primary key, data text); +-- fail - can't add to for all tables publication +ALTER PUBLICATION testpub_foralltables ADD TABLE testpub_tbl2; +ERROR: publication "testpub_foralltables" is defined as FOR ALL TABLES +DETAIL: Tables cannot be added to or dropped from FOR ALL TABLES publications. +-- fail - can't drop from all tables publication +ALTER PUBLICATION testpub_foralltables DROP TABLE testpub_tbl2; +ERROR: publication "testpub_foralltables" is defined as FOR ALL TABLES +DETAIL: Tables cannot be added to or dropped from FOR ALL TABLES publications. +-- fail - can't add to for all tables publication +ALTER PUBLICATION testpub_foralltables SET TABLE pub_test.testpub_nopk; +ERROR: publication "testpub_foralltables" is defined as FOR ALL TABLES +DETAIL: Tables cannot be added to or dropped from FOR ALL TABLES publications. +SELECT pubname, puballtables FROM pg_publication WHERE pubname = 'testpub_foralltables'; + pubname | puballtables +----------------------+-------------- + testpub_foralltables | t +(1 row) + +\d+ testpub_tbl2 + Table "public.testpub_tbl2" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+------------------------------------------+----------+--------------+------------- + id | integer | | not null | nextval('testpub_tbl2_id_seq'::regclass) | plain | | + data | text | | | | extended | | +Indexes: + "testpub_tbl2_pkey" PRIMARY KEY, btree (id) +Publications: + "testpub_foralltables" + +DROP TABLE testpub_tbl2; +DROP PUBLICATION testpub_foralltables; +-- fail - view +CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view; +ERROR: "testpub_view" is not a table +DETAIL: Only tables can be added to publications. +CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk; +-- fail - already added +ALTER PUBLICATION testpub_fortbl ADD TABLE testpub_tbl1; +ERROR: relation "testpub_tbl1" is already member of publication "testpub_fortbl" +-- fail - already added +CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1; +ERROR: publication "testpub_fortbl" already exists +\dRp+ testpub_fortbl + Publication testpub_fortbl + Inserts | Updates | Deletes +---------+---------+--------- + t | t | t +Tables: + "pub_test.testpub_nopk" + "public.testpub_tbl1" + +-- fail - view +ALTER PUBLICATION testpub_default ADD TABLE testpub_view; +ERROR: "testpub_view" is not a table +DETAIL: Only tables can be added to publications. +ALTER PUBLICATION testpub_default ADD TABLE testpub_tbl1; +ALTER PUBLICATION testpub_default SET TABLE testpub_tbl1; +ALTER PUBLICATION testpub_default ADD TABLE pub_test.testpub_nopk; +ALTER PUBLICATION testpib_ins_trunct ADD TABLE pub_test.testpub_nopk, testpub_tbl1; +\d+ pub_test.testpub_nopk + Table "pub_test.testpub_nopk" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+---------+--------------+------------- + foo | integer | | | | plain | | + bar | integer | | | | plain | | +Publications: + "testpib_ins_trunct" + "testpub_default" + "testpub_fortbl" + +\d+ testpub_tbl1 + Table "public.testpub_tbl1" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+------------------------------------------+----------+--------------+------------- + id | integer | | not null | nextval('testpub_tbl1_id_seq'::regclass) | plain | | + data | text | | | | extended | | +Indexes: + "testpub_tbl1_pkey" PRIMARY KEY, btree (id) +Publications: + "testpib_ins_trunct" + "testpub_default" + "testpub_fortbl" + +\dRp+ testpub_default + Publication testpub_default + Inserts | Updates | Deletes +---------+---------+--------- + t | t | t +Tables: + "pub_test.testpub_nopk" + "public.testpub_tbl1" + +ALTER PUBLICATION testpub_default DROP TABLE testpub_tbl1, pub_test.testpub_nopk; +-- fail - nonexistent +ALTER PUBLICATION testpub_default DROP TABLE pub_test.testpub_nopk; +ERROR: relation "testpub_nopk" is not part of the publication +\d+ testpub_tbl1 + Table "public.testpub_tbl1" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+------------------------------------------+----------+--------------+------------- + id | integer | | not null | nextval('testpub_tbl1_id_seq'::regclass) | plain | | + data | text | | | | extended | | +Indexes: + "testpub_tbl1_pkey" PRIMARY KEY, btree (id) +Publications: + "testpib_ins_trunct" + "testpub_fortbl" + +DROP VIEW testpub_view; +DROP TABLE testpub_tbl1; +\dRp+ testpub_default + Publication testpub_default + Inserts | Updates | Deletes +---------+---------+--------- + t | t | t +(1 row) + +DROP PUBLICATION testpub_default; +DROP PUBLICATION testpib_ins_trunct; +DROP PUBLICATION testpub_fortbl; +DROP SCHEMA pub_test CASCADE; +NOTICE: drop cascades to table pub_test.testpub_nopk +RESET SESSION AUTHORIZATION; +DROP ROLE regress_publication_user; diff --git a/src/test/regress/expected/rangefuncs.out b/src/test/regress/expected/rangefuncs.out index f06cfa4b21..56481de5c3 100644 --- a/src/test/regress/expected/rangefuncs.out +++ b/src/test/regress/expected/rangefuncs.out @@ -1514,7 +1514,7 @@ SELECT dup(22); (1 row) SELECT dup('xyz'); -- fails -ERROR: could not determine polymorphic type because input has type "unknown" +ERROR: could not determine polymorphic type because input has type unknown SELECT dup('xyz'::text); dup ------------------- @@ -1995,12 +1995,10 @@ SELECT *, END) FROM (VALUES (1,''), (2,'0000000049404'), (3,'FROM 10000000876')) v(id, str); - id | str | lower -----+------------------+------------------ - 1 | | - 2 | 0000000049404 | 49404 - 3 | FROM 10000000876 | from 10000000876 -(3 rows) + id | str | lower +----+---------------+------- + 2 | 0000000049404 | 49404 +(1 row) -- check whole-row-Var handling in nested lateral functions (bug #11703) create function extractq2(t int8_tbl) returns int8 as $$ diff --git a/src/test/regress/expected/regex.linux.utf8.out b/src/test/regress/expected/regex.linux.utf8.out new file mode 100644 index 0000000000..7c170a99f3 --- /dev/null +++ b/src/test/regress/expected/regex.linux.utf8.out @@ -0,0 +1,164 @@ +/* + * This test is for Linux/glibc systems and others that implement proper + * locale classification of Unicode characters with high code values. + * It must be run in a database with UTF8 encoding and a Unicode-aware locale. + */ +SET client_encoding TO UTF8; +-- +-- Test the "high colormap" logic with single characters and ranges that +-- exceed the MAX_SIMPLE_CHR cutoff, here assumed to be less than U+2000. +-- +-- trivial cases: +SELECT 'aⓐ' ~ U&'a\24D0' AS t; + t +--- + t +(1 row) + +SELECT 'aⓐ' ~ U&'a\24D1' AS f; + f +--- + f +(1 row) + +SELECT 'aⓕ' ~ 'a[ⓐ-ⓩ]' AS t; + t +--- + t +(1 row) + +SELECT 'aⒻ' ~ 'a[ⓐ-ⓩ]' AS f; + f +--- + f +(1 row) + +-- cases requiring splitting of ranges: +SELECT 'aⓕⓕ' ~ 'aⓕ[ⓐ-ⓩ]' AS t; + t +--- + t +(1 row) + +SELECT 'aⓕⓐ' ~ 'aⓕ[ⓐ-ⓩ]' AS t; + t +--- + t +(1 row) + +SELECT 'aⓐⓕ' ~ 'aⓕ[ⓐ-ⓩ]' AS f; + f +--- + f +(1 row) + +SELECT 'aⓕⓕ' ~ 'a[ⓐ-ⓩ]ⓕ' AS t; + t +--- + t +(1 row) + +SELECT 'aⓕⓐ' ~ 'a[ⓐ-ⓩ]ⓕ' AS f; + f +--- + f +(1 row) + +SELECT 'aⓐⓕ' ~ 'a[ⓐ-ⓩ]ⓕ' AS t; + t +--- + t +(1 row) + +SELECT 'aⒶⓜ' ~ 'a[Ⓐ-ⓜ][ⓜ-ⓩ]' AS t; + t +--- + t +(1 row) + +SELECT 'aⓜⓜ' ~ 'a[Ⓐ-ⓜ][ⓜ-ⓩ]' AS t; + t +--- + t +(1 row) + +SELECT 'aⓜⓩ' ~ 'a[Ⓐ-ⓜ][ⓜ-ⓩ]' AS t; + t +--- + t +(1 row) + +SELECT 'aⓩⓩ' ~ 'a[Ⓐ-ⓜ][ⓜ-ⓩ]' AS f; + f +--- + f +(1 row) + +SELECT 'aⓜ⓪' ~ 'a[Ⓐ-ⓜ][ⓜ-ⓩ]' AS f; + f +--- + f +(1 row) + +SELECT 'a0' ~ 'a[a-ⓩ]' AS f; + f +--- + f +(1 row) + +SELECT 'aq' ~ 'a[a-ⓩ]' AS t; + t +--- + t +(1 row) + +SELECT 'aⓜ' ~ 'a[a-ⓩ]' AS t; + t +--- + t +(1 row) + +SELECT 'a⓪' ~ 'a[a-ⓩ]' AS f; + f +--- + f +(1 row) + +-- Locale-dependent character classes +SELECT 'aⒶⓜ⓪' ~ '[[:alpha:]][[:alpha:]][[:alpha:]][[:graph:]]' AS t; + t +--- + t +(1 row) + +SELECT 'aⒶⓜ⓪' ~ '[[:alpha:]][[:alpha:]][[:alpha:]][[:alpha:]]' AS f; + f +--- + f +(1 row) + +-- Locale-dependent character classes with high ranges +SELECT 'aⒶⓜ⓪' ~ '[a-z][[:alpha:]][ⓐ-ⓩ][[:graph:]]' AS t; + t +--- + t +(1 row) + +SELECT 'aⓜⒶ⓪' ~ '[a-z][[:alpha:]][ⓐ-ⓩ][[:graph:]]' AS f; + f +--- + f +(1 row) + +SELECT 'aⓜⒶ⓪' ~ '[a-z][ⓐ-ⓩ][[:alpha:]][[:graph:]]' AS t; + t +--- + t +(1 row) + +SELECT 'aⒶⓜ⓪' ~ '[a-z][ⓐ-ⓩ][[:alpha:]][[:graph:]]' AS f; + f +--- + f +(1 row) + diff --git a/src/test/regress/expected/regex.out b/src/test/regress/expected/regex.out index af097193c5..79a7fa7a84 100644 --- a/src/test/regress/expected/regex.out +++ b/src/test/regress/expected/regex.out @@ -90,6 +90,34 @@ select substring('a' from '((a)+)'); a (1 row) +-- Test regexp_match() +select regexp_match('abc', ''); + regexp_match +-------------- + {""} +(1 row) + +select regexp_match('abc', 'bc'); + regexp_match +-------------- + {bc} +(1 row) + +select regexp_match('abc', 'd') is null; + ?column? +---------- + t +(1 row) + +select regexp_match('abc', '(B)(c)', 'i'); + regexp_match +-------------- + {b,c} +(1 row) + +select regexp_match('abc', 'Bd', 'ig'); -- error +ERROR: regexp_match does not support the global option +HINT: Use the regexp_matches function instead. -- Test lookahead constraints select regexp_matches('ab', 'a(?=b)b*'); regexp_matches diff --git a/src/test/regress/expected/replica_identity.out b/src/test/regress/expected/replica_identity.out index 39a60a5619..1a04ec5561 100644 --- a/src/test/regress/expected/replica_identity.out +++ b/src/test/regress/expected/replica_identity.out @@ -77,13 +77,13 @@ SELECT relreplident FROM pg_class WHERE oid = 'test_replica_identity'::regclass; (1 row) \d test_replica_identity - Table "public.test_replica_identity" - Column | Type | Modifiers ---------+---------+-------------------------------------------------------------------- - id | integer | not null default nextval('test_replica_identity_id_seq'::regclass) - keya | text | not null - keyb | text | not null - nonkey | text | + Table "public.test_replica_identity" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------------------------------------------------- + id | integer | | not null | nextval('test_replica_identity_id_seq'::regclass) + keya | text | | not null | + keyb | text | | not null | + nonkey | text | | | Indexes: "test_replica_identity_pkey" PRIMARY KEY, btree (id) REPLICA IDENTITY "test_replica_identity_expr" UNIQUE, btree (keya, keyb, (3)) @@ -110,13 +110,13 @@ SELECT relreplident FROM pg_class WHERE oid = 'test_replica_identity'::regclass; (1 row) \d test_replica_identity - Table "public.test_replica_identity" - Column | Type | Modifiers ---------+---------+-------------------------------------------------------------------- - id | integer | not null default nextval('test_replica_identity_id_seq'::regclass) - keya | text | not null - keyb | text | not null - nonkey | text | + Table "public.test_replica_identity" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------------------------------------------------- + id | integer | | not null | nextval('test_replica_identity_id_seq'::regclass) + keya | text | | not null | + keyb | text | | not null | + nonkey | text | | | Indexes: "test_replica_identity_pkey" PRIMARY KEY, btree (id) "test_replica_identity_expr" UNIQUE, btree (keya, keyb, (3)) @@ -159,13 +159,13 @@ SELECT relreplident FROM pg_class WHERE oid = 'test_replica_identity'::regclass; (1 row) \d+ test_replica_identity - Table "public.test_replica_identity" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+--------------------------------------------------------------------+----------+--------------+------------- - id | integer | not null default nextval('test_replica_identity_id_seq'::regclass) | plain | | - keya | text | not null | extended | | - keyb | text | not null | extended | | - nonkey | text | | extended | | + Table "public.test_replica_identity" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------------------------------------------------+----------+--------------+------------- + id | integer | | not null | nextval('test_replica_identity_id_seq'::regclass) | plain | | + keya | text | | not null | | extended | | + keyb | text | | not null | | extended | | + nonkey | text | | | | extended | | Indexes: "test_replica_identity_pkey" PRIMARY KEY, btree (id) "test_replica_identity_expr" UNIQUE, btree (keya, keyb, (3)) diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out index c15bf958a5..25407bf9dd 100644 --- a/src/test/regress/expected/rowsecurity.out +++ b/src/test/regress/expected/rowsecurity.out @@ -7,6 +7,7 @@ SET client_min_messages TO 'warning'; DROP USER IF EXISTS regress_rls_alice; DROP USER IF EXISTS regress_rls_bob; DROP USER IF EXISTS regress_rls_carol; +DROP USER IF EXISTS regress_rls_dave; DROP USER IF EXISTS regress_rls_exempt_user; DROP ROLE IF EXISTS regress_rls_group1; DROP ROLE IF EXISTS regress_rls_group2; @@ -16,6 +17,7 @@ RESET client_min_messages; CREATE USER regress_rls_alice NOLOGIN; CREATE USER regress_rls_bob NOLOGIN; CREATE USER regress_rls_carol NOLOGIN; +CREATE USER regress_rls_dave NOLOGIN; CREATE USER regress_rls_exempt_user BYPASSRLS NOLOGIN; CREATE ROLE regress_rls_group1 NOLOGIN; CREATE ROLE regress_rls_group2 NOLOGIN; @@ -67,11 +69,84 @@ INSERT INTO document VALUES ( 5, 44, 2, 'regress_rls_bob', 'my second manga'), ( 6, 22, 1, 'regress_rls_carol', 'great science fiction'), ( 7, 33, 2, 'regress_rls_carol', 'great technology book'), - ( 8, 44, 1, 'regress_rls_carol', 'great manga'); + ( 8, 44, 1, 'regress_rls_carol', 'great manga'), + ( 9, 22, 1, 'regress_rls_dave', 'awesome science fiction'), + (10, 33, 2, 'regress_rls_dave', 'awesome technology book'); ALTER TABLE document ENABLE ROW LEVEL SECURITY; -- user's security level must be higher than or equal to document's -CREATE POLICY p1 ON document +CREATE POLICY p1 ON document AS PERMISSIVE USING (dlevel <= (SELECT seclv FROM uaccount WHERE pguser = current_user)); +-- try to create a policy of bogus type +CREATE POLICY p1 ON document AS UGLY + USING (dlevel <= (SELECT seclv FROM uaccount WHERE pguser = current_user)); +ERROR: unrecognized row security option "ugly" +LINE 1: CREATE POLICY p1 ON document AS UGLY + ^ +HINT: Only PERMISSIVE or RESTRICTIVE policies are supported currently. +-- but Dave isn't allowed to anything at cid 50 or above +-- this is to make sure that we sort the policies by name first +-- when applying WITH CHECK, a later INSERT by Dave should fail due +-- to p1r first +CREATE POLICY p2r ON document AS RESTRICTIVE TO regress_rls_dave + USING (cid <> 44 AND cid < 50); +-- and Dave isn't allowed to see manga documents +CREATE POLICY p1r ON document AS RESTRICTIVE TO regress_rls_dave + USING (cid <> 44); +\dp + Access privileges + Schema | Name | Type | Access privileges | Column privileges | Policies +--------------------+----------+-------+---------------------------------------------+-------------------+-------------------------------------------- + regress_rls_schema | category | table | regress_rls_alice=arwdDxt/regress_rls_alice+| | + | | | =arwdDxt/regress_rls_alice | | + regress_rls_schema | document | table | regress_rls_alice=arwdDxt/regress_rls_alice+| | p1: + + | | | =arwdDxt/regress_rls_alice | | (u): (dlevel <= ( SELECT uaccount.seclv + + | | | | | FROM uaccount + + | | | | | WHERE (uaccount.pguser = CURRENT_USER)))+ + | | | | | p2r (RESTRICTIVE): + + | | | | | (u): ((cid <> 44) AND (cid < 50)) + + | | | | | to: regress_rls_dave + + | | | | | p1r (RESTRICTIVE): + + | | | | | (u): (cid <> 44) + + | | | | | to: regress_rls_dave + regress_rls_schema | uaccount | table | regress_rls_alice=arwdDxt/regress_rls_alice+| | + | | | =r/regress_rls_alice | | +(3 rows) + +\d document + Table "regress_rls_schema.document" + Column | Type | Collation | Nullable | Default +---------+---------+-----------+----------+--------- + did | integer | | not null | + cid | integer | | | + dlevel | integer | | not null | + dauthor | name | | | + dtitle | text | | | +Indexes: + "document_pkey" PRIMARY KEY, btree (did) +Foreign-key constraints: + "document_cid_fkey" FOREIGN KEY (cid) REFERENCES category(cid) +Policies: + POLICY "p1" + USING ((dlevel <= ( SELECT uaccount.seclv + FROM uaccount + WHERE (uaccount.pguser = CURRENT_USER)))) + POLICY "p1r" AS RESTRICTIVE + TO regress_rls_dave + USING ((cid <> 44)) + POLICY "p2r" AS RESTRICTIVE + TO regress_rls_dave + USING (((cid <> 44) AND (cid < 50))) + +SELECT * FROM pg_policies WHERE schemaname = 'regress_rls_schema' AND tablename = 'document' ORDER BY policyname; + schemaname | tablename | policyname | permissive | roles | cmd | qual | with_check +--------------------+-----------+------------+-------------+--------------------+-----+--------------------------------------------+------------ + regress_rls_schema | document | p1 | PERMISSIVE | {public} | ALL | (dlevel <= ( SELECT uaccount.seclv +| + | | | | | | FROM uaccount +| + | | | | | | WHERE (uaccount.pguser = CURRENT_USER))) | + regress_rls_schema | document | p1r | RESTRICTIVE | {regress_rls_dave} | ALL | (cid <> 44) | + regress_rls_schema | document | p2r | RESTRICTIVE | {regress_rls_dave} | ALL | ((cid <> 44) AND (cid < 50)) | +(3 rows) + -- viewpoint from regress_rls_bob SET SESSION AUTHORIZATION regress_rls_bob; SET row_security TO ON; @@ -80,26 +155,30 @@ NOTICE: f_leak => my first novel NOTICE: f_leak => my first manga NOTICE: f_leak => great science fiction NOTICE: f_leak => great manga - did | cid | dlevel | dauthor | dtitle ------+-----+--------+-------------------+----------------------- +NOTICE: f_leak => awesome science fiction + did | cid | dlevel | dauthor | dtitle +-----+-----+--------+-------------------+------------------------- 1 | 11 | 1 | regress_rls_bob | my first novel 4 | 44 | 1 | regress_rls_bob | my first manga 6 | 22 | 1 | regress_rls_carol | great science fiction 8 | 44 | 1 | regress_rls_carol | great manga -(4 rows) + 9 | 22 | 1 | regress_rls_dave | awesome science fiction +(5 rows) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle) ORDER BY did; NOTICE: f_leak => my first novel NOTICE: f_leak => my first manga NOTICE: f_leak => great science fiction NOTICE: f_leak => great manga - cid | did | dlevel | dauthor | dtitle | cname ------+-----+--------+-------------------+-----------------------+----------------- - 11 | 1 | 1 | regress_rls_bob | my first novel | novel - 44 | 4 | 1 | regress_rls_bob | my first manga | manga - 22 | 6 | 1 | regress_rls_carol | great science fiction | science fiction - 44 | 8 | 1 | regress_rls_carol | great manga | manga -(4 rows) +NOTICE: f_leak => awesome science fiction + cid | did | dlevel | dauthor | dtitle | cname +-----+-----+--------+-------------------+-------------------------+----------------- + 11 | 1 | 1 | regress_rls_bob | my first novel | novel + 44 | 4 | 1 | regress_rls_bob | my first manga | manga + 22 | 6 | 1 | regress_rls_carol | great science fiction | science fiction + 44 | 8 | 1 | regress_rls_carol | great manga | manga + 22 | 9 | 1 | regress_rls_dave | awesome science fiction | science fiction +(5 rows) -- try a sampled version SELECT * FROM document TABLESAMPLE BERNOULLI(50) REPEATABLE(0) @@ -107,12 +186,14 @@ SELECT * FROM document TABLESAMPLE BERNOULLI(50) REPEATABLE(0) NOTICE: f_leak => my first manga NOTICE: f_leak => great science fiction NOTICE: f_leak => great manga - did | cid | dlevel | dauthor | dtitle ------+-----+--------+-------------------+----------------------- +NOTICE: f_leak => awesome science fiction + did | cid | dlevel | dauthor | dtitle +-----+-----+--------+-------------------+------------------------- 4 | 44 | 1 | regress_rls_bob | my first manga 6 | 22 | 1 | regress_rls_carol | great science fiction 8 | 44 | 1 | regress_rls_carol | great manga -(3 rows) + 9 | 22 | 1 | regress_rls_dave | awesome science fiction +(4 rows) -- viewpoint from regress_rls_carol SET SESSION AUTHORIZATION regress_rls_carol; @@ -125,8 +206,10 @@ NOTICE: f_leak => my second manga NOTICE: f_leak => great science fiction NOTICE: f_leak => great technology book NOTICE: f_leak => great manga - did | cid | dlevel | dauthor | dtitle ------+-----+--------+-------------------+----------------------- +NOTICE: f_leak => awesome science fiction +NOTICE: f_leak => awesome technology book + did | cid | dlevel | dauthor | dtitle +-----+-----+--------+-------------------+------------------------- 1 | 11 | 1 | regress_rls_bob | my first novel 2 | 11 | 2 | regress_rls_bob | my second novel 3 | 22 | 2 | regress_rls_bob | my science fiction @@ -135,7 +218,9 @@ NOTICE: f_leak => great manga 6 | 22 | 1 | regress_rls_carol | great science fiction 7 | 33 | 2 | regress_rls_carol | great technology book 8 | 44 | 1 | regress_rls_carol | great manga -(8 rows) + 9 | 22 | 1 | regress_rls_dave | awesome science fiction + 10 | 33 | 2 | regress_rls_dave | awesome technology book +(10 rows) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle) ORDER BY did; NOTICE: f_leak => my first novel @@ -146,17 +231,21 @@ NOTICE: f_leak => my second manga NOTICE: f_leak => great science fiction NOTICE: f_leak => great technology book NOTICE: f_leak => great manga - cid | did | dlevel | dauthor | dtitle | cname ------+-----+--------+-------------------+-----------------------+----------------- - 11 | 1 | 1 | regress_rls_bob | my first novel | novel - 11 | 2 | 2 | regress_rls_bob | my second novel | novel - 22 | 3 | 2 | regress_rls_bob | my science fiction | science fiction - 44 | 4 | 1 | regress_rls_bob | my first manga | manga - 44 | 5 | 2 | regress_rls_bob | my second manga | manga - 22 | 6 | 1 | regress_rls_carol | great science fiction | science fiction - 33 | 7 | 2 | regress_rls_carol | great technology book | technology - 44 | 8 | 1 | regress_rls_carol | great manga | manga -(8 rows) +NOTICE: f_leak => awesome science fiction +NOTICE: f_leak => awesome technology book + cid | did | dlevel | dauthor | dtitle | cname +-----+-----+--------+-------------------+-------------------------+----------------- + 11 | 1 | 1 | regress_rls_bob | my first novel | novel + 11 | 2 | 2 | regress_rls_bob | my second novel | novel + 22 | 3 | 2 | regress_rls_bob | my science fiction | science fiction + 44 | 4 | 1 | regress_rls_bob | my first manga | manga + 44 | 5 | 2 | regress_rls_bob | my second manga | manga + 22 | 6 | 1 | regress_rls_carol | great science fiction | science fiction + 33 | 7 | 2 | regress_rls_carol | great technology book | technology + 44 | 8 | 1 | regress_rls_carol | great manga | manga + 22 | 9 | 1 | regress_rls_dave | awesome science fiction | science fiction + 33 | 10 | 2 | regress_rls_dave | awesome technology book | technology +(10 rows) -- try a sampled version SELECT * FROM document TABLESAMPLE BERNOULLI(50) REPEATABLE(0) @@ -165,42 +254,111 @@ NOTICE: f_leak => my first manga NOTICE: f_leak => my second manga NOTICE: f_leak => great science fiction NOTICE: f_leak => great manga - did | cid | dlevel | dauthor | dtitle ------+-----+--------+-------------------+----------------------- +NOTICE: f_leak => awesome science fiction + did | cid | dlevel | dauthor | dtitle +-----+-----+--------+-------------------+------------------------- 4 | 44 | 1 | regress_rls_bob | my first manga 5 | 44 | 2 | regress_rls_bob | my second manga 6 | 22 | 1 | regress_rls_carol | great science fiction 8 | 44 | 1 | regress_rls_carol | great manga -(4 rows) + 9 | 22 | 1 | regress_rls_dave | awesome science fiction +(5 rows) EXPLAIN (COSTS OFF) SELECT * FROM document WHERE f_leak(dtitle); - QUERY PLAN ----------------------------------------------------------- - Subquery Scan on document - Filter: f_leak(document.dtitle) - -> Seq Scan on document document_1 - Filter: (dlevel <= $0) - InitPlan 1 (returns $0) - -> Index Scan using uaccount_pkey on uaccount - Index Cond: (pguser = "current_user"()) + QUERY PLAN +---------------------------------------------------- + Seq Scan on document + Filter: ((dlevel <= $0) AND f_leak(dtitle)) + InitPlan 1 (returns $0) + -> Index Scan using uaccount_pkey on uaccount + Index Cond: (pguser = CURRENT_USER) +(5 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle); + QUERY PLAN +----------------------------------------------------------- + Hash Join + Hash Cond: (category.cid = document.cid) + InitPlan 1 (returns $0) + -> Index Scan using uaccount_pkey on uaccount + Index Cond: (pguser = CURRENT_USER) + -> Seq Scan on category + -> Hash + -> Seq Scan on document + Filter: ((dlevel <= $0) AND f_leak(dtitle)) +(9 rows) + +-- viewpoint from regress_rls_dave +SET SESSION AUTHORIZATION regress_rls_dave; +SELECT * FROM document WHERE f_leak(dtitle) ORDER BY did; +NOTICE: f_leak => my first novel +NOTICE: f_leak => my second novel +NOTICE: f_leak => my science fiction +NOTICE: f_leak => great science fiction +NOTICE: f_leak => great technology book +NOTICE: f_leak => awesome science fiction +NOTICE: f_leak => awesome technology book + did | cid | dlevel | dauthor | dtitle +-----+-----+--------+-------------------+------------------------- + 1 | 11 | 1 | regress_rls_bob | my first novel + 2 | 11 | 2 | regress_rls_bob | my second novel + 3 | 22 | 2 | regress_rls_bob | my science fiction + 6 | 22 | 1 | regress_rls_carol | great science fiction + 7 | 33 | 2 | regress_rls_carol | great technology book + 9 | 22 | 1 | regress_rls_dave | awesome science fiction + 10 | 33 | 2 | regress_rls_dave | awesome technology book (7 rows) +SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle) ORDER BY did; +NOTICE: f_leak => my first novel +NOTICE: f_leak => my second novel +NOTICE: f_leak => my science fiction +NOTICE: f_leak => great science fiction +NOTICE: f_leak => great technology book +NOTICE: f_leak => awesome science fiction +NOTICE: f_leak => awesome technology book + cid | did | dlevel | dauthor | dtitle | cname +-----+-----+--------+-------------------+-------------------------+----------------- + 11 | 1 | 1 | regress_rls_bob | my first novel | novel + 11 | 2 | 2 | regress_rls_bob | my second novel | novel + 22 | 3 | 2 | regress_rls_bob | my science fiction | science fiction + 22 | 6 | 1 | regress_rls_carol | great science fiction | science fiction + 33 | 7 | 2 | regress_rls_carol | great technology book | technology + 22 | 9 | 1 | regress_rls_dave | awesome science fiction | science fiction + 33 | 10 | 2 | regress_rls_dave | awesome technology book | technology +(7 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM document WHERE f_leak(dtitle); + QUERY PLAN +---------------------------------------------------------------------------------------------- + Seq Scan on document + Filter: ((cid <> 44) AND (cid <> 44) AND (cid < 50) AND (dlevel <= $0) AND f_leak(dtitle)) + InitPlan 1 (returns $0) + -> Index Scan using uaccount_pkey on uaccount + Index Cond: (pguser = CURRENT_USER) +(5 rows) + EXPLAIN (COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle); - QUERY PLAN ----------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------- Hash Join Hash Cond: (category.cid = document.cid) + InitPlan 1 (returns $0) + -> Index Scan using uaccount_pkey on uaccount + Index Cond: (pguser = CURRENT_USER) -> Seq Scan on category -> Hash - -> Subquery Scan on document - Filter: f_leak(document.dtitle) - -> Seq Scan on document document_1 - Filter: (dlevel <= $0) - InitPlan 1 (returns $0) - -> Index Scan using uaccount_pkey on uaccount - Index Cond: (pguser = "current_user"()) -(11 rows) + -> Seq Scan on document + Filter: ((cid <> 44) AND (cid <> 44) AND (cid < 50) AND (dlevel <= $0) AND f_leak(dtitle)) +(9 rows) +-- 44 would technically fail for both p2r and p1r, but we should get an error +-- back from p1r for this because it sorts first +INSERT INTO document VALUES (100, 44, 1, 'regress_rls_dave', 'testing sorting of policies'); -- fail +ERROR: new row violates row-level security policy "p1r" for table "document" +-- Just to see a p2r error +INSERT INTO document VALUES (100, 55, 1, 'regress_rls_dave', 'testing sorting of policies'); -- fail +ERROR: new row violates row-level security policy "p2r" for table "document" -- only owner can change policies ALTER POLICY p1 ON document USING (true); --fail ERROR: must be owner of relation document @@ -265,25 +423,21 @@ NOTICE: f_leak => great manga (3 rows) EXPLAIN (COSTS OFF) SELECT * FROM document WHERE f_leak(dtitle); - QUERY PLAN ----------------------------------------------- - Subquery Scan on document - Filter: f_leak(document.dtitle) - -> Seq Scan on document document_1 - Filter: (dauthor = "current_user"()) -(4 rows) + QUERY PLAN +--------------------------------------------------------- + Seq Scan on document + Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle)) +(2 rows) EXPLAIN (COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle); - QUERY PLAN ----------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------- Nested Loop - -> Subquery Scan on document - Filter: f_leak(document.dtitle) - -> Seq Scan on document document_1 - Filter: (dauthor = "current_user"()) + -> Seq Scan on document + Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle)) -> Index Scan using category_pkey on category Index Cond: (cid = document.cid) -(7 rows) +(5 rows) -- interaction of FK/PK constraints SET SESSION AUTHORIZATION regress_rls_alice; @@ -318,7 +472,7 @@ SELECT * FROM document d FULL OUTER JOIN category c on d.cid = c.cid; 7 | 33 | 2 | regress_rls_carol | great technology book | | (3 rows) -INSERT INTO document VALUES (10, 33, 1, current_user, 'hoge'); +INSERT INTO document VALUES (11, 33, 1, current_user, 'hoge'); -- UNIQUE or PRIMARY KEY constraint violation DOES reveal presence of row SET SESSION AUTHORIZATION regress_rls_bob; INSERT INTO document VALUES (8, 44, 1, 'regress_rls_bob', 'my third manga'); -- Must fail with unique violation, revealing presence of did we can't see @@ -337,8 +491,8 @@ ERROR: new row violates row-level security policy for table "document" RESET SESSION AUTHORIZATION; SET row_security TO ON; SELECT * FROM document; - did | cid | dlevel | dauthor | dtitle ------+-----+--------+-------------------+----------------------- + did | cid | dlevel | dauthor | dtitle +-----+-----+--------+-------------------+------------------------- 1 | 11 | 1 | regress_rls_bob | my first novel 2 | 11 | 2 | regress_rls_bob | my second novel 3 | 22 | 2 | regress_rls_bob | my science fiction @@ -347,8 +501,10 @@ SELECT * FROM document; 6 | 22 | 1 | regress_rls_carol | great science fiction 7 | 33 | 2 | regress_rls_carol | great technology book 8 | 44 | 1 | regress_rls_carol | great manga - 10 | 33 | 1 | regress_rls_carol | hoge -(9 rows) + 9 | 22 | 1 | regress_rls_dave | awesome science fiction + 10 | 33 | 2 | regress_rls_dave | awesome technology book + 11 | 33 | 1 | regress_rls_carol | hoge +(11 rows) SELECT * FROM category; cid | cname @@ -363,8 +519,8 @@ SELECT * FROM category; RESET SESSION AUTHORIZATION; SET row_security TO OFF; SELECT * FROM document; - did | cid | dlevel | dauthor | dtitle ------+-----+--------+-------------------+----------------------- + did | cid | dlevel | dauthor | dtitle +-----+-----+--------+-------------------+------------------------- 1 | 11 | 1 | regress_rls_bob | my first novel 2 | 11 | 2 | regress_rls_bob | my second novel 3 | 22 | 2 | regress_rls_bob | my science fiction @@ -373,8 +529,10 @@ SELECT * FROM document; 6 | 22 | 1 | regress_rls_carol | great science fiction 7 | 33 | 2 | regress_rls_carol | great technology book 8 | 44 | 1 | regress_rls_carol | great manga - 10 | 33 | 1 | regress_rls_carol | hoge -(9 rows) + 9 | 22 | 1 | regress_rls_dave | awesome science fiction + 10 | 33 | 2 | regress_rls_dave | awesome technology book + 11 | 33 | 1 | regress_rls_carol | hoge +(11 rows) SELECT * FROM category; cid | cname @@ -389,8 +547,8 @@ SELECT * FROM category; SET SESSION AUTHORIZATION regress_rls_exempt_user; SET row_security TO OFF; SELECT * FROM document; - did | cid | dlevel | dauthor | dtitle ------+-----+--------+-------------------+----------------------- + did | cid | dlevel | dauthor | dtitle +-----+-----+--------+-------------------+------------------------- 1 | 11 | 1 | regress_rls_bob | my first novel 2 | 11 | 2 | regress_rls_bob | my second novel 3 | 22 | 2 | regress_rls_bob | my science fiction @@ -399,8 +557,10 @@ SELECT * FROM document; 6 | 22 | 1 | regress_rls_carol | great science fiction 7 | 33 | 2 | regress_rls_carol | great technology book 8 | 44 | 1 | regress_rls_carol | great manga - 10 | 33 | 1 | regress_rls_carol | hoge -(9 rows) + 9 | 22 | 1 | regress_rls_dave | awesome science fiction + 10 | 33 | 2 | regress_rls_dave | awesome technology book + 11 | 33 | 1 | regress_rls_carol | hoge +(11 rows) SELECT * FROM category; cid | cname @@ -415,8 +575,8 @@ SELECT * FROM category; SET SESSION AUTHORIZATION regress_rls_alice; SET row_security TO ON; SELECT * FROM document; - did | cid | dlevel | dauthor | dtitle ------+-----+--------+-------------------+----------------------- + did | cid | dlevel | dauthor | dtitle +-----+-----+--------+-------------------+------------------------- 1 | 11 | 1 | regress_rls_bob | my first novel 2 | 11 | 2 | regress_rls_bob | my second novel 3 | 22 | 2 | regress_rls_bob | my science fiction @@ -425,8 +585,10 @@ SELECT * FROM document; 6 | 22 | 1 | regress_rls_carol | great science fiction 7 | 33 | 2 | regress_rls_carol | great technology book 8 | 44 | 1 | regress_rls_carol | great manga - 10 | 33 | 1 | regress_rls_carol | hoge -(9 rows) + 9 | 22 | 1 | regress_rls_dave | awesome science fiction + 10 | 33 | 2 | regress_rls_dave | awesome technology book + 11 | 33 | 1 | regress_rls_carol | hoge +(11 rows) SELECT * FROM category; cid | cname @@ -441,8 +603,8 @@ SELECT * FROM category; SET SESSION AUTHORIZATION regress_rls_alice; SET row_security TO OFF; SELECT * FROM document; - did | cid | dlevel | dauthor | dtitle ------+-----+--------+-------------------+----------------------- + did | cid | dlevel | dauthor | dtitle +-----+-----+--------+-------------------+------------------------- 1 | 11 | 1 | regress_rls_bob | my first novel 2 | 11 | 2 | regress_rls_bob | my second novel 3 | 22 | 2 | regress_rls_bob | my science fiction @@ -451,8 +613,10 @@ SELECT * FROM document; 6 | 22 | 1 | regress_rls_carol | great science fiction 7 | 33 | 2 | regress_rls_carol | great technology book 8 | 44 | 1 | regress_rls_carol | great manga - 10 | 33 | 1 | regress_rls_carol | hoge -(9 rows) + 9 | 22 | 1 | regress_rls_dave | awesome science fiction + 10 | 33 | 2 | regress_rls_dave | awesome technology book + 11 | 33 | 1 | regress_rls_carol | hoge +(11 rows) SELECT * FROM category; cid | cname @@ -522,18 +686,16 @@ NOTICE: f_leak => yyy (5 rows) EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b); - QUERY PLAN -------------------------------------- - Subquery Scan on t1 - Filter: f_leak(t1.b) - -> Append - -> Seq Scan on t1 t1_1 - Filter: ((a % 2) = 0) - -> Seq Scan on t2 - Filter: ((a % 2) = 0) - -> Seq Scan on t3 - Filter: ((a % 2) = 0) -(9 rows) + QUERY PLAN +----------------------------------------------- + Append + -> Seq Scan on t1 + Filter: (((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t2 + Filter: (((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t3 + Filter: (((a % 2) = 0) AND f_leak(b)) +(7 rows) -- reference to system column SELECT oid, * FROM t1; @@ -593,20 +755,17 @@ SELECT * FROM t1 FOR SHARE; (5 rows) EXPLAIN (COSTS OFF) SELECT * FROM t1 FOR SHARE; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +------------------------------------- LockRows - -> Subquery Scan on t1 - -> LockRows - -> Result - -> Append - -> Seq Scan on t1 t1_1 - Filter: ((a % 2) = 0) - -> Seq Scan on t2 - Filter: ((a % 2) = 0) - -> Seq Scan on t3 - Filter: ((a % 2) = 0) -(11 rows) + -> Append + -> Seq Scan on t1 + Filter: ((a % 2) = 0) + -> Seq Scan on t2 + Filter: ((a % 2) = 0) + -> Seq Scan on t3 + Filter: ((a % 2) = 0) +(8 rows) SELECT * FROM t1 WHERE f_leak(b) FOR SHARE; NOTICE: f_leak => bbb @@ -624,21 +783,17 @@ NOTICE: f_leak => yyy (5 rows) EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b) FOR SHARE; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +----------------------------------------------------- LockRows - -> Subquery Scan on t1 - Filter: f_leak(t1.b) - -> LockRows - -> Result - -> Append - -> Seq Scan on t1 t1_1 - Filter: ((a % 2) = 0) - -> Seq Scan on t2 - Filter: ((a % 2) = 0) - -> Seq Scan on t3 - Filter: ((a % 2) = 0) -(12 rows) + -> Append + -> Seq Scan on t1 + Filter: (((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t2 + Filter: (((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t3 + Filter: (((a % 2) = 0) AND f_leak(b)) +(8 rows) -- union all query SELECT a, b, oid FROM t2 UNION ALL SELECT a, b, oid FROM t3; @@ -848,21 +1003,14 @@ NOTICE: f_leak => a87ff679a2f3e71d9181a67b7542122c (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM only s1 WHERE f_leak(b); - QUERY PLAN ----------------------------------------------------------- - Subquery Scan on s1 - Filter: f_leak(s1.b) - -> Hash Join - Hash Cond: (s1_1.a = s2.x) - -> Seq Scan on s1 s1_1 - -> Hash - -> HashAggregate - Group Key: s2.x - -> Subquery Scan on s2 - Filter: (s2.y ~~ '%2f%'::text) - -> Seq Scan on s2 s2_1 - Filter: ((x % 2) = 0) -(12 rows) + QUERY PLAN +----------------------------------------------------------- + Seq Scan on s1 + Filter: ((hashed SubPlan 1) AND f_leak(b)) + SubPlan 1 + -> Seq Scan on s2 + Filter: (((x % 2) = 0) AND (y ~~ '%2f%'::text)) +(5 rows) SET SESSION AUTHORIZATION regress_rls_alice; ALTER POLICY p1 ON s1 USING (a in (select x from v2)); -- using VIEW in RLS policy @@ -877,21 +1025,14 @@ NOTICE: f_leak => 1679091c5a880faf6fb5e6087eb1b2dc (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM s1 WHERE f_leak(b); - QUERY PLAN ----------------------------------------------------------- - Subquery Scan on s1 - Filter: f_leak(s1.b) - -> Hash Join - Hash Cond: (s1_1.a = s2.x) - -> Seq Scan on s1 s1_1 - -> Hash - -> HashAggregate - Group Key: s2.x - -> Subquery Scan on s2 - Filter: (s2.y ~~ '%af%'::text) - -> Seq Scan on s2 s2_1 - Filter: ((x % 2) = 0) -(12 rows) + QUERY PLAN +----------------------------------------------------------- + Seq Scan on s1 + Filter: ((hashed SubPlan 1) AND f_leak(b)) + SubPlan 1 + -> Seq Scan on s2 + Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text)) +(5 rows) SELECT (SELECT x FROM s1 LIMIT 1) xx, * FROM s2 WHERE y like '%28%'; xx | x | y @@ -902,24 +1043,18 @@ SELECT (SELECT x FROM s1 LIMIT 1) xx, * FROM s2 WHERE y like '%28%'; (3 rows) EXPLAIN (COSTS OFF) SELECT (SELECT x FROM s1 LIMIT 1) xx, * FROM s2 WHERE y like '%28%'; - QUERY PLAN --------------------------------------------------------------------- - Subquery Scan on s2 - Filter: (s2.y ~~ '%28%'::text) - -> Seq Scan on s2 s2_1 - Filter: ((x % 2) = 0) - SubPlan 1 + QUERY PLAN +------------------------------------------------------------------------- + Seq Scan on s2 + Filter: (((x % 2) = 0) AND (y ~~ '%28%'::text)) + SubPlan 2 -> Limit - -> Subquery Scan on s1 - -> Nested Loop Semi Join - Join Filter: (s1_1.a = s2_2.x) - -> Seq Scan on s1 s1_1 - -> Materialize - -> Subquery Scan on s2_2 - Filter: (s2_2.y ~~ '%af%'::text) - -> Seq Scan on s2 s2_3 - Filter: ((x % 2) = 0) -(15 rows) + -> Seq Scan on s1 + Filter: (hashed SubPlan 1) + SubPlan 1 + -> Seq Scan on s2 s2_1 + Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text)) +(9 rows) SET SESSION AUTHORIZATION regress_rls_alice; ALTER POLICY p2 ON s2 USING (x in (select a from s1 where b like '%d2%')); @@ -1063,28 +1198,19 @@ EXPLAIN (COSTS OFF) EXECUTE p2(2); -- SET SESSION AUTHORIZATION regress_rls_bob; EXPLAIN (COSTS OFF) UPDATE t1 SET b = b || b WHERE f_leak(b); - QUERY PLAN -------------------------------------------- - Update on t1 t1_3 - Update on t1 t1_3 - Update on t2 t1 - Update on t3 t1 - -> Subquery Scan on t1 - Filter: f_leak(t1.b) - -> LockRows - -> Seq Scan on t1 t1_4 - Filter: ((a % 2) = 0) - -> Subquery Scan on t1_1 - Filter: f_leak(t1_1.b) - -> LockRows - -> Seq Scan on t2 - Filter: ((a % 2) = 0) - -> Subquery Scan on t1_2 - Filter: f_leak(t1_2.b) - -> LockRows - -> Seq Scan on t3 - Filter: ((a % 2) = 0) -(19 rows) + QUERY PLAN +----------------------------------------------- + Update on t1 + Update on t1 + Update on t2 + Update on t3 + -> Seq Scan on t1 + Filter: (((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t2 + Filter: (((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t3 + Filter: (((a % 2) = 0) AND f_leak(b)) +(10 rows) UPDATE t1 SET b = b || b WHERE f_leak(b); NOTICE: f_leak => bbb @@ -1093,15 +1219,12 @@ NOTICE: f_leak => bcd NOTICE: f_leak => def NOTICE: f_leak => yyy EXPLAIN (COSTS OFF) UPDATE only t1 SET b = b || '_updt' WHERE f_leak(b); - QUERY PLAN -------------------------------------------- - Update on t1 t1_1 - -> Subquery Scan on t1 - Filter: f_leak(t1.b) - -> LockRows - -> Seq Scan on t1 t1_2 - Filter: ((a % 2) = 0) -(6 rows) + QUERY PLAN +----------------------------------------------- + Update on t1 + -> Seq Scan on t1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(3 rows) UPDATE only t1 SET b = b || '_updt' WHERE f_leak(b); NOTICE: f_leak => bbbbbb @@ -1149,89 +1272,63 @@ NOTICE: f_leak => yyyyyy -- updates with from clause EXPLAIN (COSTS OFF) UPDATE t2 SET b=t2.b FROM t3 WHERE t2.a = 3 and t3.a = 2 AND f_leak(t2.b) AND f_leak(t3.b); - QUERY PLAN ---------------------------------------------------------------- - Update on t2 t2_1 + QUERY PLAN +----------------------------------------------------------------- + Update on t2 -> Nested Loop - -> Subquery Scan on t2 - Filter: f_leak(t2.b) - -> LockRows - -> Seq Scan on t2 t2_2 - Filter: ((a = 3) AND ((a % 2) = 1)) + -> Seq Scan on t2 + Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b)) -> Seq Scan on t3 - Filter: (f_leak(b) AND (a = 2)) -(9 rows) + Filter: ((a = 2) AND f_leak(b)) +(6 rows) UPDATE t2 SET b=t2.b FROM t3 WHERE t2.a = 3 and t3.a = 2 AND f_leak(t2.b) AND f_leak(t3.b); NOTICE: f_leak => cde -NOTICE: f_leak => xxx -NOTICE: f_leak => zzz NOTICE: f_leak => yyyyyy EXPLAIN (COSTS OFF) UPDATE t1 SET b=t1.b FROM t2 WHERE t1.a = 3 and t2.a = 3 AND f_leak(t1.b) AND f_leak(t2.b); - QUERY PLAN ---------------------------------------------------------------- - Update on t1 t1_3 - Update on t1 t1_3 - Update on t2 t1 - Update on t3 t1 + QUERY PLAN +----------------------------------------------------------------- + Update on t1 + Update on t1 + Update on t2 t2_1 + Update on t3 -> Nested Loop - -> Subquery Scan on t1 - Filter: f_leak(t1.b) - -> LockRows - -> Seq Scan on t1 t1_4 - Filter: ((a = 3) AND ((a % 2) = 0)) - -> Subquery Scan on t2 - Filter: f_leak(t2.b) - -> Seq Scan on t2 t2_3 - Filter: ((a = 3) AND ((a % 2) = 1)) + -> Seq Scan on t1 + Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t2 + Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b)) -> Nested Loop - -> Subquery Scan on t1_1 - Filter: f_leak(t1_1.b) - -> LockRows - -> Seq Scan on t2 t2_4 - Filter: ((a = 3) AND ((a % 2) = 0)) - -> Subquery Scan on t2_1 - Filter: f_leak(t2_1.b) - -> Seq Scan on t2 t2_5 - Filter: ((a = 3) AND ((a % 2) = 1)) + -> Seq Scan on t2 t2_1 + Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t2 + Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b)) -> Nested Loop - -> Subquery Scan on t1_2 - Filter: f_leak(t1_2.b) - -> LockRows - -> Seq Scan on t3 - Filter: ((a = 3) AND ((a % 2) = 0)) - -> Subquery Scan on t2_2 - Filter: f_leak(t2_2.b) - -> Seq Scan on t2 t2_6 - Filter: ((a = 3) AND ((a % 2) = 1)) -(34 rows) + -> Seq Scan on t3 + Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t2 + Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b)) +(19 rows) UPDATE t1 SET b=t1.b FROM t2 WHERE t1.a = 3 and t2.a = 3 AND f_leak(t1.b) AND f_leak(t2.b); EXPLAIN (COSTS OFF) UPDATE t2 SET b=t2.b FROM t1 WHERE t1.a = 3 and t2.a = 3 AND f_leak(t1.b) AND f_leak(t2.b); - QUERY PLAN ---------------------------------------------------------------------- - Update on t2 t2_1 + QUERY PLAN +----------------------------------------------------------------------- + Update on t2 -> Nested Loop - -> Subquery Scan on t2 - Filter: f_leak(t2.b) - -> LockRows - -> Seq Scan on t2 t2_2 - Filter: ((a = 3) AND ((a % 2) = 1)) - -> Subquery Scan on t1 - Filter: f_leak(t1.b) - -> Result - -> Append - -> Seq Scan on t1 t1_1 - Filter: ((a = 3) AND ((a % 2) = 0)) - -> Seq Scan on t2 t2_3 - Filter: ((a = 3) AND ((a % 2) = 0)) - -> Seq Scan on t3 - Filter: ((a = 3) AND ((a % 2) = 0)) -(17 rows) + -> Seq Scan on t2 + Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b)) + -> Append + -> Seq Scan on t1 + Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t2 t2_1 + Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t3 + Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b)) +(11 rows) UPDATE t2 SET b=t2.b FROM t1 WHERE t1.a = 3 and t2.a = 3 AND f_leak(t1.b) AND f_leak(t2.b); @@ -1240,21 +1337,16 @@ NOTICE: f_leak => cde EXPLAIN (COSTS OFF) UPDATE t2 t2_1 SET b = t2_2.b FROM t2 t2_2 WHERE t2_1.a = 3 AND t2_2.a = t2_1.a AND t2_2.b = t2_1.b AND f_leak(t2_1.b) AND f_leak(t2_2.b) RETURNING *, t2_1, t2_2; - QUERY PLAN ---------------------------------------------------------------- - Update on t2 t2_1_1 + QUERY PLAN +----------------------------------------------------------------- + Update on t2 t2_1 -> Nested Loop Join Filter: (t2_1.b = t2_2.b) - -> Subquery Scan on t2_1 - Filter: f_leak(t2_1.b) - -> LockRows - -> Seq Scan on t2 t2_1_2 - Filter: ((a = 3) AND ((a % 2) = 1)) - -> Subquery Scan on t2_2 - Filter: f_leak(t2_2.b) - -> Seq Scan on t2 t2_2_1 - Filter: ((a = 3) AND ((a % 2) = 1)) -(12 rows) + -> Seq Scan on t2 t2_1 + Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b)) + -> Seq Scan on t2 t2_2 + Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b)) +(7 rows) UPDATE t2 t2_1 SET b = t2_2.b FROM t2 t2_2 WHERE t2_1.a = 3 AND t2_2.a = t2_1.a AND t2_2.b = t2_1.b @@ -1269,61 +1361,46 @@ NOTICE: f_leak => cde EXPLAIN (COSTS OFF) UPDATE t1 t1_1 SET b = t1_2.b FROM t1 t1_2 WHERE t1_1.a = 4 AND t1_2.a = t1_1.a AND t1_2.b = t1_1.b AND f_leak(t1_1.b) AND f_leak(t1_2.b) RETURNING *, t1_1, t1_2; - QUERY PLAN ---------------------------------------------------------------- - Update on t1 t1_1_3 - Update on t1 t1_1_3 - Update on t2 t1_1 - Update on t3 t1_1 + QUERY PLAN +----------------------------------------------------------------------- + Update on t1 t1_1 + Update on t1 t1_1 + Update on t2 t1_1_1 + Update on t3 t1_1_2 -> Nested Loop Join Filter: (t1_1.b = t1_2.b) - -> Subquery Scan on t1_1 - Filter: f_leak(t1_1.b) - -> LockRows - -> Seq Scan on t1 t1_1_4 - Filter: ((a = 4) AND ((a % 2) = 0)) - -> Subquery Scan on t1_2 - Filter: f_leak(t1_2.b) - -> Append - -> Seq Scan on t1 t1_2_3 - Filter: ((a = 4) AND ((a % 2) = 0)) - -> Seq Scan on t2 t1_2_4 - Filter: ((a = 4) AND ((a % 2) = 0)) - -> Seq Scan on t3 t1_2_5 - Filter: ((a = 4) AND ((a % 2) = 0)) + -> Seq Scan on t1 t1_1 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) + -> Append + -> Seq Scan on t1 t1_2 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t2 t1_2_1 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t3 t1_2_2 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) -> Nested Loop - Join Filter: (t1_1_1.b = t1_2_1.b) - -> Subquery Scan on t1_1_1 - Filter: f_leak(t1_1_1.b) - -> LockRows - -> Seq Scan on t2 t1_1_5 - Filter: ((a = 4) AND ((a % 2) = 0)) - -> Subquery Scan on t1_2_1 - Filter: f_leak(t1_2_1.b) - -> Append - -> Seq Scan on t1 t1_2_6 - Filter: ((a = 4) AND ((a % 2) = 0)) - -> Seq Scan on t2 t1_2_7 - Filter: ((a = 4) AND ((a % 2) = 0)) - -> Seq Scan on t3 t1_2_8 - Filter: ((a = 4) AND ((a % 2) = 0)) + Join Filter: (t1_1_1.b = t1_2.b) + -> Seq Scan on t2 t1_1_1 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) + -> Append + -> Seq Scan on t1 t1_2 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t2 t1_2_1 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t3 t1_2_2 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) -> Nested Loop - Join Filter: (t1_1_2.b = t1_2_2.b) - -> Subquery Scan on t1_1_2 - Filter: f_leak(t1_1_2.b) - -> LockRows - -> Seq Scan on t3 t1_1_6 - Filter: ((a = 4) AND ((a % 2) = 0)) - -> Subquery Scan on t1_2_2 - Filter: f_leak(t1_2_2.b) - -> Append - -> Seq Scan on t1 t1_2_9 - Filter: ((a = 4) AND ((a % 2) = 0)) - -> Seq Scan on t2 t1_2_10 - Filter: ((a = 4) AND ((a % 2) = 0)) - -> Seq Scan on t3 t1_2_11 - Filter: ((a = 4) AND ((a % 2) = 0)) -(52 rows) + Join Filter: (t1_1_2.b = t1_2.b) + -> Seq Scan on t3 t1_1_2 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) + -> Append + -> Seq Scan on t1 t1_2 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t2 t1_2_1 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t3 t1_2_2 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) +(37 rows) UPDATE t1 t1_1 SET b = t1_2.b FROM t1 t1_2 WHERE t1_1.a = 4 AND t1_2.a = t1_1.a AND t1_2.b = t1_1.b @@ -1361,39 +1438,27 @@ SELECT * FROM t1 ORDER BY a,b; SET SESSION AUTHORIZATION regress_rls_bob; SET row_security TO ON; EXPLAIN (COSTS OFF) DELETE FROM only t1 WHERE f_leak(b); - QUERY PLAN -------------------------------------------- - Delete on t1 t1_1 - -> Subquery Scan on t1 - Filter: f_leak(t1.b) - -> LockRows - -> Seq Scan on t1 t1_2 - Filter: ((a % 2) = 0) -(6 rows) + QUERY PLAN +----------------------------------------------- + Delete on t1 + -> Seq Scan on t1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(3 rows) EXPLAIN (COSTS OFF) DELETE FROM t1 WHERE f_leak(b); - QUERY PLAN -------------------------------------------- - Delete on t1 t1_3 - Delete on t1 t1_3 - Delete on t2 t1 - Delete on t3 t1 - -> Subquery Scan on t1 - Filter: f_leak(t1.b) - -> LockRows - -> Seq Scan on t1 t1_4 - Filter: ((a % 2) = 0) - -> Subquery Scan on t1_1 - Filter: f_leak(t1_1.b) - -> LockRows - -> Seq Scan on t2 - Filter: ((a % 2) = 0) - -> Subquery Scan on t1_2 - Filter: f_leak(t1_2.b) - -> LockRows - -> Seq Scan on t3 - Filter: ((a % 2) = 0) -(19 rows) + QUERY PLAN +----------------------------------------------- + Delete on t1 + Delete on t1 + Delete on t2 + Delete on t3 + -> Seq Scan on t1 + Filter: (((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t2 + Filter: (((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t3 + Filter: (((a % 2) = 0) AND f_leak(b)) +(10 rows) DELETE FROM only t1 WHERE f_leak(b) RETURNING oid, *, t1; NOTICE: f_leak => bbbbbb_updt @@ -1458,30 +1523,22 @@ INSERT INTO bv1 VALUES (11, 'xxx'); -- should fail RLS check ERROR: new row violates row-level security policy for table "b1" INSERT INTO bv1 VALUES (12, 'xxx'); -- ok EXPLAIN (COSTS OFF) UPDATE bv1 SET b = 'yyy' WHERE a = 4 AND f_leak(b); - QUERY PLAN ---------------------------------------------------------------------------- - Update on b1 b1_1 - -> Subquery Scan on b1 - Filter: f_leak(b1.b) - -> Subquery Scan on b1_2 - -> LockRows - -> Seq Scan on b1 b1_3 - Filter: ((a > 0) AND (a = 4) AND ((a % 2) = 0)) -(7 rows) + QUERY PLAN +----------------------------------------------------------------------- + Update on b1 + -> Seq Scan on b1 + Filter: ((a > 0) AND (a = 4) AND ((a % 2) = 0) AND f_leak(b)) +(3 rows) UPDATE bv1 SET b = 'yyy' WHERE a = 4 AND f_leak(b); NOTICE: f_leak => a87ff679a2f3e71d9181a67b7542122c EXPLAIN (COSTS OFF) DELETE FROM bv1 WHERE a = 6 AND f_leak(b); - QUERY PLAN ---------------------------------------------------------------------------- - Delete on b1 b1_1 - -> Subquery Scan on b1 - Filter: f_leak(b1.b) - -> Subquery Scan on b1_2 - -> LockRows - -> Seq Scan on b1 b1_3 - Filter: ((a > 0) AND (a = 6) AND ((a % 2) = 0)) -(7 rows) + QUERY PLAN +----------------------------------------------------------------------- + Delete on b1 + -> Seq Scan on b1 + Filter: ((a > 0) AND (a = 6) AND ((a % 2) = 0) AND f_leak(b)) +(3 rows) DELETE FROM bv1 WHERE a = 6 AND f_leak(b); NOTICE: f_leak => 1679091c5a880faf6fb5e6087eb1b2dc @@ -1517,6 +1574,7 @@ SELECT * FROM b1; -- SET SESSION AUTHORIZATION regress_rls_alice; DROP POLICY p1 ON document; +DROP POLICY p1r ON document; CREATE POLICY p1 ON document FOR SELECT USING (true); CREATE POLICY p2 ON document FOR INSERT WITH CHECK (dauthor = current_user); CREATE POLICY p3 ON document FOR UPDATE @@ -1671,53 +1729,45 @@ NOTICE: f_leak => dad (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM z1 WHERE f_leak(b); - QUERY PLAN -------------------------------- - Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 0) -(4 rows) + QUERY PLAN +----------------------------------------- + Seq Scan on z1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(2 rows) PREPARE plancache_test AS SELECT * FROM z1 WHERE f_leak(b); EXPLAIN (COSTS OFF) EXECUTE plancache_test; - QUERY PLAN -------------------------------- - Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 0) -(4 rows) + QUERY PLAN +----------------------------------------- + Seq Scan on z1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(2 rows) PREPARE plancache_test2 AS WITH q AS (SELECT * FROM z1 WHERE f_leak(b)) SELECT * FROM q,z2; EXPLAIN (COSTS OFF) EXECUTE plancache_test2; - QUERY PLAN ---------------------------------------- + QUERY PLAN +------------------------------------------------- Nested Loop CTE q - -> Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 0) + -> Seq Scan on z1 + Filter: (((a % 2) = 0) AND f_leak(b)) -> CTE Scan on q -> Materialize -> Seq Scan on z2 -(9 rows) +(7 rows) PREPARE plancache_test3 AS WITH q AS (SELECT * FROM z2) SELECT * FROM q,z1 WHERE f_leak(z1.b); EXPLAIN (COSTS OFF) EXECUTE plancache_test3; - QUERY PLAN -------------------------------------------- + QUERY PLAN +----------------------------------------------------- Nested Loop CTE q -> Seq Scan on z2 -> CTE Scan on q -> Materialize - -> Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 0) -(9 rows) + -> Seq Scan on z1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(7 rows) SET ROLE regress_rls_group1; SELECT * FROM z1 WHERE f_leak(b); @@ -1730,50 +1780,42 @@ NOTICE: f_leak => dad (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM z1 WHERE f_leak(b); - QUERY PLAN -------------------------------- - Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 0) -(4 rows) + QUERY PLAN +----------------------------------------- + Seq Scan on z1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(2 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test; - QUERY PLAN -------------------------------- - Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 0) -(4 rows) + QUERY PLAN +----------------------------------------- + Seq Scan on z1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(2 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test2; - QUERY PLAN ---------------------------------------- + QUERY PLAN +------------------------------------------------- Nested Loop CTE q - -> Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 0) + -> Seq Scan on z1 + Filter: (((a % 2) = 0) AND f_leak(b)) -> CTE Scan on q -> Materialize -> Seq Scan on z2 -(9 rows) +(7 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test3; - QUERY PLAN -------------------------------------------- + QUERY PLAN +----------------------------------------------------- Nested Loop CTE q -> Seq Scan on z2 -> CTE Scan on q -> Materialize - -> Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 0) -(9 rows) + -> Seq Scan on z1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(7 rows) SET SESSION AUTHORIZATION regress_rls_carol; SELECT * FROM z1 WHERE f_leak(b); @@ -1786,50 +1828,42 @@ NOTICE: f_leak => ccc (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM z1 WHERE f_leak(b); - QUERY PLAN -------------------------------- - Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 1) -(4 rows) + QUERY PLAN +----------------------------------------- + Seq Scan on z1 + Filter: (((a % 2) = 1) AND f_leak(b)) +(2 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test; - QUERY PLAN -------------------------------- - Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 1) -(4 rows) + QUERY PLAN +----------------------------------------- + Seq Scan on z1 + Filter: (((a % 2) = 1) AND f_leak(b)) +(2 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test2; - QUERY PLAN ---------------------------------------- + QUERY PLAN +------------------------------------------------- Nested Loop CTE q - -> Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 1) + -> Seq Scan on z1 + Filter: (((a % 2) = 1) AND f_leak(b)) -> CTE Scan on q -> Materialize -> Seq Scan on z2 -(9 rows) +(7 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test3; - QUERY PLAN -------------------------------------------- + QUERY PLAN +----------------------------------------------------- Nested Loop CTE q -> Seq Scan on z2 -> CTE Scan on q -> Materialize - -> Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 1) -(9 rows) + -> Seq Scan on z1 + Filter: (((a % 2) = 1) AND f_leak(b)) +(7 rows) SET ROLE regress_rls_group2; SELECT * FROM z1 WHERE f_leak(b); @@ -1842,50 +1876,42 @@ NOTICE: f_leak => ccc (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM z1 WHERE f_leak(b); - QUERY PLAN -------------------------------- - Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 1) -(4 rows) + QUERY PLAN +----------------------------------------- + Seq Scan on z1 + Filter: (((a % 2) = 1) AND f_leak(b)) +(2 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test; - QUERY PLAN -------------------------------- - Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 1) -(4 rows) + QUERY PLAN +----------------------------------------- + Seq Scan on z1 + Filter: (((a % 2) = 1) AND f_leak(b)) +(2 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test2; - QUERY PLAN ---------------------------------------- + QUERY PLAN +------------------------------------------------- Nested Loop CTE q - -> Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 1) + -> Seq Scan on z1 + Filter: (((a % 2) = 1) AND f_leak(b)) -> CTE Scan on q -> Materialize -> Seq Scan on z2 -(9 rows) +(7 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test3; - QUERY PLAN -------------------------------------------- + QUERY PLAN +----------------------------------------------------- Nested Loop CTE q -> Seq Scan on z2 -> CTE Scan on q -> Materialize - -> Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 1) -(9 rows) + -> Seq Scan on z1 + Filter: (((a % 2) = 1) AND f_leak(b)) +(7 rows) -- -- Views should follow policy for view owner. @@ -1956,13 +1982,11 @@ NOTICE: f_leak => dad (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM rls_view; - QUERY PLAN -------------------------------- - Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 0) -(4 rows) + QUERY PLAN +----------------------------------------- + Seq Scan on z1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(2 rows) -- Query as role that is not owner of table but is owner of view. -- Should return records based on view owner policies. @@ -1977,13 +2001,11 @@ NOTICE: f_leak => dad (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM rls_view; - QUERY PLAN -------------------------------- - Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 0) -(4 rows) + QUERY PLAN +----------------------------------------- + Seq Scan on z1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(2 rows) -- Query as role that is not the owner of the table or view without permissions. SET SESSION AUTHORIZATION regress_rls_carol; @@ -2004,13 +2026,11 @@ NOTICE: f_leak => dad (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM rls_view; - QUERY PLAN -------------------------------- - Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 0) -(4 rows) + QUERY PLAN +----------------------------------------- + Seq Scan on z1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(2 rows) SET SESSION AUTHORIZATION regress_rls_bob; DROP VIEW rls_view; @@ -2156,13 +2176,11 @@ SET SESSION AUTHORIZATION regress_rls_bob; CREATE VIEW rls_sbv WITH (security_barrier) AS SELECT * FROM y1 WHERE f_leak(b); EXPLAIN (COSTS OFF) SELECT * FROM rls_sbv WHERE (a = 1); - QUERY PLAN ----------------------------------------------------------- - Subquery Scan on y1 - Filter: f_leak(y1.b) - -> Seq Scan on y1 y1_1 - Filter: ((a = 1) AND ((a > 2) OR ((a % 2) = 0))) -(4 rows) + QUERY PLAN +------------------------------------------------------------------ + Seq Scan on y1 + Filter: ((a = 1) AND ((a > 2) OR ((a % 2) = 0)) AND f_leak(b)) +(2 rows) DROP VIEW rls_sbv; -- @@ -2207,13 +2225,11 @@ NOTICE: f_leak => 98f13708210194c475687be6106a3b84 (14 rows) EXPLAIN (COSTS OFF) SELECT * FROM y2 WHERE f_leak(b); - QUERY PLAN -------------------------------------------------------------------- - Subquery Scan on y2 - Filter: f_leak(y2.b) - -> Seq Scan on y2 y2_1 - Filter: (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------- + Seq Scan on y2 + Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b)) +(2 rows) -- -- Qual push-down of leaky functions, when not referring to table @@ -2308,17 +2324,15 @@ NOTICE: f_leak => 98f13708210194c475687be6106a3b84 (0 rows) EXPLAIN (COSTS OFF) SELECT * FROM y2 JOIN test_qual_pushdown ON (b = abc) WHERE f_leak(b); - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------- Hash Join Hash Cond: (test_qual_pushdown.abc = y2.b) -> Seq Scan on test_qual_pushdown -> Hash - -> Subquery Scan on y2 - Filter: f_leak(y2.b) - -> Seq Scan on y2 y2_1 - Filter: (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) -(8 rows) + -> Seq Scan on y2 + Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b)) +(6 rows) DROP TABLE test_qual_pushdown; -- @@ -2404,15 +2418,13 @@ NOTICE: f_leak => 98f13708210194c475687be6106a3b84 (11 rows) EXPLAIN (COSTS OFF) WITH cte1 AS (SELECT * FROM t1 WHERE f_leak(b)) SELECT * FROM cte1; - QUERY PLAN ---------------------------------------- + QUERY PLAN +------------------------------------------------- CTE Scan on cte1 CTE cte1 - -> Subquery Scan on t1 - Filter: f_leak(t1.b) - -> Seq Scan on t1 t1_1 - Filter: ((a % 2) = 0) -(6 rows) + -> Seq Scan on t1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(4 rows) WITH cte1 AS (UPDATE t1 SET a = a + 1 RETURNING *) SELECT * FROM cte1; --fail ERROR: new row violates row-level security policy for table "t1" @@ -2923,17 +2935,13 @@ SELECT * FROM current_check; -- Plan should be a subquery TID scan EXPLAIN (COSTS OFF) UPDATE current_check SET payload = payload WHERE CURRENT OF current_check_cursor; - QUERY PLAN ---------------------------------------------------------------------- - Update on current_check current_check_1 - -> Subquery Scan on current_check - -> Subquery Scan on current_check_2 - Filter: ((current_check_2.currentid % 2) = 0) - -> LockRows - -> Tid Scan on current_check current_check_3 - TID Cond: CURRENT OF current_check_cursor - Filter: (currentid = 4) -(8 rows) + QUERY PLAN +------------------------------------------------------------- + Update on current_check + -> Tid Scan on current_check + TID Cond: CURRENT OF current_check_cursor + Filter: ((currentid = 4) AND ((currentid % 2) = 0)) +(4 rows) -- Similarly can only delete row 4 FETCH ABSOLUTE 1 FROM current_check_cursor; @@ -3461,6 +3469,7 @@ RESET client_min_messages; DROP USER regress_rls_alice; DROP USER regress_rls_bob; DROP USER regress_rls_carol; +DROP USER regress_rls_dave; DROP USER regress_rls_exempt_user; DROP ROLE regress_rls_group1; DROP ROLE regress_rls_group2; diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index c5ff3181a3..60abcad101 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1379,6 +1379,10 @@ pg_matviews| SELECT n.nspname AS schemaname, pg_policies| SELECT n.nspname AS schemaname, c.relname AS tablename, pol.polname AS policyname, + CASE + WHEN pol.polpermissive THEN 'PERMISSIVE'::text + ELSE 'RESTRICTIVE'::text + END AS permissive, CASE WHEN (pol.polroles = '{0}'::oid[]) THEN (string_to_array('public'::text, ''::text))::name[] ELSE ARRAY( SELECT pg_authid.rolname @@ -1413,6 +1417,14 @@ pg_prepared_xacts| SELECT p.transaction, FROM ((pg_prepared_xact() p(transaction, gid, prepared, ownerid, dbid) LEFT JOIN pg_authid u ON ((p.ownerid = u.oid))) LEFT JOIN pg_database d ON ((p.dbid = d.oid))); +pg_publication_tables| SELECT p.pubname, + n.nspname AS schemaname, + c.relname AS tablename + FROM pg_publication p, + (pg_class c + JOIN pg_namespace n ON ((n.oid = c.relnamespace))) + WHERE (c.oid IN ( SELECT pg_get_publication_tables.relid + FROM pg_get_publication_tables((p.pubname)::text) pg_get_publication_tables(relid))); pg_replication_origin_status| SELECT pg_show_replication_origin_status.local_id, pg_show_replication_origin_status.external_id, pg_show_replication_origin_status.remote_lsn, @@ -1423,13 +1435,14 @@ pg_replication_slots| SELECT l.slot_name, l.slot_type, l.datoid, d.datname AS database, + l.temporary, l.active, l.active_pid, l.xmin, l.catalog_xmin, l.restart_lsn, l.confirmed_flush_lsn - FROM (pg_get_replication_slots() l(slot_name, plugin, slot_type, datoid, active, active_pid, xmin, catalog_xmin, restart_lsn, confirmed_flush_lsn) + FROM (pg_get_replication_slots() l(slot_name, plugin, slot_type, datoid, temporary, active, active_pid, xmin, catalog_xmin, restart_lsn, confirmed_flush_lsn) LEFT JOIN pg_database d ON ((l.datoid = d.oid))); pg_roles| SELECT pg_authid.rolname, pg_authid.rolsuper, @@ -1458,7 +1471,7 @@ pg_seclabels| SELECT l.objoid, l.classoid, l.objsubid, CASE - WHEN (rel.relkind = 'r'::"char") THEN 'table'::text + WHEN (rel.relkind = ANY (ARRAY['r'::"char", 'P'::"char"])) THEN 'table'::text WHEN (rel.relkind = 'v'::"char") THEN 'view'::text WHEN (rel.relkind = 'm'::"char") THEN 'materialized view'::text WHEN (rel.relkind = 'S'::"char") THEN 'sequence'::text @@ -1615,6 +1628,20 @@ UNION ALL l.label FROM (pg_shseclabel l JOIN pg_authid rol ON (((l.classoid = rol.tableoid) AND (l.objoid = rol.oid)))); +pg_sequences| SELECT n.nspname AS schemaname, + c.relname AS sequencename, + pg_get_userbyid(c.relowner) AS sequenceowner, + s.seqstart AS start_value, + s.seqmin AS min_value, + s.seqmax AS max_value, + s.seqincrement AS increment_by, + s.seqcycle AS cycle, + s.seqcache AS cache_size, + pg_sequence_last_value((c.oid)::regclass) AS last_value + FROM ((pg_sequence s + JOIN pg_class c ON ((c.oid = s.seqrelid))) + LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) + WHERE ((NOT pg_is_other_temp_schema(n.oid)) AND (c.relkind = 'S'::"char")); pg_settings| SELECT a.name, a.setting, a.unit, @@ -1664,10 +1691,9 @@ pg_stat_activity| SELECT s.datid, s.backend_xid, s.backend_xmin, s.query - FROM pg_database d, - pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn), - pg_authid u - WHERE ((s.datid = d.oid) AND (s.usesysid = u.oid)); + FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn) + LEFT JOIN pg_database d ON ((s.datid = d.oid))) + LEFT JOIN pg_authid u ON ((s.usesysid = u.oid))); pg_stat_all_indexes| SELECT c.oid AS relid, i.oid AS indexrelid, n.nspname AS schemaname, @@ -1776,7 +1802,7 @@ pg_stat_progress_vacuum| SELECT s.pid, s.param6 AS max_dead_tuples, s.param7 AS num_dead_tuples FROM (pg_stat_get_progress_info('VACUUM'::text) s(pid, datid, relid, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10) - JOIN pg_database d ON ((s.datid = d.oid))); + LEFT JOIN pg_database d ON ((s.datid = d.oid))); pg_stat_replication| SELECT s.pid, s.usesysid, u.rolname AS usename, @@ -1793,10 +1819,9 @@ pg_stat_replication| SELECT s.pid, w.replay_location, w.sync_priority, w.sync_state - FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn), - pg_authid u, - pg_stat_get_wal_senders() w(pid, state, sent_location, write_location, flush_location, replay_location, sync_priority, sync_state) - WHERE ((s.usesysid = u.oid) AND (s.pid = w.pid)); + FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn) + JOIN pg_stat_get_wal_senders() w(pid, state, sent_location, write_location, flush_location, replay_location, sync_priority, sync_state) ON ((s.pid = w.pid))) + LEFT JOIN pg_authid u ON ((s.usesysid = u.oid))); pg_stat_ssl| SELECT s.pid, s.ssl, s.sslversion AS version, @@ -1805,6 +1830,16 @@ pg_stat_ssl| SELECT s.pid, s.sslcompression AS compression, s.sslclientdn AS clientdn FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn); +pg_stat_subscription| SELECT su.oid AS subid, + su.subname, + st.pid, + st.received_lsn, + st.last_msg_send_time, + st.last_msg_receipt_time, + st.latest_end_lsn, + st.latest_end_time + FROM (pg_subscription su + LEFT JOIN pg_stat_get_subscription(NULL::oid) st(subid, pid, received_lsn, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time) ON ((st.subid = su.oid))); pg_stat_sys_indexes| SELECT pg_stat_all_indexes.relid, pg_stat_all_indexes.indexrelid, pg_stat_all_indexes.schemaname, @@ -2122,7 +2157,7 @@ pg_tables| SELECT n.nspname AS schemaname, FROM ((pg_class c LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) LEFT JOIN pg_tablespace t ON ((t.oid = c.reltablespace))) - WHERE (c.relkind = 'r'::"char"); + WHERE (c.relkind = ANY (ARRAY['r'::"char", 'P'::"char"])); pg_timezone_abbrevs| SELECT pg_timezone_abbrevs.abbrev, pg_timezone_abbrevs.utc_offset, pg_timezone_abbrevs.is_dst @@ -2155,8 +2190,8 @@ pg_user_mappings| SELECT u.oid AS umid, ELSE NULL::text[] END AS umoptions FROM ((pg_user_mapping u - LEFT JOIN pg_authid a ON ((a.oid = u.umuser))) - JOIN pg_foreign_server s ON ((u.umserver = s.oid))); + JOIN pg_foreign_server s ON ((u.umserver = s.oid))) + LEFT JOIN pg_authid a ON ((a.oid = u.umuser))); pg_views| SELECT n.nspname AS schemaname, c.relname AS viewname, pg_get_userbyid(c.relowner) AS viewowner, @@ -2269,14 +2304,14 @@ pg_settings|pg_settings_u|CREATE RULE pg_settings_u AS WHERE (new.name = old.name) DO SELECT set_config(old.name, new.setting, false) AS set_config; rtest_emp|rtest_emp_del|CREATE RULE rtest_emp_del AS ON DELETE TO rtest_emp DO INSERT INTO rtest_emplog (ename, who, action, newsal, oldsal) - VALUES (old.ename, "current_user"(), 'fired'::bpchar, '$0.00'::money, old.salary); + VALUES (old.ename, CURRENT_USER, 'fired'::bpchar, '$0.00'::money, old.salary); rtest_emp|rtest_emp_ins|CREATE RULE rtest_emp_ins AS ON INSERT TO rtest_emp DO INSERT INTO rtest_emplog (ename, who, action, newsal, oldsal) - VALUES (new.ename, "current_user"(), 'hired'::bpchar, new.salary, '$0.00'::money); + VALUES (new.ename, CURRENT_USER, 'hired'::bpchar, new.salary, '$0.00'::money); rtest_emp|rtest_emp_upd|CREATE RULE rtest_emp_upd AS ON UPDATE TO rtest_emp WHERE (new.salary <> old.salary) DO INSERT INTO rtest_emplog (ename, who, action, newsal, oldsal) - VALUES (new.ename, "current_user"(), 'honored'::bpchar, new.salary, old.salary); + VALUES (new.ename, CURRENT_USER, 'honored'::bpchar, new.salary, old.salary); rtest_nothn1|rtest_nothn_r1|CREATE RULE rtest_nothn_r1 AS ON INSERT TO rtest_nothn1 WHERE ((new.a >= 10) AND (new.a < 20)) DO INSTEAD NOTHING; @@ -2709,11 +2744,11 @@ select * from rules_log; create rule r3 as on delete to rules_src do notify rules_src_deletion; \d+ rules_src - Table "public.rules_src" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+---------+--------------+------------- - f1 | integer | | plain | | - f2 | integer | | plain | | + Table "public.rules_src" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+---------+--------------+------------- + f1 | integer | | | | plain | | + f2 | integer | | | | plain | | Rules: r1 AS ON UPDATE TO rules_src DO INSERT INTO rules_log (f1, f2, tag) VALUES (old.f1,old.f2,'old'::text), (new.f1,new.f2,'new'::text) @@ -2729,11 +2764,11 @@ Rules: create rule r4 as on insert to rules_src do instead insert into rules_log AS trgt SELECT NEW.* RETURNING trgt.f1, trgt.f2; create rule r5 as on update to rules_src do instead UPDATE rules_log AS trgt SET tag = 'updated' WHERE trgt.f1 = new.f1; \d+ rules_src - Table "public.rules_src" - Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+---------+--------------+------------- - f1 | integer | | plain | | - f2 | integer | | plain | | + Table "public.rules_src" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+---------+--------------+------------- + f1 | integer | | | | plain | | + f2 | integer | | | | plain | | Rules: r1 AS ON UPDATE TO rules_src DO INSERT INTO rules_log (f1, f2, tag) VALUES (old.f1,old.f2,'old'::text), (new.f1,new.f2,'new'::text) @@ -2769,10 +2804,10 @@ SELECT * FROM rule_v1; (1 row) \d+ rule_v1 - View "public.rule_v1" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+---------+------------- - a | integer | | plain | + View "public.rule_v1" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+---------+------------- + a | integer | | | | plain | View definition: SELECT rule_t1.a FROM rule_t1; @@ -2797,22 +2832,22 @@ DROP TABLE rule_t1; -- create view rule_v1 as values(1,2); \d+ rule_v1 - View "public.rule_v1" - Column | Type | Modifiers | Storage | Description ----------+---------+-----------+---------+------------- - column1 | integer | | plain | - column2 | integer | | plain | + View "public.rule_v1" + Column | Type | Collation | Nullable | Default | Storage | Description +---------+---------+-----------+----------+---------+---------+------------- + column1 | integer | | | | plain | + column2 | integer | | | | plain | View definition: VALUES (1,2); drop view rule_v1; create view rule_v1(x) as values(1,2); \d+ rule_v1 - View "public.rule_v1" - Column | Type | Modifiers | Storage | Description ----------+---------+-----------+---------+------------- - x | integer | | plain | - column2 | integer | | plain | + View "public.rule_v1" + Column | Type | Collation | Nullable | Default | Storage | Description +---------+---------+-----------+----------+---------+---------+------------- + x | integer | | | | plain | + column2 | integer | | | | plain | View definition: SELECT "*VALUES*".column1 AS x, "*VALUES*".column2 @@ -2821,11 +2856,11 @@ View definition: drop view rule_v1; create view rule_v1(x) as select * from (values(1,2)) v; \d+ rule_v1 - View "public.rule_v1" - Column | Type | Modifiers | Storage | Description ----------+---------+-----------+---------+------------- - x | integer | | plain | - column2 | integer | | plain | + View "public.rule_v1" + Column | Type | Collation | Nullable | Default | Storage | Description +---------+---------+-----------+----------+---------+---------+------------- + x | integer | | | | plain | + column2 | integer | | | | plain | View definition: SELECT v.column1 AS x, v.column2 @@ -2834,11 +2869,11 @@ View definition: drop view rule_v1; create view rule_v1(x) as select * from (values(1,2)) v(q,w); \d+ rule_v1 - View "public.rule_v1" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+---------+------------- - x | integer | | plain | - w | integer | | plain | + View "public.rule_v1" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+---------+------------- + x | integer | | | | plain | + w | integer | | | | plain | View definition: SELECT v.q AS x, v.w diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out index 1c087a3903..0af013f8a2 100644 --- a/src/test/regress/expected/sanity_check.out +++ b/src/test/regress/expected/sanity_check.out @@ -62,6 +62,8 @@ int2_tbl|f int4_tbl|f int8_tbl|f interval_tbl|f +invalid_check_con|f +invalid_check_con_child|f iportaltest|f kd_point_tbl|t line_tbl|f @@ -118,17 +120,22 @@ pg_namespace|t pg_opclass|t pg_operator|t pg_opfamily|t +pg_partitioned_table|t pg_pltemplate|t pg_policy|t pg_proc|t +pg_publication|t +pg_publication_rel|t pg_range|t pg_replication_origin|t pg_rewrite|t pg_seclabel|t +pg_sequence|t pg_shdepend|t pg_shdescription|t pg_shseclabel|t pg_statistic|t +pg_subscription|t pg_tablespace|t pg_transform|t pg_trigger|t diff --git a/src/test/regress/expected/select_parallel.out b/src/test/regress/expected/select_parallel.out index 2286fafab3..18e21b7f13 100644 --- a/src/test/regress/expected/select_parallel.out +++ b/src/test/regress/expected/select_parallel.out @@ -111,14 +111,8 @@ explain (costs off) Index Cond: (unique1 = 1) (5 rows) -do $$begin - -- Provoke error, possibly in worker. If this error happens to occur in - -- the worker, there will be a CONTEXT line which must be hidden. - perform stringu1::int2 from tenk1 where unique1 = 1; - exception - when others then - raise 'SQLERRM: %', sqlerrm; -end$$; -ERROR: SQLERRM: invalid input syntax for integer: "BAAAAA" -CONTEXT: PL/pgSQL function inline_code_block line 7 at RAISE +-- provoke error in worker +select stringu1::int2 from tenk1 where unique1 = 1; +ERROR: invalid input syntax for integer: "BAAAAA" +CONTEXT: parallel worker rollback; diff --git a/src/test/regress/expected/select_views.out b/src/test/regress/expected/select_views.out index 7f575266c1..878035332b 100644 --- a/src/test/regress/expected/select_views.out +++ b/src/test/regress/expected/select_views.out @@ -1326,10 +1326,10 @@ NOTICE: f_leak => hamburger (1 row) EXPLAIN (COSTS OFF) SELECT * FROM my_property_normal WHERE f_leak(passwd); - QUERY PLAN ------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------- Seq Scan on customer - Filter: (f_leak(passwd) AND (name = ("current_user"())::text)) + Filter: (f_leak(passwd) AND (name = (CURRENT_USER)::text)) (2 rows) SELECT * FROM my_property_secure WHERE f_leak(passwd); @@ -1340,12 +1340,12 @@ NOTICE: f_leak => passwd123 (1 row) EXPLAIN (COSTS OFF) SELECT * FROM my_property_secure WHERE f_leak(passwd); - QUERY PLAN ---------------------------------------------------- + QUERY PLAN +----------------------------------------------- Subquery Scan on my_property_secure Filter: f_leak(my_property_secure.passwd) -> Seq Scan on customer - Filter: (name = ("current_user"())::text) + Filter: (name = (CURRENT_USER)::text) (4 rows) -- @@ -1367,10 +1367,10 @@ NOTICE: f_leak => hamburger EXPLAIN (COSTS OFF) SELECT * FROM my_property_normal v WHERE f_leak('passwd') AND f_leak(passwd); - QUERY PLAN ---------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------- Seq Scan on customer - Filter: (f_leak('passwd'::text) AND f_leak(passwd) AND (name = ("current_user"())::text)) + Filter: (f_leak('passwd'::text) AND f_leak(passwd) AND (name = (CURRENT_USER)::text)) (2 rows) SELECT * FROM my_property_secure v @@ -1386,12 +1386,12 @@ NOTICE: f_leak => passwd EXPLAIN (COSTS OFF) SELECT * FROM my_property_secure v WHERE f_leak('passwd') AND f_leak(passwd); - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------- Subquery Scan on v Filter: f_leak(v.passwd) -> Seq Scan on customer - Filter: (f_leak('passwd'::text) AND (name = ("current_user"())::text)) + Filter: (f_leak('passwd'::text) AND (name = (CURRENT_USER)::text)) (4 rows) -- @@ -1409,15 +1409,15 @@ NOTICE: f_leak => 9801-2345-6789-0123 (1 row) EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_normal WHERE f_leak(cnum); - QUERY PLAN ---------------------------------------------------------- + QUERY PLAN +----------------------------------------------------- Hash Join Hash Cond: (r.cid = l.cid) -> Seq Scan on credit_card r Filter: f_leak(cnum) -> Hash -> Seq Scan on customer l - Filter: (name = ("current_user"())::text) + Filter: (name = (CURRENT_USER)::text) (7 rows) SELECT * FROM my_credit_card_secure WHERE f_leak(cnum); @@ -1428,8 +1428,8 @@ NOTICE: f_leak => 1111-2222-3333-4444 (1 row) EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_secure WHERE f_leak(cnum); - QUERY PLAN ---------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------- Subquery Scan on my_credit_card_secure Filter: f_leak(my_credit_card_secure.cnum) -> Hash Join @@ -1437,7 +1437,7 @@ EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_secure WHERE f_leak(cnum); -> Seq Scan on credit_card r -> Hash -> Seq Scan on customer l - Filter: (name = ("current_user"())::text) + Filter: (name = (CURRENT_USER)::text) (8 rows) -- @@ -1471,7 +1471,7 @@ EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_usage_normal -> Seq Scan on credit_card r_1 -> Hash -> Seq Scan on customer l_1 - Filter: (name = ("current_user"())::text) + Filter: (name = (CURRENT_USER)::text) (13 rows) SELECT * FROM my_credit_card_usage_secure @@ -1502,7 +1502,7 @@ EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_usage_secure -> Seq Scan on credit_card r_1 -> Hash -> Seq Scan on customer l - Filter: (name = ("current_user"())::text) + Filter: (name = (CURRENT_USER)::text) (13 rows) -- diff --git a/src/test/regress/expected/select_views_1.out b/src/test/regress/expected/select_views_1.out index 5275ef0b2d..1a05c6ccbd 100644 --- a/src/test/regress/expected/select_views_1.out +++ b/src/test/regress/expected/select_views_1.out @@ -1326,10 +1326,10 @@ NOTICE: f_leak => hamburger (1 row) EXPLAIN (COSTS OFF) SELECT * FROM my_property_normal WHERE f_leak(passwd); - QUERY PLAN ------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------- Seq Scan on customer - Filter: (f_leak(passwd) AND (name = ("current_user"())::text)) + Filter: (f_leak(passwd) AND (name = (CURRENT_USER)::text)) (2 rows) SELECT * FROM my_property_secure WHERE f_leak(passwd); @@ -1340,12 +1340,12 @@ NOTICE: f_leak => passwd123 (1 row) EXPLAIN (COSTS OFF) SELECT * FROM my_property_secure WHERE f_leak(passwd); - QUERY PLAN ---------------------------------------------------- + QUERY PLAN +----------------------------------------------- Subquery Scan on my_property_secure Filter: f_leak(my_property_secure.passwd) -> Seq Scan on customer - Filter: (name = ("current_user"())::text) + Filter: (name = (CURRENT_USER)::text) (4 rows) -- @@ -1367,10 +1367,10 @@ NOTICE: f_leak => hamburger EXPLAIN (COSTS OFF) SELECT * FROM my_property_normal v WHERE f_leak('passwd') AND f_leak(passwd); - QUERY PLAN ---------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------- Seq Scan on customer - Filter: (f_leak('passwd'::text) AND f_leak(passwd) AND (name = ("current_user"())::text)) + Filter: (f_leak('passwd'::text) AND f_leak(passwd) AND (name = (CURRENT_USER)::text)) (2 rows) SELECT * FROM my_property_secure v @@ -1386,12 +1386,12 @@ NOTICE: f_leak => passwd EXPLAIN (COSTS OFF) SELECT * FROM my_property_secure v WHERE f_leak('passwd') AND f_leak(passwd); - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------- Subquery Scan on v Filter: f_leak(v.passwd) -> Seq Scan on customer - Filter: (f_leak('passwd'::text) AND (name = ("current_user"())::text)) + Filter: (f_leak('passwd'::text) AND (name = (CURRENT_USER)::text)) (4 rows) -- @@ -1409,15 +1409,15 @@ NOTICE: f_leak => 9801-2345-6789-0123 (1 row) EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_normal WHERE f_leak(cnum); - QUERY PLAN ---------------------------------------------------------- + QUERY PLAN +----------------------------------------------------- Hash Join Hash Cond: (r.cid = l.cid) -> Seq Scan on credit_card r Filter: f_leak(cnum) -> Hash -> Seq Scan on customer l - Filter: (name = ("current_user"())::text) + Filter: (name = (CURRENT_USER)::text) (7 rows) SELECT * FROM my_credit_card_secure WHERE f_leak(cnum); @@ -1428,8 +1428,8 @@ NOTICE: f_leak => 1111-2222-3333-4444 (1 row) EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_secure WHERE f_leak(cnum); - QUERY PLAN ---------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------- Subquery Scan on my_credit_card_secure Filter: f_leak(my_credit_card_secure.cnum) -> Hash Join @@ -1437,7 +1437,7 @@ EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_secure WHERE f_leak(cnum); -> Seq Scan on credit_card r -> Hash -> Seq Scan on customer l - Filter: (name = ("current_user"())::text) + Filter: (name = (CURRENT_USER)::text) (8 rows) -- @@ -1471,7 +1471,7 @@ EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_usage_normal -> Seq Scan on credit_card r_1 -> Hash -> Seq Scan on customer l_1 - Filter: (name = ("current_user"())::text) + Filter: (name = (CURRENT_USER)::text) (13 rows) SELECT * FROM my_credit_card_usage_secure @@ -1502,7 +1502,7 @@ EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_usage_secure -> Seq Scan on credit_card r_1 -> Hash -> Seq Scan on customer l - Filter: (name = ("current_user"())::text) + Filter: (name = (CURRENT_USER)::text) (13 rows) -- diff --git a/src/test/regress/expected/sequence.out b/src/test/regress/expected/sequence.out index 4ffbe92ab3..a2bdd3002b 100644 --- a/src/test/regress/expected/sequence.out +++ b/src/test/regress/expected/sequence.out @@ -173,9 +173,9 @@ DROP SEQUENCE sequence_test; CREATE SEQUENCE foo_seq; ALTER TABLE foo_seq RENAME TO foo_seq_new; SELECT * FROM foo_seq_new; - sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called ----------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+----------- - foo_seq | 1 | 1 | 1 | 9223372036854775807 | 1 | 1 | 0 | f | f + last_value | log_cnt | is_called +------------+---------+----------- + 1 | 0 | f (1 row) SELECT nextval('foo_seq_new'); @@ -191,9 +191,9 @@ SELECT nextval('foo_seq_new'); (1 row) SELECT * FROM foo_seq_new; - sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called ----------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+----------- - foo_seq | 2 | 1 | 1 | 9223372036854775807 | 1 | 1 | 31 | f | t + last_value | log_cnt | is_called +------------+---------+----------- + 2 | 31 | t (1 row) DROP SEQUENCE foo_seq_new; @@ -300,20 +300,39 @@ SELECT nextval('sequence_test2'); 5 (1 row) +CREATE SEQUENCE sequence_test3; -- not read from, to test is_called -- Information schema SELECT * FROM information_schema.sequences WHERE sequence_name IN - ('sequence_test2', 'serialtest2_f2_seq', 'serialtest2_f3_seq', + ('sequence_test2', 'sequence_test3', 'serialtest2_f2_seq', 'serialtest2_f3_seq', 'serialtest2_f4_seq', 'serialtest2_f5_seq', 'serialtest2_f6_seq') ORDER BY sequence_name ASC; sequence_catalog | sequence_schema | sequence_name | data_type | numeric_precision | numeric_precision_radix | numeric_scale | start_value | minimum_value | maximum_value | increment | cycle_option ------------------+-----------------+--------------------+-----------+-------------------+-------------------------+---------------+-------------+---------------+---------------------+-----------+-------------- regression | public | sequence_test2 | bigint | 64 | 2 | 0 | 32 | 5 | 36 | 4 | YES + regression | public | sequence_test3 | bigint | 64 | 2 | 0 | 1 | 1 | 9223372036854775807 | 1 | NO regression | public | serialtest2_f2_seq | bigint | 64 | 2 | 0 | 1 | 1 | 9223372036854775807 | 1 | NO regression | public | serialtest2_f3_seq | bigint | 64 | 2 | 0 | 1 | 1 | 9223372036854775807 | 1 | NO regression | public | serialtest2_f4_seq | bigint | 64 | 2 | 0 | 1 | 1 | 9223372036854775807 | 1 | NO regression | public | serialtest2_f5_seq | bigint | 64 | 2 | 0 | 1 | 1 | 9223372036854775807 | 1 | NO regression | public | serialtest2_f6_seq | bigint | 64 | 2 | 0 | 1 | 1 | 9223372036854775807 | 1 | NO -(6 rows) +(7 rows) + +SELECT schemaname, sequencename, start_value, min_value, max_value, increment_by, cycle, cache_size, last_value +FROM pg_sequences +WHERE sequencename IN + ('sequence_test2', 'sequence_test3', 'serialtest2_f2_seq', 'serialtest2_f3_seq', + 'serialtest2_f4_seq', 'serialtest2_f5_seq', 'serialtest2_f6_seq') + ORDER BY sequencename ASC; + schemaname | sequencename | start_value | min_value | max_value | increment_by | cycle | cache_size | last_value +------------+--------------------+-------------+-----------+---------------------+--------------+-------+------------+------------ + public | sequence_test2 | 32 | 5 | 36 | 4 | t | 1 | 5 + public | sequence_test3 | 1 | 1 | 9223372036854775807 | 1 | f | 1 | + public | serialtest2_f2_seq | 1 | 1 | 9223372036854775807 | 1 | f | 1 | 2 + public | serialtest2_f3_seq | 1 | 1 | 9223372036854775807 | 1 | f | 1 | 2 + public | serialtest2_f4_seq | 1 | 1 | 9223372036854775807 | 1 | f | 1 | 2 + public | serialtest2_f5_seq | 1 | 1 | 9223372036854775807 | 1 | f | 1 | 2 + public | serialtest2_f6_seq | 1 | 1 | 9223372036854775807 | 1 | f | 1 | 2 +(7 rows) -- Test comments COMMENT ON SEQUENCE asdf IS 'won''t work'; @@ -517,3 +536,24 @@ SELECT * FROM information_schema.sequences WHERE sequence_name IN DROP USER regress_seq_user; DROP SEQUENCE seq; +-- cache tests +CREATE SEQUENCE test_seq1 CACHE 10; +SELECT nextval('test_seq1'); + nextval +--------- + 1 +(1 row) + +SELECT nextval('test_seq1'); + nextval +--------- + 2 +(1 row) + +SELECT nextval('test_seq1'); + nextval +--------- + 3 +(1 row) + +DROP SEQUENCE test_seq1; diff --git a/src/test/regress/expected/sequence_1.out b/src/test/regress/expected/sequence_1.out index 05da2bf1ad..5d7ab72944 100644 --- a/src/test/regress/expected/sequence_1.out +++ b/src/test/regress/expected/sequence_1.out @@ -173,9 +173,9 @@ DROP SEQUENCE sequence_test; CREATE SEQUENCE foo_seq; ALTER TABLE foo_seq RENAME TO foo_seq_new; SELECT * FROM foo_seq_new; - sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called ----------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+----------- - foo_seq | 1 | 1 | 1 | 9223372036854775807 | 1 | 1 | 0 | f | f + last_value | log_cnt | is_called +------------+---------+----------- + 1 | 0 | f (1 row) SELECT nextval('foo_seq_new'); @@ -191,9 +191,9 @@ SELECT nextval('foo_seq_new'); (1 row) SELECT * FROM foo_seq_new; - sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called ----------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+----------- - foo_seq | 2 | 1 | 1 | 9223372036854775807 | 1 | 1 | 32 | f | t + last_value | log_cnt | is_called +------------+---------+----------- + 2 | 32 | t (1 row) DROP SEQUENCE foo_seq_new; @@ -300,20 +300,39 @@ SELECT nextval('sequence_test2'); 5 (1 row) +CREATE SEQUENCE sequence_test3; -- not read from, to test is_called -- Information schema SELECT * FROM information_schema.sequences WHERE sequence_name IN - ('sequence_test2', 'serialtest2_f2_seq', 'serialtest2_f3_seq', + ('sequence_test2', 'sequence_test3', 'serialtest2_f2_seq', 'serialtest2_f3_seq', 'serialtest2_f4_seq', 'serialtest2_f5_seq', 'serialtest2_f6_seq') ORDER BY sequence_name ASC; sequence_catalog | sequence_schema | sequence_name | data_type | numeric_precision | numeric_precision_radix | numeric_scale | start_value | minimum_value | maximum_value | increment | cycle_option ------------------+-----------------+--------------------+-----------+-------------------+-------------------------+---------------+-------------+---------------+---------------------+-----------+-------------- regression | public | sequence_test2 | bigint | 64 | 2 | 0 | 32 | 5 | 36 | 4 | YES + regression | public | sequence_test3 | bigint | 64 | 2 | 0 | 1 | 1 | 9223372036854775807 | 1 | NO regression | public | serialtest2_f2_seq | bigint | 64 | 2 | 0 | 1 | 1 | 9223372036854775807 | 1 | NO regression | public | serialtest2_f3_seq | bigint | 64 | 2 | 0 | 1 | 1 | 9223372036854775807 | 1 | NO regression | public | serialtest2_f4_seq | bigint | 64 | 2 | 0 | 1 | 1 | 9223372036854775807 | 1 | NO regression | public | serialtest2_f5_seq | bigint | 64 | 2 | 0 | 1 | 1 | 9223372036854775807 | 1 | NO regression | public | serialtest2_f6_seq | bigint | 64 | 2 | 0 | 1 | 1 | 9223372036854775807 | 1 | NO -(6 rows) +(7 rows) + +SELECT schemaname, sequencename, start_value, min_value, max_value, increment_by, cycle, cache_size, last_value +FROM pg_sequences +WHERE sequencename IN + ('sequence_test2', 'sequence_test3', 'serialtest2_f2_seq', 'serialtest2_f3_seq', + 'serialtest2_f4_seq', 'serialtest2_f5_seq', 'serialtest2_f6_seq') + ORDER BY sequencename ASC; + schemaname | sequencename | start_value | min_value | max_value | increment_by | cycle | cache_size | last_value +------------+--------------------+-------------+-----------+---------------------+--------------+-------+------------+------------ + public | sequence_test2 | 32 | 5 | 36 | 4 | t | 1 | 5 + public | sequence_test3 | 1 | 1 | 9223372036854775807 | 1 | f | 1 | + public | serialtest2_f2_seq | 1 | 1 | 9223372036854775807 | 1 | f | 1 | 2 + public | serialtest2_f3_seq | 1 | 1 | 9223372036854775807 | 1 | f | 1 | 2 + public | serialtest2_f4_seq | 1 | 1 | 9223372036854775807 | 1 | f | 1 | 2 + public | serialtest2_f5_seq | 1 | 1 | 9223372036854775807 | 1 | f | 1 | 2 + public | serialtest2_f6_seq | 1 | 1 | 9223372036854775807 | 1 | f | 1 | 2 +(7 rows) -- Test comments COMMENT ON SEQUENCE asdf IS 'won''t work'; @@ -517,3 +536,24 @@ SELECT * FROM information_schema.sequences WHERE sequence_name IN DROP USER regress_seq_user; DROP SEQUENCE seq; +-- cache tests +CREATE SEQUENCE test_seq1 CACHE 10; +SELECT nextval('test_seq1'); + nextval +--------- + 1 +(1 row) + +SELECT nextval('test_seq1'); + nextval +--------- + 2 +(1 row) + +SELECT nextval('test_seq1'); + nextval +--------- + 3 +(1 row) + +DROP SEQUENCE test_seq1; diff --git a/src/test/regress/expected/strings.out b/src/test/regress/expected/strings.out index 19708c32fd..35cadb24aa 100644 --- a/src/test/regress/expected/strings.out +++ b/src/test/regress/expected/strings.out @@ -681,9 +681,9 @@ SELECT regexp_split_to_array('thE QUick bROWn FOx jUMPs ovEr The lazy dOG', 'e', ERROR: invalid regexp option: "z" -- global option meaningless for regexp_split SELECT foo, length(foo) FROM regexp_split_to_table('thE QUick bROWn FOx jUMPs ovEr The lazy dOG', 'e', 'g') AS foo; -ERROR: regexp_split does not support the global option +ERROR: regexp_split_to_table does not support the global option SELECT regexp_split_to_array('thE QUick bROWn FOx jUMPs ovEr The lazy dOG', 'e', 'g'); -ERROR: regexp_split does not support the global option +ERROR: regexp_split_to_array does not support the global option -- change NULL-display back \pset null '' -- E021-11 position expression diff --git a/src/test/regress/expected/subscription.out b/src/test/regress/expected/subscription.out new file mode 100644 index 0000000000..2ccec98b15 --- /dev/null +++ b/src/test/regress/expected/subscription.out @@ -0,0 +1,66 @@ +-- +-- SUBSCRIPTION +-- +CREATE ROLE regress_subscription_user LOGIN SUPERUSER; +SET SESSION AUTHORIZATION 'regress_subscription_user'; +-- fail - no publications +CREATE SUBSCRIPTION testsub CONNECTION 'foo'; +ERROR: syntax error at or near ";" +LINE 1: CREATE SUBSCRIPTION testsub CONNECTION 'foo'; + ^ +-- fail - no connection +CREATE SUBSCRIPTION testsub PUBLICATION foo; +ERROR: syntax error at or near "PUBLICATION" +LINE 1: CREATE SUBSCRIPTION testsub PUBLICATION foo; + ^ +set client_min_messages to error; +CREATE SUBSCRIPTION testsub CONNECTION 'testconn' PUBLICATION testpub; +ERROR: invalid connection string syntax: missing "=" after "testconn" in connection info string + +CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION testpub WITH (DISABLED, NOCREATE SLOT); +reset client_min_messages; +\dRs+ + List of subscriptions + Name | Owner | Enabled | Publication | Conninfo +---------+---------------------------+---------+-------------+--------------------- + testsub | regress_subscription_user | f | {testpub} | dbname=doesnotexist +(1 row) + +ALTER SUBSCRIPTION testsub SET PUBLICATION testpub2, testpub3; +\dRs + List of subscriptions + Name | Owner | Enabled | Publication +---------+---------------------------+---------+--------------------- + testsub | regress_subscription_user | f | {testpub2,testpub3} +(1 row) + +ALTER SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist2'; +ALTER SUBSCRIPTION testsub SET PUBLICATION testpub, testpub1; +\dRs+ + List of subscriptions + Name | Owner | Enabled | Publication | Conninfo +---------+---------------------------+---------+--------------------+---------------------- + testsub | regress_subscription_user | f | {testpub,testpub1} | dbname=doesnotexist2 +(1 row) + +BEGIN; +ALTER SUBSCRIPTION testsub ENABLE; +\dRs + List of subscriptions + Name | Owner | Enabled | Publication +---------+---------------------------+---------+-------------------- + testsub | regress_subscription_user | t | {testpub,testpub1} +(1 row) + +ALTER SUBSCRIPTION testsub DISABLE; +\dRs + List of subscriptions + Name | Owner | Enabled | Publication +---------+---------------------------+---------+-------------------- + testsub | regress_subscription_user | f | {testpub,testpub1} +(1 row) + +COMMIT; +DROP SUBSCRIPTION testsub NODROP SLOT; +RESET SESSION AUTHORIZATION; +DROP ROLE regress_subscription_user; diff --git a/src/test/regress/expected/subselect.out b/src/test/regress/expected/subselect.out index 0fc93d9d72..abd3217e86 100644 --- a/src/test/regress/expected/subselect.out +++ b/src/test/regress/expected/subselect.out @@ -807,24 +807,28 @@ select * from int4_tbl where explain (verbose, costs off) select * from int4_tbl o where (f1, f1) in (select f1, generate_series(1,2) / 10 g from int4_tbl i group by f1); - QUERY PLAN ----------------------------------------------------------------- - Hash Semi Join + QUERY PLAN +------------------------------------------------------------------- + Nested Loop Semi Join Output: o.f1 - Hash Cond: (o.f1 = "ANY_subquery".f1) + Join Filter: (o.f1 = "ANY_subquery".f1) -> Seq Scan on public.int4_tbl o Output: o.f1 - -> Hash + -> Materialize Output: "ANY_subquery".f1, "ANY_subquery".g -> Subquery Scan on "ANY_subquery" Output: "ANY_subquery".f1, "ANY_subquery".g Filter: ("ANY_subquery".f1 = "ANY_subquery".g) - -> HashAggregate - Output: i.f1, (generate_series(1, 2) / 10) - Group Key: i.f1 - -> Seq Scan on public.int4_tbl i - Output: i.f1 -(15 rows) + -> Result + Output: i.f1, ((generate_series(1, 2)) / 10) + -> ProjectSet + Output: i.f1, generate_series(1, 2) + -> HashAggregate + Output: i.f1 + Group Key: i.f1 + -> Seq Scan on public.int4_tbl i + Output: i.f1 +(19 rows) select * from int4_tbl o where (f1, f1) in (select f1, generate_series(1,2) / 10 g from int4_tbl i group by f1); @@ -880,3 +884,106 @@ select nextval('ts1'); 11 (1 row) +-- +-- Check that volatile quals aren't pushed down past a set-returning function; +-- while a nonvolatile qual can be, if it doesn't reference the SRF. +-- +create function tattle(x int, y int) returns bool +volatile language plpgsql as $$ +begin + raise notice 'x = %, y = %', x, y; + return x > y; +end$$; +explain (verbose, costs off) +select * from + (select 9 as x, unnest(array[1,2,3,11,12,13]) as u) ss + where tattle(x, 8); + QUERY PLAN +---------------------------------------------------------- + Subquery Scan on ss + Output: x, u + Filter: tattle(ss.x, 8) + -> ProjectSet + Output: 9, unnest('{1,2,3,11,12,13}'::integer[]) + -> Result +(6 rows) + +select * from + (select 9 as x, unnest(array[1,2,3,11,12,13]) as u) ss + where tattle(x, 8); +NOTICE: x = 9, y = 8 +NOTICE: x = 9, y = 8 +NOTICE: x = 9, y = 8 +NOTICE: x = 9, y = 8 +NOTICE: x = 9, y = 8 +NOTICE: x = 9, y = 8 + x | u +---+---- + 9 | 1 + 9 | 2 + 9 | 3 + 9 | 11 + 9 | 12 + 9 | 13 +(6 rows) + +-- if we pretend it's stable, we get different results: +alter function tattle(x int, y int) stable; +explain (verbose, costs off) +select * from + (select 9 as x, unnest(array[1,2,3,11,12,13]) as u) ss + where tattle(x, 8); + QUERY PLAN +---------------------------------------------------- + ProjectSet + Output: 9, unnest('{1,2,3,11,12,13}'::integer[]) + -> Result + One-Time Filter: tattle(9, 8) +(4 rows) + +select * from + (select 9 as x, unnest(array[1,2,3,11,12,13]) as u) ss + where tattle(x, 8); +NOTICE: x = 9, y = 8 + x | u +---+---- + 9 | 1 + 9 | 2 + 9 | 3 + 9 | 11 + 9 | 12 + 9 | 13 +(6 rows) + +-- although even a stable qual should not be pushed down if it references SRF +explain (verbose, costs off) +select * from + (select 9 as x, unnest(array[1,2,3,11,12,13]) as u) ss + where tattle(x, u); + QUERY PLAN +---------------------------------------------------------- + Subquery Scan on ss + Output: x, u + Filter: tattle(ss.x, ss.u) + -> ProjectSet + Output: 9, unnest('{1,2,3,11,12,13}'::integer[]) + -> Result +(6 rows) + +select * from + (select 9 as x, unnest(array[1,2,3,11,12,13]) as u) ss + where tattle(x, u); +NOTICE: x = 9, y = 1 +NOTICE: x = 9, y = 2 +NOTICE: x = 9, y = 3 +NOTICE: x = 9, y = 11 +NOTICE: x = 9, y = 12 +NOTICE: x = 9, y = 13 + x | u +---+--- + 9 | 1 + 9 | 2 + 9 | 3 +(3 rows) + +drop function tattle(x int, y int); diff --git a/src/test/regress/expected/tablesample.out b/src/test/regress/expected/tablesample.out index 727a835439..7e91b958ae 100644 --- a/src/test/regress/expected/tablesample.out +++ b/src/test/regress/expected/tablesample.out @@ -69,19 +69,19 @@ CREATE VIEW test_tablesample_v1 AS CREATE VIEW test_tablesample_v2 AS SELECT id FROM test_tablesample TABLESAMPLE SYSTEM (99); \d+ test_tablesample_v1 - View "public.test_tablesample_v1" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+---------+------------- - id | integer | | plain | + View "public.test_tablesample_v1" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+---------+------------- + id | integer | | | | plain | View definition: SELECT test_tablesample.id FROM test_tablesample TABLESAMPLE system ((10 * 2)) REPEATABLE (2); \d+ test_tablesample_v2 - View "public.test_tablesample_v2" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+---------+------------- - id | integer | | plain | + View "public.test_tablesample_v2" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+---------+------------- + id | integer | | | | plain | View definition: SELECT test_tablesample.id FROM test_tablesample TABLESAMPLE system (99); diff --git a/src/test/regress/expected/timestamptz.out b/src/test/regress/expected/timestamptz.out index 67f26db204..51d4d21157 100644 --- a/src/test/regress/expected/timestamptz.out +++ b/src/test/regress/expected/timestamptz.out @@ -2603,3 +2603,57 @@ SELECT '2007-12-09 07:30:00 UTC'::timestamptz AT TIME ZONE 'VET'; Sun Dec 09 03:00:00 2007 (1 row) +-- +-- Test that the pg_timezone_names and pg_timezone_abbrevs views are +-- more-or-less working. We can't test their contents in any great detail +-- without the outputs changing anytime IANA updates the underlying data, +-- but it seems reasonable to expect at least one entry per major meridian. +-- (At the time of writing, the actual counts are around 38 because of +-- zones using fractional GMT offsets, so this is a pretty loose test.) +-- +select count(distinct utc_offset) >= 24 as ok from pg_timezone_names; + ok +---- + t +(1 row) + +select count(distinct utc_offset) >= 24 as ok from pg_timezone_abbrevs; + ok +---- + t +(1 row) + +-- Let's check the non-default timezone abbreviation sets, too +set timezone_abbreviations = 'Australia'; +select count(distinct utc_offset) >= 24 as ok from pg_timezone_abbrevs; + ok +---- + t +(1 row) + +set timezone_abbreviations = 'India'; +select count(distinct utc_offset) >= 24 as ok from pg_timezone_abbrevs; + ok +---- + t +(1 row) + +-- +-- Test that AT TIME ZONE isn't misoptimized when using an index (bug #14504) +-- +create temp table tmptz (f1 timestamptz primary key); +insert into tmptz values ('2017-01-18 00:00+00'); +explain (costs off) +select * from tmptz where f1 at time zone 'utc' = '2017-01-18 00:00'; + QUERY PLAN +------------------------------------------------------------------------------------------------- + Seq Scan on tmptz + Filter: (timezone('utc'::text, f1) = 'Wed Jan 18 00:00:00 2017'::timestamp without time zone) +(2 rows) + +select * from tmptz where f1 at time zone 'utc' = '2017-01-18 00:00'; + f1 +------------------------------ + Tue Jan 17 16:00:00 2017 PST +(1 row) + diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out index a7bf5dc159..f408475f33 100644 --- a/src/test/regress/expected/triggers.out +++ b/src/test/regress/expected/triggers.out @@ -1059,11 +1059,11 @@ DELETE 1 \set QUIET true -- Describe view should list triggers \d main_view - View "public.main_view" - Column | Type | Modifiers ---------+---------+----------- - a | integer | - b | integer | + View "public.main_view" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + b | integer | | | Triggers: after_del_stmt_trig AFTER DELETE ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('after_view_del_stmt') after_ins_stmt_trig AFTER INSERT ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('after_view_ins_stmt') @@ -1079,11 +1079,11 @@ Triggers: DROP TRIGGER instead_of_insert_trig ON main_view; DROP TRIGGER instead_of_delete_trig ON main_view; \d+ main_view - View "public.main_view" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+---------+------------- - a | integer | | plain | - b | integer | | plain | + View "public.main_view" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+---------+------------- + a | integer | | | | plain | + b | integer | | | | plain | View definition: SELECT main_table.a, main_table.b diff --git a/src/test/regress/expected/tsdicts.out b/src/test/regress/expected/tsdicts.out index c55591a678..8ed64d3c68 100644 --- a/src/test/regress/expected/tsdicts.out +++ b/src/test/regress/expected/tsdicts.out @@ -470,15 +470,15 @@ SELECT to_tsquery('hunspell_tst', 'footballyklubber:b & rebookings:A & sky'); (1 row) SELECT to_tsquery('hunspell_tst', 'footballyklubber:b <-> sky'); - to_tsquery ------------------------------------------------------------------ - 'foot':B <-> 'sky' & 'ball':B <-> 'sky' & 'klubber':B <-> 'sky' + to_tsquery +------------------------------------------------- + ( 'foot':B & 'ball':B & 'klubber':B ) <-> 'sky' (1 row) SELECT phraseto_tsquery('hunspell_tst', 'footballyklubber sky'); - phraseto_tsquery ------------------------------------------------------------ - 'foot' <-> 'sky' & 'ball' <-> 'sky' & 'klubber' <-> 'sky' + phraseto_tsquery +------------------------------------------- + ( 'foot' & 'ball' & 'klubber' ) <-> 'sky' (1 row) -- Test ispell dictionary with hunspell affix with FLAG long in configuration diff --git a/src/test/regress/expected/tsearch.out b/src/test/regress/expected/tsearch.out index 129d06ef07..0681d43358 100644 --- a/src/test/regress/expected/tsearch.out +++ b/src/test/regress/expected/tsearch.out @@ -556,15 +556,15 @@ SELECT plainto_tsquery('english', 'foo bar') && 'asd | fg'; -- Check stop word deletion, a and s are stop-words SELECT to_tsquery('english', '!(a & !b) & c'); - to_tsquery ------------- - 'b' & 'c' + to_tsquery +------------- + !!'b' & 'c' (1 row) SELECT to_tsquery('english', '!(a & !b)'); to_tsquery ------------ - 'b' + !!'b' (1 row) SELECT to_tsquery('english', '(1 <-> 2) <-> a'); @@ -594,7 +594,7 @@ SELECT to_tsquery('english', 'a <-> (1 <-> 2)'); SELECT to_tsquery('english', '1 <-> (a <-> 2)'); to_tsquery ------------- - '1' <-> '2' + '1' <2> '2' (1 row) SELECT to_tsquery('english', '1 <-> (2 <-> a)'); @@ -630,7 +630,7 @@ SELECT to_tsquery('english', 'a <3> (1 <-> 2)'); SELECT to_tsquery('english', '1 <3> (a <-> 2)'); to_tsquery ------------- - '1' <3> '2' + '1' <4> '2' (1 row) SELECT to_tsquery('english', '1 <3> (2 <-> a)'); @@ -666,7 +666,7 @@ SELECT to_tsquery('english', 'a <-> (1 <3> 2)'); SELECT to_tsquery('english', '1 <-> (a <3> 2)'); to_tsquery ------------- - '1' <-> '2' + '1' <4> '2' (1 row) SELECT to_tsquery('english', '1 <-> (2 <3> a)'); @@ -684,7 +684,7 @@ SELECT to_tsquery('english', '((a <-> 1) <-> 2) <-> s'); SELECT to_tsquery('english', '(2 <-> (a <-> 1)) <-> s'); to_tsquery ------------- - '2' <-> '1' + '2' <2> '1' (1 row) SELECT to_tsquery('english', '((1 <-> a) <-> 2) <-> s'); @@ -708,7 +708,7 @@ SELECT to_tsquery('english', 's <-> ((a <-> 1) <-> 2)'); SELECT to_tsquery('english', 's <-> (2 <-> (a <-> 1))'); to_tsquery ------------- - '2' <-> '1' + '2' <2> '1' (1 row) SELECT to_tsquery('english', 's <-> ((1 <-> a) <-> 2)'); @@ -750,13 +750,13 @@ SELECT to_tsquery('english', '(s <-> (1 <-> a)) <-> 2'); SELECT to_tsquery('english', '2 <-> ((a <-> 1) <-> s)'); to_tsquery ------------- - '2' <-> '1' + '2' <2> '1' (1 row) SELECT to_tsquery('english', '2 <-> (s <-> (a <-> 1))'); to_tsquery ------------- - '2' <-> '1' + '2' <3> '1' (1 row) SELECT to_tsquery('english', '2 <-> ((1 <-> a) <-> s)'); @@ -768,13 +768,13 @@ SELECT to_tsquery('english', '2 <-> ((1 <-> a) <-> s)'); SELECT to_tsquery('english', '2 <-> (s <-> (1 <-> a))'); to_tsquery ------------- - '2' <-> '1' + '2' <2> '1' (1 row) SELECT to_tsquery('english', 'foo <-> (a <-> (the <-> bar))'); to_tsquery ----------------- - 'foo' <-> 'bar' + 'foo' <3> 'bar' (1 row) SELECT to_tsquery('english', '((foo <-> a) <-> the) <-> bar'); @@ -1184,6 +1184,13 @@ SELECT ts_rewrite('foo & bar & qq & new & york', 'new & york'::tsquery, 'big & 'foo' & 'bar' & 'qq' & ( 'city' & 'new' & 'york' | 'nyc' | 'big' & 'apple' ) (1 row) +SELECT ts_rewrite(ts_rewrite('new & !york ', 'york', '!jersey'), + 'jersey', 'mexico'); + ts_rewrite +-------------------- + 'new' & !!'mexico' +(1 row) + SELECT ts_rewrite('moscow', 'SELECT keyword, sample FROM test_tsquery'::text ); ts_rewrite --------------------- @@ -1233,15 +1240,30 @@ SELECT ts_rewrite('1 & (2 <2> 3)', 'SELECT keyword, sample FROM test_tsquery'::t (1 row) SELECT ts_rewrite('5 <-> (1 & (2 <-> 3))', 'SELECT keyword, sample FROM test_tsquery'::text ); - ts_rewrite ---------------------------------------- - '5' <-> '1' & '5' <-> ( '2' <-> '3' ) + ts_rewrite +------------------------- + '5' <-> ( '2' <-> '4' ) (1 row) SELECT ts_rewrite('5 <-> (6 | 8)', 'SELECT keyword, sample FROM test_tsquery'::text ); - ts_rewrite ---------------------------- - '5' <-> '7' | '5' <-> '8' + ts_rewrite +----------------------- + '5' <-> ( '6' | '8' ) +(1 row) + +-- Check empty substitution +SELECT ts_rewrite(to_tsquery('5 & (6 | 5)'), to_tsquery('5'), to_tsquery('')); +NOTICE: text-search query doesn't contain lexemes: "" + ts_rewrite +------------ + '6' +(1 row) + +SELECT ts_rewrite(to_tsquery('!5'), to_tsquery('5'), to_tsquery('')); +NOTICE: text-search query doesn't contain lexemes: "" + ts_rewrite +------------ + (1 row) SELECT keyword FROM test_tsquery WHERE keyword @> 'new'; @@ -1364,6 +1386,26 @@ SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_t 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) (1 row) +SELECT ts_rewrite(tsquery_phrase('foo', 'foo'), 'foo', 'bar | baz'); + ts_rewrite +----------------------------------------- + ( 'bar' | 'baz' ) <-> ( 'bar' | 'baz' ) +(1 row) + +SELECT to_tsvector('foo bar') @@ + ts_rewrite(tsquery_phrase('foo', 'foo'), 'foo', 'bar | baz'); + ?column? +---------- + f +(1 row) + +SELECT to_tsvector('bar baz') @@ + ts_rewrite(tsquery_phrase('foo', 'foo'), 'foo', 'bar | baz'); + ?column? +---------- + t +(1 row) + RESET enable_seqscan; --test GUC SET default_text_search_config=simple; diff --git a/src/test/regress/expected/tsrf.out b/src/test/regress/expected/tsrf.out new file mode 100644 index 0000000000..dca51a842f --- /dev/null +++ b/src/test/regress/expected/tsrf.out @@ -0,0 +1,523 @@ +-- +-- tsrf - targetlist set returning function tests +-- +-- simple srf +SELECT generate_series(1, 3); + generate_series +----------------- + 1 + 2 + 3 +(3 rows) + +-- parallel iteration +SELECT generate_series(1, 3), generate_series(3,5); + generate_series | generate_series +-----------------+----------------- + 1 | 3 + 2 | 4 + 3 | 5 +(3 rows) + +-- parallel iteration, different number of rows +SELECT generate_series(1, 2), generate_series(1,4); + generate_series | generate_series +-----------------+----------------- + 1 | 1 + 2 | 2 + | 3 + | 4 +(4 rows) + +-- srf, with SRF argument +SELECT generate_series(1, generate_series(1, 3)); + generate_series +----------------- + 1 + 1 + 2 + 1 + 2 + 3 +(6 rows) + +-- srf, with two SRF arguments +SELECT generate_series(generate_series(1,3), generate_series(2, 4)); + generate_series +----------------- + 1 + 2 + 2 + 3 + 3 + 4 +(6 rows) + +CREATE TABLE few(id int, dataa text, datab text); +INSERT INTO few VALUES(1, 'a', 'foo'),(2, 'a', 'bar'),(3, 'b', 'bar'); +-- SRF output order of sorting is maintained, if SRF is not referenced +SELECT few.id, generate_series(1,3) g FROM few ORDER BY id DESC; + id | g +----+--- + 3 | 1 + 3 | 2 + 3 | 3 + 2 | 1 + 2 | 2 + 2 | 3 + 1 | 1 + 1 | 2 + 1 | 3 +(9 rows) + +-- but SRFs can be referenced in sort +SELECT few.id, generate_series(1,3) g FROM few ORDER BY id, g DESC; + id | g +----+--- + 1 | 3 + 1 | 2 + 1 | 1 + 2 | 3 + 2 | 2 + 2 | 1 + 3 | 3 + 3 | 2 + 3 | 1 +(9 rows) + +SELECT few.id, generate_series(1,3) g FROM few ORDER BY id, generate_series(1,3) DESC; + id | g +----+--- + 1 | 3 + 1 | 2 + 1 | 1 + 2 | 3 + 2 | 2 + 2 | 1 + 3 | 3 + 3 | 2 + 3 | 1 +(9 rows) + +-- it's weird to have ORDER BYs that increase the number of results +SELECT few.id FROM few ORDER BY id, generate_series(1,3) DESC; + id +---- + 1 + 1 + 1 + 2 + 2 + 2 + 3 + 3 + 3 +(9 rows) + +-- SRFs are computed after aggregation +SET enable_hashagg TO 0; -- stable output order +SELECT few.dataa, count(*), min(id), max(id), unnest('{1,1,3}'::int[]) FROM few WHERE few.id = 1 GROUP BY few.dataa; + dataa | count | min | max | unnest +-------+-------+-----+-----+-------- + a | 1 | 1 | 1 | 1 + a | 1 | 1 | 1 | 1 + a | 1 | 1 | 1 | 3 +(3 rows) + +-- unless referenced in GROUP BY clause +SELECT few.dataa, count(*), min(id), max(id), unnest('{1,1,3}'::int[]) FROM few WHERE few.id = 1 GROUP BY few.dataa, unnest('{1,1,3}'::int[]); + dataa | count | min | max | unnest +-------+-------+-----+-----+-------- + a | 2 | 1 | 1 | 1 + a | 1 | 1 | 1 | 3 +(2 rows) + +SELECT few.dataa, count(*), min(id), max(id), unnest('{1,1,3}'::int[]) FROM few WHERE few.id = 1 GROUP BY few.dataa, 5; + dataa | count | min | max | unnest +-------+-------+-----+-----+-------- + a | 2 | 1 | 1 | 1 + a | 1 | 1 | 1 | 3 +(2 rows) + +RESET enable_hashagg; +-- check HAVING works when GROUP BY does [not] reference SRF output +SELECT dataa, generate_series(1,1), count(*) FROM few GROUP BY 1 HAVING count(*) > 1; + dataa | generate_series | count +-------+-----------------+------- + a | 1 | 2 +(1 row) + +SELECT dataa, generate_series(1,1), count(*) FROM few GROUP BY 1, 2 HAVING count(*) > 1; + dataa | generate_series | count +-------+-----------------+------- + a | 1 | 2 +(1 row) + +-- it's weird to have GROUP BYs that increase the number of results +SELECT few.dataa, count(*) FROM few WHERE dataa = 'a' GROUP BY few.dataa ORDER BY 2; + dataa | count +-------+------- + a | 2 +(1 row) + +SELECT few.dataa, count(*) FROM few WHERE dataa = 'a' GROUP BY few.dataa, unnest('{1,1,3}'::int[]) ORDER BY 2; + dataa | count +-------+------- + a | 2 + a | 4 +(2 rows) + +-- SRFs are not allowed in aggregate arguments +SELECT min(generate_series(1, 3)) FROM few; +ERROR: set-valued function called in context that cannot accept a set +-- SRFs are not allowed in window function arguments, either +SELECT min(generate_series(1, 3)) OVER() FROM few; +ERROR: set-valued function called in context that cannot accept a set +-- SRFs are normally computed after window functions +SELECT id,lag(id) OVER(), count(*) OVER(), generate_series(1,3) FROM few; + id | lag | count | generate_series +----+-----+-------+----------------- + 1 | | 3 | 1 + 1 | | 3 | 2 + 1 | | 3 | 3 + 2 | 1 | 3 | 1 + 2 | 1 | 3 | 2 + 2 | 1 | 3 | 3 + 3 | 2 | 3 | 1 + 3 | 2 | 3 | 2 + 3 | 2 | 3 | 3 +(9 rows) + +-- unless referencing SRFs +SELECT SUM(count(*)) OVER(PARTITION BY generate_series(1,3) ORDER BY generate_series(1,3)), generate_series(1,3) g FROM few GROUP BY g; + sum | g +-----+--- + 3 | 1 + 3 | 2 + 3 | 3 +(3 rows) + +-- sorting + grouping +SELECT few.dataa, count(*), min(id), max(id), generate_series(1,3) FROM few GROUP BY few.dataa ORDER BY 5, 1; + dataa | count | min | max | generate_series +-------+-------+-----+-----+----------------- + a | 2 | 1 | 2 | 1 + b | 1 | 3 | 3 | 1 + a | 2 | 1 | 2 | 2 + b | 1 | 3 | 3 | 2 + a | 2 | 1 | 2 | 3 + b | 1 | 3 | 3 | 3 +(6 rows) + +-- grouping sets are a bit special, they produce NULLs in columns not actually NULL +SELECT dataa, datab b, generate_series(1,2) g, count(*) FROM few GROUP BY CUBE(dataa, datab); + dataa | b | g | count +-------+-----+---+------- + a | bar | 1 | 1 + a | bar | 2 | 1 + a | foo | 1 | 1 + a | foo | 2 | 1 + a | | 1 | 2 + a | | 2 | 2 + b | bar | 1 | 1 + b | bar | 2 | 1 + b | | 1 | 1 + b | | 2 | 1 + | | 1 | 3 + | | 2 | 3 + | bar | 1 | 2 + | bar | 2 | 2 + | foo | 1 | 1 + | foo | 2 | 1 +(16 rows) + +SELECT dataa, datab b, generate_series(1,2) g, count(*) FROM few GROUP BY CUBE(dataa, datab) ORDER BY dataa; + dataa | b | g | count +-------+-----+---+------- + a | bar | 1 | 1 + a | bar | 2 | 1 + a | foo | 1 | 1 + a | foo | 2 | 1 + a | | 1 | 2 + a | | 2 | 2 + b | bar | 1 | 1 + b | bar | 2 | 1 + b | | 1 | 1 + b | | 2 | 1 + | | 1 | 3 + | | 2 | 3 + | bar | 1 | 2 + | bar | 2 | 2 + | foo | 1 | 1 + | foo | 2 | 1 +(16 rows) + +SELECT dataa, datab b, generate_series(1,2) g, count(*) FROM few GROUP BY CUBE(dataa, datab) ORDER BY g; + dataa | b | g | count +-------+-----+---+------- + a | bar | 1 | 1 + a | foo | 1 | 1 + a | | 1 | 2 + b | bar | 1 | 1 + b | | 1 | 1 + | | 1 | 3 + | bar | 1 | 2 + | foo | 1 | 1 + | foo | 2 | 1 + a | bar | 2 | 1 + b | | 2 | 1 + a | foo | 2 | 1 + | bar | 2 | 2 + a | | 2 | 2 + | | 2 | 3 + b | bar | 2 | 1 +(16 rows) + +SELECT dataa, datab b, generate_series(1,2) g, count(*) FROM few GROUP BY CUBE(dataa, datab, g); + dataa | b | g | count +-------+-----+---+------- + a | bar | 1 | 1 + a | bar | 2 | 1 + a | bar | | 2 + a | foo | 1 | 1 + a | foo | 2 | 1 + a | foo | | 2 + a | | | 4 + b | bar | 1 | 1 + b | bar | 2 | 1 + b | bar | | 2 + b | | | 2 + | | | 6 + a | | 1 | 2 + b | | 1 | 1 + | | 1 | 3 + a | | 2 | 2 + b | | 2 | 1 + | | 2 | 3 + | bar | 1 | 2 + | bar | 2 | 2 + | bar | | 4 + | foo | 1 | 1 + | foo | 2 | 1 + | foo | | 2 +(24 rows) + +SELECT dataa, datab b, generate_series(1,2) g, count(*) FROM few GROUP BY CUBE(dataa, datab, g) ORDER BY dataa; + dataa | b | g | count +-------+-----+---+------- + a | bar | 1 | 1 + a | bar | 2 | 1 + a | bar | | 2 + a | foo | 1 | 1 + a | foo | 2 | 1 + a | foo | | 2 + a | | | 4 + a | | 1 | 2 + a | | 2 | 2 + b | bar | 2 | 1 + b | | | 2 + b | | 1 | 1 + b | | 2 | 1 + b | bar | 1 | 1 + b | bar | | 2 + | foo | | 2 + | foo | 1 | 1 + | | 2 | 3 + | bar | 1 | 2 + | bar | 2 | 2 + | | | 6 + | foo | 2 | 1 + | bar | | 4 + | | 1 | 3 +(24 rows) + +SELECT dataa, datab b, generate_series(1,2) g, count(*) FROM few GROUP BY CUBE(dataa, datab, g) ORDER BY g; + dataa | b | g | count +-------+-----+---+------- + a | bar | 1 | 1 + a | foo | 1 | 1 + b | bar | 1 | 1 + a | | 1 | 2 + b | | 1 | 1 + | | 1 | 3 + | bar | 1 | 2 + | foo | 1 | 1 + | foo | 2 | 1 + | bar | 2 | 2 + a | | 2 | 2 + b | | 2 | 1 + a | bar | 2 | 1 + | | 2 | 3 + a | foo | 2 | 1 + b | bar | 2 | 1 + a | foo | | 2 + b | bar | | 2 + b | | | 2 + | | | 6 + a | | | 4 + | bar | | 4 + | foo | | 2 + a | bar | | 2 +(24 rows) + +-- data modification +CREATE TABLE fewmore AS SELECT generate_series(1,3) AS data; +INSERT INTO fewmore VALUES(generate_series(4,5)); +SELECT * FROM fewmore; + data +------ + 1 + 2 + 3 + 4 + 5 +(5 rows) + +-- SRFs are not allowed in UPDATE (they once were, but it was nonsense) +UPDATE fewmore SET data = generate_series(4,9); +ERROR: set-returning functions are not allowed in UPDATE +LINE 1: UPDATE fewmore SET data = generate_series(4,9); + ^ +-- SRFs are not allowed in RETURNING +INSERT INTO fewmore VALUES(1) RETURNING generate_series(1,3); +ERROR: set-returning functions are not allowed in RETURNING +LINE 1: INSERT INTO fewmore VALUES(1) RETURNING generate_series(1,3)... + ^ +-- nor standalone VALUES (but surely this is a bug?) +VALUES(1, generate_series(1,2)); +ERROR: set-returning functions are not allowed in VALUES +LINE 1: VALUES(1, generate_series(1,2)); + ^ +-- We allow tSRFs that are not at top level +SELECT int4mul(generate_series(1,2), 10); + int4mul +--------- + 10 + 20 +(2 rows) + +-- but SRFs in function RTEs must be at top level (annoying restriction) +SELECT * FROM int4mul(generate_series(1,2), 10); +ERROR: set-valued function called in context that cannot accept a set +-- DISTINCT ON is evaluated before tSRF evaluation if SRF is not +-- referenced either in ORDER BY or in the DISTINCT ON list. The ORDER +-- BY reference can be implicitly generated, if there's no other ORDER BY. +-- implicit reference (via implicit ORDER) to all columns +SELECT DISTINCT ON (a) a, b, generate_series(1,3) g +FROM (VALUES (3, 2), (3,1), (1,1), (1,4), (5,3), (5,1)) AS t(a, b); + a | b | g +---+---+--- + 1 | 1 | 1 + 3 | 2 | 1 + 5 | 3 | 1 +(3 rows) + +-- unreferenced in DISTINCT ON or ORDER BY +SELECT DISTINCT ON (a) a, b, generate_series(1,3) g +FROM (VALUES (3, 2), (3,1), (1,1), (1,4), (5,3), (5,1)) AS t(a, b) +ORDER BY a, b DESC; + a | b | g +---+---+--- + 1 | 4 | 1 + 1 | 4 | 2 + 1 | 4 | 3 + 3 | 2 | 1 + 3 | 2 | 2 + 3 | 2 | 3 + 5 | 3 | 1 + 5 | 3 | 2 + 5 | 3 | 3 +(9 rows) + +-- referenced in ORDER BY +SELECT DISTINCT ON (a) a, b, generate_series(1,3) g +FROM (VALUES (3, 2), (3,1), (1,1), (1,4), (5,3), (5,1)) AS t(a, b) +ORDER BY a, b DESC, g DESC; + a | b | g +---+---+--- + 1 | 4 | 3 + 3 | 2 | 3 + 5 | 3 | 3 +(3 rows) + +-- referenced in ORDER BY and DISTINCT ON +SELECT DISTINCT ON (a, b, g) a, b, generate_series(1,3) g +FROM (VALUES (3, 2), (3,1), (1,1), (1,4), (5,3), (5,1)) AS t(a, b) +ORDER BY a, b DESC, g DESC; + a | b | g +---+---+--- + 1 | 4 | 3 + 1 | 4 | 2 + 1 | 4 | 1 + 1 | 1 | 3 + 1 | 1 | 2 + 1 | 1 | 1 + 3 | 2 | 3 + 3 | 2 | 2 + 3 | 2 | 1 + 3 | 1 | 3 + 3 | 1 | 2 + 3 | 1 | 1 + 5 | 3 | 3 + 5 | 3 | 2 + 5 | 3 | 1 + 5 | 1 | 3 + 5 | 1 | 2 + 5 | 1 | 1 +(18 rows) + +-- only SRF mentioned in DISTINCT ON +SELECT DISTINCT ON (g) a, b, generate_series(1,3) g +FROM (VALUES (3, 2), (3,1), (1,1), (1,4), (5,3), (5,1)) AS t(a, b); + a | b | g +---+---+--- + 3 | 2 | 1 + 5 | 1 | 2 + 3 | 1 | 3 +(3 rows) + +-- LIMIT / OFFSET is evaluated after SRF evaluation +SELECT a, generate_series(1,2) FROM (VALUES(1),(2),(3)) r(a) LIMIT 2 OFFSET 2; + a | generate_series +---+----------------- + 2 | 1 + 2 | 2 +(2 rows) + +-- SRFs are not allowed in LIMIT. +SELECT 1 LIMIT generate_series(1,3); +ERROR: set-returning functions are not allowed in LIMIT +LINE 1: SELECT 1 LIMIT generate_series(1,3); + ^ +-- tSRF in correlated subquery, referencing table outside +SELECT (SELECT generate_series(1,3) LIMIT 1 OFFSET few.id) FROM few; + generate_series +----------------- + 2 + 3 + +(3 rows) + +-- tSRF in correlated subquery, referencing SRF outside +SELECT (SELECT generate_series(1,3) LIMIT 1 OFFSET g.i) FROM generate_series(0,3) g(i); + generate_series +----------------- + 1 + 2 + 3 + +(4 rows) + +-- Operators can return sets too +CREATE OPERATOR |@| (PROCEDURE = unnest, RIGHTARG = ANYARRAY); +SELECT |@|ARRAY[1,2,3]; + ?column? +---------- + 1 + 2 + 3 +(3 rows) + +-- Clean up +DROP TABLE few; +DROP TABLE fewmore; diff --git a/src/test/regress/expected/tstypes.out b/src/test/regress/expected/tstypes.out index 8d9290cbac..dcce82fdc4 100644 --- a/src/test/regress/expected/tstypes.out +++ b/src/test/regress/expected/tstypes.out @@ -366,133 +366,6 @@ SELECT '!!a & !!b'::tsquery; !!'a' & !!'b' (1 row) --- phrase transformation -SELECT 'a <-> (b|c)'::tsquery; - tsquery ---------------------------- - 'a' <-> 'b' | 'a' <-> 'c' -(1 row) - -SELECT '(a|b) <-> c'::tsquery; - tsquery ---------------------------- - 'a' <-> 'c' | 'b' <-> 'c' -(1 row) - -SELECT '(a|b) <-> (d|c)'::tsquery; - tsquery -------------------------------------------------------- - 'a' <-> 'd' | 'b' <-> 'd' | 'a' <-> 'c' | 'b' <-> 'c' -(1 row) - -SELECT 'a <-> (b&c)'::tsquery; - tsquery ---------------------------- - 'a' <-> 'b' & 'a' <-> 'c' -(1 row) - -SELECT '(a&b) <-> c'::tsquery; - tsquery ---------------------------- - 'a' <-> 'c' & 'b' <-> 'c' -(1 row) - -SELECT '(a&b) <-> (d&c)'::tsquery; - tsquery -------------------------------------------------------- - 'a' <-> 'd' & 'b' <-> 'd' & 'a' <-> 'c' & 'b' <-> 'c' -(1 row) - -SELECT 'a <-> !b'::tsquery; - tsquery ------------------------- - 'a' & !( 'a' <-> 'b' ) -(1 row) - -SELECT '!a <-> b'::tsquery; - tsquery ------------------------- - !( 'a' <-> 'b' ) & 'b' -(1 row) - -SELECT '!a <-> !b'::tsquery; - tsquery ------------------------------------- - !'a' & !( !( 'a' <-> 'b' ) & 'b' ) -(1 row) - -SELECT 'a <-> !(b&c)'::tsquery; - tsquery --------------------------------------- - 'a' & !( 'a' <-> 'b' & 'a' <-> 'c' ) -(1 row) - -SELECT 'a <-> !(b|c)'::tsquery; - tsquery --------------------------------------- - 'a' & !( 'a' <-> 'b' | 'a' <-> 'c' ) -(1 row) - -SELECT '!(a&b) <-> c'::tsquery; - tsquery --------------------------------------- - !( 'a' <-> 'c' & 'b' <-> 'c' ) & 'c' -(1 row) - -SELECT '!(a|b) <-> c'::tsquery; - tsquery --------------------------------------- - !( 'a' <-> 'c' | 'b' <-> 'c' ) & 'c' -(1 row) - -SELECT '(!a|b) <-> c'::tsquery; - tsquery --------------------------------------- - !( 'a' <-> 'c' ) & 'c' | 'b' <-> 'c' -(1 row) - -SELECT '(!a&b) <-> c'::tsquery; - tsquery --------------------------------------- - !( 'a' <-> 'c' ) & 'c' & 'b' <-> 'c' -(1 row) - -SELECT 'c <-> (!a|b)'::tsquery; - tsquery --------------------------------------- - 'c' & !( 'c' <-> 'a' ) | 'c' <-> 'b' -(1 row) - -SELECT 'c <-> (!a&b)'::tsquery; - tsquery --------------------------------------- - 'c' & !( 'c' <-> 'a' ) & 'c' <-> 'b' -(1 row) - -SELECT '(a|b) <-> !c'::tsquery; - tsquery ------------------------------------------------- - ( 'a' | 'b' ) & !( 'a' <-> 'c' | 'b' <-> 'c' ) -(1 row) - -SELECT '(a&b) <-> !c'::tsquery; - tsquery --------------------------------------------- - 'a' & 'b' & !( 'a' <-> 'c' & 'b' <-> 'c' ) -(1 row) - -SELECT '!c <-> (a|b)'::tsquery; - tsquery -------------------------------------------------- - !( 'c' <-> 'a' ) & 'a' | !( 'c' <-> 'b' ) & 'b' -(1 row) - -SELECT '!c <-> (a&b)'::tsquery; - tsquery -------------------------------------------------- - !( 'c' <-> 'a' ) & 'a' & !( 'c' <-> 'b' ) & 'b' -(1 row) - --comparisons SELECT 'a' < 'b & c'::tsquery as "true"; true @@ -568,33 +441,33 @@ SELECT 'foo & bar'::tsquery && 'asd | fg'; (1 row) SELECT 'a' <-> 'b & d'::tsquery; - ?column? ---------------------------- - 'a' <-> 'b' & 'a' <-> 'd' + ?column? +----------------------- + 'a' <-> ( 'b' & 'd' ) (1 row) SELECT 'a & g' <-> 'b & d'::tsquery; - ?column? -------------------------------------------------------- - 'a' <-> 'b' & 'g' <-> 'b' & 'a' <-> 'd' & 'g' <-> 'd' + ?column? +--------------------------------- + ( 'a' & 'g' ) <-> ( 'b' & 'd' ) (1 row) SELECT 'a & g' <-> 'b | d'::tsquery; - ?column? -------------------------------------------------------- - 'a' <-> 'b' & 'g' <-> 'b' | 'a' <-> 'd' & 'g' <-> 'd' + ?column? +--------------------------------- + ( 'a' & 'g' ) <-> ( 'b' | 'd' ) (1 row) SELECT 'a & g' <-> 'b <-> d'::tsquery; - ?column? ---------------------------------------------------- - 'a' <-> ( 'b' <-> 'd' ) & 'g' <-> ( 'b' <-> 'd' ) + ?column? +----------------------------------- + ( 'a' & 'g' ) <-> ( 'b' <-> 'd' ) (1 row) SELECT tsquery_phrase('a <3> g', 'b & d', 10); - tsquery_phrase ---------------------------------------------- - 'a' <3> 'g' <10> 'b' & 'a' <3> 'g' <10> 'd' + tsquery_phrase +-------------------------------- + 'a' <3> 'g' <10> ( 'b' & 'd' ) (1 row) -- tsvector-tsquery operations @@ -749,25 +622,152 @@ SELECT to_tsvector('simple', '1 2 3 4') @@ '(1 <-> 2) <-> 3' AS "true"; t (1 row) -SELECT to_tsvector('simple', '1 2 3 4') @@ '1 <-> (2 <-> 3)' AS "false"; +SELECT to_tsvector('simple', '1 2 3 4') @@ '1 <-> (2 <-> 3)' AS "true"; + true +------ + t +(1 row) + +SELECT to_tsvector('simple', '1 2 3 4') @@ '1 <2> (2 <-> 3)' AS "false"; false ------- f (1 row) -SELECT to_tsvector('simple', '1 2 3 4') @@ '1 <2> (2 <-> 3)' AS "true"; +SELECT to_tsvector('simple', '1 2 1 2 3 4') @@ '(1 <-> 2) <-> 3' AS "true"; true ------ t (1 row) -SELECT to_tsvector('simple', '1 2 1 2 3 4') @@ '(1 <-> 2) <-> 3' AS "true"; +SELECT to_tsvector('simple', '1 2 1 2 3 4') @@ '1 <-> 2 <-> 3' AS "true"; true ------ t (1 row) -SELECT to_tsvector('simple', '1 2 1 2 3 4') @@ '1 <-> 2 <-> 3' AS "true"; +-- without position data, phrase search does not match +SELECT strip(to_tsvector('simple', '1 2 3 4')) @@ '1 <-> 2 <-> 3' AS "false"; + false +------- + f +(1 row) + +select to_tsvector('simple', 'q x q y') @@ 'q <-> (x & y)' AS "false"; + false +------- + f +(1 row) + +select to_tsvector('simple', 'q x') @@ 'q <-> (x | y <-> z)' AS "true"; + true +------ + t +(1 row) + +select to_tsvector('simple', 'q y') @@ 'q <-> (x | y <-> z)' AS "false"; + false +------- + f +(1 row) + +select to_tsvector('simple', 'q y z') @@ 'q <-> (x | y <-> z)' AS "true"; + true +------ + t +(1 row) + +select to_tsvector('simple', 'q y x') @@ 'q <-> (x | y <-> z)' AS "false"; + false +------- + f +(1 row) + +select to_tsvector('simple', 'q x y') @@ 'q <-> (x | y <-> z)' AS "true"; + true +------ + t +(1 row) + +select to_tsvector('simple', 'q x') @@ '(x | y <-> z) <-> q' AS "false"; + false +------- + f +(1 row) + +select to_tsvector('simple', 'x q') @@ '(x | y <-> z) <-> q' AS "true"; + true +------ + t +(1 row) + +select to_tsvector('simple', 'x y q') @@ '(x | y <-> z) <-> q' AS "false"; + false +------- + f +(1 row) + +select to_tsvector('simple', 'x y z') @@ '(x | y <-> z) <-> q' AS "false"; + false +------- + f +(1 row) + +select to_tsvector('simple', 'x y z q') @@ '(x | y <-> z) <-> q' AS "true"; + true +------ + t +(1 row) + +select to_tsvector('simple', 'y z q') @@ '(x | y <-> z) <-> q' AS "true"; + true +------ + t +(1 row) + +select to_tsvector('simple', 'y y q') @@ '(x | y <-> z) <-> q' AS "false"; + false +------- + f +(1 row) + +select to_tsvector('simple', 'y y q') @@ '(!x | y <-> z) <-> q' AS "true"; + true +------ + t +(1 row) + +select to_tsvector('simple', 'x y q') @@ '(!x | y <-> z) <-> q' AS "true"; + true +------ + t +(1 row) + +select to_tsvector('simple', 'y y q') @@ '(x | y <-> !z) <-> q' AS "true"; + true +------ + t +(1 row) + +select to_tsvector('simple', 'x q') @@ '(x | y <-> !z) <-> q' AS "true"; + true +------ + t +(1 row) + +select to_tsvector('simple', 'x q') @@ '(!x | y <-> z) <-> q' AS "false"; + false +------- + f +(1 row) + +select to_tsvector('simple', 'z q') @@ '(!x | y <-> z) <-> q' AS "true"; + true +------ + t +(1 row) + +select to_tsvector('simple', 'x y q y') @@ '!x <-> y' AS "true"; true ------ t @@ -1002,6 +1002,12 @@ SELECT 'a:1 b:3'::tsvector @@ 'a <3> b'::tsquery AS "false"; f (1 row) +SELECT 'a:1 b:3'::tsvector @@ 'a <0> a:*'::tsquery AS "true"; + true +------ + t +(1 row) + -- tsvector editing operations SELECT strip('w:12B w:13* w:12,5,6 a:1,3* a:3 w asd:1dc asd'::tsvector); strip diff --git a/src/test/regress/expected/txid.out b/src/test/regress/expected/txid.out index ddd217eb10..802ccb949f 100644 --- a/src/test/regress/expected/txid.out +++ b/src/test/regress/expected/txid.out @@ -238,3 +238,19 @@ SELECT txid_snapshot '1:9223372036854775808:3'; ERROR: invalid input syntax for type txid_snapshot: "1:9223372036854775808:3" LINE 1: SELECT txid_snapshot '1:9223372036854775808:3'; ^ +-- test txid_current_if_assigned +BEGIN; +SELECT txid_current_if_assigned() IS NULL; + ?column? +---------- + t +(1 row) + +SELECT txid_current() \gset +SELECT txid_current_if_assigned() IS NOT DISTINCT FROM BIGINT :'txid_current'; + ?column? +---------- + t +(1 row) + +COMMIT; diff --git a/src/test/regress/expected/typed_table.out b/src/test/regress/expected/typed_table.out index dce609803c..141d3bcf87 100644 --- a/src/test/regress/expected/typed_table.out +++ b/src/test/regress/expected/typed_table.out @@ -10,11 +10,11 @@ SELECT * FROM persons; (0 rows) \d persons - Table "public.persons" - Column | Type | Modifiers ---------+---------+----------- - id | integer | - name | text | + Table "public.persons" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + id | integer | | | + name | text | | | Typed table of type: person_type CREATE FUNCTION get_all_persons() RETURNS SETOF person_type @@ -46,11 +46,11 @@ CREATE TABLE persons2 OF person_type ( UNIQUE (name) ); \d persons2 - Table "public.persons2" - Column | Type | Modifiers ---------+---------+----------- - id | integer | not null - name | text | + Table "public.persons2" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + id | integer | | not null | + name | text | | | Indexes: "persons2_pkey" PRIMARY KEY, btree (id) "persons2_name_key" UNIQUE CONSTRAINT, btree (name) @@ -61,11 +61,11 @@ CREATE TABLE persons3 OF person_type ( name WITH OPTIONS DEFAULT '' ); \d persons3 - Table "public.persons3" - Column | Type | Modifiers ---------+---------+------------------ - id | integer | not null - name | text | default ''::text + Table "public.persons3" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+---------- + id | integer | | not null | + name | text | | | ''::text Indexes: "persons3_pkey" PRIMARY KEY, btree (id) Typed table of type: person_type diff --git a/src/test/regress/expected/union.out b/src/test/regress/expected/union.out index 016571bd4a..4d697bada7 100644 --- a/src/test/regress/expected/union.out +++ b/src/test/regress/expected/union.out @@ -2,14 +2,14 @@ -- UNION (also INTERSECT, EXCEPT) -- -- Simple UNION constructs -SELECT 1 AS two UNION SELECT 2; +SELECT 1 AS two UNION SELECT 2 ORDER BY 1; two ----- 1 2 (2 rows) -SELECT 1 AS one UNION SELECT 1; +SELECT 1 AS one UNION SELECT 1 ORDER BY 1; one ----- 1 @@ -29,7 +29,7 @@ SELECT 1 AS two UNION ALL SELECT 1; 1 (2 rows) -SELECT 1 AS three UNION SELECT 2 UNION SELECT 3; +SELECT 1 AS three UNION SELECT 2 UNION SELECT 3 ORDER BY 1; three ------- 1 @@ -37,14 +37,14 @@ SELECT 1 AS three UNION SELECT 2 UNION SELECT 3; 3 (3 rows) -SELECT 1 AS two UNION SELECT 2 UNION SELECT 2; +SELECT 1 AS two UNION SELECT 2 UNION SELECT 2 ORDER BY 1; two ----- 1 2 (2 rows) -SELECT 1 AS three UNION SELECT 2 UNION ALL SELECT 2; +SELECT 1 AS three UNION SELECT 2 UNION ALL SELECT 2 ORDER BY 1; three ------- 1 @@ -52,7 +52,7 @@ SELECT 1 AS three UNION SELECT 2 UNION ALL SELECT 2; 2 (3 rows) -SELECT 1.1 AS two UNION SELECT 2.2; +SELECT 1.1 AS two UNION SELECT 2.2 ORDER BY 1; two ----- 1.1 @@ -60,41 +60,41 @@ SELECT 1.1 AS two UNION SELECT 2.2; (2 rows) -- Mixed types -SELECT 1.1 AS two UNION SELECT 2; +SELECT 1.1 AS two UNION SELECT 2 ORDER BY 1; two ----- 1.1 2 (2 rows) -SELECT 1 AS two UNION SELECT 2.2; +SELECT 1 AS two UNION SELECT 2.2 ORDER BY 1; two ----- 1 2.2 (2 rows) -SELECT 1 AS one UNION SELECT 1.0::float8; +SELECT 1 AS one UNION SELECT 1.0::float8 ORDER BY 1; one ----- 1 (1 row) -SELECT 1.1 AS two UNION ALL SELECT 2; +SELECT 1.1 AS two UNION ALL SELECT 2 ORDER BY 1; two ----- 1.1 2 (2 rows) -SELECT 1.0::float8 AS two UNION ALL SELECT 1; +SELECT 1.0::float8 AS two UNION ALL SELECT 1 ORDER BY 1; two ----- 1 1 (2 rows) -SELECT 1.1 AS three UNION SELECT 2 UNION SELECT 3; +SELECT 1.1 AS three UNION SELECT 2 UNION SELECT 3 ORDER BY 1; three ------- 1.1 @@ -109,7 +109,7 @@ SELECT 1.1::float8 AS two UNION SELECT 2 UNION SELECT 2.0::float8 ORDER BY 1; 2 (2 rows) -SELECT 1.1 AS three UNION SELECT 2 UNION ALL SELECT 2; +SELECT 1.1 AS three UNION SELECT 2 UNION ALL SELECT 2 ORDER BY 1; three ------- 1.1 @@ -117,7 +117,7 @@ SELECT 1.1 AS three UNION SELECT 2 UNION ALL SELECT 2; 2 (3 rows) -SELECT 1.1 AS two UNION (SELECT 2 UNION ALL SELECT 2); +SELECT 1.1 AS two UNION (SELECT 2 UNION ALL SELECT 2) ORDER BY 1; two ----- 1.1 @@ -195,7 +195,8 @@ SELECT f1 AS five FROM FLOAT8_TBL WHERE f1 BETWEEN -1e6 AND 1e6 UNION SELECT f1 FROM INT4_TBL - WHERE f1 BETWEEN 0 AND 1000000; + WHERE f1 BETWEEN 0 AND 1000000 +ORDER BY 1; five ----------------------- -1004.3 @@ -260,19 +261,19 @@ ORDER BY 1; -- -- INTERSECT and EXCEPT -- -SELECT q2 FROM int8_tbl INTERSECT SELECT q1 FROM int8_tbl; +SELECT q2 FROM int8_tbl INTERSECT SELECT q1 FROM int8_tbl ORDER BY 1; q2 ------------------ - 4567890123456789 123 + 4567890123456789 (2 rows) -SELECT q2 FROM int8_tbl INTERSECT ALL SELECT q1 FROM int8_tbl; +SELECT q2 FROM int8_tbl INTERSECT ALL SELECT q1 FROM int8_tbl ORDER BY 1; q2 ------------------ + 123 4567890123456789 4567890123456789 - 123 (3 rows) SELECT q2 FROM int8_tbl EXCEPT SELECT q1 FROM int8_tbl ORDER BY 1; @@ -297,24 +298,24 @@ SELECT q2 FROM int8_tbl EXCEPT ALL SELECT DISTINCT q1 FROM int8_tbl ORDER BY 1; 4567890123456789 (3 rows) -SELECT q1 FROM int8_tbl EXCEPT SELECT q2 FROM int8_tbl; +SELECT q1 FROM int8_tbl EXCEPT SELECT q2 FROM int8_tbl ORDER BY 1; q1 ---- (0 rows) -SELECT q1 FROM int8_tbl EXCEPT ALL SELECT q2 FROM int8_tbl; +SELECT q1 FROM int8_tbl EXCEPT ALL SELECT q2 FROM int8_tbl ORDER BY 1; q1 ------------------ - 4567890123456789 123 + 4567890123456789 (2 rows) -SELECT q1 FROM int8_tbl EXCEPT ALL SELECT DISTINCT q2 FROM int8_tbl; +SELECT q1 FROM int8_tbl EXCEPT ALL SELECT DISTINCT q2 FROM int8_tbl ORDER BY 1; q1 ------------------ + 123 4567890123456789 4567890123456789 - 123 (3 rows) SELECT q1 FROM int8_tbl EXCEPT ALL SELECT q1 FROM int8_tbl FOR NO KEY UPDATE; @@ -322,7 +323,7 @@ ERROR: FOR NO KEY UPDATE is not allowed with UNION/INTERSECT/EXCEPT -- -- Mixed types -- -SELECT f1 FROM float8_tbl INTERSECT SELECT f1 FROM int4_tbl; +SELECT f1 FROM float8_tbl INTERSECT SELECT f1 FROM int4_tbl ORDER BY 1; f1 ---- 0 @@ -340,30 +341,30 @@ SELECT f1 FROM float8_tbl EXCEPT SELECT f1 FROM int4_tbl ORDER BY 1; -- -- Operator precedence and (((((extra))))) parentheses -- -SELECT q1 FROM int8_tbl INTERSECT SELECT q2 FROM int8_tbl UNION ALL SELECT q2 FROM int8_tbl; +SELECT q1 FROM int8_tbl INTERSECT SELECT q2 FROM int8_tbl UNION ALL SELECT q2 FROM int8_tbl ORDER BY 1; q1 ------------------- - 4567890123456789 + -4567890123456789 + 123 123 456 4567890123456789 - 123 4567890123456789 - -4567890123456789 + 4567890123456789 (7 rows) -SELECT q1 FROM int8_tbl INTERSECT (((SELECT q2 FROM int8_tbl UNION ALL SELECT q2 FROM int8_tbl))); +SELECT q1 FROM int8_tbl INTERSECT (((SELECT q2 FROM int8_tbl UNION ALL SELECT q2 FROM int8_tbl))) ORDER BY 1; q1 ------------------ - 4567890123456789 123 + 4567890123456789 (2 rows) -(((SELECT q1 FROM int8_tbl INTERSECT SELECT q2 FROM int8_tbl))) UNION ALL SELECT q2 FROM int8_tbl; +(((SELECT q1 FROM int8_tbl INTERSECT SELECT q2 FROM int8_tbl ORDER BY 1))) UNION ALL SELECT q2 FROM int8_tbl; q1 ------------------- - 4567890123456789 123 + 4567890123456789 456 4567890123456789 123 @@ -416,11 +417,11 @@ LINE 1: ... int8_tbl EXCEPT SELECT q2 FROM int8_tbl ORDER BY q2 LIMIT 1... ^ HINT: There is a column named "q2" in table "*SELECT* 2", but it cannot be referenced from this part of the query. -- But this should work: -SELECT q1 FROM int8_tbl EXCEPT (((SELECT q2 FROM int8_tbl ORDER BY q2 LIMIT 1))); +SELECT q1 FROM int8_tbl EXCEPT (((SELECT q2 FROM int8_tbl ORDER BY q2 LIMIT 1))) ORDER BY 1; q1 ------------------ - 4567890123456789 123 + 4567890123456789 (2 rows) -- @@ -593,23 +594,27 @@ SELECT * FROM (SELECT 1 AS t, 2 AS x UNION SELECT 2 AS t, 4 AS x) ss -WHERE x < 4; - QUERY PLAN --------------------------------------------- - Unique - -> Sort - Sort Key: (1), (2) - -> Append - -> Result - -> Result - One-Time Filter: false -(7 rows) +WHERE x < 4 +ORDER BY x; + QUERY PLAN +-------------------------------------------------- + Sort + Sort Key: (2) + -> Unique + -> Sort + Sort Key: (1), (2) + -> Append + -> Result + -> Result + One-Time Filter: false +(9 rows) SELECT * FROM (SELECT 1 AS t, 2 AS x UNION SELECT 2 AS t, 4 AS x) ss -WHERE x < 4; +WHERE x < 4 +ORDER BY x; t | x ---+--- 1 | 2 @@ -631,9 +636,10 @@ ORDER BY x; -> HashAggregate Group Key: (1), (generate_series(1, 10)) -> Append + -> ProjectSet + -> Result -> Result - -> Result -(9 rows) +(10 rows) SELECT * FROM (SELECT 1 AS t, generate_series(1,10) AS x @@ -653,24 +659,28 @@ SELECT * FROM (SELECT 1 AS t, (random()*3)::int AS x UNION SELECT 2 AS t, 4 AS x) ss -WHERE x > 3; - QUERY PLAN ------------------------------------------------------------------------------- - Subquery Scan on ss - Filter: (ss.x > 3) - -> Unique - -> Sort - Sort Key: (1), (((random() * '3'::double precision))::integer) - -> Append - -> Result - -> Result -(8 rows) +WHERE x > 3 +ORDER BY x; + QUERY PLAN +------------------------------------------------------------------------------------ + Sort + Sort Key: ss.x + -> Subquery Scan on ss + Filter: (ss.x > 3) + -> Unique + -> Sort + Sort Key: (1), (((random() * '3'::double precision))::integer) + -> Append + -> Result + -> Result +(10 rows) SELECT * FROM (SELECT 1 AS t, (random()*3)::int AS x UNION SELECT 2 AS t, 4 AS x) ss -WHERE x > 3; +WHERE x > 3 +ORDER BY x; t | x ---+--- 2 | 4 @@ -710,3 +720,33 @@ select * from drop table t3; drop function expensivefunc(int); +-- Test handling of appendrel quals that const-simplify into an AND +explain (costs off) +select * from + (select *, 0 as x from int8_tbl a + union all + select *, 1 as x from int8_tbl b) ss +where (x = 0) or (q1 >= q2 and q1 <= q2); + QUERY PLAN +--------------------------------------------- + Append + -> Seq Scan on int8_tbl a + -> Seq Scan on int8_tbl b + Filter: ((q1 >= q2) AND (q1 <= q2)) +(4 rows) + +select * from + (select *, 0 as x from int8_tbl a + union all + select *, 1 as x from int8_tbl b) ss +where (x = 0) or (q1 >= q2 and q1 <= q2); + q1 | q2 | x +------------------+-------------------+--- + 123 | 456 | 0 + 123 | 4567890123456789 | 0 + 4567890123456789 | 123 | 0 + 4567890123456789 | 4567890123456789 | 0 + 4567890123456789 | -4567890123456789 | 0 + 4567890123456789 | 4567890123456789 | 1 +(6 rows) + diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out index f60991eed0..2da3c069e1 100644 --- a/src/test/regress/expected/updatable_views.out +++ b/src/test/regress/expected/updatable_views.out @@ -86,55 +86,48 @@ SELECT table_name, column_name, is_updatable FROM information_schema.columns WHERE table_name LIKE E'r_\\_view%' ORDER BY table_name, ordinal_position; - table_name | column_name | is_updatable -------------+---------------+-------------- - ro_view1 | a | NO - ro_view1 | b | NO - ro_view10 | a | NO - ro_view11 | a | NO - ro_view11 | b | NO - ro_view12 | a | NO - ro_view13 | a | NO - ro_view13 | b | NO - ro_view17 | a | NO - ro_view17 | b | NO - ro_view18 | a | NO - ro_view19 | sequence_name | NO - ro_view19 | last_value | NO - ro_view19 | start_value | NO - ro_view19 | increment_by | NO - ro_view19 | max_value | NO - ro_view19 | min_value | NO - ro_view19 | cache_value | NO - ro_view19 | log_cnt | NO - ro_view19 | is_cycled | NO - ro_view19 | is_called | NO - ro_view2 | a | NO - ro_view2 | b | NO - ro_view20 | a | NO - ro_view20 | b | NO - ro_view20 | g | NO - ro_view3 | ?column? | NO - ro_view4 | count | NO - ro_view5 | a | NO - ro_view5 | rank | NO - ro_view6 | a | NO - ro_view6 | b | NO - ro_view7 | a | NO - ro_view7 | b | NO - ro_view8 | a | NO - ro_view8 | b | NO - ro_view9 | a | NO - ro_view9 | b | NO - rw_view14 | ctid | NO - rw_view14 | a | YES - rw_view14 | b | YES - rw_view15 | a | YES - rw_view15 | upper | NO - rw_view16 | a | YES - rw_view16 | b | YES - rw_view16 | aa | YES -(46 rows) + table_name | column_name | is_updatable +------------+-------------+-------------- + ro_view1 | a | NO + ro_view1 | b | NO + ro_view10 | a | NO + ro_view11 | a | NO + ro_view11 | b | NO + ro_view12 | a | NO + ro_view13 | a | NO + ro_view13 | b | NO + ro_view17 | a | NO + ro_view17 | b | NO + ro_view18 | a | NO + ro_view19 | last_value | NO + ro_view19 | log_cnt | NO + ro_view19 | is_called | NO + ro_view2 | a | NO + ro_view2 | b | NO + ro_view20 | a | NO + ro_view20 | b | NO + ro_view20 | g | NO + ro_view3 | ?column? | NO + ro_view4 | count | NO + ro_view5 | a | NO + ro_view5 | rank | NO + ro_view6 | a | NO + ro_view6 | b | NO + ro_view7 | a | NO + ro_view7 | b | NO + ro_view8 | a | NO + ro_view8 | b | NO + ro_view9 | a | NO + ro_view9 | b | NO + rw_view14 | ctid | NO + rw_view14 | a | YES + rw_view14 | b | YES + rw_view15 | a | YES + rw_view15 | upper | NO + rw_view16 | a | YES + rw_view16 | b | YES + rw_view16 | aa | YES +(39 rows) -- Read-only views DELETE FROM ro_view1; @@ -327,7 +320,7 @@ DELETE FROM ro_view18; ERROR: cannot delete from view "ro_view18" DETAIL: Views that do not select from a single table or view are not automatically updatable. HINT: To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule. -UPDATE ro_view19 SET max_value=1000; +UPDATE ro_view19 SET last_value=1000; ERROR: cannot update view "ro_view19" DETAIL: Views that do not select from a single table or view are not automatically updatable. HINT: To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule. @@ -1433,11 +1426,11 @@ INSERT INTO base_tbl VALUES (1,2), (2,3), (1,-1); CREATE VIEW rw_view1 AS SELECT * FROM base_tbl WHERE a < b WITH LOCAL CHECK OPTION; \d+ rw_view1 - View "public.rw_view1" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+---------+------------- - a | integer | | plain | - b | integer | | plain | + View "public.rw_view1" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+---------+------------- + a | integer | | | | plain | + b | integer | | | | plain | View definition: SELECT base_tbl.a, base_tbl.b @@ -1487,10 +1480,10 @@ CREATE VIEW rw_view1 AS SELECT * FROM base_tbl WHERE a > 0; CREATE VIEW rw_view2 AS SELECT * FROM rw_view1 WHERE a < 10 WITH CHECK OPTION; -- implicitly cascaded \d+ rw_view2 - View "public.rw_view2" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+---------+------------- - a | integer | | plain | + View "public.rw_view2" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+---------+------------- + a | integer | | | | plain | View definition: SELECT rw_view1.a FROM rw_view1 @@ -1527,10 +1520,10 @@ DETAIL: Failing row contains (15). CREATE OR REPLACE VIEW rw_view2 AS SELECT * FROM rw_view1 WHERE a < 10 WITH LOCAL CHECK OPTION; \d+ rw_view2 - View "public.rw_view2" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+---------+------------- - a | integer | | plain | + View "public.rw_view2" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+---------+------------- + a | integer | | | | plain | View definition: SELECT rw_view1.a FROM rw_view1 @@ -1568,10 +1561,10 @@ ERROR: new row violates check option for view "rw_view2" DETAIL: Failing row contains (30). ALTER VIEW rw_view2 RESET (check_option); \d+ rw_view2 - View "public.rw_view2" - Column | Type | Modifiers | Storage | Description ---------+---------+-----------+---------+------------- - a | integer | | plain | + View "public.rw_view2" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------+-----------+----------+---------+---------+------------- + a | integer | | | | plain | View definition: SELECT rw_view1.a FROM rw_view1 @@ -1903,26 +1896,20 @@ EXPLAIN (costs off) SELECT * FROM rw_view1 WHERE snoop(person); (4 rows) EXPLAIN (costs off) UPDATE rw_view1 SET person=person WHERE snoop(person); - QUERY PLAN ------------------------------------------------------------ - Update on base_tbl base_tbl_1 - -> Subquery Scan on base_tbl - Filter: snoop(base_tbl.person) - -> LockRows - -> Seq Scan on base_tbl base_tbl_2 - Filter: (visibility = 'public'::text) -(6 rows) + QUERY PLAN +------------------------------------------------------------------- + Update on base_tbl + -> Seq Scan on base_tbl + Filter: ((visibility = 'public'::text) AND snoop(person)) +(3 rows) EXPLAIN (costs off) DELETE FROM rw_view1 WHERE NOT snoop(person); - QUERY PLAN ------------------------------------------------------------ - Delete on base_tbl base_tbl_1 - -> Subquery Scan on base_tbl - Filter: (NOT snoop(base_tbl.person)) - -> LockRows - -> Seq Scan on base_tbl base_tbl_2 - Filter: (visibility = 'public'::text) -(6 rows) + QUERY PLAN +------------------------------------------------------------------------- + Delete on base_tbl + -> Seq Scan on base_tbl + Filter: ((visibility = 'public'::text) AND (NOT snoop(person))) +(3 rows) -- security barrier view on top of security barrier view CREATE VIEW rw_view2 WITH (security_barrier = true) AS @@ -1985,30 +1972,20 @@ EXPLAIN (costs off) SELECT * FROM rw_view2 WHERE snoop(person); (6 rows) EXPLAIN (costs off) UPDATE rw_view2 SET person=person WHERE snoop(person); - QUERY PLAN ------------------------------------------------------------------ - Update on base_tbl base_tbl_1 - -> Subquery Scan on base_tbl - Filter: snoop(base_tbl.person) - -> Subquery Scan on base_tbl_2 - Filter: snoop(base_tbl_2.person) - -> LockRows - -> Seq Scan on base_tbl base_tbl_3 - Filter: (visibility = 'public'::text) -(8 rows) + QUERY PLAN +------------------------------------------------------------------------------------- + Update on base_tbl + -> Seq Scan on base_tbl + Filter: ((visibility = 'public'::text) AND snoop(person) AND snoop(person)) +(3 rows) EXPLAIN (costs off) DELETE FROM rw_view2 WHERE NOT snoop(person); - QUERY PLAN ------------------------------------------------------------------ - Delete on base_tbl base_tbl_1 - -> Subquery Scan on base_tbl - Filter: (NOT snoop(base_tbl.person)) - -> Subquery Scan on base_tbl_2 - Filter: snoop(base_tbl_2.person) - -> LockRows - -> Seq Scan on base_tbl base_tbl_3 - Filter: (visibility = 'public'::text) -(8 rows) + QUERY PLAN +------------------------------------------------------------------------------------------- + Delete on base_tbl + -> Seq Scan on base_tbl + Filter: ((visibility = 'public'::text) AND snoop(person) AND (NOT snoop(person))) +(3 rows) DROP TABLE base_tbl CASCADE; NOTICE: drop cascades to 2 other objects @@ -2033,18 +2010,16 @@ SELECT * FROM rw_view1; (1 row) EXPLAIN (costs off) DELETE FROM rw_view1 WHERE id = 1 AND snoop(data); - QUERY PLAN -------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------- Update on base_tbl base_tbl_1 -> Nested Loop -> Index Scan using base_tbl_pkey on base_tbl base_tbl_1 Index Cond: (id = 1) - -> Subquery Scan on base_tbl - Filter: snoop(base_tbl.data) - -> Index Scan using base_tbl_pkey on base_tbl base_tbl_2 - Index Cond: (id = 1) - Filter: (NOT deleted) -(9 rows) + -> Index Scan using base_tbl_pkey on base_tbl + Index Cond: (id = 1) + Filter: ((NOT deleted) AND snoop(data)) +(7 rows) DELETE FROM rw_view1 WHERE id = 1 AND snoop(data); NOTICE: snooped value: Row 1 @@ -2121,85 +2096,45 @@ SELECT * FROM v1 WHERE a=8; (4 rows) EXPLAIN (VERBOSE, COSTS OFF) -UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a = 3; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Update on public.t1 t1_4 - Update on public.t1 t1_4 - Update on public.t11 t1 - Update on public.t12 t1 - Update on public.t111 t1 - -> Subquery Scan on t1 +UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a < 7 AND a != 6; + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------- + Update on public.t1 + Update on public.t1 + Update on public.t11 + Update on public.t12 + Update on public.t111 + -> Index Scan using t1_a_idx on public.t1 Output: 100, t1.b, t1.c, t1.ctid - Filter: snoop(t1.a) - -> LockRows - Output: t1_5.ctid, t1_5.a, t1_5.b, t1_5.c, t1_5.ctid, t12.ctid, t12.tableoid - -> Nested Loop Semi Join - Output: t1_5.ctid, t1_5.a, t1_5.b, t1_5.c, t1_5.ctid, t12.ctid, t12.tableoid - -> Seq Scan on public.t1 t1_5 - Output: t1_5.ctid, t1_5.a, t1_5.b, t1_5.c - Filter: ((t1_5.a > 5) AND (t1_5.a = 3) AND leakproof(t1_5.a)) - -> Append - -> Seq Scan on public.t12 - Output: t12.ctid, t12.tableoid, t12.a - Filter: (t12.a = 3) - -> Seq Scan on public.t111 - Output: t111.ctid, t111.tableoid, t111.a - Filter: (t111.a = 3) - -> Subquery Scan on t1_1 - Output: 100, t1_1.b, t1_1.c, t1_1.d, t1_1.ctid - Filter: snoop(t1_1.a) - -> LockRows - Output: t11.ctid, t11.a, t11.b, t11.c, t11.d, t11.ctid, t12_1.ctid, t12_1.tableoid - -> Nested Loop Semi Join - Output: t11.ctid, t11.a, t11.b, t11.c, t11.d, t11.ctid, t12_1.ctid, t12_1.tableoid - -> Seq Scan on public.t11 - Output: t11.ctid, t11.a, t11.b, t11.c, t11.d - Filter: ((t11.a > 5) AND (t11.a = 3) AND leakproof(t11.a)) - -> Append - -> Seq Scan on public.t12 t12_1 - Output: t12_1.ctid, t12_1.tableoid, t12_1.a - Filter: (t12_1.a = 3) - -> Seq Scan on public.t111 t111_1 - Output: t111_1.ctid, t111_1.tableoid, t111_1.a - Filter: (t111_1.a = 3) - -> Subquery Scan on t1_2 - Output: 100, t1_2.b, t1_2.c, t1_2.e, t1_2.ctid - Filter: snoop(t1_2.a) - -> LockRows - Output: t12_2.ctid, t12_2.a, t12_2.b, t12_2.c, t12_2.e, t12_2.ctid, t12_3.ctid, t12_3.tableoid - -> Nested Loop Semi Join - Output: t12_2.ctid, t12_2.a, t12_2.b, t12_2.c, t12_2.e, t12_2.ctid, t12_3.ctid, t12_3.tableoid - -> Seq Scan on public.t12 t12_2 - Output: t12_2.ctid, t12_2.a, t12_2.b, t12_2.c, t12_2.e - Filter: ((t12_2.a > 5) AND (t12_2.a = 3) AND leakproof(t12_2.a)) - -> Append - -> Seq Scan on public.t12 t12_3 - Output: t12_3.ctid, t12_3.tableoid, t12_3.a - Filter: (t12_3.a = 3) - -> Seq Scan on public.t111 t111_2 - Output: t111_2.ctid, t111_2.tableoid, t111_2.a - Filter: (t111_2.a = 3) - -> Subquery Scan on t1_3 - Output: 100, t1_3.b, t1_3.c, t1_3.d, t1_3.e, t1_3.ctid - Filter: snoop(t1_3.a) - -> LockRows - Output: t111_3.ctid, t111_3.a, t111_3.b, t111_3.c, t111_3.d, t111_3.e, t111_3.ctid, t12_4.ctid, t12_4.tableoid - -> Nested Loop Semi Join - Output: t111_3.ctid, t111_3.a, t111_3.b, t111_3.c, t111_3.d, t111_3.e, t111_3.ctid, t12_4.ctid, t12_4.tableoid - -> Seq Scan on public.t111 t111_3 - Output: t111_3.ctid, t111_3.a, t111_3.b, t111_3.c, t111_3.d, t111_3.e - Filter: ((t111_3.a > 5) AND (t111_3.a = 3) AND leakproof(t111_3.a)) - -> Append - -> Seq Scan on public.t12 t12_4 - Output: t12_4.ctid, t12_4.tableoid, t12_4.a - Filter: (t12_4.a = 3) - -> Seq Scan on public.t111 t111_4 - Output: t111_4.ctid, t111_4.tableoid, t111_4.a - Filter: (t111_4.a = 3) -(73 rows) - -UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a = 3; + Index Cond: ((t1.a > 5) AND (t1.a < 7)) + Filter: ((t1.a <> 6) AND (alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t1.a) AND leakproof(t1.a)) + SubPlan 1 + -> Append + -> Seq Scan on public.t12 t12_1 + Filter: (t12_1.a = t1.a) + -> Seq Scan on public.t111 t111_1 + Filter: (t111_1.a = t1.a) + SubPlan 2 + -> Append + -> Seq Scan on public.t12 t12_2 + Output: t12_2.a + -> Seq Scan on public.t111 t111_2 + Output: t111_2.a + -> Index Scan using t11_a_idx on public.t11 + Output: 100, t11.b, t11.c, t11.d, t11.ctid + Index Cond: ((t11.a > 5) AND (t11.a < 7)) + Filter: ((t11.a <> 6) AND (alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t11.a) AND leakproof(t11.a)) + -> Index Scan using t12_a_idx on public.t12 + Output: 100, t12.b, t12.c, t12.e, t12.ctid + Index Cond: ((t12.a > 5) AND (t12.a < 7)) + Filter: ((t12.a <> 6) AND (alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t12.a) AND leakproof(t12.a)) + -> Index Scan using t111_a_idx on public.t111 + Output: 100, t111.b, t111.c, t111.d, t111.e, t111.ctid + Index Cond: ((t111.a > 5) AND (t111.a < 7)) + Filter: ((t111.a <> 6) AND (alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t111.a) AND leakproof(t111.a)) +(33 rows) + +UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a < 7 AND a != 6; SELECT * FROM v1 WHERE a=100; -- Nothing should have been changed to 100 a | b | c | d ---+---+---+--- @@ -2212,82 +2147,42 @@ SELECT * FROM t1 WHERE a=100; -- Nothing should have been changed to 100 EXPLAIN (VERBOSE, COSTS OFF) UPDATE v1 SET a=a+1 WHERE snoop(a) AND leakproof(a) AND a = 8; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Update on public.t1 t1_4 - Update on public.t1 t1_4 - Update on public.t11 t1 - Update on public.t12 t1 - Update on public.t111 t1 - -> Subquery Scan on t1 + QUERY PLAN +--------------------------------------------------------------------------------------------------------- + Update on public.t1 + Update on public.t1 + Update on public.t11 + Update on public.t12 + Update on public.t111 + -> Index Scan using t1_a_idx on public.t1 Output: (t1.a + 1), t1.b, t1.c, t1.ctid - Filter: snoop(t1.a) - -> LockRows - Output: t1_5.a, t1_5.ctid, t1_5.b, t1_5.c, t1_5.ctid, t12.ctid, t12.tableoid - -> Nested Loop Semi Join - Output: t1_5.a, t1_5.ctid, t1_5.b, t1_5.c, t1_5.ctid, t12.ctid, t12.tableoid - -> Seq Scan on public.t1 t1_5 - Output: t1_5.a, t1_5.ctid, t1_5.b, t1_5.c - Filter: ((t1_5.a > 5) AND (t1_5.a = 8) AND leakproof(t1_5.a)) - -> Append - -> Seq Scan on public.t12 - Output: t12.ctid, t12.tableoid, t12.a - Filter: (t12.a = 8) - -> Seq Scan on public.t111 - Output: t111.ctid, t111.tableoid, t111.a - Filter: (t111.a = 8) - -> Subquery Scan on t1_1 - Output: (t1_1.a + 1), t1_1.b, t1_1.c, t1_1.d, t1_1.ctid - Filter: snoop(t1_1.a) - -> LockRows - Output: t11.a, t11.ctid, t11.b, t11.c, t11.d, t11.ctid, t12_1.ctid, t12_1.tableoid - -> Nested Loop Semi Join - Output: t11.a, t11.ctid, t11.b, t11.c, t11.d, t11.ctid, t12_1.ctid, t12_1.tableoid - -> Seq Scan on public.t11 - Output: t11.a, t11.ctid, t11.b, t11.c, t11.d - Filter: ((t11.a > 5) AND (t11.a = 8) AND leakproof(t11.a)) - -> Append - -> Seq Scan on public.t12 t12_1 - Output: t12_1.ctid, t12_1.tableoid, t12_1.a - Filter: (t12_1.a = 8) - -> Seq Scan on public.t111 t111_1 - Output: t111_1.ctid, t111_1.tableoid, t111_1.a - Filter: (t111_1.a = 8) - -> Subquery Scan on t1_2 - Output: (t1_2.a + 1), t1_2.b, t1_2.c, t1_2.e, t1_2.ctid - Filter: snoop(t1_2.a) - -> LockRows - Output: t12_2.a, t12_2.ctid, t12_2.b, t12_2.c, t12_2.e, t12_2.ctid, t12_3.ctid, t12_3.tableoid - -> Nested Loop Semi Join - Output: t12_2.a, t12_2.ctid, t12_2.b, t12_2.c, t12_2.e, t12_2.ctid, t12_3.ctid, t12_3.tableoid - -> Seq Scan on public.t12 t12_2 - Output: t12_2.a, t12_2.ctid, t12_2.b, t12_2.c, t12_2.e - Filter: ((t12_2.a > 5) AND (t12_2.a = 8) AND leakproof(t12_2.a)) - -> Append - -> Seq Scan on public.t12 t12_3 - Output: t12_3.ctid, t12_3.tableoid, t12_3.a - Filter: (t12_3.a = 8) - -> Seq Scan on public.t111 t111_2 - Output: t111_2.ctid, t111_2.tableoid, t111_2.a - Filter: (t111_2.a = 8) - -> Subquery Scan on t1_3 - Output: (t1_3.a + 1), t1_3.b, t1_3.c, t1_3.d, t1_3.e, t1_3.ctid - Filter: snoop(t1_3.a) - -> LockRows - Output: t111_3.a, t111_3.ctid, t111_3.b, t111_3.c, t111_3.d, t111_3.e, t111_3.ctid, t12_4.ctid, t12_4.tableoid - -> Nested Loop Semi Join - Output: t111_3.a, t111_3.ctid, t111_3.b, t111_3.c, t111_3.d, t111_3.e, t111_3.ctid, t12_4.ctid, t12_4.tableoid - -> Seq Scan on public.t111 t111_3 - Output: t111_3.a, t111_3.ctid, t111_3.b, t111_3.c, t111_3.d, t111_3.e - Filter: ((t111_3.a > 5) AND (t111_3.a = 8) AND leakproof(t111_3.a)) - -> Append - -> Seq Scan on public.t12 t12_4 - Output: t12_4.ctid, t12_4.tableoid, t12_4.a - Filter: (t12_4.a = 8) - -> Seq Scan on public.t111 t111_4 - Output: t111_4.ctid, t111_4.tableoid, t111_4.a - Filter: (t111_4.a = 8) -(73 rows) + Index Cond: ((t1.a > 5) AND (t1.a = 8)) + Filter: ((alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t1.a) AND leakproof(t1.a)) + SubPlan 1 + -> Append + -> Seq Scan on public.t12 t12_1 + Filter: (t12_1.a = t1.a) + -> Seq Scan on public.t111 t111_1 + Filter: (t111_1.a = t1.a) + SubPlan 2 + -> Append + -> Seq Scan on public.t12 t12_2 + Output: t12_2.a + -> Seq Scan on public.t111 t111_2 + Output: t111_2.a + -> Index Scan using t11_a_idx on public.t11 + Output: (t11.a + 1), t11.b, t11.c, t11.d, t11.ctid + Index Cond: ((t11.a > 5) AND (t11.a = 8)) + Filter: ((alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t11.a) AND leakproof(t11.a)) + -> Index Scan using t12_a_idx on public.t12 + Output: (t12.a + 1), t12.b, t12.c, t12.e, t12.ctid + Index Cond: ((t12.a > 5) AND (t12.a = 8)) + Filter: ((alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t12.a) AND leakproof(t12.a)) + -> Index Scan using t111_a_idx on public.t111 + Output: (t111.a + 1), t111.b, t111.c, t111.d, t111.e, t111.ctid + Index Cond: ((t111.a > 5) AND (t111.a = 8)) + Filter: ((alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t111.a) AND leakproof(t111.a)) +(33 rows) UPDATE v1 SET a=a+1 WHERE snoop(a) AND leakproof(a) AND a = 8; NOTICE: snooped value: 8 @@ -2459,3 +2354,16 @@ DROP VIEW v2; DROP VIEW v1; DROP TABLE t2; DROP TABLE t1; +-- +-- Test CREATE OR REPLACE VIEW turning a non-updatable view into an +-- auto-updatable view and adding check options in a single step +-- +CREATE TABLE t1 (a int, b text); +CREATE VIEW v1 AS SELECT null::int AS a; +CREATE OR REPLACE VIEW v1 AS SELECT * FROM t1 WHERE a > 0 WITH CHECK OPTION; +INSERT INTO v1 VALUES (1, 'ok'); -- ok +INSERT INTO v1 VALUES (-1, 'invalid'); -- should fail +ERROR: new row violates check option for view "v1" +DETAIL: Failing row contains (-1, invalid). +DROP VIEW v1; +DROP TABLE t1; diff --git a/src/test/regress/expected/update.out b/src/test/regress/expected/update.out index adc1fd7c39..a1e9255450 100644 --- a/src/test/regress/expected/update.out +++ b/src/test/regress/expected/update.out @@ -56,6 +56,13 @@ SELECT * FROM update_test; 100 | 20 | (2 rows) +-- fail, wrong data type: +UPDATE update_test SET a = v.* FROM (VALUES(100, 20)) AS v(i, j) + WHERE update_test.b = v.j; +ERROR: column "a" is of type integer but expression is of type record +LINE 1: UPDATE update_test SET a = v.* FROM (VALUES(100, 20)) AS v(i... + ^ +HINT: You will need to rewrite or cast the expression. -- -- Test multiple-set-clause syntax -- @@ -133,6 +140,15 @@ SELECT * FROM update_test; | | (4 rows) +-- *-expansion should work in this context: +UPDATE update_test SET (a,b) = ROW(v.*) FROM (VALUES(21, 100)) AS v(i, j) + WHERE update_test.a = v.i; +-- you might expect this to work, but syntactically it's not a RowExpr: +UPDATE update_test SET (a,b) = (v.*) FROM (VALUES(21, 101)) AS v(i, j) + WHERE update_test.a = v.i; +ERROR: source for a multiple-column UPDATE item must be a sub-SELECT or ROW() expression +LINE 1: UPDATE update_test SET (a,b) = (v.*) FROM (VALUES(21, 101)) ... + ^ -- if an alias for the target table is specified, don't allow references -- to the original table name UPDATE update_test AS t SET b = update_test.b + 10 WHERE t.a = 10; @@ -145,8 +161,8 @@ UPDATE update_test SET c = repeat('x', 10000) WHERE c = 'car'; SELECT a, b, char_length(c) FROM update_test; a | b | char_length ----+-----+------------- - 21 | 101 | | | + 21 | 100 | 41 | 12 | 10000 42 | 12 | 10000 (4 rows) @@ -182,3 +198,30 @@ INSERT INTO upsert_test VALUES (1, 'Bat') ON CONFLICT(a) DROP TABLE update_test; DROP TABLE upsert_test; +-- update to a partition should check partition bound constraint for the new tuple +create table range_parted ( + a text, + b int +) partition by range (a, b); +create table part_a_1_a_10 partition of range_parted for values from ('a', 1) to ('a', 10); +create table part_a_10_a_20 partition of range_parted for values from ('a', 10) to ('a', 20); +create table part_b_1_b_10 partition of range_parted for values from ('b', 1) to ('b', 10); +create table part_b_10_b_20 partition of range_parted for values from ('b', 10) to ('b', 20); +insert into part_a_1_a_10 values ('a', 1); +insert into part_b_10_b_20 values ('b', 10); +-- fail +update part_a_1_a_10 set a = 'b' where a = 'a'; +ERROR: new row for relation "part_a_1_a_10" violates partition constraint +DETAIL: Failing row contains (b, 1). +update range_parted set b = b - 1 where b = 10; +ERROR: new row for relation "part_b_10_b_20" violates partition constraint +DETAIL: Failing row contains (b, 9). +-- ok +update range_parted set b = b + 1 where b = 10; +-- cleanup +drop table range_parted cascade; +NOTICE: drop cascades to 4 other objects +DETAIL: drop cascades to table part_a_1_a_10 +drop cascades to table part_a_10_a_20 +drop cascades to table part_b_1_b_10 +drop cascades to table part_b_10_b_20 diff --git a/src/test/regress/expected/uuid.out b/src/test/regress/expected/uuid.out index 59cb1e0ba6..423f27787f 100644 --- a/src/test/regress/expected/uuid.out +++ b/src/test/regress/expected/uuid.out @@ -13,30 +13,30 @@ CREATE TABLE guid2 -- inserting invalid data tests -- too long INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-1111-111111111111F'); -ERROR: invalid input syntax for uuid: "11111111-1111-1111-1111-111111111111F" +ERROR: invalid input syntax for type uuid: "11111111-1111-1111-1111-111111111111F" LINE 1: INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-111... ^ -- too short INSERT INTO guid1(guid_field) VALUES('{11111111-1111-1111-1111-11111111111}'); -ERROR: invalid input syntax for uuid: "{11111111-1111-1111-1111-11111111111}" +ERROR: invalid input syntax for type uuid: "{11111111-1111-1111-1111-11111111111}" LINE 1: INSERT INTO guid1(guid_field) VALUES('{11111111-1111-1111-11... ^ -- valid data but invalid format INSERT INTO guid1(guid_field) VALUES('111-11111-1111-1111-1111-111111111111'); -ERROR: invalid input syntax for uuid: "111-11111-1111-1111-1111-111111111111" +ERROR: invalid input syntax for type uuid: "111-11111-1111-1111-1111-111111111111" LINE 1: INSERT INTO guid1(guid_field) VALUES('111-11111-1111-1111-11... ^ INSERT INTO guid1(guid_field) VALUES('{22222222-2222-2222-2222-222222222222 '); -ERROR: invalid input syntax for uuid: "{22222222-2222-2222-2222-222222222222 " +ERROR: invalid input syntax for type uuid: "{22222222-2222-2222-2222-222222222222 " LINE 1: INSERT INTO guid1(guid_field) VALUES('{22222222-2222-2222-22... ^ -- invalid data INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-G111-111111111111'); -ERROR: invalid input syntax for uuid: "11111111-1111-1111-G111-111111111111" +ERROR: invalid input syntax for type uuid: "11111111-1111-1111-G111-111111111111" LINE 1: INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-G11... ^ INSERT INTO guid1(guid_field) VALUES('11+11111-1111-1111-1111-111111111111'); -ERROR: invalid input syntax for uuid: "11+11111-1111-1111-1111-111111111111" +ERROR: invalid input syntax for type uuid: "11+11111-1111-1111-1111-111111111111" LINE 1: INSERT INTO guid1(guid_field) VALUES('11+11111-1111-1111-111... ^ --inserting three input formats diff --git a/src/test/regress/expected/with.out b/src/test/regress/expected/with.out index 137420d9b7..02fa08e932 100644 --- a/src/test/regress/expected/with.out +++ b/src/test/regress/expected/with.out @@ -354,10 +354,10 @@ UNION ALL ) SELECT sum(n) FROM t; \d+ sums_1_100 - View "public.sums_1_100" - Column | Type | Modifiers | Storage | Description ---------+--------+-----------+---------+------------- - sum | bigint | | plain | + View "public.sums_1_100" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+--------+-----------+----------+---------+---------+------------- + sum | bigint | | | | plain | View definition: WITH RECURSIVE t(n) AS ( VALUES (1) @@ -1244,7 +1244,7 @@ WITH outermost(x) AS ( SELECT * FROM innermost UNION SELECT 3) ) -SELECT * FROM outermost; +SELECT * FROM outermost ORDER BY 1; x --- 1 @@ -1258,7 +1258,7 @@ WITH outermost(x) AS ( SELECT * FROM outermost -- fail UNION SELECT * FROM innermost) ) -SELECT * FROM outermost; +SELECT * FROM outermost ORDER BY 1; ERROR: relation "outermost" does not exist LINE 4: SELECT * FROM outermost ^ @@ -1270,7 +1270,7 @@ WITH RECURSIVE outermost(x) AS ( SELECT * FROM outermost UNION SELECT * FROM innermost) ) -SELECT * FROM outermost; +SELECT * FROM outermost ORDER BY 1; x --- 1 @@ -1282,7 +1282,7 @@ WITH RECURSIVE outermost(x) AS ( SELECT * FROM innermost UNION SELECT * from outermost ) -SELECT * FROM outermost; +SELECT * FROM outermost ORDER BY 1; ERROR: recursive reference to query "outermost" must not appear within a subquery LINE 2: WITH innermost as (SELECT 2 FROM outermost) ^ diff --git a/src/test/regress/input/create_function_2.source b/src/test/regress/input/create_function_2.source index c518559777..3c26b2fec6 100644 --- a/src/test/regress/input/create_function_2.source +++ b/src/test/regress/input/create_function_2.source @@ -62,15 +62,6 @@ CREATE FUNCTION equipment_named_ambiguous_2b(hobby text) LANGUAGE SQL; -CREATE FUNCTION user_relns() - RETURNS setof name - AS 'select relname - from pg_class c, pg_namespace n - where relnamespace = n.oid and - (nspname !~ ''pg_.*'' and nspname <> ''information_schema'') and - relkind <> ''i'' ' - LANGUAGE SQL; - CREATE FUNCTION pt_in_widget(point, widget) RETURNS bool AS '@libdir@/regress@DLSUFFIX@' diff --git a/src/test/regress/input/misc.source b/src/test/regress/input/misc.source index e16dc21f40..dd2d1b2033 100644 --- a/src/test/regress/input/misc.source +++ b/src/test/regress/input/misc.source @@ -218,9 +218,6 @@ SELECT (p.hobbies).equipment.name, name(p.hobbies), p.name FROM ONLY person p; SELECT name(equipment(p.hobbies)), name(p.hobbies), p.name FROM person* p; -SELECT user_relns() AS user_relns - ORDER BY user_relns; - SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer'))); SELECT name(equipment(hobby_construct_named(text 'skywalking', text 'mer'))); diff --git a/src/test/regress/input/tablespace.source b/src/test/regress/input/tablespace.source index 041ec97400..743c4b982c 100644 --- a/src/test/regress/input/tablespace.source +++ b/src/test/regress/input/tablespace.source @@ -44,6 +44,49 @@ CREATE INDEX foo_idx on testschema.foo(i) TABLESPACE regress_tblspace; SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c where c.reltablespace = t.oid AND c.relname = 'foo_idx'; +-- check that default_tablespace doesn't affect ALTER TABLE index rebuilds +CREATE TABLE testschema.test_default_tab(id bigint) TABLESPACE regress_tblspace; +INSERT INTO testschema.test_default_tab VALUES (1); +CREATE INDEX test_index1 on testschema.test_default_tab (id); +CREATE INDEX test_index2 on testschema.test_default_tab (id) TABLESPACE regress_tblspace; +\d testschema.test_index1 +\d testschema.test_index2 +-- use a custom tablespace for default_tablespace +SET default_tablespace TO regress_tblspace; +-- tablespace should not change if no rewrite +ALTER TABLE testschema.test_default_tab ALTER id TYPE bigint; +\d testschema.test_index1 +\d testschema.test_index2 +SELECT * FROM testschema.test_default_tab; +-- tablespace should not change even if there is an index rewrite +ALTER TABLE testschema.test_default_tab ALTER id TYPE int; +\d testschema.test_index1 +\d testschema.test_index2 +SELECT * FROM testschema.test_default_tab; +-- now use the default tablespace for default_tablespace +SET default_tablespace TO ''; +-- tablespace should not change if no rewrite +ALTER TABLE testschema.test_default_tab ALTER id TYPE int; +\d testschema.test_index1 +\d testschema.test_index2 +-- tablespace should not change even if there is an index rewrite +ALTER TABLE testschema.test_default_tab ALTER id TYPE bigint; +\d testschema.test_index1 +\d testschema.test_index2 +DROP TABLE testschema.test_default_tab; + +-- check that default_tablespace affects index additions in ALTER TABLE +CREATE TABLE testschema.test_tab(id int) TABLESPACE regress_tblspace; +INSERT INTO testschema.test_tab VALUES (1); +SET default_tablespace TO regress_tblspace; +ALTER TABLE testschema.test_tab ADD CONSTRAINT test_tab_unique UNIQUE (id); +SET default_tablespace TO ''; +ALTER TABLE testschema.test_tab ADD CONSTRAINT test_tab_pkey PRIMARY KEY (id); +\d testschema.test_tab_unique +\d testschema.test_tab_pkey +SELECT * FROM testschema.test_tab; +DROP TABLE testschema.test_tab; + -- let's try moving a table from one place to another CREATE TABLE testschema.atable AS VALUES (1), (2); CREATE UNIQUE INDEX anindex ON testschema.atable(column1); diff --git a/src/test/regress/output/create_function_2.source b/src/test/regress/output/create_function_2.source index 829393243e..bdd1b1bec5 100644 --- a/src/test/regress/output/create_function_2.source +++ b/src/test/regress/output/create_function_2.source @@ -47,14 +47,6 @@ CREATE FUNCTION equipment_named_ambiguous_2b(hobby text) RETURNS setof equipment_r AS 'select * from equipment_r where equipment_r.hobby = hobby' LANGUAGE SQL; -CREATE FUNCTION user_relns() - RETURNS setof name - AS 'select relname - from pg_class c, pg_namespace n - where relnamespace = n.oid and - (nspname !~ ''pg_.*'' and nspname <> ''information_schema'') and - relkind <> ''i'' ' - LANGUAGE SQL; CREATE FUNCTION pt_in_widget(point, widget) RETURNS bool AS '@libdir@/regress@DLSUFFIX@' diff --git a/src/test/regress/output/misc.source b/src/test/regress/output/misc.source index 5c88aadc5d..574ef0d2e3 100644 --- a/src/test/regress/output/misc.source +++ b/src/test/regress/output/misc.source @@ -574,144 +574,6 @@ SELECT name(equipment(p.hobbies)), name(p.hobbies), p.name FROM person* p; peet's coffee | posthacking | jeff (6 rows) -SELECT user_relns() AS user_relns - ORDER BY user_relns; - user_relns ---------------------- - a - a_star - abstime_tbl - aggtest - aggtype - array_index_op_test - array_op_test - arrtest - b - b_star - box_tbl - bprime - brinopers - brintest - bt_f8_heap - bt_i4_heap - bt_name_heap - bt_txt_heap - btree_tall_tbl - c - c_star - char_tbl - check2_tbl - check_seq - check_tbl - circle_tbl - city - copy_tbl - d - d_star - date_tbl - default_seq - default_tbl - defaultexpr_tbl - dept - dupindexcols - e_star - emp - equipment_r - f_star - fast_emp4000 - float4_tbl - float8_tbl - func_index_heap - gin_test_tbl - gist_point_tbl - hash_f8_heap - hash_i4_heap - hash_name_heap - hash_txt_heap - hobbies_r - iexit - ihighway - inet_tbl - inhf - inhx - insert_seq - insert_tbl - int2_tbl - int4_tbl - int8_tbl - interval_tbl - iportaltest - kd_point_tbl - line_tbl - log_table - lseg_tbl - main_table - money_data - mvtest_bb - mvtest_t - mvtest_tm - mvtest_tmm - mvtest_tv - mvtest_tvm - mvtest_tvmm - mvtest_tvv - mvtest_tvvm - mvtest_tvvmv - num_data - num_exp_add - num_exp_div - num_exp_ln - num_exp_log10 - num_exp_mul - num_exp_power_10_ln - num_exp_sqrt - num_exp_sub - num_input_test - num_result - onek - onek2 - path_tbl - person - point_tbl - polygon_tbl - quad_point_tbl - radix_text_tbl - ramp - random_tbl - real_city - reltime_tbl - rls_tbl - rls_tbl_force - road - shighway - slow_emp4000 - spgist_point_tbl - spgist_text_tbl - street - stud_emp - student - subselect_tbl - tenk1 - tenk2 - test_range_excl - test_range_gist - test_range_spgist - test_tablesample - test_tablesample_v1 - test_tablesample_v2 - test_tsvector - testjsonb - text_tbl - time_tbl - timestamp_tbl - timestamptz_tbl - timetz_tbl - tinterval_tbl - toyemp - varchar_tbl - xacttest -(132 rows) - SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer'))); name ------ diff --git a/src/test/regress/output/tablespace.source b/src/test/regress/output/tablespace.source index 384f689ac1..31f2ac0ebd 100644 --- a/src/test/regress/output/tablespace.source +++ b/src/test/regress/output/tablespace.source @@ -61,6 +61,140 @@ SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c foo_idx | regress_tblspace (1 row) +-- check that default_tablespace doesn't affect ALTER TABLE index rebuilds +CREATE TABLE testschema.test_default_tab(id bigint) TABLESPACE regress_tblspace; +INSERT INTO testschema.test_default_tab VALUES (1); +CREATE INDEX test_index1 on testschema.test_default_tab (id); +CREATE INDEX test_index2 on testschema.test_default_tab (id) TABLESPACE regress_tblspace; +\d testschema.test_index1 +Index "testschema.test_index1" + Column | Type | Definition +--------+--------+------------ + id | bigint | id +btree, for table "testschema.test_default_tab" + +\d testschema.test_index2 +Index "testschema.test_index2" + Column | Type | Definition +--------+--------+------------ + id | bigint | id +btree, for table "testschema.test_default_tab" +Tablespace: "regress_tblspace" + +-- use a custom tablespace for default_tablespace +SET default_tablespace TO regress_tblspace; +-- tablespace should not change if no rewrite +ALTER TABLE testschema.test_default_tab ALTER id TYPE bigint; +\d testschema.test_index1 +Index "testschema.test_index1" + Column | Type | Definition +--------+--------+------------ + id | bigint | id +btree, for table "testschema.test_default_tab" + +\d testschema.test_index2 +Index "testschema.test_index2" + Column | Type | Definition +--------+--------+------------ + id | bigint | id +btree, for table "testschema.test_default_tab" +Tablespace: "regress_tblspace" + +SELECT * FROM testschema.test_default_tab; + id +---- + 1 +(1 row) + +-- tablespace should not change even if there is an index rewrite +ALTER TABLE testschema.test_default_tab ALTER id TYPE int; +\d testschema.test_index1 +Index "testschema.test_index1" + Column | Type | Definition +--------+---------+------------ + id | integer | id +btree, for table "testschema.test_default_tab" + +\d testschema.test_index2 +Index "testschema.test_index2" + Column | Type | Definition +--------+---------+------------ + id | integer | id +btree, for table "testschema.test_default_tab" +Tablespace: "regress_tblspace" + +SELECT * FROM testschema.test_default_tab; + id +---- + 1 +(1 row) + +-- now use the default tablespace for default_tablespace +SET default_tablespace TO ''; +-- tablespace should not change if no rewrite +ALTER TABLE testschema.test_default_tab ALTER id TYPE int; +\d testschema.test_index1 +Index "testschema.test_index1" + Column | Type | Definition +--------+---------+------------ + id | integer | id +btree, for table "testschema.test_default_tab" + +\d testschema.test_index2 +Index "testschema.test_index2" + Column | Type | Definition +--------+---------+------------ + id | integer | id +btree, for table "testschema.test_default_tab" +Tablespace: "regress_tblspace" + +-- tablespace should not change even if there is an index rewrite +ALTER TABLE testschema.test_default_tab ALTER id TYPE bigint; +\d testschema.test_index1 +Index "testschema.test_index1" + Column | Type | Definition +--------+--------+------------ + id | bigint | id +btree, for table "testschema.test_default_tab" + +\d testschema.test_index2 +Index "testschema.test_index2" + Column | Type | Definition +--------+--------+------------ + id | bigint | id +btree, for table "testschema.test_default_tab" +Tablespace: "regress_tblspace" + +DROP TABLE testschema.test_default_tab; +-- check that default_tablespace affects index additions in ALTER TABLE +CREATE TABLE testschema.test_tab(id int) TABLESPACE regress_tblspace; +INSERT INTO testschema.test_tab VALUES (1); +SET default_tablespace TO regress_tblspace; +ALTER TABLE testschema.test_tab ADD CONSTRAINT test_tab_unique UNIQUE (id); +SET default_tablespace TO ''; +ALTER TABLE testschema.test_tab ADD CONSTRAINT test_tab_pkey PRIMARY KEY (id); +\d testschema.test_tab_unique +Index "testschema.test_tab_unique" + Column | Type | Definition +--------+---------+------------ + id | integer | id +unique, btree, for table "testschema.test_tab" +Tablespace: "regress_tblspace" + +\d testschema.test_tab_pkey +Index "testschema.test_tab_pkey" + Column | Type | Definition +--------+---------+------------ + id | integer | id +primary key, btree, for table "testschema.test_tab" + +SELECT * FROM testschema.test_tab; + id +---- + 1 +(1 row) + +DROP TABLE testschema.test_tab; -- let's try moving a table from one place to another CREATE TABLE testschema.atable AS VALUES (1), (2); CREATE UNIQUE INDEX anindex ON testschema.atable(column1); diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index 3815182fe7..e9b2bad6fd 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -89,10 +89,16 @@ test: brin gin gist spgist privileges init_privs security_label collate matview # ---------- # Another group of parallel tests # ---------- -test: alter_generic alter_operator misc psql async dbsize misc_functions +test: alter_generic alter_operator misc psql async dbsize misc_functions tsrf # rules cannot run concurrently with any test that creates a view -test: rules psql_crosstab select_parallel amutils +test: rules psql_crosstab amutils + +# run by itself so it can run parallel workers +test: select_parallel + +# no relation related tests can be put in this group +test: publication subscription # ---------- # Another group of parallel tests diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c index 574f5b87be..d4d00d9c66 100644 --- a/src/test/regress/pg_regress.c +++ b/src/test/regress/pg_regress.c @@ -8,7 +8,7 @@ * * This code is released under the terms of the PostgreSQL License. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/test/regress/pg_regress.c @@ -151,10 +151,10 @@ unlimit_core_size(void) void add_stringlist_item(_stringlist **listhead, const char *str) { - _stringlist *newentry = malloc(sizeof(_stringlist)); + _stringlist *newentry = pg_malloc(sizeof(_stringlist)); _stringlist *oldentry; - newentry->str = strdup(str); + newentry->str = pg_strdup(str); newentry->next = NULL; if (*listhead == NULL) *listhead = newentry; @@ -187,7 +187,7 @@ free_stringlist(_stringlist **listhead) static void split_to_stringlist(const char *s, const char *delim, _stringlist **listhead) { - char *sc = strdup(s); + char *sc = pg_strdup(s); char *token = strtok(sc, delim); while (token) @@ -265,7 +265,7 @@ stop_postmaster(void) fflush(stderr); snprintf(buf, sizeof(buf), - "\"%s%spg_ctl\" stop -D \"%s/data\" -s -m fast", + "\"%s%spg_ctl\" stop -D \"%s/data\" -s", bindir ? bindir : "", bindir ? "/" : "", temp_instance); @@ -327,7 +327,7 @@ signal_remove_temp(int signum) static const char * make_temp_sockdir(void) { - char *template = strdup("/tmp/pg_regress-XXXXXX"); + char *template = pg_strdup("/tmp/pg_regress-XXXXXX"); temp_sockdir = mkdtemp(template); if (temp_sockdir == NULL) @@ -441,7 +441,7 @@ replace_string(char *string, char *replace, char *replacement) while ((ptr = strstr(string, replace)) != NULL) { - char *dup = strdup(string); + char *dup = pg_strdup(string); strlcpy(string, dup, ptr - string + 1); strcat(string, replacement); @@ -661,11 +661,11 @@ load_resultmap(void) */ if (string_matches_pattern(host_platform, platform)) { - _resultmap *entry = malloc(sizeof(_resultmap)); + _resultmap *entry = pg_malloc(sizeof(_resultmap)); - entry->test = strdup(buf); - entry->type = strdup(file_type); - entry->resultfile = strdup(expected); + entry->test = pg_strdup(buf); + entry->type = pg_strdup(file_type); + entry->resultfile = pg_strdup(expected); entry->next = resultmap; resultmap = entry; } @@ -738,9 +738,9 @@ initialize_environment(void) /* * Most platforms have adopted the POSIX locale as their * implementation-defined default locale. Exceptions include native - * Windows, Darwin with --enable-nls, and Cygwin with --enable-nls. + * Windows, macOS with --enable-nls, and Cygwin with --enable-nls. * (Use of --enable-nls matters because libintl replaces setlocale().) - * Also, PostgreSQL does not support Darwin with locale environment + * Also, PostgreSQL does not support macOS with locale environment * variables unset; see PostmasterMain(). */ #if defined(WIN32) || defined(__CYGWIN__) || defined(__darwin__) @@ -876,6 +876,29 @@ initialize_environment(void) load_resultmap(); } +pg_attribute_unused() +static const char * +fmtHba(const char *raw) +{ + static char *ret; + const char *rp; + char *wp; + + wp = ret = realloc(ret, 3 + strlen(raw) * 2); + + *wp++ = '"'; + for (rp = raw; *rp; rp++) + { + if (*rp == '"') + *wp++ = '"'; + *wp++ = *rp; + } + *wp++ = '"'; + *wp++ = '\0'; + + return ret; +} + #ifdef ENABLE_SSPI /* * Get account and domain/realm names for the current user. This is based on @@ -908,7 +931,7 @@ current_windows_user(const char **acct, const char **dom) progname, GetLastError()); exit(2); } - tokenuser = malloc(retlen); + tokenuser = pg_malloc(retlen); if (!GetTokenInformation(token, TokenUser, tokenuser, retlen, &retlen)) { fprintf(stderr, @@ -1037,11 +1060,11 @@ config_sspi_auth(const char *pgdata) * '#'. Windows forbids the double-quote character itself, so don't * bother escaping embedded double-quote characters. */ - CW(fprintf(ident, "regress \"%s@%s\" \"%s\"\n", - accountname, domainname, username) >= 0); + CW(fprintf(ident, "regress \"%s@%s\" %s\n", + accountname, domainname, fmtHba(username)) >= 0); for (sl = extraroles; sl; sl = sl->next) - CW(fprintf(ident, "regress \"%s@%s\" \"%s\"\n", - accountname, domainname, sl->str) >= 0); + CW(fprintf(ident, "regress \"%s@%s\" %s\n", + accountname, domainname, fmtHba(sl->str)) >= 0); CW(fclose(ident) == 0); } #endif @@ -1460,7 +1483,7 @@ wait_for_tests(PID_TYPE * pids, int *statuses, char **names, int num_tests) int i; #ifdef WIN32 - PID_TYPE *active_pids = malloc(num_tests * sizeof(PID_TYPE)); + PID_TYPE *active_pids = pg_malloc(num_tests * sizeof(PID_TYPE)); memcpy(active_pids, pids, num_tests * sizeof(PID_TYPE)); #endif @@ -1848,7 +1871,7 @@ open_result_files(void) /* create the log file (copy of running status output) */ snprintf(file, sizeof(file), "%s/regression.out", outputdir); - logfilename = strdup(file); + logfilename = pg_strdup(file); logfile = fopen(logfilename, "w"); if (!logfile) { @@ -1859,7 +1882,7 @@ open_result_files(void) /* create the diffs file as empty */ snprintf(file, sizeof(file), "%s/regression.diffs", outputdir); - difffilename = strdup(file); + difffilename = pg_strdup(file); difffile = fopen(difffilename, "w"); if (!difffile) { @@ -2064,13 +2087,13 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc * before we add the specified one. */ free_stringlist(&dblist); - split_to_stringlist(strdup(optarg), ", ", &dblist); + split_to_stringlist(optarg, ",", &dblist); break; case 2: debug = true; break; case 3: - inputdir = strdup(optarg); + inputdir = pg_strdup(optarg); break; case 4: add_stringlist_item(&loadlanguage, optarg); @@ -2079,10 +2102,10 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc max_connections = atoi(optarg); break; case 6: - encoding = strdup(optarg); + encoding = pg_strdup(optarg); break; case 7: - outputdir = strdup(optarg); + outputdir = pg_strdup(optarg); break; case 8: add_stringlist_item(&schedulelist, optarg); @@ -2094,27 +2117,27 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc nolocale = true; break; case 13: - hostname = strdup(optarg); + hostname = pg_strdup(optarg); break; case 14: port = atoi(optarg); port_specified_by_user = true; break; case 15: - user = strdup(optarg); + user = pg_strdup(optarg); break; case 16: /* "--bindir=" means to use PATH */ if (strlen(optarg)) - bindir = strdup(optarg); + bindir = pg_strdup(optarg); else bindir = NULL; break; case 17: - dlpath = strdup(optarg); + dlpath = pg_strdup(optarg); break; case 18: - split_to_stringlist(strdup(optarg), ", ", &extraroles); + split_to_stringlist(optarg, ",", &extraroles); break; case 19: add_stringlist_item(&temp_configs, optarg); @@ -2123,13 +2146,13 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc use_existing = true; break; case 21: - launcher = strdup(optarg); + launcher = pg_strdup(optarg); break; case 22: add_stringlist_item(&loadextension, optarg); break; case 24: - config_auth_datadir = pstrdup(optarg); + config_auth_datadir = pg_strdup(optarg); break; default: /* getopt_long already emitted a complaint */ @@ -2216,7 +2239,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc /* initdb */ header(_("initializing database system")); snprintf(buf, sizeof(buf), - "\"%s%sinitdb\" -D \"%s/data\" --noclean --nosync%s%s > \"%s/log/initdb.log\" 2>&1", + "\"%s%sinitdb\" -D \"%s/data\" --no-clean --no-sync%s%s > \"%s/log/initdb.log\" 2>&1", bindir ? bindir : "", bindir ? "/" : "", temp_instance, @@ -2247,6 +2270,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc fputs("\n# Configuration added by pg_regress\n\n", pg_conf); fputs("log_autovacuum_min_duration = 0\n", pg_conf); fputs("log_checkpoints = on\n", pg_conf); + fputs("log_line_prefix = '%m [%p] %q%a '\n", pg_conf); fputs("log_lock_waits = on\n", pg_conf); fputs("log_temp_files = 128kB\n", pg_conf); fputs("max_prepared_transactions = 2\n", pg_conf); diff --git a/src/test/regress/pg_regress.h b/src/test/regress/pg_regress.h index 51442e0425..62433b158f 100644 --- a/src/test/regress/pg_regress.h +++ b/src/test/regress/pg_regress.h @@ -1,7 +1,7 @@ /*------------------------------------------------------------------------- * pg_regress.h --- regression test driver * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/test/regress/pg_regress.h diff --git a/src/test/regress/pg_regress_main.c b/src/test/regress/pg_regress_main.c index d9591c0608..6106c6bbda 100644 --- a/src/test/regress/pg_regress_main.c +++ b/src/test/regress/pg_regress_main.c @@ -8,7 +8,7 @@ * * This code is released under the terms of the PostgreSQL License. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/test/regress/pg_regress_main.c @@ -34,6 +34,7 @@ psql_start_test(const char *testname, char expectfile[MAXPGPATH]; char psql_cmd[MAXPGPATH * 3]; size_t offset = 0; + char *appnameenv; /* * Look for files in the output dir first, consistent with a vpath search. @@ -63,6 +64,9 @@ psql_start_test(const char *testname, offset += snprintf(psql_cmd + offset, sizeof(psql_cmd) - offset, "%s ", launcher); + appnameenv = psprintf("PGAPPNAME=pg_regress/%s", testname); + putenv(appnameenv); + snprintf(psql_cmd + offset, sizeof(psql_cmd) - offset, "\"%s%spsql\" -X -a -q -d \"%s\" < \"%s\" > \"%s\" 2>&1", bindir ? bindir : "", @@ -80,6 +84,9 @@ psql_start_test(const char *testname, exit(2); } + unsetenv("PGAPPNAME"); + free(appnameenv); + return pid; } diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c index e7826a4513..986d54ce2f 100644 --- a/src/test/regress/regress.c +++ b/src/test/regress/regress.c @@ -6,7 +6,7 @@ * * This code is released under the terms of the PostgreSQL License. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/test/regress/regress.c @@ -523,11 +523,12 @@ ttdummy(PG_FUNCTION_ARGS) for (i = 0; i < 2; i++) { attnum[i] = SPI_fnumber(tupdesc, args[i]); - if (attnum[i] < 0) - elog(ERROR, "ttdummy (%s): there is no attribute %s", relname, args[i]); + if (attnum[i] <= 0) + elog(ERROR, "ttdummy (%s): there is no attribute %s", + relname, args[i]); if (SPI_gettypeid(tupdesc, attnum[i]) != INT4OID) - elog(ERROR, "ttdummy (%s): attributes %s and %s must be of abstime type", - relname, args[0], args[1]); + elog(ERROR, "ttdummy (%s): attribute %s must be of integer type", + relname, args[i]); } oldon = SPI_getbinval(trigtuple, tupdesc, attnum[0], &isnull); @@ -638,15 +639,8 @@ ttdummy(PG_FUNCTION_ARGS) /* Tuple to return to upper Executor ... */ if (newtuple) /* UPDATE */ - { - HeapTuple tmptuple; - - tmptuple = SPI_copytuple(trigtuple); - rettuple = SPI_modifytuple(rel, tmptuple, 1, &(attnum[1]), &newoff, NULL); - SPI_freetuple(tmptuple); - } - else - /* DELETE */ + rettuple = SPI_modifytuple(rel, trigtuple, 1, &(attnum[1]), &newoff, NULL); + else /* DELETE */ rettuple = trigtuple; SPI_finish(); /* don't forget say Bye to SPI mgr */ diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule index 8958d8cdb9..7cdc0f6a69 100644 --- a/src/test/regress/serial_schedule +++ b/src/test/regress/serial_schedule @@ -123,9 +123,12 @@ test: psql test: async test: dbsize test: misc_functions +test: tsrf test: rules test: psql_crosstab test: select_parallel +test: publication +test: subscription test: amutils test: select_views test: portals_p2 diff --git a/src/test/regress/sql/aggregates.sql b/src/test/regress/sql/aggregates.sql index 9983ff3a89..2eeb3eedbd 100644 --- a/src/test/regress/sql/aggregates.sql +++ b/src/test/regress/sql/aggregates.sql @@ -98,6 +98,28 @@ select (select max((select i.unique2 from tenk1 i where i.unique1 = o.unique1))) from tenk1 o; +-- Test handling of Params within aggregate arguments in hashed aggregation. +-- Per bug report from Jeevan Chalke. +explain (verbose, costs off) +select s1, s2, sm +from generate_series(1, 3) s1, + lateral (select s2, sum(s1 + s2) sm + from generate_series(1, 3) s2 group by s2) ss +order by 1, 2; +select s1, s2, sm +from generate_series(1, 3) s1, + lateral (select s2, sum(s1 + s2) sm + from generate_series(1, 3) s2 group by s2) ss +order by 1, 2; + +explain (verbose, costs off) +select array(select sum(x+y) s + from generate_series(1,3) y group by y order by s) + from generate_series(1,3) x; +select array(select sum(x+y) s + from generate_series(1,3) y group by y order by s) + from generate_series(1,3) x; + -- -- test for bitwise integer aggregates -- @@ -705,6 +727,9 @@ select my_avg(one),my_avg(one) from (values(1),(3)) t(one); -- aggregate state should be shared as transfn is the same for both aggs. select my_avg(one),my_sum(one) from (values(1),(3)) t(one); +-- same as previous one, but with DISTINCT, which requires sorting the input. +select my_avg(distinct one),my_sum(distinct one) from (values(1),(3),(1)) t(one); + -- shouldn't share states due to the distinctness not matching. select my_avg(distinct one),my_sum(one) from (values(1),(3)) t(one); diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index 72e65d4ee0..4611cbb731 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -407,6 +407,39 @@ ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2) -- As does this... ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest2, ftest1) references pktable(ptest1, ptest2); +DROP TABLE FKTABLE; +DROP TABLE PKTABLE; + +-- Test that ALTER CONSTRAINT updates trigger deferrability properly + +CREATE TEMP TABLE PKTABLE (ptest1 int primary key); +CREATE TEMP TABLE FKTABLE (ftest1 int); + +ALTER TABLE FKTABLE ADD CONSTRAINT fknd FOREIGN KEY(ftest1) REFERENCES pktable + ON DELETE CASCADE ON UPDATE NO ACTION NOT DEFERRABLE; +ALTER TABLE FKTABLE ADD CONSTRAINT fkdd FOREIGN KEY(ftest1) REFERENCES pktable + ON DELETE CASCADE ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED; +ALTER TABLE FKTABLE ADD CONSTRAINT fkdi FOREIGN KEY(ftest1) REFERENCES pktable + ON DELETE CASCADE ON UPDATE NO ACTION DEFERRABLE INITIALLY IMMEDIATE; + +ALTER TABLE FKTABLE ADD CONSTRAINT fknd2 FOREIGN KEY(ftest1) REFERENCES pktable + ON DELETE CASCADE ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED; +ALTER TABLE FKTABLE ALTER CONSTRAINT fknd2 NOT DEFERRABLE; +ALTER TABLE FKTABLE ADD CONSTRAINT fkdd2 FOREIGN KEY(ftest1) REFERENCES pktable + ON DELETE CASCADE ON UPDATE NO ACTION NOT DEFERRABLE; +ALTER TABLE FKTABLE ALTER CONSTRAINT fkdd2 DEFERRABLE INITIALLY DEFERRED; +ALTER TABLE FKTABLE ADD CONSTRAINT fkdi2 FOREIGN KEY(ftest1) REFERENCES pktable + ON DELETE CASCADE ON UPDATE NO ACTION NOT DEFERRABLE; +ALTER TABLE FKTABLE ALTER CONSTRAINT fkdi2 DEFERRABLE INITIALLY IMMEDIATE; + +SELECT conname, tgfoid::regproc, tgtype, tgdeferrable, tginitdeferred +FROM pg_trigger JOIN pg_constraint con ON con.oid = tgconstraint +WHERE tgrelid = 'pktable'::regclass +ORDER BY 1,2,3; +SELECT conname, tgfoid::regproc, tgtype, tgdeferrable, tginitdeferred +FROM pg_trigger JOIN pg_constraint con ON con.oid = tgconstraint +WHERE tgrelid = 'fktable'::regclass +ORDER BY 1,2,3; -- temp tables should go away by themselves, need not drop them. @@ -1302,6 +1335,28 @@ select relname, conname, coninhcount, conislocal, connoinherit where relname like 'test_inh_check%' and c.conrelid = r.oid order by 1, 2; +-- ALTER COLUMN TYPE with different schema in children +-- Bug at https://postgr.es/m/20170102225618.GA10071@telsasoft.com +CREATE TABLE test_type_diff (f1 int); +CREATE TABLE test_type_diff_c (extra smallint) INHERITS (test_type_diff); +ALTER TABLE test_type_diff ADD COLUMN f2 int; +INSERT INTO test_type_diff_c VALUES (1, 2, 3); +ALTER TABLE test_type_diff ALTER COLUMN f2 TYPE bigint USING f2::bigint; + +CREATE TABLE test_type_diff2 (int_two int2, int_four int4, int_eight int8); +CREATE TABLE test_type_diff2_c1 (int_four int4, int_eight int8, int_two int2); +CREATE TABLE test_type_diff2_c2 (int_eight int8, int_two int2, int_four int4); +CREATE TABLE test_type_diff2_c3 (int_two int2, int_four int4, int_eight int8); +ALTER TABLE test_type_diff2_c1 INHERIT test_type_diff2; +ALTER TABLE test_type_diff2_c2 INHERIT test_type_diff2; +ALTER TABLE test_type_diff2_c3 INHERIT test_type_diff2; +INSERT INTO test_type_diff2_c1 VALUES (1, 2, 3); +INSERT INTO test_type_diff2_c2 VALUES (4, 5, 6); +INSERT INTO test_type_diff2_c3 VALUES (7, 8, 9); +ALTER TABLE test_type_diff2 ALTER COLUMN int_four TYPE int8 USING int_four::int8; +-- whole-row references are disallowed +ALTER TABLE test_type_diff2 ALTER COLUMN int_four TYPE int4 USING (pg_column_size(test_type_diff2)); + -- check for rollback of ANALYZE corrupting table property flags (bug #11638) CREATE TABLE check_fk_presence_1 (id int PRIMARY KEY, t text); CREATE TABLE check_fk_presence_2 (id int REFERENCES check_fk_presence_1, t text); @@ -1842,3 +1897,325 @@ ALTER TABLE test_add_column ADD COLUMN c4 integer; \d test_add_column DROP TABLE test_add_column; + +-- unsupported constraint types for partitioned tables +CREATE TABLE partitioned ( + a int, + b int +) PARTITION BY RANGE (a, (a+b+1)); +ALTER TABLE partitioned ADD UNIQUE (a); +ALTER TABLE partitioned ADD PRIMARY KEY (a); +ALTER TABLE partitioned ADD FOREIGN KEY (a) REFERENCES blah; +ALTER TABLE partitioned ADD EXCLUDE USING gist (a WITH &&); + +-- cannot drop column that is part of the partition key +ALTER TABLE partitioned DROP COLUMN a; +ALTER TABLE partitioned ALTER COLUMN a TYPE char(5); +ALTER TABLE partitioned DROP COLUMN b; +ALTER TABLE partitioned ALTER COLUMN b TYPE char(5); + +-- cannot drop NOT NULL on columns in the range partition key +ALTER TABLE partitioned ALTER COLUMN a DROP NOT NULL; + +-- partitioned table cannot partiticipate in regular inheritance +CREATE TABLE foo ( + a int, + b int +); +ALTER TABLE partitioned INHERIT foo; +ALTER TABLE foo INHERIT partitioned; + +-- cannot add NO INHERIT constraint to partitioned tables +ALTER TABLE partitioned ADD CONSTRAINT chk_a CHECK (a > 0) NO INHERIT; + +DROP TABLE partitioned, foo; + +-- +-- ATTACH PARTITION +-- + +-- check that target table is partitioned +CREATE TABLE unparted ( + a int +); +CREATE TABLE fail_part (like unparted); +ALTER TABLE unparted ATTACH PARTITION fail_part FOR VALUES IN ('a'); +DROP TABLE unparted, fail_part; + +-- check that partition bound is compatible +CREATE TABLE list_parted ( + a int NOT NULL, + b char(2) COLLATE "C", + CONSTRAINT check_a CHECK (a > 0) +) PARTITION BY LIST (a); +CREATE TABLE fail_part (LIKE list_parted); +ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES FROM (1) TO (10); +DROP TABLE fail_part; + +-- check that the table being attached exists +ALTER TABLE list_parted ATTACH PARTITION nonexistant FOR VALUES IN (1); + +-- check ownership of the source table +CREATE ROLE regress_test_me; +CREATE ROLE regress_test_not_me; +CREATE TABLE not_owned_by_me (LIKE list_parted); +ALTER TABLE not_owned_by_me OWNER TO regress_test_not_me; +SET SESSION AUTHORIZATION regress_test_me; +CREATE TABLE owned_by_me ( + a int +) PARTITION BY LIST (a); +ALTER TABLE owned_by_me ATTACH PARTITION not_owned_by_me FOR VALUES IN (1); +RESET SESSION AUTHORIZATION; +DROP TABLE owned_by_me, not_owned_by_me; +DROP ROLE regress_test_not_me; +DROP ROLE regress_test_me; + +-- check that the table being attached is not part of regular inheritance +CREATE TABLE parent (LIKE list_parted); +CREATE TABLE child () INHERITS (parent); +ALTER TABLE list_parted ATTACH PARTITION child FOR VALUES IN (1); +ALTER TABLE list_parted ATTACH PARTITION parent FOR VALUES IN (1); +DROP TABLE parent CASCADE; + +-- check any TEMP-ness +CREATE TEMP TABLE temp_parted (a int) PARTITION BY LIST (a); +CREATE TABLE perm_part (a int); +ALTER TABLE temp_parted ATTACH PARTITION perm_part FOR VALUES IN (1); +DROP TABLE temp_parted, perm_part; + +-- check that the table being attached is not a typed table +CREATE TYPE mytype AS (a int); +CREATE TABLE fail_part OF mytype; +ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1); +DROP TYPE mytype CASCADE; + +-- check existence (or non-existence) of oid column +ALTER TABLE list_parted SET WITH OIDS; +CREATE TABLE fail_part (a int); +ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1); + +ALTER TABLE list_parted SET WITHOUT OIDS; +ALTER TABLE fail_part SET WITH OIDS; +ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1); +DROP TABLE fail_part; + +-- check that the table being attached has only columns present in the parent +CREATE TABLE fail_part (like list_parted, c int); +ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1); +DROP TABLE fail_part; + +-- check that the table being attached has every column of the parent +CREATE TABLE fail_part (a int NOT NULL); +ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1); +DROP TABLE fail_part; + +-- check that columns match in type, collation and NOT NULL status +CREATE TABLE fail_part ( + b char(3), + a int NOT NULL +); +ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1); +ALTER TABLE fail_part ALTER b TYPE char (2) COLLATE "POSIX"; +ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1); +DROP TABLE fail_part; + +-- check that the table being attached has all constraints of the parent +CREATE TABLE fail_part ( + b char(2) COLLATE "C", + a int NOT NULL +); +ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1); + +-- check that the constraint matches in definition with parent's constraint +ALTER TABLE fail_part ADD CONSTRAINT check_a CHECK (a >= 0); +ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1); +DROP TABLE fail_part; + +-- check the attributes and constraints after partition is attached +CREATE TABLE part_1 ( + a int NOT NULL, + b char(2) COLLATE "C", + CONSTRAINT check_a CHECK (a > 0) +); +ALTER TABLE list_parted ATTACH PARTITION part_1 FOR VALUES IN (1); +-- attislocal and conislocal are always false for merged attributes and constraints respectively. +SELECT attislocal, attinhcount FROM pg_attribute WHERE attrelid = 'part_1'::regclass AND attnum > 0; +SELECT conislocal, coninhcount FROM pg_constraint WHERE conrelid = 'part_1'::regclass AND conname = 'check_a'; + +-- check that the new partition won't overlap with an existing partition +CREATE TABLE fail_part (LIKE part_1 INCLUDING CONSTRAINTS); +ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1); + +-- check validation when attaching list partitions +CREATE TABLE list_parted2 ( + a int, + b char +) PARTITION BY LIST (a); + +-- check that violating rows are correctly reported +CREATE TABLE part_2 (LIKE list_parted2); +INSERT INTO part_2 VALUES (3, 'a'); +ALTER TABLE list_parted2 ATTACH PARTITION part_2 FOR VALUES IN (2); + +-- should be ok after deleting the bad row +DELETE FROM part_2; +ALTER TABLE list_parted2 ATTACH PARTITION part_2 FOR VALUES IN (2); + +-- adding constraints that describe the desired partition constraint +-- (or more restrictive) will help skip the validation scan +CREATE TABLE part_3_4 ( + LIKE list_parted2, + CONSTRAINT check_a CHECK (a IN (3)) +); + +-- however, if a list partition does not accept nulls, there should be +-- an explicit NOT NULL constraint on the partition key column for the +-- validation scan to be skipped; +ALTER TABLE list_parted2 ATTACH PARTITION part_3_4 FOR VALUES IN (3, 4); + +-- adding a NOT NULL constraint will cause the scan to be skipped +ALTER TABLE list_parted2 DETACH PARTITION part_3_4; +ALTER TABLE part_3_4 ALTER a SET NOT NULL; +ALTER TABLE list_parted2 ATTACH PARTITION part_3_4 FOR VALUES IN (3, 4); + + +-- check validation when attaching range partitions +CREATE TABLE range_parted ( + a int, + b int +) PARTITION BY RANGE (a, b); + +-- check that violating rows are correctly reported +CREATE TABLE part1 ( + a int NOT NULL CHECK (a = 1), + b int NOT NULL CHECK (b >= 1 AND b <= 10) +); +INSERT INTO part1 VALUES (1, 10); +-- Remember the TO bound is exclusive +ALTER TABLE range_parted ATTACH PARTITION part1 FOR VALUES FROM (1, 1) TO (1, 10); + +-- should be ok after deleting the bad row +DELETE FROM part1; +ALTER TABLE range_parted ATTACH PARTITION part1 FOR VALUES FROM (1, 1) TO (1, 10); + +-- adding constraints that describe the desired partition constraint +-- (or more restrictive) will help skip the validation scan +CREATE TABLE part2 ( + a int NOT NULL CHECK (a = 1), + b int NOT NULL CHECK (b >= 10 AND b < 18) +); +ALTER TABLE range_parted ATTACH PARTITION part2 FOR VALUES FROM (1, 10) TO (1, 20); + +-- check that leaf partitions are scanned when attaching a partitioned +-- table +CREATE TABLE part_5 ( + LIKE list_parted2 +) PARTITION BY LIST (b); + +-- check that violating rows are correctly reported +CREATE TABLE part_5_a PARTITION OF part_5 FOR VALUES IN ('a'); +INSERT INTO part_5_a (a, b) VALUES (6, 'a'); +ALTER TABLE list_parted2 ATTACH PARTITION part_5 FOR VALUES IN (5); + +-- delete the faulting row and also add a constraint to skip the scan +DELETE FROM part_5_a WHERE a NOT IN (3); +ALTER TABLE part_5 ADD CONSTRAINT check_a CHECK (a IN (5)), ALTER a SET NOT NULL; +ALTER TABLE list_parted2 ATTACH PARTITION part_5 FOR VALUES IN (5); + + +-- check that the table being attached is not already a partition +ALTER TABLE list_parted2 ATTACH PARTITION part_2 FOR VALUES IN (2); + +-- check that circular inheritance is not allowed +ALTER TABLE part_5 ATTACH PARTITION list_parted2 FOR VALUES IN ('b'); +ALTER TABLE list_parted2 ATTACH PARTITION list_parted2 FOR VALUES IN (0); + +-- +-- DETACH PARTITION +-- + +-- check that the partition being detached exists at all +ALTER TABLE list_parted2 DETACH PARTITION part_4; + +-- check that the partition being detached is actually a partition of the parent +CREATE TABLE not_a_part (a int); +ALTER TABLE list_parted2 DETACH PARTITION not_a_part; +ALTER TABLE list_parted2 DETACH PARTITION part_1; + +-- check that, after being detached, attinhcount/coninhcount is dropped to 0 and +-- attislocal/conislocal is set to true +ALTER TABLE list_parted2 DETACH PARTITION part_3_4; +SELECT attinhcount, attislocal FROM pg_attribute WHERE attrelid = 'part_3_4'::regclass AND attnum > 0; +SELECT coninhcount, conislocal FROM pg_constraint WHERE conrelid = 'part_3_4'::regclass AND conname = 'check_a'; +DROP TABLE part_3_4; + +-- Check ALTER TABLE commands for partitioned tables and partitions + +-- cannot add/drop column to/from *only* the parent +ALTER TABLE ONLY list_parted2 ADD COLUMN c int; +ALTER TABLE ONLY list_parted2 DROP COLUMN b; + +-- cannot add a column to partition or drop an inherited one +ALTER TABLE part_2 ADD COLUMN c text; +ALTER TABLE part_2 DROP COLUMN b; + +-- Nor rename, alter type +ALTER TABLE part_2 RENAME COLUMN b to c; +ALTER TABLE part_2 ALTER COLUMN b TYPE text; + +-- cannot add NOT NULL or check constraints to *only* the parent (ie, non-inherited) +ALTER TABLE ONLY list_parted2 ALTER b SET NOT NULL; +ALTER TABLE ONLY list_parted2 add constraint check_b check (b <> 'zz'); +ALTER TABLE list_parted2 add constraint check_b check (b <> 'zz') NO INHERIT; + +-- cannot drop inherited NOT NULL or check constraints from partition +ALTER TABLE list_parted2 ALTER b SET NOT NULL, ADD CONSTRAINT check_a2 CHECK (a > 0); +ALTER TABLE part_2 ALTER b DROP NOT NULL; +ALTER TABLE part_2 DROP CONSTRAINT check_a2; + +-- cannot drop NOT NULL or check constraints from *only* the parent +ALTER TABLE ONLY list_parted2 ALTER a DROP NOT NULL; +ALTER TABLE ONLY list_parted2 DROP CONSTRAINT check_a2; + +-- check that a partition cannot participate in regular inheritance +CREATE TABLE inh_test () INHERITS (part_2); +CREATE TABLE inh_test (LIKE part_2); +ALTER TABLE inh_test INHERIT part_2; +ALTER TABLE part_2 INHERIT inh_test; + +-- cannot drop or alter type of partition key columns of lower level +-- partitioned tables; for example, part_5, which is list_parted2's +-- partition, is partitioned on b; +ALTER TABLE list_parted2 DROP COLUMN b; +ALTER TABLE list_parted2 ALTER COLUMN b TYPE text; + +-- cleanup: avoid using CASCADE +DROP TABLE list_parted, part_1; +DROP TABLE list_parted2, part_2, part_5, part_5_a; +DROP TABLE range_parted, part1, part2; + +-- more tests for certain multi-level partitioning scenarios +create table p (a int, b int) partition by range (a, b); +create table p1 (b int, a int not null) partition by range (b); +create table p11 (like p1); +alter table p11 drop a; +alter table p11 add a int; +alter table p11 drop a; +alter table p11 add a int not null; +-- attnum for key attribute 'a' is different in p, p1, and p11 +select attrelid::regclass, attname, attnum +from pg_attribute +where attname = 'a' + and (attrelid = 'p'::regclass + or attrelid = 'p1'::regclass + or attrelid = 'p11'::regclass) +order by attrelid::regclass::text; + +alter table p1 attach partition p11 for values from (2) to (5); + +insert into p1 (a, b) values (2, 3); +-- check that partition validation scan correctly detects violating rows +alter table p attach partition p1 for values from (1, 2) to (1, 10); + +-- cleanup: avoid using CASCADE +drop table p, p1, p11; diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql index a2c3db1127..9de7207563 100644 --- a/src/test/regress/sql/arrays.sql +++ b/src/test/regress/sql/arrays.sql @@ -262,6 +262,15 @@ $$ LANGUAGE plpgsql; SELECT array_position('[2:4]={1,2,3}'::int[], 1); SELECT array_positions('[2:4]={1,2,3}'::int[], 1); +SELECT + array_position(ids, (1, 1)), + array_positions(ids, (1, 1)) + FROM +(VALUES + (ARRAY[(0, 0), (1, 1)]), + (ARRAY[(1, 1)]) +) AS f (ids); + -- operators SELECT a FROM arrtest WHERE b = ARRAY[[[113,142],[1,147]]]; SELECT NOT ARRAY[1.1,1.2,1.3] = ARRAY[1.1,1.2,1.3] AS "FALSE"; @@ -473,11 +482,19 @@ select array_fill(7, array[3,3],array[2,2]); select array_fill(7, array[3,3]); select array_fill('juhu'::text, array[3,3],array[2,2]); select array_fill('juhu'::text, array[3,3]); +select a, a = '{}' as is_eq, array_dims(a) + from (select array_fill(42, array[0]) as a) ss; +select a, a = '{}' as is_eq, array_dims(a) + from (select array_fill(42, '{}') as a) ss; +select a, a = '{}' as is_eq, array_dims(a) + from (select array_fill(42, '{}', '{}') as a) ss; -- raise exception select array_fill(1, null, array[2,2]); select array_fill(1, array[2,2], null); +select array_fill(1, array[2,2], '{}'); select array_fill(1, array[3,3], array[1,1,1]); select array_fill(1, array[1,2,null]); +select array_fill(1, array[[1,2],[3,4]]); select string_to_array('1|2|3', '|'); select string_to_array('1|2|3|', '|'); diff --git a/src/test/regress/sql/case.sql b/src/test/regress/sql/case.sql index b2377e4610..a7ae7b4a9e 100644 --- a/src/test/regress/sql/case.sql +++ b/src/test/regress/sql/case.sql @@ -167,6 +167,10 @@ SELECT * FROM CASE_TBL; -- the third WHEN-clause not to match. The volatile function calls are needed -- to prevent constant-folding in the planner, which would hide the bug. +-- Wrap this in a single transaction so the transient '=' operator doesn't +-- cause problems in concurrent sessions +BEGIN; + CREATE FUNCTION vol(text) returns text as 'begin return $1; end' language plpgsql volatile; @@ -194,14 +198,39 @@ CREATE OPERATOR = (procedure = inline_eq, SELECT CASE volfoo('bar') WHEN 'foo'::foodomain THEN 'is foo' ELSE 'is not foo' END; +ROLLBACK; + +-- Test multiple evaluation of a CASE arg that is a read/write object (#14472) +-- Wrap this in a single transaction so the transient '=' operator doesn't +-- cause problems in concurrent sessions +BEGIN; + +CREATE DOMAIN arrdomain AS int[]; + +CREATE FUNCTION make_ad(int,int) returns arrdomain as + 'declare x arrdomain; + begin + x := array[$1,$2]; + return x; + end' language plpgsql volatile; + +CREATE FUNCTION ad_eq(arrdomain, arrdomain) returns boolean as + 'begin return array_eq($1, $2); end' language plpgsql; + +CREATE OPERATOR = (procedure = ad_eq, + leftarg = arrdomain, rightarg = arrdomain); + +SELECT CASE make_ad(1,2) + WHEN array[2,4]::arrdomain THEN 'wrong' + WHEN array[2,5]::arrdomain THEN 'still wrong' + WHEN array[1,2]::arrdomain THEN 'right' + END; + +ROLLBACK; + -- -- Clean up -- DROP TABLE CASE_TBL; DROP TABLE CASE2_TBL; -DROP OPERATOR = (foodomain, foodomain); -DROP FUNCTION inline_eq(foodomain, foodomain); -DROP FUNCTION volfoo(text); -DROP DOMAIN foodomain; -DROP FUNCTION vol(text); diff --git a/src/test/regress/sql/combocid.sql b/src/test/regress/sql/combocid.sql index f24ac6b01a..4faea36f41 100644 --- a/src/test/regress/sql/combocid.sql +++ b/src/test/regress/sql/combocid.sql @@ -91,3 +91,21 @@ SELECT ctid,cmin,* FROM combocidtest; COMMIT; SELECT ctid,cmin,* FROM combocidtest; + +-- test for bug reported in +-- CABRT9RC81YUf1=jsmWopcKJEro=VoeG2ou6sPwyOUTx_qteRsg@mail.gmail.com +CREATE TABLE IF NOT EXISTS testcase( + id int PRIMARY KEY, + balance numeric +); +INSERT INTO testcase VALUES (1, 0); +BEGIN; +SELECT * FROM testcase WHERE testcase.id = 1 FOR UPDATE; +UPDATE testcase SET balance = balance + 400 WHERE id=1; +SAVEPOINT subxact; +UPDATE testcase SET balance = balance - 100 WHERE id=1; +ROLLBACK TO SAVEPOINT subxact; +-- should return one tuple +SELECT * FROM testcase WHERE id = 1 FOR UPDATE; +ROLLBACK; +DROP TABLE testcase; diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql index 39a9deb8f7..f3a6d228fa 100644 --- a/src/test/regress/sql/copy2.sql +++ b/src/test/regress/sql/copy2.sql @@ -327,9 +327,101 @@ copy check_con_tbl from stdin; \. select * from check_con_tbl; +-- test with RLS enabled. +CREATE ROLE regress_rls_copy_user; +CREATE ROLE regress_rls_copy_user_colperms; +CREATE TABLE rls_t1 (a int, b int, c int); + +COPY rls_t1 (a, b, c) from stdin; +1 4 1 +2 3 2 +3 2 3 +4 1 4 +\. + +CREATE POLICY p1 ON rls_t1 FOR SELECT USING (a % 2 = 0); +ALTER TABLE rls_t1 ENABLE ROW LEVEL SECURITY; +ALTER TABLE rls_t1 FORCE ROW LEVEL SECURITY; + +GRANT SELECT ON TABLE rls_t1 TO regress_rls_copy_user; +GRANT SELECT (a, b) ON TABLE rls_t1 TO regress_rls_copy_user_colperms; + +-- all columns +COPY rls_t1 TO stdout; +COPY rls_t1 (a, b, c) TO stdout; + +-- subset of columns +COPY rls_t1 (a) TO stdout; +COPY rls_t1 (a, b) TO stdout; + +-- column reordering +COPY rls_t1 (b, a) TO stdout; + +SET SESSION AUTHORIZATION regress_rls_copy_user; + +-- all columns +COPY rls_t1 TO stdout; +COPY rls_t1 (a, b, c) TO stdout; + +-- subset of columns +COPY rls_t1 (a) TO stdout; +COPY rls_t1 (a, b) TO stdout; + +-- column reordering +COPY rls_t1 (b, a) TO stdout; + +RESET SESSION AUTHORIZATION; + +SET SESSION AUTHORIZATION regress_rls_copy_user_colperms; + +-- attempt all columns (should fail) +COPY rls_t1 TO stdout; +COPY rls_t1 (a, b, c) TO stdout; + +-- try to copy column with no privileges (should fail) +COPY rls_t1 (c) TO stdout; + +-- subset of columns (should succeed) +COPY rls_t1 (a) TO stdout; +COPY rls_t1 (a, b) TO stdout; + +RESET SESSION AUTHORIZATION; + +-- test with INSTEAD OF INSERT trigger on a view +CREATE TABLE instead_of_insert_tbl(id serial, name text); +CREATE VIEW instead_of_insert_tbl_view AS SELECT ''::text AS str; + +COPY instead_of_insert_tbl_view FROM stdin; -- fail +test1 +\. + +CREATE FUNCTION fun_instead_of_insert_tbl() RETURNS trigger AS $$ +BEGIN + INSERT INTO instead_of_insert_tbl (name) VALUES (NEW.str); + RETURN NULL; +END; +$$ LANGUAGE plpgsql; +CREATE TRIGGER trig_instead_of_insert_tbl_view + INSTEAD OF INSERT ON instead_of_insert_tbl_view + FOR EACH ROW EXECUTE PROCEDURE fun_instead_of_insert_tbl(); + +COPY instead_of_insert_tbl_view FROM stdin; +test1 +\. + +SELECT * FROM instead_of_insert_tbl; + + +-- clean up DROP TABLE forcetest; DROP TABLE vistest; DROP FUNCTION truncate_in_subxact(); DROP TABLE x, y; +DROP TABLE rls_t1 CASCADE; +DROP ROLE regress_rls_copy_user; +DROP ROLE regress_rls_copy_user_colperms; DROP FUNCTION fn_x_before(); DROP FUNCTION fn_x_after(); +DROP TABLE instead_of_insert_tbl; +DROP VIEW instead_of_insert_tbl_view; +DROP FUNCTION fun_instead_of_insert_tbl(); diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql index 71f4f54cad..1648072568 100644 --- a/src/test/regress/sql/create_index.sql +++ b/src/test/regress/sql/create_index.sql @@ -1001,7 +1001,7 @@ SELECT thousand, tenthous FROM tenk1 WHERE thousand < 2 AND tenthous IN (1001,3000) ORDER BY thousand; -RESET enable_indexscan; +RESET enable_indexonlyscan; -- -- Check elimination of constant-NULL subexpressions @@ -1010,6 +1010,21 @@ RESET enable_indexscan; explain (costs off) select * from tenk1 where (thousand, tenthous) in ((1,1001), (null,null)); +-- +-- Check matching of boolean index columns to WHERE conditions and sort keys +-- + +create temp table boolindex (b bool, i int, unique(b, i), junk float); + +explain (costs off) + select * from boolindex order by b, i limit 10; +explain (costs off) + select * from boolindex where b order by i limit 10; +explain (costs off) + select * from boolindex where b = true order by i desc limit 10; +explain (costs off) + select * from boolindex where not b order by i limit 10; + -- -- REINDEX (VERBOSE) -- diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql index 78bdc8bf5e..8242e7328d 100644 --- a/src/test/regress/sql/create_table.sql +++ b/src/test/regress/sql/create_table.sql @@ -269,3 +269,326 @@ DROP TABLE as_select1; -- check that the oid column is added before the primary key is checked CREATE TABLE oid_pk (f1 INT, PRIMARY KEY(oid)) WITH OIDS; DROP TABLE oid_pk; + +-- +-- Partitioned tables +-- + +-- cannot combine INHERITS and PARTITION BY (although grammar allows) +CREATE TABLE partitioned ( + a int +) INHERITS (some_table) PARTITION BY LIST (a); + +-- cannot use more than 1 column as partition key for list partitioned table +CREATE TABLE partitioned ( + a1 int, + a2 int +) PARTITION BY LIST (a1, a2); -- fail + +-- unsupported constraint type for partitioned tables +CREATE TABLE partitioned ( + a int PRIMARY KEY +) PARTITION BY RANGE (a); + +CREATE TABLE pkrel ( + a int PRIMARY KEY +); +CREATE TABLE partitioned ( + a int REFERENCES pkrel(a) +) PARTITION BY RANGE (a); +DROP TABLE pkrel; + +CREATE TABLE partitioned ( + a int UNIQUE +) PARTITION BY RANGE (a); + +CREATE TABLE partitioned ( + a int, + EXCLUDE USING gist (a WITH &&) +) PARTITION BY RANGE (a); + +-- prevent column from being used twice in the partition key +CREATE TABLE partitioned ( + a int +) PARTITION BY RANGE (a, a); + +-- prevent using prohibited expressions in the key +CREATE FUNCTION retset (a int) RETURNS SETOF int AS $$ SELECT 1; $$ LANGUAGE SQL IMMUTABLE; +CREATE TABLE partitioned ( + a int +) PARTITION BY RANGE (retset(a)); +DROP FUNCTION retset(int); + +CREATE TABLE partitioned ( + a int +) PARTITION BY RANGE ((avg(a))); + +CREATE TABLE partitioned ( + a int, + b int +) PARTITION BY RANGE ((avg(a) OVER (PARTITION BY b))); + +CREATE TABLE partitioned ( + a int +) PARTITION BY LIST ((a LIKE (SELECT 1))); + +CREATE TABLE partitioned ( + a int +) PARTITION BY RANGE (('a')); + +CREATE FUNCTION const_func () RETURNS int AS $$ SELECT 1; $$ LANGUAGE SQL IMMUTABLE; +CREATE TABLE partitioned ( + a int +) PARTITION BY RANGE (const_func()); +DROP FUNCTION const_func(); + +-- only accept "list" and "range" as partitioning strategy +CREATE TABLE partitioned ( + a int +) PARTITION BY HASH (a); + +-- specified column must be present in the table +CREATE TABLE partitioned ( + a int +) PARTITION BY RANGE (b); + +-- cannot use system columns in partition key +CREATE TABLE partitioned ( + a int +) PARTITION BY RANGE (xmin); + +-- functions in key must be immutable +CREATE FUNCTION immut_func (a int) RETURNS int AS $$ SELECT a + random()::int; $$ LANGUAGE SQL; +CREATE TABLE partitioned ( + a int +) PARTITION BY RANGE (immut_func(a)); +DROP FUNCTION immut_func(int); + +-- cannot contain whole-row references +CREATE TABLE partitioned ( + a int +) PARTITION BY RANGE ((partitioned)); + +-- prevent using columns of unsupported types in key (type must have a btree operator class) +CREATE TABLE partitioned ( + a point +) PARTITION BY LIST (a); +CREATE TABLE partitioned ( + a point +) PARTITION BY LIST (a point_ops); +CREATE TABLE partitioned ( + a point +) PARTITION BY RANGE (a); +CREATE TABLE partitioned ( + a point +) PARTITION BY RANGE (a point_ops); + +-- cannot add NO INHERIT constraints to partitioned tables +CREATE TABLE partitioned ( + a int, + CONSTRAINT check_a CHECK (a > 0) NO INHERIT +) PARTITION BY RANGE (a); + +-- some checks after successful creation of a partitioned table +CREATE FUNCTION plusone(a int) RETURNS INT AS $$ SELECT a+1; $$ LANGUAGE SQL; + +CREATE TABLE partitioned ( + a int, + b int, + c text, + d text +) PARTITION BY RANGE (a oid_ops, plusone(b), c collate "default", d collate "C"); + +-- check relkind +SELECT relkind FROM pg_class WHERE relname = 'partitioned'; + +-- check that range partition key columns are marked NOT NULL +SELECT attname, attnotnull FROM pg_attribute + WHERE attrelid = 'partitioned'::regclass AND attnum > 0 + ORDER BY attnum; + +-- prevent a function referenced in partition key from being dropped +DROP FUNCTION plusone(int); + +-- partitioned table cannot partiticipate in regular inheritance +CREATE TABLE partitioned2 ( + a int +) PARTITION BY LIST ((a+1)); +CREATE TABLE fail () INHERITS (partitioned2); + +-- Partition key in describe output +\d partitioned +\d partitioned2 + +DROP TABLE partitioned, partitioned2; + +-- +-- Partitions +-- + +-- check partition bound syntax + +CREATE TABLE list_parted ( + a int +) PARTITION BY LIST (a); +-- syntax allows only string literal, numeric literal and null to be +-- specified for a partition bound value +CREATE TABLE part_1 PARTITION OF list_parted FOR VALUES IN ('1'); +CREATE TABLE part_2 PARTITION OF list_parted FOR VALUES IN (2); +CREATE TABLE part_null PARTITION OF list_parted FOR VALUES IN (null); +CREATE TABLE fail_part PARTITION OF list_parted FOR VALUES IN (int '1'); +CREATE TABLE fail_part PARTITION OF list_parted FOR VALUES IN ('1'::int); + +-- syntax does not allow empty list of values for list partitions +CREATE TABLE fail_part PARTITION OF list_parted FOR VALUES IN (); +-- trying to specify range for list partitioned table +CREATE TABLE fail_part PARTITION OF list_parted FOR VALUES FROM (1) TO (2); + +-- specified literal can't be cast to the partition column data type +CREATE TABLE bools ( + a bool +) PARTITION BY LIST (a); +CREATE TABLE bools_true PARTITION OF bools FOR VALUES IN (1); +DROP TABLE bools; + +CREATE TABLE range_parted ( + a date +) PARTITION BY RANGE (a); + +-- trying to specify list for range partitioned table +CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES IN ('a'); +-- each of start and end bounds must have same number of values as the +-- length of the partition key +CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES FROM ('a', 1) TO ('z'); +CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES FROM ('a') TO ('z', 1); + +-- cannot specify null values in range bounds +CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES FROM (null) TO (unbounded); + +-- check if compatible with the specified parent + +-- cannot create as partition of a non-partitioned table +CREATE TABLE unparted ( + a int +); +CREATE TABLE fail_part PARTITION OF unparted FOR VALUES IN ('a'); +DROP TABLE unparted; + +-- cannot create a permanent rel as partition of a temp rel +CREATE TEMP TABLE temp_parted ( + a int +) PARTITION BY LIST (a); +CREATE TABLE fail_part PARTITION OF temp_parted FOR VALUES IN ('a'); +DROP TABLE temp_parted; + +-- cannot create a table with oids as partition of table without oids +CREATE TABLE no_oids_parted ( + a int +) PARTITION BY RANGE (a) WITHOUT OIDS; +CREATE TABLE fail_part PARTITION OF no_oids_parted FOR VALUES FROM (1) TO (10 )WITH OIDS; +DROP TABLE no_oids_parted; + +-- likewise, the reverse if also true +CREATE TABLE oids_parted ( + a int +) PARTITION BY RANGE (a) WITH OIDS; +CREATE TABLE fail_part PARTITION OF oids_parted FOR VALUES FROM (1) TO (10 ) WITHOUT OIDS; +DROP TABLE oids_parted; + +-- check for partition bound overlap and other invalid specifications + +CREATE TABLE list_parted2 ( + a varchar +) PARTITION BY LIST (a); +CREATE TABLE part_null_z PARTITION OF list_parted2 FOR VALUES IN (null, 'z'); +CREATE TABLE part_ab PARTITION OF list_parted2 FOR VALUES IN ('a', 'b'); + +CREATE TABLE fail_part PARTITION OF list_parted2 FOR VALUES IN (null); +CREATE TABLE fail_part PARTITION OF list_parted2 FOR VALUES IN ('b', 'c'); + +CREATE TABLE range_parted2 ( + a int +) PARTITION BY RANGE (a); + +-- trying to create range partition with empty range +CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (1) TO (0); +-- note that the range '[1, 1)' has no elements +CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (1) TO (1); + +CREATE TABLE part0 PARTITION OF range_parted2 FOR VALUES FROM (unbounded) TO (1); +CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (unbounded) TO (2); +CREATE TABLE part1 PARTITION OF range_parted2 FOR VALUES FROM (1) TO (10); +CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (9) TO (unbounded); +CREATE TABLE part2 PARTITION OF range_parted2 FOR VALUES FROM (20) TO (30); +CREATE TABLE part3 PARTITION OF range_parted2 FOR VALUES FROM (30) TO (40); +CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (10) TO (30); +CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (10) TO (50); + +-- now check for multi-column range partition key +CREATE TABLE range_parted3 ( + a int, + b int +) PARTITION BY RANGE (a, (b+1)); + +CREATE TABLE part00 PARTITION OF range_parted3 FOR VALUES FROM (0, unbounded) TO (0, unbounded); +CREATE TABLE fail_part PARTITION OF range_parted3 FOR VALUES FROM (0, unbounded) TO (0, 1); + +CREATE TABLE part10 PARTITION OF range_parted3 FOR VALUES FROM (1, unbounded) TO (1, 1); +CREATE TABLE part11 PARTITION OF range_parted3 FOR VALUES FROM (1, 1) TO (1, 10); +CREATE TABLE part12 PARTITION OF range_parted3 FOR VALUES FROM (1, 10) TO (1, unbounded); +CREATE TABLE fail_part PARTITION OF range_parted3 FOR VALUES FROM (1, 10) TO (1, 20); + +-- cannot create a partition that says column b is allowed to range +-- from -infinity to +infinity, while there exist partitions that have +-- more specific ranges +CREATE TABLE fail_part PARTITION OF range_parted3 FOR VALUES FROM (1, unbounded) TO (1, unbounded); + +-- check schema propagation from parent + +CREATE TABLE parted ( + a text, + b int NOT NULL DEFAULT 0, + CONSTRAINT check_a CHECK (length(a) > 0) +) PARTITION BY LIST (a); + +CREATE TABLE part_a PARTITION OF parted FOR VALUES IN ('a'); + +-- only inherited attributes (never local ones) +SELECT attname, attislocal, attinhcount FROM pg_attribute + WHERE attrelid = 'part_a'::regclass and attnum > 0 + ORDER BY attnum; + +-- able to specify column default, column constraint, and table constraint +CREATE TABLE part_b PARTITION OF parted ( + b NOT NULL DEFAULT 1 CHECK (b >= 0), + CONSTRAINT check_a CHECK (length(a) > 0) +) FOR VALUES IN ('b'); +-- conislocal should be false for any merged constraints +SELECT conislocal, coninhcount FROM pg_constraint WHERE conrelid = 'part_b'::regclass AND conname = 'check_a'; + +-- specify PARTITION BY for a partition +CREATE TABLE fail_part_col_not_found PARTITION OF parted FOR VALUES IN ('c') PARTITION BY RANGE (c); +CREATE TABLE part_c PARTITION OF parted FOR VALUES IN ('c') PARTITION BY RANGE ((b)); + +-- create a level-2 partition +CREATE TABLE part_c_1_10 PARTITION OF part_c FOR VALUES FROM (1) TO (10); + +-- Partition bound in describe output +\d part_b + +-- Both partition bound and partition key in describe output +\d part_c + +-- Show partition count in the parent's describe output +-- Tempted to include \d+ output listing partitions with bound info but +-- output could vary depending on the order in which partition oids are +-- returned. +\d parted + +-- cleanup: avoid using CASCADE +DROP TABLE parted, part_a, part_b, part_c, part_c_1_10; +DROP TABLE list_parted, part_1, part_2, part_null; +DROP TABLE range_parted; +DROP TABLE list_parted2, part_ab, part_null_z; +DROP TABLE range_parted2, part0, part1, part2, part3; +DROP TABLE range_parted3, part00, part10, part11, part12; diff --git a/src/test/regress/sql/create_table_like.sql b/src/test/regress/sql/create_table_like.sql index 6dded1fdef..900ca804cb 100644 --- a/src/test/regress/sql/create_table_like.sql +++ b/src/test/regress/sql/create_table_like.sql @@ -131,4 +131,7 @@ CREATE TABLE like_test3 (z INTEGER, LIKE has_oid, LIKE no_oid); SELECT oid FROM like_test3; CREATE TABLE like_test4 (z INTEGER, PRIMARY KEY(oid), LIKE has_oid); SELECT oid FROM like_test4; -DROP TABLE has_oid, no_oid, like_test, like_test2, like_test3, like_test4; +CREATE TABLE like_test5 (z INTEGER, LIKE no_oid) WITH OIDS; +SELECT oid FROM like_test5; +DROP TABLE has_oid, no_oid, like_test, like_test2, like_test3, + like_test4, like_test5; diff --git a/src/test/regress/sql/create_view.sql b/src/test/regress/sql/create_view.sql index 8bed5a53b3..5fe8b94aae 100644 --- a/src/test/regress/sql/create_view.sql +++ b/src/test/regress/sql/create_view.sql @@ -224,6 +224,19 @@ SELECT relname, relkind, reloptions FROM pg_class 'mysecview3'::regclass, 'mysecview4'::regclass) ORDER BY relname; +-- This test checks that proper typmods are assigned in a multi-row VALUES + +CREATE VIEW tt1 AS + SELECT * FROM ( + VALUES + ('abc'::varchar(3), '0123456789', 42, 'abcd'::varchar(4)), + ('0123456789', 'abc'::varchar(3), 42.12, 'abc'::varchar(4)) + ) vv(a,b,c,d); +\d+ tt1 +SELECT * FROM tt1; +SELECT a::varchar(3) FROM tt1; +DROP VIEW tt1; + -- Test view decompilation in the face of relation renaming conflicts CREATE TABLE tt1 (f1 int, f2 int, f3 text); diff --git a/src/test/regress/sql/date.sql b/src/test/regress/sql/date.sql index 4553fd1c97..22f80f2ee2 100644 --- a/src/test/regress/sql/date.sql +++ b/src/test/regress/sql/date.sql @@ -338,11 +338,11 @@ SELECT EXTRACT(UNDEFINED FROM DATE 'infinity'); -- ERROR: timestamp units " -- test constructors select make_date(2013, 7, 15); +select make_date(-44, 3, 15); select make_time(8, 20, 0.0); -- should fail select make_date(2013, 2, 30); select make_date(2013, 13, 1); select make_date(2013, 11, -1); -select make_date(-44, 3, 15); -- perhaps we should allow this sometime? select make_time(10, 55, 100.1); select make_time(24, 0, 2.1); diff --git a/src/test/regress/sql/enum.sql b/src/test/regress/sql/enum.sql index 88a835e8aa..d7e87143a0 100644 --- a/src/test/regress/sql/enum.sql +++ b/src/test/regress/sql/enum.sql @@ -257,31 +257,58 @@ CREATE TYPE bogus AS ENUM('good', 'bad', 'ugly'); CREATE TABLE enumtest_bogus_child(parent bogus REFERENCES enumtest_parent); DROP TYPE bogus; +-- check renaming a value +ALTER TYPE rainbow RENAME VALUE 'red' TO 'crimson'; +SELECT enumlabel, enumsortorder +FROM pg_enum +WHERE enumtypid = 'rainbow'::regtype +ORDER BY 2; +-- check that renaming a non-existent value fails +ALTER TYPE rainbow RENAME VALUE 'red' TO 'crimson'; +-- check that renaming to an existent value fails +ALTER TYPE rainbow RENAME VALUE 'blue' TO 'green'; + -- -- check transactional behaviour of ALTER TYPE ... ADD VALUE -- CREATE TYPE bogus AS ENUM('good'); --- check that we can't add new values to existing enums in a transaction +-- check that we can add new values to existing enums in a transaction +-- but we can't use them BEGIN; -ALTER TYPE bogus ADD VALUE 'bad'; +ALTER TYPE bogus ADD VALUE 'new'; +SAVEPOINT x; +SELECT 'new'::bogus; -- unsafe +ROLLBACK TO x; +SELECT enum_first(null::bogus); -- safe +SELECT enum_last(null::bogus); -- unsafe +ROLLBACK TO x; +SELECT enum_range(null::bogus); -- unsafe +ROLLBACK TO x; COMMIT; +SELECT 'new'::bogus; -- now safe +SELECT enumlabel, enumsortorder +FROM pg_enum +WHERE enumtypid = 'bogus'::regtype +ORDER BY 2; -- check that we recognize the case where the enum already existed but was --- modified in the current txn +-- modified in the current txn; this should not be considered safe BEGIN; ALTER TYPE bogus RENAME TO bogon; ALTER TYPE bogon ADD VALUE 'bad'; +SELECT 'bad'::bogon; ROLLBACK; DROP TYPE bogus; --- check that we *can* add new values to existing enums in a transaction, --- if the type is new as well +-- check that we can add new values to existing enums in a transaction +-- and use them, if the type is new as well BEGIN; -CREATE TYPE bogus AS ENUM(); -ALTER TYPE bogus ADD VALUE 'good'; +CREATE TYPE bogus AS ENUM('good'); +ALTER TYPE bogus ADD VALUE 'bad'; ALTER TYPE bogus ADD VALUE 'ugly'; +SELECT enum_range(null::bogus); ROLLBACK; -- diff --git a/src/test/regress/sql/equivclass.sql b/src/test/regress/sql/equivclass.sql index 17fad673e9..0e4aa0cd2c 100644 --- a/src/test/regress/sql/equivclass.sql +++ b/src/test/regress/sql/equivclass.sql @@ -222,3 +222,35 @@ explain (costs off) union all select ff + 4 as x from ec1) as ss1 where ss1.x = ec1.f1 and ec1.ff = 42::int8; + +-- check effects of row-level security +set enable_nestloop = on; +set enable_mergejoin = off; + +alter table ec1 enable row level security; +create policy p1 on ec1 using (f1 < '5'::int8alias1); + +create user regress_user_ectest; +grant select on ec0 to regress_user_ectest; +grant select on ec1 to regress_user_ectest; + +-- without any RLS, we'll treat {a.ff, b.ff, 43} as an EquivalenceClass +explain (costs off) + select * from ec0 a, ec1 b + where a.ff = b.ff and a.ff = 43::bigint::int8alias1; + +set session authorization regress_user_ectest; + +-- with RLS active, the non-leakproof a.ff = 43 clause is not treated +-- as a suitable source for an EquivalenceClass; currently, this is true +-- even though the RLS clause has nothing to do directly with the EC +explain (costs off) + select * from ec0 a, ec1 b + where a.ff = b.ff and a.ff = 43::bigint::int8alias1; + +reset session authorization; + +revoke select on ec0 from regress_user_ectest; +revoke select on ec1 from regress_user_ectest; + +drop user regress_user_ectest; diff --git a/src/test/regress/sql/foreign_key.sql b/src/test/regress/sql/foreign_key.sql index 85c9d04d64..5f19dad03c 100644 --- a/src/test/regress/sql/foreign_key.sql +++ b/src/test/regress/sql/foreign_key.sql @@ -1019,3 +1019,39 @@ create rule r1 as on delete to t1 do delete from t2 where t2.b = old.a; explain (costs off) delete from t1 where a = 1; delete from t1 where a = 1; + +-- +-- Test deferred FK check on a tuple deleted by a rolled-back subtransaction +-- +create table pktable2(f1 int primary key); +create table fktable2(f1 int references pktable2 deferrable initially deferred); +insert into pktable2 values(1); + +begin; +insert into fktable2 values(1); +savepoint x; +delete from fktable2; +rollback to x; +commit; + +begin; +insert into fktable2 values(2); +savepoint x; +delete from fktable2; +rollback to x; +commit; -- fail + +-- +-- Test that we prevent dropping FK constraint with pending trigger events +-- +begin; +insert into fktable2 values(2); +alter table fktable2 drop constraint fktable2_f1_fkey; +commit; + +begin; +delete from pktable2 where f1 = 1; +alter table fktable2 drop constraint fktable2_f1_fkey; +commit; + +drop table pktable2, fktable2; diff --git a/src/test/regress/sql/hash_index.sql b/src/test/regress/sql/hash_index.sql index 411e8aed39..15a3b06d17 100644 --- a/src/test/regress/sql/hash_index.sql +++ b/src/test/regress/sql/hash_index.sql @@ -151,3 +151,46 @@ SELECT h.seqno AS f20000 -- SELECT count(*) AS i988 FROM hash_ovfl_heap -- WHERE x = 1000; + +-- +-- Cause some overflow insert and splits. +-- +CREATE TABLE hash_split_heap (keycol INT); +CREATE INDEX hash_split_index on hash_split_heap USING HASH (keycol); +INSERT INTO hash_split_heap SELECT 1 FROM generate_series(1, 70000) a; + +VACUUM FULL hash_split_heap; + +-- Let's do a backward scan. +BEGIN; +SET enable_seqscan = OFF; +SET enable_bitmapscan = OFF; + +DECLARE c CURSOR FOR SELECT * from hash_split_heap WHERE keycol = 1; +MOVE FORWARD ALL FROM c; +MOVE BACKWARD 10000 FROM c; +MOVE BACKWARD ALL FROM c; +CLOSE c; +END; + +-- DELETE, INSERT, REBUILD INDEX. +DELETE FROM hash_split_heap WHERE keycol = 1; +INSERT INTO hash_split_heap SELECT a/2 FROM generate_series(1, 50000) a; + +VACUUM hash_split_heap; +REINDEX INDEX hash_split_index; + +-- Clean up. +DROP TABLE hash_split_heap; + +-- Index on temp table. +CREATE TEMP TABLE hash_temp_heap (x int, y int); +INSERT INTO hash_temp_heap VALUES (1,1); +CREATE INDEX hash_idx ON hash_temp_heap USING hash (x); +DROP TABLE hash_temp_heap CASCADE; + +-- Float4 type. +CREATE TABLE hash_heap_float4 (x float4, y int); +INSERT INTO hash_heap_float4 VALUES (1.1,1); +CREATE INDEX hash_idx ON hash_heap_float4 USING hash (x); +DROP TABLE hash_heap_float4 CASCADE; diff --git a/src/test/regress/sql/horology.sql b/src/test/regress/sql/horology.sql index c81437ba35..a7bc9dcfc4 100644 --- a/src/test/regress/sql/horology.sql +++ b/src/test/regress/sql/horology.sql @@ -412,6 +412,9 @@ SELECT to_timestamp('19971116', 'YYYYMMDD'); SELECT to_timestamp('20000-1116', 'YYYY-MMDD'); +SELECT to_timestamp('1997 AD 11 16', 'YYYY BC MM DD'); +SELECT to_timestamp('1997 BC 11 16', 'YYYY BC MM DD'); + SELECT to_timestamp('9-1116', 'Y-MMDD'); SELECT to_timestamp('95-1116', 'YY-MMDD'); @@ -440,6 +443,9 @@ SELECT to_timestamp(' 2005 03 02', 'YYYYMMDD'); SELECT to_timestamp(' 20050302', 'YYYYMMDD'); +SELECT to_timestamp('2011-12-18 11:38 AM', 'YYYY-MM-DD HH12:MI PM'); +SELECT to_timestamp('2011-12-18 11:38 PM', 'YYYY-MM-DD HH12:MI PM'); + -- -- Check handling of multiple spaces in format and/or input -- @@ -461,7 +467,7 @@ SELECT to_date('2011 12 18', 'YYYY MM DD'); SELECT to_date('2011 12 18', 'YYYY MM DD'); -- --- Check errors for some incorrect usages of to_timestamp() +-- Check errors for some incorrect usages of to_timestamp() and to_date() -- -- Mixture of date conventions (ISO week and Gregorian): @@ -482,6 +488,28 @@ SELECT to_timestamp('199711xy', 'YYYYMMDD'); -- Input that doesn't fit in an int: SELECT to_timestamp('10000000000', 'FMYYYY'); +-- Out-of-range and not-quite-out-of-range fields: +SELECT to_timestamp('2016-06-13 25:00:00', 'YYYY-MM-DD HH24:MI:SS'); +SELECT to_timestamp('2016-06-13 15:60:00', 'YYYY-MM-DD HH24:MI:SS'); +SELECT to_timestamp('2016-06-13 15:50:60', 'YYYY-MM-DD HH24:MI:SS'); +SELECT to_timestamp('2016-06-13 15:50:55', 'YYYY-MM-DD HH24:MI:SS'); -- ok +SELECT to_timestamp('2016-06-13 15:50:55', 'YYYY-MM-DD HH:MI:SS'); +SELECT to_timestamp('2016-13-01 15:50:55', 'YYYY-MM-DD HH24:MI:SS'); +SELECT to_timestamp('2016-02-30 15:50:55', 'YYYY-MM-DD HH24:MI:SS'); +SELECT to_timestamp('2016-02-29 15:50:55', 'YYYY-MM-DD HH24:MI:SS'); -- ok +SELECT to_timestamp('2015-02-29 15:50:55', 'YYYY-MM-DD HH24:MI:SS'); +SELECT to_timestamp('2015-02-11 86000', 'YYYY-MM-DD SSSS'); -- ok +SELECT to_timestamp('2015-02-11 86400', 'YYYY-MM-DD SSSS'); +SELECT to_date('2016-13-10', 'YYYY-MM-DD'); +SELECT to_date('2016-02-30', 'YYYY-MM-DD'); +SELECT to_date('2016-02-29', 'YYYY-MM-DD'); -- ok +SELECT to_date('2015-02-29', 'YYYY-MM-DD'); +SELECT to_date('2015 365', 'YYYY DDD'); -- ok +SELECT to_date('2015 366', 'YYYY DDD'); +SELECT to_date('2016 365', 'YYYY DDD'); -- ok +SELECT to_date('2016 366', 'YYYY DDD'); -- ok +SELECT to_date('2016 367', 'YYYY DDD'); + -- -- Check behavior with SQL-style fixed-GMT-offset time zone (cf bug #8572) -- diff --git a/src/test/regress/sql/hs_standby_allowed.sql b/src/test/regress/sql/hs_standby_allowed.sql index 7fc22148cb..a33199dbbd 100644 --- a/src/test/regress/sql/hs_standby_allowed.sql +++ b/src/test/regress/sql/hs_standby_allowed.sql @@ -16,7 +16,7 @@ COPY hs1 TO '/tmp/copy_test'; \! cat /tmp/copy_test -- Access sequence directly -select min_value as sequence_min_value from hsseq; +select is_called from hsseq; -- Transactions diff --git a/src/test/regress/sql/inet.sql b/src/test/regress/sql/inet.sql index 007741e935..880e115360 100644 --- a/src/test/regress/sql/inet.sql +++ b/src/test/regress/sql/inet.sql @@ -93,6 +93,29 @@ SELECT i FROM inet_tbl WHERE i << '192.168.1.0/24'::cidr ORDER BY i; SET enable_seqscan TO on; DROP INDEX inet_idx2; +-- check that spgist index works correctly +CREATE INDEX inet_idx3 ON inet_tbl using spgist (i); +SET enable_seqscan TO off; +SELECT * FROM inet_tbl WHERE i << '192.168.1.0/24'::cidr ORDER BY i; +SELECT * FROM inet_tbl WHERE i <<= '192.168.1.0/24'::cidr ORDER BY i; +SELECT * FROM inet_tbl WHERE i && '192.168.1.0/24'::cidr ORDER BY i; +SELECT * FROM inet_tbl WHERE i >>= '192.168.1.0/24'::cidr ORDER BY i; +SELECT * FROM inet_tbl WHERE i >> '192.168.1.0/24'::cidr ORDER BY i; +SELECT * FROM inet_tbl WHERE i < '192.168.1.0/24'::cidr ORDER BY i; +SELECT * FROM inet_tbl WHERE i <= '192.168.1.0/24'::cidr ORDER BY i; +SELECT * FROM inet_tbl WHERE i = '192.168.1.0/24'::cidr ORDER BY i; +SELECT * FROM inet_tbl WHERE i >= '192.168.1.0/24'::cidr ORDER BY i; +SELECT * FROM inet_tbl WHERE i > '192.168.1.0/24'::cidr ORDER BY i; +SELECT * FROM inet_tbl WHERE i <> '192.168.1.0/24'::cidr ORDER BY i; + +-- test index-only scans +EXPLAIN (COSTS OFF) +SELECT i FROM inet_tbl WHERE i << '192.168.1.0/24'::cidr ORDER BY i; +SELECT i FROM inet_tbl WHERE i << '192.168.1.0/24'::cidr ORDER BY i; + +SET enable_seqscan TO on; +DROP INDEX inet_idx3; + -- simple tests of inet boolean and arithmetic operators SELECT i, ~i AS "~i" FROM inet_tbl; SELECT i, c, i & c AS "and" FROM inet_tbl; diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql index b307a5049b..a8b7eb1c8d 100644 --- a/src/test/regress/sql/inherit.sql +++ b/src/test/regress/sql/inherit.sql @@ -145,6 +145,32 @@ insert into d values('test','one','two','three'); alter table a alter column aa type integer using bit_length(aa); select * from d; +-- check that oid column is handled properly during alter table inherit +create table oid_parent (a int) with oids; + +create table oid_child () inherits (oid_parent); +select attinhcount, attislocal from pg_attribute + where attrelid = 'oid_child'::regclass and attname = 'oid'; +drop table oid_child; + +create table oid_child (a int) without oids; +alter table oid_child inherit oid_parent; -- fail +alter table oid_child set with oids; +select attinhcount, attislocal from pg_attribute + where attrelid = 'oid_child'::regclass and attname = 'oid'; +alter table oid_child inherit oid_parent; +select attinhcount, attislocal from pg_attribute + where attrelid = 'oid_child'::regclass and attname = 'oid'; +alter table oid_child set without oids; -- fail +alter table oid_parent set without oids; +select attinhcount, attislocal from pg_attribute + where attrelid = 'oid_child'::regclass and attname = 'oid'; +alter table oid_child set without oids; +select attinhcount, attislocal from pg_attribute + where attrelid = 'oid_child'::regclass and attname = 'oid'; + +drop table oid_parent cascade; + -- Test non-inheritable parent constraints create table p1(ff1 int); alter table p1 add constraint p1chk check (ff1 > 0) no inherit; @@ -157,6 +183,9 @@ create table c1 () inherits (p1); \d p1 \d c1 +-- Test that child does not override inheritable constraints of the parent +create table c2 (constraint p2chk check (ff1 > 10) no inherit) inherits (p1); --fails + drop table p1 cascade; -- Tests for casting between the rowtypes of parent and child @@ -334,6 +363,45 @@ DROP TABLE test_foreign_constraints_inh; DROP TABLE test_foreign_constraints; DROP TABLE test_primary_constraints; +-- Test that parent and child CHECK constraints can be created in either order +create table p1(f1 int); +create table p1_c1() inherits(p1); + +alter table p1 add constraint inh_check_constraint1 check (f1 > 0); +alter table p1_c1 add constraint inh_check_constraint1 check (f1 > 0); + +alter table p1_c1 add constraint inh_check_constraint2 check (f1 < 10); +alter table p1 add constraint inh_check_constraint2 check (f1 < 10); + +select conrelid::regclass::text as relname, conname, conislocal, coninhcount +from pg_constraint where conname like 'inh\_check\_constraint%' +order by 1, 2; + +drop table p1 cascade; + +-- Test that a valid child can have not-valid parent, but not vice versa +create table invalid_check_con(f1 int); +create table invalid_check_con_child() inherits(invalid_check_con); + +alter table invalid_check_con_child add constraint inh_check_constraint check(f1 > 0) not valid; +alter table invalid_check_con add constraint inh_check_constraint check(f1 > 0); -- fail +alter table invalid_check_con_child drop constraint inh_check_constraint; + +insert into invalid_check_con values(0); + +alter table invalid_check_con_child add constraint inh_check_constraint check(f1 > 0); +alter table invalid_check_con add constraint inh_check_constraint check(f1 > 0) not valid; + +insert into invalid_check_con values(0); -- fail +insert into invalid_check_con_child values(0); -- fail + +select conrelid::regclass::text as relname, conname, + convalidated, conislocal, coninhcount, connoinherit +from pg_constraint where conname like 'inh\_check\_constraint%' +order by 1, 2; + +-- We don't drop the invalid_check_con* tables, to test dump/reload with + -- -- Test parameterized append plans for inheritance trees -- @@ -494,3 +562,55 @@ FROM generate_series(1, 3) g(i); reset enable_seqscan; reset enable_indexscan; reset enable_bitmapscan; + +-- +-- Check that constraint exclusion works correctly with partitions using +-- implicit constraints generated from the partition bound information. +-- +create table list_parted ( + a varchar +) partition by list (a); +create table part_ab_cd partition of list_parted for values in ('ab', 'cd'); +create table part_ef_gh partition of list_parted for values in ('ef', 'gh'); +create table part_null_xy partition of list_parted for values in (null, 'xy'); + +explain (costs off) select * from list_parted; +explain (costs off) select * from list_parted where a is null; +explain (costs off) select * from list_parted where a is not null; +explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef'); +explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd'); +explain (costs off) select * from list_parted where a = 'ab'; + +create table range_list_parted ( + a int, + b char(2) +) partition by range (a); +create table part_1_10 partition of range_list_parted for values from (1) to (10) partition by list (b); +create table part_1_10_ab partition of part_1_10 for values in ('ab'); +create table part_1_10_cd partition of part_1_10 for values in ('cd'); +create table part_10_20 partition of range_list_parted for values from (10) to (20) partition by list (b); +create table part_10_20_ab partition of part_10_20 for values in ('ab'); +create table part_10_20_cd partition of part_10_20 for values in ('cd'); +create table part_21_30 partition of range_list_parted for values from (21) to (30) partition by list (b); +create table part_21_30_ab partition of part_21_30 for values in ('ab'); +create table part_21_30_cd partition of part_21_30 for values in ('cd'); +create table part_40_inf partition of range_list_parted for values from (40) to (unbounded) partition by list (b); +create table part_40_inf_ab partition of part_40_inf for values in ('ab'); +create table part_40_inf_cd partition of part_40_inf for values in ('cd'); +create table part_40_inf_null partition of part_40_inf for values in (null); + +explain (costs off) select * from range_list_parted; +explain (costs off) select * from range_list_parted where a = 5; +explain (costs off) select * from range_list_parted where b = 'ab'; +explain (costs off) select * from range_list_parted where a between 3 and 23 and b in ('ab'); + +/* Should select no rows because range partition key cannot be null */ +explain (costs off) select * from range_list_parted where a is null; + +/* Should only select rows from the null-accepting partition */ +explain (costs off) select * from range_list_parted where b is null; +explain (costs off) select * from range_list_parted where a is not null and a < 67; +explain (costs off) select * from range_list_parted where a >= 30; + +drop table list_parted cascade; +drop table range_list_parted cascade; diff --git a/src/test/regress/sql/insert.sql b/src/test/regress/sql/insert.sql index 7924d5d46d..3d5138a8e0 100644 --- a/src/test/regress/sql/insert.sql +++ b/src/test/regress/sql/insert.sql @@ -84,3 +84,161 @@ create rule irule3 as on insert to inserttest2 do also drop table inserttest2; drop table inserttest; drop type insert_test_type; + +-- direct partition inserts should check partition bound constraint +create table range_parted ( + a text, + b int +) partition by range (a, (b+0)); +create table part1 partition of range_parted for values from ('a', 1) to ('a', 10); +create table part2 partition of range_parted for values from ('a', 10) to ('a', 20); +create table part3 partition of range_parted for values from ('b', 1) to ('b', 10); +create table part4 partition of range_parted for values from ('b', 10) to ('b', 20); + +-- fail +insert into part1 values ('a', 11); +insert into part1 values ('b', 1); +-- ok +insert into part1 values ('a', 1); +-- fail +insert into part4 values ('b', 21); +insert into part4 values ('a', 10); +-- ok +insert into part4 values ('b', 10); + +-- fail (partition key a has a NOT NULL constraint) +insert into part1 values (null); +-- fail (expression key (b+0) cannot be null either) +insert into part1 values (1); + +create table list_parted ( + a text, + b int +) partition by list (lower(a)); +create table part_aa_bb partition of list_parted FOR VALUES IN ('aa', 'bb'); +create table part_cc_dd partition of list_parted FOR VALUES IN ('cc', 'dd'); +create table part_null partition of list_parted FOR VALUES IN (null); + +-- fail +insert into part_aa_bb values ('cc', 1); +insert into part_aa_bb values ('AAa', 1); +insert into part_aa_bb values (null); +-- ok +insert into part_cc_dd values ('cC', 1); +insert into part_null values (null, 0); + +-- check in case of multi-level partitioned table +create table part_ee_ff partition of list_parted for values in ('ee', 'ff') partition by range (b); +create table part_ee_ff1 partition of part_ee_ff for values from (1) to (10); +create table part_ee_ff2 partition of part_ee_ff for values from (10) to (20); + +-- fail +insert into part_ee_ff1 values ('EE', 11); +-- fail (even the parent's, ie, part_ee_ff's partition constraint applies) +insert into part_ee_ff1 values ('cc', 1); +-- ok +insert into part_ee_ff1 values ('ff', 1); +insert into part_ee_ff2 values ('ff', 11); + +-- Check tuple routing for partitioned tables + +-- fail +insert into range_parted values ('a', 0); +-- ok +insert into range_parted values ('a', 1); +insert into range_parted values ('a', 10); +-- fail +insert into range_parted values ('a', 20); +-- ok +insert into range_parted values ('b', 1); +insert into range_parted values ('b', 10); +-- fail (partition key (b+0) is null) +insert into range_parted values ('a'); +select tableoid::regclass, * from range_parted; + +-- ok +insert into list_parted values (null, 1); +insert into list_parted (a) values ('aA'); +-- fail (partition of part_ee_ff not found in both cases) +insert into list_parted values ('EE', 0); +insert into part_ee_ff values ('EE', 0); +-- ok +insert into list_parted values ('EE', 1); +insert into part_ee_ff values ('EE', 10); +select tableoid::regclass, * from list_parted; + +-- some more tests to exercise tuple-routing with multi-level partitioning +create table part_gg partition of list_parted for values in ('gg') partition by range (b); +create table part_gg1 partition of part_gg for values from (unbounded) to (1); +create table part_gg2 partition of part_gg for values from (1) to (10) partition by range (b); +create table part_gg2_1 partition of part_gg2 for values from (1) to (5); +create table part_gg2_2 partition of part_gg2 for values from (5) to (10); + +create table part_ee_ff3 partition of part_ee_ff for values from (20) to (30) partition by range (b); +create table part_ee_ff3_1 partition of part_ee_ff3 for values from (20) to (25); +create table part_ee_ff3_2 partition of part_ee_ff3 for values from (25) to (30); + +truncate list_parted; +insert into list_parted values ('aa'), ('cc'); +insert into list_parted select 'Ff', s.a from generate_series(1, 29) s(a); +insert into list_parted select 'gg', s.a from generate_series(1, 9) s(a); +insert into list_parted (b) values (1); +select tableoid::regclass::text, a, min(b) as min_b, max(b) as max_b from list_parted group by 1, 2 order by 1; + +-- cleanup +drop table part1, part2, part3, part4, range_parted; +drop table part_ee_ff3_1, part_ee_ff3_2, part_ee_ff1, part_ee_ff2, part_ee_ff3; +drop table part_ee_ff, part_gg2_2, part_gg2_1, part_gg2, part_gg1, part_gg; +drop table part_aa_bb, part_cc_dd, part_null, list_parted; + +-- more tests for certain multi-level partitioning scenarios +create table p (a int, b int) partition by range (a, b); +create table p1 (b int, a int not null) partition by range (b); +create table p11 (like p1); +alter table p11 drop a; +alter table p11 add a int; +alter table p11 drop a; +alter table p11 add a int not null; +-- attnum for key attribute 'a' is different in p, p1, and p11 +select attrelid::regclass, attname, attnum +from pg_attribute +where attname = 'a' + and (attrelid = 'p'::regclass + or attrelid = 'p1'::regclass + or attrelid = 'p11'::regclass) +order by attrelid::regclass::text; + +alter table p1 attach partition p11 for values from (2) to (5); +alter table p attach partition p1 for values from (1, 2) to (1, 10); + +-- check that "(1, 2)" is correctly routed to p11. +insert into p values (1, 2); +select tableoid::regclass, * from p; + +truncate p; +alter table p add constraint check_b check (b = 3); +-- check that correct input row is shown when constraint check_b fails on p11 +-- after "(1, 2)" is routed to it +insert into p values (1, 2); + +-- check that inserting into an internal partition successfully results in +-- checking its partition constraint before inserting into the leaf partition +-- selected by tuple-routing +insert into p1 (a, b) values (2, 3); + +-- check that RETURNING works correctly with tuple-routing +alter table p drop constraint check_b; +create table p12 partition of p1 for values from (5) to (10); +create table p2 (b int not null, a int not null); +alter table p attach partition p2 for values from (1, 10) to (1, 20); +create table p3 partition of p for values from (1, 20) to (1, 30); +create table p4 (like p); +alter table p4 drop a; +alter table p4 add a int not null; +alter table p attach partition p4 for values from (1, 30) to (1, 40); +with ins (a, b, c) as + (insert into p (b, a) select s.a, 1 from generate_series(2, 39) s(a) returning tableoid::regclass, *) + select a, b, min(c), max(c) from ins group by a, b order by 1; + +-- cleanup +drop table p, p1, p11, p12, p2, p3, p4; diff --git a/src/test/regress/sql/insert_conflict.sql b/src/test/regress/sql/insert_conflict.sql index 190c605562..116cf763f9 100644 --- a/src/test/regress/sql/insert_conflict.sql +++ b/src/test/regress/sql/insert_conflict.sql @@ -283,6 +283,24 @@ on conflict (b) where coalesce(a, 1) > 1 do nothing; drop table insertconflict; +-- +-- test insertion through view +-- + +create table insertconflict (f1 int primary key, f2 text); +create view insertconflictv as + select * from insertconflict with cascaded check option; + +insert into insertconflictv values (1,'foo') + on conflict (f1) do update set f2 = excluded.f2; +select * from insertconflict; +insert into insertconflictv values (1,'bar') + on conflict (f1) do update set f2 = excluded.f2; +select * from insertconflict; + +drop view insertconflictv; +drop table insertconflict; + -- ****************************************************************** -- * * @@ -421,3 +439,35 @@ insert into twoconstraints values(2, '((0,0),(1,2))') on conflict on constraint twoconstraints_f2_excl do nothing; -- do nothing select * from twoconstraints; drop table twoconstraints; + +-- check handling of self-conflicts at various isolation levels + +create table selfconflict (f1 int primary key, f2 int); + +begin transaction isolation level read committed; +insert into selfconflict values (1,1), (1,2) on conflict do nothing; +commit; + +begin transaction isolation level repeatable read; +insert into selfconflict values (2,1), (2,2) on conflict do nothing; +commit; + +begin transaction isolation level serializable; +insert into selfconflict values (3,1), (3,2) on conflict do nothing; +commit; + +begin transaction isolation level read committed; +insert into selfconflict values (4,1), (4,2) on conflict(f1) do update set f2 = 0; +commit; + +begin transaction isolation level repeatable read; +insert into selfconflict values (5,1), (5,2) on conflict(f1) do update set f2 = 0; +commit; + +begin transaction isolation level serializable; +insert into selfconflict values (6,1), (6,2) on conflict(f1) do update set f2 = 0; +commit; + +select * from selfconflict; + +drop table selfconflict; diff --git a/src/test/regress/sql/interval.sql b/src/test/regress/sql/interval.sql index 789c3de440..cff9adab32 100644 --- a/src/test/regress/sql/interval.sql +++ b/src/test/regress/sql/interval.sql @@ -196,6 +196,11 @@ SELECT interval '1 2.3456' minute to second(2); SELECT interval '1 2:03.5678' minute to second(2); SELECT interval '1 2:03:04.5678' minute to second(2); +-- test casting to restricted precision (bug #14479) +SELECT f1, f1::INTERVAL DAY TO MINUTE AS "minutes", + (f1 + INTERVAL '1 month')::INTERVAL MONTH::INTERVAL YEAR AS "years" + FROM interval_tbl; + -- test inputting and outputting SQL standard interval literals SET IntervalStyle TO sql_standard; SELECT interval '0' AS "zero", diff --git a/src/test/regress/sql/jsonb.sql b/src/test/regress/sql/jsonb.sql index b84bd70a29..eb65a38197 100644 --- a/src/test/regress/sql/jsonb.sql +++ b/src/test/regress/sql/jsonb.sql @@ -777,6 +777,10 @@ select '["a","b","c"]'::jsonb - -2; select '["a","b","c"]'::jsonb - -3; select '["a","b","c"]'::jsonb - -4; +select '{"a":1 , "b":2, "c":3}'::jsonb - '{b}'::text[]; +select '{"a":1 , "b":2, "c":3}'::jsonb - '{c,b}'::text[]; +select '{"a":1 , "b":2, "c":3}'::jsonb - '{}'::text[]; + select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb, '{n}', '[1,2,3]'); select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb, '{b,-1}', '[1,2,3]'); select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb, '{d,1,0}', '[1,2,3]'); @@ -814,6 +818,7 @@ select '[]'::jsonb #- '{a}'; select jsonb_set('"a"','{a}','"b"'); --error select jsonb_set('{}','{a}','"b"', false); select jsonb_set('[]','{1}','"b"', false); +select jsonb_set('[{"f1":1,"f2":null},2,null,3]', '{0}','[2,3,4]', false); -- jsonb_set adding instead of replacing diff --git a/src/test/regress/sql/matview.sql b/src/test/regress/sql/matview.sql index 5f3269def8..65a743ced9 100644 --- a/src/test/regress/sql/matview.sql +++ b/src/test/regress/sql/matview.sql @@ -16,11 +16,11 @@ EXPLAIN (costs off) CREATE MATERIALIZED VIEW mvtest_tm AS SELECT type, sum(amt) AS totamt FROM mvtest_t GROUP BY type WITH NO DATA; CREATE MATERIALIZED VIEW mvtest_tm AS SELECT type, sum(amt) AS totamt FROM mvtest_t GROUP BY type WITH NO DATA; SELECT relispopulated FROM pg_class WHERE oid = 'mvtest_tm'::regclass; -SELECT * FROM mvtest_tm; +SELECT * FROM mvtest_tm ORDER BY type; REFRESH MATERIALIZED VIEW mvtest_tm; SELECT relispopulated FROM pg_class WHERE oid = 'mvtest_tm'::regclass; CREATE UNIQUE INDEX mvtest_tm_type ON mvtest_tm (type); -SELECT * FROM mvtest_tm; +SELECT * FROM mvtest_tm ORDER BY type; -- create various views EXPLAIN (costs off) diff --git a/src/test/regress/sql/money.sql b/src/test/regress/sql/money.sql index 09b9476b70..f5a92f2a69 100644 --- a/src/test/regress/sql/money.sql +++ b/src/test/regress/sql/money.sql @@ -9,8 +9,22 @@ SELECT * FROM money_data; SELECT m + '123' FROM money_data; SELECT m + '123.45' FROM money_data; SELECT m - '123.45' FROM money_data; +SELECT m / '2'::money FROM money_data; SELECT m * 2 FROM money_data; +SELECT 2 * m FROM money_data; SELECT m / 2 FROM money_data; +SELECT m * 2::int2 FROM money_data; +SELECT 2::int2 * m FROM money_data; +SELECT m / 2::int2 FROM money_data; +SELECT m * 2::int8 FROM money_data; +SELECT 2::int8 * m FROM money_data; +SELECT m / 2::int8 FROM money_data; +SELECT m * 2::float8 FROM money_data; +SELECT 2::float8 * m FROM money_data; +SELECT m / 2::float8 FROM money_data; +SELECT m * 2::float4 FROM money_data; +SELECT 2::float4 * m FROM money_data; +SELECT m / 2::float4 FROM money_data; -- All true SELECT m = '$123.00' FROM money_data; @@ -57,17 +71,45 @@ DELETE FROM money_data; INSERT INTO money_data VALUES ('$123.459'); SELECT * FROM money_data; --- Cast int4/int8 to money +-- input checks +SELECT '1234567890'::money; +SELECT '12345678901234567'::money; +SELECT '123456789012345678'::money; +SELECT '9223372036854775807'::money; +SELECT '-12345'::money; +SELECT '-1234567890'::money; +SELECT '-12345678901234567'::money; +SELECT '-123456789012345678'::money; +SELECT '-9223372036854775808'::money; + +-- special characters +SELECT '(1)'::money; +SELECT '($123,456.78)'::money; + +-- documented minimums and maximums +SELECT '-92233720368547758.08'::money; +SELECT '92233720368547758.07'::money; + +SELECT '-92233720368547758.09'::money; +SELECT '92233720368547758.08'::money; + +-- rounding +SELECT '-92233720368547758.085'::money; +SELECT '92233720368547758.075'::money; + +-- Cast int4/int8/numeric to money SELECT 1234567890::money; SELECT 12345678901234567::money; -SELECT 123456789012345678::money; -SELECT 9223372036854775807::money; SELECT (-12345)::money; SELECT (-1234567890)::money; SELECT (-12345678901234567)::money; -SELECT (-123456789012345678)::money; -SELECT (-9223372036854775808)::money; SELECT 1234567890::int4::money; SELECT 12345678901234567::int8::money; +SELECT 12345678901234567::numeric::money; SELECT (-1234567890)::int4::money; SELECT (-12345678901234567)::int8::money; +SELECT (-12345678901234567)::numeric::money; + +-- Cast from money +SELECT '12345678901234567'::money::numeric; +SELECT '-12345678901234567'::money::numeric; diff --git a/src/test/regress/sql/numeric.sql b/src/test/regress/sql/numeric.sql index fc472187d8..b51225c47f 100644 --- a/src/test/regress/sql/numeric.sql +++ b/src/test/regress/sql/numeric.sql @@ -997,3 +997,11 @@ select scale(1.12345); select scale(110123.12475871856128); select scale(-1123.12471856128); select scale(-13.000000000000000); + +-- +-- Tests for SUM() +-- + +-- cases that need carry propagation +SELECT SUM(9999::numeric) FROM generate_series(1, 100000); +SELECT SUM((-9999)::numeric) FROM generate_series(1, 100000); diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql index 776f2292ea..877d3ad08e 100644 --- a/src/test/regress/sql/plpgsql.sql +++ b/src/test/regress/sql/plpgsql.sql @@ -3719,6 +3719,7 @@ drop function tftest(int); create or replace function rttest() returns setof int as $$ declare rc int; + rca int[]; begin return query values(10),(20); get diagnostics rc = row_count; @@ -3727,11 +3728,12 @@ begin get diagnostics rc = row_count; raise notice '% %', found, rc; return query execute 'values(10),(20)'; - get diagnostics rc = row_count; - raise notice '% %', found, rc; + -- just for fun, let's use array elements as targets + get diagnostics rca[1] = row_count; + raise notice '% %', found, rca[1]; return query execute 'select * from (values(10),(20)) f(a) where false'; - get diagnostics rc = row_count; - raise notice '% %', found, rc; + get diagnostics rca[2] = row_count; + raise notice '% %', found, rca[2]; end; $$ language plpgsql; @@ -4428,3 +4430,48 @@ exception when others then null; -- do nothing end; $$; + +-- Test use of plpgsql in a domain check constraint (cf. bug #14414) + +create function plpgsql_domain_check(val int) returns boolean as $$ +begin return val > 0; end +$$ language plpgsql immutable; + +create domain plpgsql_domain as integer check(plpgsql_domain_check(value)); + +do $$ +declare v_test plpgsql_domain; +begin + v_test := 1; +end; +$$; + +do $$ +declare v_test plpgsql_domain := 1; +begin + v_test := 0; -- fail +end; +$$; + +-- Test handling of expanded array passed to a domain constraint (bug #14472) + +create function plpgsql_arr_domain_check(val int[]) returns boolean as $$ +begin return val[1] > 0; end +$$ language plpgsql immutable; + +create domain plpgsql_arr_domain as int[] check(plpgsql_arr_domain_check(value)); + +do $$ +declare v_test plpgsql_arr_domain; +begin + v_test := array[1]; + v_test := v_test || 2; +end; +$$; + +do $$ +declare v_test plpgsql_arr_domain := array[1]; +begin + v_test := 0 || v_test; -- fail +end; +$$; diff --git a/src/test/regress/sql/polymorphism.sql b/src/test/regress/sql/polymorphism.sql index 72f6cb5e7c..45ae7a23aa 100644 --- a/src/test/regress/sql/polymorphism.sql +++ b/src/test/regress/sql/polymorphism.sql @@ -443,6 +443,28 @@ create aggregate build_group(int8, integer) ( STYPE = int8[] ); +-- check proper resolution of data types for polymorphic transfn/finalfn + +create function first_el(anyarray) returns anyelement as +'select $1[1]' language sql strict immutable; + +create aggregate first_el_agg_f8(float8) ( + SFUNC = array_append, + STYPE = float8[], + FINALFUNC = first_el +); + +create aggregate first_el_agg_any(anyelement) ( + SFUNC = array_append, + STYPE = anyarray, + FINALFUNC = first_el +); + +select first_el_agg_f8(x::float8) from generate_series(1,10) x; +select first_el_agg_any(x) from generate_series(1,10) x; +select first_el_agg_f8(x::float8) over(order by x) from generate_series(1,10) x; +select first_el_agg_any(x) over(order by x) from generate_series(1,10) x; + -- check that we can apply functions taking ANYARRAY to pg_stats select distinct array_ndims(histogram_bounds) from pg_stats where histogram_bounds is not null; diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql index 0aa9c672d5..00dc7bd4ab 100644 --- a/src/test/regress/sql/privileges.sql +++ b/src/test/regress/sql/privileges.sql @@ -259,7 +259,7 @@ INSERT INTO atest5(two) VALUES (6) ON CONFLICT (two) DO UPDATE set three = EXCLU INSERT INTO atest5(two) VALUES (6) ON CONFLICT (two) DO UPDATE set three = EXCLUDED.three; INSERT INTO atest5(two) VALUES (6) ON CONFLICT (two) DO UPDATE set one = 8; -- fails (due to UPDATE) INSERT INTO atest5(three) VALUES (4) ON CONFLICT (two) DO UPDATE set three = 10; -- fails (due to INSERT) --- Check that the the columns in the inference require select privileges +-- Check that the columns in the inference require select privileges -- Error. No privs on four INSERT INTO atest5(three) VALUES (4) ON CONFLICT (four) DO UPDATE set three = 10; diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql index 4dc0745f1d..900aa7ee1e 100644 --- a/src/test/regress/sql/psql.sql +++ b/src/test/regress/sql/psql.sql @@ -67,7 +67,7 @@ select 'drop table gexec_test', 'select ''2000-01-01''::date as party_over' prepare q as select array_to_string(array_agg(repeat('x',2*n)),E'\n') as "ab c", array_to_string(array_agg(repeat('y',20-2*n)),E'\n') as "a -bc" from generate_series(1,10) as n(n) group by n>1 ; +bc" from generate_series(1,10) as n(n) group by n>1 order by n>1; \pset linestyle ascii diff --git a/src/test/regress/sql/psql_crosstab.sql b/src/test/regress/sql/psql_crosstab.sql index 1237e82f2d..5a4511389d 100644 --- a/src/test/regress/sql/psql_crosstab.sql +++ b/src/test/regress/sql/psql_crosstab.sql @@ -111,3 +111,14 @@ SELECT a,a,1 FROM generate_series(1,3000) AS a SELECT 1 \crosstabview DROP TABLE ctv_data; + +-- check error reporting (bug #14476) +CREATE TABLE ctv_data (x int, y int, v text); + +INSERT INTO ctv_data SELECT 1, x, '*' || x FROM generate_series(1,10) x; +SELECT * FROM ctv_data \crosstabview + +INSERT INTO ctv_data VALUES (1, 10, '*'); -- duplicate data to cause error +SELECT * FROM ctv_data \crosstabview + +DROP TABLE ctv_data; diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql new file mode 100644 index 0000000000..87797884d2 --- /dev/null +++ b/src/test/regress/sql/publication.sql @@ -0,0 +1,83 @@ +-- +-- PUBLICATION +-- +CREATE ROLE regress_publication_user LOGIN SUPERUSER; +SET SESSION AUTHORIZATION 'regress_publication_user'; + +CREATE PUBLICATION testpub_default; + +CREATE PUBLICATION testpib_ins_trunct WITH (nopublish delete, nopublish update); + +ALTER PUBLICATION testpub_default WITH (nopublish insert, nopublish delete); + +\dRp + +ALTER PUBLICATION testpub_default WITH (publish insert, publish delete); + +\dRp + +--- adding tables +CREATE SCHEMA pub_test; +CREATE TABLE testpub_tbl1 (id serial primary key, data text); +CREATE TABLE pub_test.testpub_nopk (foo int, bar int); +CREATE VIEW testpub_view AS SELECT 1; + +CREATE PUBLICATION testpub_foralltables FOR ALL TABLES WITH (nopublish delete, nopublish update); +ALTER PUBLICATION testpub_foralltables WITH (publish update); + +CREATE TABLE testpub_tbl2 (id serial primary key, data text); +-- fail - can't add to for all tables publication +ALTER PUBLICATION testpub_foralltables ADD TABLE testpub_tbl2; +-- fail - can't drop from all tables publication +ALTER PUBLICATION testpub_foralltables DROP TABLE testpub_tbl2; +-- fail - can't add to for all tables publication +ALTER PUBLICATION testpub_foralltables SET TABLE pub_test.testpub_nopk; + +SELECT pubname, puballtables FROM pg_publication WHERE pubname = 'testpub_foralltables'; +\d+ testpub_tbl2 + +DROP TABLE testpub_tbl2; +DROP PUBLICATION testpub_foralltables; + +-- fail - view +CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view; +CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk; +-- fail - already added +ALTER PUBLICATION testpub_fortbl ADD TABLE testpub_tbl1; +-- fail - already added +CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1; + +\dRp+ testpub_fortbl + +-- fail - view +ALTER PUBLICATION testpub_default ADD TABLE testpub_view; + +ALTER PUBLICATION testpub_default ADD TABLE testpub_tbl1; +ALTER PUBLICATION testpub_default SET TABLE testpub_tbl1; +ALTER PUBLICATION testpub_default ADD TABLE pub_test.testpub_nopk; + +ALTER PUBLICATION testpib_ins_trunct ADD TABLE pub_test.testpub_nopk, testpub_tbl1; + +\d+ pub_test.testpub_nopk +\d+ testpub_tbl1 +\dRp+ testpub_default + +ALTER PUBLICATION testpub_default DROP TABLE testpub_tbl1, pub_test.testpub_nopk; +-- fail - nonexistent +ALTER PUBLICATION testpub_default DROP TABLE pub_test.testpub_nopk; + +\d+ testpub_tbl1 + +DROP VIEW testpub_view; +DROP TABLE testpub_tbl1; + +\dRp+ testpub_default + +DROP PUBLICATION testpub_default; +DROP PUBLICATION testpib_ins_trunct; +DROP PUBLICATION testpub_fortbl; + +DROP SCHEMA pub_test CASCADE; + +RESET SESSION AUTHORIZATION; +DROP ROLE regress_publication_user; diff --git a/src/test/regress/sql/regex.linux.utf8.sql b/src/test/regress/sql/regex.linux.utf8.sql new file mode 100644 index 0000000000..4577811645 --- /dev/null +++ b/src/test/regress/sql/regex.linux.utf8.sql @@ -0,0 +1,46 @@ +/* + * This test is for Linux/glibc systems and others that implement proper + * locale classification of Unicode characters with high code values. + * It must be run in a database with UTF8 encoding and a Unicode-aware locale. + */ + +SET client_encoding TO UTF8; + +-- +-- Test the "high colormap" logic with single characters and ranges that +-- exceed the MAX_SIMPLE_CHR cutoff, here assumed to be less than U+2000. +-- + +-- trivial cases: +SELECT 'aⓐ' ~ U&'a\24D0' AS t; +SELECT 'aⓐ' ~ U&'a\24D1' AS f; +SELECT 'aⓕ' ~ 'a[ⓐ-ⓩ]' AS t; +SELECT 'aⒻ' ~ 'a[ⓐ-ⓩ]' AS f; +-- cases requiring splitting of ranges: +SELECT 'aⓕⓕ' ~ 'aⓕ[ⓐ-ⓩ]' AS t; +SELECT 'aⓕⓐ' ~ 'aⓕ[ⓐ-ⓩ]' AS t; +SELECT 'aⓐⓕ' ~ 'aⓕ[ⓐ-ⓩ]' AS f; +SELECT 'aⓕⓕ' ~ 'a[ⓐ-ⓩ]ⓕ' AS t; +SELECT 'aⓕⓐ' ~ 'a[ⓐ-ⓩ]ⓕ' AS f; +SELECT 'aⓐⓕ' ~ 'a[ⓐ-ⓩ]ⓕ' AS t; +SELECT 'aⒶⓜ' ~ 'a[Ⓐ-ⓜ][ⓜ-ⓩ]' AS t; +SELECT 'aⓜⓜ' ~ 'a[Ⓐ-ⓜ][ⓜ-ⓩ]' AS t; +SELECT 'aⓜⓩ' ~ 'a[Ⓐ-ⓜ][ⓜ-ⓩ]' AS t; +SELECT 'aⓩⓩ' ~ 'a[Ⓐ-ⓜ][ⓜ-ⓩ]' AS f; +SELECT 'aⓜ⓪' ~ 'a[Ⓐ-ⓜ][ⓜ-ⓩ]' AS f; +SELECT 'a0' ~ 'a[a-ⓩ]' AS f; +SELECT 'aq' ~ 'a[a-ⓩ]' AS t; +SELECT 'aⓜ' ~ 'a[a-ⓩ]' AS t; +SELECT 'a⓪' ~ 'a[a-ⓩ]' AS f; + +-- Locale-dependent character classes + +SELECT 'aⒶⓜ⓪' ~ '[[:alpha:]][[:alpha:]][[:alpha:]][[:graph:]]' AS t; +SELECT 'aⒶⓜ⓪' ~ '[[:alpha:]][[:alpha:]][[:alpha:]][[:alpha:]]' AS f; + +-- Locale-dependent character classes with high ranges + +SELECT 'aⒶⓜ⓪' ~ '[a-z][[:alpha:]][ⓐ-ⓩ][[:graph:]]' AS t; +SELECT 'aⓜⒶ⓪' ~ '[a-z][[:alpha:]][ⓐ-ⓩ][[:graph:]]' AS f; +SELECT 'aⓜⒶ⓪' ~ '[a-z][ⓐ-ⓩ][[:alpha:]][[:graph:]]' AS t; +SELECT 'aⒶⓜ⓪' ~ '[a-z][ⓐ-ⓩ][[:alpha:]][[:graph:]]' AS f; diff --git a/src/test/regress/sql/regex.sql b/src/test/regress/sql/regex.sql index 1028ca6dcd..1361b62570 100644 --- a/src/test/regress/sql/regex.sql +++ b/src/test/regress/sql/regex.sql @@ -25,6 +25,13 @@ select substring('asd TO foo' from ' TO (([a-z0-9._]+|"([^"]+|"")+")+)'); select substring('a' from '((a))+'); select substring('a' from '((a)+)'); +-- Test regexp_match() +select regexp_match('abc', ''); +select regexp_match('abc', 'bc'); +select regexp_match('abc', 'd') is null; +select regexp_match('abc', '(B)(c)', 'i'); +select regexp_match('abc', 'Bd', 'ig'); -- error + -- Test lookahead constraints select regexp_matches('ab', 'a(?=b)b*'); select regexp_matches('a', 'a(?=b)b*'); diff --git a/src/test/regress/sql/rowsecurity.sql b/src/test/regress/sql/rowsecurity.sql index 7fcefe4502..5e2f4ef884 100644 --- a/src/test/regress/sql/rowsecurity.sql +++ b/src/test/regress/sql/rowsecurity.sql @@ -10,6 +10,7 @@ SET client_min_messages TO 'warning'; DROP USER IF EXISTS regress_rls_alice; DROP USER IF EXISTS regress_rls_bob; DROP USER IF EXISTS regress_rls_carol; +DROP USER IF EXISTS regress_rls_dave; DROP USER IF EXISTS regress_rls_exempt_user; DROP ROLE IF EXISTS regress_rls_group1; DROP ROLE IF EXISTS regress_rls_group2; @@ -22,6 +23,7 @@ RESET client_min_messages; CREATE USER regress_rls_alice NOLOGIN; CREATE USER regress_rls_bob NOLOGIN; CREATE USER regress_rls_carol NOLOGIN; +CREATE USER regress_rls_dave NOLOGIN; CREATE USER regress_rls_exempt_user BYPASSRLS NOLOGIN; CREATE ROLE regress_rls_group1 NOLOGIN; CREATE ROLE regress_rls_group2 NOLOGIN; @@ -80,14 +82,35 @@ INSERT INTO document VALUES ( 5, 44, 2, 'regress_rls_bob', 'my second manga'), ( 6, 22, 1, 'regress_rls_carol', 'great science fiction'), ( 7, 33, 2, 'regress_rls_carol', 'great technology book'), - ( 8, 44, 1, 'regress_rls_carol', 'great manga'); + ( 8, 44, 1, 'regress_rls_carol', 'great manga'), + ( 9, 22, 1, 'regress_rls_dave', 'awesome science fiction'), + (10, 33, 2, 'regress_rls_dave', 'awesome technology book'); ALTER TABLE document ENABLE ROW LEVEL SECURITY; -- user's security level must be higher than or equal to document's -CREATE POLICY p1 ON document +CREATE POLICY p1 ON document AS PERMISSIVE USING (dlevel <= (SELECT seclv FROM uaccount WHERE pguser = current_user)); +-- try to create a policy of bogus type +CREATE POLICY p1 ON document AS UGLY + USING (dlevel <= (SELECT seclv FROM uaccount WHERE pguser = current_user)); + +-- but Dave isn't allowed to anything at cid 50 or above +-- this is to make sure that we sort the policies by name first +-- when applying WITH CHECK, a later INSERT by Dave should fail due +-- to p1r first +CREATE POLICY p2r ON document AS RESTRICTIVE TO regress_rls_dave + USING (cid <> 44 AND cid < 50); + +-- and Dave isn't allowed to see manga documents +CREATE POLICY p1r ON document AS RESTRICTIVE TO regress_rls_dave + USING (cid <> 44); + +\dp +\d document +SELECT * FROM pg_policies WHERE schemaname = 'regress_rls_schema' AND tablename = 'document' ORDER BY policyname; + -- viewpoint from regress_rls_bob SET SESSION AUTHORIZATION regress_rls_bob; SET row_security TO ON; @@ -110,6 +133,20 @@ SELECT * FROM document TABLESAMPLE BERNOULLI(50) REPEATABLE(0) EXPLAIN (COSTS OFF) SELECT * FROM document WHERE f_leak(dtitle); EXPLAIN (COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle); +-- viewpoint from regress_rls_dave +SET SESSION AUTHORIZATION regress_rls_dave; +SELECT * FROM document WHERE f_leak(dtitle) ORDER BY did; +SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle) ORDER BY did; + +EXPLAIN (COSTS OFF) SELECT * FROM document WHERE f_leak(dtitle); +EXPLAIN (COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle); + +-- 44 would technically fail for both p2r and p1r, but we should get an error +-- back from p1r for this because it sorts first +INSERT INTO document VALUES (100, 44, 1, 'regress_rls_dave', 'testing sorting of policies'); -- fail +-- Just to see a p2r error +INSERT INTO document VALUES (100, 55, 1, 'regress_rls_dave', 'testing sorting of policies'); -- fail + -- only owner can change policies ALTER POLICY p1 ON document USING (true); --fail DROP POLICY p1 ON document; --fail @@ -147,7 +184,7 @@ DELETE FROM category WHERE cid = 33; -- fails with FK violation -- can insert FK referencing invisible PK SET SESSION AUTHORIZATION regress_rls_carol; SELECT * FROM document d FULL OUTER JOIN category c on d.cid = c.cid; -INSERT INTO document VALUES (10, 33, 1, current_user, 'hoge'); +INSERT INTO document VALUES (11, 33, 1, current_user, 'hoge'); -- UNIQUE or PRIMARY KEY constraint violation DOES reveal presence of row SET SESSION AUTHORIZATION regress_rls_bob; @@ -517,6 +554,7 @@ SELECT * FROM b1; SET SESSION AUTHORIZATION regress_rls_alice; DROP POLICY p1 ON document; +DROP POLICY p1r ON document; CREATE POLICY p1 ON document FOR SELECT USING (true); CREATE POLICY p2 ON document FOR INSERT WITH CHECK (dauthor = current_user); @@ -1577,6 +1615,7 @@ RESET client_min_messages; DROP USER regress_rls_alice; DROP USER regress_rls_bob; DROP USER regress_rls_carol; +DROP USER regress_rls_dave; DROP USER regress_rls_exempt_user; DROP ROLE regress_rls_group1; DROP ROLE regress_rls_group2; diff --git a/src/test/regress/sql/select_parallel.sql b/src/test/regress/sql/select_parallel.sql index 38d3166742..8b4090f2ec 100644 --- a/src/test/regress/sql/select_parallel.sql +++ b/src/test/regress/sql/select_parallel.sql @@ -44,13 +44,7 @@ set force_parallel_mode=1; explain (costs off) select stringu1::int2 from tenk1 where unique1 = 1; -do $$begin - -- Provoke error, possibly in worker. If this error happens to occur in - -- the worker, there will be a CONTEXT line which must be hidden. - perform stringu1::int2 from tenk1 where unique1 = 1; - exception - when others then - raise 'SQLERRM: %', sqlerrm; -end$$; +-- provoke error in worker +select stringu1::int2 from tenk1 where unique1 = 1; rollback; diff --git a/src/test/regress/sql/sequence.sql b/src/test/regress/sql/sequence.sql index 98a2e7db36..a79330e780 100644 --- a/src/test/regress/sql/sequence.sql +++ b/src/test/regress/sql/sequence.sql @@ -138,12 +138,23 @@ SELECT nextval('sequence_test2'); SELECT nextval('sequence_test2'); SELECT nextval('sequence_test2'); + +CREATE SEQUENCE sequence_test3; -- not read from, to test is_called + + -- Information schema SELECT * FROM information_schema.sequences WHERE sequence_name IN - ('sequence_test2', 'serialtest2_f2_seq', 'serialtest2_f3_seq', + ('sequence_test2', 'sequence_test3', 'serialtest2_f2_seq', 'serialtest2_f3_seq', 'serialtest2_f4_seq', 'serialtest2_f5_seq', 'serialtest2_f6_seq') ORDER BY sequence_name ASC; +SELECT schemaname, sequencename, start_value, min_value, max_value, increment_by, cycle, cache_size, last_value +FROM pg_sequences +WHERE sequencename IN + ('sequence_test2', 'sequence_test3', 'serialtest2_f2_seq', 'serialtest2_f3_seq', + 'serialtest2_f4_seq', 'serialtest2_f5_seq', 'serialtest2_f6_seq') + ORDER BY sequencename ASC; + -- Test comments COMMENT ON SEQUENCE asdf IS 'won''t work'; COMMENT ON SEQUENCE sequence_test2 IS 'will work'; @@ -262,3 +273,11 @@ SELECT * FROM information_schema.sequences WHERE sequence_name IN DROP USER regress_seq_user; DROP SEQUENCE seq; + +-- cache tests +CREATE SEQUENCE test_seq1 CACHE 10; +SELECT nextval('test_seq1'); +SELECT nextval('test_seq1'); +SELECT nextval('test_seq1'); + +DROP SEQUENCE test_seq1; diff --git a/src/test/regress/sql/subscription.sql b/src/test/regress/sql/subscription.sql new file mode 100644 index 0000000000..68c17d5cfd --- /dev/null +++ b/src/test/regress/sql/subscription.sql @@ -0,0 +1,44 @@ +-- +-- SUBSCRIPTION +-- + +CREATE ROLE regress_subscription_user LOGIN SUPERUSER; +SET SESSION AUTHORIZATION 'regress_subscription_user'; + +-- fail - no publications +CREATE SUBSCRIPTION testsub CONNECTION 'foo'; + +-- fail - no connection +CREATE SUBSCRIPTION testsub PUBLICATION foo; + +set client_min_messages to error; +CREATE SUBSCRIPTION testsub CONNECTION 'testconn' PUBLICATION testpub; +CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION testpub WITH (DISABLED, NOCREATE SLOT); +reset client_min_messages; + +\dRs+ + +ALTER SUBSCRIPTION testsub SET PUBLICATION testpub2, testpub3; + +\dRs + +ALTER SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist2'; +ALTER SUBSCRIPTION testsub SET PUBLICATION testpub, testpub1; + +\dRs+ + +BEGIN; +ALTER SUBSCRIPTION testsub ENABLE; + +\dRs + +ALTER SUBSCRIPTION testsub DISABLE; + +\dRs + +COMMIT; + +DROP SUBSCRIPTION testsub NODROP SLOT; + +RESET SESSION AUTHORIZATION; +DROP ROLE regress_subscription_user; diff --git a/src/test/regress/sql/subselect.sql b/src/test/regress/sql/subselect.sql index 2991223089..08eb825c54 100644 --- a/src/test/regress/sql/subselect.sql +++ b/src/test/regress/sql/subselect.sql @@ -481,3 +481,47 @@ select * from order by 1; select nextval('ts1'); + +-- +-- Check that volatile quals aren't pushed down past a set-returning function; +-- while a nonvolatile qual can be, if it doesn't reference the SRF. +-- +create function tattle(x int, y int) returns bool +volatile language plpgsql as $$ +begin + raise notice 'x = %, y = %', x, y; + return x > y; +end$$; + +explain (verbose, costs off) +select * from + (select 9 as x, unnest(array[1,2,3,11,12,13]) as u) ss + where tattle(x, 8); + +select * from + (select 9 as x, unnest(array[1,2,3,11,12,13]) as u) ss + where tattle(x, 8); + +-- if we pretend it's stable, we get different results: +alter function tattle(x int, y int) stable; + +explain (verbose, costs off) +select * from + (select 9 as x, unnest(array[1,2,3,11,12,13]) as u) ss + where tattle(x, 8); + +select * from + (select 9 as x, unnest(array[1,2,3,11,12,13]) as u) ss + where tattle(x, 8); + +-- although even a stable qual should not be pushed down if it references SRF +explain (verbose, costs off) +select * from + (select 9 as x, unnest(array[1,2,3,11,12,13]) as u) ss + where tattle(x, u); + +select * from + (select 9 as x, unnest(array[1,2,3,11,12,13]) as u) ss + where tattle(x, u); + +drop function tattle(x int, y int); diff --git a/src/test/regress/sql/timestamptz.sql b/src/test/regress/sql/timestamptz.sql index c023095bb8..ab86622a88 100644 --- a/src/test/regress/sql/timestamptz.sql +++ b/src/test/regress/sql/timestamptz.sql @@ -468,3 +468,28 @@ SELECT '2007-12-09 07:00:00 UTC'::timestamptz AT TIME ZONE 'VET'; SELECT '2007-12-09 07:00:01 UTC'::timestamptz AT TIME ZONE 'VET'; SELECT '2007-12-09 07:29:59 UTC'::timestamptz AT TIME ZONE 'VET'; SELECT '2007-12-09 07:30:00 UTC'::timestamptz AT TIME ZONE 'VET'; + +-- +-- Test that the pg_timezone_names and pg_timezone_abbrevs views are +-- more-or-less working. We can't test their contents in any great detail +-- without the outputs changing anytime IANA updates the underlying data, +-- but it seems reasonable to expect at least one entry per major meridian. +-- (At the time of writing, the actual counts are around 38 because of +-- zones using fractional GMT offsets, so this is a pretty loose test.) +-- +select count(distinct utc_offset) >= 24 as ok from pg_timezone_names; +select count(distinct utc_offset) >= 24 as ok from pg_timezone_abbrevs; +-- Let's check the non-default timezone abbreviation sets, too +set timezone_abbreviations = 'Australia'; +select count(distinct utc_offset) >= 24 as ok from pg_timezone_abbrevs; +set timezone_abbreviations = 'India'; +select count(distinct utc_offset) >= 24 as ok from pg_timezone_abbrevs; + +-- +-- Test that AT TIME ZONE isn't misoptimized when using an index (bug #14504) +-- +create temp table tmptz (f1 timestamptz primary key); +insert into tmptz values ('2017-01-18 00:00+00'); +explain (costs off) +select * from tmptz where f1 at time zone 'utc' = '2017-01-18 00:00'; +select * from tmptz where f1 at time zone 'utc' = '2017-01-18 00:00'; diff --git a/src/test/regress/sql/tsearch.sql b/src/test/regress/sql/tsearch.sql index 65eb9438d4..1255f6954d 100644 --- a/src/test/regress/sql/tsearch.sql +++ b/src/test/regress/sql/tsearch.sql @@ -402,6 +402,8 @@ SELECT COUNT(*) FROM test_tsquery WHERE keyword > 'new & york'; RESET enable_seqscan; SELECT ts_rewrite('foo & bar & qq & new & york', 'new & york'::tsquery, 'big & apple | nyc | new & york & city'); +SELECT ts_rewrite(ts_rewrite('new & !york ', 'york', '!jersey'), + 'jersey', 'mexico'); SELECT ts_rewrite('moscow', 'SELECT keyword, sample FROM test_tsquery'::text ); SELECT ts_rewrite('moscow & hotel', 'SELECT keyword, sample FROM test_tsquery'::text ); @@ -416,6 +418,9 @@ SELECT ts_rewrite('1 & (2 <2> 3)', 'SELECT keyword, sample FROM test_tsquery'::t SELECT ts_rewrite('5 <-> (1 & (2 <-> 3))', 'SELECT keyword, sample FROM test_tsquery'::text ); SELECT ts_rewrite('5 <-> (6 | 8)', 'SELECT keyword, sample FROM test_tsquery'::text ); +-- Check empty substitution +SELECT ts_rewrite(to_tsquery('5 & (6 | 5)'), to_tsquery('5'), to_tsquery('')); +SELECT ts_rewrite(to_tsquery('!5'), to_tsquery('5'), to_tsquery('')); SELECT keyword FROM test_tsquery WHERE keyword @> 'new'; SELECT keyword FROM test_tsquery WHERE keyword @> 'moscow'; @@ -442,6 +447,12 @@ SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_t SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'moscow & hotel') AS query; SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & new & qq & foo & york') AS query; +SELECT ts_rewrite(tsquery_phrase('foo', 'foo'), 'foo', 'bar | baz'); +SELECT to_tsvector('foo bar') @@ + ts_rewrite(tsquery_phrase('foo', 'foo'), 'foo', 'bar | baz'); +SELECT to_tsvector('bar baz') @@ + ts_rewrite(tsquery_phrase('foo', 'foo'), 'foo', 'bar | baz'); + RESET enable_seqscan; --test GUC diff --git a/src/test/regress/sql/tsrf.sql b/src/test/regress/sql/tsrf.sql new file mode 100644 index 0000000000..ff2fa3eb9a --- /dev/null +++ b/src/test/regress/sql/tsrf.sql @@ -0,0 +1,134 @@ +-- +-- tsrf - targetlist set returning function tests +-- + +-- simple srf +SELECT generate_series(1, 3); + +-- parallel iteration +SELECT generate_series(1, 3), generate_series(3,5); + +-- parallel iteration, different number of rows +SELECT generate_series(1, 2), generate_series(1,4); + +-- srf, with SRF argument +SELECT generate_series(1, generate_series(1, 3)); + +-- srf, with two SRF arguments +SELECT generate_series(generate_series(1,3), generate_series(2, 4)); + +CREATE TABLE few(id int, dataa text, datab text); +INSERT INTO few VALUES(1, 'a', 'foo'),(2, 'a', 'bar'),(3, 'b', 'bar'); + +-- SRF output order of sorting is maintained, if SRF is not referenced +SELECT few.id, generate_series(1,3) g FROM few ORDER BY id DESC; + +-- but SRFs can be referenced in sort +SELECT few.id, generate_series(1,3) g FROM few ORDER BY id, g DESC; +SELECT few.id, generate_series(1,3) g FROM few ORDER BY id, generate_series(1,3) DESC; + +-- it's weird to have ORDER BYs that increase the number of results +SELECT few.id FROM few ORDER BY id, generate_series(1,3) DESC; + +-- SRFs are computed after aggregation +SET enable_hashagg TO 0; -- stable output order +SELECT few.dataa, count(*), min(id), max(id), unnest('{1,1,3}'::int[]) FROM few WHERE few.id = 1 GROUP BY few.dataa; +-- unless referenced in GROUP BY clause +SELECT few.dataa, count(*), min(id), max(id), unnest('{1,1,3}'::int[]) FROM few WHERE few.id = 1 GROUP BY few.dataa, unnest('{1,1,3}'::int[]); +SELECT few.dataa, count(*), min(id), max(id), unnest('{1,1,3}'::int[]) FROM few WHERE few.id = 1 GROUP BY few.dataa, 5; +RESET enable_hashagg; + +-- check HAVING works when GROUP BY does [not] reference SRF output +SELECT dataa, generate_series(1,1), count(*) FROM few GROUP BY 1 HAVING count(*) > 1; +SELECT dataa, generate_series(1,1), count(*) FROM few GROUP BY 1, 2 HAVING count(*) > 1; + +-- it's weird to have GROUP BYs that increase the number of results +SELECT few.dataa, count(*) FROM few WHERE dataa = 'a' GROUP BY few.dataa ORDER BY 2; +SELECT few.dataa, count(*) FROM few WHERE dataa = 'a' GROUP BY few.dataa, unnest('{1,1,3}'::int[]) ORDER BY 2; + +-- SRFs are not allowed in aggregate arguments +SELECT min(generate_series(1, 3)) FROM few; + +-- SRFs are not allowed in window function arguments, either +SELECT min(generate_series(1, 3)) OVER() FROM few; + +-- SRFs are normally computed after window functions +SELECT id,lag(id) OVER(), count(*) OVER(), generate_series(1,3) FROM few; +-- unless referencing SRFs +SELECT SUM(count(*)) OVER(PARTITION BY generate_series(1,3) ORDER BY generate_series(1,3)), generate_series(1,3) g FROM few GROUP BY g; + +-- sorting + grouping +SELECT few.dataa, count(*), min(id), max(id), generate_series(1,3) FROM few GROUP BY few.dataa ORDER BY 5, 1; + +-- grouping sets are a bit special, they produce NULLs in columns not actually NULL +SELECT dataa, datab b, generate_series(1,2) g, count(*) FROM few GROUP BY CUBE(dataa, datab); +SELECT dataa, datab b, generate_series(1,2) g, count(*) FROM few GROUP BY CUBE(dataa, datab) ORDER BY dataa; +SELECT dataa, datab b, generate_series(1,2) g, count(*) FROM few GROUP BY CUBE(dataa, datab) ORDER BY g; +SELECT dataa, datab b, generate_series(1,2) g, count(*) FROM few GROUP BY CUBE(dataa, datab, g); +SELECT dataa, datab b, generate_series(1,2) g, count(*) FROM few GROUP BY CUBE(dataa, datab, g) ORDER BY dataa; +SELECT dataa, datab b, generate_series(1,2) g, count(*) FROM few GROUP BY CUBE(dataa, datab, g) ORDER BY g; + +-- data modification +CREATE TABLE fewmore AS SELECT generate_series(1,3) AS data; +INSERT INTO fewmore VALUES(generate_series(4,5)); +SELECT * FROM fewmore; + +-- SRFs are not allowed in UPDATE (they once were, but it was nonsense) +UPDATE fewmore SET data = generate_series(4,9); + +-- SRFs are not allowed in RETURNING +INSERT INTO fewmore VALUES(1) RETURNING generate_series(1,3); + +-- nor standalone VALUES (but surely this is a bug?) +VALUES(1, generate_series(1,2)); + +-- We allow tSRFs that are not at top level +SELECT int4mul(generate_series(1,2), 10); + +-- but SRFs in function RTEs must be at top level (annoying restriction) +SELECT * FROM int4mul(generate_series(1,2), 10); + +-- DISTINCT ON is evaluated before tSRF evaluation if SRF is not +-- referenced either in ORDER BY or in the DISTINCT ON list. The ORDER +-- BY reference can be implicitly generated, if there's no other ORDER BY. + +-- implicit reference (via implicit ORDER) to all columns +SELECT DISTINCT ON (a) a, b, generate_series(1,3) g +FROM (VALUES (3, 2), (3,1), (1,1), (1,4), (5,3), (5,1)) AS t(a, b); + +-- unreferenced in DISTINCT ON or ORDER BY +SELECT DISTINCT ON (a) a, b, generate_series(1,3) g +FROM (VALUES (3, 2), (3,1), (1,1), (1,4), (5,3), (5,1)) AS t(a, b) +ORDER BY a, b DESC; + +-- referenced in ORDER BY +SELECT DISTINCT ON (a) a, b, generate_series(1,3) g +FROM (VALUES (3, 2), (3,1), (1,1), (1,4), (5,3), (5,1)) AS t(a, b) +ORDER BY a, b DESC, g DESC; + +-- referenced in ORDER BY and DISTINCT ON +SELECT DISTINCT ON (a, b, g) a, b, generate_series(1,3) g +FROM (VALUES (3, 2), (3,1), (1,1), (1,4), (5,3), (5,1)) AS t(a, b) +ORDER BY a, b DESC, g DESC; + +-- only SRF mentioned in DISTINCT ON +SELECT DISTINCT ON (g) a, b, generate_series(1,3) g +FROM (VALUES (3, 2), (3,1), (1,1), (1,4), (5,3), (5,1)) AS t(a, b); + +-- LIMIT / OFFSET is evaluated after SRF evaluation +SELECT a, generate_series(1,2) FROM (VALUES(1),(2),(3)) r(a) LIMIT 2 OFFSET 2; +-- SRFs are not allowed in LIMIT. +SELECT 1 LIMIT generate_series(1,3); + +-- tSRF in correlated subquery, referencing table outside +SELECT (SELECT generate_series(1,3) LIMIT 1 OFFSET few.id) FROM few; +-- tSRF in correlated subquery, referencing SRF outside +SELECT (SELECT generate_series(1,3) LIMIT 1 OFFSET g.i) FROM generate_series(0,3) g(i); + +-- Operators can return sets too +CREATE OPERATOR |@| (PROCEDURE = unnest, RIGHTARG = ANYARRAY); +SELECT |@|ARRAY[1,2,3]; + +-- Clean up +DROP TABLE few; +DROP TABLE fewmore; diff --git a/src/test/regress/sql/tstypes.sql b/src/test/regress/sql/tstypes.sql index 9ea93a2993..77436ce04e 100644 --- a/src/test/regress/sql/tstypes.sql +++ b/src/test/regress/sql/tstypes.sql @@ -64,34 +64,6 @@ SELECT 'a & !!b'::tsquery; SELECT '!!a & b'::tsquery; SELECT '!!a & !!b'::tsquery; --- phrase transformation -SELECT 'a <-> (b|c)'::tsquery; -SELECT '(a|b) <-> c'::tsquery; -SELECT '(a|b) <-> (d|c)'::tsquery; - -SELECT 'a <-> (b&c)'::tsquery; -SELECT '(a&b) <-> c'::tsquery; -SELECT '(a&b) <-> (d&c)'::tsquery; - -SELECT 'a <-> !b'::tsquery; -SELECT '!a <-> b'::tsquery; -SELECT '!a <-> !b'::tsquery; - -SELECT 'a <-> !(b&c)'::tsquery; -SELECT 'a <-> !(b|c)'::tsquery; -SELECT '!(a&b) <-> c'::tsquery; -SELECT '!(a|b) <-> c'::tsquery; - -SELECT '(!a|b) <-> c'::tsquery; -SELECT '(!a&b) <-> c'::tsquery; -SELECT 'c <-> (!a|b)'::tsquery; -SELECT 'c <-> (!a&b)'::tsquery; - -SELECT '(a|b) <-> !c'::tsquery; -SELECT '(a&b) <-> !c'::tsquery; -SELECT '!c <-> (a|b)'::tsquery; -SELECT '!c <-> (a&b)'::tsquery; - --comparisons SELECT 'a' < 'b & c'::tsquery as "true"; SELECT 'a' > 'b & c'::tsquery as "false"; @@ -146,10 +118,33 @@ SELECT to_tsvector('simple', '1 2 11 3') @@ '1:* <-> 3' AS "true"; SELECT to_tsvector('simple', '1 2 3 4') @@ '1 <-> 2 <-> 3' AS "true"; SELECT to_tsvector('simple', '1 2 3 4') @@ '(1 <-> 2) <-> 3' AS "true"; -SELECT to_tsvector('simple', '1 2 3 4') @@ '1 <-> (2 <-> 3)' AS "false"; -SELECT to_tsvector('simple', '1 2 3 4') @@ '1 <2> (2 <-> 3)' AS "true"; +SELECT to_tsvector('simple', '1 2 3 4') @@ '1 <-> (2 <-> 3)' AS "true"; +SELECT to_tsvector('simple', '1 2 3 4') @@ '1 <2> (2 <-> 3)' AS "false"; SELECT to_tsvector('simple', '1 2 1 2 3 4') @@ '(1 <-> 2) <-> 3' AS "true"; SELECT to_tsvector('simple', '1 2 1 2 3 4') @@ '1 <-> 2 <-> 3' AS "true"; +-- without position data, phrase search does not match +SELECT strip(to_tsvector('simple', '1 2 3 4')) @@ '1 <-> 2 <-> 3' AS "false"; + +select to_tsvector('simple', 'q x q y') @@ 'q <-> (x & y)' AS "false"; +select to_tsvector('simple', 'q x') @@ 'q <-> (x | y <-> z)' AS "true"; +select to_tsvector('simple', 'q y') @@ 'q <-> (x | y <-> z)' AS "false"; +select to_tsvector('simple', 'q y z') @@ 'q <-> (x | y <-> z)' AS "true"; +select to_tsvector('simple', 'q y x') @@ 'q <-> (x | y <-> z)' AS "false"; +select to_tsvector('simple', 'q x y') @@ 'q <-> (x | y <-> z)' AS "true"; +select to_tsvector('simple', 'q x') @@ '(x | y <-> z) <-> q' AS "false"; +select to_tsvector('simple', 'x q') @@ '(x | y <-> z) <-> q' AS "true"; +select to_tsvector('simple', 'x y q') @@ '(x | y <-> z) <-> q' AS "false"; +select to_tsvector('simple', 'x y z') @@ '(x | y <-> z) <-> q' AS "false"; +select to_tsvector('simple', 'x y z q') @@ '(x | y <-> z) <-> q' AS "true"; +select to_tsvector('simple', 'y z q') @@ '(x | y <-> z) <-> q' AS "true"; +select to_tsvector('simple', 'y y q') @@ '(x | y <-> z) <-> q' AS "false"; +select to_tsvector('simple', 'y y q') @@ '(!x | y <-> z) <-> q' AS "true"; +select to_tsvector('simple', 'x y q') @@ '(!x | y <-> z) <-> q' AS "true"; +select to_tsvector('simple', 'y y q') @@ '(x | y <-> !z) <-> q' AS "true"; +select to_tsvector('simple', 'x q') @@ '(x | y <-> !z) <-> q' AS "true"; +select to_tsvector('simple', 'x q') @@ '(!x | y <-> z) <-> q' AS "false"; +select to_tsvector('simple', 'z q') @@ '(!x | y <-> z) <-> q' AS "true"; +select to_tsvector('simple', 'x y q y') @@ '!x <-> y' AS "true"; --ranking SELECT ts_rank(' a:1 s:2C d g'::tsvector, 'a | s'); @@ -193,6 +188,7 @@ SELECT 'a:1 b:3'::tsvector @@ 'a <0> b'::tsquery AS "false"; SELECT 'a:1 b:3'::tsvector @@ 'a <1> b'::tsquery AS "false"; SELECT 'a:1 b:3'::tsvector @@ 'a <2> b'::tsquery AS "true"; SELECT 'a:1 b:3'::tsvector @@ 'a <3> b'::tsquery AS "false"; +SELECT 'a:1 b:3'::tsvector @@ 'a <0> a:*'::tsquery AS "true"; -- tsvector editing operations diff --git a/src/test/regress/sql/txid.sql b/src/test/regress/sql/txid.sql index b6650b922e..4aefd9e64d 100644 --- a/src/test/regress/sql/txid.sql +++ b/src/test/regress/sql/txid.sql @@ -52,3 +52,10 @@ select txid_visible_in_snapshot('1000100010001015', '1000100010001000:1000100010 -- test 64bit overflow SELECT txid_snapshot '1:9223372036854775807:3'; SELECT txid_snapshot '1:9223372036854775808:3'; + +-- test txid_current_if_assigned +BEGIN; +SELECT txid_current_if_assigned() IS NULL; +SELECT txid_current() \gset +SELECT txid_current_if_assigned() IS NOT DISTINCT FROM BIGINT :'txid_current'; +COMMIT; diff --git a/src/test/regress/sql/union.sql b/src/test/regress/sql/union.sql index 9ff1551e5d..48e6850798 100644 --- a/src/test/regress/sql/union.sql +++ b/src/test/regress/sql/union.sql @@ -4,41 +4,41 @@ -- Simple UNION constructs -SELECT 1 AS two UNION SELECT 2; +SELECT 1 AS two UNION SELECT 2 ORDER BY 1; -SELECT 1 AS one UNION SELECT 1; +SELECT 1 AS one UNION SELECT 1 ORDER BY 1; SELECT 1 AS two UNION ALL SELECT 2; SELECT 1 AS two UNION ALL SELECT 1; -SELECT 1 AS three UNION SELECT 2 UNION SELECT 3; +SELECT 1 AS three UNION SELECT 2 UNION SELECT 3 ORDER BY 1; -SELECT 1 AS two UNION SELECT 2 UNION SELECT 2; +SELECT 1 AS two UNION SELECT 2 UNION SELECT 2 ORDER BY 1; -SELECT 1 AS three UNION SELECT 2 UNION ALL SELECT 2; +SELECT 1 AS three UNION SELECT 2 UNION ALL SELECT 2 ORDER BY 1; -SELECT 1.1 AS two UNION SELECT 2.2; +SELECT 1.1 AS two UNION SELECT 2.2 ORDER BY 1; -- Mixed types -SELECT 1.1 AS two UNION SELECT 2; +SELECT 1.1 AS two UNION SELECT 2 ORDER BY 1; -SELECT 1 AS two UNION SELECT 2.2; +SELECT 1 AS two UNION SELECT 2.2 ORDER BY 1; -SELECT 1 AS one UNION SELECT 1.0::float8; +SELECT 1 AS one UNION SELECT 1.0::float8 ORDER BY 1; -SELECT 1.1 AS two UNION ALL SELECT 2; +SELECT 1.1 AS two UNION ALL SELECT 2 ORDER BY 1; -SELECT 1.0::float8 AS two UNION ALL SELECT 1; +SELECT 1.0::float8 AS two UNION ALL SELECT 1 ORDER BY 1; -SELECT 1.1 AS three UNION SELECT 2 UNION SELECT 3; +SELECT 1.1 AS three UNION SELECT 2 UNION SELECT 3 ORDER BY 1; SELECT 1.1::float8 AS two UNION SELECT 2 UNION SELECT 2.0::float8 ORDER BY 1; -SELECT 1.1 AS three UNION SELECT 2 UNION ALL SELECT 2; +SELECT 1.1 AS three UNION SELECT 2 UNION ALL SELECT 2 ORDER BY 1; -SELECT 1.1 AS two UNION (SELECT 2 UNION ALL SELECT 2); +SELECT 1.1 AS two UNION (SELECT 2 UNION ALL SELECT 2) ORDER BY 1; -- -- Try testing from tables... @@ -66,7 +66,8 @@ SELECT f1 AS five FROM FLOAT8_TBL WHERE f1 BETWEEN -1e6 AND 1e6 UNION SELECT f1 FROM INT4_TBL - WHERE f1 BETWEEN 0 AND 1000000; + WHERE f1 BETWEEN 0 AND 1000000 +ORDER BY 1; SELECT CAST(f1 AS char(4)) AS three FROM VARCHAR_TBL UNION @@ -93,9 +94,9 @@ ORDER BY 1; -- INTERSECT and EXCEPT -- -SELECT q2 FROM int8_tbl INTERSECT SELECT q1 FROM int8_tbl; +SELECT q2 FROM int8_tbl INTERSECT SELECT q1 FROM int8_tbl ORDER BY 1; -SELECT q2 FROM int8_tbl INTERSECT ALL SELECT q1 FROM int8_tbl; +SELECT q2 FROM int8_tbl INTERSECT ALL SELECT q1 FROM int8_tbl ORDER BY 1; SELECT q2 FROM int8_tbl EXCEPT SELECT q1 FROM int8_tbl ORDER BY 1; @@ -103,11 +104,11 @@ SELECT q2 FROM int8_tbl EXCEPT ALL SELECT q1 FROM int8_tbl ORDER BY 1; SELECT q2 FROM int8_tbl EXCEPT ALL SELECT DISTINCT q1 FROM int8_tbl ORDER BY 1; -SELECT q1 FROM int8_tbl EXCEPT SELECT q2 FROM int8_tbl; +SELECT q1 FROM int8_tbl EXCEPT SELECT q2 FROM int8_tbl ORDER BY 1; -SELECT q1 FROM int8_tbl EXCEPT ALL SELECT q2 FROM int8_tbl; +SELECT q1 FROM int8_tbl EXCEPT ALL SELECT q2 FROM int8_tbl ORDER BY 1; -SELECT q1 FROM int8_tbl EXCEPT ALL SELECT DISTINCT q2 FROM int8_tbl; +SELECT q1 FROM int8_tbl EXCEPT ALL SELECT DISTINCT q2 FROM int8_tbl ORDER BY 1; SELECT q1 FROM int8_tbl EXCEPT ALL SELECT q1 FROM int8_tbl FOR NO KEY UPDATE; @@ -115,7 +116,7 @@ SELECT q1 FROM int8_tbl EXCEPT ALL SELECT q1 FROM int8_tbl FOR NO KEY UPDATE; -- Mixed types -- -SELECT f1 FROM float8_tbl INTERSECT SELECT f1 FROM int4_tbl; +SELECT f1 FROM float8_tbl INTERSECT SELECT f1 FROM int4_tbl ORDER BY 1; SELECT f1 FROM float8_tbl EXCEPT SELECT f1 FROM int4_tbl ORDER BY 1; @@ -123,11 +124,11 @@ SELECT f1 FROM float8_tbl EXCEPT SELECT f1 FROM int4_tbl ORDER BY 1; -- Operator precedence and (((((extra))))) parentheses -- -SELECT q1 FROM int8_tbl INTERSECT SELECT q2 FROM int8_tbl UNION ALL SELECT q2 FROM int8_tbl; +SELECT q1 FROM int8_tbl INTERSECT SELECT q2 FROM int8_tbl UNION ALL SELECT q2 FROM int8_tbl ORDER BY 1; -SELECT q1 FROM int8_tbl INTERSECT (((SELECT q2 FROM int8_tbl UNION ALL SELECT q2 FROM int8_tbl))); +SELECT q1 FROM int8_tbl INTERSECT (((SELECT q2 FROM int8_tbl UNION ALL SELECT q2 FROM int8_tbl))) ORDER BY 1; -(((SELECT q1 FROM int8_tbl INTERSECT SELECT q2 FROM int8_tbl))) UNION ALL SELECT q2 FROM int8_tbl; +(((SELECT q1 FROM int8_tbl INTERSECT SELECT q2 FROM int8_tbl ORDER BY 1))) UNION ALL SELECT q2 FROM int8_tbl; SELECT q1 FROM int8_tbl UNION ALL SELECT q2 FROM int8_tbl EXCEPT SELECT q1 FROM int8_tbl ORDER BY 1; @@ -147,7 +148,7 @@ ORDER BY q2,q1; SELECT q1 FROM int8_tbl EXCEPT SELECT q2 FROM int8_tbl ORDER BY q2 LIMIT 1; -- But this should work: -SELECT q1 FROM int8_tbl EXCEPT (((SELECT q2 FROM int8_tbl ORDER BY q2 LIMIT 1))); +SELECT q1 FROM int8_tbl EXCEPT (((SELECT q2 FROM int8_tbl ORDER BY q2 LIMIT 1))) ORDER BY 1; -- -- New syntaxes (7.1) permit new tests @@ -261,13 +262,15 @@ SELECT * FROM (SELECT 1 AS t, 2 AS x UNION SELECT 2 AS t, 4 AS x) ss -WHERE x < 4; +WHERE x < 4 +ORDER BY x; SELECT * FROM (SELECT 1 AS t, 2 AS x UNION SELECT 2 AS t, 4 AS x) ss -WHERE x < 4; +WHERE x < 4 +ORDER BY x; explain (costs off) SELECT * FROM @@ -289,13 +292,15 @@ SELECT * FROM (SELECT 1 AS t, (random()*3)::int AS x UNION SELECT 2 AS t, 4 AS x) ss -WHERE x > 3; +WHERE x > 3 +ORDER BY x; SELECT * FROM (SELECT 1 AS t, (random()*3)::int AS x UNION SELECT 2 AS t, 4 AS x) ss -WHERE x > 3; +WHERE x > 3 +ORDER BY x; -- Test proper handling of parameterized appendrel paths when the -- potential join qual is expensive @@ -317,3 +322,16 @@ select * from drop table t3; drop function expensivefunc(int); + +-- Test handling of appendrel quals that const-simplify into an AND +explain (costs off) +select * from + (select *, 0 as x from int8_tbl a + union all + select *, 1 as x from int8_tbl b) ss +where (x = 0) or (q1 >= q2 and q1 <= q2); +select * from + (select *, 0 as x from int8_tbl a + union all + select *, 1 as x from int8_tbl b) ss +where (x = 0) or (q1 >= q2 and q1 <= q2); diff --git a/src/test/regress/sql/updatable_views.sql b/src/test/regress/sql/updatable_views.sql index 03c3f9d35e..ffc64d2de9 100644 --- a/src/test/regress/sql/updatable_views.sql +++ b/src/test/regress/sql/updatable_views.sql @@ -95,7 +95,7 @@ DELETE FROM rw_view16 WHERE a=-3; -- should be OK -- Read-only views INSERT INTO ro_view17 VALUES (3, 'ROW 3'); DELETE FROM ro_view18; -UPDATE ro_view19 SET max_value=1000; +UPDATE ro_view19 SET last_value=1000; UPDATE ro_view20 SET b=upper(b); DROP TABLE base_tbl CASCADE; @@ -1001,8 +1001,8 @@ SELECT * FROM v1 WHERE a=3; -- should not see anything SELECT * FROM v1 WHERE a=8; EXPLAIN (VERBOSE, COSTS OFF) -UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a = 3; -UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a = 3; +UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a < 7 AND a != 6; +UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a < 7 AND a != 6; SELECT * FROM v1 WHERE a=100; -- Nothing should have been changed to 100 SELECT * FROM t1 WHERE a=100; -- Nothing should have been changed to 100 @@ -1098,3 +1098,17 @@ DROP VIEW v2; DROP VIEW v1; DROP TABLE t2; DROP TABLE t1; + +-- +-- Test CREATE OR REPLACE VIEW turning a non-updatable view into an +-- auto-updatable view and adding check options in a single step +-- +CREATE TABLE t1 (a int, b text); +CREATE VIEW v1 AS SELECT null::int AS a; +CREATE OR REPLACE VIEW v1 AS SELECT * FROM t1 WHERE a > 0 WITH CHECK OPTION; + +INSERT INTO v1 VALUES (1, 'ok'); -- ok +INSERT INTO v1 VALUES (-1, 'invalid'); -- should fail + +DROP VIEW v1; +DROP TABLE t1; diff --git a/src/test/regress/sql/update.sql b/src/test/regress/sql/update.sql index 5637c68acf..d7721ed376 100644 --- a/src/test/regress/sql/update.sql +++ b/src/test/regress/sql/update.sql @@ -40,6 +40,10 @@ UPDATE update_test SET a=v.i FROM (VALUES(100, 20)) AS v(i, j) SELECT * FROM update_test; +-- fail, wrong data type: +UPDATE update_test SET a = v.* FROM (VALUES(100, 20)) AS v(i, j) + WHERE update_test.b = v.j; + -- -- Test multiple-set-clause syntax -- @@ -70,6 +74,12 @@ UPDATE update_test SET (b,a) = (select a+1,b from update_test); UPDATE update_test SET (b,a) = (select a+1,b from update_test where a = 1000) WHERE a = 11; SELECT * FROM update_test; +-- *-expansion should work in this context: +UPDATE update_test SET (a,b) = ROW(v.*) FROM (VALUES(21, 100)) AS v(i, j) + WHERE update_test.a = v.i; +-- you might expect this to work, but syntactically it's not a RowExpr: +UPDATE update_test SET (a,b) = (v.*) FROM (VALUES(21, 101)) AS v(i, j) + WHERE update_test.a = v.i; -- if an alias for the target table is specified, don't allow references -- to the original table name @@ -96,3 +106,24 @@ INSERT INTO upsert_test VALUES (1, 'Bat') ON CONFLICT(a) DROP TABLE update_test; DROP TABLE upsert_test; + +-- update to a partition should check partition bound constraint for the new tuple +create table range_parted ( + a text, + b int +) partition by range (a, b); +create table part_a_1_a_10 partition of range_parted for values from ('a', 1) to ('a', 10); +create table part_a_10_a_20 partition of range_parted for values from ('a', 10) to ('a', 20); +create table part_b_1_b_10 partition of range_parted for values from ('b', 1) to ('b', 10); +create table part_b_10_b_20 partition of range_parted for values from ('b', 10) to ('b', 20); +insert into part_a_1_a_10 values ('a', 1); +insert into part_b_10_b_20 values ('b', 10); + +-- fail +update part_a_1_a_10 set a = 'b' where a = 'a'; +update range_parted set b = b - 1 where b = 10; +-- ok +update range_parted set b = b + 1 where b = 10; + +-- cleanup +drop table range_parted cascade; diff --git a/src/test/regress/sql/with.sql b/src/test/regress/sql/with.sql index 133ff0b195..7ee32bab8f 100644 --- a/src/test/regress/sql/with.sql +++ b/src/test/regress/sql/with.sql @@ -575,7 +575,7 @@ WITH outermost(x) AS ( SELECT * FROM innermost UNION SELECT 3) ) -SELECT * FROM outermost; +SELECT * FROM outermost ORDER BY 1; WITH outermost(x) AS ( SELECT 1 @@ -583,7 +583,7 @@ WITH outermost(x) AS ( SELECT * FROM outermost -- fail UNION SELECT * FROM innermost) ) -SELECT * FROM outermost; +SELECT * FROM outermost ORDER BY 1; WITH RECURSIVE outermost(x) AS ( SELECT 1 @@ -591,14 +591,14 @@ WITH RECURSIVE outermost(x) AS ( SELECT * FROM outermost UNION SELECT * FROM innermost) ) -SELECT * FROM outermost; +SELECT * FROM outermost ORDER BY 1; WITH RECURSIVE outermost(x) AS ( WITH innermost as (SELECT 2 FROM outermost) -- fail SELECT * FROM innermost UNION SELECT * from outermost ) -SELECT * FROM outermost; +SELECT * FROM outermost ORDER BY 1; -- -- This test will fail with the old implementation of PARAM_EXEC parameter diff --git a/src/test/ssl/Makefile b/src/test/ssl/Makefile index d8c4741963..e4437d19c3 100644 --- a/src/test/ssl/Makefile +++ b/src/test/ssl/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/test/ssl # -# Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/test/ssl/Makefile @@ -23,7 +23,8 @@ SSLFILES := $(CERTIFICATES:%=ssl/%.key) $(CERTIFICATES:%=ssl/%.crt) \ ssl/client.crl ssl/server.crl ssl/root.crl \ ssl/both-cas-1.crt ssl/both-cas-2.crt \ ssl/root+server_ca.crt ssl/root+server.crl \ - ssl/root+client_ca.crt ssl/root+client.crl + ssl/root+client_ca.crt ssl/root+client.crl \ + ssl/client+client_ca.crt # This target generates all the key and certificate files. sslfiles: $(SSLFILES) @@ -41,15 +42,16 @@ ssl/%.key: # Root CA certificate ssl/root_ca.crt: ssl/root_ca.key cas.config touch ssl/root_ca-certindex - openssl req -new -out ssl/root_ca.crt -x509 -config cas.config -config root_ca.config -key ssl/root_ca.key -days 10000 + openssl req -new -out ssl/root_ca.crt -x509 -config cas.config -config root_ca.config -key ssl/root_ca.key -days 10000 -extensions v3_ca echo "01" > ssl/root_ca.srl # Client and server CAs ssl/%_ca.crt: ssl/%_ca.key %_ca.config ssl/root_ca.crt ssl/new_certs_dir touch ssl/$*_ca-certindex + echo "unique_subject=no" > ssl/$*_ca-certindex.attr openssl req -new -out ssl/temp_ca.crt -config cas.config -config $*_ca.config -key ssl/$*_ca.key # Sign the certificate with the root CA - openssl ca -name root_ca -batch -config cas.config -in ssl/temp_ca.crt -out ssl/temp_ca_signed.crt + openssl ca -name root_ca -batch -config cas.config -in ssl/temp_ca.crt -out ssl/temp_ca_signed.crt -extensions v3_ca openssl x509 -in ssl/temp_ca_signed.crt -out ssl/$*_ca.crt # to keep just the PEM cert rm ssl/temp_ca.crt ssl/temp_ca_signed.crt echo "01" > ssl/$*_ca.srl @@ -98,6 +100,9 @@ ssl/root+server_ca.crt: ssl/root_ca.crt ssl/server_ca.crt ssl/root+client_ca.crt: ssl/root_ca.crt ssl/client_ca.crt cat $^ > $@ +ssl/client+client_ca.crt: ssl/client.crt ssl/client_ca.crt + cat $^ > $@ + #### CRLs ssl/client.crl: ssl/client-revoked.crt diff --git a/src/test/ssl/README b/src/test/ssl/README index 52bd68f49f..50fa14e287 100644 --- a/src/test/ssl/README +++ b/src/test/ssl/README @@ -65,6 +65,10 @@ root+server_ca root+client_ca Contains root_crt and client_ca.crt. For use as server's "ssl_ca_file". +client+client_ca + Contains client.crt and client_ca.crt in that order. For use as client's + certificate chain. + There are also CRLs for each of the CAs: root.crl, server.crl and client.crl. For convenience, all of these keypairs and certificates are included in the diff --git a/src/test/ssl/ServerSetup.pm b/src/test/ssl/ServerSetup.pm index 4e93184eb0..20eaf76bff 100644 --- a/src/test/ssl/ServerSetup.pm +++ b/src/test/ssl/ServerSetup.pm @@ -70,49 +70,67 @@ sub configure_test_server_for_ssl close CONF; -# Copy all server certificates and keys, and client root cert, to the data dir + # ssl configuration will be placed here + open SSLCONF, ">$pgdata/sslconfig.conf"; + close SSLCONF; + + # Copy all server certificates and keys, and client root cert, to the data dir copy_files("ssl/server-*.crt", $pgdata); copy_files("ssl/server-*.key", $pgdata); chmod(0600, glob "$pgdata/server-*.key") or die $!; copy_files("ssl/root+client_ca.crt", $pgdata); + copy_files("ssl/root_ca.crt", $pgdata); copy_files("ssl/root+client.crl", $pgdata); - # Only accept SSL connections from localhost. Our tests don't depend on this - # but seems best to keep it as narrow as possible for security reasons. - # - # When connecting to certdb, also check the client certificate. - open HBA, ">$pgdata/pg_hba.conf"; - print HBA -"# TYPE DATABASE USER ADDRESS METHOD\n"; - print HBA -"hostssl trustdb ssltestuser $serverhost/32 trust\n"; - print HBA -"hostssl trustdb ssltestuser ::1/128 trust\n"; - print HBA -"hostssl certdb ssltestuser $serverhost/32 cert\n"; - print HBA -"hostssl certdb ssltestuser ::1/128 cert\n"; - close HBA; + # Stop and restart server to load new listen_addresses. + $node->restart; + + # Change pg_hba after restart because hostssl requires ssl=on + configure_hba_for_ssl($node, $serverhost); } -# Change the configuration to use given server cert file, and restart +# Change the configuration to use given server cert file, and reload # the server so that the configuration takes effect. sub switch_server_cert { my $node = $_[0]; my $certfile = $_[1]; + my $cafile = $_[2] || "root+client_ca"; my $pgdata = $node->data_dir; - diag "Restarting server with certfile \"$certfile\"..."; + diag "Reloading server with certfile \"$certfile\" and cafile \"$cafile\"..."; open SSLCONF, ">$pgdata/sslconfig.conf"; print SSLCONF "ssl=on\n"; - print SSLCONF "ssl_ca_file='root+client_ca.crt'\n"; + print SSLCONF "ssl_ca_file='$cafile.crt'\n"; print SSLCONF "ssl_cert_file='$certfile.crt'\n"; print SSLCONF "ssl_key_file='$certfile.key'\n"; print SSLCONF "ssl_crl_file='root+client.crl'\n"; close SSLCONF; - # Stop and restart server to reload the new config. - $node->restart; + $node->reload; +} + +sub configure_hba_for_ssl +{ + my $node = $_[0]; + my $serverhost = $_[1]; + my $pgdata = $node->data_dir; + + # Only accept SSL connections from localhost. Our tests don't depend on this + # but seems best to keep it as narrow as possible for security reasons. + # + # When connecting to certdb, also check the client certificate. + open HBA, ">$pgdata/pg_hba.conf"; + print HBA +"# TYPE DATABASE USER ADDRESS METHOD\n"; + print HBA +"hostssl trustdb ssltestuser $serverhost/32 trust\n"; + print HBA +"hostssl trustdb ssltestuser ::1/128 trust\n"; + print HBA +"hostssl certdb ssltestuser $serverhost/32 cert\n"; + print HBA +"hostssl certdb ssltestuser ::1/128 cert\n"; + close HBA; } diff --git a/src/test/ssl/cas.config b/src/test/ssl/cas.config index 9c6cbb93f3..013cebae16 100644 --- a/src/test/ssl/cas.config +++ b/src/test/ssl/cas.config @@ -2,11 +2,10 @@ [ req ] prompt = no -req_extensions = v3_req -# For Subject Alternative Names -[ v3_req ] -subjectAltName = @alt_names +# Extensions for CA certs +[ v3_ca ] +basicConstraints = CA:true # Root CA, used to sign the certificates of the intermediary server and # client CAs. diff --git a/src/test/ssl/root_ca.config b/src/test/ssl/root_ca.config index 72484d040f..187a9b8a46 100644 --- a/src/test/ssl/root_ca.config +++ b/src/test/ssl/root_ca.config @@ -7,3 +7,7 @@ prompt = no [ req_distinguished_name ] CN = Test root CA for PostgreSQL SSL regression test suite + +# Extensions for CA certs +[ v3_ca ] +basicConstraints = CA:true diff --git a/src/test/ssl/server-cn-only.config b/src/test/ssl/server-cn-only.config index 7849d090eb..1e5d582213 100644 --- a/src/test/ssl/server-cn-only.config +++ b/src/test/ssl/server-cn-only.config @@ -3,7 +3,6 @@ [ req ] distinguished_name = req_distinguished_name -req_extensions = v3_req prompt = no [ req_distinguished_name ] diff --git a/src/test/ssl/server-no-names.config b/src/test/ssl/server-no-names.config index 92cf779086..2a71125a42 100644 --- a/src/test/ssl/server-no-names.config +++ b/src/test/ssl/server-no-names.config @@ -5,7 +5,6 @@ [ req ] distinguished_name = req_distinguished_name -req_extensions = v3_req prompt = no [ req_distinguished_name ] diff --git a/src/test/ssl/server-revoked.config b/src/test/ssl/server-revoked.config index 9924af8ec1..47ef6462dc 100644 --- a/src/test/ssl/server-revoked.config +++ b/src/test/ssl/server-revoked.config @@ -5,7 +5,6 @@ [ req ] distinguished_name = req_distinguished_name -req_extensions = v3_req prompt = no [ req_distinguished_name ] diff --git a/src/test/ssl/ssl/both-cas-1.crt b/src/test/ssl/ssl/both-cas-1.crt index abf4612f9f..0e2a10a180 100644 --- a/src/test/ssl/ssl/both-cas-1.crt +++ b/src/test/ssl/ssl/both-cas-1.crt @@ -1,39 +1,40 @@ -----BEGIN CERTIFICATE----- -MIIB9zCCAWACCQDrgvp38CAy8DANBgkqhkiG9w0BAQsFADBAMT4wPAYDVQQDDDVU -ZXN0IHJvb3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBz -dWl0ZTAeFw0xNTAyMTYyMDA2MjNaFw00MjA3MDQyMDA2MjNaMEAxPjA8BgNVBAMM -NVRlc3Qgcm9vdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0 -IHN1aXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyTfGMPAjAylLr3G7c -/QToCA3da5YZzdhd3TiQGugrJjWI4TzVB7pQ8IwDYk/jZf5TzVdEtz0B4TeIeUZl -FLW9dMpa/8SY2TETvMTuXR5MOxyw6FMEKb3buolsIksCCQ1btEIrDZ+gv9SJXcdL -ylU+VI1lKmn2fLNWWATzWrIUawIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAF2T84iG -zWKXu+3PysuPOn7RuRpMgYQKouQktErNJ8hM7Yqj3vu879zUkX1rP0HGnx7xQC3d -nBkoJ7yNDR0MwQpWo1Dj1HLKNEY6ojKJgPd0+m8nG+02yUmmOjo0oMYzJx2DQy0u -Y4qecEd6aDbqXTo+qOJ7Qm/U+U4kD9MTT6GD +MIICDjCCAXegAwIBAgIJAO2nC4XHXDkUMA0GCSqGSIb3DQEBCwUAMEAxPjA8BgNV +BAMMNVRlc3Qgcm9vdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0 +ZXN0IHN1aXRlMB4XDTE2MDkxMjE2MzAwMVoXDTQ0MDEyOTE2MzAwMVowQDE+MDwG +A1UEAww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9u +IHRlc3Qgc3VpdGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vUDilEsB5 +qI9cGWTthAIjlvr2ngFJqHmMeOgTg4JQQ24MQedh0r22nDNwm80r4RD9RCjlw/k8 +sS+chRwQclJqpE6EV65TIH0JhOKGFpx/Pz/yrru5QwEDkYcHl1QcK3xFUKbSxi/B +MCq4TZf63HkI6/VRY+1SwKF2a4pjWIaDAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQELBQADgYEAtBNiRyqydB+iy2DtoYYjsvq/q69o3UrbIhKPMlYE +TJcgWyEz4gsRMnceM/dQl0dchZ8jrAbLiAbqr7PvitjdxGSQJ8w7Gb4IawPu3UCE +TfMWiG5oYV1nHHZotEQuE+Gx4AdzSVGzLGj2xF9dSMxEQq7uPlpv67IeHEn5g3w1 +K5Y= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- -MIIB8TCCAVoCAQIwDQYJKoZIhvcNAQEFBQAwQDE+MDwGA1UEAww1VGVzdCByb290 -IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc3VpdGUwHhcN -MTUwMjE2MjAwNjIzWhcNNDIwNzA0MjAwNjIzWjBCMUAwPgYDVQQDDDdUZXN0IENB -IGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRz -MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8wIYcmeePSXVufP/Hn/6ICEog -IUXqSNls5QIJR7Sate4iKGGTDEsRTxI4oDgkOYtcQNuEeXMf6k3xo+PRR08IEQNk -XKy1zUWds6UBFboD72SyuTE2lxJBg+xOAWgl7JSNA+g8e0Y+wfhfxGZgRuqVxVNP -9sAsfCEzGKna1l46dQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAD20Bmina/uXTLXO -oPWgpMmKwQu7Q6DPXxItCUdWgK1k1D82brRjH+usrkrmCW5BQNXOC/0zJS22ioC1 -CJbhAujH3iPaV0C3xsVSf+bvTL6OMkwV/9x9OdDN+LI2auEt4S+fP5ZTVsTXt4wA -A9cQIl2Qy88enZZAFKxrScFFlstp +MIICCDCCAXGgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBAMT4wPAYDVQQDDDVUZXN0 +IHJvb3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzdWl0 +ZTAeFw0xNjA5MTIxNjMwMDFaFw00NDAxMjkxNjMwMDFaMEIxQDA+BgNVBAMMN1Rl +c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBjbGllbnQg +Y2VydHMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMI2MXWSb8TZnCLVNYJ+ +19b4noxRmaR1W2zUxl4aTMfiPt9cK06lNY39EPBfjmb7hjxD76w8fLoV/aZ0gOgd +JXFRZvIg7SyM7QVFma0AJAIZayes+ba1odEmBEi378g0mLrjCLqZtBVHfvJxL/6x +6/flSTAn/+09vtELvvLWBePZAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZI +hvcNAQEFBQADgYEAlGC24V2TsiSlo9RIboBZTZqd0raUpKkmVbkwKyqcmecoFfCI +TCmoyJLYyUL5/e3dtn/cGDcaqxaO3qxnstxVEMSrlCGfZdZJ2oouXZMpDy9CkeOM +ypCCx9pc4EmP3mvu64f21+dNCXlhM36pZ1IokeS5jk2FIHUda+m5jlk5o6I= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- -MIIB8TCCAVoCAQEwDQYJKoZIhvcNAQEFBQAwQDE+MDwGA1UEAww1VGVzdCByb290 -IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc3VpdGUwHhcN -MTUwMjE2MjAwNjIzWhcNNDIwNzA0MjAwNjIzWjBCMUAwPgYDVQQDDDdUZXN0IENB -IGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRz -MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDAYtajRx8vM6IB0SLZsAhTD0Y -VHM+/+t0a4m3JXolJBbo9/B2/WAN0IH1E2zmlalLc3JBmGsH1a8U5ZlRow3p2ODL -rFra9FbOl0wekmRFvZeaRln/99dpI5itVpL97QPHO8QMMK1IsyurFA5GfuPOBx9P -i0MvzsT0tYsRvR929QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAJw4ngOYElfyMYkS -K6bOgMosrBoX8ns6jQgdXEzf7QOIa110bs6nD+XeJeKmzUAZ3wumXBTalPaiqkEz -bq4nlsEs1phvj0Coy5eehjV3DB8bDLEneOlV5N9y4Z4VO1BrhX61bLiPXBRp1MZR -I0sCdxhswSrq02/OuFGe6mqrSBBI +MIICCDCCAXGgAwIBAgIBATANBgkqhkiG9w0BAQUFADBAMT4wPAYDVQQDDDVUZXN0 +IHJvb3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzdWl0 +ZTAeFw0xNjA5MTIxNjMwMDFaFw00NDAxMjkxNjMwMDFaMEIxQDA+BgNVBAMMN1Rl +c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzZXJ2ZXIg +Y2VydHMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKpkEBIZexm3YZ94RA+c +vUREqvLgECfHlP9BbkXySFPGWcAPt/0uSW62eVS3UFcB9083W4w/uilL75PXDHV1 +37fyq+6LHCYE5TinzVr5ECAtQMpIzlKkAuAPq3mTa1fklwT/MCz/PKGAljs2o95w +mNyEJwTchOQ52fZjFexRiarNAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZI +hvcNAQEFBQADgYEAP1ZhwGxsL7GTNxfs2qwYCjsF2zYSjCPXtwJnKFu5ayGxz6dB +paspokWFCglP1PwPAmINHeqp669WNnAmC5EixdTy2jcnod8NB6RlkOqJmNzVPhvO +cTZXxKd3awOzz0+IJ2bMcC9JPXs8phhRuRgvSfKTTZVtdcFmVF/HYIrBB5Y= -----END CERTIFICATE----- diff --git a/src/test/ssl/ssl/both-cas-2.crt b/src/test/ssl/ssl/both-cas-2.crt index b0bc3f5b2c..e857f8079b 100644 --- a/src/test/ssl/ssl/both-cas-2.crt +++ b/src/test/ssl/ssl/both-cas-2.crt @@ -1,39 +1,40 @@ -----BEGIN CERTIFICATE----- -MIIB9zCCAWACCQDrgvp38CAy8DANBgkqhkiG9w0BAQsFADBAMT4wPAYDVQQDDDVU -ZXN0IHJvb3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBz -dWl0ZTAeFw0xNTAyMTYyMDA2MjNaFw00MjA3MDQyMDA2MjNaMEAxPjA8BgNVBAMM -NVRlc3Qgcm9vdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0 -IHN1aXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyTfGMPAjAylLr3G7c -/QToCA3da5YZzdhd3TiQGugrJjWI4TzVB7pQ8IwDYk/jZf5TzVdEtz0B4TeIeUZl -FLW9dMpa/8SY2TETvMTuXR5MOxyw6FMEKb3buolsIksCCQ1btEIrDZ+gv9SJXcdL -ylU+VI1lKmn2fLNWWATzWrIUawIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAF2T84iG -zWKXu+3PysuPOn7RuRpMgYQKouQktErNJ8hM7Yqj3vu879zUkX1rP0HGnx7xQC3d -nBkoJ7yNDR0MwQpWo1Dj1HLKNEY6ojKJgPd0+m8nG+02yUmmOjo0oMYzJx2DQy0u -Y4qecEd6aDbqXTo+qOJ7Qm/U+U4kD9MTT6GD +MIICDjCCAXegAwIBAgIJAO2nC4XHXDkUMA0GCSqGSIb3DQEBCwUAMEAxPjA8BgNV +BAMMNVRlc3Qgcm9vdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0 +ZXN0IHN1aXRlMB4XDTE2MDkxMjE2MzAwMVoXDTQ0MDEyOTE2MzAwMVowQDE+MDwG +A1UEAww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9u +IHRlc3Qgc3VpdGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vUDilEsB5 +qI9cGWTthAIjlvr2ngFJqHmMeOgTg4JQQ24MQedh0r22nDNwm80r4RD9RCjlw/k8 +sS+chRwQclJqpE6EV65TIH0JhOKGFpx/Pz/yrru5QwEDkYcHl1QcK3xFUKbSxi/B +MCq4TZf63HkI6/VRY+1SwKF2a4pjWIaDAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQELBQADgYEAtBNiRyqydB+iy2DtoYYjsvq/q69o3UrbIhKPMlYE +TJcgWyEz4gsRMnceM/dQl0dchZ8jrAbLiAbqr7PvitjdxGSQJ8w7Gb4IawPu3UCE +TfMWiG5oYV1nHHZotEQuE+Gx4AdzSVGzLGj2xF9dSMxEQq7uPlpv67IeHEn5g3w1 +K5Y= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- -MIIB8TCCAVoCAQEwDQYJKoZIhvcNAQEFBQAwQDE+MDwGA1UEAww1VGVzdCByb290 -IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc3VpdGUwHhcN -MTUwMjE2MjAwNjIzWhcNNDIwNzA0MjAwNjIzWjBCMUAwPgYDVQQDDDdUZXN0IENB -IGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRz -MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDAYtajRx8vM6IB0SLZsAhTD0Y -VHM+/+t0a4m3JXolJBbo9/B2/WAN0IH1E2zmlalLc3JBmGsH1a8U5ZlRow3p2ODL -rFra9FbOl0wekmRFvZeaRln/99dpI5itVpL97QPHO8QMMK1IsyurFA5GfuPOBx9P -i0MvzsT0tYsRvR929QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAJw4ngOYElfyMYkS -K6bOgMosrBoX8ns6jQgdXEzf7QOIa110bs6nD+XeJeKmzUAZ3wumXBTalPaiqkEz -bq4nlsEs1phvj0Coy5eehjV3DB8bDLEneOlV5N9y4Z4VO1BrhX61bLiPXBRp1MZR -I0sCdxhswSrq02/OuFGe6mqrSBBI +MIICCDCCAXGgAwIBAgIBATANBgkqhkiG9w0BAQUFADBAMT4wPAYDVQQDDDVUZXN0 +IHJvb3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzdWl0 +ZTAeFw0xNjA5MTIxNjMwMDFaFw00NDAxMjkxNjMwMDFaMEIxQDA+BgNVBAMMN1Rl +c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzZXJ2ZXIg +Y2VydHMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKpkEBIZexm3YZ94RA+c +vUREqvLgECfHlP9BbkXySFPGWcAPt/0uSW62eVS3UFcB9083W4w/uilL75PXDHV1 +37fyq+6LHCYE5TinzVr5ECAtQMpIzlKkAuAPq3mTa1fklwT/MCz/PKGAljs2o95w +mNyEJwTchOQ52fZjFexRiarNAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZI +hvcNAQEFBQADgYEAP1ZhwGxsL7GTNxfs2qwYCjsF2zYSjCPXtwJnKFu5ayGxz6dB +paspokWFCglP1PwPAmINHeqp669WNnAmC5EixdTy2jcnod8NB6RlkOqJmNzVPhvO +cTZXxKd3awOzz0+IJ2bMcC9JPXs8phhRuRgvSfKTTZVtdcFmVF/HYIrBB5Y= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- -MIIB8TCCAVoCAQIwDQYJKoZIhvcNAQEFBQAwQDE+MDwGA1UEAww1VGVzdCByb290 -IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc3VpdGUwHhcN -MTUwMjE2MjAwNjIzWhcNNDIwNzA0MjAwNjIzWjBCMUAwPgYDVQQDDDdUZXN0IENB -IGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRz -MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8wIYcmeePSXVufP/Hn/6ICEog -IUXqSNls5QIJR7Sate4iKGGTDEsRTxI4oDgkOYtcQNuEeXMf6k3xo+PRR08IEQNk -XKy1zUWds6UBFboD72SyuTE2lxJBg+xOAWgl7JSNA+g8e0Y+wfhfxGZgRuqVxVNP -9sAsfCEzGKna1l46dQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAD20Bmina/uXTLXO -oPWgpMmKwQu7Q6DPXxItCUdWgK1k1D82brRjH+usrkrmCW5BQNXOC/0zJS22ioC1 -CJbhAujH3iPaV0C3xsVSf+bvTL6OMkwV/9x9OdDN+LI2auEt4S+fP5ZTVsTXt4wA -A9cQIl2Qy88enZZAFKxrScFFlstp +MIICCDCCAXGgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBAMT4wPAYDVQQDDDVUZXN0 +IHJvb3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzdWl0 +ZTAeFw0xNjA5MTIxNjMwMDFaFw00NDAxMjkxNjMwMDFaMEIxQDA+BgNVBAMMN1Rl +c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBjbGllbnQg +Y2VydHMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMI2MXWSb8TZnCLVNYJ+ +19b4noxRmaR1W2zUxl4aTMfiPt9cK06lNY39EPBfjmb7hjxD76w8fLoV/aZ0gOgd +JXFRZvIg7SyM7QVFma0AJAIZayes+ba1odEmBEi378g0mLrjCLqZtBVHfvJxL/6x +6/flSTAn/+09vtELvvLWBePZAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZI +hvcNAQEFBQADgYEAlGC24V2TsiSlo9RIboBZTZqd0raUpKkmVbkwKyqcmecoFfCI +TCmoyJLYyUL5/e3dtn/cGDcaqxaO3qxnstxVEMSrlCGfZdZJ2oouXZMpDy9CkeOM +ypCCx9pc4EmP3mvu64f21+dNCXlhM36pZ1IokeS5jk2FIHUda+m5jlk5o6I= -----END CERTIFICATE----- diff --git a/src/test/ssl/ssl/client+client_ca.crt b/src/test/ssl/ssl/client+client_ca.crt new file mode 100644 index 0000000000..3caada693d --- /dev/null +++ b/src/test/ssl/ssl/client+client_ca.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIBxzCCATACAQEwDQYJKoZIhvcNAQEFBQAwQjFAMD4GA1UEAww3VGVzdCBDQSBm +b3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IGNsaWVudCBjZXJ0czAe +Fw0xNjA5MTIxNjMwMDFaFw00NDAxMjkxNjMwMDFaMBYxFDASBgNVBAMMC3NzbHRl +c3R1c2VyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDN3RFl8VWMEBN1Qas0 +w1CFcXdDEbKVNSPsqWHzHIEPoGJv+eUIBK2lQ/Ce8nRCdelO50RsmlbcXBIrjVl6 +BN0RmEeEVclgCdiamYN53LBdc5KWKpKCKn45lCtlZodWt0hNNx1pAmh85jDKpoO9 +ErbCnSU1wODPqnOzdkLU7jBu5QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBABUz+vnu +dD1Q1N/Ezs5DzJeQDtiJb9PNzBHAUPQoXeLvuITcDdyYWc18Yi4fX7gwyD42q2iu +1I0hmm2bNJfujsGbvGYFLuQ4hC2ucAAj2Gm681GhhaNYtfsfHYm9R8GRZFvp40oj +qXpkDkYsPdyVxUyoxJ+M0Ub5VC/k1pQNtIaq +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICCDCCAXGgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBAMT4wPAYDVQQDDDVUZXN0 +IHJvb3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzdWl0 +ZTAeFw0xNjA5MTIxNjMwMDFaFw00NDAxMjkxNjMwMDFaMEIxQDA+BgNVBAMMN1Rl +c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBjbGllbnQg +Y2VydHMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMI2MXWSb8TZnCLVNYJ+ +19b4noxRmaR1W2zUxl4aTMfiPt9cK06lNY39EPBfjmb7hjxD76w8fLoV/aZ0gOgd +JXFRZvIg7SyM7QVFma0AJAIZayes+ba1odEmBEi378g0mLrjCLqZtBVHfvJxL/6x +6/flSTAn/+09vtELvvLWBePZAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZI +hvcNAQEFBQADgYEAlGC24V2TsiSlo9RIboBZTZqd0raUpKkmVbkwKyqcmecoFfCI +TCmoyJLYyUL5/e3dtn/cGDcaqxaO3qxnstxVEMSrlCGfZdZJ2oouXZMpDy9CkeOM +ypCCx9pc4EmP3mvu64f21+dNCXlhM36pZ1IokeS5jk2FIHUda+m5jlk5o6I= +-----END CERTIFICATE----- diff --git a/src/test/ssl/ssl/client-revoked.crt b/src/test/ssl/ssl/client-revoked.crt index c38229f847..8448e96125 100644 --- a/src/test/ssl/ssl/client-revoked.crt +++ b/src/test/ssl/ssl/client-revoked.crt @@ -1,12 +1,12 @@ -----BEGIN CERTIFICATE----- MIIBxzCCATACAQIwDQYJKoZIhvcNAQEFBQAwQjFAMD4GA1UEAww3VGVzdCBDQSBm b3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IGNsaWVudCBjZXJ0czAe -Fw0xNTAyMTYyMDA2MjNaFw00MjA3MDQyMDA2MjNaMBYxFDASBgNVBAMMC3NzbHRl -c3R1c2VyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDmApiFBFLZi/hgQOMz -iAHXBbY7A5hNMitQZMSTUB+/fLnzofkUjf/7GiRCLmdTCa4w1wvQp5VbrEhIbSGW -sFSam6GuE0IBfSRJA0IouBtxdk8bCY4HDpXsh/6eC9XtV4k9YDp4JlkUNxOVu8Pb -Z86OEQf3Ww/EZP5AfwORXLYgVQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAEarnPO1 -Rc88mDYZWM8H/I18L0omdib21+lJczkm4sgv2hVp2nR4Wfb51DojYruLxNJ0k/A5 -T0nEZghQDtNQQpMko9e8jn8gmEAs83zQIsVsmosfTYg0Zr2pSkT0ILSfR6BupHFJ -I96I+qcRKc4rotOirgMrcgo/VpUcWnz8VPEo +Fw0xNjA5MTIxNjMwMDFaFw00NDAxMjkxNjMwMDFaMBYxFDASBgNVBAMMC3NzbHRl +c3R1c2VyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKeycg+E5SBlaTxcus +Fps4yZnGVB78Kt/HQAZcmgiwWZxN0th9SsJVMw2VkwMPPm4o8idEF/PZvbz15DHk +MrNWSOMB8qsXlt3P8VMhKhWG025TbWpfXbNHKKqQqAc55i1SvQJvllrAYKOlpu/K +YQsIK/ZpjeTywcVi19B3aPE82wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAE3vuzMF +C5Ut6X981NjsuSlDptqDd8aQqO1HK7McEcH7Tjw6DU9ZPqw9Ktpz/wAJc2DvsmBM +QqlM+OtSkEncAdWx/xOzN46oHUNxrR2cXD1N/0HgVHJEUfq8p+oJHYXKVWtsjO7S +2/fZnMMO9Gv6e7eTiYE55R0IZrQENwtmIJ8y -----END CERTIFICATE----- diff --git a/src/test/ssl/ssl/client-revoked.key b/src/test/ssl/ssl/client-revoked.key index b272f70cbe..b2321ca4dc 100644 --- a/src/test/ssl/ssl/client-revoked.key +++ b/src/test/ssl/ssl/client-revoked.key @@ -1,15 +1,15 @@ -----BEGIN RSA PRIVATE KEY----- -MIICXgIBAAKBgQDmApiFBFLZi/hgQOMziAHXBbY7A5hNMitQZMSTUB+/fLnzofkU -jf/7GiRCLmdTCa4w1wvQp5VbrEhIbSGWsFSam6GuE0IBfSRJA0IouBtxdk8bCY4H -DpXsh/6eC9XtV4k9YDp4JlkUNxOVu8PbZ86OEQf3Ww/EZP5AfwORXLYgVQIDAQAB -AoGBAOV1iXqJya1Fuc8sbHyoHk3IYPeWqoW4mwVkwcbElCeP4mJvH/Glh82VUr7D -VEi+y4vlvN+3j4UY5jN6y5ts5bhDam4RjdHzhLT+ddlztoH4LNcgPDokQtPDtfOd -UbbMcM6Pim7+ynBLncAj7dTin4/pVL2tYUIrKWvLhCU2zISxAkEA+CyHJZs49vOs -hx8xEXGStdLq3k9vUk8G4BISicswixDWPQmJ3YN053FAZ+moHjqNpU5dMn7cVIcA -HEW6LLS7IwJBAO1DbyWtCNQJZBKXzvBKxx9nOBb+5ovQZWs92bpvxkATPn4TUbQx -nEe7eOPX+R2szP9+/3ApmZA1gV1mpVKsyicCQQCcUmf6jzCtlUXKgyJES5bPAwFA -cSa84NyCzb9xnlSAdGWOYvC9YC2GD3czPSHRkK5iPt9DjFc6wyKVrHId8OWjAkBh -8Yp6dRnF3jKPclec3mGg1w1SgNtPMDINuTSeP/IJFWigxvzdc/Vdr0hSVh+iXmkp -t5VfCe04mL3UfsEUhfvVAkEA5Y05DCgaT+rOZbl6hMXlIqT5eT+xTatmDZzv6FUJ -eAaYYhja/FrWa5JFXFUpFTamWGMTkfd6zsDS1bI6hwg/5Q== +MIICXQIBAAKBgQDKeycg+E5SBlaTxcusFps4yZnGVB78Kt/HQAZcmgiwWZxN0th9 +SsJVMw2VkwMPPm4o8idEF/PZvbz15DHkMrNWSOMB8qsXlt3P8VMhKhWG025TbWpf +XbNHKKqQqAc55i1SvQJvllrAYKOlpu/KYQsIK/ZpjeTywcVi19B3aPE82wIDAQAB +AoGAKXV79pFBICRyF8HZSTw7vi3xUZ2p1oJE3bxrUQytGMbQbVLtxwHGtsFEV8sJ +RlbHIZUrmxK4eG4UQdjeqlYDSBsV4x/g4sqpgQAoE1J6TQ9D3at6LqnvUa6ObjQW +W/GczCkrQRkRTxwa35PSE2CcgNcoyUXRkF0DHhugPcOVjRkCQQD1jUQYgLoUKDbZ +mZ1odm2adDu4BMFTd3pyQBVZmetlPrLVr8iU6bHJGUWpaFkpv/jbOJfNgijqQ3i6 +vZRhyHgHAkEA0xi6XZITkzmLP7qEQsho9JX02Pqqpd4ZQOp6CZDY6TH45oOBK0Bn ++xsfGENexiqU2EFtIChesScVpzTuvq2XjQJBALB82HTEEPpr7QB5aKmsdRqOcF3T +DSDwvxFe/flop8gdSGxN690cGqxvfaJFXdCkKjlmc7VB2CaIWD3gBMZDUAECQQC8 +oUIXTurTCf6WSdLZ4j93H3CVWxiV8uraCSxX0+kgKBlj0mrf/UNtLQUSJ1FO/snW +nFApBinnXyeILFKSbIgZAkB74ahj70+NmAFfEcgN3FjcHOy81rsvN9tO4rC0/0nt +iYBz1jc4KBZdyQY1rgk2om9m+EC+mlJsxtgFNK3k/kRJ -----END RSA PRIVATE KEY----- diff --git a/src/test/ssl/ssl/client.crl b/src/test/ssl/ssl/client.crl index cb86d82a76..72ed9e6d61 100644 --- a/src/test/ssl/ssl/client.crl +++ b/src/test/ssl/ssl/client.crl @@ -1,9 +1,9 @@ -----BEGIN X509 CRL----- MIIBHTCBhzANBgkqhkiG9w0BAQUFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ -b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0xNTAy -MTYyMDA2MjNaFw00MjA3MDQyMDA2MjNaMBQwEgIBAhcNMTUwMjE2MjAwNjIzWjAN -BgkqhkiG9w0BAQUFAAOBgQAsrnXoVeyU8vmxPOVQrHvoMXkEvF9dOnSHIQD0ZnAW -pxbj98hCMSIW+DPIXXFebMQ6GIPp4S/w5kVpngY51paT4iztRMlV+YeyuZQuZX9a -EVgpj4t+i6hhtBHk5p9DeknERoAIsl4m2maQ58lT5UyeN4fdz4eNP6y3mQRfSTUn -bQ== +b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0xNjA5 +MTIxNjMwMDFaFw00NDAxMjkxNjMwMDFaMBQwEgIBAhcNMTYwOTEyMTYzMDAxWjAN +BgkqhkiG9w0BAQUFAAOBgQAyiU3V6ci5JR5oAZjlG7yFBhVO2TFLga5FynwHK5Wd +ML0BA/0TtTXFiPoul+zvOdqwpX8GC3IuxqgJzlxWOxl5mZzyKEtheT9RBwvBmjAe +ZjT7bFttKo/WKpztNE/2ZEDYyN87Xlpcm5UBFNhcYUjQkxuWIEvH4VOPm0iFjzm4 +tA== -----END X509 CRL----- diff --git a/src/test/ssl/ssl/client.crt b/src/test/ssl/ssl/client.crt index 0c397c02cf..33d57ce0ba 100644 --- a/src/test/ssl/ssl/client.crt +++ b/src/test/ssl/ssl/client.crt @@ -1,12 +1,12 @@ -----BEGIN CERTIFICATE----- MIIBxzCCATACAQEwDQYJKoZIhvcNAQEFBQAwQjFAMD4GA1UEAww3VGVzdCBDQSBm b3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IGNsaWVudCBjZXJ0czAe -Fw0xNTAyMTYyMDA2MjNaFw00MjA3MDQyMDA2MjNaMBYxFDASBgNVBAMMC3NzbHRl -c3R1c2VyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDay1hT3/0Nj5ndv2TJ -DxJZWQTOZD+/0ktqW9qyiRY9o0nf7PCQZE9OCh3ylaaPPfpL7iITZi1KASmSIn7M -E4w1ibmBqFiogDE0Bq0DgJaoeUgLHMERDUtcxBJgwyCGjfI9Om4jy74kwMXb8I5i -jVwZLUTSWzRSgany3WRqMb6CwwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBALfP/i7o -ZVYsIZWksIb/uxr/AlghyNQjLPVJTAOjrm9PP9rwKR2alI/zjkDrHVH57n4MfcmD -Xn247DRv/MJFJ1xWCSh4PCy0vyTCFAerNDcqniSTqp2+Yusdr0mH/gHa+34ASYu/ -MXXB4UBMjTnZ/KhaVTmAv3cPeiMAQODRud65 +Fw0xNjA5MTIxNjMwMDFaFw00NDAxMjkxNjMwMDFaMBYxFDASBgNVBAMMC3NzbHRl +c3R1c2VyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDN3RFl8VWMEBN1Qas0 +w1CFcXdDEbKVNSPsqWHzHIEPoGJv+eUIBK2lQ/Ce8nRCdelO50RsmlbcXBIrjVl6 +BN0RmEeEVclgCdiamYN53LBdc5KWKpKCKn45lCtlZodWt0hNNx1pAmh85jDKpoO9 +ErbCnSU1wODPqnOzdkLU7jBu5QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBABUz+vnu +dD1Q1N/Ezs5DzJeQDtiJb9PNzBHAUPQoXeLvuITcDdyYWc18Yi4fX7gwyD42q2iu +1I0hmm2bNJfujsGbvGYFLuQ4hC2ucAAj2Gm681GhhaNYtfsfHYm9R8GRZFvp40oj +qXpkDkYsPdyVxUyoxJ+M0Ub5VC/k1pQNtIaq -----END CERTIFICATE----- diff --git a/src/test/ssl/ssl/client.key b/src/test/ssl/ssl/client.key index 6cb6655bc3..4400c8ede5 100644 --- a/src/test/ssl/ssl/client.key +++ b/src/test/ssl/ssl/client.key @@ -1,15 +1,15 @@ -----BEGIN RSA PRIVATE KEY----- -MIICXQIBAAKBgQDay1hT3/0Nj5ndv2TJDxJZWQTOZD+/0ktqW9qyiRY9o0nf7PCQ -ZE9OCh3ylaaPPfpL7iITZi1KASmSIn7ME4w1ibmBqFiogDE0Bq0DgJaoeUgLHMER -DUtcxBJgwyCGjfI9Om4jy74kwMXb8I5ijVwZLUTSWzRSgany3WRqMb6CwwIDAQAB -AoGAJAMiR7Pvb+L5/XC6QwmzCHfJfbssbwNLHHd/+LDtszmEOFJEik+oafzqTvpo -ztzxrLvGahEAVVT5pa791dNF2V//AKCDj3mOSVfrh6aYeA5naMT91JjnuRVgpdlc -1b7p1FpbnwmzppqSbAfVQxmTlFxvVevukTqkAzP03uuQZ+kCQQD8XMpgCYXFuAl9 -n59OjS9Fi4oISI2lxFFxUK4KjGW4fOzS9/PdHepc4YBJQXSrDdELkH/un5AZQ7tr -67R5YkB1AkEA3fKwaV0dPlXg78rVImUEXwNRM9SgxHquE6itzuT7RYg47bEnDHDm -EGzN5QVs7TrxApk8KCxPUzlv/3vSWszPVwJBAMN+2mN1XQTi4a9IhW+jnZghVce+ -9MQShgjjOEABrRcy538zB94mO5TCN9AH/eo45NUxlnlzcHyx5LHgwUk7HLUCQQCP -RhT/Ty6LiOCVqvf/Jfq2YuvOa5oEe7VX13Grt0FFV3R4a/1rGI5LWBFpoCD62yut -o8GjpUbn0JIt+H6IQuItAkAqnLiP2ZJMhDoey8+btgwiAEoUnkDfa3bNA9wncJhO -M3G4BM/bZhX5cuIaU7kPUHUS5fQeLLUfveWtbVSu1cRn +MIICXAIBAAKBgQDN3RFl8VWMEBN1Qas0w1CFcXdDEbKVNSPsqWHzHIEPoGJv+eUI +BK2lQ/Ce8nRCdelO50RsmlbcXBIrjVl6BN0RmEeEVclgCdiamYN53LBdc5KWKpKC +Kn45lCtlZodWt0hNNx1pAmh85jDKpoO9ErbCnSU1wODPqnOzdkLU7jBu5QIDAQAB +AoGBAMFEdSwGuTCoewwPXcNIRpUxJC1ENStdW1+42atarFPWV/QWYI35jmhkc0dW +Cg3HEwUvm452C2wPyEM5DbK/VCacUkcvcA1taPnNjaw4qUjxRnsVCMhIZp0sCKEW +N1LZhBcc9ThGyOvirRZfk3URqtW58nDqTKZeKZQr/d4DkNz1AkEA7QrHDZUdtdQw +znG+8gsby7hK6+4h3F7ICD+RfUVAHEdSC2L59YsEH03d/kr62t1YOxdlMmCYK9sO +7bthNibwhwJBAN5T8BDD1eRukPPGu602uAPRCfOgx6uoUGL78jTXUYGOiVG/fxkt +EIr3m4G7KKj7LKipX8eowsCVC+Fj/3+SXDMCQAnzPN3OF5wtVwsjbS991eHcT5DN +wzAb7muiN3o5sPI+8Cu4MOPkvPyPaTUmcpdDWVPJrJ7LvTeCD4NdLTx3r/sCQEsV +g+zVhoX4BUIe6sELyseXMEo0EVrapBNZzSmlUiRz89JE3vKssnqMNttwTsIK2cE4 +Ol2ek+8gJvv+nooB7tsCQCu8ZYH75hVZGONfviwHk1RD5DegNZ6pT1Or4g9N23cj +YbP58Lvi4tiQqG6zKMCosWFoDsiKKIH9qQkrygSCn3o= -----END RSA PRIVATE KEY----- diff --git a/src/test/ssl/ssl/client_ca.crt b/src/test/ssl/ssl/client_ca.crt index 003baed56c..6507bc5f07 100644 --- a/src/test/ssl/ssl/client_ca.crt +++ b/src/test/ssl/ssl/client_ca.crt @@ -1,13 +1,13 @@ -----BEGIN CERTIFICATE----- -MIIB8TCCAVoCAQIwDQYJKoZIhvcNAQEFBQAwQDE+MDwGA1UEAww1VGVzdCByb290 -IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc3VpdGUwHhcN -MTUwMjE2MjAwNjIzWhcNNDIwNzA0MjAwNjIzWjBCMUAwPgYDVQQDDDdUZXN0IENB -IGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRz -MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8wIYcmeePSXVufP/Hn/6ICEog -IUXqSNls5QIJR7Sate4iKGGTDEsRTxI4oDgkOYtcQNuEeXMf6k3xo+PRR08IEQNk -XKy1zUWds6UBFboD72SyuTE2lxJBg+xOAWgl7JSNA+g8e0Y+wfhfxGZgRuqVxVNP -9sAsfCEzGKna1l46dQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAD20Bmina/uXTLXO -oPWgpMmKwQu7Q6DPXxItCUdWgK1k1D82brRjH+usrkrmCW5BQNXOC/0zJS22ioC1 -CJbhAujH3iPaV0C3xsVSf+bvTL6OMkwV/9x9OdDN+LI2auEt4S+fP5ZTVsTXt4wA -A9cQIl2Qy88enZZAFKxrScFFlstp +MIICCDCCAXGgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBAMT4wPAYDVQQDDDVUZXN0 +IHJvb3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzdWl0 +ZTAeFw0xNjA5MTIxNjMwMDFaFw00NDAxMjkxNjMwMDFaMEIxQDA+BgNVBAMMN1Rl +c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBjbGllbnQg +Y2VydHMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMI2MXWSb8TZnCLVNYJ+ +19b4noxRmaR1W2zUxl4aTMfiPt9cK06lNY39EPBfjmb7hjxD76w8fLoV/aZ0gOgd +JXFRZvIg7SyM7QVFma0AJAIZayes+ba1odEmBEi378g0mLrjCLqZtBVHfvJxL/6x +6/flSTAn/+09vtELvvLWBePZAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZI +hvcNAQEFBQADgYEAlGC24V2TsiSlo9RIboBZTZqd0raUpKkmVbkwKyqcmecoFfCI +TCmoyJLYyUL5/e3dtn/cGDcaqxaO3qxnstxVEMSrlCGfZdZJ2oouXZMpDy9CkeOM +ypCCx9pc4EmP3mvu64f21+dNCXlhM36pZ1IokeS5jk2FIHUda+m5jlk5o6I= -----END CERTIFICATE----- diff --git a/src/test/ssl/ssl/client_ca.key b/src/test/ssl/ssl/client_ca.key index 1d636ec1b9..0e6c4649cf 100644 --- a/src/test/ssl/ssl/client_ca.key +++ b/src/test/ssl/ssl/client_ca.key @@ -1,15 +1,15 @@ -----BEGIN RSA PRIVATE KEY----- -MIICXQIBAAKBgQC8wIYcmeePSXVufP/Hn/6ICEogIUXqSNls5QIJR7Sate4iKGGT -DEsRTxI4oDgkOYtcQNuEeXMf6k3xo+PRR08IEQNkXKy1zUWds6UBFboD72SyuTE2 -lxJBg+xOAWgl7JSNA+g8e0Y+wfhfxGZgRuqVxVNP9sAsfCEzGKna1l46dQIDAQAB -AoGAMAXDmU9G7NvBtuSypvV76txBD7+nbB4ww1XYmMfXmW0kMyiW+rSr/LFjb2jE -H+NMI6KUtzW3Jq2UOyB5e+tqnbDjqZlQjnBYFnWKRa8SxsuamSAvGNLPIzur8rxm -qxOWkxlHpS+I6OXn263sWzG38ptQ3X4zK6ADcTpg7FkkYJkCQQDhCJH630aXQyia -90QM+BaKp7rhr+DHW+vVU/5pg3FrPIuvRlLo+E8iJItY3Ae+AJylK6kP6/5AJzOz -s1tXjZezAkEA1rnW4YIlWRlaJE4hXMNvF4VJO5MBtS60F4/z1kR0uVO5+JAgTZT0 -GE7ghZQ3VwdyRiWc59zXr2qkA75qtMFRNwJBAK0x82iqP6Jbxfy/Ilj4+CBvR547 -xzyourHNm5mJ2Nk4GCombdlwgzc7+SPC9RJ/VhCpsczXTTAC+//qovqXt5ECQEtF -rlwzQWBwkLb1ZKCeKg12vetSZ2DaVGuGHRZZvQlSnnjSHWDU/JSg4fgxswyhIaAR -g2WMd1eY7JIbaFChDBUCQQC46CikUDq2kfIPOkj/dsa4wLkUETrcgBx+eaZbOCgx -JU7GqsoSXxTgKcjZPm/5O/rWWtwB9XhtTuvS/NYi3aSs +MIICXQIBAAKBgQDCNjF1km/E2Zwi1TWCftfW+J6MUZmkdVts1MZeGkzH4j7fXCtO +pTWN/RDwX45m+4Y8Q++sPHy6Ff2mdIDoHSVxUWbyIO0sjO0FRZmtACQCGWsnrPm2 +taHRJgRIt+/INJi64wi6mbQVR37ycS/+sev35UkwJ//tPb7RC77y1gXj2QIDAQAB +AoGALo7NVpEvaDJ+wr74H/uGhMt/PsZFHe7gZvuvPlnxtC1hwywWWbkzWIGlcOqH +edqseIAU0eaCRB4He8MMMBjko5WZcPRrE6mR0ZqtcTSIsg2dRkXJeSbY0A8ZPLjU +xw0RiNPRwcr0zgImzMCR5dVuKOgnAGDRZiDwWefF0g6pRYECQQDwXJyT/E5EKOBY +U4tioFMVypbYlyLXjvhKIFL6wdNAVIOa0LQ+X6cPBZRIM6q+eUjodHWnjf9uFX1i +4mjegCwJAkEAztjruKRIoHAk6zQtSEv2vJhObeXg0gAHWRuCmivS/9NtqrEyGGpl +V0YCe3T257Mrw7A0TgBf7lojkrSnOT+NUQJBAM4Fs7gstTE7EEDlKz4YSd8NzQpN +UXIOe8eduUJyTI6BYmSaq0QjXOBFWfohPyMQdmu5FvfNgLls9hKCGn1Mw3ECQCMQ +tvU4NG+uUzPkRoDpD8zs7O7Id5JiGtzKQxurrjtcNk0neNyWvNNMtQME0w54W0Tz +TAqlGZ4ofbtTEL4tveECQQCFl7OS+Emv0kvUCUm4QQ/xR9bjZ80lRdRn0AwXPiPz +zzYjV0OILDlMip+WrleC99v6R2M6BJrSPQr08oxeIUzy -----END RSA PRIVATE KEY----- diff --git a/src/test/ssl/ssl/root+client.crl b/src/test/ssl/ssl/root+client.crl index 017f16b6ea..e90d4b9193 100644 --- a/src/test/ssl/ssl/root+client.crl +++ b/src/test/ssl/ssl/root+client.crl @@ -1,17 +1,17 @@ -----BEGIN X509 CRL----- MIIBBDBvMA0GCSqGSIb3DQEBBQUAMEAxPjA8BgNVBAMMNVRlc3Qgcm9vdCBDQSBm -b3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHN1aXRlFw0xNTAyMTYy -MDA2MjNaFw00MjA3MDQyMDA2MjNaMA0GCSqGSIb3DQEBBQUAA4GBACEwQiR8BKoD -eGuJKMy73AGLzNu3m7jUPWBPntGpNrUMZXNQXgtfm1t3twXbklQq4pao+9SKgT5X -guXpfoa/mPLs//gsTEx0EQV/YzsXm2xFBUtaRq46GbJK3XTfRJLw7OOzBFij1o3i -GaeVMn7IXwQBNkxQT0AAAiCUz5yz/Wvx +b3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHN1aXRlFw0xNjA5MTIx +NjMwMDFaFw00NDAxMjkxNjMwMDFaMA0GCSqGSIb3DQEBBQUAA4GBAAX612LU7WpG +0AsQy1TPAXCwQdvzCVLU2L58unheWGSZruzlaLrh/x435xJ/3a2p9ZxCPlAMTUNk ++4mz4BC14uB7nkKQlTGHH3o1qGhwFTmdXmeDDjzyBPEQkSEfcpLDampRBLaFjq/F +yaKadxocukmCcbxXdiDZePFpf7TfuoIm -----END X509 CRL----- -----BEGIN X509 CRL----- MIIBHTCBhzANBgkqhkiG9w0BAQUFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ -b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0xNTAy -MTYyMDA2MjNaFw00MjA3MDQyMDA2MjNaMBQwEgIBAhcNMTUwMjE2MjAwNjIzWjAN -BgkqhkiG9w0BAQUFAAOBgQAsrnXoVeyU8vmxPOVQrHvoMXkEvF9dOnSHIQD0ZnAW -pxbj98hCMSIW+DPIXXFebMQ6GIPp4S/w5kVpngY51paT4iztRMlV+YeyuZQuZX9a -EVgpj4t+i6hhtBHk5p9DeknERoAIsl4m2maQ58lT5UyeN4fdz4eNP6y3mQRfSTUn -bQ== +b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0xNjA5 +MTIxNjMwMDFaFw00NDAxMjkxNjMwMDFaMBQwEgIBAhcNMTYwOTEyMTYzMDAxWjAN +BgkqhkiG9w0BAQUFAAOBgQAyiU3V6ci5JR5oAZjlG7yFBhVO2TFLga5FynwHK5Wd +ML0BA/0TtTXFiPoul+zvOdqwpX8GC3IuxqgJzlxWOxl5mZzyKEtheT9RBwvBmjAe +ZjT7bFttKo/WKpztNE/2ZEDYyN87Xlpcm5UBFNhcYUjQkxuWIEvH4VOPm0iFjzm4 +tA== -----END X509 CRL----- diff --git a/src/test/ssl/ssl/root+client_ca.crt b/src/test/ssl/ssl/root+client_ca.crt index 227ab7257a..35dfac2828 100644 --- a/src/test/ssl/ssl/root+client_ca.crt +++ b/src/test/ssl/ssl/root+client_ca.crt @@ -1,26 +1,27 @@ -----BEGIN CERTIFICATE----- -MIIB9zCCAWACCQDrgvp38CAy8DANBgkqhkiG9w0BAQsFADBAMT4wPAYDVQQDDDVU -ZXN0IHJvb3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBz -dWl0ZTAeFw0xNTAyMTYyMDA2MjNaFw00MjA3MDQyMDA2MjNaMEAxPjA8BgNVBAMM -NVRlc3Qgcm9vdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0 -IHN1aXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyTfGMPAjAylLr3G7c -/QToCA3da5YZzdhd3TiQGugrJjWI4TzVB7pQ8IwDYk/jZf5TzVdEtz0B4TeIeUZl -FLW9dMpa/8SY2TETvMTuXR5MOxyw6FMEKb3buolsIksCCQ1btEIrDZ+gv9SJXcdL -ylU+VI1lKmn2fLNWWATzWrIUawIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAF2T84iG -zWKXu+3PysuPOn7RuRpMgYQKouQktErNJ8hM7Yqj3vu879zUkX1rP0HGnx7xQC3d -nBkoJ7yNDR0MwQpWo1Dj1HLKNEY6ojKJgPd0+m8nG+02yUmmOjo0oMYzJx2DQy0u -Y4qecEd6aDbqXTo+qOJ7Qm/U+U4kD9MTT6GD +MIICDjCCAXegAwIBAgIJAO2nC4XHXDkUMA0GCSqGSIb3DQEBCwUAMEAxPjA8BgNV +BAMMNVRlc3Qgcm9vdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0 +ZXN0IHN1aXRlMB4XDTE2MDkxMjE2MzAwMVoXDTQ0MDEyOTE2MzAwMVowQDE+MDwG +A1UEAww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9u +IHRlc3Qgc3VpdGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vUDilEsB5 +qI9cGWTthAIjlvr2ngFJqHmMeOgTg4JQQ24MQedh0r22nDNwm80r4RD9RCjlw/k8 +sS+chRwQclJqpE6EV65TIH0JhOKGFpx/Pz/yrru5QwEDkYcHl1QcK3xFUKbSxi/B +MCq4TZf63HkI6/VRY+1SwKF2a4pjWIaDAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQELBQADgYEAtBNiRyqydB+iy2DtoYYjsvq/q69o3UrbIhKPMlYE +TJcgWyEz4gsRMnceM/dQl0dchZ8jrAbLiAbqr7PvitjdxGSQJ8w7Gb4IawPu3UCE +TfMWiG5oYV1nHHZotEQuE+Gx4AdzSVGzLGj2xF9dSMxEQq7uPlpv67IeHEn5g3w1 +K5Y= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- -MIIB8TCCAVoCAQIwDQYJKoZIhvcNAQEFBQAwQDE+MDwGA1UEAww1VGVzdCByb290 -IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc3VpdGUwHhcN -MTUwMjE2MjAwNjIzWhcNNDIwNzA0MjAwNjIzWjBCMUAwPgYDVQQDDDdUZXN0IENB -IGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRz -MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8wIYcmeePSXVufP/Hn/6ICEog -IUXqSNls5QIJR7Sate4iKGGTDEsRTxI4oDgkOYtcQNuEeXMf6k3xo+PRR08IEQNk -XKy1zUWds6UBFboD72SyuTE2lxJBg+xOAWgl7JSNA+g8e0Y+wfhfxGZgRuqVxVNP -9sAsfCEzGKna1l46dQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAD20Bmina/uXTLXO -oPWgpMmKwQu7Q6DPXxItCUdWgK1k1D82brRjH+usrkrmCW5BQNXOC/0zJS22ioC1 -CJbhAujH3iPaV0C3xsVSf+bvTL6OMkwV/9x9OdDN+LI2auEt4S+fP5ZTVsTXt4wA -A9cQIl2Qy88enZZAFKxrScFFlstp +MIICCDCCAXGgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBAMT4wPAYDVQQDDDVUZXN0 +IHJvb3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzdWl0 +ZTAeFw0xNjA5MTIxNjMwMDFaFw00NDAxMjkxNjMwMDFaMEIxQDA+BgNVBAMMN1Rl +c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBjbGllbnQg +Y2VydHMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMI2MXWSb8TZnCLVNYJ+ +19b4noxRmaR1W2zUxl4aTMfiPt9cK06lNY39EPBfjmb7hjxD76w8fLoV/aZ0gOgd +JXFRZvIg7SyM7QVFma0AJAIZayes+ba1odEmBEi378g0mLrjCLqZtBVHfvJxL/6x +6/flSTAn/+09vtELvvLWBePZAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZI +hvcNAQEFBQADgYEAlGC24V2TsiSlo9RIboBZTZqd0raUpKkmVbkwKyqcmecoFfCI +TCmoyJLYyUL5/e3dtn/cGDcaqxaO3qxnstxVEMSrlCGfZdZJ2oouXZMpDy9CkeOM +ypCCx9pc4EmP3mvu64f21+dNCXlhM36pZ1IokeS5jk2FIHUda+m5jlk5o6I= -----END CERTIFICATE----- diff --git a/src/test/ssl/ssl/root+server.crl b/src/test/ssl/ssl/root+server.crl index ac31888a93..096b48ccd1 100644 --- a/src/test/ssl/ssl/root+server.crl +++ b/src/test/ssl/ssl/root+server.crl @@ -1,17 +1,17 @@ -----BEGIN X509 CRL----- MIIBBDBvMA0GCSqGSIb3DQEBBQUAMEAxPjA8BgNVBAMMNVRlc3Qgcm9vdCBDQSBm -b3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHN1aXRlFw0xNTAyMTYy -MDA2MjNaFw00MjA3MDQyMDA2MjNaMA0GCSqGSIb3DQEBBQUAA4GBACEwQiR8BKoD -eGuJKMy73AGLzNu3m7jUPWBPntGpNrUMZXNQXgtfm1t3twXbklQq4pao+9SKgT5X -guXpfoa/mPLs//gsTEx0EQV/YzsXm2xFBUtaRq46GbJK3XTfRJLw7OOzBFij1o3i -GaeVMn7IXwQBNkxQT0AAAiCUz5yz/Wvx +b3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHN1aXRlFw0xNjA5MTIx +NjMwMDFaFw00NDAxMjkxNjMwMDFaMA0GCSqGSIb3DQEBBQUAA4GBAAX612LU7WpG +0AsQy1TPAXCwQdvzCVLU2L58unheWGSZruzlaLrh/x435xJ/3a2p9ZxCPlAMTUNk ++4mz4BC14uB7nkKQlTGHH3o1qGhwFTmdXmeDDjzyBPEQkSEfcpLDampRBLaFjq/F +yaKadxocukmCcbxXdiDZePFpf7TfuoIm -----END X509 CRL----- -----BEGIN X509 CRL----- MIIBHTCBhzANBgkqhkiG9w0BAQUFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ -b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0xNTAy -MTYyMDA2MjNaFw00MjA3MDQyMDA2MjNaMBQwEgIBBhcNMTUwMjE2MjAwNjIzWjAN -BgkqhkiG9w0BAQUFAAOBgQB1c54zLMueMtLiSmBT6kfXJe9o3Krd2n774g7kzNlR -DeLpCHeUvyLF0m8YK09vbLv2W0r6VQnbjyQGr9xyweRLLtOXc0FIDsTO8g/jvMSq -Q9zITuqWiCHRbNhi2B3HPo2NsrfA+tQEAZvMUgnynlerNvGkLWQZeC2UsxrrSs4t -9Q== +b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0xNjA5 +MTIxNjMwMDFaFw00NDAxMjkxNjMwMDFaMBQwEgIBBhcNMTYwOTEyMTYzMDAxWjAN +BgkqhkiG9w0BAQUFAAOBgQAm5J6912hKDUWXyu3yCEk1j3KICE2J42ZjFRvxBNdO +Zhv/iBjyFI6TmCVJqoe4GJbNG78xmNEl3/2ZUavG/aD0Z3xGu2xm0p+3Uh2zhfDQ +VEdlgFNKNItS0AtKvoduoZUXKnz3Ft09yLmz9yHLu6EslIsYryi+wnZ5DwUBj5Ec +WA== -----END X509 CRL----- diff --git a/src/test/ssl/ssl/root+server_ca.crt b/src/test/ssl/ssl/root+server_ca.crt index 4a33f77ef6..8b548b46a5 100644 --- a/src/test/ssl/ssl/root+server_ca.crt +++ b/src/test/ssl/ssl/root+server_ca.crt @@ -1,26 +1,27 @@ -----BEGIN CERTIFICATE----- -MIIB9zCCAWACCQDrgvp38CAy8DANBgkqhkiG9w0BAQsFADBAMT4wPAYDVQQDDDVU -ZXN0IHJvb3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBz -dWl0ZTAeFw0xNTAyMTYyMDA2MjNaFw00MjA3MDQyMDA2MjNaMEAxPjA8BgNVBAMM -NVRlc3Qgcm9vdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0 -IHN1aXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyTfGMPAjAylLr3G7c -/QToCA3da5YZzdhd3TiQGugrJjWI4TzVB7pQ8IwDYk/jZf5TzVdEtz0B4TeIeUZl -FLW9dMpa/8SY2TETvMTuXR5MOxyw6FMEKb3buolsIksCCQ1btEIrDZ+gv9SJXcdL -ylU+VI1lKmn2fLNWWATzWrIUawIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAF2T84iG -zWKXu+3PysuPOn7RuRpMgYQKouQktErNJ8hM7Yqj3vu879zUkX1rP0HGnx7xQC3d -nBkoJ7yNDR0MwQpWo1Dj1HLKNEY6ojKJgPd0+m8nG+02yUmmOjo0oMYzJx2DQy0u -Y4qecEd6aDbqXTo+qOJ7Qm/U+U4kD9MTT6GD +MIICDjCCAXegAwIBAgIJAO2nC4XHXDkUMA0GCSqGSIb3DQEBCwUAMEAxPjA8BgNV +BAMMNVRlc3Qgcm9vdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0 +ZXN0IHN1aXRlMB4XDTE2MDkxMjE2MzAwMVoXDTQ0MDEyOTE2MzAwMVowQDE+MDwG +A1UEAww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9u +IHRlc3Qgc3VpdGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vUDilEsB5 +qI9cGWTthAIjlvr2ngFJqHmMeOgTg4JQQ24MQedh0r22nDNwm80r4RD9RCjlw/k8 +sS+chRwQclJqpE6EV65TIH0JhOKGFpx/Pz/yrru5QwEDkYcHl1QcK3xFUKbSxi/B +MCq4TZf63HkI6/VRY+1SwKF2a4pjWIaDAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQELBQADgYEAtBNiRyqydB+iy2DtoYYjsvq/q69o3UrbIhKPMlYE +TJcgWyEz4gsRMnceM/dQl0dchZ8jrAbLiAbqr7PvitjdxGSQJ8w7Gb4IawPu3UCE +TfMWiG5oYV1nHHZotEQuE+Gx4AdzSVGzLGj2xF9dSMxEQq7uPlpv67IeHEn5g3w1 +K5Y= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- -MIIB8TCCAVoCAQEwDQYJKoZIhvcNAQEFBQAwQDE+MDwGA1UEAww1VGVzdCByb290 -IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc3VpdGUwHhcN -MTUwMjE2MjAwNjIzWhcNNDIwNzA0MjAwNjIzWjBCMUAwPgYDVQQDDDdUZXN0IENB -IGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRz -MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDAYtajRx8vM6IB0SLZsAhTD0Y -VHM+/+t0a4m3JXolJBbo9/B2/WAN0IH1E2zmlalLc3JBmGsH1a8U5ZlRow3p2ODL -rFra9FbOl0wekmRFvZeaRln/99dpI5itVpL97QPHO8QMMK1IsyurFA5GfuPOBx9P -i0MvzsT0tYsRvR929QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAJw4ngOYElfyMYkS -K6bOgMosrBoX8ns6jQgdXEzf7QOIa110bs6nD+XeJeKmzUAZ3wumXBTalPaiqkEz -bq4nlsEs1phvj0Coy5eehjV3DB8bDLEneOlV5N9y4Z4VO1BrhX61bLiPXBRp1MZR -I0sCdxhswSrq02/OuFGe6mqrSBBI +MIICCDCCAXGgAwIBAgIBATANBgkqhkiG9w0BAQUFADBAMT4wPAYDVQQDDDVUZXN0 +IHJvb3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzdWl0 +ZTAeFw0xNjA5MTIxNjMwMDFaFw00NDAxMjkxNjMwMDFaMEIxQDA+BgNVBAMMN1Rl +c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzZXJ2ZXIg +Y2VydHMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKpkEBIZexm3YZ94RA+c +vUREqvLgECfHlP9BbkXySFPGWcAPt/0uSW62eVS3UFcB9083W4w/uilL75PXDHV1 +37fyq+6LHCYE5TinzVr5ECAtQMpIzlKkAuAPq3mTa1fklwT/MCz/PKGAljs2o95w +mNyEJwTchOQ52fZjFexRiarNAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZI +hvcNAQEFBQADgYEAP1ZhwGxsL7GTNxfs2qwYCjsF2zYSjCPXtwJnKFu5ayGxz6dB +paspokWFCglP1PwPAmINHeqp669WNnAmC5EixdTy2jcnod8NB6RlkOqJmNzVPhvO +cTZXxKd3awOzz0+IJ2bMcC9JPXs8phhRuRgvSfKTTZVtdcFmVF/HYIrBB5Y= -----END CERTIFICATE----- diff --git a/src/test/ssl/ssl/root.crl b/src/test/ssl/ssl/root.crl index 65e470cce1..2158728f85 100644 --- a/src/test/ssl/ssl/root.crl +++ b/src/test/ssl/ssl/root.crl @@ -1,8 +1,8 @@ -----BEGIN X509 CRL----- MIIBBDBvMA0GCSqGSIb3DQEBBQUAMEAxPjA8BgNVBAMMNVRlc3Qgcm9vdCBDQSBm -b3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHN1aXRlFw0xNTAyMTYy -MDA2MjNaFw00MjA3MDQyMDA2MjNaMA0GCSqGSIb3DQEBBQUAA4GBACEwQiR8BKoD -eGuJKMy73AGLzNu3m7jUPWBPntGpNrUMZXNQXgtfm1t3twXbklQq4pao+9SKgT5X -guXpfoa/mPLs//gsTEx0EQV/YzsXm2xFBUtaRq46GbJK3XTfRJLw7OOzBFij1o3i -GaeVMn7IXwQBNkxQT0AAAiCUz5yz/Wvx +b3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHN1aXRlFw0xNjA5MTIx +NjMwMDFaFw00NDAxMjkxNjMwMDFaMA0GCSqGSIb3DQEBBQUAA4GBAAX612LU7WpG +0AsQy1TPAXCwQdvzCVLU2L58unheWGSZruzlaLrh/x435xJ/3a2p9ZxCPlAMTUNk ++4mz4BC14uB7nkKQlTGHH3o1qGhwFTmdXmeDDjzyBPEQkSEfcpLDampRBLaFjq/F +yaKadxocukmCcbxXdiDZePFpf7TfuoIm -----END X509 CRL----- diff --git a/src/test/ssl/ssl/root_ca.crt b/src/test/ssl/ssl/root_ca.crt index e491d7317c..fab7a68907 100644 --- a/src/test/ssl/ssl/root_ca.crt +++ b/src/test/ssl/ssl/root_ca.crt @@ -1,13 +1,14 @@ -----BEGIN CERTIFICATE----- -MIIB9zCCAWACCQDrgvp38CAy8DANBgkqhkiG9w0BAQsFADBAMT4wPAYDVQQDDDVU -ZXN0IHJvb3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBz -dWl0ZTAeFw0xNTAyMTYyMDA2MjNaFw00MjA3MDQyMDA2MjNaMEAxPjA8BgNVBAMM -NVRlc3Qgcm9vdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0 -IHN1aXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyTfGMPAjAylLr3G7c -/QToCA3da5YZzdhd3TiQGugrJjWI4TzVB7pQ8IwDYk/jZf5TzVdEtz0B4TeIeUZl -FLW9dMpa/8SY2TETvMTuXR5MOxyw6FMEKb3buolsIksCCQ1btEIrDZ+gv9SJXcdL -ylU+VI1lKmn2fLNWWATzWrIUawIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAF2T84iG -zWKXu+3PysuPOn7RuRpMgYQKouQktErNJ8hM7Yqj3vu879zUkX1rP0HGnx7xQC3d -nBkoJ7yNDR0MwQpWo1Dj1HLKNEY6ojKJgPd0+m8nG+02yUmmOjo0oMYzJx2DQy0u -Y4qecEd6aDbqXTo+qOJ7Qm/U+U4kD9MTT6GD +MIICDjCCAXegAwIBAgIJAO2nC4XHXDkUMA0GCSqGSIb3DQEBCwUAMEAxPjA8BgNV +BAMMNVRlc3Qgcm9vdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0 +ZXN0IHN1aXRlMB4XDTE2MDkxMjE2MzAwMVoXDTQ0MDEyOTE2MzAwMVowQDE+MDwG +A1UEAww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9u +IHRlc3Qgc3VpdGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vUDilEsB5 +qI9cGWTthAIjlvr2ngFJqHmMeOgTg4JQQ24MQedh0r22nDNwm80r4RD9RCjlw/k8 +sS+chRwQclJqpE6EV65TIH0JhOKGFpx/Pz/yrru5QwEDkYcHl1QcK3xFUKbSxi/B +MCq4TZf63HkI6/VRY+1SwKF2a4pjWIaDAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQELBQADgYEAtBNiRyqydB+iy2DtoYYjsvq/q69o3UrbIhKPMlYE +TJcgWyEz4gsRMnceM/dQl0dchZ8jrAbLiAbqr7PvitjdxGSQJ8w7Gb4IawPu3UCE +TfMWiG5oYV1nHHZotEQuE+Gx4AdzSVGzLGj2xF9dSMxEQq7uPlpv67IeHEn5g3w1 +K5Y= -----END CERTIFICATE----- diff --git a/src/test/ssl/ssl/root_ca.key b/src/test/ssl/ssl/root_ca.key index e5cddee941..b79f4b0ef7 100644 --- a/src/test/ssl/ssl/root_ca.key +++ b/src/test/ssl/ssl/root_ca.key @@ -1,15 +1,15 @@ -----BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQCyTfGMPAjAylLr3G7c/QToCA3da5YZzdhd3TiQGugrJjWI4TzV -B7pQ8IwDYk/jZf5TzVdEtz0B4TeIeUZlFLW9dMpa/8SY2TETvMTuXR5MOxyw6FME -Kb3buolsIksCCQ1btEIrDZ+gv9SJXcdLylU+VI1lKmn2fLNWWATzWrIUawIDAQAB -AoGAQ8TmMuO6e/QqUiUlKe8tBzfQdUDn+wTG4N4tGnBvn77VCCJ7qYhXY14aCUs7 -i/V/FcDtE1wF3woHvmJBxDd731TILBhuqn3UIWJafoiezlhqwR2uvTfnWh62N15w -xlmGDuPwXMtQCazbcD6I9hgbADBbMmsyym8cuwN+hxU7bKECQQDfzkAN0RNI/m31 -7GVjOvWrd3+brwf19jXtxhzJCRThjyVyCMYfG9ELP/u76aNCMs2otn2K49Vd0s5A -rG6uN4Z7AkEAy/QXExktz0YxaTMHYHafwSkraoygKVUIoxWm2AHhNXdSY1M8AqkL -6VqGpNgcwiEE0QJHG0MFjB0tZAe9/kq+0QJAWqc+htozR5PXko+ImeMd87BZvgPt -45ExUvi2XDAThzHmZwRqy9sGl9n466q9eGj/qOEShRm4KWLkLIor4uGW1QJAbj2h -u1EA0ei/DH3ontt/vojiTtV0POMZqA0sAdYCRUQZ5FY5ObbmGVw1KyUlZkkysUbp -6HJxrSqYPllw+OKuAQJBAN54Aep6BvzI+arJrOm2Un5l27jfPbuKmvJWjus1mU+e -HkaXYUF31/LIN4gNeu0ULbCSKpvk00UaBfjbwvfLmAk= +MIICXQIBAAKBgQDOL1A4pRLAeaiPXBlk7YQCI5b69p4BSah5jHjoE4OCUENuDEHn +YdK9tpwzcJvNK+EQ/UQo5cP5PLEvnIUcEHJSaqROhFeuUyB9CYTihhacfz8/8q67 +uUMBA5GHB5dUHCt8RVCm0sYvwTAquE2X+tx5COv1UWPtUsChdmuKY1iGgwIDAQAB +AoGAE+iNnmqR/PPCStVhvlUQwgQdt+3II+ew1MuzgPUhZZvKZv3X/zd62cagHndp +E86A1NsfkbNd0NsDYM2ELMmJwC8cTKFw2WyB9t3v0GTtVG8e338QdrrTOvawO3F4 +f4tCESvBgY4qmJMuvicMqLey9fAXc8ul+wocRRYx4r1Gc4ECQQDpgATrxdy7vkf0 +KFxO6htUnKB/V5Q56qvlMzXKHSiwnCMKRYPY7NAxLVNVTmH3ACaBFCvg1f7++Yn7 +r5zEEcuLAkEA4g17NFfFZmBz37C9Cu1W6cX0ps0MgI9w38bEYy8LOk0liUGd+Qit +AKpu8KNOb3v5FQ5TL25EaX1VhM78OE9v6QJBAIFHZPIZGY5E2te+pOT4Tut40I/Q +sHukh0meIdDmdgnaWLguJsKq0tX3b2USwcCcr7TVszmHoegPxyq3X0dbRuMCQQDW +7OhyWO1XrGcfjKQAyq4zMMKvARBc/4TbTtoUT3tGYGlK+jdfuw76LhGy/CIsP1wQ +2ADhfN7QyZjQ4BfQ1j5ZAkBggAL3a/4+KjsPesTxWjlufmoL9QG8Bgaj1tWBYDzX +5CQCWYRPVE7aV+Jh1NDHgToQsziZtvRL16l+GivYEnTX -----END RSA PRIVATE KEY----- diff --git a/src/test/ssl/ssl/server-cn-and-alt-names.crt b/src/test/ssl/ssl/server-cn-and-alt-names.crt index 04f9b58ddc..ef7fd66b7b 100644 --- a/src/test/ssl/ssl/server-cn-and-alt-names.crt +++ b/src/test/ssl/ssl/server-cn-and-alt-names.crt @@ -1,15 +1,15 @@ -----BEGIN CERTIFICATE----- MIICSTCCAbKgAwIBAgIBATANBgkqhkiG9w0BAQUFADBCMUAwPgYDVQQDDDdUZXN0 IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNl -cnRzMB4XDTE1MDIxNjIwMDYyM1oXDTQyMDcwNDIwMDYyM1owRjEeMBwGA1UECwwV +cnRzMB4XDTE2MDkxMjE2MzAwMVoXDTQ0MDEyOTE2MzAwMVowRjEeMBwGA1UECwwV UG9zdGdyZVNRTCB0ZXN0IHN1aXRlMSQwIgYDVQQDDBtjb21tb24tbmFtZS5wZy1z -c2x0ZXN0LnRlc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMH7OtRvW0qP -gYDMInkd0mgKnqhexEUnTf90mGihzd4sw91J0bJBnC/wfLmpP9a1wOwvAma1GSJ2 -1lLFrSC8bXkT+6nIiqXlFK4HqW5w3PktbO1InujFS1PoxXOdlSwdcIzQ+VDk3Kv3 -IVnCq9w8rcchthnSb+3kYx5QjA0Gb1vhAgMBAAGjSzBJMEcGA1UdEQRAMD6CHWRu +c2x0ZXN0LnRlc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALsIeqZ7pHER +w0nqVgePeSDdr7/fXMNtF/yFk4ZYUXGLuyzterEUaxeSYB5jmNAeY7ANRjbMb5N9 +mvoHHUsz0AzVNFihcSvP5nB9xIAEypMUF7qoXNVgXbG33gFKLbfNWqbuLUqaiWCb ++B7ahLVPTbm16Kwaw0sEMcSALED/lsMfAgMBAAGjSzBJMEcGA1UdEQRAMD6CHWRu czEuYWx0LW5hbWUucGctc3NsdGVzdC50ZXN0gh1kbnMyLmFsdC1uYW1lLnBnLXNz -bHRlc3QudGVzdDANBgkqhkiG9w0BAQUFAAOBgQCBBVEMkprc18bqWcZ8P93JGc1r -lJoSARfIkBuAkJODyQHJ6kp6fq1kuR8seax35VPNXIvBlPqXoS9zvXYVmF/qOJEk -TtW8YAACZywn02dM5CQRS7T9HCcBJeFUHxbGcBCY+AqzbhM+tGii6UnogjvqdKje -ApVvu0m4MsSn+WWQlw== +bHRlc3QudGVzdDANBgkqhkiG9w0BAQUFAAOBgQAcbbxoyusUuTKq+hz7wLiJfEis +UHrq8BwakaOP0zTln8XBT3uvNeumjQQGciqMNsV8QQ0xT3XadO7R9ix5V5IzTxnC +q4s1xKxSJsmVcPf9Ql43ev3S+lRnyw1ws4lfe9hOdKfOopjHpa+D2VW8/iRfhNj2 +PO7iYMyUZKXB0ynKTw== -----END CERTIFICATE----- diff --git a/src/test/ssl/ssl/server-cn-and-alt-names.key b/src/test/ssl/ssl/server-cn-and-alt-names.key index 7577e6f2d4..a1ca8f4286 100644 --- a/src/test/ssl/ssl/server-cn-and-alt-names.key +++ b/src/test/ssl/ssl/server-cn-and-alt-names.key @@ -1,15 +1,15 @@ -----BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDB+zrUb1tKj4GAzCJ5HdJoCp6oXsRFJ03/dJhooc3eLMPdSdGy -QZwv8Hy5qT/WtcDsLwJmtRkidtZSxa0gvG15E/upyIql5RSuB6lucNz5LWztSJ7o -xUtT6MVznZUsHXCM0PlQ5Nyr9yFZwqvcPK3HIbYZ0m/t5GMeUIwNBm9b4QIDAQAB -AoGAVOp2gWJR81zI0yoJeT2dyt/DPm9lueQP1+EhisQyC61K/IcBHehsx+udneTC -RmqADqQxh+aFHzoobkmMlUUHInIF8gQe/brw6s27BemUSrT2M47BrZINnOKTvhVa -6xnqcD46DkdYE3z4dF2DsZ+uzgw/bO4sksw/yus2C+2tLlUCQQD8dy5+Ivw7AUVW -H5VNR0joFlR8xeJA8FA460+UhNle/oDtqEjq/YDotHdOnd8EePpR24/c3cMVfXj3 -uqTnKyo7AkEAxLJx8D55ZiDQYprL9DWONVuEk5WZJZIgCNRX+hlymf00Hfm67cue -aD0Y8G1DA5vNywNVpUihdm9wDFPz/PSUkwJAevnG4NRDzq4QyyG5RRpLDhoKb3io -e/9S5FbivbJ0e4w22wzU7/opt7BoSRgnUPNo40Sy79/precfbHQy7ROejwJASovu -zsR+sgwhrh1Iywc5HFPRDTYXUrvs1CvWI/1dB6uFAw9QnysaoBr3xrdCPK3h8t0S -qo+6Ue6uIp32zJnNbQJBALLb34EY6Au69ztILcUpYgzTE8wmXtBTt4RBQDMIw+F1 -ZBw3e3tZjKmOPJySq5v8jyNF5L3s5gd/GRtPRCTkOfo= +MIICXQIBAAKBgQC7CHqme6RxEcNJ6lYHj3kg3a+/31zDbRf8hZOGWFFxi7ss7Xqx +FGsXkmAeY5jQHmOwDUY2zG+TfZr6Bx1LM9AM1TRYoXErz+ZwfcSABMqTFBe6qFzV +YF2xt94BSi23zVqm7i1Kmolgm/ge2oS1T025teisGsNLBDHEgCxA/5bDHwIDAQAB +AoGAB0Hh+HnNvLFywXh9VBfGHHddrXVOVSrzhlHskob0yhIg9jJU03A2Y5jDcApv +UIwNVDR/p/qwzalPDSqfgV6GURgqzS/If+qKN7aPiTZPwTB1I9zNVLf07EaZjS08 +IppwpVbFnrJww1WP/P5VRZxnkbhZ0ClZWm3Bo/V6Axi5O8kCQQDitdVoEerONTq3 +a3n6lzPm473l0P+gZdqbSeqRO59c0uMvE3aIged6cPQZ7WIAivID7Wh7AP0zHetz +NQOCw1fNAkEA0zJfIDyNtkcuPzm9Eg5gQzdgusZ455Eij3VoSRJTX5fLDaBf/lo+ +z6bsGqmnGK8JVtKkpvSPV0L9R47KDCUCmwJBAKlWmKi7eV+9crY+mUYMWsBDrDxU ++Bue+MK1W3hPyKFVBEzNhORB490ZMbuMDH/LSSqV0kzOWFIuLwhGuPCbaKECQEeU +VvFSFKWm0mHTa+VmwfGGH16uTeQOKKx+mm3JrEBF7igcJuzKIWe3p2YSAfQ3vu6S +TgPX940Xw0gxeQFMuekCQQDHuGhGdj3faCSkW8/dIkAX37/VkOxSvaZGpmDxclZL +g21KLL9Ng6wI56wvMo61TCK5gEPnpmDB8H5l3VULt9Yn -----END RSA PRIVATE KEY----- diff --git a/src/test/ssl/ssl/server-cn-only.crt b/src/test/ssl/ssl/server-cn-only.crt index edf0bb895e..9891072335 100644 --- a/src/test/ssl/ssl/server-cn-only.crt +++ b/src/test/ssl/ssl/server-cn-only.crt @@ -1,13 +1,13 @@ -----BEGIN CERTIFICATE----- MIIB/DCCAWWgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBCMUAwPgYDVQQDDDdUZXN0 IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNl -cnRzMB4XDTE1MDIxNjIwMDYyM1oXDTQyMDcwNDIwMDYyM1owRjEeMBwGA1UECwwV +cnRzMB4XDTE2MDkxMjE2MzAwMVoXDTQ0MDEyOTE2MzAwMVowRjEeMBwGA1UECwwV UG9zdGdyZVNRTCB0ZXN0IHN1aXRlMSQwIgYDVQQDDBtjb21tb24tbmFtZS5wZy1z -c2x0ZXN0LnRlc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOqxI3Umy7P+ -FqPSenj/4SgwJgKMM73Q0tJvaDNXb1ipfAUHbvnKCNUs693YjRdZwTAVXsYq8btC -ja/4L24FLCNktLzQfxmVuueMgi7HuYevxVbhOXhxuy8cbTeC6FZj3F6vU7Obg5rM -L6FNzVljbtx/YA2lM4H/lWafTp0mXnmFAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEA -DLLwuxmM5ReGFO6L95kxK++vFa7oXNBw8JxagzqfnF85N2leNbpQxxsDS9U/Bavu -D0okKJR1ezdWlT0AwJcOtnt/X/qoxVFo35rIEjDZv4rWveiPwe3BeYm2tWLRHgKI -6NrPD+kXXqGFPHobbXBPvE2MrW4p+ojD0DTeO8ZXjj4= +c2x0ZXN0LnRlc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALkR7DNyRnAE +D7ZxnsfOPQ55QB0nM2onJmVZkG4EeqQJ6GZHJym7pHHwbww+dgXvlNzkv2SOvA+Y +q8TXgYvSiKhZ4N4ReSWWZ71P+RqJXpSrj6K2mVKOw0Rno9kMt0370bQOnkvSQY9B +WxJbxji2ks3oj4wma+1zje3i46IlwoYHAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEA +G2ZMgJnCz3/kDv30Uun3YzVktMW4O1y9AbFR1YrbHM8xvVGFLpp9z2PVYOKwKeND +oS3UjW/wJynAT3xPwY3Zg6GbTqx2Fu8BG9bb73RK2af1IT8sB1Pxj8t4kZr0egaO +m8TIbipkZNVakwG9idiVYjn4CusqYthFsOKW+OHiM3I= -----END CERTIFICATE----- diff --git a/src/test/ssl/ssl/server-cn-only.key b/src/test/ssl/ssl/server-cn-only.key index 9037a9bb8b..f58af68a83 100644 --- a/src/test/ssl/ssl/server-cn-only.key +++ b/src/test/ssl/ssl/server-cn-only.key @@ -1,15 +1,15 @@ -----BEGIN RSA PRIVATE KEY----- -MIICXgIBAAKBgQDqsSN1Jsuz/haj0np4/+EoMCYCjDO90NLSb2gzV29YqXwFB275 -ygjVLOvd2I0XWcEwFV7GKvG7Qo2v+C9uBSwjZLS80H8ZlbrnjIIux7mHr8VW4Tl4 -cbsvHG03guhWY9xer1Ozm4OazC+hTc1ZY27cf2ANpTOB/5Vmn06dJl55hQIDAQAB -AoGBAN1Vp9oBd5VNqS5g/y4EK+VJ218FuHpoaZsahEv/Rrx4QsU/aHLdDg11qxBy -/UUrWZ2uWc5Mi+ON9bAiQSDicec0ybYD5+Nn3Yv6v82J4Lr6Nlg6lsMSXxr0tfh7 -1Jh4EZWkIvMilSyo2ft2bP5o/rBCiIKXPzLDOmaoYUurNwPVAkEA+uR8icow3Ig4 -DXatPDIVaCr66cfndBSmbXe9M0eY23ic/8VNqjyuo3CNLOqBupl5teZTv6dTLXY4 -9RD5U3x70wJBAO94OTptH8Mp5aJX5PX6x2eggydTBnSNUyZZp1FquFpE5GRhyd5O -RO7V4f0fcZCyuJcZI9xNvkqLIC8WzyZ8FkcCQQCwJk2d/HxzyZv5L/KPCebnvQ1v -p+/EG1+CCgingUQ8CyHHngJaXMKMc9Ba0ccFeQ3v/WedbuBCUffJcAJtcEALAkA7 -fIn60ZDKUmYQ5fSihiFyxJTP9/fqjBDTvgGqX/BbvDFgHkqfRqIpEkiJMH5ti3f/ -UOdvmoBi1Byyld/vl3ORAkEAzruQTKAG5HeD+XPijO1qtaNXAiyxLr49FkJsm/Yx -sgM/ZMbLmYZwu6JHt3+Tvo1++scUuwrsYCUmTP1+Ca37Uw== +MIICXQIBAAKBgQC5EewzckZwBA+2cZ7Hzj0OeUAdJzNqJyZlWZBuBHqkCehmRycp +u6Rx8G8MPnYF75Tc5L9kjrwPmKvE14GL0oioWeDeEXkllme9T/kaiV6Uq4+itplS +jsNEZ6PZDLdN+9G0Dp5L0kGPQVsSW8Y4tpLN6I+MJmvtc43t4uOiJcKGBwIDAQAB +AoGBAJzj6r86UyhG6SMbcyWjWvNYKtgMEXQeOFiW8u+xcF57375E95hTcHb/AsT4 +dolVr3cLnI0cy6TVIli+8R2dnybVxgdV/NSWLk69HDb+YPh2cEA7TxAb3vSfMdyJ +T4uC6ibyjAaWdmEDYhuhP45ALf8MKYHEdtmpdGVU0TtrcZThAkEA8oERu+OPXEVO +OG6yJh6JKwrGOv5jEVK9G2v9ns0LiJDhnDc/wTv5/zq6GIQlWDViV7dmtYPedOAr +Zk3e4HNUHwJBAMNemFSkwMew7jI0yQKuHLN3/kKQXi70ZGXHr6i6hzlcxgoa68zq +Ayx9/4m3D4ucwzSTQo/84p7PA+JXTGLu0RkCQF07WgIOXtNuob/4bu1Q2BOANO4B +Vz0VvjaIsh0XX9PFP7e7VfuIf3isr1c1ltXu0DxA+m/WnvP4KzdNwN4x+KkCQCrP +mr/Jjnjzu26DBJ0yvBVTsQKzEgBmC24GMObfYOxf+QGT3qH7kZB5V7q8w4pLYrct +ocNdnedA49AAYzu2q1kCQQDR5DJ+L/kM02pV4LLhbQ6U6nhBKDPXY26nob/TAtwq +eODDcDiceMGKThwwnGEjEeO2w4uZEM124v5sJgZtlByD -----END RSA PRIVATE KEY----- diff --git a/src/test/ssl/ssl/server-multiple-alt-names.crt b/src/test/ssl/ssl/server-multiple-alt-names.crt index d15c911e18..c330d4d422 100644 --- a/src/test/ssl/ssl/server-multiple-alt-names.crt +++ b/src/test/ssl/ssl/server-multiple-alt-names.crt @@ -1,15 +1,15 @@ -----BEGIN CERTIFICATE----- MIICPzCCAaigAwIBAgIBBDANBgkqhkiG9w0BAQUFADBCMUAwPgYDVQQDDDdUZXN0 IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNl -cnRzMB4XDTE1MDIxNjIwMDYyM1oXDTQyMDcwNDIwMDYyM1owIDEeMBwGA1UECwwV +cnRzMB4XDTE2MDkxMjE2MzAwMVoXDTQ0MDEyOTE2MzAwMVowIDEeMBwGA1UECwwV UG9zdGdyZVNRTCB0ZXN0IHN1aXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB -gQC0Bkarg2DSU/0+vFG5dgmxV38SSC006t69zkFmrkUMIEg0iuj4I44qlOf/6EP4 -++RfDwQpiUNRTQmTNwDmjmc1bsXysIvVPzIDKEgpvqI82T1sLpF14PogoNlAzdpu -CnpnU+QTUS3Ic5dhxK8YHyVtsG5nfF/3u1S15p5UaPGiOwIDAQABo2cwZTBjBgNV +gQC3KEGfUWKDHb5tzwJ58o5GaFwUctjQxOg4Wtf6TvBRnuAd7VYAVFRtdPLnH9k5 +dHDUpMw1bHx4nUmbnphtLJDS8VVowLyjKGAU/uOuQidUk0nCSllHPaE8soBZPV8x +BwG7TQ47GO7Jg4dmcTLF+E4m3YbzHglOmoN5+vrwWSJnLQIDAQABo2cwZTBjBgNV HREEXDBagh1kbnMxLmFsdC1uYW1lLnBnLXNzbHRlc3QudGVzdIIdZG5zMi5hbHQt bmFtZS5wZy1zc2x0ZXN0LnRlc3SCGioud2lsZGNhcmQucGctc3NsdGVzdC50ZXN0 -MA0GCSqGSIb3DQEBBQUAA4GBAASEAOEwDFE4qCPXJPpEzma7+vRqVFedWPXFXoW0 -R3HCGlvYJKwnlgxf41ipWHWmJPHLdg+KVJtlfRQ5U2SIIn7yjr3Wk+apcvWMvDpQ -lkIVTwCmSINnj8GjQqgJsHD6I75edRaMQk3PlurzdBWJp6oz+UWbYvGDRDC4pHWu -nLhZ +MA0GCSqGSIb3DQEBBQUAA4GBAANowuGrcHzwfVLHa1PC4W0obG2it61VaA+OFHwv +OAloZTbbNslSh/RGyrD2ZafRZpZNhjNB3JRIt7bv5Y0j5YP7CQkp2ucD90V580Pe +vuoP+jZ/f5ZIC2ffiG9ofPxQdJEHy63GWHSH668rWQBc12GhHqgwZXNoWRMJxVrj +EZqd -----END CERTIFICATE----- diff --git a/src/test/ssl/ssl/server-multiple-alt-names.key b/src/test/ssl/ssl/server-multiple-alt-names.key index 64266e3b81..5969b9b5ce 100644 --- a/src/test/ssl/ssl/server-multiple-alt-names.key +++ b/src/test/ssl/ssl/server-multiple-alt-names.key @@ -1,15 +1,15 @@ -----BEGIN RSA PRIVATE KEY----- -MIICXQIBAAKBgQC0Bkarg2DSU/0+vFG5dgmxV38SSC006t69zkFmrkUMIEg0iuj4 -I44qlOf/6EP4++RfDwQpiUNRTQmTNwDmjmc1bsXysIvVPzIDKEgpvqI82T1sLpF1 -4PogoNlAzdpuCnpnU+QTUS3Ic5dhxK8YHyVtsG5nfF/3u1S15p5UaPGiOwIDAQAB -AoGAPa3gzKbIp4drPvFatsZAb+hgey0LgBPwmOtv8PRIZ+0vkAD/7PSRovk9u6oi -j84N4pvMe0ayL8rLOwsfXd7wcQTxDPxy+RkkMW7RRFzusPjeTMgS753/l4IqehCX -2SLPBkE9e3/UMRR0vds8T7btgTrv3R8pcgntli7W6RPrmLECQQDgZDjxx9X9O36v -SR29RhMUQdz0PQpHYwhtmBLECmr1Lpecu5Zr0JOaabWvd5Lzx1cV2hmldZFQP/gO -fEdzhsfHAkEAzWIjB0y/NH61U4Bj4fML1dGnMEzO0wm0MVEMKjcmPJUbtktvZ6jD -MedYw5VLcWbjXMAJt70UFjcxxAJPmZXZ7QJBAMKEnwiZX1uCc7OoAmvNj0SEQ/JF -598ybl/y8HGZRlb86NkplKAp04qMEL/nPDCvoUKEKq9QV4PlsDd+bMItGIkCQFml -omCHUVZakE84VWDEs7/K2U0t2YEoVSzJkaPDmr8K3qO9XY1Djp/zuTz1p46COG+9 -qwA2WdQwl1pVH+WMESkCQQC1UPYLBYIDj0JaJokSgBPh71Ui8/iBP0J1cvhvKOsS -LrEO4JUq2HBFVcxb7QahHPC22dWI8HlIJgzlUi9BEJPv +MIICXAIBAAKBgQC3KEGfUWKDHb5tzwJ58o5GaFwUctjQxOg4Wtf6TvBRnuAd7VYA +VFRtdPLnH9k5dHDUpMw1bHx4nUmbnphtLJDS8VVowLyjKGAU/uOuQidUk0nCSllH +PaE8soBZPV8xBwG7TQ47GO7Jg4dmcTLF+E4m3YbzHglOmoN5+vrwWSJnLQIDAQAB +AoGAPUp4Y0MNz0il0ANFFd/oYoFLxwADtCEggLNNsRK3cujSoNEqRWPy+Mn4+wT6 +YTKpC0+2km4iXQ5tcmkpIueV8qAitks7n8Ed7qP9Le4MXePnzgn4lL0qY1zExESX +ibAQy/ThPdRuWvelpAXpEOMZclZsix6ksFaAMdC7o8+KwdUCQQDcrd0/X4N+wlSa +LBUcnTmhFI9gcPcvckZoxISHWV2B/QaDVvGA2gYMNJa3lEcuH07LfQh0rraEzAP3 +AhG8BRPnAkEA1Hj2+qKf7aBqcjyQ5yHdxsyw/wFF3ivH5dW7mShi/C6fo+qj6WSU +JNLPN3nhJ++5IH3DuuCTop1qNwk9jEOJywJAQED3bJ5Y4S2gCIvRUdWNlBMyc/gw +YMY7LgIaPHaOvWx42wETrFrO6/rb73PjDdDb1m//aEn+psfoV6FonIA1/QJBAK1D +c4xRf39k2EkN8NA6wsKx+wgIPrR9GUboc1HjKE0jrBUca8wQs+oPauF/Z0eM6nd/ +d1R2fI4YNhxpUaKHFN8CQEpJAGi5/CfFQWdGuDbJwbXwNA8zKlyGohE/lGfjZx55 +LnL3KE/rQXKRaCmLyk5Ce6oZQkDiN7GVEwEz2wMJlys= -----END RSA PRIVATE KEY----- diff --git a/src/test/ssl/ssl/server-no-names.crt b/src/test/ssl/ssl/server-no-names.crt index 378050cd94..e1305277fb 100644 --- a/src/test/ssl/ssl/server-no-names.crt +++ b/src/test/ssl/ssl/server-no-names.crt @@ -1,12 +1,12 @@ -----BEGIN CERTIFICATE----- MIIB1jCCAT+gAwIBAgIBBTANBgkqhkiG9w0BAQUFADBCMUAwPgYDVQQDDDdUZXN0 IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNl -cnRzMB4XDTE1MDIxNjIwMDYyM1oXDTQyMDcwNDIwMDYyM1owIDEeMBwGA1UECwwV +cnRzMB4XDTE2MDkxMjE2MzAwMVoXDTQ0MDEyOTE2MzAwMVowIDEeMBwGA1UECwwV UG9zdGdyZVNRTCB0ZXN0IHN1aXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB -gQDE2mzybnsgbq7owCPC0m+igNt5pBk5hDpzFAhpbAZ6hZ85AzHnLbpCDTH5w0Zm -HeevCRkNcDgjqfoDo4DruXYpI8jH+QwuKvUwTt3GGm6C4lb3SBtfNdzJsk5kRE3o -ziMG/OxtiApxFu14nbCnqMuDs3meykD1jHheK0CsHCKq2wIDAQABMA0GCSqGSIb3 -DQEBBQUAA4GBAFNfiKDTLJ2V7kgIWDEOcyKQY8T4cAzgz6jcpN9CePgATB2Yrb9P -x7kkKW68h9SbEk6qtS4YQZjSXWKUqrjjIW22+DJSQAXMZoyADZTnZOASHjNXIzLE -y6B1RX+c7CjolHHSYkbki3RqKGhTQr1hnwkq3N8Fl9bftT5zFuezwnjD +gQC6VU212xAM+d99liOE5ROUG7qwuHhELgNbqGxUgNu8S/nKBrZSsGzWnqA4//iG +DXTZLHszRctXVrkhq2VXFCmRZLajk8uw4GtGCwb/HdvANrDM3rwiU23yjX3Q5Dvh +vHgkG+0PBf2Ghr+/XEbDkAwB0xi8QhO33F+1uQEH4XJM4QIDAQABMA0GCSqGSIb3 +DQEBBQUAA4GBAFBH5fx/I61acluRFTP5RJ8aymi8ez37+MoQ+Aftj1BXwcGSRe2E +57c0VjWUooJGKy/gs/y9F09JngEhFRz0pUCMAKQMaciEJh17ai+QOuSo6/NsGA50 +dw+w4UrYbxJK1RxhgKIYY3sojJ/6G+VbprPlWtSPSEcukRGjj31XRIfp -----END CERTIFICATE----- diff --git a/src/test/ssl/ssl/server-no-names.key b/src/test/ssl/ssl/server-no-names.key index 01a09153ca..da86d1e22e 100644 --- a/src/test/ssl/ssl/server-no-names.key +++ b/src/test/ssl/ssl/server-no-names.key @@ -1,15 +1,15 @@ -----BEGIN RSA PRIVATE KEY----- -MIICWwIBAAKBgQDE2mzybnsgbq7owCPC0m+igNt5pBk5hDpzFAhpbAZ6hZ85AzHn -LbpCDTH5w0ZmHeevCRkNcDgjqfoDo4DruXYpI8jH+QwuKvUwTt3GGm6C4lb3SBtf -NdzJsk5kRE3oziMG/OxtiApxFu14nbCnqMuDs3meykD1jHheK0CsHCKq2wIDAQAB -AoGATKkLWHXx+TVhZD6/LnWpB83KqtpfAGkgIgShKfzpoPk8goVd/7ttF5/v4GZN -miL3QND4MqWLF0hwls4rvKDjBH7q4zw+AR55pnfwoQMsfqMvAn7wZi5HKTah1xbj -yf2J1N62pNW4ZdFnlcXmAPLVDxKyCYaZqdeqgr4VkLvgIVECQQD05OYFasP/5be1 -wSj7zxd5vPK2/EJ6CFN+gwXXYOZWWR7m90g3CXxMWeH7RPIlrfcPC8o8r6xna2BS -E+BKzTYXAkEAzcfLpwZUHcCPrCipMsoC35FQhNCpecuZjVYx0oGsfiE6gu87ddLX -H3YL7+EEmtPdps4fF/9WK87MSpj1IRFv3QJAJIEOTJZqmvV6GeyuGEL5Y9snbuFR -Y3FkSMJtF3rJOuvT8GfB6vpN/e+UAOl5EubIogSG497n2w6lb/aog13thwJADtel -WcO8F3VHJ5y7L32gnW2GyD2gq7dCuQ4Jg+x0e5h79uu4dzQg7hT+oWuygFRdvWVK -mtmA5qIA3DSSIbN3RQJAd97xYxEPMF2NU+vdsLBxrkdH9tCHrqOlzEVTdhBCJrx/ -L/lJQvtxkpWEiFtQdd5OhAurNZ6iWoIdA7fhNHPCqg== +MIICXQIBAAKBgQC6VU212xAM+d99liOE5ROUG7qwuHhELgNbqGxUgNu8S/nKBrZS +sGzWnqA4//iGDXTZLHszRctXVrkhq2VXFCmRZLajk8uw4GtGCwb/HdvANrDM3rwi +U23yjX3Q5DvhvHgkG+0PBf2Ghr+/XEbDkAwB0xi8QhO33F+1uQEH4XJM4QIDAQAB +AoGBAJrFaDr5rqdYlc6W+wHT1SNctQE8+IiJP7jOeMzoC5yn7t9kG+UrLfxG3gb6 +ds/CNaB+VgcMng35tuTEnPRrhuoWh3d0jWZ/QqMklPMyrLO5s0wEOuW47D/KI4MR +wKoucQW44LrTdQgKsa4ZJbILKMScanY1oQXXjq4tueZaxajBAkEA4w8gO1rby9zQ +fIp2C4Mfi9Pe46c1/bM+AD+9hXRO9oYCE+aoi0ww4/qvE5fMYQluSmSd8Yhbvuzk +nifMF2l5xQJBANIVTdPudQvviCoXXtexl71b4KVdX9EjuWTNTCx64YB2ISg30YNw +xvlPvDQy/EvVj/3wSGAy5M/7ZVpkXCQe5G0CQC/Jgi4bzECWo6Zieb+ohB4opDNj +gMB5VeY1hAyvUuMdhxhrJjPTAEMrAmfsPc56bqTnkjpASZbgQqlqlNCkmUUCQHlV +epTLpWhWWMNOqiVTWbsxBGcdrchhpKLWe4c5FWKXV4Ed8/DBQvodFirjw5mc58QX +cgW1fzesD5aMXjcybGUCQQCZwYJir3OQC+CJCrsvACSPr3SQm28hiuO4P41dC7eT +JWluvXOGmWnZwskW/+6imEe7pGYnY81pKThnsV+CXfN9 -----END RSA PRIVATE KEY----- diff --git a/src/test/ssl/ssl/server-revoked.crt b/src/test/ssl/ssl/server-revoked.crt index 0197116d41..08a5e01526 100644 --- a/src/test/ssl/ssl/server-revoked.crt +++ b/src/test/ssl/ssl/server-revoked.crt @@ -1,13 +1,13 @@ -----BEGIN CERTIFICATE----- MIIB/DCCAWWgAwIBAgIBBjANBgkqhkiG9w0BAQUFADBCMUAwPgYDVQQDDDdUZXN0 IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNl -cnRzMB4XDTE1MDIxNjIwMDYyM1oXDTQyMDcwNDIwMDYyM1owRjEeMBwGA1UECwwV +cnRzMB4XDTE2MDkxMjE2MzAwMVoXDTQ0MDEyOTE2MzAwMVowRjEeMBwGA1UECwwV UG9zdGdyZVNRTCB0ZXN0IHN1aXRlMSQwIgYDVQQDDBtjb21tb24tbmFtZS5wZy1z -c2x0ZXN0LnRlc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMGFtZgJN+Lt -w1Bu6MmAB6h9IUrSFEVxUrrxwz5RG3UDiBkr8StZCM2hXLdSB9tSjBLIWILmuPCR -ydyf70XFTTO8L0Mc6F38I+4GVthNp8h1VJIrl1wRQIfVqFbbKYKiyCQYITzezVuC -UjHjo6xklmMewdInRrcNbWxNVkWH91zLAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEA -m9bRiYypdOrU/1hCzo6bj3Ly39/zUZp+T5xBkLJQpgVLTU8GSEdP35kc3CWzEu77 -39610RY3X0A5fNTLs74t7w2dCViYPvNu/suu87AVtlioHMkwL3QEOUnWM/l23XUR -mj33SwQfmLOV94cNLVTd8IZ9PIT0ARn/YrS1Prx1zeg= +c2x0ZXN0LnRlc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOmX1G+61akp +XA8zveTsQOtipWN8UzF0TbtxFO6LndM4RMlMFPrS/18KAbOFcfSjQvw9dfMXfOIk +zuwIYtAPD2qVyWAGRvk0Xl5qEz8aaVBbayUN5uRMByF2vgbOMz4IEywNRTWZRS2x +kAFO4/FCb/LRxD+82yck8zcZoL+SdbZZAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEA +LryjYf+t8X5j4DeeRN0uh3OWUpzFo7FaVcakjDQSgZIdlgA9RofL81yzJZAoSqk1 +zT8jqo0HKOAwunbNJxhIH54gAIpsEE9624IUAoLMo8OUF2WdMWLXJJTljfbXx/Tb +4ccuQvMLs+Um70Ogc7Mqm0+BM5N61lBdJOgMlDP511E= -----END CERTIFICATE----- diff --git a/src/test/ssl/ssl/server-revoked.key b/src/test/ssl/ssl/server-revoked.key index b12071a52d..33004170b7 100644 --- a/src/test/ssl/ssl/server-revoked.key +++ b/src/test/ssl/ssl/server-revoked.key @@ -1,15 +1,15 @@ -----BEGIN RSA PRIVATE KEY----- -MIICWwIBAAKBgQDBhbWYCTfi7cNQbujJgAeofSFK0hRFcVK68cM+URt1A4gZK/Er -WQjNoVy3UgfbUowSyFiC5rjwkcncn+9FxU0zvC9DHOhd/CPuBlbYTafIdVSSK5dc -EUCH1ahW2ymCosgkGCE83s1bglIx46OsZJZjHsHSJ0a3DW1sTVZFh/dcywIDAQAB -AoGADWTrxLIepB5AvnhutEOgRBElFMCllojZaQcCtHV4qQititB3yMBI07KvcCDF -WnDEMSict7KwajYs+pA3R2T4itVLCoz5iXYJ2CIf6XOJK+NYcf7XulSm5IqukbqT -3KlofUY2GY/5DN9tgUUnAsZ7wh6iMaq/H+BPBcblZg2kyYECQQDpYRAjwepzpr0P -gfohKYlfKJwQ9WWTRkMasn6q4DY6txeXNk5nMC9C3FHeiTgpfRr8GZBvk61lb6pV -pFWADR2TAkEA1EepQ95Mums8BxU6/PAOhXKLlyYvldaIXcajv/+/PclVuEL8ko5z -jspEGk7U/jqonwcN98R/h4ui7nxhoxIG6QJAFydgGIwWnJ7ARxeYH04lqOE4ip4u -E6x23+Exm/ZeqvibSI9EvAwVxEZjgPaQMd2NndFTeR5np5aqiZCiQvAKLQJAfRs+ -xqDc14Ebf5Ejkq5n4H4BhrMamFQ3Sg0ntKAlNWTTACV6dWU+9Yh/WoHbRXmMpyyh -LsS/5EKHY8YqRND7AQJAd+qIgqFUI0RAwvbmLxW/iR5JIKM5kZ4xJ13/O4x55XEI -4H+8YS/nYPnjMpaEWrFppNfv2UEXD2L1OkJVuYx1Sg== +MIICXAIBAAKBgQDpl9RvutWpKVwPM73k7EDrYqVjfFMxdE27cRTui53TOETJTBT6 +0v9fCgGzhXH0o0L8PXXzF3ziJM7sCGLQDw9qlclgBkb5NF5eahM/GmlQW2slDebk +TAchdr4GzjM+CBMsDUU1mUUtsZABTuPxQm/y0cQ/vNsnJPM3GaC/knW2WQIDAQAB +AoGATDyWQ6TZiK0L85Yyep00jt4SFkcEK9bGa897QmNkrgPmR0BCdJ4aZF0ysvFx +gKMsAIDaluzqgC/9LIGMJlVT9RisKWQks2cPIs5gERmYg7uNzfYegbn4N2liRG5z +d7aWevi82Dtie1xch2DdUW/mxGdvR4duyXOlSYUhbDmK8oECQQD4MylmccYxz8Ry +7APVKXPMhSCmD86y4KGfWGtKuLo4vF4Ifaze7sVtEBznNQLIAn2U4M5XD4to/VQN +2nT1ESHJAkEA8O8nDKC4vWtCXzMD2/DdHrJjxhCPbDJFp24PRFUia1yUOAgqcnfv +UzXkdcxSv/zUBB/WejLEvvrQ6Ib48Lq4EQJAZ8ashsMHhYhDsXFxYM1GN7tqHUT6 +vdwid8e2hLWcV2CbSJ2TjFr1fVaBX0LQ+OPhskAUxl4fgjR50pkG0fjp0QJAJvB/ +/yp6sSKEt54nIYTsN+nc9kX26CW33DeNgB3CUlfEHMo1EgsQQwKSyfcb6KuUGJaM +s3NBGRywZuRpl36WAQJBAKgyfmq15Ggoe4rQOyO774e1mfUQW6/fWVX8dE09ZxXz +28Sy4/K16UDUzIzzuaW3L7WjzCKql82vy2PpmWX28OM= -----END RSA PRIVATE KEY----- diff --git a/src/test/ssl/ssl/server-single-alt-name.crt b/src/test/ssl/ssl/server-single-alt-name.crt index 349792fc28..832aa051e7 100644 --- a/src/test/ssl/ssl/server-single-alt-name.crt +++ b/src/test/ssl/ssl/server-single-alt-name.crt @@ -1,13 +1,13 @@ -----BEGIN CERTIFICATE----- MIICBjCCAW+gAwIBAgIBAzANBgkqhkiG9w0BAQUFADBCMUAwPgYDVQQDDDdUZXN0 IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNl -cnRzMB4XDTE1MDIxNjIwMDYyM1oXDTQyMDcwNDIwMDYyM1owIDEeMBwGA1UECwwV +cnRzMB4XDTE2MDkxMjE2MzAwMVoXDTQ0MDEyOTE2MzAwMVowIDEeMBwGA1UECwwV UG9zdGdyZVNRTCB0ZXN0IHN1aXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB -gQDnDMJShFXba5o4o1ubyRmV9AyJLVM+8nZaC1iJzqeIPObXYpbcp3bhXtowAwvk -d3IGI/fBm/2/NKvYnyagTS9DUNRTnykHxlCKsMitx38+sU1EerkDltK0OId+obvZ -eVD+h3j7pVfA0NPKXkpcP3xoihQU9I5kOPKQEIQPNAUfdwIDAQABoy4wLDAqBgNV +gQD8lRO7m7xRlUJCKdkHdPnLKu/pbHLBgIYJk33nr22CQaM0UCgfCzr0LPaPCtlF +r5D/WS/MIlyzaXHHJMnzbFB1bx3T9BQijobeO1LKS7s3ZyPEaiNVJoih6ZXlXMQ/ +sPp887EChn+COh9BWgnWbSV0Zq2m9bggDg83J34bIeWOmwIDAQABoy4wLDAqBgNV HREEIzAhgh9zaW5nbGUuYWx0LW5hbWUucGctc3NsdGVzdC50ZXN0MA0GCSqGSIb3 -DQEBBQUAA4GBAHDkKwNT8p+/sv0Q2dIo0jdFxtBdS/fnsHzjr5ZJNa9SXEer5m3v -lMllzYW8lfTdR9PgBZ3y2lFZixD63ZF3nkIEYcD5njLp4ui7g2OVqxRfmt+rHefh -HiKm5v5GLs72lhR4GQT13AsjGVS1WWZtYhO4LwTjN+nbjnRIpXIhrSC/ +DQEBBQUAA4GBAIIcaM6MHSbH9t8cQhgWKXhjqlph/oRsNwTTalSamLR6JeT9BWxp +IZXrsgzIJsVlTSHj8JRZnv++6TVDe/1N2MtwNfJUqnblIFwaf83kulv18Vhwoh4l +dqPNaBZqdk9+EWJwPSzolK2VRKZcea+E2sMZBTYAV3pijy1k/oC8OX1V -----END CERTIFICATE----- diff --git a/src/test/ssl/ssl/server-single-alt-name.key b/src/test/ssl/ssl/server-single-alt-name.key index 71fd85c0db..90b6bc4663 100644 --- a/src/test/ssl/ssl/server-single-alt-name.key +++ b/src/test/ssl/ssl/server-single-alt-name.key @@ -1,15 +1,15 @@ -----BEGIN RSA PRIVATE KEY----- -MIICXgIBAAKBgQDnDMJShFXba5o4o1ubyRmV9AyJLVM+8nZaC1iJzqeIPObXYpbc -p3bhXtowAwvkd3IGI/fBm/2/NKvYnyagTS9DUNRTnykHxlCKsMitx38+sU1EerkD -ltK0OId+obvZeVD+h3j7pVfA0NPKXkpcP3xoihQU9I5kOPKQEIQPNAUfdwIDAQAB -AoGBAOP42uPAX1aY3Rp1VLZpvi0PGC9h4XmCkvRVrY6LsRHjxYFPbbtaIRpOFMq6 -tsk+cetNIfCOkdhPiB+9KMeSYMYShiyCrHfFxuS0FIP4rQhBB89wzcjffw2CYLGD -Umx65+XVv6RBW85p6v4s1+LQMVUtf41yxm9JXT0TVDjEcgRBAkEA+/FKxv9DuZNZ -Abjak3MeaULpnPl+Fxp+jg1M4wK12MFYCm2eBUx0X+cqVORErwLJ3gdXQBT7fJQz -bNwxjUKuTQJBAOrFVKF2dtuPAeFBlKG4sy5azGfgzS6cAJQ4LPp4uGX7ve9C8OzI -oZU21LT4cm3nuFSeMjcCKHmur85gFQrETtMCQQDKWu1yk8gzn1OX/H8iew3sAaBd -Qk6yA8euFKSymJSyOeiax5xqKRQ3ixYHBSjdYGH/AOplP/UWBHqhbuIl0W7pAkAr -f9qZfCizr8CqawtOF7njeeFr0eRSoYcd73auBhYsl0NvBJk9VkNSMXGiAnK5WHj3 -/MPTG2xCd5KNi5H6h7sPAkEApf8JUvEA5ZPkFAA6x+OXLmEL+nXOnJnhKjSUIVJx -Pgp7FTy6eKg+/iUEyhRHw5So7QjwHqH61+CIBNS41vGPuA== +MIICXwIBAAKBgQD8lRO7m7xRlUJCKdkHdPnLKu/pbHLBgIYJk33nr22CQaM0UCgf +Czr0LPaPCtlFr5D/WS/MIlyzaXHHJMnzbFB1bx3T9BQijobeO1LKS7s3ZyPEaiNV +Joih6ZXlXMQ/sPp887EChn+COh9BWgnWbSV0Zq2m9bggDg83J34bIeWOmwIDAQAB +AoGBAOkekmraLvJBRzkXtJZcUVxBkdIn5LZRb+SQu2jFkdXhzMawoIceb1gD08Br +6+KUSshSQXov0M1KKdf6TWYc9xfGg0+XgqPLw0CIJjdO8TZkIaaHZU803snWtM0e +9PlhUm2T/RDdx0cG7HD4WR8x5ij1Fc+W5QsDOi5oCke0XC0xAkEA/+rmRUaOSOaI +CohIH+oHlLTLfr0acAP2cjQHJkf5OUBVnyirfCcsFsxmnhvARuuIdftwd9p73Gw9 +MIGVV6TDIwJBAPyp5xByHy7sicsi2ynSTpS9JhuVvR9cdKBLGmbPQtS0Fb0rannR +wyybfFIN1trfZJ6QmNKAPSPfUFhre3b4WikCQQDVOZYaairquojmnZ3aWVdvoyNZ +uZ1pbyPLC2ZZkuYnuV6deXlHvCuT40Iswdp2PJA6HQEcG0HP6a8h1xXjLDgZAkEA +wMKirTJTxgnh6l9SUyrGlsVjoGHx4k44D96catkvBHXLrAHGft/ghlStWTCDvYH3 +Et4AKYB6pLaHZp3BmPdKWQJBAMI65XkJC5+XESMUP26lC71eo6tMcJ9fBKOa7PEW +M9I04AeId/3nbA2eKCebfUzrZOizeHHOjhH3Dubz3df8Ww8= -----END RSA PRIVATE KEY----- diff --git a/src/test/ssl/ssl/server-ss.crt b/src/test/ssl/ssl/server-ss.crt index d0c9b83923..9b4f4d1e80 100644 --- a/src/test/ssl/ssl/server-ss.crt +++ b/src/test/ssl/ssl/server-ss.crt @@ -1,13 +1,13 @@ -----BEGIN CERTIFICATE----- -MIICCDCCAXGgAwIBAgIJAJyw4sQKTY2UMA0GCSqGSIb3DQEBCwUAMEYxJDAiBgNV +MIICCDCCAXGgAwIBAgIJAJ5i7OAq01pyMA0GCSqGSIb3DQEBCwUAMEYxJDAiBgNV BAMMG2NvbW1vbi1uYW1lLnBnLXNzbHRlc3QudGVzdDEeMBwGA1UECwwVUG9zdGdy -ZVNRTCB0ZXN0IHN1aXRlMB4XDTE1MDIxNjIwMDYyM1oXDTQyMDcwNDIwMDYyM1ow +ZVNRTCB0ZXN0IHN1aXRlMB4XDTE2MDkxMjE2MzAwMVoXDTQ0MDEyOTE2MzAwMVow RjEkMCIGA1UEAwwbY29tbW9uLW5hbWUucGctc3NsdGVzdC50ZXN0MR4wHAYDVQQL DBVQb3N0Z3JlU1FMIHRlc3Qgc3VpdGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ -AoGBAOqxI3Umy7P+FqPSenj/4SgwJgKMM73Q0tJvaDNXb1ipfAUHbvnKCNUs693Y -jRdZwTAVXsYq8btCja/4L24FLCNktLzQfxmVuueMgi7HuYevxVbhOXhxuy8cbTeC -6FZj3F6vU7Obg5rML6FNzVljbtx/YA2lM4H/lWafTp0mXnmFAgMBAAEwDQYJKoZI -hvcNAQELBQADgYEAGweDmEYzoEWb3WNn7Mc58ToPnl5DbRZdVmRjsyC6J5oZRu2E -e/GZZ/1MSNPgccoyhdcPmSqTzUzbQnvYsqcHfuncA/oNJR3wvMV/wSy0QepklX1b -ixjZg9c+mhQ/JTSjYnRK5iSTPNX4F3zkpvP79POuQYl/7Oihqxl0Mmkezuc= +AoGBALkR7DNyRnAED7ZxnsfOPQ55QB0nM2onJmVZkG4EeqQJ6GZHJym7pHHwbww+ +dgXvlNzkv2SOvA+Yq8TXgYvSiKhZ4N4ReSWWZ71P+RqJXpSrj6K2mVKOw0Rno9kM +t0370bQOnkvSQY9BWxJbxji2ks3oj4wma+1zje3i46IlwoYHAgMBAAEwDQYJKoZI +hvcNAQELBQADgYEAZtnJALcQmbqBAm16RE/Smu75lBkniqlB0MwOJyGpDg5DkXtA +YnZP139cRWKCjbWiYj4hgK0eGGRoBuubF6zRrRlYLV9iyZyRx1cBYyUbQBW+AfER +jWiL4IBJWn7RNej6Uc0Th8Di5eEZapDt0DFkdALFhpFNaWJIcCUKpqEJHUA= -----END CERTIFICATE----- diff --git a/src/test/ssl/ssl/server-ss.key b/src/test/ssl/ssl/server-ss.key index 39cf3e3c05..69bc907b74 100644 --- a/src/test/ssl/ssl/server-ss.key +++ b/src/test/ssl/ssl/server-ss.key @@ -1,15 +1,15 @@ -----BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQC6FTHDuNKbYQChNtxAFLKzJESIKOZh8WpgCN91HFtnXX4hp3rS -bkEDIABlQdqfcXLk7PmlR/rboOIqwuIAaIa12BxEJ5KW2vtcSAFd17anhG/a9n8w -cQnoEUvLLAp7V2xGJ8Cu8mtyv9Qsmd5bS+SFchmbIcMZUb4znZfIr7AWWQIDAQAB -AoGAJvVzAtA6P8+ySw5qVHxA4aKxOnSdr1nU9KBG8ITsWhrH4pHm9BGjSN01V/3O -oN0mueknZ0RHsB3h3CQLHxzDPwmsah7apU8W/1AVyZ9LDEMuoZQef3+JfegmuNMj -YYtBR8xozTviOH0UH6t3VOW8Y2TLtZo5kMz3XwjWBS+cCYECQQDlPEfH1x9QGXNW -Eo37QK4UkL6/2czIXWitvb5+79KiG70XYIxrQR9NhpZHSGjBlS+TqJ4tnQa/fv95 -v4I7Q5NpAkEAz88ax91FeHr8y41s01MmJ6Gs6EOrFEpoHGboDdbwJ50pME5XnVJu -xjHPklHgwiWFf4dQURjv6hCPUMVpe1w9cQJAZocPk9Ijry+y5kxmNHo5YflbV3OS -pAsjRpIXIa8iBl9hs5L7Ov1lgscvb7JzKCIRpXlFRiF1YzDqEwoUtW0EAQJAH+/c -VcsT2ihMoZvilbe5rW2TfT6pFD07MuI916Ko1e25Xssre+onTB5roDklKbFKiwbo -uQ30ESzqWad9RpAugQJBANmRD25BmlHbdBDg+Zfd+4jDPAjXN8OesslEs5dMvs8C -vqGrozvmtpLRcLiIitTiT4TzuUPowgZQtCjC0X6jSGY= +MIICXgIBAAKBgQC3ekl7kd5dbcgs5UDu2im/oNSranNRqfqe4USVtiD9NPEWIc43 +wJhkp7w5BOf4xwWukrhOkpTzPLJwYH5HsQL6gBFZi095VExrdRopmpk268l41rSD +q+y0eWM+DoapoiU8tZ106RtMVSinDfXpXz6Nh9+WQ7/Q4EHWbREvf/SIeQIDAQAB +AoGAWbacqaRIk2xznag3WNMp6L5OXsa9Pmgb2IYTkBSvCsBRRd4fxFkS6tythz/j +4VwHZjXtktXPqSO7qIE2Hf3qkxfBpZ72qrvEDpHLXzEFXUamJMPRDZIBHrkfa/sl +pq+z0siCwO/ozoiInQFxArHeZs8MoGd/FYtECwbuvQd9LuUCQQDkYhlrELE7MB47 +Ot+vgkodp84p2LHlY48cLfn0Es+3aDzusWZbNDENmY9tOubIygh3qo0G2NtSEGVK +NZzm73GHAkEAzaoUKK3YCD95OKyj3FZ9P/32K1y7JqCH/9ux9dXBQLegdd0hWLk9 +USLlaPgC4FOVrSSbiQHbZ8lUewwtNeK1/wJBALf0nGy0wUzfcTpcLZh85Z4Fb/Yc +6Q3Pp5IXJmIGVPFyMMJCeiO0Yl6F9hURgJrywOdCpN2DBwWO10dy77LD4zkCQQCP +EJHnXk8aJbVYpFd0TcHhAvP8ZAxYKXGRnS0lWqWNNG9trf6lbm5mA4VcSLIPhHVp +NT7wxpbukpGu6uCETInXAkEAhF7m+XeHvJ0vrdpI3OSOVTW8o9QZSqUffsGB6eRb +v/dJvKgaz3JOzpvRS87lRUd62QfjfmiDXjyhllRn8OPMuw== -----END RSA PRIVATE KEY----- diff --git a/src/test/ssl/ssl/server.crl b/src/test/ssl/ssl/server.crl index d36ce7fe75..e481d011f6 100644 --- a/src/test/ssl/ssl/server.crl +++ b/src/test/ssl/ssl/server.crl @@ -1,9 +1,9 @@ -----BEGIN X509 CRL----- MIIBHTCBhzANBgkqhkiG9w0BAQUFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ -b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0xNTAy -MTYyMDA2MjNaFw00MjA3MDQyMDA2MjNaMBQwEgIBBhcNMTUwMjE2MjAwNjIzWjAN -BgkqhkiG9w0BAQUFAAOBgQB1c54zLMueMtLiSmBT6kfXJe9o3Krd2n774g7kzNlR -DeLpCHeUvyLF0m8YK09vbLv2W0r6VQnbjyQGr9xyweRLLtOXc0FIDsTO8g/jvMSq -Q9zITuqWiCHRbNhi2B3HPo2NsrfA+tQEAZvMUgnynlerNvGkLWQZeC2UsxrrSs4t -9Q== +b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0xNjA5 +MTIxNjMwMDFaFw00NDAxMjkxNjMwMDFaMBQwEgIBBhcNMTYwOTEyMTYzMDAxWjAN +BgkqhkiG9w0BAQUFAAOBgQAm5J6912hKDUWXyu3yCEk1j3KICE2J42ZjFRvxBNdO +Zhv/iBjyFI6TmCVJqoe4GJbNG78xmNEl3/2ZUavG/aD0Z3xGu2xm0p+3Uh2zhfDQ +VEdlgFNKNItS0AtKvoduoZUXKnz3Ft09yLmz9yHLu6EslIsYryi+wnZ5DwUBj5Ec +WA== -----END X509 CRL----- diff --git a/src/test/ssl/ssl/server_ca.crt b/src/test/ssl/ssl/server_ca.crt index 517a30aa4b..2bbb8c9c1b 100644 --- a/src/test/ssl/ssl/server_ca.crt +++ b/src/test/ssl/ssl/server_ca.crt @@ -1,13 +1,13 @@ -----BEGIN CERTIFICATE----- -MIIB8TCCAVoCAQEwDQYJKoZIhvcNAQEFBQAwQDE+MDwGA1UEAww1VGVzdCByb290 -IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc3VpdGUwHhcN -MTUwMjE2MjAwNjIzWhcNNDIwNzA0MjAwNjIzWjBCMUAwPgYDVQQDDDdUZXN0IENB -IGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRz -MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDAYtajRx8vM6IB0SLZsAhTD0Y -VHM+/+t0a4m3JXolJBbo9/B2/WAN0IH1E2zmlalLc3JBmGsH1a8U5ZlRow3p2ODL -rFra9FbOl0wekmRFvZeaRln/99dpI5itVpL97QPHO8QMMK1IsyurFA5GfuPOBx9P -i0MvzsT0tYsRvR929QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAJw4ngOYElfyMYkS -K6bOgMosrBoX8ns6jQgdXEzf7QOIa110bs6nD+XeJeKmzUAZ3wumXBTalPaiqkEz -bq4nlsEs1phvj0Coy5eehjV3DB8bDLEneOlV5N9y4Z4VO1BrhX61bLiPXBRp1MZR -I0sCdxhswSrq02/OuFGe6mqrSBBI +MIICCDCCAXGgAwIBAgIBATANBgkqhkiG9w0BAQUFADBAMT4wPAYDVQQDDDVUZXN0 +IHJvb3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzdWl0 +ZTAeFw0xNjA5MTIxNjMwMDFaFw00NDAxMjkxNjMwMDFaMEIxQDA+BgNVBAMMN1Rl +c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzZXJ2ZXIg +Y2VydHMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKpkEBIZexm3YZ94RA+c +vUREqvLgECfHlP9BbkXySFPGWcAPt/0uSW62eVS3UFcB9083W4w/uilL75PXDHV1 +37fyq+6LHCYE5TinzVr5ECAtQMpIzlKkAuAPq3mTa1fklwT/MCz/PKGAljs2o95w +mNyEJwTchOQ52fZjFexRiarNAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZI +hvcNAQEFBQADgYEAP1ZhwGxsL7GTNxfs2qwYCjsF2zYSjCPXtwJnKFu5ayGxz6dB +paspokWFCglP1PwPAmINHeqp669WNnAmC5EixdTy2jcnod8NB6RlkOqJmNzVPhvO +cTZXxKd3awOzz0+IJ2bMcC9JPXs8phhRuRgvSfKTTZVtdcFmVF/HYIrBB5Y= -----END CERTIFICATE----- diff --git a/src/test/ssl/ssl/server_ca.key b/src/test/ssl/ssl/server_ca.key index ac4e76f2b2..668c37bff9 100644 --- a/src/test/ssl/ssl/server_ca.key +++ b/src/test/ssl/ssl/server_ca.key @@ -1,15 +1,15 @@ -----BEGIN RSA PRIVATE KEY----- -MIICXgIBAAKBgQDDAYtajRx8vM6IB0SLZsAhTD0YVHM+/+t0a4m3JXolJBbo9/B2 -/WAN0IH1E2zmlalLc3JBmGsH1a8U5ZlRow3p2ODLrFra9FbOl0wekmRFvZeaRln/ -99dpI5itVpL97QPHO8QMMK1IsyurFA5GfuPOBx9Pi0MvzsT0tYsRvR929QIDAQAB -AoGAcq9i1INvAJFN6cRUdKOeVTbwK3HnQWLjh9mC6bpZxqQd8S94NZK4Pgelloux -HT9hjGU+CgPo1ne+e0y4ycFaeWf6SFyMJ3KmGFKCliE6A5zd/g+rIp8oja0Y7eLZ -PUdx984qynfvFMxgB+VJk22cLui9az65WCY+akdWbnwfR4ECQQD4GH6S71bZya9G -/DDS2YYi3Cvke6wsGSXTMyfDaW42M3mtJOrmoczrx1sAzTmO4rwhuzFFQRs662IS -/c9nmXOhAkEAyTgK9BNbkb5n2KN0Ebpx+x9cCh7fJ6qY54DOk+svp2jOhBcV9Aqd -fYPHzPI0v358buPjozXgALNl7FGrO6sC1QJBAPKrwuMmiOVuiav9ciRL8RCYG7bZ -4Ycg8garuvFBZzRNFW9u9PWyvibCURlvpCVHUo4L9B2xmVkAdGXvLbhAOQECQQDD -9zKjtl6NuFRGphmaUmxDV605pgtLBFhZzhZh9MC6V9YYyqr0u4nZ/YeOz6wTe0oQ -bRz7jLKVvCHdX0RWnhvpAkEAhY+plw7q6fyXSBBOVUcHUO2Wtmdm8clvKbs64Wdl -bjryhvBhq3gPii7jnLGwS2v5jwqCcKpK1tszO/8+gj2T+A== +MIICXAIBAAKBgQCqZBASGXsZt2GfeEQPnL1ERKry4BAnx5T/QW5F8khTxlnAD7f9 +LklutnlUt1BXAfdPN1uMP7opS++T1wx1dd+38qvuixwmBOU4p81a+RAgLUDKSM5S +pALgD6t5k2tX5JcE/zAs/zyhgJY7NqPecJjchCcE3ITkOdn2YxXsUYmqzQIDAQAB +AoGATaLcI7MSgOwqggPFVyu+nS2AiruHAOkSPZ/tg9daFznISRegaK6/bL+d1vjT +lWFi8ugxQV0EEK710XHpzldQAH0YQ9YA86s7P/a4SjETdRChFYt+CV+aZ4feyNPV +OZcKuoE82MUFU03jaJsWJJ4jybPPTcZ0Rr25oFpkR2fnPMECQQDXrRWviHuLkmrV +WqZQLXiPt6bCrTowpnKo62Un5yrA7dehfL9b12J7/9tgfy0ZHXZtBXSHlELZ4LeA +wpYfsq59AkEAyj99EE++kU2QbkCqYKJ5xBQxNc2ntZ/EfiBXMuQNwncj4m86xFLj +coFHyOrRjo1GZAFxsZsNbf74xgMLDxIOkQJAHzKiWGndtSrQ2Vvrgt2Q+vkN3ktA +h5kMLPMgBs2hmZbOAkYRSC+3x0gTa7n5xBBG+S441QPVR78BzFZZcOxf4QJBAIVk +lH8iqYU6jE07l2Q/JWK/Eqny529yXe32NK0bHzwoymE5jaAZL2zBefA5eFe2NDwX +e75xjs0Cw2AOd8fL2BECQBqAafyDcER1SasqV5hkjyFQQu8FqzLUyppwbTKTRZji +s+xxGwP9jT9LaKC6w9nuzFmaGi0OO3ciE+I+X89YiKc= -----END RSA PRIVATE KEY----- diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl index 80e8ea1fe7..dc8e064b25 100644 --- a/src/test/ssl/t/001_ssltests.pl +++ b/src/test/ssl/t/001_ssltests.pl @@ -2,7 +2,7 @@ use warnings; use PostgresNode; use TestLib; -use Test::More tests => 38; +use Test::More tests => 40; use ServerSetup; use File::Copy; @@ -239,3 +239,11 @@ sub test_connect_fails test_connect_fails( "user=ssltestuser sslcert=ssl/client-revoked.crt sslkey=ssl/client-revoked.key" ); + +# intermediate client_ca.crt is provided by client, and isn't in server's ssl_ca_file +switch_server_cert($node, 'server-cn-only', 'root_ca'); +$common_connstr = +"user=ssltestuser dbname=certdb sslkey=ssl/client.key sslrootcert=ssl/root+server_ca.crt hostaddr=$SERVERHOSTADDR"; + +test_connect_ok("sslmode=require sslcert=ssl/client+client_ca.crt"); +test_connect_fails("sslmode=require sslcert=ssl/client.crt"); diff --git a/src/test/subscription/.gitignore b/src/test/subscription/.gitignore new file mode 100644 index 0000000000..871e943d50 --- /dev/null +++ b/src/test/subscription/.gitignore @@ -0,0 +1,2 @@ +# Generated by test suite +/tmp_check/ diff --git a/src/test/subscription/Makefile b/src/test/subscription/Makefile new file mode 100644 index 0000000000..bb9795453a --- /dev/null +++ b/src/test/subscription/Makefile @@ -0,0 +1,22 @@ +#------------------------------------------------------------------------- +# +# Makefile for src/test/subscription +# +# Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/test/subscription/Makefile +# +#------------------------------------------------------------------------- + +subdir = src/test/subscription +top_builddir = ../../.. +include $(top_builddir)/src/Makefile.global + +EXTRA_INSTALL = contrib/hstore + +check: + $(prove_check) + +clean distclean maintainer-clean: + rm -rf tmp_check diff --git a/src/test/subscription/README b/src/test/subscription/README new file mode 100644 index 0000000000..e9e93755b7 --- /dev/null +++ b/src/test/subscription/README @@ -0,0 +1,16 @@ +src/test/subscription/README + +Regression tests for subscription/logical replication +===================================================== + +This directory contains a test suite for subscription/logical replication. + +Running the tests +================= + + make check + +NOTE: This creates a temporary installation, and some tests may +create one or multiple nodes, for the purpose of the tests. + +NOTE: This requires the --enable-tap-tests argument to configure. diff --git a/src/test/subscription/t/001_rep_changes.pl b/src/test/subscription/t/001_rep_changes.pl new file mode 100644 index 0000000000..b51740bcd4 --- /dev/null +++ b/src/test/subscription/t/001_rep_changes.pl @@ -0,0 +1,188 @@ +# Basic logical replication test +use strict; +use warnings; +use PostgresNode; +use TestLib; +use Test::More tests => 11; + +# Initialize publisher node +my $node_publisher = get_new_node('publisher'); +$node_publisher->init(allows_streaming => 'logical'); +$node_publisher->start; + +# Create subscriber node +my $node_subscriber = get_new_node('subscriber'); +$node_subscriber->init(allows_streaming => 'logical'); +$node_subscriber->start; + +# Create some preexisting content on publisher +$node_publisher->safe_psql('postgres', + "CREATE TABLE tab_notrep AS SELECT generate_series(1,10) AS a"); +$node_publisher->safe_psql('postgres', + "CREATE TABLE tab_ins (a int)"); +$node_publisher->safe_psql('postgres', + "CREATE TABLE tab_full AS SELECT generate_series(1,10) AS a"); +$node_publisher->safe_psql('postgres', + "CREATE TABLE tab_rep (a int primary key)"); + +# Setup structure on subscriber +$node_subscriber->safe_psql('postgres', + "CREATE TABLE tab_notrep (a int)"); +$node_subscriber->safe_psql('postgres', + "CREATE TABLE tab_ins (a int)"); +$node_subscriber->safe_psql('postgres', + "CREATE TABLE tab_full (a int)"); +$node_subscriber->safe_psql('postgres', + "CREATE TABLE tab_rep (a int primary key)"); + +# Setup logical replication +my $publisher_connstr = $node_publisher->connstr . ' dbname=postgres'; +$node_publisher->safe_psql('postgres', + "CREATE PUBLICATION tap_pub"); +$node_publisher->safe_psql('postgres', + "CREATE PUBLICATION tap_pub_ins_only WITH (nopublish delete, nopublish update)"); +$node_publisher->safe_psql('postgres', + "ALTER PUBLICATION tap_pub ADD TABLE tab_rep, tab_full"); +$node_publisher->safe_psql('postgres', + "ALTER PUBLICATION tap_pub_ins_only ADD TABLE tab_ins"); + +my $appname = 'tap_sub'; +$node_subscriber->safe_psql('postgres', + "CREATE SUBSCRIPTION tap_sub CONNECTION '$publisher_connstr application_name=$appname' PUBLICATION tap_pub, tap_pub_ins_only"); + +# Wait for subscriber to finish initialization +my $caughtup_query = +"SELECT pg_current_xlog_location() <= replay_location FROM pg_stat_replication WHERE application_name = '$appname';"; +$node_publisher->poll_query_until('postgres', $caughtup_query) + or die "Timed out while waiting for subscriber to catch up"; + +my $result = + $node_subscriber->safe_psql('postgres', "SELECT count(*) FROM tab_notrep"); +is($result, qq(0), 'check non-replicated table is empty on subscriber'); + +$node_publisher->safe_psql('postgres', + "INSERT INTO tab_ins SELECT generate_series(1,50)"); +$node_publisher->safe_psql('postgres', + "DELETE FROM tab_ins WHERE a > 20"); +$node_publisher->safe_psql('postgres', + "UPDATE tab_ins SET a = -a"); + +$node_publisher->safe_psql('postgres', + "INSERT INTO tab_rep SELECT generate_series(1,50)"); +$node_publisher->safe_psql('postgres', + "DELETE FROM tab_rep WHERE a > 20"); +$node_publisher->safe_psql('postgres', + "UPDATE tab_rep SET a = -a"); + +$node_publisher->poll_query_until('postgres', $caughtup_query) + or die "Timed out while waiting for subscriber to catch up"; + +$result = + $node_subscriber->safe_psql('postgres', "SELECT count(*), min(a), max(a) FROM tab_ins"); +is($result, qq(50|1|50), 'check replicated inserts on subscriber'); + +$result = + $node_subscriber->safe_psql('postgres', "SELECT count(*), min(a), max(a) FROM tab_rep"); +is($result, qq(20|-20|-1), 'check replicated changes on subscriber'); + +# insert some duplicate rows +$node_publisher->safe_psql('postgres', + "INSERT INTO tab_full SELECT generate_series(1,10)"); + +# add REPLICA IDENTITY FULL so we can update +$node_publisher->safe_psql('postgres', + "ALTER TABLE tab_full REPLICA IDENTITY FULL"); +$node_subscriber->safe_psql('postgres', + "ALTER TABLE tab_full REPLICA IDENTITY FULL"); +$node_publisher->safe_psql('postgres', + "ALTER TABLE tab_ins REPLICA IDENTITY FULL"); +$node_subscriber->safe_psql('postgres', + "ALTER TABLE tab_ins REPLICA IDENTITY FULL"); + +# and do the update +$node_publisher->safe_psql('postgres', + "UPDATE tab_full SET a = a * a"); + +# Wait for subscription to catch up +$node_publisher->poll_query_until('postgres', $caughtup_query) + or die "Timed out while waiting for subscriber to catch up"; + +$result = + $node_subscriber->safe_psql('postgres', "SELECT count(*), min(a), max(a) FROM tab_full"); +is($result, qq(10|1|100), 'update works with REPLICA IDENTITY FULL and duplicate tuples'); + +# check that change of connection string and/or publication list causes +# restart of subscription workers. Not all of these are registered as tests +# as we need to poll for a change but the test suite will fail none the less +# when something goes wrong. +my $oldpid = $node_publisher->safe_psql('postgres', + "SELECT pid FROM pg_stat_replication WHERE application_name = '$appname';"); +$node_subscriber->safe_psql('postgres', + "ALTER SUBSCRIPTION tap_sub CONNECTION 'application_name=$appname $publisher_connstr'"); +$node_publisher->poll_query_until('postgres', + "SELECT pid != $oldpid FROM pg_stat_replication WHERE application_name = '$appname';") + or die "Timed out while waiting for apply to restart"; + +$oldpid = $node_publisher->safe_psql('postgres', + "SELECT pid FROM pg_stat_replication WHERE application_name = '$appname';"); +$node_subscriber->safe_psql('postgres', + "ALTER SUBSCRIPTION tap_sub SET PUBLICATION tap_pub_ins_only"); +$node_publisher->poll_query_until('postgres', + "SELECT pid != $oldpid FROM pg_stat_replication WHERE application_name = '$appname';") + or die "Timed out while waiting for apply to restart"; + +$node_publisher->safe_psql('postgres', + "INSERT INTO tab_ins SELECT generate_series(1001,1100)"); +$node_publisher->safe_psql('postgres', + "DELETE FROM tab_rep"); + +$node_publisher->poll_query_until('postgres', $caughtup_query) + or die "Timed out while waiting for subscriber to catch up"; + +$result = + $node_subscriber->safe_psql('postgres', "SELECT count(*), min(a), max(a) FROM tab_ins"); +is($result, qq(150|1|1100), 'check replicated inserts after subscription publication change'); + +$result = + $node_subscriber->safe_psql('postgres', "SELECT count(*), min(a), max(a) FROM tab_rep"); +is($result, qq(20|-20|-1), 'check changes skipped after subscription publication change'); + +# check alter publication (relcache invalidation etc) +$node_publisher->safe_psql('postgres', + "ALTER PUBLICATION tap_pub_ins_only WITH (publish delete)"); +$node_publisher->safe_psql('postgres', + "ALTER PUBLICATION tap_pub_ins_only ADD TABLE tab_full"); +$node_publisher->safe_psql('postgres', + "DELETE FROM tab_ins WHERE a > 0"); +$node_publisher->safe_psql('postgres', + "INSERT INTO tab_full VALUES(0)"); + +$node_publisher->poll_query_until('postgres', $caughtup_query) + or die "Timed out while waiting for subscriber to catch up"; + +# note that data are different on provider and subscriber +$result = + $node_subscriber->safe_psql('postgres', "SELECT count(*), min(a), max(a) FROM tab_ins"); +is($result, qq(50|1|50), 'check replicated deletes after alter publication'); + +$result = + $node_subscriber->safe_psql('postgres', "SELECT count(*), min(a), max(a) FROM tab_full"); +is($result, qq(11|0|100), 'check replicated insert after alter publication'); + +# check all the cleanup +$node_subscriber->safe_psql('postgres', "DROP SUBSCRIPTION tap_sub"); + +$result = + $node_subscriber->safe_psql('postgres', "SELECT count(*) FROM pg_subscription"); +is($result, qq(0), 'check subscription was dropped on subscriber'); + +$result = + $node_publisher->safe_psql('postgres', "SELECT count(*) FROM pg_replication_slots"); +is($result, qq(0), 'check replication slot was dropped on publisher'); + +$result = + $node_subscriber->safe_psql('postgres', "SELECT count(*) FROM pg_replication_origin"); +is($result, qq(0), 'check replication origin was dropped on subscriber'); + +$node_subscriber->stop('fast'); +$node_publisher->stop('fast'); diff --git a/src/test/subscription/t/002_types.pl b/src/test/subscription/t/002_types.pl new file mode 100644 index 0000000000..9064eb4c6d --- /dev/null +++ b/src/test/subscription/t/002_types.pl @@ -0,0 +1,539 @@ +# This tests that more complex datatypes are replicated correctly +# by logical replication +use strict; +use warnings; +use PostgresNode; +use TestLib; +use Test::More tests => 3; + +# Initialize publisher node +my $node_publisher = get_new_node('publisher'); +$node_publisher->init(allows_streaming => 'logical'); +$node_publisher->start; + +# Create subscriber node +my $node_subscriber = get_new_node('subscriber'); +$node_subscriber->init(allows_streaming => 'logical'); +$node_subscriber->start; + +# Create some preexisting content on publisher +my $ddl = qq( + CREATE EXTENSION hstore WITH SCHEMA public; + CREATE TABLE public.tst_one_array ( + a INTEGER PRIMARY KEY, + b INTEGER[] + ); + CREATE TABLE public.tst_arrays ( + a INTEGER[] PRIMARY KEY, + b TEXT[], + c FLOAT[], + d INTERVAL[] + ); + + CREATE TYPE public.tst_enum_t AS ENUM ('a', 'b', 'c', 'd', 'e'); + CREATE TABLE public.tst_one_enum ( + a INTEGER PRIMARY KEY, + b public.tst_enum_t + ); + CREATE TABLE public.tst_enums ( + a public.tst_enum_t PRIMARY KEY, + b public.tst_enum_t[] + ); + + CREATE TYPE public.tst_comp_basic_t AS (a FLOAT, b TEXT, c INTEGER); + CREATE TYPE public.tst_comp_enum_t AS (a FLOAT, b public.tst_enum_t, c INTEGER); + CREATE TYPE public.tst_comp_enum_array_t AS (a FLOAT, b public.tst_enum_t[], c INTEGER); + CREATE TABLE public.tst_one_comp ( + a INTEGER PRIMARY KEY, + b public.tst_comp_basic_t + ); + CREATE TABLE public.tst_comps ( + a public.tst_comp_basic_t PRIMARY KEY, + b public.tst_comp_basic_t[] + ); + CREATE TABLE public.tst_comp_enum ( + a INTEGER PRIMARY KEY, + b public.tst_comp_enum_t + ); + CREATE TABLE public.tst_comp_enum_array ( + a public.tst_comp_enum_t PRIMARY KEY, + b public.tst_comp_enum_t[] + ); + CREATE TABLE public.tst_comp_one_enum_array ( + a INTEGER PRIMARY KEY, + b public.tst_comp_enum_array_t + ); + CREATE TABLE public.tst_comp_enum_what ( + a public.tst_comp_enum_array_t PRIMARY KEY, + b public.tst_comp_enum_array_t[] + ); + + CREATE TYPE public.tst_comp_mix_t AS ( + a public.tst_comp_basic_t, + b public.tst_comp_basic_t[], + c public.tst_enum_t, + d public.tst_enum_t[] + ); + CREATE TABLE public.tst_comp_mix_array ( + a public.tst_comp_mix_t PRIMARY KEY, + b public.tst_comp_mix_t[] + ); + CREATE TABLE public.tst_range ( + a INTEGER PRIMARY KEY, + b int4range + ); + CREATE TABLE public.tst_range_array ( + a INTEGER PRIMARY KEY, + b TSTZRANGE, + c int8range[] + ); + CREATE TABLE public.tst_hstore ( + a INTEGER PRIMARY KEY, + b public.hstore + );); + +# Setup structure on both nodes +$node_publisher->safe_psql('postgres', $ddl); +$node_subscriber->safe_psql('postgres', $ddl); + +# Setup logical replication +my $publisher_connstr = $node_publisher->connstr . ' dbname=postgres'; +$node_publisher->safe_psql('postgres', + "CREATE PUBLICATION tap_pub FOR ALL TABLES"); + +my $appname = 'tap_sub'; +$node_subscriber->safe_psql('postgres', + "CREATE SUBSCRIPTION tap_sub CONNECTION '$publisher_connstr application_name=$appname' PUBLICATION tap_pub WITH (SLOT NAME = tap_sub_slot)"); + +# Wait for subscriber to finish initialization +my $caughtup_query = +"SELECT pg_current_xlog_location() <= replay_location FROM pg_stat_replication WHERE application_name = '$appname';"; +$node_publisher->poll_query_until('postgres', $caughtup_query) + or die "Timed out while waiting for subscriber to catch up"; + +# Insert initial test data +$node_publisher->safe_psql('postgres', qq( + -- test_tbl_one_array_col + INSERT INTO tst_one_array (a, b) VALUES + (1, '{1, 2, 3}'), + (2, '{2, 3, 1}'), + (3, '{3, 2, 1}'), + (4, '{4, 3, 2}'), + (5, '{5, NULL, 3}'); + + -- test_tbl_arrays + INSERT INTO tst_arrays (a, b, c, d) VALUES + ('{1, 2, 3}', '{"a", "b", "c"}', '{1.1, 2.2, 3.3}', '{"1 day", "2 days", "3 days"}'), + ('{2, 3, 1}', '{"b", "c", "a"}', '{2.2, 3.3, 1.1}', '{"2 minutes", "3 minutes", "1 minute"}'), + ('{3, 1, 2}', '{"c", "a", "b"}', '{3.3, 1.1, 2.2}', '{"3 years", "1 year", "2 years"}'), + ('{4, 1, 2}', '{"d", "a", "b"}', '{4.4, 1.1, 2.2}', '{"4 years", "1 year", "2 years"}'), + ('{5, NULL, NULL}', '{"e", NULL, "b"}', '{5.5, 1.1, NULL}', '{"5 years", NULL, NULL}'); + + -- test_tbl_single_enum + INSERT INTO tst_one_enum (a, b) VALUES + (1, 'a'), + (2, 'b'), + (3, 'c'), + (4, 'd'), + (5, NULL); + + -- test_tbl_enums + INSERT INTO tst_enums (a, b) VALUES + ('a', '{b, c}'), + ('b', '{c, a}'), + ('c', '{b, a}'), + ('d', '{c, b}'), + ('e', '{d, NULL}'); + + -- test_tbl_single_composites + INSERT INTO tst_one_comp (a, b) VALUES + (1, ROW(1.0, 'a', 1)), + (2, ROW(2.0, 'b', 2)), + (3, ROW(3.0, 'c', 3)), + (4, ROW(4.0, 'd', 4)), + (5, ROW(NULL, NULL, 5)); + + -- test_tbl_composites + INSERT INTO tst_comps (a, b) VALUES + (ROW(1.0, 'a', 1), ARRAY[ROW(1, 'a', 1)::tst_comp_basic_t]), + (ROW(2.0, 'b', 2), ARRAY[ROW(2, 'b', 2)::tst_comp_basic_t]), + (ROW(3.0, 'c', 3), ARRAY[ROW(3, 'c', 3)::tst_comp_basic_t]), + (ROW(4.0, 'd', 4), ARRAY[ROW(4, 'd', 3)::tst_comp_basic_t]), + (ROW(5.0, 'e', NULL), ARRAY[NULL, ROW(5, NULL, 5)::tst_comp_basic_t]); + + -- test_tbl_composite_with_enums + INSERT INTO tst_comp_enum (a, b) VALUES + (1, ROW(1.0, 'a', 1)), + (2, ROW(2.0, 'b', 2)), + (3, ROW(3.0, 'c', 3)), + (4, ROW(4.0, 'd', 4)), + (5, ROW(NULL, 'e', NULL)); + + -- test_tbl_composite_with_enums_array + INSERT INTO tst_comp_enum_array (a, b) VALUES + (ROW(1.0, 'a', 1), ARRAY[ROW(1, 'a', 1)::tst_comp_enum_t]), + (ROW(2.0, 'b', 2), ARRAY[ROW(2, 'b', 2)::tst_comp_enum_t]), + (ROW(3.0, 'c', 3), ARRAY[ROW(3, 'c', 3)::tst_comp_enum_t]), + (ROW(4.0, 'd', 3), ARRAY[ROW(3, 'd', 3)::tst_comp_enum_t]), + (ROW(5.0, 'e', 3), ARRAY[ROW(3, 'e', 3)::tst_comp_enum_t, NULL]); + + -- test_tbl_composite_with_single_enums_array_in_composite + INSERT INTO tst_comp_one_enum_array (a, b) VALUES + (1, ROW(1.0, '{a, b, c}', 1)), + (2, ROW(2.0, '{a, b, c}', 2)), + (3, ROW(3.0, '{a, b, c}', 3)), + (4, ROW(4.0, '{c, b, d}', 4)), + (5, ROW(5.0, '{NULL, e, NULL}', 5)); + + -- test_tbl_composite_with_enums_array_in_composite + INSERT INTO tst_comp_enum_what (a, b) VALUES + (ROW(1.0, '{a, b, c}', 1), ARRAY[ROW(1, '{a, b, c}', 1)::tst_comp_enum_array_t]), + (ROW(2.0, '{b, c, a}', 2), ARRAY[ROW(2, '{b, c, a}', 1)::tst_comp_enum_array_t]), + (ROW(3.0, '{c, a, b}', 1), ARRAY[ROW(3, '{c, a, b}', 1)::tst_comp_enum_array_t]), + (ROW(4.0, '{c, b, d}', 4), ARRAY[ROW(4, '{c, b, d}', 4)::tst_comp_enum_array_t]), + (ROW(5.0, '{c, NULL, b}', NULL), ARRAY[ROW(5, '{c, e, b}', 1)::tst_comp_enum_array_t]); + + -- test_tbl_mixed_composites + INSERT INTO tst_comp_mix_array (a, b) VALUES + (ROW( + ROW(1,'a',1), + ARRAY[ROW(1,'a',1)::tst_comp_basic_t, ROW(2,'b',2)::tst_comp_basic_t], + 'a', + '{a,b,NULL,c}'), + ARRAY[ + ROW( + ROW(1,'a',1), + ARRAY[ + ROW(1,'a',1)::tst_comp_basic_t, + ROW(2,'b',2)::tst_comp_basic_t, + NULL + ], + 'a', + '{a,b,c}' + )::tst_comp_mix_t + ] + ); + + -- test_tbl_range + INSERT INTO tst_range (a, b) VALUES + (1, '[1, 10]'), + (2, '[2, 20]'), + (3, '[3, 30]'), + (4, '[4, 40]'), + (5, '[5, 50]'); + + -- test_tbl_range_array + INSERT INTO tst_range_array (a, b, c) VALUES + (1, tstzrange('Mon Aug 04 00:00:00 2014 CEST'::timestamptz, 'infinity'), '{"[1,2]", "[10,20]"}'), + (2, tstzrange('Mon Aug 04 00:00:00 2014 CEST'::timestamptz - interval '2 days', 'Mon Aug 04 00:00:00 2014 CEST'::timestamptz), '{"[2,3]", "[20,30]"}'), + (3, tstzrange('Mon Aug 04 00:00:00 2014 CEST'::timestamptz - interval '3 days', 'Mon Aug 04 00:00:00 2014 CEST'::timestamptz), '{"[3,4]"}'), + (4, tstzrange('Mon Aug 04 00:00:00 2014 CEST'::timestamptz - interval '4 days', 'Mon Aug 04 00:00:00 2014 CEST'::timestamptz), '{"[4,5]", NULL, "[40,50]"}'), + (5, NULL, NULL); + + -- tst_hstore + INSERT INTO tst_hstore (a, b) VALUES + (1, '"a"=>"1"'), + (2, '"zzz"=>"foo"'), + (3, '"123"=>"321"'), + (4, '"yellow horse"=>"moaned"'); +)); + +$node_publisher->poll_query_until('postgres', $caughtup_query) + or die "Timed out while waiting for subscriber to catch up"; + +# Check the data on subscriber +my $result = $node_subscriber->safe_psql('postgres', qq( + SET timezone = '+2'; + SELECT a, b FROM tst_one_array ORDER BY a; + SELECT a, b, c, d FROM tst_arrays ORDER BY a; + SELECT a, b FROM tst_one_enum ORDER BY a; + SELECT a, b FROM tst_enums ORDER BY a; + SELECT a, b FROM tst_one_comp ORDER BY a; + SELECT a, b FROM tst_comps ORDER BY a; + SELECT a, b FROM tst_comp_enum ORDER BY a; + SELECT a, b FROM tst_comp_enum_array ORDER BY a; + SELECT a, b FROM tst_comp_one_enum_array ORDER BY a; + SELECT a, b FROM tst_comp_enum_what ORDER BY a; + SELECT a, b FROM tst_comp_mix_array ORDER BY a; + SELECT a, b FROM tst_range ORDER BY a; + SELECT a, b, c FROM tst_range_array ORDER BY a; + SELECT a, b FROM tst_hstore ORDER BY a; +)); + +is($result, '1|{1,2,3} +2|{2,3,1} +3|{3,2,1} +4|{4,3,2} +5|{5,NULL,3} +{1,2,3}|{a,b,c}|{1.1,2.2,3.3}|{"1 day","2 days","3 days"} +{2,3,1}|{b,c,a}|{2.2,3.3,1.1}|{00:02:00,00:03:00,00:01:00} +{3,1,2}|{c,a,b}|{3.3,1.1,2.2}|{"3 years","1 year","2 years"} +{4,1,2}|{d,a,b}|{4.4,1.1,2.2}|{"4 years","1 year","2 years"} +{5,NULL,NULL}|{e,NULL,b}|{5.5,1.1,NULL}|{"5 years",NULL,NULL} +1|a +2|b +3|c +4|d +5| +a|{b,c} +b|{c,a} +c|{b,a} +d|{c,b} +e|{d,NULL} +1|(1,a,1) +2|(2,b,2) +3|(3,c,3) +4|(4,d,4) +5|(,,5) +(1,a,1)|{"(1,a,1)"} +(2,b,2)|{"(2,b,2)"} +(3,c,3)|{"(3,c,3)"} +(4,d,4)|{"(4,d,3)"} +(5,e,)|{NULL,"(5,,5)"} +1|(1,a,1) +2|(2,b,2) +3|(3,c,3) +4|(4,d,4) +5|(,e,) +(1,a,1)|{"(1,a,1)"} +(2,b,2)|{"(2,b,2)"} +(3,c,3)|{"(3,c,3)"} +(4,d,3)|{"(3,d,3)"} +(5,e,3)|{"(3,e,3)",NULL} +1|(1,"{a,b,c}",1) +2|(2,"{a,b,c}",2) +3|(3,"{a,b,c}",3) +4|(4,"{c,b,d}",4) +5|(5,"{NULL,e,NULL}",5) +(1,"{a,b,c}",1)|{"(1,\"{a,b,c}\",1)"} +(2,"{b,c,a}",2)|{"(2,\"{b,c,a}\",1)"} +(3,"{c,a,b}",1)|{"(3,\"{c,a,b}\",1)"} +(4,"{c,b,d}",4)|{"(4,\"{c,b,d}\",4)"} +(5,"{c,NULL,b}",)|{"(5,\"{c,e,b}\",1)"} +("(1,a,1)","{""(1,a,1)"",""(2,b,2)""}",a,"{a,b,NULL,c}")|{"(\"(1,a,1)\",\"{\"\"(1,a,1)\"\",\"\"(2,b,2)\"\",NULL}\",a,\"{a,b,c}\")"} +1|[1,11) +2|[2,21) +3|[3,31) +4|[4,41) +5|[5,51) +1|["2014-08-04 00:00:00+02",infinity)|{"[1,3)","[10,21)"} +2|["2014-08-02 00:00:00+02","2014-08-04 00:00:00+02")|{"[2,4)","[20,31)"} +3|["2014-08-01 00:00:00+02","2014-08-04 00:00:00+02")|{"[3,5)"} +4|["2014-07-31 00:00:00+02","2014-08-04 00:00:00+02")|{"[4,6)",NULL,"[40,51)"} +5|| +1|"a"=>"1" +2|"zzz"=>"foo" +3|"123"=>"321" +4|"yellow horse"=>"moaned"', +'check replicated inserts on subscriber'); + +# Run batch of updates +$node_publisher->safe_psql('postgres', qq( + UPDATE tst_one_array SET b = '{4, 5, 6}' WHERE a = 1; + UPDATE tst_one_array SET b = '{4, 5, 6, 1}' WHERE a > 3; + UPDATE tst_arrays SET b = '{"1a", "2b", "3c"}', c = '{1.0, 2.0, 3.0}', d = '{"1 day 1 second", "2 days 2 seconds", "3 days 3 second"}' WHERE a = '{1, 2, 3}'; + UPDATE tst_arrays SET b = '{"c", "d", "e"}', c = '{3.0, 4.0, 5.0}', d = '{"3 day 1 second", "4 days 2 seconds", "5 days 3 second"}' WHERE a[1] > 3; + UPDATE tst_one_enum SET b = 'c' WHERE a = 1; + UPDATE tst_one_enum SET b = NULL WHERE a > 3; + UPDATE tst_enums SET b = '{e, NULL}' WHERE a = 'a'; + UPDATE tst_enums SET b = '{e, d}' WHERE a > 'c'; + UPDATE tst_one_comp SET b = ROW(1.0, 'A', 1) WHERE a = 1; + UPDATE tst_one_comp SET b = ROW(NULL, 'x', -1) WHERE a > 3; + UPDATE tst_comps SET b = ARRAY[ROW(9, 'x', -1)::tst_comp_basic_t] WHERE (a).a = 1.0; + UPDATE tst_comps SET b = ARRAY[NULL, ROW(9, 'x', NULL)::tst_comp_basic_t] WHERE (a).a > 3.9; + UPDATE tst_comp_enum SET b = ROW(1.0, NULL, NULL) WHERE a = 1; + UPDATE tst_comp_enum SET b = ROW(4.0, 'd', 44) WHERE a > 3; + UPDATE tst_comp_enum_array SET b = ARRAY[NULL, ROW(3, 'd', 3)::tst_comp_enum_t] WHERE a = ROW(1.0, 'a', 1)::tst_comp_enum_t; + UPDATE tst_comp_enum_array SET b = ARRAY[ROW(1, 'a', 1)::tst_comp_enum_t, ROW(2, 'b', 2)::tst_comp_enum_t] WHERE (a).a > 3; + UPDATE tst_comp_one_enum_array SET b = ROW(1.0, '{a, e, c}', NULL) WHERE a = 1; + UPDATE tst_comp_one_enum_array SET b = ROW(4.0, '{c, b, d}', 4) WHERE a > 3; + UPDATE tst_comp_enum_what SET b = ARRAY[NULL, ROW(1, '{a, b, c}', 1)::tst_comp_enum_array_t, ROW(NULL, '{a, e, c}', 2)::tst_comp_enum_array_t] WHERE (a).a = 1; + UPDATE tst_comp_enum_what SET b = ARRAY[ROW(5, '{a, b, c}', 5)::tst_comp_enum_array_t] WHERE (a).a > 3; + UPDATE tst_comp_mix_array SET b[2] = NULL WHERE ((a).a).a = 1; + UPDATE tst_range SET b = '[100, 1000]' WHERE a = 1; + UPDATE tst_range SET b = '(1, 90)' WHERE a > 3; + UPDATE tst_range_array SET c = '{"[100, 1000]"}' WHERE a = 1; + UPDATE tst_range_array SET b = tstzrange('Mon Aug 04 00:00:00 2014 CEST'::timestamptz, 'infinity'), c = '{NULL, "[11,9999999]"}' WHERE a > 3; + UPDATE tst_hstore SET b = '"updated"=>"value"' WHERE a < 3; + UPDATE tst_hstore SET b = '"also"=>"updated"' WHERE a = 3; +)); + +$node_publisher->poll_query_until('postgres', $caughtup_query) + or die "Timed out while waiting for subscriber to catch up"; + +# Check the data on subscriber +$result = $node_subscriber->safe_psql('postgres', qq( + SET timezone = '+2'; + SELECT a, b FROM tst_one_array ORDER BY a; + SELECT a, b, c, d FROM tst_arrays ORDER BY a; + SELECT a, b FROM tst_one_enum ORDER BY a; + SELECT a, b FROM tst_enums ORDER BY a; + SELECT a, b FROM tst_one_comp ORDER BY a; + SELECT a, b FROM tst_comps ORDER BY a; + SELECT a, b FROM tst_comp_enum ORDER BY a; + SELECT a, b FROM tst_comp_enum_array ORDER BY a; + SELECT a, b FROM tst_comp_one_enum_array ORDER BY a; + SELECT a, b FROM tst_comp_enum_what ORDER BY a; + SELECT a, b FROM tst_comp_mix_array ORDER BY a; + SELECT a, b FROM tst_range ORDER BY a; + SELECT a, b, c FROM tst_range_array ORDER BY a; + SELECT a, b FROM tst_hstore ORDER BY a; +)); + +is($result, '1|{4,5,6} +2|{2,3,1} +3|{3,2,1} +4|{4,5,6,1} +5|{4,5,6,1} +{1,2,3}|{1a,2b,3c}|{1,2,3}|{"1 day 00:00:01","2 days 00:00:02","3 days 00:00:03"} +{2,3,1}|{b,c,a}|{2.2,3.3,1.1}|{00:02:00,00:03:00,00:01:00} +{3,1,2}|{c,a,b}|{3.3,1.1,2.2}|{"3 years","1 year","2 years"} +{4,1,2}|{c,d,e}|{3,4,5}|{"3 days 00:00:01","4 days 00:00:02","5 days 00:00:03"} +{5,NULL,NULL}|{c,d,e}|{3,4,5}|{"3 days 00:00:01","4 days 00:00:02","5 days 00:00:03"} +1|c +2|b +3|c +4| +5| +a|{e,NULL} +b|{c,a} +c|{b,a} +d|{e,d} +e|{e,d} +1|(1,A,1) +2|(2,b,2) +3|(3,c,3) +4|(,x,-1) +5|(,x,-1) +(1,a,1)|{"(9,x,-1)"} +(2,b,2)|{"(2,b,2)"} +(3,c,3)|{"(3,c,3)"} +(4,d,4)|{NULL,"(9,x,)"} +(5,e,)|{NULL,"(9,x,)"} +1|(1,,) +2|(2,b,2) +3|(3,c,3) +4|(4,d,44) +5|(4,d,44) +(1,a,1)|{NULL,"(3,d,3)"} +(2,b,2)|{"(2,b,2)"} +(3,c,3)|{"(3,c,3)"} +(4,d,3)|{"(1,a,1)","(2,b,2)"} +(5,e,3)|{"(1,a,1)","(2,b,2)"} +1|(1,"{a,e,c}",) +2|(2,"{a,b,c}",2) +3|(3,"{a,b,c}",3) +4|(4,"{c,b,d}",4) +5|(4,"{c,b,d}",4) +(1,"{a,b,c}",1)|{NULL,"(1,\"{a,b,c}\",1)","(,\"{a,e,c}\",2)"} +(2,"{b,c,a}",2)|{"(2,\"{b,c,a}\",1)"} +(3,"{c,a,b}",1)|{"(3,\"{c,a,b}\",1)"} +(4,"{c,b,d}",4)|{"(5,\"{a,b,c}\",5)"} +(5,"{c,NULL,b}",)|{"(5,\"{a,b,c}\",5)"} +("(1,a,1)","{""(1,a,1)"",""(2,b,2)""}",a,"{a,b,NULL,c}")|{"(\"(1,a,1)\",\"{\"\"(1,a,1)\"\",\"\"(2,b,2)\"\",NULL}\",a,\"{a,b,c}\")",NULL} +1|[100,1001) +2|[2,21) +3|[3,31) +4|[2,90) +5|[2,90) +1|["2014-08-04 00:00:00+02",infinity)|{"[100,1001)"} +2|["2014-08-02 00:00:00+02","2014-08-04 00:00:00+02")|{"[2,4)","[20,31)"} +3|["2014-08-01 00:00:00+02","2014-08-04 00:00:00+02")|{"[3,5)"} +4|["2014-08-04 00:00:00+02",infinity)|{NULL,"[11,10000000)"} +5|["2014-08-04 00:00:00+02",infinity)|{NULL,"[11,10000000)"} +1|"updated"=>"value" +2|"updated"=>"value" +3|"also"=>"updated" +4|"yellow horse"=>"moaned"', +'check replicated updates on subscriber'); + +# Run batch of deletes +$node_publisher->safe_psql('postgres', qq( + DELETE FROM tst_one_array WHERE a = 1; + DELETE FROM tst_one_array WHERE b = '{2, 3, 1}'; + DELETE FROM tst_arrays WHERE a = '{1, 2, 3}'; + DELETE FROM tst_arrays WHERE a[1] = 2; + DELETE FROM tst_one_enum WHERE a = 1; + DELETE FROM tst_one_enum WHERE b = 'b'; + DELETE FROM tst_enums WHERE a = 'a'; + DELETE FROM tst_enums WHERE b[1] = 'b'; + DELETE FROM tst_one_comp WHERE a = 1; + DELETE FROM tst_one_comp WHERE (b).a = 2.0; + DELETE FROM tst_comps WHERE (a).b = 'a'; + DELETE FROM tst_comps WHERE ROW(3, 'c', 3)::tst_comp_basic_t = ANY(b); + DELETE FROM tst_comp_enum WHERE a = 1; + DELETE FROM tst_comp_enum WHERE (b).a = 2.0; + DELETE FROM tst_comp_enum_array WHERE a = ROW(1.0, 'a', 1)::tst_comp_enum_t; + DELETE FROM tst_comp_enum_array WHERE ROW(3, 'c', 3)::tst_comp_enum_t = ANY(b); + DELETE FROM tst_comp_one_enum_array WHERE a = 1; + DELETE FROM tst_comp_one_enum_array WHERE 'a' = ANY((b).b); + DELETE FROM tst_comp_enum_what WHERE (a).a = 1; + DELETE FROM tst_comp_enum_what WHERE (b[1]).b = '{c, a, b}'; + DELETE FROM tst_comp_mix_array WHERE ((a).a).a = 1; + DELETE FROM tst_range WHERE a = 1; + DELETE FROM tst_range WHERE '[10,20]' && b; + DELETE FROM tst_range_array WHERE a = 1; + DELETE FROM tst_range_array WHERE tstzrange('Mon Aug 04 00:00:00 2014 CEST'::timestamptz, 'Mon Aug 05 00:00:00 2014 CEST'::timestamptz) && b; + DELETE FROM tst_hstore WHERE a = 1; +)); + +$node_publisher->poll_query_until('postgres', $caughtup_query) + or die "Timed out while waiting for subscriber to catch up"; + +# Check the data on subscriber +$result = $node_subscriber->safe_psql('postgres', qq( + SET timezone = '+2'; + SELECT a, b FROM tst_one_array ORDER BY a; + SELECT a, b, c, d FROM tst_arrays ORDER BY a; + SELECT a, b FROM tst_one_enum ORDER BY a; + SELECT a, b FROM tst_enums ORDER BY a; + SELECT a, b FROM tst_one_comp ORDER BY a; + SELECT a, b FROM tst_comps ORDER BY a; + SELECT a, b FROM tst_comp_enum ORDER BY a; + SELECT a, b FROM tst_comp_enum_array ORDER BY a; + SELECT a, b FROM tst_comp_one_enum_array ORDER BY a; + SELECT a, b FROM tst_comp_enum_what ORDER BY a; + SELECT a, b FROM tst_comp_mix_array ORDER BY a; + SELECT a, b FROM tst_range ORDER BY a; + SELECT a, b, c FROM tst_range_array ORDER BY a; + SELECT a, b FROM tst_hstore ORDER BY a; +)); + +is($result, '3|{3,2,1} +4|{4,5,6,1} +5|{4,5,6,1} +{3,1,2}|{c,a,b}|{3.3,1.1,2.2}|{"3 years","1 year","2 years"} +{4,1,2}|{c,d,e}|{3,4,5}|{"3 days 00:00:01","4 days 00:00:02","5 days 00:00:03"} +{5,NULL,NULL}|{c,d,e}|{3,4,5}|{"3 days 00:00:01","4 days 00:00:02","5 days 00:00:03"} +3|c +4| +5| +b|{c,a} +d|{e,d} +e|{e,d} +3|(3,c,3) +4|(,x,-1) +5|(,x,-1) +(2,b,2)|{"(2,b,2)"} +(4,d,4)|{NULL,"(9,x,)"} +(5,e,)|{NULL,"(9,x,)"} +3|(3,c,3) +4|(4,d,44) +5|(4,d,44) +(2,b,2)|{"(2,b,2)"} +(4,d,3)|{"(1,a,1)","(2,b,2)"} +(5,e,3)|{"(1,a,1)","(2,b,2)"} +4|(4,"{c,b,d}",4) +5|(4,"{c,b,d}",4) +(2,"{b,c,a}",2)|{"(2,\"{b,c,a}\",1)"} +(4,"{c,b,d}",4)|{"(5,\"{a,b,c}\",5)"} +(5,"{c,NULL,b}",)|{"(5,\"{a,b,c}\",5)"} +2|["2014-08-02 00:00:00+02","2014-08-04 00:00:00+02")|{"[2,4)","[20,31)"} +3|["2014-08-01 00:00:00+02","2014-08-04 00:00:00+02")|{"[3,5)"} +2|"updated"=>"value" +3|"also"=>"updated" +4|"yellow horse"=>"moaned"', +'check replicated deletes on subscriber'); + +$node_subscriber->stop('fast'); +$node_publisher->stop('fast'); diff --git a/src/test/thread/Makefile b/src/test/thread/Makefile index 4c9bdec997..66c22691ae 100644 --- a/src/test/thread/Makefile +++ b/src/test/thread/Makefile @@ -2,7 +2,7 @@ # # Makefile for tools/thread # -# Copyright (c) 2003-2016, PostgreSQL Global Development Group +# Copyright (c) 2003-2017, PostgreSQL Global Development Group # # src/test/thread/Makefile # diff --git a/src/test/thread/thread_test.c b/src/test/thread/thread_test.c index 26d1949dc4..cb93bcc5ab 100644 --- a/src/test/thread/thread_test.c +++ b/src/test/thread/thread_test.c @@ -3,7 +3,7 @@ * test_thread_funcs.c * libc thread test program * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/test/thread/thread_test.c diff --git a/src/timezone/README b/src/timezone/README index 1df4ce1f69..a82d77c7ba 100644 --- a/src/timezone/README +++ b/src/timezone/README @@ -34,6 +34,11 @@ in the same commit. Usually, if a known abbreviation has changed meaning, the appropriate fix is to make it refer to a long-form zone name instead of a fixed GMT offset. +The core regression test suite does some simple validation of the zone +data and abbreviations data (notably by checking that the pg_timezone_names +and pg_timezone_abbrevs views don't throw errors). It's worth running it +as a cross-check on proposed updates. + When there has been a new release of Windows (probably including Service Packs), the list of matching timezones need to be updated. Run the script in src/tools/win32tzlist.pl on a Windows machine running this new @@ -45,7 +50,7 @@ match properly on the old version. Time Zone code ============== -The code in this directory is currently synced with tzcode release 2016c. +The code in this directory is currently synced with tzcode release 2016j. There are many cosmetic (and not so cosmetic) differences from the original tzcode library, but diffs in the upstream version should usually be propagated to our version. Here are some notes about that. diff --git a/src/timezone/data/africa b/src/timezone/data/africa index 50f29d5dd5..d35aaa593e 100644 --- a/src/timezone/data/africa +++ b/src/timezone/data/africa @@ -464,7 +464,7 @@ Zone Africa/Monrovia -0:43:08 - LMT 1882 # http://www.libyaherald.com/2013/10/24/correction-no-time-change-tomorrow/ # # From Paul Eggert (2013-10-25): -# For now, assume they're reverting to the pre-2012 rules of permanent UTC+2. +# For now, assume they're reverting to the pre-2012 rules of permanent UT +02. # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Libya 1951 only - Oct 14 2:00 1:00 S diff --git a/src/timezone/data/antarctica b/src/timezone/data/antarctica index a537832954..0995835752 100644 --- a/src/timezone/data/antarctica +++ b/src/timezone/data/antarctica @@ -10,9 +10,7 @@ # http://www.spri.cam.ac.uk/bob/periant.htm # for information. # Unless otherwise specified, we have no time zone information. -# -# Except for the French entries, -# I made up all time zone abbreviations mentioned here; corrections welcome! + # FORMAT is '-00' and GMTOFF is 0 for locations while uninhabited. # Argentina - year-round bases @@ -29,7 +27,7 @@ # previously sealers and scientific personnel wintered # Margaret Turner reports # http://web.archive.org/web/20021204222245/http://www.dstc.qut.edu.au/DST/marg/daylight.html -# (1999-09-30) that they're UTC+5, with no DST; +# (1999-09-30) that they're UT +05, with no DST; # presumably this is when they have visitors. # # year-round bases @@ -68,23 +66,22 @@ # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Antarctica/Casey 0 - -00 1969 - 8:00 - AWST 2009 Oct 18 2:00 - # Australian Western Std Time - 11:00 - CAST 2010 Mar 5 2:00 # Casey Time - 8:00 - AWST 2011 Oct 28 2:00 - 11:00 - CAST 2012 Feb 21 17:00u - 8:00 - AWST + 8:00 - +08 2009 Oct 18 2:00 + 11:00 - +11 2010 Mar 5 2:00 + 8:00 - +08 2011 Oct 28 2:00 + 11:00 - +11 2012 Feb 21 17:00u + 8:00 - +08 Zone Antarctica/Davis 0 - -00 1957 Jan 13 - 7:00 - DAVT 1964 Nov # Davis Time + 7:00 - +07 1964 Nov 0 - -00 1969 Feb - 7:00 - DAVT 2009 Oct 18 2:00 - 5:00 - DAVT 2010 Mar 10 20:00u - 7:00 - DAVT 2011 Oct 28 2:00 - 5:00 - DAVT 2012 Feb 21 20:00u - 7:00 - DAVT + 7:00 - +07 2009 Oct 18 2:00 + 5:00 - +05 2010 Mar 10 20:00u + 7:00 - +07 2011 Oct 28 2:00 + 5:00 - +05 2012 Feb 21 20:00u + 7:00 - +07 Zone Antarctica/Mawson 0 - -00 1954 Feb 13 - 6:00 - MAWT 2009 Oct 18 2:00 # Mawson Time - 5:00 - MAWT + 6:00 - +06 2009 Oct 18 2:00 + 5:00 - +05 # References: # Casey Weather (1998-02-26) # http://www.antdiv.gov.au/aad/exop/sfo/casey/casey_aws.html @@ -138,7 +135,7 @@ Zone Antarctica/Mawson 0 - -00 1954 Feb 13 # # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Indian/Kerguelen 0 - -00 1950 # Port-aux-Français - 5:00 - TFT # ISO code TF Time + 5:00 - +05 # # year-round base in the main continent # Dumont d'Urville, Île des Pétrels, -6640+14001, since 1956-11 @@ -149,9 +146,9 @@ Zone Indian/Kerguelen 0 - -00 1950 # Port-aux-Français # # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Antarctica/DumontDUrville 0 - -00 1947 - 10:00 - PMT 1952 Jan 14 # Port-Martin Time + 10:00 - +10 1952 Jan 14 0 - -00 1956 Nov - 10:00 - DDUT # Dumont-d'Urville Time + 10:00 - +10 # France & Italy - year-round base # Concordia, -750600+1232000, since 2005 @@ -177,7 +174,7 @@ Zone Antarctica/DumontDUrville 0 - -00 1947 # station of Japan, it's appropriate for the principal location. # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Antarctica/Syowa 0 - -00 1957 Jan 29 - 3:00 - SYOT # Syowa Time + 3:00 - +03 # See: # NIPR Antarctic Research Activities (1999-08-17) # http://www.nipr.ac.jp/english/ara01.html @@ -214,17 +211,17 @@ Zone Antarctica/Syowa 0 - -00 1957 Jan 29 # correct, but they should be quite close to the actual dates. # # From Paul Eggert (2014-03-21): -# The CET-switching Troll rules require zic from tzcode 2014b or later, so as +# The CET-switching Troll rules require zic from tz 2014b or later, so as # suggested by Bengt-Inge Larsson comment them out for now, and approximate # with only UTC and CEST. Uncomment them when 2014b is more prevalent. # # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S -#Rule Troll 2005 max - Mar 1 1:00u 1:00 CET -Rule Troll 2005 max - Mar lastSun 1:00u 2:00 CEST -#Rule Troll 2005 max - Oct lastSun 1:00u 1:00 CET -#Rule Troll 2004 max - Nov 7 1:00u 0:00 UTC +#Rule Troll 2005 max - Mar 1 1:00u 1:00 +01 +Rule Troll 2005 max - Mar lastSun 1:00u 2:00 +02 +#Rule Troll 2005 max - Oct lastSun 1:00u 1:00 +01 +#Rule Troll 2004 max - Nov 7 1:00u 0:00 +00 # Remove the following line when uncommenting the above '#Rule' lines. -Rule Troll 2004 max - Oct lastSun 1:00u 0:00 UTC +Rule Troll 2004 max - Oct lastSun 1:00u 0:00 +00 # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Antarctica/Troll 0 - -00 2005 Feb 12 0:00 Troll %s @@ -265,10 +262,10 @@ Zone Antarctica/Troll 0 - -00 2005 Feb 12 # changes during the year and does not necessarily correspond to mean # solar noon. So the Vostok time might have been whatever the clocks # happened to be during their visit. So we still don't really know what time -# it is at Vostok. But we'll guess UTC+6. +# it is at Vostok. But we'll guess +06. # Zone Antarctica/Vostok 0 - -00 1957 Dec 16 - 6:00 - VOST # Vostok time + 6:00 - +06 # S Africa - year-round bases # Marion Island, -4653+03752 @@ -301,7 +298,7 @@ Zone Antarctica/Vostok 0 - -00 1957 Dec 16 # # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Antarctica/Rothera 0 - -00 1976 Dec 1 - -3:00 - ROTT # Rothera time + -3:00 - -03 # Uruguay - year round base # Artigas, King George Island, -621104-0585107 diff --git a/src/timezone/data/asia b/src/timezone/data/asia index 533e2186d2..b2c9930853 100644 --- a/src/timezone/data/asia +++ b/src/timezone/data/asia @@ -116,13 +116,11 @@ Zone Asia/Kabul 4:36:48 - LMT 1890 # http://www.worldtimezone.com/dst_news/dst_news_armenia03.html # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Yerevan 2:58:00 - LMT 1924 May 2 - 3:00 - YERT 1957 Mar # Yerevan Time - 4:00 RussiaAsia YER%sT 1991 Mar 31 2:00s - 3:00 1:00 YERST 1991 Sep 23 # independence - 3:00 RussiaAsia AM%sT 1995 Sep 24 2:00s - 4:00 - AMT 1997 - 4:00 RussiaAsia AM%sT 2012 Feb 9 - 4:00 - AMT + 3:00 - +03 1957 Mar + 4:00 RussiaAsia +04/+05 1991 Mar 31 2:00s + 3:00 RussiaAsia +03/+04 1995 Sep 24 2:00s + 4:00 - +04 1997 + 4:00 RussiaAsia +04/+05 # Azerbaijan @@ -143,13 +141,12 @@ Rule Azer 1997 2015 - Mar lastSun 4:00 1:00 S Rule Azer 1997 2015 - Oct lastSun 5:00 0 - # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Baku 3:19:24 - LMT 1924 May 2 - 3:00 - BAKT 1957 Mar # Baku Time - 4:00 RussiaAsia BAK%sT 1991 Mar 31 2:00s - 3:00 1:00 BAKST 1991 Aug 30 # independence - 3:00 RussiaAsia AZ%sT 1992 Sep lastSun 2:00s - 4:00 - AZT 1996 # Azerbaijan Time - 4:00 EUAsia AZ%sT 1997 - 4:00 Azer AZ%sT + 3:00 - +03 1957 Mar + 4:00 RussiaAsia +04/+05 1991 Mar 31 2:00s + 3:00 RussiaAsia +03/+04 1992 Sep lastSun 2:00s + 4:00 - +04 1996 + 4:00 EUAsia +04/+05 1997 + 4:00 Azer +04/+05 # Bahrain # See Asia/Qatar. @@ -268,7 +265,7 @@ Zone Asia/Brunei 7:39:40 - LMT 1926 Mar # Bandar Seri Begawan # Milne says 6:24:40 was the meridian of the time ball observatory at Rangoon. # Zone NAME GMTOFF RULES FORMAT [UNTIL] -Zone Asia/Rangoon 6:24:40 - LMT 1880 # or Yangon +Zone Asia/Yangon 6:24:40 - LMT 1880 # or Rangoon 6:24:40 - RMT 1920 # Rangoon Mean Time? 6:30 - BURT 1942 May # Burma Time 9:00 - JST 1945 May 3 @@ -383,7 +380,7 @@ Rule PRC 1987 1991 - Apr Sun>=10 0:00 1:00 D # Lewiston (ME) Daily Sun (1939-05-29), p 17, said "Even the time is # different - the occupied districts going by Tokyo time, an hour # ahead of that prevailing in the rest of Shanghai." Guess that the -# Xujiahui Observatory was under French control and stuck with UT+8. +# Xujiahui Observatory was under French control and stuck with UT +08. # # In earlier versions of this file, China had many separate Zone entries, but # this was based on what were apparently incorrect data in Shanks & Pottenger. @@ -392,26 +389,26 @@ Rule PRC 1987 1991 - Apr Sun>=10 0:00 1:00 D # Proposed in 1918 and theoretically in effect until 1949 (although in practice # mainly observed in coastal areas), the five zones were: # -# Changbai Time ("Long-white Time", Long-white = Heilongjiang area) UT+8.5 +# Changbai Time ("Long-white Time", Long-white = Heilongjiang area) UT +08:30 # Asia/Harbin (currently a link to Asia/Shanghai) # Heilongjiang (except Mohe county), Jilin # -# Zhongyuan Time ("Central plain Time") UT+8 +# Zhongyuan Time ("Central plain Time") UT +08 # Asia/Shanghai # most of China # This currently represents most other zones as well, # as apparently these regions have been the same since 1970. # Milne gives 8:05:43.2 for Xujiahui Observatory time; round to nearest. -# Guo says Shanghai switched to UT+8 "from the end of the 19th century". +# Guo says Shanghai switched to UT +08 "from the end of the 19th century". # -# Long-shu Time (probably due to Long and Shu being two names of that area) UT+7 +# Long-shu Time (probably due to Long and Shu being two names of the area) UT +07 # Asia/Chongqing (currently a link to Asia/Shanghai) # Guangxi, Guizhou, Hainan, Ningxia, Sichuan, Shaanxi, and Yunnan; # most of Gansu; west Inner Mongolia; west Qinghai; and the Guangdong # counties Deqing, Enping, Kaiping, Luoding, Taishan, Xinxing, # Yangchun, Yangjiang, Yu'nan, and Yunfu. # -# Xin-zang Time ("Xinjiang-Tibet Time") UT+6 +# Xin-zang Time ("Xinjiang-Tibet Time") UT +06 # Asia/Urumqi # This currently represents Kunlun Time as well, # as apparently the two regions have been the same since 1970. @@ -424,7 +421,7 @@ Rule PRC 1987 1991 - Apr Sun>=10 0:00 1:00 D # Shihezi, Changji, Yanqi, Heshuo, Tuokexun, Tulufan, Shanshan, Hami, # Fukang, Kuitun, Kumukuli, Miquan, Qitai, and Turfan. # -# Kunlun Time UT+5.5 +# Kunlun Time UT +05:30 # Asia/Kashgar (currently a link to Asia/Urumqi) # West Tibet, including Pulan, Aheqi, Shufu, Shule; # West Xinjiang, including Aksu, Atushi, Yining, Hetian, Cele, Luopu, Nileke, @@ -440,7 +437,7 @@ Rule PRC 1987 1991 - Apr Sun>=10 0:00 1:00 D # # On the other hand, ethnic Uyghurs, who make up about half the # population of Xinjiang, typically use "Xinjiang time" which is two -# hours behind Beijing time, or UTC +0600. The government of the Xinjiang +# hours behind Beijing time, or UT +06. The government of the Xinjiang # Uyghur Autonomous Region, (XAUR, or just Xinjiang for short) as well as # local governments such as the Ürümqi city government use both times in # publications, referring to what is popularly called Xinjiang time as @@ -496,8 +493,8 @@ Rule PRC 1987 1991 - Apr Sun>=10 0:00 1:00 D # having the same time as Beijing. # From Paul Eggert (2014-06-30): -# In the early days of the PRC, Tibet was given its own time zone (UT+6) but -# this was withdrawn in 1959 and never reinstated; see Tubten Khétsun, +# In the early days of the PRC, Tibet was given its own time zone (UT +06) +# but this was withdrawn in 1959 and never reinstated; see Tubten Khétsun, # Memories of life in Lhasa under Chinese Rule, Columbia U Press, ISBN # 978-0231142861 (2008), translator's introduction by Matthew Akester, p x. # As this is before our 1970 cutoff, Tibet doesn't need a separate zone. @@ -511,12 +508,12 @@ Rule PRC 1987 1991 - Apr Sun>=10 0:00 1:00 D # Republics, the Soviet Union, the Kuomintang, and the People's Republic of # China, and tracking down all these organizations' timekeeping rules would be # quite a trick. Approximate this lost history by a transition from LMT to -# XJT at the start of 1928, the year of accession of the warlord Jin Shuren, +# UT +06 at the start of 1928, the year of accession of the warlord Jin Shuren, # which happens to be the date given by Shanks & Pottenger (no doubt as a -# guess) as the transition from LMT. Ignore the usage of UT+8 before -# 1986-02-01 under the theory that the transition date to UT+8 is unknown and +# guess) as the transition from LMT. Ignore the usage of +08 before +# 1986-02-01 under the theory that the transition date to +08 is unknown and # that the sort of users who prefer Asia/Urumqi now typically ignored the -# UT+8 mandate back then. +# +08 mandate back then. # Zone NAME GMTOFF RULES FORMAT [UNTIL] # Beijing time, used throughout China; represented by Shanghai. @@ -721,7 +718,7 @@ Zone Asia/Hong_Kong 7:36:42 - LMT 1904 Oct 30 # be found from historical government announcement database. # From Paul Eggert (2014-07-03): -# As per Yu-Cheng Chuang, say that Taiwan was at UT+9 from 1937-10-01 +# As per Yu-Cheng Chuang, say that Taiwan was at UT +09 from 1937-10-01 # until 1945-09-21 at 01:00, overriding Shanks & Pottenger. # Likewise, use Yu-Cheng Chuang's data for DST in Taiwan. @@ -835,16 +832,15 @@ Link Asia/Nicosia Europe/Nicosia # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Tbilisi 2:59:11 - LMT 1880 2:59:11 - TBMT 1924 May 2 # Tbilisi Mean Time - 3:00 - TBIT 1957 Mar # Tbilisi Time - 4:00 RussiaAsia TBI%sT 1991 Mar 31 2:00s - 3:00 1:00 TBIST 1991 Apr 9 # independence - 3:00 RussiaAsia GE%sT 1992 # Georgia Time - 3:00 E-EurAsia GE%sT 1994 Sep lastSun - 4:00 E-EurAsia GE%sT 1996 Oct lastSun - 4:00 1:00 GEST 1997 Mar lastSun - 4:00 E-EurAsia GE%sT 2004 Jun 27 - 3:00 RussiaAsia GE%sT 2005 Mar lastSun 2:00 - 4:00 - GET + 3:00 - +03 1957 Mar + 4:00 RussiaAsia +04/+05 1991 Mar 31 2:00s + 3:00 RussiaAsia +03/+04 1992 + 3:00 E-EurAsia +03/+04 1994 Sep lastSun + 4:00 E-EurAsia +04/+05 1996 Oct lastSun + 4:00 1:00 +05 1997 Mar lastSun + 4:00 E-EurAsia +04/+05 2004 Jun 27 + 3:00 RussiaAsia +03/+04 2005 Mar lastSun 2:00 + 4:00 - +04 # East Timor @@ -921,7 +917,7 @@ Zone Asia/Kolkata 5:53:28 - LMT 1880 # Kolkata # These would be the earliest possible times for a change. # Régimes horaires pour le monde entier, by Henri Le Corre, (Éditions # Traditionnelles, 1987, Paris) says that Java and Madura switched -# from JST to UTC+07:30 on 1945-09-23, and gives 1944-09-01 for Jayapura +# from UT +09 to +07:30 on 1945-09-23, and gives 1944-09-01 for Jayapura # (Hollandia). For now, assume all Indonesian locations other than Jayapura # switched on 1945-09-23. # @@ -932,11 +928,11 @@ Zone Asia/Kolkata 5:53:28 - LMT 1880 # Kolkata # summary published by the Time and Frequency Laboratory of the # Research Center for Calibration, Instrumentation and Metrology, # Indonesia, (2006-09-29). -# The abbreviations are: +# The time zone abbreviations and UT offsets are: # -# WIB - UTC+7 - Waktu Indonesia Barat (Indonesia western time) -# WITA - UTC+8 - Waktu Indonesia Tengah (Indonesia central time) -# WIT - UTC+9 - Waktu Indonesia Timur (Indonesia eastern time) +# WIB - +07 - Waktu Indonesia Barat (Indonesia western time) +# WITA - +08 - Waktu Indonesia Tengah (Indonesia central time) +# WIT - +09 - Waktu Indonesia Timur (Indonesia eastern time) # # Zone NAME GMTOFF RULES FORMAT [UNTIL] # Java, Sumatra @@ -1825,11 +1821,11 @@ Rule Kyrgyz 1997 2005 - Mar lastSun 2:30 1:00 S Rule Kyrgyz 1997 2004 - Oct lastSun 2:30 0 - # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Bishkek 4:58:24 - LMT 1924 May 2 - 5:00 - FRUT 1930 Jun 21 # Frunze Time - 6:00 RussiaAsia FRU%sT 1991 Mar 31 2:00s - 5:00 1:00 FRUST 1991 Aug 31 2:00 # independence - 5:00 Kyrgyz KG%sT 2005 Aug 12 # Kyrgyzstan Time - 6:00 - KGT + 5:00 - +05 1930 Jun 21 + 6:00 RussiaAsia +06/+07 1991 Mar 31 2:00s + 5:00 RussiaAsia +05/+06 1991 Aug 31 2:00 + 5:00 Kyrgyz +05/+06 2005 Aug 12 + 6:00 - +06 ############################################################################### @@ -1868,25 +1864,24 @@ Rule ROK 1957 1960 - Sep Sun>=18 0:00 0 S Rule ROK 1987 1988 - May Sun>=8 2:00 1:00 D Rule ROK 1987 1988 - Oct Sun>=8 3:00 0 S -# From Paul Eggert (2014-10-30): +# From Paul Eggert (2016-08-23): # The Korean Wikipedia entry gives the following sources for UT offsets: # -# 1908: Official Journal Article No. 3994 (Edict No. 5) +# 1908: Official Journal Article No. 3994 (decree No. 5) # 1912: Governor-General of Korea Official Gazette Issue No. 367 # (Announcement No. 338) # 1954: Presidential Decree No. 876 (1954-03-17) # 1961: Law No. 676 (1961-08-07) -# 1987: Law No. 3919 (1986-12-31) # -# The Wikipedia entry also has confusing information about a change -# to UT+9 in April 1910, but then what would be the point of the later change -# to UT+9 on 1912-01-01? Omit the 1910 change for now. +# (Another source "1987: Law No. 3919 (1986-12-31)" was in the 2014-10-30 +# edition of the Korean Wikipedia entry.) # # I guessed that time zone abbreviations through 1945 followed the same # rules as discussed under Taiwan, with nominal switches from JST to KST # when the respective cities were taken over by the Allies after WWII. # -# For Pyongyang we have no information; guess no changes since World War II. +# For Pyongyang, guess no changes from World War II until 2015, as we +# have no information otherwise. # From Steffen Thorsen (2015-08-07): # According to many news sources, North Korea is going to change to @@ -2046,7 +2041,7 @@ Zone Indian/Maldives 4:54:00 - LMT 1880 # Male # Bill Bonnet (2005-05-19) reports that the US Embassy in Ulaanbaatar says # there is only one time zone and that DST is observed, citing Microsoft # Windows XP as the source. Risto Nykänen (2005-05-16) reports that -# travelmongolia.org says there are two time zones (UTC+7, UTC+8) with no DST. +# travelmongolia.org says there are two time zones (UT +07, +08) with no DST. # Oscar van Vlijmen (2005-05-20) reports that the Mongolian Embassy in # Washington, DC says there are two time zones, with DST observed. # He also found @@ -2549,11 +2544,6 @@ Zone Asia/Karachi 4:28:12 - LMT 1907 # From Paul Eggert (2015-03-03): # http://www.timeanddate.com/time/change/west-bank/ramallah?year=2014 # says that the fall 2014 transition was Oct 23 at 24:00. -# For future dates, guess the last Friday in March at 24:00 through -# the first Friday on or after October 21 at 00:00. This is consistent with -# the predictions in today's editions of the following URLs: -# http://www.timeanddate.com/time/change/gaza-strip/gaza -# http://www.timeanddate.com/time/change/west-bank/hebron # From Hannah Kreitem (2016-03-09): # http://www.palestinecabinet.gov.ps/WebSite/ar/ViewDetails?ID=31728 @@ -2563,7 +2553,21 @@ Zone Asia/Karachi 4:28:12 - LMT 1907 # # From Paul Eggert (2016-03-12): # Predict spring transitions on March's last Saturday at 01:00 from now on. -# Leave fall predictions alone for now. + +# From Sharef Mustafa (2016-10-19): +# [T]he Palestinian cabinet decision (Mar 8th 2016) published on +# http://www.palestinecabinet.gov.ps/WebSite/Upload/Decree/GOV_17/16032016134830.pdf +# states that summer time will end on Oct 29th at 01:00. +# +# From Tim Parenti (2016-10-19): +# Predict fall transitions on October's last Saturday at 01:00 from now on. +# This is consistent with the 2016 transition as well as our spring +# predictions. +# +# From Paul Eggert (2016-10-19): +# It's also consistent with predictions in the following URLs today: +# http://www.timeanddate.com/time/change/gaza-strip/gaza +# http://www.timeanddate.com/time/change/west-bank/hebron # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule EgyptAsia 1957 only - May 10 0:00 1:00 S @@ -2592,9 +2596,10 @@ Rule Palestine 2011 only - Sep 30 0:00 0 - Rule Palestine 2012 2014 - Mar lastThu 24:00 1:00 S Rule Palestine 2012 only - Sep 21 1:00 0 - Rule Palestine 2013 only - Sep Fri>=21 0:00 0 - -Rule Palestine 2014 max - Oct Fri>=21 0:00 0 - +Rule Palestine 2014 2015 - Oct Fri>=21 0:00 0 - Rule Palestine 2015 only - Mar lastFri 24:00 1:00 S Rule Palestine 2016 max - Mar lastSat 1:00 1:00 S +Rule Palestine 2016 max - Oct lastSat 1:00 0 - # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Gaza 2:17:52 - LMT 1900 Oct @@ -2682,7 +2687,7 @@ Link Asia/Qatar Asia/Bahrain # earlier date. # # Shanks & Pottenger also state that until 1968-05-01 Saudi Arabia had two -# time zones; the other zone, at UTC+4, was in the far eastern part of +# time zones; the other zone, at UT +04, was in the far eastern part of # the country. Ignore this, as it's before our 1970 cutoff. # # Zone NAME GMTOFF RULES FORMAT [UNTIL] @@ -2744,45 +2749,31 @@ Zone Asia/Singapore 6:55:25 - LMT 1901 Jan 1 # People who live in regions under Tamil control can use [TZ='Asia/Kolkata'], # as that zone has agreed with the Tamil areas since our cutoff date of 1970. -# From K Sethu (2006-04-25): -# I think the abbreviation LKT originated from the world of computers at -# the time of or subsequent to the time zone changes by SL Government -# twice in 1996 and probably SL Government or its standardization -# agencies never declared an abbreviation as a national standard. -# -# I recollect before the recent change the government announcements -# mentioning it as simply changing Sri Lanka Standard Time or Sri Lanka -# Time and no mention was made about the abbreviation. -# -# If we look at Sri Lanka Department of Government's "Official News -# Website of Sri Lanka" ... http://www.news.lk/ we can see that they -# use SLT as abbreviation in time stamp at the beginning of each news -# item.... -# -# Within Sri Lanka I think LKT is well known among computer users and -# administrators. In my opinion SLT may not be a good choice because the -# nation's largest telcom / internet operator Sri Lanka Telcom is well -# known by that abbreviation - simply as SLT (there IP domains are -# slt.lk and sltnet.lk). -# -# But if indeed our government has adopted SLT as standard abbreviation -# (that we have not known so far) then it is better that it be used for -# all computers. - -# From Paul Eggert (2006-04-25): -# One possibility is that we wait for a bit for the dust to settle down -# and then see what people actually say in practice. +# From Sadika Sumanapala (2016-10-19): +# According to http://www.sltime.org (maintained by Measurement Units, +# Standards & Services Department, Sri Lanka) abbreviation for Sri Lanka +# standard time is SLST. +# +# From Paul Eggert (2016-10-18): +# "SLST" seems to be reasonably recent and rarely-used outside time +# zone nerd sources. I searched Google News and found three uses of +# it in the International Business Times of India in February and +# March of this year when discussing cricket match times, but nothing +# since then (though there has been a lot of cricket) and nothing in +# other English-language news sources. Our old abbreviation "LKT" is +# even worse. For now, let's use a numeric abbreviation; we can +# switch to "SLST" if it catches on. # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Colombo 5:19:24 - LMT 1880 5:19:32 - MMT 1906 # Moratuwa Mean Time - 5:30 - IST 1942 Jan 5 - 5:30 0:30 IHST 1942 Sep - 5:30 1:00 IST 1945 Oct 16 2:00 - 5:30 - IST 1996 May 25 0:00 - 6:30 - LKT 1996 Oct 26 0:30 - 6:00 - LKT 2006 Apr 15 0:30 - 5:30 - IST + 5:30 - +0530 1942 Jan 5 + 5:30 0:30 +0530/+06 1942 Sep + 5:30 1:00 +0530/+0630 1945 Oct 16 2:00 + 5:30 - +0530 1996 May 25 0:00 + 6:30 - +0630 1996 Oct 26 0:30 + 6:00 - +06 2006 Apr 15 0:30 + 5:30 - +0530 # Syria # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S @@ -2951,10 +2942,10 @@ Zone Asia/Damascus 2:25:12 - LMT 1920 # Dimashq # From Shanks & Pottenger. # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Dushanbe 4:35:12 - LMT 1924 May 2 - 5:00 - DUST 1930 Jun 21 # Dushanbe Time - 6:00 RussiaAsia DUS%sT 1991 Mar 31 2:00s - 5:00 1:00 DUSST 1991 Sep 9 2:00s - 5:00 - TJT # Tajikistan Time + 5:00 - +05 1930 Jun 21 + 6:00 RussiaAsia +06/+07 1991 Mar 31 2:00s + 5:00 1:00 +05/+06 1991 Sep 9 2:00s + 5:00 - +05 # Thailand # Zone NAME GMTOFF RULES FORMAT [UNTIL] @@ -2968,11 +2959,10 @@ Link Asia/Bangkok Asia/Vientiane # Laos # From Shanks & Pottenger. # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Ashgabat 3:53:32 - LMT 1924 May 2 # or Ashkhabad - 4:00 - ASHT 1930 Jun 21 # Ashkhabad Time - 5:00 RussiaAsia ASH%sT 1991 Mar 31 2:00 - 4:00 RussiaAsia ASH%sT 1991 Oct 27 # independence - 4:00 RussiaAsia TM%sT 1992 Jan 19 2:00 - 5:00 - TMT + 4:00 - +04 1930 Jun 21 + 5:00 RussiaAsia +05/+06 1991 Mar 31 2:00 + 4:00 RussiaAsia +04/+05 1992 Jan 19 2:00 + 5:00 - +05 # United Arab Emirates # Zone NAME GMTOFF RULES FORMAT [UNTIL] @@ -2984,20 +2974,18 @@ Link Asia/Dubai Asia/Muscat # Oman # Byalokoz 1919 says Uzbekistan was 4:27:53. # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Samarkand 4:27:53 - LMT 1924 May 2 - 4:00 - SAMT 1930 Jun 21 # Samarkand Time - 5:00 - SAMT 1981 Apr 1 - 5:00 1:00 SAMST 1981 Oct 1 - 6:00 - TAST 1982 Apr 1 # Tashkent Time - 5:00 RussiaAsia SAM%sT 1991 Sep 1 # independence - 5:00 RussiaAsia UZ%sT 1992 - 5:00 - UZT + 4:00 - +04 1930 Jun 21 + 5:00 - +05 1981 Apr 1 + 5:00 1:00 +06 1981 Oct 1 + 6:00 - +06 1982 Apr 1 + 5:00 RussiaAsia +05/+06 1992 + 5:00 - +05 # Milne says Tashkent was 4:37:10.8; round to nearest. Zone Asia/Tashkent 4:37:11 - LMT 1924 May 2 - 5:00 - TAST 1930 Jun 21 # Tashkent Time - 6:00 RussiaAsia TAS%sT 1991 Mar 31 2:00 - 5:00 RussiaAsia TAS%sT 1991 Sep 1 # independence - 5:00 RussiaAsia UZ%sT 1992 - 5:00 - UZT + 5:00 - +05 1930 Jun 21 + 6:00 RussiaAsia +06/+07 1991 Mar 31 2:00 + 5:00 RussiaAsia +05/+06 1992 + 5:00 - +05 # Vietnam diff --git a/src/timezone/data/australasia b/src/timezone/data/australasia index 0b33f67ed4..85d363295b 100644 --- a/src/timezone/data/australasia +++ b/src/timezone/data/australasia @@ -350,7 +350,13 @@ Zone Indian/Cocos 6:27:40 - LMT 1900 # commencing at 2.00 am on Sunday 1st November, 2015 and ending at # 3.00 am on Sunday 17th January, 2016. -# From Paul Eggert (2015-09-01): +# From Raymond Kumar (2016-10-04): +# http://www.fiji.gov.fj/Media-Center/Press-Releases/DAYLIGHT-SAVING-STARTS-ON-6th-NOVEMBER,-2016.aspx +# "Fiji's daylight savings will begin on Sunday, 6 November 2016, when +# clocks go forward an hour at 2am to 3am.... Daylight Saving will +# end at 3.00am on Sunday 15th January 2017." + +# From Paul Eggert (2016-10-03): # For now, guess DST from 02:00 the first Sunday in November to # 03:00 the third Sunday in January. Although ad hoc, it matches # transitions since late 2014 and seems more likely to match future @@ -545,7 +551,7 @@ Zone Pacific/Port_Moresby 9:48:40 - LMT 1880 # Base the Bougainville entry on the Arawa-Kieta region, which appears to have # the most people even though it was devastated in the Bougainville Civil War. # -# Although Shanks gives 1942-03-15 / 1943-11-01 for JST, these dates +# Although Shanks gives 1942-03-15 / 1943-11-01 for UT +09, these dates # are apparently rough guesswork from the starts of military campaigns. # The World War II entries below are instead based on Arawa-Kieta. # The Japanese occupied Kieta in July 1942, @@ -553,8 +559,8 @@ Zone Pacific/Port_Moresby 9:48:40 - LMT 1880 # http://pwencycl.kgbudge.com/B/o/Bougainville.htm # and seem to have controlled it until their 1945-08-21 surrender. # -# The Autonomous Region of Bougainville plans to switch from UTC+10 to UTC+11 -# on 2014-12-28 at 02:00. They call UTC+11 "Bougainville Standard Time"; +# The Autonomous Region of Bougainville switched from UT +10 to +11 +# on 2014-12-28 at 02:00. They call +11 "Bougainville Standard Time"; # abbreviate this as BST. See: # http://www.bougainville24.com/bougainville-issues/bougainville-gets-own-timezone/ # @@ -620,7 +626,7 @@ Link Pacific/Pago_Pago Pacific/Midway # in US minor outlying islands # From Paul Eggert (2014-06-27): # The International Date Line Act 2011 # http://www.parliament.gov.ws/images/ACTS/International_Date_Line_Act__2011_-_Eng.pdf -# changed Samoa from UTC-11 to UTC+13, effective "12 o'clock midnight, on +# changed Samoa from UT -11 to +13, effective "12 o'clock midnight, on # Thursday 29th December 2011". The International Date Line was adjusted # accordingly. @@ -715,7 +721,7 @@ Zone Pacific/Funafuti 11:56:52 - LMT 1901 # 1886-1891; Baker was similar but exact dates are not known. # Inhabited by civilians 1935-1942; U.S. military bases 1943-1944; # uninhabited thereafter. -# Howland observed Hawaii Standard Time (UT-10:30) in 1937; +# Howland observed Hawaii Standard Time (UT -10:30) in 1937; # see page 206 of Elgen M. Long and Marie K. Long, # Amelia Earhart: the Mystery Solved, Simon & Schuster (2000). # So most likely Howland and Baker observed Hawaii Time from 1935 @@ -1473,7 +1479,7 @@ Zone Pacific/Wallis 12:15:20 - LMT 1901 # Zealand time. I understand that is the time they keep locally, anyhow." # For now, assume this practice goes back to the introduction of standard time # in New Zealand, as this would make Chatham Islands time almost exactly match -# LMT back when New Zealand was at UTC+11:30; also, assume Chatham Islands did +# LMT back when New Zealand was at UT +11:30; also, assume Chatham Islands did # not observe New Zealand's prewar DST. ############################################################################### @@ -1529,7 +1535,7 @@ Zone Pacific/Wallis 12:15:20 - LMT 1901 # For now, we assume the Ladrones switched at the same time as the Philippines; # see Asia/Manila. -# US Public Law 106-564 (2000-12-23) made UTC+10 the official standard time, +# US Public Law 106-564 (2000-12-23) made UT +10 the official standard time, # under the name "Chamorro Standard Time". There is no official abbreviation, # but Congressman Robert A. Underwood, author of the bill that became law, # wrote in a press release (2000-12-27) that he will seek the use of "ChST". @@ -1541,15 +1547,15 @@ Zone Pacific/Wallis 12:15:20 - LMT 1901 # "I am certain, having lived there for the past decade, that 'Truk' # (now properly known as Chuuk) ... is in the time zone GMT+10." # -# Shanks & Pottenger write that Truk switched from UTC+10 to UTC+11 +# Shanks & Pottenger write that Truk switched from UT +10 to +11 # on 1978-10-01; ignore this for now. # From Paul Eggert (1999-10-29): # The Federated States of Micronesia Visitors Board writes in # The Federated States of Micronesia - Visitor Information (1999-01-26) # http://www.fsmgov.org/info/clocks.html -# that Truk and Yap are UTC+10, and Ponape and Kosrae are UTC+11. -# We don't know when Kosrae switched from UTC+12; assume January 1 for now. +# that Truk and Yap are UT +10, and Ponape and Kosrae are +11. +# We don't know when Kosrae switched from +12; assume January 1 for now. # Midway @@ -1615,11 +1621,11 @@ Zone Pacific/Wallis 12:15:20 - LMT 1901 # ordaining - by a masterpiece of diplomatic flattery - that # the Fourth of July should be celebrated twice in that year." -# Although Shanks & Pottenger says they both switched to UTC-11:30 -# in 1911, and to UTC-11 in 1950. many earlier sources give UTC-11 +# Although Shanks & Pottenger says they both switched to UT -11:30 +# in 1911, and to -11 in 1950. many earlier sources give -11 # for American Samoa, e.g., the US National Bureau of Standards # circular "Standard Time Throughout the World", 1932. -# Assume American Samoa switched to UTC-11 in 1911, not 1950, +# Assume American Samoa switched to -11 in 1911, not 1950, # and that after 1950 they agreed until (western) Samoa skipped a # day in 2011. Assume also that the Samoas follow the US and New # Zealand's "ST"/"DT" style of daylight-saving abbreviations. diff --git a/src/timezone/data/backward b/src/timezone/data/backward index aab237a5e2..aa23dd844e 100644 --- a/src/timezone/data/backward +++ b/src/timezone/data/backward @@ -36,6 +36,7 @@ Link Asia/Shanghai Asia/Harbin Link Asia/Urumqi Asia/Kashgar Link Asia/Kathmandu Asia/Katmandu Link Asia/Macau Asia/Macao +Link Asia/Yangon Asia/Rangoon Link Asia/Ho_Chi_Minh Asia/Saigon Link Asia/Jerusalem Asia/Tel_Aviv Link Asia/Thimphu Asia/Thimbu diff --git a/src/timezone/data/backzone b/src/timezone/data/backzone index 13dc8d4d13..4a5085f422 100644 --- a/src/timezone/data/backzone +++ b/src/timezone/data/backzone @@ -194,9 +194,9 @@ Zone Africa/Lusaka 1:53:08 - LMT 1903 Mar # Equatorial Guinea # -# Although Shanks says that Malabo switched from UTC to UTC+1 on 1963-12-15, +# Although Shanks says that Malabo switched from UT +00 to +01 on 1963-12-15, # a Google Books search says that London Calling, Issues 432-465 (1948), p 19, -# says that Spanish Guinea was at GMT+1 back then. The Shanks data entries +# says that Spanish Guinea was at +01 back then. The Shanks data entries # are most likely wrong, but we have nothing better; use them here for now. # Zone Africa/Malabo 0:35:08 - LMT 1912 @@ -479,14 +479,14 @@ Zone Asia/Muscat 3:54:24 - LMT 1920 # From Paul Eggert (2014-08-11), after a heads-up from Stephen Colebourne: # According to a Portuguese decree (1911-05-26) # http://dre.pt/pdf1sdip/1911/05/12500/23132313.pdf -# Portuguese India switched to GMT+5 on 1912-01-01. +# Portuguese India switched to UT +05 on 1912-01-01. #Zone Asia/Panaji [not enough info to complete] # Cambodia # From Paul Eggert (2014-10-11): # See Asia/Ho_Chi_Minh for the source for most of this data. Also, guess -# (1) Cambodia reverted to UT+7 on 1945-09-02, when Vietnam did, and -# (2) they also reverted to UT+7 on 1953-11-09, the date of independence. +# (1) Cambodia reverted to UT +07 on 1945-09-02, when Vietnam did, and +# (2) they also reverted to +07 on 1953-11-09, the date of independence. # These guesses are probably wrong but they're better than guessing no # transitions there. Zone Asia/Phnom_Penh 6:59:40 - LMT 1906 Jul 1 @@ -506,8 +506,8 @@ Zone Asia/Tel_Aviv 2:19:04 - LMT 1880 # Laos # From Paul Eggert (2014-10-11): # See Asia/Ho_Chi_Minh for the source for most of this data. -# Trần's book says that Laos reverted to UT+7 on 1955-04-15. -# Also, guess that Laos reverted to UT+7 on 1945-09-02, when Vietnam did; +# Trần's book says that Laos reverted to UT +07 on 1955-04-15. +# Also, guess that Laos reverted to +07 on 1945-09-02, when Vietnam did; # this is probably wrong but it's better than guessing no transition. Zone Asia/Vientiane 6:50:24 - LMT 1906 Jul 1 7:06:30 - PLMT 1911 May 1 diff --git a/src/timezone/data/etcetera b/src/timezone/data/etcetera index c2e25328d5..f5fa4c94b4 100644 --- a/src/timezone/data/etcetera +++ b/src/timezone/data/etcetera @@ -8,6 +8,13 @@ # need now for the entries that are not on UTC are for ships at sea # that cannot use POSIX TZ settings. +# Starting with POSIX 1003.1-2001, the entries below are all +# unnecessary as settings for the TZ environment variable. E.g., +# instead of TZ='Etc/GMT+4' one can use the POSIX setting TZ='<-04>+4'. +# +# Do not use a POSIX TZ setting like TZ='GMT+4', which is four hours +# behind GMT but uses the completely misleading abbreviation "GMT". + Zone Etc/GMT 0 - GMT Zone Etc/UTC 0 - UTC Zone Etc/UCT 0 - UCT @@ -26,23 +33,13 @@ Link Etc/GMT Etc/GMT-0 Link Etc/GMT Etc/GMT+0 Link Etc/GMT Etc/GMT0 -# We use POSIX-style signs in the Zone names and the output abbreviations, +# Be consistent with POSIX TZ settings in the Zone names, # even though this is the opposite of what many people expect. # POSIX has positive signs west of Greenwich, but many people expect # positive signs east of Greenwich. For example, TZ='Etc/GMT+4' uses -# the abbreviation "GMT+4" and corresponds to 4 hours behind UT +# the abbreviation "-04" and corresponds to 4 hours behind UT # (i.e. west of Greenwich) even though many people would expect it to # mean 4 hours ahead of UT (i.e. east of Greenwich). -# -# In the draft 5 of POSIX 1003.1-200x, the angle bracket notation allows for -# TZ='+4'; if you want time zone abbreviations conforming to -# ISO 8601 you can use TZ='<-0400>+4'. Thus the commonly-expected -# offset is kept within the angle bracket (and is used for display) -# while the POSIX sign is kept outside the angle bracket (and is used -# for calculation). -# -# Do not use a TZ setting like TZ='GMT+4', which is four hours behind -# GMT but uses the completely misleading abbreviation "GMT". # Earlier incarnations of this package were not POSIX-compliant, # and had lines such as @@ -51,30 +48,31 @@ Link Etc/GMT Etc/GMT0 # way does a # zic -l GMT-12 # so we moved the names into the Etc subdirectory. +# Also, the time zone abbreviations are now compatible with %z. -Zone Etc/GMT-14 14 - GMT-14 # 14 hours ahead of GMT -Zone Etc/GMT-13 13 - GMT-13 -Zone Etc/GMT-12 12 - GMT-12 -Zone Etc/GMT-11 11 - GMT-11 -Zone Etc/GMT-10 10 - GMT-10 -Zone Etc/GMT-9 9 - GMT-9 -Zone Etc/GMT-8 8 - GMT-8 -Zone Etc/GMT-7 7 - GMT-7 -Zone Etc/GMT-6 6 - GMT-6 -Zone Etc/GMT-5 5 - GMT-5 -Zone Etc/GMT-4 4 - GMT-4 -Zone Etc/GMT-3 3 - GMT-3 -Zone Etc/GMT-2 2 - GMT-2 -Zone Etc/GMT-1 1 - GMT-1 -Zone Etc/GMT+1 -1 - GMT+1 -Zone Etc/GMT+2 -2 - GMT+2 -Zone Etc/GMT+3 -3 - GMT+3 -Zone Etc/GMT+4 -4 - GMT+4 -Zone Etc/GMT+5 -5 - GMT+5 -Zone Etc/GMT+6 -6 - GMT+6 -Zone Etc/GMT+7 -7 - GMT+7 -Zone Etc/GMT+8 -8 - GMT+8 -Zone Etc/GMT+9 -9 - GMT+9 -Zone Etc/GMT+10 -10 - GMT+10 -Zone Etc/GMT+11 -11 - GMT+11 -Zone Etc/GMT+12 -12 - GMT+12 +Zone Etc/GMT-14 14 - +14 +Zone Etc/GMT-13 13 - +13 +Zone Etc/GMT-12 12 - +12 +Zone Etc/GMT-11 11 - +11 +Zone Etc/GMT-10 10 - +10 +Zone Etc/GMT-9 9 - +09 +Zone Etc/GMT-8 8 - +08 +Zone Etc/GMT-7 7 - +07 +Zone Etc/GMT-6 6 - +06 +Zone Etc/GMT-5 5 - +05 +Zone Etc/GMT-4 4 - +04 +Zone Etc/GMT-3 3 - +03 +Zone Etc/GMT-2 2 - +02 +Zone Etc/GMT-1 1 - +01 +Zone Etc/GMT+1 -1 - -01 +Zone Etc/GMT+2 -2 - -02 +Zone Etc/GMT+3 -3 - -03 +Zone Etc/GMT+4 -4 - -04 +Zone Etc/GMT+5 -5 - -05 +Zone Etc/GMT+6 -6 - -06 +Zone Etc/GMT+7 -7 - -07 +Zone Etc/GMT+8 -8 - -08 +Zone Etc/GMT+9 -9 - -09 +Zone Etc/GMT+10 -10 - -10 +Zone Etc/GMT+11 -11 - -11 +Zone Etc/GMT+12 -12 - -12 diff --git a/src/timezone/data/europe b/src/timezone/data/europe index cd3a0883d8..a7dc350d1e 100644 --- a/src/timezone/data/europe +++ b/src/timezone/data/europe @@ -75,8 +75,7 @@ # 1:00 CET CEST CEMT Central Europe # 1:00:14 SET Swedish (1879-1899)* # 2:00 EET EEST Eastern Europe -# 3:00 FET Further-eastern Europe (2011-2014)* -# 3:00 MSK MSD MSM* Minsk, Moscow +# 3:00 MSK MSD Moscow # From Peter Ilieve (1994-12-04), # The original six [EU members]: Belgium, France, (West) Germany, Italy, @@ -583,16 +582,33 @@ Rule E-Eur 1979 1995 - Sep lastSun 0:00 0 - Rule E-Eur 1981 max - Mar lastSun 0:00 1:00 S Rule E-Eur 1996 max - Oct lastSun 0:00 0 - + +# Daylight saving time for Russia and the Soviet Union +# +# The 1917-1921 decree URLs are from Alexander Belopolsky (2016-08-23). + # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Russia 1917 only - Jul 1 23:00 1:00 MST # Moscow Summer Time +# +# Decree No. 142 (1917-12-22) http://istmat.info/node/28137 Rule Russia 1917 only - Dec 28 0:00 0 MMT # Moscow Mean Time +# +# Decree No. 497 (1918-05-30) http://istmat.info/node/30001 Rule Russia 1918 only - May 31 22:00 2:00 MDST # Moscow Double Summer Time Rule Russia 1918 only - Sep 16 1:00 1:00 MST +# +# Decree No. 258 (1919-05-29) http://istmat.info/node/37949 Rule Russia 1919 only - May 31 23:00 2:00 MDST -Rule Russia 1919 only - Jul 1 2:00 1:00 MSD +# +Rule Russia 1919 only - Jul 1 0:00u 1:00 MSD Rule Russia 1919 only - Aug 16 0:00 0 MSK +# +# Decree No. 63 (1921-02-03) http://istmat.info/node/45840 Rule Russia 1921 only - Feb 14 23:00 1:00 MSD -Rule Russia 1921 only - Mar 20 23:00 2:00 MSM # Midsummer +# +# Decree No. 121 (1921-03-07) http://istmat.info/node/45949 +Rule Russia 1921 only - Mar 20 23:00 2:00 +05 +# Rule Russia 1921 only - Sep 1 0:00 1:00 MSD Rule Russia 1921 only - Oct 1 0:00 0 - # Act No. 925 of the Council of Ministers of the USSR (1980-10-24): @@ -775,8 +791,6 @@ Zone Europe/Vienna 1:05:21 - LMT 1893 Apr # From Alexander Bokovoy (2014-10-09): # Belarussian government decided against changing to winter time.... # http://eng.belta.by/all_news/society/Belarus-decides-against-adjusting-time-in-Russias-wake_i_76335.html -# From Paul Eggert (2014-10-08): -# Hence Belarus can share time zone abbreviations with Moscow again. # # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Europe/Minsk 1:50:16 - LMT 1880 @@ -787,8 +801,7 @@ Zone Europe/Minsk 1:50:16 - LMT 1880 3:00 Russia MSK/MSD 1990 3:00 - MSK 1991 Mar 31 2:00s 2:00 Russia EE%sT 2011 Mar 27 2:00s - 3:00 - FET 2014 Oct 26 1:00s - 3:00 - MSK + 3:00 - +03 # Belgium # @@ -1296,7 +1309,7 @@ Zone Europe/Paris 0:09:21 - LMT 1891 Mar 15 0:01 # http://www.parlament-berlin.de/pds-fraktion.nsf/727459127c8b66ee8525662300459099/defc77cb784f180ac1256c2b0030274b/$FILE/bersarint.pdf # says that Bersarin issued an order to use Moscow time on May 20. # However, Moscow did not observe daylight saving in 1945, so -# this was equivalent to CEMT (GMT+3), not GMT+4. +# this was equivalent to UT +03, not +04. # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S @@ -1895,7 +1908,7 @@ Zone Europe/Monaco 0:29:32 - LMT 1891 Mar 15 # Amsterdam mean time. # The data entries before 1945 are taken from -# http://www.phys.uu.nl/~vgent/wettijd/wettijd.htm +# http://www.staff.science.uu.nl/~gent0113/idl/idl.htm # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Neth 1916 only - May 1 0:00 1:00 NST # Netherlands Summer Time @@ -2260,7 +2273,6 @@ Zone Europe/Bucharest 1:44:24 - LMT 1891 Oct # http://www.worldtimezone.com/dst_news/dst_news_russia-map-2014-07.html # From Paul Eggert (2006-03-22): -# Except for Moscow after 1919-07-01, I invented the time zone abbreviations. # Moscow time zone abbreviations after 1919-07-01, and Moscow rules after 1991, # are from Andrey A. Chernov. The rest is from Shanks & Pottenger, # except we follow Chernov's report that 1992 DST transitions were Sat @@ -2336,7 +2348,7 @@ Zone Europe/Kaliningrad 1:22:00 - LMT 1893 Apr 2:00 Poland CE%sT 1946 3:00 Russia MSK/MSD 1989 Mar 26 2:00s 2:00 Russia EE%sT 2011 Mar 27 2:00s - 3:00 - FET 2014 Oct 26 2:00s + 3:00 - +03 2014 Oct 26 2:00s 2:00 - EET @@ -2389,6 +2401,16 @@ Zone Europe/Kaliningrad 1:22:00 - LMT 1893 Apr # 78 RU-SPE Saint Petersburg # 83 RU-NEN Nenets Autonomous Okrug +# From Paul Eggert (2016-08-23): +# The Soviets switched to UT-based time in 1919. Decree No. 59 +# (1919-02-08) http://istmat.info/node/35567 established UT-based time +# zones, and Decree No. 147 (1919-03-29) http://istmat.info/node/35854 +# specified a transition date of 1919-07-01, apparently at 00:00 UT. +# No doubt only the Soviet-controlled regions switched on that date; +# later transitions to UT-based time in other parts of Russia are +# taken from what appear to be guesses by Shanks. +# (Thanks to Alexander Belopolsky for pointers to the decrees.) + # From Stepan Golosunov (2016-03-07): # 11. Regions-violators, 1981-1982. # Wikipedia refers to @@ -2430,7 +2452,7 @@ Zone Europe/Kaliningrad 1:22:00 - LMT 1893 Apr # attributes the 1982 changes to the Act of the Council of Ministers # of the USSR No. 126 from 18.02.1982. 1980-925.txt also adds # Udmurtia to the list of affected territories and lists Khatangsky -# district separately from Taymyr Autonomous Okurg. Probably erroneously. +# district separately from Taymyr Autonomous Okrug. Probably erroneously. # # The affected territories are currently listed under Europe/Moscow, # Asia/Yekaterinburg and Asia/Krasnoyarsk. @@ -2490,7 +2512,7 @@ Zone Europe/Kaliningrad 1:22:00 - LMT 1893 Apr Zone Europe/Moscow 2:30:17 - LMT 1880 2:30:17 - MMT 1916 Jul 3 # Moscow Mean Time - 2:31:19 Russia %s 1919 Jul 1 2:00 + 2:31:19 Russia %s 1919 Jul 1 0:00u 3:00 Russia %s 1921 Oct 3:00 Russia MSK/MSD 1922 Oct 2:00 - EET 1930 Jun 21 @@ -2573,22 +2595,21 @@ Zone Europe/Astrakhan 3:12:12 - LMT 1924 May # The 1988 transition is from USSR act No. 5 (1988-01-04). Zone Europe/Volgograd 2:57:40 - LMT 1920 Jan 3 - 3:00 - TSAT 1925 Apr 6 # Tsaritsyn Time - 3:00 - STAT 1930 Jun 21 # Stalingrad Time - 4:00 - STAT 1961 Nov 11 - 4:00 Russia VOL%sT 1988 Mar 27 2:00s # Volgograd T - 3:00 Russia VOL%sT 1991 Mar 31 2:00s - 4:00 - VOLT 1992 Mar 29 2:00s - 3:00 Russia MSK/MSD 2011 Mar 27 2:00s - 4:00 - MSK 2014 Oct 26 2:00s - 3:00 - MSK + 3:00 - +03 1930 Jun 21 + 4:00 - +04 1961 Nov 11 + 4:00 Russia +04/+05 1988 Mar 27 2:00s + 3:00 Russia +03/+04 1991 Mar 31 2:00s + 4:00 - +04 1992 Mar 29 2:00s + 3:00 Russia +03/+04 2011 Mar 27 2:00s + 4:00 - +04 2014 Oct 26 2:00s + 3:00 - +03 # From Paul Eggert (2016-03-18): # Europe/Kirov covers: # 43 RU-KIR Kirov Oblast # The 1989 transition is from USSR act No. 227 (1989-03-14). # -Zone Europe/Kirov 3:18:48 - LMT 1919 Jul 1 2:00 +Zone Europe/Kirov 3:18:48 - LMT 1919 Jul 1 0:00u 3:00 - +03 1930 Jun 21 4:00 Russia +04/+05 1989 Mar 26 2:00s 3:00 Russia +03/+04 1991 Mar 31 2:00s @@ -2606,16 +2627,16 @@ Zone Europe/Kirov 3:18:48 - LMT 1919 Jul 1 2:00 # Byalokoz 1919 says Samara was 3:20:20. # The 1989 transition is from USSR act No. 227 (1989-03-14). -Zone Europe/Samara 3:20:20 - LMT 1919 Jul 1 2:00 - 3:00 - SAMT 1930 Jun 21 # Samara Time - 4:00 - SAMT 1935 Jan 27 - 4:00 Russia KUY%sT 1989 Mar 26 2:00s # Kuybyshev - 3:00 Russia MSK/MSD 1991 Mar 31 2:00s - 2:00 Russia EE%sT 1991 Sep 29 2:00s - 3:00 - SAMT 1991 Oct 20 3:00 - 4:00 Russia SAM%sT 2010 Mar 28 2:00s - 3:00 Russia SAM%sT 2011 Mar 27 2:00s - 4:00 - SAMT +Zone Europe/Samara 3:20:20 - LMT 1919 Jul 1 0:00u + 3:00 - +03 1930 Jun 21 + 4:00 - +04 1935 Jan 27 + 4:00 Russia +04/+05 1989 Mar 26 2:00s + 3:00 Russia +03/+04 1991 Mar 31 2:00s + 2:00 Russia +02/+03 1991 Sep 29 2:00s + 3:00 - +03 1991 Oct 20 3:00 + 4:00 Russia +04/+05 2010 Mar 28 2:00s + 3:00 Russia +03/+04 2011 Mar 27 2:00s + 4:00 - +04 # From Paul Eggert (2016-03-18): # Europe/Ulyanovsk covers: @@ -2630,7 +2651,7 @@ Zone Europe/Samara 3:20:20 - LMT 1919 Jul 1 2:00 # From Matt Johnson (2016-03-09): # http://publication.pravo.gov.ru/Document/View/0001201603090051 -Zone Europe/Ulyanovsk 3:13:36 - LMT 1919 Jul 1 2:00 +Zone Europe/Ulyanovsk 3:13:36 - LMT 1919 Jul 1 0:00u 3:00 - +03 1930 Jun 21 4:00 Russia +04/+05 1989 Mar 26 2:00s 3:00 Russia +03/+04 1991 Mar 31 2:00s @@ -2662,12 +2683,12 @@ Zone Europe/Ulyanovsk 3:13:36 - LMT 1919 Jul 1 2:00 Zone Asia/Yekaterinburg 4:02:33 - LMT 1916 Jul 3 3:45:05 - PMT 1919 Jul 15 4:00 - 4:00 - SVET 1930 Jun 21 # Sverdlovsk Time - 5:00 Russia SVE%sT 1991 Mar 31 2:00s - 4:00 Russia SVE%sT 1992 Jan 19 2:00s - 5:00 Russia YEK%sT 2011 Mar 27 2:00s - 6:00 - YEKT 2014 Oct 26 2:00s - 5:00 - YEKT + 4:00 - +04 1930 Jun 21 + 5:00 Russia +05/+06 1991 Mar 31 2:00s + 4:00 Russia +04/+05 1992 Jan 19 2:00s + 5:00 Russia +05/+06 2011 Mar 27 2:00s + 6:00 - +06 2014 Oct 26 2:00s + 5:00 - +05 # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25): @@ -2677,12 +2698,12 @@ Zone Asia/Yekaterinburg 4:02:33 - LMT 1916 Jul 3 # Byalokoz 1919 says Omsk was 4:53:30. Zone Asia/Omsk 4:53:30 - LMT 1919 Nov 14 - 5:00 - OMST 1930 Jun 21 # Omsk Time - 6:00 Russia OMS%sT 1991 Mar 31 2:00s - 5:00 Russia OMS%sT 1992 Jan 19 2:00s - 6:00 Russia OMS%sT 2011 Mar 27 2:00s - 7:00 - OMST 2014 Oct 26 2:00s - 6:00 - OMST + 5:00 - +05 1930 Jun 21 + 6:00 Russia +06/+07 1991 Mar 31 2:00s + 5:00 Russia +05/+06 1992 Jan 19 2:00s + 6:00 Russia +06/+07 2011 Mar 27 2:00s + 7:00 - +07 2014 Oct 26 2:00s + 6:00 - +06 # From Paul Eggert (2016-02-22): # Asia/Barnaul covers: @@ -2762,7 +2783,7 @@ Zone Asia/Novosibirsk 5:31:40 - LMT 1919 Dec 14 6:00 # Note that time belts (numbered from 2 (Moscow) to 12 according to their # GMT/UTC offset and having too many exceptions like regions formally # belonging to one belt but using time from another) were replaced -# with time zones in 2011 with different numberings (there was a +# with time zones in 2011 with different numbering (there was a # 2-hour gap between second and third zones in 2011-2014). # From Stepan Golosunov (2016-04-12): @@ -2845,12 +2866,12 @@ Zone Asia/Novokuznetsk 5:48:48 - LMT 1924 May 1 # Byalokoz 1919 says Krasnoyarsk was 6:11:26. Zone Asia/Krasnoyarsk 6:11:26 - LMT 1920 Jan 6 - 6:00 - KRAT 1930 Jun 21 # Krasnoyarsk Time - 7:00 Russia KRA%sT 1991 Mar 31 2:00s - 6:00 Russia KRA%sT 1992 Jan 19 2:00s - 7:00 Russia KRA%sT 2011 Mar 27 2:00s - 8:00 - KRAT 2014 Oct 26 2:00s - 7:00 - KRAT + 6:00 - +06 1930 Jun 21 + 7:00 Russia +07/+08 1991 Mar 31 2:00s + 6:00 Russia +06/+07 1992 Jan 19 2:00s + 7:00 Russia +07/+08 2011 Mar 27 2:00s + 8:00 - +08 2014 Oct 26 2:00s + 7:00 - +07 # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25): @@ -2867,12 +2888,12 @@ Zone Asia/Krasnoyarsk 6:11:26 - LMT 1920 Jan 6 Zone Asia/Irkutsk 6:57:05 - LMT 1880 6:57:05 - IMT 1920 Jan 25 # Irkutsk Mean Time - 7:00 - IRKT 1930 Jun 21 # Irkutsk Time - 8:00 Russia IRK%sT 1991 Mar 31 2:00s - 7:00 Russia IRK%sT 1992 Jan 19 2:00s - 8:00 Russia IRK%sT 2011 Mar 27 2:00s - 9:00 - IRKT 2014 Oct 26 2:00s - 8:00 - IRKT + 7:00 - +07 1930 Jun 21 + 8:00 Russia +08/+09 1991 Mar 31 2:00s + 7:00 Russia +07/+08 1992 Jan 19 2:00s + 8:00 Russia +08/+09 2011 Mar 27 2:00s + 9:00 - +09 2014 Oct 26 2:00s + 8:00 - +08 # From Tim Parenti (2014-07-06): @@ -2889,13 +2910,13 @@ Zone Asia/Irkutsk 6:57:05 - LMT 1880 # http://publication.pravo.gov.ru/Document/View/0001201512300107 Zone Asia/Chita 7:33:52 - LMT 1919 Dec 15 - 8:00 - YAKT 1930 Jun 21 # Yakutsk Time - 9:00 Russia YAK%sT 1991 Mar 31 2:00s - 8:00 Russia YAK%sT 1992 Jan 19 2:00s - 9:00 Russia YAK%sT 2011 Mar 27 2:00s - 10:00 - YAKT 2014 Oct 26 2:00s - 8:00 - IRKT 2016 Mar 27 2:00 - 9:00 - YAKT + 8:00 - +08 1930 Jun 21 + 9:00 Russia +09/+10 1991 Mar 31 2:00s + 8:00 Russia +08/+09 1992 Jan 19 2:00s + 9:00 Russia +09/+10 2011 Mar 27 2:00s + 10:00 - +10 2014 Oct 26 2:00s + 8:00 - +08 2016 Mar 27 2:00 + 9:00 - +09 # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29): @@ -2935,12 +2956,12 @@ Zone Asia/Chita 7:33:52 - LMT 1919 Dec 15 # Byalokoz 1919 says Yakutsk was 8:38:58. Zone Asia/Yakutsk 8:38:58 - LMT 1919 Dec 15 - 8:00 - YAKT 1930 Jun 21 # Yakutsk Time - 9:00 Russia YAK%sT 1991 Mar 31 2:00s - 8:00 Russia YAK%sT 1992 Jan 19 2:00s - 9:00 Russia YAK%sT 2011 Mar 27 2:00s - 10:00 - YAKT 2014 Oct 26 2:00s - 9:00 - YAKT + 8:00 - +08 1930 Jun 21 + 9:00 Russia +09/+10 1991 Mar 31 2:00s + 8:00 Russia +08/+09 1992 Jan 19 2:00s + 9:00 Russia +09/+10 2011 Mar 27 2:00s + 10:00 - +10 2014 Oct 26 2:00s + 9:00 - +09 # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29): @@ -2958,12 +2979,12 @@ Zone Asia/Yakutsk 8:38:58 - LMT 1919 Dec 15 # Go with Byalokoz. Zone Asia/Vladivostok 8:47:31 - LMT 1922 Nov 15 - 9:00 - VLAT 1930 Jun 21 # Vladivostok Time - 10:00 Russia VLA%sT 1991 Mar 31 2:00s - 9:00 Russia VLA%sT 1992 Jan 19 2:00s - 10:00 Russia VLA%sT 2011 Mar 27 2:00s - 11:00 - VLAT 2014 Oct 26 2:00s - 10:00 - VLAT + 9:00 - +09 1930 Jun 21 + 10:00 Russia +10/+11 1991 Mar 31 2:00s + 9:00 Russia +09/+10 1992 Jan 19 2:00s + 10:00 Russia +10/+11 2011 Mar 27 2:00s + 11:00 - +11 2014 Oct 26 2:00s + 10:00 - +10 # From Tim Parenti (2014-07-03): @@ -2981,14 +3002,14 @@ Zone Asia/Vladivostok 8:47:31 - LMT 1922 Nov 15 # This transition is no doubt wrong, but we have no better info. Zone Asia/Khandyga 9:02:13 - LMT 1919 Dec 15 - 8:00 - YAKT 1930 Jun 21 # Yakutsk Time - 9:00 Russia YAK%sT 1991 Mar 31 2:00s - 8:00 Russia YAK%sT 1992 Jan 19 2:00s - 9:00 Russia YAK%sT 2004 - 10:00 Russia VLA%sT 2011 Mar 27 2:00s - 11:00 - VLAT 2011 Sep 13 0:00s # Decree 725? - 10:00 - YAKT 2014 Oct 26 2:00s - 9:00 - YAKT + 8:00 - +08 1930 Jun 21 + 9:00 Russia +09/+10 1991 Mar 31 2:00s + 8:00 Russia +08/+09 1992 Jan 19 2:00s + 9:00 Russia +09/+10 2004 + 10:00 Russia +10/+11 2011 Mar 27 2:00s + 11:00 - +11 2011 Sep 13 0:00s # Decree 725? + 10:00 - +10 2014 Oct 26 2:00s + 9:00 - +09 # From Tim Parenti (2014-07-03): @@ -3004,15 +3025,14 @@ Zone Asia/Khandyga 9:02:13 - LMT 1919 Dec 15 # The Zone name should be Asia/Yuzhno-Sakhalinsk, but that's too long. Zone Asia/Sakhalin 9:30:48 - LMT 1905 Aug 23 - 9:00 - JCST 1937 Oct 1 - 9:00 - JST 1945 Aug 25 - 11:00 Russia SAK%sT 1991 Mar 31 2:00s # Sakhalin T - 10:00 Russia SAK%sT 1992 Jan 19 2:00s - 11:00 Russia SAK%sT 1997 Mar lastSun 2:00s - 10:00 Russia SAK%sT 2011 Mar 27 2:00s - 11:00 - SAKT 2014 Oct 26 2:00s - 10:00 - SAKT 2016 Mar 27 2:00s - 11:00 - SAKT + 9:00 - +09 1945 Aug 25 + 11:00 Russia +11/+12 1991 Mar 31 2:00s # Sakhalin T + 10:00 Russia +10/+11 1992 Jan 19 2:00s + 11:00 Russia +11/+12 1997 Mar lastSun 2:00s + 10:00 Russia +10/+11 2011 Mar 27 2:00s + 11:00 - +11 2014 Oct 26 2:00s + 10:00 - +10 2016 Mar 27 2:00s + 11:00 - +11 # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29): @@ -3035,13 +3055,13 @@ Zone Asia/Sakhalin 9:30:48 - LMT 1905 Aug 23 # http://publication.pravo.gov.ru/Document/View/0001201604050038 Zone Asia/Magadan 10:03:12 - LMT 1924 May 2 - 10:00 - MAGT 1930 Jun 21 # Magadan Time - 11:00 Russia MAG%sT 1991 Mar 31 2:00s - 10:00 Russia MAG%sT 1992 Jan 19 2:00s - 11:00 Russia MAG%sT 2011 Mar 27 2:00s - 12:00 - MAGT 2014 Oct 26 2:00s - 10:00 - MAGT 2016 Apr 24 2:00s - 11:00 - MAGT + 10:00 - +10 1930 Jun 21 # Magadan Time + 11:00 Russia +11/+12 1991 Mar 31 2:00s + 10:00 Russia +10/+11 1992 Jan 19 2:00s + 11:00 Russia +11/+12 2011 Mar 27 2:00s + 12:00 - +12 2014 Oct 26 2:00s + 10:00 - +10 2016 Apr 24 2:00s + 11:00 - +11 # From Tim Parenti (2014-07-06): @@ -3084,17 +3104,14 @@ Zone Asia/Magadan 10:03:12 - LMT 1924 May 2 # in Russian.) In addition, Srednekolymsk appears to be a much older # settlement and the population of Zyryanka seems to be declining. # Go with Srednekolymsk. -# -# Since Magadan Oblast moves to UTC+10 on 2014-10-26, we cannot keep using MAGT -# as the abbreviation. Use SRET instead. Zone Asia/Srednekolymsk 10:14:52 - LMT 1924 May 2 - 10:00 - MAGT 1930 Jun 21 # Magadan Time - 11:00 Russia MAG%sT 1991 Mar 31 2:00s - 10:00 Russia MAG%sT 1992 Jan 19 2:00s - 11:00 Russia MAG%sT 2011 Mar 27 2:00s - 12:00 - MAGT 2014 Oct 26 2:00s - 11:00 - SRET # Srednekolymsk Time + 10:00 - +10 1930 Jun 21 + 11:00 Russia +11/+12 1991 Mar 31 2:00s + 10:00 Russia +10/+11 1992 Jan 19 2:00s + 11:00 Russia +11/+12 2011 Mar 27 2:00s + 12:00 - +12 2014 Oct 26 2:00s + 11:00 - +11 # From Tim Parenti (2014-07-03): @@ -3112,14 +3129,14 @@ Zone Asia/Srednekolymsk 10:14:52 - LMT 1924 May 2 # UTC+12 since at least then, too. Zone Asia/Ust-Nera 9:32:54 - LMT 1919 Dec 15 - 8:00 - YAKT 1930 Jun 21 # Yakutsk Time - 9:00 Russia YAKT 1981 Apr 1 - 11:00 Russia MAG%sT 1991 Mar 31 2:00s - 10:00 Russia MAG%sT 1992 Jan 19 2:00s - 11:00 Russia MAG%sT 2011 Mar 27 2:00s - 12:00 - MAGT 2011 Sep 13 0:00s # Decree 725? - 11:00 - VLAT 2014 Oct 26 2:00s - 10:00 - VLAT + 8:00 - +08 1930 Jun 21 + 9:00 Russia +09/+10 1981 Apr 1 + 11:00 Russia +11/+12 1991 Mar 31 2:00s + 10:00 Russia +10/+11 1992 Jan 19 2:00s + 11:00 Russia +11/+12 2011 Mar 27 2:00s + 12:00 - +12 2011 Sep 13 0:00s # Decree 725? + 11:00 - +11 2014 Oct 26 2:00s + 10:00 - +10 # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25): @@ -3132,12 +3149,12 @@ Zone Asia/Ust-Nera 9:32:54 - LMT 1919 Dec 15 # The Zone name should be Asia/Petropavlovsk-Kamchatski or perhaps # Asia/Petropavlovsk-Kamchatsky, but these are too long. Zone Asia/Kamchatka 10:34:36 - LMT 1922 Nov 10 - 11:00 - PETT 1930 Jun 21 # P-K Time - 12:00 Russia PET%sT 1991 Mar 31 2:00s - 11:00 Russia PET%sT 1992 Jan 19 2:00s - 12:00 Russia PET%sT 2010 Mar 28 2:00s - 11:00 Russia PET%sT 2011 Mar 27 2:00s - 12:00 - PETT + 11:00 - +11 1930 Jun 21 + 12:00 Russia +12/+13 1991 Mar 31 2:00s + 11:00 Russia +11/+12 1992 Jan 19 2:00s + 12:00 Russia +12/+13 2010 Mar 28 2:00s + 11:00 Russia +11/+12 2011 Mar 27 2:00s + 12:00 - +12 # From Tim Parenti (2014-07-03): @@ -3145,13 +3162,13 @@ Zone Asia/Kamchatka 10:34:36 - LMT 1922 Nov 10 # 87 RU-CHU Chukotka Autonomous Okrug Zone Asia/Anadyr 11:49:56 - LMT 1924 May 2 - 12:00 - ANAT 1930 Jun 21 # Anadyr Time - 13:00 Russia ANA%sT 1982 Apr 1 0:00s - 12:00 Russia ANA%sT 1991 Mar 31 2:00s - 11:00 Russia ANA%sT 1992 Jan 19 2:00s - 12:00 Russia ANA%sT 2010 Mar 28 2:00s - 11:00 Russia ANA%sT 2011 Mar 27 2:00s - 12:00 - ANAT + 12:00 - +12 1930 Jun 21 + 13:00 Russia +13/+14 1982 Apr 1 0:00s + 12:00 Russia +12/+13 1991 Mar 31 2:00s + 11:00 Russia +11/+12 1992 Jan 19 2:00s + 12:00 Russia +12/+13 2010 Mar 28 2:00s + 11:00 Russia +11/+12 2011 Mar 27 2:00s + 12:00 - +12 # San Marino @@ -3410,22 +3427,24 @@ Zone Europe/Zurich 0:34:08 - LMT 1853 Jul 16 # See above comment. # Turkey -# From Amar Devegowda (2007-01-03): -# The time zone rules for Istanbul, Turkey have not been changed for years now. -# ... The latest rules are available at: -# http://www.timeanddate.com/worldclock/timezone.html?n=107 -# From Steffen Thorsen (2007-01-03): -# I have been able to find press records back to 1996 which all say that -# DST started 01:00 local time and end at 02:00 local time. I am not sure -# what happened before that. One example for each year from 1996 to 2001: -# http://newspot.byegm.gov.tr/arsiv/1996/21/N4.htm -# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING97/03/97X03X25.TXT -# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING98/03/98X03X02.HTM -# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING99/10/99X10X26.HTM#%2016 -# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING2000/03/00X03X06.HTM#%2021 -# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING2001/03/23x03x01.HTM#%2027 -# From Paul Eggert (2007-01-03): -# Prefer the above source to Shanks & Pottenger for time stamps after 1990. +# From Kıvanç Yazan (2016-09-25): +# 1) For 1986-2006, DST started at 01:00 local and ended at 02:00 local, with +# no exceptions. +# 2) 1994's lastSun was overridden with Mar 20 ... +# Here are official papers: +# http://www.resmigazete.gov.tr/arsiv/19032.pdf - page 2 for 1986 +# http://www.resmigazete.gov.tr/arsiv/19400.pdf - page 4 for 1987 +# http://www.resmigazete.gov.tr/arsiv/19752.pdf - page 15 for 1988 +# http://www.resmigazete.gov.tr/arsiv/20102.pdf - page 6 for 1989 +# http://www.resmigazete.gov.tr/arsiv/20464.pdf - page 1 for 1990 - 1992 +# http://www.resmigazete.gov.tr/arsiv/21531.pdf - page 15 for 1993 - 1995 +# http://www.resmigazete.gov.tr/arsiv/21879.pdf - page 1 for overriding 1994 +# http://www.resmigazete.gov.tr/arsiv/22588.pdf - page 1 for 1996, 1997 +# http://www.resmigazete.gov.tr/arsiv/23286.pdf - page 10 for 1998 - 2000 +# http://www.resmigazete.gov.tr/eskiler/2001/03/20010324.htm#2 - for 2001 +# http://www.resmigazete.gov.tr/eskiler/2002/03/20020316.htm#2 - for 2002-2006 +# From Paul Eggert (2016-09-25): +# Prefer the above sources to Shanks & Pottenger for time stamps after 1985. # From Steffen Thorsen (2007-03-09): # Starting 2007 though, it seems that they are adopting EU's 1:00 UTC @@ -3472,6 +3491,14 @@ Zone Europe/Zurich 0:34:08 - LMT 1853 Jul 16 # See above comment. # Engineered Standard Time," said Twitter user @aysekarahasan. # http://www.bbc.com/news/world-europe-34631326 +# From Burak AYDIN (2016-09-08): +# Turkey will stay in Daylight Saving Time even in winter.... +# http://www.resmigazete.gov.tr/eskiler/2016/09/20160908-2.pdf +# +# From Paul Eggert (2016-09-07): +# The change is permanent, so this is the new standard time in Turkey. +# It takes effect today, which is not much notice. + # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Turkey 1916 only - May 1 0:00 1:00 S Rule Turkey 1916 only - Oct 1 0:00 0 - @@ -3526,16 +3553,16 @@ Rule Turkey 1983 only - Jul 31 0:00 1:00 S Rule Turkey 1983 only - Oct 2 0:00 0 - Rule Turkey 1985 only - Apr 20 0:00 1:00 S Rule Turkey 1985 only - Sep 28 0:00 0 - -Rule Turkey 1986 1990 - Mar lastSun 2:00s 1:00 S -Rule Turkey 1986 1990 - Sep lastSun 2:00s 0 - -Rule Turkey 1991 2006 - Mar lastSun 1:00s 1:00 S -Rule Turkey 1991 1995 - Sep lastSun 1:00s 0 - +Rule Turkey 1986 1993 - Mar lastSun 1:00s 1:00 S +Rule Turkey 1986 1995 - Sep lastSun 1:00s 0 - +Rule Turkey 1994 only - Mar 20 1:00s 1:00 S +Rule Turkey 1995 2006 - Mar lastSun 1:00s 1:00 S Rule Turkey 1996 2006 - Oct lastSun 1:00s 0 - # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Europe/Istanbul 1:55:52 - LMT 1880 1:56:56 - IMT 1910 Oct # Istanbul Mean Time? 2:00 Turkey EE%sT 1978 Oct 15 - 3:00 Turkey TR%sT 1985 Apr 20 # Turkey Time + 3:00 Turkey +03/+04 1985 Apr 20 2:00 Turkey EE%sT 2007 2:00 EU EE%sT 2011 Mar 27 1:00u 2:00 - EET 2011 Mar 28 1:00u @@ -3543,7 +3570,8 @@ Zone Europe/Istanbul 1:55:52 - LMT 1880 2:00 - EET 2014 Mar 31 1:00u 2:00 EU EE%sT 2015 Oct 25 1:00u 2:00 1:00 EEST 2015 Nov 8 1:00u - 2:00 EU EE%sT + 2:00 EU EE%sT 2016 Sep 7 + 3:00 - +03 Link Europe/Istanbul Asia/Istanbul # Istanbul is in both continents. # Ukraine diff --git a/src/timezone/data/factory b/src/timezone/data/factory index 4304f7cf7b..75fa4a11c3 100644 --- a/src/timezone/data/factory +++ b/src/timezone/data/factory @@ -1,9 +1,10 @@ # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. -# For companies who don't want to put time zone specification in -# their installation procedures. When users run date, they'll get the message. -# Also useful for the "comp.sources" version. +# For distributors who don't want to put time zone specification in +# their installation procedures. Users that run 'date' will get the +# time zone abbreviation "-00", indicating that the actual time zone +# is unknown. # Zone NAME GMTOFF RULES FORMAT -Zone Factory 0 - "Local time zone must be set--see zic manual page" +Zone Factory 0 - -00 diff --git a/src/timezone/data/northamerica b/src/timezone/data/northamerica index 6256f970a8..e1ed9e4a87 100644 --- a/src/timezone/data/northamerica +++ b/src/timezone/data/northamerica @@ -24,8 +24,32 @@ # was the result of his proposals at the Convention of Railroad Trunk Lines # in New York City (1869-10). His 1870 proposal was based on Washington, DC, # but in 1872-05 he moved the proposed origin to Greenwich. -# His proposal was adopted by the railroads on 1883-11-18 at 12:00, -# and the most of the country soon followed suit. + +# From Paul Eggert (2016-09-21): +# Dowd's proposal left many details unresolved, such as where to draw +# lines between time zones. The key individual who made time zones +# work in the US was William Frederick Allen - railway engineer, +# managing editor of the Travelers' Guide, and secretary of the +# General Time Convention, a railway standardization group. Allen +# spent months in dialogs with scientific and railway leaders, +# developed a workable plan to institute time zones, and presented it +# to the General Time Convention on 1883-04-11, saying that his plan +# meant "local time would be practically abolished" - a plus for +# railway scheduling. By the next convention on 1883-10-11 nearly all +# railroads had agreed and it took effect on 1883-11-18 at 12:00. +# That Sunday was called the "day of two noons", as the eastern parts +# of the new zones observed noon twice. Allen witnessed the +# transition in New York City, writing: +# +# I heard the bells of St. Paul's strike on the old time. Four +# minutes later, obedient to the electrical signal from the Naval +# Observatory ... the time-ball made its rapid descent, the chimes +# of old Trinity rang twelve measured strokes, and local time was +# abandoned, probably forever. +# +# Most of the US soon followed suit. See: +# Bartky IR. The adoption of standard time. Technol Cult 1989 Jan;30(1):25-56. +# http://dx.doi.org/10.2307/3105430 # From Paul Eggert (2005-04-16): # That 1883 transition occurred at 12:00 new time, not at 12:00 old time. @@ -413,11 +437,42 @@ Zone America/Denver -6:59:56 - LMT 1883 Nov 18 12:00:04 # north of the Salmon River, and the towns of Burgdorf and Warren), # Nevada (except West Wendover), Oregon (except the northern 3/4 of # Malheur county), and Washington + +# From Paul Eggert (2016-08-20): +# In early February 1948, in response to California's electricity shortage, +# PG&E changed power frequency from 60 to 59.5 Hz during daylight hours, +# causing electric clocks to lose six minutes per day. (This did not change +# legal time, and is not part of the data here.) See: +# Ross SA. An energy crisis from the past: Northern California in 1948. +# Working Paper No. 8, Institute of Governmental Studies, UC Berkeley, +# 1973-11. http://escholarship.org/uc/item/8x22k30c +# +# In another measure to save electricity, DST was instituted from 1948-03-14 +# at 02:01 to 1949-01-16 at 02:00, with the governor having the option to move +# the fallback transition earlier. See pages 3-4 of: +# http://clerk.assembly.ca.gov/sites/clerk.assembly.ca.gov/files/archive/Statutes/1948/48Vol1_Chapters.pdf +# +# In response: +# +# Governor Warren received a torrent of objecting mail, and it is not too much +# to speculate that the objections to Daylight Saving Time were one important +# factor in the defeat of the Dewey-Warren Presidential ticket in California. +# -- Ross, p 25 +# +# On December 8 the governor exercised the option, setting the date to January 1 +# (LA Times 1948-12-09). The transition time was 02:00 (LA Times 1949-01-01). +# +# Despite the controversy, in 1949 California voters approved Proposition 12, +# which established DST from April's last Sunday at 01:00 until September's +# last Sunday at 02:00. This was amended by 1962's Proposition 6, which changed +# the fall-back date to October's last Sunday. See: +# http://repository.uchastings.edu/cgi/viewcontent.cgi?article=1501&context=ca_ballot_props +# http://repository.uchastings.edu/cgi/viewcontent.cgi?article=1636&context=ca_ballot_props # # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER -Rule CA 1948 only - Mar 14 2:00 1:00 D +Rule CA 1948 only - Mar 14 2:01 1:00 D Rule CA 1949 only - Jan 1 2:00 0 S -Rule CA 1950 1966 - Apr lastSun 2:00 1:00 D +Rule CA 1950 1966 - Apr lastSun 1:00 1:00 D Rule CA 1950 1961 - Sep lastSun 2:00 0 S Rule CA 1962 1966 - Oct lastSun 2:00 0 S # Zone NAME GMTOFF RULES FORMAT [UNTIL] @@ -3281,7 +3336,7 @@ Zone America/Miquelon -3:44:40 - LMT 1911 May 15 # St Pierre # indicating that the normal ET rules are followed. # # From Paul Eggert (2014-08-19): -# The 2014-08-13 Cabinet meeting decided to stay on UTC-4 year-round. See: +# The 2014-08-13 Cabinet meeting decided to stay on UT -04 year-round. See: # http://tcweeklynews.com/daylight-savings-time-to-be-maintained-p5353-127.htm # Model this as a switch from EST/EDT to AST ... # From Chris Walton (2014-11-04): diff --git a/src/timezone/data/southamerica b/src/timezone/data/southamerica index 1c38f63d1c..532145172f 100644 --- a/src/timezone/data/southamerica +++ b/src/timezone/data/southamerica @@ -410,9 +410,9 @@ Rule Arg 2008 only - Oct Sun>=15 0:00 1:00 S # stuck on Summer daylight savings time even though the summer is over. # From Paul Eggert (2013-09-05): -# Perhaps San Luis operates on the legal fiction that it is at UTC-4 +# Perhaps San Luis operates on the legal fiction that it is at -04 # with perpetual summer time, but ordinary usage typically seems to -# just say it's at UTC-3; see, for example, +# just say it's at -03; see, for example, # http://es.wikipedia.org/wiki/Hora_oficial_argentina # We've documented similar situations as being plain changes to # standard time, so let's do that here too. This does not change UTC diff --git a/src/timezone/known_abbrevs.txt b/src/timezone/known_abbrevs.txt index 015f4c90ba..59328dcc76 100644 --- a/src/timezone/known_abbrevs.txt +++ b/src/timezone/known_abbrevs.txt @@ -1,8 +1,33 @@ ++00 0 ++01 3600 ++02 7200 ++02 7200 D +03 10800 +04 14400 +05 18000 ++0530 19800 +06 21600 +07 25200 ++08 28800 ++09 32400 ++10 36000 ++11 39600 ++12 43200 ++13 46800 ++14 50400 +-00 0 +-01 -3600 +-02 -7200 +-03 -10800 +-04 -14400 +-05 -18000 +-06 -21600 +-07 -25200 +-08 -28800 +-09 -32400 +-10 -36000 +-11 -39600 +-12 -43200 ACDT 37800 D ACST 34200 ACT -18000 @@ -15,15 +40,12 @@ AKDT -28800 D AKST -32400 AMST -10800 D AMT -14400 -AMT 14400 -ANAT 43200 ART -10800 AST -14400 AST 10800 AWST 28800 AZOST 0 D AZOT -3600 -AZT 14400 BDT 21600 BNT 28800 BOT -14400 @@ -53,8 +75,6 @@ CST 28800 CVT -3600 CXT 25200 ChST 36000 -DAVT 25200 -DDUT 36000 EASST -18000 D EAST -21600 EAT 10800 @@ -71,36 +91,9 @@ FKST -10800 FNT -7200 GALT -21600 GAMT -32400 -GET 14400 GFT -10800 GILT 43200 GMT 0 -GMT+1 -3600 -GMT+10 -36000 -GMT+11 -39600 -GMT+12 -43200 -GMT+2 -7200 -GMT+3 -10800 -GMT+4 -14400 -GMT+5 -18000 -GMT+6 -21600 -GMT+7 -25200 -GMT+8 -28800 -GMT+9 -32400 -GMT-1 3600 -GMT-10 36000 -GMT-11 39600 -GMT-12 43200 -GMT-13 46800 -GMT-14 50400 -GMT-2 7200 -GMT-3 10800 -GMT-4 14400 -GMT-5 18000 -GMT-6 21600 -GMT-7 25200 -GMT-8 28800 -GMT-9 32400 GST -7200 GST 14400 GYT -14400 @@ -113,23 +106,18 @@ ICT 25200 IDT 10800 D IOT 21600 IRDT 16200 D -IRKT 28800 IRST 12600 IST 19800 IST 3600 D IST 7200 JST 32400 -KGT 21600 KOST 39600 -KRAT 25200 KST 30600 KST 32400 LHDT 39600 D LHST 37800 LINT 50400 -MAGT 39600 MART -34200 -MAWT 18000 MDT -21600 D MEST 7200 D MET 3600 @@ -150,10 +138,8 @@ NST -12600 NUT -39600 NZDT 46800 D NZST 43200 -OMST 21600 PDT -25200 D PET -18000 -PETT 43200 PGT 36000 PHOT 46800 PHT 28800 @@ -166,23 +152,15 @@ PWT 32400 PYST -10800 D PYT -14400 RET 14400 -ROTT -10800 -SAKT 39600 -SAMT 14400 SAST 7200 SBT 39600 SCT 14400 SGT 28800 -SRET 39600 SRT -10800 SST -39600 -SYOT 10800 TAHT -36000 -TFT 18000 -TJT 18000 TKT 46800 TLT 32400 -TMT 18000 TOT 46800 TVT 43200 UCT 0 @@ -190,10 +168,7 @@ ULAST 32400 D ULAT 28800 UTC 0 UYT -10800 -UZT 18000 VET -14400 -VLAT 36000 -VOST 21600 VUT 39600 WAKT 43200 WAST 7200 D @@ -209,5 +184,3 @@ WITA 28800 WSDT 50400 D WSST 46800 XJT 21600 -YAKT 32400 -YEKT 18000 diff --git a/src/timezone/localtime.c b/src/timezone/localtime.c index a14215d6bd..e6c1beaf96 100644 --- a/src/timezone/localtime.c +++ b/src/timezone/localtime.c @@ -489,7 +489,7 @@ tzloadbody(char const * name, char *canonname, struct state * sp, bool doextend, } /* - * If type 0 is is unused in transitions, it's the type to use for early + * If type 0 is unused in transitions, it's the type to use for early * times. */ for (i = 0; i < sp->timecnt; ++i) @@ -1280,9 +1280,8 @@ gmtsub(pg_time_t const * timep, int32 offset, struct pg_tm * tmp) result = timesub(timep, offset, gmtptr, tmp); /* - * Could get fancy here and deliver something such as "UT+xxxx" or - * "UT-xxxx" if offset is non-zero, but this is no time for a treasure - * hunt. + * Could get fancy here and deliver something such as "+xx" or "-xx" if + * offset is non-zero, but this is no time for a treasure hunt. */ if (offset != 0) tmp->tm_zone = wildabbr; diff --git a/src/timezone/pgtz.c b/src/timezone/pgtz.c index 4fa3d0da89..826857d943 100644 --- a/src/timezone/pgtz.c +++ b/src/timezone/pgtz.c @@ -3,7 +3,7 @@ * pgtz.c * Timezone Library Integration Functions * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/timezone/pgtz.c diff --git a/src/timezone/pgtz.h b/src/timezone/pgtz.h index 2adec19838..cd193b8255 100644 --- a/src/timezone/pgtz.h +++ b/src/timezone/pgtz.h @@ -6,7 +6,7 @@ * Note: this file contains only definitions that are private to the * timezone library. Public definitions are in pgtime.h. * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * * IDENTIFICATION * src/timezone/pgtz.h diff --git a/src/timezone/private.h b/src/timezone/private.h index 8480d38961..b8533d51e8 100644 --- a/src/timezone/private.h +++ b/src/timezone/private.h @@ -23,6 +23,7 @@ #include "pgtime.h" +/* This string was in the Factory zone through version 2016f. */ #define GRANDPARENTED "Local time zone must be set--see zic manual page" /* diff --git a/src/timezone/strftime.c b/src/timezone/strftime.c index 5630619321..4a0a01db65 100644 --- a/src/timezone/strftime.c +++ b/src/timezone/strftime.c @@ -128,7 +128,7 @@ pg_strftime(char *s, size_t maxsize, const char *format, int warn; warn = IN_NONE; - p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn); + p = _fmt(format, t, s, s + maxsize, &warn); if (p == s + maxsize) return 0; *p = '\0'; diff --git a/src/timezone/tznames/Africa.txt b/src/timezone/tznames/Africa.txt index f80676dc33..0bd0c405f6 100644 --- a/src/timezone/tznames/Africa.txt +++ b/src/timezone/tznames/Africa.txt @@ -144,7 +144,7 @@ GMT 0 # Greenwich Mean Time # (Europe/London) # CONFLICT! SAST is not unique # Other timezones: -# - SAST South Australian Standard Time (not in zic) +# - SAST South Australian Standard Time (not in IANA database) SAST 7200 # South Africa Standard Time # (Africa/Johannesburg) WAST 7200 D # West Africa Summer Time diff --git a/src/timezone/tznames/America.txt b/src/timezone/tznames/America.txt index b76c311f50..f00834e987 100644 --- a/src/timezone/tznames/America.txt +++ b/src/timezone/tznames/America.txt @@ -15,7 +15,7 @@ ACT -18000 # Acre Time # CONFLICT! ACST is not unique # Other timezones: # - ACST: Australian Central Standard Time -ACST -14400 D # Acre Summer Time (obsolete, not in zic) +ACST -14400 D # Acre Summer Time (obsolete, not in IANA database) ADT -10800 D # Atlantic Daylight Time # (America/Glace_Bay) # (America/Goose_Bay) @@ -92,7 +92,7 @@ AST -14400 # Atlantic Standard Time # (Atlantic/Bermuda) BOT -14400 # Bolivia Time # (America/La_Paz) -BRA -10800 # Brazil Time (not in zic) +BRA -10800 # Brazil Time (not in IANA database) BRST -7200 D # Brasil Summer Time # (America/Sao_Paulo) BRT -10800 # Brasil Time @@ -131,7 +131,7 @@ CLST -10800 D # Chile Summer Time CLT America/Santiago # Chile Time # (America/Santiago) # (Antarctica/Palmer) -COT -18000 # Columbia Time (not in zic) +COT -18000 # Columbia Time (not in IANA database) # CONFLICT! CST is not unique # Other timezones: # - CST: Central Standard Time (Australia) @@ -207,7 +207,7 @@ EST -18000 # Eastern Standard Time (America) # (America/Toronto) FNT -7200 # Fernando de Noronha Time # (America/Noronha) -FNST -3600 D # Fernando de Noronha Summer Time (not in zic) +FNST -3600 D # Fernando de Noronha Summer Time (not in IANA database) # (America/Noronha) GFT -10800 # French Guiana Time # (America/Cayenne) @@ -265,7 +265,7 @@ NDT -9000 D # Newfoundland Daylight Time # CONFLICT! NFT is not unique # Other timezones: # - NFT: Norfolk Time (Pacific) -NFT -12600 # Newfoundland Time (not in zic) +NFT -12600 # Newfoundland Time (not in IANA database) NST -12600 # Newfoundland Standard Time # (America/St_Johns) PDT -25200 D # Pacific Daylight Time @@ -274,7 +274,7 @@ PDT -25200 D # Pacific Daylight Time # (America/Tijuana) # (America/Vancouver) # (America/Whitehorse) -PET -18000 # Peru Time (not in zic) +PET -18000 # Peru Time (not in IANA database) PMDT -7200 D # Pierre & Miquelon Daylight Time # (America/Miquelon) PMST -10800 # Pierre & Miquelon Standard Time diff --git a/src/timezone/tznames/Antarctica.txt b/src/timezone/tznames/Antarctica.txt index 942e81993a..1a0729dcbb 100644 --- a/src/timezone/tznames/Antarctica.txt +++ b/src/timezone/tznames/Antarctica.txt @@ -16,12 +16,9 @@ CLST -10800 D # Chile Summer Time CLT America/Santiago # Chile Time # (America/Santiago) # (Antarctica/Palmer) -DAVT Antarctica/Davis # Davis Time (Antarctica) - # (Antarctica/Davis) -DDUT 36000 # Dumont-d`Urville Time (Antarctica) - # (Antarctica/DumontDUrville) -MAWT Antarctica/Mawson # Mawson Time (Antarctica) - # (Antarctica/Mawson) +DAVT Antarctica/Davis # Davis Time (Antarctica) (obsolete) +DDUT 36000 # Dumont-d`Urville Time (Antarctica) (obsolete) +MAWT Antarctica/Mawson # Mawson Time (Antarctica) (obsolete) MIST 39600 # Macquarie Island Time # (Antarctica/Macquarie) NZDT 46800 D # New Zealand Daylight Time @@ -30,9 +27,6 @@ NZDT 46800 D # New Zealand Daylight Time NZST 43200 # New Zealand Standard Time # (Antarctica/McMurdo) # (Pacific/Auckland) -ROTT -10800 # Rothera Time - # (Antarctica/Rothera) -SYOT 10800 # Syowa Time - # (Antarctica/Syowa) -VOST 21600 # Vostok time - # (Antarctica/Vostok) +ROTT -10800 # Rothera Time (obsolete) +SYOT 10800 # Syowa Time (obsolete) +VOST 21600 # Vostok time (obsolete) diff --git a/src/timezone/tznames/Asia.txt b/src/timezone/tznames/Asia.txt index 42244501b8..c834b6f1e4 100644 --- a/src/timezone/tznames/Asia.txt +++ b/src/timezone/tznames/Asia.txt @@ -19,11 +19,9 @@ AMST Asia/Yerevan # Armenia Summer Time # CONFLICT! AMT is not unique # Other timezones: # - AMT: Amazon Time (America) -AMT Asia/Yerevan # Armenia Time - # (Asia/Yerevan) +AMT Asia/Yerevan # Armenia Time (obsolete) ANAST Asia/Anadyr # Anadyr Summer Time (obsolete) -ANAT Asia/Anadyr # Anadyr Time - # (Asia/Anadyr) +ANAT Asia/Anadyr # Anadyr Time (obsolete) AQTST Asia/Aqtau # Aqtau Summer Time (obsolete) AQTT Asia/Aqtau # Aqtau Time (obsolete) # CONFLICT! AST is not unique @@ -42,16 +40,15 @@ AST 10800 # Arabia Standard Time # (Asia/Qatar) # (Asia/Riyadh) AZST Asia/Baku # Azerbaijan Summer Time (obsolete) -AZT Asia/Baku # Azerbaijan Time - # (Asia/Baku) +AZT Asia/Baku # Azerbaijan Time (obsolete) BDT 21600 # Bangladesh Time # (Asia/Dhaka) BNT 28800 # Brunei Darussalam Time # (Asia/Brunei) -BORT 28800 # Borneo Time (Indonesia) (not in zic) +BORT 28800 # Borneo Time (Indonesia) (not in IANA database) BTT 21600 # Bhutan Time # (Asia/Thimphu) -CCT 28800 # China Coastal Time (not in zic) +CCT 28800 # China Coastal Time (not in IANA database) CHOST Asia/Choibalsan # Choibalsan Summer Time # (Asia/Choibalsan) CHOT Asia/Choibalsan # Choibalsan Time @@ -115,15 +112,14 @@ EET 7200 # East-Egypt Time # (Europe/Zaporozhye) EIT 32400 # East Indonesia Time (obsolete, WIT is now preferred) GEST Asia/Tbilisi # Georgia Summer Time (obsolete) -GET Asia/Tbilisi # Georgia Time - # (Asia/Tbilisi) +GET Asia/Tbilisi # Georgia Time (obsolete) # CONFLICT! GST is not unique # Other timezones: # - GST: South Georgia Time (Atlantic) GST 14400 # Gulf Standard Time # (Asia/Dubai) # (Asia/Muscat) -HKT 28800 # Hong Kong Time (not in zic) +HKT 28800 # Hong Kong Time (not in IANA database) HOVST 28800 D # Hovd Summer Time # (Asia/Hovd) HOVT Asia/Hovd # Hovd Time @@ -138,11 +134,10 @@ IDT 10800 D # Israel Daylight Time IRDT Asia/Tehran # Iran Daylight Time # (Asia/Tehran) IRKST Asia/Irkutsk # Irkutsk Summer Time (obsolete) -IRKT Asia/Irkutsk # Irkutsk Time - # (Asia/Irkutsk) +IRKT Asia/Irkutsk # Irkutsk Time (obsolete) IRST Asia/Tehran # Iran Standard Time # (Asia/Tehran) -IRT 12600 # Iran Time (not in zic) +IRT 12600 # Iran Time (not in IANA database) # CONFLICT! IST is not unique # Other timezones: # - IST: Irish Summer Time (Europe) @@ -155,26 +150,23 @@ IST 19800 # Indian Standard Time # - IST: Indian Standard Time (Asia) IST 7200 # Israel Standard Time # (Asia/Jerusalem) -JAYT 32400 # Jayapura Time (Indonesia) (not in zic) +JAYT 32400 # Jayapura Time (Indonesia) (not in IANA database) JST 32400 # Japan Standard Time # (Asia/Tokyo) -KDT 36000 D # Korean Daylight Time (not in zic) +KDT 36000 D # Korean Daylight Time (not in IANA database) KGST 21600 D # Kyrgyzstan Summer Time (obsolete) -KGT Asia/Bishkek # Kyrgyzstan Time - # (Asia/Bishkek) +KGT Asia/Bishkek # Kyrgyzstan Time (obsolete) KRAST Asia/Krasnoyarsk # Krasnoyarsk Summer Time (obsolete) -KRAT Asia/Krasnoyarsk # Krasnoyarsk Time - # (Asia/Krasnoyarsk) +KRAT Asia/Krasnoyarsk # Krasnoyarsk Time (obsolete) KST Asia/Pyongyang # Korean Standard Time # (Asia/Pyongyang) KST 32400 # Korean Standard Time # (Asia/Seoul) LKT Asia/Colombo # Lanka Time (obsolete) MAGST Asia/Magadan # Magadan Summer Time (obsolete) -MAGT Asia/Magadan # Magadan Time - # (Asia/Magadan) +MAGT Asia/Magadan # Magadan Time (obsolete) MMT 23400 # Myanmar Time - # (Asia/Rangoon) + # (Asia/Yangon) MYT 28800 # Malaysia Time # (Asia/Kuala_Lumpur) # (Asia/Kuching) @@ -183,12 +175,10 @@ NOVT Asia/Novosibirsk # Novosibirsk Time (obsolete) NPT 20700 # Nepal Time # (Asia/Katmandu) OMSST Asia/Omsk # Omsk Summer Time (obsolete) -OMST Asia/Omsk # Omsk Time - # (Asia/Omsk) +OMST Asia/Omsk # Omsk Time (obsolete) ORAT Asia/Oral # Oral Time (obsolete) PETST Asia/Kamchatka # Petropavlovsk-Kamchatski Summer Time (obsolete) -PETT Asia/Kamchatka # Petropavlovsk-Kamchatski Time - # (Asia/Kamchatka) +PETT Asia/Kamchatka # Petropavlovsk-Kamchatski Time (obsolete) PHT 28800 # Philippine Time # (Asia/Manila) PKT 18000 # Pakistan Time @@ -197,18 +187,14 @@ PKST 21600 D # Pakistan Summer Time # (Asia/Karachi) QYZT 21600 # Kizilorda Time (obsolete) SAKST Asia/Sakhalin # Sakhalin Summer Time (obsolete) -SAKT Asia/Sakhalin # Sakhalin Time - # (Asia/Sakhalin) +SAKT Asia/Sakhalin # Sakhalin Time (obsolete) SGT Asia/Singapore # Singapore Time # (Asia/Singapore) -SRET 39600 # Srednekolymsk Time - # (Asia/Srednekolymsk) -TJT 18000 # Tajikistan Time - # (Asia/Dushanbe) +SRET 39600 # Srednekolymsk Time (obsolete) +TJT 18000 # Tajikistan Time (obsolete) TLT 32400 # East Timor Time # (Asia/Dili) -TMT Asia/Ashgabat # Turkmenistan Time - # (Asia/Ashgabat) +TMT Asia/Ashgabat # Turkmenistan Time (obsolete) ULAST 32400 D # Ulan Bator Summer Time # (Asia/Ulaanbaatar) ULAT Asia/Ulaanbaatar # Ulan Bator Time @@ -216,12 +202,9 @@ ULAT Asia/Ulaanbaatar # Ulan Bator Time UZST 21600 D # Uzbekistan Summer Time # (Asia/Samarkand) # (Asia/Tashkent) -UZT 18000 # Uzbekistan Time - # (Asia/Samarkand) - # (Asia/Tashkent) +UZT 18000 # Uzbekistan Time (obsolete) VLAST Asia/Vladivostok # Vladivostok Summer Time (obsolete) -VLAT Asia/Vladivostok # Vladivostok Time - # (Asia/Vladivostok) +VLAT Asia/Vladivostok # Vladivostok Time (obsolete) WIB 25200 # Waktu Indonesia Barat # (Asia/Jakarta) # (Asia/Pontianak) @@ -232,8 +215,6 @@ WITA 28800 # Waktu Indonesia Tengah XJT 21600 # Xinjiang Time # (Asia/Urumqi) YAKST Asia/Yakutsk # Yakutsk Summer Time (obsolete) -YAKT Asia/Yakutsk # Yakutsk Time - # (Asia/Yakutsk) +YAKT Asia/Yakutsk # Yakutsk Time (obsolete) YEKST 21600 D # Yekaterinburg Summer Time (obsolete) -YEKT Asia/Yekaterinburg # Yekaterinburg Time - # (Asia/Yekaterinburg) +YEKT Asia/Yekaterinburg # Yekaterinburg Time (obsolete) diff --git a/src/timezone/tznames/Australia b/src/timezone/tznames/Australia index f888fbcd6c..7216e06d6a 100644 --- a/src/timezone/tznames/Australia +++ b/src/timezone/tznames/Australia @@ -19,9 +19,9 @@ # in case of a conflict. @OVERRIDE -CST 34200 # Central Standard Time (not in zic) -EAST 36000 # East Australian Standard Time (not in zic) -EST 36000 # Eastern Standard Time (not in zic) -SAST 34200 # South Australian Standard Time (not in zic) -SAT 34200 # South Australian Standard Time (not in zic) -WST 28800 # Western Standard Time (not in zic) +CST 34200 # Central Standard Time (not in IANA database) +EAST 36000 # East Australian Standard Time (not in IANA database) +EST 36000 # Eastern Standard Time (not in IANA database) +SAST 34200 # South Australian Standard Time (not in IANA database) +SAT 34200 # South Australian Standard Time (not in IANA database) +WST 28800 # Western Standard Time (not in IANA database) diff --git a/src/timezone/tznames/Australia.txt b/src/timezone/tznames/Australia.txt index 8f1c1379c1..9751c3deb1 100644 --- a/src/timezone/tznames/Australia.txt +++ b/src/timezone/tznames/Australia.txt @@ -7,7 +7,7 @@ # src/timezone/tznames/Australia.txt # -ACSST 37800 D # Central Australia (not in zic) +ACSST 37800 D # Central Australia (not in IANA database) ACDT 37800 D # Australian Central Daylight Time # (Australia/Adelaide) # (Australia/Broken_Hill) @@ -18,7 +18,7 @@ ACST 34200 # Australian Central Standard Time # (Australia/Darwin) ACWST 31500 # Australian Central Western Standard Time # (Australia/Eucla) -AESST 39600 D # Australia Eastern Summer Standard Time (not in zic) +AESST 39600 D # Australia Eastern Summer Standard Time (not in IANA database) AEDT 39600 D # Australian Eastern Daylight Time # (Australia/Brisbane) # (Australia/Currie) @@ -33,42 +33,42 @@ AEST 36000 # Australian Eastern Standard Time # (Australia/Lindeman) # (Australia/Melbourne) # (Australia/Sydney) -AWSST 32400 D # Australia Western Summer Standard Time (not in zic) +AWSST 32400 D # Australia Western Summer Standard Time (not in IANA database) AWST 28800 # Australian Western Standard Time # (Australia/Perth) -CADT 37800 D # Central Australia Daylight-Saving Time (not in zic) -CAST 34200 # Central Australia Standard Time (not in zic) +CADT 37800 D # Central Australia Daylight-Saving Time (not in IANA database) +CAST 34200 # Central Australia Standard Time (not in IANA database) # CONFLICT! CST is not unique # Other timezones: # - CST: Central Standard Time (America) # - CST: China Standard Time (Asia) # - CST: Cuba Central Standard Time (America) -CST 34200 # Central Standard Time (not in zic) -CWST 31500 # Central Western Standard Time (not in zic) +CST 34200 # Central Standard Time (not in IANA database) +CWST 31500 # Central Western Standard Time (not in IANA database) # CONFLICT! EAST is not unique # Other timezones: # - EAST: Easter Island Time (Chile) (Pacific) -EAST 36000 # East Australian Standard Time (not in zic) +EAST 36000 # East Australian Standard Time (not in IANA database) # CONFLICT! EST is not unique # Other timezones: # - EST: Eastern Standard Time (America) -EST 36000 # Eastern Standard Time (not in zic) +EST 36000 # Eastern Standard Time (not in IANA database) LHDT Australia/Lord_Howe # Lord Howe Daylight Time # (Australia/Lord_Howe) LHST 37800 # Lord Howe Standard Time # (Australia/Lord_Howe) -LIGT 36000 # Melbourne, Australia (not in zic) -NZT 43200 # New Zealand Time (not in zic) -SADT 37800 D # South Australian Daylight-Saving Time (not in zic) +LIGT 36000 # Melbourne, Australia (not in IANA database) +NZT 43200 # New Zealand Time (not in IANA database) +SADT 37800 D # South Australian Daylight-Saving Time (not in IANA database) # CONFLICT! SAST is not unique # Other timezones: # - SAST South Africa Standard Time -SAST 34200 # South Australian Standard Time (not in zic) -SAT 34200 # South Australian Standard Time (not in zic) -WADT 28800 D # West Australian Daylight-Saving Time (not in zic) -WAST 25200 # West Australian Standard Time (not in zic) -WDT 32400 D # West Australian Daylight-Saving Time (not in zic) +SAST 34200 # South Australian Standard Time (not in IANA database) +SAT 34200 # South Australian Standard Time (not in IANA database) +WADT 28800 D # West Australian Daylight-Saving Time (not in IANA database) +WAST 25200 # West Australian Standard Time (not in IANA database) +WDT 32400 D # West Australian Daylight-Saving Time (not in IANA database) # CONFLICT! WST is not unique # Other timezones: # - WST: West Samoa Time -WST 28800 # Western Standard Time (not in zic) +WST 28800 # Western Standard Time (not in IANA database) diff --git a/src/timezone/tznames/Default b/src/timezone/tznames/Default index fe82a2fac3..6f6e46e6b4 100644 --- a/src/timezone/tznames/Default +++ b/src/timezone/tznames/Default @@ -68,7 +68,7 @@ ART America/Argentina/Buenos_Aires # Argentina Time ARST America/Argentina/Buenos_Aires # Argentina Summer Time BOT -14400 # Bolivia Time # (America/La_Paz) -BRA -10800 # Brazil Time (not in zic) +BRA -10800 # Brazil Time (not in IANA database) BRST -7200 D # Brasil Summer Time # (America/Sao_Paulo) BRT -10800 # Brasil Time @@ -79,7 +79,7 @@ BRT -10800 # Brasil Time # (America/Maceio) # (America/Recife) # (America/Sao_Paulo) -COT -18000 # Columbia Time (not in zic) +COT -18000 # Columbia Time (not in IANA database) # CONFLICT! CDT is not unique # Other timezones: # - CDT: Mexico Central Daylight Time (America) @@ -166,7 +166,7 @@ EST -18000 # Eastern Standard Time (America) # (America/Toronto) FNT -7200 # Fernando de Noronha Time # (America/Noronha) -FNST -3600 D # Fernando de Noronha Summer Time (not in zic) +FNST -3600 D # Fernando de Noronha Summer Time (not in IANA database) # (America/Noronha) GFT -10800 # French Guiana Time # (America/Cayenne) @@ -199,7 +199,7 @@ NDT -9000 D # Newfoundland Daylight Time # (America/St_Johns) NST -12600 # Newfoundland Standard Time # (America/St_Johns) -PET -18000 # Peru Time (not in zic) +PET -18000 # Peru Time (not in IANA database) PDT -25200 D # Pacific Daylight Time # (America/Dawson) # (America/Los_Angeles) @@ -234,14 +234,9 @@ WGT -10800 # West Greenland Time #################### ANTARCTICA #################### -DAVT Antarctica/Davis # Davis Time (Antarctica) - # (Antarctica/Davis) -DDUT 36000 # Dumont-d'Urville Time (Antarctica) - # (Antarctica/DumontDUrville) - # (Antarctica/Palmer) - # (America/Santiago) -MAWT Antarctica/Mawson # Mawson Time (Antarctica) - # (Antarctica/Mawson) +DAVT Antarctica/Davis # Davis Time (Antarctica) (obsolete) +DDUT 36000 # Dumont-d'Urville Time (Antarctica) (obsolete) +MAWT Antarctica/Mawson # Mawson Time (Antarctica) (obsolete) #################### ASIA #################### @@ -256,27 +251,28 @@ AMST Asia/Yerevan # Armenia Summer Time # (Asia/Yerevan) # CONFLICT! AMT is not unique # Other timezones: -# - AMT: Amazon Time (America) -AMT Asia/Yerevan # Armenia Time - # (Asia/Yerevan) +# - AMT: Armenia Time (Asia) +AMT -14400 # Amazon Time + # (America/Boa_Vista) + # (America/Campo_Grande) + # (America/Cuiaba) + # (America/Manaus) + # (America/Porto_Velho) ANAST Asia/Anadyr # Anadyr Summer Time (obsolete) -ANAT Asia/Anadyr # Anadyr Time - # (Asia/Anadyr) +ANAT Asia/Anadyr # Anadyr Time (obsolete) AZST Asia/Baku # Azerbaijan Summer Time (obsolete) -AZT Asia/Baku # Azerbaijan Time - # (Asia/Baku) +AZT Asia/Baku # Azerbaijan Time (obsolete) BDT 21600 # Bangladesh Time # (Asia/Dhaka) BNT 28800 # Brunei Darussalam Time # (Asia/Brunei) -BORT 28800 # Borneo Time (Indonesia) (not in zic) +BORT 28800 # Borneo Time (Indonesia) (not in IANA database) BTT 21600 # Bhutan Time # (Asia/Thimphu) -CCT 28800 # China Coastal Time (not in zic) +CCT 28800 # China Coastal Time (not in IANA database) GEST Asia/Tbilisi # Georgia Summer Time (obsolete) -GET Asia/Tbilisi # Georgia Time - # (Asia/Tbilisi) -HKT 28800 # Hong Kong Time (not in zic) +GET Asia/Tbilisi # Georgia Time (obsolete) +HKT 28800 # Hong Kong Time (not in IANA database) ICT 25200 # Indochina Time # (Asia/Bangkok) # (Asia/Phnom_Penh) @@ -285,33 +281,29 @@ ICT 25200 # Indochina Time IDT 10800 D # Israel Daylight Time # (Asia/Jerusalem) IRKST Asia/Irkutsk # Irkutsk Summer Time (obsolete) -IRKT Asia/Irkutsk # Irkutsk Time - # (Asia/Irkutsk) -IRT 12600 # Iran Time (not in zic) +IRKT Asia/Irkutsk # Irkutsk Time (obsolete) +IRT 12600 # Iran Time (not in IANA database) # CONFLICT! IST is not unique # Other timezones: # - IST: Irish Summer Time (Europe) # - IST: Indian Standard Time (Asia) IST 7200 # Israel Standard Time # (Asia/Jerusalem) -JAYT 32400 # Jayapura Time (Indonesia) (not in zic) +JAYT 32400 # Jayapura Time (Indonesia) (not in IANA database) JST 32400 # Japan Standard Time # (Asia/Tokyo) -KDT 36000 D # Korean Daylight Time (not in zic) +KDT 36000 D # Korean Daylight Time (not in IANA database) KGST 21600 D # Kyrgyzstan Summer Time (obsolete) -KGT Asia/Bishkek # Kyrgyzstan Time - # (Asia/Bishkek) +KGT Asia/Bishkek # Kyrgyzstan Time (obsolete) KRAST Asia/Krasnoyarsk # Krasnoyarsk Summer Time (obsolete) -KRAT Asia/Krasnoyarsk # Krasnoyarsk Time - # (Asia/Krasnoyarsk) +KRAT Asia/Krasnoyarsk # Krasnoyarsk Time (obsolete) KST 32400 # Korean Standard Time # (Asia/Seoul) LKT Asia/Colombo # Lanka Time (obsolete) MAGST Asia/Magadan # Magadan Summer Time (obsolete) -MAGT Asia/Magadan # Magadan Time - # (Asia/Magadan) +MAGT Asia/Magadan # Magadan Time (obsolete) MMT 23400 # Myanmar Time - # (Asia/Rangoon) + # (Asia/Yangon) MYT 28800 # Malaysia Time # (Asia/Kuala_Lumpur) # (Asia/Kuching) @@ -320,11 +312,9 @@ NOVT Asia/Novosibirsk # Novosibirsk Time (obsolete) NPT 20700 # Nepal Time # (Asia/Katmandu) OMSST Asia/Omsk # Omsk Summer Time (obsolete) -OMST Asia/Omsk # Omsk Time - # (Asia/Omsk) +OMST Asia/Omsk # Omsk Time (obsolete) PETST Asia/Kamchatka # Petropavlovsk-Kamchatski Summer Time (obsolete) -PETT Asia/Kamchatka # Petropavlovsk-Kamchatski Time - # (Asia/Kamchatka) +PETT Asia/Kamchatka # Petropavlovsk-Kamchatski Time (obsolete) PHT 28800 # Philippine Time # (Asia/Manila) PKT 18000 # Pakistan Time @@ -333,10 +323,8 @@ PKST 21600 D # Pakistan Summer Time # (Asia/Karachi) SGT Asia/Singapore # Singapore Time # (Asia/Singapore) -TJT 18000 # Tajikistan Time - # (Asia/Dushanbe) -TMT Asia/Ashgabat # Turkmenistan Time - # (Asia/Ashgabat) +TJT 18000 # Tajikistan Time (obsolete) +TMT Asia/Ashgabat # Turkmenistan Time (obsolete) ULAST 32400 D # Ulan Bator Summer Time # (Asia/Ulaanbaatar) ULAT Asia/Ulaanbaatar # Ulan Bator Time @@ -344,20 +332,15 @@ ULAT Asia/Ulaanbaatar # Ulan Bator Time UZST 21600 D # Uzbekistan Summer Time # (Asia/Samarkand) # (Asia/Tashkent) -UZT 18000 # Uzbekistan Time - # (Asia/Samarkand) - # (Asia/Tashkent) +UZT 18000 # Uzbekistan Time (obsolete) VLAST Asia/Vladivostok # Vladivostok Summer Time (obsolete) -VLAT Asia/Vladivostok # Vladivostok Time - # (Asia/Vladivostok) +VLAT Asia/Vladivostok # Vladivostok Time (obsolete) XJT 21600 # Xinjiang Time # (Asia/Urumqi) YAKST Asia/Yakutsk # Yakutsk Summer Time (obsolete) -YAKT Asia/Yakutsk # Yakutsk Time - # (Asia/Yakutsk) +YAKT Asia/Yakutsk # Yakutsk Time (obsolete) YEKST 21600 D # Yekaterinburg Summer Time (obsolete) -YEKT Asia/Yekaterinburg # Yekaterinburg Time - # (Asia/Yekaterinburg) +YEKT Asia/Yekaterinburg # Yekaterinburg Time (obsolete) #################### ATLANTIC #################### @@ -408,7 +391,7 @@ FKT Atlantic/Stanley # Falkland Islands Time (obsolete) #################### AUSTRALIA #################### -ACSST 37800 D # Australian Central Summer Standard Time (not in zic) +ACSST 37800 D # Australian Central Summer Standard Time (not in IANA database) ACDT 37800 D # Australian Central Daylight Time # (Australia/Adelaide) # (Australia/Broken_Hill) @@ -419,7 +402,7 @@ ACST 34200 # Australian Central Standard Time # (Australia/Darwin) ACWST 31500 # Australian Central Western Standard Time # (Australia/Eucla) -AESST 39600 D # Australian Eastern Summer Standard Time (not in zic) +AESST 39600 D # Australian Eastern Summer Standard Time (not in IANA database) AEDT 39600 D # Australian Eastern Daylight Time # (Australia/Brisbane) # (Australia/Currie) @@ -434,21 +417,21 @@ AEST 36000 # Australian Eastern Standard Time # (Australia/Lindeman) # (Australia/Melbourne) # (Australia/Sydney) -AWSST 32400 D # Australia Western Summer Standard Time (not in zic) +AWSST 32400 D # Australia Western Summer Standard Time (not in IANA database) AWST 28800 # Australian Western Standard Time # (Australia/Perth) -CADT 37800 D # Central Australia Daylight-Saving Time (not in zic) -CAST 34200 # Central Australia Standard Time (not in zic) +CADT 37800 D # Central Australia Daylight-Saving Time (not in IANA database) +CAST 34200 # Central Australia Standard Time (not in IANA database) LHDT Australia/Lord_Howe # Lord Howe Daylight Time # (Australia/Lord_Howe) LHST 37800 # Lord Howe Standard Time # (Australia/Lord_Howe) -LIGT 36000 # Melbourne, Australia (not in zic) -NZT 43200 # New Zealand Time (not in zic) -SADT 37800 D # South Australian Daylight-Saving Time (not in zic) -WADT 28800 D # West Australian Daylight-Saving Time (not in zic) -WAST 25200 # West Australian Standard Time (not in zic) -WDT 32400 D # West Australian Daylight-Saving Time (not in zic) +LIGT 36000 # Melbourne, Australia (not in IANA database) +NZT 43200 # New Zealand Time (not in IANA database) +SADT 37800 D # South Australian Daylight-Saving Time (not in IANA database) +WADT 28800 D # West Australian Daylight-Saving Time (not in IANA database) +WAST 25200 # West Australian Standard Time (not in IANA database) +WDT 32400 D # West Australian Daylight-Saving Time (not in IANA database) #################### ETC #################### @@ -472,7 +455,7 @@ GMT 0 # Greenwich Mean Time # (Europe/London) UCT 0 # Universal Coordinated Time # (Etc/UCT) -UT 0 # Universal Time (not in zic) +UT 0 # Universal Time (not in IANA database) UTC 0 # Coordinated Universal Time Z 0 # Zulu ZULU 0 # Zulu @@ -631,10 +614,10 @@ EETDST 10800 D # East-Egypt Summertime FET 10800 # Further-eastern European Time (obsolete) # (Europe/Kaliningrad) # (Europe/Minsk) -MEST 7200 D # Middle Europe Summer Time (not in zic) -MET 3600 # Middle Europe Time (not in zic) -METDST 7200 D # Middle Europe Summer Time (not in zic) -MEZ 3600 # Mitteleuropaeische Zeit (German) (not in zic) +MEST 7200 D # Middle Europe Summer Time (not in IANA database) +MET 3600 # Middle Europe Time (not in IANA database) +METDST 7200 D # Middle Europe Summer Time (not in IANA database) +MEZ 3600 # Mitteleuropaeische Zeit (German) (not in IANA database) MSD 14400 D # Moscow Daylight Time (obsolete) MSK Europe/Moscow # Moscow Time # (Europe/Moscow) @@ -669,8 +652,7 @@ RET 14400 # Reunion Time # (Indian/Reunion) SCT 14400 # Seychelles Time # (Indian/Mahe) -TFT 18000 # Kerguelen Time - # (Indian/Kerguelen) +TFT 18000 # Kerguelen Time (obsolete) #################### PACIFIC #################### @@ -708,11 +690,11 @@ MART -34200 # Marquesas Time MHT 43200 # Kwajalein Time # (Pacific/Kwajalein) # (Pacific/Majuro) -MPT 36000 # North Mariana Islands Time (not in zic) +MPT 36000 # North Mariana Islands Time (not in IANA database) # CONFLICT! NFT is not unique # Other timezones: # - NFT: Norfolk Time (Pacific) -NFT -12600 # Newfoundland Time (not in zic) +NFT -12600 # Newfoundland Time (not in IANA database) NUT Pacific/Niue # Niue Time # (Pacific/Niue) NZDT 46800 D # New Zealand Daylight Time @@ -729,13 +711,13 @@ PONT 39600 # Ponape Time (Micronesia) # (Pacific/Ponape) PWT 32400 # Palau Time # (Pacific/Palau) -TAHT -36000 # Tahiti Time (zic says "TAHT", other sources "THAT") +TAHT -36000 # Tahiti Time (IANA database says "TAHT", other sources "THAT") # (Pacific/Tahiti) TKT Pacific/Fakaofo # Tokelau Time # (Pacific/Fakaofo) TOT 46800 # Tonga Time # (Pacific/Tongatapu) -TRUT 36000 # Truk Time (zic used to say "TRUT", other sources say "TRUK") +TRUT 36000 # Truk Time (IANA database used to say "TRUT", other sources say "TRUK") # (Pacific/Truk) TVT 43200 # Tuvalu Time # (Pacific/Funafuti) @@ -745,4 +727,4 @@ WAKT 43200 # Wake Time # (Pacific/Wake) WFT 43200 # Wallis and Futuna Time # (Pacific/Wallis) -YAPT 36000 # Yap Time (Micronesia) (not in zic) +YAPT 36000 # Yap Time (Micronesia) (not in IANA database) diff --git a/src/timezone/tznames/Etc.txt b/src/timezone/tznames/Etc.txt index a4ea1dee68..aa48404819 100644 --- a/src/timezone/tznames/Etc.txt +++ b/src/timezone/tznames/Etc.txt @@ -27,7 +27,7 @@ GMT 0 # Greenwich Mean Time # (Europe/London) UCT 0 # Universal Coordinated Time # (Etc/UCT) -UT 0 # Universal Time (not in zic) +UT 0 # Universal Time (not in IANA database) UTC 0 # Coordinated Universal Time # (Etc/UTC) Z 0 # Zulu diff --git a/src/timezone/tznames/Europe.txt b/src/timezone/tznames/Europe.txt index a4223e5e22..85d18d9d2d 100644 --- a/src/timezone/tznames/Europe.txt +++ b/src/timezone/tznames/Europe.txt @@ -182,17 +182,16 @@ GMT 0 # Greenwich Mean Time # - IST: Israel Standard Time (Asia) IST 3600 D # Irish Summer Time # (Europe/Dublin) -MEST 7200 D # Middle Europe Summer Time (not in zic) -MET 3600 # Middle Europe Time (not in zic) -METDST 7200 D # Middle Europe Summer Time (not in zic) -MEZ 3600 # Mitteleurop�ische Zeit (German) (not in zic) +MEST 7200 D # Middle Europe Summer Time (not in IANA database) +MET 3600 # Middle Europe Time (not in IANA database) +METDST 7200 D # Middle Europe Summer Time (not in IANA database) +MEZ 3600 # Mitteleurop�ische Zeit (German) (not in IANA database) MSD 14400 D # Moscow Daylight Time (obsolete) MSK Europe/Moscow # Moscow Time # (Europe/Moscow) # (Europe/Volgograd) SAMST Europe/Samara # Samara Summer Time (obsolete) -SAMT Europe/Samara # Samara Time - # (Europe/Samara) +SAMT Europe/Samara # Samara Time (obsolete) VOLT Europe/Volgograd # Volgograd Time (obsolete) WEST 3600 D # Western Europe Summer Time # (Africa/Casablanca) diff --git a/src/timezone/tznames/Indian.txt b/src/timezone/tznames/Indian.txt index 634660075f..12842d366f 100644 --- a/src/timezone/tznames/Indian.txt +++ b/src/timezone/tznames/Indian.txt @@ -35,5 +35,4 @@ RET 14400 # Reunion Time # (Indian/Reunion) SCT 14400 # Seychelles Time # (Indian/Mahe) -TFT 18000 # Kerguelen Time - # (Indian/Kerguelen) +TFT 18000 # Kerguelen Time (obsolete) diff --git a/src/timezone/tznames/Pacific.txt b/src/timezone/tznames/Pacific.txt index 67211fcad0..85c9991298 100644 --- a/src/timezone/tznames/Pacific.txt +++ b/src/timezone/tznames/Pacific.txt @@ -16,7 +16,7 @@ CHADT 49500 D # Chatham Daylight Time (New Zealand) # (Pacific/Chatham) CHAST 45900 # Chatham Standard Time (New Zealand) # (Pacific/Chatham) -ChST 36000 # Chamorro Standard Time (lower case "h" is as in zic) +ChST 36000 # Chamorro Standard Time (lower case "h" is as in IANA database) # (Pacific/Guam) # (Pacific/Saipan) CHUT 36000 # Chuuk Time @@ -52,7 +52,7 @@ MART -34200 # Marquesas Time MHT 43200 # Kwajalein Time # (Pacific/Kwajalein) # (Pacific/Majuro) -MPT 36000 # North Mariana Islands Time (not in zic) +MPT 36000 # North Mariana Islands Time (not in IANA database) NCT 39600 # New Caledonia Time # (Pacific/Noumea) # CONFLICT! NFT is not unique @@ -90,13 +90,13 @@ SBT 39600 # Solomon Islands Time SST -39600 # South Sumatran Time # (Pacific/Midway) # (Pacific/Pago_Pago) -TAHT -36000 # Tahiti Time (zic says "TAHT", other sources "THAT") +TAHT -36000 # Tahiti Time (IANA database says "TAHT", other sources "THAT") # (Pacific/Tahiti) TKT Pacific/Fakaofo # Tokelau Time # (Pacific/Fakaofo) TOT 46800 # Tonga Time # (Pacific/Tongatapu) -TRUT 36000 # Truk Time (zic used to say "TRUT", other sources say "TRUK") +TRUT 36000 # Truk Time (IANA database used to say "TRUT", other sources say "TRUK") # (Pacific/Truk) TVT 43200 # Tuvalu Time # (Pacific/Funafuti) @@ -113,5 +113,5 @@ WSST 46800 # West Samoa Standard Time # CONFLICT! WST is not unique # Other timezones: # - WST: Western Standard Time (Australia) -WST 46800 # West Samoa Time (caution: this used to mean -39600) (not in zic) -YAPT 36000 # Yap Time (Micronesia) (not in zic) +WST 46800 # West Samoa Time (caution: this used to mean -39600) (not in IANA database) +YAPT 36000 # Yap Time (Micronesia) (not in IANA database) diff --git a/src/timezone/zic.c b/src/timezone/zic.c index b546a17372..a83cea12dd 100644 --- a/src/timezone/zic.c +++ b/src/timezone/zic.c @@ -8,9 +8,11 @@ #include "postgres_fe.h" +#include #include #include #include +#include #include "pg_getopt.h" @@ -35,11 +37,24 @@ typedef int64 zic_t; #define MKDIR_UMASK 0755 #endif #endif +#ifndef AT_SYMLINK_FOLLOW +#define linkat(fromdir, from, todir, to, flag) \ + (itssymlink(from) ? (errno = ENOTSUP, -1) : link(from, to)) +#endif + +/* The maximum ptrdiff_t value, for pre-C99 platforms. */ +#ifndef PTRDIFF_MAX +static ptrdiff_t const PTRDIFF_MAX = MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t)); +#endif + +/* The type and printf format for line numbers. */ +typedef int lineno_t; +#define PRIdLINENO "d" struct rule { const char *r_filename; - int r_linenum; + lineno_t r_linenum; const char *r_name; zic_t r_loyear; /* for example, 1986 */ @@ -61,7 +76,7 @@ struct rule zic_t r_stdoff; /* offset from standard time */ const char *r_abbrvar; /* variable part of abbreviation */ - int r_todo; /* a rule to do (used in outzone) */ + bool r_todo; /* a rule to do (used in outzone) */ zic_t r_temp; /* used in outzone */ }; @@ -76,7 +91,7 @@ struct rule struct zone { const char *z_filename; - int z_linenum; + lineno_t z_linenum; const char *z_name; zic_t z_gmtoff; @@ -87,7 +102,7 @@ struct zone zic_t z_stdoff; struct rule *z_rules; - int z_nrules; + ptrdiff_t z_nrules; struct rule z_untilrule; zic_t z_untiltime; @@ -105,7 +120,7 @@ static int addtype(zic_t, char const *, bool, bool, bool); static void leapadd(zic_t, bool, int, int); static void adjleap(void); static void associate(void); -static void dolink(const char *fromfield, const char *tofield); +static void dolink(const char *, const char *, bool); static char **getfields(char *buf); static zic_t gethms(const char *string, const char *errstring, bool); @@ -116,26 +131,36 @@ static void inrule(char **fields, int nfields); static bool inzcont(char **fields, int nfields); static bool inzone(char **fields, int nfields); static bool inzsub(char **, int, bool); -static int itsdir(const char *name); +static bool itsdir(char const *); +static bool itssymlink(char const *); static bool is_alpha(char a); static char lowerit(char); -static bool mkdirs(char *); +static void mkdirs(char const *, bool); static void newabbr(const char *abbr); static zic_t oadd(zic_t t1, zic_t t2); -static void outzone(const struct zone * zp, int ntzones); +static void outzone(const struct zone * zp, ptrdiff_t ntzones); static zic_t rpytime(const struct rule * rp, zic_t wantedy); static void rulesub(struct rule * rp, const char *loyearp, const char *hiyearp, const char *typep, const char *monthp, const char *dayp, const char *timep); static zic_t tadd(zic_t t1, zic_t t2); -static bool yearistype(int year, const char *type); +static bool yearistype(zic_t year, const char *type); /* Bound on length of what %z can expand to. */ enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1}; +/* If true, work around a bug in Qt 5.6.1 and earlier, which mishandles + tz binary files whose POSIX-TZ-style strings contain '<'; see + QTBUG-53071 . This + workaround will no longer be needed when Qt 5.6.1 and earlier are + obsolete, say in the year 2021. */ +enum +{ +WORK_AROUND_QTBUG_53071 = true}; + static int charcnt; static bool errors; static bool warnings; @@ -144,7 +169,7 @@ static int leapcnt; static bool leapseen; static zic_t leapminyear; static zic_t leapmaxyear; -static int linenum; +static lineno_t linenum; static int max_abbrvar_len = PERCENT_Z_LEN_BOUND; static int max_format_len; static zic_t max_year; @@ -153,10 +178,10 @@ static bool noise; static bool print_abbrevs; static zic_t print_cutoff; static const char *rfilename; -static int rlinenum; +static lineno_t rlinenum; static const char *progname; -static int timecnt; -static int timecnt_alloc; +static ptrdiff_t timecnt; +static ptrdiff_t timecnt_alloc; static int typecnt; /* @@ -241,24 +266,24 @@ static int typecnt; #define YR_ONLY 2 static struct rule *rules; -static int nrules; /* number of rules */ -static int nrules_alloc; +static ptrdiff_t nrules; /* number of rules */ +static ptrdiff_t nrules_alloc; static struct zone *zones; -static int nzones; /* number of zones */ -static int nzones_alloc; +static ptrdiff_t nzones; /* number of zones */ +static ptrdiff_t nzones_alloc; struct link { const char *l_filename; - int l_linenum; + lineno_t l_linenum; const char *l_from; const char *l_to; }; static struct link *links; -static int nlinks; -static int nlinks_alloc; +static ptrdiff_t nlinks; +static ptrdiff_t nlinks_alloc; struct lookup { @@ -346,6 +371,7 @@ static const int len_years[2] = { static struct attype { zic_t at; + bool dontmerge; unsigned char type; } *attypes; static zic_t gmtoffs[TZ_MAX_TYPES]; @@ -404,17 +430,17 @@ ecpyalloc(char const * str) } static void * -growalloc(void *ptr, size_t itemsize, int nitems, int *nitems_alloc) +growalloc(void *ptr, size_t itemsize, ptrdiff_t nitems, ptrdiff_t *nitems_alloc) { if (nitems < *nitems_alloc) return ptr; else { - int amax = INT_MAX < SIZE_MAX ? INT_MAX : SIZE_MAX; + ptrdiff_t amax = PTRDIFF_MAX - WORK_AROUND_QTBUG_53071; if ((amax - 1) / 3 * 2 < *nitems_alloc) - memory_exhausted(_("int overflow")); - *nitems_alloc = *nitems_alloc + (*nitems_alloc >> 1) + 1; + memory_exhausted(_("integer overflow")); + *nitems_alloc += (*nitems_alloc >> 1) + 1; return erealloc(ptr, size_product(*nitems_alloc, itemsize)); } } @@ -424,7 +450,7 @@ growalloc(void *ptr, size_t itemsize, int nitems, int *nitems_alloc) */ static void -eats(const char *name, int num, const char *rname, int rnum) +eats(char const * name, lineno_t num, char const * rname, lineno_t rnum) { filename = name; linenum = num; @@ -433,7 +459,7 @@ eats(const char *name, int num, const char *rname, int rnum) } static void -eat(const char *name, int num) +eat(char const * name, lineno_t num) { eats(name, num, NULL, -1); } @@ -446,10 +472,10 @@ verror(const char *string, va_list args) * "*" -v on BSD systems. */ if (filename) - fprintf(stderr, _("\"%s\", line %d: "), filename, linenum); + fprintf(stderr, _("\"%s\", line %" PRIdLINENO ": "), filename, linenum); vfprintf(stderr, string, args); if (rfilename != NULL) - fprintf(stderr, _(" (rule from \"%s\", line %d)"), + fprintf(stderr, _(" (rule from \"%s\", line %" PRIdLINENO ")"), rfilename, rlinenum); fprintf(stderr, "\n"); } @@ -478,17 +504,17 @@ warning(const char *string,...) } static void -close_file(FILE *stream, char const * name) +close_file(FILE *stream, char const * dir, char const * name) { char const *e = (ferror(stream) ? _("I/O error") : fclose(stream) != 0 ? strerror(errno) : NULL); if (e) { - fprintf(stderr, "%s: ", progname); - if (name) - fprintf(stderr, "%s: ", name); - fprintf(stderr, "%s\n", e); + fprintf(stderr, "%s: %s%s%s%s%s\n", progname, + dir ? dir : "", dir ? "/" : "", + name ? name : "", name ? ": " : "", + e); exit(EXIT_FAILURE); } } @@ -503,10 +529,34 @@ usage(FILE *stream, int status) "Report bugs to %s.\n"), progname, progname, PACKAGE_BUGREPORT); if (status == EXIT_SUCCESS) - close_file(stream, NULL); + close_file(stream, NULL, NULL); exit(status); } +/* Change the working directory to DIR, possibly creating DIR and its + ancestors. After this is done, all files are accessed with names + relative to DIR. */ +static void +change_directory(char const * dir) +{ + if (chdir(dir) != 0) + { + int chdir_errno = errno; + + if (chdir_errno == ENOENT) + { + mkdirs(dir, false); + chdir_errno = chdir(dir) == 0 ? 0 : errno; + } + if (chdir_errno != 0) + { + fprintf(stderr, _("%s: Can't chdir to %s: %s\n"), + progname, dir, strerror(chdir_errno)); + exit(EXIT_FAILURE); + } + } +} + static const char *psxrules; static const char *lcltime; static const char *directory; @@ -516,9 +566,10 @@ static const char *yitcommand; int main(int argc, char *argv[]) { - int i; - int j; - int c; + int c, + k; + ptrdiff_t i, + j; #ifndef WIN32 umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH)); @@ -530,14 +581,14 @@ main(int argc, char *argv[]) _("wild compilation-time specification of zic_t")); return EXIT_FAILURE; } - for (i = 1; i < argc; ++i) - if (strcmp(argv[i], "--version") == 0) + for (k = 1; k < argc; k++) + if (strcmp(argv[k], "--version") == 0) { printf("zic %s\n", PG_VERSION); - close_file(stdout, NULL); + close_file(stdout, NULL, NULL); return EXIT_SUCCESS; } - else if (strcmp(argv[i], "--help") == 0) + else if (strcmp(argv[k], "--help") == 0) { usage(stdout, EXIT_SUCCESS); } @@ -625,11 +676,12 @@ main(int argc, char *argv[]) adjleap(); } - for (i = optind; i < argc; ++i) - infile(argv[i]); + for (k = optind; k < argc; k++) + infile(argv[k]); if (errors) return EXIT_FAILURE; associate(); + change_directory(directory); for (i = 0; i < nzones; i = j) { /* @@ -646,7 +698,7 @@ main(int argc, char *argv[]) for (i = 0; i < nlinks; ++i) { eat(links[i].l_filename, links[i].l_linenum); - dolink(links[i].l_from, links[i].l_to); + dolink(links[i].l_from, links[i].l_to, false); if (noise) for (j = 0; j < nlinks; ++j) if (strcmp(links[i].l_to, @@ -656,12 +708,12 @@ main(int argc, char *argv[]) if (lcltime != NULL) { eat(_("command line"), 1); - dolink(lcltime, TZDEFAULT); + dolink(lcltime, TZDEFAULT, true); } if (psxrules != NULL) { eat(_("command line"), 1); - dolink(psxrules, TZDEFRULES); + dolink(psxrules, TZDEFRULES, true); } if (warnings && (ferror(stderr) || fclose(stderr) != 0)) return EXIT_FAILURE; @@ -675,7 +727,7 @@ componentcheck(char const * name, char const * component, enum { component_len_max = 14}; - size_t component_len = component_end - component; + ptrdiff_t component_len = component_end - component; if (component_len == 0) { @@ -693,8 +745,10 @@ componentcheck(char const * name, char const * component, if (0 < component_len && component_len <= 2 && component[0] == '.' && component_end[-1] == '.') { + int len = component_len; + error(_("file name '%s' contains '%.*s' component"), - name, (int) component_len, component); + name, len, component); return false; } if (noise) @@ -751,131 +805,160 @@ namecheck(const char *name) return componentcheck(name, component, cp); } +/* + * Create symlink contents suitable for symlinking FROM to TO, as a + * freshly allocated string. FROM should be a relative file name, and + * is relative to the global variable DIRECTORY. TO can be either + * relative or absolute. + */ +#ifdef HAVE_SYMLINK static char * -relname(char const * dir, char const * base) +relname(char const * from, char const * to) +{ + size_t i, + taillen, + dotdotetcsize; + size_t dir_len = 0, + dotdots = 0, + linksize = SIZE_MAX; + char const *f = from; + char *result = NULL; + + if (*to == '/') + { + /* Make F absolute too. */ + size_t len = strlen(directory); + bool needslash = len && directory[len - 1] != '/'; + + linksize = len + needslash + strlen(from) + 1; + f = result = emalloc(linksize); + strcpy(result, directory); + result[len] = '/'; + strcpy(result + len + needslash, from); + } + for (i = 0; f[i] && f[i] == to[i]; i++) + if (f[i] == '/') + dir_len = i + 1; + for (; to[i]; i++) + dotdots += to[i] == '/' && to[i - 1] != '/'; + taillen = strlen(f + dir_len); + dotdotetcsize = 3 * dotdots + taillen + 1; + if (dotdotetcsize <= linksize) + { + if (!result) + result = emalloc(dotdotetcsize); + for (i = 0; i < dotdots; i++) + memcpy(result + 3 * i, "../", 3); + memmove(result + 3 * dotdots, f + dir_len, taillen + 1); + } + return result; +} +#endif /* HAVE_SYMLINK */ + +/* Hard link FROM to TO, following any symbolic links. + Return 0 if successful, an error number otherwise. */ +static int +hardlinkerr(char const * from, char const * to) { - if (*base == '/') - return ecpyalloc(base); - else - { - size_t dir_len = strlen(dir); - bool needs_slash = dir_len && dir[dir_len - 1] != '/'; - char *result = emalloc(dir_len + needs_slash + strlen(base) + 1); + int r = linkat(AT_FDCWD, from, AT_FDCWD, to, AT_SYMLINK_FOLLOW); - result[dir_len] = '/'; - strcpy(result + dir_len + needs_slash, base); - return memcpy(result, dir, dir_len); - } + return r == 0 ? 0 : errno; } static void -dolink(char const * fromfield, char const * tofield) +dolink(char const * fromfield, char const * tofield, bool staysymlink) { - char *fromname; - char *toname; - int fromisdir; - - fromname = relname(directory, fromfield); - toname = relname(directory, tofield); + bool todirs_made = false; + int link_errno; /* * We get to be careful here since there's a fair chance of root running * us. */ - fromisdir = itsdir(fromname); - if (fromisdir) + if (itsdir(fromfield)) + { + fprintf(stderr, _("%s: link from %s/%s failed: %s\n"), + progname, directory, fromfield, strerror(EPERM)); + exit(EXIT_FAILURE); + } + if (staysymlink) + staysymlink = itssymlink(tofield); + if (remove(tofield) == 0) + todirs_made = true; + else if (errno != ENOENT) { - char const *e = strerror(fromisdir < 0 ? errno : EPERM); + char const *e = strerror(errno); - fprintf(stderr, _("%s: link from %s failed: %s"), - progname, fromname, e); + fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"), + progname, directory, tofield, e); exit(EXIT_FAILURE); } - if (link(fromname, toname) != 0) + link_errno = staysymlink ? ENOTSUP : hardlinkerr(fromfield, tofield); + if (link_errno == ENOENT && !todirs_made) { - int link_errno = errno; - bool retry_if_link_supported = false; + mkdirs(tofield, true); + todirs_made = true; + link_errno = hardlinkerr(fromfield, tofield); + } + if (link_errno != 0) + { +#ifdef HAVE_SYMLINK + bool absolute = *fromfield == '/'; + char *linkalloc = absolute ? NULL : relname(fromfield, tofield); + char const *contents = absolute ? fromfield : linkalloc; + int symlink_errno = symlink(contents, tofield) == 0 ? 0 : errno; - if (link_errno == ENOENT || link_errno == ENOTSUP) + if (symlink_errno == ENOENT && !todirs_made) { - if (!mkdirs(toname)) - exit(EXIT_FAILURE); - retry_if_link_supported = true; + mkdirs(tofield, true); + symlink_errno = symlink(contents, tofield) == 0 ? 0 : errno; } - if ((link_errno == EEXIST || link_errno == ENOTSUP) - && itsdir(toname) == 0 - && (remove(toname) == 0 || errno == ENOENT)) - retry_if_link_supported = true; - if (retry_if_link_supported && link_errno != ENOTSUP) - link_errno = link(fromname, toname) == 0 ? 0 : errno; - if (link_errno != 0) + free(linkalloc); + if (symlink_errno == 0) { -#ifdef HAVE_SYMLINK - const char *s = fromfield; - const char *t; - char *p; - size_t dotdots = 0; - char *symlinkcontents; - int symlink_result; - - do - t = s; - while ((s = strchr(s, '/')) - && strncmp(fromfield, tofield, ++s - fromfield) == 0); - - for (s = tofield + (t - fromfield); *s; s++) - dotdots += *s == '/'; - symlinkcontents = emalloc(3 * dotdots + strlen(t) + 1); - for (p = symlinkcontents; dotdots-- != 0; p += 3) - memcpy(p, "../", 3); - strcpy(p, t); - symlink_result = symlink(symlinkcontents, toname); - free(symlinkcontents); - if (symlink_result == 0) - { - if (link_errno != ENOTSUP) - warning(_("symbolic link used because hard link failed: %s"), - strerror(link_errno)); - } - else + if (link_errno != ENOTSUP) + warning(_("symbolic link used because hard link failed: %s"), + strerror(link_errno)); + } + else #endif /* HAVE_SYMLINK */ - { - FILE *fp, - *tp; - int c; + { + FILE *fp, + *tp; + int c; - fp = fopen(fromname, "rb"); - if (!fp) - { - const char *e = strerror(errno); + fp = fopen(fromfield, "rb"); + if (!fp) + { + char const *e = strerror(errno); - fprintf(stderr, - _("%s: Can't read %s: %s\n"), - progname, fromname, e); - exit(EXIT_FAILURE); - } - tp = fopen(toname, "wb"); - if (!tp) - { - const char *e = strerror(errno); + fprintf(stderr, _("%s: Can't read %s/%s: %s\n"), + progname, directory, fromfield, e); + exit(EXIT_FAILURE); + } + tp = fopen(tofield, "wb"); + if (!tp) + { + char const *e = strerror(errno); - fprintf(stderr, - _("%s: Can't create %s: %s\n"), - progname, toname, e); - exit(EXIT_FAILURE); - } - while ((c = getc(fp)) != EOF) - putc(c, tp); - close_file(fp, fromname); - close_file(tp, toname); - if (link_errno != ENOTSUP) - warning(_("copy used because hard link failed: %s"), - strerror(link_errno)); + fprintf(stderr, _("%s: Can't create %s/%s: %s\n"), + progname, directory, tofield, e); + exit(EXIT_FAILURE); } + while ((c = getc(fp)) != EOF) + putc(c, tp); + close_file(fp, directory, fromfield); + close_file(tp, directory, tofield); + if (link_errno != ENOTSUP) + warning(_("copy used because hard link failed: %s"), + strerror(link_errno)); +#ifdef HAVE_SYMLINK + else if (symlink_errno != ENOTSUP) + warning(_("copy used because symbolic link failed: %s"), + strerror(symlink_errno)); +#endif } } - free(fromname); - free(toname); } #define TIME_T_BITS_IN_FILE 64 @@ -888,10 +971,6 @@ static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE); * rounded downward to the negation of a power of two that is * comfortably outside the error bounds. * - * zic does not output time stamps before this, partly because they - * are physically suspect, and partly because GNOME mishandles them; see - * GNOME bug 730332 . - * * For the time of the Big Bang, see: * * Ade PAR, Aghanim N, Armitage-Caplan C et al. Planck 2013 results. @@ -913,28 +992,58 @@ static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE); #define BIG_BANG (- (((zic_t) 1) << 59)) #endif -static const zic_t big_bang_time = BIG_BANG; +/* If true, work around GNOME bug 730332 + + by refusing to output time stamps before BIG_BANG. + Such time stamps are physically suspect anyway. -/* Return 1 if NAME is a directory, 0 if it's something else, -1 if trouble. */ -static int + The GNOME bug is scheduled to be fixed in GNOME 3.22, and if so + this workaround will no longer be needed when GNOME 3.21 and + earlier are obsolete, say in the year 2021. */ +enum +{ +WORK_AROUND_GNOME_BUG_730332 = true}; + +static const zic_t early_time = (WORK_AROUND_GNOME_BUG_730332 + ? BIG_BANG + : MINVAL(zic_t, TIME_T_BITS_IN_FILE)); + +/* Return true if NAME is a directory. */ +static bool itsdir(char const * name) { struct stat st; int res = stat(name, &st); - #ifdef S_ISDIR if (res == 0) return S_ISDIR(st.st_mode) != 0; #endif if (res == 0 || errno == EOVERFLOW) { - char *nameslashdot = relname(name, "."); - bool dir = stat(nameslashdot, &st) == 0 || errno == EOVERFLOW; + size_t n = strlen(name); + char *nameslashdot = emalloc(n + 3); + bool dir; + memcpy(nameslashdot, name, n); + strcpy(&nameslashdot[n], &"/."[!(n && name[n - 1] != '/')]); + dir = stat(nameslashdot, &st) == 0 || errno == EOVERFLOW; free(nameslashdot); return dir; } - return -1; + return false; +} + +/* Return true if NAME is a symbolic link. */ +static bool +itssymlink(char const * name) +{ +#ifdef HAVE_SYMLINK + char c; + + return 0 <= readlink(name, &c, 1); +#else + return false; +#endif } /* @@ -957,10 +1066,10 @@ associate(void) { struct zone *zp; struct rule *rp; - int base, + ptrdiff_t i, + j, + base, out; - int i, - j; if (nrules != 0) { @@ -1047,7 +1156,7 @@ infile(const char *name) const struct lookup *lp; int nfields; bool wantcont; - int num; + lineno_t num; char buf[BUFSIZ]; if (strcmp(name, "-") == 0) @@ -1098,7 +1207,7 @@ infile(const char *name) if (lp == NULL) error(_("input line of unknown type")); else - switch ((int) (lp->l_value)) + switch (lp->l_value) { case LC_RULE: inrule(fields, nfields); @@ -1129,7 +1238,7 @@ infile(const char *name) } free(fields); } - close_file(fp, filename); + close_file(fp, NULL, filename); if (wantcont) error(_("expected continuation line not found")); } @@ -1225,7 +1334,7 @@ inrule(char **fields, int nfields) static bool inzone(char **fields, int nfields) { - int i; + ptrdiff_t i; if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { @@ -1250,8 +1359,8 @@ inzone(char **fields, int nfields) if (zones[i].z_name != NULL && strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { - error( - _("duplicate zone name %s (file \"%s\", line %d)"), + error(_("duplicate zone name %s" + " (file \"%s\", line %" PRIdLINENO ")"), fields[ZF_NAME], zones[i].z_filename, zones[i].z_linenum); @@ -1313,7 +1422,7 @@ inzsub(char **fields, int nfields, bool iscont) z.z_filename = filename; z.z_linenum = linenum; z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UT offset"), true); - if ((cp = strchr(fields[i_format], '%')) != 0) + if ((cp = strchr(fields[i_format], '%')) != NULL) { if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%') || strchr(fields[i_format], '/')) @@ -1375,7 +1484,7 @@ inleap(char **fields, int nfields) { const char *cp; const struct lookup *lp; - int i, + zic_t i, j; /* PG: make year be int not zic_t to avoid sscanf portability issues */ @@ -1491,7 +1600,7 @@ inleap(char **fields, int nfields) return; } t = tadd(t, tod); - if (t < big_bang_time) + if (t < early_time) { error(_("leap second precedes Big Bang")); return; @@ -1582,7 +1691,7 @@ rulesub(struct rule * rp, const char *loyearp, const char *hiyearp, lp = byword(cp, begin_years); rp->r_lowasnum = lp == NULL; if (!rp->r_lowasnum) - switch ((int) lp->l_value) + switch (lp->l_value) { case YR_MINIMUM: rp->r_loyear = ZIC_MIN; @@ -1607,7 +1716,7 @@ rulesub(struct rule * rp, const char *loyearp, const char *hiyearp, lp = byword(cp, end_years); rp->r_hiwasnum = lp == NULL; if (!rp->r_hiwasnum) - switch ((int) lp->l_value) + switch (lp->l_value) { case YR_MINIMUM: rp->r_hiyear = ZIC_MIN; @@ -1757,18 +1866,21 @@ static void writezone(const char *const name, const char *const string, char version) { FILE *fp; - int i, + ptrdiff_t i, j; int leapcnt32, leapi32; - int timecnt32, + ptrdiff_t timecnt32, timei32; int pass; - char *fullname; static const struct tzhead tzh0; static struct tzhead tzh; - zic_t *ats = emalloc(size_product(timecnt, sizeof *ats + 1)); - void *typesptr = ats + timecnt; + bool dir_checked = false; + zic_t one = 1; + zic_t y2038_boundary = one << 31; + ptrdiff_t nats = timecnt + WORK_AROUND_QTBUG_53071; + zic_t *ats = emalloc(size_product(nats, sizeof *ats + 1)); + void *typesptr = ats + nats; unsigned char *types = typesptr; /* @@ -1781,12 +1893,12 @@ writezone(const char *const name, const char *const string, char version) * Optimize. */ { - int fromi; - int toi; + ptrdiff_t fromi, + toi; toi = 0; fromi = 0; - while (fromi < timecnt && attypes[fromi].at < big_bang_time) + while (fromi < timecnt && attypes[fromi].at < early_time) ++fromi; for (; fromi < timecnt; ++fromi) { @@ -1799,15 +1911,24 @@ writezone(const char *const name, const char *const string, char version) attypes[fromi].type; continue; } - if (toi == 0 || - attypes[toi - 1].type != attypes[fromi].type) + if (toi == 0 + || attypes[fromi].dontmerge + || attypes[toi - 1].type != attypes[fromi].type) attypes[toi++] = attypes[fromi]; } timecnt = toi; } + if (noise && timecnt > 1200) - warning(_("pre-2014 clients may mishandle" - " more than 1200 transition times")); + { + if (timecnt > TZ_MAX_TIMES) + warning(_("reference clients mishandle" + " more than %d transition times"), + TZ_MAX_TIMES); + else + warning(_("pre-2014 clients may mishandle" + " more than 1200 transition times")); + } /* * Transfer. @@ -1818,6 +1939,20 @@ writezone(const char *const name, const char *const string, char version) types[i] = attypes[i].type; } + /* + * Work around QTBUG-53071 for time stamps less than y2038_boundary - 1, + * by inserting a no-op transition at time y2038_boundary - 1. This works + * only for timestamps before the boundary, which should be good enough in + * practice as QTBUG-53071 should be long-dead by 2038. + */ + if (WORK_AROUND_QTBUG_53071 && timecnt != 0 + && ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<')) + { + ats[timecnt] = y2038_boundary - 1; + types[timecnt] = types[timecnt - 1]; + timecnt++; + } + /* * Correct for leap seconds. */ @@ -1862,51 +1997,59 @@ writezone(const char *const name, const char *const string, char version) --leapcnt32; ++leapi32; } - fullname = relname(directory, name); /* * Remove old file, if any, to snap links. */ - if (itsdir(fullname) == 0 && remove(fullname) != 0 && errno != ENOENT) + if (remove(name) == 0) + dir_checked = true; + else if (errno != ENOENT) { const char *e = strerror(errno); - fprintf(stderr, _("%s: Cannot remove %s: %s\n"), - progname, fullname, e); + fprintf(stderr, _("%s: Cannot remove %s/%s: %s\n"), + progname, directory, name, e); exit(EXIT_FAILURE); } - if ((fp = fopen(fullname, "wb")) == NULL) + fp = fopen(name, "wb"); + if (!fp) { - if (!mkdirs(fullname)) - exit(EXIT_FAILURE); - if ((fp = fopen(fullname, "wb")) == NULL) - { - const char *e = strerror(errno); + int fopen_errno = errno; - fprintf(stderr, _("%s: Cannot create %s: %s\n"), - progname, fullname, e); + if (fopen_errno == ENOENT && !dir_checked) + { + mkdirs(name, true); + fp = fopen(name, "wb"); + fopen_errno = errno; + } + if (!fp) + { + fprintf(stderr, _("%s: Cannot create %s/%s: %s\n"), + progname, directory, name, strerror(fopen_errno)); exit(EXIT_FAILURE); } } for (pass = 1; pass <= 2; ++pass) { - int thistimei, - thistimecnt; + ptrdiff_t thistimei, + thistimecnt, + thistimelim; int thisleapi, - thisleapcnt; - int thistimelim, + thisleapcnt, thisleaplim; int writetype[TZ_MAX_TYPES]; int typemap[TZ_MAX_TYPES]; int thistypecnt; char thischars[TZ_MAX_CHARS]; - char thischarcnt; + int thischarcnt; + bool toomanytimes; int indmap[TZ_MAX_CHARS]; if (pass == 1) { thistimei = timei32; thistimecnt = timecnt32; + toomanytimes = thistimecnt >> 31 >> 1 != 0; thisleapi = leapi32; thisleapcnt = leapcnt32; } @@ -1914,9 +2057,12 @@ writezone(const char *const name, const char *const string, char version) { thistimei = 0; thistimecnt = timecnt; + toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0; thisleapi = 0; thisleapcnt = leapcnt; } + if (toomanytimes) + error(_("too many transition times")); thistimelim = thistimei + thistimecnt; thisleaplim = thisleapi + thisleapcnt; for (i = 0; i < typecnt; ++i) @@ -2017,8 +2163,7 @@ writezone(const char *const name, const char *const string, char version) break; if (j == thischarcnt) { - strcpy(&thischars[(int) thischarcnt], - thisabbr); + strcpy(&thischars[thischarcnt], thisabbr); thischarcnt += strlen(thisabbr) + 1; } indmap[abbrinds[i]] = j; @@ -2130,9 +2275,8 @@ writezone(const char *const name, const char *const string, char version) putc(ttisgmts[i], fp); } fprintf(fp, "\n%s\n", string); - close_file(fp, fullname); + close_file(fp, directory, name); free(ats); - free(fullname); } static char const * @@ -2366,13 +2510,13 @@ enum YEAR_BY_YEAR_ZONE = 1}; static int -stringzone(char *result, const struct zone * const zpfirst, const int zonecount) +stringzone(char *result, struct zone const * zpfirst, ptrdiff_t zonecount) { const struct zone *zp; struct rule *rp; struct rule *stdrp; struct rule *dstrp; - int i; + ptrdiff_t i; const char *abbrvar; int compat = 0; int c; @@ -2501,11 +2645,11 @@ stringzone(char *result, const struct zone * const zpfirst, const int zonecount) } static void -outzone(const struct zone * zpfirst, int zonecount) +outzone(const struct zone * zpfirst, ptrdiff_t zonecount) { const struct zone *zp; struct rule *rp; - int i, + ptrdiff_t i, j; bool usestart, useuntil; @@ -2527,6 +2671,7 @@ outzone(const struct zone * zpfirst, int zonecount) int compat; bool do_extend; char version; + ptrdiff_t lastatmax = -1; max_abbr_len = 2 + max_format_len + max_abbrvar_len; max_envvar_len = 2 * max_abbr_len + 5 * 9; @@ -2649,9 +2794,9 @@ outzone(const struct zone * zpfirst, int zonecount) */ stdoff = 0; zp = &zpfirst[i]; - usestart = i > 0 && (zp - 1)->z_untiltime > big_bang_time; + usestart = i > 0 && (zp - 1)->z_untiltime > early_time; useuntil = i < (zonecount - 1); - if (useuntil && zp->z_untiltime <= big_bang_time) + if (useuntil && zp->z_untiltime <= early_time) continue; gmtoff = zp->z_gmtoff; eat(zp->z_filename, zp->z_linenum); @@ -2670,7 +2815,7 @@ outzone(const struct zone * zpfirst, int zonecount) usestart = false; } else - addtt(big_bang_time, type); + addtt(early_time, type); } else for (year = min_year; year <= max_year; ++year) @@ -2695,7 +2840,7 @@ outzone(const struct zone * zpfirst, int zonecount) } for (;;) { - int k; + ptrdiff_t k; zic_t jtime, ktime = 0; zic_t offset; @@ -2792,6 +2937,10 @@ outzone(const struct zone * zpfirst, int zonecount) offset = oadd(zp->z_gmtoff, rp->r_stdoff); type = addtype(offset, ab, rp->r_stdoff != 0, rp->r_todisstd, rp->r_todisgmt); + if (rp->r_hiyear == ZIC_MAX + && !(0 <= lastatmax + && ktime < attypes[lastatmax].at)) + lastatmax = timecnt; addtt(ktime, type); } } @@ -2827,6 +2976,8 @@ outzone(const struct zone * zpfirst, int zonecount) starttime = tadd(starttime, -gmtoff); } } + if (0 <= lastatmax) + attypes[lastatmax].dontmerge = true; if (do_extend) { /* @@ -2850,22 +3001,8 @@ outzone(const struct zone * zpfirst, int zonecount) lastat = &attypes[i]; if (lastat->at < rpytime(&xr, max_year - 1)) { - /* - * Create new type code for the redundant entry, to prevent it - * being optimized away. - */ - if (typecnt >= TZ_MAX_TYPES) - { - error(_("too many local time types")); - exit(EXIT_FAILURE); - } - gmtoffs[typecnt] = gmtoffs[lastat->type]; - isdsts[typecnt] = isdsts[lastat->type]; - ttisstds[typecnt] = ttisstds[lastat->type]; - ttisgmts[typecnt] = ttisgmts[lastat->type]; - abbrinds[typecnt] = abbrinds[lastat->type]; - ++typecnt; addtt(rpytime(&xr, max_year + 1), typecnt - 1); + attypes[timecnt - 1].dontmerge = true; } } writezone(zpfirst->z_name, envvar, version); @@ -2877,8 +3014,8 @@ outzone(const struct zone * zpfirst, int zonecount) static void addtt(zic_t starttime, int type) { - if (starttime <= big_bang_time || - (timecnt == 1 && attypes[0].at < big_bang_time)) + if (starttime <= early_time + || (timecnt == 1 && attypes[0].at < early_time)) { gmtoffs[0] = gmtoffs[type]; isdsts[0] = isdsts[type]; @@ -2894,6 +3031,7 @@ addtt(zic_t starttime, int type) } attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc); attypes[timecnt].at = starttime; + attypes[timecnt].dontmerge = false; attypes[timecnt].type = type; ++timecnt; } @@ -2997,30 +3135,52 @@ adjleap(void) } } +static char * +shellquote(char *b, char const * s) +{ + *b++ = '\''; + while (*s) + { + if (*s == '\'') + *b++ = '\'', *b++ = '\\', *b++ = '\''; + *b++ = *s++; + } + *b++ = '\''; + return b; +} + static bool -yearistype(int year, const char *type) +yearistype(zic_t year, const char *type) { - static char *buf; + char *buf; + char *b; int result; if (type == NULL || *type == '\0') return true; - buf = erealloc(buf, 132 + strlen(yitcommand) + strlen(type)); - sprintf(buf, "%s %d %s", yitcommand, year, type); + buf = emalloc(1 + 4 * strlen(yitcommand) + 2 + + INT_STRLEN_MAXIMUM(zic_t) +2 + 4 * strlen(type) + 2); + b = shellquote(buf, yitcommand); + *b++ = ' '; + b += sprintf(b, INT64_FORMAT, year); + *b++ = ' '; + b = shellquote(b, type); + *b = '\0'; result = system(buf); if (WIFEXITED(result)) - switch (WEXITSTATUS(result)) + { + int status = WEXITSTATUS(result); + + if (status <= 1) { - case 0: - return true; - case 1: - return false; + free(buf); + return status == 0; } + } error(_("Wild result from command execution")); fprintf(stderr, _("%s: command was '%s', result was %d\n"), progname, buf, result); - for (;;) - exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } /* Is A a space character in the C locale? */ @@ -3254,7 +3414,7 @@ getfields(char *cp) else { error(_("Odd number of quotation marks")); - exit(1); + exit(EXIT_FAILURE); } } while (*cp && *cp != '#' && !is_space(*cp)); if (is_space(*cp)) @@ -3441,53 +3601,57 @@ newabbr(const char *string) charcnt += i; } -static bool -mkdirs(char *argname) +/* Ensure that the directories of ARGNAME exist, by making any missing + ones. If ANCESTORS, do this only for ARGNAME's ancestors; otherwise, + do it for ARGNAME too. Exit with failure if there is trouble. + Do not consider an existing non-directory to be trouble. */ +static void +mkdirs(char const * argname, bool ancestors) { char *name; char *cp; - if (argname == NULL || *argname == '\0') - return true; cp = name = ecpyalloc(argname); - while ((cp = strchr(cp + 1, '/')) != NULL) - { - *cp = '\0'; + + /* Do not mkdir a root directory, as it must exist. */ #ifdef WIN32 + if (is_alpha(name[0]) && name[1] == ':') + cp += 2; +#endif + while (*cp == '/') + cp++; - /* - * DOS drive specifier? - */ - if (is_alpha(name[0]) && name[1] == ':' && name[2] == '\0') - { - *cp = '/'; - continue; - } -#endif /* WIN32 */ + while (cp && ((cp = strchr(cp, '/')) || !ancestors)) + { + if (cp) + *cp = '\0'; /* * Try to create it. It's OK if creation fails because the directory * already exists, perhaps because some other process just created it. + * For simplicity do not check first whether it already exists, as + * that is checked anyway if the mkdir fails. */ if (mkdir(name, MKDIR_UMASK) != 0) { + /* + * For speed, skip itsdir if errno == EEXIST. Since mkdirs is + * called only after open fails with ENOENT on a subfile, EEXIST + * implies itsdir here. + */ int err = errno; - if (itsdir(name) <= 0) + if (err != EEXIST && !itsdir(name)) { - char const *e = strerror(err); - - warning(_("%s: Can't create directory" - " %s: %s"), - progname, name, e); - free(name); - return false; + error(_("%s: Cannot create directory %s: %s"), + progname, name, strerror(err)); + exit(EXIT_FAILURE); } } - *cp = '/'; + if (cp) + *cp++ = '/'; } free(name); - return true; } diff --git a/src/tools/RELEASE_CHANGES b/src/tools/RELEASE_CHANGES index ad49220592..45cd178ae7 100644 --- a/src/tools/RELEASE_CHANGES +++ b/src/tools/RELEASE_CHANGES @@ -11,7 +11,7 @@ For All Releases (major, minor, beta, RC) o run spellchecker on result o add SGML markup -* Update timezone data to match latest zic database and new +* Update timezone data to match latest IANA timezone database and new Windows releases, if any (see src/timezone/README) * Translation updates @@ -73,21 +73,12 @@ Starting a New Development Cycle for example, git push origin master:refs/heads/REL9_2_STABLE +* Add new branch's name to list in src/tools/git_changelog + * Increment the major version number in src/tools/version_stamp.pl * Run "src/tools/version_stamp.pl devel", then run autoconf -* Add version tag to src/tools/git_changelog - -* Bump minor library versions, major if appropriate (see below) - o Look for SO_MINOR_VERSION and MINOR_VERSION macros in - src/interfaces/ecpg/compatlib/Makefile - src/interfaces/ecpg/ecpglib/Makefile - src/interfaces/ecpg/pgtypeslib/Makefile - src/interfaces/ecpg/preproc/Makefile - src/interfaces/libpq/Makefile - src/tools/msvc/Mkvcbuild.pm - Creating Back-Branch Release Notes ================================== @@ -141,8 +132,7 @@ function which would give the new field a suitable default value. Adding a new function should NOT force an increase in the major version number. (Packagers will see the standard minor number update and install the new library.) When the major version is increased all applications -which link to the library MUST be recompiled - this is not desirable. When -the major version is updated the minor version gets reset. +which link to the library MUST be recompiled - this is not desirable. Minor Version ============= @@ -152,9 +142,19 @@ the library has changed, typically a change in source code between releases would mean an increase in the minor version number so long as it does not require a major version increase. -Given that we make at least minor changes to our libraries in every major -PostgreSQL version, we always bump all minor library version numbers at the -start of each development cycle as a matter of policy. +Given that we make at least some changes to our libraries in every major +PostgreSQL version, we always bump all minor library version numbers in +each development cycle as a matter of policy. This is currently mechanized +by referencing the MAJORVERSION make macro in the value of SO_MINOR_VERSION +for each shared library. As of v10, SO_MINOR_VERSION is simply equal to +MAJORVERSION in all cases. If we ever make an incompatible break in a +library's API, forcing a major version bump, we could continue to increase +SO_MINOR_VERSION (thus, perhaps, going from libpq.so.5.12 to libpq.so.6.13), +or we could reset SO_MINOR_VERSION to zero, using makefile code along the +lines of + SO_MINOR_VERSION= $(shell expr $(MAJORVERSION) - 13) +so that the number continues to increase automatically in later branches. +For now, that complication is not necessary. Minimizing Changes ================== diff --git a/src/tools/check_bison_recursion.pl b/src/tools/check_bison_recursion.pl index dd220d6b98..14590663c6 100755 --- a/src/tools/check_bison_recursion.pl +++ b/src/tools/check_bison_recursion.pl @@ -16,7 +16,7 @@ # To use: run bison with the -v switch, then feed the produced y.output # file to this script. # -# Copyright (c) 2011-2016, PostgreSQL Global Development Group +# Copyright (c) 2011-2017, PostgreSQL Global Development Group # # src/tools/check_bison_recursion.pl ################################################################# diff --git a/src/tools/copyright.pl b/src/tools/copyright.pl index aab162ed75..53942f12f0 100755 --- a/src/tools/copyright.pl +++ b/src/tools/copyright.pl @@ -2,7 +2,7 @@ ################################################################# # copyright.pl -- update copyright notices throughout the source tree, idempotently. # -# Copyright (c) 2011-2016, PostgreSQL Global Development Group +# Copyright (c) 2011-2017, PostgreSQL Global Development Group # # src/tools/copyright.pl # diff --git a/src/tools/find_typedef b/src/tools/find_typedef index fee0fb5152..24e9b76651 100755 --- a/src/tools/find_typedef +++ b/src/tools/find_typedef @@ -13,7 +13,7 @@ # find both .o files and executables. Therefore, ignore error messages about # unsuitable files being fed to objdump. # -# This is known to work on Linux and on some BSDen, including Mac OS X. +# This is known to work on Linux and on some BSDen, including macOS. # # Caution: on the platforms we use, this only prints typedefs that are used # to declare at least one variable or struct field. If you have say diff --git a/src/tools/findoidjoins/Makefile b/src/tools/findoidjoins/Makefile index b1785ced6b..e37b027dbd 100644 --- a/src/tools/findoidjoins/Makefile +++ b/src/tools/findoidjoins/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/tools/findoidjoins # -# Copyright (c) 2003-2016, PostgreSQL Global Development Group +# Copyright (c) 2003-2017, PostgreSQL Global Development Group # # src/tools/findoidjoins/Makefile # diff --git a/src/tools/findoidjoins/findoidjoins.c b/src/tools/findoidjoins/findoidjoins.c index 1e59772b1a..9fe0379f63 100644 --- a/src/tools/findoidjoins/findoidjoins.c +++ b/src/tools/findoidjoins/findoidjoins.c @@ -1,7 +1,7 @@ /* * findoidjoins.c * - * Copyright (c) 2002-2016, PostgreSQL Global Development Group + * Copyright (c) 2002-2017, PostgreSQL Global Development Group * * src/tools/findoidjoins/findoidjoins.c */ diff --git a/src/tools/git_changelog b/src/tools/git_changelog index c9a503f3fe..b9e631bb9c 100755 --- a/src/tools/git_changelog +++ b/src/tools/git_changelog @@ -57,7 +57,7 @@ require IPC::Open2; # (We could get this from "git branches", but not worth the trouble.) # NB: master must be first! my @BRANCHES = qw(master - REL9_5_STABLE + REL9_6_STABLE REL9_5_STABLE REL9_4_STABLE REL9_3_STABLE REL9_2_STABLE REL9_1_STABLE REL9_0_STABLE REL8_4_STABLE REL8_3_STABLE REL8_2_STABLE REL8_1_STABLE REL8_0_STABLE REL7_4_STABLE REL7_3_STABLE REL7_2_STABLE REL7_1_STABLE REL7_0_PATCHES diff --git a/src/tools/ifaddrs/Makefile b/src/tools/ifaddrs/Makefile index 231f388901..a5153207fe 100644 --- a/src/tools/ifaddrs/Makefile +++ b/src/tools/ifaddrs/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/tools/ifaddrs # -# Copyright (c) 2003-2016, PostgreSQL Global Development Group +# Copyright (c) 2003-2017, PostgreSQL Global Development Group # # src/tools/ifaddrs/Makefile # @@ -20,8 +20,8 @@ OBJS = test_ifaddrs.o all: test_ifaddrs -test_ifaddrs: test_ifaddrs.o $(libpq_backend_dir)/ip.o - $(CC) $(CFLAGS) test_ifaddrs.o $(libpq_backend_dir)/ip.o $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) +test_ifaddrs: test_ifaddrs.o $(libpq_backend_dir)/ifaddr.o + $(CC) $(CFLAGS) test_ifaddrs.o $(libpq_backend_dir)/ifaddr.o $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) clean distclean maintainer-clean: rm -f test_ifaddrs$(X) $(OBJS) diff --git a/src/tools/ifaddrs/test_ifaddrs.c b/src/tools/ifaddrs/test_ifaddrs.c index 48d184c84a..80b9bb0266 100644 --- a/src/tools/ifaddrs/test_ifaddrs.c +++ b/src/tools/ifaddrs/test_ifaddrs.c @@ -12,7 +12,7 @@ #include #include -#include "libpq/ip.h" +#include "libpq/ifaddr.h" static void diff --git a/src/tools/msvc/Install.pm b/src/tools/msvc/Install.pm index 52dde65a0e..e04efe6559 100644 --- a/src/tools/msvc/Install.pm +++ b/src/tools/msvc/Install.pm @@ -24,8 +24,8 @@ my @client_program_files = ( 'dropdb', 'droplang', 'dropuser', 'ecpg', 'libecpg', 'libecpg_compat', 'libpgtypes', 'libpq', 'pg_basebackup', 'pg_config', 'pg_dump', 'pg_dumpall', - 'pg_isready', 'pg_receivexlog', 'pg_restore', 'psql', - 'reindexdb', 'vacuumdb', @client_contribs); + 'pg_isready', 'pg_receivexlog', 'pg_recvlogical', 'pg_restore', + 'psql', 'reindexdb', 'vacuumdb', @client_contribs); sub lcopy { diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index fe905d3c9d..db566f9c88 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -50,7 +50,7 @@ my @contrib_excludes = ( # Set of variables for frontend modules my $frontend_defines = { 'initdb' => 'FRONTEND' }; -my @frontend_uselibpq = ('pg_ctl', 'pg_upgrade', 'pgbench', 'psql'); +my @frontend_uselibpq = ('pg_ctl', 'pg_upgrade', 'pgbench', 'psql', 'initdb'); my @frontend_uselibpgport = ( 'pg_archivecleanup', 'pg_test_fsync', 'pg_test_timing', 'pg_upgrade', @@ -91,8 +91,8 @@ sub mkvcbuild chklocale.c crypt.c fls.c fseeko.c getrusage.c inet_aton.c random.c srandom.c getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c - pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c pqsignal.c - mkdtemp.c qsort.c qsort_arg.c quotes.c system.c + pg_strong_random.c pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c + pqsignal.c mkdtemp.c qsort.c qsort_arg.c quotes.c system.c sprompt.c tar.c thread.c getopt.c getopt_long.c dirent.c win32env.c win32error.c win32security.c win32setlocale.c); @@ -110,12 +110,12 @@ sub mkvcbuild } our @pgcommonallfiles = qw( - config_info.c controldata_utils.c exec.c keywords.c - pg_lzcompress.c pgfnames.c psprintf.c relpath.c rmtree.c + config_info.c controldata_utils.c exec.c ip.c keywords.c + md5.c pg_lzcompress.c pgfnames.c psprintf.c relpath.c rmtree.c string.c username.c wait_error.c); our @pgcommonfrontendfiles = ( - @pgcommonallfiles, qw(fe_memutils.c + @pgcommonallfiles, qw(fe_memutils.c file_utils.c restricted_token.c)); our @pgcommonbkndfiles = @pgcommonallfiles; @@ -269,9 +269,6 @@ sub mkvcbuild $ecpg->AddIncludeDir('src/interfaces/libpq'); $ecpg->AddPrefixInclude('src/interfaces/ecpg/preproc'); $ecpg->AddFiles('src/interfaces/ecpg/preproc', 'pgc.l', 'preproc.y'); - $ecpg->AddDefine('MAJOR_VERSION=4'); - $ecpg->AddDefine('MINOR_VERSION=12'); - $ecpg->AddDefine('PATCHLEVEL=0'); $ecpg->AddDefine('ECPG_COMPILE'); $ecpg->AddReference($libpgcommon, $libpgport); @@ -384,18 +381,7 @@ sub mkvcbuild $zic->AddDirResourceFile('src/timezone'); $zic->AddReference($libpgcommon, $libpgport); - if ($solution->{options}->{xml}) - { - $contrib_extraincludes->{'pgxml'} = [ - $solution->{options}->{xml} . '/include', - $solution->{options}->{xslt} . '/include', - $solution->{options}->{iconv} . '/include' ]; - - $contrib_extralibs->{'pgxml'} = [ - $solution->{options}->{xml} . '/lib/libxml2.lib', - $solution->{options}->{xslt} . '/lib/libxslt.lib' ]; - } - else + if (!$solution->{options}->{xml}) { push @contrib_excludes, 'xml2'; } @@ -405,14 +391,7 @@ sub mkvcbuild push @contrib_excludes, 'sslinfo'; } - if ($solution->{options}->{uuid}) - { - $contrib_extraincludes->{'uuid-ossp'} = - [ $solution->{options}->{uuid} . '/include' ]; - $contrib_extralibs->{'uuid-ossp'} = - [ $solution->{options}->{uuid} . '/lib/uuid.lib' ]; - } - else + if (!$solution->{options}->{uuid}) { push @contrib_excludes, 'uuid-ossp'; } @@ -446,7 +425,6 @@ sub mkvcbuild 'sha1.c', 'sha2.c', 'internal.c', 'internal-sha2.c', 'blf.c', 'rijndael.c', - 'fortuna.c', 'random.c', 'pgp-mpi-internal.c', 'imath.c'); } $pgcrypto->AddReference($postgres); @@ -496,14 +474,16 @@ sub mkvcbuild $plpython->AddReference($postgres); # Add transform modules dependent on plpython - AddTransformModule( + my $hstore_plpython = AddTransformModule( 'hstore_plpython' . $pymajorver, 'contrib/hstore_plpython', 'plpython' . $pymajorver, 'src/pl/plpython', 'hstore', 'contrib/hstore'); - AddTransformModule( + $hstore_plpython->AddDefine('PLPYTHON_LIBNAME="plpython' . $pymajorver . '"'); + my $ltree_plpython = AddTransformModule( 'ltree_plpython' . $pymajorver, 'contrib/ltree_plpython', 'plpython' . $pymajorver, 'src/pl/plpython', 'ltree', 'contrib/ltree'); + $ltree_plpython->AddDefine('PLPYTHON_LIBNAME="plpython' . $pymajorver . '"'); } if ($solution->{options}->{perl}) @@ -578,16 +558,17 @@ sub mkvcbuild } } $plperl->AddReference($postgres); + my $perl_path = $solution->{options}->{perl} . '\lib\CORE\perl*.lib'; my @perl_libs = grep { /perl\d+.lib$/ } - glob($solution->{options}->{perl} . '\lib\CORE\perl*.lib'); + glob($perl_path); if (@perl_libs == 1) { $plperl->AddLibrary($perl_libs[0]); } else { - die "could not identify perl library version"; + die "could not identify perl library version matching pattern $perl_path\n"; } # Add transform module dependent on plperl diff --git a/src/tools/msvc/Project.pm b/src/tools/msvc/Project.pm index a4eb653c26..faf1a683f6 100644 --- a/src/tools/msvc/Project.pm +++ b/src/tools/msvc/Project.pm @@ -256,7 +256,7 @@ sub AddDir # Match rules that pull in source files from different directories, eg # pgstrcasecmp.c rint.c snprintf.c: % : $(top_srcdir)/src/port/% my $replace_re = - qr{^([^:\n\$]+\.c)\s*:\s*(?:%\s*: )?\$(\([^\)]+\))\/(.*)\/[^\/]+$}m; + qr{^([^:\n\$]+\.c)\s*:\s*(?:%\s*: )?\$(\([^\)]+\))\/(.*)\/[^\/]+\n}m; while ($mf =~ m{$replace_re}m) { my $match = $1; diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm index f07029bce1..fbf4da3d68 100644 --- a/src/tools/msvc/Solution.pm +++ b/src/tools/msvc/Solution.pm @@ -37,12 +37,9 @@ sub _new unless exists $options->{float8byval}; die "float8byval not permitted on 32 bit platforms" if $options->{float8byval} && $bits == 32; - if ($options->{xml}) + if ($options->{xslt} && !$options->{xml}) { - if (!($options->{xslt} && $options->{iconv})) - { - die "XML requires both XSLT and ICONV\n"; - } + die "XSLT requires XML\n"; } $options->{blocksize} = 8 unless $options->{blocksize}; # undef or 0 means default @@ -131,12 +128,12 @@ sub GenerateFiles if (/^AC_INIT\(\[PostgreSQL\], \[([^\]]+)\]/) { $self->{strver} = $1; - if ($self->{strver} !~ /^(\d+)\.(\d+)(?:\.(\d+))?/) + if ($self->{strver} !~ /^(\d+)(?:\.(\d+))?/) { confess "Bad format of version: $self->{strver}\n"; } - $self->{numver} = sprintf("%d%02d%02d", $1, $2, $3 ? $3 : 0); - $self->{majorver} = sprintf("%d.%d", $1, $2); + $self->{numver} = sprintf("%d%04d", $1, $2 ? $2 : 0); + $self->{majorver} = sprintf("%d", $1); } } close(C); @@ -271,7 +268,7 @@ s{PG_VERSION_STR "[^"]+"}{__STRINGIFY(x) #x\n#define __STRINGIFY2(z) __STRINGIFY if (IsNewer( 'src/backend/utils/fmgrtab.c', 'src/include/catalog/pg_proc.h')) { - print "Generating fmgrtab.c and fmgroids.h...\n"; + print "Generating fmgrtab.c, fmgroids.h, fmgrprotos.h...\n"; chdir('src/backend/utils'); system( "perl -I ../catalog Gen_fmgrtab.pl ../../../src/include/catalog/pg_proc.h"); @@ -285,6 +282,14 @@ s{PG_VERSION_STR "[^"]+"}{__STRINGIFY(x) #x\n#define __STRINGIFY2(z) __STRINGIFY 'src/include/utils/fmgroids.h'); } + if (IsNewer( + 'src/include/utils/fmgrprotos.h', + 'src/backend/utils/fmgrprotos.h')) + { + copyFile('src/backend/utils/fmgrprotos.h', + 'src/include/utils/fmgrprotos.h'); + } + if (IsNewer( 'src/include/storage/lwlocknames.h', 'src/backend/storage/lmgr/lwlocknames.txt')) @@ -555,6 +560,11 @@ sub AddProject $proj->AddIncludeDir($self->{options}->{xslt} . '\include'); $proj->AddLibrary($self->{options}->{xslt} . '\lib\libxslt.lib'); } + if ($self->{options}->{uuid}) + { + $proj->AddIncludeDir($self->{options}->{uuid} . '\include'); + $proj->AddLibrary($self->{options}->{uuid} . '\lib\uuid.lib'); + } return $proj; } diff --git a/src/tools/msvc/build.pl b/src/tools/msvc/build.pl index 007e3c73b2..2e7c54853a 100644 --- a/src/tools/msvc/build.pl +++ b/src/tools/msvc/build.pl @@ -2,6 +2,8 @@ # src/tools/msvc/build.pl +use strict; + BEGIN { @@ -38,6 +40,7 @@ BEGIN # check what sort of build we are doing my $bconf = $ENV{CONFIG} || "Release"; +my $msbflags = $ENV{MSBFLAGS} || ""; my $buildwhat = $ARGV[1] || ""; if (uc($ARGV[0]) eq 'DEBUG') { @@ -53,20 +56,20 @@ BEGIN if ($buildwhat and $vcver >= 10.00) { system( - "msbuild $buildwhat.vcxproj /verbosity:normal /p:Configuration=$bconf" + "msbuild $buildwhat.vcxproj /verbosity:normal $msbflags /p:Configuration=$bconf" ); } elsif ($buildwhat) { - system("vcbuild $buildwhat.vcproj $bconf"); + system("vcbuild $msbflags $buildwhat.vcproj $bconf"); } else { - system("msbuild pgsql.sln /verbosity:normal /p:Configuration=$bconf"); + system("msbuild pgsql.sln /verbosity:normal $msbflags /p:Configuration=$bconf"); } # report status -$status = $? >> 8; +my $status = $? >> 8; exit $status; diff --git a/src/tools/msvc/clean.bat b/src/tools/msvc/clean.bat index 469b8a24b2..ab51284e64 100755 --- a/src/tools/msvc/clean.bat +++ b/src/tools/msvc/clean.bat @@ -42,9 +42,11 @@ if exist src\include\dynloader.h del /q src\include\dynloader.h if %DIST%==1 if exist src\backend\parser\gram.h del /q src\backend\parser\gram.h if exist src\include\utils\errcodes.h del /q src\include\utils\errcodes.h if exist src\include\utils\fmgroids.h del /q src\include\utils\fmgroids.h +if exist src\include\utils\fmgrprotos.h del /q src\include\utils\fmgrprotos.h if exist src\include\utils\probes.h del /q src\include\utils\probes.h if %DIST%==1 if exist src\backend\utils\fmgroids.h del /q src\backend\utils\fmgroids.h +if %DIST%==1 if exist src\backend\utils\fmgrprotos.h del /q src\backend\utils\fmgrprotos.h if %DIST%==1 if exist src\backend\utils\fmgrtab.c del /q src\backend\utils\fmgrtab.c if %DIST%==1 if exist src\backend\catalog\postgres.bki del /q src\backend\catalog\postgres.bki if %DIST%==1 if exist src\backend\catalog\postgres.description del /q src\backend\catalog\postgres.description @@ -107,6 +109,6 @@ REM for /r %%f in (*.sql) do if exist %%f.in del %%f cd %D% REM Clean up ecpg regression test files -msbuild /NoLogo ecpg_regression.proj /t:clean /v:q +msbuild ecpg_regression.proj /NoLogo /v:q %MSBFLAGS% /t:clean goto :eof diff --git a/src/tools/msvc/gendef.pl b/src/tools/msvc/gendef.pl index 8ccaab3551..3bcff7ffaf 100644 --- a/src/tools/msvc/gendef.pl +++ b/src/tools/msvc/gendef.pl @@ -1,10 +1,11 @@ -my @def; - -use warnings; use strict; +use warnings; use 5.8.0; +use File::Spec::Functions qw(splitpath catpath); use List::Util qw(max); +my @def; + # # Script that generates a .DEF file for all objects in a directory # @@ -14,9 +15,11 @@ sub dumpsyms { my ($objfile, $symfile) = @_; - system("dumpbin /symbols /out:symbols.out $_ >NUL") + my ($symvol, $symdirs, $symbase) = splitpath($symfile); + my $tmpfile = catpath($symvol, $symdirs, "symbols.out"); + system("dumpbin /symbols /out:$tmpfile $_ >NUL") && die "Could not call dumpbin"; - rename("symbols.out", $symfile); + rename($tmpfile, $symfile); } # Given a symbol file path, loops over its contents diff --git a/src/tools/msvc/pgflex.pl b/src/tools/msvc/pgflex.pl index 474ce63e5c..3a42add0d2 100644 --- a/src/tools/msvc/pgflex.pl +++ b/src/tools/msvc/pgflex.pl @@ -2,12 +2,12 @@ # src/tools/msvc/pgflex.pl -# silence flex bleatings about file path style -$ENV{CYGWIN} = 'nodosfilewarning'; - use strict; use File::Basename; +# silence flex bleatings about file path style +$ENV{CYGWIN} = 'nodosfilewarning'; + # assume we are in the postgres source root require 'src/tools/msvc/buildenv.pl' if -e 'src/tools/msvc/buildenv.pl'; diff --git a/src/tools/msvc/vcregress.pl b/src/tools/msvc/vcregress.pl index b4f946474f..f1b9819cd2 100644 --- a/src/tools/msvc/vcregress.pl +++ b/src/tools/msvc/vcregress.pl @@ -138,8 +138,9 @@ sub check sub ecpgcheck { + my $msbflags = $ENV{MSBFLAGS} || ""; chdir $startdir; - system("msbuild ecpg_regression.proj /p:config=$Config"); + system("msbuild ecpg_regression.proj $msbflags /p:config=$Config"); my $status = $? >> 8; exit $status if $status; InstallTemp(); @@ -447,7 +448,7 @@ sub upgradecheck print "\nRunning initdb on old cluster\n\n"; standard_initdb() or exit 1; print "\nStarting old cluster\n\n"; - my @args = ('pg_ctl', 'start', '-l', "$logdir/postmaster1.log", '-w'); + my @args = ('pg_ctl', 'start', '-l', "$logdir/postmaster1.log"); system(@args) == 0 or exit 1; print "\nCreating databases with names covering most ASCII bytes\n\n"; @@ -464,7 +465,7 @@ sub upgradecheck @args = ('pg_dumpall', '-f', "$tmp_root/dump1.sql"); system(@args) == 0 or exit 1; print "\nStopping old cluster\n\n"; - system("pg_ctl -m fast stop") == 0 or exit 1; + system("pg_ctl stop") == 0 or exit 1; $ENV{PGDATA} = "$data"; print "\nSetting up new cluster\n\n"; standard_initdb() or exit 1; @@ -474,7 +475,7 @@ sub upgradecheck $bindir, '-B', $bindir); system(@args) == 0 or exit 1; print "\nStarting new cluster\n\n"; - @args = ('pg_ctl', '-l', "$logdir/postmaster2.log", '-w', 'start'); + @args = ('pg_ctl', '-l', "$logdir/postmaster2.log", 'start'); system(@args) == 0 or exit 1; print "\nSetting up stats on new cluster\n\n"; system(".\\analyze_new_cluster.bat") == 0 or exit 1; @@ -482,7 +483,7 @@ sub upgradecheck @args = ('pg_dumpall', '-f', "$tmp_root/dump2.sql"); system(@args) == 0 or exit 1; print "\nStopping new cluster\n\n"; - system("pg_ctl -m fast stop") == 0 or exit 1; + system("pg_ctl stop") == 0 or exit 1; print "\nDeleting old cluster\n\n"; system(".\\delete_old_cluster.bat") == 0 or exit 1; print "\nComparing old and new cluster dumps\n\n"; diff --git a/src/tools/pginclude/pgcheckdefines b/src/tools/pginclude/pgcheckdefines index 5db507070f..e166efa08d 100755 --- a/src/tools/pginclude/pgcheckdefines +++ b/src/tools/pginclude/pgcheckdefines @@ -20,14 +20,16 @@ # src/tools/pginclude/pgcheckdefines # +use strict; + use Cwd; use File::Basename; -$topdir = cwd(); +my $topdir = cwd(); # Programs to use -$FIND = "find"; -$MAKE = "make"; +my $FIND = "find"; +my $MAKE = "make"; # # Build arrays of all the .c and .h files in the tree @@ -38,6 +40,8 @@ $MAKE = "make"; # Including these .h files would clutter the list of define'd symbols and # cause a lot of false-positive results. # +my (@cfiles, @hfiles); + open PIPE, "$FIND * -type f -name '*.c' |" or die "can't fork: $!"; while () @@ -63,7 +67,9 @@ close PIPE or die "$FIND failed: $!"; # a hash table. To cover the possibility of multiple .h files defining # the same symbol, we make each hash entry a hash of filenames. # -foreach $hfile (@hfiles) +my %defines; + +foreach my $hfile (@hfiles) { open HFILE, $hfile or die "can't open $hfile: $!"; @@ -82,9 +88,9 @@ foreach $hfile (@hfiles) # files it #include's. Then extract all the symbols it tests for defined-ness, # and check each one against the previously built hashtable. # -foreach $file (@hfiles, @cfiles) +foreach my $file (@hfiles, @cfiles) { - ($fname, $fpath) = fileparse($file); + my ($fname, $fpath) = fileparse($file); chdir $fpath or die "can't chdir to $fpath: $!"; # @@ -96,16 +102,18 @@ foreach $file (@hfiles, @cfiles) # hence printing multiple definitions --- we keep the last one, which # should come from the current Makefile. # + my $MAKECMD; + if (-f "Makefile" || -f "GNUmakefile") { $MAKECMD = "$MAKE -qp"; } else { - $subdir = $fpath; + my $subdir = $fpath; chop $subdir; - $top_builddir = ".."; - $tmp = $fpath; + my $top_builddir = ".."; + my $tmp = $fpath; while (($tmp = dirname($tmp)) ne '.') { $top_builddir = $top_builddir . "/.."; @@ -113,6 +121,9 @@ foreach $file (@hfiles, @cfiles) $MAKECMD = "$MAKE -qp 'subdir=$subdir' 'top_builddir=$top_builddir' -f '$top_builddir/src/Makefile.global'"; } + + my ($CPPFLAGS, $CFLAGS, $CFLAGS_SL, $PTHREAD_CFLAGS, $CC); + open PIPE, "$MAKECMD |" or die "can't fork: $!"; while () @@ -153,15 +164,15 @@ foreach $file (@hfiles, @cfiles) # "gcc -H" reports inclusions on stderr as "... filename" where the # number of dots varies according to nesting depth. # - @includes = (); - $COMPILE = "$CC $CPPFLAGS $CFLAGS -H -E $fname"; + my @includes = (); + my $COMPILE = "$CC $CPPFLAGS $CFLAGS -H -E $fname"; open PIPE, "$COMPILE 2>&1 >/dev/null |" or die "can't fork: $!"; while () { if (m/^\.+ (.*)/) { - $include = $1; + my $include = $1; # Ignore system headers (absolute paths); but complain if a # .c file includes a system header before any PG header. @@ -176,7 +187,7 @@ foreach $file (@hfiles, @cfiles) $include =~ s|^\./||; # Make path relative to top of tree - $ipath = $fpath; + my $ipath = $fpath; while ($include =~ s|^\.\./||) { $ipath = dirname($ipath) . "/"; @@ -202,19 +213,17 @@ foreach $file (@hfiles, @cfiles) # open FILE, $fname or die "can't open $file: $!"; - $inif = 0; + my $inif = 0; while () { - $line = $_; + my $line = $_; if ($line =~ m/^\s*#\s*ifdef\s+(\w+)/) { - $symbol = $1; - &checkit; + checkit($file, $1, @includes); } if ($line =~ m/^\s*#\s*ifndef\s+(\w+)/) { - $symbol = $1; - &checkit; + checkit($file, $1, @includes); } if ($line =~ m/^\s*#\s*if\s+/) { @@ -224,8 +233,7 @@ foreach $file (@hfiles, @cfiles) { while ($line =~ s/\bdefined(\s+|\s*\(\s*)(\w+)//) { - $symbol = $2; - &checkit; + checkit($file, $2, @includes); } if (!($line =~ m/\\$/)) { @@ -243,6 +251,7 @@ exit 0; # Check an is-defined reference sub checkit { + my ($file, $symbol, @includes) = @_; # Ignore if symbol isn't defined in any PG include files if (!defined $defines{$symbol}) @@ -258,10 +267,10 @@ sub checkit # occur after the use of the symbol. Given our normal file layout, # however, the risk is minimal. # - foreach $deffile (keys %{ $defines{$symbol} }) + foreach my $deffile (keys %{ $defines{$symbol} }) { return if $deffile eq $file; - foreach $reffile (@includes) + foreach my $reffile (@includes) { return if $deffile eq $reffile; } @@ -273,7 +282,7 @@ sub checkit # if ($file =~ m/\.h$/) { - foreach $deffile (keys %{ $defines{$symbol} }) + foreach my $deffile (keys %{ $defines{$symbol} }) { return if $deffile eq 'src/include/c.h'; return if $deffile eq 'src/include/postgres.h'; @@ -284,7 +293,7 @@ sub checkit } # - @places = keys %{ $defines{$symbol} }; + my @places = keys %{ $defines{$symbol} }; print "$file references $symbol, defined in @places\n"; # print "includes: @includes\n"; diff --git a/src/tools/pgindent/pgindent b/src/tools/pgindent/pgindent index 0d3859d029..befb5cdb39 100755 --- a/src/tools/pgindent/pgindent +++ b/src/tools/pgindent/pgindent @@ -463,7 +463,7 @@ sub run_build $ENV{PGTYPEDEFS} = abs_path('tmp_typedefs.list'); my $pg_bsd_indent_url = - "ftp://ftp.postgresql.org/pub/dev/pg_bsd_indent-" + "https://ftp.postgresql.org/pub/dev/pg_bsd_indent-" . $INDENT_VERSION . ".tar.gz"; diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index dff6f65ef0..993880da43 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -1,7 +1,6 @@ ABITVEC ACCESS_ALLOWED_ACE ACL_SIZE_INFORMATION -AES_KEY AFFIX ASN1_INTEGER ASN1_OBJECT @@ -37,14 +36,12 @@ AfterTriggerSharedData AfterTriggersData Agg AggClauseCosts -AggHashEntry AggInfo AggPath AggSplit AggState AggStatePerAgg AggStatePerGroup -AggStatePerGroupData AggStatePerPhase AggStatePerTrans AggStrategy @@ -139,7 +136,6 @@ AuthRequest AutoVacOpts AutoVacuumShmemStruct AuxProcType -BF_KEY BF_ctx BF_key BF_word @@ -263,7 +259,6 @@ BuiltinScript BulkInsertState CACHESIGN CAC_state -CAST_KEY CEOUC_WAIT_MODE CFuncHashTabEntry CHAR @@ -354,12 +349,14 @@ CompositeTypeStmt CompoundAffixFlag CompressionAlgorithm CompressorState +ConditionVariable ConfigData ConfigVariable ConnCacheEntry ConnCacheKey ConnStatusType ConnType +ConnectionStateEnum ConsiderSplitContext Const ConstrCheck @@ -434,8 +431,6 @@ DBState DCHCacheEntry DEADLOCK_INFO DECountItem -DES_cblock -DES_key_schedule DH DIR DNSServiceErrorType @@ -473,6 +468,8 @@ DictSnowball DictSubState DictSyn DictThesaurus +DirectoryMethodData +DirectoryMethodFile DisableTimeoutParams DiscardMode DiscardStmt @@ -508,6 +505,8 @@ EOM_get_flat_size_method EPQState EPlan EState +EVP_CIPHER +EVP_CIPHER_CTX EVP_MD EVP_MD_CTX EVP_PKEY @@ -588,7 +587,6 @@ FILETIME FSMAddress FSMPage FSMPageData -FState FakeRelCacheEntry FakeRelCacheEntryData FastPathStrongRelationLockData @@ -654,6 +652,7 @@ FormData_pg_namespace FormData_pg_opclass FormData_pg_operator FormData_pg_opfamily +FormData_pg_partitioned_table FormData_pg_pltemplate FormData_pg_policy FormData_pg_proc @@ -704,6 +703,7 @@ Form_pg_namespace Form_pg_opclass Form_pg_operator Form_pg_opfamily +Form_pg_partitioned_table Form_pg_pltemplate Form_pg_policy Form_pg_proc @@ -726,6 +726,13 @@ Form_pg_user_mapping FormatNode FreeBlockNumberArray FreeListData +FreePageBtree +FreePageBtreeHeader +FreePageBtreeInternalKey +FreePageBtreeLeafKey +FreePageBtreeSearchResult +FreePageManager +FreePageSpanLeader FromCharDateMode FromExpr FuncCall @@ -854,6 +861,7 @@ HASHELEMENT HASHHDR HASHSEGMENT HASH_SEQ_STATUS +HCRYPTPROV HE HEntry HIST_ENTRY @@ -884,8 +892,6 @@ HashMetaPageData HashPageOpaque HashPageOpaqueData HashPath -HashScanList -HashScanListData HashScanOpaque HashScanOpaqueData HashSkewBucket @@ -971,6 +977,7 @@ Interval IntoClause InvalidationChunk InvalidationListHeader +InvertedWalkNextStep IpcMemoryId IpcMemoryKey IpcSemaphoreId @@ -981,8 +988,6 @@ IspellDict Item ItemId ItemIdData -ItemLength -ItemOffset ItemPointer ItemPointerData IterateDirectModify_function @@ -1124,8 +1129,6 @@ MEMORY_BASIC_INFORMATION MINIDUMPWRITEDUMP MINIDUMP_TYPE MJEvalResult -MasterEndParallelItemPtr -MasterStartParallelItemPtr Material MaterialPath MaterialState @@ -1199,12 +1202,14 @@ Numeric NumericAggState NumericDigit NumericSortSupport +NumericSumAccum NumericVar OM_uint32 OP OSAPerGroupState OSAPerQueryState OSInfo +OSSLCipher OSSLDigest OSVERSIONINFO OVERLAPPED @@ -1320,6 +1325,7 @@ PLpgSQL_arrayelem PLpgSQL_case_when PLpgSQL_condition PLpgSQL_datum +PLpgSQL_datum_type PLpgSQL_diag_item PLpgSQL_exception PLpgSQL_exception_block @@ -1327,10 +1333,14 @@ PLpgSQL_execstate PLpgSQL_expr PLpgSQL_func_hashkey PLpgSQL_function +PLpgSQL_getdiag_kind PLpgSQL_if_elsif +PLpgSQL_label_type PLpgSQL_nsitem +PLpgSQL_nsitem_type PLpgSQL_plugin PLpgSQL_raise_option +PLpgSQL_raise_option_type PLpgSQL_rec PLpgSQL_recfield PLpgSQL_resolve_option @@ -1360,9 +1370,11 @@ PLpgSQL_stmt_raise PLpgSQL_stmt_return PLpgSQL_stmt_return_next PLpgSQL_stmt_return_query +PLpgSQL_stmt_type PLpgSQL_stmt_while PLpgSQL_trigtype PLpgSQL_type +PLpgSQL_type_type PLpgSQL_var PLpgSQL_variable PLwdatum @@ -1375,6 +1387,7 @@ PLyExecutionContext PLyObToDatum PLyObToDatumFunc PLyObToTuple +PLyObject_AsString_t PLyPlanObject PLyProcedure PLyProcedureEntry @@ -1388,6 +1401,7 @@ PLyTupleToOb PLyTypeInfo PLyTypeInput PLyTypeOutput +PLyUnicode_FromStringAndSize_t PMINIDUMP_CALLBACK_INFORMATION PMINIDUMP_EXCEPTION_INFORMATION PMINIDUMP_USER_STREAM_INFORMATION @@ -1421,6 +1435,7 @@ PSQL_ECHO_HIDDEN PSQL_ERROR_ROLLBACK PTOKEN_GROUPS PTOKEN_USER +PUTENVPROC PVOID PX_Alias PX_Cipher @@ -1435,7 +1450,7 @@ PageHeaderData PageXLogRecPtr PagetableEntry Pairs -ParallelArgs +ParallelCompletionPtr ParallelContext ParallelExecutorInfo ParallelHeapScanDesc @@ -1462,6 +1477,21 @@ ParsedText ParsedWord ParserSetupHook ParserState +PartInfo +PartitionBoundInfo +PartitionBoundInfoData +PartitionBoundSpec +PartitionCmd +PartitionDesc +PartitionDescData +PartitionDispatch +PartitionDispatchData +PartitionElem +PartitionKey +PartitionListValue +PartitionRangeBound +PartitionRangeDatum +PartitionSpec Path PathClauseUsage PathCostComparison @@ -1639,6 +1669,7 @@ QueuePosition RBNode RBOrderControl RBTree +RBTreeIterator REPARSE_JUNCTION_DATA_BUFFER RIX RI_CompareHashEntry @@ -1646,13 +1677,13 @@ RI_CompareKey RI_ConstraintInfo RI_QueryHashEntry RI_QueryKey -RSA RTEKind RWConflict RWConflictPoolHeader Range RangeBound RangeBox +RangeDatumContent RangeFunction RangeIOData RangeQueryClause @@ -1715,6 +1746,9 @@ RelfilenodeMapEntry RelfilenodeMapKey Relids RelocationBufferInfo +RelptrFreePageBtree +RelptrFreePageManager +RelptrFreePageSpanLeader RenameStmt ReopenPtr ReorderBuffer @@ -1822,6 +1856,8 @@ SQLDropObject SQLFunctionCache SQLFunctionCachePtr SQLFunctionParseInfoPtr +SQLValueFunction +SQLValueFunctionOp SSL SSLExtensionInfoContext SSL_CTX @@ -1865,11 +1901,9 @@ SetConstraintTriggerData SetFunctionReturnMode SetOp SetOpCmd -SetOpHashEntry SetOpPath SetOpState SetOpStatePerGroup -SetOpStatePerGroupData SetOpStrategy SetOperation SetOperationStmt @@ -1902,6 +1936,7 @@ SimpleStringList SimpleStringListCell SingleBoundSortItem Size +SlabSlot SlotNumber SlruCtl SlruCtlData @@ -2049,6 +2084,8 @@ TableSpaceCacheEntry TableSpaceOpts TablespaceList TablespaceListCell +TarMethodData +TarMethodFile TargetEntry TclExceptionNameMap Tcl_DString @@ -2115,6 +2152,7 @@ TriggerDesc TriggerEvent TriggerFlags TriggerInfo +TriggerTransition TruncateStmt TsmRoutine TupOutputState @@ -2207,6 +2245,7 @@ WALInsertLock WALInsertLockPadded WCHAR WCOKind +WFW_WaitOption WIDGET WIN32_FILE_ATTRIBUTE_DATA WORD @@ -2216,14 +2255,23 @@ WSADATA WSANETWORKEVENTS WSAPROTOCOL_INFO WaitEvent +WaitEventActivity +WaitEventClient +WaitEventIPC WaitEventSet +WaitEventTimeout +WalCloseMethod WalLevel WalRcvData WalRcvState +WalReceiverConn +WalReceiverFunctionsType WalSnd WalSndCtlData WalSndSendDataCallback WalSndState +WalWriteMethod +Walfile WholeRowVarExprState WindowAgg WindowAggPath @@ -2358,7 +2406,6 @@ brin_column_state bytea cached_re_str cashKEY -celt cfp check_agg_arguments_context check_function_callback @@ -2375,6 +2422,7 @@ codes_t coercion collation_cache_entry color +colormaprange config_var_value contain_aggs_of_level_context convert_testexpr_context @@ -2406,6 +2454,15 @@ dlist_iter dlist_mutable_iter dlist_node ds_state +dsa_area +dsa_area_control +dsa_area_pool +dsa_area_span +dsa_handle +dsa_pointer +dsa_segment_header +dsa_segment_index +dsa_segment_map dsm_control_header dsm_control_item dsm_handle @@ -2491,12 +2548,16 @@ gss_ctx_id_t gss_name_t gtrgm_consistent_cache gzFile -has_parallel_hazard_arg hashfunc hbaPort heap_page_items_state help_handler hlCheck +hstoreCheckKeyLen_t +hstoreCheckValLen_t +hstorePairs_t +hstoreUniquePairs_t +hstoreUpgrade_t hyperLogLogState import_error_callback_arg indexed_tlist @@ -2535,6 +2596,7 @@ lclContext lclTocEntry leafSegmentInfo line_t +lineno_t locale_t locate_agg_of_level_context locate_var_of_level_context @@ -2551,6 +2613,7 @@ mXactCacheEnt macKEY macaddr map_variable_attnos_context +max_parallel_hazard_context mb2wchar_with_len_converter mbcharacter_incrementer mbdisplaylen_converter @@ -2582,19 +2645,23 @@ oidKEY oidvector on_dsm_detach_callback on_exit_nicely_callback +ossl_EVP_cipher_func ossldata output_type +pagetable_hash +pagetable_iterator pairingheap pairingheap_comparator pairingheap_node parallel_worker_main_type parse_error_callback_arg -pcolor pendingPosition pgParameterStatus pg_atomic_flag pg_atomic_uint32 pg_atomic_uint64 +pg_conn_host +pg_conn_host_type pg_conv_map pg_crc32 pg_crc32c @@ -2648,6 +2715,7 @@ plperl_query_entry plpgsql_CastHashEntry plpgsql_CastHashKey plpgsql_HashEnt +pltcl_call_state pltcl_interp_desc pltcl_proc_desc pltcl_proc_key @@ -2668,12 +2736,16 @@ printTextRule priv_map process_file_callback_t process_sublinks_context +proclist_head +proclist_mutable_iter +proclist_node promptStatus_t pthread_attr_t pthread_key_t pthread_mutex_t pthread_once_t pthread_t +ptrdiff_t pull_var_clause_context pull_varattnos_context pull_varnos_context @@ -2721,6 +2793,7 @@ role_auth_extra row_security_policy_hook_type save_buffer security_barrier_replace_vars_context +sem_t sequence_magic set_join_pathlist_hook_type set_rel_pathlist_hook_type @@ -2807,6 +2880,8 @@ tsKEY ts_db_fctx ts_tokentype tsearch_readline_state +tuplehash_hash +tuplehash_iterator txid tzEntry u1byte @@ -2832,6 +2907,7 @@ unicode_linestyle unit_conversion unlogged_relation_entry utf_local_conversion_func +uuidKEY uuid_rc_t uuid_sortsupport_state uuid_t @@ -2844,15 +2920,15 @@ varattrib_1b varattrib_1b_e varattrib_4b vbits -walrcv_connect_type -walrcv_disconnect_type -walrcv_endstreaming_type -walrcv_get_conninfo_type -walrcv_identify_system_type -walrcv_readtimelinehistoryfile_type -walrcv_receive_type -walrcv_send_type -walrcv_startstreaming_type +walrcv_connect_fn +walrcv_disconnect_fn +walrcv_endstreaming_fn +walrcv_get_conninfo_fn +walrcv_identify_system_fn +walrcv_readtimelinehistoryfile_fn +walrcv_receive_fn +walrcv_send_fn +walrcv_startstreaming_fn wchar2mb_with_len_converter wchar_t win32_deadchild_waitinfo diff --git a/src/tools/version_stamp.pl b/src/tools/version_stamp.pl index cc685453dd..dc9173f234 100755 --- a/src/tools/version_stamp.pl +++ b/src/tools/version_stamp.pl @@ -3,7 +3,7 @@ ################################################################# # version_stamp.pl -- update version stamps throughout the source tree # -# Copyright (c) 2008-2016, PostgreSQL Global Development Group +# Copyright (c) 2008-2017, PostgreSQL Global Development Group # # src/tools/version_stamp.pl ################################################################# @@ -20,15 +20,18 @@ # "devel", "alphaN", "betaN", "rcN". # +use strict; + # Major version is hard-wired into the script. We update it when we branch # a new development version. -$major1 = 9; -$major2 = 6; +my $majorversion = 10; # Validate argument and compute derived variables -$minor = shift; +my $minor = shift; defined($minor) || die "$0: missing required argument: minor-version\n"; +my ($dotneeded, $numericminor); + if ($minor =~ m/^\d+$/) { $dotneeded = 1; @@ -59,8 +62,9 @@ die "$0: minor-version must be N, devel, alphaN, betaN, or rcN\n"; } +my $fullversion; + # Create various required forms of the version number -$majorversion = $major1 . "." . $major2; if ($dotneeded) { $fullversion = $majorversion . "." . $minor; @@ -69,13 +73,13 @@ { $fullversion = $majorversion . $minor; } -$numericversion = $majorversion . "." . $numericminor; -$padnumericversion = sprintf("%d%02d%02d", $major1, $major2, $numericminor); +my $numericversion = $majorversion . "." . $numericminor; +my $padnumericversion = sprintf("%d%04d", $majorversion, $numericminor); # Get the autoconf version number for eventual nag message # (this also ensures we're in the right directory) -$aconfver = ""; +my $aconfver = ""; open(FILE, "configure.in") || die "could not read configure.in: $!\n"; while () { @@ -92,7 +96,7 @@ # Update configure.in and other files that contain version numbers -$fixedfiles = ""; +my $fixedfiles = ""; sed_file("configure.in", "-e 's/AC_INIT(\\[PostgreSQL\\], \\[[0-9a-z.]*\\]/AC_INIT([PostgreSQL], [$fullversion]/'" @@ -110,15 +114,15 @@ ); sed_file("src/interfaces/libpq/libpq.rc.in", -"-e 's/FILEVERSION [0-9]*,[0-9]*,[0-9]*,0/FILEVERSION $major1,$major2,$numericminor,0/' " - . "-e 's/PRODUCTVERSION [0-9]*,[0-9]*,[0-9]*,0/PRODUCTVERSION $major1,$major2,$numericminor,0/' " +"-e 's/FILEVERSION [0-9]*,[0-9]*,[0-9]*,0/FILEVERSION $majorversion,0,$numericminor,0/' " + . "-e 's/PRODUCTVERSION [0-9]*,[0-9]*,[0-9]*,0/PRODUCTVERSION $majorversion,0,$numericminor,0/' " . "-e 's/VALUE \"FileVersion\", \"[0-9.]*/VALUE \"FileVersion\", \"$numericversion/' " . "-e 's/VALUE \"ProductVersion\", \"[0-9.]*/VALUE \"ProductVersion\", \"$numericversion/'" ); sed_file("src/port/win32ver.rc", -"-e 's/FILEVERSION [0-9]*,[0-9]*,[0-9]*,0/FILEVERSION $major1,$major2,$numericminor,0/' " - . "-e 's/PRODUCTVERSION [0-9]*,[0-9]*,[0-9]*,0/PRODUCTVERSION $major1,$major2,$numericminor,0/'" +"-e 's/FILEVERSION [0-9]*,[0-9]*,[0-9]*,0/FILEVERSION $majorversion,0,$numericminor,0/' " + . "-e 's/PRODUCTVERSION [0-9]*,[0-9]*,[0-9]*,0/PRODUCTVERSION $majorversion,0,$numericminor,0/'" ); print "Stamped these files with version number $fullversion:\n$fixedfiles"; diff --git a/src/tools/win32tzlist.pl b/src/tools/win32tzlist.pl index 3976205446..6345465b19 100755 --- a/src/tools/win32tzlist.pl +++ b/src/tools/win32tzlist.pl @@ -2,7 +2,7 @@ # # win32tzlist.pl -- compare Windows timezone information # -# Copyright (c) 2008-2016, PostgreSQL Global Development Group +# Copyright (c) 2008-2017, PostgreSQL Global Development Group # # src/tools/win32tzlist.pl ################################################################# diff --git a/src/tutorial/complex.source b/src/tutorial/complex.source index 1d910b8b45..035c7a7d13 100644 --- a/src/tutorial/complex.source +++ b/src/tutorial/complex.source @@ -5,7 +5,7 @@ -- use this new type. -- -- --- Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +-- Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group -- Portions Copyright (c) 1994, Regents of the University of California -- -- src/tutorial/complex.source diff --git a/src/tutorial/syscat.source b/src/tutorial/syscat.source index 926ed63b63..2f97642a39 100644 --- a/src/tutorial/syscat.source +++ b/src/tutorial/syscat.source @@ -4,7 +4,7 @@ -- sample queries to the system catalogs -- -- --- Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group +-- Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group -- Portions Copyright (c) 1994, Regents of the University of California -- -- src/tutorial/syscat.source